diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000000..710873e1b56 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,4 @@ +module.exports = { + extends: ['turbo', '@solana/eslint-config-solana', '@solana/eslint-config-solana/jest'], + root: true, +}; diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d6c2e5bd151..17349d72aa3 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,40 +1,22 @@ version: 2 updates: -- package-ecosystem: npm - directory: "/token/js" - schedule: - interval: daily - time: "01:00" - timezone: America/Los_Angeles - open-pull-requests-limit: 3 - labels: - - "automerge" -- package-ecosystem: npm - directory: "/token-lending/js" +- package-ecosystem: cargo + directory: "/" schedule: interval: daily - time: "02:00" - timezone: America/Los_Angeles - open-pull-requests-limit: 3 + time: "09:00" + timezone: UTC labels: - "automerge" + open-pull-requests-limit: 6 + ignore: + - dependency-name: "cbindgen" - package-ecosystem: npm - directory: "/token-swap/js" - schedule: - interval: daily - time: "03:00" - timezone: America/Los_Angeles - open-pull-requests-limit: 3 - labels: - - "automerge" -- package-ecosystem: cargo directory: "/" schedule: interval: daily - time: "04:00" - timezone: America/Los_Angeles + time: "10:00" + timezone: UTC + open-pull-requests-limit: 12 labels: - "automerge" - open-pull-requests-limit: 3 - ignore: - - dependency-name: "cbindgen" diff --git a/.github/label-actions.yml b/.github/label-actions.yml new file mode 100644 index 00000000000..540641756b4 --- /dev/null +++ b/.github/label-actions.yml @@ -0,0 +1,27 @@ +question: + issues: + # Post a comment, `{issue-author}` is an optional placeholder + comment: > + Hi @{issue-author}, + + + Thanks for your question! + + + We want to make sure to keep signal strong in the GitHub issue tracker – to make sure + that it remains the best place to track issues that affect the development of Solana itself. + + + Questions like yours deserve a purpose-built Q&A forum. Unless there exists evidence that + this is a bug with Solana itself, please post your question to the Solana Stack Exchange + using this link: https://solana.stackexchange.com/questions/ask + + + --- + + _This + [automated message](https://github.com/solana-labs/solana-program-library/blob/master/.github/label-actions.yml) + is a result of having added the ‘question’ tag_. + + # Close the issue + close: true diff --git a/.github/workflows/fuzz-nightly.yml b/.github/workflows/fuzz-nightly.yml index 43d6a6c4883..5a83bf630c7 100644 --- a/.github/workflows/fuzz-nightly.yml +++ b/.github/workflows/fuzz-nightly.yml @@ -12,7 +12,7 @@ jobs: fuzz_target: [token-swap-instructions] fail-fast: false steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set env vars run: | @@ -21,13 +21,11 @@ jobs: source ci/solana-version.sh echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV - - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.RUST_STABLE }} - override: true - profile: minimal - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/registry @@ -35,14 +33,14 @@ jobs: target key: cargo-fuzz-${{ hashFiles('**/Cargo.lock') }} - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/bin/cargo-hfuzz ~/.cargo/bin/cargo-honggfuzz key: cargo-fuzz-bins-${{ runner.os }} - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: ~/.cache/solana key: solana-${{ env.SOLANA_VERSION }} diff --git a/.github/workflows/label-actions.yml b/.github/workflows/label-actions.yml new file mode 100644 index 00000000000..218876135a1 --- /dev/null +++ b/.github/workflows/label-actions.yml @@ -0,0 +1,15 @@ +name: "Issue Label Actions" + +on: + issues: + types: [labeled, unlabeled] + +permissions: + contents: read + issues: write + +jobs: + action: + runs-on: ubuntu-latest + steps: + - uses: dessant/label-actions@v2 diff --git a/.github/workflows/manage-stale-issues-and-prs.yml b/.github/workflows/manage-stale-issues-and-prs.yml new file mode 100644 index 00000000000..15e9a9e9e93 --- /dev/null +++ b/.github/workflows/manage-stale-issues-and-prs.yml @@ -0,0 +1,39 @@ +name: "Manage stale issues and PRs" +on: + # Chosen to be just before London wakes up and way past San Francisco's bedtime. + schedule: + - cron: "0 8 * * 1-5" # This is in UTC. + # Do a dry-run (debug-only: true) whenever this workflow itself is changed. + pull_request: + paths: + - .github/workflows/manage-stale-issues-and-prs.yml + types: + - opened + - synchronize + +permissions: + issues: write + pull-requests: write + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v6 + with: + ascending: true # Spend API operations budget on older, more-likely-to-get-closed issues first + close-issue-message: "" # Leave no comment when closing + close-pr-message: "" # Leave no comment when closing + days-before-issue-stale: 365 + days-before-pr-stale: 14 + days-before-close: 7 + debug-only: ${{ github.event_name == 'pull_request' }} # Dry-run when true. + exempt-all-milestones: true # Milestones can sometimes last a month, so exempt issues attached to a milestone. + exempt-issue-labels: blocked,do-not-close,security + exempt-pr-labels: blocked,do-not-close,security + # No actual changes get made in debug-only mode, so we can raise the operations ceiling. + operations-per-run: ${{ github.event_name == 'pull_request' && 1000 || 900}} + stale-issue-label: stale + stale-issue-message: "" # Leave no comment when marking as stale + stale-pr-label: stale + stale-pr-message: "" # Leave no comment when marking as stale diff --git a/.github/workflows/publish-rust.yml b/.github/workflows/publish-rust.yml new file mode 100644 index 00000000000..923960e74aa --- /dev/null +++ b/.github/workflows/publish-rust.yml @@ -0,0 +1,230 @@ +name: Publish Rust Crate + +on: + workflow_dispatch: + inputs: + package_path: + description: Path to directory with package to release + required: true + type: string + level: + description: Level + required: true + default: patch + type: choice + options: + - patch + - minor + - major + - rc + - beta + - alpha + - release + - version + version: + description: Version (used with level "version") + required: false + type: string + dry_run: + description: Dry run + required: true + default: true + type: boolean + create_release: + description: Create a GitHub release + required: true + type: boolean + default: true + +jobs: + rustfmt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set env vars + run: | + source ci/rust-version.sh + echo "RUST_NIGHTLY=$rust_nightly" >> $GITHUB_ENV + + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_NIGHTLY }} + components: rustfmt + + - name: Run fmt + run: ./cargo-nightly fmt --all -- --check + + clippy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Remove unneeded packages for more space + run: bash ./ci/warning/purge-ubuntu-runner.sh + + - name: Set env vars + run: | + source ci/rust-version.sh + echo "RUST_NIGHTLY=$rust_nightly" >> $GITHUB_ENV + + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_NIGHTLY }} + components: clippy + + - uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: cargo-clippy-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + cargo-clippy- + + - name: Install dependencies + run: ./ci/install-build-deps.sh + + - name: Run clippy + run: ./cargo-nightly clippy -Zunstable-options --workspace --all-targets --all-features -- --deny=warnings --deny=clippy::arithmetic_side_effects + + cargo-build-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Remove unneeded packages for more space + run: bash ./ci/warning/purge-ubuntu-runner.sh + + - name: Set env vars + run: | + source ci/rust-version.sh + echo "RUST_STABLE=$rust_stable" >> $GITHUB_ENV + source ci/solana-version.sh + echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV + + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_STABLE }} + + - uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: cargo-build-${{ hashFiles('**/Cargo.lock') }}-${{ env.RUST_STABLE }} + + - uses: actions/cache@v4 + with: + path: | + ~/.cargo/bin/rustfilt + key: cargo-sbf-bins-${{ runner.os }} + + - uses: actions/cache@v4 + with: + path: ~/.cache/solana + key: solana-${{ env.SOLANA_VERSION }} + + - name: Install dependencies + run: | + ./ci/install-build-deps.sh + ./ci/install-program-deps.sh + echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH + + - name: Build and test + run: ./ci/cargo-build-test.sh + + publish_crate: + name: Publish crate + runs-on: ubuntu-latest + needs: [rustfmt, clippy, cargo-build-test] + permissions: + contents: write + steps: + - name: Git Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 # get the whole history for git-cliff + + - name: Set env vars + run: | + source ci/rust-version.sh + echo "RUST_STABLE=$rust_stable" >> $GITHUB_ENV + + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_STABLE }} + + - name: Install dependencies + run: ./ci/install-build-deps.sh + + - uses: actions/cache@v4 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry + ~/.cargo/git + key: cargo-publish-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + cargo-publish- + + - name: Install Cargo Release + run: which cargo-release || cargo install cargo-release --version 0.25.11 + + - name: Ensure CARGO_REGISTRY_TOKEN variable is set + env: + token: ${{ secrets.CARGO_REGISTRY_TOKEN }} + if: ${{ env.token == '' }} + run: | + echo "The CARGO_REGISTRY_TOKEN secret variable is not set" + echo "Go to \"Settings\" -> \"Secrets and variables\" -> \"Actions\" -> \"New repository secret\"." + exit 1 + + - name: Set Git Author + run: | + git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + + - name: Rebase + run: git pull --rebase origin + + - name: Publish Crate + id: publish + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + run: | + if [ "${{ inputs.level }}" == "version" ]; then + LEVEL=${{ inputs.version }} + else + LEVEL=${{ inputs.level }} + fi + + if [ "${{ inputs.dry_run }}" == "true" ]; then + OPTIONS="--dry-run" + else + OPTIONS="" + fi + + ./ci/publish-rust.sh "${{ inputs.package_path }}" $LEVEL $OPTIONS + + - name: Generate a changelog + if: github.event.inputs.create_release == 'true' + uses: orhun/git-cliff-action@v3 + with: + config: "ci/cliff.toml" + args: | + "${{ steps.publish.outputs.old_git_tag }}"..master + --include-path "${{ inputs.package_path }}/**" + --github-repo "${{ github.repository }}" + env: + OUTPUT: TEMP_CHANGELOG.md + GITHUB_REPO: ${{ github.repository }} + + - name: Create GitHub release + if: github.event.inputs.create_release == 'true' && github.event.inputs.dry_run != 'true' + uses: ncipollo/release-action@v1 + with: + tag: ${{ steps.publish.outputs.new_git_tag }} + bodyFile: TEMP_CHANGELOG.md + name: ${{ steps.publish.outputs.release_title }} diff --git a/.github/workflows/pull-request-account-compression.yml b/.github/workflows/pull-request-account-compression.yml new file mode 100644 index 00000000000..d11a636b2dd --- /dev/null +++ b/.github/workflows/pull-request-account-compression.yml @@ -0,0 +1,100 @@ +name: Account Compression Pull Request + +on: + pull_request: + paths: + - "account-compression/**" + - "libraries/concurrent-merkle-tree/**" + - "ci/*-version.sh" + - "ci/install-anchor.sh" + - ".github/workflows/pull-request-account-compression.yml" + - "!account-compression/sdk/**" + push: + branches: [master, ac-mainnet-tag] + paths: + - "account-compression/**" + - "libraries/concurrent-merkle-tree/**" + - "ci/*-version.sh" + - "ci/install-anchor.sh" + - ".github/workflows/pull-request-account-compression.yml" + - "!account-compression/sdk/**" + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + anchor-build-account-compression: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set env vars + run: | + echo "RUST_STABLE_VERSION=1.78.0" >> $GITHUB_ENV + echo "SOLANA_VERSION=v2.0.14" >> $GITHUB_ENV + source ci/rust-version.sh + echo "RUST_STABLE=$rust_stable" >> $GITHUB_ENV + source ci/solana-version.sh + source ci/install-anchor.sh + echo "ANCHOR_CLI_VERSION=$anchor_cli_version" >> $GITHUB_ENV + + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_STABLE }} + + - uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: cargo-build-${{ hashFiles('**/Cargo.lock') }}-${{ env.RUST_STABLE }} + + - uses: actions/cache@v4 + with: + path: | + ~/.cargo/bin/rustfilt + key: cargo-sbf-bins-${{ runner.os }} + + - uses: actions/cache@v4 + with: + path: ~/.cache/solana + key: solana-${{ env.SOLANA_VERSION }} + + - name: Install dependencies + run: | + ./ci/install-build-deps.sh + ./ci/install-program-deps.sh + echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH + + - name: Build and test programs + run: ./ci/cargo-test-sbf.sh account-compression + + - name: Upload programs + uses: actions/upload-artifact@v4 + with: + name: account-compression-programs + path: "account-compression/target/deploy/*.so" + if-no-files-found: error + + js-test-account-compression: + runs-on: ubuntu-latest + env: + NODE_VERSION: 20.X + steps: + - uses: actions/checkout@v4 + - name: Use Node.js ${{ env.NODE_VERSION }} + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + - uses: pnpm/action-setup@v4 + - uses: actions/cache@v4 + with: + path: ~/.npm + key: node-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: | + node- + - name: Set env vars + run: echo "SOLANA_VERSION=v2.0.14" >> $GITHUB_ENV + - run: ./ci/js-test-account-compression.sh diff --git a/.github/workflows/pull-request-binary-oracle-pair.yml b/.github/workflows/pull-request-binary-oracle-pair.yml index d5fa38e3057..b24cf5c4e68 100644 --- a/.github/workflows/pull-request-binary-oracle-pair.yml +++ b/.github/workflows/pull-request-binary-oracle-pair.yml @@ -6,18 +6,24 @@ on: - 'binary-oracle-pair/**' - 'token/**' - 'ci/*-version.sh' + - '!token/js/**' push: branches: [master] paths: - 'binary-oracle-pair/**' - 'token/**' - 'ci/*-version.sh' + - '!token/js/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: - cargo-test-bpf: + cargo-test-sbf: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set env vars run: | @@ -26,26 +32,24 @@ jobs: source ci/solana-version.sh echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV - - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.RUST_STABLE }} - override: true - profile: minimal - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git key: cargo-build-${{ hashFiles('**/Cargo.lock') }}-${{ env.RUST_STABLE}} - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/bin/rustfilt - key: cargo-bpf-bins-${{ runner.os }} + key: cargo-sbf-bins-${{ runner.os }} - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: ~/.cache/solana key: solana-${{ env.SOLANA_VERSION }} @@ -57,4 +61,4 @@ jobs: echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH - name: Build and test - run: ./ci/cargo-test-bpf.sh binary-oracle-pair + run: ./ci/cargo-test-sbf.sh binary-oracle-pair diff --git a/.github/workflows/pull-request-docs.yml b/.github/workflows/pull-request-docs.yml index 7c02b91f4bf..a16d21ab900 100644 --- a/.github/workflows/pull-request-docs.yml +++ b/.github/workflows/pull-request-docs.yml @@ -4,10 +4,16 @@ on: pull_request: paths: - 'docs/**' + - '.github/workflows/pull-request-docs.yml' push: branches: [master] paths: - 'docs/**' + - '.github/workflows/pull-request-docs.yml' + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: all_github_action_checks: @@ -25,7 +31,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 2 @@ -33,13 +39,13 @@ jobs: id: check_files run: | echo "========== check paths of modified files ==========" - echo "::set-output name=run_all_github_action_checks::true" + echo "run_all_github_action_checks=true" >> $GITHUB_OUTPUT git diff --name-only HEAD^ HEAD > files.txt while IFS= read -r file do if [[ $file != docs/** ]]; then echo "Found modified non-'docs' file(s)" - echo "::set-output name=run_all_github_action_checks::false" + echo "run_all_github_action_checks=false" >> $GITHUB_OUTPUT break fi done < files.txt @@ -47,10 +53,10 @@ jobs: build_docs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: - node-version: '16' + node-version: '18' - name: "Build Docs" run: | cd docs/ diff --git a/.github/workflows/pull-request-examples.yml b/.github/workflows/pull-request-examples.yml index 6bdccf6e607..d9b86f4e2e5 100644 --- a/.github/workflows/pull-request-examples.yml +++ b/.github/workflows/pull-request-examples.yml @@ -11,11 +11,15 @@ on: - 'examples/rust/**' - 'ci/*-version.sh' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: - cargo-test-bpf: + cargo-test-sbf: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set env vars run: | @@ -24,26 +28,24 @@ jobs: source ci/solana-version.sh echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV - - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.RUST_STABLE }} - override: true - profile: minimal - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git key: cargo-build-${{ hashFiles('**/Cargo.lock') }}-${{ env.RUST_STABLE}} - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/bin/rustfilt - key: cargo-bpf-bins-${{ runner.os }} + key: cargo-sbf-bins-${{ runner.os }} - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: ~/.cache/solana key: solana-${{ env.SOLANA_VERSION }} @@ -55,4 +57,4 @@ jobs: echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH - name: Build and test - run: ./ci/cargo-test-bpf.sh examples/rust + run: ./ci/cargo-test-sbf.sh examples/rust diff --git a/.github/workflows/pull-request-feature-proposal.yml b/.github/workflows/pull-request-feature-proposal.yml deleted file mode 100644 index e5ad8a7748a..00000000000 --- a/.github/workflows/pull-request-feature-proposal.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Feature Proposal Pull Request - -on: - pull_request: - paths: - - 'feature-proposal/**' - - 'token/**' - - 'ci/*-version.sh' - push: - branches: [master] - paths: - - 'feature-proposal/**' - - 'token/**' - - 'ci/*-version.sh' - -jobs: - cargo-test-bpf: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - name: Set env vars - run: | - source ci/rust-version.sh - echo "RUST_STABLE=$rust_stable" >> $GITHUB_ENV - source ci/solana-version.sh - echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV - - - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ env.RUST_STABLE }} - override: true - profile: minimal - - - uses: actions/cache@v2 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - key: cargo-build-${{ hashFiles('**/Cargo.lock') }}-${{ env.RUST_STABLE}} - - - uses: actions/cache@v2 - with: - path: | - ~/.cargo/bin/rustfilt - key: cargo-bpf-bins-${{ runner.os }} - - - uses: actions/cache@v2 - with: - path: ~/.cache/solana - key: solana-${{ env.SOLANA_VERSION }} - - - name: Install dependencies - run: | - ./ci/install-build-deps.sh - ./ci/install-program-deps.sh - echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH - - - name: Build and test - run: ./ci/cargo-test-bpf.sh feature-proposal diff --git a/.github/workflows/pull-request-governance.yml b/.github/workflows/pull-request-governance.yml index e001f16bc4b..f8eb96299db 100644 --- a/.github/workflows/pull-request-governance.yml +++ b/.github/workflows/pull-request-governance.yml @@ -3,21 +3,37 @@ name: Governance Pull Request on: pull_request: paths: - - 'governance/**' - - 'token/**' - - 'ci/*-version.sh' + - "governance/**" + - "token/**" + - "ci/*-version.sh" + - '!token/js/**' push: branches: [master] paths: - - 'governance/**' - - 'token/**' - - 'ci/*-version.sh' + - "governance/**" + - "token/**" + - "ci/*-version.sh" + - '!token/js/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: - cargo-test-bpf: + cargo-test-sbf: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - name: Clean up space on runner machine + # Workaround to provide additional free space for testing. + # https://github.com/actions/virtual-environments/issues/2840 + run: | + sudo rm -rf /usr/share/dotnet + sudo rm -rf /usr/local/lib/android + sudo rm -rf /opt/ghc + sudo rm -rf "/usr/local/share/boost" + sudo rm -rf "$AGENT_TOOLSDIRECTORY" + + - uses: actions/checkout@v4 - name: Set env vars run: | @@ -26,26 +42,24 @@ jobs: source ci/solana-version.sh echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV - - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.RUST_STABLE }} - override: true - profile: minimal - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git key: cargo-build-${{ hashFiles('**/Cargo.lock') }}-${{ env.RUST_STABLE}} - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/bin/rustfilt - key: cargo-bpf-bins-${{ runner.os }} + key: cargo-sbf-bins-${{ runner.os }} - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: ~/.cache/solana key: solana-${{ env.SOLANA_VERSION }} @@ -57,4 +71,5 @@ jobs: echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH - name: Build and test - run: ./ci/cargo-test-bpf.sh governance + timeout-minutes: 60 + run: ./ci/cargo-test-sbf.sh governance diff --git a/.github/workflows/pull-request-js.yml b/.github/workflows/pull-request-js.yml new file mode 100644 index 00000000000..225874ebade --- /dev/null +++ b/.github/workflows/pull-request-js.yml @@ -0,0 +1,55 @@ +name: Pull Request JS + +on: + pull_request: + paths: + - 'account-compression/sdk/**' + - 'name-service/js/**' + - 'token-lending/js/**' + - 'token-swap/js/**' + - 'pnpm-lock.yaml' + - '.github/workflows/pull-request-js.yml' + push: + branches: [master] + paths: + - 'account-compression/sdk/**' + - 'token-lending/js/**' + - 'token-swap/js/**' + - 'pnpm-lock.yaml' + - '.github/workflows/pull-request-js.yml' + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + js-test: + strategy: + matrix: + node-version: [16.x, 18.x, 20.x] + package: + [ + name-service, + token-swap, + ] + include: + # Restrict certain packages to supported Node.js versions. + - package: account-compression + node-version: 20.x + - package: token-lending + node-version: 18.5 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + - uses: pnpm/action-setup@v4 + - uses: actions/cache@v4 + with: + path: ~/.npm + key: node-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: | + node- + - run: ./ci/js-test-${{ matrix.package }}.sh diff --git a/.github/workflows/pull-request-libraries.yml b/.github/workflows/pull-request-libraries.yml index 8afca9d17a5..7b7a06e424f 100644 --- a/.github/workflows/pull-request-libraries.yml +++ b/.github/workflows/pull-request-libraries.yml @@ -5,17 +5,23 @@ on: paths: - 'libraries/**' - 'ci/*-version.sh' + - '.github/workflows/pull-request-libraries.yml' push: branches: [master] paths: - 'libraries/**' - 'ci/*-version.sh' + - '.github/workflows/pull-request-libraries.yml' + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: - cargo-test-bpf: + cargo-test-sbf: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set env vars run: | @@ -24,26 +30,24 @@ jobs: source ci/solana-version.sh echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV - - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.RUST_STABLE }} - override: true - profile: minimal - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git key: cargo-build-${{ hashFiles('**/Cargo.lock') }}-${{ env.RUST_STABLE}} - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/bin/rustfilt - key: cargo-bpf-bins-${{ runner.os }} + key: cargo-sbf-bins-${{ runner.os }} - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: ~/.cache/solana key: solana-${{ env.SOLANA_VERSION }} @@ -55,4 +59,4 @@ jobs: echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH - name: Build and test - run: ./ci/cargo-test-bpf.sh libraries + run: ./ci/cargo-test-sbf.sh libraries diff --git a/.github/workflows/pull-request-memo.yml b/.github/workflows/pull-request-memo.yml deleted file mode 100644 index bd0bb1a7541..00000000000 --- a/.github/workflows/pull-request-memo.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: Memo Pull Request - -on: - pull_request: - paths: - - 'memo/**' - - 'ci/*-version.sh' - push: - branches: [master] - paths: - - 'memo/**' - - 'ci/*-version.sh' - -jobs: - cargo-test-bpf: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - name: Set env vars - run: | - source ci/rust-version.sh - echo "RUST_STABLE=$rust_stable" >> $GITHUB_ENV - source ci/solana-version.sh - echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV - - - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ env.RUST_STABLE }} - override: true - profile: minimal - - - uses: actions/cache@v2 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - key: cargo-build-${{ hashFiles('**/Cargo.lock') }}-${{ env.RUST_STABLE}} - - - uses: actions/cache@v2 - with: - path: | - ~/.cargo/bin/rustfilt - key: cargo-bpf-bins-${{ runner.os }} - - - uses: actions/cache@v2 - with: - path: ~/.cache/solana - key: solana-${{ env.SOLANA_VERSION }} - - - name: Install dependencies - run: | - ./ci/install-build-deps.sh - ./ci/install-program-deps.sh - echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH - - - name: Build and test - run: ./ci/cargo-test-bpf.sh memo - - js-test: - runs-on: ubuntu-latest - env: - NODE_VERSION: 16.x - steps: - - uses: actions/checkout@v2 - - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@v1 - with: - node-version: ${{ env.NODE_VERSION }} - - uses: actions/cache@v2 - with: - path: ~/.cache/yarn - key: yarn-${{ hashFiles('memo/ts/yarn.lock') }} - - run: ./ci/ts-test-memo.sh diff --git a/.github/workflows/pull-request-name-service.yml b/.github/workflows/pull-request-name-service.yml index 24dbe65a8a9..70ce45a3168 100644 --- a/.github/workflows/pull-request-name-service.yml +++ b/.github/workflows/pull-request-name-service.yml @@ -5,17 +5,23 @@ on: paths: - 'name-service/**' - 'ci/*-version.sh' + - '!name-service/js/**' push: branches: [master] paths: - 'name-service/**' - 'ci/*-version.sh' + - '!name-service/js/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: - cargo-test-bpf: + cargo-test-sbf: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set env vars run: | @@ -24,26 +30,24 @@ jobs: source ci/solana-version.sh echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV - - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.RUST_STABLE }} - override: true - profile: minimal - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git key: cargo-build-${{ hashFiles('**/Cargo.lock') }}-${{ env.RUST_STABLE}} - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/bin/rustfilt - key: cargo-bpf-bins-${{ runner.os }} + key: cargo-sbf-bins-${{ runner.os }} - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: ~/.cache/solana key: solana-${{ env.SOLANA_VERSION }} @@ -55,22 +59,23 @@ jobs: echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH - name: Build and test - run: ./ci/cargo-test-bpf.sh name-service + run: ./ci/cargo-test-sbf.sh name-service js-test: runs-on: ubuntu-latest env: - NODE_VERSION: 14.x + NODE_VERSION: 16.x steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@v1 + uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} - - uses: actions/cache@v2 + - uses: pnpm/action-setup@v4 + - uses: actions/cache@v4 with: - path: ~/.cache/yarn - key: node-${{ hashFiles('name-service/js/yarn.lock') }} + path: ~/.npm + key: node-${{ hashFiles('pnpm-lock.yaml') }} restore-keys: | node- - run: ./ci/js-test-name-service.sh diff --git a/.github/workflows/pull-request-record.yml b/.github/workflows/pull-request-record.yml deleted file mode 100644 index c487c4b2e51..00000000000 --- a/.github/workflows/pull-request-record.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Record Pull Request - -on: - pull_request: - paths: - - 'record/**' - - 'ci/*-version.sh' - push: - branches: [master] - paths: - - 'record/**' - - 'ci/*-version.sh' - -jobs: - cargo-test-bpf: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - name: Set env vars - run: | - source ci/rust-version.sh - echo "RUST_STABLE=$rust_stable" >> $GITHUB_ENV - source ci/solana-version.sh - echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV - - - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ env.RUST_STABLE }} - override: true - profile: minimal - - - uses: actions/cache@v2 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - key: cargo-build-${{ hashFiles('**/Cargo.lock') }}-${{ env.RUST_STABLE}} - - - uses: actions/cache@v2 - with: - path: | - ~/.cargo/bin/rustfilt - key: cargo-bpf-bins-${{ runner.os }} - - - uses: actions/cache@v2 - with: - path: ~/.cache/solana - key: solana-${{ env.SOLANA_VERSION }} - - - name: Install dependencies - run: | - ./ci/install-build-deps.sh - ./ci/install-program-deps.sh - echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH - - - name: Build and test - run: ./ci/cargo-test-bpf.sh record diff --git a/.github/workflows/pull-request-shared-memory.yml b/.github/workflows/pull-request-shared-memory.yml index f371bd11aa8..a7bbbae849b 100644 --- a/.github/workflows/pull-request-shared-memory.yml +++ b/.github/workflows/pull-request-shared-memory.yml @@ -11,11 +11,15 @@ on: - 'shared-memory/**' - 'ci/*-version.sh' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: - cargo-test-bpf: + cargo-test-sbf: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set env vars run: | @@ -24,26 +28,24 @@ jobs: source ci/solana-version.sh echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV - - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.RUST_STABLE }} - override: true - profile: minimal - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git key: cargo-build-${{ hashFiles('**/Cargo.lock') }}-${{ env.RUST_STABLE}} - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/bin/rustfilt - key: cargo-bpf-bins-${{ runner.os }} + key: cargo-sbf-bins-${{ runner.os }} - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: ~/.cache/solana key: solana-${{ env.SOLANA_VERSION }} @@ -55,4 +57,4 @@ jobs: echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH - name: Build and test - run: ./ci/cargo-test-bpf.sh shared-memory + run: ./ci/cargo-test-sbf.sh shared-memory diff --git a/.github/workflows/pull-request-stake-pool.yml b/.github/workflows/pull-request-stake-pool.yml deleted file mode 100644 index 04efa394ffd..00000000000 --- a/.github/workflows/pull-request-stake-pool.yml +++ /dev/null @@ -1,115 +0,0 @@ -name: Stake Pool Pull Request - -on: - pull_request: - paths: - - 'stake-pool/**' - - 'token/**' - - 'ci/*-version.sh' - push: - branches: [master] - paths: - - 'stake-pool/**' - - 'token/**' - - 'ci/*-version.sh' - -jobs: - cargo-test-bpf: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - name: Set env vars - run: | - source ci/rust-version.sh - echo "RUST_STABLE=$rust_stable" >> $GITHUB_ENV - source ci/solana-version.sh - echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV - - - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ env.RUST_STABLE }} - override: true - profile: minimal - - - uses: actions/cache@v2 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - key: cargo-build-${{ hashFiles('**/Cargo.lock') }}-${{ env.RUST_STABLE}} - - - uses: actions/cache@v2 - with: - path: | - ~/.cargo/bin/rustfilt - key: cargo-bpf-bins-${{ runner.os }} - - - uses: actions/cache@v2 - with: - path: ~/.cache/solana - key: solana-${{ env.SOLANA_VERSION }} - - - name: Install dependencies - run: | - ./ci/install-build-deps.sh - ./ci/install-program-deps.sh - echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH - - - name: Build and test - run: ./ci/cargo-test-bpf.sh stake-pool - - - name: Upload programs - uses: actions/upload-artifact@v2 - with: - name: stake-pool-programs - path: "target/deploy/*.so" - if-no-files-found: error - - js-test: - runs-on: ubuntu-latest - env: - NODE_VERSION: 16.x - needs: cargo-test-bpf - steps: - - uses: actions/checkout@v2 - - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@v1 - with: - node-version: ${{ env.NODE_VERSION }} - - uses: actions/cache@v2 - with: - path: ~/.npm - key: node-${{ hashFiles('stake-pool/js/package-lock.json') }} - restore-keys: | - node- - - name: Download programs - uses: actions/download-artifact@v2 - with: - name: stake-pool-programs - path: target/deploy - - run: ./ci/js-test-stake-pool.sh - - py-test: - runs-on: ubuntu-latest - needs: cargo-test-bpf - steps: - - uses: actions/checkout@v2 - - - name: Setup Python version - uses: actions/setup-python@v2 - with: - python-version: 3.8 - - - uses: actions/cache@v2 - with: - path: ~/.cache/pip - key: pip-stake-pool-${{ hashFiles('stake-pool/py/requirements.txt') }} - - - name: Download programs - uses: actions/download-artifact@v2 - with: - name: stake-pool-programs - path: target/deploy - - - run: ./ci/py-test-stake-pool.sh diff --git a/.github/workflows/pull-request-token-collection.yml b/.github/workflows/pull-request-token-collection.yml new file mode 100644 index 00000000000..f94eda3f159 --- /dev/null +++ b/.github/workflows/pull-request-token-collection.yml @@ -0,0 +1,74 @@ +name: Token Collection Pull Request + +on: + pull_request: + paths: + - 'token-collection/**' + - 'token/**' + - 'token-group/**' + - 'token-metadata/**' + - 'ci/*-version.sh' + - '.github/workflows/pull-request-token-collection.yml' + - '!token/js/**' + - '!token-group/js/**' + - '!token-metadata/js/**' + push: + branches: [master] + paths: + - 'token-collection/**' + - 'token/**' + - 'token-group/**' + - 'token-metadata/**' + - 'ci/*-version.sh' + - '.github/workflows/pull-request-token-collection.yml' + - '!token/js/**' + - '!token-group/js/**' + - '!token-metadata/js/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + cargo-test-sbf: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set env vars + run: | + source ci/rust-version.sh + echo "RUST_STABLE=$rust_stable" >> $GITHUB_ENV + source ci/solana-version.sh + echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV + + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_STABLE }} + + - uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: cargo-build-${{ hashFiles('**/Cargo.lock') }}-${{ env.RUST_STABLE}} + + - uses: actions/cache@v4 + with: + path: | + ~/.cargo/bin/rustfilt + key: cargo-sbf-bins-${{ runner.os }} + + - uses: actions/cache@v4 + with: + path: ~/.cache/solana + key: solana-${{ env.SOLANA_VERSION }} + + - name: Install dependencies + run: | + ./ci/install-build-deps.sh + ./ci/install-program-deps.sh + echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH + + - name: Build and test + run: ./ci/cargo-test-sbf.sh token-collection diff --git a/.github/workflows/pull-request-token-lending.yml b/.github/workflows/pull-request-token-lending.yml index d72f0163c9c..9add4942a50 100644 --- a/.github/workflows/pull-request-token-lending.yml +++ b/.github/workflows/pull-request-token-lending.yml @@ -6,18 +6,26 @@ on: - 'token-lending/**' - 'token/**' - 'ci/*-version.sh' + - '!token-lending/js/**' + - '!token/js/**' push: branches: [master] paths: - 'token-lending/**' - 'token/**' - 'ci/*-version.sh' + - '!token-lending/js/**' + - '!token/js/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: - cargo-test-bpf: + cargo-test-sbf: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set env vars run: | @@ -26,26 +34,24 @@ jobs: source ci/solana-version.sh echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV - - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.RUST_STABLE }} - override: true - profile: minimal - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git key: cargo-build-${{ hashFiles('**/Cargo.lock') }}-${{ env.RUST_STABLE}} - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/bin/rustfilt - key: cargo-bpf-bins-${{ runner.os }} + key: cargo-sbf-bins-${{ runner.os }} - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: ~/.cache/solana key: solana-${{ env.SOLANA_VERSION }} @@ -57,35 +63,23 @@ jobs: echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH - name: Build and test - run: ./ci/cargo-test-bpf.sh token-lending - - - name: Upload programs - uses: actions/upload-artifact@v2 - with: - name: token-lending-programs - path: "target/deploy/*.so" - if-no-files-found: error + run: ./ci/cargo-test-sbf.sh token-lending js-test: runs-on: ubuntu-latest env: - NODE_VERSION: 14.x - needs: cargo-test-bpf + NODE_VERSION: 18.x steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@v1 + uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} - - uses: actions/cache@v2 + - uses: pnpm/action-setup@v4 + - uses: actions/cache@v4 with: path: ~/.npm - key: node-${{ hashFiles('token-lending/js/package-lock.json') }} + key: node-${{ hashFiles('pnpm-lock.yaml') }} restore-keys: | node- - - name: Download programs - uses: actions/download-artifact@v2 - with: - name: token-lending-programs - path: target/deploy - run: ./ci/js-test-token-lending.sh diff --git a/.github/workflows/pull-request-token-swap.yml b/.github/workflows/pull-request-token-swap.yml index b43a514bc24..c86865137c7 100644 --- a/.github/workflows/pull-request-token-swap.yml +++ b/.github/workflows/pull-request-token-swap.yml @@ -7,6 +7,8 @@ on: - 'token/**' - 'libraries/math/**' - 'ci/*-version.sh' + - '!token-swap/js/**' + - '!token/js/**' push: branches: [master] paths: @@ -14,12 +16,18 @@ on: - 'token/**' - 'libraries/math/**' - 'ci/*-version.sh' + - '!token-swap/js/**' + - '!token/js/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: - cargo-test-bpf: + cargo-test-sbf: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set env vars run: | @@ -28,26 +36,24 @@ jobs: source ci/solana-version.sh echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV - - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.RUST_STABLE }} - override: true - profile: minimal - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git key: cargo-build-${{ hashFiles('**/Cargo.lock') }}-${{ env.RUST_STABLE}} - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/bin/rustfilt - key: cargo-bpf-bins-${{ runner.os }} + key: cargo-sbf-bins-${{ runner.os }} - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: ~/.cache/solana key: solana-${{ env.SOLANA_VERSION }} @@ -59,14 +65,14 @@ jobs: echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH - name: Build and test - run: ./ci/cargo-test-bpf.sh token-swap + run: ./ci/cargo-test-sbf.sh token-swap - name: Build production version run: | - cargo +"$RUST_STABLE" build-bpf \ + cargo +"$RUST_STABLE" build-sbf \ --manifest-path=token-swap/program/Cargo.toml \ --features production \ - --bpf-out-dir target/deploy-production + --sbf-out-dir target/deploy-production env: SWAP_PROGRAM_OWNER_FEE_ADDRESS: HfoTxFR1Tm6kGmWgYWD6J7YHVy1UwqSULUGVLXkJqaKN @@ -74,41 +80,29 @@ jobs: run: | mv target/deploy-production/spl_token_swap.so target/deploy/spl_token_swap_production.so - - name: Upload programs - uses: actions/upload-artifact@v2 - with: - name: token-swap-programs - path: "target/deploy/*.so" - if-no-files-found: error - js-test: runs-on: ubuntu-latest env: - NODE_VERSION: 14.x - needs: cargo-test-bpf + NODE_VERSION: 16.x steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@v1 + uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} - - uses: actions/cache@v2 + - uses: pnpm/action-setup@v4 + - uses: actions/cache@v4 with: path: ~/.npm - key: node-${{ hashFiles('token-swap/js/package-lock.json') }} + key: node-${{ hashFiles('pnpm-lock.yaml') }} restore-keys: | node- - - name: Download programs - uses: actions/download-artifact@v2 - with: - name: token-swap-programs - path: target/deploy - run: ./ci/js-test-token-swap.sh fuzz: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set env vars run: | @@ -117,27 +111,25 @@ jobs: source ci/solana-version.sh echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV - - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.RUST_STABLE }} - override: true - profile: minimal - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git key: token-swap-fuzz-${{ hashFiles('**/Cargo.lock') }} - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/bin/cargo-hfuzz ~/.cargo/bin/cargo-honggfuzz key: cargo-fuzz-bins-${{ runner.os }} - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cache diff --git a/.github/workflows/pull-request-token-upgrade.yml b/.github/workflows/pull-request-token-upgrade.yml new file mode 100644 index 00000000000..306e269e186 --- /dev/null +++ b/.github/workflows/pull-request-token-upgrade.yml @@ -0,0 +1,108 @@ +name: Token Upgrade Pull Request + +on: + pull_request: + paths: + - 'token-upgrade/**' + - 'token/**' + - 'ci/*-version.sh' + - '.github/workflows/pull-request-token-upgrade.yml' + - '!token/js/**' + push: + branches: [master] + paths: + - 'token-upgrade/**' + - 'token/**' + - 'ci/*-version.sh' + - '.github/workflows/pull-request-token-upgrade.yml' + - '!token/js/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + cargo-test-sbf: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set env vars + run: | + source ci/rust-version.sh + echo "RUST_STABLE=$rust_stable" >> $GITHUB_ENV + source ci/solana-version.sh + echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV + + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_STABLE }} + + - uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: cargo-build-${{ hashFiles('**/Cargo.lock') }}-${{ env.RUST_STABLE}} + + - uses: actions/cache@v4 + with: + path: | + ~/.cargo/bin/rustfilt + key: cargo-sbf-bins-${{ runner.os }} + + - uses: actions/cache@v4 + with: + path: ~/.cache/solana + key: solana-${{ env.SOLANA_VERSION }} + + - name: Install dependencies + run: | + ./ci/install-build-deps.sh + ./ci/install-program-deps.sh + echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH + + - name: Build and test + run: ./ci/cargo-test-sbf.sh token-upgrade + + cargo-build-test-cli: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set env vars + run: | + source ci/rust-version.sh + echo "RUST_STABLE=$rust_stable" >> $GITHUB_ENV + source ci/solana-version.sh + echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV + + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_STABLE }} + + - uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: cargo-build-${{ hashFiles('**/Cargo.lock') }}-${{ env.RUST_STABLE }} + + - uses: actions/cache@v4 + with: + path: ~/.cache/solana + key: solana-${{ env.SOLANA_VERSION }} + + - name: Install dependencies + run: | + ./ci/install-build-deps.sh + ./ci/install-program-deps.sh + echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH + + - name: Build dependent programs + run: | + cargo build-sbf --manifest-path ./token-upgrade/program/Cargo.toml + + - name: Run CLI tests + run: | + cargo test --manifest-path ./token-upgrade/cli/Cargo.toml diff --git a/.github/workflows/pull-request-token.yml b/.github/workflows/pull-request-token.yml deleted file mode 100644 index 340dc65a4d0..00000000000 --- a/.github/workflows/pull-request-token.yml +++ /dev/null @@ -1,182 +0,0 @@ -name: Token Pull Request - -on: - pull_request: - paths: - - 'associated-token-account/**' - - 'token/**' - - 'ci/*-version.sh' - - '.github/workflows/pull-request-token.yml' - push: - branches: [master] - paths: - - 'associated-token-account/**' - - 'token/**' - - 'ci/*-version.sh' - - '.github/workflows/pull-request-token.yml' - -jobs: - cargo-test-bpf: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - name: Set env vars - run: | - source ci/rust-version.sh - echo "RUST_STABLE=$rust_stable" >> $GITHUB_ENV - source ci/solana-version.sh - echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV - - - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ env.RUST_STABLE }} - override: true - profile: minimal - - - uses: actions/cache@v2 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - key: cargo-build-${{ hashFiles('**/Cargo.lock') }}-${{ env.RUST_STABLE}} - - - uses: actions/cache@v2 - with: - path: | - ~/.cargo/bin/rustfilt - key: cargo-bpf-bins-${{ runner.os }} - - - uses: actions/cache@v2 - with: - path: ~/.cache/solana - key: solana-${{ env.SOLANA_VERSION }} - - - name: Install dependencies - run: | - ./ci/install-build-deps.sh - ./ci/install-program-deps.sh - echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH - - - name: Build and test token - run: ./ci/cargo-test-bpf.sh token - - - name: Build and test ATA - run: ./ci/cargo-test-bpf.sh associated-token-account - - - name: Build and test token-2022 with "serde" activated - run: | - cargo +"${{ env.RUST_STABLE }}" test \ - --manifest-path=token/program-2022/Cargo.toml \ - --features serde-traits \ - -- --nocapture - exit 0 - - - name: Upload programs - uses: actions/upload-artifact@v2 - with: - name: token-programs - path: "target/deploy/*.so" - if-no-files-found: error - - cargo-test-bpf-twoxtx: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - name: Set env vars - run: | - echo "RUST_STABLE_VERSION=1.60.0" >> $GITHUB_ENV - source ci/rust-version.sh - echo "RUST_STABLE=$rust_stable" >> $GITHUB_ENV - source ci/solana-version.sh - echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV - - - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ env.RUST_STABLE }} - override: true - profile: minimal - - - uses: actions/cache@v2 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - key: cargo-build-${{ hashFiles('**/Cargo.lock') }}-${{ env.RUST_STABLE}} - - - name: Install dependencies - run: | - ./ci/install-build-deps.sh - ./ci/install-program-deps.sh - echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH - - - name: Build and test token-2022 twoxtx (TEMPORARY) - run: | - ./token/twoxtx-setup.sh - ./ci/cargo-test-bpf.sh token/program-2022-test - - js-test: - runs-on: ubuntu-latest - env: - NODE_VERSION: 14.x - needs: cargo-test-bpf - steps: - - uses: actions/checkout@v2 - - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@v1 - with: - node-version: ${{ env.NODE_VERSION }} - - uses: actions/cache@v2 - with: - path: ~/.cache/yarn - key: node-${{ hashFiles('token/js/yarn.lock') }} - restore-keys: | - node- - - name: Download programs - uses: actions/download-artifact@v2 - with: - name: token-programs - path: target/deploy - - run: ./ci/js-test-token.sh - - cargo-build-test-cli: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - name: Set env vars - run: | - source ci/rust-version.sh - echo "RUST_STABLE=$rust_stable" >> $GITHUB_ENV - source ci/solana-version.sh - echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV - - - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ env.RUST_STABLE }} - override: true - profile: minimal - - - uses: actions/cache@v2 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - key: cargo-build-${{ hashFiles('**/Cargo.lock') }}-${{ env.RUST_STABLE }} - - - uses: actions/cache@v2 - with: - path: ~/.cache/solana - key: solana-${{ env.SOLANA_VERSION }} - - - name: Install dependencies - run: | - ./ci/install-build-deps.sh - ./ci/install-program-deps.sh - echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH - - - name: Build and test - run: | - BUILD_DEPENDENT_PROGRAMS=1 cargo build --manifest-path ./token/cli/Cargo.toml - cargo test --manifest-path ./token/cli/Cargo.toml diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index badd9244b98..7e730b72183 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -9,6 +9,10 @@ on: paths-ignore: - 'docs/**' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: all_github_action_checks: runs-on: ubuntu-latest @@ -23,44 +27,40 @@ jobs: rustfmt: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set env vars run: | source ci/rust-version.sh - echo "RUST_STABLE=$rust_stable" >> $GITHUB_ENV + echo "RUST_NIGHTLY=$rust_nightly" >> $GITHUB_ENV - - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@master with: - toolchain: ${{ env.RUST_STABLE }} - override: true - profile: minimal + toolchain: ${{ env.RUST_NIGHTLY }} components: rustfmt - name: Run fmt - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all -- --check + run: ./cargo-nightly fmt --all -- --check clippy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + + - name: Remove unneeded packages for more space + run: bash ./ci/warning/purge-ubuntu-runner.sh - name: Set env vars run: | source ci/rust-version.sh echo "RUST_NIGHTLY=$rust_nightly" >> $GITHUB_ENV - - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.RUST_NIGHTLY }} - override: true - profile: minimal components: clippy - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/registry @@ -74,32 +74,24 @@ jobs: run: ./ci/install-build-deps.sh - name: Run clippy - uses: actions-rs/cargo@v1 - with: - command: clippy - args: -Zunstable-options --workspace --all-targets -- --deny=warnings + run: ./cargo-nightly clippy -Zunstable-options --workspace --all-targets --all-features -- --deny=warnings --deny=clippy::arithmetic_side_effects audit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set env vars run: | source ci/rust-version.sh echo "RUST_STABLE=$rust_stable" >> $GITHUB_ENV - - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.RUST_STABLE }} - override: true - profile: minimal - name: Install Cargo Audit - uses: actions-rs/install@v0.1 - with: - crate: cargo-audit - version: latest + run: cargo install cargo-audit --version 0.17.6 - name: Run Cargo Audit run: ./ci/do-audit.sh @@ -107,7 +99,10 @@ jobs: cargo-build-test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + + - name: Remove unneeded packages for more space + run: bash ./ci/warning/purge-ubuntu-runner.sh - name: Set env vars run: | @@ -116,13 +111,11 @@ jobs: source ci/solana-version.sh echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV - - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.RUST_STABLE }} - override: true - profile: minimal - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/registry @@ -130,13 +123,13 @@ jobs: # target # Removed due to build dependency caching conflicts key: cargo-build-${{ hashFiles('**/Cargo.lock') }}-${{ env.RUST_STABLE}} - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/bin/rustfilt - key: cargo-bpf-bins-${{ runner.os }} + key: cargo-sbf-bins-${{ runner.os }} - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: ~/.cache/solana key: solana-${{ env.SOLANA_VERSION }} diff --git a/.github/workflows/spl_action.yml b/.github/workflows/spl_action.yml index 09f7a8eee2a..25f4144b3be 100644 --- a/.github/workflows/spl_action.yml +++ b/.github/workflows/spl_action.yml @@ -5,17 +5,22 @@ on: branches: [master] paths: - 'docs/**' + - '.github/workflows/spl_action.yml' + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 name: "importing all the document" - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v4 with: - node-version: '16' - name: "installing the node.js with version 16" + node-version: '18' + name: "installing the node.js with version 18" - name: "Build Docs" if: ${{ github.event_name == ('push' || 'pull_request')}} && ${{github.ref == 'master'}} run: | @@ -24,3 +29,4 @@ jobs: ./build.sh env: VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} + VERCEL_SCOPE: ${{ secrets.VERCEL_SCOPE }} diff --git a/.gitignore b/.gitignore index a6c0a9961fa..2d6060fdbdd 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ test-ledger docker-target .idea .coderrect +.turbo diff --git a/.mergify.yml b/.mergify.yml index fe43cea03a9..66d7a457fa1 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -6,7 +6,9 @@ pull_request_rules: - name: label changes from community conditions: - - author≠@core-contributors + - author≠@spl-maintainers + - author≠@spl-triage + - author≠@spl-write - author≠mergify[bot] - author≠dependabot[bot] actions: diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000000..6c59086d862 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +enable-pre-post-scripts=true diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000000..7bfa0e8650f --- /dev/null +++ b/.prettierignore @@ -0,0 +1,11 @@ +docs +lib +test-ledger +node_modules +dist +generated +.mypy_cache +*.yml +*.yaml +*.md +*.json diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000000..173a61f766c --- /dev/null +++ b/.prettierrc @@ -0,0 +1,9 @@ +{ + "semi": true, + "singleQuote": true, + "trailingComma": "es5", + "useTabs": false, + "tabWidth": 4, + "arrowParens": "always", + "printWidth": 80 +} diff --git a/Anchor.toml b/Anchor.toml index a9fd4671bc3..5ec1ebb7bf3 100644 --- a/Anchor.toml +++ b/Anchor.toml @@ -1,13 +1,14 @@ -anchor_version = "0.24.2" -solana_version = "1.10.33" +[toolchain] +anchor_version = "0.29.0" +solana_version = "2.1.0" [workspace] members = [ "governance/program", - "memo/program", - "stake-pool/program", - "token/program", - "token/program-2022", + "governance/chat/program", +] +exclude = [ + "account-compression/" ] [provider] @@ -16,6 +17,4 @@ wallet = "~/.config/solana/id.json" [programs.mainnet] spl_governance = "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw" -spl_stake_pool = "SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy" -spl_token = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" -spl_token_2022 = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" +spl_governance_chat = "gCHAtYKrUUktTVzE4hEnZdLV4LXrdBf6Hh9qMaJALET" diff --git a/Cargo.lock b/Cargo.lock index 14ed7c3ca99..cdb00c16039 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,59 +12,109 @@ dependencies = [ "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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[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 = [ - "generic-array 0.14.5", + "crypto-common", + "generic-array 0.14.7", ] [[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 1.0.0", - "cipher 0.3.0", + "cipher", "cpufeatures", - "opaque-debug 0.3.0", ] [[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", - "cipher 0.3.0", + "cipher", "ctr", "polyval", "subtle", "zeroize", ] +[[package]] +name = "agave-geyser-plugin-interface" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9291468d48d46cfe92d7807990e19c6ee9a07b05a75cda5e118f48597e079391" +dependencies = [ + "log", + "solana-sdk", + "solana-transaction-status", + "thiserror 1.0.69", +] + +[[package]] +name = "agave-transaction-view" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a249374d6349eeb31348a849666f3d47cacb18e0e05454fbd11a1fc69fae8e7e" +dependencies = [ + "solana-sdk", + "solana-svm-transaction", +] + [[package]] name = "ahash" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.3", + "getrandom 0.2.10", "once_cell", "version_check", ] +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if 1.0.0", + "getrandom 0.2.10", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "0.7.18" @@ -75,10 +125,13 @@ dependencies = [ ] [[package]] -name = "aliasable" -version = "0.1.3" +name = "aho-corasick" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +dependencies = [ + "memchr", +] [[package]] name = "alloc-no-stdlib" @@ -95,6 +148,27 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "ansi_term" version = "0.12.1" @@ -106,15 +180,29 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.58" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8" + +[[package]] +name = "aquamarine" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" +checksum = "d1da02abba9f9063d786eab1509833ebb2fac0f966862ca59439c76b9c566760" +dependencies = [ + "include_dir", + "itertools 0.10.5", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.107", +] [[package]] name = "arbitrary" -version = "1.0.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "510c76ecefdceada737ea728f4f9a84bd2e1ef29f1ba555e560940fe279954de" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" dependencies = [ "derive_arbitrary", ] @@ -125,17 +213,134 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5d78ce20460b82d3fa150275ed9d55e21064fc7951177baacf86a145c4a4b1f" +[[package]] +name = "ark-bn254" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools 0.10.5", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint 0.4.6", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.107", +] + +[[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.107", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest 0.10.7", + "num-bigint 0.4.6", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + [[package]] name = "arrayref" -version = "0.3.6" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "ascii" @@ -155,8 +360,8 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror", - "time 0.3.9", + "thiserror 1.0.69", + "time", ] [[package]] @@ -165,9 +370,9 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 1.0.107", "synstructure", ] @@ -177,23 +382,9 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", -] - -[[package]] -name = "assert_cmd" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ae1ddd39efd67689deb1979d80bad3bf7f2b09c6e6117c8d1f2443b5e2f83e" -dependencies = [ - "bstr", - "doc-comment", - "predicates", - "predicates-core", - "predicates-tree", - "wait-timeout", + "proc-macro2", + "quote", + "syn 1.0.107", ] [[package]] @@ -202,11 +393,22 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.2", + "futures-core", +] + [[package]] name = "async-compression" -version = "0.3.14" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345fd392ab01f746c717b1357165b76f0b67a60192007b234058c9045fdcf695" +checksum = "f658e2baef915ba0f26f1f7c42bfb8e12f532a01f449a090ded75ae7a07e9ba2" dependencies = [ "brotli", "flate2", @@ -217,12 +419,14 @@ dependencies = [ ] [[package]] -name = "async-mutex" -version = "1.4.0" +name = "async-lock" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ - "event-listener", + "event-listener 5.3.1", + "event-listener-strategy", + "pin-project-lite", ] [[package]] @@ -241,20 +445,20 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 1.0.107", ] [[package]] name = "async-trait" -version = "0.1.53" +version = "0.1.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600" +checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] @@ -263,7 +467,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi 0.3.9", ] @@ -274,40 +478,48 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "autotools" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8138adefca3e5d2e73bfba83bd6eeaf904b26a7ac1b4a19892cfe16cc7e1701" +dependencies = [ + "cc", +] + [[package]] name = "axum" -version = "0.5.1" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47594e438a243791dba58124b6669561f5baa14cb12046641d8008bf035e5a25" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ "async-trait", "axum-core", - "bitflags", + "bitflags 1.3.2", "bytes", "futures-util", "http", "http-body", "hyper", - "itoa 1.0.1", + "itoa", "matchit", "memchr", "mime", - "percent-encoding 2.1.0", + "percent-encoding 2.3.1", "pin-project-lite", + "rustversion", "serde", "sync_wrapper", - "tokio", "tower", - "tower-http", "tower-layer", "tower-service", ] [[package]] name = "axum-core" -version = "0.2.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a671c9ae99531afdd5d3ee8340b8da547779430689947144c140fc74a740244" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" dependencies = [ "async-trait", "bytes", @@ -315,6 +527,9 @@ dependencies = [ "http", "http-body", "mime", + "rustversion", + "tower-layer", + "tower-service", ] [[package]] @@ -324,7 +539,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" dependencies = [ "futures-core", - "getrandom 0.2.3", + "getrandom 0.2.10", "instant", "pin-project-lite", "rand 0.8.5", @@ -332,10 +547,19 @@ dependencies = [ ] [[package]] -name = "base-x" -version = "0.2.8" +name = "backtrace" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if 1.0.0", + "libc", + "miniz_oxide 0.7.1", + "object", + "rustc-demangle", +] [[package]] name = "base64" @@ -350,20 +574,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] -name = "base64ct" -version = "1.5.0" +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea908e7347a8c64e378c17e30ef880ad73e3b4498346b055c2c00ea342f3179" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "binary-option" version = "0.1.0" dependencies = [ "arrayref", - "borsh", + "borsh 1.5.3", "solana-program", - "spl-token 3.3.1", - "thiserror", + "spl-token 7.0.0", + "thiserror 2.0.9", "uint", ] @@ -378,37 +608,38 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.59.2" +version = "0.69.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" +checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" dependencies = [ - "bitflags", + "bitflags 2.6.0", "cexpr", "clang-sys", + "itertools 0.12.1", "lazy_static", "lazycell", - "peeking_take_while", - "proc-macro2 1.0.36", - "quote 1.0.14", + "proc-macro2", + "quote", "regex", - "rustc-hash", + "rustc-hash 1.1.0", "shlex", + "syn 2.0.87", ] [[package]] name = "bit-set" -version = "0.5.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" -version = "0.6.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitflags" @@ -416,6 +647,15 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] + [[package]] name = "bitmaps" version = "2.1.0" @@ -427,16 +667,16 @@ dependencies = [ [[package]] name = "blake3" -version = "1.3.1" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f" +checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" dependencies = [ "arrayref", "arrayvec", "cc", "cfg-if 1.0.0", "constant_time_eq", - "digest 0.10.3", + "digest 0.10.7", ] [[package]] @@ -445,7 +685,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" dependencies = [ - "block-padding 0.1.5", + "block-padding", "byte-tools", "byteorder", "generic-array 0.12.4", @@ -457,17 +697,16 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "block-padding 0.2.1", - "generic-array 0.14.5", + "generic-array 0.14.7", ] [[package]] name = "block-buffer" -version = "0.10.2" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array 0.14.5", + "generic-array 0.14.7", ] [[package]] @@ -480,54 +719,71 @@ dependencies = [ ] [[package]] -name = "block-padding" -version = "0.2.1" +name = "borsh" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" +checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" +dependencies = [ + "borsh-derive 0.10.3", + "hashbrown 0.13.2", +] [[package]] name = "borsh" -version = "0.9.3" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" +checksum = "2506947f73ad44e344215ccd6403ac2ae18cd8e046e581a441bf8d199f257f03" dependencies = [ - "borsh-derive", - "hashbrown", + "borsh-derive 1.5.3", + "cfg_aliases", ] [[package]] name = "borsh-derive" -version = "0.9.3" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" +checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" dependencies = [ "borsh-derive-internal", "borsh-schema-derive-internal", "proc-macro-crate 0.1.5", - "proc-macro2 1.0.36", - "syn 1.0.91", + "proc-macro2", + "syn 1.0.107", +] + +[[package]] +name = "borsh-derive" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2593a3b8b938bd68373196c9832f516be11fa487ef4ae745eb282e6a56a7244" +dependencies = [ + "once_cell", + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] name = "borsh-derive-internal" -version = "0.9.3" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" +checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 1.0.107", ] [[package]] name = "borsh-schema-derive-internal" -version = "0.9.3" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" +checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 1.0.107", ] [[package]] @@ -553,9 +809,12 @@ dependencies = [ [[package]] name = "bs58" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] [[package]] name = "bstr" @@ -563,16 +822,14 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ - "lazy_static", "memchr", - "regex-automata", ] [[package]] name = "bumpalo" -version = "3.8.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bv" @@ -592,41 +849,41 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "bytemuck" -version = "1.8.0" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e851ca7c24871e7336801608a4797d7376545b6928a10d32d75685687141ead" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.1.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562e382481975bc61d11275ac5e62a19abd00b0547d99516a415336f183dcd0e" +checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.1.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "bzip2" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6afcd980b5f3a45017c57e57a2fcccbb351cc43a356ce117ef760ef8052b89b0" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" dependencies = [ "bzip2-sys", "libc", @@ -645,13 +902,12 @@ dependencies = [ [[package]] name = "caps" -version = "0.5.3" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61bf7211aad104ce2769ec05efcdfabf85ee84ac92461d142f22cf8badd0e54c" +checksum = "190baaad529bcfbde9e1a19022c42781bdb6ff9de25721abdb8fd98c0807730b" dependencies = [ - "errno", "libc", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -660,28 +916,36 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9344318b9c787667b95cd2c5124f5eaf2bde35e959dd01ea04fc5b234c542c11" dependencies = [ - "clap", + "clap 2.34.0", "heck 0.3.3", - "indexmap", + "indexmap 1.9.3", "log", - "proc-macro2 1.0.36", - "quote 1.0.14", + "proc-macro2", + "quote", "serde", "serde_json", - "syn 1.0.91", + "syn 1.0.107", "tempfile", "toml", ] [[package]] name = "cc" -version = "1.0.72" +version = "1.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" +checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" dependencies = [ "jobserver", + "libc", + "shlex", ] +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cexpr" version = "0.6.0" @@ -703,6 +967,23 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "cfg_eval" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "cgen" version = "0.1.0" @@ -712,41 +993,33 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.19" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ - "libc", - "num-integer", + "android-tzdata", + "iana-time-zone", + "js-sys", "num-traits", "serde", - "time 0.1.44", - "winapi 0.3.9", + "wasm-bindgen", + "windows-targets 0.52.6", ] [[package]] name = "chrono-humanize" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eddc119501d583fd930cb92144e605f44e0252c38dd89d9247fffa1993375cb" +checksum = "799627e6b4d27827a814e837b9d8a504832086081806d45b1afa34dc982b023b" dependencies = [ "chrono", ] [[package]] name = "cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" -dependencies = [ - "generic-array 0.14.5", -] - -[[package]] -name = "cipher" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common", "inout", @@ -771,20 +1044,46 @@ checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "ansi_term", "atty", - "bitflags", + "bitflags 1.3.2", "strsim 0.8.0", - "textwrap", - "unicode-width", + "textwrap 0.11.0", + "unicode-width 0.1.9", "vec_map", ] [[package]] -name = "cmake" -version = "0.1.48" +name = "clap" +version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ - "cc", + "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", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width 0.1.9", ] [[package]] @@ -801,33 +1100,35 @@ dependencies = [ ] [[package]] -name = "console" -version = "0.14.1" +name = "combine" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3993e6445baa160675931ec041a5e03ca84b9c6e32a056150d3aa2bdda0a1f45" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ - "encode_unicode", - "lazy_static", - "libc", - "regex", - "terminal_size", - "unicode-width", - "winapi 0.3.9", + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", ] [[package]] name = "console" -version = "0.15.0" +version = "0.15.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28b32d32ca44b70c3e4acd7db1babf555fa026e385fb95f18028f88848b3c31" +checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" dependencies = [ "encode_unicode", "libc", "once_cell", - "regex", - "terminal_size", - "unicode-width", - "winapi 0.3.9", + "unicode-width 0.2.0", + "windows-sys 0.59.0", ] [[package]] @@ -842,31 +1143,19 @@ dependencies = [ [[package]] name = "console_log" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501a375961cef1a0d44767200e66e4a559283097e91d0730b1d75dfb2f8a1494" +checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f" dependencies = [ "log", "web-sys", ] -[[package]] -name = "const-oid" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" - -[[package]] -name = "const_fn" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" - [[package]] name = "constant_time_eq" -version = "0.1.5" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" [[package]] name = "convert_case" @@ -904,9 +1193,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.1" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] @@ -922,11 +1211,10 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.1" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ - "cfg-if 1.0.0", "crossbeam-utils", ] @@ -950,19 +1238,15 @@ dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", "lazy_static", - "memoffset", + "memoffset 0.6.5", "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.5" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" -dependencies = [ - "cfg-if 1.0.0", - "lazy_static", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crunchy" @@ -972,11 +1256,12 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-common" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array 0.14.5", + "generic-array 0.14.7", + "rand_core 0.6.4", "typenum", ] @@ -986,38 +1271,110 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ - "generic-array 0.14.5", + "generic-array 0.14.7", "subtle", ] [[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 0.3.0", + "cipher", ] [[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 1.0.0", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rand_core 0.6.4", + "rustc_version", "serde", "subtle", "zeroize", ] +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "cxx" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b7d4e43b25d3c994662706a1d4fcfc32aaa6afd287502c111b237093bb23f3a" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84f8829ddc213e2c1368e51a2564c552b65a8cb6a28f31e576270ac81d5e5827" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn 1.0.107", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e72537424b474af1460806647c41d4b6d35d09ef7fe031c5c2fa5766047cc56a" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "309e4fb93eed90e1e14bea0da16b209f81813ba9fc7830c20ed151dd7bc0a4d7" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.107", +] + [[package]] name = "darling" -version = "0.13.4" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" dependencies = [ "darling_core", "darling_macro", @@ -1025,37 +1382,40 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.13.4" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.36", - "quote 1.0.14", + "proc-macro2", + "quote", "strsim 0.10.0", - "syn 1.0.91", + "syn 2.0.87", ] [[package]] name = "darling_macro" -version = "0.13.4" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", - "quote 1.0.14", - "syn 1.0.91", + "quote", + "syn 2.0.87", ] [[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 1.0.0", - "num_cpus", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core 0.9.9", "rayon", ] @@ -1065,15 +1425,6 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" -[[package]] -name = "der" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" -dependencies = [ - "const-oid", -] - [[package]] name = "der-parser" version = "8.1.0" @@ -1083,11 +1434,20 @@ dependencies = [ "asn1-rs", "displaydoc", "nom", - "num-bigint 0.4.3", + "num-bigint 0.4.6", "num-traits", "rusticata-macros", ] +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + [[package]] name = "derivation-path" version = "0.2.0" @@ -1100,20 +1460,20 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 1.0.107", ] [[package]] name = "derive_arbitrary" -version = "1.0.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b24629208e87a2d8b396ff43b15c4afb0a69cea3fbbaa9ed9b92b7c02f0aed73" +checksum = "d475dfebcb4854d596b17b09f477616f80f17a550517f2b3615d8c205d5c802b" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] @@ -1123,19 +1483,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ "convert_case", - "proc-macro2 1.0.36", - "quote 1.0.14", - "rustc_version 0.4.0", - "syn 1.0.91", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.107", ] [[package]] name = "dialoguer" -version = "0.10.0" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d6b4fabcd9e97e1df1ae15395ac7e49fb144946a0d453959dc2696273b9da" +checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87" dependencies = [ - "console 0.15.0", + "console", + "shell-words", "tempfile", "zeroize", ] @@ -1161,25 +1522,25 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array 0.14.5", + "generic-array 0.14.7", ] [[package]] name = "digest" -version = "0.10.3" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.2", + "block-buffer 0.10.4", "crypto-common", "subtle", ] [[package]] name = "dir-diff" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2860407d7d7e2e004bb2128510ad9e8d669e76fa005ccf567977b5d71b8b4a0b" +checksum = "a7ad16bf5f84253b50d6557681c58c3ab67c47c77d39fed9aeb56e947290bd10" dependencies = [ "walkdir", ] @@ -1205,51 +1566,51 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "discard" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" - [[package]] name = "displaydoc" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 1.0.107", ] [[package]] -name = "dlopen" -version = "0.1.8" +name = "dlopen2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e80ad39f814a9abe68583cd50a2d45c8a67561c3361ab8da240587dda80937" +checksum = "09b4f5f101177ff01b8ec4ecc81eead416a8aa42819a2869311b3420fa114ffa" dependencies = [ - "dlopen_derive", - "lazy_static", + "dlopen2_derive", "libc", + "once_cell", "winapi 0.3.9", ] [[package]] -name = "dlopen_derive" -version = "0.1.4" +name = "dlopen2_derive" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f236d9e1b1fbd81cea0f9cbdc8dcc7e8ebcd80e6659cd7cb2ad5f6c05946c581" +checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" dependencies = [ - "libc", - "quote 0.6.13", - "syn 0.15.44", + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] -name = "doc-comment" -version = "0.3.3" +name = "downcast" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" + +[[package]] +name = "eager" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +checksum = "abe71d579d1812060163dff96056261deb5bf6729b100fa2e36a68b9649ba3d3" [[package]] name = "ed25519" @@ -1266,11 +1627,11 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ - "curve25519-dalek", + "curve25519-dalek 3.2.0", "ed25519", "rand 0.7.3", "serde", - "sha2 0.9.8", + "sha2 0.9.9", "zeroize", ] @@ -1283,7 +1644,7 @@ dependencies = [ "derivation-path", "ed25519-dalek", "hmac 0.12.1", - "sha2 0.10.2", + "sha2 0.10.8", ] [[package]] @@ -1293,22 +1654,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f86b50932a01e7ec5c06160492ab660fb19b6bb2a7878030dd6cd68d21df9d4d" dependencies = [ "enum-ordinalize", - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 1.0.107", ] [[package]] name = "either" -version = "1.6.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "encode_unicode" -version = "0.3.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "encoding_rs" @@ -1321,22 +1682,22 @@ dependencies = [ [[package]] name = "enum-iterator" -version = "0.7.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eeac5c5edb79e4e39fe8439ef35207780a11f69c52cbe424ce3dfad4cb78de6" +checksum = "9fd242f399be1da0a5354aa462d57b4ab2b4ee0683cc552f7c007d2d12d36e94" dependencies = [ "enum-iterator-derive", ] [[package]] name = "enum-iterator-derive" -version = "0.7.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c134c37760b27a871ba422106eedbb8247da973a09e82558bf26d619c882b159" +checksum = "03cdc46ec28bd728e67540c528013c6a10eb69a02eb31078a1bda695438cbfb8" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] @@ -1345,30 +1706,30 @@ version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b166c9e378360dd5a6666a9604bb4f54ae0cac39023ffbac425e917a2a04fef" dependencies = [ - "num-bigint 0.4.3", + "num-bigint 0.4.6", "num-traits", - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 1.0.107", ] [[package]] name = "enum_dispatch" -version = "0.3.8" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eb359f1476bf611266ac1f5355bc14aeca37b299d0ebccc038ee7058891c9cb" +checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" dependencies = [ "once_cell", - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] name = "env_logger" -version = "0.9.0" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" dependencies = [ "atty", "humantime", @@ -1378,38 +1739,34 @@ dependencies = [ ] [[package]] -name = "errno" -version = "0.2.8" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" -dependencies = [ - "errno-dragonfly", - "libc", - "winapi 0.3.9", -] +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "errno-dragonfly" -version = "0.1.2" +name = "errno" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "cc", "libc", + "windows-sys 0.52.0", ] [[package]] name = "etcd-client" -version = "0.8.2" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3bfae4cb9cd8c3c2a552d45e155cafd079f385a3b9421b9a010878f44531f1e" +checksum = "f4b0ea5ef6dc2388a4b1669fa32097249bc03a15417b97cb75e38afb309e4a89" dependencies = [ "http", - "prost 0.9.0", + "prost", "tokio", "tokio-stream", - "tonic 0.6.2", - "tonic-build 0.6.2", + "tonic", + "tonic-build", + "tower", "tower-service", ] @@ -1419,6 +1776,27 @@ version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71" +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener 5.3.1", + "pin-project-lite", +] + [[package]] name = "fake-simd" version = "0.1.2" @@ -1436,12 +1814,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "1.7.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" -dependencies = [ - "instant", -] +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "feature-probe" @@ -1449,6 +1824,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "filetime" version = "0.2.15" @@ -1457,10 +1838,25 @@ checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall", + "redox_syscall 0.2.10", "winapi 0.3.9", ] +[[package]] +name = "five8_const" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b4f62f0f8ca357f93ae90c8c2dd1041a1f665fde2f889ea9b1787903829015" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94474d15a76982be62ca8a39570dccce148d98c238ebb7408b0a21b2c4bdddc4" + [[package]] name = "fixedbitset" version = "0.4.1" @@ -1473,19 +1869,26 @@ version = "1.0.0" dependencies = [ "arrayref", "solana-program", - "spl-token 3.3.1", + "spl-token 7.0.0", ] [[package]] name = "flate2" -version = "1.0.23" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ - "cfg-if 1.0.0", "crc32fast", - "libc", - "miniz_oxide", + "miniz_oxide 0.8.0", +] + +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", ] [[package]] @@ -1511,19 +1914,24 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.0.1" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ - "matches", - "percent-encoding 2.1.0", + "percent-encoding 2.3.1", ] +[[package]] +name = "fragile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" + [[package]] name = "fs_extra" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "futures" @@ -1533,9 +1941,9 @@ checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" [[package]] name = "futures" -version = "0.3.21" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -1548,9 +1956,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.21" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -1558,15 +1966,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.21" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -1576,38 +1984,44 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.21" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.21" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] name = "futures-sink" -version = "0.3.21" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.21" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[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.21" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures 0.1.31", "futures-channel", @@ -1622,15 +2036,6 @@ dependencies = [ "slab", ] -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - [[package]] name = "generic-array" version = "0.12.4" @@ -1642,9 +2047,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.5" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "serde", "typenum", @@ -1676,15 +2081,23 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.3" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if 1.0.0", + "js-sys", "libc", - "wasi 0.10.0+wasi-snapshot-preview1", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", ] +[[package]] +name = "gimli" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" + [[package]] name = "glob" version = "0.3.0" @@ -1697,7 +2110,7 @@ version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10463d9ff00a2a068db14231982f5132edebad0d7660cd956a1c30292dbcbfbd" dependencies = [ - "aho-corasick", + "aho-corasick 0.7.18", "bstr", "fnv", "log", @@ -1706,12 +2119,12 @@ dependencies = [ [[package]] name = "goauth" -version = "0.11.1" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f3d68c8343245dc047982651b5afb8bd659c9959ed72efe5a73bf22684e5fd" +checksum = "f8af59a261bcf42f45d1b261232847b9b850ba0a1419d6100698246fb66e9240" dependencies = [ "arc-swap", - "futures 0.3.21", + "futures 0.3.31", "log", "reqwest", "serde", @@ -1719,26 +2132,35 @@ dependencies = [ "serde_json", "simpl", "smpl_jwt", - "time 0.3.9", + "time", "tokio", ] [[package]] -name = "goblin" -version = "0.4.3" +name = "governor" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32401e89c6446dcd28185931a01b1093726d0356820ac744023e6850689bf926" +checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b" dependencies = [ - "log", - "plain", - "scroll", + "cfg-if 1.0.0", + "dashmap", + "futures 0.3.31", + "futures-timer", + "no-std-compat", + "nonzero_ext", + "parking_lot 0.12.0", + "portable-atomic", + "quanta", + "rand 0.8.5", + "smallvec", + "spinning_top", ] [[package]] name = "h2" -version = "0.3.13" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", @@ -1746,7 +2168,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 2.6.0", "slab", "tokio", "tokio-util 0.7.1", @@ -1755,30 +2177,55 @@ dependencies = [ [[package]] name = "hash32" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4041af86e63ac4298ce40e5cca669066e75b6f1aa3390fe2561ffa5e1d9f4cc" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" 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", + "ahash 0.7.8", ] [[package]] -name = "headers" -version = "0.3.7" +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.11", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash 0.8.11", + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" + +[[package]] +name = "headers" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cff78e5788be1e0ab65b04d306b2ed5092c815ec97ec70f4ebd5aee158aa55d" dependencies = [ "base64 0.13.0", - "bitflags", + "bitflags 1.3.2", "bytes", "headers-core", "http", @@ -1807,9 +2254,9 @@ dependencies = [ [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -1820,6 +2267,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "hex" version = "0.4.3" @@ -1828,13 +2281,15 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hidapi" -version = "1.4.1" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b1717343691998deb81766bfcd1dce6df0d5d6c37070b5a3de2bb6d39f7822" +checksum = "03b876ecf37e86b359573c16c8366bc3eba52b689884a0fc42ba3f67203d2a8b" dependencies = [ "cc", + "cfg-if 1.0.0", "libc", "pkg-config", + "windows-sys 0.48.0", ] [[package]] @@ -1859,7 +2314,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.3", + "digest 0.10.7", ] [[package]] @@ -1869,54 +2324,49 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" dependencies = [ "digest 0.9.0", - "generic-array 0.14.5", + "generic-array 0.14.7", "hmac 0.8.1", ] [[package]] name = "honggfuzz" -version = "0.5.54" +version = "0.5.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea09577d948a98a5f59b7c891e274c4fb35ad52f67782b3d0cb53b9c05301f1" +checksum = "7c76b6234c13c9ea73946d1379d33186151148e0da231506b964b44f3d023505" dependencies = [ "arbitrary", "lazy_static", - "memmap", + "memmap2 0.9.4", + "rustc_version", ] [[package]] name = "http" -version = "0.2.6" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", - "itoa 1.0.1", + "itoa", ] [[package]] name = "http-body" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", "http", "pin-project-lite", ] -[[package]] -name = "http-range-header" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" - [[package]] name = "httparse" -version = "1.5.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" @@ -1932,9 +2382,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.16" +version = "0.14.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55" +checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" dependencies = [ "bytes", "futures-channel", @@ -1945,7 +2395,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa 0.4.8", + "itoa", "pin-project-lite", "socket2", "tokio", @@ -1961,7 +2411,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca815a891b24fdfb243fa3239c86154392b0953ee584aa1a2a1f66d20cbe75cc" dependencies = [ "bytes", - "futures 0.3.21", + "futures 0.3.31", "headers", "http", "hyper", @@ -1974,15 +2424,16 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.23.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" +checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" dependencies = [ + "futures-util", "http", "hyper", - "rustls 0.20.4", + "rustls 0.21.12", "tokio", - "tokio-rustls 0.23.2", + "tokio-rustls", ] [[package]] @@ -2010,6 +2461,30 @@ dependencies = [ "tokio-native-tls", ] +[[package]] +name = "iana-time-zone" +version = "0.1.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5a6ef98976b22b3b7f2f3a806f858cb862044cfa66805aa3ad84cb3d3b785ed" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "winapi 0.3.9", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -2029,11 +2504,10 @@ dependencies = [ [[package]] name = "idna" -version = "0.2.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ - "matches", "unicode-bidi", "unicode-normalization", ] @@ -2051,7 +2525,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" dependencies = [ "bitmaps", - "rand_core 0.6.3", + "rand_core 0.6.4", "rand_xoshiro", "rayon", "serde", @@ -2061,64 +2535,71 @@ dependencies = [ ] [[package]] -name = "index_list" -version = "0.2.7" +name = "include_dir" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9d968042a4902e08810946fc7cd5851eb75e80301342305af755ca06cb82ce" +checksum = "18762faeff7122e89e0857b02f7ce6fcc0d101d5e9ad2ad7846cc01d61b7f19e" +dependencies = [ + "include_dir_macros", +] [[package]] -name = "indexmap" -version = "1.8.1" +name = "include_dir_macros" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" dependencies = [ - "autocfg", - "hashbrown", - "rayon", + "proc-macro2", + "quote", ] [[package]] -name = "indicatif" -version = "0.16.2" +name = "index_list" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e6ba961c14e98151cd6416dd3685efe786a94c38bc1a535c06ceff0a1600813" + +[[package]] +name = "indexmap" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d207dc617c7a380ab07ff572a6e52fa202a2a8f355860ac9c38e23f8196be1b" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ - "console 0.15.0", - "lazy_static", - "number_prefix", - "regex", + "autocfg", + "hashbrown 0.12.3", ] [[package]] -name = "indoc" -version = "0.3.6" +name = "indexmap" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47741a8bc60fb26eb8d6e0238bbb26d8575ff623fdc97b1a2c00c050b9684ed8" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ - "indoc-impl", - "proc-macro-hack", + "equivalent", + "hashbrown 0.15.1", + "rayon", ] [[package]] -name = "indoc-impl" -version = "0.3.6" +name = "indicatif" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce046d161f000fffde5f432a0d034d0341dc152643b2598ed5bfce44c4f3a8f0" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" dependencies = [ - "proc-macro-hack", - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", - "unindent", + "console", + "instant", + "number_prefix", + "portable-atomic", + "unicode-width 0.1.9", ] [[package]] name = "inout" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1f03d4ab4d5dc9ec2d219f86c15d2a15fc08239d1cd3b2d6a19717c0a2f443" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" dependencies = [ - "generic-array 0.14.5", + "generic-array 0.14.7", ] [[package]] @@ -2138,39 +2619,62 @@ checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" [[package]] name = "itertools" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] [[package]] -name = "itoa" -version = "0.4.8" +name = "itertools" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] [[package]] name = "itoa" -version = "1.0.1" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine 4.6.7", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.24" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.57" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] @@ -2193,7 +2697,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2b99d4207e2a04fb4581746903c2bb7eb376f88de9c699d0f3e10feeac0cd3a" dependencies = [ "derive_more", - "futures 0.3.21", + "futures 0.3.31", "jsonrpc-core", "jsonrpc-pubsub", "log", @@ -2208,7 +2712,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" dependencies = [ - "futures 0.3.21", + "futures 0.3.31", "futures-executor", "futures-util", "log", @@ -2223,7 +2727,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b51da17abecbdab3e3d4f26b01c5ec075e88d3abe3ab3b05dc9aa69392764ec0" dependencies = [ - "futures 0.3.21", + "futures 0.3.31", "jsonrpc-client-transports", ] @@ -2234,9 +2738,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b939a78fa820cdfcb7ee7484466746a7377760970f6f9c6fe19f9edcc8a38d2" dependencies = [ "proc-macro-crate 0.1.5", - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 1.0.107", ] [[package]] @@ -2245,7 +2749,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1dea6e07251d9ce6a552abfb5d7ad6bc290a4596c8dcc3d795fae2bbdc1f3ff" dependencies = [ - "futures 0.3.21", + "futures 0.3.31", "hyper", "jsonrpc-core", "jsonrpc-server-utils", @@ -2261,7 +2765,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240f87695e6c6f62fb37f05c02c04953cf68d6408b8c1c89de85c7a0125b1011" dependencies = [ - "futures 0.3.21", + "futures 0.3.31", "jsonrpc-core", "lazy_static", "log", @@ -2277,7 +2781,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa4fdea130485b572c39a460d50888beb00afb3e35de23ccd7fad8ff19f0e0d4" dependencies = [ "bytes", - "futures 0.3.21", + "futures 0.3.31", "globset", "jsonrpc-core", "lazy_static", @@ -2290,9 +2794,12 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.0" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +dependencies = [ + "cpufeatures", +] [[package]] name = "kernel32-sys" @@ -2304,11 +2811,20 @@ dependencies = [ "winapi-build", ] +[[package]] +name = "lazy-lru" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b031495510a5a17bfb14e9f1fc00f6efdebfaa9ab04a876a4e153b042a3fe06" +dependencies = [ + "hashbrown 0.14.5", +] + [[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 = "lazycell" @@ -2318,15 +2834,15 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.124" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "libloading" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" dependencies = [ "cfg-if 1.0.0", "winapi 0.3.9", @@ -2334,15 +2850,15 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.2" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33a33a362ce288760ec6a508b94caaec573ae7d3bbbd91b87aa0bad4456839db" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "librocksdb-sys" -version = "0.6.1+6.28.2" +version = "0.16.0+8.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bc587013734dadb7cf23468e531aa120788b87243648be42e2d3a072186291" +checksum = "ce3d60bc059831dc1c83903fb45c103f75db65c5a7bf22272764d9cc683e348c" dependencies = [ "bindgen", "bzip2-sys", @@ -2350,6 +2866,7 @@ dependencies = [ "glob", "libc", "libz-sys", + "lz4-sys", ] [[package]] @@ -2367,7 +2884,7 @@ dependencies = [ "libsecp256k1-gen-genmult", "rand 0.7.3", "serde", - "sha2 0.9.8", + "sha2 0.9.9", "typenum", ] @@ -2412,53 +2929,71 @@ dependencies = [ ] [[package]] -name = "linked-hash-map" -version = "0.5.4" +name = "light-poseidon" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" +checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" +dependencies = [ + "ark-bn254", + "ark-ff", + "num-bigint 0.4.6", + "thiserror 1.0.69", +] [[package]] -name = "lock_api" -version = "0.4.6" +name = "link-cplusplus" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" +checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" dependencies = [ - "scopeguard", + "cc", ] [[package]] -name = "log" +name = "linux-raw-sys" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ - "cfg-if 1.0.0", + "autocfg", + "scopeguard", ] +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + [[package]] name = "lru" -version = "0.7.5" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32613e41de4c47ab04970c348ca7ae7382cf116625755af070b008a15516a889" +checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a" dependencies = [ - "hashbrown", + "hashbrown 0.12.3", ] [[package]] name = "lz4" -version = "1.23.3" +version = "1.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4edcb94251b1c375c459e5abe9fb0168c1c826c3370172684844f8f3f8d1a885" +checksum = "4d1febb2b4a79ddd1980eede06a8f7902197960aa0383ffcfdd62fe723036725" dependencies = [ - "libc", "lz4-sys", ] [[package]] name = "lz4-sys" -version = "1.9.3" +version = "1.11.1+lz4-1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7be8908e2ed6f31c02db8a9fa962f03e36c53fbfde437363eae3306b85d7e17" +checksum = "6bd8c0d6c6ed0cd30b3652886bb8711dc4bb01d637a68105a3d5158039b418e6" dependencies = [ "cc", "libc", @@ -2472,37 +3007,36 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" [[package]] name = "matches" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "matchit" -version = "0.5.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" +checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" [[package]] name = "memchr" -version = "2.4.1" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] -name = "memmap" -version = "0.7.0" +name = "memmap2" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" dependencies = [ "libc", - "winapi 0.3.9", ] [[package]] name = "memmap2" -version = "0.5.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057a3db23999c867821a7a59feb06a578fcb03685e983dff90daf9e7d24ac08f" +checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" dependencies = [ "libc", ] @@ -2516,6 +3050,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + [[package]] name = "merlin" version = "3.0.0" @@ -2524,46 +3067,26 @@ checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" dependencies = [ "byteorder", "keccak", - "rand_core 0.6.3", + "rand_core 0.6.4", "zeroize", ] [[package]] -name = "metaplex-token-metadata" -version = "0.0.1" +name = "mime" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abcc939f0afdc6db054b9998a1292d0a016244b382462e61cfc7c570624982cb" -dependencies = [ - "arrayref", - "borsh", - "metaplex-token-vault", - "num-derive", - "num-traits", - "solana-program", - "spl-token 3.3.0", - "thiserror", -] +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" [[package]] -name = "metaplex-token-vault" -version = "0.0.1" +name = "mime_guess" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5211991ba3273df89cd5e0f6f558bc8d7453c87c0546f915b4a319e1541df33" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" dependencies = [ - "borsh", - "num-derive", - "num-traits", - "solana-program", - "spl-token 3.3.0", - "thiserror", + "mime", + "unicase", ] -[[package]] -name = "mime" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" - [[package]] name = "min-max-heap" version = "1.3.0" @@ -2578,86 +3101,80 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.5.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ "adler", ] [[package]] -name = "mio" -version = "0.7.14" +name = "miniz_oxide" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "libc", - "log", - "miow", - "ntapi", - "winapi 0.3.9", + "adler2", ] [[package]] -name = "miow" -version = "0.3.7" +name = "mio" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" dependencies = [ - "winapi 0.3.9", + "hermit-abi 0.3.9", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", ] [[package]] -name = "modular-bitfield" -version = "0.11.2" +name = "mockall" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a53d79ba8304ac1c4f9eb3b9d281f21f7be9d4626f72ce7df4ad8fbde4f38a74" +checksum = "4c84490118f2ee2d74570d114f3d0493cbf02790df303d2707606c3e14e07c96" dependencies = [ - "modular-bitfield-impl", - "static_assertions", + "cfg-if 1.0.0", + "downcast", + "fragile", + "lazy_static", + "mockall_derive", + "predicates", + "predicates-tree", ] [[package]] -name = "modular-bitfield-impl" -version = "0.11.2" +name = "mockall_derive" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a7d5f7076603ebc68de2dc6a650ec331a062a13abaa346975be747bbfa4b789" +checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "cfg-if 1.0.0", + "proc-macro2", + "quote", + "syn 1.0.107", ] [[package]] -name = "mpl-token-metadata" -version = "1.3.1" +name = "modular-bitfield" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8b06b6275bd3f6444e22b03de7bdf6145ee6d6fa3e14415ddd317473b9ef807" +checksum = "a53d79ba8304ac1c4f9eb3b9d281f21f7be9d4626f72ce7df4ad8fbde4f38a74" dependencies = [ - "arrayref", - "borsh", - "mpl-token-vault", - "num-derive", - "num-traits", - "shank", - "solana-program", - "spl-associated-token-account 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-token 3.3.0", - "thiserror", + "modular-bitfield-impl", + "static_assertions", ] [[package]] -name = "mpl-token-vault" -version = "0.1.0" +name = "modular-bitfield-impl" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ade4ef15bc06a6033076c4ff28cba9b42521df5ec61211d6f419415ace2746a" +checksum = "5a7d5f7076603ebc68de2dc6a650ec331a062a13abaa346975be747bbfa4b789" dependencies = [ - "borsh", - "num-derive", - "num-traits", - "solana-program", - "spl-token 3.3.0", - "thiserror", + "proc-macro2", + "quote", + "syn 1.0.107", ] [[package]] @@ -2697,17 +3214,23 @@ dependencies = [ [[package]] name = "nix" -version = "0.23.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags", - "cc", + "bitflags 2.6.0", "cfg-if 1.0.0", + "cfg_aliases", "libc", - "memoffset", + "memoffset 0.9.0", ] +[[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.1" @@ -2719,13 +3242,16 @@ dependencies = [ ] [[package]] -name = "ntapi" -version = "0.3.6" +name = "nonzero_ext" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" -dependencies = [ - "winapi 0.3.9", -] +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" @@ -2754,11 +3280,10 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.3" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "autocfg", "num-integer", "num-traits", ] @@ -2773,24 +3298,29 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-derive" -version = "0.3.3" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] name = "num-integer" -version = "0.1.44" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] @@ -2819,52 +3349,43 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.14" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] name = "num_cpus" -version = "1.13.1" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", ] [[package]] name = "num_enum" -version = "0.5.5" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "085fe377a4b2805c0fbc09484415ec261174614b7f080b0e0d520456ac421a67" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ - "derivative", "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5249369707a1e07b39f78d98c8f34e00aca7dcb053812fdbb5ad7be82c1bba38" -dependencies = [ - "proc-macro-crate 1.1.0", - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", -] - -[[package]] -name = "num_threads" -version = "0.1.5" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aba1801fb138d8e85e11d0fc70baf4fe1cdfffda7c6cd34a854905df588e5ed0" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "libc", + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] @@ -2873,6 +3394,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + [[package]] name = "oid-registry" version = "0.6.0" @@ -2884,9 +3414,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.9.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" @@ -2902,18 +3432,30 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.38" +version = "0.10.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ - "bitflags", + "bitflags 2.6.0", "cfg-if 1.0.0", "foreign-types", "libc", "once_cell", + "openssl-macros", "openssl-sys", ] +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.107", +] + [[package]] name = "openssl-probe" version = "0.1.5" @@ -2922,20 +3464,19 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "111.22.0+1.1.1q" +version = "300.3.1+3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f31f0d509d1c1ae9cada2f9539ff8f37933831fd5098879e482aa687d659853" +checksum = "7259953d42a81bf137fbbd73bd30a8e1914d6dce43c2b90ed575783a22608b91" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.72" +version = "0.9.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" dependencies = [ - "autocfg", "cc", "libc", "openssl-src", @@ -2945,44 +3486,34 @@ dependencies = [ [[package]] name = "opentelemetry" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf9b1c4e9a6c4de793c632496fa490bdc0e1eea73f0c91394f7b6990935d22" +checksum = "6105e89802af13fdf48c49d7646d3b533a70e536d818aae7e78ba0433d01acb8" dependencies = [ "async-trait", "crossbeam-channel", - "futures 0.3.21", + "futures-channel", + "futures-executor", + "futures-util", "js-sys", "lazy_static", - "percent-encoding 2.1.0", + "percent-encoding 2.3.1", "pin-project", "rand 0.8.5", - "thiserror", + "thiserror 1.0.69", ] [[package]] -name = "ouroboros" -version = "0.14.2" +name = "os_str_bytes" +version = "6.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71643f290d126e18ac2598876d01e1d57aed164afc78fdb6e2a0c6589a1f6662" -dependencies = [ - "aliasable", - "ouroboros_macro", - "stable_deref_trait", -] +checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" [[package]] -name = "ouroboros_macro" -version = "0.14.2" +name = "parking" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9a247206016d424fe8497bc611e510887af5c261fbbf977877c4bb55ca4d82" -dependencies = [ - "Inflector", - "proc-macro-error", - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", -] +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -3002,7 +3533,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" dependencies = [ "lock_api", - "parking_lot_core 0.9.2", + "parking_lot_core 0.9.9", ] [[package]] @@ -3014,42 +3545,29 @@ dependencies = [ "cfg-if 1.0.0", "instant", "libc", - "redox_syscall", + "redox_syscall 0.2.10", "smallvec", "winapi 0.3.9", ] [[package]] name = "parking_lot_core" -version = "0.9.2" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "995f667a6c822200b0433ac218e05582f0e2efa1b922a3fd2fbaadc5f87bab37" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall", + "redox_syscall 0.4.1", "smallvec", - "windows-sys", + "windows-targets 0.48.0", ] [[package]] name = "paste" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880" -dependencies = [ - "paste-impl", - "proc-macro-hack", -] - -[[package]] -name = "paste-impl" -version = "0.1.18" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6" -dependencies = [ - "proc-macro-hack", -] +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" [[package]] name = "pbkdf2" @@ -3062,24 +3580,18 @@ dependencies = [ [[package]] name = "pbkdf2" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271779f35b581956db91a3e55737327a03aa051e90b1c47aeb189508533adfd7" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ - "digest 0.10.3", + "digest 0.10.7", ] -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - [[package]] name = "pem" -version = "1.0.2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9a3b09a20e374558580a4914d3b7d89bd61b954a5a5e1dcbea98753addb1947" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" dependencies = [ "base64 0.13.0", ] @@ -3092,9 +3604,9 @@ checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" [[package]] name = "percent-encoding" -version = "2.1.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "percentage" @@ -3132,9 +3644,9 @@ checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 1.0.107", ] [[package]] @@ -3155,34 +3667,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" dependencies = [ "fixedbitset", - "indexmap", + "indexmap 1.9.3", ] [[package]] name = "pin-project" -version = "1.0.9" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1622113ce508488160cff04e6abc60960e676d330e1ca0f77c0b8df17c81438f" +checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.9" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b95af56fee93df76d721d356ac1ca41fccf168bc448eb14049234df764ba3e76" +checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] name = "pin-project-lite" -version = "0.2.7" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -3190,34 +3702,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkcs8" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" -dependencies = [ - "der", - "spki", - "zeroize", -] - [[package]] name = "pkg-config" version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" -[[package]] -name = "plain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" - [[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 1.0.0", "cpufeatures", @@ -3225,6 +3720,18 @@ dependencies = [ "universal-hash", ] +[[package]] +name = "portable-atomic" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.15" @@ -3233,20 +3740,23 @@ checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" [[package]] name = "predicates" -version = "2.1.1" +version = "2.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5aab5be6e4732b473071984b3164dbbfb7a3674d30ea5ff44410b6bcd960c3c" +checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" dependencies = [ "difflib", - "itertools", + "float-cmp", + "itertools 0.10.5", + "normalize-line-endings", "predicates-core", + "regex", ] [[package]] name = "predicates-core" -version = "1.0.3" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da1c2388b1513e1b605fcec39a95e0a9e8ef088f71443ef37099fa9ae6673fcb" +checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" [[package]] name = "predicates-tree" @@ -3258,14 +3768,29 @@ dependencies = [ "termtree", ] +[[package]] +name = "pretty-hex" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6fa0831dd7cc608c38a5e323422a0077678fa5744aa2be4ad91c4ece8eec8d5" + [[package]] name = "prettyplease" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b83ec2d0af5c5c556257ff52c9f98934e243b9fd39604bfb2a9b75ec2e97f18" dependencies = [ - "proc-macro2 1.0.36", - "syn 1.0.91", + "proc-macro2", + "syn 1.0.107", +] + +[[package]] +name = "prio-graph" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f28921629370a46cf564f6ba1828bd8d1c97f7fad4ee9d1c6438f92feed6b8d" +dependencies = [ + "ahash 0.8.11", ] [[package]] @@ -3279,12 +3804,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.1.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebace6889caf889b4d3f76becee12e90353f2b8c7d875534a71e5742f8f6f83" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" dependencies = [ - "thiserror", - "toml", + "toml_edit", ] [[package]] @@ -3294,9 +3818,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 1.0.107", "version_check", ] @@ -3306,218 +3830,136 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", + "proc-macro2", + "quote", "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - -[[package]] -name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -dependencies = [ - "unicode-xid 0.1.0", -] - [[package]] name = "proc-macro2" -version = "1.0.36" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ - "unicode-xid 0.2.2", + "unicode-ident", ] [[package]] name = "proptest" -version = "1.0.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0d9cc07f18492d879586c92b485def06bc850da3118075cd45d50e9c95b0e5" +checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" dependencies = [ "bit-set", - "bitflags", - "byteorder", + "bit-vec", + "bitflags 2.6.0", "lazy_static", "num-traits", - "quick-error 2.0.1", "rand 0.8.5", "rand_chacha 0.3.1", "rand_xorshift", "regex-syntax", "rusty-fork", "tempfile", + "unarray", ] [[package]] name = "prost" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" -dependencies = [ - "bytes", - "prost-derive 0.9.0", -] - -[[package]] -name = "prost" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bd5316aa8f5c82add416dfbc25116b84b748a21153f512917e8143640a71bbd" -dependencies = [ - "bytes", - "prost-derive 0.10.0", -] - -[[package]] -name = "prost-build" -version = "0.9.0" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" dependencies = [ "bytes", - "heck 0.3.3", - "itertools", - "lazy_static", - "log", - "multimap", - "petgraph", - "prost 0.9.0", - "prost-types 0.9.0", - "regex", - "tempfile", - "which", + "prost-derive", ] [[package]] name = "prost-build" -version = "0.10.0" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "328f9f29b82409216decb172d81e936415d21245befa79cd34c3f29d87d1c50b" +checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" dependencies = [ "bytes", - "cfg-if 1.0.0", - "cmake", - "heck 0.4.0", - "itertools", + "heck 0.4.1", + "itertools 0.10.5", "lazy_static", "log", "multimap", "petgraph", - "prost 0.10.0", - "prost-types 0.10.0", + "prettyplease", + "prost", + "prost-types", "regex", + "syn 1.0.107", "tempfile", "which", ] [[package]] name = "prost-derive" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", -] - -[[package]] -name = "prost-derive" -version = "0.10.0" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df35198f0777b75e9ff669737c6da5136b59dba33cf5a010a6d1cc4d56defc6f" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", - "itertools", - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", -] - -[[package]] -name = "prost-types" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" -dependencies = [ - "bytes", - "prost 0.9.0", + "itertools 0.10.5", + "proc-macro2", + "quote", + "syn 1.0.107", ] [[package]] name = "prost-types" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "926681c118ae6e512a3ccefd4abbe5521a14f4cc1e207356d4d00c0b7f2006fd" -dependencies = [ - "bytes", - "prost 0.10.0", -] - -[[package]] -name = "pyo3" -version = "0.15.1" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cf01dbf1c05af0a14c7779ed6f3aa9deac9c3419606ac9de537a2d649005720" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" dependencies = [ - "cfg-if 1.0.0", - "indoc", - "libc", - "parking_lot 0.11.2", - "paste", - "pyo3-build-config", - "pyo3-macros", - "unindent", + "prost", ] [[package]] -name = "pyo3-build-config" -version = "0.15.1" +name = "protobuf-src" +version = "1.1.0+21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf9e4d128bfbddc898ad3409900080d8d5095c379632fbbfbb9c8cfb1fb852b" +checksum = "c7ac8852baeb3cc6fb83b93646fb93c0ffe5d14bf138c945ceb4b9948ee0e3c1" dependencies = [ - "once_cell", + "autotools", ] [[package]] -name = "pyo3-macros" -version = "0.15.1" +name = "qstring" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67701eb32b1f9a9722b4bc54b548ff9d7ebfded011c12daece7b9063be1fd755" +checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" dependencies = [ - "pyo3-macros-backend", - "quote 1.0.14", - "syn 1.0.91", + "percent-encoding 2.3.1", ] [[package]] -name = "pyo3-macros-backend" -version = "0.15.1" +name = "qualifier_attr" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f44f09e825ee49a105f2c7b23ebee50886a9aee0746f4dd5a704138a64b0218a" +checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" dependencies = [ - "proc-macro2 1.0.36", - "pyo3-build-config", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] -name = "qstring" -version = "0.7.2" +name = "quanta" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" +checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5" dependencies = [ - "percent-encoding 2.1.0", + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi 0.11.0+wasi-snapshot-preview1", + "web-sys", + "winapi 0.3.9", ] [[package]] @@ -3526,82 +3968,63 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -[[package]] -name = "quick-error" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" - [[package]] name = "quinn" -version = "0.8.3" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7542006acd6e057ff632307d219954c44048f818898da03113d6c0086bfddd9" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" dependencies = [ "bytes", - "futures-channel", - "futures-util", - "fxhash", + "pin-project-lite", "quinn-proto", "quinn-udp", - "rustls 0.20.4", - "thiserror", + "rustc-hash 2.0.0", + "rustls 0.23.18", + "socket2", + "thiserror 1.0.69", "tokio", "tracing", - "webpki 0.22.0", ] [[package]] name = "quinn-proto" -version = "0.8.3" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a13a5c0a674c1ce7150c9df7bc4a1e46c2fbbe7c710f56c0dc78b1a810e779e" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" dependencies = [ "bytes", - "fxhash", "rand 0.8.5", - "ring", - "rustls 0.20.4", - "rustls-native-certs", - "rustls-pemfile 0.2.1", + "ring 0.17.3", + "rustc-hash 2.0.0", + "rustls 0.23.18", + "rustls-platform-verifier", "slab", - "thiserror", + "thiserror 1.0.69", "tinyvec", "tracing", - "webpki 0.22.0", ] [[package]] name = "quinn-udp" -version = "0.1.1" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df185e5e5f7611fa6e628ed8f9633df10114b03bbaecab186ec55822c44ac727" +checksum = "e346e016eacfff12233c243718197ca12f148c84e1e84268a896699b41c71780" dependencies = [ - "futures-util", + "cfg_aliases", "libc", - "mio", - "quinn-proto", + "once_cell", "socket2", - "tokio", "tracing", + "windows-sys 0.59.0", ] [[package]] name = "quote" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" -dependencies = [ - "proc-macro2 0.4.30", -] - -[[package]] -name = "quote" -version = "1.0.14" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ - "proc-macro2 1.0.36", + "proc-macro2", ] [[package]] @@ -3615,7 +4038,6 @@ dependencies = [ "rand_chacha 0.2.2", "rand_core 0.5.1", "rand_hc", - "rand_pcg", ] [[package]] @@ -3626,7 +4048,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha 0.3.1", - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] @@ -3646,7 +4068,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] @@ -3660,27 +4082,28 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.3", + "getrandom 0.2.10", ] [[package]] -name = "rand_hc" -version = "0.2.0" +name = "rand_distr" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" dependencies = [ - "rand_core 0.5.1", + "num-traits", + "rand 0.8.5", ] [[package]] -name = "rand_pcg" -version = "0.2.1" +name = "rand_hc" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ "rand_core 0.5.1", ] @@ -3691,7 +4114,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] @@ -3700,52 +4123,54 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" dependencies = [ - "rand_core 0.6.3", + "rand_core 0.6.4", +] + +[[package]] +name = "raw-cpuid" +version = "11.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0" +dependencies = [ + "bitflags 2.6.0", ] [[package]] name = "rayon" -version = "1.5.2" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd249e82c21598a9a426a4e00dd7adc1d640b22445ec8545feef801d1a74c221" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ - "autocfg", - "crossbeam-deque", "either", "rayon-core", ] [[package]] name = "rayon-core" -version = "1.9.2" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f51245e1e62e1f1629cbfec37b5793bbabcaeb90f30e94d2ba03564687353e4" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] [[package]] -name = "rcgen" -version = "0.9.2" +name = "redox_syscall" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7fa2d386df8533b02184941c76ae2e0d0c1d053f5d43339169d80f21275fc5e" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ - "pem", - "ring", - "time 0.3.9", - "yasna", + "bitflags 1.3.2", ] [[package]] name = "redox_syscall" -version = "0.2.10" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -3754,19 +4179,20 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ - "getrandom 0.2.3", - "redox_syscall", + "getrandom 0.2.10", + "redox_syscall 0.2.10", ] [[package]] name = "reed-solomon-erasure" -version = "5.0.1" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7170bac0d8306941e101df0caaa6518b10bc4232dd36c34f1cb78b8a063024db" +checksum = "7263373d500d4d4f505d43a2a662d475a894aa94503a1ee28e9188b5f3960d4f" dependencies = [ "cc", "libc", "libm", + "lru", "parking_lot 0.11.2", "smallvec", "spin 0.9.2", @@ -3774,44 +4200,41 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.5" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ - "aho-corasick", + "aho-corasick 1.0.2", "memchr", + "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" -version = "0.1.10" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick 1.0.2", + "memchr", + "regex-syntax", +] [[package]] name = "regex-syntax" -version = "0.6.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" - -[[package]] -name = "remove_dir_all" -version = "0.5.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi 0.3.9", -] +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.11.10" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a1f7aa4f35e5e8b4160449f51afc758f0ce6454315a9fa7d0d113e958c41eb" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ "async-compression", - "base64 0.13.0", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", @@ -3824,37 +4247,50 @@ dependencies = [ "hyper-tls", "ipnet", "js-sys", - "lazy_static", "log", "mime", + "mime_guess", "native-tls", - "percent-encoding 2.1.0", + "once_cell", + "percent-encoding 2.3.1", "pin-project-lite", - "rustls 0.20.4", - "rustls-pemfile 0.3.0", + "rustls 0.21.12", + "rustls-pemfile 1.0.1", "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", + "system-configuration", "tokio", "tokio-native-tls", - "tokio-rustls 0.23.2", - "tokio-util 0.6.9", - "url 2.2.2", + "tokio-rustls", + "tokio-util 0.7.1", + "tower-service", + "url 2.5.2", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", + "webpki-roots 0.25.2", "winreg", ] [[package]] -name = "retain_mut" -version = "0.1.7" +name = "reqwest-middleware" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c31b5c4033f8fdde8700e4657be2c497e7288f01515be52168c631e2e4d4086" - -[[package]] -name = "ring" +checksum = "5a735987236a8e238bf0296c7e351b999c188ccc11477f311b82b55c93984216" +dependencies = [ + "anyhow", + "async-trait", + "http", + "reqwest", + "serde", + "task-local-extensions", + "thiserror 1.0.69", +] + +[[package]] +name = "ring" version = "0.16.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" @@ -3863,36 +4299,68 @@ dependencies = [ "libc", "once_cell", "spin 0.5.2", - "untrusted", + "untrusted 0.7.1", "web-sys", "winapi 0.3.9", ] +[[package]] +name = "ring" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babe80d5c16becf6594aa32ad2be8fe08498e7ae60b77de8df700e67f191d7e" +dependencies = [ + "cc", + "getrandom 0.2.10", + "libc", + "spin 0.9.2", + "untrusted 0.9.0", + "windows-sys 0.48.0", +] + [[package]] name = "rocksdb" -version = "0.18.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "620f4129485ff1a7128d184bc687470c21c7951b64779ebc9cfdad3dcd920290" +checksum = "6bd13e55d6d7b8cd0ea569161127567cd587676c99f4472f779a0279aa60a7a7" dependencies = [ "libc", "librocksdb-sys", ] +[[package]] +name = "rolling-file" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8395b4f860856b740f20a296ea2cd4d823e81a2658cf05ef61be22916026a906" +dependencies = [ + "chrono", +] + [[package]] name = "roots" -version = "0.0.7" +version = "0.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c36d2bbc763f480668d6d6790ae2fdd2e52ac0c21a3a26d156f3534a3d9eea9" +checksum = "082f11ffa03bbef6c2c6ea6bea1acafaade2fd9050ae0234ab44a2153742b058" [[package]] name = "rpassword" -version = "6.0.1" +version = "7.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bf099a1888612545b683d2661a1940089f6c2e5a8e38979b2159da876bfd956" +checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" +dependencies = [ + "libc", + "rtoolbox", + "windows-sys 0.48.0", +] + +[[package]] +name = "rtoolbox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a" dependencies = [ "libc", - "serde", - "serde_json", "winapi 0.3.9", ] @@ -3909,13 +4377,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] -name = "rustc_version" -version = "0.2.3" +name = "rustc-hash" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" [[package]] name = "rustc_version" @@ -3923,7 +4388,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.7", + "semver", ] [[package]] @@ -3935,66 +4400,135 @@ dependencies = [ "nom", ] +[[package]] +name = "rustix" +version = "0.38.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "375116bee2be9ed569afe2154ea6a99dfdffd257f533f187498c2a8f5feaf4ee" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + [[package]] name = "rustls" -version = "0.19.1" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ - "base64 0.13.0", "log", - "ring", - "sct 0.6.1", - "webpki 0.21.4", + "ring 0.17.3", + "rustls-webpki 0.101.7", + "sct", ] [[package]] name = "rustls" -version = "0.20.4" +version = "0.23.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fbfeb8d0ddb84706bc597a5574ab8912817c52a397f819e5b614e2265206921" +checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f" dependencies = [ - "log", - "ring", - "sct 0.7.0", - "webpki 0.22.0", + "once_cell", + "ring 0.17.3", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", ] [[package]] name = "rustls-native-certs" -version = "0.6.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca9ebdfa27d3fc180e42879037b5338ab1c040c06affd00d8338598e7800943" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" dependencies = [ "openssl-probe", - "rustls-pemfile 0.2.1", + "rustls-pemfile 2.2.0", + "rustls-pki-types", "schannel", "security-framework", ] [[package]] name = "rustls-pemfile" -version = "0.2.1" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" +checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" dependencies = [ "base64 0.13.0", ] [[package]] name = "rustls-pemfile" -version = "0.3.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee86d63972a7c661d1536fefe8c3c8407321c3df668891286de28abcd087360" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64 0.13.0", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" + +[[package]] +name = "rustls-platform-verifier" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afbb878bdfdf63a336a5e63561b1835e7a8c91524f51621db870169eac84b490" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls 0.23.18", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki 0.102.8", + "security-framework", + "security-framework-sys", + "webpki-roots 0.26.6", + "winapi 0.3.9", +] + +[[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.3", + "untrusted 0.9.0", +] + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring 0.17.3", + "rustls-pki-types", + "untrusted 0.9.0", ] [[package]] name = "rustversion" -version = "1.0.6" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "rusty-fork" @@ -4003,7 +4537,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" dependencies = [ "fnv", - "quick-error 1.2.3", + "quick-error", "tempfile", "wait-timeout", ] @@ -4035,39 +4569,21 @@ dependencies = [ [[package]] name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "scroll" -version = "0.10.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda28d4b4830b807a8b43f7b0e6b5df875311b3e7621d84577188c175b6ec1ec" -dependencies = [ - "scroll_derive", -] +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "scroll_derive" -version = "0.10.5" +name = "scratch" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaaae8f38bb311444cfb7f1979af0bc9240d95795f75f9ceddf6a59b79ceffa0" -dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", -] +checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" [[package]] -name = "sct" -version = "0.6.1" +name = "scroll" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" -dependencies = [ - "ring", - "untrusted", -] +checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" [[package]] name = "sct" @@ -4075,28 +4591,29 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" dependencies = [ - "ring", - "untrusted", + "ring 0.16.20", + "untrusted 0.7.1", ] [[package]] name = "security-framework" -version = "2.6.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" +checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", + "num-bigint 0.4.6", "security-framework-sys", ] [[package]] name = "security-framework-sys" -version = "2.6.1" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" dependencies = [ "core-foundation-sys", "libc", @@ -4104,61 +4621,56 @@ dependencies = [ [[package]] name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver" -version = "1.0.7" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] -name = "semver-parser" -version = "0.7.0" +name = "seqlock" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +checksum = "b5c67b6f14ecc5b86c66fa63d76b5092352678545a8a3cdae80aef5128371910" +dependencies = [ + "parking_lot 0.12.0", +] [[package]] name = "serde" -version = "1.0.137" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.5" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.137" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] name = "serde_json" -version = "1.0.81" +version = "1.0.135" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" dependencies = [ - "itoa 1.0.1", + "itoa", + "memchr", "ryu", "serde", ] @@ -4170,91 +4682,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.1", + "itoa", "ryu", "serde", ] [[package]] name = "serde_with" -version = "1.14.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" dependencies = [ "serde", + "serde_derive", "serde_with_macros", ] [[package]] name = "serde_with_macros" -version = "1.5.2" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" dependencies = [ "darling", - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] name = "serde_yaml" -version = "0.8.23" +version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap", + "indexmap 2.6.0", + "itoa", "ryu", "serde", - "yaml-rust", -] - -[[package]] -name = "serial_test" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0bccbcf40c8938196944a3da0e133e031a33f4d6b72db3bda3cc556e361905d" -dependencies = [ - "lazy_static", - "parking_lot 0.11.2", - "serial_test_derive 0.5.1", -] - -[[package]] -name = "serial_test" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eec42e7232e5ca56aa59d63af3c7f991fe71ee6a3ddd2d3480834cf3902b007" -dependencies = [ - "futures 0.3.21", - "lazy_static", - "log", - "parking_lot 0.12.0", - "serial_test_derive 0.8.0", -] - -[[package]] -name = "serial_test_derive" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2acd6defeddb41eb60bb468f8825d0cfd0c2a76bc03bfd235b6a1dc4f6a1ad5" -dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", -] - -[[package]] -name = "serial_test_derive" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1b95bb2f4f624565e8fe8140c789af7e2082c0e0561b5a82a1b678baa9703dc" -dependencies = [ - "proc-macro-error", - "proc-macro2 1.0.36", - "quote 1.0.14", - "rustversion", - "syn 1.0.91", + "unsafe-libyaml", ] [[package]] @@ -4290,29 +4756,25 @@ checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.3", + "digest 0.10.7", ] [[package]] name = "sha1" -version = "0.6.1" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ - "sha1_smol", + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.7", ] -[[package]] -name = "sha1_smol" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" - [[package]] name = "sha2" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", "cfg-if 1.0.0", @@ -4323,69 +4785,69 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.2" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.3", -] - -[[package]] -name = "sha3" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" -dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "keccak", - "opaque-debug 0.3.0", + "digest 0.10.7", ] [[package]] name = "sha3" -version = "0.10.1" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881bf8156c87b6301fc5ca6b27f11eeb2761224c7081e69b409d5a1951a70c86" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ - "digest 0.10.3", + "digest 0.10.7", "keccak", ] [[package]] name = "shank" -version = "0.0.3" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62c7f8aac4c67081e718ff2a7754a6264774a0eaa6ed64a6e94b1ec1c17af200" +checksum = "23d894855493d4ce613b25550fe1ed1c62d0af5486b984579ba55e3f8c9631d5" dependencies = [ "shank_macro", ] [[package]] name = "shank_macro" -version = "0.0.3" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7538be7f2a6530a37d4e03de34569a1f27a2287b3efe06732d7e5648a9105" +checksum = "a9bf2645f8eebde043da69200195058e7b59806705104f908a31d05ca82844ce" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", + "proc-macro2", + "quote", "shank_macro_impl", - "syn 1.0.91", + "shank_render", + "syn 1.0.107", ] [[package]] name = "shank_macro_impl" -version = "0.0.3" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4679c7294e45b98031bade3d50f5b01a562962176d76058af69e21e195919190" +checksum = "93d0593f48acb0a722906416b1f6b8926f6571eb9af16d566a7c65427f269f50" dependencies = [ "anyhow", - "proc-macro2 1.0.36", - "quote 1.0.14", + "proc-macro2", + "quote", "serde", - "syn 1.0.91", + "syn 1.0.107", +] + +[[package]] +name = "shank_render" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121175ba61809189f888dc5822ebfd30fa0d91e1e1f61d25a4d40b0847b3075e" +dependencies = [ + "proc-macro2", + "quote", + "shank_macro_impl", ] [[package]] @@ -4398,10 +4860,16 @@ dependencies = [ ] [[package]] -name = "shlex" +name = "shell-words" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" @@ -4418,19 +4886,18 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" -[[package]] -name = "sim" -version = "0.1.0" -dependencies = [ - "pyo3", -] - [[package]] name = "simpl" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a30f10c911c0355f80f1c2faa8096efc4a58cdf8590b954d5b395efa071c711" +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "sized-chunks" version = "0.6.5" @@ -4443,21 +4910,24 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] [[package]] name = "smallvec" -version = "1.7.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smpl_jwt" -version = "0.6.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4370044f8b20f944e05c35d77edd3518e6f21fc4de77e593919f287c6a3f428a" +checksum = "95b6ff8c21c74ce7744643a7cddbb02579a44f1f77e4316bff1ddb741aca8ac9" dependencies = [ "base64 0.13.0", "log", @@ -4466,17 +4936,17 @@ dependencies = [ "serde_derive", "serde_json", "simpl", - "time 0.2.27", + "time", ] [[package]] name = "socket2" -version = "0.4.4" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", - "winapi 0.3.9", + "windows-sys 0.52.0", ] [[package]] @@ -4487,21 +4957,35 @@ checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" dependencies = [ "base64 0.13.0", "bytes", - "futures 0.3.21", + "futures 0.3.31", "httparse", "log", "rand 0.8.5", "sha-1 0.9.8", ] +[[package]] +name = "solana-account" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "730219420b206253977b8cc8fd7846ffe021ab2e2c718e70db420efbd2775547" +dependencies = [ + "bincode", + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-program", +] + [[package]] name = "solana-account-decoder" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f66dee087a53e7ce07cbf02be14d5b7261d83ebe6f445ca777c18fa7821f027" +checksum = "14e5b1c167335942b659d077552607f79b2eca3472e40eeed97a2c55838b84ef" dependencies = [ "Inflector", - "base64 0.13.0", + "base64 0.22.1", "bincode", "bs58", "bv", @@ -4509,160 +4993,330 @@ dependencies = [ "serde", "serde_derive", "serde_json", + "solana-account-decoder-client-types", "solana-config-program", "solana-sdk", - "solana-vote-program", - "spl-token 3.3.0", - "spl-token-2022 0.2.0", - "thiserror", + "spl-token 6.0.0", + "spl-token-2022 4.0.0", + "spl-token-group-interface 0.3.0", + "spl-token-metadata-interface 0.4.0", + "thiserror 1.0.69", "zstd", ] [[package]] -name = "solana-address-lookup-table-program" -version = "1.10.33" +name = "solana-account-decoder-client-types" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1018ed920d3fdae80397da2640513946119be7fb327c8a2d8e8018b109df6768" +checksum = "dee0750d2f106ecbee6d4508b6e2029e6946cb5f67288bf002b5a62f9f451c43" dependencies = [ - "bincode", - "bytemuck", - "log", - "num-derive", - "num-traits", - "rustc_version 0.4.0", + "base64 0.22.1", + "bs58", "serde", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-program", - "solana-program-runtime", - "solana-sdk", - "thiserror", -] - -[[package]] -name = "solana-banks-client" -version = "1.10.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a7762a0254ac809b97075fd6f9ec92edaa5de9a47a3494969d561d1fa6b979f" -dependencies = [ - "borsh", - "futures 0.3.21", - "solana-banks-interface", - "solana-program", - "solana-sdk", - "tarpc", - "thiserror", - "tokio", - "tokio-serde", + "serde_derive", + "serde_json", + "solana-account", + "solana-pubkey", + "zstd", ] [[package]] -name = "solana-banks-interface" -version = "1.10.33" +name = "solana-account-info" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5178e2a0ede374043ddf5a825f1bb610188b0ad2c74d73676cd0f8ab59c5fd83" +checksum = "6abe81cfc4a75f71a510c6856b03a7d8525e416af3c69d55daef62e6078b8d40" dependencies = [ + "bincode", "serde", - "solana-sdk", - "tarpc", + "solana-program-error", + "solana-program-memory", + "solana-pubkey", ] [[package]] -name = "solana-banks-server" -version = "1.10.33" +name = "solana-accounts-db" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f1c01d9ebe8a1c5cd45efda5cb60b31ab1c15589f835f280428d4241c76ef57" +checksum = "b9fecc332ad4edd98ed63e5a46d990ecaf6fe4abd2bf9795c15474a64534ced6" dependencies = [ + "ahash 0.8.11", "bincode", - "crossbeam-channel", - "futures 0.3.21", - "solana-banks-interface", + "blake3", + "bv", + "bytemuck", + "bytemuck_derive", + "bzip2", + "crossbeam-channel", + "dashmap", + "index_list", + "indexmap 2.6.0", + "itertools 0.12.1", + "lazy_static", + "log", + "lz4", + "memmap2 0.5.10", + "modular-bitfield", + "num_cpus", + "num_enum", + "rand 0.8.5", + "rayon", + "seqlock", + "serde", + "serde_derive", + "smallvec", + "solana-bucket-map", + "solana-inline-spl", + "solana-lattice-hash", + "solana-measure", + "solana-metrics", + "solana-nohash-hasher", + "solana-rayon-threadlimit", + "solana-sdk", + "solana-svm-transaction", + "static_assertions", + "tar", + "tempfile", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-address-lookup-table-program" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cf79a76f2878982b9781dfd0831d58ee15eb905be65406ccf7370c3ecd69c52" +dependencies = [ + "bincode", + "bytemuck", + "log", + "num-derive", + "num-traits", + "solana-feature-set", + "solana-log-collector", + "solana-program", + "solana-program-runtime", + "solana-sdk", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-atomic-u64" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "391b795afcdcad39ddc6c938d64b789d036cdfe00d9dc5ff83024cf2da9f066f" +dependencies = [ + "parking_lot 0.12.0", +] + +[[package]] +name = "solana-banks-client" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f857fb6590467d433f40eee507666ca496ec67907e50b7d530b6c04f6541875" +dependencies = [ + "borsh 1.5.3", + "futures 0.3.31", + "solana-banks-interface", + "solana-program", + "solana-sdk", + "tarpc", + "thiserror 1.0.69", + "tokio", + "tokio-serde", +] + +[[package]] +name = "solana-banks-interface" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20052d231bb9ac3268dc61a713e3915d6c95fc942f9a5c15ca3a81a3fcd9cc12" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk", + "tarpc", +] + +[[package]] +name = "solana-banks-server" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10db60e4bf077b870a7e75f8596bf3790d079b3762e9b4edc032475077007d0b" +dependencies = [ + "bincode", + "crossbeam-channel", + "futures 0.3.31", + "solana-banks-interface", "solana-client", + "solana-feature-set", "solana-runtime", "solana-sdk", "solana-send-transaction-service", + "solana-svm", "tarpc", "tokio", "tokio-serde", - "tokio-stream", +] + +[[package]] +name = "solana-bincode" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e85cb5961c356345a61378163fd9057011b35540f8bcdd8d8a09cb10117264f" +dependencies = [ + "bincode", + "serde", + "solana-instruction", ] [[package]] name = "solana-bloom" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "540ea29af5c747299e69dfad1f096c982f1f5cfe2a42c0e8f596c6e3786dc0ef" +checksum = "a6cdcc35537b23cd3376eb2ea7753d958f6ce64f69318b00dc137817c0b49411" dependencies = [ "bv", "fnv", "log", - "rand 0.7.3", - "rayon", - "rustc_version 0.4.0", + "rand 0.8.5", "serde", "serde_derive", - "solana-frozen-abi", - "solana-frozen-abi-macro", + "solana-sanitize", "solana-sdk", ] +[[package]] +name = "solana-bn254" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39c4030db26ad618f7e18fb5284df19fd52a68e092a1ca58db857108c4cc777" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-serialize", + "bytemuck", + "solana-program", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-borsh" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d526f3525ab22a3ada3f9a1d642664dafac00dc9208326b701a2045514eb04" +dependencies = [ + "borsh 0.10.3", + "borsh 1.5.3", +] + [[package]] name = "solana-bpf-loader-program" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe9ea7c9b3f2710b0d9696d54797784db79d9a84e7e88bea514178537c9b20c" +checksum = "142e0407f8428a1d2a33154d1d3d1c134ad257651ddff0811c17a6ee840def36" dependencies = [ "bincode", "byteorder", "libsecp256k1", "log", + "scopeguard", + "solana-bn254", + "solana-compute-budget", + "solana-curve25519", + "solana-feature-set", + "solana-log-collector", "solana-measure", - "solana-metrics", + "solana-poseidon", + "solana-program-memory", "solana-program-runtime", "solana-sdk", - "solana-zk-token-sdk 1.10.33", + "solana-timings", + "solana-type-overrides", "solana_rbpf", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "solana-bucket-map" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb0d1e5523bcbd2869c5431bc1258cf995e2a4803bce9c7ddac6eb942e574bdd" +checksum = "66eb348939fcfea6e40eed61bca06a1c631f8cb70f1801a5b14021bddefe93eb" dependencies = [ + "bv", + "bytemuck", + "bytemuck_derive", "log", - "memmap2", + "memmap2 0.5.10", "modular-bitfield", - "rand 0.7.3", + "num_enum", + "rand 0.8.5", "solana-measure", "solana-sdk", "tempfile", ] +[[package]] +name = "solana-builtins-default-costs" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854270e266040355f5fd5b67c91855bc36cebf1d3f325eb54d8b1b0ca385f74b" +dependencies = [ + "ahash 0.8.11", + "lazy_static", + "log", + "solana-address-lookup-table-program", + "solana-bpf-loader-program", + "solana-compute-budget-program", + "solana-config-program", + "solana-loader-v4-program", + "solana-sdk", + "solana-stake-program", + "solana-system-program", + "solana-vote-program", +] + [[package]] name = "solana-clap-utils" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "974c122764ca2ef5335f133868c991a24bcd648bb4a66c81a289f9e5893c994f" +checksum = "1709e1b0aefc8062fca29a4fde8d35f39ee95586e77cc6360e9bfc50a094c44f" dependencies = [ "chrono", - "clap", + "clap 2.34.0", "rpassword", - "solana-perf", + "solana-derivation-path", + "solana-remote-wallet", + "solana-sdk", + "thiserror 1.0.69", + "tiny-bip39", + "uriparse", + "url 2.5.2", +] + +[[package]] +name = "solana-clap-v3-utils" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9682fa05e9e8bcd49340567c000b20e4f094db530ef7912d74ea12706448814" +dependencies = [ + "chrono", + "clap 3.2.25", + "rpassword", + "solana-derivation-path", "solana-remote-wallet", "solana-sdk", - "thiserror", + "solana-zk-token-sdk", + "thiserror 1.0.69", "tiny-bip39", "uriparse", - "url 2.2.2", + "url 2.5.2", ] [[package]] name = "solana-cli-config" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb6b92a2f9e42cf221880ec2198b5f1e872fdd0b23966ba488ffeada8b36c450" +checksum = "384fda0ddf3099eab0f702b326663f499e84731e8584fd7d0c6d8bab03bead79" dependencies = [ "dirs-next", "lazy_static", @@ -4671,95 +5325,93 @@ dependencies = [ "serde_yaml", "solana-clap-utils", "solana-sdk", - "url 2.2.2", + "url 2.5.2", ] [[package]] name = "solana-cli-output" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda3f66881691a9a9ca9310d0bd84cbc3026852e1d118780a5d138324ec813fa" +checksum = "b82ae7fc5a012ad5bc4077a235ea5b26145fab50ca05b550e792a50bdd6d77a9" dependencies = [ "Inflector", - "base64 0.13.0", + "base64 0.22.1", "chrono", - "clap", - "console 0.15.0", + "clap 2.34.0", + "console", "humantime", "indicatif", - "semver 1.0.7", + "pretty-hex", + "semver", "serde", "serde_json", "solana-account-decoder", "solana-clap-utils", "solana-cli-config", - "solana-client", + "solana-rpc-client-api", "solana-sdk", "solana-transaction-status", "solana-vote-program", - "spl-memo 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-memo 5.0.0", ] [[package]] name = "solana-client" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e92734a47b2ab8846b0ea732f6a4541e6e46e0a9f6074cd715ecf12b5214bbd8" +checksum = "1d9a40b8e9e11604e8c05e8b5fcdb89359235db47d1aae84dcba0fc98e95dd0c" dependencies = [ - "async-mutex", "async-trait", - "base64 0.13.0", "bincode", - "bs58", - "bytes", - "clap", - "crossbeam-channel", - "enum_dispatch", - "futures 0.3.21", + "dashmap", + "futures 0.3.31", "futures-util", - "indexmap", + "indexmap 2.6.0", "indicatif", - "itertools", - "jsonrpc-core", - "lazy_static", "log", - "lru", "quinn", - "quinn-proto", - "rand 0.7.3", - "rand_chacha 0.2.2", "rayon", - "reqwest", - "rustls 0.20.4", - "semver 1.0.7", - "serde", - "serde_derive", - "serde_json", - "solana-account-decoder", - "solana-clap-utils", - "solana-faucet", + "solana-connection-cache", "solana-measure", - "solana-metrics", - "solana-net-utils", + "solana-pubsub-client", + "solana-quic-client", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-rpc-client-nonce-utils", "solana-sdk", "solana-streamer", - "solana-transaction-status", - "solana-version", - "solana-vote-program", - "spl-token-2022 0.2.0", - "thiserror", + "solana-thin-client", + "solana-tpu-client", + "solana-udp-client", + "thiserror 1.0.69", "tokio", - "tokio-stream", - "tokio-tungstenite", - "tungstenite", - "url 2.2.2", +] + +[[package]] +name = "solana-clock" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7848171e53fa528efd41dd4b3ab919f47b851f8bb4a827d63ff95678f08737fc" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-macro", +] + +[[package]] +name = "solana-compute-budget" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebf2f023f471bd1195b7f420e13ffc2422592dd48e71104b4901300b49ac493e" +dependencies = [ + "solana-sdk", ] [[package]] name = "solana-compute-budget-program" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c5a23f363826f03ca34552b558ca478d99e0a03ab8de573ac7609dc7c6308c3" +checksum = "73eddf023f02a56daa838818e30894b874368a741782457468eeefdfce2f7f53" dependencies = [ "solana-program-runtime", "solana-sdk", @@ -4767,51 +5419,87 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fae70ea08b7843ed7883a07b2769ffd15204be62cc7ef6150c9d54418522c1d" +checksum = "a035a01970ebbf40a244b3b79af533329ac8d48d80b0b98e166e23e35aa88171" dependencies = [ "bincode", "chrono", "serde", "serde_derive", + "solana-log-collector", "solana-program-runtime", "solana-sdk", + "solana-short-vec", +] + +[[package]] +name = "solana-connection-cache" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f45dd2a6d5d55ed951781486231d0d2ee9ff7047fdafaed01ee021e236319d0" +dependencies = [ + "async-trait", + "bincode", + "crossbeam-channel", + "futures-util", + "indexmap 2.6.0", + "log", + "rand 0.8.5", + "rayon", + "solana-measure", + "solana-metrics", + "solana-sdk", + "thiserror 1.0.69", + "tokio", ] [[package]] name = "solana-core" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74521ba9343f4ce60ac79926b9c8bde3c9f82f06eee62fdbf866d0b91bf7b5de" +checksum = "9d499325db220d9442530d625addc20defe35c41a2e349a9ffb8f3bf20e7a9b7" dependencies = [ - "ahash", - "base64 0.13.0", + "ahash 0.8.11", + "anyhow", + "arrayvec", + "base64 0.22.1", "bincode", "bs58", + "bytes", "chrono", "crossbeam-channel", "dashmap", "etcd-client", - "fs_extra", + "futures 0.3.31", "histogram", - "itertools", + "itertools 0.12.1", + "lazy_static", "log", "lru", "min-max-heap", - "rand 0.7.3", - "rand_chacha 0.2.2", + "num_enum", + "prio-graph", + "qualifier_attr", + "quinn", + "rand 0.8.5", + "rand_chacha 0.3.1", "rayon", - "retain_mut", - "rustc_version 0.4.0", + "rolling-file", + "rustls 0.23.18", "serde", + "serde_bytes", "serde_derive", - "solana-address-lookup-table-program", + "solana-accounts-db", "solana-bloom", + "solana-builtins-default-costs", "solana-client", + "solana-compute-budget", + "solana-connection-cache", + "solana-cost-model", "solana-entry", - "solana-frozen-abi", - "solana-frozen-abi-macro", + "solana-feature-set", + "solana-fee", "solana-geyser-plugin-manager", "solana-gossip", "solana-ledger", @@ -4820,169 +5508,258 @@ dependencies = [ "solana-net-utils", "solana-perf", "solana-poh", - "solana-program-runtime", + "solana-quic-client", "solana-rayon-threadlimit", - "solana-replica-lib", "solana-rpc", + "solana-rpc-client-api", "solana-runtime", + "solana-runtime-transaction", + "solana-sanitize", "solana-sdk", "solana-send-transaction-service", + "solana-short-vec", "solana-streamer", + "solana-svm", + "solana-svm-transaction", + "solana-timings", + "solana-tpu-client", "solana-transaction-status", + "solana-turbine", + "solana-unified-scheduler-pool", "solana-version", + "solana-vote", "solana-vote-program", + "solana-wen-restart", + "strum", + "strum_macros", "sys-info", "sysctl", "tempfile", - "thiserror", + "thiserror 1.0.69", "tokio", "trees", ] [[package]] -name = "solana-entry" -version = "1.10.33" +name = "solana-cost-model" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc348090c87b7d4fa2a6a55ac82142a82f537b5264a864fb21e1f223f23394c2" +checksum = "448128561bb950bce19cdbbdc1780955a52ef25f1984c9c13b35b4b9cdc548c4" dependencies = [ - "bincode", - "crossbeam-channel", - "dlopen", - "dlopen_derive", + "ahash 0.8.11", + "lazy_static", "log", - "rand 0.7.3", - "rayon", - "serde", - "solana-measure", - "solana-merkle-tree", + "solana-builtins-default-costs", + "solana-compute-budget", + "solana-feature-set", "solana-metrics", - "solana-perf", - "solana-rayon-threadlimit", + "solana-runtime-transaction", "solana-sdk", + "solana-svm-transaction", + "solana-vote-program", ] [[package]] -name = "solana-faucet" -version = "1.10.33" +name = "solana-cpi" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb7e99a5978347e936f17fd59dc10375db07036671f45a10e67e01fc504e6703" +checksum = "25c536ad0ce25d84a64f48dedcb773e764827e0ef781eda41fa1fa35f5d64b38" dependencies = [ - "bincode", - "byteorder", - "clap", - "crossbeam-channel", - "log", - "serde", - "serde_derive", - "solana-clap-utils", + "solana-account-info", + "solana-define-syscall", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-stable-layout", +] + +[[package]] +name = "solana-curve25519" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f934d38b6f2a940fb1e1d8eaa17a14ffd3773b37be9fb29fa4bcec1bac5e4591" +dependencies = [ + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "solana-program", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-decode-error" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5a431f532d030098e81d120877f2dddbd3dd90bea5b259198a6aae4ff6456c3" +dependencies = [ + "num-traits", +] + +[[package]] +name = "solana-define-syscall" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7062ae1de58e294d3bee5fd2c89efc155b7f7383ddce4cb88345dfafaaabc5bd" + +[[package]] +name = "solana-derivation-path" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12080d9bf8eecd559c6f40b5aaf9e47f7f28f515218087f83f02e493b46d8388" +dependencies = [ + "derivation-path", + "qstring", + "uriparse", +] + +[[package]] +name = "solana-entry" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "151cbfd824285d3b6ab6391f85448f73364baca34a897184e26ad7c66165e3f0" +dependencies = [ + "bincode", + "crossbeam-channel", + "dlopen2", + "lazy_static", + "log", + "rand 0.8.5", + "rayon", + "serde", + "solana-measure", + "solana-merkle-tree", + "solana-metrics", + "solana-perf", + "solana-rayon-threadlimit", + "solana-sdk", +] + +[[package]] +name = "solana-epoch-schedule" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c4cf7d7c266d353169cf4feeada5e4bba3a55f33715535fa1ef49080eac3e0" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-macro", +] + +[[package]] +name = "solana-faucet" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "281c481c0efa41a7ddada5dbffabee9099a6b01e9d748b7135366df589f7415e" +dependencies = [ + "bincode", + "byteorder", + "clap 2.34.0", + "crossbeam-channel", + "log", + "serde", + "serde_derive", + "solana-clap-utils", "solana-cli-config", "solana-logger", "solana-metrics", "solana-sdk", "solana-version", - "spl-memo 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror", + "spl-memo 5.0.0", + "thiserror 1.0.69", "tokio", ] [[package]] -name = "solana-frozen-abi" -version = "1.10.33" +name = "solana-feature-set" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a5d3280421bb53fc12bdba1eaa505153fb4f99a06b5609dae22192652ead3b" +checksum = "5cebf45992982065a0b01b4e109bf039b2ebf6394b21672382fd951516d4c9b0" dependencies = [ - "bs58", - "bv", - "generic-array 0.14.5", - "im", "lazy_static", - "log", - "memmap2", - "rustc_version 0.4.0", - "serde", - "serde_bytes", - "serde_derive", - "sha2 0.10.2", - "solana-frozen-abi-macro", - "thiserror", + "solana-clock", + "solana-epoch-schedule", + "solana-hash", + "solana-pubkey", + "solana-sha256-hasher", ] [[package]] -name = "solana-frozen-abi-macro" -version = "1.10.33" +name = "solana-fee" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "635c60ac96b1347af272c625465068b908aff919d19f29b5795a44310310494d" +checksum = "833e9a34c8cb1271e360b240dce43065cc4419ad74fc7e807c4e30cf06ebca80" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "rustc_version 0.4.0", - "syn 1.0.91", + "solana-sdk", + "solana-svm-transaction", ] [[package]] -name = "solana-geyser-plugin-interface" -version = "1.10.33" +name = "solana-fee-calculator" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a423e0473af51d982a155f6edf4a1f31e146ae27b2ef414319190dbb83e7be33" +checksum = "c2befe056ece2eb5807298c2b569a35ee52f79df859bdd16a1f97869f8224a28" dependencies = [ "log", - "solana-sdk", - "solana-transaction-status", - "thiserror", + "serde", + "serde_derive", ] [[package]] name = "solana-geyser-plugin-manager" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64aaf28a2bfa87b766083ecf2f65a1487435ac0bb2e7622f0d7ebf3e3f31401" +checksum = "4ac089db04deff5826ad8469e0c934e77451315396ee30fde4d512d6b60f2cca" dependencies = [ + "agave-geyser-plugin-interface", "bs58", "crossbeam-channel", "json5", + "jsonrpc-core", "libloading", "log", "serde_json", - "solana-geyser-plugin-interface", + "solana-accounts-db", + "solana-entry", + "solana-ledger", "solana-measure", "solana-metrics", "solana-rpc", "solana-runtime", "solana-sdk", "solana-transaction-status", - "thiserror", + "thiserror 1.0.69", + "tokio", ] [[package]] name = "solana-gossip" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf1702499e86cccb08e081a0e92a2d8c42a107df29f2dbec66bfc77186811bb" +checksum = "c5849898b9a0a9b4dc9a200fa7b28d1c929bb89f8db4e8b5899d2d32277459ce" dependencies = [ + "assert_matches", "bincode", "bv", - "clap", + "clap 2.34.0", "crossbeam-channel", "flate2", - "indexmap", - "itertools", + "indexmap 2.6.0", + "itertools 0.12.1", "log", "lru", - "matches", "num-traits", - "rand 0.7.3", - "rand_chacha 0.2.2", + "rand 0.8.5", + "rand_chacha 0.3.1", "rayon", - "rustc_version 0.4.0", "serde", "serde_bytes", "serde_derive", "solana-bloom", "solana-clap-utils", "solana-client", + "solana-connection-cache", "solana-entry", - "solana-frozen-abi", - "solana-frozen-abi-macro", + "solana-feature-set", "solana-ledger", "solana-logger", "solana-measure", @@ -4990,49 +5767,144 @@ dependencies = [ "solana-net-utils", "solana-perf", "solana-rayon-threadlimit", + "solana-rpc-client", "solana-runtime", + "solana-sanitize", "solana-sdk", + "solana-serde-varint", + "solana-short-vec", "solana-streamer", + "solana-tpu-client", "solana-version", + "solana-vote", "solana-vote-program", - "thiserror", + "static_assertions", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-hash" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1807bc4e9e1d25271514167d5a1e698ce5a330bce547a368242dd63b355b5faa" +dependencies = [ + "borsh 1.5.3", + "bs58", + "bytemuck", + "bytemuck_derive", + "js-sys", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-sanitize", + "wasm-bindgen", +] + +[[package]] +name = "solana-inflation" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a60b572cdf0ec8fcf5a53e5ba4e3e19814dd96c2b9c156d5828be68d0d2e7103" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-inline-spl" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24c9c6590e4eaf91efa887b2689b2941fe4b324bccd9a95f77853168f3d9a88" +dependencies = [ + "bytemuck", + "solana-pubkey", +] + +[[package]] +name = "solana-instruction" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfef689e06e5c7cb6206d4dc61ac77733de4f72d754e0d531393206abc27dbe4" +dependencies = [ + "bincode", + "borsh 1.5.3", + "getrandom 0.2.10", + "js-sys", + "num-traits", + "serde", + "serde_derive", + "solana-define-syscall", + "solana-pubkey", + "wasm-bindgen", +] + +[[package]] +name = "solana-last-restart-slot" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3186feae497bdfd2e77bfa56caed38b1cb1b0f389506666e3331f0b9ae799cb" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-macro", +] + +[[package]] +name = "solana-lattice-hash" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ec86f48a8694d55757922823823069a3652d2896f61f3ffc4b741646c166a62" +dependencies = [ + "base64 0.22.1", + "blake3", + "bs58", + "bytemuck", ] [[package]] name = "solana-ledger" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fca2ef01ff7b1f1454ef1f154ebc231729aff4a5284abbbff1cd7203e228fb" +checksum = "d181954a7e0ef3847ed2336adda1214cda401ac2c5557ebb63d700e409864881" dependencies = [ + "assert_matches", "bincode", - "bitflags", + "bitflags 2.6.0", "byteorder", + "bzip2", "chrono", "chrono-humanize", "crossbeam-channel", + "dashmap", + "eager", "fs_extra", - "futures 0.3.21", - "itertools", + "futures 0.3.31", + "itertools 0.12.1", + "lazy-lru", "lazy_static", "libc", "log", "lru", + "mockall", "num_cpus", "num_enum", - "prost 0.10.0", - "rand 0.7.3", - "rand_chacha 0.2.2", + "prost", + "qualifier_attr", + "rand 0.8.5", + "rand_chacha 0.3.1", "rayon", "reed-solomon-erasure", "rocksdb", - "rustc_version 0.4.0", + "scopeguard", "serde", "serde_bytes", - "sha2 0.10.2", + "sha2 0.10.8", + "solana-account-decoder", + "solana-accounts-db", "solana-bpf-loader-program", + "solana-cost-model", "solana-entry", - "solana-frozen-abi", - "solana-frozen-abi-macro", + "solana-feature-set", "solana-measure", "solana-metrics", "solana-perf", @@ -5040,22 +5912,59 @@ dependencies = [ "solana-rayon-threadlimit", "solana-runtime", "solana-sdk", + "solana-stake-program", "solana-storage-bigtable", "solana-storage-proto", + "solana-svm", + "solana-svm-transaction", + "solana-timings", "solana-transaction-status", + "solana-vote", "solana-vote-program", + "spl-token 6.0.0", + "spl-token-2022 4.0.0", + "static_assertions", + "strum", + "strum_macros", + "tar", "tempfile", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "trees", ] +[[package]] +name = "solana-loader-v4-program" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94c6915a49e537925e934551dbce2db2357d555d257a311bbf5ba0810cb1017a" +dependencies = [ + "log", + "solana-bpf-loader-program", + "solana-compute-budget", + "solana-log-collector", + "solana-measure", + "solana-program-runtime", + "solana-sdk", + "solana-type-overrides", + "solana_rbpf", +] + +[[package]] +name = "solana-log-collector" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b529f5736a6c0794a885dac2e091138d3db6d924335906f117a62b58b0d3b5dc" +dependencies = [ + "log", +] + [[package]] name = "solana-logger" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b12cb6e6f1f9c9876d356c928b8c2ac532f6715e7cd2a1b4343d747bee3eca73" +checksum = "367c5431bad14b10fbb62614b48720b746672558dba3244167ff7d251890c355" dependencies = [ "env_logger", "lazy_static", @@ -5064,30 +5973,26 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03deb847b269c14a69956c9917697b221b4c7431ea35c221244c3a4d4a59ed7c" -dependencies = [ - "log", - "solana-sdk", -] +checksum = "33b2047a2f588082b71080b060918f107c3330ae1505f759c3b2d74bae9d9c88" [[package]] name = "solana-merkle-tree" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f157bb336ae832c2a5181650cb294dee6bdcf06bf449015705f75263f2dba019" +checksum = "e75fa782e9cf2a846f09f96594db01e3005aeefb36ce53aebc41b050381e9989" dependencies = [ "fast-math", - "matches", - "solana-program", + "solana-hash", + "solana-sha256-hasher", ] [[package]] name = "solana-metrics" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9105cdcc6e42b8788250f6d3721c5d552b48e2cf8374b76c617639ba672c9302" +checksum = "6319c74238e8ed4f7159fd37c693a574ab8316d03b053103f9cc83dce13f1d5c" dependencies = [ "crossbeam-channel", "gethostname", @@ -5095,62 +6000,95 @@ dependencies = [ "log", "reqwest", "solana-sdk", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-msg" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f7551f85064bc7299d56dbd7126258b084a2d78d0325b1579324f818b405123" +dependencies = [ + "solana-define-syscall", ] +[[package]] +name = "solana-native-token" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0c4074f5fc67574dabd8f30fe6e51e290a812d88326b19b49c462058e23340" + [[package]] name = "solana-net-utils" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2434e5973ab61b1465d4642ddcce1616773fe53473bc2736771b76251ead99b8" +checksum = "bbac19474a4c4f91cb264c2fccead8a1a4f65384ce650b24360d9df5650e65bc" dependencies = [ "bincode", - "clap", "crossbeam-channel", "log", "nix", - "rand 0.7.3", + "rand 0.8.5", "serde", "serde_derive", "socket2", - "solana-logger", "solana-sdk", - "solana-version", "tokio", - "url 2.2.2", + "url 2.5.2", +] + +[[package]] +name = "solana-nohash-hasher" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b8a731ed60e89177c8a7ab05fe0f1511cedd3e70e773f288f9de33a9cfdc21e" + +[[package]] +name = "solana-packet" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dafc2d84e57dbfe32583fe915962bd2ca3af6be496628a871db3c3d697b38d7" +dependencies = [ + "bincode", + "bitflags 2.6.0", + "cfg_eval", + "serde", + "serde_derive", + "serde_with", ] [[package]] name = "solana-perf" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38caa622fe38f83fc7b68ffc7c0b30a7fccd0d9173944ccea710119e9cdd7d4" +checksum = "e8299f1ba518f9888da8cafa861addc6ffdd639c689e3ce219ae08212c0dcd0e" dependencies = [ - "ahash", + "ahash 0.8.11", "bincode", "bv", "caps", - "curve25519-dalek", - "dlopen", - "dlopen_derive", + "curve25519-dalek 4.1.3", + "dlopen2", "fnv", "lazy_static", "libc", "log", "nix", - "rand 0.7.3", + "rand 0.8.5", "rayon", "serde", "solana-metrics", "solana-rayon-threadlimit", "solana-sdk", + "solana-short-vec", "solana-vote-program", ] [[package]] name = "solana-poh" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03ca21c5b1889e8c38121bec7db770fe8f957971e9f475a845b6b093a633459b" +checksum = "c11f9be81af30870cfc5b782e46565f65685d75a6969052d5f8f063a3271c66c" dependencies = [ "core_affinity", "crossbeam-channel", @@ -5161,105 +6099,305 @@ dependencies = [ "solana-metrics", "solana-runtime", "solana-sdk", - "solana-sys-tuner", - "thiserror", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-poseidon" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f193a65f0db7fe5615c76c2814d6450a2e4cda61f786d5bf7a6b1ad0c179b947" +dependencies = [ + "ark-bn254", + "light-poseidon", + "solana-define-syscall", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-precompile-error" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a30ab58b9e37cde4e5577282670f30df71b97b6b06dbdb420e9b84e57b831227" +dependencies = [ + "num-traits", + "solana-decode-error", ] [[package]] name = "solana-program" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeecf504cee2821b006871f70e7a1f54db15f914cedf259eaf5976fe606470f0" +checksum = "9040decf2f295d35da22557eeab3768ab8dfca8aed9afe668663c8fa0e97d60e" dependencies = [ - "base64 0.13.0", + "base64 0.22.1", "bincode", - "bitflags", + "bitflags 2.6.0", "blake3", - "borsh", - "borsh-derive", + "borsh 0.10.3", + "borsh 1.5.3", "bs58", "bv", "bytemuck", + "bytemuck_derive", "console_error_panic_hook", "console_log", - "curve25519-dalek", - "getrandom 0.1.16", - "itertools", + "curve25519-dalek 4.1.3", + "five8_const", + "getrandom 0.2.10", "js-sys", "lazy_static", - "libsecp256k1", "log", + "memoffset 0.9.0", + "num-bigint 0.4.6", "num-derive", "num-traits", "parking_lot 0.12.0", - "rand 0.7.3", - "rustc_version 0.4.0", - "rustversion", + "rand 0.8.5", "serde", "serde_bytes", "serde_derive", - "sha2 0.10.2", - "sha3 0.10.1", - "solana-frozen-abi", - "solana-frozen-abi-macro", + "sha2 0.10.8", + "sha3", + "solana-account-info", + "solana-atomic-u64", + "solana-bincode", + "solana-borsh", + "solana-clock", + "solana-cpi", + "solana-decode-error", + "solana-define-syscall", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-hash", + "solana-instruction", + "solana-last-restart-slot", + "solana-msg", + "solana-native-token", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-program-option", + "solana-program-pack", + "solana-pubkey", + "solana-rent", + "solana-sanitize", "solana-sdk-macro", - "thiserror", + "solana-secp256k1-recover", + "solana-serde-varint", + "solana-serialize-utils", + "solana-sha256-hasher", + "solana-short-vec", + "solana-slot-hashes", + "solana-slot-history", + "solana-stable-layout", + "solana-transaction-error", + "thiserror 1.0.69", "wasm-bindgen", ] +[[package]] +name = "solana-program-entrypoint" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eb90f3fa3e979b912451a404508f1f90bb6e5c1d7767625f622b20016fb9fde" +dependencies = [ + "solana-account-info", + "solana-msg", + "solana-program-error", + "solana-pubkey", +] + +[[package]] +name = "solana-program-error" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd089caeef26dd07bd12b7b67d45e92faddc2fc67a960f316df7ae4776a2f3d5" +dependencies = [ + "borsh 1.5.3", + "num-traits", + "serde", + "serde_derive", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-pubkey", +] + +[[package]] +name = "solana-program-memory" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed4bc044dc2b49c323aeff04aec03c908a052e278c2edf2f7616f32fc0f1bcd9" +dependencies = [ + "num-traits", + "solana-define-syscall", +] + +[[package]] +name = "solana-program-option" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3babbdffd81994c043fc9a61458ce87496218825d6e9a303de643c0a53089b9a" + +[[package]] +name = "solana-program-pack" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fb28439d23e1f505e59c7a14ed5012365ab7aa0f20dc7bda048e02ff231cf6" +dependencies = [ + "solana-program-error", +] + [[package]] name = "solana-program-runtime" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f70c2156446824a18421c6be3976fd739cfa293e94ff44cd0954dfde5941233c" +checksum = "ba1de51df173401d50c0f4cf750f5070d7a4c82125a03c1aec9622dc041b0b54" dependencies = [ - "base64 0.13.0", + "base64 0.22.1", "bincode", "enum-iterator", - "itertools", + "itertools 0.12.1", "libc", - "libloading", "log", "num-derive", "num-traits", - "rustc_version 0.4.0", + "percentage", + "rand 0.8.5", "serde", - "solana-frozen-abi", - "solana-frozen-abi-macro", + "solana-compute-budget", + "solana-feature-set", + "solana-log-collector", "solana-measure", + "solana-metrics", "solana-sdk", - "thiserror", + "solana-timings", + "solana-type-overrides", + "solana-vote", + "solana_rbpf", + "thiserror 1.0.69", ] [[package]] name = "solana-program-test" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f25303f31e6160c2b0fa15b840ce9ca652cb6d04e123230f705f498b73e33183" +checksum = "974591eca853eafee8196a3445b81fd03ebd9b3e38a6dd7b6f22dc3414c32be6" dependencies = [ + "assert_matches", "async-trait", - "base64 0.13.0", + "base64 0.22.1", "bincode", "chrono-humanize", + "crossbeam-channel", "log", "serde", + "solana-accounts-db", "solana-banks-client", + "solana-banks-interface", "solana-banks-server", "solana-bpf-loader-program", + "solana-compute-budget", + "solana-feature-set", + "solana-inline-spl", + "solana-instruction", + "solana-log-collector", "solana-logger", "solana-program-runtime", "solana-runtime", "solana-sdk", + "solana-svm", + "solana-timings", "solana-vote-program", - "thiserror", + "solana_rbpf", + "thiserror 1.0.69", + "tokio", +] + +[[package]] +name = "solana-pubkey" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bea3215775fcedf200d47590c7e2ce9a3a46bc2b7d3f77d0eae9c6edf0a39aec" +dependencies = [ + "borsh 0.10.3", + "borsh 1.5.3", + "bs58", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "five8_const", + "getrandom 0.2.10", + "js-sys", + "num-traits", + "rand 0.8.5", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-decode-error", + "solana-define-syscall", + "solana-sanitize", + "solana-sha256-hasher", + "wasm-bindgen", +] + +[[package]] +name = "solana-pubsub-client" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d28adf5ff89c19ef3cb24d0f484afa05852697881c2e4ef12aec190d61f76d8" +dependencies = [ + "crossbeam-channel", + "futures-util", + "log", + "reqwest", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder", + "solana-rpc-client-api", + "solana-sdk", + "thiserror 1.0.69", + "tokio", + "tokio-stream", + "tokio-tungstenite", + "tungstenite", + "url 2.5.2", +] + +[[package]] +name = "solana-quic-client" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "259c6d420c0b7620557700f13fbbdb00afbb1b82274485c27ba30dd660ea921b" +dependencies = [ + "async-lock", + "async-trait", + "futures 0.3.31", + "itertools 0.12.1", + "lazy_static", + "log", + "quinn", + "quinn-proto", + "rustls 0.23.18", + "solana-connection-cache", + "solana-measure", + "solana-metrics", + "solana-net-utils", + "solana-rpc-client-api", + "solana-sdk", + "solana-streamer", + "thiserror 1.0.69", "tokio", ] [[package]] name = "solana-rayon-threadlimit" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34f6dabbe88f6dffff8f88178635e0a81d603f056a32e3ad4787b442687500f2" +checksum = "4c69806ad1a7b0986f750134e13e55d83919631d81a2328a588615740e14ed0a" dependencies = [ "lazy_static", "num_cpus", @@ -5267,11 +6405,11 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0083b9dac3ff1a668057a75c3f49fae8eb8d5dfc9caece270679b396bb4d2846" +checksum = "6f36cf8ad0090276b5e9c73512df889b84092761ed733a26781b164c9e95f544" dependencies = [ - "console 0.15.0", + "console", "dialoguer", "hidapi", "log", @@ -5279,42 +6417,36 @@ dependencies = [ "num-traits", "parking_lot 0.12.0", "qstring", - "semver 1.0.7", + "semver", + "solana-derivation-path", "solana-sdk", - "thiserror", + "thiserror 1.0.69", "uriparse", ] [[package]] -name = "solana-replica-lib" -version = "1.10.33" +name = "solana-rent" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e706a61be896aea03f7e07b2c2da7b13158c4257d3320cce43215d9e1a4973" +checksum = "aab3f4a270196c38d62c3bb3c7a2f07732af2c772b50da49c9b1e2c9d2ace286" dependencies = [ - "crossbeam-channel", - "futures-util", - "log", - "prost 0.10.0", - "solana-rpc", - "solana-runtime", - "solana-sdk", - "tokio", - "tonic 0.7.1", - "tonic-build 0.7.0", + "serde", + "serde_derive", + "solana-sdk-macro", ] [[package]] name = "solana-rpc" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99ebbe110c68da4aca684e4f62d68ab430737819e80a92343e2a92f37e61bd73" +checksum = "b6e2cf5309990480e4d52e59850bbd8181e1e2c8d4321a44b1c6b89e05df2c44" dependencies = [ - "base64 0.13.0", + "base64 0.22.1", "bincode", "bs58", "crossbeam-channel", "dashmap", - "itertools", + "itertools 0.12.1", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -5329,39 +6461,112 @@ dependencies = [ "serde_json", "soketto", "solana-account-decoder", + "solana-accounts-db", "solana-client", "solana-entry", "solana-faucet", + "solana-feature-set", "solana-gossip", + "solana-inline-spl", "solana-ledger", "solana-measure", "solana-metrics", "solana-perf", "solana-poh", "solana-rayon-threadlimit", + "solana-rpc-client-api", "solana-runtime", "solana-sdk", "solana-send-transaction-service", + "solana-stake-program", "solana-storage-bigtable", "solana-streamer", + "solana-svm", + "solana-tpu-client", "solana-transaction-status", "solana-version", + "solana-vote", "solana-vote-program", - "spl-token 3.3.0", - "spl-token-2022 0.2.0", + "spl-token 6.0.0", + "spl-token-2022 4.0.0", "stream-cancel", - "thiserror", + "thiserror 1.0.69", "tokio", - "tokio-util 0.6.9", + "tokio-util 0.7.1", +] + +[[package]] +name = "solana-rpc-client" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b05822aceeb484074a72d82a1b289da9fc3383f9ba3f55ce4bfd003bf9d62e6" +dependencies = [ + "async-trait", + "base64 0.22.1", + "bincode", + "bs58", + "indicatif", + "log", + "reqwest", + "reqwest-middleware", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-rpc-client-api", + "solana-sdk", + "solana-transaction-status-client-types", + "solana-version", + "solana-vote-program", + "tokio", +] + +[[package]] +name = "solana-rpc-client-api" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb9c6e64f01cfafef9b2d43d6adb02979bb22f579ec8ee88b77796259acce92e" +dependencies = [ + "anyhow", + "base64 0.22.1", + "bs58", + "jsonrpc-core", + "reqwest", + "reqwest-middleware", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-inline-spl", + "solana-sdk", + "solana-transaction-status-client-types", + "solana-version", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-rpc-client-nonce-utils" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f0ab2d1ca3769c5058c689b438d35eb1cb7d2a32fc4b2b7c16fe72fa187927c" +dependencies = [ + "solana-rpc-client", + "solana-sdk", + "thiserror 1.0.69", ] [[package]] name = "solana-runtime" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17af3f430e3c7d1f41af76d012582a2ad3188251abfe61c3fb4be6b8803a945b" +checksum = "60f579df1ed24b2e7be5c99c2b97cb2a331823008129103b5b7753057ddf3cf7" dependencies = [ + "ahash 0.8.11", + "aquamarine", "arrayref", + "base64 0.22.1", "bincode", "blake3", "bv", @@ -5375,152 +6580,313 @@ dependencies = [ "fnv", "im", "index_list", - "itertools", + "itertools 0.12.1", "lazy_static", + "libc", "log", "lz4", - "memmap2", + "memmap2 0.5.10", + "mockall", + "modular-bitfield", "num-derive", "num-traits", "num_cpus", - "ouroboros", - "rand 0.7.3", + "num_enum", + "percentage", + "qualifier_attr", + "rand 0.8.5", "rayon", "regex", - "rustc_version 0.4.0", "serde", "serde_derive", + "serde_json", + "serde_with", + "solana-accounts-db", "solana-address-lookup-table-program", + "solana-bpf-loader-program", "solana-bucket-map", + "solana-compute-budget", "solana-compute-budget-program", "solana-config-program", - "solana-frozen-abi", - "solana-frozen-abi-macro", + "solana-cost-model", + "solana-feature-set", + "solana-fee", + "solana-inline-spl", + "solana-lattice-hash", + "solana-loader-v4-program", "solana-measure", "solana-metrics", + "solana-perf", + "solana-program", "solana-program-runtime", "solana-rayon-threadlimit", + "solana-runtime-transaction", "solana-sdk", "solana-stake-program", + "solana-svm", + "solana-svm-rent-collector", + "solana-svm-transaction", + "solana-system-program", + "solana-timings", + "solana-transaction-status", + "solana-version", + "solana-vote", "solana-vote-program", + "solana-zk-elgamal-proof-program", + "solana-zk-sdk", "solana-zk-token-proof-program", - "solana-zk-token-sdk 1.10.33", + "solana-zk-token-sdk", + "static_assertions", "strum", "strum_macros", "symlink", "tar", "tempfile", - "thiserror", + "thiserror 1.0.69", "zstd", ] +[[package]] +name = "solana-runtime-transaction" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01e1757d4473c7a2f462d2ce5f3cb5689145cfbde3a6b12161a49e497633ab85" +dependencies = [ + "agave-transaction-view", + "log", + "solana-builtins-default-costs", + "solana-compute-budget", + "solana-pubkey", + "solana-sdk", + "solana-svm-transaction", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-sanitize" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "203b90994371db8cade8e885f74ec9f68ee02a32b25d514594158b2551a4e5ed" + [[package]] name = "solana-sdk" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "636f6c615aca6f75e22b6baceaf0ffed9d74367f9320b07ed57cd9b5ce2e4ff9" +checksum = "524604d94185c189616296e5b7da1014cc96d1e446bd2b26f247f00708b9225a" dependencies = [ - "assert_matches", - "base64 0.13.0", "bincode", - "bitflags", - "borsh", + "bitflags 2.6.0", + "borsh 1.5.3", "bs58", "bytemuck", + "bytemuck_derive", "byteorder", "chrono", - "derivation-path", - "digest 0.10.3", + "digest 0.10.7", "ed25519-dalek", "ed25519-dalek-bip32", - "generic-array 0.14.5", + "getrandom 0.1.16", "hmac 0.12.1", - "itertools", + "itertools 0.12.1", "js-sys", "lazy_static", "libsecp256k1", "log", - "memmap2", + "memmap2 0.5.10", "num-derive", "num-traits", - "pbkdf2 0.10.1", - "qstring", + "num_enum", + "pbkdf2 0.11.0", "rand 0.7.3", - "rand_chacha 0.2.2", - "rustc_version 0.4.0", - "rustversion", + "rand 0.8.5", "serde", "serde_bytes", "serde_derive", "serde_json", - "sha2 0.10.2", - "sha3 0.10.1", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-logger", + "serde_with", + "sha2 0.10.8", + "sha3", + "siphasher", + "solana-account", + "solana-bn254", + "solana-decode-error", + "solana-derivation-path", + "solana-feature-set", + "solana-inflation", + "solana-instruction", + "solana-native-token", + "solana-packet", + "solana-precompile-error", "solana-program", + "solana-program-memory", + "solana-pubkey", + "solana-sanitize", "solana-sdk-macro", - "thiserror", - "uriparse", + "solana-secp256k1-recover", + "solana-serde-varint", + "solana-short-vec", + "solana-signature", + "solana-transaction-error", + "thiserror 1.0.69", "wasm-bindgen", ] [[package]] name = "solana-sdk-macro" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b8bcac4394644f21dc013e932a7df9f536fcecef3e5df43fe362b4ec532ce30" +checksum = "1bd2265b93dce9d3dcf9f395abf1a85b5e06e4da4aa60ca147620003ac3abc67" dependencies = [ "bs58", - "proc-macro2 1.0.36", - "quote 1.0.14", - "rustversion", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 2.0.87", ] +[[package]] +name = "solana-secp256k1-recover" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2eef5a00a75648273c3fb6e3d85b0c8c02fcc1e36c4271664dcc39b6b128d41" +dependencies = [ + "borsh 1.5.3", + "libsecp256k1", + "solana-define-syscall", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-security-txt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" + [[package]] name = "solana-send-transaction-service" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffcfd3f7d9d77831cc14ec80b3f5e95efa56dd4bcac3156f01c5446030b95e2" +checksum = "8dc6adaa31bdaab1e5f8932575e75160f4806553ab5e15e552c258dfe1d5594b" dependencies = [ "crossbeam-channel", "log", "solana-client", + "solana-connection-cache", "solana-measure", "solana-metrics", "solana-runtime", "solana-sdk", + "solana-tpu-client", +] + +[[package]] +name = "solana-serde-varint" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aeb51d3c20e2a61db0ef72617f3b8c9207a342a867af454a95f17add9f6c262" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serialize-utils" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cfb0b57c6a431fb15ff33053caadb6c36aed4e1ce74bea9adfc459a710b3626" +dependencies = [ + "solana-instruction", + "solana-pubkey", + "solana-sanitize", +] + +[[package]] +name = "solana-sha256-hasher" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd115f3a1136314b0183235080d29023530c3a0a5df60505fdb7ea620eff9fd6" +dependencies = [ + "sha2 0.10.8", + "solana-define-syscall", + "solana-hash", +] + +[[package]] +name = "solana-short-vec" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08e55330b694db1139dcdf2a1ea7781abe8bd994dec2ab29e36abfd06e4e9274" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ad9784d110f195a3a4fe423479d18f05b01a1c380a1430644a3b3038fdbe2f0" +dependencies = [ + "bs58", + "ed25519-dalek", + "generic-array 0.14.7", + "rand 0.8.5", + "serde", + "serde_derive", + "solana-sanitize", +] + +[[package]] +name = "solana-slot-hashes" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17d216c0ebf00e95acaf2b1e227e6cc900a5ce50fb81fa0743272851e88a788d" +dependencies = [ + "serde", + "serde_derive", + "solana-hash", +] + +[[package]] +name = "solana-slot-history" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88cbcdf767891c6a40116a5ef8f7241000f074ece4ba80c8f00b4f62705fc8a4" +dependencies = [ + "bv", + "serde", + "serde_derive", +] + +[[package]] +name = "solana-stable-layout" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a5305ca88fb5deb219cd88f04e24f3a131769417d7fcb11a8da1126a8f98d23" +dependencies = [ + "solana-instruction", + "solana-pubkey", ] [[package]] name = "solana-stake-program" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad00016a85a712b016e8965bfc47857b49fccf96aa436b1f74f8760cc4516be" +checksum = "c8bb1a59fdd929becddfaed9ec33a1ca4db853f45ae85e14e4f4054a875fc41d" dependencies = [ "bincode", "log", - "num-derive", - "num-traits", - "rustc_version 0.4.0", - "serde", - "serde_derive", "solana-config-program", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-metrics", + "solana-feature-set", + "solana-log-collector", "solana-program-runtime", "solana-sdk", + "solana-type-overrides", "solana-vote-program", - "thiserror", ] [[package]] name = "solana-storage-bigtable" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d81c3d6fdb2e4bb76a1e9b75c160c1225f80c813037ab390c45bf8f13f28b6c" +checksum = "bd27a62abd1e8abab640ed77565fcbf10745e732fc016013f521f3a46193d07a" dependencies = [ "backoff", "bincode", @@ -5528,15 +6894,15 @@ dependencies = [ "bzip2", "enum-iterator", "flate2", - "futures 0.3.21", + "futures 0.3.31", "goauth", "http", "hyper", "hyper-proxy", "log", "openssl", - "prost 0.10.0", - "prost-types 0.10.0", + "prost", + "prost-types", "serde", "serde_derive", "smpl_jwt", @@ -5544,109 +6910,251 @@ dependencies = [ "solana-sdk", "solana-storage-proto", "solana-transaction-status", - "thiserror", + "thiserror 1.0.69", "tokio", - "tonic 0.7.1", + "tonic", "zstd", ] [[package]] name = "solana-storage-proto" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec85840d9211d85c6affe2ed778084dd3733d61548eee6617a0f06e2e25e4ab9" +checksum = "12335d3d506aa9a49ac0674c00a5ea3de2d617e77ced0611080a3c1cdd61ada5" dependencies = [ "bincode", "bs58", - "prost 0.10.0", + "prost", + "protobuf-src", "serde", "solana-account-decoder", "solana-sdk", "solana-transaction-status", - "tonic-build 0.7.0", + "tonic-build", ] [[package]] name = "solana-streamer" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6fe2555776c5cb437a6682fde283bf115e1230c7108ee8767cd74b395e644f9" +checksum = "ff771524872781eca074e0ba221d72b07fa0800cc1a7ffa400a9eb3e125fb922" dependencies = [ + "async-channel", + "bytes", "crossbeam-channel", + "dashmap", + "futures 0.3.31", "futures-util", + "governor", "histogram", - "indexmap", - "itertools", + "indexmap 2.6.0", + "itertools 0.12.1", "libc", "log", "nix", "pem", "percentage", - "pkcs8", "quinn", - "rand 0.7.3", - "rcgen", - "rustls 0.20.4", + "quinn-proto", + "rand 0.8.5", + "rustls 0.23.18", + "smallvec", + "socket2", + "solana-measure", "solana-metrics", "solana-perf", "solana-sdk", - "thiserror", + "solana-transaction-metrics-tracker", + "thiserror 1.0.69", "tokio", + "tokio-util 0.7.1", "x509-parser", ] [[package]] -name = "solana-sys-tuner" -version = "1.10.33" +name = "solana-svm" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "700a3182befd37b8094b693fadecfb110f78c7e366c842463a4c298f0a9af3d8" +checksum = "43f3b139a001effc93295b693437013f365785fab04dcf2fa679164af4206ec8" dependencies = [ - "clap", - "libc", + "itertools 0.12.1", "log", - "nix", - "solana-logger", - "solana-version", - "sysctl", - "unix_socket2", - "users", + "percentage", + "serde", + "serde_derive", + "solana-bpf-loader-program", + "solana-compute-budget", + "solana-feature-set", + "solana-fee", + "solana-loader-v4-program", + "solana-log-collector", + "solana-measure", + "solana-program-runtime", + "solana-runtime-transaction", + "solana-sdk", + "solana-svm-rent-collector", + "solana-svm-transaction", + "solana-system-program", + "solana-timings", + "solana-type-overrides", + "solana-vote", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-svm-rent-collector" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e7068d6cc69c730190c96b87b106afd42cde203cf56164106792778cd0aaeb" +dependencies = [ + "solana-sdk", +] + +[[package]] +name = "solana-svm-transaction" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38a8533576cb7beca4a44b976ac27df9865bbf8c4cbca2ee8f4f3469cdd8175f" +dependencies = [ + "solana-sdk", +] + +[[package]] +name = "solana-system-program" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "242634cdc1eacaa83738cc100fdd583eb88f99cc2edcc900c8ebe57d77af51b1" +dependencies = [ + "bincode", + "log", + "serde", + "serde_derive", + "solana-log-collector", + "solana-program-runtime", + "solana-sdk", + "solana-type-overrides", ] [[package]] name = "solana-test-validator" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a36f2a7684ee66976c17c89f9b92af3988e6ae279a3bc0371e3ae4cb7685ca1" +checksum = "f1ff3137ff403e0d6c7f04b0800448341e8b4c889eefb2a1cd52e31e71596e72" dependencies = [ - "base64 0.13.0", + "base64 0.22.1", + "bincode", + "crossbeam-channel", "log", "serde_derive", "serde_json", + "solana-accounts-db", "solana-cli-output", - "solana-client", + "solana-compute-budget", "solana-core", + "solana-feature-set", + "solana-geyser-plugin-manager", "solana-gossip", "solana-ledger", "solana-logger", "solana-net-utils", "solana-program-test", "solana-rpc", + "solana-rpc-client", + "solana-rpc-client-api", "solana-runtime", "solana-sdk", "solana-streamer", + "solana-tpu-client", + "tokio", +] + +[[package]] +name = "solana-thin-client" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10314ae3e0889cf38140902862d2c2ea481895c82c19f51dc4457b7dfa3aa6d0" +dependencies = [ + "bincode", + "log", + "rayon", + "solana-connection-cache", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-sdk", +] + +[[package]] +name = "solana-timings" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a8e2f926d488c1e2a65cbc05544dcb68cfa88deb4d50f89db5bfbda7ff2419" +dependencies = [ + "eager", + "enum-iterator", + "solana-sdk", +] + +[[package]] +name = "solana-tpu-client" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516cbed8800cd36fb3ecc9a65df1e76bf8251929aa32e9b10497e8d6612de605" +dependencies = [ + "async-trait", + "bincode", + "futures-util", + "indexmap 2.6.0", + "indicatif", + "log", + "rayon", + "solana-connection-cache", + "solana-measure", + "solana-pubsub-client", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-sdk", + "thiserror 1.0.69", "tokio", ] +[[package]] +name = "solana-transaction-error" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a4bea6d80b34fe6e785d19bf928fe103928d1f6c9935ec23bb6a9d4d7a33d2" +dependencies = [ + "serde", + "serde_derive", + "solana-instruction", + "solana-sanitize", +] + +[[package]] +name = "solana-transaction-metrics-tracker" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0b668c986a83e6b2eb8f130039045b54abc37ee821853250755386d26c1c668" +dependencies = [ + "base64 0.22.1", + "bincode", + "lazy_static", + "log", + "rand 0.8.5", + "solana-perf", + "solana-sdk", + "solana-short-vec", +] + [[package]] name = "solana-transaction-status" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3be33f630671045322f3f3b83e83b9f7dcc38629c75d5415456cc7a8cab5a6b" +checksum = "e3e8ed5bf2511c45b923de25482407c9a2eb56af73dba52c19db76df4dd35cba" dependencies = [ "Inflector", - "base64 0.13.0", + "base64 0.22.1", "bincode", - "borsh", + "borsh 1.5.3", "bs58", "lazy_static", "log", @@ -5654,147 +7162,315 @@ dependencies = [ "serde_derive", "serde_json", "solana-account-decoder", + "solana-sdk", + "solana-transaction-status-client-types", + "spl-associated-token-account 4.0.0", + "spl-memo 5.0.0", + "spl-token 6.0.0", + "spl-token-2022 4.0.0", + "spl-token-group-interface 0.3.0", + "spl-token-metadata-interface 0.4.0", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-transaction-status-client-types" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fb35fb678fec581e9bdf6350d2c7f5829951a6280038fc06949b1589a9605e1" +dependencies = [ + "base64 0.22.1", + "bincode", + "bs58", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-sdk", + "solana-signature", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-turbine" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf66a4e4cf0deed11e1d351fdce52e2a48058bd4b7ece4f5e1e1b435911460e0" +dependencies = [ + "bincode", + "bytes", + "crossbeam-channel", + "futures 0.3.31", + "itertools 0.12.1", + "lazy-lru", + "log", + "lru", + "quinn", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rayon", + "rustls 0.23.18", + "solana-entry", + "solana-feature-set", + "solana-geyser-plugin-manager", + "solana-gossip", + "solana-ledger", "solana-measure", "solana-metrics", + "solana-perf", + "solana-poh", + "solana-quic-client", + "solana-rayon-threadlimit", + "solana-rpc", + "solana-rpc-client-api", "solana-runtime", "solana-sdk", - "solana-vote-program", - "spl-associated-token-account 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-memo 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-token 3.3.0", - "spl-token-2022 0.2.0", - "thiserror", + "solana-streamer", + "static_assertions", + "thiserror 1.0.69", + "tokio", +] + +[[package]] +name = "solana-type-overrides" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2066f25d460d63801f91436c2640aaba4f2dc95aa18fe1e76f7f2c063e981d4e" +dependencies = [ + "lazy_static", + "rand 0.8.5", +] + +[[package]] +name = "solana-udp-client" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ec0cbc2d5e3379fafb2c1493f2358f07c09e76e2081c44e3a8c36da12fbd40" +dependencies = [ + "async-trait", + "solana-connection-cache", + "solana-net-utils", + "solana-sdk", + "solana-streamer", + "thiserror 1.0.69", + "tokio", +] + +[[package]] +name = "solana-unified-scheduler-logic" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd7b34042dc9a9731d47fc0ae1f5e0b4a393b0ad51b27b633df3d21771e4f12b" +dependencies = [ + "assert_matches", + "solana-sdk", + "static_assertions", +] + +[[package]] +name = "solana-unified-scheduler-pool" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "672e74caac59ba67407a9895bd34906edd9b4de1884ece54afb49607919ab957" +dependencies = [ + "assert_matches", + "crossbeam-channel", + "dashmap", + "derivative", + "log", + "qualifier_attr", + "scopeguard", + "solana-ledger", + "solana-runtime", + "solana-sdk", + "solana-timings", + "solana-unified-scheduler-logic", + "static_assertions", + "vec_extract_if_polyfill", ] [[package]] name = "solana-version" -version = "1.10.33" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7310708b642fb83c04f44934509f4f149ffd69d0cd4cf76d9645c991177d7ea0" +dependencies = [ + "semver", + "serde", + "serde_derive", + "solana-feature-set", + "solana-sanitize", + "solana-serde-varint", +] + +[[package]] +name = "solana-vote" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7016d49908046f61806bc327fba3f7cf8715d4aea7a3fff8edfd5f713743c4" +checksum = "5ab46788981765ee706094ca53ad8421aae0286a6b948e892fa7db88992a5373" dependencies = [ + "itertools 0.12.1", "log", - "rustc_version 0.4.0", - "semver 1.0.7", "serde", "serde_derive", - "solana-frozen-abi", - "solana-frozen-abi-macro", "solana-sdk", + "thiserror 1.0.69", ] [[package]] name = "solana-vote-program" -version = "1.10.33" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "637cadc921725d1804a451ea7d2dff83310a12b75e0b6c83a8bb67ebc02d10f1" +dependencies = [ + "bincode", + "log", + "num-derive", + "num-traits", + "serde", + "serde_derive", + "solana-feature-set", + "solana-metrics", + "solana-program", + "solana-program-runtime", + "solana-sdk", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-wen-restart" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a5e990bfaf78ca45d692993538d25c64d983397b6e68a5f25b7673ec082f446" +checksum = "fb5c015db11fa341ee48fd17d573f27960d32e027606c7cd0586c07332923062" dependencies = [ - "bincode", + "anyhow", "log", - "num-derive", - "num-traits", - "rustc_version 0.4.0", - "serde", - "serde_derive", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-metrics", - "solana-program-runtime", + "prost", + "prost-build", + "prost-types", + "protobuf-src", + "rayon", + "solana-entry", + "solana-gossip", + "solana-ledger", + "solana-program", + "solana-runtime", "solana-sdk", - "thiserror", + "solana-timings", + "solana-vote-program", ] [[package]] -name = "solana-zk-token-proof-program" -version = "1.10.33" +name = "solana-zk-elgamal-proof-program" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f363100394910c0c1d9c5451870d892d0613548b04a5450f32ad80e2731cf093" +checksum = "47f5ac026a972c9cbc6bd0f72f692f85ff9ceec961fc4bcb1f2550e6387e962c" dependencies = [ "bytemuck", - "getrandom 0.1.16", "num-derive", "num-traits", + "solana-log-collector", "solana-program-runtime", "solana-sdk", - "solana-zk-token-sdk 1.10.33", + "solana-zk-sdk", ] [[package]] -name = "solana-zk-token-sdk" -version = "0.8.1" +name = "solana-zk-sdk" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74b149253f9ed1afb68b3161b53b62b637d0dd7a3b328dffdc8bb5878d48358e" +checksum = "18c2d96f65cb033f4dc16d3a1b085f8af0ea38012c514a8f65b9b6d75bc9339f" dependencies = [ "aes-gcm-siv", - "arrayref", - "base64 0.13.0", + "base64 0.22.1", "bincode", "bytemuck", - "byteorder", - "cipher 0.3.0", - "curve25519-dalek", - "getrandom 0.1.16", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "itertools 0.12.1", + "js-sys", "lazy_static", "merlin", "num-derive", "num-traits", - "rand 0.7.3", + "rand 0.8.5", "serde", + "serde_derive", "serde_json", - "sha3 0.9.1", + "sha3", + "solana-derivation-path", "solana-program", "solana-sdk", "subtle", - "thiserror", + "thiserror 1.0.69", + "wasm-bindgen", "zeroize", ] +[[package]] +name = "solana-zk-token-proof-program" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83029f0fac09633fc4463dd5a7d13959d1825dccf77889c6e617e2b1265fb2f1" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "solana-feature-set", + "solana-log-collector", + "solana-program-runtime", + "solana-sdk", + "solana-zk-token-sdk", +] + [[package]] name = "solana-zk-token-sdk" -version = "1.10.33" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "410ee53a26ac91098c289c983863535d4fbb6604b229ae1159503f48fa4fc90f" +checksum = "ed293089d8eebd6b5c1b53ee4ad6817889fea254274ddb34cb01ad35a2f817cb" dependencies = [ "aes-gcm-siv", - "arrayref", - "base64 0.13.0", + "base64 0.22.1", "bincode", "bytemuck", + "bytemuck_derive", "byteorder", - "cipher 0.4.3", - "curve25519-dalek", - "getrandom 0.1.16", + "curve25519-dalek 4.1.3", + "itertools 0.12.1", "lazy_static", "merlin", "num-derive", "num-traits", - "rand 0.7.3", + "rand 0.8.5", "serde", + "serde_derive", "serde_json", - "sha3 0.9.1", + "sha3", + "solana-curve25519", + "solana-derivation-path", "solana-program", "solana-sdk", "subtle", - "thiserror", + "thiserror 1.0.69", "zeroize", ] [[package]] name = "solana_rbpf" -version = "0.2.24" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41e138f6d6d4eb6a65f8e9f01ca620bc9907d79648d5038a69dd3f07b6ed3f1f" +checksum = "1c1941b5ef0c3ce8f2ac5dd984d0fb1a97423c4ff2a02eec81e3913f02e2ac2b" dependencies = [ "byteorder", - "combine", - "goblin", + "combine 3.8.1", "hash32", "libc", "log", - "rand 0.7.3", + "rand 0.8.5", "rustc-demangle", "scroll", - "thiserror", - "time 0.1.44", + "thiserror 1.0.69", + "winapi 0.3.9", ] [[package]] @@ -5810,57 +7486,144 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5" [[package]] -name = "spki" -version = "0.5.4" +name = "spinning_top" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" +checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" dependencies = [ - "base64ct", - "der", + "lock_api", ] [[package]] name = "spl-associated-token-account" -version = "1.0.5" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68034596cf4804880d265f834af1ff2f821ad5293e41fa0f8f59086c181fc38e" dependencies = [ "assert_matches", - "borsh", + "borsh 1.5.3", "num-derive", "num-traits", "solana-program", - "solana-program-test", - "solana-sdk", - "spl-token 3.3.1", - "spl-token-2022 0.4.2", - "thiserror", + "spl-token 6.0.0", + "spl-token-2022 4.0.0", + "thiserror 1.0.69", ] [[package]] name = "spl-associated-token-account" -version = "1.0.5" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b013067447a1396303ddfc294f36e3d260a32f8a16c501c295bcdc7de39b490" +checksum = "76fee7d65013667032d499adc3c895e286197a35a0d3a4643c80e7fd3e9969e3" dependencies = [ - "borsh", + "borsh 1.5.3", + "num-derive", + "num-traits", "solana-program", - "spl-token 3.3.0", + "spl-associated-token-account-client", + "spl-token 7.0.0", + "spl-token-2022 6.0.0", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-associated-token-account-client" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f8349dbcbe575f354f9a533a21f272f3eb3808a49e2fdc1c34393b88ba76cb" +dependencies = [ + "solana-instruction", + "solana-pubkey", ] [[package]] name = "spl-binary-oracle-pair" version = "0.1.0" dependencies = [ - "borsh", + "borsh 1.5.3", "num-derive", "num-traits", "solana-program", "solana-program-test", "solana-sdk", - "spl-token 3.3.1", - "thiserror", + "spl-token 7.0.0", + "thiserror 2.0.9", "uint", ] +[[package]] +name = "spl-concurrent-merkle-tree" +version = "0.4.0" +dependencies = [ + "bytemuck", + "rand 0.8.5", + "rand_distr", + "solana-program", + "spl-merkle-tree-reference", + "thiserror 2.0.9", + "tokio", +] + +[[package]] +name = "spl-discriminator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38ea8b6dedb7065887f12d62ed62c1743aa70749e8558f963609793f6fb12bc" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator-derive", +] + +[[package]] +name = "spl-discriminator" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7398da23554a31660f17718164e31d31900956054f54f52d5ec1be51cb4f4b3" +dependencies = [ + "bytemuck", + "solana-program-error", + "solana-sha256-hasher", + "spl-discriminator-derive", +] + +[[package]] +name = "spl-discriminator-derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750" +dependencies = [ + "quote", + "spl-discriminator-syn", + "syn 2.0.87", +] + +[[package]] +name = "spl-discriminator-syn" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1f05593b7ca9eac7caca309720f2eafb96355e037e6d373b909a80fe7b69b9" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.87", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-elgamal-registry" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a157622a63a4d12fbd8b347fd75ee442cb913137fa98647824c992fb049a15b" +dependencies = [ + "bytemuck", + "solana-program", + "solana-zk-sdk", + "spl-pod 0.5.0", + "spl-token-confidential-transfer-proof-extraction", +] + [[package]] name = "spl-example-cross-program-invocation" version = "1.0.0" @@ -5907,40 +7670,24 @@ dependencies = [ ] [[package]] -name = "spl-feature-proposal" +name = "spl-example-transfer-tokens" version = "1.0.0" dependencies = [ - "borsh", - "borsh-derive", "solana-program", "solana-program-test", "solana-sdk", - "spl-token 3.3.1", -] - -[[package]] -name = "spl-feature-proposal-cli" -version = "1.2.0" -dependencies = [ - "chrono", - "clap", - "solana-clap-utils", - "solana-cli-config", - "solana-client", - "solana-logger", - "solana-sdk", - "spl-feature-proposal", + "spl-token 7.0.0", ] [[package]] name = "spl-governance" -version = "3.0.0" +version = "4.0.0" dependencies = [ "arrayref", "assert_matches", - "base64 0.13.0", + "base64 0.22.1", "bincode", - "borsh", + "borsh 1.5.3", "num-derive", "num-traits", "proptest", @@ -5953,28 +7700,27 @@ dependencies = [ "spl-governance-addin-mock", "spl-governance-test-sdk", "spl-governance-tools", - "spl-token 3.3.1", - "thiserror", + "spl-token 7.0.0", + "thiserror 2.0.9", ] [[package]] name = "spl-governance-addin-api" -version = "0.1.2" +version = "0.1.4" dependencies = [ - "borsh", + "borsh 1.5.3", "solana-program", "spl-governance-tools", ] [[package]] name = "spl-governance-addin-mock" -version = "0.1.2" +version = "0.1.4" dependencies = [ "arrayref", "assert_matches", - "base64 0.13.0", "bincode", - "borsh", + "borsh 1.5.3", "num-derive", "num-traits", "proptest", @@ -5986,19 +7732,18 @@ dependencies = [ "spl-governance-addin-api", "spl-governance-test-sdk", "spl-governance-tools", - "spl-token 3.3.1", - "thiserror", + "spl-token 7.0.0", + "thiserror 2.0.9", ] [[package]] name = "spl-governance-chat" -version = "0.2.6" +version = "0.2.9" dependencies = [ "arrayref", "assert_matches", - "base64 0.13.0", "bincode", - "borsh", + "borsh 1.5.3", "num-derive", "num-traits", "proptest", @@ -6012,17 +7757,17 @@ dependencies = [ "spl-governance-addin-mock", "spl-governance-test-sdk", "spl-governance-tools", - "spl-token 3.3.1", - "thiserror", + "spl-token 7.0.0", + "thiserror 2.0.9", ] [[package]] name = "spl-governance-test-sdk" -version = "0.1.2" +version = "0.1.4" dependencies = [ "arrayref", "bincode", - "borsh", + "borsh 1.5.3", "lazy_static", "num-derive", "num-traits", @@ -6031,183 +7776,283 @@ dependencies = [ "solana-program", "solana-program-test", "solana-sdk", - "spl-token 3.3.1", - "thiserror", + "spl-token 7.0.0", + "thiserror 2.0.9", ] [[package]] name = "spl-governance-tools" -version = "0.1.2" +version = "0.1.4" dependencies = [ "arrayref", "bincode", - "borsh", + "borsh 1.5.3", "num-derive", "num-traits", "serde", "serde_derive", "solana-program", - "spl-token 3.3.1", - "thiserror", + "spl-token 7.0.0", + "thiserror 2.0.9", ] [[package]] -name = "spl-math" +name = "spl-managed-token" version = "0.1.0" dependencies = [ - "borsh", - "borsh-derive", + "borsh 1.5.3", + "shank", + "solana-program", + "solana-program-test", + "solana-sdk", + "spl-associated-token-account 6.0.0", + "spl-associated-token-account-client", + "spl-token 7.0.0", + "thiserror 2.0.9", +] + +[[package]] +name = "spl-math" +version = "0.3.0" +dependencies = [ "libm", - "num-derive", "num-traits", "proptest", + "uint", +] + +[[package]] +name = "spl-math-example" +version = "0.1.0" +dependencies = [ + "borsh 1.5.3", + "num-derive", + "num-traits", "solana-program", "solana-program-test", "solana-sdk", - "thiserror", - "uint", + "spl-math", + "thiserror 2.0.9", ] [[package]] name = "spl-memo" -version = "3.0.1" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0dba2f2bb6419523405d21c301a32c9f9568354d4742552e7972af801f4bdb3" dependencies = [ "solana-program", - "solana-program-test", - "solana-sdk", ] [[package]] name = "spl-memo" -version = "3.0.1" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0dc6f70db6bacea7ff25870b016a65ba1d1b6013536f08e4fd79a8f9005325" +checksum = "9f09647c0974e33366efeb83b8e2daebb329f0420149e74d3a4bd2c08cf9f7cb" +dependencies = [ + "solana-account-info", + "solana-instruction", + "solana-msg", + "solana-program-entrypoint", + "solana-program-error", + "solana-pubkey", +] + +[[package]] +name = "spl-merkle-tree-reference" +version = "0.1.0" dependencies = [ "solana-program", + "thiserror 2.0.9", ] [[package]] name = "spl-name-service" -version = "0.2.0" +version = "0.3.0" dependencies = [ - "borsh", + "borsh 1.5.3", "num-derive", "num-traits", "solana-program", "solana-program-test", "solana-sdk", - "thiserror", + "thiserror 2.0.9", ] [[package]] -name = "spl-record" -version = "0.1.0" +name = "spl-pod" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6166a591d93af33afd75bbd8573c5fd95fb1213f1bf254f0508c89fdb5ee156" +dependencies = [ + "borsh 1.5.3", + "bytemuck", + "bytemuck_derive", + "solana-program", + "solana-zk-token-sdk", + "spl-program-error 0.5.0", +] + +[[package]] +name = "spl-pod" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a7d5950993e1ff2680bd989df298eeb169367fb2f9deeef1f132de6e4e8016" +dependencies = [ + "borsh 1.5.3", + "bytemuck", + "bytemuck_derive", + "num-derive", + "num-traits", + "solana-decode-error", + "solana-msg", + "solana-program-error", + "solana-program-option", + "solana-pubkey", + "solana-zk-sdk", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-program-error" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7b28bed65356558133751cc32b48a7a5ddfc59ac4e941314630bbed1ac10532" dependencies = [ - "borsh", - "borsh-derive", "num-derive", "num-traits", "solana-program", - "solana-program-test", - "solana-sdk", - "thiserror", + "spl-program-error-derive", + "thiserror 1.0.69", ] [[package]] -name = "spl-shared-memory" -version = "2.0.6" +name = "spl-program-error" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d39b5186f42b2b50168029d81e58e800b690877ef0b30580d107659250da1d1" dependencies = [ - "arrayref", + "num-derive", + "num-traits", "solana-program", - "solana-program-test", - "solana-sdk", + "spl-program-error-derive", + "thiserror 1.0.69", ] [[package]] -name = "spl-stake-pool" -version = "0.6.4" +name = "spl-program-error-derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d375dd76c517836353e093c2dbb490938ff72821ab568b545fd30ab3256b3e" dependencies = [ - "arrayref", - "bincode", - "borsh", - "mpl-token-metadata", + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.87", +] + +[[package]] +name = "spl-record" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1288810a85bbe7e62ee3c6f7b8119e8c1016e90351411d12e4132e98c7ca7344" +dependencies = [ + "bytemuck", "num-derive", "num-traits", - "num_enum", - "proptest", - "serde", - "serde_derive", + "solana-account-info", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-pack", + "solana-pubkey", + "solana-rent", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-shared-memory" +version = "2.0.6" +dependencies = [ + "arrayref", "solana-program", "solana-program-test", "solana-sdk", - "solana-vote-program", - "spl-math", - "spl-token 3.3.1", - "thiserror", ] [[package]] -name = "spl-stake-pool-cli" -version = "0.6.4" +name = "spl-tlv-account-resolution" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a75a5f0fcc58126693ed78a17042e9dc53f07e357d6be91789f7d62aff61a4" dependencies = [ - "bincode", - "borsh", - "bs58", - "clap", - "serde", - "serde_derive", - "serde_json", - "solana-account-decoder", - "solana-clap-utils", - "solana-cli-config", - "solana-cli-output", - "solana-client", - "solana-logger", + "bytemuck", "solana-program", - "solana-remote-wallet", - "solana-sdk", - "spl-associated-token-account 1.0.5", - "spl-stake-pool", - "spl-token 3.3.1", + "spl-discriminator 0.3.0", + "spl-pod 0.3.0", + "spl-program-error 0.5.0", + "spl-type-length-value 0.5.0", +] + +[[package]] +name = "spl-tlv-account-resolution" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd99ff1e9ed2ab86e3fd582850d47a739fec1be9f4661cba1782d3a0f26805f3" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "solana-account-info", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator 0.4.1", + "spl-pod 0.5.0", + "spl-program-error 0.6.0", + "spl-type-length-value 0.7.0", + "thiserror 1.0.69", ] [[package]] name = "spl-token" -version = "3.3.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc67166ef99d10c18cb5e9c208901e6d8255c6513bb1f877977eba48e6cc4fb" +checksum = "70a0f06ac7f23dc0984931b1fe309468f14ea58e32660439c1cef19456f5d0e3" dependencies = [ "arrayref", + "bytemuck", "num-derive", "num-traits", "num_enum", "solana-program", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "spl-token" -version = "3.3.1" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed320a6c934128d4f7e54fe00e16b8aeaecf215799d060ae14f93378da6dc834" dependencies = [ "arrayref", "bytemuck", - "lazy_static", "num-derive", "num-traits", "num_enum", - "proptest", - "serial_test 0.5.1", "solana-program", - "solana-program-test", - "solana-sdk", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "spl-token-2022" -version = "0.2.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fce48c69350134e8678de5c0956a531b7de586b28eebdddc03211ceec0660983" +checksum = "d9c10f3483e48679619c76598d4e4aebb955bc49b0a5cc63323afbf44135c9bf" dependencies = [ "arrayref", "bytemuck", @@ -6215,97 +8060,144 @@ dependencies = [ "num-traits", "num_enum", "solana-program", - "solana-zk-token-sdk 0.8.1", - "spl-memo 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-token 3.3.0", - "thiserror", + "solana-security-txt", + "solana-zk-token-sdk", + "spl-memo 5.0.0", + "spl-pod 0.3.0", + "spl-token 6.0.0", + "spl-token-group-interface 0.3.0", + "spl-token-metadata-interface 0.4.0", + "spl-transfer-hook-interface 0.7.0", + "spl-type-length-value 0.5.0", + "thiserror 1.0.69", ] [[package]] name = "spl-token-2022" -version = "0.4.2" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b27f7405010ef816587c944536b0eafbcc35206ab6ba0f2ca79f1d28e488f4f" dependencies = [ "arrayref", "bytemuck", - "lazy_static", "num-derive", "num-traits", "num_enum", - "proptest", - "serde", - "serde_json", - "serde_with", - "serial_test 0.5.1", "solana-program", - "solana-program-test", - "solana-sdk", - "solana-zk-token-sdk 1.10.33", - "spl-memo 3.0.1", - "spl-token 3.3.1", - "thiserror", + "solana-security-txt", + "solana-zk-sdk", + "spl-elgamal-registry", + "spl-memo 6.0.0", + "spl-pod 0.5.0", + "spl-token 7.0.0", + "spl-token-confidential-transfer-ciphertext-arithmetic", + "spl-token-confidential-transfer-proof-extraction", + "spl-token-confidential-transfer-proof-generation", + "spl-token-group-interface 0.5.0", + "spl-token-metadata-interface 0.6.0", + "spl-transfer-hook-interface 0.9.0", + "spl-type-length-value 0.7.0", + "thiserror 1.0.69", ] [[package]] -name = "spl-token-2022-test" -version = "0.0.1" +name = "spl-token-client" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9155237581388a928822ce91caf936cf54406d27bf21def44f18b25e304ba0e" dependencies = [ "async-trait", - "solana-program", + "bincode", + "bytemuck", + "futures 0.3.31", + "futures-util", + "solana-banks-interface", + "solana-cli-output", "solana-program-test", + "solana-rpc-client", + "solana-rpc-client-api", "solana-sdk", - "spl-associated-token-account 1.0.5", - "spl-memo 3.0.1", - "spl-token-2022 0.4.2", - "spl-token-client", - "walkdir", + "spl-associated-token-account-client", + "spl-elgamal-registry", + "spl-memo 6.0.0", + "spl-record", + "spl-token 7.0.0", + "spl-token-2022 6.0.0", + "spl-token-confidential-transfer-proof-extraction", + "spl-token-confidential-transfer-proof-generation", + "spl-token-group-interface 0.5.0", + "spl-token-metadata-interface 0.6.0", + "spl-transfer-hook-interface 0.9.0", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token-confidential-transfer-ciphertext-arithmetic" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1f1bf731fc65546330a7929a9735679add70f828dd076a4e69b59d3afb5423c" +dependencies = [ + "base64 0.22.1", + "bytemuck", + "solana-curve25519", + "solana-zk-sdk", ] [[package]] -name = "spl-token-cli" -version = "2.0.16" +name = "spl-token-confidential-transfer-proof-extraction" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "383937e637ccbe546f736d5115344351ebd4d2a076907582335261da58236816" dependencies = [ - "assert_cmd", - "clap", - "console 0.14.1", - "indicatif", - "serde", - "serde_derive", - "serde_json", - "serial_test 0.8.0", - "solana-account-decoder", - "solana-clap-utils", - "solana-cli-config", - "solana-cli-output", - "solana-client", - "solana-logger", - "solana-remote-wallet", - "solana-sdk", - "solana-test-validator", - "solana-transaction-status", - "spl-associated-token-account 1.0.5", - "spl-memo 3.0.1", - "spl-token 3.3.1", - "spl-token-2022 0.4.2", - "spl-token-client", - "strum", - "strum_macros", - "tempfile", - "tokio", - "walkdir", + "bytemuck", + "solana-curve25519", + "solana-program", + "solana-zk-sdk", + "spl-pod 0.5.0", + "thiserror 1.0.69", ] [[package]] -name = "spl-token-client" -version = "0.1.0" +name = "spl-token-confidential-transfer-proof-generation" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8627184782eec1894de8ea26129c61303f1f0adeed65c20e0b10bc584f09356d" dependencies = [ - "async-trait", - "solana-client", - "solana-program-test", - "solana-sdk", - "spl-associated-token-account 1.0.5", - "spl-memo 3.0.1", - "spl-token-2022 0.4.2", - "thiserror", + "curve25519-dalek 4.1.3", + "solana-zk-sdk", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token-group-interface" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8752b85a5ecc1d9f3a43bce3dd9a6a053673aacf5deb513d1cbb88d3534ffd" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator 0.3.0", + "spl-pod 0.3.0", + "spl-program-error 0.5.0", +] + +[[package]] +name = "spl-token-group-interface" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d595667ed72dbfed8c251708f406d7c2814a3fa6879893b323d56a10bedfc799" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator 0.4.1", + "spl-pod 0.5.0", + "thiserror 1.0.69", ] [[package]] @@ -6314,19 +8206,15 @@ version = "0.2.0" dependencies = [ "arrayref", "assert_matches", - "base64 0.13.0", "bytemuck", - "log", "num-derive", "num-traits", "proptest", - "serde", - "serde_yaml", "solana-program", "solana-program-test", "solana-sdk", - "spl-token 3.3.1", - "thiserror", + "spl-token 7.0.0", + "thiserror 2.0.9", "uint", ] @@ -6334,17 +8222,52 @@ dependencies = [ name = "spl-token-lending-cli" version = "0.2.0" dependencies = [ - "clap", + "clap 2.34.0", "solana-clap-utils", "solana-cli-config", "solana-client", "solana-logger", "solana-program", "solana-sdk", - "spl-token 3.3.1", + "spl-token 7.0.0", "spl-token-lending", ] +[[package]] +name = "spl-token-metadata-interface" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6c2318ddff97e006ed9b1291ebec0750a78547f870f62a69c56fe3b46a5d8fc" +dependencies = [ + "borsh 1.5.3", + "solana-program", + "spl-discriminator 0.3.0", + "spl-pod 0.3.0", + "spl-program-error 0.5.0", + "spl-type-length-value 0.5.0", +] + +[[package]] +name = "spl-token-metadata-interface" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfb9c89dbc877abd735f05547dcf9e6e12c00c11d6d74d8817506cab4c99fdbb" +dependencies = [ + "borsh 1.5.3", + "num-derive", + "num-traits", + "solana-borsh", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator 0.4.1", + "spl-pod 0.5.0", + "spl-type-length-value 0.7.0", + "thiserror 1.0.69", +] + [[package]] name = "spl-token-swap" version = "3.0.0" @@ -6356,12 +8279,13 @@ dependencies = [ "num-traits", "proptest", "roots", - "sim", "solana-program", "solana-sdk", "spl-math", - "spl-token 3.3.1", - "thiserror", + "spl-token 7.0.0", + "spl-token-2022 6.0.0", + "test-case", + "thiserror 2.0.9", ] [[package]] @@ -6372,99 +8296,158 @@ dependencies = [ "honggfuzz", "solana-program", "spl-math", - "spl-token 3.3.1", + "spl-token 7.0.0", "spl-token-swap", ] [[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +name = "spl-token-upgrade" +version = "0.1.1" +dependencies = [ + "num-derive", + "num-traits", + "num_enum", + "solana-program", + "solana-program-test", + "solana-sdk", + "spl-token 7.0.0", + "spl-token-2022 6.0.0", + "spl-token-client", + "test-case", + "thiserror 2.0.9", +] [[package]] -name = "standback" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" +name = "spl-token-upgrade-cli" +version = "0.1.1" dependencies = [ - "version_check", + "clap 3.2.25", + "futures-util", + "solana-clap-v3-utils", + "solana-cli-config", + "solana-client", + "solana-logger", + "solana-remote-wallet", + "solana-sdk", + "solana-test-validator", + "spl-associated-token-account-client", + "spl-token 7.0.0", + "spl-token-2022 6.0.0", + "spl-token-client", + "spl-token-upgrade", + "tokio", + "walkdir", ] [[package]] -name = "stateless-asks" +name = "spl-token-wrap" version = "0.1.0" dependencies = [ - "borsh", - "metaplex-token-metadata", + "bytemuck", + "num_enum", "solana-program", - "solana-program-test", - "solana-sdk", - "spl-associated-token-account 1.0.5", - "spl-token 3.3.1", - "thiserror", + "spl-associated-token-account 6.0.0", + "spl-token 7.0.0", + "spl-token-2022 6.0.0", + "thiserror 2.0.9", ] [[package]] -name = "static_assertions" -version = "1.1.0" +name = "spl-transfer-hook-interface" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +checksum = "a110f33d941275d9f868b96daaa993f1e73b6806cc8836e43075b4d3ad8338a7" +dependencies = [ + "arrayref", + "bytemuck", + "solana-program", + "spl-discriminator 0.3.0", + "spl-pod 0.3.0", + "spl-program-error 0.5.0", + "spl-tlv-account-resolution 0.7.0", + "spl-type-length-value 0.5.0", +] [[package]] -name = "stdweb" -version = "0.4.20" +name = "spl-transfer-hook-interface" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +checksum = "4aa7503d52107c33c88e845e1351565050362c2314036ddf19a36cd25137c043" dependencies = [ - "discard", - "rustc_version 0.2.3", - "stdweb-derive", - "stdweb-internal-macros", - "stdweb-internal-runtime", - "wasm-bindgen", + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "solana-account-info", + "solana-cpi", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator 0.4.1", + "spl-pod 0.5.0", + "spl-program-error 0.6.0", + "spl-tlv-account-resolution 0.9.0", + "spl-type-length-value 0.7.0", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-type-length-value" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdcd73ec187bc409464c60759232e309f83b52a18a9c5610bf281c9c6432918c" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator 0.3.0", + "spl-pod 0.3.0", + "spl-program-error 0.5.0", ] [[package]] -name = "stdweb-derive" -version = "0.5.3" +name = "spl-type-length-value" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +checksum = "ba70ef09b13af616a4c987797870122863cba03acc4284f226a4473b043923f9" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "serde", - "serde_derive", - "syn 1.0.91", + "bytemuck", + "num-derive", + "num-traits", + "solana-account-info", + "solana-decode-error", + "solana-msg", + "solana-program-error", + "spl-discriminator 0.4.1", + "spl-pod 0.5.0", + "thiserror 1.0.69", ] [[package]] -name = "stdweb-internal-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +name = "stateless-asks" +version = "0.1.0" dependencies = [ - "base-x", - "proc-macro2 1.0.36", - "quote 1.0.14", - "serde", - "serde_derive", - "serde_json", - "sha1", - "syn 1.0.91", + "borsh 1.5.3", + "solana-program", + "solana-program-test", + "solana-sdk", + "spl-associated-token-account-client", + "spl-token 7.0.0", + "thiserror 2.0.9", ] [[package]] -name = "stdweb-internal-runtime" -version = "0.1.5" +name = "static_assertions" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "stream-cancel" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0a9eb2715209fb8cc0d942fcdff45674bfc9f0090a0d897e85a22955ad159b" +checksum = "5f9fbf9bd71e4cf18d68a8a0951c0e5b7255920c0cd992c4ff51cddd6ef514a3" dependencies = [ "futures-core", "pin-project", @@ -6485,31 +8468,31 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strum" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96acfc1b70604b8b2f1ffa4c57e59176c7dbb05d556c71ecd2f5498a1dee7f8" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.24.0" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6878079b17446e4d3eba6192bb0a2950d5b14f0ed8424b852310e5a94345d0ef" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ - "heck 0.4.0", - "proc-macro2 1.0.36", - "quote 1.0.14", + "heck 0.4.1", + "proc-macro2", + "quote", "rustversion", - "syn 1.0.91", + "syn 1.0.107", ] [[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" @@ -6519,31 +8502,31 @@ checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" [[package]] name = "syn" -version = "0.15.44" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "unicode-xid 0.1.0", + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] name = "syn" -version = "1.0.91" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "unicode-xid 0.2.2", + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] name = "sync_wrapper" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "synstructure" @@ -6551,10 +8534,10 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", - "unicode-xid 0.2.2", + "proc-macro2", + "quote", + "syn 1.0.107", + "unicode-xid", ] [[package]] @@ -6569,22 +8552,43 @@ dependencies = [ [[package]] name = "sysctl" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1123645dfaf2b5eac6b6c88addafc359c789b8ef2a770ecaef758c1ddf363ea4" +checksum = "225e483f02d0ad107168dc57381a8a40c3aeea6abe47f37506931f861643cfa8" dependencies = [ - "bitflags", + "bitflags 1.3.2", "byteorder", "libc", - "thiserror", + "thiserror 1.0.69", "walkdir", ] +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tar" -version = "0.4.38" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" +checksum = "4ff6c40d3aedb5e06b57c6f669ad17ab063dd1e63d977c6a88e7f4dfa4f04020" dependencies = [ "filetime", "libc", @@ -6593,13 +8597,13 @@ dependencies = [ [[package]] name = "tarpc" -version = "0.27.2" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b85d0a9369a919ba0db919b142a2b704cd207dfc676f7a43c2d105d0bc225487" +checksum = "1c38a012bed6fb9681d3bf71ffaa4f88f3b4b9ed3198cda6e4c8462d24d4bb80" dependencies = [ "anyhow", "fnv", - "futures 0.3.21", + "futures 0.3.31", "humantime", "opentelemetry", "pin-project", @@ -6607,7 +8611,7 @@ dependencies = [ "serde", "static_assertions", "tarpc-plugins", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-serde", "tokio-util 0.6.9", @@ -6621,23 +8625,31 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee42b4e559f17bce0385ebf511a7beb67d5cc33c12c96b7f4e9789919d9c10f" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "task-local-extensions" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba323866e5d033818e3240feeb9f7db2c4296674e4d9e16b97b7bf8f490434e8" +dependencies = [ + "pin-utils", ] [[package]] name = "tempfile" -version = "3.3.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if 1.0.0", "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi 0.3.9", + "once_cell", + "rustix", + "windows-sys 0.59.0", ] [[package]] @@ -6650,28 +8662,53 @@ dependencies = [ ] [[package]] -name = "terminal_size" -version = "0.1.17" +name = "termtree" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b" + +[[package]] +name = "test-case" +version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" +checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8" dependencies = [ - "libc", - "winapi 0.3.9", + "test-case-macros", ] [[package]] -name = "termtree" -version = "0.2.4" +name = "test-case-core" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b" +checksum = "54c25e2cb8f5fcd7318157634e8838aa6f7e4715c96637f969fabaccd1ef5462" +dependencies = [ + "cfg-if 1.0.0", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "test-case-macros" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37cfd7bbc88a0104e304229fba519bdc45501a30b760fb72240342f1289ad257" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.87", + "test-case-core", +] [[package]] name = "test-client" version = "0.1.0" dependencies = [ "solana-sdk", - "spl-memo 3.0.1", - "spl-token 3.3.1", + "spl-memo 6.0.0", + "spl-token 7.0.0", "spl-token-swap", ] @@ -6681,103 +8718,93 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" dependencies = [ - "unicode-width", + "unicode-width 0.1.9", ] [[package]] -name = "thiserror" -version = "1.0.30" +name = "textwrap" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" -dependencies = [ - "thiserror-impl", -] +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] -name = "thiserror-impl" -version = "1.0.30" +name = "thiserror" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "thiserror-impl 1.0.69", ] [[package]] -name = "thread_local" -version = "1.1.4" +name = "thiserror" +version = "2.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" dependencies = [ - "once_cell", + "thiserror-impl 2.0.9", ] [[package]] -name = "time" -version = "0.1.44" +name = "thiserror-impl" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi 0.3.9", + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] -name = "time" -version = "0.2.27" +name = "thiserror-impl" +version = "2.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" -dependencies = [ - "const_fn", - "libc", - "standback", - "stdweb", - "time-macros 0.1.1", - "version_check", - "winapi 0.3.9", +checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] -name = "time" -version = "0.3.9" +name = "thread_local" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" dependencies = [ - "itoa 1.0.1", - "libc", - "num_threads", - "time-macros 0.2.4", + "once_cell", ] [[package]] -name = "time-macros" -version = "0.1.1" +name = "time" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ - "proc-macro-hack", - "time-macros-impl", + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", ] [[package]] -name = "time-macros" -version = "0.2.4" +name = "time-core" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] -name = "time-macros-impl" -version = "0.1.2" +name = "time-macros" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ - "proc-macro-hack", - "proc-macro2 1.0.36", - "quote 1.0.14", - "standback", - "syn 1.0.91", + "num-conv", + "time-core", ] [[package]] @@ -6791,9 +8818,9 @@ dependencies = [ "once_cell", "pbkdf2 0.4.0", "rand 0.7.3", - "rustc-hash", - "sha2 0.9.8", - "thiserror", + "rustc-hash 1.1.0", + "sha2 0.9.9", + "thiserror 1.0.69", "unicode-normalization", "wasm-bindgen", "zeroize", @@ -6801,9 +8828,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] @@ -6816,22 +8843,20 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.14.1" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d0183f6f6001549ab68f8c7585093bb732beefbcf6d23a10b9b95c73a1dd49" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ - "autocfg", + "backtrace", "bytes", "libc", - "memchr", "mio", - "num_cpus", - "once_cell", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "pin-project-lite", "signal-hook-registry", + "socket2", "tokio-macros", - "winapi 0.3.9", + "windows-sys 0.52.0", ] [[package]] @@ -6846,13 +8871,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.7.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] @@ -6867,24 +8892,12 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" -dependencies = [ - "rustls 0.19.1", - "tokio", - "webpki 0.21.4", -] - -[[package]] -name = "tokio-rustls" -version = "0.23.2" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27d5f2b839802bd8267fa19b0530f5a08b9c08cd417976be2a65d130fe1c11b" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.20.4", + "rustls 0.21.12", "tokio", - "webpki 0.22.0", ] [[package]] @@ -6905,9 +8918,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.8" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", @@ -6916,18 +8929,17 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.17.1" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06cda1232a49558c46f8a504d5b93101d42c0bf7f911f12a105ba48168f821ae" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", - "rustls 0.20.4", + "rustls 0.21.12", "tokio", - "tokio-rustls 0.23.2", + "tokio-rustls", "tungstenite", - "webpki 0.22.0", - "webpki-roots", + "webpki-roots 0.25.2", ] [[package]] @@ -6938,7 +8950,6 @@ checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" dependencies = [ "bytes", "futures-core", - "futures-io", "futures-sink", "log", "pin-project-lite", @@ -6954,6 +8965,7 @@ checksum = "0edfdeb067411dba2044da6d1cb2df793dd35add7888d73c16e3381ded401764" dependencies = [ "bytes", "futures-core", + "futures-io", "futures-sink", "pin-project-lite", "tokio", @@ -6970,47 +8982,32 @@ dependencies = [ ] [[package]] -name = "tonic" -version = "0.6.2" +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" + +[[package]] +name = "toml_edit" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff08f4649d10a70ffa3522ca559031285d8e421d727ac85c60825761818f5d0a" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "async-stream", - "async-trait", - "base64 0.13.0", - "bytes", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-timeout", - "percent-encoding 2.1.0", - "pin-project", - "prost 0.9.0", - "prost-derive 0.9.0", - "tokio", - "tokio-rustls 0.22.0", - "tokio-stream", - "tokio-util 0.6.9", - "tower", - "tower-layer", - "tower-service", - "tracing", - "tracing-futures", + "indexmap 2.6.0", + "toml_datetime", + "winnow", ] [[package]] name = "tonic" -version = "0.7.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30fb54bf1e446f44d870d260d99957e7d11fb9d0a0f5bd1a662ad1411cc103f9" +checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" dependencies = [ "async-stream", "async-trait", "axum", - "base64 0.13.0", + "base64 0.21.7", "bytes", "futures-core", "futures-util", @@ -7019,56 +9016,41 @@ dependencies = [ "http-body", "hyper", "hyper-timeout", - "percent-encoding 2.1.0", + "percent-encoding 2.3.1", "pin-project", - "prost 0.10.0", - "prost-derive 0.10.0", - "rustls-pemfile 0.3.0", + "prost", + "rustls-pemfile 1.0.1", "tokio", - "tokio-rustls 0.23.2", + "tokio-rustls", "tokio-stream", - "tokio-util 0.7.1", "tower", "tower-layer", "tower-service", "tracing", - "tracing-futures", -] - -[[package]] -name = "tonic-build" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9403f1bafde247186684b230dc6f38b5cd514584e8bec1dd32514be4745fa757" -dependencies = [ - "proc-macro2 1.0.36", - "prost-build 0.9.0", - "quote 1.0.14", - "syn 1.0.91", ] [[package]] name = "tonic-build" -version = "0.7.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d17087af5c80e5d5fc8ba9878e60258065a0a757e35efe7a05b7904bece1943" +checksum = "a6fdaae4c2c638bb70fe42803a26fbd6fc6ac8c72f5c59f67ecc2a2dcabf4b07" dependencies = [ "prettyplease", - "proc-macro2 1.0.36", - "prost-build 0.10.0", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "prost-build", + "quote", + "syn 1.0.107", ] [[package]] name = "tower" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a89fd63ad6adf737582df5db40d286574513c69a11dac5214dc3b5603d6713e" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ "futures-core", "futures-util", - "indexmap", + "indexmap 1.9.3", "pin-project", "pin-project-lite", "rand 0.8.5", @@ -7080,44 +9062,24 @@ dependencies = [ "tracing", ] -[[package]] -name = "tower-http" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aba3f3efabf7fb41fae8534fc20a817013dd1c12cb45441efb6c82e6556b4cd8" -dependencies = [ - "bitflags", - "bytes", - "futures-core", - "futures-util", - "http", - "http-body", - "http-range-header", - "pin-project-lite", - "tower", - "tower-layer", - "tower-service", -] - [[package]] name = "tower-layer" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" [[package]] name = "tower-service" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.29" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if 1.0.0", "log", "pin-project-lite", "tracing-attributes", @@ -7126,40 +9088,32 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.18" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] name = "tracing-core" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "tracing-futures" -version = "0.2.5" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ - "pin-project", - "tracing", + "once_cell", + "valuable", ] [[package]] name = "tracing-opentelemetry" -version = "0.15.0" +version = "0.17.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "599f388ecb26b28d9c1b2e4437ae019a7b336018b45ed911458cd9ebf91129f6" +checksum = "fbbe89715c1dbbb790059e2565353978564924ee85017b5fff365c872ff6721f" dependencies = [ + "once_cell", "opentelemetry", "tracing", "tracing-core", @@ -7168,9 +9122,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.2.25" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +checksum = "5312f325fe3588e277415f5a6cca1f4ccad0f248c4cd5a4bd33032d7286abc22" dependencies = [ "sharded-slab", "thread_local", @@ -7191,24 +9145,23 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "tungstenite" -version = "0.17.2" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96a2dea40e7570482f28eb57afbe42d97551905da6a9400acc5c328d24004f5" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" dependencies = [ - "base64 0.13.0", "byteorder", "bytes", + "data-encoding", "http", "httparse", "log", "rand 0.8.5", - "rustls 0.20.4", - "sha-1 0.10.0", - "thiserror", - "url 2.2.2", + "rustls 0.21.12", + "sha1", + "thiserror 1.0.69", + "url 2.5.2", "utf-8", - "webpki 0.22.0", - "webpki-roots", + "webpki-roots 0.24.0", ] [[package]] @@ -7225,9 +9178,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" [[package]] name = "uint" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6470ab50f482bde894a037a57064480a246dbfdd5960bd65a44824693f08da5f" +checksum = "909988d098b2f738727b161a106cfc7cab00c539c2687a8836f8e565976fb53e" dependencies = [ "byteorder", "crunchy", @@ -7235,6 +9188,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + [[package]] name = "unicase" version = "2.6.0" @@ -7246,24 +9205,30 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.7" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" [[package]] name = "unicode-normalization" -version = "0.1.19" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.8.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] name = "unicode-width" @@ -7272,10 +9237,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] -name = "unicode-xid" -version = "0.1.0" +name = "unicode-width" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "unicode-xid" @@ -7283,31 +9248,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" -[[package]] -name = "unindent" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7" - [[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 0.14.5", + "crypto-common", "subtle", ] -[[package]] -name = "unix_socket2" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b57c6eace16c00eccb98a28e85db3370eab0685bdd5e13831d59e2bcb49a1d8a" -dependencies = [ - "libc", -] - [[package]] name = "unreachable" version = "1.0.0" @@ -7317,12 +9267,24 @@ dependencies = [ "void", ] +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "uriparse" version = "0.6.4" @@ -7346,24 +9308,13 @@ dependencies = [ [[package]] name = "url" -version = "2.2.2" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", - "idna 0.2.3", - "matches", - "percent-encoding 2.1.0", -] - -[[package]] -name = "users" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa4227e95324a443c9fcb06e03d4d85e91aabe9a5a02aa818688b6918b6af486" -dependencies = [ - "libc", - "log", + "idna 0.5.0", + "percent-encoding 2.3.1", ] [[package]] @@ -7372,12 +9323,24 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vcpkg" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "vec_extract_if_polyfill" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c9cb5fb67c2692310b6eb3fce7dd4b6e4c9a75be4f2f46b27f0b2b7799759c" + [[package]] name = "vec_map" version = "0.8.2" @@ -7386,9 +9349,9 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version_check" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "void" @@ -7407,12 +9370,11 @@ dependencies = [ [[package]] name = "walkdir" -version = "2.3.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", - "winapi 0.3.9", "winapi-util", ] @@ -7434,32 +9396,33 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.80" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if 1.0.0", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.80" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", - "lazy_static", "log", - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.87", "wasm-bindgen-shared", ] @@ -7477,32 +9440,32 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.80" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ - "quote 1.0.14", + "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.80" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", + "proc-macro2", + "quote", + "syn 2.0.87", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.80" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "web-sys" @@ -7515,32 +9478,27 @@ dependencies = [ ] [[package]] -name = "webpki" -version = "0.21.4" +name = "webpki-roots" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" +checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888" dependencies = [ - "ring", - "untrusted", + "rustls-webpki 0.101.7", ] [[package]] -name = "webpki" -version = "0.22.0" +name = "webpki-roots" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" -dependencies = [ - "ring", - "untrusted", -] +checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" [[package]] name = "webpki-roots" -version = "0.22.1" +version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c475786c6f47219345717a043a37ec04cb4bc185e28853adcc4fa0a947eba630" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" dependencies = [ - "webpki 0.22.0", + "rustls-pki-types", ] [[package]] @@ -7599,54 +9557,169 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.34.0" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5acdd78cb4ba54c0045ac14f62d8f94a03d10047904ae2a40afa1e99d8f70825" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "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_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + [[package]] name = "windows_aarch64_msvc" -version = "0.34.0" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" [[package]] name = "windows_i686_gnu" -version = "0.34.0" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" [[package]] name = "windows_i686_msvc" -version = "0.34.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.34.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "windows_x86_64_msvc" -version = "0.34.0" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] [[package]] name = "winreg" -version = "0.10.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi 0.3.9", + "cfg-if 1.0.0", + "windows-sys 0.48.0", ] [[package]] @@ -7663,83 +9736,85 @@ dependencies = [ "nom", "oid-registry", "rusticata-macros", - "thiserror", - "time 0.3.9", + "thiserror 1.0.69", + "time", ] [[package]] name = "xattr" -version = "0.2.2" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" dependencies = [ "libc", + "linux-raw-sys", + "rustix", ] [[package]] -name = "yaml-rust" -version = "0.4.5" +name = "zerocopy" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" dependencies = [ - "linked-hash-map", + "zerocopy-derive", ] [[package]] -name = "yasna" -version = "0.5.0" +name = "zerocopy-derive" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "346d34a236c9d3e5f3b9b74563f238f955bbd05fa0b8b4efa53c130c43982f4c" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ - "time 0.3.9", + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] name = "zeroize" -version = "1.3.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.2.2" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65f1a51723ec88c66d5d1fe80c841f17f63587d6691901d66be9bec6c3b51f73" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "proc-macro2 1.0.36", - "quote 1.0.14", - "syn 1.0.91", - "synstructure", + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] name = "zstd" -version = "0.11.1+zstd.1.5.2" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a16b8414fde0414e90c612eba70985577451c4c504b99885ebed24762cb81a" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "5.0.1+zstd.1.5.2" +version = "7.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c12659121420dd6365c5c3de4901f97145b79651fb1d25814020ed2ed0585ae" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" dependencies = [ - "libc", "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.1+zstd.1.5.2" +version = "2.0.13+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fd07cbbc53846d9145dbffdf6dd09a7a0aa52be46741825f5c97bdd4f73f12b" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" dependencies = [ "cc", - "libc", + "pkg-config", ] diff --git a/Cargo.toml b/Cargo.toml index 8317eac31e4..ef88ac61895 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,18 @@ +[profile.dev] +split-debuginfo = "unpacked" + +# The curve25519-dalek crate uses the `simd` backend by default in v4 if +# possible, which has very slow performance on some platforms with opt-level 0, +# which is the default for `dev` and `test` builds. This slowdown causes +# certain interactions in the solana-test-validator, such as verifying ZK +# proofs in transactions, to take much more than 400ms, creating problems in +# the test environment. To give better performance in the solana-test-validator +# during tests and dev builds, override the opt-level to 3 for the crate. +[profile.dev.package.curve25519-dalek] +opt-level = 3 + [workspace] members = [ - "associated-token-account/program", "binary-option/program", "binary-oracle-pair/program", "examples/rust/cross-program-invocation", @@ -8,47 +20,47 @@ members = [ "examples/rust/logging", "examples/rust/sysvar", "examples/rust/transfer-lamports", - "feature-proposal/program", - "feature-proposal/cli", + "examples/rust/transfer-tokens", "governance/addin-mock/program", "governance/addin-api", "governance/program", "governance/test-sdk", "governance/tools", "governance/chat/program", + "libraries/concurrent-merkle-tree", "libraries/math", - "memo/program", + "libraries/math-example", + "libraries/merkle-tree-reference", "name-service/program", - "record/program", + "managed-token/program", "shared-memory/program", - "stake-pool/cli", - "stake-pool/program", "stateless-asks/program", + #"token-collection/program", "token-lending/cli", + "token-lending/flash_loan_receiver", "token-lending/program", "token-swap/program", "token-swap/program/fuzz", - "token/cli", - "token/program", - "token/program-2022", - "token/program-2022-test", - "token/client", + "token-upgrade/cli", + "token-upgrade/program", + "token-wrap/program", "utils/cgen", "utils/test-client", - "token-lending/flash_loan_receiver", ] + exclude = [ - "farms/farm-client", - "farms/farm-ctrl", - "farms/farm-rpc", - "farms/farm-sdk", - "farms/fund", - "farms/router-main", - "farms/router-raydium", - "farms/router-saber", - "farms/router-orca", - "farms/vaults", ] -[profile.dev] -split-debuginfo = "unpacked" +resolver = "2" + +[workspace.lints.rust.unexpected_cfgs] +level = "warn" +check-cfg = [ + 'cfg(target_os, values("solana"))', + 'cfg(feature, values("frozen-abi", "no-entrypoint"))', +] + +[workspace.metadata.release] +pre-release-commit-message = "Publish {{crate_name}} v{{version}}" +tag-message = "Publish {{crate_name}} v{{version}}" +consolidate-commits = false diff --git a/LICENSE b/LICENSE index 50bf8b1de23..3a23e7f2e72 100644 --- a/LICENSE +++ b/LICENSE @@ -1,13 +1,51 @@ -Copyright 2020 Solana Foundation. +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - http://www.apache.org/licenses/LICENSE-2.0 +1. Definitions. -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. \ No newline at end of file +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of this License; and +You must cause any modified files to carry prominent notices stating that You changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/README.md b/README.md index 390f8f5465d..1a3d09fb19a 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,33 @@ -[![Build status][travis-image]][travis-url] +# PLEASE READ: This repo no longer contains the SPL program implementations + +This repo still exists in archived form, feel free to fork any reference +implementations it still contains. + +## Migrated Packages + +The Solana Program Library repository has been broken up into separate repos for +each program and set of clients, under the +[solana-program organization](https://github.com/solana-program). + +The following programs have been moved: + +* [Associated-Token-Account](https://github.com/solana-program/associated-token-account) +* [Feature Proposal](https://github.com/solana-program/feature-proposal) +* [Instruction Padding](https://github.com/solana-program/instruction-padding) +* [Libraries](https://github.com/solana-program/libraries) +* [Memo](https://github.com/solana-program/memo) +* [Record](https://github.com/solana-program/record) +* [Single Pool](https://github.com/solana-program/single-pool) +* [Slashing](https://github.com/solana-program/slashing) +* [Stake Pool](https://github.com/solana-program/stake-pool) +* [Token](https://github.com/solana-program/token) +* [Token-2022](https://github.com/solana-program/token-2022) +* [Token-Group](https://github.com/solana-program/token-group) +* [Token-Metadata](https://github.com/solana-program/token-metadata) +* [Token-2022 Transfer Hook](https://github.com/solana-program/transfer-hook) + +The governance programs have been moved to https://github.com/Mythic-Project/solana-program-library/tree/master/governance -[travis-image]: -https://travis-ci.org/solana-labs/solana-program-library.svg?branch=master -[travis-url]: https://travis-ci.org/solana-labs/solana-program-library # Solana Program Library @@ -10,19 +35,116 @@ The Solana Program Library (SPL) is a collection of on-chain programs targeting the [Sealevel parallel runtime](https://medium.com/solana-labs/sealevel-parallel-processing-thousands-of-smart-contracts-d814b378192). These programs are tested against Solana's implementation of Sealevel, -solana-runtime, and deployed to its mainnet. As others implement Sealevel, we -will graciously accept patches to ensure the programs here are portable across -all implementations. - -Full documentation is available at https://spl.solana.com -TypeDocs: https://solana-labs.github.io/solana-program-library/token/js/ +solana-runtime, and some are deployed to Mainnet Beta. As others implement +Sealevel, we will graciously accept patches to ensure the programs here are +portable across all implementations. + +For more information see the [SPL documentation](https://spl.solana.com) and the [Token TypeDocs](https://solana-labs.github.io/solana-program-library/token/js/). + +## Deployments + +Only a subset of programs within the Solana Program Library repo are deployed to +the Solana Mainnet Beta. Currently, this includes: + +| Program | Version | +| --- | --- | +| [token](https://github.com/solana-program/token/tree/main/program) | [3.4.0](https://github.com/solana-labs/solana-program-library/releases/tag/token-v3.4.0) | +| [associated-token-account](https://github.com/solana-program/associated-token-account/tree/main/program) | [1.1.0](https://github.com/solana-labs/solana-program-library/releases/tag/associated-token-account-v1.1.0) | +| [token-2022](https://github.com/solana-program/token-2022/tree/main/program) | [1.0.0](https://github.com/solana-labs/solana-program-library/releases/tag/token-2022-v1.0.0) | +| [governance](https://github.com/solana-labs/solana-program-library/tree/master/governance/program) | [3.1.0](https://github.com/solana-labs/solana-program-library/releases/tag/governance-v3.1.0) | +| [stake-pool](https://github.com/solana-program/stake-pool/tree/main/program) | [1.0.0](https://github.com/solana-labs/solana-program-library/releases/tag/stake-pool-v1.0.0) | +| [account-compression](https://github.com/solana-labs/solana-program-library/tree/master/account-compression/programs/account-compression) | [0.1.3](https://github.com/solana-labs/solana-program-library/releases/tag/account-compression-v0.1.3) | +| [shared-memory](https://github.com/solana-labs/solana-program-library/tree/master/shared-memory/program) | [1.0.0](https://github.com/solana-labs/solana-program-library/commit/b40e0dd3fd6c0e509dc1e8dd3da0a6d609035bbd) | +| [feature-proposal](https://github.com/solana-program/feature-proposal/tree/main/program) | [1.0.0](https://github.com/solana-labs/solana-program-library/releases/tag/feature-proposal-v1.0.0) | +| [name-service](https://github.com/solana-labs/solana-program-library/tree/master/name-service/program) | [0.3.0](https://github.com/solana-labs/solana-program-library/releases/tag/name-service-v0.3.0) | +| [memo](https://github.com/solana-program/memo/tree/main/program) | [3.0.0](https://github.com/solana-labs/solana-program-library/releases/tag/memo-v3.0.0) | +| [single-pool](https://github.com/solana-program/single-pool/tree/main/program) | [1.0.1](https://github.com/solana-labs/solana-program-library/releases/tag/single-pool-v1.0.1) | + +## Audits + +Only a subset of programs within the Solana Program Library repo are audited. Currently, this includes: + +| Program | Last Audit Date | Version | +| --- | --- | --- | +| [token](https://github.com/solana-program/token) | 2022-08-04 (Peer review) | [4fadd55](https://github.com/solana-labs/solana-program-library/commit/4fadd553e1c549afd1d62aeb5ffa7ef31d1999d1) | +| [associated-token-account](https://github.com/solana-program/associated-token-account) | 2022-08-04 (Peer review) | [c00194d](https://github.com/solana-labs/solana-program-library/commit/c00194d2257302f028f44a403c6dee95c0f9c3bc) | +| [token-2022](https://github.com/solana-program/token-2022) | [2023-11-03](https://github.com/solana-labs/security-audits/blob/master/spl/OtterSecToken2022Audit-2023-11-03.pdf) | [e924132](https://github.com/solana-labs/solana-program-library/tree/e924132d65ba0896249fb4983f6f97caff15721a) | +| [stake-pool](https://github.com/solana-program/stake-pool) | [2023-12-31](https://github.com/solana-labs/security-audits/blob/master/spl/HalbornStakePoolAudit-2023-12-31.pdf) | [a17fffe](https://github.com/solana-labs/solana-program-library/commit/a17fffe70d6cc13742abfbc4a4a375b087580bc1) | +| [account-compression](https://github.com/solana-labs/solana-program-library/tree/master/account-compression/programs/account-compression) | [2022-12-05](https://github.com/solana-labs/security-audits/blob/master/spl/OtterSecAccountCompressionAudit-2022-12-03.pdf) | [6e81794](https://github.com/solana-labs/solana-program-library/commit/6e81794) | +| [shared-memory](https://github.com/solana-labs/solana-program-library/tree/master/shared-memory/program) | [2021-02-25](https://github.com/solana-labs/security-audits/blob/master/spl/KudelskiTokenSwapSharedMemAudit-2021-02-25.pdf) | [b40e0dd](https://github.com/solana-labs/solana-program-library/commit/b40e0dd3fd6c0e509dc1e8dd3da0a6d609035bbd) | +| [single-pool](https://github.com/solana-program/single-pool) | [2024-01-02](https://github.com/solana-labs/security-audits/blob/master/spl/ZellicSinglePoolAudit-2024-01-02.pdf) | [ef44df9](https://github.com/solana-labs/solana-program-library/commit/ef44df985e76a697ee9a8aabb3a223610e4cf1dc) | + +All other programs may be updated from time to time. These programs are not +audited, so fork and deploy them at your own risk. Here is the full list of +unaudited programs: + +* [binary-option](https://github.com/solana-labs/solana-program-library/tree/master/binary-option/program) +* [binary-oracle-pair](https://github.com/solana-labs/solana-program-library/tree/master/binary-oracle-pair/program) +* [feature-proposal](https://github.com/solana-program/feature-proposal) +* [instruction-padding](https://github.com/solana-program/instruction-padding) +* [managed-token](https://github.com/solana-labs/solana-program-library/tree/master/managed-token/program) +* [name-service](https://github.com/solana-labs/solana-program-library/tree/master/name-service/program) +* [record](https://github.com/solana-program/record) +* [stateless-asks](https://github.com/solana-labs/solana-program-library/tree/master/stateless-asks/program) +* [token-lending](https://github.com/solana-labs/solana-program-library/tree/master/token-lending/program) +* [token-swap](https://github.com/solana-labs/solana-program-library/tree/master/token-swap/program) +* [token-upgrade](https://github.com/solana-labs/solana-program-library/tree/master/token-upgrade/program) + +More information about the repository's security policy at +[SECURITY.md](https://github.com/solana-labs/solana-program-library/tree/master/SECURITY.md). + +The [security-audits repo](https://github.com/solana-labs/security-audits) contains +all past and present program audits. + +## Program Packages + +| Package | Description | Version | Docs | +| :-- | :-- | :--| :-- | +| `spl-token` | ERC20-like token program on Solana | [![Crates.io](https://img.shields.io/crates/v/spl-token)](https://crates.io/crates/spl-token) | [![Docs.rs](https://docs.rs/spl-token/badge.svg)](https://docs.rs/spl-token) | +| `spl-token-2022` | Token program compatible with `spl-token`, with extensions | [![Crates.io](https://img.shields.io/crates/v/spl-token-2022)](https://crates.io/crates/spl-token-2022) | [![Docs.rs](https://docs.rs/spl-token-2022/badge.svg)](https://docs.rs/spl-token-2022) | +| `spl-associated-token-account` | Stateless protocol defining a canonical "associated" token account for a wallet | [![Crates.io](https://img.shields.io/crates/v/spl-associated-token-account)](https://crates.io/crates/spl-associated-token-account) | [![Docs.rs](https://docs.rs/spl-associated-token-account/badge.svg)](https://docs.rs/spl-associated-token-account) | +| `spl-governance` | DAO program using tokens for voting | [![Crates.io](https://img.shields.io/crates/v/spl-governance)](https://crates.io/crates/spl-governance) | [![Docs.rs](https://docs.rs/spl-governance/badge.svg)](https://docs.rs/spl-governance) | +| `spl-account-compression` | Program for managing compressed accounts stored in an off-chain merkle tree | [![Crates.io](https://img.shields.io/crates/v/spl-account-compression)](https://crates.io/crates/spl-account-compression) | [![Docs.rs](https://docs.rs/spl-account-compression/badge.svg)](https://docs.rs/spl-account-compression) | +| `spl-feature-proposal` | Program using tokens to vote on enabling Solana network features | [![Crates.io](https://img.shields.io/crates/v/spl-feature-proposal)](https://crates.io/crates/spl-feature-proposal) | [![Docs.rs](https://docs.rs/spl-feature-proposal/badge.svg)](https://docs.rs/spl-feature-proposal) | +| `spl-noop` | Program that does nothing, used for logging instruction data | [![Crates.io](https://img.shields.io/crates/v/spl-noop)](https://crates.io/crates/spl-noop) | [![Docs.rs](https://docs.rs/spl-noop/badge.svg)](https://docs.rs/spl-noop) | +| `spl-name-service` | Program for managing ownership of data on-chain | [![Crates.io](https://img.shields.io/crates/v/spl-name-service)](https://crates.io/crates/spl-name-service) | [![Docs.rs](https://docs.rs/spl-name-service/badge.svg)](https://docs.rs/spl-name-service) | +| `spl-shared-memory` | Program for sharing data between programs | [![Crates.io](https://img.shields.io/crates/v/spl-shared-memory)](https://crates.io/crates/spl-shared-memory) | [![Docs.rs](https://docs.rs/spl-shared-memory/badge.svg)](https://docs.rs/spl-shared-memory) | +| `spl-stake-pool` | Program for pooling stake accounts, managed by another entity | [![Crates.io](https://img.shields.io/crates/v/spl-stake-pool)](https://crates.io/crates/spl-stake-pool) | [![Docs.rs](https://docs.rs/spl-stake-pool/badge.svg)](https://docs.rs/spl-stake-pool) | +| `spl-instruction-padding` | Program to padding to other instructions | [![Crates.io](https://img.shields.io/crates/v/spl-instruction-padding)](https://crates.io/crates/spl-instruction-padding) | [![Docs.rs](https://docs.rs/spl-instruction-padding/badge.svg)](https://docs.rs/spl-instruction-padding) | +| `spl-concurrent-merkle-tree` | Library for on-chain representation of merkle tree | [![Crates.io](https://img.shields.io/crates/v/spl-concurrent-merkle-tree)](https://crates.io/crates/spl-concurrent-merkle-tree) | [![Docs.rs](https://docs.rs/spl-concurrent-merkle-tree/badge.svg)](https://docs.rs/spl-concurrent-merkle-tree) | +| `spl-math` | Library for on-chain math | [![Crates.io](https://img.shields.io/crates/v/spl-math)](https://crates.io/crates/spl-math) | [![Docs.rs](https://docs.rs/spl-math/badge.svg)](https://docs.rs/spl-math) | +| `spl-token-lending` | Over-collateralized lending program for tokens | [![Crates.io](https://img.shields.io/crates/v/spl-token-lending)](https://crates.io/crates/spl-token-lending) | [![Docs.rs](https://docs.rs/spl-token-lending/badge.svg)](https://docs.rs/spl-token-lending) | +| `spl-token-swap` | AMM for trading tokens | [![Crates.io](https://img.shields.io/crates/v/spl-token-swap)](https://crates.io/crates/spl-token-swap) | [![Docs.rs](https://docs.rs/spl-token-swap/badge.svg)](https://docs.rs/spl-token-swap) | +| `spl-token-upgrade` | Protocol for burning one token type in exchange for another | [![Crates.io](https://img.shields.io/crates/v/spl-token-upgrade)](https://crates.io/crates/spl-token-upgrade) | [![Docs.rs](https://docs.rs/spl-token-upgrade/badge.svg)](https://docs.rs/spl-token-upgrade) | + +## CLI Packages + +| Package | Description | Version | +| :-- | :-- | :--| +| `spl-token-cli` | CLI for the token, token-2022, and associated-token-account programs | [![Crates.io](https://img.shields.io/crates/v/spl-token-cli)](https://crates.io/crates/spl-token-cli) | +| `spl-stake-pool-cli` | CLI for the stake-pool program | [![Crates.io](https://img.shields.io/crates/v/spl-stake-pool-cli)](https://crates.io/crates/spl-stake-pool-cli) | +| `spl-feature-proposal-cli` | CLI for the feature-proposal program | [![Crates.io](https://img.shields.io/crates/v/spl-feature-proposal-cli)](https://crates.io/crates/spl-feature-proposal-cli) | +| `spl-token-lending-cli` | CLI for the token-lending program | [![Crates.io](https://img.shields.io/crates/v/spl-token-lending-cli)](https://crates.io/crates/spl-token-lending-cli) | +| `spl-token-upgrade-cli` | CLI for the token-upgrade program | [![Crates.io](https://img.shields.io/crates/v/spl-token-upgrade-cli)](https://crates.io/crates/spl-token-upgrade-cli) | + +## JavaScript Packages + +| Package | Description | Version | Docs | +| :-- | :-- | :--| :-- | +| `@solana/spl-token` | Bindings for the token, token-2022, and associated-token-account programs | [![npm](https://img.shields.io/npm/v/@solana/spl-token.svg)](https://www.npmjs.com/package/@solana/spl-token) | [![Docs](https://img.shields.io/badge/docs-typedoc-blue)](https://solana-labs.github.io/solana-program-library/token/js) | +| `@solana/spl-governance` | Bindings for the governance program | [![npm](https://img.shields.io/npm/v/@solana/spl-governance.svg)](https://www.npmjs.com/package/@solana/spl-governance) | N/A | +| `@solana/spl-account-compression` | Bindings for the account-compression program | [![npm](https://img.shields.io/npm/v/@solana/spl-account-compression.svg)](https://www.npmjs.com/package/@solana/spl-account-compression) | [![Docs](https://img.shields.io/badge/docs-typedoc-blue)](https://solana-labs.github.io/solana-program-library/account-compression/sdk/docs) | +| `@solana/spl-name-service` | Bindings for the name-service program | [![npm](https://img.shields.io/npm/v/@solana/spl-name-service.svg)](https://www.npmjs.com/package/@solana/spl-name-service) | N/A | +| `@solana/spl-stake-pool` | Bindings for the stake-pool program | [![npm](https://img.shields.io/npm/v/@solana/spl-stake-pool.svg)](https://www.npmjs.com/package/@solana/spl-stake-pool) | N/A | +| `@solana/spl-token-lending` | Bindings for the token-lending program | [![npm](https://img.shields.io/npm/v/@solana/spl-token-lending.svg)](https://www.npmjs.com/package/@solana/spl-token-lending) | N/A | +| `@solana/spl-token-swap` | Bindings for the token-swap program | [![npm](https://img.shields.io/npm/v/@solana/spl-token-swap.svg)](https://www.npmjs.com/package/@solana/spl-token-swap) | N/A | ## Development ### Environment Setup -1. Install the latest Solana tools from from https://docs.solana.com/cli/install-solana-cli-tools. -2. Install the latest Rust stable from https://rustup.rs/. If you already have Rust, run `rustup update` to get the latest version. +1. Install the latest [Solana tools](https://docs.solana.com/cli/install-solana-cli-tools). +2. Install the latest [Rust stable](https://rustup.rs/). If you already have Rust, run `rustup update` to get the latest version. 3. Install the `libudev` development package for your distribution (`libudev-dev` on Debian-derived distros, `libudev-devel` on Redhat-derived). ### Build @@ -31,11 +153,11 @@ TypeDocs: https://solana-labs.github.io/solana-program-library/token/js/ ```bash # To build all on-chain programs -$ cargo build-bpf +$ cargo build-sbf # To build a specific on-chain program $ cd /program -$ cargo build-bpf +$ cargo build-sbf ``` ### Build clients @@ -54,30 +176,31 @@ $ cargo build Unit tests contained within all projects can be run with: ```bash $ cargo test # <-- runs host-based tests -$ cargo test-bpf # <-- runs BPF program tests +$ cargo test-sbf # <-- runs BPF program tests ``` To run a specific program's tests, such as SPL Token: ```bash $ cd token/program $ cargo test # <-- runs host-based tests -$ cargo test-bpf # <-- runs BPF program tests +$ cargo test-sbf # <-- runs BPF program tests ``` Integration testing may be performed via the per-project .js bindings. See the [token program's js project](token/js) for an example. ### Common Issues + Solutions to a few issues you might run into are mentioned here. 1. `Failed to open: ../../deploy/spl_.so` - - Update your Rust and Cargo to the latest versions and re-run `cargo build-bpf` in the relevant `` directory, + + Update your Rust and Cargo to the latest versions and re-run `cargo build-sbf` in the relevant `` directory, or run it at the repository root to rebuild all on-chain programs. -2. [Error while loading shared libraries. (libssl.so.1.1)](https://github.com/project-serum/anchor/issues/1831) +2. [Error while loading shared libraries. (libssl.so.1.1)](https://solana.stackexchange.com/q/3029/36) - A working solution was mentioned [here](https://github.com/project-serum/anchor/issues/1831#issuecomment-1109124934). + A working solution was mentioned [here](https://solana.stackexchange.com/q/3029/36). Install libssl. ```bash wget http://nz2.archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1l-1ubuntu1.2_amd64.deb @@ -110,6 +233,7 @@ $ rustup toolchain install nightly-x86_64-apple-darwin ## Release Process + SPL programs are currently tagged and released manually. Each program is versioned independently of the others, with all new development occurring on master. Once a program is tested and deemed ready for release: @@ -117,13 +241,12 @@ master. Once a program is tested and deemed ready for release: ### Bump Version * Increment the version number in the program's Cargo.toml - * Generate a new program ID and replace in `/program-id.md` and `/src/lib.rs` - * Run `cargo build-bpf ` to update relevant C bindings. (Note the - location of the generated `spl_.so` for attaching to the Github - release.) + * Run `cargo build-sbf ` to build binary. Note the + location of the generated `spl_.so` for attaching to the GitHub + release. * Open a PR with these version changes and merge after passing CI. -### Create Github tag +### Create GitHub tag Program tags are of the form `-vX.Y.Z`. Create the new tag at the version-bump commit and push to the @@ -134,7 +257,7 @@ $ git tag token-v1.0.0 b24bfe7 $ git push upstream --tags ``` -### Publish Github release +### Publish GitHub release * Go to [GitHub Releases UI](https://github.com/solana-labs/solana-program-library/releases) * Click "Draft new release", and enter the new tag in the "Tag version" box. @@ -145,18 +268,18 @@ $ git push upstream --tags Navigate to the program directory and run `cargo package` to test the build. Then run `cargo publish`. - + # Disclaimer All claims, content, designs, algorithms, estimates, roadmaps, specifications, and performance measurements described in this project -are done with the Solana Foundation's ("SF") best efforts. It is up to +are done with the Solana Labs, Inc. (“SL”) best efforts. It is up to the reader to check and validate their accuracy and truthfulness. Furthermore nothing in this project constitutes a solicitation for investment. -Any content produced by SF or developer resources that SF provides, are -for educational and inspiration purposes only. SF does not encourage, +Any content produced by SL or developer resources that SL provides, are +for educational and inspiration purposes only. SL does not encourage, induce or sanction the deployment, integration or use of any such applications (including the code comprising the Solana blockchain protocol) in violation of applicable laws or regulations and hereby @@ -170,20 +293,10 @@ reader is or is working on behalf of a Specially Designated National (SDN) or a person subject to similar blocking or denied party prohibitions. -The reader should be aware that U.S. export control and sanctions laws -prohibit U.S. persons (and other persons that are subject to such laws) -from transacting with persons in certain countries and territories or -that are on the SDN list. As a project based primarily on open-source -software, it is possible that such sanctioned persons may nevertheless -bypass prohibitions, obtain the code comprising the Solana blockchain -protocol (or other project code or applications) and deploy, integrate, -or otherwise use it. Accordingly, there is a risk to individuals that -other persons using the Solana blockchain protocol may be sanctioned -persons and that transactions with such persons would be a violation of -U.S. export controls and sanctions law. This risk applies to -individuals, organizations, and other ecosystem participants that -deploy, integrate, or use the Solana blockchain protocol code directly -(e.g., as a node operator), and individuals that transact on the Solana -blockchain through light clients, third party interfaces, and/or wallet -software. - +The reader should be aware that U.S. export control and sanctions laws +prohibit U.S. persons (and other persons that are subject to such laws) +from transacting with persons in certain countries and territories or +that are on the SDN list. Accordingly, there is a risk to individuals +that other persons using any of the code contained in this repo, or a +derivation thereof, may be sanctioned persons and that transactions with +such persons would be a violation of U.S. export controls and sanctions law. diff --git a/SECURITY.md b/SECURITY.md index 78a9b939be7..57d453670fd 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,54 +1,13 @@ -# Security Policy - -1. [Reporting security problems](#reporting) -1. [Security Bug Bounties](#bounty) -1. [Scope](#scope) -1. [Incident Response Process](#process) - - -## Reporting security problems to Solana - -**DO NOT CREATE AN ISSUE** to report a security problem. Instead, please send an -email to security@solana.com and provide your github username so we can add you -to a new draft security advisory for further discussion. - -Expect a response as fast as possible, typically within 72 hours. - - -## Security Bug Bounties -We offer bounties for critical security issues. Please see the -[Solana Security Bug Bounties](https://github.com/solana-labs/solana/security/policy#security-bug-bounties) -for details on classes of bugs and payment amounts. - - -## Scope - -Only a subset of programs within the Solana Program Library repo are deployed to -mainnet-beta and maintained by the team. Currently, this includes: - -* [associated-token-account](https://github.com/solana-labs/solana-program-library/tree/master/associated-token-account/program) -* [feature-proposal](https://github.com/solana-labs/solana-program-library/tree/master/feature-proposal/program) -* [governance](https://github.com/solana-labs/solana-program-library/tree/master/governance/program) -* [memo](https://github.com/solana-labs/solana-program-library/tree/master/memo/program) -* [name-service](https://github.com/solana-labs/solana-program-library/tree/master/name-service/program) -* [stake-pool](https://github.com/solana-labs/solana-program-library/tree/master/stake-pool/program) -* [token](https://github.com/solana-labs/solana-program-library/tree/master/token/program) - -If you discover a critical security issue in an out-of-scope program, your finding -may still be valuable. - -Many programs, including -[token-swap](https://github.com/solana-labs/solana-program-library/tree/master/token-swap/program) -and [token-lending](https://github.com/solana-labs/solana-program-library/tree/master/token-lending/program), -have been forked and deployed by prominent ecosystem projects, many of which -have their own bug bounty programs. - -While we cannot guarantee a bounty from another entity, we can help determine who -may be affected and put you in touch the corresponding teams. - - -## Incident Response Process - -In case an incident is discovered or reported, the -[Solana Security Incident Response Process](https://github.com/solana-labs/solana/security/policy#incident-response-process) -will be followed to contain, respond and remediate. +## This repo will be archived soon +Active development in this repo is ending 2024-03-02. Anza is continuing development +in program-specific repos under the +[solana-program organization](https://github.com/solana-program). Please refer to +the security policy in individual repos: + +* [associated-token-account](https://github.com/solana-program/associated-token-account/security) +* [feature-proposal](https://github.com/solana-program/feature-proposal/security) +* [memo](https://github.com/solana-program/memo/security) +* [single-pool](https://github.com/solana-program/single-pool/security) +* [stake-pool](https://github.com/solana-program/stake-pool/security) +* [token](https://github.com/solana-program/token/security) +* [token-2022](https://github.com/solana-program/token-2022/security) diff --git a/account-compression/Anchor.toml b/account-compression/Anchor.toml new file mode 100644 index 00000000000..448f74c0d73 --- /dev/null +++ b/account-compression/Anchor.toml @@ -0,0 +1,13 @@ +[programs.localnet] +spl_account_compression = "cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK" + +[[test.genesis]] +address = "noopb9bkMVfRPU8AsbpTUg8AQkHtKwMYZiFUjNRtMmV" +program = "./target/deploy/wrapper.so" + +[registry] +url = "https://anchor.projectserum.com" + +[provider] +cluster = "localnet" +wallet = "~/.config/solana/id.json" diff --git a/account-compression/Cargo.lock b/account-compression/Cargo.lock new file mode 100644 index 00000000000..7e147646d36 --- /dev/null +++ b/account-compression/Cargo.lock @@ -0,0 +1,1911 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +dependencies = [ + "getrandom 0.2.10", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd7d5a2cecb58716e47d67d5703a249964b14c7be1ec3cad3affc295b2d1c35d" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "anchor-attribute-access-control" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5f619f1d04f53621925ba8a2e633ba5a6081f2ae14758cbb67f38fd823e0a3e" +dependencies = [ + "anchor-syn", + "proc-macro2", + "quote", + "syn 1.0.108", +] + +[[package]] +name = "anchor-attribute-account" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f2a3e1df4685f18d12a943a9f2a7456305401af21a07c9fe076ef9ecd6e400" +dependencies = [ + "anchor-syn", + "bs58 0.5.0", + "proc-macro2", + "quote", + "syn 1.0.108", +] + +[[package]] +name = "anchor-attribute-constant" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9423945cb55627f0b30903288e78baf6f62c6c8ab28fb344b6b25f1ffee3dca7" +dependencies = [ + "anchor-syn", + "quote", + "syn 1.0.108", +] + +[[package]] +name = "anchor-attribute-error" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ed12720033cc3c3bf3cfa293349c2275cd5ab99936e33dd4bf283aaad3e241" +dependencies = [ + "anchor-syn", + "quote", + "syn 1.0.108", +] + +[[package]] +name = "anchor-attribute-event" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eef4dc0371eba2d8c8b54794b0b0eb786a234a559b77593d6f80825b6d2c77a2" +dependencies = [ + "anchor-syn", + "proc-macro2", + "quote", + "syn 1.0.108", +] + +[[package]] +name = "anchor-attribute-program" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b18c4f191331e078d4a6a080954d1576241c29c56638783322a18d308ab27e4f" +dependencies = [ + "anchor-syn", + "quote", + "syn 1.0.108", +] + +[[package]] +name = "anchor-derive-accounts" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de10d6e9620d3bcea56c56151cad83c5992f50d5960b3a9bebc4a50390ddc3c" +dependencies = [ + "anchor-syn", + "quote", + "syn 1.0.108", +] + +[[package]] +name = "anchor-derive-serde" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4e2e5be518ec6053d90a2a7f26843dbee607583c779e6c8395951b9739bdfbe" +dependencies = [ + "anchor-syn", + "borsh-derive-internal 0.10.3", + "proc-macro2", + "quote", + "syn 1.0.108", +] + +[[package]] +name = "anchor-derive-space" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ecc31d19fa54840e74b7a979d44bcea49d70459de846088a1d71e87ba53c419" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.108", +] + +[[package]] +name = "anchor-lang" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35da4785497388af0553586d55ebdc08054a8b1724720ef2749d313494f2b8ad" +dependencies = [ + "anchor-attribute-access-control", + "anchor-attribute-account", + "anchor-attribute-constant", + "anchor-attribute-error", + "anchor-attribute-event", + "anchor-attribute-program", + "anchor-derive-accounts", + "anchor-derive-serde", + "anchor-derive-space", + "anchor-syn", + "arrayref", + "base64 0.13.0", + "bincode", + "borsh 0.10.3", + "bytemuck", + "getrandom 0.2.10", + "solana-program", + "thiserror", +] + +[[package]] +name = "anchor-syn" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9101b84702fed2ea57bd22992f75065da5648017135b844283a2f6d74f27825" +dependencies = [ + "anyhow", + "bs58 0.5.0", + "heck", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2 0.10.8", + "syn 1.0.108", + "thiserror", +] + +[[package]] +name = "anyhow" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" + +[[package]] +name = "ark-bn254" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest 0.10.7", + "itertools", + "num-bigint", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.108", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.108", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.108", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +dependencies = [ + "serde", +] + +[[package]] +name = "bitmaps" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" +dependencies = [ + "typenum", +] + +[[package]] +name = "blake3" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "digest 0.10.7", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "borsh" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" +dependencies = [ + "borsh-derive 0.9.3", + "hashbrown 0.11.2", +] + +[[package]] +name = "borsh" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" +dependencies = [ + "borsh-derive 0.10.3", + "hashbrown 0.13.2", +] + +[[package]] +name = "borsh" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f58b559fd6448c6e2fd0adb5720cd98a2506594cafa4737ff98c396f3e82f667" +dependencies = [ + "borsh-derive 1.3.1", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" +dependencies = [ + "borsh-derive-internal 0.9.3", + "borsh-schema-derive-internal 0.9.3", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.108", +] + +[[package]] +name = "borsh-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" +dependencies = [ + "borsh-derive-internal 0.10.3", + "borsh-schema-derive-internal 0.10.3", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.108", +] + +[[package]] +name = "borsh-derive" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aadb5b6ccbd078890f6d7003694e33816e6b784358f18e15e7e6d9f065a57cd" +dependencies = [ + "once_cell", + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.87", + "syn_derive", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.108", +] + +[[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.108", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.108", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.108", +] + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + +[[package]] +name = "bv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340" +dependencies = [ + "feature-probe", + "serde", +] + +[[package]] +name = "bytemuck" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aca418a974d83d40a0c1f0c5cba6ff4bc28d8df099109ca459a2118d40b6322" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.108", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "console_log" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f" +dependencies = [ + "log", + "web-sys", +] + +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset 0.6.5", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "serde", + "subtle", + "zeroize", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.108", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", + "subtle", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "feature-probe" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "serde", + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash 0.7.7", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.5", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array", + "hmac", +] + +[[package]] +name = "im" +version = "15.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" +dependencies = [ + "bitmaps", + "rand_core 0.6.4", + "rand_xoshiro", + "rayon", + "serde", + "sized-chunks", + "typenum", + "version_check", +] + +[[package]] +name = "indexmap" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "jobserver" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" + +[[package]] +name = "libsecp256k1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9d220bc1feda2ac231cb78c3d26f27676b8cf82c96971f7aeef3d0cf2797c73" +dependencies = [ + "arrayref", + "base64 0.12.3", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.7.3", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "light-poseidon" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" +dependencies = [ + "ark-bn254", + "ark-ff", + "num-bigint", + "thiserror", +] + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "pbkdf2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" +dependencies = [ + "crypto-mac", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.10", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_xoshiro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "rayon" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41d061efea015927ac527063765e73601444cdc344ba855bc7bd44578b25e1c" + +[[package]] +name = "serde" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "serde_json" +version = "1.0.113" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "sized-chunks" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +dependencies = [ + "bitmaps", + "typenum", +] + +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" + +[[package]] +name = "solana-frozen-abi" +version = "1.18.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4867f66e9527fa44451c861c1dc6d9b2a7c7a668d7c6a297cdefbe39f4395b33" +dependencies = [ + "block-buffer 0.10.4", + "bs58 0.4.0", + "bv", + "either", + "generic-array", + "im", + "lazy_static", + "log", + "memmap2", + "rustc_version", + "serde", + "serde_bytes", + "serde_derive", + "sha2 0.10.8", + "solana-frozen-abi-macro", + "subtle", + "thiserror", +] + +[[package]] +name = "solana-frozen-abi-macro" +version = "1.18.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168f24d97347b85f05192df58d6be3e3047a4aadc4001bc1b9e711a5ec878eea" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.87", +] + +[[package]] +name = "solana-program" +version = "1.18.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc5a636dc75e5c25651e34f7a36afc9ae60d38166687c5b0375abb580ac81a2" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-serialize", + "base64 0.21.7", + "bincode", + "bitflags 2.4.2", + "blake3", + "borsh 0.10.3", + "borsh 0.9.3", + "borsh 1.3.1", + "bs58 0.4.0", + "bv", + "bytemuck", + "cc", + "console_error_panic_hook", + "console_log", + "curve25519-dalek", + "getrandom 0.2.10", + "itertools", + "js-sys", + "lazy_static", + "libc", + "libsecp256k1", + "light-poseidon", + "log", + "memoffset 0.9.0", + "num-bigint", + "num-derive", + "num-traits", + "parking_lot", + "rand 0.8.5", + "rustc_version", + "rustversion", + "serde", + "serde_bytes", + "serde_derive", + "serde_json", + "sha2 0.10.8", + "sha3", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-sdk-macro", + "thiserror", + "tiny-bip39", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "solana-sdk-macro" +version = "1.18.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86c76414183a325038ff020b22c07d1e9d2da0703ddc0244acfed37ee2921d96" +dependencies = [ + "bs58 0.4.0", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.87", +] + +[[package]] +name = "spl-account-compression" +version = "0.4.2" +dependencies = [ + "anchor-lang", + "bytemuck", + "solana-program", + "spl-concurrent-merkle-tree", + "spl-noop", +] + +[[package]] +name = "spl-concurrent-merkle-tree" +version = "0.4.0" +dependencies = [ + "bytemuck", + "solana-program", + "thiserror", +] + +[[package]] +name = "spl-noop" +version = "0.2.0" +dependencies = [ + "solana-program", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56e159d99e6c2b93995d171050271edb50ecc5288fbc7cc17de8fdce4e58c14" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "thiserror" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3c6efbfc763e64eb85c11c25320f0737cb7364c4b6336db90aa9ebe27a0bbd" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b607164372e89797d78b8e23a6d67d5d1038c1c65efd52e1389ef8b77caba2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "tiny-bip39" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d" +dependencies = [ + "anyhow", + "hmac", + "once_cell", + "pbkdf2", + "rand 0.7.3", + "rustc-hash", + "sha2 0.9.9", + "thiserror", + "unicode-normalization", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-ident" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.87", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" + +[[package]] +name = "web-sys" +version = "0.3.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "zeroize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] diff --git a/account-compression/Cargo.toml b/account-compression/Cargo.toml new file mode 100644 index 00000000000..94d054a43fc --- /dev/null +++ b/account-compression/Cargo.toml @@ -0,0 +1,7 @@ +[workspace] +members = [ + "programs/account-compression", + "programs/noop" +] + +resolver = "2" diff --git a/account-compression/README.md b/account-compression/README.md new file mode 100644 index 00000000000..19d9632f4bb --- /dev/null +++ b/account-compression/README.md @@ -0,0 +1,36 @@ +# Account Compression (Beta) + +This on-chain program provides an interface for composing smart-contracts to create and use +SPL ConcurrentMerkleTrees. The primary application of using SPL ConcurrentMerkleTrees is +to make edits to off-chain data with on-chain verification. + +This program is targeted towards supporting [Metaplex Compressed NFTs](https://github.com/metaplex-foundation/mpl-bubblegum) and may be subject to change. + +Note: Using this program requires an indexer to parse transaction information and write relevant information to an off-chain database. + +A _**rough draft**_ of the whitepaper for SPL ConcurrentMerkleTree's can be found [here](https://drive.google.com/file/d/1BOpa5OFmara50fTvL0VIVYjtg-qzHCVc/view). + +## Rust Packages + +* `spl-account-compression`: SDK for interacting with account compression program +* `spl-noop`: SDK for interacting with no op program, primarily for circumventing log truncation +* `spl-concurrent-merkle-tree`: SDK for creating SPL ConcurrentMerkleTrees + +## Typescript SDK + +`@solana/spl-account-compression` is generated using Metaplex Foundation's [Solita](https://github.com/metaplex-foundation/solita/). + +## Testing and Development + +Testing contracts locally requires the SDK to be built. + +With a built local SDK, the test suite can be ran with: + +1. `pnpm link @solana/spl-account-compression` +2. `pnpm i` +3. `pnpm test` + +## Audit + +The repository [README](https://github.com/solana-labs/solana-program-library#audits) +contains information about program audits. diff --git a/account-compression/programs/account-compression/Cargo.toml b/account-compression/programs/account-compression/Cargo.toml new file mode 100644 index 00000000000..75895cb151c --- /dev/null +++ b/account-compression/programs/account-compression/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "spl-account-compression" +version = "0.4.2" +description = "Solana Program Library Account Compression Program" +authors = ["Solana Labs Maintainers "] +repository = "https://github.com/solana-labs/solana-program-library" +license = "Apache-2.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] + +[features] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +cpi = ["no-entrypoint"] +default = [] +idl-build = ["anchor-lang/idl-build"] + +[dependencies] +anchor-lang = { version = "0.29.0" } +bytemuck = "1.13" +solana-program = ">=1.18.11,<=2" +spl-concurrent-merkle-tree = { version = "0.4.0", path = "../../../libraries/concurrent-merkle-tree" } +spl-noop = { version = "0.2.0", path = "../noop", features = ["no-entrypoint"] } + +[profile.release] +overflow-checks = true diff --git a/account-compression/programs/account-compression/README.md b/account-compression/programs/account-compression/README.md new file mode 100644 index 00000000000..e720cc57b9d --- /dev/null +++ b/account-compression/programs/account-compression/README.md @@ -0,0 +1,11 @@ +

+ + Solana + +

+ +# SPL Account Compression Rust SDK + +More information about account compression can be found in [the solana-program-library repo](https://github.com/solana-labs/solana-program-library/tree/master/account-compression). + +`spl-account-compression` and this crate's implementation are targeted towards supporting [Metaplex Compressed NFTs](https://github.com/metaplex-foundation/mpl-bubblegum) and may be subject to change. \ No newline at end of file diff --git a/stake-pool/program/Xargo.toml b/account-compression/programs/account-compression/Xargo.toml similarity index 100% rename from stake-pool/program/Xargo.toml rename to account-compression/programs/account-compression/Xargo.toml diff --git a/account-compression/programs/account-compression/src/canopy.rs b/account-compression/programs/account-compression/src/canopy.rs new file mode 100644 index 00000000000..284b2fbbe73 --- /dev/null +++ b/account-compression/programs/account-compression/src/canopy.rs @@ -0,0 +1,561 @@ +//! Canopy is way to cache the upper `N` levels of a SPL ConcurrentMerkleTree. +//! +//! By caching the upper `N` levels of a depth `D` SPL ConcurrentMerkleTree, +//! proofs can be truncated to the first `D - N` nodes. This helps reduce the size of account +//! compression transactions, and makes it possible to +//! modify trees up to depth 31, which store more than 1 billion leaves. +//! +//! Note: this means that creating a tree of depth > 24 without a canopy will be impossible to modify +//! on-chain until TransactionV2 is launched. +//! +//! To initialize a canopy on a ConcurrentMerkleTree account, you must initialize +//! the ConcurrentMerkleTree account with additional bytes. The number of additional bytes +//! needed is `(pow(2, N+1)-1) * 32`, where `N` is the number of levels of the merkle tree +//! you want the canopy to cache. +//! +//! The canopy will be updated everytime the concurrent merkle tree is modified. No additional work +//! needed. + +use crate::error::AccountCompressionError; +use crate::events::ChangeLogEvent; +use anchor_lang::prelude::*; +use bytemuck::{cast_slice, cast_slice_mut}; +use solana_program::keccak::hashv; +use spl_concurrent_merkle_tree::node::{empty_node_cached, empty_node_cached_mut, Node, EMPTY}; +use std::mem::size_of; + +/// Maximum depth of the tree, supported by the SPL Compression +const MAX_SUPPORTED_DEPTH: usize = 30; + +#[inline(always)] +pub fn check_canopy_bytes(canopy_bytes: &[u8]) -> Result<()> { + if canopy_bytes.len() % size_of::() != 0 { + msg!( + "Canopy byte length {} is not a multiple of {}", + canopy_bytes.len(), + size_of::() + ); + err!(AccountCompressionError::CanopyLengthMismatch) + } else { + Ok(()) + } +} + +#[inline(always)] +fn get_cached_path_length(canopy: &[Node], max_depth: u32) -> Result { + // The offset of 2 is applied because the canopy is a full binary tree without the root node + // Size: (2^n - 2) -> Size + 2 must be a power of 2 + let closest_power_of_2 = (canopy.len() + 2) as u32; + // This expression will return true if `closest_power_of_2` is actually a power of 2 + if closest_power_of_2 & (closest_power_of_2 - 1) == 0 { + // (1 << max_depth) returns the number of leaves in the full merkle tree + // (1 << (max_depth + 1)) - 1 returns the number of nodes in the full tree + // The canopy size cannot exceed the size of the tree + if closest_power_of_2 > (1 << (max_depth + 1)) { + msg!( + "Canopy size is too large. Size: {}. Max size: {}", + closest_power_of_2 - 2, + (1 << (max_depth + 1)) - 2 + ); + return err!(AccountCompressionError::CanopyLengthMismatch); + } + } else { + msg!( + "Canopy length {} is not 2 less than a power of 2", + canopy.len() + ); + return err!(AccountCompressionError::CanopyLengthMismatch); + } + // 1 is subtracted from the trailing zeros because the root is not stored in the canopy + Ok(closest_power_of_2.trailing_zeros() - 1) +} + +pub fn update_canopy( + canopy_bytes: &mut [u8], + max_depth: u32, + change_log: Option<&ChangeLogEvent>, +) -> Result<()> { + check_canopy_bytes(canopy_bytes)?; + let canopy = cast_slice_mut::(canopy_bytes); + let path_len = get_cached_path_length(canopy, max_depth)?; + if let Some(cl_event) = change_log { + match &*cl_event { + ChangeLogEvent::V1(cl) => { + // Update the canopy from the newest change log + for path_node in cl.path.iter().rev().skip(1).take(path_len as usize) { + // node_idx - 2 maps to the canopy index + canopy[(path_node.index - 2) as usize] = path_node.node; + } + } + } + } + Ok(()) +} + +pub fn fill_in_proof_from_canopy( + canopy_bytes: &[u8], + max_depth: u32, + index: u32, + proof: &mut Vec, +) -> Result<()> { + let mut empty_node_cache = Box::new([EMPTY; MAX_SUPPORTED_DEPTH]); + check_canopy_bytes(canopy_bytes)?; + let canopy = cast_slice::(canopy_bytes); + let path_len = get_cached_path_length(canopy, max_depth)?; + + // We want to compute the node index (w.r.t. the canopy) where the current path + // intersects the leaves of the canopy + let mut node_idx = ((1 << max_depth) + index) >> (max_depth - path_len); + let mut inferred_nodes = vec![]; + while node_idx > 1 { + // node_idx - 2 maps to the canopy index + let shifted_index = node_idx as usize - 2; + let cached_idx = if shifted_index % 2 == 0 { + shifted_index + 1 + } else { + shifted_index - 1 + }; + if canopy[cached_idx] == EMPTY { + let level = max_depth - (31 - node_idx.leading_zeros()); + let empty_node = empty_node_cached::(level, &mut empty_node_cache); + inferred_nodes.push(empty_node); + } else { + inferred_nodes.push(canopy[cached_idx]); + } + node_idx >>= 1; + } + // We only want to add inferred canopy nodes such that the proof length + // is equal to the tree depth. If the length of proof + length of canopy nodes is + // less than the tree depth, the instruction will fail. + let overlap = (proof.len() + inferred_nodes.len()).saturating_sub(max_depth as usize); + proof.extend(inferred_nodes.iter().skip(overlap)); + Ok(()) +} + +/// Sets the leaf nodes of the canopy. The leaf nodes are the lowest level of the canopy, +/// representing the leaves of the canopy-tree. The method will update the parent nodes of all the +/// modified subtrees up to the uppermost level of the canopy. The leaf nodes indexing for the +/// start_index is 0-based without regards to the full tree indexes or the node indexes. The +/// start_index is the index of the first leaf node to be updated. +pub fn set_canopy_leaf_nodes( + canopy_bytes: &mut [u8], + max_depth: u32, + start_index: u32, + nodes: &[Node], +) -> Result<()> { + check_canopy_bytes(canopy_bytes)?; + let canopy = cast_slice_mut::(canopy_bytes); + let path_len = get_cached_path_length(canopy, max_depth)?; + if path_len == 0 { + return err!(AccountCompressionError::CanopyNotAllocated); + } + let start_canopy_node = leaf_node_index_to_canopy_index(path_len, start_index)?; + let start_canopy_idx = start_canopy_node - 2; + // set the "leaf" nodes of the canopy first - that's the lowest level of the canopy + for (i, node) in nodes.iter().enumerate() { + canopy[start_canopy_idx + i] = *node; + } + let mut start_canopy_node = start_canopy_node; + let mut end_canopy_node = start_canopy_node + nodes.len() - 1; + let mut empty_node_cache = Box::new([EMPTY; MAX_SUPPORTED_DEPTH]); + let leaf_node_level = max_depth - path_len; + // traverse up the tree and update the parent nodes in the modified subtree + for level in leaf_node_level + 1..max_depth { + start_canopy_node >>= 1; + end_canopy_node >>= 1; + for node in start_canopy_node..end_canopy_node + 1 { + let left_child = get_value_for_node::( + node << 1, + level - 1, + canopy, + &mut empty_node_cache, + ); + let right_child = get_value_for_node::( + (node << 1) + 1, + level - 1, + canopy, + &mut empty_node_cache, + ); + canopy[node - 2].copy_from_slice(hashv(&[&left_child, &right_child]).as_ref()); + } + } + Ok(()) +} + +/// Checks the root of the canopy against the expected root. +pub fn check_canopy_root(canopy_bytes: &[u8], expected_root: &Node, max_depth: u32) -> Result<()> { + check_canopy_bytes(canopy_bytes)?; + let canopy = cast_slice::(canopy_bytes); + if canopy.is_empty() { + return Ok(()); // Canopy is empty + } + let mut empty_node_cache = Box::new([EMPTY; MAX_SUPPORTED_DEPTH]); + // first two nodes are the children of the root, they have index 2 and 3 respectively + let left_root_child = + get_value_for_node::(2, max_depth - 1, canopy, &mut empty_node_cache); + let right_root_child = + get_value_for_node::(3, max_depth - 1, canopy, &mut empty_node_cache); + let actual_root = hashv(&[&left_root_child, &right_root_child]).to_bytes(); + if actual_root != *expected_root { + msg!( + "Canopy root mismatch. Expected: {:?}, Actual: {:?}", + expected_root, + actual_root + ); + err!(AccountCompressionError::CanopyRootMismatch) + } else { + Ok(()) + } +} + +/// Checks the canopy doesn't have any nodes to the right of the provided index in the full tree. +/// This is done by iterating through the canopy nodes to the right of the provided index and +/// finding the top-most node that has the node as its left child. The node should be empty. The +/// iteration contains following the previous checked node on the same level until the last node on +/// the level is reached. +pub fn check_canopy_no_nodes_to_right_of_index( + canopy_bytes: &[u8], + max_depth: u32, + index: u32, +) -> Result<()> { + check_canopy_bytes(canopy_bytes)?; + check_index(index, max_depth)?; + let canopy = cast_slice::(canopy_bytes); + let path_len = get_cached_path_length(canopy, max_depth)?; + + let mut node_idx = ((1 << max_depth) + index) >> (max_depth - path_len); + // no need to check the node_idx as it's the leaf continaing the index underneath it + while node_idx & (node_idx + 1) != 0 { + // check the next node to the right + node_idx += 1; + // find the top-most node that has the node as its left-most child + node_idx >>= node_idx.trailing_zeros(); + + let shifted_index = node_idx as usize - 2; + if canopy[shifted_index] != EMPTY { + msg!("Canopy node at index {} is not empty", shifted_index); + return err!(AccountCompressionError::CanopyRightmostLeafMismatch); + } + } + Ok(()) +} + +#[inline(always)] +fn check_index(index: u32, at_depth: u32) -> Result<()> { + if at_depth > MAX_SUPPORTED_DEPTH as u32 { + return err!(AccountCompressionError::ConcurrentMerkleTreeConstantsError); + } + if at_depth == 0 { + return err!(AccountCompressionError::ConcurrentMerkleTreeConstantsError); + } + if index >= (1 << at_depth) { + return err!(AccountCompressionError::LeafIndexOutOfBounds); + } + Ok(()) +} + +#[inline(always)] +fn get_value_for_node( + node_idx: usize, + level: u32, + canopy: &[Node], + empty_node_cache: &mut [Node; N], +) -> Node { + if canopy[node_idx - 2] != EMPTY { + return canopy[node_idx - 2]; + } + empty_node_cached_mut::(level, empty_node_cache) +} + +#[inline(always)] +fn leaf_node_index_to_canopy_index(path_len: u32, index: u32) -> Result { + check_index(index, path_len)?; + Ok((1 << path_len) + index as usize) +} + +#[cfg(test)] +mod tests { + use {super::*, spl_concurrent_merkle_tree::node::empty_node}; + + fn success_leaf_node_index_to_canopy_index(path_len: u32, index: u32, expected: usize) { + assert_eq!( + leaf_node_index_to_canopy_index(path_len, index).unwrap(), + expected + ); + } + + #[test] + fn test_zero_length_tree() { + assert_eq!( + leaf_node_index_to_canopy_index(0, 0).unwrap_err(), + AccountCompressionError::ConcurrentMerkleTreeConstantsError.into() + ); + } + + #[test] + fn test_1_level_0_index() { + success_leaf_node_index_to_canopy_index(1, 0, 2); + } + + #[test] + fn test_1_level_1_index() { + success_leaf_node_index_to_canopy_index(1, 1, 3); + } + + #[test] + fn test_2_level_0_index() { + success_leaf_node_index_to_canopy_index(2, 0, 4); + } + #[test] + fn test_2_level_3_index() { + success_leaf_node_index_to_canopy_index(2, 3, 7); + } + + #[test] + fn test_10_level_0_index() { + success_leaf_node_index_to_canopy_index(10, 0, 1024); + } + + #[test] + fn test_10_level_1023_index() { + success_leaf_node_index_to_canopy_index(10, 1023, 2047); + } + + #[test] + fn test_simple_single_level_canopy_set_canopy_leaf_nodes_with_empty_nodes() { + let mut canopy_bytes = vec![0_u8; 2 * size_of::()]; + let nodes = vec![EMPTY; 2]; + set_canopy_leaf_nodes(&mut canopy_bytes, 1, 0, &nodes).unwrap(); + let canopy = cast_slice::(&canopy_bytes); + + assert_eq!(canopy[0], EMPTY); + assert_eq!(canopy[1], EMPTY); + } + + #[test] + fn test_simple_single_level_canopy_set_canopy_leaf_nodes_non_empty_nodes() { + let mut canopy_bytes = vec![0_u8; 2 * size_of::()]; + let nodes = vec![[1_u8; 32], [2_u8; 32]]; + set_canopy_leaf_nodes(&mut canopy_bytes, 1, 0, &nodes).unwrap(); + let canopy = cast_slice::(&canopy_bytes); + + assert_eq!(canopy[0], [1_u8; 32]); + assert_eq!(canopy[1], [2_u8; 32]); + } + + #[test] + fn test_2levels_canopy_set_canopy_leaf_nodes_first_2_elements_provided() { + let mut canopy_bytes = vec![0_u8; 6 * size_of::()]; + let nodes = vec![[1_u8; 32], [2_u8; 32]]; + set_canopy_leaf_nodes(&mut canopy_bytes, 2, 0, &nodes).unwrap(); + let canopy = cast_slice::(&canopy_bytes); + + assert_eq!(canopy[0], hashv(&[&[1_u8; 32], &[2_u8; 32]]).to_bytes()); + assert_eq!(canopy[1], EMPTY); // is not updated + assert_eq!(canopy[2], [1_u8; 32]); + assert_eq!(canopy[3], [2_u8; 32]); + assert_eq!(canopy[4], EMPTY); + assert_eq!(canopy[5], EMPTY); + } + + #[test] + fn test_2levels_canopy_set_canopy_leaf_nodes_last_2_elements_provided() { + let mut canopy_bytes = vec![0_u8; 6 * size_of::()]; + let nodes = vec![[1_u8; 32], [2_u8; 32]]; + set_canopy_leaf_nodes(&mut canopy_bytes, 2, 2, &nodes).unwrap(); + let canopy = cast_slice::(&canopy_bytes); + + assert_eq!(canopy[0], EMPTY); // is not updated + assert_eq!(canopy[1], hashv(&[&[1_u8; 32], &[2_u8; 32]]).to_bytes()); + assert_eq!(canopy[2], EMPTY); + assert_eq!(canopy[3], EMPTY); + assert_eq!(canopy[4], [1_u8; 32]); + assert_eq!(canopy[5], [2_u8; 32]); + } + + #[test] + fn test_2levels_canopy_set_canopy_leaf_nodes_middle_2_elements_provided() { + let mut canopy_bytes = vec![0_u8; 6 * size_of::()]; + let nodes = vec![[1_u8; 32], [2_u8; 32]]; + set_canopy_leaf_nodes(&mut canopy_bytes, 2, 1, &nodes).unwrap(); + let canopy = cast_slice::(&canopy_bytes); + + assert_eq!(canopy[2], EMPTY); + assert_eq!(canopy[3], [1_u8; 32]); + assert_eq!(canopy[4], [2_u8; 32]); + assert_eq!(canopy[5], EMPTY); + assert_eq!(canopy[0], hashv(&[&EMPTY, &[1_u8; 32]]).to_bytes()); + assert_eq!(canopy[1], hashv(&[&[2_u8; 32], &EMPTY]).to_bytes()); + } + + #[test] + fn test_3level_canopy_in_10_level_tree_set_canopy_leaf_nodes_first_2_elements_provided() { + let mut canopy_bytes = vec![0_u8; 14 * size_of::()]; + let nodes = vec![[1_u8; 32], [2_u8; 32]]; + set_canopy_leaf_nodes(&mut canopy_bytes, 10, 0, &nodes).unwrap(); + let canopy = cast_slice::(&canopy_bytes); + + let expected_hash12 = hashv(&[&[1_u8; 32], &[2_u8; 32]]).to_bytes(); + assert_eq!( + canopy[0], + hashv(&[&expected_hash12, &empty_node(8)]).to_bytes() + ); + assert_eq!(canopy[1], EMPTY); // is not updated + assert_eq!(canopy[2], expected_hash12); + assert_eq!(canopy[3], EMPTY); // is not updated + assert_eq!(canopy[4], EMPTY); // is not updated + assert_eq!(canopy[5], EMPTY); // is not updated + assert_eq!(canopy[6], [1_u8; 32]); + assert_eq!(canopy[7], [2_u8; 32]); + } + + #[test] + fn test_3level_canopy_in_10_level_tree_set_canopy_leaf_nodes_middle_2_elements_provided() { + let mut canopy_bytes = vec![0_u8; 14 * size_of::()]; + let nodes = vec![[1_u8; 32], [2_u8; 32]]; + set_canopy_leaf_nodes(&mut canopy_bytes, 10, 3, &nodes).unwrap(); + let canopy = cast_slice::(&canopy_bytes); + + let expected_hash_empty_1 = hashv(&[&empty_node(7), &[1_u8; 32]]).to_bytes(); + let expected_hash_2_empty = hashv(&[&[2_u8; 32], &empty_node(7)]).to_bytes(); + + assert_eq!( + canopy[0], + hashv(&[&empty_node(8), &expected_hash_empty_1]).to_bytes() + ); + assert_eq!( + canopy[1], + hashv(&[&expected_hash_2_empty, &empty_node(8)]).to_bytes() + ); + assert_eq!(canopy[2], EMPTY); // is not updated + assert_eq!(canopy[3], expected_hash_empty_1); + assert_eq!(canopy[4], expected_hash_2_empty); + assert_eq!(canopy[5], EMPTY); // is not updated + assert_eq!(canopy[9], [1_u8; 32]); + assert_eq!(canopy[10], [2_u8; 32]); + } + + #[test] + fn test_3level_canopy_empty_set_canopy_leaf_nodes_no_impact() { + let mut canopy_bytes = vec![0_u8; 14 * size_of::()]; + let nodes = vec![]; + set_canopy_leaf_nodes(&mut canopy_bytes, 10, 0, &nodes).unwrap(); + assert_eq!(canopy_bytes, vec![0_u8; 14 * size_of::()]); + } + + #[test] + fn test_success_check_canopy_root() { + let mut canopy_bytes = vec![0_u8; 2 * size_of::()]; + let expected_root = hashv(&[&[1_u8; 32], &[2_u8; 32]]).to_bytes(); + let nodes = vec![[1_u8; 32], [2_u8; 32]]; + set_canopy_leaf_nodes(&mut canopy_bytes, 1, 0, &nodes).unwrap(); + check_canopy_root(&canopy_bytes, &expected_root, 30).unwrap(); + } + + #[test] + fn test_success_check_canopy_root_with_empty_right_branch() { + let mut canopy_bytes = vec![0_u8; 2 * size_of::()]; + let mut empty_node_cache = Box::new([EMPTY; MAX_SUPPORTED_DEPTH]); + let top_level = (MAX_SUPPORTED_DEPTH - 1) as u32; + let right_branch = + empty_node_cached_mut::(top_level, &mut empty_node_cache); + let expected_root = hashv(&[&[1_u8; 32], &right_branch]).to_bytes(); + let nodes = vec![[1_u8; 32], EMPTY]; + set_canopy_leaf_nodes(&mut canopy_bytes, MAX_SUPPORTED_DEPTH as u32, 0, &nodes).unwrap(); + check_canopy_root(&canopy_bytes, &expected_root, 30).unwrap(); + } + + #[test] + fn test_failure_check_canopy_root() { + let mut canopy_bytes = vec![0_u8; 2 * size_of::()]; + let expected_root = hashv(&[&[1_u8; 32], &[2_u8; 32]]).to_bytes(); + let nodes = vec![[1_u8; 32], [2_u8; 32]]; + set_canopy_leaf_nodes(&mut canopy_bytes, 1, 0, &nodes).unwrap(); + let mut expected_root = expected_root; + expected_root[0] = 0; + assert_eq!( + check_canopy_root(&canopy_bytes, &expected_root, 30).unwrap_err(), + AccountCompressionError::CanopyRootMismatch.into() + ); + } + + #[test] + fn test_success_check_canopy_no_nodes_to_right_of_index_empty_tree_first_index() { + let canopy_bytes = vec![0_u8; 6 * size_of::()]; + check_canopy_no_nodes_to_right_of_index(&canopy_bytes, 20, 0).unwrap(); + } + + #[test] + fn test_success_check_canopy_no_nodes_to_right_of_index_empty_tree_last_index() { + let canopy_bytes = vec![0_u8; 6 * size_of::()]; + check_canopy_no_nodes_to_right_of_index(&canopy_bytes, 20, (1 << 20) - 1).unwrap(); + } + + #[test] + fn test_success_check_canopy_no_nodes_to_right_of_index_empty_canopy_only_tree_first_index() { + let canopy_bytes = vec![0_u8; 6 * size_of::()]; + check_canopy_no_nodes_to_right_of_index(&canopy_bytes, 2, 0).unwrap(); + } + + #[test] + fn test_success_check_canopy_no_nodes_to_right_of_index_empty_canopy_only_tree_last_index() { + let canopy_bytes = vec![0_u8; 6 * size_of::()]; + check_canopy_no_nodes_to_right_of_index(&canopy_bytes, 2, (1 << 2) - 1).unwrap(); + } + + #[test] + fn test_failure_check_canopy_no_nodes_to_right_of_index_empty_tree_index_out_of_range() { + let canopy_bytes = vec![0_u8; 6 * size_of::()]; + assert_eq!( + check_canopy_no_nodes_to_right_of_index(&canopy_bytes, 2, 1 << 20).unwrap_err(), + AccountCompressionError::LeafIndexOutOfBounds.into() + ); + } + + #[test] + fn test_failure_check_canopy_no_nodes_to_right_of_index_full_tree_index_out_of_range() { + let canopy_bytes = vec![1_u8; 6 * size_of::()]; + assert_eq!( + check_canopy_no_nodes_to_right_of_index(&canopy_bytes, 2, 1 << 21).unwrap_err(), + AccountCompressionError::LeafIndexOutOfBounds.into() + ); + } + + #[test] + fn test_success_check_canopy_no_nodes_to_right_of_index_full_tree_last_index() { + let canopy_bytes = vec![1_u8; 6 * size_of::()]; + check_canopy_no_nodes_to_right_of_index(&canopy_bytes, 20, (1 << 20) - 1).unwrap(); + } + + #[test] + fn test_success_check_canopy_no_nodes_to_right_of_index_full_tree_first_child_of_last_canopy_node_leaf( + ) { + let canopy_bytes = vec![1_u8; 6 * size_of::()]; + check_canopy_no_nodes_to_right_of_index(&canopy_bytes, 20, 3 << (20 - 2)).unwrap(); + } + + #[test] + fn test_failure_check_canopy_no_nodes_to_right_of_index_full_tree_last_child_of_second_to_last_canopy_node_leaf( + ) { + let canopy_bytes = vec![1_u8; 6 * size_of::()]; + assert_eq!( + check_canopy_no_nodes_to_right_of_index(&canopy_bytes, 20, (3 << (20 - 2)) - 1) + .unwrap_err(), + AccountCompressionError::CanopyRightmostLeafMismatch.into() + ); + } + + #[test] + fn test_success_check_canopy_no_nodes_to_right_of_index_last_child_of_second_to_last_canopy_node_leaf( + ) { + let mut canopy_bytes = vec![1_u8; 6 * size_of::()]; + canopy_bytes[5 * size_of::()..].fill(0); + check_canopy_no_nodes_to_right_of_index(&canopy_bytes, 20, (3 << (20 - 2)) - 1).unwrap(); + } + + #[test] + fn test_succes_check_canopy_no_nodes_to_right_of_index_no_canopy() { + let canopy_bytes = vec![]; + check_canopy_no_nodes_to_right_of_index(&canopy_bytes, 20, 0).unwrap(); + } +} diff --git a/account-compression/programs/account-compression/src/concurrent_tree_wrapper.rs b/account-compression/programs/account-compression/src/concurrent_tree_wrapper.rs new file mode 100644 index 00000000000..e954fea5c57 --- /dev/null +++ b/account-compression/programs/account-compression/src/concurrent_tree_wrapper.rs @@ -0,0 +1,115 @@ +//! This module provides a wrapper around the `ConcurrentMerkleTree` struct from +//! the `spl_concurrent_merkle_tree` crate. It provides a set of functions that +//! can be called from the Anchor program to interact with the tree. +//! The functions are used to initialize the tree, set a leaf, fill empty or +//! append a leaf, and prove a leaf. As the tree is generic over the depth and +//! buffer size, the functions are implemented using macros that infer the depth +//! and buffer size from the header information stored on-chain. Usage of the +//! macros directly is discouraged, as they have huge match statements with +//! every case taking it's own stack frame. Instead, use the exported functions +//! from this module and refenrece or Box the arguments to the functions to +//! avoid the stack frame explosion. + +pub use crate::error::AccountCompressionError; +/// Exported for Anchor / Solita +pub use spl_concurrent_merkle_tree::{ + concurrent_merkle_tree::{ + ConcurrentMerkleTree, FillEmptyOrAppendArgs, InitializeWithRootArgs, ProveLeafArgs, + SetLeafArgs, + }, + error::ConcurrentMerkleTreeError, + node::Node, + node::EMPTY, +}; +use { + crate::{ + events::ChangeLogEvent, macros::*, state::ConcurrentMerkleTreeHeader, zero_copy::ZeroCopy, + }, + anchor_lang::prelude::*, +}; + +#[inline(never)] +pub fn merkle_tree_initialize_empty( + header: &ConcurrentMerkleTreeHeader, + tree_id: Pubkey, + tree_bytes: &mut [u8], +) -> Result> { + merkle_tree_apply_fn_mut!(header, tree_id, tree_bytes, initialize,) +} + +#[inline(never)] +pub fn merkle_tree_initialize_with_root( + header: &ConcurrentMerkleTreeHeader, + tree_id: Pubkey, + tree_bytes: &mut [u8], + args: &InitializeWithRootArgs, +) -> Result> { + merkle_tree_apply_fn_mut!(header, tree_id, tree_bytes, initialize_with_root, args) +} + +#[inline(never)] +pub fn merkle_tree_set_leaf( + header: &ConcurrentMerkleTreeHeader, + tree_id: Pubkey, + tree_bytes: &mut [u8], + args: &SetLeafArgs, +) -> Result> { + merkle_tree_apply_fn_mut!(header, tree_id, tree_bytes, set_leaf, args) +} + +#[inline(never)] +pub fn merkle_tree_fill_empty_or_append( + header: &ConcurrentMerkleTreeHeader, + tree_id: Pubkey, + tree_bytes: &mut [u8], + args: &FillEmptyOrAppendArgs, +) -> Result> { + merkle_tree_apply_fn_mut!(header, tree_id, tree_bytes, fill_empty_or_append, args) +} + +#[inline(never)] +pub fn merkle_tree_prove_leaf( + header: &ConcurrentMerkleTreeHeader, + tree_id: Pubkey, + tree_bytes: &[u8], + args: &ProveLeafArgs, +) -> Result> { + merkle_tree_apply_fn!(header, tree_id, tree_bytes, prove_leaf, args) +} + +#[inline(never)] +pub fn merkle_tree_append_leaf( + header: &ConcurrentMerkleTreeHeader, + tree_id: Pubkey, + tree_bytes: &mut [u8], + args: &[u8; 32], +) -> Result> { + merkle_tree_apply_fn_mut!(header, tree_id, tree_bytes, append, *args) +} + +/// Checks whether the tree in not initialized yet without doing the deserialization. A rought +/// equivalent to deserializing the tree and calling is_initialized() on it without the heavy +/// lifting with macros. An empty account is a zero'd account. The tree is considered empty if the +/// tree_bytes are all 0. A regular non-batch initialized tree is initialized early on when the +/// init_empty_merkle_tree is called. A batch initialized tree stays uninitialized until the +/// init_prepared_tree_with_root is called. +pub fn tree_bytes_uninitialized(tree_bytes: &[u8]) -> bool { + tree_bytes.iter().all(|&x| x == 0) +} + +#[inline(never)] +pub fn assert_tree_is_empty( + header: &ConcurrentMerkleTreeHeader, + tree_id: Pubkey, + tree_bytes: &mut [u8], +) -> Result<()> { + // If the tree is batch initialized and not finalized yet, we can treat it as empty. + // Before the tree is finalized, the tree_bytes will be all 0 as only the header will be + // initialized at that point, so we may skip the deserialization. + if header.get_is_batch_initialized() && tree_bytes_uninitialized(tree_bytes) { + return Ok(()); + } + // check the tree is empty + merkle_tree_apply_fn_mut!(header, tree_id, tree_bytes, prove_tree_is_empty,)?; + Ok(()) +} diff --git a/account-compression/programs/account-compression/src/error.rs b/account-compression/programs/account-compression/src/error.rs new file mode 100644 index 00000000000..ef682300ebc --- /dev/null +++ b/account-compression/programs/account-compression/src/error.rs @@ -0,0 +1,88 @@ +use anchor_lang::{ + prelude::*, + solana_program::{msg, program_error::ProgramError}, +}; +use bytemuck::PodCastError; +use spl_concurrent_merkle_tree::error::ConcurrentMerkleTreeError; +use std::any::type_name; +use std::mem::size_of; + +/// Errors related to misconfiguration or misuse of the Merkle tree +#[error_code] +pub enum AccountCompressionError { + /// This error is currently not used. + #[msg("Incorrect leaf length. Expected vec of 32 bytes")] + IncorrectLeafLength, + + /// A modification to the tree was invalid and a changelog was not emitted. + /// The proof may be invalid or out-of-date, or the provided leaf hash was invalid. + #[msg("Concurrent merkle tree error")] + ConcurrentMerkleTreeError, + + /// An issue was detected with loading the provided account data for this ConcurrentMerkleTree. + #[msg("Issue zero copying concurrent merkle tree data")] + ZeroCopyError, + + /// See [ConcurrentMerkleTreeHeader](/spl_account_compression/state/struct.ConcurrentMerkleTreeHeader.html) for valid configuration options. + #[msg("An unsupported max depth or max buffer size constant was provided")] + ConcurrentMerkleTreeConstantsError, + + /// When using Canopy, the stored byte length should a multiple of the node's byte length (32 bytes) + #[msg("Expected a different byte length for the merkle tree canopy")] + CanopyLengthMismatch, + + /// Incorrect authority account provided + #[msg("Provided authority does not match expected tree authority")] + IncorrectAuthority, + + /// Incorrect account owner + #[msg("Account is owned by a different program, expected it to be owned by this program")] + IncorrectAccountOwner, + + /// Incorrect account type + #[msg("Account provided has incorrect account type")] + IncorrectAccountType, + + /// Tree information cannot be processed because the provided leaf_index + /// is out of bounds of tree's maximum leaf capacity + #[msg("Leaf index of concurrent merkle tree is out of bounds")] + LeafIndexOutOfBounds, + + /// When initializing a canopy of the tree, the underlying tree was allocated without space for the canopy + #[msg("Tree was initialized without allocating space for the canopy")] + CanopyNotAllocated, + + /// The tree was already initialized + #[msg("Tree was already initialized")] + TreeAlreadyInitialized, + + /// The tree header was not initialized for batch processing + #[msg("Tree header was not initialized for batch processing")] + BatchNotInitialized, + + /// The canopy root doesn't match the root of the tree + #[msg("Canopy root does not match the root of the tree")] + CanopyRootMismatch, + + /// The canopy contains nodes to the right of the rightmost leaf of the tree + #[msg("Canopy contains nodes to the right of the rightmost leaf of the tree")] + CanopyRightmostLeafMismatch, +} + +impl From<&ConcurrentMerkleTreeError> for AccountCompressionError { + fn from(_error: &ConcurrentMerkleTreeError) -> Self { + AccountCompressionError::ConcurrentMerkleTreeError + } +} + +pub fn error_msg(data_len: usize) -> impl Fn(PodCastError) -> ProgramError { + move |_: PodCastError| -> ProgramError { + msg!( + "Failed to load {}. Size is {}, expected {}", + type_name::(), + data_len, + size_of::(), + ); + ProgramError::InvalidAccountData + } +} diff --git a/account-compression/programs/account-compression/src/events/application_data.rs b/account-compression/programs/account-compression/src/events/application_data.rs new file mode 100644 index 00000000000..71c0d6f05e2 --- /dev/null +++ b/account-compression/programs/account-compression/src/events/application_data.rs @@ -0,0 +1,12 @@ +use anchor_lang::prelude::*; + +#[derive(AnchorDeserialize, AnchorSerialize)] +#[repr(C)] +pub enum ApplicationDataEvent { + V1(ApplicationDataEventV1), +} + +#[derive(AnchorDeserialize, AnchorSerialize)] +pub struct ApplicationDataEventV1 { + pub application_data: Vec, +} diff --git a/account-compression/programs/account-compression/src/events/changelog_event.rs b/account-compression/programs/account-compression/src/events/changelog_event.rs new file mode 100644 index 00000000000..d904fb6034a --- /dev/null +++ b/account-compression/programs/account-compression/src/events/changelog_event.rs @@ -0,0 +1,64 @@ +use crate::state::PathNode; + +use anchor_lang::prelude::*; +use spl_concurrent_merkle_tree::changelog::ChangeLog; + +#[derive(AnchorDeserialize, AnchorSerialize)] +#[repr(C)] +pub enum ChangeLogEvent { + V1(ChangeLogEventV1), +} + +#[derive(AnchorDeserialize, AnchorSerialize)] +pub struct ChangeLogEventV1 { + /// Public key of the ConcurrentMerkleTree + pub id: Pubkey, + + /// Nodes of off-chain merkle tree needed by indexer + pub path: Vec, + + /// Index corresponding to the number of successful operations on this tree. + /// Used by the off-chain indexer to figure out when there are gaps to be backfilled. + pub seq: u64, + + /// Bitmap of node parity (used when hashing) + pub index: u32, +} + +impl ChangeLogEvent { + pub fn new(id: Pubkey, path: Vec, seq: u64, index: u32) -> Self { + Self::V1(ChangeLogEventV1 { + id, + path, + seq, + index, + }) + } +} + +impl From<(Box>, Pubkey, u64)> + for Box +{ + fn from(log_info: (Box>, Pubkey, u64)) -> Self { + let (changelog, tree_id, seq) = log_info; + let path_len = changelog.path.len() as u32; + let mut path: Vec = changelog + .path + .iter() + .enumerate() + .map(|(lvl, n)| { + PathNode::new( + *n, + (1 << (path_len - lvl as u32)) + (changelog.index >> lvl), + ) + }) + .collect(); + path.push(PathNode::new(changelog.root, 1)); + Box::new(ChangeLogEvent::V1(ChangeLogEventV1 { + id: tree_id, + path, + seq, + index: changelog.index, + })) + } +} diff --git a/account-compression/programs/account-compression/src/events/mod.rs b/account-compression/programs/account-compression/src/events/mod.rs new file mode 100644 index 00000000000..2efcbbd1da5 --- /dev/null +++ b/account-compression/programs/account-compression/src/events/mod.rs @@ -0,0 +1,17 @@ +//! Anchor events are used to emit information necessary to +//! index changes made to a SPL ConcurrentMerkleTree + +use anchor_lang::prelude::*; + +mod application_data; +mod changelog_event; + +pub use application_data::{ApplicationDataEvent, ApplicationDataEventV1}; +pub use changelog_event::{ChangeLogEvent, ChangeLogEventV1}; + +#[derive(AnchorDeserialize, AnchorSerialize)] +#[repr(C)] +pub enum AccountCompressionEvent { + ChangeLog(ChangeLogEvent), + ApplicationData(ApplicationDataEvent), +} diff --git a/account-compression/programs/account-compression/src/lib.rs b/account-compression/programs/account-compression/src/lib.rs new file mode 100644 index 00000000000..93d8411b3c4 --- /dev/null +++ b/account-compression/programs/account-compression/src/lib.rs @@ -0,0 +1,587 @@ +//! SPL Account Compression is an on-chain program that exposes an interface to manipulating SPL ConcurrentMerkleTrees +//! +//! A buffer of proof-like changelogs is stored on-chain that allow multiple proof-based writes to succeed within the same slot. +//! This is accomplished by fast-forwarding out-of-date (or possibly invalid) proofs based on information stored in the changelogs. +//! See a copy of the whitepaper [here](https://drive.google.com/file/d/1BOpa5OFmara50fTvL0VIVYjtg-qzHCVc/view) +//! +//! To circumvent proof size restrictions stemming from Solana transaction size restrictions, +//! SPL Account Compression also provides the ability to cache the upper most leaves of the +//! concurrent merkle tree. This is called the "canopy", and is stored at the end of the +//! ConcurrentMerkleTreeAccount. More information can be found in the initialization instruction +//! documentation. +//! +//! While SPL ConcurrentMerkleTrees can generically store arbitrary information, +//! one exemplified use-case is the [Bubblegum](https://github.com/metaplex-foundation/metaplex-program-library/tree/master/bubblegum) contract, +//! which uses SPL-Compression to store encoded information about NFTs. +//! The use of SPL-Compression within Bubblegum allows for: +//! - up to 1 billion NFTs to be stored in a single account on-chain (>10,000x decrease in on-chain cost) +//! - up to 2048 concurrent updates per slot +//! +//! Operationally, SPL ConcurrentMerkleTrees **must** be supplemented by off-chain indexers to cache information +//! about leafs and to power an API that can supply up-to-date proofs to allow updates to the tree. +//! All modifications to SPL ConcurrentMerkleTrees are settled on the Solana ledger via instructions against the SPL Compression contract. +//! A production-ready indexer (Plerkle) can be found in the [Metaplex program library](https://github.com/metaplex-foundation/digital-asset-validator-plugin) + +use anchor_lang::{ + prelude::*, + solana_program::sysvar::{clock::Clock, rent::Rent}, +}; +use borsh::{BorshDeserialize, BorshSerialize}; + +pub mod canopy; +pub mod concurrent_tree_wrapper; +pub mod error; +pub mod events; +#[macro_use] +pub mod macros; +mod noop; +pub mod state; +pub mod zero_copy; + +pub use crate::noop::{wrap_application_data_v1, Noop}; + +use crate::canopy::{ + check_canopy_bytes, check_canopy_no_nodes_to_right_of_index, check_canopy_root, + fill_in_proof_from_canopy, set_canopy_leaf_nodes, update_canopy, +}; +use crate::concurrent_tree_wrapper::*; +pub use crate::error::AccountCompressionError; +pub use crate::events::{AccountCompressionEvent, ChangeLogEvent}; +use crate::noop::wrap_event; +use crate::state::{ + merkle_tree_get_size, ConcurrentMerkleTreeHeader, CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1, +}; + +/// Exported for Anchor / Solita +pub use spl_concurrent_merkle_tree::{ + concurrent_merkle_tree::{ConcurrentMerkleTree, FillEmptyOrAppendArgs}, + error::ConcurrentMerkleTreeError, + node::Node, + node::EMPTY, +}; + +declare_id!("cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK"); + +/// Context for initializing a new SPL ConcurrentMerkleTree +#[derive(Accounts)] +pub struct Initialize<'info> { + #[account(zero)] + /// CHECK: This account will be zeroed out, and the size will be validated + pub merkle_tree: UncheckedAccount<'info>, + + /// Authority that controls write-access to the tree + /// Typically a program, e.g., the Bubblegum contract validates that leaves are valid NFTs. + pub authority: Signer<'info>, + + /// Program used to emit changelogs as cpi instruction data. + pub noop: Program<'info, Noop>, +} + +/// Context for modifying a tree: inserting, appending, or replacing a leaf in +/// the existing tree and setting the canopy or finalizing a prepared tree. +/// +/// Modification instructions also require the proof to the leaf to be provided +/// as 32-byte nodes via "remaining accounts". +#[derive(Accounts)] +pub struct Modify<'info> { + #[account(mut)] + /// CHECK: This account is validated in the instruction + pub merkle_tree: UncheckedAccount<'info>, + + /// Authority that controls write-access to the tree + /// Typically a program, e.g., the Bubblegum contract validates that leaves are valid NFTs. + pub authority: Signer<'info>, + + /// Program used to emit changelogs as cpi instruction data. + pub noop: Program<'info, Noop>, +} + +/// Context for validating a provided proof against the SPL ConcurrentMerkleTree. +/// Throws an error if provided proof is invalid. +#[derive(Accounts)] +pub struct VerifyLeaf<'info> { + /// CHECK: This account is validated in the instruction + pub merkle_tree: UncheckedAccount<'info>, +} + +/// Context for transferring `authority` +#[derive(Accounts)] +pub struct TransferAuthority<'info> { + #[account(mut)] + /// CHECK: This account is validated in the instruction + pub merkle_tree: UncheckedAccount<'info>, + + /// Authority that controls write-access to the tree + /// Typically a program, e.g., the Bubblegum contract validates that leaves are valid NFTs. + pub authority: Signer<'info>, +} + +/// Context for closing a tree +#[derive(Accounts)] +pub struct CloseTree<'info> { + #[account(mut)] + /// CHECK: This account is validated in the instruction + pub merkle_tree: AccountInfo<'info>, + + /// Authority that controls write-access to the tree + pub authority: Signer<'info>, + + /// CHECK: Recipient of funds after + #[account(mut)] + pub recipient: AccountInfo<'info>, +} + +#[program] +pub mod spl_account_compression { + use super::*; + + /// Creates a new merkle tree with maximum leaf capacity of `power(2, max_depth)` + /// and a minimum concurrency limit of `max_buffer_size`. + /// + /// Concurrency limit represents the # of replace instructions that can be successfully + /// executed with proofs dated for the same root. For example, a maximum buffer size of 1024 + /// means that a minimum of 1024 replaces can be executed before a new proof must be + /// generated for the next replace instruction. + /// + /// Concurrency limit should be determined by empirically testing the demand for + /// state built on top of SPL Compression. + /// + /// For instructions on enabling the canopy, see [canopy]. + pub fn init_empty_merkle_tree( + ctx: Context, + max_depth: u32, + max_buffer_size: u32, + ) -> Result<()> { + require_eq!( + *ctx.accounts.merkle_tree.owner, + crate::id(), + AccountCompressionError::IncorrectAccountOwner + ); + let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?; + + let (mut header_bytes, rest) = + merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1); + + let mut header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?; + header.initialize( + max_depth, + max_buffer_size, + &ctx.accounts.authority.key(), + Clock::get()?.slot, + ); + header.serialize(&mut header_bytes)?; + + let merkle_tree_size = merkle_tree_get_size(&header)?; + let (tree_bytes, canopy_bytes) = rest.split_at_mut(merkle_tree_size); + let id = ctx.accounts.merkle_tree.key(); + + let change_log_event = merkle_tree_initialize_empty(&header, id, tree_bytes)?; + + wrap_event( + &AccountCompressionEvent::ChangeLog(*change_log_event), + &ctx.accounts.noop, + )?; + update_canopy(canopy_bytes, header.get_max_depth(), None) + } + + /// (Devnet only) In order to initialize a tree with a root, we need to create the tree on-chain first with + /// the proper authority. The tree might contain a canopy, which is a cache of the uppermost + /// nodes. The canopy is used to decrease the size of the proof required to update the tree. + /// If the tree is expected to have a canopy, it needs to be prefilled with the necessary nodes. + /// There are 2 ways to initialize a merkle tree: + /// 1. Initialize an empty tree + /// 2. Initialize a tree with a root and leaf + /// For the former case, the canopy will be empty which is expected for an empty tree. The + /// expected flow is `init_empty_merkle_tree`. For the latter case, the canopy should be + /// filled with the necessary nodes to render the tree usable. Thus we need to prefill the + /// canopy with the necessary nodes. The expected flow for a tree without canopy is + /// `prepare_batch_merkle_tree` -> `init_prepared_tree_with_root`. The expected flow for a tree + /// with canopy is `prepare_batch_merkle_tree` -> `append_canopy_nodes` (multiple times + /// until all of the canopy is filled) -> `init_prepared_tree_with_root`. This instruction + /// initializes the tree header while leaving the tree itself uninitialized. This allows + /// distinguishing between an empty tree and a tree prepare to be initialized with a root. + pub fn prepare_batch_merkle_tree( + ctx: Context, + max_depth: u32, + max_buffer_size: u32, + ) -> Result<()> { + require_eq!( + *ctx.accounts.merkle_tree.owner, + crate::id(), + AccountCompressionError::IncorrectAccountOwner + ); + let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?; + + let (mut header_bytes, rest) = + merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1); + + let mut header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?; + header.initialize_batched( + max_depth, + max_buffer_size, + &ctx.accounts.authority.key(), + Clock::get()?.slot, + ); + header.serialize(&mut header_bytes)?; + let merkle_tree_size = merkle_tree_get_size(&header)?; + let (_tree_bytes, canopy_bytes) = rest.split_at_mut(merkle_tree_size); + check_canopy_bytes(canopy_bytes) + } + + /// (Devnet only) This instruction pre-initializes the canopy with the specified leaf nodes of the canopy. + /// This is intended to be used after `prepare_batch_merkle_tree` and in conjunction with the + /// `init_prepared_tree_with_root` instruction that'll finalize the tree initialization. + /// The canopy is used to cache the uppermost nodes of the tree, which allows for a smaller + /// proof size when updating the tree. The canopy should be filled with the necessary nodes + /// before calling `init_prepared_tree_with_root`. You may call this instruction multiple + /// times to fill the canopy with the necessary nodes. The canopy may be filled with the + /// nodes in any order. The already filled nodes may be replaced with new nodes before calling + /// `init_prepared_tree_with_root` if the step was done in error. + /// The canopy should be filled with all the nodes that are to the left of the rightmost + /// leaf of the tree before calling `init_prepared_tree_with_root`. The canopy should not + /// contain any nodes to the right of the rightmost leaf of the tree. + /// This instruction calculates and filles in all the canopy nodes "above" the provided ones. + /// The validation of the canopy is done in the `init_prepared_tree_with_root` instruction. + pub fn append_canopy_nodes( + ctx: Context, + start_index: u32, + canopy_nodes: Vec<[u8; 32]>, + ) -> Result<()> { + require_eq!( + *ctx.accounts.merkle_tree.owner, + crate::id(), + AccountCompressionError::IncorrectAccountOwner + ); + let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?; + + let (header_bytes, rest) = + merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1); + + let header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?; + header.assert_valid_authority(&ctx.accounts.authority.key())?; + header.assert_is_batch_initialized()?; + // assert the tree is not initialized yet, we don't want to overwrite the canopy of an + // initialized tree + let merkle_tree_size = merkle_tree_get_size(&header)?; + let (tree_bytes, canopy_bytes) = rest.split_at_mut(merkle_tree_size); + // ensure the tree is not initialized, the hacky way + require!( + tree_bytes_uninitialized(tree_bytes), + AccountCompressionError::TreeAlreadyInitialized + ); + set_canopy_leaf_nodes( + canopy_bytes, + header.get_max_depth(), + start_index, + &canopy_nodes, + ) + } + + /// (Devnet only) Initializes a prepared tree with a root and a rightmost leaf. The rightmost leaf is used to + /// verify the canopy if the tree has it. Before calling this instruction, the tree should be + /// prepared with `prepare_batch_merkle_tree` and the canopy should be filled with the necessary + /// nodes with `append_canopy_nodes` (if the canopy is used). This method should be used for + /// batch creation of trees. The indexing of such batches should be done off-chain. The + /// programs calling this instruction should take care of ensuring the indexing is possible. + /// For example, staking may be required to ensure the tree creator has some responsibility + /// for what is being indexed. If indexing is not possible, there should be a mechanism to + /// penalize the tree creator. + pub fn init_prepared_tree_with_root( + ctx: Context, + root: [u8; 32], + rightmost_leaf: [u8; 32], + rightmost_index: u32, + ) -> Result<()> { + require_eq!( + *ctx.accounts.merkle_tree.owner, + crate::id(), + AccountCompressionError::IncorrectAccountOwner + ); + let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?; + + let (header_bytes, rest) = + merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1); + // the header should already be initialized with prepare_batch_merkle_tree + let header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?; + header.assert_valid_authority(&ctx.accounts.authority.key())?; + header.assert_is_batch_initialized()?; + let merkle_tree_size = merkle_tree_get_size(&header)?; + let (tree_bytes, canopy_bytes) = rest.split_at_mut(merkle_tree_size); + // check the canopy root matches the tree root + check_canopy_root(canopy_bytes, &root, header.get_max_depth())?; + // verify the canopy does not conain any nodes to the right of the rightmost leaf + check_canopy_no_nodes_to_right_of_index( + canopy_bytes, + header.get_max_depth(), + rightmost_index, + )?; + + // Get rightmost proof from accounts + let mut proof = vec![]; + for node in ctx.remaining_accounts.iter() { + proof.push(node.key().to_bytes()); + } + fill_in_proof_from_canopy( + canopy_bytes, + header.get_max_depth(), + rightmost_index, + &mut proof, + )?; + assert_eq!(proof.len(), header.get_max_depth() as usize); + + let id = ctx.accounts.merkle_tree.key(); + // A call is made to ConcurrentMerkleTree::initialize_with_root + let args = &InitializeWithRootArgs { + root, + rightmost_leaf, + proof_vec: proof, + index: rightmost_index, + }; + let change_log = merkle_tree_initialize_with_root(&header, id, tree_bytes, args)?; + update_canopy(canopy_bytes, header.get_max_depth(), Some(&change_log))?; + wrap_event( + &AccountCompressionEvent::ChangeLog(*change_log), + &ctx.accounts.noop, + ) + } + + /// Executes an instruction that overwrites a leaf node. + /// Composing programs should check that the data hashed into previous_leaf + /// matches the authority information necessary to execute this instruction. + pub fn replace_leaf( + ctx: Context, + root: [u8; 32], + previous_leaf: [u8; 32], + new_leaf: [u8; 32], + index: u32, + ) -> Result<()> { + require_eq!( + *ctx.accounts.merkle_tree.owner, + crate::id(), + AccountCompressionError::IncorrectAccountOwner + ); + let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?; + let (header_bytes, rest) = + merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1); + + let header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?; + header.assert_valid_authority(&ctx.accounts.authority.key())?; + header.assert_valid_leaf_index(index)?; + + let merkle_tree_size = merkle_tree_get_size(&header)?; + let (tree_bytes, canopy_bytes) = rest.split_at_mut(merkle_tree_size); + + let mut proof = vec![]; + for node in ctx.remaining_accounts.iter() { + proof.push(node.key().to_bytes()); + } + fill_in_proof_from_canopy(canopy_bytes, header.get_max_depth(), index, &mut proof)?; + let id = ctx.accounts.merkle_tree.key(); + // A call is made to ConcurrentMerkleTree::set_leaf(root, previous_leaf, new_leaf, proof, index) + let args = &SetLeafArgs { + current_root: root, + previous_leaf, + new_leaf, + proof_vec: proof, + index, + }; + let change_log_event = merkle_tree_set_leaf(&header, id, tree_bytes, args)?; + + update_canopy( + canopy_bytes, + header.get_max_depth(), + Some(&change_log_event), + )?; + wrap_event( + &AccountCompressionEvent::ChangeLog(*change_log_event), + &ctx.accounts.noop, + ) + } + + /// Transfers `authority`. + /// Requires `authority` to sign + pub fn transfer_authority( + ctx: Context, + new_authority: Pubkey, + ) -> Result<()> { + require_eq!( + *ctx.accounts.merkle_tree.owner, + crate::id(), + AccountCompressionError::IncorrectAccountOwner + ); + let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?; + let (mut header_bytes, _) = + merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1); + + let mut header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?; + header.assert_valid_authority(&ctx.accounts.authority.key())?; + + header.set_new_authority(&new_authority); + header.serialize(&mut header_bytes)?; + + Ok(()) + } + + /// Verifies a provided proof and leaf. + /// If invalid, throws an error. + pub fn verify_leaf( + ctx: Context, + root: [u8; 32], + leaf: [u8; 32], + index: u32, + ) -> Result<()> { + require_eq!( + *ctx.accounts.merkle_tree.owner, + crate::id(), + AccountCompressionError::IncorrectAccountOwner + ); + let merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_data()?; + let (header_bytes, rest) = + merkle_tree_bytes.split_at(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1); + + let header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?; + header.assert_valid()?; + header.assert_valid_leaf_index(index)?; + + let merkle_tree_size = merkle_tree_get_size(&header)?; + let (tree_bytes, canopy_bytes) = rest.split_at(merkle_tree_size); + + let mut proof = vec![]; + for node in ctx.remaining_accounts.iter() { + proof.push(node.key().to_bytes()); + } + fill_in_proof_from_canopy(canopy_bytes, header.get_max_depth(), index, &mut proof)?; + let id = ctx.accounts.merkle_tree.key(); + + let args = &ProveLeafArgs { + current_root: root, + leaf, + proof_vec: proof, + index, + }; + merkle_tree_prove_leaf(&header, id, tree_bytes, args)?; + + Ok(()) + } + + /// This instruction allows the tree's `authority` to append a new leaf to the tree + /// without having to supply a proof. + /// + /// Learn more about SPL + /// ConcurrentMerkleTree + /// [here](https://github.com/solana-labs/solana-program-library/tree/master/libraries/concurrent-merkle-tree) + pub fn append(ctx: Context, leaf: [u8; 32]) -> Result<()> { + require_eq!( + *ctx.accounts.merkle_tree.owner, + crate::id(), + AccountCompressionError::IncorrectAccountOwner + ); + let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?; + let (header_bytes, rest) = + merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1); + + let header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?; + header.assert_valid_authority(&ctx.accounts.authority.key())?; + + let id = ctx.accounts.merkle_tree.key(); + let merkle_tree_size = merkle_tree_get_size(&header)?; + let (tree_bytes, canopy_bytes) = rest.split_at_mut(merkle_tree_size); + let change_log_event = merkle_tree_append_leaf(&header, id, tree_bytes, &leaf)?; + update_canopy( + canopy_bytes, + header.get_max_depth(), + Some(&change_log_event), + )?; + wrap_event( + &AccountCompressionEvent::ChangeLog(*change_log_event), + &ctx.accounts.noop, + ) + } + + /// This instruction takes a proof, and will attempt to write the given leaf + /// to the specified index in the tree. If the insert operation fails, the leaf will be `append`-ed + /// to the tree. + /// It is up to the indexer to parse the final location of the leaf from the emitted changelog. + pub fn insert_or_append( + ctx: Context, + root: [u8; 32], + leaf: [u8; 32], + index: u32, + ) -> Result<()> { + require_eq!( + *ctx.accounts.merkle_tree.owner, + crate::id(), + AccountCompressionError::IncorrectAccountOwner + ); + let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?; + let (header_bytes, rest) = + merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1); + + let header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?; + header.assert_valid_authority(&ctx.accounts.authority.key())?; + header.assert_valid_leaf_index(index)?; + + let merkle_tree_size = merkle_tree_get_size(&header)?; + let (tree_bytes, canopy_bytes) = rest.split_at_mut(merkle_tree_size); + + let mut proof = vec![]; + for node in ctx.remaining_accounts.iter() { + proof.push(node.key().to_bytes()); + } + fill_in_proof_from_canopy(canopy_bytes, header.get_max_depth(), index, &mut proof)?; + // A call is made to ConcurrentMerkleTree::fill_empty_or_append + let id = ctx.accounts.merkle_tree.key(); + let args = &FillEmptyOrAppendArgs { + current_root: root, + leaf, + proof_vec: proof, + index, + }; + let change_log_event = merkle_tree_fill_empty_or_append(&header, id, tree_bytes, args)?; + + update_canopy( + canopy_bytes, + header.get_max_depth(), + Some(&change_log_event), + )?; + wrap_event( + &AccountCompressionEvent::ChangeLog(*change_log_event), + &ctx.accounts.noop, + ) + } + + pub fn close_empty_tree(ctx: Context) -> Result<()> { + require_eq!( + *ctx.accounts.merkle_tree.owner, + crate::id(), + AccountCompressionError::IncorrectAccountOwner + ); + let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?; + let (header_bytes, rest) = + merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1); + + let header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?; + header.assert_valid_authority(&ctx.accounts.authority.key())?; + + let merkle_tree_size = merkle_tree_get_size(&header)?; + let (tree_bytes, canopy_bytes) = rest.split_at_mut(merkle_tree_size); + + let id = ctx.accounts.merkle_tree.key(); + assert_tree_is_empty(&header, id, tree_bytes)?; + + // Close merkle tree account + // 1. Move lamports + let dest_starting_lamports = ctx.accounts.recipient.lamports(); + **ctx.accounts.recipient.lamports.borrow_mut() = dest_starting_lamports + .checked_add(ctx.accounts.merkle_tree.lamports()) + .unwrap(); + **ctx.accounts.merkle_tree.lamports.borrow_mut() = 0; + + // 2. Set all CMT account bytes to 0 + header_bytes.fill(0); + tree_bytes.fill(0); + canopy_bytes.fill(0); + + Ok(()) + } +} diff --git a/account-compression/programs/account-compression/src/macros.rs b/account-compression/programs/account-compression/src/macros.rs new file mode 100644 index 00000000000..fd2e339fb56 --- /dev/null +++ b/account-compression/programs/account-compression/src/macros.rs @@ -0,0 +1,125 @@ +#[allow(dead_code)] +enum TreeLoad { + Immutable, + Mutable, +} + +/// This macro applies functions on a ConcurrentMerkleT:ee and emits leaf +/// information needed to sync the merkle tree state with off-chain indexers. +#[macro_export] +macro_rules! _merkle_tree_depth_size_apply_fn { + ($max_depth:literal, $max_size:literal, $id:ident, $bytes:ident, $func:ident, TreeLoad::Mutable, $($arg:tt)*) + => { + match ConcurrentMerkleTree::<$max_depth, $max_size>::load_mut_bytes($bytes) { + Ok(merkle_tree) => { + match merkle_tree.$func($($arg)*) { + Ok(_) => { + Ok(Box::::from((merkle_tree.get_change_log(), $id, merkle_tree.sequence_number))) + } + Err(err) => { + msg!("Error using concurrent merkle tree: {}", err); + err!(AccountCompressionError::ConcurrentMerkleTreeError) + } + } + } + Err(err) => { + msg!("Error zero copying concurrent merkle tree: {}", err); + err!(AccountCompressionError::ZeroCopyError) + } + } + }; + ($max_depth:literal, $max_size:literal, $id:ident, $bytes:ident, $func:ident, TreeLoad::Immutable, $($arg:tt)*) => { + match ConcurrentMerkleTree::<$max_depth, $max_size>::load_bytes($bytes) { + Ok(merkle_tree) => { + match merkle_tree.$func($($arg)*) { + Ok(_) => { + Ok(Box::::from((merkle_tree.get_change_log(), $id, merkle_tree.sequence_number))) + } + Err(err) => { + msg!("Error using concurrent merkle tree: {}", err); + err!(AccountCompressionError::ConcurrentMerkleTreeError) + } + } + } + Err(err) => { + msg!("Error zero copying concurrent merkle tree: {}", err); + err!(AccountCompressionError::ZeroCopyError) + } + } + }; +} + +/// This applies a given function on a ConcurrentMerkleTree by +/// allowing the compiler to infer the size of the tree based +/// upon the header information stored on-chain +#[macro_export] +macro_rules! _merkle_tree_apply_fn { + ($header:ident, $($arg:tt)*) => { + // Note: max_buffer_size MUST be a power of 2 + match ($header.get_max_depth(), $header.get_max_buffer_size()) { + (3, 8) => _merkle_tree_depth_size_apply_fn!(3, 8, $($arg)*), + (5, 8) => _merkle_tree_depth_size_apply_fn!(5, 8, $($arg)*), + (6, 16) => _merkle_tree_depth_size_apply_fn!(6, 16, $($arg)*), + (7, 16) => _merkle_tree_depth_size_apply_fn!(7, 16, $($arg)*), + (8, 16) => _merkle_tree_depth_size_apply_fn!(8, 16, $($arg)*), + (9, 16) => _merkle_tree_depth_size_apply_fn!(9, 16, $($arg)*), + (10, 32) => _merkle_tree_depth_size_apply_fn!(10, 32, $($arg)*), + (11, 32) => _merkle_tree_depth_size_apply_fn!(11, 32, $($arg)*), + (12, 32) => _merkle_tree_depth_size_apply_fn!(12, 32, $($arg)*), + (13, 32) => _merkle_tree_depth_size_apply_fn!(13, 32, $($arg)*), + (14, 64) => _merkle_tree_depth_size_apply_fn!(14, 64, $($arg)*), + (14, 256) => _merkle_tree_depth_size_apply_fn!(14, 256, $($arg)*), + (14, 1024) => _merkle_tree_depth_size_apply_fn!(14, 1024, $($arg)*), + (14, 2048) => _merkle_tree_depth_size_apply_fn!(14, 2048, $($arg)*), + (15, 64) => _merkle_tree_depth_size_apply_fn!(15, 64, $($arg)*), + (16, 64) => _merkle_tree_depth_size_apply_fn!(16, 64, $($arg)*), + (17, 64) => _merkle_tree_depth_size_apply_fn!(17, 64, $($arg)*), + (18, 64) => _merkle_tree_depth_size_apply_fn!(18, 64, $($arg)*), + (19, 64) => _merkle_tree_depth_size_apply_fn!(19, 64, $($arg)*), + (20, 64) => _merkle_tree_depth_size_apply_fn!(20, 64, $($arg)*), + (20, 256) => _merkle_tree_depth_size_apply_fn!(20, 256, $($arg)*), + (20, 1024) => _merkle_tree_depth_size_apply_fn!(20, 1024, $($arg)*), + (20, 2048) => _merkle_tree_depth_size_apply_fn!(20, 2048, $($arg)*), + (24, 64) => _merkle_tree_depth_size_apply_fn!(24, 64, $($arg)*), + (24, 256) => _merkle_tree_depth_size_apply_fn!(24, 256, $($arg)*), + (24, 512) => _merkle_tree_depth_size_apply_fn!(24, 512, $($arg)*), + (24, 1024) => _merkle_tree_depth_size_apply_fn!(24, 1024, $($arg)*), + (24, 2048) => _merkle_tree_depth_size_apply_fn!(24, 2048, $($arg)*), + (26, 512) => _merkle_tree_depth_size_apply_fn!(26, 512, $($arg)*), + (26, 1024) => _merkle_tree_depth_size_apply_fn!(26, 1024, $($arg)*), + (26, 2048) => _merkle_tree_depth_size_apply_fn!(26, 2048, $($arg)*), + (30, 512) => _merkle_tree_depth_size_apply_fn!(30, 512, $($arg)*), + (30, 1024) => _merkle_tree_depth_size_apply_fn!(30, 1024, $($arg)*), + (30, 2048) => _merkle_tree_depth_size_apply_fn!(30, 2048, $($arg)*), + _ => { + msg!("Failed to apply {} on concurrent merkle tree with max depth {} and max buffer size {}", + stringify!($func), + $header.get_max_depth(), + $header.get_max_buffer_size() + ); + err!(AccountCompressionError::ConcurrentMerkleTreeConstantsError) + } + } + }; +} + +/// This applies a given function on a mutable ConcurrentMerkleTree +#[macro_export] +macro_rules! merkle_tree_apply_fn_mut { + ($header:ident, $id:ident, $bytes:ident, $func:ident, $($arg:tt)*) => { + _merkle_tree_apply_fn!($header, $id, $bytes, $func, TreeLoad::Mutable, $($arg)*) + }; +} + +/// This applies a given function on a read-only ConcurrentMerkleTree +#[macro_export] +macro_rules! merkle_tree_apply_fn { + ($header:ident, $id:ident, $bytes:ident, $func:ident, $($arg:tt)*) => { + _merkle_tree_apply_fn!($header, $id, $bytes, $func, TreeLoad::Immutable, $($arg)*) + }; +} + +pub(crate) use { + _merkle_tree_apply_fn, _merkle_tree_depth_size_apply_fn, merkle_tree_apply_fn, + merkle_tree_apply_fn_mut, +}; diff --git a/account-compression/programs/account-compression/src/noop/mod.rs b/account-compression/programs/account-compression/src/noop/mod.rs new file mode 100644 index 00000000000..a0b52889b23 --- /dev/null +++ b/account-compression/programs/account-compression/src/noop/mod.rs @@ -0,0 +1,45 @@ +//! # Data Wrapper +//! We use CPI calls to circumvent the 10kb log limit on Solana transactions. +//! Instead of logging events to the runtime, we execute a CPI to the `wrapper` program +//! where the log data is serialized into the instruction data. +//! +//! This works because CPI instruction data is never truncated. Logging information is +//! vital to the functioning of compression. When compression logs are truncated, indexers can fallback to +//! deserializing the CPI instruction data. + +use crate::events::{AccountCompressionEvent, ApplicationDataEvent, ApplicationDataEventV1}; +use anchor_lang::{prelude::*, solana_program::program::invoke}; + +#[derive(Clone)] +pub struct Noop; + +impl anchor_lang::Id for Noop { + fn id() -> Pubkey { + spl_noop::id() + } +} + +pub fn wrap_event<'info>( + event: &AccountCompressionEvent, + noop_program: &Program<'info, Noop>, +) -> Result<()> { + invoke( + &spl_noop::instruction(event.try_to_vec()?), + &[noop_program.to_account_info()], + )?; + Ok(()) +} + +/// Wraps a custom event in the most recent version of application event data +pub fn wrap_application_data_v1<'info>( + custom_data: Vec, + noop_program: &Program<'info, Noop>, +) -> Result<()> { + let versioned_data = ApplicationDataEventV1 { + application_data: custom_data, + }; + wrap_event( + &AccountCompressionEvent::ApplicationData(ApplicationDataEvent::V1(versioned_data)), + noop_program, + ) +} diff --git a/account-compression/programs/account-compression/src/state/concurrent_merkle_tree_header.rs b/account-compression/programs/account-compression/src/state/concurrent_merkle_tree_header.rs new file mode 100644 index 00000000000..5483a12947f --- /dev/null +++ b/account-compression/programs/account-compression/src/state/concurrent_merkle_tree_header.rs @@ -0,0 +1,250 @@ +use anchor_lang::prelude::*; +use borsh::{BorshDeserialize, BorshSerialize}; + +use spl_concurrent_merkle_tree::concurrent_merkle_tree::ConcurrentMerkleTree; +use std::mem::size_of; + +use crate::error::AccountCompressionError; + +pub const CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1: usize = 2 + 54; + +#[derive(Debug, Copy, Clone, PartialEq, BorshDeserialize, BorshSerialize)] +#[repr(u8)] +pub enum CompressionAccountType { + /// Uninitialized + Uninitialized, + + /// SPL ConcurrentMerkleTree data structure, may include a Canopy + ConcurrentMerkleTree, +} + +impl std::fmt::Display for CompressionAccountType { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{:?}", &self) + } +} + +#[cfg(feature = "idl-build")] +impl anchor_lang::IdlBuild for CompressionAccountType {} + +/// Initialization parameters for an SPL ConcurrentMerkleTree. +/// +/// Only the following permutations are valid: +/// +/// | max_depth | max_buffer_size | +/// | --------- | --------------------- | +/// | 14 | (64, 256, 1024, 2048) | +/// | 20 | (64, 256, 1024, 2048) | +/// | 24 | (64, 256, 512, 1024, 2048) | +/// | 26 | (64, 256, 512, 1024, 2048) | +/// | 30 | (512, 1024, 2048) | +/// +#[repr(C)] +#[derive(AnchorDeserialize, AnchorSerialize)] +pub struct ConcurrentMerkleTreeHeader { + /// Account type + pub account_type: CompressionAccountType, + /// Versioned header + pub header: ConcurrentMerkleTreeHeaderData, +} + +#[repr(C)] +#[derive(AnchorDeserialize, AnchorSerialize)] +pub struct ConcurrentMerkleTreeHeaderDataV1 { + /// Buffer of changelogs stored on-chain. + /// Must be a power of 2; see above table for valid combinations. + max_buffer_size: u32, + + /// Depth of the SPL ConcurrentMerkleTree to store. + /// Tree capacity can be calculated as power(2, max_depth). + /// See above table for valid options. + max_depth: u32, + + /// Authority that validates the content of the trees. + /// Typically a program, e.g., the Bubblegum contract validates that leaves are valid NFTs. + authority: Pubkey, + + /// Slot corresponding to when the Merkle tree was created. + /// Provides a lower-bound on what slot to start (re-)building a tree from. + creation_slot: u64, + + /// A flag indicating whether the tree has been initialized with a root. + /// This field was added together with the `finalize_tree_with_root` instruction. + /// It takes 1 byte of space taken from the previous padding for existing accounts. + is_batch_initialized: bool, + + /// Needs padding for the account to be 8-byte aligned + /// 8-byte alignment is necessary to zero-copy the SPL ConcurrentMerkleTree + _padding: [u8; 5], +} + +#[repr(C)] +#[derive(AnchorDeserialize, AnchorSerialize)] +pub enum ConcurrentMerkleTreeHeaderData { + V1(ConcurrentMerkleTreeHeaderDataV1), +} + +impl ConcurrentMerkleTreeHeader { + pub fn initialize( + &mut self, + max_depth: u32, + max_buffer_size: u32, + authority: &Pubkey, + creation_slot: u64, + ) { + self.account_type = CompressionAccountType::ConcurrentMerkleTree; + + match self.header { + ConcurrentMerkleTreeHeaderData::V1(ref mut header) => { + // Double check header is empty after deserialization from zero'd bytes + assert_eq!(header.max_buffer_size, 0); + assert_eq!(header.max_depth, 0); + header.max_buffer_size = max_buffer_size; + header.max_depth = max_depth; + header.authority = *authority; + header.creation_slot = creation_slot; + // is_batch_initialized is left false by default + } + } + } + + /// Initializes the header with the given parameters and sets the `is_batch_initialized` flag to + /// true. + pub fn initialize_batched( + &mut self, + max_depth: u32, + max_buffer_size: u32, + authority: &Pubkey, + creation_slot: u64, + ) { + self.initialize(max_depth, max_buffer_size, authority, creation_slot); + match self.header { + ConcurrentMerkleTreeHeaderData::V1(ref mut header) => { + header.is_batch_initialized = true; + } + } + } + + pub fn get_max_depth(&self) -> u32 { + match &self.header { + ConcurrentMerkleTreeHeaderData::V1(header) => header.max_depth, + } + } + + pub fn get_max_buffer_size(&self) -> u32 { + match &self.header { + ConcurrentMerkleTreeHeaderData::V1(header) => header.max_buffer_size, + } + } + + pub fn get_creation_slot(&self) -> u64 { + match &self.header { + ConcurrentMerkleTreeHeaderData::V1(header) => header.creation_slot, + } + } + + pub fn get_is_batch_initialized(&self) -> bool { + match &self.header { + ConcurrentMerkleTreeHeaderData::V1(header) => header.is_batch_initialized, + } + } + + pub fn set_new_authority(&mut self, new_authority: &Pubkey) { + match self.header { + ConcurrentMerkleTreeHeaderData::V1(ref mut header) => { + header.authority = new_authority.clone(); + msg!("Authority transferred to: {:?}", header.authority); + } + } + } + + pub fn assert_valid(&self) -> Result<()> { + require_eq!( + self.account_type, + CompressionAccountType::ConcurrentMerkleTree, + AccountCompressionError::IncorrectAccountType, + ); + Ok(()) + } + + pub fn assert_valid_authority(&self, expected_authority: &Pubkey) -> Result<()> { + self.assert_valid()?; + match &self.header { + ConcurrentMerkleTreeHeaderData::V1(header) => { + require_eq!( + header.authority, + *expected_authority, + AccountCompressionError::IncorrectAuthority, + ); + } + } + Ok(()) + } + + pub fn assert_valid_leaf_index(&self, leaf_index: u32) -> Result<()> { + if leaf_index >= (1 << self.get_max_depth()) { + return Err(AccountCompressionError::LeafIndexOutOfBounds.into()); + } + Ok(()) + } + + pub fn assert_is_batch_initialized(&self) -> Result<()> { + match &self.header { + ConcurrentMerkleTreeHeaderData::V1(header) => { + require!( + header.is_batch_initialized, + AccountCompressionError::BatchNotInitialized + ); + } + } + Ok(()) + } +} + +pub fn merkle_tree_get_size(header: &ConcurrentMerkleTreeHeader) -> Result { + // Note: max_buffer_size MUST be a power of 2 + match (header.get_max_depth(), header.get_max_buffer_size()) { + (3, 8) => Ok(size_of::>()), + (5, 8) => Ok(size_of::>()), + (6, 16) => Ok(size_of::>()), + (7, 16) => Ok(size_of::>()), + (8, 16) => Ok(size_of::>()), + (9, 16) => Ok(size_of::>()), + (10, 32) => Ok(size_of::>()), + (11, 32) => Ok(size_of::>()), + (12, 32) => Ok(size_of::>()), + (13, 32) => Ok(size_of::>()), + (14, 64) => Ok(size_of::>()), + (14, 256) => Ok(size_of::>()), + (14, 1024) => Ok(size_of::>()), + (14, 2048) => Ok(size_of::>()), + (15, 64) => Ok(size_of::>()), + (16, 64) => Ok(size_of::>()), + (17, 64) => Ok(size_of::>()), + (18, 64) => Ok(size_of::>()), + (19, 64) => Ok(size_of::>()), + (20, 64) => Ok(size_of::>()), + (20, 256) => Ok(size_of::>()), + (20, 1024) => Ok(size_of::>()), + (20, 2048) => Ok(size_of::>()), + (24, 64) => Ok(size_of::>()), + (24, 256) => Ok(size_of::>()), + (24, 512) => Ok(size_of::>()), + (24, 1024) => Ok(size_of::>()), + (24, 2048) => Ok(size_of::>()), + (26, 512) => Ok(size_of::>()), + (26, 1024) => Ok(size_of::>()), + (26, 2048) => Ok(size_of::>()), + (30, 512) => Ok(size_of::>()), + (30, 1024) => Ok(size_of::>()), + (30, 2048) => Ok(size_of::>()), + _ => { + msg!( + "Failed to get size of max depth {} and max buffer size {}", + header.get_max_depth(), + header.get_max_buffer_size() + ); + err!(AccountCompressionError::ConcurrentMerkleTreeConstantsError) + } + } +} diff --git a/account-compression/programs/account-compression/src/state/mod.rs b/account-compression/programs/account-compression/src/state/mod.rs new file mode 100644 index 00000000000..1027a6525f4 --- /dev/null +++ b/account-compression/programs/account-compression/src/state/mod.rs @@ -0,0 +1,6 @@ +//! State needed to manipulate SPL ConcurrentMerkleTrees +mod concurrent_merkle_tree_header; +mod path_node; + +pub use concurrent_merkle_tree_header::*; +pub use path_node::PathNode; diff --git a/account-compression/programs/account-compression/src/state/path_node.rs b/account-compression/programs/account-compression/src/state/path_node.rs new file mode 100644 index 00000000000..c245791413a --- /dev/null +++ b/account-compression/programs/account-compression/src/state/path_node.rs @@ -0,0 +1,17 @@ +use anchor_lang::prelude::*; +use spl_concurrent_merkle_tree::node::Node; + +#[derive(AnchorDeserialize, AnchorSerialize, Clone, Copy, Debug)] +pub struct PathNode { + pub node: [u8; 32], + pub index: u32, +} + +impl PathNode { + pub fn new(tree_node: Node, index: u32) -> Self { + Self { + node: tree_node, + index, + } + } +} diff --git a/account-compression/programs/account-compression/src/zero_copy.rs b/account-compression/programs/account-compression/src/zero_copy.rs new file mode 100644 index 00000000000..1ab76741262 --- /dev/null +++ b/account-compression/programs/account-compression/src/zero_copy.rs @@ -0,0 +1,31 @@ +//! Implements ZeroCopy over ConcurrrentMerkleTree generics +use crate::error::error_msg; +use anchor_lang::prelude::*; +use bytemuck::Pod; +use spl_concurrent_merkle_tree::concurrent_merkle_tree::ConcurrentMerkleTree; +use std::mem::size_of; + +pub trait ZeroCopy: Pod { + fn load_mut_bytes<'a>(data: &'a mut [u8]) -> Result<&'a mut Self> { + let size = size_of::(); + let data_len = data.len(); + + Ok(bytemuck::try_from_bytes_mut(&mut data[..size]) + .map_err(error_msg::(data_len)) + .unwrap()) + } + + fn load_bytes<'a>(data: &'a [u8]) -> Result<&'a Self> { + let size = size_of::(); + let data_len = data.len(); + + Ok(bytemuck::try_from_bytes(&data[..size]) + .map_err(error_msg::(data_len)) + .unwrap()) + } +} + +impl ZeroCopy + for ConcurrentMerkleTree +{ +} diff --git a/account-compression/programs/noop/Cargo.toml b/account-compression/programs/noop/Cargo.toml new file mode 100644 index 00000000000..00bf8d43053 --- /dev/null +++ b/account-compression/programs/noop/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "spl-noop" +version = "0.2.0" +description = "Solana Program Library No-op Program" +authors = ["Solana Labs Maintainers "] +repository = "https://github.com/solana-labs/solana-program-library" +license = "Apache-2.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] + +[features] +no-entrypoint = [] +cpi = ["no-entrypoint"] +default = [] + +[dependencies] +solana-program = ">=1.18.11,<=2" diff --git a/account-compression/programs/noop/README.md b/account-compression/programs/noop/README.md new file mode 100644 index 00000000000..7ebb949011d --- /dev/null +++ b/account-compression/programs/noop/README.md @@ -0,0 +1,12 @@ +

+ + Solana + +

+ +# SPL Noop Rust SDK + +This crate provides a wrapper for invoking `spl-noop`, which does nothing. +It's primary use is circumventing log truncation when emitting application data by `invoke`-ing `spl-noop` with event data. + +`spl-noop` and this crate's implementation are targeted towards supporting [account-compression](https://github.com/solana-labs/solana-program-library/tree/master/account-compression) and may be subject to change. diff --git a/account-compression/programs/noop/src/lib.rs b/account-compression/programs/noop/src/lib.rs new file mode 100644 index 00000000000..da30b630dae --- /dev/null +++ b/account-compression/programs/noop/src/lib.rs @@ -0,0 +1,25 @@ +use solana_program::{ + account_info::AccountInfo, declare_id, entrypoint::ProgramResult, instruction::Instruction, + pubkey::Pubkey, +}; + +declare_id!("noopb9bkMVfRPU8AsbpTUg8AQkHtKwMYZiFUjNRtMmV"); + +#[cfg(not(feature = "no-entrypoint"))] +solana_program::entrypoint!(noop); + +pub fn noop( + _program_id: &Pubkey, + _accounts: &[AccountInfo], + _instruction_data: &[u8], +) -> ProgramResult { + Ok(()) +} + +pub fn instruction(data: Vec) -> Instruction { + Instruction { + program_id: crate::id(), + accounts: vec![], + data, + } +} diff --git a/account-compression/sdk/.eslintignore b/account-compression/sdk/.eslintignore new file mode 100644 index 00000000000..fd7d66e9833 --- /dev/null +++ b/account-compression/sdk/.eslintignore @@ -0,0 +1,5 @@ +/.eslintrc.js +/.solitarc.js +/jest.config.js +doc +dist diff --git a/account-compression/sdk/.eslintrc.js b/account-compression/sdk/.eslintrc.js new file mode 100644 index 00000000000..05db167860a --- /dev/null +++ b/account-compression/sdk/.eslintrc.js @@ -0,0 +1,12 @@ +module.exports = { + extends: ['turbo', '@solana/eslint-config-solana', '@solana/eslint-config-solana/jest'], + overrides: [ + { + files: ['tests/**.ts'], + rules: { + 'no-empty': ['error', { allowEmptyCatch: true }], + }, + }, + ], + root: true, +}; diff --git a/account-compression/sdk/.gitignore b/account-compression/sdk/.gitignore new file mode 100644 index 00000000000..ee9ee6b5a87 --- /dev/null +++ b/account-compression/sdk/.gitignore @@ -0,0 +1,3 @@ +dist/ +doc/ +test-ledger/ diff --git a/account-compression/sdk/.npmignore b/account-compression/sdk/.npmignore new file mode 100644 index 00000000000..ea6ea0c48cb --- /dev/null +++ b/account-compression/sdk/.npmignore @@ -0,0 +1,3 @@ +node_modules/ +test-ledger/ +tests/ diff --git a/account-compression/sdk/.solitarc.js b/account-compression/sdk/.solitarc.js new file mode 100644 index 00000000000..f6613107c1f --- /dev/null +++ b/account-compression/sdk/.solitarc.js @@ -0,0 +1,16 @@ +// @ts-check +const path = require('path'); +const programDir = path.join(__dirname, '..', 'programs', 'account-compression'); +const idlDir = path.join(__dirname, 'idl'); +const sdkDir = path.join(__dirname, 'src', 'generated'); +const binaryInstallDir = path.join(__dirname, '..', 'target', 'solita'); + +module.exports = { + idlGenerator: 'anchor', + programName: 'spl_account_compression', + programId: 'cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK', + idlDir, + sdkDir, + binaryInstallDir, + programDir, +}; diff --git a/account-compression/sdk/README.md b/account-compression/sdk/README.md new file mode 100644 index 00000000000..00c37ff2169 --- /dev/null +++ b/account-compression/sdk/README.md @@ -0,0 +1,180 @@ +# `@solana/spl-account-compression` + +A TypeScript library for interacting with SPL Account Compression and SPL NoOp. +For more information, see the full [Solana account compression SDK documentation](https://solana-labs.github.io/solana-program-library/account-compression/sdk/). + +## Install + +```shell +npm install --save @solana/spl-account-compression @solana/web3.js@1 +``` + +__OR__ + +```shell +yarn add @solana/spl-account-compression @solana/web3.js@1 +``` + +## Information + +This on-chain program provides an interface for composing smart contracts to create and use SPL ConcurrentMerkleTrees. +The primary application of using SPL ConcurrentMerkleTrees is to synchronize off-chain databases with on-chain updates. + +SPL ConcurrentMerkleTrees are Merkle Trees that have their roots on-chain with support for fast-forwarding proofs. Fast forwarding allows multiple updates to the tree in a single block and reduces the latency burden on indexers. + + +In order to execute transactions that modify an SPL ConcurrentMerkleTree, an indexer will need to +parse through transactions that touch the tree in order to provide up-to-date merkle proofs. +For more information regarding merkle proofs, see this great [explainer](https://ethereum.org/en/developers/tutorials/merkle-proofs-for-offline-data-integrity/). + +This program is targeted towards supporting [Metaplex Compressed NFTs](https://github.com/metaplex-foundation/metaplex-program-library/tree/master/bubblegum) and may be subject to change. + +A **rough draft** of the whitepaper for SPL ConcurrentMerkleTrees can be found [here](https://drive.google.com/file/d/1BOpa5OFmara50fTvL0VIVYjtg-qzHCVc/view). + +## High Level Overview + +### Instructions +Code to interact with the on-chain instructions is auto-generated by `@metaplex-foundation/solita`. +Exported functions to create instructions have pattern `createInstruction`. +* For example, account compression's `append_leaf` instruction has a `Solita`-generated factory function called +`createAppendLeafInstruction`. + +`Solita` provides very low-level functions to create instructions. Thus, helper functions are provided for each instruction, denoted with the suffix `ix`. +* For example: `createReplaceLeafInstruction` has a helper function `createReplaceLeafIx` + +### Modules + +A merkle tree reference implementation is provided to index the on-chain trees. The `MerkleTree` class and its helpers are provided +under `src/merkle-tree`. + +The `MerkleTree` class is meant to follow a similar interface as `MerkleTree` from [`merkletreejs`](https://www.npmjs.com/package/merkletreejs). + +| Feature | Our Tree | `merkletreejs` | Notes | +| ---------- | -------- | -------------- | ------------------------------------------------------------ | +| updateLeaf | ✅ | ❌ | This is the unique feature of `ConcurrentMerkleTree`'s | +| multiProof | ❌ | ✅ | Possible to support in future version of Account Compression | +| addLeaf | ✅ | ✅ | Our version does this via `updateLeaf()` | + +If you'd like to see more features added, please create an issue with the title `Account Compression` and your feature request. + +### Examples + +1. Create a tree + +```typescript +// Assume: known `payer` Keypair + +// Generate a keypair for the ConcurrentMerkleTree +const cmtKeypair = Keypair.generate(); + +// Create a system instruction to allocate enough +// space for the tree +const allocAccountIx = await createAllocTreeIx( + connection, + cmtKeypair.publicKey, + payer.publicKey, + { maxDepth, maxBufferSize }, + canopyDepth, +); + +// Create an SPL compression instruction to initialize +// the newly created ConcurrentMerkleTree +const initTreeIx = createInitEmptyMerkleTreeIx( + cmtKeypair.publicKey, + payer.publicKey, + { maxDepth, maxBufferSize } +); + +const tx = new Transaction().add(allocAccountIx).add(initTreeIx); + +await sendAndConfirmTransaction(connection, tx, [cmtKeypair, payer]); +``` + +2. Add a leaf to the tree + +```typescript +// Create a new leaf +const newLeaf: Buffer = crypto.randomBytes(32); + +// Add the new leaf to the existing tree +const appendIx = createAppendIx(cmtKeypair.publicKey, payer.publicKey, newLeaf); + +const tx = new Transaction().add(appendIx); + +await sendAndConfirmTransaction(connection, tx, [payer]); +``` + +3. Replace a leaf in the tree, using the provided `MerkleTree` as an indexer + +This example assumes that `offChainTree` has been indexing all previous modifying transactions +involving this tree. +It is okay for the indexer to be behind by a maximum of `maxBufferSize` transactions. + + +```typescript +// Assume: `offChainTree` is a MerkleTree instance +// that has been indexing the `cmtKeypair.publicKey` transactions + +// Get a new leaf +const newLeaf: Buffer = crypto.randomBytes(32); + +// Query off-chain records for information about the leaf +// you wish to replace by its index in the tree +const leafIndex = 314; + +// Replace the leaf at `leafIndex` with `newLeaf` +const replaceIx = createReplaceIx( + cmtKeypair.publicKey, + payer.publicKey, + newLeaf, + offChainTree.getProof(leafIndex) +); + +const tx = new Transaction().add(replaceIx); + +await sendAndConfirmTransaction(connection, tx, [payer]); +``` + +4. Replace a leaf in the tree, using a 3rd party indexer + +This example assumes that some 3rd party service is indexing the tree at `cmtKeypair.publicKey` for you, and providing MerkleProofs via some REST endpoint. +The `getProofFromAnIndexer` function is a **placeholder** to exemplify this relationship. + +```typescript +// Get a new leaf +const newLeaf: Buffer = crypto.randomBytes(32); + +// Query off-chain indexer for a MerkleProof +// possibly by executing GET request against a REST api +const proof = await getProofFromAnIndexer(myOldLeaf); + +// Replace `myOldLeaf` with `newLeaf` at the same index in the tree +const replaceIx = createReplaceIx( + cmtKeypair.publicKey, + payer.publicKey, + newLeaf, + proof +); + +const tx = new Transaction().add(replaceIx); + +await sendAndConfirmTransaction(connection, tx, [payer]); +``` + +## Reference examples + +Here are some examples using account compression in the wild: + +* Solana Program Library [tests](https://github.com/solana-labs/solana-program-library/tree/master/account-compression/sdk/tests) + +* Metaplex Program Library Compressed NFT [tests](https://github.com/metaplex-foundation/mpl-bubblegum/tree/main/clients/js/test) + +## Build from Source + +0. Install dependencies with `pnpm i`. + +1. Generate the Solita SDK with `pnpm solita`. + +2. Then build the SDK with `pnpm build`. + +3. Run tests with `pnpm test`. (Expect `jest` to detect an open handle that prevents it from exiting naturally) diff --git a/account-compression/sdk/idl/spl_account_compression.json b/account-compression/sdk/idl/spl_account_compression.json new file mode 100644 index 00000000000..a9477f25eca --- /dev/null +++ b/account-compression/sdk/idl/spl_account_compression.json @@ -0,0 +1,768 @@ +{ + "version": "0.3.1", + "name": "spl_account_compression", + "instructions": [ + { + "name": "initEmptyMerkleTree", + "docs": [ + "Creates a new merkle tree with maximum leaf capacity of `power(2, max_depth)`", + "and a minimum concurrency limit of `max_buffer_size`.", + "", + "Concurrency limit represents the # of replace instructions that can be successfully", + "executed with proofs dated for the same root. For example, a maximum buffer size of 1024", + "means that a minimum of 1024 replaces can be executed before a new proof must be", + "generated for the next replace instruction.", + "", + "Concurrency limit should be determined by empirically testing the demand for", + "state built on top of SPL Compression.", + "", + "For instructions on enabling the canopy, see [canopy]." + ], + "accounts": [ + { + "name": "merkleTree", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "docs": [ + "Authority that controls write-access to the tree", + "Typically a program, e.g., the Bubblegum contract validates that leaves are valid NFTs." + ] + }, + { + "name": "noop", + "isMut": false, + "isSigner": false, + "docs": ["Program used to emit changelogs as cpi instruction data."] + } + ], + "args": [ + { + "name": "maxDepth", + "type": "u32" + }, + { + "name": "maxBufferSize", + "type": "u32" + } + ] + }, + { + "name": "prepareBatchMerkleTree", + "docs": [ + "In order to initialize a tree with a root, we need to create the tree on-chain first with", + "the proper authority. The tree might contain a canopy, which is a cache of the uppermost", + "nodes. The canopy is used to decrease the size of the proof required to update the tree.", + "If the tree is expected to have a canopy, it needs to be prefilled with the necessary nodes.", + "There are 2 ways to initialize a merkle tree:", + "1. Initialize an empty tree", + "2. Initialize a tree with a root and leaf", + "For the former case, the canopy will be empty which is expected for an empty tree. The", + "expected flow is `init_empty_merkle_tree`. For the latter case, the canopy should be", + "filled with the necessary nodes to render the tree usable. Thus we need to prefill the", + "canopy with the necessary nodes. The expected flow for a tree without canopy is", + "`prepare_batch_merkle_tree` -> `init_prepared_tree_with_root`. The expected flow for a tree", + "with canopy is `prepare_batch_merkle_tree` -> `append_canopy_nodes` (multiple times", + "until all of the canopy is filled) -> `init_prepared_tree_with_root`. This instruction", + "initializes the tree header while leaving the tree itself uninitialized. This allows", + "distinguishing between an empty tree and a tree prepare to be initialized with a root." + ], + "accounts": [ + { + "name": "merkleTree", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "docs": [ + "Authority that controls write-access to the tree", + "Typically a program, e.g., the Bubblegum contract validates that leaves are valid NFTs." + ] + }, + { + "name": "noop", + "isMut": false, + "isSigner": false, + "docs": ["Program used to emit changelogs as cpi instruction data."] + } + ], + "args": [ + { + "name": "maxDepth", + "type": "u32" + }, + { + "name": "maxBufferSize", + "type": "u32" + } + ] + }, + { + "name": "appendCanopyNodes", + "docs": [ + "This instruction pre-initializes the canopy with the specified leaf nodes of the canopy.", + "This is intended to be used after `prepare_batch_merkle_tree` and in conjunction with the", + "`init_prepared_tree_with_root` instruction that'll finalize the tree initialization.", + "The canopy is used to cache the uppermost nodes of the tree, which allows for a smaller", + "proof size when updating the tree. The canopy should be filled with the necessary nodes", + "before calling `init_prepared_tree_with_root`. You may call this instruction multiple", + "times to fill the canopy with the necessary nodes. The canopy may be filled with the", + "nodes in any order. The already filled nodes may be replaced with new nodes before calling", + "`init_prepared_tree_with_root` if the step was done in error.", + "The canopy should be filled with all the nodes that are to the left of the rightmost", + "leaf of the tree before calling `init_prepared_tree_with_root`. The canopy should not", + "contain any nodes to the right of the rightmost leaf of the tree.", + "This instruction calculates and filles in all the canopy nodes \"above\" the provided ones.", + "The validation of the canopy is done in the `init_prepared_tree_with_root` instruction." + ], + "accounts": [ + { + "name": "merkleTree", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "docs": [ + "Authority that controls write-access to the tree", + "Typically a program, e.g., the Bubblegum contract validates that leaves are valid NFTs." + ] + }, + { + "name": "noop", + "isMut": false, + "isSigner": false, + "docs": ["Program used to emit changelogs as cpi instruction data."] + } + ], + "args": [ + { + "name": "startIndex", + "type": "u32" + }, + { + "name": "canopyNodes", + "type": { + "vec": { + "array": ["u8", 32] + } + } + } + ] + }, + { + "name": "initPreparedTreeWithRoot", + "docs": [ + "Initializes a prepared tree with a root and a rightmost leaf. The rightmost leaf is used to", + "verify the canopy if the tree has it. Before calling this instruction, the tree should be", + "prepared with `prepare_batch_merkle_tree` and the canopy should be filled with the necessary", + "nodes with `append_canopy_nodes` (if the canopy is used). This method should be used for", + "batch creation of trees. The indexing of such batches should be done off-chain. The", + "programs calling this instruction should take care of ensuring the indexing is possible.", + "For example, staking may be required to ensure the tree creator has some responsibility", + "for what is being indexed. If indexing is not possible, there should be a mechanism to", + "penalize the tree creator." + ], + "accounts": [ + { + "name": "merkleTree", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "docs": [ + "Authority that controls write-access to the tree", + "Typically a program, e.g., the Bubblegum contract validates that leaves are valid NFTs." + ] + }, + { + "name": "noop", + "isMut": false, + "isSigner": false, + "docs": ["Program used to emit changelogs as cpi instruction data."] + } + ], + "args": [ + { + "name": "root", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "rightmostLeaf", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "rightmostIndex", + "type": "u32" + } + ] + }, + { + "name": "replaceLeaf", + "docs": [ + "Executes an instruction that overwrites a leaf node.", + "Composing programs should check that the data hashed into previous_leaf", + "matches the authority information necessary to execute this instruction." + ], + "accounts": [ + { + "name": "merkleTree", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "docs": [ + "Authority that controls write-access to the tree", + "Typically a program, e.g., the Bubblegum contract validates that leaves are valid NFTs." + ] + }, + { + "name": "noop", + "isMut": false, + "isSigner": false, + "docs": ["Program used to emit changelogs as cpi instruction data."] + } + ], + "args": [ + { + "name": "root", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "previousLeaf", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "newLeaf", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "index", + "type": "u32" + } + ] + }, + { + "name": "transferAuthority", + "docs": ["Transfers `authority`.", "Requires `authority` to sign"], + "accounts": [ + { + "name": "merkleTree", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "docs": [ + "Authority that controls write-access to the tree", + "Typically a program, e.g., the Bubblegum contract validates that leaves are valid NFTs." + ] + } + ], + "args": [ + { + "name": "newAuthority", + "type": "publicKey" + } + ] + }, + { + "name": "verifyLeaf", + "docs": [ + "Verifies a provided proof and leaf.", + "If invalid, throws an error." + ], + "accounts": [ + { + "name": "merkleTree", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "root", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "leaf", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "index", + "type": "u32" + } + ] + }, + { + "name": "append", + "docs": [ + "This instruction allows the tree's `authority` to append a new leaf to the tree", + "without having to supply a proof.", + "", + "Learn more about SPL", + "ConcurrentMerkleTree", + "[here](https://github.com/solana-labs/solana-program-library/tree/master/libraries/concurrent-merkle-tree)" + ], + "accounts": [ + { + "name": "merkleTree", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "docs": [ + "Authority that controls write-access to the tree", + "Typically a program, e.g., the Bubblegum contract validates that leaves are valid NFTs." + ] + }, + { + "name": "noop", + "isMut": false, + "isSigner": false, + "docs": ["Program used to emit changelogs as cpi instruction data."] + } + ], + "args": [ + { + "name": "leaf", + "type": { + "array": ["u8", 32] + } + } + ] + }, + { + "name": "insertOrAppend", + "docs": [ + "This instruction takes a proof, and will attempt to write the given leaf", + "to the specified index in the tree. If the insert operation fails, the leaf will be `append`-ed", + "to the tree.", + "It is up to the indexer to parse the final location of the leaf from the emitted changelog." + ], + "accounts": [ + { + "name": "merkleTree", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "docs": [ + "Authority that controls write-access to the tree", + "Typically a program, e.g., the Bubblegum contract validates that leaves are valid NFTs." + ] + }, + { + "name": "noop", + "isMut": false, + "isSigner": false, + "docs": ["Program used to emit changelogs as cpi instruction data."] + } + ], + "args": [ + { + "name": "root", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "leaf", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "index", + "type": "u32" + } + ] + }, + { + "name": "closeEmptyTree", + "accounts": [ + { + "name": "merkleTree", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "docs": ["Authority that controls write-access to the tree"] + }, + { + "name": "recipient", + "isMut": true, + "isSigner": false + } + ], + "args": [] + } + ], + "types": [ + { + "name": "ApplicationDataEventV1", + "type": { + "kind": "struct", + "fields": [ + { + "name": "applicationData", + "type": "bytes" + } + ] + } + }, + { + "name": "ChangeLogEventV1", + "type": { + "kind": "struct", + "fields": [ + { + "name": "id", + "docs": ["Public key of the ConcurrentMerkleTree"], + "type": "publicKey" + }, + { + "name": "path", + "docs": ["Nodes of off-chain merkle tree needed by indexer"], + "type": { + "vec": { + "defined": "PathNode" + } + } + }, + { + "name": "seq", + "docs": [ + "Index corresponding to the number of successful operations on this tree.", + "Used by the off-chain indexer to figure out when there are gaps to be backfilled." + ], + "type": "u64" + }, + { + "name": "index", + "docs": ["Bitmap of node parity (used when hashing)"], + "type": "u32" + } + ] + } + }, + { + "name": "ConcurrentMerkleTreeHeader", + "docs": [ + "Initialization parameters for an SPL ConcurrentMerkleTree.", + "", + "Only the following permutations are valid:", + "", + "| max_depth | max_buffer_size |", + "| --------- | --------------------- |", + "| 14 | (64, 256, 1024, 2048) |", + "| 20 | (64, 256, 1024, 2048) |", + "| 24 | (64, 256, 512, 1024, 2048) |", + "| 26 | (64, 256, 512, 1024, 2048) |", + "| 30 | (512, 1024, 2048) |", + "" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "accountType", + "docs": ["Account type"], + "type": { + "defined": "CompressionAccountType" + } + }, + { + "name": "header", + "docs": ["Versioned header"], + "type": { + "defined": "ConcurrentMerkleTreeHeaderData" + } + } + ] + } + }, + { + "name": "ConcurrentMerkleTreeHeaderDataV1", + "type": { + "kind": "struct", + "fields": [ + { + "name": "maxBufferSize", + "docs": [ + "Buffer of changelogs stored on-chain.", + "Must be a power of 2; see above table for valid combinations." + ], + "type": "u32" + }, + { + "name": "maxDepth", + "docs": [ + "Depth of the SPL ConcurrentMerkleTree to store.", + "Tree capacity can be calculated as power(2, max_depth).", + "See above table for valid options." + ], + "type": "u32" + }, + { + "name": "authority", + "docs": [ + "Authority that validates the content of the trees.", + "Typically a program, e.g., the Bubblegum contract validates that leaves are valid NFTs." + ], + "type": "publicKey" + }, + { + "name": "creationSlot", + "docs": [ + "Slot corresponding to when the Merkle tree was created.", + "Provides a lower-bound on what slot to start (re-)building a tree from." + ], + "type": "u64" + }, + { + "name": "isBatchInitialized", + "docs": [ + "A flag indicating whether the tree has been initialized with a root.", + "This field was added together with the `finalize_tree_with_root` instruction.", + "It takes 1 byte of space taken from the previous padding for existing accounts." + ], + "type": "bool" + }, + { + "name": "padding", + "docs": [ + "Needs padding for the account to be 8-byte aligned", + "8-byte alignment is necessary to zero-copy the SPL ConcurrentMerkleTree" + ], + "type": { + "array": ["u8", 5] + } + } + ] + } + }, + { + "name": "PathNode", + "type": { + "kind": "struct", + "fields": [ + { + "name": "node", + "type": { + "array": ["u8", 32] + } + }, + { + "name": "index", + "type": "u32" + } + ] + } + }, + { + "name": "ApplicationDataEvent", + "type": { + "kind": "enum", + "variants": [ + { + "name": "V1", + "fields": [ + { + "defined": "ApplicationDataEventV1" + } + ] + } + ] + } + }, + { + "name": "ChangeLogEvent", + "type": { + "kind": "enum", + "variants": [ + { + "name": "V1", + "fields": [ + { + "defined": "ChangeLogEventV1" + } + ] + } + ] + } + }, + { + "name": "AccountCompressionEvent", + "type": { + "kind": "enum", + "variants": [ + { + "name": "ChangeLog", + "fields": [ + { + "defined": "ChangeLogEvent" + } + ] + }, + { + "name": "ApplicationData", + "fields": [ + { + "defined": "ApplicationDataEvent" + } + ] + } + ] + } + }, + { + "name": "CompressionAccountType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Uninitialized" + }, + { + "name": "ConcurrentMerkleTree" + } + ] + } + }, + { + "name": "ConcurrentMerkleTreeHeaderData", + "type": { + "kind": "enum", + "variants": [ + { + "name": "V1", + "fields": [ + { + "defined": "ConcurrentMerkleTreeHeaderDataV1" + } + ] + } + ] + } + } + ], + "errors": [ + { + "code": 6000, + "name": "IncorrectLeafLength", + "msg": "Incorrect leaf length. Expected vec of 32 bytes" + }, + { + "code": 6001, + "name": "ConcurrentMerkleTreeError", + "msg": "Concurrent merkle tree error" + }, + { + "code": 6002, + "name": "ZeroCopyError", + "msg": "Issue zero copying concurrent merkle tree data" + }, + { + "code": 6003, + "name": "ConcurrentMerkleTreeConstantsError", + "msg": "An unsupported max depth or max buffer size constant was provided" + }, + { + "code": 6004, + "name": "CanopyLengthMismatch", + "msg": "Expected a different byte length for the merkle tree canopy" + }, + { + "code": 6005, + "name": "IncorrectAuthority", + "msg": "Provided authority does not match expected tree authority" + }, + { + "code": 6006, + "name": "IncorrectAccountOwner", + "msg": "Account is owned by a different program, expected it to be owned by this program" + }, + { + "code": 6007, + "name": "IncorrectAccountType", + "msg": "Account provided has incorrect account type" + }, + { + "code": 6008, + "name": "LeafIndexOutOfBounds", + "msg": "Leaf index of concurrent merkle tree is out of bounds" + }, + { + "code": 6009, + "name": "CanopyNotAllocated", + "msg": "Tree was initialized without allocating space for the canopy" + }, + { + "code": 6010, + "name": "TreeAlreadyInitialized", + "msg": "Tree was already initialized" + }, + { + "code": 6011, + "name": "BatchNotInitialized", + "msg": "Tree header was not initialized for batch processing" + }, + { + "code": 6012, + "name": "CanopyRootMismatch", + "msg": "Canopy root does not match the root of the tree" + }, + { + "code": 6013, + "name": "CanopyRightmostLeafMismatch", + "msg": "Canopy contains nodes to the right of the rightmost leaf of the tree" + } + ], + "metadata": { + "address": "cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK", + "origin": "anchor", + "binaryVersion": "0.29.0", + "libVersion": "0.29.0" + } +} diff --git a/account-compression/sdk/jest.config.js b/account-compression/sdk/jest.config.js new file mode 100644 index 00000000000..9cf351f0803 --- /dev/null +++ b/account-compression/sdk/jest.config.js @@ -0,0 +1,6 @@ +module.exports = { + preset: 'ts-jest/presets/default', + testEnvironment: 'node', + testTimeout: 100000, + resolver: 'ts-jest-resolver', +}; diff --git a/account-compression/sdk/package.json b/account-compression/sdk/package.json new file mode 100644 index 00000000000..c5b5069991b --- /dev/null +++ b/account-compression/sdk/package.json @@ -0,0 +1,91 @@ +{ + "name": "@solana/spl-account-compression", + "description": "SPL Account Compression Program JS API", + "version": "0.4.1", + "author": "Solana Labs Maintainers ", + "repository": { + "url": "https://github.com/solana-labs/solana-program-library", + "type": "git" + }, + "license": "Apache-2.0", + "sideEffects": false, + "engines": { + "node": ">=16" + }, + "files": [ + "dist", + "src", + "idl", + "README.md" + ], + "publishConfig": { + "access": "public" + }, + "main": "./dist/cjs/index.js", + "module": "./dist/cjs/index.js", + "types": "./dist/types/index.d.ts", + "exports": { + ".": { + "types": "./dist/types/index.d.ts", + "require": "./dist/cjs/index.js", + "import": "./dist/cjs/index.js" + }, + "./idl/spl_account_compression.json": "./idl/spl_account_compression.json" + }, + "scripts": { + "build": "rm -rf dist/ && tsc -p tsconfig.json", + "build:program": "cargo build-sbf --manifest-path=../programs/account-compression/Cargo.toml && cargo build-sbf --manifest-path=../programs/noop/Cargo.toml", + "lint": "set -ex; eslint . --ext .js,.ts", + "lint:fix": "eslint . --fix --ext .js,.ts", + "docs": "rm -rf docs/ && typedoc --out docs", + "deploy:docs": "npm run docs && gh-pages --dest account-compression/sdk --dist docs --dotfiles", + "start-validator": "solana-test-validator --reset --quiet --bpf-program cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK ../target/deploy/spl_account_compression.so --bpf-program noopb9bkMVfRPU8AsbpTUg8AQkHtKwMYZiFUjNRtMmV ../target/deploy/spl_noop.so --account 27QMkDMpBoAhmWj6xxQNYdqXZL5nnC8tkZcEtkNxCqeX pre-batch-init-tree-account.json", + "run-tests": "jest tests --detectOpenHandles", + "run-tests:events": "jest tests/events --detectOpenHandles", + "run-tests:accounts": "jest tests/accounts --detectOpenHandles", + "run-tests:e2e": "jest accountCompression.test.ts --detectOpenHandles", + "test:events": "start-server-and-test start-validator http://127.0.0.1:8899/health run-tests:events", + "test:accounts": "start-server-and-test start-validator http://127.0.0.1:8899/health run-tests:accounts", + "test:e2e": "start-server-and-test start-validator http://127.0.0.1:8899/health run-tests:e2e", + "test:merkle-tree": "jest tests/merkleTree.test.ts --detectOpenHandles", + "test": "start-server-and-test start-validator http://127.0.0.1:8899/health run-tests" + }, + "dependencies": { + "@metaplex-foundation/beet": "^0.7.2", + "@metaplex-foundation/beet-solana": "^0.4.1", + "bn.js": "^5.2.1", + "js-sha3": "^0.9.3", + "typescript-collections": "^1.3.3" + }, + "peerDependencies": { + "@solana/web3.js": "^1.95.4" + }, + "devDependencies": { + "@metaplex-foundation/rustbin": "^0.3.5", + "@metaplex-foundation/solita": "0.20.1", + "@coral-xyz/anchor": "^0.29.0", + "@solana/eslint-config-solana": "^3.0.3", + "@types/bn.js": "^5.1.6", + "@types/jest": "^29.5.14", + "@types/node": "^22.10.5", + "@types/node-fetch": "^2.6.12", + "@typescript-eslint/eslint-plugin": "^8.4.0", + "@typescript-eslint/parser": "^8.4.0", + "eslint": "^8.57.0", + "eslint-config-turbo": "^2.3.3", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jest": "^28.10.0", + "eslint-plugin-mocha": "^10.5.0", + "eslint-plugin-simple-import-sort": "^12.1.1", + "eslint-plugin-sort-keys-fix": "^1.1.2", + "gh-pages": "^6.3.0", + "jest": "^29.0.1", + "jest-config": "^29.0.1", + "start-server-and-test": "^2.0.9", + "ts-jest": "^29.2.5", + "ts-jest-resolver": "^2.0.1", + "ts-node": "^10.9.2", + "typedoc": "^0.27.6", + "typescript": "5.7.2" + } +} diff --git a/account-compression/sdk/prettierrc.yaml b/account-compression/sdk/prettierrc.yaml new file mode 100644 index 00000000000..67cd9222f75 --- /dev/null +++ b/account-compression/sdk/prettierrc.yaml @@ -0,0 +1,6 @@ +arrowParens: "avoid" +bracketSpacing: false +semi: true +singleQuote: true +tabWidth: 2 +trailingComma: "all" \ No newline at end of file diff --git a/account-compression/sdk/src/accounts/ConcurrentMerkleTreeAccount.ts b/account-compression/sdk/src/accounts/ConcurrentMerkleTreeAccount.ts new file mode 100644 index 00000000000..bef2f4954cb --- /dev/null +++ b/account-compression/sdk/src/accounts/ConcurrentMerkleTreeAccount.ts @@ -0,0 +1,207 @@ +import type { Commitment, Connection, GetAccountInfoConfig, PublicKey } from '@solana/web3.js'; +import { BN } from 'bn.js'; + +import { ConcurrentMerkleTreeHeaderDataV1, concurrentMerkleTreeHeaderDataV1Beet } from '../generated'; +import { + ConcurrentMerkleTreeHeader, + concurrentMerkleTreeHeaderBeet, +} from '../generated/types/ConcurrentMerkleTreeHeader'; +import { Canopy, canopyBeetFactory, ConcurrentMerkleTree, concurrentMerkleTreeBeetFactory } from '../types'; + +/** + * This class provides all the getter methods to deserialize + * information associated with an on-chain ConcurrentMerkleTree + */ +export class ConcurrentMerkleTreeAccount { + public header: ConcurrentMerkleTreeHeader; + public tree: ConcurrentMerkleTree; + public canopy: Canopy; + + constructor(header: ConcurrentMerkleTreeHeader, tree: ConcurrentMerkleTree, canopy: Canopy) { + this.header = header; + this.tree = tree; + this.canopy = canopy; + } + + static fromBuffer(buffer: Buffer): ConcurrentMerkleTreeAccount { + return deserializeConcurrentMerkleTree(buffer); + } + + static async fromAccountAddress( + connection: Connection, + publicKey: PublicKey, + commitmentOrConfig?: Commitment | GetAccountInfoConfig, + ): Promise { + const account = await connection.getAccountInfo(publicKey, commitmentOrConfig); + if (!account) { + throw new Error('CMT account data unexpectedly null!'); + } + return deserializeConcurrentMerkleTree(account.data); + } + + private getHeaderV1(): ConcurrentMerkleTreeHeaderDataV1 { + return this.header.header.fields[0]; + } + + /** + * Returns the `maxBufferSize` for this tree, by reading the account's header + * @returns + */ + getMaxBufferSize(): number { + return this.getHeaderV1().maxBufferSize; + } + + /** + * Returns the `maxDepth` of this tree, by reading the account's header + * @returns + */ + getMaxDepth(): number { + return this.getHeaderV1().maxDepth; + } + + /** + * Returns `min(seq, maxBufferSize)` + * @returns + */ + getBufferSize(): number { + return new BN.BN(this.tree.bufferSize).toNumber(); + } + + /** + * Returns the current root hash for this on-chain tree + * @returns + */ + getCurrentRoot(): Buffer { + return this.tree.changeLogs[this.getCurrentBufferIndex()].root.toBuffer(); + } + + /** + * Returns the index to the spot in the on-chain buffer that stores the current + * root and last changelog. + * + * Should always be `this.getCurrentSeq() % this.getMaxBufferSize()` + * @returns + */ + getCurrentBufferIndex(): number { + return new BN.BN(this.tree.activeIndex).toNumber(); + } + + /** + * Returns the PublicKey that can execute modifying operations + * on this tree + * @returns + */ + getAuthority(): PublicKey { + return this.getHeaderV1().authority; + } + + /** + * Returns the slot that this tree was created in. Useful for indexing + * transactions associated with this tree. + * @returns + */ + getCreationSlot() { + return new BN(this.getHeaderV1().creationSlot); + } + + /** + * Returns the number of modifying operations that have been performed + * on this tree. + * @returns + */ + getCurrentSeq() { + return new BN(this.tree.sequenceNumber); + } + + /** + * Returns the depth of the on-chain tree-cache. Increasing the canopy depth reduces the size of the proofs + * that have to be passed for tree instructions. + * @returns the size + */ + getCanopyDepth(): number { + return getCanopyDepth(this.canopy.canopyBytes.length); + } + + /** + * Returns the flag that indicates if the tree has been batch initialized + * @returns the flag + */ + getIsBatchInitialized(): boolean { + return this.getHeaderV1().isBatchInitialized; + } +} + +/** + * Return expected depth of the cached {@link Canopy} tree just from the number + * of bytes used to store the Canopy + * + * @param canopyByteLength + * @returns + */ +export function getCanopyDepth(canopyByteLength: number): number { + if (canopyByteLength === 0) { + return 0; + } + return Math.log2(canopyByteLength / 32 + 2) - 1; +} + +function deserializeConcurrentMerkleTree(buffer: Buffer): ConcurrentMerkleTreeAccount { + let offset = 0; + const [versionedHeader, offsetIncr] = concurrentMerkleTreeHeaderBeet.deserialize(buffer); + offset = offsetIncr; + + // Only 1 version available + if (versionedHeader.header.__kind !== 'V1') { + throw Error(`Header has unsupported version: ${versionedHeader.header.__kind}`); + } + const header = versionedHeader.header.fields[0]; + const [tree, offsetIncr2] = concurrentMerkleTreeBeetFactory(header.maxDepth, header.maxBufferSize).deserialize( + buffer, + offset, + ); + offset = offsetIncr2; + + const canopyDepth = getCanopyDepth(buffer.byteLength - offset); + let canopy: Canopy = { + canopyBytes: [], + }; + if (canopyDepth !== 0) { + const [deserializedCanopy, offsetIncr3] = canopyBeetFactory(canopyDepth).deserialize(buffer, offset); + canopy = deserializedCanopy; + offset = offsetIncr3; + } + + if (buffer.byteLength !== offset) { + throw new Error('Failed to process whole buffer when deserializing Merkle Account Data'); + } + return new ConcurrentMerkleTreeAccount(versionedHeader, tree, canopy); +} + +/** + * Calculate the expected size of an ConcurrentMerkleTreeAccount + * @param maxDepth + * @param maxBufferSize + * @param canopyDepth + * @param headerVersion + * @returns + */ +export function getConcurrentMerkleTreeAccountSize( + maxDepth: number, + maxBufferSize: number, + canopyDepth?: number, + headerVersion = 'V1', +): number { + if (headerVersion != 'V1') { + throw Error('Unsupported header version'); + } + + // The additional 2 bytes are needed for + // - the account disciminant (1 byte) + // - the header version (1 byte) + return ( + 2 + + concurrentMerkleTreeHeaderDataV1Beet.byteSize + + concurrentMerkleTreeBeetFactory(maxDepth, maxBufferSize).byteSize + + (canopyDepth ? canopyBeetFactory(canopyDepth).byteSize : 0) + ); +} diff --git a/account-compression/sdk/src/accounts/index.ts b/account-compression/sdk/src/accounts/index.ts new file mode 100644 index 00000000000..ee78e898d92 --- /dev/null +++ b/account-compression/sdk/src/accounts/index.ts @@ -0,0 +1 @@ +export * from './ConcurrentMerkleTreeAccount'; diff --git a/account-compression/sdk/src/constants/index.ts b/account-compression/sdk/src/constants/index.ts new file mode 100644 index 00000000000..c5f70de210e --- /dev/null +++ b/account-compression/sdk/src/constants/index.ts @@ -0,0 +1,97 @@ +import { PublicKey } from '@solana/web3.js'; + +export const SPL_NOOP_ADDRESS = 'noopb9bkMVfRPU8AsbpTUg8AQkHtKwMYZiFUjNRtMmV'; +export const SPL_NOOP_PROGRAM_ID = new PublicKey(SPL_NOOP_ADDRESS); + +/** + * DepthSizePair is a valid (`maxDepth`, `maxBufferSize`) tuple for an SPL ConcurrentMerkleTree + * Only the tuples listed in {@link ALL_DEPTH_SIZE_PAIRS} are valid for + * creating a new {@link ConcurrentMerkleTreeAccount}. + */ +export type DepthSizePair = { + maxBufferSize: number; + maxDepth: number; +}; + +const allPairs: number[][] = [ + [3, 8], + [5, 8], + [6, 16], + [7, 16], + [8, 16], + [9, 16], + [10, 32], + [11, 32], + [12, 32], + [13, 32], + [14, 64], + [14, 256], + [14, 1024], + [14, 2048], + [15, 64], + [16, 64], + [17, 64], + [18, 64], + [19, 64], + [20, 64], + [20, 256], + [20, 1024], + [20, 2048], + [24, 64], + [24, 256], + [24, 512], + [24, 1024], + [24, 2048], + [26, 512], + [26, 1024], + [26, 2048], + [30, 512], + [30, 1024], + [30, 2048], +]; + +/** + * Valid pairs for creating a new {@link ConcurrentMerkleTreeAccount} + */ +export const ALL_DEPTH_SIZE_PAIRS: ValidDepthSizePair[] = allPairs.map(pair => { + return { + maxBufferSize: pair[1], + maxDepth: pair[0], + } as ValidDepthSizePair; +}); + +export type ValidDepthSizePair = + | { maxBufferSize: 8; maxDepth: 3 } + | { maxBufferSize: 8; maxDepth: 5 } + | { maxBufferSize: 16; maxDepth: 6 } + | { maxBufferSize: 16; maxDepth: 7 } + | { maxBufferSize: 16; maxDepth: 8 } + | { maxBufferSize: 16; maxDepth: 9 } + | { maxBufferSize: 32; maxDepth: 10 } + | { maxBufferSize: 32; maxDepth: 11 } + | { maxBufferSize: 32; maxDepth: 12 } + | { maxBufferSize: 32; maxDepth: 13 } + | { maxBufferSize: 64; maxDepth: 14 } + | { maxBufferSize: 64; maxDepth: 15 } + | { maxBufferSize: 64; maxDepth: 16 } + | { maxBufferSize: 64; maxDepth: 17 } + | { maxBufferSize: 64; maxDepth: 18 } + | { maxBufferSize: 64; maxDepth: 19 } + | { maxBufferSize: 64; maxDepth: 20 } + | { maxBufferSize: 64; maxDepth: 24 } + | { maxBufferSize: 256; maxDepth: 14 } + | { maxBufferSize: 256; maxDepth: 20 } + | { maxBufferSize: 256; maxDepth: 24 } + | { maxBufferSize: 512; maxDepth: 24 } + | { maxBufferSize: 512; maxDepth: 26 } + | { maxBufferSize: 512; maxDepth: 30 } + | { maxBufferSize: 1024; maxDepth: 14 } + | { maxBufferSize: 1024; maxDepth: 20 } + | { maxBufferSize: 1024; maxDepth: 24 } + | { maxBufferSize: 1024; maxDepth: 26 } + | { maxBufferSize: 1024; maxDepth: 30 } + | { maxBufferSize: 2048; maxDepth: 14 } + | { maxBufferSize: 2048; maxDepth: 20 } + | { maxBufferSize: 2048; maxDepth: 24 } + | { maxBufferSize: 2048; maxDepth: 26 } + | { maxBufferSize: 2048; maxDepth: 30 }; diff --git a/account-compression/sdk/src/events/index.ts b/account-compression/sdk/src/events/index.ts new file mode 100644 index 00000000000..ac9341575d6 --- /dev/null +++ b/account-compression/sdk/src/events/index.ts @@ -0,0 +1,42 @@ +import BN from 'bn.js'; + +import { ApplicationDataEvent, ChangeLogEventV1 as CLV1 } from '../generated'; +import { accountCompressionEventBeet } from '../generated/types/AccountCompressionEvent'; +import { ChangeLogEventV1 } from '../types'; + +/** + * Helper method for indexing a {@link ConcurrentMerkleTree} + * @param data + * @returns + */ +export function deserializeChangeLogEventV1(data: Buffer): ChangeLogEventV1 { + const event = accountCompressionEventBeet.toFixedFromData(data, 0).read(data, 0); + + if (event.__kind == 'ChangeLog' && event.fields[0].__kind == 'V1') { + const changeLogV1: CLV1 = event.fields[0].fields[0]; + return { + index: changeLogV1.index, + path: changeLogV1.path, + seq: new BN.BN(changeLogV1.seq), + treeId: changeLogV1.id, + }; + } else { + throw Error('Unable to decode buffer as ChangeLogEvent V1'); + } +} + +/** + * Helper function for indexing data logged via `wrap_application_data_v1` + * @param data + * @returns + */ +export function deserializeApplicationDataEvent(data: Buffer): ApplicationDataEvent { + const event = accountCompressionEventBeet.toFixedFromData(data, 0).read(data, 0); + switch (event.__kind) { + case 'ApplicationData': { + return event.fields[0]; + } + default: + throw Error('Unable to decode buffer as ApplicationDataEvent'); + } +} diff --git a/account-compression/sdk/src/generated/errors/index.ts b/account-compression/sdk/src/generated/errors/index.ts new file mode 100644 index 00000000000..03066ebcf49 --- /dev/null +++ b/account-compression/sdk/src/generated/errors/index.ts @@ -0,0 +1,315 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +type ErrorWithCode = Error & { code: number }; +type MaybeErrorWithCode = ErrorWithCode | null | undefined; + +const createErrorFromCodeLookup: Map ErrorWithCode> = new Map(); +const createErrorFromNameLookup: Map ErrorWithCode> = new Map(); + +/** + * IncorrectLeafLength: 'Incorrect leaf length. Expected vec of 32 bytes' + * + * @category Errors + * @category generated + */ +export class IncorrectLeafLengthError extends Error { + readonly code: number = 0x1770; + readonly name: string = 'IncorrectLeafLength'; + constructor() { + super('Incorrect leaf length. Expected vec of 32 bytes'); + if (typeof Error.captureStackTrace === 'function') { + Error.captureStackTrace(this, IncorrectLeafLengthError); + } + } +} + +createErrorFromCodeLookup.set(0x1770, () => new IncorrectLeafLengthError()); +createErrorFromNameLookup.set('IncorrectLeafLength', () => new IncorrectLeafLengthError()); + +/** + * ConcurrentMerkleTreeError: 'Concurrent merkle tree error' + * + * @category Errors + * @category generated + */ +export class ConcurrentMerkleTreeErrorError extends Error { + readonly code: number = 0x1771; + readonly name: string = 'ConcurrentMerkleTreeError'; + constructor() { + super('Concurrent merkle tree error'); + if (typeof Error.captureStackTrace === 'function') { + Error.captureStackTrace(this, ConcurrentMerkleTreeErrorError); + } + } +} + +createErrorFromCodeLookup.set(0x1771, () => new ConcurrentMerkleTreeErrorError()); +createErrorFromNameLookup.set('ConcurrentMerkleTreeError', () => new ConcurrentMerkleTreeErrorError()); + +/** + * ZeroCopyError: 'Issue zero copying concurrent merkle tree data' + * + * @category Errors + * @category generated + */ +export class ZeroCopyErrorError extends Error { + readonly code: number = 0x1772; + readonly name: string = 'ZeroCopyError'; + constructor() { + super('Issue zero copying concurrent merkle tree data'); + if (typeof Error.captureStackTrace === 'function') { + Error.captureStackTrace(this, ZeroCopyErrorError); + } + } +} + +createErrorFromCodeLookup.set(0x1772, () => new ZeroCopyErrorError()); +createErrorFromNameLookup.set('ZeroCopyError', () => new ZeroCopyErrorError()); + +/** + * ConcurrentMerkleTreeConstantsError: 'An unsupported max depth or max buffer size constant was provided' + * + * @category Errors + * @category generated + */ +export class ConcurrentMerkleTreeConstantsErrorError extends Error { + readonly code: number = 0x1773; + readonly name: string = 'ConcurrentMerkleTreeConstantsError'; + constructor() { + super('An unsupported max depth or max buffer size constant was provided'); + if (typeof Error.captureStackTrace === 'function') { + Error.captureStackTrace(this, ConcurrentMerkleTreeConstantsErrorError); + } + } +} + +createErrorFromCodeLookup.set(0x1773, () => new ConcurrentMerkleTreeConstantsErrorError()); +createErrorFromNameLookup.set( + 'ConcurrentMerkleTreeConstantsError', + () => new ConcurrentMerkleTreeConstantsErrorError(), +); + +/** + * CanopyLengthMismatch: 'Expected a different byte length for the merkle tree canopy' + * + * @category Errors + * @category generated + */ +export class CanopyLengthMismatchError extends Error { + readonly code: number = 0x1774; + readonly name: string = 'CanopyLengthMismatch'; + constructor() { + super('Expected a different byte length for the merkle tree canopy'); + if (typeof Error.captureStackTrace === 'function') { + Error.captureStackTrace(this, CanopyLengthMismatchError); + } + } +} + +createErrorFromCodeLookup.set(0x1774, () => new CanopyLengthMismatchError()); +createErrorFromNameLookup.set('CanopyLengthMismatch', () => new CanopyLengthMismatchError()); + +/** + * IncorrectAuthority: 'Provided authority does not match expected tree authority' + * + * @category Errors + * @category generated + */ +export class IncorrectAuthorityError extends Error { + readonly code: number = 0x1775; + readonly name: string = 'IncorrectAuthority'; + constructor() { + super('Provided authority does not match expected tree authority'); + if (typeof Error.captureStackTrace === 'function') { + Error.captureStackTrace(this, IncorrectAuthorityError); + } + } +} + +createErrorFromCodeLookup.set(0x1775, () => new IncorrectAuthorityError()); +createErrorFromNameLookup.set('IncorrectAuthority', () => new IncorrectAuthorityError()); + +/** + * IncorrectAccountOwner: 'Account is owned by a different program, expected it to be owned by this program' + * + * @category Errors + * @category generated + */ +export class IncorrectAccountOwnerError extends Error { + readonly code: number = 0x1776; + readonly name: string = 'IncorrectAccountOwner'; + constructor() { + super('Account is owned by a different program, expected it to be owned by this program'); + if (typeof Error.captureStackTrace === 'function') { + Error.captureStackTrace(this, IncorrectAccountOwnerError); + } + } +} + +createErrorFromCodeLookup.set(0x1776, () => new IncorrectAccountOwnerError()); +createErrorFromNameLookup.set('IncorrectAccountOwner', () => new IncorrectAccountOwnerError()); + +/** + * IncorrectAccountType: 'Account provided has incorrect account type' + * + * @category Errors + * @category generated + */ +export class IncorrectAccountTypeError extends Error { + readonly code: number = 0x1777; + readonly name: string = 'IncorrectAccountType'; + constructor() { + super('Account provided has incorrect account type'); + if (typeof Error.captureStackTrace === 'function') { + Error.captureStackTrace(this, IncorrectAccountTypeError); + } + } +} + +createErrorFromCodeLookup.set(0x1777, () => new IncorrectAccountTypeError()); +createErrorFromNameLookup.set('IncorrectAccountType', () => new IncorrectAccountTypeError()); + +/** + * LeafIndexOutOfBounds: 'Leaf index of concurrent merkle tree is out of bounds' + * + * @category Errors + * @category generated + */ +export class LeafIndexOutOfBoundsError extends Error { + readonly code: number = 0x1778; + readonly name: string = 'LeafIndexOutOfBounds'; + constructor() { + super('Leaf index of concurrent merkle tree is out of bounds'); + if (typeof Error.captureStackTrace === 'function') { + Error.captureStackTrace(this, LeafIndexOutOfBoundsError); + } + } +} + +createErrorFromCodeLookup.set(0x1778, () => new LeafIndexOutOfBoundsError()); +createErrorFromNameLookup.set('LeafIndexOutOfBounds', () => new LeafIndexOutOfBoundsError()); + +/** + * CanopyNotAllocated: 'Tree was initialized without allocating space for the canopy' + * + * @category Errors + * @category generated + */ +export class CanopyNotAllocatedError extends Error { + readonly code: number = 0x1779; + readonly name: string = 'CanopyNotAllocated'; + constructor() { + super('Tree was initialized without allocating space for the canopy'); + if (typeof Error.captureStackTrace === 'function') { + Error.captureStackTrace(this, CanopyNotAllocatedError); + } + } +} + +createErrorFromCodeLookup.set(0x1779, () => new CanopyNotAllocatedError()); +createErrorFromNameLookup.set('CanopyNotAllocated', () => new CanopyNotAllocatedError()); + +/** + * TreeAlreadyInitialized: 'Tree was already initialized' + * + * @category Errors + * @category generated + */ +export class TreeAlreadyInitializedError extends Error { + readonly code: number = 0x177a; + readonly name: string = 'TreeAlreadyInitialized'; + constructor() { + super('Tree was already initialized'); + if (typeof Error.captureStackTrace === 'function') { + Error.captureStackTrace(this, TreeAlreadyInitializedError); + } + } +} + +createErrorFromCodeLookup.set(0x177a, () => new TreeAlreadyInitializedError()); +createErrorFromNameLookup.set('TreeAlreadyInitialized', () => new TreeAlreadyInitializedError()); + +/** + * BatchNotInitialized: 'Tree header was not initialized for batch processing' + * + * @category Errors + * @category generated + */ +export class BatchNotInitializedError extends Error { + readonly code: number = 0x177b; + readonly name: string = 'BatchNotInitialized'; + constructor() { + super('Tree header was not initialized for batch processing'); + if (typeof Error.captureStackTrace === 'function') { + Error.captureStackTrace(this, BatchNotInitializedError); + } + } +} + +createErrorFromCodeLookup.set(0x177b, () => new BatchNotInitializedError()); +createErrorFromNameLookup.set('BatchNotInitialized', () => new BatchNotInitializedError()); + +/** + * CanopyRootMismatch: 'Canopy root does not match the root of the tree' + * + * @category Errors + * @category generated + */ +export class CanopyRootMismatchError extends Error { + readonly code: number = 0x177c; + readonly name: string = 'CanopyRootMismatch'; + constructor() { + super('Canopy root does not match the root of the tree'); + if (typeof Error.captureStackTrace === 'function') { + Error.captureStackTrace(this, CanopyRootMismatchError); + } + } +} + +createErrorFromCodeLookup.set(0x177c, () => new CanopyRootMismatchError()); +createErrorFromNameLookup.set('CanopyRootMismatch', () => new CanopyRootMismatchError()); + +/** + * CanopyRightmostLeafMismatch: 'Canopy contains nodes to the right of the rightmost leaf of the tree' + * + * @category Errors + * @category generated + */ +export class CanopyRightmostLeafMismatchError extends Error { + readonly code: number = 0x177d; + readonly name: string = 'CanopyRightmostLeafMismatch'; + constructor() { + super('Canopy contains nodes to the right of the rightmost leaf of the tree'); + if (typeof Error.captureStackTrace === 'function') { + Error.captureStackTrace(this, CanopyRightmostLeafMismatchError); + } + } +} + +createErrorFromCodeLookup.set(0x177d, () => new CanopyRightmostLeafMismatchError()); +createErrorFromNameLookup.set('CanopyRightmostLeafMismatch', () => new CanopyRightmostLeafMismatchError()); + +/** + * Attempts to resolve a custom program error from the provided error code. + * @category Errors + * @category generated + */ +export function errorFromCode(code: number): MaybeErrorWithCode { + const createError = createErrorFromCodeLookup.get(code); + return createError != null ? createError() : null; +} + +/** + * Attempts to resolve a custom program error from the provided error name, i.e. 'Unauthorized'. + * @category Errors + * @category generated + */ +export function errorFromName(name: string): MaybeErrorWithCode { + const createError = createErrorFromNameLookup.get(name); + return createError != null ? createError() : null; +} diff --git a/account-compression/sdk/src/generated/index.ts b/account-compression/sdk/src/generated/index.ts new file mode 100644 index 00000000000..600796d9257 --- /dev/null +++ b/account-compression/sdk/src/generated/index.ts @@ -0,0 +1,20 @@ +import { PublicKey } from '@solana/web3.js'; +export * from './errors'; +export * from './instructions'; +export * from './types'; + +/** + * Program address + * + * @category constants + * @category generated + */ +export const PROGRAM_ADDRESS = 'cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK'; + +/** + * Program public key + * + * @category constants + * @category generated + */ +export const PROGRAM_ID = new PublicKey(PROGRAM_ADDRESS); diff --git a/account-compression/sdk/src/generated/instructions/append.ts b/account-compression/sdk/src/generated/instructions/append.ts new file mode 100644 index 00000000000..ed98ac95047 --- /dev/null +++ b/account-compression/sdk/src/generated/instructions/append.ts @@ -0,0 +1,103 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as beet from '@metaplex-foundation/beet'; +import * as web3 from '@solana/web3.js'; + +/** + * @category Instructions + * @category Append + * @category generated + */ +export type AppendInstructionArgs = { + leaf: number[] /* size: 32 */; +}; +/** + * @category Instructions + * @category Append + * @category generated + */ +export const appendStruct = new beet.BeetArgsStruct< + AppendInstructionArgs & { + instructionDiscriminator: number[] /* size: 8 */; + } +>( + [ + ['instructionDiscriminator', beet.uniformFixedSizeArray(beet.u8, 8)], + ['leaf', beet.uniformFixedSizeArray(beet.u8, 32)], + ], + 'AppendInstructionArgs', +); +/** + * Accounts required by the _append_ instruction + * + * @property [_writable_] merkleTree + * @property [**signer**] authority + * @property [] noop + * @category Instructions + * @category Append + * @category generated + */ +export type AppendInstructionAccounts = { + anchorRemainingAccounts?: web3.AccountMeta[]; + authority: web3.PublicKey; + merkleTree: web3.PublicKey; + noop: web3.PublicKey; +}; + +export const appendInstructionDiscriminator = [149, 120, 18, 222, 236, 225, 88, 203]; + +/** + * Creates a _Append_ instruction. + * + * @param accounts that will be accessed while the instruction is processed + * @param args to provide as instruction data to the program + * + * @category Instructions + * @category Append + * @category generated + */ +export function createAppendInstruction( + accounts: AppendInstructionAccounts, + args: AppendInstructionArgs, + programId = new web3.PublicKey('cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK'), +) { + const [data] = appendStruct.serialize({ + instructionDiscriminator: appendInstructionDiscriminator, + ...args, + }); + const keys: web3.AccountMeta[] = [ + { + isSigner: false, + isWritable: true, + pubkey: accounts.merkleTree, + }, + { + isSigner: true, + isWritable: false, + pubkey: accounts.authority, + }, + { + isSigner: false, + isWritable: false, + pubkey: accounts.noop, + }, + ]; + + if (accounts.anchorRemainingAccounts != null) { + for (const acc of accounts.anchorRemainingAccounts) { + keys.push(acc); + } + } + + const ix = new web3.TransactionInstruction({ + data, + keys, + programId, + }); + return ix; +} diff --git a/account-compression/sdk/src/generated/instructions/appendCanopyNodes.ts b/account-compression/sdk/src/generated/instructions/appendCanopyNodes.ts new file mode 100644 index 00000000000..5cf4ddff765 --- /dev/null +++ b/account-compression/sdk/src/generated/instructions/appendCanopyNodes.ts @@ -0,0 +1,105 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as beet from '@metaplex-foundation/beet'; +import * as web3 from '@solana/web3.js'; + +/** + * @category Instructions + * @category AppendCanopyNodes + * @category generated + */ +export type AppendCanopyNodesInstructionArgs = { + canopyNodes: number[] /* size: 32 */[]; + startIndex: number; +}; +/** + * @category Instructions + * @category AppendCanopyNodes + * @category generated + */ +export const appendCanopyNodesStruct = new beet.FixableBeetArgsStruct< + AppendCanopyNodesInstructionArgs & { + instructionDiscriminator: number[] /* size: 8 */; + } +>( + [ + ['instructionDiscriminator', beet.uniformFixedSizeArray(beet.u8, 8)], + ['startIndex', beet.u32], + ['canopyNodes', beet.array(beet.uniformFixedSizeArray(beet.u8, 32))], + ], + 'AppendCanopyNodesInstructionArgs', +); +/** + * Accounts required by the _appendCanopyNodes_ instruction + * + * @property [_writable_] merkleTree + * @property [**signer**] authority + * @property [] noop + * @category Instructions + * @category AppendCanopyNodes + * @category generated + */ +export type AppendCanopyNodesInstructionAccounts = { + anchorRemainingAccounts?: web3.AccountMeta[]; + authority: web3.PublicKey; + merkleTree: web3.PublicKey; + noop: web3.PublicKey; +}; + +export const appendCanopyNodesInstructionDiscriminator = [139, 155, 238, 167, 11, 243, 132, 205]; + +/** + * Creates a _AppendCanopyNodes_ instruction. + * + * @param accounts that will be accessed while the instruction is processed + * @param args to provide as instruction data to the program + * + * @category Instructions + * @category AppendCanopyNodes + * @category generated + */ +export function createAppendCanopyNodesInstruction( + accounts: AppendCanopyNodesInstructionAccounts, + args: AppendCanopyNodesInstructionArgs, + programId = new web3.PublicKey('cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK'), +) { + const [data] = appendCanopyNodesStruct.serialize({ + instructionDiscriminator: appendCanopyNodesInstructionDiscriminator, + ...args, + }); + const keys: web3.AccountMeta[] = [ + { + isSigner: false, + isWritable: true, + pubkey: accounts.merkleTree, + }, + { + isSigner: true, + isWritable: false, + pubkey: accounts.authority, + }, + { + isSigner: false, + isWritable: false, + pubkey: accounts.noop, + }, + ]; + + if (accounts.anchorRemainingAccounts != null) { + for (const acc of accounts.anchorRemainingAccounts) { + keys.push(acc); + } + } + + const ix = new web3.TransactionInstruction({ + data, + keys, + programId, + }); + return ix; +} diff --git a/account-compression/sdk/src/generated/instructions/closeEmptyTree.ts b/account-compression/sdk/src/generated/instructions/closeEmptyTree.ts new file mode 100644 index 00000000000..9de760f51e3 --- /dev/null +++ b/account-compression/sdk/src/generated/instructions/closeEmptyTree.ts @@ -0,0 +1,83 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as beet from '@metaplex-foundation/beet'; +import * as web3 from '@solana/web3.js'; + +/** + * @category Instructions + * @category CloseEmptyTree + * @category generated + */ +export const closeEmptyTreeStruct = new beet.BeetArgsStruct<{ + instructionDiscriminator: number[] /* size: 8 */; +}>([['instructionDiscriminator', beet.uniformFixedSizeArray(beet.u8, 8)]], 'CloseEmptyTreeInstructionArgs'); +/** + * Accounts required by the _closeEmptyTree_ instruction + * + * @property [_writable_] merkleTree + * @property [**signer**] authority + * @property [_writable_] recipient + * @category Instructions + * @category CloseEmptyTree + * @category generated + */ +export type CloseEmptyTreeInstructionAccounts = { + anchorRemainingAccounts?: web3.AccountMeta[]; + authority: web3.PublicKey; + merkleTree: web3.PublicKey; + recipient: web3.PublicKey; +}; + +export const closeEmptyTreeInstructionDiscriminator = [50, 14, 219, 107, 78, 103, 16, 103]; + +/** + * Creates a _CloseEmptyTree_ instruction. + * + * @param accounts that will be accessed while the instruction is processed + * @category Instructions + * @category CloseEmptyTree + * @category generated + */ +export function createCloseEmptyTreeInstruction( + accounts: CloseEmptyTreeInstructionAccounts, + programId = new web3.PublicKey('cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK'), +) { + const [data] = closeEmptyTreeStruct.serialize({ + instructionDiscriminator: closeEmptyTreeInstructionDiscriminator, + }); + const keys: web3.AccountMeta[] = [ + { + isSigner: false, + isWritable: true, + pubkey: accounts.merkleTree, + }, + { + isSigner: true, + isWritable: false, + pubkey: accounts.authority, + }, + { + isSigner: false, + isWritable: true, + pubkey: accounts.recipient, + }, + ]; + + if (accounts.anchorRemainingAccounts != null) { + for (const acc of accounts.anchorRemainingAccounts) { + keys.push(acc); + } + } + + const ix = new web3.TransactionInstruction({ + data, + keys, + programId, + }); + return ix; +} diff --git a/account-compression/sdk/src/generated/instructions/index.ts b/account-compression/sdk/src/generated/instructions/index.ts new file mode 100644 index 00000000000..10605ab4704 --- /dev/null +++ b/account-compression/sdk/src/generated/instructions/index.ts @@ -0,0 +1,10 @@ +export * from './append'; +export * from './appendCanopyNodes'; +export * from './closeEmptyTree'; +export * from './initEmptyMerkleTree'; +export * from './initPreparedTreeWithRoot'; +export * from './insertOrAppend'; +export * from './prepareBatchMerkleTree'; +export * from './replaceLeaf'; +export * from './transferAuthority'; +export * from './verifyLeaf'; diff --git a/account-compression/sdk/src/generated/instructions/initEmptyMerkleTree.ts b/account-compression/sdk/src/generated/instructions/initEmptyMerkleTree.ts new file mode 100644 index 00000000000..8d745acf786 --- /dev/null +++ b/account-compression/sdk/src/generated/instructions/initEmptyMerkleTree.ts @@ -0,0 +1,105 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as beet from '@metaplex-foundation/beet'; +import * as web3 from '@solana/web3.js'; + +/** + * @category Instructions + * @category InitEmptyMerkleTree + * @category generated + */ +export type InitEmptyMerkleTreeInstructionArgs = { + maxBufferSize: number; + maxDepth: number; +}; +/** + * @category Instructions + * @category InitEmptyMerkleTree + * @category generated + */ +export const initEmptyMerkleTreeStruct = new beet.BeetArgsStruct< + InitEmptyMerkleTreeInstructionArgs & { + instructionDiscriminator: number[] /* size: 8 */; + } +>( + [ + ['instructionDiscriminator', beet.uniformFixedSizeArray(beet.u8, 8)], + ['maxDepth', beet.u32], + ['maxBufferSize', beet.u32], + ], + 'InitEmptyMerkleTreeInstructionArgs', +); +/** + * Accounts required by the _initEmptyMerkleTree_ instruction + * + * @property [_writable_] merkleTree + * @property [**signer**] authority + * @property [] noop + * @category Instructions + * @category InitEmptyMerkleTree + * @category generated + */ +export type InitEmptyMerkleTreeInstructionAccounts = { + anchorRemainingAccounts?: web3.AccountMeta[]; + authority: web3.PublicKey; + merkleTree: web3.PublicKey; + noop: web3.PublicKey; +}; + +export const initEmptyMerkleTreeInstructionDiscriminator = [191, 11, 119, 7, 180, 107, 220, 110]; + +/** + * Creates a _InitEmptyMerkleTree_ instruction. + * + * @param accounts that will be accessed while the instruction is processed + * @param args to provide as instruction data to the program + * + * @category Instructions + * @category InitEmptyMerkleTree + * @category generated + */ +export function createInitEmptyMerkleTreeInstruction( + accounts: InitEmptyMerkleTreeInstructionAccounts, + args: InitEmptyMerkleTreeInstructionArgs, + programId = new web3.PublicKey('cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK'), +) { + const [data] = initEmptyMerkleTreeStruct.serialize({ + instructionDiscriminator: initEmptyMerkleTreeInstructionDiscriminator, + ...args, + }); + const keys: web3.AccountMeta[] = [ + { + isSigner: false, + isWritable: true, + pubkey: accounts.merkleTree, + }, + { + isSigner: true, + isWritable: false, + pubkey: accounts.authority, + }, + { + isSigner: false, + isWritable: false, + pubkey: accounts.noop, + }, + ]; + + if (accounts.anchorRemainingAccounts != null) { + for (const acc of accounts.anchorRemainingAccounts) { + keys.push(acc); + } + } + + const ix = new web3.TransactionInstruction({ + data, + keys, + programId, + }); + return ix; +} diff --git a/account-compression/sdk/src/generated/instructions/initPreparedTreeWithRoot.ts b/account-compression/sdk/src/generated/instructions/initPreparedTreeWithRoot.ts new file mode 100644 index 00000000000..b729a877a95 --- /dev/null +++ b/account-compression/sdk/src/generated/instructions/initPreparedTreeWithRoot.ts @@ -0,0 +1,107 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as beet from '@metaplex-foundation/beet'; +import * as web3 from '@solana/web3.js'; + +/** + * @category Instructions + * @category InitPreparedTreeWithRoot + * @category generated + */ +export type InitPreparedTreeWithRootInstructionArgs = { + rightmostIndex: number; + rightmostLeaf: number[] /* size: 32 */; + root: number[] /* size: 32 */; +}; +/** + * @category Instructions + * @category InitPreparedTreeWithRoot + * @category generated + */ +export const initPreparedTreeWithRootStruct = new beet.BeetArgsStruct< + InitPreparedTreeWithRootInstructionArgs & { + instructionDiscriminator: number[] /* size: 8 */; + } +>( + [ + ['instructionDiscriminator', beet.uniformFixedSizeArray(beet.u8, 8)], + ['root', beet.uniformFixedSizeArray(beet.u8, 32)], + ['rightmostLeaf', beet.uniformFixedSizeArray(beet.u8, 32)], + ['rightmostIndex', beet.u32], + ], + 'InitPreparedTreeWithRootInstructionArgs', +); +/** + * Accounts required by the _initPreparedTreeWithRoot_ instruction + * + * @property [_writable_] merkleTree + * @property [**signer**] authority + * @property [] noop + * @category Instructions + * @category InitPreparedTreeWithRoot + * @category generated + */ +export type InitPreparedTreeWithRootInstructionAccounts = { + anchorRemainingAccounts?: web3.AccountMeta[]; + authority: web3.PublicKey; + merkleTree: web3.PublicKey; + noop: web3.PublicKey; +}; + +export const initPreparedTreeWithRootInstructionDiscriminator = [218, 248, 192, 55, 91, 205, 122, 10]; + +/** + * Creates a _InitPreparedTreeWithRoot_ instruction. + * + * @param accounts that will be accessed while the instruction is processed + * @param args to provide as instruction data to the program + * + * @category Instructions + * @category InitPreparedTreeWithRoot + * @category generated + */ +export function createInitPreparedTreeWithRootInstruction( + accounts: InitPreparedTreeWithRootInstructionAccounts, + args: InitPreparedTreeWithRootInstructionArgs, + programId = new web3.PublicKey('cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK'), +) { + const [data] = initPreparedTreeWithRootStruct.serialize({ + instructionDiscriminator: initPreparedTreeWithRootInstructionDiscriminator, + ...args, + }); + const keys: web3.AccountMeta[] = [ + { + isSigner: false, + isWritable: true, + pubkey: accounts.merkleTree, + }, + { + isSigner: true, + isWritable: false, + pubkey: accounts.authority, + }, + { + isSigner: false, + isWritable: false, + pubkey: accounts.noop, + }, + ]; + + if (accounts.anchorRemainingAccounts != null) { + for (const acc of accounts.anchorRemainingAccounts) { + keys.push(acc); + } + } + + const ix = new web3.TransactionInstruction({ + data, + keys, + programId, + }); + return ix; +} diff --git a/account-compression/sdk/src/generated/instructions/insertOrAppend.ts b/account-compression/sdk/src/generated/instructions/insertOrAppend.ts new file mode 100644 index 00000000000..ae00b328563 --- /dev/null +++ b/account-compression/sdk/src/generated/instructions/insertOrAppend.ts @@ -0,0 +1,107 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as beet from '@metaplex-foundation/beet'; +import * as web3 from '@solana/web3.js'; + +/** + * @category Instructions + * @category InsertOrAppend + * @category generated + */ +export type InsertOrAppendInstructionArgs = { + index: number; + leaf: number[] /* size: 32 */; + root: number[] /* size: 32 */; +}; +/** + * @category Instructions + * @category InsertOrAppend + * @category generated + */ +export const insertOrAppendStruct = new beet.BeetArgsStruct< + InsertOrAppendInstructionArgs & { + instructionDiscriminator: number[] /* size: 8 */; + } +>( + [ + ['instructionDiscriminator', beet.uniformFixedSizeArray(beet.u8, 8)], + ['root', beet.uniformFixedSizeArray(beet.u8, 32)], + ['leaf', beet.uniformFixedSizeArray(beet.u8, 32)], + ['index', beet.u32], + ], + 'InsertOrAppendInstructionArgs', +); +/** + * Accounts required by the _insertOrAppend_ instruction + * + * @property [_writable_] merkleTree + * @property [**signer**] authority + * @property [] noop + * @category Instructions + * @category InsertOrAppend + * @category generated + */ +export type InsertOrAppendInstructionAccounts = { + anchorRemainingAccounts?: web3.AccountMeta[]; + authority: web3.PublicKey; + merkleTree: web3.PublicKey; + noop: web3.PublicKey; +}; + +export const insertOrAppendInstructionDiscriminator = [6, 42, 50, 190, 51, 109, 178, 168]; + +/** + * Creates a _InsertOrAppend_ instruction. + * + * @param accounts that will be accessed while the instruction is processed + * @param args to provide as instruction data to the program + * + * @category Instructions + * @category InsertOrAppend + * @category generated + */ +export function createInsertOrAppendInstruction( + accounts: InsertOrAppendInstructionAccounts, + args: InsertOrAppendInstructionArgs, + programId = new web3.PublicKey('cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK'), +) { + const [data] = insertOrAppendStruct.serialize({ + instructionDiscriminator: insertOrAppendInstructionDiscriminator, + ...args, + }); + const keys: web3.AccountMeta[] = [ + { + isSigner: false, + isWritable: true, + pubkey: accounts.merkleTree, + }, + { + isSigner: true, + isWritable: false, + pubkey: accounts.authority, + }, + { + isSigner: false, + isWritable: false, + pubkey: accounts.noop, + }, + ]; + + if (accounts.anchorRemainingAccounts != null) { + for (const acc of accounts.anchorRemainingAccounts) { + keys.push(acc); + } + } + + const ix = new web3.TransactionInstruction({ + data, + keys, + programId, + }); + return ix; +} diff --git a/account-compression/sdk/src/generated/instructions/prepareBatchMerkleTree.ts b/account-compression/sdk/src/generated/instructions/prepareBatchMerkleTree.ts new file mode 100644 index 00000000000..0d5aa007db4 --- /dev/null +++ b/account-compression/sdk/src/generated/instructions/prepareBatchMerkleTree.ts @@ -0,0 +1,105 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as beet from '@metaplex-foundation/beet'; +import * as web3 from '@solana/web3.js'; + +/** + * @category Instructions + * @category PrepareBatchMerkleTree + * @category generated + */ +export type PrepareBatchMerkleTreeInstructionArgs = { + maxBufferSize: number; + maxDepth: number; +}; +/** + * @category Instructions + * @category PrepareBatchMerkleTree + * @category generated + */ +export const prepareBatchMerkleTreeStruct = new beet.BeetArgsStruct< + PrepareBatchMerkleTreeInstructionArgs & { + instructionDiscriminator: number[] /* size: 8 */; + } +>( + [ + ['instructionDiscriminator', beet.uniformFixedSizeArray(beet.u8, 8)], + ['maxDepth', beet.u32], + ['maxBufferSize', beet.u32], + ], + 'PrepareBatchMerkleTreeInstructionArgs', +); +/** + * Accounts required by the _prepareBatchMerkleTree_ instruction + * + * @property [_writable_] merkleTree + * @property [**signer**] authority + * @property [] noop + * @category Instructions + * @category PrepareBatchMerkleTree + * @category generated + */ +export type PrepareBatchMerkleTreeInstructionAccounts = { + anchorRemainingAccounts?: web3.AccountMeta[]; + authority: web3.PublicKey; + merkleTree: web3.PublicKey; + noop: web3.PublicKey; +}; + +export const prepareBatchMerkleTreeInstructionDiscriminator = [230, 124, 120, 196, 249, 134, 199, 128]; + +/** + * Creates a _PrepareBatchMerkleTree_ instruction. + * + * @param accounts that will be accessed while the instruction is processed + * @param args to provide as instruction data to the program + * + * @category Instructions + * @category PrepareBatchMerkleTree + * @category generated + */ +export function createPrepareBatchMerkleTreeInstruction( + accounts: PrepareBatchMerkleTreeInstructionAccounts, + args: PrepareBatchMerkleTreeInstructionArgs, + programId = new web3.PublicKey('cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK'), +) { + const [data] = prepareBatchMerkleTreeStruct.serialize({ + instructionDiscriminator: prepareBatchMerkleTreeInstructionDiscriminator, + ...args, + }); + const keys: web3.AccountMeta[] = [ + { + isSigner: false, + isWritable: true, + pubkey: accounts.merkleTree, + }, + { + isSigner: true, + isWritable: false, + pubkey: accounts.authority, + }, + { + isSigner: false, + isWritable: false, + pubkey: accounts.noop, + }, + ]; + + if (accounts.anchorRemainingAccounts != null) { + for (const acc of accounts.anchorRemainingAccounts) { + keys.push(acc); + } + } + + const ix = new web3.TransactionInstruction({ + data, + keys, + programId, + }); + return ix; +} diff --git a/account-compression/sdk/src/generated/instructions/replaceLeaf.ts b/account-compression/sdk/src/generated/instructions/replaceLeaf.ts new file mode 100644 index 00000000000..57d7ebad18a --- /dev/null +++ b/account-compression/sdk/src/generated/instructions/replaceLeaf.ts @@ -0,0 +1,109 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as beet from '@metaplex-foundation/beet'; +import * as web3 from '@solana/web3.js'; + +/** + * @category Instructions + * @category ReplaceLeaf + * @category generated + */ +export type ReplaceLeafInstructionArgs = { + index: number; + newLeaf: number[] /* size: 32 */; + previousLeaf: number[] /* size: 32 */; + root: number[] /* size: 32 */; +}; +/** + * @category Instructions + * @category ReplaceLeaf + * @category generated + */ +export const replaceLeafStruct = new beet.BeetArgsStruct< + ReplaceLeafInstructionArgs & { + instructionDiscriminator: number[] /* size: 8 */; + } +>( + [ + ['instructionDiscriminator', beet.uniformFixedSizeArray(beet.u8, 8)], + ['root', beet.uniformFixedSizeArray(beet.u8, 32)], + ['previousLeaf', beet.uniformFixedSizeArray(beet.u8, 32)], + ['newLeaf', beet.uniformFixedSizeArray(beet.u8, 32)], + ['index', beet.u32], + ], + 'ReplaceLeafInstructionArgs', +); +/** + * Accounts required by the _replaceLeaf_ instruction + * + * @property [_writable_] merkleTree + * @property [**signer**] authority + * @property [] noop + * @category Instructions + * @category ReplaceLeaf + * @category generated + */ +export type ReplaceLeafInstructionAccounts = { + anchorRemainingAccounts?: web3.AccountMeta[]; + authority: web3.PublicKey; + merkleTree: web3.PublicKey; + noop: web3.PublicKey; +}; + +export const replaceLeafInstructionDiscriminator = [204, 165, 76, 100, 73, 147, 0, 128]; + +/** + * Creates a _ReplaceLeaf_ instruction. + * + * @param accounts that will be accessed while the instruction is processed + * @param args to provide as instruction data to the program + * + * @category Instructions + * @category ReplaceLeaf + * @category generated + */ +export function createReplaceLeafInstruction( + accounts: ReplaceLeafInstructionAccounts, + args: ReplaceLeafInstructionArgs, + programId = new web3.PublicKey('cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK'), +) { + const [data] = replaceLeafStruct.serialize({ + instructionDiscriminator: replaceLeafInstructionDiscriminator, + ...args, + }); + const keys: web3.AccountMeta[] = [ + { + isSigner: false, + isWritable: true, + pubkey: accounts.merkleTree, + }, + { + isSigner: true, + isWritable: false, + pubkey: accounts.authority, + }, + { + isSigner: false, + isWritable: false, + pubkey: accounts.noop, + }, + ]; + + if (accounts.anchorRemainingAccounts != null) { + for (const acc of accounts.anchorRemainingAccounts) { + keys.push(acc); + } + } + + const ix = new web3.TransactionInstruction({ + data, + keys, + programId, + }); + return ix; +} diff --git a/account-compression/sdk/src/generated/instructions/transferAuthority.ts b/account-compression/sdk/src/generated/instructions/transferAuthority.ts new file mode 100644 index 00000000000..d531b12abab --- /dev/null +++ b/account-compression/sdk/src/generated/instructions/transferAuthority.ts @@ -0,0 +1,97 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as beet from '@metaplex-foundation/beet'; +import * as beetSolana from '@metaplex-foundation/beet-solana'; +import * as web3 from '@solana/web3.js'; + +/** + * @category Instructions + * @category TransferAuthority + * @category generated + */ +export type TransferAuthorityInstructionArgs = { + newAuthority: web3.PublicKey; +}; +/** + * @category Instructions + * @category TransferAuthority + * @category generated + */ +export const transferAuthorityStruct = new beet.BeetArgsStruct< + TransferAuthorityInstructionArgs & { + instructionDiscriminator: number[] /* size: 8 */; + } +>( + [ + ['instructionDiscriminator', beet.uniformFixedSizeArray(beet.u8, 8)], + ['newAuthority', beetSolana.publicKey], + ], + 'TransferAuthorityInstructionArgs', +); +/** + * Accounts required by the _transferAuthority_ instruction + * + * @property [_writable_] merkleTree + * @property [**signer**] authority + * @category Instructions + * @category TransferAuthority + * @category generated + */ +export type TransferAuthorityInstructionAccounts = { + anchorRemainingAccounts?: web3.AccountMeta[]; + authority: web3.PublicKey; + merkleTree: web3.PublicKey; +}; + +export const transferAuthorityInstructionDiscriminator = [48, 169, 76, 72, 229, 180, 55, 161]; + +/** + * Creates a _TransferAuthority_ instruction. + * + * @param accounts that will be accessed while the instruction is processed + * @param args to provide as instruction data to the program + * + * @category Instructions + * @category TransferAuthority + * @category generated + */ +export function createTransferAuthorityInstruction( + accounts: TransferAuthorityInstructionAccounts, + args: TransferAuthorityInstructionArgs, + programId = new web3.PublicKey('cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK'), +) { + const [data] = transferAuthorityStruct.serialize({ + instructionDiscriminator: transferAuthorityInstructionDiscriminator, + ...args, + }); + const keys: web3.AccountMeta[] = [ + { + isSigner: false, + isWritable: true, + pubkey: accounts.merkleTree, + }, + { + isSigner: true, + isWritable: false, + pubkey: accounts.authority, + }, + ]; + + if (accounts.anchorRemainingAccounts != null) { + for (const acc of accounts.anchorRemainingAccounts) { + keys.push(acc); + } + } + + const ix = new web3.TransactionInstruction({ + data, + keys, + programId, + }); + return ix; +} diff --git a/account-compression/sdk/src/generated/instructions/verifyLeaf.ts b/account-compression/sdk/src/generated/instructions/verifyLeaf.ts new file mode 100644 index 00000000000..988b7e8877a --- /dev/null +++ b/account-compression/sdk/src/generated/instructions/verifyLeaf.ts @@ -0,0 +1,93 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as beet from '@metaplex-foundation/beet'; +import * as web3 from '@solana/web3.js'; + +/** + * @category Instructions + * @category VerifyLeaf + * @category generated + */ +export type VerifyLeafInstructionArgs = { + index: number; + leaf: number[] /* size: 32 */; + root: number[] /* size: 32 */; +}; +/** + * @category Instructions + * @category VerifyLeaf + * @category generated + */ +export const verifyLeafStruct = new beet.BeetArgsStruct< + VerifyLeafInstructionArgs & { + instructionDiscriminator: number[] /* size: 8 */; + } +>( + [ + ['instructionDiscriminator', beet.uniformFixedSizeArray(beet.u8, 8)], + ['root', beet.uniformFixedSizeArray(beet.u8, 32)], + ['leaf', beet.uniformFixedSizeArray(beet.u8, 32)], + ['index', beet.u32], + ], + 'VerifyLeafInstructionArgs', +); +/** + * Accounts required by the _verifyLeaf_ instruction + * + * @property [] merkleTree + * @category Instructions + * @category VerifyLeaf + * @category generated + */ +export type VerifyLeafInstructionAccounts = { + anchorRemainingAccounts?: web3.AccountMeta[]; + merkleTree: web3.PublicKey; +}; + +export const verifyLeafInstructionDiscriminator = [124, 220, 22, 223, 104, 10, 250, 224]; + +/** + * Creates a _VerifyLeaf_ instruction. + * + * @param accounts that will be accessed while the instruction is processed + * @param args to provide as instruction data to the program + * + * @category Instructions + * @category VerifyLeaf + * @category generated + */ +export function createVerifyLeafInstruction( + accounts: VerifyLeafInstructionAccounts, + args: VerifyLeafInstructionArgs, + programId = new web3.PublicKey('cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK'), +) { + const [data] = verifyLeafStruct.serialize({ + instructionDiscriminator: verifyLeafInstructionDiscriminator, + ...args, + }); + const keys: web3.AccountMeta[] = [ + { + isSigner: false, + isWritable: false, + pubkey: accounts.merkleTree, + }, + ]; + + if (accounts.anchorRemainingAccounts != null) { + for (const acc of accounts.anchorRemainingAccounts) { + keys.push(acc); + } + } + + const ix = new web3.TransactionInstruction({ + data, + keys, + programId, + }); + return ix; +} diff --git a/account-compression/sdk/src/generated/types/AccountCompressionEvent.ts b/account-compression/sdk/src/generated/types/AccountCompressionEvent.ts new file mode 100644 index 00000000000..ee25ced07a1 --- /dev/null +++ b/account-compression/sdk/src/generated/types/AccountCompressionEvent.ts @@ -0,0 +1,65 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as beet from '@metaplex-foundation/beet'; + +import { ApplicationDataEvent, applicationDataEventBeet } from './ApplicationDataEvent'; +import { ChangeLogEvent, changeLogEventBeet } from './ChangeLogEvent'; +/** + * This type is used to derive the {@link AccountCompressionEvent} type as well as the de/serializer. + * However don't refer to it in your code but use the {@link AccountCompressionEvent} type instead. + * + * @category userTypes + * @category enums + * @category generated + * @private + */ +export type AccountCompressionEventRecord = { + ApplicationData: { fields: [ApplicationDataEvent] }; + ChangeLog: { fields: [ChangeLogEvent] }; +}; + +/** + * Union type respresenting the AccountCompressionEvent data enum defined in Rust. + * + * NOTE: that it includes a `__kind` property which allows to narrow types in + * switch/if statements. + * Additionally `isAccountCompressionEvent*` type guards are exposed below to narrow to a specific variant. + * + * @category userTypes + * @category enums + * @category generated + */ +export type AccountCompressionEvent = beet.DataEnumKeyAsKind; + +export const isAccountCompressionEventChangeLog = ( + x: AccountCompressionEvent, +): x is AccountCompressionEvent & { __kind: 'ChangeLog' } => x.__kind === 'ChangeLog'; +export const isAccountCompressionEventApplicationData = ( + x: AccountCompressionEvent, +): x is AccountCompressionEvent & { __kind: 'ApplicationData' } => x.__kind === 'ApplicationData'; + +/** + * @category userTypes + * @category generated + */ +export const accountCompressionEventBeet = beet.dataEnum([ + [ + 'ChangeLog', + new beet.FixableBeetArgsStruct( + [['fields', beet.tuple([changeLogEventBeet])]], + 'AccountCompressionEventRecord["ChangeLog"]', + ), + ], + [ + 'ApplicationData', + new beet.FixableBeetArgsStruct( + [['fields', beet.tuple([applicationDataEventBeet])]], + 'AccountCompressionEventRecord["ApplicationData"]', + ), + ], +]) as beet.FixableBeet; diff --git a/account-compression/sdk/src/generated/types/ApplicationDataEvent.ts b/account-compression/sdk/src/generated/types/ApplicationDataEvent.ts new file mode 100644 index 00000000000..d6fd2aff4bf --- /dev/null +++ b/account-compression/sdk/src/generated/types/ApplicationDataEvent.ts @@ -0,0 +1,52 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as beet from '@metaplex-foundation/beet'; + +import { ApplicationDataEventV1, applicationDataEventV1Beet } from './ApplicationDataEventV1'; +/** + * This type is used to derive the {@link ApplicationDataEvent} type as well as the de/serializer. + * However don't refer to it in your code but use the {@link ApplicationDataEvent} type instead. + * + * @category userTypes + * @category enums + * @category generated + * @private + */ +export type ApplicationDataEventRecord = { + V1: { fields: [ApplicationDataEventV1] }; +}; + +/** + * Union type respresenting the ApplicationDataEvent data enum defined in Rust. + * + * NOTE: that it includes a `__kind` property which allows to narrow types in + * switch/if statements. + * Additionally `isApplicationDataEvent*` type guards are exposed below to narrow to a specific variant. + * + * @category userTypes + * @category enums + * @category generated + */ +export type ApplicationDataEvent = beet.DataEnumKeyAsKind; + +export const isApplicationDataEventV1 = (x: ApplicationDataEvent): x is ApplicationDataEvent & { __kind: 'V1' } => + x.__kind === 'V1'; + +/** + * @category userTypes + * @category generated + */ +export const applicationDataEventBeet = beet.dataEnum([ + [ + 'V1', + new beet.FixableBeetArgsStruct( + [['fields', beet.tuple([applicationDataEventV1Beet])]], + 'ApplicationDataEventRecord["V1"]', + ), + ], +]) as beet.FixableBeet; diff --git a/account-compression/sdk/src/generated/types/ApplicationDataEventV1.ts b/account-compression/sdk/src/generated/types/ApplicationDataEventV1.ts new file mode 100644 index 00000000000..b581369ffdc --- /dev/null +++ b/account-compression/sdk/src/generated/types/ApplicationDataEventV1.ts @@ -0,0 +1,20 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as beet from '@metaplex-foundation/beet'; +export type ApplicationDataEventV1 = { + applicationData: Uint8Array; +}; + +/** + * @category userTypes + * @category generated + */ +export const applicationDataEventV1Beet = new beet.FixableBeetArgsStruct( + [['applicationData', beet.bytes]], + 'ApplicationDataEventV1', +); diff --git a/account-compression/sdk/src/generated/types/ChangeLogEvent.ts b/account-compression/sdk/src/generated/types/ChangeLogEvent.ts new file mode 100644 index 00000000000..9418cff3bcf --- /dev/null +++ b/account-compression/sdk/src/generated/types/ChangeLogEvent.ts @@ -0,0 +1,51 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as beet from '@metaplex-foundation/beet'; + +import { ChangeLogEventV1, changeLogEventV1Beet } from './ChangeLogEventV1'; +/** + * This type is used to derive the {@link ChangeLogEvent} type as well as the de/serializer. + * However don't refer to it in your code but use the {@link ChangeLogEvent} type instead. + * + * @category userTypes + * @category enums + * @category generated + * @private + */ +export type ChangeLogEventRecord = { + V1: { fields: [ChangeLogEventV1] }; +}; + +/** + * Union type respresenting the ChangeLogEvent data enum defined in Rust. + * + * NOTE: that it includes a `__kind` property which allows to narrow types in + * switch/if statements. + * Additionally `isChangeLogEvent*` type guards are exposed below to narrow to a specific variant. + * + * @category userTypes + * @category enums + * @category generated + */ +export type ChangeLogEvent = beet.DataEnumKeyAsKind; + +export const isChangeLogEventV1 = (x: ChangeLogEvent): x is ChangeLogEvent & { __kind: 'V1' } => x.__kind === 'V1'; + +/** + * @category userTypes + * @category generated + */ +export const changeLogEventBeet = beet.dataEnum([ + [ + 'V1', + new beet.FixableBeetArgsStruct( + [['fields', beet.tuple([changeLogEventV1Beet])]], + 'ChangeLogEventRecord["V1"]', + ), + ], +]) as beet.FixableBeet; diff --git a/account-compression/sdk/src/generated/types/ChangeLogEventV1.ts b/account-compression/sdk/src/generated/types/ChangeLogEventV1.ts new file mode 100644 index 00000000000..df16281b885 --- /dev/null +++ b/account-compression/sdk/src/generated/types/ChangeLogEventV1.ts @@ -0,0 +1,32 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as beet from '@metaplex-foundation/beet'; +import * as beetSolana from '@metaplex-foundation/beet-solana'; +import * as web3 from '@solana/web3.js'; + +import { PathNode, pathNodeBeet } from './PathNode'; +export type ChangeLogEventV1 = { + id: web3.PublicKey; + index: number; + path: PathNode[]; + seq: beet.bignum; +}; + +/** + * @category userTypes + * @category generated + */ +export const changeLogEventV1Beet = new beet.FixableBeetArgsStruct( + [ + ['id', beetSolana.publicKey], + ['path', beet.array(pathNodeBeet)], + ['seq', beet.u64], + ['index', beet.u32], + ], + 'ChangeLogEventV1', +); diff --git a/account-compression/sdk/src/generated/types/CompressionAccountType.ts b/account-compression/sdk/src/generated/types/CompressionAccountType.ts new file mode 100644 index 00000000000..8ad34d172dd --- /dev/null +++ b/account-compression/sdk/src/generated/types/CompressionAccountType.ts @@ -0,0 +1,25 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as beet from '@metaplex-foundation/beet'; +/** + * @category enums + * @category generated + */ +export enum CompressionAccountType { + Uninitialized, + ConcurrentMerkleTree, +} + +/** + * @category userTypes + * @category generated + */ +export const compressionAccountTypeBeet = beet.fixedScalarEnum(CompressionAccountType) as beet.FixedSizeBeet< + CompressionAccountType, + CompressionAccountType +>; diff --git a/account-compression/sdk/src/generated/types/ConcurrentMerkleTreeHeader.ts b/account-compression/sdk/src/generated/types/ConcurrentMerkleTreeHeader.ts new file mode 100644 index 00000000000..4ab090445e3 --- /dev/null +++ b/account-compression/sdk/src/generated/types/ConcurrentMerkleTreeHeader.ts @@ -0,0 +1,27 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as beet from '@metaplex-foundation/beet'; + +import { CompressionAccountType, compressionAccountTypeBeet } from './CompressionAccountType'; +import { ConcurrentMerkleTreeHeaderData, concurrentMerkleTreeHeaderDataBeet } from './ConcurrentMerkleTreeHeaderData'; +export type ConcurrentMerkleTreeHeader = { + accountType: CompressionAccountType; + header: ConcurrentMerkleTreeHeaderData; +}; + +/** + * @category userTypes + * @category generated + */ +export const concurrentMerkleTreeHeaderBeet = new beet.FixableBeetArgsStruct( + [ + ['accountType', compressionAccountTypeBeet], + ['header', concurrentMerkleTreeHeaderDataBeet], + ], + 'ConcurrentMerkleTreeHeader', +); diff --git a/account-compression/sdk/src/generated/types/ConcurrentMerkleTreeHeaderData.ts b/account-compression/sdk/src/generated/types/ConcurrentMerkleTreeHeaderData.ts new file mode 100644 index 00000000000..3c1c8011f10 --- /dev/null +++ b/account-compression/sdk/src/generated/types/ConcurrentMerkleTreeHeaderData.ts @@ -0,0 +1,56 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as beet from '@metaplex-foundation/beet'; + +import { + ConcurrentMerkleTreeHeaderDataV1, + concurrentMerkleTreeHeaderDataV1Beet, +} from './ConcurrentMerkleTreeHeaderDataV1'; +/** + * This type is used to derive the {@link ConcurrentMerkleTreeHeaderData} type as well as the de/serializer. + * However don't refer to it in your code but use the {@link ConcurrentMerkleTreeHeaderData} type instead. + * + * @category userTypes + * @category enums + * @category generated + * @private + */ +export type ConcurrentMerkleTreeHeaderDataRecord = { + V1: { fields: [ConcurrentMerkleTreeHeaderDataV1] }; +}; + +/** + * Union type respresenting the ConcurrentMerkleTreeHeaderData data enum defined in Rust. + * + * NOTE: that it includes a `__kind` property which allows to narrow types in + * switch/if statements. + * Additionally `isConcurrentMerkleTreeHeaderData*` type guards are exposed below to narrow to a specific variant. + * + * @category userTypes + * @category enums + * @category generated + */ +export type ConcurrentMerkleTreeHeaderData = beet.DataEnumKeyAsKind; + +export const isConcurrentMerkleTreeHeaderDataV1 = ( + x: ConcurrentMerkleTreeHeaderData, +): x is ConcurrentMerkleTreeHeaderData & { __kind: 'V1' } => x.__kind === 'V1'; + +/** + * @category userTypes + * @category generated + */ +export const concurrentMerkleTreeHeaderDataBeet = beet.dataEnum([ + [ + 'V1', + new beet.BeetArgsStruct( + [['fields', beet.fixedSizeTuple([concurrentMerkleTreeHeaderDataV1Beet])]], + 'ConcurrentMerkleTreeHeaderDataRecord["V1"]', + ), + ], +]) as beet.FixableBeet; diff --git a/account-compression/sdk/src/generated/types/ConcurrentMerkleTreeHeaderDataV1.ts b/account-compression/sdk/src/generated/types/ConcurrentMerkleTreeHeaderDataV1.ts new file mode 100644 index 00000000000..7e3b0e54e78 --- /dev/null +++ b/account-compression/sdk/src/generated/types/ConcurrentMerkleTreeHeaderDataV1.ts @@ -0,0 +1,34 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as beet from '@metaplex-foundation/beet'; +import * as beetSolana from '@metaplex-foundation/beet-solana'; +import * as web3 from '@solana/web3.js'; +export type ConcurrentMerkleTreeHeaderDataV1 = { + authority: web3.PublicKey; + creationSlot: beet.bignum; + isBatchInitialized: boolean; + maxBufferSize: number; + maxDepth: number; + padding: number[] /* size: 5 */; +}; + +/** + * @category userTypes + * @category generated + */ +export const concurrentMerkleTreeHeaderDataV1Beet = new beet.BeetArgsStruct( + [ + ['maxBufferSize', beet.u32], + ['maxDepth', beet.u32], + ['authority', beetSolana.publicKey], + ['creationSlot', beet.u64], + ['isBatchInitialized', beet.bool], + ['padding', beet.uniformFixedSizeArray(beet.u8, 5)], + ], + 'ConcurrentMerkleTreeHeaderDataV1', +); diff --git a/account-compression/sdk/src/generated/types/PathNode.ts b/account-compression/sdk/src/generated/types/PathNode.ts new file mode 100644 index 00000000000..8d2600febcc --- /dev/null +++ b/account-compression/sdk/src/generated/types/PathNode.ts @@ -0,0 +1,24 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as beet from '@metaplex-foundation/beet'; +export type PathNode = { + index: number; + node: number[] /* size: 32 */; +}; + +/** + * @category userTypes + * @category generated + */ +export const pathNodeBeet = new beet.BeetArgsStruct( + [ + ['node', beet.uniformFixedSizeArray(beet.u8, 32)], + ['index', beet.u32], + ], + 'PathNode', +); diff --git a/account-compression/sdk/src/generated/types/index.ts b/account-compression/sdk/src/generated/types/index.ts new file mode 100644 index 00000000000..ad9797f9b72 --- /dev/null +++ b/account-compression/sdk/src/generated/types/index.ts @@ -0,0 +1,10 @@ +export * from './AccountCompressionEvent'; +export * from './ApplicationDataEvent'; +export * from './ApplicationDataEventV1'; +export * from './ChangeLogEvent'; +export * from './ChangeLogEventV1'; +export * from './CompressionAccountType'; +export * from './ConcurrentMerkleTreeHeader'; +export * from './ConcurrentMerkleTreeHeaderData'; +export * from './ConcurrentMerkleTreeHeaderDataV1'; +export * from './PathNode'; diff --git a/account-compression/sdk/src/index.ts b/account-compression/sdk/src/index.ts new file mode 100644 index 00000000000..9ea2dfa9c7b --- /dev/null +++ b/account-compression/sdk/src/index.ts @@ -0,0 +1,12 @@ +export * from './generated'; +export { + PROGRAM_ADDRESS as SPL_ACCOUNT_COMPRESSION_ADDRESS, + PROGRAM_ID as SPL_ACCOUNT_COMPRESSION_PROGRAM_ID, +} from './generated'; +export * from './instructions'; +export * from './accounts'; +export * from './events'; +export * from './constants'; +export * from './types'; +export * from './merkle-tree'; +export type { ChangeLogEventV1 } from './types'; diff --git a/account-compression/sdk/src/instructions/index.ts b/account-compression/sdk/src/instructions/index.ts new file mode 100644 index 00000000000..0f4b8cdc052 --- /dev/null +++ b/account-compression/sdk/src/instructions/index.ts @@ -0,0 +1,298 @@ +import { Connection, PublicKey, SystemProgram, TransactionInstruction } from '@solana/web3.js'; + +import { getConcurrentMerkleTreeAccountSize } from '../accounts'; +import { SPL_NOOP_PROGRAM_ID, ValidDepthSizePair } from '../constants'; +import { + createAppendCanopyNodesInstruction, + createAppendInstruction, + createCloseEmptyTreeInstruction, + createInitEmptyMerkleTreeInstruction, + createInitPreparedTreeWithRootInstruction, + createPrepareBatchMerkleTreeInstruction, + createReplaceLeafInstruction, + createTransferAuthorityInstruction, + createVerifyLeafInstruction, + PROGRAM_ID, +} from '../generated'; +import { MerkleTreeProof } from '../merkle-tree'; + +/** + * Helper function that adds proof nodes to a TransactionInstruction + * by adding extra keys to the transaction + */ +export function addProof(instruction: TransactionInstruction, nodeProof: Buffer[]): TransactionInstruction { + instruction.keys = instruction.keys.concat( + nodeProof.map(node => { + return { + isSigner: false, + isWritable: false, + pubkey: new PublicKey(node), + }; + }), + ); + return instruction; +} + +/** + * Helper function for {@link createInitEmptyMerkleTreeInstruction} + * + * @param merkleTree + * @param authority + * @param depthSizePair + * @returns + */ +export function createInitEmptyMerkleTreeIx( + merkleTree: PublicKey, + authority: PublicKey, + depthSizePair: ValidDepthSizePair, +): TransactionInstruction { + return createInitEmptyMerkleTreeInstruction( + { + authority: authority, + merkleTree, + noop: SPL_NOOP_PROGRAM_ID, + }, + depthSizePair, + ); +} + +/** + * (Devnet only) Helper function for {@link createPrepareBatchMerkleTreeInstruction} + * @param merkleTree + * @param authority + * @param depthSizePair + * @returns + */ +export function prepareTreeIx( + merkleTree: PublicKey, + authority: PublicKey, + depthSizePair: ValidDepthSizePair, +): TransactionInstruction { + return createPrepareBatchMerkleTreeInstruction( + { + authority: authority, + merkleTree, + noop: SPL_NOOP_PROGRAM_ID, + }, + depthSizePair, + ); +} + +/** + * (Devnet only) Helper function for {@link createAppendCanopyNodesInstruction} + * @param merkleTree + * @param authority + * @param canopyNodes + * @param startIndex + * @returns + */ +export function createAppendCanopyNodesIx( + merkleTree: PublicKey, + authority: PublicKey, + canopyNodes: ArrayLike[] | Buffer[], + startIndex: number, +): TransactionInstruction { + return createAppendCanopyNodesInstruction( + { + authority, + merkleTree, + noop: SPL_NOOP_PROGRAM_ID, + }, + { + canopyNodes: canopyNodes.map(node => Array.from(node)), + startIndex, + }, + ); +} + +/** + * (Devnet only) Helper function for {@link createInitPreparedTreeWithRootInstruction} + * @param merkleTree + * @param authority + * @param root + * @param rightmostLeaf + * @param rightmostIndex + * @param proof + * @returns + */ +export function createInitPreparedTreeWithRootIx( + merkleTree: PublicKey, + authority: PublicKey, + root: ArrayLike | Buffer, + rightmostLeaf: ArrayLike | Buffer, + rightmostIndex: number, + proof: Buffer[], +): TransactionInstruction { + return createInitPreparedTreeWithRootInstruction( + { + anchorRemainingAccounts: proof.map(node => { + return { + isSigner: false, + isWritable: false, + pubkey: new PublicKey(node), + }; + }), + authority, + merkleTree, + noop: SPL_NOOP_PROGRAM_ID, + }, + { + rightmostIndex, + rightmostLeaf: Array.from(rightmostLeaf), + root: Array.from(root), + }, + ); +} + +/** + * Helper function for {@link createReplaceLeafInstruction} + * @param merkleTree + * @param authority + * @param proof + * @param newLeaf + * @returns + */ +export function createReplaceIx( + merkleTree: PublicKey, + authority: PublicKey, + newLeaf: Buffer, + proof: MerkleTreeProof, +): TransactionInstruction { + return addProof( + createReplaceLeafInstruction( + { + authority: authority, + merkleTree, + noop: SPL_NOOP_PROGRAM_ID, + }, + { + index: proof.leafIndex, + newLeaf: Array.from(newLeaf), + previousLeaf: Array.from(proof.leaf), + root: Array.from(proof.root), + }, + ), + proof.proof, + ); +} + +/** + * Helper function for {@link createAppendInstruction} + * @param merkleTree + * @param authority + * @param newLeaf + * @returns + */ +export function createAppendIx( + merkleTree: PublicKey, + authority: PublicKey, + newLeaf: ArrayLike | Buffer, +): TransactionInstruction { + return createAppendInstruction( + { + authority: authority, + merkleTree, + noop: SPL_NOOP_PROGRAM_ID, + }, + { + leaf: Array.from(newLeaf), + }, + ); +} + +/** + * Helper function for {@link createTransferAuthorityIx} + * @param merkleTree + * @param authority + * @param newAuthority + * @returns + */ +export function createTransferAuthorityIx( + merkleTree: PublicKey, + authority: PublicKey, + newAuthority: PublicKey, +): TransactionInstruction { + return createTransferAuthorityInstruction( + { + authority: authority, + merkleTree, + }, + { + newAuthority, + }, + ); +} + +/** + * Helper function for {@link createVerifyLeafInstruction} + * @param merkleTree + * @param proof + * @returns + */ +export function createVerifyLeafIx(merkleTree: PublicKey, proof: MerkleTreeProof): TransactionInstruction { + return addProof( + createVerifyLeafInstruction( + { + merkleTree, + }, + { + index: proof.leafIndex, + leaf: Array.from(proof.leaf), + root: Array.from(proof.root), + }, + ), + proof.proof, + ); +} + +/** + * Helper function for creating the {@link ConcurrentMerkleTreeAccount}. + * It is best to use this method to initialize a {@link ConcurrentMerkleTreeAccount} + * because these accounts can be quite large, and over the limit for what you + * can allocate via CPI. + * @param connection + * @param merkleTree + * @param payer + * @param depthSizePair + * @param canopyDepth + * @returns + */ +export async function createAllocTreeIx( + connection: Connection, + merkleTree: PublicKey, + payer: PublicKey, + depthSizePair: ValidDepthSizePair, + canopyDepth: number, +): Promise { + const requiredSpace = getConcurrentMerkleTreeAccountSize( + depthSizePair.maxDepth, + depthSizePair.maxBufferSize, + canopyDepth ?? 0, + ); + return SystemProgram.createAccount({ + fromPubkey: payer, + lamports: await connection.getMinimumBalanceForRentExemption(requiredSpace), + newAccountPubkey: merkleTree, + programId: PROGRAM_ID, + space: requiredSpace, + }); +} + +/** + * Helper function for {@link createCloseEmptyTreeInstruction}. + * @param merkleTree + * @param authority + * @param recipient + * @returns + */ +export function createCloseEmptyTreeIx( + merkleTree: PublicKey, + authority: PublicKey, + recipient: PublicKey, +): TransactionInstruction { + return createCloseEmptyTreeInstruction({ + authority, + merkleTree, + recipient, + }); +} diff --git a/account-compression/sdk/src/merkle-tree/index.ts b/account-compression/sdk/src/merkle-tree/index.ts new file mode 100644 index 00000000000..1b640ff3972 --- /dev/null +++ b/account-compression/sdk/src/merkle-tree/index.ts @@ -0,0 +1,291 @@ +import { PublicKey } from '@solana/web3.js'; +import pkg from 'js-sha3'; +import * as Collections from 'typescript-collections'; +const { keccak_256 } = pkg; + +const CACHE_EMPTY_NODE = new Map(); +export const LEAF_BUFFER_LENGTH = 32; + +export type MerkleTreeProof = { + leaf: Buffer; + leafIndex: number; + proof: Buffer[]; + root: Buffer; +}; + +export class MerkleTree { + leaves: TreeNode[]; + root: Buffer; + depth: number; + + /** + * Please use `MerkleTree.sparseMerkleTreeFromLeaves` to + * create trees instead. This method is exposed for testing purposes, + * and for those that are familiar with the MerkleTree data structure. + * @param leaves leaf nodes of the tree + */ + constructor(leaves: Buffer[]) { + const [nodes, finalLeaves] = buildLeaves(leaves); + let seqNum = leaves.length; + + while (nodes.size() > 1) { + const left = nodes.dequeue()!; + const level = left.level; + + let right: TreeNode; + if (level != nodes.peek()!.level) { + right = emptyTreeNode(level, seqNum); + seqNum++; + } else { + right = nodes.dequeue()!; + } + + const parent: TreeNode = { + id: seqNum, + left: left, + level: level + 1, + node: hash(left.node, right.node), + parent: undefined, + right: right, + }; + left.parent = parent; + right.parent = parent; + nodes.enqueue(parent); + seqNum++; + } + + this.leaves = finalLeaves; + this.root = nodes.peek()!.node; + this.depth = nodes.peek()!.level + 1; + } + + /** + * This is the recommended way to create MerkleTrees. + * If you're trying to match an on-chain MerkleTree, + * set `depth` to `{@link ConcurrentMerkleTreeAccount}.getMaxDepth()` + * + * @param leaves leaves of the tree + * @param depth number of levels in the tree + * @returns MerkleTree + */ + static sparseMerkleTreeFromLeaves(leaves: Buffer[], depth: number): MerkleTree { + const _leaves: Buffer[] = []; + for (let i = 0; i < 2 ** depth; i++) { + if (i < leaves.length) { + _leaves.push(leaves[i]); + } else { + _leaves.push(Buffer.alloc(32)); + } + } + return new MerkleTree(_leaves); + } + + getRoot(): Buffer { + return this.root; + } + + getProof(leafIndex: number, minimizeProofHeight = false, treeHeight = -1, verbose = false): MerkleTreeProof { + const proof: TreeNode[] = []; + + let node = this.leaves[leafIndex]; + + let height = 0; + while (typeof node.parent !== 'undefined') { + if (minimizeProofHeight && height >= treeHeight) { + break; + } + if (verbose) { + console.log(`${node.level}: ${Uint8Array.from(node.node)}`); + } + const parent = node.parent; + if (parent.left!.id === node.id) { + proof.push(parent.right!); + + const hashed = hash(node.node, parent.right!.node); + if (!hashed.equals(parent.node)) { + console.log(hashed); + console.log(parent.node); + throw new Error('Invariant broken when hashing left node'); + } + } else { + proof.push(parent.left!); + + const hashed = hash(parent.left!.node, node.node); + if (!hashed.equals(parent.node)) { + console.log(hashed); + console.log(parent.node); + throw new Error('Invariant broken when hashing right node'); + } + } + node = parent; + height++; + } + + return { + leaf: this.leaves[leafIndex].node, + leafIndex, + proof: proof.map(treeNode => treeNode.node), + root: this.getRoot(), + }; + } + + updateLeaf(leafIndex: number, newLeaf: Buffer, verbose = false) { + const leaf = this.leaves[leafIndex]; + leaf.node = newLeaf; + let node = leaf; + + let i = 0; + while (typeof node.parent !== 'undefined') { + if (verbose) { + console.log(`${i}: ${Uint8Array.from(node.node)}`); + } + node = node.parent; + node.node = hash(node.left!.node, node.right!.node); + i++; + } + if (verbose) { + console.log(`${i}: ${Uint8Array.from(node.node)}`); + } + this.root = node.node; + } + + static hashProof(merkleTreeProof: MerkleTreeProof, verbose = false): Buffer { + const { leaf, leafIndex, proof } = merkleTreeProof; + + let node = new PublicKey(leaf).toBuffer(); + for (let i = 0; i < proof.length; i++) { + if ((leafIndex >> i) % 2 === 0) { + node = hash(node, new PublicKey(proof[i]).toBuffer()); + } else { + node = hash(new PublicKey(proof[i]).toBuffer(), node); + } + if (verbose) console.log(`node ${i} ${new PublicKey(node).toString()}`); + } + return node; + } + + /** + * Verifies that a root matches the proof. + * @param root Root of a MerkleTree + * @param merkleTreeProof Proof to a leaf in the MerkleTree + * @param verbose Whether to print hashed nodes + * @returns Whether the proof is valid + */ + static verify(root: Buffer, merkleTreeProof: MerkleTreeProof, verbose = false): boolean { + const node = MerkleTree.hashProof(merkleTreeProof, verbose); + const rehashed = new PublicKey(node).toString(); + const received = new PublicKey(root).toString(); + if (rehashed !== received) { + if (verbose) console.log(`Roots don't match! Expected ${rehashed} got ${received}`); + return false; + } + if (verbose) console.log(`Hashed ${rehashed} got ${received}`); + return rehashed === received; + } +} + +export type TreeNode = { + id: number; + left: TreeNode | undefined; + level: number; + node: Buffer; + parent: TreeNode | undefined; + right: TreeNode | undefined; +}; + +/** + * Uses on-chain hash fn to hash together buffers + */ +export function hash(left: Buffer, right: Buffer): Buffer { + return Buffer.from(keccak_256.digest(Buffer.concat([left, right]))); +} + +/* + Breadth-first iteration over a merkle tree +*/ +// export function bfs(tree: Tree, iterFunc: (node: TreeNode, nodeIdx: number) => T): T[] { +// let toExplore = [getRoot(tree)]; +// const results: T[] = [] +// let idx = 0; +// while (toExplore.length) { +// const nextLevel: TreeNode[] = []; +// for (let i = 0; i < toExplore.length; i++) { +// const node = toExplore[i]; +// if (node.left) { +// nextLevel.push(node.left); +// } +// if (node.right) { +// nextLevel.push(node.right); +// } +// results.push(iterFunc(node, idx)); +// idx++; +// } +// toExplore = nextLevel; +// } +// return results; +// } + +/** + * Creates the leaf node in a tree of empty leaves of height `level`. + * Uses {@link CACHE_EMPTY_NODE} to efficiently produce + * @param level + * @returns + */ +export function emptyNode(level: number): Buffer { + if (CACHE_EMPTY_NODE.has(level)) { + return CACHE_EMPTY_NODE.get(level)!; + } + if (level == 0) { + return Buffer.alloc(32); + } + + const result = hash(emptyNode(level - 1), emptyNode(level - 1)); + CACHE_EMPTY_NODE.set(level, result); + return result; +} + +/** + * Helper function when creating a MerkleTree + * @param level + * @param id + * @returns + */ +function emptyTreeNode(level: number, id: number): TreeNode { + return { + id, + left: undefined, + level: level, + node: emptyNode(level), + parent: undefined, + right: undefined, + }; +} + +/** + * Helper function to build a MerkleTree + * @param leaves + * @returns + */ +function buildLeaves(leaves: Buffer[]): [Collections.Queue, TreeNode[]] { + const nodes = new Collections.Queue(); + const finalLeaves: TreeNode[] = []; + leaves.forEach((buffer, index) => { + if (buffer.length != LEAF_BUFFER_LENGTH) { + throw Error( + `Provided leaf has length: ${buffer.length}, but we need all leaves to be length ${LEAF_BUFFER_LENGTH}`, + ); + } + + const treeNode = { + id: index, + left: undefined, + level: 0, + node: buffer, + parent: undefined, + right: undefined, + }; + nodes.enqueue(treeNode); + finalLeaves.push(treeNode); + }); + return [nodes, finalLeaves]; +} diff --git a/account-compression/sdk/src/types/Canopy.ts b/account-compression/sdk/src/types/Canopy.ts new file mode 100644 index 00000000000..ee7902f1319 --- /dev/null +++ b/account-compression/sdk/src/types/Canopy.ts @@ -0,0 +1,31 @@ +import * as beet from '@metaplex-foundation/beet'; + +/** + * Canopy fields necessary for deserializing an on-chain Canopy + * for a {@link ConcurrentMerkleTreeAccount} + */ +export type Canopy = { + canopyBytes: number[]; +}; + +/** + * Factory function for generating a `beet` that can deserialize + * an on-chain {@link Canopy} + * + * {@link Canopy} of depth `N` is an on-chain cache of the top + * `N` nodes in the {@link ConcurrentMerkleTree}. This is a total + * of `2^(N+1) - 1` nodes. Each node has `32` bytes. + * However, the current root of the tree is always stored in the + * most recent {@link ChangeLog}, so we only need to cache the remaining `N-1` levels. + * + * The final formula for account size in bytes: `(2^(N) - 1 - 1) * 32`. + * + * @param canopyDepth + * @returns + */ +export const canopyBeetFactory = (canopyDepth: number) => { + return new beet.BeetArgsStruct( + [['canopyBytes', beet.uniformFixedSizeArray(beet.u8, Math.max(((1 << (canopyDepth + 1)) - 2) * 32, 0))]], + 'Canopy', + ); +}; diff --git a/account-compression/sdk/src/types/ConcurrentMerkleTree.ts b/account-compression/sdk/src/types/ConcurrentMerkleTree.ts new file mode 100644 index 00000000000..523373bda3e --- /dev/null +++ b/account-compression/sdk/src/types/ConcurrentMerkleTree.ts @@ -0,0 +1,64 @@ +import * as beet from '@metaplex-foundation/beet'; +import * as beetSolana from '@metaplex-foundation/beet-solana'; +import { PublicKey } from '@solana/web3.js'; + +import { Path, pathBeetFactory } from './Path'; + +/** + * ChangeLog information necessary for deserializing an on-chain ConcurrentMerkleTree + * @private + */ +export type ChangeLogInternal = { + // u32 + _padding: number; + index: number; + pathNodes: PublicKey[]; + root: PublicKey; // u32 +}; + +const changeLogBeetFactory = (maxDepth: number) => { + return new beet.BeetArgsStruct( + [ + ['root', beetSolana.publicKey], + ['pathNodes', beet.uniformFixedSizeArray(beetSolana.publicKey, maxDepth)], + ['index', beet.u32], + ['_padding', beet.u32], + ], + 'ChangeLog', + ); +}; + +/** + * ConcurrentMerkleTree fields necessary for deserializing an on-chain ConcurrentMerkleTree + */ +export type ConcurrentMerkleTree = { + // u64 + activeIndex: beet.bignum; + // u64 + bufferSize: beet.bignum; + // u64 + changeLogs: ChangeLogInternal[]; + rightMostPath: Path; + sequenceNumber: beet.bignum; +}; + +/** + * Factory function for generating a `beet` that can deserialize + * an on-chain {@link ConcurrentMerkleTree} + * + * @param maxDepth + * @param maxBufferSize + * @returns + */ +export const concurrentMerkleTreeBeetFactory = (maxDepth: number, maxBufferSize: number) => { + return new beet.BeetArgsStruct( + [ + ['sequenceNumber', beet.u64], + ['activeIndex', beet.u64], + ['bufferSize', beet.u64], + ['changeLogs', beet.uniformFixedSizeArray(changeLogBeetFactory(maxDepth), maxBufferSize)], + ['rightMostPath', pathBeetFactory(maxDepth)], + ], + 'ConcurrentMerkleTree', + ); +}; diff --git a/account-compression/sdk/src/types/Path.ts b/account-compression/sdk/src/types/Path.ts new file mode 100644 index 00000000000..d87b6b09bb1 --- /dev/null +++ b/account-compression/sdk/src/types/Path.ts @@ -0,0 +1,34 @@ +import * as beet from '@metaplex-foundation/beet'; +import * as beetSolana from '@metaplex-foundation/beet-solana'; +import { PublicKey } from '@solana/web3.js'; + +/** + * Canopy fields necessary for deserializing an on-chain Path + * used in an {@link ConcurrentMerkleTree} + */ +export type Path = { + // u32 + _padding: number; + index: number; + leaf: PublicKey; + proof: PublicKey[]; // u32 +}; + +/** + * Factory function for generating a `beet` that can deserialize + * an on-chain {@link Path} + * + * @param maxDepth + * @returns + */ +export const pathBeetFactory = (maxDepth: number) => { + return new beet.BeetArgsStruct( + [ + ['proof', beet.uniformFixedSizeArray(beetSolana.publicKey, maxDepth)], + ['leaf', beetSolana.publicKey], + ['index', beet.u32], + ['_padding', beet.u32], + ], + 'Path', + ); +}; diff --git a/account-compression/sdk/src/types/index.ts b/account-compression/sdk/src/types/index.ts new file mode 100644 index 00000000000..620d1669800 --- /dev/null +++ b/account-compression/sdk/src/types/index.ts @@ -0,0 +1,14 @@ +import { PublicKey } from '@solana/web3.js'; +import BN from 'bn.js'; + +import { PathNode } from '../generated'; +export * from './Path'; +export * from './Canopy'; +export * from './ConcurrentMerkleTree'; + +export type ChangeLogEventV1 = { + index: number; + path: PathNode[]; + seq: BN; + treeId: PublicKey; +}; diff --git a/account-compression/sdk/tests/accountCompression.test.ts b/account-compression/sdk/tests/accountCompression.test.ts new file mode 100644 index 00000000000..deb7a2e3173 --- /dev/null +++ b/account-compression/sdk/tests/accountCompression.test.ts @@ -0,0 +1,1096 @@ +import { strict as assert } from 'node:assert'; + +import { AnchorProvider } from '@coral-xyz/anchor'; +import NodeWallet from '@coral-xyz/anchor/dist/cjs/nodewallet'; +import { Connection, Keypair, PublicKey, TransactionInstruction } from '@solana/web3.js'; +import { BN } from 'bn.js'; +import * as crypto from 'crypto'; + +import { + ConcurrentMerkleTreeAccount, + createAppendCanopyNodesIx, + createAppendIx, + createCloseEmptyTreeInstruction, + createCloseEmptyTreeIx, + createInitEmptyMerkleTreeIx, + createInitPreparedTreeWithRootIx, + createReplaceIx, + createTransferAuthorityIx, + createVerifyLeafIx, + prepareTreeIx, + ValidDepthSizePair, +} from '../src'; +import { hash, MerkleTree } from '../src/merkle-tree'; +import { assertCMTProperties } from './accounts/concurrentMerkleTreeAccount.test'; +import { createTreeOnChain, execute, prepareTree } from './utils'; + +// eslint-disable-next-line no-empty +describe('Account Compression', () => { + // Configure the client to use the local cluster. + let offChainTree: MerkleTree; + let cmtKeypair: Keypair; + let cmt: PublicKey; + let payerKeypair: Keypair; + let payer: PublicKey; + let connection: Connection; + let provider: AnchorProvider; + + const MAX_SIZE = 64; + const MAX_DEPTH = 14; + const DEPTH_SIZE_PAIR: ValidDepthSizePair = { + maxBufferSize: MAX_SIZE, + maxDepth: MAX_DEPTH, + }; + + beforeEach(async () => { + payerKeypair = Keypair.generate(); + payer = payerKeypair.publicKey; + connection = new Connection('http://127.0.0.1:8899', { + commitment: 'confirmed', + }); + const wallet = new NodeWallet(payerKeypair); + provider = new AnchorProvider(connection, wallet, { + commitment: connection.commitment, + skipPreflight: true, + }); + + await provider.connection.confirmTransaction( + await provider.connection.requestAirdrop(payer, 1e10), + 'confirmed', + ); + }); + + describe('Having prepared a tree without canopy', () => { + const depth = 3; + const size = 8; + const canopyDepth = 0; + const leaves = [ + crypto.randomBytes(32), + crypto.randomBytes(32), + crypto.randomBytes(32), + crypto.randomBytes(32), + crypto.randomBytes(32), + crypto.randomBytes(32), + crypto.randomBytes(32), + crypto.randomBytes(32), + ]; + let anotherKeyPair: Keypair; + let another: PublicKey; + + beforeEach(async () => { + const cmtKeypair = await prepareTree({ + canopyDepth, + depthSizePair: { + maxBufferSize: size, + maxDepth: depth, + }, + payer: payerKeypair, + provider, + }); + cmt = cmtKeypair.publicKey; + anotherKeyPair = Keypair.generate(); + another = anotherKeyPair.publicKey; + await provider.connection.confirmTransaction( + await provider.connection.requestAirdrop(another, 1e10), + 'confirmed', + ); + }); + it('Should be able to finalize the tree', async () => { + const merkleTreeRaw = new MerkleTree(leaves); + const root = merkleTreeRaw.root; + const leaf = leaves[leaves.length - 1]; + const canopyDepth = 0; + const finalize = createInitPreparedTreeWithRootIx( + cmt, + payer, + root, + leaf, + leaves.length - 1, + merkleTreeRaw.getProof(leaves.length - 1).proof, + ); + + await execute(provider, [finalize], [payerKeypair]); + + const splCMT = await ConcurrentMerkleTreeAccount.fromAccountAddress(connection, cmt); + assertCMTProperties(splCMT, depth, size, payer, root, canopyDepth, true); + assert(splCMT.getBufferSize() == 1, 'Buffer size does not match'); + }); + it('Should fail to append canopy node for a tree without canopy', async () => { + const appendIx = createAppendCanopyNodesIx(cmt, payer, [crypto.randomBytes(32)], 0); + try { + await execute(provider, [appendIx], [payerKeypair]); + assert(false, 'Canopy appending should have failed to execute for a tree without canopy'); + } catch {} + }); + it('Should fail to finalize the tree with another payer authority', async () => { + const merkleTreeRaw = new MerkleTree(leaves); + const root = merkleTreeRaw.root; + const leaf = leaves[leaves.length - 1]; + + const finalize = createInitPreparedTreeWithRootIx( + cmt, + another, + root, + leaf, + leaves.length - 1, + merkleTreeRaw.getProof(leaves.length - 1).proof, + ); + + try { + await execute(provider, [finalize], [anotherKeyPair]); + assert(false, 'Finalizing with another payer should have failed'); + } catch {} + }); + it('Should fail to finalize the tree with a wrong proof', async () => { + const merkleTreeRaw = new MerkleTree(leaves); + const root = merkleTreeRaw.root; + const leaf = leaves[leaves.length - 1]; + // Replace valid proof with random bytes so it is wrong + const proof = merkleTreeRaw.getProof(leaves.length - 1); + proof.proof = proof.proof.map(_ => { + return crypto.randomBytes(32); + }); + + const finalize = createInitPreparedTreeWithRootIx(cmt, payer, root, leaf, leaves.length - 1, proof.proof); + + try { + await execute(provider, [finalize], [payerKeypair]); + assert(false, 'Finalizing with a wrong proof should have failed'); + } catch {} + }); + it('Should fail to double finalize the tree', async () => { + const merkleTreeRaw = new MerkleTree(leaves); + const root = merkleTreeRaw.root; + const leaf = leaves[leaves.length - 1]; + + const finalize = createInitPreparedTreeWithRootIx( + cmt, + payer, + root, + leaf, + leaves.length - 1, + merkleTreeRaw.getProof(leaves.length - 1).proof, + ); + + await execute(provider, [finalize], [payerKeypair]); + + try { + await execute(provider, [finalize], [payerKeypair]); + assert(false, 'Double finalizing should have failed'); + } catch {} + }); + + it('Should be able to close a prepared tree', async () => { + let payerInfo = await provider.connection.getAccountInfo(payer, 'confirmed')!; + let treeInfo = await provider.connection.getAccountInfo(cmt, 'confirmed')!; + + const payerLamports = payerInfo!.lamports; + const treeLamports = treeInfo!.lamports; + + const closeIx = createCloseEmptyTreeIx(cmt, payer, payer); + await execute(provider, [closeIx], [payerKeypair]); + + payerInfo = await provider.connection.getAccountInfo(payer, 'confirmed')!; + const finalLamports = payerInfo!.lamports; + assert( + finalLamports === payerLamports + treeLamports - 5000, + 'Expected payer to have received the lamports from the closed tree account', + ); + + treeInfo = await provider.connection.getAccountInfo(cmt, 'confirmed'); + assert(treeInfo === null, 'Expected the merkle tree account info to be null'); + }); + }); + describe('Having prepared a tree with canopy', () => { + const depth = 3; + const size = 8; + const canopyDepth = 2; + const leaves = [ + crypto.randomBytes(32), + crypto.randomBytes(32), + crypto.randomBytes(32), + crypto.randomBytes(32), + crypto.randomBytes(32), + crypto.randomBytes(32), + crypto.randomBytes(32), + crypto.randomBytes(32), + ]; + let anotherKeyPair: Keypair; + let another: PublicKey; + beforeEach(async () => { + const cmtKeypair = await prepareTree({ + canopyDepth, + depthSizePair: { + maxBufferSize: size, + maxDepth: depth, + }, + payer: payerKeypair, + provider, + }); + cmt = cmtKeypair.publicKey; + anotherKeyPair = Keypair.generate(); + another = anotherKeyPair.publicKey; + await provider.connection.confirmTransaction( + await provider.connection.requestAirdrop(another, 1e10), + 'confirmed', + ); + }); + it('Should be able to append a single canopy node', async () => { + const appendIx = createAppendCanopyNodesIx(cmt, payer, [crypto.randomBytes(32)], 0); + await execute(provider, [appendIx], [payerKeypair]); + }); + it('Should be able to append a single canopy node at the index more then 0', async () => { + const appendIx = createAppendCanopyNodesIx(cmt, payer, [crypto.randomBytes(32)], 1); + await execute(provider, [appendIx], [payerKeypair]); + }); + it('Should be able to append several canopy nodes at the start of the node leaves', async () => { + const appendIx = createAppendCanopyNodesIx(cmt, payer, [crypto.randomBytes(32), crypto.randomBytes(32)], 0); + await execute(provider, [appendIx], [payerKeypair]); + }); + it('Should fail to append canopy node with another payer authority', async () => { + const appendIx = createAppendCanopyNodesIx(cmt, another, [crypto.randomBytes(32)], 0); + try { + await execute(provider, [appendIx], [anotherKeyPair]); + assert(false, 'Appending with another payer should have failed'); + } catch {} + }); + it('Should fail to append canopy nodes over the limit', async () => { + const appendIx = createAppendCanopyNodesIx( + cmt, + payer, + Array.from({ length: 3 }, () => crypto.randomBytes(32)), + 0, + ); + try { + await execute(provider, [appendIx], [payerKeypair]); + assert(false, 'Appending over the limit should have failed'); + } catch {} + }); + it('Should fail to append canopy nodes over the limit starting from the last index', async () => { + const appendIx = createAppendCanopyNodesIx( + cmt, + payer, + Array.from({ length: 2 }, () => crypto.randomBytes(32)), + 1, + ); + try { + await execute(provider, [appendIx], [payerKeypair]); + assert(false, 'Appending over the limit should have failed'); + } catch {} + }); + it('Should fail to append 0 canopy nodes', async () => { + const appendIx = createAppendCanopyNodesIx(cmt, payer, [], 0); + try { + await execute(provider, [appendIx], [payerKeypair]); + assert(false, 'Appending 0 nodes should have failed'); + } catch {} + }); + it('Should fail to finalize the tree without canopy', async () => { + const merkleTreeRaw = new MerkleTree(leaves); + const root = merkleTreeRaw.root; + const leaf = leaves[leaves.length - 1]; + + const finalize = createInitPreparedTreeWithRootIx( + cmt, + payer, + root, + leaf, + leaves.length - 1, + merkleTreeRaw.getProof(leaves.length - 1).proof, + ); + + try { + await execute(provider, [finalize], [payerKeypair]); + assert(false, 'Finalizing without canopy should have failed'); + } catch {} + }); + it('Should fail to finalize the tree with an incomplete canopy', async () => { + const merkleTreeRaw = new MerkleTree(leaves); + const root = merkleTreeRaw.root; + const leaf = leaves[leaves.length - 1]; + + const appendIx = createAppendCanopyNodesIx(cmt, payer, [merkleTreeRaw.leaves[0].parent!.node!], 0); + await execute(provider, [appendIx], [payerKeypair]); + const finalize = createInitPreparedTreeWithRootIx( + cmt, + payer, + root, + leaf, + leaves.length - 1, + merkleTreeRaw.getProof(leaves.length - 1).proof, + ); + + try { + await execute(provider, [finalize], [payerKeypair]); + assert(false, 'Finalization for an incomplete canopy should have failed'); + } catch {} + }); + it('Should finalize the tree with a complete canopy', async () => { + const merkleTreeRaw = new MerkleTree(leaves); + const root = merkleTreeRaw.root; + const leaf = leaves[leaves.length - 1]; + + // take every second leaf and append it's parent node to the canopy + const appendIx = createAppendCanopyNodesIx( + cmt, + payer, + merkleTreeRaw.leaves.filter((_, i) => i % 2 === 0).map(leaf => leaf.parent!.node!), + 0, + ); + await execute(provider, [appendIx], [payerKeypair]); + const finalize = createInitPreparedTreeWithRootIx( + cmt, + payer, + root, + leaf, + leaves.length - 1, + merkleTreeRaw.getProof(leaves.length - 1).proof, + ); + await execute(provider, [finalize], [payerKeypair]); + const splCMT = await ConcurrentMerkleTreeAccount.fromAccountAddress(connection, cmt); + assertCMTProperties(splCMT, depth, size, payer, root, canopyDepth, true); + }); + it('Should be able to setup canopy with several transactions', async () => { + const merkleTreeRaw = new MerkleTree(leaves); + const root = merkleTreeRaw.root; + const leaf = leaves[leaves.length - 1]; + // take every second leaf of the first half of a tree and append it's parent node to the canopy + const appendIx = createAppendCanopyNodesIx( + cmt, + payer, + merkleTreeRaw.leaves + .slice(0, leaves.length / 2) + .filter((_, i) => i % 2 === 0) + .map(leaf => leaf.parent!.node!), + 0, + ); + await execute(provider, [appendIx], [payerKeypair]); + // take every second leaf of the second half of a tree and append it's parent node to the canopy + const appendIx2 = createAppendCanopyNodesIx( + cmt, + payer, + merkleTreeRaw.leaves + .slice(leaves.length / 2) + .filter((_, i) => i % 2 === 0) + .map(leaf => leaf.parent!.node!), + 2, + ); + await execute(provider, [appendIx2], [payerKeypair]); + const finalize = createInitPreparedTreeWithRootIx( + cmt, + payer, + root, + leaf, + leaves.length - 1, + merkleTreeRaw.getProof(leaves.length - 1).proof, + ); + await execute(provider, [finalize], [payerKeypair]); + }); + it('Should be able to setup canopy with several transactions in reverse order', async () => { + const merkleTreeRaw = new MerkleTree(leaves); + const root = merkleTreeRaw.root; + const leaf = leaves[leaves.length - 1]; + + const appendIx = createAppendCanopyNodesIx( + cmt, + payer, + merkleTreeRaw.leaves + .slice(leaves.length / 2) + .filter((_, i) => i % 2 === 0) + .map(leaf => leaf.parent!.node!), + 2, + ); + await execute(provider, [appendIx], [payerKeypair]); + const appendIx2 = createAppendCanopyNodesIx( + cmt, + payer, + merkleTreeRaw.leaves + .slice(0, leaves.length / 2) + .filter((_, i) => i % 2 === 0) + .map(leaf => leaf.parent!.node!), + 0, + ); + await execute(provider, [appendIx2], [payerKeypair]); + const finalize = createInitPreparedTreeWithRootIx( + cmt, + payer, + root, + leaf, + leaves.length - 1, + merkleTreeRaw.getProof(leaves.length - 1).proof, + ); + await execute(provider, [finalize], [payerKeypair]); + }); + it('Should be able to replace a canopy node', async () => { + const merkleTreeRaw = new MerkleTree(leaves); + const root = merkleTreeRaw.root; + const leaf = leaves[leaves.length - 1]; + + const appendIx = createAppendCanopyNodesIx( + cmt, + payer, + merkleTreeRaw.leaves + .slice(0, leaves.length / 2) + .filter((_, i) => i % 2 === 0) + .map(leaf => leaf.parent!.node!), + 0, + ); + await execute(provider, [appendIx], [payerKeypair]); + const appendIx2 = createAppendCanopyNodesIx(cmt, payer, [crypto.randomBytes(32)], 2); + await execute(provider, [appendIx2], [payerKeypair]); + const replaceIx = createAppendCanopyNodesIx( + cmt, + payer, + merkleTreeRaw.leaves + .slice(leaves.length / 2) + .filter((_, i) => i % 2 === 0) + .map(leaf => leaf.parent!.node!), + 2, + ); + await execute(provider, [replaceIx], [payerKeypair]); + const finalize = createInitPreparedTreeWithRootIx( + cmt, + payer, + root, + leaf, + leaves.length - 1, + merkleTreeRaw.getProof(leaves.length - 1).proof, + ); + await execute(provider, [finalize], [payerKeypair]); + }); + it('Should fail to replace a canopy node for a finalised tree', async () => { + const merkleTreeRaw = new MerkleTree(leaves); + const root = merkleTreeRaw.root; + const leaf = leaves[leaves.length - 1]; + + const appendIx = createAppendCanopyNodesIx( + cmt, + payer, + merkleTreeRaw.leaves.filter((_, i) => i % 2 === 0).map(leaf => leaf.parent!.node!), + 0, + ); + await execute(provider, [appendIx], [payerKeypair]); + const finalize = createInitPreparedTreeWithRootIx( + cmt, + payer, + root, + leaf, + leaves.length - 1, + merkleTreeRaw.getProof(leaves.length - 1).proof, + ); + await execute(provider, [finalize], [payerKeypair]); + const replaceIx = createAppendCanopyNodesIx(cmt, payer, [crypto.randomBytes(32)], 0); + try { + await execute(provider, [replaceIx], [payerKeypair]); + assert(false, 'Replacing a canopy node for a finalised tree should have failed'); + } catch {} + }); + it('Should fail to initialize an empty tree after preparing a tree', async () => { + const ixs = [ + createInitEmptyMerkleTreeIx(cmt, payer, { + maxBufferSize: size, + maxDepth: depth, + }), + ]; + try { + await execute(provider, ixs, [payerKeypair]); + assert(false, 'Initializing an empty tree after preparing a tree should have failed'); + } catch {} + }); + it('Should be able to close a prepared tree after setting the canopy', async () => { + const merkleTreeRaw = new MerkleTree(leaves); + + const appendIx = createAppendCanopyNodesIx( + cmt, + payer, + merkleTreeRaw.leaves + .slice(0, leaves.length / 2) + .filter((_, i) => i % 2 === 0) + .map(leaf => leaf.parent!.node!), + 0, + ); + await execute(provider, [appendIx], [payerKeypair]); + let payerInfo = await provider.connection.getAccountInfo(payer, 'confirmed')!; + let treeInfo = await provider.connection.getAccountInfo(cmt, 'confirmed')!; + + const payerLamports = payerInfo!.lamports; + const treeLamports = treeInfo!.lamports; + + const closeIx = createCloseEmptyTreeIx(cmt, payer, payer); + await execute(provider, [closeIx], [payerKeypair]); + + payerInfo = await provider.connection.getAccountInfo(payer, 'confirmed')!; + const finalLamports = payerInfo!.lamports; + assert( + finalLamports === payerLamports + treeLamports - 5000, + 'Expected payer to have received the lamports from the closed tree account', + ); + + treeInfo = await provider.connection.getAccountInfo(cmt, 'confirmed'); + assert(treeInfo === null, 'Expected the merkle tree account info to be null'); + }); + }); + describe('Having prepared an empty tree with canopy', () => { + const depth = 3; + const size = 8; + const canopyDepth = 2; + // empty leaves represent the empty tree + const leaves = [ + Buffer.alloc(32), + Buffer.alloc(32), + Buffer.alloc(32), + Buffer.alloc(32), + Buffer.alloc(32), + Buffer.alloc(32), + Buffer.alloc(32), + Buffer.alloc(32), + ]; + let anotherKeyPair: Keypair; + let another: PublicKey; + beforeEach(async () => { + const cmtKeypair = await prepareTree({ + canopyDepth, + depthSizePair: { + maxBufferSize: size, + maxDepth: depth, + }, + payer: payerKeypair, + provider, + }); + cmt = cmtKeypair.publicKey; + anotherKeyPair = Keypair.generate(); + another = anotherKeyPair.publicKey; + await provider.connection.confirmTransaction( + await provider.connection.requestAirdrop(another, 1e10), + 'confirmed', + ); + }); + + it('Should be able to finalize an empty tree with empty canopy and close it afterwards', async () => { + const merkleTreeRaw = new MerkleTree(leaves); + const root = merkleTreeRaw.root; + const leaf = leaves[leaves.length - 1]; + + const finalize = createInitPreparedTreeWithRootIx( + cmt, + payer, + root, + leaf, + leaves.length - 1, + merkleTreeRaw.getProof(leaves.length - 1).proof, + ); + await execute(provider, [finalize], [payerKeypair]); + let payerInfo = await provider.connection.getAccountInfo(payer, 'confirmed')!; + let treeInfo = await provider.connection.getAccountInfo(cmt, 'confirmed')!; + + const payerLamports = payerInfo!.lamports; + const treeLamports = treeInfo!.lamports; + + const closeIx = createCloseEmptyTreeIx(cmt, payer, payer); + await execute(provider, [closeIx], [payerKeypair]); + + payerInfo = await provider.connection.getAccountInfo(payer, 'confirmed')!; + const finalLamports = payerInfo!.lamports; + assert( + finalLamports === payerLamports + treeLamports - 5000, + 'Expected payer to have received the lamports from the closed tree account', + ); + + treeInfo = await provider.connection.getAccountInfo(cmt, 'confirmed'); + assert(treeInfo === null, 'Expected the merkle tree account info to be null'); + }); + }); + + describe('Having created a tree with a single leaf', () => { + beforeEach(async () => { + [cmtKeypair, offChainTree] = await createTreeOnChain(provider, payerKeypair, 1, DEPTH_SIZE_PAIR); + cmt = cmtKeypair.publicKey; + }); + it('Append single leaf', async () => { + const newLeaf = crypto.randomBytes(32); + const appendIx = createAppendIx(cmt, payer, newLeaf); + + await execute(provider, [appendIx], [payerKeypair]); + offChainTree.updateLeaf(1, newLeaf); + + const splCMT = await ConcurrentMerkleTreeAccount.fromAccountAddress(connection, cmt); + const onChainRoot = splCMT.getCurrentRoot(); + + assert( + Buffer.from(onChainRoot).equals(offChainTree.root), + 'Updated on chain root matches root of updated off chain tree', + ); + }); + it('Verify proof works for that leaf', async () => { + const newLeaf = crypto.randomBytes(32); + const index = 0; + const proof = offChainTree.getProof(index); + + const verifyLeafIx = createVerifyLeafIx(cmt, proof); + const replaceLeafIx = createReplaceIx(cmt, payer, newLeaf, proof); + await execute(provider, [verifyLeafIx, replaceLeafIx], [payerKeypair]); + + offChainTree.updateLeaf(index, newLeaf); + + const splCMT = await ConcurrentMerkleTreeAccount.fromAccountAddress(connection, cmt); + const onChainRoot = splCMT.getCurrentRoot(); + + assert( + Buffer.from(onChainRoot).equals(offChainTree.root), + 'Updated on chain root matches root of updated off chain tree', + ); + }); + it('Verify leaf fails when proof fails', async () => { + const newLeaf = crypto.randomBytes(32); + const index = 0; + // Replace valid proof with random bytes so it is wrong + const proof = offChainTree.getProof(index); + proof.proof = proof.proof.map(_ => { + return crypto.randomBytes(32); + }); + + // Verify proof is invalid + const verifyLeafIx = createVerifyLeafIx(cmt, proof); + try { + await execute(provider, [verifyLeafIx], [payerKeypair]); + assert(false, 'Proof should have failed to verify'); + } catch {} + + // Replace instruction with same proof fails + const replaceLeafIx = createReplaceIx(cmt, payer, newLeaf, proof); + try { + await execute(provider, [replaceLeafIx], [payerKeypair]); + assert(false, 'Replace should have failed to verify'); + } catch {} + + const splCMT = await ConcurrentMerkleTreeAccount.fromAccountAddress(connection, cmtKeypair.publicKey); + const onChainRoot = splCMT.getCurrentRoot(); + + assert( + Buffer.from(onChainRoot).equals(offChainTree.root), + 'Updated on chain root matches root of updated off chain tree', + ); + }); + it('Replace that leaf', async () => { + const newLeaf = crypto.randomBytes(32); + const index = 0; + + const replaceLeafIx = createReplaceIx(cmt, payer, newLeaf, offChainTree.getProof(index, false, -1)); + assert(replaceLeafIx.keys.length == 3 + MAX_DEPTH, `Failed to create proof for ${MAX_DEPTH}`); + + await execute(provider, [replaceLeafIx], [payerKeypair]); + + offChainTree.updateLeaf(index, newLeaf); + + const splCMT = await ConcurrentMerkleTreeAccount.fromAccountAddress(connection, cmt); + const onChainRoot = splCMT.getCurrentRoot(); + + assert( + Buffer.from(onChainRoot).equals(offChainTree.root), + 'Updated on chain root matches root of updated off chain tree', + ); + }); + + it('Replace that leaf with a minimal proof', async () => { + const newLeaf = crypto.randomBytes(32); + const index = 0; + + const replaceLeafIx = createReplaceIx(cmt, payer, newLeaf, offChainTree.getProof(index, true, 1)); + assert(replaceLeafIx.keys.length == 3 + 1, 'Failed to minimize proof to expected size of 1'); + await execute(provider, [replaceLeafIx], [payerKeypair]); + + offChainTree.updateLeaf(index, newLeaf); + + const splCMT = await ConcurrentMerkleTreeAccount.fromAccountAddress(connection, cmt); + const onChainRoot = splCMT.getCurrentRoot(); + + assert( + Buffer.from(onChainRoot).equals(offChainTree.root), + 'Updated on chain root matches root of updated off chain tree', + ); + }); + + it('Should fail to prepare a batch ready tree for an existing tree', async () => { + const prepareIx = prepareTreeIx(cmt, payer, DEPTH_SIZE_PAIR); + try { + await execute(provider, [prepareIx], [payerKeypair]); + assert(false, 'Prepare a batch tree should have failed for the existing tree'); + } catch {} + }); + + it('Should fail to finalize an existing tree', async () => { + const index = offChainTree.leaves.length - 1; + const finalizeIx = createInitPreparedTreeWithRootIx( + cmt, + payer, + offChainTree.root, + offChainTree.leaves[index].node, + index, + offChainTree.getProof(index).proof, + ); + try { + await execute(provider, [finalizeIx], [payerKeypair]); + assert(false, 'Finalize an existing tree should have failed'); + } catch {} + }); + }); + + describe('Examples transferring authority', () => { + const authorityKeypair = Keypair.generate(); + const authority = authorityKeypair.publicKey; + const randomSignerKeypair = Keypair.generate(); + const randomSigner = randomSignerKeypair.publicKey; + + beforeEach(async () => { + await provider.connection.confirmTransaction( + await (connection as Connection).requestAirdrop(authority, 1e10), + ); + [cmtKeypair, offChainTree] = await createTreeOnChain(provider, authorityKeypair, 1, DEPTH_SIZE_PAIR); + cmt = cmtKeypair.publicKey; + }); + it('Attempting to replace with random authority fails', async () => { + const newLeaf = crypto.randomBytes(32); + const replaceIndex = 0; + const proof = offChainTree.getProof(replaceIndex); + const replaceIx = createReplaceIx(cmt, randomSigner, newLeaf, proof); + + try { + await execute(provider, [replaceIx], [randomSignerKeypair]); + assert(false, 'Transaction should have failed since incorrect authority cannot execute replaces'); + } catch {} + }); + it('Can transfer authority', async () => { + const transferAuthorityIx = createTransferAuthorityIx(cmt, authority, randomSigner); + await execute(provider, [transferAuthorityIx], [authorityKeypair]); + + const splCMT = await ConcurrentMerkleTreeAccount.fromAccountAddress(connection, cmt); + + assert( + splCMT.getAuthority().equals(randomSigner), + `Upon transferring authority, authority should be ${randomSigner.toString()}, but was instead updated to ${splCMT.getAuthority()}`, + ); + + // Attempting to replace with new authority now works + const newLeaf = crypto.randomBytes(32); + const replaceIndex = 0; + const proof = offChainTree.getProof(replaceIndex); + const replaceIx = createReplaceIx(cmt, randomSigner, newLeaf, proof); + + await execute(provider, [replaceIx], [randomSignerKeypair]); + }); + }); + + describe(`Having created a tree with ${MAX_SIZE} leaves`, () => { + beforeEach(async () => { + [cmtKeypair, offChainTree] = await createTreeOnChain(provider, payerKeypair, MAX_SIZE, DEPTH_SIZE_PAIR); + cmt = cmtKeypair.publicKey; + }); + it(`Replace all of them in a block`, async () => { + // Replace 64 leaves before syncing off-chain tree with on-chain tree + const ixArray: TransactionInstruction[] = []; + const txList: Promise[] = []; + + const leavesToUpdate: Buffer[] = []; + for (let i = 0; i < MAX_SIZE; i++) { + const index = i; + const newLeaf = hash(payer.toBuffer(), Buffer.from(new BN(i).toArray())); + leavesToUpdate.push(newLeaf); + const proof = offChainTree.getProof(index); + const replaceIx = createReplaceIx(cmt, payer, newLeaf, proof); + ixArray.push(replaceIx); + } + + // Execute all replaces + ixArray.map(ix => { + txList.push(execute(provider, [ix], [payerKeypair])); + }); + await Promise.all(txList); + + leavesToUpdate.map((leaf, index) => { + offChainTree.updateLeaf(index, leaf); + }); + + // Compare on-chain & off-chain roots + const splCMT = await ConcurrentMerkleTreeAccount.fromAccountAddress(connection, cmt); + const onChainRoot = splCMT.getCurrentRoot(); + + assert( + Buffer.from(onChainRoot).equals(offChainTree.root), + 'Updated on chain root does not match root of updated off chain tree', + ); + }); + it('Empty all of the leaves and close the tree', async () => { + const ixArray: TransactionInstruction[] = []; + const txList: Promise[] = []; + const leavesToUpdate: Buffer[] = []; + for (let i = 0; i < MAX_SIZE; i++) { + const index = i; + const newLeaf = hash(payer.toBuffer(), Buffer.from(new BN(i).toArray())); + leavesToUpdate.push(newLeaf); + const proof = offChainTree.getProof(index); + const replaceIx = createReplaceIx(cmt, payer, Buffer.alloc(32), proof); + ixArray.push(replaceIx); + } + // Execute all replaces + ixArray.map(ix => { + txList.push(execute(provider, [ix], [payerKeypair])); + }); + await Promise.all(txList); + + let payerInfo = await provider.connection.getAccountInfo(payer, 'confirmed')!; + let treeInfo = await provider.connection.getAccountInfo(cmt, 'confirmed')!; + + const payerLamports = payerInfo!.lamports; + const treeLamports = treeInfo!.lamports; + + const ix = createCloseEmptyTreeInstruction({ + authority: payer, + merkleTree: cmt, + recipient: payer, + }); + await execute(provider, [ix], [payerKeypair]); + + payerInfo = await provider.connection.getAccountInfo(payer, 'confirmed')!; + const finalLamports = payerInfo!.lamports; + assert( + finalLamports === payerLamports + treeLamports - 5000, + 'Expected payer to have received the lamports from the closed tree account', + ); + + treeInfo = await provider.connection.getAccountInfo(cmt, 'confirmed'); + assert(treeInfo === null, 'Expected the merkle tree account info to be null'); + }); + it('It cannot be closed until empty', async () => { + const ix = createCloseEmptyTreeInstruction({ + authority: payer, + merkleTree: cmt, + recipient: payer, + }); + try { + await execute(provider, [ix], [payerKeypair]); + assert(false, 'Closing a tree account before it is empty should ALWAYS error'); + } catch {} + }); + }); + + describe(`Having created a tree with depth 3`, () => { + const DEPTH = 3; + beforeEach(async () => { + [cmtKeypair, offChainTree] = await createTreeOnChain(provider, payerKeypair, 0, { + maxBufferSize: 8, + maxDepth: DEPTH, + }); + cmt = cmtKeypair.publicKey; + + for (let i = 0; i < 2 ** DEPTH; i++) { + const newLeaf = Array.from(Buffer.alloc(32, i + 1)); + const appendIx = createAppendIx(cmt, payer, newLeaf); + await execute(provider, [appendIx], [payerKeypair]); + } + + // Compare on-chain & off-chain roots + const splCMT = await ConcurrentMerkleTreeAccount.fromAccountAddress(connection, cmt); + + assert(splCMT.getBufferSize() === 2 ** DEPTH, 'Not all changes were processed'); + assert(splCMT.getCurrentBufferIndex() === 0, 'Not all changes were processed'); + }); + + it('Random attacker fails to fake the existence of a leaf by autocompleting proof', async () => { + const maliciousLeafHash = crypto.randomBytes(32); + const maliciousLeafHash1 = crypto.randomBytes(32); + const nodeProof: Buffer[] = []; + for (let i = 0; i < DEPTH; i++) { + nodeProof.push(Buffer.alloc(32)); + } + + // Root - make this nonsense so it won't match what's in ChangeLog, thus forcing proof autocompletion + const replaceIx = createReplaceIx(cmt, payer, maliciousLeafHash1, { + leaf: maliciousLeafHash, + leafIndex: 0, + proof: nodeProof, + root: Buffer.alloc(32), + }); + + try { + await execute(provider, [replaceIx], [payerKeypair]); + assert(false, 'Attacker was able to successfully write fake existence of a leaf'); + } catch {} + + const splCMT = await ConcurrentMerkleTreeAccount.fromAccountAddress(connection, cmt); + + assert( + splCMT.getCurrentBufferIndex() === 0, + "CMT updated its active index after attacker's transaction, when it shouldn't have done anything", + ); + }); + }); + describe(`Canopy test`, () => { + const DEPTH = 5; + it(`Testing canopy for verify leaf instructions`, async () => { + [cmtKeypair, offChainTree] = await createTreeOnChain( + provider, + payerKeypair, + 2 ** DEPTH, + { maxBufferSize: 8, maxDepth: DEPTH }, + DEPTH, // Store full tree on chain + ); + cmt = cmtKeypair.publicKey; + + const splCMT = await ConcurrentMerkleTreeAccount.fromAccountAddress(connection, cmt, 'confirmed'); + let i = 0; + const stepSize = 4; + while (i < 2 ** DEPTH) { + const ixs: TransactionInstruction[] = []; + for (let j = 0; j < stepSize; j += 1) { + const leafIndex = i + j; + const leaf = offChainTree.leaves[leafIndex].node; + const verifyIx = createVerifyLeafIx(cmt, { + leaf, + leafIndex, + proof: [], + root: splCMT.getCurrentRoot(), + }); + ixs.push(verifyIx); + } + i += stepSize; + await execute(provider, ixs, [payerKeypair]); + } + }); + it('Testing canopy for appends and replaces on a full on chain tree', async () => { + [cmtKeypair, offChainTree] = await createTreeOnChain( + provider, + payerKeypair, + 0, + { maxBufferSize: 8, maxDepth: DEPTH }, + DEPTH, // Store full tree on chain + ); + cmt = cmtKeypair.publicKey; + + // Test that the canopy updates properly throughout multiple modifying instructions + // in the same transaction + const leaves: Array[] = []; + let i = 0; + const stepSize = 4; + while (i < 2 ** DEPTH) { + const ixs: TransactionInstruction[] = []; + for (let j = 0; j < stepSize; ++j) { + const newLeaf = Array.from(Buffer.alloc(32, i + 1)); + leaves.push(newLeaf); + const appendIx = createAppendIx(cmt, payer, newLeaf); + ixs.push(appendIx); + } + await execute(provider, ixs, [payerKeypair]); + i += stepSize; + console.log('Appended', i, 'leaves'); + } + + // Compare on-chain & off-chain roots + let ixs: TransactionInstruction[] = []; + const splCMT = await ConcurrentMerkleTreeAccount.fromAccountAddress(connection, cmt); + const root = splCMT.getCurrentRoot(); + + // Test that the entire state of the tree is stored properly + // by using the canopy to infer proofs to all of the leaves in the tree. + // We test that the canopy is updating properly by replacing all the leaves + // in the tree + const leafList = Array.from(leaves.entries()); + leafList.sort(() => Math.random() - 0.5); + let replaces = 0; + const newLeaves: Record = {}; + for (const [i, leaf] of leafList) { + const newLeaf = crypto.randomBytes(32); + newLeaves[i] = newLeaf; + const replaceIx = createReplaceIx(cmt, payer, newLeaf, { + leaf: Buffer.from(Uint8Array.from(leaf)), + leafIndex: i, + proof: [], + root, // No proof necessary + }); + ixs.push(replaceIx); + if (ixs.length == stepSize) { + replaces++; + await execute(provider, ixs, [payerKeypair]); + console.log('Replaced', replaces * stepSize, 'leaves'); + ixs = []; + } + } + + const newLeafList: Buffer[] = []; + for (let i = 0; i < 32; ++i) { + newLeafList.push(newLeaves[i]); + } + + const tree = new MerkleTree(newLeafList); + + for (let proofSize = 1; proofSize <= 5; ++proofSize) { + const newLeaf = crypto.randomBytes(32); + const i = Math.floor(Math.random() * 32); + const leaf = newLeaves[i]; + + let proof = tree.getProof(i); + const partialProof = proof.proof.slice(0, proofSize); + + // Create an instruction to replace the leaf + const replaceIx = createReplaceIx(cmt, payer, newLeaf, { + ...proof, + proof: partialProof, + }); + tree.updateLeaf(i, newLeaf); + + // Create an instruction to undo the previous replace, but using the now-outdated partialProof + proof = tree.getProof(i); + const replaceBackIx = createReplaceIx(cmt, payer, leaf, { + ...proof, + proof: partialProof, + }); + tree.updateLeaf(i, leaf); + await execute(provider, [replaceIx, replaceBackIx], [payerKeypair], true, true); + } + }); + + it('Should fail to append a canopy node for an existing tree', async () => { + [cmtKeypair, offChainTree] = await createTreeOnChain( + provider, + payerKeypair, + 0, + { maxBufferSize: 8, maxDepth: DEPTH }, + DEPTH, // Store full tree on chain + ); + cmt = cmtKeypair.publicKey; + const appendIx = createAppendCanopyNodesIx(cmt, payer, [crypto.randomBytes(32)], 0); + try { + await execute(provider, [appendIx], [payerKeypair]); + assert(false, 'Appending a canopy node for an existing tree should have failed'); + } catch {} + }); + }); + describe(`Having created a tree with 8 leaves`, () => { + beforeEach(async () => { + [cmtKeypair, offChainTree] = await createTreeOnChain(provider, payerKeypair, 1 << 3, { + maxBufferSize: 8, + maxDepth: 3, + }); + cmt = cmtKeypair.publicKey; + }); + it(`Attempt to replace a leaf beyond the tree's capacity`, async () => { + // Ensure that this fails + const outOfBoundsIndex = 8; + const index = outOfBoundsIndex; + const newLeaf = hash(payer.toBuffer(), Buffer.from(new BN(outOfBoundsIndex).toArray())); + const node = offChainTree.leaves[outOfBoundsIndex - 1].node; + const proof = offChainTree.getProof(index - 1).proof; + + const replaceIx = createReplaceIx(cmt, payer, newLeaf, { + leaf: node, + leafIndex: index, + proof, + root: offChainTree.root, + }); + + try { + await execute(provider, [replaceIx], [payerKeypair]); + throw Error('This replace instruction should have failed because the leaf index is OOB'); + } catch {} + }); + }); +}); diff --git a/account-compression/sdk/tests/accounts/concurrentMerkleTreeAccount.test.ts b/account-compression/sdk/tests/accounts/concurrentMerkleTreeAccount.test.ts new file mode 100644 index 00000000000..5e85aaca0c9 --- /dev/null +++ b/account-compression/sdk/tests/accounts/concurrentMerkleTreeAccount.test.ts @@ -0,0 +1,176 @@ +import { strict as assert } from 'node:assert'; + +import { AnchorProvider } from '@coral-xyz/anchor'; +import NodeWallet from '@coral-xyz/anchor/dist/cjs/nodewallet'; +import { Connection, Keypair, PublicKey } from '@solana/web3.js'; + +import { ALL_DEPTH_SIZE_PAIRS, ConcurrentMerkleTreeAccount, getConcurrentMerkleTreeAccountSize } from '../../src'; +import { emptyNode, MerkleTree } from '../../src/merkle-tree'; +import { createEmptyTreeOnChain, createTreeOnChain } from '../utils'; + +export function assertCMTProperties( + onChainCMT: ConcurrentMerkleTreeAccount, + expectedMaxDepth: number, + expectedMaxBufferSize: number, + expectedAuthority: PublicKey, + expectedRoot: Buffer, + expectedCanopyDepth?: number, + expectedIsBatchInitialized = false, +) { + assert( + onChainCMT.getMaxDepth() === expectedMaxDepth, + `Max depth does not match ${onChainCMT.getMaxDepth()}, expected ${expectedMaxDepth}`, + ); + assert( + onChainCMT.getMaxBufferSize() === expectedMaxBufferSize, + `Max buffer size does not match ${onChainCMT.getMaxBufferSize()}, expected ${expectedMaxBufferSize}`, + ); + assert(onChainCMT.getAuthority().equals(expectedAuthority), 'Failed to write auth pubkey'); + assert(onChainCMT.getCurrentRoot().equals(expectedRoot), 'On chain root does not match root passed in instruction'); + if (expectedCanopyDepth) { + assert( + onChainCMT.getCanopyDepth() === expectedCanopyDepth, + 'On chain canopy depth does not match expected canopy depth', + ); + } + assert( + onChainCMT.getIsBatchInitialized() === expectedIsBatchInitialized, + 'On chain isBatchInitialized does not match expected value', + ); +} + +describe('ConcurrentMerkleTreeAccount tests', () => { + // Configure the client to use the local cluster. + let offChainTree: MerkleTree; + let cmtKeypair: Keypair; + let payerKeypair: Keypair; + let payer: PublicKey; + let connection: Connection; + let provider: AnchorProvider; + + beforeEach(async () => { + payerKeypair = Keypair.generate(); + payer = payerKeypair.publicKey; + connection = new Connection('http://127.0.0.1:8899', { + commitment: 'confirmed', + }); + const wallet = new NodeWallet(payerKeypair); + provider = new AnchorProvider(connection, wallet, { + commitment: connection.commitment, + skipPreflight: true, + }); + + await provider.connection.confirmTransaction( + await provider.connection.requestAirdrop(payer, 1e10), + 'confirmed', + ); + }); + + describe('Can deserialize a CMTAccount from an on-chain CMT with a single leaf', () => { + const MAX_SIZE = 64; + const MAX_DEPTH = 14; + + beforeEach(async () => { + [cmtKeypair, offChainTree] = await createTreeOnChain(provider, payerKeypair, 1, { + maxBufferSize: MAX_SIZE, + maxDepth: MAX_DEPTH, + }); + }); + + it('Interpreted on-chain fields correctly', async () => { + const cmt = await ConcurrentMerkleTreeAccount.fromAccountAddress( + connection, + cmtKeypair.publicKey, + 'confirmed', + ); + + await assertCMTProperties(cmt, MAX_DEPTH, MAX_SIZE, payer, offChainTree.root); + }); + }); + + describe('Test deserialization for available depth-size pairs', () => { + it('Test all pairs', async () => { + for (const depthSizePair of ALL_DEPTH_SIZE_PAIRS) { + // Airdrop enough SOL to cover tree creation + const size = getConcurrentMerkleTreeAccountSize(depthSizePair.maxDepth, depthSizePair.maxBufferSize); + const rent = await connection.getMinimumBalanceForRentExemption(size, 'confirmed'); + const airdropId = await connection.requestAirdrop(payer, rent + 5000 * 2); + await connection.confirmTransaction(airdropId, 'confirmed'); + + // Create on chain tree + cmtKeypair = await createEmptyTreeOnChain(provider, payerKeypair, depthSizePair); + const cmt = await ConcurrentMerkleTreeAccount.fromAccountAddress( + connection, + cmtKeypair.publicKey, + 'confirmed', + ); + + // Verify it was initialized correctly + await assertCMTProperties( + cmt, + depthSizePair.maxDepth, + depthSizePair.maxBufferSize, + payer, + emptyNode(depthSizePair.maxDepth), + ); + } + }); + }); + + describe('Test deserialization for canopy size for depth 30 tree', () => { + it('Test all pairs', async () => { + const maxDepth = 30; + const maxBufferSize = 2048; + + for (let canopyDepth = 1; canopyDepth <= 14; canopyDepth++) { + // Airdrop enough SOL to cover tree creation + const size = getConcurrentMerkleTreeAccountSize(maxDepth, maxBufferSize, canopyDepth); + const rent = await connection.getMinimumBalanceForRentExemption(size, 'confirmed'); + const airdropId = await connection.requestAirdrop(payer, rent + 5000 * 2); + await connection.confirmTransaction(airdropId, 'confirmed'); + + // Create on chain tree + cmtKeypair = await createEmptyTreeOnChain( + provider, + payerKeypair, + { maxBufferSize, maxDepth }, + canopyDepth, + ); + const cmt = await ConcurrentMerkleTreeAccount.fromAccountAddress( + connection, + cmtKeypair.publicKey, + 'confirmed', + ); + + // Verify it was initialized correctly + await assertCMTProperties(cmt, maxDepth, maxBufferSize, payer, emptyNode(maxDepth), canopyDepth); + } + }); + }); + + describe('Can deserialize an existing CMTAccount from a real on-chain CMT created before the is_batch_initialized field was introduced inplace of the first byte of _padding', () => { + it('Interpreted on-chain fields correctly', async () => { + // The account data was generated by running: + // $ solana account 27QMkDMpBoAhmWj6xxQNYdqXZL5nnC8tkZcEtkNxCqeX \ + // --output-file tests/fixtures/pre-batch-init-tree-account.json \ + // --output json + const deployedAccount = new PublicKey('27QMkDMpBoAhmWj6xxQNYdqXZL5nnC8tkZcEtkNxCqeX'); + const cmt = await ConcurrentMerkleTreeAccount.fromAccountAddress(connection, deployedAccount, 'confirmed'); + const expectedMaxDepth = 10; + const expectedMaxBufferSize = 32; + const expectedCanopyDepth = 0; + const expectedAuthority = new PublicKey('BFNT941iRwYPe2Js64dTJSoksGCptWAwrkKMaSN73XK2'); + const expectedRoot = new PublicKey('83UjseEuEgxyVyDTmrJCQ9QbeksdRZ7KPDZGQYc5cAgF').toBuffer(); + const expectedIsBatchInitialized = false; + await assertCMTProperties( + cmt, + expectedMaxDepth, + expectedMaxBufferSize, + expectedAuthority, + expectedRoot, + expectedCanopyDepth, + expectedIsBatchInitialized, + ); + }); + }); +}); diff --git a/account-compression/sdk/tests/events/applicationData.test.ts b/account-compression/sdk/tests/events/applicationData.test.ts new file mode 100644 index 00000000000..8f82490348d --- /dev/null +++ b/account-compression/sdk/tests/events/applicationData.test.ts @@ -0,0 +1,24 @@ +import { strict as assert } from 'node:assert'; + +import { BN } from 'bn.js'; + +import { deserializeApplicationDataEvent } from '../../src'; + +describe('Serde tests', () => { + describe('ApplicationDataEvent tests', () => { + it('Can serialize and deserialize ApplicationDataEvent', () => { + const data = Buffer.from('Hello world'); + const applicationDataEvent = Buffer.concat([ + Buffer.from([0x1]), // ApplicationData Event tag + Buffer.from([0x0]), // version 0 tag + Buffer.from(new BN.BN(data.length).toArray('le', 4)), // Size of application data (for Vec) + data, // serialized application data (for Vec) + ]); + + const deserialized = deserializeApplicationDataEvent(applicationDataEvent); + const decoder = new TextDecoder(); + const deserializedData = decoder.decode(deserialized.fields[0].applicationData); + assert('Hello world' === deserializedData); + }); + }); +}); diff --git a/account-compression/sdk/tests/events/changelog.test.ts b/account-compression/sdk/tests/events/changelog.test.ts new file mode 100644 index 00000000000..114e8a9d5f7 --- /dev/null +++ b/account-compression/sdk/tests/events/changelog.test.ts @@ -0,0 +1,100 @@ +import { strict as assert } from 'node:assert'; + +import { AnchorProvider } from '@coral-xyz/anchor'; +import NodeWallet from '@coral-xyz/anchor/dist/cjs/nodewallet'; +import { bs58 } from '@coral-xyz/anchor/dist/cjs/utils/bytes'; +import { Connection, Keypair, PublicKey } from '@solana/web3.js'; +import { BN } from 'bn.js'; +import * as crypto from 'crypto'; + +import { createAppendIx, deserializeChangeLogEventV1, SPL_NOOP_PROGRAM_ID } from '../../src'; +import { MerkleTree } from '../../src/merkle-tree'; +import { createTreeOnChain, execute } from '../utils'; + +describe('Serde tests', () => { + let offChainTree: MerkleTree; + let cmtKeypair: Keypair; + let payerKeypair: Keypair; + let payer: PublicKey; + let connection: Connection; + let provider: AnchorProvider; + + const MAX_SIZE = 64; + const MAX_DEPTH = 14; + + beforeEach(async () => { + payerKeypair = Keypair.generate(); + payer = payerKeypair.publicKey; + + connection = new Connection('http://127.0.0.1:8899', { + commitment: 'confirmed', + }); + const wallet = new NodeWallet(payerKeypair); + provider = new AnchorProvider(connection, wallet, { + commitment: connection.commitment, + skipPreflight: true, + }); + + await provider.connection.confirmTransaction( + await provider.connection.requestAirdrop(payer, 1e10), + 'confirmed', + ); + }); + describe('ChangeLogEvent tests', () => { + let cmt: PublicKey; + beforeEach(async () => { + [cmtKeypair, offChainTree] = await createTreeOnChain(provider, payerKeypair, 0, { + maxBufferSize: MAX_SIZE, + maxDepth: MAX_DEPTH, + }); + cmt = cmtKeypair.publicKey; + }); + it('Can deserialize a ChangeLogEvent', async () => { + const newLeaf = crypto.randomBytes(32); + const txId = await execute(provider, [createAppendIx(cmt, payer, newLeaf)], [payerKeypair]); + offChainTree.updateLeaf(0, newLeaf); + + const transaction = await connection.getTransaction(txId, { + commitment: 'confirmed', + maxSupportedTransactionVersion: 2, + }); + + // Get noop program instruction + const accountKeys = transaction!.transaction.message.getAccountKeys(); + const noopInstruction = transaction!.meta!.innerInstructions![0].instructions[0]; + const programId = accountKeys.get(noopInstruction.programIdIndex)!; + if (!programId.equals(SPL_NOOP_PROGRAM_ID)) { + throw Error(`Only inner ix should be a noop, but instead is a ${programId.toBase58()}`); + } + const cpiData = Buffer.from(bs58.decode(noopInstruction.data)); + const changeLogEvent = deserializeChangeLogEventV1(cpiData); + + assert( + changeLogEvent.treeId.equals(cmt), + `Tree id in changeLog differs from expected tree ${cmt.toBase58()}`, + ); + assert(changeLogEvent.index === 0, `ChangeLog should have index 0, but has index ${changeLogEvent.index}`); + assert( + new BN.BN(changeLogEvent.seq).toNumber() === 1, + `ChangeLog should have sequence number of 1, but has seq number of ${changeLogEvent.seq.toString()}`, + ); + + // Check that the emitted ChangeLog path matches up with the updated Tree + let nodeIndex = 0 + (1 << MAX_DEPTH); + let realTreeNode = offChainTree.leaves[0]; + while (nodeIndex > 0) { + const clNode = changeLogEvent.path.shift()!; + assert( + nodeIndex === clNode.index, + `Expected changeLog index to be ${nodeIndex} but is ${clNode.index}`, + ); + assert( + realTreeNode!.node.equals(Buffer.from(clNode.node)), + `ChangeLog node differs at node index: ${clNode.index}`, + ); + realTreeNode = realTreeNode.parent!; + nodeIndex = nodeIndex >> 1; + } + }); + }); +}); diff --git a/account-compression/sdk/tests/fixtures/pre-batch-init-tree-account.json b/account-compression/sdk/tests/fixtures/pre-batch-init-tree-account.json new file mode 100644 index 00000000000..98adaa774dc --- /dev/null +++ b/account-compression/sdk/tests/fixtures/pre-batch-init-tree-account.json @@ -0,0 +1,14 @@ +{ + "pubkey": "27QMkDMpBoAhmWj6xxQNYdqXZL5nnC8tkZcEtkNxCqeX", + "account": { + "lamports": 84132480, + "data": [ + "AQAgAAAACgAAAJhDQUO8VHxyuU2+8Gbazk9rGe2MW3Xu3mPjn5qN+Mnd8qEyDgAAAAAAAAAAAAAJAAAAAAAAAAkAAAAAAAAACgAAAAAAAAD53D5/4BbgUO/yYDNPGKXU/jkdggkjGfWWTy4ut8HDpQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArTIotnb3081ChKVEPxfxlis25JGzCkCyQFhJ5Ze6X7W0wRlRlXxvj2QsSvYc1rJGQP7G3H/GB+6CBqmekkENMCHduaNWgVw/rBAmtt7F3zEkr7rbSFybpaPjOYoEt7qF5Ydpsyob6vHqJzdaRAlaDR+2ZM4t01jn/L+3jCahk0QOsB6/ye0nUAzU38l5Jy0fCRPMn2ZUDX6ABYERCeHPLYh8Ir2HUNNAFqw8ZrX/EC2s3XP2sBTnELUegCKvmhlo/9cBV+SAY/wzyXoFD39kAjO/ZGzJjZUkxrkrzzq1b4OYZ8xffxlrk7rh4n5jIHQkRdKQ8iY4J0mLVP7FOfdWr8761OUIwJi5p+HY/rGZVfsCupZ1WFB4cQlp00QPUFTgAAAAAAAAAABCQcymud9cvMqkqaz7rb8B4fJGipunRCEkcpIwwf1bqgG0jc8ty2NKzqQ11mfpEgaWHx71Zkd+KhVW6g9RF++oo50UCdctGN9/Yj9M997BjhZjf9P0egTPElcLkXHmGEjtm+CkQBf+3Sbkkq2UmWgP+WnCKKzej7Rk25CTxmlTwR0oez8apwcYlgkfdQNxr3jMbmyJlZungLUL0qdF54IhXXYkra5BQiu8imQXVs5vHpaJmrjUhQCiQT0GdoO+zap3nFWBCJyTSPURgM3qEQhr6WeAPbarDAZnu2Hn6KOJBJiGW8/Mdyb2UHzslHH5v92pUD262jHxv9Dxka11yDv8R21qTggJggnyd9Y9xfFQJmMOlsHxK/OXAbJx15vj+kmxMg/C5+70VPL35eDhb5k8H351PyxQoZH0RK2eXBcIbwO6kdDpcOt1lYsFGxVJOtPzJ+Eq2c5sWwdFSlaopv7WAAAAAAAAAAC4lUsocxFm8dZSnJRk0dztzMPjp1Tw++Vr9kJl2nwJK9rUpl3vmHv+1y5vONxkqse+I11hYnCbfPjlMwi1H3TGbXub1fM1JIxVi6J8yee8q1pLyvHD6l8RgltY7GeLcH/U4Ya37FWODitELZNDut7d8YRI66XliIh458WBFM9ZkWXQAtLrm0fso9F+CE4K2hmZHGSd1tnCGMe1CN5PYnAd32gpAsQAHgFgjiYdxQ+Ezfk2PTE2KL6ltcvyeQ2fVk/xBR50NHfWV4D8JytRVz0YXRQ3fYf4EniFtQtPmQ2CntMT1AroOs/TbheIWHf427xgdUB6Nbd0xZqaRnp3PgDnBy4iDWhVohnVlke8mes2HV+4PTvKtS8QvSek76DrEV0oeh2SM/j5OOPFLfsK2gHRGX20vcKOYa3Rcs9g7X+F3uMazFbBC/vFwbCK/Pfjhmj6ZWod2MSVhsq2Xn9ezssqAQAAAAAAAAARmQ/IUesWNRXIOks0o34cvGsvVMbFCIZqluF+zkUg3hdpJ3DYGBOMaX3Jtz5u3/HqSrb4Uio0kx5VrkfTuCStLPB7V+PqjzBlN326Cg9WoxfTC6nEgo++DbKYbMIW+kYXnWqnD0lliL2PQlq/MxvtOYbZSWYNIg687iKjYnZpTKfNIilBb7JXh6KfMm2xDEpsmNy+djJBXPNfcB9y90yP7xXZA4/4HL5hPpQTNnestf54Wvoo2ZFUKHF/b1hmH7EzF4X5SJlrI/RlinkvdEjGtPzaIL2jYEjQ2S0rSYMD9impk0XbfWrsrHNs8UwnVVrAzmYtnvI0q4YFRoHl0hO45BUJhpj4wEBrSEt11HdPrSj9ENeYuMHmDeN8j7I3oZ0YQ8BhI/FSTMKss2tGL8oa0Z0QPCvQHmL+6bAj38xXGmE/mHkgRdP2Cfy9f++ql/p2oA0Fh6zlzDHT5GjR1V4aAgAAAAAAAAB8dN1Ir+WmUJgJmzlUI8WF6f4d7ht9QkK/wnbsSBjBRpJkz7UEmWcwil8CTYmNwaV2Du1lW32sVcgVEJujtpMImqpKqpjfJAV7T+VhZOwOrz4Cxbhy0Uk6AP5Dzt03oE2am+sbNkvl+u4EBJ7nI9+OF5a2fd+T8QZNfFKuK+sbcJ5MDyIH+szPX7DliqrMLVHTov3qzMMT1BnoZIM7oxf94ksHIuS7WwOlsyXxkLuD/r+QiLUacD4bdxSxxR8+5YlhEhEUKbOZvMJCq4o+0LWkNvYGY7Dy4J3MbXY4yzp/VEu7WuifydqNvwfmiHT9Z/o5T4z1ApBoFyXyblXRAJH9FwVy0dLmQP9M13f6Akv1vxEzPg4SaSZcwK1onN8GLnvz2b4OH2bpevfc8pZId4ukEjaMURY9n7GtYyuvIK8rZS9OoNUDYlgULbDKfheL6sYW/j5plzTZOxRDjZIMyX4pAwAAAAAAAADNp9MXV4O0q8K4yJ4rPS4VXwuq4t6hgk27MVZJKGlunsiS1BPzCUsYrjY3HC+M6PP9IYX6/C1lnCIJ0o+cGJbYD19oYWHldkOUktrvzv1YeIT02RPpXgD7krjwyw6GMkhnmRHM08ykLrx+su31lZ/7InhGHjMGkXE2RSSpISmXIKyTFqBiz4VpTggxrfX9+GjlvMNkhfOFIfePNnEkf+68dCkpR1dgZNsp8j7B2L6NTDXn0xlzzOFCPdYIW+khPYsvornwd8zpbJ5MrdNJ83iC52PruW+e81UFB2tsjX/V8hfGsXTW9Himu9kyZl20vhO5ySw0Z75NoEX2FF5w7z1I9BgV2QhCFgzt0zrTY6OZbibtCjzVuhbEcXSt78iQY6P4u2kfGGabhJ8jRzmrTl7fXpjX/NASK+oOTkveW5gvCh+4k9wetZPvkoCJOSj7rPsxrFs4ac13sWE6OK/Vu+yABAAAAAAAAACMUJhFEGPVsytUOFCvzFCerXY67FhmJvjd7P8/Ab3J9VSkSuNkq51kaKlKK1xhWXrj1UgdBRbh1Esks6jgfWyPNinZuBr83cBaOA09aMy5pE4aD3NM9VnTXi/qfIRcTBhYE15K4fr+Qq+1stfqGG79wM9CwprrCpltIbuAoTjySt4mWHDzbROyEl4QNmaCm/GMyIT5joPvINeBDngrSmzV7J1lAC0hj27wLpADHGbGmL21SgKBIka32HJvVbRnN6GCL+Bk7OmUUNnUoKK0c/mlFguIN7DoiyOWdhCHN3YbM23aZIHefz1HkjUMnW4sIP3jF5I9Za+lJLOR+Y80vL/X8P2Ti5wEFqYOTNjg+y6Yz20KF7Z2GCwOTSgIEshFms939zWviwqjq1KT5KeHoyAVUuHXe6ZaI2l9FIhLOlFDZFz/39I24yvRY3ZCp6XhC5X9EbwbXJ7+dwCwQgbzES1ABQAAAAAAAABjqS9H5fcSRNDGyBaFKz79o8xeMIRKzzlT7sFa/bMX3kkyS5iXq/g0JVqbjB2dQajXxf9E3+IOICDQd1ZPSxHDFJSUjQD9vX44uD9ITmVSGxgS7j59qA7RCYXZadRg+TMmfB9Ji2xLITEiD31ZnNzCAjTvf2nYowheYXqzIK2OpXKvcAwtvYZ6jQUXYQN8MbRpugjApKVETYk3uXwnZE3VK8i5NLxjGokDVRdbGjlKV4Whugr31MZOvQrOhpW0vO3C97zgdgI/HyNGJeILnH3Xjn0b47Lzq1r/0FJx/ECc5D2kXvbpgCQLc1b69+hVg1N4H9/qvMCtpYwILqNbk0My1FzSfUupEqsFEcfhiVXz2uM5JaUm5ei0h8S2zmH/eBAz4smlHxG/xtAT3NnLmEUkI1jtSnIquo2kuKrOoU7Dyv2AE0zHGJRLQGwDCzfDasneG68qjdK7WioqemFHYB5GBgAAAAAAAAC67j8goNDnD6JGvBqXvwGS77IyYa56EExRm96UvuqOjz6G8UCwmDpNdjVbd0qr1ViFXTtoozYLJPsM1Q3xmxPxAKRZU70n/FaS1N4p4SPQ/TN7i+a/rph3DHMrpd3RsI7OyYZIRPCCqLdQrpA7xz4lXRaEt9hqN96n4UJvafy3d1CQJss98bv5Y+8je4Wb+bqavGOBnT7XQlrcTPnMTYIsJjE5Wjv8iP1IUuo0C4QsTF6CFGT7dfIf3sQx8O7Coz1dficqvARL6riF3SlIZ9V0K7YWDinCWUSqt9s2jul37QjE/wYvGg7E8lz2yeVpXXjDxl4gh1GzOEn0OWDTc+XzJ/yNCzDeI0Z/52C1rj9hMf2D5/Cl5DJAR4HJsk7nVMV9QT88uOxYi5TWVR2qChpSJ0pULmoPTLAiyW47/g7yfqLPJ+8vhMP2TXv7rcnviSHPo2CGxSBc4ZmhpojK3pY1BwAAAAAAAABopFW8eCE4hGyMUCyvKkQ+GSMhBfrBc6HcBAOIRfpeAPWxOuEEHeBOEdf46B5t7j+RhQ6FEju+knqr9ZyHLaiTGWyc6JkD47GcNMQmldLaVovSYKtB+BESBYjL0jLzGCp58k+YbjuCUpp6iImugZizQSMOYtYVUjbc1DyM3IdHVsohegHZOROewEmAImpFV56O8G+tCcYlnRWQI2cfduj9GjJOGcVqB3xYTcV9WEc1Yrr1JtHSWI4W3r3zo2UbnSpDmpI3fmG2VuvHQLh5h8sFt/1fgrRkI5yZ5eFPHsp1E7LHzoD5y/rVHBYsqKhxKPOgWrUJnXjUrwNJfB1RNWQPzXMz/WJ1OdGvxQOsnVfqLrh7VS9pDPqS+FuJPoX66qT3pdemBFWruc87OG9JPadnG6whSDrCnPiAswOYQL0ArJGPPuHqjtPw/OTL2DDIvOy08OYVQfJiJ2cHEuJaSNrICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK0yKLZ299PNQoSlRD8X8ZYrNuSRswpAskBYSeWXul+1tMEZUZV8b49kLEr2HNayRkD+xtx/xgfuggapnpJBDTBQkCbLPfG7+WPvI3uFm/m6mrxjgZ0+10Ja3Ez5zE2CLOWHabMqG+rx6ic3WkQJWg0ftmTOLdNY5/y/t4wmoZNEDrAev8ntJ1AM1N/JeSctHwkTzJ9mVA1+gAWBEQnhzy2IfCK9h1DTQBasPGa1/xAtrN1z9rAU5xC1HoAir5oZaP/XAVfkgGP8M8l6BQ9/ZAIzv2RsyY2VJMa5K886tW+DmGfMX38Za5O64eJ+YyB0JEXSkPImOCdJi1T+xTn3Vq/O+tTlCMCYuafh2P6xmVX7ArqWdVhQeHEJadNED1BU4PWxOuEEHeBOEdf46B5t7j+RhQ6FEju+knqr9ZyHLaiTCQAAAAAAAAA=", + "base64" + ], + "owner": "cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK", + "executable": false, + "rentEpoch": 18446744073709551615, + "space": 11960 + } +} \ No newline at end of file diff --git a/account-compression/sdk/tests/merkleTree.test.ts b/account-compression/sdk/tests/merkleTree.test.ts new file mode 100644 index 00000000000..1ecc6763b2d --- /dev/null +++ b/account-compression/sdk/tests/merkleTree.test.ts @@ -0,0 +1,31 @@ +import { strict as assert } from 'node:assert'; + +import * as crypto from 'crypto'; + +import { emptyNode, MerkleTree } from '../src'; + +describe('MerkleTree tests', () => { + it('Check constructor equivalence for depth 2 tree', () => { + const leaves = [crypto.randomBytes(32), crypto.randomBytes(32), crypto.randomBytes(32)]; + const rawLeaves = leaves.concat(emptyNode(0)); + const merkleTreeRaw = new MerkleTree(rawLeaves); + const merkleTreeSparse = MerkleTree.sparseMerkleTreeFromLeaves(leaves, 2); + + assert(merkleTreeRaw.root.equals(merkleTreeSparse.root)); + }); + + const TEST_DEPTH = 14; + it(`Check proofs for 2^${TEST_DEPTH} tree`, () => { + const leaves: Buffer[] = []; + for (let i = 0; i < 2 ** TEST_DEPTH; i++) { + leaves.push(crypto.randomBytes(32)); + } + const merkleTree = new MerkleTree(leaves); + + // Check proofs + for (let i = 0; i < leaves.length; i++) { + const proof = merkleTree.getProof(i); + assert(MerkleTree.verify(merkleTree.getRoot(), proof)); + } + }); +}); diff --git a/account-compression/sdk/tests/utils.ts b/account-compression/sdk/tests/utils.ts new file mode 100644 index 00000000000..4e49c305c71 --- /dev/null +++ b/account-compression/sdk/tests/utils.ts @@ -0,0 +1,148 @@ +import { AnchorProvider } from '@coral-xyz/anchor'; +import { Keypair, SendTransactionError, Signer, Transaction, TransactionInstruction } from '@solana/web3.js'; +import * as crypto from 'crypto'; + +import { + createAllocTreeIx, + createAppendIx, + createInitEmptyMerkleTreeIx, + prepareTreeIx, + ValidDepthSizePair, +} from '../src'; +import { MerkleTree } from '../src/merkle-tree'; + +/// Wait for a transaction of a certain id to confirm and optionally log its messages +export async function confirmAndLogTx(provider: AnchorProvider, txId: string, verbose = false) { + const tx = await provider.connection.confirmTransaction(txId, 'confirmed'); + if (tx.value.err || verbose) { + console.log((await provider.connection.getTransaction(txId, { commitment: 'confirmed' }))!.meta!.logMessages); + } + if (tx.value.err) { + console.log('Transaction failed'); + throw new Error(JSON.stringify(tx.value.err)); + } +} + +/// Execute a series of instructions in a txn +export async function execute( + provider: AnchorProvider, + instructions: TransactionInstruction[], + signers: Signer[], + skipPreflight = false, + verbose = false, +): Promise { + let tx = new Transaction(); + instructions.map(ix => { + tx = tx.add(ix); + }); + + let txid: string | null = null; + try { + txid = await provider.sendAndConfirm!(tx, signers, { + skipPreflight, + }); + } catch (e) { + if (e instanceof SendTransactionError) { + console.log('Tx error!', e.logs); + } + throw e; + } + + if (verbose && txid) { + console.log((await provider.connection.getTransaction(txid, { commitment: 'confirmed' }))!.meta!.logMessages); + } + + return txid; +} + +export async function createTreeOnChain( + provider: AnchorProvider, + payer: Keypair, + numLeaves: number, + depthSizePair: ValidDepthSizePair, + canopyDepth = 0, +): Promise<[Keypair, MerkleTree]> { + const cmtKeypair = Keypair.generate(); + + const leaves = Array(2 ** depthSizePair.maxDepth).fill(Buffer.alloc(32)); + for (let i = 0; i < numLeaves; i++) { + leaves[i] = crypto.randomBytes(32); + } + const tree = new MerkleTree(leaves); + + const allocAccountIx = await createAllocTreeIx( + provider.connection, + cmtKeypair.publicKey, + payer.publicKey, + depthSizePair, + canopyDepth, + ); + + const ixs = [allocAccountIx, createInitEmptyMerkleTreeIx(cmtKeypair.publicKey, payer.publicKey, depthSizePair)]; + + const txId = await execute(provider, ixs, [payer, cmtKeypair]); + if (canopyDepth) { + await confirmAndLogTx(provider, txId as string); + } + + if (numLeaves) { + const nonZeroLeaves = leaves.slice(0, numLeaves); + let appendIxs: TransactionInstruction[] = nonZeroLeaves.map(leaf => { + return createAppendIx(cmtKeypair.publicKey, payer.publicKey, leaf); + }); + while (appendIxs.length) { + const batch = appendIxs.slice(0, 5); + await execute(provider, batch, [payer]); + appendIxs = appendIxs.slice(5); + } + } + return [cmtKeypair, tree]; +} + +export async function createEmptyTreeOnChain( + provider: AnchorProvider, + payer: Keypair, + depthSizePair: ValidDepthSizePair, + canopyDepth = 0, +): Promise { + const cmtKeypair = Keypair.generate(); + const allocAccountIx = await createAllocTreeIx( + provider.connection, + cmtKeypair.publicKey, + payer.publicKey, + depthSizePair, + canopyDepth, + ); + + const ixs = [allocAccountIx, createInitEmptyMerkleTreeIx(cmtKeypair.publicKey, payer.publicKey, depthSizePair)]; + + const txId = await execute(provider, ixs, [payer, cmtKeypair]); + await confirmAndLogTx(provider, txId as string); + + return cmtKeypair; +} + +export type PrepareTreeArgs = { + canopyDepth: number; + depthSizePair: ValidDepthSizePair; + payer: Keypair; + provider: AnchorProvider; +}; + +export async function prepareTree(args: PrepareTreeArgs): Promise { + const { provider, payer, depthSizePair, canopyDepth } = args; + const cmtKeypair = Keypair.generate(); + const allocAccountIx = await createAllocTreeIx( + provider.connection, + cmtKeypair.publicKey, + payer.publicKey, + depthSizePair, + canopyDepth, + ); + + const ixs = [allocAccountIx, prepareTreeIx(cmtKeypair.publicKey, payer.publicKey, depthSizePair)]; + + const txId = await execute(provider, ixs, [payer, cmtKeypair]); + await confirmAndLogTx(provider, txId as string); + return cmtKeypair; +} diff --git a/account-compression/sdk/tsconfig.base.json b/account-compression/sdk/tsconfig.base.json new file mode 100644 index 00000000000..ed98ba42620 --- /dev/null +++ b/account-compression/sdk/tsconfig.base.json @@ -0,0 +1,15 @@ +{ + "include": [], + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "Node", + "esModuleInterop": true, + "isolatedModules": true, + "noEmitOnError": true, + "resolveJsonModule": true, + "strict": true, + "stripInternal": true, + "typeRoots": ["node_modules/@types"] + } +} diff --git a/account-compression/sdk/tsconfig.json b/account-compression/sdk/tsconfig.json new file mode 100644 index 00000000000..e175d1bfd7a --- /dev/null +++ b/account-compression/sdk/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.base.json", + "include": ["src", "tests"], + "compilerOptions": { + "outDir": "dist/cjs/", + "declarationDir": "dist/types", + "sourceMap": true, + "declaration": true, + "declarationMap": true, + "target": "ES2016", + "module": "CommonJS" + } +} diff --git a/account-compression/sdk/typedoc.json b/account-compression/sdk/typedoc.json new file mode 100644 index 00000000000..265991d0559 --- /dev/null +++ b/account-compression/sdk/typedoc.json @@ -0,0 +1,6 @@ +{ + "entryPoints": ["src/index.ts", "src/merkle-tree/index.ts"], + "excludeInternal": true, + "excludePrivate": false, + "out": "doc" +} diff --git a/associated-token-account/README.md b/associated-token-account/README.md new file mode 100644 index 00000000000..5ed8fdcbbe1 --- /dev/null +++ b/associated-token-account/README.md @@ -0,0 +1,2 @@ +NOTE: The associated-token-account program and clients are now maintained at +[solana-program/associated-token-account](https://github.com/solana-program/associated-token-account). diff --git a/associated-token-account/program/Cargo.toml b/associated-token-account/program/Cargo.toml deleted file mode 100644 index 59181b05437..00000000000 --- a/associated-token-account/program/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -name = "spl-associated-token-account" -version = "1.0.5" -description = "Solana Program Library Associated Token Account" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana-program-library" -license = "Apache-2.0" -edition = "2018" - -[features] -no-entrypoint = [] -test-bpf = [] - -[dependencies] -assert_matches = "1.5.0" -borsh = "0.9.1" -num-derive = "0.3" -num-traits = "0.2" -solana-program = "1.10.33" -spl-token = { version = "3.3", path = "../../token/program", features = ["no-entrypoint"] } -spl-token-2022 = { version = "0.4", path = "../../token/program-2022", features = ["no-entrypoint"] } -thiserror = "1.0" - -[dev-dependencies] -solana-program-test = "1.10.33" -solana-sdk = "1.10.33" - -[lib] -crate-type = ["cdylib", "lib"] - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] diff --git a/associated-token-account/program/program-id.md b/associated-token-account/program/program-id.md deleted file mode 100644 index de8233b720f..00000000000 --- a/associated-token-account/program/program-id.md +++ /dev/null @@ -1 +0,0 @@ -ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL diff --git a/associated-token-account/program/run-tests.sh b/associated-token-account/program/run-tests.sh deleted file mode 100755 index 74e4f115360..00000000000 --- a/associated-token-account/program/run-tests.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -set -ex -cd "$(dirname "$0")" -cargo clippy -cargo build -cargo build-bpf - -if [[ $1 = -v ]]; then - export RUST_LOG=solana=debug -fi - -cargo test -cargo test-bpf diff --git a/associated-token-account/program/src/entrypoint.rs b/associated-token-account/program/src/entrypoint.rs deleted file mode 100644 index 82641a41587..00000000000 --- a/associated-token-account/program/src/entrypoint.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! Program entrypoint - -#![cfg(not(feature = "no-entrypoint"))] - -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, pubkey::Pubkey, -}; - -entrypoint!(process_instruction); -fn process_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - instruction_data: &[u8], -) -> ProgramResult { - crate::processor::process_instruction(program_id, accounts, instruction_data) -} diff --git a/associated-token-account/program/src/error.rs b/associated-token-account/program/src/error.rs deleted file mode 100644 index ae858a0d537..00000000000 --- a/associated-token-account/program/src/error.rs +++ /dev/null @@ -1,26 +0,0 @@ -//! Error types - -use { - num_derive::FromPrimitive, - solana_program::{decode_error::DecodeError, program_error::ProgramError}, - thiserror::Error, -}; - -/// Errors that may be returned by the program. -#[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] -pub enum AssociatedTokenAccountError { - // 0 - /// Associated token account owner does not match address derivation - #[error("Associated token account owner does not match address derivation")] - InvalidOwner, -} -impl From for ProgramError { - fn from(e: AssociatedTokenAccountError) -> Self { - ProgramError::Custom(e as u32) - } -} -impl DecodeError for AssociatedTokenAccountError { - fn type_of() -> &'static str { - "AssociatedTokenAccountError" - } -} diff --git a/associated-token-account/program/src/instruction.rs b/associated-token-account/program/src/instruction.rs deleted file mode 100644 index cdbe21909e4..00000000000 --- a/associated-token-account/program/src/instruction.rs +++ /dev/null @@ -1,160 +0,0 @@ -//! Program instructions - -use { - crate::{get_associated_token_address_with_program_id, id}, - assert_matches::assert_matches, - borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, - solana_program::{ - instruction::{AccountMeta, Instruction}, - pubkey::Pubkey, - }, -}; - -/// Instructions supported by the AssociatedTokenAccount program -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] -pub enum AssociatedTokenAccountInstruction { - /// Creates an associated token account for the given wallet address and token mint - /// Returns an error if the account exists. - /// - /// 0. `[writeable,signer]` Funding account (must be a system account) - /// 1. `[writeable]` Associated token account address to be created - /// 2. `[]` Wallet address for the new associated token account - /// 3. `[]` The token mint for the new associated token account - /// 4. `[]` System program - /// 5. `[]` SPL Token program - Create, - /// Creates an associated token account for the given wallet address and token mint, - /// if it doesn't already exist. Returns an error if the account exists, - /// but with a different owner. - /// - /// 0. `[writeable,signer]` Funding account (must be a system account) - /// 1. `[writeable]` Associated token account address to be created - /// 2. `[]` Wallet address for the new associated token account - /// 3. `[]` The token mint for the new associated token account - /// 4. `[]` System program - /// 5. `[]` SPL Token program - CreateIdempotent, - /// Transfers from and closes a nested associated token account: an - /// associated token account owned by an associated token account. - /// - /// The tokens are moved from the nested associated token account to the - /// wallet's associated token account, and the nested account lamports are - /// moved to the wallet. - /// - /// Note: Nested token accounts are an anti-pattern, and almost always - /// created unintentionally, so this instruction should only be used to - /// recover from errors. - /// - /// 0. `[writeable]` Nested associated token account, must be owned by `3` - /// 1. `[]` Token mint for the nested associated token account - /// 2. `[writeable]` Wallet's associated token account - /// 3. `[]` Owner associated token account address, must be owned by `5` - /// 4. `[]` Token mint for the owner associated token account - /// 5. `[writeable, signer]` Wallet address for the owner associated token account - /// 6. `[]` SPL Token program - RecoverNested, -} - -fn build_associated_token_account_instruction( - funding_address: &Pubkey, - wallet_address: &Pubkey, - token_mint_address: &Pubkey, - token_program_id: &Pubkey, - instruction: AssociatedTokenAccountInstruction, -) -> Instruction { - let associated_account_address = get_associated_token_address_with_program_id( - wallet_address, - token_mint_address, - token_program_id, - ); - // safety check, assert if not a creation instruction - assert_matches!( - instruction, - AssociatedTokenAccountInstruction::Create - | AssociatedTokenAccountInstruction::CreateIdempotent - ); - Instruction { - program_id: id(), - accounts: vec![ - AccountMeta::new(*funding_address, true), - AccountMeta::new(associated_account_address, false), - AccountMeta::new_readonly(*wallet_address, false), - AccountMeta::new_readonly(*token_mint_address, false), - AccountMeta::new_readonly(solana_program::system_program::id(), false), - AccountMeta::new_readonly(*token_program_id, false), - ], - data: instruction.try_to_vec().unwrap(), - } -} - -/// Creates Create instruction -pub fn create_associated_token_account( - funding_address: &Pubkey, - wallet_address: &Pubkey, - token_mint_address: &Pubkey, - token_program_id: &Pubkey, -) -> Instruction { - build_associated_token_account_instruction( - funding_address, - wallet_address, - token_mint_address, - token_program_id, - AssociatedTokenAccountInstruction::Create, - ) -} - -/// Creates CreateIdempotent instruction -pub fn create_associated_token_account_idempotent( - funding_address: &Pubkey, - wallet_address: &Pubkey, - token_mint_address: &Pubkey, - token_program_id: &Pubkey, -) -> Instruction { - build_associated_token_account_instruction( - funding_address, - wallet_address, - token_mint_address, - token_program_id, - AssociatedTokenAccountInstruction::CreateIdempotent, - ) -} - -/// Creates a `RecoverNested` instruction -pub fn recover_nested( - wallet_address: &Pubkey, - owner_token_mint_address: &Pubkey, - nested_token_mint_address: &Pubkey, - token_program_id: &Pubkey, -) -> Instruction { - let owner_associated_account_address = get_associated_token_address_with_program_id( - wallet_address, - owner_token_mint_address, - token_program_id, - ); - let destination_associated_account_address = get_associated_token_address_with_program_id( - wallet_address, - nested_token_mint_address, - token_program_id, - ); - let nested_associated_account_address = get_associated_token_address_with_program_id( - &owner_associated_account_address, // ATA is wrongly used as a wallet_address - nested_token_mint_address, - token_program_id, - ); - - let instruction_data = AssociatedTokenAccountInstruction::RecoverNested; - - Instruction { - program_id: id(), - accounts: vec![ - AccountMeta::new(nested_associated_account_address, false), - AccountMeta::new_readonly(*nested_token_mint_address, false), - AccountMeta::new(destination_associated_account_address, false), - AccountMeta::new_readonly(owner_associated_account_address, false), - AccountMeta::new_readonly(*owner_token_mint_address, false), - AccountMeta::new(*wallet_address, true), - AccountMeta::new_readonly(*token_program_id, false), - ], - data: instruction_data.try_to_vec().unwrap(), - } -} diff --git a/associated-token-account/program/src/lib.rs b/associated-token-account/program/src/lib.rs deleted file mode 100644 index d5906816f22..00000000000 --- a/associated-token-account/program/src/lib.rs +++ /dev/null @@ -1,114 +0,0 @@ -//! Convention for associating token accounts with a user wallet -#![deny(missing_docs)] -#![forbid(unsafe_code)] - -mod entrypoint; -pub mod error; -pub mod instruction; -pub mod processor; -pub mod tools; - -// Export current SDK types for downstream users building with a different SDK version -pub use solana_program; -use solana_program::{ - instruction::{AccountMeta, Instruction}, - pubkey::Pubkey, - sysvar, -}; - -solana_program::declare_id!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"); - -pub(crate) fn get_associated_token_address_and_bump_seed( - wallet_address: &Pubkey, - token_mint_address: &Pubkey, - program_id: &Pubkey, - token_program_id: &Pubkey, -) -> (Pubkey, u8) { - get_associated_token_address_and_bump_seed_internal( - wallet_address, - token_mint_address, - program_id, - token_program_id, - ) -} - -/// Derives the associated token account address for the given wallet address and token mint -pub fn get_associated_token_address( - wallet_address: &Pubkey, - token_mint_address: &Pubkey, -) -> Pubkey { - get_associated_token_address_with_program_id( - wallet_address, - token_mint_address, - &spl_token::id(), - ) -} - -/// Derives the associated token account address for the given wallet address, token mint and token program id -pub fn get_associated_token_address_with_program_id( - wallet_address: &Pubkey, - token_mint_address: &Pubkey, - token_program_id: &Pubkey, -) -> Pubkey { - get_associated_token_address_and_bump_seed( - wallet_address, - token_mint_address, - &id(), - token_program_id, - ) - .0 -} - -fn get_associated_token_address_and_bump_seed_internal( - wallet_address: &Pubkey, - token_mint_address: &Pubkey, - program_id: &Pubkey, - token_program_id: &Pubkey, -) -> (Pubkey, u8) { - Pubkey::find_program_address( - &[ - &wallet_address.to_bytes(), - &token_program_id.to_bytes(), - &token_mint_address.to_bytes(), - ], - program_id, - ) -} - -/// Create an associated token account for the given wallet address and token mint -/// -/// Accounts expected by this instruction: -/// -/// 0. `[writeable,signer]` Funding account (must be a system account) -/// 1. `[writeable]` Associated token account address to be created -/// 2. `[]` Wallet address for the new associated token account -/// 3. `[]` The token mint for the new associated token account -/// 4. `[]` System program -/// 5. `[]` SPL Token program -/// -#[deprecated( - since = "1.0.5", - note = "please use `instruction::create_associated_token_account` instead" -)] -pub fn create_associated_token_account( - funding_address: &Pubkey, - wallet_address: &Pubkey, - token_mint_address: &Pubkey, -) -> Instruction { - let associated_account_address = - get_associated_token_address(wallet_address, token_mint_address); - - Instruction { - program_id: id(), - accounts: vec![ - AccountMeta::new(*funding_address, true), - AccountMeta::new(associated_account_address, false), - AccountMeta::new_readonly(*wallet_address, false), - AccountMeta::new_readonly(*token_mint_address, false), - AccountMeta::new_readonly(solana_program::system_program::id(), false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - ], - data: vec![], - } -} diff --git a/associated-token-account/program/src/processor.rs b/associated-token-account/program/src/processor.rs deleted file mode 100644 index 20767a247d1..00000000000 --- a/associated-token-account/program/src/processor.rs +++ /dev/null @@ -1,309 +0,0 @@ -//! Program state processor - -use { - crate::{ - error::AssociatedTokenAccountError, - instruction::AssociatedTokenAccountInstruction, - tools::account::{create_pda_account, get_account_len}, - *, - }, - borsh::BorshDeserialize, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - program::{invoke, invoke_signed}, - program_error::ProgramError, - pubkey::Pubkey, - rent::Rent, - system_program, - sysvar::Sysvar, - }, - spl_token_2022::{ - extension::{ExtensionType, StateWithExtensions}, - state::{Account, Mint}, - }, -}; - -/// Specify when to create the associated token account -#[derive(PartialEq)] -enum CreateMode { - /// Always try to create the ATA - Always, - /// Only try to create the ATA if non-existent - Idempotent, -} - -/// Instruction processor -pub fn process_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - input: &[u8], -) -> ProgramResult { - let instruction = if input.is_empty() { - AssociatedTokenAccountInstruction::Create - } else { - AssociatedTokenAccountInstruction::try_from_slice(input) - .map_err(|_| ProgramError::InvalidInstructionData)? - }; - - msg!("{:?}", instruction); - - match instruction { - AssociatedTokenAccountInstruction::Create => { - process_create_associated_token_account(program_id, accounts, CreateMode::Always) - } - AssociatedTokenAccountInstruction::CreateIdempotent => { - process_create_associated_token_account(program_id, accounts, CreateMode::Idempotent) - } - AssociatedTokenAccountInstruction::RecoverNested => { - process_recover_nested(program_id, accounts) - } - } -} - -/// Processes CreateAssociatedTokenAccount instruction -fn process_create_associated_token_account( - program_id: &Pubkey, - accounts: &[AccountInfo], - create_mode: CreateMode, -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - - let funder_info = next_account_info(account_info_iter)?; - let associated_token_account_info = next_account_info(account_info_iter)?; - let wallet_account_info = next_account_info(account_info_iter)?; - let spl_token_mint_info = next_account_info(account_info_iter)?; - let system_program_info = next_account_info(account_info_iter)?; - let spl_token_program_info = next_account_info(account_info_iter)?; - let spl_token_program_id = spl_token_program_info.key; - - let (associated_token_address, bump_seed) = get_associated_token_address_and_bump_seed_internal( - wallet_account_info.key, - spl_token_mint_info.key, - program_id, - spl_token_program_id, - ); - if associated_token_address != *associated_token_account_info.key { - msg!("Error: Associated address does not match seed derivation"); - return Err(ProgramError::InvalidSeeds); - } - - if create_mode == CreateMode::Idempotent - && associated_token_account_info.owner == spl_token_program_id - { - let ata_data = associated_token_account_info.data.borrow(); - if let Ok(associated_token_account) = StateWithExtensions::::unpack(&ata_data) { - if associated_token_account.base.owner != *wallet_account_info.key { - let error = AssociatedTokenAccountError::InvalidOwner; - msg!("{}", error); - return Err(error.into()); - } - if associated_token_account.base.mint != *spl_token_mint_info.key { - return Err(ProgramError::InvalidAccountData); - } - return Ok(()); - } - } - if *associated_token_account_info.owner != system_program::id() { - return Err(ProgramError::IllegalOwner); - } - - let rent = Rent::get()?; - - let associated_token_account_signer_seeds: &[&[_]] = &[ - &wallet_account_info.key.to_bytes(), - &spl_token_program_id.to_bytes(), - &spl_token_mint_info.key.to_bytes(), - &[bump_seed], - ]; - - let account_len = get_account_len( - spl_token_mint_info, - spl_token_program_info, - &[ExtensionType::ImmutableOwner], - )?; - - create_pda_account( - funder_info, - &rent, - account_len, - spl_token_program_id, - system_program_info, - associated_token_account_info, - associated_token_account_signer_seeds, - )?; - - msg!("Initialize the associated token account"); - invoke( - &spl_token_2022::instruction::initialize_immutable_owner( - spl_token_program_id, - associated_token_account_info.key, - )?, - &[ - associated_token_account_info.clone(), - spl_token_program_info.clone(), - ], - )?; - invoke( - &spl_token_2022::instruction::initialize_account3( - spl_token_program_id, - associated_token_account_info.key, - spl_token_mint_info.key, - wallet_account_info.key, - )?, - &[ - associated_token_account_info.clone(), - spl_token_mint_info.clone(), - wallet_account_info.clone(), - spl_token_program_info.clone(), - ], - ) -} - -/// Processes `RecoverNested` instruction -pub fn process_recover_nested(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - - let nested_associated_token_account_info = next_account_info(account_info_iter)?; - let nested_token_mint_info = next_account_info(account_info_iter)?; - let destination_associated_token_account_info = next_account_info(account_info_iter)?; - let owner_associated_token_account_info = next_account_info(account_info_iter)?; - let owner_token_mint_info = next_account_info(account_info_iter)?; - let wallet_account_info = next_account_info(account_info_iter)?; - let spl_token_program_info = next_account_info(account_info_iter)?; - let spl_token_program_id = spl_token_program_info.key; - - // Check owner address derivation - let (owner_associated_token_address, bump_seed) = - get_associated_token_address_and_bump_seed_internal( - wallet_account_info.key, - owner_token_mint_info.key, - program_id, - spl_token_program_id, - ); - if owner_associated_token_address != *owner_associated_token_account_info.key { - msg!("Error: Owner associated address does not match seed derivation"); - return Err(ProgramError::InvalidSeeds); - } - - // Check nested address derivation - let (nested_associated_token_address, _) = get_associated_token_address_and_bump_seed_internal( - owner_associated_token_account_info.key, - nested_token_mint_info.key, - program_id, - spl_token_program_id, - ); - if nested_associated_token_address != *nested_associated_token_account_info.key { - msg!("Error: Nested associated address does not match seed derivation"); - return Err(ProgramError::InvalidSeeds); - } - - // Check destination address derivation - let (destination_associated_token_address, _) = - get_associated_token_address_and_bump_seed_internal( - wallet_account_info.key, - nested_token_mint_info.key, - program_id, - spl_token_program_id, - ); - if destination_associated_token_address != *destination_associated_token_account_info.key { - msg!("Error: Destination associated address does not match seed derivation"); - return Err(ProgramError::InvalidSeeds); - } - - if !wallet_account_info.is_signer { - msg!("Wallet of the owner associated token account must sign"); - return Err(ProgramError::MissingRequiredSignature); - } - - if owner_token_mint_info.owner != spl_token_program_id { - msg!("Owner mint not owned by provided token program"); - return Err(ProgramError::IllegalOwner); - } - - // Account data is dropped at the end of this, so the CPI can succeed - // without a double-borrow - let (amount, decimals) = { - // Check owner associated token account data - if owner_associated_token_account_info.owner != spl_token_program_id { - msg!("Owner associated token account not owned by provided token program, recreate the owner associated token account first"); - return Err(ProgramError::IllegalOwner); - } - let owner_account_data = owner_associated_token_account_info.data.borrow(); - let owner_account = StateWithExtensions::::unpack(&owner_account_data)?; - if owner_account.base.owner != *wallet_account_info.key { - msg!("Owner associated token account not owned by provided wallet"); - return Err(AssociatedTokenAccountError::InvalidOwner.into()); - } - - // Check nested associated token account data - if nested_associated_token_account_info.owner != spl_token_program_id { - msg!("Nested associated token account not owned by provided token program"); - return Err(ProgramError::IllegalOwner); - } - let nested_account_data = nested_associated_token_account_info.data.borrow(); - let nested_account = StateWithExtensions::::unpack(&nested_account_data)?; - if nested_account.base.owner != *owner_associated_token_account_info.key { - msg!("Nested associated token account not owned by provided associated token account"); - return Err(AssociatedTokenAccountError::InvalidOwner.into()); - } - let amount = nested_account.base.amount; - - // Check nested token mint data - if nested_token_mint_info.owner != spl_token_program_id { - msg!("Nested mint account not owned by provided token program"); - return Err(ProgramError::IllegalOwner); - } - let nested_mint_data = nested_token_mint_info.data.borrow(); - let nested_mint = StateWithExtensions::::unpack(&nested_mint_data)?; - let decimals = nested_mint.base.decimals; - (amount, decimals) - }; - - // Transfer everything out - let owner_associated_token_account_signer_seeds: &[&[_]] = &[ - &wallet_account_info.key.to_bytes(), - &spl_token_program_id.to_bytes(), - &owner_token_mint_info.key.to_bytes(), - &[bump_seed], - ]; - invoke_signed( - &spl_token_2022::instruction::transfer_checked( - spl_token_program_id, - nested_associated_token_account_info.key, - nested_token_mint_info.key, - destination_associated_token_account_info.key, - owner_associated_token_account_info.key, - &[], - amount, - decimals, - )?, - &[ - nested_associated_token_account_info.clone(), - nested_token_mint_info.clone(), - destination_associated_token_account_info.clone(), - owner_associated_token_account_info.clone(), - spl_token_program_info.clone(), - ], - &[owner_associated_token_account_signer_seeds], - )?; - - // Close the nested account so it's never used again - invoke_signed( - &spl_token_2022::instruction::close_account( - spl_token_program_id, - nested_associated_token_account_info.key, - wallet_account_info.key, - owner_associated_token_account_info.key, - &[], - )?, - &[ - nested_associated_token_account_info.clone(), - wallet_account_info.clone(), - owner_associated_token_account_info.clone(), - spl_token_program_info.clone(), - ], - &[owner_associated_token_account_signer_seeds], - ) -} diff --git a/associated-token-account/program/src/tools/account.rs b/associated-token-account/program/src/tools/account.rs deleted file mode 100644 index 14158f70bf4..00000000000 --- a/associated-token-account/program/src/tools/account.rs +++ /dev/null @@ -1,99 +0,0 @@ -//! Account utility functions - -use { - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - program::{get_return_data, invoke, invoke_signed}, - program_error::ProgramError, - pubkey::Pubkey, - rent::Rent, - system_instruction, - }, - spl_token_2022::extension::ExtensionType, - std::convert::TryInto, -}; - -/// Creates associated token account using Program Derived Address for the given seeds -pub fn create_pda_account<'a>( - payer: &AccountInfo<'a>, - rent: &Rent, - space: usize, - owner: &Pubkey, - system_program: &AccountInfo<'a>, - new_pda_account: &AccountInfo<'a>, - new_pda_signer_seeds: &[&[u8]], -) -> ProgramResult { - if new_pda_account.lamports() > 0 { - let required_lamports = rent - .minimum_balance(space) - .max(1) - .saturating_sub(new_pda_account.lamports()); - - if required_lamports > 0 { - invoke( - &system_instruction::transfer(payer.key, new_pda_account.key, required_lamports), - &[ - payer.clone(), - new_pda_account.clone(), - system_program.clone(), - ], - )?; - } - - invoke_signed( - &system_instruction::allocate(new_pda_account.key, space as u64), - &[new_pda_account.clone(), system_program.clone()], - &[new_pda_signer_seeds], - )?; - - invoke_signed( - &system_instruction::assign(new_pda_account.key, owner), - &[new_pda_account.clone(), system_program.clone()], - &[new_pda_signer_seeds], - ) - } else { - invoke_signed( - &system_instruction::create_account( - payer.key, - new_pda_account.key, - rent.minimum_balance(space).max(1), - space as u64, - owner, - ), - &[ - payer.clone(), - new_pda_account.clone(), - system_program.clone(), - ], - &[new_pda_signer_seeds], - ) - } -} - -/// Determines the required initial data length for a new token account based on the extensions -/// initialized on the Mint -pub fn get_account_len<'a>( - mint: &AccountInfo<'a>, - spl_token_program: &AccountInfo<'a>, - extension_types: &[ExtensionType], -) -> Result { - invoke( - &spl_token_2022::instruction::get_account_data_size( - spl_token_program.key, - mint.key, - extension_types, - )?, - &[mint.clone(), spl_token_program.clone()], - )?; - get_return_data() - .ok_or(ProgramError::InvalidInstructionData) - .and_then(|(key, data)| { - if key != *spl_token_program.key { - return Err(ProgramError::IncorrectProgramId); - } - data.try_into() - .map(usize::from_le_bytes) - .map_err(|_| ProgramError::InvalidInstructionData) - }) -} diff --git a/associated-token-account/program/src/tools/mod.rs b/associated-token-account/program/src/tools/mod.rs deleted file mode 100644 index 5cb1ab5f753..00000000000 --- a/associated-token-account/program/src/tools/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -//! Utility functions - -pub mod account; diff --git a/associated-token-account/program/tests/create_idempotent.rs b/associated-token-account/program/tests/create_idempotent.rs deleted file mode 100644 index 9d2c29f98fc..00000000000 --- a/associated-token-account/program/tests/create_idempotent.rs +++ /dev/null @@ -1,242 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod program_test; - -use { - program_test::program_test_2022, - solana_program::{instruction::*, pubkey::Pubkey}, - solana_program_test::*, - solana_sdk::{ - account::Account as SolanaAccount, - program_option::COption, - program_pack::Pack, - signature::Signer, - signer::keypair::Keypair, - system_instruction::create_account, - transaction::{Transaction, TransactionError}, - }, - spl_associated_token_account::{ - error::AssociatedTokenAccountError, - get_associated_token_address_with_program_id, - instruction::{ - create_associated_token_account, create_associated_token_account_idempotent, - }, - }, - spl_token_2022::{ - extension::ExtensionType, - instruction::initialize_account, - state::{Account, AccountState}, - }, -}; - -#[tokio::test] -async fn success_account_exists() { - let wallet_address = Pubkey::new_unique(); - let token_mint_address = Pubkey::new_unique(); - let associated_token_address = get_associated_token_address_with_program_id( - &wallet_address, - &token_mint_address, - &spl_token_2022::id(), - ); - - let (mut banks_client, payer, recent_blockhash) = - program_test_2022(token_mint_address, true).start().await; - let rent = banks_client.get_rent().await.unwrap(); - let expected_token_account_len = - ExtensionType::get_account_len::(&[ExtensionType::ImmutableOwner]); - let expected_token_account_balance = rent.minimum_balance(expected_token_account_len); - - let instruction = create_associated_token_account_idempotent( - &payer.pubkey(), - &wallet_address, - &token_mint_address, - &spl_token_2022::id(), - ); - - let transaction = Transaction::new_signed_with_payer( - &[instruction], - Some(&payer.pubkey()), - &[&payer], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); - - // Associated account now exists - let associated_account = banks_client - .get_account(associated_token_address) - .await - .expect("get_account") - .expect("associated_account not none"); - assert_eq!(associated_account.data.len(), expected_token_account_len); - assert_eq!(associated_account.owner, spl_token_2022::id()); - assert_eq!(associated_account.lamports, expected_token_account_balance); - - // Unchecked instruction fails - let instruction = create_associated_token_account( - &payer.pubkey(), - &wallet_address, - &token_mint_address, - &spl_token_2022::id(), - ); - - let transaction = Transaction::new_signed_with_payer( - &[instruction], - Some(&payer.pubkey()), - &[&payer], - recent_blockhash, - ); - assert_eq!( - banks_client - .process_transaction(transaction) - .await - .unwrap_err() - .unwrap(), - TransactionError::InstructionError(0, InstructionError::IllegalOwner) - ); - - // Get a new blockhash, succeed with create if non existent - let recent_blockhash = banks_client - .get_new_latest_blockhash(&recent_blockhash) - .await - .unwrap(); - - let instruction = create_associated_token_account_idempotent( - &payer.pubkey(), - &wallet_address, - &token_mint_address, - &spl_token_2022::id(), - ); - - let transaction = Transaction::new_signed_with_payer( - &[instruction], - Some(&payer.pubkey()), - &[&payer], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); - - // Associated account is unchanged - let associated_account = banks_client - .get_account(associated_token_address) - .await - .expect("get_account") - .expect("associated_account not none"); - assert_eq!(associated_account.data.len(), expected_token_account_len); - assert_eq!(associated_account.owner, spl_token_2022::id()); - assert_eq!(associated_account.lamports, expected_token_account_balance); -} - -#[tokio::test] -async fn fail_account_exists_with_wrong_owner() { - let wallet_address = Pubkey::new_unique(); - let token_mint_address = Pubkey::new_unique(); - let associated_token_address = get_associated_token_address_with_program_id( - &wallet_address, - &token_mint_address, - &spl_token_2022::id(), - ); - - let wrong_owner = Pubkey::new_unique(); - let mut associated_token_account = - SolanaAccount::new(1_000_000_000, Account::LEN, &spl_token_2022::id()); - let token_account = Account { - mint: token_mint_address, - owner: wrong_owner, - amount: 0, - delegate: COption::None, - state: AccountState::Initialized, - is_native: COption::None, - delegated_amount: 0, - close_authority: COption::None, - }; - Account::pack(token_account, &mut associated_token_account.data).unwrap(); - let mut pt = program_test_2022(token_mint_address, true); - pt.add_account(associated_token_address, associated_token_account); - let (mut banks_client, payer, recent_blockhash) = pt.start().await; - - // fail creating token account if non existent - let instruction = create_associated_token_account_idempotent( - &payer.pubkey(), - &wallet_address, - &token_mint_address, - &spl_token_2022::id(), - ); - let transaction = Transaction::new_signed_with_payer( - &[instruction], - Some(&payer.pubkey()), - &[&payer], - recent_blockhash, - ); - - assert_eq!( - banks_client - .process_transaction(transaction) - .await - .unwrap_err() - .unwrap(), - TransactionError::InstructionError( - 0, - InstructionError::Custom(AssociatedTokenAccountError::InvalidOwner as u32) - ) - ); -} - -#[tokio::test] -async fn fail_non_ata() { - let token_mint_address = Pubkey::new_unique(); - let (mut banks_client, payer, recent_blockhash) = - program_test_2022(token_mint_address, true).start().await; - - let rent = banks_client.get_rent().await.unwrap(); - let token_account_len = - ExtensionType::get_account_len::(&[ExtensionType::ImmutableOwner]); - let token_account_balance = rent.minimum_balance(token_account_len); - - let wallet_address = Pubkey::new_unique(); - let account = Keypair::new(); - let transaction = Transaction::new_signed_with_payer( - &[ - create_account( - &payer.pubkey(), - &account.pubkey(), - token_account_balance, - token_account_len as u64, - &spl_token_2022::id(), - ), - initialize_account( - &spl_token_2022::id(), - &account.pubkey(), - &token_mint_address, - &wallet_address, - ) - .unwrap(), - ], - Some(&payer.pubkey()), - &[&payer, &account], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); - - let mut instruction = create_associated_token_account_idempotent( - &payer.pubkey(), - &wallet_address, - &token_mint_address, - &spl_token_2022::id(), - ); - instruction.accounts[1] = AccountMeta::new(account.pubkey(), false); // <-- Invalid associated_account_address - - let transaction = Transaction::new_signed_with_payer( - &[instruction], - Some(&payer.pubkey()), - &[&payer], - recent_blockhash, - ); - assert_eq!( - banks_client - .process_transaction(transaction) - .await - .unwrap_err() - .unwrap(), - TransactionError::InstructionError(0, InstructionError::InvalidSeeds) - ); -} diff --git a/associated-token-account/program/tests/extended_mint.rs b/associated-token-account/program/tests/extended_mint.rs deleted file mode 100644 index cc131c0d716..00000000000 --- a/associated-token-account/program/tests/extended_mint.rs +++ /dev/null @@ -1,202 +0,0 @@ -// Mark this test as BPF-only due to current `ProgramTest` limitations when CPIing into the system program -#![cfg(feature = "test-bpf")] - -mod program_test; - -use { - program_test::program_test_2022, - solana_program::{instruction::*, pubkey::Pubkey, system_instruction}, - solana_program_test::*, - solana_sdk::{ - signature::Signer, - signer::keypair::Keypair, - transaction::{Transaction, TransactionError}, - }, - spl_associated_token_account::{ - get_associated_token_address_with_program_id, instruction::create_associated_token_account, - }, - spl_token_2022::{ - error::TokenError, - extension::{transfer_fee, ExtensionType, StateWithExtensionsOwned}, - state::{Account, Mint}, - }, -}; - -#[tokio::test] -async fn test_associated_token_account_with_transfer_fees() { - let wallet_sender = Keypair::new(); - let wallet_address_sender = wallet_sender.pubkey(); - let wallet_receiver = Keypair::new(); - let wallet_address_receiver = wallet_receiver.pubkey(); - let (mut banks_client, payer, recent_blockhash) = - program_test_2022(Pubkey::new_unique(), true).start().await; - let rent = banks_client.get_rent().await.unwrap(); - - // create extended mint - // ... in the future, a mint can be pre-loaded in program_test.rs like the regular mint - let mint_account = Keypair::new(); - let token_mint_address = mint_account.pubkey(); - let mint_authority = Keypair::new(); - let space = ExtensionType::get_account_len::(&[ExtensionType::TransferFeeConfig]); - let maximum_fee = 100; - let mut transaction = Transaction::new_with_payer( - &[ - system_instruction::create_account( - &payer.pubkey(), - &mint_account.pubkey(), - rent.minimum_balance(space), - space as u64, - &spl_token_2022::id(), - ), - transfer_fee::instruction::initialize_transfer_fee_config( - &spl_token_2022::id(), - &token_mint_address, - Some(&mint_authority.pubkey()), - Some(&mint_authority.pubkey()), - 1_000, - maximum_fee, - ) - .unwrap(), - spl_token_2022::instruction::initialize_mint( - &spl_token_2022::id(), - &token_mint_address, - &mint_authority.pubkey(), - Some(&mint_authority.pubkey()), - 0, - ) - .unwrap(), - ], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &mint_account], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - // create extended ATAs - let mut transaction = Transaction::new_with_payer( - &[create_associated_token_account( - &payer.pubkey(), - &wallet_address_sender, - &token_mint_address, - &spl_token_2022::id(), - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - let mut transaction = Transaction::new_with_payer( - &[create_associated_token_account( - &payer.pubkey(), - &wallet_address_receiver, - &token_mint_address, - &spl_token_2022::id(), - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - let associated_token_address_sender = get_associated_token_address_with_program_id( - &wallet_address_sender, - &token_mint_address, - &spl_token_2022::id(), - ); - let associated_token_address_receiver = get_associated_token_address_with_program_id( - &wallet_address_receiver, - &token_mint_address, - &spl_token_2022::id(), - ); - - // mint tokens - let sender_amount = 50 * maximum_fee; - let mut transaction = Transaction::new_with_payer( - &[spl_token_2022::instruction::mint_to( - &spl_token_2022::id(), - &token_mint_address, - &associated_token_address_sender, - &mint_authority.pubkey(), - &[], - sender_amount, - ) - .unwrap()], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &mint_authority], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - // not enough tokens - let mut transaction = Transaction::new_with_payer( - &[transfer_fee::instruction::transfer_checked_with_fee( - &spl_token_2022::id(), - &associated_token_address_sender, - &token_mint_address, - &associated_token_address_receiver, - &wallet_address_sender, - &[], - 10_001, - 0, - maximum_fee, - ) - .unwrap()], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &wallet_sender], recent_blockhash); - let err = banks_client - .process_transaction(transaction) - .await - .unwrap_err() - .unwrap(); - assert_eq!( - err, - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::InsufficientFunds as u32) - ) - ); - - // success - let transfer_amount = 500; - let fee = 50; - let mut transaction = Transaction::new_with_payer( - &[transfer_fee::instruction::transfer_checked_with_fee( - &spl_token_2022::id(), - &associated_token_address_sender, - &token_mint_address, - &associated_token_address_receiver, - &wallet_address_sender, - &[], - transfer_amount, - 0, - fee, - ) - .unwrap()], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &wallet_sender], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - let sender_account = banks_client - .get_account(associated_token_address_sender) - .await - .unwrap() - .unwrap(); - let sender_state = StateWithExtensionsOwned::::unpack(sender_account.data).unwrap(); - assert_eq!(sender_state.base.amount, sender_amount - transfer_amount); - let extension = sender_state - .get_extension::() - .unwrap(); - assert_eq!(extension.withheld_amount, 0.into()); - - let receiver_account = banks_client - .get_account(associated_token_address_receiver) - .await - .unwrap() - .unwrap(); - let receiver_state = - StateWithExtensionsOwned::::unpack(receiver_account.data).unwrap(); - assert_eq!(receiver_state.base.amount, transfer_amount - fee); - let extension = receiver_state - .get_extension::() - .unwrap(); - assert_eq!(extension.withheld_amount, fee.into()); -} diff --git a/associated-token-account/program/tests/fixtures/token-mint-data.bin b/associated-token-account/program/tests/fixtures/token-mint-data.bin deleted file mode 100644 index 4a48512c02a..00000000000 Binary files a/associated-token-account/program/tests/fixtures/token-mint-data.bin and /dev/null differ diff --git a/associated-token-account/program/tests/process_create_associated_token_account.rs b/associated-token-account/program/tests/process_create_associated_token_account.rs deleted file mode 100644 index c988e6e2446..00000000000 --- a/associated-token-account/program/tests/process_create_associated_token_account.rs +++ /dev/null @@ -1,314 +0,0 @@ -// Mark this test as BPF-only due to current `ProgramTest` limitations when CPIing into the system program -#![cfg(feature = "test-bpf")] - -mod program_test; - -use { - program_test::program_test_2022, - solana_program::{instruction::*, pubkey::Pubkey, system_instruction, sysvar}, - solana_program_test::*, - solana_sdk::{ - signature::Signer, - transaction::{Transaction, TransactionError}, - }, - spl_associated_token_account::{ - get_associated_token_address_with_program_id, instruction::create_associated_token_account, - }, - spl_token_2022::{extension::ExtensionType, state::Account}, -}; - -#[tokio::test] -async fn test_associated_token_address() { - let wallet_address = Pubkey::new_unique(); - let token_mint_address = Pubkey::new_unique(); - let associated_token_address = get_associated_token_address_with_program_id( - &wallet_address, - &token_mint_address, - &spl_token_2022::id(), - ); - - let (mut banks_client, payer, recent_blockhash) = - program_test_2022(token_mint_address, true).start().await; - let rent = banks_client.get_rent().await.unwrap(); - - let expected_token_account_len = - ExtensionType::get_account_len::(&[ExtensionType::ImmutableOwner]); - let expected_token_account_balance = rent.minimum_balance(expected_token_account_len); - - // Associated account does not exist - assert_eq!( - banks_client - .get_account(associated_token_address) - .await - .expect("get_account"), - None, - ); - - let mut transaction = Transaction::new_with_payer( - &[create_associated_token_account( - &payer.pubkey(), - &wallet_address, - &token_mint_address, - &spl_token_2022::id(), - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - // Associated account now exists - let associated_account = banks_client - .get_account(associated_token_address) - .await - .expect("get_account") - .expect("associated_account not none"); - assert_eq!(associated_account.data.len(), expected_token_account_len,); - assert_eq!(associated_account.owner, spl_token_2022::id()); - assert_eq!(associated_account.lamports, expected_token_account_balance); -} - -#[tokio::test] -async fn test_create_with_fewer_lamports() { - let wallet_address = Pubkey::new_unique(); - let token_mint_address = Pubkey::new_unique(); - let associated_token_address = get_associated_token_address_with_program_id( - &wallet_address, - &token_mint_address, - &spl_token_2022::id(), - ); - - let (mut banks_client, payer, recent_blockhash) = - program_test_2022(token_mint_address, true).start().await; - let rent = banks_client.get_rent().await.unwrap(); - let expected_token_account_len = - ExtensionType::get_account_len::(&[ExtensionType::ImmutableOwner]); - let expected_token_account_balance = rent.minimum_balance(expected_token_account_len); - - // Transfer lamports into `associated_token_address` before creating it - enough to be - // rent-exempt for 0 data, but not for an initialized token account - let mut transaction = Transaction::new_with_payer( - &[system_instruction::transfer( - &payer.pubkey(), - &associated_token_address, - rent.minimum_balance(0), - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - assert_eq!( - banks_client - .get_balance(associated_token_address) - .await - .unwrap(), - rent.minimum_balance(0) - ); - - // Check that the program adds the extra lamports - let mut transaction = Transaction::new_with_payer( - &[create_associated_token_account( - &payer.pubkey(), - &wallet_address, - &token_mint_address, - &spl_token_2022::id(), - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - assert_eq!( - banks_client - .get_balance(associated_token_address) - .await - .unwrap(), - expected_token_account_balance, - ); -} - -#[tokio::test] -async fn test_create_with_excess_lamports() { - let wallet_address = Pubkey::new_unique(); - let token_mint_address = Pubkey::new_unique(); - let associated_token_address = get_associated_token_address_with_program_id( - &wallet_address, - &token_mint_address, - &spl_token_2022::id(), - ); - - let (mut banks_client, payer, recent_blockhash) = - program_test_2022(token_mint_address, true).start().await; - let rent = banks_client.get_rent().await.unwrap(); - - let expected_token_account_len = - ExtensionType::get_account_len::(&[ExtensionType::ImmutableOwner]); - let expected_token_account_balance = rent.minimum_balance(expected_token_account_len); - - // Transfer 1 lamport into `associated_token_address` before creating it - let mut transaction = Transaction::new_with_payer( - &[system_instruction::transfer( - &payer.pubkey(), - &associated_token_address, - expected_token_account_balance + 1, - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - assert_eq!( - banks_client - .get_balance(associated_token_address) - .await - .unwrap(), - expected_token_account_balance + 1 - ); - - // Check that the program doesn't add any lamports - let mut transaction = Transaction::new_with_payer( - &[create_associated_token_account( - &payer.pubkey(), - &wallet_address, - &token_mint_address, - &spl_token_2022::id(), - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - assert_eq!( - banks_client - .get_balance(associated_token_address) - .await - .unwrap(), - expected_token_account_balance + 1 - ); -} - -#[tokio::test] -async fn test_create_account_mismatch() { - let wallet_address = Pubkey::new_unique(); - let token_mint_address = Pubkey::new_unique(); - let _associated_token_address = get_associated_token_address_with_program_id( - &wallet_address, - &token_mint_address, - &spl_token_2022::id(), - ); - - let (mut banks_client, payer, recent_blockhash) = - program_test_2022(token_mint_address, true).start().await; - - let mut instruction = create_associated_token_account( - &payer.pubkey(), - &wallet_address, - &token_mint_address, - &spl_token_2022::id(), - ); - instruction.accounts[1] = AccountMeta::new(Pubkey::default(), false); // <-- Invalid associated_account_address - - let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - assert_eq!( - banks_client - .process_transaction(transaction) - .await - .unwrap_err() - .unwrap(), - TransactionError::InstructionError(0, InstructionError::InvalidSeeds) - ); - - let mut instruction = create_associated_token_account( - &payer.pubkey(), - &wallet_address, - &token_mint_address, - &spl_token_2022::id(), - ); - instruction.accounts[2] = AccountMeta::new(Pubkey::default(), false); // <-- Invalid wallet_address - - let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - assert_eq!( - banks_client - .process_transaction(transaction) - .await - .unwrap_err() - .unwrap(), - TransactionError::InstructionError(0, InstructionError::InvalidSeeds) - ); - - let mut instruction = create_associated_token_account( - &payer.pubkey(), - &wallet_address, - &token_mint_address, - &spl_token_2022::id(), - ); - instruction.accounts[3] = AccountMeta::new(Pubkey::default(), false); // <-- Invalid token_mint_address - - let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - assert_eq!( - banks_client - .process_transaction(transaction) - .await - .unwrap_err() - .unwrap(), - TransactionError::InstructionError(0, InstructionError::InvalidSeeds) - ); -} - -#[tokio::test] -async fn test_create_associated_token_account_using_legacy_implicit_instruction() { - let wallet_address = Pubkey::new_unique(); - let token_mint_address = Pubkey::new_unique(); - let associated_token_address = get_associated_token_address_with_program_id( - &wallet_address, - &token_mint_address, - &spl_token_2022::id(), - ); - - let (mut banks_client, payer, recent_blockhash) = - program_test_2022(token_mint_address, true).start().await; - let rent = banks_client.get_rent().await.unwrap(); - let expected_token_account_len = - ExtensionType::get_account_len::(&[ExtensionType::ImmutableOwner]); - let expected_token_account_balance = rent.minimum_balance(expected_token_account_len); - - // Associated account does not exist - assert_eq!( - banks_client - .get_account(associated_token_address) - .await - .expect("get_account"), - None, - ); - - let mut create_associated_token_account_ix = create_associated_token_account( - &payer.pubkey(), - &wallet_address, - &token_mint_address, - &spl_token_2022::id(), - ); - - // Use implicit instruction and rent account to replicate the legacy invocation - create_associated_token_account_ix.data = vec![]; - create_associated_token_account_ix - .accounts - .push(AccountMeta::new_readonly(sysvar::rent::id(), false)); - - let mut transaction = - Transaction::new_with_payer(&[create_associated_token_account_ix], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - // Associated account now exists - let associated_account = banks_client - .get_account(associated_token_address) - .await - .expect("get_account") - .expect("associated_account not none"); - assert_eq!(associated_account.data.len(), expected_token_account_len); - assert_eq!(associated_account.owner, spl_token_2022::id()); - assert_eq!(associated_account.lamports, expected_token_account_balance); -} diff --git a/associated-token-account/program/tests/program_test.rs b/associated-token-account/program/tests/program_test.rs deleted file mode 100644 index f72f378cb0c..00000000000 --- a/associated-token-account/program/tests/program_test.rs +++ /dev/null @@ -1,80 +0,0 @@ -use { - solana_program::pubkey::Pubkey, - solana_program_test::{ProgramTest, *}, - spl_associated_token_account::{id, processor::process_instruction}, -}; - -#[allow(dead_code)] -pub fn program_test(token_mint_address: Pubkey, use_latest_spl_token: bool) -> ProgramTest { - let mut pc = ProgramTest::new( - "spl_associated_token_account", - id(), - processor!(process_instruction), - ); - - if use_latest_spl_token { - // TODO: Remove when spl-token is available by default in program-test - pc.add_program( - "spl_token", - spl_token::id(), - processor!(spl_token::processor::Processor::process), - ); - } - - // Add a token mint account - // - // The account data was generated by running: - // $ solana account EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v \ - // --output-file tests/fixtures/token-mint-data.bin - // - pc.add_account_with_file_data( - token_mint_address, - 1461600, - spl_token::id(), - "token-mint-data.bin", - ); - - // Dial down the BPF compute budget to detect if the program gets bloated in the future - pc.set_compute_max_units(50_000); - - pc -} - -#[allow(dead_code)] -pub fn program_test_2022( - token_mint_address: Pubkey, - use_latest_spl_token_2022: bool, -) -> ProgramTest { - let mut pc = ProgramTest::new( - "spl_associated_token_account", - id(), - processor!(process_instruction), - ); - - if use_latest_spl_token_2022 { - // TODO: Remove when spl-token-2022 is available by default in program-test - pc.add_program( - "spl_token_2022", - spl_token_2022::id(), - processor!(spl_token_2022::processor::Processor::process), - ); - } - - // Add a token mint account - // - // The account data was generated by running: - // $ solana account EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v \ - // --output-file tests/fixtures/token-mint-data.bin - // - pc.add_account_with_file_data( - token_mint_address, - 1461600, - spl_token_2022::id(), - "token-mint-data.bin", - ); - - // Dial down the BPF compute budget to detect if the program gets bloated in the future - pc.set_compute_max_units(50_000); - - pc -} diff --git a/associated-token-account/program/tests/recover_nested.rs b/associated-token-account/program/tests/recover_nested.rs deleted file mode 100644 index d86c59eb6fb..00000000000 --- a/associated-token-account/program/tests/recover_nested.rs +++ /dev/null @@ -1,632 +0,0 @@ -// Mark this test as BPF-only due to current `ProgramTest` limitations when CPIing into the system program -#![cfg(feature = "test-bpf")] - -mod program_test; - -use { - program_test::{program_test, program_test_2022}, - solana_program::{pubkey::Pubkey, system_instruction}, - solana_program_test::*, - solana_sdk::{ - instruction::{AccountMeta, InstructionError}, - signature::Signer, - signer::keypair::Keypair, - transaction::{Transaction, TransactionError}, - }, - spl_associated_token_account::{get_associated_token_address_with_program_id, instruction}, - spl_token_2022::{ - extension::{ExtensionType, StateWithExtensionsOwned}, - state::{Account, Mint}, - }, -}; - -async fn create_mint(context: &mut ProgramTestContext, program_id: &Pubkey) -> (Pubkey, Keypair) { - let mint_account = Keypair::new(); - let token_mint_address = mint_account.pubkey(); - let mint_authority = Keypair::new(); - let space = ExtensionType::get_account_len::(&[]); - let rent = context.banks_client.get_rent().await.unwrap(); - let transaction = Transaction::new_signed_with_payer( - &[ - system_instruction::create_account( - &context.payer.pubkey(), - &mint_account.pubkey(), - rent.minimum_balance(space), - space as u64, - program_id, - ), - spl_token_2022::instruction::initialize_mint( - program_id, - &token_mint_address, - &mint_authority.pubkey(), - Some(&mint_authority.pubkey()), - 0, - ) - .unwrap(), - ], - Some(&context.payer.pubkey()), - &[&context.payer, &mint_account], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - (token_mint_address, mint_authority) -} - -async fn create_associated_token_account( - context: &mut ProgramTestContext, - owner: &Pubkey, - mint: &Pubkey, - program_id: &Pubkey, -) -> Pubkey { - let transaction = Transaction::new_signed_with_payer( - &[instruction::create_associated_token_account( - &context.payer.pubkey(), - owner, - mint, - program_id, - )], - Some(&context.payer.pubkey()), - &[&context.payer], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - get_associated_token_address_with_program_id(owner, mint, program_id) -} - -#[allow(clippy::too_many_arguments)] -async fn try_recover_nested( - context: &mut ProgramTestContext, - program_id: &Pubkey, - nested_mint: Pubkey, - nested_mint_authority: Keypair, - nested_associated_token_address: Pubkey, - destination_token_address: Pubkey, - wallet: Keypair, - recover_transaction: Transaction, - expected_error: Option, -) { - let nested_account = context - .banks_client - .get_account(nested_associated_token_address) - .await - .unwrap() - .unwrap(); - let lamports = nested_account.lamports; - - // mint to nested account - let amount = 100; - let transaction = Transaction::new_signed_with_payer( - &[spl_token_2022::instruction::mint_to( - program_id, - &nested_mint, - &nested_associated_token_address, - &nested_mint_authority.pubkey(), - &[], - amount, - ) - .unwrap()], - Some(&context.payer.pubkey()), - &[&context.payer, &nested_mint_authority], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - // transfer / close nested account - let result = context - .banks_client - .process_transaction(recover_transaction) - .await; - - if let Some(expected_error) = expected_error { - let error = result.unwrap_err().unwrap(); - assert_eq!(error, TransactionError::InstructionError(0, expected_error)); - } else { - result.unwrap(); - // nested account is gone - assert!(context - .banks_client - .get_account(nested_associated_token_address) - .await - .unwrap() - .is_none()); - let destination_account = context - .banks_client - .get_account(destination_token_address) - .await - .unwrap() - .unwrap(); - let destination_state = - StateWithExtensionsOwned::::unpack(destination_account.data).unwrap(); - assert_eq!(destination_state.base.amount, amount); - let wallet_account = context - .banks_client - .get_account(wallet.pubkey()) - .await - .unwrap() - .unwrap(); - assert_eq!(wallet_account.lamports, lamports); - } -} - -async fn check_same_mint(context: &mut ProgramTestContext, program_id: &Pubkey) { - let wallet = Keypair::new(); - let (mint, mint_authority) = create_mint(context, program_id).await; - - let owner_associated_token_address = - create_associated_token_account(context, &wallet.pubkey(), &mint, program_id).await; - let nested_associated_token_address = create_associated_token_account( - context, - &owner_associated_token_address, - &mint, - program_id, - ) - .await; - - let transaction = Transaction::new_signed_with_payer( - &[instruction::recover_nested( - &wallet.pubkey(), - &mint, - &mint, - program_id, - )], - Some(&context.payer.pubkey()), - &[&context.payer, &wallet], - context.last_blockhash, - ); - try_recover_nested( - context, - program_id, - mint, - mint_authority, - nested_associated_token_address, - owner_associated_token_address, - wallet, - transaction, - None, - ) - .await; -} - -#[tokio::test] -async fn success_same_mint_2022() { - let dummy_mint = Pubkey::new_unique(); - let pt = program_test_2022(dummy_mint, true); - let mut context = pt.start_with_context().await; - check_same_mint(&mut context, &spl_token_2022::id()).await; -} - -#[tokio::test] -async fn success_same_mint() { - let dummy_mint = Pubkey::new_unique(); - let pt = program_test(dummy_mint, true); - let mut context = pt.start_with_context().await; - check_same_mint(&mut context, &spl_token::id()).await; -} - -async fn check_different_mints(context: &mut ProgramTestContext, program_id: &Pubkey) { - let wallet = Keypair::new(); - let (owner_mint, _owner_mint_authority) = create_mint(context, program_id).await; - let (nested_mint, nested_mint_authority) = create_mint(context, program_id).await; - - let owner_associated_token_address = - create_associated_token_account(context, &wallet.pubkey(), &owner_mint, program_id).await; - let nested_associated_token_address = create_associated_token_account( - context, - &owner_associated_token_address, - &nested_mint, - program_id, - ) - .await; - let destination_token_address = - create_associated_token_account(context, &wallet.pubkey(), &nested_mint, program_id).await; - - let transaction = Transaction::new_signed_with_payer( - &[instruction::recover_nested( - &wallet.pubkey(), - &owner_mint, - &nested_mint, - program_id, - )], - Some(&context.payer.pubkey()), - &[&context.payer, &wallet], - context.last_blockhash, - ); - try_recover_nested( - context, - program_id, - nested_mint, - nested_mint_authority, - nested_associated_token_address, - destination_token_address, - wallet, - transaction, - None, - ) - .await; -} - -#[tokio::test] -async fn success_different_mints() { - let dummy_mint = Pubkey::new_unique(); - let pt = program_test(dummy_mint, true); - let mut context = pt.start_with_context().await; - check_different_mints(&mut context, &spl_token::id()).await; -} - -#[tokio::test] -async fn success_different_mints_2022() { - let dummy_mint = Pubkey::new_unique(); - let pt = program_test_2022(dummy_mint, true); - let mut context = pt.start_with_context().await; - check_different_mints(&mut context, &spl_token_2022::id()).await; -} - -async fn check_missing_wallet_signature(context: &mut ProgramTestContext, program_id: &Pubkey) { - let wallet = Keypair::new(); - let (mint, mint_authority) = create_mint(context, program_id).await; - - let owner_associated_token_address = - create_associated_token_account(context, &wallet.pubkey(), &mint, program_id).await; - - let nested_associated_token_address = create_associated_token_account( - context, - &owner_associated_token_address, - &mint, - program_id, - ) - .await; - - let mut recover = instruction::recover_nested(&wallet.pubkey(), &mint, &mint, program_id); - recover.accounts[5] = AccountMeta::new(wallet.pubkey(), false); - let transaction = Transaction::new_signed_with_payer( - &[recover], - Some(&context.payer.pubkey()), - &[&context.payer], - context.last_blockhash, - ); - try_recover_nested( - context, - program_id, - mint, - mint_authority, - nested_associated_token_address, - owner_associated_token_address, - wallet, - transaction, - Some(InstructionError::MissingRequiredSignature), - ) - .await; -} - -#[tokio::test] -async fn fail_missing_wallet_signature_2022() { - let dummy_mint = Pubkey::new_unique(); - let pt = program_test_2022(dummy_mint, true); - let mut context = pt.start_with_context().await; - check_missing_wallet_signature(&mut context, &spl_token_2022::id()).await; -} - -#[tokio::test] -async fn fail_missing_wallet_signature() { - let dummy_mint = Pubkey::new_unique(); - let pt = program_test(dummy_mint, true); - let mut context = pt.start_with_context().await; - check_missing_wallet_signature(&mut context, &spl_token::id()).await; -} - -async fn check_wrong_signer(context: &mut ProgramTestContext, program_id: &Pubkey) { - let wallet = Keypair::new(); - let wrong_wallet = Keypair::new(); - let (mint, mint_authority) = create_mint(context, program_id).await; - - let owner_associated_token_address = - create_associated_token_account(context, &wallet.pubkey(), &mint, program_id).await; - let nested_associated_token_address = create_associated_token_account( - context, - &owner_associated_token_address, - &mint, - program_id, - ) - .await; - - let transaction = Transaction::new_signed_with_payer( - &[instruction::recover_nested( - &wrong_wallet.pubkey(), - &mint, - &mint, - program_id, - )], - Some(&context.payer.pubkey()), - &[&context.payer, &wrong_wallet], - context.last_blockhash, - ); - try_recover_nested( - context, - program_id, - mint, - mint_authority, - nested_associated_token_address, - owner_associated_token_address, - wrong_wallet, - transaction, - Some(InstructionError::IllegalOwner), - ) - .await; -} - -#[tokio::test] -async fn fail_wrong_signer_2022() { - let dummy_mint = Pubkey::new_unique(); - let pt = program_test_2022(dummy_mint, true); - let mut context = pt.start_with_context().await; - check_wrong_signer(&mut context, &spl_token_2022::id()).await; -} - -#[tokio::test] -async fn fail_wrong_signer() { - let dummy_mint = Pubkey::new_unique(); - let pt = program_test(dummy_mint, true); - let mut context = pt.start_with_context().await; - check_wrong_signer(&mut context, &spl_token::id()).await; -} - -async fn check_not_nested(context: &mut ProgramTestContext, program_id: &Pubkey) { - let wallet = Keypair::new(); - let wrong_wallet = Keypair::new(); - let (mint, mint_authority) = create_mint(context, program_id).await; - - let owner_associated_token_address = - create_associated_token_account(context, &wallet.pubkey(), &mint, program_id).await; - let nested_associated_token_address = - create_associated_token_account(context, &wrong_wallet.pubkey(), &mint, program_id).await; - - let transaction = Transaction::new_signed_with_payer( - &[instruction::recover_nested( - &wallet.pubkey(), - &mint, - &mint, - program_id, - )], - Some(&context.payer.pubkey()), - &[&context.payer, &wallet], - context.last_blockhash, - ); - try_recover_nested( - context, - program_id, - mint, - mint_authority, - nested_associated_token_address, - owner_associated_token_address, - wallet, - transaction, - Some(InstructionError::IllegalOwner), - ) - .await; -} - -#[tokio::test] -async fn fail_not_nested_2022() { - let dummy_mint = Pubkey::new_unique(); - let pt = program_test_2022(dummy_mint, true); - let mut context = pt.start_with_context().await; - check_not_nested(&mut context, &spl_token_2022::id()).await; -} - -#[tokio::test] -async fn fail_not_nested() { - let dummy_mint = Pubkey::new_unique(); - let pt = program_test(dummy_mint, true); - let mut context = pt.start_with_context().await; - check_not_nested(&mut context, &spl_token::id()).await; -} - -async fn check_wrong_address_derivation_owner( - context: &mut ProgramTestContext, - program_id: &Pubkey, -) { - let wallet = Keypair::new(); - let wrong_wallet = Keypair::new(); - let (mint, mint_authority) = create_mint(context, program_id).await; - - let owner_associated_token_address = - create_associated_token_account(context, &wallet.pubkey(), &mint, program_id).await; - let nested_associated_token_address = create_associated_token_account( - context, - &owner_associated_token_address, - &mint, - program_id, - ) - .await; - - let wrong_owner_associated_token_address = - get_associated_token_address_with_program_id(&mint, &wrong_wallet.pubkey(), program_id); - let mut recover = instruction::recover_nested(&wallet.pubkey(), &mint, &mint, program_id); - recover.accounts[3] = AccountMeta::new(wrong_owner_associated_token_address, false); - let transaction = Transaction::new_signed_with_payer( - &[recover], - Some(&context.payer.pubkey()), - &[&context.payer, &wallet], - context.last_blockhash, - ); - try_recover_nested( - context, - program_id, - mint, - mint_authority, - nested_associated_token_address, - wrong_owner_associated_token_address, - wallet, - transaction, - Some(InstructionError::InvalidSeeds), - ) - .await; -} - -#[tokio::test] -async fn fail_wrong_address_derivation_owner_2022() { - let dummy_mint = Pubkey::new_unique(); - let pt = program_test_2022(dummy_mint, true); - let mut context = pt.start_with_context().await; - check_wrong_address_derivation_owner(&mut context, &spl_token_2022::id()).await; -} - -#[tokio::test] -async fn fail_wrong_address_derivation_owner() { - let dummy_mint = Pubkey::new_unique(); - let pt = program_test(dummy_mint, true); - let mut context = pt.start_with_context().await; - check_wrong_address_derivation_owner(&mut context, &spl_token::id()).await; -} - -async fn check_owner_account_does_not_exist(context: &mut ProgramTestContext, program_id: &Pubkey) { - let wallet = Keypair::new(); - let (mint, mint_authority) = create_mint(context, program_id).await; - - let owner_associated_token_address = - get_associated_token_address_with_program_id(&wallet.pubkey(), &mint, program_id); - let nested_associated_token_address = create_associated_token_account( - context, - &owner_associated_token_address, - &mint, - program_id, - ) - .await; - - let transaction = Transaction::new_signed_with_payer( - &[instruction::recover_nested( - &wallet.pubkey(), - &mint, - &mint, - program_id, - )], - Some(&context.payer.pubkey()), - &[&context.payer, &wallet], - context.last_blockhash, - ); - try_recover_nested( - context, - program_id, - mint, - mint_authority, - nested_associated_token_address, - owner_associated_token_address, - wallet, - transaction, - Some(InstructionError::IllegalOwner), - ) - .await; -} - -#[tokio::test] -async fn fail_owner_account_does_not_exist() { - let dummy_mint = Pubkey::new_unique(); - let pt = program_test_2022(dummy_mint, true); - let mut context = pt.start_with_context().await; - check_owner_account_does_not_exist(&mut context, &spl_token_2022::id()).await; -} - -#[tokio::test] -async fn fail_wrong_spl_token_program() { - let wallet = Keypair::new(); - let dummy_mint = Pubkey::new_unique(); - let pt = program_test_2022(dummy_mint, true); - let mut context = pt.start_with_context().await; - let program_id = spl_token_2022::id(); - let wrong_program_id = spl_token::id(); - let (mint, mint_authority) = create_mint(&mut context, &program_id).await; - - let owner_associated_token_address = - create_associated_token_account(&mut context, &wallet.pubkey(), &mint, &program_id).await; - let nested_associated_token_address = create_associated_token_account( - &mut context, - &owner_associated_token_address, - &mint, - &program_id, - ) - .await; - - let transaction = Transaction::new_signed_with_payer( - &[instruction::recover_nested( - &wallet.pubkey(), - &mint, - &mint, - &wrong_program_id, - )], - Some(&context.payer.pubkey()), - &[&context.payer, &wallet], - context.last_blockhash, - ); - try_recover_nested( - &mut context, - &program_id, - mint, - mint_authority, - nested_associated_token_address, - owner_associated_token_address, - wallet, - transaction, - Some(InstructionError::IllegalOwner), - ) - .await; -} - -#[tokio::test] -async fn fail_destination_not_wallet_ata() { - let wallet = Keypair::new(); - let wrong_wallet = Keypair::new(); - let dummy_mint = Pubkey::new_unique(); - let pt = program_test_2022(dummy_mint, true); - let program_id = spl_token_2022::id(); - let mut context = pt.start_with_context().await; - let (mint, mint_authority) = create_mint(&mut context, &program_id).await; - - let owner_associated_token_address = - create_associated_token_account(&mut context, &wallet.pubkey(), &mint, &program_id).await; - let nested_associated_token_address = create_associated_token_account( - &mut context, - &owner_associated_token_address, - &mint, - &program_id, - ) - .await; - let wrong_destination_associated_token_account_address = - create_associated_token_account(&mut context, &wrong_wallet.pubkey(), &mint, &program_id) - .await; - - let mut recover = instruction::recover_nested(&wallet.pubkey(), &mint, &mint, &program_id); - recover.accounts[2] = - AccountMeta::new(wrong_destination_associated_token_account_address, false); - - let transaction = Transaction::new_signed_with_payer( - &[recover], - Some(&context.payer.pubkey()), - &[&context.payer, &wallet], - context.last_blockhash, - ); - try_recover_nested( - &mut context, - &program_id, - mint, - mint_authority, - nested_associated_token_address, - owner_associated_token_address, - wallet, - transaction, - Some(InstructionError::InvalidSeeds), - ) - .await; -} diff --git a/associated-token-account/program/tests/spl_token_create.rs b/associated-token-account/program/tests/spl_token_create.rs deleted file mode 100644 index a1e465ce739..00000000000 --- a/associated-token-account/program/tests/spl_token_create.rs +++ /dev/null @@ -1,113 +0,0 @@ -// Mark this test as BPF-only due to current `ProgramTest` limitations when CPIing into the system program -#![cfg(feature = "test-bpf")] - -mod program_test; - -use { - program_test::program_test, - solana_program::pubkey::Pubkey, - solana_program_test::*, - solana_sdk::{program_pack::Pack, signature::Signer, transaction::Transaction}, - spl_associated_token_account::{ - get_associated_token_address, instruction::create_associated_token_account, - }, - spl_token::state::Account, -}; - -#[allow(deprecated)] -use spl_associated_token_account::create_associated_token_account as deprecated_create_associated_token_account; - -#[tokio::test] -async fn success_create() { - let wallet_address = Pubkey::new_unique(); - let token_mint_address = Pubkey::new_unique(); - let associated_token_address = - get_associated_token_address(&wallet_address, &token_mint_address); - - let (mut banks_client, payer, recent_blockhash) = - program_test(token_mint_address, true).start().await; - let rent = banks_client.get_rent().await.unwrap(); - let expected_token_account_len = Account::LEN; - let expected_token_account_balance = rent.minimum_balance(expected_token_account_len); - - // Associated account does not exist - assert_eq!( - banks_client - .get_account(associated_token_address) - .await - .expect("get_account"), - None, - ); - - let transaction = Transaction::new_signed_with_payer( - &[create_associated_token_account( - &payer.pubkey(), - &wallet_address, - &token_mint_address, - &spl_token::id(), - )], - Some(&payer.pubkey()), - &[&payer], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); - - // Associated account now exists - let associated_account = banks_client - .get_account(associated_token_address) - .await - .expect("get_account") - .expect("associated_account not none"); - assert_eq!(associated_account.data.len(), expected_token_account_len); - assert_eq!(associated_account.owner, spl_token::id()); - assert_eq!(associated_account.lamports, expected_token_account_balance); -} - -#[tokio::test] -async fn success_using_deprecated_instruction_creator() { - let wallet_address = Pubkey::new_unique(); - let token_mint_address = Pubkey::new_unique(); - let associated_token_address = - get_associated_token_address(&wallet_address, &token_mint_address); - - let (mut banks_client, payer, recent_blockhash) = - program_test(token_mint_address, true).start().await; - let rent = banks_client.get_rent().await.unwrap(); - let expected_token_account_len = Account::LEN; - let expected_token_account_balance = rent.minimum_balance(expected_token_account_len); - - // Associated account does not exist - assert_eq!( - banks_client - .get_account(associated_token_address) - .await - .expect("get_account"), - None, - ); - - // Use legacy instruction creator - #[allow(deprecated)] - let create_associated_token_account_ix = deprecated_create_associated_token_account( - &payer.pubkey(), - &wallet_address, - &token_mint_address, - ); - - let transaction = Transaction::new_signed_with_payer( - &[create_associated_token_account_ix], - Some(&payer.pubkey()), - &[&payer], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); - - // Associated account now exists - let associated_account = banks_client - .get_account(associated_token_address) - .await - .expect("get_account") - .expect("associated_account not none"); - assert_eq!(associated_account.data.len(), expected_token_account_len); - assert_eq!(associated_account.owner, spl_token::id()); - assert_eq!(associated_account.lamports, expected_token_account_balance); -} diff --git a/binary-option/README.md b/binary-option/README.md index 9652f66d9b6..13efe1b08f1 100644 --- a/binary-option/README.md +++ b/binary-option/README.md @@ -1,10 +1,10 @@ # Binary Option -This protocol is a primitive version of a binary options. Participants can enter a long or short position depending on their conviction. (These sides are set completely arbitrarily). The eventual goal is to have a higher level program manage the pool and handle settlements with an oracle based voting approach. Every bet in the pool involves 2 parties (1 long and 1 short) each depositing some collateral. Because bets are made on binary event, the sum of collateral will be equal to a multiple of some power of 10 (`10 ** N` where `N` is configurable). +This protocol is a primitive version of binary options. Participants can enter a long or short position depending on their conviction. (These sides are set completely arbitrarily). The eventual goal is to have a higher level program manage the pool and handle settlements with an oracle based voting approach. Every bet in the pool involves 2 parties (1 long and 1 short) each depositing some collateral. Because bets are made on a binary event, the sum of collateral will be equal to a multiple of some power of 10 (`10 ** N` where `N` is configurable). -The module contains the Rust implementation of protocol as well as a Python client and test suite. +The module contains the Rust implementation of the protocol as well as a Python client and test suite. -Suppose we had a binary option on the winner of the 2021 NBA Finals (Phoenix Suns vs. Milwaulkee Bucks). At the time of writing this (July 9th, 2021), the moneyline spread is -190 Suns +170 Bucks. This backs out an implied probability of approximately 36% that the Bucks win the championship. Suppose our binary option was on the Bucks winning this series, and that it is denominated by some wrapped stablecoin WUSD (dollar pegged) where every contract settled to 10000 WUSD (`N = 4` corresponding to 1 cent granularity). You observe that someone is willing to go short Bucks for 10 contracts at 3000 WUSD (less than the estimated probability of 36%). You can take on the opposite trade by buying 10 long contracts on the Bucks for 3000. +Suppose we had a binary option on the winner of the 2021 NBA Finals (Phoenix Suns vs. Milwaukee Bucks). At the time of writing this (July 9th, 2021), the moneyline spread is -190 Suns +170 Bucks. This backs out an implied probability of approximately 36% that the Bucks win the championship. Suppose our binary option was on the Bucks winning this series, and that it is denominated by some wrapped stablecoin WUSD (dollar pegged) where every contract settled to 10000 WUSD (`N = 4` corresponding to 1 cent granularity). You observe that someone is willing to go short Bucks for 10 contracts at 3000 WUSD (less than the estimated probability of 36%). You can take on the opposite trade by buying 10 long contracts on the Bucks for 3000. This invokes a `Trade` instruction with size 10, buy_price 3000, and sell_price 7000. Note that these prices must sum to 10000. As part of the protocol, you transfer 30000 WUSD into the binary option and the counterparty deposits 70000 (assuming that both parties start with 0 position). In return, 10 long tokens (minted by the contract) are added to your account, and 10 short tokens are minted to your counterparty's account. @@ -12,10 +12,15 @@ Now suppose the Bucks win Game 3, and the estimated probability of the Bucks win We'll discuss this mechanism in more detail later. +## Audit + +The repository [README](https://github.com/solana-labs/solana-program-library#audits) +contains information about program audits. + ## Client Setup  First, clone down the repository (TODO publish to PyPI) -Create a virtual environment and and install the dependencies in `client/requirements.txt` +Create a virtual environment and install the dependencies in `client/requirements.txt` ``` python3 -m virtualenv venv @@ -42,7 +47,7 @@ python -m client.test `n_s` the number of long contracts owned by the seller -We know from our college combanatorics/discrete math class that there are 3! = 6 ways to order 3 items. Let's list out all configurations of how these numbers can bet ordered from largest to smallest (assuming all distinct): +We know from our college combinatorics/discrete math class that there are 3! = 6 ways to order 3 items. Let's list out all configurations of how these numbers can be ordered from largest to smallest (assuming all distinct): ``` 1) n_b > n_s > n @@ -56,7 +61,7 @@ This is a lot of cases to consider, but we can group them into combined categori ``` n_b >= n && n_s >= n ``` -This clause essentially groups 1) and 2) together. In this case, both buyer and seller are simply reducing their existing inventory. Therefore, we can just remove `n` long tokens and `n` short tokens from circulation. Both parties are also entitled to the locked up funds for their positions that were closed, so the buyer receives `n * sell_price` and the seller received `n * buy_price`. This might be confusing at first, but a good way to think about this is that there are no "sellers". Everyone with inventory is a "buyer". If an event as a probability `p` of occurring, the buyer is paying `p` and the seller is paying `1-p`. When a market participant receives funds, they are "selling out" (either locking in profits or losses) of their existing position. +This clause essentially groups 1) and 2) together. In this case, both buyer and seller are simply reducing their existing inventory. Therefore, we can just remove `n` long tokens and `n` short tokens from circulation. Both parties are also entitled to the locked up funds for their positions that were closed, so the buyer receives `n * sell_price` and the seller received `n * buy_price`. This might be confusing at first, but a good way to think about this is that there are no "sellers". Everyone with inventory is a "buyer". If an event has a probability `p` of occurring, the buyer is paying `p` and the seller is paying `1-p`. When a market participant receives funds, they are "selling out" (either locking in profits or losses) of their existing position. ``` n_b < n && n_s < n diff --git a/binary-option/client/binary_option.py b/binary-option/client/binary_option.py index 08972560f00..da78cc00545 100644 --- a/binary-option/client/binary_option.py +++ b/binary-option/client/binary_option.py @@ -140,7 +140,7 @@ def __init__(self, cfg): def initialize(self, api_endpoint, escrow_mint, decimals=2, skip_confirmation=True): msg = "" - # Initialize Clinet + # Initialize Client client = Client(api_endpoint) msg += "Initialized client" # Create account objects diff --git a/binary-option/client/requirements.txt b/binary-option/client/requirements.txt index 5c637902a27..cd8592a055d 100644 --- a/binary-option/client/requirements.txt +++ b/binary-option/client/requirements.txt @@ -1,21 +1,21 @@ attrs==21.2.0 base58==2.1.0 -certifi==2021.5.30 +certifi==2024.7.4 cffi==1.14.5 chardet==4.0.0 cheroot==8.5.2 CherryPy==18.6.0 construct==2.10.67 -cryptography==3.4.7 +cryptography==43.0.1 ed25519==1.5 -idna==2.10 +idna==3.7 iniconfig==1.1.1 jaraco.classes==3.2.1 jaraco.collections==3.3.0 jaraco.functools==3.3.0 jaraco.text==3.5.0 more-itertools==8.8.0 -numpy==1.21.0 +numpy==1.22.0 packaging==20.9 pandas==1.3.0 pluggy==0.13.1 @@ -27,12 +27,12 @@ pyparsing==2.4.7 pytest==6.2.4 python-dateutil==2.8.1 pytz==2021.1 -requests==2.25.1 +requests==2.32.0 six==1.16.0 solana==0.10.0 tempora==4.1.1 toml==0.10.2 typing-extensions==3.10.0.0 -urllib3==1.26.6 +urllib3==1.26.19 websockets==9.1 zc.lockfile==2.0 diff --git a/binary-option/program/Cargo.toml b/binary-option/program/Cargo.toml index 02f6610b4b3..b9b64a6b6e1 100644 --- a/binary-option/program/Cargo.toml +++ b/binary-option/program/Cargo.toml @@ -1,20 +1,25 @@ [package] name = "binary-option" version = "0.1.0" -edition = "2018" +edition = "2021" license = "WTFPL" [features] no-entrypoint = [] -test-bpf = [] +test-sbf = [] [dependencies] -solana-program = "1.10.33" -thiserror = "1.0" -spl-token = {version = "3.1.1", path = "../../token/program", features = ["no-entrypoint"]} -arrayref = "0.3.6" -borsh = "0.9" -uint = "0.9" +solana-program = "2.1.0" +thiserror = "2.0" +spl-token = { version = "7.0", features = [ + "no-entrypoint", +] } +arrayref = "0.3.9" +borsh = "1.5.3" +uint = "0.10" [lib] crate-type = ["cdylib", "lib"] + +[lints] +workspace = true diff --git a/binary-option/program/src/entrypoint.rs b/binary-option/program/src/entrypoint.rs index 3baa990ba0d..cbf8ed562f9 100644 --- a/binary-option/program/src/entrypoint.rs +++ b/binary-option/program/src/entrypoint.rs @@ -1,12 +1,11 @@ #![cfg(all(target_os = "solana", not(feature = "no-entrypoint")))] -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, pubkey::Pubkey, +use { + crate::processor::Processor, + solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey}, }; -use crate::processor::Processor; - -entrypoint!(process_instruction); +solana_program::entrypoint!(process_instruction); fn process_instruction( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/binary-option/program/src/error.rs b/binary-option/program/src/error.rs index 1a597ea1386..8c9ccdda264 100644 --- a/binary-option/program/src/error.rs +++ b/binary-option/program/src/error.rs @@ -1,6 +1,4 @@ -use thiserror::Error; - -use solana_program::program_error::ProgramError; +use {solana_program::program_error::ProgramError, thiserror::Error}; #[derive(Error, Debug, Copy, Clone)] pub enum BinaryOptionError { @@ -28,6 +26,8 @@ pub enum BinaryOptionError { PublicKeysShouldBeUnique, #[error("TradePricesIncorrect")] TradePricesIncorrect, + #[error("AmountOverflow")] + AmountOverflow, } impl From for ProgramError { diff --git a/binary-option/program/src/instruction.rs b/binary-option/program/src/instruction.rs index e1a7dd814fd..485386d6d31 100644 --- a/binary-option/program/src/instruction.rs +++ b/binary-option/program/src/instruction.rs @@ -1,11 +1,12 @@ -use solana_program::{ - instruction::{AccountMeta, Instruction}, - pubkey::Pubkey, - sysvar, +use { + borsh::{BorshDeserialize, BorshSerialize}, + solana_program::{ + instruction::{AccountMeta, Instruction}, + pubkey::Pubkey, + sysvar, + }, }; -use borsh::{BorshDeserialize, BorshSerialize}; - #[repr(C)] #[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)] pub struct InitializeBinaryOptionArgs { @@ -59,10 +60,9 @@ pub fn initialize_binary_option( AccountMeta::new_readonly(solana_program::system_program::id(), false), AccountMeta::new_readonly(sysvar::rent::id(), false), ], - data: BinaryOptionInstruction::InitializeBinaryOption(InitializeBinaryOptionArgs { - decimals, - }) - .try_to_vec() + data: borsh::to_vec(&BinaryOptionInstruction::InitializeBinaryOption( + InitializeBinaryOptionArgs { decimals }, + )) .unwrap(), } } @@ -106,12 +106,11 @@ pub fn trade( AccountMeta::new_readonly(escrow_authority, false), AccountMeta::new_readonly(spl_token::id(), false), ], - data: BinaryOptionInstruction::Trade(TradeArgs { + data: borsh::to_vec(&BinaryOptionInstruction::Trade(TradeArgs { size, buy_price, sell_price, - }) - .try_to_vec() + })) .unwrap(), } } @@ -130,7 +129,7 @@ pub fn settle( AccountMeta::new_readonly(winning_mint, false), AccountMeta::new_readonly(pool_authority, true), ], - data: BinaryOptionInstruction::Settle.try_to_vec().unwrap(), + data: borsh::to_vec(&BinaryOptionInstruction::Settle).unwrap(), } } @@ -166,6 +165,6 @@ pub fn collect( AccountMeta::new_readonly(solana_program::system_program::id(), false), AccountMeta::new_readonly(sysvar::rent::id(), false), ], - data: BinaryOptionInstruction::Collect.try_to_vec().unwrap(), + data: borsh::to_vec(&BinaryOptionInstruction::Collect).unwrap(), } } diff --git a/binary-option/program/src/lib.rs b/binary-option/program/src/lib.rs index 9b5922f796e..e75cd473b86 100644 --- a/binary-option/program/src/lib.rs +++ b/binary-option/program/src/lib.rs @@ -1,3 +1,4 @@ +#![allow(clippy::arithmetic_side_effects)] pub mod entrypoint; pub mod error; pub mod instruction; @@ -6,7 +7,8 @@ pub mod spl_utils; pub mod state; pub mod system_utils; pub mod validation_utils; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version pub use solana_program; solana_program::declare_id!("betw959P4WToez4DkuXwNsJszqbpe3HuY56AcG5yevx"); diff --git a/binary-option/program/src/processor.rs b/binary-option/program/src/processor.rs index cf91338ded1..43286e33f66 100644 --- a/binary-option/program/src/processor.rs +++ b/binary-option/program/src/processor.rs @@ -1,28 +1,30 @@ -use crate::{ - error::BinaryOptionError, - instruction::BinaryOptionInstruction, - spl_utils::{ - spl_approve, spl_burn, spl_burn_signed, spl_initialize, spl_mint_initialize, spl_mint_to, - spl_set_authority, spl_token_transfer, spl_token_transfer_signed, +use { + crate::{ + error::BinaryOptionError, + instruction::BinaryOptionInstruction, + spl_utils::{ + spl_approve, spl_burn, spl_burn_signed, spl_initialize, spl_mint_initialize, + spl_mint_to, spl_set_authority, spl_token_transfer, spl_token_transfer_signed, + }, + state::BinaryOption, + system_utils::{create_new_account, create_or_allocate_account_raw}, + validation_utils::{ + assert_initialized, assert_keys_equal, assert_keys_unequal, assert_owned_by, + }, }, - state::BinaryOption, - system_utils::{create_new_account, create_or_allocate_account_raw}, - validation_utils::{ - assert_initialized, assert_keys_equal, assert_keys_unequal, assert_owned_by, + borsh::BorshDeserialize, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + msg, + program_error::ProgramError, + program_pack::Pack, + pubkey::Pubkey, + }, + spl_token::{ + instruction::AuthorityType, + state::{Account, Mint}, }, -}; -use borsh::{BorshDeserialize, BorshSerialize}; -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - program_error::ProgramError, - program_pack::Pack, - pubkey::Pubkey, -}; -use spl_token::{ - instruction::AuthorityType, - state::{Account, Mint}, }; pub struct Processor; @@ -175,8 +177,10 @@ pub fn process_initialize_binary_option( binary_option.escrow_mint_account_pubkey = *escrow_mint_info.key; binary_option.escrow_account_pubkey = *escrow_account_info.key; binary_option.owner = *update_authority_info.key; - binary_option.serialize(&mut *binary_option_account_info.data.borrow_mut())?; - + borsh::to_writer( + &mut binary_option_account_info.data.borrow_mut()[..], + &binary_option, + )?; Ok(()) } @@ -234,7 +238,10 @@ pub fn process_trade( ]; // Validate data - if buy_price + sell_price != u64::pow(10, binary_option.decimals as u32) { + let total_price = buy_price + .checked_add(sell_price) + .ok_or(BinaryOptionError::TradePricesIncorrect)?; + if total_price != u64::pow(10, binary_option.decimals as u32) { return Err(BinaryOptionError::TradePricesIncorrect.into()); } if binary_option.settled { @@ -411,7 +418,7 @@ pub fn process_trade( seeds, )?; if n > n_b + n_s { - binary_option.increment_supply(n - n_b - n_s); + binary_option.increment_supply(n - n_b - n_s)?; } else { binary_option.decrement_supply(n - n_b - n_s)?; } @@ -535,8 +542,9 @@ pub fn process_trade( binary_option.decrement_supply(n_b)?; } } - // Delegate the burn authority to the PDA, so a private key is unnecessary on collection - // This can probably be optimized to reduce the number of instructions needed at some point + // Delegate the burn authority to the PDA, so a private key is unnecessary on + // collection This can probably be optimized to reduce the number of + // instructions needed at some point spl_approve( token_program_info, buyer_long_token_account_info, @@ -573,14 +581,18 @@ pub fn process_trade( s_l, long_token_mint.decimals, )?; - binary_option.serialize(&mut *binary_option_account_info.data.borrow_mut())?; + borsh::to_writer( + &mut binary_option_account_info.data.borrow_mut()[..], + &binary_option, + )?; Ok(()) } pub fn process_settle(_program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { // This should NEVER be called directly (otherwise this is literally a rug) - // The `pool_owner_info` needs to approve this action, so the recommended use case is to have a higher - // level program own the pool and use an oracle to resolve settlements + // The `pool_owner_info` needs to approve this action, so the recommended use + // case is to have a higher level program own the pool and use an oracle to + // resolve settlements let account_info_iter = &mut accounts.iter(); let binary_option_account_info = next_account_info(account_info_iter)?; let winning_mint_account_info = next_account_info(account_info_iter)?; @@ -604,7 +616,10 @@ pub fn process_settle(_program_id: &Pubkey, accounts: &[AccountInfo]) -> Program return Err(BinaryOptionError::InvalidWinner.into()); } binary_option.settled = true; - binary_option.serialize(&mut *binary_option_account_info.data.borrow_mut())?; + borsh::to_writer( + &mut binary_option_account_info.data.borrow_mut()[..], + &binary_option, + )?; Ok(()) } @@ -707,7 +722,10 @@ pub fn process_collect(program_id: &Pubkey, accounts: &[AccountInfo]) -> Program seeds, )?; if reward > 0 { - let amount = (reward * escrow_account.amount) / binary_option.circulation; + let amount = reward + .checked_mul(escrow_account.amount) + .ok_or(BinaryOptionError::AmountOverflow)?; + let amount = amount / binary_option.circulation; spl_token_transfer_signed( token_program_info, escrow_account_info, @@ -718,6 +736,9 @@ pub fn process_collect(program_id: &Pubkey, accounts: &[AccountInfo]) -> Program )?; binary_option.decrement_supply(reward)?; } - binary_option.serialize(&mut *binary_option_account_info.data.borrow_mut())?; + borsh::to_writer( + &mut binary_option_account_info.data.borrow_mut()[..], + &binary_option, + )?; Ok(()) } diff --git a/binary-option/program/src/state.rs b/binary-option/program/src/state.rs index be46400f843..b04cc0223b0 100644 --- a/binary-option/program/src/state.rs +++ b/binary-option/program/src/state.rs @@ -1,11 +1,12 @@ -use solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, - pubkey::Pubkey, +use { + crate::error::BinaryOptionError, + borsh::{BorshDeserialize, BorshSerialize}, + solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, + pubkey::Pubkey, + }, }; -use crate::error::BinaryOptionError; -use borsh::{BorshDeserialize, BorshSerialize}; - #[repr(C)] #[derive(BorshSerialize, BorshDeserialize, Debug, Clone)] pub struct BinaryOption { @@ -28,8 +29,12 @@ impl BinaryOption { Ok(binary_option) } - pub fn increment_supply(&mut self, n: u64) { - self.circulation += n; + pub fn increment_supply(&mut self, n: u64) -> ProgramResult { + self.circulation = self + .circulation + .checked_add(n) + .ok_or(BinaryOptionError::AmountOverflow)?; + Ok(()) } pub fn decrement_supply(&mut self, n: u64) -> ProgramResult { diff --git a/binary-oracle-pair/README.md b/binary-oracle-pair/README.md index 9371114fe78..3eb51f91d64 100644 --- a/binary-oracle-pair/README.md +++ b/binary-oracle-pair/README.md @@ -1,4 +1,4 @@ -Simple Oracle Pair Token +# Simple Oracle Pair Token 1. pick a deposit token 2. pick the decider's pubkey @@ -10,3 +10,8 @@ the mint term end slot. After the decide term end slot the `Pass` token converts 1:1 with the deposit token if and only if the decider had set `pass` before the end of the decide term, otherwise the `Fail` token converts 1:1 with the deposit token. + +## Audit + +The repository [README](https://github.com/solana-labs/solana-program-library#audits) +contains information about program audits. diff --git a/binary-oracle-pair/program/Cargo.toml b/binary-oracle-pair/program/Cargo.toml index 7a7c2923446..afea331bd9d 100644 --- a/binary-oracle-pair/program/Cargo.toml +++ b/binary-oracle-pair/program/Cargo.toml @@ -2,26 +2,31 @@ name = "spl-binary-oracle-pair" version = "0.1.0" description = "Solana Program Library Binary Oracle Pair" -authors = ["Solana Maintainers "] +authors = ["Solana Labs Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" license = "Apache-2.0" -edition = "2018" +edition = "2021" [features] -test-bpf = [] +test-sbf = [] [dependencies] -num-derive = "0.3" +num-derive = "0.4" num-traits = "0.2" -solana-program = "1.10.33" -spl-token = { version = "3.3", path = "../../token/program", features = [ "no-entrypoint" ] } -thiserror = "1.0" -uint = "0.9" -borsh = "0.9.1" +solana-program = "2.1.0" +spl-token = { version = "7.0", features = [ + "no-entrypoint", +] } +thiserror = "2.0" +uint = "0.10" +borsh = "1.5.3" [dev-dependencies] -solana-program-test = "1.10.33" -solana-sdk = "1.10.33" +solana-program-test = "2.1.0" +solana-sdk = "2.1.0" [lib] crate-type = ["cdylib", "lib"] + +[lints] +workspace = true diff --git a/binary-oracle-pair/program/src/entrypoint.rs b/binary-oracle-pair/program/src/entrypoint.rs index 381135f4a9b..b6c32a48e65 100644 --- a/binary-oracle-pair/program/src/entrypoint.rs +++ b/binary-oracle-pair/program/src/entrypoint.rs @@ -2,13 +2,15 @@ #![cfg(all(target_os = "solana", not(feature = "no-entrypoint")))] -use crate::{error::PoolError, processor}; -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, - program_error::PrintProgramError, pubkey::Pubkey, +use { + crate::{error::PoolError, processor}, + solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, program_error::PrintProgramError, + pubkey::Pubkey, + }, }; -entrypoint!(process_instruction); +solana_program::entrypoint!(process_instruction); fn process_instruction( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/binary-oracle-pair/program/src/error.rs b/binary-oracle-pair/program/src/error.rs index 17884848bc4..9da5a15d52b 100644 --- a/binary-oracle-pair/program/src/error.rs +++ b/binary-oracle-pair/program/src/error.rs @@ -1,11 +1,15 @@ //! Error types -use num_derive::FromPrimitive; -use num_traits::FromPrimitive; -use solana_program::{ - decode_error::DecodeError, msg, program_error::PrintProgramError, program_error::ProgramError, +use { + num_derive::FromPrimitive, + num_traits::FromPrimitive, + solana_program::{ + decode_error::DecodeError, + msg, + program_error::{PrintProgramError, ProgramError}, + }, + thiserror::Error, }; -use thiserror::Error; /// Errors that may be returned by the Binary Oracle Pair program. #[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] diff --git a/binary-oracle-pair/program/src/instruction.rs b/binary-oracle-pair/program/src/instruction.rs index 67c72881c13..b524010cb03 100644 --- a/binary-oracle-pair/program/src/instruction.rs +++ b/binary-oracle-pair/program/src/instruction.rs @@ -1,12 +1,14 @@ //! Instruction types -use borsh::{BorshDeserialize, BorshSerialize}; -use solana_program::{ - clock::Slot, - instruction::{AccountMeta, Instruction}, - program_error::ProgramError, - pubkey::Pubkey, - sysvar, +use { + borsh::{BorshDeserialize, BorshSerialize}, + solana_program::{ + clock::Slot, + instruction::{AccountMeta, Instruction}, + program_error::ProgramError, + pubkey::Pubkey, + sysvar, + }, }; /// Initialize arguments for pool @@ -42,7 +44,8 @@ pub enum PoolInstruction { /// 0. `[]` Pool /// 1. `[]` Authority /// 2. `[s]` User transfer authority - /// 3. `[w]` Token SOURCE Account, amount is transferable by pool authority with allowances. + /// 3. `[w]` Token SOURCE Account, amount is transferable by pool + /// authority with allowances. /// 4. `[w]` Deposit token account /// 5. `[w]` token_P PASS mint /// 6. `[w]` token_F FAIL mint @@ -53,12 +56,14 @@ pub enum PoolInstruction { Deposit(u64), /// Withdraw from the pool. - /// If current slot is < mint_end slot, 1 Pass AND 1 Fail token convert to 1 deposit - /// If current slot is > decide_end_slot slot && decide == Some(true), 1 Pass convert to 1 deposit - /// otherwise 1 Fail converts to 1 deposit + /// If current slot is < mint_end slot, 1 Pass AND 1 Fail token convert + /// to 1 deposit + /// If current slot is > decide_end_slot slot && decide == + /// Some(true), 1 Pass convert to 1 deposit otherwise 1 Fail converts + /// to 1 deposit /// - /// Pass tokens convert 1:1 to the deposit token iff decision is set to Some(true) - /// AND current slot is > decide_end_slot. + /// Pass tokens convert 1:1 to the deposit token iff decision is set to + /// Some(true) AND current slot is > decide_end_slot. /// /// 0. `[]` Pool /// 1. `[]` Authority @@ -74,7 +79,8 @@ pub enum PoolInstruction { Withdraw(u64), /// Trigger the decision. - /// Call only succeeds once and if current slot > mint_end slot AND < decide_end slot + /// Call only succeeds once and if current slot > mint_end slot AND < + /// decide_end slot /// 0. `[]` Pool /// 1. `[s]` Decider pubkey /// 2. `[]` Sysvar Clock @@ -96,7 +102,7 @@ pub fn init_pool( init_args: InitArgs, ) -> Result { let init_data = PoolInstruction::InitPool(init_args); - let data = init_data.try_to_vec()?; + let data = borsh::to_vec(&init_data)?; let accounts = vec![ AccountMeta::new(*pool, false), AccountMeta::new_readonly(*authority, false), @@ -132,7 +138,7 @@ pub fn deposit( amount: u64, ) -> Result { let init_data = PoolInstruction::Deposit(amount); - let data = init_data.try_to_vec()?; + let data = borsh::to_vec(&init_data)?; let accounts = vec![ AccountMeta::new_readonly(*pool, false), @@ -174,7 +180,7 @@ pub fn withdraw( amount: u64, ) -> Result { let init_data = PoolInstruction::Withdraw(amount); - let data = init_data.try_to_vec()?; + let data = borsh::to_vec(&init_data)?; let accounts = vec![ AccountMeta::new_readonly(*pool, false), AccountMeta::new_readonly(*authority, false), @@ -206,7 +212,7 @@ pub fn decide( decision: bool, ) -> Result { let init_data = PoolInstruction::Decide(decision); - let data = init_data.try_to_vec()?; + let data = borsh::to_vec(&init_data)?; let accounts = vec![ AccountMeta::new(*pool, false), AccountMeta::new_readonly(*decider, true), diff --git a/binary-oracle-pair/program/src/lib.rs b/binary-oracle-pair/program/src/lib.rs index 7b20c3b9bcf..a82bffaea06 100644 --- a/binary-oracle-pair/program/src/lib.rs +++ b/binary-oracle-pair/program/src/lib.rs @@ -9,7 +9,8 @@ pub mod state; #[cfg(not(feature = "no-entrypoint"))] mod entrypoint; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version pub use solana_program; // Binary Oracle Pair id diff --git a/binary-oracle-pair/program/src/processor.rs b/binary-oracle-pair/program/src/processor.rs index f6f2f94bd5a..bec3d560fe0 100644 --- a/binary-oracle-pair/program/src/processor.rs +++ b/binary-oracle-pair/program/src/processor.rs @@ -1,25 +1,26 @@ //! Program state processor -use crate::{ - error::PoolError, - instruction::PoolInstruction, - state::{Decision, Pool, POOL_VERSION}, +use { + crate::{ + error::PoolError, + instruction::PoolInstruction, + state::{Decision, Pool, POOL_VERSION}, + }, + borsh::BorshDeserialize, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + clock::{Clock, Slot}, + entrypoint::ProgramResult, + msg, + program::{invoke, invoke_signed}, + program_error::ProgramError, + program_pack::{IsInitialized, Pack}, + pubkey::Pubkey, + rent::Rent, + sysvar::Sysvar, + }, + spl_token::state::{Account, Mint}, }; -use borsh::{BorshDeserialize, BorshSerialize}; -use solana_program::{ - account_info::next_account_info, - account_info::AccountInfo, - clock::{Clock, Slot}, - entrypoint::ProgramResult, - msg, - program::{invoke, invoke_signed}, - program_error::ProgramError, - program_pack::{IsInitialized, Pack}, - pubkey::Pubkey, - rent::Rent, - sysvar::Sysvar, -}; -use spl_token::state::{Account, Mint}; /// Program state handler. pub struct Processor {} @@ -300,8 +301,7 @@ impl Processor { pool.decide_end_slot = decide_end_slot; pool.decision = Decision::Undecided; - pool.serialize(&mut *pool_account_info.data.borrow_mut()) - .map_err(|e| e.into()) + borsh::to_writer(&mut pool_account_info.data.borrow_mut()[..], &pool).map_err(|e| e.into()) } /// Process Deposit instruction @@ -556,8 +556,7 @@ impl Processor { Decision::Fail }; - pool.serialize(&mut *pool_account_info.data.borrow_mut()) - .map_err(|e| e.into()) + borsh::to_writer(&mut pool_account_info.data.borrow_mut()[..], &pool).map_err(|e| e.into()) } /// Processes an instruction diff --git a/binary-oracle-pair/program/src/state.rs b/binary-oracle-pair/program/src/state.rs index 9b8438f650e..da3ac37abd7 100644 --- a/binary-oracle-pair/program/src/state.rs +++ b/binary-oracle-pair/program/src/state.rs @@ -1,7 +1,9 @@ //! State transition types -use borsh::{BorshDeserialize, BorshSerialize}; -use solana_program::pubkey::Pubkey; +use { + borsh::{BorshDeserialize, BorshSerialize}, + solana_program::pubkey::Pubkey, +}; /// Uninitialized version value, all instances are at least version 1 pub const UNINITIALIZED_VERSION: u8 = 0; @@ -83,7 +85,7 @@ mod test { decision: Decision::Fail, }; - let packed = p.try_to_vec().unwrap(); + let packed = borsh::to_vec(&p).unwrap(); let unpacked = Pool::try_from_slice(packed.as_slice()).unwrap(); diff --git a/binary-oracle-pair/program/tests/tests.rs b/binary-oracle-pair/program/tests/tests.rs index d4a93f4ff7d..e6c913e5968 100644 --- a/binary-oracle-pair/program/tests/tests.rs +++ b/binary-oracle-pair/program/tests/tests.rs @@ -1,15 +1,17 @@ -#![cfg(feature = "test-bpf")] - -use borsh::de::BorshDeserialize; -use solana_program::{hash::Hash, program_pack::Pack, pubkey::Pubkey, system_instruction}; -use solana_program_test::*; -use solana_sdk::{ - account::Account, - signature::{Keypair, Signer}, - transaction::Transaction, - transport::TransportError, +#![cfg(feature = "test-sbf")] + +use { + borsh::de::BorshDeserialize, + solana_program::{hash::Hash, program_pack::Pack, pubkey::Pubkey, system_instruction}, + solana_program_test::*, + solana_sdk::{ + account::Account, + signature::{Keypair, Signer}, + transaction::Transaction, + transport::TransportError, + }, + spl_binary_oracle_pair::*, }; -use spl_binary_oracle_pair::*; pub fn program_test() -> ProgramTest { ProgramTest::new( @@ -128,6 +130,7 @@ pub async fn make_decision( Ok(()) } +#[allow(clippy::too_many_arguments)] pub async fn make_withdraw( program_context: &mut ProgramTestContext, pool_account: &Pubkey, @@ -446,6 +449,11 @@ impl TestPool { banks_client.process_transaction(transaction).await.unwrap(); } } +impl Default for TestPool { + fn default() -> Self { + Self::new() + } +} pub async fn create_mint( banks_client: &mut BanksClient, @@ -467,7 +475,7 @@ pub async fn create_mint( spl_token::instruction::initialize_mint( &spl_token::id(), &mint_account.pubkey(), - &owner, + owner, None, 0, ) diff --git a/cargo-nightly b/cargo-nightly new file mode 100755 index 00000000000..fc885367b67 --- /dev/null +++ b/cargo-nightly @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +here=$(dirname "$0") +source "${here}"/ci/rust-version.sh nightly +# shellcheck disable=SC2054 # rust_nightly is sourced from rust-version.sh +toolchain="$rust_nightly" +set -x +exec cargo "+${toolchain}" "${@}" \ No newline at end of file diff --git a/ci/anchor-build.sh b/ci/anchor-build.sh new file mode 100755 index 00000000000..e30a0319a0c --- /dev/null +++ b/ci/anchor-build.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +set -e + +source ci/rust-version.sh stable +source ci/solana-version.sh install +source ci/install-anchor.sh install + +set -x + +usage() { + exitcode=0 + if [[ -n "$1" ]]; then + exitcode=1 + echo "Error: $*" + fi + echo "Usage: $0 [program-directory]" + exit $exitcode +} + +program_directory=$1 +if [[ -z $program_directory ]]; then + usage "No program directory provided" +fi + +cd $program_directory +anchor build \ No newline at end of file diff --git a/ci/cargo-build-test.sh b/ci/cargo-build-test.sh index 5358a4ade1f..fa930f4e92d 100755 --- a/ci/cargo-build-test.sh +++ b/ci/cargo-build-test.sh @@ -15,8 +15,8 @@ set -x make -C examples/c # Build/test all host crates -cargo +"$rust_stable" build --workspace --exclude spl-token-cli -cargo +"$rust_stable" test --workspace --exclude spl-token-cli -- --nocapture +cargo +"$rust_stable" build --workspace --exclude spl-token-cli --exclude spl-token-upgrade-cli --exclude spl-single-pool-cli --exclude spl-transfer-hook-cli +cargo +"$rust_stable" test --workspace --exclude spl-token-cli --exclude spl-token-upgrade-cli --exclude spl-single-pool-cli --exclude spl-transfer-hook-cli -- --nocapture # Run test-client sanity check cargo +"$rust_stable" run --manifest-path=utils/test-client/Cargo.toml diff --git a/ci/cargo-test-bpf.sh b/ci/cargo-test-bpf.sh deleted file mode 100755 index ab9dc7cb164..00000000000 --- a/ci/cargo-test-bpf.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env bash - -set -e -cd "$(dirname "$0")/.." - -source ./ci/rust-version.sh stable -source ./ci/solana-version.sh - -export RUSTFLAGS="-D warnings" -export RUSTBACKTRACE=1 - -usage() { - exitcode=0 - if [[ -n "$1" ]]; then - exitcode=1 - echo "Error: $*" - fi - echo "Usage: $0 [program-directory]" - exit $exitcode -} - -program_directory=$1 -if [[ -z $program_directory ]]; then - usage "No program directory provided" -fi - -cd $program_directory -run_dir=$(pwd) - -if [[ -r $run_dir/Cargo.toml ]]; then - # Build/test just one BPF program - set -x - cd $run_dir - cargo +"$rust_stable" test-bpf -- --nocapture - exit 0 -fi - -run_all=1 -for program in $run_dir/program{,-*}; do - # Build/test all program directories - if [[ -r $program/Cargo.toml ]]; then - run_all= - ( - set -x - cd $program - cargo +"$rust_stable" test-bpf -- --nocapture - ) - fi -done - -if [[ -n $run_all ]]; then - # Build/test all directories - set -x - for directory in $(ls -d $run_dir/*/); do - cd $directory - cargo +"$rust_stable" test-bpf -- --nocapture - done -fi diff --git a/ci/cargo-test-sbf.sh b/ci/cargo-test-sbf.sh new file mode 100755 index 00000000000..498c2252fdb --- /dev/null +++ b/ci/cargo-test-sbf.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash + +set -e +cd "$(dirname "$0")/.." + +source ./ci/rust-version.sh stable +source ./ci/solana-version.sh + +export RUSTFLAGS="-D warnings" +export RUSTBACKTRACE=1 + +usage() { + exitcode=0 + if [[ -n "$1" ]]; then + exitcode=1 + echo "Error: $*" + fi + echo "Usage: $0 [program-directory]" + exit $exitcode +} + +program_directory=$1 +if [[ -z $program_directory ]]; then + usage "No program directory provided" +fi + +cd $program_directory +run_dir=$(pwd) + +if [[ -r $run_dir/Cargo.toml ]]; then + # Build/test just one BPF program + set -x + cd $run_dir + cargo +"$rust_stable" test-sbf -- --nocapture + exit 0 +fi + +run_all=1 +for program in $run_dir/program{,-*}; do + # Build/test all program directories + if [[ -r $program/Cargo.toml ]]; then + run_all= + ( + set -x + cd $program + cargo +"$rust_stable" test-sbf -- --nocapture + ) + fi +done + +if [[ -n $run_all ]]; then + # Build/test all directories + set -x + for directory in $(ls -d $run_dir/*/); do + cd $directory + cargo +"$rust_stable" test-sbf -- --nocapture + done +fi diff --git a/ci/cliff.toml b/ci/cliff.toml new file mode 100644 index 00000000000..62578ee4bb0 --- /dev/null +++ b/ci/cliff.toml @@ -0,0 +1,58 @@ +# git-cliff configuration file +# https://git-cliff.org/docs/configuration +# +# Lines starting with "#" are comments. +# Configuration options are organized into tables and keys. +# See documentation for more information on available options. + +[changelog] +header = """ +## What's new +""" +# template for the changelog body +# https://tera.netlify.app/docs +body = """ +{% for group, commits in commits | group_by(attribute="group") %}\ + {% for commit in commits %} + - {{ commit.message | upper_first | split(pat="\n") | first | trim }}\ + {% if commit.remote.username %} by @{{ commit.remote.username }}{%- endif %}\ + {% endfor %}\ +{% endfor %} +""" +# remove the leading and trailing whitespace from the template +trim = true +footer = """ +""" +postprocessors = [ ] +[git] +# parse the commits based on https://www.conventionalcommits.org +conventional_commits = true +# filter out the commits that are not conventional +filter_unconventional = false +# process each line of a commit as an individual commit +split_commits = false +# regex for preprocessing the commit messages +commit_preprocessors = [] +# regex for parsing and grouping commits +commit_parsers = [ + { message = "^build\\(deps\\)", skip = true }, + { message = "^build\\(deps-dev\\)", skip = true }, + { message = "^ci", skip = true }, + { body = ".*", group = "Changes" }, +] +# protect breaking changes from being skipped due to matching a skipping commit_parser +protect_breaking_commits = false +# filter out the commits that are not matched by commit parsers +filter_commits = false +# glob pattern for matching git tags +tag_pattern = "v[0-9]*" +# regex for skipping tags +skip_tags = "" +# regex for ignoring tags +ignore_tags = "" +# sort the tags topologically +topo_order = false +# sort the commits inside sections by oldest/newest order +sort_commits = "newest" +# limit the number of commits included in the changelog. +# limit_commits = 42 diff --git a/ci/do-audit.sh b/ci/do-audit.sh index 9c2bd39cb3b..43ceb9c0ac8 100755 --- a/ci/do-audit.sh +++ b/ci/do-audit.sh @@ -5,26 +5,34 @@ cd "$(dirname "$0")/.." source ./ci/rust-version.sh stable cargo_audit_ignores=( - # failure is officially deprecated/unmaintained + # ed25519-dalek: Double Public Key Signing Function Oracle Attack # - # Blocked on multiple upstream crates removing their `failure` dependency. - --ignore RUSTSEC-2020-0036 + # Remove once SPL upgrades to ed25519-dalek v2 + --ignore RUSTSEC-2022-0093 - # Potential segfault in the time crate + # curve25519-dalek # - # Blocked on chrono and solana_rbpf updating `time` to >= 0.2.23 - --ignore RUSTSEC-2020-0071 + # Remove once SPL upgrades to curve25519-dalek v4 + --ignore RUSTSEC-2024-0344 - # chrono: Potential segfault in `localtime_r` invocations - # - # Blocked due to no safe upgrade - # https://github.com/chronotope/chrono/issues/499 - --ignore RUSTSEC-2020-0159 + # Crate: tonic + # Version: 0.9.2 + # Title: Remotely exploitable Denial of Service in Tonic + # Date: 2024-10-01 + # ID: RUSTSEC-2024-0376 + # URL: https://rustsec.org/advisories/RUSTSEC-2024-0376 + # Solution: Upgrade to >=0.12.3 + --ignore RUSTSEC-2024-0376 - # memmap is officially deprecated/unmaintained, used by honggfuzz - # - # Blcoked on honggfuzz, fixed in https://github.com/rust-fuzz/honggfuzz-rs/pull/55 - # need to update honggfuzz dependency whenever the next version is released - --ignore RUSTSEC-2020-0077 + # Crate: idna + # Version: 0.1.5 + # Title: `idna` accepts Punycode labels that do not produce any non-ASCII when decoded + # Date: 2024-12-09 + # ID: RUSTSEC-2024-0421 + # URL: https://rustsec.org/advisories/RUSTSEC-2024-0421 + # Solution: Upgrade to >=1.0.0 + # need to solve this depentant tree: + # jsonrpc-core-client v18.0.0 -> jsonrpc-client-transports v18.0.0 -> url v1.7.2 -> idna v0.1.5 + --ignore RUSTSEC-2024-0421 ) cargo +"$rust_stable" audit "${cargo_audit_ignores[@]}" diff --git a/ci/fuzz.sh b/ci/fuzz.sh index 0d975f2f097..3fbe4f998e9 100755 --- a/ci/fuzz.sh +++ b/ci/fuzz.sh @@ -2,8 +2,9 @@ set -e cd "$(dirname "$0")/.." +source ./ci/rust-version.sh stable -source ./ci/rust-version.sh nightly +cargo +"$rust_stable" install honggfuzz --version=0.5.56 --force || true usage() { exitcode=0 @@ -25,10 +26,7 @@ if [[ -z $2 ]]; then usage "No runtime provided" fi -# Temporary workaround using RUSTFLAGS and rust nightly due to: -# https://github.com/rust-fuzz/honggfuzz-rs/issues/61 -# Once the issue is resolved, remove the RUSTFLAGS and nightly usage everywhere. -RUSTFLAGS="-Znew-llvm-pass-manager=no" HFUZZ_RUN_ARGS="--run_time $run_time --exit_upon_crash" cargo +nightly-2022-02-24 hfuzz run $fuzz_target +HFUZZ_RUN_ARGS="--run_time $run_time --exit_upon_crash" cargo +"$rust_stable" hfuzz run $fuzz_target # Until https://github.com/rust-fuzz/honggfuzz-rs/issues/16 is resolved, # hfuzz does not return an error code on crash, so look for a crash artifact diff --git a/ci/install-anchor.sh b/ci/install-anchor.sh new file mode 100755 index 00000000000..1ec3711a447 --- /dev/null +++ b/ci/install-anchor.sh @@ -0,0 +1,32 @@ +# +# This file maintains the solana versions for use by CI. +# +# Obtain the environment variables without any automatic updating: +# $ source ci/install-anchor.sh +# +# Obtain the environment variables and install update: +# $ source ci/install-anchor.sh install + +# Then to access the anchor version: +# $ echo "$anchor_cli_version" +# + +if [[ -n $ANCHOR_CLI_VERSION ]]; then + anchor_cli_version="$ANCHOR_CLI_VERSION" +else + anchor_cli_version=v0.29.0 +fi + +export anchor_cli_version="$anchor_cli_version" + +if [[ -n $1 ]]; then + case $1 in + install) + cargo install --git https://github.com/coral-xyz/anchor --tag $anchor_cli_version anchor-cli --locked + anchor --version + ;; + *) + echo "anchor-version.sh: Note: ignoring unknown argument: $1" >&2 + ;; + esac +fi diff --git a/ci/install-build-deps.sh b/ci/install-build-deps.sh index 6b9c82f5995..e1bcdc556bd 100755 --- a/ci/install-build-deps.sh +++ b/ci/install-build-deps.sh @@ -2,6 +2,8 @@ set -ex +sudo apt update sudo apt install libudev-dev -y sudo apt install binutils-dev -y sudo apt install libunwind-dev -y +sudo apt install protobuf-compiler -y diff --git a/ci/install-program-deps.sh b/ci/install-program-deps.sh index 020b945eff1..634153225bc 100755 --- a/ci/install-program-deps.sh +++ b/ci/install-program-deps.sh @@ -9,6 +9,5 @@ set -x cargo --version cargo install rustfilt || true -cargo install honggfuzz --version=0.5.54 --force || true -cargo +"$rust_stable" build-bpf --version +cargo +"$rust_stable" build-sbf --version diff --git a/ci/js-test-account-compression.sh b/ci/js-test-account-compression.sh new file mode 100755 index 00000000000..4d60fd2abc2 --- /dev/null +++ b/ci/js-test-account-compression.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +set -e +cd "$(dirname "$0")/.." +export SOLANA_VERSION="v2.0.14" +source ./ci/solana-version.sh install + +set -x +pnpm install +pnpm format +cd account-compression/sdk +pnpm build +pnpm build:program +pnpm lint +pnpm test diff --git a/ci/js-test-name-service.sh b/ci/js-test-name-service.sh index 4328ef099f1..e78cb1501a2 100755 --- a/ci/js-test-name-service.sh +++ b/ci/js-test-name-service.sh @@ -5,8 +5,11 @@ cd "$(dirname "$0")/.." source ./ci/solana-version.sh install set -x -cd name-service/js +pnpm install +pnpm format -yarn install --pure-lockfile -yarn lint -yarn build +cd name-service/js +pnpm lint +pnpm build:program +pnpm build +pnpm test diff --git a/ci/js-test-stake-pool.sh b/ci/js-test-stake-pool.sh deleted file mode 100755 index 83293036e74..00000000000 --- a/ci/js-test-stake-pool.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -set -ex -cd "$(dirname "$0")/.." -source ./ci/solana-version.sh install - -cd stake-pool/js -npm install -npm run lint -npm run build -npm run test diff --git a/ci/js-test-token-lending.sh b/ci/js-test-token-lending.sh index 2a1c2a146a2..4753d04e2fc 100755 --- a/ci/js-test-token-lending.sh +++ b/ci/js-test-token-lending.sh @@ -2,12 +2,11 @@ set -e cd "$(dirname "$0")/.." -source ./ci/solana-version.sh install - -npm install --global yarn set -x +pnpm install +pnpm format +pnpm build + cd token-lending/js -yarn install --pure-lockfile -yarn run lint -yarn run build +pnpm lint diff --git a/ci/js-test-token-swap.sh b/ci/js-test-token-swap.sh index 867b292f3fe..923a72c7cf1 100755 --- a/ci/js-test-token-swap.sh +++ b/ci/js-test-token-swap.sh @@ -4,10 +4,11 @@ set -ex cd "$(dirname "$0")/.." source ./ci/solana-version.sh install +pnpm install +pnpm format +pnpm build + cd token-swap/js -npm install -npm run lint -npm run build -npm run start-with-test-validator -(cd ../../target/deploy && mv spl_token_swap_production.so spl_token_swap.so) -SWAP_PROGRAM_OWNER_FEE_ADDRESS="HfoTxFR1Tm6kGmWgYWD6J7YHVy1UwqSULUGVLXkJqaKN" npm run start-with-test-validator +pnpm build:program +pnpm lint +pnpm test diff --git a/ci/js-test-token.sh b/ci/js-test-token.sh deleted file mode 100755 index e62fdc10398..00000000000 --- a/ci/js-test-token.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -set -e -cd "$(dirname "$0")/.." -source ./ci/solana-version.sh install - -set -x -cd token/js - -yarn install --pure-lockfile -yarn lint -yarn build -yarn test diff --git a/ci/publish-rust.sh b/ci/publish-rust.sh new file mode 100755 index 00000000000..b5e6f362c3b --- /dev/null +++ b/ci/publish-rust.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash + +set -e +base="$(dirname "${BASH_SOURCE[0]}")" +source "$base/read-cargo-variable.sh" +cd "$base/.." + +if [[ -z $1 ]]; then + echo 'A package manifest path — e.g. "token/program" — must be provided.' + exit 1 +fi +PACKAGE_PATH=$1 +if [[ -z $2 ]]; then + echo 'A version level — e.g. "patch" — must be provided.' + exit 1 +fi +LEVEL=$2 +DRY_RUN=$3 + +# Go to the directory +cd "${PACKAGE_PATH}" + +# Get the old version, used with git-cliff +old_version=$(readCargoVariable version "Cargo.toml") +package_name=$(readCargoVariable name "Cargo.toml") +tag_name="$(echo $package_name | sed 's/spl-//')" + +# Publish the new version, commit the repo change, tag it, and push it all. +if [[ -n ${DRY_RUN} ]]; then + cargo release ${LEVEL} +else + cargo release ${LEVEL} --tag-name "${tag_name}-v{{version}}" --no-confirm --execute +fi + +# Stop here if this is a dry run. +if [[ -n $DRY_RUN ]]; then + exit 0 +fi + +# Get the new version. +new_version=$(readCargoVariable version "Cargo.toml") +new_git_tag="${tag_name}-v${new_version}" +old_git_tag="${tag_name}-v${old_version}" +release_title="SPL ${tag_name} - v${new_version}" + +# Expose the new version to CI if needed. +if [[ -n $CI ]]; then + echo "new_git_tag=${new_git_tag}" >> $GITHUB_OUTPUT + echo "old_git_tag=${old_git_tag}" >> $GITHUB_OUTPUT + echo "release_title=${release_title}" >> $GITHUB_OUTPUT +fi diff --git a/ci/py-test-stake-pool.sh b/ci/py-test-stake-pool.sh deleted file mode 100755 index 4c3ca8cfe72..00000000000 --- a/ci/py-test-stake-pool.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -set -ex -cd "$(dirname "$0")/.." -source ./ci/solana-version.sh install - -cd stake-pool/py -python3 -m venv venv -source ./venv/bin/activate -pip3 install -r requirements.txt -pip3 install -r optional-requirements.txt -check_dirs=( - "bot" - "spl_token" - "stake" - "stake_pool" - "system" - "tests" - "vote" -) -flake8 "${check_dirs[@]}" -mypy "${check_dirs[@]}" -python3 -m pytest diff --git a/ci/read-cargo-variable.sh b/ci/read-cargo-variable.sh new file mode 100644 index 00000000000..7f6c9518156 --- /dev/null +++ b/ci/read-cargo-variable.sh @@ -0,0 +1,14 @@ +# source this file + +readCargoVariable() { + declare variable="$1" + declare Cargo_toml="$2" + + while read -r name equals value _; do + if [[ $name = "$variable" && $equals = = ]]; then + echo "${value//\"/}" + return + fi + done < <(cat "$Cargo_toml") + echo "Unable to locate $variable in $Cargo_toml" 1>&2 +} diff --git a/ci/rust-version.sh b/ci/rust-version.sh index 370f018f600..2d9d7060a83 100644 --- a/ci/rust-version.sh +++ b/ci/rust-version.sh @@ -18,13 +18,15 @@ if [[ -n $RUST_STABLE_VERSION ]]; then stable_version="$RUST_STABLE_VERSION" else - stable_version=1.59.0 + base="$(dirname "${BASH_SOURCE[0]}")" + source "$base/read-cargo-variable.sh" + stable_version=$(readCargoVariable channel "$base/../rust-toolchain.toml") fi if [[ -n $RUST_NIGHTLY_VERSION ]]; then nightly_version="$RUST_NIGHTLY_VERSION" else - nightly_version=2022-02-24 + nightly_version=2024-08-08 fi export rust_stable="$stable_version" diff --git a/ci/solana-version.sh b/ci/solana-version.sh index a17386c475c..a299a5ee36d 100755 --- a/ci/solana-version.sh +++ b/ci/solana-version.sh @@ -14,7 +14,7 @@ if [[ -n $SOLANA_VERSION ]]; then solana_version="$SOLANA_VERSION" else - solana_version=v1.10.33 + solana_version=v2.1.0 fi export solana_version="$solana_version" @@ -23,7 +23,7 @@ export PATH="$HOME"/.local/share/solana/install/active_release/bin:"$PATH" if [[ -n $1 ]]; then case $1 in install) - sh -c "$(curl -sSfL https://release.solana.com/$solana_version/install)" + sh -c "$(curl -sSfL https://release.anza.xyz/$solana_version/install)" solana --version ;; *) diff --git a/ci/ts-test-memo.sh b/ci/ts-test-memo.sh deleted file mode 100755 index 6d71cb72135..00000000000 --- a/ci/ts-test-memo.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash - -set -e -cd "$(dirname "$0")/.." -source ./ci/solana-version.sh install - -set -x -cd memo/ts -yarn -yarn build -yarn lint -yarn test diff --git a/ci/warning/purge-ubuntu-runner.sh b/ci/warning/purge-ubuntu-runner.sh new file mode 100644 index 00000000000..bcdf9073320 --- /dev/null +++ b/ci/warning/purge-ubuntu-runner.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +# WARNING: THIS IS NOT TO BE USED LOCALLY, BUT ONLY IN GITHUB ACTIONS TO CLEAR +# DISK SPACE ON UBUNTU. IT IS NOT MARKED AS EXECUTABLE BY DEFAULT FOR SAFETY AND +# ONLY RUNS IN CI. +# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +if [[ -n "$CI" ]]; then + set -e + + sudo rm -rf /usr/share/dotnet + sudo rm -rf /usr/share/swift + sudo rm -rf /usr/share/mysql + sudo rm -rf /usr/share/az_* + sudo rm -rf /usr/share/postgresql-common + + sudo rm -rf /opt/ghc + sudo rm -rf /opt/az + sudo rm -rf /opt/pipx + sudo rm -rf /opt/microsoft + sudo rm -rf /opt/google + sudo rm -rf /opt/hostedtoolcache + + sudo rm -rf /usr/local/lib/android + sudo rm -rf /usr/local/lib/heroku + sudo rm -rf /imagegeneration +fi diff --git a/coverage.sh b/coverage.sh index e2923813d81..edaca0b88ba 100755 --- a/coverage.sh +++ b/coverage.sh @@ -22,8 +22,6 @@ reportName="lcov-${CI_COMMIT:0:9}" if [[ -z $1 ]]; then programs=( libraries/math - memo/program - token/program token-lending/program token-swap/program ) diff --git a/docs/README.md b/docs/README.md index ff77dbd1b33..bfce9f734e3 100644 --- a/docs/README.md +++ b/docs/README.md @@ -11,7 +11,7 @@ $ npm install ### Local Development -This command starts a local development server and open up a browser window. +This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. ``` diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index a2dd00a14d8..4de5c7aa7e7 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -21,7 +21,7 @@ module.exports = { position: "left", }, { - href: "https://discordapp.com/invite/pquxPsq", + href: "https://solana.com/discord", label: "Chat", position: "right", }, @@ -41,7 +41,7 @@ module.exports = { items: [ { label: "Discord", - href: "https://discordapp.com/invite/pquxPsq", + href: "https://solana.com/discord", }, { label: "Twitter", @@ -75,6 +75,9 @@ module.exports = { path: "src", routeBasePath: "/", sidebarPath: require.resolve("./sidebars.js"), + editUrl: ({ docPath }) => { + return `https://github.com/solana-labs/solana-program-library/edit/master/docs/src/${docPath}`; + } }, theme: { customCss: require.resolve("./src/css/custom.css"), @@ -82,4 +85,10 @@ module.exports = { }, ], ], + scripts: [ + 'https://buttons.github.io/buttons.js', + 'https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js', + '/js/code-block-buttons.js', + ], + stylesheets: ['/css/code-block-buttons.css'], }; diff --git a/docs/package-lock.json b/docs/package-lock.json index fe68c4fb968..0ac0508faa6 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -8,114 +8,129 @@ "name": "solana-spl-docs", "version": "0.0.0", "dependencies": { - "@docusaurus/core": "^2.0.0-alpha.73", - "@docusaurus/preset-classic": "^2.0.0-alpha.73", - "@docusaurus/theme-search-algolia": "^2.0.0-alpha.73", + "@babel/eslint-parser": "^7.2.0", + "@docusaurus/core": "^3.0.0", + "@docusaurus/preset-classic": "^3.0.0", "autocomplete.js": "^0.38.1", - "babel-eslint": "^10.1.0", "clsx": "^1.1.1", - "docusaurus-lunr-search": "^2.1.7", + "docusaurus-lunr-search": "^3.3.0", "eslint": "^7.3.1", - "eslint-plugin-react": "^7.20.0", + "eslint-plugin-react": "^7.28.0", "prettier": "^2.0.5", - "react": "^16.8.4", - "react-dom": "^16.8.4" + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, "node_modules/@algolia/autocomplete-core": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.5.2.tgz", - "integrity": "sha512-DY0bhyczFSS1b/CqJlTE/nQRtnTAHl6IemIkBy0nEWnhDzRDdtdx4p5Uuk3vwAFxwEEgi1WqKwgSSMx6DpNL4A==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.9.3.tgz", + "integrity": "sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.9.3", + "@algolia/autocomplete-shared": "1.9.3" + } + }, + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.9.3.tgz", + "integrity": "sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg==", "dependencies": { - "@algolia/autocomplete-shared": "1.5.2" + "@algolia/autocomplete-shared": "1.9.3" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" } }, "node_modules/@algolia/autocomplete-preset-algolia": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.5.2.tgz", - "integrity": "sha512-3MRYnYQFJyovANzSX2CToS6/5cfVjbLLqFsZTKcvF3abhQzxbqwwaMBlJtt620uBUOeMzhdfasKhCc40+RHiZw==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.9.3.tgz", + "integrity": "sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA==", "dependencies": { - "@algolia/autocomplete-shared": "1.5.2" + "@algolia/autocomplete-shared": "1.9.3" }, "peerDependencies": { - "@algolia/client-search": "^4.9.1", - "algoliasearch": "^4.9.1" + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" } }, "node_modules/@algolia/autocomplete-shared": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.5.2.tgz", - "integrity": "sha512-ylQAYv5H0YKMfHgVWX0j0NmL8XBcAeeeVQUmppnnMtzDbDnca6CzhKj3Q8eF9cHCgcdTDdb5K+3aKyGWA0obug==" + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.9.3.tgz", + "integrity": "sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } }, "node_modules/@algolia/cache-browser-local-storage": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.12.1.tgz", - "integrity": "sha512-ERFFOnC9740xAkuO0iZTQqm2AzU7Dpz/s+g7o48GlZgx5p9GgNcsuK5eS0GoW/tAK+fnKlizCtlFHNuIWuvfsg==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.20.0.tgz", + "integrity": "sha512-uujahcBt4DxduBTvYdwO3sBfHuJvJokiC3BP1+O70fglmE1ShkH8lpXqZBac1rrU3FnNYSUs4pL9lBdTKeRPOQ==", "dependencies": { - "@algolia/cache-common": "4.12.1" + "@algolia/cache-common": "4.20.0" } }, "node_modules/@algolia/cache-common": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.12.1.tgz", - "integrity": "sha512-UugTER3V40jT+e19Dmph5PKMeliYKxycNPwrPNADin0RcWNfT2QksK9Ff2N2W7UKraqMOzoeDb4LAJtxcK1a8Q==" + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.20.0.tgz", + "integrity": "sha512-vCfxauaZutL3NImzB2G9LjLt36vKAckc6DhMp05An14kVo8F1Yofb6SIl6U3SaEz8pG2QOB9ptwM5c+zGevwIQ==" }, "node_modules/@algolia/cache-in-memory": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.12.1.tgz", - "integrity": "sha512-U6iaunaxK1lHsAf02UWF58foKFEcrVLsHwN56UkCtwn32nlP9rz52WOcHsgk6TJrL8NDcO5swMjtOQ5XHESFLw==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.20.0.tgz", + "integrity": "sha512-Wm9ak/IaacAZXS4mB3+qF/KCoVSBV6aLgIGFEtQtJwjv64g4ePMapORGmCyulCFwfePaRAtcaTbMcJF+voc/bg==", "dependencies": { - "@algolia/cache-common": "4.12.1" + "@algolia/cache-common": "4.20.0" } }, "node_modules/@algolia/client-account": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.12.1.tgz", - "integrity": "sha512-jGo4ConJNoMdTCR2zouO0jO/JcJmzOK6crFxMMLvdnB1JhmMbuIKluOTJVlBWeivnmcsqb7r0v7qTCPW5PAyxQ==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.20.0.tgz", + "integrity": "sha512-GGToLQvrwo7am4zVkZTnKa72pheQeez/16sURDWm7Seyz+HUxKi3BM6fthVVPUEBhtJ0reyVtuK9ArmnaKl10Q==", "dependencies": { - "@algolia/client-common": "4.12.1", - "@algolia/client-search": "4.12.1", - "@algolia/transporter": "4.12.1" + "@algolia/client-common": "4.20.0", + "@algolia/client-search": "4.20.0", + "@algolia/transporter": "4.20.0" } }, "node_modules/@algolia/client-analytics": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.12.1.tgz", - "integrity": "sha512-h1It7KXzIthlhuhfBk7LteYq72tym9maQDUsyRW0Gft8b6ZQahnRak9gcCvKwhcJ1vJoP7T7JrNYGiYSicTD9g==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.20.0.tgz", + "integrity": "sha512-EIr+PdFMOallRdBTHHdKI3CstslgLORQG7844Mq84ib5oVFRVASuuPmG4bXBgiDbcsMLUeOC6zRVJhv1KWI0ug==", "dependencies": { - "@algolia/client-common": "4.12.1", - "@algolia/client-search": "4.12.1", - "@algolia/requester-common": "4.12.1", - "@algolia/transporter": "4.12.1" + "@algolia/client-common": "4.20.0", + "@algolia/client-search": "4.20.0", + "@algolia/requester-common": "4.20.0", + "@algolia/transporter": "4.20.0" } }, "node_modules/@algolia/client-common": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.12.1.tgz", - "integrity": "sha512-obnJ8eSbv+h94Grk83DTGQ3bqhViSWureV6oK1s21/KMGWbb3DkduHm+lcwFrMFkjSUSzosLBHV9EQUIBvueTw==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.20.0.tgz", + "integrity": "sha512-P3WgMdEss915p+knMMSd/fwiHRHKvDu4DYRrCRaBrsfFw7EQHon+EbRSm4QisS9NYdxbS04kcvNoavVGthyfqQ==", "dependencies": { - "@algolia/requester-common": "4.12.1", - "@algolia/transporter": "4.12.1" + "@algolia/requester-common": "4.20.0", + "@algolia/transporter": "4.20.0" } }, "node_modules/@algolia/client-personalization": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.12.1.tgz", - "integrity": "sha512-sMSnjjPjRgByGHYygV+5L/E8a6RgU7l2GbpJukSzJ9GRY37tHmBHuvahv8JjdCGJ2p7QDYLnQy5bN5Z02qjc7Q==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.20.0.tgz", + "integrity": "sha512-N9+zx0tWOQsLc3K4PVRDV8GUeOLAY0i445En79Pr3zWB+m67V+n/8w4Kw1C5LlbHDDJcyhMMIlqezh6BEk7xAQ==", "dependencies": { - "@algolia/client-common": "4.12.1", - "@algolia/requester-common": "4.12.1", - "@algolia/transporter": "4.12.1" + "@algolia/client-common": "4.20.0", + "@algolia/requester-common": "4.20.0", + "@algolia/transporter": "4.20.0" } }, "node_modules/@algolia/client-search": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.12.1.tgz", - "integrity": "sha512-MwwKKprfY6X2nJ5Ki/ccXM2GDEePvVjZnnoOB2io3dLKW4fTqeSRlC5DRXeFD7UM0vOPPHr4ItV2aj19APKNVQ==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.20.0.tgz", + "integrity": "sha512-zgwqnMvhWLdpzKTpd3sGmMlr4c+iS7eyyLGiaO51zDZWGMkpgoNVmltkzdBwxOVXz0RsFMznIxB9zuarUv4TZg==", "dependencies": { - "@algolia/client-common": "4.12.1", - "@algolia/requester-common": "4.12.1", - "@algolia/transporter": "4.12.1" + "@algolia/client-common": "4.20.0", + "@algolia/requester-common": "4.20.0", + "@algolia/transporter": "4.20.0" } }, "node_modules/@algolia/events": { @@ -124,99 +139,101 @@ "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==" }, "node_modules/@algolia/logger-common": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.12.1.tgz", - "integrity": "sha512-fCgrzlXGATNqdFTxwx0GsyPXK+Uqrx1SZ3iuY2VGPPqdt1a20clAG2n2OcLHJpvaa6vMFPlJyWvbqAgzxdxBlQ==" + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.20.0.tgz", + "integrity": "sha512-xouigCMB5WJYEwvoWW5XDv7Z9f0A8VoXJc3VKwlHJw/je+3p2RcDXfksLI4G4lIVncFUYMZx30tP/rsdlvvzHQ==" }, "node_modules/@algolia/logger-console": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.12.1.tgz", - "integrity": "sha512-0owaEnq/davngQMYqxLA4KrhWHiXujQ1CU3FFnyUcMyBR7rGHI48zSOUpqnsAXrMBdSH6rH5BDkSUUFwsh8RkQ==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.20.0.tgz", + "integrity": "sha512-THlIGG1g/FS63z0StQqDhT6bprUczBI8wnLT3JWvfAQDZX5P6fCg7dG+pIrUBpDIHGszgkqYEqECaKKsdNKOUA==", "dependencies": { - "@algolia/logger-common": "4.12.1" + "@algolia/logger-common": "4.20.0" } }, "node_modules/@algolia/requester-browser-xhr": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.12.1.tgz", - "integrity": "sha512-OaMxDyG0TZG0oqz1lQh9e3woantAG1bLnuwq3fmypsrQxra4IQZiyn1x+kEb69D2TcXApI5gOgrD4oWhtEVMtw==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.20.0.tgz", + "integrity": "sha512-HbzoSjcjuUmYOkcHECkVTwAelmvTlgs48N6Owt4FnTOQdwn0b8pdht9eMgishvk8+F8bal354nhx/xOoTfwiAw==", "dependencies": { - "@algolia/requester-common": "4.12.1" + "@algolia/requester-common": "4.20.0" } }, "node_modules/@algolia/requester-common": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.12.1.tgz", - "integrity": "sha512-XWIrWQNJ1vIrSuL/bUk3ZwNMNxl+aWz6dNboRW6+lGTcMIwc3NBFE90ogbZKhNrFRff8zI4qCF15tjW+Fyhpow==" + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.20.0.tgz", + "integrity": "sha512-9h6ye6RY/BkfmeJp7Z8gyyeMrmmWsMOCRBXQDs4mZKKsyVlfIVICpcSibbeYcuUdurLhIlrOUkH3rQEgZzonng==" }, "node_modules/@algolia/requester-node-http": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.12.1.tgz", - "integrity": "sha512-awBtwaD+s0hxkA1aehYn8F0t9wqGoBVWgY4JPHBmp1ChO3pK7RKnnvnv7QQa9vTlllX29oPt/BBVgMo1Z3n1Qg==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.20.0.tgz", + "integrity": "sha512-ocJ66L60ABSSTRFnCHIEZpNHv6qTxsBwJEPfYaSBsLQodm0F9ptvalFkHMpvj5DfE22oZrcrLbOYM2bdPJRHng==", "dependencies": { - "@algolia/requester-common": "4.12.1" + "@algolia/requester-common": "4.20.0" } }, "node_modules/@algolia/transporter": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.12.1.tgz", - "integrity": "sha512-BGeNgdEHc6dXIk2g8kdlOoQ6fQ6OIaKQcplEj7HPoi+XZUeAvRi3Pff3QWd7YmybWkjzd9AnTzieTASDWhL+sQ==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.20.0.tgz", + "integrity": "sha512-Lsii1pGWOAISbzeyuf+r/GPhvHMPHSPrTDWNcIzOE1SG1inlJHICaVe2ikuoRjcpgxZNU54Jl+if15SUCsaTUg==", "dependencies": { - "@algolia/cache-common": "4.12.1", - "@algolia/logger-common": "4.12.1", - "@algolia/requester-common": "4.12.1" + "@algolia/cache-common": "4.20.0", + "@algolia/logger-common": "4.20.0", + "@algolia/requester-common": "4.20.0" } }, "node_modules/@ampproject/remapping": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", - "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.0" + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.4.tgz", + "integrity": "sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==", "dependencies": { - "@babel/highlight": "^7.16.7" + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", - "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz", + "integrity": "sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.17.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.5.tgz", - "integrity": "sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA==", - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helpers": "^7.17.2", - "@babel/parser": "^7.17.3", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0", - "convert-source-map": "^1.7.0", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.3.tgz", + "integrity": "sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.2", + "@babel/parser": "^7.23.3", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.3", + "@babel/types": "^7.23.3", + "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0" + "json5": "^2.2.3", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -227,86 +244,132 @@ } }, "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/eslint-parser": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.23.3.tgz", + "integrity": "sha512-9bTuNlyx7oSstodm1cR1bECj4fkiknsDa1YniISkJemMY3DGhJNYBECbe6QD/q54mp2J8VO66jW3/7uP//iFCw==", + "dependencies": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0", + "eslint": "^7.5.0 || ^8.0.0" + } + }, + "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@babel/eslint-parser/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/generator": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", - "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.4.tgz", + "integrity": "sha512-esuS49Cga3HcThFNebGhlgsrVLkvhqvYDTzgjfFFlHJcIfLe5jFmRRfCQ1KuBfc4Jrtn3ndLgKWAKjBE+IraYQ==", "dependencies": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@babel/types": "^7.23.4", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", - "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", - "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", - "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", "dependencies": { - "@babel/compat-data": "^7.16.4", - "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.17.5", - "semver": "^6.3.0" + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" } }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz", - "integrity": "sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz", + "integrity": "sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -315,13 +378,22 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", - "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "regexpu-core": "^5.0.1" + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -330,259 +402,241 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", - "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", - "dependencies": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0-0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", - "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.3.tgz", + "integrity": "sha512-WBrLmuPP47n7PNwsZ57pqam6G/RGo1vw/87b0Blc53tZNGZ4x7YvZ6HgQe2vo1W/FR20OgjeZuGXzudPiXHFug==", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" }, - "engines": { - "node": ">=6.9.0" + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", - "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", - "dependencies": { - "@babel/types": "^7.16.7" - }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", - "dependencies": { - "@babel/helper-get-function-arity": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", - "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", - "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz", - "integrity": "sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", "dependencies": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", - "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", - "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", - "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-wrap-function": "^7.16.8", - "@babel/types": "^7.16.8" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", - "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", + "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", "dependencies": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", - "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", - "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", "dependencies": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", - "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", - "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", "dependencies": { - "@babel/helper-function-name": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.8", - "@babel/types": "^7.16.8" + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", - "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.4.tgz", + "integrity": "sha512-HfcMizYz10cr3h29VqyfGL6ZWIjTwWfvYBMsBVGwpcbhNGe3wQ1ZXZRPzZoAHhd9OqHadHqjQ89iVKINXnbzuw==", "dependencies": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.0", - "@babel/types": "^7.17.0" + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.4", + "@babel/types": "^7.23.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -590,9 +644,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz", - "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.4.tgz", + "integrity": "sha512-vf3Xna6UEprW+7t6EtOmFpHNAuxw3xqPZghy+brsnusscJRW5BMUzzHZc5ICjULee81WeUV2jjakG09MDglJXQ==", "bin": { "parser": "bin/babel-parser.js" }, @@ -601,11 +655,11 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz", - "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.23.3.tgz", + "integrity": "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -615,13 +669,13 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", - "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz", + "integrity": "sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.23.3" }, "engines": { "node": ">=6.9.0" @@ -630,217 +684,25 @@ "@babel/core": "^7.13.0" } }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", - "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", - "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.6.tgz", - "integrity": "sha512-X/tididvL2zbs7jZCeeRJ8167U/+Ac135AM6jCAx6gYXDUviZV5Ku9UDvWS2NCuWlFjIRXklYhwo6HhAC7ETnA==", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.17.6", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", - "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", - "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", - "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", - "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", - "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", - "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz", - "integrity": "sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw==", - "dependencies": { - "@babel/compat-data": "^7.17.0", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", - "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", - "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", - "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.3.tgz", + "integrity": "sha512-XaJak1qcityzrX0/IU5nKHb34VaibwP3saKqG6a/tppelgllOH13LUann4ZCIBcVOeE6H18K4Vx9QKkVww3z/w==", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.10", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", - "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", "engines": { "node": ">=6.9.0" }, @@ -848,21 +710,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", - "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-async-generators": { "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", @@ -921,6 +768,45 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz", + "integrity": "sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.23.3.tgz", + "integrity": "sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-json-strings": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", @@ -933,11 +819,11 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz", - "integrity": "sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz", + "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1041,11 +927,11 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", - "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz", + "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1054,28 +940,27 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", - "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", - "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz", + "integrity": "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==", "dependencies": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1084,12 +969,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", - "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.4.tgz", + "integrity": "sha512-efdkfPhHYTtn0G6n2ddrESE91fgXxjlqLsnUtPWnJs4a4mZIbUaK7ffqKIIUKXSHwcDvaCVX6GXkaJJFqtX7jw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20", + "@babel/plugin-syntax-async-generators": "^7.8.4" }, "engines": { "node": ">=6.9.0" @@ -1098,12 +986,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", - "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", + "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20" }, "engines": { "node": ">=6.9.0" @@ -1112,18 +1002,78 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz", + "integrity": "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz", + "integrity": "sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.23.3.tgz", + "integrity": "sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.23.4.tgz", + "integrity": "sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", - "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.3.tgz", + "integrity": "sha512-FGEQmugvAEu2QtgtU0uTASXevfLMFfBeVCIIdcQhn/uBQsMTjBajdnAtanQlOcuihWh10PZ7+HWvc7NtBwP74w==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-split-export-declaration": "^7.22.6", "globals": "^11.1.0" }, "engines": { @@ -1134,11 +1084,12 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", - "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz", + "integrity": "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.15" }, "engines": { "node": ">=6.9.0" @@ -1148,11 +1099,11 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.3.tgz", - "integrity": "sha512-dDFzegDYKlPqa72xIlbmSkly5MluLoaC1JswABGktyt6NTXSBcUuse/kWE/wvKFWJHPETpi158qJZFS3JmykJg==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz", + "integrity": "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1162,12 +1113,12 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", - "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz", + "integrity": "sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1177,11 +1128,26 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", - "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz", + "integrity": "sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.23.4.tgz", + "integrity": "sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -1191,12 +1157,12 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", - "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz", + "integrity": "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==", "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1205,12 +1171,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", - "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.4.tgz", + "integrity": "sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -1219,14 +1186,12 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", - "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.3.tgz", + "integrity": "sha512-X8jSm8X1CMwxmK878qsUGJRmbysKNbdpTv/O1/v0LuY/ZkZrng5WYiekYSdg9m09OTmDDUWeEDsTE+17WYbAZw==", "dependencies": { - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1235,12 +1200,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", - "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz", + "integrity": "sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1249,12 +1216,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", - "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.23.4.tgz", + "integrity": "sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -1263,14 +1231,12 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", - "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", + "node_modules/@babel/plugin-transform-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz", + "integrity": "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==", "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1279,23 +1245,27 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-modules-amd/node_modules/babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.23.4.tgz", + "integrity": "sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==", "dependencies": { - "object.assign": "^4.1.0" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", - "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz", + "integrity": "sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==", "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1304,24 +1274,29 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-modules-commonjs/node_modules/babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz", + "integrity": "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==", "dependencies": { - "object.assign": "^4.1.0" + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", - "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", + "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", "dependencies": { - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1330,21 +1305,30 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-modules-systemjs/node_modules/babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.3.tgz", + "integrity": "sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==", "dependencies": { - "object.assign": "^4.1.0" + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", - "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz", + "integrity": "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==", "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1354,11 +1338,12 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", - "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1368,11 +1353,59 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", - "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz", + "integrity": "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.4.tgz", + "integrity": "sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.23.4.tgz", + "integrity": "sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz", + "integrity": "sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==", + "dependencies": { + "@babel/compat-data": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.23.3" }, "engines": { "node": ">=6.9.0" @@ -1382,12 +1415,43 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", - "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz", + "integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.23.4.tgz", + "integrity": "sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz", + "integrity": "sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -1397,11 +1461,43 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", - "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz", + "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.23.3.tgz", + "integrity": "sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.4.tgz", + "integrity": "sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "engines": { "node": ">=6.9.0" @@ -1411,11 +1507,11 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", - "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz", + "integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1425,11 +1521,11 @@ } }, "node_modules/@babel/plugin-transform-react-constant-elements": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.17.6.tgz", - "integrity": "sha512-OBv9VkyyKtsHZiHLoSfCn+h6yU7YKX8nrs32xUmOa1SRSk+t03FosB6fBZ0Yz4BpD1WV7l73Nsad+2Tz7APpqw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.23.3.tgz", + "integrity": "sha512-zP0QKq/p6O42OL94udMgSfKXyse4RyJ0JqbQ34zDAONWjyrEsghYEyTSK5FIpmXmCpB55SHokL1cRRKHv8L2Qw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1439,11 +1535,11 @@ } }, "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz", - "integrity": "sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.22.5.tgz", + "integrity": "sha512-PVk3WPYudRF5z4GKMEYUrLjPl38fJSKNaEOkFuoprioowGuWN6w2RKznuFNSlJx7pzzXXStPUnNSOEO0jL5EVw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1453,15 +1549,15 @@ } }, "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.17.3.tgz", - "integrity": "sha512-9tjBm4O07f7mzKSIlEmPdiE6ub7kfIe6Cd+w+oQebpATfTQMAgW+YOuWxogbKVTulA+MEO7byMeIUtQ1z+z+ZQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.5.tgz", + "integrity": "sha512-rog5gZaVbUip5iWDMTYbVM15XQq+RkUKhET/IHR6oizR+JEoN6CAfTTuHcK4vwUyzca30qqHqEpzBOnaRMWYMA==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-jsx": "^7.16.7", - "@babel/types": "^7.17.0" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.22.5", + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1471,11 +1567,11 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.7.tgz", - "integrity": "sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz", + "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==", "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.16.7" + "@babel/plugin-transform-react-jsx": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1485,12 +1581,12 @@ } }, "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.7.tgz", - "integrity": "sha512-hs71ToC97k3QWxswh2ElzMFABXHvGiJ01IB1TbYQDGeWRKWz/MPUTh5jGExdHvosYKpnJW5Pm3S4+TA3FyX+GA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.22.5.tgz", + "integrity": "sha512-gP4k85wx09q+brArVinTXhWiyzLl9UpmGva0+mWyKxk6JZequ05x3eUcIUE+FyttPKJFRRVtAvQaJ6YF9h1ZpA==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1500,11 +1596,12 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", - "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz", + "integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==", "dependencies": { - "regenerator-transform": "^0.14.2" + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.2" }, "engines": { "node": ">=6.9.0" @@ -1514,11 +1611,11 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", - "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz", + "integrity": "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1528,16 +1625,16 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.17.0.tgz", - "integrity": "sha512-fr7zPWnKXNc1xoHfrIU9mN/4XKX4VLZ45Q+oMhfsYIaHvg7mHgmhfOy/ckRWqDK7XF3QDigRpkh5DKq6+clE8A==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.23.4.tgz", + "integrity": "sha512-ITwqpb6V4btwUG0YJR82o2QvmWrLgDnx/p2A3CTPYGaRgULkDiC0DRA2C4jlRB9uXGUEfaSS/IGHfVW+ohzYDw==", "dependencies": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "semver": "^6.3.0" + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "babel-plugin-polyfill-corejs2": "^0.4.6", + "babel-plugin-polyfill-corejs3": "^0.8.5", + "babel-plugin-polyfill-regenerator": "^0.5.3", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -1547,19 +1644,19 @@ } }, "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", - "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz", + "integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1569,12 +1666,12 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", - "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz", + "integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1584,11 +1681,11 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", - "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz", + "integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1598,11 +1695,11 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", - "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz", + "integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1612,11 +1709,11 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", - "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz", + "integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1626,13 +1723,14 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz", - "integrity": "sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.22.5.tgz", + "integrity": "sha512-SMubA9S7Cb5sGSFFUlqxyClTA9zWJ8qGQrppNUm05LtFuN1ELRFNndkix4zUJrC9F+YivWwa1dHMSyo0e0N9dA==", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-typescript": "^7.16.7" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-typescript": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1642,11 +1740,26 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", - "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz", + "integrity": "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.23.3.tgz", + "integrity": "sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1656,12 +1769,12 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", - "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz", + "integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1670,37 +1783,42 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.23.3.tgz", + "integrity": "sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/preset-env": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", - "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", - "dependencies": { - "@babel/compat-data": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-async-generator-functions": "^7.16.8", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-class-static-block": "^7.16.7", - "@babel/plugin-proposal-dynamic-import": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.16.7", - "@babel/plugin-proposal-json-strings": "^7.16.7", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", - "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.16.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", - "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.11", - "@babel/plugin-proposal-private-property-in-object": "^7.16.7", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.3.tgz", + "integrity": "sha512-ovzGc2uuyNfNAs/jyjIGxS8arOHS5FENZaNn4rtE7UdKMMkqHCvboHfcuhWLZNX5cB44QfcGNWjaevxMzzMf+Q==", + "dependencies": { + "@babel/compat-data": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.3", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.23.3", + "@babel/plugin-syntax-import-attributes": "^7.23.3", + "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", @@ -1710,45 +1828,61 @@ "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.7", - "@babel/plugin-transform-async-to-generator": "^7.16.8", - "@babel/plugin-transform-block-scoped-functions": "^7.16.7", - "@babel/plugin-transform-block-scoping": "^7.16.7", - "@babel/plugin-transform-classes": "^7.16.7", - "@babel/plugin-transform-computed-properties": "^7.16.7", - "@babel/plugin-transform-destructuring": "^7.16.7", - "@babel/plugin-transform-dotall-regex": "^7.16.7", - "@babel/plugin-transform-duplicate-keys": "^7.16.7", - "@babel/plugin-transform-exponentiation-operator": "^7.16.7", - "@babel/plugin-transform-for-of": "^7.16.7", - "@babel/plugin-transform-function-name": "^7.16.7", - "@babel/plugin-transform-literals": "^7.16.7", - "@babel/plugin-transform-member-expression-literals": "^7.16.7", - "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-modules-commonjs": "^7.16.8", - "@babel/plugin-transform-modules-systemjs": "^7.16.7", - "@babel/plugin-transform-modules-umd": "^7.16.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", - "@babel/plugin-transform-new-target": "^7.16.7", - "@babel/plugin-transform-object-super": "^7.16.7", - "@babel/plugin-transform-parameters": "^7.16.7", - "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.16.7", - "@babel/plugin-transform-reserved-words": "^7.16.7", - "@babel/plugin-transform-shorthand-properties": "^7.16.7", - "@babel/plugin-transform-spread": "^7.16.7", - "@babel/plugin-transform-sticky-regex": "^7.16.7", - "@babel/plugin-transform-template-literals": "^7.16.7", - "@babel/plugin-transform-typeof-symbol": "^7.16.7", - "@babel/plugin-transform-unicode-escapes": "^7.16.7", - "@babel/plugin-transform-unicode-regex": "^7.16.7", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.8", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.20.2", - "semver": "^6.3.0" + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.23.3", + "@babel/plugin-transform-async-generator-functions": "^7.23.3", + "@babel/plugin-transform-async-to-generator": "^7.23.3", + "@babel/plugin-transform-block-scoped-functions": "^7.23.3", + "@babel/plugin-transform-block-scoping": "^7.23.3", + "@babel/plugin-transform-class-properties": "^7.23.3", + "@babel/plugin-transform-class-static-block": "^7.23.3", + "@babel/plugin-transform-classes": "^7.23.3", + "@babel/plugin-transform-computed-properties": "^7.23.3", + "@babel/plugin-transform-destructuring": "^7.23.3", + "@babel/plugin-transform-dotall-regex": "^7.23.3", + "@babel/plugin-transform-duplicate-keys": "^7.23.3", + "@babel/plugin-transform-dynamic-import": "^7.23.3", + "@babel/plugin-transform-exponentiation-operator": "^7.23.3", + "@babel/plugin-transform-export-namespace-from": "^7.23.3", + "@babel/plugin-transform-for-of": "^7.23.3", + "@babel/plugin-transform-function-name": "^7.23.3", + "@babel/plugin-transform-json-strings": "^7.23.3", + "@babel/plugin-transform-literals": "^7.23.3", + "@babel/plugin-transform-logical-assignment-operators": "^7.23.3", + "@babel/plugin-transform-member-expression-literals": "^7.23.3", + "@babel/plugin-transform-modules-amd": "^7.23.3", + "@babel/plugin-transform-modules-commonjs": "^7.23.3", + "@babel/plugin-transform-modules-systemjs": "^7.23.3", + "@babel/plugin-transform-modules-umd": "^7.23.3", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.23.3", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.3", + "@babel/plugin-transform-numeric-separator": "^7.23.3", + "@babel/plugin-transform-object-rest-spread": "^7.23.3", + "@babel/plugin-transform-object-super": "^7.23.3", + "@babel/plugin-transform-optional-catch-binding": "^7.23.3", + "@babel/plugin-transform-optional-chaining": "^7.23.3", + "@babel/plugin-transform-parameters": "^7.23.3", + "@babel/plugin-transform-private-methods": "^7.23.3", + "@babel/plugin-transform-private-property-in-object": "^7.23.3", + "@babel/plugin-transform-property-literals": "^7.23.3", + "@babel/plugin-transform-regenerator": "^7.23.3", + "@babel/plugin-transform-reserved-words": "^7.23.3", + "@babel/plugin-transform-shorthand-properties": "^7.23.3", + "@babel/plugin-transform-spread": "^7.23.3", + "@babel/plugin-transform-sticky-regex": "^7.23.3", + "@babel/plugin-transform-template-literals": "^7.23.3", + "@babel/plugin-transform-typeof-symbol": "^7.23.3", + "@babel/plugin-transform-unicode-escapes": "^7.23.3", + "@babel/plugin-transform-unicode-property-regex": "^7.23.3", + "@babel/plugin-transform-unicode-regex": "^7.23.3", + "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.6", + "babel-plugin-polyfill-corejs3": "^0.8.5", + "babel-plugin-polyfill-regenerator": "^0.5.3", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -1758,39 +1892,37 @@ } }, "node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", "@babel/types": "^7.4.4", "esutils": "^2.0.2" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, "node_modules/@babel/preset-react": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.16.7.tgz", - "integrity": "sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.22.5.tgz", + "integrity": "sha512-M+Is3WikOpEJHgR385HbuCITPTaPRaNkibTEa9oiofmJvIsrceb4yp9RL9Kb+TE8LznmeyZqpP+Lopwcx59xPQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-transform-react-display-name": "^7.16.7", - "@babel/plugin-transform-react-jsx": "^7.16.7", - "@babel/plugin-transform-react-jsx-development": "^7.16.7", - "@babel/plugin-transform-react-pure-annotations": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.5", + "@babel/plugin-transform-react-display-name": "^7.22.5", + "@babel/plugin-transform-react-jsx": "^7.22.5", + "@babel/plugin-transform-react-jsx-development": "^7.22.5", + "@babel/plugin-transform-react-pure-annotations": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1800,13 +1932,15 @@ } }, "node_modules/@babel/preset-typescript": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz", - "integrity": "sha512-WbVEmgXdIyvzB77AQjGBEyYPZx+8tTsO50XtfozQrkW8QB2rLJpH2lgx0TRw5EJrBxOZQ+wCcyPVQvS8tjEHpQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.22.5.tgz", + "integrity": "sha512-YbPaal9LxztSGhmndR46FmAbkJ/1fAsw293tSU+I5E5h+cnJ3d4GTwyUgGYmOXJYdGA+uNePle4qbaRzj2NISQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-transform-typescript": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.22.5", + "@babel/plugin-transform-modules-commonjs": "^7.22.5", + "@babel/plugin-transform-typescript": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1815,55 +1949,60 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" + }, "node_modules/@babel/runtime": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", - "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.4.tgz", + "integrity": "sha512-2Yv65nlWnWlSpe3fXEyX5i7fx5kIKo4Qbcj+hMO0odwaneFjfXw5fdum+4yL20O0QiaHpia0cYQ9xpNMqrBwHg==", "dependencies": { - "regenerator-runtime": "^0.13.4" + "regenerator-runtime": "^0.14.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/runtime-corejs3": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.17.2.tgz", - "integrity": "sha512-NcKtr2epxfIrNM4VOmPKO46TvDMCBhgi2CrSHaEarrz+Plk2K5r9QemmOFTGpZaoKnWoGH5MO+CzeRsih/Fcgg==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.23.4.tgz", + "integrity": "sha512-zQyB4MJGM+rvd4pM58n26kf3xbiitw9MHzL8oLiBMKb8MCtVDfV5nDzzJWWzLMtbvKI9wN6XwJYl479qF4JluQ==", "dependencies": { - "core-js-pure": "^3.20.2", - "regenerator-runtime": "^0.13.4" + "core-js-pure": "^3.30.2", + "regenerator-runtime": "^0.14.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", - "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", - "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.3", - "@babel/types": "^7.17.0", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.4.tgz", + "integrity": "sha512-IYM8wSUwunWTB6tFC2dkKZhxbIjHoWemdK+3f8/wq8aKhbUscxD5MX72ubd90fxvFknaLPeGw5ycU84V1obHJg==", + "dependencies": { + "@babel/code-frame": "^7.23.4", + "@babel/generator": "^7.23.4", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.4", + "@babel/types": "^7.23.4", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1872,201 +2011,280 @@ } }, "node_modules/@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.4.tgz", + "integrity": "sha512-7uIFwVYpoplT5jp/kVv6EF93VaJ8H+Yn5IczYiaAi98ajzjfoZfslet/e0sLh+wVBjb2qqIut1b0S26VSafsSQ==", "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@docsearch/css": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.0.0.tgz", - "integrity": "sha512-1kkV7tkAsiuEd0shunYRByKJe3xQDG2q7wYg24SOw1nV9/2lwEd4WrUYRJC/ukGTl2/kHeFxsaUvtiOy0y6fFA==" + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.5.2.tgz", + "integrity": "sha512-SPiDHaWKQZpwR2siD0KQUwlStvIAnEyK6tAE2h2Wuoq8ue9skzhlyVQ1ddzOxX6khULnAALDiR/isSF3bnuciA==" + }, + "node_modules/@docsearch/react": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.5.2.tgz", + "integrity": "sha512-9Ahcrs5z2jq/DcAvYtvlqEBHImbm4YJI8M9y0x6Tqg598P40HTEkX7hsMcIuThI+hTFxRGZ9hll0Wygm2yEjng==", + "dependencies": { + "@algolia/autocomplete-core": "1.9.3", + "@algolia/autocomplete-preset-algolia": "1.9.3", + "@docsearch/css": "3.5.2", + "algoliasearch": "^4.19.1" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 19.0.0", + "react": ">= 16.8.0 < 19.0.0", + "react-dom": ">= 16.8.0 < 19.0.0", + "search-insights": ">= 1 < 3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "search-insights": { + "optional": true + } + } }, "node_modules/@docusaurus/core": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-2.0.0-beta.15.tgz", - "integrity": "sha512-zXhhD0fApMSvq/9Pkm9DQxa//hGOXVCq9yMHiXOkI5D1tLec7PxtnaC5cLfGHljkN9cKIfRDYUVcG1gHymVfpA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.0.0.tgz", + "integrity": "sha512-bHWtY55tJTkd6pZhHrWz1MpWuwN4edZe0/UWgFF7PW/oJeDZvLSXKqwny3L91X1/LGGoypBGkeZn8EOuKeL4yQ==", "dependencies": { - "@babel/core": "^7.16.0", - "@babel/generator": "^7.16.0", + "@babel/core": "^7.22.9", + "@babel/generator": "^7.22.9", "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-transform-runtime": "^7.16.0", - "@babel/preset-env": "^7.16.4", - "@babel/preset-react": "^7.16.0", - "@babel/preset-typescript": "^7.16.0", - "@babel/runtime": "^7.16.3", - "@babel/runtime-corejs3": "^7.16.3", - "@babel/traverse": "^7.16.3", - "@docusaurus/cssnano-preset": "2.0.0-beta.15", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/mdx-loader": "2.0.0-beta.15", + "@babel/plugin-transform-runtime": "^7.22.9", + "@babel/preset-env": "^7.22.9", + "@babel/preset-react": "^7.22.5", + "@babel/preset-typescript": "^7.22.5", + "@babel/runtime": "^7.22.6", + "@babel/runtime-corejs3": "^7.22.6", + "@babel/traverse": "^7.22.8", + "@docusaurus/cssnano-preset": "3.0.0", + "@docusaurus/logger": "3.0.0", + "@docusaurus/mdx-loader": "3.0.0", "@docusaurus/react-loadable": "5.5.2", - "@docusaurus/utils": "2.0.0-beta.15", - "@docusaurus/utils-common": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", - "@slorber/static-site-generator-webpack-plugin": "^4.0.0", - "@svgr/webpack": "^6.0.0", - "autoprefixer": "^10.3.5", - "babel-loader": "^8.2.2", - "babel-plugin-dynamic-import-node": "2.3.0", - "boxen": "^5.0.1", - "chokidar": "^3.5.2", - "clean-css": "^5.1.5", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-common": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "@slorber/static-site-generator-webpack-plugin": "^4.0.7", + "@svgr/webpack": "^6.5.1", + "autoprefixer": "^10.4.14", + "babel-loader": "^9.1.3", + "babel-plugin-dynamic-import-node": "^2.3.3", + "boxen": "^6.2.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "clean-css": "^5.3.2", + "cli-table3": "^0.6.3", + "combine-promises": "^1.1.0", "commander": "^5.1.0", - "copy-webpack-plugin": "^10.2.0", - "core-js": "^3.18.0", - "css-loader": "^6.5.1", - "css-minimizer-webpack-plugin": "^3.3.1", - "cssnano": "^5.0.8", - "del": "^6.0.0", - "detect-port": "^1.3.0", + "copy-webpack-plugin": "^11.0.0", + "core-js": "^3.31.1", + "css-loader": "^6.8.1", + "css-minimizer-webpack-plugin": "^4.2.2", + "cssnano": "^5.1.15", + "del": "^6.1.1", + "detect-port": "^1.5.1", "escape-html": "^1.0.3", - "eta": "^1.12.3", + "eta": "^2.2.0", "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "html-minifier-terser": "^6.0.2", - "html-tags": "^3.1.0", - "html-webpack-plugin": "^5.4.0", - "import-fresh": "^3.3.0", - "is-root": "^2.1.0", + "fs-extra": "^11.1.1", + "html-minifier-terser": "^7.2.0", + "html-tags": "^3.3.1", + "html-webpack-plugin": "^5.5.3", "leven": "^3.1.0", - "lodash": "^4.17.20", - "mini-css-extract-plugin": "^1.6.0", - "nprogress": "^0.2.0", - "postcss": "^8.3.7", - "postcss-loader": "^6.1.1", - "prompts": "^2.4.1", - "react-dev-utils": "^12.0.0", - "react-helmet": "^6.1.0", + "lodash": "^4.17.21", + "mini-css-extract-plugin": "^2.7.6", + "postcss": "^8.4.26", + "postcss-loader": "^7.3.3", + "prompts": "^2.4.2", + "react-dev-utils": "^12.0.1", + "react-helmet-async": "^1.3.0", "react-loadable": "npm:@docusaurus/react-loadable@5.5.2", "react-loadable-ssr-addon-v5-slorber": "^1.0.1", - "react-router": "^5.2.0", + "react-router": "^5.3.4", "react-router-config": "^5.1.1", - "react-router-dom": "^5.2.0", - "remark-admonitions": "^1.2.1", + "react-router-dom": "^5.3.4", "rtl-detect": "^1.0.4", - "semver": "^7.3.4", - "serve-handler": "^6.1.3", - "shelljs": "^0.8.4", - "strip-ansi": "^6.0.0", - "terser-webpack-plugin": "^5.2.4", - "tslib": "^2.3.1", - "update-notifier": "^5.1.0", + "semver": "^7.5.4", + "serve-handler": "^6.1.5", + "shelljs": "^0.8.5", + "terser-webpack-plugin": "^5.3.9", + "tslib": "^2.6.0", + "update-notifier": "^6.0.2", "url-loader": "^4.1.1", - "wait-on": "^6.0.0", - "webpack": "^5.61.0", - "webpack-bundle-analyzer": "^4.4.2", - "webpack-dev-server": "^4.7.1", - "webpack-merge": "^5.8.0", + "wait-on": "^7.0.1", + "webpack": "^5.88.1", + "webpack-bundle-analyzer": "^4.9.0", + "webpack-dev-server": "^4.15.1", + "webpack-merge": "^5.9.0", "webpackbar": "^5.0.2" }, "bin": { - "docusaurus": "bin/docusaurus.js" + "docusaurus": "bin/docusaurus.mjs" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, "node_modules/@docusaurus/core/node_modules/@docusaurus/mdx-loader": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.15.tgz", - "integrity": "sha512-MVpytjDDao7hmPF1QSs9B5zoTgevZjiqjnX3FM1yjqdCv+chyUo0gnmYHjeG/4Gqu7jucp+dDdp6yQpzs4g09A==", - "dependencies": { - "@babel/parser": "^7.16.4", - "@babel/traverse": "^7.16.3", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@mdx-js/mdx": "^1.6.21", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.0.0.tgz", + "integrity": "sha512-JkGge6WYDrwjNgMxwkb6kNQHnpISt5L1tMaBWFDBKeDToFr5Kj29IL35MIQm0RfrnoOfr/29RjSH4aRtvlAR0A==", + "dependencies": { + "@babel/parser": "^7.22.7", + "@babel/traverse": "^7.22.8", + "@docusaurus/logger": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "@mdx-js/mdx": "^3.0.0", + "@slorber/remark-comment": "^1.0.0", "escape-html": "^1.0.3", + "estree-util-value-to-estree": "^3.0.1", "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "image-size": "^1.0.1", - "mdast-util-to-string": "^2.0.0", - "remark-emoji": "^2.1.0", + "fs-extra": "^11.1.1", + "image-size": "^1.0.2", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-string": "^4.0.0", + "rehype-raw": "^7.0.0", + "remark-directive": "^3.0.0", + "remark-emoji": "^4.0.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0", "stringify-object": "^3.3.0", - "tslib": "^2.3.1", - "unist-util-visit": "^2.0.2", + "tslib": "^2.6.0", + "unified": "^11.0.3", + "unist-util-visit": "^5.0.0", "url-loader": "^4.1.1", - "webpack": "^5.61.0" + "vfile": "^6.0.1", + "webpack": "^5.88.1" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" - } - }, - "node_modules/@docusaurus/core/node_modules/@docusaurus/react-loadable": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", - "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", - "dependencies": { - "@types/react": "*", - "prop-types": "^15.6.2" + "node": ">=18.0" }, "peerDependencies": { - "react": "*" + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, "node_modules/@docusaurus/core/node_modules/@docusaurus/utils": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.0.0-beta.15.tgz", - "integrity": "sha512-xkoPmFxCBkDqbZR4U3SE752OcXtWTGgZnc/pZWxItzb1IYRGNZHrzdIr7CnI7rppriuZzsyivDGiC4Ud9MWhkA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.0.0.tgz", + "integrity": "sha512-JwGjh5mtjG9XIAESyPxObL6CZ6LO/yU4OSTpq7Q0x+jN25zi/AMbvLjpSyZzWy+qm5uQiFiIhqFaOxvy+82Ekg==", "dependencies": { - "@docusaurus/logger": "2.0.0-beta.15", - "@mdx-js/runtime": "^1.6.22", - "@svgr/webpack": "^6.0.0", + "@docusaurus/logger": "3.0.0", + "@svgr/webpack": "^6.5.1", + "escape-string-regexp": "^4.0.0", "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "github-slugger": "^1.4.0", - "globby": "^11.0.4", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", "gray-matter": "^4.0.3", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "micromatch": "^4.0.4", - "remark-mdx-remove-exports": "^1.6.22", - "remark-mdx-remove-imports": "^1.6.22", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", "resolve-pathname": "^3.0.0", - "tslib": "^2.3.1", - "url-loader": "^4.1.1" + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.88.1" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "@babel/core": "^7.0.0", - "react": "*", - "react-dom": "*", - "webpack": "5.x" + "@docusaurus/types": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/types": { + "optional": true + } } }, - "node_modules/@docusaurus/core/node_modules/@docusaurus/utils-validation": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.15.tgz", - "integrity": "sha512-1oOVBCkRrsTXSYrBTsMdnj3a/R56zrx11rjF4xo0+dmm8C01Xw4msFtc3uA7VLX0HQvgHsk8xPzU5GERNdsNpg==", + "node_modules/@docusaurus/core/node_modules/@docusaurus/utils-common": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.0.0.tgz", + "integrity": "sha512-7iJWAtt4AHf4PFEPlEPXko9LZD/dbYnhLe0q8e3GRK1EXZyRASah2lznpMwB3lLmVjq/FR6ZAKF+E0wlmL5j0g==", "dependencies": { - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "joi": "^17.4.2", - "tslib": "^2.3.1" + "tslib": "^2.6.0" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "react": "*", - "react-dom": "*" + "@docusaurus/types": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/types": { + "optional": true + } + } + }, + "node_modules/@docusaurus/core/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/@docusaurus/core/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@docusaurus/core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/@docusaurus/core/node_modules/argparse": { @@ -2074,93 +2292,111 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, - "node_modules/@docusaurus/core/node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "engines": { - "node": ">=8" + "node_modules/@docusaurus/core/node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/@docusaurus/core/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "node_modules/@docusaurus/core/node_modules/boxen": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-6.2.1.tgz", + "integrity": "sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==", "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" + "ansi-align": "^3.0.1", + "camelcase": "^6.2.0", + "chalk": "^4.1.2", + "cli-boxes": "^3.0.0", + "string-width": "^5.0.1", + "type-fest": "^2.5.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.0.1" }, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@docusaurus/core/node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "node_modules/@docusaurus/core/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": ">= 4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@docusaurus/core/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "node_modules/@docusaurus/core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "argparse": "^2.0.1" + "color-name": "~1.1.4" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">=7.0.0" } }, - "node_modules/@docusaurus/core/node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dependencies": { - "isarray": "0.0.1" - } + "node_modules/@docusaurus/core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/@docusaurus/core/node_modules/react-helmet": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-6.1.0.tgz", - "integrity": "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==", - "dependencies": { - "object-assign": "^4.1.1", - "prop-types": "^15.7.2", - "react-fast-compare": "^3.1.1", - "react-side-effect": "^2.1.0" + "node_modules/@docusaurus/core/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/@docusaurus/core/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" }, - "peerDependencies": { - "react": ">=16.3.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@docusaurus/core/node_modules/react-helmet/node_modules/react-side-effect": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.1.tgz", - "integrity": "sha512-2FoTQzRNTncBVtnzxFOk2mCpcfxQpenBMbk5kSVBg5UcPqV9fRbgY2zhb7GTWWOlpFmAxhClBDlIq8Rsubz1yQ==", - "peerDependencies": { - "react": "^16.3.0 || ^17.0.0" + "node_modules/@docusaurus/core/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" } }, - "node_modules/@docusaurus/core/node_modules/react-loadable": { - "name": "@docusaurus/react-loadable", - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", - "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", + "node_modules/@docusaurus/core/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@docusaurus/core/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dependencies": { - "@types/react": "*", - "prop-types": "^15.6.2" + "argparse": "^2.0.1" }, - "peerDependencies": { - "react": "*" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, "node_modules/@docusaurus/core/node_modules/react-loadable-ssr-addon-v5-slorber": { @@ -2178,26 +2414,6 @@ "webpack": ">=4.41.1 || 5.x" } }, - "node_modules/@docusaurus/core/node_modules/react-router": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.1.tgz", - "integrity": "sha512-lIboRiOtDLFdg1VTemMwud9vRVuOCZmUIT/7lUoZiSpPODiiH1UQlfXy+vPLC/7IWdFYnhRwAyNqA/+I7wnvKQ==", - "dependencies": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "hoist-non-react-statics": "^3.1.0", - "loose-envify": "^1.3.1", - "mini-create-react-context": "^0.4.0", - "path-to-regexp": "^1.7.0", - "prop-types": "^15.6.2", - "react-is": "^16.6.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - }, - "peerDependencies": { - "react": ">=15" - } - }, "node_modules/@docusaurus/core/node_modules/react-router-config": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/react-router-config/-/react-router-config-5.1.1.tgz", @@ -2210,56 +2426,187 @@ "react-router": ">=5" } }, - "node_modules/@docusaurus/core/node_modules/react-router-dom": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.0.tgz", - "integrity": "sha512-ObVBLjUZsphUUMVycibxgMdh5jJ1e3o+KpAZBVeHcNQZ4W+uUGGWsokurzlF4YOldQYRQL4y6yFRWM4m3svmuQ==", + "node_modules/@docusaurus/core/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dependencies": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "loose-envify": "^1.3.1", - "prop-types": "^15.6.2", - "react-router": "5.2.1", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, - "peerDependencies": { - "react": ">=15" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@docusaurus/core/node_modules/react-router/node_modules/mini-create-react-context": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", - "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", + "node_modules/@docusaurus/core/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dependencies": { - "@babel/runtime": "^7.12.1", - "tiny-warning": "^1.0.3" + "ansi-regex": "^6.0.1" }, - "peerDependencies": { - "prop-types": "^15.0.0", - "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@docusaurus/core/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@docusaurus/core/node_modules/trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@docusaurus/core/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@docusaurus/core/node_modules/unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@docusaurus/core/node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@docusaurus/core/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@docusaurus/core/node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@docusaurus/core/node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@docusaurus/core/node_modules/vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@docusaurus/core/node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, "node_modules/@docusaurus/cssnano-preset": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-2.0.0-beta.15.tgz", - "integrity": "sha512-55aYURbB5dqrx64lStNcZxDx5R6bKkAawlCB7mDKx3r+Qnp3ofGW7UExLQSCbTu3axT1vJCF5D7H6ljTRYJLtA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.0.0.tgz", + "integrity": "sha512-FHiRfwmVvIVdIGsHcijUOaX7hMn0mugVYB7m4GkpYI6Mi56zwQV4lH5p7DxcW5CUYNWMVxz2loWSCiWEm5ikwA==", "dependencies": { - "cssnano-preset-advanced": "^5.1.4", - "postcss": "^8.3.7", - "postcss-sort-media-queries": "^4.1.0" + "cssnano-preset-advanced": "^5.3.10", + "postcss": "^8.4.26", + "postcss-sort-media-queries": "^4.4.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" } }, "node_modules/@docusaurus/logger": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-2.0.0-beta.15.tgz", - "integrity": "sha512-5bDSHCyLfMtz6QnFfICdL5mgxbGfC7DW1V+/Q17nRdpZSPZgsNKK/Esp0zdDi1oxAyEpXMXx64nLaHL7joJxIg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.0.0.tgz", + "integrity": "sha512-6eX0eOfioMQCk+qgCnHvbLLuyIAA+r2lSID6d6JusiLtDKmYMfNp3F4yyE8bnb0Abmzt2w68XwptEFYyALSAXw==", "dependencies": { "chalk": "^4.1.2", - "tslib": "^2.3.1" + "tslib": "^2.6.0" }, "engines": { - "node": ">=14" + "node": ">=18.0" } }, "node_modules/@docusaurus/logger/node_modules/ansi-styles": { @@ -2326,1435 +2673,1156 @@ "node": ">=8" } }, - "node_modules/@docusaurus/preset-classic": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-2.0.0-beta.15.tgz", - "integrity": "sha512-3NZIXWTAzk+kOgiB8uAbD+FZv3VFR1qkU6+TW24DRenjRnXof3CkRuldhI1QI0hILm1fuJ319QRkakV8FFtXyA==", - "dependencies": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/plugin-content-blog": "2.0.0-beta.15", - "@docusaurus/plugin-content-docs": "2.0.0-beta.15", - "@docusaurus/plugin-content-pages": "2.0.0-beta.15", - "@docusaurus/plugin-debug": "2.0.0-beta.15", - "@docusaurus/plugin-google-analytics": "2.0.0-beta.15", - "@docusaurus/plugin-google-gtag": "2.0.0-beta.15", - "@docusaurus/plugin-sitemap": "2.0.0-beta.15", - "@docusaurus/theme-classic": "2.0.0-beta.15", - "@docusaurus/theme-common": "2.0.0-beta.15", - "@docusaurus/theme-search-algolia": "2.0.0-beta.15" - }, - "engines": { - "node": ">=14" + "node_modules/@docusaurus/module-type-aliases": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.0.0.tgz", + "integrity": "sha512-CfC6CgN4u/ce+2+L1JdsHNyBd8yYjl4De2B2CBj2a9F7WuJ5RjV1ciuU7KDg8uyju+NRVllRgvJvxVUjCdkPiw==", + "dependencies": { + "@docusaurus/react-loadable": "5.5.2", + "@docusaurus/types": "3.0.0", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "@types/react-router-dom": "*", + "react-helmet-async": "*", + "react-loadable": "npm:@docusaurus/react-loadable@5.5.2" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/@docusaurus/preset-classic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.0.0.tgz", + "integrity": "sha512-90aOKZGZdi0+GVQV+wt8xx4M4GiDrBRke8NO8nWwytMEXNrxrBxsQYFRD1YlISLJSCiHikKf3Z/MovMnQpnZyg==", + "dependencies": { + "@docusaurus/core": "3.0.0", + "@docusaurus/plugin-content-blog": "3.0.0", + "@docusaurus/plugin-content-docs": "3.0.0", + "@docusaurus/plugin-content-pages": "3.0.0", + "@docusaurus/plugin-debug": "3.0.0", + "@docusaurus/plugin-google-analytics": "3.0.0", + "@docusaurus/plugin-google-gtag": "3.0.0", + "@docusaurus/plugin-google-tag-manager": "3.0.0", + "@docusaurus/plugin-sitemap": "3.0.0", + "@docusaurus/theme-classic": "3.0.0", + "@docusaurus/theme-common": "3.0.0", + "@docusaurus/theme-search-algolia": "3.0.0", + "@docusaurus/types": "3.0.0" + }, + "engines": { + "node": ">=18.0" }, "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-content-blog": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.0.0-beta.15.tgz", - "integrity": "sha512-VtEwkgkoNIS8JFPe+huBeBuJ8HG8Lq1JNYM/ItwQg/cwGAgP8EgwbEuKDn428oZKEI2PpgAuf5Gv4AzJWIes9A==", - "dependencies": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/mdx-loader": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@docusaurus/utils-common": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", - "cheerio": "^1.0.0-rc.10", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.0.0.tgz", + "integrity": "sha512-iA8Wc3tIzVnROJxrbIsU/iSfixHW16YeW9RWsBw7hgEk4dyGsip9AsvEDXobnRq3lVv4mfdgoS545iGWf1Ip9w==", + "dependencies": { + "@docusaurus/core": "3.0.0", + "@docusaurus/logger": "3.0.0", + "@docusaurus/mdx-loader": "3.0.0", + "@docusaurus/types": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-common": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "cheerio": "^1.0.0-rc.12", "feed": "^4.2.2", - "fs-extra": "^10.0.0", - "lodash": "^4.17.20", + "fs-extra": "^11.1.1", + "lodash": "^4.17.21", "reading-time": "^1.5.0", - "remark-admonitions": "^1.2.1", - "tslib": "^2.3.1", + "srcset": "^4.0.0", + "tslib": "^2.6.0", + "unist-util-visit": "^5.0.0", "utility-types": "^3.10.0", - "webpack": "^5.61.0" + "webpack": "^5.88.1" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-content-blog/node_modules/@docusaurus/mdx-loader": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.15.tgz", - "integrity": "sha512-MVpytjDDao7hmPF1QSs9B5zoTgevZjiqjnX3FM1yjqdCv+chyUo0gnmYHjeG/4Gqu7jucp+dDdp6yQpzs4g09A==", - "dependencies": { - "@babel/parser": "^7.16.4", - "@babel/traverse": "^7.16.3", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@mdx-js/mdx": "^1.6.21", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.0.0.tgz", + "integrity": "sha512-JkGge6WYDrwjNgMxwkb6kNQHnpISt5L1tMaBWFDBKeDToFr5Kj29IL35MIQm0RfrnoOfr/29RjSH4aRtvlAR0A==", + "dependencies": { + "@babel/parser": "^7.22.7", + "@babel/traverse": "^7.22.8", + "@docusaurus/logger": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "@mdx-js/mdx": "^3.0.0", + "@slorber/remark-comment": "^1.0.0", "escape-html": "^1.0.3", + "estree-util-value-to-estree": "^3.0.1", "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "image-size": "^1.0.1", - "mdast-util-to-string": "^2.0.0", - "remark-emoji": "^2.1.0", + "fs-extra": "^11.1.1", + "image-size": "^1.0.2", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-string": "^4.0.0", + "rehype-raw": "^7.0.0", + "remark-directive": "^3.0.0", + "remark-emoji": "^4.0.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0", "stringify-object": "^3.3.0", - "tslib": "^2.3.1", - "unist-util-visit": "^2.0.2", + "tslib": "^2.6.0", + "unified": "^11.0.3", + "unist-util-visit": "^5.0.0", "url-loader": "^4.1.1", - "webpack": "^5.61.0" + "vfile": "^6.0.1", + "webpack": "^5.88.1" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-content-blog/node_modules/@docusaurus/utils": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.0.0-beta.15.tgz", - "integrity": "sha512-xkoPmFxCBkDqbZR4U3SE752OcXtWTGgZnc/pZWxItzb1IYRGNZHrzdIr7CnI7rppriuZzsyivDGiC4Ud9MWhkA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.0.0.tgz", + "integrity": "sha512-JwGjh5mtjG9XIAESyPxObL6CZ6LO/yU4OSTpq7Q0x+jN25zi/AMbvLjpSyZzWy+qm5uQiFiIhqFaOxvy+82Ekg==", "dependencies": { - "@docusaurus/logger": "2.0.0-beta.15", - "@mdx-js/runtime": "^1.6.22", - "@svgr/webpack": "^6.0.0", + "@docusaurus/logger": "3.0.0", + "@svgr/webpack": "^6.5.1", + "escape-string-regexp": "^4.0.0", "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "github-slugger": "^1.4.0", - "globby": "^11.0.4", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", "gray-matter": "^4.0.3", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "micromatch": "^4.0.4", - "remark-mdx-remove-exports": "^1.6.22", - "remark-mdx-remove-imports": "^1.6.22", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", "resolve-pathname": "^3.0.0", - "tslib": "^2.3.1", - "url-loader": "^4.1.1" + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.88.1" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "@babel/core": "^7.0.0", - "react": "*", - "react-dom": "*", - "webpack": "5.x" + "@docusaurus/types": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/types": { + "optional": true + } } }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-content-blog/node_modules/@docusaurus/utils-validation": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.15.tgz", - "integrity": "sha512-1oOVBCkRrsTXSYrBTsMdnj3a/R56zrx11rjF4xo0+dmm8C01Xw4msFtc3uA7VLX0HQvgHsk8xPzU5GERNdsNpg==", + "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-content-blog/node_modules/@docusaurus/utils-common": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.0.0.tgz", + "integrity": "sha512-7iJWAtt4AHf4PFEPlEPXko9LZD/dbYnhLe0q8e3GRK1EXZyRASah2lznpMwB3lLmVjq/FR6ZAKF+E0wlmL5j0g==", "dependencies": { - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "joi": "^17.4.2", - "tslib": "^2.3.1" + "tslib": "^2.6.0" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "react": "*", - "react-dom": "*" + "@docusaurus/types": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/types": { + "optional": true + } } }, "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-content-docs": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.0.0-beta.15.tgz", - "integrity": "sha512-HSwNZdUKz4rpJiGbFjl/OFhSleeZUSZ6E6lk98i4iL1A5u6fIm4CHsT53yp4UUOse+lFrePTFZsyqwMA4nZZYA==", - "dependencies": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/mdx-loader": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.0.0.tgz", + "integrity": "sha512-MFZsOSwmeJ6rvoZMLieXxPuJsA9M9vn7/mUZmfUzSUTeHAeq+fEqvLltFOxcj4DVVDTYlQhgWYd+PISIWgamKw==", + "dependencies": { + "@docusaurus/core": "3.0.0", + "@docusaurus/logger": "3.0.0", + "@docusaurus/mdx-loader": "3.0.0", + "@docusaurus/module-type-aliases": "3.0.0", + "@docusaurus/types": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "@types/react-router-config": "^5.0.7", "combine-promises": "^1.1.0", - "fs-extra": "^10.0.0", - "import-fresh": "^3.2.2", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "remark-admonitions": "^1.2.1", - "shelljs": "^0.8.4", - "tslib": "^2.3.1", + "fs-extra": "^11.1.1", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "tslib": "^2.6.0", "utility-types": "^3.10.0", - "webpack": "^5.61.0" + "webpack": "^5.88.1" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-content-docs/node_modules/@docusaurus/mdx-loader": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.15.tgz", - "integrity": "sha512-MVpytjDDao7hmPF1QSs9B5zoTgevZjiqjnX3FM1yjqdCv+chyUo0gnmYHjeG/4Gqu7jucp+dDdp6yQpzs4g09A==", - "dependencies": { - "@babel/parser": "^7.16.4", - "@babel/traverse": "^7.16.3", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@mdx-js/mdx": "^1.6.21", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.0.0.tgz", + "integrity": "sha512-JkGge6WYDrwjNgMxwkb6kNQHnpISt5L1tMaBWFDBKeDToFr5Kj29IL35MIQm0RfrnoOfr/29RjSH4aRtvlAR0A==", + "dependencies": { + "@babel/parser": "^7.22.7", + "@babel/traverse": "^7.22.8", + "@docusaurus/logger": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "@mdx-js/mdx": "^3.0.0", + "@slorber/remark-comment": "^1.0.0", "escape-html": "^1.0.3", + "estree-util-value-to-estree": "^3.0.1", "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "image-size": "^1.0.1", - "mdast-util-to-string": "^2.0.0", - "remark-emoji": "^2.1.0", + "fs-extra": "^11.1.1", + "image-size": "^1.0.2", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-string": "^4.0.0", + "rehype-raw": "^7.0.0", + "remark-directive": "^3.0.0", + "remark-emoji": "^4.0.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0", "stringify-object": "^3.3.0", - "tslib": "^2.3.1", - "unist-util-visit": "^2.0.2", + "tslib": "^2.6.0", + "unified": "^11.0.3", + "unist-util-visit": "^5.0.0", "url-loader": "^4.1.1", - "webpack": "^5.61.0" + "vfile": "^6.0.1", + "webpack": "^5.88.1" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-content-docs/node_modules/@docusaurus/utils": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.0.0-beta.15.tgz", - "integrity": "sha512-xkoPmFxCBkDqbZR4U3SE752OcXtWTGgZnc/pZWxItzb1IYRGNZHrzdIr7CnI7rppriuZzsyivDGiC4Ud9MWhkA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.0.0.tgz", + "integrity": "sha512-JwGjh5mtjG9XIAESyPxObL6CZ6LO/yU4OSTpq7Q0x+jN25zi/AMbvLjpSyZzWy+qm5uQiFiIhqFaOxvy+82Ekg==", "dependencies": { - "@docusaurus/logger": "2.0.0-beta.15", - "@mdx-js/runtime": "^1.6.22", - "@svgr/webpack": "^6.0.0", + "@docusaurus/logger": "3.0.0", + "@svgr/webpack": "^6.5.1", + "escape-string-regexp": "^4.0.0", "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "github-slugger": "^1.4.0", - "globby": "^11.0.4", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", "gray-matter": "^4.0.3", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "micromatch": "^4.0.4", - "remark-mdx-remove-exports": "^1.6.22", - "remark-mdx-remove-imports": "^1.6.22", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", "resolve-pathname": "^3.0.0", - "tslib": "^2.3.1", - "url-loader": "^4.1.1" + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.88.1" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "@babel/core": "^7.0.0", - "react": "*", - "react-dom": "*", - "webpack": "5.x" - } - }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-content-docs/node_modules/@docusaurus/utils-validation": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.15.tgz", - "integrity": "sha512-1oOVBCkRrsTXSYrBTsMdnj3a/R56zrx11rjF4xo0+dmm8C01Xw4msFtc3uA7VLX0HQvgHsk8xPzU5GERNdsNpg==", - "dependencies": { - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "joi": "^17.4.2", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14" + "@docusaurus/types": "*" }, - "peerDependencies": { - "react": "*", - "react-dom": "*" + "peerDependenciesMeta": { + "@docusaurus/types": { + "optional": true + } } }, "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-content-pages": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.0.0-beta.15.tgz", - "integrity": "sha512-N7YhW5RiOY6J228z4lOoP//qX0Q48cRtxDONZ/Ohd9C5OI2vS6TD8iQuDqOIYHxH+BshjNSsKvbJ+SMIQDwysg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.0.0.tgz", + "integrity": "sha512-EXYHXK2Ea1B5BUmM0DgSwaOYt8EMSzWtYUToNo62Q/EoWxYOQFdWglYnw3n7ZEGyw5Kog4LHaRwlazAdmDomvQ==", "dependencies": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/mdx-loader": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", - "fs-extra": "^10.0.0", - "globby": "^11.0.2", - "remark-admonitions": "^1.2.1", - "tslib": "^2.3.1", - "webpack": "^5.61.0" + "@docusaurus/core": "3.0.0", + "@docusaurus/mdx-loader": "3.0.0", + "@docusaurus/types": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "fs-extra": "^11.1.1", + "tslib": "^2.6.0", + "webpack": "^5.88.1" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-content-pages/node_modules/@docusaurus/mdx-loader": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.15.tgz", - "integrity": "sha512-MVpytjDDao7hmPF1QSs9B5zoTgevZjiqjnX3FM1yjqdCv+chyUo0gnmYHjeG/4Gqu7jucp+dDdp6yQpzs4g09A==", - "dependencies": { - "@babel/parser": "^7.16.4", - "@babel/traverse": "^7.16.3", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@mdx-js/mdx": "^1.6.21", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.0.0.tgz", + "integrity": "sha512-JkGge6WYDrwjNgMxwkb6kNQHnpISt5L1tMaBWFDBKeDToFr5Kj29IL35MIQm0RfrnoOfr/29RjSH4aRtvlAR0A==", + "dependencies": { + "@babel/parser": "^7.22.7", + "@babel/traverse": "^7.22.8", + "@docusaurus/logger": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "@mdx-js/mdx": "^3.0.0", + "@slorber/remark-comment": "^1.0.0", "escape-html": "^1.0.3", + "estree-util-value-to-estree": "^3.0.1", "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "image-size": "^1.0.1", - "mdast-util-to-string": "^2.0.0", - "remark-emoji": "^2.1.0", + "fs-extra": "^11.1.1", + "image-size": "^1.0.2", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-string": "^4.0.0", + "rehype-raw": "^7.0.0", + "remark-directive": "^3.0.0", + "remark-emoji": "^4.0.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0", "stringify-object": "^3.3.0", - "tslib": "^2.3.1", - "unist-util-visit": "^2.0.2", + "tslib": "^2.6.0", + "unified": "^11.0.3", + "unist-util-visit": "^5.0.0", "url-loader": "^4.1.1", - "webpack": "^5.61.0" + "vfile": "^6.0.1", + "webpack": "^5.88.1" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-content-pages/node_modules/@docusaurus/utils": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.0.0-beta.15.tgz", - "integrity": "sha512-xkoPmFxCBkDqbZR4U3SE752OcXtWTGgZnc/pZWxItzb1IYRGNZHrzdIr7CnI7rppriuZzsyivDGiC4Ud9MWhkA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.0.0.tgz", + "integrity": "sha512-JwGjh5mtjG9XIAESyPxObL6CZ6LO/yU4OSTpq7Q0x+jN25zi/AMbvLjpSyZzWy+qm5uQiFiIhqFaOxvy+82Ekg==", "dependencies": { - "@docusaurus/logger": "2.0.0-beta.15", - "@mdx-js/runtime": "^1.6.22", - "@svgr/webpack": "^6.0.0", + "@docusaurus/logger": "3.0.0", + "@svgr/webpack": "^6.5.1", + "escape-string-regexp": "^4.0.0", "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "github-slugger": "^1.4.0", - "globby": "^11.0.4", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", "gray-matter": "^4.0.3", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "micromatch": "^4.0.4", - "remark-mdx-remove-exports": "^1.6.22", - "remark-mdx-remove-imports": "^1.6.22", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", "resolve-pathname": "^3.0.0", - "tslib": "^2.3.1", - "url-loader": "^4.1.1" + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.88.1" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "@babel/core": "^7.0.0", - "react": "*", - "react-dom": "*", - "webpack": "5.x" - } - }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-content-pages/node_modules/@docusaurus/utils-validation": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.15.tgz", - "integrity": "sha512-1oOVBCkRrsTXSYrBTsMdnj3a/R56zrx11rjF4xo0+dmm8C01Xw4msFtc3uA7VLX0HQvgHsk8xPzU5GERNdsNpg==", - "dependencies": { - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "joi": "^17.4.2", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14" + "@docusaurus/types": "*" }, - "peerDependencies": { - "react": "*", - "react-dom": "*" + "peerDependenciesMeta": { + "@docusaurus/types": { + "optional": true + } } }, "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-debug": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-2.0.0-beta.15.tgz", - "integrity": "sha512-Jth11jB/rVqPwCGdkVKSUWeXZPAr/NyPn+yeknTBk2LgQKBJ3YU5dNG0uyt0Ay+UYT01TkousPJkXhLuy4Qrsw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.0.0.tgz", + "integrity": "sha512-gSV07HfQgnUboVEb3lucuVyv5pEoy33E7QXzzn++3kSc/NLEimkjXh3sSnTGOishkxCqlFV9BHfY/VMm5Lko5g==", "dependencies": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "fs-extra": "^10.0.0", - "react-json-view": "^1.21.3", - "tslib": "^2.3.1" + "@docusaurus/core": "3.0.0", + "@docusaurus/types": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@microlink/react-json-view": "^1.22.2", + "fs-extra": "^11.1.1", + "tslib": "^2.6.0" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-debug/node_modules/@docusaurus/utils": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.0.0-beta.15.tgz", - "integrity": "sha512-xkoPmFxCBkDqbZR4U3SE752OcXtWTGgZnc/pZWxItzb1IYRGNZHrzdIr7CnI7rppriuZzsyivDGiC4Ud9MWhkA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.0.0.tgz", + "integrity": "sha512-JwGjh5mtjG9XIAESyPxObL6CZ6LO/yU4OSTpq7Q0x+jN25zi/AMbvLjpSyZzWy+qm5uQiFiIhqFaOxvy+82Ekg==", "dependencies": { - "@docusaurus/logger": "2.0.0-beta.15", - "@mdx-js/runtime": "^1.6.22", - "@svgr/webpack": "^6.0.0", + "@docusaurus/logger": "3.0.0", + "@svgr/webpack": "^6.5.1", + "escape-string-regexp": "^4.0.0", "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "github-slugger": "^1.4.0", - "globby": "^11.0.4", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", "gray-matter": "^4.0.3", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "micromatch": "^4.0.4", - "remark-mdx-remove-exports": "^1.6.22", - "remark-mdx-remove-imports": "^1.6.22", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", "resolve-pathname": "^3.0.0", - "tslib": "^2.3.1", - "url-loader": "^4.1.1" + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.88.1" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "@babel/core": "^7.0.0", - "react": "*", - "react-dom": "*", - "webpack": "5.x" + "@docusaurus/types": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/types": { + "optional": true + } } }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-debug/node_modules/react-json-view": { - "version": "1.21.3", - "resolved": "https://registry.npmjs.org/react-json-view/-/react-json-view-1.21.3.tgz", - "integrity": "sha512-13p8IREj9/x/Ye4WI/JpjhoIwuzEgUAtgJZNBJckfzJt1qyh24BdTm6UQNGnyTq9dapQdrqvquZTo3dz1X6Cjw==", + "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-google-analytics": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.0.0.tgz", + "integrity": "sha512-0zcLK8w+ohmSm1fjUQCqeRsjmQc0gflvXnaVA/QVVCtm2yCiBtkrSGQXqt4MdpD7Xq8mwo3qVd5nhIcvrcebqw==", "dependencies": { - "flux": "^4.0.1", - "react-base16-styling": "^0.6.0", - "react-lifecycles-compat": "^3.0.4", - "react-textarea-autosize": "^8.3.2" + "@docusaurus/core": "3.0.0", + "@docusaurus/types": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" }, "peerDependencies": { - "react": "^17.0.0 || ^16.3.0 || ^15.5.4", - "react-dom": "^17.0.0 || ^16.3.0 || ^15.5.4" + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-debug/node_modules/react-json-view/node_modules/flux": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.3.tgz", - "integrity": "sha512-yKAbrp7JhZhj6uiT1FTuVMlIAT1J4jqEyBpFApi1kxpGZCvacMVc/t1pMQyotqHhAgvoE3bNvAykhCo2CLjnYw==", + "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-google-gtag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.0.0.tgz", + "integrity": "sha512-asEKavw8fczUqvXu/s9kG2m1epLnHJ19W6CCCRZEmpnkZUZKiM8rlkDiEmxApwIc2JDDbIMk+Y2TMkJI8mInbQ==", "dependencies": { - "fbemitter": "^3.0.0", - "fbjs": "^3.0.1" + "@docusaurus/core": "3.0.0", + "@docusaurus/types": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "@types/gtag.js": "^0.0.12", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" }, "peerDependencies": { - "react": "^15.0.2 || ^16.0.0 || ^17.0.0" + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-debug/node_modules/react-json-view/node_modules/react-textarea-autosize": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.3.3.tgz", - "integrity": "sha512-2XlHXK2TDxS6vbQaoPbMOfQ8GK7+irc2fVK6QFIcC8GOnH3zI/v481n+j1L0WaPVvKxwesnY93fEfH++sus2rQ==", + "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-google-tag-manager": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.0.0.tgz", + "integrity": "sha512-lytgu2eyn+7p4WklJkpMGRhwC29ezj4IjPPmVJ8vGzcSl6JkR1sADTHLG5xWOMuci420xZl9dGEiLTQ8FjCRyA==", "dependencies": { - "@babel/runtime": "^7.10.2", - "use-composed-ref": "^1.0.0", - "use-latest": "^1.0.0" + "@docusaurus/core": "3.0.0", + "@docusaurus/types": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "tslib": "^2.6.0" }, "engines": { - "node": ">=10" + "node": ">=18.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0" + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-debug/node_modules/react-json-view/node_modules/react-textarea-autosize/node_modules/use-composed-ref": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.2.1.tgz", - "integrity": "sha512-6+X1FLlIcjvFMAeAD/hcxDT8tmyrWnbSPMU0EnxQuDLIxokuFzWliXBiYZuGIx+mrAMLBw0WFfCkaPw8ebzAhw==", + "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-sitemap": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.0.0.tgz", + "integrity": "sha512-cfcONdWku56Oi7Hdus2uvUw/RKRRlIGMViiHLjvQ21CEsEqnQ297MRoIgjU28kL7/CXD/+OiANSq3T1ezAiMhA==", + "dependencies": { + "@docusaurus/core": "3.0.0", + "@docusaurus/logger": "3.0.0", + "@docusaurus/types": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-common": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "fs-extra": "^11.1.1", + "sitemap": "^7.1.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0" + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-debug/node_modules/react-json-view/node_modules/react-textarea-autosize/node_modules/use-latest": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.0.tgz", - "integrity": "sha512-d2TEuG6nSLKQLAfW3By8mKr8HurOlTkul0sOpxbClIv4SQ4iOd7BYr7VIzdbktUCnv7dua/60xzd8igMU6jmyw==", + "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-sitemap/node_modules/@docusaurus/utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.0.0.tgz", + "integrity": "sha512-JwGjh5mtjG9XIAESyPxObL6CZ6LO/yU4OSTpq7Q0x+jN25zi/AMbvLjpSyZzWy+qm5uQiFiIhqFaOxvy+82Ekg==", "dependencies": { - "use-isomorphic-layout-effect": "^1.0.0" + "@docusaurus/logger": "3.0.0", + "@svgr/webpack": "^6.5.1", + "escape-string-regexp": "^4.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "resolve-pathname": "^3.0.0", + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=18.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0" + "@docusaurus/types": "*" }, "peerDependenciesMeta": { - "@types/react": { + "@docusaurus/types": { "optional": true } } }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-debug/node_modules/react-json-view/node_modules/react-textarea-autosize/node_modules/use-latest/node_modules/use-isomorphic-layout-effect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz", - "integrity": "sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ==", + "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-sitemap/node_modules/@docusaurus/utils-common": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.0.0.tgz", + "integrity": "sha512-7iJWAtt4AHf4PFEPlEPXko9LZD/dbYnhLe0q8e3GRK1EXZyRASah2lznpMwB3lLmVjq/FR6ZAKF+E0wlmL5j0g==", + "dependencies": { + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0" + "@docusaurus/types": "*" }, "peerDependenciesMeta": { - "@types/react": { + "@docusaurus/types": { "optional": true } } }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-google-analytics": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.0.0-beta.15.tgz", - "integrity": "sha512-ELAnxNYiC2i7gfu/ViurNIdm1/DdnbEfVDmpffS9niQhOREM1U3jpxkz/ff1GIC6heOLyHTtini/CZBDoroVGw==", - "dependencies": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", - "tslib": "^2.3.1" + "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/theme-classic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.0.0.tgz", + "integrity": "sha512-wWOHSrKMn7L4jTtXBsb5iEJ3xvTddBye5PjYBnWiCkTAlhle2yMdc4/qRXW35Ot+OV/VXu6YFG8XVUJEl99z0A==", + "dependencies": { + "@docusaurus/core": "3.0.0", + "@docusaurus/mdx-loader": "3.0.0", + "@docusaurus/module-type-aliases": "3.0.0", + "@docusaurus/plugin-content-blog": "3.0.0", + "@docusaurus/plugin-content-docs": "3.0.0", + "@docusaurus/plugin-content-pages": "3.0.0", + "@docusaurus/theme-common": "3.0.0", + "@docusaurus/theme-translations": "3.0.0", + "@docusaurus/types": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-common": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "@mdx-js/react": "^3.0.0", + "clsx": "^1.2.1", + "copy-text-to-clipboard": "^3.2.0", + "infima": "0.2.0-alpha.43", + "lodash": "^4.17.21", + "nprogress": "^0.2.0", + "postcss": "^8.4.26", + "prism-react-renderer": "^2.1.0", + "prismjs": "^1.29.0", + "react-router-dom": "^5.3.4", + "rtlcss": "^4.1.0", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-google-analytics/node_modules/@docusaurus/utils-validation": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.15.tgz", - "integrity": "sha512-1oOVBCkRrsTXSYrBTsMdnj3a/R56zrx11rjF4xo0+dmm8C01Xw4msFtc3uA7VLX0HQvgHsk8xPzU5GERNdsNpg==", - "dependencies": { - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "joi": "^17.4.2", - "tslib": "^2.3.1" + "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/theme-classic/node_modules/@docusaurus/mdx-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.0.0.tgz", + "integrity": "sha512-JkGge6WYDrwjNgMxwkb6kNQHnpISt5L1tMaBWFDBKeDToFr5Kj29IL35MIQm0RfrnoOfr/29RjSH4aRtvlAR0A==", + "dependencies": { + "@babel/parser": "^7.22.7", + "@babel/traverse": "^7.22.8", + "@docusaurus/logger": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "@mdx-js/mdx": "^3.0.0", + "@slorber/remark-comment": "^1.0.0", + "escape-html": "^1.0.3", + "estree-util-value-to-estree": "^3.0.1", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "image-size": "^1.0.2", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-string": "^4.0.0", + "rehype-raw": "^7.0.0", + "remark-directive": "^3.0.0", + "remark-emoji": "^4.0.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0", + "stringify-object": "^3.3.0", + "tslib": "^2.6.0", + "unified": "^11.0.3", + "unist-util-visit": "^5.0.0", + "url-loader": "^4.1.1", + "vfile": "^6.0.1", + "webpack": "^5.88.1" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "react": "*", - "react-dom": "*" + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-google-analytics/node_modules/@docusaurus/utils-validation/node_modules/@docusaurus/utils": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.0.0-beta.15.tgz", - "integrity": "sha512-xkoPmFxCBkDqbZR4U3SE752OcXtWTGgZnc/pZWxItzb1IYRGNZHrzdIr7CnI7rppriuZzsyivDGiC4Ud9MWhkA==", + "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/theme-classic/node_modules/@docusaurus/utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.0.0.tgz", + "integrity": "sha512-JwGjh5mtjG9XIAESyPxObL6CZ6LO/yU4OSTpq7Q0x+jN25zi/AMbvLjpSyZzWy+qm5uQiFiIhqFaOxvy+82Ekg==", "dependencies": { - "@docusaurus/logger": "2.0.0-beta.15", - "@mdx-js/runtime": "^1.6.22", - "@svgr/webpack": "^6.0.0", + "@docusaurus/logger": "3.0.0", + "@svgr/webpack": "^6.5.1", + "escape-string-regexp": "^4.0.0", "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "github-slugger": "^1.4.0", - "globby": "^11.0.4", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", "gray-matter": "^4.0.3", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "micromatch": "^4.0.4", - "remark-mdx-remove-exports": "^1.6.22", - "remark-mdx-remove-imports": "^1.6.22", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", "resolve-pathname": "^3.0.0", - "tslib": "^2.3.1", - "url-loader": "^4.1.1" + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.88.1" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "@babel/core": "^7.0.0", - "react": "*", - "react-dom": "*", - "webpack": "5.x" - } - }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-google-gtag": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.0.0-beta.15.tgz", - "integrity": "sha512-E5Rm3+dN7i3A9V5uq5sl9xTNA3aXsLwTZEA2SpOkY571dCpd+sfVvz1lR+KRY9Fy6ZHk8PqrNImgCWfIerRuZQ==", - "dependencies": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14" + "@docusaurus/types": "*" }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" + "peerDependenciesMeta": { + "@docusaurus/types": { + "optional": true + } } }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-google-gtag/node_modules/@docusaurus/utils-validation": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.15.tgz", - "integrity": "sha512-1oOVBCkRrsTXSYrBTsMdnj3a/R56zrx11rjF4xo0+dmm8C01Xw4msFtc3uA7VLX0HQvgHsk8xPzU5GERNdsNpg==", + "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/theme-classic/node_modules/@docusaurus/utils-common": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.0.0.tgz", + "integrity": "sha512-7iJWAtt4AHf4PFEPlEPXko9LZD/dbYnhLe0q8e3GRK1EXZyRASah2lznpMwB3lLmVjq/FR6ZAKF+E0wlmL5j0g==", "dependencies": { - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "joi": "^17.4.2", - "tslib": "^2.3.1" + "tslib": "^2.6.0" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "react": "*", - "react-dom": "*" + "@docusaurus/types": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/types": { + "optional": true + } } }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-google-gtag/node_modules/@docusaurus/utils-validation/node_modules/@docusaurus/utils": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.0.0-beta.15.tgz", - "integrity": "sha512-xkoPmFxCBkDqbZR4U3SE752OcXtWTGgZnc/pZWxItzb1IYRGNZHrzdIr7CnI7rppriuZzsyivDGiC4Ud9MWhkA==", - "dependencies": { - "@docusaurus/logger": "2.0.0-beta.15", - "@mdx-js/runtime": "^1.6.22", - "@svgr/webpack": "^6.0.0", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "github-slugger": "^1.4.0", - "globby": "^11.0.4", - "gray-matter": "^4.0.3", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "micromatch": "^4.0.4", - "remark-mdx-remove-exports": "^1.6.22", - "remark-mdx-remove-imports": "^1.6.22", - "resolve-pathname": "^3.0.0", - "tslib": "^2.3.1", - "url-loader": "^4.1.1" + "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/theme-common": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.0.0.tgz", + "integrity": "sha512-PahRpCLRK5owCMEqcNtUeTMOkTUCzrJlKA+HLu7f+8osYOni617YurXvHASCsSTxurjXaLz/RqZMnASnqATxIA==", + "dependencies": { + "@docusaurus/mdx-loader": "3.0.0", + "@docusaurus/module-type-aliases": "3.0.0", + "@docusaurus/plugin-content-blog": "3.0.0", + "@docusaurus/plugin-content-docs": "3.0.0", + "@docusaurus/plugin-content-pages": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-common": "3.0.0", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "clsx": "^1.2.1", + "parse-numeric-range": "^1.3.0", + "prism-react-renderer": "^2.1.0", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "@babel/core": "^7.0.0", - "react": "*", - "react-dom": "*", - "webpack": "5.x" + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-sitemap": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.0.0-beta.15.tgz", - "integrity": "sha512-PBjeQb2Qpe4uPdRefWL/eXCeYjrgNB/UArExYeUuP4wiY1dpw2unGNCvFUxv4hzJGmARoTLsnRkeYkUim809LQ==", - "dependencies": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@docusaurus/utils-common": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", - "fs-extra": "^10.0.0", - "sitemap": "^7.0.0", - "tslib": "^2.3.1" + "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/theme-common/node_modules/@docusaurus/mdx-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.0.0.tgz", + "integrity": "sha512-JkGge6WYDrwjNgMxwkb6kNQHnpISt5L1tMaBWFDBKeDToFr5Kj29IL35MIQm0RfrnoOfr/29RjSH4aRtvlAR0A==", + "dependencies": { + "@babel/parser": "^7.22.7", + "@babel/traverse": "^7.22.8", + "@docusaurus/logger": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "@mdx-js/mdx": "^3.0.0", + "@slorber/remark-comment": "^1.0.0", + "escape-html": "^1.0.3", + "estree-util-value-to-estree": "^3.0.1", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "image-size": "^1.0.2", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-string": "^4.0.0", + "rehype-raw": "^7.0.0", + "remark-directive": "^3.0.0", + "remark-emoji": "^4.0.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0", + "stringify-object": "^3.3.0", + "tslib": "^2.6.0", + "unified": "^11.0.3", + "unist-util-visit": "^5.0.0", + "url-loader": "^4.1.1", + "vfile": "^6.0.1", + "webpack": "^5.88.1" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-sitemap/node_modules/@docusaurus/utils": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.0.0-beta.15.tgz", - "integrity": "sha512-xkoPmFxCBkDqbZR4U3SE752OcXtWTGgZnc/pZWxItzb1IYRGNZHrzdIr7CnI7rppriuZzsyivDGiC4Ud9MWhkA==", + "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/theme-common/node_modules/@docusaurus/utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.0.0.tgz", + "integrity": "sha512-JwGjh5mtjG9XIAESyPxObL6CZ6LO/yU4OSTpq7Q0x+jN25zi/AMbvLjpSyZzWy+qm5uQiFiIhqFaOxvy+82Ekg==", "dependencies": { - "@docusaurus/logger": "2.0.0-beta.15", - "@mdx-js/runtime": "^1.6.22", - "@svgr/webpack": "^6.0.0", + "@docusaurus/logger": "3.0.0", + "@svgr/webpack": "^6.5.1", + "escape-string-regexp": "^4.0.0", "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "github-slugger": "^1.4.0", - "globby": "^11.0.4", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", "gray-matter": "^4.0.3", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "micromatch": "^4.0.4", - "remark-mdx-remove-exports": "^1.6.22", - "remark-mdx-remove-imports": "^1.6.22", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", "resolve-pathname": "^3.0.0", - "tslib": "^2.3.1", - "url-loader": "^4.1.1" + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.88.1" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "@babel/core": "^7.0.0", - "react": "*", - "react-dom": "*", - "webpack": "5.x" + "@docusaurus/types": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/types": { + "optional": true + } } }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/plugin-sitemap/node_modules/@docusaurus/utils-validation": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.15.tgz", - "integrity": "sha512-1oOVBCkRrsTXSYrBTsMdnj3a/R56zrx11rjF4xo0+dmm8C01Xw4msFtc3uA7VLX0HQvgHsk8xPzU5GERNdsNpg==", + "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/theme-common/node_modules/@docusaurus/utils-common": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.0.0.tgz", + "integrity": "sha512-7iJWAtt4AHf4PFEPlEPXko9LZD/dbYnhLe0q8e3GRK1EXZyRASah2lznpMwB3lLmVjq/FR6ZAKF+E0wlmL5j0g==", "dependencies": { - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "joi": "^17.4.2", - "tslib": "^2.3.1" + "tslib": "^2.6.0" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "react": "*", - "react-dom": "*" + "@docusaurus/types": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/types": { + "optional": true + } } }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/theme-classic": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-2.0.0-beta.15.tgz", - "integrity": "sha512-WwNRcQvMtQ7KDhOEHFKFHxXCdoZwLg66hT3vhqNIFMfGQuPzOP91MX5LUSo1QWHhlrD3H3Og+r7Ik/fy2bf5lQ==", - "dependencies": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/plugin-content-blog": "2.0.0-beta.15", - "@docusaurus/plugin-content-docs": "2.0.0-beta.15", - "@docusaurus/plugin-content-pages": "2.0.0-beta.15", - "@docusaurus/theme-common": "2.0.0-beta.15", - "@docusaurus/theme-translations": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@docusaurus/utils-common": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", - "@mdx-js/react": "^1.6.21", - "clsx": "^1.1.1", - "copy-text-to-clipboard": "^3.0.1", - "infima": "0.2.0-alpha.37", - "lodash": "^4.17.20", - "postcss": "^8.3.7", - "prism-react-renderer": "^1.2.1", - "prismjs": "^1.23.0", - "react-router-dom": "^5.2.0", - "rtlcss": "^3.3.0" + "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/theme-search-algolia": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.0.0.tgz", + "integrity": "sha512-PyMUNIS9yu0dx7XffB13ti4TG47pJq3G2KE/INvOFb6M0kWh+wwCnucPg4WAOysHOPh+SD9fjlXILoLQstgEIA==", + "dependencies": { + "@docsearch/react": "^3.5.2", + "@docusaurus/core": "3.0.0", + "@docusaurus/logger": "3.0.0", + "@docusaurus/plugin-content-docs": "3.0.0", + "@docusaurus/theme-common": "3.0.0", + "@docusaurus/theme-translations": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "algoliasearch": "^4.18.0", + "algoliasearch-helper": "^3.13.3", + "clsx": "^1.2.1", + "eta": "^2.2.0", + "fs-extra": "^11.1.1", + "lodash": "^4.17.21", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/theme-classic/node_modules/@docusaurus/utils": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.0.0-beta.15.tgz", - "integrity": "sha512-xkoPmFxCBkDqbZR4U3SE752OcXtWTGgZnc/pZWxItzb1IYRGNZHrzdIr7CnI7rppriuZzsyivDGiC4Ud9MWhkA==", + "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/theme-search-algolia/node_modules/@docusaurus/utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.0.0.tgz", + "integrity": "sha512-JwGjh5mtjG9XIAESyPxObL6CZ6LO/yU4OSTpq7Q0x+jN25zi/AMbvLjpSyZzWy+qm5uQiFiIhqFaOxvy+82Ekg==", "dependencies": { - "@docusaurus/logger": "2.0.0-beta.15", - "@mdx-js/runtime": "^1.6.22", - "@svgr/webpack": "^6.0.0", + "@docusaurus/logger": "3.0.0", + "@svgr/webpack": "^6.5.1", + "escape-string-regexp": "^4.0.0", "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "github-slugger": "^1.4.0", - "globby": "^11.0.4", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", "gray-matter": "^4.0.3", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "micromatch": "^4.0.4", - "remark-mdx-remove-exports": "^1.6.22", - "remark-mdx-remove-imports": "^1.6.22", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", "resolve-pathname": "^3.0.0", - "tslib": "^2.3.1", - "url-loader": "^4.1.1" + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.88.1" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "@babel/core": "^7.0.0", - "react": "*", - "react-dom": "*", - "webpack": "5.x" + "@docusaurus/types": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/types": { + "optional": true + } } }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/theme-classic/node_modules/@docusaurus/utils-validation": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.15.tgz", - "integrity": "sha512-1oOVBCkRrsTXSYrBTsMdnj3a/R56zrx11rjF4xo0+dmm8C01Xw4msFtc3uA7VLX0HQvgHsk8xPzU5GERNdsNpg==", - "dependencies": { - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "joi": "^17.4.2", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "react": "*", - "react-dom": "*" - } + "node_modules/@docusaurus/preset-classic/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/theme-classic/node_modules/react-router-dom": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.0.tgz", - "integrity": "sha512-ObVBLjUZsphUUMVycibxgMdh5jJ1e3o+KpAZBVeHcNQZ4W+uUGGWsokurzlF4YOldQYRQL4y6yFRWM4m3svmuQ==", - "dependencies": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "loose-envify": "^1.3.1", - "prop-types": "^15.6.2", - "react-router": "5.2.1", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - }, - "peerDependencies": { - "react": ">=15" + "node_modules/@docusaurus/preset-classic/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/@docusaurus/preset-classic/node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/theme-classic/node_modules/react-router-dom/node_modules/react-router": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.1.tgz", - "integrity": "sha512-lIboRiOtDLFdg1VTemMwud9vRVuOCZmUIT/7lUoZiSpPODiiH1UQlfXy+vPLC/7IWdFYnhRwAyNqA/+I7wnvKQ==", - "dependencies": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "hoist-non-react-statics": "^3.1.0", - "loose-envify": "^1.3.1", - "mini-create-react-context": "^0.4.0", - "path-to-regexp": "^1.7.0", - "prop-types": "^15.6.2", - "react-is": "^16.6.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" + "node_modules/@docusaurus/preset-classic/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" }, - "peerDependencies": { - "react": ">=15" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/theme-classic/node_modules/react-router-dom/node_modules/react-router/node_modules/mini-create-react-context": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", - "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", - "dependencies": { - "@babel/runtime": "^7.12.1", - "tiny-warning": "^1.0.3" + "node_modules/@docusaurus/preset-classic/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "engines": { + "node": ">=12" }, - "peerDependencies": { - "prop-types": "^15.0.0", - "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/theme-common": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.0.0-beta.15.tgz", - "integrity": "sha512-+pvarmzcyECE4nWxw+dCMKRIoes0NegrRuM9+nRsUrS/E5ywsF539kpupKIEqaMjq6AuM0CJtDoHxHHPNe0KaQ==", + "node_modules/@docusaurus/preset-classic/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dependencies": { - "@docusaurus/plugin-content-blog": "2.0.0-beta.15", - "@docusaurus/plugin-content-docs": "2.0.0-beta.15", - "@docusaurus/plugin-content-pages": "2.0.0-beta.15", - "clsx": "^1.1.1", - "parse-numeric-range": "^1.3.0", - "tslib": "^2.3.1", - "utility-types": "^3.10.0" - }, - "engines": { - "node": ">=14" + "argparse": "^2.0.1" }, - "peerDependencies": { - "prism-react-renderer": "^1.2.1", - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@docusaurus/preset-classic/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/@docusaurus/preset-classic/node_modules/array-union": { + "node_modules/@docusaurus/preset-classic/node_modules/trough": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "engines": { - "node": ">=8" + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/@docusaurus/preset-classic/node_modules/cheerio": { - "version": "1.0.0-rc.10", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", - "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", + "node_modules/@docusaurus/preset-classic/node_modules/unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", "dependencies": { - "cheerio-select": "^1.5.0", - "dom-serializer": "^1.3.2", - "domhandler": "^4.2.0", - "htmlparser2": "^6.1.0", - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "tslib": "^2.2.0" - }, - "engines": { - "node": ">= 6" + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" }, "funding": { - "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/@docusaurus/preset-classic/node_modules/dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "node_modules/@docusaurus/preset-classic/node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" + "@types/unist": "^3.0.0" }, "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/@docusaurus/preset-classic/node_modules/domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/@docusaurus/preset-classic/node_modules/domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", + "node_modules/@docusaurus/preset-classic/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" + "@types/unist": "^3.0.0" }, "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/@docusaurus/preset-classic/node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "node_modules/@docusaurus/preset-classic/node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" }, "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/@docusaurus/preset-classic/node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "node_modules/@docusaurus/preset-classic/node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/@docusaurus/preset-classic/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "node_modules/@docusaurus/preset-classic/node_modules/vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/@docusaurus/preset-classic/node_modules/htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], + "node_modules/@docusaurus/preset-classic/node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "node_modules/@docusaurus/preset-classic/node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "engines": { - "node": ">= 4" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/@docusaurus/preset-classic/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "node_modules/@docusaurus/react-loadable": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", + "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", "dependencies": { - "argparse": "^2.0.1" + "@types/react": "*", + "prop-types": "^15.6.2" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "peerDependencies": { + "react": "*" } }, - "node_modules/@docusaurus/preset-classic/node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "node_modules/@docusaurus/theme-translations": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.0.0.tgz", + "integrity": "sha512-p/H3+5LdnDtbMU+csYukA6601U1ld2v9knqxGEEV96qV27HsHfP63J9Ta2RBZUrNhQAgrwFzIc9GdDO8P1Baag==", "dependencies": { - "isarray": "0.0.1" - } - }, - "node_modules/@docusaurus/preset-classic/node_modules/prism-react-renderer": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-1.3.1.tgz", - "integrity": "sha512-xUeDMEz074d0zc5y6rxiMp/dlC7C+5IDDlaEUlcBOFE2wddz7hz5PNupb087mPwTt7T9BrFmewObfCBuf/LKwQ==", - "peerDependencies": { - "react": ">=0.14.9" - } - }, - "node_modules/@docusaurus/theme-search-algolia": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.0.0-beta.15.tgz", - "integrity": "sha512-XrrQKyjOPzmEuOcdsaAn1tzNJkNMA3PC86PwPZUaah0cYPpBGptcJYDlIW4VHIrCBfkQvhvmg/B3qKF6bMMi8g==", - "dependencies": { - "@docsearch/react": "^3.0.0-alpha.39", - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/theme-common": "2.0.0-beta.15", - "@docusaurus/theme-translations": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", - "algoliasearch": "^4.10.5", - "algoliasearch-helper": "^3.5.5", - "clsx": "^1.1.1", - "eta": "^1.12.3", - "lodash": "^4.17.20", - "tslib": "^2.3.1", - "utility-types": "^3.10.0" + "fs-extra": "^11.1.1", + "tslib": "^2.6.0" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" + "node": ">=18.0" } }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/@docsearch/react": { + "node_modules/@docusaurus/types": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.0.0.tgz", - "integrity": "sha512-yhMacqS6TVQYoBh/o603zszIb5Bl8MIXuOc6Vy617I74pirisDzzcNh0NEaYQt50fVVR3khUbeEhUEWEWipESg==", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.0.0.tgz", + "integrity": "sha512-Qb+l/hmCOVemReuzvvcFdk84bUmUFyD0Zi81y651ie3VwMrXqC7C0E7yZLKMOsLj/vkqsxHbtkAuYMI89YzNzg==", "dependencies": { - "@algolia/autocomplete-core": "1.5.2", - "@algolia/autocomplete-preset-algolia": "1.5.2", - "@docsearch/css": "3.0.0", - "algoliasearch": "^4.0.0" + "@types/history": "^4.7.11", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "^1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.88.1", + "webpack-merge": "^5.9.0" }, "peerDependencies": { - "@types/react": ">= 16.8.0 < 18.0.0", - "react": ">= 16.8.0 < 18.0.0", - "react-dom": ">= 16.8.0 < 18.0.0" + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/@docusaurus/theme-common": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.0.0-beta.15.tgz", - "integrity": "sha512-+pvarmzcyECE4nWxw+dCMKRIoes0NegrRuM9+nRsUrS/E5ywsF539kpupKIEqaMjq6AuM0CJtDoHxHHPNe0KaQ==", + "node_modules/@docusaurus/utils-validation": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.0.0.tgz", + "integrity": "sha512-MlIGUspB/HBW5CYgHvRhmkZbeMiUWKbyVoCQYvbGN8S19SSzVgzyy97KRpcjCOYYeEdkhmRCUwFBJBlLg3IoNQ==", "dependencies": { - "@docusaurus/plugin-content-blog": "2.0.0-beta.15", - "@docusaurus/plugin-content-docs": "2.0.0-beta.15", - "@docusaurus/plugin-content-pages": "2.0.0-beta.15", - "clsx": "^1.1.1", - "parse-numeric-range": "^1.3.0", - "tslib": "^2.3.1", - "utility-types": "^3.10.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "prism-react-renderer": "^1.2.1", - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" - } - }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/@docusaurus/theme-common/node_modules/@docusaurus/plugin-content-blog": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.0.0-beta.15.tgz", - "integrity": "sha512-VtEwkgkoNIS8JFPe+huBeBuJ8HG8Lq1JNYM/ItwQg/cwGAgP8EgwbEuKDn428oZKEI2PpgAuf5Gv4AzJWIes9A==", - "dependencies": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/mdx-loader": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@docusaurus/utils-common": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", - "cheerio": "^1.0.0-rc.10", - "feed": "^4.2.2", - "fs-extra": "^10.0.0", - "lodash": "^4.17.20", - "reading-time": "^1.5.0", - "remark-admonitions": "^1.2.1", - "tslib": "^2.3.1", - "utility-types": "^3.10.0", - "webpack": "^5.61.0" + "@docusaurus/logger": "3.0.0", + "@docusaurus/utils": "3.0.0", + "joi": "^17.9.2", + "js-yaml": "^4.1.0", + "tslib": "^2.6.0" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" + "node": ">=18.0" } }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/@docusaurus/theme-common/node_modules/@docusaurus/plugin-content-blog/node_modules/@docusaurus/mdx-loader": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.15.tgz", - "integrity": "sha512-MVpytjDDao7hmPF1QSs9B5zoTgevZjiqjnX3FM1yjqdCv+chyUo0gnmYHjeG/4Gqu7jucp+dDdp6yQpzs4g09A==", + "node_modules/@docusaurus/utils-validation/node_modules/@docusaurus/utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.0.0.tgz", + "integrity": "sha512-JwGjh5mtjG9XIAESyPxObL6CZ6LO/yU4OSTpq7Q0x+jN25zi/AMbvLjpSyZzWy+qm5uQiFiIhqFaOxvy+82Ekg==", "dependencies": { - "@babel/parser": "^7.16.4", - "@babel/traverse": "^7.16.3", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@mdx-js/mdx": "^1.6.21", - "escape-html": "^1.0.3", + "@docusaurus/logger": "3.0.0", + "@svgr/webpack": "^6.5.1", + "escape-string-regexp": "^4.0.0", "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "image-size": "^1.0.1", - "mdast-util-to-string": "^2.0.0", - "remark-emoji": "^2.1.0", - "stringify-object": "^3.3.0", - "tslib": "^2.3.1", - "unist-util-visit": "^2.0.2", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "resolve-pathname": "^3.0.0", + "shelljs": "^0.8.5", + "tslib": "^2.6.0", "url-loader": "^4.1.1", - "webpack": "^5.61.0" + "webpack": "^5.88.1" }, "engines": { - "node": ">=14" + "node": ">=18.0" }, "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" + "@docusaurus/types": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/types": { + "optional": true + } } }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/@docusaurus/theme-common/node_modules/@docusaurus/plugin-content-docs": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.0.0-beta.15.tgz", - "integrity": "sha512-HSwNZdUKz4rpJiGbFjl/OFhSleeZUSZ6E6lk98i4iL1A5u6fIm4CHsT53yp4UUOse+lFrePTFZsyqwMA4nZZYA==", - "dependencies": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/mdx-loader": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", - "combine-promises": "^1.1.0", - "fs-extra": "^10.0.0", - "import-fresh": "^3.2.2", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "remark-admonitions": "^1.2.1", - "shelljs": "^0.8.4", - "tslib": "^2.3.1", - "utility-types": "^3.10.0", - "webpack": "^5.61.0" - }, + "node_modules/@docusaurus/utils-validation/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/@docusaurus/utils-validation/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "engines": { - "node": ">=14" + "node": ">=10" }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/@docusaurus/theme-common/node_modules/@docusaurus/plugin-content-docs/node_modules/@docusaurus/mdx-loader": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.15.tgz", - "integrity": "sha512-MVpytjDDao7hmPF1QSs9B5zoTgevZjiqjnX3FM1yjqdCv+chyUo0gnmYHjeG/4Gqu7jucp+dDdp6yQpzs4g09A==", - "dependencies": { - "@babel/parser": "^7.16.4", - "@babel/traverse": "^7.16.3", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@mdx-js/mdx": "^1.6.21", - "escape-html": "^1.0.3", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "image-size": "^1.0.1", - "mdast-util-to-string": "^2.0.0", - "remark-emoji": "^2.1.0", - "stringify-object": "^3.3.0", - "tslib": "^2.3.1", - "unist-util-visit": "^2.0.2", - "url-loader": "^4.1.1", - "webpack": "^5.61.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" - } - }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/@docusaurus/theme-common/node_modules/@docusaurus/plugin-content-pages": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.0.0-beta.15.tgz", - "integrity": "sha512-N7YhW5RiOY6J228z4lOoP//qX0Q48cRtxDONZ/Ohd9C5OI2vS6TD8iQuDqOIYHxH+BshjNSsKvbJ+SMIQDwysg==", - "dependencies": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/mdx-loader": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", - "fs-extra": "^10.0.0", - "globby": "^11.0.2", - "remark-admonitions": "^1.2.1", - "tslib": "^2.3.1", - "webpack": "^5.61.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" - } - }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/@docusaurus/theme-common/node_modules/@docusaurus/plugin-content-pages/node_modules/@docusaurus/mdx-loader": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.15.tgz", - "integrity": "sha512-MVpytjDDao7hmPF1QSs9B5zoTgevZjiqjnX3FM1yjqdCv+chyUo0gnmYHjeG/4Gqu7jucp+dDdp6yQpzs4g09A==", - "dependencies": { - "@babel/parser": "^7.16.4", - "@babel/traverse": "^7.16.3", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@mdx-js/mdx": "^1.6.21", - "escape-html": "^1.0.3", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "image-size": "^1.0.1", - "mdast-util-to-string": "^2.0.0", - "remark-emoji": "^2.1.0", - "stringify-object": "^3.3.0", - "tslib": "^2.3.1", - "unist-util-visit": "^2.0.2", - "url-loader": "^4.1.1", - "webpack": "^5.61.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" - } - }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/@docusaurus/utils": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.0.0-beta.15.tgz", - "integrity": "sha512-xkoPmFxCBkDqbZR4U3SE752OcXtWTGgZnc/pZWxItzb1IYRGNZHrzdIr7CnI7rppriuZzsyivDGiC4Ud9MWhkA==", - "dependencies": { - "@docusaurus/logger": "2.0.0-beta.15", - "@mdx-js/runtime": "^1.6.22", - "@svgr/webpack": "^6.0.0", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "github-slugger": "^1.4.0", - "globby": "^11.0.4", - "gray-matter": "^4.0.3", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "micromatch": "^4.0.4", - "remark-mdx-remove-exports": "^1.6.22", - "remark-mdx-remove-imports": "^1.6.22", - "resolve-pathname": "^3.0.0", - "tslib": "^2.3.1", - "url-loader": "^4.1.1" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "react": "*", - "react-dom": "*", - "webpack": "5.x" - } - }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/@docusaurus/utils-validation": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.15.tgz", - "integrity": "sha512-1oOVBCkRrsTXSYrBTsMdnj3a/R56zrx11rjF4xo0+dmm8C01Xw4msFtc3uA7VLX0HQvgHsk8xPzU5GERNdsNpg==", - "dependencies": { - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "joi": "^17.4.2", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "react": "*", - "react-dom": "*" - } - }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/cheerio": { - "version": "1.0.0-rc.10", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", - "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", - "dependencies": { - "cheerio-select": "^1.5.0", - "dom-serializer": "^1.3.2", - "domhandler": "^4.2.0", - "htmlparser2": "^6.1.0", - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "tslib": "^2.2.0" - }, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/cheeriojs/cheerio?sponsor=1" - } - }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "node_modules/@docusaurus/utils-validation/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dependencies": { "argparse": "^2.0.1" }, @@ -3762,38 +3830,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/prism-react-renderer": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-1.3.1.tgz", - "integrity": "sha512-xUeDMEz074d0zc5y6rxiMp/dlC7C+5IDDlaEUlcBOFE2wddz7hz5PNupb087mPwTt7T9BrFmewObfCBuf/LKwQ==", - "peer": true, - "peerDependencies": { - "react": ">=0.14.9" - } - }, - "node_modules/@docusaurus/theme-translations": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-2.0.0-beta.15.tgz", - "integrity": "sha512-Lu2JDsnZaB2BcJe8Hpq5nrbS7+7bd09jT08b9vztQyvzR8PgzsthnzlLN4ilOeamRIuYJKo1pUGm0EsQBOP6Nw==", - "dependencies": { - "fs-extra": "^10.0.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@docusaurus/utils-common": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-2.0.0-beta.15.tgz", - "integrity": "sha512-kIGlSIvbE/oniUpUjI8GOkSpH8o4NXbYqAh9dqPn+TJ0KbEFY3fc80gzZQU+9SunCwJMJbIxIGevX9Ry+nackw==", - "dependencies": { - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/@eslint/eslintrc": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", @@ -3828,9 +3864,9 @@ } }, "node_modules/@hapi/hoek": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz", - "integrity": "sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw==" + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" }, "node_modules/@hapi/topo": { "version": "5.1.0", @@ -3858,163 +3894,383 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "node_modules/@jest/schemas": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", + "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", + "dependencies": { + "@sinclair/typebox": "^0.25.16" + }, "engines": { - "node": ">=6.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", - "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "node_modules/@jest/types": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", + "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jest/schemas": "^29.4.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@mdx-js/mdx": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-1.6.22.tgz", - "integrity": "sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA==", - "dependencies": { - "@babel/core": "7.12.9", - "@babel/plugin-syntax-jsx": "7.12.1", - "@babel/plugin-syntax-object-rest-spread": "7.8.3", - "@mdx-js/util": "1.6.22", - "babel-plugin-apply-mdx-type-prop": "1.6.22", - "babel-plugin-extract-import-names": "1.6.22", - "camelcase-css": "2.0.1", - "detab": "2.0.4", - "hast-util-raw": "6.0.1", - "lodash.uniq": "4.5.0", - "mdast-util-to-hast": "10.0.1", - "remark-footnotes": "2.0.0", - "remark-mdx": "1.6.22", - "remark-parse": "8.0.3", - "remark-squeeze-paragraphs": "4.0.0", - "style-to-object": "0.3.0", - "unified": "9.2.0", - "unist-builder": "2.0.3", - "unist-util-visit": "2.0.3" + "node_modules/@jest/types/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@mdx-js/mdx/node_modules/@babel/core": { - "version": "7.12.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", - "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.5", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.5", - "@babel/parser": "^7.12.7", - "@babel/template": "^7.12.7", - "@babel/traverse": "^7.12.9", - "@babel/types": "^7.12.7", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@mdx-js/mdx/node_modules/@babel/plugin-syntax-jsx": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", - "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", + "node_modules/@jest/types/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "color-name": "~1.1.4" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=7.0.0" } }, - "node_modules/@mdx-js/mdx/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "bin": { - "semver": "bin/semver" + "node_modules/@jest/types/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@jest/types/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" } }, - "node_modules/@mdx-js/mdx/node_modules/unified": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz", - "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", + "node_modules/@jest/types/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^2.0.0", - "trough": "^1.0.0", - "vfile": "^4.0.0" + "has-flag": "^4.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=8" } }, - "node_modules/@mdx-js/react": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-1.6.22.tgz", - "integrity": "sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz", + "integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" + }, + "node_modules/@mdx-js/mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.0.0.tgz", + "integrity": "sha512-Icm0TBKBLYqroYbNW3BPnzMGn+7mwpQOK310aZ7+fkCtiU3aqv2cdcX+nd0Ydo3wI5Rx8bX2Z2QmGb/XcAClCw==", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-to-js": "^2.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-estree": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "periscopic": "^3.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" - }, - "peerDependencies": { - "react": "^16.13.1 || ^17.0.0" } }, - "node_modules/@mdx-js/runtime": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/runtime/-/runtime-1.6.22.tgz", - "integrity": "sha512-p17spaO2+55VLCuxXA3LVHC4phRx60NR2XMdZ+qgVU1lKvEX4y88dmFNOzGDCPLJ03IZyKrJ/rPWWRiBrd9JrQ==", + "node_modules/@mdx-js/mdx/node_modules/@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", "dependencies": { - "@mdx-js/mdx": "1.6.22", - "@mdx-js/react": "1.6.22", - "buble-jsx-only": "^0.19.8" + "@types/unist": "*" + } + }, + "node_modules/@mdx-js/mdx/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/@mdx-js/mdx/node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@mdx-js/mdx/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "engines": { + "node": ">=12" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@mdx-js/mdx/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", "engines": { - "node": ">=8" + "node": ">= 8" + } + }, + "node_modules/@mdx-js/mdx/node_modules/trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@mdx-js/mdx/node_modules/unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dependencies": { + "@types/unist": "^3.0.0" }, - "peerDependencies": { - "react": "^16.13.1" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/@mdx-js/util": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/util/-/util-1.6.22.tgz", - "integrity": "sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==", + "node_modules/@mdx-js/react": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.0.0.tgz", + "integrity": "sha512-nDctevR9KyYFyV+m+/+S4cpzCWHqj+iHDHq3QrsWezcC+B17uZdIWgCguESUkwFhM3n/56KxWVE3V6EokrmONQ==", + "dependencies": { + "@types/mdx": "^2.0.0" + }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, + "node_modules/@microlink/react-json-view": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/@microlink/react-json-view/-/react-json-view-1.23.0.tgz", + "integrity": "sha512-HYJ1nsfO4/qn8afnAMhuk7+5a1vcjEaS8Gm5Vpr1SqdHDY0yLBJGpA+9DvKyxyVKaUkXzKXt3Mif9RcmFSdtYg==", + "dependencies": { + "flux": "~4.0.1", + "react-base16-styling": "~0.6.0", + "react-lifecycles-compat": "~3.0.4", + "react-textarea-autosize": "~8.3.2" + }, + "peerDependencies": { + "react": ">= 15", + "react-dom": ">= 15" + } + }, + "node_modules/@microlink/react-json-view/node_modules/flux": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.4.tgz", + "integrity": "sha512-NCj3XlayA2UsapRpM7va6wU1+9rE5FIL7qoMcmxWHRzbp0yujihMBm9BBHZ1MDIk5h5o2Bl6eGiCe8rYELAmYw==", + "dependencies": { + "fbemitter": "^3.0.0", + "fbjs": "^3.0.1" + }, + "peerDependencies": { + "react": "^15.0.2 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dependencies": { + "eslint-scope": "5.1.1" } }, "node_modules/@nodelib/fs.scandir": { @@ -4049,53 +4305,112 @@ "node": ">= 8" } }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/npm-conf": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz", + "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==", + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@polka/url": { - "version": "1.0.0-next.21", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", - "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==" + "version": "1.0.0-next.23", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.23.tgz", + "integrity": "sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==" }, "node_modules/@sideway/address": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.3.tgz", - "integrity": "sha512-8ncEUtmnTsMmL7z1YPB47kPUq7LpKWJNFPsRzHiIajGC5uXlWGn+AmkYPcHNl8S4tcEGx+cnORnNYaw2wvL+LQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", "dependencies": { "@hapi/hoek": "^9.0.0" } }, "node_modules/@sideway/formula": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", - "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" }, "node_modules/@sideway/pinpoint": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" }, + "node_modules/@sinclair/typebox": { + "version": "0.25.24", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", + "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==" + }, "node_modules/@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", "engines": { - "node": ">=6" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@slorber/remark-comment": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@slorber/remark-comment/-/remark-comment-1.0.0.tgz", + "integrity": "sha512-RCE24n7jsOj1M0UPvIQCHTe7fI0sFL4S2nwKVWwHyVr/wI/H8GosgsJGyhnsZoGFnD/P2hLf1mSbrrgSLN93NA==", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.1.0", + "micromark-util-symbol": "^1.0.1" } }, "node_modules/@slorber/static-site-generator-webpack-plugin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.1.tgz", - "integrity": "sha512-PSv4RIVO1Y3kvHxjvqeVisk3E9XFoO04uwYBDWe217MFqKspplYswTuKLiJu0aLORQWzuQjfVsSlLPojwfYsLw==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.7.tgz", + "integrity": "sha512-Ug7x6z5lwrz0WqdnNFOMYrDQNTPAprvHLSh6+/fmml3qUiz6l5eq+2MzLKWtn/q5K5NpSiFsZTP/fck/3vjSxA==", "dependencies": { - "bluebird": "^3.7.1", - "cheerio": "^0.22.0", - "eval": "^0.1.4", - "url": "^0.11.0", - "webpack-sources": "^1.4.3" + "eval": "^0.1.8", + "p-map": "^4.0.0", + "webpack-sources": "^3.2.2" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@slorber/static-site-generator-webpack-plugin/node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "engines": { + "node": ">=10.13.0" } }, "node_modules/@svgr/babel-plugin-add-jsx-attribute": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.0.0.tgz", - "integrity": "sha512-MdPdhdWLtQsjd29Wa4pABdhWbaRMACdM1h31BY+c6FghTZqNGT7pEYdBoaGeKtdTOBC/XNFQaKVj+r/Ei2ryWA==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.5.1.tgz", + "integrity": "sha512-9PYGcXrAxitycIjRmZB+Q0JaN07GZIWaTBIGQzfaZv+qr1n8X1XUEJ5rZ/vx6OVD9RRYlrNnXWExQXcmZeD/BQ==", "engines": { "node": ">=10" }, @@ -4108,11 +4423,11 @@ } }, "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-6.0.0.tgz", - "integrity": "sha512-aVdtfx9jlaaxc3unA6l+M9YRnKIZjOhQPthLKqmTXC8UVkBLDRGwPKo+r8n3VZN8B34+yVajzPTZ+ptTSuZZCw==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", @@ -4123,11 +4438,11 @@ } }, "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-6.0.0.tgz", - "integrity": "sha512-Ccj42ApsePD451AZJJf1QzTD1B/BOU392URJTeXFxSK709i0KUsGtbwyiqsKu7vsYxpTM0IA5clAKDyf9RCZyA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", @@ -4138,9 +4453,9 @@ } }, "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-6.0.0.tgz", - "integrity": "sha512-88V26WGyt1Sfd1emBYmBJRWMmgarrExpKNVmI9vVozha4kqs6FzQJ/Kp5+EYli1apgX44518/0+t9+NU36lThQ==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-6.5.1.tgz", + "integrity": "sha512-8DPaVVE3fd5JKuIC29dqyMB54sA6mfgki2H2+swh+zNJoynC8pMPzOkidqHOSc6Wj032fhl8Z0TVn1GiPpAiJg==", "engines": { "node": ">=10" }, @@ -4153,9 +4468,9 @@ } }, "node_modules/@svgr/babel-plugin-svg-dynamic-title": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-6.0.0.tgz", - "integrity": "sha512-F7YXNLfGze+xv0KMQxrl2vkNbI9kzT9oDK55/kUuymh1ACyXkMV+VZWX1zEhSTfEKh7VkHVZGmVtHg8eTZ6PRg==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-6.5.1.tgz", + "integrity": "sha512-FwOEi0Il72iAzlkaHrlemVurgSQRDFbk0OC8dSvD5fSBPHltNh7JtLsxmZUhjYBZo2PpcU/RJvvi6Q0l7O7ogw==", "engines": { "node": ">=10" }, @@ -4168,9 +4483,9 @@ } }, "node_modules/@svgr/babel-plugin-svg-em-dimensions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-6.0.0.tgz", - "integrity": "sha512-+rghFXxdIqJNLQK08kwPBD3Z22/0b2tEZ9lKiL/yTfuyj1wW8HUXu4bo/XkogATIYuXSghVQOOCwURXzHGKyZA==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-6.5.1.tgz", + "integrity": "sha512-gWGsiwjb4tw+ITOJ86ndY/DZZ6cuXMNE/SjcDRg+HLuCmwpcjOktwRF9WgAiycTqJD/QXqL2f8IzE2Rzh7aVXA==", "engines": { "node": ">=10" }, @@ -4183,9 +4498,9 @@ } }, "node_modules/@svgr/babel-plugin-transform-react-native-svg": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-6.0.0.tgz", - "integrity": "sha512-VaphyHZ+xIKv5v0K0HCzyfAaLhPGJXSk2HkpYfXIOKb7DjLBv0soHDxNv6X0vr2titsxE7klb++u7iOf7TSrFQ==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-6.5.1.tgz", + "integrity": "sha512-2jT3nTayyYP7kI6aGutkyfJ7UMGtuguD72OjeGLwVNyfPRBD8zQthlvL+fAbAKk5n9ZNcvFkp/b1lZ7VsYqVJg==", "engines": { "node": ">=10" }, @@ -4198,9 +4513,9 @@ } }, "node_modules/@svgr/babel-plugin-transform-svg-component": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-6.2.0.tgz", - "integrity": "sha512-bhYIpsORb++wpsp91fymbFkf09Z/YEKR0DnFjxvN+8JHeCUD2unnh18jIMKnDJTWtvpTaGYPXELVe4OOzFI0xg==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-6.5.1.tgz", + "integrity": "sha512-a1p6LF5Jt33O3rZoVRBqdxL350oge54iZWHNI6LJB5tQ7EelvD/Mb1mfBiZNAan0dt4i3VArkFRjA4iObuNykQ==", "engines": { "node": ">=12" }, @@ -4213,18 +4528,18 @@ } }, "node_modules/@svgr/babel-preset": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-6.2.0.tgz", - "integrity": "sha512-4WQNY0J71JIaL03DRn0vLiz87JXx0b9dYm2aA8XHlQJQoixMl4r/soYHm8dsaJZ3jWtkCiOYy48dp9izvXhDkQ==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-6.5.1.tgz", + "integrity": "sha512-6127fvO/FF2oi5EzSQOAjo1LE3OtNVh11R+/8FXa+mHx1ptAaS4cknIjnUA7e6j6fwGGJ17NzaTJFUwOV2zwCw==", "dependencies": { - "@svgr/babel-plugin-add-jsx-attribute": "^6.0.0", - "@svgr/babel-plugin-remove-jsx-attribute": "^6.0.0", - "@svgr/babel-plugin-remove-jsx-empty-expression": "^6.0.0", - "@svgr/babel-plugin-replace-jsx-attribute-value": "^6.0.0", - "@svgr/babel-plugin-svg-dynamic-title": "^6.0.0", - "@svgr/babel-plugin-svg-em-dimensions": "^6.0.0", - "@svgr/babel-plugin-transform-react-native-svg": "^6.0.0", - "@svgr/babel-plugin-transform-svg-component": "^6.2.0" + "@svgr/babel-plugin-add-jsx-attribute": "^6.5.1", + "@svgr/babel-plugin-remove-jsx-attribute": "*", + "@svgr/babel-plugin-remove-jsx-empty-expression": "*", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^6.5.1", + "@svgr/babel-plugin-svg-dynamic-title": "^6.5.1", + "@svgr/babel-plugin-svg-em-dimensions": "^6.5.1", + "@svgr/babel-plugin-transform-react-native-svg": "^6.5.1", + "@svgr/babel-plugin-transform-svg-component": "^6.5.1" }, "engines": { "node": ">=10" @@ -4238,11 +4553,13 @@ } }, "node_modules/@svgr/core": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/@svgr/core/-/core-6.2.1.tgz", - "integrity": "sha512-NWufjGI2WUyrg46mKuySfviEJ6IxHUOm/8a3Ph38VCWSp+83HBraCQrpEM3F3dB6LBs5x8OElS8h3C0oOJaJAA==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-6.5.1.tgz", + "integrity": "sha512-/xdLSWxK5QkqG524ONSjvg3V/FkNyCv538OIBdQqPNaAta3AsXj/Bd2FbvR87yMbXO2hFSWiAe/Q6IkVPDw+mw==", "dependencies": { - "@svgr/plugin-jsx": "^6.2.1", + "@babel/core": "^7.19.6", + "@svgr/babel-preset": "^6.5.1", + "@svgr/plugin-jsx": "^6.5.1", "camelcase": "^6.2.0", "cosmiconfig": "^7.0.1" }, @@ -4255,12 +4572,12 @@ } }, "node_modules/@svgr/hast-util-to-babel-ast": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.2.1.tgz", - "integrity": "sha512-pt7MMkQFDlWJVy9ULJ1h+hZBDGFfSCwlBNW1HkLnVi7jUhyEXUaGYWi1x6bM2IXuAR9l265khBT4Av4lPmaNLQ==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.5.1.tgz", + "integrity": "sha512-1hnUxxjd83EAxbL4a0JDJoD3Dao3hmjvyvyEV8PzWmLK3B9m9NPlW7GKjFyoWE8nM7HnXzPcmmSyOW8yOddSXw==", "dependencies": { - "@babel/types": "^7.15.6", - "entities": "^3.0.1" + "@babel/types": "^7.20.0", + "entities": "^4.4.0" }, "engines": { "node": ">=10" @@ -4271,14 +4588,14 @@ } }, "node_modules/@svgr/plugin-jsx": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-6.2.1.tgz", - "integrity": "sha512-u+MpjTsLaKo6r3pHeeSVsh9hmGRag2L7VzApWIaS8imNguqoUwDq/u6U/NDmYs/KAsrmtBjOEaAAPbwNGXXp1g==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-6.5.1.tgz", + "integrity": "sha512-+UdQxI3jgtSjCykNSlEMuy1jSRQlGC7pqBCPvkG/2dATdWo082zHTTK3uhnAju2/6XpE6B5mZ3z4Z8Ns01S8Gw==", "dependencies": { - "@babel/core": "^7.15.5", - "@svgr/babel-preset": "^6.2.0", - "@svgr/hast-util-to-babel-ast": "^6.2.1", - "svg-parser": "^2.0.2" + "@babel/core": "^7.19.6", + "@svgr/babel-preset": "^6.5.1", + "@svgr/hast-util-to-babel-ast": "^6.5.1", + "svg-parser": "^2.0.4" }, "engines": { "node": ">=10" @@ -4292,13 +4609,13 @@ } }, "node_modules/@svgr/plugin-svgo": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-6.2.0.tgz", - "integrity": "sha512-oDdMQONKOJEbuKwuy4Np6VdV6qoaLLvoY86hjvQEgU82Vx1MSWRyYms6Sl0f+NtqxLI/rDVufATbP/ev996k3Q==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-6.5.1.tgz", + "integrity": "sha512-omvZKf8ixP9z6GWgwbtmP9qQMPX4ODXi+wzbVZgomNFsUIlHA1sf4fThdwTWSsZGgvGAG6yE+b/F5gWUkcZ/iQ==", "dependencies": { "cosmiconfig": "^7.0.1", "deepmerge": "^4.2.2", - "svgo": "^2.5.0" + "svgo": "^2.8.0" }, "engines": { "node": ">=10" @@ -4308,22 +4625,22 @@ "url": "https://github.com/sponsors/gregberge" }, "peerDependencies": { - "@svgr/core": "^6.0.0" + "@svgr/core": "*" } }, "node_modules/@svgr/webpack": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-6.2.1.tgz", - "integrity": "sha512-h09ngMNd13hnePwgXa+Y5CgOjzlCvfWLHg+MBnydEedAnuLRzUHUJmGS3o2OsrhxTOOqEsPOFt5v/f6C5Qulcw==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-6.5.1.tgz", + "integrity": "sha512-cQ/AsnBkXPkEK8cLbv4Dm7JGXq2XrumKnL1dRpJD9rIO2fTIlJI9a1uCciYG1F2aUsox/hJQyNGbt3soDxSRkA==", "dependencies": { - "@babel/core": "^7.15.5", - "@babel/plugin-transform-react-constant-elements": "^7.14.5", - "@babel/preset-env": "^7.15.6", - "@babel/preset-react": "^7.14.5", - "@babel/preset-typescript": "^7.15.0", - "@svgr/core": "^6.2.1", - "@svgr/plugin-jsx": "^6.2.1", - "@svgr/plugin-svgo": "^6.2.0" + "@babel/core": "^7.19.6", + "@babel/plugin-transform-react-constant-elements": "^7.18.12", + "@babel/preset-env": "^7.19.4", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.18.6", + "@svgr/core": "^6.5.1", + "@svgr/plugin-jsx": "^6.5.1", + "@svgr/plugin-svgo": "^6.5.1" }, "engines": { "node": ">=10" @@ -4334,14 +4651,14 @@ } }, "node_modules/@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", "dependencies": { - "defer-to-connect": "^1.0.1" + "defer-to-connect": "^2.0.1" }, "engines": { - "node": ">=6" + "node": ">=14.16" } }, "node_modules/@trysound/sax": { @@ -4352,6 +4669,14 @@ "node": ">=10.13.0" } }, + "node_modules/@types/acorn": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", + "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -4378,58 +4703,62 @@ } }, "node_modules/@types/connect-history-api-fallback": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", - "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz", + "integrity": "sha512-4x5FkPpLipqwthjPsF7ZRbOv3uoLUFkTA9G9v583qi4pACvq0uTELrB8OLUzPWUI4IJIyvM85vzkV1nyiI2Lig==", "dependencies": { "@types/express-serve-static-core": "*", "@types/node": "*" } }, - "node_modules/@types/eslint": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", - "integrity": "sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA==", + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" + "@types/ms": "*" } }, - "node_modules/@types/eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.3.tgz", + "integrity": "sha512-pvQ+TKeRHeiUGRhvYwRrQ/ISnohKkSJR14fT2yqyZ4e9K5vqc7hrtY2Y1Dw0ZwAzQ6DQsxsaCUuSIIi8v0Cq6w==", "dependencies": { - "@types/eslint": "*", "@types/estree": "*" } }, - "node_modules/@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==" - }, "node_modules/@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", "dependencies": { "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", + "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "*" } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.28", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", - "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", + "version": "4.17.35", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz", + "integrity": "sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==", "dependencies": { "@types/node": "*", "@types/qs": "*", - "@types/range-parser": "*" + "@types/range-parser": "*", + "@types/send": "*" } }, + "node_modules/@types/gtag.js": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/@types/gtag.js/-/gtag.js-0.0.12.tgz", + "integrity": "sha512-YQV9bUsemkzG81Ea295/nF/5GijnD2Af7QhEofh7xu+kvCN6RdodgNwwGWXB5GMI3NoyvQo0odNctoH/qLMIpg==" + }, "node_modules/@types/hast": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", @@ -4438,37 +4767,83 @@ "@types/unist": "*" } }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==" + }, "node_modules/@types/html-minifier-terser": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==" + }, + "node_modules/@types/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==" + }, "node_modules/@types/http-proxy": { - "version": "1.17.8", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz", - "integrity": "sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA==", + "version": "1.17.11", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.11.tgz", + "integrity": "sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA==", "dependencies": { "@types/node": "*" } }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, "node_modules/@types/json-schema": { "version": "7.0.9", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==" }, "node_modules/@types/mdast": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", - "integrity": "sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz", + "integrity": "sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==", "dependencies": { "@types/unist": "*" } }, + "node_modules/@types/mdx": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.10.tgz", + "integrity": "sha512-Rllzc5KHk0Al5/WANwgSPl1/CwjqCy+AZrGd78zuK+jO9aDM6ffblZ+zIjgPNAaEBmlO0RYDvLNh7wD0zKVgEg==" + }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" }, + "node_modules/@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" + }, "node_modules/@types/node": { "version": "17.0.19", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.19.tgz", @@ -4484,6 +4859,11 @@ "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz", "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==" }, + "node_modules/@types/prismjs": { + "version": "1.26.3", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.3.tgz", + "integrity": "sha512-A0D0aTXvjlqJ5ZILMz3rNfDBOx9hHxLZYv2by47Sm/pqW35zzjusrZTryatjN/Rf8Us2gZrJD+KeHbUSTux1Cw==" + }, "node_modules/@types/prop-types": { "version": "15.7.4", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", @@ -4509,15 +4889,44 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/react-router": { + "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-config": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/@types/react-router-config/-/react-router-config-5.0.10.tgz", + "integrity": "sha512-Wn6c/tXdEgi9adCMtDwx8Q2vGty6TsPTc/wCQQ9kAlye8UqFxj0vGFWWuhywNfkwqth+SOgJxQTLTZukrqDQmQ==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "^5.1.0" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, "node_modules/@types/retry": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", - "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==" + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" }, "node_modules/@types/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-pSAff4IAxJjfAXUG6tFkO7dsSbTmf8CtUpfhhZ5VhkRpC4628tJhh3+V6H1E+/Gs9piSzYKT5yzHO5M4GG9jkw==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", + "integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==", "dependencies": { "@types/node": "*" } @@ -4527,6 +4936,15 @@ "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" }, + "node_modules/@types/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", + "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, "node_modules/@types/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", @@ -4536,11 +4954,12 @@ } }, "node_modules/@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.2.tgz", + "integrity": "sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw==", "dependencies": { - "@types/mime": "^1", + "@types/http-errors": "*", + "@types/mime": "*", "@types/node": "*" } }, @@ -4558,141 +4977,159 @@ "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" }, "node_modules/@types/ws": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-ahRJZquUYCdOZf/rCsWg88S0/+cb9wazUBHv6HZEe3XdYaBe2zr/slM8J28X07Hn88Pnm4ezo7N8/ofnOgrPVQ==", + "version": "8.5.5", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", + "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", "dependencies": { "@types/node": "*" } }, + "node_modules/@types/yargs": { + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + }, "node_modules/@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" } }, "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==" + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" }, "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==" + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==" + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==" }, "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==" + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" } }, "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==" + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", "dependencies": { - "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/ast": "1.12.1", "@xtuc/long": "4.2.2" } }, @@ -4724,19 +5161,19 @@ } }, "node_modules/accepts/node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "engines": { "node": ">= 0.6" } }, "node_modules/accepts/node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dependencies": { - "mime-db": "1.51.0" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" @@ -4762,9 +5199,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz", + "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==", "engines": { "node": ">=0.4.0" } @@ -4821,9 +5258,9 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -4849,35 +5286,35 @@ } }, "node_modules/algoliasearch": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.12.1.tgz", - "integrity": "sha512-c0dM1g3zZBJrkzE5GA/Nu1y3fFxx3LCzxKzcmp2dgGS8P4CjszB/l3lsSh2MSrrK1Hn/KV4BlbBMXtYgG1Bfrw==", - "dependencies": { - "@algolia/cache-browser-local-storage": "4.12.1", - "@algolia/cache-common": "4.12.1", - "@algolia/cache-in-memory": "4.12.1", - "@algolia/client-account": "4.12.1", - "@algolia/client-analytics": "4.12.1", - "@algolia/client-common": "4.12.1", - "@algolia/client-personalization": "4.12.1", - "@algolia/client-search": "4.12.1", - "@algolia/logger-common": "4.12.1", - "@algolia/logger-console": "4.12.1", - "@algolia/requester-browser-xhr": "4.12.1", - "@algolia/requester-common": "4.12.1", - "@algolia/requester-node-http": "4.12.1", - "@algolia/transporter": "4.12.1" + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.20.0.tgz", + "integrity": "sha512-y+UHEjnOItoNy0bYO+WWmLWBlPwDjKHW6mNHrPi0NkuhpQOOEbrkwQH/wgKFDLh7qlKjzoKeiRtlpewDPDG23g==", + "dependencies": { + "@algolia/cache-browser-local-storage": "4.20.0", + "@algolia/cache-common": "4.20.0", + "@algolia/cache-in-memory": "4.20.0", + "@algolia/client-account": "4.20.0", + "@algolia/client-analytics": "4.20.0", + "@algolia/client-common": "4.20.0", + "@algolia/client-personalization": "4.20.0", + "@algolia/client-search": "4.20.0", + "@algolia/logger-common": "4.20.0", + "@algolia/logger-console": "4.20.0", + "@algolia/requester-browser-xhr": "4.20.0", + "@algolia/requester-common": "4.20.0", + "@algolia/requester-node-http": "4.20.0", + "@algolia/transporter": "4.20.0" } }, "node_modules/algoliasearch-helper": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.7.0.tgz", - "integrity": "sha512-XJ3QfERBLfeVCyTVx80gon7r3/rgm/CE8Ha1H7cbablRe/X7SfYQ14g/eO+MhjVKIQp+gy9oC6G5ilmLwS1k6w==", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.15.0.tgz", + "integrity": "sha512-DGUnK3TGtDQsaUE4ayF/LjSN0DGsuYThB8WBgnnDY0Wq04K6lNVruO3LfqJOgSfDiezp+Iyt8Tj4YKHi+/ivSA==", "dependencies": { "@algolia/events": "^4.0.1" }, "peerDependencies": { - "algoliasearch": ">= 3.1 < 5" + "algoliasearch": ">= 3.1 < 6" } }, "node_modules/ansi-align": { @@ -4927,9 +5364,9 @@ } }, "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -4944,9 +5381,9 @@ "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" }, "node_modules/arg": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.1.tgz", - "integrity": "sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA==" + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" }, "node_modules/argparse": { "version": "1.0.10", @@ -4980,14 +5417,11 @@ } }, "node_modules/array-union": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-3.0.1.tgz", - "integrity": "sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/array.prototype.flatmap": { @@ -5009,7 +5443,7 @@ "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" }, "node_modules/astral-regex": { "version": "2.0.0", @@ -5019,14 +5453,19 @@ "node": ">=8" } }, - "node_modules/async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dependencies": { - "lodash": "^4.17.14" + "node_modules/astring": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.8.6.tgz", + "integrity": "sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==", + "bin": { + "astring": "bin/astring" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "node_modules/at-least-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", @@ -5044,13 +5483,27 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.2", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.2.tgz", - "integrity": "sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ==", + "version": "10.4.16", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", + "integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "dependencies": { - "browserslist": "^4.19.1", - "caniuse-lite": "^1.0.30001297", - "fraction.js": "^4.1.2", + "browserslist": "^4.21.10", + "caniuse-lite": "^1.0.30001538", + "fraction.js": "^4.3.6", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", "postcss-value-parser": "^4.2.0" @@ -5061,148 +5514,86 @@ "engines": { "node": "^10 || ^12 || >=14" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, "peerDependencies": { "postcss": "^8.1.0" } }, "node_modules/axios": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", - "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", - "dependencies": { - "follow-redirects": "^1.14.7" - } - }, - "node_modules/babel-eslint": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", - "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", - "deprecated": "babel-eslint is now @babel/eslint-parser. This package will no longer receive updates.", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", + "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", "dependencies": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.7.0", - "@babel/traverse": "^7.7.0", - "@babel/types": "^7.7.0", - "eslint-visitor-keys": "^1.0.0", - "resolve": "^1.12.0" - }, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "eslint": ">= 4.12.1" + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, "node_modules/babel-loader": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.3.tgz", - "integrity": "sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw==", + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", + "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", "dependencies": { - "find-cache-dir": "^3.3.1", - "loader-utils": "^1.4.0", - "make-dir": "^3.1.0", - "schema-utils": "^2.6.5" + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" }, "engines": { - "node": ">= 8.9" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "webpack": ">=2" - } - }, - "node_modules/babel-plugin-apply-mdx-type-prop": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-1.6.22.tgz", - "integrity": "sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ==", - "dependencies": { - "@babel/helper-plugin-utils": "7.10.4", - "@mdx-js/util": "1.6.22" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "node": ">= 14.15.0" }, "peerDependencies": { - "@babel/core": "^7.11.6" + "@babel/core": "^7.12.0", + "webpack": ">=5" } }, - "node_modules/babel-plugin-apply-mdx-type-prop/node_modules/@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" - }, "node_modules/babel-plugin-dynamic-import-node": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz", - "integrity": "sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", "dependencies": { "object.assign": "^4.1.0" } }, - "node_modules/babel-plugin-extract-import-names": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.6.22.tgz", - "integrity": "sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ==", - "dependencies": { - "@babel/helper-plugin-utils": "7.10.4" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/babel-plugin-extract-import-names/node_modules/@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" - }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", - "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.6.tgz", + "integrity": "sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q==", "dependencies": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.3.1", - "semver": "^6.1.1" + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.4.3", + "semver": "^6.3.1" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", - "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", + "version": "0.8.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.6.tgz", + "integrity": "sha512-leDIc4l4tUgU7str5BWLS2h8q2N4Nf6lGZP6UrNDxdtfF2g69eJ5L0H7S8A5Ln/arfFAfHor5InAdZuIOwZdgQ==", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1", - "core-js-compat": "^3.21.0" + "@babel/helper-define-polyfill-provider": "^0.4.3", + "core-js-compat": "^3.33.1" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.3.tgz", + "integrity": "sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw==", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1" + "@babel/helper-define-polyfill-provider": "^0.4.3" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/bail": { @@ -5222,12 +5613,12 @@ "node_modules/base16": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz", - "integrity": "sha1-4pf2DX7BAUp6lxo568ipjAtoHnA=" + "integrity": "sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ==" }, "node_modules/batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=" + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" }, "node_modules/bcp-47-match": { "version": "1.0.3", @@ -5254,29 +5645,27 @@ "node": ">=8" } }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" - }, "node_modules/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.8.1", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.9.7", - "raw-body": "2.4.3", - "type-is": "~1.6.18" + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, "node_modules/body-parser/node_modules/bytes": { @@ -5298,19 +5687,17 @@ "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/bonjour": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", - "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "node_modules/bonjour-service": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz", + "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==", "dependencies": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", + "array-flatten": "^2.1.2", "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" } }, "node_modules/boolbase": { @@ -5319,88 +5706,103 @@ "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" }, "node_modules/boxen": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz", + "integrity": "sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==", "dependencies": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" + "ansi-align": "^3.0.1", + "camelcase": "^7.0.1", + "chalk": "^5.2.0", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.1.0" }, "engines": { - "node": ">=10" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/boxen/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" + "node_modules/boxen/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/boxen/node_modules/camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", "engines": { - "node": ">=8" + "node": ">=14.16" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/boxen/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "engines": { - "node": ">=10" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/boxen/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/boxen/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/boxen/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dependencies": { - "color-name": "~1.1.4" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=7.0.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/boxen/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/boxen/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/boxen/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/boxen/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, + "node_modules/boxen/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", "engines": { - "node": ">=8" + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/brace-expansion": { @@ -5413,123 +5815,45 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" } }, "node_modules/browserslist": { - "version": "4.19.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.3.tgz", - "integrity": "sha512-XK3X4xtKJ+Txj8G5c30B4gsm71s69lqXlkYui4s6EkKxuv49qjYlY6oVd+IFJ73d4YymtM3+djvvt/R/iJwwDg==", + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "dependencies": { - "caniuse-lite": "^1.0.30001312", - "electron-to-chromium": "^1.4.71", - "escalade": "^3.1.1", - "node-releases": "^2.0.2", - "picocolors": "^1.0.0" + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" }, "bin": { "browserslist": "cli.js" }, "engines": { "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/buble-jsx-only": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/buble-jsx-only/-/buble-jsx-only-0.19.8.tgz", - "integrity": "sha512-7AW19pf7PrKFnGTEDzs6u9+JZqQwM1VnLS19OlqYDhXomtFFknnoQJAPHeg84RMFWAvOhYrG7harizJNwUKJsA==", - "dependencies": { - "acorn": "^6.1.1", - "acorn-dynamic-import": "^4.0.0", - "acorn-jsx": "^5.0.1", - "chalk": "^2.4.2", - "magic-string": "^0.25.3", - "minimist": "^1.2.0", - "regexpu-core": "^4.5.4" - }, - "bin": { - "buble": "bin/buble" - } - }, - "node_modules/buble-jsx-only/node_modules/acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/buble-jsx-only/node_modules/acorn-dynamic-import": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz", - "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==", - "peerDependencies": { - "acorn": "^6.0.0" - } - }, - "node_modules/buble-jsx-only/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "bin": { - "jsesc": "bin/jsesc" - } - }, - "node_modules/buble-jsx-only/node_modules/regenerate-unicode-properties": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz", - "integrity": "sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA==", - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/buble-jsx-only/node_modules/regexpu-core": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.8.0.tgz", - "integrity": "sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg==", - "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^9.0.0", - "regjsgen": "^0.5.2", - "regjsparser": "^0.7.0", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/buble-jsx-only/node_modules/regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==" - }, - "node_modules/buble-jsx-only/node_modules/regjsparser": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.7.0.tgz", - "integrity": "sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ==", - "dependencies": { - "jsesc": "~0.5.0" - }, - "bin": { - "regjsparser": "bin/parser" } }, "node_modules/buffer-from": { @@ -5537,11 +5861,6 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, - "node_modules/buffer-indexof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==" - }, "node_modules/bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", @@ -5550,60 +5869,55 @@ "node": ">= 0.8" } }, + "node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "engines": { + "node": ">=14.16" + } + }, "node_modules/cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=14.16" } }, - "node_modules/cacheable-request/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dependencies": { - "pump": "^3.0.0" - }, + "node_modules/cacheable-request/node_modules/normalize-url": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", + "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", "engines": { - "node": ">=8" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cacheable-request/node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request/node_modules/normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5637,14 +5951,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "engines": { - "node": ">= 6" - } - }, "node_modules/caniuse-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", @@ -5657,18 +5963,28 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001312", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz", - "integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } + "version": "1.0.30001564", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001564.tgz", + "integrity": "sha512-DqAOf+rhof+6GVx1y+xzbFPeOumfQnhYzVnZD6LAXijR77yPtm9mfOcqOnT3mpnJiZVT+kwLAFnRlZcIz+c6bg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] }, "node_modules/ccount": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz", - "integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -5687,130 +6003,120 @@ "node": ">=4" } }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "engines": { + "node": ">=10" + } + }, "node_modules/character-entities": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", - "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/character-entities-legacy": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", - "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/character-reference-invalid": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", - "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/cheerio": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", - "integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=", - "dependencies": { - "css-select": "~1.2.0", - "dom-serializer": "~0.1.0", - "entities": "~1.1.1", - "htmlparser2": "^3.9.1", - "lodash.assignin": "^4.0.9", - "lodash.bind": "^4.1.4", - "lodash.defaults": "^4.0.1", - "lodash.filter": "^4.4.0", - "lodash.flatten": "^4.2.0", - "lodash.foreach": "^4.3.0", - "lodash.map": "^4.4.0", - "lodash.merge": "^4.4.0", - "lodash.pick": "^4.2.1", - "lodash.reduce": "^4.4.0", - "lodash.reject": "^4.4.0", - "lodash.some": "^4.4.0" + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" } }, "node_modules/cheerio-select": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz", - "integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", "dependencies": { - "css-select": "^4.1.3", - "css-what": "^5.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0", - "domutils": "^2.7.0" + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" }, "funding": { "url": "https://github.com/sponsors/fb55" } }, "node_modules/cheerio-select/node_modules/css-select": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", - "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dependencies": { "boolbase": "^1.0.0", - "css-what": "^5.1.0", - "domhandler": "^4.3.0", - "domutils": "^2.8.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", "nth-check": "^2.0.1" }, "funding": { "url": "https://github.com/sponsors/fb55" } }, - "node_modules/cheerio-select/node_modules/css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, "node_modules/cheerio-select/node_modules/dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" }, "funding": { "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "node_modules/cheerio-select/node_modules/domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, "node_modules/cheerio-select/node_modules/domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dependencies": { - "domelementtype": "^2.2.0" + "domelementtype": "^2.3.0" }, "engines": { "node": ">= 4" @@ -5820,41 +6126,86 @@ } }, "node_modules/cheerio-select/node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" }, "funding": { "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "node_modules/cheerio-select/node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "node_modules/cheerio/node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "node_modules/cheerio-select/node_modules/nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "node_modules/cheerio/node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dependencies": { - "boolbase": "^1.0.0" + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" }, "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" + "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "node_modules/cheerio/node_modules/entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + "node_modules/cheerio/node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/cheerio/node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/cheerio/node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } }, "node_modules/chokidar": { "version": "3.5.3", @@ -5891,19 +6242,23 @@ } }, "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" - }, - "node_modules/classnames": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", - "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } }, "node_modules/clean-css": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.2.4.tgz", - "integrity": "sha512-nKseG8wCzEuji/4yrgM/5cthL9oTDc5UOQyFMvW/Q53oP6gLH690o1NbuTh6Y18nujr7BxlsFuS7gXLnLzKJGg==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz", + "integrity": "sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==", "dependencies": { "source-map": "~0.6.0" }, @@ -5911,14 +6266,6 @@ "node": ">= 10.0" } }, - "node_modules/clean-css/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -5928,16 +6275,30 @@ } }, "node_modules/cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", "engines": { - "node": ">=6" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cli-table3": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", + "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -5951,26 +6312,29 @@ "node": ">=6" } }, - "node_modules/clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "node_modules/clone-deep/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dependencies": { - "mimic-response": "^1.0.0" + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, "node_modules/clsx": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", - "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", "engines": { "node": ">=6" } }, "node_modules/collapse-white-space": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz", - "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", + "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -5998,14 +6362,14 @@ } }, "node_modules/colord": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.2.tgz", - "integrity": "sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ==" + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" }, "node_modules/colorette": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", - "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==" + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" }, "node_modules/combine-promises": { "version": "1.1.0", @@ -6015,6 +6379,17 @@ "node": ">=10" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/comma-separated-tokens": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", @@ -6032,10 +6407,10 @@ "node": ">= 6" } }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==" }, "node_modules/compressible": { "version": "2.0.18", @@ -6084,33 +6459,44 @@ "node_modules/compression/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, "node_modules/configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz", + "integrity": "sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==", "dependencies": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" + "dot-prop": "^6.0.1", + "graceful-fs": "^4.2.6", + "unique-string": "^3.0.0", + "write-file-atomic": "^3.0.3", + "xdg-basedir": "^5.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/yeoman/configstore?sponsor=1" } }, "node_modules/connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", "engines": { "node": ">=0.8" } @@ -6134,25 +6520,22 @@ } }, "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "engines": { "node": ">= 0.6" } }, "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dependencies": { - "safe-buffer": "~5.1.1" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, "node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "engines": { "node": ">= 0.6" } @@ -6160,12 +6543,12 @@ "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "node_modules/copy-text-to-clipboard": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.0.1.tgz", - "integrity": "sha512-rvVsHrpFcL4F2P8ihsoLdFHmd404+CMg71S756oRSeQgqk51U3kicGdnvfkrxva0xXH92SjGS62B0XIJsbh+9Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.0.tgz", + "integrity": "sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q==", "engines": { "node": ">=12" }, @@ -6174,19 +6557,19 @@ } }, "node_modules/copy-webpack-plugin": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-10.2.4.tgz", - "integrity": "sha512-xFVltahqlsRcyyJqQbDY6EYTtyQZF9rf+JPjwHObLdPFMEISqkFkr7mFoVOC6BfYS/dNThyoQKvziugm+OnwBg==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", "dependencies": { - "fast-glob": "^3.2.7", + "fast-glob": "^3.2.11", "glob-parent": "^6.0.1", - "globby": "^12.0.2", + "globby": "^13.1.1", "normalize-path": "^3.0.0", "schema-utils": "^4.0.0", "serialize-javascript": "^6.0.0" }, "engines": { - "node": ">= 12.20.0" + "node": ">= 14.15.0" }, "funding": { "type": "opencollective", @@ -6196,32 +6579,6 @@ "webpack": "^5.1.0" } }, - "node_modules/copy-webpack-plugin/node_modules/ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/copy-webpack-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, "node_modules/copy-webpack-plugin/node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -6233,64 +6590,69 @@ "node": ">=10.13.0" } }, - "node_modules/copy-webpack-plugin/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "node_modules/copy-webpack-plugin/node_modules/schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "node_modules/copy-webpack-plugin/node_modules/globby": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.0.tgz", + "integrity": "sha512-jWsQfayf13NvqKUIL3Ta+CIqMnvlaIDFveWE/dpOZ9+3AMEJozsxDvKA02zync9UuvOM8rOXzsD5GqKP4OnWPQ==", "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" }, "engines": { - "node": ">= 12.13.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/core-js": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.21.1.tgz", - "integrity": "sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==", - "hasInstallScript": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" + "node_modules/copy-webpack-plugin/node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "engines": { + "node": ">= 4" } }, - "node_modules/core-js-compat": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.1.tgz", - "integrity": "sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g==", - "dependencies": { - "browserslist": "^4.19.1", - "semver": "7.0.0" - }, + "node_modules/copy-webpack-plugin/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/core-js": { + "version": "3.33.3", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.33.3.tgz", + "integrity": "sha512-lo0kOocUlLKmm6kv/FswQL8zbkH7mVsLJ/FULClOhv8WRVmKLVcs6XPNQAzstfeJTCHMyButEwG+z1kHxHoDZw==", + "hasInstallScript": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" } }, - "node_modules/core-js-compat/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "bin": { - "semver": "bin/semver.js" + "node_modules/core-js-compat": { + "version": "3.33.3", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.33.3.tgz", + "integrity": "sha512-cNzGqFsh3Ot+529GIXacjTJ7kegdt5fPXxCBVS1G0iaZpuo/tBz399ymceLJveQhFFZ8qThHiP3fzuoQjKN2ow==", + "dependencies": { + "browserslist": "^4.22.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" } }, "node_modules/core-js-pure": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.21.1.tgz", - "integrity": "sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ==", + "version": "3.33.3", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.33.3.tgz", + "integrity": "sha512-taJ00IDOP+XYQEA2dAe4ESkmHt1fL8wzYDo3mRWQey8uO9UojlBFMneA65kMyxfYP7106c6LzWaq7/haDT6BCQ==", "hasInstallScript": true, "funding": { "type": "opencollective", @@ -6303,9 +6665,9 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, "node_modules/cosmiconfig": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", - "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -6318,17 +6680,17 @@ } }, "node_modules/cross-fetch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", - "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", "dependencies": { - "node-fetch": "2.6.7" + "node-fetch": "^2.6.12" } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz", + "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -6339,40 +6701,54 @@ } }, "node_modules/crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "dependencies": { + "type-fest": "^1.0.1" + }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/css-declaration-sorter": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.1.4.tgz", - "integrity": "sha512-lpfkqS0fctcmZotJGhnxkIyJWvBXgpyi2wsFd4J8VB7wzyrT6Ch/3Q+FMNJpjK4gu1+GN5khOnpU2ZVKrLbhCw==", - "dependencies": { - "timsort": "^0.3.0" + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "engines": { + "node": ">=10" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/css-declaration-sorter": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz", + "integrity": "sha512-jDfsatwWMWN0MODAFuHszfjphEXfNw9JUAhmY4pLu3TyTU+ohUpsbVtbU+1MZn4a47D9kqh03i4eyOm+74+zew==", "engines": { - "node": ">= 10" + "node": "^10 || ^12 || >=14" }, "peerDependencies": { "postcss": "^8.0.9" } }, "node_modules/css-loader": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.6.0.tgz", - "integrity": "sha512-FK7H2lisOixPT406s5gZM1S3l8GrfhEBT3ZiL2UX1Ng1XWs0y2GPllz/OTyvbaHe12VgQrIXIzuEGVlbUhodqg==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz", + "integrity": "sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==", "dependencies": { "icss-utils": "^5.1.0", - "postcss": "^8.4.5", + "postcss": "^8.4.21", "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-local-by-default": "^4.0.3", "postcss-modules-scope": "^3.0.0", "postcss-modules-values": "^4.0.0", "postcss-value-parser": "^4.2.0", - "semver": "^7.3.5" + "semver": "^7.3.8" }, "engines": { "node": ">= 12.13.0" @@ -6386,19 +6762,19 @@ } }, "node_modules/css-minimizer-webpack-plugin": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz", - "integrity": "sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-4.2.2.tgz", + "integrity": "sha512-s3Of/4jKfw1Hj9CxEO1E5oXhQAxlayuHO2y/ML+C6I9sQ7FdzfEV6QgMLN3vI+qFsjJGIAFLKtQK7t8BOXAIyA==", "dependencies": { - "cssnano": "^5.0.6", - "jest-worker": "^27.0.2", - "postcss": "^8.3.5", + "cssnano": "^5.1.8", + "jest-worker": "^29.1.2", + "postcss": "^8.4.17", "schema-utils": "^4.0.0", "serialize-javascript": "^6.0.0", "source-map": "^0.6.1" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 14.15.0" }, "funding": { "type": "opencollective", @@ -6411,6 +6787,9 @@ "@parcel/css": { "optional": true }, + "@swc/css": { + "optional": true + }, "clean-css": { "optional": true }, @@ -6419,75 +6798,61 @@ }, "esbuild": { "optional": true + }, + "lightningcss": { + "optional": true } } }, - "node_modules/css-minimizer-webpack-plugin/node_modules/ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "node_modules/css-minimizer-webpack-plugin/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" } }, - "node_modules/css-minimizer-webpack-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "node_modules/css-minimizer-webpack-plugin/node_modules/jest-worker": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", + "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", "dependencies": { - "fast-deep-equal": "^3.1.3" + "@types/node": "*", + "jest-util": "^29.5.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" }, - "peerDependencies": { - "ajv": "^8.8.2" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/css-minimizer-webpack-plugin/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "node_modules/css-minimizer-webpack-plugin/node_modules/schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "node_modules/css-minimizer-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">= 12.13.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/css-minimizer-webpack-plugin/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/css-select": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", - "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "dependencies": { - "boolbase": "~1.0.0", - "css-what": "2.1", - "domutils": "1.5.1", - "nth-check": "~1.0.1" + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" } }, "node_modules/css-selector-parser": { @@ -6507,20 +6872,15 @@ "node": ">=8.0.0" } }, - "node_modules/css-tree/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/css-what": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", - "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", "engines": { - "node": "*" + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" } }, "node_modules/cssesc": { @@ -6535,11 +6895,11 @@ } }, "node_modules/cssnano": { - "version": "5.0.17", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.0.17.tgz", - "integrity": "sha512-fmjLP7k8kL18xSspeXTzRhaFtRI7DL9b8IcXR80JgtnWBpvAzHT7sCR/6qdn0tnxIaINUN6OEQu83wF57Gs3Xw==", + "version": "5.1.15", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz", + "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", "dependencies": { - "cssnano-preset-default": "^5.1.12", + "cssnano-preset-default": "^5.2.14", "lilconfig": "^2.0.3", "yaml": "^1.10.2" }, @@ -6555,16 +6915,16 @@ } }, "node_modules/cssnano-preset-advanced": { - "version": "5.1.12", - "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-5.1.12.tgz", - "integrity": "sha512-5WWV9mbqVNwH4nRjs5UbhNl7eKo+16eYNzGogmz0Sa6iqWUeLdN8oo83WuTTqz5vjEKhTbRM5oX6WV1i6ees6g==", + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.10.tgz", + "integrity": "sha512-fnYJyCS9jgMU+cmHO1rPSPf9axbQyD7iUhLO5Df6O4G+fKIOMps+ZbU0PdGFejFBBZ3Pftf18fn1eG7MAPUSWQ==", "dependencies": { - "autoprefixer": "^10.3.7", - "cssnano-preset-default": "^5.1.12", - "postcss-discard-unused": "^5.0.3", - "postcss-merge-idents": "^5.0.3", - "postcss-reduce-idents": "^5.0.3", - "postcss-zindex": "^5.0.2" + "autoprefixer": "^10.4.12", + "cssnano-preset-default": "^5.2.14", + "postcss-discard-unused": "^5.1.0", + "postcss-merge-idents": "^5.1.1", + "postcss-reduce-idents": "^5.2.0", + "postcss-zindex": "^5.1.0" }, "engines": { "node": "^10 || ^12 || >=14.0" @@ -6574,39 +6934,39 @@ } }, "node_modules/cssnano-preset-default": { - "version": "5.1.12", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.1.12.tgz", - "integrity": "sha512-rO/JZYyjW1QNkWBxMGV28DW7d98UDLaF759frhli58QFehZ+D/LSmwQ2z/ylBAe2hUlsIWTq6NYGfQPq65EF9w==", - "dependencies": { - "css-declaration-sorter": "^6.0.3", - "cssnano-utils": "^3.0.2", - "postcss-calc": "^8.2.0", - "postcss-colormin": "^5.2.5", - "postcss-convert-values": "^5.0.4", - "postcss-discard-comments": "^5.0.3", - "postcss-discard-duplicates": "^5.0.3", - "postcss-discard-empty": "^5.0.3", - "postcss-discard-overridden": "^5.0.4", - "postcss-merge-longhand": "^5.0.6", - "postcss-merge-rules": "^5.0.6", - "postcss-minify-font-values": "^5.0.4", - "postcss-minify-gradients": "^5.0.6", - "postcss-minify-params": "^5.0.5", - "postcss-minify-selectors": "^5.1.3", - "postcss-normalize-charset": "^5.0.3", - "postcss-normalize-display-values": "^5.0.3", - "postcss-normalize-positions": "^5.0.4", - "postcss-normalize-repeat-style": "^5.0.4", - "postcss-normalize-string": "^5.0.4", - "postcss-normalize-timing-functions": "^5.0.3", - "postcss-normalize-unicode": "^5.0.4", - "postcss-normalize-url": "^5.0.5", - "postcss-normalize-whitespace": "^5.0.4", - "postcss-ordered-values": "^5.0.5", - "postcss-reduce-initial": "^5.0.3", - "postcss-reduce-transforms": "^5.0.4", - "postcss-svgo": "^5.0.4", - "postcss-unique-selectors": "^5.0.4" + "version": "5.2.14", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", + "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", + "dependencies": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.1", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.4", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.2", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" }, "engines": { "node": "^10 || ^12 || >=14.0" @@ -6616,9 +6976,9 @@ } }, "node_modules/cssnano-utils": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.0.2.tgz", - "integrity": "sha512-KhprijuQv2sP4kT92sSQwhlK3SJTbDIsxcfIEySB0O+3m9esFOai7dP9bMx5enHAh2MwarVIcnwiWoOm01RIbQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", "engines": { "node": "^10 || ^12 || >=14.0" }, @@ -6642,6 +7002,11 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" + }, "node_modules/debug": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", @@ -6658,31 +7023,41 @@ } } }, + "node_modules/decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "dependencies": { - "mimic-response": "^1.0.0" + "mimic-response": "^3.1.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "dependencies": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/deep-extend": { @@ -6718,9 +7093,28 @@ } }, "node_modules/defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/define-lazy-prop": { "version": "2.0.0", @@ -6742,9 +7136,9 @@ } }, "node_modules/del": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", - "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", "dependencies": { "globby": "^11.0.1", "graceful-fs": "^4.2.4", @@ -6762,64 +7156,37 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/del/node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/del/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.4.0" } }, - "node_modules/del/node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "engines": { - "node": ">= 4" + "node": ">= 0.8" } }, - "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "engines": { - "node": ">= 0.6" + "node": ">=6" } }, "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "node_modules/detab": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detab/-/detab-2.0.4.tgz", - "integrity": "sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g==", - "dependencies": { - "repeat-string": "^1.5.4" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, "node_modules/detect-node": { @@ -6828,19 +7195,16 @@ "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" }, "node_modules/detect-port": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.3.0.tgz", - "integrity": "sha512-E+B1gzkl2gqxt1IhUzwjrxBKRqx1UzC3WLONHinn8S3T6lwV/agVCyitiFOsGJ/eYuEUBvD71MZHy3Pv1G9doQ==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", + "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", "dependencies": { "address": "^1.0.1", - "debug": "^2.6.0" + "debug": "4" }, "bin": { - "detect": "bin/detect-port", - "detect-port": "bin/detect-port" - }, - "engines": { - "node": ">= 4.2.1" + "detect": "bin/detect-port.js", + "detect-port": "bin/detect-port.js" } }, "node_modules/detect-port-alt": { @@ -6870,21 +7234,20 @@ "node_modules/detect-port-alt/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/detect-port/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", "dependencies": { - "ms": "2.0.0" + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/detect-port/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -6911,23 +7274,17 @@ "node_modules/dns-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=" + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==" }, "node_modules/dns-packet": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", - "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", - "dependencies": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/dns-txt": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", - "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.0.tgz", + "integrity": "sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ==", "dependencies": { - "buffer-indexof": "^1.0.0" + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" } }, "node_modules/doctrine": { @@ -6942,18 +7299,19 @@ } }, "node_modules/docusaurus-lunr-search": { - "version": "2.1.15", - "resolved": "https://registry.npmjs.org/docusaurus-lunr-search/-/docusaurus-lunr-search-2.1.15.tgz", - "integrity": "sha512-W37af7ziwNFstM0VNjruJi3HChPWI5BWGAAxFYpRRbMZQAZqdQtz4aZHX5E/ORrfqHWsKTGMCRWode1rb3ncQw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/docusaurus-lunr-search/-/docusaurus-lunr-search-3.3.0.tgz", + "integrity": "sha512-F2fSAA+6vRCHxF4R+rV8xSg1cYY7pXFKdbBNlTX6+dyKdwCWcnrmTXJmlCkN4DT65ntNU9iTd+mZ8lZzH3Lncg==", "dependencies": { "autocomplete.js": "^0.37.0", - "classnames": "^2.2.6", + "clsx": "^1.2.1", "gauge": "^3.0.0", "hast-util-select": "^4.0.0", "hast-util-to-text": "^2.0.0", "hogan.js": "^3.0.2", "lunr": "^2.3.8", "lunr-languages": "^1.4.0", + "mark.js": "^8.11.1", "minimatch": "^3.0.4", "object-assign": "^4.1.1", "rehype-parse": "^7.0.1", @@ -6965,9 +7323,9 @@ "node": ">= 8.10.0" }, "peerDependencies": { - "@docusaurus/core": "^2.0.0-alpha.60 || ^2.0.0", - "react": "^16.8.4 || ^17", - "react-dom": "^16.8.4 || ^17" + "@docusaurus/core": "^2.0.0-alpha.60 || ^2.0.0 || ^3.0.0", + "react": "^16.8.4 || ^17 || ^18", + "react-dom": "^16.8.4 || ^17 || ^18" } }, "node_modules/docusaurus-lunr-search/node_modules/autocomplete.js": { @@ -6987,39 +7345,62 @@ } }, "node_modules/dom-serializer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", - "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "dependencies": { - "domelementtype": "^1.3.0", - "entities": "^1.1.1" + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, "node_modules/dom-serializer/node_modules/entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } }, "node_modules/domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] }, "node_modules/domhandler": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dependencies": { - "domelementtype": "1" + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" } }, "node_modules/domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "dependencies": { - "dom-serializer": "0", - "domelementtype": "1" + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" } }, "node_modules/dot-case": { @@ -7032,14 +7413,17 @@ } }, "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", "dependencies": { "is-obj": "^2.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/duplexer": { @@ -7047,26 +7431,31 @@ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" }, - "node_modules/duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.71", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.71.tgz", - "integrity": "sha512-Hk61vXXKRb2cd3znPE9F+2pLWdIOmP7GjiTj45y6L3W/lO+hSnUSUhq+6lEaERWBdZOHbk2s3YV5c9xVl3boVw==" + "version": "1.4.590", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.590.tgz", + "integrity": "sha512-hohItzsQcG7/FBsviCYMtQwUSWvVF7NVqPOnJCErWsAshsP/CR2LAXdmq276RbESNdhxiAq5/vRo1g2pxGXVww==" }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, + "node_modules/emojilib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", + "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==" + }, "node_modules/emojis-list": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", @@ -7076,34 +7465,26 @@ } }, "node_modules/emoticon": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/emoticon/-/emoticon-3.2.0.tgz", - "integrity": "sha512-SNujglcLTTg+lDAcApPNgEdudaqQFiAbJCqzjNxJkvN9vAwCGi0uu8IUVvx+f16h+V44KCY6Y2yboroc9pilHg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/emoticon/-/emoticon-4.0.1.tgz", + "integrity": "sha512-dqx7eA9YaqyvYtUhJwT4rC1HIp82j5ybS1/vQ42ur+jBe17dJMwZE4+gvL1XadSFfxaPFFGt3Xsw+Y8akThDlw==", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "engines": { "node": ">= 0.8" } }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dependencies": { - "once": "^1.4.0" - } - }, "node_modules/enhanced-resolve": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.0.tgz", - "integrity": "sha512-weDYmzbBygL7HzGGS26M3hGQx68vehdEg6VUmqSOaFzXExFqlnKuSvsEJCVGQHScS8CQMbrAqftT+AzzHNt/YA==", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -7124,9 +7505,9 @@ } }, "node_modules/entities": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", - "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "engines": { "node": ">=0.12" }, @@ -7175,10 +7556,29 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==" + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", + "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==" }, "node_modules/es-to-primitive": { "version": "1.2.1", @@ -7205,11 +7605,14 @@ } }, "node_modules/escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", + "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/escape-html": { @@ -7332,9 +7735,9 @@ } }, "node_modules/eslint-plugin-react/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -7541,6 +7944,116 @@ "node": ">=4.0" } }, + "node_modules/estree-util-attach-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", + "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-build-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-walker": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-to-js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", + "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "astring": "^1.8.0", + "source-map": "^0.7.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-to-js/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/estree-util-value-to-estree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-value-to-estree/-/estree-util-value-to-estree-3.0.1.tgz", + "integrity": "sha512-b2tdzTurEIbwRh+mKrEcaWfu1wgb8J1hVsgREg7FFiecWwK/PhO8X0kyc+0bIcKNtD4sqxIdNoRy6/p/TvECEA==", + "dependencies": { + "@types/estree": "^1.0.0", + "is-plain-obj": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/remcohaszing" + } + }, + "node_modules/estree-util-value-to-estree/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/estree-util-visit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-visit/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -7550,9 +8063,9 @@ } }, "node_modules/eta": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/eta/-/eta-1.12.3.tgz", - "integrity": "sha512-qHixwbDLtekO/d51Yr4glcaUJCIjGVJyTzuqV4GPlgZo1YpgOKG+avQynErZIYrfM6JIJdtiG2Kox8tbb+DoGg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eta/-/eta-2.2.0.tgz", + "integrity": "sha512-UVQ72Rqjy/ZKQalzV5dCCJP80GrmPrMxh6NlNf+erV6ObL0ZFkhCstWRawS85z3smdr3d2wXPsZEY7rDPfGd2g==", "engines": { "node": ">=6.0.0" }, @@ -7563,16 +8076,17 @@ "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "engines": { "node": ">= 0.6" } }, "node_modules/eval": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/eval/-/eval-0.1.6.tgz", - "integrity": "sha512-o0XUw+5OGkXw4pJZzQoXUk+H87DHuC+7ZE//oSrRGtatTmr12oTnLfg6QOq9DyTt0c/p4TwzgmkKrBzWTSizyQ==", + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eval/-/eval-0.1.8.tgz", + "integrity": "sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==", "dependencies": { + "@types/node": "*", "require-like": ">= 0.1.1" }, "engines": { @@ -7614,49 +8128,39 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/execa/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/express": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", - "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.2", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", + "depd": "2.0.0", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "~1.1.2", + "finalhandler": "1.3.1", "fresh": "0.5.2", - "merge-descriptors": "1.0.1", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.9.7", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.17.2", - "serve-static": "1.14.2", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", - "statuses": "~1.5.0", + "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -7668,7 +8172,7 @@ "node_modules/express/node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, "node_modules/express/node_modules/content-disposition": { "version": "0.5.4", @@ -7692,12 +8196,12 @@ "node_modules/express/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/express/node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" }, "node_modules/express/node_modules/range-parser": { "version": "1.2.1", @@ -7734,7 +8238,7 @@ "node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dependencies": { "is-extendable": "^0.1.0" }, @@ -7748,9 +8252,9 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -7781,13 +8285,25 @@ } }, "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", "dependencies": { "reusify": "^1.0.4" } }, + "node_modules/fault": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", + "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/faye-websocket": { "version": "0.11.4", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", @@ -7808,9 +8324,9 @@ } }, "node_modules/fbjs": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.4.tgz", - "integrity": "sha512-ucV0tDODnGV3JCnnkmoszb5lf4bNpzjv80K41wd4k798Etq+UYD0y0TIfalLjZoKgjive6/adkRnszwapiDgBQ==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.5.tgz", + "integrity": "sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==", "dependencies": { "cross-fetch": "^3.1.5", "fbjs-css-vars": "^1.0.0", @@ -7818,7 +8334,7 @@ "object-assign": "^4.1.0", "promise": "^7.1.1", "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.30" + "ua-parser-js": "^1.0.35" } }, "node_modules/fbjs-css-vars": { @@ -7867,19 +8383,6 @@ "webpack": "^4.0.0 || ^5.0.0" } }, - "node_modules/file-loader/node_modules/loader-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, "node_modules/file-loader/node_modules/schema-utils": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", @@ -7906,9 +8409,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -7917,16 +8420,16 @@ } }, "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", - "statuses": "~1.5.0", + "statuses": "2.0.1", "unpipe": "~1.0.0" }, "engines": { @@ -7944,34 +8447,52 @@ "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=14.16" }, "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "bin": { + "flat": "cli.js" } }, "node_modules/flat-cache": { @@ -7992,9 +8513,9 @@ "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==" }, "node_modules/follow-redirects": { - "version": "1.14.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", - "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "funding": [ { "type": "individual", @@ -8010,51 +8531,236 @@ } } }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz", + "integrity": "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==", + "dependencies": { + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "chokidar": "^3.4.2", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "glob": "^7.1.6", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=10", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "eslint": ">= 6", + "typescript": ">= 2.7", + "vue-template-compiler": "*", + "webpack": ">= 4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + } } }, - "node_modules/fraction.js": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.3.tgz", - "integrity": "sha512-pUHWWt6vHzZZiQJcM6S/0PXfS+g6FM4BF5rj9wZyreivhQPdsh5PpE25VtSNxq80wHS5RfY51Ii+8Z0Zl/pmzg==", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": "*" + "node": ">=8" }, "funding": { - "type": "patreon", - "url": "https://www.patreon.com/infusion" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/fs-extra": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", - "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dependencies": { + "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" }, "engines": { - "node": ">=12" + "node": ">=10" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "dependencies": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "engines": { + "node": ">= 14.17" + } + }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" } }, "node_modules/fs-monkey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", - "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==" + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.4.tgz", + "integrity": "sha512-INM/fWAxMICjttnD0DX1rBvinKskj5G1w+oy/pnm9u/tSlnBrzFonJMcalKJ30P8RRsPzKcCG7Q8l0jx5Fh9YQ==" }, "node_modules/fs.realpath": { "version": "1.0.0", @@ -8075,9 +8781,12 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/functional-red-black-tree": { "version": "1.0.1", @@ -8112,13 +8821,18 @@ } }, "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -8130,14 +8844,14 @@ "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" }, "node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dependencies": { - "pump": "^3.0.0" - }, + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/get-symbol-description": { @@ -8156,9 +8870,9 @@ } }, "node_modules/github-slugger": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.4.0.tgz", - "integrity": "sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ==" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.5.0.tgz", + "integrity": "sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==" }, "node_modules/glob": { "version": "7.2.0", @@ -8196,9 +8910,9 @@ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" }, "node_modules/global-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", "dependencies": { "ini": "2.0.0" }, @@ -8261,68 +8975,71 @@ } }, "node_modules/globby": { - "version": "12.2.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-12.2.0.tgz", - "integrity": "sha512-wiSuFQLZ+urS9x2gGPl1H5drc5twabmm4m2gTR27XDFyjUHJUNsS8o/2aKyIF6IoBaR630atdher0XJ5g6OMmA==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dependencies": { - "array-union": "^3.0.1", + "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.2.7", - "ignore": "^5.1.9", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", "merge2": "^1.4.1", - "slash": "^4.0.0" + "slash": "^3.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/globby/node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "engines": { "node": ">= 4" } }, - "node_modules/globby/node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "engines": { - "node": ">=12" + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dependencies": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" }, "engines": { - "node": ">=8.6" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" } }, "node_modules/graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" }, "node_modules/gray-matter": { "version": "4.0.3", @@ -8384,10 +9101,32 @@ "node": ">=4" } }, - "node_modules/has-symbols": { + "node_modules/has-property-descriptors": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "engines": { "node": ">= 0.4" }, @@ -8415,29 +9154,25 @@ "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" }, "node_modules/has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz", + "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==", "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/hast-to-hyperscript": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz", - "integrity": "sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA==", + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dependencies": { - "@types/unist": "^2.0.3", - "comma-separated-tokens": "^1.0.0", - "property-information": "^5.3.0", - "space-separated-tokens": "^1.0.0", - "style-to-object": "^0.3.0", - "unist-util-is": "^4.0.0", - "web-namespaces": "^1.0.0" + "function-bind": "^1.1.2" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">= 0.4" } }, "node_modules/hast-util-from-parse5": { @@ -8485,2035 +9220,2009 @@ } }, "node_modules/hast-util-raw": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-6.0.1.tgz", - "integrity": "sha512-ZMuiYA+UF7BXBtsTBNcLBF5HzXzkyE6MLzJnL605LKE8GJylNjGc4jjxazAHUtcwT5/CEt6afRKViYB4X66dig==", - "dependencies": { - "@types/hast": "^2.0.0", - "hast-util-from-parse5": "^6.0.0", - "hast-util-to-parse5": "^6.0.0", - "html-void-elements": "^1.0.0", - "parse5": "^6.0.0", - "unist-util-position": "^3.0.0", - "vfile": "^4.0.0", - "web-namespaces": "^1.0.0", - "xtend": "^4.0.0", - "zwitch": "^1.0.0" + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.0.1.tgz", + "integrity": "sha512-5m1gmba658Q+lO5uqL5YNGQWeh1MYWZbZmWrM5lncdcuiXuo5E2HT/CIOp0rLF8ksfSwiCVJ3twlgVRyTGThGA==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-select": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/hast-util-select/-/hast-util-select-4.0.2.tgz", - "integrity": "sha512-8EEG2//bN5rrzboPWD2HdS3ugLijNioS1pqOTIolXNf67xxShYw4SQEmVXd3imiBG+U2bC2nVTySr/iRAA7Cjg==", + "node_modules/hast-util-raw/node_modules/@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", "dependencies": { - "bcp-47-match": "^1.0.0", - "comma-separated-tokens": "^1.0.0", - "css-selector-parser": "^1.0.0", - "direction": "^1.0.0", - "hast-util-has-property": "^1.0.0", - "hast-util-is-element": "^1.0.0", - "hast-util-to-string": "^1.0.0", - "hast-util-whitespace": "^1.0.0", - "not": "^0.1.0", - "nth-check": "^2.0.0", - "property-information": "^5.0.0", - "space-separated-tokens": "^1.0.0", - "unist-util-visit": "^2.0.0", - "zwitch": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "@types/unist": "*" } }, - "node_modules/hast-util-select/node_modules/nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "dependencies": { - "boolbase": "^1.0.0" - }, + "node_modules/hast-util-raw/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/hast-util-raw/node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/hast-util-to-parse5": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz", - "integrity": "sha512-Lu5m6Lgm/fWuz8eWnrKezHtVY83JeRGaNQ2kn9aJgqaxvVkFCZQBEhgodZUDUvoodgyROHDb3r5IxAEdl6suJQ==", + "node_modules/hast-util-raw/node_modules/hast-util-from-parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.1.tgz", + "integrity": "sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==", "dependencies": { - "hast-to-hyperscript": "^9.0.0", - "property-information": "^5.0.0", - "web-namespaces": "^1.0.0", - "xtend": "^4.0.0", - "zwitch": "^1.0.0" + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^8.0.0", + "property-information": "^6.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-to-string": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-1.0.4.tgz", - "integrity": "sha512-eK0MxRX47AV2eZ+Lyr18DCpQgodvaS3fAQO2+b9Two9F5HEoRPhiUMNzoXArMJfZi2yieFzUBMRl3HNJ3Jus3w==", + "node_modules/hast-util-raw/node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "dependencies": { + "@types/hast": "^3.0.0" + }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-to-text": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-2.0.1.tgz", - "integrity": "sha512-8nsgCARfs6VkwH2jJU9b8LNTuR4700na+0h3PqCaEk4MAnMDeu5P0tP8mjk9LLNGxIeQRLbiDbZVw6rku+pYsQ==", + "node_modules/hast-util-raw/node_modules/hastscript": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-8.0.0.tgz", + "integrity": "sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==", "dependencies": { - "hast-util-is-element": "^1.0.0", - "repeat-string": "^1.0.0", - "unist-util-find-after": "^3.0.0" + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-whitespace": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-1.0.4.tgz", - "integrity": "sha512-I5GTdSfhYfAPNztx2xJRQpG8cuDSNt599/7YUn7Gx/WxNMsG+a835k97TDkFgk123cwjfwINaZknkKkphx/f2A==", + "node_modules/hast-util-raw/node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dependencies": { + "entities": "^4.4.0" + }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/hastscript": { + "node_modules/hast-util-raw/node_modules/property-information": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.4.0.tgz", + "integrity": "sha512-9t5qARVofg2xQqKtytzt+lZ4d1Qvj8t5B8fEwXK6qOfgRLgH/b13QlgEyDh033NOS31nXeFbYv7CLUDG1CeifQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/hast-util-raw/node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/hast-util-raw/node_modules/unist-util-is": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", - "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", "dependencies": { - "@types/hast": "^2.0.0", - "comma-separated-tokens": "^1.0.0", - "hast-util-parse-selector": "^2.0.0", - "property-information": "^5.0.0", - "space-separated-tokens": "^1.0.0" + "@types/unist": "^3.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "bin": { - "he": "bin/he" + "node_modules/hast-util-raw/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/history": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", - "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "node_modules/hast-util-raw/node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", "dependencies": { - "@babel/runtime": "^7.1.2", - "loose-envify": "^1.2.0", - "resolve-pathname": "^3.0.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0", - "value-equal": "^1.0.1" + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/hogan.js": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/hogan.js/-/hogan.js-3.0.2.tgz", - "integrity": "sha1-TNnhq9QpQUbnZ55B14mHMrAse/0=", + "node_modules/hast-util-raw/node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", "dependencies": { - "mkdirp": "0.3.0", - "nopt": "1.0.10" + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" }, - "bin": { - "hulk": "bin/hulk" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "node_modules/hast-util-raw/node_modules/vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", "dependencies": { - "react-is": "^16.7.0" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "node_modules/hast-util-raw/node_modules/vfile-location": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.2.tgz", + "integrity": "sha512-NXPYyxyBSH7zB5U6+3uDdd6Nybz6o6/od9rk8bp9H8GR3L+cm/fC0uUTbqBmUTnMCUDslAGBOIKNfvvb+gGlDg==", "dependencies": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/hpack.js/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "node_modules/hpack.js/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "node_modules/hast-util-raw/node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/hpack.js/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" + "node_modules/hast-util-raw/node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/html-entities": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz", - "integrity": "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==" + "node_modules/hast-util-raw/node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } }, - "node_modules/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "node_modules/hast-util-select": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hast-util-select/-/hast-util-select-4.0.2.tgz", + "integrity": "sha512-8EEG2//bN5rrzboPWD2HdS3ugLijNioS1pqOTIolXNf67xxShYw4SQEmVXd3imiBG+U2bC2nVTySr/iRAA7Cjg==", "dependencies": { - "camel-case": "^4.1.2", - "clean-css": "^5.2.2", - "commander": "^8.3.0", - "he": "^1.2.0", - "param-case": "^3.0.4", - "relateurl": "^0.2.7", - "terser": "^5.10.0" - }, - "bin": { - "html-minifier-terser": "cli.js" + "bcp-47-match": "^1.0.0", + "comma-separated-tokens": "^1.0.0", + "css-selector-parser": "^1.0.0", + "direction": "^1.0.0", + "hast-util-has-property": "^1.0.0", + "hast-util-is-element": "^1.0.0", + "hast-util-to-string": "^1.0.0", + "hast-util-whitespace": "^1.0.0", + "not": "^0.1.0", + "nth-check": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0", + "unist-util-visit": "^2.0.0", + "zwitch": "^1.0.0" }, - "engines": { - "node": ">=12" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/html-minifier-terser/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "engines": { - "node": ">= 12" + "node_modules/hast-util-to-estree": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.0.tgz", + "integrity": "sha512-lfX5g6hqVh9kjS/B9E2gSkvHH4SZNiQFiqWS0x9fENzEl+8W12RqdRxX6d/Cwxi30tPQs3bIO+aolQJNp1bIyw==", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^0.4.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/html-tags": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz", - "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==", - "engines": { - "node": ">=8" + "node_modules/hast-util-to-estree/node_modules/@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "dependencies": { + "@types/unist": "*" } }, - "node_modules/html-void-elements": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz", - "integrity": "sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==", + "node_modules/hast-util-to-estree/node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/html-webpack-plugin": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", - "integrity": "sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw==", + "node_modules/hast-util-to-estree/node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", "dependencies": { - "@types/html-minifier-terser": "^6.0.0", - "html-minifier-terser": "^6.0.2", - "lodash": "^4.17.21", - "pretty-error": "^4.0.0", - "tapable": "^2.0.0" - }, - "engines": { - "node": ">=10.13.0" + "@types/hast": "^3.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/html-webpack-plugin" - }, - "peerDependencies": { - "webpack": "^5.20.0" + "url": "https://opencollective.com/unified" } }, - "node_modules/htmlparser2": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", - "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", - "dependencies": { - "domelementtype": "^1.3.1", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^3.1.1" + "node_modules/hast-util-to-estree/node_modules/property-information": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.4.0.tgz", + "integrity": "sha512-9t5qARVofg2xQqKtytzt+lZ4d1Qvj8t5B8fEwXK6qOfgRLgH/b13QlgEyDh033NOS31nXeFbYv7CLUDG1CeifQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/htmlparser2/node_modules/entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" - }, - "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + "node_modules/hast-util-to-estree/node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } }, - "node_modules/http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=" + "node_modules/hast-util-to-estree/node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } }, - "node_modules/http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.2.0.tgz", + "integrity": "sha512-wSlp23N45CMjDg/BPW8zvhEi3R+8eRE1qFbjEyAUzMCzu2l1Wzwakq+Tlia9nkCtEl5mDxa7nKHsvYJ6Gfn21A==", "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.1" + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^0.4.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" }, - "engines": { - "node": ">= 0.6" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/http-parser-js": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.5.tgz", - "integrity": "sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA==" - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "node_modules/hast-util-to-jsx-runtime/node_modules/@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" + "@types/unist": "*" } }, - "node_modules/http-proxy-middleware": { + "node_modules/hast-util-to-jsx-runtime/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/hast-util-to-jsx-runtime/node_modules/comma-separated-tokens": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.3.tgz", - "integrity": "sha512-1bloEwnrHMnCoO/Gcwbz7eSVvW50KPES01PecpagI+YLNLci4AcuKJrujW4Mc3sBLpFxMSlsLNHS5Nl/lvrTPA==", - "dependencies": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@types/express": "^4.17.13" - }, - "peerDependenciesMeta": { - "@types/express": { - "optional": true - } + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { + "node_modules/hast-util-to-jsx-runtime/node_modules/hast-util-whitespace": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", - "engines": { - "node": ">=10" + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "dependencies": { + "@types/hast": "^3.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "engines": { - "node": ">=10.17.0" + "node_modules/hast-util-to-jsx-runtime/node_modules/property-information": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.4.0.tgz", + "integrity": "sha512-9t5qARVofg2xQqKtytzt+lZ4d1Qvj8t5B8fEwXK6qOfgRLgH/b13QlgEyDh033NOS31nXeFbYv7CLUDG1CeifQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" + "node_modules/hast-util-to-jsx-runtime/node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "engines": { - "node": "^10 || ^12 || >= 14" + "node_modules/hast-util-to-jsx-runtime/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dependencies": { + "@types/unist": "^3.0.0" }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "engines": { - "node": ">= 4" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/image-size": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.1.tgz", - "integrity": "sha512-VAwkvNSNGClRw9mDHhc5Efax8PLlsOGcUTh0T/LIriC8vPA3U5PdqXWqkz406MoYHMKW8Uf9gWr05T/rYB44kQ==", + "node_modules/hast-util-to-jsx-runtime/node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", "dependencies": { - "queue": "6.0.2" - }, - "bin": { - "image-size": "bin/image-size.js" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/immediate": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", - "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==" - }, - "node_modules/immer": { - "version": "9.0.12", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz", - "integrity": "sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA==", "funding": { "type": "opencollective", - "url": "https://opencollective.com/immer" + "url": "https://opencollective.com/unified" } }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "node_modules/hast-util-to-parse5": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz", + "integrity": "sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==", "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", - "engines": { - "node": ">=4" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/infima": { - "version": "0.2.0-alpha.37", - "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.37.tgz", - "integrity": "sha512-4GX7Baw+/lwS4PPW/UJNY89tWSvYG1DL6baKVdpK6mC593iRgMssxNtORMTFArLPJ/A/lzsGhRmx+z6MaMxj0Q==", - "engines": { - "node": ">=12" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "node_modules/hast-util-to-parse5/node_modules/@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "@types/unist": "*" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "node_modules/inline-style-parser": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", - "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" + "node_modules/hast-util-to-parse5/node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "engines": { - "node": ">= 0.10" + "node_modules/hast-util-to-parse5/node_modules/property-information": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.4.0.tgz", + "integrity": "sha512-9t5qARVofg2xQqKtytzt+lZ4d1Qvj8t5B8fEwXK6qOfgRLgH/b13QlgEyDh033NOS31nXeFbYv7CLUDG1CeifQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + "node_modules/hast-util-to-parse5/node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } }, - "node_modules/ipaddr.js": { + "node_modules/hast-util-to-parse5/node_modules/web-namespaces": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", - "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", - "engines": { - "node": ">= 10" + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-alphabetical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", - "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", + "node_modules/hast-util-to-parse5/node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-alphanumerical": { + "node_modules/hast-util-to-string": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", - "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", - "dependencies": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" - }, + "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-1.0.4.tgz", + "integrity": "sha512-eK0MxRX47AV2eZ+Lyr18DCpQgodvaS3fAQO2+b9Two9F5HEoRPhiUMNzoXArMJfZi2yieFzUBMRl3HNJ3Jus3w==", "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "node_modules/hast-util-to-text": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-2.0.1.tgz", + "integrity": "sha512-8nsgCARfs6VkwH2jJU9b8LNTuR4700na+0h3PqCaEk4MAnMDeu5P0tP8mjk9LLNGxIeQRLbiDbZVw6rku+pYsQ==", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "hast-util-is-element": "^1.0.0", + "repeat-string": "^1.0.0", + "unist-util-find-after": "^3.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" - }, - "node_modules/is-bigint": { + "node_modules/hast-util-whitespace": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dependencies": { - "has-bigints": "^1.0.1" - }, + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-1.0.4.tgz", + "integrity": "sha512-I5GTdSfhYfAPNztx2xJRQpG8cuDSNt599/7YUn7Gx/WxNMsG+a835k97TDkFgk123cwjfwINaZknkKkphx/f2A==", "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "node_modules/hastscript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", + "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^1.0.0", + "hast-util-parse-selector": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "engines": { - "node": ">=4" + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" } }, - "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node_modules/history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "dependencies": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" } }, - "node_modules/is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "node_modules/hogan.js": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/hogan.js/-/hogan.js-3.0.2.tgz", + "integrity": "sha1-TNnhq9QpQUbnZ55B14mHMrAse/0=", "dependencies": { - "ci-info": "^2.0.0" + "mkdirp": "0.3.0", + "nopt": "1.0.10" }, "bin": { - "is-ci": "bin.js" + "hulk": "bin/hulk" } }, - "node_modules/is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "react-is": "^16.7.0" } }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" } }, - "node_modules/is-decimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", - "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" } }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "node_modules/html-entities": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz", + "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" + }, + "node_modules/html-minifier-terser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", + "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "~5.3.2", + "commander": "^10.0.0", + "entities": "^4.4.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.15.1" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, "engines": { - "node": ">=0.10.0" + "node": "^14.13.1 || >=16.0.0" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "engines": { - "node": ">=0.10.0" + "node": ">=14" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", "engines": { "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dependencies": { - "is-extglob": "^2.1.1" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-hexadecimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", - "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "node_modules/html-webpack-plugin": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz", + "integrity": "sha512-6YrDKTuqaP/TquFH7h4srYWsZx+x6k6+FbsTm0ziCwGHDP78Unr1r9F/H4+sGmMbX08GQcJ+K64x55b+7VM/jg==", "dependencies": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=10.13.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "engines": { - "node": ">= 0.4" + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "webpack": "^5.20.0" } }, - "node_modules/is-npm": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", - "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", + "node_modules/html-webpack-plugin/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 12" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/html-webpack-plugin/node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, "engines": { - "node": ">=0.12.0" + "node": ">=12" } }, - "node_modules/is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "engines": { - "node": ">=8" + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" } }, - "node_modules/is-path-cwd": { + "node_modules/htmlparser2/node_modules/entities": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "engines": { - "node": ">=6" + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "engines": { - "node": ">=8" - } + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, "engines": { - "node": ">=8" + "node": ">= 0.8" } }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "dependencies": { - "isobject": "^3.0.1" + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8.0.0" } }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "node_modules/http-proxy-middleware": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" }, "engines": { - "node": ">= 0.4" + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "engines": { + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", + "node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10.19.0" } }, - "node_modules/is-root": { + "node_modules/human-signals": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", - "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "engines": { - "node": ">=6" + "node": ">=10.17.0" } }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", "engines": { - "node": ">=8" + "node": "^10 || ^12 || >= 14" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 4" } }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "node_modules/image-size": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.2.tgz", + "integrity": "sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==", "dependencies": { - "has-symbols": "^1.0.2" + "queue": "6.0.2" }, - "engines": { - "node": ">= 0.4" + "bin": { + "image-size": "bin/image-size.js" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=14.0.0" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + "node_modules/immediate": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", + "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==" }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "node_modules/immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dependencies": { - "call-bind": "^1.0.2" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-whitespace-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", - "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "engines": { + "node": ">=8" } }, - "node_modules/is-word-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz", - "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "engines": { + "node": ">=0.8.19" } }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dependencies": { - "is-docker": "^2.0.0" - }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "engines": { "node": ">=8" } }, - "node_modules/is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==" + "node_modules/infima": { + "version": "0.2.0-alpha.43", + "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.43.tgz", + "integrity": "sha512-2uw57LvUqW0rK/SWYnd/2rRfxNA5DDNOh33jxF7fy46VWoNhGxiUQyVZHbBMjQ33mQem0cjdDVwgWVAmlRfgyQ==", + "engines": { + "node": ">=12" + } }, - "node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "engines": { - "node": ">=0.10.0" - } + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, - "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "node_modules/inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" + }, + "node_modules/internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 0.4" } }, - "node_modules/jest-worker/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", "engines": { - "node": ">=8" + "node": ">= 0.10" } }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "dependencies": { - "has-flag": "^4.0.0" - }, + "loose-envify": "^1.0.0" + } + }, + "node_modules/ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", "engines": { - "node": ">=10" - }, + "node": ">= 10" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/joi": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.0.tgz", - "integrity": "sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw==", + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", "dependencies": { - "@hapi/hoek": "^9.0.0", - "@hapi/topo": "^5.0.0", - "@sideway/address": "^4.1.3", - "@sideway/formula": "^3.0.0", - "@sideway/pinpoint": "^2.0.0" + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "has-bigints": "^1.0.1" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "bin": { - "jsesc": "bin/jsesc" + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" - }, - "node_modules/json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "dependencies": { - "minimist": "^1.2.5" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" }, - "bin": { - "json5": "lib/cli.js" + "engines": { + "node": ">= 0.4" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "engines": { - "node": ">=6" + "node": ">=4" } }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dependencies": { - "universalify": "^2.0.0" + "node_modules/is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "engines": { + "node": ">= 0.4" }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jsx-ast-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz", - "integrity": "sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==", + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", "dependencies": { - "array-includes": "^3.1.3", - "object.assign": "^4.1.2" + "ci-info": "^3.2.0" }, - "engines": { - "node": ">=4.0" + "bin": { + "is-ci": "bin.js" } }, - "node_modules/keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "node_modules/is-core-module": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", "dependencies": { - "json-buffer": "3.0.0" + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "engines": { - "node": ">=6" + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/klona": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", - "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "bin": { + "is-docker": "cli.js" + }, "engines": { - "node": ">= 8" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", - "dependencies": { - "package-json": "^6.3.0" - }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "engines": { - "node": ">= 0.8.0" + "node": ">=8" } }, - "node_modules/lilconfig": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", - "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, "engines": { - "node": ">=10" + "node": ">=0.10.0" } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" - }, - "node_modules/loader-runner": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", - "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", - "engines": { - "node": ">=6.11.5" + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" }, "engines": { - "node": ">=4.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/loader-utils/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dependencies": { - "minimist": "^1.2.0" + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "engines": { + "node": ">= 0.4" }, - "bin": { - "json5": "lib/cli.js" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dependencies": { - "p-locate": "^4.1.0" - }, + "node_modules/is-npm": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", + "integrity": "sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==", "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash.assignin": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", - "integrity": "sha1-uo31+4QesKPoBEIysOJjqNxqKKI=" - }, - "node_modules/lodash.bind": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz", - "integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU=" - }, - "node_modules/lodash.curry": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz", - "integrity": "sha1-JI42By7ekGUB11lmIAqG2riyMXA=" - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" - }, - "node_modules/lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" - }, - "node_modules/lodash.filter": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz", - "integrity": "sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4=" - }, - "node_modules/lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" - }, - "node_modules/lodash.flow": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz", - "integrity": "sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o=" - }, - "node_modules/lodash.foreach": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", - "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=" - }, - "node_modules/lodash.map": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", - "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=" - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" - }, - "node_modules/lodash.pick": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", - "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=" - }, - "node_modules/lodash.reduce": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz", - "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs=" - }, - "node_modules/lodash.reject": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz", - "integrity": "sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU=" - }, - "node_modules/lodash.some": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", - "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=" - }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=" - }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "node_modules/is-number-object": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", + "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" + "has-tostringtag": "^1.0.0" }, - "bin": { - "loose-envify": "cli.js" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dependencies": { - "tslib": "^2.0.3" + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "engines": { + "node": ">=8" } }, - "node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/lunr": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==" + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "engines": { + "node": ">=8" + } }, - "node_modules/lunr-languages": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/lunr-languages/-/lunr-languages-1.9.0.tgz", - "integrity": "sha512-Be5vFuc8NAheOIjviCRms3ZqFFBlzns3u9DXpPSZvALetgnydAN0poV71pVLFn0keYy/s4VblMMkqewTLe+KPg==" + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "node_modules/is-reference": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", + "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", "dependencies": { - "sourcemap-codec": "^1.4.4" + "@types/estree": "*" } }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dependencies": { - "semver": "^6.0.0" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/markdown-escapes": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz", - "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==", + "node_modules/is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", + "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/mdast-squeeze-paragraphs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-squeeze-paragraphs/-/mdast-squeeze-paragraphs-4.0.0.tgz", - "integrity": "sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ==", - "dependencies": { - "unist-util-remove": "^2.0.0" + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mdast-util-definitions": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz", - "integrity": "sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==", + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "dependencies": { - "unist-util-visit": "^2.0.0" + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/mdast-util-to-hast": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-10.0.1.tgz", - "integrity": "sha512-BW3LM9SEMnjf4HXXVApZMt8gLQWVNXc3jryK0nJu/rOXPOnlkUjmdkDlmxMirpbU9ILncGFIwLH/ubnWBbcdgA==", + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dependencies": { - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "mdast-util-definitions": "^4.0.0", - "mdurl": "^1.0.0", - "unist-builder": "^2.0.0", - "unist-util-generated": "^1.0.0", - "unist-util-position": "^3.0.0", - "unist-util-visit": "^2.0.0" + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/mdast-util-to-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", - "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dependencies": { + "call-bind": "^1.0.2" + }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" - }, - "node_modules/mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dependencies": { + "is-docker": "^2.0.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=8" } }, - "node_modules/memfs": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.1.tgz", - "integrity": "sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw==", - "dependencies": { - "fs-monkey": "1.0.3" - }, + "node_modules/is-yarn-global": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.1.tgz", + "integrity": "sha512-/kppl+R+LO5VmhYSEWARUFjodS25D68gvj8W7z0I7OWhUla5xWu8KL6CtB2V0R6yqhnRgbcaREMr4EEM6htLPQ==", "engines": { - "node": ">= 4.0.0" + "node": ">=12" } }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" }, - "node_modules/merge-stream": { + "node_modules/isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "engines": { - "node": ">= 8" - } + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dependencies": { - "braces": "^3.0.1", + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", "picomatch": "^2.2.3" }, "engines": { - "node": ">=8.6" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" + "node_modules/jest-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/mime-db": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/mime-types": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "node_modules/jest-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "mime-db": "~1.33.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">= 0.6" + "node": ">=7.0.0" } }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "node_modules/jest-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "node_modules/jest-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/mini-css-extract-plugin": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.6.2.tgz", - "integrity": "sha512-WhDvO3SjGm40oV5y26GjMJYjd2UMqrLAGKy5YS2/3QKJy2F7jgynuHTir/tgUUOiNQu5saXHdc8reo7YuhhT4Q==", + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dependencies": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0", - "webpack-sources": "^1.1.0" + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" }, "engines": { "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.4.0 || ^5.0.0" } }, - "node_modules/mini-css-extract-plugin/node_modules/loader-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { - "node": ">=8.9.0" + "node": ">=8" } }, - "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "has-flag": "^4.0.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + "node_modules/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "bin": { + "jiti": "bin/jiti.js" + } }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/joi": { + "version": "17.11.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.11.0.tgz", + "integrity": "sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==", "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.3", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" } }, - "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - }, - "node_modules/mkdirp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", - "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", - "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", - "engines": { - "node": "*" - } - }, - "node_modules/mrmime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.0.tgz", - "integrity": "sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ==", - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, - "node_modules/multicast-dns": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", - "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dependencies": { - "dns-packet": "^1.3.1", - "thunky": "^1.0.2" + "argparse": "^1.0.7", + "esprima": "^4.0.0" }, "bin": { - "multicast-dns": "cli.js" + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" - }, - "node_modules/nanoid": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", - "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "bin": { - "nanoid": "bin/nanoid.cjs" + "jsesc": "bin/jsesc" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": ">=4" } }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "engines": { - "node": ">= 0.6" - } + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, - "node_modules/no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dependencies": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - } + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" }, - "node_modules/node-emoji": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", - "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", - "dependencies": { - "lodash": "^4.17.21" + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" } }, - "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" + "universalify": "^2.0.0" }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "node_modules/node-forge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.2.1.tgz", - "integrity": "sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w==", + "node_modules/jsx-ast-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz", + "integrity": "sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==", + "dependencies": { + "array-includes": "^3.1.3", + "object.assign": "^4.1.2" + }, "engines": { - "node": ">= 6.13.0" + "node": ">=4.0" } }, - "node_modules/node-releases": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", - "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==" - }, - "node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "*" + "json-buffer": "3.0.1" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "engines": { "node": ">=0.10.0" } }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "node_modules/latest-version": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", + "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", + "dependencies": { + "package-json": "^8.1.0" + }, "engines": { - "node": ">=10" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/not": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/not/-/not-0.1.0.tgz", - "integrity": "sha1-yWkcF0bFXc++VMvYvU/wQbwrUZ0=" - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "node_modules/launch-editor": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz", + "integrity": "sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ==", "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" + "picocolors": "^1.0.0", + "shell-quote": "^1.7.3" } }, - "node_modules/nprogress": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", - "integrity": "sha1-y480xTIT2JVyP8urkH6UIq28r7E=" + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "engines": { + "node": ">=6" + } }, - "node_modules/nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dependencies": { - "boolbase": "~1.0.0" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, - "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, + "node_modules/loader-runner": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", + "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=6.11.5" } }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, "engines": { - "node": ">= 0.4" + "node": ">=8.9.0" } }, - "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" + "p-locate": "^6.0.0" }, "engines": { - "node": ">= 0.4" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/object.entries": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", - "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.curry": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz", + "integrity": "sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "node_modules/lodash.flow": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz", + "integrity": "sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" + "js-tokens": "^3.0.0 || ^4.0.0" }, - "engines": { - "node": ">= 0.4" + "bin": { + "loose-envify": "cli.js" } }, - "node_modules/object.fromentries": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", - "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, + "tslib": "^2.0.3" + } + }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", "engines": { - "node": ">= 0.4" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/object.hasown": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.0.tgz", - "integrity": "sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg==", + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" + "yallist": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=10" } }, - "node_modules/object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==" + }, + "node_modules/lunr-languages": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/lunr-languages/-/lunr-languages-1.9.0.tgz", + "integrity": "sha512-Be5vFuc8NAheOIjviCRms3ZqFFBlzns3u9DXpPSZvALetgnydAN0poV71pVLFn0keYy/s4VblMMkqewTLe+KPg==" + }, + "node_modules/mark.js": { + "version": "8.11.1", + "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", + "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==" + }, + "node_modules/markdown-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", + "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", "engines": { - "node": ">= 0.4" + "node": ">=16" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + "node_modules/markdown-table": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", + "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } }, - "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "node_modules/mdast-util-directive": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.0.0.tgz", + "integrity": "sha512-JUpYOqKI4mM3sZcNxmF/ox04XYFFkNwr0CFlrQIkCwbvH0xzMCqkMqAde9wRd80VAhaUrwFwKm2nxretdT1h7Q==", "dependencies": { - "ee-first": "1.1.1" + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-visit-parents": "^6.0.0" }, - "engines": { - "node": ">= 0.8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "engines": { - "node": ">= 0.8" - } + "node_modules/mdast-util-directive/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "node_modules/mdast-util-directive/node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", "dependencies": { - "wrappy": "1" + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "node_modules/mdast-util-directive/node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/open": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", - "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.1.tgz", + "integrity": "sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==", "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", "engines": { "node": ">=12" }, @@ -10521,2321 +11230,2976 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/opener": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", - "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", - "bin": { - "opener": "bin/opener-bin.js" + "node_modules/mdast-util-find-and-replace/node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "node_modules/mdast-util-find-and-replace/node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" }, - "engines": { - "node": ">= 0.8.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", - "engines": { - "node": ">=6" + "node_modules/mdast-util-from-markdown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.0.tgz", + "integrity": "sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/mdast-util-from-markdown/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/mdast-util-from-markdown/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/mdast-util-from-markdown/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" + "@types/unist": "^3.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/mdast-util-frontmatter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", + "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==", "dependencies": { - "p-limit": "^2.2.0" + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "escape-string-regexp": "^5.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dependencies": { - "aggregate-error": "^3.0.0" - }, + "node_modules/mdast-util-frontmatter/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-retry": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.1.tgz", - "integrity": "sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA==", + "node_modules/mdast-util-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz", + "integrity": "sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==", "dependencies": { - "@types/retry": "^0.12.0", - "retry": "^0.13.1" + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "engines": { - "node": ">=6" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.0.tgz", + "integrity": "sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg==", "dependencies": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/package-json/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/param-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz", + "integrity": "sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==", "dependencies": { - "callsites": "^3.0.0" + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" }, - "engines": { - "node": ">=6" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/parse-entities": { + "node_modules/mdast-util-gfm-strikethrough": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", "dependencies": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/parse-numeric-range": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", - "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==" - }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" - }, - "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", "dependencies": { - "parse5": "^6.0.1" + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" + "node_modules/mdast-util-mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/pascal-case": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz", + "integrity": "sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw==", "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "engines": { - "node": ">=8" + "node_modules/mdast-util-mdx-expression/node_modules/@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "dependencies": { + "@types/unist": "*" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "engines": { - "node": ">=0.10.0" + "node_modules/mdast-util-mdx-jsx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.0.0.tgz", + "integrity": "sha512-XZuPPzQNBPAlaqsTTgRrcJnyFbSOBovSadFgbFu8SnuNgm+6Bdx1K+IWoitsmj6Lq6MNtI+ytOqwN70n//NaBA==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-remove-position": "^5.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "engines": { - "node": ">=8" + "node_modules/mdast-util-mdx-jsx/node_modules/@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "dependencies": { + "@types/unist": "*" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "node_modules/path-to-regexp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", - "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==" + "node_modules/mdast-util-mdx-jsx/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, - "node_modules/path-type": { + "node_modules/mdast-util-mdx-jsx/node_modules/unist-util-stringify-position": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "engines": { - "node": ">=8.6" + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dependencies": { + "@types/unist": "^3.0.0" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "node_modules/mdast-util-mdx-jsx/node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", "dependencies": { - "find-up": "^4.0.0" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/pkg-up": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", - "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", "dependencies": { - "find-up": "^3.0.0" + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/pkg-up/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "node_modules/mdast-util-mdxjs-esm/node_modules/@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" + "@types/unist": "*" } }, - "node_modules/pkg-up/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "node_modules/mdast-util-phrasing": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.0.0.tgz", + "integrity": "sha512-xadSsJayQIucJ9n053dfQwVu1kuXg7jCTdYsMK8rqzKZh52nLfSH/k0sAxE0u+pj/zKZX+o5wB+ML5mRayOxFA==", "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" }, - "engines": { - "node": ">=6" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/pkg-up/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "node_modules/mdast-util-phrasing/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/mdast-util-phrasing/node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", "dependencies": { - "p-limit": "^2.0.0" + "@types/unist": "^3.0.0" }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-up/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "engines": { - "node": ">=4" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/portfinder": { - "version": "1.0.28", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", - "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", + "node_modules/mdast-util-to-hast": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.0.2.tgz", + "integrity": "sha512-U5I+500EOOw9e3ZrclN3Is3fRpw8c19SMyNZlZ2IS+7vLsNzb2Om11VpIVOR+/0137GhZsFEF6YiKD5+0Hr2Og==", "dependencies": { - "async": "^2.6.2", - "debug": "^3.1.1", - "mkdirp": "^0.5.5" + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0" }, - "engines": { - "node": ">= 0.12.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/portfinder/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/mdast-util-to-hast/node_modules/@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", "dependencies": { - "ms": "^2.1.1" + "@types/unist": "*" } }, - "node_modules/portfinder/node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } + "node_modules/mdast-util-to-hast/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, - "node_modules/postcss": { - "version": "8.4.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz", - "integrity": "sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==", + "node_modules/mdast-util-to-hast/node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", "dependencies": { - "nanoid": "^3.2.0", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" + "@types/unist": "^3.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "url": "https://opencollective.com/unified" } }, - "node_modules/postcss-calc": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", - "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "node_modules/mdast-util-to-hast/node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", "dependencies": { - "postcss-selector-parser": "^6.0.9", - "postcss-value-parser": "^4.2.0" + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" }, - "peerDependencies": { - "postcss": "^8.2.2" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/postcss-colormin": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.2.5.tgz", - "integrity": "sha512-+X30aDaGYq81mFqwyPpnYInsZQnNpdxMX0ajlY7AExCexEFkPVV+KrO7kXwayqEWL2xwEbNQ4nUO0ZsRWGnevg==", + "node_modules/mdast-util-to-hast/node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", "dependencies": { - "browserslist": "^4.16.6", - "caniuse-api": "^3.0.0", - "colord": "^2.9.1", - "postcss-value-parser": "^4.2.0" + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/postcss-convert-values": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.0.4.tgz", - "integrity": "sha512-bugzSAyjIexdObovsPZu/sBCTHccImJxLyFgeV0MmNBm/Lw5h5XnjfML6gzEmJ3A6nyfCW7hb1JXzcsA4Zfbdw==", + "node_modules/mdast-util-to-markdown": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz", + "integrity": "sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==", "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/postcss-discard-comments": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.0.3.tgz", - "integrity": "sha512-6W5BemziRoqIdAKT+1QjM4bNcJAQ7z7zk073730NHg4cUXh3/rQHHj7pmYxUB9aGhuRhBiUf0pXvIHkRwhQP0Q==", - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } + "node_modules/mdast-util-to-markdown/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, - "node_modules/postcss-discard-duplicates": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.0.3.tgz", - "integrity": "sha512-vPtm1Mf+kp7iAENTG7jI1MN1lk+fBqL5y+qxyi4v3H+lzsXEdfS3dwUZD45KVhgzDEgduur8ycB4hMegyMTeRw==", - "engines": { - "node": "^10 || ^12 || >=14.0" + "node_modules/mdast-util-to-markdown/node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dependencies": { + "@types/unist": "^3.0.0" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/postcss-discard-empty": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.0.3.tgz", - "integrity": "sha512-xGJugpaXKakwKI7sSdZjUuN4V3zSzb2Y0LOlmTajFbNinEjTfVs9PFW2lmKBaC/E64WwYppfqLD03P8l9BuueA==", - "engines": { - "node": "^10 || ^12 || >=14.0" + "node_modules/mdast-util-to-markdown/node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/postcss-discard-overridden": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.0.4.tgz", - "integrity": "sha512-3j9QH0Qh1KkdxwiZOW82cId7zdwXVQv/gRXYDnwx5pBtR1sTkU4cXRK9lp5dSdiM0r0OICO/L8J6sV1/7m0kHg==", - "engines": { - "node": "^10 || ^12 || >=14.0" + "node_modules/mdast-util-to-markdown/node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/postcss-discard-unused": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-5.0.3.tgz", - "integrity": "sha512-WO6FJxL5fGnuE77ZbTcZ/nRZJ4+TOqNaqLBLWgkR4e+WdmHn77OHPyQmsRv7eOB2rLKL6tsq2bs1GwoKXD/++Q==", - "dependencies": { - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "node_modules/mdast-util-to-markdown/node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/postcss-loader": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", - "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", "dependencies": { - "cosmiconfig": "^7.0.0", - "klona": "^2.0.5", - "semver": "^7.3.5" - }, - "engines": { - "node": ">= 12.13.0" + "@types/mdast": "^4.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "postcss": "^7.0.0 || ^8.0.1", - "webpack": "^5.0.0" + "url": "https://opencollective.com/unified" } }, - "node_modules/postcss-merge-idents": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-5.0.3.tgz", - "integrity": "sha512-Z4LCzh2WzMn69KaS2FaJcrIeDQ170V13QHq+0hnBEFKJJkD+y5qndZ/bl3AhpddrSrXWIVR+xAwjmHQIJI2Eog==", - "dependencies": { - "cssnano-utils": "^3.0.2", - "postcss-value-parser": "^4.2.0" - }, + "node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "node": ">= 0.6" } }, - "node_modules/postcss-merge-longhand": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.0.6.tgz", - "integrity": "sha512-rkmoPwQO6ymJSmWsX6l2hHeEBQa7C4kJb9jyi5fZB1sE8nSCv7sqchoYPixRwX/yvLoZP2y6FA5kcjiByeJqDg==", + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", "dependencies": { - "postcss-value-parser": "^4.2.0", - "stylehacks": "^5.0.3" + "fs-monkey": "^1.0.4" }, "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "node": ">= 4.0.0" } }, - "node_modules/postcss-merge-rules": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.0.6.tgz", - "integrity": "sha512-nzJWJ9yXWp8AOEpn/HFAW72WKVGD2bsLiAmgw4hDchSij27bt6TF+sIK0cJUBAYT3SGcjtGGsOR89bwkkMuMgQ==", - "dependencies": { - "browserslist": "^4.16.6", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^3.0.2", - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-minify-font-values": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.0.4.tgz", - "integrity": "sha512-RN6q3tyuEesvyCYYFCRGJ41J1XFvgV+dvYGHr0CeHv8F00yILlN8Slf4t8XW4IghlfZYCeyRrANO6HpJ948ieA==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "node": ">= 8" } }, - "node_modules/postcss-minify-gradients": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.0.6.tgz", - "integrity": "sha512-E/dT6oVxB9nLGUTiY/rG5dX9taugv9cbLNTFad3dKxOO+BQg25Q/xo2z2ddG+ZB1CbkZYaVwx5blY8VC7R/43A==", - "dependencies": { - "colord": "^2.9.1", - "cssnano-utils": "^3.0.2", - "postcss-value-parser": "^4.2.0" - }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "node": ">= 0.6" } }, - "node_modules/postcss-minify-params": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.0.5.tgz", - "integrity": "sha512-YBNuq3Rz5LfLFNHb9wrvm6t859b8qIqfXsWeK7wROm3jSKNpO1Y5e8cOyBv6Acji15TgSrAwb3JkVNCqNyLvBg==", + "node_modules/micromark": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", + "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "browserslist": "^4.16.6", - "cssnano-utils": "^3.0.2", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.0.tgz", + "integrity": "sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-minify-selectors": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.1.3.tgz", - "integrity": "sha512-9RJfTiQEKA/kZhMaEXND893nBqmYQ8qYa/G+uPdVnXF6D/FzpfI6kwBtWEcHx5FqDbA79O9n6fQJfrIj6M8jvQ==", + "node_modules/micromark-core-commonmark/node_modules/micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-modules-extract-imports": { + "node_modules/micromark-core-commonmark/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-directive": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", - "engines": { - "node": "^10 || ^12 || >= 14" + "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-3.0.0.tgz", + "integrity": "sha512-61OI07qpQrERc+0wEysLHMvoiO3s2R56x5u7glHq2Yqq6EHbH4dW25G9GfDdGCDYqA21KE6DWgNSzxSwHc2hSg==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "parse-entities": "^4.0.0" }, - "peerDependencies": { - "postcss": "^8.1.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/postcss-modules-local-by-default": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", - "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "node_modules/micromark-extension-directive/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-modules-scope": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "node_modules/micromark-extension-directive/node_modules/micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "node_modules/micromark-extension-directive/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-frontmatter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz", + "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==", "dependencies": { - "icss-utils": "^5.0.0" + "fault": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/postcss-normalize-charset": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.0.3.tgz", - "integrity": "sha512-iKEplDBco9EfH7sx4ut7R2r/dwTnUqyfACf62Unc9UiyFuI7uUqZZtY+u+qp7g8Qszl/U28HIfcsI3pEABWFfA==", - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "node_modules/micromark-extension-frontmatter/node_modules/micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-normalize-display-values": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.0.3.tgz", - "integrity": "sha512-FIV5FY/qs4Ja32jiDb5mVj5iWBlS3N8tFcw2yg98+8MkRgyhtnBgSC0lxU+16AMHbjX5fbSJgw5AXLMolonuRQ==", + "node_modules/micromark-extension-frontmatter/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/postcss-normalize-positions": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.0.4.tgz", - "integrity": "sha512-qynirjBX0Lc73ROomZE3lzzmXXTu48/QiEzKgMeqh28+MfuHLsuqC9po4kj84igZqqFGovz8F8hf44hA3dPYmQ==", + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.0.0.tgz", + "integrity": "sha512-rTHfnpt/Q7dEAK1Y5ii0W8bhfJlVJFnJMHIPisfPK3gpVNuOP0VnRl96+YJ3RYWV/P4gFeQoGKNlT3RhuvpqAg==", "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/postcss-normalize-repeat-style": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.0.4.tgz", - "integrity": "sha512-Innt+wctD7YpfeDR7r5Ik6krdyppyAg2HBRpX88fo5AYzC1Ut/l3xaxACG0KsbX49cO2n5EB13clPwuYVt8cMA==", + "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-normalize-string": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.0.4.tgz", - "integrity": "sha512-Dfk42l0+A1CDnVpgE606ENvdmksttLynEqTQf5FL3XGQOyqxjbo25+pglCUvziicTxjtI2NLUR6KkxyUWEVubQ==", + "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.0.0.tgz", + "integrity": "sha512-6Rzu0CYRKDv3BfLAUnZsSlzx3ak6HAoI85KTiijuKIz5UxZxbUI+pD6oHgw+6UtQuiRwnGRhzMmPRv4smcz0fg==", "dependencies": { - "postcss-value-parser": "^4.2.0" + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/postcss-normalize-timing-functions": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.0.3.tgz", - "integrity": "sha512-QRfjvFh11moN4PYnJ7hia4uJXeFotyK3t2jjg8lM9mswleGsNw2Lm3I5wO+l4k1FzK96EFwEVn8X8Ojrp2gP4g==", + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-normalize-unicode": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.0.4.tgz", - "integrity": "sha512-W79Regn+a+eXTzB+oV/8XJ33s3pDyFTND2yDuUCo0Xa3QSy1HtNIfRVPXNubHxjhlqmMFADr3FSCHT84ITW3ig==", + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "browserslist": "^4.16.6", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-normalize-url": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.0.5.tgz", - "integrity": "sha512-Ws3tX+PcekYlXh+ycAt0wyzqGthkvVtZ9SZLutMVvHARxcpu4o7vvXcNoiNKyjKuWecnjS6HDI3fjBuDr5MQxQ==", + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-c3BR1ClMp5fxxmwP6AoOY2fXO9U8uFMKs4ADD66ahLTNcwzSCyRVU4k7LPV5Nxo/VJiR4TdzxRQY2v3qIUceCw==", "dependencies": { - "normalize-url": "^6.0.1", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/postcss-normalize-whitespace": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.4.tgz", - "integrity": "sha512-wsnuHolYZjMwWZJoTC9jeI2AcjA67v4UuidDrPN9RnX8KIZfE+r2Nd6XZRwHVwUiHmRvKQtxiqo64K+h8/imaw==", + "node_modules/micromark-extension-gfm-strikethrough/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.0.0.tgz", + "integrity": "sha512-PoHlhypg1ItIucOaHmKE8fbin3vTLpDOUg8KAr8gRCF1MOZI9Nquq2i/44wFvviM4WuxJzc3demT8Y3dkfvYrw==", "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/postcss-ordered-values": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.0.5.tgz", - "integrity": "sha512-mfY7lXpq+8bDEHfP+muqibDPhZ5eP9zgBEF9XRvoQgXcQe2Db3G1wcvjbnfjXG6wYsl+0UIjikqq4ym1V2jGMQ==", + "node_modules/micromark-extension-gfm-table/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "cssnano-utils": "^3.0.2", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-reduce-idents": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-5.0.3.tgz", - "integrity": "sha512-9bj9/Xhwiti0Z35kkguJX4G6yUYVw8S1kRLU4jFSCTEuHu4yJggf4rNUoVnT45lm/vU97Wd593CxspMDbHxy4w==", + "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "dependencies": { + "micromark-util-types": "^2.0.0" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/postcss-reduce-initial": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.0.3.tgz", - "integrity": "sha512-c88TkSnQ/Dnwgb4OZbKPOBbCaauwEjbECP5uAuFPOzQ+XdjNjRH7SG0dteXrpp1LlIFEKK76iUGgmw2V0xeieA==", + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.0.1.tgz", + "integrity": "sha512-cY5PzGcnULaN5O7T+cOzfMoHjBW7j+T9D2sucA5d/KbsBTPcYdebm9zUd9zzdgJGCwahV+/W78Z3nbulBYVbTw==", "dependencies": { - "browserslist": "^4.16.6", - "caniuse-api": "^3.0.0" + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/postcss-reduce-transforms": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.0.4.tgz", - "integrity": "sha512-VIJB9SFSaL8B/B7AXb7KHL6/GNNbbCHslgdzS9UDfBZYIA2nx8NLY7iD/BXFSO/1sRUILzBTfHCoW5inP37C5g==", + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-selector-parser": { - "version": "6.0.9", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", - "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-sort-media-queries": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-4.2.1.tgz", - "integrity": "sha512-9VYekQalFZ3sdgcTjXMa0dDjsfBVHXlraYJEMiOJ/2iMmI2JGCMavP16z3kWOaRu8NSaJCTgVpB/IVpH5yT9YQ==", + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-mdx-expression": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.0.tgz", + "integrity": "sha512-sI0nwhUDz97xyzqJAbHQhp5TfaxEvZZZ2JDqUo+7NvyIYG6BZ5CPPqj2ogUoPJlmXHBnyZUzISg9+oUmU6tUjQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "sort-css-media-queries": "2.0.4" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "postcss": "^8.4.4" + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-svgo": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.0.4.tgz", - "integrity": "sha512-yDKHvULbnZtIrRqhZoA+rxreWpee28JSRH/gy9727u0UCgtpv1M/9WEWY3xySlFa0zQJcqf6oCBJPR5NwkmYpg==", + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "postcss-value-parser": "^4.2.0", - "svgo": "^2.7.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-unique-selectors": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.0.4.tgz", - "integrity": "sha512-5ampwoSDJCxDPoANBIlMgoBcYUHnhaiuLYJR5pj1DLnYQvMRVyFuTA5C3Bvt+aHtiqWpJkD/lXT50Vo1D0ZsAQ==", + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] }, - "node_modules/postcss-zindex": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-5.0.2.tgz", - "integrity": "sha512-KPQFjQu73H35HLHmE8Wv31ygfQoucxD52oRm4FPFv1emYhFMzUQdF8adaXCevFLIHPRp2rRYfbaDiEqZ4YjVtw==", - "engines": { - "node": "^10 || ^12 || >=14.0" + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.0.tgz", + "integrity": "sha512-uvhhss8OGuzR4/N17L1JwvmJIpPhAd8oByMawEKx6NVdBCbesjH4t+vjEp3ZXft9DwvlKSD07fCeI44/N0Vf2w==", + "dependencies": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "engines": { - "node": ">= 0.8.0" - } + "node_modules/micromark-extension-mdx-jsx/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, - "node_modules/prepend-http": { + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-factory-space": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", - "engines": { - "node": ">=4" - } - }, - "node_modules/prettier": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", - "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/pretty-error": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", - "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "lodash": "^4.17.20", - "renderkid": "^3.0.0" - } - }, - "node_modules/pretty-time": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", - "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/prismjs": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz", - "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==", - "engines": { - "node": ">=6" + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/process-nextick-args": { + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-util-character": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "engines": { - "node": ">=0.4.0" + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/promise": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-mdx-jsx/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", "dependencies": { - "asap": "~2.0.3" + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "node_modules/micromark-extension-mdx-jsx/node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" }, - "engines": { - "node": ">= 6" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/property-information": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", - "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", "dependencies": { - "xtend": "^4.0.0" + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" }, - "engines": { - "node": ">= 0.10" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/proxy-addr/node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "engines": { - "node": ">= 0.10" - } + "node_modules/micromark-extension-mdxjs-esm/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "node_modules/micromark-extension-mdxjs-esm/node_modules/micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + "node_modules/micromark-extension-mdxjs-esm/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] }, - "node_modules/pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "node_modules/micromark-extension-mdxjs-esm/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", "dependencies": { - "escape-goat": "^2.0.0" + "@types/unist": "^3.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/pure-color": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/pure-color/-/pure-color-1.3.0.tgz", - "integrity": "sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4=" - }, - "node_modules/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", - "engines": { - "node": ">=0.6" + "node_modules/micromark-extension-mdxjs-esm/node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "node_modules/micromark-extension-mdxjs/node_modules/acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "bin": { + "acorn": "bin/acorn" + }, "engines": { - "node": ">=0.4.x" + "node": ">=0.4.0" } }, - "node_modules/queue": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", - "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "node_modules/micromark-factory-destination": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", + "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "inherits": "~2.0.3" + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "node_modules/micromark-factory-destination/node_modules/micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/feross" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "patreon", - "url": "https://www.patreon.com/feross" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "consulting", - "url": "https://feross.org/support" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ] }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "node_modules/micromark-factory-label": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", + "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "safe-buffer": "^5.1.0" + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/range-parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", - "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", - "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", + "node_modules/micromark-factory-label/node_modules/micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "bytes": "3.1.2", - "http-errors": "1.8.1", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/raw-body/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "engines": { - "node": ">= 0.8" - } + "node_modules/micromark-factory-label/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "node_modules/micromark-factory-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.1.tgz", + "integrity": "sha512-F0ccWIUHRLRrYp5TC9ZYXmZo+p2AM13ggbsW4T0b5CRKP8KHVRB8t4pwtBgTxtjRmwrK0Irwm7vs2JOZabHZfg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" } }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "engines": { - "node": ">=0.10.0" - } + "node_modules/micromark-factory-mdx-expression/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, - "node_modules/react": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", - "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" - }, - "engines": { - "node": ">=0.10.0" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/react-base16-styling": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.6.0.tgz", - "integrity": "sha1-7yFW1mz0E5aVyKFniGy2nqZgeSw=", - "dependencies": { - "base16": "^1.0.0", - "lodash.curry": "^4.0.1", - "lodash.flow": "^3.3.0", - "pure-color": "^1.2.0" - } + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] }, - "node_modules/react-dev-utils": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.0.tgz", - "integrity": "sha512-xBQkitdxozPxt1YZ9O1097EJiVpwHr9FoAuEVURCKV0Av8NBERovJauzP7bo1ThvuhZ4shsQ1AJiu4vQpoT1AQ==", + "node_modules/micromark-factory-mdx-expression/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", "dependencies": { - "@babel/code-frame": "^7.16.0", - "address": "^1.1.2", - "browserslist": "^4.18.1", - "chalk": "^4.1.2", - "cross-spawn": "^7.0.3", - "detect-port-alt": "^1.1.6", - "escape-string-regexp": "^4.0.0", - "filesize": "^8.0.6", - "find-up": "^5.0.0", - "fork-ts-checker-webpack-plugin": "^6.5.0", - "global-modules": "^2.0.0", - "globby": "^11.0.4", - "gzip-size": "^6.0.0", - "immer": "^9.0.7", - "is-root": "^2.1.0", - "loader-utils": "^3.2.0", - "open": "^8.4.0", - "pkg-up": "^3.1.0", - "prompts": "^2.4.2", - "react-error-overlay": "^6.0.10", - "recursive-readdir": "^2.2.2", - "shell-quote": "^1.7.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" + "@types/unist": "^3.0.0" }, - "engines": { - "node": ">=14" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/react-dev-utils/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/micromark-factory-mdx-expression/node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/react-dev-utils/node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "engines": { - "node": ">=8" + "node_modules/micromark-factory-space": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz", + "integrity": "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" } }, - "node_modules/react-dev-utils/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/micromark-factory-space/node_modules/micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-factory-title": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", + "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/react-dev-utils/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/micromark-factory-title/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/react-dev-utils/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/react-dev-utils/node_modules/cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "node_modules/micromark-factory-title/node_modules/micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - }, - "engines": { - "node": ">=8" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/react-dev-utils/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "node_modules/micromark-factory-title/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] }, - "node_modules/react-dev-utils/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/micromark-factory-whitespace": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", + "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/react-dev-utils/node_modules/fork-ts-checker-webpack-plugin": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.0.tgz", - "integrity": "sha512-cS178Y+xxtIjEUorcHddKS7yCMlrDPV31mt47blKKRfMd70Kxu5xruAFE2o9sDY6wVC5deuob/u/alD04YYHnw==", - "dependencies": { - "@babel/code-frame": "^7.8.3", - "@types/json-schema": "^7.0.5", - "chalk": "^4.1.0", - "chokidar": "^3.4.2", - "cosmiconfig": "^6.0.0", - "deepmerge": "^4.2.2", - "fs-extra": "^9.0.0", - "glob": "^7.1.6", - "memfs": "^3.1.2", - "minimatch": "^3.0.4", - "schema-utils": "2.7.0", - "semver": "^7.3.2", - "tapable": "^1.0.0" - }, - "engines": { - "node": ">=10", - "yarn": ">=1.0.0" - }, - "peerDependencies": { - "eslint": ">= 6", - "typescript": ">= 2.7", - "vue-template-compiler": "*", - "webpack": ">= 4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true + "node_modules/micromark-factory-whitespace/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, - "vue-template-compiler": { - "optional": true + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/react-dev-utils/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "node_modules/micromark-factory-whitespace/node_modules/micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/react-dev-utils/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "node_modules/micromark-factory-whitespace/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-character": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz", + "integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" } }, - "node_modules/react-dev-utils/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } + "node_modules/micromark-util-character/node_modules/micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] }, - "node_modules/react-dev-utils/node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "engines": { - "node": ">= 4" + "node_modules/micromark-util-chunked": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", + "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/react-dev-utils/node_modules/loader-utils": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.0.tgz", - "integrity": "sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ==", - "engines": { - "node": ">= 12.13.0" - } + "node_modules/micromark-util-chunked/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] }, - "node_modules/react-dev-utils/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/micromark-util-classify-character": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", + "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/react-dev-utils/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/micromark-util-classify-character/node_modules/micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/react-dev-utils/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/micromark-util-classify-character/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", + "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/react-dev-utils/node_modules/schema-utils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", - "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", + "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "@types/json-schema": "^7.0.4", - "ajv": "^6.12.2", - "ajv-keywords": "^3.4.1" - }, - "engines": { - "node": ">= 8.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/react-dev-utils/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } + "node_modules/micromark-util-decode-numeric-character-reference/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] }, - "node_modules/react-dev-utils/node_modules/tapable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", - "engines": { - "node": ">=6" + "node_modules/micromark-util-decode-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", + "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/react-dom": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", - "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", + "node_modules/micromark-util-decode-string/node_modules/micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.19.1" - }, - "peerDependencies": { - "react": "^16.14.0" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/react-error-overlay": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz", - "integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA==" - }, - "node_modules/react-fast-compare": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", - "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" - }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/react-lifecycles-compat": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + "node_modules/micromark-util-decode-string/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } + "node_modules/micromark-util-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", + "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "node_modules/micromark-util-events-to-acorn": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.2.tgz", + "integrity": "sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" } }, - "node_modules/reading-time": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz", - "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==" + "node_modules/micromark-util-events-to-acorn/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, - "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dependencies": { - "resolve": "^1.1.6" - }, - "engines": { - "node": ">= 0.10" - } + "node_modules/micromark-util-events-to-acorn/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] }, - "node_modules/recursive-readdir": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", - "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", + "node_modules/micromark-util-events-to-acorn/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", "dependencies": { - "minimatch": "3.0.4" + "@types/unist": "^3.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/recursive-readdir/node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "node_modules/micromark-util-events-to-acorn/node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", "dependencies": { - "brace-expansion": "^1.1.7" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" }, - "engines": { - "node": "*" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", + "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] }, - "node_modules/regenerate-unicode-properties": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", - "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", + "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + "node_modules/micromark-util-normalize-identifier/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] }, - "node_modules/regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "node_modules/micromark-util-resolve-all": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", + "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "@babel/runtime": "^7.8.4" + "micromark-util-types": "^2.0.0" } }, - "node_modules/regexp.prototype.flags": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz", - "integrity": "sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==", + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", + "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/regexpu-core": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", - "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", + "node_modules/micromark-util-sanitize-uri/node_modules/micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.0.1", - "regjsgen": "^0.6.0", - "regjsparser": "^0.8.2", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "node_modules/micromark-util-sanitize-uri/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.0.tgz", + "integrity": "sha512-vc93L1t+gpR3p8jxeVdaYlbV2jTYteDje19rNSS/H5dlhxUYll5Fy6vJ2cDwP8RnsXi818yGty1ayP55y3W6fg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "rc": "^1.2.8" - }, - "engines": { - "node": ">=6.0.0" + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "node_modules/micromark-util-subtokenize/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-symbol": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz", + "integrity": "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", + "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "rc": "^1.2.8" - }, - "engines": { - "node": ">=8" + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/regjsgen": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", - "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==" + "node_modules/micromark/node_modules/micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } }, - "node_modules/regjsparser": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", - "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", + "node_modules/micromark/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dependencies": { - "jsesc": "~0.5.0" + "braces": "^3.0.3", + "picomatch": "^2.3.1" }, - "bin": { - "regjsparser": "bin/parser" + "engines": { + "node": ">=8.6" } }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "bin": { - "jsesc": "bin/jsesc" - } - }, - "node_modules/rehype-parse": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-7.0.1.tgz", - "integrity": "sha512-fOiR9a9xH+Le19i4fGzIEowAbwG7idy2Jzs4mOrFWBSJ0sNUgy0ev871dwWnbOo371SjgjG4pwzrbgSVrKxecw==", - "dependencies": { - "hast-util-from-parse5": "^6.0.0", - "parse5": "^6.0.0" + "mime": "cli.js" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=4" } }, - "node_modules/relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "node_modules/mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", "engines": { - "node": ">= 0.10" + "node": ">= 0.6" } }, - "node_modules/remark-admonitions": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/remark-admonitions/-/remark-admonitions-1.2.1.tgz", - "integrity": "sha512-Ji6p68VDvD+H1oS95Fdx9Ar5WA2wcDA4kwrrhVU7fGctC6+d3uiMICu7w7/2Xld+lnU7/gi+432+rRbup5S8ow==", + "node_modules/mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", "dependencies": { - "rehype-parse": "^6.0.2", - "unified": "^8.4.2", - "unist-util-visit": "^2.0.1" + "mime-db": "~1.33.0" + }, + "engines": { + "node": ">= 0.6" } }, - "node_modules/remark-admonitions/node_modules/hast-util-from-parse5": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-5.0.3.tgz", - "integrity": "sha512-gOc8UB99F6eWVWFtM9jUikjN7QkWxB3nY0df5Z0Zq1/Nkwl5V4hAAsl0tmwlgWl/1shlTF8DnNYLO8X6wRV9pA==", - "dependencies": { - "ccount": "^1.0.3", - "hastscript": "^5.0.0", - "property-information": "^5.0.0", - "web-namespaces": "^1.1.2", - "xtend": "^4.0.1" + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/remark-admonitions/node_modules/hastscript": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-5.1.2.tgz", - "integrity": "sha512-WlztFuK+Lrvi3EggsqOkQ52rKbxkXL3RwB6t5lwoa8QLMemoWfBuL43eDrwOamJyR7uKQKdmKYaBH1NZBiIRrQ==", + "node_modules/mini-css-extract-plugin": { + "version": "2.7.6", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz", + "integrity": "sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw==", "dependencies": { - "comma-separated-tokens": "^1.0.0", - "hast-util-parse-selector": "^2.0.0", - "property-information": "^5.0.0", - "space-separated-tokens": "^1.0.0" + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" } }, - "node_modules/remark-admonitions/node_modules/parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" }, - "node_modules/remark-admonitions/node_modules/rehype-parse": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-6.0.2.tgz", - "integrity": "sha512-0S3CpvpTAgGmnz8kiCyFLGuW5yA4OQhyNTm/nwPopZ7+PI11WnGl1TTWTGv/2hPEe/g2jRLlhVVSsoDH8waRug==", + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dependencies": { - "hast-util-from-parse5": "^5.0.0", - "parse5": "^5.0.0", - "xtend": "^4.0.0" + "brace-expansion": "^1.1.7" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": "*" } }, - "node_modules/remark-admonitions/node_modules/unified": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/unified/-/unified-8.4.2.tgz", - "integrity": "sha512-JCrmN13jI4+h9UAyKEoGcDZV+i1E7BLFuG7OsaDvTXI5P0qhHX+vZO/kOhz9jn8HGENDKbwSeB0nVOg4gVStGA==", - "dependencies": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "is-plain-obj": "^2.0.0", - "trough": "^1.0.0", - "vfile": "^4.0.0" - }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/remark-emoji": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/remark-emoji/-/remark-emoji-2.2.0.tgz", - "integrity": "sha512-P3cj9s5ggsUvWw5fS2uzCHJMGuXYRb0NnZqYlNecewXt8QBU9n5vW3DUUKOhepS8F9CwdMx9B8a3i7pqFWAI5w==", - "dependencies": { - "emoticon": "^3.2.0", - "node-emoji": "^1.10.0", - "unist-util-visit": "^2.0.3" + "node_modules/mkdirp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", + "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "engines": { + "node": "*" } }, - "node_modules/remark-footnotes": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/remark-footnotes/-/remark-footnotes-2.0.0.tgz", - "integrity": "sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "node_modules/mrmime": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", + "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", + "engines": { + "node": ">=10" } }, - "node_modules/remark-mdx": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-1.6.22.tgz", - "integrity": "sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ==", + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "dependencies": { - "@babel/core": "7.12.9", - "@babel/helper-plugin-utils": "7.10.4", - "@babel/plugin-proposal-object-rest-spread": "7.12.1", - "@babel/plugin-syntax-jsx": "7.12.1", - "@mdx-js/util": "1.6.22", - "is-alphabetical": "1.0.4", - "remark-parse": "8.0.3", - "unified": "9.2.0" + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "bin": { + "multicast-dns": "cli.js" } }, - "node_modules/remark-mdx-remove-exports": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/remark-mdx-remove-exports/-/remark-mdx-remove-exports-1.6.22.tgz", - "integrity": "sha512-7g2uiTmTGfz5QyVb+toeX25frbk1Y6yd03RXGPtqx0+DVh86Gb7MkNYbk7H2X27zdZ3CQv1W/JqlFO0Oo8IxVA==", - "dependencies": { - "unist-util-remove": "2.0.0" + "node_modules/nanoid": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/remark-mdx-remove-exports/node_modules/unist-util-remove": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-2.0.0.tgz", - "integrity": "sha512-HwwWyNHKkeg/eXRnE11IpzY8JT55JNM1YCwwU9YNCnfzk6s8GhPXrVBBZWiwLeATJbI7euvoGSzcy9M29UeW3g==", + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", "dependencies": { - "unist-util-is": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "lower-case": "^2.0.2", + "tslib": "^2.0.3" } }, - "node_modules/remark-mdx-remove-imports": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/remark-mdx-remove-imports/-/remark-mdx-remove-imports-1.6.22.tgz", - "integrity": "sha512-lmjAXD8Ltw0TsvBzb45S+Dxx7LTJAtDaMneMAv8LAUIPEyYoKkmGbmVsiF0/pY6mhM1Q16swCmu1TN+ie/vn/A==", + "node_modules/node-emoji": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.1.3.tgz", + "integrity": "sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA==", "dependencies": { - "unist-util-remove": "2.0.0" + "@sindresorhus/is": "^4.6.0", + "char-regex": "^1.0.2", + "emojilib": "^2.4.0", + "skin-tone": "^2.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=18" } }, - "node_modules/remark-mdx-remove-imports/node_modules/unist-util-remove": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-2.0.0.tgz", - "integrity": "sha512-HwwWyNHKkeg/eXRnE11IpzY8JT55JNM1YCwwU9YNCnfzk6s8GhPXrVBBZWiwLeATJbI7euvoGSzcy9M29UeW3g==", - "dependencies": { - "unist-util-is": "^4.0.0" + "node_modules/node-emoji/node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "engines": { + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sindresorhus/is?sponsor=1" } }, - "node_modules/remark-mdx/node_modules/@babel/core": { - "version": "7.12.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", - "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.5", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.5", - "@babel/parser": "^7.12.7", - "@babel/template": "^7.12.7", - "@babel/traverse": "^7.12.9", - "@babel/types": "^7.12.7", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" }, "engines": { - "node": ">=6.9.0" + "node": "4.x || >=6.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } } }, - "node_modules/remark-mdx/node_modules/@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" }, - "node_modules/remark-mdx/node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", - "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-transform-parameters": "^7.12.1" + "abbrev": "1" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" } }, - "node_modules/remark-mdx/node_modules/@babel/plugin-syntax-jsx": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", - "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/remark-mdx/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "bin": { - "semver": "bin/semver" + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/remark-mdx/node_modules/unified": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz", - "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", - "dependencies": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^2.0.0", - "trough": "^1.0.0", - "vfile": "^4.0.0" + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "engines": { + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/remark-parse": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-8.0.3.tgz", - "integrity": "sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==", - "dependencies": { - "ccount": "^1.0.0", - "collapse-white-space": "^1.0.2", - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-whitespace-character": "^1.0.0", - "is-word-character": "^1.0.0", - "markdown-escapes": "^1.0.0", - "parse-entities": "^2.0.0", - "repeat-string": "^1.5.4", - "state-toggle": "^1.0.0", - "trim": "0.0.1", - "trim-trailing-lines": "^1.0.0", - "unherit": "^1.0.4", - "unist-util-remove-position": "^2.0.0", - "vfile-location": "^3.0.0", - "xtend": "^4.0.1" + "node_modules/not": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/not/-/not-0.1.0.tgz", + "integrity": "sha1-yWkcF0bFXc++VMvYvU/wQbwrUZ0=" + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dependencies": { + "path-key": "^3.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=8" } }, - "node_modules/remark-squeeze-paragraphs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/remark-squeeze-paragraphs/-/remark-squeeze-paragraphs-4.0.0.tgz", - "integrity": "sha512-8qRqmL9F4nuLPIgl92XUuxI3pFxize+F1H0e/W3llTk0UsjJaj01+RrirkMw7P21RKe4X6goQhYRSvNWX+70Rw==", + "node_modules/nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==" + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dependencies": { - "mdast-squeeze-paragraphs": "^4.0.0" + "boolbase": "^1.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/renderkid": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", - "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", - "dependencies": { - "css-select": "^4.1.3", - "dom-converter": "^0.2.0", - "htmlparser2": "^6.1.0", - "lodash": "^4.17.21", - "strip-ansi": "^6.0.1" + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/renderkid/node_modules/css-select": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", - "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^5.1.0", - "domhandler": "^4.3.0", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "engines": { + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/fb55" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/renderkid/node_modules/css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" + "node": ">= 0.4" } }, - "node_modules/renderkid/node_modules/dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/renderkid/node_modules/domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] + "node_modules/object.entries": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + } }, - "node_modules/renderkid/node_modules/domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", + "node_modules/object.fromentries": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", "dependencies": { - "domelementtype": "^2.2.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" }, "engines": { - "node": ">= 4" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/renderkid/node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "node_modules/object.hasown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.0.tgz", + "integrity": "sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg==", "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" }, "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/renderkid/node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "node_modules/object.values": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + }, "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/renderkid/node_modules/htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" }, - "node_modules/renderkid/node_modules/nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dependencies": { - "boolbase": "^1.0.0" + "ee-first": "1.1.1" }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" + "engines": { + "node": ">= 0.8" } }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "engines": { - "node": ">=0.10" + "node": ">= 0.8" } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "engines": { - "node": ">=0.10.0" + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" } }, - "node_modules/require-like": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", - "integrity": "sha1-rW8wwTvs15cBDEaK+ndcDAprR/o=", + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, "engines": { - "node": "*" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" - }, - "node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", "dependencies": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" }, - "bin": { - "resolve": "bin/resolve" + "engines": { + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "engines": { - "node": ">=4" + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "bin": { + "opener": "bin/opener-bin.js" } }, - "node_modules/resolve-pathname": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", - "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" - }, - "node_modules/responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", "dependencies": { - "lowercase-keys": "^1.0.0" - } - }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, "engines": { - "node": ">= 4" + "node": ">= 0.8.0" } }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" + "node": ">=12.20" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dependencies": { - "glob": "^7.1.3" + "p-try": "^2.0.0" }, - "bin": { - "rimraf": "bin.js" + "engines": { + "node": ">=6" }, "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rtl-detect": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/rtl-detect/-/rtl-detect-1.0.4.tgz", - "integrity": "sha512-EBR4I2VDSSYr7PkBmFy04uhycIpDKp+21p/jARYXlCSjQksTBQcJ0HFUPOO79EPPH5JS6VAhiIQbycf0O3JAxQ==" - }, - "node_modules/rtlcss": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-3.5.0.tgz", - "integrity": "sha512-wzgMaMFHQTnyi9YOwsx9LjOxYXJPzS8sYnFaKm6R5ysvTkwzHiB0vxnbHwchHQT65PTdBjDG21/kQBWI7q9O7A==", - "dependencies": { - "find-up": "^5.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.3.11", - "strip-json-comments": "^3.1.1" - }, - "bin": { - "rtlcss": "bin/rtlcss.js" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/rtlcss/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "p-limit": "^4.0.0" }, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/rtlcss/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/p-locate/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", "dependencies": { - "p-locate": "^5.0.0" + "yocto-queue": "^1.0.0" }, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/rtlcss/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dependencies": { - "yocto-queue": "^0.1.0" - }, + "node_modules/p-locate/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", "engines": { - "node": ">=10" + "node": ">=12.20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/rtlcss/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", "dependencies": { - "p-limit": "^3.0.2" + "aggregate-error": "^3.0.0" }, "engines": { "node": ">=10" @@ -12844,744 +14208,679 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rxjs": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.4.tgz", - "integrity": "sha512-h5M3Hk78r6wAheJF0a5YahB1yRQKCsZ4MsGdZ5O9ETbVtjPcScGfrMmoOq7EBsCRzd4BDkvDJ7ogP8Sz5tTFiQ==", + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", "dependencies": { - "tslib": "^2.1.0" + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" } }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "node_modules/scheduler": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", - "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" } }, - "node_modules/schema-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "node_modules/package-json": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", + "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", "dependencies": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" }, "engines": { - "node": ">= 8.9.0" + "node": ">=14.16" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/section-matter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", - "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", "dependencies": { - "extend-shallow": "^2.0.1", - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=4" + "dot-case": "^3.0.4", + "tslib": "^2.0.3" } }, - "node_modules/select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=" - }, - "node_modules/selfsigned": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.0.0.tgz", - "integrity": "sha512-cUdFiCbKoa1mZ6osuJs2uDHrs0k0oprsKveFiiaBKCNq3SYyb5gs2HxhQyDNLCmL51ZZThqi4YNDpCK6GOP1iQ==", + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dependencies": { - "node-forge": "^1.2.0" + "callsites": "^3.0.0" }, "engines": { - "node": ">=10" + "node": ">=6" } }, - "node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/parse-entities": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz", + "integrity": "sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "@types/unist": "^2.0.0", + "character-entities": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" }, - "engines": { - "node": ">=10" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dependencies": { - "semver": "^6.3.0" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/semver-diff/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" + "node_modules/parse-numeric-range": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", + "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==" + }, + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dependencies": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dependencies": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "1.8.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "domelementtype": "^2.3.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", "dependencies": { - "ms": "2.0.0" + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/send/node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dependencies": { - "randombytes": "^2.1.0" + "node": ">= 0.8" } }, - "node_modules/serve-handler": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.3.tgz", - "integrity": "sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==", + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", "dependencies": { - "bytes": "3.0.0", - "content-disposition": "0.5.2", - "fast-url-parser": "1.1.3", - "mime-types": "2.1.18", - "minimatch": "3.0.4", - "path-is-inside": "1.0.2", - "path-to-regexp": "2.2.1", - "range-parser": "1.2.0" + "no-case": "^3.0.4", + "tslib": "^2.0.3" } }, - "node_modules/serve-handler/node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "engines": { - "node": "*" + "node": ">=8" } }, - "node_modules/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", - "dependencies": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "engines": { - "node": ">= 0.8.0" + "node": ">=0.10.0" } }, - "node_modules/serve-index/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" }, - "node_modules/serve-index/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "engines": { - "node": ">= 0.6" + "node": ">=8" } }, - "node_modules/serve-index/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, - "node_modules/serve-index/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "node_modules/path-to-regexp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", + "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==" }, - "node_modules/serve-index/node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } }, - "node_modules/serve-static": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", - "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "node_modules/periscopic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", + "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.2" - }, - "engines": { - "node": ">= 0.8.0" + "@types/estree": "^1.0.0", + "estree-walker": "^3.0.0", + "is-reference": "^3.0.0" } }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", "dependencies": { - "kind-of": "^6.0.2" + "find-up": "^6.3.0" }, "engines": { - "node": ">=8" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", "dependencies": { - "shebang-regex": "^3.0.0" + "find-up": "^3.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/shebang-regex": { + "node_modules/pkg-up/node_modules/find-up": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/shell-quote": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", - "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==" - }, - "node_modules/shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "node_modules/pkg-up/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dependencies": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - }, - "bin": { - "shjs": "bin/shjs" + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" }, "engines": { - "node": ">=4" + "node": ">=6" } }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "node_modules/pkg-up/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "p-limit": "^2.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=6" } }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "node_modules/sirv": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz", - "integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==", - "dependencies": { - "@polka/url": "^1.0.0-next.20", - "mrmime": "^1.0.0", - "totalist": "^1.0.0" - }, + "node_modules/pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", "engines": { - "node": ">= 10" + "node": ">=4" } }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" - }, - "node_modules/sitemap": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-7.1.1.tgz", - "integrity": "sha512-mK3aFtjz4VdJN0igpIJrinf3EO8U8mxOPsTBzSsy06UtjZQJ3YY3o3Xa7zSc5nMqcMrRwlChHZ18Kxg0caiPBg==", + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "dependencies": { - "@types/node": "^17.0.5", - "@types/sax": "^1.2.1", - "arg": "^5.0.0", - "sax": "^1.2.4" - }, - "bin": { - "sitemap": "dist/cli.js" + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" }, "engines": { - "node": ">=12.0.0", - "npm": ">=5.6.0" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "engines": { - "node": ">=8" + "node": "^10 || ^12 || >=14" } }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "node_modules/postcss-calc": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", + "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" + "peerDependencies": { + "postcss": "^8.2.2" } }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/postcss-colormin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", + "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", "dependencies": { - "color-convert": "^2.0.1" + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=8" + "node": "^10 || ^12 || >=14.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/postcss-convert-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", + "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", "dependencies": { - "color-name": "~1.1.4" + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=7.0.0" + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/sockjs": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", - "dependencies": { - "faye-websocket": "^0.11.3", - "uuid": "^8.3.2", - "websocket-driver": "^0.7.4" + "node_modules/postcss-discard-comments": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", + "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/sort-css-media-queries": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.0.4.tgz", - "integrity": "sha512-PAIsEK/XupCQwitjv7XxoMvYhT7EAfyzI3hsy/MyDgTvc+Ft55ctdkctJLOy6cQejaIC+zjpUL4djFVm2ivOOw==", + "node_modules/postcss-discard-duplicates": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", + "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", "engines": { - "node": ">= 6.3.0" + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" - }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "node_modules/postcss-discard-empty": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", + "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", "engines": { - "node": ">=0.10.0" + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "node_modules/postcss-discard-overridden": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", + "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", "engines": { - "node": ">=0.10.0" + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "node_modules/postcss-discard-unused": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-5.1.0.tgz", + "integrity": "sha512-KwLWymI9hbwXmJa0dkrzpRbSJEh0vVUd7r8t0yOGPcfKzyJJxFM8kLyC5Ev9avji6nY95pOp1W6HqIrfT+0VGw==", "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/postcss-loader": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.3.tgz", + "integrity": "sha512-YgO/yhtevGO/vJePCQmTxiaEwER94LABZN0ZMT4A0vsak9TpO+RvKRs7EmJ8peIlB9xfXCsS7M8LjqncsUZ5HA==", + "dependencies": { + "cosmiconfig": "^8.2.0", + "jiti": "^1.18.2", + "semver": "^7.3.8" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + "node_modules/postcss-loader/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, - "node_modules/space-separated-tokens": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", - "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", + "node_modules/postcss-loader/node_modules/cosmiconfig": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz", + "integrity": "sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==", + "dependencies": { + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/d-fischer" } }, - "node_modules/spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "node_modules/postcss-loader/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dependencies": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" + "argparse": "^2.0.1" }, - "engines": { - "node": ">=6.0.0" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "node_modules/postcss-merge-idents": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-5.1.1.tgz", + "integrity": "sha512-pCijL1TREiCoog5nQp7wUe+TUonA2tC2sQ54UGeMmryK3UFGIYKqDyjnqd6RcuI4znFn9hWSLNN8xKE/vWcUQw==", "dependencies": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "node_modules/stable": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" - }, - "node_modules/state-toggle": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz", - "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/std-env": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.0.1.tgz", - "integrity": "sha512-mC1Ps9l77/97qeOZc+HrOL7TIaOboHqMZ24dGVQrlxFcpPpfCHpH+qfUT7Dz+6mlG8+JPA1KfBQo19iC/+Ngcw==" - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "node_modules/postcss-merge-longhand": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", + "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", "dependencies": { - "safe-buffer": "~5.2.0" + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/postcss-merge-rules": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", + "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.1.0", + "postcss-selector-parser": "^6.0.5" }, "engines": { - "node": ">=8" + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/string.prototype.matchall": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz", - "integrity": "sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg==", + "node_modules/postcss-minify-font-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", + "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.3.1", - "side-channel": "^1.0.4" + "postcss-value-parser": "^4.2.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "node_modules/postcss-minify-gradients": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", + "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "colord": "^2.9.1", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "node_modules/postcss-minify-params": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", + "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "node_modules/postcss-minify-selectors": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", + "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", "dependencies": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" + "postcss-selector-parser": "^6.0.5" }, "engines": { - "node": ">=4" + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/stringify-object/node_modules/is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", "engines": { - "node": ">=0.10.0" + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", + "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", "dependencies": { - "ansi-regex": "^5.0.1" + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" }, "engines": { - "node": ">=8" + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/strip-bom-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", - "integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=", + "node_modules/postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, "engines": { - "node": ">=0.10.0" + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dependencies": { + "icss-utils": "^5.0.0" + }, "engines": { - "node": ">=6" + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "node_modules/postcss-normalize-charset": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", + "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", "engines": { - "node": ">=8" + "node": "^10 || ^12 || >=14.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/style-to-object": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", - "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==", + "node_modules/postcss-normalize-display-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", + "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", "dependencies": { - "inline-style-parser": "0.1.1" + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/stylehacks": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.0.3.tgz", - "integrity": "sha512-ENcUdpf4yO0E1rubu8rkxI+JGQk4CgjchynZ4bDBJDfqdy+uhTRSWb8/F3Jtu+Bw5MW45Po3/aQGeIyyxgQtxg==", + "node_modules/postcss-normalize-positions": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", + "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", "dependencies": { - "browserslist": "^4.16.6", - "postcss-selector-parser": "^6.0.4" + "postcss-value-parser": "^4.2.0" }, "engines": { "node": "^10 || ^12 || >=14.0" @@ -13590,751 +14889,563 @@ "postcss": "^8.2.15" } }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/postcss-normalize-repeat-style": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", + "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", "dependencies": { - "has-flag": "^3.0.0" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=4" + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "node_modules/postcss-normalize-string": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", + "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, "engines": { - "node": ">= 0.4" + "node": "^10 || ^12 || >=14.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/svg-parser": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", - "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" - }, - "node_modules/svgo": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", - "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "node_modules/postcss-normalize-timing-functions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", + "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", "dependencies": { - "@trysound/sax": "0.2.0", - "commander": "^7.2.0", - "css-select": "^4.1.3", - "css-tree": "^1.1.3", - "csso": "^4.2.0", - "picocolors": "^1.0.0", - "stable": "^0.1.8" - }, - "bin": { - "svgo": "bin/svgo" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/svgo/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "engines": { - "node": ">= 10" + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/svgo/node_modules/css-select": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", - "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", + "node_modules/postcss-normalize-unicode": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", + "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^5.1.0", - "domhandler": "^4.3.0", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" }, - "funding": { - "url": "https://github.com/sponsors/fb55" + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/svgo/node_modules/css-what": { + "node_modules/postcss-normalize-url": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", + "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "dependencies": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, "engines": { - "node": ">= 6" + "node": "^10 || ^12 || >=14.0" }, - "funding": { - "url": "https://github.com/sponsors/fb55" + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/svgo/node_modules/dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "node_modules/postcss-normalize-whitespace": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", + "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" + "postcss-value-parser": "^4.2.0" }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/svgo/node_modules/domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/svgo/node_modules/domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", + "node_modules/postcss-ordered-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", + "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", "dependencies": { - "domelementtype": "^2.2.0" + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">= 4" + "node": "^10 || ^12 || >=14.0" }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/svgo/node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "node_modules/postcss-reduce-idents": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-5.2.0.tgz", + "integrity": "sha512-BTrLjICoSB6gxbc58D5mdBK8OhXRDqud/zodYfdSi52qvDHdMwk+9kB9xsM8yJThH/sZU5A6QVSmMmaN001gIg==", "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" + "postcss-value-parser": "^4.2.0" }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/svgo/node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/svgo/node_modules/nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "node_modules/postcss-reduce-initial": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", + "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", "dependencies": { - "boolbase": "^1.0.0" + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/table": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", - "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", + "node_modules/postcss-reduce-transforms": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", + "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=10.0.0" + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/table/node_modules/ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "node_modules/postcss-selector-parser": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "engines": { - "node": ">=6" + "node": ">=4" } }, - "node_modules/terser": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.11.0.tgz", - "integrity": "sha512-uCA9DLanzzWSsN1UirKwylhhRz3aKPInlfmpGfw8VN6jHsAtu8HJtIpeeHHK23rxnE/cDc+yvmq5wqkIC6Kn0A==", + "node_modules/postcss-sort-media-queries": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-4.4.1.tgz", + "integrity": "sha512-QDESFzDDGKgpiIh4GYXsSy6sek2yAwQx1JASl5AxBtU1Lq2JfKBljIPNdil989NcSKRQX1ToiaKphImtBuhXWw==", "dependencies": { - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map": "~0.7.2", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" + "sort-css-media-queries": "2.1.0" }, "engines": { - "node": ">=10" + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.4.16" } }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", - "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", + "node_modules/postcss-svgo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", + "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", "dependencies": { - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1", - "terser": "^5.7.2" + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" }, "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "node": "^10 || ^12 || >=14.0" }, "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } + "postcss": "^8.2.15" } }, - "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "node_modules/postcss-unique-selectors": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", + "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "postcss-selector-parser": "^6.0.5" }, "engines": { - "node": ">= 10.13.0" + "node": "^10 || ^12 || >=14.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/terser-webpack-plugin/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "node_modules/postcss-zindex": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-5.1.0.tgz", + "integrity": "sha512-fgFMf0OtVSBR1va1JNHYgMxYk73yhn/qb4uQDq1DLGYolz8gHCyr/sesEuGUaYs58E3ZJRcpoGuPVoB7Meiq9A==", "engines": { - "node": ">=0.10.0" + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/terser/node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "bin": { - "acorn": "bin/acorn" - }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "engines": { - "node": ">=0.4.0" + "node": ">= 0.8.0" } }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "node_modules/terser/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "node_modules/prettier": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", + "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", + "bin": { + "prettier": "bin-prettier.js" + }, "engines": { - "node": ">= 8" + "node": ">=10.13.0" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } }, - "node_modules/thunky": { + "node_modules/pretty-time": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" - }, - "node_modules/timsort": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", - "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" - }, - "node_modules/tiny-invariant": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz", - "integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg==" + "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", + "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==", + "engines": { + "node": ">=4" + } }, - "node_modules/tiny-warning": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", - "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + "node_modules/prism-react-renderer": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-2.3.0.tgz", + "integrity": "sha512-UYRg2TkVIaI6tRVHC5OJ4/BxqPUxJkJvq/odLT/ykpt1zGYXooNperUxQcCvi87LyRnR4nCh81ceOA+e7nrydg==", + "dependencies": { + "@types/prismjs": "^1.26.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.0.0" + } }, - "node_modules/to-fast-properties": { + "node_modules/prism-react-renderer/node_modules/clsx": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", "engines": { - "node": ">=4" + "node": ">=6" } }, - "node_modules/to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", "engines": { "node": ">=6" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "engines": { - "node": ">=8.0" + "node": ">=0.4.0" } }, - "node_modules/to-vfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/to-vfile/-/to-vfile-6.1.0.tgz", - "integrity": "sha512-BxX8EkCxOAZe+D/ToHdDsJcVI4HqQfmw0tCkp31zf3dNP/XWIAjU4CmeuSwsSoOzOTqHPOL0KUzyZqJplkD0Qw==", + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", "dependencies": { - "is-buffer": "^2.0.0", - "vfile": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "engines": { - "node": ">=0.6" + "asap": "~2.0.3" } }, - "node_modules/totalist": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", - "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==", + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, "engines": { - "node": ">=6" + "node": ">= 6" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" - }, - "node_modules/trim": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", - "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=" - }, - "node_modules/trim-trailing-lines": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz", - "integrity": "sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" } }, - "node_modules/trough": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", - "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==", + "node_modules/property-information": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", + "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", + "dependencies": { + "xtend": "^4.0.0" + }, "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==" }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dependencies": { - "prelude-ls": "^1.2.1" + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 0.10" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.10" } }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "node_modules/pupa": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz", + "integrity": "sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==", "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "escape-goat": "^4.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/type-is/node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", - "engines": { - "node": ">= 0.6" - } + "node_modules/pure-color": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/pure-color/-/pure-color-1.3.0.tgz", + "integrity": "sha512-QFADYnsVoBMw1srW7OVKEYjG+MbIa49s54w1MA1EDY6r2r/sTcKKYqRX1f4GYvnXP7eN/Pe9HFcX+hwzmrXRHA==" }, - "node_modules/type-is/node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dependencies": { - "mime-db": "1.51.0" + "side-channel": "^1.0.6" }, "engines": { - "node": ">= 0.6" + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/typescript": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", - "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" + "inherits": "~2.0.3" } }, - "node_modules/ua-parser-js": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz", - "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==", + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "funding": [ { - "type": "opencollective", - "url": "https://opencollective.com/ua-parser-js" + "type": "github", + "url": "https://github.com/sponsors/feross" }, { - "type": "paypal", - "url": "https://paypal.me/faisalman" + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" } - ], + ] + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", "engines": { - "node": "*" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/unherit": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz", - "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==", + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dependencies": { - "inherits": "^2.0.0", - "xtend": "^4.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "safe-buffer": "^5.1.0" } }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "node_modules/range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", "engines": { - "node": ">=4" + "node": ">= 0.6" } }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" }, "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", - "engines": { - "node": ">=4" - } - }, - "node_modules/unified": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.2.tgz", - "integrity": "sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ==", - "dependencies": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^2.0.0", - "trough": "^1.0.0", - "vfile": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "node": ">= 0.8" } }, - "node_modules/unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dependencies": { - "crypto-random-string": "^2.0.0" - }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "engines": { - "node": ">=8" - } - }, - "node_modules/unist-builder": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-2.0.3.tgz", - "integrity": "sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-find-after": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-3.0.0.tgz", - "integrity": "sha512-ojlBqfsBftYXExNu3+hHLfJQ/X1jYY/9vdm4yZWjIbf0VuWF6CRufci1ZyoD/wV2TYMKxXUoNuoqwy+CkgzAiQ==", - "dependencies": { - "unist-util-is": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-generated": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.6.tgz", - "integrity": "sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-is": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", - "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-position": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.1.0.tgz", - "integrity": "sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "node": ">= 0.8" } }, - "node_modules/unist-util-remove": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-2.1.0.tgz", - "integrity": "sha512-J8NYPyBm4baYLdCbjmf1bhPu45Cr1MWTm77qd9istEkzWpnN6O9tMsEbB2JhNnBCqGENRqEWomQ+He6au0B27Q==", + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dependencies": { - "unist-util-is": "^4.0.0" + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "bin": { + "rc": "cli.js" } }, - "node_modules/unist-util-remove-position": { + "node_modules/rc/node_modules/strip-json-comments": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz", - "integrity": "sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==", - "dependencies": { - "unist-util-visit": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-stringify-position": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", - "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", - "dependencies": { - "@types/unist": "^2.0.2" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", - "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", - "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^4.0.0", - "unist-util-visit-parents": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/unist-util-visit-parents": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", - "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^4.0.0" + "loose-envify": "^1.1.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "engines": { - "node": ">= 10.0.0" + "node": ">=0.10.0" } }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "engines": { - "node": ">= 0.8" + "node_modules/react-base16-styling": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.6.0.tgz", + "integrity": "sha512-yvh/7CArceR/jNATXOKDlvTnPKPmGZz7zsenQ3jUwLzHkNUR0CvY3yGYJbWJ/nnxsL8Sgmt5cO3/SILVuPO6TQ==", + "dependencies": { + "base16": "^1.0.0", + "lodash.curry": "^4.0.1", + "lodash.flow": "^3.3.0", + "pure-color": "^1.2.0" } }, - "node_modules/update-notifier": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", - "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", + "node_modules/react-dev-utils": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", + "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", "dependencies": { - "boxen": "^5.0.0", - "chalk": "^4.1.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.4.0", - "is-npm": "^5.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.1.0", - "pupa": "^2.1.1", - "semver": "^7.3.4", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" + "@babel/code-frame": "^7.16.0", + "address": "^1.1.2", + "browserslist": "^4.18.1", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "detect-port-alt": "^1.1.6", + "escape-string-regexp": "^4.0.0", + "filesize": "^8.0.6", + "find-up": "^5.0.0", + "fork-ts-checker-webpack-plugin": "^6.5.0", + "global-modules": "^2.0.0", + "globby": "^11.0.4", + "gzip-size": "^6.0.0", + "immer": "^9.0.7", + "is-root": "^2.1.0", + "loader-utils": "^3.2.0", + "open": "^8.4.0", + "pkg-up": "^3.1.0", + "prompts": "^2.4.2", + "react-error-overlay": "^6.0.11", + "recursive-readdir": "^2.2.2", + "shell-quote": "^1.7.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/yeoman/update-notifier?sponsor=1" + "node": ">=14" } }, - "node_modules/update-notifier/node_modules/ansi-styles": { + "node_modules/react-dev-utils/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", @@ -14348,7 +15459,7 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/update-notifier/node_modules/chalk": { + "node_modules/react-dev-utils/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -14363,7 +15474,7 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/update-notifier/node_modules/color-convert": { + "node_modules/react-dev-utils/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", @@ -14374,6467 +15485,10024 @@ "node": ">=7.0.0" } }, - "node_modules/update-notifier/node_modules/color-name": { + "node_modules/react-dev-utils/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/update-notifier/node_modules/has-flag": { + "node_modules/react-dev-utils/node_modules/escape-string-regexp": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/update-notifier/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/react-dev-utils/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dependencies": { - "has-flag": "^4.0.0" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/uri-js/node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "node_modules/react-dev-utils/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "dependencies": { - "punycode": "1.3.2", - "querystring": "0.2.0" + "node_modules/react-dev-utils/node_modules/loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "engines": { + "node": ">= 12.13.0" } }, - "node_modules/url-loader": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", - "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "node_modules/react-dev-utils/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dependencies": { - "loader-utils": "^2.0.0", - "mime-types": "^2.1.27", - "schema-utils": "^3.0.0" + "p-locate": "^5.0.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "file-loader": "*", - "webpack": "^4.0.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "file-loader": { - "optional": true - } + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/url-loader/node_modules/loader-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "node_modules/react-dev-utils/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/url-loader/node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/url-loader/node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", - "dependencies": { - "mime-db": "1.51.0" + "node": ">=10" }, - "engines": { - "node": ">= 0.6" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/url-loader/node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "node_modules/react-dev-utils/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "p-limit": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "node_modules/react-dev-utils/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { - "prepend-http": "^2.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/url/node_modules/punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "node_modules/utila": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=" - }, - "node_modules/utility-types": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", - "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==", - "engines": { - "node": ">= 4" + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" } }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "engines": { - "node": ">= 0.4.0" - } + "node_modules/react-error-overlay": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", + "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" + }, + "node_modules/react-helmet-async": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.3.0.tgz", + "integrity": "sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "invariant": "^2.2.4", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.2.0", + "shallowequal": "^1.1.0" + }, + "peerDependencies": { + "react": "^16.6.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0" } }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==" + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, - "node_modules/value-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", - "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "engines": { - "node": ">= 0.8" + "node_modules/react-loadable": { + "name": "@docusaurus/react-loadable", + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", + "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", + "dependencies": { + "@types/react": "*", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": "*" } }, - "node_modules/vfile": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", - "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", + "node_modules/react-router": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", + "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", "dependencies": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^2.0.0", - "vfile-message": "^2.0.0" + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "peerDependencies": { + "react": ">=15" } }, - "node_modules/vfile-location": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.2.0.tgz", - "integrity": "sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "node_modules/react-router-dom": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz", + "integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==", + "dependencies": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.3.4", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" } }, - "node_modules/vfile-message": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", - "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "node_modules/react-router/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" + }, + "node_modules/react-router/node_modules/path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "isarray": "0.0.1" } }, - "node_modules/wait-on": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz", - "integrity": "sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==", + "node_modules/react-textarea-autosize": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.3.4.tgz", + "integrity": "sha512-CdtmP8Dc19xL8/R6sWvtknD/eCXkQr30dtvC4VmGInhRsfF8X/ihXCq6+9l9qbxmKRiq407/7z5fxE7cVWQNgQ==", "dependencies": { - "axios": "^0.25.0", - "joi": "^17.6.0", - "lodash": "^4.17.21", - "minimist": "^1.2.5", - "rxjs": "^7.5.4" - }, - "bin": { - "wait-on": "bin/wait-on" + "@babel/runtime": "^7.10.2", + "use-composed-ref": "^1.3.0", + "use-latest": "^1.2.1" }, "engines": { - "node": ">=10.0.0" + "node": ">=10" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, - "node_modules/watchpack": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", - "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "engines": { - "node": ">=10.13.0" + "node": ">= 6" } }, - "node_modules/wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dependencies": { - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/web-namespaces": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.4.tgz", - "integrity": "sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" } }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + "node_modules/reading-time": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz", + "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==" }, - "node_modules/webpack": { - "version": "5.69.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.69.1.tgz", - "integrity": "sha512-+VyvOSJXZMT2V5vLzOnDuMz5GxEqLk7hKWQ56YxPW/PQRUuKimPqmEIJOx8jHYeyo65pKbapbW464mvsKbaj4A==", - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.8.3", - "es-module-lexer": "^0.9.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", - "webpack-sources": "^3.2.3" - }, - "bin": { - "webpack": "bin/webpack.js" + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dependencies": { + "resolve": "^1.1.6" }, "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } + "node": ">= 0.10" } }, - "node_modules/webpack-bundle-analyzer": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.5.0.tgz", - "integrity": "sha512-GUMZlM3SKwS8Z+CKeIFx7CVoHn3dXFcUAjT/dcZQQmfSZGvitPfMob2ipjai7ovFFqPvTqkEZ/leL4O0YOdAYQ==", + "node_modules/recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", "dependencies": { - "acorn": "^8.0.4", - "acorn-walk": "^8.0.0", - "chalk": "^4.1.0", - "commander": "^7.2.0", - "gzip-size": "^6.0.0", - "lodash": "^4.17.20", - "opener": "^1.5.2", - "sirv": "^1.0.7", - "ws": "^7.3.1" - }, - "bin": { - "webpack-bundle-analyzer": "lib/bin/analyzer.js" + "minimatch": "^3.0.5" }, "engines": { - "node": ">= 10.13.0" + "node": ">=6.0.0" } }, - "node_modules/webpack-bundle-analyzer/node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "bin": { - "acorn": "bin/acorn" + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dependencies": { + "regenerate": "^1.4.2" }, "engines": { - "node": ">=0.4.0" + "node": ">=4" } }, - "node_modules/webpack-bundle-analyzer/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", "dependencies": { - "color-convert": "^2.0.1" + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz", + "integrity": "sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/webpack-bundle-analyzer/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/webpack-bundle-analyzer/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", "dependencies": { - "color-name": "~1.1.4" + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=4" } }, - "node_modules/webpack-bundle-analyzer/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/webpack-bundle-analyzer/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "node_modules/registry-auth-token": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", + "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", + "dependencies": { + "@pnpm/npm-conf": "^2.1.0" + }, "engines": { - "node": ">= 10" + "node": ">=14" } }, - "node_modules/webpack-bundle-analyzer/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "dependencies": { + "rc": "1.2.8" + }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/webpack-bundle-analyzer/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", "dependencies": { - "has-flag": "^4.0.0" + "jsesc": "~0.5.0" }, - "engines": { - "node": ">=8" + "bin": { + "regjsparser": "bin/parser" } }, - "node_modules/webpack-dev-middleware": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.1.tgz", - "integrity": "sha512-81EujCKkyles2wphtdrnPg/QqegC/AtqNH//mQkBYSMqwFVCQrxM6ktB2O/SPlZy7LqeEfTbV3cZARGQz6umhg==", + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/rehype-parse": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-7.0.1.tgz", + "integrity": "sha512-fOiR9a9xH+Le19i4fGzIEowAbwG7idy2Jzs4mOrFWBSJ0sNUgy0ev871dwWnbOo371SjgjG4pwzrbgSVrKxecw==", "dependencies": { - "colorette": "^2.0.10", - "memfs": "^3.4.1", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 12.13.0" + "hast-util-from-parse5": "^6.0.0", + "parse5": "^6.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "url": "https://opencollective.com/unified" } }, - "node_modules/webpack-dev-middleware/node_modules/ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "node_modules/rehype-raw/node_modules/@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" + "@types/unist": "*" } }, - "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "node_modules/webpack-dev-middleware/node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", - "engines": { - "node": ">= 0.6" - } + "node_modules/rehype-raw/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, - "node_modules/webpack-dev-middleware/node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "node_modules/rehype-raw/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", "dependencies": { - "mime-db": "1.51.0" + "@types/unist": "^3.0.0" }, - "engines": { - "node": ">= 0.6" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/webpack-dev-middleware/node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/webpack-dev-middleware/node_modules/schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "node_modules/rehype-raw/node_modules/vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - }, - "engines": { - "node": ">= 12.13.0" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://opencollective.com/unified" } }, - "node_modules/webpack-dev-server": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.7.4.tgz", - "integrity": "sha512-nfdsb02Zi2qzkNmgtZjkrMOcXnYZ6FLKcQwpxT7MvmHKc+oTtDsBju8j+NMyAygZ9GW1jMEUpy3itHtqgEhe1A==", + "node_modules/rehype-raw/node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", "dependencies": { - "@types/bonjour": "^3.5.9", - "@types/connect-history-api-fallback": "^1.3.5", - "@types/express": "^4.17.13", - "@types/serve-index": "^1.9.1", - "@types/sockjs": "^0.3.33", - "@types/ws": "^8.2.2", - "ansi-html-community": "^0.0.8", - "bonjour": "^3.5.0", - "chokidar": "^3.5.3", - "colorette": "^2.0.10", - "compression": "^1.7.4", - "connect-history-api-fallback": "^1.6.0", - "default-gateway": "^6.0.3", - "del": "^6.0.0", - "express": "^4.17.1", - "graceful-fs": "^4.2.6", - "html-entities": "^2.3.2", - "http-proxy-middleware": "^2.0.0", - "ipaddr.js": "^2.0.1", - "open": "^8.0.9", - "p-retry": "^4.5.0", - "portfinder": "^1.0.28", - "schema-utils": "^4.0.0", - "selfsigned": "^2.0.0", - "serve-index": "^1.9.1", - "sockjs": "^0.3.21", - "spdy": "^4.0.2", - "strip-ansi": "^7.0.0", - "webpack-dev-middleware": "^5.3.1", - "ws": "^8.4.2" - }, - "bin": { - "webpack-dev-server": "bin/webpack-dev-server.js" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", "engines": { - "node": ">= 12.13.0" - }, - "peerDependencies": { - "webpack": "^4.37.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } + "node": ">= 0.10" } }, - "node_modules/webpack-dev-server/node_modules/ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "node_modules/remark-directive": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remark-directive/-/remark-directive-3.0.0.tgz", + "integrity": "sha512-l1UyWJ6Eg1VPU7Hm/9tt0zKtReJQNOA4+iDMAxTyZNWnJnFlbS/7zhiel/rogTLQ2vMYwDzSJa4BiVNqGlqIMA==", "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "@types/mdast": "^4.0.0", + "mdast-util-directive": "^3.0.0", + "micromark-extension-directive": "^3.0.0", + "unified": "^11.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/webpack-dev-server/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" + "node_modules/remark-directive/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/remark-directive/node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/webpack-dev-server/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "node_modules/remark-directive/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + "node_modules/remark-directive/node_modules/trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } }, - "node_modules/webpack-dev-server/node_modules/schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "node_modules/remark-directive/node_modules/unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - }, - "engines": { - "node": ">= 12.13.0" + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://opencollective.com/unified" } }, - "node_modules/webpack-dev-server/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "node_modules/remark-directive/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" + "@types/unist": "^3.0.0" }, "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/webpack-dev-server/node_modules/ws": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "node_modules/remark-directive/node_modules/vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/webpack-merge": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "node_modules/remark-directive/node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", "dependencies": { - "clone-deep": "^4.0.1", - "wildcard": "^2.0.0" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" }, - "engines": { - "node": ">=10.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "node_modules/remark-emoji": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-emoji/-/remark-emoji-4.0.1.tgz", + "integrity": "sha512-fHdvsTR1dHkWKev9eNyhTo4EFwbUvJ8ka9SgeWkMPYFX4WoI7ViVBms3PjlQYgw5TLvNQso3GUB/b/8t3yo+dg==", "dependencies": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - } - }, - "node_modules/webpack-sources/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "bin": { - "acorn": "bin/acorn" + "@types/mdast": "^4.0.2", + "emoticon": "^4.0.1", + "mdast-util-find-and-replace": "^3.0.1", + "node-emoji": "^2.1.0", + "unified": "^11.0.4" }, "engines": { - "node": ">=0.4.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/webpack/node_modules/acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "peerDependencies": { - "acorn": "^8" + "node_modules/remark-emoji/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/remark-emoji/node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/webpack/node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "node_modules/remark-emoji/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "engines": { - "node": ">= 0.6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/webpack/node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", - "dependencies": { - "mime-db": "1.51.0" - }, - "engines": { - "node": ">= 0.6" + "node_modules/remark-emoji/node_modules/trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/webpack/node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "node_modules/remark-emoji/node_modules/unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/webpack/node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "engines": { - "node": ">=10.13.0" + "url": "https://opencollective.com/unified" } }, - "node_modules/webpackbar": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-5.0.2.tgz", - "integrity": "sha512-BmFJo7veBDgQzfWXl/wwYXr/VFus0614qZ8i9znqcl9fnEdiVkdbi0TedLQ6xAK92HZHDJ0QmyQ0fmuZPAgCYQ==", + "node_modules/remark-emoji/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", "dependencies": { - "chalk": "^4.1.0", - "consola": "^2.15.3", - "pretty-time": "^1.1.0", - "std-env": "^3.0.1" - }, - "engines": { - "node": ">=12" + "@types/unist": "^3.0.0" }, - "peerDependencies": { - "webpack": "3 || 4 || 5" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/webpackbar/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/remark-emoji/node_modules/vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/webpackbar/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/remark-emoji/node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/webpackbar/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/remark-frontmatter": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-5.0.0.tgz", + "integrity": "sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==", "dependencies": { - "color-name": "~1.1.4" + "@types/mdast": "^4.0.0", + "mdast-util-frontmatter": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0", + "unified": "^11.0.0" }, - "engines": { - "node": ">=7.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/webpackbar/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "node_modules/remark-frontmatter/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, - "node_modules/webpackbar/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" + "node_modules/remark-frontmatter/node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/webpackbar/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, + "node_modules/remark-frontmatter/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "engines": { - "node": ">=8" - } - }, - "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" + "node": ">=12" }, - "engines": { - "node": ">=0.8.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "engines": { - "node": ">=0.8.0" + "node_modules/remark-frontmatter/node_modules/trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "node_modules/remark-frontmatter/node_modules/unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/remark-frontmatter/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "@types/unist": "^3.0.0" }, - "engines": { - "node": ">= 8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "node_modules/remark-frontmatter/node_modules/vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "node_modules/remark-frontmatter/node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "node_modules/remark-gfm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz", + "integrity": "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==", "dependencies": { - "string-width": "^4.0.0" + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/wildcard": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", - "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==" + "node_modules/remark-gfm/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "engines": { - "node": ">=0.10.0" + "node_modules/remark-gfm/node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, + "node_modules/remark-gfm/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, + "node_modules/remark-gfm/node_modules/trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/remark-gfm/node_modules/unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", "dependencies": { - "color-name": "~1.1.4" + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" }, - "engines": { - "node": ">=7.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "node_modules/remark-gfm/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "node_modules/remark-gfm/node_modules/vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", - "engines": { - "node": ">=8" + "node_modules/remark-gfm/node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/xml-js": { - "version": "1.6.11", - "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", - "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "node_modules/remark-mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.0.0.tgz", + "integrity": "sha512-O7yfjuC6ra3NHPbRVxfflafAj3LTwx3b73aBvkEFU5z4PsD6FD4vrqJAkE5iNGLz71GdjXfgRqm3SQ0h0VuE7g==", "dependencies": { - "sax": "^1.2.4" + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" }, - "bin": { - "xml-js": "bin/cli.js" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "engines": { - "node": ">=0.4" + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "node_modules/remark-parse/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "engines": { - "node": ">= 6" + "node_modules/remark-parse/node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "node_modules/remark-parse/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/zwitch": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", - "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", + "node_modules/remark-parse/node_modules/trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } - } - }, - "dependencies": { - "@algolia/autocomplete-core": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.5.2.tgz", - "integrity": "sha512-DY0bhyczFSS1b/CqJlTE/nQRtnTAHl6IemIkBy0nEWnhDzRDdtdx4p5Uuk3vwAFxwEEgi1WqKwgSSMx6DpNL4A==", - "requires": { - "@algolia/autocomplete-shared": "1.5.2" - } }, - "@algolia/autocomplete-preset-algolia": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.5.2.tgz", - "integrity": "sha512-3MRYnYQFJyovANzSX2CToS6/5cfVjbLLqFsZTKcvF3abhQzxbqwwaMBlJtt620uBUOeMzhdfasKhCc40+RHiZw==", - "requires": { - "@algolia/autocomplete-shared": "1.5.2" + "node_modules/remark-parse/node_modules/unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@algolia/autocomplete-shared": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.5.2.tgz", - "integrity": "sha512-ylQAYv5H0YKMfHgVWX0j0NmL8XBcAeeeVQUmppnnMtzDbDnca6CzhKj3Q8eF9cHCgcdTDdb5K+3aKyGWA0obug==" - }, - "@algolia/cache-browser-local-storage": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.12.1.tgz", - "integrity": "sha512-ERFFOnC9740xAkuO0iZTQqm2AzU7Dpz/s+g7o48GlZgx5p9GgNcsuK5eS0GoW/tAK+fnKlizCtlFHNuIWuvfsg==", - "requires": { - "@algolia/cache-common": "4.12.1" + "node_modules/remark-parse/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@algolia/cache-common": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.12.1.tgz", - "integrity": "sha512-UugTER3V40jT+e19Dmph5PKMeliYKxycNPwrPNADin0RcWNfT2QksK9Ff2N2W7UKraqMOzoeDb4LAJtxcK1a8Q==" - }, - "@algolia/cache-in-memory": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.12.1.tgz", - "integrity": "sha512-U6iaunaxK1lHsAf02UWF58foKFEcrVLsHwN56UkCtwn32nlP9rz52WOcHsgk6TJrL8NDcO5swMjtOQ5XHESFLw==", - "requires": { - "@algolia/cache-common": "4.12.1" + "node_modules/remark-parse/node_modules/vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@algolia/client-account": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.12.1.tgz", - "integrity": "sha512-jGo4ConJNoMdTCR2zouO0jO/JcJmzOK6crFxMMLvdnB1JhmMbuIKluOTJVlBWeivnmcsqb7r0v7qTCPW5PAyxQ==", - "requires": { - "@algolia/client-common": "4.12.1", - "@algolia/client-search": "4.12.1", - "@algolia/transporter": "4.12.1" + "node_modules/remark-parse/node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@algolia/client-analytics": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.12.1.tgz", - "integrity": "sha512-h1It7KXzIthlhuhfBk7LteYq72tym9maQDUsyRW0Gft8b6ZQahnRak9gcCvKwhcJ1vJoP7T7JrNYGiYSicTD9g==", - "requires": { - "@algolia/client-common": "4.12.1", - "@algolia/client-search": "4.12.1", - "@algolia/requester-common": "4.12.1", - "@algolia/transporter": "4.12.1" + "node_modules/remark-rehype": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.0.0.tgz", + "integrity": "sha512-vx8x2MDMcxuE4lBmQ46zYUDfcFMmvg80WYX+UNLeG6ixjdCCLcw1lrgAukwBTuOFsS78eoAedHGn9sNM0w7TPw==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@algolia/client-common": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.12.1.tgz", - "integrity": "sha512-obnJ8eSbv+h94Grk83DTGQ3bqhViSWureV6oK1s21/KMGWbb3DkduHm+lcwFrMFkjSUSzosLBHV9EQUIBvueTw==", - "requires": { - "@algolia/requester-common": "4.12.1", - "@algolia/transporter": "4.12.1" + "node_modules/remark-rehype/node_modules/@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "dependencies": { + "@types/unist": "*" } }, - "@algolia/client-personalization": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.12.1.tgz", - "integrity": "sha512-sMSnjjPjRgByGHYygV+5L/E8a6RgU7l2GbpJukSzJ9GRY37tHmBHuvahv8JjdCGJ2p7QDYLnQy5bN5Z02qjc7Q==", - "requires": { - "@algolia/client-common": "4.12.1", - "@algolia/requester-common": "4.12.1", - "@algolia/transporter": "4.12.1" - } + "node_modules/remark-rehype/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, - "@algolia/client-search": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.12.1.tgz", - "integrity": "sha512-MwwKKprfY6X2nJ5Ki/ccXM2GDEePvVjZnnoOB2io3dLKW4fTqeSRlC5DRXeFD7UM0vOPPHr4ItV2aj19APKNVQ==", - "requires": { - "@algolia/client-common": "4.12.1", - "@algolia/requester-common": "4.12.1", - "@algolia/transporter": "4.12.1" + "node_modules/remark-rehype/node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "@algolia/events": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@algolia/events/-/events-4.0.1.tgz", - "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==" - }, - "@algolia/logger-common": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.12.1.tgz", - "integrity": "sha512-fCgrzlXGATNqdFTxwx0GsyPXK+Uqrx1SZ3iuY2VGPPqdt1a20clAG2n2OcLHJpvaa6vMFPlJyWvbqAgzxdxBlQ==" - }, - "@algolia/logger-console": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.12.1.tgz", - "integrity": "sha512-0owaEnq/davngQMYqxLA4KrhWHiXujQ1CU3FFnyUcMyBR7rGHI48zSOUpqnsAXrMBdSH6rH5BDkSUUFwsh8RkQ==", - "requires": { - "@algolia/logger-common": "4.12.1" + "node_modules/remark-rehype/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "@algolia/requester-browser-xhr": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.12.1.tgz", - "integrity": "sha512-OaMxDyG0TZG0oqz1lQh9e3woantAG1bLnuwq3fmypsrQxra4IQZiyn1x+kEb69D2TcXApI5gOgrD4oWhtEVMtw==", - "requires": { - "@algolia/requester-common": "4.12.1" + "node_modules/remark-rehype/node_modules/trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "@algolia/requester-common": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.12.1.tgz", - "integrity": "sha512-XWIrWQNJ1vIrSuL/bUk3ZwNMNxl+aWz6dNboRW6+lGTcMIwc3NBFE90ogbZKhNrFRff8zI4qCF15tjW+Fyhpow==" - }, - "@algolia/requester-node-http": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.12.1.tgz", - "integrity": "sha512-awBtwaD+s0hxkA1aehYn8F0t9wqGoBVWgY4JPHBmp1ChO3pK7RKnnvnv7QQa9vTlllX29oPt/BBVgMo1Z3n1Qg==", - "requires": { - "@algolia/requester-common": "4.12.1" + "node_modules/remark-rehype/node_modules/unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@algolia/transporter": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.12.1.tgz", - "integrity": "sha512-BGeNgdEHc6dXIk2g8kdlOoQ6fQ6OIaKQcplEj7HPoi+XZUeAvRi3Pff3QWd7YmybWkjzd9AnTzieTASDWhL+sQ==", - "requires": { - "@algolia/cache-common": "4.12.1", - "@algolia/logger-common": "4.12.1", - "@algolia/requester-common": "4.12.1" + "node_modules/remark-rehype/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@ampproject/remapping": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", - "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", - "requires": { - "@jridgewell/trace-mapping": "^0.3.0" + "node_modules/remark-rehype/node_modules/vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", - "requires": { - "@babel/highlight": "^7.16.7" + "node_modules/remark-rehype/node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@babel/compat-data": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", - "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==" - }, - "@babel/core": { - "version": "7.17.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.5.tgz", - "integrity": "sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA==", - "requires": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helpers": "^7.17.2", - "@babel/parser": "^7.17.3", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0" - }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@babel/generator": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", - "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", - "requires": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "node_modules/remark-stringify/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/remark-stringify/node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "@babel/helper-annotate-as-pure": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", - "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", - "requires": { - "@babel/types": "^7.16.7" + "node_modules/remark-stringify/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", - "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", - "requires": { - "@babel/helper-explode-assignable-expression": "^7.16.7", - "@babel/types": "^7.16.7" + "node_modules/remark-stringify/node_modules/trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "@babel/helper-compilation-targets": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", - "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", - "requires": { - "@babel/compat-data": "^7.16.4", - "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.17.5", - "semver": "^6.3.0" - }, + "node_modules/remark-stringify/node_modules/unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@babel/helper-create-class-features-plugin": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz", - "integrity": "sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7" + "node_modules/remark-stringify/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", - "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "regexpu-core": "^5.0.1" + "node_modules/remark-stringify/node_modules/vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@babel/helper-define-polyfill-provider": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", - "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", - "requires": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, + "node_modules/remark-stringify/node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@babel/helper-environment-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", - "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", - "requires": { - "@babel/types": "^7.16.7" + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" } }, - "@babel/helper-explode-assignable-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", - "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", - "requires": { - "@babel/types": "^7.16.7" + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "engines": { + "node": ">=0.10" } }, - "@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", - "requires": { - "@babel/helper-get-function-arity": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" } }, - "@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", - "requires": { - "@babel/types": "^7.16.7" + "node_modules/require-like": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", + "integrity": "sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==", + "engines": { + "node": "*" } }, - "@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", - "requires": { - "@babel/types": "^7.16.7" - } + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, - "@babel/helper-member-expression-to-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", - "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", - "requires": { - "@babel/types": "^7.16.7" + "node_modules/resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dependencies": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@babel/helper-module-imports": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", - "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-module-transforms": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz", - "integrity": "sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA==", - "requires": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0" - } + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" }, - "@babel/helper-optimise-call-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", - "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", - "requires": { - "@babel/types": "^7.16.7" + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" } }, - "@babel/helper-plugin-utils": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", - "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==" - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", - "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-wrap-function": "^7.16.8", - "@babel/types": "^7.16.8" - } + "node_modules/resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" }, - "@babel/helper-replace-supers": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", - "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", - "requires": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" + "node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "@babel/helper-simple-access": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", - "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", - "requires": { - "@babel/types": "^7.16.7" + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "engines": { + "node": ">= 4" } }, - "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", - "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", - "requires": { - "@babel/types": "^7.16.0" + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" } }, - "@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", - "requires": { - "@babel/types": "^7.16.7" + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==" - }, - "@babel/helper-validator-option": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", - "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==" + "node_modules/rtl-detect": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/rtl-detect/-/rtl-detect-1.0.4.tgz", + "integrity": "sha512-EBR4I2VDSSYr7PkBmFy04uhycIpDKp+21p/jARYXlCSjQksTBQcJ0HFUPOO79EPPH5JS6VAhiIQbycf0O3JAxQ==" }, - "@babel/helper-wrap-function": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", - "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", - "requires": { - "@babel/helper-function-name": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.8", - "@babel/types": "^7.16.8" + "node_modules/rtlcss": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.1.1.tgz", + "integrity": "sha512-/oVHgBtnPNcggP2aVXQjSy6N1mMAfHg4GSag0QtZBlD5bdDgAHwr4pydqJGd+SUCu9260+Pjqbjwtvu7EMH1KQ==", + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0", + "postcss": "^8.4.21", + "strip-json-comments": "^3.1.1" + }, + "bin": { + "rtlcss": "bin/rtlcss.js" + }, + "engines": { + "node": ">=12.0.0" } }, - "@babel/helpers": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", - "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", - "requires": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.0", - "@babel/types": "^7.17.0" + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" } }, - "@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", - "requires": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dependencies": { + "tslib": "^2.1.0" } }, - "@babel/parser": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz", - "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==" + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz", - "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", - "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.7" - } + "node_modules/sax": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", - "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8", - "@babel/plugin-syntax-async-generators": "^7.8.4" + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" } }, - "@babel/plugin-proposal-class-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", - "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "@babel/plugin-proposal-class-static-block": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.6.tgz", - "integrity": "sha512-X/tididvL2zbs7jZCeeRJ8167U/+Ac135AM6jCAx6gYXDUviZV5Ku9UDvWS2NCuWlFjIRXklYhwo6HhAC7ETnA==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.17.6", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-class-static-block": "^7.14.5" + "node_modules/schema-utils/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "@babel/plugin-proposal-dynamic-import": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", - "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" } }, - "@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", - "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - } + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, - "@babel/plugin-proposal-json-strings": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", - "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-json-strings": "^7.8.3" - } + "node_modules/search-insights": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.11.0.tgz", + "integrity": "sha512-Uin2J8Bpm3xaZi9Y8QibSys6uJOFZ+REMrf42v20AA3FUDUrshKkMEP6liJbMAHCm71wO6ls4mwAf7a3gFVxLw==", + "peer": true }, - "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", - "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" } }, - "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", - "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - } + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==" }, - "@babel/plugin-proposal-numeric-separator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", - "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" + "node_modules/selfsigned": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", + "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "dependencies": { + "node-forge": "^1" + }, + "engines": { + "node": ">=10" } }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz", - "integrity": "sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw==", - "requires": { - "@babel/compat-data": "^7.17.0", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.7" + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", - "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + "node_modules/semver-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", + "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "@babel/plugin-proposal-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", - "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" } }, - "@babel/plugin-proposal-private-methods": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", - "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.10", - "@babel/helper-plugin-utils": "^7.16.7" + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" } }, - "@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", - "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - } + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", - "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" } }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" + "node_modules/send/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" } }, - "@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dependencies": { + "randombytes": "^2.1.0" } }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" + "node_modules/serve-handler": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.5.tgz", + "integrity": "sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg==", + "dependencies": { + "bytes": "3.0.0", + "content-disposition": "0.5.2", + "fast-url-parser": "1.1.3", + "mime-types": "2.1.18", + "minimatch": "3.1.2", + "path-is-inside": "1.0.2", + "path-to-regexp": "2.2.1", + "range-parser": "1.2.0" } }, - "@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" } }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" } }, - "@babel/plugin-syntax-jsx": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz", - "integrity": "sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "engines": { + "node": ">= 0.6" } }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" } }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "engines": { + "node": ">= 0.6" } }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" } }, - "@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" } }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" }, - "@babel/plugin-syntax-typescript": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", - "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", - "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" } }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", - "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", - "requires": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8" - } + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", - "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "@babel/plugin-transform-block-scoping": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", - "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" } }, - "@babel/plugin-transform-classes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", - "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "globals": "^11.1.0" + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@babel/plugin-transform-computed-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", - "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" } }, - "@babel/plugin-transform-destructuring": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.3.tgz", - "integrity": "sha512-dDFzegDYKlPqa72xIlbmSkly5MluLoaC1JswABGktyt6NTXSBcUuse/kWE/wvKFWJHPETpi158qJZFS3JmykJg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", - "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", - "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", - "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", - "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "node_modules/sirv": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.3.tgz", + "integrity": "sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==", + "dependencies": { + "@polka/url": "^1.0.0-next.20", + "mrmime": "^1.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" } }, - "@babel/plugin-transform-for-of": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", - "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" }, - "@babel/plugin-transform-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", - "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", - "requires": { - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "node_modules/sitemap": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-7.1.1.tgz", + "integrity": "sha512-mK3aFtjz4VdJN0igpIJrinf3EO8U8mxOPsTBzSsy06UtjZQJ3YY3o3Xa7zSc5nMqcMrRwlChHZ18Kxg0caiPBg==", + "dependencies": { + "@types/node": "^17.0.5", + "@types/sax": "^1.2.1", + "arg": "^5.0.0", + "sax": "^1.2.4" + }, + "bin": { + "sitemap": "dist/cli.js" + }, + "engines": { + "node": ">=12.0.0", + "npm": ">=5.6.0" } }, - "@babel/plugin-transform-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", - "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "node_modules/skin-tone": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", + "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", + "dependencies": { + "unicode-emoji-modifier-base": "^1.0.0" + }, + "engines": { + "node": ">=8" } }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", - "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" } }, - "@babel/plugin-transform-modules-amd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", - "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", - "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dependencies": { - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "requires": { - "object.assign": "^4.1.0" - } - } - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", - "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", - "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" }, - "dependencies": { - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "requires": { - "object.assign": "^4.1.0" - } - } - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", - "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", - "requires": { - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" + "engines": { + "node": ">=10" }, - "dependencies": { - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "requires": { - "object.assign": "^4.1.0" - } - } - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", - "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", - "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", - "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7" + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "@babel/plugin-transform-new-target": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", - "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "@babel/plugin-transform-object-super": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", - "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7" - } + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "@babel/plugin-transform-parameters": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", - "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" } }, - "@babel/plugin-transform-property-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", - "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "node_modules/sort-css-media-queries": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.1.0.tgz", + "integrity": "sha512-IeWvo8NkNiY2vVYdPa27MCQiR0MN0M80johAYFVxWWXQ44KU84WNxjslwBHmc/7ZL2ccwkM7/e6S5aiKZXm7jA==", + "engines": { + "node": ">= 6.3.0" } }, - "@babel/plugin-transform-react-constant-elements": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.17.6.tgz", - "integrity": "sha512-OBv9VkyyKtsHZiHLoSfCn+h6yU7YKX8nrs32xUmOa1SRSk+t03FosB6fBZ0Yz4BpD1WV7l73Nsad+2Tz7APpqw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" } }, - "@babel/plugin-transform-react-display-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz", - "integrity": "sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" } }, - "@babel/plugin-transform-react-jsx": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.17.3.tgz", - "integrity": "sha512-9tjBm4O07f7mzKSIlEmPdiE6ub7kfIe6Cd+w+oQebpATfTQMAgW+YOuWxogbKVTulA+MEO7byMeIUtQ1z+z+ZQ==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-jsx": "^7.16.7", - "@babel/types": "^7.17.0" + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } }, - "@babel/plugin-transform-react-jsx-development": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.7.tgz", - "integrity": "sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A==", - "requires": { - "@babel/plugin-transform-react-jsx": "^7.16.7" + "node_modules/space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "@babel/plugin-transform-react-pure-annotations": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.7.tgz", - "integrity": "sha512-hs71ToC97k3QWxswh2ElzMFABXHvGiJ01IB1TbYQDGeWRKWz/MPUTh5jGExdHvosYKpnJW5Pm3S4+TA3FyX+GA==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" } }, - "@babel/plugin-transform-regenerator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", - "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", - "requires": { - "regenerator-transform": "^0.14.2" + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" } }, - "@babel/plugin-transform-reserved-words": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", - "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, - "@babel/plugin-transform-runtime": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.17.0.tgz", - "integrity": "sha512-fr7zPWnKXNc1xoHfrIU9mN/4XKX4VLZ45Q+oMhfsYIaHvg7mHgmhfOy/ckRWqDK7XF3QDigRpkh5DKq6+clE8A==", - "requires": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "semver": "^6.3.0" + "node_modules/srcset": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/srcset/-/srcset-4.0.0.tgz", + "integrity": "sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==", + "engines": { + "node": ">=12" }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", - "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } + "node_modules/stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" }, - "@babel/plugin-transform-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", - "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" } }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", - "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } + "node_modules/std-env": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.0.1.tgz", + "integrity": "sha512-mC1Ps9l77/97qeOZc+HrOL7TIaOboHqMZ24dGVQrlxFcpPpfCHpH+qfUT7Dz+6mlG8+JPA1KfBQo19iC/+Ngcw==" }, - "@babel/plugin-transform-template-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", - "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" } }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", - "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "@babel/plugin-transform-typescript": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz", - "integrity": "sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-typescript": "^7.16.7" + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" } }, - "@babel/plugin-transform-unicode-escapes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", - "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "node_modules/string.prototype.matchall": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz", + "integrity": "sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.3.1", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", - "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "node_modules/string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@babel/preset-env": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", - "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", - "requires": { - "@babel/compat-data": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-async-generator-functions": "^7.16.8", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-class-static-block": "^7.16.7", - "@babel/plugin-proposal-dynamic-import": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.16.7", - "@babel/plugin-proposal-json-strings": "^7.16.7", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", - "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.16.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", - "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.11", - "@babel/plugin-proposal-private-property-in-object": "^7.16.7", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.7", - "@babel/plugin-transform-async-to-generator": "^7.16.8", - "@babel/plugin-transform-block-scoped-functions": "^7.16.7", - "@babel/plugin-transform-block-scoping": "^7.16.7", - "@babel/plugin-transform-classes": "^7.16.7", - "@babel/plugin-transform-computed-properties": "^7.16.7", - "@babel/plugin-transform-destructuring": "^7.16.7", - "@babel/plugin-transform-dotall-regex": "^7.16.7", - "@babel/plugin-transform-duplicate-keys": "^7.16.7", - "@babel/plugin-transform-exponentiation-operator": "^7.16.7", - "@babel/plugin-transform-for-of": "^7.16.7", - "@babel/plugin-transform-function-name": "^7.16.7", - "@babel/plugin-transform-literals": "^7.16.7", - "@babel/plugin-transform-member-expression-literals": "^7.16.7", - "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-modules-commonjs": "^7.16.8", - "@babel/plugin-transform-modules-systemjs": "^7.16.7", - "@babel/plugin-transform-modules-umd": "^7.16.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", - "@babel/plugin-transform-new-target": "^7.16.7", - "@babel/plugin-transform-object-super": "^7.16.7", - "@babel/plugin-transform-parameters": "^7.16.7", - "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.16.7", - "@babel/plugin-transform-reserved-words": "^7.16.7", - "@babel/plugin-transform-shorthand-properties": "^7.16.7", - "@babel/plugin-transform-spread": "^7.16.7", - "@babel/plugin-transform-sticky-regex": "^7.16.7", - "@babel/plugin-transform-template-literals": "^7.16.7", - "@babel/plugin-transform-typeof-symbol": "^7.16.7", - "@babel/plugin-transform-unicode-escapes": "^7.16.7", - "@babel/plugin-transform-unicode-regex": "^7.16.7", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.8", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.20.2", - "semver": "^6.3.0" + "node_modules/string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.3.tgz", + "integrity": "sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==", "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" } }, - "@babel/preset-react": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.16.7.tgz", - "integrity": "sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-transform-react-display-name": "^7.16.7", - "@babel/plugin-transform-react-jsx": "^7.16.7", - "@babel/plugin-transform-react-jsx-development": "^7.16.7", - "@babel/plugin-transform-react-pure-annotations": "^7.16.7" + "node_modules/stringify-object/node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "engines": { + "node": ">=0.10.0" } }, - "@babel/preset-typescript": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz", - "integrity": "sha512-WbVEmgXdIyvzB77AQjGBEyYPZx+8tTsO50XtfozQrkW8QB2rLJpH2lgx0TRw5EJrBxOZQ+wCcyPVQvS8tjEHpQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-transform-typescript": "^7.16.7" + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "@babel/runtime": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", - "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==", - "requires": { - "regenerator-runtime": "^0.13.4" + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "engines": { + "node": ">=0.10.0" } }, - "@babel/runtime-corejs3": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.17.2.tgz", - "integrity": "sha512-NcKtr2epxfIrNM4VOmPKO46TvDMCBhgi2CrSHaEarrz+Plk2K5r9QemmOFTGpZaoKnWoGH5MO+CzeRsih/Fcgg==", - "requires": { - "core-js-pure": "^3.20.2", - "regenerator-runtime": "^0.13.4" + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "engines": { + "node": ">=6" } }, - "@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", - "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "@babel/traverse": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", - "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", - "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.3", - "@babel/types": "^7.17.0", - "debug": "^4.1.0", - "globals": "^11.1.0" + "node_modules/style-to-object": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.4.tgz", + "integrity": "sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==", + "dependencies": { + "inline-style-parser": "0.1.1" } }, - "@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", - "requires": { - "@babel/helper-validator-identifier": "^7.16.7", - "to-fast-properties": "^2.0.0" + "node_modules/stylehacks": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", + "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "@docsearch/css": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.0.0.tgz", - "integrity": "sha512-1kkV7tkAsiuEd0shunYRByKJe3xQDG2q7wYg24SOw1nV9/2lwEd4WrUYRJC/ukGTl2/kHeFxsaUvtiOy0y6fFA==" + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } }, - "@docusaurus/core": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-2.0.0-beta.15.tgz", - "integrity": "sha512-zXhhD0fApMSvq/9Pkm9DQxa//hGOXVCq9yMHiXOkI5D1tLec7PxtnaC5cLfGHljkN9cKIfRDYUVcG1gHymVfpA==", - "requires": { - "@babel/core": "^7.16.0", - "@babel/generator": "^7.16.0", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-transform-runtime": "^7.16.0", - "@babel/preset-env": "^7.16.4", - "@babel/preset-react": "^7.16.0", - "@babel/preset-typescript": "^7.16.0", - "@babel/runtime": "^7.16.3", - "@babel/runtime-corejs3": "^7.16.3", - "@babel/traverse": "^7.16.3", - "@docusaurus/cssnano-preset": "2.0.0-beta.15", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/mdx-loader": "2.0.0-beta.15", - "@docusaurus/react-loadable": "5.5.2", - "@docusaurus/utils": "2.0.0-beta.15", - "@docusaurus/utils-common": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", - "@slorber/static-site-generator-webpack-plugin": "^4.0.0", - "@svgr/webpack": "^6.0.0", - "autoprefixer": "^10.3.5", - "babel-loader": "^8.2.2", - "babel-plugin-dynamic-import-node": "2.3.0", - "boxen": "^5.0.1", - "chokidar": "^3.5.2", - "clean-css": "^5.1.5", - "commander": "^5.1.0", - "copy-webpack-plugin": "^10.2.0", - "core-js": "^3.18.0", - "css-loader": "^6.5.1", - "css-minimizer-webpack-plugin": "^3.3.1", - "cssnano": "^5.0.8", - "del": "^6.0.0", - "detect-port": "^1.3.0", - "escape-html": "^1.0.3", - "eta": "^1.12.3", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "html-minifier-terser": "^6.0.2", - "html-tags": "^3.1.0", - "html-webpack-plugin": "^5.4.0", - "import-fresh": "^3.3.0", - "is-root": "^2.1.0", - "leven": "^3.1.0", - "lodash": "^4.17.20", - "mini-css-extract-plugin": "^1.6.0", - "nprogress": "^0.2.0", - "postcss": "^8.3.7", - "postcss-loader": "^6.1.1", - "prompts": "^2.4.1", - "react-dev-utils": "^12.0.0", - "react-helmet": "^6.1.0", - "react-loadable": "npm:@docusaurus/react-loadable@5.5.2", - "react-loadable-ssr-addon-v5-slorber": "^1.0.1", - "react-router": "^5.2.0", - "react-router-config": "^5.1.1", - "react-router-dom": "^5.2.0", - "remark-admonitions": "^1.2.1", - "rtl-detect": "^1.0.4", - "semver": "^7.3.4", - "serve-handler": "^6.1.3", - "shelljs": "^0.8.4", - "strip-ansi": "^6.0.0", - "terser-webpack-plugin": "^5.2.4", - "tslib": "^2.3.1", - "update-notifier": "^5.1.0", - "url-loader": "^4.1.1", - "wait-on": "^6.0.0", - "webpack": "^5.61.0", - "webpack-bundle-analyzer": "^4.4.2", - "webpack-dev-server": "^4.7.1", - "webpack-merge": "^5.8.0", - "webpackbar": "^5.0.2" + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" + }, + "node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", "dependencies": { - "@docusaurus/mdx-loader": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.15.tgz", - "integrity": "sha512-MVpytjDDao7hmPF1QSs9B5zoTgevZjiqjnX3FM1yjqdCv+chyUo0gnmYHjeG/4Gqu7jucp+dDdp6yQpzs4g09A==", - "requires": { - "@babel/parser": "^7.16.4", - "@babel/traverse": "^7.16.3", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@mdx-js/mdx": "^1.6.21", - "escape-html": "^1.0.3", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "image-size": "^1.0.1", - "mdast-util-to-string": "^2.0.0", - "remark-emoji": "^2.1.0", - "stringify-object": "^3.3.0", - "tslib": "^2.3.1", - "unist-util-visit": "^2.0.2", - "url-loader": "^4.1.1", - "webpack": "^5.61.0" - } - }, - "@docusaurus/react-loadable": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", - "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", - "requires": { - "@types/react": "*", - "prop-types": "^15.6.2" - } - }, - "@docusaurus/utils": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.0.0-beta.15.tgz", - "integrity": "sha512-xkoPmFxCBkDqbZR4U3SE752OcXtWTGgZnc/pZWxItzb1IYRGNZHrzdIr7CnI7rppriuZzsyivDGiC4Ud9MWhkA==", - "requires": { - "@docusaurus/logger": "2.0.0-beta.15", - "@mdx-js/runtime": "^1.6.22", - "@svgr/webpack": "^6.0.0", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "github-slugger": "^1.4.0", - "globby": "^11.0.4", - "gray-matter": "^4.0.3", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "micromatch": "^4.0.4", - "remark-mdx-remove-exports": "^1.6.22", - "remark-mdx-remove-imports": "^1.6.22", - "resolve-pathname": "^3.0.0", - "tslib": "^2.3.1", - "url-loader": "^4.1.1" - } - }, - "@docusaurus/utils-validation": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.15.tgz", - "integrity": "sha512-1oOVBCkRrsTXSYrBTsMdnj3a/R56zrx11rjF4xo0+dmm8C01Xw4msFtc3uA7VLX0HQvgHsk8xPzU5GERNdsNpg==", - "requires": { - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "joi": "^17.4.2", - "tslib": "^2.3.1" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "requires": { - "argparse": "^2.0.1" - } - }, - "path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "requires": { - "isarray": "0.0.1" - } - }, - "react-helmet": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-6.1.0.tgz", - "integrity": "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==", - "requires": { - "object-assign": "^4.1.1", - "prop-types": "^15.7.2", - "react-fast-compare": "^3.1.1", - "react-side-effect": "^2.1.0" - }, - "dependencies": { - "react-side-effect": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.1.tgz", - "integrity": "sha512-2FoTQzRNTncBVtnzxFOk2mCpcfxQpenBMbk5kSVBg5UcPqV9fRbgY2zhb7GTWWOlpFmAxhClBDlIq8Rsubz1yQ==", - "requires": {} - } - } - }, - "react-loadable": { - "version": "npm:@docusaurus/react-loadable@5.5.2", - "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", - "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", - "requires": { - "@types/react": "*", - "prop-types": "^15.6.2" - } - }, - "react-loadable-ssr-addon-v5-slorber": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.1.tgz", - "integrity": "sha512-lq3Lyw1lGku8zUEJPDxsNm1AfYHBrO9Y1+olAYwpUJ2IGFBskM0DMKok97A6LWUpHm+o7IvQBOWu9MLenp9Z+A==", - "requires": { - "@babel/runtime": "^7.10.3" - } - }, - "react-router": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.1.tgz", - "integrity": "sha512-lIboRiOtDLFdg1VTemMwud9vRVuOCZmUIT/7lUoZiSpPODiiH1UQlfXy+vPLC/7IWdFYnhRwAyNqA/+I7wnvKQ==", - "requires": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "hoist-non-react-statics": "^3.1.0", - "loose-envify": "^1.3.1", - "mini-create-react-context": "^0.4.0", - "path-to-regexp": "^1.7.0", - "prop-types": "^15.6.2", - "react-is": "^16.6.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - }, - "dependencies": { - "mini-create-react-context": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", - "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", - "requires": { - "@babel/runtime": "^7.12.1", - "tiny-warning": "^1.0.3" - } - } - } - }, - "react-router-config": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/react-router-config/-/react-router-config-5.1.1.tgz", - "integrity": "sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==", - "requires": { - "@babel/runtime": "^7.1.2" - } - }, - "react-router-dom": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.0.tgz", - "integrity": "sha512-ObVBLjUZsphUUMVycibxgMdh5jJ1e3o+KpAZBVeHcNQZ4W+uUGGWsokurzlF4YOldQYRQL4y6yFRWM4m3svmuQ==", - "requires": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "loose-envify": "^1.3.1", - "prop-types": "^15.6.2", - "react-router": "5.2.1", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - } - } + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" } }, - "@docusaurus/cssnano-preset": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-2.0.0-beta.15.tgz", - "integrity": "sha512-55aYURbB5dqrx64lStNcZxDx5R6bKkAawlCB7mDKx3r+Qnp3ofGW7UExLQSCbTu3axT1vJCF5D7H6ljTRYJLtA==", - "requires": { - "cssnano-preset-advanced": "^5.1.4", - "postcss": "^8.3.7", - "postcss-sort-media-queries": "^4.1.0" + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" } }, - "@docusaurus/logger": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-2.0.0-beta.15.tgz", - "integrity": "sha512-5bDSHCyLfMtz6QnFfICdL5mgxbGfC7DW1V+/Q17nRdpZSPZgsNKK/Esp0zdDi1oxAyEpXMXx64nLaHL7joJxIg==", - "requires": { - "chalk": "^4.1.2", - "tslib": "^2.3.1" + "node_modules/table": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", + "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", + "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "@docusaurus/preset-classic": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-2.0.0-beta.15.tgz", - "integrity": "sha512-3NZIXWTAzk+kOgiB8uAbD+FZv3VFR1qkU6+TW24DRenjRnXof3CkRuldhI1QI0hILm1fuJ319QRkakV8FFtXyA==", - "requires": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/plugin-content-blog": "2.0.0-beta.15", - "@docusaurus/plugin-content-docs": "2.0.0-beta.15", - "@docusaurus/plugin-content-pages": "2.0.0-beta.15", - "@docusaurus/plugin-debug": "2.0.0-beta.15", - "@docusaurus/plugin-google-analytics": "2.0.0-beta.15", - "@docusaurus/plugin-google-gtag": "2.0.0-beta.15", - "@docusaurus/plugin-sitemap": "2.0.0-beta.15", - "@docusaurus/theme-classic": "2.0.0-beta.15", - "@docusaurus/theme-common": "2.0.0-beta.15", - "@docusaurus/theme-search-algolia": "2.0.0-beta.15" + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.31.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz", + "integrity": "sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", "dependencies": { - "@docusaurus/plugin-content-blog": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.0.0-beta.15.tgz", - "integrity": "sha512-VtEwkgkoNIS8JFPe+huBeBuJ8HG8Lq1JNYM/ItwQg/cwGAgP8EgwbEuKDn428oZKEI2PpgAuf5Gv4AzJWIes9A==", - "requires": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/mdx-loader": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@docusaurus/utils-common": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", - "cheerio": "^1.0.0-rc.10", - "feed": "^4.2.2", - "fs-extra": "^10.0.0", - "lodash": "^4.17.20", - "reading-time": "^1.5.0", - "remark-admonitions": "^1.2.1", - "tslib": "^2.3.1", - "utility-types": "^3.10.0", - "webpack": "^5.61.0" - }, - "dependencies": { - "@docusaurus/mdx-loader": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.15.tgz", - "integrity": "sha512-MVpytjDDao7hmPF1QSs9B5zoTgevZjiqjnX3FM1yjqdCv+chyUo0gnmYHjeG/4Gqu7jucp+dDdp6yQpzs4g09A==", - "requires": { - "@babel/parser": "^7.16.4", - "@babel/traverse": "^7.16.3", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@mdx-js/mdx": "^1.6.21", - "escape-html": "^1.0.3", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "image-size": "^1.0.1", - "mdast-util-to-string": "^2.0.0", - "remark-emoji": "^2.1.0", - "stringify-object": "^3.3.0", - "tslib": "^2.3.1", - "unist-util-visit": "^2.0.2", - "url-loader": "^4.1.1", - "webpack": "^5.61.0" - } - }, - "@docusaurus/utils": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.0.0-beta.15.tgz", - "integrity": "sha512-xkoPmFxCBkDqbZR4U3SE752OcXtWTGgZnc/pZWxItzb1IYRGNZHrzdIr7CnI7rppriuZzsyivDGiC4Ud9MWhkA==", - "requires": { - "@docusaurus/logger": "2.0.0-beta.15", - "@mdx-js/runtime": "^1.6.22", - "@svgr/webpack": "^6.0.0", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "github-slugger": "^1.4.0", - "globby": "^11.0.4", - "gray-matter": "^4.0.3", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "micromatch": "^4.0.4", - "remark-mdx-remove-exports": "^1.6.22", - "remark-mdx-remove-imports": "^1.6.22", - "resolve-pathname": "^3.0.0", - "tslib": "^2.3.1", - "url-loader": "^4.1.1" - } - }, - "@docusaurus/utils-validation": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.15.tgz", - "integrity": "sha512-1oOVBCkRrsTXSYrBTsMdnj3a/R56zrx11rjF4xo0+dmm8C01Xw4msFtc3uA7VLX0HQvgHsk8xPzU5GERNdsNpg==", - "requires": { - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "joi": "^17.4.2", - "tslib": "^2.3.1" - } - } - } + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true }, - "@docusaurus/plugin-content-docs": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.0.0-beta.15.tgz", - "integrity": "sha512-HSwNZdUKz4rpJiGbFjl/OFhSleeZUSZ6E6lk98i4iL1A5u6fIm4CHsT53yp4UUOse+lFrePTFZsyqwMA4nZZYA==", - "requires": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/mdx-loader": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", - "combine-promises": "^1.1.0", - "fs-extra": "^10.0.0", - "import-fresh": "^3.2.2", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "remark-admonitions": "^1.2.1", - "shelljs": "^0.8.4", - "tslib": "^2.3.1", - "utility-types": "^3.10.0", - "webpack": "^5.61.0" - }, - "dependencies": { - "@docusaurus/mdx-loader": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.15.tgz", - "integrity": "sha512-MVpytjDDao7hmPF1QSs9B5zoTgevZjiqjnX3FM1yjqdCv+chyUo0gnmYHjeG/4Gqu7jucp+dDdp6yQpzs4g09A==", - "requires": { - "@babel/parser": "^7.16.4", - "@babel/traverse": "^7.16.3", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@mdx-js/mdx": "^1.6.21", - "escape-html": "^1.0.3", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "image-size": "^1.0.1", - "mdast-util-to-string": "^2.0.0", - "remark-emoji": "^2.1.0", - "stringify-object": "^3.3.0", - "tslib": "^2.3.1", - "unist-util-visit": "^2.0.2", - "url-loader": "^4.1.1", - "webpack": "^5.61.0" - } - }, - "@docusaurus/utils": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.0.0-beta.15.tgz", - "integrity": "sha512-xkoPmFxCBkDqbZR4U3SE752OcXtWTGgZnc/pZWxItzb1IYRGNZHrzdIr7CnI7rppriuZzsyivDGiC4Ud9MWhkA==", - "requires": { - "@docusaurus/logger": "2.0.0-beta.15", - "@mdx-js/runtime": "^1.6.22", - "@svgr/webpack": "^6.0.0", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "github-slugger": "^1.4.0", - "globby": "^11.0.4", - "gray-matter": "^4.0.3", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "micromatch": "^4.0.4", - "remark-mdx-remove-exports": "^1.6.22", - "remark-mdx-remove-imports": "^1.6.22", - "resolve-pathname": "^3.0.0", - "tslib": "^2.3.1", - "url-loader": "^4.1.1" - } - }, - "@docusaurus/utils-validation": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.15.tgz", - "integrity": "sha512-1oOVBCkRrsTXSYrBTsMdnj3a/R56zrx11rjF4xo0+dmm8C01Xw4msFtc3uA7VLX0HQvgHsk8xPzU5GERNdsNpg==", - "requires": { - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "joi": "^17.4.2", - "tslib": "^2.3.1" - } - } - } + "esbuild": { + "optional": true }, - "@docusaurus/plugin-content-pages": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.0.0-beta.15.tgz", - "integrity": "sha512-N7YhW5RiOY6J228z4lOoP//qX0Q48cRtxDONZ/Ohd9C5OI2vS6TD8iQuDqOIYHxH+BshjNSsKvbJ+SMIQDwysg==", - "requires": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/mdx-loader": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", - "fs-extra": "^10.0.0", - "globby": "^11.0.2", - "remark-admonitions": "^1.2.1", - "tslib": "^2.3.1", - "webpack": "^5.61.0" - }, - "dependencies": { - "@docusaurus/mdx-loader": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.15.tgz", - "integrity": "sha512-MVpytjDDao7hmPF1QSs9B5zoTgevZjiqjnX3FM1yjqdCv+chyUo0gnmYHjeG/4Gqu7jucp+dDdp6yQpzs4g09A==", - "requires": { - "@babel/parser": "^7.16.4", - "@babel/traverse": "^7.16.3", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@mdx-js/mdx": "^1.6.21", - "escape-html": "^1.0.3", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "image-size": "^1.0.1", - "mdast-util-to-string": "^2.0.0", - "remark-emoji": "^2.1.0", - "stringify-object": "^3.3.0", - "tslib": "^2.3.1", - "unist-util-visit": "^2.0.2", - "url-loader": "^4.1.1", - "webpack": "^5.61.0" - } - }, - "@docusaurus/utils": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.0.0-beta.15.tgz", - "integrity": "sha512-xkoPmFxCBkDqbZR4U3SE752OcXtWTGgZnc/pZWxItzb1IYRGNZHrzdIr7CnI7rppriuZzsyivDGiC4Ud9MWhkA==", - "requires": { - "@docusaurus/logger": "2.0.0-beta.15", - "@mdx-js/runtime": "^1.6.22", - "@svgr/webpack": "^6.0.0", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "github-slugger": "^1.4.0", - "globby": "^11.0.4", - "gray-matter": "^4.0.3", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "micromatch": "^4.0.4", - "remark-mdx-remove-exports": "^1.6.22", - "remark-mdx-remove-imports": "^1.6.22", - "resolve-pathname": "^3.0.0", - "tslib": "^2.3.1", - "url-loader": "^4.1.1" - } - }, - "@docusaurus/utils-validation": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.15.tgz", - "integrity": "sha512-1oOVBCkRrsTXSYrBTsMdnj3a/R56zrx11rjF4xo0+dmm8C01Xw4msFtc3uA7VLX0HQvgHsk8xPzU5GERNdsNpg==", - "requires": { - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "joi": "^17.4.2", - "tslib": "^2.3.1" - } - } - } - }, - "@docusaurus/plugin-debug": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-2.0.0-beta.15.tgz", - "integrity": "sha512-Jth11jB/rVqPwCGdkVKSUWeXZPAr/NyPn+yeknTBk2LgQKBJ3YU5dNG0uyt0Ay+UYT01TkousPJkXhLuy4Qrsw==", - "requires": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "fs-extra": "^10.0.0", - "react-json-view": "^1.21.3", - "tslib": "^2.3.1" - }, - "dependencies": { - "@docusaurus/utils": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.0.0-beta.15.tgz", - "integrity": "sha512-xkoPmFxCBkDqbZR4U3SE752OcXtWTGgZnc/pZWxItzb1IYRGNZHrzdIr7CnI7rppriuZzsyivDGiC4Ud9MWhkA==", - "requires": { - "@docusaurus/logger": "2.0.0-beta.15", - "@mdx-js/runtime": "^1.6.22", - "@svgr/webpack": "^6.0.0", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "github-slugger": "^1.4.0", - "globby": "^11.0.4", - "gray-matter": "^4.0.3", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "micromatch": "^4.0.4", - "remark-mdx-remove-exports": "^1.6.22", - "remark-mdx-remove-imports": "^1.6.22", - "resolve-pathname": "^3.0.0", - "tslib": "^2.3.1", - "url-loader": "^4.1.1" - } - }, - "react-json-view": { - "version": "1.21.3", - "resolved": "https://registry.npmjs.org/react-json-view/-/react-json-view-1.21.3.tgz", - "integrity": "sha512-13p8IREj9/x/Ye4WI/JpjhoIwuzEgUAtgJZNBJckfzJt1qyh24BdTm6UQNGnyTq9dapQdrqvquZTo3dz1X6Cjw==", - "requires": { - "flux": "^4.0.1", - "react-base16-styling": "^0.6.0", - "react-lifecycles-compat": "^3.0.4", - "react-textarea-autosize": "^8.3.2" - }, - "dependencies": { - "flux": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.3.tgz", - "integrity": "sha512-yKAbrp7JhZhj6uiT1FTuVMlIAT1J4jqEyBpFApi1kxpGZCvacMVc/t1pMQyotqHhAgvoE3bNvAykhCo2CLjnYw==", - "requires": { - "fbemitter": "^3.0.0", - "fbjs": "^3.0.1" - } - }, - "react-textarea-autosize": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.3.3.tgz", - "integrity": "sha512-2XlHXK2TDxS6vbQaoPbMOfQ8GK7+irc2fVK6QFIcC8GOnH3zI/v481n+j1L0WaPVvKxwesnY93fEfH++sus2rQ==", - "requires": { - "@babel/runtime": "^7.10.2", - "use-composed-ref": "^1.0.0", - "use-latest": "^1.0.0" - }, - "dependencies": { - "use-composed-ref": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.2.1.tgz", - "integrity": "sha512-6+X1FLlIcjvFMAeAD/hcxDT8tmyrWnbSPMU0EnxQuDLIxokuFzWliXBiYZuGIx+mrAMLBw0WFfCkaPw8ebzAhw==", - "requires": {} - }, - "use-latest": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.0.tgz", - "integrity": "sha512-d2TEuG6nSLKQLAfW3By8mKr8HurOlTkul0sOpxbClIv4SQ4iOd7BYr7VIzdbktUCnv7dua/60xzd8igMU6jmyw==", - "requires": { - "use-isomorphic-layout-effect": "^1.0.0" - }, - "dependencies": { - "use-isomorphic-layout-effect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz", - "integrity": "sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ==", - "requires": {} - } - } - } - } - } - } - } - } - }, - "@docusaurus/plugin-google-analytics": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.0.0-beta.15.tgz", - "integrity": "sha512-ELAnxNYiC2i7gfu/ViurNIdm1/DdnbEfVDmpffS9niQhOREM1U3jpxkz/ff1GIC6heOLyHTtini/CZBDoroVGw==", - "requires": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", - "tslib": "^2.3.1" - }, - "dependencies": { - "@docusaurus/utils-validation": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.15.tgz", - "integrity": "sha512-1oOVBCkRrsTXSYrBTsMdnj3a/R56zrx11rjF4xo0+dmm8C01Xw4msFtc3uA7VLX0HQvgHsk8xPzU5GERNdsNpg==", - "requires": { - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "joi": "^17.4.2", - "tslib": "^2.3.1" - }, - "dependencies": { - "@docusaurus/utils": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.0.0-beta.15.tgz", - "integrity": "sha512-xkoPmFxCBkDqbZR4U3SE752OcXtWTGgZnc/pZWxItzb1IYRGNZHrzdIr7CnI7rppriuZzsyivDGiC4Ud9MWhkA==", - "requires": { - "@docusaurus/logger": "2.0.0-beta.15", - "@mdx-js/runtime": "^1.6.22", - "@svgr/webpack": "^6.0.0", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "github-slugger": "^1.4.0", - "globby": "^11.0.4", - "gray-matter": "^4.0.3", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "micromatch": "^4.0.4", - "remark-mdx-remove-exports": "^1.6.22", - "remark-mdx-remove-imports": "^1.6.22", - "resolve-pathname": "^3.0.0", - "tslib": "^2.3.1", - "url-loader": "^4.1.1" - } - } - } - } - } - }, - "@docusaurus/plugin-google-gtag": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.0.0-beta.15.tgz", - "integrity": "sha512-E5Rm3+dN7i3A9V5uq5sl9xTNA3aXsLwTZEA2SpOkY571dCpd+sfVvz1lR+KRY9Fy6ZHk8PqrNImgCWfIerRuZQ==", - "requires": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", - "tslib": "^2.3.1" - }, - "dependencies": { - "@docusaurus/utils-validation": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.15.tgz", - "integrity": "sha512-1oOVBCkRrsTXSYrBTsMdnj3a/R56zrx11rjF4xo0+dmm8C01Xw4msFtc3uA7VLX0HQvgHsk8xPzU5GERNdsNpg==", - "requires": { - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "joi": "^17.4.2", - "tslib": "^2.3.1" - }, - "dependencies": { - "@docusaurus/utils": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.0.0-beta.15.tgz", - "integrity": "sha512-xkoPmFxCBkDqbZR4U3SE752OcXtWTGgZnc/pZWxItzb1IYRGNZHrzdIr7CnI7rppriuZzsyivDGiC4Ud9MWhkA==", - "requires": { - "@docusaurus/logger": "2.0.0-beta.15", - "@mdx-js/runtime": "^1.6.22", - "@svgr/webpack": "^6.0.0", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "github-slugger": "^1.4.0", - "globby": "^11.0.4", - "gray-matter": "^4.0.3", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "micromatch": "^4.0.4", - "remark-mdx-remove-exports": "^1.6.22", - "remark-mdx-remove-imports": "^1.6.22", - "resolve-pathname": "^3.0.0", - "tslib": "^2.3.1", - "url-loader": "^4.1.1" - } - } - } - } - } + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser/node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "node_modules/tiny-invariant": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz", + "integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg==" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/to-vfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/to-vfile/-/to-vfile-6.1.0.tgz", + "integrity": "sha512-BxX8EkCxOAZe+D/ToHdDsJcVI4HqQfmw0tCkp31zf3dNP/XWIAjU4CmeuSwsSoOzOTqHPOL0KUzyZqJplkD0Qw==", + "dependencies": { + "is-buffer": "^2.0.0", + "vfile": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", + "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/tslib": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", + "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz", + "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ua-parser-js": { + "version": "1.0.37", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.37.tgz", + "integrity": "sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" }, - "@docusaurus/plugin-sitemap": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.0.0-beta.15.tgz", - "integrity": "sha512-PBjeQb2Qpe4uPdRefWL/eXCeYjrgNB/UArExYeUuP4wiY1dpw2unGNCvFUxv4hzJGmARoTLsnRkeYkUim809LQ==", - "requires": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@docusaurus/utils-common": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", - "fs-extra": "^10.0.0", - "sitemap": "^7.0.0", - "tslib": "^2.3.1" - }, - "dependencies": { - "@docusaurus/utils": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.0.0-beta.15.tgz", - "integrity": "sha512-xkoPmFxCBkDqbZR4U3SE752OcXtWTGgZnc/pZWxItzb1IYRGNZHrzdIr7CnI7rppriuZzsyivDGiC4Ud9MWhkA==", - "requires": { - "@docusaurus/logger": "2.0.0-beta.15", - "@mdx-js/runtime": "^1.6.22", - "@svgr/webpack": "^6.0.0", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "github-slugger": "^1.4.0", - "globby": "^11.0.4", - "gray-matter": "^4.0.3", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "micromatch": "^4.0.4", - "remark-mdx-remove-exports": "^1.6.22", - "remark-mdx-remove-imports": "^1.6.22", - "resolve-pathname": "^3.0.0", - "tslib": "^2.3.1", - "url-loader": "^4.1.1" - } - }, - "@docusaurus/utils-validation": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.15.tgz", - "integrity": "sha512-1oOVBCkRrsTXSYrBTsMdnj3a/R56zrx11rjF4xo0+dmm8C01Xw4msFtc3uA7VLX0HQvgHsk8xPzU5GERNdsNpg==", - "requires": { - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "joi": "^17.4.2", - "tslib": "^2.3.1" - } - } - } + { + "type": "paypal", + "url": "https://paypal.me/faisalman" }, - "@docusaurus/theme-classic": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-2.0.0-beta.15.tgz", - "integrity": "sha512-WwNRcQvMtQ7KDhOEHFKFHxXCdoZwLg66hT3vhqNIFMfGQuPzOP91MX5LUSo1QWHhlrD3H3Og+r7Ik/fy2bf5lQ==", - "requires": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/plugin-content-blog": "2.0.0-beta.15", - "@docusaurus/plugin-content-docs": "2.0.0-beta.15", - "@docusaurus/plugin-content-pages": "2.0.0-beta.15", - "@docusaurus/theme-common": "2.0.0-beta.15", - "@docusaurus/theme-translations": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@docusaurus/utils-common": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", - "@mdx-js/react": "^1.6.21", - "clsx": "^1.1.1", - "copy-text-to-clipboard": "^3.0.1", - "infima": "0.2.0-alpha.37", - "lodash": "^4.17.20", - "postcss": "^8.3.7", - "prism-react-renderer": "^1.2.1", - "prismjs": "^1.23.0", - "react-router-dom": "^5.2.0", - "rtlcss": "^3.3.0" - }, - "dependencies": { - "@docusaurus/utils": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.0.0-beta.15.tgz", - "integrity": "sha512-xkoPmFxCBkDqbZR4U3SE752OcXtWTGgZnc/pZWxItzb1IYRGNZHrzdIr7CnI7rppriuZzsyivDGiC4Ud9MWhkA==", - "requires": { - "@docusaurus/logger": "2.0.0-beta.15", - "@mdx-js/runtime": "^1.6.22", - "@svgr/webpack": "^6.0.0", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "github-slugger": "^1.4.0", - "globby": "^11.0.4", - "gray-matter": "^4.0.3", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "micromatch": "^4.0.4", - "remark-mdx-remove-exports": "^1.6.22", - "remark-mdx-remove-imports": "^1.6.22", - "resolve-pathname": "^3.0.0", - "tslib": "^2.3.1", - "url-loader": "^4.1.1" - } - }, - "@docusaurus/utils-validation": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.15.tgz", - "integrity": "sha512-1oOVBCkRrsTXSYrBTsMdnj3a/R56zrx11rjF4xo0+dmm8C01Xw4msFtc3uA7VLX0HQvgHsk8xPzU5GERNdsNpg==", - "requires": { - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "joi": "^17.4.2", - "tslib": "^2.3.1" - } - }, - "react-router-dom": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.0.tgz", - "integrity": "sha512-ObVBLjUZsphUUMVycibxgMdh5jJ1e3o+KpAZBVeHcNQZ4W+uUGGWsokurzlF4YOldQYRQL4y6yFRWM4m3svmuQ==", - "requires": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "loose-envify": "^1.3.1", - "prop-types": "^15.6.2", - "react-router": "5.2.1", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - }, - "dependencies": { - "react-router": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.1.tgz", - "integrity": "sha512-lIboRiOtDLFdg1VTemMwud9vRVuOCZmUIT/7lUoZiSpPODiiH1UQlfXy+vPLC/7IWdFYnhRwAyNqA/+I7wnvKQ==", - "requires": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "hoist-non-react-statics": "^3.1.0", - "loose-envify": "^1.3.1", - "mini-create-react-context": "^0.4.0", - "path-to-regexp": "^1.7.0", - "prop-types": "^15.6.2", - "react-is": "^16.6.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - }, - "dependencies": { - "mini-create-react-context": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", - "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", - "requires": { - "@babel/runtime": "^7.12.1", - "tiny-warning": "^1.0.3" - } - } - } - } - } - } - } - }, - "@docusaurus/theme-common": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.0.0-beta.15.tgz", - "integrity": "sha512-+pvarmzcyECE4nWxw+dCMKRIoes0NegrRuM9+nRsUrS/E5ywsF539kpupKIEqaMjq6AuM0CJtDoHxHHPNe0KaQ==", - "requires": { - "@docusaurus/plugin-content-blog": "2.0.0-beta.15", - "@docusaurus/plugin-content-docs": "2.0.0-beta.15", - "@docusaurus/plugin-content-pages": "2.0.0-beta.15", - "clsx": "^1.1.1", - "parse-numeric-range": "^1.3.0", - "tslib": "^2.3.1", - "utility-types": "^3.10.0" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" - }, - "cheerio": { - "version": "1.0.0-rc.10", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", - "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", - "requires": { - "cheerio-select": "^1.5.0", - "dom-serializer": "^1.3.2", - "domhandler": "^4.2.0", - "htmlparser2": "^6.1.0", - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "tslib": "^2.2.0" - } + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dependencies": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-emoji-modifier-base": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", + "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unified": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.2.tgz", + "integrity": "sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ==", + "dependencies": { + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^2.0.0", + "trough": "^1.0.0", + "vfile": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unique-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "dependencies": { + "crypto-random-string": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unist-util-find-after": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-3.0.0.tgz", + "integrity": "sha512-ojlBqfsBftYXExNu3+hHLfJQ/X1jYY/9vdm4yZWjIbf0VuWF6CRufci1ZyoD/wV2TYMKxXUoNuoqwy+CkgzAiQ==", + "dependencies": { + "unist-util-is": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", + "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", + "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position-from-estree/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/unist-util-position/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/unist-util-remove-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/unist-util-remove-position/node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position/node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position/node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", + "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", + "dependencies": { + "@types/unist": "^2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", + "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0", + "unist-util-visit-parents": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" }, - "dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - } + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" }, - "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/update-notifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz", + "integrity": "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==", + "dependencies": { + "boxen": "^7.0.0", + "chalk": "^5.0.1", + "configstore": "^6.0.0", + "has-yarn": "^3.0.0", + "import-lazy": "^4.0.0", + "is-ci": "^3.0.1", + "is-installed-globally": "^0.4.0", + "is-npm": "^6.0.0", + "is-yarn-global": "^0.4.0", + "latest-version": "^7.0.0", + "pupa": "^3.1.0", + "semver": "^7.3.7", + "semver-diff": "^4.0.0", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uri-js/node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "dependencies": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "file-loader": "*", + "webpack": "^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "file-loader": { + "optional": true + } + } + }, + "node_modules/url-loader/node_modules/mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/url-loader/node_modules/mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "dependencies": { + "mime-db": "1.51.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/url-loader/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/use-composed-ref": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.3.0.tgz", + "integrity": "sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-latest": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.1.tgz", + "integrity": "sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==", + "dependencies": { + "use-isomorphic-layout-effect": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" + }, + "node_modules/utility-types": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", + "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==" + }, + "node_modules/value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vfile": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", + "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^2.0.0", + "vfile-message": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.2.0.tgz", + "integrity": "sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/wait-on": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.2.0.tgz", + "integrity": "sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ==", + "dependencies": { + "axios": "^1.6.1", + "joi": "^17.11.0", + "lodash": "^4.17.21", + "minimist": "^1.2.8", + "rxjs": "^7.8.1" + }, + "bin": { + "wait-on": "bin/wait-on" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/web-namespaces": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.4.tgz", + "integrity": "sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/webpack": { + "version": "5.94.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", + "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", + "dependencies": { + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.7.1", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-bundle-analyzer": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.1.tgz", + "integrity": "sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ==", + "dependencies": { + "@discoveryjs/json-ext": "0.5.7", + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", + "gzip-size": "^6.0.0", + "html-escaper": "^2.0.2", + "is-plain-object": "^5.0.0", + "opener": "^1.5.2", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-middleware/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-middleware/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", + "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack/node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/webpack/node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/webpack/node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/webpack/node_modules/mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack/node_modules/mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "dependencies": { + "mime-db": "1.51.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack/node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpackbar": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-5.0.2.tgz", + "integrity": "sha512-BmFJo7veBDgQzfWXl/wwYXr/VFus0614qZ8i9znqcl9fnEdiVkdbi0TedLQ6xAK92HZHDJ0QmyQ0fmuZPAgCYQ==", + "dependencies": { + "chalk": "^4.1.0", + "consola": "^2.15.3", + "pretty-time": "^1.1.0", + "std-env": "^3.0.1" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "webpack": "3 || 4 || 5" + } + }, + "node_modules/webpackbar/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/webpackbar/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/webpackbar/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/webpackbar/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/webpackbar/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/webpackbar/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/widest-line/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/widest-line/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/widest-line/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/widest-line/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==" + }, + "node_modules/word-wrap": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zwitch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", + "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + }, + "dependencies": { + "@algolia/autocomplete-core": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.9.3.tgz", + "integrity": "sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==", + "requires": { + "@algolia/autocomplete-plugin-algolia-insights": "1.9.3", + "@algolia/autocomplete-shared": "1.9.3" + } + }, + "@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.9.3.tgz", + "integrity": "sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg==", + "requires": { + "@algolia/autocomplete-shared": "1.9.3" + } + }, + "@algolia/autocomplete-preset-algolia": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.9.3.tgz", + "integrity": "sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA==", + "requires": { + "@algolia/autocomplete-shared": "1.9.3" + } + }, + "@algolia/autocomplete-shared": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.9.3.tgz", + "integrity": "sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==", + "requires": {} + }, + "@algolia/cache-browser-local-storage": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.20.0.tgz", + "integrity": "sha512-uujahcBt4DxduBTvYdwO3sBfHuJvJokiC3BP1+O70fglmE1ShkH8lpXqZBac1rrU3FnNYSUs4pL9lBdTKeRPOQ==", + "requires": { + "@algolia/cache-common": "4.20.0" + } + }, + "@algolia/cache-common": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.20.0.tgz", + "integrity": "sha512-vCfxauaZutL3NImzB2G9LjLt36vKAckc6DhMp05An14kVo8F1Yofb6SIl6U3SaEz8pG2QOB9ptwM5c+zGevwIQ==" + }, + "@algolia/cache-in-memory": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.20.0.tgz", + "integrity": "sha512-Wm9ak/IaacAZXS4mB3+qF/KCoVSBV6aLgIGFEtQtJwjv64g4ePMapORGmCyulCFwfePaRAtcaTbMcJF+voc/bg==", + "requires": { + "@algolia/cache-common": "4.20.0" + } + }, + "@algolia/client-account": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.20.0.tgz", + "integrity": "sha512-GGToLQvrwo7am4zVkZTnKa72pheQeez/16sURDWm7Seyz+HUxKi3BM6fthVVPUEBhtJ0reyVtuK9ArmnaKl10Q==", + "requires": { + "@algolia/client-common": "4.20.0", + "@algolia/client-search": "4.20.0", + "@algolia/transporter": "4.20.0" + } + }, + "@algolia/client-analytics": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.20.0.tgz", + "integrity": "sha512-EIr+PdFMOallRdBTHHdKI3CstslgLORQG7844Mq84ib5oVFRVASuuPmG4bXBgiDbcsMLUeOC6zRVJhv1KWI0ug==", + "requires": { + "@algolia/client-common": "4.20.0", + "@algolia/client-search": "4.20.0", + "@algolia/requester-common": "4.20.0", + "@algolia/transporter": "4.20.0" + } + }, + "@algolia/client-common": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.20.0.tgz", + "integrity": "sha512-P3WgMdEss915p+knMMSd/fwiHRHKvDu4DYRrCRaBrsfFw7EQHon+EbRSm4QisS9NYdxbS04kcvNoavVGthyfqQ==", + "requires": { + "@algolia/requester-common": "4.20.0", + "@algolia/transporter": "4.20.0" + } + }, + "@algolia/client-personalization": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.20.0.tgz", + "integrity": "sha512-N9+zx0tWOQsLc3K4PVRDV8GUeOLAY0i445En79Pr3zWB+m67V+n/8w4Kw1C5LlbHDDJcyhMMIlqezh6BEk7xAQ==", + "requires": { + "@algolia/client-common": "4.20.0", + "@algolia/requester-common": "4.20.0", + "@algolia/transporter": "4.20.0" + } + }, + "@algolia/client-search": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.20.0.tgz", + "integrity": "sha512-zgwqnMvhWLdpzKTpd3sGmMlr4c+iS7eyyLGiaO51zDZWGMkpgoNVmltkzdBwxOVXz0RsFMznIxB9zuarUv4TZg==", + "requires": { + "@algolia/client-common": "4.20.0", + "@algolia/requester-common": "4.20.0", + "@algolia/transporter": "4.20.0" + } + }, + "@algolia/events": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@algolia/events/-/events-4.0.1.tgz", + "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==" + }, + "@algolia/logger-common": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.20.0.tgz", + "integrity": "sha512-xouigCMB5WJYEwvoWW5XDv7Z9f0A8VoXJc3VKwlHJw/je+3p2RcDXfksLI4G4lIVncFUYMZx30tP/rsdlvvzHQ==" + }, + "@algolia/logger-console": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.20.0.tgz", + "integrity": "sha512-THlIGG1g/FS63z0StQqDhT6bprUczBI8wnLT3JWvfAQDZX5P6fCg7dG+pIrUBpDIHGszgkqYEqECaKKsdNKOUA==", + "requires": { + "@algolia/logger-common": "4.20.0" + } + }, + "@algolia/requester-browser-xhr": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.20.0.tgz", + "integrity": "sha512-HbzoSjcjuUmYOkcHECkVTwAelmvTlgs48N6Owt4FnTOQdwn0b8pdht9eMgishvk8+F8bal354nhx/xOoTfwiAw==", + "requires": { + "@algolia/requester-common": "4.20.0" + } + }, + "@algolia/requester-common": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.20.0.tgz", + "integrity": "sha512-9h6ye6RY/BkfmeJp7Z8gyyeMrmmWsMOCRBXQDs4mZKKsyVlfIVICpcSibbeYcuUdurLhIlrOUkH3rQEgZzonng==" + }, + "@algolia/requester-node-http": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.20.0.tgz", + "integrity": "sha512-ocJ66L60ABSSTRFnCHIEZpNHv6qTxsBwJEPfYaSBsLQodm0F9ptvalFkHMpvj5DfE22oZrcrLbOYM2bdPJRHng==", + "requires": { + "@algolia/requester-common": "4.20.0" + } + }, + "@algolia/transporter": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.20.0.tgz", + "integrity": "sha512-Lsii1pGWOAISbzeyuf+r/GPhvHMPHSPrTDWNcIzOE1SG1inlJHICaVe2ikuoRjcpgxZNU54Jl+if15SUCsaTUg==", + "requires": { + "@algolia/cache-common": "4.20.0", + "@algolia/logger-common": "4.20.0", + "@algolia/requester-common": "4.20.0" + } + }, + "@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@babel/code-frame": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.4.tgz", + "integrity": "sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==", + "requires": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + } + }, + "@babel/compat-data": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz", + "integrity": "sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==" + }, + "@babel/core": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.3.tgz", + "integrity": "sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==", + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.2", + "@babel/parser": "^7.23.3", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.3", + "@babel/types": "^7.23.3", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/eslint-parser": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.23.3.tgz", + "integrity": "sha512-9bTuNlyx7oSstodm1cR1bECj4fkiknsDa1YniISkJemMY3DGhJNYBECbe6QD/q54mp2J8VO66jW3/7uP//iFCw==", + "requires": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.1" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==" + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/generator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.4.tgz", + "integrity": "sha512-esuS49Cga3HcThFNebGhlgsrVLkvhqvYDTzgjfFFlHJcIfLe5jFmRRfCQ1KuBfc4Jrtn3ndLgKWAKjBE+IraYQ==", + "requires": { + "@babel/types": "^7.23.4", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "requires": { + "@babel/types": "^7.22.15" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "requires": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz", + "integrity": "sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.3.tgz", + "integrity": "sha512-WBrLmuPP47n7PNwsZ57pqam6G/RGo1vw/87b0Blc53tZNGZ4x7YvZ6HgQe2vo1W/FR20OgjeZuGXzudPiXHFug==", + "requires": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==" + }, + "@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "requires": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "requires": { + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "requires": { + "@babel/types": "^7.22.15" + } + }, + "@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" + } + }, + "@babel/helper-replace-supers": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", + "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5" + } + }, + "@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==" + }, + "@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" + }, + "@babel/helper-validator-option": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==" + }, + "@babel/helper-wrap-function": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", + "requires": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" + } + }, + "@babel/helpers": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.4.tgz", + "integrity": "sha512-HfcMizYz10cr3h29VqyfGL6ZWIjTwWfvYBMsBVGwpcbhNGe3wQ1ZXZRPzZoAHhd9OqHadHqjQ89iVKINXnbzuw==", + "requires": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.4", + "@babel/types": "^7.23.4" + } + }, + "@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "requires": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.4.tgz", + "integrity": "sha512-vf3Xna6UEprW+7t6EtOmFpHNAuxw3xqPZghy+brsnusscJRW5BMUzzHZc5ICjULee81WeUV2jjakG09MDglJXQ==" + }, + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.23.3.tgz", + "integrity": "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz", + "integrity": "sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.23.3" + } + }, + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.3.tgz", + "integrity": "sha512-XaJak1qcityzrX0/IU5nKHb34VaibwP3saKqG6a/tppelgllOH13LUann4ZCIBcVOeE6H18K4Vx9QKkVww3z/w==", + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "requires": {} + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz", + "integrity": "sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-syntax-import-attributes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.23.3.tgz", + "integrity": "sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz", + "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz", + "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz", + "integrity": "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-async-generator-functions": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.4.tgz", + "integrity": "sha512-efdkfPhHYTtn0G6n2ddrESE91fgXxjlqLsnUtPWnJs4a4mZIbUaK7ffqKIIUKXSHwcDvaCVX6GXkaJJFqtX7jw==", + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20", + "@babel/plugin-syntax-async-generators": "^7.8.4" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", + "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", + "requires": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz", + "integrity": "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz", + "integrity": "sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-class-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.23.3.tgz", + "integrity": "sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-class-static-block": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.23.4.tgz", + "integrity": "sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.3.tgz", + "integrity": "sha512-FGEQmugvAEu2QtgtU0uTASXevfLMFfBeVCIIdcQhn/uBQsMTjBajdnAtanQlOcuihWh10PZ7+HWvc7NtBwP74w==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz", + "integrity": "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.15" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz", + "integrity": "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz", + "integrity": "sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz", + "integrity": "sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-dynamic-import": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.23.4.tgz", + "integrity": "sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz", + "integrity": "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==", + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-export-namespace-from": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.4.tgz", + "integrity": "sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.3.tgz", + "integrity": "sha512-X8jSm8X1CMwxmK878qsUGJRmbysKNbdpTv/O1/v0LuY/ZkZrng5WYiekYSdg9m09OTmDDUWeEDsTE+17WYbAZw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz", + "integrity": "sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==", + "requires": { + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-json-strings": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.23.4.tgz", + "integrity": "sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz", + "integrity": "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-logical-assignment-operators": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.23.4.tgz", + "integrity": "sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz", + "integrity": "sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz", + "integrity": "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==", + "requires": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", + "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", + "requires": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.3.tgz", + "integrity": "sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==", + "requires": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz", + "integrity": "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==", + "requires": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz", + "integrity": "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.4.tgz", + "integrity": "sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-transform-numeric-separator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.23.4.tgz", + "integrity": "sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-transform-object-rest-spread": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz", + "integrity": "sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==", + "requires": { + "@babel/compat-data": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.23.3" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz", + "integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20" + } + }, + "@babel/plugin-transform-optional-catch-binding": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.23.4.tgz", + "integrity": "sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-transform-optional-chaining": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz", + "integrity": "sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz", + "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-private-methods": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.23.3.tgz", + "integrity": "sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-private-property-in-object": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.4.tgz", + "integrity": "sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz", + "integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-react-constant-elements": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.23.3.tgz", + "integrity": "sha512-zP0QKq/p6O42OL94udMgSfKXyse4RyJ0JqbQ34zDAONWjyrEsghYEyTSK5FIpmXmCpB55SHokL1cRRKHv8L2Qw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-react-display-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.22.5.tgz", + "integrity": "sha512-PVk3WPYudRF5z4GKMEYUrLjPl38fJSKNaEOkFuoprioowGuWN6w2RKznuFNSlJx7pzzXXStPUnNSOEO0jL5EVw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-react-jsx": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.5.tgz", + "integrity": "sha512-rog5gZaVbUip5iWDMTYbVM15XQq+RkUKhET/IHR6oizR+JEoN6CAfTTuHcK4vwUyzca30qqHqEpzBOnaRMWYMA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.22.5", + "@babel/types": "^7.22.5" + } + }, + "@babel/plugin-transform-react-jsx-development": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz", + "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==", + "requires": { + "@babel/plugin-transform-react-jsx": "^7.22.5" + } + }, + "@babel/plugin-transform-react-pure-annotations": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.22.5.tgz", + "integrity": "sha512-gP4k85wx09q+brArVinTXhWiyzLl9UpmGva0+mWyKxk6JZequ05x3eUcIUE+FyttPKJFRRVtAvQaJ6YF9h1ZpA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz", + "integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.2" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz", + "integrity": "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.23.4.tgz", + "integrity": "sha512-ITwqpb6V4btwUG0YJR82o2QvmWrLgDnx/p2A3CTPYGaRgULkDiC0DRA2C4jlRB9uXGUEfaSS/IGHfVW+ohzYDw==", + "requires": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "babel-plugin-polyfill-corejs2": "^0.4.6", + "babel-plugin-polyfill-corejs3": "^0.8.5", + "babel-plugin-polyfill-regenerator": "^0.5.3", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz", + "integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz", + "integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz", + "integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz", + "integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz", + "integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.22.5.tgz", + "integrity": "sha512-SMubA9S7Cb5sGSFFUlqxyClTA9zWJ8qGQrppNUm05LtFuN1ELRFNndkix4zUJrC9F+YivWwa1dHMSyo0e0N9dA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-typescript": "^7.22.5" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz", + "integrity": "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-unicode-property-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.23.3.tgz", + "integrity": "sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz", + "integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-unicode-sets-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.23.3.tgz", + "integrity": "sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/preset-env": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.3.tgz", + "integrity": "sha512-ovzGc2uuyNfNAs/jyjIGxS8arOHS5FENZaNn4rtE7UdKMMkqHCvboHfcuhWLZNX5cB44QfcGNWjaevxMzzMf+Q==", + "requires": { + "@babel/compat-data": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.3", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.23.3", + "@babel/plugin-syntax-import-attributes": "^7.23.3", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.23.3", + "@babel/plugin-transform-async-generator-functions": "^7.23.3", + "@babel/plugin-transform-async-to-generator": "^7.23.3", + "@babel/plugin-transform-block-scoped-functions": "^7.23.3", + "@babel/plugin-transform-block-scoping": "^7.23.3", + "@babel/plugin-transform-class-properties": "^7.23.3", + "@babel/plugin-transform-class-static-block": "^7.23.3", + "@babel/plugin-transform-classes": "^7.23.3", + "@babel/plugin-transform-computed-properties": "^7.23.3", + "@babel/plugin-transform-destructuring": "^7.23.3", + "@babel/plugin-transform-dotall-regex": "^7.23.3", + "@babel/plugin-transform-duplicate-keys": "^7.23.3", + "@babel/plugin-transform-dynamic-import": "^7.23.3", + "@babel/plugin-transform-exponentiation-operator": "^7.23.3", + "@babel/plugin-transform-export-namespace-from": "^7.23.3", + "@babel/plugin-transform-for-of": "^7.23.3", + "@babel/plugin-transform-function-name": "^7.23.3", + "@babel/plugin-transform-json-strings": "^7.23.3", + "@babel/plugin-transform-literals": "^7.23.3", + "@babel/plugin-transform-logical-assignment-operators": "^7.23.3", + "@babel/plugin-transform-member-expression-literals": "^7.23.3", + "@babel/plugin-transform-modules-amd": "^7.23.3", + "@babel/plugin-transform-modules-commonjs": "^7.23.3", + "@babel/plugin-transform-modules-systemjs": "^7.23.3", + "@babel/plugin-transform-modules-umd": "^7.23.3", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.23.3", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.3", + "@babel/plugin-transform-numeric-separator": "^7.23.3", + "@babel/plugin-transform-object-rest-spread": "^7.23.3", + "@babel/plugin-transform-object-super": "^7.23.3", + "@babel/plugin-transform-optional-catch-binding": "^7.23.3", + "@babel/plugin-transform-optional-chaining": "^7.23.3", + "@babel/plugin-transform-parameters": "^7.23.3", + "@babel/plugin-transform-private-methods": "^7.23.3", + "@babel/plugin-transform-private-property-in-object": "^7.23.3", + "@babel/plugin-transform-property-literals": "^7.23.3", + "@babel/plugin-transform-regenerator": "^7.23.3", + "@babel/plugin-transform-reserved-words": "^7.23.3", + "@babel/plugin-transform-shorthand-properties": "^7.23.3", + "@babel/plugin-transform-spread": "^7.23.3", + "@babel/plugin-transform-sticky-regex": "^7.23.3", + "@babel/plugin-transform-template-literals": "^7.23.3", + "@babel/plugin-transform-typeof-symbol": "^7.23.3", + "@babel/plugin-transform-unicode-escapes": "^7.23.3", + "@babel/plugin-transform-unicode-property-regex": "^7.23.3", + "@babel/plugin-transform-unicode-regex": "^7.23.3", + "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.6", + "babel-plugin-polyfill-corejs3": "^0.8.5", + "babel-plugin-polyfill-regenerator": "^0.5.3", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/preset-react": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.22.5.tgz", + "integrity": "sha512-M+Is3WikOpEJHgR385HbuCITPTaPRaNkibTEa9oiofmJvIsrceb4yp9RL9Kb+TE8LznmeyZqpP+Lopwcx59xPQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.5", + "@babel/plugin-transform-react-display-name": "^7.22.5", + "@babel/plugin-transform-react-jsx": "^7.22.5", + "@babel/plugin-transform-react-jsx-development": "^7.22.5", + "@babel/plugin-transform-react-pure-annotations": "^7.22.5" + } + }, + "@babel/preset-typescript": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.22.5.tgz", + "integrity": "sha512-YbPaal9LxztSGhmndR46FmAbkJ/1fAsw293tSU+I5E5h+cnJ3d4GTwyUgGYmOXJYdGA+uNePle4qbaRzj2NISQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.22.5", + "@babel/plugin-transform-modules-commonjs": "^7.22.5", + "@babel/plugin-transform-typescript": "^7.22.5" + } + }, + "@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" + }, + "@babel/runtime": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.4.tgz", + "integrity": "sha512-2Yv65nlWnWlSpe3fXEyX5i7fx5kIKo4Qbcj+hMO0odwaneFjfXw5fdum+4yL20O0QiaHpia0cYQ9xpNMqrBwHg==", + "requires": { + "regenerator-runtime": "^0.14.0" + } + }, + "@babel/runtime-corejs3": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.23.4.tgz", + "integrity": "sha512-zQyB4MJGM+rvd4pM58n26kf3xbiitw9MHzL8oLiBMKb8MCtVDfV5nDzzJWWzLMtbvKI9wN6XwJYl479qF4JluQ==", + "requires": { + "core-js-pure": "^3.30.2", + "regenerator-runtime": "^0.14.0" + } + }, + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + }, + "@babel/traverse": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.4.tgz", + "integrity": "sha512-IYM8wSUwunWTB6tFC2dkKZhxbIjHoWemdK+3f8/wq8aKhbUscxD5MX72ubd90fxvFknaLPeGw5ycU84V1obHJg==", + "requires": { + "@babel/code-frame": "^7.23.4", + "@babel/generator": "^7.23.4", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.4", + "@babel/types": "^7.23.4", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.4.tgz", + "integrity": "sha512-7uIFwVYpoplT5jp/kVv6EF93VaJ8H+Yn5IczYiaAi98ajzjfoZfslet/e0sLh+wVBjb2qqIut1b0S26VSafsSQ==", + "requires": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + } + }, + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "optional": true + }, + "@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==" + }, + "@docsearch/css": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.5.2.tgz", + "integrity": "sha512-SPiDHaWKQZpwR2siD0KQUwlStvIAnEyK6tAE2h2Wuoq8ue9skzhlyVQ1ddzOxX6khULnAALDiR/isSF3bnuciA==" + }, + "@docsearch/react": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.5.2.tgz", + "integrity": "sha512-9Ahcrs5z2jq/DcAvYtvlqEBHImbm4YJI8M9y0x6Tqg598P40HTEkX7hsMcIuThI+hTFxRGZ9hll0Wygm2yEjng==", + "requires": { + "@algolia/autocomplete-core": "1.9.3", + "@algolia/autocomplete-preset-algolia": "1.9.3", + "@docsearch/css": "3.5.2", + "algoliasearch": "^4.19.1" + } + }, + "@docusaurus/core": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.0.0.tgz", + "integrity": "sha512-bHWtY55tJTkd6pZhHrWz1MpWuwN4edZe0/UWgFF7PW/oJeDZvLSXKqwny3L91X1/LGGoypBGkeZn8EOuKeL4yQ==", + "requires": { + "@babel/core": "^7.22.9", + "@babel/generator": "^7.22.9", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.22.9", + "@babel/preset-env": "^7.22.9", + "@babel/preset-react": "^7.22.5", + "@babel/preset-typescript": "^7.22.5", + "@babel/runtime": "^7.22.6", + "@babel/runtime-corejs3": "^7.22.6", + "@babel/traverse": "^7.22.8", + "@docusaurus/cssnano-preset": "3.0.0", + "@docusaurus/logger": "3.0.0", + "@docusaurus/mdx-loader": "3.0.0", + "@docusaurus/react-loadable": "5.5.2", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-common": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "@slorber/static-site-generator-webpack-plugin": "^4.0.7", + "@svgr/webpack": "^6.5.1", + "autoprefixer": "^10.4.14", + "babel-loader": "^9.1.3", + "babel-plugin-dynamic-import-node": "^2.3.3", + "boxen": "^6.2.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "clean-css": "^5.3.2", + "cli-table3": "^0.6.3", + "combine-promises": "^1.1.0", + "commander": "^5.1.0", + "copy-webpack-plugin": "^11.0.0", + "core-js": "^3.31.1", + "css-loader": "^6.8.1", + "css-minimizer-webpack-plugin": "^4.2.2", + "cssnano": "^5.1.15", + "del": "^6.1.1", + "detect-port": "^1.5.1", + "escape-html": "^1.0.3", + "eta": "^2.2.0", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "html-minifier-terser": "^7.2.0", + "html-tags": "^3.3.1", + "html-webpack-plugin": "^5.5.3", + "leven": "^3.1.0", + "lodash": "^4.17.21", + "mini-css-extract-plugin": "^2.7.6", + "postcss": "^8.4.26", + "postcss-loader": "^7.3.3", + "prompts": "^2.4.2", + "react-dev-utils": "^12.0.1", + "react-helmet-async": "^1.3.0", + "react-loadable": "npm:@docusaurus/react-loadable@5.5.2", + "react-loadable-ssr-addon-v5-slorber": "^1.0.1", + "react-router": "^5.3.4", + "react-router-config": "^5.1.1", + "react-router-dom": "^5.3.4", + "rtl-detect": "^1.0.4", + "semver": "^7.5.4", + "serve-handler": "^6.1.5", + "shelljs": "^0.8.5", + "terser-webpack-plugin": "^5.3.9", + "tslib": "^2.6.0", + "update-notifier": "^6.0.2", + "url-loader": "^4.1.1", + "wait-on": "^7.0.1", + "webpack": "^5.88.1", + "webpack-bundle-analyzer": "^4.9.0", + "webpack-dev-server": "^4.15.1", + "webpack-merge": "^5.9.0", + "webpackbar": "^5.0.2" + }, + "dependencies": { + "@docusaurus/mdx-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.0.0.tgz", + "integrity": "sha512-JkGge6WYDrwjNgMxwkb6kNQHnpISt5L1tMaBWFDBKeDToFr5Kj29IL35MIQm0RfrnoOfr/29RjSH4aRtvlAR0A==", + "requires": { + "@babel/parser": "^7.22.7", + "@babel/traverse": "^7.22.8", + "@docusaurus/logger": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "@mdx-js/mdx": "^3.0.0", + "@slorber/remark-comment": "^1.0.0", + "escape-html": "^1.0.3", + "estree-util-value-to-estree": "^3.0.1", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "image-size": "^1.0.2", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-string": "^4.0.0", + "rehype-raw": "^7.0.0", + "remark-directive": "^3.0.0", + "remark-emoji": "^4.0.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0", + "stringify-object": "^3.3.0", + "tslib": "^2.6.0", + "unified": "^11.0.3", + "unist-util-visit": "^5.0.0", + "url-loader": "^4.1.1", + "vfile": "^6.0.1", + "webpack": "^5.88.1" + } + }, + "@docusaurus/utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.0.0.tgz", + "integrity": "sha512-JwGjh5mtjG9XIAESyPxObL6CZ6LO/yU4OSTpq7Q0x+jN25zi/AMbvLjpSyZzWy+qm5uQiFiIhqFaOxvy+82Ekg==", + "requires": { + "@docusaurus/logger": "3.0.0", + "@svgr/webpack": "^6.5.1", + "escape-string-regexp": "^4.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "resolve-pathname": "^3.0.0", + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.88.1" + } + }, + "@docusaurus/utils-common": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.0.0.tgz", + "integrity": "sha512-7iJWAtt4AHf4PFEPlEPXko9LZD/dbYnhLe0q8e3GRK1EXZyRASah2lznpMwB3lLmVjq/FR6ZAKF+E0wlmL5j0g==", + "requires": { + "tslib": "^2.6.0" + } + }, + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==" + }, + "boxen": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-6.2.1.tgz", + "integrity": "sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==", + "requires": { + "ansi-align": "^3.0.1", + "camelcase": "^6.2.0", + "chalk": "^4.1.2", + "cli-boxes": "^3.0.0", + "string-width": "^5.0.1", + "type-fest": "^2.5.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + }, + "react-loadable-ssr-addon-v5-slorber": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.1.tgz", + "integrity": "sha512-lq3Lyw1lGku8zUEJPDxsNm1AfYHBrO9Y1+olAYwpUJ2IGFBskM0DMKok97A6LWUpHm+o7IvQBOWu9MLenp9Z+A==", + "requires": { + "@babel/runtime": "^7.10.3" + } + }, + "react-router-config": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/react-router-config/-/react-router-config-5.1.1.tgz", + "integrity": "sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==", + "requires": { + "@babel/runtime": "^7.1.2" + } + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==" + }, + "type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==" + }, + "unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", + "requires": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + } + }, + "unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + } + }, + "unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + } + }, + "vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + } + }, + "vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + } + } + } + }, + "@docusaurus/cssnano-preset": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.0.0.tgz", + "integrity": "sha512-FHiRfwmVvIVdIGsHcijUOaX7hMn0mugVYB7m4GkpYI6Mi56zwQV4lH5p7DxcW5CUYNWMVxz2loWSCiWEm5ikwA==", + "requires": { + "cssnano-preset-advanced": "^5.3.10", + "postcss": "^8.4.26", + "postcss-sort-media-queries": "^4.4.1", + "tslib": "^2.6.0" + } + }, + "@docusaurus/logger": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.0.0.tgz", + "integrity": "sha512-6eX0eOfioMQCk+qgCnHvbLLuyIAA+r2lSID6d6JusiLtDKmYMfNp3F4yyE8bnb0Abmzt2w68XwptEFYyALSAXw==", + "requires": { + "chalk": "^4.1.2", + "tslib": "^2.6.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@docusaurus/module-type-aliases": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.0.0.tgz", + "integrity": "sha512-CfC6CgN4u/ce+2+L1JdsHNyBd8yYjl4De2B2CBj2a9F7WuJ5RjV1ciuU7KDg8uyju+NRVllRgvJvxVUjCdkPiw==", + "requires": { + "@docusaurus/react-loadable": "5.5.2", + "@docusaurus/types": "3.0.0", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "@types/react-router-dom": "*", + "react-helmet-async": "*", + "react-loadable": "npm:@docusaurus/react-loadable@5.5.2" + } + }, + "@docusaurus/preset-classic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.0.0.tgz", + "integrity": "sha512-90aOKZGZdi0+GVQV+wt8xx4M4GiDrBRke8NO8nWwytMEXNrxrBxsQYFRD1YlISLJSCiHikKf3Z/MovMnQpnZyg==", + "requires": { + "@docusaurus/core": "3.0.0", + "@docusaurus/plugin-content-blog": "3.0.0", + "@docusaurus/plugin-content-docs": "3.0.0", + "@docusaurus/plugin-content-pages": "3.0.0", + "@docusaurus/plugin-debug": "3.0.0", + "@docusaurus/plugin-google-analytics": "3.0.0", + "@docusaurus/plugin-google-gtag": "3.0.0", + "@docusaurus/plugin-google-tag-manager": "3.0.0", + "@docusaurus/plugin-sitemap": "3.0.0", + "@docusaurus/theme-classic": "3.0.0", + "@docusaurus/theme-common": "3.0.0", + "@docusaurus/theme-search-algolia": "3.0.0", + "@docusaurus/types": "3.0.0" + }, + "dependencies": { + "@docusaurus/plugin-content-blog": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.0.0.tgz", + "integrity": "sha512-iA8Wc3tIzVnROJxrbIsU/iSfixHW16YeW9RWsBw7hgEk4dyGsip9AsvEDXobnRq3lVv4mfdgoS545iGWf1Ip9w==", + "requires": { + "@docusaurus/core": "3.0.0", + "@docusaurus/logger": "3.0.0", + "@docusaurus/mdx-loader": "3.0.0", + "@docusaurus/types": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-common": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "cheerio": "^1.0.0-rc.12", + "feed": "^4.2.2", + "fs-extra": "^11.1.1", + "lodash": "^4.17.21", + "reading-time": "^1.5.0", + "srcset": "^4.0.0", + "tslib": "^2.6.0", + "unist-util-visit": "^5.0.0", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" + }, + "dependencies": { + "@docusaurus/mdx-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.0.0.tgz", + "integrity": "sha512-JkGge6WYDrwjNgMxwkb6kNQHnpISt5L1tMaBWFDBKeDToFr5Kj29IL35MIQm0RfrnoOfr/29RjSH4aRtvlAR0A==", + "requires": { + "@babel/parser": "^7.22.7", + "@babel/traverse": "^7.22.8", + "@docusaurus/logger": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "@mdx-js/mdx": "^3.0.0", + "@slorber/remark-comment": "^1.0.0", + "escape-html": "^1.0.3", + "estree-util-value-to-estree": "^3.0.1", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "image-size": "^1.0.2", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-string": "^4.0.0", + "rehype-raw": "^7.0.0", + "remark-directive": "^3.0.0", + "remark-emoji": "^4.0.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0", + "stringify-object": "^3.3.0", + "tslib": "^2.6.0", + "unified": "^11.0.3", + "unist-util-visit": "^5.0.0", + "url-loader": "^4.1.1", + "vfile": "^6.0.1", + "webpack": "^5.88.1" + } + }, + "@docusaurus/utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.0.0.tgz", + "integrity": "sha512-JwGjh5mtjG9XIAESyPxObL6CZ6LO/yU4OSTpq7Q0x+jN25zi/AMbvLjpSyZzWy+qm5uQiFiIhqFaOxvy+82Ekg==", + "requires": { + "@docusaurus/logger": "3.0.0", + "@svgr/webpack": "^6.5.1", + "escape-string-regexp": "^4.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "resolve-pathname": "^3.0.0", + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.88.1" + } + }, + "@docusaurus/utils-common": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.0.0.tgz", + "integrity": "sha512-7iJWAtt4AHf4PFEPlEPXko9LZD/dbYnhLe0q8e3GRK1EXZyRASah2lznpMwB3lLmVjq/FR6ZAKF+E0wlmL5j0g==", + "requires": { + "tslib": "^2.6.0" + } + } + } + }, + "@docusaurus/plugin-content-docs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.0.0.tgz", + "integrity": "sha512-MFZsOSwmeJ6rvoZMLieXxPuJsA9M9vn7/mUZmfUzSUTeHAeq+fEqvLltFOxcj4DVVDTYlQhgWYd+PISIWgamKw==", + "requires": { + "@docusaurus/core": "3.0.0", + "@docusaurus/logger": "3.0.0", + "@docusaurus/mdx-loader": "3.0.0", + "@docusaurus/module-type-aliases": "3.0.0", + "@docusaurus/types": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "@types/react-router-config": "^5.0.7", + "combine-promises": "^1.1.0", + "fs-extra": "^11.1.1", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "tslib": "^2.6.0", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" + }, + "dependencies": { + "@docusaurus/mdx-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.0.0.tgz", + "integrity": "sha512-JkGge6WYDrwjNgMxwkb6kNQHnpISt5L1tMaBWFDBKeDToFr5Kj29IL35MIQm0RfrnoOfr/29RjSH4aRtvlAR0A==", + "requires": { + "@babel/parser": "^7.22.7", + "@babel/traverse": "^7.22.8", + "@docusaurus/logger": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "@mdx-js/mdx": "^3.0.0", + "@slorber/remark-comment": "^1.0.0", + "escape-html": "^1.0.3", + "estree-util-value-to-estree": "^3.0.1", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "image-size": "^1.0.2", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-string": "^4.0.0", + "rehype-raw": "^7.0.0", + "remark-directive": "^3.0.0", + "remark-emoji": "^4.0.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0", + "stringify-object": "^3.3.0", + "tslib": "^2.6.0", + "unified": "^11.0.3", + "unist-util-visit": "^5.0.0", + "url-loader": "^4.1.1", + "vfile": "^6.0.1", + "webpack": "^5.88.1" + } + }, + "@docusaurus/utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.0.0.tgz", + "integrity": "sha512-JwGjh5mtjG9XIAESyPxObL6CZ6LO/yU4OSTpq7Q0x+jN25zi/AMbvLjpSyZzWy+qm5uQiFiIhqFaOxvy+82Ekg==", + "requires": { + "@docusaurus/logger": "3.0.0", + "@svgr/webpack": "^6.5.1", + "escape-string-regexp": "^4.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "resolve-pathname": "^3.0.0", + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.88.1" + } + } + } + }, + "@docusaurus/plugin-content-pages": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.0.0.tgz", + "integrity": "sha512-EXYHXK2Ea1B5BUmM0DgSwaOYt8EMSzWtYUToNo62Q/EoWxYOQFdWglYnw3n7ZEGyw5Kog4LHaRwlazAdmDomvQ==", + "requires": { + "@docusaurus/core": "3.0.0", + "@docusaurus/mdx-loader": "3.0.0", + "@docusaurus/types": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "fs-extra": "^11.1.1", + "tslib": "^2.6.0", + "webpack": "^5.88.1" + }, + "dependencies": { + "@docusaurus/mdx-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.0.0.tgz", + "integrity": "sha512-JkGge6WYDrwjNgMxwkb6kNQHnpISt5L1tMaBWFDBKeDToFr5Kj29IL35MIQm0RfrnoOfr/29RjSH4aRtvlAR0A==", + "requires": { + "@babel/parser": "^7.22.7", + "@babel/traverse": "^7.22.8", + "@docusaurus/logger": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "@mdx-js/mdx": "^3.0.0", + "@slorber/remark-comment": "^1.0.0", + "escape-html": "^1.0.3", + "estree-util-value-to-estree": "^3.0.1", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "image-size": "^1.0.2", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-string": "^4.0.0", + "rehype-raw": "^7.0.0", + "remark-directive": "^3.0.0", + "remark-emoji": "^4.0.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0", + "stringify-object": "^3.3.0", + "tslib": "^2.6.0", + "unified": "^11.0.3", + "unist-util-visit": "^5.0.0", + "url-loader": "^4.1.1", + "vfile": "^6.0.1", + "webpack": "^5.88.1" + } + }, + "@docusaurus/utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.0.0.tgz", + "integrity": "sha512-JwGjh5mtjG9XIAESyPxObL6CZ6LO/yU4OSTpq7Q0x+jN25zi/AMbvLjpSyZzWy+qm5uQiFiIhqFaOxvy+82Ekg==", + "requires": { + "@docusaurus/logger": "3.0.0", + "@svgr/webpack": "^6.5.1", + "escape-string-regexp": "^4.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "resolve-pathname": "^3.0.0", + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.88.1" + } + } + } + }, + "@docusaurus/plugin-debug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.0.0.tgz", + "integrity": "sha512-gSV07HfQgnUboVEb3lucuVyv5pEoy33E7QXzzn++3kSc/NLEimkjXh3sSnTGOishkxCqlFV9BHfY/VMm5Lko5g==", + "requires": { + "@docusaurus/core": "3.0.0", + "@docusaurus/types": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@microlink/react-json-view": "^1.22.2", + "fs-extra": "^11.1.1", + "tslib": "^2.6.0" + }, + "dependencies": { + "@docusaurus/utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.0.0.tgz", + "integrity": "sha512-JwGjh5mtjG9XIAESyPxObL6CZ6LO/yU4OSTpq7Q0x+jN25zi/AMbvLjpSyZzWy+qm5uQiFiIhqFaOxvy+82Ekg==", + "requires": { + "@docusaurus/logger": "3.0.0", + "@svgr/webpack": "^6.5.1", + "escape-string-regexp": "^4.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "resolve-pathname": "^3.0.0", + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.88.1" + } + } + } + }, + "@docusaurus/plugin-google-analytics": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.0.0.tgz", + "integrity": "sha512-0zcLK8w+ohmSm1fjUQCqeRsjmQc0gflvXnaVA/QVVCtm2yCiBtkrSGQXqt4MdpD7Xq8mwo3qVd5nhIcvrcebqw==", + "requires": { + "@docusaurus/core": "3.0.0", + "@docusaurus/types": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "tslib": "^2.6.0" + } + }, + "@docusaurus/plugin-google-gtag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.0.0.tgz", + "integrity": "sha512-asEKavw8fczUqvXu/s9kG2m1epLnHJ19W6CCCRZEmpnkZUZKiM8rlkDiEmxApwIc2JDDbIMk+Y2TMkJI8mInbQ==", + "requires": { + "@docusaurus/core": "3.0.0", + "@docusaurus/types": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "@types/gtag.js": "^0.0.12", + "tslib": "^2.6.0" + } + }, + "@docusaurus/plugin-google-tag-manager": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.0.0.tgz", + "integrity": "sha512-lytgu2eyn+7p4WklJkpMGRhwC29ezj4IjPPmVJ8vGzcSl6JkR1sADTHLG5xWOMuci420xZl9dGEiLTQ8FjCRyA==", + "requires": { + "@docusaurus/core": "3.0.0", + "@docusaurus/types": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "tslib": "^2.6.0" + } + }, + "@docusaurus/plugin-sitemap": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.0.0.tgz", + "integrity": "sha512-cfcONdWku56Oi7Hdus2uvUw/RKRRlIGMViiHLjvQ21CEsEqnQ297MRoIgjU28kL7/CXD/+OiANSq3T1ezAiMhA==", + "requires": { + "@docusaurus/core": "3.0.0", + "@docusaurus/logger": "3.0.0", + "@docusaurus/types": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-common": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "fs-extra": "^11.1.1", + "sitemap": "^7.1.1", + "tslib": "^2.6.0" + }, + "dependencies": { + "@docusaurus/utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.0.0.tgz", + "integrity": "sha512-JwGjh5mtjG9XIAESyPxObL6CZ6LO/yU4OSTpq7Q0x+jN25zi/AMbvLjpSyZzWy+qm5uQiFiIhqFaOxvy+82Ekg==", + "requires": { + "@docusaurus/logger": "3.0.0", + "@svgr/webpack": "^6.5.1", + "escape-string-regexp": "^4.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "resolve-pathname": "^3.0.0", + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.88.1" + } + }, + "@docusaurus/utils-common": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.0.0.tgz", + "integrity": "sha512-7iJWAtt4AHf4PFEPlEPXko9LZD/dbYnhLe0q8e3GRK1EXZyRASah2lznpMwB3lLmVjq/FR6ZAKF+E0wlmL5j0g==", + "requires": { + "tslib": "^2.6.0" + } + } + } + }, + "@docusaurus/theme-classic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.0.0.tgz", + "integrity": "sha512-wWOHSrKMn7L4jTtXBsb5iEJ3xvTddBye5PjYBnWiCkTAlhle2yMdc4/qRXW35Ot+OV/VXu6YFG8XVUJEl99z0A==", + "requires": { + "@docusaurus/core": "3.0.0", + "@docusaurus/mdx-loader": "3.0.0", + "@docusaurus/module-type-aliases": "3.0.0", + "@docusaurus/plugin-content-blog": "3.0.0", + "@docusaurus/plugin-content-docs": "3.0.0", + "@docusaurus/plugin-content-pages": "3.0.0", + "@docusaurus/theme-common": "3.0.0", + "@docusaurus/theme-translations": "3.0.0", + "@docusaurus/types": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-common": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "@mdx-js/react": "^3.0.0", + "clsx": "^1.2.1", + "copy-text-to-clipboard": "^3.2.0", + "infima": "0.2.0-alpha.43", + "lodash": "^4.17.21", + "nprogress": "^0.2.0", + "postcss": "^8.4.26", + "prism-react-renderer": "^2.1.0", + "prismjs": "^1.29.0", + "react-router-dom": "^5.3.4", + "rtlcss": "^4.1.0", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "dependencies": { + "@docusaurus/mdx-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.0.0.tgz", + "integrity": "sha512-JkGge6WYDrwjNgMxwkb6kNQHnpISt5L1tMaBWFDBKeDToFr5Kj29IL35MIQm0RfrnoOfr/29RjSH4aRtvlAR0A==", + "requires": { + "@babel/parser": "^7.22.7", + "@babel/traverse": "^7.22.8", + "@docusaurus/logger": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "@mdx-js/mdx": "^3.0.0", + "@slorber/remark-comment": "^1.0.0", + "escape-html": "^1.0.3", + "estree-util-value-to-estree": "^3.0.1", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "image-size": "^1.0.2", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-string": "^4.0.0", + "rehype-raw": "^7.0.0", + "remark-directive": "^3.0.0", + "remark-emoji": "^4.0.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0", + "stringify-object": "^3.3.0", + "tslib": "^2.6.0", + "unified": "^11.0.3", + "unist-util-visit": "^5.0.0", + "url-loader": "^4.1.1", + "vfile": "^6.0.1", + "webpack": "^5.88.1" + } + }, + "@docusaurus/utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.0.0.tgz", + "integrity": "sha512-JwGjh5mtjG9XIAESyPxObL6CZ6LO/yU4OSTpq7Q0x+jN25zi/AMbvLjpSyZzWy+qm5uQiFiIhqFaOxvy+82Ekg==", + "requires": { + "@docusaurus/logger": "3.0.0", + "@svgr/webpack": "^6.5.1", + "escape-string-regexp": "^4.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "resolve-pathname": "^3.0.0", + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.88.1" + } + }, + "@docusaurus/utils-common": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.0.0.tgz", + "integrity": "sha512-7iJWAtt4AHf4PFEPlEPXko9LZD/dbYnhLe0q8e3GRK1EXZyRASah2lznpMwB3lLmVjq/FR6ZAKF+E0wlmL5j0g==", + "requires": { + "tslib": "^2.6.0" + } + } + } + }, + "@docusaurus/theme-common": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.0.0.tgz", + "integrity": "sha512-PahRpCLRK5owCMEqcNtUeTMOkTUCzrJlKA+HLu7f+8osYOni617YurXvHASCsSTxurjXaLz/RqZMnASnqATxIA==", + "requires": { + "@docusaurus/mdx-loader": "3.0.0", + "@docusaurus/module-type-aliases": "3.0.0", + "@docusaurus/plugin-content-blog": "3.0.0", + "@docusaurus/plugin-content-docs": "3.0.0", + "@docusaurus/plugin-content-pages": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-common": "3.0.0", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "clsx": "^1.2.1", + "parse-numeric-range": "^1.3.0", + "prism-react-renderer": "^2.1.0", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "dependencies": { + "@docusaurus/mdx-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.0.0.tgz", + "integrity": "sha512-JkGge6WYDrwjNgMxwkb6kNQHnpISt5L1tMaBWFDBKeDToFr5Kj29IL35MIQm0RfrnoOfr/29RjSH4aRtvlAR0A==", + "requires": { + "@babel/parser": "^7.22.7", + "@babel/traverse": "^7.22.8", + "@docusaurus/logger": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "@mdx-js/mdx": "^3.0.0", + "@slorber/remark-comment": "^1.0.0", + "escape-html": "^1.0.3", + "estree-util-value-to-estree": "^3.0.1", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "image-size": "^1.0.2", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-string": "^4.0.0", + "rehype-raw": "^7.0.0", + "remark-directive": "^3.0.0", + "remark-emoji": "^4.0.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0", + "stringify-object": "^3.3.0", + "tslib": "^2.6.0", + "unified": "^11.0.3", + "unist-util-visit": "^5.0.0", + "url-loader": "^4.1.1", + "vfile": "^6.0.1", + "webpack": "^5.88.1" + } + }, + "@docusaurus/utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.0.0.tgz", + "integrity": "sha512-JwGjh5mtjG9XIAESyPxObL6CZ6LO/yU4OSTpq7Q0x+jN25zi/AMbvLjpSyZzWy+qm5uQiFiIhqFaOxvy+82Ekg==", + "requires": { + "@docusaurus/logger": "3.0.0", + "@svgr/webpack": "^6.5.1", + "escape-string-regexp": "^4.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "resolve-pathname": "^3.0.0", + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.88.1" + } + }, + "@docusaurus/utils-common": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.0.0.tgz", + "integrity": "sha512-7iJWAtt4AHf4PFEPlEPXko9LZD/dbYnhLe0q8e3GRK1EXZyRASah2lznpMwB3lLmVjq/FR6ZAKF+E0wlmL5j0g==", + "requires": { + "tslib": "^2.6.0" + } + } + } + }, + "@docusaurus/theme-search-algolia": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.0.0.tgz", + "integrity": "sha512-PyMUNIS9yu0dx7XffB13ti4TG47pJq3G2KE/INvOFb6M0kWh+wwCnucPg4WAOysHOPh+SD9fjlXILoLQstgEIA==", + "requires": { + "@docsearch/react": "^3.5.2", + "@docusaurus/core": "3.0.0", + "@docusaurus/logger": "3.0.0", + "@docusaurus/plugin-content-docs": "3.0.0", + "@docusaurus/theme-common": "3.0.0", + "@docusaurus/theme-translations": "3.0.0", + "@docusaurus/utils": "3.0.0", + "@docusaurus/utils-validation": "3.0.0", + "algoliasearch": "^4.18.0", + "algoliasearch-helper": "^3.13.3", + "clsx": "^1.2.1", + "eta": "^2.2.0", + "fs-extra": "^11.1.1", + "lodash": "^4.17.21", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "dependencies": { + "@docusaurus/utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.0.0.tgz", + "integrity": "sha512-JwGjh5mtjG9XIAESyPxObL6CZ6LO/yU4OSTpq7Q0x+jN25zi/AMbvLjpSyZzWy+qm5uQiFiIhqFaOxvy+82Ekg==", + "requires": { + "@docusaurus/logger": "3.0.0", + "@svgr/webpack": "^6.5.1", + "escape-string-regexp": "^4.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "resolve-pathname": "^3.0.0", + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.88.1" + } + } + } + }, + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + }, + "is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + }, + "trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==" + }, + "unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", + "requires": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + } + }, + "unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + } + }, + "unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + } + }, + "vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + } + }, + "vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + } + } + } + }, + "@docusaurus/react-loadable": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", + "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", + "requires": { + "@types/react": "*", + "prop-types": "^15.6.2" + } + }, + "@docusaurus/theme-translations": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.0.0.tgz", + "integrity": "sha512-p/H3+5LdnDtbMU+csYukA6601U1ld2v9knqxGEEV96qV27HsHfP63J9Ta2RBZUrNhQAgrwFzIc9GdDO8P1Baag==", + "requires": { + "fs-extra": "^11.1.1", + "tslib": "^2.6.0" + } + }, + "@docusaurus/types": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.0.0.tgz", + "integrity": "sha512-Qb+l/hmCOVemReuzvvcFdk84bUmUFyD0Zi81y651ie3VwMrXqC7C0E7yZLKMOsLj/vkqsxHbtkAuYMI89YzNzg==", + "requires": { + "@types/history": "^4.7.11", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "^1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.88.1", + "webpack-merge": "^5.9.0" + } + }, + "@docusaurus/utils-validation": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.0.0.tgz", + "integrity": "sha512-MlIGUspB/HBW5CYgHvRhmkZbeMiUWKbyVoCQYvbGN8S19SSzVgzyy97KRpcjCOYYeEdkhmRCUwFBJBlLg3IoNQ==", + "requires": { + "@docusaurus/logger": "3.0.0", + "@docusaurus/utils": "3.0.0", + "joi": "^17.9.2", + "js-yaml": "^4.1.0", + "tslib": "^2.6.0" + }, + "dependencies": { + "@docusaurus/utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.0.0.tgz", + "integrity": "sha512-JwGjh5mtjG9XIAESyPxObL6CZ6LO/yU4OSTpq7Q0x+jN25zi/AMbvLjpSyZzWy+qm5uQiFiIhqFaOxvy+82Ekg==", + "requires": { + "@docusaurus/logger": "3.0.0", + "@svgr/webpack": "^6.5.1", + "escape-string-regexp": "^4.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "resolve-pathname": "^3.0.0", + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.88.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" }, - "domhandler": { + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + } + } + }, + "@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "globals": { + "version": "13.12.1", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", + "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", + "requires": { + "type-fest": "^0.20.2" + } + } + } + }, + "@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" + }, + "@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, + "@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "requires": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" + }, + "@jest/schemas": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", + "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", + "requires": { + "@sinclair/typebox": "^0.25.16" + } + }, + "@jest/types": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", + "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", + "requires": { + "@jest/schemas": "^29.4.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "requires": { - "domelementtype": "^2.2.0" + "color-convert": "^2.0.1" } }, - "domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" + "color-name": "~1.1.4" } }, - "htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" + }, + "@jridgewell/source-map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz", + "integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==", + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" + }, + "@mdx-js/mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.0.0.tgz", + "integrity": "sha512-Icm0TBKBLYqroYbNW3BPnzMGn+7mwpQOK310aZ7+fkCtiU3aqv2cdcX+nd0Ydo3wI5Rx8bX2Z2QmGb/XcAClCw==", + "requires": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-to-js": "^2.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-estree": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "periscopic": "^3.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "dependencies": { + "@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" + "@types/unist": "*" } }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, - "js-yaml": { + "bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==" + }, + "is-plain-obj": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==" + }, + "source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==" + }, + "trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==" + }, + "unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", "requires": { - "argparse": "^2.0.1" + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" } }, - "path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", "requires": { - "isarray": "0.0.1" + "@types/unist": "^3.0.0" } }, - "prism-react-renderer": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-1.3.1.tgz", - "integrity": "sha512-xUeDMEz074d0zc5y6rxiMp/dlC7C+5IDDlaEUlcBOFE2wddz7hz5PNupb087mPwTt7T9BrFmewObfCBuf/LKwQ==", - "requires": {} + "unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + } + }, + "unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + } + }, + "vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + } + }, + "vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + } + } + } + }, + "@mdx-js/react": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.0.0.tgz", + "integrity": "sha512-nDctevR9KyYFyV+m+/+S4cpzCWHqj+iHDHq3QrsWezcC+B17uZdIWgCguESUkwFhM3n/56KxWVE3V6EokrmONQ==", + "requires": { + "@types/mdx": "^2.0.0" + } + }, + "@microlink/react-json-view": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/@microlink/react-json-view/-/react-json-view-1.23.0.tgz", + "integrity": "sha512-HYJ1nsfO4/qn8afnAMhuk7+5a1vcjEaS8Gm5Vpr1SqdHDY0yLBJGpA+9DvKyxyVKaUkXzKXt3Mif9RcmFSdtYg==", + "requires": { + "flux": "~4.0.1", + "react-base16-styling": "~0.6.0", + "react-lifecycles-compat": "~3.0.4", + "react-textarea-autosize": "~8.3.2" + }, + "dependencies": { + "flux": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.4.tgz", + "integrity": "sha512-NCj3XlayA2UsapRpM7va6wU1+9rE5FIL7qoMcmxWHRzbp0yujihMBm9BBHZ1MDIk5h5o2Bl6eGiCe8rYELAmYw==", + "requires": { + "fbemitter": "^3.0.0", + "fbjs": "^3.0.1" + } + } + } + }, + "@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "requires": { + "eslint-scope": "5.1.1" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==" + }, + "@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "requires": { + "graceful-fs": "4.2.10" + } + }, + "@pnpm/npm-conf": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz", + "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==", + "requires": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + } + }, + "@polka/url": { + "version": "1.0.0-next.23", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.23.tgz", + "integrity": "sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==" + }, + "@sideway/address": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, + "@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" + }, + "@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" + }, + "@sinclair/typebox": { + "version": "0.25.24", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", + "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==" + }, + "@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==" + }, + "@slorber/remark-comment": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@slorber/remark-comment/-/remark-comment-1.0.0.tgz", + "integrity": "sha512-RCE24n7jsOj1M0UPvIQCHTe7fI0sFL4S2nwKVWwHyVr/wI/H8GosgsJGyhnsZoGFnD/P2hLf1mSbrrgSLN93NA==", + "requires": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.1.0", + "micromark-util-symbol": "^1.0.1" + } + }, + "@slorber/static-site-generator-webpack-plugin": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.7.tgz", + "integrity": "sha512-Ug7x6z5lwrz0WqdnNFOMYrDQNTPAprvHLSh6+/fmml3qUiz6l5eq+2MzLKWtn/q5K5NpSiFsZTP/fck/3vjSxA==", + "requires": { + "eval": "^0.1.8", + "p-map": "^4.0.0", + "webpack-sources": "^3.2.2" + }, + "dependencies": { + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==" } } }, - "@docusaurus/theme-search-algolia": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.0.0-beta.15.tgz", - "integrity": "sha512-XrrQKyjOPzmEuOcdsaAn1tzNJkNMA3PC86PwPZUaah0cYPpBGptcJYDlIW4VHIrCBfkQvhvmg/B3qKF6bMMi8g==", + "@svgr/babel-plugin-add-jsx-attribute": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.5.1.tgz", + "integrity": "sha512-9PYGcXrAxitycIjRmZB+Q0JaN07GZIWaTBIGQzfaZv+qr1n8X1XUEJ5rZ/vx6OVD9RRYlrNnXWExQXcmZeD/BQ==", + "requires": {} + }, + "@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "requires": {} + }, + "@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "requires": {} + }, + "@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-6.5.1.tgz", + "integrity": "sha512-8DPaVVE3fd5JKuIC29dqyMB54sA6mfgki2H2+swh+zNJoynC8pMPzOkidqHOSc6Wj032fhl8Z0TVn1GiPpAiJg==", + "requires": {} + }, + "@svgr/babel-plugin-svg-dynamic-title": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-6.5.1.tgz", + "integrity": "sha512-FwOEi0Il72iAzlkaHrlemVurgSQRDFbk0OC8dSvD5fSBPHltNh7JtLsxmZUhjYBZo2PpcU/RJvvi6Q0l7O7ogw==", + "requires": {} + }, + "@svgr/babel-plugin-svg-em-dimensions": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-6.5.1.tgz", + "integrity": "sha512-gWGsiwjb4tw+ITOJ86ndY/DZZ6cuXMNE/SjcDRg+HLuCmwpcjOktwRF9WgAiycTqJD/QXqL2f8IzE2Rzh7aVXA==", + "requires": {} + }, + "@svgr/babel-plugin-transform-react-native-svg": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-6.5.1.tgz", + "integrity": "sha512-2jT3nTayyYP7kI6aGutkyfJ7UMGtuguD72OjeGLwVNyfPRBD8zQthlvL+fAbAKk5n9ZNcvFkp/b1lZ7VsYqVJg==", + "requires": {} + }, + "@svgr/babel-plugin-transform-svg-component": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-6.5.1.tgz", + "integrity": "sha512-a1p6LF5Jt33O3rZoVRBqdxL350oge54iZWHNI6LJB5tQ7EelvD/Mb1mfBiZNAan0dt4i3VArkFRjA4iObuNykQ==", + "requires": {} + }, + "@svgr/babel-preset": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-6.5.1.tgz", + "integrity": "sha512-6127fvO/FF2oi5EzSQOAjo1LE3OtNVh11R+/8FXa+mHx1ptAaS4cknIjnUA7e6j6fwGGJ17NzaTJFUwOV2zwCw==", + "requires": { + "@svgr/babel-plugin-add-jsx-attribute": "^6.5.1", + "@svgr/babel-plugin-remove-jsx-attribute": "*", + "@svgr/babel-plugin-remove-jsx-empty-expression": "*", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^6.5.1", + "@svgr/babel-plugin-svg-dynamic-title": "^6.5.1", + "@svgr/babel-plugin-svg-em-dimensions": "^6.5.1", + "@svgr/babel-plugin-transform-react-native-svg": "^6.5.1", + "@svgr/babel-plugin-transform-svg-component": "^6.5.1" + } + }, + "@svgr/core": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-6.5.1.tgz", + "integrity": "sha512-/xdLSWxK5QkqG524ONSjvg3V/FkNyCv538OIBdQqPNaAta3AsXj/Bd2FbvR87yMbXO2hFSWiAe/Q6IkVPDw+mw==", + "requires": { + "@babel/core": "^7.19.6", + "@svgr/babel-preset": "^6.5.1", + "@svgr/plugin-jsx": "^6.5.1", + "camelcase": "^6.2.0", + "cosmiconfig": "^7.0.1" + } + }, + "@svgr/hast-util-to-babel-ast": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.5.1.tgz", + "integrity": "sha512-1hnUxxjd83EAxbL4a0JDJoD3Dao3hmjvyvyEV8PzWmLK3B9m9NPlW7GKjFyoWE8nM7HnXzPcmmSyOW8yOddSXw==", + "requires": { + "@babel/types": "^7.20.0", + "entities": "^4.4.0" + } + }, + "@svgr/plugin-jsx": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-6.5.1.tgz", + "integrity": "sha512-+UdQxI3jgtSjCykNSlEMuy1jSRQlGC7pqBCPvkG/2dATdWo082zHTTK3uhnAju2/6XpE6B5mZ3z4Z8Ns01S8Gw==", + "requires": { + "@babel/core": "^7.19.6", + "@svgr/babel-preset": "^6.5.1", + "@svgr/hast-util-to-babel-ast": "^6.5.1", + "svg-parser": "^2.0.4" + } + }, + "@svgr/plugin-svgo": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-6.5.1.tgz", + "integrity": "sha512-omvZKf8ixP9z6GWgwbtmP9qQMPX4ODXi+wzbVZgomNFsUIlHA1sf4fThdwTWSsZGgvGAG6yE+b/F5gWUkcZ/iQ==", + "requires": { + "cosmiconfig": "^7.0.1", + "deepmerge": "^4.2.2", + "svgo": "^2.8.0" + } + }, + "@svgr/webpack": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-6.5.1.tgz", + "integrity": "sha512-cQ/AsnBkXPkEK8cLbv4Dm7JGXq2XrumKnL1dRpJD9rIO2fTIlJI9a1uCciYG1F2aUsox/hJQyNGbt3soDxSRkA==", + "requires": { + "@babel/core": "^7.19.6", + "@babel/plugin-transform-react-constant-elements": "^7.18.12", + "@babel/preset-env": "^7.19.4", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.18.6", + "@svgr/core": "^6.5.1", + "@svgr/plugin-jsx": "^6.5.1", + "@svgr/plugin-svgo": "^6.5.1" + } + }, + "@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "requires": { + "defer-to-connect": "^2.0.1" + } + }, + "@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==" + }, + "@types/acorn": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", + "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", + "requires": { + "@types/estree": "*" + } + }, + "@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/bonjour": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "requires": { + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "requires": { + "@types/node": "*" + } + }, + "@types/connect-history-api-fallback": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz", + "integrity": "sha512-4x5FkPpLipqwthjPsF7ZRbOv3uoLUFkTA9G9v583qi4pACvq0uTELrB8OLUzPWUI4IJIyvM85vzkV1nyiI2Lig==", + "requires": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "requires": { + "@types/ms": "*" + } + }, + "@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + }, + "@types/estree-jsx": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.3.tgz", + "integrity": "sha512-pvQ+TKeRHeiUGRhvYwRrQ/ISnohKkSJR14fT2yqyZ4e9K5vqc7hrtY2Y1Dw0ZwAzQ6DQsxsaCUuSIIi8v0Cq6w==", + "requires": { + "@types/estree": "*" + } + }, + "@types/express": { + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.35", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz", + "integrity": "sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==", + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "@types/gtag.js": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/@types/gtag.js/-/gtag.js-0.0.12.tgz", + "integrity": "sha512-YQV9bUsemkzG81Ea295/nF/5GijnD2Af7QhEofh7xu+kvCN6RdodgNwwGWXB5GMI3NoyvQo0odNctoH/qLMIpg==" + }, + "@types/hast": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", + "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==", + "requires": { + "@types/unist": "*" + } + }, + "@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==" + }, + "@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" + }, + "@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==" + }, + "@types/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==" + }, + "@types/http-proxy": { + "version": "1.17.11", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.11.tgz", + "integrity": "sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA==", + "requires": { + "@types/node": "*" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/json-schema": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", + "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==" + }, + "@types/mdast": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz", + "integrity": "sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==", + "requires": { + "@types/unist": "*" + } + }, + "@types/mdx": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.10.tgz", + "integrity": "sha512-Rllzc5KHk0Al5/WANwgSPl1/CwjqCy+AZrGd78zuK+jO9aDM6ffblZ+zIjgPNAaEBmlO0RYDvLNh7wD0zKVgEg==" + }, + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" + }, + "@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" + }, + "@types/node": { + "version": "17.0.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.19.tgz", + "integrity": "sha512-PfeQhvcMR4cPFVuYfBN4ifG7p9c+Dlh3yUZR6k+5yQK7wX3gDgVxBly4/WkBRs9x4dmcy1TVl08SY67wwtEvmA==" + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + }, + "@types/parse5": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz", + "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==" + }, + "@types/prismjs": { + "version": "1.26.3", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.3.tgz", + "integrity": "sha512-A0D0aTXvjlqJ5ZILMz3rNfDBOx9hHxLZYv2by47Sm/pqW35zzjusrZTryatjN/Rf8Us2gZrJD+KeHbUSTux1Cw==" + }, + "@types/prop-types": { + "version": "15.7.4", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", + "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" + }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" + }, + "@types/react": { + "version": "17.0.39", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.39.tgz", + "integrity": "sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==", + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-router": { + "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "requires": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "@types/react-router-config": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/@types/react-router-config/-/react-router-config-5.0.10.tgz", + "integrity": "sha512-Wn6c/tXdEgi9adCMtDwx8Q2vGty6TsPTc/wCQQ9kAlye8UqFxj0vGFWWuhywNfkwqth+SOgJxQTLTZukrqDQmQ==", + "requires": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "^5.1.0" + } + }, + "@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "requires": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" + }, + "@types/sax": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", + "integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==", + "requires": { + "@types/node": "*" + } + }, + "@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, + "@types/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", + "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "@types/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "requires": { + "@types/express": "*" + } + }, + "@types/serve-static": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.2.tgz", + "integrity": "sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw==", "requires": { - "@docsearch/react": "^3.0.0-alpha.39", - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/theme-common": "2.0.0-beta.15", - "@docusaurus/theme-translations": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", - "algoliasearch": "^4.10.5", - "algoliasearch-helper": "^3.5.5", - "clsx": "^1.1.1", - "eta": "^1.12.3", - "lodash": "^4.17.20", - "tslib": "^2.3.1", - "utility-types": "^3.10.0" - }, - "dependencies": { - "@docsearch/react": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.0.0.tgz", - "integrity": "sha512-yhMacqS6TVQYoBh/o603zszIb5Bl8MIXuOc6Vy617I74pirisDzzcNh0NEaYQt50fVVR3khUbeEhUEWEWipESg==", - "requires": { - "@algolia/autocomplete-core": "1.5.2", - "@algolia/autocomplete-preset-algolia": "1.5.2", - "@docsearch/css": "3.0.0", - "algoliasearch": "^4.0.0" - } - }, - "@docusaurus/theme-common": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.0.0-beta.15.tgz", - "integrity": "sha512-+pvarmzcyECE4nWxw+dCMKRIoes0NegrRuM9+nRsUrS/E5ywsF539kpupKIEqaMjq6AuM0CJtDoHxHHPNe0KaQ==", - "requires": { - "@docusaurus/plugin-content-blog": "2.0.0-beta.15", - "@docusaurus/plugin-content-docs": "2.0.0-beta.15", - "@docusaurus/plugin-content-pages": "2.0.0-beta.15", - "clsx": "^1.1.1", - "parse-numeric-range": "^1.3.0", - "tslib": "^2.3.1", - "utility-types": "^3.10.0" - }, - "dependencies": { - "@docusaurus/plugin-content-blog": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.0.0-beta.15.tgz", - "integrity": "sha512-VtEwkgkoNIS8JFPe+huBeBuJ8HG8Lq1JNYM/ItwQg/cwGAgP8EgwbEuKDn428oZKEI2PpgAuf5Gv4AzJWIes9A==", - "requires": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/mdx-loader": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@docusaurus/utils-common": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", - "cheerio": "^1.0.0-rc.10", - "feed": "^4.2.2", - "fs-extra": "^10.0.0", - "lodash": "^4.17.20", - "reading-time": "^1.5.0", - "remark-admonitions": "^1.2.1", - "tslib": "^2.3.1", - "utility-types": "^3.10.0", - "webpack": "^5.61.0" - }, - "dependencies": { - "@docusaurus/mdx-loader": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.15.tgz", - "integrity": "sha512-MVpytjDDao7hmPF1QSs9B5zoTgevZjiqjnX3FM1yjqdCv+chyUo0gnmYHjeG/4Gqu7jucp+dDdp6yQpzs4g09A==", - "requires": { - "@babel/parser": "^7.16.4", - "@babel/traverse": "^7.16.3", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@mdx-js/mdx": "^1.6.21", - "escape-html": "^1.0.3", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "image-size": "^1.0.1", - "mdast-util-to-string": "^2.0.0", - "remark-emoji": "^2.1.0", - "stringify-object": "^3.3.0", - "tslib": "^2.3.1", - "unist-util-visit": "^2.0.2", - "url-loader": "^4.1.1", - "webpack": "^5.61.0" - } - } - } - }, - "@docusaurus/plugin-content-docs": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.0.0-beta.15.tgz", - "integrity": "sha512-HSwNZdUKz4rpJiGbFjl/OFhSleeZUSZ6E6lk98i4iL1A5u6fIm4CHsT53yp4UUOse+lFrePTFZsyqwMA4nZZYA==", - "requires": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/mdx-loader": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", - "combine-promises": "^1.1.0", - "fs-extra": "^10.0.0", - "import-fresh": "^3.2.2", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "remark-admonitions": "^1.2.1", - "shelljs": "^0.8.4", - "tslib": "^2.3.1", - "utility-types": "^3.10.0", - "webpack": "^5.61.0" - }, - "dependencies": { - "@docusaurus/mdx-loader": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.15.tgz", - "integrity": "sha512-MVpytjDDao7hmPF1QSs9B5zoTgevZjiqjnX3FM1yjqdCv+chyUo0gnmYHjeG/4Gqu7jucp+dDdp6yQpzs4g09A==", - "requires": { - "@babel/parser": "^7.16.4", - "@babel/traverse": "^7.16.3", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@mdx-js/mdx": "^1.6.21", - "escape-html": "^1.0.3", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "image-size": "^1.0.1", - "mdast-util-to-string": "^2.0.0", - "remark-emoji": "^2.1.0", - "stringify-object": "^3.3.0", - "tslib": "^2.3.1", - "unist-util-visit": "^2.0.2", - "url-loader": "^4.1.1", - "webpack": "^5.61.0" - } - } - } - }, - "@docusaurus/plugin-content-pages": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.0.0-beta.15.tgz", - "integrity": "sha512-N7YhW5RiOY6J228z4lOoP//qX0Q48cRtxDONZ/Ohd9C5OI2vS6TD8iQuDqOIYHxH+BshjNSsKvbJ+SMIQDwysg==", - "requires": { - "@docusaurus/core": "2.0.0-beta.15", - "@docusaurus/mdx-loader": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@docusaurus/utils-validation": "2.0.0-beta.15", - "fs-extra": "^10.0.0", - "globby": "^11.0.2", - "remark-admonitions": "^1.2.1", - "tslib": "^2.3.1", - "webpack": "^5.61.0" - }, - "dependencies": { - "@docusaurus/mdx-loader": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.15.tgz", - "integrity": "sha512-MVpytjDDao7hmPF1QSs9B5zoTgevZjiqjnX3FM1yjqdCv+chyUo0gnmYHjeG/4Gqu7jucp+dDdp6yQpzs4g09A==", - "requires": { - "@babel/parser": "^7.16.4", - "@babel/traverse": "^7.16.3", - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "@mdx-js/mdx": "^1.6.21", - "escape-html": "^1.0.3", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "image-size": "^1.0.1", - "mdast-util-to-string": "^2.0.0", - "remark-emoji": "^2.1.0", - "stringify-object": "^3.3.0", - "tslib": "^2.3.1", - "unist-util-visit": "^2.0.2", - "url-loader": "^4.1.1", - "webpack": "^5.61.0" - } - } - } - } - } - }, - "@docusaurus/utils": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.0.0-beta.15.tgz", - "integrity": "sha512-xkoPmFxCBkDqbZR4U3SE752OcXtWTGgZnc/pZWxItzb1IYRGNZHrzdIr7CnI7rppriuZzsyivDGiC4Ud9MWhkA==", - "requires": { - "@docusaurus/logger": "2.0.0-beta.15", - "@mdx-js/runtime": "^1.6.22", - "@svgr/webpack": "^6.0.0", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "github-slugger": "^1.4.0", - "globby": "^11.0.4", - "gray-matter": "^4.0.3", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "micromatch": "^4.0.4", - "remark-mdx-remove-exports": "^1.6.22", - "remark-mdx-remove-imports": "^1.6.22", - "resolve-pathname": "^3.0.0", - "tslib": "^2.3.1", - "url-loader": "^4.1.1" - } - }, - "@docusaurus/utils-validation": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.15.tgz", - "integrity": "sha512-1oOVBCkRrsTXSYrBTsMdnj3a/R56zrx11rjF4xo0+dmm8C01Xw4msFtc3uA7VLX0HQvgHsk8xPzU5GERNdsNpg==", - "requires": { - "@docusaurus/logger": "2.0.0-beta.15", - "@docusaurus/utils": "2.0.0-beta.15", - "joi": "^17.4.2", - "tslib": "^2.3.1" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" - }, - "cheerio": { - "version": "1.0.0-rc.10", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", - "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", - "requires": { - "cheerio-select": "^1.5.0", - "dom-serializer": "^1.3.2", - "domhandler": "^4.2.0", - "htmlparser2": "^6.1.0", - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "tslib": "^2.2.0" - } - }, - "dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - } - }, - "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" - }, - "domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", - "requires": { - "domelementtype": "^2.2.0" - } - }, - "domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - } - }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "requires": { - "argparse": "^2.0.1" - } - }, - "prism-react-renderer": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-1.3.1.tgz", - "integrity": "sha512-xUeDMEz074d0zc5y6rxiMp/dlC7C+5IDDlaEUlcBOFE2wddz7hz5PNupb087mPwTt7T9BrFmewObfCBuf/LKwQ==", - "peer": true, - "requires": {} - } + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" } }, - "@docusaurus/theme-translations": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-2.0.0-beta.15.tgz", - "integrity": "sha512-Lu2JDsnZaB2BcJe8Hpq5nrbS7+7bd09jT08b9vztQyvzR8PgzsthnzlLN4ilOeamRIuYJKo1pUGm0EsQBOP6Nw==", + "@types/sockjs": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", + "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", "requires": { - "fs-extra": "^10.0.0", - "tslib": "^2.3.1" + "@types/node": "*" } }, - "@docusaurus/utils-common": { - "version": "2.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-2.0.0-beta.15.tgz", - "integrity": "sha512-kIGlSIvbE/oniUpUjI8GOkSpH8o4NXbYqAh9dqPn+TJ0KbEFY3fc80gzZQU+9SunCwJMJbIxIGevX9Ry+nackw==", + "@types/unist": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", + "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" + }, + "@types/ws": { + "version": "8.5.5", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", + "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", "requires": { - "tslib": "^2.3.1" + "@types/node": "*" } }, - "@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "@types/yargs": { + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "requires": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", - "requires": { - "type-fest": "^0.20.2" - } - } + "@types/yargs-parser": "*" } }, - "@hapi/hoek": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz", - "integrity": "sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw==" + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" }, - "@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + }, + "@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", "requires": { - "@hapi/hoek": "^9.0.0" + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" } }, - "@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" + }, + "@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==" + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", "requires": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" } }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" }, - "@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==" + "@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==" + "@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" + }, + "@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "dependencies": { + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + } + } + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "requires": {} + }, + "acorn-walk": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz", + "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==" + }, + "address": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.1.2.tgz", + "integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==" + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } }, - "@jridgewell/trace-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", - "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, - "@mdx-js/mdx": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-1.6.22.tgz", - "integrity": "sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA==", - "requires": { - "@babel/core": "7.12.9", - "@babel/plugin-syntax-jsx": "7.12.1", - "@babel/plugin-syntax-object-rest-spread": "7.8.3", - "@mdx-js/util": "1.6.22", - "babel-plugin-apply-mdx-type-prop": "1.6.22", - "babel-plugin-extract-import-names": "1.6.22", - "camelcase-css": "2.0.1", - "detab": "2.0.4", - "hast-util-raw": "6.0.1", - "lodash.uniq": "4.5.0", - "mdast-util-to-hast": "10.0.1", - "remark-footnotes": "2.0.0", - "remark-mdx": "1.6.22", - "remark-parse": "8.0.3", - "remark-squeeze-paragraphs": "4.0.0", - "style-to-object": "0.3.0", - "unified": "9.2.0", - "unist-builder": "2.0.3", - "unist-util-visit": "2.0.3" - }, - "dependencies": { - "@babel/core": { - "version": "7.12.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", - "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.5", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.5", - "@babel/parser": "^7.12.7", - "@babel/template": "^7.12.7", - "@babel/traverse": "^7.12.9", - "@babel/types": "^7.12.7", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", - "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "unified": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz", - "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "requires": { + "ajv": "^8.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "requires": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^2.0.0", - "trough": "^1.0.0", - "vfile": "^4.0.0" + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" } } }, - "@mdx-js/react": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-1.6.22.tgz", - "integrity": "sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg==", + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "requires": {} }, - "@mdx-js/runtime": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/runtime/-/runtime-1.6.22.tgz", - "integrity": "sha512-p17spaO2+55VLCuxXA3LVHC4phRx60NR2XMdZ+qgVU1lKvEX4y88dmFNOzGDCPLJ03IZyKrJ/rPWWRiBrd9JrQ==", - "requires": { - "@mdx-js/mdx": "1.6.22", - "@mdx-js/react": "1.6.22", - "buble-jsx-only": "^0.19.8" + "algoliasearch": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.20.0.tgz", + "integrity": "sha512-y+UHEjnOItoNy0bYO+WWmLWBlPwDjKHW6mNHrPi0NkuhpQOOEbrkwQH/wgKFDLh7qlKjzoKeiRtlpewDPDG23g==", + "requires": { + "@algolia/cache-browser-local-storage": "4.20.0", + "@algolia/cache-common": "4.20.0", + "@algolia/cache-in-memory": "4.20.0", + "@algolia/client-account": "4.20.0", + "@algolia/client-analytics": "4.20.0", + "@algolia/client-common": "4.20.0", + "@algolia/client-personalization": "4.20.0", + "@algolia/client-search": "4.20.0", + "@algolia/logger-common": "4.20.0", + "@algolia/logger-console": "4.20.0", + "@algolia/requester-browser-xhr": "4.20.0", + "@algolia/requester-common": "4.20.0", + "@algolia/requester-node-http": "4.20.0", + "@algolia/transporter": "4.20.0" } }, - "@mdx-js/util": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/util/-/util-1.6.22.tgz", - "integrity": "sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==" - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "algoliasearch-helper": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.15.0.tgz", + "integrity": "sha512-DGUnK3TGtDQsaUE4ayF/LjSN0DGsuYThB8WBgnnDY0Wq04K6lNVruO3LfqJOgSfDiezp+Iyt8Tj4YKHi+/ivSA==", "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "@algolia/events": "^4.0.1" } }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "string-width": "^4.1.0" } }, - "@polka/url": { - "version": "1.0.0-next.21", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", - "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==" + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==" }, - "@sideway/address": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.3.tgz", - "integrity": "sha512-8ncEUtmnTsMmL7z1YPB47kPUq7LpKWJNFPsRzHiIajGC5uXlWGn+AmkYPcHNl8S4tcEGx+cnORnNYaw2wvL+LQ==", + "ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==" + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { - "@hapi/hoek": "^9.0.0" + "color-convert": "^1.9.0" } }, - "@sideway/formula": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", - "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==" + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } }, - "@sideway/pinpoint": { + "aproba": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" }, - "@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==" + "arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" }, - "@slorber/static-site-generator-webpack-plugin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.1.tgz", - "integrity": "sha512-PSv4RIVO1Y3kvHxjvqeVisk3E9XFoO04uwYBDWe217MFqKspplYswTuKLiJu0aLORQWzuQjfVsSlLPojwfYsLw==", + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "requires": { - "bluebird": "^3.7.1", - "cheerio": "^0.22.0", - "eval": "^0.1.4", - "url": "^0.11.0", - "webpack-sources": "^1.4.3" + "sprintf-js": "~1.0.2" } }, - "@svgr/babel-plugin-add-jsx-attribute": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.0.0.tgz", - "integrity": "sha512-MdPdhdWLtQsjd29Wa4pABdhWbaRMACdM1h31BY+c6FghTZqNGT7pEYdBoaGeKtdTOBC/XNFQaKVj+r/Ei2ryWA==", - "requires": {} - }, - "@svgr/babel-plugin-remove-jsx-attribute": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-6.0.0.tgz", - "integrity": "sha512-aVdtfx9jlaaxc3unA6l+M9YRnKIZjOhQPthLKqmTXC8UVkBLDRGwPKo+r8n3VZN8B34+yVajzPTZ+ptTSuZZCw==", - "requires": {} - }, - "@svgr/babel-plugin-remove-jsx-empty-expression": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-6.0.0.tgz", - "integrity": "sha512-Ccj42ApsePD451AZJJf1QzTD1B/BOU392URJTeXFxSK709i0KUsGtbwyiqsKu7vsYxpTM0IA5clAKDyf9RCZyA==", - "requires": {} - }, - "@svgr/babel-plugin-replace-jsx-attribute-value": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-6.0.0.tgz", - "integrity": "sha512-88V26WGyt1Sfd1emBYmBJRWMmgarrExpKNVmI9vVozha4kqs6FzQJ/Kp5+EYli1apgX44518/0+t9+NU36lThQ==", - "requires": {} - }, - "@svgr/babel-plugin-svg-dynamic-title": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-6.0.0.tgz", - "integrity": "sha512-F7YXNLfGze+xv0KMQxrl2vkNbI9kzT9oDK55/kUuymh1ACyXkMV+VZWX1zEhSTfEKh7VkHVZGmVtHg8eTZ6PRg==", - "requires": {} - }, - "@svgr/babel-plugin-svg-em-dimensions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-6.0.0.tgz", - "integrity": "sha512-+rghFXxdIqJNLQK08kwPBD3Z22/0b2tEZ9lKiL/yTfuyj1wW8HUXu4bo/XkogATIYuXSghVQOOCwURXzHGKyZA==", - "requires": {} - }, - "@svgr/babel-plugin-transform-react-native-svg": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-6.0.0.tgz", - "integrity": "sha512-VaphyHZ+xIKv5v0K0HCzyfAaLhPGJXSk2HkpYfXIOKb7DjLBv0soHDxNv6X0vr2titsxE7klb++u7iOf7TSrFQ==", - "requires": {} - }, - "@svgr/babel-plugin-transform-svg-component": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-6.2.0.tgz", - "integrity": "sha512-bhYIpsORb++wpsp91fymbFkf09Z/YEKR0DnFjxvN+8JHeCUD2unnh18jIMKnDJTWtvpTaGYPXELVe4OOzFI0xg==", - "requires": {} + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" }, - "@svgr/babel-preset": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-6.2.0.tgz", - "integrity": "sha512-4WQNY0J71JIaL03DRn0vLiz87JXx0b9dYm2aA8XHlQJQoixMl4r/soYHm8dsaJZ3jWtkCiOYy48dp9izvXhDkQ==", + "array-includes": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", + "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", "requires": { - "@svgr/babel-plugin-add-jsx-attribute": "^6.0.0", - "@svgr/babel-plugin-remove-jsx-attribute": "^6.0.0", - "@svgr/babel-plugin-remove-jsx-empty-expression": "^6.0.0", - "@svgr/babel-plugin-replace-jsx-attribute-value": "^6.0.0", - "@svgr/babel-plugin-svg-dynamic-title": "^6.0.0", - "@svgr/babel-plugin-svg-em-dimensions": "^6.0.0", - "@svgr/babel-plugin-transform-react-native-svg": "^6.0.0", - "@svgr/babel-plugin-transform-svg-component": "^6.2.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" } }, - "@svgr/core": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/@svgr/core/-/core-6.2.1.tgz", - "integrity": "sha512-NWufjGI2WUyrg46mKuySfviEJ6IxHUOm/8a3Ph38VCWSp+83HBraCQrpEM3F3dB6LBs5x8OElS8h3C0oOJaJAA==", - "requires": { - "@svgr/plugin-jsx": "^6.2.1", - "camelcase": "^6.2.0", - "cosmiconfig": "^7.0.1" - } + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" }, - "@svgr/hast-util-to-babel-ast": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.2.1.tgz", - "integrity": "sha512-pt7MMkQFDlWJVy9ULJ1h+hZBDGFfSCwlBNW1HkLnVi7jUhyEXUaGYWi1x6bM2IXuAR9l265khBT4Av4lPmaNLQ==", + "array.prototype.flatmap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz", + "integrity": "sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA==", "requires": { - "@babel/types": "^7.15.6", - "entities": "^3.0.1" + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0" } }, - "@svgr/plugin-jsx": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-6.2.1.tgz", - "integrity": "sha512-u+MpjTsLaKo6r3pHeeSVsh9hmGRag2L7VzApWIaS8imNguqoUwDq/u6U/NDmYs/KAsrmtBjOEaAAPbwNGXXp1g==", - "requires": { - "@babel/core": "^7.15.5", - "@svgr/babel-preset": "^6.2.0", - "@svgr/hast-util-to-babel-ast": "^6.2.1", - "svg-parser": "^2.0.2" - } + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" }, - "@svgr/plugin-svgo": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-6.2.0.tgz", - "integrity": "sha512-oDdMQONKOJEbuKwuy4Np6VdV6qoaLLvoY86hjvQEgU82Vx1MSWRyYms6Sl0f+NtqxLI/rDVufATbP/ev996k3Q==", + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==" + }, + "astring": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.8.6.tgz", + "integrity": "sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" + }, + "autocomplete.js": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/autocomplete.js/-/autocomplete.js-0.38.1.tgz", + "integrity": "sha512-6pSJzuRMY3pqpozt+SXThl2DmJfma8Bi3SVFbZHS0PW/N72bOUv+Db0jAh2cWOhTsA4X+GNmKvIl8wExJTnN9w==", "requires": { - "cosmiconfig": "^7.0.1", - "deepmerge": "^4.2.2", - "svgo": "^2.5.0" + "immediate": "^3.2.3" } }, - "@svgr/webpack": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-6.2.1.tgz", - "integrity": "sha512-h09ngMNd13hnePwgXa+Y5CgOjzlCvfWLHg+MBnydEedAnuLRzUHUJmGS3o2OsrhxTOOqEsPOFt5v/f6C5Qulcw==", + "autoprefixer": { + "version": "10.4.16", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", + "integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==", "requires": { - "@babel/core": "^7.15.5", - "@babel/plugin-transform-react-constant-elements": "^7.14.5", - "@babel/preset-env": "^7.15.6", - "@babel/preset-react": "^7.14.5", - "@babel/preset-typescript": "^7.15.0", - "@svgr/core": "^6.2.1", - "@svgr/plugin-jsx": "^6.2.1", - "@svgr/plugin-svgo": "^6.2.0" + "browserslist": "^4.21.10", + "caniuse-lite": "^1.0.30001538", + "fraction.js": "^4.3.6", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" } }, - "@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "axios": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", + "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", "requires": { - "defer-to-connect": "^1.0.1" + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, - "@trysound/sax": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", - "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==" - }, - "@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "babel-loader": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", + "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", "requires": { - "@types/connect": "*", - "@types/node": "*" + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" } }, - "@types/bonjour": { - "version": "3.5.10", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", - "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", "requires": { - "@types/node": "*" + "object.assign": "^4.1.0" } }, - "@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "babel-plugin-polyfill-corejs2": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.6.tgz", + "integrity": "sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q==", "requires": { - "@types/node": "*" + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.4.3", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } } }, - "@types/connect-history-api-fallback": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", - "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", + "babel-plugin-polyfill-corejs3": { + "version": "0.8.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.6.tgz", + "integrity": "sha512-leDIc4l4tUgU7str5BWLS2h8q2N4Nf6lGZP6UrNDxdtfF2g69eJ5L0H7S8A5Ln/arfFAfHor5InAdZuIOwZdgQ==", "requires": { - "@types/express-serve-static-core": "*", - "@types/node": "*" + "@babel/helper-define-polyfill-provider": "^0.4.3", + "core-js-compat": "^3.33.1" } }, - "@types/eslint": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", - "integrity": "sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA==", + "babel-plugin-polyfill-regenerator": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.3.tgz", + "integrity": "sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw==", "requires": { - "@types/estree": "*", - "@types/json-schema": "*" + "@babel/helper-define-polyfill-provider": "^0.4.3" } }, - "@types/eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", - "requires": { - "@types/eslint": "*", - "@types/estree": "*" - } + "bail": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", + "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==" }, - "@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==" + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, - "@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", - "@types/qs": "*", - "@types/serve-static": "*" - } + "base16": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz", + "integrity": "sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ==" }, - "@types/express-serve-static-core": { - "version": "4.17.28", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", - "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" + }, + "bcp-47-match": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-1.0.3.tgz", + "integrity": "sha512-LggQ4YTdjWQSKELZF5JwchnBa1u0pIQSZf5lSdOHEdbVP55h0qICA/FUp3+W99q0xqxYa1ZQizTUH87gecII5w==" + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + }, + "body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } } }, - "@types/hast": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", - "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==", + "bonjour-service": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz", + "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==", "requires": { - "@types/unist": "*" + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" } }, - "@types/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" }, - "@types/http-proxy": { - "version": "1.17.8", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz", - "integrity": "sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA==", + "boxen": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz", + "integrity": "sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==", "requires": { - "@types/node": "*" + "ansi-align": "^3.0.1", + "camelcase": "^7.0.1", + "chalk": "^5.2.0", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" + }, + "camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==" + }, + "chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==" + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==" + } } }, - "@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==" - }, - "@types/mdast": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", - "integrity": "sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==", + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { - "@types/unist": "*" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" - }, - "@types/node": { - "version": "17.0.19", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.19.tgz", - "integrity": "sha512-PfeQhvcMR4cPFVuYfBN4ifG7p9c+Dlh3yUZR6k+5yQK7wX3gDgVxBly4/WkBRs9x4dmcy1TVl08SY67wwtEvmA==" - }, - "@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + "braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "requires": { + "fill-range": "^7.1.1" + } }, - "@types/parse5": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz", - "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==" + "browserslist": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "requires": { + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" + } }, - "@types/prop-types": { - "version": "15.7.4", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", - "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, - "@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" }, - "@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" + "cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==" }, - "@types/react": { - "version": "17.0.39", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.39.tgz", - "integrity": "sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==", + "cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "dependencies": { + "normalize-url": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", + "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==" + } } }, - "@types/retry": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", - "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==" - }, - "@types/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-pSAff4IAxJjfAXUG6tFkO7dsSbTmf8CtUpfhhZ5VhkRpC4628tJhh3+V6H1E+/Gs9piSzYKT5yzHO5M4GG9jkw==", + "call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "requires": { - "@types/node": "*" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" } }, - "@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" }, - "@types/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", "requires": { - "@types/express": "*" + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" } }, - "@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", - "requires": { - "@types/mime": "^1", - "@types/node": "*" - } + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" }, - "@types/sockjs": { - "version": "0.3.33", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", - "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", "requires": { - "@types/node": "*" + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" } }, - "@types/unist": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", - "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" + "caniuse-lite": { + "version": "1.0.30001564", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001564.tgz", + "integrity": "sha512-DqAOf+rhof+6GVx1y+xzbFPeOumfQnhYzVnZD6LAXijR77yPtm9mfOcqOnT3mpnJiZVT+kwLAFnRlZcIz+c6bg==" }, - "@types/ws": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-ahRJZquUYCdOZf/rCsWg88S0/+cb9wazUBHv6HZEe3XdYaBe2zr/slM8J28X07Hn88Pnm4ezo7N8/ofnOgrPVQ==", - "requires": { - "@types/node": "*" - } + "ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==" }, - "@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==" + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==" }, - "@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==" + "character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==" }, - "@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==" + "character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==" }, - "@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", - "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" - } + "character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==" }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==" + "character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==" }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "dependencies": { + "dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + } + }, + "domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "requires": { + "domelementtype": "^2.3.0" + } + }, + "domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "requires": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + } + }, + "htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "requires": { + "entities": "^4.4.0" + } + } } }, - "@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", "requires": { - "@xtuc/ieee754": "^1.2.0" + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "dependencies": { + "css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + } + }, + "dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + } + }, + "domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "requires": { + "domelementtype": "^2.3.0" + } + }, + "domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "requires": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + } + } } }, - "@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "requires": { - "@xtuc/long": "4.2.2" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" } }, - "@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==" + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" }, - "@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } + "ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==" }, - "@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "clean-css": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz", + "integrity": "sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==", "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "source-map": "~0.6.0" } }, - "@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" - } + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" }, - "@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } + "cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==" }, - "@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "cli-table3": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", + "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", "requires": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" + "@colors/colors": "1.5.0", + "string-width": "^4.2.0" } }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" - }, - "@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" }, "dependencies": { - "mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" - }, - "mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "requires": { - "mime-db": "1.51.0" + "isobject": "^3.0.1" } } } }, - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + "clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "requires": {} + "collapse-white-space": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", + "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==" }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } }, - "address": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/address/-/address-1.1.2.tgz", - "integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==" + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" + }, + "colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" + }, + "colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" + }, + "combine-promises": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/combine-promises/-/combine-promises-1.1.0.tgz", + "integrity": "sha512-ZI9jvcLDxqwaXEixOhArm3r7ReIivsXkpbyEWyeOhzz1QS0iSgBPnWvEqvIQtYyamGCYA88gFhmUrs9hrrQ0pg==" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" + "delayed-stream": "~1.0.0" } }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==" + }, + "commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==" + }, + "common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==" + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "mime-db": ">= 1.43.0 < 2" + }, + "dependencies": { + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + } } }, - "ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", "requires": { - "ajv": "^8.0.0" + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" }, - "dependencies": { - "ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "ms": "2.0.0" } }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" } } }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "requires": {} - }, - "algoliasearch": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.12.1.tgz", - "integrity": "sha512-c0dM1g3zZBJrkzE5GA/Nu1y3fFxx3LCzxKzcmp2dgGS8P4CjszB/l3lsSh2MSrrK1Hn/KV4BlbBMXtYgG1Bfrw==", - "requires": { - "@algolia/cache-browser-local-storage": "4.12.1", - "@algolia/cache-common": "4.12.1", - "@algolia/cache-in-memory": "4.12.1", - "@algolia/client-account": "4.12.1", - "@algolia/client-analytics": "4.12.1", - "@algolia/client-common": "4.12.1", - "@algolia/client-personalization": "4.12.1", - "@algolia/client-search": "4.12.1", - "@algolia/logger-common": "4.12.1", - "@algolia/logger-console": "4.12.1", - "@algolia/requester-browser-xhr": "4.12.1", - "@algolia/requester-common": "4.12.1", - "@algolia/requester-node-http": "4.12.1", - "@algolia/transporter": "4.12.1" - } + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, - "algoliasearch-helper": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.7.0.tgz", - "integrity": "sha512-XJ3QfERBLfeVCyTVx80gon7r3/rgm/CE8Ha1H7cbablRe/X7SfYQ14g/eO+MhjVKIQp+gy9oC6G5ilmLwS1k6w==", + "config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", "requires": { - "@algolia/events": "^4.0.1" + "ini": "^1.3.4", + "proto-list": "~1.2.1" } }, - "ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "configstore": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz", + "integrity": "sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==", "requires": { - "string-width": "^4.1.0" + "dot-prop": "^6.0.1", + "graceful-fs": "^4.2.6", + "unique-string": "^3.0.0", + "write-file-atomic": "^3.0.3", + "xdg-basedir": "^5.0.1" } }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==" + "connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==" }, - "ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==" + "consola": { + "version": "2.15.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", + "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" }, - "aproba": { + "convert-source-map": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, - "arg": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.1.tgz", - "integrity": "sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA==" + "cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==" }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "~1.0.2" - } + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, - "array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + "copy-text-to-clipboard": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.0.tgz", + "integrity": "sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q==" }, - "array-includes": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.7" + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "dependencies": { + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "requires": { + "is-glob": "^4.0.3" + } + }, + "globby": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.0.tgz", + "integrity": "sha512-jWsQfayf13NvqKUIL3Ta+CIqMnvlaIDFveWE/dpOZ9+3AMEJozsxDvKA02zync9UuvOM8rOXzsD5GqKP4OnWPQ==", + "requires": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" + } + }, + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==" + }, + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==" + } } }, - "array-union": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-3.0.1.tgz", - "integrity": "sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw==" + "core-js": { + "version": "3.33.3", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.33.3.tgz", + "integrity": "sha512-lo0kOocUlLKmm6kv/FswQL8zbkH7mVsLJ/FULClOhv8WRVmKLVcs6XPNQAzstfeJTCHMyButEwG+z1kHxHoDZw==" }, - "array.prototype.flatmap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz", - "integrity": "sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA==", + "core-js-compat": { + "version": "3.33.3", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.33.3.tgz", + "integrity": "sha512-cNzGqFsh3Ot+529GIXacjTJ7kegdt5fPXxCBVS1G0iaZpuo/tBz399ymceLJveQhFFZ8qThHiP3fzuoQjKN2ow==", "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" + "browserslist": "^4.22.1" } }, - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + "core-js-pure": { + "version": "3.33.3", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.33.3.tgz", + "integrity": "sha512-taJ00IDOP+XYQEA2dAe4ESkmHt1fL8wzYDo3mRWQey8uO9UojlBFMneA65kMyxfYP7106c6LzWaq7/haDT6BCQ==" }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==" + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, - "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", "requires": { - "lodash": "^4.17.14" + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" } }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" - }, - "autocomplete.js": { - "version": "0.38.1", - "resolved": "https://registry.npmjs.org/autocomplete.js/-/autocomplete.js-0.38.1.tgz", - "integrity": "sha512-6pSJzuRMY3pqpozt+SXThl2DmJfma8Bi3SVFbZHS0PW/N72bOUv+Db0jAh2cWOhTsA4X+GNmKvIl8wExJTnN9w==", + "cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", "requires": { - "immediate": "^3.2.3" + "node-fetch": "^2.6.12" } }, - "autoprefixer": { - "version": "10.4.2", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.2.tgz", - "integrity": "sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ==", + "cross-spawn": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz", + "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==", "requires": { - "browserslist": "^4.19.1", - "caniuse-lite": "^1.0.30001297", - "fraction.js": "^4.1.2", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" } }, - "axios": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", - "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", + "crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", "requires": { - "follow-redirects": "^1.14.7" + "type-fest": "^1.0.1" + }, + "dependencies": { + "type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==" + } } }, - "babel-eslint": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", - "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.7.0", - "@babel/traverse": "^7.7.0", - "@babel/types": "^7.7.0", - "eslint-visitor-keys": "^1.0.0", - "resolve": "^1.12.0" - } + "css-declaration-sorter": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz", + "integrity": "sha512-jDfsatwWMWN0MODAFuHszfjphEXfNw9JUAhmY4pLu3TyTU+ohUpsbVtbU+1MZn4a47D9kqh03i4eyOm+74+zew==", + "requires": {} }, - "babel-loader": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.3.tgz", - "integrity": "sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw==", + "css-loader": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz", + "integrity": "sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==", "requires": { - "find-cache-dir": "^3.3.1", - "loader-utils": "^1.4.0", - "make-dir": "^3.1.0", - "schema-utils": "^2.6.5" + "icss-utils": "^5.1.0", + "postcss": "^8.4.21", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.3", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.8" } }, - "babel-plugin-apply-mdx-type-prop": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-1.6.22.tgz", - "integrity": "sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ==", + "css-minimizer-webpack-plugin": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-4.2.2.tgz", + "integrity": "sha512-s3Of/4jKfw1Hj9CxEO1E5oXhQAxlayuHO2y/ML+C6I9sQ7FdzfEV6QgMLN3vI+qFsjJGIAFLKtQK7t8BOXAIyA==", "requires": { - "@babel/helper-plugin-utils": "7.10.4", - "@mdx-js/util": "1.6.22" + "cssnano": "^5.1.8", + "jest-worker": "^29.1.2", + "postcss": "^8.4.17", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1" }, "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "jest-worker": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", + "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", + "requires": { + "@types/node": "*", + "jest-util": "^29.5.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } } } }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz", - "integrity": "sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==", + "css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "requires": { - "object.assign": "^4.1.0" + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" } }, - "babel-plugin-extract-import-names": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.6.22.tgz", - "integrity": "sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ==", + "css-selector-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-1.4.1.tgz", + "integrity": "sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g==" + }, + "css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", "requires": { - "@babel/helper-plugin-utils": "7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" - } + "mdn-data": "2.0.14", + "source-map": "^0.6.1" } }, - "babel-plugin-polyfill-corejs2": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", - "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", + "css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" + }, + "cssnano": { + "version": "5.1.15", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz", + "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", "requires": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.3.1", - "semver": "^6.1.1" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } + "cssnano-preset-default": "^5.2.14", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" } }, - "babel-plugin-polyfill-corejs3": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", - "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", + "cssnano-preset-advanced": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.10.tgz", + "integrity": "sha512-fnYJyCS9jgMU+cmHO1rPSPf9axbQyD7iUhLO5Df6O4G+fKIOMps+ZbU0PdGFejFBBZ3Pftf18fn1eG7MAPUSWQ==", "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1", - "core-js-compat": "^3.21.0" + "autoprefixer": "^10.4.12", + "cssnano-preset-default": "^5.2.14", + "postcss-discard-unused": "^5.1.0", + "postcss-merge-idents": "^5.1.1", + "postcss-reduce-idents": "^5.2.0", + "postcss-zindex": "^5.1.0" } }, - "babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1" + "cssnano-preset-default": { + "version": "5.2.14", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", + "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", + "requires": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.1", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.4", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.2", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" } }, - "bail": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", - "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==" - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "base16": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz", - "integrity": "sha1-4pf2DX7BAUp6lxo568ipjAtoHnA=" - }, - "batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=" - }, - "bcp-47-match": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-1.0.3.tgz", - "integrity": "sha512-LggQ4YTdjWQSKELZF5JwchnBa1u0pIQSZf5lSdOHEdbVP55h0qICA/FUp3+W99q0xqxYa1ZQizTUH87gecII5w==" + "cssnano-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "requires": {} }, - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" + "csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "requires": { + "css-tree": "^1.1.2" + } }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + "csstype": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", + "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + "debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" }, - "body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.8.1", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.9.7", - "raw-body": "2.4.3", - "type-is": "~1.6.18" - }, - "dependencies": { - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } + "ms": "2.1.2" } }, - "bonjour": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", - "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", "requires": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" + "character-entities": "^2.0.0" } }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" - }, - "boxen": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "requires": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" + "mimic-response": "^3.1.0" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" } } }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" + }, + "default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "execa": "^5.0.0" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==" + }, + "define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "requires": { - "fill-range": "^7.0.1" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" } }, - "browserslist": { - "version": "4.19.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.3.tgz", - "integrity": "sha512-XK3X4xtKJ+Txj8G5c30B4gsm71s69lqXlkYui4s6EkKxuv49qjYlY6oVd+IFJ73d4YymtM3+djvvt/R/iJwwDg==", + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==" + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "requires": { - "caniuse-lite": "^1.0.30001312", - "electron-to-chromium": "^1.4.71", - "escalade": "^3.1.1", - "node-releases": "^2.0.2", - "picocolors": "^1.0.0" + "object-keys": "^1.0.12" } }, - "buble-jsx-only": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/buble-jsx-only/-/buble-jsx-only-0.19.8.tgz", - "integrity": "sha512-7AW19pf7PrKFnGTEDzs6u9+JZqQwM1VnLS19OlqYDhXomtFFknnoQJAPHeg84RMFWAvOhYrG7harizJNwUKJsA==", + "del": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", "requires": { - "acorn": "^6.1.1", - "acorn-dynamic-import": "^4.0.0", - "acorn-jsx": "^5.0.1", - "chalk": "^2.4.2", - "magic-string": "^0.25.3", - "minimist": "^1.2.0", - "regexpu-core": "^4.5.4" - }, - "dependencies": { - "acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" - }, - "acorn-dynamic-import": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz", - "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==", - "requires": {} - }, - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" - }, - "regenerate-unicode-properties": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz", - "integrity": "sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA==", - "requires": { - "regenerate": "^1.4.2" - } - }, - "regexpu-core": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.8.0.tgz", - "integrity": "sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg==", - "requires": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^9.0.0", - "regjsgen": "^0.5.2", - "regjsparser": "^0.7.0", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" - } - }, - "regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==" - }, - "regjsparser": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.7.0.tgz", - "integrity": "sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ==", - "requires": { - "jsesc": "~0.5.0" - } - } + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" } }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" }, - "buffer-indexof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==" + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" }, - "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + "dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==" }, - "cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, + "detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + }, + "detect-port": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", + "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", + "requires": { + "address": "^1.0.1", + "debug": "4" + } + }, + "detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" + "address": "^1.0.1", + "debug": "^2.6.0" }, "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "requires": { - "pump": "^3.0.0" + "ms": "2.0.0" } }, - "lowercase-keys": { + "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" - }, - "normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==" + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" } } }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "dequal": "^2.0.0" } }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" - }, - "camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "requires": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" + "path-type": "^4.0.0" } }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" + "direction": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/direction/-/direction-1.0.4.tgz", + "integrity": "sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ==" }, - "camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==" + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==" }, - "caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dns-packet": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.0.tgz", + "integrity": "sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ==", "requires": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" + "@leichtgewicht/ip-codec": "^2.0.1" } }, - "caniuse-lite": { - "version": "1.0.30001312", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz", - "integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==" - }, - "ccount": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz", - "integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==" - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "esutils": "^2.0.2" } }, - "character-entities": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", - "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==" - }, - "character-entities-legacy": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", - "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==" - }, - "character-reference-invalid": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", - "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==" - }, - "cheerio": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", - "integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=", - "requires": { - "css-select": "~1.2.0", - "dom-serializer": "~0.1.0", - "entities": "~1.1.1", - "htmlparser2": "^3.9.1", - "lodash.assignin": "^4.0.9", - "lodash.bind": "^4.1.4", - "lodash.defaults": "^4.0.1", - "lodash.filter": "^4.4.0", - "lodash.flatten": "^4.2.0", - "lodash.foreach": "^4.3.0", - "lodash.map": "^4.4.0", - "lodash.merge": "^4.4.0", - "lodash.pick": "^4.2.1", - "lodash.reduce": "^4.4.0", - "lodash.reject": "^4.4.0", - "lodash.some": "^4.4.0" + "docusaurus-lunr-search": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/docusaurus-lunr-search/-/docusaurus-lunr-search-3.3.0.tgz", + "integrity": "sha512-F2fSAA+6vRCHxF4R+rV8xSg1cYY7pXFKdbBNlTX6+dyKdwCWcnrmTXJmlCkN4DT65ntNU9iTd+mZ8lZzH3Lncg==", + "requires": { + "autocomplete.js": "^0.37.0", + "clsx": "^1.2.1", + "gauge": "^3.0.0", + "hast-util-select": "^4.0.0", + "hast-util-to-text": "^2.0.0", + "hogan.js": "^3.0.2", + "lunr": "^2.3.8", + "lunr-languages": "^1.4.0", + "mark.js": "^8.11.1", + "minimatch": "^3.0.4", + "object-assign": "^4.1.1", + "rehype-parse": "^7.0.1", + "to-vfile": "^6.1.0", + "unified": "^9.0.0", + "unist-util-is": "^4.0.2" }, "dependencies": { - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + "autocomplete.js": { + "version": "0.37.1", + "resolved": "https://registry.npmjs.org/autocomplete.js/-/autocomplete.js-0.37.1.tgz", + "integrity": "sha512-PgSe9fHYhZEsm/9jggbjtVsGXJkPLvd+9mC7gZJ662vVL5CRWEtm/mIrrzCx0MrNxHVwxD5d00UOn6NsmL2LUQ==", + "requires": { + "immediate": "^3.2.3" + } } } }, - "cheerio-select": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz", - "integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==", + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", "requires": { - "css-select": "^4.1.3", - "css-what": "^5.0.1", - "domelementtype": "^2.2.0", + "utila": "~0.4" + } + }, + "dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "requires": { + "domelementtype": "^2.0.1", "domhandler": "^4.2.0", - "domutils": "^2.7.0" + "entities": "^2.0.0" }, "dependencies": { - "css-select": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", - "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", - "requires": { - "boolbase": "^1.0.0", - "css-what": "^5.1.0", - "domhandler": "^4.3.0", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - } - }, - "css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==" - }, - "dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - } - }, - "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" - }, - "domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", - "requires": { - "domelementtype": "^2.2.0" - } - }, - "domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - } - }, "entities": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" - }, - "nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "requires": { - "boolbase": "^1.0.0" - } } } }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, - "chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" - }, - "classnames": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", - "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" }, - "clean-css": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.2.4.tgz", - "integrity": "sha512-nKseG8wCzEuji/4yrgM/5cthL9oTDc5UOQyFMvW/Q53oP6gLH690o1NbuTh6Y18nujr7BxlsFuS7gXLnLzKJGg==", + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "requires": { - "source-map": "~0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } + "domelementtype": "^2.2.0" } }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" - }, - "cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==" - }, - "clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "requires": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" } }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", "requires": { - "mimic-response": "^1.0.0" + "no-case": "^3.0.4", + "tslib": "^2.0.3" } }, - "clsx": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", - "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==" - }, - "collapse-white-space": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz", - "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==" - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", "requires": { - "color-name": "1.1.3" + "is-obj": "^2.0.0" } }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" }, - "color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, - "colord": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.2.tgz", - "integrity": "sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ==" + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, - "colorette": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", - "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==" + "electron-to-chromium": { + "version": "1.4.590", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.590.tgz", + "integrity": "sha512-hohItzsQcG7/FBsviCYMtQwUSWvVF7NVqPOnJCErWsAshsP/CR2LAXdmq276RbESNdhxiAq5/vRo1g2pxGXVww==" }, - "combine-promises": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/combine-promises/-/combine-promises-1.1.0.tgz", - "integrity": "sha512-ZI9jvcLDxqwaXEixOhArm3r7ReIivsXkpbyEWyeOhzz1QS0iSgBPnWvEqvIQtYyamGCYA88gFhmUrs9hrrQ0pg==" + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "emojilib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", + "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==" }, - "comma-separated-tokens": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", - "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==" + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" }, - "commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==" + "emoticon": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/emoticon/-/emoticon-4.0.1.tgz", + "integrity": "sha512-dqx7eA9YaqyvYtUhJwT4rC1HIp82j5ybS1/vQ42ur+jBe17dJMwZE4+gvL1XadSFfxaPFFGt3Xsw+Y8akThDlw==" }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" + "encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" }, - "compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "requires": { - "mime-db": ">= 1.43.0 < 2" - }, - "dependencies": { - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - } + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" } }, - "compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", "requires": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } + "ansi-colors": "^4.1.1" } }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" }, - "configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "requires": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" + "is-arrayish": "^0.2.1" } }, - "connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==" - }, - "consola": { - "version": "2.15.3", - "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", - "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" + "es-abstract": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + "es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "requires": { + "get-intrinsic": "^1.2.4" + } }, - "content-disposition": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + "es-module-lexer": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", + "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==" }, - "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "requires": { - "safe-buffer": "~5.1.1" + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" } }, - "cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + "escape-goat": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", + "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==" }, - "copy-text-to-clipboard": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.0.1.tgz", - "integrity": "sha512-rvVsHrpFcL4F2P8ihsoLdFHmd404+CMg71S756oRSeQgqk51U3kicGdnvfkrxva0xXH92SjGS62B0XIJsbh+9Q==" + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, - "copy-webpack-plugin": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-10.2.4.tgz", - "integrity": "sha512-xFVltahqlsRcyyJqQbDY6EYTtyQZF9rf+JPjwHObLdPFMEISqkFkr7mFoVOC6BfYS/dNThyoQKvziugm+OnwBg==", + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", "requires": { - "fast-glob": "^3.2.7", - "glob-parent": "^6.0.1", - "globby": "^12.0.2", - "normalize-path": "^3.0.0", - "schema-utils": "^4.0.0", - "serialize-javascript": "^6.0.0" + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" }, "dependencies": { - "ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "@babel/highlight": "^7.10.4" } }, - "ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "requires": { - "fast-deep-equal": "^3.1.3" + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" } }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==" + }, + "globals": { + "version": "13.12.1", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", + "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", "requires": { - "is-glob": "^4.0.3" + "type-fest": "^0.20.2" } }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "schema-utils": { + "has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" + "has-flag": "^4.0.0" } } } }, - "core-js": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.21.1.tgz", - "integrity": "sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==" - }, - "core-js-compat": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.1.tgz", - "integrity": "sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g==", - "requires": { - "browserslist": "^4.19.1", - "semver": "7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" - } - } - }, - "core-js-pure": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.21.1.tgz", - "integrity": "sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ==" - }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, - "cosmiconfig": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", - "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - } - }, - "cross-fetch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", - "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", - "requires": { - "node-fetch": "2.6.7" - } - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" - }, - "css-declaration-sorter": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.1.4.tgz", - "integrity": "sha512-lpfkqS0fctcmZotJGhnxkIyJWvBXgpyi2wsFd4J8VB7wzyrT6Ch/3Q+FMNJpjK4gu1+GN5khOnpU2ZVKrLbhCw==", - "requires": { - "timsort": "^0.3.0" - } - }, - "css-loader": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.6.0.tgz", - "integrity": "sha512-FK7H2lisOixPT406s5gZM1S3l8GrfhEBT3ZiL2UX1Ng1XWs0y2GPllz/OTyvbaHe12VgQrIXIzuEGVlbUhodqg==", - "requires": { - "icss-utils": "^5.1.0", - "postcss": "^8.4.5", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.2.0", - "semver": "^7.3.5" - } - }, - "css-minimizer-webpack-plugin": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz", - "integrity": "sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==", + "eslint-plugin-react": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.28.0.tgz", + "integrity": "sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw==", "requires": { - "cssnano": "^5.0.6", - "jest-worker": "^27.0.2", - "postcss": "^8.3.5", - "schema-utils": "^4.0.0", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1" + "array-includes": "^3.1.4", + "array.prototype.flatmap": "^1.2.5", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.0.4", + "object.entries": "^1.1.5", + "object.fromentries": "^2.0.5", + "object.hasown": "^1.1.0", + "object.values": "^1.1.5", + "prop-types": "^15.7.2", + "resolve": "^2.0.0-next.3", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.6" }, "dependencies": { - "ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "requires": { - "fast-deep-equal": "^3.1.3" + "esutils": "^2.0.2" } }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "resolve": { + "version": "2.0.0-next.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", + "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, - "css-select": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", - "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", - "requires": { - "boolbase": "~1.0.0", - "css-what": "2.1", - "domutils": "1.5.1", - "nth-check": "~1.0.1" - } - }, - "css-selector-parser": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-1.4.1.tgz", - "integrity": "sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g==" - }, - "css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "requires": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" }, "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" } } }, - "css-what": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", - "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==" - }, - "cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" - }, - "cssnano": { - "version": "5.0.17", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.0.17.tgz", - "integrity": "sha512-fmjLP7k8kL18xSspeXTzRhaFtRI7DL9b8IcXR80JgtnWBpvAzHT7sCR/6qdn0tnxIaINUN6OEQu83wF57Gs3Xw==", - "requires": { - "cssnano-preset-default": "^5.1.12", - "lilconfig": "^2.0.3", - "yaml": "^1.10.2" - } - }, - "cssnano-preset-advanced": { - "version": "5.1.12", - "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-5.1.12.tgz", - "integrity": "sha512-5WWV9mbqVNwH4nRjs5UbhNl7eKo+16eYNzGogmz0Sa6iqWUeLdN8oo83WuTTqz5vjEKhTbRM5oX6WV1i6ees6g==", - "requires": { - "autoprefixer": "^10.3.7", - "cssnano-preset-default": "^5.1.12", - "postcss-discard-unused": "^5.0.3", - "postcss-merge-idents": "^5.0.3", - "postcss-reduce-idents": "^5.0.3", - "postcss-zindex": "^5.0.2" - } - }, - "cssnano-preset-default": { - "version": "5.1.12", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.1.12.tgz", - "integrity": "sha512-rO/JZYyjW1QNkWBxMGV28DW7d98UDLaF759frhli58QFehZ+D/LSmwQ2z/ylBAe2hUlsIWTq6NYGfQPq65EF9w==", - "requires": { - "css-declaration-sorter": "^6.0.3", - "cssnano-utils": "^3.0.2", - "postcss-calc": "^8.2.0", - "postcss-colormin": "^5.2.5", - "postcss-convert-values": "^5.0.4", - "postcss-discard-comments": "^5.0.3", - "postcss-discard-duplicates": "^5.0.3", - "postcss-discard-empty": "^5.0.3", - "postcss-discard-overridden": "^5.0.4", - "postcss-merge-longhand": "^5.0.6", - "postcss-merge-rules": "^5.0.6", - "postcss-minify-font-values": "^5.0.4", - "postcss-minify-gradients": "^5.0.6", - "postcss-minify-params": "^5.0.5", - "postcss-minify-selectors": "^5.1.3", - "postcss-normalize-charset": "^5.0.3", - "postcss-normalize-display-values": "^5.0.3", - "postcss-normalize-positions": "^5.0.4", - "postcss-normalize-repeat-style": "^5.0.4", - "postcss-normalize-string": "^5.0.4", - "postcss-normalize-timing-functions": "^5.0.3", - "postcss-normalize-unicode": "^5.0.4", - "postcss-normalize-url": "^5.0.5", - "postcss-normalize-whitespace": "^5.0.4", - "postcss-ordered-values": "^5.0.5", - "postcss-reduce-initial": "^5.0.3", - "postcss-reduce-transforms": "^5.0.4", - "postcss-svgo": "^5.0.4", - "postcss-unique-selectors": "^5.0.4" - } - }, - "cssnano-utils": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.0.2.tgz", - "integrity": "sha512-KhprijuQv2sP4kT92sSQwhlK3SJTbDIsxcfIEySB0O+3m9esFOai7dP9bMx5enHAh2MwarVIcnwiWoOm01RIbQ==", - "requires": {} - }, - "csso": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", - "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", - "requires": { - "css-tree": "^1.1.2" - } - }, - "csstype": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", - "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" - }, - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", "requires": { - "ms": "2.1.2" + "eslint-visitor-keys": "^1.1.0" } }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "requires": { - "mimic-response": "^1.0.0" - } + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" }, - "deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", "requires": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" } }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" - }, - "default-gateway": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "requires": { - "execa": "^5.0.0" + "estraverse": "^5.1.0" } }, - "defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "requires": { + "estraverse": "^5.2.0" + } }, - "define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==" + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "estree-util-attach-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", + "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", "requires": { - "object-keys": "^1.0.12" + "@types/estree": "^1.0.0" } }, - "del": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", - "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", + "estree-util-build-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", "requires": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - }, - "dependencies": { - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" - } + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-walker": "^3.0.0" } }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + "estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==" }, - "detab": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detab/-/detab-2.0.4.tgz", - "integrity": "sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g==", + "estree-util-to-js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", + "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", "requires": { - "repeat-string": "^1.5.4" + "@types/estree-jsx": "^1.0.0", + "astring": "^1.8.0", + "source-map": "^0.7.0" + }, + "dependencies": { + "source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==" + } } }, - "detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" - }, - "detect-port": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.3.0.tgz", - "integrity": "sha512-E+B1gzkl2gqxt1IhUzwjrxBKRqx1UzC3WLONHinn8S3T6lwV/agVCyitiFOsGJ/eYuEUBvD71MZHy3Pv1G9doQ==", + "estree-util-value-to-estree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-value-to-estree/-/estree-util-value-to-estree-3.0.1.tgz", + "integrity": "sha512-b2tdzTurEIbwRh+mKrEcaWfu1wgb8J1hVsgREg7FFiecWwK/PhO8X0kyc+0bIcKNtD4sqxIdNoRy6/p/TvECEA==", "requires": { - "address": "^1.0.1", - "debug": "^2.6.0" + "@types/estree": "^1.0.0", + "is-plain-obj": "^4.0.0" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==" } } }, - "detect-port-alt": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", - "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "estree-util-visit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", "requires": { - "address": "^1.0.1", - "debug": "^2.6.0" + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" } } }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "requires": { - "path-type": "^4.0.0" + "@types/estree": "^1.0.0" } }, - "direction": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/direction/-/direction-1.0.4.tgz", - "integrity": "sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ==" + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" }, - "dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=" + "eta": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eta/-/eta-2.2.0.tgz", + "integrity": "sha512-UVQ72Rqjy/ZKQalzV5dCCJP80GrmPrMxh6NlNf+erV6ObL0ZFkhCstWRawS85z3smdr3d2wXPsZEY7rDPfGd2g==" }, - "dns-packet": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", - "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", - "requires": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" - } + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, - "dns-txt": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", - "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "eval": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eval/-/eval-0.1.8.tgz", + "integrity": "sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==", "requires": { - "buffer-indexof": "^1.0.0" + "@types/node": "*", + "require-like": ">= 0.1.1" } }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "requires": { - "esutils": "^2.0.2" + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" } }, - "docusaurus-lunr-search": { - "version": "2.1.15", - "resolved": "https://registry.npmjs.org/docusaurus-lunr-search/-/docusaurus-lunr-search-2.1.15.tgz", - "integrity": "sha512-W37af7ziwNFstM0VNjruJi3HChPWI5BWGAAxFYpRRbMZQAZqdQtz4aZHX5E/ORrfqHWsKTGMCRWode1rb3ncQw==", + "express": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "requires": { - "autocomplete.js": "^0.37.0", - "classnames": "^2.2.6", - "gauge": "^3.0.0", - "hast-util-select": "^4.0.0", - "hast-util-to-text": "^2.0.0", - "hogan.js": "^3.0.2", - "lunr": "^2.3.8", - "lunr-languages": "^1.4.0", - "minimatch": "^3.0.4", - "object-assign": "^4.1.1", - "rehype-parse": "^7.0.1", - "to-vfile": "^6.1.0", - "unified": "^9.0.0", - "unist-util-is": "^4.0.2" + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.10", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" }, "dependencies": { - "autocomplete.js": { - "version": "0.37.1", - "resolved": "https://registry.npmjs.org/autocomplete.js/-/autocomplete.js-0.37.1.tgz", - "integrity": "sha512-PgSe9fHYhZEsm/9jggbjtVsGXJkPLvd+9mC7gZJ662vVL5CRWEtm/mIrrzCx0MrNxHVwxD5d00UOn6NsmL2LUQ==", + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "requires": { - "immediate": "^3.2.3" + "safe-buffer": "5.2.1" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "path-to-regexp": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" } } }, - "dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "requires": { - "utila": "~0.4" + "is-extendable": "^0.1.0" } }, - "dom-serializer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", - "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "requires": { - "domelementtype": "^1.3.0", - "entities": "^1.1.1" - }, - "dependencies": { - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" - } + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" } }, - "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, - "domhandler": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "fast-url-parser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", + "integrity": "sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=", "requires": { - "domelementtype": "1" + "punycode": "^1.3.2" } }, - "domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", "requires": { - "dom-serializer": "0", - "domelementtype": "1" + "reusify": "^1.0.4" } }, - "dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "fault": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", + "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", "requires": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" + "format": "^0.2.0" } }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "requires": { - "is-obj": "^2.0.0" + "websocket-driver": ">=0.5.1" } }, - "duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "electron-to-chromium": { - "version": "1.4.71", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.71.tgz", - "integrity": "sha512-Hk61vXXKRb2cd3znPE9F+2pLWdIOmP7GjiTj45y6L3W/lO+hSnUSUhq+6lEaERWBdZOHbk2s3YV5c9xVl3boVw==" - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "emojis-list": { + "fbemitter": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" + "resolved": "https://registry.npmjs.org/fbemitter/-/fbemitter-3.0.0.tgz", + "integrity": "sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==", + "requires": { + "fbjs": "^3.0.0" + } }, - "emoticon": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/emoticon/-/emoticon-3.2.0.tgz", - "integrity": "sha512-SNujglcLTTg+lDAcApPNgEdudaqQFiAbJCqzjNxJkvN9vAwCGi0uu8IUVvx+f16h+V44KCY6Y2yboroc9pilHg==" + "fbjs": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.5.tgz", + "integrity": "sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==", + "requires": { + "cross-fetch": "^3.1.5", + "fbjs-css-vars": "^1.0.0", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^1.0.35" + } }, - "encodeurl": { + "fbjs-css-vars": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", + "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==" }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "feed": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz", + "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==", "requires": { - "once": "^1.4.0" + "xml-js": "^1.6.11" } }, - "enhanced-resolve": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.0.tgz", - "integrity": "sha512-weDYmzbBygL7HzGGS26M3hGQx68vehdEg6VUmqSOaFzXExFqlnKuSvsEJCVGQHScS8CQMbrAqftT+AzzHNt/YA==", + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "requires": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" + "flat-cache": "^3.0.4" } }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", "requires": { - "ansi-colors": "^4.1.1" + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } } }, - "entities": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", - "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==" + "filesize": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", + "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==" }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "requires": { - "is-arrayish": "^0.2.1" + "to-regex-range": "^5.0.1" } }, - "es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } } }, - "es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==" - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" } }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" - }, - "escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==" - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", "requires": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "dependencies": { + "path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==" + } + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==" + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==" + }, + "follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" + }, + "fork-ts-checker-webpack-plugin": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz", + "integrity": "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==", + "requires": { + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "chokidar": "^3.4.2", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "glob": "^7.1.6", + "memfs": "^3.1.2", "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" }, "dependencies": { - "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "requires": { - "@babel/highlight": "^7.10.4" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -20865,22 +25533,27 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" - }, - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==" + "cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + } }, - "globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "requires": { - "type-fest": "^0.20.2" + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" } }, "has-flag": { @@ -20888,6 +25561,16 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, + "schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "requires": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -20895,1946 +25578,3232 @@ "requires": { "has-flag": "^4.0.0" } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" } } }, - "eslint-plugin-react": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.28.0.tgz", - "integrity": "sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw==", + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "requires": { - "array-includes": "^3.1.4", - "array.prototype.flatmap": "^1.2.5", - "doctrine": "^2.1.0", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==" + }, + "format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==" + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs-monkey": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.4.tgz", + "integrity": "sha512-INM/fWAxMICjttnD0DX1rBvinKskj5G1w+oy/pnm9u/tSlnBrzFonJMcalKJ30P8RRsPzKcCG7Q8l0jx5Fh9YQ==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" + }, + "gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + } + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + }, + "get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "github-slugger": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.5.0.tgz", + "integrity": "sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==" + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", "minimatch": "^3.0.4", - "object.entries": "^1.1.5", - "object.fromentries": "^2.0.5", - "object.hasown": "^1.1.0", - "object.values": "^1.1.5", - "prop-types": "^15.7.2", - "resolve": "^2.0.0-next.3", - "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.6" + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "requires": { + "ini": "2.0.0" + }, + "dependencies": { + "ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==" + } + } + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "requires": { + "global-prefix": "^3.0.0" + } + }, + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" }, "dependencies": { - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "requires": { - "esutils": "^2.0.2" - } - }, - "resolve": { - "version": "2.0.0-next.3", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", - "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "isexe": "^2.0.0" } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" }, "dependencies": { - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==" } } }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "requires": { - "eslint-visitor-keys": "^1.1.0" + "get-intrinsic": "^1.1.3" } }, - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" + "got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "requires": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + } }, - "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" } }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", "requires": { - "estraverse": "^5.1.0" + "duplexer": "^0.1.2" } }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "requires": { - "estraverse": "^5.2.0" + "function-bind": "^1.1.1" } }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, - "eta": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/eta/-/eta-1.12.3.tgz", - "integrity": "sha512-qHixwbDLtekO/d51Yr4glcaUJCIjGVJyTzuqV4GPlgZo1YpgOKG+avQynErZIYrfM6JIJdtiG2Kox8tbb+DoGg==" + "has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "requires": { + "es-define-property": "^1.0.0" + } }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + "has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==" }, - "eval": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/eval/-/eval-0.1.6.tgz", - "integrity": "sha512-o0XUw+5OGkXw4pJZzQoXUk+H87DHuC+7ZE//oSrRGtatTmr12oTnLfg6QOq9DyTt0c/p4TwzgmkKrBzWTSizyQ==", + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", "requires": { - "require-like": ">= 0.1.1" + "has-symbols": "^1.0.2" } }, - "eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" }, - "events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + "has-yarn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz", + "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==" }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "dependencies": { - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" - } + "function-bind": "^1.1.2" } }, - "express": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", - "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", + "hast-util-from-parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-6.0.1.tgz", + "integrity": "sha512-jeJUWiN5pSxW12Rh01smtVkZgZr33wBokLzKLwinYOUfSzm1Nl/c3GUGebDyOKjdsRgMvoVbV0VpAcpjF4NrJA==", "requires": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.19.2", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.4.2", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.9.7", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.17.2", - "serve-static": "1.14.2", - "setprototypeof": "1.2.0", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + "@types/parse5": "^5.0.0", + "hastscript": "^6.0.0", + "property-information": "^5.0.0", + "vfile": "^4.0.0", + "vfile-location": "^3.2.0", + "web-namespaces": "^1.0.0" + } + }, + "hast-util-has-property": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-1.0.4.tgz", + "integrity": "sha512-ghHup2voGfgFoHMGnaLHOjbYFACKrRh9KFttdCzMCbFoBMJXiNi2+XTrPP8+q6cDJM/RSqlCfVWrjp1H201rZg==" + }, + "hast-util-is-element": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-1.1.0.tgz", + "integrity": "sha512-oUmNua0bFbdrD/ELDSSEadRVtWZOf3iF6Lbv81naqsIV99RnSCieTbWuWCY8BAeEfKJTKl0gRdokv+dELutHGQ==" + }, + "hast-util-parse-selector": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", + "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==" + }, + "hast-util-raw": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.0.1.tgz", + "integrity": "sha512-5m1gmba658Q+lO5uqL5YNGQWeh1MYWZbZmWrM5lncdcuiXuo5E2HT/CIOp0rLF8ksfSwiCVJ3twlgVRyTGThGA==", + "requires": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "dependencies": { + "@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "requires": { + "@types/unist": "*" + } + }, + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==" + }, + "hast-util-from-parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.1.tgz", + "integrity": "sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==", + "requires": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^8.0.0", + "property-information": "^6.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + } + }, + "hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "requires": { + "@types/hast": "^3.0.0" + } + }, + "hastscript": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-8.0.0.tgz", + "integrity": "sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==", + "requires": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0" + } + }, + "parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "requires": { + "entities": "^4.4.0" + } }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "property-information": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.4.0.tgz", + "integrity": "sha512-9t5qARVofg2xQqKtytzt+lZ4d1Qvj8t5B8fEwXK6qOfgRLgH/b13QlgEyDh033NOS31nXeFbYv7CLUDG1CeifQ==" + }, + "space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==" + }, + "unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", "requires": { - "safe-buffer": "5.2.1" + "@types/unist": "^3.0.0" } }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", "requires": { - "ms": "2.0.0" + "@types/unist": "^3.0.0" } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + } }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + "unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + } }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + "vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + } }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + "vfile-location": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.2.tgz", + "integrity": "sha512-NXPYyxyBSH7zB5U6+3uDdd6Nybz6o6/od9rk8bp9H8GR3L+cm/fC0uUTbqBmUTnMCUDslAGBOIKNfvvb+gGlDg==", + "requires": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + } + }, + "vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + } + }, + "web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==" + }, + "zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==" } } }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "hast-util-select": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hast-util-select/-/hast-util-select-4.0.2.tgz", + "integrity": "sha512-8EEG2//bN5rrzboPWD2HdS3ugLijNioS1pqOTIolXNf67xxShYw4SQEmVXd3imiBG+U2bC2nVTySr/iRAA7Cjg==", "requires": { - "is-extendable": "^0.1.0" + "bcp-47-match": "^1.0.0", + "comma-separated-tokens": "^1.0.0", + "css-selector-parser": "^1.0.0", + "direction": "^1.0.0", + "hast-util-has-property": "^1.0.0", + "hast-util-is-element": "^1.0.0", + "hast-util-to-string": "^1.0.0", + "hast-util-whitespace": "^1.0.0", + "not": "^0.1.0", + "nth-check": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0", + "unist-util-visit": "^2.0.0", + "zwitch": "^1.0.0" } }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "hast-util-to-estree": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.0.tgz", + "integrity": "sha512-lfX5g6hqVh9kjS/B9E2gSkvHH4SZNiQFiqWS0x9fENzEl+8W12RqdRxX6d/Cwxi30tPQs3bIO+aolQJNp1bIyw==", + "requires": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^0.4.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" + }, + "dependencies": { + "@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "requires": { + "@types/unist": "*" + } + }, + "comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==" + }, + "hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "requires": { + "@types/hast": "^3.0.0" + } + }, + "property-information": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.4.0.tgz", + "integrity": "sha512-9t5qARVofg2xQqKtytzt+lZ4d1Qvj8t5B8fEwXK6qOfgRLgH/b13QlgEyDh033NOS31nXeFbYv7CLUDG1CeifQ==" + }, + "space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==" + }, + "zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==" + } + } }, - "fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "hast-util-to-jsx-runtime": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.2.0.tgz", + "integrity": "sha512-wSlp23N45CMjDg/BPW8zvhEi3R+8eRE1qFbjEyAUzMCzu2l1Wzwakq+Tlia9nkCtEl5mDxa7nKHsvYJ6Gfn21A==", + "requires": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^0.4.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "dependencies": { + "@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "requires": { + "@types/unist": "*" + } + }, + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==" + }, + "hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "requires": { + "@types/hast": "^3.0.0" + } + }, + "property-information": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.4.0.tgz", + "integrity": "sha512-9t5qARVofg2xQqKtytzt+lZ4d1Qvj8t5B8fEwXK6qOfgRLgH/b13QlgEyDh033NOS31nXeFbYv7CLUDG1CeifQ==" + }, + "space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==" + }, + "unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + } + } } }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + "hast-util-to-parse5": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz", + "integrity": "sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==", + "requires": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "dependencies": { + "@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "requires": { + "@types/unist": "*" + } + }, + "comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==" + }, + "property-information": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.4.0.tgz", + "integrity": "sha512-9t5qARVofg2xQqKtytzt+lZ4d1Qvj8t5B8fEwXK6qOfgRLgH/b13QlgEyDh033NOS31nXeFbYv7CLUDG1CeifQ==" + }, + "space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==" + }, + "web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==" + }, + "zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==" + } + } }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + "hast-util-to-string": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-1.0.4.tgz", + "integrity": "sha512-eK0MxRX47AV2eZ+Lyr18DCpQgodvaS3fAQO2+b9Two9F5HEoRPhiUMNzoXArMJfZi2yieFzUBMRl3HNJ3Jus3w==" }, - "fast-url-parser": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", - "integrity": "sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=", + "hast-util-to-text": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-2.0.1.tgz", + "integrity": "sha512-8nsgCARfs6VkwH2jJU9b8LNTuR4700na+0h3PqCaEk4MAnMDeu5P0tP8mjk9LLNGxIeQRLbiDbZVw6rku+pYsQ==", "requires": { - "punycode": "^1.3.2" + "hast-util-is-element": "^1.0.0", + "repeat-string": "^1.0.0", + "unist-util-find-after": "^3.0.0" } }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "requires": { - "reusify": "^1.0.4" - } + "hast-util-whitespace": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-1.0.4.tgz", + "integrity": "sha512-I5GTdSfhYfAPNztx2xJRQpG8cuDSNt599/7YUn7Gx/WxNMsG+a835k97TDkFgk123cwjfwINaZknkKkphx/f2A==" }, - "faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "hastscript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", + "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", "requires": { - "websocket-driver": ">=0.5.1" + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^1.0.0", + "hast-util-parse-selector": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0" } }, - "fbemitter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/fbemitter/-/fbemitter-3.0.0.tgz", - "integrity": "sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==", - "requires": { - "fbjs": "^3.0.0" - } + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, - "fbjs": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.4.tgz", - "integrity": "sha512-ucV0tDODnGV3JCnnkmoszb5lf4bNpzjv80K41wd4k798Etq+UYD0y0TIfalLjZoKgjive6/adkRnszwapiDgBQ==", + "history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", "requires": { - "cross-fetch": "^3.1.5", - "fbjs-css-vars": "^1.0.0", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.30" + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" } }, - "fbjs-css-vars": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", - "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==" - }, - "feed": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz", - "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==", + "hogan.js": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/hogan.js/-/hogan.js-3.0.2.tgz", + "integrity": "sha1-TNnhq9QpQUbnZ55B14mHMrAse/0=", "requires": { - "xml-js": "^1.6.11" + "mkdirp": "0.3.0", + "nopt": "1.0.10" } }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", "requires": { - "flat-cache": "^3.0.4" + "react-is": "^16.7.0" } }, - "file-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", - "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "requires": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" }, "dependencies": { - "loader-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "safe-buffer": "~5.1.0" } } } }, - "filesize": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", - "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==" + "html-entities": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz", + "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==" }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" + }, + "html-minifier-terser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", + "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", "requires": { - "to-regex-range": "^5.0.1" + "camel-case": "^4.1.2", + "clean-css": "~5.3.2", + "commander": "^10.0.0", + "entities": "^4.4.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.15.1" + }, + "dependencies": { + "commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==" + } } }, - "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==" + }, + "html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==" + }, + "html-webpack-plugin": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz", + "integrity": "sha512-6YrDKTuqaP/TquFH7h4srYWsZx+x6k6+FbsTm0ziCwGHDP78Unr1r9F/H4+sGmMbX08GQcJ+K64x55b+7VM/jg==", "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==" + }, + "html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", "requires": { - "ms": "2.0.0" + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" } } }, - "find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + }, + "dependencies": { + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + } } }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } + "http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" } }, - "flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==" + "http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" }, - "follow-redirects": { - "version": "1.14.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", - "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + "http-proxy-middleware": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", + "requires": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "dependencies": { + "is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==" + } + } }, - "fraction.js": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.3.tgz", - "integrity": "sha512-pUHWWt6vHzZZiQJcM6S/0PXfS+g6FM4BF5rj9wZyreivhQPdsh5PpE25VtSNxq80wHS5RfY51Ii+8Z0Zl/pmzg==" + "http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + } }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" }, - "fs-extra": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", - "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "safer-buffer": ">= 2.1.2 < 3" } }, - "fs-monkey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", - "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==" + "icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "requires": {} }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "optional": true + "image-size": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.2.tgz", + "integrity": "sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==", + "requires": { + "queue": "6.0.2" + } }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "immediate": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", + "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==" }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" + "immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==" }, - "gauge": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", - "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "requires": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.2", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.1", - "object-assign": "^4.1.1", - "signal-exit": "^3.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.2" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" } }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + "import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==" }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" + }, + "infima": { + "version": "0.2.0-alpha.43", + "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.43.tgz", + "integrity": "sha512-2uw57LvUqW0rK/SWYnd/2rRfxNA5DDNOh33jxF7fy46VWoNhGxiUQyVZHbBMjQ33mQem0cjdDVwgWVAmlRfgyQ==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "once": "^1.3.0", + "wrappy": "1" } }, - "get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "requires": { - "pump": "^3.0.0" - } + "inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" } }, - "github-slugger": { + "interpret": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.4.0.tgz", - "integrity": "sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ==" + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==" }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "loose-envify": "^1.0.0" } }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==" + }, + "is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==" + }, + "is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", "requires": { - "is-glob": "^4.0.1" + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" } }, - "glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, - "global-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "requires": { - "ini": "2.0.0" - }, - "dependencies": { - "ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==" - } + "has-bigints": "^1.0.1" } }, - "global-modules": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", - "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "requires": { - "global-prefix": "^3.0.0" + "binary-extensions": "^2.0.0" } }, - "global-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "requires": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" - }, - "dependencies": { - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - } + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" } }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" }, - "globby": { - "version": "12.2.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-12.2.0.tgz", - "integrity": "sha512-wiSuFQLZ+urS9x2gGPl1H5drc5twabmm4m2gTR27XDFyjUHJUNsS8o/2aKyIF6IoBaR630atdher0XJ5g6OMmA==", - "requires": { - "array-union": "^3.0.1", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.7", - "ignore": "^5.1.9", - "merge2": "^1.4.1", - "slash": "^4.0.0" - }, - "dependencies": { - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" - }, - "slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==" - } - } + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" }, - "got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "requires": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" + "is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "requires": { + "ci-info": "^3.2.0" } }, - "graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" - }, - "gray-matter": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", - "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "is-core-module": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", "requires": { - "js-yaml": "^3.13.1", - "kind-of": "^6.0.2", - "section-matter": "^1.0.0", - "strip-bom-string": "^1.0.0" + "has": "^1.0.3" } }, - "gzip-size": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", - "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "requires": { - "duplexer": "^0.1.2" + "has-tostringtag": "^1.0.0" } }, - "handle-thing": { + "is-decimal": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==" }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" }, - "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==" }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "requires": { - "has-symbols": "^1.0.2" + "is-extglob": "^2.1.1" } }, - "has-unicode": { + "is-hexadecimal": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" - }, - "has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==" + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==" }, - "hast-to-hyperscript": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz", - "integrity": "sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA==", + "is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", "requires": { - "@types/unist": "^2.0.3", - "comma-separated-tokens": "^1.0.0", - "property-information": "^5.3.0", - "space-separated-tokens": "^1.0.0", - "style-to-object": "^0.3.0", - "unist-util-is": "^4.0.0", - "web-namespaces": "^1.0.0" + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" } }, - "hast-util-from-parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-6.0.1.tgz", - "integrity": "sha512-jeJUWiN5pSxW12Rh01smtVkZgZr33wBokLzKLwinYOUfSzm1Nl/c3GUGebDyOKjdsRgMvoVbV0VpAcpjF4NrJA==", + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==" + }, + "is-npm": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", + "integrity": "sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==" + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-number-object": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", + "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", "requires": { - "@types/parse5": "^5.0.0", - "hastscript": "^6.0.0", - "property-information": "^5.0.0", - "vfile": "^4.0.0", - "vfile-location": "^3.2.0", - "web-namespaces": "^1.0.0" + "has-tostringtag": "^1.0.0" } }, - "hast-util-has-property": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-1.0.4.tgz", - "integrity": "sha512-ghHup2voGfgFoHMGnaLHOjbYFACKrRh9KFttdCzMCbFoBMJXiNi2+XTrPP8+q6cDJM/RSqlCfVWrjp1H201rZg==" + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" + }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==" }, - "hast-util-is-element": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-1.1.0.tgz", - "integrity": "sha512-oUmNua0bFbdrD/ELDSSEadRVtWZOf3iF6Lbv81naqsIV99RnSCieTbWuWCY8BAeEfKJTKl0gRdokv+dELutHGQ==" + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==" }, - "hast-util-parse-selector": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", - "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==" + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==" }, - "hast-util-raw": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-6.0.1.tgz", - "integrity": "sha512-ZMuiYA+UF7BXBtsTBNcLBF5HzXzkyE6MLzJnL605LKE8GJylNjGc4jjxazAHUtcwT5/CEt6afRKViYB4X66dig==", - "requires": { - "@types/hast": "^2.0.0", - "hast-util-from-parse5": "^6.0.0", - "hast-util-to-parse5": "^6.0.0", - "html-void-elements": "^1.0.0", - "parse5": "^6.0.0", - "unist-util-position": "^3.0.0", - "vfile": "^4.0.0", - "web-namespaces": "^1.0.0", - "xtend": "^4.0.0", - "zwitch": "^1.0.0" - } + "is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" }, - "hast-util-select": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/hast-util-select/-/hast-util-select-4.0.2.tgz", - "integrity": "sha512-8EEG2//bN5rrzboPWD2HdS3ugLijNioS1pqOTIolXNf67xxShYw4SQEmVXd3imiBG+U2bC2nVTySr/iRAA7Cjg==", + "is-reference": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", + "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", "requires": { - "bcp-47-match": "^1.0.0", - "comma-separated-tokens": "^1.0.0", - "css-selector-parser": "^1.0.0", - "direction": "^1.0.0", - "hast-util-has-property": "^1.0.0", - "hast-util-is-element": "^1.0.0", - "hast-util-to-string": "^1.0.0", - "hast-util-whitespace": "^1.0.0", - "not": "^0.1.0", - "nth-check": "^2.0.0", - "property-information": "^5.0.0", - "space-separated-tokens": "^1.0.0", - "unist-util-visit": "^2.0.0", - "zwitch": "^1.0.0" - }, - "dependencies": { - "nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "requires": { - "boolbase": "^1.0.0" - } - } + "@types/estree": "*" } }, - "hast-util-to-parse5": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz", - "integrity": "sha512-Lu5m6Lgm/fWuz8eWnrKezHtVY83JeRGaNQ2kn9aJgqaxvVkFCZQBEhgodZUDUvoodgyROHDb3r5IxAEdl6suJQ==", + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "requires": { - "hast-to-hyperscript": "^9.0.0", - "property-information": "^5.0.0", - "web-namespaces": "^1.0.0", - "xtend": "^4.0.0", - "zwitch": "^1.0.0" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" } }, - "hast-util-to-string": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-1.0.4.tgz", - "integrity": "sha512-eK0MxRX47AV2eZ+Lyr18DCpQgodvaS3fAQO2+b9Two9F5HEoRPhiUMNzoXArMJfZi2yieFzUBMRl3HNJ3Jus3w==" + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==" }, - "hast-util-to-text": { + "is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==" + }, + "is-shared-array-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", + "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==" + }, + "is-stream": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-2.0.1.tgz", - "integrity": "sha512-8nsgCARfs6VkwH2jJU9b8LNTuR4700na+0h3PqCaEk4MAnMDeu5P0tP8mjk9LLNGxIeQRLbiDbZVw6rku+pYsQ==", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "requires": { - "hast-util-is-element": "^1.0.0", - "repeat-string": "^1.0.0", - "unist-util-find-after": "^3.0.0" + "has-tostringtag": "^1.0.0" } }, - "hast-util-whitespace": { + "is-symbol": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-1.0.4.tgz", - "integrity": "sha512-I5GTdSfhYfAPNztx2xJRQpG8cuDSNt599/7YUn7Gx/WxNMsG+a835k97TDkFgk123cwjfwINaZknkKkphx/f2A==" - }, - "hastscript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", - "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "requires": { - "@types/hast": "^2.0.0", - "comma-separated-tokens": "^1.0.0", - "hast-util-parse-selector": "^2.0.0", - "property-information": "^5.0.0", - "space-separated-tokens": "^1.0.0" + "has-symbols": "^1.0.2" } }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" }, - "history": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", - "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "requires": { - "@babel/runtime": "^7.1.2", - "loose-envify": "^1.2.0", - "resolve-pathname": "^3.0.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0", - "value-equal": "^1.0.1" + "call-bind": "^1.0.2" } }, - "hogan.js": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/hogan.js/-/hogan.js-3.0.2.tgz", - "integrity": "sha1-TNnhq9QpQUbnZ55B14mHMrAse/0=", + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "requires": { - "mkdirp": "0.3.0", - "nopt": "1.0.10" + "is-docker": "^2.0.0" } }, - "hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "requires": { - "react-is": "^16.7.0" - } + "is-yarn-global": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.1.tgz", + "integrity": "sha512-/kppl+R+LO5VmhYSEWARUFjodS25D68gvj8W7z0I7OWhUla5xWu8KL6CtB2V0R6yqhnRgbcaREMr4EEM6htLPQ==" }, - "hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" + }, + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "requires": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "requires": { - "safe-buffer": "~5.1.0" + "has-flag": "^4.0.0" } } } }, - "html-entities": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz", - "integrity": "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==" + "jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==" }, - "html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "joi": { + "version": "17.11.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.11.0.tgz", + "integrity": "sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==", "requires": { - "camel-case": "^4.1.2", - "clean-css": "^5.2.2", - "commander": "^8.3.0", - "he": "^1.2.0", - "param-case": "^3.0.4", - "relateurl": "^0.2.7", - "terser": "^5.10.0" - }, - "dependencies": { - "commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==" - } + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.3", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" } }, - "html-tags": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz", - "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==" - }, - "html-void-elements": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz", - "integrity": "sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==" + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, - "html-webpack-plugin": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", - "integrity": "sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw==", + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "requires": { - "@types/html-minifier-terser": "^6.0.0", - "html-minifier-terser": "^6.0.2", - "lodash": "^4.17.21", - "pretty-error": "^4.0.0", - "tapable": "^2.0.0" + "argparse": "^1.0.7", + "esprima": "^4.0.0" } }, - "htmlparser2": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", - "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", - "requires": { - "domelementtype": "^1.3.1", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^3.1.1" - }, - "dependencies": { - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" - } - } + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" }, - "http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=" + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, - "http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.1" + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" } }, - "http-parser-js": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.5.tgz", - "integrity": "sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA==" - }, - "http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "jsx-ast-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz", + "integrity": "sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==", "requires": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" + "array-includes": "^3.1.3", + "object.assign": "^4.1.2" } }, - "http-proxy-middleware": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.3.tgz", - "integrity": "sha512-1bloEwnrHMnCoO/Gcwbz7eSVvW50KPES01PecpagI+YLNLci4AcuKJrujW4Mc3sBLpFxMSlsLNHS5Nl/lvrTPA==", + "keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "requires": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - }, - "dependencies": { - "is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==" - } + "json-buffer": "3.0.1" } }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + }, + "latest-version": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", + "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "package-json": "^8.1.0" } }, - "icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "requires": {} + "launch-editor": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz", + "integrity": "sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ==", + "requires": { + "picocolors": "^1.0.0", + "shell-quote": "^1.7.3" + } }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" }, - "image-size": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.1.tgz", - "integrity": "sha512-VAwkvNSNGClRw9mDHhc5Efax8PLlsOGcUTh0T/LIriC8vPA3U5PdqXWqkz406MoYHMKW8Uf9gWr05T/rYB44kQ==", + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "requires": { - "queue": "6.0.2" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" } }, - "immediate": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", - "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==" + "lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==" }, - "immer": { - "version": "9.0.12", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz", - "integrity": "sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA==" + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "loader-runner": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", + "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==" + }, + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" } }, - "import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=" + "locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "requires": { + "p-locate": "^6.0.0" + } }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" + "lodash.curry": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz", + "integrity": "sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==" }, - "infima": { - "version": "0.2.0-alpha.37", - "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.37.tgz", - "integrity": "sha512-4GX7Baw+/lwS4PPW/UJNY89tWSvYG1DL6baKVdpK6mC593iRgMssxNtORMTFArLPJ/A/lzsGhRmx+z6MaMxj0Q==" + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "lodash.flow": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz", + "integrity": "sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==" + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=" + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" + }, + "longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==" + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "requires": { - "once": "^1.3.0", - "wrappy": "1" + "js-tokens": "^3.0.0 || ^4.0.0" } }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + "lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "requires": { + "tslib": "^2.0.3" + } }, - "inline-style-parser": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", - "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" + "lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==" }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" + "yallist": "^4.0.0" } }, - "interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==" + "lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==" }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + "lunr-languages": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/lunr-languages/-/lunr-languages-1.9.0.tgz", + "integrity": "sha512-Be5vFuc8NAheOIjviCRms3ZqFFBlzns3u9DXpPSZvALetgnydAN0poV71pVLFn0keYy/s4VblMMkqewTLe+KPg==" }, - "ipaddr.js": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", - "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==" + "mark.js": { + "version": "8.11.1", + "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", + "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==" }, - "is-alphabetical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", - "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==" + "markdown-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", + "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==" }, - "is-alphanumerical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", - "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", - "requires": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" + "markdown-table": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", + "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==" + }, + "mdast-util-directive": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.0.0.tgz", + "integrity": "sha512-JUpYOqKI4mM3sZcNxmF/ox04XYFFkNwr0CFlrQIkCwbvH0xzMCqkMqAde9wRd80VAhaUrwFwKm2nxretdT1h7Q==", + "requires": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + } + } } }, - "is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "mdast-util-find-and-replace": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.1.tgz", + "integrity": "sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==", "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==" + }, + "unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + } + } } }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "requires": { - "has-bigints": "^1.0.1" + "mdast-util-from-markdown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.0.tgz", + "integrity": "sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA==", + "requires": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + }, + "unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "requires": { + "@types/unist": "^3.0.0" + } + } } }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "mdast-util-frontmatter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", + "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==", "requires": { - "binary-extensions": "^2.0.0" + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "escape-string-regexp": "^5.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==" + } } }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "mdast-util-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz", + "integrity": "sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==", "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" } }, - "is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" - }, - "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" - }, - "is-ci": { + "mdast-util-gfm-autolink-literal": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.0.tgz", + "integrity": "sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg==", "requires": { - "ci-info": "^2.0.0" + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "dependencies": { + "micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "requires": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + } } }, - "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "mdast-util-gfm-footnote": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz", + "integrity": "sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==", "requires": { - "has": "^1.0.3" + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" } }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", "requires": { - "has-tostringtag": "^1.0.0" + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" } }, - "is-decimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", - "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==" - }, - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", "requires": { - "is-extglob": "^2.1.1" + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" } }, - "is-hexadecimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", - "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==" - }, - "is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", "requires": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" } }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==" - }, - "is-npm": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", - "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==" - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" - }, - "is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "mdast-util-mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", "requires": { - "has-tostringtag": "^1.0.0" + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" } }, - "is-obj": { + "mdast-util-mdx-expression": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" - }, - "is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==" - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==" - }, - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==" + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz", + "integrity": "sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw==", + "requires": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "dependencies": { + "@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "requires": { + "@types/unist": "*" + } + } + } }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "mdast-util-mdx-jsx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.0.0.tgz", + "integrity": "sha512-XZuPPzQNBPAlaqsTTgRrcJnyFbSOBovSadFgbFu8SnuNgm+6Bdx1K+IWoitsmj6Lq6MNtI+ytOqwN70n//NaBA==", + "requires": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-remove-position": "^5.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "dependencies": { + "@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "requires": { + "@types/unist": "*" + } + }, + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + } + } + } + }, + "mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", "requires": { - "isobject": "^3.0.1" + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "dependencies": { + "@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "requires": { + "@types/unist": "*" + } + } } }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "mdast-util-phrasing": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.0.0.tgz", + "integrity": "sha512-xadSsJayQIucJ9n053dfQwVu1kuXg7jCTdYsMK8rqzKZh52nLfSH/k0sAxE0u+pj/zKZX+o5wB+ML5mRayOxFA==", "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "requires": { + "@types/unist": "^3.0.0" + } + } } }, - "is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=" + "mdast-util-to-hast": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.0.2.tgz", + "integrity": "sha512-U5I+500EOOw9e3ZrclN3Is3fRpw8c19SMyNZlZ2IS+7vLsNzb2Om11VpIVOR+/0137GhZsFEF6YiKD5+0Hr2Og==", + "requires": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0" + }, + "dependencies": { + "@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "requires": { + "@types/unist": "*" + } + }, + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + } + }, + "unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + } + } + } }, - "is-root": { + "mdast-util-to-markdown": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", - "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==" - }, - "is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==" - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "requires": { - "has-tostringtag": "^1.0.0" + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz", + "integrity": "sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==", + "requires": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + } + }, + "unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + } + }, + "zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==" + } } }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", "requires": { - "has-symbols": "^1.0.2" + "@types/mdast": "^4.0.0" } }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + "mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + }, + "memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", "requires": { - "call-bind": "^1.0.2" + "fs-monkey": "^1.0.4" } }, - "is-whitespace-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", - "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==" + "merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==" }, - "is-word-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz", - "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==" + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "requires": { - "is-docker": "^2.0.0" - } + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" }, - "is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==" + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + "micromark": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", + "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", + "requires": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "dependencies": { + "micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "requires": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "requires": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + } + } }, - "isexe": { + "micromark-core-commonmark": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.0.tgz", + "integrity": "sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA==", + "requires": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "dependencies": { + "micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "requires": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "requires": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + } + } }, - "jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "micromark-extension-directive": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-3.0.0.tgz", + "integrity": "sha512-61OI07qpQrERc+0wEysLHMvoiO3s2R56x5u7glHq2Yqq6EHbH4dW25G9GfDdGCDYqA21KE6DWgNSzxSwHc2hSg==", "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "parse-entities": "^4.0.0" }, "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "requires": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", "requires": { - "has-flag": "^4.0.0" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } + }, + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" } } }, - "joi": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.0.tgz", - "integrity": "sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw==", + "micromark-extension-frontmatter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz", + "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==", "requires": { - "@hapi/hoek": "^9.0.0", - "@hapi/topo": "^5.0.0", - "@sideway/address": "^4.1.3", - "@sideway/formula": "^3.0.0", - "@sideway/pinpoint": "^2.0.0" + "fault": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "dependencies": { + "micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "requires": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + } } }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" - }, - "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "micromark-extension-gfm-autolink-literal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.0.0.tgz", + "integrity": "sha512-rTHfnpt/Q7dEAK1Y5ii0W8bhfJlVJFnJMHIPisfPK3gpVNuOP0VnRl96+YJ3RYWV/P4gFeQoGKNlT3RhuvpqAg==", + "requires": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "dependencies": { + "micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "requires": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + } + } }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + "micromark-extension-gfm-footnote": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.0.0.tgz", + "integrity": "sha512-6Rzu0CYRKDv3BfLAUnZsSlzx3ak6HAoI85KTiijuKIz5UxZxbUI+pD6oHgw+6UtQuiRwnGRhzMmPRv4smcz0fg==", + "requires": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "dependencies": { + "micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "requires": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "requires": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + } + } }, - "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "micromark-extension-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-c3BR1ClMp5fxxmwP6AoOY2fXO9U8uFMKs4ADD66ahLTNcwzSCyRVU4k7LPV5Nxo/VJiR4TdzxRQY2v3qIUceCw==", "requires": { - "minimist": "^1.2.5" + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "dependencies": { + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + } } }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "micromark-extension-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.0.0.tgz", + "integrity": "sha512-PoHlhypg1ItIucOaHmKE8fbin3vTLpDOUg8KAr8gRCF1MOZI9Nquq2i/44wFvviM4WuxJzc3demT8Y3dkfvYrw==", "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "dependencies": { + "micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "requires": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "requires": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + } } }, - "jsx-ast-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz", - "integrity": "sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==", + "micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", "requires": { - "array-includes": "^3.1.3", - "object.assign": "^4.1.2" + "micromark-util-types": "^2.0.0" } }, - "keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "micromark-extension-gfm-task-list-item": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.0.1.tgz", + "integrity": "sha512-cY5PzGcnULaN5O7T+cOzfMoHjBW7j+T9D2sucA5d/KbsBTPcYdebm9zUd9zzdgJGCwahV+/W78Z3nbulBYVbTw==", "requires": { - "json-buffer": "3.0.0" + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "dependencies": { + "micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "requires": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "requires": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + } } }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" - }, - "klona": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", - "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==" - }, - "latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "micromark-extension-mdx-expression": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.0.tgz", + "integrity": "sha512-sI0nwhUDz97xyzqJAbHQhp5TfaxEvZZZ2JDqUo+7NvyIYG6BZ5CPPqj2ogUoPJlmXHBnyZUzISg9+oUmU6tUjQ==", "requires": { - "package-json": "^6.3.0" + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "dependencies": { + "micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "requires": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "requires": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + } } }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" + "micromark-extension-mdx-jsx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.0.tgz", + "integrity": "sha512-uvhhss8OGuzR4/N17L1JwvmJIpPhAd8oByMawEKx6NVdBCbesjH4t+vjEp3ZXft9DwvlKSD07fCeI44/N0Vf2w==", + "requires": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "requires": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "requires": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + }, + "unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + } + } + } }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "micromark-extension-mdx-md": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "micromark-util-types": "^2.0.0" } }, - "lilconfig": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", - "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==" - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + "micromark-extension-mdxjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", + "requires": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "dependencies": { + "acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==" + } + } }, - "loader-runner": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", - "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==" + "micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", + "requires": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "requires": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + }, + "unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + } + } + } }, - "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "micromark-factory-destination": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", + "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "dependencies": { - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", "requires": { - "minimist": "^1.2.0" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } + }, + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" } } }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "micromark-factory-label": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", + "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", "requires": { - "p-locate": "^4.1.0" + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "dependencies": { + "micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "requires": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + } } }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash.assignin": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", - "integrity": "sha1-uo31+4QesKPoBEIysOJjqNxqKKI=" - }, - "lodash.bind": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz", - "integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU=" - }, - "lodash.curry": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz", - "integrity": "sha1-JI42By7ekGUB11lmIAqG2riyMXA=" - }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" - }, - "lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" - }, - "lodash.filter": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz", - "integrity": "sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4=" - }, - "lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" - }, - "lodash.flow": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz", - "integrity": "sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o=" - }, - "lodash.foreach": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", - "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=" - }, - "lodash.map": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", - "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=" - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" - }, - "lodash.pick": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", - "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=" - }, - "lodash.reduce": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz", - "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs=" - }, - "lodash.reject": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz", - "integrity": "sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU=" - }, - "lodash.some": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", - "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=" - }, - "lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=" + "micromark-factory-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.1.tgz", + "integrity": "sha512-F0ccWIUHRLRrYp5TC9ZYXmZo+p2AM13ggbsW4T0b5CRKP8KHVRB8t4pwtBgTxtjRmwrK0Irwm7vs2JOZabHZfg==", + "requires": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "requires": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + }, + "unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + } + } + } }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" + "micromark-factory-space": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz", + "integrity": "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==", + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" + }, + "dependencies": { + "micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==" + } + } }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "micromark-factory-title": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", + "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "dependencies": { + "micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "requires": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "requires": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + } } }, - "lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "micromark-factory-whitespace": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", + "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", "requires": { - "tslib": "^2.0.3" + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "dependencies": { + "micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "requires": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "requires": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + } } }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "micromark-util-character": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz", + "integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==", "requires": { - "yallist": "^4.0.0" + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + }, + "dependencies": { + "micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==" + } } }, - "lunr": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==" - }, - "lunr-languages": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/lunr-languages/-/lunr-languages-1.9.0.tgz", - "integrity": "sha512-Be5vFuc8NAheOIjviCRms3ZqFFBlzns3u9DXpPSZvALetgnydAN0poV71pVLFn0keYy/s4VblMMkqewTLe+KPg==" - }, - "magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "micromark-util-chunked": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", + "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", "requires": { - "sourcemap-codec": "^1.4.4" + "micromark-util-symbol": "^2.0.0" + }, + "dependencies": { + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + } } }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "micromark-util-classify-character": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", + "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", "requires": { - "semver": "^6.0.0" + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "requires": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" } } }, - "markdown-escapes": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz", - "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==" - }, - "mdast-squeeze-paragraphs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-squeeze-paragraphs/-/mdast-squeeze-paragraphs-4.0.0.tgz", - "integrity": "sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ==", + "micromark-util-combine-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", + "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", "requires": { - "unist-util-remove": "^2.0.0" + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "mdast-util-definitions": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz", - "integrity": "sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==", + "micromark-util-decode-numeric-character-reference": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", + "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", "requires": { - "unist-util-visit": "^2.0.0" + "micromark-util-symbol": "^2.0.0" + }, + "dependencies": { + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + } } }, - "mdast-util-to-hast": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-10.0.1.tgz", - "integrity": "sha512-BW3LM9SEMnjf4HXXVApZMt8gLQWVNXc3jryK0nJu/rOXPOnlkUjmdkDlmxMirpbU9ILncGFIwLH/ubnWBbcdgA==", + "micromark-util-decode-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", + "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", "requires": { - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "mdast-util-definitions": "^4.0.0", - "mdurl": "^1.0.0", - "unist-builder": "^2.0.0", - "unist-util-generated": "^1.0.0", - "unist-util-position": "^3.0.0", - "unist-util-visit": "^2.0.0" + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + }, + "dependencies": { + "micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "requires": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + } } }, - "mdast-util-to-string": { + "micromark-util-encode": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", - "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==" + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", + "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==" }, - "mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + "micromark-util-events-to-acorn": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.2.tgz", + "integrity": "sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==", + "requires": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + }, + "unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + } + } + } }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" + "micromark-util-html-tag-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", + "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==" }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + "micromark-util-normalize-identifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", + "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", + "requires": { + "micromark-util-symbol": "^2.0.0" + }, + "dependencies": { + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + } + } }, - "memfs": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.1.tgz", - "integrity": "sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw==", + "micromark-util-resolve-all": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", + "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", "requires": { - "fs-monkey": "1.0.3" + "micromark-util-types": "^2.0.0" } }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + "micromark-util-sanitize-uri": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", + "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", + "requires": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + }, + "dependencies": { + "micromark-util-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz", + "integrity": "sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==", + "requires": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + } + } }, - "merge-stream": { + "micromark-util-subtokenize": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.0.tgz", + "integrity": "sha512-vc93L1t+gpR3p8jxeVdaYlbV2jTYteDje19rNSS/H5dlhxUYll5Fy6vJ2cDwP8RnsXi818yGty1ayP55y3W6fg==", + "requires": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "dependencies": { + "micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==" + } + } }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + "micromark-util-symbol": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz", + "integrity": "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==" }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + "micromark-util-types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", + "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==" }, "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.3", + "picomatch": "^2.3.1" } }, "mime": { @@ -22861,40 +28830,16 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" }, "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==" }, "mini-css-extract-plugin": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.6.2.tgz", - "integrity": "sha512-WhDvO3SjGm40oV5y26GjMJYjd2UMqrLAGKy5YS2/3QKJy2F7jgynuHTir/tgUUOiNQu5saXHdc8reo7YuhhT4Q==", + "version": "2.7.6", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz", + "integrity": "sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw==", "requires": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0", - "webpack-sources": "^1.1.0" - }, - "dependencies": { - "loader-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - }, - "schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", - "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - } + "schema-utils": "^4.0.0" } }, "minimalistic-assert": { @@ -22911,9 +28856,9 @@ } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" }, "mkdirp": { "version": "0.3.0", @@ -22921,9 +28866,9 @@ "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=" }, "mrmime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.0.tgz", - "integrity": "sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", + "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==" }, "ms": { "version": "2.1.2", @@ -22931,23 +28876,18 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "multicast-dns": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", - "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "requires": { - "dns-packet": "^1.3.1", + "dns-packet": "^5.2.2", "thunky": "^1.0.2" } }, - "multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" - }, "nanoid": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", - "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==" + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==" }, "natural-compare": { "version": "1.4.0", @@ -22974,30 +28914,40 @@ } }, "node-emoji": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", - "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.1.3.tgz", + "integrity": "sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA==", "requires": { - "lodash": "^4.17.21" + "@sindresorhus/is": "^4.6.0", + "char-regex": "^1.0.2", + "emojilib": "^2.4.0", + "skin-tone": "^2.0.0" + }, + "dependencies": { + "@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==" + } } }, "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "requires": { "whatwg-url": "^5.0.0" } }, "node-forge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.2.1.tgz", - "integrity": "sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w==" + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==" }, "node-releases": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", - "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==" + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" }, "nopt": { "version": "1.0.10", @@ -23015,7 +28965,7 @@ "normalize-range": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=" + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==" }, "normalize-url": { "version": "6.1.0", @@ -23038,14 +28988,14 @@ "nprogress": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", - "integrity": "sha1-y480xTIT2JVyP8urkH6UIq28r7E=" + "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==" }, "nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "requires": { - "boolbase": "~1.0.0" + "boolbase": "^1.0.0" } }, "object-assign": { @@ -23054,18 +29004,9 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==" - }, - "object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==" }, "object-keys": { "version": "1.1.1", @@ -23128,9 +29069,9 @@ "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" }, "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "requires": { "ee-first": "1.1.1" } @@ -23157,9 +29098,9 @@ } }, "open": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", - "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", "requires": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", @@ -23185,9 +29126,9 @@ } }, "p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==" }, "p-limit": { "version": "2.3.0", @@ -23198,11 +29139,26 @@ } }, "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", "requires": { - "p-limit": "^2.2.0" + "p-limit": "^4.0.0" + }, + "dependencies": { + "p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "requires": { + "yocto-queue": "^1.0.0" + } + }, + "yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==" + } } }, "p-map": { @@ -23214,11 +29170,11 @@ } }, "p-retry": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.1.tgz", - "integrity": "sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA==", + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", "requires": { - "@types/retry": "^0.12.0", + "@types/retry": "0.12.0", "retry": "^0.13.1" } }, @@ -23228,21 +29184,14 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" }, "package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", + "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", "requires": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" } }, "param-case": { @@ -23263,16 +29212,18 @@ } }, "parse-entities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz", + "integrity": "sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==", "requires": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" + "@types/unist": "^2.0.0", + "character-entities": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" } }, "parse-json": { @@ -23297,11 +29248,30 @@ "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" }, "parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", "requires": { - "parse5": "^6.0.1" + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + }, + "dependencies": { + "domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "requires": { + "domelementtype": "^2.3.0" + } + }, + "parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "requires": { + "entities": "^4.4.0" + } + } } }, "parseurl": { @@ -23353,6 +29323,16 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" }, + "periscopic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", + "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", + "requires": { + "@types/estree": "^1.0.0", + "estree-walker": "^3.0.0", + "is-reference": "^3.0.0" + } + }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -23364,11 +29344,11 @@ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" }, "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", "requires": { - "find-up": "^4.0.0" + "find-up": "^6.3.0" } }, "pkg-up": { @@ -23407,44 +29387,16 @@ "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - } - } - }, - "portfinder": { - "version": "1.0.28", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", - "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", - "requires": { - "async": "^2.6.2", - "debug": "^3.1.1", - "mkdirp": "^0.5.5" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "requires": { - "ms": "^2.1.1" - } - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" - } + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==" } } }, "postcss": { - "version": "8.4.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz", - "integrity": "sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "requires": { - "nanoid": "^3.2.0", + "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } @@ -23459,127 +29411,154 @@ } }, "postcss-colormin": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.2.5.tgz", - "integrity": "sha512-+X30aDaGYq81mFqwyPpnYInsZQnNpdxMX0ajlY7AExCexEFkPVV+KrO7kXwayqEWL2xwEbNQ4nUO0ZsRWGnevg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", + "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", "requires": { - "browserslist": "^4.16.6", + "browserslist": "^4.21.4", "caniuse-api": "^3.0.0", "colord": "^2.9.1", "postcss-value-parser": "^4.2.0" } }, "postcss-convert-values": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.0.4.tgz", - "integrity": "sha512-bugzSAyjIexdObovsPZu/sBCTHccImJxLyFgeV0MmNBm/Lw5h5XnjfML6gzEmJ3A6nyfCW7hb1JXzcsA4Zfbdw==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", + "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", "requires": { + "browserslist": "^4.21.4", "postcss-value-parser": "^4.2.0" } }, "postcss-discard-comments": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.0.3.tgz", - "integrity": "sha512-6W5BemziRoqIdAKT+1QjM4bNcJAQ7z7zk073730NHg4cUXh3/rQHHj7pmYxUB9aGhuRhBiUf0pXvIHkRwhQP0Q==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", + "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", "requires": {} }, "postcss-discard-duplicates": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.0.3.tgz", - "integrity": "sha512-vPtm1Mf+kp7iAENTG7jI1MN1lk+fBqL5y+qxyi4v3H+lzsXEdfS3dwUZD45KVhgzDEgduur8ycB4hMegyMTeRw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", + "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", "requires": {} }, "postcss-discard-empty": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.0.3.tgz", - "integrity": "sha512-xGJugpaXKakwKI7sSdZjUuN4V3zSzb2Y0LOlmTajFbNinEjTfVs9PFW2lmKBaC/E64WwYppfqLD03P8l9BuueA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", + "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", "requires": {} }, "postcss-discard-overridden": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.0.4.tgz", - "integrity": "sha512-3j9QH0Qh1KkdxwiZOW82cId7zdwXVQv/gRXYDnwx5pBtR1sTkU4cXRK9lp5dSdiM0r0OICO/L8J6sV1/7m0kHg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", + "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", "requires": {} }, "postcss-discard-unused": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-5.0.3.tgz", - "integrity": "sha512-WO6FJxL5fGnuE77ZbTcZ/nRZJ4+TOqNaqLBLWgkR4e+WdmHn77OHPyQmsRv7eOB2rLKL6tsq2bs1GwoKXD/++Q==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-5.1.0.tgz", + "integrity": "sha512-KwLWymI9hbwXmJa0dkrzpRbSJEh0vVUd7r8t0yOGPcfKzyJJxFM8kLyC5Ev9avji6nY95pOp1W6HqIrfT+0VGw==", "requires": { "postcss-selector-parser": "^6.0.5" } }, "postcss-loader": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", - "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.3.tgz", + "integrity": "sha512-YgO/yhtevGO/vJePCQmTxiaEwER94LABZN0ZMT4A0vsak9TpO+RvKRs7EmJ8peIlB9xfXCsS7M8LjqncsUZ5HA==", "requires": { - "cosmiconfig": "^7.0.0", - "klona": "^2.0.5", - "semver": "^7.3.5" + "cosmiconfig": "^8.2.0", + "jiti": "^1.18.2", + "semver": "^7.3.8" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "cosmiconfig": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz", + "integrity": "sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==", + "requires": { + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" + } + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + } } }, "postcss-merge-idents": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-5.0.3.tgz", - "integrity": "sha512-Z4LCzh2WzMn69KaS2FaJcrIeDQ170V13QHq+0hnBEFKJJkD+y5qndZ/bl3AhpddrSrXWIVR+xAwjmHQIJI2Eog==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-5.1.1.tgz", + "integrity": "sha512-pCijL1TREiCoog5nQp7wUe+TUonA2tC2sQ54UGeMmryK3UFGIYKqDyjnqd6RcuI4znFn9hWSLNN8xKE/vWcUQw==", "requires": { - "cssnano-utils": "^3.0.2", + "cssnano-utils": "^3.1.0", "postcss-value-parser": "^4.2.0" } }, "postcss-merge-longhand": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.0.6.tgz", - "integrity": "sha512-rkmoPwQO6ymJSmWsX6l2hHeEBQa7C4kJb9jyi5fZB1sE8nSCv7sqchoYPixRwX/yvLoZP2y6FA5kcjiByeJqDg==", + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", + "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", "requires": { "postcss-value-parser": "^4.2.0", - "stylehacks": "^5.0.3" + "stylehacks": "^5.1.1" } }, "postcss-merge-rules": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.0.6.tgz", - "integrity": "sha512-nzJWJ9yXWp8AOEpn/HFAW72WKVGD2bsLiAmgw4hDchSij27bt6TF+sIK0cJUBAYT3SGcjtGGsOR89bwkkMuMgQ==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", + "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", "requires": { - "browserslist": "^4.16.6", + "browserslist": "^4.21.4", "caniuse-api": "^3.0.0", - "cssnano-utils": "^3.0.2", + "cssnano-utils": "^3.1.0", "postcss-selector-parser": "^6.0.5" } }, "postcss-minify-font-values": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.0.4.tgz", - "integrity": "sha512-RN6q3tyuEesvyCYYFCRGJ41J1XFvgV+dvYGHr0CeHv8F00yILlN8Slf4t8XW4IghlfZYCeyRrANO6HpJ948ieA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", + "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", "requires": { "postcss-value-parser": "^4.2.0" } }, "postcss-minify-gradients": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.0.6.tgz", - "integrity": "sha512-E/dT6oVxB9nLGUTiY/rG5dX9taugv9cbLNTFad3dKxOO+BQg25Q/xo2z2ddG+ZB1CbkZYaVwx5blY8VC7R/43A==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", + "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", "requires": { "colord": "^2.9.1", - "cssnano-utils": "^3.0.2", + "cssnano-utils": "^3.1.0", "postcss-value-parser": "^4.2.0" } }, "postcss-minify-params": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.0.5.tgz", - "integrity": "sha512-YBNuq3Rz5LfLFNHb9wrvm6t859b8qIqfXsWeK7wROm3jSKNpO1Y5e8cOyBv6Acji15TgSrAwb3JkVNCqNyLvBg==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", + "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", "requires": { - "browserslist": "^4.16.6", - "cssnano-utils": "^3.0.2", + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", "postcss-value-parser": "^4.2.0" } }, "postcss-minify-selectors": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.1.3.tgz", - "integrity": "sha512-9RJfTiQEKA/kZhMaEXND893nBqmYQ8qYa/G+uPdVnXF6D/FzpfI6kwBtWEcHx5FqDbA79O9n6fQJfrIj6M8jvQ==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", + "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", "requires": { "postcss-selector-parser": "^6.0.5" } @@ -23591,9 +29570,9 @@ "requires": {} }, "postcss-modules-local-by-default": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", - "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", + "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", "requires": { "icss-utils": "^5.0.0", "postcss-selector-parser": "^6.0.2", @@ -23617,141 +29596,141 @@ } }, "postcss-normalize-charset": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.0.3.tgz", - "integrity": "sha512-iKEplDBco9EfH7sx4ut7R2r/dwTnUqyfACf62Unc9UiyFuI7uUqZZtY+u+qp7g8Qszl/U28HIfcsI3pEABWFfA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", + "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", "requires": {} }, "postcss-normalize-display-values": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.0.3.tgz", - "integrity": "sha512-FIV5FY/qs4Ja32jiDb5mVj5iWBlS3N8tFcw2yg98+8MkRgyhtnBgSC0lxU+16AMHbjX5fbSJgw5AXLMolonuRQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", + "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", "requires": { "postcss-value-parser": "^4.2.0" } }, "postcss-normalize-positions": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.0.4.tgz", - "integrity": "sha512-qynirjBX0Lc73ROomZE3lzzmXXTu48/QiEzKgMeqh28+MfuHLsuqC9po4kj84igZqqFGovz8F8hf44hA3dPYmQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", + "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", "requires": { "postcss-value-parser": "^4.2.0" } }, "postcss-normalize-repeat-style": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.0.4.tgz", - "integrity": "sha512-Innt+wctD7YpfeDR7r5Ik6krdyppyAg2HBRpX88fo5AYzC1Ut/l3xaxACG0KsbX49cO2n5EB13clPwuYVt8cMA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", + "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", "requires": { "postcss-value-parser": "^4.2.0" } }, "postcss-normalize-string": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.0.4.tgz", - "integrity": "sha512-Dfk42l0+A1CDnVpgE606ENvdmksttLynEqTQf5FL3XGQOyqxjbo25+pglCUvziicTxjtI2NLUR6KkxyUWEVubQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", + "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", "requires": { "postcss-value-parser": "^4.2.0" } }, "postcss-normalize-timing-functions": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.0.3.tgz", - "integrity": "sha512-QRfjvFh11moN4PYnJ7hia4uJXeFotyK3t2jjg8lM9mswleGsNw2Lm3I5wO+l4k1FzK96EFwEVn8X8Ojrp2gP4g==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", + "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", "requires": { "postcss-value-parser": "^4.2.0" } }, "postcss-normalize-unicode": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.0.4.tgz", - "integrity": "sha512-W79Regn+a+eXTzB+oV/8XJ33s3pDyFTND2yDuUCo0Xa3QSy1HtNIfRVPXNubHxjhlqmMFADr3FSCHT84ITW3ig==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", + "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", "requires": { - "browserslist": "^4.16.6", + "browserslist": "^4.21.4", "postcss-value-parser": "^4.2.0" } }, "postcss-normalize-url": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.0.5.tgz", - "integrity": "sha512-Ws3tX+PcekYlXh+ycAt0wyzqGthkvVtZ9SZLutMVvHARxcpu4o7vvXcNoiNKyjKuWecnjS6HDI3fjBuDr5MQxQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", + "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", "requires": { "normalize-url": "^6.0.1", "postcss-value-parser": "^4.2.0" } }, "postcss-normalize-whitespace": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.4.tgz", - "integrity": "sha512-wsnuHolYZjMwWZJoTC9jeI2AcjA67v4UuidDrPN9RnX8KIZfE+r2Nd6XZRwHVwUiHmRvKQtxiqo64K+h8/imaw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", + "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", "requires": { "postcss-value-parser": "^4.2.0" } }, "postcss-ordered-values": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.0.5.tgz", - "integrity": "sha512-mfY7lXpq+8bDEHfP+muqibDPhZ5eP9zgBEF9XRvoQgXcQe2Db3G1wcvjbnfjXG6wYsl+0UIjikqq4ym1V2jGMQ==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", + "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", "requires": { - "cssnano-utils": "^3.0.2", + "cssnano-utils": "^3.1.0", "postcss-value-parser": "^4.2.0" } }, "postcss-reduce-idents": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-5.0.3.tgz", - "integrity": "sha512-9bj9/Xhwiti0Z35kkguJX4G6yUYVw8S1kRLU4jFSCTEuHu4yJggf4rNUoVnT45lm/vU97Wd593CxspMDbHxy4w==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-5.2.0.tgz", + "integrity": "sha512-BTrLjICoSB6gxbc58D5mdBK8OhXRDqud/zodYfdSi52qvDHdMwk+9kB9xsM8yJThH/sZU5A6QVSmMmaN001gIg==", "requires": { "postcss-value-parser": "^4.2.0" } }, "postcss-reduce-initial": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.0.3.tgz", - "integrity": "sha512-c88TkSnQ/Dnwgb4OZbKPOBbCaauwEjbECP5uAuFPOzQ+XdjNjRH7SG0dteXrpp1LlIFEKK76iUGgmw2V0xeieA==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", + "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", "requires": { - "browserslist": "^4.16.6", + "browserslist": "^4.21.4", "caniuse-api": "^3.0.0" } }, "postcss-reduce-transforms": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.0.4.tgz", - "integrity": "sha512-VIJB9SFSaL8B/B7AXb7KHL6/GNNbbCHslgdzS9UDfBZYIA2nx8NLY7iD/BXFSO/1sRUILzBTfHCoW5inP37C5g==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", + "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", "requires": { "postcss-value-parser": "^4.2.0" } }, "postcss-selector-parser": { - "version": "6.0.9", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", - "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", "requires": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "postcss-sort-media-queries": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-4.2.1.tgz", - "integrity": "sha512-9VYekQalFZ3sdgcTjXMa0dDjsfBVHXlraYJEMiOJ/2iMmI2JGCMavP16z3kWOaRu8NSaJCTgVpB/IVpH5yT9YQ==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-4.4.1.tgz", + "integrity": "sha512-QDESFzDDGKgpiIh4GYXsSy6sek2yAwQx1JASl5AxBtU1Lq2JfKBljIPNdil989NcSKRQX1ToiaKphImtBuhXWw==", "requires": { - "sort-css-media-queries": "2.0.4" + "sort-css-media-queries": "2.1.0" } }, "postcss-svgo": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.0.4.tgz", - "integrity": "sha512-yDKHvULbnZtIrRqhZoA+rxreWpee28JSRH/gy9727u0UCgtpv1M/9WEWY3xySlFa0zQJcqf6oCBJPR5NwkmYpg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", + "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", "requires": { "postcss-value-parser": "^4.2.0", "svgo": "^2.7.0" } }, "postcss-unique-selectors": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.0.4.tgz", - "integrity": "sha512-5ampwoSDJCxDPoANBIlMgoBcYUHnhaiuLYJR5pj1DLnYQvMRVyFuTA5C3Bvt+aHtiqWpJkD/lXT50Vo1D0ZsAQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", + "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", "requires": { "postcss-selector-parser": "^6.0.5" } @@ -23762,9 +29741,9 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, "postcss-zindex": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-5.0.2.tgz", - "integrity": "sha512-KPQFjQu73H35HLHmE8Wv31ygfQoucxD52oRm4FPFv1emYhFMzUQdF8adaXCevFLIHPRp2rRYfbaDiEqZ4YjVtw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-5.1.0.tgz", + "integrity": "sha512-fgFMf0OtVSBR1va1JNHYgMxYk73yhn/qb4uQDq1DLGYolz8gHCyr/sesEuGUaYs58E3ZJRcpoGuPVoB7Meiq9A==", "requires": {} }, "prelude-ls": { @@ -23772,11 +29751,6 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" - }, "prettier": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", @@ -23796,10 +29770,26 @@ "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==" }, + "prism-react-renderer": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-2.3.0.tgz", + "integrity": "sha512-UYRg2TkVIaI6tRVHC5OJ4/BxqPUxJkJvq/odLT/ykpt1zGYXooNperUxQcCvi87LyRnR4nCh81ceOA+e7nrydg==", + "requires": { + "@types/prismjs": "^1.26.0", + "clsx": "^2.0.0" + }, + "dependencies": { + "clsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==" + } + } + }, "prismjs": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz", - "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==" + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==" }, "process-nextick-args": { "version": "2.0.1", @@ -23846,6 +29836,11 @@ "xtend": "^4.0.0" } }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==" + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -23862,14 +29857,10 @@ } } }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "punycode": { "version": "1.4.1", @@ -23877,27 +29868,25 @@ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" }, "pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz", + "integrity": "sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==", "requires": { - "escape-goat": "^2.0.0" + "escape-goat": "^4.0.0" } }, "pure-color": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/pure-color/-/pure-color-1.3.0.tgz", - "integrity": "sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4=" + "integrity": "sha512-QFADYnsVoBMw1srW7OVKEYjG+MbIa49s54w1MA1EDY6r2r/sTcKKYqRX1f4GYvnXP7eN/Pe9HFcX+hwzmrXRHA==" }, "qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==" - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "requires": { + "side-channel": "^1.0.6" + } }, "queue": { "version": "6.0.2", @@ -23912,6 +29901,11 @@ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==" + }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -23926,12 +29920,12 @@ "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" }, "raw-body": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", - "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "requires": { "bytes": "3.1.2", - "http-errors": "1.8.1", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, @@ -23957,24 +29951,22 @@ "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" } } }, "react": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", - "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" + "loose-envify": "^1.1.0" } }, "react-base16-styling": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.6.0.tgz", - "integrity": "sha1-7yFW1mz0E5aVyKFniGy2nqZgeSw=", + "integrity": "sha512-yvh/7CArceR/jNATXOKDlvTnPKPmGZz7zsenQ3jUwLzHkNUR0CvY3yGYJbWJ/nnxsL8Sgmt5cO3/SILVuPO6TQ==", "requires": { "base16": "^1.0.0", "lodash.curry": "^4.0.1", @@ -23983,9 +29975,9 @@ } }, "react-dev-utils": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.0.tgz", - "integrity": "sha512-xBQkitdxozPxt1YZ9O1097EJiVpwHr9FoAuEVURCKV0Av8NBERovJauzP7bo1ThvuhZ4shsQ1AJiu4vQpoT1AQ==", + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", + "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", "requires": { "@babel/code-frame": "^7.16.0", "address": "^1.1.2", @@ -24006,7 +29998,7 @@ "open": "^8.4.0", "pkg-up": "^3.1.0", "prompts": "^2.4.2", - "react-error-overlay": "^6.0.10", + "react-error-overlay": "^6.0.11", "recursive-readdir": "^2.2.2", "shell-quote": "^1.7.3", "strip-ansi": "^6.0.1", @@ -24021,11 +30013,6 @@ "color-convert": "^2.0.1" } }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -24048,18 +30035,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - } - }, "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -24074,64 +30049,15 @@ "path-exists": "^4.0.0" } }, - "fork-ts-checker-webpack-plugin": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.0.tgz", - "integrity": "sha512-cS178Y+xxtIjEUorcHddKS7yCMlrDPV31mt47blKKRfMd70Kxu5xruAFE2o9sDY6wVC5deuob/u/alD04YYHnw==", - "requires": { - "@babel/code-frame": "^7.8.3", - "@types/json-schema": "^7.0.5", - "chalk": "^4.1.0", - "chokidar": "^3.4.2", - "cosmiconfig": "^6.0.0", - "deepmerge": "^4.2.2", - "fs-extra": "^9.0.0", - "glob": "^7.1.6", - "memfs": "^3.1.2", - "minimatch": "^3.0.4", - "schema-utils": "2.7.0", - "semver": "^7.3.2", - "tapable": "^1.0.0" - } - }, - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" - }, "loader-utils": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.0.tgz", - "integrity": "sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ==" + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==" }, "locate-path": { "version": "6.0.0", @@ -24157,16 +30083,6 @@ "p-limit": "^3.0.2" } }, - "schema-utils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", - "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", - "requires": { - "@types/json-schema": "^7.0.4", - "ajv": "^6.12.2", - "ajv-keywords": "^3.4.1" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -24174,34 +30090,39 @@ "requires": { "has-flag": "^4.0.0" } - }, - "tapable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" } } }, "react-dom": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", - "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", "requires": { "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.19.1" + "scheduler": "^0.23.0" } }, "react-error-overlay": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz", - "integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA==" + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", + "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, "react-fast-compare": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", - "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" + }, + "react-helmet-async": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.3.0.tgz", + "integrity": "sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==", + "requires": { + "@babel/runtime": "^7.12.5", + "invariant": "^2.2.4", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.2.0", + "shallowequal": "^1.1.0" + } }, "react-is": { "version": "16.13.1", @@ -24213,10 +30134,74 @@ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, + "react-loadable": { + "version": "npm:@docusaurus/react-loadable@5.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", + "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", + "requires": { + "@types/react": "*", + "prop-types": "^15.6.2" + } + }, + "react-router": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", + "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", + "requires": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "requires": { + "isarray": "0.0.1" + } + } + } + }, + "react-router-dom": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz", + "integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==", + "requires": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.3.4", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + } + }, + "react-textarea-autosize": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.3.4.tgz", + "integrity": "sha512-CdtmP8Dc19xL8/R6sWvtknD/eCXkQr30dtvC4VmGInhRsfF8X/ihXCq6+9l9qbxmKRiq407/7z5fxE7cVWQNgQ==", + "requires": { + "@babel/runtime": "^7.10.2", + "use-composed-ref": "^1.3.0", + "use-latest": "^1.2.1" + } + }, "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -24245,21 +30230,11 @@ } }, "recursive-readdir": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", - "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", "requires": { - "minimatch": "3.0.4" - }, - "dependencies": { - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - } + "minimatch": "^3.0.5" } }, "regenerate": { @@ -24268,22 +30243,22 @@ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" }, "regenerate-unicode-properties": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", - "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", "requires": { "regenerate": "^1.4.2" } }, "regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, "regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", "requires": { "@babel/runtime": "^7.8.4" } @@ -24303,43 +30278,38 @@ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==" }, "regexpu-core": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", - "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", "requires": { + "@babel/regjsgen": "^0.8.0", "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.0.1", - "regjsgen": "^0.6.0", - "regjsparser": "^0.8.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" + "unicode-match-property-value-ecmascript": "^2.1.0" } }, "registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", + "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", "requires": { - "rc": "^1.2.8" + "@pnpm/npm-conf": "^2.1.0" } }, "registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", "requires": { - "rc": "^1.2.8" + "rc": "1.2.8" } }, - "regjsgen": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", - "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==" - }, "regjsparser": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", - "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", "requires": { "jsesc": "~0.5.0" }, @@ -24347,7 +30317,7 @@ "jsesc": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==" } } }, @@ -24360,324 +30330,613 @@ "parse5": "^6.0.0" } }, - "relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=" - }, - "remark-admonitions": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/remark-admonitions/-/remark-admonitions-1.2.1.tgz", - "integrity": "sha512-Ji6p68VDvD+H1oS95Fdx9Ar5WA2wcDA4kwrrhVU7fGctC6+d3uiMICu7w7/2Xld+lnU7/gi+432+rRbup5S8ow==", + "rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "requires": { + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "dependencies": { + "@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "requires": { + "@types/unist": "*" + } + }, + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + } + }, + "vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + } + } + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==" + }, + "remark-directive": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remark-directive/-/remark-directive-3.0.0.tgz", + "integrity": "sha512-l1UyWJ6Eg1VPU7Hm/9tt0zKtReJQNOA4+iDMAxTyZNWnJnFlbS/7zhiel/rogTLQ2vMYwDzSJa4BiVNqGlqIMA==", + "requires": { + "@types/mdast": "^4.0.0", + "mdast-util-directive": "^3.0.0", + "micromark-extension-directive": "^3.0.0", + "unified": "^11.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==" + }, + "is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==" + }, + "trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==" + }, + "unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", + "requires": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + } + }, + "unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + } + }, + "vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + } + } + } + }, + "remark-emoji": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-emoji/-/remark-emoji-4.0.1.tgz", + "integrity": "sha512-fHdvsTR1dHkWKev9eNyhTo4EFwbUvJ8ka9SgeWkMPYFX4WoI7ViVBms3PjlQYgw5TLvNQso3GUB/b/8t3yo+dg==", "requires": { - "rehype-parse": "^6.0.2", - "unified": "^8.4.2", - "unist-util-visit": "^2.0.1" + "@types/mdast": "^4.0.2", + "emoticon": "^4.0.1", + "mdast-util-find-and-replace": "^3.0.1", + "node-emoji": "^2.1.0", + "unified": "^11.0.4" }, "dependencies": { - "hast-util-from-parse5": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-5.0.3.tgz", - "integrity": "sha512-gOc8UB99F6eWVWFtM9jUikjN7QkWxB3nY0df5Z0Zq1/Nkwl5V4hAAsl0tmwlgWl/1shlTF8DnNYLO8X6wRV9pA==", + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==" + }, + "is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==" + }, + "trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==" + }, + "unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", "requires": { - "ccount": "^1.0.3", - "hastscript": "^5.0.0", - "property-information": "^5.0.0", - "web-namespaces": "^1.1.2", - "xtend": "^4.0.1" + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" } }, - "hastscript": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-5.1.2.tgz", - "integrity": "sha512-WlztFuK+Lrvi3EggsqOkQ52rKbxkXL3RwB6t5lwoa8QLMemoWfBuL43eDrwOamJyR7uKQKdmKYaBH1NZBiIRrQ==", + "unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", "requires": { - "comma-separated-tokens": "^1.0.0", - "hast-util-parse-selector": "^2.0.0", - "property-information": "^5.0.0", - "space-separated-tokens": "^1.0.0" + "@types/unist": "^3.0.0" } }, - "parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" - }, - "rehype-parse": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-6.0.2.tgz", - "integrity": "sha512-0S3CpvpTAgGmnz8kiCyFLGuW5yA4OQhyNTm/nwPopZ7+PI11WnGl1TTWTGv/2hPEe/g2jRLlhVVSsoDH8waRug==", + "vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", "requires": { - "hast-util-from-parse5": "^5.0.0", - "parse5": "^5.0.0", - "xtend": "^4.0.0" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" } }, - "unified": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/unified/-/unified-8.4.2.tgz", - "integrity": "sha512-JCrmN13jI4+h9UAyKEoGcDZV+i1E7BLFuG7OsaDvTXI5P0qhHX+vZO/kOhz9jn8HGENDKbwSeB0nVOg4gVStGA==", + "vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", "requires": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "is-plain-obj": "^2.0.0", - "trough": "^1.0.0", - "vfile": "^4.0.0" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" } } } }, - "remark-emoji": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/remark-emoji/-/remark-emoji-2.2.0.tgz", - "integrity": "sha512-P3cj9s5ggsUvWw5fS2uzCHJMGuXYRb0NnZqYlNecewXt8QBU9n5vW3DUUKOhepS8F9CwdMx9B8a3i7pqFWAI5w==", + "remark-frontmatter": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-5.0.0.tgz", + "integrity": "sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==", "requires": { - "emoticon": "^3.2.0", - "node-emoji": "^1.10.0", - "unist-util-visit": "^2.0.3" - } - }, - "remark-footnotes": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/remark-footnotes/-/remark-footnotes-2.0.0.tgz", - "integrity": "sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ==" - }, - "remark-mdx": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-1.6.22.tgz", - "integrity": "sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ==", - "requires": { - "@babel/core": "7.12.9", - "@babel/helper-plugin-utils": "7.10.4", - "@babel/plugin-proposal-object-rest-spread": "7.12.1", - "@babel/plugin-syntax-jsx": "7.12.1", - "@mdx-js/util": "1.6.22", - "is-alphabetical": "1.0.4", - "remark-parse": "8.0.3", - "unified": "9.2.0" - }, - "dependencies": { - "@babel/core": { - "version": "7.12.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", - "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.5", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.5", - "@babel/parser": "^7.12.7", - "@babel/template": "^7.12.7", - "@babel/traverse": "^7.12.9", - "@babel/types": "^7.12.7", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", - "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-transform-parameters": "^7.12.1" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", - "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } + "@types/mdast": "^4.0.0", + "mdast-util-frontmatter": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0", + "unified": "^11.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==" + }, + "is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==" + }, + "trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==" }, "unified": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz", - "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", "requires": { - "bail": "^1.0.0", + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^2.0.0", - "trough": "^1.0.0", - "vfile": "^4.0.0" + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + } + }, + "unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + } + }, + "vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" } } } }, - "remark-mdx-remove-exports": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/remark-mdx-remove-exports/-/remark-mdx-remove-exports-1.6.22.tgz", - "integrity": "sha512-7g2uiTmTGfz5QyVb+toeX25frbk1Y6yd03RXGPtqx0+DVh86Gb7MkNYbk7H2X27zdZ3CQv1W/JqlFO0Oo8IxVA==", + "remark-gfm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz", + "integrity": "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==", "requires": { - "unist-util-remove": "2.0.0" + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" }, "dependencies": { - "unist-util-remove": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-2.0.0.tgz", - "integrity": "sha512-HwwWyNHKkeg/eXRnE11IpzY8JT55JNM1YCwwU9YNCnfzk6s8GhPXrVBBZWiwLeATJbI7euvoGSzcy9M29UeW3g==", + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==" + }, + "is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==" + }, + "trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==" + }, + "unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", + "requires": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + } + }, + "unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + } + }, + "vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", "requires": { - "unist-util-is": "^4.0.0" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" } } } }, - "remark-mdx-remove-imports": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/remark-mdx-remove-imports/-/remark-mdx-remove-imports-1.6.22.tgz", - "integrity": "sha512-lmjAXD8Ltw0TsvBzb45S+Dxx7LTJAtDaMneMAv8LAUIPEyYoKkmGbmVsiF0/pY6mhM1Q16swCmu1TN+ie/vn/A==", + "remark-mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.0.0.tgz", + "integrity": "sha512-O7yfjuC6ra3NHPbRVxfflafAj3LTwx3b73aBvkEFU5z4PsD6FD4vrqJAkE5iNGLz71GdjXfgRqm3SQ0h0VuE7g==", + "requires": { + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" + } + }, + "remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", "requires": { - "unist-util-remove": "2.0.0" + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" }, "dependencies": { - "unist-util-remove": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-2.0.0.tgz", - "integrity": "sha512-HwwWyNHKkeg/eXRnE11IpzY8JT55JNM1YCwwU9YNCnfzk6s8GhPXrVBBZWiwLeATJbI7euvoGSzcy9M29UeW3g==", + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==" + }, + "is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==" + }, + "trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==" + }, + "unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", + "requires": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + } + }, + "unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + } + }, + "vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", "requires": { - "unist-util-is": "^4.0.0" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" } } } }, - "remark-parse": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-8.0.3.tgz", - "integrity": "sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==", - "requires": { - "ccount": "^1.0.0", - "collapse-white-space": "^1.0.2", - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-whitespace-character": "^1.0.0", - "is-word-character": "^1.0.0", - "markdown-escapes": "^1.0.0", - "parse-entities": "^2.0.0", - "repeat-string": "^1.5.4", - "state-toggle": "^1.0.0", - "trim": "0.0.1", - "trim-trailing-lines": "^1.0.0", - "unherit": "^1.0.4", - "unist-util-remove-position": "^2.0.0", - "vfile-location": "^3.0.0", - "xtend": "^4.0.1" - } - }, - "remark-squeeze-paragraphs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/remark-squeeze-paragraphs/-/remark-squeeze-paragraphs-4.0.0.tgz", - "integrity": "sha512-8qRqmL9F4nuLPIgl92XUuxI3pFxize+F1H0e/W3llTk0UsjJaj01+RrirkMw7P21RKe4X6goQhYRSvNWX+70Rw==", - "requires": { - "mdast-squeeze-paragraphs": "^4.0.0" - } - }, - "renderkid": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", - "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "remark-rehype": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.0.0.tgz", + "integrity": "sha512-vx8x2MDMcxuE4lBmQ46zYUDfcFMmvg80WYX+UNLeG6ixjdCCLcw1lrgAukwBTuOFsS78eoAedHGn9sNM0w7TPw==", "requires": { - "css-select": "^4.1.3", - "dom-converter": "^0.2.0", - "htmlparser2": "^6.1.0", - "lodash": "^4.17.21", - "strip-ansi": "^6.0.1" + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" }, "dependencies": { - "css-select": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", - "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", + "@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", "requires": { - "boolbase": "^1.0.0", - "css-what": "^5.1.0", - "domhandler": "^4.3.0", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" + "@types/unist": "*" } }, - "css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==" + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, - "dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==" + }, + "is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==" + }, + "trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==" + }, + "unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" } }, - "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" + "unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "requires": { + "@types/unist": "^3.0.0" + } }, - "domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", + "vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", "requires": { - "domelementtype": "^2.2.0" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" } }, - "domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" } + } + } + }, + "remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "requires": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + "bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==" }, - "htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==" + }, + "trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==" + }, + "unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" } }, - "nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", "requires": { - "boolbase": "^1.0.0" + "@types/unist": "^3.0.0" + } + }, + "vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + } + }, + "vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" } } } }, + "renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "requires": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", @@ -24691,12 +30950,12 @@ "require-like": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", - "integrity": "sha1-rW8wwTvs15cBDEaK+ndcDAprR/o=" + "integrity": "sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==" }, "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, "resolve": { "version": "1.22.0", @@ -24708,6 +30967,11 @@ "supports-preserve-symlinks-flag": "^1.0.0" } }, + "resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" + }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -24719,80 +30983,45 @@ "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" }, "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", - "requires": { - "lowercase-keys": "^1.0.0" - } - }, - "retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==" - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", "requires": { - "glob": "^7.1.3" + "lowercase-keys": "^3.0.0" } - }, - "rtl-detect": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/rtl-detect/-/rtl-detect-1.0.4.tgz", - "integrity": "sha512-EBR4I2VDSSYr7PkBmFy04uhycIpDKp+21p/jARYXlCSjQksTBQcJ0HFUPOO79EPPH5JS6VAhiIQbycf0O3JAxQ==" - }, - "rtlcss": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-3.5.0.tgz", - "integrity": "sha512-wzgMaMFHQTnyi9YOwsx9LjOxYXJPzS8sYnFaKm6R5ysvTkwzHiB0vxnbHwchHQT65PTdBjDG21/kQBWI7q9O7A==", - "requires": { - "find-up": "^5.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.3.11", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "requires": { - "p-locate": "^5.0.0" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "requires": { - "p-limit": "^3.0.2" - } - } + }, + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==" + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "rtl-detect": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/rtl-detect/-/rtl-detect-1.0.4.tgz", + "integrity": "sha512-EBR4I2VDSSYr7PkBmFy04uhycIpDKp+21p/jARYXlCSjQksTBQcJ0HFUPOO79EPPH5JS6VAhiIQbycf0O3JAxQ==" + }, + "rtlcss": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.1.1.tgz", + "integrity": "sha512-/oVHgBtnPNcggP2aVXQjSy6N1mMAfHg4GSag0QtZBlD5bdDgAHwr4pydqJGd+SUCu9260+Pjqbjwtvu7EMH1KQ==", + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0", + "postcss": "^8.4.21", + "strip-json-comments": "^3.1.1" } }, "run-parallel": { @@ -24804,9 +31033,9 @@ } }, "rxjs": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.4.tgz", - "integrity": "sha512-h5M3Hk78r6wAheJF0a5YahB1yRQKCsZ4MsGdZ5O9ETbVtjPcScGfrMmoOq7EBsCRzd4BDkvDJ7ogP8Sz5tTFiQ==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "requires": { "tslib": "^2.1.0" } @@ -24822,29 +31051,61 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" }, "scheduler": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", - "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" } }, "schema-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", "requires": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + } } }, + "search-insights": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.11.0.tgz", + "integrity": "sha512-Uin2J8Bpm3xaZi9Y8QibSys6uJOFZ+REMrf42v20AA3FUDUrshKkMEP6liJbMAHCm71wO6ls4mwAf7a3gFVxLw==", + "peer": true + }, "section-matter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", @@ -24857,57 +31118,50 @@ "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=" + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==" }, "selfsigned": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.0.0.tgz", - "integrity": "sha512-cUdFiCbKoa1mZ6osuJs2uDHrs0k0oprsKveFiiaBKCNq3SYyb5gs2HxhQyDNLCmL51ZZThqi4YNDpCK6GOP1iQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", + "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", "requires": { - "node-forge": "^1.2.0" + "node-forge": "^1" } }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" } }, "semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", + "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", "requires": { - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } + "semver": "^7.3.5" } }, "send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "requires": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", + "depd": "2.0.0", + "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "1.8.1", + "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "statuses": "2.0.1" }, "dependencies": { "debug": { @@ -24921,10 +31175,15 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" } } }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -24938,42 +31197,32 @@ } }, "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", "requires": { "randombytes": "^2.1.0" } }, "serve-handler": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.3.tgz", - "integrity": "sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==", + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.5.tgz", + "integrity": "sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg==", "requires": { "bytes": "3.0.0", "content-disposition": "0.5.2", "fast-url-parser": "1.1.3", "mime-types": "2.1.18", - "minimatch": "3.0.4", + "minimatch": "3.1.2", "path-is-inside": "1.0.2", "path-to-regexp": "2.2.1", "range-parser": "1.2.0" - }, - "dependencies": { - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - } } }, "serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "requires": { "accepts": "~1.3.4", "batch": "0.6.1", @@ -24992,10 +31241,15 @@ "ms": "2.0.0" } }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" + }, "http-errors": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "requires": { "depd": "~1.1.2", "inherits": "2.0.3", @@ -25006,35 +31260,53 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" } } }, "serve-static": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", - "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "requires": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.2" + "send": "0.19.0" + } + }, + "set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" } }, "setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" }, "setprototypeof": { "version": "1.2.0", @@ -25049,6 +31321,11 @@ "kind-of": "^6.0.2" } }, + "shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -25063,9 +31340,9 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" }, "shell-quote": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", - "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==" + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==" }, "shelljs": { "version": "0.8.5", @@ -25078,13 +31355,14 @@ } }, "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" } }, "signal-exit": { @@ -25093,13 +31371,13 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "sirv": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz", - "integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.3.tgz", + "integrity": "sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==", "requires": { "@polka/url": "^1.0.0-next.20", "mrmime": "^1.0.0", - "totalist": "^1.0.0" + "totalist": "^3.0.0" } }, "sisteransi": { @@ -25118,6 +31396,14 @@ "sax": "^1.2.4" } }, + "skin-tone": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", + "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", + "requires": { + "unicode-emoji-modifier-base": "^1.0.0" + } + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -25167,19 +31453,14 @@ } }, "sort-css-media-queries": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.0.4.tgz", - "integrity": "sha512-PAIsEK/XupCQwitjv7XxoMvYhT7EAfyzI3hsy/MyDgTvc+Ft55ctdkctJLOy6cQejaIC+zjpUL4djFVm2ivOOw==" - }, - "source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.1.0.tgz", + "integrity": "sha512-IeWvo8NkNiY2vVYdPa27MCQiR0MN0M80johAYFVxWWXQ44KU84WNxjslwBHmc/7ZL2ccwkM7/e6S5aiKZXm7jA==" }, "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "source-map-js": { "version": "1.0.2", @@ -25193,20 +31474,8 @@ "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } } }, - "sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" - }, "space-separated-tokens": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", @@ -25242,20 +31511,20 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, + "srcset": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/srcset/-/srcset-4.0.0.tgz", + "integrity": "sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==" + }, "stable": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" }, - "state-toggle": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz", - "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==" - }, "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" }, "std-env": { "version": "3.0.1", @@ -25320,6 +31589,15 @@ "define-properties": "^1.1.3" } }, + "stringify-entities": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.3.tgz", + "integrity": "sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==", + "requires": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + } + }, "stringify-object": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", @@ -25333,7 +31611,7 @@ "is-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==" } } }, @@ -25348,7 +31626,7 @@ "strip-bom-string": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", - "integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=" + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==" }, "strip-final-newline": { "version": "2.0.0", @@ -25361,19 +31639,19 @@ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" }, "style-to-object": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", - "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==", + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.4.tgz", + "integrity": "sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==", "requires": { "inline-style-parser": "0.1.1" } }, "stylehacks": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.0.3.tgz", - "integrity": "sha512-ENcUdpf4yO0E1rubu8rkxI+JGQk4CgjchynZ4bDBJDfqdy+uhTRSWb8/F3Jtu+Bw5MW45Po3/aQGeIyyxgQtxg==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", + "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", "requires": { - "browserslist": "^4.16.6", + "browserslist": "^4.21.4", "postcss-selector-parser": "^6.0.4" } }, @@ -25413,69 +31691,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" - }, - "css-select": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", - "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", - "requires": { - "boolbase": "^1.0.0", - "css-what": "^5.1.0", - "domhandler": "^4.3.0", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - } - }, - "css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==" - }, - "dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - } - }, - "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" - }, - "domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", - "requires": { - "domelementtype": "^2.2.0" - } - }, - "domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - } - }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" - }, - "nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "requires": { - "boolbase": "^1.0.0" - } } } }, @@ -25515,43 +31730,38 @@ "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" }, "terser": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.11.0.tgz", - "integrity": "sha512-uCA9DLanzzWSsN1UirKwylhhRz3aKPInlfmpGfw8VN6jHsAtu8HJtIpeeHHK23rxnE/cDc+yvmq5wqkIC6Kn0A==", + "version": "5.31.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz", + "integrity": "sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==", "requires": { - "acorn": "^8.5.0", + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" }, "dependencies": { "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==" + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==" }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" } } }, "terser-webpack-plugin": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", - "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", "requires": { + "@jridgewell/trace-mapping": "^0.3.20", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1", - "terser": "^5.7.2" + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" }, "dependencies": { "schema-utils": { @@ -25563,11 +31773,6 @@ "ajv": "^6.12.5", "ajv-keywords": "^3.5.2" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" } } }, @@ -25581,11 +31786,6 @@ "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" }, - "timsort": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", - "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" - }, "tiny-invariant": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz", @@ -25601,11 +31801,6 @@ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" }, - "to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==" - }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -25629,24 +31824,19 @@ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, "totalist": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", - "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==" }, "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" - }, - "trim": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", - "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=" + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, - "trim-trailing-lines": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz", - "integrity": "sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==" + "trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==" }, "trough": { "version": "1.0.5", @@ -25654,9 +31844,9 @@ "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==" }, "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", + "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==" }, "type-check": { "version": "0.4.0", @@ -25681,16 +31871,16 @@ }, "dependencies": { "mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" }, "mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "requires": { - "mime-db": "1.51.0" + "mime-db": "1.52.0" } } } @@ -25704,15 +31894,15 @@ } }, "typescript": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", - "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz", + "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==", "peer": true }, "ua-parser-js": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz", - "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==" + "version": "1.0.37", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.37.tgz", + "integrity": "sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==" }, "unbox-primitive": { "version": "1.0.1", @@ -25725,20 +31915,16 @@ "which-boxed-primitive": "^1.0.2" } }, - "unherit": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz", - "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==", - "requires": { - "inherits": "^2.0.0", - "xtend": "^4.0.0" - } - }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==" }, + "unicode-emoji-modifier-base": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", + "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==" + }, "unicode-match-property-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", @@ -25749,14 +31935,14 @@ } }, "unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==" }, "unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==" }, "unified": { "version": "9.2.2", @@ -25772,18 +31958,13 @@ } }, "unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", "requires": { - "crypto-random-string": "^2.0.0" + "crypto-random-string": "^4.0.0" } }, - "unist-builder": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-2.0.3.tgz", - "integrity": "sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==" - }, "unist-util-find-after": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-3.0.0.tgz", @@ -25792,35 +31973,82 @@ "unist-util-is": "^4.0.0" } }, - "unist-util-generated": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.6.tgz", - "integrity": "sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg==" - }, "unist-util-is": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==" }, "unist-util-position": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.1.0.tgz", - "integrity": "sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA==" + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "requires": { + "@types/unist": "^3.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + } + } }, - "unist-util-remove": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-2.1.0.tgz", - "integrity": "sha512-J8NYPyBm4baYLdCbjmf1bhPu45Cr1MWTm77qd9istEkzWpnN6O9tMsEbB2JhNnBCqGENRqEWomQ+He6au0B27Q==", + "unist-util-position-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", + "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", "requires": { - "unist-util-is": "^4.0.0" + "@types/unist": "^3.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + } } }, "unist-util-remove-position": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz", - "integrity": "sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", "requires": { - "unist-util-visit": "^2.0.0" + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "dependencies": { + "@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + } + }, + "unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + } + } } }, "unist-util-stringify-position": { @@ -25858,71 +32086,42 @@ "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" }, - "update-notifier": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", - "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", + "update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", "requires": { - "boxen": "^5.0.0", - "chalk": "^4.1.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.4.0", - "is-npm": "^5.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.1.0", - "pupa": "^2.1.1", - "semver": "^7.3.4", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "update-notifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz", + "integrity": "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==", + "requires": { + "boxen": "^7.0.0", + "chalk": "^5.0.1", + "configstore": "^6.0.0", + "has-yarn": "^3.0.0", + "import-lazy": "^4.0.0", + "is-ci": "^3.0.1", + "is-installed-globally": "^0.4.0", + "is-npm": "^6.0.0", + "is-yarn-global": "^0.4.0", + "latest-version": "^7.0.0", + "pupa": "^3.1.0", + "semver": "^7.3.7", + "semver-diff": "^4.0.0", + "xdg-basedir": "^5.1.0" + }, + "dependencies": { "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==" } } }, @@ -25941,22 +32140,6 @@ } } }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" - } - } - }, "url-loader": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", @@ -25967,16 +32150,6 @@ "schema-utils": "^3.0.0" }, "dependencies": { - "loader-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - }, "mime-db": { "version": "1.51.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", @@ -26002,23 +32175,35 @@ } } }, - "url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "use-composed-ref": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.3.0.tgz", + "integrity": "sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==", + "requires": {} + }, + "use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "requires": {} + }, + "use-latest": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.1.tgz", + "integrity": "sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==", "requires": { - "prepend-http": "^2.0.0" + "use-isomorphic-layout-effect": "^1.1.1" } }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "utila": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=" + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" }, "utility-types": { "version": "3.10.0", @@ -26028,7 +32213,7 @@ "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" }, "uuid": { "version": "8.3.2", @@ -26048,7 +32233,7 @@ "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" }, "vfile": { "version": "4.2.1", @@ -26076,21 +32261,21 @@ } }, "wait-on": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz", - "integrity": "sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.2.0.tgz", + "integrity": "sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ==", "requires": { - "axios": "^0.25.0", - "joi": "^17.6.0", + "axios": "^1.6.1", + "joi": "^17.11.0", "lodash": "^4.17.21", - "minimist": "^1.2.5", - "rxjs": "^7.5.4" + "minimist": "^1.2.8", + "rxjs": "^7.8.1" } }, "watchpack": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", - "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", "requires": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -26112,50 +32297,54 @@ "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "webpack": { - "version": "5.69.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.69.1.tgz", - "integrity": "sha512-+VyvOSJXZMT2V5vLzOnDuMz5GxEqLk7hKWQ56YxPW/PQRUuKimPqmEIJOx8jHYeyo65pKbapbW464mvsKbaj4A==", - "requires": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", + "version": "5.94.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", + "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", + "requires": { + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.7.1", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.8.3", - "es-module-lexer": "^0.9.0", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-better-errors": "^1.0.2", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", "webpack-sources": "^3.2.3" }, "dependencies": { "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==" + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==" }, - "acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", "requires": {} }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, "mime-db": { "version": "1.51.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", @@ -26170,9 +32359,9 @@ } }, "schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "requires": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -26187,261 +32376,129 @@ } }, "webpack-bundle-analyzer": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.5.0.tgz", - "integrity": "sha512-GUMZlM3SKwS8Z+CKeIFx7CVoHn3dXFcUAjT/dcZQQmfSZGvitPfMob2ipjai7ovFFqPvTqkEZ/leL4O0YOdAYQ==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.1.tgz", + "integrity": "sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ==", "requires": { + "@discoveryjs/json-ext": "0.5.7", "acorn": "^8.0.4", "acorn-walk": "^8.0.0", - "chalk": "^4.1.0", "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", "gzip-size": "^6.0.0", - "lodash": "^4.17.20", + "html-escaper": "^2.0.2", + "is-plain-object": "^5.0.0", "opener": "^1.5.2", - "sirv": "^1.0.7", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", "ws": "^7.3.1" }, "dependencies": { "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==" - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==" }, "commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" }, - "has-flag": { + "escape-string-regexp": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" } } }, "webpack-dev-middleware": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.1.tgz", - "integrity": "sha512-81EujCKkyles2wphtdrnPg/QqegC/AtqNH//mQkBYSMqwFVCQrxM6ktB2O/SPlZy7LqeEfTbV3cZARGQz6umhg==", + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", "requires": { "colorette": "^2.0.10", - "memfs": "^3.4.1", + "memfs": "^3.4.3", "mime-types": "^2.1.31", "range-parser": "^1.2.1", "schema-utils": "^4.0.0" }, "dependencies": { - "ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "requires": { - "fast-deep-equal": "^3.1.3" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, "mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" }, "mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "requires": { - "mime-db": "1.51.0" + "mime-db": "1.52.0" } }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - } } } }, "webpack-dev-server": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.7.4.tgz", - "integrity": "sha512-nfdsb02Zi2qzkNmgtZjkrMOcXnYZ6FLKcQwpxT7MvmHKc+oTtDsBju8j+NMyAygZ9GW1jMEUpy3itHtqgEhe1A==", + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", + "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", "requires": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", "@types/express": "^4.17.13", "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", "@types/sockjs": "^0.3.33", - "@types/ws": "^8.2.2", + "@types/ws": "^8.5.5", "ansi-html-community": "^0.0.8", - "bonjour": "^3.5.0", + "bonjour-service": "^1.0.11", "chokidar": "^3.5.3", "colorette": "^2.0.10", "compression": "^1.7.4", - "connect-history-api-fallback": "^1.6.0", + "connect-history-api-fallback": "^2.0.0", "default-gateway": "^6.0.3", - "del": "^6.0.0", - "express": "^4.17.1", + "express": "^4.17.3", "graceful-fs": "^4.2.6", "html-entities": "^2.3.2", - "http-proxy-middleware": "^2.0.0", + "http-proxy-middleware": "^2.0.3", "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", "open": "^8.0.9", "p-retry": "^4.5.0", - "portfinder": "^1.0.28", + "rimraf": "^3.0.2", "schema-utils": "^4.0.0", - "selfsigned": "^2.0.0", + "selfsigned": "^2.1.1", "serve-index": "^1.9.1", - "sockjs": "^0.3.21", + "sockjs": "^0.3.24", "spdy": "^4.0.2", - "strip-ansi": "^7.0.0", "webpack-dev-middleware": "^5.3.1", - "ws": "^8.4.2" + "ws": "^8.13.0" }, "dependencies": { - "ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "requires": { - "fast-deep-equal": "^3.1.3" - } - }, - "ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - } - }, - "strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "requires": { - "ansi-regex": "^6.0.1" - } - }, "ws": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "requires": {} } } }, "webpack-merge": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", "requires": { "clone-deep": "^4.0.1", + "flat": "^5.0.2", "wildcard": "^2.0.0" } }, - "webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, "webpackbar": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-5.0.2.tgz", @@ -26516,7 +32573,7 @@ "whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -26551,53 +32608,95 @@ } }, "widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", "requires": { - "string-width": "^4.0.0" + "string-width": "^5.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "requires": { + "ansi-regex": "^6.0.1" + } + } } }, "wildcard": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", - "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==" }, "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==" }, "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" + }, "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==" + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "requires": { - "color-convert": "^2.0.1" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "requires": { - "color-name": "~1.1.4" + "ansi-regex": "^6.0.1" } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" } } }, @@ -26618,15 +32717,15 @@ } }, "ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "requires": {} }, "xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==" }, "xml-js": { "version": "1.6.11", diff --git a/docs/package.json b/docs/package.json index 7bb35e51b05..01ff431c355 100644 --- a/docs/package.json +++ b/docs/package.json @@ -5,6 +5,7 @@ "scripts": { "start": "docusaurus start", "build": "docusaurus build", + "serve": "docusaurus serve", "swizzle": "docusaurus swizzle", "deploy": "docusaurus deploy", "format": "prettier --check \"**/*.{js,jsx,json,md,scss}\"", @@ -13,18 +14,17 @@ "lint:fix": "npm run lint -- --fix" }, "dependencies": { - "@docusaurus/core": "^2.0.0-alpha.73", - "@docusaurus/preset-classic": "^2.0.0-alpha.73", - "@docusaurus/theme-search-algolia": "^2.0.0-alpha.73", + "@babel/eslint-parser": "^7.2.0", + "@docusaurus/core": "^3.0.0", + "@docusaurus/preset-classic": "^3.0.0", "autocomplete.js": "^0.38.1", - "babel-eslint": "^10.1.0", "clsx": "^1.1.1", - "docusaurus-lunr-search": "^2.1.7", + "docusaurus-lunr-search": "^3.3.0", "eslint": "^7.3.1", - "eslint-plugin-react": "^7.20.0", + "eslint-plugin-react": "^7.28.0", "prettier": "^2.0.5", - "react": "^16.8.4", - "react-dom": "^16.8.4" + "react": "^18.0.0", + "react-dom": "^18.0.0" }, "browserslist": { "production": [ diff --git a/docs/publish-docs.sh b/docs/publish-docs.sh index 2a19ba0d0b9..c7a47dd77eb 100755 --- a/docs/publish-docs.sh +++ b/docs/publish-docs.sh @@ -17,7 +17,7 @@ fi cat > "$CONFIG_FILE" <i ∈ \{0,1\}^256 which is hashed using `H: {0, 1}^256 × {0, 1}^256 → {0, 1}^256`, meaning two child nodes with their 256 bit strings are hashed into one parent node with a 256 bit string. You can use any hash function that satisfies this property but we use SHA256. + +Important properties of merkle trees: + +- The tree must be a fully balanced binary tree +- Each Node _Xi = H(X2i, X2i+1) for all i < 2^D_ +- Each Leaf Node _Xi for all i {'<='} 2^D_. Xi is the hash of the data. + +Because of these properties we can verify if certain data exists in tree while compressing all the data into a single 256 bit string called the root hash. + +Example of a merkle tree of depth 2: + +```txt + X1 + / \ + X2 X3 + / \ / \ + X4 X5 X6 X7 +``` + +You can verify that X5 computes to X1 by doing X1 = H(H(X4,X5),X3)) where \{X4,X5,X3\} are the proof. +If you change X5 to X5' then you will have to recompute the root hash in the following steps: + +- X2' = H(X4,X5') +- X1' = H(X2',X3) + +### Concurrent leaf replacement + +We know that there can be multiple concurrent requests to write to the same state, however when the root changes while the first write is happening the second write will generate an invalid root, in other words every time a root is modified all modifications in progress will be invalid. + +```txt + X1' X1'' + / \ / \ + X2' X3 X2 X3'' + / \ / \ / \ / \ + X4 X5' X6 X7 X4 X5 X6'' X7 +``` + +In the above example let's say we try to modify `X5 -> X5'` and make another request to modify X6 -> X6''. For the first change we get root `X1'` computed using `X1' = H(H(X4,X5'),X3)`. For the second change we get root X1'' computed using `X1'' = H(H(X6'',X7),X2`). However `X1''` is not valid as `X1' != H(H(X6, X7), X2)` because the new root is actually `X1'`. + +The reason this happens is because the change in the first trees path actually changes the proofs required by the second trees change. To circumvent this problem we maintain a changelog of updates that have been made to the tree, so when `X5 -> X5'` the second mutation can actually use X2' instead of X2 which would compute to the correct root. + +To swap the nodes when adding a new leaf in the second tree we do the following: + +- Take XOR of the leaf indices of the change log path and the new leaf in base 2 +- The depth at which you have to make the swap is the number of leading zeroes in the result(we also add one to it because the swap node is one below the intersection node) +- At that depth change the node in the proof to the node in the changelog + +Example with the previous trees: + +```txt + 2 1 +Changelog: [X5',X2'] +New Leaf: X6'' at leaf index 2 + + 2 1 +Old proof for new leaf: [X7,X2] + +1 XOR 2 = 001 XOR 010 = 011 (no leading zeroes) +depth to swap at = 0 + 1 = 1 + + 2 1 +New proof for new leaf: [X7,X2'] +``` + +**Note:** We use XOR here because changelogs can get large as there can be many concurrent writes so using XOR is more efficient than a simple array search algorithm. + +**Note**: Solana imposes a transactions size restriction of 1232 bytes hence the program also provides the ability to cache the upper most part of the concurrent merkle tree called a "canopy" which is stored at the end of the account. diff --git a/docs/src/account-compression/usage.md b/docs/src/account-compression/usage.md new file mode 100644 index 00000000000..31bd53e6b0c --- /dev/null +++ b/docs/src/account-compression/usage.md @@ -0,0 +1,112 @@ +--- +title: Example usage of the TS SDK +--- + + + +## Install + +```shell +npm install --save @solana/spl-account-compression @solana/web3.js@1 +``` + +__OR__ + +```shell +yarn add @solana/spl-account-compression @solana/web3.js@1 +``` + +### Examples + +1. Create a tree + +```typescript +// Assume: known `payer` Keypair +// Generate a keypair for the ConcurrentMerkleTree +const cmtKeypair = Keypair.generate(); +// Create a system instruction to allocate enough +// space for the tree +const allocAccountIx = await createAllocTreeIx( + connection, + cmtKeypair.publicKey, + payer.publicKey, + { maxDepth, maxBufferSize }, + canopyDepth, +); +// Create an SPL compression instruction to initialize +// the newly created ConcurrentMerkleTree +const initTreeIx = createInitEmptyMerkleTreeIx( + cmtKeypair.publicKey, + payer.publicKey, + { maxDepth, maxBufferSize } +); +const tx = new Transaction().add(allocAccountIx).add(initTreeIx); +await sendAndConfirmTransaction(connection, tx, [cmtKeypair, payer]); +``` + +2. Add a leaf to the tree + +```typescript +// Create a new leaf +const newLeaf: Buffer = crypto.randomBytes(32); +// Add the new leaf to the existing tree +const appendIx = createAppendIx(cmtKeypair.publicKey, payer.publicKey, newLeaf); +const tx = new Transaction().add(appendIx); +await sendAndConfirmTransaction(connection, tx, [payer]); +``` + +3. Replace a leaf in the tree, using the provided `MerkleTree` as an indexer + +This example assumes that `offChainTree` has been indexing all previous modifying transactions +involving this tree. +It is okay for the indexer to be behind by a maximum of `maxBufferSize` transactions. + + +```typescript +// Assume: `offChainTree` is a MerkleTree instance +// that has been indexing the `cmtKeypair.publicKey` transactions +// Get a new leaf +const newLeaf: Buffer = crypto.randomBytes(32); +// Query off-chain records for information about the leaf +// you wish to replace by its index in the tree +const leafIndex = 314; +// Replace the leaf at `leafIndex` with `newLeaf` +const replaceIx = createReplaceIx( + cmtKeypair.publicKey, + payer.publicKey, + newLeaf, + offChainTree.getProof(leafIndex) +); +const tx = new Transaction().add(replaceIx); +await sendAndConfirmTransaction(connection, tx, [payer]); +``` + +4. Replace a leaf in the tree, using a 3rd party indexer + +This example assumes that some 3rd party service is indexing the tree at `cmtKeypair.publicKey` for you, and providing MerkleProofs via some REST endpoint. +The `getProofFromAnIndexer` function is a **placeholder** to exemplify this relationship. + +```typescript +// Get a new leaf +const newLeaf: Buffer = crypto.randomBytes(32); +// Query off-chain indexer for a MerkleProof +// possibly by executing GET request against a REST api +const proof = await getProofFromAnIndexer(myOldLeaf); +// Replace `myOldLeaf` with `newLeaf` at the same index in the tree +const replaceIx = createReplaceIx( + cmtKeypair.publicKey, + payer.publicKey, + newLeaf, + proof +); +const tx = new Transaction().add(replaceIx); +await sendAndConfirmTransaction(connection, tx, [payer]); +``` + +## Reference examples + +Here are some examples using account compression in the wild: + +* Solana Program Library [tests](https://github.com/solana-labs/solana-program-library/tree/master/account-compression/sdk/tests) + +* Metaplex Program Library Compressed NFT [tests](https://github.com/metaplex-foundation/metaplex-program-library/tree/master/bubblegum/js/tests) diff --git a/docs/src/associated-token-account.md b/docs/src/associated-token-account.md index d810adac94c..ff23010aa7c 100644 --- a/docs/src/associated-token-account.md +++ b/docs/src/associated-token-account.md @@ -38,10 +38,10 @@ document are available at: ## Source The Associated Token Account Program's source is available on -[github](https://github.com/solana-labs/solana-program-library). - +[GitHub](https://github.com/solana-program/associated-token-account). ## Interface + The Associated Token Account Program is written in Rust and available on [crates.io](https://crates.io/crates/spl-associated-token-account) and [docs.rs](https://docs.rs/spl-associated-token-account). @@ -64,18 +64,18 @@ const SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID: PublicKey = new PublicKey( 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL', ); -async function findAssociatedTokenAddress( +function findAssociatedTokenAddress( walletAddress: PublicKey, tokenMintAddress: PublicKey -): Promise { - return (await PublicKey.findProgramAddress( +): PublicKey { + return PublicKey.findProgramAddressSync( [ walletAddress.toBuffer(), TOKEN_PROGRAM_ID.toBuffer(), tokenMintAddress.toBuffer(), ], SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID - ))[0]; + )[0]; } ``` diff --git a/docs/src/confidential-token/deep-dive/encryption.md b/docs/src/confidential-token/deep-dive/encryption.md index dc5cc75b6d8..f800499726a 100644 --- a/docs/src/confidential-token/deep-dive/encryption.md +++ b/docs/src/confidential-token/deep-dive/encryption.md @@ -16,7 +16,7 @@ ElGamal encryption scheme where a ciphertext is divided into two components: - A Pedersen commitment of the encrypted message. This component is independent of the public key. - A "decryption handle" that binds the encryption randomness with respect to a - specific ElGamal public key. This component is independent of the actually + specific ElGamal public key. This component is independent of the actual encrypted message. The structure of the twisted ElGamal ciphertexts simplifies their design of some diff --git a/docs/src/confidential-token/deep-dive/equality_proof.pdf b/docs/src/confidential-token/deep-dive/equality_proof.pdf new file mode 100644 index 00000000000..164b4050404 Binary files /dev/null and b/docs/src/confidential-token/deep-dive/equality_proof.pdf differ diff --git a/docs/src/confidential-token/deep-dive/overview.md b/docs/src/confidential-token/deep-dive/overview.md index 31c2d370d9e..8016cd301e2 100644 --- a/docs/src/confidential-token/deep-dive/overview.md +++ b/docs/src/confidential-token/deep-dive/overview.md @@ -4,16 +4,16 @@ title: Protocol Overview In this section, we provide an overview of the underlying cryptographic protocol for the confidential Token extension. An understanding of the details that are -discussed in the following subsections are not needed to actually use the +discussed in the following subsections is not needed to actually use the confidential extension. We refer to the previous section for a quick start guide. We note that this overview exists mainly to provide the design intuition behind -the underlying cryptography that is used in the confidential extension. Some of +the underlying cryptography that is used in the confidential extension. Some parts of the description of the protocol in the overview could differ from the actual implementation. We refer to the subsequent subsections, the [source code](https://github.com/solana-labs/solana-program-library), and the -documentations within for the precise details of the underlying cryptography. +documentation within for the precise details of the underlying cryptography. ## Tokens with Encryption and Proofs @@ -188,7 +188,7 @@ token program itself, preventing it from verifying the validity of a transaction. To fix this, we require that transfer instructions include zero-knowledge proofs -that validate their correctness. Put simply, zero-knolwedge proofs consist of +that validate their correctness. Put simply, zero-knowledge proofs consist of two pair of algorithms `prove` and `verify` that work over public and private data. The `prove` algorithm generates a "proof" that certifies that some property of the public and private data is true. The `verify` algorithm checks @@ -238,7 +238,7 @@ zero-knowledge proofs. `lower_bound <= x < upper_bound`. In the confidential extension, we require that a transfer instruction includes - a range proof that certify the following: + a range proof that certifies the following: - The proof should certify that there are enough funds in the source account. Specifically, let `ct_source` be the encrypted balance of a source account @@ -299,7 +299,7 @@ decrypting transaction amounts allow for a more flexible interface. In a potential application, the decryption key for specific accounts can be shared among multiple users (e.g. regulators) that should have access to an account balance. Although these users can decrypt account balances, only the -owner of the account that have access to the owner signing key can sign a +owner of the account who has access to the owner signing key can sign a transaction that initiates a transfer of tokens. The owner of an account can update the account with a new encryption key using the `ConfigureAccount`. @@ -343,13 +343,13 @@ One way an attacker can disrupt the use of a confidential extension account is by using _front-running_. Zero-knowledge proofs are verified with respect to the encrypted balance of an account. Suppose that a user Alice generates a proof with respect to her current encrypted account balance. If another user Bob -transfers some tokesn to Alice, and Bob's transaction is processed first, then +transfers some tokens to Alice, and Bob's transaction is processed first, then Alice's transaction will be rejected by the Token program as the proof will not verify with respect to the newly updated account state. Under normal conditions, upon a rejection by the program, Alice can simply look up the newly updated ciphertext and submit a new transaction. However, if a -malicious attacker continuously flods the network with a transfer to Alice's +malicious attacker continuously floods the network with a transfer to Alice's account, then the account may theoretically become unusable. To prevent this type of attack, we modify the account data structure such that the encrypted balance of an account is divided into two separate components: the _pending_ @@ -369,7 +369,7 @@ Account { } ``` -Any outgoing funds from an account is subtracted from its available balance. Any +Any outgoing funds from an account are subtracted from its available balance. Any incoming funds to an account is added to its pending balance. As an example, consider a transfer instruction that moves 10 tokens from a @@ -435,7 +435,7 @@ Account { A well-known limitation of using linearly-homomorphic ElGamal encryption is the inefficiency of decryption. Even with a proper secret key, in order to recover the originally encrypted value, one must solve a computational problem called -the _discrete logarithm_, which requires an expoential time to solve. In the +the _discrete logarithm_, which requires an exponential time to solve. In the confidential extension program, we address this issue in the following two ways: - Transfer amounts are restricted to 48-bit numbers. diff --git a/docs/src/confidential-token/deep-dive/pubkey_proof.pdf b/docs/src/confidential-token/deep-dive/pubkey_proof.pdf new file mode 100644 index 00000000000..d2025436445 Binary files /dev/null and b/docs/src/confidential-token/deep-dive/pubkey_proof.pdf differ diff --git a/docs/src/confidential-token/deep-dive/validity_proof.pdf b/docs/src/confidential-token/deep-dive/validity_proof.pdf new file mode 100644 index 00000000000..39fcc121488 Binary files /dev/null and b/docs/src/confidential-token/deep-dive/validity_proof.pdf differ diff --git a/docs/src/confidential-token/deep-dive/zero_proof.pdf b/docs/src/confidential-token/deep-dive/zero_proof.pdf new file mode 100644 index 00000000000..1415a5d8a9e Binary files /dev/null and b/docs/src/confidential-token/deep-dive/zero_proof.pdf differ diff --git a/docs/src/confidential-token/deep-dive/zkps.md b/docs/src/confidential-token/deep-dive/zkps.md index dcf025bc702..9414baeac69 100644 --- a/docs/src/confidential-token/deep-dive/zkps.md +++ b/docs/src/confidential-token/deep-dive/zkps.md @@ -1,3 +1,340 @@ --- title: Zero-Knowledge Proofs --- + +Zero-knowledge proofs are tools that allow users to prove certain properties of +encrypted data. Most of the zero-knowledge proofs that are used in the +confidential extension are relatively small systems that are specifically +designed for the simple use-case of the confidential extension. Due to their +simplicity, none of the zero-knowledge systems that are used in the program +require any trusted setup or sophisticated circuit design. + +The zero-knowledge proofs that are used in the confidential extension can be +divided into two categories: _sigma protocols_ and _bulletproofs_. Sigma +protocols are simple systems that are tailor designed for the confidential +extension use-cases. Bulletproofs is an existing range proof system that was +developed in the specified [paper](https://eprint.iacr.org/2017/1066). + +## Transfer Instruction Data + +The confidential extension `Transfer` instruction data requires a number of +cryptographic components. Here, we provide intuition for each of these +components by building the transfer data in a series of steps. + +```rust +struct TransferData { + ... +} +``` + +### ElGamal Public Keys + +A transfer instruction has three associated ElGamal public keys: sender, +receiver, and auditor. A transfer instruction data must include these three +encryption public keys. + +```rust +struct TransferPubkeys { + source_pubkey: ElGamalPubkey, + destination_pubkey: ElGamal Pubkey, + auditor_pubkey: ElGamalPubkey, +} + +struct TransferData { + transfer_pubkeys: TransferPubkeys, +} +``` + +If there is no associated auditor associated with the mint, then the auditor +pubkey is simply 32 zero bytes. + +### Low and High-bit Encryption + +Transfer instruction data must include the transfer amount that is encrypted +under the three ElGamal public keys associated with the instruction. To cope +with ElGamal decryption as discussed in the previous section, the transfer +amount is restricted to 48-bit numbers and is encrypted as two separate +numbers: `amount_lo` that represents the low 16-bits and `amount_hi` that +represents the high 32-bits. + +Each `amount_lo` and `amount_hi` is encrypted under the three ElGamal public +keys associated with a transfer. Instead of including three independent +ciphertexts as part of the transfer data, we use the randomness-reuse property +of ElGamal encryption to minimize the size of ciphertexts. + +```rust +/// Ciphertext structure of the transfer amount encrypted under three ElGamal +/// public keys +struct TransferAmountEncryption { + commitment: PedersenCommitment, + source_handle: DecryptHandle, + destination_handle: DecryptionHandle, + auditor_handle: DecryptHandle, +} + +struct TransferData { + ciphertext_lo: TransferAmountEncryption, + ciphertext_hi: TransferAmountEncryption, + transfer_pubkeys: TransferPubkeys, +} +``` + +In addition to these ciphertexts, transfer data must include proofs that these +ciphertexts are generated properly. There are two ways that a user can +potentially cheat the program. First a user may provide ciphertexts that are +malformed. For example, even if a user may encrypt the transfer amount under a +wrong public key, there is no way for the program to check the validity of a +ciphertext. Therefore, we require that transfer data require a _ciphertext +validity_ proof that certifies that the ciphertexts are properly generated. + +Ciphertext validity proof only guarantees that a twisted ElGamal ciphertext is +properly generated. However, it does not certify any property regarding the +encrypted amount in a ciphertext. For example, a malicious user can encrypt +negative values, but there is no way for the program to detect this by simply +inspecting the ciphertext. Therefore, in addition to a ciphertext validity +proof, a transfer instruction must include a _range proof_ that certifies that +the encrypted amounts `amount_lo` and `amount_hi` are positive 16 and 32-bit +values respectively. + +```rust +struct TransferProof { + validity_proof: ValidityProof, + range_proof: RangeProof, +} + +struct TransferData { + ciphertext_lo: TransferAmountEncryption, + ciphertext_hi: TransferAmountEncryption, + transfer_pubkeys: TransferPubkeys, + proof: TransferProof, +} +``` + +### Verifying Net-Balance + +Finally, in addition to proving that the transfer amount is properly encrypted, +a user must include a proof that the source account has enough balance to +make the transfer. The canonical way to do this is for the user to generate a +range proof that certifies that the ciphertext +`source_available_balance - (ciphertext_lo + 2^16 * ciphertext_hi)`, which holds +the available balance of the source account subtracted by the transfer amount, +encrypts a positive 64-bit value. Since Bulletproofs supports proof +aggregation, this additional range proof can be aggregated into the original +range proof on the transfer amount. + +```rust +struct TransferProof { + validity_proof: ValidityProof, + range_proof: RangeProof, // certifies ciphertext amount and net-balance +} + +struct TransferData { + ciphertext_lo: TransferAmountEncryption, + ciphertext_hi: TransferAmountEncryption, + transfer_pubkeys: TransferPubkeys, + proof: TransferProof, +} +``` + +One technical problem with the above is that although the sender of a transfer +knows an ElGamal decryption key for the ciphertext `source_available_balance`, +it does not necessarily know a Pedersen opening for the ciphertext, which is +needed to generate the range proofs on the ciphertext +`source_available_balance - (ciphertext_lo + 2^16 * ciphertext_hi)`. Therefore, +in a transfer instruction, we require that the sender decrypt the ciphertext +`source_available_balance - (ciphertext_lo + 2^16 * ciphertext_hi)` on the +client side and include a new Pedersen commitment on the new source balance +`new_source_commitment` along with an _equality proof_ that certifies that the +ciphertext `source_available_balance - (ciphertext_lo + 2^16 * ciphertext_hi)` +and `new_source_commitment` encrypt the same message. + +```rust +struct TransferProof { + new_source_commitment: PedersenCommitment, + equality_proof: CtxtCommEqualityProof, + validity_proof: ValidityProof, + range_proof: RangeProof, +} + +struct TransferData { + ciphertext_lo: TransferAmountEncryption, + ciphertext_hi: TransferAmountEncryption, + transfer_pubkeys: TransferPubkeys, + proof: TransferProof, +} +``` + +## Transfer With Fee Instruction Data + +The confidential extension can be enabled for mints that are extended for fees. +If a mint is extended for fees, then any confidential transfer of the +corresponding tokens must use the confidential extension `TransferWithFee` +instruction. In addition to the data that are required for the `Transfer` +instruction, the `TransferWithFee` instruction requires additional cryptographic +components associated with fees. + +### Background on Transfer Fees + +If a mint is extended for fees, then transfers of tokens that pertains to the +mint requires a transfer fee that is calculated as a percentage of the transfer +amount. Specifically, a transaction fee is determined by two parameters: + +- `bp`: The base point representing the fee rate. It is a positive integer that + represents a percentage rate that is two points to the right of the decimal + place. + + For example, `bp = 1` represents the fee rate of 0.01%, `bp = 100` represents + the fee rate of 1%, and `bp = 10000` represents the fee rate of 100%. + +- `max_fee`: the max fee rate. A transfer fee is calculated using the fee rate + that is determined by `bp`, but it is capped by `max_fee`. + + For example, consider a transfer amount of 200 tokens. + + - For fee parameter `bp = 100` and `max_fee = 3`, the fee is simply 1% of the + transfer amount, which is 2. + - For fee parameter `bp = 200` and `max_fee = 3`, the fee is 3 since 2% of 200 + is 4, which is greater than the max fee of 3. + +The transfer fee is always rounded up to the nearest positive integer. For +example, if a transfer amount is `100` and the fee parameter is `bp = 110` and +`max_fee = 3`, then the fee is `2`, which is rounded up from 1.1% of the +transfer amount. + +The fee parameters can be specified in mints that are extended for fees. In +addition to the fee parameters, mints that are extended for fees contain the +`withdraw_withheld_authority` field, which specifies the public key of an +authority that can collect fees that are withheld from transfer amounts. + +A Token account that is extended for fees has an associated field +`withheld_amount`. Any transfer fee that is deducted from a transfer amount is +aggregated into the `withheld_amount` field of the destination account of the +transfer. The `withheld_amount` can be collected by the withdraw-withheld +authority into a specific account using the +`TransferFeeInstructions::WithdrawWithheldTokensFromAccounts` or into the mint +account using the `TransferFeeInstructions::HarvestWithheldTokensToMint`. The +withheld fees that accumulate in a mint can be collected into an account using +the `TransferFeeInstructions::WithdrawWithheldTokensFromMint`. + +### Fee Encryption + +The actual amount of a transfer fee cannot be included in the confidential +extension `TransferWithFee` instruction in the clear since the transfer amount +can be inferred from the fee. Therefore, in the confidential extension, the +transfer fee is encrypted under the destination and withheld authority ElGamal +public key. + +```rust +struct FeeEncryption { + commitment: PedersenCommitment, + destination_handle: DecryptHandle, + withdraw_withheld_authority_handle: DecryptHandle, +} + +struct TransferWithFeeData { + ... // `TransferData` components + fee_ciphertext: FeeEncryption, +} +``` + +Upon receiving a `TransferWithFee` instruction, the Token program deducts the +encrypted fee under the destination ElGamal public key from the encrypted +transfer amount under the same public key. Then it aggregates the ciphertext +that encrypts the fee under the withdraw withheld authority's ElGamal public key +into the `withheld_fee` component of the destination account. + +### Verifying the Fee Ciphertext + +The remaining pieces of the `TransferWithFee` instruction data are fields that +are required to verify the validity of the encrypted fee. Since the fee is +encrypted, the Token program cannot check that the fee was computed correctly by +simply inspecting the ciphertext. A `TransferWithFee` must include three +additional proofs to certify that the fee ciphertext is valid. + +- _ciphertext validity proof_: This proof component certifies that the actual + fee ciphertext is properly generated under the correct destination and + withdraw withheld authority ElGamal public key. +- _fee sigma proof_: In combination with range proof component, the fee sigma + proof certifies that the fee that is encrypted in `fee_ciphertext` is properly + calculated according to the fee parameter. +- _range proof_: In combination with the fee sigma proof components, the range + proof component certifies that the encrypted fee in `fee_ciphertext` is + properly calculated according to the fee parameter. + +We refer to the proof specifications below for the additional details. + +## Sigma Protocols + +### (Public-key) Validity Proof + +A public-key validity proof certifies that a twisted ElGamal public-key is a +well-formed public key. The precise description of the system is specified in +the following notes. + +[[Notes]](./pubkey_proof.pdf) + +The public-key validity proof is required for the `ConfigureAccount` +instruction. + +### (Ciphertext) Validity Proof + +A ciphertext validity proof certifies that a twisted ElGamal ciphertext is a +well-formed ciphertext. The precise description of the system is specified in +the following notes. + +[[Notes]](./validity_proof.pdf) + +Validity proofs are required for the `Withdraw`, `Transfer`, and +`TransferWithFee` instructions. These instructions require the client to include +twisted ElGamal ciphertexts as part of the instruction data. Validity proofs +that are attached with these instructions certify that these ElGamal ciphertexts +are well-formed. + +### Zero-balance Proof + +A zero-balance proof certifies that a twisted ElGamal ciphertext encrypts the +number zero. The precise description of the system is specified in the following +notes. + +[[Notes]](./zero_proof.pdf). + +Zero-balance proofs are required for the `EmptyAccount` instruction, which +prepares a token account for closing. An account may only be closed if the +balance in an account is zero. Since the balance is encrypted in the +confidential extension, the Token program cannot directly check that the +encrypted balance in an account is zero by inspecting the account state. +Instead, the program verifies the zero-balance proof that is attached in the +`EmptyAccount` instruction to check that the balance is indeed zero. + +### Equality Proof + +The confidential extension makes use of two kinds of equality proof. The first +variant _ciphertext-commitment_ equality proof certifies that a twisted ElGamal +ciphertext and a Pedersen commitment encode the same message. The second variant +_ciphertext-ciphertext_ equality proof certifies that two twisted ElGamal +ciphertexts encrypt the same message. The precise description of the system is +specified in the following notes. + +[[Notes]](./equality_proof.pdf). + +Ciphertext-commitment equality proofs are required for the `Transfer` and +`TransferWithFee` instructions. Ciphertext-ciphertext equality proofs are +required for the `WithdrawWithheldTokensFromMint` and +`WithdrawWithheldTokensFromAccounts` instructions. + +### Fee Sigma Proof + +The fee sigma proof certifies that a committed transfer fee is computed +correctly. The precise description of the system is specified in the following +notes. + +[Notes] + +The fee sigma proof is required for the `TransferWithFee` instruction. + +## Range Proofs + +The confidential extension uses Bulletproofs for range proofs. We refer to the +[academic paper](https://eprint.iacr.org/2017/1066) and the +[dalek](https://doc-internal.dalek.rs/bulletproofs/notes/index.html) +implementation for the details. diff --git a/docs/src/confidential-token/quickstart.md b/docs/src/confidential-token/quickstart.md index 311b4550c2f..a73334618da 100644 --- a/docs/src/confidential-token/quickstart.md +++ b/docs/src/confidential-token/quickstart.md @@ -1,3 +1,108 @@ --- title: Quick Start Guide --- + +The Token-2022 program provides confidential transfer functionality through the +confidential transfer extension. + +This guide explains how to use the confidential transfer extension. + +Please see the [Token-2022 Introduction](../token-2022) for more general information +about Token-2022 and the concept of extensions. + +## Setup + +See the [Token Setup Guide](../token#setup) to install the client utilities. +Token-2022 shares the same CLI and NPM packages for maximal compatibility. + +All of the commands here exist in a +[helper script](https://github.com/solana-labs/solana-program-library/tree/master/token/cli/examples/confidential-transfer.sh) +at the +[Token CLI Examples](https://github.com/solana-labs/solana-program-library/tree/master/token/cli/examples). + +### Example: Create a mint with confidential transfers + +To create a new mint with confidential transfers enabled, run: + +```console +$ spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token --enable-confidential-transfers auto +``` + +The `auto` keyword means that any token user can permissionlessly configure their +account to perform confidential transfers. + +If you would like to gate confidential transfer functionality to certain users, +you can set the approve policy to `manual`. With this approve policy, all users +must be manually approved to perform confidential transfers. Anyone can still use +the token non-confidentially. + +Note that you must configure your mint with confidential transfers at creation, +and cannot add it later. + +### Example: Configure a token account for confidential transfers + +Account creation works as normal: + +```console +$ spl-token create-account +``` + +Once the user creates their account, they may configure it for confidential transfers: + +```console +$ spl-token configure-confidential-transfer-account --address +``` + +Note that only the account owner may configure confidential transfers for their +account: only they should set the encryption key for their account. This is +different from normal accounts, such as associated-token-accounts, where someone +can create another person's account. + +### Example: Deposit confidential tokens + +Once the user configures their account for confidential transfers and has a +non-confidential token balance, they must deposit their tokens from non-confidential +to confidential: + +```console +$ spl-token deposit-confidential-tokens --address +``` + +Note that the deposited tokens will no longer exist on the account's non-confidential +balance: they have been completely moved into the confidential balance. + +### Example: Apply pending balance + +Whenever an account receives confidential tokens from transfers or deposits, the +balance will appear in the "pending" balance, which means that the user cannot +immediately access the funds. + +To move a balance from "pending" to "available", simply run: + +```console +$ spl-token apply-pending-balance --address +``` + +### Example: Transfer confidential tokens + +Once an account has an available balance, a user may finally transfer the tokens +to another account that has been configured for confidential transfers! + +```console +$ spl-token transfer --confidential +``` + +This operation takes a little bit longer since it requires multiple dependent +transactions, but it's still only a few seconds. + +### Example: Withdraw confidential tokens + +A user whose account has an available confidential balance may withdraw those +tokens back into their non-confidential balance. + +```console +$ spl-token withdraw-confidential-tokens --address +``` + +Be sure to apply any pending balance before running this command to be sure that +all tokens are available. diff --git a/docs/src/feature-proposal.md b/docs/src/feature-proposal.md index 4f6f556d03e..705d991ad0c 100644 --- a/docs/src/feature-proposal.md +++ b/docs/src/feature-proposal.md @@ -35,7 +35,7 @@ when appropriate. ## Source The Feature Proposal Program's source is available on -[github](https://github.com/solana-labs/solana-program-library) +[GitHub](https://github.com/solana-program/feature-proposal). ## Interface The Feature Proposal Program is written in Rust and available on [crates.io](https://crates.io/crates/spl-feature-proposal) and [docs.rs](https://docs.rs/spl-feature-proposal). @@ -58,9 +58,9 @@ This section describes the life cycle of a feature proposal. ### Implement the Feature The first step is to conceive of the new feature and realize it in the -Solana code base, working with the core Solana developers at https://github.com/solana-labs/solana. +Solana code base, working with the core Solana developers at https://github.com/anza-xyz/agave -During the implementation, a *feature id* will be required to identity the new +During the implementation, a *feature id* will be required to identify the new feature in the code base to avoid the new functionality until its activation. The *feature id* for a feature proposal is derived by running the following commands. @@ -140,8 +140,8 @@ acceptance, the votes are tallied by running: ``` $ spl-feature-proposal tally 8CyUVvio2oYAP28ZkMBPHq88ikhRgWet6i4NYsCW5Cxa ``` -Anybody may tally the vote. Once the required number of votes are tallied, the +Anybody may tally the vote. Once the required number of votes is tallied, the feature will be automatically activated at the start of the next epoch. Upon a successful activation the feature will now show as activated by -`solana feature status` as well. \ No newline at end of file +`solana feature status` as well. diff --git a/docs/src/memo.md b/docs/src/memo.md index aa2b77f212b..95bbd49d881 100644 --- a/docs/src/memo.md +++ b/docs/src/memo.md @@ -20,7 +20,7 @@ document are available at: ## Source The Memo Program's source is available on -[github](https://github.com/solana-labs/solana-program-library) +[GitHub](https://github.com/solana-program/memo) ## Interface diff --git a/docs/src/name-service.md b/docs/src/name-service.md index eed6e02262b..8e223dcf47b 100644 --- a/docs/src/name-service.md +++ b/docs/src/name-service.md @@ -42,7 +42,7 @@ centralized, the creation of new classes is permissionless and as a class owner any kind of decentralized governance signing program could be used. - Twitter handles can be added as names of one specific name class. The class - authority of will therefore hold the right to add a Twitter handle name. This + authority will therefore hold the right to add a Twitter handle name. This enables the verification of Twitter accounts for example by asking the user to tweet their pubkey or a signed message. A bot that holds the private issuing authority key can then sign the Create instruction (with a metadata_authority diff --git a/docs/src/shared-memory.md b/docs/src/shared-memory.md index e6a3cafd8b3..f1e5d485435 100644 --- a/docs/src/shared-memory.md +++ b/docs/src/shared-memory.md @@ -16,7 +16,7 @@ document are available at: ## Source The Shared memory Program's source is available on -[github](https://github.com/solana-labs/solana-program-library) +[GitHub](https://github.com/solana-labs/solana-program-library) ## Interface diff --git a/docs/src/single-pool.mdx b/docs/src/single-pool.mdx new file mode 100644 index 00000000000..357a025d296 --- /dev/null +++ b/docs/src/single-pool.mdx @@ -0,0 +1,485 @@ +--- +title: Single-Validator Stake Pool +--- + +```mdx-code-block +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +``` + +Trustless liquid staking for all Solana validators. + +| Information | Account Address | +| --- | --- | +| Single Pool Program | `SVSPxpvHdN29nkVg9rPapPNDddN5DipNLRUFhyjFThE` | + +## Overview + +The single-validator stake pool program is an SPL program that enables liquid staking with zero fees, no counterparty, and 100% capital efficiency. + +The program defines a canonical pool for every vote account, which can be initialized permissionlessly, and mints tokens in exchange for stake delegated to its designated validator. + +The program is a stripped-down adaptation of the existing multi-validator stake pool program, with approximately 80% less code, to minimize execution risk. + +## Source + +The Single Pool Program's source is available on +[GitHub](https://github.com/solana-program/single-pool). + +## Security Audits + +The Single Pool Program has received three audits to ensure total safety of funds: + +* Zellic (2024-01-02) + - Review commit hash [`ef44df9`](https://github.com/solana-labs/solana-program-library/commit/ef44df985e76a697ee9a8aabb3a223610e4cf1dc) + - Final report https://github.com/anza-xyz/security-audits/blob/master/spl/ZellicSinglePoolAudit-2024-01-02.pdf +* Neodyme (2023-08-08) + - Review commit hash [`735d729`](https://github.com/solana-labs/solana-program-library/commit/735d7292e35d35101750a4452d2647bdbf848e8b) + - Final report https://github.com/anza-xyz/security-audits/blob/master/spl/NeodymeSinglePoolAudit-2023-08-08.pdf +* Zellic (2023-06-21) + - Review commit hash [`9dbdc3b`](https://github.com/solana-labs/solana-program-library/commit/9dbdc3bdae31dda1dcb35346aab2d879deecf194) + - Final report https://github.com/anza-xyz/security-audits/blob/master/spl/ZellicSinglePoolAudit-2023-06-21.pdf + +## Interface + +The single-validator stake pool program is written in Rust and available on [crates.io](https://crates.io/crates/spl-single-pool) and [docs.rs](https://docs.rs/spl-single-pool). + +Javascript bindings are available for [Web3.js Classic](https://www.npmjs.com/package/@solana/spl-single-pool-classic) and [Web3.js Next](https://www.npmjs.com/package/@solana/spl-single-pool). + +## Reference Guide + +### Environment Setup + + + + +The easiest way to interact with the single pool program is using the `spl-single-pool` command-line program. +With [Rust installed](https://rustup.rs/), run: +```console +$ cargo install spl-single-pool-cli +``` + +Run `spl-single-pool --help` for a full description of available commands. + +### Configuration + +The `spl-single-pool` configuration is shared with the `solana` command-line tool. + +#### Current Configuration + +```console +$ solana config get +Config File: ${HOME}/.config/solana/cli/config.yml +RPC URL: https://api.mainnet-beta.solana.com +WebSocket URL: wss://api.mainnet-beta.solana.com/ (computed) +Keypair Path: ${HOME}/.config/solana/id.json +Commitment: confirmed +``` + +#### Cluster RPC URL + +See [Solana clusters](https://docs.solana.com/clusters) for cluster-specific RPC URLs +```console +$ solana config set --url https://api.devnet.solana.com +``` + +#### Default Keypair + +See [Keypair conventions](https://docs.solana.com/cli/conventions#keypair-conventions) +for information on how to setup a keypair if you don't already have one. + +Keypair File +```console +$ solana config set --keypair ${HOME}/new-keypair.json +``` + +Hardware Wallet URL (See [URL spec](https://docs.solana.com/wallet-guide/hardware-wallets#specify-a-keypair-url)) +```console +$ solana config set --keypair usb://ledger/ +``` + +`spl-single-pool` generally uses the default keypair as the fee-payer, +the wallet to draw funds from (for instance, to fund new stake accounts), +and the signing authority on accounts that require one. +When token accounts are required, it defaults to the default keypair's associated account. +All of these roles can be overridden by command-line flags. + + + + +#### pnpm +```console +$ pnpm install @solana/spl-single-pool-classic +``` +#### Yarn +```console +$ yarn add @solana/spl-single-pool-classic +``` +#### npm +```console +$ npm install @solana/spl-single-pool-classic +``` + +### Configuration +You can connect to different clusters using `Connection` in `@solana/web3.js` + +```typescript +import { Connection, clusterApiUrl } from '@solana/web3.js'; +const connection = new Connection(clusterApiUrl('devnet'), 'confirmed'); +``` + +### Keypair +You can either get your keypair using [`Keypair`](https://solana-labs.github.io/solana-web3.js/v1.x/classes/Keypair.html) from `@solana/web3.js`, or let the user's wallet handle the keypair and use `sendTransaction` from [`wallet-adapter`](https://github.com/solana-labs/wallet-adapter) + + + + +#### pnpm +```console +$ pnpm install @solana/spl-single-pool +``` +#### Yarn +```console +$ yarn add @solana/spl-single-pool +``` +#### npm +```console +$ npm install @solana/spl-single-pool +``` + +### Configuration +You can connect to different clusters using `createDefaultRpcTransport` and `createSolanaRpc` in `@solana/web3.js` + +```typescript +import { createDefaultRpcTransport, createSolanaRpc } from '@solana/web3.js'; +const transport = createDefaultRpcTransport({ url: 'https://api.devnet.solana.com' }); +const rpc = createSolanaRpc({ transport }); +``` + +### Keypair +Web3.js Next uses [`crypto.subtle`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/subtle) for key management. For local development, one can create an object `{ privateKey, publicKey }` using `crypto.subtle.importKey` to produce signing (private) and verifying (public) keys. Generally, however, one should allow the user wallet to manage keys, as the system when used properly is designed to not allow key material to leave secure storage. + + + + +### Setting up a single-validator pool + +#### Creating the pool + +A single-validator stake pool can be created permissionlessly, by anyone, for a +given vote account. This allows you to receive the full staking yield you would by +staking directly while holding the value in a tokenized form. +It also allows you to buy or sell stakes smaller than the minimum delegation on the market. + +Assuming a vote account `Ammgaa2iZfA745BmZMhkcS27uh87fEVDC6Gm2RXz5hrC` exists, we create a pool at address `DkE6XFGbqSyYzRugLVSmmB42F9BQZ7mZU837e2Cti7kb`: + + + + +```console +$ spl-single-pool manage initialize Ammgaa2iZfA745BmZMhkcS27uh87fEVDC6Gm2RXz5hrC +``` + + + + + +```typescript +const voteAccountAddress = new PublicKey('Ammgaa2iZfA745BmZMhkcS27uh87fEVDC6Gm2RXz5hrC'); +const transaction = await SinglePoolProgram.initialize( + connection, + voteAccountAddress, + feePayerAddress, +); + +// sign with the fee payer +``` + + + + + +```typescript +const voteAccountAddress = 'Ammgaa2iZfA745BmZMhkcS27uh87fEVDC6Gm2RXz5hrC' as VoteAccountAddress; +const transaction = await SinglePoolProgram.initialize( + rpc, + voteAccountAddress, + feePayerAddress, +); + +// sign with the fee payer +``` + + + + +#### Managing token metadata + +By default, when a pool is created, it also creates Metaplex token metadata for the mint associated with the pool. +If, for whatever reason, this was opted out of by the pool creator, anyone may create the default metadata permissionlessly: + + + + +```console +$ spl-single-pool manage create-token-metadata --pool DkE6XFGbqSyYzRugLVSmmB42F9BQZ7mZU837e2Cti7kb +``` + + + + + +```typescript +const transaction = await SinglePoolProgram.createTokenMetadata(poolAddress, feePayerAddress); + +// sign with the fee payer +``` + + + + + +```typescript +const transaction = await SinglePoolProgram.createTokenMetadata(poolAddress, feePayerAddress); + +// sign with the fee payer +``` + + + + +The default token metadata is only minimally helpful, spotlighting the address of the validator vote account. +The owner of the vote account, however, can change the metadata to anything they wish. +They prove their identity by signing with the vote account's authorized withdrawer; +this is the only permissioned instruction on the pool. + + + + +```console +$ spl-single-pool manage update-token-metadata DkE6XFGbqSyYzRugLVSmmB42F9BQZ7mZU837e2Cti7kb "My Cool Pool" cPool "https://www.cool.pool/token.jpg" +``` + + + + + +```typescript +const transaction = await SinglePoolProgram.updateTokenMetadata( + voteAccountAddress, + authorizedWithdrawerAddress, + 'My Cool Pool', + 'cPool', + 'https://www.cool.pool/token.jpg', +); + +// sign with the fee payer and authorized withdrawer +``` + + + + + +```typescript +const transaction = await SinglePoolProgram.updateTokenMetadata( + voteAccountAddress, + authorizedWithdrawerAddress, + 'My Cool Pool', + 'cPool', + 'https://www.cool.pool/token.jpg', +); + +// sign with the fee payer and authorized withdrawer +``` + + + + +The URL parameter is optional. + +### Using a single-validator pool + +#### Depositing + +When a pool is created, its stake account is delegated to the appropriate vote account, and for that epoch, stake in an "activating" state can be deposited into it. +After this epoch, stake must be in an "active" state to deposit into the pool. +That is, it must be delegated to the vote account, and a deposit can only be performed after the next epoch boundary. + +Assuming the stake account `9cc4cmLcZA89fYmcVPPTLmHPQ5gab3R6jMqj124abkSi` is in an active state: + + + + +```console +$ spl-single-pool deposit 9cc4cmLcZA89fYmcVPPTLmHPQ5gab3R6jMqj124abkSi +``` + +When an explicit stake account address is provided, the CLI can determine the pool address automatically. + + + + + +```typescript +const transaction = await SinglePoolProgram.deposit({ + connection, + pool: poolAddress, + userWallet, + userStakeAccount, +}); + +// sign with the fee payer and stake account withdraw authority, if these signers differ +// userWallet is a convenience parameter to use one account as a payer, authority, and lamport recipient +``` + + + + + +```typescript +const transaction = await SinglePoolProgram.deposit({ + rpc, + pool: poolAddress, + userWallet, + userStakeAccount, +}); + +// sign with the fee payer and stake account withdraw authority, if these signers differ +// userWallet is a convenience parameter to use one account as a payer, authority, and lamport recipient +``` + + + + +All versions of the `deposit` command/transaction automatically create the associated token account for the pool token if it doesn't exist and no auxiliary token account address is provided. + +The program also makes available a convenience address for each pool, called the default deposit address. +This allows a flow where you create and delegate a stake at a program-derived address, and then can deposit this stake after the epoch boundary, without having to generate or keep track of any new keypairs. +The user retains full authority on the stake account until they decide to deposit. + + + + +```console +$ spl-single-pool create-default-stake --pool DkE6XFGbqSyYzRugLVSmmB42F9BQZ7mZU837e2Cti7kb 1000000000 +``` + +Once the stake becomes active, typically in the next epoch: + +```console +$ spl-single-pool deposit --pool DkE6XFGbqSyYzRugLVSmmB42F9BQZ7mZU837e2Cti7kb --default-stake-account +``` + + + + + +```typescript +const transaction = await SinglePoolProgram.createAndDelegateUserStake( + connection, + voteAccountAddress, + userWallet, + 1000000000, +); + +// sign with user wallet +``` + +Once the stake becomes active, typically in the next epoch: + +```typescript +const transaction = await SinglePoolProgram.deposit({ + connection, + pool: poolAddress, + userWallet, + depositFromDefaultAccount: true, +}); + +// sign with user wallet +``` + + + + + +```typescript +const transaction = await SinglePoolProgram.createAndDelegateUserStake( + rpc, + voteAccountAddress, + userWallet, + 1000000000n, +); + +// sign with user wallet, which is used as the fee payer and as the base address for a seeded account +``` + +Once the stake becomes active, typically in the next epoch: + +```typescript +const transaction = await SinglePoolProgram.deposit({ + rpc, + pool: poolAddress, + userWallet, + depositFromDefaultAccount: true, +}); + +// sign with user wallet, which is used as the fee payer and as the base address for a seeded account +``` + + + + +#### Withdrawing + +Withdrawing is simple, burning tokens to receive the amount of stake they're backed by. +Stake can be withdrawn into an active stake account delegated to the appropriate vote account, or to a new stake account, with all authority assigned to the user wallet. +Internally, all versions of the `withdraw` command/transaction use a token delegate to accomplish the burn. +This means the user does not have to provide a wallet signature to the single pool program. + + + + +```console +$ spl-single-pool withdraw --pool DkE6XFGbqSyYzRugLVSmmB42F9BQZ7mZU837e2Cti7kb 1000000000 +``` + +The `--deactivate` flag may also be passed, as a convenience to start the undelegation process. + + + + + +```typescript +const withdrawAccount = new Keypair(); +const transaction = await SinglePoolProgram.withdraw({ + connection, + pool: poolAddress, + userWallet, + userStakeAccount: withdrawAccount.publicKey, + tokenAmount: 1000000000, + createStakeAccount: true, +}); + +// sign with fee payer, and the stake account keypair if a new account is being created +``` + + + + + +```typescript +const { publicKey, privateKey } = await generateKeyPair(); +const transaction = await SinglePoolProgram.withdraw({ + rpc, + pool: poolAddress, + userWallet, + userStakeAccount: publicKey, + tokenAmount: 1000000000n, + createStakeAccount: true, +}); + +// sign with fee payer, and the stake account keypair if a new account is being created +``` + + + diff --git a/docs/src/stake-pool.md b/docs/src/stake-pool.md index 3fc09ca1314..637b32c33e8 100644 --- a/docs/src/stake-pool.md +++ b/docs/src/stake-pool.md @@ -10,6 +10,10 @@ to maximize censorship resistance and rewards. | --- | --- | | Stake Pool Program | `SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy` | +NOTE: The devnet deployment of the program still uses v0.6.4, and is not suitable +for testing. For testing, it is recommended to use testnet, a local test validator, +or deploy your own version for devnet. + ## Getting Started To get started with stake pools: @@ -23,10 +27,10 @@ To get started with stake pools: ## Source The Stake Pool Program's source is available on -[GitHub](https://github.com/solana-labs/solana-program-library/tree/master/stake-pool). +[GitHub](https://github.com/solana-program/stake-pool). For information about the types and instructions, the Stake Pool Rust docs are -available at [docs.rs](https://docs.rs/spl-stake-pool/0.6.3/spl_stake_pool/). +available at [docs.rs](https://docs.rs/spl-stake-pool/latest/spl_stake_pool/index.html). ## Security Audits @@ -37,10 +41,28 @@ chronological order, and the commit hash that each was reviewed at: * Quantstamp - Initial review commit hash [`99914c9`](https://github.com/solana-labs/solana-program-library/tree/99914c9fc7246b22ef04416586ab1722c89576de) - Re-review commit hash [`3b48fa0`](https://github.com/solana-labs/solana-program-library/tree/3b48fa09d38d1b66ffb4fef186b606f1bc4fdb31) - - Final report https://solana.com/SolanaQuantstampStakePoolAudit.pdf + - Final report https://github.com/anza-xyz/security-audits/blob/master/spl/QuantstampStakePoolAudit-2021-10-22.pdf * Neodyme - Review commit hash [`0a85a9a`](https://github.com/solana-labs/solana-program-library/tree/0a85a9a533795b6338ea144e433893c6c0056210) - - Report https://solana.com/SolanaNeodymeStakePoolAudit.pdf + - Report https://github.com/anza-xyz/security-audits/blob/master/spl/NeodymeStakePoolAudit-2021-10-16.pdf * Kudelski - Review commit hash [`3dd6767`](https://github.com/solana-labs/solana-program-library/tree/3dd67672974f92d3b648bb50ee74f4747a5f8973) - - Report https://solana.com/SolanaKudelskiStakePoolAudit.pdf + - Report https://github.com/anza-xyz/security-audits/blob/master/spl/KudelskiStakePoolAudit-2021-07-07.pdf +* Neodyme Second Audit + - Review commit hash [`fd92ccf`](https://github.com/solana-labs/solana-program-library/tree/fd92ccf9e9308508b719d6e5f36474f57023b0b2) + - Report https://github.com/anza-xyz/security-audits/blob/master/spl/NeodymeStakePoolAudit-2022-12-10.pdf +* OtterSec + - Review commit hash [`eba709b`](https://github.com/solana-labs/solana-program-library/tree/eba709b9317f8c7b8b197045161cb744241f0bff) + - Report https://github.com/anza-xyz/security-audits/blob/master/spl/OtterSecStakePoolAudit-2023-01-20.pdf +* Neodyme Third Audit + - Review commit hash [`b341022`](https://github.com/solana-labs/solana-program-library/tree/b34102211f2a5ea6b83f3ee22f045fb115d87813) + - Report https://github.com/anza-xyz/security-audits/blob/master/spl/NeodymeStakePoolAudit-2023-01-31.pdf +* Halborn + - Review commit hash [`eba709b`](https://github.com/solana-labs/solana-program-library/tree/eba709b9317f8c7b8b197045161cb744241f0bff) + - Report https://github.com/anza-xyz/security-audits/blob/master/spl/HalbornStakePoolAudit-2023-01-25.pdf +* Neodyme Fourth Audit + - Review commit hash [`6ed7254`](https://github.com/solana-labs/solana-program-library/tree/6ed7254d1a578ffbc2b091d28cb92b25e7cc511d) + - Report https://github.com/anza-xyz/security-audits/blob/master/spl/NeodymeStakePoolAudit-2023-11-14.pdf +* Halborn Second Audit + - Review commit hash [`a17fffe`](https://github.com/solana-labs/solana-program-library/tree/a17fffe70d6cc13742abfbc4a4a375b087580bc1) + - Report https://github.com/anza-xyz/security-audits/blob/master/spl/HalbornStakePoolAudit-2023-12-31.pdf diff --git a/docs/src/stake-pool/cli.md b/docs/src/stake-pool/cli.md index 3ce9f9e4d87..f9cdef997c8 100644 --- a/docs/src/stake-pool/cli.md +++ b/docs/src/stake-pool/cli.md @@ -169,18 +169,20 @@ Signature: 5yPXfVj5cbKBfZiEVi2UR5bXzVDuc2c3ruBwSjkAqpvxPHigwGHiS1mXQVE4qwok5moMW ``` In order to protect stake pool depositors from malicious managers, the program -applies the new fee for the following epoch. +applies the new fee after crossing two epoch boundaries, giving a minimum wait +time of one full epoch. For example, if the fee is 1% at epoch 100, and the manager sets it to 10%, the -manager will still gain 1% for the rewards earned during epoch 100. Starting -with epoch 101, the manager will earn 10%. +manager will still gain 1% for the rewards earned during epochs 100 and 101. Starting +with epoch 102, the manager will earn 10%. Additionally, to prevent a malicious manager from immediately setting the withdrawal fee to a very high amount, making it practically impossible for users to withdraw, -the stake pool program currently enforces a limit of 1.5x increase per epoch. +the stake pool program currently enforces a limit of 1.5x increase every two +epoch boundaries. -For example, if the current withdrawal fee is 2.5%, the maximum that can be set -for the next epoch is 3.75%. +For example, if the current withdrawal fee is 2.5%, the maximum settable fee is +3.75%, and will take effect after two epoch boundaries. The possible options for the fee type are `epoch`, `sol-withdrawal`, `stake-withdrawal`, `sol-deposit`, and `stake-deposit`. @@ -261,7 +263,11 @@ In order to accommodate large numbers of user deposits into the stake pool, the stake pool only manages one stake account per validator. To add a new validator to the stake pool, the staker must use the `add-validator` command. -Let's add some random validators to the stake pool. +The SOL used to add validators to the pool comes from the stake pool's reserve +account. If there is insufficient SOL in the reserve, the command will fail. +Be sure to use the `deposit-sol` command to move some SOL into the pool. + +With 10 SOL in the pool, let's add some random validators to the stake pool. ```console $ spl-stake-pool add-validator Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk @@ -285,18 +291,18 @@ We can see the status of a stake account using the Solana command-line utility. ```console $ solana stake-account 5AaobwjccyHnXhFCd24uiX6VqPjXE3Ry4o92fJjqqjAr -Balance: 0.00328288 SOL +Balance: 1.00228288 SOL Rent Exempt Reserve: 0.00228288 SOL -Delegated Stake: 0.001 SOL +Delegated Stake: 1 SOL Active Stake: 0 SOL -Activating Stake: 0.001 SOL +Activating Stake: 1 SOL Stake activates starting from epoch: 5 Delegated Vote Account Address: J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H Stake Authority: DS3AyFN9dF1ruNBcSeo8XXQR8UyVMhcCPcnjU5GnY18S Withdraw Authority: DS3AyFN9dF1ruNBcSeo8XXQR8UyVMhcCPcnjU5GnY18S ``` -The stake pool creates these special staking accounts with 0.001 SOL as the required +The stake pool creates these special staking accounts with 1 SOL as the required minimum delegation amount. The stake and withdraw authorities are the stake pool withdraw authority, program addresses derived from the stake pool's address. @@ -312,21 +318,20 @@ Stake Deposit Fee: none SOL Deposit Fee: none SOL Deposit Referral Fee: none Stake Deposit Referral Fee: none -Reserve Account: EN4px2h4gFkYtsQUi4yeCYBrdRM4DoRxCVJyavMXEAm5 Available Balance: ◎0.000000000 -Vote Account: EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ Balance: ◎0.000000000 Last Update Epoch: 4 -Vote Account: J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H Balance: ◎0.000000000 Last Update Epoch: 4 -Vote Account: 38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk Balance: ◎0.000000000 Last Update Epoch: 4 -Total Pool Stake: ◎0.000000000 -Total Pool Tokens: 0.00000000 +Reserve Account: EN4px2h4gFkYtsQUi4yeCYBrdRM4DoRxCVJyavMXEAm5 Available Balance: ◎6.99315136 +Vote Account: EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ Balance: ◎1.002282880 Last Update Epoch: 4 +Vote Account: J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H Balance: ◎1.002282880 Last Update Epoch: 4 +Vote Account: 38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk Balance: ◎1.002282880 Last Update Epoch: 4 +Total Pool Stake: ◎10.000000000 +Total Pool Tokens: 10.00000000 Current Number of Validators: 3 Max Number of Validators: 1000 ``` To make reading easier, the tool will not show balances that cannot be touched by -the stake pool. The stake account `5AaobwjccyHnXhFCd24uiX6VqPjXE3Ry4o92fJjqqjAr`, -delegated to `J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H`, actually has a balance -of 0.00328288 SOL, but since this is the minimum required amount, it is -not shown by the CLI. +the stake pool. The reserve stake account `EN4px2h4gFkYtsQUi4yeCYBrdRM4DoRxCVJyavMXEAm5` +actually has an additional balance of 0.002282881 SOL, but since this is the minimum +required amount, it is not shown by the CLI. ### Remove validator stake account @@ -334,7 +339,7 @@ If the stake pool staker wants to stop delegating to a vote account, they can totally remove the validator stake account from the stake pool. As with adding a validator, the validator stake account must have exactly -0.00328288 SOL (0.001 SOL delegated, 0.00228288 SOL for rent exemption) to be removed. +1.00228288 SOL (1 SOL delegated, 0.00228288 SOL for rent exemption) to be removed. If that is not the case, the staker must first decrease the stake to that minimum amount. Let's assume that the validator stake account delegated to @@ -356,29 +361,18 @@ Creating account to receive stake nHEEyey8KkgHuVRAUDzkH5Q4PkA4veSHuTxgG6C8L2G Signature: 4XprnR768Ch6LUvqUVLTjMCiqdYvtjNfECh4izErqwbsASTGjUBz7NtLZHAiraTqhs7b9PoSAazetdsgXa6J4wVu ``` -Unlike a normal withdrawal, the validator stake account is totally moved from -the stake pool and into a new account belonging to the administrator. - -Note: since removal is only possible when the validator stake is at the minimum -amount of 0.00328288, the administrator does not get any control of user funds, -and only recovers the amount contributed during `add-validator`. - -The authority for the withdrawn stake account can also be specified using the -`--new-authority` flag: - -```console -$ spl-stake-pool remove-validator Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H --new-authority 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn -Signature: 5rrQ3xhDWyiPkUTAQkNAeq31n6sMf1xsg2x9hVY8Vj1NonwBnhxuTv87nADLkwC8Xzc4CGTNCTX2Vph9esWnXk2d -``` +Unlike a normal withdrawal, the validator stake account is deactivated, and then +merged into the reserve during the next epoch. -We can check the removed stake account: +We can check the deactivating stake account: ```console $ solana stake-account nHEEyey8KkgHuVRAUDzkH5Q4PkA4veSHuTxgG6C8L2G -Balance: 0.003282880 SOL -Rent Exempt Reserve: 0.00328288 SOL -Delegated Stake: 0.001000000 SOL -Active Stake: 0.001000000 SOL +Balance: 1.002282880 SOL +Rent Exempt Reserve: 0.00228288 SOL +Delegated Stake: 1.000000000 SOL +Active Stake: 1.000000000 SOL +Stake deactivates starting from epoch: 10 Delegated Vote Account Address: J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H Stake Authority: 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn Withdraw Authority: 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn @@ -812,7 +806,7 @@ be able to withdraw their funds. To get around this case, it is also possible to withdraw from the stake pool's reserve, but only if all of the validator stake accounts are at the minimum amount of -`0.001 SOL + stake account rent exemption`. +`1 SOL + stake account rent exemption`. ```console $ spl-stake-pool withdraw-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 5 --use-reserve @@ -820,3 +814,20 @@ Withdrawing ◎5.000000000, or 5 pool tokens, from stake account J5XB7mWpeaUZxZ6 Creating account to receive stake 51XdXiBSsVzeuY79xJwWAGZgeKzzgFKWajkwvWyrRiNE Signature: yQH9n7Go6iCMEYXqWef38ZYBPwXDmbwKAJFJ4EHD6TusBpusKsfNuT3TV9TL8FmxR2N9ExZTZwbD9Njc3rMvUcf ``` + +#### Special case: removing validator from the pool + +Since the funds used to add validators to the pool come from outside deposits, +it's possible for a delinquent or malicious staker to make it impossible for +users to reclaim their SOL by keeping everything at the minimum amount. + +To get around this case, it is also possible to remove a validator from the stake pool +but only if all of the validator stake accounts are at the minimum amount of +`1 SOL + stake account rent exemption`. + +```console +$ spl-stake-pool withdraw-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 1.00228288 SOL +Withdrawing ◎1.00228288 or 1.00228288 pool tokens, from stake account J5XB7mWpeaUZxZ6ogXT57qSCobczx27vLZYSgfSbZoBB +Creating account to receive stake 51XdXiBSsVzeuY79xJwWAGZgeKzzgFKWajkwvWyrRiNE +Signature: yQH9n7Go6iCMEYXqWef38ZYBPwXDmbwKAJFJ4EHD6TusBpusKsfNuT3TV9TL8FmxR2N9ExZTZwbD9Njc3rMvUcf +``` diff --git a/docs/src/stake-pool/fees.md b/docs/src/stake-pool/fees.md index bb5c3abeca2..2ab84660a29 100644 --- a/docs/src/stake-pool/fees.md +++ b/docs/src/stake-pool/fees.md @@ -22,6 +22,10 @@ and the stake pool charges 2%, and a stake in the pool earns 100 SOL pre-commiss then that stake will actually enrich the pool by 90.16 SOL. The total rewards on that validator will be reduced by ~9.84%. +When the epoch fee is updated, the change only takes effect after two epoch +boundaries. For example, if you update the epoch fee during epoch 100, the new +fee will only be used starting in epoch 102. + ### SOL Withdraw Fee Sends a proportion of the desired withdrawal amount to the manager. @@ -30,6 +34,14 @@ For example, if a user wishes to withdraw 100 pool tokens, and the fee is set to 3%, 3 pool tokens go to the manager, and the remaining 97 tokens are converted to SOL and sent to the user. +When the SOL withdrawal fee is updated, the change only takes effect after two +epoch boundaries. For example, if you update the fee during epoch 100, the +new fee will only be used starting in epoch 102. + +Also, the fee increase is limited to 1.5x the current fee. For example, if the +current fee is 2.5%, the maximum settable fee is 3.75%, which will take effect +after two epoch boundaries. + ### Stake Withdraw Fee Sends a proportion of the desired withdrawal amount to the manager before @@ -39,6 +51,14 @@ For example, if a user wishes to withdraw 100 pool tokens, and the fee is set to 0.5%, 0.5 pool tokens go to the manager, and the remaining 99.5 tokens are converted to SOL then sent to the user as an activated stake account. +When the stake withdrawal fee is updated, the change only takes effect after two +epoch boundaries. For example, if you update the fee during epoch 100, the new +fee will only be used starting in epoch 102. + +Also, the fee increase is limited to 1.5x the current fee. For example, if the +current fee is 2.5%, the maximum settable fee is 3.75%, which will take effect +after two epoch boundaries. + ### SOL Deposit Fee Converts the entire SOL deposit into pool tokens, then sends a proportion of diff --git a/docs/src/stake-pool/overview.md b/docs/src/stake-pool/overview.md index 3d28f573d0b..5fd9fcdcdf3 100644 --- a/docs/src/stake-pool/overview.md +++ b/docs/src/stake-pool/overview.md @@ -31,8 +31,8 @@ document are available at: This document is intended for the main actors of the stake pool system: * manager: creates and manages the stake pool, earns fees, can update the fee, staker, and manager -* staker: adds and removes validators to the pool, rebalances stake among validators -* user: provides staked SOL into an existing stake pool +* staker: adds and removes validators to the pool, rebalances stake among validators, can update the staker +* user: provides liquid or staked SOL into an existing stake pool In its current iteration, the stake pool accepts active stakes or SOL, so deposits may come from either an active stake or SOL wallet. Withdrawals @@ -56,18 +56,17 @@ providers for direct SOL deposits. ## Operation -A stake pool manager creates a stake pool, and the staker includes validators that will -receive delegations from the pool by adding "validator stake accounts" to the pool -using the `add-validator` instruction. In this command, the stake pool creates -a new stake account and delegates it to the desired validator. +A stake pool manager creates a stake pool. At this point, users can immediately +participate with SOL deposits with the `deposit-sol` instruction, moving funds +into the reserve in exchange for pool tokens. -At this point, users can participate with deposits. They can directly deposit -SOL into the stake pool using the `deposit-sol` instruction. Within this instruction, -the stake pool will move SOL into the pool's reserve account, to be redistributed -by the staker. +Using those SOL deposits, the staker includes validators that will receive +delegations from the pool by adding "validator stake accounts" to the pool +using the `add-validator` instruction. In this command, the stake pool uses +reserve funds to create a new stake account and delegate it to the desired validator. -Alternatively, users can deposit a stake account into the pool. To do this, -they must delegate a stake account to the one of the validators in the stake pool. +At this point, users can also deposit a stake account into the pool. To do this, +they must delegate a stake account to one of the validators in the stake pool. If the stake pool has a preferred deposit validator, the user must delegate their stake to that validator's vote account. @@ -101,10 +100,8 @@ The stake pool staker can add and remove validators, or rebalance the pool by decreasing the stake on a validator, waiting an epoch to move it into the stake pool's reserve account, then increasing the stake on another validator. -The staker operation to add a new validator requires 0.00328288 SOL to create -the stake account on a validator, so the stake pool staker will need liquidity -on hand to fully manage the pool stakes. The SOL used to add a new validator -is recovered when removing the validator. +The staker operation to add a new validator requires 1.00228288 SOL to create +the stake account on a validator, so the stake pool reserve needs liquidity. ### Funding restrictions @@ -153,6 +150,7 @@ When processing withdrawals, the order of priority goes: * validator stake accounts * transient stake accounts * reserve stake account +* removing validator stake accounts entirely If there is preferred withdraw validator, and that validator stake account has any SOL, a user must withdraw from that account. @@ -165,7 +163,7 @@ staker decreases the stake on all validators at once, then the user must withdra from any transient stake account. If all transient stake accounts are empty, then the user must withdraw from the -reserve. +reserve or completely remove a validator stake account. In this way, a user's funds are never at risk, and always redeemable. @@ -174,7 +172,7 @@ In this way, a user's funds are never at risk, and always redeemable. ### Active stakes As mentioned earlier, the stake pool works with active stakes to -maintains fungibility of stake pool tokens. Fully activated stakes +maintain fungibility of stake pool tokens. Fully activated stakes are not equivalent to inactive, activating, or deactivating stakes due to the time cost of staking. diff --git a/docs/src/stake-pool/quickstart.md b/docs/src/stake-pool/quickstart.md index 3a6bc34fe1c..5fe89d45aa5 100644 --- a/docs/src/stake-pool/quickstart.md +++ b/docs/src/stake-pool/quickstart.md @@ -117,13 +117,13 @@ Carefully read through the [Fees](fees.md) for more information about fees and best practices. In our example, we will use fees of 0.3%, a referral fee of 50%, opt to *not* -set a deposit authority, and have the maximum number of validators (2,950). Next, -run the script: +set a deposit authority, and have the maximum number of validators (2,350). Next, +run the script with the amount of SOL to deposit. We'll use 15 SOL: ```bash -$ ./setup-stake-pool.sh +$ ./setup-stake-pool.sh 15 Creating pool -+ spl-stake-pool create-pool --epoch-fee-numerator 3 --epoch-fee-denominator 1000 --withdrawal-fee-numerator 3 --withdrawal-fee-denominator 1000 --deposit-fee-numerator 3 --deposit-fee-denominator 1000 --referral-fee 50 --max-validators 2950 --pool-keypair keys/stake-pool.json --validator-list-keypair keys/validator-list.json --mint-keypair keys/mint.json --reserve-keypair keys/reserve.json ++ spl-stake-pool create-pool --epoch-fee-numerator 3 --epoch-fee-denominator 1000 --withdrawal-fee-numerator 3 --withdrawal-fee-denominator 1000 --deposit-fee-numerator 3 --deposit-fee-denominator 1000 --referral-fee 50 --max-validators 2350 --pool-keypair keys/stake-pool.json --validator-list-keypair keys/validator-list.json --mint-keypair keys/mint.json --reserve-keypair keys/reserve.json Creating reserve stake 4tvTkLB4X7ahUYZ2NaTohkG3mud4UBBvu9ZEGD4Wk9mt Creating mint BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB Creating associated token account DgyZrAq88bnG1TNRxpgDQzWXpzEurCvfY2ukKFWBvADQ to receive stake pool tokens of mint BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB, owned by 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn @@ -131,14 +131,36 @@ Creating pool fee collection account DgyZrAq88bnG1TNRxpgDQzWXpzEurCvfY2ukKFWBvAD Signature: 51yf2J6dSGAx42KPs2oTMTV4ufEm1ncAHyLPQ6PNf4sbeMHGqno7BGn2tHkUnrd7PRXiWBbGzCWpJNevYjmoLgn2 Creating stake pool Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR with validator list 86VZZCuqiz7sDJpFKjQy9c9dZQN9vwDKbYgY8pcwHuaF Signature: 47QHcWMEa5Syg13C3SQRA4n88Y8iLx1f39wJXQAStRUxpt2VD5t6pYgAdruNRHUQt1ZBY8QwbvEC1LX9j3nPrAzn +Depositing SOL into stake pool +Update not required +Using existing associated token account DgyZrAq88bnG1TNRxpgDQzWXpzEurCvfY2ukKFWBvADQ to receive stake pool tokens of mint BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB, owned by 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn +Signature: 4jnS368HcofZ1rUpsGZtmSK9kVxFzJRndSX5VS7eMV3kVgzyg9efA4mcgd2C6BoSNksTmTonRGXTVM1WMywFpiKq ``` Your stake pool now exists! For the largest number of validators, the cost for -this phase is ~2.02 SOL. +this phase is ~2.02 SOL, plus 15 SOL deposited into the pool in exchange for +pool tokens. + +## Step 2: Deposit SOL into the pool + +Now that the pool exists, let's deposit some SOL in exchange for some pool tokens. + +SOL will likely be the most attractive form of deposit, since it's the easiest +for everyone to use. Normally, this will likely be done from a DeFi app or +wallet, but in our example, we'll do it straight from the command line. + +We already deposited 15 SOL during creation of the pool, but let's deposit +another 10 SOL into the pool: + +``` +$ spl-stake-pool deposit-sol Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 10 +Using existing associated token account DgyZrAq88bnG1TNRxpgDQzWXpzEurCvfY2ukKFWBvADQ to receive stake pool tokens of mint BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB, owned by 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn +Signature: 4AJv6hSznYoMGnaQvjWXSBjKqtjYpjBx2MLezmRRjWRDa8vUaBLQfPNGd3kamZNs1JeWSvnzczwtzsMD5WkgKamA +``` -## Step 2: Add validators to the pool +## Step 3: Add validators to the pool -Now that the pool exists, we need to add validators to it. +Now that the pool has some SOL, we need to add validators to it. Using `add-validators.sh`, we'll add each of the validators created during step 0 to the stake pool. If you are running on another network, you can create your own @@ -153,34 +175,17 @@ Signature: 3XtmYu9msqnMeKJs9BopYjn5QTc5hENMXXiBwvEw6HYzU5w6z1HUkGwNW24io4Vu9WRKF ... (something similar repeated 9 more times) ``` -This operation costs 0.00328288 SOL per validator. This amount is totally recoverable -by removing the validator from the stake pool. +This operation moves 1.00228288 SOL from the reserve to a stake account on a given +validator. This means you'll need over 1 SOL for each validator that you want to add. -## Step 3: Deposit into the pool +## Step 4: Deposit stakes into the pool -Now that your pool has validators, it needs some SOL or stake accounts for you +Now that your pool has validators, it can accept stake accounts for you to manage. There are two possible sources of deposits: SOL or stake accounts. +In step 2, we deposited SOL directly, so now we'll deposit stake accounts. -### a) Depositing SOL - -This will likely be the most attractive form of deposit, since it's the easiest -for everyone to use. Normally, this will likely be done from a DeFi app or -wallet, but in our example, we'll do it straight from the command line. Let's -deposit 10 SOL into our pool: - -``` -$ spl-stake-pool deposit-sol Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 100 -Using existing associated token account DgyZrAq88bnG1TNRxpgDQzWXpzEurCvfY2ukKFWBvADQ to receive stake pool tokens of mint BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB, owned by 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn -Signature: 4AJv6hSznYoMGnaQvjWXSBjKqtjYpjBx2MLezmRRjWRDa8vUaBLQfPNGd3kamZNs1JeWSvnzczwtzsMD5WkgKamA -``` - -Now there will be some SOL for us to work with. - -### b) Depositing stake accounts - -Alternatively, users can deposit stake accounts into the pool. This option is -particularly attractive for users that already have a stake account, and either -want stake pool tokens in return, or to diversify their stake more. +This option is particularly attractive for users that already have a stake +account, and either want stake pool tokens in return, or to diversify their stake more. The `deposit.sh` script gives an idea of how this works with the CLI. @@ -191,10 +196,10 @@ the pool, given the stake pool and validator file. $ ./deposit.sh keys/stake-pool.json local_validators.txt 10 ``` -Note: This is a bit more finnicky on a local network because of the short epochs, and +Note: This is a bit more finicky on a local network because of the short epochs, and may fail. No problem, you simply need to retry. -## Step 4: Rebalance stake in the pool +## Step 5: Rebalance stake in the pool Over time, as people deposit SOL into the reserve, or as validator performance varies, you will want to move stake around. The best way to do this will be @@ -202,7 +207,7 @@ through an automated system to collect information about the stake pool and the network, and decide how much stake to allocate to each validator. The Solana Foundation maintains an open-source bot for its delegation program, -which can be adapated for your stake pool. The source code is part of the +which can be adapted for your stake pool. The source code is part of the [stake-o-matic GitHub repo](https://github.com/solana-labs/stake-o-matic/tree/master/bot). Additionally, there is a work-in-progress Python stake pool bot, found at the @@ -216,7 +221,7 @@ to make sure that this is valid. $ ./rebalance.sh keys/stake-pool.json local_validators.txt 1 ``` -## Step 5: Withdraw from the stake pool +## Step 6: Withdraw from the stake pool Finally, if a user wants to withdraw from the stake pool, they can choose to withdraw SOL from the reserve if it has enough SOL, or to withdraw from one of diff --git a/docs/src/theme/SearchBar/algolia.css b/docs/src/theme/SearchBar/algolia.css index 7bc622647dd..02946a9045c 100644 --- a/docs/src/theme/SearchBar/algolia.css +++ b/docs/src/theme/SearchBar/algolia.css @@ -17,7 +17,7 @@ .algolia-docsearch-suggestion--highlight { color: #3a33d1; } -/* Highligted search terms in the main category headers */ +/* Highlighted search terms in the main category headers */ .algolia-docsearch-suggestion--category-header .algolia-docsearch-suggestion--highlight { background-color: #4d47d5; diff --git a/docs/src/theme/SearchBar/index.js b/docs/src/theme/SearchBar/index.js index 76c43025929..8c5c8601184 100644 --- a/docs/src/theme/SearchBar/index.js +++ b/docs/src/theme/SearchBar/index.js @@ -6,7 +6,7 @@ */ import React, { useRef, useCallback } from "react"; -import classnames from "classnames"; +import { clsx } from "clsx"; import { useHistory } from "@docusaurus/router"; import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; const Search = props => { @@ -76,7 +76,7 @@ const Search = props => { { type="search" placeholder="Search" aria-label="Search" - className={classnames( + className={clsx( "navbar__search-input", { "search-bar-expanded": props.isSearchBarExpanded }, { "search-bar": !props.isSearchBarExpanded } diff --git a/docs/src/token-2022.md b/docs/src/token-2022.md index 76ce14ef848..c4aa63f2055 100644 --- a/docs/src/token-2022.md +++ b/docs/src/token-2022.md @@ -5,8 +5,8 @@ title: Token-2022 Program A token program on the Solana blockchain, defining a common implementation for fungible and non-fungible tokens. -The Token-2022 Program is a superset of the functionality provided by the -[Token Program](token.mdx), deployed to all networks. +The Token-2022 Program, also known as Token Extensions, is a superset of the +functionality provided by the [Token Program](token.mdx). | Information | Account Address | | --- | --- | @@ -43,13 +43,14 @@ Token-2022 are a strict superset of Token. ### Instructions Token-2022 supports the exact same instruction layouts as Token, byte for -byte. For example, if you want to transfer 100 tokens on a mint with 2 decimals, -you create a `TransferChecked` instruction, with this byte-representated data: +byte. For example, if you want to transfer 0.75 tokens in UI amount, on a mint with 2 decimals, +then the transfer amount is 75 tokens. You create a `TransferChecked` instruction, with +this byte-represented data: ``` -[12, 100, 0, 0, 0, 0, 0, 0, 0, 2] +[12, 75, 0, 0, 0, 0, 0, 0, 0, 2] ^^ TransferChecked enum - ^^^^^^^^^^^^^^^^^^^^^^^^ 100, as a little-endian 64-bit unsigned integer + ^^^^^^^^^^^^^^^^^^^^^^^^ 75, as a little-endian 64-bit unsigned integer ^ 2, as a byte ``` @@ -81,7 +82,7 @@ is written after the end of the `Account` in Token, which is the byte at index `165`. This means it is always possible to differentiate mints and accounts. You can read more about how this is done at the -[source code](https://github.com/solana-labs/solana-program-library/blob/master/token/program-2022/src/extension/mod.rs). +[source code](https://github.com/solana-program/token-2022/blob/main/program/src/extension/mod.rs). Mint extensions currently include: @@ -89,11 +90,18 @@ Mint extensions currently include: * transfer fees * closing mint * interest-bearing tokens +* non-transferable tokens +* permanent delegate +* transfer hook +* metadata pointer +* metadata Account extensions currently include: * memo required on incoming transfers * immutable ownership +* default account state +* CPI guard Extensions can be mixed and matched, which means it's possible to create a mint with only transfer fees, only interest-bearing tokens, both, or neither! @@ -108,9 +116,11 @@ program, that creates new token accounts for either Token or Token-2022. To get started with Token-2022: - [Install the Solana Tools](https://docs.solana.com/cli/install-solana-cli-tools) -- [Extension Guide](token-2022/extensions.md) +- [Project Status](token-2022/status.md) +- [Extension Guide](token-2022/extensions.mdx) - [Wallet Guide](token-2022/wallet.md) - [On-Chain Program Guide](token-2022/onchain.md) +- [Presentation about Token-2022](token-2022/presentation.md) For existing functionality in the Token Program, see the [token docs](token.mdx). The Token functionality will always apply to Token-2022. @@ -118,12 +128,33 @@ The Token functionality will always apply to Token-2022. ## Source The Token-2022 Program's source is available on -[GitHub](https://github.com/solana-labs/solana-program-library/tree/master/token/program-2022). +[GitHub](https://github.com/solana-program/token-2022). For information about the types and instructions, the Rust docs are available at [docs.rs](https://docs.rs/spl-token-2022/latest/spl_token_2022/). ## Security Audits -The Token-2022 Program is currently under multiple audits to ensure safety of -funds. All audits will be published here as they are completed. +The Token-2022 Program has been audited multiple times. All audits are published +here as they are completed. + +Here are the completed audits as of 13 December 2023: + +* Halborn + - Review commit hash [`c3137a`](https://github.com/solana-labs/solana-program-library/tree/c3137af9dfa2cc0873cc84c4418dea88ac542965/token/program-2022) + - Final report https://github.com/anza-xyz/security-audits/blob/master/spl/HalbornToken2022Audit-2022-07-27.pdf +* Zellic + - Review commit hash [`54695b`](https://github.com/solana-labs/solana-program-library/tree/54695b233484722458b18c0e26ebb8334f98422c/token/program-2022) + - Final report https://github.com/anza-xyz/security-audits/blob/master/spl/ZellicToken2022Audit-2022-12-05.pdf +* Trail of Bits + - Review commit hash [`50abad`](https://github.com/solana-labs/solana-program-library/tree/50abadd819df2e406567d6eca31c213264c1c7cd/token/program-2022) + - Final report https://github.com/anza-xyz/security-audits/blob/master/spl/TrailOfBitsToken2022Audit-2023-02-10.pdf +* NCC Group + - Review commit hash [`4e43aa`](https://github.com/solana-labs/solana/tree/4e43aa6c18e6bb4d98559f80eb004de18bc6b418/zk-token-sdk) + - Final report https://github.com/anza-xyz/security-audits/blob/master/spl/NCCToken2022Audit-2023-04-05.pdf +* OtterSec + - Review commit hash [`e92413`](https://github.com/solana-labs/solana-program-library/tree/e924132d65ba0896249fb4983f6f97caff15721a) + - Final report https://github.com/anza-xyz/security-audits/blob/master/spl/OtterSecToken2022Audit-2023-11-03.pdf +* OtterSec (ZK Token SDK) + - Review commit hash [`9e703f8`](https://github.com/solana-labs/solana/tree/9e703f8/zk-token-sdk) + - Final report https://github.com/anza-xyz/security-audits/blob/master/spl/OtterSecZkTokenSdkAudit-2023-11-04.pdf diff --git a/docs/src/token-2022/extensions.md b/docs/src/token-2022/extensions.md deleted file mode 100644 index 1380c7f5191..00000000000 --- a/docs/src/token-2022/extensions.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Extension Guide ---- - -Coming soon! diff --git a/docs/src/token-2022/extensions.mdx b/docs/src/token-2022/extensions.mdx new file mode 100644 index 00000000000..4fd48665e1f --- /dev/null +++ b/docs/src/token-2022/extensions.mdx @@ -0,0 +1,2078 @@ +--- +title: Extension Guide +--- + +```mdx-code-block +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +``` + +The Token-2022 program provides additional functionality on mints and token +accounts through an extension model. + +This guide explains all of the available extensions, along with some examples of +how to use them. + +Please see the [Token-2022 Introduction](../token-2022) for more general information +about Token-2022 and the concept of extensions. + +## Setup + +See the [Token Setup Guide](../token#setup) to install the client utilities. +Token-2022 shares the same CLI and NPM packages for maximal compatibility. + +All JS examples are adapted from the tests, and available in full at the +[Token JS examples](https://github.com/solana-program/token-2022/tree/main/clients/js-legacy/examples). + +## Extensions + +### Mint Close Authority + +The Token program allows owners to close token accounts, but it is impossible +to close mint accounts. In Token-2022, it is possible to close mints by initializing +the `MintCloseAuthority` extension before initializing the mint. + +#### Example: Initializing a mint with mint close authority + + + + +```console +$ spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token --enable-close +Creating token C47NXhUTVEisCfX7s16KrxYyimnui7HpUXZecE2TmLdB under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb +``` + + + + +```jsx +import { + closeAccount, + createInitializeMintInstruction, + createInitializeMintCloseAuthorityInstruction, + getMintLen, + ExtensionType, + TOKEN_2022_PROGRAM_ID, +} from '@solana/spl-token'; +import { + clusterApiUrl, + sendAndConfirmTransaction, + Connection, + Keypair, + SystemProgram, + Transaction, + LAMPORTS_PER_SOL, +} from '@solana/web3.js'; + +(async () => { + const payer = Keypair.generate(); + + const mintKeypair = Keypair.generate(); + const mint = mintKeypair.publicKey; + const mintAuthority = Keypair.generate(); + const freezeAuthority = Keypair.generate(); + const closeAuthority = Keypair.generate(); + + const connection = new Connection(clusterApiUrl('devnet'), 'confirmed'); + + const airdropSignature = await connection.requestAirdrop(payer.publicKey, 2 * LAMPORTS_PER_SOL); + await connection.confirmTransaction({ signature: airdropSignature, ...(await connection.getLatestBlockhash()) }); + + const extensions = [ExtensionType.MintCloseAuthority]; + const mintLen = getMintLen(extensions); + const lamports = await connection.getMinimumBalanceForRentExemption(mintLen); + + const transaction = new Transaction().add( + SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + newAccountPubkey: mint, + space: mintLen, + lamports, + programId: TOKEN_2022_PROGRAM_ID, + }), + createInitializeMintCloseAuthorityInstruction(mint, closeAuthority.publicKey, TOKEN_2022_PROGRAM_ID), + createInitializeMintInstruction( + mint, + 9, + mintAuthority.publicKey, + freezeAuthority.publicKey, + TOKEN_2022_PROGRAM_ID + ) + ); + await sendAndConfirmTransaction(connection, transaction, [payer, mintKeypair], undefined); +})(); +``` + + + + +#### Example: Closing a mint + +With the `MintCloseAuthority` extension on the mint and a valid authority, it's +possible to close the mint account and reclaim the lamports on the mint account. +**Note**: The supply on the mint must be 0. + + + + +```console +$ spl-token close-mint C47NXhUTVEisCfX7s16KrxYyimnui7HpUXZecE2TmLdB +Signature: 5nidwS9fJGJGdmaQjcwvNGVtk2ba5Zyu9ZLubjUKSsaAyzLUYvB6LK5RfUA767veBr45x7R1WW9N7WkYZ3Rqsb5B +``` + + + + +```jsx +await closeAccount(connection, payer, mint, payer.publicKey, closeAuthority, [], undefined, TOKEN_2022_PROGRAM_ID); +``` + + + + +### Transfer Fees + +In the Token program, it is impossible to assess a fee on every transfer. The +existing systems typically involve freezing user accounts, and forcing them to go +through a third party to unfreeze, transfer, and refreeze the accounts. + +With Token-2022, it's possible to configure a transfer fee on a mint so that fees +are assessed at the protocol level. On every transfer, some amount is withheld +on the recipient account, untouchable by the recipient. These tokens can be +withheld by a separate authority on the mint. + +**Important note**: Transferring tokens with a transfer fee requires using +`transfer_checked` or `transfer_checked_with_fee` instead of `transfer`. +Otherwise, the transfer will fail. + +#### Example: Creating a mint with a transfer fee + +Transfer fee configurations contain a few important fields: + +* Fee in basis points: fee assessed on every transfer, as basis points of + the transfer amount. For example, with 50 basis points, a transfer of 1,000 + tokens yields 5 tokens +* Maximum fee: cap on transfer fees. With a maximum fee of 5,000 tokens, even + a transfer of 10,000,000,000,000 tokens only yields 5,000 tokens +* Transfer fee authority: entity that can modify the fees +* Withdraw withheld authority: entity that can move tokens withheld on the + mint or token accounts + +Let's create a mint with 50 basis point transfer fee, and a maximum fee of 5,000 +tokens. + + + + +```console +$ spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token --transfer-fee-basis-points 50 --transfer-fee-maximum-fee 5000 +Creating token Dg3i18BN7vzsbAZDnDv3H8nQQjSaPUTqhwX41J7NZb5H under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb + +Address: Dg3i18BN7vzsbAZDnDv3H8nQQjSaPUTqhwX41J7NZb5H +Decimals: 9 + +Signature: 39okFGqW23wQZ1HqH2tdJvtFP5aYgpfbmNktCZpV5XKTpKuA9xJmvBmrBwcLdfAT632VEC4y4dJJfDoeAvMWRPYP +``` + + + + +```jsx +import { + clusterApiUrl, + sendAndConfirmTransaction, + Connection, + Keypair, + SystemProgram, + Transaction, + LAMPORTS_PER_SOL, +} from '@solana/web3.js'; + +import { + ExtensionType, + createInitializeMintInstruction, + mintTo, + createAccount, + getMintLen, + TOKEN_2022_PROGRAM_ID, +} from '@solana/spl-token'; + +import { + createInitializeTransferFeeConfigInstruction, + harvestWithheldTokensToMint, + transferCheckedWithFee, + withdrawWithheldTokensFromAccounts, + withdrawWithheldTokensFromMint, +} from '@solana/spl-token'; + +(async () => { + const payer = Keypair.generate(); + + const mintAuthority = Keypair.generate(); + const mintKeypair = Keypair.generate(); + const mint = mintKeypair.publicKey; + const transferFeeConfigAuthority = Keypair.generate(); + const withdrawWithheldAuthority = Keypair.generate(); + + const extensions = [ExtensionType.TransferFeeConfig]; + + const mintLen = getMintLen(extensions); + const decimals = 9; + const feeBasisPoints = 50; + const maxFee = BigInt(5_000); + + const connection = new Connection(clusterApiUrl('devnet'), 'confirmed'); + + const airdropSignature = await connection.requestAirdrop(payer.publicKey, 2 * LAMPORTS_PER_SOL); + await connection.confirmTransaction({ signature: airdropSignature, ...(await connection.getLatestBlockhash()) }); + + const mintLamports = await connection.getMinimumBalanceForRentExemption(mintLen); + const mintTransaction = new Transaction().add( + SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + newAccountPubkey: mint, + space: mintLen, + lamports: mintLamports, + programId: TOKEN_2022_PROGRAM_ID, + }), + createInitializeTransferFeeConfigInstruction( + mint, + transferFeeConfigAuthority.publicKey, + withdrawWithheldAuthority.publicKey, + feeBasisPoints, + maxFee, + TOKEN_2022_PROGRAM_ID + ), + createInitializeMintInstruction(mint, decimals, mintAuthority.publicKey, null, TOKEN_2022_PROGRAM_ID) + ); + await sendAndConfirmTransaction(connection, mintTransaction, [payer, mintKeypair], undefined); +})(); +``` + + + + +#### Example: Transferring tokens with the fee checked + +As part of the extension, there is a new `transfer_checked_with_fee` instruction, +which accepts the expected fee. The transfer only succeeds if the fee is correctly +calculated, in order to avoid any surprises during the transfer. + + + + +```console +$ spl-token create-account Dg3i18BN7vzsbAZDnDv3H8nQQjSaPUTqhwX41J7NZb5H +Creating account 7UKuG4W68hW9eGrDms6BenRf8DCEHKGN49xewtWyB5cx + +Signature: 6h591BMuguh9TtSdQPRPcPy97mLqJiybeaxGVZzD8mvPEsYypjZ2jjKgHzji5FGh8CJE3NAzqrqGxfyMdnbWrs7 +$ solana-keygen new -o destination.json +$ spl-token create-account Dg3i18BN7vzsbAZDnDv3H8nQQjSaPUTqhwX41J7NZb5H destination.json +Creating account 5wY8fiMZG5wGbQmtzKgqqEEp4vsCMJZ53RXEagUUWhEr + +Signature: 2SyA17AJRWLH2j7svgxgW7nouUGioeWoRDWjz2Wq8j1eisThezSvqgN4NbHfj9uWmDh2XRp56ttZtHV1SxaUC7ys +$ spl-token mint Dg3i18BN7vzsbAZDnDv3H8nQQjSaPUTqhwX41J7NZb5H 1000000000 +Minting 1000000000 tokens + Token: Dg3i18BN7vzsbAZDnDv3H8nQQjSaPUTqhwX41J7NZb5H + Recipient: 7UKuG4W68hW9eGrDms6BenRf8DCEHKGN49xewtWyB5cx + +Signature: 5MFJGpLaWe3yLLU8X4ax3KofeqPVzdxJsa3ScjChJJHJawKsRx4og9eaFkWn3CPF7JXaxdj5v4LdAW56LiNTuP6s +$ spl-token transfer --expected-fee 0.000005 Dg3i18BN7vzsbAZDnDv3H8nQQjSaPUTqhwX41J7NZb5H 1000000 destination.json +Transfer 1000000 tokens + Sender: 7UKuG4W68hW9eGrDms6BenRf8DCEHKGN49xewtWyB5cx + Recipient: 5wY8fiMZG5wGbQmtzKgqqEEp4vsCMJZ53RXEagUUWhEr + +Signature: 3hc3CCiETiuCArJ6yZ76ScyfMeK1rw8CTfZ3aDGnYoEMeoqXfSNAtnM3ATFjm7UihthzEkEWzeUfWL4qqqB4ofgv +``` + + + + +```jsx + const mintAmount = BigInt(1_000_000_000); + const owner = Keypair.generate(); + const sourceAccount = await createAccount( + connection, + payer, + mint, + owner.publicKey, + undefined, + undefined, + TOKEN_2022_PROGRAM_ID + ); + await mintTo( + connection, + payer, + mint, + sourceAccount, + mintAuthority, + mintAmount, + [], + undefined, + TOKEN_2022_PROGRAM_ID + ); + + const accountKeypair = Keypair.generate(); + const destinationAccount = await createAccount( + connection, + payer, + mint, + owner.publicKey, + accountKeypair, + undefined, + TOKEN_2022_PROGRAM_ID + ); + + const transferAmount = BigInt(1_000_000); + const fee = (transferAmount * BigInt(feeBasisPoints)) / BigInt(10_000); + await transferCheckedWithFee( + connection, + payer, + sourceAccount, + mint, + destinationAccount, + owner, + transferAmount, + decimals, + fee, + [], + undefined, + TOKEN_2022_PROGRAM_ID + ); +``` + + + + +#### Example: Find accounts with withheld tokens + +As users transfer their tokens, transfer fees accumulate in the various recipient +accounts. The withdraw withheld authority, configured at initialization, can move +these tokens wherever they wish using `withdraw_withheld_tokens_from_accounts` or +`harvest_withheld_tokens_to_mint`. + +Before doing that, however, they must find which accounts have withheld tokens +by iterating over all accounts for the mint. + + + + +CLI support coming soon! + + + + +```jsx + const allAccounts = await connection.getProgramAccounts(TOKEN_2022_PROGRAM_ID, { + commitment: 'confirmed', + filters: [ + { + memcmp: { + offset: 0, + bytes: mint.toString(), + }, + }, + ], + }); + const accountsToWithdrawFrom = []; + for (const accountInfo of allAccounts) { + const account = unpackAccount(accountInfo.account, accountInfo.pubkey, TOKEN_2022_PROGRAM_ID); + const transferFeeAmount = getTransferFeeAmount(account); + if (transferFeeAmount !== null && transferFeeAmount.withheldAmount > BigInt(0)) { + accountsToWithdrawFrom.push(accountInfo.pubkey); + } + } +``` + + + + +#### Example: Withdraw withheld tokens from accounts + +With the accounts found, the withheld withdraw authority may move the withheld +tokens. + + + + +```console +$ spl-token withdraw-withheld-tokens 7UKuG4W68hW9eGrDms6BenRf8DCEHKGN49xewtWyB5cx 5wY8fiMZG5wGbQmtzKgqqEEp4vsCMJZ53RXEagUUWhEr +Signature: 2NfjbEnRQC7kXkf86stb6u7eUtaQTGDebo8ktCdz4gP4wCD93xtx75rSJxJDQVePNAa8NqtVLjUm19ZBDRVaYurt +``` + + + + +```jsx + await withdrawWithheldTokensFromAccounts( + connection, + payer, + mint, + destinationAccount, + withdrawWithheldAuthority, + [], + [destinationAccount], + undefined, + TOKEN_2022_PROGRAM_ID + ); +``` + + + + +**Note**: The design of pooling transfer fees at the recipient account is meant to +maximize parallelization of transactions. Otherwise, one configured fee recipient +account would be write-locked between parallel transfers, decreasing throughput +of the protocol. + +#### Example: Harvest withheld tokens to mint + +Users may want to close a token account with withheld transfer fees, but it is +impossible to close an account that holds any tokens, including withheld ones. + +To clear out their account of withheld tokens, they can use the permissionless +`harvest_withheld_tokens_to_mint` instruction. + + + + +The harvest instruction isn't explicitly exposed since it typically isn't needed. +It is required before closing an account, however, so we can show the harvest +behavior by closing the account: + +```console +$ spl-token close --address 5wY8fiMZG5wGbQmtzKgqqEEp4vsCMJZ53RXEagUUWhEr +Signature: KAKXryAdGSVFqpQhrwrvP6NCAQwLQp2Sj1WiAqCHxxwJsvRLKx4JzWgN9zYUaJNmfrZnQQw9yYoDw5Xx1YrwY6i + +Signature: 2i5KGekFFtwzkX2W71cxPvQsGEH21qmZ3ieNQz7Mz2qGqp2pyzMNZhSVRfxJxQuAxnKQoZKjAb62FBx2gxaq25Le +``` + + + + +```jsx + await harvestWithheldTokensToMint(connection, payer, mint, [destinationAccount], undefined, TOKEN_2022_PROGRAM_ID); +``` + + + + +#### Example: Withdraw withheld tokens from mint + +As users move the withheld tokens to the mint, the withdraw authority +may choose to move those tokens from the mint to any other account. + + + + +```console +$ spl-token withdraw-withheld-tokens --include-mint 7UKuG4W68hW9eGrDms6BenRf8DCEHKGN49xewtWyB5cx + +Signature: 5KzdgcKgi3rLaBRfDbG5pxZwyKppyVjAA8TUCjTMfb1vMYv7CLQWaxgFz81jz4reUaF7oP67Gdqoc91Ted6qr1Hb +``` + + + + +```jsx + await withdrawWithheldTokensFromMint( + connection, + payer, + mint, + destinationAccount, + withdrawWithheldAuthority, + [], + undefined, + TOKEN_2022_PROGRAM_ID + ); +``` + + + + +### Default Account State + +A mint creator may want to restrict who can use their token. There are many +heavy-handed approaches to this problem, most of which include going through a +centralized service at the beginning. Even through a centralized service, however, +it's possible for anyone to create a new token account and transfer the tokens +around. + +To simplify the restriction, a mint creator may use the `DefaultAccountState` +extension, which can force all new token accounts to be frozen. This way, users +must eventually interact with some service to unfreeze their account and use +tokens. + +#### Example: Creating a mint with default frozen accounts + + + + +```console +$ spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token --enable-freeze --default-account-state frozen +Creating token 8Sqz2zV8TFTnkLtnCdqRkjJsre3GKRwHcZd3juE5jJHf under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb + +Address: 8Sqz2zV8TFTnkLtnCdqRkjJsre3GKRwHcZd3juE5jJHf +Decimals: 9 + +Signature: 5wfYvovguPEbyv2uSWxGt9JcpTWgyuP4hY3wutjS32Ahnoni4qd7gf6sLre855WvT6xLHwrvV7J8bVmXymNU2qUz + +$ spl-token create-account 8Sqz2zV8TFTnkLtnCdqRkjJsre3GKRwHcZd3juE5jJHf +Creating account 6XpKagP1N3K1XnzStufpV5YZ6DksEkQWgLNG9kPpLyvv + +Signature: 2awxWdQMgv89ew34sEyG361vshB2wPXHHfva5iJ43dWr18f2Pr6awoXfsqYPpyS2eSbH6jhfVY9EUck8iJ4wCSN6 + +$ spl-token display 6XpKagP1N3K1XnzStufpV5YZ6DksEkQWgLNG9kPpLyvv +SPL Token Account + Address: 6XpKagP1N3K1XnzStufpV5YZ6DksEkQWgLNG9kPpLyvv + Program: TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb + Balance: 0 + Decimals: 9 + Mint: 8Sqz2zV8TFTnkLtnCdqRkjJsre3GKRwHcZd3juE5jJHf + Owner: 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn + State: Frozen + Delegation: (not set) + Close authority: (not set) +Extensions: + Immutable owner +``` + + + + +```jsx +import { + clusterApiUrl, + sendAndConfirmTransaction, + Connection, + Keypair, + SystemProgram, + Transaction, + LAMPORTS_PER_SOL, +} from '@solana/web3.js'; +import { + AccountState, + createInitializeMintInstruction, + createInitializeDefaultAccountStateInstruction, + getMintLen, + updateDefaultAccountState, + ExtensionType, + TOKEN_2022_PROGRAM_ID, +} from '@solana/spl-token'; + +(async () => { + const payer = Keypair.generate(); + + const mintAuthority = Keypair.generate(); + const freezeAuthority = Keypair.generate(); + const mintKeypair = Keypair.generate(); + const mint = mintKeypair.publicKey; + + const extensions = [ExtensionType.DefaultAccountState]; + const mintLen = getMintLen(extensions); + const decimals = 9; + + const connection = new Connection(clusterApiUrl('devnet'), 'confirmed'); + + const airdropSignature = await connection.requestAirdrop(payer.publicKey, 2 * LAMPORTS_PER_SOL); + await connection.confirmTransaction({ signature: airdropSignature, ...(await connection.getLatestBlockhash()) }); + + const defaultState = AccountState.Frozen; + + const lamports = await connection.getMinimumBalanceForRentExemption(mintLen); + const transaction = new Transaction().add( + SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + newAccountPubkey: mint, + space: mintLen, + lamports, + programId: TOKEN_2022_PROGRAM_ID, + }), + createInitializeDefaultAccountStateInstruction(mint, defaultState, TOKEN_2022_PROGRAM_ID), + createInitializeMintInstruction( + mint, + decimals, + mintAuthority.publicKey, + freezeAuthority.publicKey, + TOKEN_2022_PROGRAM_ID + ) + ); + await sendAndConfirmTransaction(connection, transaction, [payer, mintKeypair], undefined); +})(); +``` + + + + +#### Example: Updating default state + +Over time, if the mint creator decides to relax this restriction, the freeze +authority may sign an `update_default_account_state` instruction to make all +accounts unfrozen by default. + + + + +```console +$ spl-token update-default-account-state 8Sqz2zV8TFTnkLtnCdqRkjJsre3GKRwHcZd3juE5jJHf initialized + +Signature: 3Mm2JCPrf6SrAe9awV3QzYvHiYmatiGWTmrQ7YnmzJSqyNCf75rLNMyH7jU26uZwX7q3MmBEBj1A36o5sGk9Vakb +``` + + + + +```jsx + await updateDefaultAccountState( + connection, + payer, + mint, + AccountState.Initialized, + freezeAuthority, + [], + undefined, + TOKEN_2022_PROGRAM_ID + ); +``` + + + + +### Immutable Owner + +Token account owners may reassign ownership to any other address. This is useful +in many situations, but it can also create security vulnerabilities. + +For example, the addresses for Associated Token Accounts are derived based on +the owner and the mint, making it easy to find the "right" token account for an +owner. If the account owner has reassigned ownership of their associated token +account, then applications may derive the address for that account and use it, +not knowing that it does not belong to the owner anymore. + +To avoid this issue, Token-2022 includes the `ImmutableOwner` extension, which +makes it impossible to reassign ownership of an account. The Associated Token +Account program always uses this extension when creating accounts. + +#### Example: Explicitly creating an account with immutable ownership + + + + +```console +$ spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token +Creating token CZxztd7SEZWxg6B9PH5xa7QwKpMCpWBJiTLftw1o3qyV under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb + +Address: CZxztd7SEZWxg6B9PH5xa7QwKpMCpWBJiTLftw1o3qyV +Decimals: 9 + +Signature: 4fT19YaE3zAscj71n213K22M3wDSXgwSn39RBCVtiCTxMX7pZhAoHywP2QMKqWpZMB5vT7diQ8QaFp3abHztpyPC +$ solana-keygen new -o account.json +$ spl-token create-account CZxztd7SEZWxg6B9PH5xa7QwKpMCpWBJiTLftw1o3qyV account.json --immutable +Creating account EV2xsZto1TRqehewwWHUUQm68X6C6MepBSkbfZcVdShy + +Signature: 5NqXiE3LPFnufnZhcwKPoZt7DaPR7qwfhmRr9W9ykhNM7rnu6MDdx7n5eTpEisiaSET2R4fZW7a91Ai6pCuskXF8 +``` + + + + +```jsx +import { + clusterApiUrl, + sendAndConfirmTransaction, + Connection, + Keypair, + SystemProgram, + Transaction, + LAMPORTS_PER_SOL, +} from '@solana/web3.js'; +import { + createAccount, + createMint, + createInitializeImmutableOwnerInstruction, + createInitializeAccountInstruction, + getAccountLen, + ExtensionType, + TOKEN_2022_PROGRAM_ID, +} from '@solana/spl-token'; + +(async () => { + const connection = new Connection(clusterApiUrl('devnet'), 'confirmed'); + + const payer = Keypair.generate(); + const airdropSignature = await connection.requestAirdrop(payer.publicKey, 2 * LAMPORTS_PER_SOL); + await connection.confirmTransaction({ signature: airdropSignature, ...(await connection.getLatestBlockhash()) }); + + const mintAuthority = Keypair.generate(); + const decimals = 9; + const mint = await createMint( + connection, + payer, + mintAuthority.publicKey, + mintAuthority.publicKey, + decimals, + undefined, + undefined, + TOKEN_2022_PROGRAM_ID + ); + + const accountLen = getAccountLen([ExtensionType.ImmutableOwner]); + const lamports = await connection.getMinimumBalanceForRentExemption(accountLen); + + const owner = Keypair.generate(); + const accountKeypair = Keypair.generate(); + const account = accountKeypair.publicKey; + const transaction = new Transaction().add( + SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + newAccountPubkey: account, + space: accountLen, + lamports, + programId: TOKEN_2022_PROGRAM_ID, + }), + createInitializeImmutableOwnerInstruction(account, TOKEN_2022_PROGRAM_ID), + createInitializeAccountInstruction(account, mint, owner.publicKey, TOKEN_2022_PROGRAM_ID) + ); + await sendAndConfirmTransaction(connection, transaction, [payer, accountKeypair], undefined); +})(); +``` + + + + +#### Example: Creating an associated token account with immutable ownership + +All associated token accounts have the immutable owner extension included, so +it's extremely easy to use the extension. + + + + +```console +$ spl-token create-account CZxztd7SEZWxg6B9PH5xa7QwKpMCpWBJiTLftw1o3qyV +Creating account 4nvfLgYMERdNbbf1pADUSp44XukAyjeWWXCMkM1gMqC4 + +Signature: w4TRYDdCpTfmQh96E4UNgFFeiAHphWNaeYrJTu6bGyuPMokJrKFR33Ntj3iNQ5QQuFqom2CaYkhXiX9sBpWEW23 +``` + +The CLI will tell us that it's unnecessary to specify the `--immutable` argument +if it's provided: + +```console +$ spl-token create-account CZxztd7SEZWxg6B9PH5xa7QwKpMCpWBJiTLftw1o3qyV --immutable +Creating account 4nvfLgYMERdNbbf1pADUSp44XukAyjeWWXCMkM1gMqC4 +Note: --immutable specified, but Token-2022 ATAs are always immutable, ignoring + +Signature: w4TRYDdCpTfmQh96E4UNgFFeiAHphWNaeYrJTu6bGyuPMokJrKFR33Ntj3iNQ5QQuFqom2CaYkhXiX9sBpWEW23 +``` + + + + +```jsx + const associatedAccount = await createAccount( + connection, + payer, + mint, + owner.publicKey, + undefined, + undefined, + TOKEN_2022_PROGRAM_ID + ); +``` + + + + +### Non-Transferable Tokens + +To accompany immutably owned token accounts, the `NonTransferable` mint extension +allows for "soul-bound" tokens that cannot be moved to any other entity. For +example, this extension is perfect for achievements that can only belong to one +person or account. + +This extension is very similar to issuing a token and then freezing the account, +but allows the owner to burn and close the account if they want. + +#### Example: Creating a non-transferable mint + + + + +```console +$ spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token --enable-non-transferable +Creating token 7De7wwkvNLPXpShbPDeRCLukb3CRzCNcC3iUuHtD6k4f under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb + +Address: 7De7wwkvNLPXpShbPDeRCLukb3CRzCNcC3iUuHtD6k4f +Decimals: 9 + +Signature: 2QtCBwCo2J9hf2Prd2t4CBBUxEXQCBSSD5gkNc59AwhxsKgRp92czNAvwWDxjeXGFCWSuNmzAcD19cEpqubovDDv +``` + + + + +```jsx +import { + clusterApiUrl, + sendAndConfirmTransaction, + Connection, + Keypair, + SystemProgram, + Transaction, + LAMPORTS_PER_SOL, +} from '@solana/web3.js'; +import { + createInitializeNonTransferableMintInstruction, + createInitializeMintInstruction, + getMintLen, + ExtensionType, + TOKEN_2022_PROGRAM_ID, +} from '@solana/spl-token'; + +(async () => { + const connection = new Connection(clusterApiUrl('devnet'), 'confirmed'); + + const payer = Keypair.generate(); + const airdropSignature = await connection.requestAirdrop(payer.publicKey, 2 * LAMPORTS_PER_SOL); + await connection.confirmTransaction({ signature: airdropSignature, ...(await connection.getLatestBlockhash()) }); + + const mintAuthority = Keypair.generate(); + const decimals = 9; + + const mintKeypair = Keypair.generate(); + const mint = mintKeypair.publicKey; + const mintLen = getMintLen([ExtensionType.NonTransferable]); + const lamports = await connection.getMinimumBalanceForRentExemption(mintLen); + + const transaction = new Transaction().add( + SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + newAccountPubkey: mint, + space: mintLen, + lamports, + programId: TOKEN_2022_PROGRAM_ID, + }), + createInitializeNonTransferableMintInstruction(mint, TOKEN_2022_PROGRAM_ID), + createInitializeMintInstruction(mint, decimals, mintAuthority.publicKey, null, TOKEN_2022_PROGRAM_ID) + ); + await sendAndConfirmTransaction(connection, transaction, [payer, mintKeypair], undefined); +})(); +``` + + + + +### Required Memo on Transfer + +Traditional banking systems typically require a memo to accompany all transfers. +The Token-2022 program contains an extension to satisfy this requirement. + +By enabling required memo transfers on your token account, the program enforces +that all incoming transfers must have an accompanying memo instruction right +before the transfer instruction. + +**Note**: This also works in CPI contexts, as long as a CPI is performed to log +the memo before invoking the transfer. + +#### Example: Create account with required memo transfers + + + + +```console +$ spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token +Creating token EbPBt3XkCb9trcV4c8fidhrvoeURbDbW87Acustzyi8N under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb + +Address: EbPBt3XkCb9trcV4c8fidhrvoeURbDbW87Acustzyi8N +Decimals: 9 + +Signature: 2mCoV3ujSUArgZMyayiYtLZp2QzpqKx3NXnv9W8DpinY39rBU2yGmYLfp2tZ9uZqVbfJ6Mf3SqDHexdCcFcDAEvc +$ spl-token create-account EbPBt3XkCb9trcV4c8fidhrvoeURbDbW87Acustzyi8N +Creating account 4Uzz67txwYbfYpF8r5UGEMYJwhPAYQ5eFUY89KTYc2bL + +Signature: 57wZHDaQtSzszDkusrnozZNj5PemQhpqHMEFLWFKpqASCErcDuBuYuEky5g3evHtkjMrKgh1s3aEap1L8y5UhW5W +$ spl-token enable-required-transfer-memos 4Uzz67txwYbfYpF8r5UGEMYJwhPAYQ5eFUY89KTYc2bL +Signature: 5MnWtrhMK32zkbacDMwBNft48VAUpr4EoRM87hkT9AFYvPgPEU7V7ERV6gdfb3kASri4wnUnr13hNKuYJ66pD8Fs +``` + + + + +```jsx +import { + clusterApiUrl, + sendAndConfirmTransaction, + Connection, + Keypair, + SystemProgram, + Transaction, + LAMPORTS_PER_SOL, +} from '@solana/web3.js'; +import { createMemoInstruction } from '@solana/spl-memo'; +import { + createAssociatedTokenAccount, + createMint, + createEnableRequiredMemoTransfersInstruction, + createInitializeAccountInstruction, + createTransferInstruction, + disableRequiredMemoTransfers, + enableRequiredMemoTransfers, + getAccountLen, + mintTo, + ExtensionType, + TOKEN_2022_PROGRAM_ID, +} from '@solana/spl-token'; + +(async () => { + const connection = new Connection(clusterApiUrl('devnet'), 'confirmed'); + + const payer = Keypair.generate(); + const airdropSignature = await connection.requestAirdrop(payer.publicKey, 2 * LAMPORTS_PER_SOL); + await connection.confirmTransaction({ signature: airdropSignature, ...(await connection.getLatestBlockhash()) }); + + const mintAuthority = Keypair.generate(); + const decimals = 9; + const mint = await createMint( + connection, + payer, + mintAuthority.publicKey, + mintAuthority.publicKey, + decimals, + undefined, + undefined, + TOKEN_2022_PROGRAM_ID + ); + + const accountLen = getAccountLen([ExtensionType.MemoTransfer]); + const lamports = await connection.getMinimumBalanceForRentExemption(accountLen); + + const owner = Keypair.generate(); + const destinationKeypair = Keypair.generate(); + const destination = destinationKeypair.publicKey; + const transaction = new Transaction().add( + SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + newAccountPubkey: destination, + space: accountLen, + lamports, + programId: TOKEN_2022_PROGRAM_ID, + }), + createInitializeAccountInstruction(destination, mint, owner.publicKey, TOKEN_2022_PROGRAM_ID), + createEnableRequiredMemoTransfersInstruction(destination, owner.publicKey, [], TOKEN_2022_PROGRAM_ID) + ); + + await sendAndConfirmTransaction(connection, transaction, [payer, owner, destinationKeypair], undefined); + +})(); +``` + + + + +#### Example: Enabling or disabling required memo transfers + +An account owner may always choose to flip required memo transfers on or off. + + + + +```console +$ spl-token disable-required-transfer-memos 4Uzz67txwYbfYpF8r5UGEMYJwhPAYQ5eFUY89KTYc2bL +Signature: 5a9X8JrWzwZqb3iMonfUfSZbisQ57aEmW5cFntWGYRv2UZx8ACkMineBEQRHwLMzYHeyFDEHMXu8zqAMv5tm4u1g + +$ spl-token enable-required-transfer-memos 4Uzz67txwYbfYpF8r5UGEMYJwhPAYQ5eFUY89KTYc2bL +Signature: 5MnWtrhMK32zkbacDMwBNft48VAUpr4EoRM87hkT9AFYvPgPEU7V7ERV6gdfb3kASri4wnUnr13hNKuYJ66pD8Fs +``` + + + + +```jsx + await disableRequiredMemoTransfers(connection, payer, destination, owner, [], undefined, TOKEN_2022_PROGRAM_ID); + + await enableRequiredMemoTransfers(connection, payer, destination, owner, [], undefined, TOKEN_2022_PROGRAM_ID); +``` + + + + +#### Example: Transferring with a memo + +When transferring into an account with required transfer memos, you must include +a memo instruction before the transfer. + + + + +```console +$ spl-token transfer EbPBt3XkCb9trcV4c8fidhrvoeURbDbW87Acustzyi8N 10 4Uzz67txwYbfYpF8r5UGEMYJwhPAYQ5eFUY89KTYc2bL --with-memo "memo text" +Signature: 5a9X8JrWzwZqb3iMonfUfSZbisQ57aEmW5cFntWGYRv2UZx8ACkMineBEQRHwLMzYHeyFDEHMXu8zqAMv5tm4u1g +``` + + + + +```jsx + const sourceTokenAccount = await createAssociatedTokenAccount( + connection, + payer, + mint, + payer.publicKey, + undefined, + TOKEN_2022_PROGRAM_ID + ); + await mintTo(connection, payer, mint, sourceTokenAccount, mintAuthority, 100, [], undefined, TOKEN_2022_PROGRAM_ID); + + const transferTransaction = new Transaction().add( + createMemoInstruction('Hello, memo-transfer!', [payer.publicKey]), + createTransferInstruction(sourceTokenAccount, destination, payer.publicKey, 100, [], TOKEN_2022_PROGRAM_ID) + ); + await sendAndConfirmTransaction(connection, transferTransaction, [payer], undefined); +``` + + + + +### Reallocate + +In the previous example, astute readers of the JavaScript code may have noticed +that the `EnableRequiredMemoTransfers` instruction came after `InitializeAccount`, +which means that this extension can be enabled after the account is already +created. + +In order to actually add this extension after the account is created, however, +you may need to reallocate more space in the account for the additional extension +bytes. + +The `Reallocate` instruction allows an owner to reallocate their token account +to fit room for more extensions. + +#### Example: Reallocating existing account to enable required memo transfers + + + + +The CLI reallocs automatically, so if you use `enable-required-transfer-memos` +with an account that does not have enough space, it will add the `Reallocate` +instruction. + +```console +$ spl-token create-account EbPBt3XkCb9trcV4c8fidhrvoeURbDbW87Acustzyi8N +Creating account 4Uzz67txwYbfYpF8r5UGEMYJwhPAYQ5eFUY89KTYc2bL + +Signature: 57wZHDaQtSzszDkusrnozZNj5PemQhpqHMEFLWFKpqASCErcDuBuYuEky5g3evHtkjMrKgh1s3aEap1L8y5UhW5W +$ spl-token enable-required-transfer-memos 4Uzz67txwYbfYpF8r5UGEMYJwhPAYQ5eFUY89KTYc2bL +Signature: 5MnWtrhMK32zkbacDMwBNft48VAUpr4EoRM87hkT9AFYvPgPEU7V7ERV6gdfb3kASri4wnUnr13hNKuYJ66pD8Fs +``` + + + + +```jsx +import { + clusterApiUrl, + sendAndConfirmTransaction, + Connection, + Keypair, + Transaction, + LAMPORTS_PER_SOL, +} from '@solana/web3.js'; +import { + createAccount, + createMint, + createEnableRequiredMemoTransfersInstruction, + createReallocateInstruction, + ExtensionType, + TOKEN_2022_PROGRAM_ID, +} from '@solana/spl-token'; + +(async () => { + const connection = new Connection(clusterApiUrl('devnet'), 'confirmed'); + + const payer = Keypair.generate(); + const airdropSignature = await connection.requestAirdrop(payer.publicKey, 2 * LAMPORTS_PER_SOL); + await connection.confirmTransaction({ signature: airdropSignature, ...(await connection.getLatestBlockhash()) }); + + const mintAuthority = Keypair.generate(); + const decimals = 9; + const mint = await createMint( + connection, + payer, + mintAuthority.publicKey, + mintAuthority.publicKey, + decimals, + undefined, + undefined, + TOKEN_2022_PROGRAM_ID + ); + + const owner = Keypair.generate(); + const account = await createAccount( + connection, + payer, + mint, + owner.publicKey, + undefined, + undefined, + TOKEN_2022_PROGRAM_ID + ); + + const extensions = [ExtensionType.MemoTransfer]; + const transaction = new Transaction().add( + createReallocateInstruction( + account, + payer.publicKey, + extensions, + owner.publicKey, + undefined, + TOKEN_2022_PROGRAM_ID + ), + createEnableRequiredMemoTransfersInstruction(account, owner.publicKey, [], TOKEN_2022_PROGRAM_ID) + ); + await sendAndConfirmTransaction(connection, transaction, [payer, owner], undefined); +})(); +``` + + + + +### Interest-Bearing Tokens + +Tokens that constantly grow or decrease in value have many uses in the real world. +The most well known example is a bond. + +With Token, this has only been possible through proxy contracts that require +regular rebase or update operations. + +With the Token-2022 extension model, however, we have the possibility to change +how the UI amount of tokens are represented. Using the `InterestBearingMint` +extension and the `amount_to_ui_amount` instruction, you can set an interest +rate on your token and fetch its amount with interest at any time. + +Interest is continuously compounded based on the timestamp in the network. Due +to drift that may occur in the network timestamp, the accumulated interest could +be lower than the expected value. Thankfully, this is rare. + +**Note**: No new tokens are ever created, the UI amount returns the amount of tokens +plus all interest the tokens have accumulated. The feature is entirely cosmetic. + +#### Example: Create an interest-bearing mint + + + + +```console +$ spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token --interest-rate 10 +Creating token 7N4HggYEJAtCLJdnHGCtFqfxcB5rhQCsQTze3ftYstVj under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb + +Address: 7N4HggYEJAtCLJdnHGCtFqfxcB5rhQCsQTze3ftYstVj +Decimals: 9 + +Signature: 5dSW5QUacEsaKYb3MwYp4ycqq4jpNJ1rpLhS5rotoe3CWv9XhhjrncUFpk14R1fRamS1xprziC3NkpbYno4c8JxD +``` + + + + +```jsx +import { clusterApiUrl, Connection, Keypair, LAMPORTS_PER_SOL } from '@solana/web3.js'; +import { createInterestBearingMint, updateRateInterestBearingMint, TOKEN_2022_PROGRAM_ID } from '@solana/spl-token'; + +(async () => { + const connection = new Connection(clusterApiUrl('devnet'), 'confirmed'); + + const payer = Keypair.generate(); + const airdropSignature = await connection.requestAirdrop(payer.publicKey, 2 * LAMPORTS_PER_SOL); + await connection.confirmTransaction({ signature: airdropSignature, ...(await connection.getLatestBlockhash()) }); + + const mintAuthority = Keypair.generate(); + const freezeAuthority = Keypair.generate(); + const rateAuthority = Keypair.generate(); + const mintKeypair = Keypair.generate(); + const rate = 10; + const decimals = 9; + const mint = await createInterestBearingMint( + connection, + payer, + mintAuthority.publicKey, + freezeAuthority.publicKey, + rateAuthority.publicKey, + rate, + decimals, + mintKeypair, + undefined, + TOKEN_2022_PROGRAM_ID + ); +})(); +``` + + + + +#### Example: Update the interest rate + +The rate authority may update the interest rate on the mint at any time. + + + + +```console +$ spl-token set-interest-rate 7N4HggYEJAtCLJdnHGCtFqfxcB5rhQCsQTze3ftYstVj 50 +Setting Interest Rate for 7N4HggYEJAtCLJdnHGCtFqfxcB5rhQCsQTze3ftYstVj to 50 bps + +Signature: 5DQs6hzkfGq3uotESuVwF7MGeMawwfQcm1e9RHaUeVySDV6xpUzYhzdb6ygqJfsEZqewgiDR5KuxaGzkdTMcDrTn +``` + + + + +```jsx + const updateRate = 50; + await updateRateInterestBearingMint( + connection, + payer, + mint, + rateAuthority, + updateRate, + [], + undefined, + TOKEN_2022_PROGRAM_ID + ); +``` + + + + +### Permanent Delegate + +With Token-2022, it's possible to specify a permanent account delegate for a +mint. This authority has unlimited delegate privileges over any account for that +mint, meaning that it can burn or transfer any amount of tokens. + +While this feature certainly has room for abuse, it has many important real-world +use cases. + +In some jurisdictions, a stablecoin issuer must be able to seize assets from +sanctioned entities. Through the permanent delegate, the stablecoin issuer can +transfer or burn tokens from accounts owned by sanctioned entities. + +It's also possible to implement a [Harberger Tax](http://www.harbergertax.com/) +on an NFT, whereby an auction program has permanent delegate authority for the +token. After a sale, the permanent delegate can move the NFT from the owner to +the buyer if the previous owner doesn't pay the tax. + +#### Example: Create a mint with a permanent delegate + + + + +```console +$ spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token --enable-permanent-delegate +Creating token 7LUgoQCqhk3VMPhpAnmS1zdCFW4C6cupxgbqWrTwydGx under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb + +Address: 7LUgoQCqhk3VMPhpAnmS1zdCFW4C6cupxgbqWrTwydGx +Decimals: 9 + +Signature: 439yVq2WfUEegAPv5BAkFampBPo696UbZ58RAYCzvUcbcBcxhfThpt1pcdKmiQrurHj65CqmWiHzrfT12BhL3Nxb +``` + +The CLI defaults the permanent delegate to the mint authority, but you can change +it using the `authorize` command. + +```console +$ spl-token authorize 7LUgoQCqhk3VMPhpAnmS1zdCFW4C6cupxgbqWrTwydGx permanent-delegate GFMniFoE5X4F87L9jzjHaW4MTkXyX1AYHNfhFencgamg +Updating 7LUgoQCqhk3VMPhpAnmS1zdCFW4C6cupxgbqWrTwydGx + Current permanent delegate: 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn + New permanent delegate: GFMniFoE5X4F87L9jzjHaW4MTkXyX1AYHNfhFencgamg + +Signature: 2ABDrR6meXk4rrAwd2LsHaTsnM5BuTC9RbiZmgBxgzze8ZM2yxuYp8iyg8viHgVaKRbXGzjKsFjF5RR9Kkzn4Prj +``` + + + + +```jsx +import { + clusterApiUrl, + sendAndConfirmTransaction, + Connection, + Keypair, + SystemProgram, + Transaction, + LAMPORTS_PER_SOL, +} from '@solana/web3.js'; + +import { + ExtensionType, + createInitializeMintInstruction, + createInitializePermanentDelegateInstruction, + mintTo, + createAccount, + getMintLen, + TOKEN_2022_PROGRAM_ID, +} from '@solana/spl-token'; + +(async () => { + const payer = Keypair.generate(); + + const mintAuthority = Keypair.generate(); + const mintKeypair = Keypair.generate(); + const mint = mintKeypair.publicKey; + const permanentDelegate = Keypair.generate(); + + const extensions = [ExtensionType.PermanentDelegate]; + const mintLen = getMintLen(extensions); + const decimals = 9; + + const connection = new Connection(clusterApiUrl('devnet'), 'confirmed'); + + const airdropSignature = await connection.requestAirdrop(payer.publicKey, 2 * LAMPORTS_PER_SOL); + await connection.confirmTransaction({ signature: airdropSignature, ...(await connection.getLatestBlockhash()) }); + + const mintLamports = await connection.getMinimumBalanceForRentExemption(mintLen); + const mintTransaction = new Transaction().add( + SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + newAccountPubkey: mint, + space: mintLen, + lamports: mintLamports, + programId: TOKEN_2022_PROGRAM_ID, + }), + createInitializePermanentDelegateInstruction(mint, permanentDelegate.publicKey, TOKEN_2022_PROGRAM_ID), + createInitializeMintInstruction(mint, decimals, mintAuthority.publicKey, null, TOKEN_2022_PROGRAM_ID) + ); + await sendAndConfirmTransaction(connection, mintTransaction, [payer, mintKeypair], undefined); +})(); +``` + + + + +### CPI Guard + +CPI Guard is an extension that prohibits certain actions inside cross-program +invocations, to protect users from implicitly signing for actions they can't see, +hidden in programs that aren't the System or Token programs. + +Users may choose to enable or disable the CPI Guard extension on their token +account at will. When enabled, it has the following effects during CPI: + +* Transfer: the signing authority must be the account delegate +* Burn: the signing authority must be the account delegate +* Approve: prohibited +* Close Account: the lamport destination must be the account owner +* Set Close Authority: prohibited unless unsetting +* Set Owner: always prohibited, including outside CPI + +#### Background + +When interacting with a dapp, users sign transactions that are constructed by +frontend code. Given a user's signature, there are three fundamental ways for a +dapp to transfer funds from the user to the dapp (or, equivalently, burn them): + +* Insert a transfer instruction in the transaction +* Insert an approve instruction in the transaction, and perform a CPI transfer +under program authority +* Insert an opaque program instruction, and perform a CPI transfer with the user's +authorization + +The first two are safe, in that the user can see exactly what is being done, with +zero ambiguity. The third is quite dangerous. A wallet signature allows the program +to perform any action as the user, without any visibility into its actions. There +have been some attempts at workarounds, for instance, simulating the transaction +and warning about balance changes. But, fundamentally, this is intractable. + +There are two ways to make this much safer: + +* Wallets warn whenever a wallet signature is made available to an opaque +(non-system, non-token) instruction. Users should be educated to treat the request +for a signature on such an instruction as highly suspect +* The token program prohibits CPI calls with the user authority, forcing opaque +programs to directly ask for the user's authority + +The CPI Guard covers the second instance. + +#### Example: Enable CPI Guard on a token account + + + +```console +$ spl-token enable-cpi-guard 4YfkXX89TrsWqSSxb3av36Rk8EZBoDqxGzuaDNXr7UnL + +Signature: 2fohon7oraTCgBZB3dfzhpGsBobYmYPgA8nvgCqKzjqpdX6EYZaBY3VwzjNuwDpsFYYNbpTVYBjxqiaMBrvXM8S2 +``` + + +```jsx +import { + clusterApiUrl, + sendAndConfirmTransaction, + Connection, + Keypair, + SystemProgram, + Transaction, + LAMPORTS_PER_SOL, +} from '@solana/web3.js'; +import { + createMint, + createEnableCpiGuardInstruction, + createInitializeAccountInstruction, + disableCpiGuard, + enableCpiGuard, + getAccountLen, + ExtensionType, + TOKEN_2022_PROGRAM_ID, +} from '@solana/spl-token'; + +(async () => { + const connection = new Connection(clusterApiUrl('devnet'), 'confirmed'); + + const payer = Keypair.generate(); + const airdropSignature = await connection.requestAirdrop(payer.publicKey, 2 * LAMPORTS_PER_SOL); + await connection.confirmTransaction({ signature: airdropSignature, ...(await connection.getLatestBlockhash()) }); + + const mintAuthority = Keypair.generate(); + const decimals = 9; + const mint = await createMint( + connection, + payer, + mintAuthority.publicKey, + mintAuthority.publicKey, + decimals, + undefined, + undefined, + TOKEN_2022_PROGRAM_ID + ); + + const accountLen = getAccountLen([ExtensionType.CpiGuard]); + const lamports = await connection.getMinimumBalanceForRentExemption(accountLen); + + const owner = Keypair.generate(); + const destinationKeypair = Keypair.generate(); + const destination = destinationKeypair.publicKey; + const transaction = new Transaction().add( + SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + newAccountPubkey: destination, + space: accountLen, + lamports, + programId: TOKEN_2022_PROGRAM_ID, + }), + createInitializeAccountInstruction(destination, mint, owner.publicKey, TOKEN_2022_PROGRAM_ID), + createEnableCpiGuardInstruction(destination, owner.publicKey, [], TOKEN_2022_PROGRAM_ID) + ); + + await sendAndConfirmTransaction(connection, transaction, [payer, owner, destinationKeypair], undefined); + + // OR + await enableCpiGuard(connection, payer, destination, owner, [], undefined, TOKEN_2022_PROGRAM_ID); +})(); +``` + + + +#### Example: Disable CPI Guard on a token account + + + +```console +$ spl-token disable-cpi-guard 4YfkXX89TrsWqSSxb3av36Rk8EZBoDqxGzuaDNXr7UnL + +Signature: 4JJSBSc1UAtArbBqYRpTk9264WwJuZ8n6NqyXtCSmyVQpmHoetzyVDwHxtxrdK8wQawoocDxFD9rRPhpAMzJ6EdG +``` + + +```jsx + await disableCpiGuard(connection, payer, destination, owner, [], undefined, TOKEN_2022_PROGRAM_ID); +``` + + + +### Transfer Hook + +#### Motivation + +Token creators may need more control over how their token is transferred. The +most prominent use case revolves around NFT royalties. Whenever a token is moved, +the creator should be entitled to royalties, but due to the design of the current +token program, it's impossible to stop a transfer at the protocol level. + +Current solutions typically resort to perpetually freezing tokens, which requires +a whole proxy layer to interact with the token. Wallets and marketplaces need +to be aware of the proxy layer in order to properly use the token. + +Worse still, different royalty systems have different proxy layers for using +their token. All in all, these systems harm composability and make development +harder. + +#### Solution + +To improve the situation, Token-2022 introduces the concept of the +[transfer-hook interface](../transfer-hook-interface) +and extension. A token creator must develop and deploy a program that +implements the interface and then configure their token mint to use their program. + +During transfer, Token-2022 calls into the program with the accounts specified +at a well-defined program-derived address for that mint and program id. This +call happens after all other transfer logic, so the accounts reflect the *end* +state of the transfer. + +When interacting with a transfer-hook program, it's possible to send an +instruction - such as `Execute` (transfer) - to the program with only the +accounts required for the `Transfer` instruction, and any extra accounts that +the program may require are automatically resolved on-chain! This process is +explained in detail in many of the linked `README` files below under +**Resources**. + +#### Resources + +The interface description and structs exist at +[spl-transfer-hook-interface](https://github.com/solana-program/transfer-hook/tree/main/interface), +along with a sample minimal program implementation. You can find detailed +instructions on how to implement this interface for an on-chain program or +interact with a program that implements transfer-hook in the repository's +[README](https://github.com/solana-program/transfer-hook/tree/main/interface/README.md). + +The `spl-transfer-hook-interface` library provides offchain and onchain helpers +for resolving the additional accounts required. See +[onchain.rs](https://github.com/solana-program/transfer-hook/blob/main/interface/src/onchain.rs) +for usage on-chain, and +[offchain.rs](https://github.com/solana-program/transfer-hook/blob/main/interface/src/offchain.rs) +for fetching the additional required account metas with any async off-chain client +like `BanksClient` or `RpcClient`. + +A usable example program exists at +[spl-transfer-hook-example](https://github.com/solana-program/transfer-hook/tree/main/program). +Token-2022 uses this example program in tests to ensure that it properly uses +the transfer hook interface. + +The example program and the interface are powered by the +[spl-tlv-account-resolution](https://github.com/solana-program/libraries/tree/main/tlv-account-resolution) +library, which is explained in detail in the repository's +[README](https://github.com/solana-program/libraries/tree/main/tlv-account-resolution/README.md) + +#### Example: Create a mint with a transfer hook + + + + +```console +$ spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token --transfer-hook 7N4HggYEJAtCLJdnHGCtFqfxcB5rhQCsQTze3ftYstVj +Creating token HFg1FFaj4PqFHmkYrqbZsarNJEZT436aXAXgQFMJihwc under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb + +Address: HFg1FFaj4PqFHmkYrqbZsarNJEZT436aXAXgQFMJihwc +Decimals: 9 + +Signature: 3ug4Ejs16jJgEm1WyBwDDxzh9xqPzQ3a2cmy1hSYiPFcLQi9U12HYF1Dbhzb2bx75SSydfU6W4e11dGUXaPbJqVc +``` + + + + +```jsx +import { + clusterApiUrl, + sendAndConfirmTransaction, + Connection, + Keypair, + PublicKey, + SystemProgram, + Transaction, + LAMPORTS_PER_SOL, +} from '@solana/web3.js'; + +import { + ExtensionType, + createInitializeMintInstruction, + createInitializeTransferHookInstruction, + mintTo, + createAccount, + getMintLen, + TOKEN_2022_PROGRAM_ID, +} from '@solana/spl-token'; + +(async () => { + const payer = Keypair.generate(); + + const mintAuthority = Keypair.generate(); + const mintKeypair = Keypair.generate(); + const mint = mintKeypair.publicKey; + + const extensions = [ExtensionType.TransferHook]; + const mintLen = getMintLen(extensions); + const decimals = 9; + const transferHookProgramId = new PublicKey('7N4HggYEJAtCLJdnHGCtFqfxcB5rhQCsQTze3ftYstVj') + + const connection = new Connection(clusterApiUrl('devnet'), 'confirmed'); + + const airdropSignature = await connection.requestAirdrop(payer.publicKey, 2 * LAMPORTS_PER_SOL); + await connection.confirmTransaction({ signature: airdropSignature, ...(await connection.getLatestBlockhash()) }); + + const mintLamports = await connection.getMinimumBalanceForRentExemption(mintLen); + const mintTransaction = new Transaction().add( + SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + newAccountPubkey: mint, + space: mintLen, + lamports: mintLamports, + programId: TOKEN_2022_PROGRAM_ID, + }), + createInitializeTransferHookInstruction(mint, payer.publicKey, transferHookProgramId, TOKEN_2022_PROGRAM_ID), + createInitializeMintInstruction(mint, decimals, mintAuthority.publicKey, null, TOKEN_2022_PROGRAM_ID) + ); + await sendAndConfirmTransaction(connection, mintTransaction, [payer, mintKeypair], undefined); +})(); +``` + + + + +#### Example: Update transfer-hook program in mint + + + + +```console +$ spl-token set-transfer-hook HFg1FFaj4PqFHmkYrqbZsarNJEZT436aXAXgQFMJihwc EbPBt3XkCb9trcV4c8fidhrvoeURbDbW87Acustzyi8N + +Signature: 3Ffw6yjseDsL3Az5n2LjdwXXwVPYxDF3JUU1JC1KGAEb1LE68S9VN4ebtAyvKeYMHvhjdz1LJVyugGNdWHyotzay +``` + + + + +```js +await updateTransferHook( + connection, + payer, mint, + newTransferHookProgramId, + payer.publicKey, + [], + undefined, + TOKEN_2022_PROGRAM_ID +); +``` + + + + +#### Example: Manage a transfer-hook program + +A sample CLI for managing a transfer-hook program exists at +[spl-transfer-hook-cli](https://github.com/solana-program/transfer-hook/tree/main/clients/cli). +A mint manager can fork the tool for their own program. + +It only contains a command to create the required transfer-hook account for the +mint. + +First, you must build the transfer-hook program and deploy it: + +```console +$ cargo build-sbf +$ solana program deploy target/deploy/spl-transfer-hook-example.so +``` + +After that, you can initialize the transfer-hook account: + +```console +$ spl-transfer-hook create-extra-metas [: ...] +``` + +### Metadata Pointer + +With the potential proliferation of multiple metadata programs, a mint can have +multiple different accounts all claiming to describe the mint. + +To make it easy for clients to distinguish, the metadata pointer extension allows +a token creator to designate an address that describes the canonical metadata. +As you'll see in the "Metadata" section, this address can be the mint itself! + +To avoid phony mints claiming to be stablecoins, however, a client must check +that the mint and the metadata both point to each other. + +#### Example: Create a mint with a metadata pointer to an external account + + + + +```console +$ spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token --metadata-address 7N4HggYEJAtCLJdnHGCtFqfxcB5rhQCsQTze3ftYstVj +Creating token HFg1FFaj4PqFHmkYrqbZsarNJEZT436aXAXgQFMJihwc under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb + +Address: HFg1FFaj4PqFHmkYrqbZsarNJEZT436aXAXgQFMJihwc +Decimals: 9 + +Signature: 3ug4Ejs16jJgEm1WyBwDDxzh9xqPzQ3a2cmy1hSYiPFcLQi9U12HYF1Dbhzb2bx75SSydfU6W4e11dGUXaPbJqVc +``` + + + + +Coming soon! + + + + +### Metadata + +To facilitate token-metadata usage, Token-2022 allows a mint creator to include +their token's metadata directly in the mint account. + +Token-2022 implements all of the instructions from the +[spl-token-metadata-interface](https://github.com/solana-program/token-metadata/tree/main/interface). + +The metadata extension should work directly with the metadata-pointer extension. +During mint creation, you should also add the metadata-pointer extension, pointed +at the mint itself. + +The tools do this for you automatically. + +#### Example: Create a mint with metadata + + + + +```console +$ spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token --enable-metadata +Creating token 5K8RVdjpY3CHujyKjQ7RkyiCJqTG8Kba9krNfpZnmvpS under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb +To initialize metadata inside the mint, please run `spl-token initialize-metadata 5K8RVdjpY3CHujyKjQ7RkyiCJqTG8Kba9krNfpZnmvpS `, and sign with the mint authority + +Address: 5K8RVdjpY3CHujyKjQ7RkyiCJqTG8Kba9krNfpZnmvpS +Decimals: 9 + +Signature: 2BZH8KE7zVcBj7Mmnu6uCM9NT4ey7qHasZmEk6Bt3tyx1wKCXS3JtcgEvrXXEMFB5numQgA9wvR67o2Z4YQdEw7m + +$ spl-token initialize-metadata 5K8RVdjpY3CHujyKjQ7RkyiCJqTG8Kba9krNfpZnmvpS MyTokenName TOKEN http://my.token --update-authority 3pGiHDDek35npQuyWQ7FGcWxqJdHvVPDHDDmBFs2YxQj +Signature: 2H16XtBqdwSbvvq8g5o2jhy4TknP6zgt71KHawEdyPvNuvusQrV4dPccUrMqjFeNTbk75AtzmzUVueH3yWiTjBCG +``` + + + + +```js +import { + clusterApiUrl, + Connection, + Keypair, + LAMPORTS_PER_SOL, + sendAndConfirmTransaction, + SystemProgram, + Transaction, +} from '@solana/web3.js'; +import { + createInitializeMetadataPointerInstruction, + createInitializeMintInstruction, + ExtensionType, + getMintLen, + LENGTH_SIZE, + TOKEN_2022_PROGRAM_ID, + TYPE_SIZE, +} from '@solana/spl-token'; +import { createInitializeInstruction, pack, TokenMetadata } from '@solana/spl-token-metadata'; + +(async () => { + const payer = Keypair.generate(); + + const mint = Keypair.generate(); + const decimals = 9; + + const metadata: TokenMetadata = { + mint: mint.publicKey, + name: 'TOKEN_NAME', + symbol: 'SMBL', + uri: 'URI', + additionalMetadata: [['new-field', 'new-value']], + }; + + const mintLen = getMintLen([ExtensionType.MetadataPointer]); + + const metadataLen = TYPE_SIZE + LENGTH_SIZE + pack(metadata).length; + + const connection = new Connection(clusterApiUrl('devnet'), 'confirmed'); + + const airdropSignature = await connection.requestAirdrop(payer.publicKey, 2 * LAMPORTS_PER_SOL); + await connection.confirmTransaction({ + signature: airdropSignature, + ...(await connection.getLatestBlockhash()), + }); + + const mintLamports = await connection.getMinimumBalanceForRentExemption(mintLen + metadataLen); + const mintTransaction = new Transaction().add( + SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + newAccountPubkey: mint.publicKey, + space: mintLen, + lamports: mintLamports, + programId: TOKEN_2022_PROGRAM_ID, + }), + createInitializeMetadataPointerInstruction(mint.publicKey, payer.publicKey, mint.publicKey, TOKEN_2022_PROGRAM_ID), + createInitializeMintInstruction(mint.publicKey, decimals, payer.publicKey, null, TOKEN_2022_PROGRAM_ID), + createInitializeInstruction({ + programId: TOKEN_2022_PROGRAM_ID, + mint: mint.publicKey, + metadata: mint.publicKey, + name: metadata.name, + symbol: metadata.symbol, + uri: metadata.uri, + mintAuthority: payer.publicKey, + updateAuthority: payer.publicKey, + }), + ); + await sendAndConfirmTransaction(connection, mintTransaction, [payer, mint]); +})(); +``` + + + + +#### Example: Update a field + + + + +```console +$ spl-token update-metadata 5K8RVdjpY3CHujyKjQ7RkyiCJqTG8Kba9krNfpZnmvpS name YourToken +Signature: 2H16XtBqdwSbvvq8g5o2jhy4TknP6zgt71KHawEdyPvNuvusQrV4dPccUrMqjFeNTbk75AtzmzUVueH3yWiTjBCG +``` + + + +```js +import { createUpdateFieldInstruction } from "@solana/spl-token-metadata"; + +(async () => { + const tx = new Transaction().add( + createUpdateFieldInstruction({ + metadata: mint.publicKey, + updateAuthority: payer.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + field: 'name', + value: 'YourToken', + }), + ); + await sendAndConfirmTransaction(connection, tx, [ payer, mint ]); +})(); +``` + + + + +#### Example: Add a custom field + + + + +```console +$ spl-token update-metadata 5K8RVdjpY3CHujyKjQ7RkyiCJqTG8Kba9krNfpZnmvpS new-field new-value +Signature: 31uerYNa6yhb21k5CCX69k7RLUKEhJEV99UadEpPnZtWWpykwr7vkTFkuFeJ7AaEyQPrepe8m8xr4N23JEAeuTRY +``` + + + +```js +import { createUpdateFieldInstruction } from "@solana/spl-token-metadata"; + +(async () => { + const tx = new Transaction().add( + createUpdateFieldInstruction({ + metadata: mint.publicKey, + updateAuthority: payer.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + field: 'new-field', + value: 'new-value', + }), + ); + await sendAndConfirmTransaction(connection, tx, [ payer, mint ]); +})(); +``` + + + + +#### Example: Remove a custom field + + + + +```console +$ spl-token update-metadata 5K8RVdjpY3CHujyKjQ7RkyiCJqTG8Kba9krNfpZnmvpS new-field --remove +Signature: 52s1mxRqnr2jcZNvcmcgsQuXfVyT2w1TuRsEE3J6YwEZBu74BbFcHh2DvwnJG7qC7Cy6C5ZrTfnoPREFjFS7kXjF +``` + + + +```js +import { createRemoveKeyInstruction } from "@solana/spl-token-metadata"; + +(async () => { + const tx = new Transaction().add( + createRemoveKeyInstruction({ + programId: TOKEN_2022_PROGRAM_ID, + metadata: mint.publicKey, + updateAuthority: payer.publicKey, + key: 'new-field', + idempotent: true, // If false the operation will fail if the field does not exist in the metadata + }), + ); + await sendAndConfirmTransaction(connection, tx, [ payer, mint ]); +})(); +``` + + + + +### Group Pointer + +Similar to the metadata pointer, the group pointer allows a token creator to +designate a group account that describes the mint. However, rather than +describing token metadata, the group account describes configurations for +grouping tokens together. + +When a Token-2022 mint possesses a group pointer, the mint is considered to be +a group mint (for example a Collection NFT). Group mints have configurations +that allow them to be used as a point of reference for a related set of tokens. + +Similar to metadata, the group pointer can point to the mint itself, and a +client must check that the mint and the group both point to each other. + +#### Example: Create a mint with a group pointer to an external account + + + + +```console +$ spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token --group-address 7ZJVSav7y76M41eFeyA3xz39UDigQspVNwyJ469TgR1S +Creating token EUMhJgfvjZa7Lb7fSqfD6WCUwELzzRVKunKSnSi4xK42 under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb + +Address: EUMhJgfvjZa7Lb7fSqfD6WCUwELzzRVKunKSnSi4xK42 +Decimals: 9 + +Signature: 3ug4Ejs16jJgEm1WyBwDDxzh9xqPzQ3a2cmy1hSYiPFcLQi9U12HYF1Dbhzb2bx75SSydfU6W4e11dGUXaPbJqVc +``` + + + + +Coming soon! + + + + +### Group + +Token-2022 supports grouping of tokens through the group extension. The +configurations for a group, which describe things like the update authority +and the group's maximum size, can be stored directly in the mint itself. + +Token-2022 implements all of the instructions from the +[spl-token-group-interface](https://github.com/solana-program/token-group/tree/main/interface). + +The group extension works directly with the group-pointer extension. +To initialize group configurations within a mint, you must add the group-pointer +extension, pointed at the mint itself, during mint creation. + +The tools do this for you automatically. + +#### Example: Create a mint with group configurations + + + + +```console +$ spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token --enable-group +Creating token 812A34SxxYx9KqFwUNAuW7Wpwtmuj2pc5u1TGQcvPnj3 under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb +To initialize group configurations inside the mint, please run `spl-token initialize-group 812A34SxxYx9KqFwUNAuW7Wpwtmuj2pc5u1TGQcvPnj3 `, and sign with the mint authority. + +Address: 812A34SxxYx9KqFwUNAuW7Wpwtmuj2pc5u1TGQcvPnj3 +Decimals: 9 + +Signature: 2BZH8KE7zVcBj7Mmnu6uCM9NT4ey7qHasZmEk6Bt3tyx1wKCXS3JtcgEvrXXEMFB5numQgA9wvR67o2Z4YQdEw7m + +$ spl-token initialize-group 812A34SxxYx9KqFwUNAuW7Wpwtmuj2pc5u1TGQcvPnj3 12 --update-authority 3pGiHDDek35npQuyWQ7FGcWxqJdHvVPDHDDmBFs2YxQj +Signature: 2H16XtBqdwSbvvq8g5o2jhy4TknP6zgt71KHawEdyPvNuvusQrV4dPccUrMqjFeNTbk75AtzmzUVueH3yWiTjBCG +``` + + + + +Coming soon! + + + + +### Member Pointer + +Similar to the metadata pointer and group pointer, the member pointer allows a +token creator to designate a member account that describes the mint. This +pointer describes configurations for a mint's membership of a group. + +When a Token-2022 mint possesses a member pointer, the mint is considered to be +a member mint (for example an NFT that belongs to a collection). + +Similar to metadata and group, the member pointer can point to the mint itself, +and a client must check that the mint and the member both point to each other. + +#### Example: Create a mint with a member pointer to an external account + + + + +```console +$ spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token --member-address CXWuFdWifFQSvMMZ3UxZZVKtjYi2bZt89f5v3yV8zdVE +Creating token 5anZzJbbj6rBkrXW7zzw7MH28xXufj7AB5oKX1Cv4fdh under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb + +Address: 5anZzJbbj6rBkrXW7zzw7MH28xXufj7AB5oKX1Cv4fdh +Decimals: 9 + +Signature: 3ug4Ejs16jJgEm1WyBwDDxzh9xqPzQ3a2cmy1hSYiPFcLQi9U12HYF1Dbhzb2bx75SSydfU6W4e11dGUXaPbJqVc +``` + + + + +Coming soon! + + + + +### Member + +The member extension also plays a key role in managing groups of tokens with +Token-2022. The configurations for a member, which describe things like the +group address and the member's number, can be stored directly in the mint +itself. + +The member extension, like the group extension, works directly with the +member-pointer extension. To initialize member configurations within a mint, +you must add the member-pointer extension, pointed at the mint itself, during +mint creation. + +The tools do this for you automatically. + +#### Example: Create a mint with member configurations + + + + +```console +$ spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token --enable-member +Creating token 9uyqmf9Ued4yQKi4hXT5wMzPF5Nv1S6skAjkjxcCaAyV under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb +To initialize group member configurations inside the mint, please run `spl-token initialize-member 9uyqmf9Ued4yQKi4hXT5wMzPF5Nv1S6skAjkjxcCaAyV`, and sign with the mint authority. + +Address: 9uyqmf9Ued4yQKi4hXT5wMzPF5Nv1S6skAjkjxcCaAyV +Decimals: 9 + +Signature: 2BZH8KE7zVcBj7Mmnu6uCM9NT4ey7qHasZmEk6Bt3tyx1wKCXS3JtcgEvrXXEMFB5numQgA9wvR67o2Z4YQdEw7m + +$ spl-token initialize-member 9uyqmf9Ued4yQKi4hXT5wMzPF5Nv1S6skAjkjxcCaAyV --update-authority 3pGiHDDek35npQuyWQ7FGcWxqJdHvVPDHDDmBFs2YxQj +Signature: 2H16XtBqdwSbvvq8g5o2jhy4TknP6zgt71KHawEdyPvNuvusQrV4dPccUrMqjFeNTbk75AtzmzUVueH3yWiTjBCG +``` + + + + +Coming soon! + + + diff --git a/docs/src/token-2022/onchain.md b/docs/src/token-2022/onchain.md index fbf39685730..bf750fb48b5 100644 --- a/docs/src/token-2022/onchain.md +++ b/docs/src/token-2022/onchain.md @@ -2,4 +2,765 @@ title: On-chain Program Guide --- -Coming soon! +## Supporting Token and Token-2022 Together In Your Program + +This guide is meant for on-chain program / dapp developers who want to support +Token and Token-2022 concurrently. + +## Prerequisites + +This guide requires the Solana CLI tool suite, minimum version 1.10.33 in order +to support all Token-2022 features. + +## Motivation + +On-chain program developers are accustomed to only including one token program, +to be used for all tokens in the application. + +With the addition of Token-2022, developers must update on-chain programs. This +guide walks through the steps required to support both. + +Important note: if you do not wish to support Token-2022, there is nothing to do. +Your existing on-chain program will loudly fail if an instruction includes any +Token-2022 mints / accounts. + +Most likely, your program will fail with `ProgramError::IncorrectProgramId` while +trying to create a CPI instruction into the Token program, providing the Token-2022 +program id. + +## Structure of this Guide + +To safely code the transition, we'll follow a test-driven development approach: + +- add a dependency to `spl-token-2022` +- change tests to use `spl_token::id()` or `spl_token_2022::id()`, see that all + tests fail with Token-2022 +- update on-chain program code to always use the instruction and deserializers from + `spl_token_2022`, make all tests pass + +Optionally, if an instruction uses more than one token mint, common to most DeFi, +you must add an input token program account for each additional mint. Since it's +possible to swap all types of tokens, we need to either invoke the correct token +program. + +Everything here will reference real commits to the token-swap program, so +feel free to follow along and make the changes to your program. + +## Part I: Support both token programs in single-token use cases + +### Step 1: Update dependencies + +In your `Cargo.toml`, add the latest `spl-token-2022` to your `dependencies`. +Check for the latest version of `spl-token-2022` in [crates.io](https://crates.io), since +that will typically be the version deployed to mainnet-beta. + +### Step 2: Add test cases for Token and Token-2022 + +Using the `test-case` crate, you can update all tests to use both Token and +Token-2022. For example, a test defined as: + +``` +#[tokio::test] +async fn test_swap() { + ... +} +``` + +Will become: + +``` +#[test_case(spl_token::id() ; "Token Program")] +#[test_case(spl_token_2022::id() ; "Token-2022 Program")] +#[tokio::test] +async fn test_swap(token_program_id: Pubkey) { + ... +} +``` + +In your program-test setup, you must include `spl_token_2022.so` at the correct +address. You can add it as normal to `tests/fixtures/` after downloading it using: + +```console +$ solana program dump TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb spl_token_2022.so +``` + +If you're using `solana-test-validator` for your tests, you can include it using: + +```console +$ solana-test-validator -c TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb +``` + +**Note**: This step is temporary, until Token-2022 is included by default in +`program-test` and `solana-test-validator`. + +The token-swap does not use `program-test`, so there's a bit more +boilerplate, but the same principle applies. + +### Step 3: Replace instruction creators + +Everywhere in the code that uses `spl_token::instruction` must now use +`spl_token_2022::instruction`. The `"Token-2022 Program"` tests will still fail, +but importantly, the `"Token Program"` tests will pass using the new instruction +creators. + +If your program uses unchecked transfers, you'll see a deprecation warning: + +``` +warning: use of deprecated function `spl_token_2022::instruction::transfer`: please use `transfer_checked` or `transfer_checked_with_fee` instead +``` + +If a token has a transfer fee, an unchecked transfer will fail. We'll fix that +later. If you want, in the meantime, feel free to add an `#[allow(deprecated)]` +to pass CI, with a TODO or issue to transition to `transfer_checked` everywhere. + +### Step 4: Replace spl_token::id() with a parameter + +Step 2 started the transition away from a fixed program id by adding +`token_program_id` as a parameter to the test function, but now you'll go +through your program and tests to use it everywhere. + +Whenever `spl_token::id()` appears in the code, use a parameter corresponding +either to `spl_token::id()` or `spl_token_2022::id()`. + +After this, all of your tests should pass! Not so fast though, there's one more +step needed to ensure compatibility. + +### Step 5: Add Extensions to Tests + +Although all of your tests are passing, you still need to account for differences +in accounts in token-2022. + +Account extensions are stored after the first 165 bytes of the account, and the +normal `Account::unpack` and `Mint::unpack` will fail if the size of the account +is not exactly 165 and 82, respectively. + +Let's make the tests fail again by adding an extension to all mint and token +accounts. We'll add the `MintCloseAuthority` extension to mints, and the `ImmutableOwner` +extension to accounts. + +When creating mint accounts, calculate the space required before allocating, then +include an `initialize_mint_close_authority` instruction before `initialize_mint`. +For example this could be: + +```rust +use spl_token_2022::{extension::ExtensionType, instruction::*, state::Mint}; +use solana_sdk::{system_instruction, transaction::Transaction}; + +// Calculate the space required using the `ExtensionType` +let space = ExtensionType::try_calculate_account_len::(&[ExtensionType::MintCloseAuthority]).unwrap(); + +// get the Rent object and calculate the rent required +let rent_required = rent.minimum_balance(space); + +// and then create the account using those parameters +let create_instruction = system_instruction::create_account(&payer.pubkey(), mint_pubkey, rent_required, space, token_program_id); + +// Important: you must initialize the mint close authority *BEFORE* initializing the mint, +// and only when working with Token-2022, since the instruction is unsupported by Token. +let initialize_close_authority_instruction = initialize_mint_close_authority(token_program_id, mint_pubkey, Some(close_authority)).unwrap(); +let initialize_mint_instruction = initialize_mint(token_program_id, mint_pubkey, mint_authority_pubkey, freeze_authority, 9).unwrap(); + +// Make the transaction with all of these instructions +let create_mint_transaction = Transaction::new(&[create_instruction, initialize_close_authority_instruction, initialize_mint_instruction], Some(&payer.pubkey)); + +// Sign it and send it however you want! +``` + +The concept is similar with token accounts, but we'll use the `ImmutableOwner` +extension, which is actually supported by both programs, but `Tokenkeg...` will +no-op. + +```rust +use spl_token_2022::{extension::ExtensionType, instruction::*, state::Account}; +use solana_sdk::{system_instruction, transaction::Transaction}; + +// Calculate the space required using the `ExtensionType` +let space = ExtensionType::try_calculate_account_len::(&[ExtensionType::ImmutableOwner]).unwrap(); + +// get the Rent object and calculate the rent required +let rent_required = rent.minimum_balance(space); + +// and then create the account using those parameters +let create_instruction = system_instruction::create_account(&payer.pubkey(), account_pubkey, rent_required, space, token_program_id); + +// Important: you must initialize immutable owner *BEFORE* initializing the account +let initialize_immutable_owner_instruction = initialize_immutable_owner(token_program_id, account_pubkey).unwrap(); +let initialize_account_instruction = initialize_account(token_program_id, account_pubkey, mint_pubkey, owner_pubkey).unwrap(); + +// Make the transaction with all of these instructions +let create_account_transaction = Transaction::new(&[create_instruction, initialize_immutable_owner_instruction, initialize_account_instruction], Some(&payer.pubkey)); + +// Sign it and send it however you want! +``` + +After making these changes, everything fails again. Well done! + +### Step 6: Use `StateWithExtensions` instead of `Mint` and `Account` + +The test failures happen because the program is trying to deserialize a pure +`Mint` or `Account`, and failing because there are extensions added to it. + +Token-2022 adds a new type called `StateWithExtensions`, which allows you to +deserialize the base type, and then pull out any extensions on the fly. It's +very close to the same cost as the normal `unpack`. + +Everywhere in your code, wherever you see `Mint::unpack` or `Account::unpack`, +you'll have to change that to: + +```rust +use spl_token_2022::{extension::StateWithExtensions, state::{Account, Mint}}; +let account_state = StateWithExtensions::::unpack(&token_account_info.data.borrow())?; +let mint_state = StateWithExtensions::::unpack(&mint_account_info.data.borrow())?; +``` + +Anytime you access fields in the state, you'll need to go through the `base`. For +example, to access the amount, you must do: + +```rust +let token_amount = account_state.base.amount; +``` + +So typically, you'll just need to add in `.base` wherever those fields are accessed. + +Once that's done, all of your tests should pass! Congratulations, your program +is now compatible with Token-2022! + +If your program is using multiple token types at once, however, you will need to +do more work. + +## Part II: Support Mixed Token Programs: trading a Token for a Token-2022 + +In Part I, we looked at the minimal amount of work to support Token-2022 in your +program. This work won't cover all cases, however. Specifically, in the token-swap +program, most instructions involve multiple token types. If those token types are +from different token programs, then our current implementation will fail. + +For example, if you want to swap tokens from the Token program for tokens from +the Token-2022 program, then your program's instruction must provide each token +program, so that your program may invoke them. + +Let's go through the steps to support both token programs in the same instruction. + +### Step 1: Update all instruction interfaces + +The first step is to update all instruction interfaces to accept a token program +for each token type used in the program. + +For example, here is the previous definition for the `Swap` instruction: + +```rust +/// Swap the tokens in the pool. +/// +/// 0. `[]` Token-swap +/// 1. `[]` swap authority +/// 2. `[]` user transfer authority +/// 3. `[writable]` token_(A|B) SOURCE Account, amount is transferable by user transfer authority, +/// 4. `[writable]` token_(A|B) Base Account to swap INTO. Must be the SOURCE token. +/// 5. `[writable]` token_(A|B) Base Account to swap FROM. Must be the DESTINATION token. +/// 6. `[writable]` token_(A|B) DESTINATION Account assigned to USER as the owner. +/// 7. `[writable]` Pool token mint, to generate trading fees +/// 8. `[writable]` Fee account, to receive trading fees +/// 9. `[]` Token program id +/// 10. `[optional, writable]` Host fee account to receive additional trading fees +Swap { + pub amount_in: u64, + pub minimum_amount_out: u64 +} +``` + +`Swap` contains 3 different token types: token A, token B, and the pool token. Let's +add a separate token program for each, transforming the instruction into: + +```rust +/// Swap the tokens in the pool. +/// +/// 0. `[]` Token-swap +/// 1. `[]` swap authority +/// 2. `[]` user transfer authority +/// 3. `[writable]` token_(A|B) SOURCE Account, amount is transferable by user transfer authority, +/// 4. `[writable]` token_(A|B) Base Account to swap INTO. Must be the SOURCE token. +/// 5. `[writable]` token_(A|B) Base Account to swap FROM. Must be the DESTINATION token. +/// 6. `[writable]` token_(A|B) DESTINATION Account assigned to USER as the owner. +/// 7. `[writable]` Pool token mint, to generate trading fees +/// 8. `[writable]` Fee account, to receive trading fees +/// 9. `[]` Token (A|B) SOURCE program id +/// 10. `[]` Token (A|B) DESTINATION program id +/// 11. `[]` Pool Token program id +/// 12. `[optional, writable]` Host fee account to receive additional trading fees +Swap { + pub amount_in: u64, + pub minimum_amount_out: u64 +} +``` + +Note the new inputs of `9.` and `10.`, and the clarification on `11`. + +All of these additional accounts may make you wonder: how big will transactions +get with these new accounts? If you are using both Token and Token-2022, +the additional Token-2022 program will take up space in the transaction, +32 bytes for the pubkey, and 1 byte for its index. + +On the flip side, if you're only using one token program at once, you will only +incur 1 byte of overhead because of the deduplication of accounts in the Solana +transaction format. + +Also note that some instructions will remain unchanged. For example, here is the +`Initialize` instruction: + +```rust +/// Initializes a new swap +/// +/// 0. `[writable, signer]` New Token-swap to create. +/// 1. `[]` swap authority derived from `create_program_address(&[Token-swap account])` +/// 2. `[]` token_a Account. Must be non zero, owned by swap authority. +/// 3. `[]` token_b Account. Must be non zero, owned by swap authority. +/// 4. `[writable]` Pool Token Mint. Must be empty, owned by swap authority. +/// 5. `[]` Pool Token Account to deposit trading and withdraw fees. +/// Must be empty, not owned by swap authority +/// 6. `[writable]` Pool Token Account to deposit the initial pool token +/// supply. Must be empty, not owned by swap authority. +/// 7. `[]` Token program id +Initialize { ... } // details omitted +``` + +Although we pass in token A and token B accounts, we don't actually need to invoke +their respective token programs. We do, however, mint new pool tokens, so we must +pass in the token program for the pool token mint. + +This step is mostly churn since interfaces must be updated. Don't worry if some +tests fail after this step. We'll fix them in the next step. + +### Step 2: Update instruction processors + +If your instruction processor is expecting accounts after the added token programs, +you may see some test failures. + +Specifically, in the token-swap example, the `Swap` instruction is expecting +an optional account at the end, which has been clobbered by the added token +programs. + +For this step, we'll simply pull out all of the new provided accounts. For example, +in the `Swap` instruction processor, we'll go from: + +```rust +let account_info_iter = &mut accounts.iter(); +let swap_info = next_account_info(account_info_iter)?; +let authority_info = next_account_info(account_info_iter)?; +let user_transfer_authority_info = next_account_info(account_info_iter)?; +let source_info = next_account_info(account_info_iter)?; +let swap_source_info = next_account_info(account_info_iter)?; +let swap_destination_info = next_account_info(account_info_iter)?; +let destination_info = next_account_info(account_info_iter)?; +let pool_mint_info = next_account_info(account_info_iter)?; +let pool_fee_account_info = next_account_info(account_info_iter)?; +let token_program_info = next_account_info(account_info_iter)?; +``` + +To: + +```rust +let account_info_iter = &mut accounts.iter(); +let swap_info = next_account_info(account_info_iter)?; +let authority_info = next_account_info(account_info_iter)?; +let user_transfer_authority_info = next_account_info(account_info_iter)?; +let source_info = next_account_info(account_info_iter)?; +let swap_source_info = next_account_info(account_info_iter)?; +let swap_destination_info = next_account_info(account_info_iter)?; +let destination_info = next_account_info(account_info_iter)?; +let pool_mint_info = next_account_info(account_info_iter)?; +let pool_fee_account_info = next_account_info(account_info_iter)?; +let source_token_program_info = next_account_info(account_info_iter)?; // added +let destination_token_program_info = next_account_info(account_info_iter)?; // added +let pool_token_program_info = next_account_info(account_info_iter)?; // renamed +``` + +For now, just use one of those. For example, we'll just use `pool_token_program_info` +everywhere. In the next step, we'll add some tests which will properly fail since +we're always using the same token program. + +Once again, all of your tests should pass! But not for long. + +### Step 3: Write tests using multiple token programs at once + +In the spirit of test-driven development, let's start by writing some failing +tests. + +Previously, our `test_case`s defined only provided one program id. Now it's +time to mix them up and add more cases. For full coverage, we could do all +permutations of different programs, but let's go with: + +- all mints belong to Token +- all mints belong to Token-2022 +- the pool mint belongs to Token, but token A and B belong to Token-2022 +- the pool mint belongs to Token-2022, but token A and B are mixed + +Let's update test cases to pass in three different program ids, and then use them +in the tests. For example, that means transforming: + +```rust +#[test_case(spl_token::id(); "token")] +#[test_case(spl_token_2022::id(); "token-2022")] +fn test_initialize(token_program_id: Pubkey) { +``` + +Into: + +```rust +#[test_case(spl_token::id(), spl_token::id(), spl_token::id(); "all-token")] +#[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token_2022::id(); "all-token-2022")] +#[test_case(spl_token::id(), spl_token_2022::id(), spl_token_2022::id(); "mixed-pool-token")] +#[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token::id(); "mixed-pool-token-2022")] +fn test_initialize(pool_token_program_id: Pubkey, token_a_program_id: Pubkey, token_b_program_id: Pubkey) { + ... +} +``` + +This step may also involve churn, but take your time to go through it carefully, +and you'll have failing tests for the `mixed-pool-token` and `mixed-pool-token-2022` +test cases. + +### Step 4: Use appropriate token program in your processor + +Let's fix the failing tests! The errors come up because we're trying to operate +on tokens with the wrong program in a "mixed" Token and Token-2022 environment. + +We need to properly use all of the `pool_token_program_info` / `token_a_program_info` +variables that we extracted in Step 2. + +In the token-swap example, we'll check anywhere we filled in `pool_token_program_info` +by default, and instead choose the correct program info. For example, when +transferring the source tokens in `process_swap`, we currently have: + +```rust +Self::token_transfer( + swap_info.key, + pool_token_program_info.clone(), + source_info.clone(), + swap_source_info.clone(), + user_transfer_authority_info.clone(), + token_swap.bump_seed(), + to_u64(result.source_amount_swapped)?, +)?; +``` + +Let's use the correct token program, making this: + +```rust +Self::token_transfer( + swap_info.key, + source_token_program_info.clone(), + source_info.clone(), + swap_source_info.clone(), + user_transfer_authority_info.clone(), + token_swap.bump_seed(), + to_u64(result.source_amount_swapped)?, +)?; +``` + +While going through this, if you notice any owner checks for a token account or mint +in the form of: + +```rust +if token_account_info.owner != &spl_token::id() { ... } +``` + +You'll need to update to a new owner check from `spl_token_2022`: + +```rust +if spl_token_2022::check_spl_token_program_account(token_account_info.owner).is_err() { ... } +``` + +In this step, because of all the test cases in token-swap, we also have to update +the expected error due to mismatched owner token programs. + +It's tedious, but at this point, we have updated our program to use both Token +and Token-2022 simultaneously. Congratulations! You're ready to be part of the +next stage of DeFi on Solana. + +## Part III: Support All Extensions + +It seems like our program is working perfectly and that it won't have any issues +processing Token-2022 mints. + +Unfortunately, there's one more bit of work required for full compatibility in +token-swap. Since the program is using `transfer` instead of `transfer_checked`, +it will fail for certain mints. + +We must upgrade to using `transfer_checked` if we want to support all extensions +in Token-2022. As always, let's start by making our tests fail. + +### Step 1: Add transfer fee extension to Token-2022 tests + +The Token-2022 tests currently initialize the `MintCloseAuthority` extension. +Let's add the `TransferFeeConfig` extension to the mint, and the `TransferFeeAmount` +extension to the token accounts. + +Instead of: + +```rust +let mint_space = ExtensionType::try_calculate_account_len::(&[ExtensionType::MintCloseAuthority]).unwrap(); +let account_space = ExtensionType::try_calculate_account_len::(&[ExtensionType::ImmutableOwner]).unwrap(); +``` + +We'll do: + +```rust +let mint_space = ExtensionType::try_calculate_account_len::(&[ExtensionType::MintCloseAuthority, ExtensionType::TransferFeeConfig]).unwrap(); +let account_space = ExtensionType::try_calculate_account_len::(&[ExtensionType::ImmutableOwner, ExtensionType::TransferFeeAmount]).unwrap(); +``` + +And during initialization of the mint, we'll add in the instruction to initialize +the transfer fee config to the initialization transaction: + +```rust +let rate_authority = Keypair::new(); +let withdraw_authority = Keypair::new(); + +let instruction = spl_token_2022::extension::transfer_fee::instruction::initialize_transfer_fee_config( + program_id, &mint_key, rate_authority.pubkey(), withdraw_authority.pubkey(), 0, 0 +).unwrap(); +``` + +With this step, some of the Token-2022 test variants fail with: "Mint required +for this account to transfer tokens, use `transfer_checked` or +`transfer_checked_with_fee`". + +### Step 2: Add mints to instructions that use `transfer` + +The biggest difference between `transfer` and `transfer_checked` is the presence +of the mint for the tokens. First, we must provide the mint account for every +instruction that uses `transfer`. + +For example, the swap instruction becomes: + +```rust +/// Swap the tokens in the pool. +/// +/// 0. `[]` Token-swap +/// 1. `[]` swap authority +/// 2. `[]` user transfer authority +/// 3. `[writable]` token_(A|B) SOURCE Account, amount is transferable by user transfer authority, +/// 4. `[writable]` token_(A|B) Base Account to swap INTO. Must be the SOURCE token. +/// 5. `[writable]` token_(A|B) Base Account to swap FROM. Must be the DESTINATION token. +/// 6. `[writable]` token_(A|B) DESTINATION Account assigned to USER as the owner. +/// 7. `[writable]` Pool token mint, to generate trading fees +/// 8. `[writable]` Fee account, to receive trading fees +/// 9. `[]` Token (A|B) SOURCE mint +/// 10. `[]` Token (A|B) DESTINATION mint +/// 11. `[]` Token (A|B) SOURCE program id +/// 12. `[]` Token (A|B) DESTINATION program id +/// 13. `[]` Pool Token program id +/// 14. `[optional, writable]` Host fee account to receive additional trading fees +Swap(...), +``` + +Note the addition of `Token (A|B) SOURCE mint` and `Token (A|B) DESTINATION mint`. +The pool token mint is already included, so we're safe there. + +Next, in the processor code, we'll extract these additional accounts, but we +won't use them yet. + +For swap, the beginning becomes: + +```rust +let account_info_iter = &mut accounts.iter(); +let swap_info = next_account_info(account_info_iter)?; +let authority_info = next_account_info(account_info_iter)?; +let user_transfer_authority_info = next_account_info(account_info_iter)?; +let source_info = next_account_info(account_info_iter)?; +let swap_source_info = next_account_info(account_info_iter)?; +let swap_destination_info = next_account_info(account_info_iter)?; +let destination_info = next_account_info(account_info_iter)?; +let pool_mint_info = next_account_info(account_info_iter)?; +let pool_fee_account_info = next_account_info(account_info_iter)?; +let source_token_mint_info = next_account_info(account_info_iter)?; +let destination_token_mint_info = next_account_info(account_info_iter)?; +let source_token_program_info = next_account_info(account_info_iter)?; +let destination_token_program_info = next_account_info(account_info_iter)?; +let pool_token_program_info = next_account_info(account_info_iter)?; +``` + +Note the addition of `source_token_mint_info` and `destination_token_mint_info`. + +We'll go through every instruction that uses `transfer`, which for token-swap, +includes `swap`, `deposit_all_token_types`, `withdraw_all_token_types`, +`deposit_single_token_type_exact_amount_in`, and +`withdraw_single_token_type_exact_amount_out`. + +By the end of this, some of the Token-2022 tests still fail, but the Token +tests all pass. + +### Step 3: Change `transfer` to `transfer_checked` instruction + +Everything's in place to use `transfer_checked`, so the next step will thankfully +be quite simple and get all of our tests to pass. + +Where we normally use `spl_token_2022::instruction::transfer`, we'll instead use +`spl_token_2022::instruction::transfer_checked`, also providing the mint account +info and decimals. + +For example, we can do: + +```rust +let decimals = StateWithExtensions::::unpack(&mint.data.borrow()).map(|m| m.base)?.decimals; +let ix = spl_token_2022::instruction::transfer_checked( + token_program.key, + source.key, + mint.key, + destination.key, + authority.key, + &[], + amount, + decimals, +)?; +invoke( + &ix, + &[source, mint, destination, authority, token_program], +) +``` + +After this step, all of your tests should pass once again, so congratulations +again! + +## Part IV: Support transfer fees in calculation + +Now that everything is in place to support every possible extension in Token-2022, +we find that token-swap has some strange behavior for certain extensions. + +In token-swap, if a token has transfer fees, then the curve calculations will +not be correct. For example, if you try to trade token A for B, and token A has +a 1% transfer fee, then fewer tokens will arrive into the pool, which means that +you should receive fewer tokens. + +We'll add logic to properly handle the transfer fee extension as an example in +token-swap. + +### Step 1: Add a failing test swapping with transfer fees + +Let's start by adding a failing test where we swap between tokens that have +non-zero transfer fees. + +For token-swap, we can reuse a previous test which checks that the curve calculation +lines up with what is actually traded. The most important part is to add a transfer +fee when initializing the mint, meaning we go from: + +```rust +let rate_authority = Keypair::new(); +let withdraw_authority = Keypair::new(); + +let instruction = spl_token_2022::extension::transfer_fee::instruction::initialize_transfer_fee_config( + program_id, &mint_key, rate_authority.pubkey(), withdraw_authority.pubkey(), 0, 0 +).unwrap(); +``` + +To: + +```rust +let rate_authority = Keypair::new(); +let withdraw_authority = Keypair::new(); +let transfer_fee_basis_points = 100; +let maximum_transfer_fee = 1_000_000_000; + +let instruction = spl_token_2022::extension::transfer_fee::instruction::initialize_transfer_fee_config( + program_id, &mint_key, rate_authority.pubkey(), withdraw_authority.pubkey(), + transfer_fee_basis_points, maximum_transfer_fee +).unwrap(); +``` + +### Step 2: Calculate the expected transfer fee + +Whenever the program moves tokens, it needs to check if the mint contains a +transfer fee and account for them. + +To check if the mint has an extension, we simply need to get the extension for +the desired type, and properly handle the valid error case. + +Roughly speaking that means changing the amount traded before calculation: + +```rust +use solana_program::{clock::Clock, sysvar::Sysvar}; +use spl_token_2022::{extension::{StateWithExtensions, transfer_fee::TransferFeeConfig}, state::Mint}; + +let mint_data = token_mint_info.data.borrow(); +let mint = StateWithExtensions::::unpack(&mint_data)?; +let actual_amount = if let Ok(transfer_fee_config) = mint.get_extension::() { + let fee = transfer_fee_config + .calculate_epoch_fee(Clock::get()?.epoch, amount) + .ok_or(ProgramError::InvalidArgument)?; + amount.saturating_sub(fee) +} else { + amount +}; +``` + +After making these changes, our tests pass once again, congratulations! + +**Note**: in the case of token-swap, we need to reverse calculate the fee, which +introduces extra complexity. Most likely, your program won't need that. + +## Part V: Prohibit closable mints + +In Token-2022, it's possible for certain mints to be closed if their supply is 0. +Typically, this won't cause any damage, because all token accounts are empty if +a mint is closable. + +If your program stores any information about mints, however, it can go out of +sync if the mint is closed and re-created on that same address. Worse, the +account can be used for something completely different. If your program is storing +mint info, find a way to redesign your solution so it always uses the information +from the mint directly. + +In token-swap, the program gracefully handles closed mints, but an empty pool +can be rendered unusable if the pool mint is closed. No funds are at risk, since +the pool is empty anyway, but for the sake of the tutorial, let's prohibit the +pool mint from being closable. + +### Step 1: Add a failing test with a mint close authority + +Let's add a mint close authority to the pool token mint. During initialization, +we'll do: + +```rust +use spl_token_2022::{extension::ExtensionType, instruction::*, state::Mint}; +use solana_sdk::{system_instruction, transaction::Transaction}; + +// Calculate the space required using the `ExtensionType` +let space = ExtensionType::try_calculate_account_len::(&[ExtensionType::MintCloseAuthority]).unwrap(); + +// get the Rent object and calculate the rent required +let rent_required = rent.minimum_balance(space); + +// and then create the account using those parameters +let create_instruction = system_instruction::create_account(&payer.pubkey(), mint_pubkey, rent_required, space, token_program_id); + +// Important: you must initialize the mint close authority *BEFORE* initializing the mint, +// and only when working with Token-2022, since the instruction is unsupported by Token. +let initialize_close_authority_instruction = initialize_mint_close_authority(token_program_id, mint_pubkey, Some(close_authority)).unwrap(); +let initialize_mint_instruction = initialize_mint(token_program_id, mint_pubkey, mint_authority_pubkey, freeze_authority, 9).unwrap(); + +// Make the transaction with all of these instructions +let create_mint_transaction = Transaction::new(&[create_instruction, initialize_close_authority_instruction, initialize_mint_instruction], Some(&payer.pubkey)); +``` + +And then try to initialize the token swap pool as normal, checking for a failure. +Since there isn't any logic to prohibit a close authority, it should fail. Nice! + +### Step 2: Add processor check to prevent a mint close authority + +When processing the initialize code, we simply add a check to see if a non-`None` +mint close authority exists. + +For example, that means: + +```rust +let pool_mint_data = pool_mint_info.data.borrow(); +let pool_mint = StateWithExtensions::::unpack(pool_mint_data)?; +if let Ok(extension) = pool_mint.get_extension::() { + let close_authority: Option = extension.close_authority.into(); + if close_authority.is_some() { + return Err(ProgramError::InvalidAccountData); + } +} +``` + +Now the test should pass. Well done! diff --git a/docs/src/token-2022/presentation.md b/docs/src/token-2022/presentation.md new file mode 100644 index 00000000000..cfd072dcc50 --- /dev/null +++ b/docs/src/token-2022/presentation.md @@ -0,0 +1,380 @@ +--- +title: Presentation +--- + +- Why a new token program? +- What are extensions? +- How can I get you excited with an FAQ? + +--- + +### Why + +- SPL Token works and is battle-tested +- ...but it needs more protocol-level functionality, without impacting existing tokens +- Let's deploy a new and separate token program +- ...even though it's no longer 2022! + +--- + +### Wait, are you sure about this? + +- Adopting a separate token program is tricky +- ...but extremely valuable to the ecosystem +- Going from 1 to 2 is hard, but 2 to N is easy + +--- + +### Are you aware that it's not 2022? + +Yes. + +--- + +### Ok... how does it work? + +- Token-2022 is a superset of Token: structures and instructions have the same ABI +- Opt-in to *extensions* on mints and accounts +- New data is written after the 165th byte + +--- + +### Cool, but can I even use this? + +- Yes! Out on all networks *for testing* +- `solana` tools version >= 1.14.17 +- `@solana/spl-token` version >= 0.3 +- `spl-token-cli` version >= 2.2 + +--- + +### Who supports it? + +The base is mostly there. + +- RPC indexes Token-2022 +- Anchor +- Wallets +- DeFi Protocols +- Token Metadata + +--- + +### That's great! Is it safe? + +- 4 audits +- 1 more after WIP features +- Currently upgradeable +- Officially recommended after 1.17 on mainnet (~January 2024) +- More ZK features in 1.18 (~May 2024) +- May be frozen ~6 months after that + +--- + +### I'll bite: what are the extensions for accounts? + +- Confidential transfers +- CPI guard +- Memo required on transfer +- Immutable ownership + +--- + +### Not bad, what are the extensions for mints? + +- Confidential transfers +- Transfer fees +- Closing mint +- Interest-bearing tokens +- Non-transferable tokens +- Default account state +- Permanent delegate +- Transfer-hook +- Metadata pointer + metadata +- Group pointer + group + +--- + +### Wow that's a lot! + +Yeah. + +--- + +### I don't get what they're for. + +Let's learn with a game! + +- Describe a token design +- Think about how to do it with Token-2022 +- I give the answer + +Hint: the answers are in the CLI docs at https://spl.solana.com/token-2022/extensions + +--- + +### Question 1 + +I heard about compressed NFTs, so how can I make a token that can be compressed, +decompressed, and recompressed with an off-chain merkle tree? + +--- + +### Answer 1 + +Create a mint with the close mint authority extension, so you can close and +re-open the mint account when the supply is 0. + +--- + +### Question 2 + +I want to send my token without anyone knowing how much I have or how much I transferred. + +--- + +### Answer 2 + +Add the confidential transfer extension to your mint! + +Although the first deposit is public, transfer amounts are encrypted and +validated through zero-knowledge proofs. + +* Used to require larger transaction sizes, but instead we're splitting +up the proofs! + +--- + +### Question 3 + +I run a stake pool / lending protocol, and I want the pool token amount to go up +over time to approximate the value of the token. + +--- + +### Answer 3 + +Create a mint with the interest-bearing extension, and have the protocol update +the interest rate every epoch. + +--- + +### Question 4 + +I'm creating a bank-like payments system, and I want to create legible monthly +statements for my clients. + +And I don't want them to get rugged by sketchy protocols. + +--- + +### Answer 4 + +Enforce that all client token accounts require memos on incoming transfers. +Clients can figure out the motive for all funds coming into their account. + +Also add the CPI guard extension, to force dapp transfers to go through a delegate. + +--- + +### Question 5 + +For my game, I only want players to hold my token, and I don't want them +to dump it on an exchange. + +--- + +### Answer 5 + +Create the mint with the default account state extension, set to `frozen`. Players +must go through your program or service to unfreeze their account. + +--- + +### Question 6 + +My DAO needs a privileged token for council members. + +I don't want them to sell or move the tokens, and the DAO must be able to +revoke the token if they behave poorly. + +--- + +### Answer 6 + +Create a mint with: +- permanent delegation to the DAO, so it can burn any token +- non-transferable, so members can't move them +- Bonus: non-transferable forces immutable ownership + +--- + +### Question 7 + +There's definitely a lot of new features, but I just want to program my own +token. + +--- + +### Answer 7 + +This isn't possible currently. We need to develop a suite of interfaces and move +everyone to using them. + +In the meantime, you can configure your token-2022 mint to call into a program that +implements the "transfer hook" interface. + +More info at https://github.com/solana-labs/solana-program-library/tree/master/token/transfer-hook-interface + +--- + +### Question 8 + +You mentioned something about metadata. Does this mean there's going to be more +than one metadata program? That sounds like chaos. + +--- + +### Answer 8 + +It could be! That's why the "metadata pointer" extension in token-2022 lets you +specify which account holds the metadata for your mint. + +For safety, you *must* make sure that the mint and metadata point at each other. + +--- + +### Question 9 + +Can't we just put the metadata in the mint? + +--- + +### Answer 9 + +Yes! With the WIP "metadata" extension, you just put everything in the mint. + +--- + +### Question 10 + +These features sound awesome, but I already have lots of token holders, +so how can I migrate them to Token-2022? + +--- + +### Answer 10 + +Create a new mint with Token-2022, and have them use the `spl-token-upgrade` +program to convert. + +- Stateless protocol with an escrow account +- Mint new tokens to the escrow +- Protocol burns old tokens and gives new tokens + +Fun fact: you can use this between any two mints! + +--- + +### Question 11 + +Yeah, hi, same as number 10, but I don't want to burn tokens. + +--- + +### Answer 11 + +That's fine! The WIP `token-wrap` program allows you to wrap between any two mints. + +Note: the default wrapping program does not add extensions, but can be forked +into a new program if you want to wrap your token with extensions. + +--- + +### Question 12 + +I have an on-chain program (smart contract), how can I add support for Token-2022? + +--- + +### Answer 12 + +That's awesome! If you only process one token in an instruction, it's easy. + +If you use multiple token programs at once (e.g. trading), it's trickier since +you need both programs in your instruction. + +Extensive docs and examples at https://spl.solana.com/token-2022/onchain + +--- + +### Question 13 + +I work on a wallet, so how can I show and transfer Token-2022 tokens? + +--- + +### Answer 13 + +Nice! It's pretty easy to add support. + +Docs and examples at https://spl.solana.com/token-2022/wallet + +--- + +### Question 14 + +Why did you add metadata? + +--- + +### Answer 14 + +- On-chain programming should become more open +- People kept bothering us about it + +--- + +### Question 15 + +What if I don't want to use your metadata? + +--- + +### Answer 15 + +- No problem, bring your own! +- The "metadata pointer" extension lets you point to *any* account +- You can also implement the "SPL Token Metadata Interface" in your program + +Security bonus: check that the mint and metadata point to each other! + +--- + +### Question 16 + +Can I just use my own token program? + +--- + +#### Answer 16 + +- That's the future! In the meantime, we have Transfer Hooks +- With a Transfer Hook, Token-2022 calls a program of your choice during all +transfers for your mint +- The program must implement `spl-transfer-hook-interface` +- Feel free to fork `spl-transfer-hook-example` + +--- + +### I'm a bit overwhelmed + +No problem, we're done, here are your links: + +- Token-2022: https://spl.solana.com/token-2022 +- Token-upgrade: https://spl.solana.com/token-upgrade +- Metadata interface: https://docs.rs/crate/spl-token-metadata-interface/latest +- Transfer hook interface: https://docs.rs/crate/spl-transfer-hook-interface/latest +- Confidential transfers: https://github.com/solana-labs/solana-program-library/blob/master/token/zk-token-protocol-paper/part1.pdf + +Thanks for listening! diff --git a/docs/src/token-2022/status.md b/docs/src/token-2022/status.md new file mode 100644 index 00000000000..dcc414e3ad5 --- /dev/null +++ b/docs/src/token-2022/status.md @@ -0,0 +1,55 @@ +--- +title: Project Status +--- + +All clusters have the latest program deployed **without confidential transfer +functionality**. + +The program with confidential transfer functionality will be deployed once +Agave v2.0 reaches mainnet-beta with the appropriate cluster features enabled. + +## Timeline + +Here is the general program timeline and rough ETAs: + +| Issue | ETA | +| --------------------------- | ------------------------------ | +| Mainnet recommendation | Winter 2024 (depends on v1.17) | +| Token group extension | Summer 2024 | +| Confidential transfers | Autumn 2024 (depends on v2.0) | +| Freeze program | 2025 | + +More information: https://github.com/orgs/solana-labs/projects/34 + +## Remaining items + +### v2.0 with ZK ElGamal Proof Program + +In order to use confidential tokens, the cluster must run at least version 2.0 +with the ZK ElGamal Proof Program enabled. + +More information: https://github.com/anza-xyz/agave/issues/1966 + +## Future work + +### Wallets + +To start, wallets need to properly handle the Token-2022 program and its accounts, +by fetching Token-2022 accounts and sending instructions to the proper program. + +Next, to use confidential tokens, wallets need to create zero-knowledge proofs, +which entails a new transaction flow. + +### Increased transaction size + +To support confidential transfers in one transaction, rather than split up over +multiple transactions, the Solana network must accept transactions with a larger +payload. + +More information: https://github.com/orgs/solana-labs/projects/16 + +## Upgradability + +To facilitate deploying updates and security fixes, the program deployment remains +upgradable. Once audits are complete and the program has been stable for six months, +the deployment will be marked final and no further upgrades will be possible. diff --git a/docs/src/token-2022/wallet.md b/docs/src/token-2022/wallet.md index 7a070f51b32..fdf2e84029a 100644 --- a/docs/src/token-2022/wallet.md +++ b/docs/src/token-2022/wallet.md @@ -2,4 +2,260 @@ title: Wallet Guide --- -Coming soon! +This guide is meant for wallet developers who want to support Token-2022. + +Since wallets have very different internals for managing token account state +and connections to blockchains, this guide will focus on the very specific changes +required, without only vague mentions of code design. + +## Motivation + +Wallet developers are accustomed to only including one token program used for +all tokens. + +To properly support Token-2022, wallet developers must make code changes. + +Important note: if you do not wish to support Token-2022, you do not need to do +anything. The wallet will not load Token-2022 accounts, and transactions created +by the wallet will fail loudly if using Token-2022 incorrectly. + +Most likely, transactions will fail with `ProgramError::IncorrectProgramId` +when trying to target the Token program with Token-2022 accounts. + +## Prerequisites + +When testing locally, be sure to use at least `solana-test-validator` version +1.14.17, which includes the Token-2022 program by default. This comes bundled +with version 2.3.0 of the `spl-token` CLI, which also supports Token-2022. + +## Setup + +You'll need some Token-2022 tokens for testing. First, create a mint with an +extension. We'll use the "Mint Close Authority" extension: + +```console +$ spl-token -ul create-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb --enable-close +Creating token E5SUrbnx7bMBp3bRdMWNCFS3FXp5VpvFDdNFp8rjrMLM under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb + +Address: E5SUrbnx7bMBp3bRdMWNCFS3FXp5VpvFDdNFp8rjrMLM +Decimals: 9 + +Signature: 2dYhT1M3dHjbGd9GFCFPXmHMtjujXBGhM8b5wBkx3mtUptQa5U9jjRTWHCEmUQnv8XLt2x5BHdbDUkZpNJFqfJn1 +``` + +The extension is important because it will test that your wallet properly handles +larger mint accounts. + +Next, create an account for your test wallet: + +```console +$ spl-token -ul create-account E5SUrbnx7bMBp3bRdMWNCFS3FXp5VpvFDdNFp8rjrMLM --owner --fee-payer +Creating account 4L45ZpFS6dqTyLMofmQZ9yuTqYvQrfCJfWL2xAjd5WDW + +Signature: 5Cjvvzid7w2tNZojrWVCmZ2MFiezxxnWgJHLJKkvJNByZU2sLN97y85CghxHwPaVf5d5pJAcDV9R4N1MNigAbBMN +``` + +With the `--owner` parameter, the new account is an associated token account, +which includes the "Immutable Owner" account extension. This way, you'll also +test larger token accounts. + +Finally, mint some tokens: + +```console +$ spl-token -ul mint E5SUrbnx7bMBp3bRdMWNCFS3FXp5VpvFDdNFp8rjrMLM 100000 4L45ZpFS6dqTyLMofmQZ9yuTqYvQrfCJfWL2xAjd5WDW +Minting 100000 tokens + Token: E5SUrbnx7bMBp3bRdMWNCFS3FXp5VpvFDdNFp8rjrMLM + Recipient: 4L45ZpFS6dqTyLMofmQZ9yuTqYvQrfCJfWL2xAjd5WDW + +Signature: 43rsisVeLKjBCgLruwTFJXtGTBgwyfpLjwm44dY2YLHH9WJaazEvkyYGdq6omqs4thRfCS4G8z4KqzEGRP2xoMo9 +``` + +It's also helpful for your test wallet to have some SOL, so be sure to transfer some: + +```console +$ solana -ul transfer 10 --allow-unfunded-recipient +Signature: 5A4MbdMTgGiV7hzLesKbzmrPSCvYPG15e1bg3d7dViqMaPbZrdJweKSuY1BQAfq245RMMYeGudxyKQYkgKoGT1Ui +``` + +Finally, you can save all of these accounts in a directory to be re-used for testing: + +```console +$ mkdir test-accounts +$ solana -ul account --output-file test-accounts/token-account.json --output json 4L45ZpFS6dqTyLMofmQZ9yuTqYvQrfCJfWL2xAjd5WDW +... output truncated ... +$ solana -ul account --output-file test-accounts/mint.json --output json E5SUrbnx7bMBp3bRdMWNCFS3FXp5VpvFDdNFp8rjrMLM +... output truncated ... +$ solana -ul account --output-file test-accounts/wallet.json --output json +``` + +This way, whenever you want to restart your test validator, you can simply run: + +```console +$ solana-test-validator -r --account-dir test-accounts +``` + +## Structure of this Guide + +We'll go through the required code changes to support Token-2022 in your wallet, +using only little code snippets. This work was done for the Backpack wallet in +[PR #3976](https://github.com/coral-xyz/backpack/pull/3976), +but as mentioned earlier, the actual code changes may look very different for +your wallet. + +## Part I: Fetch Token-2022 Accounts + +In addition to normal Token accounts, your wallet must also fetch Token-2022 +accounts. Typically, wallets use the `getTokenAccountsByOwner` RPC endpoint once +to fetch the accounts. + +For Token-2022, you simply need to add one more call to get the additional accounts: + +```typescript +import { Connection, PublicKey } from '@solana/web3.js'; + +const TOKEN_PROGRAM_ID = new PublicKey( + 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' +); +const TOKEN_2022_PROGRAM_ID = new PublicKey( + 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb' +); +const walletPublicKey = new PublicKey('11111111111111111111111111111111'); // insert your key +const connection = new Connection('http://127.0.0.1:8899', 'confirmed'); + +const tokenAccounts = await connection.getTokenAccountsByOwner( + walletPublicKey, { programId: TOKEN_PROGRAM_ID } +); +const token2022Accounts = await connection.getTokenAccountsByOwner( + walletPublicKey, { programId: TOKEN_2022_PROGRAM_ID } +); +``` + +Merge the two responses, and you're good to go! If you can see your test account, +then you've done it correctly. + +If there are issues, your wallet may be deserializing the token account too strictly, +so be sure to relax any restriction that the data size must be equal to 165 bytes. + +## Part II: Use the Token Program Id for Instructions + +If you try to transfer or burn a Token-2022 token, you will likely receive an +error because the wallet is trying to send an instruction to Token instead of +Token-2022. + +Here are two possible ways to resolve the problem. + +### Option 1: Store the token account's owner during fetch + +In the first part, we fetched all of the token accounts and threw away the +program id associated with the account. Instead of always targeting the Token +program, we need to target the right program for that token. + +If we store the program id for each token account, then we can re-use that +information when we need to transfer or burn. + +```typescript +import { Connection, PublicKey } from '@solana/web3.js'; +import { createTransferInstruction } from '@solana/spl-token'; + +const TOKEN_PROGRAM_ID = new PublicKey( + 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' +); +const TOKEN_2022_PROGRAM_ID = new PublicKey( + 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb' +); +const walletPublicKey = new PublicKey('11111111111111111111111111111111'); // insert your key +const connection = new Connection('http://127.0.0.1:8899', 'confirmed'); + +const tokenAccounts = await connection.getTokenAccountsByOwner( + walletPublicKey, { programId: TOKEN_PROGRAM_ID } +); +const token2022Accounts = await connection.getTokenAccountsByOwner( + walletPublicKey, { programId: TOKEN_2022_PROGRAM_ID } +); +const accountsWithProgramId = [...tokenAccounts.value, ...token2022Accounts.value].map( + ({ account, pubkey }) => + { + account, + pubkey, + programId: account.data.program === 'spl-token' ? TOKEN_PROGRAM_ID : TOKEN_2022_PROGRAM_ID, + }, +); + +// later on... +const accountWithProgramId = accountsWithProgramId[0]; +const instruction = createTransferInstruction( + accountWithProgramId.pubkey, // source + accountWithProgramId.pubkey, // destination + walletPublicKey, // owner + 1, // amount + [], // multisigners + accountWithProgramId.programId, // token program id +); +``` + +### Option 2: Fetch the program owner before transfer / burn + +This approach introduces one more network call, but may be simpler to integrate. +Before creating an instruction, you can fetch the mint, source account, or +destination account from the network, and pull out its `owner` field. + +```typescript +import { Connection, PublicKey } from '@solana/web3.js'; + +const connection = new Connection('http://127.0.0.1:8899', 'confirmed'); +const accountPublicKey = new PublicKey('11111111111111111111111111111111'); // insert your account key here +const accountInfo = await connection.getParsedAccountInfo(accountPublicKey); +if (accountInfo.value === null) { + throw new Error('Account not found'); +} +const programId = accountInfo.value.owner; +``` + +## Part III: Use the Token Program Id for Associated Token Accounts + +Whenever we derive an associated token account, we must use the correct token +program id. Currently, most implementations hardcode the token program id. +Instead, you must add the program id as a parameter: + +```typescript +import { PublicKey } from '@solana/web3.js'; + +const ASSOCIATED_TOKEN_PROGRAM_ID = new PublicKey( + "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" +); + +function associatedTokenAccountAddress( + mint: PublicKey, + wallet: PublicKey, + programId: PublicKey, +): PublicKey { + return PublicKey.findProgramAddressSync( + [wallet.toBuffer(), programId.toBuffer(), mint.toBuffer()], + ASSOCIATED_TOKEN_PROGRAM_ID + )[0]; +} +``` + +If you're creating associated token accounts, you'll also need to pass the +token program id, which currently defaults to `TOKEN_PROGRAM_ID`: + +```typescript +import { Connection, PublicKey } from '@solana/web3.js'; +import { createAssociatedTokenAccountInstruction } from '@solana/spl-token'; + +const tokenProgramId = new PublicKey( + 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb' +); // either `Tokenz...` or `Tokenkeg...` +const wallet = new PublicKey('11111111111111111111111111111111'); // insert your key +const mint = new PublicKey('11111111111111111111111111111111'); // insert mint key +const associatedTokenAccount = associatedTokenAccountAddress(mint, wallet, tokenProgramId); + +const instruction = createAssociatedTokenAccountInstruction( + wallet, // payer + associatedTokenAccount, // associated token account + wallet, // owner + tokenProgramId, // token program id +); +``` + +With these three parts done, your wallet will provide basic support for Token-2022! diff --git a/docs/src/token-lending.md b/docs/src/token-lending.md index b4b44981af8..2cac5b97526 100644 --- a/docs/src/token-lending.md +++ b/docs/src/token-lending.md @@ -2,13 +2,10 @@ title: Token-Lending Program --- -A lending protocol for the Token program on the Solana blockchain inspired by Aave and Compound. +A lending protocol for the Token program on the Solana blockchain inspired by +Aave and Compound. +## Audit -### On-Chain Programs - -| Cluster | Program Address | -| --- | --- | -| Mainnet Beta | [`LendZqTs8gn5CTSJU1jWKhKuVpjJGom45nnwPb2AMTi`](https://explorer.solana.com/address/LendZqTs7gn5CTSJU1jWKhKuVpjJGom45nnwPb2AMTi) | -| Testnet | [`LendZqTs8gn5CTSJU1jWKhKuVpjJGom45nnwPb2AMTi`](https://explorer.solana.com/address/LendZqTs8gn5CTSJU1jWKhKuVpjJGom45nnwPb2AMTi?cluster=testnet) | -| Devnet | [`LendZqTs8gn5CTSJU1jWKhKuVpjJGom45nnwPb2AMTi`](https://explorer.solana.com/address/LendZqTs8gn5CTSJU1jWKhKuVpjJGom45nnwPb2AMTi?cluster=devnet) | +The repository [README](https://github.com/solana-labs/solana-program-library#audits) +contains information about program audits. diff --git a/docs/src/token-swap.md b/docs/src/token-swap.md index 4abbc4e4708..7028e9669c6 100644 --- a/docs/src/token-swap.md +++ b/docs/src/token-swap.md @@ -5,25 +5,22 @@ title: Token Swap Program A Uniswap-like exchange for the Token program on the Solana blockchain, implementing multiple automated market maker (AMM) curves. -## Available Deployments +## Audit +The repository [README](https://github.com/solana-labs/solana-program-library#audits) +contains information about program audits. -| Network | Version | Program Address | Fee Owner Address | -| --- | --- | --- | -| Devnet, Testnet | 3.0.0 | `SwapsVeCiPHMUAtzQWZw7RjsKjgCjhwU55QGu4U1Szw` | Any | -| All | 2.0.0 | `SwaPpA9LAaLfeLi3a68M4DjnLqgtticKg6CnyNwgAC8` | `HfoTxFR1Tm6kGmWgYWD6J7YHVy1UwqSULUGVLXkJqaKN` | +## Available Deployments -The Token Swap Program was deployed to all networks by the Serum team at -`SwaPpA9LAaLfeLi3a68M4DjnLqgtticKg6CnyNwgAC8`, requiring a fee owner of -`HfoTxFR1Tm6kGmWgYWD6J7YHVy1UwqSULUGVLXkJqaKN`, but that version was deprecated -in the middle of 2021. Though that program still exists, it is not actively -maintained. +| Network | Version | Program Address | +| --- | --- | --- | +| Testnet | 3.0.0 | `SwapsVeCiPHMUAtzQWZw7RjsKjgCjhwU55QGu4U1Szw` | +| Devnet | 3.0.0 | `SwapsVeCiPHMUAtzQWZw7RjsKjgCjhwU55QGu4U1Szw` | -For devnet and testnet, please use the maintainted deployment at -`SwapsVeCiPHMUAtzQWZw7RjsKjgCjhwU55QGu4U1Szw`, and for mainnet, please use any -other AMM project on Solana. Almost all of these were based on Token Swap! +While third-party deployments of token-swap exist on Mainnet Beta, the team has +no plans to deploy it themselves. -Check out +Check out the [program repository](https://github.com/solana-labs/solana-program-library/tree/master/token-swap) for more developer information. @@ -66,8 +63,7 @@ bindings](https://github.com/solana-labs/solana-program-library/blob/master/toke are available that support loading the Token Swap Program on to a chain and issuing instructions. -Example user interface built and maintained by Serum team is available -[here](https://github.com/project-serum/oyster-swap) +Example user interface is available [here](https://github.com/solana-labs/oyster-swap). ## Operational overview diff --git a/docs/src/token-upgrade.md b/docs/src/token-upgrade.md new file mode 100644 index 00000000000..fe654eaec47 --- /dev/null +++ b/docs/src/token-upgrade.md @@ -0,0 +1,153 @@ +--- +title: Token Upgrade Program +--- + +The Token Upgrade Program provides a stateless protocol for permanently converting +tokens from one mint to another. + +The program provides a simple mechanism for burning the original tokens and receiving +an equal number of new tokens from an escrow account controlled by the program. + +## Audit + +The repository [README](https://github.com/solana-labs/solana-program-library#audits) +contains information about program audits. + +## Background + +Token-2022 contains many new features for mint owners to customize the behavior +of their tokens. You can find full information about Token-2022 and its extensions +in the [documentation](token-2022.md). + +Mint owners may want to take advantage of new functionality for their users, but +there is no way to automatically convert tokens from Token to Token-2022. + +The Token Upgrade Program defines an escrow authority, a program-derived address +from two addresses, the original and new mints. Any new token account owned by or +delegated to this escrow authority may be used as the escrow account. + +A holder of original tokens provides their original token account, a new token account, +and the escrow account. If the escrow account has enough tokens, the protocol will +burn the original tokens and transfer the same amount of new tokens to the user's +new account. + +The program ensures that the decimals of both mints are the same, so if the mints +have different decimals, the upgrade fails. + +The program is completely stateless and has a simple implementation, so mint owners +may customize it with additional functionality. For example, if they want to +upgrade between mints with different decimals, they can define how to scale +the transferred number up or down as desired. + +**Note**: The Token Upgrade Program can also exchange tokens that belong to the +same program, but different mints. For example, a mint owner can provide an upgrade +between two Token-2022 mints. This is useful if the mint owner wants to add new +functionality to their mint. + +## Source + +The Token Upgrade Program's source is available on +[GitHub](https://github.com/solana-labs/solana-program-library) + +## Interface + +The Token Upgrade Program is written in Rust and available on +[crates.io](https://crates.io/crates/spl-token-upgrade) and +[docs.rs](https://docs.rs/spl-token-upgrade). + +## Command-line Utility + +The `spl-token-upgrade` command-line utility can be used to manage token upgrades. +Once you have [Rust installed](https://rustup.rs/), run: + +```sh +$ cargo install spl-token-upgrade-cli +``` + +Run `spl-token-upgrade --help` for a full description of available commands. + +### Configuration + +The `spl-token-upgrade` configuration is shared with the `solana` command-line tool. + +## Token Upgrade Process + +This section describes how to upgrade tokens from Token to Token-2022, for the +mint owner and token holders. + +This guide also uses the `spl-token` command-line tool. Please see the full +[Token documentation](token.mdx) for more info. + +### Setup + +A mint owner has a mint associated with the Token program at address +`o1d5Jt8z8vszx4FJ2gNJ3FZH34cer9sbparg7GVt7qm`, and they want `o1d` token holders +to upgrade to `NewnQeoDG4BbHRCodgjscuypfXdiixcWDPyLiseziQZ` tokens, associated with +Token-2022. + +### Create token escrow + +The command-line tool allows anyone to create a new token account owned by the +escrow authority, given the original and new mint addresses: + +```sh +$ spl-token-upgrade create-escrow o1d5Jt8z8vszx4FJ2gNJ3FZH34cer9sbparg7GVt7qm NewnQeoDG4BbHRCodgjscuypfXdiixcWDPyLiseziQZ +Creating escrow account 2mW9oGUbaJiCHtkhN5TNTaucY2ziJmAdcJtp5Ud6m4Jy owned by escrow authority A38VXB1Qgssz2qkKgzEkyZNQ27oTuy18T6tA9HRP5mpE +Signature: 4tuJffE4DTrsXb7AM3UWNjd286vyAQcvhQaSKPVThaZMzaBiptKCKudaMWjbbygTUEaho87Ar288Mih5Hx6PpKke +``` + +**Note**: The command-line tool creates the associated token account for the escrow +authority, but any token account for `NewnQeoDG4BbHRCodgjscuypfXdiixcWDPyLiseziQZ` +is usable for upgrades, as long as the account is owned by or delegated to the +escrow authority. + +### Add tokens to the escrow account + +With the escrow account created, the mint owner must now add tokens to that account. +They can do this by minting new tokens or transferring existing tokens. + +```sh +$ spl-token mint NewnQeoDG4BbHRCodgjscuypfXdiixcWDPyLiseziQZ 1000 2mW9oGUbaJiCHtkhN5TNTaucY2ziJmAdcJtp5Ud6m4Jy +``` + +Or: + +```sh +$ spl-token transfer NewnQeoDG4BbHRCodgjscuypfXdiixcWDPyLiseziQZ 1000 2mW9oGUbaJiCHtkhN5TNTaucY2ziJmAdcJtp5Ud6m4Jy +``` + +### Upgrade original tokens into new tokens + +With all accounts in place, any original token holder may redeem new tokens +whenever they want. + +First, they must create a new token account to receive the tokens: + +```sh +$ spl-token create-account NewnQeoDG4BbHRCodgjscuypfXdiixcWDPyLiseziQZ +``` + +Next, they perform the exchange: + +```sh +$ spl-token-upgrade exchange o1d5Jt8z8vszx4FJ2gNJ3FZH34cer9sbparg7GVt7qm NewnQeoDG4BbHRCodgjscuypfXdiixcWDPyLiseziQZ +Burning tokens from account 4YfpfMzHYCCYVBJqvTG9VtTPLMuPzVBi77aMRxVB4TDg, receiving tokens into account JCaWYSvLZkja51RbToWBaV4kp1PhfddX64cTLUqpdMzE +Signature: 3Zs1PtMV7XyRpfX9k7cPg7Hd43URvBD3aYEnd6hb5deKvSWXrEW5yoRaCuqtYJSsoa2WtkdprTsHEh3VLYWEGhkb +``` + +The tool defaults to using associated token accounts for the user on the original +and new token mints, and for the escrow authority on the new mint. It's possible +to specify each of these individually: + +```sh +$ spl-token-upgrade exchange o1d5Jt8z8vszx4FJ2gNJ3FZH34cer9sbparg7GVt7qm NewnQeoDG4BbHRCodgjscuypfXdiixcWDPyLiseziQZ --burn-from 4YfpfMzHYCCYVBJqvTG9VtTPLMuPzVBi77aMRxVB4TDg --destination JCaWYSvLZkja51RbToWBaV4kp1PhfddX64cTLUqpdMzE --escrow 2mW9oGUbaJiCHtkhN5TNTaucY2ziJmAdcJtp5Ud6m4Jy +Burning tokens from account 4YfpfMzHYCCYVBJqvTG9VtTPLMuPzVBi77aMRxVB4TDg, receiving tokens into account JCaWYSvLZkja51RbToWBaV4kp1PhfddX64cTLUqpdMzE +Signature: 3P4o4Fxnm4yvB9i6jQzyniqNUqnNLsaQZmCw5q5n5J8nwv9wxJ73ZRYH3XNFT4ferDbCXMqc5egCkhZEkyfCxhgC +``` + +After the upgrade, the user may clean up the old token account to recover the +rent-exempt lamports. + +```sh +$ spl-token close o1d5Jt8z8vszx4FJ2gNJ3FZH34cer9sbparg7GVt7qm +``` diff --git a/docs/src/token.mdx b/docs/src/token.mdx index 4ef863bb38e..cb68488ce67 100644 --- a/docs/src/token.mdx +++ b/docs/src/token.mdx @@ -22,23 +22,28 @@ document are available at: ## Source The Token Program's source is available on -[github](https://github.com/solana-labs/solana-program-library) +[GitHub](https://github.com/solana-program/token). ## Interface The Token Program is written in Rust and available on [crates.io](https://crates.io/crates/spl-token) and [docs.rs](https://docs.rs/spl-token). Auto-generated C bindings are also available -[here](https://github.com/solana-labs/solana-program-library/blob/master/token/program/inc/token.h) +[here](https://github.com/solana-program/token/blob/main/program/inc/token.h) [JavaScript -bindings](https://github.com/solana-labs/solana-program-library/tree/master/token/js) +bindings](https://github.com/solana-program/token-2022/tree/main/clients/js-legacy) are available that support loading the Token Program on to a chain and issue instructions. See the [SPL Associated Token Account](associated-token-account.md) program for convention around wallet address to token account mapping and funding. +## Status + +The SPL Token program is considered complete, and there are no plans to add new +functionality. There may be changes to fix important or breaking bugs. + ## Reference Guide ### Setup @@ -108,7 +113,7 @@ const web3 = require('@solana/web3.js'); const connection = new web3.Connection(web3.clusterApiUrl('devnet'), 'confirmed'); ``` ### Keypair -You can either get your keypair using [`Keypair`](https://solana-labs.github.io/solana-web3.js/classes/Keypair.html) from `@solana/web3.js`, or let the user's wallet handle the keypair and use `sendTransaction` from [`wallet-adapter`](https://github.com/solana-labs/wallet-adapter) +You can either get your keypair using [`Keypair`](https://solana-labs.github.io/solana-web3.js/v1.x/classes/Keypair.html) from `@solana/web3.js`, or let the user's wallet handle the keypair and use `sendTransaction` from [`wallet-adapter`](https://github.com/solana-labs/wallet-adapter) @@ -383,9 +388,9 @@ import {clusterApiUrl, Connection, PublicKey} from "@solana/web3.js"; console.log("Token Balance"); console.log("------------------------------------------------------------"); - tokenAccounts.value.forEach((e) => { - const accountInfo = AccountLayout.decode(e.account.data); - console.log(`${new PublicKey(accountInfo.mint)} ${accountInfo.amount}`); + tokenAccounts.value.forEach((tokenAccount) => { + const accountData = AccountLayout.decode(tokenAccount.account.data); + console.log(`${new PublicKey(accountData.mint)} ${accountData.amount}`); }) })(); @@ -944,7 +949,7 @@ Signatures are then provided by the multisig signer-set members specified by the Multisig accounts can be used for any authority on an SPL Token mint or token account. -
    +{
    • Mint account mint authority: spl-token mint ..., spl-token authorize ... mint ... @@ -967,19 +972,19 @@ account. spl-token close ..., spl-token authorize ... close ...
    • -
    +
} The main difference in using multisign is specifying the owner as the multisig key, -and giving the list of signers when contructing a transaction. Normally you would +and giving the list of signers when constructing a transaction. Normally you would provide the signer that has authority to run the transaction as the owner, but in the multisig case the owner would be the multisig key. Multisig accounts can be used for any authority on an SPL Token mint or token account. -
    +{
    • Mint account mint authority: createMint(/* ... */, mintAuthority: multisigKey, /* ... */)
    • @@ -992,7 +997,7 @@ Multisig accounts can be used for any authority on an SPL Token mint or token ac
    • Token account close authority: closeAccount(/* ... */, authority: multisigKey, /* ... */)
    • -
    +
}
@@ -1063,7 +1068,7 @@ will use a "2 of 3" multisig account. That is, two of the three allowed keypair must sign all transactions. NOTE: SPL Token Multisig accounts are limited to a signer-set of eleven signers -(1 <= `N` <= 11) and minimum signers must be no more than `N` (1 <= `M` <= `N`) +(1 {'<='} `N` {'<='} 11) and minimum signers must be no more than `N` (1 {'<='} `M` {'<='} `N`) @@ -1176,8 +1181,8 @@ try { multisigKey, 1 ) -} catch (e) { - console.log(e); +} catch (error) { + console.log(error); } // Error: Signature verification failed ``` @@ -1234,7 +1239,7 @@ console.log(`Minted ${mintInfo.supply} token`); ### Example: Offline signing with multisig -Sometimes online signing is not possible or desireable. Such is the case for example when signers are not in the same geographic location +Sometimes online signing is not possible or desirable. Such is the case for example when signers are not in the same geographic location or when they use air-gapped devices not connected to the network. In this case, we use offline signing which combines the previous examples of [multisig](#example-mint-with-multisig-authority) with [offline signing](https://docs.solana.com/offline-signing) and a [nonce account](https://docs.solana.com/offline-signing/durable-nonce). @@ -1672,6 +1677,11 @@ require the Solana account being initialized also be a signer. The instruction that creates the Solana account by including both instructions in the same transaction. +Also, multisignatures allow for duplicate accounts in the signer sets, for very +simple weighting systems. For example, a 2 of 4 multisig can be constructed with +3 unique pubkeys, and one pubkey specified twice to give that pubkey double +voting power. + ### Freezing accounts The Mint may also contain a `freeze_authority` which can be used to issue @@ -1810,20 +1820,21 @@ then: creation the transfer will require more SOL than normal. However a wallet that chooses to not support creating the recipient's associated token account at this time should present a message to the user with enough - information to permit them to find a workaround (such as transferring the - token through a fully compliant intermediary wallet such as https://sollet.io) - to allow the users to accomplish their goal + information to find a workaround to accomplish their goal 1. Use `TokenInstruction::Transfer` to complete the transfer The sender's wallet must not require that the recipient's main wallet address hold a balance before allowing the transfer. ### Registry for token details -At the moment there exist two solutions for Token Mint registries: -* hard coded addresses in the wallet or dapp -* [spl-token-registry](https://www.npmjs.com/package/@solana/spl-token-registry) -package, maintained at [https://github.com/solana-labs/token-list](https://github.com/solana-labs/token-list) +At the moment there exist a few solutions for Token Mint registries: + +* Hard coded addresses in the wallet or dapp +* Metaplex Token Metadata. Learn more at the +[Token Metadata Documentation](https://docs.metaplex.com/programs/token-metadata/) +* The deprecated token-list repo has +[instructions for creating your own metadata](https://github.com/solana-labs/token-list#this-repository-is-eol-) **A decentralized solution is in progress.** @@ -1868,7 +1879,7 @@ Unlocking works by pushing a permissionless crank on the contract that moves the - Audit: The audit was conducted by Kudelski, the report can be found [here](https://github.com/Bonfida/token-vesting/blob/master/audit/Bonfida_SecurityAssessment_Vesting_Final050521.pdf) #### 2) Streamflow Timelock -Enables creation, withdrawal, cancelation and transfer of token vesting contracts using time-based lock and escrow accounts. +Enables creation, withdrawal, cancellation and transfer of token vesting contracts using time-based lock and escrow accounts. Contracts are by default cancelable by the creator and transferable by the recipient. Vesting contract creator chooses various options upon creation, such as: diff --git a/docs/src/transfer-hook-interface.md b/docs/src/transfer-hook-interface.md new file mode 100644 index 00000000000..b7d12bdc4c4 --- /dev/null +++ b/docs/src/transfer-hook-interface.md @@ -0,0 +1,27 @@ +--- +title: Transfer Hook Interface +--- + +The Transfer Hook Interface is one of several interfaces introduced within the +Solana Program Library that can be implemented by any Solana program. + +During transfers, Token-2022 calls a mint's configured transfer hook program +using this interface, as described in the +[Transfer Hook Extension Guide](../../token-2022/extensions#transfer-hook). +Additionally, a +[reference implementation](https://github.com/solana-program/transfer-hook/tree/main/program) +can be found in the SPL GitHub repository, detailing +how one might implement this interface in their own program. + +The Transfer Hook Interface is designed to allow token creators to "hook" +additional functionality into token transfers. The token program CPIs into the +transfer hook program using the interface-defined instruction. The transfer +hook program can then perform any custom functionality. + +In the case of Token-2022, a token creator configures a transfer hook program +using a mint extension, and this extension tells Token-2022 which program to +invoke whenever a transfer is conducted. + +With this interface, programs can compose highly customizable transfer +functionality that can be compatible with many other programs - particularly +tokens who implement the SPL Token interface. diff --git a/docs/src/transfer-hook-interface/configuring-extra-accounts.md b/docs/src/transfer-hook-interface/configuring-extra-accounts.md new file mode 100644 index 00000000000..2587b69929d --- /dev/null +++ b/docs/src/transfer-hook-interface/configuring-extra-accounts.md @@ -0,0 +1,183 @@ +--- +title: Configuring Extra Accounts +--- + +As mentioned previously, programs who implement the Transfer Hook interface can +provide additional custom functionality to token transfers. However, this +functionality may require additional accounts beyond those that exist in a +transfer instruction (source, mint, destination, etc.). + +Part of the Transfer Hook interface specification is the validation account - an +account which stores configurations for additional accounts required by the +transfer hook program. + +### The Validation Account + +The validation account is a PDA off of the transfer hook program derived from +the following seeds: + +``` +"extra-account-metas" + +``` + +As you can see, one validation account maps to one mint account. This means you +can customize the additional required accounts on a per-mint basis! + +The validation account stores configurations for extra accounts using +[Type-Length-Value](https://en.wikipedia.org/wiki/Type%E2%80%93length%E2%80%93value) +(TLV) encoding: +- **Type:** The instruction discriminator, in this case `Execute` +- **Length:** The total length of the subsequent data buffer, in this case a + `u32` +- **Data:** The data itself, in this case containing the extra account + configurations + +When a transfer hook program seeks to deserialize extra account configurations +from a validation account, it can find the 8-byte instruction discriminator for +`Execute`, then read the length, then use that length to deserialize the data. + +The data itself is a list of fixed-size configuration objects serialized into a +byte slab. Because the entries are fixed-length, we can use a custom "slice" +structure which divides the length by the fixed-length to determine the number +of entries. + +This custom slice structure is called a `PodSlice` and is part of the Solana +Program Library's +[Pod](https://github.com/solana-program/libraries/tree/main/pod) +library. The Pod library provides a handful of fixed-length types that +implement the `bytemuck` +[`Pod`](https://docs.rs/bytemuck/latest/bytemuck/trait.Pod.html) trait, as well +as the `PodSlice`. + +Another SPL library +useful for Type-Length-Value encoded data is +[Type-Length-Value](https://github.com/solana-program/libraries/tree/main/type-length-value) +which is used extensively to manage TLV-encoded data structures. + +### Dynamic Account Resolution + +When clients build a transfer instruction to the token program, they must +ensure the instruction includes all required accounts, especially the extra +required accounts you've specified in the validation account. + +These additional accounts must be _resolved_, and another library used to pull off +the resolution of additional accounts for transfer hooks is +[TLV Account Resolution](https://github.com/solana-program/libraries/tree/main/tlv-account-resolution). + +Using the TLV Account Resolution library, transfer hook programs can empower +**dynamic account resolution** of additional required accounts. This means that +no particular client or program needs to know the specific accounts your +transfer hook requires. Instead, they can be automatically resolved from the +validation account's data. + +In fact, the Transfer Hook interface offers helpers that perform this account +resolution in the +[onchain](https://github.com/solana-program/transfer-hook/blob/main/interface/src/onchain.rs) +and +[offchain](https://github.com/solana-program/transfer-hook/blob/main/interface/src/offchain.rs) +modules of the Transfer Hook interface crate. + +The account resolution is powered by the way configurations for additional +accounts are stored, and how they can be used to derive actual Solana addresses +and roles (signer, writeable, etc.) for accounts. + +### The `ExtraAccountMeta` Struct + +A member of the TLV Account Resolution library, the +[`ExtraAccountMeta`](https://github.com/solana-program/libraries/blob/c5cc979f188ddc136de2ff556173a6f655322915/tlv-account-resolution/src/account.rs#L123) +struct allows account configurations to be serialized into a fixed-length data +format of length 35 bytes. + +```rust +pub struct ExtraAccountMeta { + /// Discriminator to tell whether this represents a standard + /// `AccountMeta` or a PDA + pub discriminator: u8, + /// This `address_config` field can either be the pubkey of the account + /// or the seeds used to derive the pubkey from provided inputs + pub address_config: [u8; 32], + /// Whether the account should sign + pub is_signer: PodBool, + /// Whether the account should be writable + pub is_writable: PodBool, +} +``` + +As the documentation on the struct conveys, an `ExtraAccountMeta` can store +configurations for three types of accounts: + +|Discriminator|Account Type| +|:------------|:-----------| +|`0` | An account with a static address | +| `1` | A PDA off of the transfer hook program itself | +| `(1 << 7) + i ` | A PDA off of another program, where `i` is that program's index in the accounts list | + +`1 << 7` is the top bit of the `u8`, or `128`. If the program you are deriving +this PDA from is at index `9` of the accounts list for `Execute`, then the +discriminator for this account configuration is `128 + 9 = 137`. More on +determining this index later. + +#### Accounts With Static Addresses + +Static-address additional accounts are straightforward to serialize with +`ExtraAccountMeta`. The discriminator is simply `0` and the `address_config` is +the 32-byte public key. + +#### PDAs Off the Transfer Hook Program + +You might be wondering: "how can I store all of my PDA seeds in only 32 bytes?". +Well, you don't. Instead, you tell the account resolution functionality _where_ +to find the seeds you need. + +To do this, the transfer hook program can use the +[`Seed`](https://github.com/solana-program/libraries/blob/c5cc979f188ddc136de2ff556173a6f655322915/tlv-account-resolution/src/seeds.rs#L38) +enum to describe their seeds and where to find them. With the exception of +literals, these seed configurations comprise only a small handful of bytes. + +The following types of seeds are supported by the `Seed` enum and can be used to +create an `address_config` array of bytes. +- **Literal**: The literal seed itself encoded to bytes +- **Instruction Data:** A slice of the instruction data, denoted by the `index` + (offset) and `length` of bytes to slice +- **AccountKey:** The address of some account in the list as bytes, denoted by + the `index` at which this account can be found in the accounts list +- **Account Data:** A slice of an account's data, denoted by the `account_index` + at which this account can be found in the accounts list, as well as the + `data_index` (offset) and `length` of bytes to slice + +Here's an example of packing a list of `Seed` entries into a 32-byte +`address_config`: + +```rust +let seed1 = Seed::Literal { bytes: vec![1; 8] }; +let seed2 = Seed::InstructionData { + index: 0, + length: 4, +}; +let seed3 = Seed::AccountKey { index: 0 }; +let address_config: [u8; 32] = Seed::pack_into_address_config( + &[seed1, seed2, seed3] +)?; +``` + +#### PDAs Off Another Program + +Storing configurations for seeds for an address that is a PDA off of another +program is the same as above. However, the program whose address this account is +a PDA off of must be present in the account list. Its index in the accounts list +is required to build the proper discriminator, and thus resolve the proper PDA. + +```rust +let program_index = 7; +let seeds = &[seed1, seed2, seed3]; +let is_signer = false; +let is_writable = true; + +let extra_meta = ExtraAccountMeta::new_external_pda_with_seeds( + program_index, + seeds, + is_signer, + is_writable, +)?; +``` + diff --git a/docs/src/transfer-hook-interface/examples.md b/docs/src/transfer-hook-interface/examples.md new file mode 100644 index 00000000000..7a4fc1ed0b8 --- /dev/null +++ b/docs/src/transfer-hook-interface/examples.md @@ -0,0 +1,223 @@ +--- +title: Examples +--- + +More examples can be found in the +[Transfer Hook example tests](https://github.com/solana-program/transfer-hook/blob/main/program/tests/functional.rs), +as well as the +[TLV Account Resolution tests](https://github.com/solana-program/libraries/blob/main/tlv-account-resolution/src/state.rs). + +### Initializing Extra Account Metas On-Chain + +The +[`ExtraAccountMetaList`](https://github.com/solana-program/libraries/blob/c5cc979f188ddc136de2ff556173a6f655322915/tlv-account-resolution/src/state.rs#L164) +struct is designed to make working with extra account +configurations as seamless as possible. + +Using `ExtraAccountMetaList::init(..)`, you can initialize a buffer with the +serialized `ExtraAccountMeta` configurations by simply providing a mutable +reference to the buffer and a slice of `ExtraAccountMeta`. The generic `T` is +the instruction whose discriminator the extra account configurations should be +assigned to. In our case, this will be +[`spl_transfer_hook_interface::instruction::ExecuteInstruction`](https://github.com/solana-program/transfer-hook/blob/e00f3b5c591fd55b4aed6a1e9b1ccc502cb6da05/interface/src/instruction.rs#L67) +from the Transfer Hook interface. + +> Note: All instructions from the SPL Transfer Hook interface implement the +> trait +> [`SplDiscriminate`](https://github.com/solana-program/libraries/blob/c5cc979f188ddc136de2ff556173a6f655322915/discriminator/src/discriminator.rs#L10), +> which provides a constant 8-byte discriminator that +> can be used to create a TLV data entry. + +```rust +pub fn process_initialize_extra_account_meta_list( + program_id: &Pubkey, + accounts: &[AccountInfo], + extra_account_metas: &[ExtraAccountMeta], +) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + + let validation_info = next_account_info(account_info_iter)?; + let mint_info = next_account_info(account_info_iter)?; + let authority_info = next_account_info(account_info_iter)?; + let _system_program_info = next_account_info(account_info_iter)?; + + // Check validation account + let (expected_validation_address, bump_seed) = + get_extra_account_metas_address_and_bump_seed(mint_info.key, program_id); + if expected_validation_address != *validation_info.key { + return Err(ProgramError::InvalidSeeds); + } + + // Create the account + let bump_seed = [bump_seed]; + let signer_seeds = collect_extra_account_metas_signer_seeds(mint_info.key, &bump_seed); + let length = extra_account_metas.len(); + let account_size = ExtraAccountMetaList::size_of(length)?; + invoke_signed( + &system_instruction::allocate(validation_info.key, account_size as u64), + &[validation_info.clone()], + &[&signer_seeds], + )?; + invoke_signed( + &system_instruction::assign(validation_info.key, program_id), + &[validation_info.clone()], + &[&signer_seeds], + )?; + + // Write the data + let mut data = validation_info.try_borrow_mut_data()?; + ExtraAccountMetaList::init::(&mut data, extra_account_metas)?; + + Ok(()) +} +``` + +After calling `ExtraAccountMetaList::init::(..)` on the +mutable account data, the account now stores all of the serialized extra account +configurations for an `Execute` instruction! + +### Resolving Extra Account Metas Off-Chain + +When building a transaction with an instruction, either for your transfer hook +program directly or for a program that will CPI to your transfer hook program, +you must include all required accounts - including the extra accounts. + +Below is an example of the logic contained in the Transfer Hook interface's +[offchain helper](https://github.com/solana-program/transfer-hook/blob/e00f3b5c591fd55b4aed6a1e9b1ccc502cb6da05/interface/src/offchain.rs#L48). + +```rust +// You'll need to provide an "account data function", which is a function that +// can, given a `Pubkey`, return account data within an `AccountDataResult`. +// This is most likely based off of an RPC call like `getAccountInfo`. + +// Load the validation state data +let validate_state_pubkey = get_extra_account_metas_address(mint_pubkey, program_id); +let validate_state_data = fetch_account_data_fn(validate_state_pubkey) + .await? + .ok_or(ProgramError::InvalidAccountData)?; + + +// First create an `ExecuteInstruction` +let mut execute_instruction = execute( + program_id, + source_pubkey, + mint_pubkey, + destination_pubkey, + authority_pubkey, + &validate_state_pubkey, + amount, +); + +// Resolve all additional required accounts for `ExecuteInstruction` +ExtraAccountMetaList::add_to_instruction::( + &mut execute_instruction, + fetch_account_data_fn, + &validate_state_data, +) +.await?; + +// Add only the extra accounts resolved from the validation state +instruction + .accounts + .extend_from_slice(&execute_instruction.accounts[5..]); + +// Add the program id and validation state account +instruction + .accounts + .push(AccountMeta::new_readonly(*program_id, false)); +instruction + .accounts + .push(AccountMeta::new_readonly(validate_state_pubkey, false)); +``` + +As you can see from the example, an important concept to remember is which +instruction these extra accounts are for. Even though you might be building an +instruction for some other program, which may not need them, if that program is +going to CPI to your transfer hook program, it needs to have the proper +accounts. + +Additionally, in order to perform a successful dynamic account resolution, the +proper instruction needs to be provided to align with the instruction that was +configured in the validation account - in this case the Transfer Hook +interface's `ExecuteInstruction`. This is why we first create an +`ExecuteInstruction`, then resolve the extra accounts for that instruction, and +finally add those accounts to our current instruction. + +### Resolving Extra Account Metas On-Chain for CPI + +During the execution of a program that seeks to CPI to your transfer hook +program, even though the additional required accounts were provided by the +offchain account resolution, the executing program has to know how to build a +CPI instruction with the proper accounts as well! + +Below is an example of the logic contained in the Transfer Hook interface's +[onchain helper](https://github.com/solana-program/transfer-hook/blob/e00f3b5c591fd55b4aed6a1e9b1ccc502cb6da05/interface/src/onchain.rs#L15). + +```rust +// Find the validation account from the list of `AccountInfo`s and load its +// data +let validate_state_pubkey = get_extra_account_metas_address(mint_info.key, program_id); +let validate_state_info = account_infos + .iter() + .find(|&x| *x.key == validate_state_pubkey) + .ok_or(TransferHookError::IncorrectAccount)?; + +// Find the transfer hook program ID +let program_info = account_infos + .iter() + .find(|&x| x.key == program_id) + .ok_or(TransferHookError::IncorrectAccount)?; + +// First create an `ExecuteInstruction` +let mut execute_instruction = instruction::execute( + program_id, + source_info.key, + mint_info.key, + destination_info.key, + authority_info.key, + &validate_state_pubkey, + amount, +); +let mut execute_account_infos = vec![ + source_info, + mint_info, + destination_info, + authority_info, + validate_state_info.clone(), +]; + +// Resolve all additional required accounts for `ExecuteInstruction` +ExtraAccountMetaList::add_to_cpi_instruction::( + &mut execute_instruction, + &mut execute_account_infos, + &validate_state_info.try_borrow_data()?, + account_infos, +)?; + +// Add only the extra accounts resolved from the validation state +cpi_instruction + .accounts + .extend_from_slice(&execute_instruction.accounts[5..]); +cpi_account_infos.extend_from_slice(&execute_account_infos[5..]); + +// Add the program id and validation state account +cpi_instruction + .accounts + .push(AccountMeta::new_readonly(*program_id, false)); +cpi_instruction + .accounts + .push(AccountMeta::new_readonly(validate_state_pubkey, false)); +cpi_account_infos.push(program_info.clone()); +cpi_account_infos.push(validate_state_info.clone()); +``` + +Although this example may appear more verbose than its offchain counterpart, +it's actually doing the exact same steps, just with an instruction _and_ a list +of account infos, since CPI requires both. + +The key difference between `ExtraAccountMetaList::add_to_instruction(..)` and +`ExtraAccountMetaList::add_to_cpi_instruction(..)` is that the latter method +will find the corresponding `AccountInfo` in the list and add it to +`cpi_account_infos` at the same time as it adds the resolved `AccountMeta` to +the instruction, ensuring all resolved account keys are present in the +`AccountInfo` list. diff --git a/docs/src/transfer-hook-interface/specification.md b/docs/src/transfer-hook-interface/specification.md new file mode 100644 index 00000000000..47570f4694f --- /dev/null +++ b/docs/src/transfer-hook-interface/specification.md @@ -0,0 +1,71 @@ +--- +title: Specification +--- + +The Transfer Hook interface specification includes two optional instructions and +one required one. + +Each instruction of the Transfer Hook interface uses a specific 8-byte +discriminator at the start of its instruction data. + +### Instruction: `Execute` + +The `Execute` instruction is required by any program who wishes to implement the +interface, and this is the instruction in which custom transfer functionality +will live. + +- **Discriminator:** First 8 bytes of the hash of the string literal + `"spl-transfer-hook-interface:execute"` +- **Data:** + - `amount: u64` - The transfer amount +- **Accounts:** + - 1 `[]`: Source token account + - 2 `[]`: Mint + - 3 `[]`: Destination token account + - 4 `[]`: Source token account authority + - 5 `[]`: Validation account + - `n` number of additional accounts, written into the validation account + +The **validation account** is a key piece of the Transfer Hook interface, and is +covered in more detail in the [next section](./configuring-extra-accounts). In +short, it's an account whose data stores configurations that can be deserialized +to determine which additional accounts are required by the transfer hook +program. + +The next two instructions of the interface deal with these configurations. + +### (Optional) Instruction: `InitializeExtraAccountMetaList` + +This instruction does exactly what the name implies: it initializes the +validation account to store a list of extra required +[`AccountMeta`](https://docs.rs/solana-program/latest/solana_program/instruction/struct.AccountMeta.html) +configurations for the `Execute` instruction. + +- **Discriminator:** First 8 bytes of the hash of the string literal + `"spl-transfer-hook-interface:initialize-extra-account-metas"` +- **Data:** + - `extra_account_metas: Vec` - A list of extra account + configurations to be written into the validation account +- **Accounts:** + - 1 `[writable]`: Validation account + - 2 `[]`: Mint + - 3 `[signer]`: Mint authority + - 4 `[]`: System program + +### (Optional) Instruction: `UpdateExtraAccountMetaList` + +The `UpdateExtraAccountMetaList` instruction allows an on-chain program to +update its list of required accounts for `Execute`. By implementing this +instruction, developers can make updates to their list of required extra +accounts stored in the validation account. + +- **Discriminator:** First 8 bytes of the hash of the string literal + `"spl-transfer-hook-interface:update-extra-account-metas"` +- **Data:** + - `extra_account_metas: Vec` - A list of extra account + configurations to be written into the validation account +- **Accounts:** + - 1 `[writable]`: Validation account + - 2 `[]`: Mint + - 3 `[signer]`: Mint authority + diff --git a/examples/c/README.md b/examples/c/README.md index ce7ba1e68fd..446d53bfe46 100644 --- a/examples/c/README.md +++ b/examples/c/README.md @@ -19,4 +19,9 @@ To build the examples and run the tests: ```bash $ make -``` \ No newline at end of file +``` + +## Audit + +The repository [README](https://github.com/solana-labs/solana-program-library#audits) +contains information about program audits. diff --git a/examples/c/makefile b/examples/c/makefile index 83c4b7f645e..fbc041bc386 100644 --- a/examples/c/makefile +++ b/examples/c/makefile @@ -1,2 +1,2 @@ OUT_DIR := ../../target/deploy -include ~/.local/share/solana/install/active_release/bin/sdk/bpf/c/bpf.mk +include ~/.local/share/solana/install/active_release/bin/sdk/sbf/c/sbf.mk diff --git a/examples/c/src/cross-program-invocation/cross-program-invocation.c b/examples/c/src/cross-program-invocation/cross-program-invocation.c index e13104cb95e..259585e3d10 100644 --- a/examples/c/src/cross-program-invocation/cross-program-invocation.c +++ b/examples/c/src/cross-program-invocation/cross-program-invocation.c @@ -30,7 +30,23 @@ extern uint64_t do_invoke(SolParameters *params) { if (!SolPubkey_same(&expected_allocated_key, allocated_info->key)) { return ERROR_INVALID_ARGUMENT; } - + /* + System program instruction source: https://github.com/solana-labs/solana/blob/master/sdk/program/src/system_instruction.rs + Enum Values: + 0: CreateAccount + 1: Assign + 2: Transfer + 3: CreateAccountWithSeed + 4: AdvanceNonceAccount + 5: WithdrawNonceAccount + 6: InitializeNonceAccount + 7: AuthorizeNonceAccount + 8: Allocate + 9: AllocateWithSeed + 10: AssignWithSeed + 11: TransferWithSeed + 12: UpgradeNonceAccount + */ SolAccountMeta arguments[] = {{allocated_info->key, true, true}}; uint8_t data[4 + 8]; // Enough room for the Allocate instruction *(uint16_t *)data = 8; // Allocate instruction enum value diff --git a/examples/rust/README.md b/examples/rust/README.md index 892cbfd5354..5138284945e 100644 --- a/examples/rust/README.md +++ b/examples/rust/README.md @@ -8,3 +8,8 @@ with a live cluster. The root [README](../../README.md) gives instructions on how to build and test these examples. + +## Audit + +The repository [README](https://github.com/solana-labs/solana-program-library#audits) +contains information about program audits. diff --git a/examples/rust/cross-program-invocation/Cargo.toml b/examples/rust/cross-program-invocation/Cargo.toml index a8d5153f777..ca6cf3a81d4 100644 --- a/examples/rust/cross-program-invocation/Cargo.toml +++ b/examples/rust/cross-program-invocation/Cargo.toml @@ -2,22 +2,22 @@ name = "spl-example-cross-program-invocation" version = "1.0.0" description = "Solana Program Library Cross Program Invocation Example" -authors = ["Solana Maintainers "] +authors = ["Solana Labs Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" license = "Apache-2.0" -edition = "2018" +edition = "2021" publish = false [features] no-entrypoint = [] -test-bpf = [] +test-sbf = [] [dependencies] -solana-program = "1.10.33" +solana-program = "2.1.0" [dev-dependencies] -solana-program-test = "1.10.33" -solana-sdk = "1.10.33" +solana-program-test = "2.1.0" +solana-sdk = "2.1.0" [lib] crate-type = ["cdylib", "lib"] diff --git a/examples/rust/cross-program-invocation/src/entrypoint.rs b/examples/rust/cross-program-invocation/src/entrypoint.rs index 82641a41587..8876e45b78b 100644 --- a/examples/rust/cross-program-invocation/src/entrypoint.rs +++ b/examples/rust/cross-program-invocation/src/entrypoint.rs @@ -2,11 +2,9 @@ #![cfg(not(feature = "no-entrypoint"))] -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, pubkey::Pubkey, -}; +use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey}; -entrypoint!(process_instruction); +solana_program::entrypoint!(process_instruction); fn process_instruction( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/examples/rust/cross-program-invocation/tests/functional.rs b/examples/rust/cross-program-invocation/tests/functional.rs index 05847047526..e0c924abac3 100644 --- a/examples/rust/cross-program-invocation/tests/functional.rs +++ b/examples/rust/cross-program-invocation/tests/functional.rs @@ -1,5 +1,6 @@ -// Mark this test as BPF-only due to current `ProgramTest` limitations when CPIing into the system program -#![cfg(feature = "test-bpf")] +// Mark this test as BPF-only due to current `ProgramTest` limitations when +// CPIing into the system program +#![cfg(feature = "test-sbf")] use { solana_program::{ @@ -16,7 +17,7 @@ use { #[tokio::test] async fn test_cross_program_invocation() { - let program_id = Pubkey::from_str(&"invoker111111111111111111111111111111111111").unwrap(); + let program_id = Pubkey::from_str("invoker111111111111111111111111111111111111").unwrap(); let (allocated_pubkey, bump_seed) = Pubkey::find_program_address(&[b"You pass butter"], &program_id); let mut program_test = ProgramTest::new( @@ -32,7 +33,7 @@ async fn test_cross_program_invocation() { }, ); - let (mut banks_client, payer, recent_blockhash) = program_test.start().await; + let (banks_client, payer, recent_blockhash) = program_test.start().await; let mut transaction = Transaction::new_with_payer( &[Instruction::new_with_bincode( diff --git a/examples/rust/custom-heap/Cargo.toml b/examples/rust/custom-heap/Cargo.toml index f538963147d..93eaca3022e 100644 --- a/examples/rust/custom-heap/Cargo.toml +++ b/examples/rust/custom-heap/Cargo.toml @@ -2,27 +2,30 @@ name = "spl-example-custom-heap" version = "1.0.0" description = "Solana Program Library Custom Heap Example" -authors = ["Solana Maintainers "] +authors = ["Solana Labs Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" license = "Apache-2.0" -edition = "2018" +edition = "2021" publish = false [features] default = ["custom-heap"] custom-heap = [] no-entrypoint = [] -test-bpf = [] +test-sbf = [] [dependencies] -solana-program = "1.10.33" +solana-program = "2.1.0" [dev-dependencies] -solana-program-test = "1.10.33" -solana-sdk = "1.10.33" +solana-program-test = "2.1.0" +solana-sdk = "2.1.0" [lib] crate-type = ["cdylib", "lib"] [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] + +[lints] +workspace = true diff --git a/examples/rust/custom-heap/src/entrypoint.rs b/examples/rust/custom-heap/src/entrypoint.rs index 8955e6f93bf..16232528e38 100644 --- a/examples/rust/custom-heap/src/entrypoint.rs +++ b/examples/rust/custom-heap/src/entrypoint.rs @@ -2,18 +2,19 @@ #![cfg(not(feature = "no-entrypoint"))] -use solana_program::{ - account_info::AccountInfo, - entrypoint, - entrypoint::{ProgramResult, HEAP_LENGTH, HEAP_START_ADDRESS}, - pubkey::Pubkey, +use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey}; +#[cfg(target_os = "solana")] +use { + solana_program::entrypoint::{HEAP_LENGTH, HEAP_START_ADDRESS}, + std::{alloc::Layout, mem::size_of, ptr::null_mut, usize}, }; -use std::{alloc::Layout, mem::size_of, ptr::null_mut, usize}; /// Developers can implement their own heap by defining their own /// `#[global_allocator]`. The following implements a dummy for test purposes /// but can be flushed out with whatever the developer sees fit. +#[cfg(target_os = "solana")] struct BumpAllocator; +#[cfg(target_os = "solana")] unsafe impl std::alloc::GlobalAlloc for BumpAllocator { #[inline] unsafe fn alloc(&self, layout: Layout) -> *mut u8 { @@ -44,7 +45,7 @@ unsafe impl std::alloc::GlobalAlloc for BumpAllocator { #[global_allocator] static A: BumpAllocator = BumpAllocator; -entrypoint!(process_instruction); +solana_program::entrypoint!(process_instruction); fn process_instruction( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/examples/rust/custom-heap/tests/functional.rs b/examples/rust/custom-heap/tests/functional.rs index 98a3585ca37..a4575e0532b 100644 --- a/examples/rust/custom-heap/tests/functional.rs +++ b/examples/rust/custom-heap/tests/functional.rs @@ -9,7 +9,7 @@ use { #[tokio::test] async fn test_custom_heap() { let program_id = Pubkey::from_str("CustomHeap111111111111111111111111111111111").unwrap(); - let (mut banks_client, payer, recent_blockhash) = ProgramTest::new( + let (banks_client, payer, recent_blockhash) = ProgramTest::new( "spl_example_custom_heap", program_id, processor!(process_instruction), diff --git a/examples/rust/logging/Cargo.toml b/examples/rust/logging/Cargo.toml index 2166093d8e2..70312922678 100644 --- a/examples/rust/logging/Cargo.toml +++ b/examples/rust/logging/Cargo.toml @@ -2,22 +2,22 @@ name = "spl-example-logging" version = "1.0.0" description = "Solana Program Library Logging Example" -authors = ["Solana Maintainers "] +authors = ["Solana Labs Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" license = "Apache-2.0" -edition = "2018" +edition = "2021" publish = false [features] no-entrypoint = [] -test-bpf = [] +test-sbf = [] [dependencies] -solana-program = "1.10.33" +solana-program = "2.1.0" [dev-dependencies] -solana-program-test = "1.10.33" -solana-sdk = "1.10.33" +solana-program-test = "2.1.0" +solana-sdk = "2.1.0" [lib] crate-type = ["cdylib", "lib"] diff --git a/examples/rust/logging/src/entrypoint.rs b/examples/rust/logging/src/entrypoint.rs index 82641a41587..8876e45b78b 100644 --- a/examples/rust/logging/src/entrypoint.rs +++ b/examples/rust/logging/src/entrypoint.rs @@ -2,11 +2,9 @@ #![cfg(not(feature = "no-entrypoint"))] -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, pubkey::Pubkey, -}; +use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey}; -entrypoint!(process_instruction); +solana_program::entrypoint!(process_instruction); fn process_instruction( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/examples/rust/logging/tests/functional.rs b/examples/rust/logging/tests/functional.rs index a36a02931d3..e822cb1e9d1 100644 --- a/examples/rust/logging/tests/functional.rs +++ b/examples/rust/logging/tests/functional.rs @@ -12,7 +12,7 @@ use { #[tokio::test] async fn test_logging() { let program_id = Pubkey::from_str("Logging111111111111111111111111111111111111").unwrap(); - let (mut banks_client, payer, recent_blockhash) = ProgramTest::new( + let (banks_client, payer, recent_blockhash) = ProgramTest::new( "spl_example_logging", program_id, processor!(process_instruction), diff --git a/examples/rust/sysvar/Cargo.toml b/examples/rust/sysvar/Cargo.toml index 14ed6679bc1..ec5b7c62a39 100644 --- a/examples/rust/sysvar/Cargo.toml +++ b/examples/rust/sysvar/Cargo.toml @@ -2,22 +2,22 @@ name = "spl-example-sysvar" version = "1.0.0" description = "Solana Program Library Sysvar Example" -authors = ["Solana Maintainers "] +authors = ["Solana Labs Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" license = "Apache-2.0" -edition = "2018" +edition = "2021" publish = false [features] no-entrypoint = [] -test-bpf = [] +test-sbf = [] [dependencies] -solana-program = "1.10.33" +solana-program = "2.1.0" [dev-dependencies] -solana-program-test = "1.10.33" -solana-sdk = "1.10.33" +solana-program-test = "2.1.0" +solana-sdk = "2.1.0" [lib] crate-type = ["cdylib", "lib"] diff --git a/examples/rust/sysvar/src/entrypoint.rs b/examples/rust/sysvar/src/entrypoint.rs index 82641a41587..8876e45b78b 100644 --- a/examples/rust/sysvar/src/entrypoint.rs +++ b/examples/rust/sysvar/src/entrypoint.rs @@ -2,11 +2,9 @@ #![cfg(not(feature = "no-entrypoint"))] -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, pubkey::Pubkey, -}; +use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey}; -entrypoint!(process_instruction); +solana_program::entrypoint!(process_instruction); fn process_instruction( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/examples/rust/sysvar/src/processor.rs b/examples/rust/sysvar/src/processor.rs index a03793a086a..8dc13c15fc6 100644 --- a/examples/rust/sysvar/src/processor.rs +++ b/examples/rust/sysvar/src/processor.rs @@ -34,7 +34,8 @@ pub fn process_instruction( let rent_via_account = Rent::from_account_info(rent_sysvar_info)?; // Both produce the same sysvar assert_eq!(rent_via_sysvar, rent_via_account); - // Can't print `exemption_threshold` because BPF does not support printing floats + // Can't print `exemption_threshold` because BPF does not support printing + // floats msg!( "Rent: lamports_per_byte_year: {:?}, burn_percent: {:?}", rent_via_sysvar.lamports_per_byte_year, diff --git a/examples/rust/sysvar/tests/functional.rs b/examples/rust/sysvar/tests/functional.rs index e67c980e0f1..171d2c0078d 100644 --- a/examples/rust/sysvar/tests/functional.rs +++ b/examples/rust/sysvar/tests/functional.rs @@ -13,7 +13,7 @@ use { #[tokio::test] async fn test_sysvar() { let program_id = Pubkey::from_str("Sysvar1111111111111111111111111111111111111").unwrap(); - let (mut banks_client, payer, recent_blockhash) = ProgramTest::new( + let (banks_client, payer, recent_blockhash) = ProgramTest::new( "spl_example_sysvar", program_id, processor!(process_instruction), diff --git a/examples/rust/transfer-lamports/Cargo.toml b/examples/rust/transfer-lamports/Cargo.toml index 4a23aadc062..d571eab3641 100644 --- a/examples/rust/transfer-lamports/Cargo.toml +++ b/examples/rust/transfer-lamports/Cargo.toml @@ -2,21 +2,21 @@ name = "spl-example-transfer-lamports" version = "1.0.0" description = "Solana Program Library Transfer Lamports Example" -authors = ["Solana Maintainers "] +authors = ["Solana Labs Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" license = "Apache-2.0" -edition = "2018" +edition = "2021" [features] no-entrypoint = [] -test-bpf = [] +test-sbf = [] [dependencies] -solana-program = "1.10.33" +solana-program = "2.1.0" [dev-dependencies] -solana-program-test = "1.10.33" -solana-sdk = "1.10.33" +solana-program-test = "2.1.0" +solana-sdk = "2.1.0" [lib] crate-type = ["cdylib", "lib"] diff --git a/examples/rust/transfer-lamports/src/entrypoint.rs b/examples/rust/transfer-lamports/src/entrypoint.rs index 82641a41587..8876e45b78b 100644 --- a/examples/rust/transfer-lamports/src/entrypoint.rs +++ b/examples/rust/transfer-lamports/src/entrypoint.rs @@ -2,11 +2,9 @@ #![cfg(not(feature = "no-entrypoint"))] -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, pubkey::Pubkey, -}; +use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey}; -entrypoint!(process_instruction); +solana_program::entrypoint!(process_instruction); fn process_instruction( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/examples/rust/transfer-lamports/src/processor.rs b/examples/rust/transfer-lamports/src/processor.rs index 33aa39f5ad9..5c8bb94ef44 100644 --- a/examples/rust/transfer-lamports/src/processor.rs +++ b/examples/rust/transfer-lamports/src/processor.rs @@ -1,3 +1,4 @@ +#![allow(clippy::arithmetic_side_effects)] //! Program instruction processor use solana_program::{ diff --git a/examples/rust/transfer-lamports/tests/functional.rs b/examples/rust/transfer-lamports/tests/functional.rs index d373859224c..0dcd1c9e7f3 100644 --- a/examples/rust/transfer-lamports/tests/functional.rs +++ b/examples/rust/transfer-lamports/tests/functional.rs @@ -34,7 +34,7 @@ async fn test_lamport_transfer() { ..Account::default() }, ); - let (mut banks_client, payer, recent_blockhash) = program_test.start().await; + let (banks_client, payer, recent_blockhash) = program_test.start().await; let mut transaction = Transaction::new_with_payer( &[Instruction::new_with_bincode( diff --git a/examples/rust/transfer-tokens/Cargo.toml b/examples/rust/transfer-tokens/Cargo.toml new file mode 100644 index 00000000000..52f0e02c6e1 --- /dev/null +++ b/examples/rust/transfer-tokens/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "spl-example-transfer-tokens" +version = "1.0.0" +description = "Solana Program Library Transfer Tokens Example" +authors = ["Solana Labs Maintainers "] +repository = "https://github.com/solana-labs/solana-program-library" +license = "Apache-2.0" +edition = "2021" + +[features] +no-entrypoint = [] +test-sbf = [] + +[dependencies] +solana-program = "2.1.0" +spl-token = { version = "7.0", features = [ "no-entrypoint" ] } + +[dev-dependencies] +solana-program-test = "2.1.0" +solana-sdk = "2.1.0" + +[lib] +crate-type = ["cdylib", "lib"] + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] diff --git a/examples/rust/transfer-tokens/src/entrypoint.rs b/examples/rust/transfer-tokens/src/entrypoint.rs new file mode 100644 index 00000000000..8876e45b78b --- /dev/null +++ b/examples/rust/transfer-tokens/src/entrypoint.rs @@ -0,0 +1,14 @@ +//! Program entrypoint + +#![cfg(not(feature = "no-entrypoint"))] + +use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey}; + +solana_program::entrypoint!(process_instruction); +fn process_instruction( + program_id: &Pubkey, + accounts: &[AccountInfo], + instruction_data: &[u8], +) -> ProgramResult { + crate::processor::process_instruction(program_id, accounts, instruction_data) +} diff --git a/examples/rust/transfer-tokens/src/lib.rs b/examples/rust/transfer-tokens/src/lib.rs new file mode 100644 index 00000000000..04c0a8c27bb --- /dev/null +++ b/examples/rust/transfer-tokens/src/lib.rs @@ -0,0 +1,6 @@ +//! A program demonstrating the transfer of lamports +#![deny(missing_docs)] +#![forbid(unsafe_code)] + +mod entrypoint; +pub mod processor; diff --git a/examples/rust/transfer-tokens/src/processor.rs b/examples/rust/transfer-tokens/src/processor.rs new file mode 100644 index 00000000000..b47bab2eefe --- /dev/null +++ b/examples/rust/transfer-tokens/src/processor.rs @@ -0,0 +1,75 @@ +//! Program instruction processor + +use { + solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + msg, + program::invoke_signed, + program_error::ProgramError, + program_pack::Pack, + pubkey::Pubkey, + }, + spl_token::{ + instruction::transfer_checked, + state::{Account, Mint}, + }, +}; + +/// Instruction processor +pub fn process_instruction( + program_id: &Pubkey, + accounts: &[AccountInfo], + _instruction_data: &[u8], +) -> ProgramResult { + // Create an iterator to safely reference accounts in the slice + let account_info_iter = &mut accounts.iter(); + + // As part of the program specification the instruction gives: + let source_info = next_account_info(account_info_iter)?; // 1. + let mint_info = next_account_info(account_info_iter)?; // 2. + let destination_info = next_account_info(account_info_iter)?; // 3. + let authority_info = next_account_info(account_info_iter)?; // 4. + let token_program_info = next_account_info(account_info_iter)?; // 5. + + // In order to transfer from the source account, owned by the program-derived + // address, we must have the correct address and seeds. + let (expected_authority, bump_seed) = Pubkey::find_program_address(&[b"authority"], program_id); + if expected_authority != *authority_info.key { + return Err(ProgramError::InvalidSeeds); + } + + // The program transfers everything out of its account, so extract that from + // the account data. + let source_account = Account::unpack(&source_info.try_borrow_data()?)?; + let amount = source_account.amount; + + // The program uses `transfer_checked`, which requires the number of decimals + // in the mint, so extract that from the account data too. + let mint = Mint::unpack(&mint_info.try_borrow_data()?)?; + let decimals = mint.decimals; + + // Invoke the transfer + msg!("Attempting to transfer {} tokens", amount); + invoke_signed( + &transfer_checked( + token_program_info.key, + source_info.key, + mint_info.key, + destination_info.key, + authority_info.key, + &[], // no multisig allowed + amount, + decimals, + ) + .unwrap(), + &[ + source_info.clone(), + mint_info.clone(), + destination_info.clone(), + authority_info.clone(), + token_program_info.clone(), // not required, but better for clarity + ], + &[&[b"authority", &[bump_seed]]], + ) +} diff --git a/examples/rust/transfer-tokens/tests/functional.rs b/examples/rust/transfer-tokens/tests/functional.rs new file mode 100644 index 00000000000..b03f82b5433 --- /dev/null +++ b/examples/rust/transfer-tokens/tests/functional.rs @@ -0,0 +1,158 @@ +use { + solana_program::{ + instruction::{AccountMeta, Instruction}, + program_pack::Pack, + pubkey::Pubkey, + rent::Rent, + system_instruction, + }, + solana_program_test::{processor, tokio, ProgramTest}, + solana_sdk::{signature::Signer, signer::keypair::Keypair, transaction::Transaction}, + spl_example_transfer_tokens::processor::process_instruction, + spl_token::state::{Account, Mint}, + std::str::FromStr, +}; + +#[tokio::test] +async fn success() { + // Setup some pubkeys for the accounts + let program_id = Pubkey::from_str("TransferTokens11111111111111111111111111111").unwrap(); + let source = Keypair::new(); + let mint = Keypair::new(); + let destination = Keypair::new(); + let (authority_pubkey, _) = Pubkey::find_program_address(&[b"authority"], &program_id); + + // Add the program to the test framework + let program_test = ProgramTest::new( + "spl_example_transfer_tokens", + program_id, + processor!(process_instruction), + ); + let amount = 10_000; + let decimals = 9; + let rent = Rent::default(); + + // Start the program test + let (banks_client, payer, recent_blockhash) = program_test.start().await; + + // Setup the mint, used in `spl_token::instruction::transfer_checked` + let transaction = Transaction::new_signed_with_payer( + &[ + system_instruction::create_account( + &payer.pubkey(), + &mint.pubkey(), + rent.minimum_balance(Mint::LEN), + Mint::LEN as u64, + &spl_token::id(), + ), + spl_token::instruction::initialize_mint( + &spl_token::id(), + &mint.pubkey(), + &payer.pubkey(), + None, + decimals, + ) + .unwrap(), + ], + Some(&payer.pubkey()), + &[&payer, &mint], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await.unwrap(); + + // Setup the source account, owned by the program-derived address + let transaction = Transaction::new_signed_with_payer( + &[ + system_instruction::create_account( + &payer.pubkey(), + &source.pubkey(), + rent.minimum_balance(Account::LEN), + Account::LEN as u64, + &spl_token::id(), + ), + spl_token::instruction::initialize_account( + &spl_token::id(), + &source.pubkey(), + &mint.pubkey(), + &authority_pubkey, + ) + .unwrap(), + ], + Some(&payer.pubkey()), + &[&payer, &source], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await.unwrap(); + + // Setup the destination account, used to receive tokens from the account + // owned by the program-derived address + let transaction = Transaction::new_signed_with_payer( + &[ + system_instruction::create_account( + &payer.pubkey(), + &destination.pubkey(), + rent.minimum_balance(Account::LEN), + Account::LEN as u64, + &spl_token::id(), + ), + spl_token::instruction::initialize_account( + &spl_token::id(), + &destination.pubkey(), + &mint.pubkey(), + &payer.pubkey(), + ) + .unwrap(), + ], + Some(&payer.pubkey()), + &[&payer, &destination], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await.unwrap(); + + // Mint some tokens to the PDA account + let transaction = Transaction::new_signed_with_payer( + &[spl_token::instruction::mint_to( + &spl_token::id(), + &mint.pubkey(), + &source.pubkey(), + &payer.pubkey(), + &[], + amount, + ) + .unwrap()], + Some(&payer.pubkey()), + &[&payer], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await.unwrap(); + + // Create an instruction following the account order expected by the program + let transaction = Transaction::new_signed_with_payer( + &[Instruction::new_with_bincode( + program_id, + &(), + vec![ + AccountMeta::new(source.pubkey(), false), + AccountMeta::new_readonly(mint.pubkey(), false), + AccountMeta::new(destination.pubkey(), false), + AccountMeta::new_readonly(authority_pubkey, false), + AccountMeta::new_readonly(spl_token::id(), false), + ], + )], + Some(&payer.pubkey()), + &[&payer], + recent_blockhash, + ); + + // See that the transaction processes successfully + banks_client.process_transaction(transaction).await.unwrap(); + + // Check that the destination account now has `amount` tokens + let account = banks_client + .get_account(destination.pubkey()) + .await + .unwrap() + .unwrap(); + let token_account = Account::unpack(&account.data).unwrap(); + assert_eq!(token_account.amount, amount); +} diff --git a/farms/.gitignore b/farms/.gitignore deleted file mode 100644 index 60a8deaff8e..00000000000 --- a/farms/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/target -Cargo.lock -fund_stats.db diff --git a/farms/Cargo.toml b/farms/Cargo.toml deleted file mode 100644 index 816aee8b8a5..00000000000 --- a/farms/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[workspace] -members = [ - "farm-client", - "farm-ctrl", - "farm-rpc", - "farm-sdk", - "fund", - "router-main", - "router-raydium", - "router-saber", - "router-orca", - "vaults" -] - -[profile.release] -overflow-checks = true - -[profile.dev] -split-debuginfo = "unpacked" diff --git a/farms/README.md b/farms/README.md deleted file mode 120000 index 47c10cef5a6..00000000000 --- a/farms/README.md +++ /dev/null @@ -1 +0,0 @@ -docs/intro.md \ No newline at end of file diff --git a/farms/docs/crate.md b/farms/docs/crate.md deleted file mode 100644 index c3f031f97bd..00000000000 --- a/farms/docs/crate.md +++ /dev/null @@ -1,5 +0,0 @@ -This Crate is a part of Solana Farms suite which is released along with [Solana Program Library](https://github.com/solana-labs/solana-program-library/blob/master/farms). - -Detailed information about Solana Farms project and how to use this Crate is available in the [Documentation](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/intro.md). - -If you still have questions please contact [Support](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/support.md). diff --git a/farms/docs/disclaimer.md b/farms/docs/disclaimer.md deleted file mode 100755 index b5e41c796e9..00000000000 --- a/farms/docs/disclaimer.md +++ /dev/null @@ -1,5 +0,0 @@ -# Disclaimer - -All claims, content, designs, algorithms, estimates, roadmaps, specifications, and performance measurements described in this project are done with the good faith efforts Solana Labs, Inc. and its affiliates ("SL"). It is up to the reader to check and validate their accuracy and truthfulness. Furthermore nothing in this project constitutes a solicitation for investment. -Any content produced by SL or developer resources that SL provides have not been subject to audit and are for educational and inspiration purposes only. SL does not encourage, induce or sanction the deployment, integration or use of any such applications (including the code comprising the Solana blockchain protocol) in violation of applicable laws or regulations and hereby prohibits any such deployment, integration or use. This includes use of any such applications by the reader (a) in violation of export control or sanctions laws of the United States or any other applicable jurisdiction, (b) if the reader is located in or ordinarily resident in a country or territory subject to comprehensive sanctions administered by the U.S. Office of Foreign Assets Control (OFAC), or (c) if the reader is or is working on behalf of a Specially Designated National (SDN) or a person subject to similar blocking or denied party prohibitions. -The reader should be aware that U.S. export control and sanctions laws prohibit U.S. persons (and other persons that are subject to such laws) from transacting with persons in certain countries and territories or that are on the SDN list. As a project based primarily on open-source software, it is possible that such sanctioned persons may nevertheless bypass prohibitions, obtain the code comprising the Solana blockchain protocol (or other project code or applications) and deploy, integrate, or otherwise use it. Accordingly, there is a risk to individuals that other persons using the Solana blockchain protocol may be sanctioned persons and that transactions with such persons would be a violation of U.S. export controls and sanctions law. This risk applies to individuals, organizations, and other ecosystem participants that deploy, integrate, or use the Solana blockchain protocol code directly (e.g., as a node operator), and individuals that transact on the Solana blockchain through light clients, third party interfaces, and/or wallet software. diff --git a/farms/docs/farm_client_cli.md b/farms/docs/farm_client_cli.md deleted file mode 100755 index c3818b7caee..00000000000 --- a/farms/docs/farm_client_cli.md +++ /dev/null @@ -1,127 +0,0 @@ -# Farm Client CLI - -`solana-farm-client` is a client-side command-line tool for interacting with liquidity Pools, Farms, Vaults, and Funds. It can also print on-chain metadata and perform general operations with tokens, system accounts, and governance. -Under the hood, it leverages [Rust Client](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/rust_client.md), but alternatively, the same functionality can be achieved by using [HTTP Client](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/http_client.md) or by sending raw instructions. - -All commands handled by `solana-farm-client` don't require Main Router admin or Fund manager privileges. - -## General commands - - balance Print SOL balance - transfer Transfer SOL to another wallet - token-address Print associated token account address - token-balance Print token balance - token-close Close associated token account - token-create Create associated token account - token-data Print token account metadata - token-supply Print token supply - token-transfer Transfer tokens to another wallet - oracle-price Print oracle price - unwrap-sol Transfer WSOL back to SOL by closing ATA - wrap-sol Transfer SOL to the associated WSOL account - sync-token-balance Updates token balance of the account - wallet-balances Print all token balances for the wallet - protocols Print description and stats of all supported protocols - -## Metadata commands - - get Query specified object in blockchain and print - get-all Query all objects of the given type and print - get-ref Query specified object by reference address and print - list-all Query all object names of the given type and print - -## Liquidity Pool commands - - find-pools Find all Pools with tokens A and B - find-pools-with-lp Find all Pools for the given LP token - pool-price Print pool price - swap Swap tokens in the pool - deposit-pool Add liquidity to the pool - withdraw-pool Remove liquidity from the pool - -## Farm commands - - find-farms-with-lp Find all Farms for the given LP token - stake Stake LP tokens to the farm - stake-balance Print user's stake balance in the farm - unstake Unstake LP tokens from the farm - harvest Harvest farm rewards - -## Vault commands - - find-vaults Find all Vaults with tokens A and B - find-vaults-with-vt Find all Vaults for the given VT token - crank-vault Crank single vault - crank-vaults Crank all vaults - deposit-vault Add liquidity to the vault - deposit-vault-locked Add locked liquidity to the vault - withdraw-vault Remove liquidity from the vault - withdraw-vault-unlocked Remove unlocked liquidity from the vault - vault-info Print vault stats - vault-user-info Print user stats for the vault - -## Fund commands - - find-funds Find all Funds with Vault names matching given pattern - request-deposit-fund Request a new deposit to the fund - cancel-deposit-fund Cancel pending deposit to the Fund - request-withdrawal-fund Request a new withdrawal from the Fund - cancel-withdrawal-fund Cancel pending withdrawal from the Fund - fund-assets Print fund assets info - fund-custodies Print all fund custodies - fund-custody Print fund custody info - fund-info Print fund stats - fund-user-info Print user stats for the fund - fund-user-requests Print user requests for the fund - fund-vault Print fund vault info - fund-vaults Print all fund vaults - start-liquidation-fund Start the Fund liquidation - update-fund-assets-with-custodies Update fund assets info based on all custodies - update-fund-assets-with-custody Update fund assets info based on custody holdings - update-fund-assets-with-vault Update fund assets info based on vault holdings - update-fund-assets-with-vaults Update fund assets info based on all vaults - -## Governance commands - - get-address Get governance account address - get-config Get governance config - get-instruction Print stored instruction in the proposal - custody-new Create new token custody account - proposal-new Create a new proposal - proposal-cancel Cancel the proposal - proposal-state Get proposal state - sign-off Sign off the proposal - signatory-add Add a signatory to the proposal - signatory-remove Remove the signatory from the proposal - tokens-deposit Deposit governing tokens - tokens-withdraw Withdraw governing tokens - vote-cast Cast a vote on the proposal - vote-finalize Finalize the vote on the proposal - vote-relinquish Remove the vote from the proposal - instruction-execute Execute the instruction in the proposal - instruction-flag-error Mark the instruction as failed - instruction-insert Add a new custom instruction to the proposal - instruction-insert-deposit-pool Add a new add liquidity to the pool instruction to the proposal - instruction-insert-deposit-vault Add a new add liquidity to the vault instruction to the proposal - instruction-insert-harvest Add a new harvest instruction to the proposal - instruction-insert-program-upgrade Add a new program upgrade instruction to the proposal - instruction-insert-stake Add a new stake instruction to the proposal - instruction-insert-swap Add a new swap instruction to the proposal - instruction-insert-token-transfer Add a new token transfer instruction to the proposal - instruction-insert-unstake Add a new unstake instruction to the proposal - instruction-insert-withdraw-fees-vault Add a new withdraw fees from the vault instruction to the proposal - instruction-insert-withdraw-pool Add a new remove liquidity from the pool instruction to the proposal - instruction-insert-withdraw-vault Add a new remove liquidity from the vault instruction to the proposal - instruction-remove Remove the instruction from the proposal - instruction-verify Verify custom instruction in the proposal - instruction-verify-deposit-pool Verify that instruction in the proposal is an add liquidity to the pool - instruction-verify-deposit-vault Verify that instruction in the proposal is an add liquidity to the vault - instruction-verify-harvest Verify that instruction in the proposal is a harvest - instruction-verify-program-upgrade Verify that instruction in the proposal is a program upgrade - instruction-verify-stake Verify that instruction in the proposal is a stake - instruction-verify-swap Verify that instruction in the proposal is a swap - instruction-verify-token-transfer Verify that instruction in the proposal is a token transfer - instruction-verify-unstake Verify that instruction in the proposal is an unstake - instruction-verify-withdraw-fees-vault Verify that instruction in the proposal is a withdraw fees from the vault - instruction-verify-withdraw-pool Verify that instruction in the proposal is a remove liquidity from the pool - instruction-verify-withdraw-vault Verify that instruction in the proposal is a remove liquidity from the vault diff --git a/farms/docs/farm_ctrl_cli.md b/farms/docs/farm_ctrl_cli.md deleted file mode 100755 index d9853f81d3a..00000000000 --- a/farms/docs/farm_ctrl_cli.md +++ /dev/null @@ -1,99 +0,0 @@ -# Farm Control CLI - -`solana-farm-ctrl` is a command-line tool for on-chain data management, Funds, and Vaults control. It can also generate metadata for Funds, Vaults, and their liquidity tokens. -Under the hood, it leverages [Rust Client](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/rust_client.md), but alternatively, the same functionality can be achieved by executing instructions directly. - -Most of the commands executed by `solana-farm-ctrl` require Main Router admin or Fund manager privileges. It is not intended to be used by the end-users. If multisig is enabled, different admins must execute the same command multiple times until the required number of signatures is collected. - -## Reference Database commands - - init Initialize Reference DB on-chain - init-all Initialize Reference DB of all storage types on-chain - drop Drop on-chain Reference DB - drop-all Drop on-chain Reference DB for all storage types - print-pda-all Derive Reference DB addresses for all objects - print-size Print Reference DB and specified object sizes - print-size-all Print Reference DB and all object sizes - -## Metadata commands - - get Query specified object in blockchain and print - get-all Query all objects of the given type and print - get-ref Query specified object by reference address and print - list-all Query all objects of the given type and print - generate Generate json boilerplate for the specified object - load Load objects from file and send to blockchain - load-all Same as "load" - remove Remove specified object from blockchain - remove-all Remove all objects of the given type from blockchain - remove-all-with-file Remove all objects in the file from blockchain - remove-ref Remove specified reference from blockchain - -## Vault commands - - vault-init Initialize the Vault - vault-crank Crank the Vault - vault-disable-deposits Disable deposits for the specified object - vault-disable-withdrawals Disable withdrawals for the specified object - vault-enable-deposits Enable deposits for the specified object - vault-enable-withdrawals Enable withdrawals for the specified object - vault-get-info Print current stats for the Vault - vault-get-admins Print current admin signers for the Vault - vault-set-admins Set new admins for the Vault - vault-set-external-fee Set new external fee percent for the Vault - vault-set-fee Set new fee percent for the Vault - vault-set-min-crank-interval Set new min crank interval in seconds for the Vault - vault-shutdown Shutdown the Vault - vault-withdraw-fees Withdraw collected fees from the Vault - -## Fund commands - - fund-add-custody Add a new custody to the Fund - fund-add-vault Add a new Vault to the Fund - fund-approve-deposit Approve pending deposit to the Fund - fund-approve-withdrawal Approve pending withdrawal from the Fund - fund-deny-deposit Deny pending deposit to the Fund - fund-deny-withdrawal Deny pending withdrawal from the Fund - fund-deposit-pool Add liquidity to the Pool in the Fund - fund-deposit-vault Add liquidity to the Vault in the Fund - fund-deposit-vault-locked Add locked liquidity to the Vault in the Fund - fund-disable-deposits Disables deposits to the Fund - fund-disable-withdrawals Disables withdrawals from the Fund - fund-get-admins Print current admin signers for the Fund - fund-get-info Print current stats for the Fund - fund-harvest Harvest rewards from the Farm in the Fund - fund-init Initialize the Fund - fund-lock-assets Moves assets from Deposit/Withdraw custody to the Fund - fund-remove-custody Remove the custody from the Fund - fund-remove-vault Remove the Vault from the Fund - fund-set-admins Set new admins for the Fund - fund-set-assets-tracking-config Set a new assets tracking config for the Fund - fund-set-deposit-schedule Set a new deposit schedule for the Fund - fund-set-manager Set a new manager for the Fund - fund-set-withdrawal-schedule Set a new withdrawal schedule for the Fund - fund-stake Stake LP tokens to the Farm in the Fund - fund-stop-liquidation Stop the Fund liquidation - fund-swap Swap tokens in the Fund - fund-unlock-assets Releases assets from the Fund to Deposit/Withdraw custody - fund-unstake Unstake LP tokens from the Farm in the Fund - fund-update-assets-with-custodies Update Fund assets info based on all custodies - fund-update-assets-with-custody Update Fund assets info based on custody holdings - fund-update-assets-with-vault Update Fund assets info based on Vault holdings - fund-update-assets-with-vaults Update Fund assets info based on all Vaults - fund-withdraw-fees Withdraw collected fees from the Fund - fund-withdraw-pool Remove liquidity from the Pool in the Fund - fund-withdraw-vault Remove liquidity from the Vault in the Fund - fund-withdraw-vault-unlocked Remove unlocked liquidity from the Vault in the Fund - -## Multisig commands - - get-admins Print current admin signers for the Main Router - set-admins Set new admins for the Main Router - program-get-admins Print current admin signers for the program - program-set-admins Set new admin signers for the program - program-set-single-authority Set single upgrade authority for the program - program-upgrade Upgrade the program from the data buffer - -## Governance commands - - governance init Initialize a new DAO diff --git a/farms/docs/fund.md b/farms/docs/fund.md deleted file mode 100755 index b5ecda39657..00000000000 --- a/farms/docs/fund.md +++ /dev/null @@ -1,56 +0,0 @@ -# Fund - -The Fund program implements a decentralized, non-custodial, and trustless capital management protocol. It is built on top of supported liquidity protocols, including Farm Vaults. Fund Managers are responsible for selecting a portfolio of assets their Fund will hold. These assets can be in various forms: individual tokens, liquidity invested into different Pools, staked into Farms, or deposited into Farm Vaults. - -Fund Managers are allowed to perform specific operations with tokens: swap, add/remove liquidity, stake/unstake/harvest, etc., and only in approved Pools, while all other actions are forbidden. It is enforced by the Fund program and allows investors to earn passive returns while maintaining custody of their assets (by holding Fund tokens that are minted upon each deposit and can be withdrawn for underlying assets). - -There could be any number of Funds, each implementing its own assets management strategy. Because of the blockchain nature, historical performance and current allocations are always transparent, so investors can make an informed decision on which Funds they want to invest in. - -## Build & Deploy - -To run the Fund, first, build and deploy Farm programs and upload metadata as described in the [Quick Start Guide](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/quick_start.md). - -To build and deploy the Fund program, run: - -```sh -cd solana-program-library/farms/fund -cargo build-bpf -solana program deploy ../target/deploy/solana_fund.so -``` - -Integration tests are located in the `fund/tests` directory and can be started as follows: - -```sh -cargo test -- --nocapture --test-threads=1 --ignored -``` - -These tests execute transactions on mainnet, which will cost you some SOL. - -The next step is to generate Fund metadata: - -```sh -solana-farm-ctrl --keypair main_admin.json generate Fund [FUND_PROGRAM_ADDRESS] [FUND_NAME] -``` - -Generated metadata should be manually saved to JSON files (tokens and funds separately) using a format similar to other tokens and vault files. And then uploaded with: - -```sh -solana-farm-ctrl --keypair main_admin.json load token fund_tokens.json -solana-farm-ctrl --keypair main_admin.json load fund funds.json -``` - -To verify metadata and installation, run `solana-farm-ctrl get-all fund` and `solana-farm-client fund-info [FUND_NAME]`. - -## Initialization - -Before a Fund can be used it, must be initialized with `solana-farm-ctrl fund-init [FUNDNAME]`. Instead of executing commands with `Farm Ctrl CLI`, alternatively, you can create and send corresponding instructions with [HTTP Client](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/http_client.md) or [Rust Client](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/rust_client.md). - -Each Fund has three types of configuration settings. First is Fund Assets Tracking Config, which can be set with `fund-set-assets-tracking-config`. It defines parameters such as assets limit, oracle price minimum quality, and whether or not to issue Fund tokens to depositors. Only admins are allowed to alter these settings. The other configs are Deposit and Withdrawal Schedules, which can be set with `fund-set-deposit-schedule` and `fund-set-withdrawal-schedule`. They define when deposits/withdrawals can be made, whether they will require the approval of the Fund Manager, fees, and amount limits. Deposit/Withdrawal configs can be set or modified by admins or Fund managers. - -Funds keep all assets in custodies. There are two types of custodies - DepositWithdraw and Trading. The former is used to accept initial deposits or process withdrawals and the latter to perform trading operations. Custodies can be added with `fund-add-custody`. Users will be allowed to make deposits and withdrawals only in tokens for which DepositWithdraw custodies have been created. Similarly, trading operations (like swaps, adding liquidity to a Farm or Vault, etc.) require corresponding Trading custodies to be pre-created, including the ones for holding LP tokens. Fund Manager can move tokens from DepositWithdraw custody to Trading or vice versa using `fund-lock-assets` and `fund-unlock-assets`. - -Liquidity Pools, Farms, and Vaults that particular Fund will be allowed to trade in or deposit liquidity to must be explicitly whitelisted. This can be done with `fund-add-vault` and require admin privileges. - -Fund Managers perform trading operations, deposit and withdrawal approvals (if enabled). New Fund Manager can be set with `fund-set-manager`. - -Whether the Fund is properly initialized can be verified with client tools, e.g. `solana-farm-client fund-info [FUND_NAME]`. diff --git a/farms/docs/governance.md b/farms/docs/governance.md deleted file mode 100755 index d804aa8d085..00000000000 --- a/farms/docs/governance.md +++ /dev/null @@ -1,36 +0,0 @@ -# Governance - -To initialize the DAO, first build and deploy the governance program: - -```sh -cd solana-program-library/governance/program -cargo build-bpf -solana program deploy --commitment finalized target/deploy/spl_governance.so -``` - -Then initialize the DAO using the Main Router admin account with: - -```sh -solana-farm-ctrl --keypair main_admin.json governance init [DAO_PROGRAM_ADDRESS] [DAO_TOKENS_TO_MINT] -``` - -It will take over on-chain programs upgrade authorities (including the DAO program itself) and DAO mint. Realm authority will also be removed. DAO tokens will be deposited to the admin account for further distribution. - -Farm client can be used to perform all DAO operations: create proposals, deposit tokens, sign-off, add or execute instructions, vote, etc. See help for details: - -```sh -solana-farm-client governance help -``` - -As part of DAO initialization, SOL token custody will be created (and more tokens can be added permissionless). Custody can be used to govern all interactions with Pools, Farms, or Vaults. It is useful if a third party manages funds, and every operation must be voted on first. [Rust Client](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/rust_client.md) or [Farm Client CLI](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/farm_client_cli.md) simplify instruction creation and verification process, here is a workflow example for already initialized DAO: - -```sh -solana-farm-client governance proposal-new FarmCustodyGovernance SwapTokens http://description.com 0 -solana-farm-client governance signatory-add FarmCustodyGovernance 0 J7paVZ8axBfUaGFDNknc7XF3GHjVLZzvL57FaCuxjJo7 -solana-farm-client governance instruction-insert-swap FarmCustodyGovernance 0 0 RDM RAY SRM 1.0 0.0 -solana-farm-client -k signer.json governance sign-off FarmCustodyGovernance 0 -solana-farm-client -k voter.json governance instruction-verify-swap FarmCustodyGovernance 0 0 RDM RAY SRM 1.0 0.0 -solana-farm-client -k voter.json governance vote-cast FarmCustodyGovernance 0 1 -solana-farm-client governance vote-finalize FarmCustodyGovernance 0 -solana-farm-client -k anyone.json governance instruction-execute FarmCustodyGovernance 0 0 -``` diff --git a/farms/docs/http_client.md b/farms/docs/http_client.md deleted file mode 100755 index b706629b933..00000000000 --- a/farms/docs/http_client.md +++ /dev/null @@ -1,3548 +0,0 @@ -# HTTP Client - -An easy way to interact with liquidity Pools, Farms, and Vaults or query on-chain information is by using Solana Farms HTTP RPC service. Under the hood, it wraps [Rust Client](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/rust_client.md) and serves its methods over HTTP. - -HTTP RPC service is a part of Farms suite, and to use it, existing deployment of Farm programs and metadata must be present per [Quick Start Guide](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/quick_start.md). - -To communicate with the service, use any tool or language that supports HTTP requests, for example: - -```sh -curl 'http://127.0.0.1:9090/api/v1/token_account_balance?wallet_address=9wsC5hx5JopG5VwoDiUGrvgM2NaYz6tS3uyhuneRKgcN&token_name=RAY' -``` - -You can also use [SwaggerHub](https://app.swaggerhub.com/apis-docs/ska22/SolanaFarms/0.1) to call any method interactively. Swagger schema is available in `solana-program-library/farms/farm-rpc/swagger.yaml`. - -The default endpoint port is `9000` and route prefix `/api/v1/`, e.g. `http://localhost:9000/api/v1`. A static page with descriptions and links to all methods will be displayed if the endpoint is opened in a browser without a particular method. - -## Signing Transactions - -While HTTP RPC service supports POST requests to interact with liquidity Pools, Farms, and Vaults, it is recommended for internal use or testing only because you will have to include a keypair with your request. Instead, you can sign a transaction locally with a wallet app and send it as usual via @solana/web3.js. To do so, you need to call an instruction building method (anything that starts with `new_instruction_` or `all_instructions_`) to receive a plain instruction in JSON, convert it, sign and send. Here is how it can be done in Javascript and Phantom: - -```js -const json_data = await ( - await fetch( - "http://127.0.0.1:9090/api/v1/new_instruction_add_liquidity_vault?wallet_address=9wsC5hx5JopG5VwoDiUGrvgM2NaYz6tS3uyhuneRKgcN&vault_name=RDM.STC.RAY-SRM&max_token_a_ui_amount=0.1&max_token_b_ui_amount=0.0" - ) -).json(); - -json_data.accounts.forEach(function (item, index) { - let acc = { - isSigner: item.is_signer ? true : false, - isWritable: item.is_writable ? true : false, - pubkey: new PublicKey(item.pubkey), - }; - accounts.push(acc); -}); - -const instruction = new TransactionInstruction({ - programId: new PublicKey(json_data.program_id), - data: json_data.data, - keys: accounts, -}); - -let transaction = new Transaction({ - recentBlockhash: (await this.connection.getRecentBlockhash()).blockhash, - feePayer: this.state.provider.publicKey, -}); -transaction.add(instruction); - -let signed = await this.state.provider.signTransaction(transaction); -let signature = await this.connection.sendRawTransaction(signed.serialize()); -``` - -No additional JS bindings or other dependencies are required for the above to work besides standard @solana/web3.js. - -## Methods - -### Get - -[protocols](#get-protocols) -[admins](#get-admins) -[program_admins](#get-program_admins) -[git_token](#get-git_token) -[git_tokens](#get-git_tokens) -[fund](#get-fund) -[funds](#get-funds) -[fund_ref](#get-fund_ref) -[fund_refs](#get-fund_refs) -[fund_by_ref](#get-fund_by_ref) -[fund_name](#get-fund_name) -[find_funds](#get-find_funds) -[vault](#get-vault) -[vaults](#get-vaults) -[vault_ref](#get-vault_ref) -[vault_refs](#get-vault_refs) -[vault_by_ref](#get-vault_by_ref) -[vault_name](#get-vault_name) -[find_vaults](#get-find_vaults) -[find_vaults_with_vt](#get-find_vaults_with_vt) -[pool](#get-pool) -[pools](#get-pools) -[pool_ref](#get-pool_ref) -[pool_refs](#get-pool_refs) -[pool_by_ref](#get-pool_by_ref) -[pool_name](#get-pool_name) -[find_pools](#get-find_pools) -[find_pools_with_lp](#get-find_pools_with_lp) -[pool_price](#get-pool_price) -[oracle](#get-oracle) -[oracle_price](#get-oracle_price) -[farm](#get-farm) -[farms](#get-farms) -[farm_ref](#get-farm_ref) -[farm_refs](#get-farm_refs) -[farm_by_ref](#get-farm_by_ref) -[farm_name](#get-farm_name) -[find_farms_with_lp](#get-find_farms_with_lp) -[token](#get-token) -[tokens](#get-tokens) -[token_ref](#get-token_ref) -[token_refs](#get-token_refs) -[token_by_ref](#get-token_by_ref) -[token_name](#get-token_name) -[token_with_mint](#get-token_with_mint) -[token_with_account](#get-token_with_account) -[program_id](#get-program_id) -[program_ids](#get-program_ids) -[program_name](#get-program_name) -[is_official_id](#get-is_official_id) -[is_fund_manager](#get-is_fund_manager) -[managed_funds](#get-managed_funds) -[token_supply](#get-token_supply) -[associated_token_address](#get-associated_token_address) -[wallet_tokens](#get-wallet_tokens) -[token_account_data](#get-token_account_data) -[account_balance](#get-account_balance) -[token_account_balance](#get-token_account_balance) -[token_account_balance_with_address](#get-token_account_balance_with_address) -[has_active_token_account](#get-has_active_token_account) -[fund_admins](#get-fund_admins) -[fund_user_info](#get-fund_user_info) -[all_fund_user_infos](#get-all_fund_user_infos) -[fund_user_requests](#get-fund_user_requests) -[all_fund_user_requests](#get-all_fund_user_requests) -[fund_info](#get-fund_info) -[all_fund_infos](#get-all_fund_infos) -[fund_assets](#get-fund_assets) -[fund_custody](#get-fund_custody) -[fund_custody_with_balance](#get-fund_custody_with_balance) -[fund_custodies](#get-fund_custodies) -[fund_custodies_with_balance](#get-fund_custodies_with_balance) -[fund_vault](#get-fund_vault) -[fund_vaults](#get-fund_vaults) -[fund_stats](#get-fund_stats) -[user_stake_balance](#get-user_stake_balance) -[vault_stake_balance](#get-vault_stake_balance) -[vault_admins](#get-vault_admins) -[vault_user_info](#get-vault_user_info) -[vault_info](#get-vault_info) -[all_vault_infos](#get-all_vault_infos) -[vault_token_decimals](#get-vault_token_decimals) -[pool_tokens_decimals](#get-pool_tokens_decimals) -[new_instruction_create_system_account](#get-new_instruction_create_system_account) -[new_instruction_create_system_account_with_seed](#get-new_instruction_create_system_account_with_seed) -[new_instruction_close_system_account](#get-new_instruction_close_system_account) -[new_instruction_transfer](#get-new_instruction_transfer) -[new_instruction_token_transfer](#get-new_instruction_token_transfer) -[new_instruction_sync_token_balance](#get-new_instruction_sync_token_balance) -[new_instruction_create_token_account](#get-new_instruction_create_token_account) -[new_instruction_close_token_account](#get-new_instruction_close_token_account) -[new_instruction_user_init_vault](#get-new_instruction_user_init_vault) -[new_instruction_add_liquidity_vault](#get-new_instruction_add_liquidity_vault) -[new_instruction_lock_liquidity_vault](#get-new_instruction_lock_liquidity_vault) -[new_instruction_unlock_liquidity_vault](#get-new_instruction_unlock_liquidity_vault) -[new_instruction_remove_liquidity_vault](#get-new_instruction_remove_liquidity_vault) -[new_instruction_add_liquidity_pool](#get-new_instruction_add_liquidity_pool) -[new_instruction_remove_liquidity_pool](#get-new_instruction_remove_liquidity_pool) -[new_instruction_wrap_token](#get-new_instruction_wrap_token) -[new_instruction_unwrap_token](#get-new_instruction_unwrap_token) -[new_instruction_swap](#get-new_instruction_swap) -[new_instruction_user_init](#get-new_instruction_user_init) -[new_instruction_stake](#get-new_instruction_stake) -[new_instruction_unstake](#get-new_instruction_unstake) -[new_instruction_harvest](#get-new_instruction_harvest) -[new_instruction_crank_vault](#get-new_instruction_crank_vault) -[new_instruction_user_init_fund](#get-new_instruction_user_init_fund) -[new_instruction_request_deposit_fund](#get-new_instruction_request_deposit_fund) -[new_instruction_cancel_deposit_fund](#get-new_instruction_cancel_deposit_fund) -[new_instruction_request_withdrawal_fund](#get-new_instruction_request_withdrawal_fund) -[new_instruction_cancel_withdrawal_fund](#get-new_instruction_cancel_withdrawal_fund) -[new_instruction_start_liquidation_fund](#get-new_instruction_start_liquidation_fund) -[new_instruction_disable_deposits_fund](#get-new_instruction_disable_deposits_fund) -[new_instruction_approve_deposit_fund](#get-new_instruction_approve_deposit_fund) -[new_instruction_deny_deposit_fund](#get-new_instruction_deny_deposit_fund) -[new_instruction_disable_withdrawals_fund](#get-new_instruction_disable_withdrawals_fund) -[new_instruction_approve_withdrawal_fund](#get-new_instruction_approve_withdrawal_fund) -[new_instruction_deny_withdrawal_fund](#get-new_instruction_deny_withdrawal_fund) -[new_instruction_lock_assets_fund](#get-new_instruction_lock_assets_fund) -[new_instruction_unlock_assets_fund](#get-new_instruction_unlock_assets_fund) -[new_instruction_update_fund_assets_with_custody](#get-new_instruction_update_fund_assets_with_custody) -[new_instruction_update_fund_assets_with_vault](#get-new_instruction_update_fund_assets_with_vault) -[new_instruction_fund_add_liquidity_pool](#get-new_instruction_fund_add_liquidity_pool) -[new_instruction_fund_remove_liquidity_pool](#get-new_instruction_fund_remove_liquidity_pool) -[new_instruction_fund_user_init_farm](#get-new_instruction_fund_user_init_farm) -[new_instruction_fund_stake](#get-new_instruction_fund_stake) -[new_instruction_fund_unstake](#get-new_instruction_fund_unstake) -[new_instruction_fund_harvest](#get-new_instruction_fund_harvest) -[new_instruction_fund_user_init_vault](#get-new_instruction_fund_user_init_vault) -[new_instruction_fund_add_liquidity_vault](#get-new_instruction_fund_add_liquidity_vault) -[new_instruction_fund_lock_liquidity_vault](#get-new_instruction_fund_lock_liquidity_vault) -[new_instruction_fund_unlock_liquidity_vault](#get-new_instruction_fund_unlock_liquidity_vault) -[new_instruction_fund_remove_liquidity_vault](#get-new_instruction_fund_remove_liquidity_vault) -[all_instructions_token_transfer](#get-all_instructions_token_transfer) -[all_instructions_wrap_sol](#get-all_instructions_wrap_sol) -[all_instructions_unwrap_sol](#get-all_instructions_unwrap_sol) -[all_instructions_add_liquidity_vault](#get-all_instructions_add_liquidity_vault) -[all_instructions_add_locked_liquidity_vault](#get-all_instructions_add_locked_liquidity_vault) -[all_instructions_remove_liquidity_vault](#get-all_instructions_remove_liquidity_vault) -[all_instructions_remove_unlocked_liquidity_vault](#get-all_instructions_remove_unlocked_liquidity_vault) -[all_instructions_add_liquidity_pool](#get-all_instructions_add_liquidity_pool) -[all_instructions_remove_liquidity_pool](#get-all_instructions_remove_liquidity_pool) -[all_instructions_swap](#get-all_instructions_swap) -[all_instructions_stake](#get-all_instructions_stake) -[all_instructions_unstake](#get-all_instructions_unstake) -[all_instructions_harvest](#get-all_instructions_harvest) -[all_instructions_request_deposit_fund](#get-all_instructions_request_deposit_fund) -[all_instructions_request_withdrawal_fund](#get-all_instructions_request_withdrawal_fund) -[all_instructions_fund_add_liquidity_pool](#get-all_instructions_fund_add_liquidity_pool) -[all_instructions_fund_remove_liquidity_pool](#get-all_instructions_fund_remove_liquidity_pool) -[all_instructions_fund_stake](#get-all_instructions_fund_stake) -[all_instructions_fund_unstake](#get-all_instructions_fund_unstake) -[all_instructions_fund_harvest](#get-all_instructions_fund_harvest) -[all_instructions_fund_add_liquidity_vault](#get-all_instructions_fund_add_liquidity_vault) -[all_instructions_fund_add_locked_liquidity_vault](#get-all_instructions_fund_add_locked_liquidity_vault) -[all_instructions_fund_remove_liquidity_vault](#get-all_instructions_fund_remove_liquidity_vault) -[all_instructions_fund_remove_unlocked_liquidity_vault](#get-all_instructions_fund_remove_unlocked_liquidity_vault) - -### Post - -[create_system_account](#post-create_system_account) -[create_system_account_with_seed](#post-create_system_account_with_seed) -[assign_system_account](#post-assign_system_account) -[close_system_account](#post-close_system_account) -[transfer](#post-transfer) -[token_transfer](#post-token_transfer) -[wrap_sol](#post-wrap_sol) -[unwrap_sol](#post-unwrap_sol) -[sync_token_balance](#post-sync_token_balance) -[create_token_account](#post-create_token_account) -[close_token_account](#post-close_token_account) -[user_init_vault](#post-user_init_vault) -[add_liquidity_vault](#post-add_liquidity_vault) -[add_locked_liquidity_vault](#post-add_locked_liquidity_vault) -[remove_liquidity_vault](#post-remove_liquidity_vault) -[remove_unlocked_liquidity_vault](#post-remove_unlocked_liquidity_vault) -[add_liquidity_pool](#post-add_liquidity_pool) -[remove_liquidity_pool](#post-remove_liquidity_pool) -[swap](#post-swap) -[user_init](#post-user_init) -[stake](#post-stake) -[unstake](#post-unstake) -[harvest](#post-harvest) -[crank_vault](#post-crank_vault) -[crank_vaults](#post-crank_vaults) -[reset_cache](#post-reset_cache) -[user_init_fund](#post-user_init_fund) -[request_deposit_fund](#post-request_deposit_fund) -[cancel_deposit_fund](#post-cancel_deposit_fund) -[request_withdrawal_fund](#post-request_withdrawal_fund) -[cancel_withdrawal_fund](#post-cancel_withdrawal_fund) -[start_liquidation_fund](#post-start_liquidation_fund) -[disable_deposits_fund](#post-disable_deposits_fund) -[approve_deposit_fund](#post-approve_deposit_fund) -[deny_deposit_fund](#post-deny_deposit_fund) -[disable_withdrawals_fund](#post-disable_withdrawals_fund) -[approve_withdrawal_fund](#post-approve_withdrawal_fund) -[deny_withdrawal_fund](#post-deny_withdrawal_fund) -[lock_assets_fund](#post-lock_assets_fund) -[unlock_assets_fund](#post-unlock_assets_fund) -[update_fund_assets_with_custody](#post-update_fund_assets_with_custody) -[update_fund_assets_with_custodies](#post-update_fund_assets_with_custodies) -[update_fund_assets_with_vault](#post-update_fund_assets_with_vault) -[update_fund_assets_with_vaults](#post-update_fund_assets_with_vaults) -[fund_add_liquidity_pool](#post-fund_add_liquidity_pool) -[fund_remove_liquidity_pool](#post-fund_remove_liquidity_pool) -[fund_user_init_farm](#post-fund_user_init_farm) -[fund_stake](#post-fund_stake) -[fund_unstake](#post-fund_unstake) -[fund_harvest](#post-fund_harvest) -[fund_user_init_vault](#post-fund_user_init_vault) -[fund_add_liquidity_vault](#post-fund_add_liquidity_vault) -[fund_add_locked_liquidity_vault](#post-fund_add_locked_liquidity_vault) -[fund_remove_liquidity_vault](#post-fund_remove_liquidity_vault) -[fund_remove_unlocked_liquidity_vault](#post-fund_remove_unlocked_liquidity_vault) - ---- - -## (GET) protocols - -Returns description and stats of all supported protocols - -### Parameters: - -No parameters - -### Results: - -The result will be an array of ProtocolInfo objects in Json or 404 status code with error description. - ---- - -## (GET) admins - -Returns current admin signers for the Main Router - -### Parameters: - -No parameters - -### Results: - -The result will be a Multisig object in Json or 404 status code with error description. - ---- - -## (GET) program_admins - -Returns program upgrade signers - -### Parameters: - -`program_id`: `Pubkey` - -### Results: - -The result will be a Multisig object in Json or 404 status code with error description. - ---- - -## (GET) git_token - -Returns Token metadata from Github - -### Parameters: - -`name`: `String` - -### Results: - -The result will be a GitToken object in Json or 404 status code with error description. - ---- - -## (GET) git_tokens - -Returns all Tokens from Github - -### Parameters: - -No parameters - -### Results: - -The result will be a GitTokens object in Json or 404 status code with error description. - ---- - -## (GET) fund - -Returns the Fund struct for the given name - -### Parameters: - -`name`: `String` - -### Results: - -The result will be a Fund object in Json or 404 status code with error description. - ---- - -## (GET) funds - -Returns all Funds available - -### Parameters: - -No parameters - -### Results: - -The result will be a FundMap object in Json or 404 status code with error description. - ---- - -## (GET) fund_ref - -Returns the Fund metadata address for the given name - -### Parameters: - -`name`: `String` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (GET) fund_refs - -Returns Fund refs: a map of Fund name to account address with metadata - -### Parameters: - -No parameters - -### Results: - -The result will be a PubkeyMap object in Json or 404 status code with error description. - ---- - -## (GET) fund_by_ref - -Returns the Fund metadata at the specified address - -### Parameters: - -`fund_ref`: `Pubkey` - -### Results: - -The result will be a Fund object in Json or 404 status code with error description. - ---- - -## (GET) fund_name - -Returns the Fund name for the given metadata address - -### Parameters: - -`fund_ref`: `Pubkey` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (GET) find_funds - -Returns all Funds that have Vaults with the name matching the pattern sorted by version - -### Parameters: - -`vault_name_pattern`: `String` - -### Results: - -The result will be an array of Fund objects in Json or 404 status code with error description. - ---- - -## (GET) vault - -Returns the Vault struct for the given name - -### Parameters: - -`name`: `String` - -### Results: - -The result will be a Vault object in Json or 404 status code with error description. - ---- - -## (GET) vaults - -Returns all Vaults available - -### Parameters: - -No parameters - -### Results: - -The result will be a VaultMap object in Json or 404 status code with error description. - ---- - -## (GET) vault_ref - -Returns the Vault metadata address for the given name - -### Parameters: - -`name`: `String` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (GET) vault_refs - -Returns Vault refs: a map of Vault name to account address with metadata - -### Parameters: - -No parameters - -### Results: - -The result will be a PubkeyMap object in Json or 404 status code with error description. - ---- - -## (GET) vault_by_ref - -Returns the Vault metadata at the specified address - -### Parameters: - -`vault_ref`: `Pubkey` - -### Results: - -The result will be a Vault object in Json or 404 status code with error description. - ---- - -## (GET) vault_name - -Returns the Vault name for the given metadata address - -### Parameters: - -`vault_ref`: `Pubkey` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (GET) find_vaults - -Returns all Vaults with tokens A and B sorted by version - -### Parameters: - -`token_a`: `String` -`token_b`: `String` - -### Results: - -The result will be an array of Vault objects in Json or 404 status code with error description. - ---- - -## (GET) find_vaults_with_vt - -Returns all Vaults with tokens A and B sorted by version - -### Parameters: - -`vt_token_name`: `String` - -### Results: - -The result will be an array of Vault objects in Json or 404 status code with error description. - ---- - -## (GET) pool - -Returns the Pool struct for the given name - -### Parameters: - -`name`: `String` - -### Results: - -The result will be a Pool object in Json or 404 status code with error description. - ---- - -## (GET) pools - -Returns all Pools available - -### Parameters: - -No parameters - -### Results: - -The result will be a PoolMap object in Json or 404 status code with error description. - ---- - -## (GET) pool_ref - -Returns the Pool metadata address for the given name - -### Parameters: - -`name`: `String` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (GET) pool_refs - -Returns Pool refs: a map of Pool name to account address with metadata - -### Parameters: - -No parameters - -### Results: - -The result will be a PubkeyMap object in Json or 404 status code with error description. - ---- - -## (GET) pool_by_ref - -Returns the Pool metadata at the specified address - -### Parameters: - -`pool_ref`: `Pubkey` - -### Results: - -The result will be a Pool object in Json or 404 status code with error description. - ---- - -## (GET) pool_name - -Returns the Pool name for the given metadata address - -### Parameters: - -`pool_ref`: `Pubkey` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (GET) find_pools - -Returns all Pools with tokens A and B sorted by version for the given protocol - -### Parameters: - -`protocol`: `String` -`token_a`: `String` -`token_b`: `String` - -### Results: - -The result will be an array of Pool objects in Json or 404 status code with error description. - ---- - -## (GET) find_pools_with_lp - -Returns all Pools sorted by version for the given LP token - -### Parameters: - -`lp_token`: `String` - -### Results: - -The result will be an array of Pool objects in Json or 404 status code with error description. - ---- - -## (GET) pool_price - -Returns pair's price based on the ratio of tokens in the pool - -### Parameters: - -`name`: `String` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (GET) oracle - -Returns oracle address for the given token - -### Parameters: - -`symbol`: `String` - -### Results: - -The result will be a Pubkey object in Json or 404 status code with error description. - ---- - -## (GET) oracle_price - -Returns the price in USD for the given token - -### Parameters: - -`symbol`: `String` -`max_price_age_sec`: `u64` -`max_price_error`: `f64` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (GET) farm - -Returns the Farm struct for the given name - -### Parameters: - -`name`: `String` - -### Results: - -The result will be a Farm object in Json or 404 status code with error description. - ---- - -## (GET) farms - -Returns all Farms available - -### Parameters: - -No parameters - -### Results: - -The result will be a FarmMap object in Json or 404 status code with error description. - ---- - -## (GET) farm_ref - -Returns the Farm metadata address for the given name - -### Parameters: - -`name`: `String` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (GET) farm_refs - -Returns Farm refs: a map of Farm name to account address with metadata - -### Parameters: - -No parameters - -### Results: - -The result will be a PubkeyMap object in Json or 404 status code with error description. - ---- - -## (GET) farm_by_ref - -Returns the Farm metadata at the specified address - -### Parameters: - -`farm_ref`: `Pubkey` - -### Results: - -The result will be a Farm object in Json or 404 status code with error description. - ---- - -## (GET) farm_name - -Returns the Farm name for the given metadata address - -### Parameters: - -`farm_ref`: `Pubkey` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (GET) find_farms_with_lp - -Returns all Farms for the given LP token - -### Parameters: - -`lp_token`: `String` - -### Results: - -The result will be an array of Farm objects in Json or 404 status code with error description. - ---- - -## (GET) token - -Returns the Token struct for the given name - -### Parameters: - -`name`: `String` - -### Results: - -The result will be a Token object in Json or 404 status code with error description. - ---- - -## (GET) tokens - -Returns all Tokens available - -### Parameters: - -No parameters - -### Results: - -The result will be a TokenMap object in Json or 404 status code with error description. - ---- - -## (GET) token_ref - -Returns the Token metadata address for the given name - -### Parameters: - -`name`: `String` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (GET) token_refs - -Returns Token refs: a map of Token name to account address with metadata - -### Parameters: - -No parameters - -### Results: - -The result will be a PubkeyMap object in Json or 404 status code with error description. - ---- - -## (GET) token_by_ref - -Returns the Token metadata at the specified address - -### Parameters: - -`token_ref`: `Pubkey` - -### Results: - -The result will be a Token object in Json or 404 status code with error description. - ---- - -## (GET) token_name - -Returns the Token name for the given metadata address - -### Parameters: - -`token_ref`: `Pubkey` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (GET) token_with_mint - -Returns the Token metadata for the specified mint - -### Parameters: - -`token_mint`: `Pubkey` - -### Results: - -The result will be a Token object in Json or 404 status code with error description. - ---- - -## (GET) token_with_account - -Returns the Token metadata for the specified token account - -### Parameters: - -`token_account`: `Pubkey` - -### Results: - -The result will be a Token object in Json or 404 status code with error description. - ---- - -## (GET) program_id - -Returns the official Program ID for the given name - -### Parameters: - -`name`: `String` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (GET) program_ids - -Returns all official Program IDs available - -### Parameters: - -No parameters - -### Results: - -The result will be a PubkeyMap object in Json or 404 status code with error description. - ---- - -## (GET) program_name - -Returns the official program name for the given Program ID - -### Parameters: - -`prog_id`: `Pubkey` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (GET) is_official_id - -Checks if the given address is the official Program ID - -### Parameters: - -`prog_id`: `Pubkey` - -### Results: - -The result will be a bool object in Json or 404 status code with error description. - ---- - -## (GET) is_fund_manager - -Checks if the given address is the Fund manager - -### Parameters: - -`wallet_address`: `Pubkey` - -### Results: - -The result will be a bool object in Json or 404 status code with error description. - ---- - -## (GET) managed_funds - -Returns all Funds managed by the given address - -### Parameters: - -`wallet_address`: `Pubkey` - -### Results: - -The result will be an array of Fund objects in Json or 404 status code with error description. - ---- - -## (GET) token_supply - -Returns token supply as UI amount - -### Parameters: - -`token_name`: `String` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (GET) associated_token_address - -Returns the associated token account address for the given token name - -### Parameters: - -`wallet_address`: `Pubkey` -`token_name`: `String` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (GET) wallet_tokens - -Returns all tokens with active account in the wallet - -### Parameters: - -`wallet_address`: `Pubkey` - -### Results: - -The result will be an array of String objects in Json or 404 status code with error description. - ---- - -## (GET) token_account_data - -Returns UiTokenAccount struct data for the associated token account address - -### Parameters: - -`wallet_address`: `Pubkey` -`token_name`: `String` - -### Results: - -The result will be a UiTokenAccount object in Json or 404 status code with error description. - ---- - -## (GET) account_balance - -Returns native SOL balance - -### Parameters: - -`wallet_address`: `Pubkey` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (GET) token_account_balance - -Returns token balance for the associated token account address - -### Parameters: - -`wallet_address`: `Pubkey` -`token_name`: `String` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (GET) token_account_balance_with_address - -Returns token balance for the specified token account address - -### Parameters: - -`token_account`: `Pubkey` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (GET) has_active_token_account - -Returns true if the associated token account exists and is initialized - -### Parameters: - -`wallet_address`: `Pubkey` -`token_name`: `String` - -### Results: - -The result will be a bool object in Json or 404 status code with error description. - ---- - -## (GET) fund_admins - -Returns current admin signers for the Fund - -### Parameters: - -`name`: `String` - -### Results: - -The result will be a Multisig object in Json or 404 status code with error description. - ---- - -## (GET) fund_user_info - -Returns user stats for specific Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` - -### Results: - -The result will be a FundUserInfo object in Json or 404 status code with error description. - ---- - -## (GET) all_fund_user_infos - -Returns user stats for all Funds - -### Parameters: - -`wallet_address`: `Pubkey` - -### Results: - -The result will be an array of FundUserInfo objects in Json or 404 status code with error description. - ---- - -## (GET) fund_user_requests - -Returns user requests for specific Fund and token - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`token_name`: `String` - -### Results: - -The result will be a FundUserRequests object in Json or 404 status code with error description. - ---- - -## (GET) all_fund_user_requests - -Returns user requests for all tokens accepted by the Fund - -### Parameters: - -`fund_name`: `String` - -### Results: - -The result will be an array of FundUserRequests objects in Json or 404 status code with error description. - ---- - -## (GET) fund_info - -Returns Fund stats and config - -### Parameters: - -`fund_name`: `String` - -### Results: - -The result will be a FundInfo object in Json or 404 status code with error description. - ---- - -## (GET) fund_assets - -Returns the Fund assets info - -### Parameters: - -`fund_name`: `String` -`asset_type`: `String` - -### Results: - -The result will be a FundAssets object in Json or 404 status code with error description. - ---- - -## (GET) fund_custody - -Returns the Fund custody info - -### Parameters: - -`fund_name`: `String` -`token_name`: `String` -`custody_type`: `String` - -### Results: - -The result will be a FundCustody object in Json or 404 status code with error description. - ---- - -## (GET) fund_custody_with_balance - -Returns the Fund custody extended info - -### Parameters: - -`fund_name`: `String` -`token_name`: `String` -`custody_type`: `String` - -### Results: - -The result will be a FundCustodyWithBalance object in Json or 404 status code with error description. - ---- - -## (GET) fund_custodies - -Returns all custodies belonging to the Fund sorted by custody_id - -### Parameters: - -`fund_name`: `String` - -### Results: - -The result will be an array of FundCustody objects in Json or 404 status code with error description. - ---- - -## (GET) fund_custodies_with_balance - -Returns all custodies belonging to the Fund with extended info - -### Parameters: - -`fund_name`: `String` - -### Results: - -The result will be an array of FundCustodyWithBalance objects in Json or 404 status code with error description. - ---- - -## (GET) fund_vault - -Returns the Fund Vault info - -### Parameters: - -`fund_name`: `String` -`vault_name`: `String` -`vault_type`: `String` - -### Results: - -The result will be a FundVault object in Json or 404 status code with error description. - ---- - -## (GET) fund_vaults - -Returns all Vaults belonging to the Fund sorted by vault_id - -### Parameters: - -`fund_name`: `String` - -### Results: - -The result will be an array of FundVault objects in Json or 404 status code with error description. - ---- - -## (GET) fund_stats - -Returns Fund's historical performance - -### Parameters: - -`fund_name`: `String` -`timeframe`: `String` -`start_time`: `i64` -`limit`: `u32` - -### Results: - -The result will be an array of FundStatsRecord objects in Json or 404 status code with error description. - ---- - -## (GET) user_stake_balance - -Returns User's stacked balance - -### Parameters: - -`wallet_address`: `Pubkey` -`farm_name`: `String` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (GET) vault_stake_balance - -Returns Vault's stacked balance - -### Parameters: - -`vault_name`: `String` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (GET) vault_admins - -Returns current admin signers for the Vault - -### Parameters: - -`name`: `String` - -### Results: - -The result will be a Multisig object in Json or 404 status code with error description. - ---- - -## (GET) vault_user_info - -Returns user stats for specific Vault - -### Parameters: - -`wallet_address`: `Pubkey` -`vault_name`: `String` - -### Results: - -The result will be a VaultUserInfo object in Json or 404 status code with error description. - ---- - -## (GET) vault_info - -Returns Vault stats - -### Parameters: - -`vault_name`: `String` - -### Results: - -The result will be a VaultInfo object in Json or 404 status code with error description. - ---- - -## (GET) vault_token_decimals - -Returns number of decimal digits of the Vault token - -### Parameters: - -`vault_name`: `String` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (GET) pool_tokens_decimals - -Returns number of decimal digits of the Vault token - -### Parameters: - -`pool_name`: `String` - -### Results: - -The result will be an array of u8 objects in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_create_system_account - -Returns a new Instruction for creating system account - -### Parameters: - -`wallet_address`: `Pubkey` -`new_address`: `Pubkey` -`lamports`: `u64` -`space`: `u64` -`owner`: `Pubkey` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_create_system_account_with_seed - -Returns a new Instruction for creating system account with seed - -### Parameters: - -`wallet_address`: `Pubkey` -`base_address`: `Pubkey` -`seed`: `String` -`lamports`: `u64` -`space`: `u64` -`owner`: `Pubkey` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_close_system_account - -Returns a new Instruction for closing system account - -### Parameters: - -`wallet_address`: `Pubkey` -`target_address`: `Pubkey` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_transfer - -Returns the native SOL transfer instruction - -### Parameters: - -`wallet_address`: `Pubkey` -`destination_wallet`: `Pubkey` -`sol_ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_token_transfer - -Returns a tokens transfer instruction - -### Parameters: - -`wallet_address`: `Pubkey` -`token_name`: `String` -`destination_wallet`: `Pubkey` -`ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_sync_token_balance - -Returns a new Instruction for syncing token balance for the specified account - -### Parameters: - -`wallet_address`: `Pubkey` -`token_name`: `String` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_create_token_account - -Returns a new Instruction for creating associated token account - -### Parameters: - -`wallet_address`: `Pubkey` -`token_name`: `String` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_close_token_account - -Returns a new Instruction for closing associated token account - -### Parameters: - -`wallet_address`: `Pubkey` -`token_name`: `String` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_user_init_vault - -Returns a new Instruction for initializing a new User for the Vault - -### Parameters: - -`wallet_address`: `Pubkey` -`vault_name`: `String` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_add_liquidity_vault - -Returns a new Instruction for adding liquidity to the Vault - -### Parameters: - -`wallet_address`: `Pubkey` -`vault_name`: `String` -`max_token_a_ui_amount`: `f64` -`max_token_b_ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_lock_liquidity_vault - -Returns a new Instruction for locking liquidity in the Vault - -### Parameters: - -`wallet_address`: `Pubkey` -`vault_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_unlock_liquidity_vault - -Returns a new Instruction for unlocking liquidity from the Vault - -### Parameters: - -`wallet_address`: `Pubkey` -`vault_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_remove_liquidity_vault - -Returns a new Instruction for removing liquidity from the Vault - -### Parameters: - -`wallet_address`: `Pubkey` -`vault_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_add_liquidity_pool - -Returns a new Instruction for adding liquidity to the Pool - -### Parameters: - -`wallet_address`: `Pubkey` -`pool_name`: `String` -`max_token_a_ui_amount`: `f64` -`max_token_b_ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_remove_liquidity_pool - -Returns a new Instruction for removing liquidity from the Pool - -### Parameters: - -`wallet_address`: `Pubkey` -`pool_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_wrap_token - -Returns a new Instruction for wrapping the token into protocol specific token - -### Parameters: - -`wallet_address`: `Pubkey` -`pool_name`: `String` -`token_to_wrap`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_unwrap_token - -Returns a new Instruction for unwrapping the token from protocol specific token - -### Parameters: - -`wallet_address`: `Pubkey` -`pool_name`: `String` -`token_to_unwrap`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_swap - -Returns a new Instruction for tokens swap - -### Parameters: - -`wallet_address`: `Pubkey` -`protocol`: `String` -`from_token`: `String` -`to_token`: `String` -`ui_amount_in`: `f64` -`min_ui_amount_out`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_user_init - -Returns a new Instruction for initializing a new User in the Farm - -### Parameters: - -`wallet_address`: `Pubkey` -`farm_name`: `String` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_stake - -Returns a new Instruction for tokens staking - -### Parameters: - -`wallet_address`: `Pubkey` -`farm_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_unstake - -Returns a new Instruction for tokens unstaking - -### Parameters: - -`wallet_address`: `Pubkey` -`farm_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_harvest - -Returns a new Instruction for rewards harvesting - -### Parameters: - -`wallet_address`: `Pubkey` -`farm_name`: `String` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_crank_vault - -Returns a new Vault Crank Instruction - -### Parameters: - -`wallet_address`: `Pubkey` -`vault_name`: `String` -`step`: `u64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_user_init_fund - -Returns a new Instruction for initializing a new User for the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`token_name`: `String` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_request_deposit_fund - -Returns a new Instruction for requesting deposit to the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`token_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_cancel_deposit_fund - -Returns a new Instruction for canceling pending deposit to the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`token_name`: `String` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_request_withdrawal_fund - -Returns a new Instruction for requesting withdrawal from the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`token_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_cancel_withdrawal_fund - -Returns a new Instruction for canceling pending withdrawal from the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`token_name`: `String` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_start_liquidation_fund - -Returns a new Instruction for initiating liquidation of the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_disable_deposits_fund - -Returns a new Instruction for disabling deposits to the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_approve_deposit_fund - -Returns a new Instruction for approving deposit to the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`user_address`: `Pubkey` -`fund_name`: `String` -`token_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_deny_deposit_fund - -Returns a new Instruction for denying deposit to the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`user_address`: `Pubkey` -`fund_name`: `String` -`token_name`: `String` -`deny_reason`: `String` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_disable_withdrawals_fund - -Returns a new Instruction for disabling withdrawals from the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_approve_withdrawal_fund - -Returns a new Instruction for approving withdrawal from the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`user_address`: `Pubkey` -`fund_name`: `String` -`token_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_deny_withdrawal_fund - -Returns a new Instruction for denying withdrawal from the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`user_address`: `Pubkey` -`fund_name`: `String` -`token_name`: `String` -`deny_reason`: `String` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_lock_assets_fund - -Returns a new Instruction for moving deposited assets to the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`token_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_unlock_assets_fund - -Returns a new Instruction for releasing assets from the Fund to Deposit/Withdraw custody - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`token_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_update_fund_assets_with_custody - -Returns a new Instruction for updating Fund assets based on custody holdings - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`custody_id`: `u32` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_update_fund_assets_with_vault - -Returns a new Instruction for updating Fund assets with Vault holdings - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`vault_id`: `u32` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_fund_add_liquidity_pool - -Returns a new Instruction for adding liquidity to the Pool in the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`pool_name`: `String` -`max_token_a_ui_amount`: `f64` -`max_token_b_ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_fund_remove_liquidity_pool - -Returns a new Instruction for removing liquidity from the Pool in the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`pool_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_fund_user_init_farm - -Returns a new Instruction for initializing a new User for the Farm in the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`farm_name`: `String` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_fund_stake - -Returns a new Instruction for tokens staking to the Farm in the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`farm_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_fund_unstake - -Returns a new Instruction for tokens unstaking from the Farm in the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`farm_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_fund_harvest - -Returns a new Instruction for rewards harvesting from the Farm in the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`farm_name`: `String` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_fund_user_init_vault - -Returns a new Instruction for initializing a new User for the Vault in the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`vault_name`: `String` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_fund_add_liquidity_vault - -Returns a new Instruction for adding liquidity to the Vault in the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`vault_name`: `String` -`max_token_a_ui_amount`: `f64` -`max_token_b_ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_fund_lock_liquidity_vault - -Returns a new Instruction for locking liquidity in the Vault in the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`vault_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_fund_unlock_liquidity_vault - -Returns a new Instruction for unlocking liquidity from the Vault in the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`vault_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) new_instruction_fund_remove_liquidity_vault - -Returns a new Instruction for removing liquidity from the Vault in the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`vault_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an Instruction object in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_token_transfer - -Returns a new complete set of instructions for tokens transfer - -### Parameters: - -`wallet_address`: `Pubkey` -`token_name`: `String` -`destination_wallet`: `Pubkey` -`ui_amount`: `f64` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_wrap_sol - -Returns a new complete set of instructions for SOL wrapping - -### Parameters: - -`wallet_address`: `Pubkey` -`ui_amount`: `f64` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_unwrap_sol - -Returns a new complete set of instructions for SOL unwrapping - -### Parameters: - -`wallet_address`: `Pubkey` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_add_liquidity_vault - -Returns a new complete set of instructions for adding liquidity to the Vault - -### Parameters: - -`wallet_address`: `Pubkey` -`vault_name`: `String` -`max_token_a_ui_amount`: `f64` -`max_token_b_ui_amount`: `f64` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_add_locked_liquidity_vault - -Returns a new complete set of instructions for adding locked liquidity to the Vault - -### Parameters: - -`wallet_address`: `Pubkey` -`vault_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_remove_liquidity_vault - -Returns a new complete set of Instructions for removing liquidity from the Vault - -### Parameters: - -`wallet_address`: `Pubkey` -`vault_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_remove_unlocked_liquidity_vault - -Returns a new complete set of Instructions for removing unlocked liquidity from the Vault - -### Parameters: - -`wallet_address`: `Pubkey` -`vault_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_add_liquidity_pool - -Returns a new complete set of Instructions for adding liquidity to the Pool - -### Parameters: - -`wallet_address`: `Pubkey` -`pool_name`: `String` -`max_token_a_ui_amount`: `f64` -`max_token_b_ui_amount`: `f64` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_remove_liquidity_pool - -Returns a new complete set of Instructions for removing liquidity from the Pool - -### Parameters: - -`wallet_address`: `Pubkey` -`pool_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_swap - -Returns a new complete set of Instructions for swapping tokens - -### Parameters: - -`wallet_address`: `Pubkey` -`protocol`: `String` -`from_token`: `String` -`to_token`: `String` -`ui_amount_in`: `f64` -`min_ui_amount_out`: `f64` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_stake - -Returns a new complete set of Instructions for staking tokens to the Farm - -### Parameters: - -`wallet_address`: `Pubkey` -`farm_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_unstake - -Returns a new complete set of Instructions for unstaking tokens from the Farm - -### Parameters: - -`wallet_address`: `Pubkey` -`farm_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_harvest - -Returns a new complete set of Instructions for harvesting rewards from the Farm - -### Parameters: - -`wallet_address`: `Pubkey` -`farm_name`: `String` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_request_deposit_fund - -Returns a new complete set of Instructions for requesting a new deposit to the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`token_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_request_withdrawal_fund - -Returns a new complete set of Instructions for requesting a new withdrawal from the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`token_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_fund_add_liquidity_pool - -Returns a new complete set of Instructions for adding liquidity to the Pool in the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`pool_name`: `String` -`max_token_a_ui_amount`: `f64` -`max_token_b_ui_amount`: `f64` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_fund_remove_liquidity_pool - -Returns a new complete set of Instructions for removing liquidity from the Pool in the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`pool_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_fund_stake - -Returns a new complete set of Instructions for staking tokens to the Farm in the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`farm_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_fund_unstake - -Returns a new complete set of Instructions for unstaking tokens from the Farm in the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`farm_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_fund_harvest - -Returns a new complete set of Instructions for harvesting rewards from the Farm in the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`farm_name`: `String` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_fund_add_liquidity_vault - -Returns a new complete set of instructions for adding liquidity to the Vault in the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`vault_name`: `String` -`max_token_a_ui_amount`: `f64` -`max_token_b_ui_amount`: `f64` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_fund_add_locked_liquidity_vault - -Returns a new complete set of instructions for adding locked liquidity to the Vault in the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`vault_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_fund_remove_liquidity_vault - -Returns a new complete set of Instructions for removing liquidity from the Vault in the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`vault_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (GET) all_instructions_fund_remove_unlocked_liquidity_vault - -Returns a new complete set of Instructions for removing unlocked liquidity from the Vault in the Fund - -### Parameters: - -`wallet_address`: `Pubkey` -`fund_name`: `String` -`vault_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be an array of Instruction objects in Json or 404 status code with error description. - ---- - -## (POST) create_system_account - -Creates a new system account - -### Parameters: - -`wallet_keypair`: `Keypair` -`new_account_keypair`: `Keypair` -`lamports`: `u64` -`space`: `u64` -`owner`: `Pubkey` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) create_system_account_with_seed - -Creates a new system account with seed - -### Parameters: - -`wallet_keypair`: `Keypair` -`base_address`: `Pubkey` -`seed`: `String` -`lamports`: `u64` -`space`: `u64` -`owner`: `Pubkey` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) assign_system_account - -Assigns system account to a program - -### Parameters: - -`wallet_keypair`: `Keypair` -`program_address`: `Pubkey` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) close_system_account - -Closes existing system account - -### Parameters: - -`wallet_keypair`: `Keypair` -`target_account_keypair`: `Keypair` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) transfer - -Transfers native SOL from the wallet to the destination - -### Parameters: - -`wallet_keypair`: `Keypair` -`destination_wallet`: `Pubkey` -`sol_ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) token_transfer - -Transfers tokens from the wallet to the destination - -### Parameters: - -`wallet_keypair`: `Keypair` -`token_name`: `String` -`destination_wallet`: `Pubkey` -`ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) wrap_sol - -Transfers native SOL from the wallet to the associated Wrapped SOL account - -### Parameters: - -`wallet_keypair`: `Keypair` -`ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) unwrap_sol - -Transfers Wrapped SOL back to SOL by closing the associated Wrapped SOL account - -### Parameters: - -`wallet_keypair`: `Keypair` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) sync_token_balance - -Updates token balance of the account, usefull after transfer SOL to WSOL account - -### Parameters: - -`wallet_keypair`: `Keypair` -`token_name`: `String` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) create_token_account - -Returns the associated token account for the given user's main account or creates one - -### Parameters: - -`wallet_keypair`: `Keypair` -`token_name`: `String` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) close_token_account - -Closes existing token account associated with the given user's main account - -### Parameters: - -`wallet_keypair`: `Keypair` -`token_name`: `String` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) user_init_vault - -Initializes a new User for the Vault - -### Parameters: - -`wallet_keypair`: `Keypair` -`vault_name`: `String` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) add_liquidity_vault - -Adds liquidity to the Vault - -### Parameters: - -`wallet_keypair`: `Keypair` -`vault_name`: `String` -`max_token_a_ui_amount`: `f64` -`max_token_b_ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) add_locked_liquidity_vault - -Adds locked liquidity to the Vault - -### Parameters: - -`wallet_keypair`: `Keypair` -`vault_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) remove_liquidity_vault - -Removes liquidity from the Vault - -### Parameters: - -`wallet_keypair`: `Keypair` -`vault_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) remove_unlocked_liquidity_vault - -Removes unlocked liquidity from the Vault - -### Parameters: - -`wallet_keypair`: `Keypair` -`vault_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) add_liquidity_pool - -Adds liquidity to the Pool - -### Parameters: - -`wallet_keypair`: `Keypair` -`pool_name`: `String` -`max_token_a_ui_amount`: `f64` -`max_token_b_ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) remove_liquidity_pool - -Removes liquidity from the Pool - -### Parameters: - -`wallet_keypair`: `Keypair` -`pool_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) swap - -Swaps tokens - -### Parameters: - -`wallet_keypair`: `Keypair` -`protocol`: `String` -`from_token`: `String` -`to_token`: `String` -`ui_amount_in`: `f64` -`min_ui_amount_out`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) user_init - -Initializes a new User for the Farm - -### Parameters: - -`wallet_keypair`: `Keypair` -`farm_name`: `String` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) stake - -Stakes tokens to the Farm - -### Parameters: - -`wallet_keypair`: `Keypair` -`farm_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) unstake - -Unstakes tokens from the Farm - -### Parameters: - -`wallet_keypair`: `Keypair` -`farm_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) harvest - -Harvests rewards from the Farm - -### Parameters: - -`wallet_keypair`: `Keypair` -`farm_name`: `String` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) crank_vault - -Cranks single Vault - -### Parameters: - -`wallet_keypair`: `Keypair` -`vault_name`: `String` -`step`: `u64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) crank_vaults - -Cranks all Vaults - -### Parameters: - -`wallet_keypair`: `Keypair` -`step`: `u64` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (POST) reset_cache - -Clears cache records to force re-pull from blockchain - -### Parameters: - -No parameters - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (POST) user_init_fund - -Initializes a new User for the Fund - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`token_name`: `String` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) request_deposit_fund - -Requests a new deposit to the Fund - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`token_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) cancel_deposit_fund - -Cancels pending deposit to the Fund - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`token_name`: `String` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) request_withdrawal_fund - -Requests a new withdrawal from the Fund - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`token_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) cancel_withdrawal_fund - -Cancels pending deposit to the Fund - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`token_name`: `String` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) start_liquidation_fund - -Starts the Fund liquidation - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) disable_deposits_fund - -Disables deposits to the Fund - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) approve_deposit_fund - -Approves pending deposit to the Fund - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`user_address`: `Pubkey` -`token_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) deny_deposit_fund - -Denies pending deposit to the Fund - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`user_address`: `Pubkey` -`token_name`: `String` -`deny_reason`: `String` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) disable_withdrawals_fund - -Disables withdrawals from the Fund - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) approve_withdrawal_fund - -Approves pending withdrawal from the Fund - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`user_address`: `Pubkey` -`token_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) deny_withdrawal_fund - -Denies pending withdrawal from the Fund - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`user_address`: `Pubkey` -`token_name`: `String` -`deny_reason`: `String` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) lock_assets_fund - -Moves deposited assets from Deposit/Withdraw custody to the Fund - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`token_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) unlock_assets_fund - -Releases assets from the Fund to Deposit/Withdraw custody - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`token_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) update_fund_assets_with_custody - -Update Fund assets info based on custody holdings - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`custody_id`: `u32` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) update_fund_assets_with_custodies - -Update Fund assets info based on all custodies - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (POST) update_fund_assets_with_vault - -Update Fund assets info based on Vault holdings - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`vault_id`: `u32` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) update_fund_assets_with_vaults - -Update Fund assets info based on Vault holdings - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` - -### Results: - -The result will be a String object or 404 status code with error description. - ---- - -## (POST) fund_add_liquidity_pool - -Adds liquidity to the Pool in the Fund - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`pool_name`: `String` -`max_token_a_ui_amount`: `f64` -`max_token_b_ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) fund_remove_liquidity_pool - -Removes liquidity from the Pool in the Fund - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`pool_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) fund_user_init_farm - -Initializes a new User for the Farm in the Fund - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`farm_name`: `String` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) fund_stake - -Stakes tokens to the Farm in the Fund - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`farm_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) fund_unstake - -Unstakes tokens from the Farm in the Fund - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`farm_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) fund_harvest - -Harvests rewards from the Farm in the Fund - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`farm_name`: `String` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) fund_user_init_vault - -Initializes a new User for the Vault in the Fund - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`vault_name`: `String` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) fund_add_liquidity_vault - -Adds liquidity to the Vault in the Fund - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`vault_name`: `String` -`max_token_a_ui_amount`: `f64` -`max_token_b_ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) fund_add_locked_liquidity_vault - -Adds locked liquidity to the Vault in the Fund - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`vault_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) fund_remove_liquidity_vault - -Removes liquidity from the Vault in the Fund - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`vault_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. - ---- - -## (POST) fund_remove_unlocked_liquidity_vault - -Removes unlocked liquidity from the Vault in the Fund - -### Parameters: - -`wallet_keypair`: `Keypair` -`fund_name`: `String` -`vault_name`: `String` -`ui_amount`: `f64` - -### Results: - -The result will be a Signature object or 404 status code with error description. diff --git a/farms/docs/intro.md b/farms/docs/intro.md deleted file mode 100755 index 25d7913a6b5..00000000000 --- a/farms/docs/intro.md +++ /dev/null @@ -1,57 +0,0 @@ -# Solana Farms - -## Introduction - -Solana Farms is a collection of easy-to-use tools and blockchain contracts for yield optimization strategies. - -It is powered by the Solana blockchain to allow for frequent automatic compounding, staking, and rebalancing. - -One of the distinct features of this platform is the on-chain Reference Database. Metadata for all objects: Tokens, Pools, Farms, Vaults, Funds, etc., is stored in the blockchain, so clients don't need any state or hard-coded data. - -Solana Farms provides a unified interface to Funds, Vaults, regular AMM Pools, Farms, and basic operations on tokens and accounts. Raydium, Saber, and Orca protocols are currently supported, but others are under development. - -This source code is an example that third parties can utilize to create and use their own version of a yield farming or aggregation service. - -## Quick start - -To quickly build, test and deploy Solana Farms and try it out in action, please follow the [Quick Start](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/quick_start.md) guide. - -## Dive in - -If you want to learn more about the tools and building blocks of the Solana Farms suite, follow the links below: - -[Rust Client](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/rust_client.md) - -[Http Client](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/http_client.md) - -[Farm Client CLI](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/farm_client_cli.md) - -[Farm Control CLI](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/farm_ctrl_cli.md) - -[Farm SDK](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/sdk.md) - -[Routers](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/routers.md) - -[Vaults](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/vaults.md) - -[Fund](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/fund.md) - -[Multisig](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/multisig.md) - -[Governance](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/governance.md) - -## Support - -For details on how to get help or report a problem, see the [Support](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/support.md) page. - -## Contributing - -Contributions are very welcome. Please refer to the [Contributing](https://github.com/solana-labs/solana/blob/master/CONTRIBUTING.md) guidelines for more information. - -## License - -Solana Farms is a part of the Solana Program Library, which is released under this [License](https://github.com/solana-labs/solana-program-library/blob/master/LICENSE). - -## Disclaimer - -By accessing or using Solana Farms or any of its components, you accept and agree with the [Disclaimer](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/disclaimer.md). diff --git a/farms/docs/multisig.md b/farms/docs/multisig.md deleted file mode 100755 index 14dd67743f1..00000000000 --- a/farms/docs/multisig.md +++ /dev/null @@ -1,26 +0,0 @@ -# Multisig - -Multi-signature mode is supported for all Main Router, Vault, and Fund transactions that require admin privileges, including program upgrades. To enable multisig for Main Router use: - -```sh -solana-farm-ctrl set-admins [MIN_SIGNATURES] [ADMIN_KEY1] [ADMIN_KEY2]... -``` - -The maximum number of admin signers is six. - -To enable multisig for program upgrades, Vaults, and Funds use `solana-farm-ctrl program-set-admins`, `solana-farm-ctrl vault-set-admins`, and `solana-farm-ctrl fund-set-admins`. Alternatively, you can use [Rust Client](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/rust_client.md) or build and send raw instructions. - -Multisig is fully transparent, no changes are required to how clients build or submit transactions. If a transaction requires multisig, API calls will return Ok (meaning intent was recorded on-chain) but won't be executed until enough signatures have been accumulated. - -If program upgrades multisig is enabled, then upgrades must be performed via Main Router using `solana-farm-ctrl program-upgrade`, e.g.: - -```sh -# write program to an on-chain buffer and get the buffer address -solana program write-buffer solana_router_raydium.so -solana program set-buffer-authority --new-buffer-authority [MULTISIG_ADDRESS] [BUFFER_ADDRESS] -solana-farm-ctrl program-upgrade [PROGRAM_ID] [BUFFER_ADDRESS] -``` - -Commands that initialize multisig can be used again to amend the existing set of admins (it will have to be signed by admins like other multisig transactions). To reset program upgrade multisig back to a single authority, use `solana-farm-ctrl program-set-single-authority`. - -To get the current list of admins you can use `get-admins`, `program-get-admins`, `vault-get-admins` and `fund-get-admins`. diff --git a/farms/docs/quick_start.md b/farms/docs/quick_start.md deleted file mode 100755 index 5e1372d232a..00000000000 --- a/farms/docs/quick_start.md +++ /dev/null @@ -1,207 +0,0 @@ -# Quick Start - -## Setup Environment - -1. Clone the repository from https://github.com/solana-labs/solana-program-library.git -2. Install the latest Solana tools from https://docs.solana.com/cli/install-solana-cli-tools. If you already have Solana tools, run `solana-install update` to get the latest compatible version. -3. Install the latest Rust stable from https://rustup.rs/. If you already have Rust, run `rustup update` to get the latest version. -4. Install the `libudev` development package for your distribution (`libudev-dev` on Debian-derived distros, `libudev-devel` on Redhat-derived). -5. Install the `libsqlite3` development package for your distribution (`libsqlite3-dev` on Debian-derived distros, `sqlite-devel` on Redhat-derived). -6. If you get an error about missing `libssl.so.1.1` file while building on-chain programs, install libssl1.1 package. It is missing in the standard repositories for the most recent versions of Ubuntu, so you might need to install it manually like this: - -``` -wget http://nz2.archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1l-1ubuntu1.5_amd64.deb -sudo dpkg -i ./libssl1.1_1.1.1l-1ubuntu1.5_amd64.deb -``` - -## Build - -Before starting the build, set `MAIN_ROUTER_ID` and `MAIN_ROUTER_ADMIN` environment variables. They should point to the existing Main Router program and admin account or generate a new set of keys if you plan to maintain your own version of the reference database: - -``` -solana-keygen new -o main_admin.json -solana-keygen new -o main_router.json -``` - -To build all of the off-chain libraries and programs, run the `cargo build` command from the `farms` directory: - -```sh -export MAIN_ROUTER_ID="replace this with main router id (solana main_router.json address)" -export MAIN_ROUTER_ADMIN="replace this with admin pubkey (solana main_admin.json address)" -cd solana-program-library/farms -cargo build --release -``` - -Binaries will be placed under `solana-program-library/farms/target/release` directory. If you plan on using `solana-farm-ctrl` or `solana-farm-client` tools per the examples below, you might want to add the release path to your environment's `PATH` variable: - -```sh -pushd target/release -export PATH=$PATH:$(pwd) -popd -``` - -Alternatively, you can execute instructions directly using [HTTP Client](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/http_client.md) or [Rust Client](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/rust_client.md). - -To build on-chain programs, use the standard `cargo build-bpf` command for Solana programs: - -```sh -for program in router-*; do - pushd $program &>/dev/null - cargo build-bpf - popd &>/dev/null -done -``` - -To build Vaults, specify an additional argument that tells the compiler which strategy needs to be built: - -```sh -pusdh vaults -cargo build-bpf --no-default-features --features SBR-STAKE-LP-COMPOUND -popd -``` - -Every time you re-build the vault program with another strategy, it overwrites the same file (target/deploy/solana_vaults.so), so you should build and deploy multiple strategies one by one and specify which address to deploy to, e.g.: - -```sh -pushd vaults &>/dev/null -for strategy in RDM SBR ORC; do - solana-keygen new -o vault_$strategy.json - cargo build-bpf --no-default-features --features $strategy-STAKE-LP-COMPOUND - solana program deploy --program-id vault_$strategy.json target/deploy/solana_vaults.so -done -popd &>/dev/null -``` - -## Test - -Tests are executed with the `cargo test` command: - -```sh -cargo test -``` - -Integration tests are located in `farm-client/tests` directory and can be started as follows: - -```sh -cargo test -- --nocapture --test-threads=1 --ignored -``` - -Remember that integration tests execute transactions on mainnet, which will cost you some SOL, and require on-chain programs and reference database to be deployed beforehand. - -## Deploy - -To deploy on-chain programs, use the standard `solana program deploy`: - -```sh -solana program deploy target/deploy/solana_router_raydium.so -solana program deploy target/deploy/solana_router_saber.so -solana program deploy target/deploy/solana_router_orca.so -``` - -If you generated your own set of keys for Main Router ID and Main Router admin, you need to deploy the Main Router program while specifying the corresponding upgrade authority and program id: - -```sh -solana program deploy --upgrade-authority main_admin.json --program-id main_router.json target/deploy/solana_router_main.so -``` - -## Upload Metadata - -This project uses an on-chain reference database to store the required metadata. If you plan to maintain your own copy of the database (i.e., generated a new pair of Main Router keys and deployed Main Router), you need to initialize the storage and upload metadata. Otherwise, skip this step. - -First, generate PDA addresses for the RefDB indexes: - -```sh -solana-farm-ctrl print-pda-all -``` - -Update `farm-ctrl/metadata/programs/programs.json` with newly generated addresses and addresses of your deployed programs (anything that has a blank address in that file needs to be updated or deleted if not needed). - -Initialize the storage (Note: it will cost you about 5 SOL): - -```sh -solana-farm-ctrl --keypair main_admin.json init-all -``` - -Metadata for external protocols, like Raydium, needs to be extracted from relative sources. For convenience, scripts for data download and data itself are available in the `farms/farm-ctrl/metadata` directory. -To upload metadata, run: - -```sh -solana-farm-ctrl -k main_admin.json load --skip-existing Token farm-ctrl/metadata/tokens/solana_token_list/filtered_tokens.json -solana-farm-ctrl -k main_admin.json load --skip-existing Token farm-ctrl/metadata/pools/raydium/pools.json -solana-farm-ctrl -k main_admin.json load --skip-existing Token farm-ctrl/metadata/pools/saber/pools.json -solana-farm-ctrl -k main_admin.json load --skip-existing Token farm-ctrl/metadata/pools/orca/pools.json -solana-farm-ctrl -k main_admin.json load --skip-existing Token farm-ctrl/metadata/farms/orca/farms.json -solana-farm-ctrl -k main_admin.json load --skip-existing Pool farm-ctrl/metadata/pools/raydium/pools.json -solana-farm-ctrl -k main_admin.json load --skip-existing Farm farm-ctrl/metadata/farms/raydium/farms.json -solana-farm-ctrl -k main_admin.json load --skip-existing Pool farm-ctrl/metadata/pools/saber/pools_and_farms.json -solana-farm-ctrl -k main_admin.json load --skip-existing Farm farm-ctrl/metadata/farms/saber/pools_and_farms.json -solana-farm-ctrl -k main_admin.json load --skip-existing Pool farm-ctrl/metadata/pools/orca/pools.json -solana-farm-ctrl -k main_admin.json load --skip-existing Farm farm-ctrl/metadata/farms/orca/farms.json -``` - -Metadata has interdependencies, so it needs to be uploaded sequentially as per the list above, don't run it in parallel even for the data of the same type. Metadata upload will cost you some SOL, depending on the number of records. You can get the price per record (Target) and max number of records (Target Max) by running this command: - -```sh -solana-farm-ctrl print-size-all -``` - -To generate metadata for all Raydium Vaults, run: - -```sh -./farm-ctrl/metadata/vaults/generate_vaults.py vaults_rdm.json tokens_rdm.json [VAULT_PROG_ID] RDM -``` - -And then upload it: - -```sh -solana-farm-ctrl --keypair main_admin.json load token tokens_rdm.json -solana-farm-ctrl --keypair main_admin.json load vault vaults_rdm.json -``` - -Similarly, metadata can be generated and uploaded for Orca and Saber Vaults. Also, it is possible to generate metadata only for a single Vault with: - -```sh -solana-farm-ctrl --keypair main_admin.json generate Vault [VAULT_PROGRAM_ADDRESS] [VAULT_NAME] [VAULT_TOKEN_NAME] -``` - -To verify metadata you can run `solana-farm-ctrl list-all vault` or `solana-farm-ctrl get-all vault`. - -## Run - -After metadata for Vaults and Vault tokens have been uploaded, Vaults need to be initialized with: - -```sh -solana-farm-ctrl vault-init all -solana-farm-ctrl vault-enable-deposits all -solana-farm-ctrl vault-enable-withdrawals all -``` - -And then, you can try one of the client commands to verify the installation: - -```sh -solana-farm-client deposit-vault [VAULT_NAME] [TOKEN_A_AMOUNT] 0 -solana-farm-client crank-vault [VAULT_NAME] 1 -solana-farm-client vault-info [VAULT_NAME] -solana-farm-client swap RDM SOL USDC 0.1 -``` - -For more information see [Vaults](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/vaults.md), for more usage examples see [Rust Client](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/rust_client.md) or [HTTP Client](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/http_client.md). - -To use HTTP RPC service, start it with: - -```sh -solana-farm-rpc --farm-client-url https://solana-api.projectserum.com --http-rpc-url http://0.0.0.0:9090 -``` - -Note that RPC service should be adequately scaled and put behind a load balancer and HTTPS proxy for production use. - -Open http://127.0.0.1:9090 in a browser to see available methods. You can also use [SwaggerHub](https://app.swaggerhub.com/apis-docs/ska22/SolanaFarms/0.1) to call any method interactively. Swagger schema is available in `solana-program-library/farms/farm-rpc/swagger.yaml`. - -## Further Steps - -Now, when everything is up and running, you may also consider: - -- Write [HTTP Client](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/http_client.md) or [Rust Client](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/rust_client.md) -- Initialize a decentralized [Fund](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/fund.md) -- Enable [Multisig](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/multisig.md) for admin operations -- Enable [Governance / DAO](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/governance.md) diff --git a/farms/docs/routers.md b/farms/docs/routers.md deleted file mode 100755 index 543b8ca7f77..00000000000 --- a/farms/docs/routers.md +++ /dev/null @@ -1,11 +0,0 @@ -# Main Router - -Main Router is an on-chain program that handles the creation, updates, and deletion of all metadata objects: tokens, pools, farms, vaults, program IDs, and generic key-value records, such as user or vault stats. - -Interaction with the Main Router can be done via [Farm Control CLI](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/farm_ctrl_cli.md), [Rust Client](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/rust_client.md), or calling instructions directly. The list of instructions can be found [here](https://github.com/solana-labs/solana-program-library/blob/master/farms/farm-sdk/src/instruction/main_router.rs). - -# Protocol Routers - -Protocol Routers are on-chain programs with a common interface for interaction with Raydium, Saber, and Orca Pools and Farms. They perform in and out amounts calculations and safety checks for tokens spent and received. They don't hold user funds but validate, wrap, and send instructions to the AMMs and Farms. - -Interaction with Protocol Routers can be done via [Farm Client CLI](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/farm_client_cli.md), [Rust Client](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/rust_client.md), [HTTP Client](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/http_client.md), or calling instructions directly. The list of instructions can be found [here](https://github.com/solana-labs/solana-program-library/blob/master/farms/farm-sdk/src/instruction/amm.rs). diff --git a/farms/docs/rust_client.md b/farms/docs/rust_client.md deleted file mode 100755 index 0e30bdc005e..00000000000 --- a/farms/docs/rust_client.md +++ /dev/null @@ -1,188 +0,0 @@ -# Rust Client - -Rust Client is a library that provides an easy way for off-chain Rust programs to interact with Routers, Pools, Funds, Vaults, and Funds, perform admin operations, metadata queries, and some common operations with wallets and accounts. - -Rust Client is a part of Farms suite, and to use it, existing deployment of Farm programs and metadata must be present per [Quick Start Guide](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/quick_start.md). - -The library needs to be specified as a dependency in your Cargo.toml: - -``` -[dependencies] -solana-farm-client = "1.1.2" -``` - -And declared in a program: - -```rust -use solana_farm_client::client::FarmClient; - -let client = FarmClient::new("https://api.mainnet-beta.solana.com"); -let keypair = FarmClient::read_keypair_from_file( - &(std::env::var("HOME").unwrap().to_string() + "/.config/solana/id.json"), -); -``` - -Client's methods accept human-readable names (tokens, polls, etc.) and UI (decimal) amounts, so you can simply call: - -```rust -client.swap(&keypair, "RDM", "SOL", "RAY", 0.1); -client.add_liquidity(&keypair, "RDM.RAY-SOL", 0.0, 0.1); -client.stake(&keypair, "RDM.RAY-SOL", 0.0); -client.harvest(&keypair, "RDM.RAY-SOL"); -``` - -to swap 0.1 SOL for RAY, deposit RAY and SOL to a Raydium pool, stake LP tokens, and harvest rewards. `RDM` above is a route or protocol. Use `SBR` for Saber pools and `ORC` for Orca. All metadata required to lookup account addresses, decimals, etc., is stored on-chain. - -Rust Client caches metadata to make subsequent calls faster, most noticeably queries that list a large number of objects, like `get_tokens()`. It also leverages RefDB to detect if any metadata objects have changed (e.g., any of the tokens) and reloads them if that is the case. - -Under the hood Client uses the official Solana RPC Client which can be accessed with -client.rpc_client, for example: `client.rpc_client.get_latest_blockhash()`. - -The naming convention for Pools and Farms is `[PROTOCOL].[TOKEN_A]-[TOKEN_B]-[VERSION]`. -Naming convention for Vaults is `[PROTOCOL].[STRATEGY].[TOKEN_A]-[TOKEN_B]-[VERSION]`. -There are single token pools where `[TOKEN_B]` is not present. -A list of supported protocols can be obtained with `get_protocols()`. -If `[VERSION]` is omitted, then Pool, Farm, or Vault with the latest version will be used. - -A few examples: - -```rust -// get SOL account balance -client.get_account_balance(&keypair.pubkey()); - -// get SPL token account balance -client.get_token_account_balance(&keypair.pubkey(), "SRM"); - -// get token metadata -client.get_token("SRM"); - -// find Raydium pools with RAY and SRM tokens -client.find_pools(Protocol::Raydium, "RAY", "SRM"); - -// find Saber pools with USDC and USDT tokens -client.find_pools(Protocol::Saber, "USDC", "USDT"); - -// get pool metadata -client.get_pool("RDM.RAY-SRM"); - -// get farm metadata -client.get_farm("RDM.RAY-SRM"); - -// find all vaults with RAY and SRM tokens -client.find_vaults("RAY", "SRM"); - -// get vault metadata -client.get_vault("RDM.STC.RAY-SRM"); - -// get fund metadata -client.get_fund("TestFund"); - -// get the list of all pools -client.get_pools(); - -// find farms for specific LP token -client.find_farms_with_lp("LP.RDM.RAY-SRM-V4"); - -// get Raydium pool price -client.get_pool_price("RDM.RAY-SRM"); -// or specify version for specific pool -client.get_pool_price("RDM.RAY-SRM-V4"); - -// get oracle price -client.get_oracle_price("SOL", 0, 0.0); - -// list official program IDs -client.get_program_ids(); - -// swap in the Raydium pool -client.swap(&keypair, Protocol::Raydium, "SOL", "RAY", 0.01, 0.0); - -// swap in the Saber pool -client.swap(&keypair, Protocol::Saber, "USDC", "USDT", 0.01, 0.0); - -// deposit liquidity to the Raydium pool (zero second token amount means calculate it automatically) -client.add_liquidity_pool(&keypair, "RDM.GRAPE-USDC", 0.1, 0.0); - -// withdraw your liquidity from the Raydium pool (zero amount means remove all tokens) -client.remove_liquidity_pool(&keypair, "RDM.GRAPE-USDC", 0.0); - -// stake LP tokens to the Raydium farm (zero amount means stake all) -client.stake(&keypair, "RDM.GRAPE-USDC", 0.0); - -// get staked balance -client.get_user_stake_balance(&keypair.pubkey(), "RDM.GRAPE-USDC"); - -// harvest rewards -client.harvest(&keypair, "RDM.GRAPE-USDC"); - -// unstake LP tokens from the farm (zero amount means unstake all) -client.unstake(&keypair, "RDM.GRAPE-USDC", 0.0); - -// deposit liquidity to the vault (zero second token amount means calculate it automatically) -client.add_liquidity_vault(&keypair, "RDM.STC.RAY-SRM", 0.01, 0.0); - -// withdraw liquidity from the vault (zero amount means remove all tokens) -client.remove_liquidity_vault(&keypair, "RDM.STC.RAY-SRM", 0.0); - -// request liquidity deposit to the fund -client.request_deposit_fund(&keypair, "TestFund", "USDC", 0.01); - -// request liquidity withdrawal from the fund (zero amount means withdraw everything) -client.request_withdrawal_fund(&keypair, "TestFund", "USDC", 0.0); - -// list all vaults that belong to particular fund -client.get_fund_vaults("TestFund"); - -// transfer SOL to another wallet -client.transfer(&keypair, &Pubkey::new_unique(), 0.001); - -// transfer SPL tokens to another wallet -client.token_transfer(&keypair, "SRM", &Pubkey::new_unique(), 0.001); - -// create associated token account for the wallet -client.get_or_create_token_account(&keypair, "SRM"); - -// list all active token accounts for the wallet -client.get_wallet_tokens(&keypair.pubkey()); - -// get vault stats -client.get_vault_info("RDM.STC.RAY-SRM"); - -// get user stats for particular vault -client.get_vault_user_info(&keypair.pubkey(), "RDM.STC.RAY-SRM"); - -// get fund stats and parameters -client.get_fund_info("TestFund"); - -// get fund custody info -client.get_fund_custody("TestFund", "USDC", FundCustodyType::DepositWithdraw); - -// get information about fund assets -client.get_fund_assets(&fund_name, FundAssetType::Vault); -client.get_fund_assets(&fund_name, FundAssetType::Custody); -``` - -The Client also allows for building raw unsigned instructions that can be integrated into more complex workflows: - -```rust -// create a new instruction for cranking a Vault, neither sign nor send it -let inst = client.new_instruction_crank_vault(&keypair.pubkey(), "RDM.STC.RAY-SRM"); -``` - -You can then sign and send it with: - -```rust -client.sign_and_send_instructions(&[keypair], &[inst]); -``` - -Some actions may require multiple instructions to be executed. To handle such cases, there are methods with names starting with `all_instructions_`, and they return a vector of instructions. For example: - -```rust -// create a single instruction for depositing liquidity to the vault assuming all prerequisites are met -client.new_instruction_add_liquidity_vault(&keypair.pubkey(), "RDM.STC.RAY-SRM", 0.1, 0.0); - -// create potentially multiple instructions that would handle new token accounts creation, user initialization, token wrap/unwrap, etc. -client.all_instructions_add_liquidity_vault(&keypair.pubkey(), "RDM.STC.RAY-SRM", 0.1, 0.0); -``` - -In addition to the library, there is also a command-line tool that sets an example for basic usage of the library: [Farm Client CLI](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/farm_client_cli.md). diff --git a/farms/docs/sdk.md b/farms/docs/sdk.md deleted file mode 100755 index e70adae4765..00000000000 --- a/farms/docs/sdk.md +++ /dev/null @@ -1,12 +0,0 @@ -# Farm SDK - -Farm SDK is a lower-level Rust library with a common code that is used by all Solana Farms tools and contracts. You might only need this SDK if you plan to build your own on-chain program or custom client that uses some of the SDK's functionality. Otherwise you should be using existing [HTTP Client](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/http_client.md) or [Rust Client](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/rust_client.md). - -To use the library, specify it in the `[dependencies]` section of your Cargo.toml, e.g.: - -``` -[dependencies] -solana-farm-sdk = "1.1.2" -``` - -The best way to learn what can be done with SDK is to look at the source code, which can be found [here](https://github.com/solana-labs/solana-program-library/tree/master/farms/farm-sdk/src). diff --git a/farms/docs/support.md b/farms/docs/support.md deleted file mode 100755 index 4fff87f22f0..00000000000 --- a/farms/docs/support.md +++ /dev/null @@ -1,7 +0,0 @@ -# Support - -If you are experiencing technical difficulties while writing code or interacting with the Solana blockchain, ask your questions on [Discord](https://discord.gg/RxeGBH), [Telegram](https://t.me/solana), or [StackOverflow](https://stackoverflow.com/questions/tagged/solana) (tag your question with `solana`). - -If you have Solana Farms specific questions or issues integrating Farms code, feel free to ask in the `developer-support` channel on [Discord](https://discord.gg/RxeGBH), but please mention that this is `solana farms` related. Or reach out to solana.farms@protonmail.com and provide your name, a link to the project website (if there is one), and a detailed description of the problem. - -If you found a bug in the code, you can raise an issue on [Github](https://github.com/solana-labs/solana-program-library). But if this is a security issue, please don't open it on Github or disclose it in public channels. Send information to the email above instead. diff --git a/farms/docs/vaults.md b/farms/docs/vaults.md deleted file mode 100755 index 38b4d4b6be7..00000000000 --- a/farms/docs/vaults.md +++ /dev/null @@ -1,31 +0,0 @@ -# Vaults - -Vaults are on-chain programs that implement various yield farming strategies. Under the hood, they interact with underlying Liquidity Pools and other Defi protocols to generate an extra yield for users that wouldn't be possible with passive investments. Individual yield farming strategies are stored under the `strategies` sub-folder. - -`RDM-STAKE-LP-COMPOUND` strategy works as follows: - -- User deposits tokens into a Vault with add_liquidity transaction. For example, Vault `RDM.STC.RAY-SRM` takes RAY and SRM tokens. To get a list of available Vaults, one can use the `client.get_vaults()` function or `api/v1/vaults` RPC call. Vault tokens are minted back to the user to represent their share in the Vault. -- Vault sends user tokens to the corresponding Raydium Pool, receives LP tokens, and stakes them to the Raydium Farm. -- Vaults should be cranked on a periodic basis. Crank operation is permissionless and can be done by anyone. And it is executed for the entire Vault, not per individual user. Crank consists of three steps: - 1. Harvest Farm rewards (in one or both tokens); - 2. Rebalance rewards to get proper amounts of each token; - 3. Place rewards back into the Pool and stake received LP tokens. A small Vault fee is taken from rewards, and it can be used to incentivize Crank operations. -- Upon liquidity removal, the user gets original tokens back in amounts proportional to Vault tokens they hold. Vault tokens are then burned. - -`SBR-STAKE-LP-COMPOUND` and `ORC-STAKE-LP-COMPOUND` are similar strategies but use Saber and Orca protocols. - -## Initialization - -In order to run Vaults, first, build and deploy Farm programs and upload metadata as described in the [Quick Start Guide](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/quick_start.md). - -To initialize and enable Vaults, run: - -```sh -solana-farm-ctrl vault-init all -solana-farm-ctrl vault-enable-deposits all -solana-farm-ctrl vault-enable-withdrawals all -``` - -You can set Vault fees and minimum allowed crank interval with `vault-set-fee` and `vault-set-min-crank-interval`. Cranks need to be executed periodically using `solana-farm-ctrl vault-crank all` or `solana-farm-client crank-vaults`. Alternatively you can use [HTTP Client](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/http_client.md) or [Rust Client](https://github.com/solana-labs/solana-program-library/blob/master/farms/docs/rust_client.md) or send raw instructions. - -Whether the Vault is properly initialized can be verified with client tools, e.g., `solana-farm-client vault-info [VAULT_NAME]`. diff --git a/farms/farm-client/.gitignore b/farms/farm-client/.gitignore deleted file mode 100644 index 96ef6c0b944..00000000000 --- a/farms/farm-client/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -Cargo.lock diff --git a/farms/farm-client/Cargo.toml b/farms/farm-client/Cargo.toml deleted file mode 100644 index a419d44ed73..00000000000 --- a/farms/farm-client/Cargo.toml +++ /dev/null @@ -1,48 +0,0 @@ -[package] -name = "solana-farm-client" -version = "1.1.3" -description = "Solana Farm Client" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana-program-library/farms" -license = "Apache-2.0" -homepage = "https://solana.com/" -edition = "2021" - -[features] -debug = [] - -[dependencies] -log = "0.4.16" -arrayvec = "0.7.2" -arrayref = "0.3.6" -serde = "1.0.136" -clap = "2.34.0" -thiserror = "1.0.30" -bs58 = "0.4.0" -solana-sdk = "1.9.18" -solana-client = "1.9.18" -solana-cli-config = "1.9.18" -solana-account-decoder = "1.9.18" -solana-logger = "1.9.18" -solana-version = "1.9.18" -solana-farm-sdk = "1.1.3" -solana-clap-utils = "1.9.18" -spl-token = { version = "3.2.0", features = ["no-entrypoint"] } -spl-associated-token-account = { version = "=1.0.3", features = ["no-entrypoint"] } -spl-governance = { version = "2.1.4", features = ["no-entrypoint"] } -quarry-mine = { version = "5.0.2", features = ["no-entrypoint"] } -stable-swap-client = "1.8.1" -stable-swap-math = "1.8.1" -chrono = "0.4.19" -base64 = "0.13.0" -bincode = "1.3.3" -num_enum = "0.5.7" -pyth-client = "=0.5.0" - -[lib] -name = "solana_farm_client" -path = "src/lib.rs" - -[[bin]] -name = "solana-farm-client" -path = "src/cli/main.rs" diff --git a/farms/farm-client/README.md b/farms/farm-client/README.md deleted file mode 120000 index ccd27901fd5..00000000000 --- a/farms/farm-client/README.md +++ /dev/null @@ -1 +0,0 @@ -../docs/crate.md \ No newline at end of file diff --git a/farms/farm-client/src/cache.rs b/farms/farm-client/src/cache.rs deleted file mode 100644 index df0d48b2644..00000000000 --- a/farms/farm-client/src/cache.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! Farm Client's cache to reduce the load on RPC endpoint. - -use std::{ - collections::HashMap, - time::{Duration, SystemTime}, -}; - -pub const RELOAD_INTERVAL: Duration = Duration::from_secs(21600); - -#[derive(Clone)] -pub struct Cache { - pub data: HashMap, - pub last_load: SystemTime, - pub counter: u32, -} - -impl Default for Cache { - fn default() -> Self { - Self { - data: HashMap::::new(), - last_load: SystemTime::now() - RELOAD_INTERVAL, - counter: 0, - } - } -} - -impl Cache { - pub fn is_stale(&self) -> bool { - if self.data.is_empty() { - return true; - } - if let Ok(diff) = SystemTime::now().duration_since(self.last_load) { - return diff >= RELOAD_INTERVAL; - } - false - } - - pub fn is_empty(&self) -> bool { - self.data.is_empty() - } - - pub fn is_updated(&self, counter: u32) -> bool { - counter != self.counter - } - - pub fn set(&mut self, data: HashMap, counter: u32) { - self.data = data; - self.last_load = SystemTime::now(); - self.counter = counter; - } - - pub fn reset(&mut self) { - self.data = HashMap::::new(); - self.last_load = SystemTime::now().checked_sub(RELOAD_INTERVAL).unwrap(); - self.counter = 0; - } - - pub fn mark_not_stale(&mut self) { - self.last_load = SystemTime::now(); - } -} diff --git a/farms/farm-client/src/cli/config.rs b/farms/farm-client/src/cli/config.rs deleted file mode 100644 index 215c88a0606..00000000000 --- a/farms/farm-client/src/cli/config.rs +++ /dev/null @@ -1,934 +0,0 @@ -//! Configuration and command line arguments management. - -use { - clap::{crate_description, crate_name, App, AppSettings, Arg, ArgMatches, SubCommand}, - solana_clap_utils::{input_validators::is_url, keypair::signer_from_path}, - solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey, signature::Signer}, - std::str::FromStr, -}; - -#[derive(Debug)] -pub struct Config { - pub farm_client_url: String, - pub commitment: CommitmentConfig, - pub keypair: Box, - pub no_pretty_print: bool, -} - -impl Config { - pub fn new(matches: &ArgMatches) -> Self { - let cli_config = if let Some(config_file) = matches.value_of("config_file") { - match solana_cli_config::Config::load(config_file) { - Err(e) => { - panic!("Failed to load config file \"{}\":{}", config_file, e); - } - Ok(config) => config, - } - } else { - solana_cli_config::Config::default() - }; - - let farm_client_url = matches - .value_of("farm_client_url") - .unwrap_or(&cli_config.json_rpc_url); - let keypair_path = matches - .value_of("keypair") - .unwrap_or(&cli_config.keypair_path); - let commitment = matches - .value_of("commitment") - .unwrap_or(&cli_config.commitment); - - Self { - farm_client_url: farm_client_url.to_string(), - commitment: CommitmentConfig::from_str(commitment).unwrap(), - keypair: signer_from_path(matches, keypair_path, "signer", &mut None).unwrap(), - no_pretty_print: matches.is_present("no_pretty_print"), - } - } -} - -pub fn get_target(matches: &ArgMatches) -> String { - matches - .value_of("target") - .unwrap() - .parse::() - .unwrap() - .to_lowercase() -} - -pub fn get_str_val<'a>(matches: &ArgMatches<'a>, argname: &str) -> String { - matches - .value_of(argname) - .unwrap() - .parse::() - .unwrap() - .to_uppercase() -} - -pub fn get_str_val_raw<'a>(matches: &ArgMatches<'a>, argname: &str) -> String { - matches - .value_of(argname) - .unwrap() - .parse::() - .unwrap() -} - -pub fn get_vec_str_val<'a>(matches: &ArgMatches<'a>, argname: &str) -> Vec { - matches - .value_of(argname) - .unwrap() - .parse::() - .unwrap() - .to_uppercase() - .split(',') - .collect::>() - .iter() - .map(|s| s.to_string()) - .collect() -} - -pub fn get_vec_str_val_raw<'a>(matches: &ArgMatches<'a>, argname: &str) -> Vec { - matches - .value_of(argname) - .unwrap() - .parse::() - .unwrap() - .split(',') - .collect::>() - .iter() - .map(|s| s.to_string()) - .collect() -} - -pub fn get_pubkey_val<'a>(matches: &ArgMatches<'a>, argname: &str) -> Pubkey { - Pubkey::from_str(matches.value_of(argname).unwrap()).unwrap() -} - -pub fn get_integer_val<'a>(matches: &ArgMatches<'a>, argname: &str) -> u64 { - matches.value_of(argname).unwrap().parse::().unwrap() -} - -pub fn get_floating_val<'a>(matches: &ArgMatches<'a>, argname: &str) -> f64 { - matches.value_of(argname).unwrap().parse::().unwrap() -} - -fn get_arg(name: &str) -> Arg { - Arg::with_name(name).required(true).takes_value(true) -} - -fn get_integer_arg(name: &str) -> Arg { - Arg::with_name(name) - .takes_value(true) - .required(true) - .validator(|p| match p.parse::() { - Err(_) => Err(String::from("Must be unsigned integer")), - Ok(_) => Ok(()), - }) -} - -fn get_floating_arg(name: &str) -> Arg { - Arg::with_name(name) - .takes_value(true) - .required(true) - .validator(|p| match p.parse::() { - Err(_) => Err(String::from("Must be floating number")), - Ok(_) => Ok(()), - }) -} - -pub fn get_clap_app<'a, 'b>(version: &'b str) -> App<'a, 'b> { - let target = Arg::with_name("target") - .required(true) - .takes_value(true) - .possible_values(&["program", "vault", "farm", "pool", "token", "fund"]) - .hide_possible_values(true) - .help("Target object type (program, vault, etc.)"); - - let objectname = Arg::with_name("object_name") - .required(true) - .takes_value(true) - .help("Target object name"); - - let tokenname = Arg::with_name("token_name") - .required(true) - .takes_value(true) - .help("Token name"); - - let tokenname2 = Arg::with_name("token_name2") - .required(true) - .takes_value(true) - .help("Second token name"); - - let amount = Arg::with_name("amount") - .takes_value(true) - .required(true) - .validator(|p| match p.parse::() { - Err(_) => Err(String::from("Must be unsigned decimal")), - Ok(val) => { - if val >= 0.0 { - Ok(()) - } else { - Err(String::from("Must be unsigned decimal")) - } - } - }) - .help("Token amount"); - - let amount2 = Arg::with_name("amount2") - .takes_value(true) - .required(false) - .default_value("0") - .validator(|p| match p.parse::() { - Err(_) => Err(String::from("Must be unsigned decimal")), - Ok(val) => { - if val >= 0.0 { - Ok(()) - } else { - Err(String::from("Must be unsigned decimal")) - } - } - }) - .help("Second token amount"); - - let wallet = Arg::with_name("wallet") - .takes_value(true) - .required(true) - .validator(|p| match Pubkey::from_str(&p) { - Err(_) => Err(String::from("Must be public key")), - Ok(_) => Ok(()), - }) - .help("Wallet address"); - - App::new(crate_name!()) - .about(crate_description!()) - .version(version) - .arg( - Arg::with_name("log_level") - .short("L") - .long("log-level") - .takes_value(true) - .default_value("info") - .global(true) - .help("Log verbosity level") - .possible_values(&[ - "debug", "info", "warning", "error" - ]) - .hide_possible_values(false) - ) - .arg({ - let arg = Arg::with_name("config_file") - .short("C") - .long("config") - .takes_value(true) - .global(true) - .help("Configuration file to use"); - if let Some(ref config_file) = *solana_cli_config::CONFIG_FILE { - arg.default_value(config_file) - } else { - arg - } - }) - .arg( - Arg::with_name("farm_client_url") - .short("f") - .long("farm-client-url") - .takes_value(true) - .global(true) - .validator(is_url) - .help("RPC URL to use with Farm Client"), - ) - .arg( - Arg::with_name("keypair") - .short("k") - .long("keypair") - .global(true) - .takes_value(true) - .help("Filepath or URL to a keypair"), - ) - .arg( - Arg::with_name("commitment") - .long("commitment") - .short("c") - .takes_value(true) - .possible_values(&[ - "processed", - "confirmed", - "finalized", - ]) - .hide_possible_values(false) - .global(true) - .help("Return information at the selected commitment level"), - ) - .arg( - Arg::with_name("no_pretty_print") - .short("n") - .long("no-pretty-print") - .global(true) - .takes_value(false) - .help("Print every record in one line"), - ) - .subcommand( - SubCommand::with_name("get") - .about("Query specified object in blockchain and print") - .arg(target.clone()) - .arg(objectname.clone()), - ) - .subcommand( - SubCommand::with_name("get-ref") - .about("Query specified object by reference address and print") - .arg(target.clone()) - .arg(objectname.clone()), - ) - .subcommand( - SubCommand::with_name("get-all") - .about("Query all objects of the given type and print") - .arg(target.clone()), - ) - .subcommand( - SubCommand::with_name("list-all") - .about("Query all object names of the given type and print") - .arg(target.clone()), - ) - .subcommand( - SubCommand::with_name("protocols") - .about("Print description and stats of all supported protocols") - ) - .subcommand( - SubCommand::with_name("pool-price") - .about("Print pool price") - .arg(get_arg("pool_name")), - ) - .subcommand( - SubCommand::with_name("oracle-price") - .about("Print oracle price") - .arg(get_arg("symbol")) - .arg(get_integer_arg("max_price_age_sec")) - .arg(get_floating_arg("max_price_error")), - ) - .subcommand( - SubCommand::with_name("transfer") - .about("Transfer SOL to another wallet") - .arg(wallet.clone()) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("token-transfer") - .about("Transfer tokens to another wallet") - .arg(tokenname.clone()) - .arg(wallet.clone()) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("wrap-sol") - .about("Transfer SOL to the associated WSOL account") - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("unwrap-sol") - .about("Transfer WSOL back to SOL by closing ATA") - ) - .subcommand( - SubCommand::with_name("sync-token-balance") - .about("Updates token balance of the account") - .arg(tokenname.clone()) - ) - .subcommand( - SubCommand::with_name("token-address") - .about("Print associated token account address") - .arg(tokenname.clone()), - ) - .subcommand( - SubCommand::with_name("token-data") - .about("Print token account metadata") - .arg(tokenname.clone()), - ) - .subcommand( - SubCommand::with_name("token-create") - .about("Create associated token account") - .arg(tokenname.clone()), - ) - .subcommand( - SubCommand::with_name("token-close") - .about("Close associated token account") - .arg(tokenname.clone()), - ) - .subcommand( - SubCommand::with_name("token-supply") - .about("Print token supply") - .arg(tokenname.clone()), - ) - .subcommand(SubCommand::with_name("balance").about("Print SOL balance")) - .subcommand( - SubCommand::with_name("token-balance") - .about("Print token balance") - .arg(tokenname.clone()), - ) - .subcommand( - SubCommand::with_name("stake-balance") - .about("Print user's stake balance in the farm") - .arg(get_arg("farm_name")), - ) - .subcommand( - SubCommand::with_name("wallet-balances") - .about("Print all token balances for the wallet") - ) - .subcommand( - SubCommand::with_name("vault-info") - .about("Print vault stats") - .arg(get_arg("vault_name")), - ) - .subcommand( - SubCommand::with_name("vault-user-info") - .about("Print user stats for the vault") - .arg(get_arg("vault_name")), - ) - .subcommand( - SubCommand::with_name("fund-info") - .about("Print fund stats") - .arg(get_arg("fund_name")), - ) - .subcommand( - SubCommand::with_name("fund-user-info") - .about("Print user stats for the fund") - .arg(get_arg("fund_name")) - ) - .subcommand( - SubCommand::with_name("fund-user-requests") - .about("Print user requests for the fund") - .arg(get_arg("fund_name")) - .arg(tokenname.clone()), - ) - .subcommand( - SubCommand::with_name("fund-assets") - .about("Print fund assets info") - .arg(get_arg("fund_name")) - .arg(get_arg("asset_type")) - ) - .subcommand( - SubCommand::with_name("fund-custody") - .about("Print fund custody info") - .arg(get_arg("fund_name")) - .arg(tokenname.clone()) - .arg(get_arg("custody_type")) - ) - .subcommand( - SubCommand::with_name("fund-custodies") - .about("Print all fund custodies") - .arg(get_arg("fund_name")) - ) - .subcommand( - SubCommand::with_name("fund-vault") - .about("Print fund vault info") - .arg(get_arg("fund_name")) - .arg(get_arg("vault_name")) - .arg(get_arg("vault_type")) - ) - .subcommand( - SubCommand::with_name("fund-vaults") - .about("Print all fund vaults") - .arg(get_arg("fund_name")) - ) - .subcommand( - SubCommand::with_name("find-funds") - .about("Find all Funds with Vault names matching given pattern") - .arg(get_arg("vault_name_pattern")) - ) - .subcommand( - SubCommand::with_name("find-pools") - .about("Find all Pools with tokens A and B") - .arg(get_arg("protocol")) - .arg(tokenname.clone()) - .arg(tokenname2.clone()) - ) - .subcommand( - SubCommand::with_name("find-pools-with-lp") - .about("Find all Pools for the given LP token") - .arg(tokenname.clone()) - ) - .subcommand( - SubCommand::with_name("find-farms-with-lp") - .about("Find all Farms for the given LP token") - .arg(tokenname.clone()) - ) - .subcommand( - SubCommand::with_name("find-vaults") - .about("Find all Vaults with tokens A and B") - .arg(tokenname.clone()) - .arg(tokenname2.clone()) - ) - .subcommand( - SubCommand::with_name("find-vaults-with-vt") - .about("Find all Vaults for the given VT token") - .arg(tokenname.clone()) - ) - .subcommand( - SubCommand::with_name("swap") - .about("Swap tokens in the pool") - .arg(get_arg("protocol")) - .arg(tokenname.clone()) - .arg(tokenname2.clone()) - .arg(amount.clone()) - .arg(amount2.clone()), - ) - .subcommand( - SubCommand::with_name("deposit-pool") - .about("Add liquidity to the pool") - .arg(get_arg("pool_name")) - .arg(amount.clone()) - .arg(amount2.clone()), - ) - .subcommand( - SubCommand::with_name("withdraw-pool") - .about("Remove liquidity from the pool") - .arg(get_arg("pool_name")) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("stake") - .about("Stake LP tokens to the farm") - .arg(get_arg("farm_name")) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("harvest") - .about("Harvest farm rewards") - .arg(get_arg("farm_name")), - ) - .subcommand( - SubCommand::with_name("unstake") - .about("Unstake LP tokens from the farm") - .arg(get_arg("farm_name")) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("deposit-vault") - .about("Add liquidity to the vault") - .arg(get_arg("vault_name")) - .arg(amount.clone()) - .arg(amount2.clone()), - ) - .subcommand( - SubCommand::with_name("deposit-vault-locked") - .about("Add locked liquidity to the vault") - .arg(get_arg("vault_name")) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("withdraw-vault") - .about("Remove liquidity from the vault") - .arg(get_arg("vault_name")) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("withdraw-vault-unlocked") - .about("Remove unlocked liquidity from the vault") - .arg(get_arg("vault_name")) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("crank-vault") - .about("Crank single vault") - .arg(get_arg("vault_name")) - .arg(get_integer_arg("step")) - ) - .subcommand( - SubCommand::with_name("crank-vaults") - .about("Crank all vaults") - .arg(get_integer_arg("step")) - ) - .subcommand( - SubCommand::with_name("request-deposit-fund") - .about("Request a new deposit to the fund") - .arg(get_arg("fund_name")) - .arg(tokenname.clone()) - .arg(amount.clone()) - ) - .subcommand( - SubCommand::with_name("cancel-deposit-fund") - .about("Cancel pending deposit to the Fund") - .arg(get_arg("fund_name")) - .arg(tokenname.clone()) - ) - .subcommand( - SubCommand::with_name("request-withdrawal-fund") - .about("Request a new withdrawal from the fund") - .arg(get_arg("fund_name")) - .arg(tokenname.clone()) - .arg(amount.clone()) - ) - .subcommand( - SubCommand::with_name("cancel-withdrawal-fund") - .about("Cancel pending withdrawal from the Fund") - .arg(get_arg("fund_name")) - .arg(tokenname.clone()) - ) - .subcommand( - SubCommand::with_name("start-liquidation-fund") - .about("Start the Fund liquidation") - .arg(get_arg("fund_name")) - ) - .subcommand( - SubCommand::with_name("update-fund-assets-with-custody") - .about("Update fund assets info based on custody holdings") - .arg(get_arg("fund_name")) - .arg(get_integer_arg("custody_id")) - ) - .subcommand( - SubCommand::with_name("update-fund-assets-with-custodies") - .about("Update fund assets info based on all custodies") - .arg(get_arg("fund_name")) - ) - .subcommand( - SubCommand::with_name("update-fund-assets-with-vault") - .about("Update fund assets info based on vault holdings") - .arg(get_arg("fund_name")) - .arg(get_integer_arg("vault_id")) - ) - .subcommand( - SubCommand::with_name("update-fund-assets-with-vaults") - .about("Update fund assets info based on all vaults") - .arg(get_arg("fund_name")) - ) - .subcommand( - SubCommand::with_name("governance") - .about("Governance commands. See `solana-farm-client governance help`") - .setting(AppSettings::SubcommandRequiredElseHelp) - .subcommand( - SubCommand::with_name("get-config") - .about("Get governance config") - .arg(get_arg("governance_name")) - ) - .subcommand( - SubCommand::with_name("get-address") - .about("Get governance account address") - .arg(get_arg("governance_name")) - ) - .subcommand( - SubCommand::with_name("get-instruction") - .about("Print stored instruction in the proposal") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - ) - .subcommand( - SubCommand::with_name("custody-new") - .about("Create new token custody account") - .arg(get_arg("token_name")) - ) - .subcommand( - SubCommand::with_name("tokens-deposit") - .about("Deposit governing tokens") - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("tokens-withdraw") - .about("Withdraw governing tokens") - ) - .subcommand( - SubCommand::with_name("proposal-new") - .about("Create a new proposal") - .arg(get_arg("governance_name")) - .arg(get_arg("proposal_name")) - .arg(get_arg("proposal_link")) - .arg(get_integer_arg("proposal_index")) - ) - .subcommand( - SubCommand::with_name("proposal-cancel") - .about("Cancel the proposal") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - ) - .subcommand( - SubCommand::with_name("proposal-state") - .about("Get proposal state") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - ) - .subcommand( - SubCommand::with_name("signatory-add") - .about("Add a signatory to the proposal") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_arg("signatory")) - ) - .subcommand( - SubCommand::with_name("signatory-remove") - .about("Remove the signatory from the proposal") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_arg("signatory")) - ) - .subcommand( - SubCommand::with_name("sign-off") - .about("Sign off the proposal") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - ) - .subcommand( - SubCommand::with_name("vote-cast") - .about("Cast a vote on the proposal") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("vote")) - ) - .subcommand( - SubCommand::with_name("vote-relinquish") - .about("Remove the vote from the proposal") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - ) - .subcommand( - SubCommand::with_name("vote-finalize") - .about("Finalize the vote on the proposal") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - ) - .subcommand( - SubCommand::with_name("instruction-execute") - .about("Execute the instruction in the proposal") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - ) - .subcommand( - SubCommand::with_name("instruction-flag-error") - .about("Mark the instruction as failed") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - ) - .subcommand( - SubCommand::with_name("instruction-remove") - .about("Remove the instruction from the proposal") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - ) - .subcommand( - SubCommand::with_name("instruction-insert") - .about("Add a new custom instruction to the proposal. Must be serialized with base64::encode(bincode::serialize(&inst).unwrap().as_slice())") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(get_arg("base64_instruction")) - ) - .subcommand( - SubCommand::with_name("instruction-verify") - .about("Verify custom instruction in the proposal. Must be serialized with base64::encode(bincode::serialize(&inst).unwrap().as_slice())") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(get_arg("base64_instruction")) - ) - .subcommand( - SubCommand::with_name("instruction-insert-token-transfer") - .about("Add a new token transfer instruction to the proposal") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(tokenname.clone()) - .arg(wallet.clone()) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("instruction-verify-token-transfer") - .about("Verify that instruction in the proposal is a token transfer") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(tokenname.clone()) - .arg(wallet.clone()) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("instruction-insert-swap") - .about("Add a new swap instruction to the proposal") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(get_arg("protocol")) - .arg(tokenname.clone()) - .arg(tokenname2.clone()) - .arg(amount.clone()) - .arg(amount2.clone()), - ) - .subcommand( - SubCommand::with_name("instruction-verify-swap") - .about("Verify that instruction in the proposal is a swap") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(get_arg("protocol")) - .arg(tokenname.clone()) - .arg(tokenname2.clone()) - .arg(amount.clone()) - .arg(amount2.clone()), - ) - .subcommand( - SubCommand::with_name("instruction-insert-deposit-pool") - .about("Add a new add liquidity to the pool instruction to the proposal") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(get_arg("pool_name")) - .arg(amount.clone()) - .arg(amount2.clone()), - ) - .subcommand( - SubCommand::with_name("instruction-verify-deposit-pool") - .about("Verify that instruction in the proposal is an add liquidity to the pool") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(get_arg("pool_name")) - .arg(amount.clone()) - .arg(amount2.clone()), - ) - .subcommand( - SubCommand::with_name("instruction-insert-withdraw-pool") - .about("Add a new remove liquidity from the pool instruction to the proposal") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(get_arg("pool_name")) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("instruction-verify-withdraw-pool") - .about("Verify that instruction in the proposal is a remove liquidity from the pool") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(get_arg("pool_name")) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("instruction-insert-stake") - .about("Add a new stake instruction to the proposal") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(get_arg("farm_name")) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("instruction-verify-stake") - .about("Verify that instruction in the proposal is a stake") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(get_arg("farm_name")) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("instruction-insert-harvest") - .about("Add a new harvest instruction to the proposal") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(get_arg("farm_name")), - ) - .subcommand( - SubCommand::with_name("instruction-verify-harvest") - .about("Verify that instruction in the proposal is a harvest") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(get_arg("farm_name")), - ) - .subcommand( - SubCommand::with_name("instruction-insert-unstake") - .about("Add a new unstake instruction to the proposal") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(get_arg("farm_name")) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("instruction-verify-unstake") - .about("Verify that instruction in the proposal is an unstake") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(get_arg("farm_name")) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("instruction-insert-deposit-vault") - .about("Add a new add liquidity to the vault instruction to the proposal") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(get_arg("vault_name")) - .arg(amount.clone()) - .arg(amount2.clone()), - ) - .subcommand( - SubCommand::with_name("instruction-verify-deposit-vault") - .about("Verify that instruction in the proposal is an add liquidity to the vault") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(get_arg("vault_name")) - .arg(amount.clone()) - .arg(amount2.clone()), - ) - .subcommand( - SubCommand::with_name("instruction-insert-withdraw-vault") - .about("Add a new remove liquidity from the vault instruction to the proposal") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(get_arg("vault_name")) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("instruction-verify-withdraw-vault") - .about("Verify that instruction in the proposal is a remove liquidity from the vault") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(get_arg("vault_name")) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("instruction-insert-withdraw-fees-vault") - .about("Add a new withdraw fees from the vault instruction to the proposal") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(get_arg("vault_name")) - .arg(get_integer_arg("fee_token")) - .arg(amount.clone()) - .arg(get_arg("receiver")) - ) - .subcommand( - SubCommand::with_name("instruction-verify-withdraw-fees-vault") - .about("Verify that instruction in the proposal is a withdraw fees from the vault") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(get_arg("vault_name")) - .arg(get_integer_arg("fee_token")) - .arg(amount.clone()) - .arg(get_arg("receiver")) - ) - .subcommand( - SubCommand::with_name("instruction-insert-program-upgrade") - .about("Add a new program upgrade instruction to the proposal") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(get_arg("buffer_address")) - ) - .subcommand( - SubCommand::with_name("instruction-verify-program-upgrade") - .about("Verify that instruction in the proposal is a program upgrade") - .arg(get_arg("governance_name")) - .arg(get_integer_arg("proposal_index")) - .arg(get_integer_arg("instruction_index")) - .arg(get_arg("buffer_address")) - ) - ) -} diff --git a/farms/farm-client/src/cli/main.rs b/farms/farm-client/src/cli/main.rs deleted file mode 100644 index 28cda5cdb05..00000000000 --- a/farms/farm-client/src/cli/main.rs +++ /dev/null @@ -1,1379 +0,0 @@ -//! Command-line interface for the Farm Client - -mod config; -mod printer; - -use { - clap::ArgMatches, - log::error, - num_enum::TryFromPrimitive, - solana_farm_client::client::FarmClient, - solana_farm_sdk::{fund::FundVaultType, id::DAO_CUSTODY_NAME, token::TokenSelector}, - solana_sdk::{bpf_loader_upgradeable, instruction::Instruction, pubkey::Pubkey}, - spl_associated_token_account::create_associated_token_account, - std::str::FromStr, -}; - -fn main() { - let matches = config::get_clap_app(solana_version::version!()).get_matches(); - - // set log verbosity level - let log_level = "solana=".to_string() + matches.value_of("log_level").unwrap(); - solana_logger::setup_with_default(log_level.as_str()); - - // load config params - let config = config::Config::new(&matches); - let client = FarmClient::new_with_commitment(&config.farm_client_url, config.commitment); - let wallet = config.keypair.pubkey(); - - // parse commands - match matches.subcommand() { - ("get", Some(subcommand_matches)) => { - let target = config::get_target(subcommand_matches); - let objects = config::get_vec_str_val_raw(subcommand_matches, "object_name"); - for object in objects { - printer::print(&client, &config, &target, &object.to_string()); - } - } - ("get-ref", Some(subcommand_matches)) => { - let target = config::get_target(subcommand_matches); - let objects = config::get_vec_str_val_raw(subcommand_matches, "object_name"); - for object in objects { - printer::print_with_ref(&client, &config, &target, &object.to_string()); - } - } - ("get-all", Some(subcommand_matches)) => { - let target = config::get_target(subcommand_matches); - printer::print_all(&client, &config, &target); - } - ("list-all", Some(subcommand_matches)) => { - let target = config::get_target(subcommand_matches); - printer::list_all(&client, &config, &target); - } - ("protocols", Some(_subcommand_matches)) => { - let protocols = client.get_protocols().unwrap(); - for protocol in protocols { - println!("{}", protocol); - } - } - ("pool-price", Some(subcommand_matches)) => { - let pools = config::get_vec_str_val(subcommand_matches, "pool_name"); - for pool in pools { - println!("{} price: {}", pool, client.get_pool_price(&pool).unwrap()); - } - } - ("oracle-price", Some(subcommand_matches)) => { - let symbol = config::get_str_val(subcommand_matches, "symbol"); - let max_price_age_sec = - config::get_integer_val(subcommand_matches, "max_price_age_sec"); - let max_price_error = config::get_floating_val(subcommand_matches, "max_price_error"); - println!( - "{} price: {}", - symbol, - client - .get_oracle_price(&symbol, max_price_age_sec, max_price_error) - .unwrap() - ); - } - ("transfer", Some(subcommand_matches)) => { - let destination = config::get_pubkey_val(subcommand_matches, "wallet"); - let amount = config::get_floating_val(subcommand_matches, "amount"); - println!( - "Done: {}", - client - .transfer(config.keypair.as_ref(), &destination, amount) - .unwrap() - ); - } - ("token-transfer", Some(subcommand_matches)) => { - let token_name = config::get_str_val(subcommand_matches, "token_name"); - let destination = config::get_pubkey_val(subcommand_matches, "wallet"); - let amount = config::get_floating_val(subcommand_matches, "amount"); - println!( - "Done: {}", - client - .token_transfer(config.keypair.as_ref(), &token_name, &destination, amount) - .unwrap() - ); - } - ("wrap-sol", Some(subcommand_matches)) => { - let amount = config::get_floating_val(subcommand_matches, "amount"); - println!( - "Done: {}", - client.wrap_sol(config.keypair.as_ref(), amount).unwrap() - ); - } - ("unwrap-sol", Some(_subcommand_matches)) => { - println!( - "Done: {}", - client.unwrap_sol(config.keypair.as_ref()).unwrap() - ); - } - ("sync-token-balance", Some(subcommand_matches)) => { - let token_name = config::get_str_val(subcommand_matches, "token_name"); - println!( - "Done: {}", - client - .sync_token_balance(config.keypair.as_ref(), &token_name) - .unwrap() - ); - } - ("token-address", Some(subcommand_matches)) => { - let tokens = config::get_vec_str_val(subcommand_matches, "token_name"); - for token in tokens { - println!( - "{} address: {}", - token, - client - .get_associated_token_address(&wallet, &token) - .unwrap() - ); - } - } - ("token-data", Some(subcommand_matches)) => { - let tokens = config::get_vec_str_val(subcommand_matches, "token_name"); - for token in tokens { - println!( - "{} data:\n{:#?}", - token, - client.get_token_account_data(&wallet, &token).unwrap() - ); - } - } - ("token-create", Some(subcommand_matches)) => { - let tokens = config::get_vec_str_val(subcommand_matches, "token_name"); - for token in tokens { - println!( - "{} created: {}", - token, - client - .get_or_create_token_account(config.keypair.as_ref(), &token) - .unwrap() - ); - } - } - ("token-close", Some(subcommand_matches)) => { - let tokens = config::get_vec_str_val(subcommand_matches, "token_name"); - for token in tokens { - println!( - "{} closed: {}", - token, - client - .close_token_account(config.keypair.as_ref(), &token) - .unwrap() - ); - } - } - ("token-supply", Some(subcommand_matches)) => { - let tokens = config::get_vec_str_val(subcommand_matches, "token_name"); - for token in tokens { - println!( - "{} supply: {}", - token, - client.get_token_supply(&token).unwrap() - ); - } - } - ("balance", Some(_)) => { - println!( - "SOL balance: {}", - client.get_account_balance(&wallet).unwrap() - ); - } - ("token-balance", Some(subcommand_matches)) => { - let tokens = config::get_vec_str_val(subcommand_matches, "token_name"); - for token in tokens { - if let Ok(balance) = client.get_token_account_balance(&wallet, &token) { - println!("{} balance: {}", token, balance); - } else { - println!("{} balance: no account", token); - } - } - } - ("stake-balance", Some(subcommand_matches)) => { - let farms = config::get_vec_str_val(subcommand_matches, "farm_name"); - for farm in farms { - if let Ok(balance) = client.get_user_stake_balance(&wallet, &farm) { - println!("{} balance: {}", farm, balance); - } else { - println!("{} balance: no account", farm); - } - } - } - ("wallet-balances", Some(_subcommand_matches)) => { - println!( - "SOL balance: {}", - client.get_account_balance(&wallet).unwrap() - ); - let tokens = client.get_wallet_tokens(&wallet).unwrap(); - for token in tokens { - if let Ok(balance) = client.get_token_account_balance(&wallet, &token) { - println!("{} balance: {}", token, balance); - } else { - println!("{} balance: no account", token); - } - } - } - ("vault-info", Some(subcommand_matches)) => { - let object = config::get_str_val(subcommand_matches, "vault_name"); - let vault = client.get_vault(&object).unwrap(); - let vault_info = client.get_vault_info(&object).unwrap(); - printer::print_object(&config, &vault.info_account, &vault_info); - } - ("vault-user-info", Some(subcommand_matches)) => { - let object = config::get_str_val(subcommand_matches, "vault_name"); - let account = client - .get_vault_user_info_account(&wallet, &object) - .unwrap(); - let user_info = client.get_vault_user_info(&wallet, &object).unwrap(); - printer::print_object(&config, &account, &user_info); - } - ("fund-info", Some(subcommand_matches)) => { - let object = config::get_str_val(subcommand_matches, "fund_name"); - let fund = client.get_fund(&object).unwrap(); - let fund_info = client.get_fund_info(&object).unwrap(); - printer::print_object(&config, &fund.info_account, &fund_info); - } - ("fund-user-info", Some(subcommand_matches)) => { - let object = config::get_str_val(subcommand_matches, "fund_name"); - let account = client.get_fund_user_info_account(&wallet, &object).unwrap(); - let user_info = client.get_fund_user_info(&wallet, &object).unwrap(); - printer::print_object(&config, &account, &user_info); - } - ("fund-user-requests", Some(subcommand_matches)) => { - let object = config::get_str_val(subcommand_matches, "fund_name"); - let token = config::get_str_val(subcommand_matches, "token_name"); - let account = client - .get_fund_user_requests_account(&wallet, &object, &token) - .unwrap(); - let user_requests = client - .get_fund_user_requests(&wallet, &object, &token) - .unwrap(); - printer::print_object(&config, &account, &user_requests); - } - ("fund-assets", Some(subcommand_matches)) => { - let object = config::get_str_val(subcommand_matches, "fund_name"); - let asset_type = config::get_str_val_raw(subcommand_matches, "asset_type") - .parse() - .unwrap(); - let account = client.get_fund_assets_account(&object, asset_type).unwrap(); - let fund_assets = client.get_fund_assets(&object, asset_type).unwrap(); - printer::print_object(&config, &account, &fund_assets); - } - ("fund-custody", Some(subcommand_matches)) => { - let object = config::get_str_val(subcommand_matches, "fund_name"); - let token = config::get_str_val(subcommand_matches, "token_name"); - let custody_type = config::get_str_val_raw(subcommand_matches, "custody_type") - .parse() - .unwrap(); - let account = client - .get_fund_custody_account(&object, &token, custody_type) - .unwrap(); - let fund_custody = client - .get_fund_custody_with_balance(&object, &token, custody_type) - .unwrap(); - printer::print_object(&config, &account, &fund_custody); - } - ("fund-custodies", Some(subcommand_matches)) => { - let object = config::get_str_val(subcommand_matches, "fund_name"); - let custodies = client.get_fund_custodies_with_balance(&object).unwrap(); - for custody in &custodies { - printer::print_object(&config, &custody.token_name, &custody); - } - } - ("fund-vault", Some(subcommand_matches)) => { - let object = config::get_str_val(subcommand_matches, "fund_name"); - let vault = config::get_str_val(subcommand_matches, "vault_name"); - let vault_type = config::get_str_val_raw(subcommand_matches, "vault_type") - .parse() - .unwrap(); - let account = client - .get_fund_vault_account(&object, &vault, vault_type) - .unwrap(); - let fund_vault = client.get_fund_vault(&object, &vault, vault_type).unwrap(); - printer::print_object(&config, &account, &fund_vault); - } - ("fund-vaults", Some(subcommand_matches)) => { - let object = config::get_str_val(subcommand_matches, "fund_name"); - let vaults = client.get_fund_vaults(&object).unwrap(); - for vault in &vaults { - let vault_name = match vault.vault_type { - FundVaultType::Vault => client.get_vault_by_ref(&vault.vault_ref).unwrap().name, - FundVaultType::Farm => client.get_farm_by_ref(&vault.vault_ref).unwrap().name, - FundVaultType::Pool => client.get_pool_by_ref(&vault.vault_ref).unwrap().name, - }; - printer::print_object(&config, &vault_name, &vault); - } - } - ("find-funds", Some(subcommand_matches)) => { - let vault_name_pattern = config::get_str_val(subcommand_matches, "vault_name_pattern"); - match client.find_funds(&vault_name_pattern) { - Ok(funds) => { - for fund in funds { - println!("{}", fund.name); - } - } - Err(e) => { - println!("{}", e); - } - } - } - ("find-pools", Some(subcommand_matches)) => { - let protocol = config::get_str_val(subcommand_matches, "protocol"); - let token1 = config::get_str_val(subcommand_matches, "token_name"); - let token2 = config::get_str_val(subcommand_matches, "token_name2"); - match client.find_pools( - protocol.parse().expect("Failed to parse protocol argument"), - &token1, - &token2, - ) { - Ok(pools) => { - for pool in pools { - println!("{}", pool.name); - } - } - Err(e) => { - println!("{}", e); - } - } - } - ("find-pools-with-lp", Some(subcommand_matches)) => { - let lp_token = config::get_str_val(subcommand_matches, "token_name"); - match client.find_pools_with_lp(&lp_token) { - Ok(pools) => { - for pool in pools { - println!("{}", pool.name); - } - } - Err(e) => { - println!("{}", e); - } - } - } - ("find-farms-with-lp", Some(subcommand_matches)) => { - let lp_token = config::get_str_val(subcommand_matches, "token_name"); - match client.find_farms_with_lp(&lp_token) { - Ok(farms) => { - for farm in farms { - println!("{}", farm.name); - } - } - Err(e) => { - println!("{}", e); - } - } - } - ("find-vaults", Some(subcommand_matches)) => { - let token1 = config::get_str_val(subcommand_matches, "token_name"); - let token2 = config::get_str_val(subcommand_matches, "token_name2"); - match client.find_vaults(&token1, &token2) { - Ok(vaults) => { - for vault in vaults { - println!("{}", vault.name); - } - } - Err(e) => { - println!("{}", e); - } - } - } - ("find-vaults-with-lp", Some(subcommand_matches)) => { - let vt_token = config::get_str_val(subcommand_matches, "token_name"); - match client.find_vaults_with_vt(&vt_token) { - Ok(vaults) => { - for vault in vaults { - println!("{}", vault.name); - } - } - Err(e) => { - println!("{}", e); - } - } - } - ("swap", Some(subcommand_matches)) => { - let protocol = config::get_str_val(subcommand_matches, "protocol"); - let token_from = config::get_str_val(subcommand_matches, "token_name"); - let token_to = config::get_str_val(subcommand_matches, "token_name2"); - let amount_in = config::get_floating_val(subcommand_matches, "amount"); - let min_amount_out = config::get_floating_val(subcommand_matches, "amount2"); - println!( - "Done: {}", - client - .swap( - config.keypair.as_ref(), - protocol.parse().expect("Failed to parse protocol argument"), - &token_from, - &token_to, - amount_in, - min_amount_out - ) - .unwrap() - ); - } - ("deposit-pool", Some(subcommand_matches)) => { - let pool_name = config::get_str_val(subcommand_matches, "pool_name"); - let token_a_amount = config::get_floating_val(subcommand_matches, "amount"); - let token_b_amount = config::get_floating_val(subcommand_matches, "amount2"); - println!( - "Done: {}", - client - .add_liquidity_pool( - config.keypair.as_ref(), - &pool_name, - token_a_amount, - token_b_amount - ) - .unwrap() - ); - } - ("withdraw-pool", Some(subcommand_matches)) => { - let pool_name = config::get_str_val(subcommand_matches, "pool_name"); - let amount = config::get_floating_val(subcommand_matches, "amount"); - println!( - "Done: {}", - client - .remove_liquidity_pool(config.keypair.as_ref(), &pool_name, amount) - .unwrap() - ); - } - ("stake", Some(subcommand_matches)) => { - let farm_name = config::get_str_val(subcommand_matches, "farm_name"); - let amount = config::get_floating_val(subcommand_matches, "amount"); - println!( - "Done: {}", - client - .stake(config.keypair.as_ref(), &farm_name, amount) - .unwrap() - ); - } - ("harvest", Some(subcommand_matches)) => { - let farm_name = config::get_str_val(subcommand_matches, "farm_name"); - println!( - "Done: {}", - client.harvest(config.keypair.as_ref(), &farm_name).unwrap() - ); - } - ("unstake", Some(subcommand_matches)) => { - let farm_name = config::get_str_val(subcommand_matches, "farm_name"); - let amount = config::get_floating_val(subcommand_matches, "amount"); - println!( - "Done: {}", - client - .unstake(config.keypair.as_ref(), &farm_name, amount) - .unwrap() - ); - } - ("deposit-vault", Some(subcommand_matches)) => { - let vault_name = config::get_str_val(subcommand_matches, "vault_name"); - let token_a_amount = config::get_floating_val(subcommand_matches, "amount"); - let token_b_amount = config::get_floating_val(subcommand_matches, "amount2"); - println!( - "Done: {}", - client - .add_liquidity_vault( - config.keypair.as_ref(), - &vault_name, - token_a_amount, - token_b_amount - ) - .unwrap() - ); - } - ("deposit-vault-locked", Some(subcommand_matches)) => { - let vault_name = config::get_str_val(subcommand_matches, "vault_name"); - let amount = config::get_floating_val(subcommand_matches, "amount"); - println!( - "Done: {}", - client - .add_locked_liquidity_vault(config.keypair.as_ref(), &vault_name, amount) - .unwrap() - ); - } - ("withdraw-vault", Some(subcommand_matches)) => { - let vault_name = config::get_str_val(subcommand_matches, "vault_name"); - let amount = config::get_floating_val(subcommand_matches, "amount"); - println!( - "Done: {}", - client - .remove_liquidity_vault(config.keypair.as_ref(), &vault_name, amount) - .unwrap() - ); - } - ("withdraw-vault-unlocked", Some(subcommand_matches)) => { - let vault_name = config::get_str_val(subcommand_matches, "vault_name"); - let amount = config::get_floating_val(subcommand_matches, "amount"); - println!( - "Done: {}", - client - .remove_unlocked_liquidity_vault(config.keypair.as_ref(), &vault_name, amount) - .unwrap() - ); - } - ("crank-vault", Some(subcommand_matches)) => { - let vault_name = config::get_str_val(subcommand_matches, "vault_name"); - let step = config::get_integer_val(subcommand_matches, "step"); - println!( - "Done: {}", - client - .crank_vault(config.keypair.as_ref(), &vault_name, step) - .unwrap() - ); - } - ("crank-vaults", Some(subcommand_matches)) => { - let step = config::get_integer_val(subcommand_matches, "step"); - println!( - "Done: {} vaults cranked", - client.crank_vaults(config.keypair.as_ref(), step).unwrap() - ); - } - ("request-deposit-fund", Some(subcommand_matches)) => { - let fund_name = config::get_str_val(subcommand_matches, "fund_name"); - let token = config::get_str_val(subcommand_matches, "token_name"); - let amount = config::get_floating_val(subcommand_matches, "amount"); - println!( - "Done: {}", - client - .request_deposit_fund(config.keypair.as_ref(), &fund_name, &token, amount) - .unwrap() - ); - } - ("cancel-deposit-fund", Some(subcommand_matches)) => { - let fund_name = config::get_str_val(subcommand_matches, "fund_name"); - let token = config::get_str_val(subcommand_matches, "token_name"); - println!( - "Done: {}", - client - .cancel_deposit_fund(config.keypair.as_ref(), &fund_name, &token) - .unwrap() - ); - } - ("request-withdrawal-fund", Some(subcommand_matches)) => { - let fund_name = config::get_str_val(subcommand_matches, "fund_name"); - let token = config::get_str_val(subcommand_matches, "token_name"); - let amount = config::get_floating_val(subcommand_matches, "amount"); - println!( - "Done: {}", - client - .request_withdrawal_fund(config.keypair.as_ref(), &fund_name, &token, amount) - .unwrap() - ); - } - ("cancel-withdrawal-fund", Some(subcommand_matches)) => { - let fund_name = config::get_str_val(subcommand_matches, "fund_name"); - let token = config::get_str_val(subcommand_matches, "token_name"); - println!( - "Done: {}", - client - .cancel_withdrawal_fund(config.keypair.as_ref(), &fund_name, &token) - .unwrap() - ); - } - ("start-liquidation-fund", Some(subcommand_matches)) => { - let fund_name = config::get_str_val(subcommand_matches, "fund_name"); - println!( - "Done: {}", - client - .start_liquidation_fund(config.keypair.as_ref(), &fund_name) - .unwrap() - ); - } - ("update-fund-assets-with-custody", Some(subcommand_matches)) => { - let fund_name = config::get_str_val(subcommand_matches, "fund_name"); - let custody_id = config::get_integer_val(subcommand_matches, "custody_id"); - println!( - "Done: {}", - client - .update_fund_assets_with_custody( - config.keypair.as_ref(), - &fund_name, - custody_id as u32 - ) - .unwrap() - ); - } - ("update-fund-assets-with-custodies", Some(subcommand_matches)) => { - let fund_name = config::get_str_val(subcommand_matches, "fund_name"); - println!( - "Done: {} custodies processed", - client - .update_fund_assets_with_custodies(config.keypair.as_ref(), &fund_name) - .unwrap() - ); - } - ("update-fund-assets-with-vault", Some(subcommand_matches)) => { - let fund_name = config::get_str_val(subcommand_matches, "fund_name"); - let vault_id = config::get_integer_val(subcommand_matches, "vault_id"); - println!( - "Done: {}", - client - .update_fund_assets_with_vault( - config.keypair.as_ref(), - &fund_name, - vault_id as u32 - ) - .unwrap() - ); - } - ("update-fund-assets-with-vaults", Some(subcommand_matches)) => { - let fund_name = config::get_str_val(subcommand_matches, "fund_name"); - println!( - "Done: {} vaults processed", - client - .update_fund_assets_with_vaults(config.keypair.as_ref(), &fund_name) - .unwrap() - ); - } - ("governance", Some(subcommand_matches)) => match subcommand_matches.subcommand() { - ("get-config", Some(subcommand_matches)) => { - let governance_name = - config::get_str_val_raw(subcommand_matches, "governance_name"); - let governance_config = client.governance_get_config(&governance_name).unwrap(); - println!("{:#?}", governance_config); - } - ("get-address", Some(subcommand_matches)) => { - let governance_name = - config::get_str_val_raw(subcommand_matches, "governance_name"); - let governance_address = client.governance_get_address(&governance_name).unwrap(); - println!("{}: {}", governance_name, governance_address); - } - ("get-instruction", Some(subcommand_matches)) => { - let (governance_name, proposal_index, instruction_index) = - get_instruction_args(subcommand_matches); - let stored_instruction = client - .governance_get_instruction(&governance_name, proposal_index, instruction_index) - .unwrap(); - println!("{:#?}", stored_instruction); - } - ("custody-new", Some(subcommand_matches)) => { - let token_name = config::get_str_val_raw(subcommand_matches, "token_name"); - let custody_authority = client.governance_get_address(DAO_CUSTODY_NAME).unwrap(); - - // create wsol account for custody authority - if !client.has_active_token_account(&custody_authority, &token_name) { - let token = client.get_token(&token_name).unwrap(); - let inst = - create_associated_token_account(&wallet, &custody_authority, &token.mint); - println!( - "Done: {}", - client - .sign_and_send_instructions(&[config.keypair.as_ref()], &[inst]) - .unwrap() - ); - } - println!( - "{} account: {}", - token_name, - client - .get_associated_token_address(&custody_authority, &token_name) - .unwrap() - ); - } - ("tokens-deposit", Some(subcommand_matches)) => { - let amount = config::get_floating_val(subcommand_matches, "amount"); - println!( - "Done: {}", - client - .governance_tokens_deposit(config.keypair.as_ref(), amount) - .unwrap() - ); - } - ("tokens-withdraw", Some(_subcommand_matches)) => { - println!( - "Done: {}", - client - .governance_tokens_withdraw(config.keypair.as_ref()) - .unwrap() - ); - } - ("proposal-new", Some(subcommand_matches)) => { - let governance_name = - config::get_str_val_raw(subcommand_matches, "governance_name"); - let proposal_name = config::get_str_val_raw(subcommand_matches, "proposal_name"); - let proposal_link = config::get_str_val_raw(subcommand_matches, "proposal_link"); - let proposal_index = config::get_integer_val(subcommand_matches, "proposal_index"); - println!( - "Done: {}", - client - .governance_proposal_new( - config.keypair.as_ref(), - &governance_name, - &proposal_name, - &proposal_link, - proposal_index as u32 - ) - .unwrap() - ); - } - ("proposal-cancel", Some(subcommand_matches)) => { - let governance_name = - config::get_str_val_raw(subcommand_matches, "governance_name"); - let proposal_index = config::get_integer_val(subcommand_matches, "proposal_index"); - println!( - "Done: {}", - client - .governance_proposal_cancel( - config.keypair.as_ref(), - &governance_name, - proposal_index as u32 - ) - .unwrap() - ); - } - ("proposal-state", Some(subcommand_matches)) => { - let governance_name = - config::get_str_val_raw(subcommand_matches, "governance_name"); - let proposal_index = config::get_integer_val(subcommand_matches, "proposal_index"); - let governance_state = client - .governance_get_proposal_state(&governance_name, proposal_index as u32) - .unwrap(); - println!("{:#?}", governance_state); - } - ("signatory-add", Some(subcommand_matches)) => { - let governance_name = - config::get_str_val_raw(subcommand_matches, "governance_name"); - let proposal_index = config::get_integer_val(subcommand_matches, "proposal_index"); - let signatory = - Pubkey::from_str(&config::get_str_val_raw(subcommand_matches, "signatory")) - .unwrap(); - println!( - "Done: {}", - client - .governance_signatory_add( - config.keypair.as_ref(), - &governance_name, - proposal_index as u32, - &signatory - ) - .unwrap() - ); - } - ("signatory-remove", Some(subcommand_matches)) => { - let governance_name = - config::get_str_val_raw(subcommand_matches, "governance_name"); - let proposal_index = config::get_integer_val(subcommand_matches, "proposal_index"); - let signatory = - Pubkey::from_str(&config::get_str_val_raw(subcommand_matches, "signatory")) - .unwrap(); - println!( - "Done: {}", - client - .governance_signatory_remove( - config.keypair.as_ref(), - &governance_name, - proposal_index as u32, - &signatory - ) - .unwrap() - ); - } - ("sign-off", Some(subcommand_matches)) => { - let governance_name = - config::get_str_val_raw(subcommand_matches, "governance_name"); - let proposal_index = config::get_integer_val(subcommand_matches, "proposal_index"); - println!( - "Done: {}", - client - .governance_sign_off( - config.keypair.as_ref(), - &governance_name, - proposal_index as u32 - ) - .unwrap() - ); - } - ("vote-cast", Some(subcommand_matches)) => { - let governance_name = - config::get_str_val_raw(subcommand_matches, "governance_name"); - let proposal_index = config::get_integer_val(subcommand_matches, "proposal_index"); - let vote = config::get_integer_val(subcommand_matches, "vote"); - println!( - "Done: {}", - client - .governance_vote_cast( - config.keypair.as_ref(), - &governance_name, - proposal_index as u32, - vote as u8 - ) - .unwrap() - ); - } - ("vote-relinquish", Some(subcommand_matches)) => { - let governance_name = - config::get_str_val_raw(subcommand_matches, "governance_name"); - let proposal_index = config::get_integer_val(subcommand_matches, "proposal_index"); - println!( - "Done: {}", - client - .governance_vote_relinquish( - config.keypair.as_ref(), - &governance_name, - proposal_index as u32 - ) - .unwrap() - ); - } - ("vote-finalize", Some(subcommand_matches)) => { - let governance_name = - config::get_str_val_raw(subcommand_matches, "governance_name"); - let proposal_index = config::get_integer_val(subcommand_matches, "proposal_index"); - println!( - "Done: {}", - client - .governance_vote_finalize( - config.keypair.as_ref(), - &governance_name, - proposal_index as u32 - ) - .unwrap() - ); - } - ("instruction-execute", Some(subcommand_matches)) => { - let (governance_name, proposal_index, instruction_index) = - get_instruction_args(subcommand_matches); - println!( - "Done: {}", - client - .governance_instruction_execute( - config.keypair.as_ref(), - &governance_name, - proposal_index, - instruction_index, - ) - .unwrap() - ); - } - ("instruction-flag-error", Some(subcommand_matches)) => { - let (governance_name, proposal_index, instruction_index) = - get_instruction_args(subcommand_matches); - println!( - "Done: {}", - client - .governance_instruction_flag_error( - config.keypair.as_ref(), - &governance_name, - proposal_index, - instruction_index, - ) - .unwrap() - ); - } - ("instruction-remove", Some(subcommand_matches)) => { - let (governance_name, proposal_index, instruction_index) = - get_instruction_args(subcommand_matches); - println!( - "Done: {}", - client - .governance_instruction_remove( - config.keypair.as_ref(), - &governance_name, - proposal_index, - instruction_index, - ) - .unwrap() - ); - } - ("instruction-insert", Some(subcommand_matches)) => { - let (governance_name, proposal_index, instruction_index) = - get_instruction_args(subcommand_matches); - let instruction_str = - config::get_str_val_raw(subcommand_matches, "base64_instruction"); - let data = base64::decode(&instruction_str).unwrap(); - let instruction: Instruction = bincode::deserialize(data.as_slice()).unwrap(); - println!( - "Done: {}", - client - .governance_instruction_insert( - config.keypair.as_ref(), - &governance_name, - proposal_index, - instruction_index, - &instruction - ) - .unwrap() - ); - } - ("instruction-verify", Some(subcommand_matches)) => { - let instruction_str = - config::get_str_val_raw(subcommand_matches, "base64_instruction"); - let data = base64::decode(&instruction_str).unwrap(); - let instruction: Instruction = bincode::deserialize(data.as_slice()).unwrap(); - - verify_instruction(&client, subcommand_matches, &instruction); - } - ("instruction-insert-token-transfer", Some(subcommand_matches)) => { - let (governance_name, proposal_index, instruction_index) = - get_instruction_args(subcommand_matches); - let token_name = config::get_str_val(subcommand_matches, "token_name"); - let destination = config::get_pubkey_val(subcommand_matches, "wallet"); - let amount = config::get_floating_val(subcommand_matches, "amount"); - let custody_authority = client.governance_get_address(DAO_CUSTODY_NAME).unwrap(); - let instruction = client - .new_instruction_token_transfer( - &custody_authority, - &token_name, - &destination, - amount, - ) - .unwrap(); - - println!( - "Done: {}", - client - .governance_instruction_insert( - config.keypair.as_ref(), - &governance_name, - proposal_index, - instruction_index, - &instruction - ) - .unwrap() - ); - } - ("instruction-verify-token-transfer", Some(subcommand_matches)) => { - let token_name = config::get_str_val(subcommand_matches, "token_name"); - let destination = config::get_pubkey_val(subcommand_matches, "wallet"); - let amount = config::get_floating_val(subcommand_matches, "amount"); - let custody_authority = client.governance_get_address(DAO_CUSTODY_NAME).unwrap(); - let instruction = client - .new_instruction_token_transfer( - &custody_authority, - &token_name, - &destination, - amount, - ) - .unwrap(); - - verify_instruction(&client, subcommand_matches, &instruction); - } - ("instruction-insert-swap", Some(subcommand_matches)) => { - let (governance_name, proposal_index, instruction_index) = - get_instruction_args(subcommand_matches); - let protocol = config::get_str_val(subcommand_matches, "protocol"); - let token_from = config::get_str_val(subcommand_matches, "token_name"); - let token_to = config::get_str_val(subcommand_matches, "token_name2"); - let amount_in = config::get_floating_val(subcommand_matches, "amount"); - let min_amount_out = config::get_floating_val(subcommand_matches, "amount2"); - let custody_authority = client.governance_get_address(DAO_CUSTODY_NAME).unwrap(); - let instruction = client - .new_instruction_swap( - &custody_authority, - protocol.parse().expect("Failed to parse protocol argument"), - &token_from, - &token_to, - amount_in, - min_amount_out, - ) - .unwrap(); - - println!( - "Done: {}", - client - .governance_instruction_insert( - config.keypair.as_ref(), - &governance_name, - proposal_index, - instruction_index, - &instruction - ) - .unwrap() - ); - } - ("instruction-verify-swap", Some(subcommand_matches)) => { - let protocol = config::get_str_val(subcommand_matches, "protocol"); - let token_from = config::get_str_val(subcommand_matches, "token_name"); - let token_to = config::get_str_val(subcommand_matches, "token_name2"); - let amount_in = config::get_floating_val(subcommand_matches, "amount"); - let min_amount_out = config::get_floating_val(subcommand_matches, "amount2"); - let custody_authority = client.governance_get_address(DAO_CUSTODY_NAME).unwrap(); - let instruction = client - .new_instruction_swap( - &custody_authority, - protocol.parse().expect("Failed to parse protocol argument"), - &token_from, - &token_to, - amount_in, - min_amount_out, - ) - .unwrap(); - - verify_instruction(&client, subcommand_matches, &instruction); - } - ("instruction-insert-deposit-pool", Some(subcommand_matches)) => { - let (governance_name, proposal_index, instruction_index) = - get_instruction_args(subcommand_matches); - let pool_name = config::get_str_val(subcommand_matches, "pool_name"); - let token_a_amount = config::get_floating_val(subcommand_matches, "amount"); - let token_b_amount = config::get_floating_val(subcommand_matches, "amount2"); - let custody_authority = client.governance_get_address(DAO_CUSTODY_NAME).unwrap(); - let instruction = client - .new_instruction_add_liquidity_pool( - &custody_authority, - &pool_name, - token_a_amount, - token_b_amount, - ) - .unwrap(); - - println!( - "Done: {}", - client - .governance_instruction_insert( - config.keypair.as_ref(), - &governance_name, - proposal_index, - instruction_index, - &instruction - ) - .unwrap() - ); - } - ("instruction-verify-deposit-pool", Some(subcommand_matches)) => { - let pool_name = config::get_str_val(subcommand_matches, "pool_name"); - let token_a_amount = config::get_floating_val(subcommand_matches, "amount"); - let token_b_amount = config::get_floating_val(subcommand_matches, "amount2"); - let custody_authority = client.governance_get_address(DAO_CUSTODY_NAME).unwrap(); - let instruction = client - .new_instruction_add_liquidity_pool( - &custody_authority, - &pool_name, - token_a_amount, - token_b_amount, - ) - .unwrap(); - - verify_instruction(&client, subcommand_matches, &instruction); - } - ("instruction-insert-withdraw-pool", Some(subcommand_matches)) => { - let (governance_name, proposal_index, instruction_index) = - get_instruction_args(subcommand_matches); - let pool_name = config::get_str_val(subcommand_matches, "pool_name"); - let amount = config::get_floating_val(subcommand_matches, "amount"); - let custody_authority = client.governance_get_address(DAO_CUSTODY_NAME).unwrap(); - let instruction = client - .new_instruction_remove_liquidity_pool(&custody_authority, &pool_name, amount) - .unwrap(); - - println!( - "Done: {}", - client - .governance_instruction_insert( - config.keypair.as_ref(), - &governance_name, - proposal_index, - instruction_index, - &instruction - ) - .unwrap() - ); - } - ("instruction-verify-withdraw-pool", Some(subcommand_matches)) => { - let pool_name = config::get_str_val(subcommand_matches, "pool_name"); - let amount = config::get_floating_val(subcommand_matches, "amount"); - let custody_authority = client.governance_get_address(DAO_CUSTODY_NAME).unwrap(); - let instruction = client - .new_instruction_remove_liquidity_pool(&custody_authority, &pool_name, amount) - .unwrap(); - - verify_instruction(&client, subcommand_matches, &instruction); - } - ("instruction-insert-stake", Some(subcommand_matches)) => { - let (governance_name, proposal_index, instruction_index) = - get_instruction_args(subcommand_matches); - let farm_name = config::get_str_val(subcommand_matches, "farm_name"); - let amount = config::get_floating_val(subcommand_matches, "amount"); - let custody_authority = client.governance_get_address(DAO_CUSTODY_NAME).unwrap(); - let instruction = client - .new_instruction_stake(&custody_authority, &farm_name, amount) - .unwrap(); - - println!( - "Done: {}", - client - .governance_instruction_insert( - config.keypair.as_ref(), - &governance_name, - proposal_index, - instruction_index, - &instruction - ) - .unwrap() - ); - } - ("instruction-verify-stake", Some(subcommand_matches)) => { - let farm_name = config::get_str_val(subcommand_matches, "farm_name"); - let amount = config::get_floating_val(subcommand_matches, "amount"); - let custody_authority = client.governance_get_address(DAO_CUSTODY_NAME).unwrap(); - let instruction = client - .new_instruction_stake(&custody_authority, &farm_name, amount) - .unwrap(); - - verify_instruction(&client, subcommand_matches, &instruction); - } - ("instruction-insert-harvest", Some(subcommand_matches)) => { - let (governance_name, proposal_index, instruction_index) = - get_instruction_args(subcommand_matches); - let farm_name = config::get_str_val(subcommand_matches, "farm_name"); - let custody_authority = client.governance_get_address(DAO_CUSTODY_NAME).unwrap(); - let instruction = client - .new_instruction_harvest(&custody_authority, &farm_name) - .unwrap(); - - println!( - "Done: {}", - client - .governance_instruction_insert( - config.keypair.as_ref(), - &governance_name, - proposal_index, - instruction_index, - &instruction - ) - .unwrap() - ); - } - ("instruction-verify-harvest", Some(subcommand_matches)) => { - let farm_name = config::get_str_val(subcommand_matches, "farm_name"); - let custody_authority = client.governance_get_address(DAO_CUSTODY_NAME).unwrap(); - let instruction = client - .new_instruction_harvest(&custody_authority, &farm_name) - .unwrap(); - - verify_instruction(&client, subcommand_matches, &instruction); - } - ("instruction-insert-unstake", Some(subcommand_matches)) => { - let (governance_name, proposal_index, instruction_index) = - get_instruction_args(subcommand_matches); - let farm_name = config::get_str_val(subcommand_matches, "farm_name"); - let amount = config::get_floating_val(subcommand_matches, "amount"); - let custody_authority = client.governance_get_address(DAO_CUSTODY_NAME).unwrap(); - let instruction = client - .new_instruction_unstake(&custody_authority, &farm_name, amount) - .unwrap(); - - println!( - "Done: {}", - client - .governance_instruction_insert( - config.keypair.as_ref(), - &governance_name, - proposal_index, - instruction_index, - &instruction - ) - .unwrap() - ); - } - ("instruction-verify-unstake", Some(subcommand_matches)) => { - let farm_name = config::get_str_val(subcommand_matches, "farm_name"); - let amount = config::get_floating_val(subcommand_matches, "amount"); - let custody_authority = client.governance_get_address(DAO_CUSTODY_NAME).unwrap(); - let instruction = client - .new_instruction_unstake(&custody_authority, &farm_name, amount) - .unwrap(); - - verify_instruction(&client, subcommand_matches, &instruction); - } - ("instruction-insert-deposit-vault", Some(subcommand_matches)) => { - let (governance_name, proposal_index, instruction_index) = - get_instruction_args(subcommand_matches); - let vault_name = config::get_str_val(subcommand_matches, "vault_name"); - let token_a_amount = config::get_floating_val(subcommand_matches, "amount"); - let token_b_amount = config::get_floating_val(subcommand_matches, "amount2"); - let custody_authority = client.governance_get_address(DAO_CUSTODY_NAME).unwrap(); - let instruction = client - .new_instruction_add_liquidity_vault( - &custody_authority, - &vault_name, - token_a_amount, - token_b_amount, - ) - .unwrap(); - - println!( - "Done: {}", - client - .governance_instruction_insert( - config.keypair.as_ref(), - &governance_name, - proposal_index, - instruction_index, - &instruction - ) - .unwrap() - ); - } - ("instruction-verify-deposit-vault", Some(subcommand_matches)) => { - let vault_name = config::get_str_val(subcommand_matches, "vault_name"); - let token_a_amount = config::get_floating_val(subcommand_matches, "amount"); - let token_b_amount = config::get_floating_val(subcommand_matches, "amount2"); - let custody_authority = client.governance_get_address(DAO_CUSTODY_NAME).unwrap(); - let instruction = client - .new_instruction_add_liquidity_vault( - &custody_authority, - &vault_name, - token_a_amount, - token_b_amount, - ) - .unwrap(); - - verify_instruction(&client, subcommand_matches, &instruction); - } - ("instruction-insert-withdraw-vault", Some(subcommand_matches)) => { - let (governance_name, proposal_index, instruction_index) = - get_instruction_args(subcommand_matches); - let vault_name = config::get_str_val(subcommand_matches, "vault_name"); - let amount = config::get_floating_val(subcommand_matches, "amount"); - let custody_authority = client.governance_get_address(DAO_CUSTODY_NAME).unwrap(); - let instruction = client - .new_instruction_remove_liquidity_vault(&custody_authority, &vault_name, amount) - .unwrap(); - - println!( - "Done: {}", - client - .governance_instruction_insert( - config.keypair.as_ref(), - &governance_name, - proposal_index, - instruction_index, - &instruction - ) - .unwrap() - ); - } - ("instruction-verify-withdraw-vault", Some(subcommand_matches)) => { - let vault_name = config::get_str_val(subcommand_matches, "vault_name"); - let amount = config::get_floating_val(subcommand_matches, "amount"); - let custody_authority = client.governance_get_address(DAO_CUSTODY_NAME).unwrap(); - let instruction = client - .new_instruction_remove_liquidity_vault(&custody_authority, &vault_name, amount) - .unwrap(); - - verify_instruction(&client, subcommand_matches, &instruction); - } - ("instruction-insert-withdraw-fees-vault", Some(subcommand_matches)) => { - let (governance_name, proposal_index, instruction_index) = - get_instruction_args(subcommand_matches); - let vault_name = config::get_str_val(subcommand_matches, "vault_name"); - let fee_token = TokenSelector::try_from_primitive(config::get_integer_val( - subcommand_matches, - "fee_token", - ) as u8) - .unwrap(); - let amount = config::get_floating_val(subcommand_matches, "amount"); - let receiver = config::get_pubkey_val(subcommand_matches, "receiver"); - let custody_authority = client.governance_get_address(DAO_CUSTODY_NAME).unwrap(); - let instruction = client - .new_instruction_withdraw_fees_vault( - &custody_authority, - &vault_name, - fee_token, - amount, - &receiver, - ) - .unwrap(); - - println!( - "Done: {}", - client - .governance_instruction_insert( - config.keypair.as_ref(), - &governance_name, - proposal_index, - instruction_index, - &instruction - ) - .unwrap() - ); - } - ("instruction-verify-withdraw-fees-vault", Some(subcommand_matches)) => { - let vault_name = config::get_str_val(subcommand_matches, "vault_name"); - let fee_token = TokenSelector::try_from_primitive(config::get_integer_val( - subcommand_matches, - "fee_token", - ) as u8) - .unwrap(); - let amount = config::get_floating_val(subcommand_matches, "amount"); - let receiver = config::get_pubkey_val(subcommand_matches, "receiver"); - let custody_authority = client.governance_get_address(DAO_CUSTODY_NAME).unwrap(); - let instruction = client - .new_instruction_withdraw_fees_vault( - &custody_authority, - &vault_name, - fee_token, - amount, - &receiver, - ) - .unwrap(); - - verify_instruction(&client, subcommand_matches, &instruction); - } - ("instruction-insert-program-upgrade", Some(subcommand_matches)) => { - let (governance_name, proposal_index, instruction_index) = - get_instruction_args(subcommand_matches); - let program_address = client.get_program_id(&governance_name).unwrap(); - let buffer_address = config::get_pubkey_val(subcommand_matches, "buffer_address"); - let program_authority = client.governance_get_address(&governance_name).unwrap(); - let instruction = bpf_loader_upgradeable::upgrade( - &program_address, - &buffer_address, - &program_authority, - &config.keypair.pubkey(), - ); - - println!( - "Done: {}", - client - .governance_instruction_insert( - config.keypair.as_ref(), - &governance_name, - proposal_index, - instruction_index, - &instruction - ) - .unwrap() - ); - } - ("instruction-verify-program-upgrade", Some(subcommand_matches)) => { - let (governance_name, _proposal_index, _instruction_index) = - get_instruction_args(subcommand_matches); - let program_address = client.get_program_id(&governance_name).unwrap(); - let buffer_address = config::get_pubkey_val(subcommand_matches, "buffer_address"); - let program_authority = client.governance_get_address(&governance_name).unwrap(); - let instruction = bpf_loader_upgradeable::upgrade( - &program_address, - &buffer_address, - &program_authority, - &config.keypair.pubkey(), - ); - - verify_instruction(&client, subcommand_matches, &instruction); - } - _ => unreachable!(), - }, - _ => error!("Unrecognized command. Use --help to list known commands."), - }; -} - -fn get_instruction_args(matches: &ArgMatches) -> (String, u32, u16) { - let governance_name = config::get_str_val_raw(matches, "governance_name"); - let proposal_index = config::get_integer_val(matches, "proposal_index") as u32; - let instruction_index = config::get_integer_val(matches, "instruction_index") as u16; - (governance_name, proposal_index, instruction_index) -} - -fn verify_instruction(client: &FarmClient, matches: &ArgMatches, instruction: &Instruction) { - let (governance_name, proposal_index, instruction_index) = get_instruction_args(matches); - let stored_instruction = client - .governance_get_instruction(&governance_name, proposal_index, instruction_index) - .unwrap(); - - if instruction == &stored_instruction { - println!("Instructions match."); - } else { - println!("Instructions are different."); - println!("Expected: {:?}", instruction); - println!("Stored: {:?}", stored_instruction); - } -} diff --git a/farms/farm-client/src/cli/printer.rs b/farms/farm-client/src/cli/printer.rs deleted file mode 100644 index 5c63cc746d4..00000000000 --- a/farms/farm-client/src/cli/printer.rs +++ /dev/null @@ -1,206 +0,0 @@ -//! Handlers for get and get_all command - -use { - crate::config::Config, - log::{error, info}, - serde::Serialize, - solana_farm_client::client::FarmClient, - solana_farm_sdk::string::to_pretty_json, - solana_sdk::pubkey::Pubkey, - std::str::FromStr, -}; - -pub fn print(client: &FarmClient, config: &Config, target: &str, object: &str) { - match target { - "program" => { - println!("{}: {}", object, client.get_program_id(object).unwrap()); - } - "fund" => { - print_object( - config, - &client.get_fund_ref(&object.to_uppercase()).unwrap(), - &client.get_fund(&object.to_uppercase()).unwrap(), - ); - } - "vault" => { - print_object( - config, - &client.get_vault_ref(&object.to_uppercase()).unwrap(), - &client.get_vault(&object.to_uppercase()).unwrap(), - ); - } - "farm" => { - print_object( - config, - &client.get_farm_ref(&object.to_uppercase()).unwrap(), - &client.get_farm(&object.to_uppercase()).unwrap(), - ); - } - "pool" => { - print_object( - config, - &client.get_pool_ref(&object.to_uppercase()).unwrap(), - &client.get_pool(&object.to_uppercase()).unwrap(), - ); - } - "token" => { - print_object( - config, - &client.get_token_ref(&object.to_uppercase()).unwrap(), - &client.get_token(&object.to_uppercase()).unwrap(), - ); - } - _ => { - error!( - "Unrecognized target. Must be one of: token, pool, farm, vault, fund or program." - ); - } - } -} - -pub fn print_with_ref(client: &FarmClient, config: &Config, target: &str, object: &str) { - let ref_key = Pubkey::from_str(object).unwrap(); - match target { - "program" => { - println!("{}: {}", client.get_program_name(&ref_key).unwrap(), object); - } - "fund" => { - print_object(config, &ref_key, &client.get_fund_by_ref(&ref_key).unwrap()); - } - "vault" => { - print_object( - config, - &ref_key, - &client.get_vault_by_ref(&ref_key).unwrap(), - ); - } - "farm" => { - print_object(config, &ref_key, &client.get_farm_by_ref(&ref_key).unwrap()); - } - "pool" => { - print_object(config, &ref_key, &client.get_pool_by_ref(&ref_key).unwrap()); - } - "token" => { - print_object( - config, - &ref_key, - &client.get_token_by_ref(&ref_key).unwrap(), - ); - } - _ => { - error!( - "Unrecognized target. Must be one of: token, pool, farm, vault, fund or program." - ); - } - } -} - -pub fn print_all(client: &FarmClient, config: &Config, target: &str) { - info!("Loading {} objects...", target); - - match target { - "program" => { - let storage = client.get_program_ids().unwrap(); - for (name, key) in storage.iter() { - println!("{}: {}", name, key); - } - } - "fund" => { - let storage = client.get_funds().unwrap(); - for (name, key) in storage.iter() { - print_object(config, &client.get_fund_ref(name).unwrap(), key); - } - } - "vault" => { - let storage = client.get_vaults().unwrap(); - for (name, key) in storage.iter() { - print_object(config, &client.get_vault_ref(name).unwrap(), key); - } - } - "farm" => { - let storage = client.get_farms().unwrap(); - for (name, key) in storage.iter() { - print_object(config, &client.get_farm_ref(name).unwrap(), key); - } - } - "pool" => { - let storage = client.get_pools().unwrap(); - for (name, key) in storage.iter() { - print_object(config, &client.get_pool_ref(name).unwrap(), key); - } - } - "token" => { - let storage = client.get_tokens().unwrap(); - for (name, key) in storage.iter() { - print_object(config, &client.get_token_ref(name).unwrap(), key); - } - } - _ => { - error!("Unrecognized target. Must be one of: token, pool, farm, vault, or program."); - } - } - - info!("Done.") -} - -pub fn list_all(client: &FarmClient, _config: &Config, target: &str) { - info!("Loading {} objects...", target); - - match target { - "program" => { - let storage = client.get_program_ids().unwrap(); - for (name, key) in storage.iter() { - println!("{}: {}", name, key); - } - } - "fund" => { - let storage = client.get_fund_refs().unwrap(); - for (name, key) in storage.iter() { - println!("{}: {}", name, key); - } - } - "vault" => { - let storage = client.get_vault_refs().unwrap(); - for (name, key) in storage.iter() { - println!("{}: {}", name, key); - } - } - "farm" => { - let storage = client.get_farm_refs().unwrap(); - for (name, key) in storage.iter() { - println!("{}: {}", name, key); - } - } - "pool" => { - let storage = client.get_pool_refs().unwrap(); - for (name, key) in storage.iter() { - println!("{}: {}", name, key); - } - } - "token" => { - let storage = client.get_token_refs().unwrap(); - for (name, key) in storage.iter() { - println!("{}: {}", name, key); - } - } - _ => { - error!( - "Unrecognized target. Must be one of: token, pool, farm, vault, fund or program." - ); - } - } - - info!("Done.") -} - -pub fn print_object(config: &Config, key: &K, object: &T) -where - T: ?Sized + Serialize + std::fmt::Display, - K: std::fmt::Display, -{ - if config.no_pretty_print { - println!("{}: {}", key, object); - } else { - println!("{}: {}", key, to_pretty_json(object).unwrap()); - } -} diff --git a/farms/farm-client/src/client.rs b/farms/farm-client/src/client.rs deleted file mode 100644 index aeaf9f6b66b..00000000000 --- a/farms/farm-client/src/client.rs +++ /dev/null @@ -1,6063 +0,0 @@ -//! Solana Farm Client -//! -//! Solana Farm Client provides an easy way to interact with pools, farms, vaults, and funds, -//! query on-chain objects metadata, and perform common operations with accounts. -//! -//! Client's methods accept human readable names (tokens, polls, etc.) and UI (decimal) -//! amounts, so you can simply call client.swap(&keypair, Protocol::Orca, "SOL", "USDC", 0.1, 0.0) -//! to swap 0.1 SOL for RAY in a Raydium pool. All metadata required to lookup account -//! addresses, decimals, etc. is stored on-chain. -//! -//! Under the hood it leverages the official Solana RPC Client which can be accessed with -//! client.rpc_client, for example: client.rpc_client.get_latest_blockhash(). -//! -//! Naming convention for Pools and Farms is [PROTOCOL].[TOKEN_A]-[TOKEN_B]-[VERSION] -//! Naming convention for Vaults is [PROTOCOL].[STRATEGY].[TOKEN_A]-[TOKEN_B]-[VERSION] -//! There are single token pools where TOKEN_B is not present. -//! A list of supported protocols can be obtained with get_protocols(). -//! If VERSION is omitted then Pool, Farm, or Vault with the latest version will be used. -//! -//! A few examples: -//! # use { -//! # solana_farm_client::client::FarmClient, -//! # solana_sdk::{pubkey::Pubkey, signer::Signer}, -//! # }; -//! # -//! # let client = FarmClient::new("https://api.mainnet-beta.solana.com"); -//! # let keypair = FarmClient::read_keypair_from_file( -//! # &(std::env::var("HOME").unwrap().to_string() + "/.config/solana/id.json"), -//! # ) -//! # .unwrap(); -//! # -//! # // get SOL account balance -//! # client.get_account_balance(&keypair.pubkey()).unwrap(); -//! # -//! # // get SPL token account balance -//! # client -//! # .get_token_account_balance(&keypair.pubkey(), "SRM") -//! # .unwrap(); -//! # -//! # // get token metadata -//! # client.get_token("SRM").unwrap(); -//! # -//! # // find Raydium pools with RAY and SRM tokens -//! # client.find_pools(Protocol::Raydium, "RAY", "SRM").unwrap(); -//! # -//! # // find Saber pools with USDC and USDT tokens -//! # client.find_pools(Protocol::Saber, "USDC", "USDT").unwrap(); -//! # -//! # // get pool metadata -//! # client.get_pool("RDM.RAY-SRM").unwrap(); -//! # -//! # // get farm metadata -//! # client.get_farm("RDM.RAY-SRM").unwrap(); -//! # -//! # // find all vaults with RAY and SRM tokens -//! # client.find_vaults("RAY", "SRM").unwrap(); -//! # -//! # // get vault metadata -//! # client.get_vault("RDM.STC.RAY-SRM").unwrap(); -//! # -//! # // get fund metadata -//! # client.get_fund("TestFund").unwrap(); -//! # -//! # // get the list of all pools -//! # client.get_pools().unwrap(); -//! # -//! # // find farms for specific LP token -//! # client.find_farms_with_lp("LP.RDM.RAY-SRM-V4").unwrap(); -//! # -//! # // get Raydium pool price -//! # client.get_pool_price("RDM.RAY-SRM").unwrap(); -//! # // or specify version for specific pool -//! # client.get_pool_price("RDM.RAY-SRM-V4").unwrap(); -//! # -//! # // get oracle price -//! # client.get_oracle_price("SOL", 0, 0.0).unwrap(); -//! # -//! # // list official program IDs -//! # client.get_program_ids().unwrap(); -//! # -//! # // swap in the Raydium pool -//! # client.swap(&keypair, Protocol::Raydium, "SOL", "RAY", 0.01, 0.0).unwrap(); -//! # -//! # // swap in the Saber pool -//! # client.swap(&keypair, Protocol::Saber, "USDC", "USDT", 0.01, 0.0).unwrap(); -//! # -//! # // deposit liquidity to the Raydium pool (zero second token amount means calculate it automatically) -//! # client -//! # .add_liquidity_pool(&keypair, "RDM.GRAPE-USDC", 0.1, 0.0) -//! # .unwrap(); -//! # -//! # // withdraw your liquidity from the Raydium pool (zero amount means remove all tokens) -//! # client -//! # .remove_liquidity_pool(&keypair, "RDM.GRAPE-USDC", 0.0) -//! # .unwrap(); -//! # -//! # // stake LP tokens to the Raydium farm (zero amount means stake all) -//! # client.stake(&keypair, "RDM.GRAPE-USDC", 0.0).unwrap(); -//! # -//! # // get staked balance -//! # client.get_user_stake_balance(&keypair.pubkey(), "RDM.GRAPE-USDC").unwrap(); -//! # -//! # // harvest rewards -//! # client.harvest(&keypair, "RDM.GRAPE-USDC").unwrap(); -//! # -//! # // unstake LP tokens from the farm (zero amount means unstake all) -//! # client.unstake(&keypair, "RDM.GRAPE-USDC", 0.0).unwrap(); -//! # -//! # // deposit liquidity to the vault (zero second token amount means calculate it automatically) -//! # client -//! # .add_liquidity_vault(&keypair, "RDM.STC.RAY-SRM", 0.01, 0.0) -//! # .unwrap(); -//! # -//! # // withdraw liquidity from the vault (zero amount means remove all tokens) -//! # client -//! # .remove_liquidity_vault(&keypair, "RDM.STC.RAY-SRM", 0.0) -//! # .unwrap(); -//! # -//! # // request liquidity deposit to the fund -//! # client -//! # .request_deposit_fund(&keypair, "TestFund", "USDC", 0.01) -//! # .unwrap(); -//! # -//! # // request liquidity withdrawal from the fund (zero amount means withdraw everything) -//! # client -//! # .request_withdrawal_fund(&keypair, "TestFund", "USDC", 0.0) -//! # .unwrap(); -//! # -//! # // list all vaults that belong to particular fund -//! # client.get_fund_vaults("TestFund").unwrap(); -//! # -//! # // transfer SOL to another wallet -//! # client -//! # .transfer(&keypair, &Pubkey::new_unique(), 0.001) -//! # .unwrap(); -//! # -//! # // transfer SPL tokens to another wallet -//! # client -//! # .token_transfer(&keypair, "SRM", &Pubkey::new_unique(), 0.001) -//! # .unwrap(); -//! # -//! # // create associated token account for the wallet -//! # client.get_or_create_token_account(&keypair, "SRM").unwrap(); -//! # -//! # // list all active token accounts for the wallet -//! # client.get_wallet_tokens(&keypair.pubkey()).unwrap(); -//! # -//! # // get vault stats -//! # client.get_vault_info("RDM.STC.RAY-SRM").unwrap(); -//! # -//! # // get user stats for particular vault -//! # client -//! # .get_vault_user_info(&keypair.pubkey(), "RDM.STC.RAY-SRM") -//! # .unwrap(); -//! # -//! # // create a new instruction for depositing liquidity to the vault, neither sign nor send it -//! # client -//! # .new_instruction_add_liquidity_vault(&keypair.pubkey(), "RDM.STC.RAY-SRM", 0.1, 0.0) -//! # .unwrap(); -//! # -//! # // get fund stats and parameters -//! # client.get_fund_info("TestFund").unwrap(); -//! # -//! # // get fund custody info -//! # client.get_fund_custody("TestFund", "USDC", FundCustodyType::DepositWithdraw).unwrap(); -//! # -//! # // get information about fund assets -//! # client.get_fund_assets(&fund_name, FundAssetType::Vault).unwrap(); -//! # client.get_fund_assets(&fund_name, FundAssetType::Custody).unwrap(); - -use { - crate::{cache::Cache, error::FarmClientError}, - arrayref::array_ref, - pyth_client::{PriceStatus, PriceType}, - solana_account_decoder::{ - parse_bpf_loader::{parse_bpf_upgradeable_loader, BpfUpgradeableLoaderAccountType}, - parse_token::{parse_token, TokenAccountType, UiAccountState, UiMint, UiTokenAccount}, - UiAccountEncoding, - }, - solana_client::{ - client_error::ClientErrorKind, - rpc_client::RpcClient, - rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig}, - rpc_custom_error, rpc_filter, - rpc_request::{RpcError, TokenAccountsFilter}, - }, - solana_farm_sdk::{ - farm::{Farm, FarmRoute}, - fund::{ - Fund, FundAssetType, FundAssets, FundAssetsTrackingConfig, FundCustody, - FundCustodyType, FundCustodyWithBalance, FundInfo, FundSchedule, FundUserInfo, - FundUserRequests, FundVault, FundVaultType, DISCRIMINATOR_FUND_CUSTODY, - DISCRIMINATOR_FUND_USER_REQUESTS, DISCRIMINATOR_FUND_VAULT, - }, - id::{ - main_router, main_router_admin, main_router_multisig, zero, DAO_CUSTODY_NAME, - DAO_MINT_NAME, DAO_PROGRAM_NAME, DAO_TOKEN_NAME, - }, - math, - pool::{Pool, PoolRoute}, - program::{ - multisig::Multisig, - protocol::{ - orca::OrcaUserStakeInfo, - raydium::{RaydiumUserStakeInfo, RaydiumUserStakeInfoV4}, - saber::Miner, - }, - }, - refdb, - refdb::{Header, RefDB}, - string::str_to_as64, - token::{OracleType, Token, TokenSelector, TokenType}, - traits::Packed, - vault::{Vault, VaultInfo, VaultStrategy, VaultUserInfo}, - ProgramIDType, Protocol, ProtocolInfo, - }, - solana_sdk::{ - account::Account, - borsh::try_from_slice_unchecked, - bpf_loader_upgradeable, - clock::UnixTimestamp, - commitment_config::{CommitmentConfig, CommitmentLevel}, - instruction::Instruction, - message::Message, - program_error::ProgramError, - program_pack::Pack, - pubkey::Pubkey, - signature::{read_keypair, read_keypair_file, Keypair, Signature, Signer}, - signers::Signers, - transaction::Transaction, - }, - spl_associated_token_account::{create_associated_token_account, get_associated_token_address}, - spl_governance::state::{ - enums::GovernanceAccountType, - governance::{ - get_account_governance_address, get_mint_governance_address, - get_program_governance_address, Governance, GovernanceConfig, - }, - proposal::{get_proposal_address, ProposalV2}, - proposal_instruction::{ - get_proposal_instruction_address, InstructionData, ProposalInstructionV2, - }, - realm::get_realm_address, - }, - spl_token::state::Mint, - stable_swap_client::state::SwapInfo, - stable_swap_math::price::SaberSwap, - std::{ - cell::RefCell, collections::HashMap, str::FromStr, thread, time, time::Duration, vec::Vec, - }, -}; - -pub type VaultMap = HashMap; -pub type FundMap = HashMap; -pub type PoolMap = HashMap; -pub type FarmMap = HashMap; -pub type TokenMap = HashMap; -pub type PubkeyMap = HashMap; -pub type StakeAccMap = HashMap; -pub type U64Map = HashMap; - -/// Farm Client -pub struct FarmClient { - pub rpc_client: RpcClient, - tokens: RefCell>, - pools: RefCell>, - farms: RefCell>, - vaults: RefCell>, - funds: RefCell>, - token_refs: RefCell>, - pool_refs: RefCell>, - farm_refs: RefCell>, - vault_refs: RefCell>, - fund_refs: RefCell>, - official_ids: RefCell>, - stake_accounts: RefCell>>, - latest_pools: RefCell>, - latest_farms: RefCell>, - latest_vaults: RefCell>, -} - -impl Default for FarmClient { - fn default() -> Self { - Self { - rpc_client: RpcClient::new("".to_string()), - tokens: RefCell::new(Cache::::default()), - pools: RefCell::new(Cache::::default()), - farms: RefCell::new(Cache::::default()), - vaults: RefCell::new(Cache::::default()), - funds: RefCell::new(Cache::::default()), - token_refs: RefCell::new(Cache::::default()), - pool_refs: RefCell::new(Cache::::default()), - farm_refs: RefCell::new(Cache::::default()), - vault_refs: RefCell::new(Cache::::default()), - fund_refs: RefCell::new(Cache::::default()), - official_ids: RefCell::new(Cache::::default()), - stake_accounts: RefCell::new(vec![HashMap::::new(); 3]), - latest_pools: RefCell::new(HashMap::::new()), - latest_farms: RefCell::new(HashMap::::new()), - latest_vaults: RefCell::new(HashMap::::new()), - } - } -} - -impl FarmClient { - /// Creates a new FarmClient object - /// RPC URLs: - /// Devnet: https://api.devnet.solana.com - /// Testnet: https://api.testnet.solana.com - /// Mainnet-beta: https://api.mainnet-beta.solana.com - /// local node: http://localhost:8899 - pub fn new(url: &str) -> Self { - Self { - rpc_client: RpcClient::new(url.to_string()), - ..FarmClient::default() - } - } - - /// Creates a new FarmClient object with commitment config - pub fn new_with_commitment(url: &str, commitment_config: CommitmentConfig) -> Self { - Self { - rpc_client: RpcClient::new_with_commitment(url.to_string(), commitment_config), - ..FarmClient::default() - } - } - - /// Creates a new FarmClient object with timeout and config - pub fn new_with_timeout_and_commitment( - url: &str, - timeout: Duration, - commitment_config: CommitmentConfig, - ) -> Self { - Self { - rpc_client: RpcClient::new_with_timeout_and_commitment( - url.to_string(), - timeout, - commitment_config, - ), - ..FarmClient::default() - } - } - - pub fn new_mock(url: &str) -> Self { - Self { - rpc_client: RpcClient::new_mock(url.to_string()), - ..FarmClient::default() - } - } - - /// Returns the Fund struct for the given name - pub fn get_fund(&self, name: &str) -> Result { - // reload Fund refs if stale - self.reload_fund_refs_if_stale()?; - // if Fund is in cache return it - if let Some(fund) = self.funds.borrow().data.get(name) { - return Ok(*fund); - } - // load Fund data from blockchain - if let Some(key) = self.fund_refs.borrow().data.get(name) { - let fund = self.load_fund_by_ref(key)?; - self.funds.borrow_mut().data.insert(name.to_string(), fund); - return Ok(fund); - } - Err(FarmClientError::RecordNotFound(format!("Fund {}", name))) - } - - /// Returns all Funds available - pub fn get_funds(&self) -> Result { - self.reload_fund_refs_if_stale()?; - self.reload_funds_if_empty()?; - Ok(self.funds.borrow().data.clone()) - } - - /// Returns the Fund metadata address for the given name - pub fn get_fund_ref(&self, name: &str) -> Result { - // reload Fund refs if stale - self.reload_fund_refs_if_stale()?; - // return the address from cache - if let Some(key) = self.fund_refs.borrow().data.get(name) { - return Ok(*key); - } - Err(FarmClientError::RecordNotFound(format!("Fund {}", name))) - } - - /// Returns Fund refs: a map of Fund name to account address with metadata - pub fn get_fund_refs(&self) -> Result { - self.reload_fund_refs_if_stale()?; - Ok(self - .get_refdb_pubkey_map(&refdb::StorageType::Fund.to_string())? - .1) - } - - /// Returns the Fund metadata at the specified address - pub fn get_fund_by_ref(&self, fund_ref: &Pubkey) -> Result { - let name = &self.get_fund_name(fund_ref)?; - self.get_fund(name) - } - - /// Returns the Fund name for the given metadata address - pub fn get_fund_name(&self, fund_ref: &Pubkey) -> Result { - // reload Fund refs if stale - self.reload_fund_refs_if_stale()?; - // return the name from cache - for (name, key) in self.fund_refs.borrow().data.iter() { - if key == fund_ref { - return Ok(name.to_string()); - } - } - Err(FarmClientError::RecordNotFound(format!( - "Fund reference {}", - fund_ref - ))) - } - - /// Returns all Funds that have Vaults with the name matching the pattern sorted by version - pub fn find_funds(&self, vault_name_pattern: &str) -> Result, FarmClientError> { - let mut res = vec![]; - let funds = self.get_funds()?; - for (fund_name, fund) in &funds { - let vaults = self.get_fund_vaults(fund_name)?; - for vault in &vaults { - if let Ok(vault) = self.get_vault_by_ref(&vault.vault_ref) { - if vault.name.contains(&vault_name_pattern) { - res.push(*fund); - } - } - } - } - if res.is_empty() { - Err(FarmClientError::RecordNotFound(format!( - "Funds with Vault name pattern {}", - vault_name_pattern - ))) - } else { - res.sort_by(|a, b| b.version.cmp(&a.version)); - Ok(res) - } - } - - /// Returns the Vault struct for the given name - pub fn get_vault(&self, name: &str) -> Result { - // reload Vault refs if stale - self.reload_vault_refs_if_stale()?; - let vault_name = if let Some(val) = self.latest_vaults.borrow().get(name) { - val.clone() - } else { - name.to_string() - }; - // if Vault is in cache return it - if let Some(vault) = self.vaults.borrow().data.get(&vault_name) { - return Ok(*vault); - } - // load Vault data from blockchain - if let Some(key) = self.vault_refs.borrow().data.get(&vault_name) { - let vault = self.load_vault_by_ref(key)?; - self.vaults.borrow_mut().data.insert(vault_name, vault); - return Ok(vault); - } - Err(FarmClientError::RecordNotFound(format!("Vault {}", name))) - } - - /// Returns all Vaults available - pub fn get_vaults(&self) -> Result { - self.reload_vault_refs_if_stale()?; - self.reload_vaults_if_empty()?; - Ok(self.vaults.borrow().data.clone()) - } - - /// Returns the Vault metadata address for the given name - pub fn get_vault_ref(&self, name: &str) -> Result { - // reload Vault refs if stale - self.reload_vault_refs_if_stale()?; - // return the address from cache - let vault_name = if let Some(val) = self.latest_vaults.borrow().get(name) { - val.clone() - } else { - name.to_string() - }; - if let Some(key) = self.vault_refs.borrow().data.get(&vault_name) { - return Ok(*key); - } - Err(FarmClientError::RecordNotFound(format!("Vault {}", name))) - } - - /// Returns Vault refs: a map of Vault name to account address with metadata - pub fn get_vault_refs(&self) -> Result { - self.reload_vault_refs_if_stale()?; - Ok(self.vault_refs.borrow().data.clone()) - } - - /// Returns the Vault metadata at the specified address - pub fn get_vault_by_ref(&self, vault_ref: &Pubkey) -> Result { - let name = &self.get_vault_name(vault_ref)?; - self.get_vault(name) - } - - /// Returns the Vault name for the given metadata address - pub fn get_vault_name(&self, vault_ref: &Pubkey) -> Result { - // reload Vault refs if stale - self.reload_vault_refs_if_stale()?; - // return the name from cache - for (name, key) in self.vault_refs.borrow().data.iter() { - if key == vault_ref { - return Ok(name.to_string()); - } - } - Err(FarmClientError::RecordNotFound(format!( - "Vault reference {}", - vault_ref - ))) - } - - /// Returns all Vaults with tokens A and B sorted by version - pub fn find_vaults(&self, token_a: &str, token_b: &str) -> Result, FarmClientError> { - self.reload_vault_refs_if_stale()?; - let pattern1 = format!(".{}-{}-", token_a, token_b); - let pattern2 = format!(".{}-{}-", token_b, token_a); - let mut res = vec![]; - for (name, _) in self.vault_refs.borrow().data.iter() { - if name.contains(&pattern1) || name.contains(&pattern2) { - res.push(self.get_vault(name)?); - } - } - if res.is_empty() { - Err(FarmClientError::RecordNotFound(format!( - "Vault with tokens {} and {}", - token_a, token_b - ))) - } else { - res.sort_by(|a, b| b.version.cmp(&a.version)); - Ok(res) - } - } - - /// Returns all Vaults sorted by version for the given VT token - pub fn find_vaults_with_vt(&self, vt_token_name: &str) -> Result, FarmClientError> { - let (protocol, token_a, token_b) = FarmClient::extract_token_names(vt_token_name)?; - let vaults = self.find_vaults(&token_a, &token_b)?; - let mut res = vec![]; - for vault in &vaults { - if self.get_token_by_ref(&vault.vault_token_ref)?.name.as_str() == vt_token_name { - res.push(*vault); - } - } - - if res.is_empty() { - Err(FarmClientError::RecordNotFound(format!( - "{} Vault with VT token {}", - protocol, vt_token_name - ))) - } else { - res.sort_by(|a, b| b.version.cmp(&a.version)); - Ok(res) - } - } - - /// Returns the Pool struct for the given name - pub fn get_pool(&self, name: &str) -> Result { - // reload Pool refs if stale - self.reload_pool_refs_if_stale()?; - let pool_name = if let Some(val) = self.latest_pools.borrow().get(name) { - val.clone() - } else { - name.to_string() - }; - // if Pool is in cache return it - if let Some(pool) = self.pools.borrow().data.get(&pool_name) { - return Ok(*pool); - } - // load Pool data from blockchain - if let Some(key) = self.pool_refs.borrow().data.get(&pool_name) { - let pool = self.load_pool_by_ref(key)?; - self.pools.borrow_mut().data.insert(pool_name, pool); - return Ok(pool); - } - Err(FarmClientError::RecordNotFound(format!("Pool {}", name))) - } - - /// Returns all Pools available - pub fn get_pools(&self) -> Result { - self.reload_pool_refs_if_stale()?; - self.reload_pools_if_empty()?; - Ok(self.pools.borrow().data.clone()) - } - - /// Returns the Pool metadata address for the given name - pub fn get_pool_ref(&self, name: &str) -> Result { - // reload Pool refs if stale - self.reload_pool_refs_if_stale()?; - // return the address from cache - let pool_name = if let Some(val) = self.latest_pools.borrow().get(name) { - val.clone() - } else { - name.to_string() - }; - if let Some(key) = self.pool_refs.borrow().data.get(&pool_name) { - return Ok(*key); - } - Err(FarmClientError::RecordNotFound(format!("Pool {}", name))) - } - - /// Returns Pool refs: a map of Pool name to account address with metadata - pub fn get_pool_refs(&self) -> Result { - self.reload_pool_refs_if_stale()?; - Ok(self.pool_refs.borrow().data.clone()) - } - - /// Returns the Pool metadata at the specified address - pub fn get_pool_by_ref(&self, pool_ref: &Pubkey) -> Result { - let name = &self.get_pool_name(pool_ref)?; - self.get_pool(name) - } - - /// Returns the Pool name for the given metadata address - pub fn get_pool_name(&self, pool_ref: &Pubkey) -> Result { - // reload Pool refs if stale - self.reload_pool_refs_if_stale()?; - // return the name from cache - for (name, key) in self.pool_refs.borrow().data.iter() { - if key == pool_ref { - return Ok(name.to_string()); - } - } - Err(FarmClientError::RecordNotFound(format!( - "Pool reference {}", - pool_ref - ))) - } - - /// Returns all Pools with tokens A and B sorted by version for the given protocol - pub fn find_pools( - &self, - protocol: Protocol, - token_a: &str, - token_b: &str, - ) -> Result, FarmClientError> { - self.reload_pool_refs_if_stale()?; - let pattern1 = format!("{}.{}-{}-", protocol.id(), token_a, token_b); - let pattern2 = format!("{}.{}-{}-", protocol.id(), token_b, token_a); - let mut res = vec![]; - for (name, _) in self.pool_refs.borrow().data.iter() { - if name.starts_with(&pattern1) || name.starts_with(&pattern2) { - res.push(self.get_pool(name)?); - } - } - if res.is_empty() { - Err(FarmClientError::RecordNotFound(format!( - "{} Pool with tokens {} and {}", - protocol, token_a, token_b - ))) - } else { - res.sort_by(|a, b| b.version.cmp(&a.version)); - Ok(res) - } - } - - /// Returns all Pools sorted by version for the given LP token - pub fn find_pools_with_lp(&self, lp_token_name: &str) -> Result, FarmClientError> { - let lp_token_ref = self.get_token_ref(lp_token_name)?; - let pools = self.get_pools()?; - let mut res = vec![]; - for pool in pools.values() { - if let Some(pool_lp_token_ref) = pool.lp_token_ref { - if lp_token_ref == pool_lp_token_ref { - res.push(*pool); - } - } - } - - if res.is_empty() { - Err(FarmClientError::RecordNotFound(format!( - "Pool with LP token {}", - lp_token_name - ))) - } else { - res.sort_by(|a, b| b.version.cmp(&a.version)); - Ok(res) - } - } - - /// Returns pair's price based on the ratio of tokens in the pool - pub fn get_pool_price(&self, pool_name: &str) -> Result { - let pool = self.get_pool(pool_name)?; - if pool.token_a_ref.is_none() || pool.token_b_ref.is_none() { - return Ok(0.0); - } - let token_a = self.get_token_by_ref(&pool.token_a_ref.unwrap())?; - let token_b = self.get_token_by_ref(&pool.token_b_ref.unwrap())?; - let token_a_balance = self - .rpc_client - .get_token_account_balance( - &pool - .token_a_account - .ok_or(ProgramError::UninitializedAccount)?, - )? - .amount - .parse::() - .unwrap(); - let token_b_balance = self - .rpc_client - .get_token_account_balance( - &pool - .token_b_account - .ok_or(ProgramError::UninitializedAccount)?, - )? - .amount - .parse::() - .unwrap(); - - match pool.route { - PoolRoute::Raydium { - amm_id, - amm_open_orders, - .. - } => self.get_pool_price_raydium( - token_a_balance, - token_b_balance, - token_a.decimals, - token_b.decimals, - &amm_id, - &amm_open_orders, - ), - PoolRoute::Saber { swap_account, .. } => { - let lp_token = self.get_token_by_ref(&pool.lp_token_ref.unwrap())?; - self.get_pool_price_saber( - &swap_account, - token_a_balance, - token_b_balance, - &lp_token, - ) - } - PoolRoute::Orca { .. } => self.get_pool_price_orca( - token_a_balance, - token_b_balance, - token_a.decimals, - token_b.decimals, - ), - } - } - - /// Returns the Farm struct for the given name - pub fn get_farm(&self, name: &str) -> Result { - // reload Farm refs if stale - self.reload_farm_refs_if_stale()?; - let farm_name = if let Some(val) = self.latest_farms.borrow().get(name) { - val.clone() - } else { - name.to_string() - }; - // if Farm is in cache return it - if let Some(farm) = self.farms.borrow().data.get(&farm_name) { - return Ok(*farm); - } - // load Farm data from blockchain - if let Some(key) = self.farm_refs.borrow().data.get(&farm_name) { - let farm = self.load_farm_by_ref(key)?; - self.farms.borrow_mut().data.insert(farm_name, farm); - return Ok(farm); - } - Err(FarmClientError::RecordNotFound(format!("Farm {}", name))) - } - - /// Returns all Farms available - pub fn get_farms(&self) -> Result { - self.reload_farm_refs_if_stale()?; - self.reload_farms_if_empty()?; - Ok(self.farms.borrow().data.clone()) - } - - /// Returns the Farm metadata address for the given name - pub fn get_farm_ref(&self, name: &str) -> Result { - // reload Farm refs if stale - self.reload_farm_refs_if_stale()?; - // return the address from cache - let farm_name = if let Some(val) = self.latest_farms.borrow().get(name) { - val.clone() - } else { - name.to_string() - }; - if let Some(key) = self.farm_refs.borrow().data.get(&farm_name) { - return Ok(*key); - } - Err(FarmClientError::RecordNotFound(format!("Farm {}", name))) - } - - /// Returns Farm refs: a map of Farm name to account address with metadata - pub fn get_farm_refs(&self) -> Result { - self.reload_farm_refs_if_stale()?; - Ok(self.farm_refs.borrow().data.clone()) - } - - /// Returns the Farm metadata at the specified address - pub fn get_farm_by_ref(&self, farm_ref: &Pubkey) -> Result { - let name = &self.get_farm_name(farm_ref)?; - self.get_farm(name) - } - - /// Returns the Farm name for the given metadata address - pub fn get_farm_name(&self, farm_ref: &Pubkey) -> Result { - // reload Farm refs if stale - self.reload_farm_refs_if_stale()?; - // return the name from cache - for (name, key) in self.farm_refs.borrow().data.iter() { - if key == farm_ref { - return Ok(name.to_string()); - } - } - Err(FarmClientError::RecordNotFound(format!( - "Farm reference {}", - farm_ref - ))) - } - - /// Returns all Farms for the given LP token - pub fn find_farms_with_lp(&self, lp_token_name: &str) -> Result, FarmClientError> { - let lp_token_ref = self.get_token_ref(lp_token_name)?; - let farms = self.get_farms()?; - let mut res = vec![]; - for farm in farms.values() { - if let Some(farm_lp_token_ref) = farm.lp_token_ref { - if lp_token_ref == farm_lp_token_ref { - res.push(*farm); - } - } - } - - if res.is_empty() { - Err(FarmClientError::RecordNotFound(format!( - "Farm with LP token {}", - lp_token_name - ))) - } else { - res.sort_by(|a, b| b.version.cmp(&a.version)); - Ok(res) - } - } - - /// Returns the Token struct for the given name - pub fn get_token(&self, name: &str) -> Result { - // reload Token refs if stale - self.reload_token_refs_if_stale()?; - // if Token is in cache return it - if let Some(token) = self.tokens.borrow().data.get(name) { - return Ok(*token); - } - // load Token data from blockchain - if let Some(key) = self.token_refs.borrow().data.get(name) { - let token = self.load_token_by_ref(key)?; - self.tokens - .borrow_mut() - .data - .insert(name.to_string(), token); - return Ok(token); - } - Err(FarmClientError::RecordNotFound(format!("Token {}", name))) - } - - /// Returns all Tokens available - pub fn get_tokens(&self) -> Result { - self.reload_token_refs_if_stale()?; - self.reload_tokens_if_empty()?; - Ok(self.tokens.borrow().data.clone()) - } - - /// Returns the Token metadata address for the given name - pub fn get_token_ref(&self, name: &str) -> Result { - // reload Token refs if stale - self.reload_token_refs_if_stale()?; - // return the address from cache - if let Some(key) = self.token_refs.borrow().data.get(name) { - return Ok(*key); - } - Err(FarmClientError::RecordNotFound(format!("Token {}", name))) - } - - /// Returns Token refs: a map of Token name to account address with metadata - pub fn get_token_refs(&self) -> Result { - self.reload_token_refs_if_stale()?; - Ok(self - .get_refdb_pubkey_map(&refdb::StorageType::Token.to_string())? - .1) - } - - /// Returns the Token metadata at the specified address - pub fn get_token_by_ref(&self, token_ref: &Pubkey) -> Result { - let name = &self.get_token_name(token_ref)?; - self.get_token(name) - } - - /// Returns the Token name for the given metadata address - pub fn get_token_name(&self, token_ref: &Pubkey) -> Result { - // reload Token refs if stale - self.reload_token_refs_if_stale()?; - // return the name from cache - for (name, key) in self.token_refs.borrow().data.iter() { - if key == token_ref { - return Ok(name.to_string()); - } - } - Err(FarmClientError::RecordNotFound(format!( - "Token reference {}", - token_ref - ))) - } - - /// Returns the Token metadata for the specified mint - /// This function loads all tokens to the cache, slow on the first call. - pub fn get_token_with_mint(&self, token_mint: &Pubkey) -> Result { - let tokens = self.get_tokens()?; - for token in tokens.values() { - if token_mint == &token.mint { - return Ok(*token); - } - } - Err(FarmClientError::RecordNotFound(format!( - "Token with mint {}", - token_mint - ))) - } - - /// Returns the Token metadata for the specified token account - /// This function loads all tokens to the cache, slow on the first call. - pub fn get_token_with_account(&self, token_account: &Pubkey) -> Result { - let data = self.rpc_client.get_account_data(token_account)?; - let res = parse_token(data.as_slice(), Some(0))?; - if let TokenAccountType::Account(ui_account) = res { - self.get_token_with_mint(&Pubkey::from_str(&ui_account.mint).map_err(|_| { - FarmClientError::ValueError(format!( - "Failed to parse mint in token account {}", - token_account - )) - })?) - } else { - Err(FarmClientError::ValueError(format!( - "No account data found in token account {}", - token_account - ))) - } - } - - /// Returns token supply as UI amount - pub fn get_token_supply(&self, name: &str) -> Result { - self.rpc_client - .get_token_supply(&self.get_token(name)?.mint)? - .ui_amount - .ok_or_else(|| FarmClientError::ValueError("Invalid UI token amount".to_string())) - } - - /// Returns the official Program ID for the given name - pub fn get_program_id(&self, name: &str) -> Result { - // reload program ids if stale - self.reload_program_ids_if_stale()?; - // if program id is in cache return it - if let Some(pubkey) = self.official_ids.borrow().data.get(name) { - return Ok(*pubkey); - } - Err(FarmClientError::RecordNotFound(format!("Program {}", name))) - } - - /// Returns all official Program IDs available - pub fn get_program_ids(&self) -> Result { - self.reload_program_ids_if_stale()?; - Ok(self - .get_refdb_pubkey_map(&refdb::StorageType::Program.to_string())? - .1) - } - - /// Returns the official program name for the given Program ID - pub fn get_program_name(&self, prog_id: &Pubkey) -> Result { - // reload program ids if stale - self.reload_program_ids_if_stale()?; - for (name, key) in self.official_ids.borrow().data.iter() { - if key == prog_id { - return Ok(name.to_string()); - } - } - Err(FarmClientError::RecordNotFound(format!( - "Program ID {}", - prog_id - ))) - } - - /// Checks if the given address is the official Program ID - pub fn is_official_id(&self, prog_id: &Pubkey) -> Result { - Ok(*prog_id == main_router::id() || self.get_program_name(prog_id).is_ok()) - } - - /// Returns program upgrade authority - pub fn get_program_upgrade_authority( - &self, - prog_id: &Pubkey, - ) -> Result { - let program_account_data = self.rpc_client.get_account_data(prog_id)?; - let program_account = parse_bpf_upgradeable_loader(&program_account_data)?; - - match program_account { - BpfUpgradeableLoaderAccountType::Program(ui_program) => { - let program_data_account_key = - FarmClient::pubkey_from_str(&ui_program.program_data)?; - let program_data_account_data = self - .rpc_client - .get_account_data(&program_data_account_key)?; - let program_data_account = - parse_bpf_upgradeable_loader(&program_data_account_data)?; - - match program_data_account { - BpfUpgradeableLoaderAccountType::ProgramData(ui_program_data) => { - if let Some(authority) = ui_program_data.authority { - Ok(FarmClient::pubkey_from_str(&authority)?) - } else { - Ok(zero::id()) - } - } - _ => { - return Err(FarmClientError::ValueError(format!( - "Invalid program data account {}", - program_data_account_key - ))) - } - } - } - _ => { - return Err(FarmClientError::ValueError(format!( - "Invalid program account {}", - prog_id - ))) - } - } - } - - /// Returns multisig account address for the program - pub fn get_program_multisig_account( - &self, - prog_id: &Pubkey, - ) -> Result { - Ok(Pubkey::find_program_address(&[b"multisig", prog_id.as_ref()], &main_router::id()).0) - } - - /// Returns data buffer account address for the program - pub fn get_program_buffer_account(&self, prog_id: &Pubkey) -> Result { - Ok(Pubkey::find_program_address(&[prog_id.as_ref()], &bpf_loader_upgradeable::id()).0) - } - - /// Returns program upgrade signers - pub fn get_program_admins(&self, prog_id: &Pubkey) -> Result { - let upgrade_authority = self.get_program_upgrade_authority(prog_id)?; - let multisig = self.get_program_multisig_account(prog_id)?; - - if upgrade_authority == multisig { - if let Ok(data) = self.rpc_client.get_account_data(&multisig) { - Multisig::unpack(&data).map_err(|e| e.into()) - } else { - Err(FarmClientError::ValueError(format!( - "Invalid multisig account {}", - multisig - ))) - } - } else { - Ok(Multisig { - num_signers: 1, - num_signed: 0, - min_signatures: 1, - instruction_accounts_len: 0, - instruction_data_len: 0, - instruction_hash: 0, - signers: [ - upgrade_authority, - zero::id(), - zero::id(), - zero::id(), - zero::id(), - zero::id(), - ], - signed: [false, false, false, false, false, false], - }) - } - } - - /// Sets new program upgrade signers - pub fn set_program_admins( - &self, - admin_signer: &dyn Signer, - prog_id: &Pubkey, - admin_signers: &[Pubkey], - min_signatures: u8, - ) -> Result { - let inst = self.new_instruction_set_program_admins( - &admin_signer.pubkey(), - prog_id, - admin_signers, - min_signatures, - )?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Sets single upgrade authority for the program removing multisig if present - pub fn set_program_single_authority( - &self, - admin_signer: &dyn Signer, - prog_id: &Pubkey, - upgrade_authority: &Pubkey, - ) -> Result { - let inst = self.new_instruction_set_program_single_authority( - &admin_signer.pubkey(), - prog_id, - upgrade_authority, - )?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Upgrades the program from the data buffer - pub fn upgrade_program( - &self, - admin_signer: &dyn Signer, - prog_id: &Pubkey, - source_buffer_address: &Pubkey, - ) -> Result { - let inst = self.new_instruction_upgrade_program( - &admin_signer.pubkey(), - prog_id, - source_buffer_address, - )?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Reads the Keypair from stdin - pub fn read_keypair_from_stdin() -> Result { - let mut stdin = std::io::stdin(); - read_keypair(&mut stdin).map_err(|e| FarmClientError::IOError(e.to_string())) - } - - /// Reads the Keypair from the file - pub fn read_keypair_from_file(path: &str) -> Result { - read_keypair_file(path).map_err(|e| FarmClientError::IOError(e.to_string())) - } - - /// Signs and sends instructions - pub fn sign_and_send_instructions( - &self, - signers: &S, - instructions: &[Instruction], - ) -> Result { - if signers.pubkeys().is_empty() { - return Err(FarmClientError::ValueError( - "No signers provided for instruction".to_string(), - )); - } - let mut transaction = - Transaction::new_with_payer(instructions, Some(&signers.pubkeys()[0])); - let mut recent_blockhash = self.rpc_client.get_latest_blockhash()?; - let mut prev_signature = Signature::default(); - - for i in 0..20 { - if i > 0 - && !self - .rpc_client - .is_blockhash_valid(&recent_blockhash, self.rpc_client.commitment())? - { - recent_blockhash = self.rpc_client.get_latest_blockhash()?; - } - transaction.sign(signers, recent_blockhash); - - let result = self - .rpc_client - .send_and_confirm_transaction_with_spinner(&transaction); - if let Ok(signature) = result { - return Ok(signature); - } else if i != 19 { - if let Err(ref error) = result { - if let ClientErrorKind::RpcError(ref rpc_error) = error.kind { - if let RpcError::RpcResponseError { code, message, .. } = rpc_error { - if *code == rpc_custom_error::JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY - || *code - == rpc_custom_error::JSON_RPC_SERVER_ERROR_BLOCK_NOT_AVAILABLE - || (*code == rpc_custom_error::JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE - && message.ends_with("Blockhash not found")) - { - println!("Node is unhealthy, re-trying in 5 secs..."); - prev_signature = transaction.signatures[0]; - thread::sleep(time::Duration::from_secs(5)); - continue; - } else if *code == rpc_custom_error::JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE - && message.ends_with("transaction has already been processed") { - return Ok(prev_signature); - } - } else if let RpcError::ForUser(msg) = rpc_error { - if msg.starts_with("unable to confirm transaction") - || msg.ends_with("Please retry.") - { - println!("Unable to confirm transaction, re-trying in 5 secs..."); - prev_signature = transaction.signatures[0]; - thread::sleep(time::Duration::from_secs(5)); - continue; - } - } - } else if let ClientErrorKind::Reqwest(ref error) = error.kind { - if error.is_timeout() { - println!("Response timed out, re-trying in 5 secs..."); - prev_signature = transaction.signatures[0]; - thread::sleep(time::Duration::from_secs(5)); - continue; - } - } - } - return Err(FarmClientError::RpcClientError(result.unwrap_err())); - } else { - return Err(FarmClientError::RpcClientError(result.unwrap_err())); - } - } - unreachable!(); - } - - /// Returns serialized and encoded transaction size - pub fn get_transaction_size(transaction: &Transaction) -> Result { - Ok( - base64::encode(bincode::serialize(&transaction).map_err(|_| { - FarmClientError::ParseError("Failed to serialize transaction".to_string()) - })?) - .len(), - ) - } - - /// Creates a new transaction with as many instructions as possible that fit transaction size limit - pub fn create_transaction( - instructions: &[Instruction], - payer: &Pubkey, - ) -> Result<(Transaction, usize), FarmClientError> { - let transaction = Transaction::new_with_payer(instructions, Some(payer)); - if instructions.len() <= 1 || FarmClient::get_transaction_size(&transaction)? <= 1644 { - return Ok((transaction, instructions.len())); - } - - for i in 2..(instructions.len() + 1) { - let transaction = Transaction::new_with_payer(&instructions[0..i], Some(payer)); - if FarmClient::get_transaction_size(&transaction)? > 1644 { - return Ok(( - Transaction::new_with_payer(&instructions[0..i - 1], Some(payer)), - i - 1, - )); - } - } - - unreachable!(); - } - - /// Signs and sends instructions - pub fn sign_and_send_instructions_in_batches( - &self, - signers: &S, - instructions: &[Instruction], - ) -> Result, FarmClientError> { - if signers.pubkeys().is_empty() { - return Err(FarmClientError::ValueError( - "No signers provided for instruction".to_string(), - )); - } - // process instructions in batches - let mut processed = 0; - let mut signatures = vec![]; - while processed < instructions.len() { - let (_, batch_size) = - FarmClient::create_transaction(&instructions[processed..], &signers.pubkeys()[0])?; - let res = self.sign_and_send_instructions( - signers, - &instructions[processed..processed + batch_size], - ); - if let Ok(signature) = res { - signatures.push(signature); - } else { - return res.map(|_| signatures); - } - - processed += batch_size; - } - Ok(signatures) - } - - /// Wait for the transaction to become finalized - pub fn confirm_async_transaction( - &self, - signature: &Signature, - commitment: CommitmentLevel, - ) -> Result<(), FarmClientError> { - let recent_blockhash = self.rpc_client.get_latest_blockhash()?; - self.rpc_client - .confirm_transaction_with_spinner( - signature, - &recent_blockhash, - CommitmentConfig { commitment }, - ) - .map_err(Into::into) - } - - /// Creates a new system account - pub fn create_system_account( - &self, - signer: &dyn Signer, - new_account_signer: &dyn Signer, - lamports: u64, - space: usize, - owner: &Pubkey, - ) -> Result { - let inst = self.new_instruction_create_system_account( - &signer.pubkey(), - &new_account_signer.pubkey(), - lamports, - space, - owner, - )?; - self.sign_and_send_instructions(&[signer, new_account_signer], &[inst]) - } - - /// Closes the system account - pub fn close_system_account( - &self, - signer: &dyn Signer, - target_account_signer: &dyn Signer, - ) -> Result { - let inst = self.new_instruction_close_system_account( - &signer.pubkey(), - &target_account_signer.pubkey(), - )?; - self.sign_and_send_instructions(&[signer, target_account_signer], &[inst]) - } - - /// Creates a new system account with seed - pub fn create_system_account_with_seed( - &self, - signer: &dyn Signer, - base_address: &Pubkey, - seed: &str, - lamports: u64, - space: usize, - owner: &Pubkey, - ) -> Result { - let inst = self.new_instruction_create_system_account_with_seed( - &signer.pubkey(), - base_address, - seed, - lamports, - space, - owner, - )?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Assigns system account to a program - pub fn assign_system_account( - &self, - signer: &dyn Signer, - program_address: &Pubkey, - ) -> Result { - let inst = self.new_instruction_assign_system_account(&signer.pubkey(), program_address)?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Transfers native SOL from the wallet to the destination - pub fn transfer( - &self, - signer: &dyn Signer, - destination_wallet: &Pubkey, - sol_ui_amount: f64, - ) -> Result { - let inst = - self.new_instruction_transfer(&signer.pubkey(), destination_wallet, sol_ui_amount)?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Transfers native SOL from the wallet to the associated Wrapped SOL account - pub fn wrap_sol( - &self, - signer: &dyn Signer, - ui_amount: f64, - ) -> Result { - let inst = self.all_instructions_wrap_sol(&signer.pubkey(), ui_amount)?; - self.sign_and_send_instructions(&[signer], &inst) - } - - /// Transfers Wrapped SOL back to SOL by closing the associated Wrapped SOL account - pub fn unwrap_sol(&self, signer: &dyn Signer) -> Result { - let inst = self.all_instructions_unwrap_sol(&signer.pubkey())?; - self.sign_and_send_instructions(&[signer], &inst) - } - - /// Transfers tokens from the wallet to the destination - pub fn token_transfer( - &self, - signer: &dyn Signer, - token_name: &str, - destination_wallet: &Pubkey, - ui_amount: f64, - ) -> Result { - let inst = self.all_instructions_token_transfer( - &signer.pubkey(), - token_name, - destination_wallet, - ui_amount, - )?; - self.sign_and_send_instructions(&[signer], &inst) - } - - /// Updates token balance of the account, usefull after transfer SOL to WSOL account - pub fn sync_token_balance( - &self, - signer: &dyn Signer, - token_name: &str, - ) -> Result { - let inst = self.new_instruction_sync_token_balance(&signer.pubkey(), token_name)?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Returns the associated token account for the given user's main account or creates one - /// if it doesn't exist - pub fn get_or_create_token_account( - &self, - signer: &dyn Signer, - token_name: &str, - ) -> Result { - let wallet_address = signer.pubkey(); - let token_addr = self.get_associated_token_address(&wallet_address, token_name)?; - if !self.has_active_token_account(&wallet_address, token_name) { - let inst = self.new_instruction_create_token_account(&wallet_address, token_name)?; - self.sign_and_send_instructions(&[signer], &[inst])?; - } else { - self.check_ata_owner(&signer.pubkey(), token_name)?; - } - Ok(token_addr) - } - - /// Closes the associated token account for the given user's main account - pub fn close_token_account( - &self, - signer: &dyn Signer, - token_name: &str, - ) -> Result { - let inst = self.new_instruction_close_token_account(&signer.pubkey(), token_name)?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Returns the associated token account address for the given token name - pub fn get_associated_token_address( - &self, - wallet_address: &Pubkey, - token_name: &str, - ) -> Result { - let token = self.get_token(token_name)?; - Ok(get_associated_token_address(wallet_address, &token.mint)) - } - - /// Returns all tokens with active account in the wallet. - /// This function loads all tokens to the cache, slow on the first call. - pub fn get_wallet_tokens( - &self, - wallet_address: &Pubkey, - ) -> Result, FarmClientError> { - let accounts = self.rpc_client.get_token_accounts_by_owner( - wallet_address, - TokenAccountsFilter::ProgramId(spl_token::id()), - )?; - let mut res = Vec::::new(); - for acc in accounts.iter() { - let token_address = FarmClient::pubkey_from_str(&acc.pubkey)?; - - let data = self.rpc_client.get_account_data(&token_address)?; - let token_info = parse_token(data.as_slice(), Some(0))?; - if let TokenAccountType::Account(ui_account) = token_info { - let token_mint = FarmClient::pubkey_from_str(&ui_account.mint)?; - if let Ok(token) = self.get_token_with_mint(&token_mint) { - res.push(token.name.as_str().to_string()); - } else { - res.push("B58.".to_string() + acc.pubkey.clone().as_str()); - } - } - } - Ok(res) - } - - /// Returns UiTokenAccount struct data for the associated token account address - pub fn get_token_account_data( - &self, - wallet_address: &Pubkey, - token_name: &str, - ) -> Result { - let token_address = self.get_associated_token_address(wallet_address, token_name)?; - let data = self.rpc_client.get_account_data(&token_address)?; - let token = self.get_token(token_name)?; - let res = parse_token(data.as_slice(), Some(token.decimals))?; - if let TokenAccountType::Account(ui_account) = res { - Ok(ui_account) - } else { - Err(FarmClientError::ValueError(format!( - "No account data found for token {}", - token_name - ))) - } - } - - /// Returns UiMint struct data for the associated token account address - pub fn get_token_mint_data( - &self, - wallet_address: &Pubkey, - token_name: &str, - ) -> Result { - let token_address = self.get_associated_token_address(wallet_address, token_name)?; - let data = self.rpc_client.get_account_data(&token_address)?; - let res = parse_token(data.as_slice(), None)?; - if let TokenAccountType::Mint(ui_mint) = res { - Ok(ui_mint) - } else { - Err(FarmClientError::ValueError(format!( - "No mint data found for token {}", - token_name - ))) - } - } - - /// Returns native SOL balance - pub fn get_account_balance(&self, wallet_address: &Pubkey) -> Result { - Ok(self.tokens_to_ui_amount_with_decimals( - self.rpc_client.get_balance(wallet_address)?, - spl_token::native_mint::DECIMALS, - )) - } - - /// Returns token balance for the associated token account address - pub fn get_token_account_balance( - &self, - wallet_address: &Pubkey, - token_name: &str, - ) -> Result { - let token_name = if token_name == "WSOL" { - "SOL" - } else { - token_name - }; - let token_address = if token_name.len() > 4 && token_name.starts_with("B58.") { - FarmClient::pubkey_from_str(&token_name[4..])? - } else { - self.get_associated_token_address(wallet_address, token_name)? - }; - self.get_token_account_balance_with_address(&token_address) - } - - /// Returns token balance for the specified token account address - pub fn get_token_account_balance_with_address( - &self, - token_account: &Pubkey, - ) -> Result { - if let Ok(balance) = self.rpc_client.get_token_account_balance(token_account) { - if let Some(ui_amount) = balance.ui_amount { - Ok(ui_amount) - } else { - Err(FarmClientError::ParseError(format!( - "Failed to parse balance for token address {}", - token_account - ))) - } - } else { - Ok(0.0) - } - } - - /// Returns true if the associated token account exists and is initialized - pub fn has_active_token_account(&self, wallet_address: &Pubkey, token_name: &str) -> bool { - if let Ok(account) = self.get_token_account_data(wallet_address, token_name) { - account.state == UiAccountState::Initialized - } else { - false - } - } - - /// Returns the account address where Vault stats are stored for the user - pub fn get_vault_user_info_account( - &self, - wallet_address: &Pubkey, - vault_name: &str, - ) -> Result { - let vault = self.get_vault(vault_name)?; - Ok(Pubkey::find_program_address( - &[ - b"user_info_account", - wallet_address.as_ref(), - vault.name.as_bytes(), - ], - &vault.vault_program_id, - ) - .0) - } - - /// Returns number of decimal digits of the Vault token - pub fn get_vault_token_decimals(&self, vault_name: &str) -> Result { - let vault = self.get_vault(vault_name)?; - if let Some(vault_token) = self.get_token_by_ref_from_cache(&Some(vault.vault_token_ref))? { - Ok(vault_token.decimals) - } else { - Err(FarmClientError::RecordNotFound(format!( - "Vault token for {}", - vault_name - ))) - } - } - - /// Returns number of decimal digits for the Pool tokens - pub fn get_pool_tokens_decimals(&self, pool_name: &str) -> Result, FarmClientError> { - let pool = self.get_pool(pool_name)?; - let mut res = vec![]; - if let Some(token) = self.get_token_by_ref_from_cache(&pool.lp_token_ref)? { - res.push(token.decimals); - } - if let Some(token) = self.get_token_by_ref_from_cache(&pool.token_a_ref)? { - res.push(token.decimals); - } - if let Some(token) = self.get_token_by_ref_from_cache(&pool.token_b_ref)? { - res.push(token.decimals); - } - Ok(res) - } - - /// Returns multisig account address for the Vault - pub fn get_vault_multisig_account(&self, vault_name: &str) -> Result { - let vault = self.get_vault(vault_name)?; - Ok(Pubkey::find_program_address( - &[b"multisig", vault.name.as_bytes()], - &vault.vault_program_id, - ) - .0) - } - - /// Returns multisig address for the Vault or Main Router's multisig if former it not initialized - pub fn get_vault_active_multisig_account( - &self, - vault_name: &str, - ) -> Result { - let vault_multisig_account = self.get_vault_multisig_account(vault_name)?; - if let Ok(data) = self.rpc_client.get_account_data(&vault_multisig_account) { - let _ = Multisig::unpack(&data)?; - Ok(vault_multisig_account) - } else { - Ok(main_router_multisig::id()) - } - } - - /// Returns current admin signers for the Vault - pub fn get_vault_admins(&self, vault_name: &str) -> Result { - if let Ok(data) = self - .rpc_client - .get_account_data(&self.get_vault_active_multisig_account(vault_name)?) - { - Multisig::unpack(&data).map_err(|e| e.into()) - } else { - Ok(Multisig::default()) - } - } - - /// Initializes Vault multisig with a new set of signers - pub fn set_vault_admins( - &self, - admin_signer: &dyn Signer, - vault_name: &str, - admin_signers: &[Pubkey], - min_signatures: u8, - ) -> Result { - let inst = self.new_instruction_set_vault_admins( - &admin_signer.pubkey(), - vault_name, - admin_signers, - min_signatures, - )?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Removes Vault specific multisig, Main Router's will be used instead - pub fn remove_vault_multisig( - &self, - admin_signer: &dyn Signer, - vault_name: &str, - ) -> Result { - let inst = - self.new_instruction_remove_vault_multisig(&admin_signer.pubkey(), vault_name)?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Returns user stats for specific Vault - pub fn get_vault_user_info( - &self, - wallet_address: &Pubkey, - vault_name: &str, - ) -> Result { - let user_info_account = self.get_vault_user_info_account(wallet_address, vault_name)?; - let data = self.rpc_client.get_account_data(&user_info_account)?; - if !RefDB::is_initialized(data.as_slice()) { - return Err(ProgramError::UninitializedAccount.into()); - } - let mut user_info = VaultUserInfo::default(); - let rec_vec = RefDB::read_all(data.as_slice())?; - for rec in rec_vec.iter() { - if let refdb::Reference::U64 { data } = rec.reference { - match rec.name.as_str() { - "LastDeposit" => user_info.last_deposit_time = data as UnixTimestamp, - "LastWithdrawal" => user_info.last_withdrawal_time = data as UnixTimestamp, - "TokenAAdded" => user_info.tokens_a_added = data, - "TokenBAdded" => user_info.tokens_b_added = data, - "TokenARemoved" => user_info.tokens_a_removed = data, - "TokenBRemoved" => user_info.tokens_b_removed = data, - "LpTokensDebt" => user_info.lp_tokens_debt = data, - _ => {} - } - } - } - - Ok(user_info) - } - - /// Returns Vault stats - pub fn get_vault_info(&self, vault_name: &str) -> Result { - let vault = self.get_vault(vault_name)?; - let data = self.rpc_client.get_account_data(&vault.info_account)?; - if !RefDB::is_initialized(data.as_slice()) { - return Err(ProgramError::UninitializedAccount.into()); - } - let mut vault_info = VaultInfo::default(); - let rec_vec = RefDB::read_all(data.as_slice())?; - for rec in rec_vec.iter() { - if let refdb::Reference::U64 { data } = rec.reference { - match rec.name.as_str() { - "CrankTime" => vault_info.crank_time = data as UnixTimestamp, - "CrankStep" => vault_info.crank_step = data, - "TokenAAdded" => vault_info.tokens_a_added = data, - "TokenBAdded" => vault_info.tokens_b_added = data, - "TokenARemoved" => vault_info.tokens_a_removed = data, - "TokenBRemoved" => vault_info.tokens_b_removed = data, - "TokenARewards" => vault_info.tokens_a_rewards = data, - "TokenBRewards" => vault_info.tokens_b_rewards = data, - "DepositAllowed" => vault_info.deposit_allowed = data > 0, - "WithdrawalAllowed" => vault_info.withdrawal_allowed = data > 0, - "MinCrankInterval" => vault_info.min_crank_interval = data, - "Fee" => vault_info.fee = f64::from_bits(data), - "ExternalFee" => vault_info.external_fee = f64::from_bits(data), - _ => {} - } - } - } - vault_info.stake_balance = self.get_vault_stake_balance(vault_name)?; - - Ok(vault_info) - } - - /// Returns Vault stats for all Vaults - pub fn get_all_vault_infos(&self) -> Result, FarmClientError> { - let mut vault_infos = vec![]; - let vaults = self.get_vaults()?; - for vault in vaults.keys() { - vault_infos.push(self.get_vault_info(vault)?); - } - - Ok(vault_infos) - } - - /// Returns User's stacked balance - pub fn get_user_stake_balance( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ) -> Result { - let farm = self.get_farm(farm_name)?; - match farm.route { - FarmRoute::Raydium { .. } => { - let stake_account = self.get_stake_account(wallet_address, farm_name)?; - if let Ok(stake_data) = self.rpc_client.get_account_data(&stake_account) { - if !stake_data.is_empty() { - let deposit_balance = if farm.version >= 4 { - RaydiumUserStakeInfoV4::unpack(stake_data.as_slice())?.deposit_balance - } else { - RaydiumUserStakeInfo::unpack(stake_data.as_slice())?.deposit_balance - }; - let farm_token = self.get_token_by_ref(&farm.lp_token_ref.unwrap())?; - Ok(self.tokens_to_ui_amount_with_decimals( - deposit_balance, - farm_token.decimals, - )) - } else { - Ok(0.0) - } - } else { - Ok(0.0) - } - } - FarmRoute::Saber { .. } => { - let stake_account = self.get_stake_account(wallet_address, farm_name)?; - if let Ok(stake_data) = self.rpc_client.get_account_data(&stake_account) { - if !stake_data.is_empty() { - let deposit_balance = Miner::unpack(stake_data.as_slice())?.balance; - let farm_token = self.get_token_by_ref(&farm.lp_token_ref.unwrap())?; - Ok(self.tokens_to_ui_amount_with_decimals( - deposit_balance, - farm_token.decimals, - )) - } else { - Ok(0.0) - } - } else { - Ok(0.0) - } - } - FarmRoute::Orca { farm_token_ref, .. } => { - if let Ok(farm_token) = self.get_token_by_ref(&farm_token_ref) { - self.get_token_account_balance(wallet_address, &farm_token.name) - } else { - Ok(0.0) - } - } - } - } - - /// Returns Vault's stacked balance - pub fn get_vault_stake_balance(&self, vault_name: &str) -> Result { - let vault = self.get_vault(vault_name)?; - match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { - farm_ref, - vault_stake_info, - .. - } => { - let farm = self.get_farm_by_ref(&farm_ref)?; - let farm_token = self.get_token_by_ref(&farm.lp_token_ref.unwrap())?; - - let balance = - if let Ok(stake_data) = self.rpc_client.get_account_data(&vault_stake_info) { - if !stake_data.is_empty() { - match farm.route { - FarmRoute::Raydium { .. } => { - if farm.version >= 4 { - RaydiumUserStakeInfoV4::unpack(stake_data.as_slice())? - .deposit_balance - } else { - RaydiumUserStakeInfo::unpack(stake_data.as_slice())? - .deposit_balance - } - } - FarmRoute::Saber { .. } => { - Miner::unpack(stake_data.as_slice())?.balance - } - FarmRoute::Orca { .. } => { - OrcaUserStakeInfo::unpack(stake_data.as_slice())? - .base_tokens_converted - } - } - } else { - 0 - } - } else { - 0 - }; - Ok(self.tokens_to_ui_amount_with_decimals(balance, farm_token.decimals)) - } - _ => Ok(0.0), - } - } - - /// Initializes a new User for the Vault - pub fn user_init_vault( - &self, - signer: &dyn Signer, - vault_name: &str, - ) -> Result { - // create and send the instruction - let inst = self.new_instruction_user_init_vault(&signer.pubkey(), vault_name)?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Adds liquidity to the Vault - pub fn add_liquidity_vault( - &self, - signer: &dyn Signer, - vault_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - ) -> Result { - let inst = self.all_instructions_add_liquidity_vault( - &signer.pubkey(), - vault_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - )?; - Ok(*self - .sign_and_send_instructions_in_batches(&[signer], &inst)? - .last() - .unwrap()) - } - - /// Adds locked liquidity to the Vault. - /// Useful if add liquidity operation partially failed. - pub fn add_locked_liquidity_vault( - &self, - signer: &dyn Signer, - vault_name: &str, - ui_amount: f64, - ) -> Result { - let inst = self.all_instructions_add_locked_liquidity_vault( - &signer.pubkey(), - vault_name, - ui_amount, - )?; - self.sign_and_send_instructions(&[signer], &inst) - } - - /// Removes liquidity from the Vault - pub fn remove_liquidity_vault( - &self, - signer: &dyn Signer, - vault_name: &str, - ui_amount: f64, - ) -> Result { - let inst = - self.all_instructions_remove_liquidity_vault(&signer.pubkey(), vault_name, ui_amount)?; - Ok(*self - .sign_and_send_instructions_in_batches(&[signer], &inst)? - .last() - .unwrap()) - } - - /// Removes unlocked liquidity from the Vault. - /// Useful if remove liquidity operation failed after unlock step. - pub fn remove_unlocked_liquidity_vault( - &self, - signer: &dyn Signer, - vault_name: &str, - ui_amount: f64, - ) -> Result { - let inst = self.all_instructions_remove_unlocked_liquidity_vault( - &signer.pubkey(), - vault_name, - ui_amount, - )?; - self.sign_and_send_instructions(&[signer], &inst) - } - - /// Adds liquidity to the Pool. - /// If one of token amounts is set to zero it will be determined based on the pool - /// price and the specified amount of another token. - pub fn add_liquidity_pool( - &self, - signer: &dyn Signer, - pool_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - ) -> Result { - let inst = self.all_instructions_add_liquidity_pool( - &signer.pubkey(), - pool_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - )?; - self.sign_and_send_instructions(&[signer], &inst) - } - - /// Removes liquidity from the Pool. - /// If the amount is set to zero entire balance will be removed from the pool. - pub fn remove_liquidity_pool( - &self, - signer: &dyn Signer, - pool_name: &str, - ui_amount: f64, - ) -> Result { - let inst = - self.all_instructions_remove_liquidity_pool(&signer.pubkey(), pool_name, ui_amount)?; - self.sign_and_send_instructions(&[signer], &inst) - } - - /// Swaps tokens - pub fn swap( - &self, - signer: &dyn Signer, - protocol: Protocol, - from_token: &str, - to_token: &str, - ui_amount_in: f64, - min_ui_amount_out: f64, - ) -> Result { - let inst = self.all_instructions_swap( - &signer.pubkey(), - protocol, - from_token, - to_token, - ui_amount_in, - min_ui_amount_out, - )?; - self.sign_and_send_instructions(&[signer], &inst) - } - - /// Initializes a new User for the Farm - pub fn user_init( - &self, - signer: &dyn Signer, - farm_name: &str, - ) -> Result { - // create and send the instruction - let inst = self.new_instruction_user_init(&signer.pubkey(), farm_name)?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Stakes tokens to the Farm. - /// If the amount is set to zero entire LP tokens balance will be staked. - pub fn stake( - &self, - signer: &dyn Signer, - farm_name: &str, - ui_amount: f64, - ) -> Result { - let inst = self.all_instructions_stake(&signer.pubkey(), farm_name, ui_amount)?; - self.sign_and_send_instructions(&[signer], &inst) - } - - /// Unstakes tokens from the Farm. - /// If the amount is set to zero entire balance will be unstaked. - pub fn unstake( - &self, - signer: &dyn Signer, - farm_name: &str, - ui_amount: f64, - ) -> Result { - let inst = self.all_instructions_unstake(&signer.pubkey(), farm_name, ui_amount)?; - self.sign_and_send_instructions(&[signer], &inst) - } - - /// Harvests rewards from the Farm - pub fn harvest( - &self, - signer: &dyn Signer, - farm_name: &str, - ) -> Result { - let inst = self.all_instructions_harvest(&signer.pubkey(), farm_name)?; - self.sign_and_send_instructions(&[signer], &inst) - } - - /// Clears cache records to force re-pull from blockchain - pub fn reset_cache(&self) { - self.tokens.borrow_mut().reset(); - self.pools.borrow_mut().reset(); - self.vaults.borrow_mut().reset(); - self.funds.borrow_mut().reset(); - self.token_refs.borrow_mut().reset(); - self.pool_refs.borrow_mut().reset(); - self.vault_refs.borrow_mut().reset(); - self.fund_refs.borrow_mut().reset(); - self.official_ids.borrow_mut().reset(); - self.latest_pools.borrow_mut().clear(); - self.latest_farms.borrow_mut().clear(); - self.latest_vaults.borrow_mut().clear(); - } - - /// Reads records from the RefDB PDA into a Pubkey map - pub fn get_refdb_pubkey_map( - &self, - refdb_name: &str, - ) -> Result<(Header, PubkeyMap), FarmClientError> { - let refdb_address = refdb::find_refdb_pda(refdb_name).0; - let data = self.rpc_client.get_account_data(&refdb_address)?; - if !RefDB::is_initialized(data.as_slice()) { - return Err(ProgramError::UninitializedAccount.into()); - } - let mut map = PubkeyMap::default(); - let rec_vec = RefDB::read_all(data.as_slice())?; - for rec in rec_vec.iter() { - if let refdb::Reference::Pubkey { data } = rec.reference { - map.insert(rec.name.to_string(), data); - } - } - Ok((RefDB::get_storage_header(data.as_slice())?, map)) - } - - /// Returns raw RefDB data, can be further used with refdb::RefDB - pub fn get_refdb_data(&self, refdb_name: &str) -> Result, FarmClientError> { - let refdb_address = refdb::find_refdb_pda(refdb_name).0; - self.rpc_client - .get_account_data(&refdb_address) - .map_err(Into::into) - } - - /// Returns the index of the record with the specified name - pub fn get_refdb_index( - &self, - refdb_name: &str, - object_name: &str, - ) -> Result, FarmClientError> { - RefDB::find_index( - self.get_refdb_data(refdb_name)?.as_slice(), - &str_to_as64(object_name)?, - ) - .map_err(Into::into) - } - - /// Returns the index of the first empty record at the back of the RefDB storage, - /// i.e. there will be no active records after the index - pub fn get_refdb_last_index(&self, refdb_name: &str) -> Result { - RefDB::find_last_index(self.get_refdb_data(refdb_name)?.as_slice()).map_err(Into::into) - } - - /// Returns the index of the next available record to write to in the RefDB storage - pub fn get_refdb_next_index(&self, refdb_name: &str) -> Result { - RefDB::find_next_index(self.get_refdb_data(refdb_name)?.as_slice()).map_err(Into::into) - } - - /// Checks if RefDB is initialized - pub fn is_refdb_initialized(&self, refdb_name: &str) -> Result { - let refdb_address = refdb::find_refdb_pda(refdb_name).0; - if let Ok(data) = self.rpc_client.get_account_data(&refdb_address) { - Ok(RefDB::is_initialized(data.as_slice())) - } else { - Ok(false) - } - } - - /// Initializes a new RefDB storage - pub fn initialize_refdb( - &self, - admin_signer: &dyn Signer, - refdb_name: &str, - reference_type: refdb::ReferenceType, - max_records: usize, - init_account: bool, - ) -> Result { - if init_account && !refdb::REFDB_ONCHAIN_INIT { - let refdb_address = refdb::find_refdb_pda(refdb_name).0; - if let Ok(refdb_account) = self.rpc_client.get_account(&refdb_address) { - if refdb_account.owner != main_router::id() { - return Err(FarmClientError::ValueError(format!( - "RefDB account owner mismatch {}", - refdb_address - ))); - } - } else { - if admin_signer.pubkey() != main_router_admin::id() { - return Err(FarmClientError::ValueError( - "RefDB init must be initially called with main_router_admin::id() if on-chain init is disabled" - .to_string(), - )); - } - self.create_system_account_with_seed( - admin_signer, - &admin_signer.pubkey(), - refdb_name, - 0, - refdb::StorageType::get_storage_size_for_records(reference_type, max_records), - &main_router::id(), - )?; - } - } - - let inst = self.new_instruction_refdb_init( - &admin_signer.pubkey(), - refdb_name, - reference_type, - max_records as u32, - init_account, - )?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Initializes Main Router multisig with a new set of signers - pub fn set_admins( - &self, - admin_signer: &dyn Signer, - admin_signers: &[Pubkey], - min_signatures: u8, - ) -> Result { - let inst = - self.new_instruction_set_admins(&admin_signer.pubkey(), admin_signers, min_signatures)?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Returns current admin signers for the Main Router - pub fn get_admins(&self) -> Result { - if let Ok(data) = self - .rpc_client - .get_account_data(&main_router_multisig::id()) - { - Multisig::unpack(&data).map_err(|e| e.into()) - } else { - Ok(Multisig::default()) - } - } - - /// Removes the RefDB storage - pub fn drop_refdb( - &self, - admin_signer: &dyn Signer, - refdb_name: &str, - close_account: bool, - ) -> Result { - let inst = - self.new_instruction_refdb_drop(&admin_signer.pubkey(), refdb_name, close_account)?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Removes referenced metadata from chain - pub fn remove_reference( - &self, - admin_signer: &dyn Signer, - storage_type: refdb::StorageType, - object_name: &str, - ) -> Result { - let inst = self.new_instruction_remove_reference( - &admin_signer.pubkey(), - storage_type, - object_name, - )?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Records the Program ID metadata on-chain - pub fn add_program_id( - &self, - admin_signer: &dyn Signer, - name: &str, - program_id: &Pubkey, - program_id_type: ProgramIDType, - refdb_index: Option, - ) -> Result { - let inst = self.new_instruction_add_program_id( - &admin_signer.pubkey(), - name, - program_id, - program_id_type, - refdb_index, - )?; - let res = self.sign_and_send_instructions(&[admin_signer], &[inst]); - if res.is_ok() { - self.official_ids - .borrow_mut() - .data - .insert(name.to_string(), *program_id); - } - res - } - - /// Removes the Program ID metadata from chain - pub fn remove_program_id( - &self, - admin_signer: &dyn Signer, - name: &str, - ) -> Result { - let inst = self.new_instruction_remove_program_id(&admin_signer.pubkey(), name)?; - let res = self.sign_and_send_instructions(&[admin_signer], &[inst]); - if res.is_ok() { - self.official_ids.borrow_mut().data.remove(name); - } - res - } - - /// Records the Fund metadata - pub fn add_fund( - &self, - admin_signer: &dyn Signer, - fund: Fund, - ) -> Result { - let inst = self.new_instruction_add_fund(&admin_signer.pubkey(), fund)?; - let res = self.sign_and_send_instructions(&[admin_signer], &[inst]); - if res.is_ok() { - self.funds - .borrow_mut() - .data - .insert(fund.name.to_string(), fund); - self.fund_refs.borrow_mut().data.insert( - fund.name.to_string(), - refdb::find_target_pda(refdb::StorageType::Fund, &fund.name).0, - ); - } - res - } - - /// Removes the Fund's on-chain metadata - pub fn remove_fund( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - ) -> Result { - let inst = self.new_instruction_remove_fund(&admin_signer.pubkey(), fund_name)?; - let res = self.sign_and_send_instructions(&[admin_signer], &[inst]); - if res.is_ok() { - self.funds.borrow_mut().data.remove(fund_name); - self.fund_refs.borrow_mut().data.remove(fund_name); - } - res - } - - /// Records the Vault metadata on-chain - pub fn add_vault( - &self, - admin_signer: &dyn Signer, - vault: Vault, - ) -> Result { - let inst = self.new_instruction_add_vault(&admin_signer.pubkey(), vault)?; - let res = self.sign_and_send_instructions(&[admin_signer], &[inst]); - if res.is_ok() { - self.vaults - .borrow_mut() - .data - .insert(vault.name.to_string(), vault); - self.vault_refs.borrow_mut().data.insert( - vault.name.to_string(), - refdb::find_target_pda(refdb::StorageType::Vault, &vault.name).0, - ); - FarmClient::reinsert_latest_versions( - &self.vault_refs.borrow().data, - &mut self.latest_vaults.borrow_mut(), - ); - } - res - } - - /// Removes the Vault's on-chain metadata - pub fn remove_vault( - &self, - admin_signer: &dyn Signer, - vault_name: &str, - ) -> Result { - let inst = self.new_instruction_remove_vault(&admin_signer.pubkey(), vault_name)?; - let res = self.sign_and_send_instructions(&[admin_signer], &[inst]); - if res.is_ok() { - self.vaults.borrow_mut().data.remove(vault_name); - self.vault_refs.borrow_mut().data.remove(vault_name); - FarmClient::reinsert_latest_versions( - &self.vault_refs.borrow().data, - &mut self.latest_vaults.borrow_mut(), - ); - } - res - } - - /// Records the Pool metadata on-chain - pub fn add_pool( - &self, - admin_signer: &dyn Signer, - pool: Pool, - ) -> Result { - let inst = self.new_instruction_add_pool(&admin_signer.pubkey(), pool)?; - let res = self.sign_and_send_instructions(&[admin_signer], &[inst]); - if res.is_ok() { - self.pools - .borrow_mut() - .data - .insert(pool.name.to_string(), pool); - self.pool_refs.borrow_mut().data.insert( - pool.name.to_string(), - refdb::find_target_pda(refdb::StorageType::Pool, &pool.name).0, - ); - FarmClient::reinsert_latest_versions( - &self.pool_refs.borrow().data, - &mut self.latest_pools.borrow_mut(), - ); - } - res - } - - /// Removes the Pool's on-chain metadata - pub fn remove_pool( - &self, - admin_signer: &dyn Signer, - pool_name: &str, - ) -> Result { - let inst = self.new_instruction_remove_pool(&admin_signer.pubkey(), pool_name)?; - let res = self.sign_and_send_instructions(&[admin_signer], &[inst]); - if res.is_ok() { - self.pools.borrow_mut().data.remove(pool_name); - self.pool_refs.borrow_mut().data.remove(pool_name); - FarmClient::reinsert_latest_versions( - &self.pool_refs.borrow().data, - &mut self.latest_pools.borrow_mut(), - ); - } - res - } - - /// Records the Farm metadata on-chain - pub fn add_farm( - &self, - admin_signer: &dyn Signer, - farm: Farm, - ) -> Result { - let inst = self.new_instruction_add_farm(&admin_signer.pubkey(), farm)?; - let res = self.sign_and_send_instructions(&[admin_signer], &[inst]); - if res.is_ok() { - self.farms - .borrow_mut() - .data - .insert(farm.name.to_string(), farm); - self.farm_refs.borrow_mut().data.insert( - farm.name.to_string(), - refdb::find_target_pda(refdb::StorageType::Farm, &farm.name).0, - ); - FarmClient::reinsert_latest_versions( - &self.farm_refs.borrow().data, - &mut self.latest_farms.borrow_mut(), - ); - } - res - } - - /// Removes the Farm's on-chain metadata - pub fn remove_farm( - &self, - admin_signer: &dyn Signer, - farm_name: &str, - ) -> Result { - let inst = self.new_instruction_remove_farm(&admin_signer.pubkey(), farm_name)?; - let res = self.sign_and_send_instructions(&[admin_signer], &[inst]); - if res.is_ok() { - self.farms.borrow_mut().data.remove(farm_name); - self.farm_refs.borrow_mut().data.remove(farm_name); - FarmClient::reinsert_latest_versions( - &self.farm_refs.borrow().data, - &mut self.latest_farms.borrow_mut(), - ); - } - res - } - - /// Records the Token metadata on-chain - pub fn add_token( - &self, - admin_signer: &dyn Signer, - token: Token, - ) -> Result { - let inst = self.new_instruction_add_token(&admin_signer.pubkey(), token)?; - let res = self.sign_and_send_instructions(&[admin_signer], &[inst]); - if res.is_ok() { - self.tokens - .borrow_mut() - .data - .insert(token.name.to_string(), token); - self.token_refs.borrow_mut().data.insert( - token.name.to_string(), - refdb::find_target_pda(refdb::StorageType::Token, &token.name).0, - ); - } - res - } - - /// Removes the Token's on-chain metadata - pub fn remove_token( - &self, - admin_signer: &dyn Signer, - token_name: &str, - ) -> Result { - let inst = self.new_instruction_remove_token(&admin_signer.pubkey(), token_name)?; - let res = self.sign_and_send_instructions(&[admin_signer], &[inst]); - if res.is_ok() { - self.tokens.borrow_mut().data.remove(token_name); - self.token_refs.borrow_mut().data.remove(token_name); - } - res - } - - /// Initializes a Vault - pub fn init_vault( - &self, - admin_signer: &dyn Signer, - vault_name: &str, - step: u64, - ) -> Result { - let inst = self.new_instruction_init_vault(&admin_signer.pubkey(), vault_name, step)?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Shutdowns a Vault - pub fn shutdown_vault( - &self, - admin_signer: &dyn Signer, - vault_name: &str, - ) -> Result { - let inst = self.new_instruction_shutdown_vault(&admin_signer.pubkey(), vault_name)?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Cranks single Vault - pub fn crank_vault( - &self, - signer: &dyn Signer, - vault_name: &str, - step: u64, - ) -> Result { - let inst = self.new_instruction_crank_vault(&signer.pubkey(), vault_name, step)?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Cranks all Vaults - pub fn crank_vaults(&self, signer: &dyn Signer, step: u64) -> Result { - let vaults = self.get_vaults()?; - for vault_name in vaults.keys() { - let _ = self.crank_vault(signer, vault_name, step)?; - } - Ok(vaults.len()) - } - - /// Withdraw collected fees from the Vault - pub fn withdraw_fees_vault( - &self, - signer: &dyn Signer, - vault_name: &str, - fee_token: TokenSelector, - ui_amount: f64, - receiver: &Pubkey, - ) -> Result { - let inst = self.new_instruction_withdraw_fees_vault( - &signer.pubkey(), - vault_name, - fee_token, - ui_amount, - receiver, - )?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Sets the Vault's min crank interval - pub fn set_min_crank_interval_vault( - &self, - admin_signer: &dyn Signer, - vault_name: &str, - min_crank_interval: u32, - ) -> Result { - let inst = self.new_instruction_set_min_crank_interval_vault( - &admin_signer.pubkey(), - vault_name, - min_crank_interval, - )?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Sets the Vault's fee - pub fn set_fee_vault( - &self, - admin_signer: &dyn Signer, - vault_name: &str, - fee_percent: f32, - ) -> Result { - let inst = - self.new_instruction_set_fee_vault(&admin_signer.pubkey(), vault_name, fee_percent)?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Sets the Vault's external fee - pub fn set_external_fee_vault( - &self, - admin_signer: &dyn Signer, - vault_name: &str, - external_fee_percent: f32, - ) -> Result { - let inst = self.new_instruction_set_external_fee_vault( - &admin_signer.pubkey(), - vault_name, - external_fee_percent, - )?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Disables deposits to the Vault - pub fn disable_deposits_vault( - &self, - admin_signer: &dyn Signer, - vault_name: &str, - ) -> Result { - let inst = - self.new_instruction_disable_deposits_vault(&admin_signer.pubkey(), vault_name)?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Enables deposits to the Vault - pub fn enable_deposits_vault( - &self, - admin_signer: &dyn Signer, - vault_name: &str, - ) -> Result { - let inst = - self.new_instruction_enable_deposits_vault(&admin_signer.pubkey(), vault_name)?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Disables withdrawal from the Vault - pub fn disable_withdrawals_vault( - &self, - admin_signer: &dyn Signer, - vault_name: &str, - ) -> Result { - let inst = - self.new_instruction_disable_withdrawals_vault(&admin_signer.pubkey(), vault_name)?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Enables withdrawals from the Vault - pub fn enable_withdrawals_vault( - &self, - admin_signer: &dyn Signer, - vault_name: &str, - ) -> Result { - let inst = - self.new_instruction_enable_withdrawals_vault(&admin_signer.pubkey(), vault_name)?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Deposits governing tokens to the farms realm - pub fn governance_tokens_deposit( - &self, - signer: &dyn Signer, - ui_amount: f64, - ) -> Result { - let inst = self.new_instruction_governance_tokens_deposit(&signer.pubkey(), ui_amount)?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Withdraws governing tokens from the farms realm - pub fn governance_tokens_withdraw( - &self, - signer: &dyn Signer, - ) -> Result { - let inst = self.new_instruction_governance_tokens_withdraw(&signer.pubkey())?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Creates a new governance proposal - pub fn governance_proposal_new( - &self, - signer: &dyn Signer, - governance_name: &str, - proposal_name: &str, - proposal_link: &str, - proposal_index: u32, - ) -> Result { - let inst = self.new_instruction_governance_proposal_new( - &signer.pubkey(), - governance_name, - proposal_name, - proposal_link, - proposal_index, - )?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Cancels governance proposal - pub fn governance_proposal_cancel( - &self, - signer: &dyn Signer, - governance_name: &str, - proposal_index: u32, - ) -> Result { - let inst = self.new_instruction_governance_proposal_cancel( - &signer.pubkey(), - governance_name, - proposal_index, - )?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Adds a signatory to governance proposal - pub fn governance_signatory_add( - &self, - signer: &dyn Signer, - governance_name: &str, - proposal_index: u32, - signatory: &Pubkey, - ) -> Result { - let inst = self.new_instruction_governance_signatory_add( - &signer.pubkey(), - governance_name, - proposal_index, - signatory, - )?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Removes the signatory from governance proposal - pub fn governance_signatory_remove( - &self, - signer: &dyn Signer, - governance_name: &str, - proposal_index: u32, - signatory: &Pubkey, - ) -> Result { - let inst = self.new_instruction_governance_signatory_remove( - &signer.pubkey(), - governance_name, - proposal_index, - signatory, - )?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Signs off governance proposal - pub fn governance_sign_off( - &self, - signer: &dyn Signer, - governance_name: &str, - proposal_index: u32, - ) -> Result { - let inst = self.new_instruction_governance_sign_off( - &signer.pubkey(), - governance_name, - proposal_index, - )?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Casts a vote on governance proposal - pub fn governance_vote_cast( - &self, - signer: &dyn Signer, - governance_name: &str, - proposal_index: u32, - vote: u8, - ) -> Result { - let inst = self.new_instruction_governance_vote_cast( - &signer.pubkey(), - governance_name, - proposal_index, - vote, - )?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Removes the vote from governance proposal - pub fn governance_vote_relinquish( - &self, - signer: &dyn Signer, - governance_name: &str, - proposal_index: u32, - ) -> Result { - let inst = self.new_instruction_governance_vote_relinquish( - &signer.pubkey(), - governance_name, - proposal_index, - )?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Finalizes the vote on governance proposal - pub fn governance_vote_finalize( - &self, - signer: &dyn Signer, - governance_name: &str, - proposal_index: u32, - ) -> Result { - let inst = self.new_instruction_governance_vote_finalize( - &signer.pubkey(), - governance_name, - proposal_index, - )?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Adds a new instruction to governance proposal - pub fn governance_instruction_insert( - &self, - signer: &dyn Signer, - governance_name: &str, - proposal_index: u32, - instruction_index: u16, - instruction: &Instruction, - ) -> Result { - let inst = self.new_instruction_governance_instruction_insert( - &signer.pubkey(), - governance_name, - proposal_index, - instruction_index, - instruction, - )?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Removes the instruction from governance proposal - pub fn governance_instruction_remove( - &self, - signer: &dyn Signer, - governance_name: &str, - proposal_index: u32, - instruction_index: u16, - ) -> Result { - let inst = self.new_instruction_governance_instruction_remove( - &signer.pubkey(), - governance_name, - proposal_index, - instruction_index, - )?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Executes the instruction in governance proposal - pub fn governance_instruction_execute( - &self, - signer: &dyn Signer, - governance_name: &str, - proposal_index: u32, - instruction_index: u16, - ) -> Result { - let inst = self.new_instruction_governance_instruction_execute( - &signer.pubkey(), - governance_name, - proposal_index, - instruction_index, - )?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Marks the instruction in governance proposal as failed - pub fn governance_instruction_flag_error( - &self, - signer: &dyn Signer, - governance_name: &str, - proposal_index: u32, - instruction_index: u16, - ) -> Result { - let inst = self.new_instruction_governance_instruction_flag_error( - &signer.pubkey(), - governance_name, - proposal_index, - instruction_index, - )?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Returns current governance config - pub fn governance_get_config( - &self, - governance_name: &str, - ) -> Result { - let governance = self.governance_get_address(governance_name)?; - let governance_data = self.rpc_client.get_account_data(&governance)?; - - let account: Governance = try_from_slice_unchecked(&governance_data) - .map_err(|e| FarmClientError::IOError(e.to_string()))?; - if account.account_type == GovernanceAccountType::AccountGovernance - || account.account_type == GovernanceAccountType::ProgramGovernance - || account.account_type == GovernanceAccountType::MintGovernance - || account.account_type == GovernanceAccountType::TokenGovernance - { - Ok(account.config) - } else { - Err(ProgramError::UninitializedAccount.into()) - } - } - - // Returns account address of the governance - pub fn governance_get_address(&self, governance_name: &str) -> Result { - let dao_program = self.get_program_id(DAO_PROGRAM_NAME)?; - let realm_address = get_realm_address(&dao_program, DAO_PROGRAM_NAME); - match governance_name { - DAO_MINT_NAME => { - let dao_token = self.get_token(DAO_TOKEN_NAME)?; - Ok(get_mint_governance_address( - &dao_program, - &realm_address, - &dao_token.mint, - )) - } - DAO_CUSTODY_NAME => { - let governed_account = - Pubkey::find_program_address(&[DAO_CUSTODY_NAME.as_bytes()], &dao_program).0; - Ok(get_account_governance_address( - &dao_program, - &realm_address, - &governed_account, - )) - } - _ => { - let governed_program = self.get_program_id(governance_name)?; - Ok(get_program_governance_address( - &dao_program, - &realm_address, - &governed_program, - )) - } - } - } - - // Returns stored instruction in the proposal - pub fn governance_get_instruction( - &self, - governance_name: &str, - proposal_index: u32, - instruction_index: u16, - ) -> Result { - let dao_program = self.get_program_id(DAO_PROGRAM_NAME)?; - let dao_token = self.get_token(DAO_TOKEN_NAME)?; - let governance = self.governance_get_address(governance_name)?; - let proposal_address = get_proposal_address( - &dao_program, - &governance, - &dao_token.mint, - &proposal_index.to_le_bytes(), - ); - - let instruction_address = get_proposal_instruction_address( - &dao_program, - &proposal_address, - &0u16.to_le_bytes(), - &instruction_index.to_le_bytes(), - ); - - let data = self.rpc_client.get_account_data(&instruction_address)?; - let ins_data: InstructionData = - try_from_slice_unchecked::(data.as_slice()) - .map_err(|e| FarmClientError::IOError(e.to_string()))? - .instruction; - Ok((&ins_data).into()) - } - - /// Returns the state of the proposal - pub fn governance_get_proposal_state( - &self, - governance_name: &str, - proposal_index: u32, - ) -> Result { - let dao_program = self.get_program_id(DAO_PROGRAM_NAME)?; - let dao_token = self.get_token(DAO_TOKEN_NAME)?; - let governance = self.governance_get_address(governance_name)?; - let proposal_address = get_proposal_address( - &dao_program, - &governance, - &dao_token.mint, - &proposal_index.to_le_bytes(), - ); - - let proposal_data = self.rpc_client.get_account_data(&proposal_address)?; - let proposal_state: ProposalV2 = try_from_slice_unchecked(&proposal_data) - .map_err(|e| FarmClientError::IOError(e.to_string()))?; - - Ok(proposal_state) - } - - /// Returns multisig account address for the Fund - pub fn get_fund_multisig_account(&self, fund_name: &str) -> Result { - let fund = self.get_fund(fund_name)?; - Ok(Pubkey::find_program_address( - &[b"multisig", fund.name.as_bytes()], - &fund.fund_program_id, - ) - .0) - } - - /// Returns multisig address for the Fund or Main Router's multisig if former it not initialized - pub fn get_fund_active_multisig_account( - &self, - fund_name: &str, - ) -> Result { - let fund_multisig_account = self.get_fund_multisig_account(fund_name)?; - if let Ok(data) = self.rpc_client.get_account_data(&fund_multisig_account) { - let _ = Multisig::unpack(&data)?; - Ok(fund_multisig_account) - } else { - Ok(main_router_multisig::id()) - } - } - - /// Returns current admin signers for the Fund - pub fn get_fund_admins(&self, fund_name: &str) -> Result { - if let Ok(data) = self - .rpc_client - .get_account_data(&self.get_fund_active_multisig_account(fund_name)?) - { - Multisig::unpack(&data).map_err(|e| e.into()) - } else { - Ok(Multisig::default()) - } - } - - /// Initializes Fund multisig with a new set of signers - pub fn set_fund_admins( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - admin_signers: &[Pubkey], - min_signatures: u8, - ) -> Result { - let inst = self.new_instruction_set_fund_admins( - &admin_signer.pubkey(), - fund_name, - admin_signers, - min_signatures, - )?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Removes Fund specific multisig, Main Router's will be used instead - pub fn remove_fund_multisig( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - ) -> Result { - let inst = self.new_instruction_remove_fund_multisig(&admin_signer.pubkey(), fund_name)?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Returns the account address where Fund stats are stored for the user - pub fn get_fund_user_info_account( - &self, - wallet_address: &Pubkey, - fund_name: &str, - ) -> Result { - let fund = self.get_fund(fund_name)?; - Ok(Pubkey::find_program_address( - &[ - b"user_info_account", - wallet_address.as_ref(), - fund.name.as_bytes(), - ], - &fund.fund_program_id, - ) - .0) - } - - /// Returns user stats for specific Fund - pub fn get_fund_user_info( - &self, - wallet_address: &Pubkey, - fund_name: &str, - ) -> Result { - let user_info_account = self.get_fund_user_info_account(wallet_address, fund_name)?; - let data = self.rpc_client.get_account_data(&user_info_account)?; - if !RefDB::is_initialized(data.as_slice()) { - return Err(ProgramError::UninitializedAccount.into()); - } - let mut fund_user_info = FundUserInfo::default(); - let rec_vec = RefDB::read_all(data.as_slice())?; - for rec in rec_vec.iter() { - if let refdb::Reference::U64 { data } = rec.reference { - if rec.name.as_str() == "VirtualTokensBalance" { - fund_user_info.virtual_tokens_balance = data - } - } - } - - Ok(fund_user_info) - } - - /// Returns user stats for all Funds - pub fn get_all_fund_user_infos( - &self, - wallet_address: &Pubkey, - ) -> Result, FarmClientError> { - let mut user_infos = vec![]; - let funds = self.get_funds()?; - for fund in funds.keys() { - user_infos.push(self.get_fund_user_info(wallet_address, fund)?); - } - - Ok(user_infos) - } - - /// Returns the account address where user requests are stored for the Fund - pub fn get_fund_user_requests_account( - &self, - wallet_address: &Pubkey, - fund_name: &str, - token_name: &str, - ) -> Result { - let fund = self.get_fund(fund_name)?; - let token = self.get_token(token_name)?; - Ok(Pubkey::find_program_address( - &[ - b"user_requests_account", - token.name.as_bytes(), - wallet_address.as_ref(), - fund.name.as_bytes(), - ], - &fund.fund_program_id, - ) - .0) - } - - /// Returns user requests for specific Fund and token - pub fn get_fund_user_requests( - &self, - wallet_address: &Pubkey, - fund_name: &str, - token_name: &str, - ) -> Result { - let user_requests_account = - self.get_fund_user_requests_account(wallet_address, fund_name, token_name)?; - let data = self.rpc_client.get_account_data(&user_requests_account)?; - FundUserRequests::unpack(data.as_slice()).map_err(|e| e.into()) - } - - /// Returns user requests for all tokens accepted by the Fund - pub fn get_all_fund_user_requests( - &self, - fund_name: &str, - ) -> Result, FarmClientError> { - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - // search for user requests accounts - let bytes = [ - &DISCRIMINATOR_FUND_USER_REQUESTS.to_le_bytes(), - fund_ref.as_ref(), - ] - .concat() - .to_vec(); - let acc_vec = self.get_accounts_with_filter(&fund.fund_program_id, 0, bytes)?; - - let mut res = vec![]; - for (_, acc) in &acc_vec { - res.push(FundUserRequests::unpack(acc.data.as_slice())?); - } - - Ok(res) - } - - /// Returns Fund info and config - pub fn get_fund_info(&self, fund_name: &str) -> Result { - let fund = self.get_fund(fund_name)?; - let data = self.rpc_client.get_account_data(&fund.info_account)?; - if !RefDB::is_initialized(data.as_slice()) { - return Err(ProgramError::UninitializedAccount.into()); - } - let mut fund_info = FundInfo::default(); - let rec_vec = RefDB::read_all(data.as_slice())?; - for rec in rec_vec.iter() { - if let refdb::Reference::U64 { data } = rec.reference { - match rec.name.as_str() { - "DepositStartTime" => { - fund_info.deposit_schedule.start_time = data as UnixTimestamp - } - "DepositEndTime" => fund_info.deposit_schedule.end_time = data as UnixTimestamp, - "DepositApprovalRequired" => { - fund_info.deposit_schedule.approval_required = data != 0 - } - "DepositMinAmountUsd" => { - fund_info.deposit_schedule.min_amount_usd = f64::from_bits(data) - } - "DepositMaxAmountUsd" => { - fund_info.deposit_schedule.max_amount_usd = f64::from_bits(data) - } - "DepositFee" => fund_info.deposit_schedule.fee = f64::from_bits(data), - "WithdrawalStartTime" => { - fund_info.withdrawal_schedule.start_time = data as UnixTimestamp - } - "WithdrawalEndTime" => { - fund_info.withdrawal_schedule.end_time = data as UnixTimestamp - } - "WithdrawalApprovalRequired" => { - fund_info.withdrawal_schedule.approval_required = data != 0 - } - "WithdrawalMinAmountUsd" => { - fund_info.withdrawal_schedule.min_amount_usd = f64::from_bits(data) - } - "WithdrawalMaxAmountUsd" => { - fund_info.withdrawal_schedule.max_amount_usd = f64::from_bits(data) - } - "WithdrawalFee" => fund_info.withdrawal_schedule.fee = f64::from_bits(data), - "AssetsLimitUsd" => { - fund_info.assets_config.assets_limit_usd = f64::from_bits(data) - } - "AssetsMaxUpdateAgeSec" => fund_info.assets_config.max_update_age_sec = data, - "AssetsMaxPriceError" => { - fund_info.assets_config.max_price_error = f64::from_bits(data) - } - "AssetsMaxPriceAgeSec" => fund_info.assets_config.max_price_age_sec = data, - "IssueVirtualTokens" => fund_info.assets_config.issue_virtual_tokens = data > 0, - "VirtualTokensSupply" => fund_info.virtual_tokens_supply = data, - "AmountInvestedUsd" => fund_info.amount_invested_usd = f64::from_bits(data), - "AmountRemovedUsd" => fund_info.amount_removed_usd = f64::from_bits(data), - "CurrentAssetsUsd" => fund_info.current_assets_usd = f64::from_bits(data), - "AssetsUpdateTime" => fund_info.assets_update_time = data as UnixTimestamp, - "AdminActionTime" => fund_info.admin_action_time = data as UnixTimestamp, - "LastTradeTime" => fund_info.last_trade_time = data as UnixTimestamp, - "LiquidationStartTime" => { - fund_info.liquidation_start_time = data as UnixTimestamp - } - "LiquidationAmountUsd" => { - fund_info.liquidation_amount_usd = f64::from_bits(data) - } - "LiquidationAmountTokens" => fund_info.liquidation_amount_tokens = data, - _ => {} - } - } - } - - Ok(fund_info) - } - - /// Returns Fund info and config for all Funds - pub fn get_all_fund_infos(&self) -> Result, FarmClientError> { - let mut fund_infos = vec![]; - let funds = self.get_funds()?; - for fund in funds.keys() { - fund_infos.push(self.get_fund_info(fund)?); - } - - Ok(fund_infos) - } - - /// Returns the account address where Fund assets info is stored - pub fn get_fund_assets_account( - &self, - fund_name: &str, - asset_type: FundAssetType, - ) -> Result { - let fund = self.get_fund(fund_name)?; - match asset_type { - FundAssetType::Vault => Ok(Pubkey::find_program_address( - &[b"vaults_assets_info", fund.name.as_bytes()], - &fund.fund_program_id, - ) - .0), - FundAssetType::Custody => Ok(Pubkey::find_program_address( - &[b"custodies_assets_info", fund.name.as_bytes()], - &fund.fund_program_id, - ) - .0), - } - } - - /// Returns the Fund assets info - pub fn get_fund_assets( - &self, - fund_name: &str, - asset_type: FundAssetType, - ) -> Result { - let assets_account = self.get_fund_assets_account(fund_name, asset_type)?; - let data = self.rpc_client.get_account_data(&assets_account)?; - FundAssets::unpack(data.as_slice()).map_err(|e| e.into()) - } - - /// Returns the token account address for the Fund assets custody - pub fn get_fund_custody_token_account( - &self, - fund_name: &str, - token_name: &str, - custody_type: FundCustodyType, - ) -> Result { - let fund = self.get_fund(fund_name)?; - let token = self.get_token(token_name)?; - - if matches!(custody_type, FundCustodyType::DepositWithdraw) { - Ok(Pubkey::find_program_address( - &[ - b"fund_wd_custody_account", - token.name.as_bytes(), - fund.name.as_bytes(), - ], - &fund.fund_program_id, - ) - .0) - } else { - self.get_associated_token_address(&fund.fund_authority, token_name) - } - } - - /// Returns the token account address for the Fund fees custody - pub fn get_fund_custody_fees_token_account( - &self, - fund_name: &str, - token_name: &str, - custody_type: FundCustodyType, - ) -> Result { - let fund = self.get_fund(fund_name)?; - let token = self.get_token(token_name)?; - let custody_seed_str: &[u8] = match custody_type { - FundCustodyType::DepositWithdraw => b"fund_wd_custody_fees_account", - FundCustodyType::Trading => b"fund_td_custody_fees_account", - }; - Ok(Pubkey::find_program_address( - &[ - custody_seed_str, - token.name.as_bytes(), - fund.name.as_bytes(), - ], - &fund.fund_program_id, - ) - .0) - } - - /// Returns the account address where Fund custody info is stored - pub fn get_fund_custody_account( - &self, - fund_name: &str, - token_name: &str, - custody_type: FundCustodyType, - ) -> Result { - let fund = self.get_fund(fund_name)?; - let token = self.get_token(token_name)?; - let custody_seed_str: &[u8] = match custody_type { - FundCustodyType::DepositWithdraw => b"fund_wd_custody_info", - FundCustodyType::Trading => b"fund_td_custody_info", - }; - Ok(Pubkey::find_program_address( - &[ - custody_seed_str, - token.name.as_bytes(), - fund.name.as_bytes(), - ], - &fund.fund_program_id, - ) - .0) - } - - /// Returns the Fund custody info - pub fn get_fund_custody( - &self, - fund_name: &str, - token_name: &str, - custody_type: FundCustodyType, - ) -> Result { - let custody_info_account = - self.get_fund_custody_account(fund_name, token_name, custody_type)?; - let data = self.rpc_client.get_account_data(&custody_info_account)?; - FundCustody::unpack(data.as_slice()).map_err(|e| e.into()) - } - - /// Returns all custodies belonging to the Fund sorted by custody_id - pub fn get_fund_custodies(&self, fund_name: &str) -> Result, FarmClientError> { - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - // search for custody accounts - let bytes = [&DISCRIMINATOR_FUND_CUSTODY.to_le_bytes(), fund_ref.as_ref()] - .concat() - .to_vec(); - let acc_vec = self.get_accounts_with_filter(&fund.fund_program_id, 0, bytes)?; - - let mut res = vec![]; - for (_, acc) in &acc_vec { - res.push(FundCustody::unpack(acc.data.as_slice())?); - } - - res.sort_by_key(|k| k.custody_id); - Ok(res) - } - - /// Returns the Fund custody extended info - pub fn get_fund_custody_with_balance( - &self, - fund_name: &str, - token_name: &str, - custody_type: FundCustodyType, - ) -> Result { - let custody = self.get_fund_custody(fund_name, token_name, custody_type)?; - let token = self.get_token_by_ref(&custody.token_ref)?; - let fund = self.get_fund_by_ref(&custody.fund_ref)?; - let balance = self.get_token_account_balance_with_address(&custody.address)?; - let fees_balance = self.get_token_account_balance_with_address(&custody.fees_address)?; - Ok(FundCustodyWithBalance { - fund_name: fund.name, - token_name: token.name, - balance, - fees_balance, - discriminator: custody.discriminator, - fund_ref: custody.fund_ref, - custody_id: custody.custody_id, - custody_type: custody.custody_type, - token_ref: custody.token_ref, - address: custody.address, - fees_address: custody.fees_address, - bump: custody.bump, - }) - } - - /// Returns all custodies belonging to the Fund with extended info - pub fn get_fund_custodies_with_balance( - &self, - fund_name: &str, - ) -> Result, FarmClientError> { - let fund = self.get_fund(fund_name)?; - let custodies = self.get_fund_custodies(fund_name)?; - let mut res = vec![]; - for custody in &custodies { - let token = self.get_token_by_ref(&custody.token_ref)?; - let balance = self.get_token_account_balance_with_address(&custody.address)?; - let fees_balance = - self.get_token_account_balance_with_address(&custody.fees_address)?; - res.push(FundCustodyWithBalance { - fund_name: fund.name, - token_name: token.name, - balance, - fees_balance, - discriminator: custody.discriminator, - fund_ref: custody.fund_ref, - custody_id: custody.custody_id, - custody_type: custody.custody_type, - token_ref: custody.token_ref, - address: custody.address, - fees_address: custody.fees_address, - bump: custody.bump, - }); - } - Ok(res) - } - - /// Adds a new custody to the Fund - pub fn add_fund_custody( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - token_name: &str, - custody_type: FundCustodyType, - ) -> Result { - // create and send the instruction - let inst = self.new_instruction_add_fund_custody( - &admin_signer.pubkey(), - fund_name, - token_name, - custody_type, - )?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Removes the custody from the Fund - pub fn remove_fund_custody( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - token_name: &str, - custody_type: FundCustodyType, - ) -> Result { - // create and send the instruction - let inst = self.new_instruction_remove_fund_custody( - &admin_signer.pubkey(), - fund_name, - token_name, - custody_type, - )?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Returns the account address where Fund Vault info is stored - pub fn get_fund_vault_account( - &self, - fund_name: &str, - vault_name: &str, - vault_type: FundVaultType, - ) -> Result { - let fund = self.get_fund(fund_name)?; - let vault_seed_str: &[u8] = match vault_type { - FundVaultType::Vault => b"fund_vault_info", - FundVaultType::Pool => b"fund_pool_info", - FundVaultType::Farm => b"fund_farm_info", - }; - Ok(Pubkey::find_program_address( - &[vault_seed_str, vault_name.as_bytes(), fund_name.as_bytes()], - &fund.fund_program_id, - ) - .0) - } - - /// Returns the Fund Vault info - pub fn get_fund_vault( - &self, - fund_name: &str, - vault_name: &str, - vault_type: FundVaultType, - ) -> Result { - let vault_info_account = self.get_fund_vault_account(fund_name, vault_name, vault_type)?; - let data = self.rpc_client.get_account_data(&vault_info_account)?; - FundVault::unpack(data.as_slice()).map_err(|e| e.into()) - } - - /// Returns all Vaults belonging to the Fund sorted by vault_id - pub fn get_fund_vaults(&self, fund_name: &str) -> Result, FarmClientError> { - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - // search for custody accounts - let bytes = [&DISCRIMINATOR_FUND_VAULT.to_le_bytes(), fund_ref.as_ref()] - .concat() - .to_vec(); - let acc_vec = self.get_accounts_with_filter(&fund.fund_program_id, 0, bytes)?; - - let mut res = vec![]; - for (_, acc) in &acc_vec { - res.push(FundVault::unpack(acc.data.as_slice())?); - } - - res.sort_by_key(|k| k.vault_id); - Ok(res) - } - - /// Adds a new Vault to the Fund - pub fn add_fund_vault( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - vault_name: &str, - vault_type: FundVaultType, - ) -> Result { - // create and send the instruction - let inst = self.new_instruction_add_fund_vault( - &admin_signer.pubkey(), - fund_name, - vault_name, - vault_type, - )?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Removes the Vault from the Fund - pub fn remove_fund_vault( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - vault_name: &str, - vault_type: FundVaultType, - ) -> Result { - // create and send the instruction - let inst = self.new_instruction_remove_fund_vault( - &admin_signer.pubkey(), - fund_name, - vault_name, - vault_type, - )?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Initializes a Fund - pub fn init_fund( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - step: u64, - ) -> Result { - let inst = self.new_instruction_init_fund(&admin_signer.pubkey(), fund_name, step)?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Initializes a new User for the Fund - pub fn user_init_fund( - &self, - signer: &dyn Signer, - fund_name: &str, - token_name: &str, - ) -> Result { - // create and send the instruction - let inst = self.new_instruction_user_init_fund(&signer.pubkey(), fund_name, token_name)?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Sets a new assets tracking config for the Fund - pub fn set_fund_assets_tracking_config( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - config: &FundAssetsTrackingConfig, - ) -> Result { - // create and send the instruction - let inst = self.new_instruction_set_fund_assets_tracking_config( - &admin_signer.pubkey(), - fund_name, - config, - )?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Sets a new deposit schedule for the Fund - pub fn set_fund_deposit_schedule( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - schedule: &FundSchedule, - ) -> Result { - // create and send the instruction - let inst = self.new_instruction_set_fund_deposit_schedule( - &admin_signer.pubkey(), - fund_name, - schedule, - )?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Disables deposits to the Fund. - /// Same outcome can be achieved with set_fund_deposit_schedule(), - /// disable_deposits_fund() function is just more explicit. - pub fn disable_deposits_fund( - &self, - signer: &dyn Signer, - fund_name: &str, - ) -> Result { - // create and send the instruction - let inst = self.new_instruction_disable_deposits_fund(&signer.pubkey(), fund_name)?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Requests a new deposit to the Fund - pub fn request_deposit_fund( - &self, - signer: &dyn Signer, - fund_name: &str, - token_name: &str, - ui_amount: f64, - ) -> Result { - let inst = self.all_instructions_request_deposit_fund( - &signer.pubkey(), - fund_name, - token_name, - ui_amount, - )?; - self.sign_and_send_instructions(&[signer], &inst) - } - - /// Cancels pending deposit to the Fund - pub fn cancel_deposit_fund( - &self, - signer: &dyn Signer, - fund_name: &str, - token_name: &str, - ) -> Result { - // create and send the instruction - let inst = - self.new_instruction_cancel_deposit_fund(&signer.pubkey(), fund_name, token_name)?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Approves pending deposit to the Fund - pub fn approve_deposit_fund( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - user_address: &Pubkey, - token_name: &str, - ui_amount: f64, - ) -> Result { - // create and send the instruction - let inst = self.new_instruction_approve_deposit_fund( - &admin_signer.pubkey(), - user_address, - fund_name, - token_name, - ui_amount, - )?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Denies pending deposit to the Fund - pub fn deny_deposit_fund( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - user_address: &Pubkey, - token_name: &str, - deny_reason: &str, - ) -> Result { - // create and send the instruction - let inst = self.new_instruction_deny_deposit_fund( - &admin_signer.pubkey(), - user_address, - fund_name, - token_name, - deny_reason, - )?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Sets a new withdrawal schedule for the Fund - pub fn set_fund_withdrawal_schedule( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - schedule: &FundSchedule, - ) -> Result { - // create and send the instruction - let inst = self.new_instruction_set_fund_withdrawal_schedule( - &admin_signer.pubkey(), - fund_name, - schedule, - )?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Disables withdrawals from the Fund. - /// Same outcome can be achieved with set_fund_withdrawal_schedule(), - /// disable_withdrawals_fund() function is just more explicit. - pub fn disable_withdrawals_fund( - &self, - signer: &dyn Signer, - fund_name: &str, - ) -> Result { - // create and send the instruction - let inst = self.new_instruction_disable_withdrawals_fund(&signer.pubkey(), fund_name)?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Requests a new withdrawal from the Fund - pub fn request_withdrawal_fund( - &self, - signer: &dyn Signer, - fund_name: &str, - token_name: &str, - ui_amount: f64, - ) -> Result { - let inst = self.all_instructions_request_withdrawal_fund( - &signer.pubkey(), - fund_name, - token_name, - ui_amount, - )?; - self.sign_and_send_instructions(&[signer], &inst) - } - - /// Cancels pending withdrawal from the Fund - pub fn cancel_withdrawal_fund( - &self, - signer: &dyn Signer, - fund_name: &str, - token_name: &str, - ) -> Result { - // create and send the instruction - let inst = - self.new_instruction_cancel_withdrawal_fund(&signer.pubkey(), fund_name, token_name)?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Approves pending withdrawal from the Fund - pub fn approve_withdrawal_fund( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - user_address: &Pubkey, - token_name: &str, - ui_amount: f64, - ) -> Result { - // create and send the instruction - let inst = self.new_instruction_approve_withdrawal_fund( - &admin_signer.pubkey(), - user_address, - fund_name, - token_name, - ui_amount, - )?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Denies pending withdrawal from the Fund - pub fn deny_withdrawal_fund( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - user_address: &Pubkey, - token_name: &str, - deny_reason: &str, - ) -> Result { - // create and send the instruction - let inst = self.new_instruction_deny_withdrawal_fund( - &admin_signer.pubkey(), - user_address, - fund_name, - token_name, - deny_reason, - )?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Moves deposited assets from Deposit/Withdraw custody to the Fund - pub fn lock_assets_fund( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - token_name: &str, - ui_amount: f64, - ) -> Result { - // create and send the instruction - let inst = self.new_instruction_lock_assets_fund( - &admin_signer.pubkey(), - fund_name, - token_name, - ui_amount, - )?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Releases assets from the Fund to Deposit/Withdraw custody - pub fn unlock_assets_fund( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - token_name: &str, - ui_amount: f64, - ) -> Result { - // create and send the instruction - let inst = self.new_instruction_unlock_assets_fund( - &admin_signer.pubkey(), - fund_name, - token_name, - ui_amount, - )?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Updates Fund assets info based on custody holdings - pub fn update_fund_assets_with_custody( - &self, - signer: &dyn Signer, - fund_name: &str, - custody_id: u32, - ) -> Result { - // create and send the instruction - let inst = self.new_instruction_update_fund_assets_with_custody( - &signer.pubkey(), - fund_name, - custody_id, - )?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Updates Fund assets info based on all custodies - pub fn update_fund_assets_with_custodies( - &self, - signer: &dyn Signer, - fund_name: &str, - ) -> Result { - let custodies = self.get_fund_custodies(fund_name)?; - for custody in &custodies { - if !custody.is_vault_token { - self.update_fund_assets_with_custody(signer, fund_name, custody.custody_id)?; - } - } - Ok(custodies.len()) - } - - /// Updates Fund assets info based on Vault holdings - pub fn update_fund_assets_with_vault( - &self, - signer: &dyn Signer, - fund_name: &str, - vault_id: u32, - ) -> Result { - // create and send the instruction - let inst = self.new_instruction_update_fund_assets_with_vault( - &signer.pubkey(), - fund_name, - vault_id, - )?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Updates Fund assets info based on all Vaults - pub fn update_fund_assets_with_vaults( - &self, - signer: &dyn Signer, - fund_name: &str, - ) -> Result { - let vaults = self.get_fund_vaults(fund_name)?; - for vault in &vaults { - if vault.vault_type != FundVaultType::Farm { - self.update_fund_assets_with_vault(signer, fund_name, vault.vault_id)?; - } - } - Ok(vaults.len()) - } - - /// Starts the Fund liquidation - pub fn start_liquidation_fund( - &self, - signer: &dyn Signer, - fund_name: &str, - ) -> Result { - // create and send the instruction - let inst = self.new_instruction_start_liquidation_fund(&signer.pubkey(), fund_name)?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Stops the Fund liquidation - pub fn stop_liquidation_fund( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - ) -> Result { - // create and send the instruction - let inst = self.new_instruction_stop_liquidation_fund(&admin_signer.pubkey(), fund_name)?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Withdraw collected fees from the Fund - pub fn withdraw_fees_fund( - &self, - signer: &dyn Signer, - fund_name: &str, - token_name: &str, - custody_type: FundCustodyType, - ui_amount: f64, - receiver: &Pubkey, - ) -> Result { - let inst = self.new_instruction_withdraw_fees_fund( - &signer.pubkey(), - fund_name, - token_name, - custody_type, - ui_amount, - receiver, - )?; - self.sign_and_send_instructions(&[signer], &[inst]) - } - - /// Adds liquidity to the Pool in the Fund - pub fn fund_add_liquidity_pool( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - pool_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - ) -> Result { - let inst = self.all_instructions_fund_add_liquidity_pool( - &admin_signer.pubkey(), - fund_name, - pool_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - )?; - Ok(*self - .sign_and_send_instructions_in_batches(&[admin_signer], &inst)? - .last() - .unwrap()) - } - - /// Removes liquidity from the Pool in the Fund - pub fn fund_remove_liquidity_pool( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - pool_name: &str, - ui_amount: f64, - ) -> Result { - let inst = self.all_instructions_fund_remove_liquidity_pool( - &admin_signer.pubkey(), - fund_name, - pool_name, - ui_amount, - )?; - Ok(*self - .sign_and_send_instructions_in_batches(&[admin_signer], &inst)? - .last() - .unwrap()) - } - - /// Swaps tokens in the Fund - #[allow(clippy::too_many_arguments)] - pub fn fund_swap( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - protocol: Protocol, - from_token: &str, - to_token: &str, - ui_amount_in: f64, - min_ui_amount_out: f64, - ) -> Result { - let inst = self.all_instructions_fund_swap( - &admin_signer.pubkey(), - fund_name, - protocol, - from_token, - to_token, - ui_amount_in, - min_ui_amount_out, - )?; - Ok(*self - .sign_and_send_instructions_in_batches(&[admin_signer], &inst)? - .last() - .unwrap()) - } - - /// Initializes a new User for the Farm in the Fund - pub fn fund_user_init_farm( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - farm_name: &str, - ) -> Result { - // create and send the instruction - let inst = - self.new_instruction_fund_user_init_farm(&admin_signer.pubkey(), fund_name, farm_name)?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Stakes tokens to the Farm in the Fund - pub fn fund_stake( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - farm_name: &str, - ui_amount: f64, - ) -> Result { - let inst = self.all_instructions_fund_stake( - &admin_signer.pubkey(), - fund_name, - farm_name, - ui_amount, - )?; - Ok(*self - .sign_and_send_instructions_in_batches(&[admin_signer], &inst)? - .last() - .unwrap()) - } - - /// Unstakes tokens from the Farm in the Fund - pub fn fund_unstake( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - farm_name: &str, - ui_amount: f64, - ) -> Result { - let inst = self.all_instructions_fund_unstake( - &admin_signer.pubkey(), - fund_name, - farm_name, - ui_amount, - )?; - Ok(*self - .sign_and_send_instructions_in_batches(&[admin_signer], &inst)? - .last() - .unwrap()) - } - - /// Harvests rewards from the Farm in the Fund - pub fn fund_harvest( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - farm_name: &str, - ) -> Result { - let inst = - self.all_instructions_fund_harvest(&admin_signer.pubkey(), fund_name, farm_name)?; - Ok(*self - .sign_and_send_instructions_in_batches(&[admin_signer], &inst)? - .last() - .unwrap()) - } - - /// Initializes a new User for the Vault in the Fund - pub fn fund_user_init_vault( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - vault_name: &str, - ) -> Result { - // create and send the instruction - let inst = self.new_instruction_fund_user_init_vault( - &admin_signer.pubkey(), - fund_name, - vault_name, - )?; - self.sign_and_send_instructions(&[admin_signer], &[inst]) - } - - /// Adds liquidity to the Vault in the Fund - pub fn fund_add_liquidity_vault( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - vault_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - ) -> Result { - let inst = self.all_instructions_fund_add_liquidity_vault( - &admin_signer.pubkey(), - fund_name, - vault_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - )?; - Ok(*self - .sign_and_send_instructions_in_batches(&[admin_signer], &inst)? - .last() - .unwrap()) - } - - /// Adds locked liquidity to the Vault in the Fund. - /// Useful if add liquidity operation partially failed. - pub fn fund_add_locked_liquidity_vault( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - vault_name: &str, - ui_amount: f64, - ) -> Result { - let inst = self.all_instructions_fund_add_locked_liquidity_vault( - &admin_signer.pubkey(), - fund_name, - vault_name, - ui_amount, - )?; - Ok(*self - .sign_and_send_instructions_in_batches(&[admin_signer], &inst)? - .last() - .unwrap()) - } - - /// Removes liquidity from the Vault in the Fund - pub fn fund_remove_liquidity_vault( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - vault_name: &str, - ui_amount: f64, - ) -> Result { - let inst = self.all_instructions_fund_remove_liquidity_vault( - &admin_signer.pubkey(), - fund_name, - vault_name, - ui_amount, - )?; - Ok(*self - .sign_and_send_instructions_in_batches(&[admin_signer], &inst)? - .last() - .unwrap()) - } - - /// Removes unlocked liquidity from the Vault in the Fund. - /// Useful if remove liquidity operation failed after unlock step. - pub fn fund_remove_unlocked_liquidity_vault( - &self, - admin_signer: &dyn Signer, - fund_name: &str, - vault_name: &str, - ui_amount: f64, - ) -> Result { - let inst = self.all_instructions_fund_remove_unlocked_liquidity_vault( - &admin_signer.pubkey(), - fund_name, - vault_name, - ui_amount, - )?; - Ok(*self - .sign_and_send_instructions_in_batches(&[admin_signer], &inst)? - .last() - .unwrap()) - } - - /// Returns oracle type and address for the given token - pub fn get_oracle( - &self, - symbol: &str, - ) -> Result<(OracleType, Option), FarmClientError> { - let token = self.get_token(symbol)?; - Ok((token.oracle_type, token.oracle_account)) - } - - /// Returns the price in USD for the given token - pub fn get_oracle_price( - &self, - symbol: &str, - max_price_age_sec: u64, - max_price_error: f64, - ) -> Result { - let (oracle_type, oracle_account) = self.get_oracle(symbol)?; - if oracle_type == OracleType::Unsupported { - return Err(FarmClientError::ValueError(format!( - "Oracle for {} is not configured", - symbol - ))); - } else if oracle_type != OracleType::Pyth { - return Err(FarmClientError::ValueError( - "Unsupported oracle type".to_string(), - )); - } - let pyth_price_data = self - .rpc_client - .get_account_data(&oracle_account.ok_or(ProgramError::UninitializedAccount)?)?; - let pyth_price = pyth_client::load_price(pyth_price_data.as_slice())?; - - if !matches!(pyth_price.agg.status, PriceStatus::Trading) - || !matches!(pyth_price.ptype, PriceType::Price) - { - return Err(FarmClientError::ValueError( - "Error: Pyth oracle price has invalid state".to_string(), - )); - } - - if max_price_age_sec > 0 { - let current_slot = self.rpc_client.get_slot()?; - let last_update_age_sec = if current_slot > pyth_price.valid_slot { - (current_slot - pyth_price.valid_slot) * solana_sdk::clock::DEFAULT_MS_PER_SLOT - / 1000 - } else { - 0 - }; - if last_update_age_sec > max_price_age_sec { - return Err(FarmClientError::ValueError( - "Error: Pyth oracle price is stale".to_string(), - )); - } - } - - if pyth_price.agg.price <= 0 - || (max_price_error > 0.0 - && pyth_price.agg.conf as f64 / pyth_price.agg.price as f64 > max_price_error) - { - return Err(FarmClientError::ValueError( - "Error: Pyth oracle price is out of bounds".to_string(), - )); - } - - Ok(pyth_price.agg.price as f64 * math::checked_powi(10.0, pyth_price.expo)?) - } - - /// Returns description and stats of all supported protocols - pub fn get_protocols(&self) -> Result, FarmClientError> { - let (raydium_pools, raydium_farms, raydium_vaults) = - self.get_protocol_stats(Protocol::Raydium)?; - let (saber_pools, saber_farms, saber_vaults) = self.get_protocol_stats(Protocol::Saber)?; - let (orca_pools, orca_farms, orca_vaults) = self.get_protocol_stats(Protocol::Orca)?; - Ok(vec![ - ProtocolInfo { - protocol: Protocol::Raydium, - description: "Raydium protocol".to_string(), - link: "www.raydium.io".to_string(), - pools: raydium_pools, - farms: raydium_farms, - vaults: raydium_vaults, - }, - ProtocolInfo { - protocol: Protocol::Saber, - description: "Saber protocol".to_string(), - link: "www.saber.so".to_string(), - pools: saber_pools, - farms: saber_farms, - vaults: saber_vaults, - }, - ProtocolInfo { - protocol: Protocol::Orca, - description: "Orca protocol".to_string(), - link: "www.orca.so".to_string(), - pools: orca_pools, - farms: orca_farms, - vaults: orca_vaults, - }, - ]) - } - - /////////////// helpers - pub fn ui_amount_to_tokens( - &self, - ui_amount: f64, - token_name: &str, - ) -> Result { - if ui_amount == 0.0 { - Ok(0) - } else if ui_amount < 0.0 { - Err(FarmClientError::ValueError(format!( - "Invalid ui_amount: {}", - ui_amount - ))) - } else { - let multiplier = - math::checked_pow(10u64, self.get_token(token_name)?.decimals as usize)?; - Ok(math::checked_as_u64( - (ui_amount * multiplier as f64).round(), - )?) - } - } - - pub fn tokens_to_ui_amount( - &self, - amount: u64, - token_name: &str, - ) -> Result { - if amount == 0 { - return Ok(0.0); - } - let divisor = math::checked_pow(10u64, self.get_token(token_name)?.decimals as usize)?; - Ok(amount as f64 / divisor as f64) - } - - pub fn ui_amount_to_tokens_with_decimals( - &self, - ui_amount: f64, - decimals: u8, - ) -> Result { - if ui_amount <= 0.0 { - return Ok(0); - } - let multiplier = math::checked_pow(10u64, decimals as usize)?; - Ok(math::checked_as_u64( - (ui_amount * multiplier as f64).round(), - )?) - } - - pub fn tokens_to_ui_amount_with_decimals(&self, amount: u64, decimals: u8) -> f64 { - if amount == 0 { - return 0.0; - } - let divisor = math::checked_pow(10u64, decimals as usize).unwrap(); - amount as f64 / divisor as f64 - } - - pub fn pool_has_sol_tokens(&self, pool_name: &str) -> Result<(bool, bool), FarmClientError> { - let pool = self.get_pool(pool_name)?; - let mut is_token_a_sol = false; - let mut is_token_b_sol = false; - if let Some(token_a_ref) = pool.token_a_ref { - let token_a = self.get_token_by_ref(&token_a_ref)?; - if token_a.token_type == TokenType::WrappedSol { - is_token_a_sol = true; - } - } - if let Some(token_b_ref) = pool.token_b_ref { - let token_b = self.get_token_by_ref(&token_b_ref)?; - if token_b.token_type == TokenType::WrappedSol { - is_token_b_sol = true; - } - } - Ok((is_token_a_sol, is_token_b_sol)) - } - - pub fn pool_has_saber_wrapped_tokens( - &self, - pool_name: &str, - ) -> Result<(bool, bool), FarmClientError> { - let pool = self.get_pool(pool_name)?; - - match pool.route { - PoolRoute::Saber { - wrapped_token_a_ref, - wrapped_token_b_ref, - .. - } => Ok((wrapped_token_a_ref.is_some(), wrapped_token_b_ref.is_some())), - _ => Ok((false, false)), - } - } - - pub fn vault_has_sol_tokens(&self, vault_name: &str) -> Result<(bool, bool), FarmClientError> { - let pool_name = self.get_underlying_pool(vault_name)?.name.to_string(); - self.pool_has_sol_tokens(&pool_name) - } - - pub fn get_protocol(vault_or_pool_name: &str) -> Result { - let protocol_str = - &vault_or_pool_name[..vault_or_pool_name.find('.').ok_or_else(|| { - FarmClientError::ValueError(format!( - "Invalid vault or pool name: {}", - vault_or_pool_name - )) - })?]; - Ok(match protocol_str { - "RDM" => Protocol::Raydium, - "SBR" => Protocol::Saber, - "ORC" => Protocol::Orca, - _ => { - return Err(FarmClientError::ValueError(format!( - "Unrecognized protocol: {}", - protocol_str - ))) - } - }) - } - - pub fn get_pool_token_names( - &self, - pool_name: &str, - ) -> Result<(String, String, String), FarmClientError> { - let pool = self.get_pool(pool_name)?; - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - Ok(( - if let Some(token) = token_a { - token.name.to_string() - } else { - String::default() - }, - if let Some(token) = token_b { - token.name.to_string() - } else { - String::default() - }, - if let Some(token) = lp_token { - token.name.to_string() - } else { - String::default() - }, - )) - } - - pub fn get_farm_token_names( - &self, - farm_name: &str, - ) -> Result<(String, String, String), FarmClientError> { - let farm = self.get_farm(farm_name)?; - let token_a = self.get_token_by_ref_from_cache(&farm.first_reward_token_ref)?; - let token_b = self.get_token_by_ref_from_cache(&farm.second_reward_token_ref)?; - let lp_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - Ok(( - if let Some(token) = token_a { - token.name.to_string() - } else { - String::default() - }, - if let Some(token) = token_b { - token.name.to_string() - } else { - String::default() - }, - if let Some(token) = lp_token { - token.name.to_string() - } else { - String::default() - }, - )) - } - - pub fn get_vault_token_names( - &self, - vault_name: &str, - ) -> Result<(String, String, String), FarmClientError> { - let vault = self.get_vault(vault_name)?; - let vt_token = self.get_token_by_ref_from_cache(&Some(vault.vault_token_ref))?; - match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { pool_ref, .. } => { - let pool = self.get_pool_by_ref(&pool_ref)?; - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - - Ok(( - if let Some(token) = token_a { - token.name.to_string() - } else { - String::default() - }, - if let Some(token) = token_b { - token.name.to_string() - } else { - String::default() - }, - if let Some(token) = vt_token { - token.name.to_string() - } else { - String::default() - }, - )) - } - _ => { - unreachable!(); - } - } - } - - pub fn unwrap_pool_tokens( - &self, - signer: &dyn Signer, - pool_name: &str, - ) -> Result { - let mut inst = Vec::::new(); - - let (is_token_a_sol, is_token_b_sol) = self.pool_has_sol_tokens(pool_name)?; - let (is_token_a_wrapped, is_token_b_wrapped) = - self.pool_has_saber_wrapped_tokens(pool_name)?; - - if is_token_a_wrapped { - inst.push(self.new_instruction_unwrap_token( - &signer.pubkey(), - pool_name, - TokenSelector::TokenA, - 0.0, - )?); - } - if is_token_b_wrapped { - inst.push(self.new_instruction_unwrap_token( - &signer.pubkey(), - pool_name, - TokenSelector::TokenB, - 0.0, - )?); - } - if is_token_a_sol || is_token_b_sol { - inst.push(self.new_instruction_close_token_account(&signer.pubkey(), "SOL")?); - } - - self.sign_and_send_instructions(&[signer], &inst) - } - - pub fn get_accounts_with_filter( - &self, - program: &Pubkey, - offset: usize, - bytes: Vec, - ) -> Result, FarmClientError> { - let filters = Some(vec![rpc_filter::RpcFilterType::Memcmp( - rpc_filter::Memcmp { - offset, - bytes: rpc_filter::MemcmpEncodedBytes::Base58(bs58::encode(bytes).into_string()), - encoding: Some(rpc_filter::MemcmpEncoding::Binary), - }, - )]); - Ok(self.rpc_client.get_program_accounts_with_config( - program, - RpcProgramAccountsConfig { - filters, - account_config: RpcAccountInfoConfig { - encoding: Some(UiAccountEncoding::Base64), - ..RpcAccountInfoConfig::default() - }, - ..RpcProgramAccountsConfig::default() - }, - )?) - } - - /// Checks if associated token account owner matches base wallet owner - pub fn check_ata_owner( - &self, - base_wallet: &Pubkey, - token_name: &str, - ) -> Result { - let token_account = self - .rpc_client - .get_account(&self.get_associated_token_address(base_wallet, token_name)?)?; - if token_account.owner != spl_token::id() { - return Ok(false); - } - let token_data = self.get_token_account_data(base_wallet, token_name)?; - let base_account = self.rpc_client.get_account(base_wallet)?; - Ok(base_account.owner == FarmClient::pubkey_from_str(token_data.owner.as_str())?) - } - - pub fn get_stake_account( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ) -> Result { - let farm = self.get_farm(farm_name)?; - match farm.route { - FarmRoute::Raydium { .. } => self.get_raydium_stake_account(wallet_address, farm_name), - FarmRoute::Saber { .. } => self.get_saber_stake_account(wallet_address, farm_name), - FarmRoute::Orca { .. } => self.get_orca_stake_account(wallet_address, farm_name), - } - } - - pub fn get_vault_stake_account(&self, vault_name: &str) -> Result { - let vault = self.get_vault(vault_name)?; - match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { - vault_stake_info, .. - } => Ok(vault_stake_info), - _ => unreachable!(), - } - } - - /// Checks if the given address is the Fund manager - pub fn is_fund_manager(&self, wallet_address: &Pubkey) -> Result { - Ok(self - .get_funds()? - .values() - .any(|&f| &f.fund_manager == wallet_address)) - } - - /// Extracts version from the full pool name - pub fn extract_pool_version(name: &str) -> Result { - if name.len() > 3 - && &name[name.len() - 2..name.len() - 1].to_uppercase() == "V" - && &name[name.len() - 3..name.len() - 2] == "-" - { - if let Ok(ver) = name[name.len() - 1..name.len()].parse::() { - return Ok(ver); - } - } - Err(FarmClientError::ProgramError(ProgramError::InvalidArgument)) - } - - /// Extracts name and version from the pool or liquidity token name - pub fn extract_pool_name_and_version(name: &str) -> Result<(String, u16), FarmClientError> { - if FarmClient::is_liquidity_token(name) { - if name.len() > 6 { - return Ok(( - name[3..name.len() - 3].to_string(), - FarmClient::extract_pool_version(name)?, - )); - } - } else if name.len() > 3 { - return Ok(( - name[..name.len() - 3].to_string(), - FarmClient::extract_pool_version(name)?, - )); - } - Err(FarmClientError::ProgramError(ProgramError::InvalidArgument)) - } - - /// Checks if token is a liquidity token - pub fn is_liquidity_token(name: &str) -> bool { - name.len() > 3 && ["LP.", "VT.", "FD."].contains(&&name[..3]) - } - - /// Extracts individual token names and protocol from the pool or liquidity token name - pub fn extract_token_names(name: &str) -> Result<(Protocol, String, String), FarmClientError> { - let dot_split = if FarmClient::is_liquidity_token(name) { - name[3..].split('.').collect::>() - } else { - name.split('.').collect::>() - }; - if dot_split.len() < 2 || dot_split[0].is_empty() { - return Err(FarmClientError::ValueError(format!( - "Can't extract token names from {}", - name - ))); - } - let dash_split = dot_split.last().unwrap().split('-').collect::>(); - if dash_split.is_empty() - || dash_split[0].is_empty() - || (dash_split.len() > 1 && dash_split[1].is_empty()) - { - return Err(FarmClientError::ValueError(format!( - "Can't extract token names from {}", - name - ))); - } - Ok(( - dot_split[0].parse()?, - dash_split[0].to_string(), - if dash_split.len() > 1 - && (FarmClient::extract_pool_version(name).is_err() || dash_split.len() > 2) - { - dash_split[1].to_string() - } else { - String::default() - }, - )) - } - - ////////////// private helpers - fn pubkey_from_str(input: &str) -> Result { - Pubkey::from_str(input).map_err(|_| { - FarmClientError::ValueError(format!( - "Failed to convert the String to a Pubkey {}", - input - )) - }) - } - - fn to_token_amount(&self, ui_amount: f64, token: &Token) -> Result { - self.ui_amount_to_tokens_with_decimals(ui_amount, token.decimals) - } - - fn to_token_amount_option( - &self, - ui_amount: f64, - token: &Option, - ) -> Result { - if let Some(tkn) = token { - self.to_token_amount(ui_amount, tkn) - } else { - Err(ProgramError::UninitializedAccount.into()) - } - } - - fn load_token_by_ref(&self, token_ref: &Pubkey) -> Result { - let data = self.rpc_client.get_account_data(token_ref)?; - Ok(Token::unpack(data.as_slice())?) - } - - fn load_pool_by_ref(&self, pool_ref: &Pubkey) -> Result { - let data = self.rpc_client.get_account_data(pool_ref)?; - Ok(Pool::unpack(data.as_slice())?) - } - - fn load_vault_by_ref(&self, vault_ref: &Pubkey) -> Result { - let data = self.rpc_client.get_account_data(vault_ref)?; - Ok(Vault::unpack(data.as_slice())?) - } - - fn load_farm_by_ref(&self, farm_ref: &Pubkey) -> Result { - let data = self.rpc_client.get_account_data(farm_ref)?; - Ok(Farm::unpack(data.as_slice())?) - } - - fn load_fund_by_ref(&self, fund_ref: &Pubkey) -> Result { - let data = self.rpc_client.get_account_data(fund_ref)?; - Ok(Fund::unpack(data.as_slice())?) - } - - // insert version-stripped names that point to the latest version - fn reinsert_latest_versions( - source: &HashMap, - dest: &mut HashMap, - ) { - let mut latest = HashMap::::default(); - for (full_name, _) in source.iter() { - if let Ok((name_no_ver, ver)) = FarmClient::extract_pool_name_and_version(full_name) { - if let Some((_, cur_ver)) = latest.get(&name_no_ver) { - if *cur_ver < ver { - latest.insert(name_no_ver, (full_name.clone(), ver)); - } - } else { - latest.insert(name_no_ver, (full_name.clone(), ver)); - } - } - } - for (name, (full_name, _)) in latest { - dest.insert(name, full_name); - } - } - - fn reload_fund_refs_if_stale(&self) -> Result { - if self.fund_refs.borrow().is_stale() { - let (header, fund_refs) = - self.get_refdb_pubkey_map(&refdb::StorageType::Fund.to_string())?; - if self.fund_refs.borrow().is_updated(header.counter) { - self.fund_refs.borrow_mut().set(fund_refs, header.counter); - self.funds.borrow_mut().reset(); - return Ok(true); - } else { - self.fund_refs.borrow_mut().mark_not_stale(); - } - } - Ok(false) - } - - fn reload_funds_if_empty(&self) -> Result { - if self.funds.borrow().is_empty() || self.funds.borrow().is_updated(1) { - let refs_map = &self.fund_refs.borrow().data; - let refs: Vec = refs_map.values().copied().collect(); - if refs.is_empty() { - return Ok(false); - } - let mut fund_map = FundMap::new(); - - let mut idx = 0; - while idx < refs.len() { - let refs_slice = &refs.as_slice()[idx..std::cmp::min(idx + 100, refs.len())]; - let accounts = self.rpc_client.get_multiple_accounts(refs_slice)?; - - for (account_option, account_ref) in accounts.iter().zip(refs_slice.iter()) { - if let Some(account) = account_option { - let fund = Fund::unpack(account.data.as_slice())?; - fund_map.insert(fund.name.as_str().to_string(), fund); - } else { - return Err(FarmClientError::RecordNotFound(format!( - "Fund with ref {}", - account_ref - ))); - } - } - idx += 100; - } - - self.funds.borrow_mut().set(fund_map, 1); - Ok(true) - } else { - Ok(false) - } - } - - fn reload_vault_refs_if_stale(&self) -> Result { - if self.vault_refs.borrow().is_stale() { - let (header, vault_refs) = - self.get_refdb_pubkey_map(&refdb::StorageType::Vault.to_string())?; - if self.vault_refs.borrow().is_updated(header.counter) { - FarmClient::reinsert_latest_versions( - &vault_refs, - &mut self.latest_vaults.borrow_mut(), - ); - self.vault_refs.borrow_mut().set(vault_refs, header.counter); - self.vaults.borrow_mut().reset(); - return Ok(true); - } else { - self.vault_refs.borrow_mut().mark_not_stale(); - } - } - Ok(false) - } - - fn reload_vaults_if_empty(&self) -> Result { - if self.vaults.borrow().is_empty() || self.vaults.borrow().is_updated(1) { - let refs_map = &self.vault_refs.borrow().data; - let refs: Vec = refs_map.values().copied().collect(); - if refs.is_empty() { - return Ok(false); - } - let mut vault_map = VaultMap::new(); - - let mut idx = 0; - while idx < refs.len() { - let refs_slice = &refs.as_slice()[idx..std::cmp::min(idx + 100, refs.len())]; - let accounts = self.rpc_client.get_multiple_accounts(refs_slice)?; - - for (account_option, account_ref) in accounts.iter().zip(refs_slice.iter()) { - if let Some(account) = account_option { - let vault = Vault::unpack(account.data.as_slice())?; - vault_map.insert(vault.name.as_str().to_string(), vault); - } else { - return Err(FarmClientError::RecordNotFound(format!( - "Vault with ref {}", - account_ref - ))); - } - } - idx += 100; - } - - self.vaults.borrow_mut().set(vault_map, 1); - Ok(true) - } else { - Ok(false) - } - } - - fn reload_pool_refs_if_stale(&self) -> Result { - if self.pool_refs.borrow().is_stale() { - let (header, pool_refs) = - self.get_refdb_pubkey_map(&refdb::StorageType::Pool.to_string())?; - if self.pool_refs.borrow().is_updated(header.counter) { - FarmClient::reinsert_latest_versions( - &pool_refs, - &mut self.latest_pools.borrow_mut(), - ); - self.pool_refs.borrow_mut().set(pool_refs, header.counter); - self.pools.borrow_mut().reset(); - return Ok(true); - } else { - self.pool_refs.borrow_mut().mark_not_stale(); - } - } - Ok(false) - } - - fn reload_pools_if_empty(&self) -> Result { - if self.pools.borrow().is_empty() || self.pools.borrow().is_updated(1) { - let refs_map = &self.pool_refs.borrow().data; - let refs: Vec = refs_map.values().copied().collect(); - if refs.is_empty() { - return Ok(false); - } - let mut pool_map = PoolMap::new(); - - let mut idx = 0; - while idx < refs.len() { - let refs_slice = &refs.as_slice()[idx..std::cmp::min(idx + 100, refs.len())]; - let accounts = self.rpc_client.get_multiple_accounts(refs_slice)?; - - for (account_option, account_ref) in accounts.iter().zip(refs_slice.iter()) { - if let Some(account) = account_option { - let pool = Pool::unpack(account.data.as_slice())?; - pool_map.insert(pool.name.as_str().to_string(), pool); - } else { - return Err(FarmClientError::RecordNotFound(format!( - "Pool with ref {}", - account_ref - ))); - } - } - idx += 100; - } - - self.pools.borrow_mut().set(pool_map, 1); - Ok(true) - } else { - Ok(false) - } - } - - fn reload_farm_refs_if_stale(&self) -> Result { - if self.farm_refs.borrow().is_stale() { - let (header, farm_refs) = - self.get_refdb_pubkey_map(&refdb::StorageType::Farm.to_string())?; - if self.farm_refs.borrow().is_updated(header.counter) { - FarmClient::reinsert_latest_versions( - &farm_refs, - &mut self.latest_farms.borrow_mut(), - ); - self.farm_refs.borrow_mut().set(farm_refs, header.counter); - self.farms.borrow_mut().reset(); - return Ok(true); - } else { - self.farm_refs.borrow_mut().mark_not_stale(); - } - } - Ok(false) - } - - fn reload_farms_if_empty(&self) -> Result { - if self.farms.borrow().is_empty() || self.farms.borrow().is_updated(1) { - let refs_map = &self.farm_refs.borrow().data; - let refs: Vec = refs_map.values().copied().collect(); - if refs.is_empty() { - return Ok(false); - } - let mut farm_map = FarmMap::new(); - - let mut idx = 0; - while idx < refs.len() { - let refs_slice = &refs.as_slice()[idx..std::cmp::min(idx + 100, refs.len())]; - let accounts = self.rpc_client.get_multiple_accounts(refs_slice)?; - - for (account_option, account_ref) in accounts.iter().zip(refs_slice.iter()) { - if let Some(account) = account_option { - let farm = Farm::unpack(account.data.as_slice())?; - farm_map.insert(farm.name.as_str().to_string(), farm); - } else { - return Err(FarmClientError::RecordNotFound(format!( - "Farm with ref {}", - account_ref - ))); - } - } - idx += 100; - } - - self.farms.borrow_mut().set(farm_map, 1); - Ok(true) - } else { - Ok(false) - } - } - - fn reload_token_refs_if_stale(&self) -> Result { - if self.token_refs.borrow().is_stale() { - let (header, token_refs) = - self.get_refdb_pubkey_map(&refdb::StorageType::Token.to_string())?; - if self.token_refs.borrow().is_updated(header.counter) { - self.token_refs.borrow_mut().set(token_refs, header.counter); - self.tokens.borrow_mut().reset(); - return Ok(true); - } else { - self.token_refs.borrow_mut().mark_not_stale(); - } - } - Ok(false) - } - - fn reload_tokens_if_empty(&self) -> Result { - if self.tokens.borrow().is_empty() || self.tokens.borrow().is_updated(1) { - let refs_map = &self.token_refs.borrow().data; - let refs: Vec = refs_map.values().copied().collect(); - if refs.is_empty() { - return Ok(false); - } - let mut token_map = TokenMap::new(); - - let mut idx = 0; - while idx < refs.len() { - let refs_slice = &refs.as_slice()[idx..std::cmp::min(idx + 100, refs.len())]; - let accounts = self.rpc_client.get_multiple_accounts(refs_slice)?; - - for (account_option, account_ref) in accounts.iter().zip(refs_slice.iter()) { - if let Some(account) = account_option { - let token = Token::unpack(account.data.as_slice())?; - token_map.insert(token.name.as_str().to_string(), token); - } else { - return Err(FarmClientError::RecordNotFound(format!( - "Token with ref {}", - account_ref - ))); - } - } - idx += 100; - } - - self.tokens.borrow_mut().set(token_map, 1); - Ok(true) - } else { - Ok(false) - } - } - - fn reload_program_ids_if_stale(&self) -> Result { - if self.official_ids.borrow().is_stale() { - let (header, official_ids) = - self.get_refdb_pubkey_map(&refdb::StorageType::Program.to_string())?; - if self.official_ids.borrow().is_updated(header.counter) { - self.official_ids - .borrow_mut() - .set(official_ids, header.counter); - return Ok(true); - } else { - self.official_ids.borrow_mut().mark_not_stale(); - } - } - Ok(false) - } - - fn get_token_by_ref_from_cache( - &self, - token_ref: &Option, - ) -> Result, FarmClientError> { - if let Some(pubkey) = token_ref { - let name = self.get_token_name(pubkey)?; - Ok(Some(self.get_token(&name)?)) - } else { - Ok(None) - } - } - - fn get_token_account(&self, wallet_address: &Pubkey, token: &Option) -> Option { - token.map(|token_info| get_associated_token_address(wallet_address, &token_info.mint)) - } - - fn pool_has_reverse_tokens(pool_name: &str, token_a: &str) -> Result { - let (_, pool_token_a, _) = FarmClient::extract_token_names(pool_name)?; - Ok(pool_token_a != token_a) - } - - fn get_raydium_stake_account( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ) -> Result { - let farm = self.get_farm(farm_name)?; - let farm_id = match farm.route { - FarmRoute::Raydium { farm_id, .. } => farm_id, - _ => unreachable!(), - }; - - // lookup in cache - let acc_key = farm_id.to_string(); - if let Some(addr_map) = self.stake_accounts.borrow()[0].get(&wallet_address.to_string()) { - if let Some(stake_acc) = addr_map.get(&acc_key) { - return Ok(*stake_acc); - } - } - - let mut stake_acc = None; - { - // search on-chain - let acc_vec = self.get_accounts_with_filter( - &farm.farm_program_id, - 40, - wallet_address.as_ref().to_vec(), - )?; - let user_acc_str = wallet_address.to_string(); - let stake_accounts_map = &mut self.stake_accounts.borrow_mut()[0]; - if !stake_accounts_map.contains_key(&user_acc_str) { - stake_accounts_map.insert(user_acc_str.clone(), StakeAccMap::new()); - } - let user_acc_map = stake_accounts_map.get_mut(&user_acc_str).unwrap(); - for (stake_acc_key, account) in acc_vec.iter() { - let farm_id_str = if farm.version >= 4 { - RaydiumUserStakeInfoV4::unpack(account.data.as_slice())? - .farm_id - .to_string() - } else { - RaydiumUserStakeInfo::unpack(account.data.as_slice())? - .farm_id - .to_string() - }; - user_acc_map.insert(farm_id_str.clone(), *stake_acc_key); - if farm_id_str == acc_key { - stake_acc = Some(*stake_acc_key); - } - } - } - - if let Some(acc) = stake_acc { - Ok(acc) - } else { - let stake_acc = Pubkey::find_program_address( - &[b"Miner", &farm_id.to_bytes(), &wallet_address.to_bytes()], - &farm.router_program_id, - ) - .0; - self.update_stake_accounts_cache(wallet_address, farm_name, &acc_key, &stake_acc)?; - Ok(stake_acc) - } - } - - fn get_saber_stake_account( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ) -> Result { - let farm = self.get_farm(farm_name)?; - let quarry = match farm.route { - FarmRoute::Saber { quarry, .. } => quarry, - _ => unreachable!(), - }; - - // lookup in cache - let acc_key = quarry.to_string(); - if let Some(addr_map) = self.stake_accounts.borrow()[1].get(&wallet_address.to_string()) { - if let Some(stake_acc) = addr_map.get(&acc_key) { - return Ok(*stake_acc); - } - } - - // update cache - let (miner, _) = Pubkey::find_program_address( - &[b"Miner", &quarry.to_bytes(), &wallet_address.to_bytes()], - &quarry_mine::id(), - ); - self.update_stake_accounts_cache(wallet_address, farm_name, &acc_key, &miner)?; - - Ok(miner) - } - - fn get_orca_stake_account( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ) -> Result { - let farm = self.get_farm(farm_name)?; - let farm_id = match farm.route { - FarmRoute::Orca { farm_id, .. } => farm_id, - _ => unreachable!(), - }; - - // lookup in cache - let acc_key = farm_id.to_string(); - if let Some(addr_map) = self.stake_accounts.borrow()[2].get(&wallet_address.to_string()) { - if let Some(stake_acc) = addr_map.get(&acc_key) { - return Ok(*stake_acc); - } - } - - // update cache - let farmer = Pubkey::find_program_address( - &[ - &farm_id.to_bytes(), - &wallet_address.to_bytes(), - &spl_token::id().to_bytes(), - ], - &farm.farm_program_id, - ) - .0; - self.update_stake_accounts_cache(wallet_address, farm_name, &acc_key, &farmer)?; - - Ok(farmer) - } - - fn update_stake_accounts_cache( - &self, - wallet_address: &Pubkey, - farm_name: &str, - acc_key: &str, - acc_address: &Pubkey, - ) -> Result<(), FarmClientError> { - let farm = self.get_farm(farm_name)?; - let index = match farm.route { - FarmRoute::Raydium { .. } => 0, - FarmRoute::Saber { .. } => 1, - FarmRoute::Orca { .. } => 2, - }; - let stake_accounts_map = &mut self.stake_accounts.borrow_mut()[index]; - let wallet_str = wallet_address.to_string(); - stake_accounts_map - .entry(wallet_str) - .or_insert_with(StakeAccMap::new); - let user_acc_map = stake_accounts_map - .get_mut(&wallet_address.to_string()) - .unwrap(); - user_acc_map.insert(acc_key.to_string(), *acc_address); - Ok(()) - } - - fn check_user_stake_account( - &self, - wallet_address: &Pubkey, - farm_name: &str, - instruction_vec: &mut Vec, - ) -> Result<(), FarmClientError> { - let farm = self.get_farm(farm_name)?; - let acc_address = match farm.route { - FarmRoute::Raydium { .. } => { - self.get_raydium_stake_account(wallet_address, farm_name)? - } - FarmRoute::Saber { .. } => self.get_saber_stake_account(wallet_address, farm_name)?, - FarmRoute::Orca { .. } => self.get_orca_stake_account(wallet_address, farm_name)?, - }; - let data = self.rpc_client.get_account_data(&acc_address); - if data.is_err() || data.unwrap().is_empty() { - instruction_vec.push(self.new_instruction_user_init(wallet_address, farm_name)?); - } - Ok(()) - } - - fn get_pool_price_raydium( - &self, - token_a_balance: u64, - token_b_balance: u64, - token_a_decimals: u8, - token_b_decimals: u8, - amm_id: &Pubkey, - amm_open_orders: &Pubkey, - ) -> Result { - // adjust with open orders - let mut token_a_balance = token_a_balance; - let mut token_b_balance = token_b_balance; - let open_orders_data = self.rpc_client.get_account_data(amm_open_orders)?; - if open_orders_data.len() == 3228 { - let base_token_total = array_ref![open_orders_data, 85, 8]; - let quote_token_total = array_ref![open_orders_data, 101, 8]; - - token_a_balance += u64::from_le_bytes(*base_token_total); - token_b_balance += u64::from_le_bytes(*quote_token_total); - } - - // adjust with amm take pnl - let amm_id_data = self.rpc_client.get_account_data(amm_id)?; - let (pnl_coin_offset, pnl_pc_offset) = if amm_id_data.len() == 624 { - (136, 144) - } else if amm_id_data.len() == 680 { - (144, 152) - } else if amm_id_data.len() == 752 { - (192, 200) - } else { - (0, 0) - }; - if pnl_coin_offset > 0 { - let need_take_pnl_coin = - u64::from_le_bytes(*array_ref![amm_id_data, pnl_coin_offset, 8]); - let need_take_pnl_pc = u64::from_le_bytes(*array_ref![amm_id_data, pnl_pc_offset, 8]); - - token_a_balance -= if need_take_pnl_coin < token_a_balance { - need_take_pnl_coin - } else { - token_a_balance - }; - token_b_balance -= if need_take_pnl_pc < token_b_balance { - need_take_pnl_pc - } else { - token_b_balance - }; - } - - if token_a_balance == 0 || token_b_balance == 0 { - Ok(0.0) - } else { - Ok( - self.tokens_to_ui_amount_with_decimals(token_b_balance, token_b_decimals) - / self.tokens_to_ui_amount_with_decimals(token_a_balance, token_a_decimals), - ) - } - } - - fn get_pool_price_saber( - &self, - swap_account: &Pubkey, - token_a_balance: u64, - token_b_balance: u64, - lp_token: &Token, - ) -> Result { - let swap_data = self.rpc_client.get_account_data(swap_account)?; - let swap_info = SwapInfo::unpack(swap_data.as_slice())?; - - let mint_data = self.rpc_client.get_account_data(&lp_token.mint)?; - let lp_mint = Mint::unpack(mint_data.as_slice())?; - - let swap = SaberSwap { - initial_amp_factor: swap_info.initial_amp_factor, - target_amp_factor: swap_info.target_amp_factor, - current_ts: chrono::Utc::now().timestamp(), - start_ramp_ts: swap_info.start_ramp_ts, - stop_ramp_ts: swap_info.stop_ramp_ts, - lp_mint_supply: lp_mint.supply, - token_a_reserve: token_a_balance, - token_b_reserve: token_b_balance, - }; - - if let Some(price) = swap.calculate_virtual_price_of_pool_tokens(1000000) { - Ok(price as f64 / 1000000.0) - } else { - Ok(0.0) - } - } - - fn get_pool_price_orca( - &self, - token_a_balance: u64, - token_b_balance: u64, - token_a_decimals: u8, - token_b_decimals: u8, - ) -> Result { - if token_a_balance == 0 || token_b_balance == 0 { - Ok(0.0) - } else { - Ok( - self.tokens_to_ui_amount_with_decimals(token_b_balance, token_b_decimals) - / self.tokens_to_ui_amount_with_decimals(token_a_balance, token_a_decimals), - ) - } - } - - fn send_sol_to_wsol( - &self, - wallet_address: &Pubkey, - ui_amount: f64, - instruction_vec: &mut Vec, - ) -> Result<(), FarmClientError> { - let token_addr = self.get_associated_token_address(wallet_address, "SOL")?; - instruction_vec.push(self.new_instruction_transfer( - wallet_address, - &token_addr, - ui_amount, - )?); - instruction_vec.push(self.new_instruction_sync_token_balance(wallet_address, "SOL")?); - Ok(()) - } - - fn check_token_account( - &self, - wallet_address: &Pubkey, - token: &Option, - ui_amount: f64, - instruction_vec: &mut Vec, - ) -> Result<(), FarmClientError> { - if let Some(tkn) = token { - if !self.has_active_token_account(wallet_address, &tkn.name) { - instruction_vec - .push(self.new_instruction_create_token_account(wallet_address, &tkn.name)?); - if ui_amount > 0.0 { - if tkn.token_type == TokenType::WrappedSol { - if self.get_account_balance(wallet_address)? < ui_amount { - return Err(FarmClientError::InsufficientBalance(tkn.name.to_string())); - } - let _ = - self.send_sol_to_wsol(wallet_address, ui_amount, instruction_vec)?; - } else { - return Err(FarmClientError::InsufficientBalance(tkn.name.to_string())); - } - } - } else if ui_amount > 0.0 { - let balance = self.get_token_account_balance(wallet_address, &tkn.name)?; - if balance < ui_amount { - if tkn.token_type == TokenType::WrappedSol { - if self.get_account_balance(wallet_address)? < ui_amount - balance { - return Err(FarmClientError::InsufficientBalance(tkn.name.to_string())); - } - let _ = self.send_sol_to_wsol( - wallet_address, - ui_amount - balance, - instruction_vec, - )?; - } else { - return Err(FarmClientError::InsufficientBalance(tkn.name.to_string())); - } - } - } - } - Ok(()) - } - - #[allow(clippy::too_many_arguments)] - fn check_pool_accounts( - &self, - wallet_address: &Pubkey, - pool_name: &str, - ui_amount_token_a: f64, - ui_amount_token_b: f64, - ui_amount_lp_token: f64, - check_lp_token: bool, - instruction_vec: &mut Vec, - ) -> Result<(), FarmClientError> { - let pool = self.get_pool(pool_name)?; - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - - if check_lp_token { - let _ = self.check_token_account( - wallet_address, - &lp_token, - ui_amount_lp_token, - instruction_vec, - )?; - } - let _ = - self.check_token_account(wallet_address, &token_a, ui_amount_token_a, instruction_vec)?; - let _ = - self.check_token_account(wallet_address, &token_b, ui_amount_token_b, instruction_vec)?; - - if let PoolRoute::Saber { - wrapped_token_a_ref, - wrapped_token_b_ref, - .. - } = pool.route - { - if let Some(token) = self.get_token_by_ref_from_cache(&wrapped_token_a_ref)? { - let _ = self.check_token_account_with_mint( - wallet_address, - &token.mint, - instruction_vec, - )?; - } - if let Some(token) = self.get_token_by_ref_from_cache(&wrapped_token_b_ref)? { - let _ = self.check_token_account_with_mint( - wallet_address, - &token.mint, - instruction_vec, - )?; - } - } - - Ok(()) - } - - fn check_token_account_with_mint( - &self, - wallet_address: &Pubkey, - mint: &Pubkey, - instruction_vec: &mut Vec, - ) -> Result<(), FarmClientError> { - let token_address = get_associated_token_address(wallet_address, mint); - if let Ok(data) = self.rpc_client.get_account_data(&token_address) { - if let Ok(TokenAccountType::Account(ui_account)) = parse_token(data.as_slice(), Some(0)) - { - if ui_account.state == UiAccountState::Initialized { - return Ok(()); - } - } - } - - instruction_vec.push(create_associated_token_account( - wallet_address, - wallet_address, - mint, - )); - Ok(()) - } - - fn check_farm_accounts( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ui_amount: f64, - instruction_vec: &mut Vec, - ) -> Result<(), FarmClientError> { - let farm = self.get_farm(farm_name)?; - let token_a = self.get_token_by_ref_from_cache(&farm.first_reward_token_ref)?; - let token_b = self.get_token_by_ref_from_cache(&farm.second_reward_token_ref)?; - let lp_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - - let _ = self.check_token_account(wallet_address, &token_a, 0.0, instruction_vec)?; - let _ = self.check_token_account(wallet_address, &token_b, 0.0, instruction_vec)?; - let _ = self.check_token_account(wallet_address, &lp_token, ui_amount, instruction_vec)?; - - let _ = self.check_user_stake_account(wallet_address, farm_name, instruction_vec)?; - - match farm.route { - FarmRoute::Saber { .. } => { - let user_info_account = self.get_stake_account(wallet_address, farm_name)?; - - let user_vault_account = self - .get_token_account(&user_info_account, &lp_token) - .ok_or(ProgramError::UninitializedAccount)?; - - let data = self.rpc_client.get_account_data(&user_vault_account); - if data.is_err() || data.unwrap().is_empty() { - instruction_vec.insert( - 0, - create_associated_token_account( - wallet_address, - &user_info_account, - &lp_token.unwrap().mint, - ), - ); - } - } - FarmRoute::Orca { farm_token_ref, .. } => { - let farm_lp_token = self.get_token_by_ref(&farm_token_ref)?; - let user_farm_lp_token_account = - get_associated_token_address(wallet_address, &farm_lp_token.mint); - let data = self - .rpc_client - .get_account_data(&user_farm_lp_token_account); - if data.is_err() || data.unwrap().is_empty() { - instruction_vec.insert( - 0, - create_associated_token_account( - wallet_address, - wallet_address, - &farm_lp_token.mint, - ), - ); - } - } - _ => {} - } - - Ok(()) - } - - #[allow(clippy::too_many_arguments)] - fn check_vault_accounts( - &self, - wallet_address: &Pubkey, - vault_name: &str, - ui_amount_token_a: f64, - ui_amount_token_b: f64, - ui_amount_vt_token: f64, - check_vt_token: bool, - check_lp_token: bool, - instruction_vec: &mut Vec, - ) -> Result<(), FarmClientError> { - let vault = self.get_vault(vault_name)?; - let vault_token = self.get_token_by_ref_from_cache(&Some(vault.vault_token_ref))?; - let pool = self.get_underlying_pool(vault_name)?; - let farm = self.get_underlying_farm(vault_name)?; - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - let token_a_reward = self.get_token_by_ref_from_cache(&farm.first_reward_token_ref)?; - let token_b_reward = self.get_token_by_ref_from_cache(&farm.second_reward_token_ref)?; - - if check_vt_token { - let _ = self.check_token_account( - wallet_address, - &vault_token, - ui_amount_vt_token, - instruction_vec, - )?; - } - if check_lp_token { - let _ = self.check_token_account(wallet_address, &lp_token, 0.0, instruction_vec)?; - } - let _ = - self.check_token_account(wallet_address, &token_a, ui_amount_token_a, instruction_vec)?; - let _ = - self.check_token_account(wallet_address, &token_b, ui_amount_token_b, instruction_vec)?; - - if token_a_reward.is_some() - && (token_a.is_none() || token_a.unwrap().name != token_a_reward.unwrap().name) - && (token_b.is_none() || token_b.unwrap().name != token_a_reward.unwrap().name) - { - let _ = - self.check_token_account(wallet_address, &token_a_reward, 0.0, instruction_vec)?; - } - if token_b_reward.is_some() - && (token_a.is_none() || token_a.unwrap().name != token_b_reward.unwrap().name) - && (token_b.is_none() || token_b.unwrap().name != token_b_reward.unwrap().name) - && (token_a_reward.is_none() - || token_a_reward.unwrap().name != token_b_reward.unwrap().name) - { - let _ = - self.check_token_account(wallet_address, &token_b_reward, 0.0, instruction_vec)?; - } - - if let PoolRoute::Saber { - wrapped_token_a_ref, - wrapped_token_b_ref, - .. - } = pool.route - { - if let Some(token) = self.get_token_by_ref_from_cache(&wrapped_token_a_ref)? { - let _ = self.check_token_account_with_mint( - wallet_address, - &token.mint, - instruction_vec, - )?; - } - if let Some(token) = self.get_token_by_ref_from_cache(&wrapped_token_b_ref)? { - let _ = self.check_token_account_with_mint( - wallet_address, - &token.mint, - instruction_vec, - )?; - } - } - - if self - .get_vault_user_info(wallet_address, vault_name) - .is_err() - { - instruction_vec.push(self.new_instruction_user_init_vault(wallet_address, vault_name)?); - } - - Ok(()) - } - - fn check_fund_accounts( - &self, - wallet_address: &Pubkey, - fund_name: &str, - token_name: &str, - ui_amount: f64, - instruction_vec: &mut Vec, - ) -> Result<(), FarmClientError> { - let fund = self.get_fund(fund_name)?; - let fund_token = Some(self.get_token_by_ref(&fund.fund_token_ref)?); - let asset_token = Some(self.get_token(token_name)?); - - let _ = self.check_token_account(wallet_address, &fund_token, 0.0, instruction_vec)?; - - let ui_amount = if ui_amount == 0.0 && token_name == "SOL" { - let balance = self.get_account_balance(wallet_address)?; - let min_balance = self.rpc_client.get_minimum_balance_for_rent_exemption(0)?; - let fees = self.rpc_client.get_fee_for_message(&Message::new( - &[self.new_instruction_transfer(wallet_address, wallet_address, 1.0)?], - None, - ))? * 10; - let to_leave = self.tokens_to_ui_amount(min_balance + fees, "SOL")?; - if balance > to_leave { - balance - to_leave - } else { - 0.0 - } - } else { - ui_amount - }; - let _ = - self.check_token_account(wallet_address, &asset_token, ui_amount, instruction_vec)?; - - if self - .get_fund_user_requests(wallet_address, fund_name, token_name) - .is_err() - { - instruction_vec.push(self.new_instruction_user_init_fund( - wallet_address, - fund_name, - token_name, - )?); - } - - Ok(()) - } - - fn is_wallet_single_fund_admin( - &self, - wallet_address: &Pubkey, - fund_name: &str, - ) -> Result { - let multisig = self.get_fund_admins(fund_name)?; - Ok(multisig.num_signers == 1 && &multisig.signers[0] == wallet_address) - } - - fn check_fund_custody( - &self, - wallet_address: &Pubkey, - fund_name: &str, - token_name: &str, - ui_amount: f64, - instruction_vec: &mut Vec, - ) -> Result<(), FarmClientError> { - if self - .get_fund_custody(fund_name, token_name, FundCustodyType::Trading) - .is_err() - { - if ui_amount > 0.0 { - return Err(FarmClientError::InsufficientBalance(token_name.to_string())); - } - if self.is_wallet_single_fund_admin(wallet_address, fund_name)? { - instruction_vec.push(self.new_instruction_add_fund_custody( - wallet_address, - fund_name, - token_name, - FundCustodyType::Trading, - )?); - } else { - return Err(FarmClientError::RecordNotFound(format!( - "Custody for token {} in the Fund {} not found", - token_name, fund_name - ))); - } - } else if ui_amount > 0.0 { - let token_account = self.get_fund_custody_token_account( - fund_name, - token_name, - FundCustodyType::Trading, - )?; - if self.get_token_account_balance_with_address(&token_account)? < ui_amount { - return Err(FarmClientError::InsufficientBalance(token_name.to_string())); - } - } - Ok(()) - } - - #[allow(clippy::too_many_arguments)] - fn check_fund_pool_custodies( - &self, - wallet_address: &Pubkey, - fund_name: &str, - pool_name: &str, - ui_amount_token_a: f64, - ui_amount_token_b: f64, - ui_amount_lp_token: f64, - check_lp_token: bool, - instruction_vec: &mut Vec, - ) -> Result<(), FarmClientError> { - let pool = self.get_pool(pool_name)?; - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - - if check_lp_token { - self.check_fund_custody( - wallet_address, - fund_name, - &lp_token.unwrap().name, - ui_amount_lp_token, - instruction_vec, - )?; - } - if token_a.is_some() { - self.check_fund_custody( - wallet_address, - fund_name, - &token_a.unwrap().name, - ui_amount_token_a, - instruction_vec, - )?; - } - if token_b.is_some() { - self.check_fund_custody( - wallet_address, - fund_name, - &token_b.unwrap().name, - ui_amount_token_b, - instruction_vec, - )?; - } - - Ok(()) - } - - fn check_fund_farm_custodies( - &self, - wallet_address: &Pubkey, - fund_name: &str, - farm_name: &str, - ui_amount: f64, - instruction_vec: &mut Vec, - ) -> Result<(), FarmClientError> { - let farm = self.get_farm(farm_name)?; - let token_a = self.get_token_by_ref_from_cache(&farm.first_reward_token_ref)?; - let token_b = self.get_token_by_ref_from_cache(&farm.second_reward_token_ref)?; - let lp_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - - if lp_token.is_some() { - self.check_fund_custody( - wallet_address, - fund_name, - &lp_token.unwrap().name, - ui_amount, - instruction_vec, - )?; - } - if token_a.is_some() { - self.check_fund_custody( - wallet_address, - fund_name, - &token_a.unwrap().name, - 0.0, - instruction_vec, - )?; - } - if token_b.is_some() { - self.check_fund_custody( - wallet_address, - fund_name, - &token_b.unwrap().name, - 0.0, - instruction_vec, - )?; - } - - self.check_fund_farm_user_account(wallet_address, fund_name, farm_name, instruction_vec) - } - - #[allow(clippy::too_many_arguments)] - fn check_fund_vault_custodies( - &self, - wallet_address: &Pubkey, - fund_name: &str, - vault_name: &str, - ui_amount_token_a: f64, - ui_amount_token_b: f64, - ui_amount_vt_token: f64, - check_vt_token: bool, - check_lp_token: bool, - instruction_vec: &mut Vec, - ) -> Result<(), FarmClientError> { - let vault = self.get_vault(vault_name)?; - let vault_token = self.get_token_by_ref_from_cache(&Some(vault.vault_token_ref))?; - let pool = self.get_underlying_pool(vault_name)?; - let farm = self.get_underlying_farm(vault_name)?; - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - let token_a_reward = self.get_token_by_ref_from_cache(&farm.first_reward_token_ref)?; - let token_b_reward = self.get_token_by_ref_from_cache(&farm.second_reward_token_ref)?; - - if check_vt_token { - self.check_fund_custody( - wallet_address, - fund_name, - &vault_token.unwrap().name, - ui_amount_vt_token, - instruction_vec, - )?; - } - if check_lp_token { - self.check_fund_custody( - wallet_address, - fund_name, - &lp_token.unwrap().name, - 0.0, - instruction_vec, - )?; - } - if token_a_reward.is_some() { - self.check_fund_custody( - wallet_address, - fund_name, - &token_a_reward.unwrap().name, - 0.0, - instruction_vec, - )?; - } - if token_b_reward.is_some() { - self.check_fund_custody( - wallet_address, - fund_name, - &token_b_reward.unwrap().name, - 0.0, - instruction_vec, - )?; - } - if token_a.is_some() { - self.check_fund_custody( - wallet_address, - fund_name, - &token_a.unwrap().name, - ui_amount_token_a, - instruction_vec, - )?; - } - if token_b.is_some() { - self.check_fund_custody( - wallet_address, - fund_name, - &token_b.unwrap().name, - ui_amount_token_b, - instruction_vec, - )?; - } - - self.check_fund_vault_user_account(wallet_address, fund_name, vault_name, instruction_vec) - } - - fn check_fund_farm_user_account( - &self, - wallet_address: &Pubkey, - fund_name: &str, - farm_name: &str, - instruction_vec: &mut Vec, - ) -> Result<(), FarmClientError> { - let fund = self.get_fund(fund_name)?; - let data = self - .rpc_client - .get_account_data(&self.get_stake_account(&fund.fund_authority, farm_name)?); - if data.is_err() || data.unwrap().is_empty() { - if &fund.fund_manager == wallet_address - || self.is_wallet_single_fund_admin(wallet_address, fund_name)? - { - instruction_vec.push(self.new_instruction_fund_user_init_farm( - wallet_address, - fund_name, - farm_name, - )?); - } else { - return Err(FarmClientError::RecordNotFound(format!( - "User is not initialized for the Farm {} in the Fund {}", - farm_name, fund_name - ))); - } - } - Ok(()) - } - - fn check_fund_vault_user_account( - &self, - wallet_address: &Pubkey, - fund_name: &str, - vault_name: &str, - instruction_vec: &mut Vec, - ) -> Result<(), FarmClientError> { - let fund = self.get_fund(fund_name)?; - let user_info_account = - self.get_vault_user_info_account(&fund.fund_authority, vault_name)?; - let data = self.rpc_client.get_account_data(&user_info_account); - if data.is_err() || !RefDB::is_initialized(data.unwrap().as_slice()) { - if &fund.fund_manager == wallet_address - || self.is_wallet_single_fund_admin(wallet_address, fund_name)? - { - instruction_vec.push(self.new_instruction_fund_user_init_vault( - wallet_address, - fund_name, - vault_name, - )?); - } else { - return Err(FarmClientError::RecordNotFound(format!( - "User is not initialized for the Vault {} in the Fund {}", - vault_name, fund_name - ))); - } - } - Ok(()) - } - - fn get_vault_lp_token_decimals(&self, vault_name: &str) -> Result { - let pool = self.get_underlying_pool(vault_name)?; - if let Some(pool_token) = self.get_token_by_ref_from_cache(&pool.lp_token_ref)? { - Ok(pool_token.decimals) - } else { - Err(FarmClientError::RecordNotFound(format!( - "LP token for {}", - vault_name - ))) - } - } - - // note: there could be multiple underlying pools in the future - fn get_underlying_pool(&self, vault_name: &str) -> Result { - let vault = self.get_vault(vault_name)?; - match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { pool_ref, .. } => { - self.get_pool_by_ref(&pool_ref) - } - VaultStrategy::DynamicHedge { .. } => self.get_pool_by_ref(&zero::id()), - } - } - - // note: there could be multiple underlying farms in the future - fn get_underlying_farm(&self, vault_name: &str) -> Result { - let vault = self.get_vault(vault_name)?; - match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { farm_ref, .. } => { - self.get_farm_by_ref(&farm_ref) - } - VaultStrategy::DynamicHedge { .. } => self.get_farm_by_ref(&zero::id()), - } - } - - fn get_vault_price(&self, vault_name: &str) -> Result { - let pool_name = self.get_underlying_pool(vault_name)?.name.to_string(); - self.get_pool_price(&pool_name) - } - - fn get_protocol_stats(&self, protocol: Protocol) -> Result<(u32, u32, u32), FarmClientError> { - let pools = self.get_pools()?; - let farms = self.get_farms()?; - let vaults = self.get_vaults()?; - let mut pools_num = 0u32; - let mut farms_num = 0u32; - let mut vaults_num = 0u32; - let protocol = protocol.id().to_string() + "."; - for name in pools.keys() { - if name.starts_with(&protocol) { - pools_num += 1; - } - } - for name in farms.keys() { - if name.starts_with(&protocol) { - farms_num += 1; - } - } - for name in vaults.keys() { - if name.starts_with(&protocol) { - vaults_num += 1; - } - } - Ok((pools_num, farms_num, vaults_num)) - } -} - -mod farm_accounts_orca; -mod farm_accounts_raydium; -mod farm_accounts_saber; -mod farm_instructions; -mod fund_instructions; -mod fund_instructions_pools; -mod governance_instructions; -mod main_router_instructions; -mod pool_accounts_orca; -mod pool_accounts_raydium; -mod pool_accounts_saber; -mod pool_instructions; -mod system_instructions; -mod vault_instructions; -mod vault_stc_accounts_orca; -mod vault_stc_accounts_raydium; -mod vault_stc_accounts_saber; - -#[cfg(test)] -mod test { - use super::*; - use solana_farm_sdk::string::{str_to_as64, ArrayString64}; - - #[test] - fn test_to_array_string() { - let arrstr: ArrayString64 = ArrayString64::try_from_str("test").unwrap(); - assert_eq!(arrstr, str_to_as64("test").unwrap()); - assert_eq!(arrstr.as_str(), "test"); - assert!(matches!( - ArrayString64::try_from_str( - "very long string, longer than 64 characters, conversion must fail" - ), - Err(_) - )); - } - - #[test] - fn test_extract_pool_version() { - assert_eq!(FarmClient::extract_pool_version("RDM.V-V3").unwrap(), 3); - assert_eq!(FarmClient::extract_pool_version("V-V3").unwrap(), 3); - assert_eq!(FarmClient::extract_pool_version("RDM.V-V-V3").unwrap(), 3); - assert!(FarmClient::extract_pool_version("RDM.V-3").is_err()); - assert!(FarmClient::extract_pool_version("RDM.V-V03").is_err()); - assert!(FarmClient::extract_pool_version("RDM.V-V").is_err()); - assert!(FarmClient::extract_pool_version("RDM.V-VV").is_err()); - assert!(FarmClient::extract_pool_version("RDM.V3").is_err()); - assert!(FarmClient::extract_pool_version("-V3").is_err()); - assert!(FarmClient::extract_pool_version("V3").is_err()); - assert!(FarmClient::extract_pool_version("3").is_err()); - } - - #[test] - fn test_extract_pool_name_and_version() { - assert_eq!( - FarmClient::extract_pool_name_and_version("RDM.Q-V-V3").unwrap(), - ("RDM.Q-V".to_string(), 3) - ); - assert_eq!( - FarmClient::extract_pool_name_and_version("RDM.Q-V1-V3").unwrap(), - ("RDM.Q-V1".to_string(), 3) - ); - assert_eq!( - FarmClient::extract_pool_name_and_version("RDM.Q-W-V-V3").unwrap(), - ("RDM.Q-W-V".to_string(), 3) - ); - assert_eq!( - FarmClient::extract_pool_name_and_version("LP.RDM.V-V3").unwrap(), - ("RDM.V".to_string(), 3) - ); - assert_eq!( - FarmClient::extract_pool_name_and_version("RDM.V-V3").unwrap(), - ("RDM.V".to_string(), 3) - ); - } - - #[test] - fn test_extract_token_names() { - assert_eq!( - FarmClient::extract_token_names("RDM.Q-V-V3").unwrap(), - (Protocol::Raydium, "Q".to_string(), "V".to_string()) - ); - assert_eq!( - FarmClient::extract_token_names("RDM.Q-V1-V3").unwrap(), - (Protocol::Raydium, "Q".to_string(), "V1".to_string()) - ); - assert_eq!( - FarmClient::extract_token_names("RDM.Q-W-V-V3").unwrap(), - (Protocol::Raydium, "Q".to_string(), "W".to_string()) - ); - assert_eq!( - FarmClient::extract_token_names("RDM.RAY-V3").unwrap(), - (Protocol::Raydium, "RAY".to_string(), String::default()) - ); - assert_eq!( - FarmClient::extract_token_names("LP.RDM.Q-V-V3").unwrap(), - (Protocol::Raydium, "Q".to_string(), "V".to_string()) - ); - assert_eq!( - FarmClient::extract_token_names("LP.RDM.Q-W-V-V3").unwrap(), - (Protocol::Raydium, "Q".to_string(), "W".to_string()) - ); - assert_eq!( - FarmClient::extract_token_names("LP.RDM.RAY-V3").unwrap(), - (Protocol::Raydium, "RAY".to_string(), String::default()) - ); - assert_eq!( - FarmClient::extract_token_names("RDM.Q-V").unwrap(), - (Protocol::Raydium, "Q".to_string(), "V".to_string()) - ); - assert_eq!( - FarmClient::extract_token_names("RDM.Q").unwrap(), - (Protocol::Raydium, "Q".to_string(), String::default()) - ); - assert_eq!( - FarmClient::extract_token_names("LP.RDM.Q-V").unwrap(), - (Protocol::Raydium, "Q".to_string(), "V".to_string()) - ); - } -} diff --git a/farms/farm-client/src/client/farm_accounts_orca.rs b/farms/farm-client/src/client/farm_accounts_orca.rs deleted file mode 100644 index 6524f2a97ee..00000000000 --- a/farms/farm-client/src/client/farm_accounts_orca.rs +++ /dev/null @@ -1,218 +0,0 @@ -//! Solana Farm Client Orca Farms accounts builder - -use { - crate::error::FarmClientError, - solana_farm_sdk::farm::FarmRoute, - solana_sdk::{ - instruction::AccountMeta, program_error::ProgramError, pubkey::Pubkey, system_program, - }, - std::vec::Vec, -}; - -use super::FarmClient; - -impl FarmClient { - /// Returns instruction accounts for initializing a new User in an Orca farm - pub fn get_user_init_accounts_orca( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ) -> Result, FarmClientError> { - // get farm info - let farm = self.get_farm(farm_name)?; - - let farm_id = match farm.route { - FarmRoute::Orca { farm_id, .. } => farm_id, - _ => unreachable!(), - }; - - let farmer = Pubkey::find_program_address( - &[ - &farm_id.to_bytes(), - &wallet_address.to_bytes(), - &spl_token::id().to_bytes(), - ], - &farm.farm_program_id, - ) - .0; - - let accounts = vec![ - AccountMeta::new(*wallet_address, true), - AccountMeta::new_readonly(*wallet_address, false), - AccountMeta::new(farmer, false), - AccountMeta::new_readonly(farm_id, false), - AccountMeta::new_readonly(farm.farm_program_id, false), - AccountMeta::new_readonly(system_program::id(), false), - ]; - - Ok(accounts) - } - - /// Returns instruction accounts for tokens staking in an Orca farm - pub fn get_stake_accounts_orca( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ) -> Result, FarmClientError> { - // get farm info - let farm = self.get_farm(farm_name)?; - - // get tokens info - let token_a = self.get_token_by_ref_from_cache(&farm.first_reward_token_ref)?; - let lp_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - - // get user accounts info - let user_reward_token_account = self.get_token_account(wallet_address, &token_a); - let user_lp_token_account = self.get_token_account(wallet_address, &lp_token); - - // fill in accounts - let mut accounts = vec![]; - if let FarmRoute::Orca { - farm_id, - farm_authority, - farm_token_ref, - base_token_vault, - reward_token_vault, - } = farm.route - { - let user_info_account = self.get_stake_account(wallet_address, farm_name)?; - let farm_lp_token = self.get_token_by_ref_from_cache(&Some(farm_token_ref))?; - let user_farm_lp_token_account = self.get_token_account(wallet_address, &farm_lp_token); - - accounts.push(AccountMeta::new_readonly(*wallet_address, true)); - accounts.push(AccountMeta::new(user_info_account, false)); - accounts.push(AccountMeta::new( - user_lp_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_reward_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_farm_lp_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - farm_lp_token - .ok_or(ProgramError::UninitializedAccount)? - .mint, - false, - )); - accounts.push(AccountMeta::new_readonly(farm.farm_program_id, false)); - accounts.push(AccountMeta::new(base_token_vault, false)); - accounts.push(AccountMeta::new(reward_token_vault, false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new(farm_id, false)); - accounts.push(AccountMeta::new_readonly(farm_authority, false)); - } - - Ok(accounts) - } - - /// Returns instruction accounts for unstaking tokens from an Orca farm - pub fn get_unstake_accounts_orca( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ) -> Result, FarmClientError> { - // get farm info - let farm = self.get_farm(farm_name)?; - - // get tokens info - let token_a = self.get_token_by_ref_from_cache(&farm.first_reward_token_ref)?; - let lp_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - - // get user accounts info - let user_reward_token_account = self.get_token_account(wallet_address, &token_a); - let user_lp_token_account = self.get_token_account(wallet_address, &lp_token); - - // fill in accounts - let mut accounts = vec![]; - if let FarmRoute::Orca { - farm_id, - farm_authority, - farm_token_ref, - base_token_vault, - reward_token_vault, - } = farm.route - { - let user_info_account = self.get_stake_account(wallet_address, farm_name)?; - let farm_lp_token = self.get_token_by_ref_from_cache(&Some(farm_token_ref))?; - let user_farm_lp_token_account = self.get_token_account(wallet_address, &farm_lp_token); - - accounts.push(AccountMeta::new_readonly(*wallet_address, true)); - accounts.push(AccountMeta::new(user_info_account, false)); - accounts.push(AccountMeta::new( - user_lp_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_reward_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_farm_lp_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - farm_lp_token - .ok_or(ProgramError::UninitializedAccount)? - .mint, - false, - )); - accounts.push(AccountMeta::new_readonly(farm.farm_program_id, false)); - accounts.push(AccountMeta::new(base_token_vault, false)); - accounts.push(AccountMeta::new(reward_token_vault, false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new(farm_id, false)); - accounts.push(AccountMeta::new_readonly(farm_authority, false)); - } - - Ok(accounts) - } - - /// Returns instruction accounts for rewards harvesting in an Orca farm - pub fn get_harvest_accounts_orca( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ) -> Result, FarmClientError> { - // get farm info - let farm = self.get_farm(farm_name)?; - - // get tokens info - let token_a = self.get_token_by_ref_from_cache(&farm.first_reward_token_ref)?; - - // get user accounts info - let user_reward_token_account = self.get_token_account(wallet_address, &token_a); - - // fill in accounts - let mut accounts = vec![]; - if let FarmRoute::Orca { - farm_id, - farm_authority, - farm_token_ref: _, - base_token_vault, - reward_token_vault, - } = farm.route - { - let user_info_account = self.get_stake_account(wallet_address, farm_name)?; - - accounts.push(AccountMeta::new_readonly(*wallet_address, true)); - accounts.push(AccountMeta::new(user_info_account, false)); - accounts.push(AccountMeta::new( - user_reward_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new_readonly(farm.farm_program_id, false)); - accounts.push(AccountMeta::new(base_token_vault, false)); - accounts.push(AccountMeta::new(reward_token_vault, false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new(farm_id, false)); - accounts.push(AccountMeta::new_readonly(farm_authority, false)); - } - - Ok(accounts) - } -} diff --git a/farms/farm-client/src/client/farm_accounts_raydium.rs b/farms/farm-client/src/client/farm_accounts_raydium.rs deleted file mode 100644 index 76831b7f317..00000000000 --- a/farms/farm-client/src/client/farm_accounts_raydium.rs +++ /dev/null @@ -1,186 +0,0 @@ -//! Solana Farm Client Raydium Farms accounts builder - -use { - crate::error::FarmClientError, - solana_farm_sdk::{farm::FarmRoute, id::zero}, - solana_sdk::{ - instruction::AccountMeta, program_error::ProgramError, pubkey::Pubkey, system_program, - sysvar, - }, - std::vec::Vec, -}; - -use super::FarmClient; - -impl FarmClient { - /// Returns instruction accounts for initializing a new User in a Raydium farm - pub fn get_user_init_accounts_raydium( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ) -> Result, FarmClientError> { - // get farm info - let farm = self.get_farm(farm_name)?; - let farm_metadata = self.get_farm_ref(farm_name)?; - - let farm_id = match farm.route { - FarmRoute::Raydium { farm_id, .. } => farm_id, - _ => unreachable!(), - }; - - let farmer = Pubkey::find_program_address( - &[b"Miner", &farm_id.to_bytes(), &wallet_address.to_bytes()], - &farm.router_program_id, - ) - .0; - - let accounts = vec![ - AccountMeta::new(*wallet_address, true), - AccountMeta::new_readonly(*wallet_address, false), - AccountMeta::new(farmer, false), - AccountMeta::new_readonly(farm_metadata, false), - AccountMeta::new_readonly(system_program::id(), false), - ]; - - Ok(accounts) - } - - /// Returns instruction accounts for tokens staking in a Raydium farm - pub fn get_stake_accounts_raydium( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ) -> Result, FarmClientError> { - // get farm info - let farm = self.get_farm(farm_name)?; - - // get tokens info - let token_a = self.get_token_by_ref_from_cache(&farm.first_reward_token_ref)?; - let token_b = self.get_token_by_ref_from_cache(&farm.second_reward_token_ref)?; - let lp_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - - // get user accounts info - let user_first_reward_token_account = self.get_token_account(wallet_address, &token_a); - let user_second_reward_token_account = self.get_token_account(wallet_address, &token_b); - let user_lp_token_account = self.get_token_account(wallet_address, &lp_token); - - // fill in accounts - let mut accounts = vec![]; - if let FarmRoute::Raydium { - farm_id, - farm_authority, - farm_lp_token_account, - farm_first_reward_token_account, - farm_second_reward_token_account, - } = farm.route - { - let user_info_account = self.get_stake_account(wallet_address, farm_name)?; - - accounts.push(AccountMeta::new_readonly(*wallet_address, true)); - accounts.push(AccountMeta::new(user_info_account, false)); - accounts.push(AccountMeta::new( - user_lp_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_first_reward_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_second_reward_token_account - .or_else(|| Some(zero::id())) - .unwrap(), - false, - )); - accounts.push(AccountMeta::new_readonly(farm.farm_program_id, false)); - accounts.push(AccountMeta::new(farm_lp_token_account, false)); - accounts.push(AccountMeta::new(farm_first_reward_token_account, false)); - accounts.push(AccountMeta::new( - farm_second_reward_token_account - .or_else(|| Some(zero::id())) - .unwrap(), - false, - )); - accounts.push(AccountMeta::new_readonly(sysvar::clock::id(), false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new(farm_id, false)); - accounts.push(AccountMeta::new_readonly(farm_authority, false)); - } - - Ok(accounts) - } - - /// Returns instruction accounts for unstaking tokens from a Raydium farm - pub fn get_unstake_accounts_raydium( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ) -> Result, FarmClientError> { - // get farm info - let farm = self.get_farm(farm_name)?; - - // get tokens info - let token_a = self.get_token_by_ref_from_cache(&farm.first_reward_token_ref)?; - let token_b = self.get_token_by_ref_from_cache(&farm.second_reward_token_ref)?; - let lp_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - - // get user accounts info - let user_first_reward_token_account = self.get_token_account(wallet_address, &token_a); - let user_second_reward_token_account = self.get_token_account(wallet_address, &token_b); - let user_lp_token_account = self.get_token_account(wallet_address, &lp_token); - - // fill in accounts - let mut accounts = vec![]; - if let FarmRoute::Raydium { - farm_id, - farm_authority, - farm_lp_token_account, - farm_first_reward_token_account, - farm_second_reward_token_account, - } = farm.route - { - let user_info_account = self.get_stake_account(wallet_address, farm_name)?; - - accounts.push(AccountMeta::new_readonly(*wallet_address, true)); - accounts.push(AccountMeta::new(user_info_account, false)); - accounts.push(AccountMeta::new( - user_lp_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_first_reward_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_second_reward_token_account - .or_else(|| Some(zero::id())) - .unwrap(), - false, - )); - accounts.push(AccountMeta::new_readonly(farm.farm_program_id, false)); - accounts.push(AccountMeta::new(farm_lp_token_account, false)); - accounts.push(AccountMeta::new(farm_first_reward_token_account, false)); - accounts.push(AccountMeta::new( - farm_second_reward_token_account - .or_else(|| Some(zero::id())) - .unwrap(), - false, - )); - accounts.push(AccountMeta::new_readonly(sysvar::clock::id(), false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new(farm_id, false)); - accounts.push(AccountMeta::new_readonly(farm_authority, false)); - } - - Ok(accounts) - } - - /// Returns instruction accounts for rewards harvesting in a Raydium farm - pub fn get_harvest_accounts_raydium( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ) -> Result, FarmClientError> { - self.get_stake_accounts_raydium(wallet_address, farm_name) - } -} diff --git a/farms/farm-client/src/client/farm_accounts_saber.rs b/farms/farm-client/src/client/farm_accounts_saber.rs deleted file mode 100644 index acdd4b28c64..00000000000 --- a/farms/farm-client/src/client/farm_accounts_saber.rs +++ /dev/null @@ -1,218 +0,0 @@ -//! Solana Farm Client Saber Farms accounts builder - -use { - crate::error::FarmClientError, - solana_farm_sdk::{farm::FarmRoute, id::zero}, - solana_sdk::{ - instruction::AccountMeta, program_error::ProgramError, pubkey::Pubkey, system_program, - }, - std::vec::Vec, -}; - -use super::FarmClient; - -impl FarmClient { - /// Returns instruction accounts for initializing a new User in a Saber farm - pub fn get_user_init_accounts_saber( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ) -> Result, FarmClientError> { - // get farm info - let farm = self.get_farm(farm_name)?; - - let (quarry, rewarder) = match farm.route { - FarmRoute::Saber { - quarry, rewarder, .. - } => (quarry, rewarder), - _ => unreachable!(), - }; - - let lp_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - let lp_mint = lp_token.ok_or(ProgramError::UninitializedAccount)?.mint; - - let (miner, _) = Pubkey::find_program_address( - &[b"Miner", &quarry.to_bytes(), &wallet_address.to_bytes()], - &quarry_mine::id(), - ); - - let miner_vault = - spl_associated_token_account::get_associated_token_address(&miner, &lp_mint); - - let accounts = vec![ - AccountMeta::new(*wallet_address, true), - AccountMeta::new_readonly(*wallet_address, false), - AccountMeta::new_readonly(farm.farm_program_id, false), - AccountMeta::new(lp_mint, false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new_readonly(system_program::id(), false), - AccountMeta::new(miner, false), - AccountMeta::new(miner_vault, false), - AccountMeta::new(quarry, false), - AccountMeta::new(rewarder, false), - ]; - - Ok(accounts) - } - - /// Returns instruction accounts for tokens staking in a Saber farm - pub fn get_stake_accounts_saber( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ) -> Result, FarmClientError> { - // get farm info - let farm = self.get_farm(farm_name)?; - - // get tokens info - let lp_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - - // get user accounts info - let user_lp_token_account = self.get_token_account(wallet_address, &lp_token); - - // fill in accounts - let mut accounts = vec![]; - if let FarmRoute::Saber { - quarry, rewarder, .. - } = farm.route - { - let user_info_account = self.get_stake_account(wallet_address, farm_name)?; - let user_vault_account = self - .get_token_account(&user_info_account, &lp_token) - .ok_or(ProgramError::UninitializedAccount)?; - - accounts.push(AccountMeta::new_readonly(*wallet_address, true)); - accounts.push(AccountMeta::new( - user_lp_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new_readonly(farm.farm_program_id, false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new(user_info_account, false)); - accounts.push(AccountMeta::new(user_vault_account, false)); - accounts.push(AccountMeta::new(quarry, false)); - accounts.push(AccountMeta::new_readonly(rewarder, false)); - } - - Ok(accounts) - } - - /// Returns instruction accounts for unstaking tokens from a Saber farm - pub fn get_unstake_accounts_saber( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ) -> Result, FarmClientError> { - // get farm info - let farm = self.get_farm(farm_name)?; - - // get tokens info - let lp_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - - // get user accounts info - let user_lp_token_account = self.get_token_account(wallet_address, &lp_token); - - // fill in accounts - let mut accounts = vec![]; - if let FarmRoute::Saber { - quarry, rewarder, .. - } = farm.route - { - let user_info_account = self.get_stake_account(wallet_address, farm_name)?; - let user_vault_account = self - .get_token_account(&user_info_account, &lp_token) - .ok_or(ProgramError::UninitializedAccount)?; - - accounts.push(AccountMeta::new_readonly(*wallet_address, true)); - accounts.push(AccountMeta::new( - user_lp_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new_readonly(farm.farm_program_id, false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new(user_info_account, false)); - accounts.push(AccountMeta::new(user_vault_account, false)); - accounts.push(AccountMeta::new(quarry, false)); - accounts.push(AccountMeta::new_readonly(rewarder, false)); - } - - Ok(accounts) - } - - /// Returns instruction accounts for rewards harvesting in a Saber farm - pub fn get_harvest_accounts_saber( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ) -> Result, FarmClientError> { - // get farm info - let farm = self.get_farm(farm_name)?; - - // get tokens info - let sbr_token = self.get_token_by_ref_from_cache(&farm.first_reward_token_ref)?; - let iou_token = self.get_token_by_ref_from_cache(&farm.second_reward_token_ref)?; - - // get user accounts info - let user_sbr_token_account = self.get_token_account(wallet_address, &sbr_token); - let user_iou_token_account = self.get_token_account(wallet_address, &iou_token); - - // fill in accounts - let mut accounts = vec![]; - if let FarmRoute::Saber { - quarry, - rewarder, - redeemer, - redeemer_program, - minter, - mint_wrapper, - mint_wrapper_program, - iou_fees_account, - sbr_vault, - mint_proxy_program, - mint_proxy_authority, - mint_proxy_state, - minter_info, - } = farm.route - { - let user_info_account = self.get_stake_account(wallet_address, farm_name)?; - - accounts.push(AccountMeta::new_readonly(*wallet_address, true)); - accounts.push(AccountMeta::new( - user_iou_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_sbr_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new_readonly(farm.farm_program_id, false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new(zero::id(), false)); - accounts.push(AccountMeta::new(user_info_account, false)); - - accounts.push(AccountMeta::new_readonly(rewarder, false)); - accounts.push(AccountMeta::new_readonly(redeemer, false)); - accounts.push(AccountMeta::new_readonly(redeemer_program, false)); - accounts.push(AccountMeta::new(minter, false)); - accounts.push(AccountMeta::new(mint_wrapper, false)); - accounts.push(AccountMeta::new_readonly(mint_wrapper_program, false)); - accounts.push(AccountMeta::new( - sbr_token.ok_or(ProgramError::UninitializedAccount)?.mint, - false, - )); - accounts.push(AccountMeta::new( - iou_token.ok_or(ProgramError::UninitializedAccount)?.mint, - false, - )); - accounts.push(AccountMeta::new(iou_fees_account, false)); - accounts.push(AccountMeta::new(quarry, false)); - accounts.push(AccountMeta::new(sbr_vault, false)); - accounts.push(AccountMeta::new_readonly(mint_proxy_program, false)); - accounts.push(AccountMeta::new_readonly(mint_proxy_authority, false)); - accounts.push(AccountMeta::new_readonly(mint_proxy_state, false)); - accounts.push(AccountMeta::new(minter_info, false)); - } - - Ok(accounts) - } -} diff --git a/farms/farm-client/src/client/farm_instructions.rs b/farms/farm-client/src/client/farm_instructions.rs deleted file mode 100644 index 68df3adb466..00000000000 --- a/farms/farm-client/src/client/farm_instructions.rs +++ /dev/null @@ -1,178 +0,0 @@ -//! Solana Farm Client Farm Instructions - -use { - crate::error::FarmClientError, - solana_farm_sdk::{farm::FarmRoute, instruction::amm::AmmInstruction}, - solana_sdk::{instruction::Instruction, pubkey::Pubkey}, -}; - -use super::FarmClient; - -impl FarmClient { - /// Creates a new Instruction for initializing a new User in the Farm - pub fn new_instruction_user_init( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ) -> Result { - // get farm info - let farm = self.get_farm(farm_name)?; - - // fill in accounts and instruction data - let data = AmmInstruction::UserInit.to_vec()?; - - let accounts = match farm.route { - FarmRoute::Raydium { .. } => { - self.get_user_init_accounts_raydium(wallet_address, farm_name)? - } - FarmRoute::Saber { .. } => { - self.get_user_init_accounts_saber(wallet_address, farm_name)? - } - FarmRoute::Orca { .. } => { - self.get_user_init_accounts_orca(wallet_address, farm_name)? - } - }; - - Ok(Instruction { - program_id: farm.router_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for tokens staking - pub fn new_instruction_stake( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ui_amount: f64, - ) -> Result { - // get farm info - let farm = self.get_farm(farm_name)?; - let lp_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - - // fill in accounts and instruction data - let data = AmmInstruction::Stake { - amount: self.to_token_amount_option(ui_amount, &lp_token)?, - } - .to_vec()?; - - let accounts = match farm.route { - FarmRoute::Raydium { .. } => { - self.get_stake_accounts_raydium(wallet_address, farm_name)? - } - FarmRoute::Saber { .. } => self.get_stake_accounts_saber(wallet_address, farm_name)?, - FarmRoute::Orca { .. } => self.get_stake_accounts_orca(wallet_address, farm_name)?, - }; - - Ok(Instruction { - program_id: farm.router_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for tokens unstaking - pub fn new_instruction_unstake( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ui_amount: f64, - ) -> Result { - // get farm info - let farm = self.get_farm(farm_name)?; - let lp_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - - // fill in accounts and instruction data - let data = AmmInstruction::Unstake { - amount: self.to_token_amount_option(ui_amount, &lp_token)?, - } - .to_vec()?; - - let accounts = match farm.route { - FarmRoute::Raydium { .. } => { - self.get_unstake_accounts_raydium(wallet_address, farm_name)? - } - FarmRoute::Saber { .. } => { - self.get_unstake_accounts_saber(wallet_address, farm_name)? - } - FarmRoute::Orca { .. } => self.get_unstake_accounts_orca(wallet_address, farm_name)?, - }; - - Ok(Instruction { - program_id: farm.router_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for rewards harvesting - pub fn new_instruction_harvest( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ) -> Result { - // get farm info - let farm = self.get_farm(farm_name)?; - - // fill in accounts and instruction data - let data = AmmInstruction::Harvest.to_vec()?; - - let accounts = match farm.route { - FarmRoute::Raydium { .. } => { - self.get_harvest_accounts_raydium(wallet_address, farm_name)? - } - FarmRoute::Saber { .. } => { - self.get_harvest_accounts_saber(wallet_address, farm_name)? - } - FarmRoute::Orca { .. } => self.get_harvest_accounts_orca(wallet_address, farm_name)?, - }; - - Ok(Instruction { - program_id: farm.router_program_id, - data, - accounts, - }) - } - - /// Creates a new complete set of Instructions for staking tokens to the Farm - pub fn all_instructions_stake( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ui_amount: f64, - ) -> Result, FarmClientError> { - let mut inst = Vec::::new(); - self.check_farm_accounts(wallet_address, farm_name, ui_amount, &mut inst)?; - inst.push(self.new_instruction_stake(wallet_address, farm_name, ui_amount)?); - - Ok(inst) - } - - /// Creates a new complete set of Instructions for unstaking tokens from the Farm - pub fn all_instructions_unstake( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ui_amount: f64, - ) -> Result, FarmClientError> { - let mut inst = Vec::::new(); - self.check_farm_accounts(wallet_address, farm_name, 0.0, &mut inst)?; - inst.push(self.new_instruction_unstake(wallet_address, farm_name, ui_amount)?); - - Ok(inst) - } - - /// Creates a new complete set of Instructions for harvesting rewards from the Farm - pub fn all_instructions_harvest( - &self, - wallet_address: &Pubkey, - farm_name: &str, - ) -> Result, FarmClientError> { - let mut inst = Vec::::new(); - self.check_farm_accounts(wallet_address, farm_name, 0.0, &mut inst)?; - inst.push(self.new_instruction_harvest(wallet_address, farm_name)?); - - Ok(inst) - } -} diff --git a/farms/farm-client/src/client/fund_instructions.rs b/farms/farm-client/src/client/fund_instructions.rs deleted file mode 100644 index 693d8901e79..00000000000 --- a/farms/farm-client/src/client/fund_instructions.rs +++ /dev/null @@ -1,1563 +0,0 @@ -//! Solana Farm Client Fund Instructions - -use { - crate::error::FarmClientError, - solana_farm_sdk::{ - farm::FarmRoute, - fund::{ - FundAssetType, FundAssetsTrackingConfig, FundCustodyType, FundSchedule, FundVaultType, - }, - id::zero, - instruction::fund::FundInstruction, - math, - pool::PoolRoute, - program::multisig::Multisig, - string::str_to_as64, - token::OracleType, - vault::VaultStrategy, - }, - solana_sdk::{ - instruction::{AccountMeta, Instruction}, - program_error::ProgramError, - pubkey::Pubkey, - system_program, sysvar, - }, -}; - -use super::FarmClient; - -impl FarmClient { - /// Creates a new Fund Init Instruction - pub fn new_instruction_init_fund( - &self, - admin_address: &Pubkey, - fund_name: &str, - step: u64, - ) -> Result { - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - let fund_token = self.get_token_by_ref(&fund.fund_token_ref)?; - - // fill in accounts and instruction data - let data = FundInstruction::Init { step }.to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new(self.get_fund_active_multisig_account(fund_name)?, false), - AccountMeta::new(fund.fund_authority, false), - AccountMeta::new_readonly(fund.fund_program_id, false), - AccountMeta::new_readonly(system_program::id(), false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - AccountMeta::new(fund_token.mint, false), - AccountMeta::new_readonly(fund.fund_token_ref, false), - AccountMeta::new(fund.vaults_assets_info, false), - AccountMeta::new(fund.custodies_assets_info, false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for initializing a new User for the Fund - pub fn new_instruction_user_init_fund( - &self, - wallet_address: &Pubkey, - fund_name: &str, - token_name: &str, - ) -> Result { - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - let token_ref = self.get_token_ref(token_name)?; - let user_info_account = self.get_fund_user_info_account(wallet_address, fund_name)?; - let user_requests_account = - self.get_fund_user_requests_account(wallet_address, fund_name, token_name)?; - - // fill in accounts and instruction data - let data = FundInstruction::UserInit.to_vec()?; - let accounts = vec![ - AccountMeta::new(*wallet_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new_readonly(*wallet_address, false), - AccountMeta::new(user_info_account, false), - AccountMeta::new(user_requests_account, false), - AccountMeta::new_readonly(token_ref, false), - AccountMeta::new_readonly(system_program::id(), false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new instruction for initializing Fund's multisig with a new set of signers - pub fn new_instruction_set_fund_admins( - &self, - admin_address: &Pubkey, - fund_name: &str, - admin_signers: &[Pubkey], - min_signatures: u8, - ) -> Result { - if admin_signers.is_empty() || min_signatures == 0 { - return Err(FarmClientError::ValueError( - "At least one signer is required".to_string(), - )); - } else if min_signatures as usize > admin_signers.len() - || admin_signers.len() > Multisig::MAX_SIGNERS - { - return Err(FarmClientError::ValueError( - "Invalid number of signatures".to_string(), - )); - } - - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - - // fill in accounts and instruction data - let mut inst = Instruction { - program_id: fund.fund_program_id, - data: FundInstruction::SetAdminSigners { min_signatures }.to_vec()?, - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new(self.get_fund_active_multisig_account(fund_name)?, false), - AccountMeta::new(self.get_fund_multisig_account(fund_name)?, false), - AccountMeta::new_readonly(system_program::id(), false), - ], - }; - - for key in admin_signers { - inst.accounts.push(AccountMeta::new_readonly(*key, false)); - } - - Ok(inst) - } - - /// Creates a new instruction for removing Fund's multisig - pub fn new_instruction_remove_fund_multisig( - &self, - admin_address: &Pubkey, - fund_name: &str, - ) -> Result { - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - - // fill in accounts and instruction data - let inst = Instruction { - program_id: fund.fund_program_id, - data: FundInstruction::RemoveMultisig.to_vec()?, - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new(self.get_fund_active_multisig_account(fund_name)?, false), - AccountMeta::new(self.get_fund_multisig_account(fund_name)?, false), - ], - }; - - Ok(inst) - } - - /// Creates a new set fund assets tracking config Instruction - pub fn new_instruction_set_fund_assets_tracking_config( - &self, - admin_address: &Pubkey, - fund_name: &str, - config: &FundAssetsTrackingConfig, - ) -> Result { - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - - // fill in accounts and instruction data - let data = FundInstruction::SetAssetsTrackingConfig { config: *config }.to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new(self.get_fund_active_multisig_account(fund_name)?, false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for adding a new custody to the Fund - pub fn new_instruction_add_fund_custody( - &self, - admin_address: &Pubkey, - fund_name: &str, - token_name: &str, - custody_type: FundCustodyType, - ) -> Result { - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - let token = self.get_token(token_name)?; - let token_ref = self.get_token_ref(token_name)?; - - // get custodies - let custodies = self.get_fund_custodies(fund_name)?; - let custody_metadata = - self.get_fund_custody_account(fund_name, token_name, custody_type)?; - let fund_assets_account = - self.get_fund_assets_account(fund_name, FundAssetType::Custody)?; - let custody_token_account = - self.get_fund_custody_token_account(fund_name, token_name, custody_type)?; - let custody_fees_token_account = - self.get_fund_custody_fees_token_account(fund_name, token_name, custody_type)?; - - // instruction params - let custody_id = if custodies.is_empty() { - 0 - } else if custodies.last().unwrap().custody_id < u32::MAX { - custodies.last().unwrap().custody_id + 1 - } else { - return Err(FarmClientError::ValueError( - "Number of custodies are over the limit".to_string(), - )); - }; - - let current_hash = self - .get_fund_assets(fund_name, FundAssetType::Custody)? - .target_hash; - - let target_hash = if FarmClient::is_liquidity_token(token_name) { - current_hash - } else { - math::hash_address(current_hash, &custody_token_account) - }; - - // fill in accounts and instruction data - let data = FundInstruction::AddCustody { - target_hash, - custody_id, - custody_type, - } - .to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new(self.get_fund_active_multisig_account(fund_name)?, false), - AccountMeta::new(self.get_fund_multisig_account(fund_name)?, false), - AccountMeta::new_readonly(fund.fund_authority, false), - AccountMeta::new_readonly(system_program::id(), false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new_readonly(spl_associated_token_account::id(), false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - AccountMeta::new(fund_assets_account, false), - AccountMeta::new(custody_token_account, false), - AccountMeta::new(custody_fees_token_account, false), - AccountMeta::new(custody_metadata, false), - AccountMeta::new_readonly(token_ref, false), - AccountMeta::new(token.mint, false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for removing the custody from the Fund - pub fn new_instruction_remove_fund_custody( - &self, - admin_address: &Pubkey, - fund_name: &str, - token_name: &str, - custody_type: FundCustodyType, - ) -> Result { - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - let token_ref = self.get_token_ref(token_name)?; - - // get custodies - let custodies = self.get_fund_custodies(fund_name)?; - if custodies.is_empty() { - return Err(FarmClientError::ValueError( - "No active custodies found".to_string(), - )); - } - let custody_metadata = - self.get_fund_custody_account(fund_name, token_name, custody_type)?; - let fund_assets_account = - self.get_fund_assets_account(fund_name, FundAssetType::Custody)?; - let custody_token_account = - self.get_fund_custody_token_account(fund_name, token_name, custody_type)?; - let custody_fees_token_account = - self.get_fund_custody_fees_token_account(fund_name, token_name, custody_type)?; - - // instruction params - let mut target_hash = 0; - for custody in custodies { - if custody.address != custody_token_account && !custody.is_vault_token { - target_hash = math::hash_address(target_hash, &custody.address); - } - } - - // fill in accounts and instruction data - let data = FundInstruction::RemoveCustody { - target_hash, - custody_type, - } - .to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new(self.get_fund_active_multisig_account(fund_name)?, false), - AccountMeta::new(self.get_fund_multisig_account(fund_name)?, false), - AccountMeta::new_readonly(fund.fund_authority, false), - AccountMeta::new_readonly(system_program::id(), false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new(fund_assets_account, false), - AccountMeta::new(custody_token_account, false), - AccountMeta::new(custody_fees_token_account, false), - AccountMeta::new(custody_metadata, false), - AccountMeta::new_readonly(token_ref, false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for adding a new Vault to the Fund - pub fn new_instruction_add_fund_vault( - &self, - admin_address: &Pubkey, - fund_name: &str, - vault_name: &str, - vault_type: FundVaultType, - ) -> Result { - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - - // get vaults - let vaults = self.get_fund_vaults(fund_name)?; - let fund_vault_metadata = self.get_fund_vault_account(fund_name, vault_name, vault_type)?; - let fund_assets_account = self.get_fund_assets_account(fund_name, FundAssetType::Vault)?; - let target_vault_metadata = match vault_type { - FundVaultType::Vault => self.get_vault_ref(vault_name)?, - FundVaultType::Pool => self.get_pool_ref(vault_name)?, - FundVaultType::Farm => self.get_farm_ref(vault_name)?, - }; - let underlying_pool_ref = match vault_type { - FundVaultType::Vault => { - let vault = self.get_vault(vault_name)?; - match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { pool_ref, .. } => pool_ref, - _ => unreachable!(), - } - } - FundVaultType::Farm => { - let farm = self.get_farm(vault_name)?; - let lp_token = self.get_token_by_ref(&farm.lp_token_ref.ok_or_else(|| { - FarmClientError::ValueError("Farms w/o LP tokens are not supported".to_string()) - })?)?; - let pools = self.find_pools_with_lp(&lp_token.name)?; - if pools.is_empty() { - return Err(FarmClientError::RecordNotFound(format!( - "Pools with LP token {}", - lp_token.name - ))); - } - self.get_pool_ref(&pools[0].name)? - } - FundVaultType::Pool => target_vault_metadata, - }; - - // instruction params - let vault_id = if vaults.is_empty() { - 0 - } else if vaults.last().unwrap().vault_id < u32::MAX { - vaults.last().unwrap().vault_id + 1 - } else { - return Err(FarmClientError::ValueError( - "Number of vaults are over the limit".to_string(), - )); - }; - - let current_hash = self - .get_fund_assets(fund_name, FundAssetType::Vault)? - .target_hash; - - let target_hash = if vault_type == FundVaultType::Farm { - current_hash - } else { - math::hash_address(current_hash, &target_vault_metadata) - }; - - // fill in accounts and instruction data - let data = FundInstruction::AddVault { - target_hash, - vault_id, - vault_type, - } - .to_vec()?; - - let (router_program_id, underlying_pool_id, underlying_lp_token_metadata) = match vault_type - { - FundVaultType::Pool => { - let pool = self.get_pool(vault_name)?; - let pool_ammid = match pool.route { - PoolRoute::Raydium { amm_id, .. } => amm_id, - PoolRoute::Saber { swap_account, .. } => swap_account, - PoolRoute::Orca { amm_id, .. } => amm_id, - }; - ( - pool.router_program_id, - pool_ammid, - pool.lp_token_ref.ok_or_else(|| { - FarmClientError::ValueError( - "Pools w/o LP tokens are not supported".to_string(), - ) - })?, - ) - } - FundVaultType::Farm => { - let farm = self.get_farm(vault_name)?; - let farm_id = match farm.route { - FarmRoute::Raydium { farm_id, .. } => farm_id, - FarmRoute::Saber { quarry, .. } => quarry, - FarmRoute::Orca { farm_id, .. } => farm_id, - }; - ( - farm.router_program_id, - farm_id, - farm.lp_token_ref.ok_or_else(|| { - FarmClientError::ValueError( - "Farms w/o LP tokens are not supported".to_string(), - ) - })?, - ) - } - FundVaultType::Vault => { - let vault = self.get_vault(vault_name)?; - let pool = self.get_pool_by_ref(&underlying_pool_ref)?; - - ( - vault.vault_program_id, - target_vault_metadata, - pool.lp_token_ref.ok_or_else(|| { - FarmClientError::ValueError( - "Underlying Pools w/o LP tokens are not supported".to_string(), - ) - })?, - ) - } - }; - - let accounts = vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new(self.get_fund_active_multisig_account(fund_name)?, false), - AccountMeta::new_readonly(fund.fund_authority, false), - AccountMeta::new_readonly(system_program::id(), false), - AccountMeta::new(fund_assets_account, false), - AccountMeta::new(fund_vault_metadata, false), - AccountMeta::new_readonly(target_vault_metadata, false), - AccountMeta::new_readonly(router_program_id, false), - AccountMeta::new_readonly(underlying_pool_id, false), - AccountMeta::new_readonly(underlying_pool_ref, false), - AccountMeta::new_readonly(underlying_lp_token_metadata, false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for removing the Vault from the Fund - pub fn new_instruction_remove_fund_vault( - &self, - admin_address: &Pubkey, - fund_name: &str, - vault_name: &str, - vault_type: FundVaultType, - ) -> Result { - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - - // get vaults - let vaults = self.get_fund_vaults(fund_name)?; - if vaults.is_empty() { - return Err(FarmClientError::ValueError( - "No active vaults found".to_string(), - )); - } - let vault_metadata = self.get_fund_vault_account(fund_name, vault_name, vault_type)?; - let fund_assets_account = self.get_fund_assets_account(fund_name, FundAssetType::Vault)?; - let vault_info = match vault_type { - FundVaultType::Vault => self.get_vault_ref(vault_name)?, - FundVaultType::Pool => self.get_pool_ref(vault_name)?, - FundVaultType::Farm => self.get_farm_ref(vault_name)?, - }; - - // instruction params - let mut target_hash = 0; - for vault in vaults { - if vault.vault_ref != vault_info && vault.vault_type != FundVaultType::Farm { - target_hash = math::hash_address(target_hash, &vault.vault_ref); - } - } - - // fill in accounts and instruction data - let data = FundInstruction::RemoveVault { - target_hash, - vault_type, - } - .to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new(self.get_fund_active_multisig_account(fund_name)?, false), - AccountMeta::new_readonly(fund.fund_authority, false), - AccountMeta::new_readonly(system_program::id(), false), - AccountMeta::new(fund_assets_account, false), - AccountMeta::new(vault_metadata, false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new set deposit schedule Instruction - pub fn new_instruction_set_fund_deposit_schedule( - &self, - admin_address: &Pubkey, - fund_name: &str, - schedule: &FundSchedule, - ) -> Result { - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - - // fill in accounts and instruction data - let data = FundInstruction::SetDepositSchedule { - schedule: *schedule, - } - .to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new(self.get_fund_active_multisig_account(fund_name)?, false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for disabling deposits to the Fund - pub fn new_instruction_disable_deposits_fund( - &self, - admin_address: &Pubkey, - fund_name: &str, - ) -> Result { - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - - // fill in accounts and instruction data - let data = FundInstruction::DisableDeposits.to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new(self.get_fund_active_multisig_account(fund_name)?, false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for requesting deposit to the Fund - pub fn new_instruction_request_deposit_fund( - &self, - wallet_address: &Pubkey, - fund_name: &str, - token_name: &str, - ui_amount: f64, - ) -> Result { - if ui_amount < 0.0 { - return Err(FarmClientError::ValueError(format!( - "Invalid deposit amount {} specified for Fund {}: Must be greater or equal to zero.", - ui_amount, fund_name - ))); - } - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - let fund_token = self.get_token_by_ref(&fund.fund_token_ref)?; - let token = self.get_token(token_name)?; - let token_ref = self.get_token_ref(token_name)?; - let user_info_account = self.get_fund_user_info_account(wallet_address, fund_name)?; - let user_requests_account = - self.get_fund_user_requests_account(wallet_address, fund_name, token_name)?; - let user_deposit_token_account = - self.get_associated_token_address(wallet_address, token.name.as_str())?; - let user_fund_token_account = - self.get_associated_token_address(wallet_address, fund_token.name.as_str())?; - let custody_metadata = - self.get_fund_custody_account(fund_name, token_name, FundCustodyType::DepositWithdraw)?; - let custody_token_account = self.get_fund_custody_token_account( - fund_name, - token_name, - FundCustodyType::DepositWithdraw, - )?; - let custody_fees_token_account = self.get_fund_custody_fees_token_account( - fund_name, - token_name, - FundCustodyType::DepositWithdraw, - )?; - let (_, oracle_account) = self.get_oracle(token_name)?; - - // fill in accounts and instruction data - let data = FundInstruction::RequestDeposit { - amount: self.to_token_amount(ui_amount, &token)?, - } - .to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*wallet_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new_readonly(fund.fund_authority, false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new(fund_token.mint, false), - AccountMeta::new(user_info_account, false), - AccountMeta::new(user_requests_account, false), - AccountMeta::new(user_deposit_token_account, false), - AccountMeta::new(user_fund_token_account, false), - AccountMeta::new(custody_token_account, false), - AccountMeta::new(custody_fees_token_account, false), - AccountMeta::new_readonly(custody_metadata, false), - AccountMeta::new_readonly(token_ref, false), - AccountMeta::new_readonly(oracle_account.unwrap_or_else(zero::id), false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for canceling pending deposit to the Fund - pub fn new_instruction_cancel_deposit_fund( - &self, - wallet_address: &Pubkey, - fund_name: &str, - token_name: &str, - ) -> Result { - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - let token = self.get_token(token_name)?; - let token_ref = self.get_token_ref(token_name)?; - let user_requests_account = - self.get_fund_user_requests_account(wallet_address, fund_name, token_name)?; - let user_deposit_token_account = - self.get_associated_token_address(wallet_address, token.name.as_str())?; - - // fill in accounts and instruction data - let data = FundInstruction::CancelDeposit.to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*wallet_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new(user_requests_account, false), - AccountMeta::new(user_deposit_token_account, false), - AccountMeta::new_readonly(token_ref, false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for approving deposit to the Fund - pub fn new_instruction_approve_deposit_fund( - &self, - admin_address: &Pubkey, - user_address: &Pubkey, - fund_name: &str, - token_name: &str, - ui_amount: f64, - ) -> Result { - if ui_amount < 0.0 { - return Err(FarmClientError::ValueError(format!( - "Invalid approve amount {} specified for Fund {}: Must be greater or equal to zero.", - ui_amount, fund_name - ))); - } - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - let fund_token = self.get_token_by_ref(&fund.fund_token_ref)?; - let token = self.get_token(token_name)?; - let token_ref = self.get_token_ref(token_name)?; - let user_info_account = self.get_fund_user_info_account(user_address, fund_name)?; - let user_requests_account = - self.get_fund_user_requests_account(user_address, fund_name, token_name)?; - let user_deposit_token_account = - self.get_associated_token_address(user_address, token.name.as_str())?; - let user_fund_token_account = - self.get_associated_token_address(user_address, fund_token.name.as_str())?; - let custody_metadata = - self.get_fund_custody_account(fund_name, token_name, FundCustodyType::DepositWithdraw)?; - let custody_token_account = self.get_fund_custody_token_account( - fund_name, - token_name, - FundCustodyType::DepositWithdraw, - )?; - let custody_fees_token_account = self.get_fund_custody_fees_token_account( - fund_name, - token_name, - FundCustodyType::DepositWithdraw, - )?; - let (_, oracle_account) = self.get_oracle(token_name)?; - - // fill in accounts and instruction data - let data = FundInstruction::ApproveDeposit { - amount: self.to_token_amount(ui_amount, &token)?, - } - .to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new(self.get_fund_active_multisig_account(fund_name)?, false), - AccountMeta::new_readonly(fund.fund_authority, false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new(fund_token.mint, false), - AccountMeta::new_readonly(*user_address, false), - AccountMeta::new(user_info_account, false), - AccountMeta::new(user_requests_account, false), - AccountMeta::new(user_deposit_token_account, false), - AccountMeta::new(user_fund_token_account, false), - AccountMeta::new(custody_token_account, false), - AccountMeta::new(custody_fees_token_account, false), - AccountMeta::new_readonly(custody_metadata, false), - AccountMeta::new_readonly(token_ref, false), - AccountMeta::new_readonly(oracle_account.unwrap_or_else(zero::id), false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for denying deposit to the Fund - pub fn new_instruction_deny_deposit_fund( - &self, - admin_address: &Pubkey, - user_address: &Pubkey, - fund_name: &str, - token_name: &str, - deny_reason: &str, - ) -> Result { - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - let token_ref = self.get_token_ref(token_name)?; - let user_requests_account = - self.get_fund_user_requests_account(user_address, fund_name, token_name)?; - - // fill in accounts and instruction data - let data = FundInstruction::DenyDeposit { - deny_reason: str_to_as64(deny_reason)?, - } - .to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new(self.get_fund_active_multisig_account(fund_name)?, false), - AccountMeta::new_readonly(*user_address, false), - AccountMeta::new(user_requests_account, false), - AccountMeta::new_readonly(token_ref, false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new set withdrawal schedule Instruction - pub fn new_instruction_set_fund_withdrawal_schedule( - &self, - admin_address: &Pubkey, - fund_name: &str, - schedule: &FundSchedule, - ) -> Result { - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - - // fill in accounts and instruction data - let data = FundInstruction::SetWithdrawalSchedule { - schedule: *schedule, - } - .to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new(self.get_fund_active_multisig_account(fund_name)?, false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for disabling withdrawals from the Fund - pub fn new_instruction_disable_withdrawals_fund( - &self, - admin_address: &Pubkey, - fund_name: &str, - ) -> Result { - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - - // fill in accounts and instruction data - let data = FundInstruction::DisableWithdrawals.to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new(self.get_fund_active_multisig_account(fund_name)?, false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for requesting withdrawal from the Fund - pub fn new_instruction_request_withdrawal_fund( - &self, - wallet_address: &Pubkey, - fund_name: &str, - token_name: &str, - ui_amount: f64, - ) -> Result { - if ui_amount < 0.0 { - return Err(FarmClientError::ValueError(format!( - "Invalid withdrawal amount {} specified for Fund {}: Must be greater or equal to zero.", - ui_amount, fund_name - ))); - } - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - let fund_token = self.get_token_by_ref(&fund.fund_token_ref)?; - let token = self.get_token(token_name)?; - let token_ref = self.get_token_ref(token_name)?; - let user_info_account = self.get_fund_user_info_account(wallet_address, fund_name)?; - let user_requests_account = - self.get_fund_user_requests_account(wallet_address, fund_name, token_name)?; - let user_withdrawal_token_account = - self.get_associated_token_address(wallet_address, token.name.as_str())?; - let user_fund_token_account = - self.get_associated_token_address(wallet_address, fund_token.name.as_str())?; - let custody_metadata = - self.get_fund_custody_account(fund_name, token_name, FundCustodyType::DepositWithdraw)?; - let custody_token_account = self.get_fund_custody_token_account( - fund_name, - token_name, - FundCustodyType::DepositWithdraw, - )?; - let custody_fees_token_account = self.get_fund_custody_fees_token_account( - fund_name, - token_name, - FundCustodyType::DepositWithdraw, - )?; - let (_, oracle_account) = self.get_oracle(token_name)?; - - // fill in accounts and instruction data - let data = FundInstruction::RequestWithdrawal { - amount: self.to_token_amount(ui_amount, &fund_token)?, - } - .to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*wallet_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new_readonly(fund.fund_authority, false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new(fund_token.mint, false), - AccountMeta::new(user_info_account, false), - AccountMeta::new(user_requests_account, false), - AccountMeta::new(user_withdrawal_token_account, false), - AccountMeta::new(user_fund_token_account, false), - AccountMeta::new(custody_token_account, false), - AccountMeta::new(custody_fees_token_account, false), - AccountMeta::new_readonly(custody_metadata, false), - AccountMeta::new_readonly(token_ref, false), - AccountMeta::new_readonly(oracle_account.unwrap_or_else(zero::id), false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for canceling pending withdrawal from the Fund - pub fn new_instruction_cancel_withdrawal_fund( - &self, - wallet_address: &Pubkey, - fund_name: &str, - token_name: &str, - ) -> Result { - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - let token = self.get_token(token_name)?; - let token_ref = self.get_token_ref(token_name)?; - let user_requests_account = - self.get_fund_user_requests_account(wallet_address, fund_name, token_name)?; - let user_withdrawal_token_account = - self.get_associated_token_address(wallet_address, token.name.as_str())?; - - // fill in accounts and instruction data - let data = FundInstruction::CancelWithdrawal.to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*wallet_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new(user_requests_account, false), - AccountMeta::new(user_withdrawal_token_account, false), - AccountMeta::new_readonly(token_ref, false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for approving withdrawal from the Fund - pub fn new_instruction_approve_withdrawal_fund( - &self, - admin_address: &Pubkey, - user_address: &Pubkey, - fund_name: &str, - token_name: &str, - ui_amount: f64, - ) -> Result { - if ui_amount < 0.0 { - return Err(FarmClientError::ValueError(format!( - "Invalid approve amount {} specified for Fund {}: Must be greater or equal to zero.", - ui_amount, fund_name - ))); - } - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - let fund_token = self.get_token_by_ref(&fund.fund_token_ref)?; - let token = self.get_token(token_name)?; - let token_ref = self.get_token_ref(token_name)?; - let user_info_account = self.get_fund_user_info_account(user_address, fund_name)?; - let user_requests_account = - self.get_fund_user_requests_account(user_address, fund_name, token_name)?; - let user_withdrawal_token_account = - self.get_associated_token_address(user_address, token.name.as_str())?; - let user_fund_token_account = - self.get_associated_token_address(user_address, fund_token.name.as_str())?; - let custody_metadata = - self.get_fund_custody_account(fund_name, token_name, FundCustodyType::DepositWithdraw)?; - let custody_token_account = self.get_fund_custody_token_account( - fund_name, - token_name, - FundCustodyType::DepositWithdraw, - )?; - let custody_fees_token_account = self.get_fund_custody_fees_token_account( - fund_name, - token_name, - FundCustodyType::DepositWithdraw, - )?; - let (_, oracle_account) = self.get_oracle(token_name)?; - - // fill in accounts and instruction data - let data = FundInstruction::ApproveWithdrawal { - amount: self.to_token_amount(ui_amount, &fund_token)?, - } - .to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new(self.get_fund_active_multisig_account(fund_name)?, false), - AccountMeta::new_readonly(fund.fund_authority, false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new(fund_token.mint, false), - AccountMeta::new_readonly(*user_address, false), - AccountMeta::new(user_info_account, false), - AccountMeta::new(user_requests_account, false), - AccountMeta::new(user_withdrawal_token_account, false), - AccountMeta::new(user_fund_token_account, false), - AccountMeta::new(custody_token_account, false), - AccountMeta::new(custody_fees_token_account, false), - AccountMeta::new_readonly(custody_metadata, false), - AccountMeta::new_readonly(token_ref, false), - AccountMeta::new_readonly(oracle_account.unwrap_or_else(zero::id), false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for denying withdrawal from the Fund - pub fn new_instruction_deny_withdrawal_fund( - &self, - admin_address: &Pubkey, - user_address: &Pubkey, - fund_name: &str, - token_name: &str, - deny_reason: &str, - ) -> Result { - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - let token_ref = self.get_token_ref(token_name)?; - let user_requests_account = - self.get_fund_user_requests_account(user_address, fund_name, token_name)?; - - // fill in accounts and instruction data - let data = FundInstruction::DenyWithdrawal { - deny_reason: str_to_as64(deny_reason)?, - } - .to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new(self.get_fund_active_multisig_account(fund_name)?, false), - AccountMeta::new_readonly(*user_address, false), - AccountMeta::new(user_requests_account, false), - AccountMeta::new_readonly(token_ref, false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for moving deposited assets to the Fund - pub fn new_instruction_lock_assets_fund( - &self, - admin_address: &Pubkey, - fund_name: &str, - token_name: &str, - ui_amount: f64, - ) -> Result { - if ui_amount < 0.0 { - return Err(FarmClientError::ValueError(format!( - "Invalid lock amount {} specified for Fund {}: Must be greater or equal to zero.", - ui_amount, fund_name - ))); - } - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - let token = self.get_token(token_name)?; - let token_ref = self.get_token_ref(token_name)?; - let wd_custody_metadata = - self.get_fund_custody_account(fund_name, token_name, FundCustodyType::DepositWithdraw)?; - let wd_custody_token_account = self.get_fund_custody_token_account( - fund_name, - token_name, - FundCustodyType::DepositWithdraw, - )?; - let trading_custody_metadata = - self.get_fund_custody_account(fund_name, token_name, FundCustodyType::Trading)?; - let trading_custody_token_account = - self.get_fund_custody_token_account(fund_name, token_name, FundCustodyType::Trading)?; - - // fill in accounts and instruction data - let data = FundInstruction::LockAssets { - amount: self.to_token_amount(ui_amount, &token)?, - } - .to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new(self.get_fund_active_multisig_account(fund_name)?, false), - AccountMeta::new_readonly(fund.fund_authority, false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new(wd_custody_token_account, false), - AccountMeta::new(wd_custody_metadata, false), - AccountMeta::new(trading_custody_token_account, false), - AccountMeta::new(trading_custody_metadata, false), - AccountMeta::new_readonly(token_ref, false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for releasing assets from the Fund to Deposit/Withdraw custody - pub fn new_instruction_unlock_assets_fund( - &self, - admin_address: &Pubkey, - fund_name: &str, - token_name: &str, - ui_amount: f64, - ) -> Result { - if ui_amount < 0.0 { - return Err(FarmClientError::ValueError(format!( - "Invalid unlock amount {} specified for Fund {}: Must be greater or equal to zero.", - ui_amount, fund_name - ))); - } - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - let token = self.get_token(token_name)?; - let token_ref = self.get_token_ref(token_name)?; - let wd_custody_metadata = - self.get_fund_custody_account(fund_name, token_name, FundCustodyType::DepositWithdraw)?; - let wd_custody_token_account = self.get_fund_custody_token_account( - fund_name, - token_name, - FundCustodyType::DepositWithdraw, - )?; - let trading_custody_metadata = - self.get_fund_custody_account(fund_name, token_name, FundCustodyType::Trading)?; - let trading_custody_token_account = - self.get_fund_custody_token_account(fund_name, token_name, FundCustodyType::Trading)?; - - // fill in accounts and instruction data - let data = FundInstruction::UnlockAssets { - amount: self.to_token_amount(ui_amount, &token)?, - } - .to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new(self.get_fund_active_multisig_account(fund_name)?, false), - AccountMeta::new_readonly(fund.fund_authority, false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new(wd_custody_token_account, false), - AccountMeta::new(wd_custody_metadata, false), - AccountMeta::new(trading_custody_token_account, false), - AccountMeta::new(trading_custody_metadata, false), - AccountMeta::new_readonly(token_ref, false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for initiating liquidation of the Fund - pub fn new_instruction_start_liquidation_fund( - &self, - wallet_address: &Pubkey, - fund_name: &str, - ) -> Result { - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - let fund_token = self.get_token_by_ref(&fund.fund_token_ref)?; - let user_info_account = self.get_fund_user_info_account(wallet_address, fund_name)?; - let user_fund_token_account = - self.get_associated_token_address(wallet_address, fund_token.name.as_str())?; - - // fill in accounts and instruction data - let data = FundInstruction::StartLiquidation.to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*wallet_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new(fund_token.mint, false), - AccountMeta::new_readonly(user_info_account, false), - AccountMeta::new_readonly(user_fund_token_account, false), - AccountMeta::new_readonly(sysvar::instructions::id(), false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for stopping liquidation of the Fund - pub fn new_instruction_stop_liquidation_fund( - &self, - admin_address: &Pubkey, - fund_name: &str, - ) -> Result { - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - - // fill in accounts and instruction data - let data = FundInstruction::StopLiquidation.to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new(self.get_fund_active_multisig_account(fund_name)?, false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for fees withdrawal from the Fund - pub fn new_instruction_withdraw_fees_fund( - &self, - wallet_address: &Pubkey, - fund_name: &str, - token_name: &str, - custody_type: FundCustodyType, - ui_amount: f64, - receiver: &Pubkey, - ) -> Result { - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - - // get custodies - let custody_fees_token_account = - self.get_fund_custody_fees_token_account(fund_name, token_name, custody_type)?; - - // fill in accounts and instruction data - let token = self.get_token(token_name)?; - let data = FundInstruction::WithdrawFees { - amount: self.ui_amount_to_tokens_with_decimals(ui_amount, token.decimals)?, - } - .to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*wallet_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new(self.get_fund_active_multisig_account(fund_name)?, false), - AccountMeta::new(self.get_fund_multisig_account(fund_name)?, false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new(custody_fees_token_account, false), - AccountMeta::new(*receiver, false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for updating Fund assets based on custody holdings - pub fn new_instruction_update_fund_assets_with_custody( - &self, - wallet_address: &Pubkey, - fund_name: &str, - custody_id: u32, - ) -> Result { - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - - // get custodies - let custodies = self.get_fund_custodies(fund_name)?; - let custody = custodies - .iter() - .find(|&c| c.custody_id == custody_id) - .ok_or_else(|| { - FarmClientError::RecordNotFound(format!("Custody with ID {}", custody_id)) - })?; - let token = self.get_token_by_ref(&custody.token_ref)?; - let custody_metadata = - self.get_fund_custody_account(fund_name, token.name.as_str(), custody.custody_type)?; - let custodies_assets_account = - self.get_fund_assets_account(fund_name, FundAssetType::Custody)?; - let vaults_assets_account = - self.get_fund_assets_account(fund_name, FundAssetType::Vault)?; - let custody_token_account = self.get_fund_custody_token_account( - fund_name, - token.name.as_str(), - custody.custody_type, - )?; - let (_, oracle_account) = self.get_oracle(&token.name)?; - - // fill in accounts and instruction data - let accounts = vec![ - AccountMeta::new_readonly(*wallet_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new(custodies_assets_account, false), - AccountMeta::new_readonly(vaults_assets_account, false), - AccountMeta::new(custody_token_account, false), - AccountMeta::new(custody_metadata, false), - AccountMeta::new_readonly(custody.token_ref, false), - AccountMeta::new_readonly(oracle_account.unwrap_or_else(zero::id), false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data: FundInstruction::UpdateAssetsWithCustody.to_vec()?, - accounts, - }) - } - - /// Creates a new Instruction for updating Fund assets with Vault holdings - pub fn new_instruction_update_fund_assets_with_vault( - &self, - wallet_address: &Pubkey, - fund_name: &str, - vault_id: u32, - ) -> Result { - // get fund info - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - - // get vaults - let vaults = self.get_fund_vaults(fund_name)?; - let vault = vaults - .iter() - .find(|&c| c.vault_id == vault_id) - .ok_or_else(|| { - FarmClientError::RecordNotFound(format!("Fund Vault with ID {}", vault_id)) - })?; - if vault.vault_type == FundVaultType::Farm { - return Err(FarmClientError::ValueError( - "Nothing to do: Farms are not processed to avoid double counting".to_string(), - )); - } - let vault_name = match vault.vault_type { - FundVaultType::Vault => self.get_vault_by_ref(&vault.vault_ref)?.name, - FundVaultType::Pool => self.get_pool_by_ref(&vault.vault_ref)?.name, - FundVaultType::Farm => unreachable!(), - }; - let token_names = match vault.vault_type { - FundVaultType::Vault => self.get_vault_token_names(&vault_name)?, - FundVaultType::Pool => self.get_pool_token_names(&vault_name)?, - FundVaultType::Farm => unreachable!(), - }; - let target_vault_metadata = match vault.vault_type { - FundVaultType::Vault => self.get_vault_ref(&vault_name)?, - FundVaultType::Pool => self.get_pool_ref(&vault_name)?, - FundVaultType::Farm => unreachable!(), - }; - let underlying_pool_ref = if vault.vault_type == FundVaultType::Vault { - match self.get_vault(&vault_name)?.strategy { - VaultStrategy::StakeLpCompoundRewards { pool_ref, .. } => pool_ref, - _ => unreachable!(), - } - } else { - target_vault_metadata - }; - let underlying_pool = self.get_pool_by_ref(&underlying_pool_ref)?; - let underlying_lp_token = self.get_token_by_ref( - &underlying_pool - .lp_token_ref - .ok_or(ProgramError::UninitializedAccount)?, - )?; - let (amm_id, amm_open_orders) = match underlying_pool.route { - PoolRoute::Raydium { - amm_id, - amm_open_orders, - .. - } => (amm_id, amm_open_orders), - PoolRoute::Orca { amm_id, .. } => (amm_id, zero::id()), - _ => { - return Err(FarmClientError::ValueError( - "Unsupported pool route".to_string(), - )); - } - }; - let vault_metadata = - self.get_fund_vault_account(fund_name, vault_name.as_str(), vault.vault_type)?; - let custodies_assets_account = - self.get_fund_assets_account(fund_name, FundAssetType::Custody)?; - let vaults_assets_account = - self.get_fund_assets_account(fund_name, FundAssetType::Vault)?; - let (_, oracle_account_token_a) = if token_names.0.is_empty() { - (OracleType::Unsupported, None) - } else { - self.get_oracle(&token_names.0)? - }; - let (_, oracle_account_token_b) = if token_names.1.is_empty() { - (OracleType::Unsupported, None) - } else { - self.get_oracle(&token_names.1)? - }; - - // fill in accounts and instruction data - let accounts = vec![ - AccountMeta::new_readonly(*wallet_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - AccountMeta::new_readonly(custodies_assets_account, false), - AccountMeta::new(vaults_assets_account, false), - AccountMeta::new(vault_metadata, false), - AccountMeta::new_readonly(vault.vault_ref, false), - AccountMeta::new_readonly(underlying_pool_ref, false), - AccountMeta::new_readonly( - underlying_pool - .token_a_ref - .ok_or(ProgramError::UninitializedAccount)?, - false, - ), - AccountMeta::new_readonly( - underlying_pool - .token_b_ref - .ok_or(ProgramError::UninitializedAccount)?, - false, - ), - AccountMeta::new_readonly(underlying_lp_token.mint, false), - AccountMeta::new_readonly( - underlying_pool - .token_a_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - ), - AccountMeta::new_readonly( - underlying_pool - .token_b_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - ), - AccountMeta::new_readonly(amm_id, false), - AccountMeta::new_readonly(amm_open_orders, false), - AccountMeta::new_readonly(oracle_account_token_a.unwrap_or_else(zero::id), false), - AccountMeta::new_readonly(oracle_account_token_b.unwrap_or_else(zero::id), false), - AccountMeta::new_readonly(sysvar::instructions::id(), false), - ]; - - Ok(Instruction { - program_id: fund.fund_program_id, - data: FundInstruction::UpdateAssetsWithVault.to_vec()?, - accounts, - }) - } - - /// Creates a new complete set of Instructions for requesting a new deposit to the Fund - pub fn all_instructions_request_deposit_fund( - &self, - wallet_address: &Pubkey, - fund_name: &str, - token_name: &str, - ui_amount: f64, - ) -> Result, FarmClientError> { - let mut inst = Vec::::new(); - let _ = - self.check_fund_accounts(wallet_address, fund_name, token_name, ui_amount, &mut inst)?; - - // create and send the instruction - inst.push(self.new_instruction_request_deposit_fund( - wallet_address, - fund_name, - token_name, - ui_amount, - )?); - - Ok(inst) - } - - /// Creates a new complete set of Instructions for requesting a new withdrawal from the Fund - pub fn all_instructions_request_withdrawal_fund( - &self, - wallet_address: &Pubkey, - fund_name: &str, - token_name: &str, - ui_amount: f64, - ) -> Result, FarmClientError> { - let mut inst = Vec::::new(); - let fund = self.get_fund(fund_name)?; - let fund_token = Some(self.get_token_by_ref(&fund.fund_token_ref)?); - let asset_token = Some(self.get_token(token_name)?); - let _ = self.check_token_account(wallet_address, &fund_token, ui_amount, &mut inst)?; - let _ = self.check_token_account(wallet_address, &asset_token, 0.0, &mut inst)?; - - if self - .get_fund_user_requests(wallet_address, fund_name, token_name) - .is_err() - { - inst.push(self.new_instruction_user_init_fund( - wallet_address, - fund_name, - token_name, - )?); - } - - // create and send the instruction - inst.push(self.new_instruction_request_withdrawal_fund( - wallet_address, - fund_name, - token_name, - ui_amount, - )?); - - Ok(inst) - } -} diff --git a/farms/farm-client/src/client/fund_instructions_pools.rs b/farms/farm-client/src/client/fund_instructions_pools.rs deleted file mode 100644 index 5af088846ef..00000000000 --- a/farms/farm-client/src/client/fund_instructions_pools.rs +++ /dev/null @@ -1,760 +0,0 @@ -//! Solana Farm Client Fund Instructions for pools, farms, and vaults - -use { - crate::error::FarmClientError, - solana_farm_sdk::{ - fund::FundVaultType, - instruction::{amm::AmmInstruction, fund::FundInstruction, vault::VaultInstruction}, - Protocol, - }, - solana_sdk::{ - instruction::{AccountMeta, Instruction}, - pubkey::Pubkey, - sysvar, - }, -}; - -use super::FarmClient; - -impl FarmClient { - /// Creates a new Instruction for initializing a new user for the Farm in the Fund - pub fn new_instruction_fund_user_init_farm( - &self, - admin_address: &Pubkey, - fund_name: &str, - farm_name: &str, - ) -> Result { - let fund = self.get_fund(fund_name)?; - let farm_inst = self.new_instruction_user_init(&fund.fund_authority, farm_name)?; - self.build_fund_instruction( - admin_address, - fund_name, - &farm_inst, - farm_name, - FundVaultType::Farm, - ) - } - - /// Creates a new Instruction for adding liquidity to the Pool in the Fund - pub fn new_instruction_fund_add_liquidity_pool( - &self, - admin_address: &Pubkey, - fund_name: &str, - pool_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - ) -> Result { - let fund = self.get_fund(fund_name)?; - let pool_inst = self.new_instruction_add_liquidity_pool( - &fund.fund_authority, - pool_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - )?; - self.build_fund_instruction( - admin_address, - fund_name, - &pool_inst, - pool_name, - FundVaultType::Pool, - ) - } - - /// Creates a new Instruction for removing liquidity from the Pool in the Fund - pub fn new_instruction_fund_remove_liquidity_pool( - &self, - admin_address: &Pubkey, - fund_name: &str, - pool_name: &str, - ui_amount: f64, - ) -> Result { - let fund = self.get_fund(fund_name)?; - let pool_inst = - self.new_instruction_remove_liquidity_pool(&fund.fund_authority, pool_name, ui_amount)?; - self.build_fund_instruction( - admin_address, - fund_name, - &pool_inst, - pool_name, - FundVaultType::Pool, - ) - } - - /// Creates a new Instruction for tokens swap - #[allow(clippy::too_many_arguments)] - pub fn new_instruction_fund_swap( - &self, - admin_address: &Pubkey, - fund_name: &str, - protocol: Protocol, - from_token: &str, - to_token: &str, - ui_amount_in: f64, - min_ui_amount_out: f64, - ) -> Result { - let fund = self.get_fund(fund_name)?; - let pool = self.find_pools(protocol, from_token, to_token)?[0]; - let pool_inst = self.new_instruction_swap( - &fund.fund_authority, - protocol, - from_token, - to_token, - ui_amount_in, - min_ui_amount_out, - )?; - self.build_fund_instruction( - admin_address, - fund_name, - &pool_inst, - &pool.name, - FundVaultType::Pool, - ) - } - - /// Creates a new Instruction for tokens staking to the Farm in the Fund - pub fn new_instruction_fund_stake( - &self, - admin_address: &Pubkey, - fund_name: &str, - farm_name: &str, - ui_amount: f64, - ) -> Result { - let fund = self.get_fund(fund_name)?; - let farm_inst = self.new_instruction_stake(&fund.fund_authority, farm_name, ui_amount)?; - self.build_fund_instruction( - admin_address, - fund_name, - &farm_inst, - farm_name, - FundVaultType::Farm, - ) - } - - /// Creates a new Instruction for tokens unstaking from the Farm in the Fund - pub fn new_instruction_fund_unstake( - &self, - admin_address: &Pubkey, - fund_name: &str, - farm_name: &str, - ui_amount: f64, - ) -> Result { - let fund = self.get_fund(fund_name)?; - let farm_inst = self.new_instruction_unstake(&fund.fund_authority, farm_name, ui_amount)?; - self.build_fund_instruction( - admin_address, - fund_name, - &farm_inst, - farm_name, - FundVaultType::Farm, - ) - } - - /// Creates a new Instruction for rewards harvesting from the Farm in the Fund - pub fn new_instruction_fund_harvest( - &self, - admin_address: &Pubkey, - fund_name: &str, - farm_name: &str, - ) -> Result { - let fund = self.get_fund(fund_name)?; - let farm_inst = self.new_instruction_harvest(&fund.fund_authority, farm_name)?; - self.build_fund_instruction( - admin_address, - fund_name, - &farm_inst, - farm_name, - FundVaultType::Farm, - ) - } - - /// Creates a new Instruction for initializing a new user for the Vault in the Fund - pub fn new_instruction_fund_user_init_vault( - &self, - admin_address: &Pubkey, - fund_name: &str, - vault_name: &str, - ) -> Result { - let fund = self.get_fund(fund_name)?; - let vault_inst = self.new_instruction_user_init_vault(&fund.fund_authority, vault_name)?; - self.build_fund_vault_instruction(admin_address, fund_name, &vault_inst, vault_name) - } - - /// Creates a new Instruction for adding liquidity to the Vault in the Fund - pub fn new_instruction_fund_add_liquidity_vault( - &self, - admin_address: &Pubkey, - fund_name: &str, - vault_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - ) -> Result { - let fund = self.get_fund(fund_name)?; - let vault_inst = self.new_instruction_add_liquidity_vault( - &fund.fund_authority, - vault_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - )?; - self.build_fund_vault_instruction(admin_address, fund_name, &vault_inst, vault_name) - } - - /// Creates a new Instruction for locking liquidity in the Vault in the Fund - pub fn new_instruction_fund_lock_liquidity_vault( - &self, - admin_address: &Pubkey, - fund_name: &str, - vault_name: &str, - ui_amount: f64, - ) -> Result { - let fund = self.get_fund(fund_name)?; - let vault_inst = - self.new_instruction_lock_liquidity_vault(&fund.fund_authority, vault_name, ui_amount)?; - self.build_fund_vault_instruction(admin_address, fund_name, &vault_inst, vault_name) - } - - /// Creates a new Instruction for unlocking liquidity in the Vault in the Fund - pub fn new_instruction_fund_unlock_liquidity_vault( - &self, - admin_address: &Pubkey, - fund_name: &str, - vault_name: &str, - ui_amount: f64, - ) -> Result { - let fund = self.get_fund(fund_name)?; - let vault_inst = self.new_instruction_unlock_liquidity_vault( - &fund.fund_authority, - vault_name, - ui_amount, - )?; - self.build_fund_vault_instruction(admin_address, fund_name, &vault_inst, vault_name) - } - - /// Creates a new Instruction for removing liquidity from the Vault in the Fund - pub fn new_instruction_fund_remove_liquidity_vault( - &self, - admin_address: &Pubkey, - fund_name: &str, - vault_name: &str, - ui_amount: f64, - ) -> Result { - let fund = self.get_fund(fund_name)?; - let vault_inst = self.new_instruction_remove_liquidity_vault( - &fund.fund_authority, - vault_name, - ui_amount, - )?; - self.build_fund_vault_instruction(admin_address, fund_name, &vault_inst, vault_name) - } - - /// Creates a new complete set of Instructions for adding liquidity to the Pool in the Fund - pub fn all_instructions_fund_add_liquidity_pool( - &self, - admin_address: &Pubkey, - fund_name: &str, - pool_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - ) -> Result, FarmClientError> { - if max_token_a_ui_amount < 0.0 - || max_token_b_ui_amount < 0.0 - || (max_token_a_ui_amount == 0.0 && max_token_b_ui_amount == 0.0) - { - return Err(FarmClientError::ValueError(format!( - "Invalid add liquidity amounts {} and {} specified for Pool {}: Must be greater or equal to zero and at least one non-zero.", - max_token_a_ui_amount, max_token_b_ui_amount, pool_name - ))); - } - // check custodies - let mut inst = Vec::::new(); - self.check_fund_pool_custodies( - admin_address, - fund_name, - pool_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - 0.0, - true, - &mut inst, - )?; - - // create and send the instruction - inst.push(self.new_instruction_fund_add_liquidity_pool( - admin_address, - fund_name, - pool_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - )?); - - Ok(inst) - } - - /// Creates a new complete set of Instructions for removing liquidity from the Pool in the Fund - pub fn all_instructions_fund_remove_liquidity_pool( - &self, - admin_address: &Pubkey, - fund_name: &str, - pool_name: &str, - ui_amount: f64, - ) -> Result, FarmClientError> { - // check custodies - let mut inst = Vec::::new(); - self.check_fund_pool_custodies( - admin_address, - fund_name, - pool_name, - 0.0, - 0.0, - ui_amount, - true, - &mut inst, - )?; - - // create and send the instruction - inst.push(self.new_instruction_fund_remove_liquidity_pool( - admin_address, - fund_name, - pool_name, - ui_amount, - )?); - - Ok(inst) - } - - /// Creates a new complete set of Instructions for swapping tokens in the Fund - #[allow(clippy::too_many_arguments)] - pub fn all_instructions_fund_swap( - &self, - admin_address: &Pubkey, - fund_name: &str, - protocol: Protocol, - from_token: &str, - to_token: &str, - ui_amount_in: f64, - min_ui_amount_out: f64, - ) -> Result, FarmClientError> { - // check amount - if ui_amount_in < 0.0 { - return Err(FarmClientError::ValueError(format!( - "Invalid ui_amount_in {} specified for swap: Must be zero or greater.", - ui_amount_in - ))); - } - // check custodies - let mut inst = Vec::::new(); - self.check_fund_custody( - admin_address, - fund_name, - from_token, - ui_amount_in, - &mut inst, - )?; - self.check_fund_custody(admin_address, fund_name, to_token, 0.0, &mut inst)?; - - // create and send the instruction - inst.push(self.new_instruction_fund_swap( - admin_address, - fund_name, - protocol, - from_token, - to_token, - ui_amount_in, - min_ui_amount_out, - )?); - - Ok(inst) - } - - /// Creates a new complete set of Instructions for staking tokens to the Farm in the Fund - pub fn all_instructions_fund_stake( - &self, - admin_address: &Pubkey, - fund_name: &str, - farm_name: &str, - ui_amount: f64, - ) -> Result, FarmClientError> { - // check custodies - let mut inst = Vec::::new(); - self.check_fund_farm_custodies(admin_address, fund_name, farm_name, ui_amount, &mut inst)?; - - // create and send the instruction - inst.push(self.new_instruction_fund_stake( - admin_address, - fund_name, - farm_name, - ui_amount, - )?); - - Ok(inst) - } - - /// Creates a new complete set of Instructions for unstaking tokens from the Farm in the Fund - pub fn all_instructions_fund_unstake( - &self, - admin_address: &Pubkey, - fund_name: &str, - farm_name: &str, - ui_amount: f64, - ) -> Result, FarmClientError> { - // check custodies - let mut inst = Vec::::new(); - self.check_fund_farm_custodies(admin_address, fund_name, farm_name, 0.0, &mut inst)?; - - // create and send the instruction - inst.push(self.new_instruction_fund_unstake( - admin_address, - fund_name, - farm_name, - ui_amount, - )?); - - Ok(inst) - } - - /// Creates a new complete set of Instructions for harvesting rewards from the Farm in the Fund - pub fn all_instructions_fund_harvest( - &self, - admin_address: &Pubkey, - fund_name: &str, - farm_name: &str, - ) -> Result, FarmClientError> { - // check custodies - let mut inst = Vec::::new(); - self.check_fund_farm_custodies(admin_address, fund_name, farm_name, 0.0, &mut inst)?; - - // create and send the instruction - inst.push(self.new_instruction_fund_harvest(admin_address, fund_name, farm_name)?); - - Ok(inst) - } - - /// Creates a new complete set of Instructions for adding liquidity to the Vault in the Fund - pub fn all_instructions_fund_add_liquidity_vault( - &self, - admin_address: &Pubkey, - fund_name: &str, - vault_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - ) -> Result, FarmClientError> { - if max_token_a_ui_amount < 0.0 - || max_token_b_ui_amount < 0.0 - || (max_token_a_ui_amount == 0.0 && max_token_b_ui_amount == 0.0) - { - return Err(FarmClientError::ValueError(format!( - "Invalid add liquidity amounts {} and {} specified for Vault {}: Must be greater or equal to zero and at least one non-zero.", - max_token_a_ui_amount, max_token_b_ui_amount, vault_name - ))); - } - - let mut inst = Vec::::new(); - self.check_fund_vault_custodies( - admin_address, - fund_name, - vault_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - 0.0, - true, - true, - &mut inst, - )?; - - // insert add liquidity instruction - inst.push(self.new_instruction_fund_add_liquidity_vault( - admin_address, - fund_name, - vault_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - )?); - - // lock liquidity if required by the vault - let vault = self.get_vault(vault_name)?; - if vault.lock_required { - let lock_inst = self.new_instruction_fund_lock_liquidity_vault( - admin_address, - fund_name, - vault_name, - 0.0, - )?; - inst.push(lock_inst); - } - - Ok(inst) - } - - /// Creates a new complete set of Instructions for adding locked liquidity to the Vault in the Fund - pub fn all_instructions_fund_add_locked_liquidity_vault( - &self, - admin_address: &Pubkey, - fund_name: &str, - vault_name: &str, - ui_amount: f64, - ) -> Result, FarmClientError> { - // check fund accounts - let mut inst = Vec::::new(); - self.check_fund_vault_custodies( - admin_address, - fund_name, - vault_name, - 0.0, - 0.0, - 0.0, - true, - false, - &mut inst, - )?; - - // check if the user has locked balance - if ui_amount > 0.0 { - let fund = self.get_fund(fund_name)?; - let lp_debt = self - .get_vault_user_info(&fund.fund_authority, vault_name)? - .lp_tokens_debt; - let pool_token_decimals = self.get_vault_lp_token_decimals(vault_name)?; - if self.tokens_to_ui_amount_with_decimals(lp_debt, pool_token_decimals) < ui_amount { - return Err(FarmClientError::InsufficientBalance( - "Not enough locked tokens to deposit".to_string(), - )); - } - } - - inst.push(self.new_instruction_fund_lock_liquidity_vault( - admin_address, - fund_name, - vault_name, - ui_amount, - )?); - - Ok(inst) - } - - /// Creates a new complete set of Instructions for removing liquidity from the Vault in the Fund - pub fn all_instructions_fund_remove_liquidity_vault( - &self, - admin_address: &Pubkey, - fund_name: &str, - vault_name: &str, - ui_amount: f64, - ) -> Result, FarmClientError> { - // check user accounts - let vault = self.get_vault(vault_name)?; - let mut inst = Vec::::new(); - self.check_fund_vault_custodies( - admin_address, - fund_name, - vault_name, - 0.0, - 0.0, - 0.0, - true, - false, - &mut inst, - )?; - - // unlock liquidity first if required by the vault - if vault.unlock_required { - inst.push(self.new_instruction_fund_unlock_liquidity_vault( - admin_address, - fund_name, - vault_name, - ui_amount, - )?); - inst.push(self.new_instruction_fund_remove_liquidity_vault( - admin_address, - fund_name, - vault_name, - 0.0, - )?); - } else { - // remove liquidity - inst.push(self.new_instruction_fund_remove_liquidity_vault( - admin_address, - fund_name, - vault_name, - ui_amount, - )?); - } - - Ok(inst) - } - - /// Creates a new complete set of Instructions for removing unlocked liquidity from the Vault in the Fund - pub fn all_instructions_fund_remove_unlocked_liquidity_vault( - &self, - admin_address: &Pubkey, - fund_name: &str, - vault_name: &str, - ui_amount: f64, - ) -> Result, FarmClientError> { - // check user accounts - let mut inst = Vec::::new(); - self.check_fund_vault_custodies( - admin_address, - fund_name, - vault_name, - 0.0, - 0.0, - 0.0, - false, - false, - &mut inst, - )?; - - // check if the user has unlocked balance - if ui_amount > 0.0 { - let fund = self.get_fund(fund_name)?; - let lp_debt = self - .get_vault_user_info(&fund.fund_authority, vault_name)? - .lp_tokens_debt; - let pool_token_decimals = self.get_vault_lp_token_decimals(vault_name)?; - if self.tokens_to_ui_amount_with_decimals(lp_debt, pool_token_decimals) < ui_amount { - return Err(FarmClientError::InsufficientBalance( - "Not enough unlocked tokens to remove".to_string(), - )); - } - } - - inst.push(self.new_instruction_fund_remove_liquidity_vault( - admin_address, - fund_name, - vault_name, - ui_amount, - )?); - - Ok(inst) - } - - ///// private helpers - fn build_fund_instruction( - &self, - admin_address: &Pubkey, - fund_name: &str, - pool_instruction: &Instruction, - pool_or_farm_name: &str, - vault_type: FundVaultType, - ) -> Result { - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - - let protocol = &FarmClient::get_protocol(pool_or_farm_name)?; - let unpacked_instruction = AmmInstruction::unpack(pool_instruction.data.as_slice())?; - let data = match protocol { - Protocol::Raydium => FundInstruction::AmmInstructionRaydium { - instruction: unpacked_instruction, - } - .to_vec()?, - Protocol::Orca => FundInstruction::AmmInstructionOrca { - instruction: unpacked_instruction, - } - .to_vec()?, - _ => { - return Err(FarmClientError::ValueError(format!( - "Unsupported protocol {} for Fund {}", - protocol, fund_name - ))); - } - }; - - let mut accounts = vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - if matches!(unpacked_instruction, AmmInstruction::UserInit { .. }) { - AccountMeta::new(fund.fund_authority, false) - } else { - AccountMeta::new_readonly(fund.fund_authority, false) - }, - AccountMeta::new_readonly(pool_instruction.program_id, false), - if matches!(unpacked_instruction, AmmInstruction::AddLiquidity { .. }) - || matches!(unpacked_instruction, AmmInstruction::RemoveLiquidity { .. }) - { - AccountMeta::new( - self.get_fund_vault_account(fund_name, pool_or_farm_name, vault_type)?, - false, - ) - } else { - AccountMeta::new_readonly( - self.get_fund_vault_account(fund_name, pool_or_farm_name, vault_type)?, - false, - ) - }, - ]; - accounts.extend_from_slice(&pool_instruction.accounts[1..]); - if matches!(unpacked_instruction, AmmInstruction::Swap { .. }) { - accounts.push(AccountMeta::new_readonly(sysvar::instructions::id(), false)); - } - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } - - fn build_fund_vault_instruction( - &self, - admin_address: &Pubkey, - fund_name: &str, - vault_instruction: &Instruction, - vault_name: &str, - ) -> Result { - let fund = self.get_fund(fund_name)?; - let fund_ref = self.get_fund_ref(fund_name)?; - - let protocol = &FarmClient::get_protocol(vault_name)?; - let unpacked_instruction = VaultInstruction::unpack(vault_instruction.data.as_slice())?; - let data = match protocol { - Protocol::Raydium => FundInstruction::VaultInstructionRaydium { - instruction: unpacked_instruction, - } - .to_vec()?, - Protocol::Orca => FundInstruction::VaultInstructionOrca { - instruction: unpacked_instruction, - } - .to_vec()?, - _ => { - return Err(FarmClientError::ValueError(format!( - "Unsupported protocol {} for Fund {}", - protocol, fund_name - ))); - } - }; - - let mut accounts = vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(fund_ref, false), - AccountMeta::new(fund.info_account, false), - if matches!(unpacked_instruction, VaultInstruction::UserInit { .. }) { - AccountMeta::new(fund.fund_authority, false) - } else { - AccountMeta::new_readonly(fund.fund_authority, false) - }, - AccountMeta::new_readonly(vault_instruction.program_id, false), - if matches!(unpacked_instruction, VaultInstruction::AddLiquidity { .. }) - || matches!( - unpacked_instruction, - VaultInstruction::RemoveLiquidity { .. } - ) - { - AccountMeta::new( - self.get_fund_vault_account(fund_name, vault_name, FundVaultType::Vault)?, - false, - ) - } else { - AccountMeta::new_readonly( - self.get_fund_vault_account(fund_name, vault_name, FundVaultType::Vault)?, - false, - ) - }, - ]; - accounts.extend_from_slice(&vault_instruction.accounts[1..]); - - Ok(Instruction { - program_id: fund.fund_program_id, - data, - accounts, - }) - } -} diff --git a/farms/farm-client/src/client/governance_instructions.rs b/farms/farm-client/src/client/governance_instructions.rs deleted file mode 100644 index 6efbaf91c04..00000000000 --- a/farms/farm-client/src/client/governance_instructions.rs +++ /dev/null @@ -1,454 +0,0 @@ -//! Solana Farm Client Governance Instructions - -use { - crate::error::FarmClientError, - solana_farm_sdk::{ - id::{DAO_PROGRAM_NAME, DAO_TOKEN_NAME}, - token::Token, - }, - solana_sdk::{borsh::try_from_slice_unchecked, instruction::Instruction, pubkey::Pubkey}, - spl_governance::instruction as dao_instruction, - spl_governance::state::{ - governance::GovernanceConfig, - proposal::{get_proposal_address, VoteType}, - proposal_instruction::{ - get_proposal_instruction_address, InstructionData, ProposalInstructionV2, - }, - realm::get_realm_address, - token_owner_record::get_token_owner_record_address, - vote_record::{Vote, VoteChoice}, - }, -}; - -use super::FarmClient; - -impl FarmClient { - /// Creates a new instruction for tokens deposit to the farms realm - pub fn new_instruction_governance_tokens_deposit( - &self, - wallet_address: &Pubkey, - ui_amount: f64, - ) -> Result { - let dao_program = self.get_program_id(DAO_PROGRAM_NAME)?; - let realm_address = get_realm_address(&dao_program, DAO_PROGRAM_NAME); - let dao_token = self.get_token(DAO_TOKEN_NAME)?; - let token_addr = self.get_associated_token_address(wallet_address, DAO_TOKEN_NAME)?; - - let inst = dao_instruction::deposit_governing_tokens( - &dao_program, - &realm_address, - &token_addr, - wallet_address, - wallet_address, - wallet_address, - self.ui_amount_to_tokens_with_decimals(ui_amount, dao_token.decimals)?, - &dao_token.mint, - ); - - Ok(inst) - } - - /// Creates a new instruction for tokens withdrawal from the farms realm - pub fn new_instruction_governance_tokens_withdraw( - &self, - wallet_address: &Pubkey, - ) -> Result { - let dao_program = self.get_program_id(DAO_PROGRAM_NAME)?; - let realm_address = get_realm_address(&dao_program, DAO_PROGRAM_NAME); - let dao_token = self.get_token(DAO_TOKEN_NAME)?; - let token_addr = self.get_associated_token_address(wallet_address, DAO_TOKEN_NAME)?; - - let inst = dao_instruction::withdraw_governing_tokens( - &dao_program, - &realm_address, - &token_addr, - wallet_address, - &dao_token.mint, - ); - - Ok(inst) - } - - /// Creates a new instruction for initializing a new governance proposal - pub fn new_instruction_governance_proposal_new( - &self, - wallet_address: &Pubkey, - governance_name: &str, - proposal_name: &str, - proposal_link: &str, - proposal_index: u32, - ) -> Result { - let (dao_program, realm_address, dao_token, governance, token_owner, _proposal_address) = - self.get_dao_accounts(wallet_address, governance_name, proposal_index)?; - - let inst = dao_instruction::create_proposal( - &dao_program, - &governance, - &token_owner, - wallet_address, - wallet_address, - None, - &realm_address, - proposal_name.to_string(), - proposal_link.to_string(), - &dao_token.mint, - VoteType::SingleChoice, - vec![proposal_name.to_string()], - true, - proposal_index, - ); - - Ok(inst) - } - - /// Creates a new instruction for canceling governance proposal - pub fn new_instruction_governance_proposal_cancel( - &self, - wallet_address: &Pubkey, - governance_name: &str, - proposal_index: u32, - ) -> Result { - let (dao_program, _realm_address, _dao_token, governance, token_owner, proposal_address) = - self.get_dao_accounts(wallet_address, governance_name, proposal_index)?; - - let inst = dao_instruction::cancel_proposal( - &dao_program, - &proposal_address, - &token_owner, - wallet_address, - &governance, - ); - - Ok(inst) - } - - /// Creates a new instruction for adding a signatory to governance proposal - pub fn new_instruction_governance_signatory_add( - &self, - wallet_address: &Pubkey, - governance_name: &str, - proposal_index: u32, - signatory: &Pubkey, - ) -> Result { - let (dao_program, _realm_address, _dao_token, _governance, token_owner, proposal_address) = - self.get_dao_accounts(wallet_address, governance_name, proposal_index)?; - - let inst = dao_instruction::add_signatory( - &dao_program, - &proposal_address, - &token_owner, - wallet_address, - wallet_address, - signatory, - ); - - Ok(inst) - } - - /// Creates a new instruction for removing the signatory from governance proposal - pub fn new_instruction_governance_signatory_remove( - &self, - wallet_address: &Pubkey, - governance_name: &str, - proposal_index: u32, - signatory: &Pubkey, - ) -> Result { - let (dao_program, _realm_address, _dao_token, _governance, token_owner, proposal_address) = - self.get_dao_accounts(wallet_address, governance_name, proposal_index)?; - - let inst = dao_instruction::remove_signatory( - &dao_program, - &proposal_address, - &token_owner, - wallet_address, - signatory, - wallet_address, - ); - - Ok(inst) - } - - /// Creates a new instruction for signing off governance proposal - pub fn new_instruction_governance_sign_off( - &self, - wallet_address: &Pubkey, - governance_name: &str, - proposal_index: u32, - ) -> Result { - let (dao_program, _realm_address, _dao_token, _governance, _token_owner, proposal_address) = - self.get_dao_accounts(wallet_address, governance_name, proposal_index)?; - - let inst = - dao_instruction::sign_off_proposal(&dao_program, &proposal_address, wallet_address); - - Ok(inst) - } - - /// Creates a new instruction for casting a vote on governance proposal - pub fn new_instruction_governance_vote_cast( - &self, - wallet_address: &Pubkey, - governance_name: &str, - proposal_index: u32, - vote: u8, - ) -> Result { - let (dao_program, realm_address, dao_token, governance, token_owner, proposal_address) = - self.get_dao_accounts(wallet_address, governance_name, proposal_index)?; - - let voter_token_owner = get_token_owner_record_address( - &dao_program, - &realm_address, - &dao_token.mint, - wallet_address, - ); - - let inst = dao_instruction::cast_vote( - &dao_program, - &realm_address, - &governance, - &proposal_address, - &token_owner, - &voter_token_owner, - wallet_address, - &dao_token.mint, - wallet_address, - None, - if vote > 0 { - Vote::Approve(vec![VoteChoice { - rank: 0, - weight_percentage: 100, - }]) - } else { - Vote::Deny - }, - ); - - Ok(inst) - } - - /// Creates a new instruction for removing the vote from governance proposal - pub fn new_instruction_governance_vote_relinquish( - &self, - wallet_address: &Pubkey, - governance_name: &str, - proposal_index: u32, - ) -> Result { - let (dao_program, _realm_address, dao_token, governance, token_owner, proposal_address) = - self.get_dao_accounts(wallet_address, governance_name, proposal_index)?; - - let inst = dao_instruction::relinquish_vote( - &dao_program, - &governance, - &proposal_address, - &token_owner, - &dao_token.mint, - Some(*wallet_address), - Some(*wallet_address), - ); - - Ok(inst) - } - - /// Creates a new instruction for finalizing the vote on governance proposal - pub fn new_instruction_governance_vote_finalize( - &self, - wallet_address: &Pubkey, - governance_name: &str, - proposal_index: u32, - ) -> Result { - let (dao_program, realm_address, dao_token, governance, token_owner, proposal_address) = - self.get_dao_accounts(wallet_address, governance_name, proposal_index)?; - - let inst = dao_instruction::finalize_vote( - &dao_program, - &realm_address, - &governance, - &proposal_address, - &token_owner, - &dao_token.mint, - ); - - Ok(inst) - } - - /// Creates a new instruction for adding a new instruction to governance proposal - pub fn new_instruction_governance_instruction_insert( - &self, - wallet_address: &Pubkey, - governance_name: &str, - proposal_index: u32, - instruction_index: u16, - instruction: &Instruction, - ) -> Result { - let (dao_program, _realm_address, _dao_token, governance, token_owner, proposal_address) = - self.get_dao_accounts(wallet_address, governance_name, proposal_index)?; - - let instruction_data: InstructionData = instruction.clone().into(); - - let inst = dao_instruction::insert_instruction( - &dao_program, - &governance, - &proposal_address, - &token_owner, - wallet_address, - wallet_address, - 0, - instruction_index, - 0, - instruction_data, - ); - - Ok(inst) - } - - /// Creates a new instruction for removing the instruction from governance proposal - pub fn new_instruction_governance_instruction_remove( - &self, - wallet_address: &Pubkey, - governance_name: &str, - proposal_index: u32, - instruction_index: u16, - ) -> Result { - let (dao_program, _realm_address, _dao_token, _governance, token_owner, proposal_address) = - self.get_dao_accounts(wallet_address, governance_name, proposal_index)?; - - let instruction_address = get_proposal_instruction_address( - &dao_program, - &proposal_address, - &0u16.to_le_bytes(), - &instruction_index.to_le_bytes(), - ); - - let inst = dao_instruction::remove_instruction( - &dao_program, - &proposal_address, - &token_owner, - wallet_address, - &instruction_address, - wallet_address, - ); - - Ok(inst) - } - - /// Creates a new instruction for executing the instruction in governance proposal - pub fn new_instruction_governance_instruction_execute( - &self, - wallet_address: &Pubkey, - governance_name: &str, - proposal_index: u32, - instruction_index: u16, - ) -> Result { - let (dao_program, _realm_address, _dao_token, governance, _token_owner, proposal_address) = - self.get_dao_accounts(wallet_address, governance_name, proposal_index)?; - - let instruction_address = get_proposal_instruction_address( - &dao_program, - &proposal_address, - &0u16.to_le_bytes(), - &instruction_index.to_le_bytes(), - ); - - let data = self.rpc_client.get_account_data(&instruction_address)?; - let ins_data: InstructionData = - try_from_slice_unchecked::(data.as_slice()) - .map_err(|e| FarmClientError::IOError(e.to_string()))? - .instruction; - let mut instruction: Instruction = (&ins_data).into(); - - for account in &mut instruction.accounts { - if account.pubkey == governance { - account.is_signer = false; - } - } - - let inst = dao_instruction::execute_instruction( - &dao_program, - &governance, - &proposal_address, - &instruction_address, - &instruction.program_id, - instruction.accounts.as_slice(), - ); - - Ok(inst) - } - - /// Creates a new instruction for marking the instruction in governance proposal as failed - pub fn new_instruction_governance_instruction_flag_error( - &self, - wallet_address: &Pubkey, - governance_name: &str, - proposal_index: u32, - instruction_index: u16, - ) -> Result { - let (dao_program, _realm_address, _dao_token, _governance, token_owner, proposal_address) = - self.get_dao_accounts(wallet_address, governance_name, proposal_index)?; - - let instruction_address = get_proposal_instruction_address( - &dao_program, - &proposal_address, - &0u16.to_le_bytes(), - &instruction_index.to_le_bytes(), - ); - - let inst = dao_instruction::flag_instruction_error( - &dao_program, - &proposal_address, - &token_owner, - wallet_address, - &instruction_address, - ); - - Ok(inst) - } - - /// Creates a new instruction for changing the governance config - pub fn new_instruction_governance_set_config( - &self, - wallet_address: &Pubkey, - governance_name: &str, - config: &GovernanceConfig, - ) -> Result { - let (dao_program, _realm_address, _dao_token, governance, _token_owner, _proposal_address) = - self.get_dao_accounts(wallet_address, governance_name, 0)?; - - let inst = - dao_instruction::set_governance_config(&dao_program, &governance, config.clone()); - - Ok(inst) - } - - /////////////// helpers - fn get_dao_accounts( - &self, - wallet_address: &Pubkey, - governance_name: &str, - proposal_index: u32, - ) -> Result<(Pubkey, Pubkey, Token, Pubkey, Pubkey, Pubkey), FarmClientError> { - let dao_program = self.get_program_id(DAO_PROGRAM_NAME)?; - let realm_address = get_realm_address(&dao_program, DAO_PROGRAM_NAME); - let dao_token = self.get_token(DAO_TOKEN_NAME)?; - let governance = self.governance_get_address(governance_name)?; - let token_owner = get_token_owner_record_address( - &dao_program, - &realm_address, - &dao_token.mint, - wallet_address, - ); - let proposal_address = get_proposal_address( - &dao_program, - &governance, - &dao_token.mint, - &proposal_index.to_le_bytes(), - ); - Ok(( - dao_program, - realm_address, - dao_token, - governance, - token_owner, - proposal_address, - )) - } -} diff --git a/farms/farm-client/src/client/main_router_instructions.rs b/farms/farm-client/src/client/main_router_instructions.rs deleted file mode 100644 index 0c46acf9fe3..00000000000 --- a/farms/farm-client/src/client/main_router_instructions.rs +++ /dev/null @@ -1,670 +0,0 @@ -//! Solana Farm Client RefDB Instructions - -use { - crate::error::FarmClientError, - solana_farm_sdk::{ - farm::Farm, - fund::Fund, - id::{main_router, main_router_multisig}, - instruction::{main_router::MainInstruction, refdb::RefDbInstruction}, - pool::Pool, - program::multisig::Multisig, - refdb, - string::str_to_as64, - token::Token, - vault::Vault, - ProgramIDType, - }, - solana_sdk::{ - bpf_loader_upgradeable, - instruction::{AccountMeta, Instruction}, - pubkey::Pubkey, - system_program, sysvar, - }, - std::vec::Vec, -}; - -use super::FarmClient; - -impl FarmClient { - /// Creates a new instruction for writing the record into on-chain RefDB - fn new_instruction_refdb_write( - &self, - admin_address: &Pubkey, - refdb_name: &str, - record: refdb::Record, - ) -> Result { - // fill in accounts and instruction data - let mut inst = Instruction { - program_id: main_router::id(), - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new(main_router_multisig::id(), false), - AccountMeta::new(refdb::find_refdb_pda(refdb_name).0, false), - AccountMeta::new_readonly(system_program::id(), false), - ], - }; - - inst.data = MainInstruction::RefDbInstruction { - instruction: RefDbInstruction::Write { record }, - } - .to_vec()?; - - Ok(inst) - } - - /// Creates a new instruction for deleteing the record from on-chain RefDB - fn new_instruction_refdb_delete( - &self, - admin_address: &Pubkey, - refdb_name: &str, - record: refdb::Record, - ) -> Result { - // fill in accounts and instruction data - let mut inst = Instruction { - program_id: main_router::id(), - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new(main_router_multisig::id(), false), - AccountMeta::new(refdb::find_refdb_pda(refdb_name).0, false), - AccountMeta::new_readonly(system_program::id(), false), - ], - }; - - inst.data = MainInstruction::RefDbInstruction { - instruction: RefDbInstruction::Delete { record }, - } - .to_vec()?; - - Ok(inst) - } - - /// Creates a new instruction for initializing on-chain RefDB storage - pub fn new_instruction_refdb_init( - &self, - admin_address: &Pubkey, - refdb_name: &str, - reference_type: refdb::ReferenceType, - max_records: u32, - init_account: bool, - ) -> Result { - // fill in accounts and instruction data - let mut inst = Instruction { - program_id: main_router::id(), - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new(main_router_multisig::id(), false), - AccountMeta::new(refdb::find_refdb_pda(refdb_name).0, false), - AccountMeta::new_readonly(system_program::id(), false), - ], - }; - - inst.data = MainInstruction::RefDbInstruction { - instruction: RefDbInstruction::Init { - name: str_to_as64(refdb_name)?, - reference_type, - max_records, - init_account: init_account && refdb::REFDB_ONCHAIN_INIT, - }, - } - .to_vec()?; - - Ok(inst) - } - - /// Creates a new instruction for removing on-chain RefDB storage - pub fn new_instruction_refdb_drop( - &self, - admin_address: &Pubkey, - refdb_name: &str, - close_account: bool, - ) -> Result { - // fill in accounts and instruction data - let mut inst = Instruction { - program_id: main_router::id(), - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new(main_router_multisig::id(), false), - AccountMeta::new(refdb::find_refdb_pda(refdb_name).0, false), - AccountMeta::new_readonly(system_program::id(), false), - ], - }; - - inst.data = MainInstruction::RefDbInstruction { - instruction: RefDbInstruction::Drop { close_account }, - } - .to_vec()?; - - Ok(inst) - } - - /// Creates a new Instruction for removing the object reference from chain - pub fn new_instruction_remove_reference( - &self, - admin_address: &Pubkey, - storage_type: refdb::StorageType, - object_name: &str, - ) -> Result { - let refdb_index = self - .get_refdb_index(&storage_type.to_string(), object_name) - .unwrap(); - self.new_instruction_refdb_delete( - admin_address, - &storage_type.to_string(), - refdb::Record { - index: refdb_index.map(|idx| idx as u32), - counter: 0, - tag: 0, - name: str_to_as64(object_name)?, - reference: refdb::Reference::Empty, - }, - ) - } - - /// Creates a new instruction for initializing Main Router multisig with a new set of signers - pub fn new_instruction_set_admins( - &self, - admin_address: &Pubkey, - admin_signers: &[Pubkey], - min_signatures: u8, - ) -> Result { - if admin_signers.is_empty() || min_signatures == 0 { - return Err(FarmClientError::ValueError( - "At least one signer is required".to_string(), - )); - } else if min_signatures as usize > admin_signers.len() - || admin_signers.len() > Multisig::MAX_SIGNERS - { - return Err(FarmClientError::ValueError( - "Invalid number of signatures".to_string(), - )); - } - - // fill in accounts and instruction data - let mut inst = Instruction { - program_id: main_router::id(), - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new(main_router_multisig::id(), false), - AccountMeta::new_readonly(system_program::id(), false), - ], - }; - - for key in admin_signers { - inst.accounts.push(AccountMeta::new_readonly(*key, false)); - } - - inst.data = MainInstruction::SetAdminSigners { min_signatures }.to_vec()?; - - Ok(inst) - } - - /// Creates a new instruction for setting new program upgrade signers - pub fn new_instruction_set_program_admins( - &self, - admin_address: &Pubkey, - prog_id: &Pubkey, - admin_signers: &[Pubkey], - min_signatures: u8, - ) -> Result { - if admin_signers.is_empty() || min_signatures == 0 { - return Err(FarmClientError::ValueError( - "At least one signer is required".to_string(), - )); - } else if min_signatures as usize > admin_signers.len() - || admin_signers.len() > Multisig::MAX_SIGNERS - { - return Err(FarmClientError::ValueError( - "Invalid number of signatures".to_string(), - )); - } - - // fill in accounts and instruction data - let mut inst = Instruction { - program_id: main_router::id(), - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new(self.get_program_multisig_account(prog_id)?, false), - AccountMeta::new_readonly(*prog_id, false), - AccountMeta::new(self.get_program_buffer_account(prog_id)?, false), - AccountMeta::new_readonly(system_program::id(), false), - AccountMeta::new_readonly(bpf_loader_upgradeable::id(), false), - ], - }; - - for key in admin_signers { - inst.accounts.push(AccountMeta::new_readonly(*key, false)); - } - - inst.data = MainInstruction::SetProgramAdminSigners { min_signatures }.to_vec()?; - - Ok(inst) - } - - /// Creates a new instruction for setting single upgrade authority for the program - pub fn new_instruction_set_program_single_authority( - &self, - admin_address: &Pubkey, - prog_id: &Pubkey, - upgrade_authority: &Pubkey, - ) -> Result { - // fill in accounts and instruction data - Ok(Instruction { - program_id: main_router::id(), - data: MainInstruction::SetProgramSingleAuthority.to_vec()?, - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new(self.get_program_multisig_account(prog_id)?, false), - AccountMeta::new_readonly(*prog_id, false), - AccountMeta::new(self.get_program_buffer_account(prog_id)?, false), - AccountMeta::new_readonly(*upgrade_authority, false), - AccountMeta::new_readonly(bpf_loader_upgradeable::id(), false), - ], - }) - } - - /// Creates a new instruction for upgrading the program from the buffer - pub fn new_instruction_upgrade_program( - &self, - admin_address: &Pubkey, - prog_id: &Pubkey, - source_buffer_address: &Pubkey, - ) -> Result { - // fill in accounts and instruction data - Ok(Instruction { - program_id: main_router::id(), - data: MainInstruction::UpgradeProgram.to_vec()?, - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new(self.get_program_multisig_account(prog_id)?, false), - AccountMeta::new(*prog_id, false), - AccountMeta::new(self.get_program_buffer_account(prog_id)?, false), - AccountMeta::new(*source_buffer_address, false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - AccountMeta::new_readonly(bpf_loader_upgradeable::id(), false), - ], - }) - } - - /// Creates a new Instruction for recording the Program ID metadata on-chain - pub fn new_instruction_add_program_id( - &self, - admin_address: &Pubkey, - name: &str, - program_id: &Pubkey, - program_id_type: ProgramIDType, - refdb_index: Option, - ) -> Result { - self.new_instruction_refdb_write( - admin_address, - &refdb::StorageType::Program.to_string(), - refdb::Record { - index: refdb_index.map(|idx| idx as u32), - counter: 0, - tag: program_id_type as u16, - name: str_to_as64(name)?, - reference: refdb::Reference::Pubkey { data: *program_id }, - }, - ) - } - - /// Creates a new Instruction for removing the Program ID metadata from chain - pub fn new_instruction_remove_program_id( - &self, - admin_address: &Pubkey, - name: &str, - ) -> Result { - let refdb_index = if self.get_program_id(name).is_ok() { - self.get_refdb_index(&refdb::StorageType::Program.to_string(), name) - .unwrap() - } else { - None - }; - self.new_instruction_refdb_delete( - admin_address, - &refdb::StorageType::Program.to_string(), - refdb::Record { - index: refdb_index.map(|idx| idx as u32), - counter: 0, - tag: 0, - name: str_to_as64(name)?, - reference: refdb::Reference::Empty, - }, - ) - } - - /// Creates a new Instruction for recording Fund's metadata on-chain - pub fn new_instruction_add_fund( - &self, - admin_address: &Pubkey, - fund: Fund, - ) -> Result { - // fill in accounts and instruction data - let mut inst = Instruction { - program_id: main_router::id(), - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new(main_router_multisig::id(), false), - AccountMeta::new( - refdb::find_refdb_pda(&refdb::StorageType::Fund.to_string()).0, - false, - ), - AccountMeta::new( - refdb::find_target_pda(refdb::StorageType::Fund, &fund.name).0, - false, - ), - AccountMeta::new_readonly(system_program::id(), false), - ], - }; - inst.data = MainInstruction::AddFund { fund }.to_vec()?; - - Ok(inst) - } - - /// Creates a new Instruction for removing Fund's on-chain metadata - pub fn new_instruction_remove_fund( - &self, - admin_address: &Pubkey, - fund_name: &str, - ) -> Result { - // fill in accounts and instruction data - let name = str_to_as64(fund_name)?; - let refdb_index = if let Ok(fund) = self.get_fund(fund_name) { - fund.refdb_index - } else { - None - }; - let mut inst = Instruction { - program_id: main_router::id(), - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new(main_router_multisig::id(), false), - AccountMeta::new( - refdb::find_refdb_pda(&refdb::StorageType::Fund.to_string()).0, - false, - ), - AccountMeta::new( - refdb::find_target_pda(refdb::StorageType::Fund, &name).0, - false, - ), - AccountMeta::new_readonly(system_program::id(), false), - ], - }; - - inst.data = MainInstruction::RemoveFund { name, refdb_index }.to_vec()?; - - Ok(inst) - } - - /// Creates a new Instruction for recording Vault's metadata on-chain - pub fn new_instruction_add_vault( - &self, - admin_address: &Pubkey, - vault: Vault, - ) -> Result { - // fill in accounts and instruction data - let mut inst = Instruction { - program_id: main_router::id(), - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new(main_router_multisig::id(), false), - AccountMeta::new( - refdb::find_refdb_pda(&refdb::StorageType::Vault.to_string()).0, - false, - ), - AccountMeta::new( - refdb::find_target_pda(refdb::StorageType::Vault, &vault.name).0, - false, - ), - AccountMeta::new_readonly(system_program::id(), false), - ], - }; - inst.data = MainInstruction::AddVault { vault }.to_vec()?; - - Ok(inst) - } - - /// Creates a new Instruction for removing Vault's on-chain metadata - pub fn new_instruction_remove_vault( - &self, - admin_address: &Pubkey, - vault_name: &str, - ) -> Result { - // fill in accounts and instruction data - let name = str_to_as64(vault_name)?; - let refdb_index = if let Ok(vault) = self.get_vault(vault_name) { - vault.refdb_index - } else { - None - }; - let mut inst = Instruction { - program_id: main_router::id(), - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new(main_router_multisig::id(), false), - AccountMeta::new( - refdb::find_refdb_pda(&refdb::StorageType::Vault.to_string()).0, - false, - ), - AccountMeta::new( - refdb::find_target_pda(refdb::StorageType::Vault, &name).0, - false, - ), - AccountMeta::new_readonly(system_program::id(), false), - ], - }; - - inst.data = MainInstruction::RemoveVault { name, refdb_index }.to_vec()?; - - Ok(inst) - } - - /// Creates a new Instruction for recording Pool's metadata on-chain - pub fn new_instruction_add_pool( - &self, - admin_address: &Pubkey, - pool: Pool, - ) -> Result { - // fill in accounts and instruction data - let mut inst = Instruction { - program_id: main_router::id(), - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new(main_router_multisig::id(), false), - AccountMeta::new( - refdb::find_refdb_pda(&refdb::StorageType::Pool.to_string()).0, - false, - ), - AccountMeta::new( - refdb::find_target_pda(refdb::StorageType::Pool, &pool.name).0, - false, - ), - AccountMeta::new_readonly(system_program::id(), false), - ], - }; - - inst.data = MainInstruction::AddPool { pool }.to_vec()?; - - Ok(inst) - } - - /// Creates a new Instruction for removing Pool's on-chain metadata - pub fn new_instruction_remove_pool( - &self, - admin_address: &Pubkey, - pool_name: &str, - ) -> Result { - // fill in accounts and instruction data - let name = str_to_as64(pool_name)?; - let refdb_index = if let Ok(pool) = self.get_pool(pool_name) { - pool.refdb_index - } else { - None - }; - let mut inst = Instruction { - program_id: main_router::id(), - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new(main_router_multisig::id(), false), - AccountMeta::new( - refdb::find_refdb_pda(&refdb::StorageType::Pool.to_string()).0, - false, - ), - AccountMeta::new( - refdb::find_target_pda(refdb::StorageType::Pool, &name).0, - false, - ), - AccountMeta::new_readonly(system_program::id(), false), - ], - }; - - inst.data = MainInstruction::RemovePool { name, refdb_index }.to_vec()?; - - Ok(inst) - } - - /// Creates a new Instruction for recording Farm's metadata on-chain - pub fn new_instruction_add_farm( - &self, - admin_address: &Pubkey, - farm: Farm, - ) -> Result { - // fill in accounts and instruction data - let mut inst = Instruction { - program_id: main_router::id(), - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new(main_router_multisig::id(), false), - AccountMeta::new( - refdb::find_refdb_pda(&refdb::StorageType::Farm.to_string()).0, - false, - ), - AccountMeta::new( - refdb::find_target_pda(refdb::StorageType::Farm, &farm.name).0, - false, - ), - AccountMeta::new_readonly(system_program::id(), false), - ], - }; - - inst.data = MainInstruction::AddFarm { farm }.to_vec()?; - - Ok(inst) - } - - /// Creates a new Instruction for removing Farm's on-chain metadata - pub fn new_instruction_remove_farm( - &self, - admin_address: &Pubkey, - farm_name: &str, - ) -> Result { - // fill in accounts and instruction data - let name = str_to_as64(farm_name)?; - let refdb_index = if let Ok(farm) = self.get_farm(farm_name) { - farm.refdb_index - } else { - None - }; - let mut inst = Instruction { - program_id: main_router::id(), - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new(main_router_multisig::id(), false), - AccountMeta::new( - refdb::find_refdb_pda(&refdb::StorageType::Farm.to_string()).0, - false, - ), - AccountMeta::new( - refdb::find_target_pda(refdb::StorageType::Farm, &name).0, - false, - ), - AccountMeta::new_readonly(system_program::id(), false), - ], - }; - - inst.data = MainInstruction::RemoveFarm { name, refdb_index }.to_vec()?; - - Ok(inst) - } - - /// Creates a new Instruction for recording Token's metadata on-chain - pub fn new_instruction_add_token( - &self, - admin_address: &Pubkey, - token: Token, - ) -> Result { - // fill in accounts and instruction data - let mut inst = Instruction { - program_id: main_router::id(), - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new(main_router_multisig::id(), false), - AccountMeta::new( - refdb::find_refdb_pda(&refdb::StorageType::Token.to_string()).0, - false, - ), - AccountMeta::new( - refdb::find_target_pda(refdb::StorageType::Token, &token.name).0, - false, - ), - AccountMeta::new_readonly(system_program::id(), false), - ], - }; - - inst.data = MainInstruction::AddToken { token }.to_vec()?; - - Ok(inst) - } - - /// Creates a new Instruction for removing Token's on-chain metadata - pub fn new_instruction_remove_token( - &self, - admin_address: &Pubkey, - token_name: &str, - ) -> Result { - // fill in accounts and instruction data - let name = str_to_as64(token_name)?; - let refdb_index = if let Ok(token) = self.get_token(token_name) { - token.refdb_index - } else { - None - }; - let mut inst = Instruction { - program_id: main_router::id(), - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new(main_router_multisig::id(), false), - AccountMeta::new( - refdb::find_refdb_pda(&refdb::StorageType::Token.to_string()).0, - false, - ), - AccountMeta::new( - refdb::find_target_pda(refdb::StorageType::Token, &name).0, - false, - ), - AccountMeta::new_readonly(system_program::id(), false), - ], - }; - - inst.data = MainInstruction::RemoveToken { name, refdb_index }.to_vec()?; - - Ok(inst) - } -} diff --git a/farms/farm-client/src/client/pool_accounts_orca.rs b/farms/farm-client/src/client/pool_accounts_orca.rs deleted file mode 100644 index 5aa4928d036..00000000000 --- a/farms/farm-client/src/client/pool_accounts_orca.rs +++ /dev/null @@ -1,198 +0,0 @@ -//! Solana Farm Client Orca Pools accounts builder - -use { - crate::error::FarmClientError, - solana_farm_sdk::pool::PoolRoute, - solana_sdk::{instruction::AccountMeta, program_error::ProgramError, pubkey::Pubkey}, - std::vec::Vec, -}; - -use super::FarmClient; - -impl FarmClient { - /// Returns instruction accounts for adding liquidity to an Orca pool - pub fn get_add_liquidity_accounts_orca( - &self, - wallet_address: &Pubkey, - pool_name: &str, - ) -> Result, FarmClientError> { - // get pool info - let pool = self.get_pool(pool_name)?; - - // get tokens info - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - - // get user accounts info - let user_token_a_account = self.get_token_account(wallet_address, &token_a); - let user_token_b_account = self.get_token_account(wallet_address, &token_b); - let user_lp_token_account = self.get_token_account(wallet_address, &lp_token); - - // fill in accounts data - let mut accounts = vec![]; - if let PoolRoute::Orca { - amm_id, - amm_authority, - .. - } = pool.route - { - accounts.push(AccountMeta::new_readonly(*wallet_address, true)); - accounts.push(AccountMeta::new( - user_token_a_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_token_b_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_lp_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new_readonly(pool.pool_program_id, false)); - accounts.push(AccountMeta::new( - pool.token_a_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - pool.token_b_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - lp_token.ok_or(ProgramError::UninitializedAccount)?.mint, - false, - )); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new_readonly(amm_id, false)); - accounts.push(AccountMeta::new_readonly(amm_authority, false)); - } - - Ok(accounts) - } - - /// Returns instruction accounts for removing liquidity from an Orca pool - pub fn get_remove_liquidity_accounts_orca( - &self, - wallet_address: &Pubkey, - pool_name: &str, - ) -> Result, FarmClientError> { - // get pool info - let pool = self.get_pool(pool_name)?; - - // get tokens info - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - - // get user accounts info - let user_token_a_account = self.get_token_account(wallet_address, &token_a); - let user_token_b_account = self.get_token_account(wallet_address, &token_b); - let user_lp_token_account = self.get_token_account(wallet_address, &lp_token); - - // fill in accounts data - let mut accounts = vec![]; - if let PoolRoute::Orca { - amm_id, - amm_authority, - fees_account, - } = pool.route - { - accounts.push(AccountMeta::new_readonly(*wallet_address, true)); - accounts.push(AccountMeta::new( - user_token_a_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_token_b_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_lp_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new_readonly(pool.pool_program_id, false)); - accounts.push(AccountMeta::new( - pool.token_a_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - pool.token_b_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - lp_token.ok_or(ProgramError::UninitializedAccount)?.mint, - false, - )); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new_readonly(amm_id, false)); - accounts.push(AccountMeta::new_readonly(amm_authority, false)); - accounts.push(AccountMeta::new(fees_account, false)); - } - - Ok(accounts) - } - - /// Returns instruction accounts for swapping tokens in an Orca pool - pub fn get_swap_accounts_orca( - &self, - wallet_address: &Pubkey, - pool_name: &str, - ) -> Result, FarmClientError> { - // get pool info - let pool = self.get_pool(pool_name)?; - - // get tokens info - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - - // get user accounts info - let user_token_a_account = self.get_token_account(wallet_address, &token_a); - let user_token_b_account = self.get_token_account(wallet_address, &token_b); - - // fill in accounts data - let mut accounts = vec![]; - if let PoolRoute::Orca { - amm_id, - amm_authority, - fees_account, - } = pool.route - { - accounts.push(AccountMeta::new_readonly(*wallet_address, true)); - accounts.push(AccountMeta::new( - user_token_a_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_token_b_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new_readonly(pool.pool_program_id, false)); - accounts.push(AccountMeta::new( - pool.token_a_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - pool.token_b_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - lp_token.ok_or(ProgramError::UninitializedAccount)?.mint, - false, - )); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new_readonly(amm_id, false)); - accounts.push(AccountMeta::new_readonly(amm_authority, false)); - accounts.push(AccountMeta::new(fees_account, false)); - } - - Ok(accounts) - } -} diff --git a/farms/farm-client/src/client/pool_accounts_raydium.rs b/farms/farm-client/src/client/pool_accounts_raydium.rs deleted file mode 100644 index 800e965dd44..00000000000 --- a/farms/farm-client/src/client/pool_accounts_raydium.rs +++ /dev/null @@ -1,260 +0,0 @@ -//! Solana Farm Client Raydium Pools accounts builder - -use { - crate::error::FarmClientError, - solana_farm_sdk::pool::PoolRoute, - solana_sdk::{instruction::AccountMeta, program_error::ProgramError, pubkey::Pubkey}, - std::vec::Vec, -}; - -use super::FarmClient; - -impl FarmClient { - /// Returns instruction accounts for adding liquidity to a Raydium pool - pub fn get_add_liquidity_accounts_raydium( - &self, - wallet_address: &Pubkey, - pool_name: &str, - ) -> Result, FarmClientError> { - // get pool info - let pool = self.get_pool(pool_name)?; - - // get tokens info - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - - // get user accounts info - let user_token_a_account = self.get_token_account(wallet_address, &token_a); - let user_token_b_account = self.get_token_account(wallet_address, &token_b); - let user_lp_token_account = self.get_token_account(wallet_address, &lp_token); - - // fill in accounts data - let mut accounts = vec![]; - if let PoolRoute::Raydium { - amm_id, - amm_authority, - amm_open_orders, - amm_target, - serum_market, - .. - } = pool.route - { - accounts.push(AccountMeta::new_readonly(*wallet_address, true)); - accounts.push(AccountMeta::new( - user_token_a_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_token_b_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_lp_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new_readonly(pool.pool_program_id, false)); - accounts.push(AccountMeta::new( - pool.token_a_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - pool.token_b_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - lp_token.ok_or(ProgramError::UninitializedAccount)?.mint, - false, - )); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new(amm_id, false)); - accounts.push(AccountMeta::new_readonly(amm_authority, false)); - accounts.push(AccountMeta::new_readonly(amm_open_orders, false)); - accounts.push(AccountMeta::new(amm_target, false)); - accounts.push(AccountMeta::new_readonly(serum_market, false)); - } - - Ok(accounts) - } - - /// Returns instruction accounts for removing liquidity from a Raydium pool - pub fn get_remove_liquidity_accounts_raydium( - &self, - wallet_address: &Pubkey, - pool_name: &str, - ) -> Result, FarmClientError> { - // get pool info - let pool = self.get_pool(pool_name)?; - - // get tokens info - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - - // get user accounts info - let user_token_a_account = self.get_token_account(wallet_address, &token_a); - let user_token_b_account = self.get_token_account(wallet_address, &token_b); - let user_lp_token_account = self.get_token_account(wallet_address, &lp_token); - - // fill in accounts data - let mut accounts = vec![]; - if let PoolRoute::Raydium { - amm_id, - amm_authority, - amm_open_orders, - amm_target, - pool_withdraw_queue, - pool_temp_lp_token_account, - serum_program_id, - serum_market, - serum_coin_vault_account, - serum_pc_vault_account, - serum_vault_signer, - serum_bids, - serum_asks, - serum_event_queue, - } = pool.route - { - accounts.push(AccountMeta::new_readonly(*wallet_address, true)); - accounts.push(AccountMeta::new( - user_token_a_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_token_b_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_lp_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new_readonly(pool.pool_program_id, false)); - - accounts.push(AccountMeta::new(pool_withdraw_queue, false)); - accounts.push(AccountMeta::new(pool_temp_lp_token_account, false)); - accounts.push(AccountMeta::new( - pool.token_a_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - pool.token_b_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - lp_token.ok_or(ProgramError::UninitializedAccount)?.mint, - false, - )); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new(amm_id, false)); - accounts.push(AccountMeta::new_readonly(amm_authority, false)); - accounts.push(AccountMeta::new(amm_open_orders, false)); - accounts.push(AccountMeta::new(amm_target, false)); - accounts.push(AccountMeta::new(serum_market, false)); - accounts.push(AccountMeta::new_readonly(serum_program_id, false)); - accounts.push(AccountMeta::new( - serum_bids.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - serum_asks.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - serum_event_queue.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new(serum_coin_vault_account, false)); - accounts.push(AccountMeta::new(serum_pc_vault_account, false)); - accounts.push(AccountMeta::new_readonly(serum_vault_signer, false)); - } - - Ok(accounts) - } - - /// Returns instruction accounts for swapping tokens in a Raydium pool - pub fn get_swap_accounts_raydium( - &self, - wallet_address: &Pubkey, - pool_name: &str, - ) -> Result, FarmClientError> { - // get pool info - let pool = self.get_pool(pool_name)?; - - // get tokens info - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - - // get user accounts info - let user_token_a_account = self.get_token_account(wallet_address, &token_a); - let user_token_b_account = self.get_token_account(wallet_address, &token_b); - - // fill in accounts data - let mut accounts = vec![]; - if let PoolRoute::Raydium { - amm_id, - amm_authority, - amm_open_orders, - amm_target, - pool_withdraw_queue: _, - pool_temp_lp_token_account: _, - serum_program_id, - serum_market, - serum_coin_vault_account, - serum_pc_vault_account, - serum_vault_signer, - serum_bids, - serum_asks, - serum_event_queue, - } = pool.route - { - accounts.push(AccountMeta::new_readonly(*wallet_address, true)); - accounts.push(AccountMeta::new( - user_token_a_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_token_b_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new_readonly(pool.pool_program_id, false)); - accounts.push(AccountMeta::new( - pool.token_a_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - pool.token_b_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new(amm_id, false)); - accounts.push(AccountMeta::new_readonly(amm_authority, false)); - accounts.push(AccountMeta::new(amm_open_orders, false)); - accounts.push(AccountMeta::new(amm_target, false)); - accounts.push(AccountMeta::new(serum_market, false)); - accounts.push(AccountMeta::new_readonly(serum_program_id, false)); - accounts.push(AccountMeta::new( - serum_bids.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - serum_asks.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - serum_event_queue.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new(serum_coin_vault_account, false)); - accounts.push(AccountMeta::new(serum_pc_vault_account, false)); - accounts.push(AccountMeta::new_readonly(serum_vault_signer, false)); - } - - Ok(accounts) - } -} diff --git a/farms/farm-client/src/client/pool_accounts_saber.rs b/farms/farm-client/src/client/pool_accounts_saber.rs deleted file mode 100644 index 4242a5aea0d..00000000000 --- a/farms/farm-client/src/client/pool_accounts_saber.rs +++ /dev/null @@ -1,319 +0,0 @@ -//! Solana Farm Client Saber Pools accounts builder - -use { - crate::error::FarmClientError, - solana_farm_sdk::{pool::PoolRoute, token::TokenSelector}, - solana_sdk::{instruction::AccountMeta, program_error::ProgramError, pubkey::Pubkey, sysvar}, - std::vec::Vec, -}; - -use super::FarmClient; - -impl FarmClient { - /// Returns instruction accounts for adding liquidity to a Saber pool - pub fn get_add_liquidity_accounts_saber( - &self, - wallet_address: &Pubkey, - pool_name: &str, - ) -> Result, FarmClientError> { - // get pool info - let pool = self.get_pool(pool_name)?; - - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - let user_lp_token_account = self.get_token_account(wallet_address, &lp_token); - - // fill in accounts data - let mut accounts = vec![]; - if let PoolRoute::Saber { - swap_account, - swap_authority, - wrapped_token_a_ref, - wrapped_token_b_ref, - .. - } = pool.route - { - let wrapped_token_a = self.get_token_by_ref_from_cache(&wrapped_token_a_ref)?; - let user_token_a_account = if wrapped_token_a.is_some() { - self.get_token_account(wallet_address, &wrapped_token_a) - } else { - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - self.get_token_account(wallet_address, &token_a) - }; - let wrapped_token_b = self.get_token_by_ref_from_cache(&wrapped_token_b_ref)?; - let user_token_b_account = if wrapped_token_b.is_some() { - self.get_token_account(wallet_address, &wrapped_token_b) - } else { - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - self.get_token_account(wallet_address, &token_b) - }; - - accounts.push(AccountMeta::new_readonly(*wallet_address, true)); - accounts.push(AccountMeta::new( - user_token_a_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_token_b_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_lp_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new_readonly(pool.pool_program_id, false)); - accounts.push(AccountMeta::new( - pool.token_a_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - pool.token_b_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - lp_token.ok_or(ProgramError::UninitializedAccount)?.mint, - false, - )); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new_readonly(sysvar::clock::id(), false)); - accounts.push(AccountMeta::new_readonly(swap_account, false)); - accounts.push(AccountMeta::new_readonly(swap_authority, false)); - } - - Ok(accounts) - } - - /// Returns instruction accounts for removing liquidity from a Saber pool - pub fn get_remove_liquidity_accounts_saber( - &self, - wallet_address: &Pubkey, - pool_name: &str, - ) -> Result, FarmClientError> { - // get pool info - let pool = self.get_pool(pool_name)?; - - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - let user_lp_token_account = self.get_token_account(wallet_address, &lp_token); - - // fill in accounts data - let mut accounts = vec![]; - if let PoolRoute::Saber { - swap_account, - swap_authority, - fees_account_a, - fees_account_b, - wrapped_token_a_ref, - wrapped_token_b_ref, - .. - } = pool.route - { - let wrapped_token_a = self.get_token_by_ref_from_cache(&wrapped_token_a_ref)?; - let user_token_a_account = if wrapped_token_a.is_some() { - self.get_token_account(wallet_address, &wrapped_token_a) - } else { - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - self.get_token_account(wallet_address, &token_a) - }; - let wrapped_token_b = self.get_token_by_ref_from_cache(&wrapped_token_b_ref)?; - let user_token_b_account = if wrapped_token_b.is_some() { - self.get_token_account(wallet_address, &wrapped_token_b) - } else { - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - self.get_token_account(wallet_address, &token_b) - }; - - accounts.push(AccountMeta::new_readonly(*wallet_address, true)); - accounts.push(AccountMeta::new( - user_token_a_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_token_b_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_lp_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new_readonly(pool.pool_program_id, false)); - accounts.push(AccountMeta::new( - pool.token_a_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - pool.token_b_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - lp_token.ok_or(ProgramError::UninitializedAccount)?.mint, - false, - )); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new_readonly(swap_account, false)); - accounts.push(AccountMeta::new_readonly(swap_authority, false)); - accounts.push(AccountMeta::new(fees_account_a, false)); - accounts.push(AccountMeta::new(fees_account_b, false)); - } - - Ok(accounts) - } - - /// Returns instruction accounts for swapping tokens in a Saber pool - pub fn get_swap_accounts_saber( - &self, - wallet_address: &Pubkey, - pool_name: &str, - ) -> Result, FarmClientError> { - // get pool info - let pool = self.get_pool(pool_name)?; - - // fill in accounts data - let mut accounts = vec![]; - if let PoolRoute::Saber { - swap_account, - swap_authority, - fees_account_a, - fees_account_b, - wrapped_token_a_ref, - wrapped_token_b_ref, - .. - } = pool.route - { - let wrapped_token_a = self.get_token_by_ref_from_cache(&wrapped_token_a_ref)?; - let user_token_a_account = if wrapped_token_a.is_some() { - self.get_token_account(wallet_address, &wrapped_token_a) - } else { - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - self.get_token_account(wallet_address, &token_a) - }; - let wrapped_token_b = self.get_token_by_ref_from_cache(&wrapped_token_b_ref)?; - let user_token_b_account = if wrapped_token_b.is_some() { - self.get_token_account(wallet_address, &wrapped_token_b) - } else { - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - self.get_token_account(wallet_address, &token_b) - }; - - accounts.push(AccountMeta::new_readonly(*wallet_address, true)); - accounts.push(AccountMeta::new( - user_token_a_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_token_b_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new_readonly(pool.pool_program_id, false)); - accounts.push(AccountMeta::new( - pool.token_a_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - pool.token_b_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new_readonly(sysvar::clock::id(), false)); - accounts.push(AccountMeta::new_readonly(swap_account, false)); - accounts.push(AccountMeta::new_readonly(swap_authority, false)); - accounts.push(AccountMeta::new(fees_account_a, false)); - accounts.push(AccountMeta::new(fees_account_b, false)); - } - - Ok(accounts) - } - - /// Returns instruction accounts for wrapping token into a Saber decimal token - pub fn get_wrap_token_accounts_saber( - &self, - wallet_address: &Pubkey, - pool_name: &str, - token_to_wrap: TokenSelector, - ) -> Result, FarmClientError> { - // get pool info - let pool = self.get_pool(pool_name)?; - - // get underlying token info - let token = if token_to_wrap == TokenSelector::TokenA { - self.get_token_by_ref_from_cache(&pool.token_a_ref)? - } else { - self.get_token_by_ref_from_cache(&pool.token_b_ref)? - }; - - // get user accounts info - let user_underlying_token_account = self.get_token_account(wallet_address, &token); - - // fill in accounts data - let mut accounts = vec![]; - if let PoolRoute::Saber { - swap_account: _, - swap_authority: _, - fees_account_a: _, - fees_account_b: _, - decimal_wrapper_program, - wrapped_token_a_ref, - wrapped_token_a_vault, - decimal_wrapper_token_a, - wrapped_token_b_ref, - wrapped_token_b_vault, - decimal_wrapper_token_b, - } = pool.route - { - let (user_wrapped_token_account, wrapped_token, wrapped_token_vault, decimal_wrapper) = - if token_to_wrap == TokenSelector::TokenA { - let wrapped_token_a = self.get_token_by_ref_from_cache(&wrapped_token_a_ref)?; - ( - self.get_token_account(wallet_address, &wrapped_token_a), - wrapped_token_a, - wrapped_token_a_vault, - decimal_wrapper_token_a, - ) - } else { - let wrapped_token_b = self.get_token_by_ref_from_cache(&wrapped_token_b_ref)?; - ( - self.get_token_account(wallet_address, &wrapped_token_b), - wrapped_token_b, - wrapped_token_b_vault, - decimal_wrapper_token_b, - ) - }; - - accounts.push(AccountMeta::new_readonly(*wallet_address, true)); - accounts.push(AccountMeta::new( - user_underlying_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new_readonly( - token.ok_or(ProgramError::UninitializedAccount)?.mint, - false, - )); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new_readonly(decimal_wrapper_program, false)); - accounts.push(AccountMeta::new( - user_wrapped_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - wrapped_token - .ok_or(ProgramError::UninitializedAccount)? - .mint, - false, - )); - accounts.push(AccountMeta::new( - wrapped_token_vault.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new_readonly( - decimal_wrapper.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - } - - Ok(accounts) - } -} diff --git a/farms/farm-client/src/client/pool_instructions.rs b/farms/farm-client/src/client/pool_instructions.rs deleted file mode 100644 index d160986df8b..00000000000 --- a/farms/farm-client/src/client/pool_instructions.rs +++ /dev/null @@ -1,569 +0,0 @@ -//! Solana Farm Client Pool Instructions - -use { - crate::error::FarmClientError, - solana_farm_sdk::{ - instruction::amm::AmmInstruction, pool::PoolRoute, program::account, token::TokenSelector, - Protocol, - }, - solana_sdk::{instruction::Instruction, program_error::ProgramError, pubkey::Pubkey}, -}; - -use super::FarmClient; - -impl FarmClient { - /// Creates a new Instruction for adding liquidity to the Pool. - /// If one of the token amounts is 0 and pool requires both tokens, - /// amount will be autocalculated based on the current pool price. - pub fn new_instruction_add_liquidity_pool( - &self, - wallet_address: &Pubkey, - pool_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - ) -> Result { - // get pool info - let pool = self.get_pool(pool_name)?; - - // get tokens info - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - - // convert amounts if wrapped tokens are used - let mut max_token_a_amount = - self.to_token_amount_option(max_token_a_ui_amount, &token_a)?; - let mut max_token_b_amount = - self.to_token_amount_option(max_token_b_ui_amount, &token_b)?; - if let PoolRoute::Saber { - wrapped_token_a_ref, - wrapped_token_b_ref, - .. - } = pool.route - { - if let Some(token_ref) = wrapped_token_a_ref { - let underlying_decimals = - token_a.ok_or(ProgramError::UninitializedAccount)?.decimals; - let wrapped_decimals = self.get_token_by_ref(&token_ref)?.decimals; - max_token_a_amount = account::to_amount_with_new_decimals( - max_token_a_amount, - underlying_decimals, - wrapped_decimals, - )?; - } - if let Some(token_ref) = wrapped_token_b_ref { - let underlying_decimals = - token_b.ok_or(ProgramError::UninitializedAccount)?.decimals; - let wrapped_decimals = self.get_token_by_ref(&token_ref)?.decimals; - max_token_b_amount = account::to_amount_with_new_decimals( - max_token_b_amount, - underlying_decimals, - wrapped_decimals, - )?; - } - } - - // fill in instruction data - let data = AmmInstruction::AddLiquidity { - max_token_a_amount, - max_token_b_amount, - } - .to_vec()?; - - let accounts = match pool.route { - PoolRoute::Raydium { .. } => { - self.get_add_liquidity_accounts_raydium(wallet_address, pool_name)? - } - PoolRoute::Saber { .. } => { - self.get_add_liquidity_accounts_saber(wallet_address, pool_name)? - } - PoolRoute::Orca { .. } => { - self.get_add_liquidity_accounts_orca(wallet_address, pool_name)? - } - }; - - Ok(Instruction { - program_id: pool.router_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for removing liquidity from the Pool - pub fn new_instruction_remove_liquidity_pool( - &self, - wallet_address: &Pubkey, - pool_name: &str, - ui_amount: f64, - ) -> Result { - // get pool info - let pool = self.get_pool(pool_name)?; - - // get tokens info - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - - // fill in instruction data - let data = AmmInstruction::RemoveLiquidity { - amount: self.to_token_amount_option(ui_amount, &lp_token)?, - } - .to_vec()?; - - let accounts = match pool.route { - PoolRoute::Raydium { .. } => { - self.get_remove_liquidity_accounts_raydium(wallet_address, pool_name)? - } - PoolRoute::Saber { .. } => { - self.get_remove_liquidity_accounts_saber(wallet_address, pool_name)? - } - PoolRoute::Orca { .. } => { - self.get_remove_liquidity_accounts_orca(wallet_address, pool_name)? - } - }; - - Ok(Instruction { - program_id: pool.router_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for tokens swap - pub fn new_instruction_swap( - &self, - wallet_address: &Pubkey, - protocol: Protocol, - from_token: &str, - to_token: &str, - ui_amount_in: f64, - min_ui_amount_out: f64, - ) -> Result { - // get pool to swap in - let pool = self.find_pools(protocol, from_token, to_token)?[0]; - let reverse = FarmClient::pool_has_reverse_tokens(&pool.name, from_token)?; - - // get tokens info - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - - // convert amounts if wrapped tokens are used - let mut max_amount_in = if reverse { - self.to_token_amount_option(ui_amount_in, &token_b)? - } else { - self.to_token_amount_option(ui_amount_in, &token_a)? - }; - let mut min_amount_out = if reverse { - self.to_token_amount_option(min_ui_amount_out, &token_a)? - } else { - self.to_token_amount_option(min_ui_amount_out, &token_b)? - }; - if let PoolRoute::Saber { - wrapped_token_a_ref, - wrapped_token_b_ref, - .. - } = pool.route - { - if let Some(token_ref) = wrapped_token_a_ref { - let underlying_decimals = - token_a.ok_or(ProgramError::UninitializedAccount)?.decimals; - let wrapped_decimals = self.get_token_by_ref(&token_ref)?.decimals; - if reverse { - min_amount_out = account::to_amount_with_new_decimals( - min_amount_out, - underlying_decimals, - wrapped_decimals, - )?; - } else { - max_amount_in = account::to_amount_with_new_decimals( - max_amount_in, - underlying_decimals, - wrapped_decimals, - )?; - } - } - if let Some(token_ref) = wrapped_token_b_ref { - let underlying_decimals = - token_b.ok_or(ProgramError::UninitializedAccount)?.decimals; - let wrapped_decimals = self.get_token_by_ref(&token_ref)?.decimals; - if reverse { - max_amount_in = account::to_amount_with_new_decimals( - max_amount_in, - underlying_decimals, - wrapped_decimals, - )?; - } else { - min_amount_out = account::to_amount_with_new_decimals( - min_amount_out, - underlying_decimals, - wrapped_decimals, - )?; - } - } - } - - // fill in accounts and instruction data - let data = if reverse { - AmmInstruction::Swap { - token_a_amount_in: 0, - token_b_amount_in: max_amount_in, - min_token_amount_out: min_amount_out, - } - } else { - AmmInstruction::Swap { - token_a_amount_in: max_amount_in, - token_b_amount_in: 0, - min_token_amount_out: min_amount_out, - } - } - .to_vec()?; - - let accounts = match pool.route { - PoolRoute::Raydium { .. } => { - self.get_swap_accounts_raydium(wallet_address, &pool.name)? - } - PoolRoute::Saber { .. } => self.get_swap_accounts_saber(wallet_address, &pool.name)?, - PoolRoute::Orca { .. } => self.get_swap_accounts_orca(wallet_address, &pool.name)?, - }; - - Ok(Instruction { - program_id: pool.router_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for wrapping the token into protocol specific token - pub fn new_instruction_wrap_token( - &self, - wallet_address: &Pubkey, - pool_name: &str, - token_to_wrap: TokenSelector, - ui_amount: f64, - ) -> Result { - // get pool info - let pool = self.get_pool(pool_name)?; - - // get underlying token info - let token = if token_to_wrap == TokenSelector::TokenA { - self.get_token_by_ref_from_cache(&pool.token_a_ref)? - } else { - self.get_token_by_ref_from_cache(&pool.token_b_ref)? - }; - - // fill in instruction data - let data = AmmInstruction::WrapToken { - amount: self.to_token_amount_option(ui_amount, &token)?, - } - .to_vec()?; - - let accounts = match pool.route { - PoolRoute::Saber { .. } => { - self.get_wrap_token_accounts_saber(wallet_address, pool_name, token_to_wrap)? - } - _ => { - panic!("WrapToken instruction is not supported for this route type"); - } - }; - - Ok(Instruction { - program_id: pool.router_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for unwrapping original token from protocol specific token - pub fn new_instruction_unwrap_token( - &self, - wallet_address: &Pubkey, - pool_name: &str, - token_to_unwrap: TokenSelector, - ui_amount: f64, - ) -> Result { - // get pool info - let pool = self.get_pool(pool_name)?; - - let (accounts, decimals) = match pool.route { - PoolRoute::Saber { - wrapped_token_a_ref, - wrapped_token_b_ref, - .. - } => { - let token = if token_to_unwrap == TokenSelector::TokenA { - self.get_token_by_ref_from_cache(&wrapped_token_a_ref)? - } else { - self.get_token_by_ref_from_cache(&wrapped_token_b_ref)? - }; - ( - self.get_wrap_token_accounts_saber(wallet_address, pool_name, token_to_unwrap)?, - token.ok_or(ProgramError::UninitializedAccount)?.decimals, - ) - } - _ => { - panic!("UnwrapToken instruction is not supported for this route type"); - } - }; - - Ok(Instruction { - program_id: pool.router_program_id, - data: AmmInstruction::UnwrapToken { - amount: self.ui_amount_to_tokens_with_decimals(ui_amount, decimals)?, - } - .to_vec()?, - accounts, - }) - } - - /// Creates a new complete set of Instructions for adding liquidity to the Pool - pub fn all_instructions_add_liquidity_pool( - &self, - wallet_address: &Pubkey, - pool_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - ) -> Result, FarmClientError> { - if max_token_a_ui_amount < 0.0 - || max_token_b_ui_amount < 0.0 - || (max_token_a_ui_amount == 0.0 && max_token_b_ui_amount == 0.0) - { - return Err(FarmClientError::ValueError(format!( - "Invalid add liquidity amounts {} and {} specified for Pool {}: Must be greater or equal to zero and at least one non-zero.", - max_token_a_ui_amount, max_token_b_ui_amount, pool_name - ))); - } - // if one of the tokens is SOL and amount is zero, we need to estimate that - // amount to get it transfered to WSOL - let is_saber_pool = pool_name.starts_with("SBR."); - let (is_token_a_sol, is_token_b_sol) = self.pool_has_sol_tokens(pool_name)?; - let token_a_ui_amount = if max_token_a_ui_amount == 0.0 && is_token_a_sol && !is_saber_pool - { - let pool_price = self.get_pool_price(pool_name)?; - if pool_price > 0.0 { - max_token_b_ui_amount * 1.03 / pool_price - } else { - 0.0 - } - } else { - max_token_a_ui_amount - }; - let token_b_ui_amount = if max_token_b_ui_amount == 0.0 && is_token_b_sol && !is_saber_pool - { - max_token_a_ui_amount * self.get_pool_price(pool_name)? * 1.03 - } else { - max_token_b_ui_amount - }; - - let mut inst = Vec::::new(); - let _ = self.check_pool_accounts( - wallet_address, - pool_name, - token_a_ui_amount, - token_b_ui_amount, - 0.0, - true, - &mut inst, - )?; - - // check if tokens need to be wrapped to a Saber decimal token - if is_saber_pool { - let (is_token_a_wrapped, is_token_b_wrapped) = - self.pool_has_saber_wrapped_tokens(pool_name)?; - if is_token_a_wrapped && max_token_a_ui_amount > 0.0 { - inst.push(self.new_instruction_wrap_token( - wallet_address, - pool_name, - TokenSelector::TokenA, - max_token_a_ui_amount, - )?); - } - if is_token_b_wrapped && max_token_b_ui_amount > 0.0 { - inst.push(self.new_instruction_wrap_token( - wallet_address, - pool_name, - TokenSelector::TokenB, - max_token_b_ui_amount, - )?); - } - } - - // create and send instruction - inst.push(self.new_instruction_add_liquidity_pool( - wallet_address, - pool_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - )?); - if is_token_a_sol || is_token_b_sol { - inst.push(self.new_instruction_close_token_account(wallet_address, "SOL")?); - } - - Ok(inst) - } - - /// Creates a new complete set of Instructions for removing liquidity from the Pool - pub fn all_instructions_remove_liquidity_pool( - &self, - wallet_address: &Pubkey, - pool_name: &str, - ui_amount: f64, - ) -> Result, FarmClientError> { - let mut inst = Vec::::new(); - let _ = self.check_pool_accounts( - wallet_address, - pool_name, - 0.0, - 0.0, - ui_amount, - true, - &mut inst, - )?; - - inst.push(self.new_instruction_remove_liquidity_pool( - wallet_address, - pool_name, - ui_amount, - )?); - - // check if tokens need to be unwrapped - let (is_token_a_sol, is_token_b_sol) = self.pool_has_sol_tokens(pool_name)?; - let (is_token_a_wrapped, is_token_b_wrapped) = - self.pool_has_saber_wrapped_tokens(pool_name)?; - - if is_token_a_wrapped { - inst.push(self.new_instruction_unwrap_token( - wallet_address, - pool_name, - TokenSelector::TokenA, - 0.0, - )?); - } - if is_token_b_wrapped { - inst.push(self.new_instruction_unwrap_token( - wallet_address, - pool_name, - TokenSelector::TokenB, - 0.0, - )?); - } - if is_token_a_sol || is_token_b_sol { - inst.push(self.new_instruction_close_token_account(wallet_address, "SOL")?); - } - - Ok(inst) - } - - /// Creates a new complete set of Instructions for swapping tokens - pub fn all_instructions_swap( - &self, - wallet_address: &Pubkey, - protocol: Protocol, - from_token: &str, - to_token: &str, - ui_amount_in: f64, - min_ui_amount_out: f64, - ) -> Result, FarmClientError> { - // find pool to swap in - let pool = self.find_pools(protocol, from_token, to_token)?[0]; - - // check amount - if ui_amount_in < 0.0 { - return Err(FarmClientError::ValueError(format!( - "Invalid token amount {} specified for pool {}: Must be zero or greater.", - ui_amount_in, - pool.name.as_str() - ))); - } - - // if amount is zero use entire balance - let ui_amount_in = if ui_amount_in == 0.0 { - if from_token == "SOL" { - return Err(FarmClientError::ValueError(format!( - "Invalid SOL amount {} specified for pool {}: Must be greater than zero.", - ui_amount_in, - pool.name.as_str() - ))); - } - let balance = self.get_token_account_balance(wallet_address, from_token)?; - if balance == 0.0 { - return Err(FarmClientError::InsufficientBalance(from_token.to_string())); - } - balance - } else { - ui_amount_in - }; - - // check token accounts - let mut inst = Vec::::new(); - let reverse = FarmClient::pool_has_reverse_tokens(&pool.name, from_token)?; - if reverse { - let _ = self.check_pool_accounts( - wallet_address, - &pool.name, - 0.0, - ui_amount_in, - 0.0, - false, - &mut inst, - )?; - } else { - let _ = self.check_pool_accounts( - wallet_address, - &pool.name, - ui_amount_in, - 0.0, - 0.0, - false, - &mut inst, - )?; - } - - // check if tokens must be wrapped to Saber decimal token - let (is_token_a_wrapped, is_token_b_wrapped) = - self.pool_has_saber_wrapped_tokens(&pool.name)?; - if is_token_a_wrapped && !reverse { - inst.push(self.new_instruction_wrap_token( - wallet_address, - &pool.name, - TokenSelector::TokenA, - ui_amount_in, - )?); - } - if is_token_b_wrapped && reverse { - inst.push(self.new_instruction_wrap_token( - wallet_address, - &pool.name, - TokenSelector::TokenB, - ui_amount_in, - )?); - } - - // create and send instruction - inst.push(self.new_instruction_swap( - wallet_address, - protocol, - from_token, - to_token, - ui_amount_in, - min_ui_amount_out, - )?); - if is_token_b_wrapped && !reverse { - inst.push(self.new_instruction_unwrap_token( - wallet_address, - &pool.name, - TokenSelector::TokenB, - 0.0, - )?); - } - if is_token_a_wrapped && reverse { - inst.push(self.new_instruction_unwrap_token( - wallet_address, - &pool.name, - TokenSelector::TokenA, - 0.0, - )?); - } - if to_token == "SOL" { - inst.push(self.new_instruction_close_token_account(wallet_address, "SOL")?); - } - - Ok(inst) - } -} diff --git a/farms/farm-client/src/client/system_instructions.rs b/farms/farm-client/src/client/system_instructions.rs deleted file mode 100644 index 2c65dbe48cf..00000000000 --- a/farms/farm-client/src/client/system_instructions.rs +++ /dev/null @@ -1,265 +0,0 @@ -//! Solana Farm Client System Instructions - -use { - crate::error::FarmClientError, - solana_account_decoder::parse_token::{parse_token, TokenAccountType}, - solana_sdk::{instruction::Instruction, pubkey::Pubkey, system_instruction, system_program}, - spl_associated_token_account::create_associated_token_account, - spl_token::instruction as spl_token_instruction, -}; - -use super::FarmClient; - -impl FarmClient { - /// Returns a new Instruction for creating system account - pub fn new_instruction_create_system_account( - &self, - wallet_address: &Pubkey, - new_account_address: &Pubkey, - lamports: u64, - space: usize, - owner: &Pubkey, - ) -> Result { - let lamports = if lamports == 0 { - self.rpc_client - .get_minimum_balance_for_rent_exemption(space)? - } else { - lamports - }; - Ok(system_instruction::create_account( - wallet_address, - new_account_address, - lamports, - space as u64, - owner, - )) - } - - /// Returns a new Instruction for closing system account - pub fn new_instruction_close_system_account( - &self, - wallet_address: &Pubkey, - target_account_address: &Pubkey, - ) -> Result { - self.new_instruction_transfer( - target_account_address, - wallet_address, - self.get_account_balance(wallet_address)?, - ) - } - - /// Returns a new Instruction for creating system account with seed - pub fn new_instruction_create_system_account_with_seed( - &self, - wallet_address: &Pubkey, - base_address: &Pubkey, - seed: &str, - lamports: u64, - space: usize, - owner: &Pubkey, - ) -> Result { - let lamports = if lamports == 0 { - self.rpc_client - .get_minimum_balance_for_rent_exemption(space)? - } else { - lamports - }; - let to_pubkey = Pubkey::create_with_seed(base_address, seed, owner)?; - Ok(system_instruction::create_account_with_seed( - wallet_address, - &to_pubkey, - base_address, - seed, - lamports, - space as u64, - owner, - )) - } - - /// Returns a new Instruction for assigning system account to a program - pub fn new_instruction_assign_system_account( - &self, - wallet_address: &Pubkey, - program_address: &Pubkey, - ) -> Result { - Ok(system_instruction::assign(wallet_address, program_address)) - } - - /// Creates the native SOL transfer instruction - pub fn new_instruction_transfer( - &self, - wallet_address: &Pubkey, - destination_wallet: &Pubkey, - sol_ui_amount: f64, - ) -> Result { - if wallet_address == destination_wallet { - return Err(FarmClientError::ValueError( - "Source and destination addresses are the same".to_string(), - )); - } - if let Ok(account) = self.rpc_client.get_account(destination_wallet) { - if destination_wallet != &self.get_associated_token_address(wallet_address, "SOL")? - && (account.owner != system_program::id() || !account.data.is_empty()) - { - return Err(FarmClientError::ValueError( - "Destination account is not a SOL wallet".to_string(), - )); - } - } - Ok(system_instruction::transfer( - wallet_address, - destination_wallet, - self.ui_amount_to_tokens_with_decimals( - sol_ui_amount, - spl_token::native_mint::DECIMALS, - )?, - )) - } - - /// Creates a tokens transfer instruction - pub fn new_instruction_token_transfer( - &self, - wallet_address: &Pubkey, - token_name: &str, - destination_wallet: &Pubkey, - ui_amount: f64, - ) -> Result { - if let Ok(account) = self.rpc_client.get_account(destination_wallet) { - if account.owner != system_program::id() || !account.data.is_empty() { - return Err(FarmClientError::ValueError( - "Destination account is not a SOL wallet".to_string(), - )); - } - } - let token_addr = self.get_associated_token_address(wallet_address, token_name)?; - let destination_address = - self.get_associated_token_address(destination_wallet, token_name)?; - Ok(spl_token_instruction::transfer( - &spl_token::id(), - &token_addr, - &destination_address, - wallet_address, - &[], - self.ui_amount_to_tokens(ui_amount, token_name)?, - )?) - } - - /// Creates a new Instruction for syncing token balance for the specified account - pub fn new_instruction_sync_token_balance( - &self, - wallet_address: &Pubkey, - token_name: &str, - ) -> Result { - let token_addr = self.get_associated_token_address(wallet_address, token_name)?; - Ok(spl_token_instruction::sync_native( - &spl_token::id(), - &token_addr, - )?) - } - - /// Returns a new Instruction for creating associated token account - pub fn new_instruction_create_token_account( - &self, - wallet_address: &Pubkey, - token_name: &str, - ) -> Result { - let token = self.get_token(token_name)?; - Ok(create_associated_token_account( - wallet_address, - wallet_address, - &token.mint, - )) - } - - /// Returns a new Instruction for closing associated token account - pub fn new_instruction_close_token_account( - &self, - wallet_address: &Pubkey, - token_name: &str, - ) -> Result { - let token_addr = self.get_associated_token_address(wallet_address, token_name)?; - Ok(spl_token_instruction::close_account( - &spl_token::id(), - &token_addr, - wallet_address, - wallet_address, - &[], - )?) - } - - /// Creates a new complete set of instructions for SOL wrapping - pub fn all_instructions_wrap_sol( - &self, - wallet_address: &Pubkey, - ui_amount: f64, - ) -> Result, FarmClientError> { - let target_account = self.get_associated_token_address(wallet_address, "SOL")?; - let mut inst = vec![]; - if !self.has_active_token_account(wallet_address, "SOL") { - inst.push(self.new_instruction_create_token_account(wallet_address, "SOL")?); - } else { - self.check_ata_owner(wallet_address, "SOL")?; - } - inst.push(self.new_instruction_transfer(wallet_address, &target_account, ui_amount)?); - Ok(inst) - } - - /// Creates a new complete set of instructions for SOL unwrapping - pub fn all_instructions_unwrap_sol( - &self, - wallet_address: &Pubkey, - ) -> Result, FarmClientError> { - let inst = vec![self.new_instruction_close_token_account(wallet_address, "SOL")?]; - Ok(inst) - } - - /// Creates a new complete set of instructions for tokens transfer - pub fn all_instructions_token_transfer( - &self, - wallet_address: &Pubkey, - token_name: &str, - destination_wallet: &Pubkey, - ui_amount: f64, - ) -> Result, FarmClientError> { - if wallet_address == destination_wallet { - return Err(FarmClientError::ValueError( - "Source and destination addresses are the same".to_string(), - )); - } - let mut inst = vec![]; - if !self.has_active_token_account(wallet_address, token_name) { - return Err(FarmClientError::RecordNotFound(format!( - "Source account with token {}", - token_name - ))); - } - let data = self.rpc_client.get_account_data(destination_wallet)?; - let res = parse_token(data.as_slice(), Some(0)); - if let Ok(TokenAccountType::Account(_)) = res { - return Err(FarmClientError::ValueError( - "Destination must be a base wallet address, token address will be derived" - .to_string(), - )); - } - - if !self.has_active_token_account(destination_wallet, token_name) { - let token = self.get_token(token_name)?; - inst.push(create_associated_token_account( - wallet_address, - destination_wallet, - &token.mint, - )); - } else { - self.check_ata_owner(destination_wallet, token_name)?; - } - - inst.push(self.new_instruction_token_transfer( - wallet_address, - token_name, - destination_wallet, - ui_amount, - )?); - - Ok(inst) - } -} diff --git a/farms/farm-client/src/client/vault_instructions.rs b/farms/farm-client/src/client/vault_instructions.rs deleted file mode 100644 index 8134dd8c23e..00000000000 --- a/farms/farm-client/src/client/vault_instructions.rs +++ /dev/null @@ -1,964 +0,0 @@ -//! Solana Farm Client Vault Instructions - -use { - crate::error::FarmClientError, - solana_farm_sdk::{ - instruction::vault::VaultInstruction, pool::PoolRoute, program::multisig::Multisig, - token::TokenSelector, vault::VaultStrategy, - }, - solana_sdk::{ - instruction::{AccountMeta, Instruction}, - program_error::ProgramError, - pubkey::Pubkey, - system_program, - }, -}; - -use super::FarmClient; - -impl FarmClient { - /// Creates a new Instruction for initializing a new User for the Vault - pub fn new_instruction_user_init_vault( - &self, - wallet_address: &Pubkey, - vault_name: &str, - ) -> Result { - // get vault info - let vault = self.get_vault(vault_name)?; - - // fill in accounts and instruction data - let (accounts, data) = match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { pool_ref, .. } => { - let pool = self.get_pool_by_ref(&pool_ref)?; - match pool.route { - PoolRoute::Raydium { .. } => { - self.get_stc_user_init_accounts_raydium(wallet_address, vault_name) - } - PoolRoute::Saber { .. } => { - self.get_stc_user_init_accounts_saber(wallet_address, vault_name) - } - PoolRoute::Orca { .. } => { - self.get_stc_user_init_accounts_orca(wallet_address, vault_name) - } - } - } - _ => { - unreachable!() - } - }?; - - Ok(Instruction { - program_id: vault.vault_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for adding liquidity to the Vault - pub fn new_instruction_add_liquidity_vault( - &self, - wallet_address: &Pubkey, - vault_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - ) -> Result { - // get vault info - let vault = self.get_vault(vault_name)?; - - // fill in accounts and instruction data - let (accounts, data) = match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { pool_ref, .. } => { - let pool = self.get_pool_by_ref(&pool_ref)?; - match pool.route { - PoolRoute::Raydium { .. } => self.get_stc_add_liquidity_accounts_raydium( - wallet_address, - vault_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - ), - PoolRoute::Saber { .. } => self.get_stc_add_liquidity_accounts_saber( - wallet_address, - vault_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - ), - PoolRoute::Orca { .. } => self.get_stc_add_liquidity_accounts_orca( - wallet_address, - vault_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - ), - } - } - _ => { - unreachable!() - } - }?; - - Ok(Instruction { - program_id: vault.vault_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for locking liquidity in the Vault - pub fn new_instruction_lock_liquidity_vault( - &self, - wallet_address: &Pubkey, - vault_name: &str, - ui_amount: f64, - ) -> Result { - // get vault info - let vault = self.get_vault(vault_name)?; - - // fill in accounts and instruction data - let (accounts, data) = match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { pool_ref, .. } => { - let pool = self.get_pool_by_ref(&pool_ref)?; - match pool.route { - PoolRoute::Raydium { .. } => self.get_stc_lock_liquidity_accounts_raydium( - wallet_address, - vault_name, - ui_amount, - ), - PoolRoute::Saber { .. } => self.get_stc_lock_liquidity_accounts_saber( - wallet_address, - vault_name, - ui_amount, - ), - PoolRoute::Orca { .. } => self.get_stc_lock_liquidity_accounts_orca( - wallet_address, - vault_name, - ui_amount, - ), - } - } - _ => { - unreachable!() - } - }?; - - Ok(Instruction { - program_id: vault.vault_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for unlocking liquidity in the Vault - pub fn new_instruction_unlock_liquidity_vault( - &self, - wallet_address: &Pubkey, - vault_name: &str, - ui_amount: f64, - ) -> Result { - // get vault info - let vault = self.get_vault(vault_name)?; - - // fill in accounts and instruction data - let (accounts, data) = match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { pool_ref, .. } => { - let pool = self.get_pool_by_ref(&pool_ref)?; - match pool.route { - PoolRoute::Raydium { .. } => self.get_stc_unlock_liquidity_accounts_raydium( - wallet_address, - vault_name, - ui_amount, - ), - PoolRoute::Saber { .. } => Err(FarmClientError::ValueError(format!( - "LockLiquidity is not supported by Vault {}", - vault_name - ))), - PoolRoute::Orca { .. } => self.get_stc_unlock_liquidity_accounts_orca( - wallet_address, - vault_name, - ui_amount, - ), - } - } - _ => { - unreachable!() - } - }?; - - Ok(Instruction { - program_id: vault.vault_program_id, - data, - accounts, - }) - } - - /// Creates a new Instruction for removing liquidity from the Vault - pub fn new_instruction_remove_liquidity_vault( - &self, - wallet_address: &Pubkey, - vault_name: &str, - ui_amount: f64, - ) -> Result { - // get vault info - let vault = self.get_vault(vault_name)?; - - // fill in accounts and instruction data - let (accounts, data) = match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { pool_ref, .. } => { - let pool = self.get_pool_by_ref(&pool_ref)?; - match pool.route { - PoolRoute::Raydium { .. } => self.get_stc_remove_liquidity_accounts_raydium( - wallet_address, - vault_name, - ui_amount, - ), - PoolRoute::Saber { .. } => self.get_stc_remove_liquidity_accounts_saber( - wallet_address, - vault_name, - ui_amount, - ), - PoolRoute::Orca { .. } => self.get_stc_remove_liquidity_accounts_orca( - wallet_address, - vault_name, - ui_amount, - ), - } - } - _ => { - unreachable!() - } - }?; - - Ok(Instruction { - program_id: vault.vault_program_id, - data, - accounts, - }) - } - - /// Creates a new Vault Init Instruction - pub fn new_instruction_init_vault( - &self, - admin_address: &Pubkey, - vault_name: &str, - step: u64, - ) -> Result { - // get vault info - let vault = self.get_vault(vault_name)?; - - // fill in accounts and instruction data - let (accounts, data) = match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { pool_ref, .. } => { - let pool = self.get_pool_by_ref(&pool_ref)?; - match pool.route { - PoolRoute::Raydium { .. } => { - self.get_stc_init_accounts_raydium(admin_address, vault_name, step) - } - PoolRoute::Saber { .. } => { - self.get_stc_init_accounts_saber(admin_address, vault_name, step) - } - PoolRoute::Orca { .. } => { - self.get_stc_init_accounts_orca(admin_address, vault_name, step) - } - } - } - _ => { - unreachable!() - } - }?; - - Ok(Instruction { - program_id: vault.vault_program_id, - data, - accounts, - }) - } - - /// Creates a new Vault Shutdown Instruction - pub fn new_instruction_shutdown_vault( - &self, - admin_address: &Pubkey, - vault_name: &str, - ) -> Result { - // get vault info - let vault = self.get_vault(vault_name)?; - - // fill in accounts and instruction data - let (accounts, data) = match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { pool_ref, .. } => { - let pool = self.get_pool_by_ref(&pool_ref)?; - match pool.route { - PoolRoute::Raydium { .. } => { - self.get_stc_shutdown_accounts_raydium(admin_address, vault_name) - } - PoolRoute::Saber { .. } => { - self.get_stc_shutdown_accounts_saber(admin_address, vault_name) - } - PoolRoute::Orca { .. } => { - self.get_stc_shutdown_accounts_orca(admin_address, vault_name) - } - } - } - _ => { - unreachable!() - } - }?; - - Ok(Instruction { - program_id: vault.vault_program_id, - data, - accounts, - }) - } - - /// Creates a new instruction for withdrawal collected fees from the Vault - pub fn new_instruction_withdraw_fees_vault( - &self, - admin_address: &Pubkey, - vault_name: &str, - fee_token: TokenSelector, - ui_amount: f64, - receiver: &Pubkey, - ) -> Result { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - - // fill in accounts and instruction data - let mut inst = Instruction { - program_id: vault.vault_program_id, - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(vault_ref, false), - AccountMeta::new(vault.info_account, false), - AccountMeta::new(self.get_vault_active_multisig_account(vault_name)?, false), - AccountMeta::new(vault.vault_authority, false), - AccountMeta::new_readonly(spl_token::id(), false), - if fee_token == TokenSelector::TokenA { - AccountMeta::new( - vault - .fees_account_a - .ok_or(ProgramError::UninitializedAccount)?, - false, - ) - } else { - AccountMeta::new( - vault - .fees_account_b - .ok_or(ProgramError::UninitializedAccount)?, - false, - ) - }, - AccountMeta::new(*receiver, false), - ], - }; - - let fee_decimals = - if let VaultStrategy::StakeLpCompoundRewards { farm_ref, .. } = vault.strategy { - let farm = self.get_farm_by_ref(&farm_ref)?; - if fee_token == TokenSelector::TokenA { - let token_a_reward = self - .get_token_by_ref_from_cache(&farm.first_reward_token_ref)? - .unwrap(); - token_a_reward.decimals - } else { - let token_b_reward = self - .get_token_by_ref_from_cache(&farm.second_reward_token_ref)? - .unwrap(); - token_b_reward.decimals - } - } else { - unreachable!(); - }; - - inst.data = VaultInstruction::WithdrawFees { - amount: self.ui_amount_to_tokens_with_decimals(ui_amount, fee_decimals)?, - } - .to_vec()?; - - Ok(inst) - } - - /// Creates a new Vault Crank Instruction - pub fn new_instruction_crank_vault( - &self, - wallet_address: &Pubkey, - vault_name: &str, - step: u64, - ) -> Result { - // get vault info - let vault = self.get_vault(vault_name)?; - - // fill in accounts and instruction data - let (accounts, data) = match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { pool_ref, .. } => { - let pool = self.get_pool_by_ref(&pool_ref)?; - match pool.route { - PoolRoute::Raydium { .. } => { - self.get_stc_crank_accounts_raydium(wallet_address, vault_name, step) - } - PoolRoute::Saber { .. } => { - self.get_stc_crank_accounts_saber(wallet_address, vault_name, step) - } - PoolRoute::Orca { .. } => { - self.get_stc_crank_accounts_orca(wallet_address, vault_name, step) - } - } - } - _ => { - unreachable!() - } - }?; - - Ok(Instruction { - program_id: vault.vault_program_id, - data, - accounts, - }) - } - - /// Creates a new instruction for initializing Vault's multisig with a new set of signers - pub fn new_instruction_set_vault_admins( - &self, - admin_address: &Pubkey, - vault_name: &str, - admin_signers: &[Pubkey], - min_signatures: u8, - ) -> Result { - if admin_signers.is_empty() || min_signatures == 0 { - return Err(FarmClientError::ValueError( - "At least one signer is required".to_string(), - )); - } else if min_signatures as usize > admin_signers.len() - || admin_signers.len() > Multisig::MAX_SIGNERS - { - return Err(FarmClientError::ValueError( - "Invalid number of signatures".to_string(), - )); - } - - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - - // fill in accounts and instruction data - let mut inst = Instruction { - program_id: vault.vault_program_id, - data: VaultInstruction::SetAdminSigners { min_signatures }.to_vec()?, - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(vault_ref, false), - AccountMeta::new(vault.info_account, false), - AccountMeta::new(self.get_vault_active_multisig_account(vault_name)?, false), - AccountMeta::new(self.get_vault_multisig_account(vault_name)?, false), - AccountMeta::new_readonly(system_program::id(), false), - ], - }; - - for key in admin_signers { - inst.accounts.push(AccountMeta::new_readonly(*key, false)); - } - - Ok(inst) - } - - /// Creates a new instruction for removing Vault's multisig - pub fn new_instruction_remove_vault_multisig( - &self, - admin_address: &Pubkey, - vault_name: &str, - ) -> Result { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - - // fill in accounts and instruction data - let inst = Instruction { - program_id: vault.vault_program_id, - data: VaultInstruction::RemoveMultisig.to_vec()?, - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(vault_ref, false), - AccountMeta::new(vault.info_account, false), - AccountMeta::new(self.get_vault_active_multisig_account(vault_name)?, false), - AccountMeta::new(self.get_vault_multisig_account(vault_name)?, false), - ], - }; - - Ok(inst) - } - - /// Creates a new Instruction for updating the Vault's min crank interval - pub fn new_instruction_set_min_crank_interval_vault( - &self, - admin_address: &Pubkey, - vault_name: &str, - min_crank_interval: u32, - ) -> Result { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - - // fill in accounts and instruction data - let mut inst = Instruction { - program_id: vault.vault_program_id, - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(vault_ref, false), - AccountMeta::new(vault.info_account, false), - AccountMeta::new(self.get_vault_active_multisig_account(vault_name)?, false), - ], - }; - - inst.data = VaultInstruction::SetMinCrankInterval { min_crank_interval }.to_vec()?; - - Ok(inst) - } - - /// Creates a new Instruction for updating the Vault's fee - pub fn new_instruction_set_fee_vault( - &self, - admin_address: &Pubkey, - vault_name: &str, - fee_percent: f32, - ) -> Result { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - - // fill in accounts and instruction data - let mut inst = Instruction { - program_id: vault.vault_program_id, - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(vault_ref, false), - AccountMeta::new(vault.info_account, false), - AccountMeta::new(self.get_vault_active_multisig_account(vault_name)?, false), - ], - }; - - inst.data = VaultInstruction::SetFee { - fee: fee_percent * 0.01, - } - .to_vec()?; - - Ok(inst) - } - - /// Creates a new Instruction for updating the Vault's external fee - pub fn new_instruction_set_external_fee_vault( - &self, - admin_address: &Pubkey, - vault_name: &str, - external_fee_percent: f32, - ) -> Result { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - - // fill in accounts and instruction data - let mut inst = Instruction { - program_id: vault.vault_program_id, - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(vault_ref, false), - AccountMeta::new(vault.info_account, false), - AccountMeta::new(self.get_vault_active_multisig_account(vault_name)?, false), - ], - }; - - inst.data = VaultInstruction::SetExternalFee { - external_fee: external_fee_percent * 0.01, - } - .to_vec()?; - - Ok(inst) - } - - /// Creates a new Instruction for disabling deposits to the Vault - pub fn new_instruction_disable_deposits_vault( - &self, - admin_address: &Pubkey, - vault_name: &str, - ) -> Result { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - - // fill in accounts and instruction data - let mut inst = Instruction { - program_id: vault.vault_program_id, - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(vault_ref, false), - AccountMeta::new(vault.info_account, false), - AccountMeta::new(self.get_vault_active_multisig_account(vault_name)?, false), - ], - }; - - inst.data = VaultInstruction::DisableDeposits.to_vec()?; - - Ok(inst) - } - - /// Creates a new Instruction for enabling deposits to the Vault - pub fn new_instruction_enable_deposits_vault( - &self, - admin_address: &Pubkey, - vault_name: &str, - ) -> Result { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - - // fill in accounts and instruction data - let mut inst = Instruction { - program_id: vault.vault_program_id, - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(vault_ref, false), - AccountMeta::new(vault.info_account, false), - AccountMeta::new(self.get_vault_active_multisig_account(vault_name)?, false), - ], - }; - - inst.data = VaultInstruction::EnableDeposits.to_vec()?; - - Ok(inst) - } - - /// Creates a new Instruction for disabling withdrawals from the Vault - pub fn new_instruction_disable_withdrawals_vault( - &self, - admin_address: &Pubkey, - vault_name: &str, - ) -> Result { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - - // fill in accounts and instruction data - let mut inst = Instruction { - program_id: vault.vault_program_id, - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(vault_ref, false), - AccountMeta::new(vault.info_account, false), - AccountMeta::new(self.get_vault_active_multisig_account(vault_name)?, false), - ], - }; - - inst.data = VaultInstruction::DisableWithdrawals.to_vec()?; - - Ok(inst) - } - - /// Creates a new Instruction for enabling withdrawals from the Vault - pub fn new_instruction_enable_withdrawals_vault( - &self, - admin_address: &Pubkey, - vault_name: &str, - ) -> Result { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - - // fill in accounts and instruction data - let mut inst = Instruction { - program_id: vault.vault_program_id, - data: Vec::::new(), - accounts: vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(vault_ref, false), - AccountMeta::new(vault.info_account, false), - AccountMeta::new(self.get_vault_active_multisig_account(vault_name)?, false), - ], - }; - - inst.data = VaultInstruction::EnableWithdrawals.to_vec()?; - - Ok(inst) - } - - /// Creates a new complete set of Instructions for adding liquidity to the Vault - pub fn all_instructions_add_liquidity_vault( - &self, - wallet_address: &Pubkey, - vault_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - ) -> Result, FarmClientError> { - if max_token_a_ui_amount < 0.0 - || max_token_b_ui_amount < 0.0 - || (max_token_a_ui_amount == 0.0 && max_token_b_ui_amount == 0.0) - { - return Err(FarmClientError::ValueError(format!( - "Invalid add liquidity amounts {} and {} specified for Vault {}: Must be greater or equal to zero and at least one non-zero.", - max_token_a_ui_amount, max_token_b_ui_amount, vault_name - ))); - } - // if one of the tokens is SOL and amount is zero, we need to estimate that - // amount to get it transfered to WSOL - let is_saber_vault = vault_name.starts_with("SBR."); - let (is_token_a_sol, is_token_b_sol) = self.vault_has_sol_tokens(vault_name)?; - let token_a_ui_amount = if max_token_a_ui_amount == 0.0 && is_token_a_sol && !is_saber_vault - { - let pool_price = self.get_vault_price(vault_name)?; - if pool_price > 0.0 { - max_token_b_ui_amount * 1.03 / pool_price - } else { - 0.0 - } - } else { - max_token_a_ui_amount - }; - let token_b_ui_amount = if max_token_b_ui_amount == 0.0 && is_token_b_sol && !is_saber_vault - { - max_token_a_ui_amount * self.get_vault_price(vault_name)? * 1.03 - } else { - max_token_b_ui_amount - }; - - // check user accounts - let mut inst = Vec::::new(); - self.check_vault_accounts( - wallet_address, - vault_name, - token_a_ui_amount, - token_b_ui_amount, - 0.0, - true, - true, - &mut inst, - )?; - - // check if tokens must be wrapped to Saber decimal token - if is_saber_vault { - let pool_name = self.get_underlying_pool(vault_name)?.name.to_string(); - let (is_token_a_wrapped, is_token_b_wrapped) = - self.pool_has_saber_wrapped_tokens(&pool_name)?; - if is_token_a_wrapped && max_token_a_ui_amount > 0.0 { - inst.push(self.new_instruction_wrap_token( - wallet_address, - &pool_name, - TokenSelector::TokenA, - max_token_a_ui_amount, - )?); - } - if is_token_b_wrapped && max_token_b_ui_amount > 0.0 { - inst.push(self.new_instruction_wrap_token( - wallet_address, - &pool_name, - TokenSelector::TokenB, - max_token_b_ui_amount, - )?); - } - } - - // insert add liquidity instruction - inst.push(self.new_instruction_add_liquidity_vault( - wallet_address, - vault_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - )?); - if is_token_a_sol || is_token_b_sol { - inst.push(self.new_instruction_close_token_account(wallet_address, "SOL")?); - } - - // lock liquidity if required by the vault - let vault = self.get_vault(vault_name)?; - if vault.lock_required { - let lock_inst = - self.new_instruction_lock_liquidity_vault(wallet_address, vault_name, 0.0)?; - inst.push(lock_inst); - } - - Ok(inst) - } - - /// Creates a new complete set of Instructions for adding locked liquidity to the Vault - pub fn all_instructions_add_locked_liquidity_vault( - &self, - wallet_address: &Pubkey, - vault_name: &str, - ui_amount: f64, - ) -> Result, FarmClientError> { - // check user accounts - let mut inst = Vec::::new(); - self.check_vault_accounts( - wallet_address, - vault_name, - 0.0, - 0.0, - 0.0, - true, - false, - &mut inst, - )?; - - // check if the user has locked balance - if ui_amount > 0.0 { - let lp_debt = self - .get_vault_user_info(wallet_address, vault_name)? - .lp_tokens_debt; - let pool_token_decimals = self.get_vault_lp_token_decimals(vault_name)?; - if self.tokens_to_ui_amount_with_decimals(lp_debt, pool_token_decimals) < ui_amount { - return Err(FarmClientError::InsufficientBalance( - "Not enough locked tokens to deposit".to_string(), - )); - } - } - - inst.push(self.new_instruction_lock_liquidity_vault( - wallet_address, - vault_name, - ui_amount, - )?); - - Ok(inst) - } - - /// Create a new complete set of Instructions for removing unlocked liquidity from the Vault - pub fn all_instructions_remove_unlocked_liquidity_vault( - &self, - wallet_address: &Pubkey, - vault_name: &str, - ui_amount: f64, - ) -> Result, FarmClientError> { - // check user accounts - let mut inst = Vec::::new(); - self.check_vault_accounts( - wallet_address, - vault_name, - 0.0, - 0.0, - 0.0, - false, - false, - &mut inst, - )?; - - // check if the user has unlocked balance - if ui_amount > 0.0 { - let lp_debt = self - .get_vault_user_info(wallet_address, vault_name)? - .lp_tokens_debt; - let pool_token_decimals = self.get_vault_lp_token_decimals(vault_name)?; - if self.tokens_to_ui_amount_with_decimals(lp_debt, pool_token_decimals) < ui_amount { - return Err(FarmClientError::InsufficientBalance( - "Not enough unlocked tokens to remove".to_string(), - )); - } - } - - inst.push(self.new_instruction_remove_liquidity_vault( - wallet_address, - vault_name, - ui_amount, - )?); - - // check if tokens need to be unwrapped - let (is_token_a_sol, is_token_b_sol) = self.vault_has_sol_tokens(vault_name)?; - let pool_name = self.get_underlying_pool(vault_name)?.name.to_string(); - let (is_token_a_wrapped, is_token_b_wrapped) = - self.pool_has_saber_wrapped_tokens(&pool_name)?; - - if is_token_a_wrapped { - inst.push(self.new_instruction_unwrap_token( - wallet_address, - &pool_name, - TokenSelector::TokenA, - 0.0, - )?); - } - if is_token_b_wrapped { - inst.push(self.new_instruction_unwrap_token( - wallet_address, - &pool_name, - TokenSelector::TokenB, - 0.0, - )?); - } - if is_token_a_sol || is_token_b_sol { - inst.push(self.new_instruction_close_token_account(wallet_address, "SOL")?); - } - - Ok(inst) - } - - /// Creates a new complete set of Instructions for removing liquidity from the Vault - pub fn all_instructions_remove_liquidity_vault( - &self, - wallet_address: &Pubkey, - vault_name: &str, - ui_amount: f64, - ) -> Result, FarmClientError> { - // check user accounts - let vault = self.get_vault(vault_name)?; - let mut inst = Vec::::new(); - self.check_vault_accounts( - wallet_address, - vault_name, - 0.0, - 0.0, - ui_amount, - true, - false, - &mut inst, - )?; - - // unlock liquidity first if required by the vault - if vault.unlock_required { - inst.push(self.new_instruction_unlock_liquidity_vault( - wallet_address, - vault_name, - ui_amount, - )?); - inst.push(self.new_instruction_remove_liquidity_vault( - wallet_address, - vault_name, - 0.0, - )?); - } else { - // remove liquidity - inst.push(self.new_instruction_remove_liquidity_vault( - wallet_address, - vault_name, - ui_amount, - )?); - } - - // check if tokens need to be unwrapped - let (is_token_a_sol, is_token_b_sol) = self.vault_has_sol_tokens(vault_name)?; - let pool_name = self.get_underlying_pool(vault_name)?.name.to_string(); - let (is_token_a_wrapped, is_token_b_wrapped) = - self.pool_has_saber_wrapped_tokens(&pool_name)?; - - if is_token_a_wrapped { - inst.push(self.new_instruction_unwrap_token( - wallet_address, - &pool_name, - TokenSelector::TokenA, - 0.0, - )?); - } - if is_token_b_wrapped { - inst.push(self.new_instruction_unwrap_token( - wallet_address, - &pool_name, - TokenSelector::TokenB, - 0.0, - )?); - } - if is_token_a_sol || is_token_b_sol { - inst.push(self.new_instruction_close_token_account(wallet_address, "SOL")?); - } - - Ok(inst) - } -} diff --git a/farms/farm-client/src/client/vault_stc_accounts_orca.rs b/farms/farm-client/src/client/vault_stc_accounts_orca.rs deleted file mode 100644 index 620192af3b9..00000000000 --- a/farms/farm-client/src/client/vault_stc_accounts_orca.rs +++ /dev/null @@ -1,766 +0,0 @@ -//! Solana Farm Client Vault Instructions - -use { - crate::error::FarmClientError, - solana_farm_sdk::{ - farm::FarmRoute, id::zero, instruction::vault::VaultInstruction, pool::PoolRoute, - vault::VaultStrategy, - }, - solana_sdk::{ - instruction::AccountMeta, program_error::ProgramError, pubkey::Pubkey, system_program, - sysvar, - }, - std::vec::Vec, -}; - -use super::FarmClient; - -impl FarmClient { - /// Returns accounts and data for initializing a new User for the Vault - pub fn get_stc_user_init_accounts_orca( - &self, - wallet_address: &Pubkey, - vault_name: &str, - ) -> Result<(Vec, Vec), FarmClientError> { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - // fill in accounts and instruction data - let data = VaultInstruction::UserInit.to_vec()?; - let accounts = vec![ - AccountMeta::new(*wallet_address, true), - AccountMeta::new_readonly(vault_ref, false), - AccountMeta::new(vault.info_account, false), - AccountMeta::new_readonly(*wallet_address, false), - AccountMeta::new( - self.get_vault_user_info_account(wallet_address, vault_name)?, - false, - ), - AccountMeta::new_readonly(system_program::id(), false), - ]; - Ok((accounts, data)) - } - - /// Returns accounts and data for adding liquidity to the Vault - pub fn get_stc_add_liquidity_accounts_orca( - &self, - wallet_address: &Pubkey, - vault_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - ) -> Result<(Vec, Vec), FarmClientError> { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - - // fill in accounts and instruction data - let mut accounts = vec![AccountMeta::new_readonly(*wallet_address, true)]; - - // general accounts - accounts.push(AccountMeta::new_readonly(vault_ref, false)); - accounts.push(AccountMeta::new(vault.info_account, false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new( - self.get_vault_user_info_account(wallet_address, vault_name)?, - false, - )); - - // strategy related accounts - let data = match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { - pool_ref, - farm_ref, - lp_token_custody, - .. - } => { - let pool = self.get_pool_by_ref(&pool_ref)?; - let farm = self.get_farm_by_ref(&farm_ref)?; - - // get tokens info - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - let farm_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - assert_eq!(farm_token, lp_token); - - // get user accounts info - let user_token_a_account = self.get_token_account(wallet_address, &token_a); - let user_token_b_account = self.get_token_account(wallet_address, &token_b); - let user_lp_token_account = self.get_token_account(wallet_address, &lp_token); - - // fill in pool related accounts - match pool.route { - PoolRoute::Orca { - amm_id, - amm_authority, - .. - } => { - accounts.push(AccountMeta::new( - user_token_a_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_token_b_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_lp_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new(lp_token_custody, false)); - accounts.push(AccountMeta::new_readonly(pool.pool_program_id, false)); - accounts.push(AccountMeta::new( - pool.token_a_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - pool.token_b_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - lp_token.ok_or(ProgramError::UninitializedAccount)?.mint, - false, - )); - accounts.push(AccountMeta::new(amm_id, false)); - accounts.push(AccountMeta::new_readonly(amm_authority, false)); - } - _ => { - unreachable!(); - } - } - - VaultInstruction::AddLiquidity { - max_token_a_amount: self - .to_token_amount_option(max_token_a_ui_amount, &token_a)?, - max_token_b_amount: self - .to_token_amount_option(max_token_b_ui_amount, &token_b)?, - } - .to_vec()? - } - VaultStrategy::DynamicHedge { .. } => { - unreachable!(); - } - }; - Ok((accounts, data)) - } - - /// Returns accounts and data for locking liquidity in the Vault - pub fn get_stc_lock_liquidity_accounts_orca( - &self, - wallet_address: &Pubkey, - vault_name: &str, - ui_amount: f64, - ) -> Result<(Vec, Vec), FarmClientError> { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - let vault_token = self.get_token_by_ref_from_cache(&Some(vault.vault_token_ref))?; - - // fill in accounts and instruction data - let mut accounts = vec![AccountMeta::new_readonly(*wallet_address, true)]; - - // general accounts - accounts.push(AccountMeta::new_readonly(vault_ref, false)); - accounts.push(AccountMeta::new(vault.info_account, false)); - accounts.push(AccountMeta::new_readonly(vault.vault_authority, false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new(vault_token.unwrap().mint, false)); - accounts.push(AccountMeta::new( - self.get_vault_user_info_account(wallet_address, vault_name)?, - false, - )); - - // strategy related accounts - let data = match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { - pool_ref, - farm_ref, - lp_token_custody, - token_a_reward_custody, - vault_stake_info, - vault_stake_custody, - .. - } => { - let pool = self.get_pool_by_ref(&pool_ref)?; - let farm = self.get_farm_by_ref(&farm_ref)?; - - // get tokens info - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - let farm_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - assert_eq!(farm_token, lp_token); - - // get user accounts info - let user_vt_token_account = self.get_token_account(wallet_address, &vault_token); - - accounts.push(AccountMeta::new( - user_vt_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new(token_a_reward_custody, false)); - accounts.push(AccountMeta::new(lp_token_custody, false)); - - // fill in farm related accounts - match farm.route { - FarmRoute::Orca { - farm_id, - farm_authority, - farm_token_ref, - base_token_vault, - reward_token_vault, - } => { - let farm_lp_token = - self.get_token_by_ref_from_cache(&Some(farm_token_ref))?; - - accounts.push(AccountMeta::new_readonly(farm.farm_program_id, false)); - accounts.push(AccountMeta::new(vault_stake_info, false)); - accounts.push(AccountMeta::new( - vault_stake_custody.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new(farm_id, false)); - accounts.push(AccountMeta::new_readonly(farm_authority, false)); - accounts.push(AccountMeta::new( - farm_lp_token - .ok_or(ProgramError::UninitializedAccount)? - .mint, - false, - )); - accounts.push(AccountMeta::new(base_token_vault, false)); - accounts.push(AccountMeta::new(reward_token_vault, false)); - } - _ => { - unreachable!(); - } - } - - VaultInstruction::LockLiquidity { - amount: self.to_token_amount_option(ui_amount, &lp_token)?, - } - .to_vec()? - } - VaultStrategy::DynamicHedge { .. } => { - unreachable!(); - } - }; - Ok((accounts, data)) - } - - /// Returns accounts and data for unlocking liquidity in the Vault - pub fn get_stc_unlock_liquidity_accounts_orca( - &self, - wallet_address: &Pubkey, - vault_name: &str, - ui_amount: f64, - ) -> Result<(Vec, Vec), FarmClientError> { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - let vault_token = self.get_token_by_ref_from_cache(&Some(vault.vault_token_ref))?; - - // fill in accounts and instruction data - let data = VaultInstruction::UnlockLiquidity { - amount: self.to_token_amount_option(ui_amount, &vault_token)?, - } - .to_vec()?; - let mut accounts = vec![AccountMeta::new_readonly(*wallet_address, true)]; - - // general accounts - accounts.push(AccountMeta::new_readonly(vault_ref, false)); - accounts.push(AccountMeta::new(vault.info_account, false)); - accounts.push(AccountMeta::new_readonly(vault.vault_authority, false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new(vault_token.unwrap().mint, false)); - accounts.push(AccountMeta::new( - self.get_vault_user_info_account(wallet_address, vault_name)?, - false, - )); - - // strategy related accounts - match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { - pool_ref, - farm_ref, - lp_token_custody, - token_a_reward_custody, - vault_stake_info, - vault_stake_custody, - .. - } => { - let pool = self.get_pool_by_ref(&pool_ref)?; - let farm = self.get_farm_by_ref(&farm_ref)?; - - // get tokens info - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - let farm_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - assert_eq!(farm_token, lp_token); - - // get user accounts info - let user_vt_token_account = self.get_token_account(wallet_address, &vault_token); - - accounts.push(AccountMeta::new( - user_vt_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new(token_a_reward_custody, false)); - accounts.push(AccountMeta::new(lp_token_custody, false)); - - // fill in farm related accounts - match farm.route { - FarmRoute::Orca { - farm_id, - farm_authority, - farm_token_ref, - base_token_vault, - reward_token_vault, - } => { - let farm_lp_token = - self.get_token_by_ref_from_cache(&Some(farm_token_ref))?; - - accounts.push(AccountMeta::new_readonly(farm.farm_program_id, false)); - accounts.push(AccountMeta::new(vault_stake_info, false)); - accounts.push(AccountMeta::new( - vault_stake_custody.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new(farm_id, false)); - accounts.push(AccountMeta::new_readonly(farm_authority, false)); - accounts.push(AccountMeta::new( - farm_lp_token - .ok_or(ProgramError::UninitializedAccount)? - .mint, - false, - )); - accounts.push(AccountMeta::new(base_token_vault, false)); - accounts.push(AccountMeta::new(reward_token_vault, false)); - } - _ => { - unreachable!(); - } - } - } - VaultStrategy::DynamicHedge { .. } => { - unreachable!(); - } - } - Ok((accounts, data)) - } - - /// Returns accounts and data for removing liquidity from the Vault - pub fn get_stc_remove_liquidity_accounts_orca( - &self, - wallet_address: &Pubkey, - vault_name: &str, - ui_amount: f64, - ) -> Result<(Vec, Vec), FarmClientError> { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - // fill in accounts and instruction data - let mut accounts = vec![AccountMeta::new_readonly(*wallet_address, true)]; - - // general accounts - accounts.push(AccountMeta::new_readonly(vault_ref, false)); - accounts.push(AccountMeta::new(vault.info_account, false)); - accounts.push(AccountMeta::new_readonly(vault.vault_authority, false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new( - self.get_vault_user_info_account(wallet_address, vault_name)?, - false, - )); - - // strategy related accounts - let data = match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { - pool_ref, - farm_ref, - lp_token_custody, - .. - } => { - let pool = self.get_pool_by_ref(&pool_ref)?; - let farm = self.get_farm_by_ref(&farm_ref)?; - - // get tokens info - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - let farm_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - assert_eq!(farm_token, lp_token); - - // get user accounts info - let user_token_a_account = self.get_token_account(wallet_address, &token_a); - let user_token_b_account = self.get_token_account(wallet_address, &token_b); - - // fill in pool related accounts - match pool.route { - PoolRoute::Orca { - amm_id, - amm_authority, - fees_account, - } => { - accounts.push(AccountMeta::new( - user_token_a_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_token_b_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new(lp_token_custody, false)); - accounts.push(AccountMeta::new_readonly(pool.pool_program_id, false)); - accounts.push(AccountMeta::new( - pool.token_a_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - pool.token_b_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - lp_token.ok_or(ProgramError::UninitializedAccount)?.mint, - false, - )); - accounts.push(AccountMeta::new(amm_id, false)); - accounts.push(AccountMeta::new_readonly(amm_authority, false)); - accounts.push(AccountMeta::new(fees_account, false)); - } - _ => { - unreachable!(); - } - } - - VaultInstruction::RemoveLiquidity { - amount: self.to_token_amount_option(ui_amount, &lp_token)?, - } - .to_vec()? - } - VaultStrategy::DynamicHedge { .. } => { - unreachable!(); - } - }; - Ok((accounts, data)) - } - - /// Returns accounts and data for a Vault Init Instruction - pub fn get_stc_init_accounts_orca( - &self, - admin_address: &Pubkey, - vault_name: &str, - step: u64, - ) -> Result<(Vec, Vec), FarmClientError> { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - let vault_token = self - .get_token_by_ref_from_cache(&Some(vault.vault_token_ref))? - .unwrap(); - - // fill in accounts and instruction data - let data = VaultInstruction::Init { step }.to_vec()?; - let mut accounts = vec![AccountMeta::new_readonly(*admin_address, true)]; - - // general accounts - accounts.push(AccountMeta::new_readonly(vault_ref, false)); - accounts.push(AccountMeta::new(vault.info_account, false)); - accounts.push(AccountMeta::new( - self.get_vault_active_multisig_account(vault_name)?, - false, - )); - accounts.push(AccountMeta::new(vault.vault_authority, false)); - accounts.push(AccountMeta::new_readonly(vault.vault_program_id, false)); - accounts.push(AccountMeta::new_readonly(system_program::id(), false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new_readonly(sysvar::rent::id(), false)); - - match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { - pool_ref, - farm_id, - farm_ref, - lp_token_custody, - token_a_custody, - token_b_custody, - token_a_reward_custody, - vault_stake_info, - vault_stake_custody, - .. - } => { - // get pools - let pool = self.get_pool_by_ref(&pool_ref)?; - let farm = self.get_farm_by_ref(&farm_ref)?; - // get tokens info - let token_a = self - .get_token_by_ref_from_cache(&pool.token_a_ref)? - .unwrap(); - let token_b = self - .get_token_by_ref_from_cache(&pool.token_b_ref)? - .unwrap(); - let lp_token = self - .get_token_by_ref_from_cache(&pool.lp_token_ref)? - .unwrap(); - let farm_token_ref = match farm.route { - FarmRoute::Orca { farm_token_ref, .. } => farm_token_ref, - _ => unreachable!(), - }; - let farm_lp_token = self.get_token_by_ref_from_cache(&Some(farm_token_ref))?; - let token_a_reward = self - .get_token_by_ref_from_cache(&farm.first_reward_token_ref)? - .unwrap(); - - accounts.push(AccountMeta::new_readonly(farm.farm_program_id, false)); - accounts.push(AccountMeta::new(vault_token.mint, false)); - accounts.push(AccountMeta::new_readonly(vault.vault_token_ref, false)); - accounts.push(AccountMeta::new(vault_stake_info, false)); - accounts.push(AccountMeta::new( - vault_stake_custody.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - vault.fees_account_a.or_else(|| Some(zero::id())).unwrap(), - false, - )); - accounts.push(AccountMeta::new(token_a_custody, false)); - accounts.push(AccountMeta::new( - token_b_custody.or_else(|| Some(zero::id())).unwrap(), - false, - )); - accounts.push(AccountMeta::new(lp_token_custody, false)); - accounts.push(AccountMeta::new(token_a.mint, false)); - accounts.push(AccountMeta::new(token_b.mint, false)); - accounts.push(AccountMeta::new(lp_token.mint, false)); - accounts.push(AccountMeta::new( - farm_lp_token - .ok_or(ProgramError::UninitializedAccount)? - .mint, - false, - )); - accounts.push(AccountMeta::new(token_a_reward_custody, false)); - accounts.push(AccountMeta::new(token_a_reward.mint, false)); - accounts.push(AccountMeta::new_readonly(farm_id, false)); - } - VaultStrategy::DynamicHedge { .. } => { - unreachable!(); - } - } - - Ok((accounts, data)) - } - - /// Returns accounts and data for a Vault Shutdown Instruction - pub fn get_stc_shutdown_accounts_orca( - &self, - admin_address: &Pubkey, - vault_name: &str, - ) -> Result<(Vec, Vec), FarmClientError> { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - - // fill in accounts and instruction data - let data = VaultInstruction::Shutdown.to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(vault_ref, false), - AccountMeta::new(vault.info_account, false), - AccountMeta::new(self.get_vault_active_multisig_account(vault_name)?, false), - ]; - - Ok((accounts, data)) - } - - /// Returns accounts and data for a Vault Crank Instruction - pub fn get_stc_crank_accounts_orca( - &self, - wallet_address: &Pubkey, - vault_name: &str, - step: u64, - ) -> Result<(Vec, Vec), FarmClientError> { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - - // fill in accounts and instruction data - let data = VaultInstruction::Crank { step }.to_vec()?; - let mut accounts = vec![AccountMeta::new_readonly(*wallet_address, true)]; - - // general accounts - accounts.push(AccountMeta::new_readonly(vault_ref, false)); - accounts.push(AccountMeta::new(vault.info_account, false)); - accounts.push(AccountMeta::new_readonly(vault.vault_authority, false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - - // strategy related accounts - match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { - pool_ref, - farm_ref, - lp_token_custody, - token_a_custody, - token_b_custody, - token_a_reward_custody, - vault_stake_info, - vault_stake_custody, - reward_exchange_pool_ref, - .. - } => { - let pool = self.get_pool_by_ref(&pool_ref)?; - let farm = self.get_farm_by_ref(&farm_ref)?; - - // get tokens info - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - let farm_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - assert_eq!(farm_token, lp_token); - - accounts.push(AccountMeta::new(token_a_reward_custody, false)); - if step == 3 { - accounts.push(AccountMeta::new(lp_token_custody, false)); - } - if step == 1 { - accounts.push(AccountMeta::new( - vault - .fees_account_a - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - } - - if step == 2 || step == 3 { - match pool.route { - PoolRoute::Orca { - amm_id, - amm_authority, - fees_account, - } => { - accounts.push(AccountMeta::new(token_a_custody, false)); - accounts.push(AccountMeta::new( - token_b_custody.or_else(|| Some(zero::id())).unwrap(), - false, - )); - accounts.push(AccountMeta::new_readonly(pool.pool_program_id, false)); - accounts.push(AccountMeta::new( - pool.token_a_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - pool.token_b_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - lp_token.ok_or(ProgramError::UninitializedAccount)?.mint, - false, - )); - accounts.push(AccountMeta::new(amm_id, false)); - accounts.push(AccountMeta::new_readonly(amm_authority, false)); - if step == 2 { - accounts.push(AccountMeta::new(fees_account, false)); - if let Some(rdex_pool_ref) = reward_exchange_pool_ref { - let rdex_pool = self.get_pool_by_ref(&rdex_pool_ref)?; - let rdex_lp_token = - self.get_token_by_ref_from_cache(&rdex_pool.lp_token_ref)?; - match rdex_pool.route { - PoolRoute::Orca { - amm_id: rdex_amm_id, - amm_authority: rdex_amm_authority, - fees_account: rdex_fees_account, - } => { - accounts.push(AccountMeta::new( - rdex_pool - .token_a_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - rdex_pool - .token_b_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - rdex_lp_token - .ok_or(ProgramError::UninitializedAccount)? - .mint, - false, - )); - accounts.push(AccountMeta::new(rdex_amm_id, false)); - accounts.push(AccountMeta::new_readonly( - rdex_amm_authority, - false, - )); - accounts - .push(AccountMeta::new(rdex_fees_account, false)); - } - _ => { - unreachable!(); - } - } - } else { - for _ in 0..6 { - accounts.push(AccountMeta::new_readonly(zero::id(), false)); - } - } - accounts.push(AccountMeta::new_readonly( - sysvar::instructions::id(), - false, - )); - } - } - _ => { - unreachable!(); - } - } - } - - // fill in farm related accounts - if step == 1 || step == 3 { - match farm.route { - FarmRoute::Orca { - farm_id, - farm_authority, - farm_token_ref, - base_token_vault, - reward_token_vault, - } => { - let farm_lp_token = - self.get_token_by_ref_from_cache(&Some(farm_token_ref))?; - - accounts.push(AccountMeta::new_readonly(farm.farm_program_id, false)); - accounts.push(AccountMeta::new(vault_stake_info, false)); - if step == 3 { - accounts.push(AccountMeta::new( - vault_stake_custody - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - } - accounts.push(AccountMeta::new(farm_id, false)); - accounts.push(AccountMeta::new_readonly(farm_authority, false)); - if step == 3 { - accounts.push(AccountMeta::new( - farm_lp_token - .ok_or(ProgramError::UninitializedAccount)? - .mint, - false, - )); - } - accounts.push(AccountMeta::new(base_token_vault, false)); - accounts.push(AccountMeta::new(reward_token_vault, false)); - } - _ => { - unreachable!(); - } - } - } - } - VaultStrategy::DynamicHedge { .. } => { - unreachable!(); - } - } - - Ok((accounts, data)) - } -} diff --git a/farms/farm-client/src/client/vault_stc_accounts_raydium.rs b/farms/farm-client/src/client/vault_stc_accounts_raydium.rs deleted file mode 100644 index e0a5f9159cd..00000000000 --- a/farms/farm-client/src/client/vault_stc_accounts_raydium.rs +++ /dev/null @@ -1,789 +0,0 @@ -//! Solana Farm Client Vault Instructions - -use { - crate::error::FarmClientError, - solana_farm_sdk::{ - farm::FarmRoute, id::zero, instruction::vault::VaultInstruction, pool::PoolRoute, - vault::VaultStrategy, - }, - solana_sdk::{ - instruction::AccountMeta, program_error::ProgramError, pubkey::Pubkey, system_program, - sysvar, - }, - std::vec::Vec, -}; - -use super::FarmClient; - -impl FarmClient { - /// Returns accounts and data for initializing a new User for the Vault - pub fn get_stc_user_init_accounts_raydium( - &self, - wallet_address: &Pubkey, - vault_name: &str, - ) -> Result<(Vec, Vec), FarmClientError> { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - // fill in accounts and instruction data - let data = VaultInstruction::UserInit.to_vec()?; - let accounts = vec![ - AccountMeta::new(*wallet_address, true), - AccountMeta::new_readonly(vault_ref, false), - AccountMeta::new(vault.info_account, false), - AccountMeta::new_readonly(*wallet_address, false), - AccountMeta::new( - self.get_vault_user_info_account(wallet_address, vault_name)?, - false, - ), - AccountMeta::new_readonly(system_program::id(), false), - ]; - Ok((accounts, data)) - } - - /// Returns accounts and data for adding liquidity to the Vault - pub fn get_stc_add_liquidity_accounts_raydium( - &self, - wallet_address: &Pubkey, - vault_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - ) -> Result<(Vec, Vec), FarmClientError> { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - - // fill in accounts and instruction data - let mut accounts = vec![AccountMeta::new_readonly(*wallet_address, true)]; - - // general accounts - accounts.push(AccountMeta::new_readonly(vault_ref, false)); - accounts.push(AccountMeta::new(vault.info_account, false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new( - self.get_vault_user_info_account(wallet_address, vault_name)?, - false, - )); - - // strategy related accounts - let data = match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { - pool_ref, - farm_ref, - lp_token_custody, - .. - } => { - let pool = self.get_pool_by_ref(&pool_ref)?; - let farm = self.get_farm_by_ref(&farm_ref)?; - - // get tokens info - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - let farm_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - assert_eq!(farm_token, lp_token); - - // get user accounts info - let user_token_a_account = self.get_token_account(wallet_address, &token_a); - let user_token_b_account = self.get_token_account(wallet_address, &token_b); - let user_lp_token_account = self.get_token_account(wallet_address, &lp_token); - - // fill in pool related accounts - match pool.route { - PoolRoute::Raydium { - amm_id, - amm_authority, - amm_open_orders, - amm_target, - serum_market, - .. - } => { - accounts.push(AccountMeta::new( - user_token_a_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_token_b_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_lp_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new(lp_token_custody, false)); - accounts.push(AccountMeta::new_readonly(pool.pool_program_id, false)); - accounts.push(AccountMeta::new( - pool.token_a_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - pool.token_b_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - lp_token.ok_or(ProgramError::UninitializedAccount)?.mint, - false, - )); - accounts.push(AccountMeta::new(amm_id, false)); - accounts.push(AccountMeta::new_readonly(amm_authority, false)); - accounts.push(AccountMeta::new_readonly(amm_open_orders, false)); - accounts.push(AccountMeta::new(amm_target, false)); - accounts.push(AccountMeta::new_readonly(serum_market, false)); - } - _ => { - unreachable!(); - } - } - - VaultInstruction::AddLiquidity { - max_token_a_amount: self - .to_token_amount_option(max_token_a_ui_amount, &token_a)?, - max_token_b_amount: self - .to_token_amount_option(max_token_b_ui_amount, &token_b)?, - } - .to_vec()? - } - VaultStrategy::DynamicHedge { .. } => { - unreachable!(); - } - }; - Ok((accounts, data)) - } - - /// Returns accounts and data for locking liquidity in the Vault - pub fn get_stc_lock_liquidity_accounts_raydium( - &self, - wallet_address: &Pubkey, - vault_name: &str, - ui_amount: f64, - ) -> Result<(Vec, Vec), FarmClientError> { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - let vault_token = self.get_token_by_ref_from_cache(&Some(vault.vault_token_ref))?; - - // fill in accounts and instruction data - let mut accounts = vec![AccountMeta::new_readonly(*wallet_address, true)]; - - // general accounts - accounts.push(AccountMeta::new_readonly(vault_ref, false)); - accounts.push(AccountMeta::new(vault.info_account, false)); - accounts.push(AccountMeta::new_readonly(vault.vault_authority, false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new(vault_token.unwrap().mint, false)); - accounts.push(AccountMeta::new( - self.get_vault_user_info_account(wallet_address, vault_name)?, - false, - )); - - // strategy related accounts - let data = match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { - pool_ref, - farm_ref, - lp_token_custody, - token_a_reward_custody, - token_b_reward_custody, - vault_stake_info, - .. - } => { - let pool = self.get_pool_by_ref(&pool_ref)?; - let farm = self.get_farm_by_ref(&farm_ref)?; - - // get tokens info - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - let farm_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - assert_eq!(farm_token, lp_token); - - // get user accounts info - let user_vt_token_account = self.get_token_account(wallet_address, &vault_token); - - accounts.push(AccountMeta::new( - user_vt_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new(token_a_reward_custody, false)); - accounts.push(AccountMeta::new( - token_b_reward_custody.or_else(|| Some(zero::id())).unwrap(), - false, - )); - accounts.push(AccountMeta::new(lp_token_custody, false)); - - // fill in farm related accounts - match farm.route { - FarmRoute::Raydium { - farm_id, - farm_authority, - farm_lp_token_account, - farm_first_reward_token_account, - farm_second_reward_token_account, - } => { - accounts.push(AccountMeta::new_readonly(farm.farm_program_id, false)); - accounts.push(AccountMeta::new(vault_stake_info, false)); - accounts.push(AccountMeta::new(farm_id, false)); - accounts.push(AccountMeta::new_readonly(farm_authority, false)); - - accounts.push(AccountMeta::new(farm_lp_token_account, false)); - accounts.push(AccountMeta::new(farm_first_reward_token_account, false)); - accounts.push(AccountMeta::new( - farm_second_reward_token_account - .or_else(|| Some(zero::id())) - .unwrap(), - false, - )); - accounts.push(AccountMeta::new_readonly(sysvar::clock::id(), false)); - } - _ => { - unreachable!(); - } - } - - VaultInstruction::LockLiquidity { - amount: self.to_token_amount_option(ui_amount, &lp_token)?, - } - .to_vec()? - } - VaultStrategy::DynamicHedge { .. } => { - unreachable!(); - } - }; - Ok((accounts, data)) - } - - /// Returns accounts and data for unlocking liquidity in the Vault - pub fn get_stc_unlock_liquidity_accounts_raydium( - &self, - wallet_address: &Pubkey, - vault_name: &str, - ui_amount: f64, - ) -> Result<(Vec, Vec), FarmClientError> { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - let vault_token = self.get_token_by_ref_from_cache(&Some(vault.vault_token_ref))?; - - // fill in accounts and instruction data - let data = VaultInstruction::UnlockLiquidity { - amount: self.to_token_amount_option(ui_amount, &vault_token)?, - } - .to_vec()?; - let mut accounts = vec![AccountMeta::new_readonly(*wallet_address, true)]; - - // general accounts - accounts.push(AccountMeta::new_readonly(vault_ref, false)); - accounts.push(AccountMeta::new(vault.info_account, false)); - accounts.push(AccountMeta::new_readonly(vault.vault_authority, false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new(vault_token.unwrap().mint, false)); - accounts.push(AccountMeta::new( - self.get_vault_user_info_account(wallet_address, vault_name)?, - false, - )); - - // strategy related accounts - match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { - pool_ref, - farm_ref, - lp_token_custody, - token_a_reward_custody, - token_b_reward_custody, - vault_stake_info, - .. - } => { - let pool = self.get_pool_by_ref(&pool_ref)?; - let farm = self.get_farm_by_ref(&farm_ref)?; - - // get tokens info - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - let farm_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - assert_eq!(farm_token, lp_token); - - // get user accounts info - let user_vt_token_account = self.get_token_account(wallet_address, &vault_token); - - accounts.push(AccountMeta::new( - user_vt_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new(token_a_reward_custody, false)); - accounts.push(AccountMeta::new( - token_b_reward_custody.or_else(|| Some(zero::id())).unwrap(), - false, - )); - accounts.push(AccountMeta::new(lp_token_custody, false)); - - // fill in farm related accounts - match farm.route { - FarmRoute::Raydium { - farm_id, - farm_authority, - farm_lp_token_account, - farm_first_reward_token_account, - farm_second_reward_token_account, - } => { - accounts.push(AccountMeta::new_readonly(farm.farm_program_id, false)); - accounts.push(AccountMeta::new(vault_stake_info, false)); - accounts.push(AccountMeta::new(farm_id, false)); - accounts.push(AccountMeta::new_readonly(farm_authority, false)); - accounts.push(AccountMeta::new(farm_lp_token_account, false)); - accounts.push(AccountMeta::new(farm_first_reward_token_account, false)); - accounts.push(AccountMeta::new( - farm_second_reward_token_account - .or_else(|| Some(zero::id())) - .unwrap(), - false, - )); - accounts.push(AccountMeta::new_readonly(sysvar::clock::id(), false)); - } - _ => { - unreachable!(); - } - } - } - VaultStrategy::DynamicHedge { .. } => { - unreachable!(); - } - } - Ok((accounts, data)) - } - - /// Returns accounts and data for removing liquidity from the Vault - pub fn get_stc_remove_liquidity_accounts_raydium( - &self, - wallet_address: &Pubkey, - vault_name: &str, - ui_amount: f64, - ) -> Result<(Vec, Vec), FarmClientError> { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - // fill in accounts and instruction data - let mut accounts = vec![AccountMeta::new_readonly(*wallet_address, true)]; - - // general accounts - accounts.push(AccountMeta::new_readonly(vault_ref, false)); - accounts.push(AccountMeta::new(vault.info_account, false)); - accounts.push(AccountMeta::new_readonly(vault.vault_authority, false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new( - self.get_vault_user_info_account(wallet_address, vault_name)?, - false, - )); - - // strategy related accounts - let data = match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { - pool_ref, - farm_ref, - lp_token_custody, - .. - } => { - let pool = self.get_pool_by_ref(&pool_ref)?; - let farm = self.get_farm_by_ref(&farm_ref)?; - - // get tokens info - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - let farm_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - assert_eq!(farm_token, lp_token); - - // get user accounts info - let user_token_a_account = self.get_token_account(wallet_address, &token_a); - let user_token_b_account = self.get_token_account(wallet_address, &token_b); - - // fill in pool related accounts - match pool.route { - PoolRoute::Raydium { - amm_id, - amm_authority, - amm_open_orders, - amm_target, - pool_withdraw_queue, - pool_temp_lp_token_account, - serum_program_id, - serum_market, - serum_coin_vault_account, - serum_pc_vault_account, - serum_vault_signer, - serum_event_queue, - serum_bids, - serum_asks, - } => { - accounts.push(AccountMeta::new( - user_token_a_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_token_b_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new(lp_token_custody, false)); - accounts.push(AccountMeta::new_readonly(pool.pool_program_id, false)); - accounts.push(AccountMeta::new(pool_withdraw_queue, false)); - accounts.push(AccountMeta::new(pool_temp_lp_token_account, false)); - accounts.push(AccountMeta::new( - pool.token_a_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - pool.token_b_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - lp_token.ok_or(ProgramError::UninitializedAccount)?.mint, - false, - )); - accounts.push(AccountMeta::new(amm_id, false)); - accounts.push(AccountMeta::new_readonly(amm_authority, false)); - accounts.push(AccountMeta::new(amm_open_orders, false)); - accounts.push(AccountMeta::new(amm_target, false)); - accounts.push(AccountMeta::new(serum_market, false)); - accounts.push(AccountMeta::new_readonly(serum_program_id, false)); - accounts.push(AccountMeta::new( - serum_bids.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - serum_asks.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - serum_event_queue.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new(serum_coin_vault_account, false)); - accounts.push(AccountMeta::new(serum_pc_vault_account, false)); - accounts.push(AccountMeta::new_readonly(serum_vault_signer, false)); - } - _ => { - unreachable!(); - } - } - - VaultInstruction::RemoveLiquidity { - amount: self.to_token_amount_option(ui_amount, &lp_token)?, - } - .to_vec()? - } - VaultStrategy::DynamicHedge { .. } => { - unreachable!(); - } - }; - Ok((accounts, data)) - } - - /// Returns accounts and data for a Vault Init Instruction - pub fn get_stc_init_accounts_raydium( - &self, - admin_address: &Pubkey, - vault_name: &str, - step: u64, - ) -> Result<(Vec, Vec), FarmClientError> { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - let vault_token = self - .get_token_by_ref_from_cache(&Some(vault.vault_token_ref))? - .unwrap(); - - // fill in accounts and instruction data - let data = VaultInstruction::Init { step }.to_vec()?; - let mut accounts = vec![AccountMeta::new_readonly(*admin_address, true)]; - - // general accounts - accounts.push(AccountMeta::new_readonly(vault_ref, false)); - accounts.push(AccountMeta::new(vault.info_account, false)); - accounts.push(AccountMeta::new( - self.get_vault_active_multisig_account(vault_name)?, - false, - )); - accounts.push(AccountMeta::new(vault.vault_authority, false)); - accounts.push(AccountMeta::new_readonly(vault.vault_program_id, false)); - accounts.push(AccountMeta::new_readonly(system_program::id(), false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new_readonly(sysvar::rent::id(), false)); - - match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { - pool_ref, - farm_ref, - lp_token_custody, - token_a_custody, - token_b_custody, - token_a_reward_custody, - token_b_reward_custody, - vault_stake_info, - .. - } => { - // get pools - let pool = self.get_pool_by_ref(&pool_ref)?; - let farm = self.get_farm_by_ref(&farm_ref)?; - // get tokens info - let token_a = self - .get_token_by_ref_from_cache(&pool.token_a_ref)? - .unwrap(); - let token_b = self - .get_token_by_ref_from_cache(&pool.token_b_ref)? - .unwrap(); - let lp_token = self - .get_token_by_ref_from_cache(&pool.lp_token_ref)? - .unwrap(); - let token_a_reward = self - .get_token_by_ref_from_cache(&farm.first_reward_token_ref)? - .unwrap(); - let token_b_reward = - self.get_token_by_ref_from_cache(&farm.second_reward_token_ref)?; - - accounts.push(AccountMeta::new_readonly(farm.farm_program_id, false)); - accounts.push(AccountMeta::new(vault_token.mint, false)); - accounts.push(AccountMeta::new_readonly(vault.vault_token_ref, false)); - if farm.version >= 4 { - accounts.push(AccountMeta::new(zero::id(), false)); - accounts.push(AccountMeta::new(vault_stake_info, false)); - } else { - accounts.push(AccountMeta::new(vault_stake_info, false)); - accounts.push(AccountMeta::new(zero::id(), false)); - } - accounts.push(AccountMeta::new( - vault.fees_account_a.or_else(|| Some(zero::id())).unwrap(), - false, - )); - accounts.push(AccountMeta::new( - vault.fees_account_b.or_else(|| Some(zero::id())).unwrap(), - false, - )); - accounts.push(AccountMeta::new(token_a_custody, false)); - accounts.push(AccountMeta::new( - token_b_custody.or_else(|| Some(zero::id())).unwrap(), - false, - )); - accounts.push(AccountMeta::new(lp_token_custody, false)); - accounts.push(AccountMeta::new(token_a.mint, false)); - accounts.push(AccountMeta::new(token_b.mint, false)); - accounts.push(AccountMeta::new(lp_token.mint, false)); - - accounts.push(AccountMeta::new(token_a_reward_custody, false)); - accounts.push(AccountMeta::new( - token_b_reward_custody.or_else(|| Some(zero::id())).unwrap(), - false, - )); - accounts.push(AccountMeta::new(token_a_reward.mint, false)); - if let Some(token) = token_b_reward { - accounts.push(AccountMeta::new(token.mint, false)); - } else { - accounts.push(AccountMeta::new(zero::id(), false)); - } - } - VaultStrategy::DynamicHedge { .. } => { - unreachable!(); - } - } - - Ok((accounts, data)) - } - - /// Returns accounts and data for a Vault Shutdown Instruction - pub fn get_stc_shutdown_accounts_raydium( - &self, - admin_address: &Pubkey, - vault_name: &str, - ) -> Result<(Vec, Vec), FarmClientError> { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - - // fill in accounts and instruction data - let data = VaultInstruction::Shutdown.to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(vault_ref, false), - AccountMeta::new(vault.info_account, false), - AccountMeta::new(self.get_vault_active_multisig_account(vault_name)?, false), - ]; - - Ok((accounts, data)) - } - - /// Returns accounts and data for a Vault Crank Instruction - pub fn get_stc_crank_accounts_raydium( - &self, - wallet_address: &Pubkey, - vault_name: &str, - step: u64, - ) -> Result<(Vec, Vec), FarmClientError> { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - - // fill in accounts and instruction data - let data = VaultInstruction::Crank { step }.to_vec()?; - let mut accounts = vec![AccountMeta::new_readonly(*wallet_address, true)]; - - // general accounts - accounts.push(AccountMeta::new_readonly(vault_ref, false)); - accounts.push(AccountMeta::new(vault.info_account, false)); - accounts.push(AccountMeta::new_readonly(vault.vault_authority, false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - - // strategy related accounts - match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { - pool_ref, - farm_ref, - lp_token_custody, - token_a_custody, - token_b_custody, - token_a_reward_custody, - token_b_reward_custody, - vault_stake_info, - .. - } => { - let pool = self.get_pool_by_ref(&pool_ref)?; - let farm = self.get_farm_by_ref(&farm_ref)?; - - // get tokens info - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - let farm_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - assert_eq!(farm_token, lp_token); - - accounts.push(AccountMeta::new(token_a_reward_custody, false)); - accounts.push(AccountMeta::new( - token_b_reward_custody.or_else(|| Some(zero::id())).unwrap(), - false, - )); - if step != 2 { - accounts.push(AccountMeta::new(lp_token_custody, false)); - } - if step == 1 { - accounts.push(AccountMeta::new( - vault - .fees_account_a - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - vault.fees_account_b.or_else(|| Some(zero::id())).unwrap(), - false, - )); - } - - if step == 2 || step == 3 { - match pool.route { - PoolRoute::Raydium { - amm_id, - amm_authority, - amm_open_orders, - amm_target, - pool_withdraw_queue: _, - pool_temp_lp_token_account: _, - serum_program_id, - serum_market, - serum_coin_vault_account, - serum_pc_vault_account, - serum_vault_signer, - serum_bids, - serum_asks, - serum_event_queue, - } => { - accounts.push(AccountMeta::new(token_a_custody, false)); - accounts.push(AccountMeta::new( - token_b_custody.or_else(|| Some(zero::id())).unwrap(), - false, - )); - accounts.push(AccountMeta::new_readonly(pool.pool_program_id, false)); - accounts.push(AccountMeta::new( - pool.token_a_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - pool.token_b_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - if step == 3 { - accounts.push(AccountMeta::new( - lp_token.ok_or(ProgramError::UninitializedAccount)?.mint, - false, - )); - } - accounts.push(AccountMeta::new(amm_id, false)); - accounts.push(AccountMeta::new_readonly(amm_authority, false)); - accounts.push(AccountMeta::new(amm_open_orders, false)); - accounts.push(AccountMeta::new(amm_target, false)); - accounts.push(AccountMeta::new(serum_market, false)); - - if step == 2 { - accounts.push(AccountMeta::new_readonly(serum_program_id, false)); - accounts.push(AccountMeta::new(serum_coin_vault_account, false)); - accounts.push(AccountMeta::new(serum_pc_vault_account, false)); - accounts.push(AccountMeta::new(serum_vault_signer, false)); - accounts.push(AccountMeta::new( - serum_bids.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - serum_asks.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - serum_event_queue.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new_readonly( - sysvar::instructions::id(), - false, - )); - } - } - _ => { - unreachable!(); - } - } - } - - // fill in farm related accounts - if step == 1 || step == 3 { - match farm.route { - FarmRoute::Raydium { - farm_id, - farm_authority, - farm_lp_token_account, - farm_first_reward_token_account, - farm_second_reward_token_account, - } => { - accounts.push(AccountMeta::new_readonly(farm.farm_program_id, false)); - accounts.push(AccountMeta::new(vault_stake_info, false)); - accounts.push(AccountMeta::new(farm_id, false)); - accounts.push(AccountMeta::new_readonly(farm_authority, false)); - - accounts.push(AccountMeta::new(farm_lp_token_account, false)); - accounts.push(AccountMeta::new(farm_first_reward_token_account, false)); - accounts.push(AccountMeta::new( - farm_second_reward_token_account - .or_else(|| Some(zero::id())) - .unwrap(), - false, - )); - accounts.push(AccountMeta::new_readonly(sysvar::clock::id(), false)); - } - _ => { - unreachable!(); - } - } - } - } - VaultStrategy::DynamicHedge { .. } => { - unreachable!(); - } - } - - Ok((accounts, data)) - } -} diff --git a/farms/farm-client/src/client/vault_stc_accounts_saber.rs b/farms/farm-client/src/client/vault_stc_accounts_saber.rs deleted file mode 100644 index d85aa331167..00000000000 --- a/farms/farm-client/src/client/vault_stc_accounts_saber.rs +++ /dev/null @@ -1,916 +0,0 @@ -//! Solana Farm Client Vault Instructions - -use { - crate::error::FarmClientError, - solana_farm_sdk::{ - farm::FarmRoute, id::zero, instruction::vault::VaultInstruction, pool::PoolRoute, - vault::VaultStrategy, - }, - solana_sdk::{ - instruction::AccountMeta, program_error::ProgramError, pubkey::Pubkey, system_program, - sysvar, - }, - std::vec::Vec, -}; - -use super::FarmClient; - -impl FarmClient { - /// Returns accounts and data for initializing a new User for the Vault - pub fn get_stc_user_init_accounts_saber( - &self, - wallet_address: &Pubkey, - vault_name: &str, - ) -> Result<(Vec, Vec), FarmClientError> { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - // fill in accounts and instruction data - let data = VaultInstruction::UserInit.to_vec()?; - let accounts = vec![ - AccountMeta::new(*wallet_address, true), - AccountMeta::new_readonly(vault_ref, false), - AccountMeta::new(vault.info_account, false), - AccountMeta::new_readonly(*wallet_address, false), - AccountMeta::new( - self.get_vault_user_info_account(wallet_address, vault_name)?, - false, - ), - AccountMeta::new_readonly(system_program::id(), false), - ]; - Ok((accounts, data)) - } - - /// Returns accounts and data for adding liquidity to the Vault - pub fn get_stc_add_liquidity_accounts_saber( - &self, - wallet_address: &Pubkey, - vault_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - ) -> Result<(Vec, Vec), FarmClientError> { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - - // fill in accounts and instruction data - let mut accounts = vec![AccountMeta::new_readonly(*wallet_address, true)]; - - // general accounts - accounts.push(AccountMeta::new_readonly(vault_ref, false)); - accounts.push(AccountMeta::new(vault.info_account, false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new( - self.get_vault_user_info_account(wallet_address, vault_name)?, - false, - )); - - // strategy related accounts - let data = match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { - pool_ref, - farm_ref, - lp_token_custody, - .. - } => { - let pool = self.get_pool_by_ref(&pool_ref)?; - let farm = self.get_farm_by_ref(&farm_ref)?; - - // get tokens info - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - let farm_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - assert_eq!(farm_token, lp_token); - - // get user accounts info - let user_lp_token_account = self.get_token_account(wallet_address, &lp_token); - // fill in pool related accounts - match pool.route { - PoolRoute::Saber { - swap_account, - swap_authority, - wrapped_token_a_ref, - wrapped_token_b_ref, - .. - } => { - let wrapped_token_a = - self.get_token_by_ref_from_cache(&wrapped_token_a_ref)?; - let user_token_a_account = if wrapped_token_a.is_some() { - self.get_token_account(wallet_address, &wrapped_token_a) - } else { - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - self.get_token_account(wallet_address, &token_a) - }; - let wrapped_token_b = - self.get_token_by_ref_from_cache(&wrapped_token_b_ref)?; - let user_token_b_account = if wrapped_token_b.is_some() { - self.get_token_account(wallet_address, &wrapped_token_b) - } else { - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - self.get_token_account(wallet_address, &token_b) - }; - - accounts.push(AccountMeta::new( - user_token_a_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_token_b_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_lp_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new(lp_token_custody, false)); - accounts.push(AccountMeta::new_readonly(pool.pool_program_id, false)); - accounts.push(AccountMeta::new( - pool.token_a_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - pool.token_b_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - lp_token.ok_or(ProgramError::UninitializedAccount)?.mint, - false, - )); - accounts.push(AccountMeta::new_readonly(sysvar::clock::id(), false)); - accounts.push(AccountMeta::new_readonly(swap_account, false)); - accounts.push(AccountMeta::new_readonly(swap_authority, false)); - } - _ => { - unreachable!(); - } - } - - VaultInstruction::AddLiquidity { - max_token_a_amount: self - .to_token_amount_option(max_token_a_ui_amount, &token_a)?, - max_token_b_amount: self - .to_token_amount_option(max_token_b_ui_amount, &token_b)?, - } - .to_vec()? - } - VaultStrategy::DynamicHedge { .. } => { - unreachable!(); - } - }; - Ok((accounts, data)) - } - - /// Returns accounts and data for locking liquidity in the Vault - pub fn get_stc_lock_liquidity_accounts_saber( - &self, - wallet_address: &Pubkey, - vault_name: &str, - ui_amount: f64, - ) -> Result<(Vec, Vec), FarmClientError> { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - let vault_token = self.get_token_by_ref_from_cache(&Some(vault.vault_token_ref))?; - - // fill in accounts and instruction data - let mut accounts = vec![AccountMeta::new_readonly(*wallet_address, true)]; - - // general accounts - accounts.push(AccountMeta::new_readonly(vault_ref, false)); - accounts.push(AccountMeta::new(vault.info_account, false)); - accounts.push(AccountMeta::new_readonly(vault.vault_authority, false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new(vault_token.unwrap().mint, false)); - accounts.push(AccountMeta::new( - self.get_vault_user_info_account(wallet_address, vault_name)?, - false, - )); - - // strategy related accounts - let data = match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { - pool_ref, - farm_ref, - lp_token_custody, - vault_stake_info, - .. - } => { - let pool = self.get_pool_by_ref(&pool_ref)?; - let farm = self.get_farm_by_ref(&farm_ref)?; - - // get tokens info - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - let farm_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - assert_eq!(farm_token, lp_token); - - let user_vt_token_account = self.get_token_account(wallet_address, &vault_token); - - // fill in farm related accounts - match farm.route { - FarmRoute::Saber { - quarry, rewarder, .. - } => { - let vault_miner_account = self - .get_token_account(&vault_stake_info, &lp_token) - .ok_or(ProgramError::UninitializedAccount)?; - - accounts.push(AccountMeta::new( - user_vt_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new(lp_token_custody, false)); - accounts.push(AccountMeta::new_readonly(farm.farm_program_id, false)); - accounts.push(AccountMeta::new(vault_stake_info, false)); - accounts.push(AccountMeta::new(vault_miner_account, false)); - accounts.push(AccountMeta::new(quarry, false)); - accounts.push(AccountMeta::new_readonly(rewarder, false)); - } - _ => { - unreachable!(); - } - } - - VaultInstruction::LockLiquidity { - amount: self.to_token_amount_option(ui_amount, &lp_token)?, - } - .to_vec()? - } - VaultStrategy::DynamicHedge { .. } => { - unreachable!(); - } - }; - Ok((accounts, data)) - } - - /// Returns accounts and data for removing liquidity from the Vault - pub fn get_stc_remove_liquidity_accounts_saber( - &self, - wallet_address: &Pubkey, - vault_name: &str, - ui_amount: f64, - ) -> Result<(Vec, Vec), FarmClientError> { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - let vault_token = self.get_token_by_ref_from_cache(&Some(vault.vault_token_ref))?; - - // fill in accounts and instruction data - let mut accounts = vec![AccountMeta::new_readonly(*wallet_address, true)]; - - // general accounts - accounts.push(AccountMeta::new_readonly(vault_ref, false)); - accounts.push(AccountMeta::new(vault.info_account, false)); - accounts.push(AccountMeta::new_readonly(vault.vault_authority, false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new(vault_token.unwrap().mint, false)); - accounts.push(AccountMeta::new( - self.get_vault_user_info_account(wallet_address, vault_name)?, - false, - )); - - // strategy related accounts - let data = match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { - pool_ref, - farm_ref, - lp_token_custody, - vault_stake_info, - .. - } => { - let pool = self.get_pool_by_ref(&pool_ref)?; - let farm = self.get_farm_by_ref(&farm_ref)?; - - // get tokens info - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - let farm_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - assert_eq!(farm_token, lp_token); - - // get user accounts info - let user_vt_token_account = self.get_token_account(wallet_address, &vault_token); - - // fill in pool related accounts - match pool.route { - PoolRoute::Saber { - swap_account, - swap_authority, - fees_account_a, - fees_account_b, - wrapped_token_a_ref, - wrapped_token_b_ref, - .. - } => { - let wrapped_token_a = - self.get_token_by_ref_from_cache(&wrapped_token_a_ref)?; - let user_token_a_account = if wrapped_token_a.is_some() { - self.get_token_account(wallet_address, &wrapped_token_a) - } else { - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - self.get_token_account(wallet_address, &token_a) - }; - let wrapped_token_b = - self.get_token_by_ref_from_cache(&wrapped_token_b_ref)?; - let user_token_b_account = if wrapped_token_b.is_some() { - self.get_token_account(wallet_address, &wrapped_token_b) - } else { - let token_b = self.get_token_by_ref_from_cache(&pool.token_b_ref)?; - self.get_token_account(wallet_address, &token_b) - }; - - accounts.push(AccountMeta::new( - user_token_a_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_token_b_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - user_vt_token_account.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new(lp_token_custody, false)); - accounts.push(AccountMeta::new_readonly(pool.pool_program_id, false)); - accounts.push(AccountMeta::new( - pool.token_a_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - pool.token_b_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - lp_token.ok_or(ProgramError::UninitializedAccount)?.mint, - false, - )); - accounts.push(AccountMeta::new_readonly(swap_account, false)); - accounts.push(AccountMeta::new_readonly(swap_authority, false)); - accounts.push(AccountMeta::new(fees_account_a, false)); - accounts.push(AccountMeta::new(fees_account_b, false)); - } - _ => { - unreachable!(); - } - } - - // fill in farm related accounts - match farm.route { - FarmRoute::Saber { - quarry, rewarder, .. - } => { - let vault_miner_account = self - .get_token_account(&vault_stake_info, &lp_token) - .ok_or(ProgramError::UninitializedAccount)?; - - accounts.push(AccountMeta::new_readonly(farm.farm_program_id, false)); - accounts.push(AccountMeta::new(vault_stake_info, false)); - accounts.push(AccountMeta::new(vault_miner_account, false)); - accounts.push(AccountMeta::new(quarry, false)); - accounts.push(AccountMeta::new_readonly(rewarder, false)); - } - _ => { - unreachable!(); - } - } - - VaultInstruction::RemoveLiquidity { - amount: self.to_token_amount_option(ui_amount, &lp_token)?, - } - .to_vec()? - } - VaultStrategy::DynamicHedge { .. } => { - unreachable!(); - } - }; - Ok((accounts, data)) - } - - /// Returns accounts and data for a Vault Init Instruction - pub fn get_stc_init_accounts_saber( - &self, - admin_address: &Pubkey, - vault_name: &str, - step: u64, - ) -> Result<(Vec, Vec), FarmClientError> { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - let vault_token = self - .get_token_by_ref_from_cache(&Some(vault.vault_token_ref))? - .unwrap(); - - // fill in accounts and instruction data - let data = VaultInstruction::Init { step }.to_vec()?; - let mut accounts = vec![AccountMeta::new(*admin_address, true)]; - - // general accounts - accounts.push(AccountMeta::new_readonly(vault_ref, false)); - accounts.push(AccountMeta::new(vault.info_account, false)); - accounts.push(AccountMeta::new( - self.get_vault_active_multisig_account(vault_name)?, - false, - )); - accounts.push(AccountMeta::new(vault.vault_authority, false)); - accounts.push(AccountMeta::new_readonly(vault.vault_program_id, false)); - accounts.push(AccountMeta::new_readonly(system_program::id(), false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - accounts.push(AccountMeta::new_readonly( - spl_associated_token_account::id(), - false, - )); - accounts.push(AccountMeta::new_readonly(sysvar::rent::id(), false)); - - match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { - pool_ref, - farm_ref, - lp_token_custody, - token_a_custody, - token_b_custody, - token_a_reward_custody, - token_b_reward_custody, - vault_stake_info, - .. - } => { - // get pools - let pool = self.get_pool_by_ref(&pool_ref)?; - let farm = self.get_farm_by_ref(&farm_ref)?; - // get tokens info - let token_a = self - .get_token_by_ref_from_cache(&pool.token_a_ref)? - .unwrap(); - let token_b = self - .get_token_by_ref_from_cache(&pool.token_b_ref)? - .unwrap(); - let usdc_token = self.get_token("USDC")?; - let token_a_usdc = if token_a.mint == usdc_token.mint { - true - } else if token_b.mint == usdc_token.mint { - false - } else { - return Err(FarmClientError::ValueError( - "Only USDC pools are supported".to_string(), - )); - }; - let lp_token = self - .get_token_by_ref_from_cache(&pool.lp_token_ref)? - .unwrap(); - let token_a_reward = self - .get_token_by_ref_from_cache(&farm.first_reward_token_ref)? - .unwrap(); - let token_b_reward = - self.get_token_by_ref_from_cache(&farm.second_reward_token_ref)?; - let wrapped_token_mint = match pool.route { - PoolRoute::Saber { - wrapped_token_a_ref, - wrapped_token_b_ref, - .. - } => { - let wrapped_token_a = - self.get_token_by_ref_from_cache(&wrapped_token_a_ref)?; - let wrapped_token_b = - self.get_token_by_ref_from_cache(&wrapped_token_b_ref)?; - if wrapped_token_a.is_some() && wrapped_token_b.is_some() { - // no such pools - unreachable!(); - } else if wrapped_token_a.is_some() { - wrapped_token_a.unwrap().mint - } else if let Some(token) = wrapped_token_b { - token.mint - } else { - zero::id() - } - } - _ => { - unreachable!() - } - }; - - let vault_miner_account = self - .get_token_account(&vault_stake_info, &Some(lp_token)) - .ok_or(ProgramError::UninitializedAccount)?; - - accounts.push(AccountMeta::new_readonly(farm.farm_program_id, false)); - accounts.push(AccountMeta::new(vault_token.mint, false)); - accounts.push(AccountMeta::new_readonly(vault.vault_token_ref, false)); - accounts.push(AccountMeta::new(vault_stake_info, false)); - accounts.push(AccountMeta::new(vault_miner_account, false)); - accounts.push(AccountMeta::new( - vault.fees_account_a.or_else(|| Some(zero::id())).unwrap(), - false, - )); - accounts.push(AccountMeta::new( - vault.fees_account_b.or_else(|| Some(zero::id())).unwrap(), - false, - )); - accounts.push(AccountMeta::new(token_a_custody, false)); - accounts.push(AccountMeta::new( - token_b_custody.or_else(|| Some(zero::id())).unwrap(), - false, - )); - accounts.push(AccountMeta::new(lp_token_custody, false)); - accounts.push(AccountMeta::new(usdc_token.mint, false)); - if token_a_usdc { - accounts.push(AccountMeta::new(token_b.mint, false)); - } else { - accounts.push(AccountMeta::new(token_a.mint, false)); - } - accounts.push(AccountMeta::new(wrapped_token_mint, false)); - accounts.push(AccountMeta::new(lp_token.mint, false)); - - accounts.push(AccountMeta::new(token_a_reward_custody, false)); - accounts.push(AccountMeta::new( - token_b_reward_custody.or_else(|| Some(zero::id())).unwrap(), - false, - )); - accounts.push(AccountMeta::new(token_a_reward.mint, false)); - if let Some(token) = token_b_reward { - accounts.push(AccountMeta::new(token.mint, false)); - } else { - accounts.push(AccountMeta::new(zero::id(), false)); - } - // fill in farm related accounts - match farm.route { - FarmRoute::Saber { - quarry, rewarder, .. - } => { - accounts.push(AccountMeta::new(quarry, false)); - accounts.push(AccountMeta::new(rewarder, false)); - } - _ => { - unreachable!(); - } - } - } - VaultStrategy::DynamicHedge { .. } => { - unreachable!(); - } - } - - Ok((accounts, data)) - } - - /// Returns accounts and data for a Vault Shutdown Instruction - pub fn get_stc_shutdown_accounts_saber( - &self, - admin_address: &Pubkey, - vault_name: &str, - ) -> Result<(Vec, Vec), FarmClientError> { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - - // fill in accounts and instruction data - let data = VaultInstruction::Shutdown.to_vec()?; - let accounts = vec![ - AccountMeta::new_readonly(*admin_address, true), - AccountMeta::new_readonly(vault_ref, false), - AccountMeta::new(vault.info_account, false), - AccountMeta::new(self.get_vault_active_multisig_account(vault_name)?, false), - ]; - - Ok((accounts, data)) - } - - /// Returns accounts and data for a Vault Crank Instruction - pub fn get_stc_crank_accounts_saber( - &self, - wallet_address: &Pubkey, - vault_name: &str, - step: u64, - ) -> Result<(Vec, Vec), FarmClientError> { - // get vault info - let vault = self.get_vault(vault_name)?; - let vault_ref = self.get_vault_ref(vault_name)?; - - // fill in accounts and instruction data - let data = VaultInstruction::Crank { step }.to_vec()?; - let mut accounts = vec![AccountMeta::new_readonly(*wallet_address, true)]; - - // general accounts - accounts.push(AccountMeta::new_readonly(vault_ref, false)); - accounts.push(AccountMeta::new(vault.info_account, false)); - accounts.push(AccountMeta::new_readonly(vault.vault_authority, false)); - accounts.push(AccountMeta::new_readonly(spl_token::id(), false)); - - // strategy related accounts - match vault.strategy { - VaultStrategy::StakeLpCompoundRewards { - pool_ref, - farm_ref, - lp_token_custody, - token_a_custody, - token_b_custody, - token_a_reward_custody, - token_b_reward_custody, - vault_stake_info, - .. - } => { - let pool = self.get_pool_by_ref(&pool_ref)?; - let farm = self.get_farm_by_ref(&farm_ref)?; - - // get tokens info - let sbr_token = self.get_token_by_ref_from_cache(&farm.first_reward_token_ref)?; - let iou_token = self.get_token_by_ref_from_cache(&farm.second_reward_token_ref)?; - let token_a = self.get_token_by_ref_from_cache(&pool.token_a_ref)?; - let lp_token = self.get_token_by_ref_from_cache(&pool.lp_token_ref)?; - let farm_token = self.get_token_by_ref_from_cache(&farm.lp_token_ref)?; - assert_eq!(farm_token, lp_token); - let (is_token_a_wrapped, is_token_b_wrapped) = - self.pool_has_saber_wrapped_tokens(&pool.name)?; - let usdc_mint = self.get_token("USDC")?.mint; - - match farm.route { - FarmRoute::Saber { - quarry, - rewarder, - redeemer, - redeemer_program, - minter, - mint_wrapper, - mint_wrapper_program, - iou_fees_account, - sbr_vault, - mint_proxy_program, - mint_proxy_authority, - mint_proxy_state, - minter_info, - } => match step { - 1 => { - accounts.push(AccountMeta::new( - token_b_reward_custody.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new_readonly(farm.farm_program_id, false)); - accounts.push(AccountMeta::new(vault_stake_info, false)); - accounts.push(AccountMeta::new(mint_wrapper, false)); - accounts.push(AccountMeta::new_readonly(mint_wrapper_program, false)); - accounts.push(AccountMeta::new(minter, false)); - accounts.push(AccountMeta::new( - iou_token.ok_or(ProgramError::UninitializedAccount)?.mint, - false, - )); - accounts.push(AccountMeta::new(iou_fees_account, false)); - accounts.push(AccountMeta::new(quarry, false)); - accounts.push(AccountMeta::new_readonly(rewarder, false)); - accounts.push(AccountMeta::new(zero::id(), false)); - } - 2 => { - accounts.push(AccountMeta::new(token_a_reward_custody, false)); - accounts.push(AccountMeta::new( - token_b_reward_custody.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - vault - .fees_account_a - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new_readonly(redeemer, false)); - accounts.push(AccountMeta::new_readonly(redeemer_program, false)); - accounts.push(AccountMeta::new( - sbr_token.ok_or(ProgramError::UninitializedAccount)?.mint, - false, - )); - accounts.push(AccountMeta::new( - iou_token.ok_or(ProgramError::UninitializedAccount)?.mint, - false, - )); - accounts.push(AccountMeta::new(sbr_vault, false)); - accounts.push(AccountMeta::new_readonly(mint_proxy_program, false)); - accounts.push(AccountMeta::new_readonly(mint_proxy_authority, false)); - accounts.push(AccountMeta::new_readonly(mint_proxy_state, false)); - accounts.push(AccountMeta::new(minter_info, false)); - } - 3 => { - accounts.push(AccountMeta::new(token_a_reward_custody, false)); - accounts.push(AccountMeta::new(token_a_custody, false)); - accounts.push(AccountMeta::new( - token_b_custody.or_else(|| Some(zero::id())).unwrap(), - false, - )); - - match pool.route { - PoolRoute::Saber { - decimal_wrapper_program, - wrapped_token_a_ref, - wrapped_token_a_vault, - decimal_wrapper_token_a, - wrapped_token_b_ref, - wrapped_token_b_vault, - decimal_wrapper_token_b, - .. - } => { - let (wrapped_token_mint, wrapped_token_vault, decimal_wrapper) = - if is_token_a_wrapped { - let wrapped_token_a = self - .get_token_by_ref_from_cache( - &wrapped_token_a_ref, - )?; - ( - wrapped_token_a - .ok_or(ProgramError::UninitializedAccount)? - .mint, - wrapped_token_a_vault - .ok_or(ProgramError::UninitializedAccount)?, - decimal_wrapper_token_a - .ok_or(ProgramError::UninitializedAccount)?, - ) - } else if is_token_b_wrapped { - let wrapped_token_b = self - .get_token_by_ref_from_cache( - &wrapped_token_b_ref, - )?; - ( - wrapped_token_b - .ok_or(ProgramError::UninitializedAccount)? - .mint, - wrapped_token_b_vault - .ok_or(ProgramError::UninitializedAccount)?, - decimal_wrapper_token_b - .ok_or(ProgramError::UninitializedAccount)?, - ) - } else { - (zero::id(), zero::id(), zero::id()) - }; - - accounts.push(AccountMeta::new_readonly(usdc_mint, false)); - accounts.push(AccountMeta::new(wrapped_token_mint, false)); - accounts.push(AccountMeta::new(wrapped_token_vault, false)); - accounts - .push(AccountMeta::new_readonly(decimal_wrapper, false)); - accounts.push(AccountMeta::new_readonly( - decimal_wrapper_program, - false, - )); - } - _ => { - unreachable!(); - } - } - - let usdc_pool = self.get_pool("RDM.SBR-USDC")?; - match usdc_pool.route { - PoolRoute::Raydium { - amm_id, - amm_authority, - amm_open_orders, - amm_target, - pool_withdraw_queue: _, - pool_temp_lp_token_account: _, - serum_program_id, - serum_market, - serum_coin_vault_account, - serum_pc_vault_account, - serum_vault_signer, - serum_bids, - serum_asks, - serum_event_queue, - } => { - accounts.push(AccountMeta::new_readonly( - usdc_pool.pool_program_id, - false, - )); - accounts.push(AccountMeta::new( - usdc_pool - .token_a_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - usdc_pool - .token_b_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new(amm_id, false)); - accounts.push(AccountMeta::new_readonly(amm_authority, false)); - accounts.push(AccountMeta::new(amm_open_orders, false)); - accounts.push(AccountMeta::new(amm_target, false)); - accounts.push(AccountMeta::new(serum_market, false)); - accounts - .push(AccountMeta::new_readonly(serum_program_id, false)); - accounts - .push(AccountMeta::new(serum_coin_vault_account, false)); - accounts.push(AccountMeta::new(serum_pc_vault_account, false)); - accounts - .push(AccountMeta::new_readonly(serum_vault_signer, false)); - accounts.push(AccountMeta::new( - serum_bids.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - serum_asks.ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - serum_event_queue - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new_readonly( - sysvar::instructions::id(), - false, - )); - } - _ => { - unreachable!(); - } - } - } - 4 => match pool.route { - PoolRoute::Saber { - swap_account, - swap_authority, - .. - } => { - let usdc_token = self.get_token("USDC")?; - if token_a.ok_or(ProgramError::UninitializedAccount)?.mint - != usdc_token.mint - { - accounts.push(AccountMeta::new( - vault - .fees_account_b - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - } - if is_token_a_wrapped || is_token_b_wrapped { - accounts.push(AccountMeta::new( - token_b_custody - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - } else { - accounts.push(AccountMeta::new(token_a_custody, false)); - } - if token_a.ok_or(ProgramError::UninitializedAccount)?.mint - == usdc_token.mint - { - accounts.push(AccountMeta::new( - vault - .fees_account_b - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - } - accounts.push(AccountMeta::new(lp_token_custody, false)); - accounts - .push(AccountMeta::new_readonly(pool.pool_program_id, false)); - accounts.push(AccountMeta::new( - pool.token_a_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - pool.token_b_account - .ok_or(ProgramError::UninitializedAccount)?, - false, - )); - accounts.push(AccountMeta::new( - lp_token.ok_or(ProgramError::UninitializedAccount)?.mint, - false, - )); - accounts - .push(AccountMeta::new_readonly(sysvar::clock::id(), false)); - accounts.push(AccountMeta::new_readonly(swap_account, false)); - accounts.push(AccountMeta::new_readonly(swap_authority, false)); - } - _ => { - unreachable!(); - } - }, - 5 => { - let vault_miner_account = self - .get_token_account(&vault_stake_info, &lp_token) - .ok_or(ProgramError::UninitializedAccount)?; - - accounts.push(AccountMeta::new(lp_token_custody, false)); - accounts.push(AccountMeta::new_readonly(farm.farm_program_id, false)); - accounts.push(AccountMeta::new(vault_stake_info, false)); - accounts.push(AccountMeta::new(vault_miner_account, false)); - accounts.push(AccountMeta::new(quarry, false)); - accounts.push(AccountMeta::new_readonly(rewarder, false)); - } - _ => { - panic!("Crank step must be 1-5"); - } - }, - _ => { - unreachable!(); - } - } - } - VaultStrategy::DynamicHedge { .. } => { - unreachable!(); - } - } - - Ok((accounts, data)) - } -} diff --git a/farms/farm-client/src/error.rs b/farms/farm-client/src/error.rs deleted file mode 100644 index 35f11e6a1b8..00000000000 --- a/farms/farm-client/src/error.rs +++ /dev/null @@ -1,34 +0,0 @@ -use { - pyth_client::PythError, - solana_account_decoder::parse_account_data::ParseAccountError, - solana_client::client_error::ClientError, - solana_sdk::{program_error::ProgramError, pubkey::PubkeyError}, - thiserror::Error, -}; - -/// Farm Client Errors -#[derive(Debug, Error)] -pub enum FarmClientError { - #[error(transparent)] - RpcClientError(#[from] ClientError), - #[error(transparent)] - ProgramError(#[from] ProgramError), - #[error(transparent)] - ParseAccountError(#[from] ParseAccountError), - #[error(transparent)] - PubkeyError(#[from] PubkeyError), - #[error(transparent)] - PythError(#[from] PythError), - #[error("Record not found: {0}")] - RecordNotFound(String), - #[error("ArrayString error: {0}")] - ArrayStringError(String), - #[error("I/O error: {0}")] - IOError(String), - #[error("Parse error: {0}")] - ParseError(String), - #[error("Value error: {0}")] - ValueError(String), - #[error("Insufficient balance: {0}")] - InsufficientBalance(String), -} diff --git a/farms/farm-client/src/lib.rs b/farms/farm-client/src/lib.rs deleted file mode 100644 index 9594afd75f9..00000000000 --- a/farms/farm-client/src/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod cache; -pub mod client; -pub mod error; diff --git a/farms/farm-client/tests/orca_pools.rs b/farms/farm-client/tests/orca_pools.rs deleted file mode 100644 index 80fa1964d60..00000000000 --- a/farms/farm-client/tests/orca_pools.rs +++ /dev/null @@ -1,118 +0,0 @@ -mod pool_actions; -mod utils; - -#[test] -#[ignore] -fn test_pool_atlas_usdc_v1() { - pool_actions::run_test( - "ORC.ATLAS-USDC-V1", - vec![ - utils::Swap { - protocol: "ORC", - from_token: "SOL", - to_token: "USDC", - amount: 0.222, - }, - utils::Swap { - protocol: "ORC", - from_token: "USDC", - to_token: "ATLAS", - amount: -0.5, - }, - ], - vec![ - utils::Swap { - protocol: "ORC", - from_token: "ATLAS", - to_token: "USDC", - amount: 0.0, - }, - utils::Swap { - protocol: "ORC", - from_token: "USDC", - to_token: "SOL", - amount: 0.0, - }, - ], - false, - ); -} - -#[test] -#[ignore] -fn test_pool_ray_sol_latest() { - pool_actions::run_test( - "ORC.RAY-SOL", - vec![utils::Swap { - protocol: "ORC", - from_token: "SOL", - to_token: "RAY", - amount: 0.111, - }], - vec![utils::Swap { - protocol: "ORC", - from_token: "RAY", - to_token: "SOL", - amount: 0.0, - }], - false, - ); -} - -#[test] -#[ignore] -fn test_pool_sol_usdc_latest() { - pool_actions::run_test( - "ORC.SOL-USDC", - vec![utils::Swap { - protocol: "ORC", - from_token: "SOL", - to_token: "USDC", - amount: 0.111, - }], - vec![utils::Swap { - protocol: "ORC", - from_token: "USDC", - to_token: "SOL", - amount: 0.0, - }], - false, - ); -} - -#[test] -#[ignore] -fn test_pool_msol_sol_latest() { - pool_actions::run_test( - "ORC.MSOL-SOL", - vec![ - utils::Swap { - protocol: "ORC", - from_token: "SOL", - to_token: "USDC", - amount: 0.119, - }, - utils::Swap { - protocol: "ORC", - from_token: "USDC", - to_token: "MSOL", - amount: -0.5, - }, - ], - vec![ - utils::Swap { - protocol: "ORC", - from_token: "MSOL", - to_token: "USDC", - amount: 0.0, - }, - utils::Swap { - protocol: "ORC", - from_token: "USDC", - to_token: "SOL", - amount: 0.0, - }, - ], - false, - ); -} diff --git a/farms/farm-client/tests/orca_vaults.rs b/farms/farm-client/tests/orca_vaults.rs deleted file mode 100644 index 04976caf94b..00000000000 --- a/farms/farm-client/tests/orca_vaults.rs +++ /dev/null @@ -1,58 +0,0 @@ -mod utils; -mod vault_actions; - -#[test] -#[ignore] -fn test_vault_chicks_usdc() { - vault_actions::run_test( - "ORC.STC.CHICKS-USDC-AQ-V1", - vec![ - utils::Swap { - protocol: "ORC", - from_token: "SOL", - to_token: "USDC", - amount: 1.222, - }, - utils::Swap { - protocol: "ORC", - from_token: "USDC", - to_token: "CHICKS", - amount: -0.5, - }, - ], - vec![utils::Swap { - protocol: "ORC", - from_token: "CHICKS", - to_token: "USDC", - amount: 0.0, - }], - ); -} - -#[test] -#[ignore] -fn test_vault_chicks_usdc_latest() { - vault_actions::run_test( - "ORC.STC.CHICKS-USDC-AQ", - vec![ - utils::Swap { - protocol: "ORC", - from_token: "SOL", - to_token: "USDC", - amount: 1.222, - }, - utils::Swap { - protocol: "ORC", - from_token: "USDC", - to_token: "CHICKS", - amount: -0.5, - }, - ], - vec![utils::Swap { - protocol: "ORC", - from_token: "CHICKS", - to_token: "USDC", - amount: 0.0, - }], - ); -} diff --git a/farms/farm-client/tests/pool_actions/mod.rs b/farms/farm-client/tests/pool_actions/mod.rs deleted file mode 100644 index c3ea373059e..00000000000 --- a/farms/farm-client/tests/pool_actions/mod.rs +++ /dev/null @@ -1,321 +0,0 @@ -use { - solana_farm_client::client::FarmClient, - solana_sdk::{commitment_config::CommitmentConfig, signature::Keypair, signer::Signer}, -}; - -use crate::{utils, utils::Swap}; - -const MAX_SOL_BALANCE_TO_USE: f64 = 0.1; - -pub fn do_swap(client: &FarmClient, keypair: &Keypair, swap: &Swap) { - let amount = if swap.amount == 0.0 { - utils::get_token_or_native_balance(client, &keypair.pubkey(), swap.from_token) - } else if swap.amount < 0.0 { - -1.0 * swap.amount - * utils::get_token_or_native_balance(client, &keypair.pubkey(), swap.from_token) - } else { - swap.amount - }; - if amount < 0.0003 { - return; - } - println!( - ">> Swap {} {} to {}", - amount, swap.from_token, swap.to_token - ); - println!( - " Done: {}", - client - .swap( - keypair, - swap.protocol - .parse() - .expect("Failed to parse protocol argument"), - swap.from_token, - swap.to_token, - amount, - 0.0, - ) - .unwrap() - ); - let _ = utils::get_balances( - client, - &keypair.pubkey(), - swap.from_token, - swap.to_token, - "After swap", - ); -} - -pub fn do_add_liquidity( - client: &FarmClient, - keypair: &Keypair, - pool_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, -) -> f64 { - println!( - ">> Add liquidity to {}: {}, {}", - pool_name, max_token_a_ui_amount, max_token_b_ui_amount - ); - let (token_a_str, token_b_str, lp_token_name) = client.get_pool_token_names(pool_name).unwrap(); - let lp_balance = utils::get_token_or_native_balance(client, &keypair.pubkey(), &lp_token_name); - println!( - " Done: {}", - client - .add_liquidity_pool( - keypair, - pool_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - ) - .unwrap() - ); - let _ = utils::get_balances( - client, - &keypair.pubkey(), - &token_a_str, - &token_b_str, - "After add liquidity", - ); - let _ = utils::get_balance(client, &keypair.pubkey(), &lp_token_name, "LP"); - utils::get_token_or_native_balance(client, &keypair.pubkey(), &lp_token_name) - lp_balance -} - -pub fn do_stake(client: &FarmClient, keypair: &Keypair, farm_name: &str, amount: f64) { - println!(">> Stake liquidity to {}: {}", farm_name, amount); - let (token_a_str, token_b_str, lp_token_name) = client.get_farm_token_names(farm_name).unwrap(); - println!( - " Done: {}", - client.stake(keypair, farm_name, amount).unwrap() - ); - let _ = utils::get_balances( - client, - &keypair.pubkey(), - &token_a_str, - &token_b_str, - "After stake", - ); - let _ = utils::get_balance(client, &keypair.pubkey(), &lp_token_name, "LP after stake"); -} - -pub fn do_harvest(client: &FarmClient, keypair: &Keypair, farm_name: &str) { - println!(">> Harvest from {}", farm_name); - let (token_a_str, token_b_str, lp_token_name) = client.get_farm_token_names(farm_name).unwrap(); - println!(" Done: {}", client.harvest(keypair, farm_name).unwrap()); - let _ = utils::get_balances( - client, - &keypair.pubkey(), - &token_a_str, - &token_b_str, - "After harvest", - ); - let _ = utils::get_balance( - client, - &keypair.pubkey(), - &lp_token_name, - "LP after harvest", - ); -} - -pub fn do_unstake(client: &FarmClient, keypair: &Keypair, farm_name: &str, amount: f64) { - println!(">> Unstake liquidity from {}: {}", farm_name, amount); - let (token_a_str, token_b_str, lp_token_name) = client.get_farm_token_names(farm_name).unwrap(); - println!( - " Done: {}", - client.unstake(keypair, farm_name, amount).unwrap() - ); - let _ = utils::get_balances( - client, - &keypair.pubkey(), - &token_a_str, - &token_b_str, - "After unstake", - ); - let _ = utils::get_balance( - client, - &keypair.pubkey(), - &lp_token_name, - "LP after unstake", - ); -} - -pub fn do_remove_liquidity(client: &FarmClient, keypair: &Keypair, pool_name: &str, amount: f64) { - println!(">> Remove liquidity from {}: {}", pool_name, amount); - let (token_a_str, token_b_str, lp_token_name) = client.get_pool_token_names(pool_name).unwrap(); - println!( - " Done: {}", - client - .remove_liquidity_pool(keypair, pool_name, amount) - .unwrap() - ); - let _ = utils::get_balances( - client, - &keypair.pubkey(), - &token_a_str, - &token_b_str, - "After remove liquidity", - ); - let _ = utils::get_balance(client, &keypair.pubkey(), &lp_token_name, "LP"); -} - -pub fn cleanup( - client: &FarmClient, - keypair: &Keypair, - pool_name: &str, - cleanup_swaps: Vec, - pool_only: bool, -) { - println!("\n>>> Clean-up {}...", pool_name); - let wallet = keypair.pubkey(); - let (token_a_str, token_b_str, lp_token_name) = client.get_pool_token_names(pool_name).unwrap(); - - if !pool_only { - let farms = client.find_farms_with_lp(&lp_token_name).unwrap(); - for farm in farms.iter() { - let farm_token_name = - "LP.".to_string() + &farm.name.as_str()[..farm.name.as_str().len() - 3]; - if let Ok(dd_farms) = client.find_farms_with_lp(&farm_token_name) { - for farm in dd_farms.iter() { - if let Ok(staked_balance) = - client.get_user_stake_balance(&wallet, farm.name.as_str()) - { - if staked_balance > 0.0 { - do_unstake(client, keypair, farm.name.as_str(), staked_balance); - } - } - } - } - - if let Ok(staked_balance) = client.get_user_stake_balance(&wallet, farm.name.as_str()) { - if staked_balance > 0.0 { - do_unstake(client, keypair, farm.name.as_str(), staked_balance); - } - } - } - } - - let lp_token_balance = utils::get_token_or_native_balance(client, &wallet, &lp_token_name); - if lp_token_balance > 0.0 { - do_remove_liquidity(client, keypair, pool_name, lp_token_balance); - } - - for swap in cleanup_swaps { - do_swap(client, keypair, &swap); - } - - if token_a_str != "SOL" { - let token_a_balance = utils::get_token_or_native_balance(client, &wallet, &token_a_str); - if token_a_balance > 0.0 { - do_swap( - client, - keypair, - &Swap { - protocol: "RDM", - from_token: token_a_str.as_str(), - to_token: "SOL", - amount: token_a_balance, - }, - ); - } - } - - if token_b_str != "SOL" { - let token_b_balance = utils::get_token_or_native_balance(client, &wallet, &token_b_str); - if token_b_balance > 0.0 { - do_swap( - client, - keypair, - &Swap { - protocol: "RDM", - from_token: token_b_str.as_str(), - to_token: "SOL", - amount: token_b_balance, - }, - ); - } - } -} - -pub fn run_test(pool_name: &str, swaps: Vec, cleanup_swaps: Vec, pool_only: bool) { - let (endpoint, keypair) = utils::get_endpoint_and_keypair(); - let client = FarmClient::new_with_commitment(&endpoint, CommitmentConfig::confirmed()); - let wallet = keypair.pubkey(); - - cleanup( - &client, - &keypair, - pool_name, - cleanup_swaps.clone(), - pool_only, - ); - - println!("\n>>> Testing {}...", pool_name); - let (token_a_str, token_b_str, lp_token_name) = client.get_pool_token_names(pool_name).unwrap(); - - let (_, _) = utils::get_balances(&client, &wallet, &token_a_str, &token_b_str, "Initial"); - //initial swaps - for swap in swaps { - do_swap(&client, &keypair, &swap); - } - - let token_a_balance = if token_a_str == "SOL" { - MAX_SOL_BALANCE_TO_USE.min(utils::get_token_or_native_balance( - &client, - &wallet, - &token_a_str, - )) - } else { - utils::get_token_or_native_balance(&client, &wallet, &token_a_str) - }; - let token_b_balance = if token_b_str == "SOL" { - MAX_SOL_BALANCE_TO_USE.min(utils::get_token_or_native_balance( - &client, - &wallet, - &token_b_str, - )) - } else { - utils::get_token_or_native_balance(&client, &wallet, &token_b_str) - }; - - assert!(token_a_balance > 0.0 && token_b_balance > 0.0); - - // main tests - let mut lp_received = - do_add_liquidity(&client, &keypair, pool_name, token_a_balance / 3.0, 0.0); - assert!(lp_received > 0.0); - lp_received += do_add_liquidity(&client, &keypair, pool_name, 0.0, token_b_balance / 3.0); - - if !pool_only { - let farms = client.find_farms_with_lp(&lp_token_name).unwrap(); - for farm in farms.iter() { - do_stake(&client, &keypair, farm.name.as_str(), lp_received / 2.0); - do_stake(&client, &keypair, farm.name.as_str(), 0.0); - do_harvest(&client, &keypair, farm.name.as_str()); - - // orca double-dip farms - if farm.name.starts_with("ORC.") { - let farm_token_name = - "LP.".to_string() + &farm.name.as_str()[..farm.name.as_str().len() - 3]; - if let Ok(dd_farms) = client.find_farms_with_lp(&farm_token_name) { - for dd_farm in dd_farms.iter() { - do_stake(&client, &keypair, dd_farm.name.as_str(), lp_received / 2.0); - do_stake(&client, &keypair, dd_farm.name.as_str(), 0.0); - do_harvest(&client, &keypair, dd_farm.name.as_str()); - do_unstake(&client, &keypair, dd_farm.name.as_str(), lp_received / 2.0); - do_unstake(&client, &keypair, dd_farm.name.as_str(), 0.0); - } - } - } - - do_unstake(&client, &keypair, farm.name.as_str(), lp_received / 2.0); - do_unstake(&client, &keypair, farm.name.as_str(), 0.0); - } - } - do_remove_liquidity(&client, &keypair, pool_name, lp_received / 2.0); - do_remove_liquidity(&client, &keypair, pool_name, 0.0); - - cleanup(&client, &keypair, pool_name, cleanup_swaps, pool_only); - - let (_, _) = utils::get_balances(&client, &wallet, &token_a_str, &token_b_str, "Final"); -} diff --git a/farms/farm-client/tests/raydium_pools.rs b/farms/farm-client/tests/raydium_pools.rs deleted file mode 100644 index e95019864b1..00000000000 --- a/farms/farm-client/tests/raydium_pools.rs +++ /dev/null @@ -1,278 +0,0 @@ -mod pool_actions; -mod utils; - -#[test] -#[ignore] -fn test_pool_ray_srm() { - pool_actions::run_test( - "RDM.RAY-SRM-V4", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "RAY", - amount: 0.111, - }, - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "SRM", - amount: 0.111, - }, - ], - vec![], - false, - ); -} - -#[test] -#[ignore] -fn test_pool_ray_srm_latest() { - pool_actions::run_test( - "RDM.RAY-SRM", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "RAY", - amount: 0.111, - }, - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "SRM", - amount: 0.111, - }, - ], - vec![], - false, - ); -} - -#[test] -#[ignore] -fn test_pool_polis_ray() { - pool_actions::run_test( - "RDM.POLIS-RAY-V4", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "RAY", - amount: 0.222, - }, - utils::Swap { - protocol: "RDM", - from_token: "RAY", - to_token: "POLIS", - amount: -0.5, - }, - ], - vec![utils::Swap { - protocol: "RDM", - from_token: "POLIS", - to_token: "RAY", - amount: 0.0, - }], - false, - ); -} - -#[test] -#[ignore] -fn test_pool_polis_ray_latest() { - pool_actions::run_test( - "RDM.POLIS-RAY", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "RAY", - amount: 0.222, - }, - utils::Swap { - protocol: "RDM", - from_token: "RAY", - to_token: "POLIS", - amount: -0.5, - }, - ], - vec![utils::Swap { - protocol: "RDM", - from_token: "POLIS", - to_token: "RAY", - amount: 0.0, - }], - false, - ); -} - -#[test] -#[ignore] -fn test_pool_grape_usdc() { - pool_actions::run_test( - "RDM.GRAPE-USDC-V4", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "USDC", - amount: 0.222, - }, - utils::Swap { - protocol: "RDM", - from_token: "USDC", - to_token: "GRAPE", - amount: -0.5, - }, - ], - vec![utils::Swap { - protocol: "RDM", - from_token: "GRAPE", - to_token: "USDC", - amount: 0.0, - }], - false, - ); -} - -#[test] -#[ignore] -fn test_pool_fida_ray() { - pool_actions::run_test( - "RDM.FIDA-RAY-V4", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "RAY", - amount: 0.21111111, - }, - utils::Swap { - protocol: "RDM", - from_token: "RAY", - to_token: "FIDA", - amount: -0.5, - }, - ], - vec![utils::Swap { - protocol: "RDM", - from_token: "FIDA", - to_token: "RAY", - amount: 0.0, - }], - false, - ); -} - -#[test] -#[ignore] -fn test_pool_ray_sol() { - pool_actions::run_test( - "RDM.RAY-SOL-V4", - vec![utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "RAY", - amount: 0.09999999, - }], - vec![], - false, - ); -} - -#[test] -#[ignore] -fn test_pool_ray_sol_latest() { - pool_actions::run_test( - "RDM.RAY-SOL", - vec![utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "RAY", - amount: 0.09999999, - }], - vec![], - false, - ); -} - -#[test] -#[ignore] -fn test_pool_sol_usdc() { - pool_actions::run_test( - "RDM.SOL-USDC-V4", - vec![utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "USDC", - amount: 0.10000001, - }], - vec![], - true, - ); -} - -#[test] -#[ignore] -fn test_pool_sol_usdc_latest() { - pool_actions::run_test( - "RDM.SOL-USDC", - vec![utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "USDC", - amount: 0.10000001, - }], - vec![], - true, - ); -} - -#[test] -#[ignore] -fn test_pool_msol_usdc() { - pool_actions::run_test( - "RDM.MSOL-USDC-V4", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "MSOL", - amount: 0.10000001, - }, - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "USDC", - amount: 0.1111, - }, - ], - vec![], - true, - ); -} - -#[test] -#[ignore] -fn test_pool_ray_usdc() { - pool_actions::run_test( - "RDM.RAY-USDC-V4", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "RAY", - amount: 0.10000001, - }, - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "USDC", - amount: 0.09999999, - }, - ], - vec![], - true, - ); -} diff --git a/farms/farm-client/tests/raydium_vaults.rs b/farms/farm-client/tests/raydium_vaults.rs deleted file mode 100644 index 161aee86e72..00000000000 --- a/farms/farm-client/tests/raydium_vaults.rs +++ /dev/null @@ -1,375 +0,0 @@ -mod utils; -mod vault_actions; - -#[test] -#[ignore] -fn test_vault_polis_ray() { - vault_actions::run_test( - "RDM.STC.POLIS-RAY-V5", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "RAY", - amount: 0.222, - }, - utils::Swap { - protocol: "RDM", - from_token: "RAY", - to_token: "POLIS", - amount: -0.5, - }, - ], - vec![utils::Swap { - protocol: "RDM", - from_token: "POLIS", - to_token: "RAY", - amount: 0.0, - }], - ); -} - -#[test] -#[ignore] -fn test_vault_polis_ray_latest() { - vault_actions::run_test( - "RDM.STC.POLIS-RAY", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "RAY", - amount: 0.222, - }, - utils::Swap { - protocol: "RDM", - from_token: "RAY", - to_token: "POLIS", - amount: -0.5, - }, - ], - vec![utils::Swap { - protocol: "RDM", - from_token: "POLIS", - to_token: "RAY", - amount: 0.0, - }], - ); -} - -#[test] -#[ignore] -fn test_vault_sny_ray() { - vault_actions::run_test( - "RDM.STC.SNY-RAY-V5", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "RAY", - amount: 0.222, - }, - utils::Swap { - protocol: "RDM", - from_token: "RAY", - to_token: "SNY", - amount: -0.5, - }, - ], - vec![utils::Swap { - protocol: "RDM", - from_token: "SNY", - to_token: "RAY", - amount: 0.0, - }], - ); -} - -#[test] -#[ignore] -fn test_vault_atlas_ray() { - vault_actions::run_test( - "RDM.STC.ATLAS-RAY-V5", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "RAY", - amount: 0.222, - }, - utils::Swap { - protocol: "RDM", - from_token: "RAY", - to_token: "ATLAS", - amount: -0.5, - }, - ], - vec![utils::Swap { - protocol: "RDM", - from_token: "ATLAS", - to_token: "RAY", - amount: 0.0, - }], - ); -} - -#[test] -#[ignore] -fn test_vault_ray_srm_v3() { - vault_actions::run_test( - "RDM.STC.RAY-SRM-V3", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "RAY", - amount: 0.123, - }, - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "SRM", - amount: 0.123, - }, - ], - vec![], - ); -} - -#[test] -#[ignore] -fn test_vault_ray_srm_v5() { - vault_actions::run_test( - "RDM.STC.RAY-SRM-V5", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "RAY", - amount: 0.123, - }, - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "SRM", - amount: 0.123, - }, - ], - vec![], - ); -} - -#[test] -#[ignore] -fn test_vault_ray_srm_latest() { - vault_actions::run_test( - "RDM.STC.RAY-SRM", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "RAY", - amount: 0.123, - }, - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "SRM", - amount: 0.123, - }, - ], - vec![], - ); -} - -#[test] -#[ignore] -fn test_vault_grape_usdc() { - vault_actions::run_test( - "RDM.STC.GRAPE-USDC-V5", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "USDC", - amount: 0.222, - }, - utils::Swap { - protocol: "RDM", - from_token: "USDC", - to_token: "GRAPE", - amount: -0.5, - }, - ], - vec![utils::Swap { - protocol: "RDM", - from_token: "GRAPE", - to_token: "USDC", - amount: 0.0, - }], - ); -} - -#[test] -#[ignore] -fn test_vault_samo_ray() { - vault_actions::run_test( - "RDM.STC.SAMO-RAY-V5", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "RAY", - amount: 0.211, - }, - utils::Swap { - protocol: "RDM", - from_token: "RAY", - to_token: "SAMO", - amount: -0.5, - }, - ], - vec![utils::Swap { - protocol: "RDM", - from_token: "SAMO", - to_token: "RAY", - amount: 0.0, - }], - ); -} - -#[test] -#[ignore] -fn test_vault_oxy_ray() { - vault_actions::run_test( - "RDM.STC.OXY-RAY-V4", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "RAY", - amount: 0.233, - }, - utils::Swap { - protocol: "RDM", - from_token: "RAY", - to_token: "OXY", - amount: -0.5, - }, - ], - vec![utils::Swap { - protocol: "RDM", - from_token: "OXY", - to_token: "RAY", - amount: 0.0, - }], - ); -} - -#[test] -#[ignore] -fn test_vault_oxy_ray_latest() { - vault_actions::run_test( - "RDM.STC.OXY-RAY", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "RAY", - amount: 0.233, - }, - utils::Swap { - protocol: "RDM", - from_token: "RAY", - to_token: "OXY", - amount: -0.5, - }, - ], - vec![utils::Swap { - protocol: "RDM", - from_token: "OXY", - to_token: "RAY", - amount: 0.0, - }], - ); -} - -#[test] -#[ignore] -fn test_vault_ray_sol() { - vault_actions::run_test( - "RDM.STC.RAY-SOL-V3", - vec![utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "RAY", - amount: 0.091111, - }], - vec![], - ); -} - -#[test] -#[ignore] -fn test_vault_ray_sol_latest() { - vault_actions::run_test( - "RDM.STC.RAY-SOL", - vec![utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "RAY", - amount: 0.091111, - }], - vec![], - ); -} - -#[test] -#[ignore] -fn test_vault_ray_usdt() { - vault_actions::run_test( - "RDM.STC.RAY-USDT-V3", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "RAY", - amount: 0.223, - }, - utils::Swap { - protocol: "RDM", - from_token: "RAY", - to_token: "USDT", - amount: -0.5, - }, - ], - vec![], - ); -} - -/* -#[test] -#[ignore] -fn all_vault_tests() { - // dual v5 - test_vault_polis_ray(); - test_vault_polis_ray_latest(); - test_vault_atlas_ray(); - test_vault_sny_ray(); - test_vault_ray_srm_v5(); - test_vault_ray_srm_latest(); - - // single reward b v5 - test_vault_grape_usdc(); - test_vault_samo_ray(); - - // dual v4 - test_vault_oxy_ray(); - test_vault_oxy_ray_latest(); - - // single reward a v3 - test_vault_ray_sol(); - test_vault_ray_sol_latest(); - test_vault_ray_usdt(); - test_vault_ray_srm_v3(); -}*/ diff --git a/farms/farm-client/tests/saber_pools.rs b/farms/farm-client/tests/saber_pools.rs deleted file mode 100644 index df2cab090cc..00000000000 --- a/farms/farm-client/tests/saber_pools.rs +++ /dev/null @@ -1,174 +0,0 @@ -mod pool_actions; -mod utils; - -#[test] -#[ignore] -fn test_pool_xsol_sol_v1() { - pool_actions::run_test( - "SBR.XSOL-SOL-V1", - vec![utils::Swap { - protocol: "SBR", - from_token: "SOL", - to_token: "XSOL", - amount: 0.222, - }], - vec![utils::Swap { - protocol: "SBR", - from_token: "XSOL", - to_token: "SOL", - amount: 0.0, - }], - false, - ); -} - -#[test] -#[ignore] -fn test_pool_xsol_sol_latest() { - pool_actions::run_test( - "SBR.XSOL-SOL", - vec![utils::Swap { - protocol: "SBR", - from_token: "SOL", - to_token: "XSOL", - amount: 0.222, - }], - vec![utils::Swap { - protocol: "SBR", - from_token: "XSOL", - to_token: "SOL", - amount: 0.0, - }], - false, - ); -} - -#[test] -#[ignore] -fn test_pool_renbtc_btc_latest() { - pool_actions::run_test( - "SBR.RENBTC-BTC", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "USDC", - amount: 0.222, - }, - utils::Swap { - protocol: "RDM", - from_token: "USDC", - to_token: "BTC", - amount: 0.0, - }, - utils::Swap { - protocol: "SBR", - from_token: "BTC", - to_token: "RENBTC", - amount: -0.5, - }, - ], - vec![ - utils::Swap { - protocol: "SBR", - from_token: "RENBTC", - to_token: "BTC", - amount: 0.0, - }, - utils::Swap { - protocol: "RDM", - from_token: "BTC", - to_token: "USDC", - amount: 0.0, - }, - ], - false, - ); -} - -#[test] -#[ignore] -fn test_pool_usdc_wust_v1_latest() { - pool_actions::run_test( - "SBR.USDC-WUST_V1", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "USDC", - amount: 0.222, - }, - utils::Swap { - protocol: "SBR", - from_token: "USDC", - to_token: "WUST_V1", - amount: -0.5, - }, - ], - vec![utils::Swap { - protocol: "SBR", - from_token: "WUST_V1", - to_token: "USDC", - amount: 0.0, - }], - false, - ); -} - -#[test] -#[ignore] -fn test_pool_wust_usdc_latest() { - pool_actions::run_test( - "SBR.WUST-USDC", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "USDC", - amount: 0.222, - }, - utils::Swap { - protocol: "SBR", - from_token: "USDC", - to_token: "WUST", - amount: -0.5, - }, - ], - vec![utils::Swap { - protocol: "SBR", - from_token: "WUST", - to_token: "USDC", - amount: 0.0, - }], - false, - ); -} - -#[test] -#[ignore] -fn test_pool_whusd_v1_usdc_latest() { - pool_actions::run_test( - "SBR.WHUSD_V1-USDC", - vec![ - utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "USDC", - amount: 0.222, - }, - utils::Swap { - protocol: "SBR", - from_token: "USDC", - to_token: "WHUSD_V1", - amount: -0.5, - }, - ], - vec![utils::Swap { - protocol: "SBR", - from_token: "WHUSD_V1", - to_token: "USDC", - amount: 0.0, - }], - false, - ); -} diff --git a/farms/farm-client/tests/saber_vaults.rs b/farms/farm-client/tests/saber_vaults.rs deleted file mode 100644 index 69044cdb2f2..00000000000 --- a/farms/farm-client/tests/saber_vaults.rs +++ /dev/null @@ -1,82 +0,0 @@ -mod utils; -mod vault_actions; - -#[test] -#[ignore] -fn test_vault_usdc_usdt() { - vault_actions::run_test( - "SBR.STC.USDC-USDT", - vec![utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "USDC", - amount: 0.222, - }], - vec![utils::Swap { - protocol: "SBR", - from_token: "USDT", - to_token: "USDC", - amount: 0.0, - }], - ); -} - -#[test] -#[ignore] -fn test_vault_usdc_wust_v1() { - vault_actions::run_test( - "SBR.STC.USDC-WUST_V1", - vec![utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "USDC", - amount: 0.221, - }], - vec![utils::Swap { - protocol: "SBR", - from_token: "WUST_V1", - to_token: "USDC", - amount: 0.0, - }], - ); -} - -#[test] -#[ignore] -fn test_vault_acusd_usdc() { - vault_actions::run_test( - "SBR.STC.ACUSD-USDC", - vec![utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "USDC", - amount: 0.223, - }], - vec![utils::Swap { - protocol: "SBR", - from_token: "ACUSD", - to_token: "USDC", - amount: 0.0, - }], - ); -} - -#[test] -#[ignore] -fn test_vault_wdai_usdc() { - vault_actions::run_test( - "SBR.STC.WDAI-USDC", - vec![utils::Swap { - protocol: "RDM", - from_token: "SOL", - to_token: "USDC", - amount: 0.224, - }], - vec![utils::Swap { - protocol: "SBR", - from_token: "WDAI", - to_token: "USDC", - amount: 0.0, - }], - ); -} diff --git a/farms/farm-client/tests/utils/mod.rs b/farms/farm-client/tests/utils/mod.rs deleted file mode 100644 index e16e50574db..00000000000 --- a/farms/farm-client/tests/utils/mod.rs +++ /dev/null @@ -1,84 +0,0 @@ -//! Common functions for tests - -use { - solana_farm_client::client::FarmClient, - solana_sdk::{pubkey::Pubkey, signature::Keypair, signer::keypair::read_keypair_file}, -}; - -#[derive(Copy, Clone)] -pub struct Swap<'a> { - pub protocol: &'a str, - pub from_token: &'a str, - pub to_token: &'a str, - pub amount: f64, -} - -#[allow(dead_code)] -pub fn get_endpoint_and_keypair() -> (String, Keypair) { - let cli_config = if let Some(ref config_file) = *solana_cli_config::CONFIG_FILE { - solana_cli_config::Config::load(config_file).unwrap() - } else { - solana_cli_config::Config::default() - }; - - ( - cli_config.json_rpc_url.to_string(), - read_keypair_file(&cli_config.keypair_path).unwrap_or_else(|_| { - panic!("Filed to read keypair from \"{}\"", cli_config.keypair_path) - }), - ) -} - -#[allow(dead_code)] -pub fn get_token_or_native_balance(client: &FarmClient, wallet: &Pubkey, token_name: &str) -> f64 { - if token_name != "SOL" { - if let Ok(balance) = client.get_token_account_balance(wallet, token_name) { - balance - } else { - 0.0 - } - } else if let Ok(balance) = client.get_account_balance(wallet) { - balance - } else { - 0.0 - } -} - -#[allow(dead_code)] -pub fn get_balance( - client: &FarmClient, - wallet: &Pubkey, - token_name: &str, - description: &str, -) -> f64 { - let token_balance = get_token_or_native_balance(client, wallet, token_name); - println!( - " {} balance. {}: {}", - description, token_name, token_balance - ); - token_balance -} - -#[allow(dead_code)] -pub fn get_balances( - client: &FarmClient, - wallet: &Pubkey, - token_a: &str, - token_b: &str, - description: &str, -) -> (f64, f64) { - let token_a_balance = get_token_or_native_balance(client, wallet, token_a); - let token_b_balance = get_token_or_native_balance(client, wallet, token_b); - println!( - " {} balances. {}: {}, {}: {}", - description, token_a, token_a_balance, token_b, token_b_balance - ); - (token_a_balance, token_b_balance) -} - -#[allow(dead_code)] -pub fn get_vault_stake_balance(client: &FarmClient, vault_name: &str) -> f64 { - let stake_balance = client.get_vault_stake_balance(vault_name).unwrap(); - println!(" Stake balance. {}", stake_balance); - stake_balance -} diff --git a/farms/farm-client/tests/vault_actions/mod.rs b/farms/farm-client/tests/vault_actions/mod.rs deleted file mode 100644 index f5301e82169..00000000000 --- a/farms/farm-client/tests/vault_actions/mod.rs +++ /dev/null @@ -1,259 +0,0 @@ -use { - crate::{utils, utils::Swap}, - solana_farm_client::client::FarmClient, - solana_sdk::{commitment_config::CommitmentConfig, signature::Keypair, signer::Signer}, - std::{thread, time}, -}; - -const MAX_SOL_BALANCE_TO_USE: f64 = 0.1; -const INITIAL_CRANK_DELAY: u64 = 600; -const CRANK_INTERVAL: u64 = 100; - -pub fn do_swap(client: &FarmClient, keypair: &Keypair, swap: &Swap) { - let amount = if swap.amount == 0.0 { - utils::get_token_or_native_balance(client, &keypair.pubkey(), swap.from_token) - } else if swap.amount < 0.0 { - -1.0 * swap.amount - * utils::get_token_or_native_balance(client, &keypair.pubkey(), swap.from_token) - } else { - swap.amount - }; - if amount < 0.0003 { - return; - } - println!( - ">> Swap {} {} to {}", - amount, swap.from_token, swap.to_token - ); - println!( - " Done: {}", - client - .swap( - keypair, - swap.protocol - .parse() - .expect("Failed to parse protocol argument"), - swap.from_token, - swap.to_token, - amount, - 0.0, - ) - .unwrap() - ); - let _ = utils::get_balances( - client, - &keypair.pubkey(), - swap.from_token, - swap.to_token, - "After swap", - ); -} - -pub fn do_add_liquidity( - client: &FarmClient, - keypair: &Keypair, - vault_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, -) -> f64 { - println!( - ">> Add liquidity to {}: {}, {}", - vault_name, max_token_a_ui_amount, max_token_b_ui_amount - ); - let (token_a_str, token_b_str, vt_token_name) = - client.get_vault_token_names(vault_name).unwrap(); - let vt_balance = utils::get_token_or_native_balance(client, &keypair.pubkey(), &vt_token_name); - println!( - " Done: {}", - client - .add_liquidity_vault( - keypair, - vault_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - ) - .unwrap() - ); - let _ = utils::get_balances( - client, - &keypair.pubkey(), - &token_a_str, - &token_b_str, - "After add liquidity", - ); - let _ = utils::get_balance(client, &keypair.pubkey(), &vt_token_name, "VT"); - let _ = utils::get_vault_stake_balance(client, vault_name); - utils::get_token_or_native_balance(client, &keypair.pubkey(), &vt_token_name) - vt_balance -} - -pub fn do_crank(client: &FarmClient, keypair: &Keypair, vault_name: &str, step: u64) { - println!(">> Crank {} with step {}", vault_name, step); - let initial_info = client.get_vault_info(vault_name).unwrap(); - println!( - " Done: {}", - client.crank_vault(keypair, vault_name, step).unwrap() - ); - let after_crank_info = client.get_vault_info(vault_name).unwrap(); - println!( - " Rewards received: {}, {}", - after_crank_info.tokens_a_rewards - initial_info.tokens_a_rewards, - after_crank_info.tokens_b_rewards - initial_info.tokens_b_rewards - ); - let _ = utils::get_vault_stake_balance(client, vault_name); -} - -pub fn do_remove_liquidity(client: &FarmClient, keypair: &Keypair, vault_name: &str, amount: f64) { - println!(">> Remove liquidity from {}: {}", vault_name, amount); - let (token_a_str, token_b_str, vt_token_name) = - client.get_vault_token_names(vault_name).unwrap(); - println!( - " Done: {}", - client - .remove_liquidity_vault(keypair, vault_name, amount) - .unwrap() - ); - let _ = utils::get_balances( - client, - &keypair.pubkey(), - &token_a_str, - &token_b_str, - "After remove liquidity", - ); - let _ = utils::get_balance(client, &keypair.pubkey(), &vt_token_name, "VT"); - let _ = utils::get_vault_stake_balance(client, vault_name); -} - -pub fn cleanup(client: &FarmClient, keypair: &Keypair, vault_name: &str, cleanup_swaps: Vec) { - println!("\n>>> Clean-up {}...", vault_name); - let wallet = keypair.pubkey(); - let (token_a_str, token_b_str, vt_token_name) = - client.get_vault_token_names(vault_name).unwrap(); - - let vt_token_balance = utils::get_token_or_native_balance(client, &wallet, &vt_token_name); - if vt_token_balance > 0.0 { - do_remove_liquidity(client, keypair, vault_name, vt_token_balance); - } - - for swap in cleanup_swaps { - do_swap(client, keypair, &swap); - } - - if token_a_str != "SOL" { - let token_a_balance = utils::get_token_or_native_balance(client, &wallet, &token_a_str); - if token_a_balance > 0.0 { - do_swap( - client, - keypair, - &Swap { - protocol: "RDM", - from_token: token_a_str.as_str(), - to_token: "SOL", - amount: token_a_balance, - }, - ); - } - } - - if token_b_str != "SOL" { - let token_b_balance = utils::get_token_or_native_balance(client, &wallet, &token_b_str); - if token_b_balance > 0.0 { - do_swap( - client, - keypair, - &Swap { - protocol: "RDM", - from_token: token_b_str.as_str(), - to_token: "SOL", - amount: token_b_balance, - }, - ); - } - } - - let _ = utils::get_vault_stake_balance(client, vault_name); -} - -pub fn run_test(vault_name: &str, swaps: Vec, cleanup_swaps: Vec) { - let (endpoint, keypair) = utils::get_endpoint_and_keypair(); - let client = FarmClient::new_with_commitment(&endpoint, CommitmentConfig::confirmed()); - let wallet = keypair.pubkey(); - - cleanup(&client, &keypair, vault_name, cleanup_swaps.clone()); - - println!("\n>>> Testing {}...", vault_name); - let (token_a_str, token_b_str, _) = client.get_vault_token_names(vault_name).unwrap(); - - let (_, _) = utils::get_balances(&client, &wallet, &token_a_str, &token_b_str, "Initial"); - let _ = utils::get_vault_stake_balance(&client, vault_name); - //initial swaps - for swap in swaps { - do_swap(&client, &keypair, &swap); - } - - let token_a_balance = if token_a_str == "SOL" { - MAX_SOL_BALANCE_TO_USE.min(utils::get_token_or_native_balance( - &client, - &wallet, - &token_a_str, - )) - } else { - utils::get_token_or_native_balance(&client, &wallet, &token_a_str) - }; - let token_b_balance = if token_b_str == "SOL" { - MAX_SOL_BALANCE_TO_USE.min(utils::get_token_or_native_balance( - &client, - &wallet, - &token_b_str, - )) - } else { - utils::get_token_or_native_balance(&client, &wallet, &token_b_str) - }; - - // main tests - let mut vt_received; - if vault_name.starts_with("SBR.") { - if token_a_str == "USDC" { - assert!(token_a_balance > 0.0); - vt_received = do_add_liquidity( - &client, - &keypair, - vault_name, - token_a_balance * 2.0 / 3.0, - 0.0, - ); - } else { - assert!(token_b_balance > 0.0); - vt_received = do_add_liquidity( - &client, - &keypair, - vault_name, - 0.0, - token_b_balance * 2.0 / 3.0, - ); - } - } else { - assert!(token_a_balance > 0.0 && token_b_balance > 0.0); - vt_received = do_add_liquidity(&client, &keypair, vault_name, token_a_balance / 3.0, 0.0); - assert!(vt_received > 0.0); - vt_received += do_add_liquidity(&client, &keypair, vault_name, 0.0, token_b_balance / 3.0); - } - - println!("Waiting {} secs for rewards...", INITIAL_CRANK_DELAY); - thread::sleep(time::Duration::from_secs(INITIAL_CRANK_DELAY)); - do_crank(&client, &keypair, vault_name, 1); - - let cranks = if vault_name.starts_with("SBR.") { 6 } else { 4 }; - for step in 2..cranks { - println!("Waiting {} secs before next crank...", CRANK_INTERVAL); - thread::sleep(time::Duration::from_secs(CRANK_INTERVAL)); - do_crank(&client, &keypair, vault_name, step); - } - - do_remove_liquidity(&client, &keypair, vault_name, vt_received / 2.0); - do_remove_liquidity(&client, &keypair, vault_name, 0.0); - - cleanup(&client, &keypair, vault_name, cleanup_swaps); - - let (_, _) = utils::get_balances(&client, &wallet, &token_a_str, &token_b_str, "Final"); - let _ = utils::get_vault_stake_balance(&client, vault_name); -} diff --git a/farms/farm-ctrl/.gitignore b/farms/farm-ctrl/.gitignore deleted file mode 100644 index 96ef6c0b944..00000000000 --- a/farms/farm-ctrl/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -Cargo.lock diff --git a/farms/farm-ctrl/Cargo.toml b/farms/farm-ctrl/Cargo.toml deleted file mode 100644 index ab5425b359d..00000000000 --- a/farms/farm-ctrl/Cargo.toml +++ /dev/null @@ -1,35 +0,0 @@ -[package] -name = "solana-farm-ctrl" -version = "1.1.3" -description = "Solana Farm Control" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana-program-library/farms" -license = "Apache-2.0" -homepage = "https://solana.com/" -edition = "2021" - -[features] -debug = [] - -[dependencies] -log = "0.4.16" -clap = "2.34.0" -serde = "1.0.136" -serde_derive = "1.0.136" -serde_json = "1.0.79" -serde_yaml = "0.8.23" -solana-client = "1.9.18" -solana-logger = "1.9.18" -solana-version = "1.9.18" -solana-clap-utils = "1.9.18" -solana-sdk = "1.9.18" -solana-farm-sdk = "1.1.3" -solana-farm-client = "1.1.3" -solana-account-decoder = "1.9.18" -spl-associated-token-account = { version = "=1.0.3", features = ["no-entrypoint"] } -spl-token = { version = "3.2.0", features = ["no-entrypoint"] } -spl-governance = { version = "2.1.4", features = ["no-entrypoint"] } -solana-cli-config = "1.9.18" -quarry-mine = { version = "5.0.2", features = ["no-entrypoint"] } -url = "2.2.2" -num_enum = "0.5.7" diff --git a/farms/farm-ctrl/README.md b/farms/farm-ctrl/README.md deleted file mode 120000 index ccd27901fd5..00000000000 --- a/farms/farm-ctrl/README.md +++ /dev/null @@ -1 +0,0 @@ -../docs/crate.md \ No newline at end of file diff --git a/farms/farm-ctrl/metadata/farms/orca/farms.json b/farms/farm-ctrl/metadata/farms/orca/farms.json deleted file mode 100644 index 90ec0f10d71..00000000000 --- a/farms/farm-ctrl/metadata/farms/orca/farms.json +++ /dev/null @@ -1,1743 +0,0 @@ -{ -"name": "Orca Farms", -"farms": - [ - { - "name": "SOL_USDC_AQ", - "address": "85HrPbJtrN82aeB74WTwoFxcNgmf5aDNP2ENngbDpd5G", - "farmTokenMint": "FFdjrSvNALfdgxANNpt3x85WpeVMdQSH5SEP2poM8fcK", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "APDFRM3HMr8CAGXwKHiu2f5ePSpaiEJhaURwhsRrUUt9", - "baseTokenDecimals": 6 - }, - { - "name": "SOL_USDT_AQ", - "address": "4RRRJkscV2DmwJUxTQgRdYock75GfwYJn7LTxy9rGTmY", - "farmTokenMint": "71vZ7Jvu8fTyFzpX399dmoSovoz24rVbipLrRn2wBNzW", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "FZthQCuYHhcfiDma7QrX7buDHwrZEd7vL8SjS6LQa3Tx", - "baseTokenDecimals": 6 - }, - { - "name": "ETH_SOL_AQ", - "address": "3ARgavt1NhqLmJWj3wAJy6XBarG6pJbEKRv1wzzRbbaN", - "farmTokenMint": "CGFTRh4jKLPbS9r4hZtbDfaRuC7qcA8rZpbLnVTzJBer", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "71FymgN2ZUf7VvVTLE8jYEnjP3jSK1Frp2XT1nHs8Hob", - "baseTokenDecimals": 6 - }, - { - "name": "ETH_USDC_AQ", - "address": "FpezTR76RRjgpBb9HhR6ap8BgQfkHyNMQSqJDcoXpjAb", - "farmTokenMint": "HDP2AYFmvLz6sWpoSuNS62JjvW4HjMKp7doXucqpWN56", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "3e1W6Aqcbuk2DfHUwRiRcyzpyYRRjg6yhZZcyEARydUX", - "baseTokenDecimals": 6 - }, - { - "name": "RAY_SOL_AQ", - "address": "B1aByG1fU5yUgQT2EtJrp96SC4tJhnipzdXqHx2CXRgj", - "farmTokenMint": "AUkn5f4N4TqPA5BiWirTDHWnG3SePfmeDpDqrFmhSgKb", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "5kimD5W6yJpHRHCyPtnEyDsQRdiiJKivu5AqN3si82Jc", - "baseTokenDecimals": 6 - }, - { - "name": "ROPE_SOL_AQ", - "address": "NFsHa28zxuLnncHme7iLx8TXWV8ypyxPvEPaQh29zDh", - "farmTokenMint": "xpPyQwQ1HXHyEpvFGyTQRLY6rmj6jtAdEgLMV5uoz4m", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "ADrvfPBsRcJfGsN6Bs385zYddH52nuM5FA8UaAkX9o2V", - "baseTokenDecimals": 6 - }, - { - "name": "STEP_SOL_AQ", - "address": "DGtiR1LWNPGV9A5byh7EjAoh9NC2cW5YDcmxCpUJosD2", - "farmTokenMint": "GwrBA1F8rGummDCDd8NY9Eu1cLNuJqbT8WaGxgWpFwGL", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "8nTzqDXHriG2CXKbybeuEh1EqDQMtrbYMFWcP7AkiDaP", - "baseTokenDecimals": 6 - }, - { - "name": "SRM_SOL_AQ", - "address": "5CQVdPpaW95X1atyfqunZf7eBE1rhQBXMfgJ1wRVF1p1", - "farmTokenMint": "D659zwnbeTgquChbaWC3KDHrkYoqMuz1doGLHTFaqTtD", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "9tf8rBSEQYG7AqL896fN2nZi1iYPqpWaLEdpbeQaC1Vy", - "baseTokenDecimals": 6 - }, - { - "name": "FTT_SOL_AQ", - "address": "GzZE2CEemaTGNtRSYs9sArAJFuJi5kwsPJFyz5puYhsj", - "farmTokenMint": "9r9BcPwCon96P5Y6JSdRAog7Uknz9p9GrnuHm4VzuB9k", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "EsYaDKJCmcJtJHFuJYwQZwqohvVMCrFzcg8yo3i328No", - "baseTokenDecimals": 6 - }, - { - "name": "COPE_SOL_AQ", - "address": "CXYEVaqtDs4R9Bpeu4xYf8KT8S6nYis6VWkDEh9Mu1FS", - "farmTokenMint": "7CT19h7n2YBKiCFCaxXqMM79jNM4cmUvjXhNMjJNRYa", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "CzieDbGRdN1QGaGDNpSqzEA18bi881ccvkkGZi51pe1k", - "baseTokenDecimals": 6 - }, - { - "name": "OXY_SOL_AQ", - "address": "ALmRst1DksKXVfY64KXq7pJUUG5PP56kwY18ijVDGAsz", - "farmTokenMint": "G48RkwsNYd3A4rBfuQhCswr9YUE63fFmZGyhgH95dq3S", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "7tYCdLN84EnTMkxM7HNamWJx7F4xgKe9KiiWvLyWjbgT", - "baseTokenDecimals": 6 - }, - { - "name": "BTC_SOL_AQ", - "address": "EeG5AAnFS56AveUrKexzivQeUdWhm6zYq6ubn6fLMCQa", - "farmTokenMint": "GxmjQZvgwNCh3QSRNB8CPED81hzySem62PDDuMp4B379", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "Acxs19v6eUMTEfdvkvWkRB4bwFCHm3XV9jABCy7c1mXe", - "baseTokenDecimals": 6 - }, - { - "name": "MER_SOL_AQ", - "address": "8gJggSfM35JpfvXmEsuJoHPLB8D6br15MEWEWdQF81d6", - "farmTokenMint": "CrKVRnH6iGbFXxEnXMn3Emwv3Fe7VwxEqpA8zNbwsgkH", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "HiwRobjfHZ4zsPtqCC4oBS24pSmy4t8GGkXRbQj4yU6L", - "baseTokenDecimals": 6 - }, - { - "name": "FIDA_SOL_AQ", - "address": "4X3U1tpfiwQ5zPPd4oQSPcu3UK7nMSUWyAXxCmcSA6qP", - "farmTokenMint": "4geGcEfgVjzJGZAaT8iTicPm1XLDPjdSpVhtA99sZ7jX", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "EYsNdtyu4gGTaGz8N5m5iQ3G1N6rDyMbR72B3CqbWW4W", - "baseTokenDecimals": 6 - }, - { - "name": "MAPS_SOL_AQ", - "address": "Gobr8FhZDtn8yxkFQDND3KmfuwZseWEuyZ3xpD56hk1i", - "farmTokenMint": "7Dy84zJNHzEM9335BrtFjCuunt2VgxJ7KBT6PJarxKMq", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "99pfC8fWymXgbq3CvrExhx3UxQDC1fMWEWLbNT83F45e", - "baseTokenDecimals": 6 - }, - { - "name": "USDC_USDT_AQ", - "address": "5psKJrxWnPmoAbCxk3An2CGh7wHAX2cWddf5vZuYbbVw", - "farmTokenMint": "GjpXgKwn4VW4J2pZdS3dovM58hiXWLJtopTfqG83zY2f", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "H2uzgruPvonVpCRhwwdukcpXK8TG17swFNzYFr2rtPxy", - "baseTokenDecimals": 6 - }, - { - "name": "ORCA_SOL_AQ", - "address": "F6pi7SyXWx56fP96mYQ4Yfh4yZ7oGNtDjwSYHT5Mz7Ld", - "farmTokenMint": "B5waaKnsmtqFawPspUwcuy1cRjAC7u2LrHSwxPSxK4sZ", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "2uVjAuRXavpM6h1scGQaxqb6HVaNRn6T2X7HHXTabz25", - "baseTokenDecimals": 6 - }, - { - "name": "ORCA_USDC_AQ", - "address": "9S1BsxbDNQXQccjFamVEGgxiYQHTeudvhEYwFr4oWeaf", - "farmTokenMint": "Gc7W5U66iuHQcC1cQyeX9hxkPF2QUVJPTf1NWbW8fNrt", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "n8Mpu28RjeYD7oUX3LG1tPxzhRZh3YYLRSHcHRdS3Zx", - "baseTokenDecimals": 6 - }, - { - "name": "KIN_SOL_AQ", - "address": "9XTA3t3X8KaeLgkv7XuDWATo4oDwBnTZqjnSPcE5ijYK", - "farmTokenMint": "7Ho3ht7krdFELBcPAsGXFfQMyG4PUvYSfpz4aNBRP3Ek", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "HEvnD66WcBfTajS9adUYnGRBMDehFtLySiFHSD6kEBWs", - "baseTokenDecimals": 6 - }, - { - "name": "SAMO_SOL_AQ", - "address": "98EDd1L47pdW1F7ne82dyFXpfhVdEcrCqUF1dYrWLFZi", - "farmTokenMint": "CNf8gZtLahBWxKe3YwsqywLHMTewGqvq6pJ5ecg3cTYU", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "D6N9j8F2DhtzDtrdpT74y3u2YmYAzcggiLc3nTjqux9M", - "baseTokenDecimals": 6 - }, - { - "name": "LIQ_USDC_AQ", - "address": "z2WHNcBJTZqbK5wCuBPtswEq2614T6si1cJmog7vFAL", - "farmTokenMint": "57vGdcMZLnbNr4TZ4hgrpGJZGR9vTPhu8L9bNKDrqxKT", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "3PD9SZFwXKkXr4akLf4ofo37ZUMycwML89R2P3qxcbZG", - "baseTokenDecimals": 6 - }, - { - "name": "SNY_USDC_AQ", - "address": "7qAQZxYQRcmHmz3Wi9NeieujwLSd3N41M4dJipgSCNsB", - "farmTokenMint": "6Qw5Gzf1TkM3YRe7Dh6yMVMo2wnJxRiCUBP8abTTn9Yg", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "AZpo4BJHHRetF96v6SGinFZBMXM4yWMo4RA8C4PriDLk", - "baseTokenDecimals": 6 - }, - { - "name": "mSOL_USDC_AQ", - "address": "EvtMzreDMq1U8ytV5fEmfoWNfPhrjZ87za835GuRvZCc", - "farmTokenMint": "5r3vDsNTGXXb9cGQfqyNuYD2bjhRPymGJBfDmKosR9Ev", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "8PSfyiTVwPb6Rr2iZ8F3kNpbg65BCfJM9v8LfB916r44", - "baseTokenDecimals": 6 - }, - { - "name": "SLRS_USDC_AQ", - "address": "5XXw91d4HoLjqhUhXmUcdkCDtQyXvQkLJMUcYJkKn5Dx", - "farmTokenMint": "66xCxkffQZKBZLiHV3PDcfR8ANJTfnDRxPCaBdv4wxB7", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "AtB4nUmdyQfuWWJ9xAHw9xyVnJFfSjSuVWkiYan8y86w", - "baseTokenDecimals": 6 - }, - { - "name": "PORT_USDC_AQ", - "address": "FpEb4eEqhnPBAA2RNvsSe8baCoev4mSNQjxKPGvx5Gjv", - "farmTokenMint": "4CGxvZdwiZgVMLXiTdJHTkJRUTpTSJCtmtCRbSkAxerE", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "F8gPSpwVHj8FdAJAYULDuZBxFEJut87hUbARYYx3471w", - "baseTokenDecimals": 6 - }, - { - "name": "SBR_USDC_AQ", - "address": "EWRNKpLc4Y8r6Aur9mo8GtBYatqfoML9A7bfEmDv2JD4", - "farmTokenMint": "Cum6sRPGpWYQHZapekDtMhbZ1BQ2QkYv9PAwQjypxMVo", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "CS7fA5n4c2D82dUoHrYzS3gAqgqaoVSfgsr18kitp2xo", - "baseTokenDecimals": 6 - }, - { - "name": "scnSOL_USDC_AQ", - "address": "5MzBKRo6YqK1BKBz67sXd42jrb6gYzBuX6R5F8ywC33e", - "farmTokenMint": "7YFfqZGTxkj3Zeq3Et23kMznCaEYZ1WBZDt6CVrxwfqd", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "Dkr8B675PGnNwEr9vTKXznjjHke5454EQdz3iaSbparB", - "baseTokenDecimals": 6 - }, - { - "name": "SOCN_USDC_AQ", - "address": "5MzBKRo6YqK1BKBz67sXd42jrb6gYzBuX6R5F8ywC33e", - "farmTokenMint": "7YFfqZGTxkj3Zeq3Et23kMznCaEYZ1WBZDt6CVrxwfqd", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "Dkr8B675PGnNwEr9vTKXznjjHke5454EQdz3iaSbparB", - "baseTokenDecimals": 6 - }, - { - "name": "pSOL_USDC_AQ", - "address": "4TK569s8SLgzmEcihyhrH8GmqFsufjZqsvHs8zrPEZYP", - "farmTokenMint": "8kWk6CuCAfaxhWQZvQva6qkB1DkWNHq9LRKKN6n9joUG", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "C2YzN6MymD5HM2kPaH7bzcbqciyjfmpqyVaR3KA5V6z1", - "baseTokenDecimals": 6 - }, - { - "name": "mSOL_SOL_AQ", - "address": "JADWjBW1Xs8WhW8kj3GTCRQn3LR4gwvbFTEMwv9ZNxQh", - "farmTokenMint": "3RTGL7gPF4V1ns1AeGFApT7cBEGVDfmJ77DqQi9AC6uG", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "29cdoMgu6MS2VXpcMo1sqRdWEzdUR9tjvoh8fcK8Z87R", - "baseTokenDecimals": 6 - }, - { - "name": "ORCA_PAI_AQ", - "address": "8KBSXu7zFjvbVXiwf1opGNBx3evVwdpaYHWR3uc4HVR6", - "farmTokenMint": "4aEi4A91hRbERJVDYxRWbbSrBrsxoM1Hm33KRoRzWMht", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "C7TH2jEJJaxVwwuvkbcDGfHUiZvEkkeYjyAcdTMi5ujb", - "baseTokenDecimals": 6 - }, - { - "name": "ORCA_mSOL_AQ", - "address": "7EVKT4iqfjiyzeVrafs23JrfhSoLd6XTanVuENNvisq7", - "farmTokenMint": "3Duk5b6fLztPmS4ryV48FM1Q9WXUSMwz9jehAT4UtqpE", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "CVapmQn7HaU1yMDW3q6oUV4hx6XoYv54T4zfGXkuJqkA", - "baseTokenDecimals": 6 - }, - { - "name": "scnSOL_SOL_AQ", - "address": "5cE7V9D13k1P1qC23g5vcQEMsvrDzL5yFHhiesVUyn93", - "farmTokenMint": "CNqmEKGjZUUARVFHcz4w9CvX5pR8Ae2c6imHDNqsbxgj", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "APNpzQvR91v1THbsAyG3HHrUEwvexWYeNCFLQuVnxgMc", - "baseTokenDecimals": 6 - }, - { - "name": "SOCN_SOL_AQ", - "address": "5cE7V9D13k1P1qC23g5vcQEMsvrDzL5yFHhiesVUyn93", - "farmTokenMint": "CNqmEKGjZUUARVFHcz4w9CvX5pR8Ae2c6imHDNqsbxgj", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "APNpzQvR91v1THbsAyG3HHrUEwvexWYeNCFLQuVnxgMc", - "baseTokenDecimals": 6 - }, - { - "name": "ATLAS_USDC_AQ", - "address": "G92aJeZBCFiECwrKSQsbobfykh6cNLCf5Pd3zkiLjGLe", - "farmTokenMint": "HFmY1ggCsCky1zJ1sfdkNR4zb3u5n38YNRdf4vsGu17t", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "FZ8x1LCRSPDeHBDoAc3Gc6Y7ETCynuHEr5q5YWV7uRCJ", - "baseTokenDecimals": 6 - }, - { - "name": "POLIS_USDC_AQ", - "address": "5NkDw3LcFscf5WSxUiquNregP6RaP79Y2pN1jyUYepzc", - "farmTokenMint": "63JUKLnCAuNMPSPioEgbjjzp9Qk8qSEEM8eZqEtPqfLU", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "GteBdo9sqE7T41G8AJsaG9WHW48uXBwsLLznmu2TBdgy", - "baseTokenDecimals": 6 - }, - { - "name": "BOP_USDC_AQ", - "address": "4bmbPAxrf5NLAD6A5fkhKhmuffdGScpu9Ei39YEaPATQ", - "farmTokenMint": "A7vvbqENJj8kED3ABjphe8TvwpasQYtoWGKpjpLArMxa", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "2gXDJZ7XAtQEtf4PRSQZKoq1WMuu1H44tQanbMA3YVpu", - "baseTokenDecimals": 6 - }, - { - "name": "SAMO_USDC_AQ", - "address": "F5ZvDWRVpQP5A17RFogL4dE7gZ2Uda7ZqKUy3DWJDEFx", - "farmTokenMint": "9voVuTq1S9bFZkF2Jo44HoVG63w2xDRT8eBzB23YbQud", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "6VK1ksrmYGMBWUUZfygGF8tHRGpNxQEWv8pfvzQHdyyc", - "baseTokenDecimals": 6 - }, - { - "name": "NINJA_SOL_AQ", - "address": "B8Q8e1hdCw6fhnSKmsMCrsDbvSNLZyzHjnPpwZKBkcSB", - "farmTokenMint": "7YyhptkxY81HPzFVfyCzA5UXxWdsNRD41ofLva3TuSpd", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "4X1oYoFWYtLebk51zuh889r1WFLe8Z9qWApj87hQMfML", - "baseTokenDecimals": 6 - }, - { - "name": "SLIM_USDC_AQ", - "address": "3muHEhQLmt7jmaicMHqe6LqXrrfFtqEuAfBog2fAXhRm", - "farmTokenMint": "3K7aZhtwWJ2JS6GnbbgeDVnxd1q2hwhqasmgRsAMZ4yC", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "BVWwyiHVHZQMPHsiW7dZH7bnBVKmbxdeEjWqVRciHCyo", - "baseTokenDecimals": 6 - }, - { - "name": "wHAPI_USDC_AQ", - "address": "r2MxTnFdnP7ECMxH7F4mcg1p3CowwhPmDmYoZ1syKZh", - "farmTokenMint": "Bfoi3RNnfdP5VeRGqvTA8MRN9ePGJoZgeKfe8WeBHUxE", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "ELfBngAgvLEHVBuJQhhE7AW6eqLX7id2sfrBngVNVAUW", - "baseTokenDecimals": 6 - }, - { - "name": "COPE_USDC_AQ", - "address": "xigyMM8txxzpvjRw3Z1tX9euUshtqeHucW6K3f81KNQ", - "farmTokenMint": "9SDpBrfqNxjXcCzpKWM6yUKdfky975VJBD6xcu5cKf5s", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "HsauTv9s52Zv12eaDuSp6y7BEm4e4BHEyAsbdjyyWzPK", - "baseTokenDecimals": 6 - }, - { - "name": "SUNNY_USDC_AQ", - "address": "Nw3caGfeqM8xQZ45iAf5zWmPMQux5wMWMjxsKEfnNk4", - "farmTokenMint": "9HPn1oREyNA7CEK7B1xwmBmVH6qtQaSfLBXc1JyRsdUE", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "GHuoeq9UnFBsBhMwH43eL3RWX5XVXbSRYJymmyMYpT7n", - "baseTokenDecimals": 6 - }, - { - "name": "GRAPE_USDC_AQ", - "address": "6eeK7PHkUXJ9t2qgdrHfbZfmU5S7zWZwpDw6i46Rf1jU", - "farmTokenMint": "97q89hnoKwqcynvwXcj83YqfqUBuCm4A8f2zHeV6bfZg", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "EorFh8siFyLF1QTZ7cCXQaPGqyo7eb4SAgKtRH8Jcxjd", - "baseTokenDecimals": 6 - }, - { - "name": "ABR_USDC_AQ", - "address": "PyzV3qSzbj98ArVpASj2LQg6zCq6zfAixqUtYDafnRU", - "farmTokenMint": "5uR5STASUmoGVHzqMeut98t26TfVkQqWU9f9dsv3NfJ6", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "GMzPbaCuQmeMUm1opH3oSCgKUjVgJUW14myq99RVPGX5", - "baseTokenDecimals": 6 - }, - { - "name": "KURO_USDC_AQ", - "address": "6bHkoSxnK3aKW3PyG34dUz1naD6T3Pc7143s41nSuuzN", - "farmTokenMint": "6PGoaQdL9e463hdaFxHXsuPcjCHRK32CQ9PFKxvM7XY2", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "DRknxb4ZFxXUTG6UJ5HupNHG1SmvBSCPzsZ1o9gAhyBi", - "baseTokenDecimals": 6 - }, - { - "name": "MEDIA_USDC_AQ", - "address": "jCGam3ptTrFKhCwBGYUcqtrvt8pY4uWXaPoqC9E7uXB", - "farmTokenMint": "3pMYToENTB7jKrJiUPq19FCZCWE35Ph7bkRRMN6kxDXK", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "2toFgkQDoPrTJYGDEVoCasPXuL9uQnjvXJaDwa9LHyTx", - "baseTokenDecimals": 6 - }, - { - "name": "TULIP_USDC_AQ", - "address": "AEemiZ28JTnz3xmj6LSfXruK1et317ZAGY5KCrKdXNCX", - "farmTokenMint": "2KYUwdRbVtaMUgHp1a6NuTomyCb33FxoZ4fkeVdwjaJA", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "4SBx8GXu8HhcVHWydQv1vsDdZs3G93XSL9CtMBny6hS5", - "baseTokenDecimals": 6 - }, - { - "name": "MNGO_USDC_AQ", - "address": "2LM1Y428kPtLAsxcdxv2iKWaPxobt9poD2DAjeGpN6TC", - "farmTokenMint": "CxhcLZtbhfkwjAZ956SEkGxkAvMVQH3hfKTjKpgTV9Q5", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "H9yC7jDng974WwcU4kTGs7BKf7nBNswpdsP5bzbdXjib", - "baseTokenDecimals": 6 - }, - { - "name": "stSOL_wstETH_AQ", - "address": "6eW2skHuzMxxPZjzE7x5fxtn3ZZ1Ak2SawrMH9T5KANp", - "farmTokenMint": "3kT3oYuS1rCfhmqfgy6EKcbZdaJimaVEjoy25QiuEaoj", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "Eswigpwm3xsipkTqahGi2PEJsJcULQBwZgxhQpr6yBEa", - "baseTokenDecimals": 6 - }, - { - "name": "SYP_USDC_AQ", - "address": "7GDHcUdLhHxCHeQccpbJr3eNGzQvnoMdLBzkVNYvQgkh", - "farmTokenMint": "Ds4VGZhZzS2PMFzhzKeC3mwcQjdiCG21R76fTVbsSJyJ", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "qJxKN9BhxbYvRNbjfK2uAVWboto6sonj8XC1ZEW5XTB", - "baseTokenDecimals": 6 - }, - { - "name": "stSOL_wLDO_AQ", - "address": "DMECkFUnVp1esox6Yyyfc7vJeN7spUHd5JypAWqEqCRC", - "farmTokenMint": "DQsbebdNDy8yQrwLTpieckhzi7Ewx9LoCPVf7G9KvY2U", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "74B9aMS7SA832xKngt5VLKmWAP3pa3qkUzWncTmQSsGF", - "baseTokenDecimals": 6 - }, - { - "name": "whETH_SOL_AQ", - "address": "BerS3SE5G6FqZER7L7G3BhUJBrZ7BpizmuQRH9LMEYQw", - "farmTokenMint": "FkHQBBZGh5GS4GcXpcVksKYUUkLTNn6Yk1PCMxucR2AK", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "7aYnrdmdCRodDy2Czn6keUquUhjF1jPEmfwZPh488z8U", - "baseTokenDecimals": 6 - }, - { - "name": "whETH_USDC_AQ", - "address": "GdQyNtN9rQWzpcm7mQMNBiXyeKRjjQoobh2waVQq5QyP", - "farmTokenMint": "B11Xp26xU2gzjToJEuGswvr6Jtidfh4GRUyCWzWMNdQZ", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "7NPtjjAP7vhp4t5NCLyY4DY5rurvyc8cgZ2a2rYabRia", - "baseTokenDecimals": 6 - }, - { - "name": "MNDE_mSOL_AQ", - "address": "5wr7m4YrJB38vuz3xyLqvq2DwLCcDkEDH5X97chKpH4T", - "farmTokenMint": "2wPsMuzhEsC6GhV3qtFpmJF6atEgLGbnmQ8U43Y6fPxZ", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "5PHS5w6hQwFNnLz1jJFe7TVTxSQ98cDYC3akmiAoFMXs", - "baseTokenDecimals": 6 - }, - { - "name": "WAG_USDC_AQ", - "address": "4GWmnvMg7EGQZ6LeQtK6rbJrtTTVsQHj2ivwm4vm8mnR", - "farmTokenMint": "8Wu5sJpERA1J5iWcT8aMpt9cTAfKDLPbLpGjNsJoPgLc", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "Df6XNHMF3uRVZnz7LCEGiZVax6rXgz76owtVkBHEjSb6", - "baseTokenDecimals": 6 - }, - { - "name": "mSOL_USDT_AQ", - "address": "HULY26UFdfVkc2STTt1KREd57BwFV2md1tqdk253QyiK", - "farmTokenMint": "Afvh7TWfcT1E9eEEWJk17fPjnqk36hreTJJK5g3s4fm8", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "9cMWe4UYRPGAUUsTkjShJWVM7bk8DUBgxtwwH8asFJoV", - "baseTokenDecimals": 6 - }, - { - "name": "mSOL_whETH_AQ", - "address": "D4Pmc82b9W1UDAqYNNNMGG7UYxBaZckf97AYExGbUK95", - "farmTokenMint": "58nifjPjF3CutGz2xMxvAMk7R9YgbVEc8Cstj4rCcs8j", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "5qoTq3qC4U7vFxo3iCzbXcaD1UEmDeCD63Dsuoct71oV", - "baseTokenDecimals": 6 - }, - { - "name": "BTC_mSOL_AQ", - "address": "GBrpFtiTabs14mc4Hi1RX9YiQY7res6JxrVfMTADfcQV", - "farmTokenMint": "DzpLz78wuwyFsQToin8iDv6YK6aBEymRqQq82swiFh7r", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "8nKJ4z9FSw6wrVZKASqBiS9DS1CiNsRnqwCCKVQjqdkB", - "baseTokenDecimals": 6 - }, - { - "name": "IVN_SOL_AQ", - "address": "FwzqbJZQiL3qzMx88r2o3CNKFxztuW3JC45YYk6ghMLR", - "farmTokenMint": "HqajzzbGMST3yCCVBJuXvNVsWkY2DXqiBz9cTRmmyBMy", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "DfgCnzaiTXfPkAH1C1Z441b5MzjjTCEh134ioxqRZxYf", - "baseTokenDecimals": 6 - }, - { - "name": "LARIX_USDC_AQ", - "address": "HeAQxAGBQdGURFFcLpdPagQ2vb66kXFTVxDfTjme8eGo", - "farmTokenMint": "DNAGfa7tK8csprRQmiDUwDaFfhw6ueHhVFHTCgTJ8HGs", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "8sfThep3io4gvcGeuoAg1Rs8GDwKJjtcdAFHqQSSNAVE", - "baseTokenDecimals": 6 - }, - { - "name": "PRT_USDC_AQ", - "address": "9dCsoLdfkpYw1s7TMNE1HZPNmVSNDZrUkUHfxn2p8675", - "farmTokenMint": "2cYMt26745oFc7PadaQn8Vv3xFUxWBfbip2NyJeVG35F", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "6jCERp5hKj37PCXP3VTjCDJeoPuSpnMDMz5A6jWQv3yS", - "baseTokenDecimals": 6 - }, - { - "name": "JET_USDC_AQ", - "address": "BKdPQziyuKmXwZeVuo8Uj7usfUYpwSfnGBDbG96y266V", - "farmTokenMint": "4DjiLEKADWjYmiY9gzFnu5xews5oCTMRByWHWEzDa3bj", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "GBijunwxa4Ni3JmYC6q6zgaVhSUJU6hVX5qTyJDRpNTc", - "baseTokenDecimals": 6 - }, - { - "name": "stSOL_USDC_AQ", - "address": "2P7FGV8XNXUkEAG6q5LbhfoBFkHJ7PDAjYqmAbwnVHBF", - "farmTokenMint": "3u2dNfGuU6C3vmSg5EvLPUpX57b3niqhWBV5Gc3WDEf5", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "GtQ1NT7R5aaTiST7K6ZWdMhwDdFxsSFvVFhBo8vyHGAq", - "baseTokenDecimals": 6 - }, - { - "name": "wstETH_USDC_AQ", - "address": "2FAzkAgm8EpE7WpWUsEcNyj4kcVeCX2L8SR1BicGWEx9", - "farmTokenMint": "ojpWEdNYa5nGviUc8k8M2XLjHuaCL2EgHFdvTtdkXA1", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "5a6Y1ephcbKSoyLMQyD1JWbtqawCy8p2FtRL9v3zhaG5", - "baseTokenDecimals": 6 - }, - { - "name": "AURY_USDC_AQ", - "address": "FvkyNXLizY4FCNkgbGpr1WA3z4A8iTRU4rPnnNJC3q2V", - "farmTokenMint": "7s7Veo1P8ZRy6z5MCvoAmg2kPFcQnq2Grt6yewWS8LbQ", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "6mJqqT5TMgveDvxzBt3hrjGkPV5VAj7tacxFCT3GebXh", - "baseTokenDecimals": 6 - }, - { - "name": "AVAX_USDC_AQ", - "address": "GkmPgsKU9uYaZtKfzjWeJjBSvX8mkK8gNqoWMYBdcvUx", - "farmTokenMint": "5mZydNG1fBPTXzgp9SoS7Jny6EmSzBPTPrFbB1ttGnvx", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "Hmfrtmo93DpSDmVNLQKcBS5D1ia5JatiRSok9ososubz", - "baseTokenDecimals": 6 - }, - { - "name": "FTT_USDC_AQ", - "address": "2FtSDVRmYq4x6NeTidpZVuLzgN2APzr3zHxpHx8zdgbr", - "farmTokenMint": "2AAzmhZ9Kh9mFcQtHJVTafu69tc5GCGpi6CTgafYta1S", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "FwCombynV2fTVizxPCNA2oZKoWXLZgdJThjE4Xv9sjxc", - "baseTokenDecimals": 6 - }, - { - "name": "RAY_USDC_AQ", - "address": "GCcVYpBCPcPjb11LeeoVhLNJQzS5GXEEd6Dmo5eejBTx", - "farmTokenMint": "9MaXcCERB4DzedPNSBwyHM2P6Yo6jCFLjnatuWCtR3WF", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "4cXw2MYj94TFBXLL73fEpMCr8DPrW68JvrV8mzWgktbD", - "baseTokenDecimals": 6 - }, - { - "name": "SLND_USDC_AQ", - "address": "5NrUSiG134QLY4JkmX82n4hdZQnmqsWMrBapQwfAtpeu", - "farmTokenMint": "GdySZb2nbeEjCLBg65veC5kzfMCfCWgtgqwH9YWDtDXr", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "F59gkD7NnsdJbFKrRZsiBC8PAooN4c56T8QmahfW1iXN", - "baseTokenDecimals": 6 - }, - { - "name": "GOFX_USDC_AQ", - "address": "GmyMx4JtRrkjmxNn4WQCmVNuLfwRjkAmCfMv2AXag5se", - "farmTokenMint": "B95rdqSY4dqPwmt295XwBZZqZJYLmqDNXU6NvBpT4ep4", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "7vnps4VE5RTGAr5fmPZu7fSrk2VnM4Up838grZfqmxqE", - "baseTokenDecimals": 6 - }, - { - "name": "WOOF_USDC_AQ", - "address": "5K7WdUTG2yZjULeNUUiH3eoWhY9YYAnpoWFGiwVj3q2V", - "farmTokenMint": "4HaQXDz9gdLgKUjvNVtnLyNZoWNYKjh3XxH1TpLgiwmi", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "9EjcYfHcG8f1mccpHyaAwpoxaUPiheC6KgLQjyD9aTb6", - "baseTokenDecimals": 6 - }, - { - "name": "SDOGE_USDC_AQ", - "address": "672wPyV8sJdqBfyay6MccLxsCj1sqQyd5WaPXkTbeB8N", - "farmTokenMint": "4kXYyZAMBdvgDaBKUGvRWJnHw9af7sCUPvpQ68PEdP8b", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "CHTKUJGYRtBDqnxCFjxe5KEkZgxV98udbhuYYyzGxup5", - "baseTokenDecimals": 6 - }, - { - "name": "CATO_USDC_AQ", - "address": "4EfikjxutL59CXMBYffhSXdPEw28T963idHiwz2qpodQ", - "farmTokenMint": "BHtZnTBMeY4EBEW5egGnuK5bdW12v6Dod6wFav79AyYx", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "55r9txzQtmjTykmTXmBYZCVMg5z9squB8b5cSw2AhxA4", - "baseTokenDecimals": 6 - }, - { - "name": "OOGI_USDC_AQ", - "address": "CzWsHjE7azpbksPhHxdkvH5gfpBAx4FqohwFnkHgfVpr", - "farmTokenMint": "FiwSk36yi1DNWcuQUeNipAc1VKxa9Wv9AR2xFvyKUxAE", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "DSiHyHDn96bUQSZtizyCRLcQzrwohZeMpVu8rYJN1HzG", - "baseTokenDecimals": 6 - }, - { - "name": "SONAR_USDC_AQ", - "address": "2SxKGe1PEKWQC6m5Q1jUnXJuZBVXyUC37ffCPop38iiA", - "farmTokenMint": "GWmwwMGYBG4NqYdnsYrudzBnbgDC49MkBxdzhfLA9kVY", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "5MvQHx8eftU39JTucFsT315JFnQASuDQg3FqxTw7xcvN", - "baseTokenDecimals": 6 - }, - { - "name": "APT_USDC_AQ", - "address": "3YZ5GYL625vWibn7d8hMdrMBawy9HGUyeTe4AoXoME1Q", - "farmTokenMint": "Dx7DYSuaBufhXyQG7155ePkLmHyn6w7WeKKtQB9zscZV", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "HNrYngS1eoqkjWro9D3Y5Z9sWBDzPNK2tX4rfV2Up177", - "baseTokenDecimals": 6 - }, - { - "name": "DFL_USDC_AQ", - "address": "GaKnyw7sYU6raJpZGjFER1eXZ9zHfqih5fAj1T5xxP6J", - "farmTokenMint": "C8jJeUM9s7R7gTw1ybgTW4LPkgrYtogstD6MtBjroGLB", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "AWrtTWG4Zgxw8D92bb3L3sQtGLD3zDztMPWsXSph8iBP", - "baseTokenDecimals": 6 - }, - { - "name": "DFL_SOL_AQ", - "address": "HTEe4r3YDRqDbA2dwQNMnMBAToV7rHvpyMBe6EjZmXyz", - "farmTokenMint": "E3omuGbZSksAdbiyvtpdfGsUGhptA26Enwe5Y5jJKnbK", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "9Y1vPaAsMz8X65DebMMnmBjbMo8i4jh4mcgiggZUUS3M", - "baseTokenDecimals": 6 - }, - { - "name": "FRKT_USDC_AQ", - "address": "EUgwcVQhm1BDHWeMThNRx143RRay1byP6gmca9dp8HMe", - "farmTokenMint": "Bc4CvPm15iLRopgLmU17RJicBgjykiMwVzYxa7Wnujdh", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "FnDxJPNk7pPmGHUbR4XUHmHevrkXHdna5D3sQKcAtjBL", - "baseTokenDecimals": 6 - }, - { - "name": "TTT_USDC_AQ", - "address": "BPsQWbFEwYRxHims8Yw14BbL8njWEQq4tNWrrJb9sgXD", - "farmTokenMint": "AmrPpJFQj4xtv3yVgPCFqhXEMBPhaKRP6qFyhuCdz66c", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "FGgP1npQTsC5Q4xBmQtNYSh51NKqNwdxBZy8JCo3igcu", - "baseTokenDecimals": 6 - }, - { - "name": "UPS_USDC_AQ", - "address": "4TQzMpNP5JdZ3YDi1iz9kYqv4L7sTKQeFtpvnfc6T7aJ", - "farmTokenMint": "9fuv3emLQXECrTWqm2HaKT3wQhmvmgqmReZSMcu8PfpH", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "E1U63VXhNiWoUkVvjrfLDdV1oJrwE6zLde3bohr6jCqz", - "baseTokenDecimals": 6 - }, - { - "name": "FANT_USDC_AQ", - "address": "BkiSfYmmt8KxrKFhpS4oq6TYf5C4DFnaFWDnn3eDhcfp", - "farmTokenMint": "C2EcthTMaC5eATXVaXg5ctvMfUYYgFyNibybHes5D3S6", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "GjG7JjTQfQpDxw4hWx4etP9oTaYCuCbPjsU8WaUT3xHB", - "baseTokenDecimals": 6 - }, - { - "name": "BLOCK_USDC_AQ", - "address": "3QHfuWvAkUfr1QenKaPBDUUUwShvoMLZCmfux5bovz1J", - "farmTokenMint": "CkSfxpcpunHLUQktiFAeTJCYHsT4brYoJE23R3vw5zCF", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "D8WjqtwC9CzBrQKfSf2ccCHFQuPYwyLv5KAy8WjT5vnf", - "baseTokenDecimals": 6 - }, - { - "name": "RUN_USDC_AQ", - "address": "2yCL6hAsNQN7R2wrPaUffxVDyK8hhSL1hYf2knhUzLZk", - "farmTokenMint": "Gxh7KubJPEqR1i4oHCxxYayWcSJMzn7h2kpJeCCEAkNC", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "34Ppq6R8NfYBwWwPY4cBK4Afyb8hHaASQFukCzH6cV4n", - "baseTokenDecimals": 6 - }, - { - "name": "UXP_USDC_AQ", - "address": "G7W1y2Mv2kxu7ht3csCUNdduaUNBkYVcvX6QA47CJKuF", - "farmTokenMint": "8BxKJ3FAFbidm9rPotQEcm6dDqJkTz2PhLtaq6hnZk8L", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "HjR8JgqNKQVMvdryqJw5RJ4PCE9WGk8sgbEF7S9S3obv", - "baseTokenDecimals": 6 - }, - { - "name": "BTC_USDC_AQ", - "address": "3japFRAWZTq8FLjeTsi4hmNHpeo7RhP9ift4joCjRkga", - "farmTokenMint": "3aDHNJpWPEzXHZNeuak3LgcB8MbAwnDKkB2YftaPyhev", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "J3kvcay3N16FBdawgnqoJ9v9p6XCvyCLE2Z9F5RLvGkj", - "baseTokenDecimals": 6 - }, - { - "name": "MNDE_USDC_AQ", - "address": "FBSHQPtDZLvv8tmj1S75GW4TKGhxXVqU1zcSK57ZWHGF", - "farmTokenMint": "BtXnDsnidDZnkVFJJnqtAMMCtkoG5uioYF72yC8fhVTn", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "12Uj74zgUUoBe4yeackwQ4qYtFMr9fk1xL6q5Nha6t2N", - "baseTokenDecimals": 6 - }, - { - "name": "CHICKS_USDC_AQ", - "address": "BQivr16DZwUyzx9Qa5LR7V7eg1ASMiPjBtyj1bsoLXw2", - "farmTokenMint": "GTcxXu3yw7yotq2UtAMvpEbx84ozJyrBwy77Cmem7m4X", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "71CBZeJ4tw38L9pSPoCz4fRsuWE64Fipyzotte7haoCS", - "baseTokenDecimals": 6 - }, - { - "name": "ONESOL_USDC_AQ", - "address": "5FSwvhovxgEJPg4yufxCXiLXD3RY2SJKQ2fFy8mMupJj", - "farmTokenMint": "4tcadvVpXQPswr5dRt6jJW1sVFW2CxrKgzP594ZxaUTv", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "6MF5CHWAj5mS7FhpxiKz37CzR2eYTu236XpBKKMXCrGg", - "baseTokenDecimals": 6 - }, - { - "name": "WMP_USDC_AQ", - "address": "8brkHbXG9fNoYZu68D7cQy9Q1gC7hfTZQD7jfKFv4hvC", - "farmTokenMint": "Ce3VXSQGFEHqrQSEzcVb2Ro88Mcn56cYBUAXFx5tL9bo", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "HDgxKmiA8Pv82fNguhVeMkZqQkos2YksFPoP1KttWxX8", - "baseTokenDecimals": 6 - }, - { - "name": "UNQ_USDC_AQ", - "address": "9hQXfKCdD4v9v8vzimd6KExoSnS36q5kUPTW3PdX6KRu", - "farmTokenMint": "CsGTrgJ6oLx9UQow9aLjuAacjXTY53zT8B2FnAbfVZAS", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "2VuGzaMrDnDyZfYvDwSXk38s7M2wpud7LDY3dGA1J9sy", - "baseTokenDecimals": 6 - }, - { - "name": "BASIS_USDC_AQ", - "address": "A8CNiARq7zYMMGKYbqJVfByVyBzdMexhc5EEGzCN13dS", - "farmTokenMint": "4yx2aHMa7N4m1uUaBRy9QPtpstw3HFPtvcCPJQaGFHKL", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "GoaAiajubRgeCFEz9L6mLnSmT2QFegoJDH5tpLfivpj", - "baseTokenDecimals": 6 - }, - { - "name": "GST_USDC_AQ", - "address": "44aNS8nnj4r3WWvnR1Ud929iAqn5jJ7ugVkJJvH4XuW9", - "farmTokenMint": "72vxFxfeSN2DRKmSQAkJCoFBNYb2WNevyaDh4v2t8TqP", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "E6FUnQHGHJVJg7oExVr5Moeaj1QpdpZQF5odYjHXWPZb", - "baseTokenDecimals": 6 - }, - { - "name": "MEAN_USDC_AQ", - "address": "4ZqD3uYerAhUrVCPSKV15JT7ToR4EW1TwK6HHckAZNio", - "farmTokenMint": "3h2VBX8533NB8eEH8rPXMdayodFDbgTHpbav6JqLZAQq", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "F5BTnwuMA6rxftTdbZ33VWKr2wrr6DuQHnd4guKmPSYQ", - "baseTokenDecimals": 6 - }, - { - "name": "AART_USDC_AQ", - "address": "6pvWTK3UZJ2gKpVZBXMEUEbnSbqf8GxEFbAQjWuuW4C7", - "farmTokenMint": "Bg7pZq7KdsQsnCQBeNpa4XVnrWfjUJNu3ViHoNB7YUZU", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "HCtyJzFUtYecXrA52s4Y9atq4J1fhT3cYsTX17XVSFag", - "baseTokenDecimals": 6 - }, - { - "name": "SHDW_USDC_AQ", - "address": "ABmFqgfvQjjU8uBkZL2KdH5AvYEMsuddtdvpm4s62Pzq", - "farmTokenMint": "7WWHfufv8vuBC1x7GXA3pu7kgNhEQkXoq3CtbaQihAJ9", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "DJqqvzSuPaWThfzwMjXx7H2ZmHDdwxza6NtFudtuXcpc", - "baseTokenDecimals": 6 - }, - { - "name": "SHDW_SOL_AQ", - "address": "EKe5CgBnBJA2cgeEUe67aQS57bAQsPvfVdArEWuEuEEW", - "farmTokenMint": "BDStVBt4NS5bfda25ubK51kVRioV4yjKKCPbe96jeEms", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "2ws7g3LBPdctfKn42Di9qxzQtUJ8ZL1aEAX2rGEQMNqh", - "baseTokenDecimals": 6 - }, - { - "name": "SCY_USDC_AQ", - "address": "GDf3GpSU1V1UCvpcU19rV8p8CUC4cken9b5RpKzBBgiN", - "farmTokenMint": "DkxeyV1TEt9umvqjPNf9tdjJjgyvW5Mdi4AQnExA5bZa", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "99ZHUQsgxL7K6PHrGNi1gSwawwPr7UA5fbWrYoHQ6qhX", - "baseTokenDecimals": 6 - }, - { - "name": "SLC_USDC_AQ", - "address": "AgscvT8HJ4uqznp4SeYMgKf9qUjTrQL7AzU6mjcqpPCB", - "farmTokenMint": "X8GnAvxq942xXjNzqYPFQQ9JstJQNEA81uPeNoQpgrN", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "E5kSBqTDxFLbLNQaVVtPtnhEYVLMCK2fVSEKoMKL98qR", - "baseTokenDecimals": 6 - }, - { - "name": "wUST_SOL_AQ", - "address": "7tHjwHKvoSPjoAZepTZsw7uV9XobkgRXhMbhbZmqA8mS", - "farmTokenMint": "F49Cm3srGucQCBanA2xL7nSKHfH1QZd9vLdFtkg4LKnq", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "6c13xsmyk7UaHUWZ2rm1MM3ZdrQRSBkQ9waaG25ridVs", - "baseTokenDecimals": 6 - }, - { - "name": "wUST_USDC_AQ", - "address": "Aq289TqufDB4A4TEGVUkVquVggyrPjCwxkEv7pDEVpWZ", - "farmTokenMint": "2mhVUMsG7eb3XhHjAbKpRZgWNyGZNCiWU7dRxauzZaGL", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "J1KfRtP5y2warpD7LdJhfBLPKoWwSqYuovdArSv1mpQ7", - "baseTokenDecimals": 6 - }, - { - "name": "mSOL_wUST_AQ", - "address": "9iXAweywwdGR76L58FNg9siQzxyzbeJsomjEohPztpHF", - "farmTokenMint": "6wqME6zPQzGDLugpnwZnVBKBbATC5nTaEa781Vj98yvM", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "68YVjgPnTUPcBqZyghqvD2WPNsrLKsjYTmBKJzHRr4qd", - "baseTokenDecimals": 6 - }, - { - "name": "wLUNA_wUST_AQ", - "address": "52VxPD3pag6QrtEKXTe4jYBvSTvfggjbXZv3vqo455uU", - "farmTokenMint": "3ZGKT28NXAqb2YtUAMvKixQvHNHT31Q5mK8AC2iBMs29", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "8Mh7drLbt3jFJYwp948XyvQscGLaLkChNcaH5wwaAoWA", - "baseTokenDecimals": 6 - }, - { - "name": "stSOL_wUST_AQ", - "address": "GxhewC22S6wsXT156yC9SARvDnijoc3YEYyLVcQFDUCx", - "farmTokenMint": "3Q44iV4URXdbS4Tk1PGs5VdWQoCxHB7zdcdMnemo8jfH", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "HTZd53fYwYQRyAjiaPsZy9Gf41gobFdqkF4oKe3XLi95", - "baseTokenDecimals": 6 - }, - { - "name": "JSOL_USDC_AQ", - "address": "62JumLDtnsQ5YsEZrJaQsvDMP5pRmok3JEWHghFkL8D2", - "farmTokenMint": "B3JDURP58ooQT8zvhLgDRKVjstqgrHhn61qzzudHWrS1", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "AzEoVuNJyo9ByoLRZ5t6vav2Zg24vULNVJM41PgCKUqR", - "baseTokenDecimals": 6 - }, - { - "name": "daoSOL_USDC_AQ", - "address": "EaxYr2iZhrgwUKQVeFFeHQLW1afzS8pgZGn6hLhgFMgy", - "farmTokenMint": "A9kPybFFdj3MGKWWSwgb3KvzQyeNXESayh4ngmkmee2R", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "CCyDxjdW3G7hPTthTMPTZ4bnhFF19XG6rx2fNiKeRQww", - "baseTokenDecimals": 6 - }, - { - "name": "ORCA_USDT_AQ", - "address": "4SNMBiDGjDSZnyQFqSodJTTmRqEkisBWciXZ4hGbDujc", - "farmTokenMint": "C2YSdSesufbMVWtKXSZGhc12f6UL2j3WDe9VT6rRbmA8", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "Gx4PoxenyQwhGGnKagAT35iVg4im1iKhJxDWqVhgu6tk", - "baseTokenDecimals": 6 - }, - { - "name": "ORCA_whETH_AQ", - "address": "AgWH92f8cPAuURyqehF6A9wFgupEsnDX3VP5eHyytabA", - "farmTokenMint": "A7EAHvFEWzW8qSTFNLrEHN894GAZWZesNiebttEwtUGJ", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "GsfyYHkSgC3Ta6aWR9MjB2sxoBrkGGeR2tAwXbpphf3", - "baseTokenDecimals": 6 - }, - { - "name": "GENE_USDC_AQ", - "address": "EoRaCH4cwmmxc78s5E1fTDt2zPkivXNLf1MvoGhJywKd", - "farmTokenMint": "GrBZ4HLhL28JTxMfAH2Vm2hVv3RE4TYXCG9p9BpyUaRq", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "7cuu94swKL5PtFQohKMAzyd1mjj65rgMW3GzLY31HCnK", - "baseTokenDecimals": 6 - }, - { - "name": "CMFI_USDC_AQ", - "address": "2CGcou8YJoannsazSYQ16jSUZzPP8zZ9jdqgSRSGsVXa", - "farmTokenMint": "E8RVjS24pBuF3oCCeJVAgC4RQ7mVa5P3FGXqGbiczzvD", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "85krvT9DxdYgoFLQDHTAGdvtNuLdAsc4xE5FkVLpN2aR", - "baseTokenDecimals": 6 - }, - { - "name": "acCELO_USDC_AQ", - "address": "EowPc9YUmqJDjAujhD1eaLzDm99JnCu88fA1W8skKgQv", - "farmTokenMint": "9RRBDWZGWGVnHgazCpb9R1XApmHLBDya8Tq1yrzoMsKY", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "HVLyX8mD8YvKgZJ4oB6rXJiCYMLpHKwB6iCiCjE1XwdT", - "baseTokenDecimals": 6 - }, - { - "name": "afFTM_USDC_AQ", - "address": "EsE6fq5rP5Dg3ivS42JodpaQNpmkB6LTFX2nDSRZZ2og", - "farmTokenMint": "E7Af9Fa2U1YqEkQpAYjXwDB5TJUou9VcN3ot33Gj6UY9", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "Gpzd833qSmv3kXpQmxEaqkrZTXZaRjhNAoqhf61qAhTG", - "baseTokenDecimals": 6 - }, - { - "name": "CELO_USDC_AQ", - "address": "EowPc9YUmqJDjAujhD1eaLzDm99JnCu88fA1W8skKgQv", - "farmTokenMint": "9RRBDWZGWGVnHgazCpb9R1XApmHLBDya8Tq1yrzoMsKY", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "HVLyX8mD8YvKgZJ4oB6rXJiCYMLpHKwB6iCiCjE1XwdT", - "baseTokenDecimals": 6 - }, - { - "name": "FTM_USDC_AQ", - "address": "EsE6fq5rP5Dg3ivS42JodpaQNpmkB6LTFX2nDSRZZ2og", - "farmTokenMint": "E7Af9Fa2U1YqEkQpAYjXwDB5TJUou9VcN3ot33Gj6UY9", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "Gpzd833qSmv3kXpQmxEaqkrZTXZaRjhNAoqhf61qAhTG", - "baseTokenDecimals": 6 - }, - { - "name": "BTC_ORCA_AQ", - "address": "8TcCqDgPgim1CV6zgAXFq3PxSBH7MDCeVSGharRzJ4SA", - "farmTokenMint": "EQsfnq9d1R2MbXGKDPSgJXnDk1oXocgMFoSd15pEAPGD", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "DFpLFcQZqDKykyDePgip4r6MExVmBKWqTa12ezq6qxUY", - "baseTokenDecimals": 6 - }, - { - "name": "HBB_USDC_AQ", - "address": "3saySWJwipyCXqqhYT8XaSMFAS7NNksKKdP3zFJuUMtT", - "farmTokenMint": "BxPd4x7gm6WQF6jsDCRQuQVZ2bopQ4KegMrqyQgdkPDk", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "cL5WhffCYFRLM4We8VS2W684kM4pHyuvEDwp8Ddw48k", - "baseTokenDecimals": 6 - }, - { - "name": "HBB_SOL_AQ", - "address": "9fEfGhHjvqDPcFx6cBNuWHHjQaa6fSEP5pRHjdFkPenE", - "farmTokenMint": "62q8m79WkXR1MAer4H2zLpA38s47Fywkqqv4MMwEHjad", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "FkKzu2HeMJZf4oHwoYPxLGVy3net5Jq8HAfnA5VqETgk", - "baseTokenDecimals": 6 - }, - { - "name": "SB_USDC_AQ", - "address": "Ax8vkRHj3Gqo5Tv6PfWZzmbr8zHfPdeYbJpG7QYkP3r1", - "farmTokenMint": "3Wppx86xN7Dg7GLUTD9C7AqCt68qZkWzNYUdCS7t1pCk", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "2Reqt4Sw9xNY8BoJ3EZLpFu5yVgNxFrbw8M3KiJpPn6o", - "baseTokenDecimals": 6 - }, - { - "name": "stSOL_USDT_AQ", - "address": "2xvT1Z2SU1iKvmWpUNP9y4vRXyB8GpGq7sD9CforJoYd", - "farmTokenMint": "CtvKaRLzCzRZCcYPwai7NCYBK4ArBj2oD6BfvMgJoiCN", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "4ni1nho89cDKAQ9ddbNQA9ieLYpzvJVmJpuogu5Ct5ur", - "baseTokenDecimals": 6 - }, - { - "name": "SEEDED_USDC_AQ", - "address": "n7VuBP5qpMt2fZxNevR2gtxsgogDv22GJsj5f2WNJCN", - "farmTokenMint": "H15WptGntFQifZmJHUzYBV9Mv7P27ofavEsF6yqpLTdX", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "H7gyTmNCDXkD8MGMqnxqoD8ANszjcju4tjT6ERZ5dakf", - "baseTokenDecimals": 6 - }, - { - "name": "AUDIO_USDC_AQ", - "address": "DvzYNQoPYFWQCjBs6rxvMmarcKMiEaQHC7sWVAm5K2XM", - "farmTokenMint": "BbRVh76k2jYsSWnd7qpDQ8ptzVzgRq67viK6tAFEkB8z", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "3hksYA17VxgiKSeihjnZkBbjc2CTbEBfvDCYgQhojTo5", - "baseTokenDecimals": 6 - }, - { - "name": "MMA_USDC_AQ", - "address": "C54TkajKsLqHZP1taiayDAaAHrr6KBmCVRT1BuZHxa9q", - "farmTokenMint": "H9qkbU2XYSQTk6JJJ2TMuZBthfkeCHigmuxB5jiQaamn", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "AaZRnJAnDyJyPD9uPJpJ8bzBGDCEi6jtBpUf92xErWPp", - "baseTokenDecimals": 6 - }, - { - "name": "ONESOL_SOL_AQ", - "address": "64zLHH6zA8yuLxxPAgbVx5Cp9F8afHZWSyUndHsFBP95", - "farmTokenMint": "Hva9oLa2GjoKdB45WoHujsX7MTpehByPshMrQpNDmkFq", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "9wPhuYapychVDSxmXqCZxy2Ka8Lmav4SHM72si8bfraV", - "baseTokenDecimals": 6 - }, - { - "name": "PUFF_SOL_AQ", - "address": "Gp4r2PFLSf9Y1Y1K46gpEYsM7mkFNVY4Ga7s6YXZmxGD", - "farmTokenMint": "Ge5kuYg5PekrPUeKzngw97Cnfngj8j6NCX5q1jTBkWSW", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "Eho8h1BcoG5QWU7X9FzJafw5ErKUXtR2LobAJJZfWff4", - "baseTokenDecimals": 6 - }, - { - "name": "SAO_USDC_AQ", - "address": "4rKjrmHAmeT6bu3JNhP2NYjFgVHtt71U9yumBDKHTe14", - "farmTokenMint": "A9BeGSRJJYXPrMs81rVZxvkk16fopzgG5YkngntgTu7p", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "4iyU77yZbg8iD344vbwruAuDAf9i1EVV3FhZJDnWStBE", - "baseTokenDecimals": 6 - }, - { - "name": "sRLY_SOL_AQ", - "address": "9SV2NL59i1PfD72AUHDXa2KT1xWnFD3VyMgfzCRDARW1", - "farmTokenMint": "6gkZ7QUmxmwPLS2NK3Dr6YHtTPZs6GQrkA595WSx5iLe", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "3dXdXg5HPyZ73GFC9LkSn3thdJUGeXWB8iSTHs5UcqiH", - "baseTokenDecimals": 6 - }, - { - "name": "ZBC_USDC_AQ", - "address": "gBBNuRf5VsGoAEwKzTAaVsPSqTiYLh5VmaxvzvbCEBb", - "farmTokenMint": "7Hoi4adCSBzERdvSiUXtVDz79tiDxMD5HpDv7m9rs3Sb", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "2LYgm6nGXmSSjfoEriPuYeGoNiWNxUs7n3rnTbDWN5c7", - "baseTokenDecimals": 6 - }, - { - "name": "GMT_USDC_AQ", - "address": "DbJT9UTTt8U8xAk7BtRWC3nQHxJnNmZdZydUAhJj14TZ", - "farmTokenMint": "8EnEoVX1aXkzbTzhrqDQ2aVGybbPpeWZDCYEGjjw1dyG", - "rewardTokenMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "rewardTokenDecimals": 6, - "baseTokenMint": "CFxQF5kNAtbbDj298Xr47Sf4mkSyuzWpRH97hrdQ6kxi", - "baseTokenDecimals": 6 - }, - { - "name": "LIQ_USDC_DD", - "address": "AraZDjfmkqzDJ3CdbjjYbtpujUYivgTEKKM2TPf6hJ27", - "farmTokenMint": "5rGtJDiJhD5Mx2fvdEYuLrCiWaMD9z3wpmJSxwGHmo4u", - "rewardTokenMint": "4wjPQJ6PrkC4dHhYghwJzGBVP78DkBzA2U3kHoFNBuhj", - "rewardTokenDecimals": 6, - "baseTokenMint": "57vGdcMZLnbNr4TZ4hgrpGJZGR9vTPhu8L9bNKDrqxKT", - "baseTokenDecimals": 6 - }, - { - "name": "STEP_SOL_DD", - "address": "FmHGpt2scyJ8NuDuknnzQ7jectLyRRQmTyXxu5tRoD2j", - "farmTokenMint": "Gs1fM7EFS1rXkxhqs4mwu9uvSkupNzZgRbHGxG2NGRh7", - "rewardTokenMint": "StepAscQoEioFxxWGnh2sLBDFp9d8rvKz2Yp39iDpyT", - "rewardTokenDecimals": 9, - "baseTokenMint": "GwrBA1F8rGummDCDd8NY9Eu1cLNuJqbT8WaGxgWpFwGL", - "baseTokenDecimals": 6 - }, - { - "name": "SLRS_USDC_DD", - "address": "8JkTAVHXChDPzsNkcJYRJ69mXN5nCcyb1qVBmbVhCH1n", - "farmTokenMint": "F3rWkGAtdjWcU1rr16Wq4YPTgFdsyb1oS1xdy5tr9K1r", - "rewardTokenMint": "SLRSSpSLUTP7okbCUBYStWCo1vUgyt775faPqz8HUMr", - "rewardTokenDecimals": 6, - "baseTokenMint": "66xCxkffQZKBZLiHV3PDcfR8ANJTfnDRxPCaBdv4wxB7", - "baseTokenDecimals": 6 - }, - { - "name": "PORT_USDC_DD", - "address": "C8k63XU8xzzvBpSraYWjHCNzvprjYKDadAML3MWSFbxW", - "farmTokenMint": "Zm2dmUuuBicmvHxGAnAzaohZR2Y86gXEV2WMfo8AoCa", - "rewardTokenMint": "PoRTjZMPXb9T7dyU7tpLEZRQj7e6ssfAE62j2oQuc6y", - "rewardTokenDecimals": 6, - "baseTokenMint": "4CGxvZdwiZgVMLXiTdJHTkJRUTpTSJCtmtCRbSkAxerE", - "baseTokenDecimals": 6 - }, - { - "name": "COPE_USDC_DD", - "address": "HW21NT7v6ViM2Cs3S2tVgUnawACF8JRRwd2AA41a8HUh", - "farmTokenMint": "AtcMEt9caZxpunQV99pxED2rhpQmaDykBreEqBsYU11v", - "rewardTokenMint": "8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh", - "rewardTokenDecimals": 6, - "baseTokenMint": "9SDpBrfqNxjXcCzpKWM6yUKdfky975VJBD6xcu5cKf5s", - "baseTokenDecimals": 6 - }, - { - "name": "BOP_USDC_DD", - "address": "GYipJSPD7zcDoEABRCZfDSqh7zqYMmjyP8dNKEUnW1iC", - "farmTokenMint": "CjGUbKiH1QmFFjMqhAbJn4DrbjgBWUhQHV4LuzrgpFqi", - "rewardTokenMint": "BLwTnYKqf7u4qjgZrrsKeNs2EzWkMLqVCu6j8iHyrNA3", - "rewardTokenDecimals": 8, - "baseTokenMint": "A7vvbqENJj8kED3ABjphe8TvwpasQYtoWGKpjpLArMxa", - "baseTokenDecimals": 6 - }, - { - "name": "SAMO_USDC_DD", - "address": "8VJT2SYGXgvQ8jYvh1Cq6mg83gkAVuTY3cHiULUy6Cit", - "farmTokenMint": "EdfAy8jwnvU1z61UaFUjwoRPFgD3UkkPvnhEBZjzwhv8", - "rewardTokenMint": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU", - "rewardTokenDecimals": 9, - "baseTokenMint": "9voVuTq1S9bFZkF2Jo44HoVG63w2xDRT8eBzB23YbQud", - "baseTokenDecimals": 6 - }, - { - "name": "wHAPI_USDC_DD", - "address": "GFFQdLWvbWzrZBQrPQVyzGQfd6SWuZaiRwmkKA2bJPeY", - "farmTokenMint": "41VBoy8SGJzQnWGcxiBL4yM6H68FiPp74aMvsZGNGCbt", - "rewardTokenMint": "6VNKqgz9hk7zRShTFdg5AnkfKwZUcojzwAkzxSH3bnUm", - "rewardTokenDecimals": 9, - "baseTokenMint": "Bfoi3RNnfdP5VeRGqvTA8MRN9ePGJoZgeKfe8WeBHUxE", - "baseTokenDecimals": 6 - }, - { - "name": "SLIM_USDC_DD", - "address": "3RsBqqz9MiXa1uhFFd6tpGVQ66ptkFPCBAUyqLAXeCTE", - "farmTokenMint": "HhDk3ySWkVbMZjgBsFSnLtAeudDCrfZ6DNSRgxh2oRUp", - "rewardTokenMint": "xxxxa1sKNGwFtw2kFn8XauW9xq8hBZ5kVtcSesTT9fW", - "rewardTokenDecimals": 6, - "baseTokenMint": "3K7aZhtwWJ2JS6GnbbgeDVnxd1q2hwhqasmgRsAMZ4yC", - "baseTokenDecimals": 6 - }, - { - "name": "NINJA_SOL_DD", - "address": "HPeAGzDEhYUNm4z4aV2PTjVjbESnNg6jBy6LtFjFJzQj", - "farmTokenMint": "Db7mPGrZbswvFmJ7MgZsM6CFhnXHMnrUDqr2hrzmi7Re", - "rewardTokenMint": "FgX1WD9WzMU3yLwXaFSarPfkgzjLb2DZCqmkx9ExpuvJ", - "rewardTokenDecimals": 6, - "baseTokenMint": "7YyhptkxY81HPzFVfyCzA5UXxWdsNRD41ofLva3TuSpd", - "baseTokenDecimals": 6 - }, - { - "name": "ATLAS_USDC_DD", - "address": "DTP1xr4EzFf1YDu4CeWTtWVsCBzFPk4HDEsL3AzoR3kB", - "farmTokenMint": "894ptAFT7d3inPsWTniCGL2NZpJDiXGvFZFfuHXA1w8F", - "rewardTokenMint": "ATLASXmbPQxBUYbxPsV97usA3fPQYEqzQBUHgiFCUsXx", - "rewardTokenDecimals": 8, - "baseTokenMint": "HFmY1ggCsCky1zJ1sfdkNR4zb3u5n38YNRdf4vsGu17t", - "baseTokenDecimals": 6 - }, - { - "name": "POLIS_USDC_DD", - "address": "7h1zAHj2xzEw3eKfprYqG36aN5XwcZXBsYwM2haWQVzR", - "farmTokenMint": "FE1QJzi5RA5aKnTfSV3DAMN3z4uHUzSR5Z4drs9S5vB", - "rewardTokenMint": "poLisWXnNRwC6oBu1vHiuKQzFjGL4XDSu4g9qjz9qVk", - "rewardTokenDecimals": 8, - "baseTokenMint": "63JUKLnCAuNMPSPioEgbjjzp9Qk8qSEEM8eZqEtPqfLU", - "baseTokenDecimals": 6 - }, - { - "name": "ABR_USDC_DD", - "address": "98htZRc2QNd8BS9GGHoxkySZ9BiL9MAgHLEQfxzXYKk6", - "farmTokenMint": "7bp7psdaC3DVc86Hmdz5tAMEjgPjmCzgFEVALfqBwMmz", - "rewardTokenMint": "a11bdAAuV8iB2fu7X6AxAvDTo1QZ8FXB3kk5eecdasp", - "rewardTokenDecimals": 9, - "baseTokenMint": "5uR5STASUmoGVHzqMeut98t26TfVkQqWU9f9dsv3NfJ6", - "baseTokenDecimals": 6 - }, - { - "name": "KURO_USDC_DD", - "address": "BK3VXXDA4KxVurHbP3yPytGWp1HifbBtB4ugpzfDeq4v", - "farmTokenMint": "88RCQs9VFvqPjsRe3PKNzBeMtzCS9oS1a1CJuAnGnLZJ", - "rewardTokenMint": "2Kc38rfQ49DFaKHQaWbijkE7fcymUMLY5guUiUsDmFfn", - "rewardTokenDecimals": 6, - "baseTokenMint": "6PGoaQdL9e463hdaFxHXsuPcjCHRK32CQ9PFKxvM7XY2", - "baseTokenDecimals": 6 - }, - { - "name": "mSOL_USDC_DD", - "address": "5fhDMuGKRDPWVWXf7BBEwifRFrp6XwXctDQoG7UHGVt6", - "farmTokenMint": "9y3QYM5mcaB8tU7oXRzAQnzHVa75P8riDuPievLp64cY", - "rewardTokenMint": "MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey", - "rewardTokenDecimals": 9, - "baseTokenMint": "5r3vDsNTGXXb9cGQfqyNuYD2bjhRPymGJBfDmKosR9Ev", - "baseTokenDecimals": 6 - }, - { - "name": "ORCA_mSOL_DD", - "address": "41ZYSekqDNtJ1BdGkTZVR1CJfBiFrud6HcT3HVUdSyWN", - "farmTokenMint": "876yhw4J4GHyynNJUtARYEnWGaejhrWC7Hy3DAm1pZxi", - "rewardTokenMint": "MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey", - "rewardTokenDecimals": 9, - "baseTokenMint": "3Duk5b6fLztPmS4ryV48FM1Q9WXUSMwz9jehAT4UtqpE", - "baseTokenDecimals": 6 - }, - { - "name": "mSOL_SOL_DD", - "address": "2SciNw7cEsKJc1PMRDzWCcEzvuScmEaUgmrJXCi9UFxY", - "farmTokenMint": "576ABEdvLG1iFU3bLC8AMJ3mo5LhfgPPhMtTeVAGG6u7", - "rewardTokenMint": "MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey", - "rewardTokenDecimals": 9, - "baseTokenMint": "3RTGL7gPF4V1ns1AeGFApT7cBEGVDfmJ77DqQi9AC6uG", - "baseTokenDecimals": 6 - }, - { - "name": "stSOL_wstETH_DD", - "address": "EmWtmApj1PtJMgMfzbYMmnmtuwfcBy7es3Tg2AR8xfW6", - "farmTokenMint": "5WXyG6zL1HmESPCSHHKBtqLuRPZCNgd9mTB25op87FkU", - "rewardTokenMint": "HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p", - "rewardTokenDecimals": 8, - "baseTokenMint": "3kT3oYuS1rCfhmqfgy6EKcbZdaJimaVEjoy25QiuEaoj", - "baseTokenDecimals": 6 - }, - { - "name": "SYP_USDC_DD", - "address": "gpy1dZRbPbLZ2KNr4wd2r9zoxERbWV8gWTqTL47KNnh", - "farmTokenMint": "BpHfwFwJwkZKWY5xVMC3oifMvWRy42R4VE1vPeBzg2G1", - "rewardTokenMint": "FnKE9n6aGjQoNWRBZXy4RW6LZVao7qwBonUbiD7edUmZ", - "rewardTokenDecimals": 9, - "baseTokenMint": "Ds4VGZhZzS2PMFzhzKeC3mwcQjdiCG21R76fTVbsSJyJ", - "baseTokenDecimals": 6 - }, - { - "name": "MNDE_mSOL_DD", - "address": "C9AfeUkti1ykMTebw9N1WoiEhNqwNiXinfXBwuLUv1BT", - "farmTokenMint": "2FMpVEhvxiFxhfideFUMNxCoUZK3TfhezzajoHGTQKP2", - "rewardTokenMint": "MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey", - "rewardTokenDecimals": 9, - "baseTokenMint": "2wPsMuzhEsC6GhV3qtFpmJF6atEgLGbnmQ8U43Y6fPxZ", - "baseTokenDecimals": 6 - }, - { - "name": "mSOL_USDT_DD", - "address": "FNV9pGMWTYSMq5dRhmjpRwHpDJKV6JD4HTKsqZndKvuY", - "farmTokenMint": "7iKG16aukdXXw43MowbfrGqXhAoYe51iVR9u2Nf2dCEY", - "rewardTokenMint": "MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey", - "rewardTokenDecimals": 9, - "baseTokenMint": "Afvh7TWfcT1E9eEEWJk17fPjnqk36hreTJJK5g3s4fm8", - "baseTokenDecimals": 6 - }, - { - "name": "mSOL_whETH_DD", - "address": "D6oqo3F2KkJcePDoNZfbb8F7SPnRhP7WCC9FNktzVCDT", - "farmTokenMint": "3kFeVJUxhQS7PE7vV8pt9bhTCQrUDqeGf6AU4sjkLzVt", - "rewardTokenMint": "MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey", - "rewardTokenDecimals": 9, - "baseTokenMint": "58nifjPjF3CutGz2xMxvAMk7R9YgbVEc8Cstj4rCcs8j", - "baseTokenDecimals": 6 - }, - { - "name": "BTC_mSOL_DD", - "address": "Cn7QNyosNQ8DyKEeMDPmtg66R7vKMXigcQ561kTkFD8E", - "farmTokenMint": "6uA1ADUJbvwYJZpzUn9z9LuyKoRVngBKcQTKdXsSivA8", - "rewardTokenMint": "MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey", - "rewardTokenDecimals": 9, - "baseTokenMint": "DzpLz78wuwyFsQToin8iDv6YK6aBEymRqQq82swiFh7r", - "baseTokenDecimals": 6 - }, - { - "name": "IVN_SOL_DD", - "address": "9DNgTpphCRXhkf8ySiSnf1L2CHwACZybgPNwsnLUdzfA", - "farmTokenMint": "5X71f6zUnVYWSxWM8wf942pzWLv1ZtCDhGCYqZipYutD", - "rewardTokenMint": "iVNcrNE9BRZBC9Aqf753iZiZfbszeAVUoikgT9yvr2a", - "rewardTokenDecimals": 6, - "baseTokenMint": "HqajzzbGMST3yCCVBJuXvNVsWkY2DXqiBz9cTRmmyBMy", - "baseTokenDecimals": 6 - }, - { - "name": "LARIX_USDC_DD", - "address": "GnFV3S7H6eM9V12EJwptv111VmV7W3AnEEfzdHJL25n7", - "farmTokenMint": "Huy453KXTaWaA3AiJeqLrAWWSMwoGjFU8nsEi7GiPY7n", - "rewardTokenMint": "Lrxqnh6ZHKbGy3dcrCED43nsoLkM1LTzU2jRfWe8qUC", - "rewardTokenDecimals": 6, - "baseTokenMint": "DNAGfa7tK8csprRQmiDUwDaFfhw6ueHhVFHTCgTJ8HGs", - "baseTokenDecimals": 6 - }, - { - "name": "GOFX_USDC_DD", - "address": "EVDvbsD5f1qz7FpVyknrzB3bLK86FHfqVbcH9WqpWZtK", - "farmTokenMint": "BzZ3mLyXEaGt1Na1zxfZYjRJBFDbDckurc2LDq46irUx", - "rewardTokenMint": "GFX1ZjR2P15tmrSwow6FjyDYcEkoFb4p4gJCpLBjaxHD", - "rewardTokenDecimals": 9, - "baseTokenMint": "B95rdqSY4dqPwmt295XwBZZqZJYLmqDNXU6NvBpT4ep4", - "baseTokenDecimals": 6 - }, - { - "name": "WOOF_USDC_DD", - "address": "9M9JKUWatibJKghbDDjHXLGGY18dLPLHgs6a4WiP9EAe", - "farmTokenMint": "G6kaJ4NrCS9VoNgPiMuR5ENFrGJBfMe98PXFgVYkBKts", - "rewardTokenMint": "9nEqaUcb16sQ3Tn1psbkWqyhPdLmfHWjKGymREjsAgTE", - "rewardTokenDecimals": 6, - "baseTokenMint": "4HaQXDz9gdLgKUjvNVtnLyNZoWNYKjh3XxH1TpLgiwmi", - "baseTokenDecimals": 6 - }, - { - "name": "SDOGE_USDC_DD", - "address": "J3AmdMedeE1mhwbZzZFysER8CZdMqxL3HoyLxCmub9mc", - "farmTokenMint": "3upLraKWWJ3Tv8JgwygBszT1nQwksYBnx2XWEgaGMTt6", - "rewardTokenMint": "8ymi88q5DtmdNTn2sPRNFkvMkszMHuLJ1e3RVdWjPa3s", - "rewardTokenDecimals": 0, - "baseTokenMint": "4kXYyZAMBdvgDaBKUGvRWJnHw9af7sCUPvpQ68PEdP8b", - "baseTokenDecimals": 6 - }, - { - "name": "CATO_USDC_DD", - "address": "7YMRTqXna5vtCkncV6hxhUd7qCrv621iRq96b7LYySR2", - "farmTokenMint": "2YbEbQD8DP8QyRQnp7CXwdD6BqeJsry4MkWZgxovZPMm", - "rewardTokenMint": "5p2zjqCd1WJzAVgcEnjhb9zWDU7b9XVhFhx4usiyN7jB", - "rewardTokenDecimals": 9, - "baseTokenMint": "BHtZnTBMeY4EBEW5egGnuK5bdW12v6Dod6wFav79AyYx", - "baseTokenDecimals": 6 - }, - { - "name": "OOGI_USDC_DD", - "address": "F1jqYgps3MsGvWJ9WKq7NYx1eT4xjPDruFtQ9gMD1pLk", - "farmTokenMint": "3CiL5pm15BiLH8PBrhx7uFJr2uYoeBNZk55kuphp48Py", - "rewardTokenMint": "H7Qc9APCWWGDVxGD5fJHmLTmdEgT9GFatAKFNg6sHh8A", - "rewardTokenDecimals": 9, - "baseTokenMint": "FiwSk36yi1DNWcuQUeNipAc1VKxa9Wv9AR2xFvyKUxAE", - "baseTokenDecimals": 6 - }, - { - "name": "SONAR_USDC_DD", - "address": "E3hyqjh9R7UWMwkMSxYHws4qdnpMSzXwkuJfVcEfmJwb", - "farmTokenMint": "9tpC9vawMtim6q3MaQHfPPwFnnErh58qXhdqczS2p7sd", - "rewardTokenMint": "sonarX4VtVkQemriJeLm6CKeW3GDMyiBnnAEMw1MRAE", - "rewardTokenDecimals": 9, - "baseTokenMint": "GWmwwMGYBG4NqYdnsYrudzBnbgDC49MkBxdzhfLA9kVY", - "baseTokenDecimals": 6 - }, - { - "name": "UPS_USDC_DD", - "address": "8V2RqGTNmz2xYBdonfvkLstGWV7ibHopoZMQeaV9rykb", - "farmTokenMint": "9Ux3QdsLpLXCNFsACXjp4F2D5ihkWZnVhdDiTDTvw2Ny", - "rewardTokenMint": "EwJN2GqUGXXzYmoAciwuABtorHczTA5LqbukKXV1viH7", - "rewardTokenDecimals": 6, - "baseTokenMint": "9fuv3emLQXECrTWqm2HaKT3wQhmvmgqmReZSMcu8PfpH", - "baseTokenDecimals": 6 - }, - { - "name": "FANT_USDC_DD", - "address": "2J5exwdrNhqK1y1DF5jPQV2JieZ5xBsR3jDrZRh8PfPZ", - "farmTokenMint": "FftGKB7DThU5N96xYQ8BWkRBpFTKDvSzN7hCCNxuypsE", - "rewardTokenMint": "FANTafPFBAt93BNJVpdu25pGPmca3RfwdsDsRrT3LX1r", - "rewardTokenDecimals": 6, - "baseTokenMint": "C2EcthTMaC5eATXVaXg5ctvMfUYYgFyNibybHes5D3S6", - "baseTokenDecimals": 6 - }, - { - "name": "stSOL_USDC_DD", - "address": "HhBtZgPaFb5rodxXsZbtZUqxk2vEg6tdzM4AcaG2PjcL", - "farmTokenMint": "CejKA1pePxny3iprRDEyiojfTKNxxX2bjmKToDGZqwvh", - "rewardTokenMint": "HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p", - "rewardTokenDecimals": 8, - "baseTokenMint": "3u2dNfGuU6C3vmSg5EvLPUpX57b3niqhWBV5Gc3WDEf5", - "baseTokenDecimals": 6 - }, - { - "name": "WMP_USDC_DD", - "address": "2aUMqCFWK3PKeScspP4SqRFS7fag18TDHv2VsaBfSS72", - "farmTokenMint": "4SWDBKeb44RQMYmyorUiuF94Fqf1toketzJyvLSjVtHN", - "rewardTokenMint": "BygDd5LURoqztD3xETc99WCxLUbTi6WYSht9XiBgZ4HW", - "rewardTokenDecimals": 9, - "baseTokenMint": "Ce3VXSQGFEHqrQSEzcVb2Ro88Mcn56cYBUAXFx5tL9bo", - "baseTokenDecimals": 6 - }, - { - "name": "CHICKS_USDC_DD", - "address": "61uQt5e3Vd3cps6mS5xnL1UVLe3rwNS4aDaa3F2V7h3z", - "farmTokenMint": "3EPqpch8B8nk37gcxKCnQ5n6VSu4NyetcyZen636NYfb", - "rewardTokenMint": "cxxShYRVcepDudXhe7U62QHvw8uBJoKFifmzggGKVC2", - "rewardTokenDecimals": 9, - "baseTokenMint": "GTcxXu3yw7yotq2UtAMvpEbx84ozJyrBwy77Cmem7m4X", - "baseTokenDecimals": 6 - }, - { - "name": "UNQ_USDC_DD", - "address": "G5cvdbZwbwAV4eW8ENQy5tmbzaJu8TbdgF5MLXgLPXj3", - "farmTokenMint": "75jdeQfjFnNzg4dSbkA3HxTN63hXo99MrpafDJsz5Gcy", - "rewardTokenMint": "UNQtEecZ5Zb4gSSVHCAWUQEoNnSVEbWiKCi1v9kdUJJ", - "rewardTokenDecimals": 6, - "baseTokenMint": "CsGTrgJ6oLx9UQow9aLjuAacjXTY53zT8B2FnAbfVZAS", - "baseTokenDecimals": 6 - }, - { - "name": "MEAN_USDC_DD", - "address": "9TQ4HQXymNLVKEMve5peFXst5VPDXX1oZ8VTVuQeG7W7", - "farmTokenMint": "FaFGyRihhc8XUqWXNrVAd6gjRsyJ98mogonH4EN8WUPb", - "rewardTokenMint": "MEANeD3XDdUmNMsRGjASkSWdC8prLYsoRJ61pPeHctD", - "rewardTokenDecimals": 6, - "baseTokenMint": "3h2VBX8533NB8eEH8rPXMdayodFDbgTHpbav6JqLZAQq", - "baseTokenDecimals": 6 - }, - { - "name": "WAG_USDC_DD", - "address": "5dA9HWoFnBagq25bpMPA79bKxQkQ6YXvBtYQn6Le6vyp", - "farmTokenMint": "BYno9HNAiLoi7K8Wa5c1f5EE7hukzZPUQZDesGxBPzhh", - "rewardTokenMint": "5tN42n9vMi6ubp67Uy4NnmM5DMZYN8aS8GeB3bEDHr6E", - "rewardTokenDecimals": 9, - "baseTokenMint": "8Wu5sJpERA1J5iWcT8aMpt9cTAfKDLPbLpGjNsJoPgLc", - "baseTokenDecimals": 6 - }, - { - "name": "SHDW_USDC_DD", - "address": "GJ9EixfM3noFT1b7Y5uAzV1qJSFev5uPaRrmfMoibck6", - "farmTokenMint": "HPv7XJ16t4pZVNTBPHoYY19xiv4pHjjSbarE7Km3jJ1R", - "rewardTokenMint": "SHDWyBxihqiCj6YekG2GUr7wqKLeLAMK1gHZck9pL6y", - "rewardTokenDecimals": 9, - "baseTokenMint": "7WWHfufv8vuBC1x7GXA3pu7kgNhEQkXoq3CtbaQihAJ9", - "baseTokenDecimals": 6 - }, - { - "name": "SHDW_SOL_DD", - "address": "2EHJ8ToKpJfXyAfechjH9QSbVMKTSViYPdJRepQz7V8S", - "farmTokenMint": "8HgXuNigmLvfsgDun1vQso6pBuj7sVvDqpcergjtu3dz", - "rewardTokenMint": "SHDWyBxihqiCj6YekG2GUr7wqKLeLAMK1gHZck9pL6y", - "rewardTokenDecimals": 9, - "baseTokenMint": "BDStVBt4NS5bfda25ubK51kVRioV4yjKKCPbe96jeEms", - "baseTokenDecimals": 6 - }, - { - "name": "AART_USDC_DD", - "address": "BKFSHwhqDHRFM3PzNh7BG1vgxtEbx1A9Co1JN6z9SLYz", - "farmTokenMint": "FvmyENsZf68ezNbHxRqv1hAb7phfhdnXMfQm74Vcpnkn", - "rewardTokenMint": "F3nefJBcejYbtdREjui1T9DPh5dBgpkKq7u2GAAMXs5B", - "rewardTokenDecimals": 6, - "baseTokenMint": "Bg7pZq7KdsQsnCQBeNpa4XVnrWfjUJNu3ViHoNB7YUZU", - "baseTokenDecimals": 6 - }, - { - "name": "BASIS_USDC_DD", - "address": "DasaXe2Wqcks6csFv1bWwdW41mV8rMD5c27Uw9rFYVu4", - "farmTokenMint": "8XtNSYBhLHa4cYzNsXd6yDAweMECumrxFJ7F2qxk2xN", - "rewardTokenMint": "Basis9oJw9j8cw53oMV7iqsgo6ihi9ALw4QR31rcjUJa", - "rewardTokenDecimals": 6, - "baseTokenMint": "4yx2aHMa7N4m1uUaBRy9QPtpstw3HFPtvcCPJQaGFHKL", - "baseTokenDecimals": 6 - }, - { - "name": "SLC_USDC_DD", - "address": "DdYbYsTgpp3pBdGhN9sSdgRJs4ijKZQuDqzqKz6qmScs", - "farmTokenMint": "6VWtaecVXHuorMwVrZ4GAnYC3T5MG1YdQLYNPGyWzQHh", - "rewardTokenMint": "METAmTMXwdb8gYzyCPfXXFmZZw4rUsXX58PNsDg7zjL", - "rewardTokenDecimals": 6, - "baseTokenMint": "X8GnAvxq942xXjNzqYPFQQ9JstJQNEA81uPeNoQpgrN", - "baseTokenDecimals": 6 - }, - { - "name": "wUST_SOL_DD", - "address": "6p47BJ5d9JmywGpbZa8MapJmhcLdu5w2uNg9NQTJKvi", - "farmTokenMint": "BkcNGF6iV6NTfoH1ocoywXrfDpPWiWUu7eARBT42e57v", - "rewardTokenMint": "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W", - "rewardTokenDecimals": 6, - "baseTokenMint": "F49Cm3srGucQCBanA2xL7nSKHfH1QZd9vLdFtkg4LKnq", - "baseTokenDecimals": 6 - }, - { - "name": "wUST_USDC_DD", - "address": "87ArJQZCaUwLkZfaRHbjU8geq6F8HsFcCtoppCV7Buby", - "farmTokenMint": "DGxLh6BykS8C4zLrBRRD4cHZRdy73eVqZ5283JkAdU7d", - "rewardTokenMint": "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W", - "rewardTokenDecimals": 6, - "baseTokenMint": "2mhVUMsG7eb3XhHjAbKpRZgWNyGZNCiWU7dRxauzZaGL", - "baseTokenDecimals": 6 - }, - { - "name": "mSOL_wUST_DD", - "address": "5z183wdSnkc1k9EmnXncE66VQYYLn8MkxG9gJTo5gabj", - "farmTokenMint": "2q4rZYZgicviVBsb8CTWGR3bGWys3ePFDYtrayyQpwyi", - "rewardTokenMint": "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W", - "rewardTokenDecimals": 6, - "baseTokenMint": "6wqME6zPQzGDLugpnwZnVBKBbATC5nTaEa781Vj98yvM", - "baseTokenDecimals": 6 - }, - { - "name": "wLUNA_wUST_DD", - "address": "4G49eoJrt6DGWnVR84tgNzw987cjwD4cPYd3SUuo6mrd", - "farmTokenMint": "HQnMrrLP5RxYN6Peuu9cfDNQK81yd3TtBt3ZCjoD8UAf", - "rewardTokenMint": "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W", - "rewardTokenDecimals": 6, - "baseTokenMint": "3ZGKT28NXAqb2YtUAMvKixQvHNHT31Q5mK8AC2iBMs29", - "baseTokenDecimals": 6 - }, - { - "name": "stSOL_wUST_DD", - "address": "CXbiLWJoYcVmV7GcF9xSwwMPSgHh5rHRLJB84F54R4qU", - "farmTokenMint": "DxiftFoeRxHk15N4rDYzpwtGhfK3LqSn4gWDCaEkMksE", - "rewardTokenMint": "HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p", - "rewardTokenDecimals": 8, - "baseTokenMint": "3Q44iV4URXdbS4Tk1PGs5VdWQoCxHB7zdcdMnemo8jfH", - "baseTokenDecimals": 6 - }, - { - "name": "CMFI_USDC_DD", - "address": "E5m2jmo8DhLiY93nh95K4XCxvZgt66JzaJnwyt5CPmVR", - "farmTokenMint": "Dr7ks8oV6iRTT2R2uqE4x6Egmg3djt14aCEciNhq3SF9", - "rewardTokenMint": "5Wsd311hY8NXQhkt9cWHwTnqafk7BGEbLu8Py3DSnPAr", - "rewardTokenDecimals": 6, - "baseTokenMint": "E8RVjS24pBuF3oCCeJVAgC4RQ7mVa5P3FGXqGbiczzvD", - "baseTokenDecimals": 6 - }, - { - "name": "HBB_USDC_DD", - "address": "CvYum3awvbxPVa5FpZRBs97Prg5GDmLha4X6mggX7R1p", - "farmTokenMint": "FYdet59VXibMU8FhnbZamZTVMsjnCyNevUqzWUrJfGum", - "rewardTokenMint": "HBB111SCo9jkCejsZfz8Ec8nH7T6THF8KEKSnvwT6XK6", - "rewardTokenDecimals": 6, - "baseTokenMint": "BxPd4x7gm6WQF6jsDCRQuQVZ2bopQ4KegMrqyQgdkPDk", - "baseTokenDecimals": 6 - }, - { - "name": "acCELO_USDC_DD", - "address": "DrDpUFTvHjznYEugMqcXTqspdmQ6GZhuBzjodU7A6qWU", - "farmTokenMint": "4EUgJ5LSF3UDVbVAYzqE133NXAxfhHZSvqx214EJkNkQ", - "rewardTokenMint": "a11bdAAuV8iB2fu7X6AxAvDTo1QZ8FXB3kk5eecdasp", - "rewardTokenDecimals": 9, - "baseTokenMint": "9RRBDWZGWGVnHgazCpb9R1XApmHLBDya8Tq1yrzoMsKY", - "baseTokenDecimals": 6 - }, - { - "name": "CELO_USDC_DD", - "address": "DrDpUFTvHjznYEugMqcXTqspdmQ6GZhuBzjodU7A6qWU", - "farmTokenMint": "4EUgJ5LSF3UDVbVAYzqE133NXAxfhHZSvqx214EJkNkQ", - "rewardTokenMint": "a11bdAAuV8iB2fu7X6AxAvDTo1QZ8FXB3kk5eecdasp", - "rewardTokenDecimals": 9, - "baseTokenMint": "9RRBDWZGWGVnHgazCpb9R1XApmHLBDya8Tq1yrzoMsKY", - "baseTokenDecimals": 6 - }, - { - "name": "SB_USDC_DD", - "address": "74hUtc4MaZUt4YDDjVSqHyUbPT8kbxW16mbAharpZhPV", - "farmTokenMint": "EdkL9TXiT2NV1LND5nj4kR1L9SYjozWpJvbcStvrUUJF", - "rewardTokenMint": "SuperbZyz7TsSdSoFAZ6RYHfAWe9NmjXBLVQpS8hqdx", - "rewardTokenDecimals": 6, - "baseTokenMint": "3Wppx86xN7Dg7GLUTD9C7AqCt68qZkWzNYUdCS7t1pCk", - "baseTokenDecimals": 6 - }, - { - "name": "afFTM_USDC_DD", - "address": "7cYU6ux4GwB1X2FKaRruQ9dbDZKUrxZAaWGNJfeoHeGJ", - "farmTokenMint": "4r3uYr4Ph4ctw1chiUaAtwon4stFGHqbSJ6Lym139rM9", - "rewardTokenMint": "a11bdAAuV8iB2fu7X6AxAvDTo1QZ8FXB3kk5eecdasp", - "rewardTokenDecimals": 9, - "baseTokenMint": "E7Af9Fa2U1YqEkQpAYjXwDB5TJUou9VcN3ot33Gj6UY9", - "baseTokenDecimals": 6 - }, - { - "name": "FTM_USDC_DD", - "address": "7cYU6ux4GwB1X2FKaRruQ9dbDZKUrxZAaWGNJfeoHeGJ", - "farmTokenMint": "4r3uYr4Ph4ctw1chiUaAtwon4stFGHqbSJ6Lym139rM9", - "rewardTokenMint": "a11bdAAuV8iB2fu7X6AxAvDTo1QZ8FXB3kk5eecdasp", - "rewardTokenDecimals": 9, - "baseTokenMint": "E7Af9Fa2U1YqEkQpAYjXwDB5TJUou9VcN3ot33Gj6UY9", - "baseTokenDecimals": 6 - }, - { - "name": "stSOL_USDT_DD", - "address": "AihUw1sSxuzL2i1ELWMXmiRT3UgyRds68iNXwFKbyQnP", - "farmTokenMint": "2kftNiMcrjp9CRqtoLZNwApGEoirfunHPvunenGLz17y", - "rewardTokenMint": "HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p", - "rewardTokenDecimals": 8, - "baseTokenMint": "CtvKaRLzCzRZCcYPwai7NCYBK4ArBj2oD6BfvMgJoiCN", - "baseTokenDecimals": 6 - }, - { - "name": "SEEDED_USDC_DD", - "address": "EsSWWXMipKC4aVHcKjkYdvNjKphxk86DGCYhdF2huoso", - "farmTokenMint": "AjCuWDEZYC9FuwdYpdAy4vLoY6PxMNF8xitQeaNZd1nW", - "rewardTokenMint": "seedEDBqu63tJ7PFqvcbwvThrYUkQeqT6NLf81kLibs", - "rewardTokenDecimals": 9, - "baseTokenMint": "H15WptGntFQifZmJHUzYBV9Mv7P27ofavEsF6yqpLTdX", - "baseTokenDecimals": 6 - }, - { - "name": "ONESOL_SOL_DD", - "address": "2GpXwBPbooPwqxLuM1bW9FaSK5hxaJqNkr7WdPsjoPca", - "farmTokenMint": "DuTybhuJgwECRHDLgtrBuKnfhxve2zXoYXD6cnDikzoT", - "rewardTokenMint": "4ThReWAbAVZjNVgs5Ui9Pk3cZ5TYaD9u6Y89fp6EFzoF", - "rewardTokenDecimals": 8, - "baseTokenMint": "Hva9oLa2GjoKdB45WoHujsX7MTpehByPshMrQpNDmkFq", - "baseTokenDecimals": 6 - }, - { - "name": "MMA_USDC_DD", - "address": "7w9ztS9wcnsk2gqCEvKmQFUBbwhPZPfb5CXhC2onUWXs", - "farmTokenMint": "9hSvWrDqgAr7E8sWpatomKcgAGy3hvgAWPXtGPySNbsy", - "rewardTokenMint": "MMAx26JtJgSWv6yH48nEHCGZcVvRbf9Lt9ALa7jSipe", - "rewardTokenDecimals": 9, - "baseTokenMint": "H9qkbU2XYSQTk6JJJ2TMuZBthfkeCHigmuxB5jiQaamn", - "baseTokenDecimals": 6 - }, - { - "name": "PUFF_SOL_DD", - "address": "HNTRmR36ZXBNakYpfPPq7VJaXzLrNY6hN1Xz9p5s8wWA", - "farmTokenMint": "Grn1ipjetWK7sz5Bq9S1nwD7F7dUsFzM44diFxbMruvK", - "rewardTokenMint": "G9tt98aYSznRk7jWsfuz9FnTdokxS6Brohdo9hSmjTRB", - "rewardTokenDecimals": 9, - "baseTokenMint": "Ge5kuYg5PekrPUeKzngw97Cnfngj8j6NCX5q1jTBkWSW", - "baseTokenDecimals": 6 - }, - { - "name": "SAO_USDC_DD", - "address": "9eVq1gfxbgRpX8W4XctocHEm2U8eT5KzTcnMduFThoz1", - "farmTokenMint": "47PY3ET5oziYHEt1mddYFE7opJnqPbp98yZ1xf6cpgER", - "rewardTokenMint": "2HeykdKjzHKGm2LKHw8pDYwjKPiFEoXAz74dirhUgQvq", - "rewardTokenDecimals": 9, - "baseTokenMint": "A9BeGSRJJYXPrMs81rVZxvkk16fopzgG5YkngntgTu7p", - "baseTokenDecimals": 6 - }, - { - "name": "sRLY_SOL_DD", - "address": "7GAp1xR64GjjbyHbvE28Rt9xLEBLTjk4W3AemRMvTcrS", - "farmTokenMint": "4Xtia3w6AKBNPCYmFZCAQV8CNwUmHYrVQiNMEGdMkRMg", - "rewardTokenMint": "RLYv2ubRMDLcGG2UyvPmnPmkfuQTsMbg4Jtygc7dmnq", - "rewardTokenDecimals": 9, - "baseTokenMint": "6gkZ7QUmxmwPLS2NK3Dr6YHtTPZs6GQrkA595WSx5iLe", - "baseTokenDecimals": 6 - }, - { - "name": "ZBC_USDC_DD", - "address": "AMVd1e1mvWxvJ9LPU3GWjRQ7bfhkwVB69RiL5oRkyAtC", - "farmTokenMint": "2ygRp6eeFaBmfEZngpkVwuVs8hmRbe3FMnF4qiJiFzhT", - "rewardTokenMint": "zebeczgi5fSEtbpfQKVZKCJ3WgYXxjkMUkNNx7fLKAF", - "rewardTokenDecimals": 9, - "baseTokenMint": "7Hoi4adCSBzERdvSiUXtVDz79tiDxMD5HpDv7m9rs3Sb", - "baseTokenDecimals": 6 - } -] -} diff --git a/farms/farm-ctrl/metadata/farms/raydium/farms.json b/farms/farm-ctrl/metadata/farms/raydium/farms.json deleted file mode 100644 index 391f0df6faf..00000000000 --- a/farms/farm-ctrl/metadata/farms/raydium/farms.json +++ /dev/null @@ -1,2317 +0,0 @@ -{ - "name": "Raydium Mainnet Farm Pools", - "timestamp": "2022-06-05T07:16:17+0000", - "version": { "major": 1, "minor": 0, "patch": 0 }, - "official": [ - { - "id": "4EwbZo8BZXP5313z5A2H11MRBP15M5n6YxfmkjXESKAW", - "lpMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "rewardMints": ["4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R"], - "version": 3, - "programId": "EhhTKczWMGQt46ynNeRX1WfeagwwJd7ufHvCDjRxjo5Q", - "authority": "4qD717qKoj3Sm8YfHMSR7tSKjWn5An817nArA6nGdcUR", - "lpVault": "8tnpAECxAT9nHBqR1Ba494Ar5dQMPGhL31MmPJz1zZvY", - "rewardVaults": ["BihEG2r7hYax6EherbRmuLLrySBuSXx4PYGd9gAsktKY"], - "upcoming": false - }, - { - "id": "5DFbcYNLLy5SJiBpCCDzNSs7cWCsUbYnCkLXzcPQiKnR", - "lpMint": "7P5Thr9Egi2rvMmEuQkLn8x8e8Qro7u2U7yLD2tU2Hbe", - "rewardMints": ["4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R"], - "version": 3, - "programId": "EhhTKczWMGQt46ynNeRX1WfeagwwJd7ufHvCDjRxjo5Q", - "authority": "DdFXxCbn5vpxPRaGmurmefCTTSUa5XZ9Kh6Noc4bvrU9", - "lpVault": "792c58UHPPuLJcYZ6nawcD5F5NQXGbBos9ZGczTrLSdb", - "rewardVaults": ["5ihtMmeTAx3kdf459Yt3bqos5zDe4WBBcSZSB6ooNxLt"], - "upcoming": false - }, - { - "id": "B6fbnZZ7sbKHR18ffEDD5Nncgp54iKN1GbCgjTRdqhS1", - "lpMint": "mjQH33MqZv5aKAbKHi8dG3g3qXeRQqq1GFcXceZkNSr", - "rewardMints": ["4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R"], - "version": 3, - "programId": "EhhTKczWMGQt46ynNeRX1WfeagwwJd7ufHvCDjRxjo5Q", - "authority": "6amoZ7YBbsz3uUUbkeEH4vDTNwjvgjxTiu6nGi9z1JGe", - "lpVault": "BjAfXpHTHz2kipraNddS6WwQvGGtbvyobn7MxLEEYfrH", - "rewardVaults": ["7YfTgYQFGEJ4kb8jCF8cBrrUwEFskLin3EbvE1crqiQh"], - "upcoming": false - }, - { - "id": "CHYrUBX2RKX8iBg7gYTkccoGNBzP44LdaazMHCLcdEgS", - "lpMint": "FbC6K13MzHvN42bXrtGaWsvZY9fxrackRSZcBGfjPc7m", - "rewardMints": ["4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R"], - "version": 3, - "programId": "EhhTKczWMGQt46ynNeRX1WfeagwwJd7ufHvCDjRxjo5Q", - "authority": "5KQFnDd33J5NaMC9hQ64P5XzaaSz8Pt7NBCkZFYn1po", - "lpVault": "BNnXLFGva3K8ACruAc1gaP49NCbLkyE6xWhGV4G2HLrs", - "rewardVaults": ["DpRueBHHhrQNvrjZX7CwGitJDJ8eZc3AHcyFMG4LqCQR"], - "upcoming": false - }, - { - "id": "HUDr9BDaAGqi37xbQHzxCyXvfMCKPTPNF8g9c9bPu1Fu", - "lpMint": "89ZKE4aoyfLBe2RuV6jM3JGNhaV18Nxh8eNtjRcndBip", - "rewardMints": ["4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R"], - "version": 3, - "programId": "EhhTKczWMGQt46ynNeRX1WfeagwwJd7ufHvCDjRxjo5Q", - "authority": "9VbmvaaPeNAke2MAL3h2Fw82VubH1tBCzwBzaWybGKiG", - "lpVault": "A4xQv2BQPB1WxsjiCC7tcMH7zUq255uCBkevFj8qSCyJ", - "rewardVaults": ["6zA5RAQYgazm4dniS8AigjGFtRi4xneqjL7ehrSqCmhr"], - "upcoming": false - }, - { - "id": "AvbVWpBi2e4C9HPmZgShGdPoNydG4Yw8GJvG9HUcLgce", - "lpMint": "C3sT1R3nsw4AVdepvLTLKr5Gvszr7jufyBWUCvy4TUvT", - "rewardMints": ["4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R"], - "version": 3, - "programId": "EhhTKczWMGQt46ynNeRX1WfeagwwJd7ufHvCDjRxjo5Q", - "authority": "8JYVFy3pYsPSpPRsqf43KSJFnJzn83nnRLQgG88XKB8q", - "lpVault": "4u4AnMBHXehdpP5tbD6qzB5Q4iZmvKKR5aUr2gavG7aw", - "rewardVaults": ["HCHNuGzkqSnw9TbwpPv1gTnoqnqYepcojHw9DAToBrUj"], - "upcoming": false - }, - { - "id": "CV2WzYEphJnNFfLLRinDo9BqfpT3rRhxEwbaw1RiKnyQ", - "lpMint": "DWk7Xg8q3jotVGuVBteJ31PjdmEn2iyjQTectbrkjBaq", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "8ZgRpndiMyVDarZe871ufXCFDbmyZuH4bauEdweiz7iX", - "lpVault": "m352YFLtVmNxFnLb9UYkKhXMsNrQW3VerEX1gLqKxK3", - "rewardVaults": [ - "Di2uxoRXywcZTbHgmn8AKvKa6irxsBXMpeQGbWUkdA6h", - "9LNn1MTvNaRYyrffJi5xAQ4mzGLpekWqhLmPtTga669B" - ], - "upcoming": false - }, - { - "id": "GUzaohfNuFbBqQTnPgPSNciv3aUvriXYjQduRE3ZkqFw", - "lpMint": "8HoQnePLqPj4M7PUDzfw8e3Ymdwgc7NLGnaTUapubyvu", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "DgbCWnbXg43nmeiAveMCkUUPEpAr3rZo3iop3TyP6S63", - "lpVault": "J6ECnRDZEXcxuruvErXDWsPZn9czowKynUr9eDSQ4QeN", - "rewardVaults": [ - "38YS2N7VUb856QDsXHS1h8zv5556YgEy9zKbbL2mefjf", - "ANDJUfDryy3jY6DngwGRXVyxCJBT5JfojLDXwZYSpnEL" - ], - "upcoming": false - }, - { - "id": "5r878BSWPtoXgnqaeFJi7BCycKZ5CodBB2vS9SeiV8q", - "lpMint": "Epm4KfTj4DMrvqn6Bwg2Tr2N8vhQuNbuK8bESFp4k33K", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "DimG1WK9N7NdbhddweGTDDBRaBdCmcbPtoWZJ4Fi4rn4", - "lpVault": "jfhZy3B6sqeu95z71GukkxpkDtfHXJiFAMULM6STWxb", - "rewardVaults": [ - "Bgj3meVYds8ficJc9xntbjmMBPVUuyn6CvDUm1AD39yq", - "DJifNDjNt7iHbkNHs9V6Wm5pdiuddtF9w3o4WEiraKrP" - ], - "upcoming": false - }, - { - "id": "8JJSdD1ca5SDtGCEm3yBbQKek2FvJ1EbNt9q2ET3E9Jt", - "lpMint": "3529SBnMCDW3S3xQ52aABbRHo7PcHvpQA4no8J12L5eK", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "DBoKA7VTfnQDj7knPTrZcg6KKs5WhsKsVRFVjBsjyobs", - "lpVault": "2ucKrVxYYCfWC6yRk3R7fRbQ5Mjz81ciEgS451TGq2hg", - "rewardVaults": [ - "3nhoDqudHBBedE9CuUqnydrWWiMFLKcZf3Ydc9zbAFet", - "B4LA1grBYY9CE3W8sG9asR7Pi2a6eSt2A8RHcXXKJ1UM" - ], - "upcoming": false - }, - { - "id": "Gi3Z6TXeH1ZhCCbwg6oJL8SE4LcmxmGRNhhfA6NZhwTK", - "lpMint": "3hbozt2Por7bcrGod8N7kEeJNMocFFjCJrQR16TQGBrE", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "HoUqzaqKTueo1DMcVcTUgnc79uoiF5nRoD2iNGrVhkei", - "lpVault": "9cTdfPLSkauS8Ys848Wz4pjfFvQjsmJpVTUnYXffkubb", - "rewardVaults": [ - "2MMFGZGEjQRovNeNtj1xN9redsVLYTMVcXzFTLQCw6ue", - "6DhjnWKLbxnDSFZApaVJXCY2wbzgt2mYhvW3yBreaYsY" - ], - "upcoming": false - }, - { - "id": "5oCZkR2k955Mvmgq3A4sFd76D5k4qZn45VpaCkp8H3uS", - "lpMint": "As3EGgLtUVpdNpE6WCKauyNRrCCwcQ57trWQ3wyRXDa6", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "EPAFdt4SkxUAq1QMJgaZZ4ouCDaisrUJJddhZRGPxHXU", - "lpVault": "DduzAhNLsqaeSno9aELfZ8TqtWh9c4kyTGRwxK4JaBw2", - "rewardVaults": [ - "DpjXRkiQEBXqLh8jpHZZRztwEej1GarxVvpBi1SR8rKk", - "6fomjaXLVgTbTaQLGRnKsJGBJ4Rt556v6NhynWDnrb5u" - ], - "upcoming": false - }, - { - "id": "BKi4WUCGcaq9hz9H1BVKGQZYndi2pfAThDXKRnJqdcuS", - "lpMint": "6MLGHP6mLcXssY8ak12QSoLmjoQMxVPdRGdyvbJGZ3Ti", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "EP2aYBDD4WvdhnwWLUMyqU69g1ePtEjgYK6qyEAFCHTx" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "EPq8hQgAGc5vBEw8sqJL23VKQg1Y5EyFUUy3ifdzfRoY", - "lpVault": "DY6VGNyiYnFKjPbin3LUSbHYwgVsis824FSqR6pRk6xN", - "rewardVaults": [ - "9TN3PHthEMWDtnP9nBkUcjirJqooNELSw6x1UfJzWX4y", - "8mQ5sSQpnoKwkddA4VeenZQJMT6HF1T4BQdCNg713CV1" - ], - "upcoming": false - }, - { - "id": "GFWLWNRgpyG5P6XYSnnhsFGnerRva1NS5exnhKTcHx7A", - "lpMint": "3KSDx1v18eMZoZGcMr5VhPeG7c6TAF79j37KTfR6TnnY", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "EzfnjRUKtc5vweE1GCLdHV4MkDQ3ebSpQXLobSKgQ9RB" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "88oLt3WafZ1vjZLtRERawZTwcqkUfTQHRNwFzyuxHiNq", - "lpVault": "2oGJxHNGi6r1WRSbMMNcE8pPV4CsQn1f8iehmfJStrvG", - "rewardVaults": [ - "FsgdfxhzdwWow25jjLnnL2dsaXovovG1HhEKZ2sky9RZ", - "EcQLodcbH7joWz126tzapZg6ESkfBC1R5zzkMifFaRvs" - ], - "upcoming": false - }, - { - "id": "3EzYvqxa4Tzn9X2bWrGLejq79ZPT9hoomk6qp9dHEUPy", - "lpMint": "9Dc6HWJ6hdbSGbCwjXhmr76xrzioCWZcxipAaADmoyNS", - "rewardMints": [ - "HBB111SCo9jkCejsZfz8Ec8nH7T6THF8KEKSnvwT6XK6", - "HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "Gm1vZ8qWSgFxFTtkXwCdtZMa1pnNBngTseWjfuaPJ2Ns", - "lpVault": "DzkdCTMMCzEY8grakdePi6U3PKiwfUwjEFJF6qHS1VZs", - "rewardVaults": [ - "DT3QWgCtuVmbq2BYXehtZssvbhrjYmpuQEN9VZxsbB32", - "2d9GiVNzGrFmyrALosyCyc2oJfygRAHjeuScoayEG1xQ" - ], - "upcoming": false - }, - { - "id": "B7A3hAej7ZbAsVPM3M5ietDigQgxyucYPANJSGDVpQEw", - "lpMint": "AVT97ti2a2nyQJBEYoXfJ3mfzxCcVnr7qPf1514RZQDM", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "7s6NLX42eURZfpyuKkVLrr9ED9hJE8718cyXFsYKqq5g" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "HD1FfUrGsXz8JBr3opqZQDmLQhbqi9gDPodbZrs24jdX", - "lpVault": "6XAFthdcYz2iGfAmX9YBf1XWWcks4T1wKivfHxRfynNu", - "rewardVaults": [ - "EfgbGcmdM4dyU4tthFVtwR4p2Yie1LdUGRyBxyubWbKb", - "14VvimEXQ8uHsrrr6xy5ZUQz63rExjFbffNK9uFHHKuV" - ], - "upcoming": false - }, - { - "id": "DjC45MNK8VtVTEnvr7fFcbNnGGS1v4kKx5iziKj8Cz3e", - "lpMint": "GtmyX9CAGa1EPVfHkxFRjm8yqk7KSBvJayHu2dBsus1a", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "htoHLBJV1err8xP5oxyQdV2PLQhtVjxLXpKB7FsgJQD" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "44k5wdUhRPxVqzAb4FdBdt37ZKwV4ijUzhZTZXhvosvn", - "lpVault": "3C8hcn5kU3t1QjGhvUXNQzzCBVvTRgJBHj3h6sSKhVHj", - "rewardVaults": [ - "7U1vMSk4SbyaTgmajD5B7jzGPfthCEYgARuqBKtXros", - "76QRAog65KgrNv3bAkLKduUX9SoFeyJ5oWhrRj5qfgaf" - ], - "upcoming": false - }, - { - "id": "qnJgKvM17GAugsHwYH9jufQ3WhCE8TKpyrQ9qXX7hsX", - "lpMint": "6pZr6uJJoMcGtdbABfdGH4rmcbTHQA6YcBaV3ndddRay", - "rewardMints": [ - "BDrL8huis6S5tpmozaAaT5zhE5A7ZBAB2jMMvpKEeF8A", - "HBB111SCo9jkCejsZfz8Ec8nH7T6THF8KEKSnvwT6XK6" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "2Rsj9TbYdNRcdCr7Ccqo7pxWVnoDgCiS4P724mzNe4de", - "lpVault": "G6Nry7M5UbWtv4eopcnteGvAcDY5uFvCaZoMf5NoKXAK", - "rewardVaults": [ - "E7FuKV5LYSkyMwZUBegFpf8eejSTLE9aVNMq6QCf3oM1", - "Fsy3CMxGmN72p3tFqVjmes7sNtksFkVyPdPFGmzzHkJS" - ], - "upcoming": false - }, - { - "id": "7Pxe2cjnc2KpDfTDm9y98KRuqPMLG94DBwWQZnMszEra", - "lpMint": "DsuahHP9WcG4wRjfj1GQydhQ58PgZkPNmwPot4QpdA9r", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "BKipkearSqAUdNKa1WDstvcMjoPsSKBuNyvKDQDDu9WE" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "AVmHH22TDZpv5B9HxutR9eqsvot4oQX2b2Kyg9QaoM71", - "lpVault": "EDW97WpQNEWmqNfUV6ASarFAhk8Wtf6ECS6ZdqUFLtnP", - "rewardVaults": [ - "CsaB4WncD42Gg7HbBDLQcFDTUq72ZnGJxnwK9x8rpPj4", - "FjyrKgnvZjuLB2ktiUZLbNxWBkHuWUNmFLrgHrihVxW1" - ], - "upcoming": false - }, - { - "id": "CeUDbMYVkuXVQknd7H1QpnacjHJpscGgjAxCFJ4auXjB", - "lpMint": "7GtZ2MnsH4PLFyvqWmyF3EQXgW78kBXCuAXt41vdKd1y", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "HBB111SCo9jkCejsZfz8Ec8nH7T6THF8KEKSnvwT6XK6" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "8npjf35Cd4uD4YWV27UfoRTAhvA84KciQuw326FjhY4n", - "lpVault": "2mPojb4vFb3zyr4Kb4Ebbk1E3fShPhhsoLKohB1WeaJP", - "rewardVaults": [ - "4iPjj2v4QtMcGVeYpZT7Ta3LNAatf5d3hSZNA8ydpKtF", - "7czpuHw3mYsY18ArznwT84yaSN1k1kuy3bMrmtFRmozG" - ], - "upcoming": false - }, - { - "id": "D5sbMJUcAWjevdGwuGvnexu8kCTRozRpryQgvUY4hctv", - "lpMint": "5mNdSmZEiX9jGZFPVpp9nFFQHDKWF2sHZuoU3uuC9wPN", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "HBB111SCo9jkCejsZfz8Ec8nH7T6THF8KEKSnvwT6XK6" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "6LL2WDWbzTn3YZSgJ2yGv2yftDbeGPjUw3yAksSn31zX", - "lpVault": "B2nXsHNG6DCHTwrBMESN7jfiqiHnf1nFXgE4jnKMvHCe", - "rewardVaults": [ - "Ea3WzVQXZ13w22NDsJG4C8XB3bpkzwntpbYdiD3t2SEm", - "9EGqdVypPjQjS8ujgoYgEGLb9nq5yvnFBX4YZyegLdyf" - ], - "upcoming": false - }, - { - "id": "Dh5FREugnMNrkJ729aD4pruARGPK4PbtGywX6FAk9Z5Y", - "lpMint": "3qn11mgGLAqZHucw8vwL2hsxRSHpnw2Jjo2HxicFN7hi", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "3UCMiSnkcnkPE1pgQ5ggPCBv6dXgVUy16TmMUe1WpG9x" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "DLPBoTH5gc5vNs8LDgQp4UgLFfEwFUAQppZXRp9iVR4p", - "lpVault": "BVMyPZZeJw7oZC45cgdxprLY3CLkwQ83rjnBQn3HEHu5", - "rewardVaults": [ - "83PiNkz9wac6V7GaPnmy1QP8z8HS7pBHPMnQCTBaCJns", - "GuqtC5HxjMnKLVLcxg5kcijuvRC3ZY7wVYBnt6LgDcRB" - ], - "upcoming": false - }, - { - "id": "6SUyGVgmP64LntGLqyE2K3rnzL4H8THkBf84P8RkgQVU", - "lpMint": "484Sp6kJTpBM57p2VuAfCZrRFXFBjpQnZcHCR7jaP98f", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "Czt7Fc4dz6BpLh2vKiSYyotNK2uPPDhvbWrrLeD9QxhV" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "GmZp5B8sHzH2rF6quCBauZWSF4ZdwmYGp2Cki4TpZQLr", - "lpVault": "Haw2cLSWGJAKuiuAbvg8RisLqgMUPEmNmvjddha1L4NC", - "rewardVaults": [ - "8HMDqaYZQrDpQKahT61VpvWBo1ZeruniEnifnNvCnpVz", - "3bsM5WrCEFkxvJUDohuEKYKezPy4UbBH8sp5xCNfcFWU" - ], - "upcoming": false - }, - { - "id": "31yEvMCTq8ExteDPNbNFojnj2bsXs85VvVC5UcFH1A98", - "lpMint": "DR5ZPstTWbsdkE1UWaUgjvanB822JYmd1QcwCuqVaRYD", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "PRAxfbouRoJ9yZqhyejEAH6RvjJ86Y82vfiZTBSM3xG" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "4VAUQjivnEQtGXk6M4v6u3GoXmFEanNkZdcZEjyceEQ4", - "lpVault": "HGVEsWN2E79iSFZQ2xYapRY8KET8DwFfrJp5M8K6XzD4", - "rewardVaults": [ - "FYcakvYh552rqR5FZLiFgjHiupTWQ7H3B5YiwwxGmb89", - "8pS2b7ZgUQyxheq9bVwqB22RSupXT9ipn4UiMLfwAwSD" - ], - "upcoming": false - }, - { - "id": "HdAQ2fyRjzRDbLyURhLR4jDGLvQu8cb3VJwicVm5GfvX", - "lpMint": "5jQ9jc92SUmYsQ1JVHDuyUqctdtfwNWjvdGLHKPnzFT", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "SLCLww7nc1PD2gQPQdGayHviVVcpMthnqUz2iWKhNQV" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "FRvzZyFJgdhPbvbzvekXXMYPTRjzo8ZkT1o7isZScPs9", - "lpVault": "AdTsU71awyPm8EjWvKyKt65zTDdB8YfiBH5My84NgF79", - "rewardVaults": [ - "32tQMmtS9quR34qaQjMHgMmC77TsYqEgGQaZR6nC3svj", - "5nmsYbpta2JTTWhZeHXQSd2YKfCFjdf5aPkdx5hU7jfQ" - ], - "upcoming": false - }, - { - "id": "GEPu4gZy3F5zYzVJeAbj3pKgLSVbQez1xSVooiNRrrKx", - "lpMint": "DfzAJVAi6z4nUxsUY1k9yW6LVc2ecbBScdDRzXgYRRFp", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "ratioMVg27rSZbSvBopUvsdrGUzeALUfFma61mpxc8J" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "3EZVwMYMYncVrfkHTVRC9YEG9B3AhScyUzCp5rWChSah", - "lpVault": "GAiceh5Amb8q4Sg7848Y9JFbfYWEMh34ze43CBzjdguC", - "rewardVaults": [ - "4Shywo9SWpshcgJgSVX3u37c9YsXi88v3cvLYXFQGXrf", - "49fbnzZys11yDN8KxTkrJ2Pw2tgzyFmdG4mQduJYGz3k" - ], - "upcoming": false - }, - { - "id": "6Y8426w1MzEBoMezQMu6JKi2ECznk3Bt6MJvbQLkwgph", - "lpMint": "D7F986x22g9uckCbQabpcw8HuJk8zRcAteDLbcCUVjm1", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "8U1fjBLZVRP9kuVbJkdBRPP5eWrgQH9RFmgJCR5ewToS", - "lpVault": "5R8wky1K15p3UUjr3CpW2hafJyDz6yyFpWb3ZQWHY8th", - "rewardVaults": [ - "7o8x78w86YSbrFBi7akYBUxbf2e4R9UT5jCVMMsSegVc", - "BA9m3qN2bV3uR1zJQQHhBEET2eDQ3Hdwno9VEVmHjiHG" - ], - "upcoming": false - }, - { - "id": "4q7DjntTWaY9dzmf5f6fLirRbgnBjQ7ZwL8gA7ZQBWaT", - "lpMint": "94Y3jaf96ysGqebzRP71isD7RKxmuhkyXK88b16ToJhE", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "5ZcdQZC1xT3gic34VvzwuddeDVi7BSUg1Rv5SXX71HPA", - "lpVault": "GzQtHx4qnRrh9diHVnZRWJijFU7xxYueEzaaszdi2Hgh", - "rewardVaults": [ - "4Qppfw4ywsZo86xMovKHAKkTVePuKAJvH3LEPR8RYZbF", - "DRwA4T96BMB2ave5JSg9sFHfk4ecXDj2EjcNd5d7U6jC" - ], - "upcoming": false - }, - { - "id": "9juVTkJ7kYNsrwyvbAVdY8ZJdHeJAmidqcAKsb9P7CDW", - "lpMint": "ECoURhBe68iQtNv3CEiQnVjzWDmD4jZf3qF77CzmCJGY", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "7MmEp1wBNRGKD8YAimPrPG6aE3hJwsKk34QLK3TbB16a", - "lpVault": "6EsuUQDTMuV8Y7msPH1GBkDPed5tdnbJG3DrcDFJiCsR", - "rewardVaults": [ - "Fk1yz3zRqRQo2BuQUnGKNHKaY1uibCEqdtNxx93Ek3A9", - "B6GGxpeganV7csX3Df5i22NSGvFfDYa54s3Ssr61k5tv" - ], - "upcoming": false - }, - { - "id": "GBjTMHf9TsRdMnP6S3ewAgpSoCacpZqQF1tXmnchborv", - "lpMint": "2HEdj3PkxeMhkf19TW2pZbV4bEFJ5fyZHHrswzUZg5VL", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "66edZnAPEJSxnAK4SckuupssXpbu5doV57FUcghaqPsY" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "Fh9hoWD46fAixcUbgRZcgNVf6ARxhF7gatZdbnSDHqjx", - "lpVault": "6JQkmgkqdaXEXgm1b1BvjaxwJkvZAXAew51rWMFh1cyY", - "rewardVaults": [ - "CzEmZxHRKZx9eyPBFNspThf52bd8rL8AgnbjY9M1kkRV", - "72aDUEj52eqN1tgr6GNWtb98dcDe75nsBigux3rCQnJ5" - ], - "upcoming": false - }, - { - "id": "5Eu1PH2p8ScdbbpKxUEqzCMzNnVzpQCiVUKrp8kZsGoW", - "lpMint": "5HRjr4s8e6QF8LGv1sqvedJk9sNxenSgfEuU7SNamAJJ", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "AAXng5czWLNtTXHdWEn9Ef7kXMXEaraHj2JQKo7ZoLux" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "C86xzN4AHHkN8TTdtvBJMbrcTNE57LyPusF47sMC39u1", - "lpVault": "CdfDZWMBqwoJU3GRPVi5Vq2szxg73R6xcqNS23ix5Q2s", - "rewardVaults": [ - "H5AczyRT4wsj3bfhkZXuVtsJnsA9MbiL8xQ2yJbsvmaV", - "JDuGbk9QTkxvvDqWWpYq3JwgNDVoccnwT6Lka8ByNsAK" - ], - "upcoming": false - }, - { - "id": "94u5pHLkEhkxiFqRTcRgKEnEn79Csf6iaXCxNFPmqoSt", - "lpMint": "YxFUkd8xiLTNRcMspfMTiWsY4hfajir9vNexqntUje2", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "bonegFPgrpZ4bfVn3kQK1aMbGYddWtfMAywNt5LsuVE" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "Dzbwfuif9XBFYNqHonbjnqGGF65wgi7N8tkp9kciPT4c", - "lpVault": "DWgLDJ695vcdBPGFS7qiCVw8mPpXSNuE76sXXpVMcrr", - "rewardVaults": [ - "8WpWE9pVeqkkvRGNKGWt4GBBe8r6bvieYXrNiD3GcXBa", - "E4aMXrpnNqEkDEAmZ4nquzJSiWsTwdgwjxYNf4yr78WK" - ], - "upcoming": false - }, - { - "id": "DaFyBEGYC5YZXdpNcH1cXegDaiUu1Diqrvb64HRhfRgC", - "lpMint": "AJ236J6tLen18QW8t7XLAaELyUjg57HcQgSq33aH8Qkq", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "zebeczgi5fSEtbpfQKVZKCJ3WgYXxjkMUkNNx7fLKAF" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "CWkd7YD8ch9oVLNKnmW7LAA8FsMZtmah3J8LKTwnLREx", - "lpVault": "ECaVZBDy4qopwKDxCk9v3h6q2wvRU8Pe97RiYn8CvHKE", - "rewardVaults": [ - "Fh4R78nzYTWrwBkieuAWQ7cDimu8UDhukdUqbrpy3Zeq", - "6cdrE6aSip66vmeXeg9iJMLrJWdrEVqkHNygAxoL7n7c" - ], - "upcoming": false - }, - { - "id": "HsCu8MR3vHcr2QbKGGnrn6Bo8dcFzFAugqdV9wVJXcFV", - "lpMint": "6UjtYnDGbQ2Y2e4M8VJUeC6kXy6hdGRecMzAbjVJDAiZ", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "DMCUFm2ZAnSU7UgsdVq23gRogMU3MEBjPgQF1gK53rEn" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "GEg83ihoLeswkmAFrxnvbGB8xWRw6Ba1oKvkhxAP9V3r", - "lpVault": "2WzeohvEA5vBLUWuvtPR1phKF3AenPLMKfrjm9Vr1tv8", - "rewardVaults": [ - "EzjyTWqQ6Q6K2vUfMUHNco1SReqtpvQ1BiNaHFWn9TCY", - "8TmLnq9Qh3qvVnyBFRghFyeudVVhU7DbpSuJKWpwH5si" - ], - "upcoming": false - }, - { - "id": "E1cnHvk2sLkhKdfd2EDaQyhG3e7Efqj127FJDSo4vZuz", - "lpMint": "BREhg1HCGk34wuUbh8CNzvE7Sj8FpiwdAVypKWHhZyYx", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "YAWtS7vWCSRPckx1agB6sKidVXiXiDUfehXdEUSRGKE" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "4aFq5wVyV46aJ7uFwHwDzMSL7vRqqcSJKrdRPiUJaktV", - "lpVault": "5F9dJJVVqaEpjqgcBGapfiDZ8ie2yxJKor1gmqmNpRvV", - "rewardVaults": [ - "27N3RxvYb6KA8EtuJubeBBAn8dG6UqWGYasGt22QRGWv", - "446S42ecEzfoaqmcacn2cN2mywvKZJWyBdBfQ22JaVbi" - ], - "upcoming": false - }, - { - "id": "5vkuK285fSgL3tjvNTYgiJnKA7MifVeQ5zSkUFEGXCJ3", - "lpMint": "4UTG7MGS7AgeRpGGZg9RmrPzByhQTnzZty9oVRt1SbdH", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "FgX1WD9WzMU3yLwXaFSarPfkgzjLb2DZCqmkx9ExpuvJ" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "DsKfKaQw4booMDdWFCQbidbqVwd87SUU2vWbYdSpLmnx", - "lpVault": "9TepjQWuP5P4PsvvvULVMYJtPQ6NBMEPqikGPL6549nV", - "rewardVaults": [ - "PK5KVHsnadvVvKz4r2mta7FtPGVndx6TYjEbkBtENX5", - "Ae7VfWmYx8FBrZDx9xtbcD45L2D4MHZCiTbu7vTdWQdV" - ], - "upcoming": false - }, - { - "id": "3r8spCbDiNeMxyru5CJCCo2sNX851pEzwAg5YioJsryT", - "lpMint": "CugVqB1qaCtQ9ZNbRM153azxHtU9ueYyxWWQ3uG2NnP7", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "fujiCeCeP9AFDVCv27P5JRcKLoH7wfs2C9xmDECs24m" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "4cRonzFNe1cY4AfuB3peCjuBm5igFH3sRE4UPJbR3tiK", - "lpVault": "3Lq22VxvF61wdwJ7GAPMhxCfvhAdbfB1LwSoAWhYnH3C", - "rewardVaults": [ - "GZ3ZpupSAodCjDpXBg2xq9uScA2iaXgPs5M4mckPf2E7", - "HdwutyRUYNUWumWnMNEN4TYooHnyijemMQeNZvukMFKg" - ], - "upcoming": false - }, - { - "id": "68sMPVDR2PvJnYkLCQnKD3g7zvxqEUvJ1Ws1kj8BvdKU", - "lpMint": "Aox49moN6MugLheGwqMBTLi7aFojfhtiLxtHsaQzJgoh", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "G9tt98aYSznRk7jWsfuz9FnTdokxS6Brohdo9hSmjTRB" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "4zn6X4aLNjUvMx6hYKTxG1Zw9ixYTdTWvJSrDw6JK8rJ", - "lpVault": "HgYm9rYe2ge7tfBwCTW8tPALUiFvroKHmoT3uCr6gs1g", - "rewardVaults": [ - "9qjSAs3qTpwmp3o78hR9F7guE19XP5UW3beYZmf1RWkY", - "6Z1472qQwjCK8msDELY4ZVBcAFCbfwGtKyzZwHQCiAd8" - ], - "upcoming": false - }, - { - "id": "6HcktBcbpue4N41AoGv8zndKRkPPkLVcWeULjobB9NrE", - "lpMint": "5XwLgkEZYuMai7D5tRv4kseYjvisqztdotuWGvyo3aBn", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "seedEDBqu63tJ7PFqvcbwvThrYUkQeqT6NLf81kLibs" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "6GBPs5u5Hvoo7TxP8D4L5TzDrQDeEthKYNyWGGhdkV9k", - "lpVault": "3DKR11sq7hBuCPARSYBZaw9XEarvRUC94Wc3fmfy3kCq", - "rewardVaults": [ - "5rUKyj9z8ZgCxeaT7G2E98HH8EGW47btCG2xykEgArXq", - "9Yt9XqbAvQPQnCawwfSCPbVD8ntEnkENVDwuDu3DnYg2" - ], - "upcoming": false - }, - { - "id": "7ubJHEDK5Uhqn9SgoauCTzMkGuA5kwvfuTpHNkAuF5y8", - "lpMint": "8uDVKmVwNmbXHDB7rNKqtpcT9VAsFHTJ5pPYxjyoBbNg", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "9zoqdwEBKWEi9G5Ze8BSkdmppxGgVv1Kw4LuigDiNr9m" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "Ebwcrt8XxderseDSDH8DzoMA3kHn4rQVY1LrL3yfJAdA", - "lpVault": "4aQks5a9M2rkfYscjMSoj3Yw58c4TECM4Wo6pnVE3tdp", - "rewardVaults": [ - "EfPKNQhWdkwnf4RxFEqcXBoG9iDkxJT6cpAuXfLdEjXk", - "4AVreDe4nJs88U1PEWXxr6BmNjMZ6d6oKrqa3kRgvDUP" - ], - "upcoming": false - }, - { - "id": "CmM9nTuYXkvMxAYptzfY8sdUSe9LUUoL2Pa6xaP4A6nG", - "lpMint": "23Ki3fss6htv8ZVGjobe4cYJffJP1UjwK1PyVmtxE1eh", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "5LSFpvLDkcdV2a3Kiyzmg5YmJsj2XDLySaXvnfP1cgLT" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "By1o7kjb3cX8k3zMf5XmJskHDh7KjkPMK25dnRXbqdah", - "lpVault": "6KtwhGoYDyPAD1YLbo5Gt2F6f67tg2NzenhtfZReVUEy", - "rewardVaults": [ - "6kzf58q3FRhiTdi3iGJAs2dJ6kHTrAgueD2B6Voz1bKh", - "Bbt1pCx3rtfBnrJmgu6sGbZmdWVBMZjX71Zh91d47mS7" - ], - "upcoming": false - }, - { - "id": "7YoBkrmXJnUqrC54HK16mCavowFNCFf8hNiV7GwfVXQU", - "lpMint": "FTXsrept22Ub4MjDSPgXaAboRi13GmKJhuaauoAXWeZJ", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "76aYNHbDfHemxSS7vmh6eJGfjodK8m7srCxiYCrKxzY1" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "EY1aZ1jq1FpqtmyDMfPqfTRxXpXVr4BfkyWVBobvdc3y", - "lpVault": "4rFebb7qsVmBnL7ELUhmwirgWjuPNq3o7iwqdw1FeJEd", - "rewardVaults": [ - "BptxDgeGaSbtUzZdqhCxvNrQ9W3SpLAqQ3UcvqRynYz", - "J7b8UWbEoKYw6KQMgaLmrQRVuSnXPvwL9cekmr9dJq9x" - ], - "upcoming": false - }, - { - "id": "BYRs8rwnXBJYf23M4BJ4SYW2zjJvVrsgwDezWSF9qju9", - "lpMint": "8YXJzgWrbnJDQytphH5BgDbz7ygoxQdD9aBRFZzVwJEJ", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "76aYNHbDfHemxSS7vmh6eJGfjodK8m7srCxiYCrKxzY1" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "E9CRhiCdFz9A7mi9YaXvBG4kGrJqofx8Am9XYjEdL83Q", - "lpVault": "42oqJAKQ3PvTXuYzC9gK3f2UNGre5JnCzBGe1LCDfrM6", - "rewardVaults": [ - "3MJ3hAQKkDTpWR5nMtJZVNkPUaXCZy6jjpnDyRLSxt8C", - "Cfrn1mdxWWeS8QBy4uuAjo7kmcCas7mQoh6uxQ4BN9SR" - ], - "upcoming": false - }, - { - "id": "7jhxXfdepg7mxmRzU1T3Gpm4EKbmtgZ7oWBiGMh53Ykd", - "lpMint": "21rqpdZbZTMyzsfrvNNLzhQSz3oEC714EyiRfzNBXyUz", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "FLWRna1gxehQ9pSyZMzxfp4UhewvLPwuKfdUTgdZuMBY" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "Ehq2Lziqu1KsRdcamv4NqbUbqHtAVuLoNmupZdzazgP8", - "lpVault": "8PDTdDaGYwy7U2SsUy3j2avCk5j6CjXwxmSHy8HHjNjb", - "rewardVaults": [ - "9xFs8pJ7nvhxQZSW751acwzJJikE7QbnqycKcmQcUnHv", - "3kgHkd5xyM9bFbsGgis3JqGtMzG4mDE2XSLAG7CgjFwo" - ], - "upcoming": false - }, - { - "id": "8QAZXSY99fCxp9FRG9W5JL4uTkicx2C7KAaMumVKLpVA", - "lpMint": "GTy3TKmh3Ejrdh7iTALUG3PYv4VC7wgwM9vGgdLj6Rus", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "HJbNXx2YMRxgfUJ6K4qeWtjatMK5KYQT1QnsCdDWywNv" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "542VDrLkDRGJPjREBaZR3NUXoKs1zJuVKNueDY8fb2aa", - "lpVault": "CGXMtE4bMjzes5jtzJEiRAAvmdK2spq1aaf6ZThBKBFs", - "rewardVaults": [ - "swUGv4QuivDJyUUgPinBseAV24mTzADEVRpCiSCNZz6", - "2Exk1S4bBovyuF3L4HV9FtVD64WFEouNzMiFoDyb6vNp" - ], - "upcoming": false - }, - { - "id": "ABBtgVwJFHCbvNi9JoEBHwNBLcbHzf8kYCMAEd2xjze5", - "lpMint": "7HwjdFEyGu7tQia33GFB4iFEa5dA7k4gr6BWUGS7tyyq", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "nosXBVoaCTtYdLvKY6Csb4AC8JCdQKKAaWYtx2ZMoo7" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "Aos3tsgPSRhzGEoAmZAiLeY8jFxQwAzikjRJEWaBAXR9", - "lpVault": "EFBfJ7J45ZefPqRqswBXwtuYwajnEZMwxR9KiY1FKbut", - "rewardVaults": [ - "Fdiav35ei1HkpgSmDTG5igPiSUF4tshRNuuW3KAsqSjn", - "5SAKfiRatUHCcCHMi6uxqAPuw4RvXFZAbrE8q8FzpYum" - ], - "upcoming": false - }, - { - "id": "8Zq81uwAeEUUgoe9fz7g25vXr4F3vJfJT5cZCxHne5NE", - "lpMint": "Hrip9d8f6iQ4JxfB85JyGGq3u2WgpmqRSXJZursm26hd", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "PsyFiqqjiv41G7o5SMRzDJCu4psptThNR2GtfeGHfSq" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "ADGv5omdvchYV1d1krEXhSWLpVvwpimHhqcs9RAL89Ms", - "lpVault": "4SWX9xNVpHQ7Hwc44nMvtmbGovj79tT8XvGnEpWMXr4N", - "rewardVaults": [ - "HgrZSAegpnYAtyUHZcZzmBdh4RLuHAwbdKYSMv3wMF4n", - "E6MdJB3aH265DxFcyDkbru7h4cA4htrZSkiE5fu92V8m" - ], - "upcoming": false - }, - { - "id": "6wUEfWbVGKWgjBbUhTEq39maofJ3gRumycyMqbrwX1sT", - "lpMint": "ExkuW75SbEGPm6i4uFv7Rnncd3hY5whirtRPTujC1Yoe", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "HovGjrBGTfna4dvg6exkMxXuexB3tUfEZKcut8AWowXj" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "9mWZ7x1H2KFPV8KcgpbVx2czuKy2GtXBw2jXcUXCGpVH", - "lpVault": "FskuB2EgKPGHyK14SSPdDscvU2MGwxzoeZecUocXgMyK", - "rewardVaults": [ - "FE6Fm8ktpFK9gEwLgDZA7YyYUw4iSkWUiLKgD8rzZTzk", - "7zWwZ6wzjGuYbgA5K97jYj538RqBosHTLNYVPg6nyunP" - ], - "upcoming": false - }, - { - "id": "FAJX3gVHKfiuT2AWU3CPfv3DJksQJtn4QrLuBo1zjoBp", - "lpMint": "7HnBaMZwUA8FKhsiHu1xsxvwpxcGMoDj7XFqgmFnw6ft", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "5Wsd311hY8NXQhkt9cWHwTnqafk7BGEbLu8Py3DSnPAr" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "8U95TuJd2h7uycPd6ktD9WdLVKHZW5MYz6htnTeqQcXq", - "lpVault": "FN7BB1p3JJj1yR55RUV37cen9JcsMFgLtwjCbTrVxHcX", - "rewardVaults": [ - "ux3AoAoxqQpmuZgnncayerYMRNNWB96fPv5gUCMrXAK", - "7BmHRKAeWjyVZPUWHjiS7yq1C7vkzrkHDNU3MquPTFb" - ], - "upcoming": false - }, - { - "id": "CJ4GdUHJztug77M2JdGgZ689mitsKysFZFi8h1MDHBaj", - "lpMint": "2e9vCgqAhxAJ8zLtmaitu8Go3hT5vozMtAtCwgAN83Yu", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "674PmuiDtgKx3uKuJ1B16f9m5L84eFvNwj3xDMvHcbo7" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "E9aSa4Rejv98MCWyTPJgzHJgX2Gfy1UakHAG9ashyDUB", - "lpVault": "25XopGuuvrFJE2zwNjSJ2RSaQFAnvUZRZ3VZhEafGTXK", - "rewardVaults": [ - "BHXhWpNMtyUBGM6cHUBHnDhvwtikxUxtNR4yU4DhKsCk", - "D7vwP5UNqiCsiEHhwxtqCuCSKXXgM8nJjZ6XhdwnPoGY" - ], - "upcoming": false - }, - { - "id": "EzMrueTeCQwTFB2KTpvR6jHpZo4Zn2P1rCLFHZiMoLDy", - "lpMint": "6K3EbDKd9VCR7YdFHZSdd5MfzjWZY79EqprVphrN75gf", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "A98UDy7z8MfmWnTQt6cKjje7UfqV3pTLf4yEbuwL2HrH" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "AuTfjTvKw3FKP3VRxoKQqKa2ySUxg3pRyLkMkcNsWmZ9", - "lpVault": "d2AWY1FgpKx37uNjrFnh2xGb3VKv9Qdmeqq57gG54Wz", - "rewardVaults": [ - "GSrVvy32RHMojQByTXK84B8MWMqMZr5ko6tDnCnaA4M6", - "BnhyEWdd3d8wkAm9fPkKodsVR5wuGGkNyi55puyVwP5R" - ], - "upcoming": false - }, - { - "id": "2exV3w3G3yNEyvGKSv3pVQmGzMZxHUY2mw2uwVBKWTZ1", - "lpMint": "6o4gmzih4Xr36UAd1NdJg8BunYGY4Dde32eJ1TMh74N4", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "AkhdZGVbJXPuQZ53u2LrimCjkRP6ZyxG1SoM85T98eE1" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "Cv6FMXrcznHY7yhgyhM5FyP5ZRKRX6jBKWAZEa5vD3WY", - "lpVault": "Dj7o9z3AemjyUrp3BHNMcfvbpKMwmsPunEF6gQ9chbbG", - "rewardVaults": [ - "7Tjz7twXNasnnNxTZ8Tq5kAh4vHV682sbuUZckijdUqo", - "46zQSbBRePTzouqFPFHcG7mkP9ysWaZmpMEBq7FTKxcs" - ], - "upcoming": false - }, - { - "id": "4TfPXqf62NUQJw1QCNwmS7a2vzX9vF8BxYtYtnsPqNb3", - "lpMint": "7vff6hQtbAC8v2i7mAGqK1HLQs9DWJ6A7GHsbovzxCNr", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "8STqYGKEf7tzm7CFBTtBJ8yBHHse59kVE4DCm8kbzb6m", - "lpVault": "75MnkYDrRZoEEv3GLSq8aR3ttBkZoXa8qmBPtQzi2fcw", - "rewardVaults": [ - "D7jgiCWcj5NpGAZB6Qy7sAve2NBhgTcdMHz76DDDCveS", - "45fiPUGHzx4smYBT7ErapRdxFXJRp47KhKJpzoLRwDM6" - ], - "upcoming": false - }, - { - "id": "BoB7TtQ6fgVceh1JMtwgL1CqfC9hKWDHfQ3QPsM7d17M", - "lpMint": "2pdg9vAH8GsTTWSSP3Za6j5ts4Nzs6tEbNterVe9H62H", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "Dw6aduBVBxp425wfSWdPFD1N17PZgsDABbeD5LNVQBDa", - "lpVault": "G9E9XKrDTHRHcX68uGxSCkY54NYtQ1D9rJSFePGySPMC", - "rewardVaults": [ - "BunXUabRBaYi8t9bE4KLcaVWwxZpN8gbVu1irxfCvyQg", - "2WQpLs1rmqqaRUZjKpvALev1VaytsmuPsixkNTe42jey" - ], - "upcoming": false - }, - { - "id": "HgAtaA7mtd2x42gtWrBYaTscoCkdjXMT7dbH3h1815AA", - "lpMint": "CuRZaiwYqFqQRehoiUK1KEeThXEGo5UysD2kzNhc7H2H", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "F3nefJBcejYbtdREjui1T9DPh5dBgpkKq7u2GAAMXs5B" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "Gi2spoWuivxVQQV4JEUyCyd9BVYbSKwJUZugA3DnnmG4", - "lpVault": "D2Cstxk2HyqqCzDYRPSBpxBwKCgFgTE32yeXZbdducB1", - "rewardVaults": [ - "HuH1HcfiF4sExGLGo9ZRD8csKfreiNHjHMcyvcB6pRuq", - "HrnTLDhmZnEEK1NZYW9kGBmkyrNwDT5MCvAGq1RsiCb8" - ], - "upcoming": false - }, - { - "id": "F7WCjhJzbZsc16n7c9PxzBqrjQC1ToX649LqBBFP3Cq3", - "lpMint": "BYkCfYGDqmmeD9nRGY2QuHpVLpEfH4JaQEFA77C13rGY", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "F3nefJBcejYbtdREjui1T9DPh5dBgpkKq7u2GAAMXs5B" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "CLtMzHKwewpiZY8LgURkiESGb3QquLBJ9mtSNMXFMc9c", - "lpVault": "5ncSUzeyWXoE9nLHxWXLMraowt7WPz1TfaLTrwa2do2V", - "rewardVaults": [ - "2nuPETZ75bp2DVFhUzkVPV6qf7ANbxTTr3mRa5zAfu37", - "FH7KXeSoV8qFxwLWLTLQg3LLKoCsmHZHKmMajUvxrZbG" - ], - "upcoming": false - }, - { - "id": "7uXi2jif5VhhTEKfqkU2ANNVCpggEDXWR94rdXuvLeSZ", - "lpMint": "HXLkojxGWSUwjagzRXMFRgmnNxkcKrFHvq4ZCZeNvBJL", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "svtMpL5eQzdmB3uqK9NXaQkq8prGZoKQFNVJghdWCkV" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "7qK4Qb1aTgQ7mGcG23JNLZyArijcS2MwMtMM9NNCQfYv", - "lpVault": "Esr3HgcYkjidTj8LDf6FUhE1nhG14naeWBbLuDB4PPf7", - "rewardVaults": [ - "Hm56yr9FkGGX37nuwWK3K8ijT6DG4Yztwn2KdqJRuZy5", - "3tUZ2tT2DqsmMfdJ7qZYSGz64tcoWr1v173iBaJ9LBAT" - ], - "upcoming": false - }, - { - "id": "64cscKpm1WXP415QHx3d3QUag2JPVmadcd7bXAkTnKYX", - "lpMint": "4A3kqZBJu581eFePXL1dTLfxEkjZPWJFgj4tJmP6mQQp", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "METAmTMXwdb8gYzyCPfXXFmZZw4rUsXX58PNsDg7zjL" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "29iVB7eHUHvS1omgnjeiCmatiHrYTfD7Wg9yAzVbBg7x", - "lpVault": "7URFH2mBh6uL7Bmg1zMV99CrrTkGFizXmTHiXUwtikvh", - "rewardVaults": [ - "EVfzrqg7HJfeNZBRK1TvXcgvFrmh6qeKNPKShKKpu6XZ", - "2wXg1vL7cPGXFmPW9nZS4BtpAHqpWuTqvYW1YNBUaJtV" - ], - "upcoming": false - }, - { - "id": "2G7qTQzw3KXm7WEMJf2izqFQWh8CLZ1wFbQVP5qo3ME9", - "lpMint": "EcYk7t6Vw59HDnY2u6H1KDPkk8juMeA1NpGpHiGk1LDf", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "SCYfrGCw8aDiqdgcpdGjV6jp4UVVQLuphxTDLNWu36f" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "4g7cYN8ySanwS5vYz44194cGC6GiY4GFRxQp3cuGyhB7", - "lpVault": "3aQKiT9f6Rcg2wt8g3fF7f6kHj36vfakrmVWrBobTYBY", - "rewardVaults": [ - "EXjGU7QfPxzvBBEmhKPzWWwkndjUq4vxxrQpZuG2zi1G", - "EXnpxUXLvgoZKvKEhRH4ss78EKA9ZG3DsLokMtyTpWYB" - ], - "upcoming": false - }, - { - "id": "Bd1hAsMAghtCjK38Ut4m938Ep7zyEp2TydQ7G35nPvUj", - "lpMint": "Hho6ZzRDj49L4z6zog8nQZFaxMSz6FX6wNzVpMeAMen", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "HKfs24UEDQpHS5hUyKYkHd9q7GY5UQ679q2bokeL2whu" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "AGQ8Ks91ywQrtYdTRDDgS5Ey1qXUo6fcTSMhet2M9zfb", - "lpVault": "EBrY4H9FL3SD8FGtkBEYQByUu8ZRoyVqX1PFmhhDqrNn", - "rewardVaults": [ - "8E4GhEuKWYU79npxJ6MXSPhJoSdBqnQqiSBA2UjU4Qpj", - "2c8jWP6S1jnrdBAcfmssN6P2j3yuS67i5Ei3vNBMXRgP" - ], - "upcoming": false - }, - { - "id": "Ej7iBkW79EdF26RxaRQfGo58PqRdzHzRmE4C2e3z3dPY", - "lpMint": "H9wUyrxpAErmdNVPitpHSXgwoomoh91ggJKPWtQQoCn1", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "MEANeD3XDdUmNMsRGjASkSWdC8prLYsoRJ61pPeHctD" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "D5JdXMkTHRrUqTfmPxJLeuaCkxqkC9FCN2j8aet9npFC", - "lpVault": "AHSbgdUJnWiRVWqrUbq88RQB6zMFAvXhC5U9jsdX55RK", - "rewardVaults": [ - "CmjoCE7MtgTSbtsvUXYHiYynVcmQUEBLiNu8ns76eZnk", - "BieoMwUt4SGfF2huQpW1uZi4DSxLpiR62BYgEhPqmfiM" - ], - "upcoming": false - }, - { - "id": "Gue2c9J2aRtY3aJ1HEwabQznwg2MUt9d9kUyr6otujR", - "lpMint": "CPzmcw81a6PDasSXhVLfDRKuTJXZPUqocS9VFf5zCFhs", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "cxxShYRVcepDudXhe7U62QHvw8uBJoKFifmzggGKVC2" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "CCFQq1Z4Wyda3qAw58NjippKbJU6GgP4fY1FT5BBBdBF", - "lpVault": "EVB51MPoAcrg6wtmSXFtURzQYYVEMbwZuyV6PqXCKFT3", - "rewardVaults": [ - "CWfUsYr2nWu7gA8CUV7G4E9i18LVJ4t89wLFRsEKpt1E", - "8Xgp3bLeT1xu9z9CtoXu4JNBfNhuNDgvkHi4i5huaUkC" - ], - "upcoming": false - }, - { - "id": "DtU5pZB99rVtxe5qe5hQa2rRpw7poFiqaHvMAbPgT2TM", - "lpMint": "3baYkTcudvSFMe25UpZcBfdp4FA5kL2E4pfaeJ8AiYJB", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "PRSMNsEPqhGVCH1TtWiJqPjJyh2cKrLostPZTNy1o5x" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "AghczE5LjWbWWBJXJNZoqPdGKeZdTWgNqrthFKiJVx9C", - "lpVault": "3NU6ELNjmu9fmgbbYaoy6iTMmQ1wzQ4rTGK6gur715eH", - "rewardVaults": [ - "AdUSKhjwuApXwFmKfnXg3a3iKZQVSRVKSscU9QJ3QF6P", - "L82H7Lct65UEYv96bxDnevrqoMREPLgHA8Hk94QT2cN" - ], - "upcoming": false - }, - { - "id": "Eqn7unnxmneDuTuXQ7EAN1wBkHMFD4LgCCAkCdPA9KbV", - "lpMint": "BAgSWaPZpsQKyZJdvB5KyvmCNj6hzczzentt5FhDCVHb", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "Fm9rHUTF5v3hwMLbStjZXqNBBoZyGriQaFM6sTFz3K8A" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "2ckG6WdUmwC5P2bvgYQEqBsg1QuJez888r72MiheXoS2", - "lpVault": "3v1jXd65H8cJUAYyDxxgMVpnDzRwcnfNHd1fApD1s96q", - "rewardVaults": [ - "HoX6ZJT3CC349M2Tv47D4oX985z6MXi1waJMbqRY8mBY", - "2M7pceDDkap8TTV5AeEr7KeV7cG1WkyBVT1TGcevV1wj" - ], - "upcoming": false - }, - { - "id": "HXpQJeAcBCKfGY6YhZgBocZGgV4xApPVK7r8CPXfvCin", - "lpMint": "7MgzqVTGeA4wENme81QPTrPy45NJMKVL9XGwxmNT87cG", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "ErGB9xa24Szxbk1M28u2Tx8rKPqzL6BroNkkzk5rG4zj" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "RuSifGR29nd7TyDHjWzJgzz2wyfTd9W3DoMADzUQPX9", - "lpVault": "5GAWXBDQtdyzf32yEHP1fhm3jHU6JNjDgLK3G4txVnXH", - "rewardVaults": [ - "DPfj6jE34t3s5EhL5qrmos4S2amJHLWAj13ef5BvSz89", - "5TPJHNJ4ZeJ6BSbZ83R4ZdA7R3Tsf3icgxQVaWjEExn7" - ], - "upcoming": false - }, - { - "id": "36Rf8dzq5gy4Ew2bLQEgKoCKVTku4EJPLqFYG6mzFrkr", - "lpMint": "HYUKXgpjaxMXHttyrFYtv3z2rdhZ1U9QDH8zEc8BooQC", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "ErGB9xa24Szxbk1M28u2Tx8rKPqzL6BroNkkzk5rG4zj" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "GwXKptwrXvFQ2VjcjXc9JwVzmAeGvPH9ogtq54AaDZcm", - "lpVault": "46WoMBPtrzD6rJVF8Znu5RGsCpjRvNUKCCe87eaedmQm", - "rewardVaults": [ - "6GWBHRbqtT5qsn234yfqhC7zvtHnR5pNq53rDJDAWDn4", - "CaGvtrQj71GkY9RXHzDerhp7iKdBD8iVr6uWEhVuMcm" - ], - "upcoming": false - }, - { - "id": "ELovJ3jDKMiWhCUCdZzPfTeVmQwhj4cvYuGwS8FfhEtJ", - "lpMint": "8i44Y23GkkwDYZ5iSkVEqmrXUfwNmwo9grguTDWKM8wg", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "NFTUkR4u7wKxy9QLaX2TGvd9oZSWoMo4jqSJqdMb7Nk" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "3wvnrh5VaiARSfkwhiLy7pakrxXJSPBEjmAA77sr2xd3", - "lpVault": "3hikNL4yh7kBusYs6hQ5roNrg3D4874N1nqupvjP2WwT", - "rewardVaults": [ - "9hdU4MgrLNJcBf85ZjM54hpsM6x9xaZX4eMTtpU52Skh", - "3Ch1odoQHrDLPtshdcYBhuSexuA8JnoqS53UE7LSfoMY" - ], - "upcoming": false - }, - { - "id": "7RQDGZ1cvHcREu211R35WSKHFjTxM5dmJHeFAWag29BA", - "lpMint": "EN43tp8xdkcM8RYSJ4msFHMPTJRXKhUteVYBDJLwTvr3", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "AD27ov5fVU2XzwsbvnFvb1JpCBaCB5dRXrczV9CqSVGb" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "96sdu18tQG6mNa2R59wtiM7jJ4uufi1DUwhRxbxrxD2R", - "lpVault": "DrMvUqiHEqnBTZe5eeWWfGVcZeuWW5kVRmkGfJ8WK3eZ", - "rewardVaults": [ - "3MYDn6i8WpCd7FpLuD8c8HeJXfmrhDeHifSF97cS2iUg", - "Ag5tg5mbAhKdECEKfSTuyw4C47CHQfVxp4CmpKj6U9zW" - ], - "upcoming": false - }, - { - "id": "6VNF4rF7ESUohzNeRf3aTg61dyFjbab749RGUHCTDFQL", - "lpMint": "H3D9Gyi4frRLW6bS9vBthDVDJyzyRJ6XhhpP6PJGWaDC", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "CRWNYkqdgvhGGae9CKfNka58j6QQkaD5bLhKXvUYqnc1" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "4EkurC1mTx89e3XpFSPZmzZhaHGWcs6KtqYubtjvLHf4", - "lpVault": "43h1qx8Ct5uTqqcrv27h16u2zP2zJQbxYEqwrxMtYmFv", - "rewardVaults": [ - "4RKLi4F1T55zwMf1t2aUsPGNouAvGeRejj2d7s3z9tii", - "Bv2fbTAaC55xiW1LJkY2NFpEAr4TkoVzwnetxNMhJ9rS" - ], - "upcoming": false - }, - { - "id": "BYmeWrwA4ixvJhNrxWzQsA3Fsz6EtUDJTo39WYZ6o1FS", - "lpMint": "5Cz9wGStNjiUg81q8t6sJJeckuT2C14CYSfyQbtYirSX", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "CRWNYkqdgvhGGae9CKfNka58j6QQkaD5bLhKXvUYqnc1" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "Eb5RguxKYW4XqsGvM2faB7RisyxMcSs4NF7RTU1MMv9X", - "lpVault": "DCQoi1ZFXrZLHV11CDPrR3ChLpqEu3uaddqXre3fVpRD", - "rewardVaults": [ - "3emSqcHiXUjaZkqUE5Kw13iBJxWLf7LMQ6fsBdGSdCF8", - "HDdd78Yg191z1TbHKYaPfpVLHYz9XMJJooBFEQqZjQjN" - ], - "upcoming": false - }, - { - "id": "3J3SYLeFZWKnUCsrPzikw9bcD9vRs7YNGfmg7ZSg3tsK", - "lpMint": "CjTLvvKSQdEujcSzeZRYgk4w1DpuXBbMppLHaxZyz11Y", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "6F9XriABHfWhit6zmMUYAQBSy6XK5VF1cHXuW5LDpRtC" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "Hps9GqZtdWSswCpsbGzUjtddWrPBNMkPMBQbvsZHRdvB", - "lpVault": "4rg9ynU2SgKzsrTRzhhF9MUPvoRSmrQWdGBwK4DhRvjZ", - "rewardVaults": [ - "HboptB7p4TV9qKCer9h3Qap9kTz2wpTYn7vtatSVL7j6", - "5wLYgZm5LT5QGMVbfKqmXR8qWZtzvSVcFChw1iZqTwee" - ], - "upcoming": false - }, - { - "id": "HtvQ5AEvu8sDM7C1oB4r5fJ5E2Q1wsJ4TADwNMqR9ccF", - "lpMint": "84fmrerHGohoRf4iLPDQ1KG4CjSjCRksYWGzjWfCRM8a", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "FNFKRV3V8DtA3gVJN6UshMiLGYA8izxFwkNWmJbFjmRj" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "GJZE4E446Zozmp9j4cjGxTvZ9BesPjLQG9ji6gJfceet", - "lpVault": "99oqRe4GVwBu6Gbu4N6PC9ifnUVp7qaMEuw6iv5KG4AA", - "rewardVaults": [ - "3ujmEuirpJWh4epqCFCagd5FjUvoyzMvoDS4t3vmQEuC", - "7DFWUKcjnWFgaxo2WgGcMnkBmcenFq5geV9nWEGWU5to" - ], - "upcoming": false - }, - { - "id": "E5L4Bx3Lsif7bDb9XMWi5guHUt4kkYpbqQ4CbmnRjHs1", - "lpMint": "GCEQbLg4ik5YJ4CMcbtuVqEc4sjLdSGy34rFk1CtGjdg", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "5gs8nf4wojB5EXgDUWNLwXpknzgV2YWDhveAeBZpVLbp" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "7hUudYqaP6eVktvoDBDARcLN3BZ8ZbhR9mGQn8dg85KK", - "lpVault": "Mogjm9wjGGptWqKnm3D8QKKrj693D4NSjrEMKx8agKT", - "rewardVaults": [ - "CqtvyoBzq7zLgYac2Z1ezrXyGFH8YTCzzRCnzbMmG5dH", - "8F9qazqCCZBZ9toQppKdTxjqQCD4hjsq1t4HPxpdqekb" - ], - "upcoming": false - }, - { - "id": "7yk1XUWmZpWMCoFpUT985z61UNTypyBGgZF3JpKgcwmL", - "lpMint": "HUJ1opSk8AiPfDT47r7n4hTiK2EXgrR3Msy7T8q1BywS", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "9TE7ebz1dsFo1uQ2T4oYAKSm39Y6fWuHrd6Uk6XaiD16" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "2C4NV3mwoQCSCLagwCtmufAka6ukEfSND5DSRGBtejRr", - "lpVault": "APmpKr8kjm3dxvRLbQVHqZnqHM5FSyMvg1Wn2zqTYVF4", - "rewardVaults": [ - "6YNQYqUC7mKwJBuHMbEasRpNwq567Wh5iPcMmrK4rDT", - "8nRwtcygNWfFsPmRkaPGbZ6mWrPCwDprAE9d1EvV4EuB" - ], - "upcoming": false - }, - { - "id": "665VvECKsLpXN4fLy8GYbyQpGJRNkxRx56X93U9FVSbv", - "lpMint": "8jjQn5Yagb6Nm2WGAxPW1bcGqrTWpg5adf6QukXEarcP", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "CN7qFa5iYkHz99PTctvT4xXUHnxwjQ5MHxCuTJtPN5uS" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "4Sg9uKPcMnhjWyEdQRhNc3th7iBQCfh3ZqqKRuyKVAtn", - "lpVault": "6a8bAkyLK6EL675b3ds4FGpojHKGUVRy9zfpXebPXgdV", - "rewardVaults": [ - "6rBSUvDjFhp6Xwi7oVK32vKB9jQQAPAEEzSxsQRzSGZk", - "ASSJYjTNLN67sGqTZkngi3ZogTagTsH165nG2Ug6MB9x" - ], - "upcoming": false - }, - { - "id": "AWbmotuJS7NLBmra9ctbfVR1BnoHmiG1HGW6hm49TuRZ", - "lpMint": "Fffijd6UVJdQeLVXhenS8YcsnMUdWJqpbBeH42LFkXgS", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "DFL1zNkaGPWm1BqAVqRjCZvHmwTFrEaJtbzJWgseoNJh" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "HphbMv737TNN9P5Q7fnfJSLKt88YBjKwF4ocv69cVvFE", - "lpVault": "91LAgDBRbit1LP8aP9NKDN1PRKbThtcvid3zYTBzHR8f", - "rewardVaults": [ - "5gJE2xtx9B23rReu35EZEHuxL1ZRHKAExL6u9VNLZhJ1", - "ujQqfpP9JzqiMGrg7QeMnwfpcKGRqvJZxJAfxp74oWF" - ], - "upcoming": false - }, - { - "id": "CgokwBwwdYsgo8hbUMtJ3GoNM3bVjvMcmaPrVvCw4sBi", - "lpMint": "CnUhYBtQEbSBZ76bgxAouVCTCb8rofZzwerVF5z5LREJ", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "6cVgJUqo4nmvQpbgrDZwyfd6RwWw5bfnCamS3M9N1fd" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "HBWs4knSBV4FQX1CMqtiDvicESo4LcU4tKshDtCaETZk", - "lpVault": "9WVDvYZ7zS2eiheHLa74uiJk3f28cg5bCM2XpYK6D8oC", - "rewardVaults": [ - "4Hb3CkSgqUprbHwuWkJxqdZytyLC5Wz1PLAk4AhozcJM", - "4dehDyT2E4soVXtgYLCFw58Wmg5Q3wQm71n3mBfMybdp" - ], - "upcoming": false - }, - { - "id": "7W8BKbMgcVpGYvTgEK758pJgDRZJ9WafKfgkV1XCkP33", - "lpMint": "Hk8mDAJFq4E9kF3DtNgPFwzbo5kbeiusNFJgWmo3LoQ5", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "APTtJyaRX5yGTsJU522N4VYWg3vCvSb65eam5GrPT5Rt" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "2LziV5nuaf7MJBExG4YPYZUBSqzQE6YcqUyVGPSFux3p", - "lpVault": "6WSdTvV5k7D76FGBUucdFLbfYaMh3XAY6AEsMSMHp32z", - "rewardVaults": [ - "EEWM6DY2XxL4mBNCjJyxpKLYZUss4rFLQsnyw81VqV6V", - "MKy2NdnjJf9A423yy72qcEmPAqpoLcLLECyWqEkKUJ8" - ], - "upcoming": false - }, - { - "id": "5Mdq5o3KKPyeVVBsbnivVk9qCATjfEQ22oysXVsd2DvJ", - "lpMint": "2tAcfqJ1YYjpGLqwh76kyNt9VaNFDd4fJySfH6SmWfKt", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "sonarX4VtVkQemriJeLm6CKeW3GDMyiBnnAEMw1MRAE" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "7kUDK6QfnwkY2V1HuGHwqBiU3XroVmbDbGgjtVtGTW28", - "lpVault": "3DpNmc28m7z18HVQp3CzmYjvoT5Snk7qFkNMJDz2GW8g", - "rewardVaults": [ - "eH3XbcgLAC43CJgs9NnqDoVTfRNXXwA3nmYHnrR1GVe", - "6mqPeL7aEwfiYLpDDRfb4ZjMe9sGN6gS7Vsa5exXyoC7" - ], - "upcoming": false - }, - { - "id": "7NZ18KhsSdJBQkJEJwhEHfdaPRNdbMd17CMoxsKxavEo", - "lpMint": "HjR23bxn2gtRDB2P1Tm3DLepAPPZgazsWJpLG9wqjnYR", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "HfYFjMKNZygfMC8LsQ8LtpPsPxEJoXJx4M6tqi75Hajo" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "A9oEpg2Nc7kPKGWtUM2MiSbzWkXkHdwji8xro9d7zUYi", - "lpVault": "EAAnP6ZUjMTxKPg8uD4y5tZqo9gt8CUBb5qhjgjEEajP", - "rewardVaults": [ - "6HDipdFSAc3FBGJz4iL6krVwRQ8nEmg9kTtJ3kdoEDbJ", - "5zbQ9kQU9ewkpfmhSduDP95svWKFJmHY2vzqv4YC3r1u" - ], - "upcoming": false - }, - { - "id": "GVfLbXA3dpEHPvc4do9HvMZ8TACxm3x54BVrHPMEixcr", - "lpMint": "3HzXnc1qZ8mGqun18Ck3KA616XnZNqF1RWbgYE2nGRMA", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "GENEtH5amGSi8kHAtQoezp1XEXwZJ8vcuePYnXdKrMYz" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "FpAPnuT9FDpvzN33kF1cAK3vWMr6BqmnJoCTvqaSeGop", - "lpVault": "9zu4NVcnWBxu4gXqVYE6bPoHD24TGDQo5VF1DmaXfAwx", - "rewardVaults": [ - "B3ACepDzCv4dicf1GnbVs8fxn1GsoLQ8fD4jSZ1y5CK1", - "8o8JzfSvGGdFLocyVYWJQ32hDLZhXMq3z7NBuusUxfSH" - ], - "upcoming": false - }, - { - "id": "DDRNVVJBEXEemcprVVUcrTbYnR88JyN6jjT2ypgAQHC8", - "lpMint": "7GKvfHEXenNiWYbJBKae89mdaMPr5gGMYwZmyC8gBNVG", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "GENEtH5amGSi8kHAtQoezp1XEXwZJ8vcuePYnXdKrMYz" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "9sdefPmehyrWqBPfn34PFcuKPYoxZ8Uy6g3436qr6jXk", - "lpVault": "DAfAJVWGbZpLn7Tahwc9LuVukMKB5JSVQjdHRwXk44GV", - "rewardVaults": [ - "tMh3bpXh2GaFLK2Buzav7niYAS81m7RigkhRn7p4wga", - "JBi2SsBHGN969aGLpQxCLaRYaBa6U7LPShPYe23Je7oQ" - ], - "upcoming": false - }, - { - "id": "FDnxy4NkJVG3GNMMrtUZmUmoYeYE34YRDwCYTi1yBTM", - "lpMint": "5Gba1k3fU7Vh7UtAiBmie9vhQNNq1JfEwgn1DPGZ7NKQ", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "4SZjjNABoqhbd4hnapbvoEPEqT8mnNkfbEoAwALf1V8t" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "DadRztERbxMwvTzwnwst5VjVZCMJ3zL5J7ngvKWpvJoF", - "lpVault": "6cxqxAYhLXzgYMBZC38xjY3b2sFux9TvLZejR5Vx7khc", - "rewardVaults": [ - "8yCUztutwnW9FHfJTfsAZdJZ8j77G1CoCkTVdsRDtt7f", - "49Y2DDJqjYFQHSgN1Zf2SUr7ktBrhyZooLPrdDe8xFwM" - ], - "upcoming": false - }, - { - "id": "27bysJaX5eu5Urb5kftR66otiVc6DKK7TnifKwnpNzYu", - "lpMint": "9XnZd82j34KxNLgQfz29jGbYdxsYznTWRpvZE3SRE7JG", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "HAWwtFc4MFNSXFyQbUZd2GefSwZLntCiumt1D6XM8jfk", - "lpVault": "HVEm5BG4jMHtwgrUtuiC9K17bjp9CjFpgqmzVABmzLxr", - "rewardVaults": [ - "9gs6XnKs3RMMSSQAZm3VCbRpoNmPMrGaQQGMmRKjPeSU", - "BsuQ3XCCapopam8byEzHzazyxcRn5dCT3UX9kUzozhw" - ], - "upcoming": false - }, - { - "id": "3HGPRHH3XFFu972MR1EdS65qc1nN9sM7miZtFTi6QcEd", - "lpMint": "3e5ZCKi4etorpV4pv1fSckP5iJD67xcUkx3RtFCZhbzD", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "FGUfADCRsS11YZimCgAbridWueJh1EBGA9hY3WkaNcAg", - "lpVault": "926QfWYN6Dgia6LiAm2PfmbL2Nj3q2DGuinBGVPAdGw5", - "rewardVaults": [ - "nEFW5G7467mSWBHJB754gMwwKyFhyu9A321UEiGDQje", - "9W8fX6moUPNwmCctgg1SdS7xVDrV2FuduWeG5VVXTEpa" - ], - "upcoming": false - }, - { - "id": "6AxxjJhAz6APspTQM4vVCHgfzEyZgBTCogJLdai7bXYE", - "lpMint": "FEsEfEJJSfiMQcshUgZ5UigfytfGRQ3z5puyF6DXDp9C", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "6KTAUxr9iHbSRLu4FuAtZ97JujUqaezeL12cTvwjR6a8", - "lpVault": "GNS68JMuV4bLiAX1s6hBvVupk1XqnGNgAGLpNPTwbSCN", - "rewardVaults": [ - "9czTqXfWQ4bdyrrQczSaH77zWD1TFifCTbp6Xesa7p2J", - "6mTuc1dfyD4uAckzmS3LVbf7cm8YAQxvJRxHmJRPwgQ6" - ], - "upcoming": false - }, - { - "id": "EBS8tc4proQE2Fj6HxU4piiZP8oiDrvyJUijDCX7P7QN", - "lpMint": "HpUkVAPRJ5zNRuJ1ZwMXEhbMHL3gSuPb2QuSER9YUd3a", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "4ZxvJJHqxC9aaUMkBfyYr2qET35tcCZxn2VikiVVSKn2", - "lpVault": "67KBaLyhWRSci4cqKgKQ2xEmuYFiRBxPHVZD5vtST5rm", - "rewardVaults": [ - "kquv6VidWpoqFMrR7nz76EPP8X7xFJJetEL1yNB92V2", - "91NJTMLgChsTWTZ5oG5NJSyCGT6jxFSjPTe47k9Gn7He" - ], - "upcoming": false - }, - { - "id": "FAKzZoGVCEBDRuHN4gDswAx7PsocCorDqH6dQaxnyorT", - "lpMint": "3dADrQa7utyiCsaFeVk9r7oebW1WheowhKo5soBYKBVT", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "8eJKiLB4GUg5FK1VDGAd7hnmbfZYqffDrR9yywsywazU", - "lpVault": "E6HgWYbvz26yyZYqgQUXAKwZyx41tAy94YL8WEN4edfi", - "rewardVaults": [ - "DJr47f2hjR5SUS2VrpQdBJtFJ8SGNrSBKQrKmu4HdyzM", - "7Ruf2uHCtddXgSh8PQV7Htj1TWARwBxfGkpokFMoD4SA" - ], - "upcoming": false - }, - { - "id": "CZZnmfvSgNVUiDBG4wN2NNcaYbsKDN4kLsc3SN8DMw6i", - "lpMint": "AcjX5pmTMGSgxkdxc3r82r6WMKBvS6eQXXFz5ck5KKUa", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "8jAuRD88B5arx8FXVRPVQt4oDWSpRHznNZDSnLSu5CWc", - "lpVault": "AYMp5MzHBJVZez25tDcrYjPvZkEtFWUc5MSdUZpc84Xh", - "rewardVaults": [ - "4MD45PUi8du6kt5m6q2Gfgz43dzCnXoJMpYxJTHQvzQz", - "4FBypcmSNzuTxhRg13aoHKciaDjfkCkR7s2gHLoBF1T5" - ], - "upcoming": false - }, - { - "id": "C8BjS9DGDvC2zS3n6fTvm1rjPbA33uZ7CAvEUZ3tg7aM", - "lpMint": "BjkkMZnnzmgLqzGErzDbkk15ozv48iVKQuunpeM2Hqnk", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "8sW8go8eeyn9tCJEndchQ4RKfTkZGMDwKdNw9QVCpgys", - "lpVault": "vZUipizkaYcEa6fUBjtQU7A1dG8XmBgt6dCDFe16HyU", - "rewardVaults": [ - "ATLtTWi5ongWbMqbHFrAiMD11dRPgDWyJLzc7tZTcnjK", - "CmW8akq2vGQeDUD1yeZTRbje21p5D61PW2mXK4kMBwo6" - ], - "upcoming": false - }, - { - "id": "7fe8QcJ6W2kHKL1h1HMYYJoGXz2LUcwCjkxX6MX35orK", - "lpMint": "6PSoJQ7myQ1BJtbQC6oiWR8HSecQGyoWsPYTZRJo2ci3", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "u83t5Q349zcntifRmWECeAJDoq8kuYwsNFQUcGEnwn1", - "lpVault": "2QWeQZJMpvcqwNMH1kBrFRjXptk5N2Js6c4tya2Jxtdm", - "rewardVaults": [ - "BFANrk5U8N2Mu3WnacBP453nHm8C9mHy2cZiTpVuiMEj", - "5hEx1CZbzhTuZtWUV2UpCHLDrDgJ4o3BjQqAr2uDYkFo" - ], - "upcoming": false - }, - { - "id": "AuyqPBiY6sNUpH6jx415NGcdvNdYbkbYsyVabUqEVdkj", - "lpMint": "3wVrtQZsiDNp5yTPyfEzQHPU6iuJoMmpnWg6CTt4V8sR", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "AmgTDN5yBjjbCG5o1CtpxB7hxpaQtHCj1GYMFtQud7TJ", - "lpVault": "DoK13McBSoFb9Q37DqVkx5LiJTpYqhM2NUv4go1DJ5RF", - "rewardVaults": [ - "FBbe6XRrXeaQ3XcXWk2tUi711HBrmmi2eLdX2L6DJ8SZ", - "2YsF3Nvw4ZaTUNqbvaGr8UzrvnoWFB343s1tFRjvM1pE" - ], - "upcoming": false - }, - { - "id": "6X495xkPWkw9SQFYf7yL1K8QooZyaeEQ6u7yMWNNZxNV", - "lpMint": "EEC4QnT41py39QaYnzQnoYQEtDUDNa6Se8SBDgfPSN2a", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "7fzrABKta6exUaLZPgvmCrMYc81qgAdzVBtQyVa5ia7Y", - "lpVault": "4wnWp8ywmCD9D1A4BuLLaJKZQx7FMvs2S97gJnyqsU8w", - "rewardVaults": [ - "EDDGwRv5aBFQu9fxK75USg2FD38N5QQPQTMGQLRnf1jA", - "4PvsqG7KkkeqiZYZx6UijATDU7B8FbXxyMNnKmgcQHqH" - ], - "upcoming": false - }, - { - "id": "AwUDfg4NYbLQRAcFipoJwyZTpqNvw5v6C7EypryL12Y6", - "lpMint": "FJ68q7NChhETcGVdinMbM2FF1Cy79dpmUi6HC83K55Hv", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "HCgybxq5Upy8Mccihrp7EsmwwFqYZtrHrsmsKwtGXLgW" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "BBsHoRKkRGyyjsQEDqMMjg4vNNbZhWhsjBE9vQc15obQ", - "lpVault": "H5VXBm5Es85jhLN5VyePC95KCx4FyUDC9apq7ksvzBgK", - "rewardVaults": [ - "5DsNCnLyZm3B8iVACCWPvXs2WXfmfuA4uiRinJJuEZgz", - "2LQWPUn6rxYrzW1oPM48ddXmWLJQTQ8P6UrJnE9ZCSy2" - ], - "upcoming": false - }, - { - "id": "FgApVk6mASrkuWNxmsFvsaAYkFKqdiwMTvYZK36A2DaC", - "lpMint": "CHT8sft3h3gpLYbCcZ9o27mT5s3Z6VifBVbUiDvprHPW", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "kinXdEcpDQeHPEuQnqmUgtYykqKGVFq6CeVX5iAHJq6" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "7kEx8qnkZPkRXV6f4ztf27zYjCACBHY3PUMfuiYJsoML", - "lpVault": "7fgDjhZn9GqRZbbCregr9tpkbWSKjibdCsJNBYbLhLir", - "rewardVaults": [ - "5XZjRyEo8Wr2CtSE5bpoKioThT9czK1dUebbK87Lqkaa", - "8jGJ3ST1j9eemfC6N2qQevtUdwxT7TpXW1NmvWyvLLVs" - ], - "upcoming": false - }, - { - "id": "8W2TqGCiFiqR1JD4sbW8uTRjV2HvFjLhkZ2tAQTYE4Gc", - "lpMint": "H2FAnazDaGFutcmnrwDxhmdncR1Bd7GG4mhPCSUiamDX", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "9nEqaUcb16sQ3Tn1psbkWqyhPdLmfHWjKGymREjsAgTE" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "EShmXWydGxetCKmJGCpZbRKYk1bS67JiUjpt9yue5xZN", - "lpVault": "BpipxpLsEs5fvzdKmwHsB1o1r6umhXiqeU2RVFSjQ9mA", - "rewardVaults": [ - "AsEty41c54HrxzjXnhDro7GGkVbGRyQQF111wSaUBM88", - "B7HMR3GXYfqCPqTg85V1dzjQGf3nLccPdj9tBcDcoThf" - ], - "upcoming": false - }, - { - "id": "Byt2kL5qi45pMpdAsNNciKZ8HLp7oU5jizCbyARLtQJy", - "lpMint": "2xJGuLAivAR1WkARRA6zP1v4jaA9jV2Qis8JfMNvrVyZ", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "FnKE9n6aGjQoNWRBZXy4RW6LZVao7qwBonUbiD7edUmZ" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "EGBJV1YpgYhRSuNkz2w6NvhNxdLg1ZqRDaZSg4HysoTF", - "lpVault": "8EziNww86hPoStUXPsPSvMuPaNxXP34597azYWshi6sx", - "rewardVaults": [ - "Fx69V3iFYHk3Sj87nUbQoZsiuQ62hDucSagX4DPUiraQ", - "DMy3GrT8atWEV3Lcofv8mG5FsUq1HuqDHfpU3sLTkoJx" - ], - "upcoming": false - }, - { - "id": "2pQQnoNpm5LoG6sZs5toNBXi4m1Pj3ExXdggPQYyiP2x", - "lpMint": "KHV6dfj2bDntzJ9z1S26cDfqWfUZdJRFmteLR6LxHwW", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "FnKE9n6aGjQoNWRBZXy4RW6LZVao7qwBonUbiD7edUmZ" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "4t9yWe9N1tBfTZKkmUdYFRjuY3xJP9AwXNYuStASYx45", - "lpVault": "81nhtKAVM1yBwUmHQSQHwbkpZGvXrs58Qz7Uj4SLAv5F", - "rewardVaults": [ - "9jSMiKksbshsUgpwyMap96yFJ6Hdjvj8uEhw8CZnS49d", - "4jebfTbaZugbkEZwzbX17iiC6d1dzQ3Ho8XCTyTZUSBm" - ], - "upcoming": false - }, - { - "id": "Gf3qFzKnGvMCVMQZERW2Qso5uEYxd9B9kWZZHsrMmmHj", - "lpMint": "FT2KZqxxM8F2h9pZtTF4PyjK88bM4YbuBzd7ZPwQ5wMB", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "FnKE9n6aGjQoNWRBZXy4RW6LZVao7qwBonUbiD7edUmZ" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "ADuiJjCaDP5rEXQEyLZYvV9WgkRHPmGgsB6hss8WCKtE", - "lpVault": "Bqz61QpzmEuvB37QzkPLgnKHW2pRkH8Zcdh54DJicayG", - "rewardVaults": [ - "4LXUy3qtHwK3nkgmrSwupdBoS4ybn2FZcZBbazCV9cHV", - "FJCKa9tpiVV84zT3VQTxP7uNVyghDTTEGKX1jsXvVRBz" - ], - "upcoming": false - }, - { - "id": "5XdeFdcJoCAPMfgYndMPcsijFBKFp2cPSCjrCZzmpTE5", - "lpMint": "49YUsDrThJosHSagCn1F59Uc9NRxbr9thVrZikUnQDXy", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "4wjPQJ6PrkC4dHhYghwJzGBVP78DkBzA2U3kHoFNBuhj" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "D8i2QREg8SnQAqH29kQpWtL8EKsJqED1oyNaJvYjdYCX", - "lpVault": "GdEyL524epc1SQQKHocrjEq3SbAXczuzZEfw91MfCgoh", - "rewardVaults": [ - "2uCm4AEafnRgyLit1gdVmkqtpg1kmJY2dWAgC8TpCCBQ", - "HKLCdmXYAkPBKG8jE8YE12kyUaovYWSJiyrrqmWNxjqk" - ], - "upcoming": false - }, - { - "id": "CzKUrVbP7hH8EjcHNc55ZFW33rJyLQ2r52bxCzaGTpz", - "lpMint": "GWpD3eTfhJB5KDCcnE85dBQrjAk2CsrgDF9b52R9CrjV", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "4wjPQJ6PrkC4dHhYghwJzGBVP78DkBzA2U3kHoFNBuhj" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "9vLMWjM1u1gAyAt3tYtRLyf1vHPZfgtBECEgGtW6wbSM", - "lpVault": "BmD9dfArwe8X2NxVUyNif2Cm47qxpyUwKGS34B9Wmt9x", - "rewardVaults": [ - "6oLDL6RMTYaE4zBWid6RANqDz4YUbEjHvsWxD2QXpmLM", - "GwkLHtcPgWbDsdoweuDaAvVQgwCbQ8FWVEDref7xmpZu" - ], - "upcoming": false - }, - { - "id": "7wNhbTS6XQczXs52wcVmfiodRMPfycB3YaG52dWWY6SD", - "lpMint": "De2EHBAdkgfc72DpShqDGG42cV3iDWh8wvvZdPsiEcqP", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "2MbHFiv8H2jjJboqWCaEY1iQh7WFQEwbqNQMYqXUre1p", - "lpVault": "4vyJYQyWusNxCCyFDvWwzjVZFJByAVudWvuTzgHYzwTY", - "rewardVaults": [ - "Erz6ai92ieTAqWKHP1tkpGgBKrUJsKe7dhCUyhqtjKRv", - "Ejed9odWtRtNrSndDnrWvu9LaiqCANbkeKHTS3g3H1Xj" - ], - "upcoming": false - }, - { - "id": "DjtZxyFBgifzpaZEzfsWXogNX5zUCnTRXJqarGe9CiSv", - "lpMint": "4xTpJ4p76bAeggXoYywpCCNKfJspbuRzZ79R7pRhbqSf", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "AcTRjdD3x4ZHzKGaApVo2RdJ7Rm7f2kaheCiDEjSr1xe", - "lpVault": "HUM5nLWT94iRQRQ7GSsjJ1DDWqWKhKfdGQCJCf7SypeD", - "rewardVaults": [ - "A5W9spnyknywKui1vudnxUomdnebrZVUnjKW6BHgUdyz", - "JE9PvgvXMnVfBkCdwJU4id1w2BaxTuxheKKFdBfRiJZi" - ], - "upcoming": false - }, - { - "id": "97N6tPMVCrAunC9embwTcffye9xC95fA5y3LauhNZ444", - "lpMint": "4bh8XCzTHSbqbWN8o1Jn4ueBdz1LvJFoEasN6K6CQ8Ny", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "hK1KZ5gEkGfrtQGF6qAP3tVjhYirRTt7TY3nFfwq8UV", - "lpVault": "4w3kTW8LYPMqCZAkWyHZ7wxgBrjpF72x6ca3d1Aigwki", - "rewardVaults": [ - "EhJLBNXDDZxXNDtYVineXadSe3T7zsHN8KsgwSAskQ4R", - "GTzobZsm4F4RTXDLnEJoWtXF7hxu9RDLpfvgcxDRfRUk" - ], - "upcoming": false - }, - { - "id": "HxhxYASqdLcR6yehT9hB9HUpgcF1R2t9HtkHdngGZ2Dh", - "lpMint": "69NCmEW9mGpiWLjAcAWHq51k4ionJZmzgRfRT3wQaCCf", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "FGJKdv7Wm1j75cBsj7FsZU256fhDSYVTwYkzFQ3sVQqg", - "lpVault": "CxY6pDZxPr8VAArC427NQficTpKEm3VxTVZEZQdQFexZ", - "rewardVaults": [ - "94zGzNAzv2xU8YW3uHYkiysjG9Qw2gCv7wx9tye1uYbE", - "8mJzCGURgpUDLnB3qaSQt3xyM7MEKpPcvzXxWTGCQbTb" - ], - "upcoming": false - }, - { - "id": "54vUWjEmg9wfCsZF7wwq2HJu5BU3cfDFAQQQgXPECcwE", - "lpMint": "HYv3grQfi8QbV7nG7EFgNK1aJSrsJ7HynXJKJVPLL2Uh", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "E4VNit9T28vRtiLv8e5o7HgVNs7frULkViYBpUjj6pTS", - "lpVault": "3vgFo13L14woTPNC249BFgwHMAAajfhjUbvDLSKDnBtP", - "rewardVaults": [ - "YVQYnEoLYv7d7JEGPLSSkmxpwVCdWjzA4kdeoag78kd", - "6pMVuiTtFSmzEPWzoUdQiQxcdEED5Z1jTakvQBHiGCcU" - ], - "upcoming": false - }, - { - "id": "914jyHBQFiroKFVCpKkzjGSaZyr4gMwgxE7snbNfGjnL", - "lpMint": "92bcERNtUmuaJ6mwLSxYHZYSph37jdKxRdoYNxpcYNPp", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "Gb17eJ4TK95SXPduUuh5YFJH4iz73qNFHmrqFBn1Tv9R", - "lpVault": "GYNDinXxGR5zsNn6bDWAidWFKT1JMQbyneuzPGosUDR7", - "rewardVaults": [ - "HVAxutFAei62E2Wn1eueYCrCPCCMrkho3xq6NyzW9hQA", - "7GbsEKskWjK9S4B3CayAGj2uL8v48u5RXZN7eSGWHABZ" - ], - "upcoming": false - }, - { - "id": "5gzQgxaKAU13SZeffmjjE2y9HwMJ42FxQkqJhJ5nqHeh", - "lpMint": "HDUJMwYZkjUZre63xUeDhdCi8c6LgUDiBqxmP3QC3VPX", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "DKSSeokFtU7cHKMdgNcZ72JETgf9Q3PqcGsk6hnzKxT4", - "lpVault": "CoUQ1tcRkEyxbCHfLkjxgUtYVhrRbsdeMKT7zB2iCZg5", - "rewardVaults": [ - "5fnav2gjLUjPCwHEnm2vMVmsDV3V8sfjj7MwfeUdgdtM", - "8geEcDpFkXqR2UEE2LVcYCzsD9cyGwJSu8Q56uqr1xs6" - ], - "upcoming": false - }, - { - "id": "Fbwy4XWMjXuP1nXg4xph4RJ9E9twVXeknXokF38PVgG1", - "lpMint": "ZRDfSLgWGeaYSmhdPvFNKQQhDcYdZQaue2N8YDmHX4q", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "Lrxqnh6ZHKbGy3dcrCED43nsoLkM1LTzU2jRfWe8qUC" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "CcRZ2sBjxFtPM2GFJ4HeRu4eeBTsx9Ng5Mug6uxUjZxo", - "lpVault": "DuYWhnzzb8yrqxnF2vd2TqP2WcWjAx9VneLhiMEwusPk", - "rewardVaults": [ - "xZHuntrMkq7EA9tahmuzC8Z4WoL7DhxoWDmGCkyaLf2", - "9AEGPpd5E6PbHkCxeFBB52xrK8fMrKdNKMaQDp95arX9" - ], - "upcoming": false - }, - { - "id": "HzxveT6pUMwYByqnScvTbpUv4avzkUDrDpS9D7DToEry", - "lpMint": "7yieit4YsNsZ9CAK8H5ZEMvvk35kPEHHeXwp6naoWU9V", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "Lrxqnh6ZHKbGy3dcrCED43nsoLkM1LTzU2jRfWe8qUC" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "sCDx3LzV8jPFX1VuRQDAGNKVfiCvhvrv3tJijaXzhXw", - "lpVault": "6PpGF8xRLwpDdVMQHQoBhrrXuUh5Gs4dCMs1DPanpjHM", - "rewardVaults": [ - "7tPiMrZB6kct1xNWLtG1jJqJYUJaG8548bEaJsb5HdXq", - "DXo3ffHBd69c9tV4wWBtFhc95UZMfYJehGnk3ViifSQ3" - ], - "upcoming": false - }, - { - "id": "8GBa1cK1NxevoxiRNK6YW9tWuo2xftcA3as9Cu4nhFL7", - "lpMint": "A8ZYmnZ1vwxUa4wpJVUaJgegsuTEz5TKy5CiJXffvmpt", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "8upjSpvjcdpuzhfR1zriwg5NXkwDruejqNE9WNbPRtyA" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "Gab4kPHmj5Hqn1KWEDsKt6Ta8jPtpc53oCPULszMNtyj", - "lpVault": "eoVzVdFEkKPKY3djJ47RZjvNr5oujYY25uxXwNvrsfg", - "rewardVaults": [ - "AYoDAc5ndfts4Aw6vzH7XUB2GsXamj72aunzBcBCnz2f", - "5i2qZN5UH4UyF3t6HNeC1bXeXhWBZy1pwpCjLDG7AdJJ" - ], - "upcoming": false - }, - { - "id": "HHm8Pgnzc56fTUYkicPv4DqGYp5fcPZFV1V1uhixSrMk", - "lpMint": "9ysGKUH6WqzjQEUT4dxqYCUaFNVK9QFEa24pGzjFq8xg", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "poLisWXnNRwC6oBu1vHiuKQzFjGL4XDSu4g9qjz9qVk" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "GHPg6z7HYx1bsdK4W9WpdmV8BcjpPBBsRGMmj9dAD3yq", - "lpVault": "4wGbaNEGeGjqqgW5S9AAWvQL3LwWZioH1JWMZFBdPFge", - "rewardVaults": [ - "4xrr44aG4kkgqQPZhBre93vg5fFY2htkkEEmTQjx5hiG", - "EanBQNubTJs2fNgeosUcESCfBnvk6bci391U5SH4Kzoo" - ], - "upcoming": false - }, - { - "id": "BHHhNLdJn69K1XPJcpcw4MBY3TPetpLxhj8s4K4ydsDV", - "lpMint": "418MFhkaYQtbn529wmjLLqL6uKxDz7j4eZBaV1cobkyd", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "ATLASXmbPQxBUYbxPsV97usA3fPQYEqzQBUHgiFCUsXx" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "DjYd34HtSwwAGfTfK13onUyq975akjzfW2abaK5YTRaS", - "lpVault": "5RPJHt2V4baK7gY1E99xCRBtEzScuNEVPr9vA9PapLhs", - "rewardVaults": [ - "AQwjpEoLwnHYnsdSnzwRpSkTSeLDNYZ6tv6odVGzXJvZ", - "DBXQnchh5zQuiEfaE8JBPTre8G1mksVTsHXoSqRPfA3r" - ], - "upcoming": false - }, - { - "id": "7qcihXTsRW5wS5BgK7iuD84W43ECByoJP45R3hu2r6mF", - "lpMint": "8MbKSBpyXs8fVneKgt71jfHrn5SWtX8n4wMLpiVfF9So", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "poLisWXnNRwC6oBu1vHiuKQzFjGL4XDSu4g9qjz9qVk" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "3MAzzKcBPJ2ykDHX1CBHzUJafy41FaTaLymg8z6SgX2Q", - "lpVault": "FwLD6rHMwm5H6edDPuGjxdBMk3u38frsnytTkPmVZVP3", - "rewardVaults": [ - "AWQr1eX2RZiMadfeEpgPEQJBJq88f7dPLK3nqriKCPJp", - "DfofnRgWFPHVaxaLGSdXvFGhr4TRwjdwQQvgkjNNkJfZ" - ], - "upcoming": false - }, - { - "id": "93wRz2LeQ3TJoair827VTng62MjCzYDgJjG9Q5GmQ3Pd", - "lpMint": "9shGU9f1EsxAbiR567MYZ78WUiS6ZNCYbHe53WUULQ7n", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "ATLASXmbPQxBUYbxPsV97usA3fPQYEqzQBUHgiFCUsXx" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "4yrRmmckKKGsPbCSFFupGqZrJhAFxQ4hN2DMC9Bh2pHo", - "lpVault": "HmE21hdD32ZjDnR5DvuNz7uS5q4bWbqf8jV2shx8kXmA", - "rewardVaults": [ - "9iQsupP7JagNLkp1bvdWWGVkzsLFfHUwDbh9KZPoXbw5", - "5oQU1hU6qggyT4CU2AMPcWTcZdSRZeQBy7How5WuEp7A" - ], - "upcoming": false - }, - { - "id": "BnYoq5y2MoH4TsBHeEZrEPowhwebHxQq7nJW1vTjPTWu", - "lpMint": "7P5Thr9Egi2rvMmEuQkLn8x8e8Qro7u2U7yLD2tU2Hbe", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "8JMnGryLkzSYdnTUPGRgxHoAmP5soH8L8TRre91Gjgni", - "lpVault": "6tuhozgcTA25fq5Lp11QX9HsG8MVspUjtcn7EgYP1cs5", - "rewardVaults": [ - "ED6Ak5wnnegeVz6jWMzGEEnFQ7HY55uPdxR8Ha6hk7gz", - "G4zqVtnHSK9Sp3SVdiQ5K56m46BdAoE2uQqpgVsmRG9d" - ], - "upcoming": false - }, - { - "id": "4wvZ9SwWaHKTpshQbCSKQoPosZp9KGwUzuQdESi39qPn", - "lpMint": "n76skjqv4LirhdLok2zJELXNLdRpYDgVJQuQFbamscy", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "CsZ5LZkDS7h9TDKjrbL7VAwQZ9nsRu8vJLhRYfmGaN8K" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "G3tniqor4UrtE29UQLGcBBuk4ScvonDpXiPSDTK3RioJ", - "lpVault": "Fx32reDAB5MyJJwr8CjCM1fNgFsmnjhaxjC9pJswpUok", - "rewardVaults": [ - "34gWdzwgj1zWQG4iwSbTeUDbQkoR8DXzLFQJsSpPDXLa", - "Gm4v69FCZ33HZsHAgtdezAUJK6n5fQ3zHpTZxAAzeyoJ" - ], - "upcoming": false - }, - { - "id": "BmbG9hv5PazcW3rYWvatA6HpNPkozEdkWBiU64pZxuwr", - "lpMint": "3AZTviji5qduMG2s4FfWGR3SSQmNUCyx8ao6UKCPg3oJ", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "TuLipcqtGVXP9XR62wM8WWCm6a9vhLs7T1uoWBk6FDs" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "956MvcyRBPMZ6waK3bdD4dn3XfaganoKed1NUQ9NaFAg", - "lpVault": "HMgHKCLetHYDUJZEXKRJCiSeQs4Udwy6MNXHoLruMctH", - "rewardVaults": [ - "5ih22SsrffDjygZHF8ADyJa4TNKQZqANg7dXyBJN9V8P", - "3zK56FmEqeH93BuH5K7JY9ZaEfFMdo3YjAasFikCmDB1" - ], - "upcoming": false - }, - { - "id": "JEC3P83x2GEijYDwXiksuh5H6YrQt5xW6MC2GDKkMoe", - "lpMint": "2k4quTuuLUxrSEhFH99qcoZzvgvVEc3b5sz3xz3qstfS", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "4dmKkXNHdgYsXqBHCuMikNQWwVomZURhYvkkX5c4pQ7y" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "9qwnkx2gRMLVoYkJVkyH2Yza5e5E7LoZEpx9jZ9r3CBY", - "lpVault": "7JrCLqrhH9kb78St4dAncBYE9VhZdB4P1tFAdxwzDrH5", - "rewardVaults": [ - "HmovkXKsso8xHwPYmMYF5bmP5CCwCtReQVb8ETTSSoyN", - "GXJSX1JNjjAK6jEEjujvzhCjMeVnZmpJ5fng3daynCnY" - ], - "upcoming": false - }, - { - "id": "J61AnYYSwjtJ4wDqEqqWSBuZbiR2SDDrtF7FFobutM6a", - "lpMint": "2pk78vsKT3jfJAcN2zbpMUnrR57SZrxHqaZYyFgp92mM", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "SLRSSpSLUTP7okbCUBYStWCo1vUgyt775faPqz8HUMr" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "BHGHqkJomVD5tKNMZFajA1PZEJaZW5Yywyp6UAcvf1Wq", - "lpVault": "H8NEHvqm43DxWbMfvLMvUqoKrjG4B4EJXEYBz2DYhRHd", - "rewardVaults": [ - "5g1ox4cwcfNFsqPiGH2zhsHYpaBf6rkigL6YR5ZBQA5k", - "95b2zMqRGsovcR69XXfRPcvLdyvLCH5M5nd4z27yC8Q1" - ], - "upcoming": false - }, - { - "id": "21xhrT4j8QnaBvj3QjhP5kZu8sXJMCE7hzHKGtWEkdKr", - "lpMint": "214hxy3AbKoaEKgqcg2aC1cP5R67cGGAyDEg5GDwC7Ub", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "MERt85fc5boKw3BW1eYdxonEuJNvXbiMbs6hvheau5K" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "6GrjogDgJ56mPcNu1nFw7MVLMALoNzd6RsZiXrQAuTvh", - "lpVault": "Ee4zr6okPiyG6ia8kZfPwoNRDtNsrn4YfPc7MMmTqufR", - "rewardVaults": [ - "FnSG5cBXyEqo3DxKrcjhj7wo8un3HrxABQrxfA5uKWsg", - "8yL9QK96Ag3NnvqZmcaupb7c4NeP5hJXraGS3jCzMzT" - ], - "upcoming": false - }, - { - "id": "DJfvL6srBht8XFMWYuuKHYGainqvwXyA5icVsDne3pwN", - "lpMint": "9Aseg5A1JD1yCiFFdDaNNxCiJ7XzrpZFmcEmLjXFdPaH", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "ETAtLmCmsoiEEKfNrHKJ2kYy3MoABhU6NQvpSfij5tDs" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "69PxTdPaRSofBJkwT9mYW14cPUEe7fU2AYEDvt3q5Fkt", - "lpVault": "3Kaibb6xYpKjFejtkgH8tBrMWShWzwBd7WfcGygZ4Vcw", - "rewardVaults": [ - "28kE8Erc2uFThiUr8RifoUEc9Kv8V54To6DJLgCuJEPp", - "3kofbYH2hPefwHSgMburaGN5XmJx7sD94jo5CsMCXzLE" - ], - "upcoming": false - }, - { - "id": "AMcVWK66iexwwCHn8drxywdNr2UgH3vmRzLXQFdErGmL", - "lpMint": "7xqDycbFSCpUpzkYapFeyPJWPwEpV7zdWbYf2MVHTNjv", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "3bRTivrVsitbmCTGtqwp7hxXPsybkjn4XLNtPsHqa3zR" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "32yVBkvq29AmXKu1A3xUtgHrMGFnLvxF18fhd4JLKfJs", - "lpVault": "6f72fpk4WDeqpTJZ4dLSvAacfwmCAfEk7RtuPQ5oyNd7", - "rewardVaults": [ - "4oPdHXXdRmjtKMLCcK8rtp3vMmq9y9LJ6W83mqrqMjCt", - "E49fLhK6Wv43FySZB1xybPghzK2cjr9hgfpcmcVSLeYm" - ], - "upcoming": false - }, - { - "id": "CM9XTJfXEHceGPXhmXxheR87Ng9CZ4jiBoTVQHhs9DVN", - "lpMint": "A7GCVHA8NSsbdFscHdoNU41tL1TRKNmCH4K94CgcLK9F", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "AWYeNgCErUafmBU2TtZgzNwixpKd3BxRTmvYDw7U1jgN", - "lpVault": "FLqRe3W9Lp59uNgzkACsXpEZkWUxBBstMtUyGSzqFhXD", - "rewardVaults": [ - "Ex23TUPEarZepXdHgjm7LVy35HDWY2VgeKao5kjYRZGE", - "JDjSMCSK9s9dDsiiXeT3HVaX48k7WewyKBoMPax3TZxL" - ], - "upcoming": false - }, - { - "id": "GzEDEkHSFFfxKMu3Toww1nrEjtbQGJKRPNRK1Pfd59Zn", - "lpMint": "DkiqCQ792n743xjWQVCbBUaVtkdiuvQeYndM53ReWnCC", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "9AMvw1TUJ9gX1kUAvcmHt2ZjokBLepXQbN8EJxBVZu2s", - "lpVault": "gjrMLKsNwXYzJnX9DT8Lc7HeC1AT52jQKtDkPiRRuEP", - "rewardVaults": [ - "4czqUC2ebdvqxPXfRniknLk7Cr2TosTabQSRnUeFia9v", - "6K1AE1wnTNaMgcAgQPvrTbnWEHB7nW6uTtv7ZbXWgMtn" - ], - "upcoming": false - }, - { - "id": "BRM5bdX2mjmFGg2RAent1Whd61o9asQD16BXsC6QvEni", - "lpMint": "cjZmbt8sJgaoyWYUttomAu5LJYU44ZrcKTbzTSEPDVw", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "3bRTivrVsitbmCTGtqwp7hxXPsybkjn4XLNtPsHqa3zR" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "9rThpjxEgNR5xi2z2QgXenS2RwRrrN1GqrudegT32Ygy", - "lpVault": "FzVu8n4UCf3o1KH4X8khM9KgKA96dJQdQMPtLvmbHyNi", - "rewardVaults": [ - "3G1cbktUU79CT3zskP16VYmEhwVQq2RYxVWV7fcjmkTX", - "2Ks41qfN2GZffbd1cqrNGuXJYJbShHhz6aHQvq8SaYYr" - ], - "upcoming": false - }, - { - "id": "Bw932pURVJRYjEJwRZGWjfUNpeyz18kjMNdb833eMxoj", - "lpMint": "HwzkXyX8B45LsaHXwY8su92NoRBS5GQC32HzjQRDqPnr", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "FzTbGLdzgWCRkq8hbS8tLf5HjfU7JzUbtRmTkjGQB9Vz", - "lpVault": "GUVKfYMiGEyp41CUw2j2NsoQJ5zDQ3Q6uSdApM8W46Ba", - "rewardVaults": [ - "J99YW5wnfgBJcG17BgSbp1S8RNJ39JAb7kg9RGHyb3Hq", - "GhctEMRSwvdZF7aFeCLdK9X1sAAeGVPjr12iVLjQNvhy" - ], - "upcoming": false - }, - { - "id": "5PVVwSqwzkCvuiKEZwWkM35ApBnoWqF8XopsVZjPwA8z", - "lpMint": "2Xxbm1hdv5wPeen5ponDSMT3VqhGMTQ7mH9stNXm9shU", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "SLRSSpSLUTP7okbCUBYStWCo1vUgyt775faPqz8HUMr" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "7jNUxDiLLyke8ECShavvPPQz4D1abj4aCZwQfZ3TCTAX", - "lpVault": "HTr2pYDBQZP13YTzLdsPzmh6e4hsNeqoGy3B777ejqTT", - "rewardVaults": [ - "Ef1tQ2E2Fe92xPVpQGzZFHmT7g7dh2hzVfWYVJJQPdbu", - "Ffmv9Ximzk8D9oKwHkkgdq9cVxv5P5Y9LxEJdu1N1jSJ" - ], - "upcoming": false - }, - { - "id": "EEe8b72w5q6T86nYRNJdFcY25tznPzrd1jGjuxZ7f9mX", - "lpMint": "9nQPYJvysyfnXhQ6nkK5V7sZG26hmDgusfdNQijRk5LD", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "BLwTnYKqf7u4qjgZrrsKeNs2EzWkMLqVCu6j8iHyrNA3" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "7d99wJT2nRjWe2eKF7FpzMFb7934KoRhLP7pp2bjRm9m", - "lpVault": "FWMHgA5iUxz3zMYf7jRJk8Z9ebWNWpvd7358rGCPFr7M", - "rewardVaults": [ - "DhvRSrQUio8LpCJH4uFCvvK4MEYVrBA6xaj1hu9jVxZn", - "3c6552swYV5nBTKTCWfKURjN1uGjtceanfb3vRbHNXpN" - ], - "upcoming": false - }, - { - "id": "31QSh1TwgoA9GbvkgfEEwKEm11t8CR4KiQr6WCyJr7EN", - "lpMint": "G8qcfeFqxwbCqpxv5LpLWxUCd1PyMB5nWb5e5YyxLMKg", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "4dmKkXNHdgYsXqBHCuMikNQWwVomZURhYvkkX5c4pQ7y" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "BbebocNt4ySwkufrY1X3wRG8PVefCRLFR2E2TGzZPkne", - "lpVault": "2t1qozn7xtWjuCqnnTx4PaKikajN2AQK3CVH6A5JqagY", - "rewardVaults": [ - "GXZq2zNPZ9odPWAPinxXK8B7cMaAN9CpbcaLicksJsbt", - "DdSL2stD9UXfY2nj9MKrNPx8QTro1GGAY6rsBd9kJXMX" - ], - "upcoming": false - }, - { - "id": "7U8Z6TWQMtsMcHV2htALnF9VQonnD1MrVm17YtmGEGEw", - "lpMint": "2doeZGLJyACtaG9DCUyqMLtswesfje1hjNA11hMdj6YU", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "TuLipcqtGVXP9XR62wM8WWCm6a9vhLs7T1uoWBk6FDs" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "9ZVNLEiBZ2u23P7rEJf5sXY7TZK723cmVs46pBRSbRnU", - "lpVault": "B6xn6doS3Qfy1LJLbdcJa5MpJ4po2bgut1rKFvmmq6Ut", - "rewardVaults": [ - "GtPTgCr6nXiogRCWqGvLa8P6dJgZpHfAX3KxGMpxnGMJ", - "8qgijAifBGx2EAJ7zKAzk6z7dVpcDV9eHvTBwofmdTP5" - ], - "upcoming": false - }, - { - "id": "JAP8SFagJBm6vt2LoFGNeSJ1hKDZ2p3yXb3CvBx11How", - "lpMint": "iUDasAP2nXm5wvTukAHEKSdSXn8vQkRtaiShs9ceGB7", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "CsZ5LZkDS7h9TDKjrbL7VAwQZ9nsRu8vJLhRYfmGaN8K" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "DVtR63sAnJPM9wdt1hYBqA5GTyFzjfcfdLTfsSzV85Ss", - "lpVault": "feCzxSvVX4EboJV4cubjqoPTK41noaHUanz8ZNJmiBp", - "rewardVaults": [ - "4mAhgUY8XGMY4743wuzVbLw7d5bqqTaxME8jmbC2YfH4", - "3sGDa8ir8GrkKbnBH6HP63JaYSs7nskmmVHpF2vuzaZr" - ], - "upcoming": false - }, - { - "id": "BLy8KuRck5bcJkQdMDLSZnL1Ka4heAZSGiwTJfEfY727", - "lpMint": "Cq4HyW5xia37tKejPF2XfZeXQoPYW6KfbPvxvw5eRoUE", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "8PMHT4swUMtBzgHnh5U564N5sjPSiUz2cjEQzFnnP1Fo" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "8xPzoFPHKWZHWmwKaxFUyVBf2V13HMbCrMDgaCZCLjgx", - "lpVault": "DiebAVak6cub1Mn3yhhvgSvGhkAP1JTtyRGoAei4wrWE", - "rewardVaults": [ - "4F9FaFewwsSF8Bsxukyj9NiEdPFQQ38dNKEDpZugYfdi", - "4tvLbnZEPZLuDf636DHEzrUxW8bDoZ5XyfVwk7ppDhbC" - ], - "upcoming": false - }, - { - "id": "D4pYuD4tbir9KBsb7Kr63v9e86JY2UoUZeFK9eHKQFZM", - "lpMint": "3H9NxvaZoxMZZDZcbBDdWMKbrfNj7PCF5sbRwDr7SdDW", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "MERt85fc5boKw3BW1eYdxonEuJNvXbiMbs6hvheau5K" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "2T46saTyTYeEFWyesRzLWj6y1ha9ngwcyWyGNn9q4zu4", - "lpVault": "EV3wsqiMiNcBmo2mFkUuCtib36NpBCsC2vfkW3By1sSu", - "rewardVaults": [ - "5gEH5Uq2QrqiEhdZ8YFAMY1HoYnKMiuu71f6BC25UXee", - "FTP4hnN5GPtPYvkrscTkKWYVVQ56hV3f4wGgpEXgrDUD" - ], - "upcoming": false - }, - { - "id": "AxVvbT9fDFEkmdLwKUJRY5HsG2RXAZbe1dRAgJ2bDDwg", - "lpMint": "Cz1kUvHw98imKkrqqu95GQB9h1frY8RikxPojMwWKGXf", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "3n1Vdmqu1MBUpBYMpYbpJAVFv4MeNMEa82waruLy7BDu", - "lpVault": "BHLzrd5MgQy4NgmUsn542yXRZWkz1iV5bfWg8s8D4tVL", - "rewardVaults": [ - "7nGY6xHCUR2MxJnHT1qvArRUEnpo2DsGGf6Pdu3tt9gv", - "6ezx1EivkxsJcZLYhSJFLc3nUs25iyubf8PPyRNEX3pL" - ], - "upcoming": false - }, - { - "id": "Ef1gD9JMzWF6PNw2uc4744zouh57GyWAeVTjHHbQ2nsu", - "lpMint": "A5zanvgtioZGiJMdEyaKN4XQmJsp1p7uVxaq2696REvQ", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "ETAtLmCmsoiEEKfNrHKJ2kYy3MoABhU6NQvpSfij5tDs" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "3dhU2g3MSHK3LwjuE1VsEJCsNeWKyBJUMHt4EUXepTjs", - "lpVault": "DGjRtqsjeubLCLPD3yH8fj1d7TnrD3jKBpwa1UbVk7E6", - "rewardVaults": [ - "Uen8f9Rn42i8sDTK5vEttrnX9AUwXV3yf6DFU63mKDb", - "Ek6n7Myojb6pSpQuqk5AyS7KXQdXkJyZT7ki9baYCxds" - ], - "upcoming": false - }, - { - "id": "8xhjCzfzVcP79jE7jXR2xtNaSL6aJYoDRLVT9FMjpRTC", - "lpMint": "3k8BDobgihmk72jVmXYLE168bxxQUhqqyESW4dQVktqC", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "StepAscQoEioFxxWGnh2sLBDFp9d8rvKz2Yp39iDpyT" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "6wRMPrHKFzj3qB4j5yj4y9mDF89fZ6w7gD1cEzCJwT9B", - "lpVault": "CP3wdgdSygYGLJMjKfbJMiANnYuAxXHPiLTtB124tzVX", - "rewardVaults": [ - "3zSiR4XrrRPhsom2hh9iigYZZ7uCpMucfJnZRgREgH8j", - "4n3vRUk3wdtbGWgMFSaxUcnGLKwa2wiWVhqw7kv9JDVS" - ], - "upcoming": false - }, - { - "id": "XnRBbNMf6YcWvC1u2vBXXuMcagmRBRLu1y84mpqnKwW", - "lpMint": "2Vyyeuyd15Gp8aH6uKE72c4hxc8TVSLibxDP9vzspQWG", - "rewardMints": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "3K6rftdAaQYMPunrtNRHgnK2UAtjm2JwyT2oCiTDouYE" - ], - "version": 5, - "programId": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z", - "authority": "AnYvA5H7oBeA1otnWHSu8ud3waFsEmfUbdAoM1VzdVvt", - "lpVault": "6tXWzm8nLVtNtvqDH8bZNfUwpSjEcKZoJFpcV4hC5rLD", - "rewardVaults": [ - "8GoDpozsDk3U3J36vvPiq3YpnA6MeJb1QPVJFiupe2wR", - "7niS4ngxgZ3oynHwH82PnwJXicTnY3fo9Vubi1PnjzJq" - ], - "upcoming": false - } - ] -} diff --git a/farms/farm-ctrl/metadata/farms/raydium/farms_dev.json b/farms/farm-ctrl/metadata/farms/raydium/farms_dev.json deleted file mode 100644 index 4dbe99aad16..00000000000 --- a/farms/farm-ctrl/metadata/farms/raydium/farms_dev.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "Raydium Farms", - "farms": [ - { - "name": "COIN-PC", - "lp": "LP.RDM.COIN-PC-V4", - "reward": "COIN", - "rewardB": "PC", - "isStake": false, - "fusion": true, - "legacy": false, - "dual": true, - "version": 5, - "programId": "STAKE_PROGRAM_ID_V5", - "poolId": "2Bsexc5j6vk4r9RhBYz2ufPrRWhumXQk6efXucqUKsyr", - "poolAuthority": "BxAtWJ4g6xguPsR9xNvXTK7EjuzwiKNbmKbhoXDZ3EsY", - "poolLpTokenAccount": "83BEhzv7eV4HeJuuPtYmHkhTjZEpNpK83mHnHfX5Krwj", - "poolRewardTokenAccount": "HVtAJ1uRiWJ7tNU9uqAzpPv14B3fN9SVEW9G4PtM77Ci", - "poolRewardTokenAccountB": "39Ea6rMGGrsNmEsYToqQfEyNSqv7hcUJa646qBYLY4yq" - } - ] -} diff --git a/farms/farm-ctrl/metadata/farms/raydium/get_farms.sh b/farms/farm-ctrl/metadata/farms/raydium/get_farms.sh deleted file mode 100755 index 39d294dac32..00000000000 --- a/farms/farm-ctrl/metadata/farms/raydium/get_farms.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -url="https://api.raydium.io/v2/sdk/farm/mainnet.json" - -if hash wget 2>/dev/null; then - wget_or_curl="wget -O farms.json $url" -elif hash curl 2>/dev/null; then - wget_or_curl="curl -o farms.json -L $url" -else - echo "Error: Neither curl nor wget were found" >&2 - return 1 -fi - -exec $wget_or_curl \ No newline at end of file diff --git a/farms/farm-ctrl/metadata/farms/saber/pools_and_farms.json b/farms/farm-ctrl/metadata/farms/saber/pools_and_farms.json deleted file mode 120000 index 58a251c20f1..00000000000 --- a/farms/farm-ctrl/metadata/farms/saber/pools_and_farms.json +++ /dev/null @@ -1 +0,0 @@ -../../pools/saber/pools_and_farms.json \ No newline at end of file diff --git a/farms/farm-ctrl/metadata/pools/orca/get_pools_and_farms.js b/farms/farm-ctrl/metadata/pools/orca/get_pools_and_farms.js deleted file mode 100644 index 05642813911..00000000000 --- a/farms/farm-ctrl/metadata/pools/orca/get_pools_and_farms.js +++ /dev/null @@ -1,60 +0,0 @@ -const orca_sdk = require("@orca-so/sdk"); -const solana = require("@solana/web3.js"); -const fs = require("fs"); - -function replacer(key, value) { - if (typeof value === "object" && "_bn" in value) { - return value.toString(); - } - return value; -} - -const getPools = () => { - const connection = new solana.Connection( - "https://api.mainnet-beta.solana.com", - "singleGossip" - ); - const orca = orca_sdk.getOrca(connection); - - let pools = new Array(); - for (const [key, value] of Object.entries(orca_sdk.OrcaPoolConfig)) { - const orcaPool = orca.getPool(value); - pools.push({ ...{ name: key }, ...orcaPool.poolParams }); - } - console.log( - '{\n"name": "Orca Pools",\n"pools":\n', - JSON.stringify(pools, replacer, 2), - "\n}" - ); -}; - -const getFarms = () => { - const connection = new solana.Connection( - "https://api.mainnet-beta.solana.com", - "singleGossip" - ); - const orca = orca_sdk.getOrca(connection); - - let farms = new Array(); - for (const [key, value] of Object.entries(orca_sdk.OrcaFarmConfig)) { - const orcaFarm = orca.getFarm(value); - farms.push({ ...{ name: key }, ...orcaFarm.farmParams }); - } - console.log( - '{\n"name": "Orca Farms",\n"farms":\n', - JSON.stringify(farms, replacer, 2), - "\n}" - ); -}; - -if (process.argv.length > 2) { - if (process.argv[2] == "get_pools") { - getPools(); - } else if (process.argv[2] == "get_farms") { - getFarms(); - } else { - console.error("Use it with get_pools or get_farms argument"); - } -} else { - console.error("Use it with get_pools or get_farms argument"); -} diff --git a/farms/farm-ctrl/metadata/pools/orca/pools.json b/farms/farm-ctrl/metadata/pools/orca/pools.json deleted file mode 100644 index cc9d5c63fb6..00000000000 --- a/farms/farm-ctrl/metadata/pools/orca/pools.json +++ /dev/null @@ -1,5170 +0,0 @@ -{ - "name": "Orca Pools", - "pools": [ - { - "name": "SOL_USDC", - "address": "EGZ7tiLeH62TPV1gL8WwbXGzEPa9zmcpVnnkPKKnrE2U", - "nonce": 252, - "authority": "JU8kmKzDHF9sXWsnoznaFDFezLsE5uomX2JkRMbmsQP", - "poolTokenMint": "APDFRM3HMr8CAGXwKHiu2f5ePSpaiEJhaURwhsRrUUt9", - "poolTokenDecimals": 6, - "feeAccount": "8JnSiuvQq3BVuCU3n4DrSTw9chBSPvEMswrhtifVkr1o", - "tokenIds": [ - "So11111111111111111111111111111111111111112", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "ANP74VNsHwSrq9uUSjiSNyNWvf6ZPrKTmE4gHoNd13Lg" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "75HgnSvXbWKZBpZHveX68ZzAhDqMzNDS29X6BGLtxMo1" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "SOL_USDT", - "address": "Dqk7mHQBx2ZWExmyrR2S8X6UG75CrbbpK2FSBZsNYsw6", - "nonce": 255, - "authority": "2sxKY7hxVFrY5oNE2DgaPAJFamMzsmFLM2DgVcjK5yTy", - "poolTokenMint": "FZthQCuYHhcfiDma7QrX7buDHwrZEd7vL8SjS6LQa3Tx", - "poolTokenDecimals": 6, - "feeAccount": "BBKgw75FivTYXj85D2AWyVdaTdTWuSuHVXRm1Xu7fipb", - "tokenIds": [ - "So11111111111111111111111111111111111111112", - "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" - ], - "tokens": { - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "DTb8NKsfhEJGY1TrA7RXN6MBiTrjnkdMAfjPEjtmTT3M" - }, - "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB": { - "tag": "USDT", - "name": "Tether USD", - "mint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "scale": 6, - "addr": "E8erPjPEorykpPjFV9yUYMYigEWKQUxuGfL2rJKLJ3KU" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "ETH_SOL", - "address": "EuK3xDa4rWuHeMQCBsHf1ETZNiEQb5C476oE9u9kp8Ji", - "nonce": 255, - "authority": "DffrDbzPiswDJaiicBBo9CjqztKgFLrqXGwNJH4XQefZ", - "poolTokenMint": "71FymgN2ZUf7VvVTLE8jYEnjP3jSK1Frp2XT1nHs8Hob", - "poolTokenDecimals": 6, - "feeAccount": "unxKgWEc71ZiHwMqZs3VLqjcjmZhfTZEg94ZLGvjdMP", - "tokenIds": [ - "2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk": { - "tag": "ETH", - "name": "Ethereum", - "mint": "2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk", - "scale": 6, - "addr": "7F2cLdio3i6CCJaypj9VfNDPW2DwT3vkDmZJDEfmxu6A" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "5pUTGvN2AA2BEzBDU4CNDh3LHER15WS6J8oJf5XeZFD8" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "ETH_USDC", - "address": "FgZut2qVQEyPBibaTJbbX2PxaMZvT1vjDebiVaDp5BWP", - "nonce": 253, - "authority": "4dfCZR32xXhoTgMRhnViNaTFwiKP9A34TDjHCR3xM5rg", - "poolTokenMint": "3e1W6Aqcbuk2DfHUwRiRcyzpyYRRjg6yhZZcyEARydUX", - "poolTokenDecimals": 6, - "feeAccount": "DLWewB12jzGn4wXJmFCddWDeof1Ma4cZYNRv9CP5hTvX", - "tokenIds": [ - "2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk": { - "tag": "ETH", - "name": "Ethereum", - "mint": "2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk", - "scale": 6, - "addr": "H9h5yTBfCHcb4eRP87fXczzXgNaMzKihr7bf1sjw7iuZ" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "JA98RXv2VdxQD8pRQq4dzJ1Bp4nH8nokCGmxvPWKJ3hx" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "RAY_SOL", - "address": "3THMPkPmcHJ54JtHRyazhs7UN7HbV5KiNJVLJs6hSPSC", - "nonce": 255, - "authority": "EUc3MtHPLL956pTDfM5q25jp5Fk9zW7omEzh1uyDY7s6", - "poolTokenMint": "5kimD5W6yJpHRHCyPtnEyDsQRdiiJKivu5AqN3si82Jc", - "poolTokenDecimals": 6, - "feeAccount": "65XNtnUsP1TMzKMGhMoD3GUFMNbmnZQwDaxDLE3jncUC", - "tokenIds": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R": { - "tag": "RAY", - "name": "Raydium", - "mint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "scale": 6, - "addr": "GZaUNWf4ov6VZaD5MqZtc5pHB3mWTqczNUB4sstt8CSR" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "GNSZ1rr57QQ6qLcmZnhMcoBymenVezhNpzcFSfJP37h9" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "ROPE_SOL", - "address": "DCENobjFZK59nLeMCVRkQtnkAWrJkWAVpmVnwVNc8gqH", - "nonce": 251, - "authority": "C2DDX95TK3uC9MQXhHp3LWRv9kWtFTp36Ub9VPCKKiCV", - "poolTokenMint": "ADrvfPBsRcJfGsN6Bs385zYddH52nuM5FA8UaAkX9o2V", - "poolTokenDecimals": 6, - "feeAccount": "88rKjeeDQYJxGVCG39znDvbxzjPc5H37XqHRQCSNJvED", - "tokenIds": [ - "8PMHT4swUMtBzgHnh5U564N5sjPSiUz2cjEQzFnnP1Fo", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "8PMHT4swUMtBzgHnh5U564N5sjPSiUz2cjEQzFnnP1Fo": { - "tag": "ROPE", - "name": "Rope", - "mint": "8PMHT4swUMtBzgHnh5U564N5sjPSiUz2cjEQzFnnP1Fo", - "scale": 9, - "addr": "HLHPVwgzYjTHmu1fmV9eZzdE8H3fZwhuCBRNNN2Z5miA" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "7Be3aStQmKgeXC1xqfJnA8qaGzw6keQTLqHYAJprZK2H" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "STEP_SOL", - "address": "2sNtf8wLZMR7XJm2pzvvVUNPTNRFsGTiC5vgDSGv5QGD", - "nonce": 255, - "authority": "HzAJLVqZ7fnmc2LfRPtz2GHu93RpAPQsdDTg6DRoTTmf", - "poolTokenMint": "8nTzqDXHriG2CXKbybeuEh1EqDQMtrbYMFWcP7AkiDaP", - "poolTokenDecimals": 6, - "feeAccount": "5FEmPmAk72NycwzMXLD3hc2f47zRXocv4mvd3HEUZ5io", - "tokenIds": [ - "StepAscQoEioFxxWGnh2sLBDFp9d8rvKz2Yp39iDpyT", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "StepAscQoEioFxxWGnh2sLBDFp9d8rvKz2Yp39iDpyT": { - "tag": "STEP", - "name": "Step", - "mint": "StepAscQoEioFxxWGnh2sLBDFp9d8rvKz2Yp39iDpyT", - "scale": 9, - "addr": "35opuEpVvggzfV361hQVNXiC7KAKS1HCeDoVpfVybo8k" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "A3DSsYZJWHiwXSQb7P2AbEoaWhpauJLU1PVdTPnzV5s9" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "SRM_SOL", - "address": "EJRXAkKyDhDgzdZz1Ss5CpWKWSK9xTR5S6GDLAer8mdh", - "nonce": 255, - "authority": "2pQbngWBSWUjBHWVWQ3tppKxW3Y5NzUcye1822itKyzZ", - "poolTokenMint": "9tf8rBSEQYG7AqL896fN2nZi1iYPqpWaLEdpbeQaC1Vy", - "poolTokenDecimals": 6, - "feeAccount": "APyc1s8wES4Q2FTqHN8jXZtRuWQyRWZ82u7EFfras2iZ", - "tokenIds": [ - "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt": { - "tag": "SRM", - "name": "Serum", - "mint": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "scale": 6, - "addr": "2JCxZv6LaFjtWqBXSC2brsWE9WryS4Cp3VwwDeNGvLyv" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "EdhG3vQbTVVAARZB4AbhU2HsVbvfFqX2yhBAfFV22nzA" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "FTT_SOL", - "address": "68Bg6yQxWm3mrUYk3XzMiF5ycE41HwPhyEdaB1cp6wuo", - "nonce": 255, - "authority": "BpshqwEmPXmJwJfFgTFafmXoHN8Lc7SouvFsh6jyYQAm", - "poolTokenMint": "EsYaDKJCmcJtJHFuJYwQZwqohvVMCrFzcg8yo3i328No", - "poolTokenDecimals": 6, - "feeAccount": "FWBCbjZnypLKz7uHGJXpBAEez2FurQXi9J3js7ZT1xDe", - "tokenIds": [ - "AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3": { - "tag": "FTT", - "name": "FTX Token", - "mint": "AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3", - "scale": 6, - "addr": "3eVE92aEAsLYcBACXNu1yxoHVfTM8e8vmQC2zSApGRJX" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "BbsiNbFfJsRDwqF4JaiJ6sKecNuY4eWmEaDHcY6h6HuD" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "COPE_SOL", - "address": "BRx4dJecxzeGYc1BskCWonfGCeMyv9G7tk66cf2QGhK6", - "nonce": 254, - "authority": "JAJr1D6BQHFj9qJ8pfXhvJgLfn9vTcviU9sTA8MhKzN4", - "poolTokenMint": "CzieDbGRdN1QGaGDNpSqzEA18bi881ccvkkGZi51pe1k", - "poolTokenDecimals": 6, - "feeAccount": "9X8VRnxk6EVKGA7TErdSZYFC8oLUM569pDbZTtycjvXw", - "tokenIds": [ - "8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh": { - "tag": "COPE", - "name": "Cope", - "mint": "8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh", - "scale": 6, - "addr": "7v5GCdHH439SztxcqL4wpfWdPvv9EfMm8GYTHSUQoGoY" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "5tSgRUK6f2x1nAXA4gdcHNXiWdToqni9pr5xvq2Fq82u" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "OXY_SOL", - "address": "Cq4EZrvuFQpsCz8L3gS6t7iQ7VWzTtqDgSxD4AgVAAfd", - "nonce": 255, - "authority": "FxxcJPunf6Vj9Ve5zyM9yatMbmkrzTQ1QSk4NqKW9DvK", - "poolTokenMint": "7tYCdLN84EnTMkxM7HNamWJx7F4xgKe9KiiWvLyWjbgT", - "poolTokenDecimals": 6, - "feeAccount": "Ch8i2A1GAspivXYfdme7vSxh1mhRjmRgeiKN8KpWhVqo", - "tokenIds": [ - "z3dn17yLaGMKffVogeFHQ9zWVcXgqgf3PQnDsNs2g6M", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "z3dn17yLaGMKffVogeFHQ9zWVcXgqgf3PQnDsNs2g6M": { - "tag": "OXY", - "name": "Oxygen", - "mint": "z3dn17yLaGMKffVogeFHQ9zWVcXgqgf3PQnDsNs2g6M", - "scale": 6, - "addr": "BoZQMfTLTPcXnevJxNFkECVbKesfhXnTUg4kxLgzV9BX" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "8ZrEcJbgg7BdoBga5RYDR8aMujLf5cAQp8zdPZqk7nNC" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "BTC_SOL", - "address": "7N2AEJ98qBs4PwEwZ6k5pj8uZBKMkZrKZeiC7A64B47u", - "nonce": 255, - "authority": "GqnLhu3bPQ46nTZYNFDnzhwm31iFoqhi3ntXMtc5DPiT", - "poolTokenMint": "Acxs19v6eUMTEfdvkvWkRB4bwFCHm3XV9jABCy7c1mXe", - "poolTokenDecimals": 6, - "feeAccount": "4yPG4A9jB3ibDMVXEN2aZW4oA1e1xzzA3z5VWjkZd18B", - "tokenIds": [ - "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E": { - "tag": "BTC", - "name": "Bitcoin", - "mint": "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "scale": 6, - "addr": "9G5TBPbEUg2iaFxJ29uVAT8ZzxY77esRshyHiLYZKRh8" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "5eqcnUasgU2NRrEAeWxvFVRTTYWJWfAJhsdffvc6nJc2" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "MER_SOL", - "address": "UJBm2tHwDbQZpjQvaHozg5qkjh6prSKhnWheqR5T76Q", - "nonce": 255, - "authority": "C8HcMrC9WRqqXVbHRhZWjuZPbbWmszDobKFxevCtGhpT", - "poolTokenMint": "HiwRobjfHZ4zsPtqCC4oBS24pSmy4t8GGkXRbQj4yU6L", - "poolTokenDecimals": 6, - "feeAccount": "3Fdj69449GhiDmqyvWWTSafjRphGdiDhZ5i5rqfHBdio", - "tokenIds": [ - "MERt85fc5boKw3BW1eYdxonEuJNvXbiMbs6hvheau5K", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "MERt85fc5boKw3BW1eYdxonEuJNvXbiMbs6hvheau5K": { - "tag": "MER", - "name": "Mercurial", - "mint": "MERt85fc5boKw3BW1eYdxonEuJNvXbiMbs6hvheau5K", - "scale": 6, - "addr": "DHdkRWTa9SRJNMtWZQYvNNbjrDP3n92EWLHezjFGPipb" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "DC5RwjB3VkXdt2PoWKTA4Ub9KbtcY8xXpmPNKsFjALwq" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "FIDA_SOL", - "address": "4SUBbivGMvMhem3ajVtkmuPvL4GuQ8kfYTJFuQfG4F8t", - "nonce": 255, - "authority": "owuNLod7H14GpQCUodcdBBeD4LiZ2T5U9KpS2sAbTp6", - "poolTokenMint": "EYsNdtyu4gGTaGz8N5m5iQ3G1N6rDyMbR72B3CqbWW4W", - "poolTokenDecimals": 6, - "feeAccount": "J2s1GpduscTTvMYt3os8LdvT24uhr9bPnTbxSKZZhEma", - "tokenIds": [ - "EchesyfXePKdLtoiZSL8pBe8Myagyy8ZRqsACNCFGnvp", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "EchesyfXePKdLtoiZSL8pBe8Myagyy8ZRqsACNCFGnvp": { - "tag": "FIDA", - "name": "Bonfida", - "mint": "EchesyfXePKdLtoiZSL8pBe8Myagyy8ZRqsACNCFGnvp", - "scale": 6, - "addr": "9ofyx5yFzjH1XWmJzfiGCDfhq6ho8yFbszGQrrJXe54" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "55moYcq91pXbSRpL2DR8P3BehqSNWiJrdTn5SZFc2STn" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "MAPS_SOL", - "address": "4rkgbbCPKk5zx3KiwcCNiSpNSSLgAkswKGfX7CJjGgtC", - "nonce": 255, - "authority": "8uuBxVsGf2bqH5t8mct5NfpgcTDb7czXuWVEm6Boia4x", - "poolTokenMint": "99pfC8fWymXgbq3CvrExhx3UxQDC1fMWEWLbNT83F45e", - "poolTokenDecimals": 6, - "feeAccount": "8w3gx1GQ1UN5sodEVP14qUwzCcgopHWUeWbT26hgK3xh", - "tokenIds": [ - "MAPS41MDahZ9QdKXhVa4dWB9RuyfV4XqhyAZ8XcYepb", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "MAPS41MDahZ9QdKXhVa4dWB9RuyfV4XqhyAZ8XcYepb": { - "tag": "MAPS", - "name": "MAPS", - "mint": "MAPS41MDahZ9QdKXhVa4dWB9RuyfV4XqhyAZ8XcYepb", - "scale": 6, - "addr": "BqExNTYk7YdeiaREHqnqN2q1F3dBCTPhkwrrWBFD4F1m" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "HdEQ99E979aXn2xTcg5UXEfLynwFkqpPTxLaNkH7Nz7P" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "USDC_USDT", - "address": "F13xvvx45jVGd84ynK3c8T89UejQVxjCLtmHfPmAXAHP", - "nonce": 255, - "authority": "3cGHDS8uWhdxQj14vTmFtYHX3NMouPpE4o9MjQ43Bbf4", - "poolTokenMint": "H2uzgruPvonVpCRhwwdukcpXK8TG17swFNzYFr2rtPxy", - "poolTokenDecimals": 6, - "feeAccount": "B4RNxMJGRzKFQyTq2Uwkmpyjtew13n7KtdqZy6qgENTu", - "tokenIds": [ - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" - ], - "tokens": { - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "6uUn2okWk5v4x9Gc4n2LLGHtWoa9tmizHq1363dW7t9W" - }, - "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB": { - "tag": "USDT", - "name": "Tether USD", - "mint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "scale": 6, - "addr": "AiwmnLy7xPT28dqZpkRm6i1ZGwELUCzCsuN92v4JkSeU" - } - }, - "curveType": 2, - "amp": 100, - "feeStructure": { - "traderFee": { - "numerator": "06", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "01", - "denominator": "2710" - } - } - }, - { - "name": "ORCA_SOL", - "address": "2ZnVuidTHpi5WWKUwFXauYGhvdT9jRKYv5MDahtbwtYr", - "nonce": 255, - "authority": "2PH1quJj9MHQXATCmNZ6qQ2gZqM8R236DpKaz99ggVpm", - "poolTokenMint": "2uVjAuRXavpM6h1scGQaxqb6HVaNRn6T2X7HHXTabz25", - "poolTokenDecimals": 6, - "feeAccount": "4Zc4kQZhRQeGztihvcGSWezJE1k44kKEgPCAkdeBfras", - "tokenIds": [ - "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE": { - "tag": "ORCA", - "name": "Orca", - "mint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "scale": 6, - "addr": "AioST8HKQJRqjE1mknk4Rydc8wVADhdQwRJmAAYX1T6Z" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "73zdy95DynZP4exdpuXTDsexcrWbDJX9TFi2E6CDzXh4" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "ORCA_USDC", - "address": "2p7nYbtPBgtmY69NsE8DAW6szpRJn7tQvDnqvoEWQvjY", - "nonce": 254, - "authority": "3fr1AhdiAmWLeNrS24CMoAu9pPgbzVhwLtJ6QUPmw2ob", - "poolTokenMint": "n8Mpu28RjeYD7oUX3LG1tPxzhRZh3YYLRSHcHRdS3Zx", - "poolTokenDecimals": 6, - "feeAccount": "7CXZED4jfRp3qdHB9Py3up6v1C4UhHofFvfT6RXbJLRN", - "tokenIds": [ - "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE": { - "tag": "ORCA", - "name": "Orca", - "mint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "scale": 6, - "addr": "9vYWHBPz817wJdQpE8u3h8UoY3sZ16ZXdCcvLB7jY4Dj" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "6UczejMUv1tzdvUzKpULKHxrK9sqLm8edR1v9jinVWm9" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "KIN_SOL", - "address": "Ez52BLSoZw3MxWxMK4ADsJXqzUiYW9sUnwcrrQwQGdLT", - "nonce": 253, - "authority": "C6WisvFQzqxTBF3DV6RFbPMPBiVHE816CZHoctB3WzrW", - "poolTokenMint": "HEvnD66WcBfTajS9adUYnGRBMDehFtLySiFHSD6kEBWs", - "poolTokenDecimals": 6, - "feeAccount": "5bLeJU66qTopjZBa48BUd7EXWcj4UeCMfHjjrvt8Zcgs", - "tokenIds": [ - "kinXdEcpDQeHPEuQnqmUgtYykqKGVFq6CeVX5iAHJq6", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "kinXdEcpDQeHPEuQnqmUgtYykqKGVFq6CeVX5iAHJq6": { - "tag": "KIN", - "name": "Kin", - "mint": "kinXdEcpDQeHPEuQnqmUgtYykqKGVFq6CeVX5iAHJq6", - "scale": 5, - "addr": "2Ssm5Dd1Zc5QpGSZzuqt3Ef4bADteuBbCGiEZJ5n48rV" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "HCS9EpKRxWDS9GCRFStNbPWgRQpvV6EyBWChJja2UbCm" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "SAMO_SOL", - "address": "DiAP9qmp5foN7fLTWfBWjo9KBS1jgvKUJLWi1ZhqKaja", - "nonce": 255, - "authority": "3uZcofBKVBYFrQ7jVjTFLEMWAQiZcih4AES5tKBqdo7m", - "poolTokenMint": "D6N9j8F2DhtzDtrdpT74y3u2YmYAzcggiLc3nTjqux9M", - "poolTokenDecimals": 6, - "feeAccount": "BYAjG645fRRHZ5JFnZKnXc4dzK9WppcoVWDMYj3zm3KF", - "tokenIds": [ - "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU": { - "tag": "SAMO", - "name": "Samoyedcoin", - "mint": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU", - "scale": 9, - "addr": "AFcbD7UTzk9d1njRxyDHNbQ5Q6miPNAE1GctjD96JYAi" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "6kYbPDsYLQUwptV7ZvQKG3gjNreEEgaWh2CM4DQPYTpq" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "LIQ_USDC", - "address": "AXSeEafwPUGSamiZWH8m2PJtvpDVtrofxvycNwxiysdh", - "nonce": 254, - "authority": "6Y5TnCwgifc8Z7QYo672nT9uNd2hcivVR1NT6oDkJx6P", - "poolTokenMint": "3PD9SZFwXKkXr4akLf4ofo37ZUMycwML89R2P3qxcbZG", - "poolTokenDecimals": 6, - "feeAccount": "FSVPcprrTkQLRtDACFEpa2rhEVx4kBvjPuQaxj572SaC", - "tokenIds": [ - "4wjPQJ6PrkC4dHhYghwJzGBVP78DkBzA2U3kHoFNBuhj", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "4wjPQJ6PrkC4dHhYghwJzGBVP78DkBzA2U3kHoFNBuhj": { - "tag": "LIQ", - "name": "LIQ Protocol", - "mint": "4wjPQJ6PrkC4dHhYghwJzGBVP78DkBzA2U3kHoFNBuhj", - "scale": 6, - "addr": "CVspL8Tj5YdqntXJegNeDXHiBn3648QDNB7gex6D9MgY" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "8YzLsZ1FtsruswkBogEaXwmRTf5PMuyVcfSZXRAdi8qA" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "SNY_USDC", - "address": "BDn3Fj9UXVi2mRVMR2jzpCrAZZphnwfkvFhs192yhCTu", - "nonce": 255, - "authority": "FvjsfbbzZAcrVdfrGtZUjGWAjWHXrfMG8Bjwc17vVSK3", - "poolTokenMint": "AZpo4BJHHRetF96v6SGinFZBMXM4yWMo4RA8C4PriDLk", - "poolTokenDecimals": 6, - "feeAccount": "DiULDJAYXdbtX8CfFsU2jCgHvQWT7u3gwRwpvQxfEMvr", - "tokenIds": [ - "4dmKkXNHdgYsXqBHCuMikNQWwVomZURhYvkkX5c4pQ7y", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "4dmKkXNHdgYsXqBHCuMikNQWwVomZURhYvkkX5c4pQ7y": { - "tag": "SNY", - "name": "SNY", - "mint": "4dmKkXNHdgYsXqBHCuMikNQWwVomZURhYvkkX5c4pQ7y", - "scale": 6, - "addr": "14RHMRzwx9Y4Z41qpr9sTwJZ58wXqV1R9WTkUA7ybmKG" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "Dw9D9T4bBC3oGdMqxE1xWfPSCJ27SYwWD8rFfUxU99QG" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "mSOL_USDC", - "address": "Hme4Jnqhdz2jAPUMnS7jGE5zv6Y1ynqrUEhmUAWkXmzn", - "nonce": 255, - "authority": "9Z7E42k46kxnBjAh8YGXDw3rRGwwxQUBYM7Ccrmwg6ZP", - "poolTokenMint": "8PSfyiTVwPb6Rr2iZ8F3kNpbg65BCfJM9v8LfB916r44", - "poolTokenDecimals": 6, - "feeAccount": "3W3Skj2vQsNEMhGRQprFXQy3Q8ZbM6ojdgiDCokVPWno", - "tokenIds": [ - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So": { - "tag": "mSOL", - "name": "Marinade.finance", - "mint": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "scale": 9, - "addr": "GBa7G5f1FqAXEgByuHXsqsEdpyMjRgT9SNxZwmmnEJAY" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "7hFgNawzzmpDM8TTVCKm8jykBrym8C3TQdb8TDAfAVkD" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "SLRS_USDC", - "address": "87Xz6RK1uzP5NEhSjMewZtDAZyg4V1tYAa1KHnvge17b", - "nonce": 254, - "authority": "5D9v9y6Kbswe6k1wnVceuqRXHMsRQJ8xzx8hadSH6EAM", - "poolTokenMint": "AtB4nUmdyQfuWWJ9xAHw9xyVnJFfSjSuVWkiYan8y86w", - "poolTokenDecimals": 6, - "feeAccount": "CLxeBxNq42AtmD43F5BTqCHTnkVHX8sP9cVPdtRkTL7D", - "tokenIds": [ - "SLRSSpSLUTP7okbCUBYStWCo1vUgyt775faPqz8HUMr", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "SLRSSpSLUTP7okbCUBYStWCo1vUgyt775faPqz8HUMr": { - "tag": "SLRS", - "name": "Solrise Finance", - "mint": "SLRSSpSLUTP7okbCUBYStWCo1vUgyt775faPqz8HUMr", - "scale": 6, - "addr": "CM7oGYHy1oxzHoum8Cxv4pwnndm6Jbs3NkBZkc6v9S9d" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "3QqPbMcUMZu3Rz762g7JgvpUxhRHPtE9HFk2MSDRmPqa" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "PORT_USDC", - "address": "4if9Gy7dvjU7XwunKxdnCcPsaT3yAHPXdz2XS1eo19LG", - "nonce": 254, - "authority": "BshtCZRCHj2RZYC7u5sW3ioRJo9ZiYA4T5p8muFwrKnb", - "poolTokenMint": "F8gPSpwVHj8FdAJAYULDuZBxFEJut87hUbARYYx3471w", - "poolTokenDecimals": 6, - "feeAccount": "5JZXUbCfaSo3y9PYq47Hj5Yc6hVFa4j7MkDzBJfMSRSN", - "tokenIds": [ - "PoRTjZMPXb9T7dyU7tpLEZRQj7e6ssfAE62j2oQuc6y", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "PoRTjZMPXb9T7dyU7tpLEZRQj7e6ssfAE62j2oQuc6y": { - "tag": "PORT", - "name": "Port Finance", - "mint": "PoRTjZMPXb9T7dyU7tpLEZRQj7e6ssfAE62j2oQuc6y", - "scale": 6, - "addr": "2wuSqR5z2Guft2yt57Hx7K6i1AYNoUi8fjxHUeAgaKXo" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "AvP1Db3SyUxLGMSc4nSXjJkjm1kAjiLjog7cup19eWa3" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "SBR_USDC", - "address": "HiYggjP2fN53Jw46e5UuskqNP3HH98jceRxEgVoeRwNw", - "nonce": 255, - "authority": "ATkEV1nEkdp7zgaGpzFCsJ5WAyejcJbxqzGhQpfcDW4S", - "poolTokenMint": "CS7fA5n4c2D82dUoHrYzS3gAqgqaoVSfgsr18kitp2xo", - "poolTokenDecimals": 6, - "feeAccount": "7S3KKuvcHfcKWBGLDwmoTgtB97JE8LHruP8jbmQkGfH", - "tokenIds": [ - "Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1": { - "tag": "SBR", - "name": "Saber", - "mint": "Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1", - "scale": 6, - "addr": "DrJTQqNZqNCf2HDLpYg9zRCMRwnhZEVQuGjeaWtX6CA7" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "DEVLUv1uiUSukQoBdy9fDQyehi4N2Boojy8J2LQ8bK2E" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "scnSOL_USDC", - "address": "6Gh36sNXrGWYiWr999d9iZtqgnipJbWuBohyHBN1cJpS", - "nonce": 255, - "authority": "GXWEpRURaQZ9E62Q23EreTUfBy4hfemXgWFUWcg7YFgv", - "poolTokenMint": "Dkr8B675PGnNwEr9vTKXznjjHke5454EQdz3iaSbparB", - "poolTokenDecimals": 6, - "feeAccount": "HsC1Jo38jK3EpoNAkxfoUJhQVPa28anewZpLfeouUNk7", - "tokenIds": [ - "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm": { - "tag": "scnSOL", - "name": "Socean Staked Sol", - "mint": "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "scale": 9, - "addr": "7xs9QsrxQDVoWQ8LQ8VsVjfPKBrPGjvg8ZhaLnU1i2VR" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "FZFJK64Fk1t619zmVPqCx8Uy29zJ3WuvjWitCQuxXRo3" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "SOCN_USDC", - "address": "6Gh36sNXrGWYiWr999d9iZtqgnipJbWuBohyHBN1cJpS", - "nonce": 255, - "authority": "GXWEpRURaQZ9E62Q23EreTUfBy4hfemXgWFUWcg7YFgv", - "poolTokenMint": "Dkr8B675PGnNwEr9vTKXznjjHke5454EQdz3iaSbparB", - "poolTokenDecimals": 6, - "feeAccount": "HsC1Jo38jK3EpoNAkxfoUJhQVPa28anewZpLfeouUNk7", - "tokenIds": [ - "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm": { - "tag": "scnSOL", - "name": "Socean Staked Sol", - "mint": "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "scale": 9, - "addr": "7xs9QsrxQDVoWQ8LQ8VsVjfPKBrPGjvg8ZhaLnU1i2VR" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "FZFJK64Fk1t619zmVPqCx8Uy29zJ3WuvjWitCQuxXRo3" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "pSOL_USDC", - "address": "GW1Xt9HHtvcnky8X7aBA3BoTgiirJKP5XwC5REFcZSsc", - "nonce": 254, - "authority": "GXueH9K1MzRncoTYbpLiXXC3WrKkmHUFxV5JEu8oADbw", - "poolTokenMint": "C2YzN6MymD5HM2kPaH7bzcbqciyjfmpqyVaR3KA5V6z1", - "poolTokenDecimals": 6, - "feeAccount": "BhHd49JYH3Hk6TV5kCjmUgf7fQSQKDjaWTokMmBhTx9o", - "tokenIds": [ - "9EaLkQrbjmbbuZG9Wdpo8qfNUEjHATJFSycEmw6f1rGX", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "9EaLkQrbjmbbuZG9Wdpo8qfNUEjHATJFSycEmw6f1rGX": { - "tag": "pSOL", - "name": "pSOL", - "mint": "9EaLkQrbjmbbuZG9Wdpo8qfNUEjHATJFSycEmw6f1rGX", - "scale": 9, - "addr": "F7XioZaGe99nosYJQCahx25TKgdUGufYf6sudm1JSgu" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "BT14DfFyNS7qcBGc8TY4HAzDev4vvqsoFBJgjtQpdM2Z" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "mSOL_SOL", - "address": "9EQMEzJdE2LDAY1hw1RytpufdwAXzatYfQ3M2UuT9b88", - "nonce": 250, - "authority": "6cwehd4xhKkJ2s7iGh4CaDb7KhMgqczSBnyNJieUYbHn", - "poolTokenMint": "29cdoMgu6MS2VXpcMo1sqRdWEzdUR9tjvoh8fcK8Z87R", - "poolTokenDecimals": 6, - "feeAccount": "6j2tt2UVYMQwqG3hRtyydW3odzBFwy3pN33tyB3xCKQ6", - "tokenIds": [ - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So": { - "tag": "mSOL", - "name": "Marinade.finance", - "mint": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "scale": 9, - "addr": "6xmki5RtGNHrfhTiHFfp9k3RQ9t8qgL1cYP2YCG2h179" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "Ew2coQtVGLeca31vqB2ssHntjzZgUy1ad9VuuAX8yw7p" - } - }, - "curveType": 2, - "amp": 100, - "feeStructure": { - "traderFee": { - "numerator": "06", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "01", - "denominator": "2710" - } - } - }, - { - "name": "ORCA_PAI", - "address": "7LfLiCnoLPefaCVuh6z92TK2tPZUa9bPjW7gHT4jqrec", - "nonce": 254, - "authority": "AwUWHxHyQHomqCGJJvagiSDhb2xMqJUiE25qDytdMw49", - "poolTokenMint": "C7TH2jEJJaxVwwuvkbcDGfHUiZvEkkeYjyAcdTMi5ujb", - "poolTokenDecimals": 6, - "feeAccount": "DrC2aGWrUmsnK6yAphSXEs8GW5nKUCkityaG8Bikn5Ne", - "tokenIds": [ - "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS" - ], - "tokens": { - "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE": { - "tag": "ORCA", - "name": "Orca", - "mint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "scale": 6, - "addr": "HSUFpGyNXEogXQLgEMQ7aMTxE4HZneRaBovbi9btXepM" - }, - "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS": { - "tag": "PAI", - "name": "Parrot Stable", - "mint": "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS", - "scale": 6, - "addr": "4c9rkBiqAY6fXpVvCbDwpDD44AGQ3MXSaCLcpmLUFtrX" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "ORCA_mSOL", - "address": "49tTgthTYLMPEqozZNyEQifqkGYxHqqDie9YxVczS3iB", - "nonce": 255, - "authority": "9FQ9gDtS6uNr5SMPafuzkDit2rMftHfQuz5mg2X3TqHT", - "poolTokenMint": "CVapmQn7HaU1yMDW3q6oUV4hx6XoYv54T4zfGXkuJqkA", - "poolTokenDecimals": 6, - "feeAccount": "Hq9xxKdMavJd4teMZusF4PiGNGV3hxdcMZwAdngkHCg7", - "tokenIds": [ - "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So" - ], - "tokens": { - "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE": { - "tag": "ORCA", - "name": "Orca", - "mint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "scale": 6, - "addr": "7hoYJc4aqttctANrNe75gscdmQD9HcXZED6AjdDdZMQ9" - }, - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So": { - "tag": "mSOL", - "name": "Marinade.finance", - "mint": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "scale": 9, - "addr": "7MuvRUFT1wWiL7uJKdZqNwk9Fmz2HJ36bEArhDTnyFij" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "scnSOL_SOL", - "address": "2q6UMko5kTnv866W9MTeAFau94pLpsdeNjDdSYSgZUXr", - "nonce": 255, - "authority": "Gyd77CwV23qq937x9UDa4TDkxEeQF9tp8ifotYxqW3Kd", - "poolTokenMint": "APNpzQvR91v1THbsAyG3HHrUEwvexWYeNCFLQuVnxgMc", - "poolTokenDecimals": 6, - "feeAccount": "42Xzazs9EvjtidvEDrj3JXbDtf6fpTq5XHh96mPctvBV", - "tokenIds": [ - "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm": { - "tag": "scnSOL", - "name": "Socean Staked Sol", - "mint": "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "scale": 9, - "addr": "C8DRXUqxXtUgvgBR7BPAmy6tnRJYgVjG27VU44wWDMNV" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "DzdxH5qJ68PiM1p5o6PbPLPpDj8m1ZshcaMFATcxDZix" - } - }, - "curveType": 2, - "amp": 100, - "feeStructure": { - "traderFee": { - "numerator": "06", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "01", - "denominator": "2710" - } - } - }, - { - "name": "SOCN_SOL", - "address": "2q6UMko5kTnv866W9MTeAFau94pLpsdeNjDdSYSgZUXr", - "nonce": 255, - "authority": "Gyd77CwV23qq937x9UDa4TDkxEeQF9tp8ifotYxqW3Kd", - "poolTokenMint": "APNpzQvR91v1THbsAyG3HHrUEwvexWYeNCFLQuVnxgMc", - "poolTokenDecimals": 6, - "feeAccount": "42Xzazs9EvjtidvEDrj3JXbDtf6fpTq5XHh96mPctvBV", - "tokenIds": [ - "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm": { - "tag": "scnSOL", - "name": "Socean Staked Sol", - "mint": "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "scale": 9, - "addr": "C8DRXUqxXtUgvgBR7BPAmy6tnRJYgVjG27VU44wWDMNV" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "DzdxH5qJ68PiM1p5o6PbPLPpDj8m1ZshcaMFATcxDZix" - } - }, - "curveType": 2, - "amp": 100, - "feeStructure": { - "traderFee": { - "numerator": "06", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "01", - "denominator": "2710" - } - } - }, - { - "name": "ATLAS_USDC", - "address": "3V5sjXj1mrWjjB1Xt6Xwp554QwHE5fppGSxbk4GzAtEW", - "nonce": 254, - "authority": "8UYN675AJn5htWydDs724xqintBZ4XzsCWqMozUSDU8m", - "poolTokenMint": "FZ8x1LCRSPDeHBDoAc3Gc6Y7ETCynuHEr5q5YWV7uRCJ", - "poolTokenDecimals": 6, - "feeAccount": "CFN4DQ2p3qroX92pPNy3mov3Dw1aCNGLrU5AXHpHxbko", - "tokenIds": [ - "ATLASXmbPQxBUYbxPsV97usA3fPQYEqzQBUHgiFCUsXx", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "ATLASXmbPQxBUYbxPsV97usA3fPQYEqzQBUHgiFCUsXx": { - "tag": "ATLAS", - "name": "Star Atlas", - "mint": "ATLASXmbPQxBUYbxPsV97usA3fPQYEqzQBUHgiFCUsXx", - "scale": 8, - "addr": "xotXsNCx4tBhnwhrajGTaVgKq1sfuMkeYHc77ZegCqE" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "8YswVYsTi66umBF2Bnkh4LB2VWMKPssDpe54VAgiuJZQ" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "POLIS_USDC", - "address": "CdKPtCb5fBRaGFS4bJgytfReeHuFyhpe9YUyWHPnEWZG", - "nonce": 251, - "authority": "8XB9V3VuHtPBzHqvxzcmpkpaoXNXjZMD8VBHC79SxcEL", - "poolTokenMint": "GteBdo9sqE7T41G8AJsaG9WHW48uXBwsLLznmu2TBdgy", - "poolTokenDecimals": 6, - "feeAccount": "3gZQ2YnrXbnRwJj5poffLirF7CwacatvtfGCNRFrbJdr", - "tokenIds": [ - "poLisWXnNRwC6oBu1vHiuKQzFjGL4XDSu4g9qjz9qVk", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "poLisWXnNRwC6oBu1vHiuKQzFjGL4XDSu4g9qjz9qVk": { - "tag": "POLIS", - "name": "Star Atlas DAO", - "mint": "poLisWXnNRwC6oBu1vHiuKQzFjGL4XDSu4g9qjz9qVk", - "scale": 8, - "addr": "EbXNEUiKxSU1vwwhrbVNVk3qX4o1yU3p75SQUUMfc1zH" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "CLCj9b1vdPutrkvZS8ACTM5q42SXB2Q7khnMLVxDMGEK" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "BOP_USDC", - "address": "9pheQ8EX2wDKHZYm75G9haEbTyAcg8F2gFWybw2w6Vyc", - "nonce": 253, - "authority": "3rxJPYuiRijipJbciewUDacab2Wo3yAe1yWBGzmqn5f1", - "poolTokenMint": "2gXDJZ7XAtQEtf4PRSQZKoq1WMuu1H44tQanbMA3YVpu", - "poolTokenDecimals": 6, - "feeAccount": "2bei4349W8FUcu5gvP5Zt8yhkpwqcCngZxUkb3xRMJZJ", - "tokenIds": [ - "BLwTnYKqf7u4qjgZrrsKeNs2EzWkMLqVCu6j8iHyrNA3", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "BLwTnYKqf7u4qjgZrrsKeNs2EzWkMLqVCu6j8iHyrNA3": { - "tag": "BOP", - "name": "Boring Protocol", - "mint": "BLwTnYKqf7u4qjgZrrsKeNs2EzWkMLqVCu6j8iHyrNA3", - "scale": 8, - "addr": "HkHjLSaP9yyWTzMGD1DKyoc1Dfvhvw4vakRhyjcVUCKs" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "CqRoKMF4kh2o568nFdDNHs7cszBjrkQME4RtCuTqcjCe" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "SAMO_USDC", - "address": "Epvp7qMYAF21VVjacdB3VfKn6nnXQSF4rGYu8sD6Bkow", - "nonce": 252, - "authority": "AB4rTE2JiKFhnfynUQCovbW75CUxT9LxcJX2SDTbY9gy", - "poolTokenMint": "6VK1ksrmYGMBWUUZfygGF8tHRGpNxQEWv8pfvzQHdyyc", - "poolTokenDecimals": 6, - "feeAccount": "9U8UF7d8kBvsS25XoZnjmVQ9vGkP4BUnHJgfc615BvG1", - "tokenIds": [ - "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU": { - "tag": "SAMO", - "name": "Samoyedcoin", - "mint": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU", - "scale": 9, - "addr": "7jwHW4Lw3nVaSJXskN5pUoKU6YB9RBVfZtGBp3VbR43U" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "G7Gqjxk9EaJMeFfoFTSy9WfH8uurgQkbNQCREWAc56DZ" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "NINJA_SOL", - "address": "3ECUtPokme1nimJfuAkMtcm7QYjDEfXRQzmGC16LuYnz", - "nonce": 255, - "authority": "H8f9n2PfehUc73gRWSRTPXvqUhUHVywdAxcfEtYmmyAo", - "poolTokenMint": "4X1oYoFWYtLebk51zuh889r1WFLe8Z9qWApj87hQMfML", - "poolTokenDecimals": 6, - "feeAccount": "43ViAbUVujnYtJyzGP4AhabMYCbLsExenT3WKsZjqJ7N", - "tokenIds": [ - "FgX1WD9WzMU3yLwXaFSarPfkgzjLb2DZCqmkx9ExpuvJ", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "FgX1WD9WzMU3yLwXaFSarPfkgzjLb2DZCqmkx9ExpuvJ": { - "tag": "NINJA", - "name": "NINJA", - "mint": "FgX1WD9WzMU3yLwXaFSarPfkgzjLb2DZCqmkx9ExpuvJ", - "scale": 6, - "addr": "6Y9VyEYHgxVahiixzphNh4HAywpab9zVoD4S8q1sfuL8" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "9SxzphwrrDVDkwkyvmtag9NLgpjSkTw35cRwg9rLMYWk" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "SLIM_USDC", - "address": "8JPid6GtND2tU3A7x7GDfPPEWwS36rMtzF7YoHU44UoA", - "nonce": 255, - "authority": "749y4fXb9SzqmrLEetQdui5iDucnNiMgCJ2uzc3y7cou", - "poolTokenMint": "BVWwyiHVHZQMPHsiW7dZH7bnBVKmbxdeEjWqVRciHCyo", - "poolTokenDecimals": 6, - "feeAccount": "E6aTzkZKdCECgpDtBZtVpqiGjxRDSAFh1SC9CdSoVK7a", - "tokenIds": [ - "xxxxa1sKNGwFtw2kFn8XauW9xq8hBZ5kVtcSesTT9fW", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "xxxxa1sKNGwFtw2kFn8XauW9xq8hBZ5kVtcSesTT9fW": { - "tag": "SLIM", - "name": "Solanium", - "mint": "xxxxa1sKNGwFtw2kFn8XauW9xq8hBZ5kVtcSesTT9fW", - "scale": 6, - "addr": "ErcxwkPgLdyoVL6j2SsekZ5iysPZEDRGfAggh282kQb8" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "EFYW6YEiCGpavuMPS1zoXhgfNkPisWkQ3bQz1b4UfKek" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "wHAPI_USDC", - "address": "2Y1Jmpkf5wt1X5zcFHNBDoHxqjTXbMJfj1UFtrYQwUbG", - "nonce": 254, - "authority": "8K4eRHeyPhBGB9zCjKtyBHoPPZ75zLN64oxBF6GyF4Qg", - "poolTokenMint": "ELfBngAgvLEHVBuJQhhE7AW6eqLX7id2sfrBngVNVAUW", - "poolTokenDecimals": 6, - "feeAccount": "Bx3ZhEBFedDqCBzuzKVS4eMKTtW1MmHkcMGU45FcyxRT", - "tokenIds": [ - "6VNKqgz9hk7zRShTFdg5AnkfKwZUcojzwAkzxSH3bnUm", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "6VNKqgz9hk7zRShTFdg5AnkfKwZUcojzwAkzxSH3bnUm": { - "tag": "wHAPI", - "name": "HAPI", - "mint": "6VNKqgz9hk7zRShTFdg5AnkfKwZUcojzwAkzxSH3bnUm", - "scale": 9, - "addr": "DRYADMQevoJHDFCYbDQeS4p551MpsDN2d7CJU3LxfNHa" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "HzsECCX6RZ2ccbR3FarRSEfc5rkuETfywXJnRZut5JzU" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "COPE_USDC", - "address": "DhGTKyT6RVkpvPxXAJodi4Z41RSvQZxV1f5eRvJ5bE4r", - "nonce": 254, - "authority": "Hu8AWoRBa7ZaYQFdHQyRHeEZGB16Me86fA5vAZzjVUmv", - "poolTokenMint": "HsauTv9s52Zv12eaDuSp6y7BEm4e4BHEyAsbdjyyWzPK", - "poolTokenDecimals": 6, - "feeAccount": "JEGcxfGxWJpRkGtvA6J6kEgTBebDz6kxURoeB3SX8vaW", - "tokenIds": [ - "8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh": { - "tag": "COPE", - "name": "Cope", - "mint": "8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh", - "scale": 6, - "addr": "6N3P3etaUYGeBs2C67ZQTDRqHsExNsfj85dDWPwHtQBS" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "36VVz3eY8YmWBGskQVjvGGBfyUKHHCEDBgkFtzMpFqeU" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "SUNNY_USDC", - "address": "3Ukqqshh3kZ8UPbcYYFSRaeJcsgttcmShtNNn12F1rj2", - "nonce": 255, - "authority": "7NP8DTzPdpbQofhNyhLW3j2khutmfy1kuFp2AjaD8rrp", - "poolTokenMint": "GHuoeq9UnFBsBhMwH43eL3RWX5XVXbSRYJymmyMYpT7n", - "poolTokenDecimals": 6, - "feeAccount": "CCuSVbnnq8SUj7cpPe7BbHLuKanyxfvfrwypzCBnaDdf", - "tokenIds": [ - "SUNNYWgPQmFxe9wTZzNK7iPnJ3vYDrkgnxJRJm1s3ag", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "SUNNYWgPQmFxe9wTZzNK7iPnJ3vYDrkgnxJRJm1s3ag": { - "tag": "SUNNY", - "name": "Sunny Aggregator", - "mint": "SUNNYWgPQmFxe9wTZzNK7iPnJ3vYDrkgnxJRJm1s3ag", - "scale": 6, - "addr": "F6nCAMYEFxsyRDVonQXLNufXgAHsgAa1Br8DhBoX3KAV" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "HWCTHmQppFSsKQEk1bHUqPC2WLaidgnfTG9MQGD4XKEt" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "GRAPE_USDC", - "address": "6MxUhBLXHCqpdYaFPTmw1D9fQ7zYnm9grZyJvpGiqr15", - "nonce": 255, - "authority": "SvWmpVVUkv8cwoRnBQ5Gqt2FFYjdpWLS665gE2ZLNQp", - "poolTokenMint": "EorFh8siFyLF1QTZ7cCXQaPGqyo7eb4SAgKtRH8Jcxjd", - "poolTokenDecimals": 6, - "feeAccount": "6vWYnRDEHu7kRLbA2dnBgEfbdba72iDMDD9k3munyPaP", - "tokenIds": [ - "8upjSpvjcdpuzhfR1zriwg5NXkwDruejqNE9WNbPRtyA", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "8upjSpvjcdpuzhfR1zriwg5NXkwDruejqNE9WNbPRtyA": { - "tag": "GRAPE", - "name": "Grape", - "mint": "8upjSpvjcdpuzhfR1zriwg5NXkwDruejqNE9WNbPRtyA", - "scale": 6, - "addr": "686KiYDMMkbredNoWx8yqvAdKSiHuWSG3dnbL6yWYmZp" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "9i14ZKzaDmzKCAQb8hCv4h5GCo2Xiq83JcL7bofk4Ddj" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "ABR_USDC", - "address": "rxwsjytcEBvXpXrXBL1rpsjhoh78imBn8WbxjKmLRge", - "nonce": 252, - "authority": "AcaxutE6Rh9vRxipTLdqinEdRK6R4ayUAAv2bZPh6UU9", - "poolTokenMint": "GMzPbaCuQmeMUm1opH3oSCgKUjVgJUW14myq99RVPGX5", - "poolTokenDecimals": 6, - "feeAccount": "7pPJGwd8Vq7aYmHaocQpQSfTn3UWYGKUgFkFhpMmRdDF", - "tokenIds": [ - "a11bdAAuV8iB2fu7X6AxAvDTo1QZ8FXB3kk5eecdasp", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "a11bdAAuV8iB2fu7X6AxAvDTo1QZ8FXB3kk5eecdasp": { - "tag": "ABR", - "name": "Allbridge", - "mint": "a11bdAAuV8iB2fu7X6AxAvDTo1QZ8FXB3kk5eecdasp", - "scale": 9, - "addr": "6FRxhbY7bvSiDojPiqoidjTyDjxaUyCoPQk3ifEdfFbm" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "8aTapFecZRZmC2bTeKr2voHFW2twNvbrh8nWYdXYQWkZ" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "KURO_USDC", - "address": "HdeYs4bpJKN2oTb7PHxbqq4kzKiLr772A5N2gWjY57ZT", - "nonce": 250, - "authority": "2KRcBDQJWEPygxcMMFMvR6dMTVtMkJV6kbxr5e9Kdj5Q", - "poolTokenMint": "DRknxb4ZFxXUTG6UJ5HupNHG1SmvBSCPzsZ1o9gAhyBi", - "poolTokenDecimals": 6, - "feeAccount": "5XuLrZqpX9gW3pJw7274EYwAft1ciTXndU4on96ERi9J", - "tokenIds": [ - "2Kc38rfQ49DFaKHQaWbijkE7fcymUMLY5guUiUsDmFfn", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "2Kc38rfQ49DFaKHQaWbijkE7fcymUMLY5guUiUsDmFfn": { - "tag": "KURO", - "name": "Kurobi", - "mint": "2Kc38rfQ49DFaKHQaWbijkE7fcymUMLY5guUiUsDmFfn", - "scale": 6, - "addr": "DBckbD9CoRBFE8WdbbnFLDz6WdDDSZ7ReEeqdjL62fpG" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "B252w7ZkUX4WyLUJKLEymEpRkYMqJhgv2PSj2Z2LWH34" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "MEDIA_USDC", - "address": "5L2aVMnNsmrnkxU4B25ajb2pR5AJWBRfUa73wjasjyaB", - "nonce": 255, - "authority": "HX3JKg5HtboRw9nQRWm47rSJkBHczdcXwBgWASyHi3Wk", - "poolTokenMint": "2toFgkQDoPrTJYGDEVoCasPXuL9uQnjvXJaDwa9LHyTx", - "poolTokenDecimals": 6, - "feeAccount": "5BkyYnBWnzBWQKnU9AcUaDrmyhjLpAcFxCvVTTnRGyYk", - "tokenIds": [ - "ETAtLmCmsoiEEKfNrHKJ2kYy3MoABhU6NQvpSfij5tDs", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "ETAtLmCmsoiEEKfNrHKJ2kYy3MoABhU6NQvpSfij5tDs": { - "tag": "MEDIA", - "name": "Media Network", - "mint": "ETAtLmCmsoiEEKfNrHKJ2kYy3MoABhU6NQvpSfij5tDs", - "scale": 6, - "addr": "BFAyLvCbMhgF7CQ9fsWWK46jD9mPXfBMDWvXgk5LTgsT" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "7CvBsWsfEif4sAo9dnsf1JKVAfBGcZUVTktqtxBSkgwB" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "TULIP_USDC", - "address": "BNwrRN23RCoq5MAneJ6Cot7iN2FLtyt9rtcjaVfAXTLt", - "nonce": 253, - "authority": "EFZs7veYVdWBHt7RcAPvXQc46gDzccpZTxAcEm6NyXFg", - "poolTokenMint": "4SBx8GXu8HhcVHWydQv1vsDdZs3G93XSL9CtMBny6hS5", - "poolTokenDecimals": 6, - "feeAccount": "8BiqDTCBQ77qjGpED2was7C4iHJrQx9bXhzRt3Wz9xJG", - "tokenIds": [ - "TuLipcqtGVXP9XR62wM8WWCm6a9vhLs7T1uoWBk6FDs", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "TuLipcqtGVXP9XR62wM8WWCm6a9vhLs7T1uoWBk6FDs": { - "tag": "TULIP", - "name": "Tulip Protocol", - "mint": "TuLipcqtGVXP9XR62wM8WWCm6a9vhLs7T1uoWBk6FDs", - "scale": 6, - "addr": "5CKd5M2nXdPM1TMXxqK6Up6GZehKL5uU9Z9Ytm2sFCiz" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "HjMQnuxjVRodoaAg9WcNXb9TAssDaFNpgwcUUKNjWdh5" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "MNGO_USDC", - "address": "Hk9ZCvmqVT1FHNkWJMrtMkkVnH1WqssWPAvmio5Vs3se", - "nonce": 254, - "authority": "5RyiYaHFDVupwnwxzKCRk7JY1CKhsczZXefMs3UUmx4Z", - "poolTokenMint": "H9yC7jDng974WwcU4kTGs7BKf7nBNswpdsP5bzbdXjib", - "poolTokenDecimals": 6, - "feeAccount": "FWKcKaMfaVezLRFr946MdgmpTZHG4A2GgqehAxjTyDAB", - "tokenIds": [ - "MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac": { - "tag": "MNGO", - "name": "Mango Markets", - "mint": "MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac", - "scale": 6, - "addr": "J8bQnhcNyixFGBskQoJ2aSPXPWjvSzaaxF4YPs96XHDJ" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "5yMoAhjfFaCPwEwKM2VeFFh2iBs5mHWLTJ4LuqZifsgN" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "stSOL_wstETH", - "address": "B32UuhPSp6srSBbRTh4qZNjkegsehY9qXTwQgnPWYMZy", - "nonce": 255, - "authority": "EtwQJxu8wih29vMpdTa74K9W9tgtL4LT6hbWBkhHwvU5", - "poolTokenMint": "Eswigpwm3xsipkTqahGi2PEJsJcULQBwZgxhQpr6yBEa", - "poolTokenDecimals": 6, - "feeAccount": "74b9j23njRpt3PYPxoze2XS29ZgGmucziLB7WrsDpBdD", - "tokenIds": [ - "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "ZScHuTtqZukUrtZS43teTKGs2VqkKL8k4QCouR2n6Uo" - ], - "tokens": { - "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj": { - "tag": "stSOL", - "name": "Lido Staked SOL", - "mint": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "scale": 9, - "addr": "CeSEpgqc3zV8xDr7Q6PiwJju6a6e92wpAv7Kg6QyFfQB" - }, - "ZScHuTtqZukUrtZS43teTKGs2VqkKL8k4QCouR2n6Uo": { - "tag": "wstETH", - "name": "Lido Staked Ether", - "mint": "ZScHuTtqZukUrtZS43teTKGs2VqkKL8k4QCouR2n6Uo", - "scale": 8, - "addr": "Fb3XpEJgghTURUGd1wphWr93ruX5egnesfdZtjWCxJFy" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "SYP_USDC", - "address": "5DnwMqYAGEKekYXJdN8Bue6vN1p5zrEnBpmd53jEK61S", - "nonce": 255, - "authority": "4NfadURWeSDPJBGcKQRt39mPhbG9M7EJx6FZDwwcFB9f", - "poolTokenMint": "qJxKN9BhxbYvRNbjfK2uAVWboto6sonj8XC1ZEW5XTB", - "poolTokenDecimals": 6, - "feeAccount": "57L2bEFecsAv4jnaM2PBaeAVyPZEYtTmXBi7eaG2xWXw", - "tokenIds": [ - "FnKE9n6aGjQoNWRBZXy4RW6LZVao7qwBonUbiD7edUmZ", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "FnKE9n6aGjQoNWRBZXy4RW6LZVao7qwBonUbiD7edUmZ": { - "tag": "SYP", - "name": "Sypool", - "mint": "FnKE9n6aGjQoNWRBZXy4RW6LZVao7qwBonUbiD7edUmZ", - "scale": 9, - "addr": "6d19CQA1FP2MLLAzA7XoZEc9Agc32FaKUS175UVWLGtv" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "HpPnUHyo19VjmXbP6FbbKXu7WQCUEn6h7be76fZdHVmf" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "stSOL_wLDO", - "address": "CqwyVxWeaiikQ3VhvEZSEmupmG1Wmc2FeaUjsCV492Sx", - "nonce": 255, - "authority": "213QoNt5dR56Ye2sx9cwPwpR3NpJUEStQXn8EbbWKkfJ", - "poolTokenMint": "74B9aMS7SA832xKngt5VLKmWAP3pa3qkUzWncTmQSsGF", - "poolTokenDecimals": 6, - "feeAccount": "D4kH4fcwwDtGMj4LpcynB977YVnmvDUcuDQoo5sqAgRz", - "tokenIds": [ - "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p" - ], - "tokens": { - "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj": { - "tag": "stSOL", - "name": "Lido Staked SOL", - "mint": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "scale": 9, - "addr": "GDprNAcXeR5GVGnCtkS5UqyPGMm2Sy5Lk15qqN36faMT" - }, - "HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p": { - "tag": "wLDO", - "name": "Lido DAO", - "mint": "HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p", - "scale": 8, - "addr": "VCgdcsExfmxUDQwusLP2xqZ3ap7VuYyQMMHDPSva2hx" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "whETH_SOL", - "address": "FcEro2uFpHcb7Z785CBs6q12KMJqUJKa8VTXPi4TTBMf", - "nonce": 252, - "authority": "HMxZz8fv2uR9suzAPRbJGNB3wZL1eT3eKL3cpYWUbM8K", - "poolTokenMint": "7aYnrdmdCRodDy2Czn6keUquUhjF1jPEmfwZPh488z8U", - "poolTokenDecimals": 6, - "feeAccount": "YCVJDKdHNi1mhJtWz7QGbBRreMmw1soeipz7wZbQKEK", - "tokenIds": [ - "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs": { - "tag": "whETH", - "name": "Ethereum", - "mint": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "scale": 8, - "addr": "3uQytDKNd5H6XK8FhTei4wCUmj2eTbLTbiLAtWk2SmbA" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "GR3g8Wej3jmv92hYM1t22kaXog2xjkGjQ7V1XzLd1efT" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "whETH_USDC", - "address": "4reGGLbesqpAeAZdAJv9hhgA2tgj45oGcyRuEvhATdMm", - "nonce": 252, - "authority": "8uLtzZ1iTLTCPsm3b4QttRmDXcFjhVHRuMS9VTVEwo7E", - "poolTokenMint": "7NPtjjAP7vhp4t5NCLyY4DY5rurvyc8cgZ2a2rYabRia", - "poolTokenDecimals": 6, - "feeAccount": "AVw52spXtzFh4bb5ghhpJaDbLx3XWuY85eQNDEo3X1yN", - "tokenIds": [ - "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs": { - "tag": "whETH", - "name": "Ethereum", - "mint": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "scale": 8, - "addr": "9KpjcpKwhoFPbixvKDfcAhBQcVXk1CSBTGsJdzojDPRv" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "5HaG31FQS4McBVcHxVfwaKaWXE3VCGqvJ1ZDkTxs94cQ" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "MNDE_mSOL", - "address": "vjHagYsgZwG9icyFLHu2xWHWdtiS5gfeNzRhDcPt5xq", - "nonce": 255, - "authority": "3HWcojnC1ruEMmsE92Ez1BoebdDXzYQa4USaeWX7eTuM", - "poolTokenMint": "5PHS5w6hQwFNnLz1jJFe7TVTxSQ98cDYC3akmiAoFMXs", - "poolTokenDecimals": 6, - "feeAccount": "46mdANZ2DCA2sTFchvD7WwbffbLQa4jCFkkRL23WuYG8", - "tokenIds": [ - "MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey", - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So" - ], - "tokens": { - "MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey": { - "tag": "MNDE", - "name": "Marinade Governance", - "mint": "MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey", - "scale": 9, - "addr": "2LferrWvYWtHFfdkmixzt9g3aKa3yBNfgbRrP1CcWMMp" - }, - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So": { - "tag": "mSOL", - "name": "Marinade.finance", - "mint": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "scale": 9, - "addr": "GimsuZjYqMXM6xK6S3e9JpGvX6jaMPuNeR6s2piDESmy" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "WAG_USDC", - "address": "B76e3wtCDTKBgKQjvx87EBkDLPGcCY9w1SGiwjD5kaK7", - "nonce": 254, - "authority": "FRUmMZDiZrDrwioiUYi3tdqF7SEBeT219bBu54PGxoCo", - "poolTokenMint": "Df6XNHMF3uRVZnz7LCEGiZVax6rXgz76owtVkBHEjSb6", - "poolTokenDecimals": 6, - "feeAccount": "BCuRKfsM99LJFCchKUBLBZ26UuziDewJDRkkKMwx2qnd", - "tokenIds": [ - "5tN42n9vMi6ubp67Uy4NnmM5DMZYN8aS8GeB3bEDHr6E", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "5tN42n9vMi6ubp67Uy4NnmM5DMZYN8aS8GeB3bEDHr6E": { - "tag": "WAG", - "name": "Waggle", - "mint": "5tN42n9vMi6ubp67Uy4NnmM5DMZYN8aS8GeB3bEDHr6E", - "scale": 9, - "addr": "8voSogytL9jLgE73GS3WuujBinKFRQJjvUFsVGYexWZd" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "HEP7mACuN13cT95eDAYTNjgwriqJnMQVhnyRctqnBRe4" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "mSOL_USDT", - "address": "Afofkb7JTc32rdpqiyc3RDmGF5s9N6W1ujcdYVfGZ5Je", - "nonce": 251, - "authority": "8vrC1FAnW6hQMwJuU5waZdRrBbDJTULqjpdc4GjDtKR6", - "poolTokenMint": "9cMWe4UYRPGAUUsTkjShJWVM7bk8DUBgxtwwH8asFJoV", - "poolTokenDecimals": 6, - "feeAccount": "7GPvi21QbwMyBoXU5Zqf8VhnuEh7VH4A1SRPgHJ36eE7", - "tokenIds": [ - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" - ], - "tokens": { - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So": { - "tag": "mSOL", - "name": "Marinade.finance", - "mint": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "scale": 9, - "addr": "RTXKRxghfWJpE344UG7UhKnCwN2Gyv6KnNSTFDnaASF" - }, - "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB": { - "tag": "USDT", - "name": "Tether USD", - "mint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "scale": 6, - "addr": "J15KntYr6iout4ce2kcD2QEdkVbLN4EHHFLfCtke3f6Y" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "mSOL_whETH", - "address": "A71DQffTzgxBSzXjPL3tmf8XXTNtS5mR2D78Y8rmV2hk", - "nonce": 250, - "authority": "FPWpe7QEQnDMivnHksQW2uvcw9tvX1oxejKBX136WRkr", - "poolTokenMint": "5qoTq3qC4U7vFxo3iCzbXcaD1UEmDeCD63Dsuoct71oV", - "poolTokenDecimals": 6, - "feeAccount": "FSqUYVzF3XZzLcnj132eT6ed3bK95G1yG4MazcHZi99Q", - "tokenIds": [ - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs" - ], - "tokens": { - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So": { - "tag": "mSOL", - "name": "Marinade.finance", - "mint": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "scale": 9, - "addr": "Fcp5u8bL3V24MXjA4noSfMpcEAP2vSj1WTaA1ZNxACZL" - }, - "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs": { - "tag": "whETH", - "name": "Ethereum", - "mint": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "scale": 8, - "addr": "DuBCBX3y2FjDWUn2ncK5EKQh229JiJ7HTCjYJhNC87K8" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "BTC_mSOL", - "address": "8DRw5wQE1pyg6RB1UwypGNFgb2Pzp2hpyDDNwo76Lcc8", - "nonce": 255, - "authority": "3X1aLdyvcQNc8TvBMPiucMsRCnGMBnGsjJHpZEyCf3pn", - "poolTokenMint": "8nKJ4z9FSw6wrVZKASqBiS9DS1CiNsRnqwCCKVQjqdkB", - "poolTokenDecimals": 6, - "feeAccount": "AqiLHbUAy4UWWKGVVgbHsaUVCMg1zemNkgsYBPSirT92", - "tokenIds": [ - "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So" - ], - "tokens": { - "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E": { - "tag": "BTC", - "name": "Bitcoin", - "mint": "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "scale": 6, - "addr": "6D3sxC6yEe84FUnF5Kpbgx6gN57N9poJCKAtrCeCWdJo" - }, - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So": { - "tag": "mSOL", - "name": "Marinade.finance", - "mint": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "scale": 9, - "addr": "EPoVJLhi9QtVPVo8n31M5k5Knvb48j8zbYyRrUbrHwC5" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "IVN_SOL", - "address": "CFCivUWXBuULVNfJezj1fAhX6hdwVFi2BsCtpu6m96bR", - "nonce": 255, - "authority": "JGhNs5r7YNnJokzzXZWE3REKV8x4GiUvn2xSg7XGg59", - "poolTokenMint": "DfgCnzaiTXfPkAH1C1Z441b5MzjjTCEh134ioxqRZxYf", - "poolTokenDecimals": 6, - "feeAccount": "HwwgrSjJGFBtRN8h2daWnVLBciwoo79wNeKi6b5SZmE2", - "tokenIds": [ - "iVNcrNE9BRZBC9Aqf753iZiZfbszeAVUoikgT9yvr2a", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "iVNcrNE9BRZBC9Aqf753iZiZfbszeAVUoikgT9yvr2a": { - "tag": "IVN", - "name": "Investin", - "mint": "iVNcrNE9BRZBC9Aqf753iZiZfbszeAVUoikgT9yvr2a", - "scale": 6, - "addr": "C5yDeB3jBz5yZPa6FgP6b7HNoFxLP63Pyzpaosnkikis" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "CCm846T6xj9VAhSAifuUJAXYCR3kaGp5KqhXFHCaeWUh" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "LARIX_USDC", - "address": "DaNULZAv2VyLk75pW3QD5szVzx5dT6iNvoih94Bttqf5", - "nonce": 255, - "authority": "FUVkG7fM3i8T49qV7WsJd68rBaYKvqTkAQCdftqTWWNj", - "poolTokenMint": "8sfThep3io4gvcGeuoAg1Rs8GDwKJjtcdAFHqQSSNAVE", - "poolTokenDecimals": 6, - "feeAccount": "AVb9Bvu4rjFYNCHygEnAYCjwnkgtC8C6UmJ7at3dsfdz", - "tokenIds": [ - "Lrxqnh6ZHKbGy3dcrCED43nsoLkM1LTzU2jRfWe8qUC", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "Lrxqnh6ZHKbGy3dcrCED43nsoLkM1LTzU2jRfWe8qUC": { - "tag": "LARIX", - "name": "Larix", - "mint": "Lrxqnh6ZHKbGy3dcrCED43nsoLkM1LTzU2jRfWe8qUC", - "scale": 6, - "addr": "AAjjSJsZM3AKK4h9cbGTHkquEZ2fWjgo9A9Pmrj2ynTH" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "82Fs8dSpMxPPfN1ULsXGFREHWz3JizREpTxwz2MaZ1n1" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "PRT_USDC", - "address": "CRm5uRBsVmUVHVqKfCCvCUX1RLUkjfcBWAeMQ5D9VuCM", - "nonce": 255, - "authority": "A9eqdCXYys7jeoroMFEnkGLoYLa2q5gGbg8RSKHkR2ne", - "poolTokenMint": "6jCERp5hKj37PCXP3VTjCDJeoPuSpnMDMz5A6jWQv3yS", - "poolTokenDecimals": 6, - "feeAccount": "FHVidN2ZdGnVaCjYwLjLXrimPbVsaqsUEEiGcVZ6WAPq", - "tokenIds": [ - "PRT88RkA4Kg5z7pKnezeNH4mafTvtQdfFgpQTGRjz44", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "PRT88RkA4Kg5z7pKnezeNH4mafTvtQdfFgpQTGRjz44": { - "tag": "PRT", - "name": "Parrot Protocol", - "mint": "PRT88RkA4Kg5z7pKnezeNH4mafTvtQdfFgpQTGRjz44", - "scale": 6, - "addr": "3oL2GjsUnQLjHw77p78CsRr7t94AVrtsCnW5uf6NYQ3g" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "2EiVwvsH5cvyk4W243zKoywkaEQb9Bwe9WGphRgBSqaP" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "JET_USDC", - "address": "ErWwp9HKjk5ZPLDt8SrHKH5PvSKTwFDdFo5E3zDuE5Be", - "nonce": 253, - "authority": "GYY1t5d4pZnJC4rMXGY9yKMyCzLqxRqbtSguD2KkxghH", - "poolTokenMint": "GBijunwxa4Ni3JmYC6q6zgaVhSUJU6hVX5qTyJDRpNTc", - "poolTokenDecimals": 6, - "feeAccount": "6NhybmW42rdWj5TcobNKQT6JaZispgngcfTDrCsgVq4Q", - "tokenIds": [ - "JET6zMJWkCN9tpRT2v2jfAmm5VnQFDpUBCyaKojmGtz", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "JET6zMJWkCN9tpRT2v2jfAmm5VnQFDpUBCyaKojmGtz": { - "tag": "JET", - "name": "JET", - "mint": "JET6zMJWkCN9tpRT2v2jfAmm5VnQFDpUBCyaKojmGtz", - "scale": 9, - "addr": "GEtZSc8188t2cCAv21UGCyjvxCeyU5Co99GtRtyTkpdh" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "Bi95f8H7o7zHWuYysxDHEubPv4c3NhsHWhaesXJu91NC" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "stSOL_USDC", - "address": "EfK84vYEKT1PoTJr6fBVKFbyA7ZoftfPo2LQPAJG1exL", - "nonce": 252, - "authority": "8PSN1CQxfyZ7T4sM3HM3RAgF2Y6VCf4tKSc8xY73Tnq5", - "poolTokenMint": "GtQ1NT7R5aaTiST7K6ZWdMhwDdFxsSFvVFhBo8vyHGAq", - "poolTokenDecimals": 6, - "feeAccount": "CJhL3UGesECFt6fvLB3csrGMuHf3M3G78pUzTopUiV8T", - "tokenIds": [ - "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj": { - "tag": "stSOL", - "name": "Lido Staked SOL", - "mint": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "scale": 9, - "addr": "9SEBxqhP8sTAzmfiQfCPim1MqQXuDPb6fkGzJF7Z339i" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "G45yhM5mZ5RXZpLxGWLk3PVzdAp33z8aH6F9mLW8fQj3" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "wstETH_USDC", - "address": "v51xWrRwmFVH6EKe8eZTjgK5E4uC2tzY5sVt5cHbrkG", - "nonce": 254, - "authority": "3Kk8rpjxpc9qv2pJPr1CbmyQqrTDPntpryXActLogQeD", - "poolTokenMint": "5a6Y1ephcbKSoyLMQyD1JWbtqawCy8p2FtRL9v3zhaG5", - "poolTokenDecimals": 6, - "feeAccount": "ACKiRmbiMaPEc73pz4dVMuJGPaa74Vx9sfYADjnHuzvo", - "tokenIds": [ - "ZScHuTtqZukUrtZS43teTKGs2VqkKL8k4QCouR2n6Uo", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "ZScHuTtqZukUrtZS43teTKGs2VqkKL8k4QCouR2n6Uo": { - "tag": "wstETH", - "name": "Lido Staked Ether", - "mint": "ZScHuTtqZukUrtZS43teTKGs2VqkKL8k4QCouR2n6Uo", - "scale": 8, - "addr": "5c4tzhRVaCxpmu8o3HrEZ8PWBDKSR6QNkBdQrUo9oe3e" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "AFNaWHH7ZGFjB7y7jmPM7jVs7QBAciffu7Z5tZidRHPR" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "AURY_USDC", - "address": "6HSguUukDH9zqJBm6oAAmFkg1WK9dJ5iLgnppTCM6jHm", - "nonce": 255, - "authority": "9T1koZp2PNJgspcx3G22yLiChBUfYzAjs2dhj2kgw2LZ", - "poolTokenMint": "6mJqqT5TMgveDvxzBt3hrjGkPV5VAj7tacxFCT3GebXh", - "poolTokenDecimals": 6, - "feeAccount": "JCqbv7r3mtYhzruNFjc21X14fndDVBLMiaNQrsHVpWui", - "tokenIds": [ - "AURYydfxJib1ZkTir1Jn1J9ECYUtjb6rKQVmtYaixWPP", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "AURYydfxJib1ZkTir1Jn1J9ECYUtjb6rKQVmtYaixWPP": { - "tag": "AURY", - "name": "Aurory", - "mint": "AURYydfxJib1ZkTir1Jn1J9ECYUtjb6rKQVmtYaixWPP", - "scale": 9, - "addr": "413s6jiRbayD9didA4VnY8kQVgVBgkYNpYB2tyNf8sbh" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "GdPeogNxRWAZtUj7ZHc7fUpBuGHJosdbukiT2krFtXm8" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "AVAX_USDC", - "address": "7c2CLgatf2TU36PgpS65WLmvWk94rmaHVf1Z1peZ7mcA", - "nonce": 251, - "authority": "Mq46N9EknnxHL9fRkJhS4Eg9YXRifHiWzFJTD11ePWC", - "poolTokenMint": "Hmfrtmo93DpSDmVNLQKcBS5D1ia5JatiRSok9ososubz", - "poolTokenDecimals": 6, - "feeAccount": "7JH76Kw4dHyC5szRXkx6MFkJ3BEViodfNy15uFJst1cX", - "tokenIds": [ - "AUrMpCDYYcPuHhyNX8gEEqbmDPFUpBpHrNW3vPeCFn5Z", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "AUrMpCDYYcPuHhyNX8gEEqbmDPFUpBpHrNW3vPeCFn5Z": { - "tag": "AVAX", - "name": "Avalanche", - "mint": "AUrMpCDYYcPuHhyNX8gEEqbmDPFUpBpHrNW3vPeCFn5Z", - "scale": 9, - "addr": "5rU6M2jAXQMSmgrsn14BPoVVhoBdCU6y5cP7XMjN4ZYy" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "D28rzq246bcXBrYiCeALY86y8NwvCUmuJGNggvKsh4WR" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "FTT_USDC", - "address": "8npdwWX2BR39kcFLtTJABbcjNq7NWQvipfqxgsfk9mTX", - "nonce": 255, - "authority": "8zU13KiLb1e87skt4rf8q1LhamEKKecyu6Xxb4Hqnm7e", - "poolTokenMint": "FwCombynV2fTVizxPCNA2oZKoWXLZgdJThjE4Xv9sjxc", - "poolTokenDecimals": 6, - "feeAccount": "C8D52rGuZcsBENhWtR9aqJVRU62cL7jyyEhxesKwc1k8", - "tokenIds": [ - "AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3": { - "tag": "FTT", - "name": "FTX Token", - "mint": "AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3", - "scale": 6, - "addr": "SasuKsATA2ATrMfFfSJr86wAGVgdS69PkQT3jFASBB8" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "3wADiuUqoakdoYYYxKqwoA4VN3uWZy5UwvLePox1mEsK" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "RAY_USDC", - "address": "2R2VhohRc5WoNHtRdwnjovAQaZRAmr1DE3QFW5jfgb6v", - "nonce": 252, - "authority": "9B9ZcYT8jDQ6XLe6gRLDCFv1zz3uHVKdbZT9DFhsYSQW", - "poolTokenMint": "4cXw2MYj94TFBXLL73fEpMCr8DPrW68JvrV8mzWgktbD", - "poolTokenDecimals": 6, - "feeAccount": "HURhvCRsrwwR5TiG75Hn274WwL76kaKgjgC6n9h4FEHj", - "tokenIds": [ - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R": { - "tag": "RAY", - "name": "Raydium", - "mint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "scale": 6, - "addr": "9ASj9zDg7cT6wtvn4euSUiZte8yN2U3Tn6cTVZvMHbU7" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "HGTxSWbb62nxk4oGkLkHUvrEzR5D4GKYRb8ZDcA2dpki" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "SLND_USDC", - "address": "GhosXH9yZPxqSyTHqJtXQt6w65YfiGjKXcEXciX1P3z8", - "nonce": 255, - "authority": "ChmSHndtXRsYnFjYA2F7yRRsnyZ8kCpxSogTsCUgCEsh", - "poolTokenMint": "F59gkD7NnsdJbFKrRZsiBC8PAooN4c56T8QmahfW1iXN", - "poolTokenDecimals": 6, - "feeAccount": "GMipxN5pu6F6wwUrq6RhpqgcMjcKLTsnDTeNFCuUm5n7", - "tokenIds": [ - "SLNDpmoWTVADgEdndyvWzroNL7zSi1dF9PC3xHGtPwp", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "SLNDpmoWTVADgEdndyvWzroNL7zSi1dF9PC3xHGtPwp": { - "tag": "SLND", - "name": "Solend", - "mint": "SLNDpmoWTVADgEdndyvWzroNL7zSi1dF9PC3xHGtPwp", - "scale": 6, - "addr": "9RcdfprKxbTzp3erTJMwXKznNCLmbCUaKhibaTMXhToi" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "6wEh8r3Czc3nKkN6JXobShnLG7ZqA5Y5DREGzkirYR36" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "GOFX_USDC", - "address": "C3b5AWQJiyar5g8EWu75zgDE26F55ZJWpqtFVCCVDQQQ", - "nonce": 253, - "authority": "3SphkwoHx3d13Eu9RehVVg4gGMZv7FEaDXvPqWbQF9bm", - "poolTokenMint": "7vnps4VE5RTGAr5fmPZu7fSrk2VnM4Up838grZfqmxqE", - "poolTokenDecimals": 6, - "feeAccount": "CT95CSNqi4nttNW84dDuA8Um7FLAC52PVUvuVRKeCHVK", - "tokenIds": [ - "GFX1ZjR2P15tmrSwow6FjyDYcEkoFb4p4gJCpLBjaxHD", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "GFX1ZjR2P15tmrSwow6FjyDYcEkoFb4p4gJCpLBjaxHD": { - "tag": "GOFX", - "name": "GooseFX", - "mint": "GFX1ZjR2P15tmrSwow6FjyDYcEkoFb4p4gJCpLBjaxHD", - "scale": 9, - "addr": "5AhPVbtyiTV3SiNRJuq5z9xeaqqwoHQWqohR9HvjJkKS" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "6mtcbtTAadVEdnWJZmsq8woqLea7ef7k5WumVXSHr5KQ" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "WOOF_USDC", - "address": "HY6iq1dp7pHwstfmLFu8m2iEvRQtjX3N751jcN6KrQXU", - "nonce": 255, - "authority": "8JuHyxYBpemmryQq4bcA1GTuKaub9JJuLPoNNJpwX9aP", - "poolTokenMint": "9EjcYfHcG8f1mccpHyaAwpoxaUPiheC6KgLQjyD9aTb6", - "poolTokenDecimals": 6, - "feeAccount": "886Yu2fd1x8xpb4icdrhxZemdD8PN9RLdrq6Mn89wR4k", - "tokenIds": [ - "9nEqaUcb16sQ3Tn1psbkWqyhPdLmfHWjKGymREjsAgTE", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "9nEqaUcb16sQ3Tn1psbkWqyhPdLmfHWjKGymREjsAgTE": { - "tag": "WOOF", - "name": "WOOF Token", - "mint": "9nEqaUcb16sQ3Tn1psbkWqyhPdLmfHWjKGymREjsAgTE", - "scale": 6, - "addr": "8ju56eRfs9wg3GtoSFVoQoR6NnQn6gsWr6FkQyZ1EeBg" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "5WcqVktXr3Rr78MGGfcuwgB6azoN9EDCZLP4werGnfi4" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "SDOGE_USDC", - "address": "8GoFKVkoxPyQKWXhoXs3ycGmp9rXYM8hz7eq1EUM1MJe", - "nonce": 252, - "authority": "DSuxdCkHQy6rAjFsL75tRu2UpHVQDoYsYFeZt15sVDYL", - "poolTokenMint": "CHTKUJGYRtBDqnxCFjxe5KEkZgxV98udbhuYYyzGxup5", - "poolTokenDecimals": 6, - "feeAccount": "2gCRgQEySFTXA5v99vRUJHAGhQPTPtHx16Rdgipz7Q1y", - "tokenIds": [ - "8ymi88q5DtmdNTn2sPRNFkvMkszMHuLJ1e3RVdWjPa3s", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "8ymi88q5DtmdNTn2sPRNFkvMkszMHuLJ1e3RVdWjPa3s": { - "tag": "SDOGE", - "name": "SolDoge", - "mint": "8ymi88q5DtmdNTn2sPRNFkvMkszMHuLJ1e3RVdWjPa3s", - "scale": 0, - "addr": "ABQfmExcxJt2wE9JeLUxvhkpA2VkoQVvWKDvfusjq226" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "EDBXkzwxu6UXqBDnzb9AJ6Eggjyyct7SmYVoR8PYJkHd" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "CATO_USDC", - "address": "GumfURfQvPaJ2E5ueCEKYJmymNQbV34gU9TmiKZYRkiv", - "nonce": 255, - "authority": "EjoLNSDggfWWE7BxwoL4tJHBEg1cFpdiyKeYTYCec2o2", - "poolTokenMint": "55r9txzQtmjTykmTXmBYZCVMg5z9squB8b5cSw2AhxA4", - "poolTokenDecimals": 6, - "feeAccount": "F6xCTe256cA6HTX5CYBkDtXoruHvjfbxeHNeqR9kR7oJ", - "tokenIds": [ - "5p2zjqCd1WJzAVgcEnjhb9zWDU7b9XVhFhx4usiyN7jB", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "5p2zjqCd1WJzAVgcEnjhb9zWDU7b9XVhFhx4usiyN7jB": { - "tag": "CATO", - "name": "CATO", - "mint": "5p2zjqCd1WJzAVgcEnjhb9zWDU7b9XVhFhx4usiyN7jB", - "scale": 9, - "addr": "AGNHgSQuPd4EqjLTLJrXEVb3KCkjRxGVDTaag4drV1XX" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "FESKk2kj9oqdYR4dcaP4LyqDyWZt3NttgypRVFoyUQNs" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "OOGI_USDC", - "address": "9tK2LaapwjxaUmfcAzY9zgC39M3wnaFX558y2Bb4oxWG", - "nonce": 255, - "authority": "EGuBsx6HAgAtf1ogzF1uXTUQgwRex61hnhvuZcMwQKUJ", - "poolTokenMint": "DSiHyHDn96bUQSZtizyCRLcQzrwohZeMpVu8rYJN1HzG", - "poolTokenDecimals": 6, - "feeAccount": "Acom6ebnmbFKQk3XeX5VHPiz8bd7kzfpUMsqHKJDJnry", - "tokenIds": [ - "H7Qc9APCWWGDVxGD5fJHmLTmdEgT9GFatAKFNg6sHh8A", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "H7Qc9APCWWGDVxGD5fJHmLTmdEgT9GFatAKFNg6sHh8A": { - "tag": "OOGI", - "name": "OOGI", - "mint": "H7Qc9APCWWGDVxGD5fJHmLTmdEgT9GFatAKFNg6sHh8A", - "scale": 9, - "addr": "GgfTGZ5DnAotnXKFM86vqffKQZ9nGgHaX1PDS7RTcKjQ" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "A3rzsPGtqowjKXfscYrPo1jvv2EVYpJwXQPGKxgvvStf" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "SONAR_USDC", - "address": "Dzp3ZWyUZGXZYWfodXdLdXfiW7gwVZBdWBwQ28eB6cTH", - "nonce": 253, - "authority": "3HJw5YCXr69DzUcLSif4BicrMrXjC2jrEMpjQhQ3AwmB", - "poolTokenMint": "5MvQHx8eftU39JTucFsT315JFnQASuDQg3FqxTw7xcvN", - "poolTokenDecimals": 6, - "feeAccount": "J8tqP1N2fEgMTGhX2PTgRyj5ZFsFWsXneJpXyRjekKWA", - "tokenIds": [ - "sonarX4VtVkQemriJeLm6CKeW3GDMyiBnnAEMw1MRAE", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "sonarX4VtVkQemriJeLm6CKeW3GDMyiBnnAEMw1MRAE": { - "tag": "SONAR", - "name": "SonarWatch", - "mint": "sonarX4VtVkQemriJeLm6CKeW3GDMyiBnnAEMw1MRAE", - "scale": 9, - "addr": "DxGfntMLqAjtB287GkPPcfotUGcWdhtpzR6KukdBo39H" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "EVymxW4gFtxw7qjMYGFq4EupxHc1RteffwETa5MKTDPR" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "APT_USDC", - "address": "Fg3UabVqnfycMtkiTVoaia9eNafehtT9Y4TicH2iBtvK", - "nonce": 255, - "authority": "JDEYn1JsacdxoB4v4mbctFSVrSUPttacX3gxWphFHJKZ", - "poolTokenMint": "HNrYngS1eoqkjWro9D3Y5Z9sWBDzPNK2tX4rfV2Up177", - "poolTokenDecimals": 6, - "feeAccount": "41H5mWwsZKewJeV4wWiNjQ3U4VYBnwqCpzvAWt86baHd", - "tokenIds": [ - "APTtJyaRX5yGTsJU522N4VYWg3vCvSb65eam5GrPT5Rt", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "APTtJyaRX5yGTsJU522N4VYWg3vCvSb65eam5GrPT5Rt": { - "tag": "APT", - "name": "Apricot", - "mint": "APTtJyaRX5yGTsJU522N4VYWg3vCvSb65eam5GrPT5Rt", - "scale": 6, - "addr": "636crNdZTf46gFUKuedaBCZDBMLahf7KGud2LyTMskU5" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "DGEYFkEHyiuHWtHeCGiQGn1JbkGHqYrNwaP44miRbgxu" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "DFL_USDC", - "address": "59wJQz25rr38YnD69eXsntbdE4LB7m39KjHqZUUaoyZ3", - "nonce": 255, - "authority": "E2kEN96wSW5bYML8qYLgxKM4pvdLjqhCRMyCvqYyVrXt", - "poolTokenMint": "AWrtTWG4Zgxw8D92bb3L3sQtGLD3zDztMPWsXSph8iBP", - "poolTokenDecimals": 6, - "feeAccount": "bZxTKZNF5gwnuXQ3xt8huUtsLAyFoh2NnQwmDDgbVxd", - "tokenIds": [ - "DFL1zNkaGPWm1BqAVqRjCZvHmwTFrEaJtbzJWgseoNJh", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "DFL1zNkaGPWm1BqAVqRjCZvHmwTFrEaJtbzJWgseoNJh": { - "tag": "DFL", - "name": "DeFi Land", - "mint": "DFL1zNkaGPWm1BqAVqRjCZvHmwTFrEaJtbzJWgseoNJh", - "scale": 9, - "addr": "EXZdhy56TjvArQRfDakjuQdT7DffwFEYdY5F39vn3Wbr" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "Bhch1NY65RNA8uFaj2s8Fzxu36SFMQiniyZidq4jzsTt" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "DFL_SOL", - "address": "GxkXvW6dJP3KUNWuXi64V99uRsPFEFnuuasNTq6fvZfP", - "nonce": 255, - "authority": "H196f95DHGfhNkF3W9h4bjBqpL8g3qesEENHRsDqJshj", - "poolTokenMint": "9Y1vPaAsMz8X65DebMMnmBjbMo8i4jh4mcgiggZUUS3M", - "poolTokenDecimals": 6, - "feeAccount": "7L7kjeEo5oE9SCZ9vacmyJvfKKmjAevVpdktBGyxBxaF", - "tokenIds": [ - "DFL1zNkaGPWm1BqAVqRjCZvHmwTFrEaJtbzJWgseoNJh", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "DFL1zNkaGPWm1BqAVqRjCZvHmwTFrEaJtbzJWgseoNJh": { - "tag": "DFL", - "name": "DeFi Land", - "mint": "DFL1zNkaGPWm1BqAVqRjCZvHmwTFrEaJtbzJWgseoNJh", - "scale": 9, - "addr": "BpjpdhuMkPPW3HPx4U9tRmNAXdUeb49jxwFGy2PrSNCp" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "HcXqJthqq1UeGHA8xPeDLnWVJFcndoUnKnpULRCjyTzi" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "FRKT_USDC", - "address": "DXNct3MfHDuhKiXHY3AUXPtj5sQVY3feuDxkDRfCw1rL", - "nonce": 254, - "authority": "JBCdhgkmW6xHdZUZdKdf56qov9LtHixf47JpoCWm4qcn", - "poolTokenMint": "FnDxJPNk7pPmGHUbR4XUHmHevrkXHdna5D3sQKcAtjBL", - "poolTokenDecimals": 6, - "feeAccount": "DRn2F5MsWzLihtqsheuJmugJuHQGDR23cvqCLy7eCucw", - "tokenIds": [ - "ErGB9xa24Szxbk1M28u2Tx8rKPqzL6BroNkkzk5rG4zj", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "ErGB9xa24Szxbk1M28u2Tx8rKPqzL6BroNkkzk5rG4zj": { - "tag": "FRKT", - "name": "FRAKT Token", - "mint": "ErGB9xa24Szxbk1M28u2Tx8rKPqzL6BroNkkzk5rG4zj", - "scale": 8, - "addr": "AUSeFBvVtLiZRppRu8Uvd8NjzCkQzaCi5Si8WWyko9p" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "C3RzSoNiBfTNbAZMyyuV2aLfwGQRyjvkjL3pf9iuvU3R" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "TTT_USDC", - "address": "HD6pqxyqj4S7eS3orAyQyan5RpwpMPjKEDWgTyYXcfr1", - "nonce": 254, - "authority": "Gh1QqgpKGd6zhicNvBh1VLbycpoq6P7QBCZT8MdhWzN1", - "poolTokenMint": "FGgP1npQTsC5Q4xBmQtNYSh51NKqNwdxBZy8JCo3igcu", - "poolTokenDecimals": 6, - "feeAccount": "AFjaSrdgNJsFDSQTDbkBoBMLHt2qCt5GuPHWDTUV4nHt", - "tokenIds": [ - "FNFKRV3V8DtA3gVJN6UshMiLGYA8izxFwkNWmJbFjmRj", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "FNFKRV3V8DtA3gVJN6UshMiLGYA8izxFwkNWmJbFjmRj": { - "tag": "TTT", - "name": "TabTrader", - "mint": "FNFKRV3V8DtA3gVJN6UshMiLGYA8izxFwkNWmJbFjmRj", - "scale": 6, - "addr": "HbrvwSnL11K5EALN21FdjmWvG16VNcq5iyHEKjdHtyJe" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "CQvyngoqxCdgFQYjbT8EKved6hTDzmzdp8Xxxv5FkXmd" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "UPS_USDC", - "address": "G67ZSkxE5N67x6A1WhcTaHiFHqRtRQUb3QHwjtPge1Xr", - "nonce": 250, - "authority": "Hj3vg6P2DBfJ6hhvCoucaGvL9cwsvUgeJWZRzuXTZ6hi", - "poolTokenMint": "E1U63VXhNiWoUkVvjrfLDdV1oJrwE6zLde3bohr6jCqz", - "poolTokenDecimals": 6, - "feeAccount": "Cu8SFyZKsHcUYhxECpt5Wr97CeHSXeDyNjs9kyDWtVJm", - "tokenIds": [ - "EwJN2GqUGXXzYmoAciwuABtorHczTA5LqbukKXV1viH7", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "EwJN2GqUGXXzYmoAciwuABtorHczTA5LqbukKXV1viH7": { - "tag": "UPS", - "name": "UPFI Network", - "mint": "EwJN2GqUGXXzYmoAciwuABtorHczTA5LqbukKXV1viH7", - "scale": 6, - "addr": "CNw37MJdV6gBChtEtUgGrx3zWXz8t3bYxD7u5axPrwdJ" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "5iLVx3LwhWiqjaRyLaiVNsLbYBqy48fvs2sTY6q96nNy" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "FANT_USDC", - "address": "95aDcNzL8tL17jzHAUQXnRwuCmYBWKUr4xfjV6AMVJY1", - "nonce": 255, - "authority": "GeTZHdp1sYgX6J73CBeqS5pjb7xfY8D9Rzf4E615oGMt", - "poolTokenMint": "GjG7JjTQfQpDxw4hWx4etP9oTaYCuCbPjsU8WaUT3xHB", - "poolTokenDecimals": 6, - "feeAccount": "AdSQYnzmJ4j2hbqT5aumXAf4a3T2AxmGHbCgHER8rf6K", - "tokenIds": [ - "FANTafPFBAt93BNJVpdu25pGPmca3RfwdsDsRrT3LX1r", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "FANTafPFBAt93BNJVpdu25pGPmca3RfwdsDsRrT3LX1r": { - "tag": "FANT", - "name": "Phantasia", - "mint": "FANTafPFBAt93BNJVpdu25pGPmca3RfwdsDsRrT3LX1r", - "scale": 6, - "addr": "CyLaJ6Y382czGE75yFDg2fneKni6PjZHH9Jh4GZN2Nyo" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "7wHMKRPVsacb3JcBsUxLKLZkAPbX81VNc6Z6J9uvJ2J8" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "BLOCK_USDC", - "address": "ExeW62iy4xEUo5b5XnDru5oQCDRDUmBaFNqE4V4u7uvm", - "nonce": 255, - "authority": "2fSbre92FnmkeUP5iT7jdFKNB3nfx5yQ5GEW2mjVigMi", - "poolTokenMint": "D8WjqtwC9CzBrQKfSf2ccCHFQuPYwyLv5KAy8WjT5vnf", - "poolTokenDecimals": 6, - "feeAccount": "BGSDZoQyH8QGJDvQ8toms4Pk4HWHaFEXSUvJ3AAYXxmF", - "tokenIds": [ - "NFTUkR4u7wKxy9QLaX2TGvd9oZSWoMo4jqSJqdMb7Nk", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "NFTUkR4u7wKxy9QLaX2TGvd9oZSWoMo4jqSJqdMb7Nk": { - "tag": "BLOCK", - "name": "Blockasset", - "mint": "NFTUkR4u7wKxy9QLaX2TGvd9oZSWoMo4jqSJqdMb7Nk", - "scale": 6, - "addr": "7uJ5SFRGzrnbspUThix8M2wFJNnS8vvSKbCEhKmqMjNm" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "4e5ZVp7u6YWEibveHscZmbmHpujtbJNUHFj14tqtAZKv" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "RUN_USDC", - "address": "9j4FdbK68xUDQVynTWHbNzBRAj7Q7Lywiqb82en4JzZs", - "nonce": 253, - "authority": "9RUMuXequVtf9UVYHoKJxwWfqyod478nBfX8H3DvSaKV", - "poolTokenMint": "34Ppq6R8NfYBwWwPY4cBK4Afyb8hHaASQFukCzH6cV4n", - "poolTokenDecimals": 6, - "feeAccount": "pPH4mFHFu1c3ZR59Zaun5jSCBRn6pU1GWSoVHD4LKUs", - "tokenIds": [ - "6F9XriABHfWhit6zmMUYAQBSy6XK5VF1cHXuW5LDpRtC", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "6F9XriABHfWhit6zmMUYAQBSy6XK5VF1cHXuW5LDpRtC": { - "tag": "RUN", - "name": "Run", - "mint": "6F9XriABHfWhit6zmMUYAQBSy6XK5VF1cHXuW5LDpRtC", - "scale": 9, - "addr": "tg7YMVac4S2ZpVrbaDqrZgURyTBBrZCQUkQ6Fn6nnrX" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "G2fZDZKa5Y599xzqP1jVQ3EMCfiG6f4dMS6G1f7BKoQe" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "UXP_USDC", - "address": "eKuTPdMHmnVzLP63oWwdUH6bBAVcdvBfg4zvH2nWWCj", - "nonce": 255, - "authority": "DYwCP16u5pmLMspCb8tdTQaaF2rBvM2qvgzm5uYvPUHT", - "poolTokenMint": "HjR8JgqNKQVMvdryqJw5RJ4PCE9WGk8sgbEF7S9S3obv", - "poolTokenDecimals": 6, - "feeAccount": "HoaPae92LswzSbvnVbdkBAYFNanrvK3kFvWtYyUhpC2o", - "tokenIds": [ - "UXPhBoR3qG4UCiGNJfV7MqhHyFqKN68g45GoYvAeL2M", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "UXPhBoR3qG4UCiGNJfV7MqhHyFqKN68g45GoYvAeL2M": { - "tag": "UXP", - "name": "UXD Protocol Token", - "mint": "UXPhBoR3qG4UCiGNJfV7MqhHyFqKN68g45GoYvAeL2M", - "scale": 9, - "addr": "BWL9ocg8VEBSfrS7zjUBUidE9T8p95J3p5wF6C4Vaqrs" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "GQC4fM5E6dr9MsXvtMzAR4Z8iCduhyFvYCLdMAAHGCM2" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "BTC_USDC", - "address": "2dwHmCoAGxCXvTbLTMjqAhvEFAHWUt9kZaroJJJdmoD4", - "nonce": 253, - "authority": "BwJ1vMtJiBy7dJaVToR1KUwVbBsGUTNN4QdKVSf8EEh1", - "poolTokenMint": "J3kvcay3N16FBdawgnqoJ9v9p6XCvyCLE2Z9F5RLvGkj", - "poolTokenDecimals": 6, - "feeAccount": "HR7c67SkeLvCpHrVSu7MiiAERQh6iD1NrCJsj3kWiZnK", - "tokenIds": [ - "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E": { - "tag": "BTC", - "name": "Bitcoin", - "mint": "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "scale": 6, - "addr": "D3Wv78j9STkfJx3vhzoCzpMZ4RqCg8oaTNGzi1rZpdJg" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "HMFLg2GtbWSSEe92Vuf2LQdUpCacGj2m2PwvMqzwQFNi" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "MNDE_USDC", - "address": "2yNwARmTmc3NzYMETCZQjAE5GGCPgviH6hiBsxaeikTK", - "nonce": 253, - "authority": "2ZzxuHxvPQtPU48Tffs8LD8sy17rgjBRQviRVxQ54fR6", - "poolTokenMint": "12Uj74zgUUoBe4yeackwQ4qYtFMr9fk1xL6q5Nha6t2N", - "poolTokenDecimals": 6, - "feeAccount": "6AvWhLSuAqTWUdpo4jF84s4gfgAjbRQv5vLf7mYNCgd8", - "tokenIds": [ - "MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey": { - "tag": "MNDE", - "name": "Marinade Governance", - "mint": "MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey", - "scale": 9, - "addr": "AfF3SJFpyfU7iw9KtrwPyi6corJbyiC24JyVis7oxNVr" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "FT4GQqs5sEvqhsWm845VF1vmHjdQkrB1jdsGPJbzB4oB" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "CHICKS_USDC", - "address": "3abwmh8LDUsXMoDgNzZLq9QvKqKbhYND9N5aXh9yz7Dm", - "nonce": 255, - "authority": "HmNqp8F5Bp16dUTUihhL3TnyQxfzJ2GtTo9VEQx6bjB3", - "poolTokenMint": "71CBZeJ4tw38L9pSPoCz4fRsuWE64Fipyzotte7haoCS", - "poolTokenDecimals": 6, - "feeAccount": "4zRJg9Kod7bd9tR3mxQhxzAQUPqQmUGJbmrWpQ4XDGT4", - "tokenIds": [ - "cxxShYRVcepDudXhe7U62QHvw8uBJoKFifmzggGKVC2", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "cxxShYRVcepDudXhe7U62QHvw8uBJoKFifmzggGKVC2": { - "tag": "CHICKS", - "name": "SolChicks Token", - "mint": "cxxShYRVcepDudXhe7U62QHvw8uBJoKFifmzggGKVC2", - "scale": 9, - "addr": "84Ha1dXH8YAWXt3AC15RstnUCoWT3hg24tUGD1GtqGSm" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "GkonWV6urvzsnKwVmPXe89fTX1zBfv4xrAhx9JnxV9Nq" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "ONESOL_USDC", - "address": "CKKuMECwW75NBNRKtYJz1svCycRHt4KpXmcNnHXiHY73", - "nonce": 253, - "authority": "2TSCMpjN6ToLJy8baiFTc9UdB1PuHFsr24mos98Zp57v", - "poolTokenMint": "6MF5CHWAj5mS7FhpxiKz37CzR2eYTu236XpBKKMXCrGg", - "poolTokenDecimals": 6, - "feeAccount": "9Rw29Mvx6b2RMAbdZoqs3gBRMcfYjBYRyiegNZoaYrWS", - "tokenIds": [ - "4ThReWAbAVZjNVgs5Ui9Pk3cZ5TYaD9u6Y89fp6EFzoF", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "4ThReWAbAVZjNVgs5Ui9Pk3cZ5TYaD9u6Y89fp6EFzoF": { - "tag": "1SOL", - "name": "1Sol", - "mint": "4ThReWAbAVZjNVgs5Ui9Pk3cZ5TYaD9u6Y89fp6EFzoF", - "scale": 8, - "addr": "2meoejmWQno2q6cbFMRytu7UMqMA8FTx651feSUHfTtC" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "n5CtiZDLm2xNxVU1o4KC98dNGiFb1sbuCazDihahbMy" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "WMP_USDC", - "address": "Cqy7PRGRx2QeTLZM3QmLGN68uHxEd9euj2eEeeZWnuvQ", - "nonce": 255, - "authority": "9vkbzRnjd9qpmunBUHqS8Fnt9DUEX5akJPm9movtfNxZ", - "poolTokenMint": "HDgxKmiA8Pv82fNguhVeMkZqQkos2YksFPoP1KttWxX8", - "poolTokenDecimals": 6, - "feeAccount": "Bfr66xExhYijJzc732abX7znkFnj4v3otQDFbHaz7RkK", - "tokenIds": [ - "BygDd5LURoqztD3xETc99WCxLUbTi6WYSht9XiBgZ4HW", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "BygDd5LURoqztD3xETc99WCxLUbTi6WYSht9XiBgZ4HW": { - "tag": "WMP", - "name": "Whalemap", - "mint": "BygDd5LURoqztD3xETc99WCxLUbTi6WYSht9XiBgZ4HW", - "scale": 9, - "addr": "3WubbpV7W82H6FERR62Bd8Z4fXFGaihtBNqnT1zkGr6f" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "8MxcExnMniQEDs361cZseukEau9Rmd3CmrCXxasmNM1x" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "UNQ_USDC", - "address": "3a3G1RjJe826EB1toShvPPWnyi2jXR53HP4vYb936kwj", - "nonce": 254, - "authority": "94V4mU6bWzU86tdzFbBCjkFngqXvf5MwXKhVLgJA83vL", - "poolTokenMint": "2VuGzaMrDnDyZfYvDwSXk38s7M2wpud7LDY3dGA1J9sy", - "poolTokenDecimals": 6, - "feeAccount": "9iHGnquXmnJnSATN4ijGj7Niz4StxXEMC8KqB1pT51uW", - "tokenIds": [ - "UNQtEecZ5Zb4gSSVHCAWUQEoNnSVEbWiKCi1v9kdUJJ", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "UNQtEecZ5Zb4gSSVHCAWUQEoNnSVEbWiKCi1v9kdUJJ": { - "tag": "UNQ", - "name": "UNQ", - "mint": "UNQtEecZ5Zb4gSSVHCAWUQEoNnSVEbWiKCi1v9kdUJJ", - "scale": 6, - "addr": "Hf4gYkKNAPhm2RYrXrcP9YVL44VbYnsRsyUuBnZGzqPr" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "BZ9oTLGDL6tsvoooQ9qEBSM3sYKJB1v2e9b4en5ix1Mp" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "BASIS_USDC", - "address": "9wb29L97MmPp7Nw8oaqiAGkXceETGNQurhySiUNLv5wh", - "nonce": 251, - "authority": "786ezhfHqkmJUBmjrWYGpzPnVWR8zhy2V71qNws7D89z", - "poolTokenMint": "GoaAiajubRgeCFEz9L6mLnSmT2QFegoJDH5tpLfivpj", - "poolTokenDecimals": 6, - "feeAccount": "4FjEd37W9FExXq85nLeuNWuhUaTwkFdnqewt3E3qoYAh", - "tokenIds": [ - "Basis9oJw9j8cw53oMV7iqsgo6ihi9ALw4QR31rcjUJa", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "Basis9oJw9j8cw53oMV7iqsgo6ihi9ALw4QR31rcjUJa": { - "tag": "BASIS", - "name": "basis.markets", - "mint": "Basis9oJw9j8cw53oMV7iqsgo6ihi9ALw4QR31rcjUJa", - "scale": 6, - "addr": "7QM71YvJm86bN9RLFoEvyDX8dBgLh2xjnabcHf4d1Q1y" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "AmP22dYrTsG2LrkQX9cLg79jUrzDJcmWqGEWmM3Mdn46" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "GST_USDC", - "address": "87E4KtN7F4LivKhjqXaoQAvS3a8HnM4DnMUrbMrkVvXY", - "nonce": 244, - "authority": "CwwMfXPXfRT5H5JUatpBctASRGhKW2SqLWWGU3eX5Zgo", - "poolTokenMint": "E6FUnQHGHJVJg7oExVr5Moeaj1QpdpZQF5odYjHXWPZb", - "poolTokenDecimals": 6, - "feeAccount": "BynpQprCNjcY2KHeffDKzquyKWvJxikty3donrMT4ZPU", - "tokenIds": [ - "AFbX8oGjGpmVFywbVouvhQSRmiW2aR1mohfahi4Y2AdB", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "AFbX8oGjGpmVFywbVouvhQSRmiW2aR1mohfahi4Y2AdB": { - "tag": "GST", - "name": "GST", - "mint": "AFbX8oGjGpmVFywbVouvhQSRmiW2aR1mohfahi4Y2AdB", - "scale": 9, - "addr": "9r39vqrJuubgafaJ5aQyDWYAUQVJeyZyveBXeRqp7xev" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "7LFnr5YgUyEgPMCLGNQ9N7wM5MFRNqCuRawLZTe5q4c7" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "MEAN_USDC", - "address": "4jhCSYuGkLCiB8uvCaS34QCtPycBjayxEk27YCartTuW", - "nonce": 255, - "authority": "Fawkj9g4s1M26uZDF6QczEviyib2Ge3FaPdCG9TJLYcm", - "poolTokenMint": "F5BTnwuMA6rxftTdbZ33VWKr2wrr6DuQHnd4guKmPSYQ", - "poolTokenDecimals": 6, - "feeAccount": "EqhWQbxsa36o7YSrCNvJTV1yoTRTWxCiLKcG9pzafprc", - "tokenIds": [ - "MEANeD3XDdUmNMsRGjASkSWdC8prLYsoRJ61pPeHctD", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "MEANeD3XDdUmNMsRGjASkSWdC8prLYsoRJ61pPeHctD": { - "tag": "MEAN", - "name": "Meanfi", - "mint": "MEANeD3XDdUmNMsRGjASkSWdC8prLYsoRJ61pPeHctD", - "scale": 6, - "addr": "5KSCuA99i7PSF6KvvbvV5hDveGse7isqF6e7tFXPeMyn" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "13PtHDhQzswoFWg8Gr4yVrTmUEW4CWxeKFkLVERCmypB" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "AART_USDC", - "address": "8wVYTnchy3WbhJvKn4NhTbgtVm6Bfd6yvxR33DsSftse", - "nonce": 255, - "authority": "GAWAD19LVUgKmkWWfB4Xg92KMXuVR7M1gUpQPiFAAtxR", - "poolTokenMint": "HCtyJzFUtYecXrA52s4Y9atq4J1fhT3cYsTX17XVSFag", - "poolTokenDecimals": 6, - "feeAccount": "FmZkn9xAwpZULmF6rSrcz1pHiqqNnAXCUFWs1z5t9LSX", - "tokenIds": [ - "F3nefJBcejYbtdREjui1T9DPh5dBgpkKq7u2GAAMXs5B", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "F3nefJBcejYbtdREjui1T9DPh5dBgpkKq7u2GAAMXs5B": { - "tag": "AART", - "name": "ALL.ART", - "mint": "F3nefJBcejYbtdREjui1T9DPh5dBgpkKq7u2GAAMXs5B", - "scale": 6, - "addr": "Hy3FDHpTfzqtooUARjgUvYuRcFnjGH5WLftu77DyEnKJ" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "J4Cd9u1WuY1WnCScENuRyL2jGh7qD6vpRsWJG6ZsC5z9" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "SHDW_USDC", - "address": "25bQ6UzZpgFgnU7MqZdqM9Axi6oJunytRL2LgXruDWZB", - "nonce": 254, - "authority": "BjnfpyU3Verx99dKcEJZpL1AqLTPrkAUcd44LpXcXVvn", - "poolTokenMint": "DJqqvzSuPaWThfzwMjXx7H2ZmHDdwxza6NtFudtuXcpc", - "poolTokenDecimals": 6, - "feeAccount": "9wmHbXURZ4zTPSj1KqoRSCdBRGUF7jrURzf7BB39cxM4", - "tokenIds": [ - "SHDWyBxihqiCj6YekG2GUr7wqKLeLAMK1gHZck9pL6y", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "SHDWyBxihqiCj6YekG2GUr7wqKLeLAMK1gHZck9pL6y": { - "tag": "SHDW", - "name": "Shadow", - "mint": "SHDWyBxihqiCj6YekG2GUr7wqKLeLAMK1gHZck9pL6y", - "scale": 9, - "addr": "8ZVaNyNZQkcMzF7esuZoRgRo7Rc9eKEN18v4zw7Ng8JZ" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "H8A2xivBXr1RMCYmuhJ7dyEXJqPxaGDyQaaim8WucU7c" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "SHDW_SOL", - "address": "E3fxkJGNNAWf5xXDfMdq5qofBVkQtLKxkP7gG6Up21Ts", - "nonce": 253, - "authority": "ByC5idkRdo2XdU5U6tSoSQmfq6spztUYMaSs2rrcJRPh", - "poolTokenMint": "2ws7g3LBPdctfKn42Di9qxzQtUJ8ZL1aEAX2rGEQMNqh", - "poolTokenDecimals": 6, - "feeAccount": "G9HR4sFJufdUovMGn4qc97r7fhgJCkTDnn4BT2wPWYar", - "tokenIds": [ - "SHDWyBxihqiCj6YekG2GUr7wqKLeLAMK1gHZck9pL6y", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "SHDWyBxihqiCj6YekG2GUr7wqKLeLAMK1gHZck9pL6y": { - "tag": "SHDW", - "name": "Shadow", - "mint": "SHDWyBxihqiCj6YekG2GUr7wqKLeLAMK1gHZck9pL6y", - "scale": 9, - "addr": "9LQEB2SZQJxtLQStgXVNzgWU3LVkc4szK22iDHcSr4K9" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "F2qtMkEy3L78wpw64bckvRx5M4w12Zi7bimuPBnYzto1" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "SCY_USDC", - "address": "Ci2T7KY8xXc3NmSr4JmbhZ2V7SfjZ7Fn2q6VxJsDD1Dg", - "nonce": 255, - "authority": "fmoBkLez7cSLnG1XNn6PTf6UH5Vq2hSAPrZ1NbvRppL", - "poolTokenMint": "99ZHUQsgxL7K6PHrGNi1gSwawwPr7UA5fbWrYoHQ6qhX", - "poolTokenDecimals": 6, - "feeAccount": "HHhxxFKyVt4xrYnJqAiywHCzuoCu45S4itkLKvop2fAe", - "tokenIds": [ - "SCYfrGCw8aDiqdgcpdGjV6jp4UVVQLuphxTDLNWu36f", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "SCYfrGCw8aDiqdgcpdGjV6jp4UVVQLuphxTDLNWu36f": { - "tag": "SCY", - "name": "Synchrony", - "mint": "SCYfrGCw8aDiqdgcpdGjV6jp4UVVQLuphxTDLNWu36f", - "scale": 9, - "addr": "Hfa6kPY27pgnbXHMd1bKBaYMBoF8RRxUm2AmWHBWudcn" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "CYKEhyhe9JZqLzaM29o8urMu8riDNBE6ycZP6bLQtkbF" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "SLC_USDC", - "address": "ByfDbpLVNVQHzU6E5dmLE1kcAKWAYRr9LPSGcVxxSRFF", - "nonce": 255, - "authority": "7G6i4eQxiJvXg7hPn5kMrso8AHQNsdfPZZdJM3NNJuYz", - "poolTokenMint": "E5kSBqTDxFLbLNQaVVtPtnhEYVLMCK2fVSEKoMKL98qR", - "poolTokenDecimals": 6, - "feeAccount": "CtBP4cFDLzm3KQCQRKXwwsMgYG9f6hbwuUswUZBzYvvY", - "tokenIds": [ - "METAmTMXwdb8gYzyCPfXXFmZZw4rUsXX58PNsDg7zjL", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "METAmTMXwdb8gYzyCPfXXFmZZw4rUsXX58PNsDg7zjL": { - "tag": "SLC", - "name": "Solice", - "mint": "METAmTMXwdb8gYzyCPfXXFmZZw4rUsXX58PNsDg7zjL", - "scale": 6, - "addr": "EnvNSVK9JRQ5jmsz7nvbhYmR3MHSeMvB8Mf1e4VwoyRe" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "CHuUSo3EMCqtGWvUGRj4crmDzV5YKdYvqrhHSEitAP8V" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "wUST_SOL", - "address": "M3DfDvKZ9WEWYWcBuguvt3rYSbKqj66PgjW69DoEq9C", - "nonce": 249, - "authority": "5mYWcs7n1JqDVeYby897eEUNeEJsp2PNMg2Y2VMD5Jrf", - "poolTokenMint": "6c13xsmyk7UaHUWZ2rm1MM3ZdrQRSBkQ9waaG25ridVs", - "poolTokenDecimals": 6, - "feeAccount": "BSoUBwfNgXSHX8QoZUnjfu8wWKyBmjNyDXwsgW3UEff9", - "tokenIds": [ - "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i": { - "tag": "wUST", - "name": "TerraUSD (Wormhole)", - "mint": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "scale": 6, - "addr": "3T7UL3ixF9S8XPjW7SEr9yYY8A5YWTDc7omgjKD2ULhb" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "91NfC8SunFRWF6BqEKnbnJCursfiDB2U3H6GGCqsFVxc" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "wUST_USDC", - "address": "Awp1hdAi5xi3CTDsXxiZsygSacpZV2a3L8rNNvpNRVn4", - "nonce": 255, - "authority": "EtdLVaBnKzfKPqp8E2swCyQcjp8XjoT5FE72kqGxWCkq", - "poolTokenMint": "J1KfRtP5y2warpD7LdJhfBLPKoWwSqYuovdArSv1mpQ7", - "poolTokenDecimals": 6, - "feeAccount": "2onwniiH5fapr1EPsCDBnY92HGzoQpiHnNPWTmxngKbd", - "tokenIds": [ - "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i": { - "tag": "wUST", - "name": "TerraUSD (Wormhole)", - "mint": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "scale": 6, - "addr": "GZWYWkbZ63teAW3tUaThq7k4NMp67TqwF94TqAMRSPx4" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "DMuVdnkRsqP7v8exbrdHNn7WoViNLjf4PVanEQtwgFZ6" - } - }, - "curveType": 2, - "amp": 100, - "feeStructure": { - "traderFee": { - "numerator": "06", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "01", - "denominator": "2710" - } - } - }, - { - "name": "mSOL_wUST", - "address": "BpiM8jnpbha2TnTKp4AogyLYYA99Ks73GfDGueUWLakT", - "nonce": 255, - "authority": "DVSsnD9fid2o6nzqbET1LctDmNMHBthf8LS1u9ZPyebr", - "poolTokenMint": "68YVjgPnTUPcBqZyghqvD2WPNsrLKsjYTmBKJzHRr4qd", - "poolTokenDecimals": 6, - "feeAccount": "ETX7csSJYTMYFwLAC6oPDKXnYWdpkzsNXyG2JuxVV4tJ", - "tokenIds": [ - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i" - ], - "tokens": { - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So": { - "tag": "mSOL", - "name": "Marinade.finance", - "mint": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "scale": 9, - "addr": "8SuMMuDbSGVpWjp3fW5kzpMWuMhxcdQwGgLJiviP25UD" - }, - "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i": { - "tag": "wUST", - "name": "TerraUSD (Wormhole)", - "mint": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "scale": 6, - "addr": "FL5QM8K2AYrqN52ssqr9GA3goYGkUiXQQxXfFFc9xD4f" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "wLUNA_wUST", - "address": "C9NcP1mx51DLZVX8VtAk2Ldip5v6xCxZGmhx7Bxtqnz8", - "nonce": 255, - "authority": "CAsASHduARHrb6pFFYrD9vcqXWhEEj7Z6AatKYVG3dbA", - "poolTokenMint": "8Mh7drLbt3jFJYwp948XyvQscGLaLkChNcaH5wwaAoWA", - "poolTokenDecimals": 6, - "feeAccount": "J43pVTNEB3AQEeXopMWTEozjPeMHBkwETXQWr4YZDzn3", - "tokenIds": [ - "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W", - "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i" - ], - "tokens": { - "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W": { - "tag": "wLUNA", - "name": "Terra", - "mint": "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W", - "scale": 6, - "addr": "97aVH3M9cjZmfA5HVu9iJ9AnE41inBG1Sxqj8UQhR2jo" - }, - "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i": { - "tag": "wUST", - "name": "TerraUSD (Wormhole)", - "mint": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "scale": 6, - "addr": "Av3RXECkvPCehJTJNbkWmUj3LmP63c4btzMYjbcYLkpm" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "stSOL_wUST", - "address": "9F3J6RY7PTkDb3SUUpg725uXyCceBGCpZrtmYGJwgMwF", - "nonce": 253, - "authority": "wJydc21tAMxYDif8uvy5rWNGWDFNZnPPmqCvegyZRod", - "poolTokenMint": "HTZd53fYwYQRyAjiaPsZy9Gf41gobFdqkF4oKe3XLi95", - "poolTokenDecimals": 6, - "feeAccount": "5rCbmppxMBHwBjCkLUP6fireQ12cL8LRa26QRUimoxN6", - "tokenIds": [ - "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i" - ], - "tokens": { - "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj": { - "tag": "stSOL", - "name": "Lido Staked SOL", - "mint": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "scale": 9, - "addr": "GFso9SAGakm8ZFa3rmuonuerbcQ8ZbACNZN7idkKR5nw" - }, - "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i": { - "tag": "wUST", - "name": "TerraUSD (Wormhole)", - "mint": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "scale": 6, - "addr": "EZ7pJskN2a4pDknrdkLzGDHpzjbfgdBj3Tt594K9HZbL" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "JSOL_USDC", - "address": "5pki97N9a6yEB3YQL3y8gvf4nSWnvEL9V6yms8Amnd9Z", - "nonce": 255, - "authority": "BqBc47X3wgrVzi8zPUMUvsaKWsj6JN4wKJ4ArGRKn2QG", - "poolTokenMint": "AzEoVuNJyo9ByoLRZ5t6vav2Zg24vULNVJM41PgCKUqR", - "poolTokenDecimals": 6, - "feeAccount": "9Qkje8PCpu4LrGwpudcN3sunWLVP6ZP61zNupaPKNRnr", - "tokenIds": [ - "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn": { - "tag": "JSOL", - "name": "JPool", - "mint": "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn", - "scale": 9, - "addr": "D4Am1hMwzQqULAvmEjwJLDGwoyTgakRXrn7ayWHMhiB7" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "GznbQjBy2KKYYVLaJ6bM59GgekRsKT5QRi2NFMYNRcmf" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "daoSOL_USDC", - "address": "6TwZgp6ABN7pbXbxvaZriHbbxeSAcEgxhKYnqGwphiRD", - "nonce": 255, - "authority": "5jFXPUF5mN83WZkT5MJQFpFcZrP5zPZy1ZZwD29Le2Kh", - "poolTokenMint": "CCyDxjdW3G7hPTthTMPTZ4bnhFF19XG6rx2fNiKeRQww", - "poolTokenDecimals": 6, - "feeAccount": "JCnNHppa7kp9bRc3zfvfnwGqoVR8Li6sJT9pMztgwE9j", - "tokenIds": [ - "GEJpt3Wjmr628FqXxTgxMce1pLntcPV4uFi8ksxMyPQh", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "GEJpt3Wjmr628FqXxTgxMce1pLntcPV4uFi8ksxMyPQh": { - "tag": "daoSOL", - "name": "daoSOL Token", - "mint": "GEJpt3Wjmr628FqXxTgxMce1pLntcPV4uFi8ksxMyPQh", - "scale": 9, - "addr": "EZf2tVoxVgGaBz6ir5iBppxiqFSqBUob2dNpiEuXMYiJ" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "3v29nJzrWebKv3DefSY5WVq4kgHWykF7fdYVaCpohwks" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "ORCA_USDT", - "address": "4YnaUPeZ2fYqpoLrCyprSai8LaDWZxmgb6cGfNHJmyP6", - "nonce": 255, - "authority": "35d4qNQiMtNV9Yb2kqk4tSd5M1yEqozWSQaYtjGHCA7b", - "poolTokenMint": "Gx4PoxenyQwhGGnKagAT35iVg4im1iKhJxDWqVhgu6tk", - "poolTokenDecimals": 6, - "feeAccount": "ABuGLBFTwcbLsqNsiCpZsFuNmHYwHEzfQR9SNpr4y3bP", - "tokenIds": [ - "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" - ], - "tokens": { - "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE": { - "tag": "ORCA", - "name": "Orca", - "mint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "scale": 6, - "addr": "D91z1TewbTQ3AVc9RThtTjiMVRqr94CP73XrsbHEhej8" - }, - "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB": { - "tag": "USDT", - "name": "Tether USD", - "mint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "scale": 6, - "addr": "Fy4AwXwAwitVdFwgWBdYkqRVv8QjigU86ssL6rqzgp8S" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "ORCA_whETH", - "address": "D67u6UEuFp9Q4Fu2gnu5thxBoVj2eRgDDDirdWsMVsgm", - "nonce": 255, - "authority": "4kwchkCnCaZPkBdnk85j9bJ9F1P883rwjbvsXGV7H5rM", - "poolTokenMint": "GsfyYHkSgC3Ta6aWR9MjB2sxoBrkGGeR2tAwXbpphf3", - "poolTokenDecimals": 6, - "feeAccount": "GdHXLai5M8FKedXUsECSzrV72nb1RTCCooFyTWT8WYmT", - "tokenIds": [ - "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs" - ], - "tokens": { - "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE": { - "tag": "ORCA", - "name": "Orca", - "mint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "scale": 6, - "addr": "EMxDw1NjdddQjPk9gCUN4iDMy8HJ5siKYMVjGbjuUCrh" - }, - "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs": { - "tag": "whETH", - "name": "Ethereum", - "mint": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "scale": 8, - "addr": "DQyhcuEvE1K9DSd51agcNLg4CDrgthnKMVhU7q6R55LV" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "GENE_USDC", - "address": "PQ1sBpkZYTkXo2aDRqWU2sEJGUj7yaeJ3GePoCRYU4V", - "nonce": 253, - "authority": "DvbTrW3tUfdgBDU5TFxfXjBpGUYivQP8MiSA5YmXHZGF", - "poolTokenMint": "7cuu94swKL5PtFQohKMAzyd1mjj65rgMW3GzLY31HCnK", - "poolTokenDecimals": 6, - "feeAccount": "AsR18ERwBhmTkjNpav9NDWdeUzvmDH2TXCwfy2kinat", - "tokenIds": [ - "GENEtH5amGSi8kHAtQoezp1XEXwZJ8vcuePYnXdKrMYz", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "GENEtH5amGSi8kHAtQoezp1XEXwZJ8vcuePYnXdKrMYz": { - "tag": "GENE", - "name": "Genopets", - "mint": "GENEtH5amGSi8kHAtQoezp1XEXwZJ8vcuePYnXdKrMYz", - "scale": 9, - "addr": "LiM9qAQi7ud4fCkAcGcJJzmY47od7vzzeqKBejATbJm" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "APQyCmCvyVFreK2JjFHinmja24jTHdwm4umNJo67Nu2v" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "CMFI_USDC", - "address": "AaJERSYSMtWxhRqZzBZ9JFr1gJkfSPgPEd3mBDT2AknQ", - "nonce": 255, - "authority": "ERMNbmKrBKk3e8ZBbVWNUTkrqamZYxnRFXvgsPUSLT5j", - "poolTokenMint": "85krvT9DxdYgoFLQDHTAGdvtNuLdAsc4xE5FkVLpN2aR", - "poolTokenDecimals": 6, - "feeAccount": "3HXU5ABkghqJ3iMEGWsGe88kvZtiEyDJ24ihgFTytRNx", - "tokenIds": [ - "5Wsd311hY8NXQhkt9cWHwTnqafk7BGEbLu8Py3DSnPAr", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "5Wsd311hY8NXQhkt9cWHwTnqafk7BGEbLu8Py3DSnPAr": { - "tag": "CMFI", - "name": "Compendium.Fi", - "mint": "5Wsd311hY8NXQhkt9cWHwTnqafk7BGEbLu8Py3DSnPAr", - "scale": 6, - "addr": "HEqNExFgmyZ4Es53pL2bfBi5pKcZwGzbvwm1UknYLD9s" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "GbK7B7ZGQNZYrEhADC8aV5HdPhYgMZ35f6c8Decie224" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "acCELO_USDC", - "address": "H2bkwBwizcotpWHbruYFKXfHvh29hhoZn52qHq2YZumW", - "nonce": 254, - "authority": "E812K73QyqSsGBeU3MLodqVs3gCKJjka4p4gP34hXtns", - "poolTokenMint": "HVLyX8mD8YvKgZJ4oB6rXJiCYMLpHKwB6iCiCjE1XwdT", - "poolTokenDecimals": 6, - "feeAccount": "35HW4HcFDzVnVsxBhPKptYfwX3HyJWEosv5T9sdBSu8t", - "tokenIds": [ - "GNCjk3FmPPgZTkbQRSxr6nCvLtYMbXKMnRxg8BgJs62e", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "GNCjk3FmPPgZTkbQRSxr6nCvLtYMbXKMnRxg8BgJs62e": { - "tag": "CELO", - "name": "Celo", - "mint": "GNCjk3FmPPgZTkbQRSxr6nCvLtYMbXKMnRxg8BgJs62e", - "scale": 9, - "addr": "H6tFXr3BnF3r21Sv2ykLSbiE7wLxWpDcXroyxBReoXou" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "GnKnjXsmZKVhduVyLiR9Ngsxwo8spfxtruiPtqDqHLNJ" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "afFTM_USDC", - "address": "4RCU8SoBzvYysNaQBAFpQMmt7LPQgxbto9uiuRjAJPpq", - "nonce": 255, - "authority": "HC6aGC7RsgVGonWs1MVy5Qit5R5ruEXZmeywpFwSCmdY", - "poolTokenMint": "Gpzd833qSmv3kXpQmxEaqkrZTXZaRjhNAoqhf61qAhTG", - "poolTokenDecimals": 6, - "feeAccount": "2cA9XLcSFJ9jgnYViJr5JtnhSpGNrPhebS4RaGm7DHmu", - "tokenIds": [ - "EsPKhGTMf3bGoy4Qm7pCv3UCcWqAmbC1UGHBTDxRjjD4", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "EsPKhGTMf3bGoy4Qm7pCv3UCcWqAmbC1UGHBTDxRjjD4": { - "tag": "FTM", - "name": "Fantom", - "mint": "EsPKhGTMf3bGoy4Qm7pCv3UCcWqAmbC1UGHBTDxRjjD4", - "scale": 9, - "addr": "EULHGNmuJWcRHm5Xen9CiG4uqVZoemLorLvAQ7vR9vCi" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "71rJZyRkxxupdqZeLrNQnHjus11C1yEVwsrKgQax6TSx" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "CELO_USDC", - "address": "H2bkwBwizcotpWHbruYFKXfHvh29hhoZn52qHq2YZumW", - "nonce": 254, - "authority": "E812K73QyqSsGBeU3MLodqVs3gCKJjka4p4gP34hXtns", - "poolTokenMint": "HVLyX8mD8YvKgZJ4oB6rXJiCYMLpHKwB6iCiCjE1XwdT", - "poolTokenDecimals": 6, - "feeAccount": "35HW4HcFDzVnVsxBhPKptYfwX3HyJWEosv5T9sdBSu8t", - "tokenIds": [ - "GNCjk3FmPPgZTkbQRSxr6nCvLtYMbXKMnRxg8BgJs62e", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "GNCjk3FmPPgZTkbQRSxr6nCvLtYMbXKMnRxg8BgJs62e": { - "tag": "CELO", - "name": "Celo", - "mint": "GNCjk3FmPPgZTkbQRSxr6nCvLtYMbXKMnRxg8BgJs62e", - "scale": 9, - "addr": "H6tFXr3BnF3r21Sv2ykLSbiE7wLxWpDcXroyxBReoXou" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "GnKnjXsmZKVhduVyLiR9Ngsxwo8spfxtruiPtqDqHLNJ" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "FTM_USDC", - "address": "4RCU8SoBzvYysNaQBAFpQMmt7LPQgxbto9uiuRjAJPpq", - "nonce": 255, - "authority": "HC6aGC7RsgVGonWs1MVy5Qit5R5ruEXZmeywpFwSCmdY", - "poolTokenMint": "Gpzd833qSmv3kXpQmxEaqkrZTXZaRjhNAoqhf61qAhTG", - "poolTokenDecimals": 6, - "feeAccount": "2cA9XLcSFJ9jgnYViJr5JtnhSpGNrPhebS4RaGm7DHmu", - "tokenIds": [ - "EsPKhGTMf3bGoy4Qm7pCv3UCcWqAmbC1UGHBTDxRjjD4", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "EsPKhGTMf3bGoy4Qm7pCv3UCcWqAmbC1UGHBTDxRjjD4": { - "tag": "FTM", - "name": "Fantom", - "mint": "EsPKhGTMf3bGoy4Qm7pCv3UCcWqAmbC1UGHBTDxRjjD4", - "scale": 9, - "addr": "EULHGNmuJWcRHm5Xen9CiG4uqVZoemLorLvAQ7vR9vCi" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "71rJZyRkxxupdqZeLrNQnHjus11C1yEVwsrKgQax6TSx" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "BTC_ORCA", - "address": "CqXRyZ23dFwdbMLGEQLhQQRJrzkFB3wBsuH92rp7d3yw", - "nonce": 255, - "authority": "Fixb6XBzoSRJ4iCkHNX3xbr61yWXUh6SYyu5Jweg36VF", - "poolTokenMint": "DFpLFcQZqDKykyDePgip4r6MExVmBKWqTa12ezq6qxUY", - "poolTokenDecimals": 6, - "feeAccount": "47pxL1vidAiARAF45SoVnpqSet8EPckF9pB4d9zT1S3N", - "tokenIds": [ - "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE" - ], - "tokens": { - "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E": { - "tag": "BTC", - "name": "Bitcoin", - "mint": "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "scale": 6, - "addr": "8dbqoSTALCCshdKXX8Nb6AskytydXtHLyPoqu9Nb2ig3" - }, - "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE": { - "tag": "ORCA", - "name": "Orca", - "mint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "scale": 6, - "addr": "7UAHjQQjYBrSKdtgbJK1SaUVgmBxcmMJKshvEiEhLheP" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "HBB_USDC", - "address": "Fpwa7a1r7kjax1nW25TVP3uiQc7XH9dv9n9UXMJRSTEx", - "nonce": 254, - "authority": "9odZioXkQTCZERzQXbDTfirMfbP9FtKqsP9LvHgm6wJr", - "poolTokenMint": "cL5WhffCYFRLM4We8VS2W684kM4pHyuvEDwp8Ddw48k", - "poolTokenDecimals": 6, - "feeAccount": "3nyqxtRPnYrwEHneWgbN1197aZoEaemnSNQ7rgJLv8hS", - "tokenIds": [ - "HBB111SCo9jkCejsZfz8Ec8nH7T6THF8KEKSnvwT6XK6", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "HBB111SCo9jkCejsZfz8Ec8nH7T6THF8KEKSnvwT6XK6": { - "tag": "HBB", - "name": "Hubble", - "mint": "HBB111SCo9jkCejsZfz8Ec8nH7T6THF8KEKSnvwT6XK6", - "scale": 6, - "addr": "2vq1vt98xBPUmvbTC5nH4GtsjJVeA64kwv6CZc7xSAf6" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "B7f4A1Pp6RCjWYv5Lsrf4MecmZQDMekXh4MFQasCQuRB" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "HBB_SOL", - "address": "2aCJ1VTwfvLej1PJJAmiVCzuLGtjQ5bEo9DYkbwwe1C6", - "nonce": 255, - "authority": "8GRweHBrpXfeYpmryfkvEsW3DmoJKGDQLpcVfeNUqn8x", - "poolTokenMint": "FkKzu2HeMJZf4oHwoYPxLGVy3net5Jq8HAfnA5VqETgk", - "poolTokenDecimals": 6, - "feeAccount": "2Y1xXr1j6xg5r5Qz8LDqnU7N8T4GGu3Ju4AHGsfU2nXS", - "tokenIds": [ - "HBB111SCo9jkCejsZfz8Ec8nH7T6THF8KEKSnvwT6XK6", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "HBB111SCo9jkCejsZfz8Ec8nH7T6THF8KEKSnvwT6XK6": { - "tag": "HBB", - "name": "Hubble", - "mint": "HBB111SCo9jkCejsZfz8Ec8nH7T6THF8KEKSnvwT6XK6", - "scale": 6, - "addr": "5k1Nj2TvG51p7s2ambWpmX6FraiSchoYS1wJgVw5f9Af" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "2s2vbHk4XzKQ9SQdPRyirY8JmBemhZ67EBx7xgF6tzq5" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "SB_USDC", - "address": "GPxcR4ci8RbLh4bVPi88mKwTEDeVxEKs3nBkKayghuuL", - "nonce": 255, - "authority": "6poTLvmbRU9FAJAnM5RmXMRTVFf2xWRKooCkStZQJf6U", - "poolTokenMint": "2Reqt4Sw9xNY8BoJ3EZLpFu5yVgNxFrbw8M3KiJpPn6o", - "poolTokenDecimals": 6, - "feeAccount": "EVRpMUxUGZGH15SB1hGhLzzz15XNopLZjSuTZSpcwMmt", - "tokenIds": [ - "SuperbZyz7TsSdSoFAZ6RYHfAWe9NmjXBLVQpS8hqdx", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "SuperbZyz7TsSdSoFAZ6RYHfAWe9NmjXBLVQpS8hqdx": { - "tag": "SB", - "name": "SuperBonds", - "mint": "SuperbZyz7TsSdSoFAZ6RYHfAWe9NmjXBLVQpS8hqdx", - "scale": 6, - "addr": "EoV9ub5aojyBFdYGhPQPQ6cDeesgsENrNYGN6L8CB6Nh" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "7kRmDjSorwKqqLAFupgGW8fEp6hywkt2bntw2gCrV5Sh" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "stSOL_USDT", - "address": "EacW6utfAJk6z5QCbyqjJHdTN2TH5UFu9K5dh3DmhsLV", - "nonce": 254, - "authority": "CUQbwmFXySWXpBgycGTTj3gQNY8AnjD4DJRjgLeG1bVK", - "poolTokenMint": "4ni1nho89cDKAQ9ddbNQA9ieLYpzvJVmJpuogu5Ct5ur", - "poolTokenDecimals": 6, - "feeAccount": "H4VgN76Mri6ctLCkf6fnyfae9fCDC51nZVPa1oPjq1Da", - "tokenIds": [ - "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" - ], - "tokens": { - "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj": { - "tag": "stSOL", - "name": "Lido Staked SOL", - "mint": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "scale": 9, - "addr": "BAMiBNk9j6Z9LLdZzzGScHDFQas58uLqW4GGX4ndq7K6" - }, - "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB": { - "tag": "USDT", - "name": "Tether USD", - "mint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "scale": 6, - "addr": "Ajf4bxNoKCyFVfV35sRTgGwZK1dfJJJVXgNFs7ncC5EF" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "SEEDED_USDC", - "address": "3fyCss3Y9ATNnTSsN7VCasEb4H5SpSuN7VEoJnNWZU3x", - "nonce": 251, - "authority": "89TxEkGNHFcniBm5pXo8Jq6s1ZaBUKCRqgYS3eAr3jJ7", - "poolTokenMint": "H7gyTmNCDXkD8MGMqnxqoD8ANszjcju4tjT6ERZ5dakf", - "poolTokenDecimals": 6, - "feeAccount": "2ZTqrZTNumBMdyQm3cAiREHozzQp18KhEuGWiUVwJMRm", - "tokenIds": [ - "seedEDBqu63tJ7PFqvcbwvThrYUkQeqT6NLf81kLibs", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "seedEDBqu63tJ7PFqvcbwvThrYUkQeqT6NLf81kLibs": { - "tag": "SEEDED", - "name": "Seeded Network", - "mint": "seedEDBqu63tJ7PFqvcbwvThrYUkQeqT6NLf81kLibs", - "scale": 9, - "addr": "Dn9LiTqcRiyxipCqvTEyT3ZwbWtf69bUcHQLWG89jpJa" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "Aq5xPmh3cZoyLN3KzVcAK8osAU7oAjo1k6qdw6gd5ovi" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "AUDIO_USDC", - "address": "2arG3AznFJbLknAQUqk44PgeABZDHpBfcRsPmPWjjBPY", - "nonce": 254, - "authority": "ETCzw3Vp2n4aas7rFtxb554h67JPeyDBr7DKcHUgSAxp", - "poolTokenMint": "3hksYA17VxgiKSeihjnZkBbjc2CTbEBfvDCYgQhojTo5", - "poolTokenDecimals": 6, - "feeAccount": "H1Rcj6jAeV9v5QsJTo957tcWgYzve4PZEuSHGNmX1UFv", - "tokenIds": [ - "9LzCMqDgTKYz9Drzqnpgee3SGa89up3a247ypMj2xrqM", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "9LzCMqDgTKYz9Drzqnpgee3SGa89up3a247ypMj2xrqM": { - "tag": "AUDIO", - "name": "Audius (Wormhole)", - "mint": "9LzCMqDgTKYz9Drzqnpgee3SGa89up3a247ypMj2xrqM", - "scale": 8, - "addr": "FfpKRggDra1uSskyzAm6f4EXFhxw6ij8BkDwiWTs126x" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "ACBf9ksELg2buAFnDTJL9WnT5kZRcFN1Bvarox9JZVbq" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "MMA_USDC", - "address": "3HJ9QwRNsdHj3xaTvrzYyvvsY1gd23N8qGiSHaytKLLB", - "nonce": 254, - "authority": "58KyKR1fHXP2ewDC93TdRxPZ7W8FNYkLc53VH9XP32hD", - "poolTokenMint": "AaZRnJAnDyJyPD9uPJpJ8bzBGDCEi6jtBpUf92xErWPp", - "poolTokenDecimals": 6, - "feeAccount": "AfesEXaDzs4mnPQJyqNHzpZ8DMBpuEPtmi1aL5xwRjVm", - "tokenIds": [ - "MMAx26JtJgSWv6yH48nEHCGZcVvRbf9Lt9ALa7jSipe", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "MMAx26JtJgSWv6yH48nEHCGZcVvRbf9Lt9ALa7jSipe": { - "tag": "MMA", - "name": "MMA Gaming", - "mint": "MMAx26JtJgSWv6yH48nEHCGZcVvRbf9Lt9ALa7jSipe", - "scale": 9, - "addr": "BzccyLPYsbhhWjHnRLUn7Fpkao9reYRdjA8wkp7iY6re" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "6uJF6gMpCxUYvmQ8hmaz44MRyRYq5ykpsx5GYABbUK5A" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "ONESOL_SOL", - "address": "8CJhJomcLYoVw6pAQdNWPJ3yDXkS55y2gAxJ9uReuXEz", - "nonce": 254, - "authority": "9DV4t1XqqNiXLCdHfaEwAbVaT5Mth3z8VjYS6CG8CPQS", - "poolTokenMint": "9wPhuYapychVDSxmXqCZxy2Ka8Lmav4SHM72si8bfraV", - "poolTokenDecimals": 6, - "feeAccount": "6yqvsmFJrMhSv31Ne6yY8f4y2ZJvMMCwTjYTxhq1eKS5", - "tokenIds": [ - "4ThReWAbAVZjNVgs5Ui9Pk3cZ5TYaD9u6Y89fp6EFzoF", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "4ThReWAbAVZjNVgs5Ui9Pk3cZ5TYaD9u6Y89fp6EFzoF": { - "tag": "1SOL", - "name": "1Sol", - "mint": "4ThReWAbAVZjNVgs5Ui9Pk3cZ5TYaD9u6Y89fp6EFzoF", - "scale": 8, - "addr": "532m3b4aSmWsrn4RfM9ByBRLJocdcHMwiscjADQYNjXG" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "2qu6tc58av5AGfrrBPdHxK2Cyi5CsDhjaZ8x8yw8UA1w" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "PUFF_SOL", - "address": "GrSE1LoQBr3p9y7HQxV8h5vc8fH4xkT4a6Nysckbu8zt", - "nonce": 253, - "authority": "79gfyi1Ct3m8RKkF618yxnA7w5JQV1NWhkMs6dXACgGq", - "poolTokenMint": "Eho8h1BcoG5QWU7X9FzJafw5ErKUXtR2LobAJJZfWff4", - "poolTokenDecimals": 6, - "feeAccount": "44XxHHYz2642Bc4sHdDuV2aEGbziugqN5tKnmBBBwPyA", - "tokenIds": [ - "G9tt98aYSznRk7jWsfuz9FnTdokxS6Brohdo9hSmjTRB", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "G9tt98aYSznRk7jWsfuz9FnTdokxS6Brohdo9hSmjTRB": { - "tag": "PUFF", - "name": "PUFF", - "mint": "G9tt98aYSznRk7jWsfuz9FnTdokxS6Brohdo9hSmjTRB", - "scale": 9, - "addr": "HYszSkhsPPNSj6Q5hRudc94kawCgUNeQ1DqrxJxtoxsK" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "AKJUQjqAHTw5rNYYv9Rvxxe23mwdNaqzt7pdriJy92sw" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "SAO_USDC", - "address": "BWCT76eQ8jtrKkMm234ZY1QEXSfZYTrzHyXaE3DxeQfd", - "nonce": 255, - "authority": "7TXfpFGVASvgkLkuTSsqQJQTXypa31zqcHmPZNMaAJu", - "poolTokenMint": "4iyU77yZbg8iD344vbwruAuDAf9i1EVV3FhZJDnWStBE", - "poolTokenDecimals": 6, - "feeAccount": "BVSJLE6RZ2cvfXPjSZcj7fK1HLra2wtcC4jLCZAh6gFX", - "tokenIds": [ - "2HeykdKjzHKGm2LKHw8pDYwjKPiFEoXAz74dirhUgQvq", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "2HeykdKjzHKGm2LKHw8pDYwjKPiFEoXAz74dirhUgQvq": { - "tag": "SAO", - "name": "Sator", - "mint": "2HeykdKjzHKGm2LKHw8pDYwjKPiFEoXAz74dirhUgQvq", - "scale": 9, - "addr": "8MNhNFCU366Y3dq3HRk5nKuKZuQLY3kffMZekadM2R8q" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "6qnLaADqFjtGsMsHjScFVmpVVNBbqaGNoBwBFy5BVRr8" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "sRLY_SOL", - "address": "Df7DkQRXEpPM5basbYHi45268hmR8m7YrtraPdGgj6R6", - "nonce": 255, - "authority": "9DaRQeoEx3EjXYxhpZrcJ6no3bcAkfm9toWbngcAqSCB", - "poolTokenMint": "3dXdXg5HPyZ73GFC9LkSn3thdJUGeXWB8iSTHs5UcqiH", - "poolTokenDecimals": 6, - "feeAccount": "B3Ao2fEX2isX8UQ99EuPz3BDzUfQTPeYS7KVvbCnkrXm", - "tokenIds": [ - "RLYv2ubRMDLcGG2UyvPmnPmkfuQTsMbg4Jtygc7dmnq", - "So11111111111111111111111111111111111111112" - ], - "tokens": { - "RLYv2ubRMDLcGG2UyvPmnPmkfuQTsMbg4Jtygc7dmnq": { - "tag": "sRLY", - "name": "Rally (Solana)", - "mint": "RLYv2ubRMDLcGG2UyvPmnPmkfuQTsMbg4Jtygc7dmnq", - "scale": 9, - "addr": "AJzDsY4wnv8nWSWoBimY6hWJpWC54oEgmfbV7YGXsLww" - }, - "So11111111111111111111111111111111111111112": { - "tag": "SOL", - "name": "Solana", - "mint": "So11111111111111111111111111111111111111112", - "scale": 9, - "addr": "qytd7KfK3pFVWog53xUVE8dqD1sBxa1H13VnF6ADGSd" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "ZBC_USDC", - "address": "J4Xvy9twDDWqqwyfX6nrc2QFJeMJ6HD9kbAmcPhfYmFP", - "nonce": 255, - "authority": "9Ssocd3xbxm3xCKwz1g8d41rS6iWbmGyo25ZdYZHbDCp", - "poolTokenMint": "2LYgm6nGXmSSjfoEriPuYeGoNiWNxUs7n3rnTbDWN5c7", - "poolTokenDecimals": 6, - "feeAccount": "8H1bUAywEerLCYxLVDjM5EqXYXtoW5gbR1MoD1LrrnMV", - "tokenIds": [ - "zebeczgi5fSEtbpfQKVZKCJ3WgYXxjkMUkNNx7fLKAF", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "zebeczgi5fSEtbpfQKVZKCJ3WgYXxjkMUkNNx7fLKAF": { - "tag": "ZBC", - "name": "Zebec Protocol", - "mint": "zebeczgi5fSEtbpfQKVZKCJ3WgYXxjkMUkNNx7fLKAF", - "scale": 9, - "addr": "8AcanN7p8KHfLxKBBMKuJUqqX2uUPz3mkp3iaNHHaZfZ" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "FwqAxdo6s5EtyVXqqU7sj3Q9n3eLuUkF2D4584MDoWLW" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - }, - { - "name": "GMT_USDC", - "address": "46GcZFgznxUf6TpoCqJqzMpgMbbJPCAwNn8GThSt9qjC", - "nonce": 255, - "authority": "3HGGVGTXbqT49PG3L8JQYH4jCeP5CNBG6CpJniZ434an", - "poolTokenMint": "CFxQF5kNAtbbDj298Xr47Sf4mkSyuzWpRH97hrdQ6kxi", - "poolTokenDecimals": 6, - "feeAccount": "3pBqsnahNsm6p14FFjtMCGfD1VCQNcUEdNEeSwTGfE2q", - "tokenIds": [ - "7i5KKsX2weiTkry7jA4ZwSuXGhs5eJBEjY8vVxR4pfRx", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "tokens": { - "7i5KKsX2weiTkry7jA4ZwSuXGhs5eJBEjY8vVxR4pfRx": { - "tag": "GMT", - "name": "STEPN", - "mint": "7i5KKsX2weiTkry7jA4ZwSuXGhs5eJBEjY8vVxR4pfRx", - "scale": 9, - "addr": "BTpvbpTArnekGgbXRqjfSvp7gENtHXvZCAwuUKQNYMeN" - }, - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { - "tag": "USDC", - "name": "USD Coin", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "scale": 6, - "addr": "DdBTJuiAXQQ7gLVXBXNPbVEG8g1avRxiJXhH5LhBytYW" - } - }, - "curveType": 0, - "feeStructure": { - "traderFee": { - "numerator": "19", - "denominator": "2710" - }, - "ownerFee": { - "numerator": "05", - "denominator": "2710" - } - } - } - ] -} diff --git a/farms/farm-ctrl/metadata/pools/raydium/get_pools.sh b/farms/farm-ctrl/metadata/pools/raydium/get_pools.sh deleted file mode 100755 index e963f24d76d..00000000000 --- a/farms/farm-ctrl/metadata/pools/raydium/get_pools.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -url="https://api.raydium.io/v2/sdk/liquidity/mainnet.json" - -if hash wget 2>/dev/null; then - wget_or_curl="wget -O pools.json $url" -elif hash curl 2>/dev/null; then - wget_or_curl="curl -o pools.json -L $url" -else - echo "Error: Neither curl nor wget were found" >&2 - return 1 -fi - -exec $wget_or_curl \ No newline at end of file diff --git a/farms/farm-ctrl/metadata/pools/raydium/pools.json b/farms/farm-ctrl/metadata/pools/raydium/pools.json deleted file mode 100644 index a408bdf9a2b..00000000000 --- a/farms/farm-ctrl/metadata/pools/raydium/pools.json +++ /dev/null @@ -1,43239 +0,0 @@ -{ - "name": "Raydium Mainnet Liquidity Pools", - "timestamp": "2022-06-10T07:38:13+0000", - "version": { "major": 1, "minor": 0, "patch": 0 }, - "official": [ - { - "id": "13uCPybNakXHGVd2DDVB7o2uwXuf9GqPFkvJMVgKy6UJ", - "baseMint": "HfYFjMKNZygfMC8LsQ8LtpPsPxEJoXJx4M6tqi75Hajo", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HjR23bxn2gtRDB2P1Tm3DLepAPPZgazsWJpLG9wqjnYR", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "E6wZo9uiPf156g9jG5ZWX3s23hM3jcicHiNjMg9NTvo3", - "targetOrders": "HnX2KEKgXfPbHoFCSfZydDDYm51DwdkXcibWP9o6sP9Z", - "baseVault": "2rgPoyabSPeYoMiACSp9UcqG9WEBhDdXDmGQ4XRoBeo7", - "quoteVault": "CzynpjFdoLekUGMPRNT6un5ieg6YQyT4WmJFKngoZHJY", - "withdrawQueue": "AwYLatzaiaRG1JBQYevogqG6VhX3xfF93FHt4T5FtQgy", - "lpVault": "4ACwuir8yUrYQLmFDX6Lsq8BozEizKCVdRduYuUyR4zr", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CDYafmdHXtfZadhuXYiR7QaqmK9Ffgk2TA8otUWj9SWz", - "marketAuthority": "GiVPfzeddXAbneSZWZ1XrNAZvB7XhNFbJtck7skN6xBE", - "marketBaseVault": "2CAabztdescZCLyTmUAvRUxi3CZDgtFPx4WFrUmXEz8H", - "marketQuoteVault": "nkMvRrq8ove9AMBJ65jPSsnd3RS7kvTTh5L3jN93uNu", - "marketBids": "A3LCjzPEE9reQhKRED1TBGBG9ksL45rhLxh4fRzThWXJ", - "marketAsks": "53krdJQgxmTaJgBPQ1Kc7SKLEEosvYs2uDYodQd9Lcqf", - "marketEventQueue": "224GEWPVsY5fjn3JqqkxC7jW2oasosipvWSZCFrpbiDm" - }, - { - "id": "21r2zeCacmm5YvbGoPZh9ZoGREuodhcbQHaP5tZmzY14", - "baseMint": "AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3", - "quoteMint": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "lpMint": "AsDuPg9MgPtt3jfoyctUCUgsvwqAN6RZPftqoeiPDefM", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CimwwQH1h2MKbFbodHHByMq8MreFuJznMGVXxYKMpyiB", - "targetOrders": "Fewh6hVTfeduAnbqwNuUx2Cu7uTyJTALP76hjpWCvRoV", - "baseVault": "Atc9Prscs9RLmDEpsCQzFgCqzkscAtTck5ZSZGV9s7hE", - "quoteVault": "31ZJVJMap4WpPbzaScPwg5MGRUDjatP2kXVsSgf12yVZ", - "withdrawQueue": "yAZD46BC1Bti2X5FEjveobueuyevi7jFV5ew6DH8Thz", - "lpVault": "7Ro1o6Vbh3Ech2zeozNDicRP1gZfHAWcRnxvrzdnLfYi", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CDvQqnMrt9rmjAxGGE6GTPUdzLpEhgNuNZ1tWAvPsF3W", - "marketAuthority": "CAAeuJAgnP368num8bCv6VMWCqMZ4pTANCcGTAMAJtm2", - "marketBaseVault": "8qTUSDRxJ65sGKEUu746xJdCquoP38AqKsQo6ZruSSBk", - "marketQuoteVault": "ALe3hiZR35cCjcrzbJi1vKEhNftdVQjwkt4S8rbPZogq", - "marketBids": "9NfJWy5QNqRDGmNARphS9kJyYtR6nkkWcFyJRLbgECtd", - "marketAsks": "9VEVBJZHVv6N2MzAzNLiCwN2MAdt5GDScCtpE4zkzDFW", - "marketEventQueue": "CbnLQT9Jwo3RHpWBnsPisAybSN4CBuwj4fcF1S9qJchV" - }, - { - "id": "2bnZ1edbvK3CK3LTNZ5jH9anvXYCmzPR4W2HQ6Ngsv5K", - "baseMint": "ATLASXmbPQxBUYbxPsV97usA3fPQYEqzQBUHgiFCUsXx", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9shGU9f1EsxAbiR567MYZ78WUiS6ZNCYbHe53WUULQ7n", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EzYB1U93e8E1KGJdUzmnwgNBFMP9E1XAuyosmiPGLAvD", - "targetOrders": "DVxJDo3E9zfGgvSkC2DYS5fsv5AyXA7gXpcs1fHFrP3y", - "baseVault": "FpFV46UVvRtcrRvYtKYgJpJtP1tZkvssjhrLUfoj8Cvo", - "quoteVault": "GzwX68f1ZF4dKnAJ58RdET8sPvvnYktbDEHmjoGw7Umk", - "withdrawQueue": "26SuCukyzbYo5kzeufaSoMjRPStAwqfVzTXb4QGynTit", - "lpVault": "HcoA8ucDBjEUVMjvURaS9CZgdEUbq8jRieGabq48mCL8", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Di66GTLsV64JgCCYGVcY21RZ173BHkjJVgPyezNN7P1K", - "marketAuthority": "FiyZW6n5VE64Yubn2PUFAxbmB2FZXhYce74LzJUhqSZg", - "marketBaseVault": "22a8dDQwHmmnW4M4WuSXHC9NdQAufZ2V8at3EtPzBqFj", - "marketQuoteVault": "5Wu76Qx7EoiR79zVVV49cZDYZ5csZaKFiHKYtCjF9FNU", - "marketBids": "2UabAccF1AFPcNqv9D46JgyGnErnaYAJuCwyaT5dCkHc", - "marketAsks": "9umNLTbks7S51TEB8XF4jeCxwyq3qmdHrFDMFB8cT1gv", - "marketEventQueue": "EYU32k5waRUxF521k2KFSuhEj11HQvg4MbQ9tFXuixLi" - }, - { - "id": "2dRNngAm729NzLbb1pzgHtfHvPqR4XHFmFyYK78EfEeX", - "baseMint": "EchesyfXePKdLtoiZSL8pBe8Myagyy8ZRqsACNCFGnvp", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "DsBuznXRTmzvEdb36Dx3aVLVo1XmH7r1PRZUFugLPTFv", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DUVSNpoCNyGDP9ef9gJC5Dg53khxTyM1pQrKVetmaW8R", - "targetOrders": "89HcsFvCQaUdorVF712EhNhecvVM7Dk6XAdPbaykB3q2", - "baseVault": "6YeEo7ZTRHotXd89JTBJKRXERBjv3N3ofgsgJ4FoAa39", - "quoteVault": "DDNURcWy3CU3CpkCnDoGXwQAeCg1mp2CC8WqvwHp5Fdt", - "withdrawQueue": "H8gZ2f4hp6LfaszDN5uHAeDwZ1qJ4M4s2A59i7nMFFkN", - "lpVault": "Bp7LNZH44vecbv69kY35bjmsTjboGbEKy62p7iRT8az", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9wH4Krv8Vim3op3JAu5NGZQdGxU8HLGAHZh3K77CemxC", - "marketAuthority": "F7VdEoWQGmdFK35SD21wAbDWtnkVpcrxM3DPVnmG8Q3i", - "marketBaseVault": "A2SMhqA1kMTudVeAeWdzCaYYeG6Dts19iEZd4ZQQAcUm", - "marketQuoteVault": "GhpccNwfein8qP6uhWnP4vuRva1iLivuQQHUTM7tW58r", - "marketBids": "E2FEkqPVcQZgRaE7KabcHGbpNkpycnvVZMan2MPNGKeM", - "marketAsks": "5TXqn1N2kpCWWV4AcXtFYJw8WqLrXP62qenxiSfhxJiD", - "marketEventQueue": "58qMcacA2Qk4Tc4Rut3Lnao91JvvWJJ26f5kojKnMRen" - }, - { - "id": "2EXiumdi14E9b8Fy62QcA5Uh6WdHS2b38wtSxp72Mibj", - "baseMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "As3EGgLtUVpdNpE6WCKauyNRrCCwcQ57trWQ3wyRXDa6", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 5, - "programId": "5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h", - "authority": "3uaZBfHPfmpAHW7dsimC1SnyR61X4bJqQZKWmRSCXJxv", - "openOrders": "4zbGjjRx8bmZjynJg2KnkJ54VAk1crcrYsGMy79EXK1P", - "targetOrders": "AYf5abBGrwjz2n2gGP4YG91hJer22zakrizrRhddTehS", - "baseVault": "5XkWQL9FJL4qEvL8c3zCzzWnMGzerM3jbGuuyRprsEgG", - "quoteVault": "jfrmNrBtxnX1FH36ATeiaXnpA4ppQcKtv7EfrgMsgLJ", - "withdrawQueue": "11111111111111111111111111111111", - "lpVault": "11111111111111111111111111111111", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "marketAuthority": "FGBvMAu88q9d1Csz7ZECB5a2gbWwp6qicNxN2Mo7QhWG", - "marketBaseVault": "H61Y7xVnbWVXrQQx3EojTEqf3ogKVY5GfGjEn5ewyX7B", - "marketQuoteVault": "9FLih4qwFMjdqRAGmHeCxa64CgjP1GtcgKJgHHgz44ar", - "marketBids": "37m9QdvxmKRdjm3KKV2AjTiGcXMfWHQpVFnmhtb289yo", - "marketAsks": "AQKXXC29ybqL8DLeAVNt3ebpwMv8Sb4csberrP6Hz6o5", - "marketEventQueue": "9MgPMkdEHFX7DZaitSh6Crya3kCCr1As6JC75bm3mjuC", - "modelDataAccount": "CDSr3ssLcRB6XYPJwAfFt18MZvEZp4LjHcvzBVZ45duo" - }, - { - "id": "2kPA9XUuHUifcCYTnjSuN7ZrC3ma8EKPrtzUhC86zj3m", - "baseMint": "MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey", - "quoteMint": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "lpMint": "4bh8XCzTHSbqbWN8o1Jn4ueBdz1LvJFoEasN6K6CQ8Ny", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "G3qeShDT2w3Y9XnJbk5TZsx1qbxkBLFmRsnNVLMnkNZb", - "targetOrders": "DfMpzNeT4XHs2xtN74j5q94QfqPSJbng5BgGyyyChsVm", - "baseVault": "F1zwWuPfYLZfLykDYUqu43A74TUsv8mHuWL6BUrwVhL7", - "quoteVault": "TuT7ftAgCQGsETei4Q4nMBwp2QLcDwKnixAEgFSBuao", - "withdrawQueue": "5FoP78mNninxP5VbSHN3LfsBBbqMNqiucANGQungGJLV", - "lpVault": "2UbzfMCHjSERpMo9C3BAq5NUhVF9sx39ruJ1zu8Gf4Lu", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AVxdeGgihchiKrhWne5xyUJj7bV2ohACkQFXMAtpMetx", - "marketAuthority": "6Ysd8CE6KwC7KQYpPD9Ax8B77z3bWRnHt1SVrBM8AYC9", - "marketBaseVault": "aj1igzDQNRg18h9yFGvNqMPBfCGGWLDvKDp2NdYh92C", - "marketQuoteVault": "3QjiyDAny7ZrwPohN8TecXL4jBwGWoSUe7hzTiX35Pza", - "marketBids": "9YBjtad6ZxR7hxNXyTjRRPnPgS7geiBMHbBp4BqHsgV2", - "marketAsks": "8UZpvreCr8bprUwstHMPb1pe5jQY82N9fJ1XLa3oKMXg", - "marketEventQueue": "3eeXmsg8byQEC6Q18NE7MSgSbnAJkxz8KNPbW2zfKyfY" - }, - { - "id": "2PfKnjEfoUoVDbDS1YwvZ8HuPGBCpN831mnTuqTAJZjH", - "baseMint": "4SZjjNABoqhbd4hnapbvoEPEqT8mnNkfbEoAwALf1V8t", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5Gba1k3fU7Vh7UtAiBmie9vhQNNq1JfEwgn1DPGZ7NKQ", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ECG1LTHELj27wyKVz4DPCKdFB8mthqEwbnPeuUzkgz2H", - "targetOrders": "H4vuXiWxuKLec3TLrZk3QgJMsLH4Y2L6E9LosnefFMyR", - "baseVault": "B1SCcyk4AqQcn6RY7Qjqj8rE53DDZ7N2eiqtMNcmfZxa", - "quoteVault": "2HUjTaYw3mmU6kRA3ZfC4MGSzUhr2H6ZUQCWWdrfwUB6", - "withdrawQueue": "83z9iqzrGv3ZF1aQ14i4cfLGLJ2yH2uBByMQe2347EjB", - "lpVault": "BNfk8c5CYcA7Cyg6iRNTBRwhEuhKARLD8toBzdxtmRJt", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "KrGK6ZHyE7Nt35D7GqAKJYAYUPUysGtVBgTXsJuAxMT", - "marketAuthority": "5bXbwUkB14na4uBAjG2u3PKx9BMV182T68EjgFV6duuz", - "marketBaseVault": "2ZzE1FQixLYqw94htVYn99kSH1LE35De3d8XeWPnypte", - "marketQuoteVault": "8oVmJ6vT6kMfWyRETDjuo4nAZZZC3KSNZBjsHzEDQDLD", - "marketBids": "73yb9Y8cZfxX8KV96dMXVp5tTfu4FVjPc9LchtrzEdUu", - "marketAsks": "3sYKt1KYtB2Ycnf6jzNvnji8wUCWbsu9ZcA4DboiU1FH", - "marketEventQueue": "D6PsDqCb5BbAhXfaLA9AtYz8SHLCUtdQSmozu7T4JGJe" - }, - { - "id": "2T4LusNHwsT15p3yrPSSL7tYw2fucQoag4HkejT1wiYw", - "baseMint": "YAWtS7vWCSRPckx1agB6sKidVXiXiDUfehXdEUSRGKE", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BREhg1HCGk34wuUbh8CNzvE7Sj8FpiwdAVypKWHhZyYx", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7vYwREyvhGiCfjS78bNE3VDQSz4j1gvfa4NYJ7quiZG5", - "targetOrders": "EY4NCrDZAgnvDPuSVzZRaaWGNkaPEczTQ3F13oQVwup1", - "baseVault": "AruoX147o2RwMNXVJajZFnfdVAeF8PZc4PxRhn6CCzdz", - "quoteVault": "EAZ1pYH6QaVnQa5FjKApiNG6rgLZxqBf14PjESe9dLAy", - "withdrawQueue": "9hWFEDG7k98TUWDHQdEsN4sL17XCBnfe7qn3hdUj33WU", - "lpVault": "HSxp1453fiso6peygjTvVARw3gSsrtbBWMEKHT1yAfc9", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "XSiwhjR4nQ9CenYXFN162Uk3ZR2njXCv5cvCsquyePL", - "marketAuthority": "AaxRLM4qhcpZXAKjiYMNW9Xii215qiVbxEZysNM9nNfe", - "marketBaseVault": "4MLmfc8PByw1gHU6XfWswZ93Hz6x4t8RxLTmroBqtBh2", - "marketQuoteVault": "D65CQ5t7vCLWnW1AXQWfJgq2AT7JQwABsQk7zDMiPb6M", - "marketBids": "GP5XbF1kGeSQZD5t5dzNCAQnF5ePy4YysHj6jBJGqJ4A", - "marketAsks": "Hd6S1Toi4c93Y3666P9ayqHjx5VzkUAR2R3dShxEQ7YX", - "marketEventQueue": "ErYfT4r9rtoyUR5BczyXRpNfpDn5Q9Goh1P9T84AEXaD" - }, - { - "id": "2Tv6eMih3iqxHrLAWn372Nba4A8FT8AxFSbowBmmTuAd", - "baseMint": "FnKE9n6aGjQoNWRBZXy4RW6LZVao7qwBonUbiD7edUmZ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2xJGuLAivAR1WkARRA6zP1v4jaA9jV2Qis8JfMNvrVyZ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GNHftHYD7WRG5HYdyWjd9KsxjUgUALrLcSG2AZvv5ahU", - "targetOrders": "89weJGn5qci3QF1tPQC3P4B3xMbKqdgeXSHfiNxKvKCd", - "baseVault": "9ZQNgn9zAc9oLKST5yW9PNjCCqSfJVwnFpfgZnd88Xn1", - "quoteVault": "HLtqBqwgdbGdFfd5UZtKkvrdxLLcpaMnAJ5aZAzDjFdT", - "withdrawQueue": "4LybXzk5xxLPRsz8evCNtNXLc6Mydb5HCWyitHeDvCKT", - "lpVault": "5WKtEZL7Zst2QBKA5E9YCbKMPxTZNrErGB8TyGs3z9oD", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9cuBrXXSH9Uw51JB9odLqEyeF5RQSeRpcfXbEW2L8X6X", - "marketAuthority": "FBLtcfAXmm5PpJLLr95L5cjfgbpJiGHsWdBXDpC2TBQ2", - "marketBaseVault": "8DGcP5Z8M878mguFLohaK9jFrrShDCREF3qa7JhMfgib", - "marketQuoteVault": "CLS4WFje2PbV3MmV4v7CGxu3bNFqx2sYewq95rzGR8t8", - "marketBids": "EmqbfgZFSQxAeJRWKrrBVST4oLsq8aMt4WtcufPARcd7", - "marketAsks": "GZqx3xX1PjNpmw2qDGhiUSa6PsM5tWYY7cMmKzYFCCLD", - "marketEventQueue": "8w8JzuqcRUm9QAC3YWJm2mBCVjWDLXh8b7ktSouJKMUd" - }, - { - "id": "33dWwj33J3NUzoTmkMAUq1VdXZL89qezxkdaHdN88vK2", - "baseMint": "4wjPQJ6PrkC4dHhYghwJzGBVP78DkBzA2U3kHoFNBuhj", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GWpD3eTfhJB5KDCcnE85dBQrjAk2CsrgDF9b52R9CrjV", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "H4zMatEWC1cgzpJd4Ckw29M7FD6h6gpVYMs8ATkVYsee", - "targetOrders": "Gz9e8TUgQg2XwPvJs5CwijFyYgRL43LiB3CeWNTkkcsu", - "baseVault": "GGQU74M6ikrn8Cj7qywpmj6qdx2nKJLXGb34MbtPChoh", - "quoteVault": "DHoRYvCnFfL53zpq6ZbdHj9wdbtYpK4ip9ieFkk1TyLw", - "withdrawQueue": "6gsvjkgSsxWtQRxYQ6J8uZPPhpgyoM6HwBJDpp2DzPon", - "lpVault": "7y59c7yGzLJGS8HmERaZgnbkgpKeAaAKSML3Jnsz4r4f", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "D7p7PebNjpkH6VNHJhmiDFNmpz9XE7UaTv9RouxJMrwb", - "marketAuthority": "GfX8cR4p9BWr47RknXetRvmHdCnbd1qRhi59kyibq6V4", - "marketBaseVault": "GuivK7Kd7aiJT9gTnhDskqUpbUD5Yur3f2NyygvwhA9B", - "marketQuoteVault": "ZKoVkBhZ9DJvuCMLvuPvZnhFTCQFAoF1BmVZZ1SqgPg", - "marketBids": "HNrzaujyABxtAcGyAqCJNcbfiJT4SLHGHuwBkVH4Zmiz", - "marketAsks": "Fm2BPhsTnozBGLhFzd5iKfoBjKRWDEoCGC78xBEJg5P", - "marketEventQueue": "CXhqNRvzdgrG8TRHjzUiymQFS7NNL8nGMyUvrQT3XPnu" - }, - { - "id": "34oD4akb2DeNcCw1smKHPsD3iqQQQWmNy3cY81nz7HP8", - "baseMint": "ArUkYE2XDKzqy77PRRGjo4wREWwqk6RXTfM9NeqzPvjU", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Hb8KnZNKvRxu7pgMRWJgoMSMcepfvNiBFFDDrdf9o3wA", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "92QStSTSQHYFg2ZxJjxWETwiS3zYsKnJm9BznJ8JDvrh", - "targetOrders": "EHjwgEneTm6DZWGbictuSxf7NfcirEjyYdzYaSyNkhT1", - "baseVault": "EgNtpEoLCiSJx8TtVLWUBpXhUWmqzBrymgweihtmnd83", - "quoteVault": "HZHCa82ezeYegyQWtsWW3vznpoiRaa3ewtxYvm5X6tTz", - "withdrawQueue": "FbWCd9uQfAD5M62Pyceff5S2WFeN9Z5rL6azysGdhais", - "lpVault": "H12qWVeehVN6CQGfwCnSH2LxcHJ9we33U6gPmiViueu5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5FpKCWYXgHWZ9CdDMHjwxAfqxJLdw2PRXuAmtECkzADk", - "marketAuthority": "Gwe1pE3rV4LLviNZqrEFPAeLchwvHrftBUQsnJtEkpSa", - "marketBaseVault": "5UbUbaVLXnZq1eibQSUxdsk6Lp38bgdTjbjQPssXGgwW", - "marketQuoteVault": "4KMsmK7gPdKMAKmEcHqtBB5EhNnWVRd71v3a5uBwhQ2T", - "marketBids": "EdXd7dZLfkjz4k38VoP8d8ij7UJdrnZ3EoR9RHr5ThqX", - "marketAsks": "DuGkNca9NtZByzAxQsbt5yPFNF8pyv2PqB2sjSbBGEWi", - "marketEventQueue": "AeRsgcjxerNiMK1wpPyt7TSkH9Ps1mTr9Ac1bbWvYhdp" - }, - { - "id": "34tFULRrRwh4bMcBLPtJaNqqe5pVgGZACi5sR8Xz95KC", - "baseMint": "MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DkiqCQ792n743xjWQVCbBUaVtkdiuvQeYndM53ReWnCC", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "58G7RrYRntVvVj9rVgDwGhAJoWhMWHNyDCoMydYUwSR6", - "targetOrders": "2qBcjDqDywhB7Kgb1VYq8K5svJh37BB8oC5kBE4VqA7q", - "baseVault": "91fMidHL8Yr8KRcu4Zu2RPRRg1FbXxZ7DV43rAyKRLjn", - "quoteVault": "93oFfbcayY2WkcR6d9AyqPcRC121dXmWarFJkwPErRRE", - "withdrawQueue": "FhnSdMoRPj75bLs6yzaDPFfiuucUZhVDiyM78WEhaKJo", - "lpVault": "FZAwAb6UxNiwDTbQZ3bPKYA4PkbYpurh8YpAH8G424Lv", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3d4rzwpy9iGdCZvgxcu7B1YocYffVLsQXPXkBZKt2zLc", - "marketAuthority": "BFkxdUwW17eANhfs1xNmBqEcegb4EStQxVb5VaMS2dq6", - "marketBaseVault": "7Ex7id4G37HynuiCAv5hTYM4BnPB9y4NU85QcaNWZy3G", - "marketQuoteVault": "9UB1NhGeDuV1apHdtK5LeAEjP7kZFH8vVYGdh2yGFRi8", - "marketBids": "3nAdH9wTEhPoW4e2s8K2cXfn4jZH8FBCkUqtzWpsZaGb", - "marketAsks": "HxbWm3iabHEFeHG9LVGYycTwn7aJVYYHbpQyhZhAYnfn", - "marketEventQueue": "H1VVmwbM96BiBJq46zubSBm6VBhfM2FUhLVUqKGh1ee9" - }, - { - "id": "3cmPpX8kKzEra2umtLCDxMfjma82ELtAMaSYVmdaNLxi", - "baseMint": "49c7WuCZkQgc3M4qH8WuEUNXfgwupZf1xqWkDQ7gjRGt", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3dADrQa7utyiCsaFeVk9r7oebW1WheowhKo5soBYKBVT", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Gwd7zQAHr3bkyGkNRrKM5hZwUVsjdBEeyNr8ME5cqxUz", - "targetOrders": "9wu7YGgankeWkeygE8Qt8A5qHeycDp9vBTSUsr85QBzZ", - "baseVault": "C1MF3pFLfRBzrywrMJvHPP2EUjCQfKYmyW975rdkXB85", - "quoteVault": "5mLSVNzt7juMjxXohvvwHZdojG81GbdFrjYxgsSqDnNH", - "withdrawQueue": "7XpC5EC51j1WBz56Nr9cq33akEeaU2NoA7MQ3NMYNjMX", - "lpVault": "8EW9HQ4QtXTFSyZ6LuLk3bRUvi1MsPVxFKmUqd37a1vh", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3FE2g3cadTJjN3C7gNRavwnv7Yh9Midq7h9KgTVUE7tR", - "marketAuthority": "FLqXAFVSveyKjtfWpfT8ttrn3yUAzoHGKiYwcR5r6tp7", - "marketBaseVault": "2t3MMN5FLMqsieeUsQK8nfM4YKQobK5ZvDgjNV6hn7SW", - "marketQuoteVault": "55SiYWMEP7XrMvP31YhZQE1YTkypv6yeDe7Z3663pMfb", - "marketBids": "HexBvvrL8jZRGti3zXZ6vCXqDzJ7skgSaMgqLJjzXaCm", - "marketAsks": "224juRrCj1VeeiG3qoXLDrJkGPSh8MJH2XuEsLCHLLj7", - "marketEventQueue": "DY4P5LEdehACn83akvVb49MNJf5VhDQuWTxfx95nGdgY" - }, - { - "id": "3hhSfFhbk7Kd8XrRYKCcGAyUVYRaW9MLhcqAaU9kx6SA", - "baseMint": "FnKE9n6aGjQoNWRBZXy4RW6LZVao7qwBonUbiD7edUmZ", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "FT2KZqxxM8F2h9pZtTF4PyjK88bM4YbuBzd7ZPwQ5wMB", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9WAbiCgjiYeV9aBh8jo2eX8ujAhfEZdZPxPeBtEemz9t", - "targetOrders": "43FmUjW5ZLQ9VeZA7B5gCqJ5fmvJgXHn2zfistpxJt8t", - "baseVault": "FPPZjSgvMJ9EkKJpsTFNnGNJYAbiteskZQGHieVh9Mfh", - "quoteVault": "FEB62fNjbKaPPc9YBnuA2SMacyQhqQw5XTy5d5kTS1oW", - "withdrawQueue": "6MMAE9t29jmuckFgmYojPQk5pJB4TTHJxAmTvWfHAkBr", - "lpVault": "EbNabXhGffsMVn2QyaRVgaR9M1M2NM9AZWCCKMLuZSRT", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5s966j9dDcs6c25MZjUZJUCvpABpC4gXqf9pktwfzhw1", - "marketAuthority": "BBaMkoum9hY53mCXAGqMcP2hMSzEyS7Nr12RLY395eCL", - "marketBaseVault": "5reSWxhb7uugMzxQXPEfYY7zaveCmHro7juk3VzQJx9T", - "marketQuoteVault": "4S5XZnwyd7kB1LnY55rJmXjZHty3FGAxyqQaNHphqfzC", - "marketBids": "6ESsneZ4fQgPE6MUKsP6Z8kzAZk9RGeVg3uffVqhuJXb", - "marketAsks": "F2SRQpGR8z4gQQxJ1QVdrzZr7gowTLmfXanTsWmBbzTf", - "marketEventQueue": "6WpyfUCGwDBMgMng5kqsYeGHq4cmFP7X5zyXSs6ZZJ93" - }, - { - "id": "3HYhQC6ne6SAPVT5sPTKawRUxv9ZpYyLuk1ifrw8baov", - "baseMint": "9nEqaUcb16sQ3Tn1psbkWqyhPdLmfHWjKGymREjsAgTE", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "H2FAnazDaGFutcmnrwDxhmdncR1Bd7GG4mhPCSUiamDX", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Bo8BrjEpfu7pJVH32FTE6rJr2UBvhPp59zfA2mWT581U", - "targetOrders": "4JZBoQLkpgPzdwLBbQeZ6PQj11vtLomuRtSFE4Xkc3CJ", - "baseVault": "5cjmkkBTx5QecZh78iwwVRUobE25fyjJZQcfEXdzWo37", - "quoteVault": "DPLFfchYfphyS86uLRx2gqHTTy8urWBGt1yYC2a6xUHX", - "withdrawQueue": "7UYg1Gh4tipvNdYYC4rqqLapcs9szENKkrgrEKmDqtJu", - "lpVault": "DQAeQPjQqB733mJfJbt4wHfA2fHVM6bVgaUGNjCerJjE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EfckmBgVkKxBAqPgzLNni6mW1gbHaRKiJSJ3KgWihZ7V", - "marketAuthority": "78dHXV2JdqQyFTs1tprMH359be7WWMYsmsSAsFctBoZe", - "marketBaseVault": "CJVUSSsd4AnqNK7pvDb3XWWx6v34NELyy8JdQoKxnSdW", - "marketQuoteVault": "4YFPXdvk2HYwAJMPFCw7EU2h6CUTeWzvsC5DnrrTGF3Z", - "marketBids": "4WfAKMzXH2Gbcx6tafVy2CwpKDbqFqtx5CbAr877ivx5", - "marketAsks": "H8WLtDAhcJZLW3J1g2sNPhiqy7PG75GkRZU93EB5xwwj", - "marketEventQueue": "7n1qHSyCH7btGmiexi1tj5tzsJgRBywg1a1Xvov3GVoq" - }, - { - "id": "3mYsmBQLB8EZSjRwtWjPbbE8LiM1oCCtNZZKiVBKsePa", - "baseMint": "3K6rftdAaQYMPunrtNRHgnK2UAtjm2JwyT2oCiTDouYE", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2Vyyeuyd15Gp8aH6uKE72c4hxc8TVSLibxDP9vzspQWG", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4tN7g8KbPt5bU9YDpeAsUNs2FY4G6GRvajTwCCHXt9Lk", - "targetOrders": "Fe5ZjyEhnB7mCgFhRkSLWNgvtkrut4iRzk1ydfJxwA9b", - "baseVault": "Guw4ErphtZQRC1foic6WweDSvA9AfuqJHKDXDcbrWH4f", - "quoteVault": "86WgydpDUFRWa9aHzd9JgcKBELPJZVrkZ3uwxiiC3w2V", - "withdrawQueue": "Gvmc1zR72pdgoWSzNBqMyNoVHe78nxKgd7FSCE422Lcp", - "lpVault": "6FpDRYsKds3WkiCLjqpDzNBHWZP2Bz6CK9dZryBLKB9D", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7MpMwArporUHEGW7quUpkPZp5L5cHPs9eKUfKCdaPHq2", - "marketAuthority": "XoGZnpfyqj539wneBe8xUQyD282mwy5AMUaChz12JCH", - "marketBaseVault": "6LtcYXZVb7zfQG33F5dCDKZ29hyQaUh6BBhWjdHp8moy", - "marketQuoteVault": "FCqm5xfy8ZvMxifVFfSz9Gxv1CTRABVMyLXuJrWvzAq7", - "marketBids": "5SZ6xDgLzp3QbzkqT68BBAB7orCezSsV5Gb9eAk84zdY", - "marketAsks": "Gwt93Xzp8aFrP8YFV8YSuHmYbkrGURBVVHnE6AqDT4Hp", - "marketEventQueue": "Ea4bQ4wBJ5MXAwTG1hKzEv1zry5WnGY2G58YR8hcZTk3" - }, - { - "id": "3rY1TU9NEkExmkVt9ouNL4FSoLdcCxmNp8rbQFaY8MQa", - "baseMint": "svtMpL5eQzdmB3uqK9NXaQkq8prGZoKQFNVJghdWCkV", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HXLkojxGWSUwjagzRXMFRgmnNxkcKrFHvq4ZCZeNvBJL", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5zSMP1GvuEqnr4AaZNbBDn7zaGe2WRUdapzMHSHVZSEG", - "targetOrders": "DDcoNXXt8FVhtBscbgrvXsSDLNNKRs1v43QqGcGAFspq", - "baseVault": "6BDCwrz9aXfywwBYTvRF7bPsu1JdVPdGpzvDEkRRk9k1", - "quoteVault": "4CNkiWouhXwbX41ePkbrp1xaXRTrfvhnEshS5ac31XBH", - "withdrawQueue": "79n1q4jP7SkNZ97PNMG7p2xa4hh7sUdtiztJynrSEmZk", - "lpVault": "7xPfrhG8eaV9Vr66dy2wEchuXvU3jQFNYtQ5Zie1AEAo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HuFKVQNyB177c9DiocQksYzBCtHMRUP5bBXZJzuLvYQm", - "marketAuthority": "BUADwkKpJNpkkgcKd6BH7ZikRmrban9SD9UrAAztG9yG", - "marketBaseVault": "2PwrP5xB816jePXPpwXFFqpLf73AHm7CrzJDzVovwJAG", - "marketQuoteVault": "FHCBp7UvkD2ppoHAec5A8VLYobSqxFmRvrKWB31CjcEY", - "marketBids": "d3LpprS4kt81QT7hozsMxQJ4EHRT66esu7HRBvnjXHk", - "marketAsks": "Ax2tmh1snhvcQEV5tE2uyCgn5Ly81JJpkBFUnaW9JzPf", - "marketEventQueue": "AwqanJUwreJjzqQnzwfJ2Gt7itdVLfb8AagdSaYePAh3" - }, - { - "id": "3XwxHcbyqcd1xkdczaPv3TNCZsevELD4Zux3pu4sF2D8", - "baseMint": "2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk", - "quoteMint": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "lpMint": "9VoY3VERETuc2FoadMSYYizF26mJinY514ZpEzkHMtwG", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FBfaqV1RRacEi27E3dm8yLcxpbWYx4BzMXG4zMNx7ZdS", - "targetOrders": "B1gQ6FHLxmBzznDKn8Rj1ZokcJtdSWjkCoXdQLRhz8NS", - "baseVault": "CsFFjzC1hmpqimExTj8g4kregUxGnGrEWX9Jhne172uU", - "quoteVault": "ACg55oVWt1a4ZVxnFVCRDEMz1JAeGY13snXufdQAp4pX", - "withdrawQueue": "C6MRGfZ13tstxjcWuLqUseUikidsAjgk7zBEYqM6cFb4", - "lpVault": "EVRzNkPU9UAzBf8XhJYD84U7petDZnSMVaaa9mtBQaM6", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3Dpu2kXk87mF9Ls9caWCHqyBiv9gK3PwQkSvnrHZDrmi", - "marketAuthority": "EC5JsbaQVp8tM59TqkQBk4Yv7bzLQq3TrzpepjGr9Ecg", - "marketBaseVault": "58jqhCZ11r6ZvATqdGfDXPk7LmiR9HS3jQt7kuoBx5CH", - "marketQuoteVault": "9NLpT5aZtbbauvEVVFsHqigv2ekTEPK1kojoMMCw6Hhx", - "marketBids": "HBVsrbKLEf1aaUy9oKFkQZVDtgTf54T9H8FQdcGbF7EH", - "marketAsks": "5T3zDaT1XvfEb9jKcgpFyQRze9qWKNTE1iSE5aboxYZy", - "marketEventQueue": "3w11TRux1gX7nqaGUMGpPH9ocDBPudeLTw6k1uhsLo2k" - }, - { - "id": "43UHp4TuwQ7BYsaULN1qfpktmg7GWs9GpR8TDb8ovu9c", - "baseMint": "51tMb3zBKDiQhNwGqpgwbavaGH54mk8fXFzxTc1xnasg", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "444cVqYyDxJNo6FqiMb9qQWFUd7tYzFRdDuJRFrSAGnU", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5SrvK4rUdhRAekLxYnDb552x1DzQP4F42mydUcxMMNJD", - "targetOrders": "8W9P9rDx5a8C234jWLaUT7x4RGUGscXx2oCpS3eMfGUo", - "baseVault": "3tMBycaDewfj2trk1HP1ZSRb4YEJQs6k7nFAk4jTrRtN", - "quoteVault": "DRDqm7rLuGnkh9RU1H2aaaJihRSU2Yg3WhropTWmcpWW", - "withdrawQueue": "HA1wfa31ogn6eMY6174gNVf9LGjfjAhBdMaYtCkWBLhx", - "lpVault": "BPJ6HpvGBpQ5TUezSv3NzicANEq8Grma6QmPV1gXKnx8", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GX26tyJyDxiFj5oaKvNB9npAHNgdoV9ZYHs5ijs5yG2U", - "marketAuthority": "GprUwgGyqBiEC5e6ivxgpUf7uhpS17n7WRiU7HDV3VGk", - "marketBaseVault": "CEGcRVzSbX5hGpsKsPX8zhTMm8N4xJSTH1VFEcWXRUmE", - "marketQuoteVault": "7Q1TDhNbhpN9KN3vCRk7WhPi2EaETSCkXpsTdaDppvAx", - "marketBids": "3N3tX1CLNCsnEffqhNBkiQxo34VJBPE7dbYUWsy4M6UD", - "marketAsks": "BLCo9efr528yH73zJU47FCDKzvsJAYFGdYkPgHb8yWxJ", - "marketEventQueue": "3St3PhenFusFH1Guo7WQhNeNSfwDNpJQScDJ1EhRcLai" - }, - { - "id": "4C2Mz1bVqe42QDDTyJ4HFCFFGsH5YDzo91Cen5w5NGun", - "baseMint": "AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "75dCoKfUHLUuZ4qEh46ovsxfgWhB4icc3SintzWRedT9", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "23WS5XY3srvBtnP6hXK64HAsXTuj1kT7dd7srjrJUNTR", - "targetOrders": "CYbPm6BCkMyX8NnnS7AoCUkpxHVwYyxvjQWwZLsrFcLR", - "baseVault": "4TaBaR1ZgHNuQM3QNHnjJdAT4Sws9cz46MtVWVebg7Ax", - "quoteVault": "7eDiHvsfcZf1VFC2sUDJwr5EMMr66TpQ2nmAreUjoASV", - "withdrawQueue": "36Aa83kffwBuEP7AqNU1w5c9oB9kLxmR4FMfadXfjNbJ", - "lpVault": "8hdJm5bvgXVtb5LA18QgGeKxnXBcp3cYKwRz8vb3fV44", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2Pbh1CvRVku1TgewMfycemghf6sU9EyuFDcNXqvRmSxc", - "marketAuthority": "B5b9ddFHrjndUieLAKkyzB1xmq8sNqGGZPmbyYWPzCyu", - "marketBaseVault": "4LXjM6rptNvhBZTcWk4AL49oF4oA8AH7D4CV6z7tmpX3", - "marketQuoteVault": "2ycZAqQ3YNPfBZnKTbz2FqPiV7fmTQpzF95vjMUekP5z", - "marketBids": "9HTDV2r7cQBUKL3fgcJZCUfmJsKA9qCP7nZAXyoyaQou", - "marketAsks": "EpnUJCMCQNZi45nCBoNs6Bugy67Kj3bCSTLYPfz6jkYH", - "marketEventQueue": "2XHxua6ZaPKpCGUNvSvTwc9teJBmexp8iMWCLu4mtzGb" - }, - { - "id": "4crhN3D8R5rnZd66q9b32P7K649e5XdzCfPMPiTzBceH", - "baseMint": "APTtJyaRX5yGTsJU522N4VYWg3vCvSb65eam5GrPT5Rt", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Hk8mDAJFq4E9kF3DtNgPFwzbo5kbeiusNFJgWmo3LoQ5", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9ZkyYVUKZ3iWZnx6uJNUNKdv3NW3WcKNWZMg2YDYTxSx", - "targetOrders": "FWKNVdavvUKdcpCCU3XT1dsCEbHF1ak21q2EzoyMy1av", - "baseVault": "6egmkyieHa2R2TiVoLkwmy3fXG1F8EG8KmEMBN2Lahh7", - "quoteVault": "4dcKsdDe39Yp4NDzko1Jv6ViSDo2AUMh2KGxT6giidpA", - "withdrawQueue": "FwSCPqMixHerULmKCuaxU8VzUGmMVTUrbpNUaY6EwBgP", - "lpVault": "CCxPRM9viLU3nr82UcgqgUkyTxM1NTW2a8DtwR9NwSAP", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ATjWoJDChATL7E5WVeSk9EsoJAhZrHjzCZABNx3Miu8B", - "marketAuthority": "Hfn1km6sEcBnQ6S1SLYsJZkwQzx7kJJ9o8UqwWhPNiW3", - "marketBaseVault": "GesJe56oHgbA9gTxNz5BFGXxhGdScteKNdmYeLj6PBmq", - "marketQuoteVault": "GvjFcsncRnqfmRig7kkgoeur7QzkZaPurpHHyWyeriNu", - "marketBids": "5M3bbs43jpQWkXccVbny317rKFFq9bZT3ccv3YoLSwRd", - "marketAsks": "EZYkKSRfdqbQbwBrVmkkWXmosYFB4cVhcT4jLT3Qjfxt", - "marketEventQueue": "7tnT8FCXaN5zryRpjJieFHLLVBUtZYR3LhYDh3da9HJh" - }, - { - "id": "4ELBQuq3ivhLamfCT36As5sXLkQDWRJw1pJ9JVFLp6gK", - "baseMint": "CRWNYkqdgvhGGae9CKfNka58j6QQkaD5bLhKXvUYqnc1", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "H3D9Gyi4frRLW6bS9vBthDVDJyzyRJ6XhhpP6PJGWaDC", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GLGAhYAAi8FuhxVys1ZqJZb1rw9p8JVM6YYxUeR9ZUfT", - "targetOrders": "douEwhf1WA7ay18r7kGDYuwPNpBus3Tu5aApeLZGKSR", - "baseVault": "3dkMWcJkghmvGeQGFUr7nKYWZjYNdxWg9riaxtT3xCHV", - "quoteVault": "B7JNDmk3YG6bGbqcDMcBpNQJqau3HJPeFwvHATdVZRsG", - "withdrawQueue": "7yJL932ytN1pQQ6PYBbKt5eqRCYE2ixtGAdguv9mJV7u", - "lpVault": "DMzWN9j6ZMV6ebZ2ugW4ENvbsJUi1cJZBAAoZ9XQZzRs", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "H8GSFzSZmPNs4ANW9dPd5XTgrzWkta3CaT57TgWYs7SV", - "marketAuthority": "HKdMHuRTgKEwGg26Ew1xUoGo4vesP6dN8dnLjFbDANfr", - "marketBaseVault": "B4n994TDxFeAz35YMEQZJvkhVtHmab5PRQUjgtigScAi", - "marketQuoteVault": "2LAVDjbCkDPY4B3aLzgWs3VCEA2Rq6SJPjCqgBcB2N2L", - "marketBids": "3onFzW294iJT3ZW2rbfFbH9jErD4mcZistyMf8Xbbf8u", - "marketAsks": "3chCWxohikbd9ENp62mLRSkjKi37MjokEUzLsdvtsyB5", - "marketEventQueue": "7pVNda7bdZzdrU7WVchS5u3gAYG9x6NNUFuD7wzRgn2q" - }, - { - "id": "4fgubfZVL6L8tc5x1j65S14P2Tnxr1YayKtKavQV5MBo", - "baseMint": "AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "2cTCiUnect5Lap2sk19xLby7aajNDYseFhC9Pigou11z", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BSDKUy73wuGskKDVgzNGLL2k7hzDEwj237nZZ3Ch3bwz", - "targetOrders": "4j1JaKap2s4XrkJeMDaMabfEDsQm9ykeUgJ9CWa9w4JU", - "baseVault": "HHTXo4Q8HFWMSDKnPJWCe1Y5UmYPFNZ6hU4mc8km7Zf4", - "quoteVault": "5rbAHV9ufT11XRR5LcvMVsuA5FcpBozLKj91z372wpZR", - "withdrawQueue": "AMU4FFUUahWfaUA6WWzTWNNuiXoNDEgNNsZjFLWhvB8f", - "lpVault": "FUVUCrKB6c7x9uVn1zK8qxbVwb6rNLqA2W17TM9Bhvta", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Hr3wzG8mZXNHV7TuL6YqtgfVUesCqMxGYCEyP3otywZE", - "marketAuthority": "CgV9LcnAukrgDZmqhUwcNQ31z4KEjZEz4DHUSE4bRaVg", - "marketBaseVault": "H1VJqo3piiadyVAUQW6yfZq4an8pgDFvAdqHJkRXMDbq", - "marketQuoteVault": "9SQ4Sjsszt59X3aLwRrTqa5SLxonEdXk5jF7KUfAxc8Z", - "marketBids": "3k5bWdYn9thQmqrye2gSobzFBYTyYosx3bKvMJRcfTTN", - "marketAsks": "DPW1r1p2uyfQxVC7vx3xVQcVvyUeiS2vhAnveQiXs9AT", - "marketEventQueue": "9zMcCfjdHH2Z7iCBtVdkmf9qXUN6y7AhbuWhRMu2DmcV" - }, - { - "id": "4Sx1NLrQiK4b9FdLKe2DhQ9FHvRzJhzKN3LoD6BrEPnf", - "baseMint": "StepAscQoEioFxxWGnh2sLBDFp9d8rvKz2Yp39iDpyT", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3k8BDobgihmk72jVmXYLE168bxxQUhqqyESW4dQVktqC", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EXgME2sUuzBxEc2wuyoSZ8FZNZMC3ChhZgFZRAW3nCQG", - "targetOrders": "78bwAGKJjaiPQqmwKmbj4fhrRTLAdzwqNwpFdpTzrhk1", - "baseVault": "8Gf8Cc6yrxtfUZqM2vf2kg5uR9bGPfCHfzdYRVBAJSJj", - "quoteVault": "ApLc86fHjVbGbU9QFzNPNuWM5VYckZM92q6sgJN1SGYn", - "withdrawQueue": "5bzBcB7cnJYGYvGPFxKcZETn6sGAyBbXgFhUbefbagYh", - "lpVault": "CpfWKDYNYfvgk42tqR8HEHUWohGSJjASXfRBm3yaKJre", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "97qCB4cAVSTthvJu3eNoEx6AY6DLuRDtCoPm5Tdyg77S", - "marketAuthority": "FbwU5U1Doj2PSKRJi7pnCny4dFPPJURwALkFhHwdHaMW", - "marketBaseVault": "CVNye3Xr9Jv26c8TVqZZHq4F43BhoWWfmrzyp1M9YA67", - "marketQuoteVault": "AnGbReAhCDFkR83nB8mXTDX5dQJFB8Pwicu6pGMfCLjt", - "marketBids": "5Xdpf7CMGFDkJj1smcVQAAZG6GY9gqAns18QLKbPZKsw", - "marketAsks": "6Tqwg8nrKJrcqsr4zR9wJuPv3iXsHAMN65FxwJ3RMH8S", - "marketEventQueue": "5frw4m8pEZHorTKVzmMzvf8xLUrj65vN7wA57KzaZFK3" - }, - { - "id": "4yrHms7ekgTBgJg77zJ33TsWrraqHsCXDtuSZqUsuGHb", - "baseMint": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "3hbozt2Por7bcrGod8N7kEeJNMocFFjCJrQR16TQGBrE", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FBU5FSjYeEZTbbLAjPCfkcDKJpAKtHVQUwL6zDgnNGRF", - "targetOrders": "2KjKkci5zpGa6orKCu3ov4eFSB2aLR2ZdAYvVnaJxJjd", - "baseVault": "5ushog8nHpHmYVJVfEs3NXqPJpne21sVZNuK3vqm8Gdg", - "quoteVault": "CWGyCCMC7xmWJZgAynhfAG7vSdYoJcmh27FMwVPsGuq5", - "withdrawQueue": "BzTWSVgYaqHvUcuPZKD4yKTDR2xCDtZFb1bqkwfoPHZJ", - "lpVault": "Dfvj9bmde56ZWgxDsrADywZhctejEG2WTbnYa7P5SAhk", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7gtMZphDnZre32WfedWnDLhYYWJ2av1CCn1RES5g8QUf", - "marketAuthority": "GRiN6BiHeaa2wrFEpqzR397d6RqefCSRhnQVsVscwT3r", - "marketBaseVault": "5F5W8nkQpXnb5ewS2GiUCuWAiamZpzGEMBciwaZ72frr", - "marketQuoteVault": "CdWhLReMv1A4BJQkogvMwxVVop6agSW22YzQBzKUCS1y", - "marketBids": "4Z6iBaVyCusvALJShz39yDY98jwPn6T1SsKaiLE3k5du", - "marketAsks": "J6ULjQv2xpifRQQAKNYAtEGapgAsAA7vNhhRU57Law6m", - "marketEventQueue": "4tMSdiQWSGJbaz4UCdHQpqczxCJfLvBNWtskGbAnFgBz" - }, - { - "id": "4ZYiiVakejxGyJ3tuBzYWoHyEV1rk7Hm7viydG6DNaUN", - "baseMint": "PRSMNsEPqhGVCH1TtWiJqPjJyh2cKrLostPZTNy1o5x", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3baYkTcudvSFMe25UpZcBfdp4FA5kL2E4pfaeJ8AiYJB", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BbLHAwRx9RtGCSYrFM9wzxqx3ZmhLMHHSYRNpKnYwrsh", - "targetOrders": "4MchsSuWUvVLWQGFsFxjEDY6vM8FhHBpkVEuYPdC8qq5", - "baseVault": "Fjrkf7uoCLgZG8jTWo71kyqUubqsi6YRagQGMxmQEvQe", - "quoteVault": "5xR14K7Wn1ABG3HyNCboR8VVwVAk9Rj2uShVVnCwFiNd", - "withdrawQueue": "9bMsYn9jr1TvYfktB4Js8hvwTjuxbMNZPFk6AJVp3icL", - "lpVault": "Gu72XLrP2yKyRpVK65Xf7eEgJFTWQEZ5Uk9D145LuSkv", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2MvXnxngd1gKp6gE8Q63wiPHSpveWcx8x4wf43VpyiA6", - "marketAuthority": "74GRGpvNtRDZkx8M9SVBU5Z4of6j4vPFWQyFX3ZvV3fg", - "marketBaseVault": "pLX8sCH4jNJVS57goC6Y7ujzLH1gG88Mej5UWwc3eFo", - "marketQuoteVault": "4mBaTptwEPRwdBzBfLu2SixTAawqqrP6UsoFgfUcfZr9", - "marketBids": "FYWe7bjakwEz22Tz9ujt3vNtzuAZX5B9ceVutUrqHS1v", - "marketAsks": "8vD5fzFY3AVv6m6oB88shTbaDxYa6ufVeTHhy5zJ5RkR", - "marketEventQueue": "LczT5PA64Uq8CBYCN73DH27e2X5r2PwPZLFCTTCUoJS" - }, - { - "id": "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2", - "baseMint": "So11111111111111111111111111111111111111112", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8HoQnePLqPj4M7PUDzfw8e3Ymdwgc7NLGnaTUapubyvu", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HRk9CMrpq7Jn9sh7mzxE8CChHG8dneX9p475QKz4Fsfc", - "targetOrders": "CZza3Ej4Mc58MnxWA385itCC9jCo3L1D7zc3LKy1bZMR", - "baseVault": "DQyrAcCrDXQ7NeoqGgDCZwBvWDcYmFCjSb9JtteuvPpz", - "quoteVault": "HLmqeL62xR1QoZ1HKKbXRrdN1p3phKpxRMb2VVopvBBz", - "withdrawQueue": "G7xeGGLevkRwB5f44QNgQtrPKBdMfkT6ZZwpS9xcC97n", - "lpVault": "Awpt6N7ZYPBa4vG4BQNFhFxDj4sxExAA9rpBAoBw2uok", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "marketAuthority": "F8Vyqk3unwxkXukZFQeYyGmFfTG3CAX4v24iyrjEYBJV", - "marketBaseVault": "36c6YqAwyGKQG66XEp2dJc5JqjaBNv7sVghEtJv4c7u6", - "marketQuoteVault": "8CFo8bL8mZQK8abbFyypFMwEDd8tVJjHTTojMLgQTUSZ", - "marketBids": "14ivtgssEBoBjuZJtSAPKYgpUK7DmnSwuPMqJoVTSgKJ", - "marketAsks": "CEQdAFKdycHugujQg9k2wbmxjcpdYZyVLfV9WerTnafJ", - "marketEventQueue": "5KKsLVU6TcbVDK4BS6K1DGDxnh4Q9xjYJ8XaDCG5t8ht" - }, - { - "id": "5cmAS6Mj4pG2Vp9hhyu3kpK9yvC7P6ejh9HiobpTE6Jc", - "baseMint": "Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9FC8xTFRbgTpuZZYAYnZLxgnQ8r7FwfSBM1SWvGwgF7s", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8bEDWrUBqMV7ei55PgySABm8swC9WFW24NB6U5f5sPJT", - "targetOrders": "G2nswHPqZLXtMimXZtsiLHVZ5gJ9GTiKRdLxahDDdYag", - "baseVault": "8vwzjpW7KPGFLQdRuyoBBoiBCsNG6SLRGssKMNsofch2", - "quoteVault": "AcK6bv25Q7xofBUiXKwUgueSi3ELS6anMbmNn2NPV8FZ", - "withdrawQueue": "BG59NCoZnxqSU2TQ2DNsENiCZci73BcRvXWtqmQhNrcw", - "lpVault": "msNco37chvHeLivUwoetEnHDFZxVNi2KXQzjGAXkRuZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HXBi8YBwbh4TXF6PjVw81m8Z3Cc4WBofvauj5SBFdgUs", - "marketAuthority": "84aqZGKMzbr8ddA267ML7JUTAjieVJe8oR1yGUaKwP53", - "marketBaseVault": "38r5pRYVzdScrJNZowNyrpjVbtRKQ5JMcQxn7PgKE45L", - "marketQuoteVault": "4YqAGXQEQTQbn4uKX981yCiSjUuYPV8aCajc9qQh3QPy", - "marketBids": "FdGKYpHxpQEkRitZw6KZ8b21Q2mYiATHXZgJjFDhnRWM", - "marketAsks": "cxqTRyeoGeh6TBEgo3NAieHaMkdmfZiCjSEfkNAe1Y3", - "marketEventQueue": "EUre4VPaLh7B95qG3JPS3atquJ5hjbwtX7XFcTtVNkc7" - }, - { - "id": "5DECiJuqwmeCptoBEpyJtXKrVfiUrG9nBbBGkxGkPYyF", - "baseMint": "inL8PMVd6iiW3RCBJnr5AsrRN6nqr4BTrcNuQWQSkvY", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GbmJtVgg9fRmmmjKUYGMZeSt8wZ47cDDXasg5Y3iF4kz", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GujdDreXBSEXUCjk39tRnM8ZYCrtyambNSa3JjJVGvLJ", - "targetOrders": "D4dBV5v9AMfGzgf1eBrpAUom72YVLYeZr1ufnY1dJd8W", - "baseVault": "2z4day3sVMRULUtFJ4sbTvKrkjMsc42rjXHDQtggbSE9", - "quoteVault": "9PVPqk5RYf5x9nRYbEzotVNpk36NJ6bAZJaaSnaaZrYn", - "withdrawQueue": "3xxiFPPRwy4bshMeG3bN4yCNDiFsbVdPq29qK2bddJ9J", - "lpVault": "EbDVS5gwPdVYK7f14g2B9zNesgEfAcgnxQzTYf7GYw9j", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "49vwM54DX3JPXpey2daePZPmimxA4CrkXLZ6E1fGxx2Z", - "marketAuthority": "D8QQQMut9bbPfpCXHgbwoPSF4KNYSg7SyRUGF828dBfZ", - "marketBaseVault": "De4wrN3UtHs783VTZjqoFZtP2v95pMWFx1KCqmkWBXqU", - "marketQuoteVault": "DiiAfxX3J5apQ8SJ42Z4z2USTK3QbhksTzniAugLaG91", - "marketBids": "8hU3yAFb1429V1TTSKqpgJ7XJyQQQoLq76wxHeM1WYo", - "marketAsks": "CEdiYZ2Cp62ECHgkz2mPiK9A6HcMG2jSmrppxiENzgKT", - "marketEventQueue": "DJgsxzKvBY2wTqAWEmiqV8quTR7k9GZ7rsmvov3yzXPw" - }, - { - "id": "5dHEPTgvscKkAc54R77xUeGdgShdG9Mf6gJ9bwBqyb3V", - "baseMint": "AR1Mtgh7zAtxuxGd2XPovXPVjcSdY3i4rQYisNadjfKy", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2QVjeR9d2PbSf8em8NE8zWd8RYHjFtucDUdDgdbDD2h2", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7a8WXaxsvDV9CjSxgSpJG8LZgdxmSps1ehvtgQj2qt4j", - "targetOrders": "9f5b3uy3hQutS6pka2GxcSoKjvKaTcB1ivkj1GK43UAV", - "baseVault": "B8vMKgzKHkapzdDu1jW76ALFvVYzHGGKhR5Afz3A4mZd", - "quoteVault": "Hsxi4jvmszcMaWfU3tk98fQa9pVXtRktfKvKJ7rKBQYi", - "withdrawQueue": "AgEspvUPUuaTqyJTjZMCAW3zTuxQBSaU17GhLJoc6Jad", - "lpVault": "BHLDqVcYUrAwv8RvDUQ76BQDQzvb2yftFN8UccpA2stx", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "A1Q9iJDVVS8Wsswr9ajeZugmj64bQVCYLZQLra2TMBMo", - "marketAuthority": "uWhVkK44yR6V5XywVom4oWzDQACSPYHhNjkwXprtUij", - "marketBaseVault": "BJfPQ2iKTJknyWo2wtCVEpRGWVt8sgpvmSQVNwLioQrk", - "marketQuoteVault": "2UN8qfXzoUDAxZMX1KqKut93frkt5hFREL8xcw6Hgtsg", - "marketBids": "J8JVRuBojWcHFRGosQKRdDtzxwux8fy2dwfk42Z3dCaf", - "marketAsks": "6DScSyKZKBi9cXhD3mRkTkpsxrhw6HABFxebsteCP1zU", - "marketEventQueue": "Hvpz2Cv2LgWUfTtdfjpnefYrjQuaw8gGjKoDAeGxzrwE" - }, - { - "id": "5TgJXpv6H3KJhHCuP7KoDLSCmi8sM8nABizP7CmYAKm1", - "baseMint": "4dmKkXNHdgYsXqBHCuMikNQWwVomZURhYvkkX5c4pQ7y", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "G8qcfeFqxwbCqpxv5LpLWxUCd1PyMB5nWb5e5YyxLMKg", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2Nr82a2ZxqsQYwBbpeLWQedy1s9kAi2U2AbeuMKjgFzw", - "targetOrders": "Cts3uDVAgUSaXAHMEfLPnQWF4W5TpGdiB7WhYDAaQbSy", - "baseVault": "FaUYbopmMVdNRe3rLnqGPBA2KB96nLHudKaEgAUcvHXn", - "quoteVault": "9YiW8N9QdEsAdTQN8asjebwwEmDXAHRnb1E3nvz64vjg", - "withdrawQueue": "HpWzYHXNeQkmW9oxFjHFozyy6sVxetqJBZdhNSTwcNid", - "lpVault": "7QAVG74PVZntmFqvnGYwYySRBjB13HSeSNABwMPtfAPR", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DPfj2jYwPaezkCmUNm5SSYfkrkz8WFqwGLcxDDUsN3gA", - "marketAuthority": "3APrMUDUQ16iEsL4vTaovTf5fPXAEwtXmWXvD9xQVPaB", - "marketBaseVault": "CddTJJj2tDWUk6Kteh3KSBJJh4HvkoWMXcQjZuXaaAzP", - "marketQuoteVault": "BGr1LWgHKaekkmScogSU1SYSRUaJBBPFeBAEBvuwf7CE", - "marketBids": "CFFoYkeUJaAEh6kQyVEbAgkWfABnH7c8Lynr2hk8ycJT", - "marketAsks": "AVQEVeftGzTV6Yj2jEPFGgWHyTYs5uyT3ZFFyTaLgTAP", - "marketEventQueue": "H6UE5r8zMsaHW9fha6Xm7bsWrYbyaL8WbBjhbqbZYPQM" - }, - { - "id": "5tho4By9RsqTF1rbm9Akiepik3kZBT7ffUzGg8bL1mD", - "baseMint": "poLisWXnNRwC6oBu1vHiuKQzFjGL4XDSu4g9qjz9qVk", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "9ysGKUH6WqzjQEUT4dxqYCUaFNVK9QFEa24pGzjFq8xg", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "UBa61sKev8gr19nqVyN3BZbW2jG7eAGjbjeZvpU4wu8", - "targetOrders": "FgMtC8pDrSQJUovmnrDiRWgLGVrVSq9kui98re6uRz5i", - "baseVault": "Ah9T12tzwnTXWrWVWzLmCrwCEmVHS7HMdWKG4qLUDzJP", - "quoteVault": "J7kjQkrpafcLjL7cCpmMamxLAFnCkGApLTC2QrbHe2NQ", - "withdrawQueue": "EgZgi8skDug7YecbFuCFxXx3SPFPhbGSVrGiNzLHErkj", - "lpVault": "TYw7qQDt6sqpwUFSRfNBaLHEA1SUxbEWtmZxtZQhojk", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3UP5PuGN6db7NhWf4Q76FLnR4AguVFN14GvgDbDj1u7h", - "marketAuthority": "5RqVkFy8hUbYDR81ucZhF6rAwpgYJngLJLSynMTeC4vM", - "marketBaseVault": "pLD9GMk4LACBXDJAWJSgbT1batbHgunBVyy8BaVBazG", - "marketQuoteVault": "Ah3JVyTAGLbH63XPWDDnJUwV1xYwHhFX2J81CDHomkLk", - "marketBids": "4tAuffNhWeF2MDWjMDgrRoR8X8Jg3BLvUAaerXzLsFpG", - "marketAsks": "9W133475h1LZ2ZzY7aJtbJajLDSCn5hNnKcsu6gXgE2G", - "marketEventQueue": "5DX4tJ8jZt91XzM7JUUPhu6CL4o6UDGnfjLJZtkmEfVT" - }, - { - "id": "5VyLSjUvaRxsubirbvbfJMbrKZRx1b7JZzuCAfyqgimf", - "baseMint": "MAPS41MDahZ9QdKXhVa4dWB9RuyfV4XqhyAZ8XcYepb", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "CcKK8srfVdTSsFGV3VLBb2YDbzF4T4NM2C3UEjC39RLP", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HViBtwESRNKLZY7qLQxP68b5vLdUQa1XMAKz19LbSHjx", - "targetOrders": "8Cwm1Z75hQdUpFUxCuoWmWBLcAaZvKMAn2xKeuotC4eC", - "baseVault": "6rYv6kLfhAVKZw1xN2S9NWNgp8EfUVvYKi1Hgzd5x9XE", - "quoteVault": "8HfvN4VyAQjX6MhziRxMg5LjbMh9Fw889yf3sDgrXakw", - "withdrawQueue": "HnzkiYgZg22ZaQGdeTHiCgJaoW138CLqCb8tr6QJFkU4", - "lpVault": "DnTQwA9PdwLSibsiQFZ35yJJDNJfG9fNbHspPmb8v8TQ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7Q4hee42y8ZGguqKmwLhpFNqVTjeVNNBqhx8nt32VF85", - "marketAuthority": "CH76NgZMpUJ8QQqVNpjyCSpQmZBNZLXW6a5vDHj3aUUC", - "marketBaseVault": "2zriJ5sVApLD9TC9PxbXK41AkVCQBaRreeXtGx7AGE41", - "marketQuoteVault": "2qAKnjzokKR4sL6Xtp1nZYKXTmsraXW9CL3HuBZx3qpA", - "marketBids": "J9ZmfF71eMMzisvaYW12EK87UaopZ4hgND2nr61YwmKw", - "marketAsks": "9ah4Mewrh841gmfaX1v1wCByHU3rbCuUmWUgt2TBAfnb", - "marketEventQueue": "EtimVRtnRUAfv9tXVAHpGCGvtYezcpmzbkwZLuwWAYqe" - }, - { - "id": "5ZPBHzMr19iQjBaDgFDYGAx2bxaQ3TzWmSS7zAGrHtQJ", - "baseMint": "ETAtLmCmsoiEEKfNrHKJ2kYy3MoABhU6NQvpSfij5tDs", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "9Aseg5A1JD1yCiFFdDaNNxCiJ7XzrpZFmcEmLjXFdPaH", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HhAqmp3r8gaKo9P1ybaEXpwjq5MfmkfD6sRVD4EYs1tU", - "targetOrders": "3Dwo6BD7H2GQMyxoh5nXdmAK7dWfqPMUj3PcrJVqUuEp", - "baseVault": "FGskpuYNgqgHU4kHSibgqDkYCCZhxAtpQxZNqFaKfBDK", - "quoteVault": "7AiT1Re8Z8m8eLdy5HWRqWvx6pBZMytdWQ3wL8zCrSNp", - "withdrawQueue": "7reJT6i8tnFjf5vbvmRLw6ikZZxs6ZJ8bsEx4iCU22ot", - "lpVault": "6LmFCURzNyEsNpF4fgMDyGPX1xoNAnm2oVcrYJJQGv9Y", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2STXADodK1iZhGh54g3QNrq2Ap4TMwrAzV3Ja14UXut9", - "marketAuthority": "F1XJJ2fkPiiYg1hWnDD6phMfDd8Sr8XwM6GKFeAZpTmr", - "marketBaseVault": "Ea7ECm7a3ECLnvJJMpZS9QrWbYnb8LkqVvWCXtmFVzWX", - "marketQuoteVault": "54a18egZToocQ2yeCstCrtYZLAj3z82qfLG4Ed1quThb", - "marketBids": "FKgbQ8Sdv9d44SMrtLMy58EmP3V59fvjse2UUQ8mNCxd", - "marketAsks": "CNcZwNeBA1QVL1Kzq3n166RSvUocLrKNs4nzTGXgVPuE", - "marketEventQueue": "FwHwAcBc54zm8XjtNxvaZG1t84shzYs68z3BAsKZdoE" - }, - { - "id": "61JtCkTQKSeBU8ztEScByZiBhS6KAHSXfQduVyA4s1h7", - "baseMint": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CTEpsih91ZLo5gunvryLpJ3pzMjmt5jbS6AnSQrzYw7V", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AtFR9ub2dbNJJod7gPL81F7gRxVtpcR1n4GczqgasqX2", - "targetOrders": "ZVmcXezubm6FXvS8Wtvah66vqZRW6NKD17tea7FcGsB", - "baseVault": "2cA595zqm12sRtsiNvV6AqD8WDYYiJoLwEYNQ1FZG2ep", - "quoteVault": "Fxn92YfcVsd9diz32YtKixqmuezgLeSWqd1gypFL5qe", - "withdrawQueue": "ioR3UfTLnz6t9Bzbcu7TPmw1xYQRwXCgGqcpvzRmCQx", - "lpVault": "8VEBvPwhBwu9D4e4Zei6X31ZBs5udL5epJHp935LVMv1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "marketAuthority": "9aZNHmGZrNnB3fKmBj5B9oD7moA1nFviZqNUSkx2tctg", - "marketBaseVault": "EqnX836tGG4PYSBPgzzQecbTP47AZQRVfcy4RqQW8F3D", - "marketQuoteVault": "7yiA6p6BXxZwcm38St3vTzyGNEmZjw8x7Ko2nyTfvVx3", - "marketBids": "B1xjpD5EEVtLWnWioHc7pCJLj1WVGyKdyMV1NzY4q5pa", - "marketAsks": "6NZf4f6dxxv83Bdfiyf1R1vMFo5QP8BLB862qrVkmhuS", - "marketEventQueue": "7RbmehbSunJLpg7N6kaCX5SenR1N79xHN8jKnuvXoEHC" - }, - { - "id": "661trVCzDWp114gy4PEK4etbjb3u3RNaP4aENa5uN8Vp", - "baseMint": "BRLsMczKuaR5w9vSubF4j8HwEGGprVAyyVgS4EX7DKEg", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GfV3QDzzdVUwCNSdfn6PjhmyJvjw18tn51RingWZYwk3", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "gng63EZXkDhK3Qp8KgvLEZkcWmVDrmBe3EuYRy8mBPy", - "targetOrders": "5Y23u3wgJ68uk7suF1mbJZQ9q1BnQKSVXUZfjJeY5RGw", - "baseVault": "CVioXLp58QsN9Xsf8JkAcadRmC1vsW74imLpKhMxPWSM", - "quoteVault": "HfBK19mBWh5D9VgnsPaKccfQaD79AYXetULtwLo62qxr", - "withdrawQueue": "7txhWR41faQuKEBb6xq53RHBdGMCXf7fM7MBJgMvTiBN", - "lpVault": "FrzaE4b2kpXtihidZj8mpTK3ji36wrTMtKLdVAxqPbiU", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6V6y6QFi17QZC9qNRpVp7SaPiHpCTp2skbRQkUyZZXPW", - "marketAuthority": "FeGULrcjRyxHyRJTAUt84TqjR89biLnwwtjReWtRNoy2", - "marketBaseVault": "4PfqVvYg6tshSnMBMrXUwzYdS9gZvoxWFwGeLEx6BKow", - "marketQuoteVault": "81WG3s7xWe8aT6nf3r3t6sBuoMFb4QPiEZ2caENXQuKr", - "marketBids": "5GdFXwsM4oW5pgyYUE4uqQXKsswL1y21DBwn6HJTteQt", - "marketAsks": "ARGstQL7aLDdfN5yXUXKh8Y4Gwqe6eq5pMvYGcgkvHR1", - "marketEventQueue": "FC9bnU5d4irjaWdCjG8sgUT5TTaADDpvxdn4twN9fA9A" - }, - { - "id": "69Mo81rUPDgru4UbigPQovx7cYBxpEm44qQok8wcut4M", - "baseMint": "333iHoRM2Awhf9uVZtSyTfU8AekdGrgQePZsKMFPgKmS", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "H8s1wQsZpRK61pyLF3XwyQc6E8vNUnwRDhy3TBDCDENQ", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "G1qyfVQgaYrUxemLV4acWZg9RG3C4RD4XqHu8B1AgcxA", - "targetOrders": "Eqs2SKiUBQadw5KbPhbKNFA7LmSjF2T6iY3cxqDj3JE2", - "baseVault": "Avh1uyt3sFu2FUUCoMHmWssrN3nPw5GrAMX5wLLefs2L", - "quoteVault": "Zfy5TtPXCEK8rxSbp2cb14WCR4aG4qGsgJLLdC7gxGe", - "withdrawQueue": "5Yhk3vYCDvmcRE9TQC5QREQw6fysTQRnZ7fXPqQdqdPY", - "lpVault": "CRDyUcasjeKwqeHziDXoHD7P9ho9K1V4aD7JN2vXJEm7", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "42QVcMqoXmHT94zaBXm9KeU7pqDfBuAPHYN9ADW8weCF", - "marketAuthority": "GMYEbrinZLmPMY6FRnFdmuHbYZ9Bz1PcTWmjqBMK5LuQ", - "marketBaseVault": "FaRw8KMqoiuRAjunz2tDnJBVbPxeKKg8z4FNrHQtpnzu", - "marketQuoteVault": "59c3uxz4qgKonm48oBHuwqrL1SdMV4WudQAsjrgw39kv", - "marketBids": "HNqcNhSHcXAcZJV45y4xyWqquuicdg88J73cTBbXLsuG", - "marketAsks": "J54QZ5LE535DVZxSzL45edE4d1nDrhbcq2NxrV9GTA6a", - "marketEventQueue": "DeypfVmbbp9ajhQdZCfx1EVkiEL3WVLPCHcRvTZgRcfZ" - }, - { - "id": "6a1CsrpeZubDjEJE9s1CMVheB6HWM5d7m1cj2jkhyXhj", - "baseMint": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HDUJMwYZkjUZre63xUeDhdCi8c6LgUDiBqxmP3QC3VPX", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "28NQqHxrqMYMQ67aWyn9AzZ1F16PYd4zvLpiiKnEZpsD", - "targetOrders": "B8nmqinHQjyqAnMWNiqSzs1Jb8VbMpX5k9VUMnDp1gUA", - "baseVault": "DD6oh3HRCvMzqHkGeUW3za4pLgWNPJdV6aNYW3gVjXXi", - "quoteVault": "6KR4qkJN91LGko2gdizheri8LMtCwsJrhtsQt6QPwCi5", - "withdrawQueue": "5i9pTTk9x7r8fx8mJMBCEN85URVLAnkLzZXKyoutUJhU", - "lpVault": "GiuNbiBirwsBp9GuxGYgNUMMKGM6Qf6wqgnxbJFHTYFa", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5F7LGsP1LPtaRV7vVKgxwNYX4Vf22xvuzyXjyar7jJqp", - "marketAuthority": "x1vRSsrhXkSn7xzJfu9mYP2i19SPqG1gjyj3vUWhim1", - "marketBaseVault": "4gqecEySZu6SEgCNhBJm7cEn2TFqCMsMNoiyski5vMTD", - "marketQuoteVault": "6FketuhRzyTpevhgjz4fFgd5GL9fHeBeRsq9uJvu8h9m", - "marketBids": "HjJSzUbis6VhBZLCbSFN1YtvWLLdxutb7WEvymCLrBJt", - "marketAsks": "9e37wf6QUqe2s4J6UUNsuv6REQkwTxd47hXhDanm1adp", - "marketEventQueue": "CQY7LwdZJrfLRZcmEzUYp34XJbxhnxgF4UXmLKqJPLCk" - }, - { - "id": "6eRECBcCVP82AvAd6Di4rZApa2btLf8RDUqrTigt4hS4", - "baseMint": "Fm9rHUTF5v3hwMLbStjZXqNBBoZyGriQaFM6sTFz3K8A", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BAgSWaPZpsQKyZJdvB5KyvmCNj6hzczzentt5FhDCVHb", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CiLegtV4wfcZ7V6RJKvesnguRpz9VRQgNNBjTxXjMkWA", - "targetOrders": "5VbiaMEzVspC3Lq4aAWmZmjP3TRccoZnK1tZY4sUkXQw", - "baseVault": "ApC5piXBR1JCJnVxBrMUtbWxFXc8EZ3TmKw9no4tnZSA", - "quoteVault": "3bWNBbLQZrz3TnfNdSRodqgwQHy3XaWbknT7BA9d7pec", - "withdrawQueue": "Cs9139e2htmeZEscdCNBZGufmomzsExhAZN8p3g7W6gW", - "lpVault": "GCdY8Qc2zQVp1XiDyBGxstvD5P7RsSDXbprtkn1DoF4k", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9sUSmgx78tt692hzwiRdBdfwjxPF6nsYeJfPCrTz6vxm", - "marketAuthority": "3HFfyFAWGizgqBrX6AQnmBa3C1S2Dq5rNed3A9mY98CV", - "marketBaseVault": "H8WFSuFwvjWFdvojecKym6UJVSk3ZLukEjeSBbzbXKYX", - "marketQuoteVault": "DDr2SB8aM3xPCoQoLFZTXGvpAz6aFWaTR34EcbG9vWhK", - "marketBids": "BQfvcMGzSApw8BAdwiWGJDTWQCXqaHwmGrFdLjM4CAgv", - "marketAsks": "9rNcJYeyVMSqYLA4tYv8r9K9PTMwcnLFgknbtcWhLcKS", - "marketEventQueue": "8ZwrnG4dyPwVLh4MBL2CAfptQQsR9BY6pcHHpYAsUuEH" - }, - { - "id": "6gpZ9JkLoYvpA5cwdyPZFsDw6tkbPyyXM5FqRqHxMCny", - "baseMint": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "De2EHBAdkgfc72DpShqDGG42cV3iDWh8wvvZdPsiEcqP", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HDsF9Mp9w3Pc8ZqQJw3NBvtC795NuWENPmTed1YVz5a3", - "targetOrders": "68g1uhKVVLFG1Aua1BKtCx3uiwPixue1qqbKDJAc32Uo", - "baseVault": "BusJVbHEkJeYRpHkqCrt85d1LALS1EVcKRjqRFZtBSty", - "quoteVault": "GM1CjxKixFkKpakxx5Lg9u3zYjXAK2Gr2pzoy1G88Td5", - "withdrawQueue": "GDZx8SZSYsRKc1WfWfbqR9JaTdBEwHwAMcJuYk2rBm74", - "lpVault": "EdLjP9p2AA7zKWwRPxKx8SKFCJ9awfSxnsPgURX6HuuJ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HVFpsSP4QsC8gFfsFWwYcdmvt3FepDRB6xdFK2pSQtMr", - "marketAuthority": "FD6U73ZW2YkD9R8cbDT6KSamVodYqWJBtS3ZcPeU7X29", - "marketBaseVault": "GPksxJSxy5pEigdtSLBBZuRQEuGPJRT2ah3J1HwMeKm5", - "marketQuoteVault": "TACxu78UJHz2Vzg2HwGa2w9mvLw2mY5mL7Q3ho9W6J9", - "marketBids": "7ZCucutxHFwJjfUmxD1Pae8vYg9HB1WQ6DhRkueNyJqF", - "marketAsks": "6cM5rqTHhngGtifjK7pUwved3CdHKZgFj7nnP3LsP325", - "marketEventQueue": "Gucy2LXDFjWBZEFX4gyrqr6xEb2AWRf4VVgqX33ZXkWu" - }, - { - "id": "6GUF8Qb5FWmifzYpRdKomFNbSQAsLShhT45GbTGg34VJ", - "baseMint": "MERt85fc5boKw3BW1eYdxonEuJNvXbiMbs6hvheau5K", - "quoteMint": "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS", - "lpMint": "DU5RT2D9EviaSmX6Ta8MZwMm85HwSEqGMRdqUiuCGfmD", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Gh3w9pfjwbZX2FVrMy6PzUQG5rhihKduGCB7UaPGUTZw", - "targetOrders": "37k5Xe8Sej1TrjrGsR2HyRR1EjYECV1HcS3Xh6Jnxggi", - "baseVault": "ApnMY7ahxTMssU1dzxYEfMcag1aSa5s4Axje3nqnnrXH", - "quoteVault": "BuQxGhmS82ZhczEGbUyi9R7TjxczXTMRoD4nQ4GvqxCf", - "withdrawQueue": "CrvN8Zi4c6BHVFc3mAB8CZSZRftY73WtpBH2Zade9MKZ", - "lpVault": "5W9V96yUqk95zUYawoCfEittj4VT4Nbv8NVjevJ4kN78", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FtxAV7xEo6DLtTszffjZrqXknAE4wpTSfN6fBHW4iZpE", - "marketAuthority": "7cBPvLMQvf1X5rzLMNKrx7TY5M186rTR49yJNHNSp81s", - "marketBaseVault": "2Duueu4HUnv6e4qUqdM4DKECM9X3XggBsXp5eLYuSLXe", - "marketQuoteVault": "3GEqHH6VAnyqrgG9jRB4Qy9PMTYJmSBvg7u3LtBWHEWD", - "marketBids": "Hi6bo1sodi7X2GrpeVpk5mKKG42Ga8n4Gi3Fxr2WK6rg", - "marketAsks": "75a4ASjShTXZPdxNzm4RoSEVydLBFfDa1V81Wcf7Xw59", - "marketEventQueue": "7WDqc3MAApvgDskQBDKVVPmya3Src228sAk8Lag8ovph" - }, - { - "id": "6kbC5epG18DF2DwPEW34tBy5pGFS7pEGALR3v5MGxgc5", - "baseMint": "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2hMdRdVWZqetQsaHG8kQjdZinEMBz75vsoWTCob1ijXu", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "L6A7qW935i2HgaiaRx6xNGCGQfFr4myFU51dUSnCshd", - "targetOrders": "6DGjaczWfFthTYW7oBk3MXP2mMwrYq86PA3ki5YF6hLg", - "baseVault": "HWTaEDR6BpWjmyeUyfGZjeppLnH7s8o225Saar7FYDt5", - "quoteVault": "7iGcnvoLAxthsXY3AFSgkTDoqnLiuti5fyPNm2VwZ3Wz", - "withdrawQueue": "8g6jrVU7E7eghT3FQa7uPbwHUHwHHLVCEjBh94pA1NVk", - "lpVault": "2Nhg2RBqHBx7R74VSEAbfSF8Kmi1x3HxyzCu3oFgpRJJ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "A8YFbxQYFVqKZaoYJLLUVcQiWP7G2MeEgW5wsAQgMvFw", - "marketAuthority": "GBWgHXLf1fX4J1p5fAkQoEbnjpgjxUtr4mrVgtj9wW8a", - "marketBaseVault": "GZ1YSupuUq9kB28kX9t1j9qCpN67AMMwn4Q72BzeSpfR", - "marketQuoteVault": "7sP9fug8rqZFLbXoEj8DETF81KasaRA1fr6jQb6ScKc5", - "marketBids": "6wLt7CX1zZdFpa6uGJJpZfzWvG6W9rxXjquJDYiFwf9K", - "marketAsks": "6EyVXMMA58Nf6MScqeLpw1jS12RCpry23u9VMfy8b65Y", - "marketEventQueue": "6NQqaa48SnBBJZt9HyVPngcZFW81JfDv9EjRX2M4WkbP" - }, - { - "id": "6kmMMacvoCKBkBrqssLEdFuEZu2wqtLdNQxh9VjtzfwT", - "baseMint": "kinXdEcpDQeHPEuQnqmUgtYykqKGVFq6CeVX5iAHJq6", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "CHT8sft3h3gpLYbCcZ9o27mT5s3Z6VifBVbUiDvprHPW", - "baseDecimals": 5, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DiP4F6FTR5jiTar8fwuwRVuYop5wYRqy2EjbiKTXPrHw", - "targetOrders": "2ak4VVyS19sVESvvBuPZRMAhvY4vVCZCxeELYAybA7wk", - "baseVault": "s7LP6qptF1wufA9neYhekmVPqhav8Ak85AV5ip5h8wK", - "quoteVault": "9Q1Xs1s8tCirX3Ky3qo9UjvSqSoGinZvWaUMFXY5r2HF", - "withdrawQueue": "DeHaCJ8KL5uwBGenkUwa39JyhacxPDqDqHAp5HLqgd1i", - "lpVault": "T2acWsGDQ4ZRXs4WXVi7vCeH4TxzgjcL6s14xFNuT26", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Fcxy8qYgs8MZqiLx2pijjay6LHsSUqXW47pwMGysa3i9", - "marketAuthority": "5V7FCcvmGtqkMJXHiTSeo61MS5LSMUFK1Esr5kn46cEv", - "marketBaseVault": "2sCJ5YZtwEbpXiw7HSXVx8Qot8hwyCpXNEkswZCssi2J", - "marketQuoteVault": "H6B59E77WZt4JLfaXdZQBKdATRcWaKy5N6Ki1ZRo1Mcv", - "marketBids": "HKWdSptDBeXTURKpQQ2AGPmT2B9LGNBVteq44UzDxKBh", - "marketAsks": "2ceQrRfuNWL8kR2fockPo7C31uDeTyXTs4EyA28FD2kg", - "marketEventQueue": "GwnDyxFnHSnzDdu8dom3vydtTpSu443oZPKepXww5zNB" - }, - { - "id": "6nJes56KF999Q8VtQTrgWEHJGAfGMuJktGb8x2uWff2u", - "baseMint": "PoRTjZMPXb9T7dyU7tpLEZRQj7e6ssfAE62j2oQuc6y", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9tmNtbUCrLS15qC4tEfr5NNeqcqpZ4uiGgi2vS5CLQBS", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ENfqr7WFKJy9VRwfDkgL4HvMM6GU7pHyowzZsZwx8P39", - "targetOrders": "9wjp6tFY1XNH6KhdCHeDgeUsNLVjTwxA3iC9k5aun2NW", - "baseVault": "GGurDvQctUDgcegSYZetkNGytcWEfLes6yXzYruhLuLP", - "quoteVault": "3FmHEQRHaKMS4vA41eYTVmfxX9ErxdAScS2tvgWvNHSz", - "withdrawQueue": "ETie1oDMcoTD8jzrseAcvTqZYyyoWxR92LH15nA6Lfub", - "lpVault": "GEJfHTwURq89KcM1RgvFZRweb4f7H8NAsmyMg2kTPBEs", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8x8jf7ikJwgP9UthadtiGFgfFuyyyYPHL3obJAuxFWko", - "marketAuthority": "63ZaXnSj7SxWLFEcjmK79fyGokJxhR3UEXomN7q7Po25", - "marketBaseVault": "8rNKJFsd9yuGx7xTTm9sb23JLJuWJ29zTSTznGFpUBZB", - "marketQuoteVault": "5Vs1UWLxZHHRW6yRYEEK3vpzE5HbQ8BFm27PnAaDjqgb", - "marketBids": "9Y24T3co7Cc7cGbG2mFc9n3LQonAWgtayqfLz3p28JPa", - "marketAsks": "8uQcJBapCnxy3tNEB8tfmssUvqYWvuCsSHYtdNFbFFjm", - "marketEventQueue": "8ptDxtRLWXAKYQYRoRXpKmrJje31p8dsDsxeZHEksqtV" - }, - { - "id": "6UmmUiYoBjSrhakAobJw8BvkmJtDVxaeBtbt7rxWo1mg", - "baseMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FbC6K13MzHvN42bXrtGaWsvZY9fxrackRSZcBGfjPc7m", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "J8u8nTHYtvudyqwLrXZboziN95LpaHFHpd97Jm5vtbkW", - "targetOrders": "3cji8XW5uhtsA757vELVFAeJpskyHwbnTSceMFY5GjVT", - "baseVault": "FdmKUE4UMiJYFK5ogCngHzShuVKrFXBamPWcewDr31th", - "quoteVault": "Eqrhxd7bDUCH3MepKmdVkgwazXRzY6iHhEoBpY7yAohk", - "withdrawQueue": "ERiPLHrxvjsoMuaWDWSTLdCMzRkQSo8SkLBLYEmSokyr", - "lpVault": "D1V5GMf3N26owUFcbz2qR5N4G81qPKQvS2Vc4SM73XGB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2xiv8A5xrJ7RnGdxXB42uFEkYHJjszEhaJyKKt4WaLep", - "marketAuthority": "FmhXe9uG6zun49p222xt3nG1rBAkWvzVz7dxERQ6ouGw", - "marketBaseVault": "GGcdamvNDYFhAXr93DWyJ8QmwawUHLCyRqWL3KngtLRa", - "marketQuoteVault": "22jHt5WmosAykp3LPGSAKgY45p7VGh4DFWSwp21SWBVe", - "marketBids": "Hf84mYadE1VqSvVWAvCWc9wqLXak4RwXiPb4A91EAUn5", - "marketAsks": "DC1HsWWRCXVg3wk2NndS5LTbce3axwUwUZH1RgnV4oDN", - "marketEventQueue": "H9dZt8kvz1Fe5FyRisb77KcYTaN8LEbuVAfJSnAaEABz" - }, - { - "id": "783kPvwHwDXaU32kV8NK5dB4JVeMWQwe8a3WUNZFpupr", - "baseMint": "Bx1fDtvTN6NvE4kjdPHQXtmGSg582bZx9fGy4DQNMmAT", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "2g9JzTWycLzK4KEBBHsponAtZRee2ii63bRrJ8tefEyt", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CxevWceR45vLckW5GwJf2P8pBHgivG7X852z43dwHzFA", - "targetOrders": "BQi5hcjDTGFVE5KkQu2aoqzcSWVV432k881Zb8BEMnyT", - "baseVault": "GCiihp9tZEcUbXuvBk2B5xaXq4KjCoHunmsVMQaFHKJv", - "quoteVault": "9ZsiqAMG5dnpjwRFxJj3zvHCsYYZdZNJmP8fYfJkR1VZ", - "withdrawQueue": "8EFyi6Lz1DbavbwwVg8rAVfuFh4au2cxCdJbxYdrRkaY", - "lpVault": "G49ujYznJPAhZS6gZHp8gfFNrtNKvGCYtZPhBqvWxRQz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HYM1HS6MM4E1NxgHPH4Wnth7ztXsYTpbB2Rh9raje8Xq", - "marketAuthority": "39uZFr8KuW6puPcovZ8h3J7xCToEQbySsLBN2UGUEdSG", - "marketBaseVault": "CF3iPT4V6HrD1iN3kVka2LFkDnYkNfJbgWqAdfFwK7XG", - "marketQuoteVault": "H5KmunmdEYA6FpiDAQPH3xXKeTtQppkiDL27ccvoSiCL", - "marketBids": "5RrrwmRQcHsrWyQffDbNQMPATdM6W21kHbvdUT3L4n1x", - "marketAsks": "6JXFumfL3e3DhK48aR9JhjKQRGqWW8nWPXkB8GuAbYZU", - "marketEventQueue": "4EPZfsmz8JgmdbgEY7zZ9rxchqbCkqXFWyvHtL9j3zx4" - }, - { - "id": "796pvggjoDCPUtUSVFSCLqPRyes5YPvRiu4zFWX582wf", - "baseMint": "CWE8jPTUYhdCTZYWPTe1o5DFqfdjzWKc9WKz6rSjQUdG", - "quoteMint": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "lpMint": "GXN6yJv12o18skTmJXaeFXZVY1iqR18CHsmCT8VVCmDD", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3bZB7mZ5hRNZfrJx6BL5C4GhP4nT14rEAGVPXL34hrZg", - "targetOrders": "Ha4yLJU1UrZi8MqCMu2pLK3xXREG1GW1bjjqTsjQnC3c", - "baseVault": "5eTUmVN3kXqBeKHUA2kWU19jB7kFN3wpejWvWYcw6dBa", - "quoteVault": "4BsmBxNQtuKgBTNjci8tWd2NqPxXBs2JY38X26epSHYy", - "withdrawQueue": "2jn4FQ2CtYwXDgCcLbNrGUzKFeB5PpPbnMr2x2z2wz3V", - "lpVault": "7SxKHHATjgEgfxnLrtKaSU77s2ABqD8BoEr6W6dFMS3a", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FafaYTnhDbLAFsr5qkD2ZwapRxaPrEn99z59UG4zqRmZ", - "marketAuthority": "CvP4Jk6AYBV6Kch6w6FjwuMqHAugQqVrqCNp1eZmGihB", - "marketBaseVault": "8J7iJ4uidHscVnNGsEgiEPJsUqrfteN7ifMscB9h4dAq", - "marketQuoteVault": "Bw7SrqDqvAXHi2yphAniH3uBw9N7J6vVi7jMH9B2KYWM", - "marketBids": "HyKmFiuoWZo7STLjvJJ66YR4V1wauAorCPUaxnnB6umk", - "marketAsks": "8qjKdvjmBPZWjxP3nWjwFCcsrAspCN5EyTD3WfgKbFj4", - "marketEventQueue": "FWZB7PJLwg7WdgoVBRrkvz2A4S7ZctKnoGj1yCSxqs9G" - }, - { - "id": "7e8GrkwsRm5sS5UaKobLJUNu9esmrzg37dqX6aQyuver", - "baseMint": "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3JZqf2VPNxj1kDZQsfzC7myM6spsGQbGuFv1gVfdYosN", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2GiFVts1PwwwKvw7n7cZkigCRfCXj6StY6dSMAzPf2A2", - "targetOrders": "F3vk58GqNs11abuGGHRxnUUUHbeWF5Pc9Yss8sCVAVV5", - "baseVault": "DqUW9TqewcqnAn3k9XpYx2w88hskgxi5PVxZofyZduTr", - "quoteVault": "HiWTWGm1hb988dwbZW2niFkrDQ9GpefGNp2aBwsc5V4S", - "withdrawQueue": "3JXDWxCSRBAdP2yquoX4ypLVeTN7QkJVfvzpvgLjtKX4", - "lpVault": "HKjKJY9AUwYDujHt12mBsbp6AetDm6bMACQPbfHksT8z", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8mQ3nNCdcwSHkYwsRygTbBFLeGPsJ4zB2zpEwXmwegBh", - "marketAuthority": "2J63m8YjYMr495tU6JfYT23RfEWwaQfzgQXxzctXCgXY", - "marketBaseVault": "9uZNMq6TbFQWT7Mj3fkH7gy9gP5bdroJKPpDFyA8x2NW", - "marketQuoteVault": "9W3sz9P8LiAKDbiaY83cKssmuQckgFpzyKKXKYMrivkB", - "marketBids": "9gwbJpCGVRYKM6twn5tyqkxXEo49JMKp4usZJQjPxRg1", - "marketAsks": "CsaJr18TyYhcabQjn16HW3ZsSoUbct8NSLSKuUcbr1cW", - "marketEventQueue": "2zvmX9TGi5afJs2B6EPaPCBbHLkydAh5TGeCsGkwv9nB" - }, - { - "id": "7eM9KWYiJmNfDfeztMoEZE1KPyWD54LRxM9GmRY9ske6", - "baseMint": "EdAhkbj5nF9sRM7XN7ewuW8C9XEUMs8P7cnoQ57SYE96", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5rTCvZq6BcApsC3VV1EEUuTJfaVd8uYhcGjwTy1By6P8", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4JJD9FBTigYALJgmJ5NN7uSAdm4UF3MqcfQG6zaDcZSj", - "targetOrders": "PknPGRn3K3HPzjyaKjSAqDWqXm65TRzQzsSjG6dibPn", - "baseVault": "Dz7UPsYuDnCPfomPDS1qzhGXqerPhoy7PYScv99JDefh", - "quoteVault": "3Xo2iExmhn4X3yrKmwsRTMMTg2mXdWuEQD2BVweNyCCr", - "withdrawQueue": "4bneChpQF8xrjB7TAYZvBm5xgxncZgn4skZxKV4r3ByM", - "lpVault": "7npJaUpN2TFcMStrQKVPjEcKD9Ju5wpyJHcnVW54Z1Ye", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Cud48DK2qoxsWNzQeTL5D8sAiHsGwG8Ev1VMNcYLayxt", - "marketAuthority": "GuLwNbHHLDyNtYF5qv16boMKvdek5AFK8v7PZ2hMgvdv", - "marketBaseVault": "71E7dr2Rodeneu6wPn8oofCpLQJjfDHr6r76HGCDv491", - "marketQuoteVault": "8gU7HWyk3X41ebNkMH44JhEWq1nzRGdWwGgZaJfr4zGR", - "marketBids": "FWSRaqAPmbwepdz49MVvvioTLWTXW18XCtEvfSv3ytBV", - "marketAsks": "21CBXgZHF58nfFJVts6rAphuPNsbj6JY8CacokMdhpNB", - "marketEventQueue": "6qdexKV3nXYtkZkh49fSFrzEStdmaGj8HttNWSG2ZViT" - }, - { - "id": "7oYaghDwJ6ZbZwzdzcPqQtW6r4cojSLJDKB6U7tqAK1x", - "baseMint": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "B2PjGEP3vPf1999fUD14pYdxvSDRVBk43hxB2rgthwEY", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DsYePDFjAFNQVEjiGwg4tsUdqfLu9hXuu9VPS6DtyPZs", - "targetOrders": "6RQvAcLyub9KNcAWkJMER3Rm2AvwysYyVVdxzSBuUNMm", - "baseVault": "4jrV1Fwqxdnw3WXvLQiXqquLvn4p6p5F9imAVNEU4yCT", - "quoteVault": "5vkX52gpV1ZXmvk2JBSjD8z2wpGKp5Cs1XW15y5YB5ca", - "withdrawQueue": "6ZX2Ct81QtwvWKUARLMjzR3jvs9QNDwPVyPN45YaoKAL", - "lpVault": "DsT2dCWWGEmNcrX8vzx9Fm89Xg4J58LjEijNhVXsRuuN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FR3SPJmgfRSKKQ2ysUZBu7vJLpzTixXnjzb84bY3Diif", - "marketAuthority": "679pdaM91fct45cM3nCvzBN57UGCFHe1CTSJwSRqjGwJ", - "marketBaseVault": "HgKq27kVsH6bFdHru5p3ohnrL2d4D776Yiptkzv2ntwX", - "marketQuoteVault": "JzkBGgCZLSzuZrC2XAmq5F4BRHmvhZtiUrbxsMP2BP6", - "marketBids": "2Ra3y1Y4HDd2jLjvAwdR6JKgGbyySGMToaZACkjroRWR", - "marketAsks": "EXBohV8AsD8kt1GcHTuwHoPLfkz5n8PmNn5JyPJybJ35", - "marketEventQueue": "9FeUXsT6LbNXXZRQohoMRuxsmmYdfQM85JbVtrLUSB2w" - }, - { - "id": "7qZJTK5NatxQJRTxZvHi3gRu4cZZsKr8ZPzs7BA5JMTC", - "baseMint": "E5ndSkaB17Dm7CsD22dvcjfrYSDLCxFcMd6z8ddCk5wp", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GfCWfrZez7BDmCSEeMERVDVUaaM2TEreyYUgb2cpuS3w", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "21yKxhKmJSvUWpL3doX5QwjXKXuzm3oxCG7k5Kima6hu", - "targetOrders": "DaN1UZZ1ExraQi1Ghz8YS3pKaZG44PASbNiApysiRSRg", - "baseVault": "7NMCVudgyHKwVXA62Rv2cFrucQiNYE9b5MMvn4cVtCPW", - "quoteVault": "4d9Q2ekDzHqX51Nu9EZHZ96PhGjLSpVosa5Nci7BbwLe", - "withdrawQueue": "DjHe1Sj7fouU5gJEiFz7C4Vd5TtvApEAxWr5EVhTuEps", - "lpVault": "EpKgUgtmTL425M9ENLqbjupm5funsPdhVr37hB8hJiuy", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7gZNLDbWE73ueAoHuAeFoSu7JqmorwCLpNTBXHtYSFTa", - "marketAuthority": "DFoStusQdrMbHms9Sce3tiRwSHAnaPLEtXCaFAnrhSy3", - "marketBaseVault": "5JCpfGbNdFhXWxMFR4xefBfLEd2qxYgovEggS6wxtmQe", - "marketQuoteVault": "FQfVJz7STBGMheiAAuZdF8ndyvbJhJZWJvpKhFKqSqYh", - "marketBids": "4mSS9iidPrVmMV9D7CNJia5zza2apmBLe3SmYW8SNPFR", - "marketAsks": "7ovw7s6Ta1EQY4PsMu1MvnHfUNyEDADacmc4Rd5m34UD", - "marketEventQueue": "2h7YS1nRQqc86jGKQLT29xnfBk9xVQrzXx9yiB21P5gK" - }, - { - "id": "7rVAbPFzqaBmydukTDFAuBiuyBrTVhpa5LpfDRrjX9mr", - "baseMint": "PRT88RkA4Kg5z7pKnezeNH4mafTvtQdfFgpQTGRjz44", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "EcJ8Wgwt1AzSPiDpVr6aaSur8TKAsNTPmmzRACeqT68Z", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7nsGyAGAawvpVF2JQRKLJ9PVwE64Xc2CzhbTukJdZ4TY", - "targetOrders": "DqR8zK676oafdCMAtRm6Jc5d8ADQtoiUKnQb6DkTnisE", - "baseVault": "Bh8KFmkkXZQzNgQ9qpjegfWQjNupLugtoNDZSacawGbb", - "quoteVault": "ArBXA3NvfSmSDq4hhR17qyKpwkKvGvgnBiZC4K36eMvz", - "withdrawQueue": "4kj6urHjHG3DD8eEdSrMvKQ3P1sL5wvaTakHoZqaTLLx", - "lpVault": "6u5JagDxsfVwGe543NKAviCwRUEXV9XCXEBXFFcUPcoT", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "H7ZmXKqEx1T8CTM4EMyqR5zyz4e4vUpWTTbCmYmzxmeW", - "marketAuthority": "9ZGDGCN9BHiqEy44JAd1ExaAiRoh9HWou8nw44MbhnNX", - "marketBaseVault": "4Zm3aQqQHJFb7Q4oQotfxUFBcf9FVP6qvt2pkJA35Ymn", - "marketQuoteVault": "B34rGhNUNxnSfxodkUoqYC3kGMdF4BjFHV2rQZAzQPMF", - "marketBids": "5Yfr8HHzV8FHWBiCDCh5U7bUNbnaUL4UKMGasaveAXQo", - "marketAsks": "A2gckowJzAv3P2fuYtMTQbEvVCpKZa6EbjwRsBzzeLQj", - "marketEventQueue": "2hYscTLaWWWELYNsHmYqK9XK8TnbGF2fn2cSqAvVrwrd" - }, - { - "id": "7XawhbbxtsRcQA8KTkHT9f9nc6d69UwqCDh6U5EEbEmX", - "baseMint": "So11111111111111111111111111111111111111112", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "Epm4KfTj4DMrvqn6Bwg2Tr2N8vhQuNbuK8bESFp4k33K", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4NJVwEAoudfSvU5kdxKm5DsQe4AAqG6XxpZcNdQVinS4", - "targetOrders": "9x4knb3nuNAzxsV7YFuGLgnYqKArGemY54r2vFExM1dp", - "baseVault": "876Z9waBygfzUrwwKFfnRcc7cfY4EQf6Kz1w7GRgbVYW", - "quoteVault": "CB86HtaqpXbNWbq67L18y5x2RhqoJ6smb7xHUcyWdQAQ", - "withdrawQueue": "52AfgxYPTGruUA9XyE8eF46hdR6gMQiA6ShVoMMsC6jQ", - "lpVault": "2JKZRQc92TaH3fgTcUZyxfD7k7V7BMqhF24eussPtkwh", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "marketAuthority": "CzZAjoEqA6sjqtaiZiPqDkmxG6UuZWxwRWCenbBMc8Xz", - "marketBaseVault": "29cTsXahEoEBwbHwVc59jToybFpagbBMV6Lh45pWEmiK", - "marketQuoteVault": "EJwyNJJPbHH4pboWQf1NxegoypuY48umbfkhyfPew4E", - "marketBids": "2juozaawVqhQHfYZ9HNcs66sPatFHSHeKG5LsTbrS2Dn", - "marketAsks": "ANXcuziKhxusxtthGxPxywY7FLRtmmCwFWDmU5eBDLdH", - "marketEventQueue": "GR363LDmwe25NZQMGtD2uvsiX66FzYByeQLcNFr596FK" - }, - { - "id": "7XXKU8oGDbeGrkPyK5yHKzdsrMJtB7J2TMugjbrXEhB5", - "baseMint": "SLRSSpSLUTP7okbCUBYStWCo1vUgyt775faPqz8HUMr", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2Xxbm1hdv5wPeen5ponDSMT3VqhGMTQ7mH9stNXm9shU", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3wNRVMaot3R2piZkzmKsAqewcZ5ABktqrJZrc4Vz3uWs", - "targetOrders": "BwSmQF7nxRqzzVdfaynxM98dNbXFi94cemDDtxMfV3SB", - "baseVault": "6vjnbp6vhw4RxNqN3e2tfE3VnkbCx8RCLt8RBmHZvuoC", - "quoteVault": "2anKifuiizorX69zWQddupMqawGfk3TMPGZs4t7ZZk43", - "withdrawQueue": "Fh5WTfP9jCbkLPzsspCs4WCSPGqE5GYE8v7kqFXijMSA", - "lpVault": "9oiniKrJ7r1cHw97gv4XPxTFS9i61vSa7PkpRcm8qGeK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2Gx3UfV831BAh8uQv1FKSPKS9yajfeeD8GJ4ZNb2o2YP", - "marketAuthority": "CjiJdQ9a7dnjTKfVPZ2fwn31NtgJA1kRU55pwDE8HHrM", - "marketBaseVault": "6B527pfkvbvbLRDgjASLGygdaQ1fFLwmmqyFCgTacsKH", - "marketQuoteVault": "Bsa11vdveUhSouxAXSYCE4yXToUP58N9EEeM1P8qbtp3", - "marketBids": "6kMW5vafM4mWZJdBNpH4EsVjFSuSTUokx5meYoVY8GTw", - "marketAsks": "D5asu2BVatxtgGFugwmNubdknAsLSJDZcqRHvkaS8UBd", - "marketEventQueue": "66Go3JcjNJaDHHvJyaFaV8rh8GAciLzvM8WzN7fRE3HM" - }, - { - "id": "7Z1c6GHutf3q2MNheyFE8KMNVEALuiPaqoEMyjbCbuku", - "baseMint": "7dgHoN8wBZCc5wbnQ2C47TDnBMAxG4Q5L3KjP67z8kNi", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HpUkVAPRJ5zNRuJ1ZwMXEhbMHL3gSuPb2QuSER9YUd3a", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "59ceFXHiqriiFLGqwabgVwZncq86hEw6bLyq3unDPnSG", - "targetOrders": "7gKNnFvzT7yrvoPnQakdV7BpCRAELnGBnn3dQYEojqHd", - "baseVault": "2A8PVremRfR6SLAaX5qPBqatzcufr6pg8wdaD828E8FC", - "quoteVault": "4XdAP2fmGo2ziQUAjDxg5y4jLhSy2ShdJE5TFg3jjxYG", - "withdrawQueue": "C6hV97zRb4WubTtwXsHTFEYLhu8vamSCCs3VmzkqSSyr", - "lpVault": "3a8FXTm3d8RUZm9eXAGSxLQiQUCnu9ox9qiSqd4WysXX", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7GSn6KQRasgPQCHwCbuDjDCsyZ3cxVHKWFmBXzJUUW8P", - "marketAuthority": "DcxxF4grETLsyYWkqAzT3MYUFAE2VA4fRs7i4Uu4K7dv", - "marketBaseVault": "3mmhhvfLeHMtTMm17r477rcnbVUtRusqVgQ3wZh8hepV", - "marketQuoteVault": "9FgALLcqFUn1o3tn5NPiEhh7HRPYr1n25cAXhcDjfGNJ", - "marketBids": "FzD4EpQmwsFhAeRJF1S6efp1uqkgJ8hqWrNkWoCxMJuc", - "marketAsks": "HLYwubWymYFtMhgU9BcNz8ngsKGNDSjQzooWYbuQ7Pze", - "marketEventQueue": "JCxtKZBuqYruJm7TZpd9DEtsSYcq23dc42dRQz4wf5Cq" - }, - { - "id": "81PmLJ8j2P8CC5EJAAhWGYA4HgJvoKs4Y94ALZF2uKKG", - "baseMint": "3JSf5tPeuscJGtaCp5giEiDhv51gQ4v3zWg8DGgyLfAB", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "FA1i7fej1pAbQbnY8NbyYUsTrWcasTyipKreDgy1Mgku", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "pxedkTHh23HBYoarBPKML3xWh96EaNzKLW3oXvHHCw5", - "targetOrders": "GUMQZC9SAqynDvoV12sRUzACF8GzLpC5fUtRuzwCbU9S", - "baseVault": "GwY3weBBK4dQFwC96tHAoAQq4pSfMYmMZ4m6Njqq7Wbk", - "quoteVault": "Bs3DatsVrDujvjpV1JUVmVgNrPkaVwvp6WtuHz4z1QE6", - "withdrawQueue": "2JJPww9oCvBxTdZaiB2H69Jx4dKWctCEuvbLtFfNCqHd", - "lpVault": "B46wMQncJ2Ugp2NwWDxK6Qd4Q9T24NK3naNVdyVYxbug", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3Xg9Q4VtZhD4bVYJbTfgGWFV5zjE3U7ztSHa938zizte", - "marketAuthority": "6LRcCMsRoGsye95Ck5oSyNqHJW8kk2iXt9z9YQyi9JkV", - "marketBaseVault": "5KgKdCWVyWi9YJ6GipzozhWxAvnbQPpUtaxuMXXEn3Zs", - "marketQuoteVault": "29CnTKiFKwGPFfLBXDXGRX6ywGz3ToZfqZuLkoa33dbE", - "marketBids": "7FN1TgMmjQ8iwTdmJZAiwdTM3MddvxmgiF2J4GVHUtQ1", - "marketAsks": "5nudyjGUfjwVYCk1MzzuBeXcj9k59g9mruAUXrsQfcrR", - "marketEventQueue": "4AMp4qKTwE7RwExstg7Pk4JZwJGeRMnjkFmf52tqCHJN" - }, - { - "id": "83xxjVczDseaCzd7D61BRo7LcP7cMXut5n7thhB4rL4d", - "baseMint": "3JSf5tPeuscJGtaCp5giEiDhv51gQ4v3zWg8DGgyLfAB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "865j7iMmRRycSYUXzJ33ZcvLiX9JHvaLidasCyUyKaRE", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DdBAps8e64hpjdWqAAHTThcVFz8mQ6WU2h6s1Kjgb9vk", - "targetOrders": "8BFicQN1AKaVbf1KNoUieULun1bvpdMxsyjrgC15acM6", - "baseVault": "HhhqmQvx2GMQ6SRQh6nZ1A4C5KjCFLQ6yga1ZXDzRJ92", - "quoteVault": "4J4Y6qkF9yzxz1EsZYTSqviMz3Lo1VHx9ViCUoJph167", - "withdrawQueue": "FPkMHzDo46vzy1eW9FuQFz7TdAp1MNCkZFgKxrHiuh3W", - "lpVault": "DuTzisr6Z2D37yTyY9E4jPMCxhQk3HCNxaL1zKqvwRjR", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7qcCo8jqepnjjvB5swP4Afsr3keVBs6gNpBTNubd1Kr2", - "marketAuthority": "HDdQQNNf9EoCGWhWUgkQHRJVbG3huDXs2z6Fcow3grCr", - "marketBaseVault": "2N59Aig7wqhfffAUjMit7T9tk4FmSRzmByMD7mncTesq", - "marketQuoteVault": "FcDTYePeh2KJts4nroCghgceiJmSBRgq2Xd3PfpernZm", - "marketBids": "8L8kU4H9Ah3fgbczYKFU9WUR1HgAghso1kKwWAPrmLfS", - "marketAsks": "4M9kDzMGsNHT3k31i54wf2ceeApvx3224pLbhDvnoj2s", - "marketEventQueue": "6wKPYgydqNrmcXwbfPeNwkzXmjKMgkUhQcGoGYrm9fS4" - }, - { - "id": "8ekXiGjEjtWzd2us3rAsusKv7kKEhPENV7nvzS7RGRYY", - "baseMint": "4TGxgCSJQx2GQk9oHZ8dC5m3JNXTYZHjXumKAW3vLnNx", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "et9pdjWm97rbmsJoN183GkFV5qzTGru79GE1Zhe7NTU", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "G1vzK51TP85Vr8bcfoDkLDakySNSruTp3Fw3RhB4uvWs", - "targetOrders": "23VaWFz63uXWpkkwoTezADokmpSbWwXfRH2AgAFMBHTY", - "baseVault": "DSiQzr8a4pEwoZa5TE8KdRBMwUoUnHumg7s2Q1vH32G5", - "quoteVault": "5zRG6Hj6QJ51h28yreTdUQpFEDikgu111XUtRNXSAKM6", - "withdrawQueue": "a3q6KagLNFZqLFZviiPeQLNveHz1Duq1nrgGcRgah7v", - "lpVault": "F4HmaY8u6x3rrfrLVHjTVjKEcGn58LjnMc5viuvqKZ5h", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "gtQT1ipaCBC5wmTm99F9irBDhiLJCo1pbxrcFUMn6mp", - "marketAuthority": "HuseDRZYHcCPFSuzhdRHvs2M4dfCWr5ZXENu4aiUtGqx", - "marketBaseVault": "GSpz3LmstYiUEWfTfFcKt6hv9TDPWg8Yxneq8xeL8RJ6", - "marketQuoteVault": "Fh8X13tSH6RfwXdTudmzEWHEcnTMJfM7HbVf4rUNUXhy", - "marketBids": "834hHw1CGbyXRjPD375P5pdhtaXhEphdcrjxFGpXHPVh", - "marketAsks": "6tf7B3V8hYnqwoqUSYTXYWBULLx2hS8TfHvB2roV3YAz", - "marketEventQueue": "SFUvgUFF2CKxS6QAtCfsbrN38QK7Bva1NHrhJ9nxCkd" - }, - { - "id": "8Fr3wxZXLtiSozqms5nF4XXGHNSNqcMC6K6MvRqEfk4a", - "baseMint": "CsZ5LZkDS7h9TDKjrbL7VAwQZ9nsRu8vJLhRYfmGaN8K", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "n76skjqv4LirhdLok2zJELXNLdRpYDgVJQuQFbamscy", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GrTQQTca8U7QpNiThwHfiQuFVihvSkkNPchhkKr7PMy", - "targetOrders": "7WCvFBFN3fjU5hKJjPF2rHLAyXfzGCEqJ8qbqKLBaGTv", - "baseVault": "4WzdFwdKaXLQdFn9i84asMxdr6Fmhmh3qd6uC2xjBXwd", - "quoteVault": "yFWn8ji7zq24UDg1mMqP1mA3vWyUdkjARQUPZCS5iCf", - "withdrawQueue": "J9QSrJtasvLydL5dgbfv55eqBoADM9z91kVi5hpxk36Y", - "lpVault": "fGohyeWwAGqGdjQsHrE4c6GoTC1xHmyiAxJsgz2uZZ9", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4qATPNrEGqE4yFJhXXWtppzJj5evmUaZ5LJspjL6TRoU", - "marketAuthority": "DDyP6zj3GTK3hTRyjPuaEL9yyqgfdstRMMKCkn939pkp", - "marketBaseVault": "7dCAQbfwtDFtLwNgoB2WahCubPhFjZRGjfVYJajcF6qJ", - "marketQuoteVault": "2DsQ33R4GqqBkmxPdFyBy7WYAzyWYm6BNPqKtENAKXuY", - "marketBids": "84wPUTporXrCAceD753fXdiysry7WNkpiJH5HwhV5PwC", - "marketAsks": "BDcmopZQkPoxkk1BLAeh4zR3oWeDFUXTkrD2fJgh8xYu", - "marketEventQueue": "4PiUj2EFVq8YNjMd8zWCUe7dV2prLEJCucapjzTeiShv" - }, - { - "id": "8FrCybrh7UFznP1hVHg8kXZ8bhii37c7BGzmjkdcsGJp", - "baseMint": "GENEtH5amGSi8kHAtQoezp1XEXwZJ8vcuePYnXdKrMYz", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "3HzXnc1qZ8mGqun18Ck3KA616XnZNqF1RWbgYE2nGRMA", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3qTqthYwuZKNQKruWJRGnubfXHU4MyGnvmoJcCbhELmn", - "targetOrders": "HwwQ3v5x3AdLopGFdQYZmwK7D5YURpFoDJcrbuZDsMHm", - "baseVault": "FMxYRoHA3Xn4Su62GCwofmdALGdn4s16S5ZA4C91ULbX", - "quoteVault": "3h7PhXbCAGvtQHqwTS2V3Mhc3fK8E5Hs8EbgCVHkQFwd", - "withdrawQueue": "HW7QPs33Fzw9uME7gqs8DRuvbdP24WFc8jfpBQaqdi5C", - "lpVault": "CJbRPzdxPXEbyfM4YKinhojgmJv6yjcwaWpgvFYL4umz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DpFKTy69uZv2G6KW7b117axwQRSztH5g4gUtBPZ9fCS7", - "marketAuthority": "SDSGfMSBFpUZWKZcsHSkLt7FGD4TQPjWNk2fux2asL6", - "marketBaseVault": "53zLrENukPYyMTgHtgLaPaSVUB15YphguocAC4b5nFbK", - "marketQuoteVault": "4ZTZ5khpqH4jBELchj4g8kcDZUcpuyWmMkj6ajycwGRu", - "marketBids": "DntegVqu4W73GAywDMnNNZv1RhzMnvg2ZG1SpEXiZCjb", - "marketAsks": "CfTMiXZnDvVEyBAoXrNhf2mNBRJ5WCQh4JEwHXMoxh7o", - "marketEventQueue": "CTe9iXRYZJ35xss1KsiFXJHS9w8638H7RKwt9WUdtznq" - }, - { - "id": "8GJdzPuEBPP3BHJpcspBcfpRZV4moZMFwhTAuXebaPL8", - "baseMint": "DFL1zNkaGPWm1BqAVqRjCZvHmwTFrEaJtbzJWgseoNJh", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Fffijd6UVJdQeLVXhenS8YcsnMUdWJqpbBeH42LFkXgS", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "zZgp9gm6MCFSvub491ncJQ78zRF4WymJErhy2cR7nnU", - "targetOrders": "GKo4P3uofE47wug87QE6QGSRHa8wBLDEiW4nXEWeDUb4", - "baseVault": "GteHVo2oJUJC2tFYe1QHS7MyasCVooPJdHfxwdF6hPZ2", - "quoteVault": "FHqPtKCB2w9C94oupinMgykxuzjF6pQRVaBVNzqemXc7", - "withdrawQueue": "495s2Vr8PPXofHsJtkvazG77qNUHrhEpS86XkiFrTQgp", - "lpVault": "6eXLVRMNEVFF7adfkbAQni537VrbPpR8LE3PEXbWxS67", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9UBuWgKN8ZYXcZWN67Spfp3Yp67DKBq1t31WLrVrPjTR", - "marketAuthority": "98fhGkizAxyzvsFZMAyt342wkNP6BGa8wfcHkJJURYrN", - "marketBaseVault": "CvCsGEAe3Lxwo7zQ5Acqd34jjpS1iFWKp9h9Vt2KExpj", - "marketQuoteVault": "EGiCYaiiL65yx8uHkQKAmCv8U1fuDN4su6pSdsL3tQqB", - "marketBids": "xNgA2EugkNq9M9yZeshGSbP7Epy85p8NHhrwkffYyAY", - "marketAsks": "CcCDWuH5zW9577wtoMVUZU6PXoT5ZhiL5dadDo4124c5", - "marketEventQueue": "9U9u5GLjbNNYaqECQATcMAuETbnh2QGjpJJVGoFxjLfm" - }, - { - "id": "8hvVAhShYLPThcxrxwMNAWmgRCSjtxygj11EGHp2WHz8", - "baseMint": "8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "A7GCVHA8NSsbdFscHdoNU41tL1TRKNmCH4K94CgcLK9F", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HMwERnf6t8JTR8qnrQDDGxGL2PeBgpzzmQBJQgvXL3NS", - "targetOrders": "9y7m8jaURWcehBkMt6ebgQ92mqaJzZfxW51wBv6dtGR8", - "baseVault": "CVCDGPwGmxHyt1HwfJgCYbskEXPTvKxZfR6nkZexFQi5", - "quoteVault": "DyHnyEW4MQ1J28JrqvY7AdMq6Djr3TjvczgsokQxj6YB", - "withdrawQueue": "PPCMh17bDnu6sZKhipEfXf4ASK4sTpHkWrEX3SBNKRV", - "lpVault": "HReYRwCxu4qEjzkyjsdf67DyEUsWn1Tqf7eisvM3J7ro", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6y9WTFJRYoqKXQQZftFxzLdnBYStvqrDmLwTFAUarudt", - "marketAuthority": "k5mhBL7yqEtAQs1WtUGdMT9eLLZkjambTd1Y4MyGouf", - "marketBaseVault": "9mQ22KCPTyFkJ4dp16Fhpd1pFrVmonS6SMa9L8nM6nLn", - "marketQuoteVault": "BKGiYU9So4XMYYuYiV2d68kcR2wwLogKbi3rmg8ci4xt", - "marketBids": "Afj14X2pCvbgVzWFAXRC4XBS3B71hZFXiTpVaFEohdCe", - "marketAsks": "GmZTkEYABdUej3QXXZSf8aeZ1UxLB2WaQ4dhVihKZPB8", - "marketEventQueue": "3PveQeVGVfaa4LpTjhuRtm1Xe3Y9q7iW7YQeGJZYKtc4" - }, - { - "id": "8idN93ZBpdtMp4672aS4GGMDy7LdVWCCXH7FKFdMw9P4", - "baseMint": "xxxxa1sKNGwFtw2kFn8XauW9xq8hBZ5kVtcSesTT9fW", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "9X4EK8E59VAVi6ChnNvvd39m6Yg9RtkBbAPq1mDVJT57", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "E9t69DajWSrPC2acSjPb2EnLhFjXaDzcWsfZkEu5i26i", - "targetOrders": "GtE4pXKu4Ps1oFP6Y2E7mu2RyqCJxoSqE9Cz3qwQRLRD", - "baseVault": "6FoSD24CM2MyadTwVUqgZQ17kXozfMa3DfusbnuqYduy", - "quoteVault": "EDL73XTnmr56U4ohW5uXXh6LJwsQQdoRLragMYEWLGPn", - "withdrawQueue": "8LEzGejBbTP7q5mNKru5vjK1HMp9XriEsVv4SAvKTSy9", - "lpVault": "3FXv4555tehX7tBwbTL1MkKxLm9Q28dJFvh32wnFoEvg", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GekRdc4eD9qnfPTjUMK5NdQDho8D9ByGrtnqhMNCTm36", - "marketAuthority": "Fv9vYZoH5t9bGnyLrV7ifGt74vz4qvtsAUyZbLXX7qoz", - "marketBaseVault": "NwNLSyB41djEmYzmqWVbia4p3kVZuqjFpdC7c72ZAZC", - "marketQuoteVault": "87FwRiq7Ct7Tvc2KUVPGvssbKwPAM7BLTzV9ixS3g6Y9", - "marketBids": "GXUZncBwk2iGYNbUtyCYon1CWu8tpTGqnyjYGZZQLuf9", - "marketAsks": "26fwQXsb5Gh5uPAwLCwBvHj6nqtXhL3DpPwYdtWKFcSo", - "marketEventQueue": "6FKmUUXSu11nnYwbWRpwQQrgLHScxDxyDdBD9MGbs23G" - }, - { - "id": "8iQFhWyceGREsWnLM8NkG9GC8DvZunGZyMzuyUScgkMK", - "baseMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "quoteMint": "2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk", - "lpMint": "mjQH33MqZv5aKAbKHi8dG3g3qXeRQqq1GFcXceZkNSr", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7iztHknuo7FAXVrrpAjsHBEEjRTaNH4b3hecVApQnSwN", - "targetOrders": "JChSqhn6yyEWqD95t8UR5DaZZtEZ1RGGjdwgMc8S6UUt", - "baseVault": "G3Szi8fUqxfZjZoNx17kQbxeMTyXt2ieRvju4f3eJt9j", - "quoteVault": "7MgaPPNa7ySdu5XV7ik29Xoav4qcDk4wznXZ2Muq9MnT", - "withdrawQueue": "C9aijsE3tLbVyYaXXHi45qneDL5jfyN8befuJh8zzpou", - "lpVault": "3CDnyBsNnexdvfvo6ASde5Q4e72jzMQFHRRkSQr49vEG", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6jx6aoNFbmorwyncVP5V5ESKfuFc9oUYebob1iF6tgN4", - "marketAuthority": "HXbRDLcX2FyqWJY95apnsTgBoRHyp7SWYXcMYod6EBrQ", - "marketBaseVault": "EVVtYo4AeCbmn2dYS1UnhtfjpzCXCcN26G1HmuHwMo7w", - "marketQuoteVault": "6ZT6KwvjLnJLpFdVfiRD9ifVUo4gv4MUie7VvPTuk69v", - "marketBids": "Hdvh4ZGL9MkiQApNqfZtdmd4jM6Sz8e9akCUuxxkYhb8", - "marketAsks": "7vWmTv9Mh8XbAxcduEqed2dLtro4N7hFroqch6mMxYKM", - "marketEventQueue": "EgcugBBSwM2FxqLQx5S6zAiU9x9qRS8qMVRMDFFU4Zty" - }, - { - "id": "8J5fa8WBGaDSv8AUpgtqdh9HM5AZuSf2ijvSkKoaCXCi", - "baseMint": "8FU95xFJhUUkyyCLU13HSzDLs7oC4QZdXQHL6SCeab36", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EEC4QnT41py39QaYnzQnoYQEtDUDNa6Se8SBDgfPSN2a", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4s8QacM13Z9Vf9en2DyM3EhKbekwnmYQTvd2RDjWAsee", - "targetOrders": "FDNvqhZiUkWwo95Q21gNimdqFQDJb5nqqttPT5uCUmBe", - "baseVault": "B5S6r6DBFgB8nxa8P7FnTwps7NAiTsFbiM6Xo7KrGtxP", - "quoteVault": "DBd8RZyBi3rdrpbXxXdcmWuTTrfkA5vfPh9HDLo1cHS", - "withdrawQueue": "CsPmj2rcDNQF85Q1bvWbieNkymtEHqyo7aXHmwHNiEKQ", - "lpVault": "9qHe2MC69BTwZY2GBJusz1rgMARsJAd6WvRu7cCYczjg", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "B7b5rjQuqQCuGqmUBWmcCTqaL3Z1462mo4NArqty6QFR", - "marketAuthority": "E4D2s9V4wuh6MMEJp7zkh6rcGgnoncJtMFFHjo4y1d5v", - "marketBaseVault": "4c4EMg5rPDx4quJdo3tL1uvQVpnoLLPKzMDn224NtER7", - "marketQuoteVault": "8MCzvWSskaoJpcXNVMui9GfzYMaMBQKPvE9GpqVZWtxq", - "marketBids": "2FafQRbcuh7sE9iPgWU7ccs5WNsSyih9rXCTZn4Bv3t2", - "marketAsks": "HJMohwcR3WUVFj9whhogSpBYzqKBjHyLcXHecArwgUEN", - "marketEventQueue": "CTZuXPjhrLb4PSNSqdsc7xUn8eiRAByfQXoi4HXkPVUe" - }, - { - "id": "8mBJC9qdPNDyrpAbrdwGbBpEAjPqwtvZQVmbnKFXXY2P", - "baseMint": "GXMvfY2jpQctDqZ9RoU3oWPhufKiCcFEfchvYumtX7jd", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CHyUpQFeW456zcr5XEh4RZiibH8Dzocs6Wbgz9aWpXnQ", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "H11WJQWj51KyYU5gdrnsXvpaYZM6ZLGULV93VbTmvaBL", - "targetOrders": "5E9x2QRpTM2oTtwb62C4rDYR8nJZxN8NFhAtnr2uYFKt", - "baseVault": "5swtuQhJQFid8uMd3DsegoxFKXVS8WoiiB3t9Pos9UHj", - "quoteVault": "Eqbux46eaW4aZiuy6VUX6z7MJ2TsszeSA7TPnpdw3jVf", - "withdrawQueue": "Hwtv6M9iTJc8SH49WjQx5rbRwzAryGm8f1NSQDmnY2iq", - "lpVault": "7YXJQ4rM59A69ow3M21MKbWEEKHbNeZQ1XFESVnbwEPx", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8BdpjpSD5n3nk8DQLqPUyTZvVqFu6kcff5bzUX5dqDpy", - "marketAuthority": "7i7rf8LANeECyi8TAwwLTyvfiVUo4x12iJtKeeA6eG53", - "marketBaseVault": "9tQtmWT3LCbVEoHFK5WK93wmDXv4us5s7NRYhficg9ih", - "marketQuoteVault": "HRFqUnxuegNbAf2auxqRwECyDijkVGDw25BCJkf5ohM5", - "marketBids": "DriSFYDLxWCEHcnFVaxKu2NrsWGB2htWhD1wkp39qxwU", - "marketAsks": "jd3YYp9WqjzyPxhBvj4ixa4DY3bCG1b74VquM4oCUbH", - "marketEventQueue": "J82jqHzNAzVYs9ZV3zuRgzRKuu1nGDFMrzJwdxvipjXk" - }, - { - "id": "8tzS7SkUZyHPQY7gLqsMCXZ5EDCgjESUHcB17tiR1h3Z", - "baseMint": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9XnZd82j34KxNLgQfz29jGbYdxsYznTWRpvZE3SRE7JG", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GJwrRrNeeQKY2eGzuXGc3KBrBftYbidCYhmA6AZj2Zur", - "targetOrders": "26LLpo8rscCpMxyAnJsqhqESPnzjMGiFdmXA4eF2Jrk5", - "baseVault": "zuLDJ5SEe76L3bpFp2Sm9qTTe5vpJL3gdQFT5At5xXG", - "quoteVault": "4usvfgPDwXBX2ySX11ubTvJ3pvJHbGEW2ytpDGCSv5cw", - "withdrawQueue": "7c1VbXTB7Xqx5eQQeUxAu5o6GHPq3P1ByhDsnRRUWYxB", - "lpVault": "2sozAi6zXDUCCkpgG3usphzeCDm4e2jTFngbm5atSdC9", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ByRys5tuUWDgL73G8JBAEfkdFf8JWBzPBDHsBVQ5vbQA", - "marketAuthority": "GVV4ZT9pccwy9d17STafFDuiSqFbXuRTdvKQ1zJX6ttX", - "marketBaseVault": "Ecfy8et9Mft9Dkavnuh4mzHMa2KWYUbBTA5oDZNoWu84", - "marketQuoteVault": "hUgoKy5wjeFbZrXDW4ecr42T4F5Z1Tos31g68s5EHbP", - "marketBids": "AuL9JzRJ55MdqzubK4EutJgAumtkuFcRVuPUvTX39pN8", - "marketAsks": "8Lx9U9wdE3afdqih1mCAXy3unJDfzSaXFqAvoLMjhwoD", - "marketEventQueue": "6o44a9xdzKKDNY7Ff2Qb129mktWbsCT4vKJcg2uk41uy" - }, - { - "id": "94CQopiGxxUXf2avyMZhAFaBdNatd62ttYGoTVQBRGdi", - "baseMint": "ETAtLmCmsoiEEKfNrHKJ2kYy3MoABhU6NQvpSfij5tDs", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "A5zanvgtioZGiJMdEyaKN4XQmJsp1p7uVxaq2696REvQ", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EdS5vqjihxRbRujPkqqzHYwBqcTP9QPbrBc9CDtnBDwo", - "targetOrders": "6Rfew8qvNp97PVN14C9Wg8ybqRdF9HUEUhuqqZBWcAUW", - "baseVault": "7zfTWDFmMi3Tzbbd3FZ2vZDdBm1w7whiZq1DrCxAHwMj", - "quoteVault": "FWUnfg1hHuanU8LxJv31TAfEWSvuWWffeMmHpcZ9BYVr", - "withdrawQueue": "F7MUnGrShtQqSvi9DoWyBNRo7FUpRiYPsS9aw77auhiS", - "lpVault": "7oX2VcPYwEV6EUUyMUoTKVVxAPAvGQZcGiGzotX43wNM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FfiqqvJcVL7oCCu8WQUMHLUC2dnHQPAPjTdSzsERFWjb", - "marketAuthority": "Cz2m3hW2Vcb8oEFz12uoWcdq8mKb9D1N7RTyXpigoFXU", - "marketBaseVault": "D8ToFvpVWmNnfJzjHuumRJ4eoJc39hsWWcLtFZQpzQTt", - "marketQuoteVault": "6RSpnBYaegSKisXaJxeP36mkdVPe9SP3p2kDERz8Ahhi", - "marketBids": "GmqbTDL5QSAhWL7UsE8MriTHSnodWM1HyGR8Cn8GzZV5", - "marketAsks": "CrTBp7ThkRRYJBL4tprke2VbKYj2wSxJp3Q1LDoHcQwP", - "marketEventQueue": "HomZxFZNGmH2XedBavMsrXgLnWFpMLT95QV8nCYtKszd" - }, - { - "id": "96hPvuJ3SRT82m7BAc7G1AUVPVcoj8DABAa5gT7wjgzX", - "baseMint": "TuLipcqtGVXP9XR62wM8WWCm6a9vhLs7T1uoWBk6FDs", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2doeZGLJyACtaG9DCUyqMLtswesfje1hjNA11hMdj6YU", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6GtSWZfdUFtT47RPk2oSxoB6RbNkp9aM6yP77jB4XmZB", - "targetOrders": "9mB928abAihkhqM6AKLMW4cZkHBXFn2TmcxEKhTqs6Yr", - "baseVault": "s9Xp7GV1jGvixdSfY6wPgivsTd3c4TzjW1eJGyojwV4", - "quoteVault": "wcyW58QFNfppgm4Wi7cKhSftdVNfpLdn67YvvCNMWrt", - "withdrawQueue": "59NA3khShyZk4dhDjFN564nScNdEi3UR4wrCnLN6rRgX", - "lpVault": "71oLQgsHknJVHGJDCaBVUnb6udGepK7kwkHXGy47u2i4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8GufnKq7YnXKhnB3WNhgy5PzU9uvHbaaRrZWQK6ixPxW", - "marketAuthority": "5uJEd4wfVH84HyFEBf5chfJMTTPHBddXi1S7GmBE6x14", - "marketBaseVault": "6qH3FNTSGKw34SEEj7GXbQ6kMQXHwuyGsAAeV5hLPhJc", - "marketQuoteVault": "6AdJbeH76BBSJ34DeQ6LLdauF6W8fZRrMKEfLt3YcMcT", - "marketBids": "69W6zLetZ7FgXPXgHRp4i4wNd422tXeZzDuBzdkjgoBW", - "marketAsks": "42RcphsKYsVWDhaqJRETmx74RHXtHJDjZLFeeDrEL2F9", - "marketEventQueue": "ExbLY71YpFaAGKuHjJKXSsWLA8hf1hGLoUYHNtzvbpGJ" - }, - { - "id": "9f4FtV6ikxUZr8fAjKSGNPPnUHJEwi4jNk8d79twbyFf", - "baseMint": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "ECoURhBe68iQtNv3CEiQnVjzWDmD4jZf3qF77CzmCJGY", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 5, - "programId": "5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h", - "authority": "3uaZBfHPfmpAHW7dsimC1SnyR61X4bJqQZKWmRSCXJxv", - "openOrders": "3zqGcrZ4wpEpXFbkQoxX4ARdBgxr7wGHvmDdETWRhJ3h", - "targetOrders": "47mYJgnTCp5bg22mx7eVLXWerYoA8S5ecKCtXFC5cbqu", - "baseVault": "7nvSNUqNqSuoPNXTqsa9kUhgRgxbsi7YwhzviNo9XPdF", - "quoteVault": "3PiJv15Ke2WZvoSRNMtZz3W8UvPzgXDPvFPi9KcRTSQe", - "withdrawQueue": "11111111111111111111111111111111", - "lpVault": "11111111111111111111111111111111", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2iDSTGhjJEiRxNaLF27CY6daMYPs5hgYrP2REHd5YD62", - "marketAuthority": "Gvc5vtXVYTnw942uEebtnrpLqhRB39wv9oaJpFVVhANP", - "marketBaseVault": "64CmtR6q3Psd1wup1hWUVLbVwM8mXZW9EpMrkM1zxd61", - "marketQuoteVault": "3G7m4634F8yFrLTdzu9yMoAB82Tt2edJAekc5i1TdTMq", - "marketBids": "GsbvB7VJ3aK5t5eS1QTs9ZT3Z8nmWqG47M55SuGPoH9r", - "marketAsks": "92aAxBLXUBQKZ9Fhfxuf3f7DWzrejpdBeZo7icHzvMxa", - "marketEventQueue": "ds6D4xBs8JY1vdJTF7NDioigPBNYje1eTmeAnawnRg7", - "modelDataAccount": "CDSr3ssLcRB6XYPJwAfFt18MZvEZp4LjHcvzBVZ45duo" - }, - { - "id": "9Hm8QX7ZhE9uB8L2arChmmagZZBtBmnzBbpfxzkQp85D", - "baseMint": "2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "GKfgC86iJoMjwAtcyiLu6nWnjggqUXsDQihXkP14fDez", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GwFM8qoBwusXVbcdfreKV9q86vqdudnVtvhYfJWgtgB", - "targetOrders": "FQp9HzJKEFfiDSnV6qyQNoz8cEKsWHnV3yFqWrT1ThgN", - "baseVault": "59STNbqDpY1sj6m95jBPRiFwjtigtivHqQeJRUofWY2a", - "quoteVault": "HXz1MFnu9ANWfCBesnrzMZMPoFbUyyqPDKT67sqgT4rk", - "withdrawQueue": "GrLKNkFVyAdV1wXoBFYxMSSPJ3BNekggiZJERrPSnAE2", - "lpVault": "AtQQZJUBrXs8nBKCHy4L2WovuEEVf7QnVWwgRdVbnKd4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HkLEttvwk2b4QDAHzNcVtxsvBG35L1gmYY4pecF9LrFe", - "marketAuthority": "GPNCigFBsjNhXu3cbmU1uxfbGVuxCA8bJN4bobwDjuTm", - "marketBaseVault": "HMPki4uRhncFhMHpLAacHCDAU4QazjgFTsB8SQgh6bMY", - "marketQuoteVault": "BeWaZ85mTxmrYfS3J9E1jQQ5tKgDRA6qmTpksKnGeNps", - "marketBids": "B38zSRMdSHYxnbsWCgY4GvSy4aRytkhqR5qVjaHsNXdA", - "marketAsks": "E4hWT9G64hLDMY7VrGXfJ5cuU8jRzJsUYAi8fqep6Sqy", - "marketEventQueue": "Bdy9encMZ7UpbEbdCgh5qDq8qQn4D31tFR45Bdas3f5y" - }, - { - "id": "9SWy6nbSVZ44XuixEvHpona663pZPpVgzXQ3N7muG4ou", - "baseMint": "ChVzxWRmrTeSgwd3Ui3UumcN8KX7VK3WaD4KGeSKpypj", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3wVrtQZsiDNp5yTPyfEzQHPU6iuJoMmpnWg6CTt4V8sR", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4dDzSb5sVQuQU7JpiELNLukEUVYoTNyhwrfTd59L3HTK", - "targetOrders": "4soQgpB1MhYjnD2cbo3aRinZh9muAAgBhTk6gLYSG4hM", - "baseVault": "CTTAtNw3TPxMhZVcrxHPjbyqEfYS7ShAf6KafC4xeJj", - "quoteVault": "EPav47MmuNRnHdiRSNpRZq9fPAvpvGb81mWfQ4TMc4VQ", - "withdrawQueue": "4DwCSyerQnxtiHc2koWWxpz31KjQdmLFe8ywWwrVkwEq", - "lpVault": "EwFVC9RA6WRBpqPjTxRmw6iYVtCGd7JoSi5MECvc3vE9", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3uWVMWu7cwMnYMAAdtsZNwaaqeeeZHARGZwcExnQiFay", - "marketAuthority": "4BRTPsziQ1QcKtsqAiXjnJe5rASuu41VXF1Bt5zpHqJs", - "marketBaseVault": "2DiofKbhznosm6ngnVXZY9r6j3WypkK6PXZu4XVhrUwS", - "marketQuoteVault": "FwRAP48S9kwXFgiBDHU4NvuGkFnqctXEurgLFZFqdt2Z", - "marketBids": "HtAQ6zXqg53WKTHoPNz6Y6nfy2vpRvaFFif13y9wWQzo", - "marketAsks": "CyMeznxwdK1vVLB8yrq1MpwZpmQ43UipnqhahrwHNj5r", - "marketEventQueue": "EiA2FLSrSJkJEGZg79eJkrAz7wtaB3jHDiXvQ4v5hZyA" - }, - { - "id": "9xyCzsHi1wUWva7t5Z8eAvZDRmUCVhRrbaFfm3VbU4Mf", - "baseMint": "poLisWXnNRwC6oBu1vHiuKQzFjGL4XDSu4g9qjz9qVk", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8MbKSBpyXs8fVneKgt71jfHrn5SWtX8n4wMLpiVfF9So", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "12A4SGay36i2cSwA4JSdvg7rWSmCz8JzhsoDqMM8Yns7", - "targetOrders": "6bszsB6zxw2YowrEm26XYhh57HKQEVMRx5YMvPSSVQNh", - "baseVault": "7HgvC7GdmUt7kMivdLMovLStW25avFsW9GDXgNr525Uy", - "quoteVault": "9FknRLGpWBqYg7fXQaBDyWWdu1v2RwUM6zRV6CiPjWBD", - "withdrawQueue": "6uN62R1i31QVoy9cmQAeDrfLccMZDjQ2gmwv2D4iBTJT", - "lpVault": "FJV66MrqZW8VYGmTuAupstwYtqfF6ULLPP9voYtnc8DS", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HxFLKUAmAMLz1jtT3hbvCMELwH5H9tpM2QugP8sKyfhW", - "marketAuthority": "FHX9fPAUVA1MxPme28f4eeVH81QVRHDWofa2V6FUJaiR", - "marketBaseVault": "5XQ7xYE3ujVA21HGbvFGVG4pLgqVHSfR9anz2EfmZ3nA", - "marketQuoteVault": "ArUDWPwzGQFfa7t7nSdkp1Dj6tYA3icXEq8K7goz9WoG", - "marketBids": "Bc5wovapX1tRjZfyZVpsGH73Gq5LGN4ANsj8kaEhfY7c", - "marketAsks": "4EHg2ANFFEKLFkpLxgiyinJ1UDWsG2p8rVoAjFfjMDKc", - "marketEventQueue": "qeQC4u5vpo5QMC17V5UMkQfK67vu3DHtBYVT1hFSGCK" - }, - { - "id": "A21ui9aYTSs3CbkscaY6irEMQx3Z59dLrRuZQTt2hJwQ", - "baseMint": "Lrxqnh6ZHKbGy3dcrCED43nsoLkM1LTzU2jRfWe8qUC", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7yieit4YsNsZ9CAK8H5ZEMvvk35kPEHHeXwp6naoWU9V", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3eCx9tQqnPUUCgCwoF5pXJBBQSTHKsNtZ46YRzDxkMJf", - "targetOrders": "rdoSiCqvxNdnzuZNUZnsXGQpwkB1jNPctiS194UtK7z", - "baseVault": "HUW3Nsvjad7jdexKu9PUbrq5G7XYykD9us25JnqxphTA", - "quoteVault": "4jBvRQSz5UDRwZH8vE6zqgqm1wpvALdNYAndteSQaSih", - "withdrawQueue": "Dt8fAfftoVcFicC8uHgKpWtdJHA8e4xCPeoVRCfounDy", - "lpVault": "FQ3XFCQAEjK1U235pgaB9nRPU1fkQaLjKQiWYYNzB5Fr", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DE6EjZoMrC5a3Pbdk8eCMGEY9deeeHECuGFmEuUpXWZm", - "marketAuthority": "4fGoqGi6jR78dU9TRdL5LvBUPjwnoUCBwxNjfFxcLaCw", - "marketBaseVault": "JDEsHM4igV84vbH3DhZKvxSTHtswcNQqVHH9RDq1ySzB", - "marketQuoteVault": "GKU4WhnfYXKGeYxZ3bDuBDNrBGupAnnh1Qhn91eyTcu7", - "marketBids": "2ngvymBN8J3EmGsVyrPHhESbF8RoBBaLdA4HBAQBTcv9", - "marketAsks": "BZpcoVeBbBytjY6vRxoufiZYB3Te4iMxrpcZykvvdH6A", - "marketEventQueue": "2sZhugKekfxcfYueUNWNsyHuaYmZ2rXsKACVQHMrgFqw" - }, - { - "id": "A7ZxDrK9LSkVXhfRTu2pRCinwYfdxW2kK6DaJk12jRWw", - "baseMint": "AD27ov5fVU2XzwsbvnFvb1JpCBaCB5dRXrczV9CqSVGb", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EN43tp8xdkcM8RYSJ4msFHMPTJRXKhUteVYBDJLwTvr3", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "E1sVmUNF4iHXLLz4yQqYufzrmzvm9aCF6NPR5C328Dzo", - "targetOrders": "9zHNsBf6kySxnPuX75muu6gm8STUWkyGjZ4od5HPmJBd", - "baseVault": "ByU8cczVRmBw3TxdKD8WUHNZgpwDPZ9ZgHTdreeTV5oX", - "quoteVault": "7GYr4FqaDsC6vUoL4nN8EfRUe1aoxbdv22jr4diurJ8C", - "withdrawQueue": "F5fCEgeh9zCKkQgN6jKnxgeMXMoSWuLhX1HW9nUmZw9Y", - "lpVault": "7JWNRx2fhWthFePZtfSx3v2eDYb2xuqGDGg8ZabjPtAw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AU8VGwd4NGRbcMz9LT6Fu2LP69LPAbWUJ6gEfEgeYM33", - "marketAuthority": "BT3TcX9UsgeVgTWN6TgvSM11mx4GbkDUCMY1mnJbkxPq", - "marketBaseVault": "3VnrHq1JWSD4DRdT1TAW4qG7nBVUFSh8mVRnkCtzV4Ry", - "marketQuoteVault": "6mSGzi7P2mM4tE6hkEsjXfZ4zR2LjctrNA3DwBvULrJU", - "marketBids": "G1K2p1C3S4SgwnFw4A4fEbmFoshAHtLmpQCdFz7BiYaD", - "marketAsks": "ESw6KKnLP3nRGtF1sgwc6EdoY5wWawkTWwa5zEjgDkHu", - "marketEventQueue": "Bii4W3FfohnHhGUDa1mA8TH82FMEQeYk48BB3zJNcfSQ" - }, - { - "id": "af8HJg2ffWoKJ6vKvkWJUJ9iWbRR83WgXs8HPs26WGr", - "baseMint": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "HYSAu42BFejBS77jZAZdNAWa3iVcbSRJSzp3wtqCbWwv", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8E2GLzSgLmzWdpdXjjEaHbPXRXsA5CFehg6FP6N39q2e", - "targetOrders": "8R5TVxXvRfCaYvT493FWAJyLt8rVssUHYVGbGupAbYaQ", - "baseVault": "D6b4Loa4LoidUor2ffouE5BTMt6tLP6MtkNrsfBWG2C3", - "quoteVault": "4gNeJniq6yqEygFmbAJa82TQjH1j3Fczm4bdeBHhwGJ1", - "withdrawQueue": "D3JQytXAydpHKUPChDe8JXdmvYRRV4EpnrxsqzMHNjFp", - "lpVault": "2dYW9SoJb51YNneQG7AywSB75jmzZa2R8rzzW7gT61h1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AtNnsY1AyRERWJ8xCskfz38YdvruWVJQUVXgScC1iPb", - "marketAuthority": "4yWr7H2p8rt11QnXb2yxQF3zxSdcToReu5qSndWFEJw", - "marketBaseVault": "GxPFMyeb7BUnu2mtGV2Zvorjwt8gxHqwL3r2kVDe6rZ8", - "marketQuoteVault": "149gvUQZeip4u8bGra5yyN11btUDahDVHrixzknfKFrL", - "marketBids": "EE2CYFBSoMvcUR9mkEF6tt8kBFhW9zcuFmYqRM9GmqYb", - "marketAsks": "nkNzrV3ZtkWCft6ykeNGXXCbNSemqcauYKiZdf5JcKQ", - "marketEventQueue": "2i34Kriz23ZaQaJK6FVhzkfLhQj8DSqdQTmMwz4FF9Cf" - }, - { - "id": "Am9FpX73ctZ3HzohcRdyCCv84iT7nugevqLjY5yTSUQP", - "baseMint": "4dmKkXNHdgYsXqBHCuMikNQWwVomZURhYvkkX5c4pQ7y", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "2k4quTuuLUxrSEhFH99qcoZzvgvVEc3b5sz3xz3qstfS", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BFxUhqhrUWqMMazhef1dwDGXDo1LkQYV2YAgMfY81Evo", - "targetOrders": "AKp1o6Nxe224Z8z4tFzyFKdCRoJDFpCen1xHyGXfyxKu", - "baseVault": "BjJMnG8c4zMHHZrvxP6ydKYGPkvXL5fF9gC38rtAu2Sx", - "quoteVault": "7dwpWj95qzPoBFCL7qzgoj9zhjmNNoDyncbyJEYiRfv7", - "withdrawQueue": "6g5sTJtMw1r9vx4RP5YkN3ZJpSssh7eH8QdVK986xLS2", - "lpVault": "9tHcrwFdxNNzosaTkqrejHNXkr2HasKSwczimjBh2F8Z", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HFAsygpAgFq3f9YQ932ptoEsEdBP2ELJSAK5eYAJrg4K", - "marketAuthority": "3enyrrweGCtkVDvaiAkSo2d2tF7B899tWHGSDfEGKtNs", - "marketBaseVault": "F1LcTLXQhFf9ymAHnxFNovSdZttZiVjRBoqQxyPAEipj", - "marketQuoteVault": "64UEnruJCyjKUz8vdgZh3FwWwd53oSMY9Knd5dt5oVuK", - "marketBids": "6A6njiM3ByNbopETpEfbqsQci3NZecTzheg2YACVFXjc", - "marketAsks": "8YvHQkUCB7HxCAu3muytUTbEXuDGmroVcnwbkXydzyEH", - "marketEventQueue": "8syFMq2kMQV9beCJ9Y5T9TARgUii6aND5MDgDEAAGF73" - }, - { - "id": "AMMwkf57c7ZsbbDCXvBit9zFehMr1xRn8ZzaT1iDF18o", - "baseMint": "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "DgGuvR9GSHimopo3Gc7gfkbKamLKrdyzWkq5yqA6LqYS", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "G5rZ4Qfv5SxpJegVng5FuZftDrJkzLkxQUNjEXuoczX5", - "targetOrders": "DMEasFJLDw27MLkTBFqSX2duvV5GV6LzwtoVqVfBqeGR", - "baseVault": "7KwCHoQ9nqTnGea4XrcfLUr1pwEWp2maGBHWFqBTeoKW", - "quoteVault": "HwbXe9YJVez3BKK22jBH1i64YeX2fSKaYny5jrcPDxAk", - "withdrawQueue": "3XUXNx72jcaXB3N56UjrtWwxv99ivqUwLAdkagvop4HF", - "lpVault": "8rZSQ23HWfZ1P6qd9ZL4ywTgRYtRZDd3xW3aK1hY7pkR", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "C1EuT9VokAKLiW7i2ASnZUvxDoKuKkCpDDeNxAptuNe4", - "marketAuthority": "EPzuCsSzHwhYWn2j69HQPKWuWz6wuv4ANZiVigLGMBoD", - "marketBaseVault": "DSf7hGudcxhhegMpZA1UtSiW4RqKgyEex9mqQECWwRgZ", - "marketQuoteVault": "BD8QnhY2T96h6KwyJoCT9abMcPBkiaFuBNK9h6FUNX2M", - "marketBids": "2e2bd5NtEGs6pb758QHUArNxt6X9TTC5abuE1Tao6fhS", - "marketAsks": "F1tDtTDNzusig3kJwhKwGWspSu8z2nRwNXFWc6wJowjM", - "marketEventQueue": "FERWWtsZoSLcHVpfDnEBnUqHv4757kTUUZhLKBCbNfpS" - }, - { - "id": "AoPebtuJC4f2RweZSxcVCcdeTgaEXY64Uho8b5HdPxAR", - "baseMint": "2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "13PoKid6cZop4sj2GfoBeujnGfthUbTERdE5tpLCDLEY", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7PwhFjfFaYp7w9N8k2do5Yz7c1G5ebp3YyJRhV4pkUJW", - "targetOrders": "BV2ucC7miDqsmABSkXGzsibCVWBp7gGPcvkhevDSTyZ1", - "baseVault": "EHT99uYfAnVxWHPLUMJRTyhD4AyQZDDknKMEssHDtor5", - "quoteVault": "58tgdkogRoMsrXZJubnFPsFmNp5mpByEmE1fF6FTNvDL", - "withdrawQueue": "9qPsKm82ZFacGn4ipV1DH85k7efP21Zbxrxbxm5v3GPb", - "lpVault": "2WtX2ow4h5FK1vb8VjwpJ3hmwmYKfJfa1hy1rcDBohBT", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4tSvZvnbyzHXLMTiFonMyxZoHmFqau1XArcRCVHLZ5gX", - "marketAuthority": "C5v68qSzDdGeRcs556YoEMJNsp8JiYEiEhw2hVUR8Z8y", - "marketBaseVault": "7Nw66LmJB6YzHsgEGQ8oDSSsJ4YzUkEVAvysQuQw7tC4", - "marketQuoteVault": "EsDTx47jjFACkBhy48Go2W7AQPk4UxtT4765f3tpK21a", - "marketBids": "8tFaNpFPWJ8i7inhKSfAcSestudiFqJ2wHyvtTfsBZZU", - "marketAsks": "2po4TC8qiTgPsqcnbf6uMZRMVnPBzVwqqYfHP15QqREU", - "marketEventQueue": "Eac7hqpaZxiBtG4MdyKpsgzcoVN6eMe9tAbsdZRYH4us" - }, - { - "id": "asdEJnE7osjgnSyQkSZJ3e5YezbmXuDQPiyeyiBxoUm", - "baseMint": "GsNzxJfFn6zQdJGeYsupJWzUAm57Ba7335mfhWvFiE9Z", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4HFaSvfgskipvrzT1exoVKsUZ174JyExEsA8bDfsAdY5", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4zuyAKT81y9mSSrjq8sN872zwgcD5ncQGyCXwRJDn6tC", - "targetOrders": "H2GMj87upPeBQT3ywzqudJodwyTFpPmwuwtiZ7DQB8Md", - "baseVault": "FHAqAqqdyZFaxUTCg19hH9pRfKKChwNekFrY428NVPtT", - "quoteVault": "7jzwUCSq1R1QX72PKRDjZ4xgUm6Q6iiLW9BY8tnj8wkc", - "withdrawQueue": "3WBnh4HbddG6sMvv6s1GALVLPq6xfwVat3WqufZKKFXa", - "lpVault": "9DRSmvcrXC7AtNrhf9tgfBuwT4q5hXyWaAybe5yfRU7q", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DYfigimKWc5VhavR4moPBibx9sMcWYVSjVdWvPztBPTa", - "marketAuthority": "y6FHXgMwWvvpoiox6Ut6mUAUHgbJMXNJnXQm7MQkEdE", - "marketBaseVault": "9ZaKDVrjCaPRZTqnuteGc8iBmJhdaGVf8JV2HBT67wbX", - "marketQuoteVault": "5Y65XyuJemmRU7G1AQQTvWKSge8WDVYhb2knd7htJHoh", - "marketBids": "2Z6Do29oGtze6dnVMXAVw8mkRxFpLGc8uS2RjfrWoCyy", - "marketAsks": "FosLnuNKUKqfqYviAPdp1doC3dKpXQXvAeRGM5xAoUCJ", - "marketEventQueue": "EW5QgqGUZ7dSmXLXiuWB8AAsjSjpb8kaaoxAUqK1DWyg" - }, - { - "id": "ASZQnZRRDLF3Fzu8pjow8mWneBQakMNiVJUBgMLPpwhF", - "baseMint": "FANTafPFBAt93BNJVpdu25pGPmca3RfwdsDsRrT3LX1r", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GdAhnP6fwhQUmQC1Pw1NvvWFwNqz8Pt4TWeH7DwkGzpB", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HjJPj9WiVc5g4Z1VB8nJTtrTSow8agjiRYdCbNnGXeJM", - "targetOrders": "HN1iZ3qTCBCGujghEbKGWfynCFhBkthnU5gpEmuzNtw6", - "baseVault": "BCPrE8fB4HQW3gsFgecX2YpNrXYUpByErJ3xvXAEgfKC", - "quoteVault": "5Y9FQtJtnNfPvo29q4UBGwUkVEYourFAJ9coSyqWK15r", - "withdrawQueue": "xDWSFcetrCJPP9aZzCScJ9RwGizHHMzLV12Y5GRzNuY", - "lpVault": "BgNJ913fJKDnVxhq8bepK2gpDxM9L4aqoCa5psx7t3Mx", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4rtLjEACKFbUxGB2zrWxNkRnCNbSr7ES1ZsXrTd6mhbr", - "marketAuthority": "DyQcNBSVbxksfiHTd6Xe4JGjyoiSorUerVqqm2qjGAk5", - "marketBaseVault": "Hgt55e2QadHXmef1Sp4Xvx6Lg7ss29nq63pk8PKSvsv3", - "marketQuoteVault": "CBuPHevzRU9Jc244b1452dNDT99xLCjnASe8nUF1Vk56", - "marketBids": "7kewioJvrRoy6FnTGr7S63kW8W3cMzDhg7GrjSuUTKM5", - "marketAsks": "C3VBBiAVH3h7HEUP4gNxMrptixiGgesLKcyoSDW1TjoQ", - "marketEventQueue": "HfuH5L933CKevZ7XucsSkMMV8KcqN2Rf6na7qiStTZaz" - }, - { - "id": "AVs9TA4nWDzfPJE9gGVNJMVhcQy3V9PGazuz33BfG2RA", - "baseMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "89ZKE4aoyfLBe2RuV6jM3JGNhaV18Nxh8eNtjRcndBip", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6Su6Ea97dBxecd5W92KcVvv6SzCurE2BXGgFe9LNGMpE", - "targetOrders": "5hATcCfvhVwAjNExvrg8rRkXmYyksHhVajWLa46iRsmE", - "baseVault": "Em6rHi68trYgBFyJ5261A2nhwuQWfLcirgzZZYoRcrkX", - "quoteVault": "3mEFzHsJyu2Cpjrz6zPmTzP7uoLFj9SbbecGVzzkL1mJ", - "withdrawQueue": "FSHqX232PHE4ev9Dpdzrg9h2Tn1byChnX4tuoPUyjjdV", - "lpVault": "87CCkBfthmyqwPuCDwFmyqKWJfjYqPFhm5btkNyoALYZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "C6tp2RVZnxBPFbnAsfTjis8BN9tycESAT4SgDQgbbrsA", - "marketAuthority": "7SdieGqwPJo5rMmSQM9JmntSEMoimM4dQn7NkGbNFcrd", - "marketBaseVault": "6U6U59zmFWrPSzm9sLX7kVkaK78Kz7XJYkrhP1DjF3uF", - "marketQuoteVault": "4YEx21yeUAZxUL9Fs7YU9Gm3u45GWoPFs8vcJiHga2eQ", - "marketBids": "C1nEbACFaHMUiKAUsXVYPWZsuxunJeBkqXHPFr8QgSj9", - "marketAsks": "4DNBdnTw6wmrK4NmdSTTxs1kEz47yjqLGuoqsMeHvkMF", - "marketEventQueue": "4HGvdannxvmAhszVVig9auH6HsqVH17qoavDiNcnm9nj" - }, - { - "id": "B5ZguAWAGC3GXVtJZVfoMtzvEvDnDKBPCevsUKMy4DTZ", - "baseMint": "z3dn17yLaGMKffVogeFHQ9zWVcXgqgf3PQnDsNs2g6M", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "FwaX9W7iThTZH5MFeasxdLpxTVxRcM7ZHieTCnYog8Yb", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FVb13WU1W1vFouhRXZWVZWGkQdK5jo35EnaCrMzFqzyd", - "targetOrders": "FYPP5v8SLHPPcivgBJPE9FgrN6o2QVMB627n3XcZ8rCS", - "baseVault": "6ttf7G7FR9GWqxiyCLFNaBTvwYzTLPdbbrNcRvShaqtS", - "quoteVault": "8orrvb6rHB776KbQmszcxPH44cZHdCTYC1fr2a3oHufC", - "withdrawQueue": "4Q9bNJsWreAGhkwhKYL7ApyhEBuwNxiPkcEQNmUjQGHZ", - "lpVault": "E12sRQvEHArCULaJu8xppoJKQgJsuDuwPVJZJRrUKYFu", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HcVjkXmvA1815Es3pSiibsRaFw8r9Gy7BhyzZX83Zhjx", - "marketAuthority": "Bf9MhS6hwAGSWVJ4uLWKSU6fqPAEroRsHX6ithEjGXiG", - "marketBaseVault": "FcDWM8eKUEny2wxopDMrZqgmPr3Tmoen9Dckh3MoVX9N", - "marketQuoteVault": "9ya4Hv4XdzntjiLwxpgqnX8eP4MtFf8YWEssF6C5Pqhq", - "marketBids": "DaGRz2TAdcVcPwPmYF5JJ7d7kPWvLN68vuBTTMwnoM3T", - "marketAsks": "3ZRtPBQVcjCpVmCt4xPPeJJiUnDDbrc5jommVHGsDLnT", - "marketEventQueue": "C5SGEXUCmN1LxmxapPn2XaHX1FF7fAuQG5Wu4yuu8VK6" - }, - { - "id": "BhuMVCzwFVZMSuc1kBbdcAnXwFg9p4HJp7A9ddwYjsaF", - "baseMint": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "69NCmEW9mGpiWLjAcAWHq51k4ionJZmzgRfRT3wQaCCf", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "67xxC7oyzGFMVX8AaAHqcT3UWpPt4fMsHuoHrHvauhog", - "targetOrders": "HrNUwbZF4NPRSdZ9hwD7EWV1cwQoJ9Yhu9Jf7ybXALpe", - "baseVault": "FaoMKkKzMDQaURce1VLewT6K38F6FQS5UQXD1mTXJ2Cb", - "quoteVault": "GE8m3rHHejrNf4jE96n5gzMmLbxTfPPcmv9Ppaw24FZa", - "withdrawQueue": "4J45miDrQ5UdqpLzunHAYUqTg8A78CHKeBwa6a1TvFeF", - "lpVault": "7WCk8sFJiUnpGbzHpFF9FsV5oJQgKs5iBERysFDyywnq", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HxkQdUnrPdHwXP5T9kewEXs3ApgvbufuTfdw9v1nApFd", - "marketAuthority": "QMhH9Mnv1jg8tLNanAvKf3ymbuzh7sDENyjCgiyn3Kk", - "marketBaseVault": "FgVVda2Wnp2PuDpuh23B341qZx2cnArqVNSgxsU877Y", - "marketQuoteVault": "2PtdrUGJd7aYoMKXpQ5d19r5Aa1z8dkRj6NNRCNGTE3D", - "marketBids": "wNv6YZ31PX5hS42XCijwgd7SuMAu63aPvDWjMNTM2UP", - "marketAsks": "7g28QYJPPNypyPvoAdir8WzPT2Me78u78jufiG7M3wym", - "marketEventQueue": "Ee9UPY9CH2jHx2LLW2daLyc9VS5Bnp4yTykw4aveeXLX" - }, - { - "id": "Bhw7DbVwWMcTBXoKaWgsCaofL6QqmQQ65FCSGfgCEawm", - "baseMint": "5U9QqCPhqXAJcEv9uyzFJd5zhN93vuPk1aNNkXnUfPnt", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "B5uyCAQcX6nAjZypLgiivbEKabSptgUb8JK9tkaSnqdW", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8jG2uaaeBSKDDCw91qoKD8zcyCmXVbjoVz6MwyoY9hY1", - "targetOrders": "CHXWrG2DV2T6ty4tEL2sFWhNq8JyDeYRiEWMKT3k6Jhh", - "baseVault": "31ug6DXqFG94kza6rqEc2j4Q4PCCncXapAFZcxMg7nPA", - "quoteVault": "HucTXQXnH7RgmDimkZZ5GuUTdXVjRnc9DwNoDaM5cVXg", - "withdrawQueue": "C1uTwAJC6Vic3WXJC5iAFLvjc3sFwiGM8ATmhKkfZhkV", - "lpVault": "GskjHddFmXpj4RtMfCDmKscD9qUfDkEfzPp3b15ZeruW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CMxieHNoWYgF5c6wS1yz1QYhxpxZV7MbDMp8c7EpiRGj", - "marketAuthority": "E623iAaJJzw5NJLBCtpFZbcn8iEnY3BsFHYfG1CYf2cm", - "marketBaseVault": "EiQdjxmFWZeyRxizBfXPsXQrnsU6KfBvnANeXYvimELr", - "marketQuoteVault": "5q1aff7VkkyHB6LvRg24PVEZNJCDPzcQpp29DuP2Gfjj", - "marketBids": "5Mb67cTCeGgbEWwdXXw1qDTBeH27ZuHPEoLojqyDmwhX", - "marketAsks": "9o8AxfYsiT5cv63rR1zrYr7r6jw7bP3p2pH9cJNAVo6X", - "marketEventQueue": "2iTAShfDpxohfYM6stE3HVSUpXJ5m1sNzEFMeHKbAmQn" - }, - { - "id": "BkfGDk676QFtTiGxn7TtEpHayJZRr6LgNk9uTV2MH4bR", - "baseMint": "MERt85fc5boKw3BW1eYdxonEuJNvXbiMbs6hvheau5K", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3H9NxvaZoxMZZDZcbBDdWMKbrfNj7PCF5sbRwDr7SdDW", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FNwXaqyYNKNwJ8Qc39VGzuGnPcNTCVKExrgUKTLCcSzU", - "targetOrders": "DKgXbNmsm1uCJ2eyh6xcnTe1G6YUav8RgzaxrbkG4xxe", - "baseVault": "6XZ1hoJQZARtyA17mXkfnKSHWK2RvocC3UDNsY7f4Lf6", - "quoteVault": "F4opwQUoVhVRaf3CpMuCPpWNcB9k3AXvMMsfQh52pa66", - "withdrawQueue": "8mqpqWGL7W2xh8B1s6XDZJsmPuo5zRedcM5sF55hhEKo", - "lpVault": "9ex6kCZsLR4ZbMCN4TcCuFzkw8YhiC9sdsJPavsrqCws", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "G4LcexdCzzJUKZfqyVDQFzpkjhB1JoCNL8Kooxi9nJz5", - "marketAuthority": "BUDJ4F1ZknbZiwHb6xHEsH6o1LuW394DE8wKT8CoAYNF", - "marketBaseVault": "4ctYuY4ZvCVRvF22QDw8LzUis9yrnupoLQNXxmZy1BGm", - "marketQuoteVault": "DovDds7NEzFn493DJ2yKBRgqsYgDXg6z38pUGXe1AAWQ", - "marketBids": "DVjhW8nLFWrpRwzaEi1fgJHJ5heMKddssrqE3AsGMCHp", - "marketAsks": "CY2gjuWxUFGcgeCy3UiureS3kmjgDSRF59AQH6TENtfC", - "marketEventQueue": "8w4n3fcajhgN8TF74j42ehWvbVJnck5cewpjwhRQpyyc" - }, - { - "id": "BKLCqnuk4qc5iHWuJuewMxuvsNZXuTBSUyRT5ftnRb6H", - "baseMint": "MERt85fc5boKw3BW1eYdxonEuJNvXbiMbs6hvheau5K", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "214hxy3AbKoaEKgqcg2aC1cP5R67cGGAyDEg5GDwC7Ub", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "qDqpetCPbbV2n8bgcy4urhDcKYkUNVoEn7xaCQSDzKv", - "targetOrders": "7KU9VPAZ8BMXA29gadnpssgtcoo4Tm1LYnc6Sn5HefcL", - "baseVault": "rmnAGzEwFnim88JLhqj66B86QLJL6cgm3tPDfGiKqZf", - "quoteVault": "4Lm4c4NqNyobLGULtHRtgoG4hbX7ytuGQFFcdip4jvBb", - "withdrawQueue": "9qwtjaEnTCHFf6GuTNxPf85hFzJVNJAAXJnWNFi4DmkX", - "lpVault": "H9uyyChWbaXCmNmQu3g4fqKF5xsa7YVZiMvGcsVrCcNn", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "75yk6hSTuX6n6PoPRxEbXapJbbXj4ynw3gKgub7vRdUf", - "marketAuthority": "FCf82FB2TFAfH4YEDkBJtEeSkTK1EQFc27d1iSnvXMjk", - "marketBaseVault": "EaFu94rusrGHjJWhuuUbKWW2AJizDGbpWJXJa4cxmLCP", - "marketQuoteVault": "ApZdrWpBu2uLkYAeVLneWnDhVrbR6TjhjbBR78kpg5r2", - "marketBids": "56zkA91Mad1HBJpiq8baMi9XhvvnTRNyd6m8hzeu5arh", - "marketAsks": "BgovKK4YP6ZgLUHsnXeUym1BH5BSjUxDuinTk6shPuzd", - "marketEventQueue": "5NVyybcVeC8wqjgBj3ZxaX3RauWa2iqvdXkUYPJnistu" - }, - { - "id": "BLVjPTgzyfiKSgDujTNKKNzW2GXx7HhdMxgr2LQ2g83s", - "baseMint": "AR1Mtgh7zAtxuxGd2XPovXPVjcSdY3i4rQYisNadjfKy", - "quoteMint": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "lpMint": "3HYhUnUdV67j1vn8fu7ExuVGy5dJozHEyWvqEstDbWwE", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Efpi6e4ckqtfaED9gRmadN3RtiTXDtGPrp1szsh7sj7C", - "targetOrders": "BZUFGpRWEsYzpVfLrFpdE7E9fzGhrySQE1TrsX92qWAC", - "baseVault": "BjWKHZxVMQykmGGmkhA1m9QQycJTeQFs51kyfP1zQvzv", - "quoteVault": "EnWaAD7WAyznuRjg9PqRr2vVaXqQpTje2fBWyFFEvr37", - "withdrawQueue": "GbEc9D11VhEHCDsqcSZ5vPVfnzV7BCS6eTquoVvhSaNz", - "lpVault": "AQ4YUkqPSbP8JpnCWEAkYNUWm6AjUSnPucKhVN8ypuiB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FGYAizUhNEC9GBmj3UyxdiRWmGjR3TfzMq2dznwYnjtH", - "marketAuthority": "HZtDGZsz2fdXF75H8tyB8skp5a4rvoawgxwXqHTGEdvU", - "marketBaseVault": "BSoAoNFKzK65TjcUpY5JZHBvZVMiYnkdo9upy3mLSTpq", - "marketQuoteVault": "8U9azb65o1dJuMs7je987i7hKxJfPZnbNRNeH5beJfo7", - "marketBids": "J9weS4eF3DcSMLttazndEwVtjsqfRf6vBg1FNhdYrKiW", - "marketAsks": "4TCPXw9UBcPfSVtaArzydHvgAXfDbq28iZVjHidbM9rp", - "marketEventQueue": "2eJU3EygyV4SWGAH1g5F57CxtaTj4nL36apaRtnEZ9zH" - }, - { - "id": "BPg6Tp8ynURqoxdCPVtZJM1K9MW7PSTxr5KAvDaFJV69", - "baseMint": "AkhdZGVbJXPuQZ53u2LrimCjkRP6ZyxG1SoM85T98eE1", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6o4gmzih4Xr36UAd1NdJg8BunYGY4Dde32eJ1TMh74N4", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BrgX16ooPYhBsFAC12PmiMRBhCcArgzTgVM6wPk1iXkv", - "targetOrders": "2Rrsg8DJUf7p1p8ARsJ9mMW19DXuuZ92VfQKj25KMJT5", - "baseVault": "AV3J3UDeT5nCTrMLGu9XvHcuGV22Dzt3A5RZ4AfmjZbJ", - "quoteVault": "7F6QN5fbpSmvBSPNo3e1Ek3duxokGhskRksfNPZURUuE", - "withdrawQueue": "5Vmv7dEuV5YHJxJ9zmMoyzTNYutvCHaDeLL1M8ABgoS2", - "lpVault": "AK2fUTT5DQFevaiFowinhEcKdjCaqjuHTrWjbGUKvUtm", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EbtdM5qD52MBb8mKLXfFc2G8wpzP4mMhtsdAJzvZ9tfC", - "marketAuthority": "BXxkijy8KdvQ47kdTYEsoFtHRibUyHEvsjp4aaV9nJnK", - "marketBaseVault": "6SusNVZk3Jx4FsganHrE6asqoRKvPJr8kFgVJU99S7gx", - "marketQuoteVault": "DKHSzMBqonDh37ThvwZ68CWzPDjfPyYNX3tG4Zcxn89z", - "marketBids": "8ha4skhcohrda3bkQsjEcChuN6nYwawewBs7GWFHYXpo", - "marketAsks": "DSFcaeqKgh9zMafAWbwpuvZsLoztxASdWNUn7csbjYrD", - "marketEventQueue": "JDhTybaqoUATJ6JYCPsdyyQUzL5guN383cSkiinBAFmK" - }, - { - "id": "BuS4ScFcZjEBixF1ceCTiXs4rqt4WDfXLoth7VcM2Eoj", - "baseMint": "8PMHT4swUMtBzgHnh5U564N5sjPSiUz2cjEQzFnnP1Fo", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Cq4HyW5xia37tKejPF2XfZeXQoPYW6KfbPvxvw5eRoUE", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ASkE1yKPBei2aUxKHrLRptB2gpC3a6oTSxafMikoHYTG", - "targetOrders": "5isDwR41fBJocfmcrcfwRtTnmSf7CdssdpsmBy2N2Eym", - "baseVault": "3mS8mb1vDrD45v4zoxbSdrvbyVM1pBLM31cYLT2RfS2U", - "quoteVault": "BWfzmvvXhQ5V8ZWDMC4u82sEWgc6HyRLnq6nauwrtz5x", - "withdrawQueue": "9T1cwwE5zZr3D2Rim8e5xnJoPJ9yKbTXvaRoxeVoqffo", - "lpVault": "FTFx4Vg6hgKLZMLBUvazvPbM7AzDe5GpfeBZexe2S6WJ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4Sg1g8U2ZuGnGYxAhc6MmX9MX7yZbrrraPkCQ9MdCPtF", - "marketAuthority": "rCFXUwdmQvRK9jtnCip3SdDm1cLn8nB6HHgEHngzfjQ", - "marketBaseVault": "F8PdvS5QFhSqgVdUFo6ivXdXC4nDEiKGc4XU97ZhCKgH", - "marketQuoteVault": "61zxdnLpgnFgdk9Jom5f6d6cZ6cTbwnC6QqmJag1N9jB", - "marketBids": "BDYAnAUSoBTtX7c8TKHeqmSy7U91V2pDg8ojvLs2fnCb", - "marketAsks": "Bdm3R8X7Vt1FpTruE9SQVESSd3BjAyFhcobPwAoK2LSw", - "marketEventQueue": "HVzqLTfcZKVC2PanNpyt8jVRJfDW8M5LgDs5NVVDa4G3" - }, - { - "id": "CbGQojcizFEHn3woL7NPu3P9BLL1SWz5a8zkL9gks24q", - "baseMint": "4Hx6Bj56eGyw8EJrrheM6LBQAvVYRikYCWsALeTrwyRU", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BjkkMZnnzmgLqzGErzDbkk15ozv48iVKQuunpeM2Hqnk", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "75hTsLMn57111C8JwG9uqrkw6iZsFtyU8CYQYSzM2CY8", - "targetOrders": "3pbY7NyETK3UBG1yvaFjqeYPLXMd2wHgcZVJi9LZVdx1", - "baseVault": "45pPLPHYUJ7ainr9eqPzdKcWJSbGuoUwcMcMamAXgcCX", - "quoteVault": "7aE4zihDvU58Uua8W82Q2u915rKqzpmpWPxZSDdeXrwu", - "withdrawQueue": "2r8yHQGdydgngeTXdqsM2P2ZWVmwRAe3Kq3MLTCQPpHD", - "lpVault": "DBmenZarP1WQx9uvrKQQj3pNfhmNanZ9ns5tpMYpDcyJ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GNmTGd6iQvQApXgsyvHepDpCnvdRPiWzRr8kzFEMMNKN", - "marketAuthority": "DD6e6WMaZ3JePsBNP9Eoz9aJsD3bZ81EjMvUSWF96qQx", - "marketBaseVault": "CXxN6hGatd5nK7uPwxvxHYmqvM4b88eKb9fcHapRhtda", - "marketQuoteVault": "NMWKX4jfzkKvRBYkcvurus8aofaHZ8MwMNYqudztWZh", - "marketBids": "89Ux1PrzAVv5tejtCQhfs5tqEfQdb3WQsfY6f7BzQtsN", - "marketAsks": "36eRuVT8kyWq1UbZeYf66q5EhUpNP2Kq8TgffyVbHEzF", - "marketEventQueue": "4GX63nbB8SHwDeDpuSKacfch1ANTLp4zn8ivkcTjCnEn" - }, - { - "id": "CfBSfVTcYFJsD8vZ2fTiMGkUYFim2rv8weAoqHxUU2pn", - "baseMint": "NFTUkR4u7wKxy9QLaX2TGvd9oZSWoMo4jqSJqdMb7Nk", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8i44Y23GkkwDYZ5iSkVEqmrXUfwNmwo9grguTDWKM8wg", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2ivrPyyMKcMmaAWcA6VReQ3qT41htQTJ4kfGcxGRiPTj", - "targetOrders": "GBkiJYXviRDBDoXRbaK5BArHeisTYo3C65FgwjmXmCzL", - "baseVault": "GNzNnmSnXo1gABhtkgHvMfimQQMhwSz1RS4amTYaSN9y", - "quoteVault": "BW2FHugQqPPgMrGRtfm1BaR5R3WP9TBCjnYt4PHcpbUn", - "withdrawQueue": "2fzhi1Qxp4FvFk4WNj1SV8kKe7kF4ZQgwLoopkQ4g2iL", - "lpVault": "GF6jDvmss3JinbbXh9EdZUo343ZRoFELEzJgnGM4WwBL", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2b6GbUbY979QhRoWb2b9F3vNi7pcCGPDivuiKPHC56zY", - "marketAuthority": "5TXTSZpWoVoJpfdf848ov8pj9NYJZ7we9BM746sMUyfF", - "marketBaseVault": "6Fxz92QGSJrWEmHFuxqMJwBiq1MPxLNzQfKw5ZRsLWRw", - "marketQuoteVault": "LcANK8GJ4uY47QyDitYBiQUzHkHWKCuoPXdCq3YLxW3", - "marketBids": "FEmTdsfmszMxwi34aawEsZPT1cWqa41StEBfYnnshDYx", - "marketAsks": "CMnyFZKG8zWWajbtZfduqtRX74cRyyVKXakM6NYe7MAN", - "marketEventQueue": "2rrYmuEieEyRTBKF39AqTdskde8kLfVSieanVWyCZNJQ" - }, - { - "id": "Cj7kD2VmzwSrwKBieuYYbjPEvr8gwhNi76KUESbGDNfF", - "baseMint": "nosXBVoaCTtYdLvKY6Csb4AC8JCdQKKAaWYtx2ZMoo7", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7HwjdFEyGu7tQia33GFB4iFEa5dA7k4gr6BWUGS7tyyq", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DEM1Zse8UWfKEk9dH1Jkjzepdb9DSaxMZ8uDe34rmbE5", - "targetOrders": "2XNpMn3zB1jKKCHkchHUUk5A3DWGNi3wcCf54cqpj4g7", - "baseVault": "9Gs4LvFZw18EBLrSmZbQBw4G2SpTu4bJRCWH1Dz33cUZ", - "quoteVault": "FqKU4BxbabPd1tcZAVVv8JkdUWmdz32CocRM856gA3Lw", - "withdrawQueue": "F6RxBH334HoBXEJUE9p31HNcBSxe8J2mnpkscan3KpHa", - "lpVault": "94nNYdTKstTkPkhBBCyEtHu3cALAq3FACC4DXLH7sXHx", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8XaEfk3TURqgrJZvdJWrPLqyXSCmJ9MfSwZrkaYmsG7r", - "marketAuthority": "22shFXrQFRFxvHVHMppAcWp8yG77ZrRWZrxeg3g39xEh", - "marketBaseVault": "9ocmLQu6ECKAG2SgNaiRJE2i39JvAKpy4hNtdAcne7Pw", - "marketQuoteVault": "5y1rS8mE6yTUub15y7z6Lo8QXcY9DrkGGYhzTJDav9Df", - "marketBids": "Dce8vCTs8sqHR9phF6TPeeKKQ6qmJ7PhawiFkcATZPHF", - "marketAsks": "BxoLDGQiBXyFuV9icqhHoXc3FrwF6mPvvKazkHfL9e1G", - "marketEventQueue": "6gEAWchqQiw96LFUw5awYN3svftvr1aWZvMa12ob6C1P" - }, - { - "id": "CrWbfKwyAaUfYctXWF9iaDUP4AH5t6k6bbaWnXBL8nHm", - "baseMint": "sonarX4VtVkQemriJeLm6CKeW3GDMyiBnnAEMw1MRAE", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2tAcfqJ1YYjpGLqwh76kyNt9VaNFDd4fJySfH6SmWfKt", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Ei23wxsu7WVsXv72yaTohSVASLqseinqA7DqXktprSSz", - "targetOrders": "NheF95jviuoA9Rv5QPQgXDT3oQUbyoHJcyY5yXAFFnh", - "baseVault": "DQX9NhwznyWTYcTJ8uiqZP3PrzqRmfGNj4XNQzVKG8hW", - "quoteVault": "AseLV5kWbAjNETCKJsXcrrs6ksvBefEPdRa7pKXFsvYE", - "withdrawQueue": "5mkppasqox6XpdcHhYAfM1GKTckQemqtANP85FphThw8", - "lpVault": "9TjtDU6TMgHqAEdnUTBCgVJapGsqKnDTCFzDG2y4higa", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9YdVSNrDsKDaGyhKL2nqEFKvxe3MSqMjmAvcjndVg1kj", - "marketAuthority": "44rLzbRfxmpsmHPZUEuLS6rxv9pyDBVnzUSps8mGaEr2", - "marketBaseVault": "EzMjpFVMZE4VrqbeGCXssfvDbpvHGMtHvkiLbX1YUTs7", - "marketQuoteVault": "B8A7V1124ka8WVKDHyWMAgbHCaCdhbU7JHy2nB7e2o6E", - "marketBids": "B6t3JoptHoNer3YgEUZASeQwcXEnhvGH4ovYeVdGW2c7", - "marketAsks": "ACEdfnzBEFRopUkLwqowPuQpiMbuYR4uCk85wdxUvVWp", - "marketEventQueue": "Vq6g4iaDJhqB8PeUPf99JixtpdQ6zrdXXNuQ2LrGyvV" - }, - { - "id": "CWQVga1qUbpZXjrWQRj6U6tmL3HhrFiAT11VYnB8d3CF", - "baseMint": "HCgybxq5Upy8Mccihrp7EsmwwFqYZtrHrsmsKwtGXLgW", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FJ68q7NChhETcGVdinMbM2FF1Cy79dpmUi6HC83K55Hv", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "D3bJNYcUhza55mdGFTAUi4CLE12f54qzMcPmawoBCNLc", - "targetOrders": "FNjcSQ7VB7ULoSU7BDTotiRDmqiQj7CvVxHALnYC5JGP", - "baseVault": "5NtsnqVNXGmxs6zEU73W2RaFh4e58gqdWrxMvzcqNxGk", - "quoteVault": "MZihwPviJgm5WjHDmh6c5pq1tTipuZnHFN3KBg63Mtj", - "withdrawQueue": "5NRhJQS8m4pgc8Lgo1kuqHJrU8JAeToriPvpJ4LY88uH", - "lpVault": "8vLEHvkCEdAj4YPGbfrcTKHccaEJQwuY32WunJWzyuZx", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DvLrUbE8THQytBCe3xrpbYadNRUfUT7SVCm677Nhrmby", - "marketAuthority": "EN7RnB2RVxeDcTQWFBAuaf5Bg9sEuHhwwWiuj1TFHEuC", - "marketBaseVault": "AzhvXGjqJtDW4ieSYVje3zxL14TP1pGJv6uULR2F86uR", - "marketQuoteVault": "8SrtqysGeiKkXWMGMgee9frWbGdhXZr9gWHh2VKRnvkZ", - "marketBids": "9Nvw43fQ4vNfdJgajMC4JUpLGGTiia1vGYEM7SbfaWei", - "marketAsks": "CnVNbSQcVNQjGA4fdBtSrzDyFNXAHuBhcMnZsQBpEHo5", - "marketEventQueue": "D1hpxetuGzfz2mSf3US6F7QHjmmA3A5Q1EUJ3Qk5E1ZG" - }, - { - "id": "D8pasgJWjP9wy39fzeD8BUjQMvYCZxABzPcnuoDSLHBB", - "baseMint": "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "61z37rpHsU6d3Fq5sUjJ85K6tXGzkoYKDAG3kPJQNDRo", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2fXtmmePfWQTFuzCZ6WydnM96j4ZZjkbEhof2f9YnQsP", - "targetOrders": "2Eh6QWELimVN4uKji1KWZohKtvWCERHf5kYpd45Pro8Y", - "baseVault": "8P81j68MyzuixeKE3U1yuCmEMcSKUWsarxUKCPjPqG5V", - "quoteVault": "ygjuCz9gawcU35UHgc8y7xLYRd12uY8ww3ToSgyAVj9", - "withdrawQueue": "vWmn9TmQrvthTYP5zRwaJba2PajduXakJQvE4sEQtq9", - "lpVault": "DQhW2UkMUJ3ZfkgfvjMGci1FHwDrAQU52sFTYsfZYZtS", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GTfi2wtcZmFVjF5rr4bexs6M6xrszb6iT5bqn694Fk6S", - "marketAuthority": "7XhDQ1epCDMRX7gDEi9r2S7pbEzuyAH3PpNZ9s8Yz4Ht", - "marketBaseVault": "CRutAjBoc5qABvZvBmnuUYQ1VFYjjBpfEcQxvAkyusLu", - "marketQuoteVault": "F54JoYXAR7m6KA4FHndF82W5kraBZvVQwqUyXRNcqDJH", - "marketBids": "4kXVcHe29TsuMPAhKcRjPEtZ3tnLWQLMe592jggAzshN", - "marketAsks": "Aw6Ris8FUTL1oQuqKrzmaWxQfmLun6ZD4vPzamFvdqEg", - "marketEventQueue": "Hb6GesB1688DUdyuvXqDZk1pUxRp7epVymAX8BLkUGcn" - }, - { - "id": "D95EzH4ZsGLikvYzp7kmz1RM1xNMo1MXXiXaedQesA2m", - "baseMint": "FnKE9n6aGjQoNWRBZXy4RW6LZVao7qwBonUbiD7edUmZ", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "KHV6dfj2bDntzJ9z1S26cDfqWfUZdJRFmteLR6LxHwW", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "34Ggyj2dNyQUWDaGUaMKVvyQDoTHEupD4o2m1mPFaPVf", - "targetOrders": "DAadSXEyP5dZPiYFKcEkj6i7rY5TQtHucXPvum53uAHY", - "baseVault": "4iuHfu5rPzdsnjBEPAdGvnK3brF3JiqpwtXerko1o6U4", - "quoteVault": "5FvQrUmnCN4o1HBsA3XqbCDPypvyroJ9MBSYH5goxFGC", - "withdrawQueue": "3sXFB5JFTi38cVbJaAf6b95GJp8UqgbBX5YMcPg5sBsH", - "lpVault": "CdQQS6QJLR6it5bNfmpiU6uQod6Z71scF5ZuGTzrwdut", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4ksjTQDc2rV3d1ZHdPxmi5s6TRc3j4aa7rAUKiY7nneh", - "marketAuthority": "BmNvsW45ZLYrnSZpFHFL3xmTyWsJ1X6jof3XoCkEry6H", - "marketBaseVault": "GkM6SiD2GFKTuqJraMuWbPVYcvEvzPqjndsKq3GfYEX4", - "marketQuoteVault": "FF6EXqFSZzUvyuj6uYRWxTFDAhd5jcz57PL69BAMPutd", - "marketBids": "BgzeMbya7kgtaV9zNhF4L6oABQSrErg9ZiDFDWeUqpv1", - "marketAsks": "8L6HcYpMr4TqaEksbUy7GkGBUvPv8UARCVH4nhbrfZFt", - "marketEventQueue": "J99229xgQtGXN7jvWFh6wB73kT44X269GEtjaykkcuf5" - }, - { - "id": "DGSnfcE1kw4uDC6jgrsZ3s5CMfsWKN7JNjDNasHdvKfq", - "baseMint": "3bRTivrVsitbmCTGtqwp7hxXPsybkjn4XLNtPsHqa3zR", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "7xqDycbFSCpUpzkYapFeyPJWPwEpV7zdWbYf2MVHTNjv", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4hgUQQevH5BauWE1CGGsfsDZbnCUrjd6YsRHB2gQjRUb", - "targetOrders": "AD3TRMfAuTJXTdxsvJ3E9p6YK3GyNAGDSk4DX26mtmFC", - "baseVault": "HXmwydLeUB7JaLWhoPFkDLazQJwUuWCBi3M28p7WfwL7", - "quoteVault": "BDbjkVrTezpirdkk24MfXprJrAi3WXazr4L6DHT5buXi", - "withdrawQueue": "FFKXu8Q3kaQjnuZsicVyUQNNBwRRLFAT86WqDN8Yz2UV", - "lpVault": "FJguakQVbJmhjVGrzakNGQo5WCm5HG1Uk23X6x75WtZz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "E4ohEJNB86RkKoveYtQZuDX1GzbxE2xrbdjJ7EddCc5T", - "marketAuthority": "GWnLv7RwJhceF3YNqawMyEJqg6WgZc6XtT7Bi6prjkyC", - "marketBaseVault": "EENxPU4YaXqTLBgd5jHBHigpH74MZNq9WxcLaKVsVSvq", - "marketQuoteVault": "5c9DtqqCvj5du96cgUCSt2GZp8sreE7uV1Defmb615na", - "marketBids": "7vhuHsR1VxAGN4DD5EywRnW9nb7cX3VHcyrAKL1AAJ4v", - "marketAsks": "KXrJ3YVBvSGpCRETy3M2ronxM55PU8xBmQ2wCWVzhpY", - "marketEventQueue": "EMTQJ2v3dn4ndnV7UwZTiGTmSNPsVSCgdSN6w5QvCv2M" - }, - { - "id": "DiWxV1SPXPNJRCt5Ao1mJRAxjw97hJVyj8qGzZwFbAFb", - "baseMint": "8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Cz1kUvHw98imKkrqqu95GQB9h1frY8RikxPojMwWKGXf", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "jg8ayFZLH2cEUJULUirWy7wNggN1eyRnTMt6EjbJUun", - "targetOrders": "8pE4fzFzRT6aje7B3hYHXrZakeEqNF2kFmJtxkrxUK9b", - "baseVault": "FhjBg8vpVgsiW9oCUxujqoWWSPSRvnWNXucEF1G1F39Z", - "quoteVault": "Dv95skm7AUr33x1p2Bu5EgvE3usB1TxgZoxjBe2rpfm6", - "withdrawQueue": "4An6jy1JocXGUjayXqVTx1jvs79o8LgsRk3VvmRgXxaq", - "lpVault": "57hiWKd47VHVD7y8BenqnakSdgQNBvyUrkSpf9BDP6UQ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6fc7v3PmjZG9Lk2XTot6BywGyYLkBQuzuFKd4FpCsPxk", - "marketAuthority": "A6q5h5Wx9iqeoVsvYWA7xofUcKx6XUPPab8BTVrW91Bs", - "marketBaseVault": "2ShBow4Bof4dkLjx8VTRjLXXvUydiBNF7bHzDaxPjpKq", - "marketQuoteVault": "EFdqJhawpCReiK2DcrbbUUWWc6cd8mqgZm5MSbQ3TR33", - "marketBids": "FLjCjU5wLUsqF6FeYJaH5JtTTFSTZzTCingxN1uyr9zn", - "marketAsks": "7TcstD7AdWqjuFoRVK24zFv66v1qyMYDNDT1V5RNWKRz", - "marketEventQueue": "2dQ1Spgc7rGSuE1t3Fb9RL7zvGc7F7pH9XwJ46u3QiJr" - }, - { - "id": "DkMAuUCQHC6BNgVnjtM5ZTKm1T8MsriQ6bL3Umi6NBtG", - "baseMint": "GXMvfY2jpQctDqZ9RoU3oWPhufKiCcFEfchvYumtX7jd", - "quoteMint": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "lpMint": "GgH9RnKrQpaMQeqmdbMvs5oo1A24hERQ9wuY2pSkeG7x", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "34eRiATmb9Ktv1QTDzzckyaFhj4KpC2y94TJXXd34erL", - "targetOrders": "CK2vFsmS2CEZ2Hi6Vf9px8p5DSpoyXST9rkFHwbbHirU", - "baseVault": "8BjTHZccnRNZKZpAxsdXx5BEQ4Kpxd9pQLNgeMqMiTZL", - "quoteVault": "DxcJXkGo8BUmsky51LuKi4Vs1zW48fHrCXEY6BKuY3TY", - "withdrawQueue": "AoP3EXWypUheq9ZURDBpf8Jd1ijRuhUCQg1uiM5zFpB5", - "lpVault": "9go7YtJ6QdG3mWgVhwRcQAfmwPruJk5MmsjyTn2HJisK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7jBrpiq3w2ywzzb54K9SoosZKy7nhuSQK9XrsgSMogFH", - "marketAuthority": "EJfMPPTvTKtgj7PUaM17bp2Gbye9CdKjZ5yqonPyY4rB", - "marketBaseVault": "8W65Bwb83MYKHf82phS9xPUDsR6RpZbAXnSELxsBb3HH", - "marketQuoteVault": "5rjDHBsjFv3Z3Dxr5RMj98vj6LA5DNEwZGDM8wyUF1Hy", - "marketBids": "ECdZLJGwcN6fXY9BjiSVNrWssKdWejW9uv8Zs6GkkxBG", - "marketAsks": "J5NN79kpFzGdxj8MGvis3NsGYcrvcdYHNXLtGGn9au5E", - "marketEventQueue": "7FrdprBxpDyM7P1AkeMtEJ75Q6UK6ZE92zgqGg5F4Gxb" - }, - { - "id": "Dm1Q15216uRARmQTbo6VfnyEGVzRvLTm4TfCWWX4MF3F", - "baseMint": "TuLipcqtGVXP9XR62wM8WWCm6a9vhLs7T1uoWBk6FDs", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "3AZTviji5qduMG2s4FfWGR3SSQmNUCyx8ao6UKCPg3oJ", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2x6JvLToztTWoiYAXFvLw9R8Ump3aDcuiRPBY9ZuzoRL", - "targetOrders": "GZzyFjERxn9CqS5jXq1o2J3zmSNmhPMzn7U4aMJ82wL", - "baseVault": "96VnEN3nhvyb6hLSyP6BGsvSFdTJycQtTr574Kavrje8", - "quoteVault": "FhnZ1j8C8d7aXecxQXEGpRycoH6uJ1Fpncj4Sm33J2iS", - "withdrawQueue": "ELX79G4JU2YQrykozCvaRnhU2dBFmxNpSrJD3BoRoxfE", - "lpVault": "BagZFcJSYZzQn3iS37sPFDPiaKsfUwo8YD98XsEMKrsd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GXde1EjpxVV5fzhHJcZqdLmsA3zmaChGFstZMjWsgKW7", - "marketAuthority": "3yRCDVhumspJgYJnNhyJaXTjRn5jiMqdbQ13rTyHHQgQ", - "marketBaseVault": "JD1MfYD2SXiY1j6p3H6DifpG6RAe8cAtmNNLdRAdB1aT", - "marketQuoteVault": "UtkM2zbygo9tig18DQJDdRjHSKQiMf5uSuDTR2kf7ov", - "marketBids": "2ty8Nq6brwkp74n6EtJkD8msgBnc3fRiavNGrE5d7yE3", - "marketAsks": "GzztpwBixtLW1vqZwtNZH7FvyGJcRmLvCZTffCW2ZoS2", - "marketEventQueue": "4EgxxtAL5zsc1GCR243EU2vpbYpSvsawyfznVuRYbGHm" - }, - { - "id": "DqYSvijBXydSx9GfvVDjEzUg5StLLrkqZVPzsU2FeVZ2", - "baseMint": "9TE7ebz1dsFo1uQ2T4oYAKSm39Y6fWuHrd6Uk6XaiD16", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "HUJ1opSk8AiPfDT47r7n4hTiK2EXgrR3Msy7T8q1BywS", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GKSbpr3z4SV2AWmLndfw6FST3rNttyAzJKNvya8CQyLd", - "targetOrders": "9rXzQFx2udvvDBkzzUAH7ASW4DFEzQYytT9fnDyZvgeM", - "baseVault": "EjrKJXurKjpxCXHcvLDdaN28tg5X2mhAFpi7vj4rPPjP", - "quoteVault": "HZcZjZZR6t6kbXTZisLKdCRnHqFWACG9RrBvJKWaDyvW", - "withdrawQueue": "CzDNWpq6Wh5iQfaCRb8HB7W92T6LSXKoyEwuk3eoi1iH", - "lpVault": "CLxnCgBv6pc9UD7cbqam67rYXjvZFvBhYPNxNCXeicbH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BBD3mBvHnx4PWiGeJCvwG8zosHwmAuwkx7JLjfTCRMw", - "marketAuthority": "DSc4PMo49kARDga5qpxGvmR8hYYyBNNKQb4Qr6nWSDYu", - "marketBaseVault": "4DVzV5Y4JwRQ6NyCnFmdkc8zqhuFrPaF319q8DRVQDGG", - "marketQuoteVault": "ARwUt79ZTCkkD6GtvwxLv72N4r6zQJjNykDmYcXDMwXD", - "marketBids": "5cabXo89gLZoQSG4AYxYqchkhczuwNRivz2U2BA1nk4g", - "marketAsks": "6wRsk3W1v5JMouuUzNjbevbuxA5onend9xEkQni7bSfP", - "marketEventQueue": "9PZ5J7LLcfv2nCjJb93wEjHUC2h5RCjZhTv8yLS6Dpcn" - }, - { - "id": "DSkXJYPZqJ3yHQECyVyh3xiE3HBrt7ARmepwNDA9rREn", - "baseMint": "E5rk3nmgLUuKUiS94gg4bpWwWwyjCMtddsAXkTFLtHEy", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7cu42ao8Jgrd5A3y3bNQsCxq5poyGZNmTydkGfJYQfzh", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6WHHLn8ia2eHZnPFPDwBKaW2nt7vTRNsvrbgzS55gVwi", - "targetOrders": "HuSyM774u2zhjbG8rQYCrALBHhK7yVWgUP36rNEtfTs2", - "baseVault": "HeMxCh5SozqLth4QPpU1cbEw29ueqFUKSYP6369GX1HV", - "quoteVault": "J3jwx9wsRAq1sBu5tSsKpA4ixQVzLiLyRKdxkjMcRenv", - "withdrawQueue": "FRSDrhT8Q28yZ3dGhVwNoAbzWawsE3qgmAAEwxTNtE6y", - "lpVault": "GP8hM7HRSjcsQfTbvHKNAWnwhqdn2Nxthb4UJiKXkfJC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2Ux1EYeWsxywPKouRCNiALCZ1y3m563Tc4hq1kQganiq", - "marketAuthority": "CTcvsPoWroF2e2iiZWe6ztBwNQHiDyAVCs8EbQ5Annig", - "marketBaseVault": "54vv5QSZkmHpQzpvUmpS5ZreDwmbuXPdbGp9ybzgcsTM", - "marketQuoteVault": "7PL69dV89XXJg9V6wzzdu9p2ymhVwBWqp82sUzWvjnp2", - "marketBids": "34oLSEmDGyH4NyP84mUXCHbpW9JvG5anNd3iPaCF55zE", - "marketAsks": "Lp7h84DcAmWqhDbJ6LpvVX9m45GJQfpvMbWPTg4qtkF", - "marketEventQueue": "8Y7MaACCFcTdjcUSLsGkxqxMLDaJDPSZtT5R1kuUL1Hk" - }, - { - "id": "DVa7Qmb5ct9RCpaU7UTpSaf3GVMYz17vNVU67XpdCRut", - "baseMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "C3sT1R3nsw4AVdepvLTLKr5Gvszr7jufyBWUCvy4TUvT", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7UF3m8hDGZ6bNnHzaT2YHrhp7A7n9qFfBj6QEpHPv5S8", - "targetOrders": "3K2uLkKwVVPvZuMhcQAPLF8hw95somMeNwJS7vgWYrsJ", - "baseVault": "3wqhzSB9avepM9xMteiZnbJw75zmTBDVmPFLTQAGcSMN", - "quoteVault": "5GtSbKJEPaoumrDzNj4kGkgZtfDyUceKaHrPziazALC1", - "withdrawQueue": "8VuvrSWfQP8vdbuMAP9AkfgLxU9hbRR6BmTJ8Gfas9aK", - "lpVault": "FBzqDD1cBgkZ1h6tiZNFpkh4sZyg6AG8K5P9DSuJoS5F", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "teE55QrL4a4QSfydR9dnHF97jgCfptpuigbb53Lo95g", - "marketAuthority": "HzWpBN6ucpsA9wcfmhLAFYqEUmHjE9n2cGHwunG5avpL", - "marketBaseVault": "2kVNVEgHicvfwiyhT2T51YiQGMPFWLMSp8qXc1hHzkpU", - "marketQuoteVault": "5AXZV7XfR7Ctr6yjQ9m9dbgycKeUXWnWqHwBTZT6mqC7", - "marketBids": "AvKStCiY8LTp3oDFrMkiHHxxhxk4sQUWnGVcetm4kRpy", - "marketAsks": "Hj9kckvMX96mQokfMBzNCYEYMLEBYKQ9WwSc1GxasW11", - "marketEventQueue": "58KcficuUqPDcMittSddhT8LzsPJoH46YP4uURoMo5EB" - }, - { - "id": "DvxLb4NnQUYq1gErk35HVt9g8kxjNbviJfiZX1wqraMv", - "baseMint": "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "quoteMint": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "lpMint": "AGHQxXb3GSzeiLTcLtXMS2D5GGDZxsB2fZYZxSB5weqB", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3CGxjymeKv5wvpVg9unUgbrGUESmeqfJUJkPjVeRuMvT", - "targetOrders": "C8YiDYrk4rfC6sgK93zM3YpGj7SDpGuRbos7DHStSssT", - "baseVault": "5jV7XQ1JnfUg7RvEShyAdV7Gzn1xS54j163x8ZBSzxuh", - "quoteVault": "HSKY5r6iqCpC4nWzCGP2oWMQdGEQsx69eBm33PrmZqhg", - "withdrawQueue": "5faTQUz7gmasinkinA7BkC6HsG8hUrD9iukaohF2fuHZ", - "lpVault": "9QutovnPtwN9pPxsTdaEWBSCT7iTKc3hwMfF4QJHDXRz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HfsedaWauvDaLPm6rwgMc6D5QRmhr8siqGtS6tf2wthU", - "marketAuthority": "9o8LaPeTMJBoYyoUVNm6ju6c5rwfphhYReQsp1vTTyRg", - "marketBaseVault": "3ABvHYBeWrpgP82jvHh5TVwid1AjDj9rei7zfY8xh2wz", - "marketQuoteVault": "CSpdPdzzbaNWgwhPRTZ4TNoYS6Vco2w1s7jvqUsYQBzf", - "marketBids": "GMM36fgidwYvXCAxQhpT1XkGoZ46g1wMc44hY8ds3P8u", - "marketAsks": "BFDQ4WGcEftURk6nrwtQ1GzYdPYj8fx3iBjeJVt6S3jQ", - "marketEventQueue": "94ER3KZeDrYSG8TytGJ56rZK9zM8oz1H8dJ2LP1gHn2s" - }, - { - "id": "DWvhPYVogsEKEsehHApUtjhP1UFtApkAPFJqFh2HPmWz", - "baseMint": "AR1Mtgh7zAtxuxGd2XPovXPVjcSdY3i4rQYisNadjfKy", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "Ba26poEYDy6P2o95AJUsewXgZ8DM9BCsmnU9hmC9i4Ki", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ARZWhFKLtqubNWdotvqeiTTpmBw4XfrySNtY4485Zmq", - "targetOrders": "J8f8p2x3wPTbpaqJydxTY5CvxtiB8HrMdW1DouaEVvRx", - "baseVault": "C77d7jRkxu3WyzL7K2UZZPdWXPzsFrmzLG4uHrsZhGTz", - "quoteVault": "BtweN6cYHBntMJiRY2gGB2u4oZFsbapjLz7QJeV3KWF1", - "withdrawQueue": "6WsofMBNdHWacgButviYgn8CCTGyjW19H13vYntkzBzp", - "lpVault": "CgaVy8TjkUdxFhi4h3RdszmPtf6MPUyfquqAWUwAnim7", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6DgQRTpJTnAYBSShngAVZZDq7j9ogRN1GfSQ3cq9tubW", - "marketAuthority": "9GN4139oezNfddWhcAc3c8Ke5aU4cwzcxL8cLkqE37Yy", - "marketBaseVault": "5LmHe3x8VwGzWZ6rooARZJNMo6AaN1P73478AuhBUjUr", - "marketQuoteVault": "iLCNUheHbq3bE1868XwWXs8enoTvjFnwpnmLFmBQGi3", - "marketBids": "7U3FPNGvcDkmfnD4u5jKVd2AKwc66RFBZ8GnyjzeNfML", - "marketAsks": "3Zx74FxHwttDuYxeqHzMijitrf25FhSzeoWBT9VeCrVj", - "marketEventQueue": "9PqaWBQ6gSZDZsztbWTnXp6LfrS2TUfVfPTSnf8tbgkE" - }, - { - "id": "E9EvurfzdSQaqCFBUaD4MgV93htuRQ93sghm922Pik88", - "baseMint": "CWE8jPTUYhdCTZYWPTe1o5DFqfdjzWKc9WKz6rSjQUdG", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "Dr12Sgt9gkY8WU5tRkgZf1TkVWJbvjYuPAhR3aDCwiiX", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CQ9roBWWPV5efTeZHoqgzJJvTSeVNMca6rteaenNwqF6", - "targetOrders": "DVXgN8m2f8Ggs8zddLZyQdsh49jeUGnLq66s4Lhfd1uj", - "baseVault": "BKNf6HxSz9tCmeZts4ABHpYuXwP2wfKf4uRycwdTm3Jh", - "quoteVault": "5Uzq3c6rnedxMF7t7s7PJVQkxxZE7YXGFPJUToyhdebY", - "withdrawQueue": "Hj5vcVZCm6JXtkmCa1MPjteoxzkWQCmHQutXxofj2sy6", - "lpVault": "7WhsN9LGSeGxhZPT4E4rczauDvhmfquAKHQUESAXYS3k", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3yEZ9ZpXSQapmKjLAGKZEzUNA1rcupJtsDp5mPBWmGZR", - "marketAuthority": "FezSC2d6sXEcJ9ah8nYxHC18nh4FZzc4u7ZTtRSrk6Nd", - "marketBaseVault": "EmS34LncbTGs4yU4GM9bESRYMCFL3JBW6mnAeKB4UtEb", - "marketQuoteVault": "AseZZ8ZRqyvkZMMGAAG8dAqM9XFf2xGX2tWWbko7a4hC", - "marketBids": "9fkA2oJQ7BKP5n2WxdLkY7mDA1mzBrGZ9osqVhvdBkH7", - "marketAsks": "G8c3xQURJk1oukLqJd3W4SJykmRq4wq3GrSWJwWipECH", - "marketEventQueue": "4MDEwZYKXuvEdQ58yMsE2zwXLG973aYp4EFvoaUSDMP2" - }, - { - "id": "E9Z2JeEKS2WGGyA18mGU33rnQskK9moPhM4tdzrv24fh", - "baseMint": "9zoqdwEBKWEi9G5Ze8BSkdmppxGgVv1Kw4LuigDiNr9m", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8uDVKmVwNmbXHDB7rNKqtpcT9VAsFHTJ5pPYxjyoBbNg", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2VXhUYA8r9dbajVrpYPhph2n4LMTHvPq9FZxePLojMh1", - "targetOrders": "9Z7bnGEZj6rrTepJcf81mpgFT6CVQ5YehuH5aNBgi9cC", - "baseVault": "GwDeKNzQGLimDszBhpikJ85Kzngpsor77ts8Ry2SEwtg", - "quoteVault": "2RVjUrDtQVWL4j7nyYx8kDhifmhxAsZM7JRRETm4g9xy", - "withdrawQueue": "F8jtVFch1Eu7GXNnAqC6vqsxyoHfjpxriFf6Zzv4TKju", - "lpVault": "BZeJqKxUTrxZ1zTVFUQ7xX5NDLwdwTEQYz9dJrPktE1Z", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6vXecj4ipEXChK9uPAd5giWn6aB3fn5Lbu4eVMLX7rRU", - "marketAuthority": "6yCg8Dmgkg6pXoJBFEV7UFEWnLSPuAUAri9KTaVQ3PKE", - "marketBaseVault": "Dy27M2AeDz3DfxmrV6JZQ8CRMzrz63QAMg2YCUaWF93x", - "marketQuoteVault": "HwTt653QDLgHKS4BjaTSFXjrJ1jVLKSTP7uwHLNNarvR", - "marketBids": "EYHrFmKz2dH7PVRQ5GXg14DRSC9sHAd5QhgazjHBQH2t", - "marketAsks": "8sC4E99kYkaYUK2G3AdXxXGJAapwBcdu54mtosQFjZZk", - "marketEventQueue": "8sPnF53bonayqHfr73apPmpivx3ATH8YE4Tzu3JMCHLv" - }, - { - "id": "EBqQdu9rGe6j3WGJQSyTvDjUMWcRd6uLcxSS4TbFT31t", - "baseMint": "Lrxqnh6ZHKbGy3dcrCED43nsoLkM1LTzU2jRfWe8qUC", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "ZRDfSLgWGeaYSmhdPvFNKQQhDcYdZQaue2N8YDmHX4q", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "MpAAS4U2fQnQRhTc1dAZEzLuQ9G4q6qRSUKwTJbYynJ", - "targetOrders": "A1w44YMFKvVXFnXYTrz7EVfSgjHdZfE67g59HdhE1Yfh", - "baseVault": "6Sq11euWaw2Hpd6bXMZccJLZpPcVgs3nhV7P5396jE7e", - "quoteVault": "12iyJhJgr9AeJrL6q6jAN63zU3YgpPV98CR87c6JGoH4", - "withdrawQueue": "BD3rgKtrnxdi45UpCHEMrtBtSA2NRcpP9zrah1CWN35a", - "lpVault": "Hc3pK8xppE3NxexxjAz4sxs3ZKwGjKfo7Lpth3FdGeQ6", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5GH4F2Z9adqkEP8FtR4sJqvrVgBuUSrWoQAa7bVCdB44", - "marketAuthority": "4pwBSrGHpVn1qXjzDC2Tm8nFG8mxR9y2qudFjAQ8cVQy", - "marketBaseVault": "5uUh8pUvYzEjPtofPbappZBswKieWtLW7d32yuDNC6tw", - "marketQuoteVault": "6eRt1RkQokKk5gmVmJ85gY42xirTMXQ1QDLXiDmbXs4b", - "marketBids": "8JdtK95nRc3sHkDdFdtMWvJ9fXFY67LMo74RiHTh8f3a", - "marketAsks": "99ScAmHwokD3Zs5assDwQHxunZe1Fz1N9GL9L1YUbvgr", - "marketEventQueue": "feXvc7XGRDETboXZiCMShmSKvsTnZtxrKoBkjJMCkNf" - }, - { - "id": "EGyhb2uLAsRUbRx9dNFBjMVYnFaASWMvD6RE1aEf2LxL", - "baseMint": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "5ijRoAHVgd5T5CNtK5KDRUBZ7Bffb69nktMj5n6ks6m4", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6c1u1cNEELKPmuH352WPNNEPdfTyVPHsei39DUPemC42", - "targetOrders": "CLuMpSesLPqdxewQTxfiLdifQfDfRsxkFhPgiChmdGfk", - "baseVault": "85SxT7AdDQvJg6pZLoDf7vPiuXLj5UYZLVVNWD1NjnFK", - "quoteVault": "BtGUR6y7uwJ6UGXNMcY3gCLm7dM3WaBdmgtKVgGnE1TJ", - "withdrawQueue": "7vvoHxA6di9EvzJKL6bmojbZnH3YaRXu2LitufrQhM21", - "lpVault": "ACn8TZ27fQ85kgdPKUfkETB4dS5JPFoq53z7uCgtHDai", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5cLrMai1DsLRYc1Nio9qMTicsWtvzjzZfJPXyAoF4t1Z", - "marketAuthority": "EHMK3DdPiPBd9aBjeRU4aZjD7z568rmwHCSAAxRooPq6", - "marketBaseVault": "2qmHPJn3URkrboLiJkQ5tBB4bmYWdb6MyhQzZ6ms7wf9", - "marketQuoteVault": "A6eEM36Vpyti2PoHK8h8Dqk5zu7YTaSRTQb7XXL8tcrV", - "marketBids": "JAABQk3n6S8W85LC6RpqTvGgP9wJFb8kfqir6kUhBXkQ", - "marketAsks": "psFs3Dm7quZZn3BhvrT1LdWCVtbMqxXanU7ZYdHULj6", - "marketEventQueue": "4bmSJJCrx3dehFQ8kXAE1c4L9kfP8DyHow4tFw6aRJZe" - }, - { - "id": "Ek8uoHjADzbNk2yr2HysybwFk1h2j9XXDsWAjAJN38n1", - "baseMint": "AURYydfxJib1ZkTir1Jn1J9ECYUtjb6rKQVmtYaixWPP", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Gub5dvTy4nzP82qpmpNkBxmRqjtqRddBTBqHSdNcf2oS", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BnGTcze1GXtCMkFPceWfUC4HPRXjJo5dGb2bmevHfgL3", - "targetOrders": "2h5kDQddqUTUaAjFv3FHNMtvVVCYo1PY6BxkxtkhVzkH", - "baseVault": "JBvjQsg5YasDvmSKnetHZzUesa1Aucp6gXwGtPhjefGY", - "quoteVault": "2auTq31drUwTmMKsJcD2KqZnKgiTRTN1XDKS9CQ7wzGe", - "withdrawQueue": "BngHmGEaQbDF9LacaSs1hQRFMVmkvEqFpo5h5gkiWQRB", - "lpVault": "5wdZqTKhpnFwWSC3mxEH4QHd9o8Jwt7swqB2QPBJb5yf", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "461R7gK9GK1kLUXQbHgaW9L6PESQFSLGxKXahvcHEJwD", - "marketAuthority": "639H2jxUJRbvNiCQnkypf4Nvz72bSdbexchvcCg2jHYR", - "marketBaseVault": "HbYw9LSKVepB9mYwbTeDy6oAj5TPrw3GqAFtKWm99jNd", - "marketQuoteVault": "6DbF2jRhrNgeZnHGR6c1UfGmQxk4qtBueox56huK8Etr", - "marketBids": "B8yZ7jW9UAKLTtPTGzfobqfn9J4obmwy8BtdX17joKVt", - "marketAsks": "8cytrpCzPUiFub2Zjxhz4VN6sz5UycVYWPEpyVteARXh", - "marketEventQueue": "Dg1CmXWtyHwoi71GVgpp9N4u7wQtcmuGcXbh9Bgpd9wb" - }, - { - "id": "Enq8vJucRbkzKA1i1PahJNhMyUTzoVL5Cs8n5rC3NLGn", - "baseMint": "GENEtH5amGSi8kHAtQoezp1XEXwZJ8vcuePYnXdKrMYz", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7GKvfHEXenNiWYbJBKae89mdaMPr5gGMYwZmyC8gBNVG", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7dcfFNqaGnHrUB1bg1mEbvJsvsvfn7oamkpjDdt7ykUm", - "targetOrders": "FrJ5aM3Vi1DyxNfSbqq4vPYX3S9kH9foWMjqHjHGQq3E", - "baseVault": "6yxszHV62pCjHtGijwgroqRXGVLuoiHUFhcEoHQepB91", - "quoteVault": "6AovHvG7UovcavaJW6rEef728JtFV5adZ9MaNRBcX2nH", - "withdrawQueue": "J6YMSZfmy68QLH4R5gv5wasyF3pTVBF5CgkY6WaNwaBD", - "lpVault": "7uNG8iCJNjN7xRDXAvb1afGAvd6GQitQ7K7chhTy43w5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FwZ2GLyNNrFqXrmR8Sdkm9DQ61YnQmxS6oobeH3rrLUM", - "marketAuthority": "CTWJZKgSwanoom2Bb9QiNKj6mrDtAMPFe2UUh8mZx9d5", - "marketBaseVault": "AjKhS74QWgcatcJvHDS3fdCJq8BdAsrHxzcoNyT738Hy", - "marketQuoteVault": "3xtHLByKqJzyvu3TbtDW8cnzJTbdRLKRjihWo1fVM5Fp", - "marketBids": "CQvBaGPpjn9aSM5VJYmXSxjrqG79aqF8wPAbuCSWhPtz", - "marketAsks": "5R4k5QNxtN1zcAiCHR4h1FmmBdpajvF6EeR3kuoMYbu9", - "marketEventQueue": "7MQzBut5taNSxbusoBnuuLB6Bmnfo6wm1Ukze5B13Uxd" - }, - { - "id": "EoNrn8iUhwgJySD1pHu8Qxm5gSQqLK3za4m8xzD2RuEb", - "baseMint": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3529SBnMCDW3S3xQ52aABbRHo7PcHvpQA4no8J12L5eK", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6iwDsRGaQucEcfXX8TgDW1eyTfxLAGrypxdMJ5uqoYcp", - "targetOrders": "EGZL5PtEnSHrNmeoQF64wXG6b5oqiTArDvAQuSRyomX5", - "baseVault": "DVWRhoXKCoRbvC5QUeTECRNyUSU1gwUM48dBMDSZ88U", - "quoteVault": "HftKFJJcUTu6xYcS75cDkm3y8HEkGgutcbGsdREDWdMr", - "withdrawQueue": "A443y1KRAvKdK8yLJ9H29mgwuY56FAq1KvJmkcPCn47B", - "lpVault": "jYvXX2z6USGtBSgJiPYWM9XZTBoiHJGPRGeQ9AUX98T", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8Gmi2HhZmwQPVdCwzS7CM66MGstMXPcTVHA7jF19cLZz", - "marketAuthority": "FG3z1H2BBsf5ekEAxSc1K6DERuAuiXpSdUGkYecQrP5v", - "marketBaseVault": "8cCoWNtgCL7pMapGZ6XQ6NSyD1KC9cosUEs4QgeVq49d", - "marketQuoteVault": "C7KrymKrLWhCsSjFaUquXU3SYRmgYLRmMjQ4dyQeFiGE", - "marketBids": "3nXzH1gYKM1FKdSLHM7GCRG76mhKwyDjwinJxAg8jjx6", - "marketAsks": "b3L5dvehk48X4mDoKzZUZKA4nXGpPAMFkYxHZmsZ98n", - "marketEventQueue": "3z4QQPFdgNSxazqEAzmZD5C5tJWepczimVqWak2ZPY8v" - }, - { - "id": "EvWJC2mnmu9C9aQrsJLXw8FhUcwBzFEUQsP1E5Y6a5N7", - "baseMint": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "AKJHspCwDhABucCxNLXUSfEzb7Ny62RqFtC9uNjJi4fq", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9ot4bg8aT2FRKfiRrM2fSPHEr7M1ihBqm1iT4771McqR", - "targetOrders": "AfzGtG3XnMixxJTx2rwoWLXKVaWoFMhsMeYo929BrUBY", - "baseVault": "BCNYwsnz3yXvi4mY5e9w2RmZvwUW3pefzYQ4tsoNdDhp", - "quoteVault": "7BXPSUXeBVqJGyxW3yvkNxnJjYHuC8mnhyFCDp2abAs6", - "withdrawQueue": "HYo9FfBpm8NCpR8qYMGYFZNqzKkXDRFACLxu8PXCCDc4", - "lpVault": "AskrcNfMDKT5c65AYeuEBW6mfMXfT3SG4nDCDRAyEnad", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "jyei9Fpj2GtHLDDGgcuhDacxYLLiSyxU4TY7KxB2xai", - "marketAuthority": "6vBhv2L33KVJvAQeiaW3JEZLrJU7TtGaqcwPdrhytYWG", - "marketBaseVault": "EhAJTsW745jiWjViB7Q4xXcgKf6tMF7RcMX9cbTuXVBk", - "marketQuoteVault": "HFSNnAxfhDt4DnmY9yVs2HNFnEMaDJ7RxMVNB9Y5Hgjr", - "marketBids": "4ZTJfhgKPizbkFXNvTRNLEncqg85yJ6pyT7NVHBAgvGw", - "marketAsks": "7hLgwZhHD1MRNyiF1qfAjfkMzwvP3VxQMLLTJmKSp4Y3", - "marketEventQueue": "nyZdeD16L5GxJq7Pso8R6KFfLA8R9v7c5A2qNaGWR44" - }, - { - "id": "EyDgEU9BdG7m6ZK4bYERxbN4NCJ129WzPtv23dBkfsLg", - "baseMint": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "HwzkXyX8B45LsaHXwY8su92NoRBS5GQC32HzjQRDqPnr", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "45TD9SmkGoq4hBxBnsQQD2V7pyWK53HkEXz7uNNHpezG", - "targetOrders": "Ave8ozwW9iBGL4SpK1tM1RfrQi8CsLUFj4UGdFkWRPRp", - "baseVault": "9RFqA8EbTTqH3ct1fTGiGgqFAg2hziUdtyGgg1w69LJP", - "quoteVault": "ArAyYYib2X8BTcURYNXKhfoUww2DWkzk67PRPGVpFAuJ", - "withdrawQueue": "ASeXk7dri8jz466wCtkCVUYheHFEznX55EMuGivL5WPL", - "lpVault": "2pu8zUYpwa9UEPvKkQvZHQUbbTdMg6N2mXi2Vv4DaEJV", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AAfgwhNU5LMjHojes1SFmENNjihQBDKdDDT1jog4NV8w", - "marketAuthority": "F2f14Nw7kqBeGwgFymm7sEPcZrKWWN56hvN5yx2vc6sE", - "marketBaseVault": "BpHuL7HNTJDDGiw4ELpnYQdhTNNgZ53ennhtkQjGawGS", - "marketQuoteVault": "BzsbZPiwLMJHhSFNVdtGqi9MWKhYijgq34Z6YjYkQJUr", - "marketBids": "AYEeLrFWhGDRgX9L428SqBU56iVzDSyP3A6Db4VekcjE", - "marketAsks": "CctHQdpAtxugQNFU7PA4ebb2T5K1ZkwDTvoFrsYrxifY", - "marketEventQueue": "CFtHmFydRBtw1qsoPZ4LufbdX39LKT9Aw5HzUib9JpiL" - }, - { - "id": "EZRHhpvAP4zEX1wZtTQcf6NP4FLWjs9c6tMRBqfrXgFD", - "baseMint": "9nEqaUcb16sQ3Tn1psbkWqyhPdLmfHWjKGymREjsAgTE", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EFSu5TMc1ijRevaYCxUkS7uGvbhsymDHEaTK3UVdNE3q", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GBGxwY1eqBJcTVAjwFDpLGQGCv5eoQTciudT9ttFybqZ", - "targetOrders": "EdQNfUu9EAX6aT7ixLV9zYBRLhArCgrxPAQPr3CBdFK7", - "baseVault": "6LP3CwLwA7StkyMQ9NpKUqLS9ipMmUjPrKhQ8V9w1BoH", - "quoteVault": "6HXfUDRXJkywFYvrKVgZMhnhvfqiU8T9pVYhJzyHEcmS", - "withdrawQueue": "EhgYsvA9J31J64LREuzTtt7QYhMBUX3EEAoCSZ6BwQjk", - "lpVault": "7E1e3kEWAgaerDErppzSJX34ukHtUQryiM7sAa7zhYPa", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CwK9brJ43MR4BJz2dwnDM7EXCNyHhGqCJDrAdsEts8n5", - "marketAuthority": "BUwcHs7HSHMexNjrEuSaP3TY5xdqBo87384VmWMV9BQF", - "marketBaseVault": "2VcGBzs54DWCVtAQsw8fx1VVdrxEvX7bJz3AD4j8EBHX", - "marketQuoteVault": "3rfTMxRqmtoVvVsZXnvf2ifpFweeKSWxuFkYtyQnN9KG", - "marketBids": "D5S8oWsPjytRq6uXB9H7fHxzFTpcmvULwYbuhAeAKNu4", - "marketAsks": "3PZAPrwUkhTqjaB7sDHLEj669J6hQXzPFTrnv7tgcgZT", - "marketEventQueue": "4V7fTH8x6qYz4GyvEVbzq1yLoGcpoByo6nCrsiA1HUUv" - }, - { - "id": "F73euqPynBwrgcZn3fNSEneSnYasDQohPM5aZazW9hp2", - "baseMint": "ATLASXmbPQxBUYbxPsV97usA3fPQYEqzQBUHgiFCUsXx", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "418MFhkaYQtbn529wmjLLqL6uKxDz7j4eZBaV1cobkyd", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2CbuxnkjsBvaQoAubc5MAmbeZSMn36z8sZnfMvZWH1vb", - "targetOrders": "6GZrucFa9hAQW7yHiPt3oZj9GkL6oBipngyY1Hw3zMx", - "baseVault": "33UaaUmmySzxK7q3yhmQiXMrW1tQrwqojyD6ZEFgM6FZ", - "quoteVault": "9SYRTwYE5UV2cxEuRz8iiJcV8gMbMnJUYFC8zgDAsUwB", - "withdrawQueue": "6bznLHPLPA3axnRfjh3sFzkxeMUQDLWhDuaHzjGL1EE6", - "lpVault": "FnmoaJqFYHotLTG2Ur84jSUmVUACVWrBvBvRHdPzhqvb", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Bn7n597jMxU4KjBPUo3QwJhbqr5145cHy31p6EPwPHwL", - "marketAuthority": "EK2TjcyoXzUweNJnJupQf6sZK8756mvBJeGBvi6y18Cq", - "marketBaseVault": "9tBagdm862GCoxZNFvXv7HFjLUFmypxPYxfiT3j9S3h3", - "marketQuoteVault": "4oc1kGhKByyxRnh3oXupjTn5P6JwWPnoxwvLxjZzi2vE", - "marketBids": "9zAgdk4Na8fBKLiTWzsqZwgYQETuHBDjPe2GYqHy17L", - "marketAsks": "Fv6MY3w7PP7A54cuPQHevQNuwekGy8yksXWioBsyVd42", - "marketEventQueue": "75iVJf9QKovBdsvgxcCFfwn2N4QyxEXyKxQdBvZTdzjr" - }, - { - "id": "Fb1WR1kYvG1tHu4pwAxXQpdKT8Grh9i7ES9rZusLg7D6", - "baseMint": "9gP2kCy3wA1ctvYWQk75guqXuHfrEomqydHLtcTCqiLa", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FEsEfEJJSfiMQcshUgZ5UigfytfGRQ3z5puyF6DXDp9C", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3AoL7SCi9ZKBAGoCdRvHwH3DMKD3WAv2Dpev4BkX3dYj", - "targetOrders": "Hh1zHYam85KshQPkMf3YSDy7bD6fDuEa5WWjp7P35dqu", - "baseVault": "2WtQHGAMAhMsj3mR2wSPcUR7yZhYhuNwRZBxVPKcrCyb", - "quoteVault": "4vrVEysPFSoS5YcZQwRUam8CbVgZehQdBVQ8yYbmkQSw", - "withdrawQueue": "C8PrYX1SCwgpZQbDyUtGPYcSHkvJmxTB3QpHPjih4JRX", - "lpVault": "J9dA4g4JXprDMgqhC6vWyCk8pTPoYQtECK6krratyHpz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3zzTxtDCt9PimwzGrgWJEbxZfSLetDMkdYegPanGNpMf", - "marketAuthority": "9sHBqMtqmKDftTLiAN19ngVFywHK8M1MGANuMoZoJaQK", - "marketBaseVault": "D77WaGjvSLwk6d3xdK9aEU3R7G5UKvqHrNAXmkHxjgh4", - "marketQuoteVault": "BwT7GkbKaQQqSCGwUjhtktYf6kjLvKLJsQA2j11jEAni", - "marketBids": "8JJrdQEzMSoekpzy7qcYDs1hVJyWoRcfTHR2pGDgd7wy", - "marketAsks": "A3TmGhemkp8u8d5HCLMyiBByvwDtp7khv9Vt3p1cqH8c", - "marketEventQueue": "ZYhSiaFWkuNTBzRFM9UPJXwHPyTGbujCKvPXhbssYPG" - }, - { - "id": "FEFzBbbEK8yDigqyJPgJKMR5X1xZARC25QTCskvudjuK", - "baseMint": "5tN42n9vMi6ubp67Uy4NnmM5DMZYN8aS8GeB3bEDHr6E", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4yykyPugitUVRewNPXXCviRvxGfsfsRMoP32z3b6FmUC", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8PAAfUWoVsSotWUGrL6CJCT2sApMpE2hn8DGWXq4y9Gs", - "targetOrders": "BFtdbsu9Tq8mup8osWretDzTbWF71WuzRBHtm7G6PVpS", - "baseVault": "AZPsv6tY1HQjmeps2sMje5ysNtPKsfbtxj5Qw3jcya1a", - "quoteVault": "9D6JfNjyi6dXBYGErxmXmezkauPJdHW4KjMr2RGyD86Y", - "withdrawQueue": "6i1US4rvtqxPUTwqq6ax381zVgry44rX3oG7gD7VJAef", - "lpVault": "F6MrQn7qPTbDmp7ZGQkJ3ztB1uzBtVoc7iNcR6CyqCBM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BHqcTEDhCoZgvXcsSbwnTuzPdxv1HPs6Kz4AnPpNrGuq", - "marketAuthority": "BuRLkxJffwznEsxXEqmXZJdLh4vQ1BRXc41sT6BtPV4X", - "marketBaseVault": "6sF1TAJjfrNucAqaQFRrMD78z2RinTGeyo4KsXPbwiqh", - "marketQuoteVault": "5iXoDYXGnMxEwL65XTJHWdr6Z2UD5qq47ZijW24VSSSQ", - "marketBids": "F61FtHm4R4F1gszB3FuwDPvXeSPQwNmHTofoYCnrV4FY", - "marketAsks": "5tYcHCW3ZZK4TMUSYiTi4dEE7iefyQ9dE17XDDAmDf92", - "marketEventQueue": "C5gcq3kmmXJ6ADWvH3Pc8bpiBQCL5cx4ypRwPg5xxFFx" - }, - { - "id": "FsERtRjCEQNyND3ccnMGrd61ntPmJ3tbZs4vvcCzMr1L", - "baseMint": "CN7qFa5iYkHz99PTctvT4xXUHnxwjQ5MHxCuTJtPN5uS", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8jjQn5Yagb6Nm2WGAxPW1bcGqrTWpg5adf6QukXEarcP", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7bQ84DTTnHz3vWjXHHr6eug4zHNPqgUA2u3hR186CQUc", - "targetOrders": "2rNGZ5DDQDTExPUDsWYgWHT2wWhcWkcz6yFzbzMaEfFH", - "baseVault": "He2merLuRCaccBvLhzmTGv5RyZuX77KrXYsDiegk1NBJ", - "quoteVault": "zLGXRcckcM4dJnwha7zC9UfeCgxcFjqArtGjni53KFX", - "withdrawQueue": "DDecdVYPEFJNgdrjYB5TKWLkF69qHKrqxWbPjY1FxAWk", - "lpVault": "8pwcYxTivm9q5Pwqzx5ui7QMDxPYpN2rY4Mqa9Wyrn4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Dvm8jjdAy8uyXn9WXjS2p1mcPeFTuYS6yW2eUL9SJE8p", - "marketAuthority": "DsaKT6fZuBGcA25WNQHScrZC9AvqSYh6hnGQzEkrubBo", - "marketBaseVault": "As6NSizcseTTvFStf5tAv3eitxDNo2djKE36AVsHvVCW", - "marketQuoteVault": "BqwG61kV7Wi1ZAsL2KRBqaFoczJFCjGXL5bveN6gr9xR", - "marketBids": "5FG62Yx8e5cM92wTvHrLbw33qhRGEiiDtS15SeWyMPa9", - "marketAsks": "3XTkgrqXoLtMw3XGZBKq43RLfN8o5DBkZ8tga5jCEQ6E", - "marketEventQueue": "BMaiUbDPukghHMFFFNPSKybHEnx1GzgnZaA7Wfa8eQkt" - }, - { - "id": "FSSRqrGrDjDXnojhSDrDBknJeQ83pyACemnaMLaZDD1U", - "baseMint": "EwJN2GqUGXXzYmoAciwuABtorHczTA5LqbukKXV1viH7", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9hSUZdREEsbaYaKY4FouvXr7xyAqtpdHRDoYCb6Mb28a", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AQLtFoAuHCbA6uLwSgWyweQ1wbk1ednmg55mzZV3M7NP", - "targetOrders": "4SSCpJvq7XQVzJVwxUdR2QJLM6j29ye3LVBUW6gz99Fb", - "baseVault": "Ft4UpV7G6eKVAL8YrsDypjAYv21cNEwvquz9WTEL6AA1", - "quoteVault": "FZpxvgZHoJxF96H1qNjj93dFYVVfm22TfDavfbojL1ho", - "withdrawQueue": "DuPqYGfu3L6G7ebZ4KvP83UTE7p3v4Q6LYYzhs8iMVWs", - "lpVault": "CS2n3zncd3mPpK8BEecuoPW4hfVYgoN4UVaqWsQGTPdL", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DByPstQRx18RU2A8DH6S9mT7bpT6xuLgD2TTFiZJTKZP", - "marketAuthority": "4WYVAki32938cxiWKcWsAxoGrtGP3LmP6oBsiujLz8sE", - "marketBaseVault": "SnDuSUVuEnNPBhn2wPVNrAQz92Ri2hZB9ixZEHhWGCE", - "marketQuoteVault": "DRyGXiW5c8SAq3c8oYt4aViY8rqL6BQrozMqw1yZSQAV", - "marketBids": "CrYL51GW3yPeekGM8ZNitiAB5ZL6Y4egNJhf8DGBUAmk", - "marketAsks": "5NHhazJmYGnYsXdMPnn1hKMhCXg8U3xpJWdQTTfdwn2u", - "marketEventQueue": "1PjxFWFojvxPxJWXGzJap5cN8dcxHLVyDgofruMxLSa" - }, - { - "id": "FTyJCLwQ3YvVfanJp8mtC2eqmvZPpzSpmNLqWpaPaXbC", - "baseMint": "6cVgJUqo4nmvQpbgrDZwyfd6RwWw5bfnCamS3M9N1fd", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CnUhYBtQEbSBZ76bgxAouVCTCb8rofZzwerVF5z5LREJ", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Fh4cmCjxTendCSrdKcihDhy2YXHQSo8AMZugkuYpSVav", - "targetOrders": "8CQgNaRxHAXKi5vFLgz1tavbsc3Bi1q9P9dbV32kxt54", - "baseVault": "jkXEdAVTBeSjPBX2NtysNcgm9h5o2Sv1EbebCWFmxny", - "quoteVault": "62S88DcNiESRWZYwar1nizpSMT83ahmps6FSZ4hU8WeJ", - "withdrawQueue": "Fogf4YY75yUURLKjhWnfaKsGemsKDsR3qNVrQRw3HfqQ", - "lpVault": "2CcwbW3x1p4mK13pA3STxprkDbJnTSp851NwC5vE7UdN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3KNXNjf1Vp3V5gYPjwnpALYCPhWpRXsPPC8CWBXqmnnN", - "marketAuthority": "D1mYg9jbfCfxz1wFv7deSkqy92NGzxSFpQiScimQozpw", - "marketBaseVault": "eSCLQn2TgtpDMGCRqmaMDuSTAk7JifTgJU7CwVtRWnH", - "marketQuoteVault": "BsJEDoCcd1EFjeVx39uffrp1WhcxJmE9H7U83Y3iTnF6", - "marketBids": "EkMB68wYrUFBFDjWfNqhH6vDy72wwGRJZwzMpWWNSrRu", - "marketAsks": "HqEzJdKq1FcHV9wDrygLsbfJx7vhVW8LEax1Gio3aa4J", - "marketEventQueue": "2CnKu8Xt9aGEShjtDVVYBRH7PpD37YeVxWrWpDExvXzG" - }, - { - "id": "FvN7dJz7GX1XB1BTk6jD5rEKRxQc3ZwNkWJKai5sBJWS", - "baseMint": "kiNeKo77w1WBEzFFCXrTDRWGRWGP8yHvKC9rX6dqjQh", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7xr1Doc1NiMWbUg99YVFqQSLfYXNzo6YvacXUsSgBMNW", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Hh87TCaD5syc3ssin4kt9gdmoMwqYbQRC4ABw5bvD6vo", - "targetOrders": "A6qas7S7Y49oGbF2zApeg3wmZPbZqqCBewmbMRraGbJt", - "baseVault": "9RyM5aXG1wcRmiGYLRTas3gySyoPvFCRcetTQGrVbPQ4", - "quoteVault": "H19PNJ24H3zMheS2wyGzNoN29dWZ2JxrQgBmqSeFJmb7", - "withdrawQueue": "BuhYTCcYtdULF5PFXQK6vuHCieVvCGq9tMX4nXHN8X6q", - "lpVault": "5a4VLYXVM3f4mZJKy3mnnkn7kW8fhWoTEo4MZ33gojVH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9zR51YmUq2Tzccaq4iXXWDKbNy2TkEyPmoqCsfpjw2bc", - "marketAuthority": "7ieataxFqG3ob8dFXgNkNjjmoWqEtJ17wHFcX7RXZMaU", - "marketBaseVault": "8UyekuWh39J7YWEquLP5rft9aEgCmBRTzKwCDjhbq3dq", - "marketQuoteVault": "2w4EZCYF8HMLrAFcDXefZcVyFfSJLfFyFRTSaoeGXyoQ", - "marketBids": "FtNaV9qZJV2LgfiYhjCqwAmLkkspnmEe84ctytYhKHUi", - "marketAsks": "HMifR9pTkhHGaa31LBUFr8KD4ggRRRhH5NoG5ZjuHA6C", - "marketEventQueue": "BSKDaDGxDzhLP91fSK7dL42aYrjJiSNazmgSV3VEyCsr" - }, - { - "id": "GaqgfieVmnmY4ZsZHHA6L5RSVzCGL3sKx4UgHBaYNy8m", - "baseMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "quoteMint": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "lpMint": "7P5Thr9Egi2rvMmEuQkLn8x8e8Qro7u2U7yLD2tU2Hbe", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7XWbMpdyGM5Aesaedh6V653wPYpEswA864sBvodGgWDp", - "targetOrders": "9u8bbHv7DnEbVRXmptz3LxrJsryY1xHqGvXLpgm9s5Ng", - "baseVault": "3FqQ8p72N85USJStyttaohu1EBsTsEZQ9tVqwcPWcuSz", - "quoteVault": "384kWWf2Km56EReGvmtCKVo1BBmmt2SwiEizjhwpCmrN", - "withdrawQueue": "58z15NsT3JJyfywFbdYzn2GVeDDC444WHyUrssZ5tCm7", - "lpVault": "8jqpuijsM2ne5dkwLyjQxa9oCbYEjM6bE1uBaFXmC3TE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Cm4MmknScg7qbKqytb1mM92xgDxv3TNXos4tKbBqTDy7", - "marketAuthority": "AorjCaSV1L6NGcaFZXEyUrmbSqY3GdB3YXbQnrh85v6F", - "marketBaseVault": "5QDTh4Bpz4wruWMfayMSjUxRgDvMzvS2ifkarhYtjS1B", - "marketQuoteVault": "76CofnHCvo5wEKtxNWfLa2jLDz4quwwSHFMne6BWWqx", - "marketBids": "G65a5G6xHpc9zV8tGhVSKJtz7AcAJ8Q3hbMqnDJQgMkz", - "marketAsks": "7bKEjcZEqVAWsiRGDnxXvTnNwhZLt2SH6cHi5hpcg5de", - "marketEventQueue": "4afBYfMNsNpLQxFFt72atZsSF4erfU28XvugpX6ugvr1" - }, - { - "id": "GDHXjn9wF2zxW35DBkCegWQdoTfFBC9LXt7D5ovJxQ5B", - "baseMint": "CsZ5LZkDS7h9TDKjrbL7VAwQZ9nsRu8vJLhRYfmGaN8K", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "iUDasAP2nXm5wvTukAHEKSdSXn8vQkRtaiShs9ceGB7", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AtUeUK7MZayoDktjrRSJAFsyPiPwPsbAeTsunM5pSnnK", - "targetOrders": "FMYSGYEL1CPYz8cpgAor5jV2HqeEQRDLMEggoz6wAiFV", - "baseVault": "BT3QMKHrha4fhqpisnYKaPDsv42XeHU2Aovhdu5Bazru", - "quoteVault": "9L4tXPyuwuLhmtmX4yaRTK6TB7tYFNHupeENoCdPceq", - "withdrawQueue": "4nRbmEUp7DQroG71jXv6cJjrhnh91ePdPhzmBSjinwB8", - "lpVault": "9JdpGvmo6aPZYf4hkiZNUjceXgd2RtR1fJgvjuoAuhsM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GcoKtAmTy5QyuijXSmJKBtFdt99e6Buza18Js7j9AJ6e", - "marketAuthority": "HKt6xFufxTBBs719WQPbro9t1DfDxffurxFhTPntMgoe", - "marketBaseVault": "EBRqW7DaUGFBHRbfgRagpSf9jTSS3yp9MAi3RvabdBGz", - "marketQuoteVault": "9QTMfdkgPWqLriB9J7FcYvroUEqfw6zW2VCi1dAabdUt", - "marketBids": "HmpcmzzajDvhFSXb4pmJo5mb23zW8Cj9FEeB3hVT78jV", - "marketAsks": "8sfGm6jsFTAcb4oLuqMKr1xNEBd5CXuNPAKZEdbeezA", - "marketEventQueue": "99Cd6D9QnFfTdKpcwtoF3zAZdQAuZQi5NsPMERresj1r" - }, - { - "id": "GDVhJmDTdSExwHeMT5RvUBUNKLwwXNKhH8ndm1tpTv6B", - "baseMint": "3JSf5tPeuscJGtaCp5giEiDhv51gQ4v3zWg8DGgyLfAB", - "quoteMint": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "lpMint": "EGJht91R7dKpCj8wzALkjmNdUUUcQgodqWCYweyKcRcV", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5k2VpDkhbvypWvg9erQTZu4KsKjVLe1VAo3K71THrNM8", - "targetOrders": "4dhnWeEq5aeqDFkEa5CKwS2TYrUmTZs7drFBAS656f6e", - "baseVault": "8FufHk1xV2j9RpVztnt9vuw9KJ89rpR7FMT1HTfsqyPH", - "quoteVault": "FTuzfUyp6fhLMQ5kUdAkBWd9BjY114DfjkrVocAFKwkQ", - "withdrawQueue": "A266ybcveVZYraGgEKWb9JqVWVp9Tsxa9hTudzvTQJgY", - "lpVault": "BXHfb8E4KNVnAVvz1eyVS12QqpvBUimtCnnNiBuoMrRa", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6xC1ia74NbGZdBkySTw93wdxN4Sh2VfULtXh1utPaJDJ", - "marketAuthority": "9VAdxQgKNLkHgtQ4fkDetwwTKZG8xVaKeUFQwBVG7c7a", - "marketBaseVault": "GzZCBp3Z3fYHZW9b4WusfQhp7p4rZXeSNahCpn8HBD9", - "marketQuoteVault": "ANK9Lpi4pUe9SxPvcKvd82jkG6AoKvvgo5kN8BCXukfA", - "marketBids": "EmfyNgr2t1mz6QJoGfs7ytLPpnT3A4kmZj2huGBFHtpr", - "marketAsks": "HQhD6ZoNfCjvUTfsE8KS46PLC8rpeyBYy1tY4FPgEbpQ", - "marketEventQueue": "4QGAwMgfi5PrMUoHvoSbGQV168kuRMURBK4pwGfSV7nC" - }, - { - "id": "GfvqUB36CPfqZDz5ntQ2YsoKRwg1MCewmurhc7jw3P5s", - "baseMint": "CobcsUrt3p91FwvULYKorQejgsm5HoQdv5T8RUZ6PnLA", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3e5ZCKi4etorpV4pv1fSckP5iJD67xcUkx3RtFCZhbzD", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5ZodjQpktYCNqtLZLvYcDQET9UVsmya2wGzsdxGrxi8z", - "targetOrders": "Tn2PqEet9R4jspxZ35dvrzDQT2LhicnbjznExJppKRw", - "baseVault": "3JyvAQagVdeGdmUqMHEYuGsCi4qZuTQwJsyHarQrAVYm", - "quoteVault": "GuMPTZBkY9WjkcdzLfjGzDBb6S7ZuwLWvHHbAYRGdaKn", - "withdrawQueue": "CiiZZRHdSppXEVjfGjZUpD4oB5wV6jMdgJcdGFd4Q9Eu", - "lpVault": "2eg2bvXrYRb1R73Uxa2SoYrcpQzZcx1eVWXni6hfs6jj", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GsWEL352sYgQC3uAVKgEQz2TtA1RA5cgNwUQahyzwJyz", - "marketAuthority": "8EnrqayT31TqvUQRsCxC3ZZTNrTQjMNxki8MN71Hwp6B", - "marketBaseVault": "CGNexJSnAQFYZRUWj5cqtb9QN2wHNo1WxuGLErbHmxxU", - "marketQuoteVault": "4i1ZsFFcVQG1Ufmeak8ibU4ur88t4QFLonyh9kR7Eh8m", - "marketBids": "DNkoCo9nN7mnnfWEvL6Qp9cyn5BjqDgVrgX3QktkXdnP", - "marketAsks": "5ZJAmbMPvjUXR345TkCH7kxXaeCGHKnoozrUhzD4TxjR", - "marketEventQueue": "FQnZjJVgRrrDJGA9ohPUrdmWMbuGwCGTVeZLqv1zJoc6" - }, - { - "id": "Ghj3v2qYbSp6XqmH4NV4KRu4Rrgqoh2Ra7L9jEdsbNzF", - "baseMint": "2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk", - "quoteMint": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "lpMint": "HYv3grQfi8QbV7nG7EFgNK1aJSrsJ7HynXJKJVPLL2Uh", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ABPcKmxjrGqSCQCvTBtjpRwLD7DJNmfhXsr6ADhjiLDZ", - "targetOrders": "7ATMf6E5StLSAtPYMoLTgZoAzmmXmii5CC6f5HYCjdKn", - "baseVault": "8jRAjkPkVLeBwA4BgTvS43irS8HPmBKXmqU6WonpdkxT", - "quoteVault": "EiuYikutCLtq1WDsinnZfXREM1vchgH5ruRJTNDYHA7b", - "withdrawQueue": "GVDZeTpSkseFrsooLNpeZzpzL3WkYo7cSVMLRHCKqbcQ", - "lpVault": "DZxRzxsztb5u3TFQaZd3ce8aNUbAikLAH79x2MMNdH86", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3KLNtqA8H4Em36tifoTHNqTZM6wiwbprYkTDyVJbrBuu", - "marketAuthority": "H6uYBVPb36jnUUxzGFWadNvuqMnCr12Sx6EbmebqwgfC", - "marketBaseVault": "DPdJZDKtTiaaqd52LPCvqyMPPNnJE3dSGAKVnZbsUSNm", - "marketQuoteVault": "5fpAmGMAqtkueG5w2doNDeBncFUvh4zgBsYoCwpGBkMA", - "marketBids": "GaGvreFFZ89SKsRMxn1MbDXwEvLKH7nd2EbykAEzvaRn", - "marketAsks": "CmktYGnATPGCus9rypT2q2GmEtXx6jv14Hz5v59iN9Em", - "marketEventQueue": "12kgGbCNQjcKWnezanmCfPodE2kkoWTojgmGkt47HhCH" - }, - { - "id": "GjrXcSvwzGrz1RwKYGVWdbZyXzyotgichSHB95moDmf8", - "baseMint": "GXMvfY2jpQctDqZ9RoU3oWPhufKiCcFEfchvYumtX7jd", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "D3iGro1vn6PWJXo9QAPj3dfta6dKkHHnmiiym2EfsAmi", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6As7AcwxnvawiY4mKnVTYqjTSRe9Uu2yW5hhJB97Ur6y", - "targetOrders": "BPU6CpQ9RVrftpofrXD3Gui5iNXpbiNiCm9ecQUahgH6", - "baseVault": "8Ev8a9a8ZQi2xHYa7fwkYqzrmMrwbnUf6D9z762zAWcF", - "quoteVault": "DriE8fPjPcTf7jzzyMqnQYqBPAVQPNS6bjZ4EABEJPUd", - "withdrawQueue": "CR4AmK8geX2e1VLdFKgC2raxMwB4JsVUKXd3mBGkv4YW", - "lpVault": "GLXgb5oGNHQAVr2t68sET3NGPBtDitE5cQaMG3zgc7D8", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GnKPri4thaGipzTbp8hhSGSrHgG4F8MFiZVrbRn16iG2", - "marketAuthority": "ECTnLdZEaxUiCwyjKcts3CoMfT4kj3CNfVCd9B18hRim", - "marketBaseVault": "P6qAvA6s7DHzzH4i74CUFAzx5bM4Yj3xk5TKmF7eWdb", - "marketQuoteVault": "8zFodcf4pKcRBq7Zhdg4tQeB76op7kSjPC2haPjPkDEm", - "marketBids": "7C1XnffUgQVnfRTUPBPxQQT1QKsHwnQ7ogAWmmJqbW9L", - "marketAsks": "Hbd8HWXcZDPUUHYXJLH4vn9t1SfQZ83fqf4jQN65QpYL", - "marketEventQueue": "5AB3QbR7Ck5qsn21fM5zBzxVUnyougXroWHeR33bscwH" - }, - { - "id": "GmaDNMWsTYWjaXVBjJTHNmCWAKU6cn5hhtWWYEZt4odo", - "baseMint": "3bRTivrVsitbmCTGtqwp7hxXPsybkjn4XLNtPsHqa3zR", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "cjZmbt8sJgaoyWYUttomAu5LJYU44ZrcKTbzTSEPDVw", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Crn5beRFeyj4Xw13E2wdJ9YkkLLEZzKYmtTV4LFDx3MN", - "targetOrders": "7XjS6MrvBRi9JeFWBMAYPaKhKgR3b7xnVdYDBkFb4CXR", - "baseVault": "8LoHX6f6bMdQVs4mThoH2KwX2dQDSkqVFADi4ZjDQv9T", - "quoteVault": "2Fwm8M8vuPXEXxvKz98VdawDxsK9W8uRuJyJhvtRdhid", - "withdrawQueue": "CW9zJ2JbBekkdd5SdvPapPcbziR8d1UHBzW7nNn1W3ga", - "lpVault": "FVHsnC1nhwMcrAzFwcK4dgUtDdYFM1VrTJ8Rp8Mb1LkY", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3WptgZZu34aiDrLMUiPntTYZGNZ72yT1yxHYxSdbTArX", - "marketAuthority": "MKCHeoqNGWU8TJBkdF1M76nMUteJCwuBRUJfCtR3iV7", - "marketBaseVault": "Dd9F1fugQj2xtduyNvFS5TtxP9vKnuxVMcrPsHFnLyqp", - "marketQuoteVault": "BnXXu8kLUXrwg3MpcVRVPLZw9bpX2mLd95qtCMnSUtu7", - "marketBids": "GzHpnQSfS7KdqLKgiEEP7pkYnwEBz9zaE7De2CjmCrNV", - "marketAsks": "FpEBAT9qP1so4ASUTiEWxyXH2SJvgoBYUiZ1AbPimcS7", - "marketEventQueue": "CUMDMV9KtE22RUZECUNHxiq7FmUiRusyKa1rHUJfRptq" - }, - { - "id": "GQJjrG6f8HbxkE3ZVSRpzoyWhQ2RiivT68BybVK9DxME", - "baseMint": "a11bdAAuV8iB2fu7X6AxAvDTo1QZ8FXB3kk5eecdasp", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "ECHfxkf5zjjZFTX95QfFahNyzG7feyEKcfTdjsdrMSGU", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AwHZdJrEDWAFhxsdsErvVPjWyE5JEY5Xq6cq4JjZX73L", - "targetOrders": "AdWdYACEwtJLtNsqjBeAuXhHFiJPNJHkScYrdQeJWV6W", - "baseVault": "3zrQ9od43vB9sV1MNbM68VnkLCfq9dVUvM1hmp8tcJNz", - "quoteVault": "5odFuHq8jhqtNBKtCu4F2GvUiH5hB1zVfpS9XXbLf35d", - "withdrawQueue": "FHi35hxZM29USwLwdAhbT8u7YhW8BPWvtLHyLnXPebW2", - "lpVault": "53fmAZj3d3YEnHY4PvyCE1Cx23x5g3d1ejwyDAZd3NzH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FrR9FBmiBjm2GjLZbfnCcgkbueUJ78NbBx1qcQKPUQe8", - "marketAuthority": "A3LkbNQUjz1q3Ux5kQKCzNMFJw3yxk9qx1RtuQBXbZZe", - "marketBaseVault": "9yg6VjgPUbojGn9d2n3UpX7B6gz7todGfTcV8apV5wkL", - "marketQuoteVault": "BDdh4ane6wXkRdbqUuMGYYR4ggf3GufUbjT2TxpHiAzU", - "marketBids": "4W6ZoBB2QNBe6AYM6ofpWjerAsnJad93hVfdC5WMjRsX", - "marketAsks": "64yfFmc7ivEknLRT2nvUmWkASGwz8MPxtcPdaiWUffro", - "marketEventQueue": "GgJ8bQSZ6Lt2mEurrhzLMWFMzTgVFq8ax91QzmZzYiS6" - }, - { - "id": "GRM4jGMtx64sEocBFz6ZgdogF2fyTWiixht8thZoHjkK", - "baseMint": "SLNDpmoWTVADgEdndyvWzroNL7zSi1dF9PC3xHGtPwp", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EunE9uDh2cGsyJcsGuGKc6wte7kBn8iye2gzC4w2ePHn", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GLgrNWTUfX4n165WaMG4dELg4e7E7RBNWMzBFvYKbcbs", - "targetOrders": "FCa9xL1TeJrDvhxyuc9J3o4KNtXBZREC3Kxr5sYVZNtQ", - "baseVault": "DCHrCqguY9Jtn8xutdVPAhCbLayYaksPSwqg5aZzFXVM", - "quoteVault": "BxzizWAWk91TKbMAZM4F9zhUM5omdtdhjQQSdEM5sEXA", - "withdrawQueue": "2TYYWf8RKyu5YoH5bwxiJnCyHdAeWUMadBDMotuNWoR8", - "lpVault": "53KFE2hkixwSRMj8Co9dZfG8uj2PXmfm1pBBUaqCocsA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "F9y9NM83kBMzBmMvNT18mkcFuNAPhNRhx7pnz9EDWwfv", - "marketAuthority": "HP7nqJpWXBS91fRncBCawqidJhxqNwKbS84Ni3HBTiGG", - "marketBaseVault": "5JDR5i3wqrLxoZfaytoW14hti9pxVEouRy5pUtyhisYD", - "marketQuoteVault": "6ktrwB3FevRNdNHXW7n6ufk2h1jwKnWFtjhHgNwYaxJb", - "marketBids": "EcwoMdYezDRLVNFzSzf7jKEuUe32KHp5ddU7RZWdAnWh", - "marketAsks": "4iLAK21RWx2XRyXzHhhuoj7hhjVFcrUiMqMSRGandobn", - "marketEventQueue": "8so7uCu3u53PUWU8UZSTJG1b9agvQtQms9gDDsynuXr1" - }, - { - "id": "H3dhkXcC5MRN7VRXNbWVSvogH8mUQPzpn8PYQL7HfBVg", - "baseMint": "ErGB9xa24Szxbk1M28u2Tx8rKPqzL6BroNkkzk5rG4zj", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "HYUKXgpjaxMXHttyrFYtv3z2rdhZ1U9QDH8zEc8BooQC", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7yHu2fwMQDA7vx5RJMX1TyzDE2cJx6u1v4abTgfEP8rd", - "targetOrders": "BXjSVXdMUYM3CpAs97SE5e9YnxC2NLqaT6tzwNiJNi6r", - "baseVault": "EAz41ABjVhXLWFXcVdC6WtYBjnVqBZQw7XxXBd8J8KMp", - "quoteVault": "6gBKhNH2U1Qrxg73Eo6BMuXLoW2H4DML18AnALSrbrXr", - "withdrawQueue": "9Pczi311AjZRXukgUws9QVPYBswXmMETZTM4TFcjqd4s", - "lpVault": "BNRZ1W1QCw9v6LNgor1fU91X49WyPUnTWEUJ6H7HVefj", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FE5nRChviHFXnUDPRpPwHcPoQSxXwjAB5gdPFJLweEYK", - "marketAuthority": "3x6rbV78zDotLTfat9tXpWgCzqKYBJKEzaDEWStcumud", - "marketBaseVault": "EgZKQ4zMUiNNXFzTJ89eyL4gjfF2yCrH1seQHTnwihAc", - "marketQuoteVault": "FCnpLA4Xzo4GKctHwMydTx81NRgbAxsZTreT9zHAEV8d", - "marketBids": "F4D6Qe2FcVSLDGByxCQoMeCdaLQF3Z7vuWnrXoEW3xss", - "marketAsks": "9oPEuJtJQTaFWqhkA9omNzKoz8BLEFmGfFyPdVYxkk8B", - "marketEventQueue": "6Bb5UtTAu6VBJ71dh8vGji6JBRsajRGKXaxhtRkqwy7R" - }, - { - "id": "HARRXESCwid3xMi2qThag1PXzmp6rDhAzMR9THhFRQGf", - "baseMint": "CRWNYkqdgvhGGae9CKfNka58j6QQkaD5bLhKXvUYqnc1", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "5Cz9wGStNjiUg81q8t6sJJeckuT2C14CYSfyQbtYirSX", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HN5KP7RDZT5w1oPB6GRrqawYJFrtrY58Ck2tDxVrD5Af", - "targetOrders": "FERGssxP2qEN9jEjQ2frQx3ckAneXJzXf6JMXZYmMRc6", - "baseVault": "FZKDZoUDjo5Ck2apVqSyk5ppKuUqSbNQgg4Uu7y6tjuK", - "quoteVault": "okPqapFBcHoRRYyER9a8z1C4xBuueu5RbJGGhJ8TemS", - "withdrawQueue": "CNkzEN6tueKqHwD4JhAFQa6LDT3kfYx91jBPxB3nsiR4", - "lpVault": "Cet73tyKCqjjUJxBueqtGxzy7C6STF3vP2MVzaFD8ryN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6NRE3U7BRWftimyzmKoNSseWDMMxzuoTefxCRBciwD3", - "marketAuthority": "8NJSfgh9fPkRw1odRyJW2ftTeK5BnTUwKpiEGs93wktu", - "marketBaseVault": "DovSvXvzRUvUYWCzJCtbYHDGu9QTsfd4v3szLYK8qq9V", - "marketQuoteVault": "54CyipC5PJnmEHwCPqEgzPEPVEMRdPebCxpoUbZBeZmC", - "marketBids": "38V5FuifMSNoNdtCzPcxLuJzUQ2YAZ1w84pzqyQqwdCF", - "marketAsks": "Hz1qNHXFyfoz5FddGoszJgSp4dhaBn8GqbntUympRNkK", - "marketEventQueue": "CubKCz6q5Q8Q9ZnW5qTYY6M9q1WmEYuvuEtmKYbfjLjN" - }, - { - "id": "HcqHvH27wk42L1ND5YPhLDJu7oGsU7HGSreMiXdq5LNK", - "baseMint": "FNFKRV3V8DtA3gVJN6UshMiLGYA8izxFwkNWmJbFjmRj", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "84fmrerHGohoRf4iLPDQ1KG4CjSjCRksYWGzjWfCRM8a", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "85ZThysvEWpvFQVaBySCjSufxBrBQ3x7oBM4Tb6Ltn7j", - "targetOrders": "CJrGZVb2uSccqX98RyhukEPKWSMEuvcamnUuenLzj9pH", - "baseVault": "FEFD8JuYMeB3SRACZa5EsFJPoURHjsPsrKFjRpWJJr3G", - "quoteVault": "g8uv7UBpdu9UkJCsqfMkGzMNtYqKXfh8m7rHFLNtmA6", - "withdrawQueue": "EPyYVUgMAcY1Zu1vFD7aJPjPNpe18m7Ab4CVoV5AAp9q", - "lpVault": "7yFVKL9K4othAe5PcBXL3WNVM6ebtC4M1PLqP3RQWidC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2sdQQDyBsHwQBRJFsYAGpLZcxzGscMUd5uxr8jowyYHs", - "marketAuthority": "C98tgmCJpdXYgwsURupvWrA6zhzyGsbE3g4NUxi9PUG4", - "marketBaseVault": "HHBEQnNnPwMhRbyiVYvET2GfdFs2tUF4kcyYUd7mdU7k", - "marketQuoteVault": "AQ4XA4eUPbmkrxForC6P24gMW6ozv4XUY8HzuAs5SKsA", - "marketBids": "2TZ3U3wed6DeM6teUJfZCYFerthdG2xYKcYBUGZtTozE", - "marketAsks": "FTnrFFR7HtYFCi6citKX2NFgdAP2KumPdpSs23V8VQHa", - "marketEventQueue": "AVL9buJzjn69bo8ZtK6UacL7KaNKQSQyEJ9jPkmLjDbV" - }, - { - "id": "He3iAEV5rYjv6Xf7PxKro19eVrC3QAcdic5CF2D2obPt", - "baseMint": "2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "nPrB78ETY8661fUgohpuVusNCZnedYCgghzRJzxWnVb", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8x4uasC632WSrk3wgwoCWHy7MK7Xo2WKAe9vV93tj5se", - "targetOrders": "G1eji3rrfRFfvHUbPEEbvnjmJ4eEyXeiJBVbMTUPfKL1", - "baseVault": "DZZwxvJakqbraXTbjRW3QoGbW5GK4R5nmyrrGrFMKWgh", - "quoteVault": "HoGPb5Rp44TyR1EpM5pjQQyFUdgteeuzuMHtimGkAVHo", - "withdrawQueue": "EispXkJcfh2PZA2fSXWsAanEGq1GHXzRRtu1DuqADQsL", - "lpVault": "9SrcJk8TB4JvutZcA4tMvvkdnxCXda8Gtepre7jcCaQr", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7dLVkUfBVfCGkFhSXDCq1ukM9usathSgS716t643iFGF", - "marketAuthority": "CVVGPFejAj3A75qPy2116iJFma7zGEuL8DgnxhwUaFBF", - "marketBaseVault": "2CZ9JbDYPux5obFXb9sefwKyG6cyteNBSzbstYQ3iZxE", - "marketQuoteVault": "D2f4NG1NC1yeBM2SgRe5YUF91w3M4naumGQMWjGtxiiE", - "marketBids": "J8a3dcUkMwrE5kxN86gsL1Mwrg63RnGdvWsPbgdFqC6X", - "marketAsks": "F6oqP13HNZho3bhwuxTmic4w5iNgTdn89HdihMUNR24i", - "marketEventQueue": "CRjXyfAxboMfCAmsvBw7pdvkfBY7XyGxB7CBTuDkm67v" - }, - { - "id": "HopVRTvFvRe1ED3dRCQrt1h5onkMvY3tKUHRVQMc7MMH", - "baseMint": "HysWcbHiYY9888pHbaqhwLYZQeZrcQMXKQWRqS7zcPK5", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6PSoJQ7myQ1BJtbQC6oiWR8HSecQGyoWsPYTZRJo2ci3", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BWJ96nvwjxqkjbu2rQN2H4U3E5PjWRMjrw2gqRcicazt", - "targetOrders": "6JtLCecsVp3UN1eEyZCHUBXKmd4HqnzYXB3AcS1DCEFe", - "baseVault": "9pyHCyqHKvfbsTeYNQRTf5zHLzZedmxWA7YGC4ybCfBD", - "quoteVault": "3WuvWRBqCtw1zqKmgZ79t5QK8Ph7Rfwf7nYB8Tv5KV2C", - "withdrawQueue": "B5ixFzgKhBysnWpJcEiozrf8Ykc361xKwkKstWCBLggW", - "lpVault": "F7NwbHNfgU9p1iQAkjDs8HnbVVDsCXfSxv5jn4LxUxKn", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HZCheduA4nsSuQpVww1TiyKZpXSAitqaXxjBD2ymg22X", - "marketAuthority": "2qodg1XKZ5hauWnz1hBBfUWzMbRqABym2hMgLSS7pmJ2", - "marketBaseVault": "69bNeKy1gM4xDfSfjCaVeGpoBR2hPeXioJMNShu1BjdS", - "marketQuoteVault": "Gzbck4nwKYEEmwHxJxBpBpGhuMZaDhL1UqVBVFTrReki", - "marketBids": "AaWuUgau8jRbbo2tVv3oFcAUyrSPXQxJkPUYsUPeCFe6", - "marketAsks": "HFZCap81Q9JAuySeggJrQvw9XJuVdbb9R617BeTnsZbA", - "marketEventQueue": "DQZDYYbCCknsvAUadroAs3YPH8XU4Bo7iCmTy3GAWFrF" - }, - { - "id": "Hr8i6MAm4W5Lwb2fB2CD44A2t3Ag3gGc1rmd6amrWsWC", - "baseMint": "CWE8jPTUYhdCTZYWPTe1o5DFqfdjzWKc9WKz6rSjQUdG", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BqjoYjqKrXtfBKXeaWeAT5sYCy7wsAYf3XjgDWsHSBRs", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "G4WdXwbczwDSs6iQmYt1F3sHDhfL6aD2uBkbAoMaaTt4", - "targetOrders": "Hf3g2Q63UPSLFSCKZBPJvjVVZxVr83rXm1xWR7yC6spn", - "baseVault": "2ueuL35kQShG1ebZz3Cov4ug9Ex6xVXx4Fc4ZKvxFqMz", - "quoteVault": "66JxeTwodpafkYLPYYAFoVoTh6ukNYoHvtwMMSzSPBCb", - "withdrawQueue": "AgVo29AiDosdiXysfwMj8bF2AyD1Nvmn971x8PLwaNAA", - "lpVault": "58EPUPaefpjDxUppc4oyDeDGc9n7sUo7vapinKXigbd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3hwH1txjJVS8qv588tWrjHfRxdqNjBykM1kMcit484up", - "marketAuthority": "8zqs77myZg6wkPjbh9YdSKtNmfPh4FJTzeo9R39mbjCm", - "marketBaseVault": "9BswoEnX3SN7YUnRujZa5ygiL8AXVHXE4xqp8USX4QSY", - "marketQuoteVault": "9TibPFxakkdogUYizRhj9Av92fxuY2HxS3nrmme81Sma", - "marketBids": "GhmGNpJhGDz6zhmJ2kskmETbX9SGxhstRsmUejMXC24t", - "marketAsks": "83KiGivH1w4SiSK9YoN9WZrTSmtwveuCUd1nuZ9AFd2V", - "marketEventQueue": "9ZZ8eGhTEYK3uBNaFWSYo6ugLD6UVvudxpFXff7XSrmx" - }, - { - "id": "HuMDhYhW1BmBjXoJZBdjqaqoD3ehQeCUMbDSiZsaXSDU", - "baseMint": "4wjPQJ6PrkC4dHhYghwJzGBVP78DkBzA2U3kHoFNBuhj", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "49YUsDrThJosHSagCn1F59Uc9NRxbr9thVrZikUnQDXy", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7wdwaVqX54dpmHsAv1p1j6CNX384ngTdPw6hhyrqnSkm", - "targetOrders": "35KVohngiK6EuhFVSycgVkedgmxGjyebjHBEWnTmZSaJ", - "baseVault": "DNfbb7s6zD1kWpGHCCEv6BrLYUFdvoqbLE7pkRpWEAD3", - "quoteVault": "6tPg3nmHnvN8HfCfLC9EEpB1dvV3sB5XtwaQeqpwaqzY", - "withdrawQueue": "2bQ5JURC12KdxzigEzUTC15wMvFb8Lf6UQWDMTr4by3f", - "lpVault": "Exj93mjyV378SD3CTDAyh5V5zEf9pSPU12yKJtp3hjgQ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FL8yPAyVTepV5YfzDfJvNu6fGL7Rcv5v653LdZ6h4Bsu", - "marketAuthority": "CEhFiD6xAgRptnuyUJg3iAkN7Zi65ZNoyi9uBPt5V8Y", - "marketBaseVault": "3VB8kEgcpuFzSf6Nbe3Nm2BiUNGxmJpZGbYSoqnDruRp", - "marketQuoteVault": "DYRShjB8necZU1Qx9FVPDLSjuu3zEkbHgd6BEkMZPS23", - "marketBids": "BkiWgktHinZLpc6ochQGUujh4aLQL7S9ZvhnRY64Z5Je", - "marketAsks": "EcHLYi56KcNKsiUiHb7mXrT29YJhArdizegkjmVJ6LeJ", - "marketEventQueue": "9U3PefXaFHYiTaCz2p4SsW6X5RK9Kq7FxUeB3PTwpG1a" - }, - { - "id": "Hv1BFhyADPjYXTqEeMgwzoybnNwYrHXNv7U2VjcAuEDr", - "baseMint": "5gs8nf4wojB5EXgDUWNLwXpknzgV2YWDhveAeBZpVLbp", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GCEQbLg4ik5YJ4CMcbtuVqEc4sjLdSGy34rFk1CtGjdg", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "JFR4ZGJwF2sA7q2Fkve1be39wnbV8EKmb3BTCi5grc6", - "targetOrders": "7TeQ8U9pZEA52Cek6FVRNisLsgsPwFy7EEUiXAiyjWQV", - "baseVault": "3UJZNSSi8JkeA9dP53Aok8EHbgE82K9HYKAGkgyxjyur", - "quoteVault": "6tTg68RpRDjVuEda62ihfTxsiMCN8Vpox4E9WvW5acRa", - "withdrawQueue": "4sWDRH7J6JU33y8JLshEt3oMSYXxw5H2Avc4DJCmMfwb", - "lpVault": "2KzSH7behRFcovtVqxQ2Xz3MmDga3tLECDP11UXJqReA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6QM3iZfkVc5Yyb5z8Uya1mvqU1JBN9ez81u9463px45A", - "marketAuthority": "FLL49yBue1tqWDjLW9ztRaVULZz91uKsEjzJ6h5scgqt", - "marketBaseVault": "5cBmqRj57VW7bpK9RscDyJjcu7S3QNUsML3axNxA3ja7", - "marketQuoteVault": "J2Yw8yeqdh89mBQfSkEnhQXudfgiuy6G11s4cduQuiN4", - "marketBids": "6Z7VQehWjM831vyTTdJnt1NyQxhXtwLKKHDjhiey1MJb", - "marketAsks": "uD6PfpLoCihKD9uVRm4AE1tb1XsAneyMKtsJu43ynYY", - "marketEventQueue": "9qQA1p3YW7LMEF3kqsYT3LsDw4GwMaopn1ghzWnN5RdS" - }, - { - "id": "J3CoGcJqHquUdSgS7qAwdGbp3so4EpLX8eVDdGuauvi", - "baseMint": "SLRSSpSLUTP7okbCUBYStWCo1vUgyt775faPqz8HUMr", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "2pk78vsKT3jfJAcN2zbpMUnrR57SZrxHqaZYyFgp92mM", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FhtXN2pPZ8JMxGcLKSfRJtGsorSCXBKJyw3n7SsEc1aR", - "targetOrders": "2hdnnbsAu7pCf6nX5fDKPAdThLZmmWFQ7Kcq2cdShPGW", - "baseVault": "8QWf745UQeyMyM1qAAsCeb73jTvQvpm2diVgjNvHgbVX", - "quoteVault": "5TsxBaazJ7Zdx4x4Zd2zC7TY98EVSwGY7hnioS2omkx1", - "withdrawQueue": "6w9z1TGNkMU2qBHj5wzfaoqCLn7cPLKvPa23qeffsn9U", - "lpVault": "39VEjufVUfdASteaQstBT25zQuLUha8ZrqYQfcDdJ47A", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BkJVRQZ7PjfwevMKsyjjpGZ4j6sBu9j5QTUmKuTLZNrq", - "marketAuthority": "E91Pu1z4q4Nr5mGSVcwyDzzbQC3LdDBzmFyLoXfXfg17", - "marketBaseVault": "F71huJuAGZ8Q9xVxQueLQ8vDQD6Nq8MkJJsyM2S937sy", - "marketQuoteVault": "AbmAd3LgTowBANXnCNPLctxL7PReirJv5VcizvQ3mfah", - "marketBids": "8KouZyh14hmqurZZd1YRpwZ9pMVkWWHPnKTsETSYUuQQ", - "marketAsks": "NBpY6i9KbWx2V5sS3iP54KYYaHg8aVB6WB43ibVFUPo", - "marketEventQueue": "BMZfHb6CkiYwdgfVkAiiy4SWf6PHuRPFZyZWQNw1uDZx" - }, - { - "id": "MphbxYtji1FSkm7G2FNGpUUz5AWn7iRPNFAvEqD4mzE", - "baseMint": "7zBWymxbZt7PVHQzfi3i85frc1YRiQc23K7bh3gos8ZC", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3MwHyHCRfVqtH3ABFtdKXdY9dwemr9GGxQFaBkeq6NjY", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6zLi1A5MYMVBtaJ8T1Un5MYoNvvaLBXo3Y1wSytdxG9c", - "targetOrders": "FavPWAiHfGL1rYGwWMMY26B8bA6y5pkhbdq6jvv5FvM2", - "baseVault": "8TePpe8C43YiphVZQPyeUUL7dy1gv1vu99bwMLrnxDUU", - "quoteVault": "Ac7fBPfyitRUgN2nTJ56nGfuYK6NXsC96aKgDgZSCReK", - "withdrawQueue": "EQtU6bpd6AX3C4LnzXXHbuyrooDQE1a6xgvoBfBFvrx7", - "lpVault": "FWn67c222MrFFuvnAQvFHFksqD989F8fPkX8xqWBCrK5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5fbYoaSBvAD8rW6zXo6oWqcCsgbYZCecbxAouk97p8SM", - "marketAuthority": "14jVcqFL27atPUFhYoFtVgbCa2tnvfeayNqoukaPfP7h", - "marketBaseVault": "9sS11MD83k3Zn9VzYzyEZSviSXwJtUtVnc9NMq4MUpkf", - "marketQuoteVault": "HQhCfR2hUgMopxh2dpfpTGccG55gGpwn2QNJCHpvrcyL", - "marketBids": "D6eckG9iezMUAqt4E8vwHt9enkV9Sw3Fyj4fFPCkRaRW", - "marketAsks": "32HGbWJsPr1bZd8XnvESgCY94XK4hSLypfNiEDxFzDve", - "marketEventQueue": "BcFtMNmx5B47F6VXocr9YJqCWHLybayC67rvKtaZ7iS2" - }, - { - "id": "SJmR8rJgzzCi4sPjGnrNsqY4akQb3jn5nsxZBhyEifC", - "baseMint": "BLwTnYKqf7u4qjgZrrsKeNs2EzWkMLqVCu6j8iHyrNA3", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "9nQPYJvysyfnXhQ6nkK5V7sZG26hmDgusfdNQijRk5LD", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8pt8zWa9hsRSsiCJtVWnApXGBkmzSubjqf9sbgkbj9LS", - "targetOrders": "Gg6gGVaokrVMJWtgDbamPwVG8PBN3VbgHLFghfSn3JxY", - "baseVault": "B345z8QcC2WvCwKjeTveLHAuEghumw2qH2xPxAbW7Awd", - "quoteVault": "EPFPMhTRNA6f7J1NzEZ1rkWyhfexZBr9VX3MAn3C6Ce4", - "withdrawQueue": "E8PcDA6vn9WHRsrMYZvKy2D2CxTB28Bp2cKAYcu16JH9", - "lpVault": "47GcR2477mHukyTte1LpDShs4RUmkcF2rejJvisRFALB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6Fcw8aEs7oP7YeuMrM2JgAQUotYxa4WHKHWdLLXssA3R", - "marketAuthority": "5JEwQ7hM1qFCBwJkZ2JyjkoJ99ojJXRx2bFjLcFobDvC", - "marketBaseVault": "CTv9hnW3nbANzJ2yyzmyMCoUxv5s95ndxcBbLzV39z3w", - "marketQuoteVault": "GXFttVfXbH7rU6GJnBVs3LyyuiPU8a6sW2tv5K5ZGEAQ", - "marketBids": "3CNgQ6KpTQYKX9s1CSy5y16ZtnXqYfcTHikmHjEjXKJm", - "marketAsks": "7VxSfKDL7i3FmpJLnK4v7YgidNa1t7SCo84FY7YinQyA", - "marketEventQueue": "9ote3YanmgQgL6vPBUGJVZyFsp6HDJNviTw7ghxzMDLT" - }, - { - "id": "SU7vPveBjEuR5tgQwidRqqTxn1WwraHpydHHBpM2W96", - "baseMint": "CiKu4eHsVrc1eueVQeHn7qhXTcVu95gSQmBpX4utjL9z", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AcjX5pmTMGSgxkdxc3r82r6WMKBvS6eQXXFz5ck5KKUa", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GQBHmoAkWiXEsoGYBqFGifCwDcfU2QYCwL8GHWFAbBqZ", - "targetOrders": "m7JmrtyJq4CxTYPmB3WKMVbsDxge8SD95rWHb4WREEz", - "baseVault": "Ar37g5ebxRMq1NJyswFw9JKwRzZ8CzVr9SEMFH5wy9P8", - "quoteVault": "EGynHanKeLLUYeWFE6ULXE1QRD8YPTV7ehSnphWsLqq2", - "withdrawQueue": "5VBUYLnVPHKtiFSqSEhaANF5fXv7QzATRB5BRHrQv3B", - "lpVault": "G5Wrnafh95moPCxvKM5QNTMwAFQMGnnB9YTh24TvWnrD", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Er7Jp4PADPVHifykFwbVoHdkL1RtZSsx9zGJrPJTrCgW", - "marketAuthority": "HoDhphLcgw8hb6GdTicv6V9are7Yi7xXvUriwWwRWuRk", - "marketBaseVault": "7nbNVNdhzZoD3KdjKnGRXbb9pPnDP2CSK1tPoRNvq94m", - "marketQuoteVault": "6ovLsr9T6754PrgH3QwFCPtjizWEh6H3DDpc3QXnMsqi", - "marketBids": "2FkkrUR6MWq7Qd1LLMnR4NWmKcnqkNhK6NK6x7Wi1aRD", - "marketAsks": "2Qxa2n6rRGm5f3Qc8H9HDV7wYsjnXZuXEWjgQs1bEwzK", - "marketEventQueue": "5jGZmP29GfcEWKVHGxCymuD5qGg33kM2rPfPvD1BFS35" - }, - { - "id": "vVXfY15WdPsCmLvbiP4hWWECPFeAvPTuPNq3Q4BXfhy", - "baseMint": "8upjSpvjcdpuzhfR1zriwg5NXkwDruejqNE9WNbPRtyA", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "A8ZYmnZ1vwxUa4wpJVUaJgegsuTEz5TKy5CiJXffvmpt", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "A7RFkvmDFN4Qev8XgGAqSr5W75sNhhtCY3ZcGHZiDDo1", - "targetOrders": "HRiPQyFJfzF7WgC4g2cFbxuKgqn1vKVRjTCuZTNGim36", - "baseVault": "BKqBnj1TLpW4UEBbZn6aVoPLLBHDB6NTEL5nFNRqX7e7", - "quoteVault": "AN7XxHrrcFL7629WySWVA2Tq9inczxkbE6YqgZ31rDnG", - "withdrawQueue": "29WgH1suwTnhL4JUwDMUQQpUzypet8PHEh8jQpZtiDBK", - "lpVault": "3XCGBJpfHV5VYkz92nqzRtHahTiHXjYzVs4PargSpYwS", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "72aW3Sgp1hMTXUiCq8aJ39DX2Jr7sZgumAvdLrLuCMLe", - "marketAuthority": "FCZkJzztVTx6qKVec25jA3m4XjeGBH1iukGdDqDBHPvG", - "marketBaseVault": "8FMjC6yopBVYTXcYSGdFgoh6AFpwTdkJAGXxBeoV8xSq", - "marketQuoteVault": "5vgxuCqMn7DUt6Le6EGhdMzZjPQrtD1x4TD9zGw3mPte", - "marketBids": "F3PQsAGiFf8fSySjUGgP3NQdAGSnioAThncyfd26GKZ3", - "marketAsks": "6KyB4XprAw7Mgp1YMMsxRGx8T59Y5Lcu6s1FcwFrXy3i", - "marketEventQueue": "Due4ZmGX2u7an9DPMvk3uX3sXYgngRatP1XmwzEgk1tT" - }, - { - "id": "ynV2H2b7FcRBho2TvE25Zc4gDeuu2N45rUw9DuJYjJ9", - "baseMint": "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "quoteMint": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "lpMint": "92bcERNtUmuaJ6mwLSxYHZYSph37jdKxRdoYNxpcYNPp", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FD7fCGepsCf3bBWF4EmPHuKCNuE9UmqqTHVsAsQSKv6b", - "targetOrders": "HBpTcRToBmQKWTwCHgziFhoRkzzEdXEyAAqHoTLpyMXg", - "baseVault": "CXmwnKYkXebSbiFdNa2AVF34iRQPaf6jecyLWkEra6Dd", - "quoteVault": "GtdKqFoUtHC8vH1rMZvW2eVqqFa3vRphqkNCviog4LAK", - "withdrawQueue": "3gctDYUqCgeinnxecj3iifkopbG88Ars14QhAf6UoCwY", - "lpVault": "5TrJppACzkDAra1MUgZ1rCm4pvYZ2gVYWBAXPt7pMQDt", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HvanEnuruBXBPJymSLr9EmsFUnZcbY97B7RBwZAmfcax", - "marketAuthority": "mZrDXx1TQizPd9CzToBx8FqqrPCPdePHy6ttgBdNPuB", - "marketBaseVault": "DxXBH5NCTENPh6zsfMstyHhoBtdaVnYSzHgaa6GyVbfY", - "marketQuoteVault": "9XqpiagW7bnAbMwpc85M2hfrcqxtvfgZucyrYPAPkcvq", - "marketBids": "UPgp2Apw1weBoAVyozcc4WuAJrCJPf6ckSZa9psCe63", - "marketAsks": "HQyMusq5noGcSz2VoPqvztZyEAy8K1Mx6F37bN5ppH35", - "marketEventQueue": "D4bcCmeFca5rF8KC1JDJkJTiRLLBmoQAdNS2x7zTaqF4" - }, - { - "id": "ZfvDXXUhZDzDVsapffUyXHj9ByCoPjP4thL6YXcZ9ix", - "baseMint": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4xTpJ4p76bAeggXoYywpCCNKfJspbuRzZ79R7pRhbqSf", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4zoatXFjMSirW2niUNhekxqeEZujjC1oioKCEJQMLeWF", - "targetOrders": "Kq9Vgb8ntBzZy5doEER2p4Zpt8SqW2GqJgY5BgWRjDn", - "baseVault": "8JUjWjAyXTMB4ZXcV7nk3p6Gg1fWAAoSck7xekuyADKL", - "quoteVault": "DaXyxj42ZDrp3mjrL9pYjPNyBp5P8A2f37am4Kd4EyrK", - "withdrawQueue": "CfjpUvQAoU4hadb9nReTCAqBFFP7MpJyBW97ezbiWgsQ", - "lpVault": "3EdqPYv3hLJFXC3U9LH7yA7HX6Z7gRxT7vGQQJrxScDH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6oGsL2puUgySccKzn9XA9afqF217LfxP5ocq4B3LWsjy", - "marketAuthority": "9dEVMESKXcMQNndoPc5ji9iTeDJ9GfToboy8prkZeT96", - "marketBaseVault": "2y3BtF5oRBpLwdoaGjLkfmT3FY3YbZCKPbA9zvvx8Pz7", - "marketQuoteVault": "6w5hF2hceQRZbaxjPJutiWSPAFWDkp3YbY2Aq3RpCSKe", - "marketBids": "8qyWhEcpuvEsdCmY1kvEnkTfgGeWHmi73Mta5jgWDTuT", - "marketAsks": "PPnJy6No31U45SVSjWTr45R8Q73X6bNHfxdFqr2vMq3", - "marketEventQueue": "BC8Tdzz7rwvuYkJWKnPnyguva27PQP5DTxosHVQrEzg9" - }, - { - "id": "zoouer92idprkptX76yvhp4stK2keTzJpMNkeLqtxAx", - "baseMint": "GFX1ZjR2P15tmrSwow6FjyDYcEkoFb4p4gJCpLBjaxHD", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4svqAwrLPGRDCQuuieYTmtLXF75wiahjeK2rEN9tY1YL", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6jQpC6ZE5sRAPbfShTxymJLE5pXUM1AGfbmyyBddCP5e", - "targetOrders": "5aDvGGEbb1ECP4yNEVdP9BbXFgX5Ut3Zb3dBjDsFQ9Kh", - "baseVault": "2RPyUYLEWRHXB7hN9p795gorU6bvPJ9UEKFniw4Cpgcm", - "quoteVault": "eRtMAhZz6qXqsrRV9cgS6n6xQyvqwkTFZXaw5RP1yxu", - "withdrawQueue": "FHLLxn9BTMF65qDc7CjHjN17qEoMVZYfgM9BTgwncGBo", - "lpVault": "AewsiURuxZ5McY3hi3zsKAgd2R7q2QWVMmWcJH7pAvaK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2wgi2FabNsSDdb8dke9mHFB67QtMYjYa318HpSqyJLDD", - "marketAuthority": "5RKd5tWKtvEocrQgf8vCo3BkPcjXYnTJWRBmNadCMemR", - "marketBaseVault": "DckgBxFNQNQA796Jg12dRpCZZ1nBqus4PDbKQhfmJraf", - "marketQuoteVault": "2jZJzfVGgHdzVq1e3HpRz9U5HnByoazyMzQ3jexn4jUE", - "marketBids": "5iME2kvAv5jVsw9df7EXXUNQtV1uUyFtibeHj6fF5T3q", - "marketAsks": "3dBK4di97jAPzQAkz39wUwmQ6qbW98H1zsmrNxEUZVif", - "marketEventQueue": "CzKrdXjLtZRq3AyrwN9MZ667Ka9buVFESJUbEWBezxCV" - }, - { - "id": "zuivKkgkNFFkV9jfNpsU1p5tWNbDWUEx5XX16m4k2Ej", - "baseMint": "6F9XriABHfWhit6zmMUYAQBSy6XK5VF1cHXuW5LDpRtC", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CjTLvvKSQdEujcSzeZRYgk4w1DpuXBbMppLHaxZyz11Y", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "E1kouJkEmATcSrsbCcZLYo5YJnYkXjAD8GwW5RC4evXb", - "targetOrders": "ECzY8XJHTLLspi3zmqh3vkeZSj5Dswh47MwZ6TWHpBQb", - "baseVault": "HAULecjkcF2GHGSQ566yRBuwRoHxH24YGZs1n6B3QpAG", - "quoteVault": "9mo6Dhx8RhrwNqxCBGcfqEZzmGPGr4hz1mfTdW8tpsq7", - "withdrawQueue": "839mt1VUqTTyK18ibCoMoZ6Lpm2EmzyocSqjPYGn4rXc", - "lpVault": "4pnYCNbsdhywXRVZGWtGyEJ4Ng1CfYCue6xGJivKbVYo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HCvX4un57v1SdYQ2LFywaDYyZySqLHMQ5cojq5kQJM3y", - "marketAuthority": "HxhgxLeE3agcvWNx9og8asUs7JKV8TXfQdo1qLK7uGUQ", - "marketBaseVault": "MhKHNubLV6SpsTosFSFnx2cPTxhfXZRYtsw97sN74eu", - "marketQuoteVault": "72SGvxnDRo9wuzcNrJxrpK5YNjXuwcfyBof9BuXELFhp", - "marketBids": "6KgrT2PgdBQEfFctsXhgFbLKTbFErVj2SBa3zJTkSbLd", - "marketAsks": "EVtsr3WNub2i9jVBEj9aHmsxrumBFmHoLp6QyhuzFP5G", - "marketEventQueue": "EpwsM7YCYEaC2LynGVSyWNUYugaxNYymPgqAX1cAvhKu" - } - ], - "unOfficial": [ - { - "id": "12e58eh6SNkpACeLcrpo8UPshDuCvNF7MYMKwAxDtCMJ", - "baseMint": "Gqiou284yNmVtTGVVM8guof4DaQtbrEDC4kgjNHZbbo4", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BoBKa2vyyVkLb5jFJfsc2PrsfoiqDyt2EtApwTLosziK", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EvZbcc7Hu2Apsg33iTzeMytZPZb36k2YrDs6jQWgwByo", - "targetOrders": "BWroXnSDvmJ8X9tSwrgLBhQA3or2qLyZzXSyZ3rtWNmG", - "baseVault": "2spt3NCjPSz3GCdGP8wGiEYk2cGLN7QYyryJ7pQrGT4U", - "quoteVault": "GZtgbLCe9WrDGYsjGpQ1snR8L3erwKZpmKMkAZN5hsWo", - "withdrawQueue": "As8zFfnuypGaJJwoKSqVTWPL3VZNu5ECf8ZKpUs3AmQc", - "lpVault": "AxHHhng9fefnKs926FgHk4JKyji7TR8uYUBLVRoYHqzw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EFugR6DusHXLfzbbMEQFCmLq5n4k5VTWGcv1MC5yS4BT", - "marketAuthority": "6jVwwEsAL92CP1LPktsuyYPjcnpNQgfEttARd3ERTTRA", - "marketBaseVault": "3oau7rESi9zmwufQiE57MsucvykA21dyDZR1apMRMmzd", - "marketQuoteVault": "BPHjS4Zbi7RdsZ738yEBPUTxtHcfCBD8i1eUiUBEnP4e", - "marketBids": "B3UNkBQTvcJkihuKo2k8S7LEJMFvZhCkHL6LyweQVDej", - "marketAsks": "8yhkGkbnU36EfrNWMC8HQ6S5jUAL1rvBk1PNaPcvreQi", - "marketEventQueue": "DU3CL2gBuBx5Popr5qtdbyzw4Y35GTcSCVLdBX8QUazm" - }, - { - "id": "12j26LeUokXQ1Ge2bvfWZzFcs46MKCq7aEhx8Hk3Fdzh", - "baseMint": "3Q6EaSEeHdNrFHe96X7brdGKgseHoaZAk14Ct6aQe3ip", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CVoZKFX5oDnPmVg68VPdxApBprQFkdNp9ELaYnox2jCD", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9PrnTEjCH5Lero9qqC3iT2HFLZprubiecYz4RY84pmSv", - "targetOrders": "DdYYJ2b7Hf9PFb1qGsN8wwHtKnnjaGqtSCzHGhTfq1yj", - "baseVault": "A2hPy77AsXC3NPMfN9PbS4W1dL4yW8wCWGtFjtAiX31o", - "quoteVault": "GBXXX83t4a13cVkp8q7Ug7W9vuBKQGm5Zb7spTfzR8NY", - "withdrawQueue": "2R3HGdMuJ3kAuBbyMAXYWJH6VLS5eCo7UjsDKikky612", - "lpVault": "965J1kmzHwyjBSwXMkHYMapiCq1echHFwu4RLoYtEKkg", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3JkZAXrcTq587arK71VCgwj1SSFbMi3U9anYBHAzzpwG", - "marketAuthority": "H9csfX5XgESXvdLBHrNmCh4PNuaJqDCfo2cym24PhUzz", - "marketBaseVault": "7VTj37Gx3YNZtT5ormDfrAtKMjyogNGCoksdETrstM2m", - "marketQuoteVault": "CKPk8Lirw7VNUY2dBdidUh7YNWDM9UmsTwSvViRCMFgq", - "marketBids": "FqrEM4UphK4o1nY9uvMZX66faUnLXh5Ui1VD2mNqwvyD", - "marketAsks": "5D9reQEzqKzyKQMzrQLR2n8TNexj2iZ8Zq68ofoAas7m", - "marketEventQueue": "Bq9QT7PQgK5AKZ88nxNdLvmj96X3SGJf1n4L2rdatigW" - }, - { - "id": "14MDXFwbr5gPdzTS43XBD6oZEjiKifTziujR1216jrBe", - "baseMint": "AWW5UQfMBnPsTaaxCK7cSEmkj1kbX2zUrqvgKXStjBKx", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5XiU5T79Y4AzCK7ZBZLrRMApjPNvKdhn1zP7TS2VE6Gk", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7XbcHamJy8LnYcofsC4AZJEw5CgFK72C8iuRrzHFbEUx", - "targetOrders": "9oEn5eKYYvMJNNPz7oHfYkvPqecr5RAJzwj6ZuFcSDiH", - "baseVault": "CUSWfDJBP4EipL31NxL5fD6k5rgdxgHFkyn678baWe6X", - "quoteVault": "28j2hTyvt7UY3DoYphGvP2GZTEE9Ve8PDsXwiQedqFox", - "withdrawQueue": "Fo6p5bNKuUPqb2g51ox7TpbW3q9kvzdGdR5rhLaHCRcW", - "lpVault": "56Dez3iytnJwdhx7cx7bdpLJfxTMz9phc6sMSZSY6LHN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3ivg8YYCsSnijDDKFgbrWMZJc377nGH8TQnNNbdEaDdJ", - "marketAuthority": "ALxh5HfHviVUdHNANNZkpN57X7sffCoyD5L3A4ZViwuF", - "marketBaseVault": "EZzzXGc36yT4eqUPZTsqU3pR6XmnEt9dyaMzQSQG1qws", - "marketQuoteVault": "74JCLmmaJqJBaiBm85PEq1Dv5cuXVyGk9UaZDsigZTSG", - "marketBids": "DUcdZ1THFvH1o6NfMtzaAZiUrt8qcNjARoSapkuucmyF", - "marketAsks": "FreJZqMxQ58qvgFjjnXHkrzygs67UYhPtLS5p7YSPtDq", - "marketEventQueue": "EY5pRZC1FRsKUCCofNawZPepJBKrhNXoeRFPBwUPSGuJ" - }, - { - "id": "14o7bNeht4sPHmAMwNwN4v9StnkxxCfp6KYjGbvsjMMp", - "baseMint": "Hj4sTP4L4rvR9WBR6KyK99sxPptBQQczNWe4y15mxhRD", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4VQkhi1Briva9bHrLqeiiXSfPWTf1M8teNQDy6HXGhcp", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DUyVevZyiZnKy1Yb35pfsA8qAyhTDHtVffqvwuzN2fqc", - "targetOrders": "943A3j8dLBwxwh3SUX6ESNZErDNzR9AHDuYNr4we91Xn", - "baseVault": "GhkxMdN7n6hPW8XkjkxBY8T9Gc8G3h2B19uDAAGJFX4w", - "quoteVault": "GRGVLTrzFHAEYPe7pq6BQsy6qCazapTQp6nyieoFRDfm", - "withdrawQueue": "EFS2xVUJReAtygR8HCk4p6xc6iAohRYWeidfHmKADLrh", - "lpVault": "8gowwhb4h3AfkyCkGerLRELwE27UrVn5w87KxqAAmU8v", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FyVdsZs15c38b6vBjiYYfq9fPrcrZJjvMgjHtEB2T9Sa", - "marketAuthority": "73jMv56qcRi2Gae9JeodCRRKtRaZGqURkz8SwjwE6DFP", - "marketBaseVault": "8nyYtVhusz5oSoYh6p9NaW9K8diCyzDZSyAqhT55FPUy", - "marketQuoteVault": "5yTMw67hdaTzXGxzUpcLG7C1xMsaNY6KpsuyfzbnvP4S", - "marketBids": "A4KSeyuFTf5GzgvgtdGmJPskti93ZDeq1RqKWV4NeQMm", - "marketAsks": "5V86ocZyaQEEbC5Rcb13KaqiWfZkFXiVDAY2Kffwn9pD", - "marketEventQueue": "EmoTaeZVgXgPUonjxBLkV7XKBwtWEyW5esuTteSpprEU" - }, - { - "id": "14PMiP8B394959iHdT98f7NLNhxWrgpmLDA17iazBC9G", - "baseMint": "2DDyLzN1pxVddhkgZYJdJH6YFUbeSVPFZBMSxcLswwap", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "AF8iQQKXZKpY7BrFZjuDXyvtYETCvkLDsRBLamuBwb3S", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HS3mKxXh3zWaiKv4KX589Sxhfb9L7C18xNFUseyYMZfN", - "targetOrders": "9JkrHPCRREN6vjM3UfBCKiytfUS7vYKmaeKmRTbkjLPj", - "baseVault": "7R3cwEiqMcoa8S6rWU8JZmi3cNat5hLa4T6HQwSmZQyW", - "quoteVault": "BMpKsVbsiBYRinRPcYyJN9x8CQVqybCbWshbyzpMcHK5", - "withdrawQueue": "5qDtM3cHdyuPBT6uLRX3AufY7LgzLn4XWGQrDdffx9zv", - "lpVault": "9EjKqxyyPhJ4NEXYKtuhvLVqjiR1wN2wFdxq5Bw6FAr2", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2FfaMmxHhZKNepzBd3gNXEZhdMczAM5b49aHkXzcAW1X", - "marketAuthority": "AzeEynidvs6rfrK7evJkJGq4gvkmRWrFpsLtXgLzro1G", - "marketBaseVault": "Ch7gc3eujf54uKFgepvGUkVfYs6x3vrksewzv9UEa21U", - "marketQuoteVault": "9kPqNKgQnX88QJW2wAwEDZKZXqEcZtaBzTtumN8Poen1", - "marketBids": "BXHSzcaDhSR3wwvH6qMTkYm6HcrZdmtmSLLTNVHztXG5", - "marketAsks": "BaBcfmmAzo817LpKE8TtmR1SQp9AhpiNNF2qwyNSYGed", - "marketEventQueue": "DV8iEM62mG2R331qib9zM385Ct4ngaD98SuxSjmoVWA5" - }, - { - "id": "1Kt3hf1166RD4WuJUr1EHhiqyKYPGhHqdKWUby5RS8V", - "baseMint": "FJ4RjC8keFvKz5LVshuoB2tHXg4nU62VpDr6YWVng1Jn", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "HbFUcp2knFMAza2JXySDK6gWAg3UfvxKTayFkQAzPGjU", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Dr8Emqvn8MvP2j3X3xEn68NUP8Y3rjWByCYPbqQDT8Wz", - "targetOrders": "EZFQBTQXTGftio8wiuLXhy6Kmxmf5c9DneoJbEHr59i8", - "baseVault": "66Qc4bLnFHHKADcSDe2uMFrUUaAjnYEJBWnrVCNBhPPE", - "quoteVault": "BWC385vEMDfwHNUhmPNqXHPwDhJjFjoDStCCxEHixqCd", - "withdrawQueue": "FRuefVV4epGXRQT8CzPXzLeJTLFc9SkMWoJPrDv6RvLq", - "lpVault": "95dM7CzNM7wa3kWAamtYANzZE555mJwFNZaZtfPq2Mg8", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4nDFBXsdYXoVouCQwewi51XBz3tQHB2PZxZfB3y793sZ", - "marketAuthority": "7pqqH946UhUFpoR4g8W25PvAXMXHe1AJ8WAJmjDRUkrQ", - "marketBaseVault": "XSWxbgHEh4tvwVmXcfyuC78poE1Y7UGRmHfnpv2BzoV", - "marketQuoteVault": "7FJBKkvTTW4aEMWYSZtp5UtJCvwXMxLNmoqam7TiFzCy", - "marketBids": "6Po3ux89kjHkVhZ4vHzyTmdzC5ubzUuUNM6jvj8KzLgV", - "marketAsks": "A2vUocadaNphd71uvWWmARsM6CWmuC6yreB3i9UQQXgZ", - "marketEventQueue": "HEEhU7xTsg3SaXy79ScTV7sUZV66ZG8aBRr8H8MFRfV7" - }, - { - "id": "21q4SsJ9kMh5UXp99EE3U2vKL6rNWS6KUPzjechumpLA", - "baseMint": "2uRFEWRBQLEKpLmF8mohFZGDcFQmrkQEEZmHQvMUBvY7", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6hiMMhsv3QX3R3GhxmTbrbchTCBpaUxCTAGpwQnS3ajn", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BJq5ANVPTEVSsGu4P29NCenPGZvXhUdGpniTYSiSAELh", - "targetOrders": "E5hc51kEeNoqGGkf6sovkTyscRJn5S8PsCAL8kCKh9ao", - "baseVault": "5MGmm1XGm9vA9dPSP1GcphkmmZC3ckXDF9wwgTjk1Vu", - "quoteVault": "BhhVSEAxt51WMEU1XzV1GdtNhyuY7R973rAJMp74CZjQ", - "withdrawQueue": "49YsgChTRR41HEEp8nTs6oUKuo3hmfqeGoKvPSiHpZjd", - "lpVault": "54RLvecmSzhUa3dcwdrtNsDB6Rgppnp4ZXNW4wcMJgeC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4MUhHF5K9simSLXuaUKMaU8nMHSCRPzPMe7UtJRXi4HZ", - "marketAuthority": "HTC8sXfqzVcwu7GhywQMsHN7W7mLWJgVgJ7G19GUg5AF", - "marketBaseVault": "HzYJRJVWc7YwURs51pyV28QDX8higLY5KbsfkFfyGBWx", - "marketQuoteVault": "FmZKugMrhDYtBe9o4BtJT8kEqrqYSniSshX6XvTStBVz", - "marketBids": "2SrPZCNBYnBtxNERbCCiZTXExBkq8ZgMojwC31XhM9dC", - "marketAsks": "2aDPzY5yAS4FJ11ZNrwQXCKJA6XLPuMCpbpYgujtKYJ7", - "marketEventQueue": "6NoZy4vukadrqUWjQiAMovXBUAoaFwzQ1onHQTHSQgGP" - }, - { - "id": "21S8fcTRHYoNTYaazzmJEbJwyVraDDzw8oP74yN4Wbya", - "baseMint": "kinXdEcpDQeHPEuQnqmUgtYykqKGVFq6CeVX5iAHJq6", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AJpSsfBURhanxqHktUrQz9hCJX9WJ6hqJxd2ujATHQRs", - "baseDecimals": 5, - "quoteDecimals": 6, - "lpDecimals": 5, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "F2MuVivxRSCz1vXcc7Ws98WuBGJvMXVmd9DLC46KXns6", - "targetOrders": "2gWAud8a1xaGvLw6EyBfFKq6tR8oWSv97ePvm1vKWZ3x", - "baseVault": "J3JWDakwqyY7Va9CNvVGXrBUHkP8R4mRyjURvF3gw9aV", - "quoteVault": "Hf5vD8m8rzwm4abZNznUZRGXMJKxeDXJmehfu19kjBWq", - "withdrawQueue": "dC34U9Kcz3kbtWw9aH2iuPKstyvtUpDnMh1zLXznNJA", - "lpVault": "2fTSasJGprukjZWfY4cs7KCAgWYudrj4pXe67SLh39z8", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Bn6NPyr6UzrFAwC4WmvPvDr2Vm8XSUnFykM2aQroedgn", - "marketAuthority": "B7HE4ynnWVh9x4MMJK2mXFRcyMqsYXtyEnu3F3fgqxJY", - "marketBaseVault": "J9XnUu66fDCQgcfBbG1Ro7B8H6zKmt9sao7xvev7YeJV", - "marketQuoteVault": "8PPR4xbmXMkjEyBX6UDJ1jVU4dZfgEnegiabeuLRFky8", - "marketBids": "AaJR985aSWX3F7y86Njpv39dapb8bz973MxRzzaWvKH7", - "marketAsks": "CkMr7kkXhPoWUxPVy2JVUDvfoYMPvr46AT4xCKjwPX24", - "marketEventQueue": "3ghFLE6TEwiMQs9j5vuJtfXR7wtKJnYJijYN6t8KP2AJ" - }, - { - "id": "22dTFdoXyWN6uGeHWWgQyi6FXL2RZdkdCXzcoMmrE9kW", - "baseMint": "9dwDXftdKpBwf4Zovybveth7sfsA8PPdFTyecRCVV6NB", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "EEiujJcRz2iGRkvrbQaYCSEphWB6eQQjiw5C1dDc7Z9M", - "baseDecimals": 3, - "quoteDecimals": 9, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4fMeFZzNvM7wWtqhyG38kSQXRT1S5HFrJ9ghVHsptc2y", - "targetOrders": "Csm4koXipK5LZ9WMzwxz5axBDC1KcaxX2LiAd1w1JdTe", - "baseVault": "wMw98agh3qzbNrKa7dbE19RuE1roRUxxp3DVd1g6x8h", - "quoteVault": "J7CT3RNXrejWmKuY634hkC3Y7ykY8G6hmVKLzsJC7zE3", - "withdrawQueue": "6fGPD2qWCsuCTmrunMAYmkRnkxbUUcArX8PuuvQ1rZac", - "lpVault": "2E58vmGYmTYmfRbXNQ3UdF6QW9JYVFmp2fkUKu7K5hux", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8HnEBijE19XDWVwDZNfGvm3PaFz7DHgr4L9JBc5a2wKC", - "marketAuthority": "EDcttUMQLsVQo7uFhYSb5VGWjWMoknmaiA3yBFMnz2Xv", - "marketBaseVault": "DXx94FjrUUag9f7dX6GeFvRDB5BRCuCVsHZeUdK7Pujy", - "marketQuoteVault": "DZzhnr5ZzBbyYmLaxknFfbhX3jCEnTwcZALjLHdEoKKy", - "marketBids": "FnVPAzgbR8qBWa5d68gxBajfdBmsfPHYoJm1mNtxepnc", - "marketAsks": "55hkBjTeWEdDxVWggb4BQzBcEdQhHSm3XyE4tZzZBvWt", - "marketEventQueue": "Gh28XL9v9VMkhS4dVmW87ZzdJhp3aU4Evr9Y39Pw8PJD" - }, - { - "id": "23PB9WZkCcg49efwthNHTiYryFw8hN53WcorNmHPDcGm", - "baseMint": "A1C9Shy732BThWvHAN936f33N7Wm1HbFvxb2zDSoBx8F", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "GfLnT2K5CjjtxyP8b6nxYmUm27YS8EaTnTVYAaLs4VX7", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "D951pFooy8hqpy556RGkj4igVNxhWVmCvM35jstkPpKD", - "targetOrders": "u3a4FisycM4s5fXttuQ8CcWdNP5m4wnDiTphBMZZsfZ", - "baseVault": "9BS8bGCzWrPWkA3hemawswcbhHF6pKtTfkrAQXteYbiH", - "quoteVault": "CjTYtn3f7iwWXPT2GoVdCX2XQ164yehA7bnBaxYj429h", - "withdrawQueue": "QkxMcip1xkau9nSZTgzrtvewQykmP8jwWivyRBeu67A", - "lpVault": "G2uNWJtTnW2TQ5iRt8TavVXrRUMVszadPd9b7bKAKwyT", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AUYZV5BbKePrAkMiWCMhc1EbZCPNHDrK7Jf8jYy8noF6", - "marketAuthority": "A37Lm95DZupd58kKnBNb85gkmAAzwHZL6m17hQcYU9UZ", - "marketBaseVault": "9mjxpQMQ7Cb8nhndQP4vYaZAVZEyPCt9mXZ5U7Rzhi18", - "marketQuoteVault": "BzBZnZF2fB2sJdv5PLACypqPT7deU9Wi8m1D6XMzBEYx", - "marketBids": "HLDMWWg6CYW6ccWoCAspxXVEEhyTA6GGD1pddoq67EQ", - "marketAsks": "B5qpP2FE2C7t8DbUNzVeUceAAiLg6adVCYDfbMc4cp8n", - "marketEventQueue": "GCuNGKc4F159o7ETusNEWiwugTGYRVMPeb7nd9ASJbk1" - }, - { - "id": "246ziastt5LrfoM76saJVahZRgtDxqsJpZHfjUFBRQji", - "baseMint": "CBV12y1pehFbhdnDpUfgPe88SbUZ5G2s1kLA449Yu3Ad", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "28skcJf8T7TLKKz4hC9M1ftbdHDopWHphwa2Zvxfo5GV", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5FSQ894gTMSp42m1YfP1ynrjXKFDt3LqYDwMhEoaWdFL", - "targetOrders": "ALXR7SbLwf3atRRWaLQqFoDynepvoHc4vq7MQU63n4hg", - "baseVault": "3hozhjVHKVhMwYcUzhum4MjhPqNPSd2XRNtbpBTor1Wn", - "quoteVault": "9YVRGRGdAeLvDJgwkcq4jk6QvoZeSBifVYjM5zthj23b", - "withdrawQueue": "GesVy34PLS77ne8BidmRm7DUdFn45Heh7xTJdcweVbA5", - "lpVault": "7ipGZJCU7si1XrWSdEFbaUQTWYdaYBcJ5FNaKJzS4uiB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GfUbMEQUh8UfZthzo1vG9DPqKQxh6hFiTSY1RZTgXPkV", - "marketAuthority": "H63FY8qpQURJKrHD7Sbm3F9QPNnddaEuWLfKWQ4vGYNd", - "marketBaseVault": "BNzeYdJNmQnmgdJrWncoS61NFbEM48iMNixeDizy8Mqj", - "marketQuoteVault": "HkhgYUsMYAZG81cN4yK7ndkhs7TvPqYqyLZC7djCQ6Ya", - "marketBids": "8Dug3HFG2A77AJpK6ZHaaykDTPW2FGvQGGVZkfepMNc2", - "marketAsks": "HpUo3sQL4KJVd9QCpVxrRYSDnGof41x2fW11pF43copg", - "marketEventQueue": "BUgR2KxDUVHEvuqGjTvq8fEyuzFbaMeohu6t9jCv7mWi" - }, - { - "id": "24kH3Xh2sTqjR63JdtRg8rMZc2pz4xPJYjvSPLpdnhbV", - "baseMint": "9wA13aDuKDAAocctNBFpt8F1UU5WQNJBemba3JZFcNzE", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7m9yLwgyLzmZ2CVmuT8sP6nAbMW5TULyNvcttdcMTMbJ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GgKNybU1Rc3q6aRZZpSfwFWokmMDsSoBFGsBH1Kye2uR", - "targetOrders": "9pSq954Qu1yJykG1NG9fM6oZR9uPJn8ebYKfQCQm6oBj", - "baseVault": "2UCBxy14GYW8UFuKcK1FTxBMwnv34M9bD1E8YvLsmgDV", - "quoteVault": "9zgZeB5MVStJPnmYUi8qfKaP5DXNPozkhKChV13s56fQ", - "withdrawQueue": "3h8qiPRt1vPwFCknqeELAtBdZeUq3hvrajpcVysACmvh", - "lpVault": "21FGjQK6eCjk7N6Rvfmou51q3JB9dQxxzx3j9MtNQfcx", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DFxaCbMCFdZzABUAvggQcp4HdnraHKWs6NFrKbHCXdFj", - "marketAuthority": "FLKYKEHwtSwH2vgj4awNnn3q5hHHx1Bi7UpWV3vKT6Xu", - "marketBaseVault": "BfYUAzHmWwMMgNb7zgL4H4coXabT2UiwvvkQ99ccDZ25", - "marketQuoteVault": "A2iK5opcz24iy1r2cWqsqFmrFFfQRM67TtVkiY5FjoUH", - "marketBids": "DLQ6zBSz5qjzXD3ehL5d847ytfLAHbVtQJxawZwjZ9h2", - "marketAsks": "2UVs8bAbrSR7ki1JD9cGp6xFi3ipRd75rn4uGhc69dnW", - "marketEventQueue": "DyocqwbK5YkGdLxaP95qbbjkErKJ4hyQC2ReaYEh2Tfi" - }, - { - "id": "24Khhqp26WVF3GH2mfPukjPVin2mXpyS21tFbQGkJ7Vt", - "baseMint": "z9WZXekbCtwoxyfAwEJn1euXybvqLzPVv3NDzJzkq7C", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9gMsdm5Su5QJKX5CASNbp5oJW6kP8YptozUKFbGB4DtL", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4CmTGh9NnEPNckAxUxL1ZPmLMUBVx7GjXtC2WicbzHwu", - "targetOrders": "Gdhx7CeDtyaMN4Cbwn2h6fLTAtoNwk7psWe6MoAU2LHE", - "baseVault": "3zwunrPS4MZismDAQQurPchjdiL3opcsXtzdEt7Wn5BG", - "quoteVault": "AQq2oQL6vPNHpe2gfr6NZcMESPbdiyWkMxSVKM6A5VWT", - "withdrawQueue": "DVujazr7ATZ7oLMUjTYuqRvSzfJJY8J9LdWqtthXpXia", - "lpVault": "G84ryvw25wyjGPiRQgVRiLU7rjLHuSqV3t8jafa1Gopd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "28UzKVL5kwzPA9xdLFYJRManeY6RHgmTiU5K1h13XCRv", - "marketAuthority": "4Sg4aRJPEugU9YC8m4pHnjhDH6EnBsmBLaAK8A4Y8oFQ", - "marketBaseVault": "8yeqrtWwVeBoM3SzhyvC3bRub5FEYViEKnEUXWZ7fHS6", - "marketQuoteVault": "DPEkmmSR4JFSY8k3oKhUDKzrDtpD3nBAvernZhMbXz94", - "marketBids": "6fx3c2X44FzcS8jDr9wGoVvVQAkUPBRTeWSztXbMAn64", - "marketAsks": "4ASnCvzEZKUDQ6BYjmv3gTLfWgE8b1G5GruzxVueJ1Ym", - "marketEventQueue": "7yiTUbawRJvhtx73uYLhEJrUuHa4L4199qgEDXQDnjiG" - }, - { - "id": "24QrDLKQ8dKrivw2YqLcVwQ9eNBAyTyzqE116hHfraEy", - "baseMint": "A7rqejP8LKN8syXMr4tvcKjs2iJ4WtZjXNs1e6qP3m9g", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CtdK2Dxq6FGx5gckdgzCh5G6Uddi5zUABZ6JfKbHML8H", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HZKHa4kNJbP9Zxyu8P6JAcMDsZTh2SGbeQkGXVeHeeHY", - "targetOrders": "EMWJgRH8HJjjwoe7ZJPJVDethDNDb8PHV5toWjsLdeEz", - "baseVault": "8ZA6YX6RbhirbAgCarfhLQajq6sm1p5E7BWH1rq5sfJY", - "quoteVault": "6M1T1kaTsgHYUzprxABk7oXBTpMXy2u6sTUbAqb6QTJj", - "withdrawQueue": "F44RSHbBZeeS5XVL84rm4d9RvzJtDGXFfhDpcAPLZTiJ", - "lpVault": "3YR8SZ8nXRTr14ZZX8SnNT9Uptr3xpT9z9c1LVUBj1qB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Hvn4jvBKF2ii24JXXrFYD6vLMrMd62p9cvan7Gr4BEHA", - "marketAuthority": "Emp3J9g7eFHPojPwep8ymAohf5EFbmQKD5zG6zWwoP3q", - "marketBaseVault": "7W5FuYSm2zwagwFtzHgfDxDf7ZL5WcZQGPMB1eb8ERK4", - "marketQuoteVault": "J4a5fK2RvVWbPEHEMbg9vv7oXtMzfrWiwg4eBEBZcfEv", - "marketBids": "6vTsBwNBwUR52dbAWLsU6a2nQeenJ32HEdPGLeHuigwT", - "marketAsks": "FvKdiH2Tv8GSFayw8YMmb2bSpg1DimXZ8uUo681bwBTD", - "marketEventQueue": "DfCsnRu7L2cwDkw6zUC61FUzFnHmg9sEJenZyv1AcxsK" - }, - { - "id": "24rKYLVSxfVWmBx2w1RBPyjtn4a2dWQ3Aoc3LrY1YpQt", - "baseMint": "2NURMkJEkLWUXF91kbhBETkZ5E2D674DF2Wi5X2ZTsTH", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "4s7eKBkiCDQCTCppN1U4mUCasjs4smog2vB5tAcRtU3Q", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "54Z7nD77YcjQdTcBYHTq91ZNNMGewUCwX4eQ9h74u6Rq", - "targetOrders": "HjXbenUD7GB8GSwaHoGzJ8Mr3Mfhyx8Xeu8ZFV9K8Bez", - "baseVault": "CbPkS2N9nura9kud3VPwNTW2gErE97mJYKwoU2pnzq8q", - "quoteVault": "CNCLRR2BVf4pppSgsEut1M3rZnTPRcFK53hfXUNCi74c", - "withdrawQueue": "Gx7NAqTzqHLF4jUCmo4X6uBStbC8hdvxZWQfY1m2uZH3", - "lpVault": "DW7UXw8RCX1XL5XFX4eZ3jsutnVahjZVzeHQkWxhzr1H", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3AXPokEMVaZTS7egUdhuN2XtWnHTLBHHgYySnpr1oQp9", - "marketAuthority": "FmkcTqiooq7U4TVsXEN4cJZopDMbaKUz5JLTJSxG775E", - "marketBaseVault": "5gYLwmFLfsrtnVXQw8JvZpQQjB62m2YDWvTB3dbEkab", - "marketQuoteVault": "E2PcHy821akU5cDNFQmQvDqM1cSjcaQ7E12Ve3fAVqEC", - "marketBids": "4pRbkYP54ZWwEMA8jec9zvof2PLoiHKXTDTNASKEbV68", - "marketAsks": "8UghTbck4yqgP7DjM3Gu8bRFxdqS5f9dLjcoDzmtrWnY", - "marketEventQueue": "GTpBKndfRp9cNnnrFsw8Amxzb3TnRKzLrUrvnyaByDVm" - }, - { - "id": "24zaqQxitjBm3NTfJsdLu51wXniwth2zLSa4WCTffbjE", - "baseMint": "ATC6C1AL4X51FXNFbPG5pxfjSgDQCNECtfsnyMUnk9X1", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DxUPUPpaF1WfnE34qB3RbBSfqRChCnCm8SSoHFT8ycWD", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GYxEEn2YhFzEDYiuMvghLoExDoSAxfWihhjgo2Dm3pjF", - "targetOrders": "Je5RQbMqZZP6Hx6HqAety8CDviVFymBBMNAYG199YKM", - "baseVault": "B4MbFfCtsAZVPZNXyzze4kQ89HpDMaaerkp8yY1uGM56", - "quoteVault": "Eva3NWvBDM6B3que6K6kdF67DtPEraPBcm3KVGr5UAEk", - "withdrawQueue": "6sbxnRhrZtaQtZt8Ezd9wbkt8b5NHatA1QnvnAx3H4UE", - "lpVault": "DCbPkapa51eJhvDNECrCTQPbX5nvoL2ccoBJ3qkKpU94", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "JDDijLLZg61zovWtykh1vCRAWsoi85qA46JSyatH7wCC", - "marketAuthority": "B7UpkaBBDVPAJwQwZCSTKjgagc2vjC2ABAk7mN2egqKs", - "marketBaseVault": "EbLodWsaaMpfz2jDraUd2rTGhsw1Tp5vVbYC7uBVoAV4", - "marketQuoteVault": "BkJEVRP6V94txnFCfsspgS4TTAhsHDMtKi19Uk6jJBgt", - "marketBids": "F758Jb8HLRkRUHqt6zSMW3zTt2tGht3xqqLgEhStVjY1", - "marketAsks": "JDw3YUKvpQjjwsjkxCAhnpqiAXhZEKqDxBjWKyDGwq9r", - "marketEventQueue": "4xgx9pS1ueX6nWNZLiqDCxxq9xvFB3p5EVDQbcjrJYEF" - }, - { - "id": "25sirkKQxavTpem6JaH9JWbsDs2V4SPPACZ4Gg8Q21tb", - "baseMint": "HkNK7BL5pSUUzc6ns1mHW5JnzbSG4S9u2QdR3cUuyzSa", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GMesQERhF8dFJ7gLx4cYoPZwRYuSe9sYoREFwx2xEXYu", - "baseDecimals": 5, - "quoteDecimals": 6, - "lpDecimals": 5, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9L4xTseU4LR2fCWwWA6h1iQUHLCM2YXg7wh3xxfhBQyr", - "targetOrders": "34GpZra42UtF9kypRutVbnkk3zFL8TpTGmABtHxcUKCw", - "baseVault": "BgbxCCtmUFZfSyD5hRFRcTybyGPhitWy4ZpsgAP7teZv", - "quoteVault": "4t3CBqV5BxQF324z5SipTMXiEXdSdunEAGJWQ5sajnxw", - "withdrawQueue": "6mPZAhu28td9nUhFCfzje6ZRhoPg377kevRLgyZujSF5", - "lpVault": "HxVaf71JzoibGD1xz4shjQoTQU4gmLiPgAvSnMNk7L2A", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DYGLKjaY2hknHJkGWPvNCWMNhaHjKYWxDPiNwyeNwVXE", - "marketAuthority": "7VvUAyipvqPS36WVB52zdrnf9jvoxqWivX4r5zk9EMhG", - "marketBaseVault": "HD8LG5BXf6PvR2jQrnUECFjs7J1Chbixq8UYtdzRiR1N", - "marketQuoteVault": "3Ntdn3UffHQYzrkLtnVdbUtPUHBuZ92FDdVfbJNTeob5", - "marketBids": "DWvkRmp3Kck8fMxfsfoi23JJD2oHQ4RSUq9PczDS6Wnv", - "marketAsks": "14gBBrAiquMtxrW3TNhkCmaUpjN3uKkjActYZjPVEUgK", - "marketEventQueue": "EaRrLZTKyAwRRSPzUajk6Kqf6FYVmvWNk12PBRnUg86Y" - }, - { - "id": "264ue6FrgMBqMj3gd2ZZMGUsXDYLQNLM3kWKR22YNmZS", - "baseMint": "FciGvHj9FjgSGgCBF1b9HY814FM9D28NijDd5SJrKvPo", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GMURuDxaKnHUzxgYtPVnaUtHFkDJ8Gpnzm3ChXWAMAFp", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GRF8KGunW42xYVAXVCN6GoUnyGh28Zs15BSaWaSDibhi", - "targetOrders": "CAUa5PPwRhoxR8ogfixMyZLE1fdoxVb9xZhUz4evmYfQ", - "baseVault": "ANV9eybbHJJtqnGKP2YbBUn4vpfPziorbKGZJeGM6Cn", - "quoteVault": "AzagSH633p9iTwct4TkZRy6cmttAMRzozsgaxojT9JC1", - "withdrawQueue": "FpriAq13PheJeLPDmcxuZYadQ14fMmabdyFgnFRftN6P", - "lpVault": "4vY4DP5MsZC4VvtpHQ6VGULMpzr6PMFe2FhUWJiDAoZv", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GfokD5aka4n8kqCgRiJtMYi4Xd1ZLBatkynxFGyKdNTc", - "marketAuthority": "Bri1UoaPM8C5K7pphguxQCJ7ziLZejHB5MhFLUhHuQXT", - "marketBaseVault": "CRkMHSPihFrXB4WygUfjkQCXbUiLLNwqzuLbpMC6a7oy", - "marketQuoteVault": "FU5EHPTs6Tf2ixobhq7DV48851Rgmb9Kz38TLgsYEWho", - "marketBids": "4B7mdEHtL5gep6gPfE4v2KobH5xnoRCE4bgyaJnVG7GN", - "marketAsks": "4YWymqNvnF5y67oBBnuVjZPbZUESfUunvJr8K5WUVWMw", - "marketEventQueue": "BeaXPT9h8VamqRbNLLAdx3y8CaZC9TNmL7qKUGSn83i9" - }, - { - "id": "26EfXJFdA8gSmYyEoXGf9KumiP7mrsizexPHt56orYrz", - "baseMint": "HtbhBYdcfXbbD2JiH6jtsTt2m2FXjn7h4k6iXfz98k5W", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "H5XqaVRGt8RiFeUZTXJFLQmS3PR59qMmePvfY9QSNbbT", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Hix12E5YpTSqaMdBRAGMfQ5o5EkBfXQsQ36d4yMex58v", - "targetOrders": "9zxtdcoAvHAELDkLu5jK9MpV6FSTSWnvvNXAQyZH8RWs", - "baseVault": "Cv99PVNFc71SUEejMEJbeY2e1wi45aqhsFapE9r7JrPA", - "quoteVault": "EAasepGHFNvxZnxuTHxC4TnWro1YbzYw9SZT6ZT5V2vH", - "withdrawQueue": "HTLuL9pJbLA3yTr2iGcKAeqrJqZayv9pqkL1iEooR7kb", - "lpVault": "7aCDthLx5XTHxAVedK6L6rHuTaQaEe87EfD3pxHjYWoK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4wiUbDit3C9EHdbwU7SHz3MFmbRC2kEZXVc8ff32nDr", - "marketAuthority": "7ympUrS1dNxFCePpC4FpB7fscdB7tTHc4qzenaeMgGcg", - "marketBaseVault": "39j8CeBGd5v7wnNEQdiZ8Lpb9aDqpcQSGHhBdxg8syZd", - "marketQuoteVault": "J84JQFg9dfWEoA68aSsVtzQ5C89bWrJjaZkgSumeyiaR", - "marketBids": "3uiagWHgJvKNJ9Y2CowR2KP3L3yu5xMrAR9HnQySeNM9", - "marketAsks": "57YbYb6sXkV6d437LQ9Rd8BbsFzyo5sgRD3MW3Fzi4iX", - "marketEventQueue": "eJCETCnebUu8s74UCmKV3LER7fFFrHumybCp3SBmupF" - }, - { - "id": "281R5caCRkPtPERKN2xYkxEacNF1NFn3SY4kWu3xSvdN", - "baseMint": "MoshMwLkVu4iwrPBaWpYkh43qJiSXsnyzNLuMXFv5F4", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6wjqHb7wzzEDevKGbnWV1ib65FSwfM2RYD8bjhDqMeN4", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FSD1bRRePx7Vp13GqjF2pUbpq1PbK8gWgzGNTZgsQfw9", - "targetOrders": "8eYHaaQMStExnGbp9rf33HPB7KGtScNSegeQtRgGFEKC", - "baseVault": "7SGK4UztvxXAgn9KiV24TsuJz9ePE9nmGTMA6CMc9L7V", - "quoteVault": "9NRsjUnaEkRFi53n9kCS4qa19vAm2kTu9cjarVNPvNzL", - "withdrawQueue": "5eNauBoApdHW7beXtovKqjGSSmeLCZPXMT65owAMRm7K", - "lpVault": "5JUacushttjAcNiQeb68Vp6Wqu52WAKjDNRhPCELF9Vz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5aWFQsgZHbP7LraZRUcSgPUtXbZCdu67FJzHawMmgKPK", - "marketAuthority": "AmCzyDjJy4H5KC4R9BNmSsgXD5amwNzAG1EknuR4F711", - "marketBaseVault": "CkRucLayapb3GbpjcvSuMxZfCbJ8gmBRmF77iJrvBhJ4", - "marketQuoteVault": "Eqj3HrG3yEgNyiEALdjsBqKPG8Dqz4w7e4bAjuRci2gP", - "marketBids": "3rzW4hPo6fE1giDqA3Ejevp3YUaxmZ49qZz6PYNaHKGs", - "marketAsks": "J6tp2F8cGBBZZ7V2dutNNkavVbavaaznh2jUBacT56uK", - "marketEventQueue": "93ebknDzDBTNL6ADhc1RRrNfKCeAPTyztMEX7dUpd8n" - }, - { - "id": "28fewAtfQUEGiLGb3EU2sHKoVPgCN1Q36zqJFRz2V7ft", - "baseMint": "8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5dqrsQgfLDnxPa91wjXuXKURHf3x7FxnRZ7nNK6RJSPu", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6J2CqjcBfYUCcjY8hNMYCYnmJYr31Z2CK7J2m8yF7AeM", - "targetOrders": "CHQw1hFh9LgoEmhfC5kASD6r1nbuTwJy4yCJNEQz1Q13", - "baseVault": "7dUpyMKpnt3U6n37fjnKRrvGMLA7fWtnUViBXafpXvHn", - "quoteVault": "CojREFqCCzvH5gUPMSKkF2d7HERotizF1ZMoWD3WopJs", - "withdrawQueue": "GUEhtjNTZV1PeBTzgMtbxve8tnABVb95uG98FxnvNPEq", - "lpVault": "3xdWZL4E6jcLqBWAbJYejbyPnvSKZrho9K1kt4UCB3YS", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CxDhLbbM9uAA2AXfSPar5qmyfmC69NLj3vgJXYAsSVBT", - "marketAuthority": "AkE4eoWFyx1TeokUY8sLhPMi2xgPNs1bFWr3d3JkovjS", - "marketBaseVault": "ExiQX7XECp4gHhdcCrkvGrzaRPCuVfhnc5UjvZFHPZ5Z", - "marketQuoteVault": "9bebFZGyq1EyAi3nx1F93eNpV8D9GoMM31xK6DUdhx4U", - "marketBids": "Enw5mQ6h4EfPevpPchWZRUQhfzPiBTBxxLiwBrWfRDEm", - "marketAsks": "3y89FwngykFmwYRkqkWC2mPdogVLJoa5ZBjx7fekp1iF", - "marketEventQueue": "TmZF3opFAiepxVaiZN7jMmBTumBRibh9fHGNkNUmj2c" - }, - { - "id": "28p77ZesjUMGUEkAVcJFY5z2idwomHDqJWeZ14DFBCQd", - "baseMint": "Dypr2gWcVuqt3z6Uh31YD8Wm2V2ZCqWVBYEWhZNF9odk", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FFNzmTxK4mDDRHAtLfpz1ZYSq2aM6hZsw4TFzUKaRDuU", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "F4WpoeNnEsq9DyFUmLQBLPmC8oFiGY8rZwfEFLce2wun", - "targetOrders": "8GNFk2DEobkSavULay5FgBA5RFB3oVqhFZCrX3JHDA56", - "baseVault": "F3pe5RETG7843pwfxV7taurqjQhjxSbh4UBGcfN9tQFa", - "quoteVault": "3YxayCkKJxuQZ1zMfiJazYgRARe729tCh4SSB3ZLGz8Z", - "withdrawQueue": "B72fLr3qHvG4P1Lio7vZHrYZEF5tSrTcdBx8jsSDH5Et", - "lpVault": "CDHTDBkyzntzNJRfHqwRxk5aLFpcSDCYm6GRFPkfBwNx", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9e63hJZ1HUNDeBwmzJy9VsRT4kzqJ92Xk24htAwjTCeQ", - "marketAuthority": "8YiB5qd9MV1kPghV85svNNQn67kt8FmFjbk2vaFV5bhy", - "marketBaseVault": "ECiU5eY6vmariNupz4YZaovmFEXGQPLS4cJv9bQqGnRf", - "marketQuoteVault": "F5XRBxYjEV8zNC7AbYm9HewmYXwMDpXUUCjUYG6wdjYL", - "marketBids": "6yobYuJ259xCL6v7vefDr1T58pHfanSyAYqYDQecqBSs", - "marketAsks": "GMtVjAsvFzZFdd7cDG9uo4nF1igp2QXkjKzrQ5iTYLJ8", - "marketEventQueue": "pjAkbrLAbckD48ouHSrQik3e3GWdETpr2g75zrigovA" - }, - { - "id": "29jLSnfR4qrrM891aFYFqE8oxCFd2UFFTinHmkqnQynP", - "baseMint": "CgsLMDGmS3iNhKxEkvNe7VjyE679nGseVgenCRYNdKuo", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "C6xB3wWQmaJjFDyzUpbGeZyZJzsBkUYNA9MTwatUWchZ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5A9qTB5asmxBCkiwFaPqxfQrvE6Rrv3jMafN2d6osMn4", - "targetOrders": "Gc3b5qfnRBi6mWj2KDqus1EGT7n6DFEbNAYoqV5auwUu", - "baseVault": "4YAS8cstCo4sV1NKajB5tXWhSexdXtSB9xSTvBHH1YeJ", - "quoteVault": "FkccApQRigrzH6V674YCpncHWUNtK8ZaX8LtH9mYe6H1", - "withdrawQueue": "FphNKKSp1ASdAneeidCRSTUfPqPYz6JdxhQdVGGwFLXs", - "lpVault": "8BPH6Tp8eHshGwovWbvHhLgtZJBsHN6kpmur5mjEcvUu", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3P8gGTLaQ8M5gwAMu7NcA5rqrYJk3Vo37AGa85dfWyEP", - "marketAuthority": "BQ3cgN3T4gDuf4HPEoAVATUH3azoLbc885JaQnZRRJyq", - "marketBaseVault": "B4wwgkYykxGZjqFjhC5FfmnLtbe9M1vrsfU1sVVEDdHE", - "marketQuoteVault": "6TscSyNAheDVrgxjFri9tQL24Hxw5iR7oUYgRAby9hEg", - "marketBids": "3trfAqBPcBDgyVSb63WaPm5Tj2nyVD2yWnFMBrmEJeDA", - "marketAsks": "ADaawbFYR2pmLjkz7CNaxM7Rd97FvLYto1CmGBrcMAaZ", - "marketEventQueue": "F4EP1TDhwGXf8xzH6swsXwCXJ4QsLidmfjKQ82mN533C" - }, - { - "id": "2arinm92n1s9bYZeAxY6mJhhHCkAGFugeK56JkMLN96A", - "baseMint": "More2NaP64ZoGZMunc5wK8D6hbiNiAD5VkST6SxcD8R", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Dm533kacGDdV73C9M34kox3sVp8jr518Ppp3DzKiVCDH", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "67iHCV87MdbwFy1cJwATg6BJSFNQSYYLbVDkQPdAJJb1", - "targetOrders": "xW9DgksHT3P4jnAxSem3SFyTH3BdVLbyzjH4y4fdvYY", - "baseVault": "EGhWc4PARcHf2AnRN1vdA85ArdLxy1FoJYanXMDva7Ud", - "quoteVault": "2TgFF1PayJq3GuiNNmxUuMXC3d2C4MS9ViJ96CBEKNvg", - "withdrawQueue": "C5D4EGmJAA9RX63saqb4XZSUDZ2jg9aR1bWvmEXZbjmM", - "lpVault": "9R18Pds2cbETo6hYUqFC1JoLF3oo2wrCfKBvRjKWExtF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CmfV3tbEcmVCR1UpKXjiGnE9fo78dnbiUPYkdVye3BZG", - "marketAuthority": "2ABrTDYm8u4Yi8n35jX8mYJAC451UiNJTRSEAcphEuLq", - "marketBaseVault": "9b7yT8bVRcYMdCNK7CPwe9jDpbtk2PiffSaQYVZanN27", - "marketQuoteVault": "96JUKRCJ8qEEHzHhLc49etvE3EH2DPEUCaR1Zdam1Hnc", - "marketBids": "8oQAzkuJMxYt588tcrmevbdzgUUSHWYp7t5tgfcZXE7r", - "marketAsks": "E7nJLkgEbu77VfoTmhtKYVtneEMXUqaC7HjiNqGpp4ey", - "marketEventQueue": "3drmjSNpHnR2TfEGBxjmaiuMv4BYWNytN3oCZiXUwxBV" - }, - { - "id": "2AYLWe2Yi7tUrSyRdinrHyPejciGYDTnLLyjCqwjq6rh", - "baseMint": "zmFoYNC3CuGY1VmgAcxXzfLMnSMVZpJF6RGJU5vDxvT", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "79r6zY4z2PEq3vTWcL8FJjoH3NUJVcERShHFFh3dwpdf", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Ck8Nz5ZVZF7Gj3EauWy3gEMqFBRmB2XXrBqJfHUXpPx5", - "targetOrders": "Gok73xhNCZgrGxRuQ8mqSRncY4qHcKnbCAZMakYCAJeQ", - "baseVault": "T2fq2N9WRoG82yQ5AtZ4uqfGwVz78Cm3VcQxiihdj8P", - "quoteVault": "q4c2Wiqqz8YxQUKePC2AsrKCNgwxyij3Vn1c5QHWq6p", - "withdrawQueue": "Ead12oKpdsyHgMQLqZ8YxvepoQnMF3VvBWF59nCDmgj5", - "lpVault": "HGq9WHYqiYgVpBpYyp1FWfVdyLo89EadWY8CWikvSoci", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BbU4Lcp5Dq8sN3fYa7HZkgddg3zwJSFvU7Q4dfpRKkN7", - "marketAuthority": "HHVVWwgxNMjQFVTvd3qBVnFaLN45pAwzg2HPBduvEtkZ", - "marketBaseVault": "2vgKapJCTsq5nYUZ4pY9QcVDijSLB34G97u4cN6Gkqnk", - "marketQuoteVault": "4dJRPjy6tuzzKQjwusdB4Ypz8bcUEc2o7ciJ64NAGVdM", - "marketBids": "DW2mRXqzcMTbBYYKR47ZeNA1qD4Z5NBhYXAppw2dABF2", - "marketAsks": "Cz1BFfVfBWPJeQEJmzQZxpVfiRBtHv3aYnJU4SnE86Eb", - "marketEventQueue": "9bY6Y9uQfEtKvVmGw331m1xgTapbjCXUDxvNeXDiGiLZ" - }, - { - "id": "2BiGhD1CMiZKvZVtF3vAGbW4HcZKkThpyWDtruKQFr3b", - "baseMint": "5uGH9wrVvdBzrdkimwNt5b78FjFdhzrP2YsGMKYYE9hd", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AfqZTSKXTHRqtEHpEzVzRv5HU1B8oNNWK1ewEZfdqHNs", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3yx9LmK94mzYCekj9d27RoFgAiypJrFHHXzpHsoAy896", - "targetOrders": "EPTTao7vmREFzVppXaSgRdvLMf73F6wup8Sn8RQeX5wv", - "baseVault": "7Lh6VM3FwCsBqvg9cvxNKX9iJ7CQb4zi7SQ848yDLorQ", - "quoteVault": "B2JVabdumZ5RSpwtympMNt4PT9MgRNJKkaQSvVpgGoDQ", - "withdrawQueue": "GYKRKf25jEsyvgBBPAxTE7g2iNBZxFBxS7Q1gAXsjVTm", - "lpVault": "6GDSmhggqQCPdpvSgPgqrtj3gjJhEDHvMkW7Xp1jQyD8", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HvFnwJwvpegFdxLkG4G3MWWfcuTruEHzHdZXgk1s6ZsY", - "marketAuthority": "dYea55GyEaZwusX2bs16oXtftpFSCDyJZPjyR7Sf17H", - "marketBaseVault": "2vDSdawCqJZdHoyBTUdV6zs1brL8ajkjPeqkTVJXa9YB", - "marketQuoteVault": "8fyJEuTixm7PJutvoHbyNgdWq5mm9kibUiyMczmvKfGD", - "marketBids": "46GLurdLL6fGhaV6EcbtrorKExLLpkfBSaVNjpAW1iX6", - "marketAsks": "8hvJ4EkHKgQoeQAhF7a6jgzXeKewCL7ZRm9dHMit7264", - "marketEventQueue": "BYVPHsZpSXCmcqyTH8D9FEZzMhmzBJgBcaGbYMozVkAD" - }, - { - "id": "2C6bungyjWLXH66KnRu4UXyZxQvf5P3KGhCMvS5b5rtQ", - "baseMint": "AR1Mtgh7zAtxuxGd2XPovXPVjcSdY3i4rQYisNadjfKy", - "quoteMint": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "lpMint": "rhua49jsYRAxFQmvVuKmNVHicYFf6FbU4UveoMLrfkV", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5U2rmuVSyNdhwt9Uzu6tmSXmSZ4HvF1vTLdLBUgJJgZh", - "targetOrders": "3WbHt276JUFP2rnLBCuzFW5KWY62QNQpLvdVyjH14HAP", - "baseVault": "3rCbD5vn384z29DUnUeK9ZfzcrkEEdsq27U3cxGQYhUF", - "quoteVault": "2fHDN4UTFU4EHKVASPVd7CHLn5dA3DMSLDUQgVZsPGSG", - "withdrawQueue": "4JkwaEsZoua3YxaJ4CHJg4xYioiEtMrYeWwDmGLEhS6a", - "lpVault": "CLQBFzTCUA6yHNgMsax6yHqF8ahrSRjNnozuRy4HCfd8", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FGYAizUhNEC9GBmj3UyxdiRWmGjR3TfzMq2dznwYnjtH", - "marketAuthority": "HZtDGZsz2fdXF75H8tyB8skp5a4rvoawgxwXqHTGEdvU", - "marketBaseVault": "BSoAoNFKzK65TjcUpY5JZHBvZVMiYnkdo9upy3mLSTpq", - "marketQuoteVault": "8U9azb65o1dJuMs7je987i7hKxJfPZnbNRNeH5beJfo7", - "marketBids": "J9weS4eF3DcSMLttazndEwVtjsqfRf6vBg1FNhdYrKiW", - "marketAsks": "4TCPXw9UBcPfSVtaArzydHvgAXfDbq28iZVjHidbM9rp", - "marketEventQueue": "2eJU3EygyV4SWGAH1g5F57CxtaTj4nL36apaRtnEZ9zH" - }, - { - "id": "2Cat6zKJm5HRsqKs7W14cuzdrDQXByu8c9bAFcM9uHvY", - "baseMint": "3UCMiSnkcnkPE1pgQ5ggPCBv6dXgVUy16TmMUe1WpG9x", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3qn11mgGLAqZHucw8vwL2hsxRSHpnw2Jjo2HxicFN7hi", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "T8aVpY2cZ2U52ziqyfegb4swaBBCbe7RuDLSrKm4yCu", - "targetOrders": "J3P4BAg3TKBcLAsFNFrEtCAKzKMxXJAh5bVDWcRBoA5n", - "baseVault": "Ebf53ZeJAR919F9XJ8ge3p66H8ARLDvp3fb9FwAtmcNd", - "quoteVault": "2XtBMLKha7dEQiW3cgSMRNN1MRdhFtsg9ku6XGu3D1vE", - "withdrawQueue": "M1xEZSjQ4UetwtWNK2ruzGRxmHGdUa2QrnSPfGqiZf8", - "lpVault": "5eHpad2RTKFQ75ohAmLcicTgMyAai4YhQzxqDaNm2t3r", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Fw4mvuE7KZmTjQPxP2sRpHwPDfRMWnKBupFZGyW9CAQH", - "marketAuthority": "7vBe5dWcitUJkmafyBrdYZq92UNRRJ4Kucr33gWxRgV7", - "marketBaseVault": "67wWyLE2SXdBb8coJd8fiVYuQfndCW7o2Ft5JeUPo1BN", - "marketQuoteVault": "Bo1EXCsE4kM6B7qedSqSpp22U9AupZt39LGsYkE5rM6v", - "marketBids": "DuMs1QfP77mbmJEPWKzx5WPAqjJVWbvWh7XyUa5Kh38J", - "marketAsks": "2VTwruePS9eMCEwxrrBg6yecgLPEFUTiq7aTomohXSyF", - "marketEventQueue": "3hB3NmTE8UXZjpXok7iRVBETg9pEmSbQkSWpQmPJAHbq" - }, - { - "id": "2ckAEvtUmafibSDoDFgQzuwFn3j2rvW1WtQNkkWoQGsi", - "baseMint": "gJtYNevehYkg9VeEaWWKztWeFt4WXdQFihMXrUMeKd4", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "49nyHUT4U1egBqyQ9D9WdmS4vDhN9syTeay74rp5iXRq", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HM8hLFvmd6SQrHXn4sSrMM5yh63GAmJjSoEumPRFxT9S", - "targetOrders": "Fcfxef6GhmJmUw6vg9emd4TThhPJsmgVa11TLaXjF778", - "baseVault": "AWi6pmRkuePG6sySKrMFjZLPr8SsG6DHrqmmanfPb3Rn", - "quoteVault": "9Pn5jQchupi9aif8axC244G4FSoqBfnqf64CAcocZyjD", - "withdrawQueue": "GuaM4VWrELGoo44vu38KvVE4XAN8PYBBjs5ySFTvNDxx", - "lpVault": "BCPMA7D6U9xi1RXwysX2gesozdtw5YyX9KNa9MQmf7vK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EVMYGduB23RgbnCEx7i7xKMvGCXM8P3BKS4iF67gQwc1", - "marketAuthority": "G95vyA2b1NsW9m1Zjv6hhNKMTwGjgxPwHYxUW4XwrHMp", - "marketBaseVault": "AJ3AohwAuS7nmBKTpGya74eUB3mT8xYjiXtarH7odt1G", - "marketQuoteVault": "8wxBGKETYewuA6Le1AyokMvXt7rJwSCDzZkrTyPfBk6o", - "marketBids": "77FPhEoJS33gynPcngtVDt7F4JEsok5DUHFLKheB9FSg", - "marketAsks": "28WoH49LVqoJqDJ6gZc25jPzS65qir7es2h3HNMY2fon", - "marketEventQueue": "AajgHVntvbw54wDogP5d227jAaLFAFNf23pjgnV8oWH3" - }, - { - "id": "2CKdhcq1MAzxAK6fAfSiturDn5n2sHE9k6ZLhmtJZvi1", - "baseMint": "Code7hV6DaK5Werof8c7vPwBxLvhmEWVUbU2AfhBZArB", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "fntaU9SmLvohjzmvHqWqFU5cGmDrTzk28XRvEonZA8Q", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HYYEPJ341wS2DmV4u8ziErNY3L5XBxt6GjXcLPXvLM3n", - "targetOrders": "G5rqQwztkEDugATGjr8ueSqxKUgPFq6NdrUSNYUTj7qc", - "baseVault": "BvkGRCyYFQ2ZKtvCnxqLAzyAHtFKAB4tsXPNLskcxiyc", - "quoteVault": "7mUsE3bJDsQTCt9esKi3kkEeCqFnyoAqPgzuNLJbZeZK", - "withdrawQueue": "3V97Xn5EDpJWzXchfjh5p7j5NfVzJskVSyixJSheSCJa", - "lpVault": "2rdUaYeST6xR1ndmxif3sRdYomxzCzt7Ptr1Qh1H1FK9", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6GqrzkppaDACqoL9RuTVifHDR4dfpVxsHD2Gd7j2WFm2", - "marketAuthority": "7JSSYGPQba1v9DGKBfxJAoW1tC4cw9qWSGbWB3QFtzuw", - "marketBaseVault": "9AXDvvAsRwFfJvXs3F13Ak9GcwEy9ggDSo4Gwi2SBUkB", - "marketQuoteVault": "4sVhRzaTU6Zpjy8ekZaxWuF7pJUb5sgnbRLH1812auin", - "marketBids": "9Xy1WeeotHeZ5FH6PQ3kRtCbqPxp4J5F3FtjxCR8mJ49", - "marketAsks": "6raShXTPYbdVpwn2oaRQhcnW9mQ51Ha6SSrRYgfSe7ra", - "marketEventQueue": "2wpgXFjwiPJgG1UraXPr31jZEyhRckFefhrkMkDKFbCP" - }, - { - "id": "2d1fh8bZNHntsom7eR3ZyPTXSKGnZ31yxBveKyg55diE", - "baseMint": "2Dzzc14S1D7cEFGJyMZMACuoQRHVUYFhVE74C5o8Fwau", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Cb5ezet84Sa8NoEGEPpYsvqVBNzxWtEWw7BGTfGB26hZ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3WJa2nhHKdhm5TbYRCTKMGCFQRnm6b49LkRTNxQ5yCNs", - "targetOrders": "2BB716t3zVcq4vXa2KXbEjtewJR61xkJ6vNj2BaAGZnG", - "baseVault": "GEr2CGrwL8b28q81zufoZ8nae4XdpMxRmBVS9qjJHk8S", - "quoteVault": "AZX7LP7vY5oWgjYATwBYD3318TdFmX83czkFKSSVJLA1", - "withdrawQueue": "6bbuqJVPstkD23syaLRchMJUwrfU6zztz28fT7YPtHuh", - "lpVault": "GugX85n3v7YYe35HVkf2dCqSEh4RdwNGsiqBfmh9G5ev", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "J5EVvCoghBepxQ1jmgc66dMwvpQEAGyy3WMzPmzte1fF", - "marketAuthority": "qeZtFMrPS72u59G8mCwuxUbNjEAzur16NermjGsHZwi", - "marketBaseVault": "YrrLbC63wpSfYSUvKEy2q3a7fcDMcj8fU5MbEgwePS3", - "marketQuoteVault": "45upHs1PbCh1dXoJ1J1DRy1fUwiJsxYvPjJuZHmaVDKp", - "marketBids": "83hkYLYeyXgeW7FkxiskuwK9rCwFyFxd996RuruoiDNU", - "marketAsks": "8s5ZhuYfTFm8jWjSBVgS7oiiBYEoF9XZkumCxLyzhCYV", - "marketEventQueue": "9KhSiY8M7UUa3vu25QxX73MQXP8Cxd9ETeyNHXEDNvRs" - }, - { - "id": "2equFfmLfDaCpeGvDfHBjKaDNxkQTD5TfvTJJS8X1Kp3", - "baseMint": "EAefyXw6E8sny1cX3LTH6RSvtzH6E5EFy1XsE2AiH1f3", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Ax8xKpnMNxX9kTi8hSpwoH9rygFFA91maziye6JC23yk", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5JjVczgeq2iMdQD1qq6UV2M5fj2gLQg4K3PjP8sntWAG", - "targetOrders": "YGRxAg8Hv3wJgbeKRS1DGMTYYFMFJXWS9wxdcxq5vkn", - "baseVault": "39RdYCVXG5xdKdiMFqA7cc8ttD3HA8cDhfetxh3xksFd", - "quoteVault": "Fy2gBLgtmb3CxLfy3Y6EoTrxhEr89QXmGEkG6b2oECJH", - "withdrawQueue": "FZhx1SV9KtrkDDwy2bPAsv2CHbjy5UPUdamMzoY22Fkp", - "lpVault": "D3t3Pp2rsrfQZwiH8Ju7qYVeE5V7Dm4htYqh61NBUyjr", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "vfARqzk9ZtFpK7etvUq23QzWidopgwBzJx29je7JER8", - "marketAuthority": "9Gdo6jc2aURDrLKgmPRckfxzNgSVDdm3qu6fFxc5exD2", - "marketBaseVault": "BiurgjAofVqF9CmQx6mvpfRTYrSwvoTRhebLubmjR8Wp", - "marketQuoteVault": "AwqTLQwCeCksuJBknbK2GtVTCBLfxmYVXJvVdP4McjCw", - "marketBids": "Fnhv95wkpjWsat693aZcjpjjDsYu1dmzj9i9XEdXs8Ks", - "marketAsks": "7ijHxAHNdBXt7jyGs2fNo35Gg7Fx8kWPMrAcWVsrBkKT", - "marketEventQueue": "Af27FVUMVnmfa4K1CJa4DQLqawQJTwRPupWKPzB9p9YT" - }, - { - "id": "2EvdDBmjW3uDwX2ytVNNrfxFD3nV5fgkK7ZERkhkGN57", - "baseMint": "sFA2de5kRsAmCev2WAoPCXbCKEd1ZwkvJ3MxPMojw9h", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HrMkudahB7XKXKTZS3HTbZtpT8LvqupFCrfrf5ZYWyEH", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9a6kGTK1dufk5JPcMdqxa8rRKbW9S8cD3TBpjZFSV35L", - "targetOrders": "Fo3wF3ys7aVJdirBpJHoLov76ZoWT8foSf2r1ya4NnB6", - "baseVault": "FapZmxGaDozKDMvSgUeUNTeMM5XANv5qt23pZwmDLbda", - "quoteVault": "2inzvwub939vsNTeyseE9HjVmGrxpXBzZ8d2ZVQZUp15", - "withdrawQueue": "75PqtXWxMqCAw7Uhi7rVQGt75iTe77jYCfdAtxwGKqtj", - "lpVault": "GtSLCh3B9Q8pTVU5nPFdRRjtESW1gZW4pNEPyrVsPCeZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9nWZ3nofZQHtGFmPJPt4PzmGTn9CesWu13Gi6qA3vjHG", - "marketAuthority": "DWwEBjrERYXyXaaroKnTEh5MwqEUovXQzdSkLPK96gZP", - "marketBaseVault": "FPbSnBKUPYue7bDuKwA44C1qht5RqJFFAaHEFHN486uN", - "marketQuoteVault": "H44tCpJjy1kUegDAVngcowiDdCEzx3D2kBBmpUFQndv", - "marketBids": "DGqUeaXWeGKm5v1frnXtzJLrjH2nMHFDUL9qqXsNPTAX", - "marketAsks": "E57aGzfiywaYfu3d3d4QWUp6926PqrNuEBaSf64Deonw", - "marketEventQueue": "48eWy5MpDkCQwoJT21LZAFBMC4vcR9yM3dNcJYiAhC1T" - }, - { - "id": "2FgRHmcmZUiw4HDVBqUwnTW5PbSo64YH7AVCD81pCR5b", - "baseMint": "2LxZrcJJhzcAju1FBHuGvw929EVkX7R7Q8yA2cdp8q7b", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Gszg2kNraUNz6V574TPBtztW6TVrXFNcGQLcjkLjcNsy", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5tFTJgtMojEwjfG7MxW6MFrEFc2HzcLy4Y4NYs3aaEXj", - "targetOrders": "FP8mFjY8r78yjhKAVjzXLo69t3wGxzbwqdsAHDHyfixW", - "baseVault": "CD6Ufyeydn4RKn4668TpWPCAsHiPU6jSSM7cvhgcx9hA", - "quoteVault": "EJABt72DKvauPuzXih7yD1dQ33jw52udBH5ML1PiMji9", - "withdrawQueue": "2FcNZRaCahtCjpCigpe4vgaKtFBHQ6FTUUbN1Y9EdhJ7", - "lpVault": "HW6y9DuDWrro6cm5Sow27RADRbu5dRiej9YQ95wkXuc1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7qYXpNp5YQ75u8hfTmNtGRazf7krXD8w8bmHBLwh14Yt", - "marketAuthority": "7G54zBtxR4tWRhjp84L54EbWWDvobuF6exG22zoQKoow", - "marketBaseVault": "5nm8XdDxrkFVJtEkSVVwd3z6ZMZ4ihbmVS7t4GpQZg4T", - "marketQuoteVault": "7NnnakbFgCKa58NafETu6ZJ1innpCJyMAo4iSLRvGYNH", - "marketBids": "CLKRDFnf45vLxWwFkoR6CaZDsdpwM3sVynAXERh9i5ae", - "marketAsks": "E3FzZAJ36mEAJ68NqimJQt3psC53SLHFQudyMicwfvYq", - "marketEventQueue": "GVNAGuxKmkw7ZaNxHFREAGi4a8Sqi5aVqVZg7apJLFT9" - }, - { - "id": "2FMKQav45EroeG1LdrYBT5EBxca8WGritVDkPXRCrsVV", - "baseMint": "SWANaZUGxF82KyVsbxeeNsMaVECtimze5VyCdywkvkH", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FPK8gpbmMdWPVXgER2PSatxyZ4UZbR7T6iFKrjxcNdYc", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Dn4EqvymTFDHpmpbmUVqQv5b9jNCKnZ5zJpR91oATm2D", - "targetOrders": "G6byKBZJasQh4oeEvJ9wHUn1b7kehiZhrfA7WiDMUckX", - "baseVault": "2HfPkzJ42XaPqXXAcf1qFfjLuFKMekG6Jh1Uw48Drvwb", - "quoteVault": "2ej29nm1xsFGsmrFHGrm7kkXeuZzKMWn2jEmPqg22QaY", - "withdrawQueue": "9DwwoJdDFnVfqsCjJWaTG9ovyQJcPG1zJBLV8qzNodoi", - "lpVault": "9KBDd6UTLgXoDfX3QDjdN9Cn8Pnjo581GZb1WQAQEEAa", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8zPVSrun5AnePjXWjC4EgMdBaLdHtkSUtYbFNobzQHRN", - "marketAuthority": "GAnS8TZYhDxHpbu1C9ZNt2JJY9Xke2kH3kiFmza1xbvg", - "marketBaseVault": "BXAX2HyzHhrK3QAH3WtQmVJ8rv4d1EVnAQgM9yuANKuZ", - "marketQuoteVault": "HUbXvN7CR8feUgtZRCttDA4XV52ru4KnTZjafu7KGEuT", - "marketBids": "E7iw4sy6XipqfVhcfDJGdJ2YCKBtdQW5viWHgDNcirNk", - "marketAsks": "HYFufusJEwE33DfJ8X6s5aaSJTx9Zjog9r9ScAmX4ot7", - "marketEventQueue": "8JRfzVmXNPgqShvxhmpwFzBogxBSdx8zr8jWKTaVYnei" - }, - { - "id": "2FyRrwYbyuMHz3BBFJ4K6Dv6dL871ZGpg86XqDg3hQi4", - "baseMint": "EuD5L5XSYKzyDC1YyYzmoWC8gmJhpEh2vMj4f8LeRW8r", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3cAyMf4G4giB539vmaS2jCU19B9p8Hp7WzpgnUWc2sgM", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8y3LQHgk4gtbBgQhwgVMGoyuFCnvuw245MuytaRzGgYT", - "targetOrders": "Z24FpN6BvsxvbFnQDDXYmoXHe2PcYwzscjuwGXsWqCU", - "baseVault": "9dmPHBbRzDyEG7i5BLoWkvqCp1YTgL37BcpDVrydn7Zm", - "quoteVault": "8ZdEbBDwv8rcuYjUBYp3uRQrvAMTpqezyT2nmqWwvmkU", - "withdrawQueue": "Fiq8GAzUsDBhAATfSrzPFkHy87DvJCbwn7g8XjGuEinw", - "lpVault": "5uvCwni87iW4P6mrsPBh5XBZSi14g8qDaR19XcSWD3rx", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BEZX5euDoe2xMfLothLcuAVRUEVJyndPV1Jfo13MbnZD", - "marketAuthority": "7mi5bYGQ2n7ntBpbhTpzyHFJRnWDRnF9N3BpJKHyNPei", - "marketBaseVault": "FX7iGL5KRENcsbWc9rMuBQb3VxuePVU3ZAR8d995D8cc", - "marketQuoteVault": "CgnSb658uK1H1r8wFknxMcoTUhLK2biovii1Cchcz3C9", - "marketBids": "Lv5SaWHjifDmJuwmjX7EM4ShWoP5dzibSSNjuEhBfF7", - "marketAsks": "C5sdJonfLU5aKTMiyMbqRd44xZXyNhFqEba4wkjxwjZj", - "marketEventQueue": "7y3yVNVMtsFpjbyM7dmwDipJv6Y4zyH22oEFys4SysPy" - }, - { - "id": "2G8pXrEUvmGSaMqmEhR675AsaH1xZ7sUnKqVymyzBWmH", - "baseMint": "CmhTb7YeYQmPsTNR1fcqQHMGFsXmcG6PERPM5hx4WRJt", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9xgX74JFceh4NL16F5oTk2Dcjk5j6jvGRzwAknyEeNzc", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2tMHPRro4UFPZbmtw6Ak194vzgdvGjs3B2R5ZZFtHzA9", - "targetOrders": "BPYrkkcf4F54StbgZrdzqdgChp3mxfpjLUXmgfDdUrho", - "baseVault": "CDBq3wFHa8vTicG6ic6qTV3swTPdvuVgUd7J8Pp3TjvG", - "quoteVault": "3eV2wjPE4acJAwvTEvZjuxgAJ449qPHDzfJFE78j2cyQ", - "withdrawQueue": "HxUykuRnCfM8wzJCCvot7sshmMqZVzUs5Q6xBBvVqbVr", - "lpVault": "B18L3t4yYyjFpttXvHdGeB4QYdMLkG6ByUAHqqaGQpT3", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Gfox6KagFb4ChyJ2UdxuR8vubSY4kfTv5JXGvBdkTC8v", - "marketAuthority": "9NueANQawmuLrWmjs5TxSLFVMUTxfU3BnfgrTYMZDUh", - "marketBaseVault": "ERfVknXAFEHzN9ktYxVXnBVSujX6T9CcfazLuUvX9Xuc", - "marketQuoteVault": "BummusTseVX2ncmTuszy2DAytXVih9iShFy9Te3nnJJ", - "marketBids": "7KRYtSFnjhGJ8kzbYKcybK5R5W9wZ32tnmNmWDcqx4SM", - "marketAsks": "qeQP6k5FyfUX6UTfJZcUzXtjeSgMMC4XRe1ew7ueRAY", - "marketEventQueue": "J5Nxhev1bMXPFaQ99ATtCUpLy3KpPACXGsrpYYkDsEhH" - }, - { - "id": "2Ga5ozJy7aqUCTiqRLaVUfxhBnbN14fHALAmfFjrnJ5g", - "baseMint": "56tNQ29XBrbovm5K5SThuQatjCy92w2wKUaUeQ8WCD9g", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "46J7E7AY8fLjveDEXHQBFwLU4rA3WpBnNHPGiWKDB8v3", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CsXVWXUYAFRTJKkcFXAK6Be48F31A5YgDZZFfo6rmd4t", - "targetOrders": "9FPegfcdKYx98WSeKhbu9MkyoKoDHHbDbSwwJmTEva5L", - "baseVault": "hNko7iYoQY6Sm76BRaXHaDvNrC6BX2KEdHfXWybn4km", - "quoteVault": "5hCtALpBRtLMkNbbcMMvoAHBgmu9Vzy5g68U1ZEx6Lkg", - "withdrawQueue": "ALGEXHDUxzjBUapNpnrdQ9BDXtBUkZLDLRVvhjX83obA", - "lpVault": "3VZ4ExQwtEUTyRDApsBkfwp8V3P9AyuXeK6FzYsuwCus", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GN7GEoxeg9yKMWt5KbvQXbjEtcCPjyPicd9AW16NjK6a", - "marketAuthority": "B81S55E8pBS8dEt1hxfs4gxLgGgLtXvSqE9yDnsKnqQa", - "marketBaseVault": "4RJZdc7twMEnG3q8ZPqsFvEge5awJQ5EJ6KahketQ8rN", - "marketQuoteVault": "AoxEZoZgRKkZUqaQ1EaqDxQ3rK8p8s31CeXayLBWx6dj", - "marketBids": "HmWj5xffgai43ZFi1bRVR8zJ6hdqyRyZh62grfwuGt8y", - "marketAsks": "Cu6xSH3kC8DefQDQR5XSCK2cgkoUhvBEUMhJ1M9EB5Xe", - "marketEventQueue": "9yrKLm7HxMfE1qf4Nm8wZgtUytQvvqeGpeXHQW74CNLR" - }, - { - "id": "2GDmgh1fvEBd67tswib2pwj5qsHg1oMVJqmCsBHHUY3A", - "baseMint": "6pSK3JkbfFcQvu6TuTsRnG61jKxdbaoRRkp1H6jhxXV3", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "CW9n7LdrTqdioqAJD9jnXyXDvggRLM7NUoRA1dpJo7Sc", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FvyuZve2BQfMVpow9LemBxydh857AX5LRKrJTaZFvoUB", - "targetOrders": "7yqkpz4kLBocsR3RWmau3A279fWDkvHpQGZo9LpNDr8k", - "baseVault": "2VFhhgRvQzGVKSUr2KzMCMCdYMNgrJfuM7T5mdFoh6V4", - "quoteVault": "3f2XiGgEitPEWfbXfkcenoRrCYo7L1W4xHTvs5JDyfH4", - "withdrawQueue": "6DnNDGaDKSi5FBrKVz6xWSgLEAyFJNxZkNR5K1Pgsw5Q", - "lpVault": "AiazDvdfKUPPU9cTHpZryoKaFJgSGqWt7axZnc3v1cn5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GU3VAgiiiXsqtcMbLDK2B8CdRhZUjtn1jNsr2CbkuSYf", - "marketAuthority": "4Bja6HqhqYUjV2VXgxz4AZHuC4PemgxH1w9DuFrPqt4f", - "marketBaseVault": "9h9LTzWJecgzkEKg6UEE5rXLnzLRtW4h73wW6Na6ni9K", - "marketQuoteVault": "QDYggzfFEoKytj4sAZqHvJu5tLTroWQ1Ge6hTF9X7Jd", - "marketBids": "41Q299ngRMt2bmmwaR6ttcgF9MmraU856w9vMKNJirgV", - "marketAsks": "fnBcrNdNvC2AG6F2tDuToBMLxKF6RfRphpJUqHZ2mi7", - "marketEventQueue": "12Stg89QnK5rC9X5NirC1vfeyqEKyVsyZbXgaDNt1HvT" - }, - { - "id": "2ggYGwNxMtAAuQ4SosCYheXdWSBxyQaeDR4aTV4WpGUR", - "baseMint": "7FntsntzGjK9PzPBbHLDJAFcKQVU14d2SbQZhgMUf2KA", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9RfdZAehFmQTUBgacjjPWnMDnzcsTWLUNVVd1rrvoY1e", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9B3fMccRx9x8NgMVW7GXkYmhjAbYum36gDu1G6WVcRvT", - "targetOrders": "GFnqwk8ytYCNSzb2HhLGCvJxNLr7jJTF8qvBF68X4aL6", - "baseVault": "8QZtVRFQCUc8ytAKZJKPZ4t9S1dXWB7ZThPCi8K5oyEq", - "quoteVault": "47S4NPxHbYw65RA5X1gcL7RVcNBwiusm3BYojMbWmcPf", - "withdrawQueue": "6NL57dG5E9zKqC1WRuNJC418uVX9ELWiXzVatN8gDrWC", - "lpVault": "2JCvj7SvXHmMRnzvaKSbtRxu1HrEmgcAomQSk4GnMtPN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BnYWx665HCvo1rpvLLdLF9Ja4bW4pvg8ZDonANh3o88n", - "marketAuthority": "5zXRmwb3ayqjjeEB7QMdnQSc8xMAy7fz58YsSYU5Yszb", - "marketBaseVault": "DavkLiV3GWTzAiYS6tE6uLtdBDjH33Kb7hLn8XLpzSU7", - "marketQuoteVault": "CDWrjeLf3RGY1SDc81AdEp79Cb5fcKogWEU8RK1g7d1r", - "marketBids": "3MvXgrWuteZVnoonRFeUvZ4ZncK1vCXutQTsUjT5kDcP", - "marketAsks": "D3oN8ssqfMtSkW7DNnHa8TY9zVUpcc5VvZBogosYLHm2", - "marketEventQueue": "5qBxbkabE5Kiy2sZtvAFAe6ESagTGyKWuXRiFRHj1afs" - }, - { - "id": "2GjVfBbxhxBhmtmhm6cHKwmfEgFqbWtEPLYfF5LRCEW9", - "baseMint": "B1nrnT8LvkxqJFw3A9tWoXCpbLUNKYkn8gW8qYZoTRaN", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2Ph2JuPaamKVXUZeh33R1KVtyod69hFuwB4iQfLkaL2Y", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BqU1p6Q6FWqztxuGBvZLwpiWFwyEZXnejTnEbvQ3xwQL", - "targetOrders": "9pvTNfEw4HXDmLEwHzoRY2q76dWVDreUkaXpUUHho24k", - "baseVault": "29CcukDMH1uZoSa2zrSuXUnpr8NcUvznqi6PwKfxV1Q1", - "quoteVault": "9joFacrEV4gq9Bcte99kHPHfinQQFrnuqAALeEbj4X76", - "withdrawQueue": "7DuCaoYUg9BPJVpTEM5hsMCHmWuZMUAfEUpvynigVvwe", - "lpVault": "D2M7FyoUnQFLkcntMKzzDTNeZvS1NiAWx59GXmG5QA1J", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8hE8ynLue1eKVp7eSm9ojQSJ1Uk8TLvRiSYonq5BXzQm", - "marketAuthority": "DpXnU8zv7WrK4xbFF9UFpY7sA5ixuPnzoWRrLAboyjN8", - "marketBaseVault": "8LuPjogGhEDaYR78t7Z4Z6iLgxbQ8RiWhC8UKTGNi2Jb", - "marketQuoteVault": "DfXY2eHJ2w5V2f4k5p3Z6wtesRxhjb3BEhWwzmwendQK", - "marketBids": "Dae5Ac6nPufYXb1mhgTUzmM6x69GHKSGpjqkKgVRxZg2", - "marketAsks": "9dXJCFYzaf3wu9hV7FcqG5FAx2bHMJk66WiBBGthhRoM", - "marketEventQueue": "9UdMknScVpaupKo2NZErphncLnDCZUrYaH1K6odUqGvj" - }, - { - "id": "2Hz2SgGBhSJHVR5wDpdBPukmt4r58S8VFhznoVPCwYPM", - "baseMint": "AgNbV1MWw7Lke8hp8w8csA9EPW9eo8oNZkqt8LAs6RYq", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6jG8t7nPrLM3Ye6KbdnmXdUPspiZmTHV1hKWsCFKY1k", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FpVh9wKgE21kkpzxskNX9t96ZE2cEkokXRP5BvePMyGV", - "targetOrders": "9vBJjyCoTHUxpqhLTncfdbSgHRUmk9Pi9zXKfqCusCqz", - "baseVault": "B7Jmc3X9CisVu9ehtmN5qmgFYpFmXUK6HwdU1ZiQJsNn", - "quoteVault": "7WWihm7XeXsFRWTWM4M1wojjdATrQ3wDZhyMurabEdEF", - "withdrawQueue": "C7Rk1k3TgZsF4JENGD5MR1c96svrCYxj5aihxcstL62f", - "lpVault": "8PwdNZVYJiHcLymZYyu4C88Zr5ymyZ5g1CK4iWLumZf", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Hm7xSUxUUR7KNt3HeHz1vum5cbGj5MvCvPUsmUxwWrdo", - "marketAuthority": "2PXaeH5NuDeiP4rKTuGe9UAajXvrYxbm3TigMsHqBNMt", - "marketBaseVault": "EN7DKXQbJp2gQvFYnT61si9mWTp9E2UiPaUBj1twbsDb", - "marketQuoteVault": "3NoFMwKJYShN81645jMMWv4L1A859FFWET7PseE2SZYv", - "marketBids": "J8XwjygCs8UEyBGsUxpTWkDNk87CEESSeYaMGk8vJuNd", - "marketAsks": "ESn484UL5jA68bCPxQqxYaUDTuPYLBMofZcu252uNYNY", - "marketEventQueue": "BNoAWhh5tb1rybAuUbJh9C55pR5NH2Sjqa8rpCiNVjuy" - }, - { - "id": "2J7YTEW987B3B4D4Bm2MsmBHm1Mm7ybM5rUpSypJ28U9", - "baseMint": "Ap3JAjPAjQxnkLezqptd6pyE7kx2DNiQ5iT7qdBFS4Ux", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "5sW4ykp44asEpKizDD2ssWMiFmfFkx83rY7igQC8PxfP", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3FiZ2iZBo64ARRybMfJHMP37P8US5P49vXLoo4xrQtv9", - "targetOrders": "AxhtZfMCiwfLhoJ4LjsuQdU7LNHP6r4rXdYSrvCH9HP8", - "baseVault": "7wiBixBtNCchwKE9XdeNMibnUQEBFecRv3HovGPGPhGB", - "quoteVault": "5V5cu44nXKKqppwhSEkYSwdXMx2uhvH74JhAqnjmSPfA", - "withdrawQueue": "13EdrfFAUhzuk9Wzugh84xZfZcRt4P41b5jh35m3LdLA", - "lpVault": "5SKGUeMC7AaSjniieC9bha7d51w7hj2SGu7wovq1GgW4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "91ACcXXZxvSCHgp7FxyxmwQYH3Bn2ax7uKjLMUCSFyTV", - "marketAuthority": "3kvrie4968UJcZdcg6kEok1kcm2EJHY326uNWysWxKJk", - "marketBaseVault": "4YM4Dk5XbGp8i2hBPpZNPMCk25Mwe9Yu5g5B4Xf3qmt6", - "marketQuoteVault": "2tEGhH6cEtB7WQKrHqzi8A7rZJHtqbNrMnC7CdyAVYeG", - "marketBids": "2TFhFq9ZbHqKjL7jDayVPF3bva1PJhDJQ9JwQDfz6TeB", - "marketAsks": "ELs4JZ9Rnhu95ezQhDh28ZXxPWK3Mzbnv1j2wkv7w7db", - "marketEventQueue": "3LCLU2wCWaVMVadEkR9uZEeQH2g9NWgCQtSrxCBQjfLP" - }, - { - "id": "2JsUshnBHjRTH4n7gLwZUvAbCfAbqVH3cYY5Rp4Tx8cR", - "baseMint": "3HVG8MLMAsu1Rd7gEkQ2K7HrsjpzV6Em3hp5Ug1V3ds1", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "ACv6k2StCoh2tdvQskdBF6cvSrqgiZaTTxXDiSynwktx", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BB3dQUXE1iKY7bN2N4adYBTUrLZcXz2xn1FAYjtvyKcD", - "targetOrders": "5SX3FWe8jJmV77Kq8fxEF8nbRm76Lro8fGCoA1oUJvey", - "baseVault": "BvLkJbgFsPEPFF2DGetFVysNMWeB84s9iq2fT3xm8Eq7", - "quoteVault": "9L3UMzEsKS3DqUBFPWKgjuFuTsPSC7xyV7AGHhJcRddq", - "withdrawQueue": "4fGZr996bsWgkGTSgpHCFMzJBj6tGYtxoqJWGd9bQxgr", - "lpVault": "Dgm5g8q2Q7rhe9guzPfQ2UPQimWVkE7cxeds6MjRQmZ3", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BdyjDaL5AtUsoh3dwaVm1Ym6NLt4HXXtcsJyFfn2drHY", - "marketAuthority": "H2335EfNwJREjfDhuX982gS1nCsc4mwaKjBN6s4fCxmi", - "marketBaseVault": "4RYgbGE2jk4HpSoreScSB8d5uqCFhmuq3zhm8F3vxhfi", - "marketQuoteVault": "DMhSTQYXAW6eFC42d9qswbbNuwV7oNzcxAqqSTCvhGFM", - "marketBids": "28s8vn9GKQ5KwVDQ2spHktZ2TpKgB6AYchZnn4jMsYYd", - "marketAsks": "C2zuRf8ps83Yxu4aEmGQEXN5KFkSkorCoeC7oRTd451b", - "marketEventQueue": "CvWx5nP5qRdbEYiWLphvPWo88xscC85CGg7uQgMGHS86" - }, - { - "id": "2K8W3s1xhZXhnj7MxecANGbg6FmMvT1bTTivYkPZnM3Y", - "baseMint": "B9CDWgvxhXViZdbHkakdRGZXXv7AnpbMejtxYNhCH91s", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "D4dHDpMNLZ2hzq3A8VA6JYS2aDL49QY7pxg45UY65JZm", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2LzdTSD7PPtfUV7LfLRgN4bMXL5HZ8J9WpTujKpUJEss", - "targetOrders": "HfN5sPyW4hjRRCZCS6BWxtijX6e12meVNpwUHwvxXx2P", - "baseVault": "J4RMNcDNd5SAMVonmQZAZtyrGuTaxGCvTMsKMbfXJKZc", - "quoteVault": "ES3EfuyEZYbGsqF121fXNvxo8VjiFrS29wqBd7oAUEb7", - "withdrawQueue": "55xRhV6NsUqzKSdvCXwJhvBHZ4WwDvqmiaYte85TzBou", - "lpVault": "2cdFLG6Pk72c46YYJMGLsFuw1H7SEea6X8Wstd5e49v2", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AQuEN1foqeThaLFVmtKSFWT7NrP8t8AXZerLqvE1v36K", - "marketAuthority": "3RVchk8PYsM7UNPtTQe6wVtsakPoQXC7H9ehGZqcpNL2", - "marketBaseVault": "937A6iAHaycArXNQcMbUuP1PjRBAP3w2B9HdNVFaVEq6", - "marketQuoteVault": "8dr2nXkiD9n16gfEkBX1heEz5uC7iHF7AeskMZx8BHo5", - "marketBids": "3GazwAfaFVaQ2TiN3R5PQrpKu8GZq6vKpkUdZfpds4fN", - "marketAsks": "BRpv25nbUav8tKBT5QT5XdYVhFmpirbddP2gPRHfhFZz", - "marketEventQueue": "2CLK1iFjqktt8XskDKbxarD5a4VCNQJhsDoir7Ym5qfx" - }, - { - "id": "2Kunmw14a1TFUgTNwMZBw6oFJ63gtNc9QQn47hJytPQ2", - "baseMint": "AcyTybdT75MhEauw1TJvRnpQjVKx6MMDyiU6FbSNKBec", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2zQxwXNU8UK2MGHGNRmKiMP3fMWuVB4kZAyR1dPMnf5o", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HdaQh6MPrnojyuJ8KDBzWnymP2CB5uvMHcWhGJf4KQCU", - "targetOrders": "FnvgqgB7DfdbkD94fms8rqqbdmN39xAVGAtKkxBA2yQq", - "baseVault": "DdQYZnuhp9dxgghAzDXdMK94GRaYCAyMPm2R5dmzAfjC", - "quoteVault": "92CXcNJt5W41t1kR9dKpiQ9wKpv8vV4FTqQ4okq9QikR", - "withdrawQueue": "4F7oRNVWbDDA3svjik3afvVjFpV9hnZxW7io9P762zX7", - "lpVault": "2HP51xVRG8ybkKmWwLMASqgpLnmeb1d2Yc1wV1tPSP3R", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AAjs98izbnDdJP6wWjtQ9WrzST48CZN885jita8STDew", - "marketAuthority": "7gaUA4rnTQUxMMsZE6jRYPvYRFdiNGiSdoUbkfjWdY2a", - "marketBaseVault": "EnHVkmmNgvHNa28AbiCTi7hjvvEy5bGi9irLHRTmZPwL", - "marketQuoteVault": "HMBLwTfn6a2pV6aRvXLobCo71M7Ss7ykb6ugGrs4zgMA", - "marketBids": "HqNAaMf9tVJqXp4zkqDSPvUhHEq4bWfzJupbnKRKF6UC", - "marketAsks": "ERiv1yZ1tHFJbgSTDk7RxS8ktEpnPTPcys67f12t4ND2", - "marketEventQueue": "AzZZ23jBQx1nnJCcJXrPwEPwnWKfsSKWgYLufUuv87P5" - }, - { - "id": "2kz8sk7PE327aNUfjmbavozpaACVQzqLdpFhsGKe1VB3", - "baseMint": "7R7rZ7SsLDXkYAfJyRCBScLuZwizeMWaTWrwFhSZU2Jq", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "4eUBVkkejhCcF5KERVFBxkGKyhMMsjBG9VrtoKET5FbM", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BzVFnW5zN67vjMtPxL4wxwya5975Msih42zfioPe1LFh", - "targetOrders": "DNrh3aCNZTs652EfESehp6pSMU7vU4LPAroc4koosQ4y", - "baseVault": "7d3YtRBnPHtX28c2cckCqpuWvAaRK2FUiA5jmfEv73xQ", - "quoteVault": "12YyWhyzQ8TJQA64cJ94m4rSsokn384DCNphz2QwQb9y", - "withdrawQueue": "bpyDauSfP74HjFyV5CS96JYh4Rbw8rC7uM8VCJ3WhxM", - "lpVault": "EEu8iYFNoqbo7oSy4JKggEC4WW9QoULnERfDfQ4CvRRW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "J4kzL5evQorhC6FPZk5q3bj9CaDPe3QisecaX5cpa2Ty", - "marketAuthority": "HMWe4Yt5aMyA75frKqBXhobZStq5y3sgbjvaT2HS6W4G", - "marketBaseVault": "BXSDkgXygK7K3fqdG9mDRwt8ZW2igdJ6WdmSuBr3Dzye", - "marketQuoteVault": "9SKUFmnKrSKFz3sjaem5DYLDiKjQYrJbkyH11bq4gPEM", - "marketBids": "Bu6ZCQdMEnppqeFUWccLZah5P4ig69PPU1YcjeJetbL4", - "marketAsks": "7KKVAeCVKwJb5Auuxhd3wQaC3VuCsN7wbLpeH9Pf67FJ", - "marketEventQueue": "HEPRf9kPm1Zh9Lb5uevrqn9VKJxPEWg5mjLyWV1VdVov" - }, - { - "id": "2LJtumucVrRUNZE1xENF4gfkrJvyuKsU5m3Nkx7S1kPV", - "baseMint": "31tCNEE6LiL9yW4Bu153Dq4vi2GuorXxCA9pW9aA6ecU", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HtR9mP3LGdJ9C7nevsfGAvKrNHd1KxjXuJbGMHY2nH6H", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Huv3QxXcRjt3Fe8eBcvnS8FhgGqVYwZx1K89bDYbM4SP", - "targetOrders": "3JiQyNvw5bG61HE2fSCjfoKHZ1Gpo8xc16U4LnHrahfL", - "baseVault": "Ea46bZBWJW6a2XgK6GyTfJFaNi9y4j4mJQ68YAxZPbuK", - "quoteVault": "FEvGxPpEm8KJMqMCmewskVrmM79FVYk1d3yzc2mQ3aw8", - "withdrawQueue": "DgzVnnMZsKGoLM4Hn1HYdUTh7fpiPR78DvsUu3YACnC2", - "lpVault": "CKHzVWCU8i1c3hWYArUU9ozPKMBJrhfHTZU9tQEJi5ph", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6b51zj1C78Tn7R3nd9j4GvyShbMNxxufbU3mqPmbDRcz", - "marketAuthority": "9Asmh4tPCWx3ur2Ykv886RqykGg5DGjApKTugLLeTMXV", - "marketBaseVault": "HuUKj5Vg27Q5GeGcWmPeBbxgQ9JMoGPRpZgFiCqEEcZa", - "marketQuoteVault": "5RzLyHc9us1DDVcH9pd5conahe8teBHSzJaKBNjnVvYt", - "marketBids": "58PoyaEaoabQJE5tQvDnFojzUs8CxJuV4a48JDDMDcGf", - "marketAsks": "2tT7CDkefg52y1bYDmdH89wEVcL6mjwuU6REqmeNTRE4", - "marketEventQueue": "6VQsEsYuiPyqA5GsU9BLfonXdoJ7KesojZM9UyqRAqqW" - }, - { - "id": "2LRTDdrGjn6yFGDnKYMNMRmpJEPDuZAPed5S2Gft3VmA", - "baseMint": "HWXWUXUNuBd6euKDxsL3FrCZ6P9RwmVmbXHKSd4MgxoA", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8Z4Rr4F7AbUvkdPNefwUGo2H6kP6yzGDXsZqVDJmQpwy", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FyC3GnAxMSWafDPXbgC2ACMZ3WGZXYr21MezR8u3rPdn", - "targetOrders": "BFWYhdq2KRtaG9BdMGH1diF12CCskdgGx52eEommPDRu", - "baseVault": "9QMP39ihqU2aShKhXcrWyG6n2RvyCK9gK3EARaqU3h64", - "quoteVault": "CqiD7RBemoRstbisiYVhB7fxsC6URQLnnf5MpXqz1fmN", - "withdrawQueue": "GogKHPtygoW7z6MsMhz3oVqeFNRuUrvZ1uHCbZn44art", - "lpVault": "FbkqNSRZtrq7v4xHtuhpNrRGxN1ReAtBX3KThCEcQXmg", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3u9PRFsha8BfAYAc1sffhJX1RpXdVDETnTNhQB1WEZzi", - "marketAuthority": "76qqMA6HSfWXYgkxUFed38J29k32UCMYb2EijyL9SnLq", - "marketBaseVault": "AFHdPk8bV9ZxRP1ZPgYuBKbWDVHQJtsuRZ7V3MyAgz6u", - "marketQuoteVault": "97tpGQFcNeaESGppfGfMpjxTDe7XCWVimzskmmPTGYgT", - "marketBids": "8pvUFF1Cp56V2qaSw5hUL7NVmmyuvcD9eoLQopcLFW5G", - "marketAsks": "L5iEoufZ9ifzH1wWcaQN7LVgm8GuGAMwHyjrReam3wY", - "marketEventQueue": "C6gzpiDvtotFuZLdyXv5v1SRVF5TqgGnfbEJXGeaQvqU" - }, - { - "id": "2N5HpqiZe2b5EKGhW1adx56chbWCAURHVqaH1gL9mppH", - "baseMint": "7s6NLX42eURZfpyuKkVLrr9ED9hJE8718cyXFsYKqq5g", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AVT97ti2a2nyQJBEYoXfJ3mfzxCcVnr7qPf1514RZQDM", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GNKyJ8AADtR98JUPTpdMdhVN4nEMKsFfiQSnRYs7RhZ4", - "targetOrders": "7UmYuizfcdUMDtbNC22U7xwLMLVaE6vorppnSfb9A2Ht", - "baseVault": "7hAo9qfgEsKtqmoVD6DsAMs75uRdYfmeqiMa3hENzGgt", - "quoteVault": "3AJ2r2AQDGu73Q3o5mSRoG1ovCf6CKMuNyQGQuCfxXEL", - "withdrawQueue": "22JaAuHiAe6meqT7n1SgXtkPc5STtNJqdqkVhNWNGJbd", - "lpVault": "C8NJEHQwnCeZuSeW9ZqosQnSyiiPLZTUNf1k31McZtco", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HzFs14Ua3opDJAg1nmonwJWGuLspnqafdv8wxWxQXrNa", - "marketAuthority": "DzKqvuYp2nXMHXnHn4UX5oB9AvfsH4vNnCjzaDBCntVh", - "marketBaseVault": "bv8Fzj4iuvfyCdBJamtNUUjV1BUEfnAMsMVMu43FQph", - "marketQuoteVault": "9Gix4pgL4zRuDweBviHRaaLddhVo3k4zh8ycZUqzFoP7", - "marketBids": "Ez7UTfvH5zT7YNTUqW7D6DELNm3JvphnEoaXNoxNv4dM", - "marketAsks": "6peaQn4zMU92FM65qrVHF7AGKThKRGzJrRpw6LegHB9s", - "marketEventQueue": "9YaKUTuB8TyYpNE9hkckUuDEUzN2zs1TrPxgFjik3Np4" - }, - { - "id": "2nC9MRnHgyLEUJHA96MLJLvJGu9qgiEgqmGaJPNf7zaX", - "baseMint": "LUSTdLASZy86pR6V5VjMpXxW9oVtCQt8q3fJ9iHZtPY", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EpdT35THyQyweaBUGR3mJsZWmTk8KUAttjWBF6KTQT3c", - "baseDecimals": 3, - "quoteDecimals": 6, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2WabrjgV9GtxfeNLzW186qgct2uk7utKxqoJoeDR4xcD", - "targetOrders": "69S3bZH5FMz3MeD692xirzPjwW5x6X6AhwBZofK2Zu94", - "baseVault": "8nR8VaBrNENj6BhnGcu2sYbshBsPJGVq3qrg7ZsRhRjz", - "quoteVault": "AAD2Rs2kKAU3ZkbBLMNdPGR5i1DVRBBkw2M62u8t78YK", - "withdrawQueue": "AP6y6Ymg6PToyvJzGaAZnUAkiGfpTCm1v1PQWLrkK3Tz", - "lpVault": "7pCnRXErX8RVKyiPNuwSZWvESWGqgrBRUHeocevpgx9E", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7iwN3bG68VCm5vVqJN6g4fwsHA3qVXvswUDWK5G3Pzc1", - "marketAuthority": "GxoteidxXUC4jhSgRUjzNGuURoBf8npRWFvcgnAdBEkm", - "marketBaseVault": "4TBJyTwVBMvvogszNzaMzJVzithTTr29aFMwxpA2eHk1", - "marketQuoteVault": "536kNS4dJgJtQEgXEYXpZaYsKRWVvQJQWwExcPg9Suou", - "marketBids": "2tbNpgCm384R1Zgc6fFkzkEDaSpoWKwXaNQ6aPL3BFTZ", - "marketAsks": "Ax6whkrGkoq8FRhx9BDUYx98xUkCbhPdyoZEA4Eyu2iv", - "marketEventQueue": "4Zs1bPA6duChcizP5q1xm128SR1w874SuNBbN8qNeEFq" - }, - { - "id": "2niyi2hV5dxqnHizSk39HzYvVfGh3QQsFuMA1Z9QJza5", - "baseMint": "2e7yNwrmTgXp9ABUmcPXvFJTSrEVLj4YMyrb4GUM4Pdd", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4aQNmS5oLiP2cLCGHJ4PnDejXrxUFUckG4MLaWoyVkCA", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7MHzNqv5KRSD1B57vBpfx6rksaQJo7yKdxqbBuHTHt4h", - "targetOrders": "J8je8qySy3vpA8tVPW8vtVacvh3o3Ds1FRmujU2h46ar", - "baseVault": "EzChw869GM7TMstHwGk2th7sB5LNWFf62LkyBFUmDe16", - "quoteVault": "7fmqDFEC5gLVJxM1o6oNC8pLDSirgiej8grAjbTV2C7i", - "withdrawQueue": "Ayeu9vgQurs7f9c1bmEc7z8HASoQa5CJ6osSC9BEjMQ8", - "lpVault": "HGumxzchsHm7HGGznCTXLp47MC9UUsrJzRn1Jnuu2DWu", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ABu7F4J8hr751ZwSmY9B52t2hpRSEEJSAEg3eLYVCimV", - "marketAuthority": "HRpCubejfwhDEXPAqPpaKoK3o6k5zmQKt6vbD2LoYgmz", - "marketBaseVault": "6dNsnMcWo3jExJtNyNip6FZ3aJLMuRGcVDpN2Y7BeLWF", - "marketQuoteVault": "7Ss9fArPFDU3BaJjrLPn9TtmCX9hGaDjZHZttKw6nYnH", - "marketBids": "Axm8upGyVYybfuJrYyQAFD1uuLrbdpkQRhHQcK3SVNBA", - "marketAsks": "93ukZhvBDh6HKaWXvdJrQFFdnAACAiie3zQ2pdVTs4NS", - "marketEventQueue": "6GozVi7Vm9BWxvJAyxvt5mddXB8hNxFZpVcgSPoEMDug" - }, - { - "id": "2NuDVoVahZMxKsWUeCPyjBtpUUQLqUkNBQMp26yZsrRi", - "baseMint": "5MMBG43QaiEYsU2ymq5JSXUPLLbmUsLQxMhKpA4jR9X7", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "59fLwou9z2W2H3ehGMX7X5AyHLxYeQaRhnkyB6D5S91k", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "66jyZ9gAptvrito6mzV1BaD52xLXLahFbjF7QPthw2U9", - "targetOrders": "4Z3Dnxg8XyJq8rtY1c6XXe6n1YJDu5QmNS4W3QuiRm4L", - "baseVault": "9WnMMrnKzoMRyXFWjRVSe8A1qCtzjpEVbU4SSKVFb5Qj", - "quoteVault": "Gn3QzTVsuS2GyfV51tEEQWYdpx2mbAKmAwDonYpVTW65", - "withdrawQueue": "6Jdko9UxQQK15Md1Zu69HjnULn7mY2EjcSxgS9Azkg5q", - "lpVault": "J1s1CL7oHiFkUeuVTDK8R8mzRRq25oXPwKKv5mFdG63", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8jbmUeNSu2bLDwaphjqEcdMESVDRArn38kB6MQaFcygc", - "marketAuthority": "HXLv9ysXyz4V6zKTcZg2fn1AQvirSutDaSKpAkhruDHU", - "marketBaseVault": "4Gp3TAAxPy3aPzyjv9va4zYqvcZrRonAyzdaMC9ykS9h", - "marketQuoteVault": "5tLEcbuKwybKC52crRPLjZY5PgbhssdfJgx9wft4TrDT", - "marketBids": "U65ai8Y57MdRVewy1C1s9yq7nr4amV2Non9z6pdhid1", - "marketAsks": "8YpkrZX5AQGkCtzjYeciDsTBj2CVuSFnq5qCz3RhcaKc", - "marketEventQueue": "FrhiLQkhHcAjERKcXsrwKN6BmgmytzU5zDFtipJTUvQ5" - }, - { - "id": "2oEAHaFF8gMDthaunNVJ2xtaXNvpqPF6JfTqV9NTmHjv", - "baseMint": "EchesyfXePKdLtoiZSL8pBe8Myagyy8ZRqsACNCFGnvp", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GZUxVfHxNKJ7139whRstrCXc9M9BbHm8oy4oGfPZCNds", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9ifvEps1h2e1UnefggnKkTmE8GSkZrHyP33wejDJqRRd", - "targetOrders": "B3ec9Bxm7UtgreCfL33FVND8XZhoLLiwK6Ja2x2WkCAr", - "baseVault": "9pR88uQwhxTd3MRtWMgy9CLdVV5ZUrHZfQt1TbRtLshY", - "quoteVault": "HQc3sCU1J6oQnRakgFTPNqz6EvPC4rbcpAysxTTnyRLZ", - "withdrawQueue": "8gwxYoKapjsaMzqgmnCrz7yNtBgzbkFjXZQU4JcS5Hvj", - "lpVault": "CzvkQUP3J4dvURR1Y26sY7aZwSkzmF8jznCuzo3pbYCC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "E14BKBhDWD4EuTkWj1ooZezesGxMW8LPCps4W5PuzZJo", - "marketAuthority": "6QCNAdJywPxW1db9JgS8PpRUxKcTgk6PHXM7pEzGkBG9", - "marketBaseVault": "9orp82njuopbWUzrGH417wvp2mED5h5hJdNGbKLaYxzJ", - "marketQuoteVault": "7YpRpKkjwpTxT42pda4TjPjm2JzMq7ZtfAAB3aQypBQ7", - "marketBids": "32XHCtmXR564sWGMfqiSuSALjZtoCLCtvmdiMfJctEtL", - "marketAsks": "GwUfumrvowPJtQGFQuXYrRPDZCFFPwzuu7V72tjCyi12", - "marketEventQueue": "AfqDqAQaivYTVY5HZdbmvJiGKFHsv4NmdQUfjwyaZ3Fw" - }, - { - "id": "2ogvvoM9BPREvYPhrDtESJiVaqDaCTEZYZHg67RmxtU3", - "baseMint": "6156vEwBw11hGF6rkr3um5RPNWfBCYBFH7XcbEF47erH", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "87er5ySvjW4i9FLcGTZk34dFjnt14bqiC1bZE3DStFPn", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "JA2L8aYxnNdxXKPLqXLqeVp2VsFozg8so3f7KrBY5tha", - "targetOrders": "HSGzazyeag5BXpKgyxdf2QHexCh3QzYqTUDrPvcy1gkm", - "baseVault": "2YaJy23Dx75PSbAYfNXFEVKAKKrgQdyu5Y9vD8j2bE1e", - "quoteVault": "68A6UDEe46qbHGM6bzczDuCYe2597YiFZgaA623b4bFA", - "withdrawQueue": "9isb9USiW82UJSoxLzLP6V9bbWMAeaqAdxeJu774YhSJ", - "lpVault": "DyfPYLFLHQ7WPLvSaWqMYybdtGgzzNEXnTdTvmKkPZS", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "WoH4Gt8CHG6xfMGtyZoYBk27Bu7osZio92Ds6HKmfb5", - "marketAuthority": "3xPmaKdYW5UuVgYsbbUWZwvZs3mzmJxmT5fSwNxrW5du", - "marketBaseVault": "2wUrogGqmRz251kWLtLH9dzvU6J9UcL1DA9dhaDrNghD", - "marketQuoteVault": "7dTr4Mbs7b2hjgvxt4xu4qSo44sFNG6UrJFbtgyBKVWS", - "marketBids": "6gLxfaLd6NTFof52jWS5SzGmitSdLBEwKdGnJL4u9frG", - "marketAsks": "2nMc2ym2h7fT8rdxPtmF66TrfQnGXK8x3b7h7UTcb6eX", - "marketEventQueue": "F9FjpAm7UA6etjfN8cuNCmHVKHqs4pRQa4fdxqdJZFvR" - }, - { - "id": "2oKKVrqW2cZoRkUnM4M5oXUqKZUGi5LioCSQhfYmAgpj", - "baseMint": "GDTVxsG41afjiJngZgFYHJkrG4PkTB9pVx7NuVsm2RcX", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "D6qTJmbxWs4qJPUqGAd3C5ZFkhPKf7r12Rt2RsSGRobv", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CtyQvfhJdAYGvzkCLaDbBLsiiHjb49deDkid4CCAaYo3", - "targetOrders": "HSreBVQ61BuoaqeQmJPKeFt4hb3nQunu6D8zP5U2c6ni", - "baseVault": "9n3aA4tX46PBryLwSWdNCucovR7AZz1x2csuEjg44xAh", - "quoteVault": "CHbPHzzHwfs9kZQzK7bD4vr6mEsQksQuREE76WVPeqkg", - "withdrawQueue": "CXwb7EqnoudihcWSAv2ySSTnyr3EKCrP8EdEuXHuhdza", - "lpVault": "APnAj5ujDXZHA5ip1MmscynXKjrjxzCsEXbEgcUnqqyM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "D55Dh2qDDgtWJ27u4URbhALVA13Xg81TWNYim2GnqX32", - "marketAuthority": "BHgtmd6SxCKWLVYhnUoMbgzhRZGc8V2ZqQQgqrq1aHj8", - "marketBaseVault": "DLC6dBnKD5NbTrEsqrvjZ7sL1sfgpjDFTzBpdLnudioD", - "marketQuoteVault": "5hf4NRP5TKFjCBV6Ri2C5pAUVpCV6kjUr4gimaoPf3tJ", - "marketBids": "FiDMm1ZHVpr94qATdAVvj4VzNpFsYwtJ7kfKuFNhmC8Z", - "marketAsks": "5P8QcbQUprX5hEhYtuGRLuw1Fsp1Wu35QzsUg5rBdsKS", - "marketEventQueue": "Gn2V7UgNJe5DPHpPXVY5Y21WHKenekV2Egn1HFrenyH2" - }, - { - "id": "2p1w1rE2K7TAfVvqqAjBYjtyyJgufBZ24XPL6L2MCLPc", - "baseMint": "32iV3tk9bDgf2nBHVMbD2HgZnv4vccDZhrDrK2eUkmJd", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "9cEc3A2tPZXDa5DkXvpXMANNYik7KHjfnqSMTdhn53Fx", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2XvmyFoc3t6qMkwzwZbRdn8gP5Sv3m4PAjj8Yx2iJRFd", - "targetOrders": "9x6JuGEy6K6stMMYnxUHwv4UkREFE84LSnrpnwJUxWXy", - "baseVault": "6qLchzye5K4RohcYNyfGWKUGbyRvkADe77s9cCiYUQRZ", - "quoteVault": "C65y9zrknX83s3Y1M7X6gi1QYMG7sJmzh5EDUBuxaGB5", - "withdrawQueue": "4vvMtYEGx4AueqFuiRbd7qRbBBkCyYhGnJFGVKHbxBaP", - "lpVault": "9sJErH3deGzeSLQr4dh7kGwdGjNqkFkxhKq7wTE8rnvM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7Bjp7PEU1UgKCNbF9nAmzwbLzKhLVmZgyh2gME2CK5eZ", - "marketAuthority": "AD4PC6DyZpGimHNN8spDjyM34fHu8qBqAmzJZ6N7nnHw", - "marketBaseVault": "ApMLyQ6oanhbZS3YwegVnFicergKQw1d7wJjs7TJNZM6", - "marketQuoteVault": "AcpjrQa6FYX5a1V18ULS6ecqSYQJLtsJcv6RuUbV96zJ", - "marketBids": "GUTV8XHBjRBP8M9x9VX1zLL4t3V6gQpotaXXHcotNy6x", - "marketAsks": "3efbvhhT6dxDwWZkh5aXmsZidMuBZfrZpRFFVPDtriEX", - "marketEventQueue": "zrXWLwR1w88Z7re4uaJFRJzzLAedZ3YU6NnMm7saTai" - }, - { - "id": "2P6Ynjn5cDLCXnWvKDifKnwFErRYGjQr3zdzKghFj8vm", - "baseMint": "E8G4uo2i9d12aGnXDHXXcw6hU2fh2NytR5XR3qurTLBx", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "G8kaXPftJYVCo8Mx8prXPTQvesiLN2F76aLakdn5yndw", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8V8aZwcvWhEqwgQUGngEqfJfaX16Qf5kp8P1ud6K6F7R", - "targetOrders": "5wXcqKzkt8Z6bAT7FrVCmtjZ44D56Jx7rGjuU4XcVGLV", - "baseVault": "Av4NFqynfdUCK2RsnrgEfx1z6kt7om7MuVp97sA6vi74", - "quoteVault": "2LCqomRLAsQNR2jeKBHiYAR4uFa4XjGcz4tcPpYEBPL1", - "withdrawQueue": "FwqFCVJHTx6jEEwZTQLmeGyahYDH8iAX7Xd5uCmAZbxz", - "lpVault": "HWCZNeUX7yPKBK5fBzSNCJpfV2WAchvLXbWwNYnatwdi", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FZF1gAKqZJgMAuWSsvxxQCHUeiyMfTxtpgnza4t1Ze3R", - "marketAuthority": "Gs88MgDWPM1tW7CFGCBSkdnnbigpp4AL4qC6Akp4cmmB", - "marketBaseVault": "F3MAiJtGAqvU2iWLkpNmkqT1moNrJHaimkYoJRyGLr25", - "marketQuoteVault": "5uvYeMpnghECdfJjDydXm8YViGQY7TGBzVBnYGwAHhrZ", - "marketBids": "3hMTKs8XU4S7JTiGnDaBDvEG3JUfEZNnNbDGT4Z9t4uZ", - "marketAsks": "4WdMiUb6JY1D5FM7podZgHiD4pLaKK4Yc9vReFK96Ba1", - "marketEventQueue": "6oASzanHp9JLid8PurjANPLy5wdBMBzLxFVdJcsjttRf" - }, - { - "id": "2QH93qGKcZ7xUhDWgT1iueG8RV5NVWgDoxeq27v9ACuF", - "baseMint": "HovGjrBGTfna4dvg6exkMxXuexB3tUfEZKcut8AWowXj", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "ExkuW75SbEGPm6i4uFv7Rnncd3hY5whirtRPTujC1Yoe", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7jd8C2WotA2sajS7eEu3A5Fqu4CYWX4hC1vuoEpng2y2", - "targetOrders": "DZrrvgyuQDGQavveqDBawoSpi1STyBEi2g2T4aYn62dU", - "baseVault": "EYuycphmRL1X3pC3jLdpDU5Nf4JtQAniEuwXMDCTcN4Z", - "quoteVault": "Fa3MuNpCrJvRPWJyPxW1zkufmcBsFf8K9H2CKWrzFFce", - "withdrawQueue": "DukPPvhXnwKMqXo24ZVnwZVJo2WkuhRAVhz1jLNb3Tit", - "lpVault": "EMoyV9RGsJVs6YhoM4mwvTuoAaZ3Fuw6C7rVooHVZHHc", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GnZuMX8RFGzasx4CoJaTSseGExqdva9KYY4Pw6QpGjS2", - "marketAuthority": "9xmXFeY6hTeRLYAkGTNv4gD1UbBfLd6t8X4e4vhF1231", - "marketBaseVault": "EGu45cCHs5VioQtGTwupUjch9ocoutk7cdHWetWukEP3", - "marketQuoteVault": "9q4kQ2huBuK2Z3UAq52tBAZHcsTzvZhKngtLjfPqSgrj", - "marketBids": "BYjnQtMx1cKVeyUnwi6zD6szUX18snWaC5bDk8JoChHT", - "marketAsks": "4CrWoQatKiQfwvjWFwK9S4q9bc9cigjsvhPnghbnUN64", - "marketEventQueue": "D6F68fT74JVH6jVVggFZbjhvptSgVR5KwSgfJuKwGFSW" - }, - { - "id": "2Qmp9jLU64idYVYrqWy8tiBcnHs7hZhzTgCdxSjsY5JZ", - "baseMint": "2MtPZqwNKTNsBoFCwm4ZTWk3ySz4LSd82ucDGeTk7VNu", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "FmqTSkyR2e3xVWgwpqbv8CeX4Zp3c8HeEHJW9LErZHMU", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7Y3m2ZsvuJCA8RxYU9ufBRwkVii2wHitMpay8fLXuyJ", - "targetOrders": "B8K9WUhSLt6vzvtAjNzG8txpscGHbNja7e51G2Y8aCb1", - "baseVault": "5c9wewWkxS1Khv3uhiARJcFGorWQYsszdmVvJw9xFfGZ", - "quoteVault": "FHy28UYtn7wbU3ZBUTnpDWeurh33Fhfuz9PdkuUM7xhn", - "withdrawQueue": "2e598JFsr4U6xDfYbDzA1ciddTbpcp9456fNkFQ4m2EH", - "lpVault": "AHc4xc8foxE8cCCrSVS6nBZ66W4V2gZrEwPe8JwJs8aS", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9rv5BXWaRvkZBtRCiPskERWUerK888CtJaXNw2fH7QgL", - "marketAuthority": "HA2Q6Q2pBmmb7LksnTeVNjx8WiefE1nJNBRbmnxEha6g", - "marketBaseVault": "HhoqrYHRoLKoRV56X5PVmpv5UuDRz9MwHnu8qjFHdWwN", - "marketQuoteVault": "2yJT4zLEjZsh1fiHYnDNEBEz4uuYd65F3t1zHS1875AJ", - "marketBids": "ATDApyfGh3XCJ3yQYUkZiX48Bo9sz9P1D9e8aGc7BYid", - "marketAsks": "5fzE9iZLKdYrESgTmqPoWWaGCwmKxQkUPXftDaNd5NiV", - "marketEventQueue": "BBQkmRECPLpqXhfMP5xTQCpjSYCDLGBBK9uJgswrQRES" - }, - { - "id": "2R2ZKxUaACazeZqFb1YkJns6t57jMH5L1NoXSbirJnem", - "baseMint": "CCKDRAd4Xwjoovtf2s1duu3d4TPTmFRyh1hfrb3ZUGR2", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9MKjTPhy7NwdAfA6axvr2SR1HmR7fwzuj9u8AQAyMABH", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "A7iLShWKkqTSyvjRGxB8rQQ5nKrUmW1UAo2LDkSfYz5q", - "targetOrders": "kvmCApV9q4bfszmvXATmad4DzcmbXUcG4TLXKoJKFPx", - "baseVault": "JBFZbmVN4Y2pv1uYCactgsEpzGExNP6y8pv37mxp8XKd", - "quoteVault": "3CtuCjHCbJLX2tPBoqU2cmjUuYGsmASYiRDnxc6UfqcD", - "withdrawQueue": "FnbmeZZSX3eqzQxNHB7FSZBCzVPkpfq5EDsQ1gLw87C1", - "lpVault": "5yPV8cDvTA2sNbPuqzBgozN2G2Jz47iG7BsTtr4rUXP6", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BJrKBQoRzbio7qTybSY42uDKq4TjCuGtNAqzh1yHcyko", - "marketAuthority": "BSUFdDbYEuHpRk1KsmAhVKy25mDQXsUGnNGXNrnbynbx", - "marketBaseVault": "7S15EDYaDLBMEpuQ7CDyxeNQ1CdARDLZ8GqTBqM5wpDP", - "marketQuoteVault": "7D8JBfYUZJpBoWBjoT9qkZFJ4wj9rDY2KrhqNuTV8XmZ", - "marketBids": "DgkX1zDH9Gaa2bKcnwcUjkDC8v6EeDRFGVVD3rDgV3Rj", - "marketAsks": "5oY9t1dkJSqrpCMYEVUvDAWmCYRcFxyRLnKtdN8t1vFM", - "marketEventQueue": "6mAxmr1Lf8TERktBska2ffjiUDWi8QGdgLpsfd7r32wW" - }, - { - "id": "2r61zWBnpRN4MRoEZ2S92neYpf3AYBKLRibcAt9PT4uk", - "baseMint": "3ZXVxxX6zCf5Yqeq6iwdTuVwC6E8b7bs2q3D1Prg86sv", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2PWrXGhw4AfzaptjZCxYcnKJ91TmjmzmEd9bNnytkUXd", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3MPsbCDfSGWgHV3PzLxT2XBmQyPyMFrRh2H2AWJAqDV9", - "targetOrders": "BkmMVyXheBcLYhfwPxmEAhcGXMPCnoKtbQRsX47aVUJ3", - "baseVault": "FXVNpXBAh813Ngua7kGCN3wEWBd4Bv5BuhYJVcWXgHpS", - "quoteVault": "G2zUNpkTy1DXjeYDhWLZoo2CcQZDbqnjJHMNsfse36K4", - "withdrawQueue": "9ftQZndKPR87MU2473emffC7Kckbq3PjQfnqshHGAVaB", - "lpVault": "AtJUtGe1k9LmYhSt7NHSPhHqbpXpJgV2p4NHNKKVTsyZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "F1d14QfL4pN5ohUngUpiwTx7Wc7nfU7ekiZZcPzLhbYJ", - "marketAuthority": "9mHvLFaHmiW6PYbfbmePRfjHkRhEq9sxfVVrPAacPzUw", - "marketBaseVault": "6k9q3KLRYppNPmUKHRN6yhKo5KQMJJd3mFtVkKQEgqao", - "marketQuoteVault": "CwwykDgwSNu2vNbNPfTVjGLUBcE5zpYcQZJEpdon6zah", - "marketBids": "Gn817Ua1kRNJcy8Qh4iuNWCGeMk7DLkjsfdX5k4D1EoG", - "marketAsks": "DkYcAhF83pBQxnR2eyVK1XUSBQ81gt619PpYfqY4ieW4", - "marketEventQueue": "5eKNLJSkXAqfzSNvrRfBQSEyLnNaCi5q6K51QYFNvPbT" - }, - { - "id": "2R9rpvmKN9RkqfJtewe3h4SqTwbnDzSeVMGPu9UFNMxy", - "baseMint": "DQgVHoMbCqPkoinGpZey1wsEEjWWx9sSz4f9neNSd5gd", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "ei8JksWJyu32rXXiQ3EozGRAsmVdXhjG4eVnPJPJWeW", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "C8843NBYZQH2jtTroKDHKDAp8JASoog2UdnpNqvcNa12", - "targetOrders": "APe4VnFzhQdj4QwDYsX2uFyEwuUpPJBPkSxtKhsm1i7w", - "baseVault": "CqU37aBP88cM8G1zAA3J2gDDc8JZEHwZjdMQ2eL7sJH5", - "quoteVault": "4dRyyyyRf4GuSUFBrb8eJeUq7NnjwjXULpTy1kvuWyCP", - "withdrawQueue": "DZ4V5iN8TCwQ3VB6CGo7fs8qUPAvGMSu7nUNvRju1mkn", - "lpVault": "5pgqxboxnhc8uUt9DcGVdGcHtPTBZJcizKqpaZ38r4oM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "68BMQGJv381SPXQxPo8vCtV56Kr9TKs7fpZmPns4Exee", - "marketAuthority": "G8NXNQskyjoiff9mr9o9DdCY318egXwHPzGtyhkfjWV2", - "marketBaseVault": "6PgDBWsV16eM33PXsL9XP44XW6RuKVnMGFW4ja89dLhf", - "marketQuoteVault": "5AJdKeb6AetaxyJk3MDFFxj9s4eb5fDqQJyqDgE9HWNF", - "marketBids": "G48KWpcomnSJmWBiEtqXeopxYjXA6hC5wWshfb3rkhR8", - "marketAsks": "FbLCM84Lgibkmo11BJrpZcWK8HTvRTzznUUWXDyuW9iR", - "marketEventQueue": "AyJQz2quBNLbjzSeDfd8xD8GCCmYhu3EwMRDXj9vfseK" - }, - { - "id": "2Re1HmaDTdCFgCFQRRBtzgGQg7gi32hmPEoKegz5gXCX", - "baseMint": "765R1rpPGVZKKJZPevTp5b2dTAHJZNX4feTiHDEqj7JV", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4UAXzqwsxLmsB3kDF4hYsnNSfzbFZSwTwoh8UM2bqmSB", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7rcYeXUySSYR5ArrFpuLtYEcPQonTnHbPzAWRAtXji3P", - "targetOrders": "AkZhs8317Na1SpAynZEN2WQy7haqSzoBmb6C5brk8v3D", - "baseVault": "ErKnPrvXEJGaUEgV7Y43djDeyGpseZLnSLWFopHRyeKN", - "quoteVault": "EDVDNJbe6e1EDTbsBagE5njtVzDaAMZPArYU542GbXaU", - "withdrawQueue": "5N2VoB6hbB72kTQFzQ7PrZ3H36ujJDdTmtYKFQdrKirD", - "lpVault": "DFesjFrjP9EjcLDHzDX8A2mJBK8qhmj1duRr6PRmiomV", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8n1L1eARKm34Wy4fowPPnGAkfQnDgAiwkQ7rc15caZFq", - "marketAuthority": "CeQZC2tey9kV2v6JhGUnDtJvVuvqpNk6LDXnRKbfaLup", - "marketBaseVault": "AYL7CAbKaGPobLghK7TAw8QH8uEWZSHVVJoC4nPkBi8M", - "marketQuoteVault": "AXz8hy5ub6k9n8dKM8fDfwio26cuofWgMCYC6Dono82u", - "marketBids": "9173b7svQCeEhL2nrEUutuKe7wYbvQSpcTD7dhP2KTPb", - "marketAsks": "12sHhA7ZMdLF6iftBzzNuBGe5nmXDDPCoHrQxJ7fkb5U", - "marketEventQueue": "H2L477UTCy61SXL3b3EHyUTAtc1TSP7bCk295KKCGnRD" - }, - { - "id": "2rKcNcyrRKEoqFCvVg2uMyxzNgm6uBXPqEfi1gRz3BtG", - "baseMint": "ZEExktbqMM5ZMS569pCNbzky92KeEmiFeVwR3exfBNn", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8kJ6PTtyP5F4tLy7cNCYvBdHBNtNRP2ioEksYB5KMv6g", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5Z136a1dXFKdc63dxfzSPXx25RSSbjZLXdk5KSy5yeQ9", - "targetOrders": "G8iW6qWPQB8tzXYPt4UvCJgiCYC2ASHMSmN6CYgmuzaM", - "baseVault": "GFSbqS7y8yPB48uhopixUk6AYtdb3Ki4D94vtWajCH3g", - "quoteVault": "fhhTK8FbCP2q6QgxtgdxgkJYdok2AYjmfL9Fwm4rU4S", - "withdrawQueue": "8pkX3mKZfq3KvwDJUbX3xSCFfS7yTK4ZnHdeX9aJpnAN", - "lpVault": "GTk2PLPTLCyQXS53JibvHo4RbcAhxngHkFqkusFpCcfm", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Bok3nWqe9CRQyJNytZkSrJWhk8CWyVZ9AD4AwMwLnqYc", - "marketAuthority": "4DdoLVy7W7txc1s3ssKZBVbTR5k8GkuRjf1e8doCnWQC", - "marketBaseVault": "B4t2UGgQsEfoVVRf2wKBqP7oQDRhVPjFy6BMYszm5m48", - "marketQuoteVault": "FS1HAjVDqnUvUiCYRmTt1KtwNjjgquw9LtvMdAMUco8b", - "marketBids": "HETywHFEe9wUvDZz2LhXEFYyTqUzoVEBVQY6DMqyGvvE", - "marketAsks": "3PteSJ6eyVnPb5u6BDojGiuz2mESzThKUrft6JzvhVMn", - "marketEventQueue": "ARhXXiXVFQGA2ym1Pty6WQcEtozFk1i8an4xrHyGFKCw" - }, - { - "id": "2Rn6LSJhMMzcjes1bzDpaVtw8gFVYtLqUZ4cygRtrUjd", - "baseMint": "4Wk4qLfLEXFTJqH9zn2LBqccorX2K2rjV9UwyujjUByW", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "8RpYYuTUywvtBJuTMxuWJ4sjw51voDABJMVa98b81nXX", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CzhyBUA8YptV7XvMTwmeN5Reu9erQQNiuyZyWzFoMKM8", - "targetOrders": "5M1rbBDFgdxF9QKLMYMraDJmvFpYJEf8257GycFxFFUr", - "baseVault": "7rkp2WFP4nk6Xspj8QxyDyJkfTyVH69NCkZt7EkLoNno", - "quoteVault": "gSCgmh8i6LTyGnrXm7MmY8rf1CRnQB1zMTwBPYye4Cv", - "withdrawQueue": "BdzdauX5ZaDJHbkADxiFWurMzxgcDUHtQGXrr347majy", - "lpVault": "Dh2g7oZyQBDmAQ3DXyDALqug1gYnL4YRe4xBhjmJdSnd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9Ejn4oLjLE93qHuBfEZ635LZqBEaunPKgppmUMZmxfTG", - "marketAuthority": "rVtyoj3byKKsUhMryw9WmbfGMh2cfFNZKgLfqC2t9cX", - "marketBaseVault": "FJuEDN6AcAXoRqG2zpHm95LTHW5VaAXPpyjBDdAsJMvq", - "marketQuoteVault": "CfitXw5iWZ6w6GKM36Nmm1fQKm9PRzQvHupgvfSd24iw", - "marketBids": "8M6th1jMoBfFqkuSdpeZbrq4aSQ1t9QryVN7gvvky7Xc", - "marketAsks": "7BVkeKAB6s99fF56uQWQQnNWc2fv2Sq3EESZaWSaPfH5", - "marketEventQueue": "AYXv3YTSEZUsTxq1RYL5VBX1JB2VaYPrRzXWSpHueNNE" - }, - { - "id": "2S8CC2Ndmg7cm3U4MjU6aRCNUw2VKFBCJtBrAGUBMq1m", - "baseMint": "8KzT4VfvzULfbyAE8PS7qzD3zNv6v2Bb4sKMx2v4Qu8e", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "55GWEnrbSzyZ9Z2GAPQULoCUCyNPxGeRWXEAC75iNWFj", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "C1mhRQ5LPwTWm63qSm8ysqDVg9ZufVSKj4ZGG5Bamd8H", - "targetOrders": "221ob14nprTd9ArV4wkHjFHWZSi3YDf3Nu7K9QrPh3To", - "baseVault": "FEdz8AjQA4kkgTgvz2XmapeT8h2tT14BEuMBcidSSf2P", - "quoteVault": "9mUqcCRgqfoysb5oPCF9RHwSRePMKRFfZ2BB6QdYQEWH", - "withdrawQueue": "CfHbzhe8f14S5zCz1jToErnc5UoPipJrG5v8pWZhtF9u", - "lpVault": "BXzQiMHEZzf15Xv24tKi4Ac3kUNsXdkRKDEudrpzx13D", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4v97J9LjPv4pJq8QgS2zPjC7KQ8ishTFR4wNK47cDSbx", - "marketAuthority": "82EMFAoDQs9BgCZtpAgJnHRgU8jmDYjrr9AvitCTtxSU", - "marketBaseVault": "CwVK3rimPnoM1a6EoXSv3TjPuUS8ry3dStB3GALAKQey", - "marketQuoteVault": "25AKMRJnB2iRYkTJQR2HUChhTfaKybLWoTXuDHZXzFDN", - "marketBids": "8BEr3z7BFxhfvmvcRzhK1C8xYi1wSiAA23gWEE9NRrVs", - "marketAsks": "B5G5HXGZGLcLvey8mexvctFudfcYqWx1ca6CTHp7Lrk8", - "marketEventQueue": "o9khsfnb4z8K5tLWcT2Mfue1xVvmsByXWNcWy3ucovq" - }, - { - "id": "2SJj5J6oYyw5vYWdjwZj3Wb4AFmgBZHAUiNZaL9jcDFy", - "baseMint": "AhDt1FnEt759Tmxwa61E9FQhFnerPwMDTTt7CJjvog7L", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7NPnqjDgkSHFNrWbTna2Zv1FCUZAhWcyWpYo7kDuZvTQ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "NZq95RrUWUNX5UxzXvuLWrb8UHMFd27kCsQbSwbooty", - "targetOrders": "GGLedyiTHYTKntVH3FezWZM2e6NKxmUZJB7P1K915M64", - "baseVault": "DjzNJWzCNy2DGodPiU3gD6BabN9moAuYKDxMkf3isSuD", - "quoteVault": "4ssYazfX75CFL58SR4TNtbnNWtpMpZrTtcd3frSeHfdU", - "withdrawQueue": "29q7wBAPKwaoBcw3EqCVddZDbouLzR1P2fzsmHJRA5xe", - "lpVault": "FXaFuKANa31KbaLT4sQ4LWBkXVAXdbRsj85gEL3UBJKk", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8rnwiK4geGow8ELoy96GamXt9nsmokX5UxAoXVPhS5zy", - "marketAuthority": "6T3rmSsGFPYJcCy6ecfESpLJzJRKjcVvjo4bJFhSwMP6", - "marketBaseVault": "7dHB4D5Kb5GfqAVwdp7BsGgW6gz6MoygDyguYzeEPVNv", - "marketQuoteVault": "5aZ5b9aKRTyhT7pVN7VsWL4bZz2CfUXQh9gtz3aKZ33q", - "marketBids": "6T1fqryWG5ZgwcSHRnqihBthkWoKSatYBqfZsbMouFrS", - "marketAsks": "DNTyAqS5rw7t68DYQqQ4qW6AdckUQZzA9cuKo2r9JwHt", - "marketEventQueue": "2vnQbebeYrroUsVbvYdWLPqoCTe1S5QqR6eiCx9x2Jze" - }, - { - "id": "2sMZ3pQULAW9EtfWqV2LydDSqgjUFBJWGP9jay26tCw8", - "baseMint": "E1CRrNYTykhsJLUEkDEzJJexzCaoJ18fVSfvrHqRYecw", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7WBoV93bUW2ufqcNvLF9vPXk9G6SHV9FkLQx4NJjTy8f", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GhyTAW4bF9rJGB3fU5quinvEJeYznLE3BT1NirvwLSgb", - "targetOrders": "J4cFkPrB9VwV1zxMCf9nqwZXhYeswEH2ze4wHuNymhgy", - "baseVault": "DR9aTYUEYTPhCJ7ybwnN4Bjd7cMY9oibLTgFH4yq8wSb", - "quoteVault": "51oZbLKSvebxWrUo8owERiTRLtNj6JEh6sqNt1e9VCr8", - "withdrawQueue": "9S5piFUc3NHC2Cj2nRTf9onxFk7jLDygFEhzKcAtSxWN", - "lpVault": "2P34VEzf5c5hLAy3nMxNpLE5YjaSy5CuVHaocUyrJCyX", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6vJ4bXCP2gJYf5acAdRd7a4DF1T6JJi7i5cMvKGrULH1", - "marketAuthority": "13hAQEv6sMFVxwLKxMA7SkXztq85D3P4HK5W3PbEmfX", - "marketBaseVault": "HfEewSymsi7kupJy5nC3Uw2ZWP43TJ4BEiY8tXKkAEfL", - "marketQuoteVault": "EW82hY2Q21WE9LipvYGn3yCa4Hp8C7pac7b66joWaczY", - "marketBids": "FsajYvqiExNp89kXmd7VtE5CBd3m1JQjgTTk5er7YaUX", - "marketAsks": "4N8DbZHYBH4NrLztHbjApJKtLD5EYuppQtYjPJqQS6Fd", - "marketEventQueue": "DuvsyVRwwSgkyg8jjPnCZHDRcYCR9AstDWwX63Qo86Qz" - }, - { - "id": "2SnAF4AxQYCjxXAXkzW6QUKB4Xc5DaLKvYcM57r9F3en", - "baseMint": "9m8E1yLHaG1B2TFSNeWahsitQh5yQRnrbyw756HFAcEa", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "9CqkuZGLdCvh2seF5wP1GSzmL4rgxhu4Sj7HJ5F1RpQH", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "yA13LyVtc96HC1t6Ljd3kx31gkdJhLk2VRQx5fh6QzT", - "targetOrders": "F9ohbHCCKj7NnXZCbiW4bBZXJisb2xMvH2Zsc5DGEfiE", - "baseVault": "GYe6dnSJUsmuWDe7d3DGbk1ahTjAmcDAWGRxQer5EQw", - "quoteVault": "G73HFqnQtV4eN5eyEciDJUMBsc9Tj9YGLnm1DNyCZ7Vz", - "withdrawQueue": "FoJTaNDVgZ5NkqU2GMud5M9c7B7UvdgNsZTknZG6FAGH", - "lpVault": "CpUGzKK6A8WFkeRu2qjj7oUpZa3WckNXP8bG6GcvGJzc", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BnfoBqhJZw1P8XE3SmjBeQWCiHumm1qM8eB1kiwksNH7", - "marketAuthority": "4ksemW8WSBJxrXG9i9kWkLUVPLWnDTTCJP24rAA3R52o", - "marketBaseVault": "EJmUJqNXQkHSt74uxd5aBishaP6TNfiyVvCCeLw8wR2k", - "marketQuoteVault": "CvM13AbveKzKLRW37iH2Yz9qrqsL7JSjEL95pBhcpjq5", - "marketBids": "GYMpQuDJ22SsGins4NL5SQJuz1w1sMfxxRend5834hyk", - "marketAsks": "EJ4LsDN26JYLdJVzgvA9oYdTXVgbf9Xuj2TfLBvvS9dA", - "marketEventQueue": "GMa47hbZSiczQmtQy6LreY6w2mTqM1Bz36f2UgrFJ6Hd" - }, - { - "id": "2SqSxxLw8oHoog3otxXpsoUhbvfXTdT8hQzRpWjjpKZg", - "baseMint": "DMCUFm2ZAnSU7UgsdVq23gRogMU3MEBjPgQF1gK53rEn", - "quoteMint": "CZY2dDTb86ARthiLP47hpmEgX1h82XCEr51XWQ5GsZoj", - "lpMint": "8x741F5RzswUuU3SyZz6vHjNV7dgCBa1gRDN2o5yBCbG", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "rPjrwW6CRfos72USZMJ6FbfppuAQpjPPn2MFgDHq2Ph", - "targetOrders": "3h8gbEPtPpEDDLq6uMP2WBRLWwijTv5w4zq7XzzHE4ft", - "baseVault": "GSEc9kZK6XKYxQjVmsk7PteCdaDau2QTSTm4scgRUsBU", - "quoteVault": "4xpmUxEvieChfKJ9RjBxkoAA3jW7MfWigWQo44KUfDQg", - "withdrawQueue": "Bq1ug9zjqrpcTYULKEQzPLzZcMQfgUMueHNHWmTLkXJ1", - "lpVault": "8apiBgUJfNJByCMWerDwKceDLUc8Lk3rkD5aKkvui5Kc", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2nE8p43cpFj6WHwfmTEs44EGH7Yk1XUSjoAJcaJZSNan", - "marketAuthority": "7tLDnvzcaLgYR1CnidJEUk8r9D4mtbMKxQ1bUDbrHM2B", - "marketBaseVault": "Gm73LjfzGBPBtoCMMXWQu8NzB3kgx8QSuJhg3QcxgBGi", - "marketQuoteVault": "8nstqWL6imuYdPxdH3G8KaoF5TFo4ioEJpSbZUhQpCKJ", - "marketBids": "GdBUk7XqTUf7Nor27F8FFSCwGLUF8bSoMMBrYWM4sAPu", - "marketAsks": "B77LpABt4zRihDFjbHWvmQk4HucukrLbhetC9icTXfwg", - "marketEventQueue": "AK78jF8RExWarXQGK5neV1fMCNws12kb76Xf9BJyDQwf" - }, - { - "id": "2SXKrb4tnALbCpcS5tJz9GjgdFsZLmdyZSUkG2dGp4uY", - "baseMint": "GZL4yjPohDShW4RofJ6dEWu2Fv7qEa5mBT7Dpje5hqe7", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "39DzdKbxRrFtS5jHVfSc9Fk6dWi9c3kz9wWNjSjhwoM5", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Br3zcjG4dgrGUB21RNgygS86dcwyUXdfHTfqGDPzhkXZ", - "targetOrders": "8ni5szJVnNajVqyCWHLjzy8mc5nyn8HXEdkrrtbGKWDe", - "baseVault": "FECMRJxPpD3rQtXQAMQkkJzmUPxKpYnMieB626bfjtWM", - "quoteVault": "dnGKaUFEEHZ9yNXMJXA7sS2RyQHi3dfDGwUVihTXnYp", - "withdrawQueue": "33u9txNd7bSmiByxPBRqUfC8ZNvF6GY5ypFHW3zSAzcH", - "lpVault": "BadRJr7HvjMKedFqwKAWghydr8V2JFwFsHNigBiDAGtW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GjWRCJ1UF5x3sF1Q2mjfu7rU22bC9aRYJhA2rowNLekh", - "marketAuthority": "8NU7xx6rq1aChPJBDa1r34G5qMQq5cUSZKmPsDFcE44", - "marketBaseVault": "DVGAXhM64TJwGonpUype83MJSehJ4UjtUfHgew989tgT", - "marketQuoteVault": "9KFMdLA79SBBj1YZSBLgMhDJBffXEhEgk8gEvu4PkeQs", - "marketBids": "9FZSw3uJgCQ2pfSrWa94NtGJiUGEYqKmojin77XA8Bhh", - "marketAsks": "DZEc1PygWAEHecSSjUWXfZkoMLDz7YctpvziesyiBiMZ", - "marketEventQueue": "EX5cafhYrjKGaVdHYPrKCxhFAEGkhpEyosEbxHPAX3cY" - }, - { - "id": "2tgXaoCozFMrAv64H5JoSAxB7ezrXkKkkeLrizspd8st", - "baseMint": "Ek1wxugWrFimo8NExqzYaGDnikEibuUrkEaWEs3z2aTU", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8rwNudXHC1t6cNK7WJQ93Rjua9dQDbkTy3Zp4HgGr1WV", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4CEHxd7dmCuqs69YH8ChrPZngwjTxVZZw6nvViq4t8dA", - "targetOrders": "CA128j4Uwzt7xXPqPrsfr7RvUfDsFc2MrDRQUP9U5YnE", - "baseVault": "7rfPDdi1vkmiZ4AqDc6NYyRGMMLW9wTa8xLvuhMvbhSV", - "quoteVault": "4n1TUdT3ebgfVzkPVSvXABhbxoj3M63jjpRKN3zipFMr", - "withdrawQueue": "Du5eRVLjVvCu3Gy2mAy5e6BZDUeVFuKKhqhXuNBiEvjv", - "lpVault": "GP9c33bf6k161mDtppRJBjEW64KSYsFxLkjBoEt2ihvs", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9QJ7PNuN8Zjfe7BnUfFuCnxrKrnU5tXRe6q26Kzjq23N", - "marketAuthority": "GokgXFZ8iLw82co4bPYYhsKDC3Xh3XzFTpondPMoScVg", - "marketBaseVault": "FmjVyj4qJYGdJtgXEakSDztpCT2hq6Vs1L7iKgj8hdpY", - "marketQuoteVault": "F4Q727ydEoSMw8dJs5wZFb2uvh2qVFv6iyp5UGCMvDuN", - "marketBids": "3xiLp6k798tZKpUYLDJEA8AoXQGCfP69Cf38Q2jvkBSk", - "marketAsks": "ErWhnuZYeNmhURtLKF2TWBFoFRHinjgWtDsGvKseqcEt", - "marketEventQueue": "AS4gdLdm7HfkUBeQ3hHTfikcyTuSibTQTX4NjA1SSGM7" - }, - { - "id": "2tt4EiDVBkexAgkPVm6FuYbCjfwDGF8ShsZEnVciii1u", - "baseMint": "DgHK9mfhMtUwwv54GChRrU54T2Em5cuszq2uMuen1ZVE", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "ELjA8fJHrozt9biqkASZkBAYdsnSEZx4nownYPxoNkUE", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CL2J3xvXwgsCtbFexrCshaewZmYx4Dm1cnk4RD9NL2t4", - "targetOrders": "9twabFNUYwoWyagoWWg3kK6BmzrSYGF1UbHkqWC6yCjT", - "baseVault": "GgAPfU6tiQPmixvKmxsvQ5NHHiVMrAMCVfYBfzkWMiiF", - "quoteVault": "DGKhCB36tnpPZEJoGfwJm9c3r7hvy18Tf8k9DvAiP4Mn", - "withdrawQueue": "J8F6Mnxvbcr946KBGgwNqYztmXfcpYtBLUASUX7cHTkd", - "lpVault": "HHaYfPcEwyNkJDTWPEs7UmAXiFj97fjJUk3aVvDvTFwS", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9MFFsTVgw6gKPZ1rpc6CSJSLaiNAonChcS7zCCMrAwEP", - "marketAuthority": "TjPbYgTQrDRLMPPz4S9SzvYveEkFFFyKKPRWUQ2dPMs", - "marketBaseVault": "HDn92VqRw7zxTrZjU9qoU8RE1EdvczPHqsehDjwAbckd", - "marketQuoteVault": "32sagQ9gbUwMxcRTYuEHyeMAo8ApjfUkKeBSWSA2KkqY", - "marketBids": "C8DXpggi9Jpo3eSEmgFMz5YCPTWSf5xavizwnpWdknE1", - "marketAsks": "3BkxW5QF9tzot77CAh1AJgSU5dRAiHvDw6KQfGw19DgN", - "marketEventQueue": "J4XU6YjGYwT8Jni6VayUZnmsi8KZXCQ6W35QngAAPN9P" - }, - { - "id": "2u7XgttfBzYdSKZJnpZoiTGN7b4ZgVPeH2uBR7Xt7T5q", - "baseMint": "3edUPhBRqprSVdEPheVsFYb34eYPq4xZrYjN6v9fqUrd", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FgwQ52d3rPuJs3qfRXF9CP3T3zx7PRGGyoUdqUbUjvtU", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DdJtZ6vcLVrE8ykKsYpkPc2zTnSPhHuaBBXaFBbxXwzb", - "targetOrders": "E5gSvnRthDtYjpcxRU58BCFx8dZW5F63bKT9LhoD8K6p", - "baseVault": "CNMKLZCyweBAFFVyuwmJYJSzmfGAFwuS7XroJkfjzccP", - "quoteVault": "8f2efLn9duGDwJ1P8KN2PaDimHXSPxwYFHG4z9keJZeG", - "withdrawQueue": "13SuzcF1Ztd5RWfyoDK59SXSqxCbuUQBx2STAd1L6T6D", - "lpVault": "5ZMcV4epe2YtD9FpbJ1pdQf5fcYX3aqBbfLMjL9DnDZo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HcTDWZ2JMM4LrSFUNqbeynfjvrSaS4d93qRHtUfJem9k", - "marketAuthority": "DSWvFYLmhaGpi4qH4TSgiE5aPxkbGrJVUTFsx4vENGWU", - "marketBaseVault": "AHd4TDJ6xqvK5T5QVpDHzM6LsvjDmL4mrY786MzoinD", - "marketQuoteVault": "Gn9vfHiCdJyAEBRodn9hzLmMcW6uMhkdrWKq2HMCwwkv", - "marketBids": "97GaiWg2k7xZRLvSJ43ogTiorF3wTqBsRdWrFcaSZ3Me", - "marketAsks": "F2gKmmmmz5f4AFrTViEPvStpVc3BYxuMK4hrvNyeKGzw", - "marketEventQueue": "9Y5b7VWB5inH9FGciSMr2Du2P3WuoR5EqzGkEfuxsQer" - }, - { - "id": "2uHyor6RsETnR9pyig2uR3M1xRENm1QraxqeRsDEBGXb", - "baseMint": "48FCZmKZw3iJcvuAMMShWRSimJ9DN2BBN4exgRpTp5WG", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8UXqg4uwXPDBwK2CrZr8xo7SGfGTmCanK1BaZzDqMRyi", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BuzD4XHkh8BsohjjaskpMneKtrdkGMhBSvYV93uSZL4q", - "targetOrders": "HazQheyANyqHBHgwTNsFwMYwcrfTPa4pNVPJ5DzEC8bG", - "baseVault": "G9wysfkBJNf6XgQbcFQVv5aF6uQB9vBq6aUj4LvgXHfT", - "quoteVault": "9BjRr4LNguaL9UGLRhx6xzi32oQpourfBKSCc1PzrsC9", - "withdrawQueue": "4frSB888MHs472q36WR3bpNYoXyoy5VR8BPY3xJS1DkD", - "lpVault": "2xrTaUfr1MZfzXE5RMkWmM18NftEyQxVVcg144LjqZQ7", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5SWZF5PpQcMhVDFduXVGApmvdHNPJRhzYEq3EgbtkvkZ", - "marketAuthority": "6GWPpQTquVLeFa6wvCgGfbppJJ6GcUToRFCJ2BGT5DZN", - "marketBaseVault": "6T5crnVYTpFf6d3ifK3rqZV6rDkXkXJTa6GLWGjBQb6w", - "marketQuoteVault": "A9HECvSUiKrvosknbXaGEyhoRReBQrz6tWy85KSczR4E", - "marketBids": "7UFYvaEYW48d5bQLH3E4tBLavH871R4wLWo2hvh7desz", - "marketAsks": "5wSgEjx4mmR7XoVTntWLUism2iwioR8JoTodfVTcDkXH", - "marketEventQueue": "6Xyo3b9HV7YifuQhTRvgDnhkP6qzC8ZdBZnSp9SVgXzL" - }, - { - "id": "2UjFk3rVRgFiynLgrPAERzRcovwv4FmwE8bWg721KMab", - "baseMint": "7JYZmXjHenJxgLUtBxgYsFfoABmWQFA1fW3tHQKUBThV", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BDb6DdPapRpP95eHcFyfRRF2Uq9zWd1FpFpFsYs3erv6", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Cr98c9odpt6ygw9WSKhj3AS9CLAmnGUDcAQ8A2k7dqu3", - "targetOrders": "A9UM89iBkhG4eJdmFXQ4hKKUBWB21UhqerCt9pA7b7kJ", - "baseVault": "78KU9WS8hoEQ6vbhyopjs2xmsKRgfuW62A85pxmrosHM", - "quoteVault": "6vLXCBvgdFtk8mWqmZno5KLgFBArWGLNxpT8SzyJVu3h", - "withdrawQueue": "AMaLCDQfv6LQg8dTVzNW4sEQLmAsLUgVRWXkJmzAzJjM", - "lpVault": "2crpEukxZLL768QwvfVb8ESgqHHGRiB2ELdTMEQFFB3w", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3DEfX1JPAPWKgeBW2XUr7Z1ztNNwbYhhD5EinGC7x1Lf", - "marketAuthority": "837ucL7FsebS5RG3XDStRvBWu4WV35XACeMMNXxhcGBC", - "marketBaseVault": "AjAZfcbZpi5wgP5jqTSBa1vShLMVTmVV8GoJzM7Y3mJx", - "marketQuoteVault": "HEpq4vosXWcFVRtkRRYwNy2Eytoj4NX3Ym9rexgKgaXU", - "marketBids": "sggbHnU5mhpcKxrvnoVSqHHDHfcMhuM2FRGvtLX3YYm", - "marketAsks": "8N9Dh9jub7ZCngGvkfKr9mLFtNqiPUweGwkHoyASJHUG", - "marketEventQueue": "39x6xMGrxiNJWFCGnbsUzt7kA2oXxoG9ctPjZzyFoXyS" - }, - { - "id": "2umHEjDWDo1pvHScYkX13XT3x8tQjvYscamoHSZ34uzb", - "baseMint": "FT84xCFrgRbP39Yo49BiDWRii8ytb1f3rHZtQiDkC7sH", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "EibNpAkyyt534vPW4Nyh3QFZD54bLYm9VhLeCywEvibS", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5kFiGnq5uG1eP4BPsXmpm969SuYgVTLWaznYT5i2YmYR", - "targetOrders": "2xv7bvafRAUQnwFkTBvqjMWQsXCrHPTAuBjp1EawmY5p", - "baseVault": "2XMXxSY2Nw82dNuwe6LE5PLjmw1VWb5duXC787mF49QX", - "quoteVault": "9xaGg9zr7wJApVmyYw9nMmfRBzKmXNfvJASnKxsbGsic", - "withdrawQueue": "C9dU7HR2YzxWR7dbQSMA1bZVgi4RPQH7NtQG4LgXnW1a", - "lpVault": "5WtJW7AFbCHoJkcJdQo1zvpZGhF69ZLhK22ULixk2K8e", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BrCn4tDBsaGzUNkFUeFYP8DTvuSr5TBsxT1RX4EJYoW5", - "marketAuthority": "qH58juWvqwkGeqA1buUsBE7nwAdKP7okP1k42UqZCr1", - "marketBaseVault": "8DuzYkSCTnoL4ka64G93gsjw64meSYfr49EGRTTL168q", - "marketQuoteVault": "svLkZ3d28BhFj3mDXtxqXnkkavwtaiVrw5JXy6zrKKi", - "marketBids": "GmPgJYSW9RebPAyFrehBKR3EkvNxmdD1x9pmxMhqkWsQ", - "marketAsks": "ArGVGDjzGC3WzZh4rot5NVvZErrLBtRZokHZCZjPqQXq", - "marketEventQueue": "D19avKNehCr8zgaXJSqhkHhJ49bungMV8wdr3x5uo43F" - }, - { - "id": "2VyUmhvFsSHG9mmPuMLDfLC3JqsTmPsYPjSqM2DDcMv2", - "baseMint": "F3pemLMio6bVPD9khaqQeCLBsFMzzpePw5vboLHeW35j", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9wy2RSkyxji8Wk4o6Fj1zv9TQZ1mAtAj4iUX5dTpA6vK", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "E2HJfPzXhF9byP8scwKfZ4Rqz8dDVoUSrQmt6QMEyxyE", - "targetOrders": "ByD6fi5c5usV1qaYsFMEAdMvyQEVmtmHT9zXKiyL7L98", - "baseVault": "D257qZnwT7QMc75U3YhKqZBpWUKywgKZqFBcU3Z4nKb1", - "quoteVault": "2J2MRCQuQB86i8vvtU3nzf15L9C6vHgZYq43vfkjjksi", - "withdrawQueue": "2ZDN6ApPiVLPUrxNL2SDCjBHceBUrt3kXe84Tnh8sVLs", - "lpVault": "uGw4Hhk1WXzLST2NrhfQeAssge3znsqJa3m3Wjhh3Yv", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "C32UCTif7VV6ERMHSrh3sN8GyQWXHMcVvXRT38qfBtWY", - "marketAuthority": "FF7XqqjqD4TM68H3bxaJraywCB32JmRXVrqRD4EnDPC7", - "marketBaseVault": "CWcQTNq1LAtkYfjKK7mXnSFVmWtnAn7hsppUvh9heuDu", - "marketQuoteVault": "6enjJUWKCCMiqLe8MvFTg3yw5pLUBgexY61nmiF3dSrb", - "marketBids": "Ahbmh16XADsuSPEZC3sao7E4R2JZneQzo7DZLPBbTU8k", - "marketAsks": "FVS6b3yjPZy7WpaZgvAwpK3gqseAgfujgr1xUejPSeQX", - "marketEventQueue": "BpUPgKwJPx87cBJWJXzgSckW2ART7N29mKnyTtr9DyW" - }, - { - "id": "2wbnvtStBTRRGJhCAwpLSWxrUrfRL4H2FTsujseALsm1", - "baseMint": "SHDWyBxihqiCj6YekG2GUr7wqKLeLAMK1gHZck9pL6y", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BeSq84RRsqQMKonw89mfYDg2dBcVc52LGN3zG6muFczu", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CvoqF36AkXohuz2SuwL6VgqnSoh8ugFAL9ysQhTTKhkR", - "targetOrders": "5WGbb3XXviH3TEHvipHix2AKT5sABeY4etet6mjsfisy", - "baseVault": "EtFcFogovBJsXKuN5qPemF7U4RBdvzVmSLUzvXdU5PX6", - "quoteVault": "Eud3SpedWUCgJBKG7XXKqX8rTRgNAk9mrH5tsM4GSyMs", - "withdrawQueue": "MScJaqBkWJjuSyuffDbV2t1eJPgNeEAjxvP6D2E6pNp", - "lpVault": "22GzeGfrhL5Py29vFzZE9M7VUgCEPTNzPgjZcf4eK3hc", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CVJVpXU9xksCt2uSduVDrrqVw6fLZCAtNusuqLKc5DhW", - "marketAuthority": "GpthK93KvWgQddsBUpuhJcLRxNn5XpEUx9omSUTjtBjV", - "marketBaseVault": "F3cScQ9u1EGLVGJwuHWxT5RG2ivQFTxLvPqRwjnKxAU6", - "marketQuoteVault": "2baMnjbNw7cTarrJPnaWckxv28RyVMbZRUoL4aGUmVzA", - "marketBids": "ESw1WkUB1rdifrK5UQwGFD1YtHhrZ1NzahGjh6PJ95Ps", - "marketAsks": "Hf4siFCMfhWnjSBtEHi7Y8edfLseGzdSuvJ9KKPEr8Tq", - "marketEventQueue": "8aChPdbQ5puSnVV5TLGy38RJCRu7EkjkdmAGGnyfESgP" - }, - { - "id": "2WBrRy7bgQwcBww6tBpJSG9FgJWptmzqvuCwXVg39opq", - "baseMint": "EqWCKXfs3x47uVosDpTRgFniThL9Y8iCztJaapxbEaVX", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "51evw78SRmnQUxDFBzXbWrFwrpKBgFpCJfMMo8ZZgdat", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HtzxwjNx9PgoSJQgcTNyFbEKuPkQdRfgyUPNAVHTEWYD", - "targetOrders": "DMSdr32AmRppc3bwBnfd3L236RJLnetFSTVYD3JWWCgB", - "baseVault": "Av1DJ6x88ygBbkKSakp4SqpEeq3R6jtRWk6v9NME4AVv", - "quoteVault": "CeHgmokEaLDrZWP9LpfBsBCXes2q2guT5NwTVgPpmBDx", - "withdrawQueue": "2FoWUBeok3X8VTNjaWjN7yswj8F1QPtYibUJaeFsjPjP", - "lpVault": "5aKq3yqdmGUvDAoEoZVLzqyMar2JN1E3z9VyWvvti4vj", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "35tV8UsHH8FnSAi3YFRrgCu4K9tb883wKnAXpnihot5r", - "marketAuthority": "Huwbj5Lp9WrEbjrtmCSkr1vxzMwgRRf53MyYLdDAijWd", - "marketBaseVault": "AYL32Pwo3FMiussnJhtMwgBGEaZwEX4fKRYgLiVvvFz2", - "marketQuoteVault": "HXxEBpBizVwVPGfUwmxT26LuswR5aPkekYapzVEZ1ayu", - "marketBids": "CQid22KsYV4JBFLXy9tWmbZo2fnSen1SnpbgNGXUskQy", - "marketAsks": "4cauJaD91DkWUDDpciDDPNg7hyjZnHKhb35P3LoPnzVe", - "marketEventQueue": "7SC5s8iWiAhSRZuc2MqPtGqhfKUa25GttJkvMt9RAVCx" - }, - { - "id": "2wEJ4pdy1qeZjMFG2bVLkk6WFwMTMafSvxgD7zLkjAPo", - "baseMint": "A5UevXJdphkzXhRtTXj8JyoYYrWnkCLHVS986JHtRLyj", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3yirfK4d3Gmk3PAtUYhqDUSrBcpGN1Hf8yoD4CShdoqL", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CcC7qbR3vT7AQGKFNjcTueKCW8ZRkecQPvzMBwsNFFjY", - "targetOrders": "5r1FVMt8iX7S3gSJCmTVW4Gs6BgwTm33q8smHLDddoZL", - "baseVault": "C1BE7U7oiRsHxteX14WhEAhDJm8qyfWPGKBsVMCvEsZc", - "quoteVault": "8433tDvur1NSTVeCtL1eSwvHuwus2Lc6hc5woeojaiqG", - "withdrawQueue": "ARgSsPqNJUm4HtDHGdknzvYeEqsByu6KNtBpeBP524DP", - "lpVault": "GmzCnRYvNLsR2Eatk4UcLVmRwmD3UwtLaNf5rXZWU4AR", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Bd2kNuq1tCiRNCMFRRcWt5EdeUK4Lvf8ufjSdzjyqegq", - "marketAuthority": "AzjEQDdU8owv44sxZGYFjo6FBPNVcg9oBShPspfrSiop", - "marketBaseVault": "2by2STL5A6A3Pdnh81rPMZnJRHZ7FDtTC8M5hAQtqUyr", - "marketQuoteVault": "EiouVJs3DPfpB7wkFxtMCPDj6ByEevyFNwuAApFarMey", - "marketBids": "1f1iCXPDGPsicWH6qfMzRQRCwUEXgfnb8yCXkQN9AUT", - "marketAsks": "6JC26BfZvf7YKbJV88VBTw9WtM6aRZVpJSWx9AfW1FqC", - "marketEventQueue": "4szbKefzvNRNfEkQ9A526Q25jpFgetNBonvoHma3f74Q" - }, - { - "id": "2WvNNTr6qN5p5NAGE1R7hHvFYzxTVV7cWrSo7TmimzdM", - "baseMint": "D6xt2imesfZ1zL57o72BBzjaDs91Q72kgoSGC6qpXY9T", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4NHozYpssq8m2kaf1Tkc7j7oMgx4k31zRLiDTRWTQqHU", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "J75M2FiwkScMYpT2UDn3fQeFq6oXuZMT2JVFmrHceshB", - "targetOrders": "BFaZTWQzESohuhCCpcxTmts2aybvqfuhbAPy15pxAr3k", - "baseVault": "J9yfjNaHAVYLdKKEx9EAPpWAZqA4WFUP2QMQzntPCEGt", - "quoteVault": "3RTUyNzjxdPDnZAt9SqR28Y43ExgzFwttxiD41PSV9Vq", - "withdrawQueue": "Gr3oBBzKsmCfkjZkYG7YZLqTemFuMjkLoKatYs94zmWH", - "lpVault": "HEqM9xVYNBzMSgev6vX42nvwn32UrY2syp6bTGTDrNqT", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "84dN1W4wL1T6gRkDWx5ichN8PfFE3wdmoTqme8MP84Bc", - "marketAuthority": "G3J3UexLSnw5Gij3V53ry9S3LSLm7YryFaVZgQrPXrDH", - "marketBaseVault": "BVKX6MJ5BWZ4RX7JuJg3vWHMT1mC3u4p5sWUtF94AJDb", - "marketQuoteVault": "3wtgKb1U2L4Yg67nNgUruUxER6QbDE8uYsU1brcrW1Cz", - "marketBids": "4ofc3MqkyoRWjwvdBPMRbn3B4smSQ9jzcCopeHqyAHrQ", - "marketAsks": "C5k8NEKBhVj8CW3AYG3RsACzdLddw3TjASefzeDqnBMh", - "marketEventQueue": "BFw41EVT15FVijtutTtay7RdwVx7CSppH6kowCXQfMVQ" - }, - { - "id": "2xDCZgRc66rkdTa26b2B4sGY5RwoowKnaxnPFkbzaB6w", - "baseMint": "GHKQF6bPUrPxLH3AyYm6z3dcJ5XukJuAAcLWthqdsvQx", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "B4VyFNBh4g16VCxUDSkQgCLTo5ZiUrybYLgxQaXgv2rr", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "95yVKZNBcrvNUwYbeedbRzfxqaEkGAovdrNiSbi8QeMb", - "targetOrders": "CmhJUtAuhEAXUVGB8q7L2ceaU4JqV4Q5VnEK8796aXk7", - "baseVault": "ANUYtYuwwwUKiDtU2b1EhE4eu79mxVe85udacfcx75eE", - "quoteVault": "B4pnhAkr5YDcMX2fiZSBjBRMmZE3PNEWG8wdWdYBohCa", - "withdrawQueue": "4aCQ1xcjJoM57nkcHLoRXmHJyVfN2R5t1bsmYMBV65e7", - "lpVault": "4LDNixRVV9VCM9PDmS4imUhN2WrtZuS6bmbbhoJRiH6U", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EshnVcNDxjLJ9CFHyGkxkVsRTKmhidKttMjaaYetmPV5", - "marketAuthority": "G2H3wB2RrzEqGhcqZ7JDsPFSWj62WtDyJr9wNVopmDNg", - "marketBaseVault": "BPBUcfPkuE4BhwLBQjS8RkJPvm7nCoJr374VaTsERKiX", - "marketQuoteVault": "8nV3xywFkt5YzunYnikp6NgGWkemF4VgSgjmjoXtZMC7", - "marketBids": "FFThbcRycvrjL5aWq4mF8BsJo7GFCA6YhK4xX3USfjcm", - "marketAsks": "4iARn4zJkBEL1euEwyj2kuedzGoyW714hgCVe6cmqghp", - "marketEventQueue": "HU6Pbu8T43UDMU2y94FEETNpViQq6QCnP6Tp58uBjNgU" - }, - { - "id": "2xEA6WBGhEZpTGARG87rMnGqiisbsdkhMi34ZKW3ncH1", - "baseMint": "AvqXZn96KzSzYVHBvUkUQSrA11h3ZNtuX18g3QuJuQSG", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DEnUZthUdZdbmF2YabBq6TQLD73BYdUvTJgohSuajkJf", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3pSsPaAy99XEUchabQKjButjtN8xUEkV6bJPRdGNoQR1", - "targetOrders": "BSuwCTXJhgbv73sSYBFA5U3rTG8jkKejDCbCh2xzBVtU", - "baseVault": "HwbMB2DQVXi5BhFzzHhvAQm7zrctD42ApYLbtjWtdfNY", - "quoteVault": "6DTGE4oGfQHcmJpGJqT3i8jvwz46T2QSgFbRxz4mkGz9", - "withdrawQueue": "5CzCHCdMGwEX7en41RhNZQ2f5GZPggHWwKjairMtk3qV", - "lpVault": "Duh8Jgvxsg2HMPrxMGV4ypj2XzaLUnBTzDRuhwex2u7S", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5NZ8bY5deVtYKGhyYmNut6TMdEnoHNUpKy51teyUkUqo", - "marketAuthority": "37utEPfUHXGLheCnCjTvroHcpLZnRmWQ9RnWVHUFuMYt", - "marketBaseVault": "9EM9Q6jhSNsUKKoV4aoM5FuTJkZ7VKNEceejguG8KxMS", - "marketQuoteVault": "ACh1DF9q1wRg6VmWZinuw26b2svY1oiAYsWW29Hpoo1e", - "marketBids": "6zDYcg7mmd8LES5Tu6yWJBePTvrE1f1PtZdNNLc4sJ2q", - "marketAsks": "GDNXN5jX6SaYm8kfEKPYkAFLEVWBReBKZAJ7WUTeTz9B", - "marketEventQueue": "24KZ7Er4NiRSxSAJtNFG9bWX425QM1Stmob2opf4Kumn" - }, - { - "id": "2XKWGM4Uvv3AGBgqYWv5iA4GbwoEjh9ajSGVKjTQKgJK", - "baseMint": "5EbpXhW7t8ypBF3Q1X7odFaHjuh7XJfCohXR3VYAW32i", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "CFMf9kTzMZFP1CwVj5EX1BfHMUCjXcJVp3Ztc3dSt4kS", - "baseDecimals": 3, - "quoteDecimals": 6, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3bREUD52ZAn9hdLtjHjtktzYAVr5C2WwoxXWpHsfLY6L", - "targetOrders": "2UQ2PYtE2Bb31TJLJQLHsC6hSTwDr2H3s6LhKXHcB2BA", - "baseVault": "AuT4MRNnMWQ1utY8ozP96MHFWKLaJHeoii2xaAoJFxuJ", - "quoteVault": "Ckac71cAAKa3W8JSdqN9xTpnyTCg42auqzDeCXzLbqZF", - "withdrawQueue": "7jYddrNLyWKy8mm6KMKR6DZCVacM2YgErEwZBfootrUW", - "lpVault": "GuGpoYbxspXxZmxRGKYQTNXeNSaunHhizUSA9aySutpa", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6JZge6qaTTxCguazAgMaQCpEVBfEoZzSLxELSF8uoPPv", - "marketAuthority": "7b5TkoZrLAPJ52ozHQJXGsiZhG9tdAKQSLoTxKrVX7fE", - "marketBaseVault": "DBLpMLjpiGcePKo82pbTyr6r6BT6Afmu1my3QmJRpTsi", - "marketQuoteVault": "6KsU2EH4HfzFbX6tNwKBH8G9mwS2D6NgJsS69obWCUPk", - "marketBids": "7UNKEtUei7gGReXHAMg7baFdgsvM7UAQdszuu3HH3mq8", - "marketAsks": "LVFdmLHUWkvQSPquDqAJs55Fb5v8ABo1NUVR73akzLS", - "marketEventQueue": "5d47PR49DaBSjFKFfjc4yCMWcWYQ2eoDfQjyE1hRPSAo" - }, - { - "id": "2XTxBjRCPZ3rek6VHQvQpfrDtn79runcr1QhaoK4MRon", - "baseMint": "AGkFkKgXUEP7ZXazza5a25bSKbz5dDpgafPhqywuQnpf", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "2eENRqXRDxa1ZJkhkpXQCE8KZUwewSfgqpdr6soaW9rN", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9ghMdzj2oejU3DnrKhtN2HP1FQEmi8gqezSMieJj8vbj", - "targetOrders": "6tz9qMKaV2i2irSUake3FGPQWvdXnanVek9YADuSKuGT", - "baseVault": "9ECwTkPJT74Wy9pRmDhTtrikX2az3B1ujEqtzqxNzwN9", - "quoteVault": "DYAVjfAaAt66xrVdbDDKY36gFFv6YQupwFibBJ1ET7HW", - "withdrawQueue": "6xtpXhttBf3AwMX5vvsfG8qhiCQzAGM4YokgGriNze35", - "lpVault": "2RJfp8XLiubu6WYeXDMmsN8yN9Cphk2H8bjWcgG8uc6U", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DbVTo7vZQz84zosY2yfytQK8tDbf9ofRNkgKepQcjNhZ", - "marketAuthority": "6FDcWzfJxQu7vP3nWKWRcfnt5dU7dcBfHosGFBGVozNF", - "marketBaseVault": "42N2UEuTXJf44UrFgyqqMu9cH6qdeCnhSdnuYNMrqWV4", - "marketQuoteVault": "C1G88vdwjQxUibJbx2KHUPDYtFWZu7rT1GL57mZ5RR8w", - "marketBids": "DjFZqyKf2KditCA5ixK8LhC5AQa6ryKZzLH4weiXKy86", - "marketAsks": "CYqGzK7WLDgxaxnmuwfpLmBTBsGs6vUi5pfBPnVxgSVZ", - "marketEventQueue": "CLFAtTtGSCkmtCN992zfcyZvjDkNNUriGpLR7D87iHjc" - }, - { - "id": "2Y9HhKwNyn418Mz6qYBYgq7QvuwydxyTL5GqE8j1jasc", - "baseMint": "3CKQgrcvwhvFqVXXxLTb1u262nh26SJ3uutkSCTtbZxH", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4Aewt1hxPDYTZTMRkc1qD3hvooKu8WtsQMwgSDg4im1Z", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Few9jqxBkKhAVyLUhvwMHyjLAhAhyH6VC2Ck25d644mi", - "targetOrders": "5bsv6nyVepMaAu2TvTQrv3eGzSTZfPKoCRxsg9MXvM1b", - "baseVault": "75sLEuRcEMW7XGG4T62TMyNu8Z9brGWL3BXwg6ehVM5n", - "quoteVault": "68KBM5UwMk8ZANv8PUkpWShfjMRPrwaQ6TTA1EinA5fQ", - "withdrawQueue": "AuNLC1PngmFEVacMwir2Qeu4JWZkiXzD5te5sQ33uscQ", - "lpVault": "2vkn3MgwgJJEtrgAeVepBRjURVxk7ohodSFVoddYEERb", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5CiYXLTk9TZ9Vt8Tktehi5rXkQz16j4TsWXs4wpM51Ka", - "marketAuthority": "ApghAXNh6r4hxUYD1VJpNEUWqRyqgYoCnKCg9Nyk7iKc", - "marketBaseVault": "2ohya49W7EMS1QFnVGRF965RM6BiYiYD3ZAp1LjZVg3f", - "marketQuoteVault": "G998DwfkDmwm3tvT6BhxPXt35QhAsqcK8JvTMsjwtCsL", - "marketBids": "FLfrivTNTKFDSSt4B4cs4GjLtjg6zPueQwFva1h5TUDZ", - "marketAsks": "89CR1Epp5CVjN6pjuKFiu6YfB4hzDwCC6nt8Q63nkayY", - "marketEventQueue": "CBbYZRcoTe2T6bkJL56ouU1DSjQ7t8r9WCYAz7xykgXc" - }, - { - "id": "2yg3bypqqEEFJ7sK4os1qiF3pN88zB1Tp8YjHxR3oaAn", - "baseMint": "DktNJUJAWJyeLw3ykCkFNpGohE24SoEhevKBskRi6P1y", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "A8dRrwLWTFgz5jtsEYpfMkNKdZdLEpiAeKgtYGYty3Us", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Hx9dQkFSoAHGRsQ7FUeBLZkKsDwprWEriT78LKFurz3D", - "targetOrders": "6a5UyLmV4VKmV7MLpe4LqvgBUaLqnjKvswQUzYzW2Tah", - "baseVault": "41Si14HVz1sj2i3RDeaGLW2zy1XLfkhy42m2QUC3K78m", - "quoteVault": "2TJEbUnH6GBQwXeM7hNLCxa5FFJZG85wp3ZMDmHHcHKx", - "withdrawQueue": "4UNyczDWotgZoyC6oCcjpUCZRMvfkEMCEVVjSbRyzCqF", - "lpVault": "4cP6S3w3tZS7z5Q6EYksdWdTQbTnL7UipZiD2qcUCXgs", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4fxxwaq6yRna6cKVvyQt1EfZaT1oS7WzncCXaXMXS61X", - "marketAuthority": "81NsVsWmANa8Jn8Bh4myKrXVy3oJEMpcCE9Zd8kAVCeK", - "marketBaseVault": "FSovMbcgc7zuySMojU6aLjnxe8VshYjPEwL3b5jdbAde", - "marketQuoteVault": "GV79193qabmy4DakNG4M1aq3MxfPgcRwk1Uh2iGB3oVX", - "marketBids": "8SQV81KuCMKWe9njrWnma8ssVPhsqFCtQ1gu72F7KVBH", - "marketAsks": "41J24Y1U2G7pozKZYV6hFgpDBPvr9cxtU5c7U55Wqbyj", - "marketEventQueue": "4tdAVxtEyA2yq1LJFJLY1FWsnDKsBP6BfoTLm3MFd2fj" - }, - { - "id": "2YknJnmcpNxhKwCmjAU9Pazpwf6wkfaWgLGaajcZSxiy", - "baseMint": "DH5KjPM53i7NMj69CEZ6FiF82ipbgz1U6QzNfQNY87Pr", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5SVSkdthcorVkRFx2D3HeQQcDvjg6wuEXPxCYdpKkZDH", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3n58rTGeoBrRgQHpE9UMR1LRtXmEits26o3Q9wnfcTAp", - "targetOrders": "7ejjyreWp4Cz3fnEbv4woLLN7okg6VUzT31zAkZQBXtz", - "baseVault": "9E3tw2xtVfRZLNd3sU5pU1Rtj3UYs1ADqBGpWk2ALPaD", - "quoteVault": "DMHbguAq3oiNkEkbbspqgC1QNDEsuh761iypURndDZLV", - "withdrawQueue": "HeMTANWAXAz6ooDnzx51DxvvnmQYPPEN7P7A3QGyJqBF", - "lpVault": "ESryQ1ftfZ8rjhZvPaX5ahgeR8VFuHHYxFSfaEzB1RDR", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GnFSvog1qSV17LQHzCnSWwBxkyVSxucnx8bYu4sy3c4k", - "marketAuthority": "7EzUrLTkDEQCj7Lqvf2afEYqP7YR6e1pNhi5VJwhB4f1", - "marketBaseVault": "HfcEqVAmRb5Zm7uZ4D2DjXiPe9g7RsweDA6HMDJXmV39", - "marketQuoteVault": "oqtkdRCUCtJ8dtadLnuYdW2dbqx82uH59HvLNABF2k3", - "marketBids": "2HinT9V4CzVuTAK1nUo4MYpeCfzzPGPxMrwGcEagbtQu", - "marketAsks": "GbqgD684JM79CgTTg4g35ZzmrorexKbebGugueTmW4Zu", - "marketEventQueue": "FpkagfQptrWqh9R1TEdzKkxYBAUuRqEnWsXsk89U99X3" - }, - { - "id": "2ytC7vUj2zHj96759k3U96Yp1qauvnizUBfXz2pT8b9Q", - "baseMint": "GpQLC7KnNgAvEpamfWi1AWFdXECZ1eQetvFYTuETLZC7", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "5FtWN1QSCRFCrfB3UodrpatmNh6tEGuyhwuEXMqntAvt", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8MTHKV8xMAyRdT7QGbnap3sVYkxvEPuhK3Wmzcp1qDgW", - "targetOrders": "7fSRjjo293CDmZYWvqWtBo1HeJEHXw9HdSZVXjtoTESz", - "baseVault": "GvVLViuisXRvfZmf7CFj8zqb5nBp8dZodHJxULr6TuZ3", - "quoteVault": "CBXeXeD8aAWcN6kbUFZQAEGJYfQ8M396PRywG73Jj8cv", - "withdrawQueue": "4XWAYk72a6iL6VW3PRrfbvjXcCCdUCCJr3fyUANy7Bgz", - "lpVault": "3tdUiwrLPjkgwwv3oGnsEG9zh2GEWwZPbaL39rdFk2uT", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DJubAM51YLZ1h88udQhwgVPqKRfojuQP1DPmGVL3EUGb", - "marketAuthority": "8uks5cWVdfNbBBfMX1EHw5Kjm95WZ4Xo3yVq1mf9AWi6", - "marketBaseVault": "3GGutd4GrEF5C1r3AyFYdMsJUadc7QA7E5nTkv2CiuoX", - "marketQuoteVault": "3s9Vy62sxUWzkuqzfRfujLnbzNTy76421sTSVx8Z8QpE", - "marketBids": "5SdPGc5cG5Wyq6HtcVJWfTEDV6VgE6TqPXNjQ6Xk3XXt", - "marketAsks": "3peggY259rFBoMtvnm12jYbgFpugnC7StPYGjJ81tTr7", - "marketEventQueue": "BinwQiUXiRtSkLdHrLhMcp74oTbyGz2qn4SYd5AetNt6" - }, - { - "id": "2zCDV9nCiUfKw8dSv9ThAkvjRTTR3zeAM7VDeatZDC12", - "baseMint": "2ZamLCGLPSpP2MRbeM2wXRWzTEDhr669cFycVWgzBixi", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FwFB8ShFUZjx7XEjvq6JyDtJV68ftHbGagnKBW9Fx5jZ", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3qd34QD3dUmde5B5upgrLs3y4xWctQteBfjqcX4p2VqG", - "targetOrders": "Dc2ML4JtcrakaoCQYvxtd5kzZ8cMQPutnCWcLGFQ19zJ", - "baseVault": "47h6TRGY2Uruz4YRpaHDq9hvL9qKUFsQqfmFpeJCCbTb", - "quoteVault": "H44yEaDWqJcSL1upM5HuScWUTQtQpNhZpJ3ZLejyNzGX", - "withdrawQueue": "FS2u6cSt4YbN41FXYaiHPhjnwXDUQEjpxKLkzYUdcJK5", - "lpVault": "3cSKVe4FKeUX28RdMzxERRPqztPWDXquWbCXMTLzG4md", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EiWwBvsadsKjPPVbvpQYzpbZd9YXbcTNjg7oQUFfmEhJ", - "marketAuthority": "4QWXYBCd2zq91sZJJimuW4BJbc3f9SJYHR2ksXXhPYZx", - "marketBaseVault": "6hUB3iqPW9Y7xXSXDE2aBPWUDyJr2tux93WiZFFAnDPz", - "marketQuoteVault": "8qtCcuo4fdpDSDBH8M4x2vW567e85gmiv2DW2V3RUSbT", - "marketBids": "45jnNDzBJ6VYH6comLDPnw5HQ43u6QQYni1MASUZ7XpL", - "marketAsks": "e1fjLyhkzmWgyNejBgC48HTkoZsTeEFVKvwdpnJkzoG", - "marketEventQueue": "4fNY8enSNP6sYaiW1a9HPuT66WshR45USLpTevgwNzMd" - }, - { - "id": "2ZSXjTj5FzMWk53yncX5pHBxacukwutxCL6BDj36T846", - "baseMint": "So11111111111111111111111111111111111111112", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "F9odmy7mjagTwTCVnM57yN7sjtrg7U7RhCTWTi9qj9KQ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "58AfakgLY6Km8MK1egqccaXAABUccYrFBVZxujWzqZmg", - "targetOrders": "BTz1bgrRTnhkvzo1aTCNmKmu7twChhDyD2NHyUxdAVcD", - "baseVault": "2f8hBWiRCWTkQTq43HoMyNQJcv1TNLQniFqLcQAsmW2U", - "quoteVault": "GuRc2Xu7fAZFgP9uiKStfDd9o5yjChcMz6hwpzJHdt42", - "withdrawQueue": "7GbsK2wV2U3EVXWiVPt4bHwWsYdu5BMkbtZ2QM8QTvZh", - "lpVault": "DtESBze4uFUiikzfCh9DKci7UU5SgQQ26ajvo8mzX1Ve", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "marketAuthority": "CzZAjoEqA6sjqtaiZiPqDkmxG6UuZWxwRWCenbBMc8Xz", - "marketBaseVault": "29cTsXahEoEBwbHwVc59jToybFpagbBMV6Lh45pWEmiK", - "marketQuoteVault": "EJwyNJJPbHH4pboWQf1NxegoypuY48umbfkhyfPew4E", - "marketBids": "2juozaawVqhQHfYZ9HNcs66sPatFHSHeKG5LsTbrS2Dn", - "marketAsks": "ANXcuziKhxusxtthGxPxywY7FLRtmmCwFWDmU5eBDLdH", - "marketEventQueue": "GR363LDmwe25NZQMGtD2uvsiX66FzYByeQLcNFr596FK" - }, - { - "id": "311e9umdWkd2BF7NHGEM17PFQ7SwFsCjfda9Zjja4CfE", - "baseMint": "5VQnKaTu522jRQyaawDNBKZjBa5SZoeetyDXEwocYxXN", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2oqRWmDV1rJMqXz6pH42CvH5Uz5PpiEjSAMEyXqGYNEv", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3e8E7XCUNZUe5m2fDPjMwymmxKaevwbCGVdNDggzy5G1", - "targetOrders": "9vg3VkkXmzfDtLpaxnrDtz4WCzvtbdMywyzfjiEgrguU", - "baseVault": "CNiKEgUTXifUAJ9cduHVcVPDCYynZXxx7Kd5Kyr2qnta", - "quoteVault": "DoMQPa3VhGVtZyZXdn4zTvwYfrWKbATLjdvUzShUgWho", - "withdrawQueue": "89fCpx5gz8kE2ufhCdEwdsBcU5vEH1DMDBvErHep6tKL", - "lpVault": "9TR6mCDXwwjrsj1imA59EDFizhAajioL7dbe36FjCPtX", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2HbCDH85DyVpn7fsC5Q1GzGSP8TfbNYSJzARE5sC3iCT", - "marketAuthority": "BX68G9V7G32MmwzR44VWrdfw7No1a26W2tgcYFYHLe2S", - "marketBaseVault": "4RR3qhrcZdFZyHCP5XHj1dhU28TmnwDPGw5NKq37nEtv", - "marketQuoteVault": "2ej865cBAaiksyPH8foWSTdtG3or2MdrVcGMe2T2WgFc", - "marketBids": "6MVehMwsNkgwvmxPGat4hMisv3tAcF3CmNRGEjGBJFWd", - "marketAsks": "F2EPcohrnsFo2twehkbKMZoxCzbryQCkdCzDDWRNgHeJ", - "marketEventQueue": "DBtvEwHuVoQFNDZzWdVLAjJVWJJM6KwvjDggBE3vB83w" - }, - { - "id": "32hp19E1teTE4WnTJngXeczuorSY4qoPYNP75E7EHFQ6", - "baseMint": "56tNQ29XBrbovm5K5SThuQatjCy92w2wKUaUeQ8WCD9g", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "59SgykotTbPs3dr2TKJw3a6Xh9imiBj5tpqcKGw64SVH", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "B5JbLmbMVhcNKu9JRcdhzMWy2Ssq1x8gJ8AajfjX3qdL", - "targetOrders": "8Yf56wdrQobmsLrSzse8wrpaHsfTrkdNPaebrgWE3BX4", - "baseVault": "DYGNBn73RSZfD6S2kCT1uYRAqbUNYZiGATfwkkeGii3M", - "quoteVault": "AZ5efB26LXhEyac7fLggCNygx5XLwf58fcPkMbFtT7ax", - "withdrawQueue": "AKgtakL9CDKfw7tALXoUYGnP9yNn6nhcgXMsefA9YjyL", - "lpVault": "BrLwtH8KXK6qqbMQNzmbCcBrvxjCzvjrsgo6mUuuuz5t", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "C5BSUX8dmZo4BqCLF4wan85MST7vZL8Haa8XMrauY5yE", - "marketAuthority": "ArQ5hyMGDJfUu1p1iBHtPYyeqwZ4HrFhvNsdGANQVjDG", - "marketBaseVault": "47r53ZJDfYyWrdhewWscdEGyhMwTBQgoiSsYWab3EC1m", - "marketQuoteVault": "B5ueY9LTtSPFGxxxPc4dGTF8kqLYWBjB5FujPhmbY255", - "marketBids": "HWJremSFxoqSYpQZAdSuQswp2QSQWNHks82ZE8a7jPBP", - "marketAsks": "CcWKRVga3omPrtmkhCDk31WgW2Difircj38at1ZtctSW", - "marketEventQueue": "4D7yndKbBPTewWzPAz6KzQ344o7hfpUB4rtG5ygGoqSR" - }, - { - "id": "32YvdjTH2JbyWE3cCsHyc4C7PQTpHho1uRf9e2uxjggv", - "baseMint": "H7Qc9APCWWGDVxGD5fJHmLTmdEgT9GFatAKFNg6sHh8A", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "GuoyGu29zWkU3xEunAydD5yt4Q5PL7u8ZbKSEbQjZ1Bz", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8MKK4SQW8XWcXQgex4572iwkNu7mz4MECt6MuUobFi7G", - "targetOrders": "ATgwuPgcTZqfdCQ1JF1eTYqiNZ5bjbLRavnBSCB7z29C", - "baseVault": "A5CaRrZbeCtKhzoPYeEj8EhLjdseyGn6FKfFVLoVATWA", - "quoteVault": "G4DtRcSv2qTGqRMb5SxMckTJutgivEwVfppqBE4nQdkf", - "withdrawQueue": "D8yYDcq7kLcP9mv5hP6YsGAtXfodLzXZXv3khsh8E6L9", - "lpVault": "FhoRyqtnxruGD3HRP5VNoHQ7aKDYLy9UbTNcmfso9ryo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6LGy6TXbq7xbmsJWsL1fRsm1ogLMz7yNRR6MgsnMwHvn", - "marketAuthority": "BYWLAfrACjr6epHJkMu6wWb7LTtx3maBt68RTpGF4f1A", - "marketBaseVault": "CtmBtvAaNndyHqmJGNtXZzghUaArjPuiufw6uo9pJvEL", - "marketQuoteVault": "CXkVefYdCaSVRp4MRF7Tu65eZxz4JN5n6SnjAwWcwUSR", - "marketBids": "8R72d5PRW3vcoYgYNPSy6tJ6FGoeFyxno1DQxQxTvi69", - "marketAsks": "EziM8yK8aLjNUeVTw7cVs81HiPTeRxrWfL5ihyTqi8h", - "marketEventQueue": "HzMwAuzDDrCt7DpugyBR4CXEpDqKnB3fU4doV6nMWP2m" - }, - { - "id": "33HKsu2gegVhr49NW5Q4puCsCee642JZjv2Ev54PtjKu", - "baseMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "quoteMint": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "lpMint": "8Jt6BQyfEzU365BHGTi48xf13A1Bejjxfs2c7A5ukaer", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7wg3EwHostrm2r2Z1k8hrvLAB4Vr9XYpV6X2yjzuiqDG", - "targetOrders": "E8Wgcu9Zsm995D2U2G5uAT4znzsGzJwTBSHrb7V66eG", - "baseVault": "6GamRbSkQhKFnmM41Au98tRWNqwMgagZkj14Qv5pqpN", - "quoteVault": "9Hx9HYC8RqZ4nF8sPXQrxMHYHfdu4MqXbLYxfWaWEPUM", - "withdrawQueue": "5DVTAFPKYTveLZY7Rtuwip2b43XyQHfbFHqn7Zgpoqzq", - "lpVault": "6e74R3MnABLBL6KTrSWqMD8Zj39W1esScNcrEm5v5KCU", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4Hx3CtzqbzNqv2hDEawPqhfVZex4w8xALLDJA81iY8D9", - "marketAuthority": "8LoXPLpn8yi1rf88viy8trWCbRGX28wHm7Xqxtjpti6A", - "marketBaseVault": "DhxRVJCjHfj86XPWykEmyQx9yut3VuKfpbzNSBXQxR5T", - "marketQuoteVault": "D2rshKYUGdermpX8wZFji4jQxZAnCMRrAqS1MVAYA5Cu", - "marketBids": "8DXzHAQYNfbHK8LyNnhN2BgZDPfnBykZ43duLsuwfyew", - "marketAsks": "9qe6MKaAVBucraorCMV9rcAGtxAQ3XgX4WRGpNVKjAdt", - "marketEventQueue": "7XSwmeNFNXuqCuyj5MCQn8izzByycBVGjRSc93weGL87" - }, - { - "id": "33tZZh5s5fuJ2UKCpacPY3KMrLtcMvoRSLcMzSWG7E9T", - "baseMint": "E5qNsCX91wqnLQQ25yEHTo3eujWGtqLe9daJvejRxikc", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3JbfJJPmPsbZJp5etcgc31dUDfqFXGBjyYwAD9j1R976", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FaewBwGdsqueoeQDmiC7dKga89RbuEBSbAXNxVZ919hV", - "targetOrders": "4k2mPPkoDV36dKp8RqkRuG39MhjCHWqT5Pt6e9dpVdgL", - "baseVault": "CFHRBVTBtHWEd2jWWUqAY9HN7qPTmawCANwLe6RMsq67", - "quoteVault": "8HeWaXNs44geWphEzj4jcD4Dd5UithuDYHmmwppUNbKj", - "withdrawQueue": "7c1RdhrXWsv1jPbWZ1ahodhh1gLmBYRs4Amd3vLvCBQ8", - "lpVault": "HAGjBKvwCpJSKeT1MwTP4VPHn6kiCZEPxb11yQ6CoYGM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HyDtN1n3Bcmmf95swdVHRZmfhR5E3FdstXqo2fBqjCPh", - "marketAuthority": "7iStjH58LbjhzXZwZ2RA7sdkAtJDNG8NHcGZAMC4CKwd", - "marketBaseVault": "91S2DPscXYEKqFciAzr5tfsQjuUJc91mi5Lk98RN8Gks", - "marketQuoteVault": "AV51jvHcMPnVHZt9HyRrKzQyVgizbdD8mCh3V5TYQ3wQ", - "marketBids": "A9tq93LQ1EuENmd6f3tEyw2QYUJS5kFauvgx3JhLzTUC", - "marketAsks": "ArcgQii17DWmywW1rttMFHNSChWeLrMHvSaFf4uKssd", - "marketEventQueue": "VZ6aveQxdqhSDARWurKnvo1EbSJkcRois16mAMbVLr7" - }, - { - "id": "33V24GEZWMeNAQmUznje9XWrMLvQZgu4cNn11cJcPq84", - "baseMint": "BABYsocP6cB95xvBDXnjXKX96VBNC37dmNWUtaV9Jk6v", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "22EqAKyvgauNaeSERVM1qr4DTy9nUP7uV1yE76V9nzyp", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "836YDQ6i6yNetZBtmTA5qk5CCyKepAAKPpnuKecWddyf", - "targetOrders": "959e2YtFgfQSdBy4M2Zk9jjMf65iC8TRzHBL3Aht9XJ", - "baseVault": "9aGadMqkhdDphpdCSiULvHwT2n9GC2GXWehXAkFnTePM", - "quoteVault": "H7MmFx4siDLBTzwNAuDJDijFPRZyemZ3UsFokxDmQQso", - "withdrawQueue": "5sWffjWT5xXxZGePbQynCKtiBdVNE5rxspfWFCyfvrfq", - "lpVault": "EbVp7pfccNkEesL3hrxySk4hrBhBpsgv6zctJd3PfZXe", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BbKYh7HWPiWVXCVogizXLHpG9w37yXGFFmYrQzR8N999", - "marketAuthority": "GsAdTYAvftqgKsLLo8cjT7gXmgGqnQp9Uf7132THPVxG", - "marketBaseVault": "6gGBTZPVQo1q6St1XXfbDR3MmfBv5wnEErEoDARqz65E", - "marketQuoteVault": "5nGmpKTTaNEpF4ZbiH3fn6YXbQDW6R1XBNWGiBvWNHd9", - "marketBids": "5neGCnkVXfN8GuM4rjuudr797CMbDvJCJP5PxtFPCs2R", - "marketAsks": "rnAwtovQAcnTgrty7CDdxc6tmTACAzpeVazk2FuPj6n", - "marketEventQueue": "zw6euqdMeZ3r7imiTvoNrDze1iTwB3Y3whm3gaSeUxP" - }, - { - "id": "3419ZVSxrxfdk4wGJZTerU26Gi9bjc86iHGMuwphjtJ6", - "baseMint": "3FYzcJvLeQubLuAgacV6sDu9Ye8Eg1vFYpCxD3ogp74M", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "21AExBdzj8JchJ4yCespw8t5AhviCN6BEfQjccU8AuUK", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4N3eDgQ6cY71T34jdrBykE5hVxhvjLDFAfm3QmhNgeCc", - "targetOrders": "EqQUTmsL7kJA5TXJbyTqt2LfLjMvkfuccPUWWyAMjAVo", - "baseVault": "2HZ8UuaCg6GjV1wKsCCRrWcXSoHBdmXwcaw8cW81WWmi", - "quoteVault": "9RbDQfDmUksHK8CNAVDHoTmiHeeDdx5GfP1iC9QhvR66", - "withdrawQueue": "ARpp5P4szwppBEdw7QwTgJ6YrEZgqVAtPrRsz8Ciuxwo", - "lpVault": "4o118jcgs5q2UvL2hz9fMSoGokcmQgNwXe7bmkLoJziL", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4CUAoHR15Di7jJJrPCwWBmDEAG4F7BHRxBQg343B1UbE", - "marketAuthority": "AuT7Fx9oiwdux9Jq8QgXj93izDviRAJqhDiJu2zipobQ", - "marketBaseVault": "586Mt5gYRkRSnT2YwqAVhJDABnhijf8GszErE1o2zbrg", - "marketQuoteVault": "Hf87au3CRYQYsrDYJ8yEvf24bMHb8pEoHM3gsNRmwVyF", - "marketBids": "7zNo1yp9GNHA7YS6GWrjFNSStxpM57QenbRxQG5yCF1C", - "marketAsks": "GS8wEWYjTsAzJWgQFdJ2nbByKwpLRYL4cQEKPxWXafcp", - "marketEventQueue": "2W78rXm8dKB7dSW1Ys63XeQuiWRPxYKmHR3eeGCYWDVM" - }, - { - "id": "349Sf81GK35fGvX5dCT8eq7L9ZvS6TDx9tu72Z8SSn29", - "baseMint": "DHxMYFZ6hZYtX4LXLkSHRN2UHFFezE5X6GkRCQNW1un9", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "GTTxiovJPi4pFDQAKLuwaaZwfm1coa9jMzsrhHLoWqUC", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2yc4BRPPeiexPaPvSkHaJSpY4uDRMtMp71dQ4KNmcmSN", - "targetOrders": "6Wh8NRiU14rxgWMs2drxsatz2KGwpnVNb5uAfRdru9Qe", - "baseVault": "G5L6A2ivGKdRd1zPBNYWpq1x7RX7kSkPMsHyCZvUybBg", - "quoteVault": "3eX39DGcoTb86movpaXLPAyEpVVQLjQyG5J1RQgBBDrN", - "withdrawQueue": "Hr3981QP8Pm4cSFkUD9pLM8J1NjsQvFBVQDyLwZsEngi", - "lpVault": "GngWUryWYxRCo9CXv5vEr8nerqVcnXfQyrUinVqR5Bjo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DSbYB1QcgfSyPDMzB7SCixPeHM4ek1ThLiwmWv8wAjPe", - "marketAuthority": "DsxNa5LsHj58GzBuvWkSVTFV45KxCeHm69eioDKywjVt", - "marketBaseVault": "F7auR6TcvgCfxoF5u4DS465HoLBYKhfCGGsAxBHe8irz", - "marketQuoteVault": "CxdRv4TCrE63d1BBfzU4sAJ6FbuuRiQys9ksrQhbGGA5", - "marketBids": "DMaRwxC8weN79fx714vYWEhpHQkvf7kEZmED5WQbtLZJ", - "marketAsks": "3Fp3bhdzLx2b3ZyVBvE3h11vWiBq25U7osd4cSCKF21b", - "marketEventQueue": "DpWSwAyNZ7GVFJDjByi34aRWSZVu85L9rPLE5c5R58vC" - }, - { - "id": "35abawJf32D7LatbTZ7w8j3hKHj3ykoZsj6uVNx23CHD", - "baseMint": "EmPxJRmDU9y3kh1XcrzDXYRUpHh875eSWKEA529eCGDN", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HuSUq5YzvkT2VRyiDqzoYsA8LDhqnLnfccHkHkZLMwgQ", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9mSVAAX81ZFhReeFy84NqLQoiTrteP9EHitgdpcCddSG", - "targetOrders": "3qFyxjs8TxX3SSnVbskbwtHAjjLE5GMpxYxc1GHbhXTr", - "baseVault": "68yVh5VwfEy71Yu5ASkveFBUUgakXjJ8xg3QdbkV8f9s", - "quoteVault": "EsxdQwTo6Gz6bjLFANYgrgqcJMi1eorqNZJCzSf77Zm4", - "withdrawQueue": "ErUqiCrqWW15rCTCak9XvVdjW6j2pNCAggUR7NVnAL4D", - "lpVault": "68qYYe6pDFbEq2wCPNmuDFjUL3ZEqAK5J9sH4159G5Z1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CskAHqQ8xRugepWduRDAQwmzEwskMm38Z33Z2yyRjZcU", - "marketAuthority": "HauZXvEfE7pNYNvxJhiQtAjizuFE1gLUQpBstQ8pKLff", - "marketBaseVault": "HKfXY9T8yXbQRRJfN9BVtWLDGFaB1E6nnnrbnRE73kbM", - "marketQuoteVault": "Ekj8jJFMsMB7X5dBbQBhLQnA9cKqJsWGdNiMfG41fVgv", - "marketBids": "3eBJvhePubRaVAnRfyB997P7ab1ppUCJMpcF3ppuibd3", - "marketAsks": "9QFKRQTQ48VRCeH7hVaKcZn7NZYLDd9br9c2NMiSQ5Vi", - "marketEventQueue": "DCVpZqhyMivwE1W1MXvvfQYcmEcyAXhRrQ19YzBKeCZY" - }, - { - "id": "35ed5C9X6XVd3mMhB7ABBsQ7z8xNmbcyVxkDPCQ9HNey", - "baseMint": "7rrJLRar2WjZwRoF3iJKHKnA7d7d9YJT1X9HAJnwUH3Z", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "2dSz8s23AD6bCJpd3Uuj6aVmHYoWwzfiMNeyYdVMSYHg", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "36NTBHwgwVHtuTR8LmCsaZhGjnLbYeaZjhZZrBJ4C9vA", - "targetOrders": "DUkUMA4TC3kLehLCM681XmZ9moezAJK3tPQmsdcnpge8", - "baseVault": "G8RJ1kDxWktnGAt4ZQjaEBUwZAUMSFJhV2nFSSkdTQ6L", - "quoteVault": "4P1DCxUbHbgDRHFz5DQozBMAWLi5SKE6Fm43mov67NFW", - "withdrawQueue": "Db9jdb5EU7G3qGsiWLMXbzjRXa1m9HTx1rSfpsGRyRrH", - "lpVault": "cV5SAKLfiJveokR2pLL7Yt9jVmopDytqzzE88kwKSfD", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CN1vBfz6pAufxifmhwwJT4vNUmyFdgVph6SFpXcL5aVr", - "marketAuthority": "7yWqgqhY4K3jBbQMHQbNubnU6HJcX3QLf1zZu3YBLUYm", - "marketBaseVault": "6udrW8KATNsb5A4oDTupTxYoioytpJWnx5AuKMEFpYJn", - "marketQuoteVault": "E8w3R5tMGJrBoJGoXRpB13rAXqbGQU9RhXwc9v9qqU38", - "marketBids": "GJcAAmm8HWm25tNu1UY3MggE3ct5acDEN7AeUYGreFeX", - "marketAsks": "8bndsYEV7mkALkWtrhe6RLhGpNXRn4hpqaJ3WGWd7dWe", - "marketEventQueue": "4yzWqVX27qbj2puKZdtNw2UaMEdYD5RBBYJW77mVwGFF" - }, - { - "id": "35tkMNqcRbtCcBvsAQyQEgrC2winoUNwJuMuCiN1g7LE", - "baseMint": "FeEdorXhQh5jsr89XtD1s6txNkmXTPu9hhNpaYvPiQGJ", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "3w2DWR4Po2FgbmZANidt68nKG6d4tMsnnAMdLVYXHLzw", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "MML7zFQUiP6Y4XfTF4ECygRhtSSe5k2hmijbDL3vTHi", - "targetOrders": "DvJuw5guSkFPQPfA4PYnVM7b4sg2udW87VDYpyZMetPw", - "baseVault": "H3ZT5CWVDwYdvkQctpL3B7djJ3Gto4SFg36jgEswkYkb", - "quoteVault": "DZkJJr9fnsjCwaswV5d3ZeSxMLDg4RjoBESUjPo91qJ8", - "withdrawQueue": "3qnZjFA1sz85cJaZos69BR7mzuNgdyeQGh34RVAQZiN5", - "lpVault": "CXjL5eyh6xnjXq5ANvrBEaHcyrMQbgV9dZeWwnBgfGj7", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5TcPCY3CCJxjiSaYezRDZHhEH4MUVHip7JV6NyHJtYcJ", - "marketAuthority": "9F9o31yqRBMzWiDu9yKEdSPi9HhiPpMGh1hg3BsY8fLW", - "marketBaseVault": "DmBTJFGVqUFJxgTvxbTdTgCp68oitj3s7SGuDG4hbT96", - "marketQuoteVault": "HBTwqTaYZVkFdn2Ca6fnFbauCAgEZEuG9HpYTDShWThH", - "marketBids": "BFD3idiHvwXZ1436QPdgSUxwcn4ZMXUZJzD1aG6h4Q83", - "marketAsks": "DvMbJUUy9dfDh22BiserhxxdJ3vhTasE9Q5FBRYkxwuE", - "marketEventQueue": "2gxJbX3tNNTwKjkjCva4KLdBaRDJpbaHNGmFpBZE5VYC" - }, - { - "id": "363MBkExHKxaN86wNgVNpBZ6KR8FziVV9GrpFetgFJ2P", - "baseMint": "GV6n9Uow3XzMWSs8vwTCML8SvMA6ozbidaEfdPoSoraQ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DKbTzo9jNUJyE9D3EELqKuvwHVsF3myP1d3fojhaxZ4q", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "B1GCPM8EFk5PLtch4duhB2erFVwoV1xz488dg1hVWVG4", - "targetOrders": "GDimfU2W1j5trYchZrWfTDCb9CnWcwFXz2jPDHcF2Vd2", - "baseVault": "G1oSA3VJj78XbPWXsD8ox2SQZpxuC8ahR7HFGKYWtKCZ", - "quoteVault": "AswALn9UUwY2XNSs8VzWFwmtL3tzJBUpJdtCLzqWYUD7", - "withdrawQueue": "EFzXhGY2vVp3h8tcK2MNwDrVS6scca8mP5wkJdN6JX1y", - "lpVault": "JDpzCEKf8Lk3HKiSz7NBDADy8MrBzheC6AyvHsBYpWSD", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8xX58rXPkrFRFEsQw8fWxsWvW7bQmMBXVc2PVqSM98hN", - "marketAuthority": "GcWkjvXyRzmCHG4S3mwFGGoXenrmi2GwdtgPmZdze1tv", - "marketBaseVault": "6efthdhFexWneRwxAC1qMXnxizwDn79XoNEEryvjgwXb", - "marketQuoteVault": "ARAXdchyGkC2SaaUwLfAPGH4C9asNpWU2yjuhtmvWq6u", - "marketBids": "43is7CYdtopqEFt4gEfDDBWX32pjZG5yuYnJsqnvfi6y", - "marketAsks": "DjbxfemqAoSoeEkxd6R5Ma7TjqE7i28i9L69ic2uCDbh", - "marketEventQueue": "CaAPPX2GHVuauAs9Q1usFwFAzPY5ZGHom3XeEdVUCQrZ" - }, - { - "id": "36CFKGuXCh7eH2rZuGEVS8fTJR6UH5iin2Qw6qcqPLEZ", - "baseMint": "2qRHKgE9k7doshwy7ZfENuSHW256pDhcbyspDgU3Ek8C", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9SSvvenZTGCJKpxpCkKoo8QUY7BDyF8GP3JR7z9qPC5Q", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "D91TgSKy3pvbstZtK5qnG91Nn1J9gXbzeZPUwBsKTtE", - "targetOrders": "5SbxcoBiTmhdSf1aL41EMqAgxfkNcqMLjiXvHM2KWTKM", - "baseVault": "AyEYoXwBJPHEkNw5hgTWu4F5J1gVAPp6pVDnvyRzJ5c7", - "quoteVault": "Bpb5yjiLqepoiF4484fBVeXSx6EJoxYs5XW9REWvbfbR", - "withdrawQueue": "CqHGMsuJQkAkqc17F3HduQ4SSGCtZJEvNwnNNapEtwGd", - "lpVault": "DBwaiCmjZ9XgiEpGnoxCZhqMbSjk4dh4FzB8qRjVdqvV", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2SBJ9CC61cwvVpaBBuY9M8zXvtwozrirKzw89tKy32i3", - "marketAuthority": "AKy4Z2LouxEXwBkGXgqG9nAshzu6eJ5QeYNdAU9mWYhn", - "marketBaseVault": "EGgg9REn9GCdo84pP6s7c7pdXNiMCUTP597vW4RUBPeP", - "marketQuoteVault": "2BcSG1XnHHUVj1WrT3yD4vZjQdKfRkKpwcFKrVmPyFGC", - "marketBids": "HvNEVapNkv8qhMozpK1zZAPQng51pn9YkdGnoZMH8syE", - "marketAsks": "56Ke5kPzrdcV1nevAPEhjbBfANgw6nyHhqrqPRqmAaDi", - "marketEventQueue": "BDuYhSfHtmb9oXUtuNyeGt2vzPWBcjjLqPXyPbHU7UA5" - }, - { - "id": "36cruU7S6MH5LLhT6WV8gCET5nmtDqwHFH2p2BT16Xxf", - "baseMint": "4wjPQJ6PrkC4dHhYghwJzGBVP78DkBzA2U3kHoFNBuhj", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "GtQ48z7NNjs7sVyp3M7iuiDcTRjeWPd1fkdiWQNy1UR6", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DFAPMWguERVjo11Mo5ymhpZDWRoi5NHLHAyEX7ej8DEX", - "targetOrders": "3E8LKvQBjZPUzVUqJteq4vanhFKFerzdWPQgo2FJjfb7", - "baseVault": "BYpFRqFz6A6Yds7smuEJY226L32arVQ2LSzCErShaYpY", - "quoteVault": "H6ZuiBCUtvqe53nmJWPn9d7nkf1XA5AbjiVnZGWenz2M", - "withdrawQueue": "3xo7T6JDeVfeMHHyULbQ63nxoSisDax1zEk6U3G8Q1DR", - "lpVault": "4eiHTPeWTnd54evXtnZYowm8XQvLMciqqyiYZ8xr3Hsi", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "F7SrwFTQ8uWBs9zhN9fctLKLJdEAz8fu7XmNyi9Sebht", - "marketAuthority": "3ghNT5T86Dp3zeNjrxpRs2vdZvKL6Gd11qGAXgc5fmFo", - "marketBaseVault": "8EVWJFHqaEryNeiuwkTiKyeV4CFK1i95eWpVMs8n94Lw", - "marketQuoteVault": "BHqWDxpG2RTVjf8VvwqJTmpGfXMyRzoqVrzzFoRZfYWd", - "marketBids": "BQE4NzguVF2qk1vVxZCy4mjXcBqx3QZMCTiqSzyD1XNs", - "marketAsks": "5FJ2hoh6jpYiHnUa1q6Nc7s9ESCNkgBiSq93cLTpZnJF", - "marketEventQueue": "DcYJVAgRrgeTXRUZ8MTu1Dyv8US1X83qHZEBnseAsCUy" - }, - { - "id": "36dH744jCC6Z5TXDs3c2j8C4QL2EbHxgSbuhHk6LKpnk", - "baseMint": "B72xRZAVS5RijKkXdxRVn394qeDDVifnnvQyp6mJQC1g", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "29rfDjZKm4y7fu7XbX17RY3pQLEu9xJDSMJ3ZoLR3aEv", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Byznm1LUHK3KpMepUpKfeuTiRGw5Xw5dki2ShtzS5gSB", - "targetOrders": "BQC3RKESNs6K5Jajo7785Rhr5Cpi9SFUEL83MckSTRhW", - "baseVault": "Da6smdtzMwN9DLZDbUs318PqV6miEMviC4iKcPfidSzZ", - "quoteVault": "6PgoERGrmbUvCS9U1tBzyabnQ8mwYhjvTeEeh7wFaDK6", - "withdrawQueue": "CpbyK5v8vY8tnM4Gmyp6g1oDdgogXiFJLAKC19RZtgqi", - "lpVault": "GKrkSCH8Z1WGcxa71uikW5nBGDnWC13LeKTy2QA3P6LC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5w2NUwi5u3Q4MwshFgTcs7MUwMpzSFAgtrH9Z7keQwrW", - "marketAuthority": "Fu3cirj2SBHmYGUTYemsN84Dyv9e9rA2pBiJDwCKZBLn", - "marketBaseVault": "4Gtg9NK7x2Ar4GzYJfMoPhqodYyq9YjkejMBrMjupSCH", - "marketQuoteVault": "9ojvJVyUtA8jbtyv1cmR7iqvUC4i6YWMXYqk3NhKU7dP", - "marketBids": "EoMW5ExWTrzvADtp5LMY5Q7DCCZPCSHAn1gVwULk9AbW", - "marketAsks": "A8TTsk2d24uCXRnPJKwnqCeCm1JmeNWCvHcuLchkoH4J", - "marketEventQueue": "ArTCuFaXtbnwQ3TWY3oBednFCh4nksEJwp2UZWmYNijK" - }, - { - "id": "36tU9GPshZ44Si4mtZgHwg8NQVC6oLQ2QXYXt63U75dT", - "baseMint": "2YJH1Y5NbdwJGEUAMY6hoTycKWrRCP6kLKs62xiSKWHM", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "J7u9N7EfYxKkjSiJyNC7ugLg2zDcVLc57zxw41Jxwg5K", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9rYBNVBRa5FyxKsUZBRY81hGwvPL8Rnw4EefRYE61ScZ", - "targetOrders": "8pMHLjSRd3i9SbJ8GxDCDEchP2wQpEdnxoHUWazdiLde", - "baseVault": "Hb83WrTGs6h2745zyhH8cS71yhSRdTb8cqgMpDFKtkLs", - "quoteVault": "5aUUEh2svEZAMwXCD3aYa9Y24jtwtaVEv9WvyTuVA9tN", - "withdrawQueue": "PsHCgx4B4EUMAbMMpc3pg66P7BMrG2d4HGz1eqjGRF9", - "lpVault": "A9tqiSE5pCJeP6ew14RwxxinpsUK8sfX7QrWXGUVbdQr", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "97fr2HWPRy4gqL95dMiVC5mmJpsSiHtsuGe9ncjDqpLG", - "marketAuthority": "8PSaTibEpq489BpmbZWCerrYEp8Lt7QN2tgju7ZtRYVT", - "marketBaseVault": "7fYNaGxkyMyBMhi99jxXdZN6miSdNcbRxU5ay2eQDAnY", - "marketQuoteVault": "BmpjaBcdY7pGNB1hbzJ2vxbXAwriGR1ALdFyLSd9FKZZ", - "marketBids": "BUEyt5bZS79ZcewZ7HTeudLvH6aZg3YMkFKvFAhvCjWm", - "marketAsks": "EwFYAH4cUP1T3XnPiwtdTbboj1Yd5BfRqkt6E2qmu5nf", - "marketEventQueue": "2iWZ4AswRv4SeofF9iG4aW92BqZ1MAbJFA6aVJpx5twL" - }, - { - "id": "378SQbNBa54RCuPoWq7qmpmfx6HZCjxcke7HZV3ojHgU", - "baseMint": "htoHLBJV1err8xP5oxyQdV2PLQhtVjxLXpKB7FsgJQD", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GtmyX9CAGa1EPVfHkxFRjm8yqk7KSBvJayHu2dBsus1a", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8rByfsQ2kPQiFCkhhAqCX9bjWX1f86ZkhJ5iorSHMfEP", - "targetOrders": "BDUAbco1zWqvs6CjR52fuoaZ3oDAgWXCKDXRGmxtZoiD", - "baseVault": "GPdmP78hq131w78rBbbcVYmJmncFVLqA9YRdkLwx5ppe", - "quoteVault": "72ThZgTQVncKmKNYUjgSqSUd3pUE6qc1zv86LStAJVFc", - "withdrawQueue": "H3HD5wYqSpm1wwKVUjMPeaycMgJfoTxJjRYztbaj8yaR", - "lpVault": "7b1d9tDnj3MLMLVgFUTRhYwsZE6eCa3pnx6i5aEEavVa", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4HedJ2uqt4cYvDNSCV85cLzKqKzoDfqzLKpU3r9M2deq", - "marketAuthority": "AxHMeECpDZx8mXK7hpYA6sAFTSnggFUWCoC4WRFiLQUC", - "marketBaseVault": "3vvjGypKhCf81xYPpsJWreYHijokBfvp1RDvmwDY5ctv", - "marketQuoteVault": "8Dz2ZEJEJ2nvghsfwHD3SJPmiesFngEFyYnRk3FExyKi", - "marketBids": "BYkgRpLyumQwdVjk4JKJgFd123FCbbP8N1uwKE3iSs5S", - "marketAsks": "CXZNWv4WpFi9P8rLUHwGub3eEN37VfSCSuVJNVHVu6N6", - "marketEventQueue": "HR48TckXfgv49sxxWwiovJFnPdKEBfeqFYwqfJdZ5WTF" - }, - { - "id": "37c3ws1ySnuHyB1DRf7aWHyA33NPi3Qsq9oQK91fVLf9", - "baseMint": "bonegFPgrpZ4bfVn3kQK1aMbGYddWtfMAywNt5LsuVE", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "AXmhRzf5g7SodKE9xN64vPDZEbHiVQQgLF5HbHptZvNk", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EtMmuv3wubG9UzqYhmCedJAtxE4QqhfyogvS5YQXyaAL", - "targetOrders": "Lq58KX82fjHcH5z2FB3qnPVTWDCH82qsNmFZachZ3sZ", - "baseVault": "4ViUyYGaYgGai1dB1wPTgnVaLYGw9kkczMKA1tzWusAC", - "quoteVault": "Ho6fUXRHwur8BASSeqSTnKHt81zpccPWHaqsf3ibzb3R", - "withdrawQueue": "9z76Ks4YJ59NxtCSyCjZiMUuga6QExsFyr5nuDe3i1vw", - "lpVault": "499og4EjJCtCNLGfWJdzY8UUAXaFF7YEA4qFM61vCv3i", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9GZ3jco4SqmcQkbpjYiC65ZfE9KrrXPiDFx36MjBh48p", - "marketAuthority": "98vQXf4AGeKCU8VMJQQckgzjTQjKTwFH1dX5CH2obE2K", - "marketBaseVault": "8uH7MuMhWZkRfFYevHMgqqBvro7wFpAYBY2ME2tWyA8Y", - "marketQuoteVault": "Bp4FfKDCNJq59xUtQS3BS6yDxYVBZDBBt6GH73dTeCyn", - "marketBids": "9JPzvomrju3y7mZQ1Shu2uSh9MdiPjsGs7WvjYxNRHGy", - "marketAsks": "EFj89WUfHUpS9njNj43NHaWqsb5yxCPUZj2JTQt4LsS1", - "marketEventQueue": "2MKz6GanhBny6wRqJ65MW4i72mYJGardo8YwQo4fqEQu" - }, - { - "id": "37suQyW5geSdtsky1qVrKvP1USLMqXEVu9k2Q6oEsNU7", - "baseMint": "5dWmnUa5cnPWTv5gkwboqTV3ZwTj4HgAMkeEsXUKE9kB", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "HHGhfhZHFxdHGKx1RzeZYE3Ris6FuFjBistFQk3GGmiN", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9epGm2iHwGv3MC5xX71uS12XCSAtTUpcsUo4aqgPiXz", - "targetOrders": "5wi2kQKh6vy8CLNZiokAzB9RULobmexQcvGeUbYu658L", - "baseVault": "FNZWopA2cHJpLoaRxo2YK9iZuMG6gNt2zVphJEm6683A", - "quoteVault": "2T2ekazjV4kZaGQbmzDPoCNR4e71bm2qkGdWaJ9nEqzs", - "withdrawQueue": "3ZsHotsB41U51pGeGWtNVeh1Q4XfNZgzshAqeTwvZdpL", - "lpVault": "3pnrFTxPC6B9jxEf8zWugFMHQstf1h5ZEdrnahPj2xUK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GuXEAifqjdUqhivuB2aWu22h3e6MEhi5NXeE7oJ9XzQh", - "marketAuthority": "4GFBQJwRJnG3Z2ybGeEup9xZzE5xeqtppPSBD9BKRQnM", - "marketBaseVault": "7AMKWFiUG65xJFMTi2EFPTsqBX9pdGe8e3c6U59mY6fQ", - "marketQuoteVault": "228aPKcd3cjqTQAVEeevT1jZrpPKbHRsdcQzh23KW9t5", - "marketBids": "2qxKJD6zR9UkVQ8fU2jzdnpK46qcWQTKrQjgxt5qQHsg", - "marketAsks": "DU2nkm5eznwDpL7J2HSCnas2kC8gi4vAj5VUDdZqJ3NL", - "marketEventQueue": "CcZqL2Ciy2uKC5BGNR4z38VNswqpdbUvp6VE3Yq4zYf3" - }, - { - "id": "38PRxtjdqPyDW21ta3PLhSWraUr7gH5b3wxic7HMURem", - "baseMint": "ArhMyF2N8XpaujYUxTTDt9EuaBCaGaccxfwaZmkm9XeF", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3wCczojLjx5uLCCrYXGnCNDz2SCc7Z4wQxGkqHt546pT", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2wkkDrjQ7B8DwGfnHkYvmZw5sovW4uHKzvLTHgBMf5BB", - "targetOrders": "EbVsymJBpJUKtF6trxUgF1yEHftJ1TGqRxgFaMcvAc4F", - "baseVault": "DAYtzvKXKATohUUaqj8hy86fnu92xP8aNQv6e6WkiTuU", - "quoteVault": "CRm1ooXR3VCSCYHQ4FaCx6HNm1Zs8j2EjhiSpyZyfL2C", - "withdrawQueue": "DU6dVPHt7ifiWdfvjDLvWMqFLqnGqzkEPyTSd45EhHrw", - "lpVault": "4KWqheDG4Ru6n7nQZvj63DdNy5Ax9DGaSBxNdwjRSTQz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "F1jBaKCMrxZpEgn79uduxpF2qHeqwiTQ3BwKdT6yqckd", - "marketAuthority": "D1w7jfP7q9gbEqYAGarub8DcUruvAqBvfJJJFHbp6umE", - "marketBaseVault": "Ccb7eKCN4neQ4MrEF5P5Bm44Fuo8Kx5DfWpWrnjskuzV", - "marketQuoteVault": "Hc1bgBwLqsPYcHfEu9hXSXwABYQSUf4sFZq7snssfTjX", - "marketBids": "6BiTyejUD3WNn3dCZex4hfBr4WUqoinFtEy4iUaHVUYn", - "marketAsks": "AnnysBeQfEdh7cNAZbjTV95KvHaLAWUBm3LVeAJs1zmw", - "marketEventQueue": "3R7mPqE4dBZeKqfkBjqQEGPXcvjxjUxk8EGghc8jxTox" - }, - { - "id": "38vmV9F6UnNEMqxDiRdw5fMMXm9dfKdYbNzYqRhULWUG", - "baseMint": "3NcCuwvTMnnf7TU2UEVhp6v2nzbLXQiDgzQySS6m8A7P", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "96ne2kcZF7uoL2yVwdSodma32JpWE3fQEmXt2kwJpwwR", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8fbeXQvWamUixaVBHPp1BKBsLJpm87LAeRev4CGSMDJ3", - "targetOrders": "9MQJhw44e2B2BnvztTuSqgwq2J3Qs85ShuoZzjGgkJSP", - "baseVault": "DM528LQu5UxZAiMhZwaTriPMGggG6HTjJAt4Tpn7xbHq", - "quoteVault": "6s4pyCwZju6PYsvXPoVYdde4s2r2BWoj3kr8epQsmoPF", - "withdrawQueue": "AQvxqKLev3vi23n6UUsBUjdB9rD2uwUZNFtQA29kRuLc", - "lpVault": "EYix6Vg55uYJjbb1guiZrrEJqx4mAgZo1JMEbaw5DzWe", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DQ4Gn2bKTssqvMFyD5qYaeVMXJDe9ELXZ1NtJX4inr9c", - "marketAuthority": "4kvBNMH6yayjT9AD1SfBbNZ4Gngo2BA4VyYERxZCgQwq", - "marketBaseVault": "BxrQhUWqmem12BdSGSSJNJVVQ8t32qMMkfonL7JuiLZh", - "marketQuoteVault": "G31XWBwL2UaqJE4VVaT4ybSzQYFS5vuCJi8scVyoMEbN", - "marketBids": "4y34YxUUxg7coDYW1HuS8M8FiSkduVcn6ADfHrZ56stb", - "marketAsks": "BM1Ua3BcpmFpAhuZ7d2NfpLqXQ7iXsavCoKYir6JqtBn", - "marketEventQueue": "BSu5117xhLF59poVCV8h1vEFcjZB7Gmjn8Fx2hLwk1Uh" - }, - { - "id": "39CSkprgyD5gGgqCpecNxX14ghHr2tVtYFv9kDqUNTZx", - "baseMint": "4wjPQJ6PrkC4dHhYghwJzGBVP78DkBzA2U3kHoFNBuhj", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "GBM6hrdxqz7q19Wk4WDxkMjTvdVoRqThpCD3rbfuqDo", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6hT9NPj2yWAjJgd9ZgYJEpW5FV8FzoPjqhhNq7hrZkiz", - "targetOrders": "EABK9zDCLWxrmNaimGXr18kUrauhEzdqvdsk31QnwZda", - "baseVault": "2ErUeW6sB5MQGZK9CJjsgDMvZphoKnjUggzEUUF4QR1b", - "quoteVault": "CtvW3D4U9NWj5tVDVuTBRFSEoWnVDJwjvSqmq7zfrJWy", - "withdrawQueue": "8k8RzzvX9pMXYavWYAiFsFawZFaZsqZU8NFeYZjTWNHD", - "lpVault": "DmcFzyWWGkSjs3hasEArLjyaR2GxmGjJMLbmsqiVBHid", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EktqwSZVYjQF7e4QMojdYrmjLV4ft9H1DcM2i6ZiShGz", - "marketAuthority": "HKjS7BcNPuEnkq3P749XVb96CPVim3qtcrB66m7LLwZi", - "marketBaseVault": "B96zHuZRzeD5cMQPzPZ6hZHCtwysB26b6rZFT7CHkwzy", - "marketQuoteVault": "7Tjx1vXtaKyZmxU95h7rZDNAoQE63ShEzuJtBqsX3Ksr", - "marketBids": "Bajt3oZT1qAZVEAugnS8omQ9upjCA8eXdxxJiqoF9gBb", - "marketAsks": "5G5uEjezrSj7aFe7PgyqhEYdAoc6KnZg9UeiXu5CYTvG", - "marketEventQueue": "9RbAbrnRhLYnd1MSfmb6CuwEHAJ2DX3t2wWrk91qpRdc" - }, - { - "id": "3aBomPsmJc5wBsYQQffQXtXWiS6pw4hbGv29Dai8DkiY", - "baseMint": "buMnhMd5xSyXBssTQo15jouu8VhuEZJCfbtBUZgRcuW", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3yQY6HfoZg9drucJAx86zWjKrqvEywxRFp3WtHFjLV5S", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "C2b68V2EP7U5ucAHiVGV6rfhczhL6TxTp5gyrCTPdCzK", - "targetOrders": "6nQYBDhZ5k9w2ouQTM6aFGQEtt3JfnV5ScaxL9f57TVe", - "baseVault": "7dWoz1c29EQTiB3RmVcUae6jgps5TVBJKjZL6c5p9N6T", - "quoteVault": "DTr5CuN9fyXLuAPhxf5Sb9JT1vEn2iKaFGCAkgFx8Kff", - "withdrawQueue": "2jyHeySuvzSETTmSib7Wka5h3BCArLdiaJYzT16YD25g", - "lpVault": "CYNCPK6TmoCKCYLVN4Y3yyk4VvBDW77akH5VBptv27iz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "J1WLWd4J8s1dk5CsAxUD1c6oG89QRzPRMrCzqXX85Jek", - "marketAuthority": "2hgZhjgTKmk3pAaeGQX8KEK9RiyUTppdci1iqvYu8Dyi", - "marketBaseVault": "CTb9qFU8HJdx84AxuE9624LPbSzXUYcNu1vnbcoLdaXQ", - "marketQuoteVault": "46CTsrNvJx61p2UL3RhjNaAvUjN8Rrq8xkBzbN4UM6Tp", - "marketBids": "4KM6CCNsXscVvFZfq5gfjNJwo4MpuRWgKNypmvtxE6J8", - "marketAsks": "raMequJVmwSLx9MupMntNhYocWex6QdzdKiftFQid6c", - "marketEventQueue": "3SYPNNWzjFMeGgbBJh9vXjswrswyWFd24sWAG6cdsYc7" - }, - { - "id": "3AiF2uXqEkRjc4PAskTB7vbn9u3X2mH5FyjgSwA5y6kX", - "baseMint": "666YXKdQzN49gzQetYffQUhy4hLxEB31PZkRew4VrXAj", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "AKKiT4oZCBJsc3TJH4K8UFwhLdCnVq6PAJRHSKTesePE", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Xs3wgPExEKJWCH5XbhiABtMiYRKtjmxFkhjkftCy91D", - "targetOrders": "GSc8aQvaMWdDR9XvxaETXcEK7nDwh5BYt61nsWmksqbU", - "baseVault": "AeFhbHcakakA2NZnJpeF1Nuyivbo5CaJ6irFzSE6Gvhr", - "quoteVault": "6pARSG9FCCAnsKzkZ8UUz7ijEZYEEKe6grRZCF167hCw", - "withdrawQueue": "ErpjiyJWupzcZ2X2NsAtKfdyc4QqoGwJdPNtBEEbwFic", - "lpVault": "Es3FqpdCobC6YeevvhUXyi4Mg74ZNVJsgxQncXsx7bcP", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EcVUMb4u2sggUFJGbzCX7pPdKKhg8UG6cjLdRCheT83d", - "marketAuthority": "EZk4TBDiYJ465EbqGwHn2q7KgBfq3yETyWJJEJPLwNsE", - "marketBaseVault": "41neUo399CQKdqmVXrMVKhKopPKZuCqxQ57dE1efoANc", - "marketQuoteVault": "AU2YnCUw1ph8EaEpiGumQ4QPZJ6wqvUVuJHm4UHrb9Rn", - "marketBids": "Amv2G2chdgE7nXVLVQAMN2xUsVLZcfggpCqNP6kGHRxE", - "marketAsks": "DRmcMfu6daLRWM1eARi9YHEdUhey72Whfv1vruoGB2U1", - "marketEventQueue": "qVnbzQ8EonZFNB95brMuXcPktWeVjVG3UFtbGUU7wQy" - }, - { - "id": "3b12ESv9QRWu14iwJxui7zy7y7sWKKCT9Ynsf1p4xuuU", - "baseMint": "3dU3xJjjPCJHvJwmqhmK4nqETfPpEGKRaWSquffAvZ5C", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "Hwkbnef6SQThTBeU3J6janLxEpvrGMWKcrCFf5Kh2erE", - "baseDecimals": 0, - "quoteDecimals": 9, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HYa6vMBsAjBu56i8iPesernutB8aCXkyT5uc3oGPTcZN", - "targetOrders": "45z3MN5VhKyRGEzFDzt6DdcugaJfWQupkGCbaDbPx2JY", - "baseVault": "AnvjDCpyeDZJXkn83zyJUGBeBNjTk1RrUYK8pA64mX5Y", - "quoteVault": "9Xt2DbQwkRSieDLqYWDq1x7UZBRuLjGrHghjXJ3Yc187", - "withdrawQueue": "2dzou2YxncpKTDmhYXcYimBG7i2YZpLu5XrtZygagDY8", - "lpVault": "EVKsLpFjkQbTdM7Ytm9BUZFmkuLC9pf7NoAB9aSBkAHZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BP7XypzysqnC4YdS4YrpSta73Suod5yUhUAyHTQFeCuW", - "marketAuthority": "Coc1mfo5eWxMzQntNtH6XSANVmHZHgWa4iZoszoc3iH6", - "marketBaseVault": "C4nn6xHopYAHqGDRLyGiFwB7ngJ3rvyrmtqdBZ3s32Sz", - "marketQuoteVault": "FYtshhB1W3kG3zafyMcWmPTXuNMjahPxgbr6CherWFdB", - "marketBids": "HDERiYJ8bgKfx2iJRWSKYcZFAnjB7PE8ZDgJpTSSA1xo", - "marketAsks": "5Nf6VNXfLygokURffuuHuk48myiJjJDCGLyWz8NSz79L", - "marketEventQueue": "GxyA2EGCCeYtNP4TRzDZUgKVGVpJWjyTXWtBrVpZwnMH" - }, - { - "id": "3BeZMcyRyauCBHBa8nGevAX2od8nacDdtZ3pMbpQvevK", - "baseMint": "9sQtcMxC7zwoVm9vsbZD6XkbZMik5882sA22oc6kb6bU", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "mbCogd29CK1Bhgb7VYsvLKNTAf7yVwJ7X1PFA6A8p6e", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "54L6pU4yurtpEcwMvxGy5QSrUKz8SvbcY6mFn5oLCASW", - "targetOrders": "74edyxceBpUHpCQAeUBDDr8ns5QfpBQJiBwXakWNpS8f", - "baseVault": "7bUdwDEk2wpjrpjeHJUThmW2Hi3W2j3C53gdD1Vs25Jp", - "quoteVault": "HNggV8TnWaoScFGtksyTV5vRZGZSPvGqBS3W6NBdEhFW", - "withdrawQueue": "3pcyXinMSngoE2TARueXC2NA4TJ7v3Z5iF1WJjqLfDpu", - "lpVault": "AhC3Dw8gZgtWWcs2NMd98HK7s3WQ7w69Nt3FbYZXWJVW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8yJJQ38vvMvAc1JmaXsFofkc4xNy2nE4SLaoxobxfGfZ", - "marketAuthority": "CgqeDDjDfJZ8YWR2egnmPELNc39UnwFsNKvpCntUBWhb", - "marketBaseVault": "5VnESkRYp5L7vdvBqgyNUbXPAknim38Mydp8nvPtZebN", - "marketQuoteVault": "BXw4pSdiTNX6F4PquLMi48HSaeevXX9ei3Wyb6uNqDu7", - "marketBids": "8Di3WUznbqJhXmrkEn93HqSZT1tU62xW4jcZBEo2ft88", - "marketAsks": "83j3QM92xNWAa3ZGWSib9peBm7vr8hcrWdPMht9uTqyb", - "marketEventQueue": "2nUapfHqDm7CZsFfRKz2MsPTBUrQt39MJvfw7p3w3LS1" - }, - { - "id": "3BHwfYjEWMcuRWJZxDkhLnDoUa9mmWeEivvqpSJi9vjo", - "baseMint": "9akvvCgpFc7LkpESHCSacrPPH7SztbvuAXNvJkzZSZWu", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "nt13UMaBveugAjzEnWt2ixigutVZMfJHyYR8yuejZH5", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DK3yBMCTcYNJwjrB55yM5NzDYPugTfwCcfUWVSwyYACF", - "targetOrders": "CfT5Bqty3Zbz9goaC9PDbsfwKkVvRETDN5gG8PKQKy6i", - "baseVault": "3htPFLBm5pfE5NDwA1AqtmtSymg9EePBWdZUErCaGvRr", - "quoteVault": "FAG4ngRWQ4DviWdJUBFYWZdwD86rgy8R8WYhmDpivFaw", - "withdrawQueue": "3hQuKmsba6iZi41aZ9UqKa8u2Xy3NBbF8z8m8PyP1oBh", - "lpVault": "86sEHzG3ndcrzudjV11qm15QXpFLxxUAGbwjY5jW4WW6", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AJYSaZrP5XVvhizswJnLZeDmgT1zSA9yWjzSGhrAoqKq", - "marketAuthority": "J7wGRCaE1UtiXrTt74Cdp4puAex6SRqbpBRUCG4UBzPv", - "marketBaseVault": "2b5g7qeGciJTGJ5ttNhfsUe4HieT8KkbNJjQNpxHybMr", - "marketQuoteVault": "3btv9BRKFCedu7HbzKmhgcU62Tp7QWJ8H5KUZsPfWGej", - "marketBids": "5ZNnsgvECA9ArXCraq9ucc8493Btzxmjt5bGL6WAv3mz", - "marketAsks": "5gcEyyxkeab5ED9u3tRuv29HTThmPiwQbW7SuKg6SNPM", - "marketEventQueue": "Aoe8BTLwGZwCe5QdXyTNS1GUaMoXT81KP4DTn1An8z8Q" - }, - { - "id": "3c9optLwGGp2vdFhCEk3VFfnxiJErd87LihU24dpZaDv", - "baseMint": "EmzYLb3fwhjNp726Na5zLdhgrZjyC8GrfNGyopq6731w", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "Tdn25ushgBJajNnG7BGvpdHiEbNdcxY7ssMefZ1jRT7", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "G88txH4oXQDgpZcBPCYMtVqZxMkjNUcb254svos5sgp5", - "targetOrders": "FDvPka2kLnWniHPHA76B4fbjG6BttiLix47YzDAZVhij", - "baseVault": "8QJJWgrLqkodDRYwGsErQFXgWmxhX4GdL3tErJk9Ph9i", - "quoteVault": "9Ur2SGj9XEAUNJLrUKMFYFGMUodgtuG8aYntuyXhanMb", - "withdrawQueue": "CoFjS1nNQDVjhskQHMBi932q7z9EHFBwM3HjSGEmEJNB", - "lpVault": "2gPe3FFoo4ws43o7H6ZfVpVJ8CjZGCnJWXqR4eMPKeoN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HKLb5pEhFUQyWKzHHSVcYy25UhtvimsrUeKR44FkD4FR", - "marketAuthority": "Gsgk9nJPPcFtro3M4X3NedMqyVDVmzzR7vPqmtxmoT8Q", - "marketBaseVault": "FnQSAfKVL7GTg1SxqdPbpxyijkhGYqLVeyEQtzcSU3rg", - "marketQuoteVault": "B2txrvrhA3uCJB5yvJQPFYw85f1K5Lc78pQGS91w4xB9", - "marketBids": "63BtEfqAhim8nhErfk8XciVTcwj8iw2qB6X7QwLxAy8P", - "marketAsks": "9s9rdMQKHnvjY4ytcXxULaa4ZFGjCGXUjTdCeyLhuXzK", - "marketEventQueue": "FfnkZP866MRMomXmyBbPPgj8L5gcDP8ArCX2cT2FwEM2" - }, - { - "id": "3cLMzoZcW4HVWhHQrvpbiLnvZqQGeXM9Vmb3DcaJkuiJ", - "baseMint": "S8v4cS7dnKzV6LYvzFPuuiWQMM4KSz7URuGYWMGXyTG", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3sfNiCYzGyvTc7f2G5ZNecw7JgCwnkKMT8f4CpdymHb6", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FxHFXqwZ98piVNwSvQYiCeuzswGUtxZ91wkptzuG2BRV", - "targetOrders": "2aP8BXbCsArK5gUXttHMgjGUg4vNJFuEPLvW6BjJr2cN", - "baseVault": "5KBrVfv2aAwiKc4fp9MN7Keubgych7mmGwLXRUtY1zJH", - "quoteVault": "8zPyuWNsAbp39KT16S1dDYHy2sRcFK67R7q9MKGUTr7D", - "withdrawQueue": "G586PYnL7JBLMh1erHdj52cWcZjeUTcJyCMeswXLHFbx", - "lpVault": "AauMgYPL7q6LhqviSgDHnz7ooPdZdzrwwVAQPWJdfBc6", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7pc2vPVeQNsResJDmhEZKXyi3img3aADK6P96D9JXbK6", - "marketAuthority": "5vkXhEPAVQnvANgHWeXjD4b23Fc5wgHnaY8cbtHC6mGz", - "marketBaseVault": "A2cXEG4PpdHpjY8tYf4AB2TwovysRRoZDZqiX9ZfUbWc", - "marketQuoteVault": "Erae6ck1P6yk8ohkViXbarSxgtxD2Gw54u5QA9AoAx1g", - "marketBids": "GLgxb4XmyicXayJLFZ4zE8jdRpK9LGhKHJNRFxY3nTyq", - "marketAsks": "Ct58a72C2HoQryeK3KkZT95p58iB12jVPrMTADgr2F8x", - "marketEventQueue": "BVFVM5YDbXNoLKrvaKpAhjycZMHPaCvckezy3iRm122e" - }, - { - "id": "3cmN5NV5hzcaBit24MW3oct2rWMEdC2RpdDcJMaWAvHJ", - "baseMint": "FtgGSFADXBtroxq8VCausXRr2of47QBf5AS1NtZCu4GD", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "GgYmckWcP4NytwkJmDY1YVHPsFDYKZPxXJWqSwRv9m7Z", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Eg1n3AAoWdNq3v91GTyMvWLSELiugkECJVP1kHbzaqUg", - "targetOrders": "EGw6tnVDpw9fFHx26WWL9LeHHHvRd6RHX95fyfZAjBn6", - "baseVault": "D6asorrivsaDN3pa2GuWnKx1idQocABcA6xkQYQDs8v7", - "quoteVault": "GiVS4ntG7Uj4se6F6qjFUWxUQCYqYeuuxeueRTgUBiFs", - "withdrawQueue": "4SXU8r7AqEPb6XBBiYs1gUpCZS2gN8fEXXMzC7n92G92", - "lpVault": "Ghabmgx7Rq13vsdxrtqHmStnV9ykJaDrhFHEUguw23EL", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4gnKvQMpcfSJem9e6woSm5oomyTBco5UhnT1eZLzC96S", - "marketAuthority": "5H8nrtGvLMh9M4Ut4q8Gkmocdqif7aQ7DXAVst5GRdHU", - "marketBaseVault": "8Q9t6u6EFX9j7qkeWmGQbCMbf3zPVAfRq9jeRX3CzFGu", - "marketQuoteVault": "DYysg8hRUMo8MzKHFo9qfYM973un8JrtvLtnMHNWXwG", - "marketBids": "A2QeamMs8vNFwxkDWVCj8JZsBeBz81JccyBExX8CYCC6", - "marketAsks": "62RXHhFsYquwEZ8Kn5wHC7eZZFyYFtDPsc2R4dnziPyY", - "marketEventQueue": "2kPSDx6jyGSWRdYB6PoRwcWePRoRqVDr6eCjQRWHRJ5Z" - }, - { - "id": "3Cq1P1w2tGbXZ325vHdTeX8GKXgoRsZUSciQ3VUd95XD", - "baseMint": "BELEkfxRkTdNexHtsJ8sk6RBx1ZuNcQmfpkKSNgq8S7N", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6wrTPNjcDNMDhzkH6pojPVv8yZsQ9LFcbcFyfN2fRGr1", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HxprBbfW18Yahaffd1x6k6XpD3N6Bwyrjae2pPcG7EuG", - "targetOrders": "GFAX5TQrp9324AyQgh2XQvWDm1wsf6judwY9wniQULtG", - "baseVault": "J87wRVc1r8Z3r6jZmAMwWhAA9MjYxjAGhdRnXhtqoFso", - "quoteVault": "E5RACjPzqpcecC24NQS1PScxRwUs3gmYoHqoEdgMytvi", - "withdrawQueue": "CSUevupq369PLR57rZMjkGZdSZ1CvgBKY5PGNgahyuU7", - "lpVault": "6esQpCXkhPHVbvG7d599xjKT7aomnQghCpgY7X3V8jQ1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Hqk7eB5q6gmDeH5b8bHJrRjWJ3wKkArXoNuY2LiCXfYv", - "marketAuthority": "2gafEvECi52BfDB1B2XBgpNAM69XXsP3Rr93cygZghNu", - "marketBaseVault": "HxAKjnZf2aXpwxoRyPKaAC1i6sMtdgEYhQuASmf6bYPn", - "marketQuoteVault": "DYoR3BbMUpmjsKadCiFurpfzwuZuSY3vVkANafnjSeVF", - "marketBids": "FBRcfPYWr5GVm6KACuzgXkm2w7LBoSNT3YZtb34L81CJ", - "marketAsks": "GXEU5GRFNkUHaP6GA4uHjaCcQGmkFLFPjxhQPLC9sJqL", - "marketEventQueue": "GZEMvmhSNPHbpVkHGTqmBkMsPAcSBXAp6qAq4baXDSMV" - }, - { - "id": "3CUtjm2vSP5bUSejW4a7z8eXctXMCxWAsF3J6bXkVp6A", - "baseMint": "ELYz5s27opRYVsAvtEBXFKPVdZCvZDUJ6E51DmihBA6M", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DtHXZaAq8T96Xu1GHQiz2jmXCHMbdgiq9UzSLYULk3Kg", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "64bcafSUcQdGSTKaUFCYMp1d5iR3iJvw7eW7jszr2UMR", - "targetOrders": "BCRhrLf6G9BFhzkLp7hz8p1L3xdhnM88yZ2WgFDq9Usn", - "baseVault": "C4yZ6A3i43P3QaaKkGDsTPpGYiY1V8hcKof6EG8u2MsJ", - "quoteVault": "96a35jFLPy5EocgTRgPM4A2JMZwHy8kePaixD7bUGSQZ", - "withdrawQueue": "BVrYXEQvenHkNYmeeehyBETpJBf9dNdstXaoMXQPjeFT", - "lpVault": "4eKG22X3RfFfW3mYbaricy9UBau7f8h5t2H313Z1Fu8F", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GztS9YxtMf8q9mB5VzcgaUCU3aKHXDj4D2cdLR2iv8qB", - "marketAuthority": "2bt5sTR68zcF4x7jg9TrBnYpzBVt9GnyBdCQWv7uT2AK", - "marketBaseVault": "5BUExentCuf8BZ5aMdRYv4dELaZwcyyTuiJtvzUzHJoZ", - "marketQuoteVault": "3UdXpKRiuqsYWWEmAhEpzcgSXDmVxF4xTJNR45gDMVph", - "marketBids": "58YNGncqzpsMDH9aF6oR1tejzHaG979g78KtN8XuTob5", - "marketAsks": "Edzttq3fsDgxBstBpsjS9AtdHZV5VmhcoawSAwXFwo4D", - "marketEventQueue": "CDFSfpF5EMEJ51hhGJQLZzW3pt9uSsLZwrHvHFmAh4f4" - }, - { - "id": "3DNsPQELjUHNB64JUe3agpJH4RXYw7eLHhanSy4UBEoo", - "baseMint": "EzfnjRUKtc5vweE1GCLdHV4MkDQ3ebSpQXLobSKgQ9RB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3KSDx1v18eMZoZGcMr5VhPeG7c6TAF79j37KTfR6TnnY", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6JF9Hpfo2crJ2NxWbcFtBdLSGchyNEwtPCMX9n5hNJbN", - "targetOrders": "3krXo9Mvxz1XBBDznkCV8vXyGWQqjYCXJcGDoTY9Uos9", - "baseVault": "Da1HUTbi8rjaXri9SutqzXHa5fSaYXG4BBodJ6mgAy6P", - "quoteVault": "3u9g5v68fmEiKTqmH4vVo72n8G5ibnYo4ryCQgtoqGQU", - "withdrawQueue": "5hMjxKW8eB3ZCFjg4mZ1VvmzPqfhhe3A8CmtH5tv9gey", - "lpVault": "5tiTj912XxkYn7dXnWVE25wa8SFWqayecZgTf9FNXi6", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8rTet11WyJTCg6jgJfstQRDGSPLpmnoecyPui4nmgh9g", - "marketAuthority": "CT51VGvcYg7PpKck6Ad66AXVXzd6d5xkucSVTeiS87cM", - "marketBaseVault": "GTd3hbaDF68BiAfZrnZJn1bL5bpMotjpeigx73tq6KX9", - "marketQuoteVault": "2TydCFKztvEUkxPyVHf8t8BUE7dMJZDw8zKpezSQFrye", - "marketBids": "5tRBpG3fykSU2ioM5knQNrbtgkix3xbCw8p4ApHU5mqw", - "marketAsks": "BiChk7WgurQALYNd5kpkhQWK1od6Rp11H1GqpcXhrEVo", - "marketEventQueue": "Cfq4x3e3hMh675G44xhKynC92B9wg8gCKYioAeEoZXzX" - }, - { - "id": "3DovTj5VdDLjptxE46RjL79B68G6BGJGeSr8NA7GkFSQ", - "baseMint": "AEb38qKfe6R6Xs1MsfKE2iBXF8tjZcVtiedrZuneFS3h", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "DhFuGN51T6SiF67cyEZu4tM9xHTmfXCHZUwscMxQ1kWs", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "D7FyDTk7Az1qa1k7KN46L4Tgw9MWbK7Uko2wsQ8nWgKD", - "targetOrders": "FzUqERzRMW8tWRapchkk7qYDRzdUXDtyk1XEVdRmt7CX", - "baseVault": "31VbNRUV9RNVg7Yj9k5xtLy6nbAkGy5kyYiGSJ93dSdg", - "quoteVault": "7v5JcekDZAqQTRyb6DCUrLU7tvzqG5E9nUTJorqHYgfv", - "withdrawQueue": "82JyF2iLHM1eZKxMGnPZtxYd8KQYNyjheg6GtvJ3JjK3", - "lpVault": "FVphRkywnCM6beh1qj25DhAoUVNLZVa1GfR1nguJuFCz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "sGWTUkSeufEjfR5S5eLPBVygWgZUAnUL1zKNfAWm8y1", - "marketAuthority": "6cgfSZPtEz6Ahd8DfoEnnH9mNRcGFpNfGbWdA2yhHSxp", - "marketBaseVault": "CLSQHpNiNULX4W97DpSaXsjTDyT7GbjfQEjpETLnxQaS", - "marketQuoteVault": "5fs3uKTqdH2BqmE4Khujt5ejGMyc29f3xSahRfrUpD6C", - "marketBids": "Bw2ZmdSSKR111CALtYywqyvcBvXiHt1Y8THbmstPQ8gT", - "marketAsks": "EAUdBmDSWWFdWxwPAh6jXzQjkhHB3Q3wqtiV5iKbqHUF", - "marketEventQueue": "Apzgyf9u8dvkLnWbNh8fzUBYTseKDixYgfD4wNwQsyfU" - }, - { - "id": "3Dp2xUz3fhACcMQgPUibhdyaERP3DacvVJy61ymzUaGW", - "baseMint": "KAT2oYwjN2uVj9gubM9VutCFMoX1Wq9eLiwJJEpBEX3", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "3dUP24FewyxEpT6qY1f6pMhPsZ1yqJEw2XWqStSxqCCV", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CYh6gTRik5Bx1UpJo7q21sGYqRfvuCEa1TjYrzJCDrV2", - "targetOrders": "AaDacPepi3u8ZU2LFPvuSKuSCyauKzXCT2rNtc1oX638", - "baseVault": "81jePm8jzpcmtkEKpNKCqJYD9HLwu5UVQvN4FhE98eVC", - "quoteVault": "bo5UscKcDbHCshmzkiXs3LA6JBxpoDMuhbYzLHQXuaL", - "withdrawQueue": "GasqMHtEyX9UvCr8JH3w7JzJqCKpLQ6GfHo8EH6PQK39", - "lpVault": "7Vg6CpDRxTqzwwdNoSc5vbCxUtPsgfPgD9nEcXaTHBt4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7n5EgnauxVNdKGXr61wd3XKsyk1jQ5yW1ir2PJ5hnVfP", - "marketAuthority": "HygFnYXsmJxZDCKeZgKHxndfHcpRnC2pSbfhT1yFsF9R", - "marketBaseVault": "Aqt9upejWxdmaQVVsfXVqTZfZpUz5XFuB7SatSLmh1sB", - "marketQuoteVault": "FQmaXK9L5JsT5YnnftoDPeE1LdY1Bnb8LPQ3ebNGxp88", - "marketBids": "HHH1Mpc2TYqEeR5pP8dbevbS2oftqQhmfmDX8ehCMnHe", - "marketAsks": "DCtnHbxGwkEexaC7pnTS18MbH4fiE8uXymvYSLnjLABa", - "marketEventQueue": "4aJV4SDj1wCGkgH8fuYTVM8NnSvSoHbSWV2P38Bavy9V" - }, - { - "id": "3EoQf2WAZ7s4avZdaaJyP1EseviYjkBjuj1KByLpWkPJ", - "baseMint": "2hWrFTaGYXNLEVnTdvYPF5roxp4NSygoC8BYWYHYLuXd", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5Nqn1NmUU71YwgGEhQ6HRoqDBhdJdRf5K2tsvkaiZd1q", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ASe3mpYZuUXjfgVvEFcxGeuHPXmfpMg2iWeK39KiG3qC", - "targetOrders": "6mmFvnCSa4dUzzK243Sz5DAMAr1wDfogZzHZt3Ejvv2p", - "baseVault": "HERuiX8eSuneSGLnVDEr3sHqBjnZamtoQN2Y9JPerGMF", - "quoteVault": "66m7Zra7jwsMt9MVDrdHSgzqs62yHG79c7Edhs9yrtuy", - "withdrawQueue": "6ftBCycfc3heGMofyT6UtSbEYUvmaYMYbgvdBedB8fhu", - "lpVault": "C2BmCbdCBBGxBCHxfyU1eD1bnEi2vBQMwBCHtiiiqZc5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3y19brFAFeP6fJo2qTihcSj191kAX2JPrB4xS3pSSZXk", - "marketAuthority": "8TQ23S8E3dZAu68Duxj6bGFRv7qAVR41aKdUh6YNnKFP", - "marketBaseVault": "nmqBaf8BxbsnMHnJB9d11SsgZYzvAnANeN6s9s5xG9P", - "marketQuoteVault": "Gd6ZTrLHAYjPCoGFkTfpuCir9mi7rnTQN3Xgq1jxAk8B", - "marketBids": "3x9Qo25vUJQLUWin3YHco4QNjzfajteV3HCnPAqE45NU", - "marketAsks": "FwFdJgt31yaDcWCjp76brSEqYK9z8jfA9GuBBZ5piRsC", - "marketEventQueue": "BWR5XWT1FuPgNVL4LXJpk41ArYn8qYJxF8dbPSCnPrgY" - }, - { - "id": "3eqFd4vQF9sHPLkvxrhW8Q7LTkRMPtTdMTAkWgw2Mbd3", - "baseMint": "BmLvq52WKMb5MYKLScay5V9C4Sh4E67zxvwLbU6i2vTR", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HYT5yHr3hTo7jHRMvUcCUEogZqnjvAvbni6KzGL95Gw8", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AU1Qr4uiVGriA8Z1NZemWS3j4pjtprMzHasLEH9AUd4A", - "targetOrders": "GYzfNTNnwZSLPdjyezvVstU6k6QyrbmLZjAa8caReC4d", - "baseVault": "5tjC8H2kV147c88CjHAjNj3PV7JrWW486aXjKM6Rq8oz", - "quoteVault": "krp38FwHn9Td1UswRP2W2VvXUYWcYRnJ9LQbRZX2bQE", - "withdrawQueue": "DsAn1TKirwQdUvvKkgu7s5vRcXFhXcsc2ZJ8Qqr25zdT", - "lpVault": "HZ9ejAYZZjMvA4N3xPRFUsVEad8HVbTKpittjpHJxLtt", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EhABxYSBodQF7vz6D633cxCG7BSK1S6NrNNPVMSpKLct", - "marketAuthority": "2mkyhFcgUC9LybP98iiUSeHQWFdndiM6ZT5D7h1H2JW8", - "marketBaseVault": "74EDGkqSraADnpikaPJ5wfJHTmjovp5Q5xc5YJkzgYsu", - "marketQuoteVault": "3QiK6PzSgcbmACBJTsCZTgJ6btysoyyT9imJ6Xtdtms1", - "marketBids": "E3YzBMwAH81sWyPN6WKbghS5RwWTMBUjp5HZmzxQn4kD", - "marketAsks": "2wy8B8tffDUzj14tZ2dT7VYdop43odjJtkJJDWr2LpZt", - "marketEventQueue": "5eWnWvLeixoPZCdqwDHzEFDPhVxxQpcAv9KpDuLmeUcg" - }, - { - "id": "3EtE2D9aNqXbGNeWw5rYvt9ti6Rk9L3oudBoRbjrgfDJ", - "baseMint": "HDiA4quoMibAGeJQzvxajp3Z9cvnkNng99oVrnuNj6px", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CFo2to4Mnvg9rVFd6XhD4SmuLm1HauGvbrrs6oE3t47B", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4o5fmF6iPfTDYoXgdMfRZ9xCDjakUzP1iokaAN8MU5u8", - "targetOrders": "CzMTSPniHVdJKDwsZXx4dEp24CrBpodEvCvQpr1AbkdV", - "baseVault": "2LBBf3mR3q98JY2gAW2uCTQCWfneK4YbaoMMbYVsML5z", - "quoteVault": "BFR32FVxwiyccwF8bkbmgChYDZ2WsZz8hyitUMcQdquD", - "withdrawQueue": "F1JVkTZEGJvZbu4YumhGP5CR8h84Mz4HFCP3StRL5DmV", - "lpVault": "EVFw2voKqCE1V1bKeWtokAPYauwLS8o813QWtbjAii37", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6Eu4eBGdktLdyucUkgFnvYseReaDeQ4V56uQ24QNcSWG", - "marketAuthority": "3tdx1GsCAkhCTVQMPGLLYZdPfbME8MAiY9KY4mCZGmHH", - "marketBaseVault": "9fadjoyzqMj29y5d81YedFcmsiV2k78RvYXSttR4kEmh", - "marketQuoteVault": "5YaJbNi3Aw1m5XCUEwkp1QAyqJxrgA6ZPjLQ2L4mzxav", - "marketBids": "A5iGhSY9HzJLnHziMotXpNk51vwsdzcCthTskkkeLHbk", - "marketAsks": "CNGd4LMnnuyiDQRjzPWdVf4gog62JjoaoNvZQddoxPSf", - "marketEventQueue": "F7HkB4dExNHr4KyedU5eAoVhZTBQLrupV79t1udDkhPS" - }, - { - "id": "3EZxBEiMJFAGuZsorfchgkbfx5vVZb2VHEdkH7xaKW1L", - "baseMint": "7YhfUG27m7ceDCBnB48dGy4mAJab2hqi6YKkp9Ho7ybv", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "JBhnWi14jLtkE7Z8a8UanLbJ8CR326ArNt71R6VvTvGg", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Bk6RJLHy6DZy3aWz7tFzgMbcDhdoBkkokui5S8d5edi9", - "targetOrders": "76qGbtJ81Qek1ztUnsnnDbzd2iiTZjZgXStLX4h6rzwL", - "baseVault": "DLtJzzohPJt1UscjpZv9CMJgZdPTdAAe9fMu94DhhopE", - "quoteVault": "2jRpVBmRS2edzw1tGgeSvK56yZAx5yDcpgv48iL6hdMS", - "withdrawQueue": "FvwdbUJLmGcATEVKKF2Huqy6DrB535PYEiYgv2GJvkph", - "lpVault": "9nJRrkZv5bNPG2qQ4XXJ7VZMQe9vYxyMXeFNkd8BEr3U", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5a96kyBNKh48c98DqshgaZpRVt7bfbWrjEpZcW8KFEUB", - "marketAuthority": "28AWzsoH7mEd82NMfyJSLXSBq8xX2AGRnkH1ZH5uqtNp", - "marketBaseVault": "4LbRmR3WD3meCkACoSkb3x88PgAEAoTSmtsDszTZira2", - "marketQuoteVault": "6TVXXQACxehuNSVsqVcPHFwDsQg7bKLUSDuTDDmYeZK9", - "marketBids": "69sMXFWgYhqrUGqfiFYNfK9h6wzN7yssWz7SqWGS5o4S", - "marketAsks": "5ABfKhnQFF1ttaDqGoS6zfttVW1pzw13m5fagqrLBcW8", - "marketEventQueue": "AcjJoqszFjYw7ubKC77gcFr3fopQcXwmAcZ6CmLud5ER" - }, - { - "id": "3FLLNMpdLvPuAZc3iDsSbUehW6gRGwXwCMHQpx3eTJt8", - "baseMint": "E48Ueg1o9avL5s7XBjfLViercSrNSJCvmbZMvnwN873", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "C5aRAixEVcmiXkoHLfin1SUuobjtqTGykQ7EfTt2E1jk", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ABh4jtkcokbrnwKWVTNDQKoehn6RmYQkaC9P3B3vrX8r", - "targetOrders": "BQKMdwb5h5bg6BjoG2YWhwhDn9poY1TZTFX2kFP2YYYK", - "baseVault": "3rXqXQZTvaQ2cbeCCQeRbvTbjkdwhsmhmBEe8Asd2gc3", - "quoteVault": "ESGYJ9EfHuTRSRHqgeMtN8UQoeTGCZjj8wAE6GWHgo6S", - "withdrawQueue": "2t5ZAPCZHcUKnHZ9iEDi58iSyUqvMohUE3PrRLP4rMd4", - "lpVault": "6bNPdHowQ4ZqFSNXeaURgaGEXi1J8swaQZERQUcDmNH9", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5WtR8r3P6yrjnZiTJUUrJNQ6n2PfDPuVTfFV4rKrxymi", - "marketAuthority": "9FPeSbqNmFBXd3qbXMPLCmtSKSAX7wC3PQzxsej76jMv", - "marketBaseVault": "HbeQf3NvHqii5fBZCoU5Qwy5Q2j8ahJ3qnGmdoLNza2m", - "marketQuoteVault": "Emkamgg3ZTGvz5CdopePvfKc8Pg2DMxAoCswjMt2B9fq", - "marketBids": "66LAW7C3hR96RuNx6fJLmBa1uNzRHXuxY9nKYPkaiaEV", - "marketAsks": "Enh55x2bYfJjxys47RGq1hW7JYUvSnD1LMa7XLHbEpvR", - "marketEventQueue": "D7xRukhxioqvjUFodyXzthWXnhKW3SZoFHfd54hY18Bj" - }, - { - "id": "3fPw9qTp2U5qPo8F4UYL1kfAet1AeMmXKicLHSDBaBqy", - "baseMint": "bonegFPgrpZ4bfVn3kQK1aMbGYddWtfMAywNt5LsuVE", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "YxFUkd8xiLTNRcMspfMTiWsY4hfajir9vNexqntUje2", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CVFq9ywAQsZ3iWJ8pfyRcozCArU4rw2KYtnUQL2Mqw97", - "targetOrders": "GW3BdZT5dCBtzKz1bk7yh1XUBfzsDzVe1ijeCGUDiamf", - "baseVault": "5o2QW5qwErMy4PDn3kbZoeWEpR629sLXYgZkJyFjgTxz", - "quoteVault": "3dHwgNSs3vRRxbdBNzTXv2HzrBVDNHCPFpLEnzfNPPhA", - "withdrawQueue": "7mqSGvb1A5PQeK1QR3KvvZgCCpNksn1nDcoHjzoa9ksL", - "lpVault": "7admg6dYLuaMQJsmr7iXqjKkdzSqNBsmqXERDhNwd3Um", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "C4zuS7w9dAZ823DQxjJZCSxw2fB7vHxvuhbELvQVURWp", - "marketAuthority": "8yEbnZNXgwHjQDi57NBTmuxrcrhWzfTKqJbKkzJXUTfU", - "marketBaseVault": "6QHk9RdYj8LYZzio7hQtqCZpmkenaZiKJy6Kj7LmorVC", - "marketQuoteVault": "6YoCYkNMUbsMmnoHiyYghYz3u1aVcdGrMm2eKCaoisAz", - "marketBids": "H9qHvg3wCjs1eHTnpjtBFrTccv9veYvnd6XBdTnfSPzm", - "marketAsks": "5hV77nhNU2pkDgHVuuhpz321WMjtRLBeMLX7DVvvvJr1", - "marketEventQueue": "E8pnEPLfqdTGTuAGevAcwNvtGPntvYMpkSRc9v9EL6Ms" - }, - { - "id": "3fyxFhPCB7pYZXqcMS985d2xJ92iKWnApcqZei4ZUkiv", - "baseMint": "BDxWSxkMLW1nJ3VggamUKkEKrtCaVqzFxoDApM8HdBks", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Epxjb3u9jjSGAdxfjLTddHgtRHFi53aBPAbNzJ8VG36i", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AH7j32CMTRh7dRAeHVXFwiNGqmKP3uYhiaRvPSxMzQmE", - "targetOrders": "3HWSrCC7xpc9ESRzM3RAGRUmBKzaF9oF1xScY6eJaU6M", - "baseVault": "FT1FGQ7W7gQ1tyUQJLzjHi7A3UUTGj3BE9rJCZhdBS8W", - "quoteVault": "7FK7GKfcPGUDMMY5EKDSr6fos5UVJv2GnC8xGs3FuyEw", - "withdrawQueue": "J5Ru6ov4ZFJ7WQtfWVanvr7U8Hp7g87eZMSWvrkww4TS", - "lpVault": "2C6WUdyDb9RsJopwbA5Skn8y39x1XFD5v7r7o3gK871i", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BF7GjWYv1AS9cDwRsdhHGrUanoYtQvZFPUQ75hnsRRhc", - "marketAuthority": "afeNV5rBbX7EDjdfhjcdMzrjvdkMyAPrfmUtspsF8ir", - "marketBaseVault": "BHMP4JNEtzA4QVzp7BGCtGBWZEyZtSymUVtLNhYhGNE2", - "marketQuoteVault": "Eu4jhxPKbfuQ1keyY4X6UBEBRBRJfrep8ceohqHsDUaJ", - "marketBids": "BN8j471nizcXxuo6PsojZ77A3LukdTK2Le1PcGw98Z1b", - "marketAsks": "4JzTjNhwaeMHoZonYsavvuT7oo4q3RvGW1cAZ4oXmckB", - "marketEventQueue": "5VfU3fgiu3jEx3gtB5TNkGcgFu6XHdaR38zGh49bJCap" - }, - { - "id": "3g8ZgCvYZ7J2oF2kgzDtctoFZvAQrxiktyYY6XwSbwEq", - "baseMint": "E1vVoJmfr3Jyvwd8iFB7F1u9uwAeFNqkNxfzybHNyHuD", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4s2RMHYzMxQNCzWweSxHJRirmt34jghGKR6o4o4t2T64", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7TkkZocbDaH3DjgTYnWwFA5aobyJCQDhJwkDHqip6xTQ", - "targetOrders": "E2RZNv526fvVEbZtjrj4xF5NQZTHYqiiimJkg6juwSt4", - "baseVault": "Dxmpx2maKr5Ys17C9LpV9CpHFDdXdbiU9qZQZf7CXyiK", - "quoteVault": "949oqXTADrMmZAi8o5vQUB8QJ1kipfJEAYb6d9ksEWsc", - "withdrawQueue": "B16BnRouogHv6goz73zboFduJ24B7qLfgfuC4YfpXp2y", - "lpVault": "ciYDfZrKZXs6pn1gW2uwmCsSBct5YTk6CNNFZVA376A", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DiLemjZd9wzLTy5QaZpJiYaHDhE1FRmFmRAUbto3RpSC", - "marketAuthority": "E4C9QDvZSBTTyTTrZ3hoKstPJhqdFiTJE1446s6LX84f", - "marketBaseVault": "ArVvXPwQSDRjt23sxCeU252owkzfye9T2o3ABQoPeVWd", - "marketQuoteVault": "6PUbphtxRckh67nuVqsUrVudNeT4DqgqQs3oXdSWdcDu", - "marketBids": "Cetgih1ThDdN6yyTygD4CMw17wsHtxuqcn2qoBzokPKX", - "marketAsks": "12pFZXcsxNpqPMiTJcw8AcWHJU1QF679HxPuURpcJY9e", - "marketEventQueue": "7THWkzZBSmbPK95sDcUr2mjP4WnNnBArCFyevHubyV7G" - }, - { - "id": "3GBxxrkoYPrAfRpn3gLPE7FURpS6nFW2AuxSPwRqKmXC", - "baseMint": "usdrQqxAGgWsBRzzcckAi9ZAzHp19rFCNn87p4Q8Eir", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GHiyM2rVQioGcSsBxLcj4vJWDrZp2ch9AuKtJKiEWfCy", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4Jy5cAKRETvXjTtvbYXRwwZVz6TGZmJQnFEFN5L3CeMT", - "targetOrders": "Fojix1Bs8EJEFkZ6ihzGqECtN2Nuaa6wX9QmkZJoDnuY", - "baseVault": "7ydoifeY75hgioKsLdyc9BEk5KDBPJgKYDko5879qbcQ", - "quoteVault": "2LBUBTC1HyqAYzLWsUQ4tNdLYcRDYDXSgFaG3zsU2VES", - "withdrawQueue": "6koQbnwFXUxq8JXxeqNJ41MyThig9yXTKGs6Tp7xWs28", - "lpVault": "682jKfDC9et5oDuSCuQ47nCTAXsp9s5VWhCzNbcPwRuW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "H2LRDGfmmnLNsKpjY6xeR9gNNqgmaKNTTrpsxaqAsQ4s", - "marketAuthority": "7R6LZzEfMxNGSLr6AxbX8XsrGiNgxmfBpFtUrgJVmHkq", - "marketBaseVault": "A9qLgYLJ3zaKjeeFwEbsPQbLabqvWPA7Qy2dzQ2nSj6J", - "marketQuoteVault": "6VM5V2H1pt2Tb1thjWV9YxMiZpHnAw2jAd6xkEB3AhZp", - "marketBids": "5uRXNpDXWhHb4aZbMsdohWDhgFyjyabjAZd92rnQHC8a", - "marketAsks": "5PD1D886cbCTUJcB7zJUkfpn2a9iNaoDGeWfkTX9thwE", - "marketEventQueue": "5t3DcDXUk2gccE4kd8drV5tiZBJGpgn6VzrLVtgqJ92X" - }, - { - "id": "3GREHom2s2KRmxfMGRWP9Ziau3kTc96134CTVYxC4ZzN", - "baseMint": "4o67Pazc9fNqEfQM66xqWngw7WdAUzsccdpPmKsANDg1", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CN3p74XsoBhSPQa8XSpHRgSWBF2qBcamGPqvqP7Wdjkk", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8SJwUF41GT3tBYfo1iRyTnrUrGhznhbCKrbJAyRnzJ1b", - "targetOrders": "9MhdBNYRrrpHRNeZpA39JXsRzgHrpvWgpFVSNk3Dinoa", - "baseVault": "EyERtNz5WyAciyEEKQtHVhY4CVC82opHa2be2cnrnAV2", - "quoteVault": "GibNwAdZ58JKbSLTjX3gvEK8LfLE8EMqCc4ZbeV7AaPG", - "withdrawQueue": "9Q1N4bFyM1UUncBjkWrPQqyPDSA7JgzMDKFd1KwjLKQe", - "lpVault": "BmuXPiEhQLccy6xEANiw2MpwvXNKwEG6G86aMs6eE64W", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9Grws717whPvGHYFVpuq67KQakidaQeGUQCwp5FzjD95", - "marketAuthority": "F1Zs3UxZdFYAHnmWEq5A1zdCqLtKFyNZ9m76RiJ13Bhs", - "marketBaseVault": "4283HgXUSNMH22Ai7An1EMs6wjH9orhQjkFvACQnkb68", - "marketQuoteVault": "CpUgVc5tA1c3YwhvtBar7MGxtYqWFDu317S1osDRAsHe", - "marketBids": "EWmBabEa5uxKihz3HbL6SumtjRwLsfeCTVn4j8uzNDt8", - "marketAsks": "651T97S9vvHYUaN2D7pySS8TCi7g9xCF8zhq5nZwL91g", - "marketEventQueue": "4KxDivJ9rCpxGN1goAEhV3Sjsu9Ydktjexta4oUEVNRN" - }, - { - "id": "3gSjs6MqyHFsp8DXvaKvVUJjV7qg5itf9qmUGuhnSaWH", - "baseMint": "So11111111111111111111111111111111111111112", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FxQssQdmSQXM6bCKdK8u6wypwJhUEWYoSZ1qRSDUHkdg", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GgiB7nWxJBTaLorLzn5CVDtbbuDRYwKoVdrSbBjeUQS1", - "targetOrders": "3HXoEhRnJRi1jk53XX5dUfYYZLUjgaBQZnRf3TZ5RNsB", - "baseVault": "9PpceUYfvUmKazYqWjqiU8nXqJzMPRwMrPYNFnnp59LG", - "quoteVault": "FtTZAjh8hP7PK5iH3FEBVAxoWMZr9ED41UqLAvFPy69H", - "withdrawQueue": "4TA5dnZ9B8yeZGQrA4By11vuzBKDa7N8aMeDtmXB8v2N", - "lpVault": "6o9qojU8behPdHXg7erigmyvDgnCpxRS1zMiirCAJsH1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "marketAuthority": "F8Vyqk3unwxkXukZFQeYyGmFfTG3CAX4v24iyrjEYBJV", - "marketBaseVault": "36c6YqAwyGKQG66XEp2dJc5JqjaBNv7sVghEtJv4c7u6", - "marketQuoteVault": "8CFo8bL8mZQK8abbFyypFMwEDd8tVJjHTTojMLgQTUSZ", - "marketBids": "14ivtgssEBoBjuZJtSAPKYgpUK7DmnSwuPMqJoVTSgKJ", - "marketAsks": "CEQdAFKdycHugujQg9k2wbmxjcpdYZyVLfV9WerTnafJ", - "marketEventQueue": "5KKsLVU6TcbVDK4BS6K1DGDxnh4Q9xjYJ8XaDCG5t8ht" - }, - { - "id": "3H6oFKAHmQK2bP5jA6HfuWhZ8HDbbEc3Jkh2Fp1bRnMS", - "baseMint": "6c4L5nTH2sBKkfeuP3WhGp6Vq1tE4Suh4ezRp5KSu8Z7", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "2Gv6TfdMfTUeS85YFvcukZRdsW33DQedPbPdERNmapFb", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CwqRYxuq2iw2aeacB2CRaDp5yS2eLSvK1krr6WSGabxG", - "targetOrders": "ctzMJCnMup6H6QD9AJBS3to9tbV1kep1X8dK2eQhi8J", - "baseVault": "J4kRen43SHYCp4r2e7iPFPTK9SFcMqYNGaiqF8RNZSJh", - "quoteVault": "CFiyWAWWYWkvXxD9vdmCi1uhptZEvE2ViETTKWdqZdxk", - "withdrawQueue": "AwKynWWCPchLqnC9MTZUXakPuhPX4YyrB2NKVEPBa5X3", - "lpVault": "3QTQ1zozpZFnRfC1KwqrLdjyx4TrGAUhDUT8k6vhb1tB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6piWpXiKDpn7XzAohbDQJCFmnevodATayWR3RLnUoecH", - "marketAuthority": "6fQyGuXUSdcEYvcta9T4oSkZ7yjzjNSCsKUi41c4Z2MU", - "marketBaseVault": "2TJY94Qdnbzy4UmmwngLvjJeGvy3bejb5cfMjgGvge5Q", - "marketQuoteVault": "G9q1bWyx1foMGeTCdcQ82GfeSAQpt6resKxf69kSC5Dg", - "marketBids": "Z9H1KSNiiD3JSPneTdp7GUkSDbz3U41Lmvzu6gsT5nV", - "marketAsks": "Cxrt881M41BcesyozpbCt7fWqH7UxX8LK8YVfAAJwK8s", - "marketEventQueue": "8VGi3mSnUrxHoVgCaGWrxyUP3AR7p85StQXGGe8ekEXC" - }, - { - "id": "3HMjQF7QMPF6xwie77rveDJUc1NJqE7YUz6EM4m4rTBi", - "baseMint": "AmTEnQM3e4ayErAsbmrgTdznpYD4bN2K2RghEb3ZENT5", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "7hqukrZ3ZMLeDY7pcXr19bqAhza6ETXezTCE8M2J6aSk", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AMdqV9EpYmrwzLwYyrf7kkADnrSfpmBZ2dQiSFDHig1W", - "targetOrders": "AqvvqyiKwME1n7oaQbABuWrzxBQwUqvc7MZMLDZ91EdE", - "baseVault": "FAaY7SeTQ4aCmCTdgWtY6AZQSmrP4hSBTQbFHA9Xi62K", - "quoteVault": "B4Pd6trJDDokBYgA83Ptn9NxAdvyxLtpWzEND4MqydQH", - "withdrawQueue": "AtGPAHX3bdT3kNxVdXzfbrDsHdpS4iJDk8YF4oKXd7Rp", - "lpVault": "6AQh1Cq5tsAuNyj7XRFGoFYe9co3YXukkL9q4Sx4vrdw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Bdci5uuz15xndwH262BDkSHsWLgGXQzfwyae5VKnK9Jp", - "marketAuthority": "EjzKh8BK1EadoomjfsQa35oYgbq4PioGZh3wZKi2kwXW", - "marketBaseVault": "Ag1mQrVmHdfDwHx3irDSonMqogeLwNLxW5jV5ZgkYZ1Z", - "marketQuoteVault": "2LzZApcYmQHF9fNGX652spzgEhcFy9q7DVqC8AhdzWGN", - "marketBids": "F5z38FPeJde3pdZsENCiSMPxovZmNJ2bdwpNimDpnYEh", - "marketAsks": "AWapr6BeMGRfkTYyzSTcd9sAUdSwrqH338KFfEuYwQza", - "marketEventQueue": "GdfbyRfdNzwfEEt9B1SPY6fBGc6Lz7BKGoM2Ciy6oAKq" - }, - { - "id": "3hTT3MZ7njxfQsWB67nijMyLTtpWLtdvLtU6qYEU3V5A", - "baseMint": "c8JyuF2fD84G6Vk4AmeVfTUoseNRmv2A9JpymAXi4B6", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6FG367jvYkPcGZcBt5Bezbdbxe3bBMbhLCxSxURN4gp3", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5wvmhuW78QEMfUVpYjogxcHJPaYvsZyPUZTMihfV3d59", - "targetOrders": "8h9UDhozhsD9KHBDoymK5wryp6x6yWvZ9wwYMCicAmkK", - "baseVault": "96BwibsJhYAGVZcCZyX15AzFGXYNxtfF4Zov5WWwmEj6", - "quoteVault": "CofYFFxGheGVCFS92dGAdTnVADmcbt22x9vwQ2Vg5P8K", - "withdrawQueue": "Av74tms7RMxtFntCEUVimEBvztVdDh8hLS86zwXydwYb", - "lpVault": "6f12p9J1wRctyukbg4Cv8q6F8jMoK9vfYURFv5vE3WLg", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "E2VRQxaVq6qfRBqNCVmhS5oqvJhyh68KvgdWYujy8jhz", - "marketAuthority": "63DDR6Lg4bdnLBWmeejdjzEjBRMVZUC8u9Aw7aNry6aL", - "marketBaseVault": "89AaSkFeN8jABmHTN8fiiJKV7FwuaFSaW3No4maFvZH1", - "marketQuoteVault": "DdsjVq6UdiLLnLYmHjJGCa6C8B2qoGBU8EKtpBArdWaM", - "marketBids": "2HFTyqwZ8WRu9fBHnQTf5fWej3hwbMWak7ae32Pyvvxy", - "marketAsks": "G6dTd5ejeufxtnkVBhgCnSVsS4utbi7Y3Kd2b7NjpsJh", - "marketEventQueue": "2mXugA4tfsCsRZufkmKaetu8hn39BgSZeDCEiXi3FmNF" - }, - { - "id": "3irczW9Xzk865vouYAMjqJExXCXhtfj2tpcwBA7FjGKV", - "baseMint": "GZNrMEdrt6Vg428JzvJYRGGPpVxgjUPsg6WLqKBvmNLw", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CP32Mse9xCgsGt9w3oJAvnVHyHPKvbEKiG15LeukfZKw", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "JCtk3XmpX9Km266wUeedwBd3vDutoaLUqxewLjZi91Zn", - "targetOrders": "9ZE7CQFq2M9LMuHhkS4FAXEzb6XTHM4swo1fUHcHNxev", - "baseVault": "ENuYWWzpApQyGvJnh9Y19r7M91ocETBndqB2sntXSEBF", - "quoteVault": "AkJDiPK6RhKXbeF4ecDkyAUPGqtnoXpo7osC8XTJnV6e", - "withdrawQueue": "JBNeUEKUpvtw44vwxiKrKrTbGakjikQyFJjMPvW4HVbX", - "lpVault": "3F7az3skVEtYd3MFcp2g4VZTkrcQfqK1D1eW7YpWdkTS", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9qJegMfhL8TMzG3TiHipTR5Y2v44HesrnHKq6Rsc3KqZ", - "marketAuthority": "CZz9ieeHqHzXHvCxjGeFkiq1rgtSW5uuCH6S3Yfp5kzK", - "marketBaseVault": "EnLiPtq2XAdzBU91DJKYNuCfJj3hYJQ9QCbcy92KkpiE", - "marketQuoteVault": "Hf7PPszENVXpAoy6ASnNEkNHf9Ly94aZYD5DNH4WKE9j", - "marketBids": "8NPVTkfTEBQbMKUFofXcGRN29jVS6DxNZV8P2gZS46JM", - "marketAsks": "AhnGFNRuyf3SD8E5GdRbh7Ab1yf5KPQ3ihgDTgbnV8gP", - "marketEventQueue": "7i5xdVoWJru3s1XVw3i9kbKkRPwrm2UiLG4JTjWPzexa" - }, - { - "id": "3j9ZWvqcMuEpTsNv6QmuCHjSHssXbyyMu9398bGVUckH", - "baseMint": "GJQ1iDoPWWo7pXeNKhC9BLD3FHL2tgFEVGMHYGEfQZT", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "12FQHsVDSV9PFiPd3wfnU3e1gHfibFwmepWh5ELc7ud9", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ABMJXoE577aN4nV9p5VDBFHmN74zv3oi5ExCBXWeGtQE", - "targetOrders": "8vKabiRpHVMMY2UpyE79a9ioTtA8V4PP6nwx2v22jz7r", - "baseVault": "dsiinw7PH2MsBykTA6Xe4NYYuExxz5vEdhuwGSCogm3", - "quoteVault": "3qJ88a4ZBJGgmTBQ71x2em2hSGNHUTAQkwZ1pEGVHB9L", - "withdrawQueue": "6qhwdhY3acQTmCPJNP8iSw7PFJ7QRYwzPJMemEaK3ebD", - "lpVault": "ARkYsgkhruXDd6sg2UCTDaacMiyB7bNxUwg8K1ygVqx6", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3cN1aMUUCyDC8VVcSyoC9ejAaYFkBKp65deCKJfbH7pL", - "marketAuthority": "HU7qn8waHiWFZdRvdr7WR6kSWSABkWKHwYaK8AFsX5Pj", - "marketBaseVault": "6w3MraymQCbdvd4softTnukayoN1ZRG12CJmee9CvyNp", - "marketQuoteVault": "3qQQ5AmnCJtQhwp6sVzbhiEKBSYeZeFvmP6NFwcH1Ydk", - "marketBids": "GiZuhDYXfwf7Mw9SH2UdxAahdJbKyAsse7oEUnXUJmpQ", - "marketAsks": "3HHUQHDukLBTP9n4i1riYQJPxcpeqVknU1EJeivtySY8", - "marketEventQueue": "9z8bpDUJ4rp1twAhuc2kqTWuyzcsSUWQHCSULGadaxGh" - }, - { - "id": "3JBesA5BQ2AcXAXbn4MRj9jyGoH5evG5hNC52wjFKgG4", - "baseMint": "E6Hkw5o48QfNo6iUi1aepjEBzVq4ZjQLxh7xVtdTqoyB", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "2MFrYsTJbaPk2fRvpruTUKH56e7qkpcMCR86KPnJBWAT", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3iqfGXEQFBdiwjfGD6aqnA4XoZCTLTv4vLyFkEPmTEfG", - "targetOrders": "6AQ9uZiDuQhA7u44yCY1JFZHhp8zLSgQbW2vCqqRmxfH", - "baseVault": "GVsprQpcEMc8VDSAYJjAT3YDuVju6obDd8JuYkpbzUF2", - "quoteVault": "DdyTfJTDUBfzFp1f1vUZqryTHSgtoczPwrJ2DPEVWQv2", - "withdrawQueue": "EvksQzwfRstwA271No3TeGFwrKa3tG1Wcrr2PfgqjsCM", - "lpVault": "Dtc9vP8GriotLK8mik7yvzurFYrrVhaNmZc6APwCYGxe", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HfinHVtU8UdVkNSy9gfkjuRNvPrMzYqfDNzgxJpKMMuz", - "marketAuthority": "BSvNSwk9jaazTXfC3SZbKtGBXCjxnJaPZNZZ1tdb5Nox", - "marketBaseVault": "52NsHUrb5EameWs4ZntgcYiuYqptgwr27bPUoTARK5ux", - "marketQuoteVault": "4ujsRvyTJd4g81rRmwWNziLMkvZCvSwFvDgPa4JpeWTm", - "marketBids": "6fNeENpdwBTg8SZ2HtoqVEzZf9jyoUHMXre6Dumhg5BB", - "marketAsks": "6aZfC5mcXiBsaEG98Tro1DisQycsLwTwVGVxARLuYHr", - "marketEventQueue": "ysYzoBk5L75pZUMxzouZRSboo7iANDPVL4wChnSZ4X7" - }, - { - "id": "3jyrUiAuUWRtMcG6DZT9MH6f5FxbAL45pj1EPm95gYhQ", - "baseMint": "Dz92DHvq6Kah9V1xfqaabSogWQU16tesztpo6QjXgjj1", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HuNTX6JCJezahNzf3aJwEVXJEvfd3f5ffjrnXDRAHZmm", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8TSC3v8Zv98gFTjcZbrUkhMDa83ZWVvUQzXawcFLaBY4", - "targetOrders": "9NL6EQF5w19WZgopynG7Y5PCEcy7LR698rAVp3VqBszA", - "baseVault": "9YXAHQdm5aRoASpXJ8NEfJchDtSAJLAMcmPUet3Wkd3h", - "quoteVault": "EjgMok1RYc4XyVD4cAmps2qzh99F9w4gNcZ8NixvWTF9", - "withdrawQueue": "7ttDsrtKRMbhEt3fwSE8X9o8QznhWAGJZdSTkdn5rG3c", - "lpVault": "AktA7NgwvTgSDwCyXpRktgFcGJapVkzb8pE1rA6GAJ9c", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3A89kgG6ujwVwP9x6ivk862kJECzPLGq9to8pChdeazF", - "marketAuthority": "ELrCeWnSD1qWwm5uGKt76vxqUmDJaxsYM1KEe9xoRFZ2", - "marketBaseVault": "2H1GTHatgS3FxPDTB22eAD8iFrVqP5PDuGShYqoqRTot", - "marketQuoteVault": "Hy97nHqWPuufV1LM2JBtzz6DNn7CykKvzkRSJRYf8HB5", - "marketBids": "Eqv2ejN61AH9i2axCe62f5PdidZy5aHqvdNPEjupe13W", - "marketAsks": "2pEWmroKKYPNgFKvtjV952mfLpL3yGdngPy8vNtCNovV", - "marketEventQueue": "Ewn6z6U13eBrXRqr4nSw15PmsJcJVvmW85CTp5MYwnrR" - }, - { - "id": "3jz3bzPtsQonPuuBDsmTKKTYiyoc7mnEgj3ymoqNe6eW", - "baseMint": "8s9FCz99Wcr3dHpiauFRi6bLXzshXfcGTfgQE7UEopVx", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7TCfExT3pp5WWEc85wZPHwXDfU6KXW7fiZwtmSqbXVtz", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7LyyvGJvQxqi4BBTDj7MBR5vm9Qw7kxg7hyhrmgVJ5UZ", - "targetOrders": "5dRQwseRUs1iUoGKsya2Rr1o6v47psEcKpk1t4BZrFCb", - "baseVault": "G37ipdetYGWrp86SZ1LC6yUTT2kbFDbRpySZRMpNZ3WW", - "quoteVault": "6CDXF4U9zQRT51GpzkCsPUhBVJrLWPdm4L9Egvm78BBa", - "withdrawQueue": "AEH8gTWEYPd3wXYfQbDSdFRCgeVr1kuf2x6sXqKSurL1", - "lpVault": "A2MsAXhQHqz4WzuiJATWJRHPkj4rhg3yDa5t2XE7GxbM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Bwc1TujgmRisCLeFWYw28Z2tvg5egZ3L5W4ezoPLWuod", - "marketAuthority": "Chok1FCaBUdKEiCdQqh9hDpEYcpziwzbm7cLfkxJzdL6", - "marketBaseVault": "BdZbEFU9ZjzRwtHWctnNTgY9tJUT5wqAjZQknqL4mw62", - "marketQuoteVault": "A46agyLaSYP5hNy6y6AFrf58GxN5MR1LB8Cd62ZNbzwP", - "marketBids": "AyU1ueY9NQknW1suAvDbGmkRV4iVexdw5HJCGZWZ8rtF", - "marketAsks": "bnZ1AJuNteAmQKh6r21T5sGDxM7EzWtUi61Hh28e2D1", - "marketEventQueue": "5Fb2odHScbK14QXQZsFeeBHAbwNrArLcMkQ5VR9r5ere" - }, - { - "id": "3jzjZzZNyfN34unzGHnfYxSyQfJktkg3tAhmHyo8w5QG", - "baseMint": "CY2E69dSG9vBsMoaXDvYmMDSMEP4SZtRY1rqVQ9tkNDu", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7NKtbXuBW5PicCMzqbVTGFWmd77hfhRiyST3C31VX4LQ", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7KNAbJRmh21jvU42aY63xCaSmoxHE6sGg8qHwCBUrx99", - "targetOrders": "4N1bTL54v3X1bwtwUfNTKPc3J5nJ5fhaP5AMfJwwXH9C", - "baseVault": "GpBk6xK3LXazCoCu8P2szXCjN2NoFTDTZvUA87ZVKuS8", - "quoteVault": "EAEugvQACL1MuEFFvna9zR3j17oHszbvrc4fWJXusnkh", - "withdrawQueue": "EKEQX75CuA2oK9KE3SobWoSGzWxdUopTu6NdaGPdTieC", - "lpVault": "APrQk4wGHqMRtnyGNJxUnBHbe7PNNNcCkfWV3VCQwTjN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4oMTpkSYkrrBq8zxGwV9QDTwK5d62r9R4ekrmBCqDp8f", - "marketAuthority": "2iMzfutwJt5ricBBG7sN7pry6friFFzddbVzoybA9fLV", - "marketBaseVault": "F63NAvNYJjjjfiUScNRE8mx97mYuUKDCy1jmXwt83gEU", - "marketQuoteVault": "EjBRE3M6bXfQS1AUkRgyMiMD1E743kK6trxiynNTTsbu", - "marketBids": "E5KEGxpboiB1M8k9jEkpdb9k1SQ7JZdVKtUapxda2hM5", - "marketAsks": "Cs8jQTrWETHpniQVxtedHUwJwfD5tDA8hcEYs7uEfXuv", - "marketEventQueue": "98G1zmorTXkjeiX9Qz8MnFyyT5hTUE6GN7caAYhsLE5a" - }, - { - "id": "3k154DunyhiZ3ny5fSRCqptvd4zbhAhYXU48ZXdMyv7s", - "baseMint": "ankhim7kPXxLKVbW1Tn7vH4mLTuvCAqHjhkKuvwWJ7b", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DNih1hgktApoZBUCgVuu6QRaHJUvRL8pGj6u3VXUSi7V", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2YDp7n3zCWgn9LU8FhJrPuFoApGJ1wP8b8wHQqHJXP8a", - "targetOrders": "33BzTgrG4syaWvqjhMeqfQcU8kgGhp6BGcgyTtqgr6xd", - "baseVault": "9ddCWVSNfEzFGiiUJveLo9JiPLBCXvB7iuY4sjioHjjY", - "quoteVault": "BLVn6o5879gxDt4Teugeefp3nuDhh2Bmbsegj8uu4wUh", - "withdrawQueue": "EFeMHZypwUJ34UywzBYRm5furRMjoqec6FhW6kGPTUUb", - "lpVault": "5FmCr6fFmieJ3mDMGF5jkJpFdNp29eCANrnwRy3fER8B", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "LgJKrXfwHJ2uFqkayPxrpNVw2Gdb3FQQEikF8kAuPFE", - "marketAuthority": "4cgiXy3UkspDq2axpFBPdKeyqkZyjGoSXhTVPxpua9Cs", - "marketBaseVault": "73Bh3ZLwoiEn5JLFW8hkV12HY6JzDTAkocssNf4SWkQc", - "marketQuoteVault": "F5RLcKAWVw4v1UjSgwAFyDj5Rvn7PdsKyvR8vkNXJmNm", - "marketBids": "G8S8vWroYGt4jtq1CV188GVhhcZdn8uZm46jdox6KWt5", - "marketAsks": "89VGTDsgZ3TiyA2jKp6BjVqwRWa5iZr9wY2QGy3A7ezb", - "marketEventQueue": "3sW9xjNR4zZbPUVNNegSQ3yZwBsDoxg8RbHR5fcDcJTE" - }, - { - "id": "3k3SXJF97iNWZZoxM5b7vMUuY56ZXcaCjeSDsGAizGq3", - "baseMint": "7CUJNc1jHfT9J391frL6CiLhwJUiFBs5SErhdBJ3KAQQ", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "6bPh55dqGoL5PgGfbrdxDPtgv82WEXRHxj2cxU3tnyNm", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AEhWzLK5Ekd9FqdA14gKbfPz9SLm745cwzghzpMvnppk", - "targetOrders": "EV9P8b79hq5swHuaakuk9vQesudg5ZN6m9jot4xqBmQT", - "baseVault": "9hyhEx5n1wiWzXJ6PK5eZntGcKkyKf7qBDk6TgRDhTtQ", - "quoteVault": "5aounKkGskFrgZnkgyC1kzZQE8p6awF6a3xfanksGju9", - "withdrawQueue": "7fDVXxsp4HPTixpPjNnv2w5AXneb6UzzLtSUDeQLAoWN", - "lpVault": "82XbjuXqh8zqzcruF85BZeDyNXEcuE8Ax3JsSHLaZ6eY", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7nzMzKicZNh6QhCPkxAAYjdV8keuJzQLTWzey4dAPTQh", - "marketAuthority": "FAqwija7rcgkUfanHcx3si3zLGrKWwXs9z4rWzwvaowS", - "marketBaseVault": "BHqK8DYanB4D89tFZvLpG982JAJ5h2pJ27sRhc6KJmAS", - "marketQuoteVault": "7GhNfyaYERQPpUQ1vTKsRRBiKuuKLJGHHeK7HPFRivWa", - "marketBids": "Aozz9CdQGpd9bM27DS3JhXZADXrRwtcXc53PktiGQpfY", - "marketAsks": "3VPAzmTDL1jR6E1wdtiZUbuggXaxvRR3d36ToH5sxtME", - "marketEventQueue": "8feNYR2GVvmPGbxUPgyujexQagFrNizBwVMMLAsdjUDL" - }, - { - "id": "3KrQFX2sS1ctfKktvhwvyKxkddUmG79mR7CAkWfoWT5s", - "baseMint": "8JjBJdV73zPPmZvkgC91ni8RsbXWTkhpuSdxeZgaw6hD", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "H15apMwx76c2nafePr6s3ndPXeYYSZRcaG3CPRpf7J8a", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8D8HvyxhStPpp5uGW2FSGQZzcLPm9QXF4Dc7E1wbARZY", - "targetOrders": "Ba3viuJrVyu6efsnGjdqCNmJxvpu7aaWxHEDVBVg4Fmd", - "baseVault": "3ydyrNsHFE8WzDaQq6PKzaxJjYCiE6GVs1ETuywM8Bvy", - "quoteVault": "51dHffWsjwdLjVSA5WqmuFUnjgoJurro5cUwcYzpoTuS", - "withdrawQueue": "3rGJg4GP6Po7JNpoBQXtauLbcjuMsucpPFUwgMR9MMqi", - "lpVault": "D9qLsfHaJHZUmgfq2aJGTRhkpDqB6dgdtkaKA83W1pKE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DyX44gTgWHdvjS7vy6xdodM6tENpijDTRSKbQA4FZgua", - "marketAuthority": "34MDeM3JJnrRdEEkdrqQZH6QvvA13eAWuHqXgRNhHxPN", - "marketBaseVault": "EGapN7wg9S9rhchn4Jo8ErSh72BGqshiurURWPWr6Yc9", - "marketQuoteVault": "3zS2x7QF7xUkE33H2ghcPYenvd2DsXHw7HJwkSVN9wBR", - "marketBids": "E1P5RFD2z4V98kr5dbErgWWFjnvWfuP8aWMkWWjf629z", - "marketAsks": "4GCEv4zBprwriqAMdJjZEJR9oTzPmX644v6vHa9pNFV1", - "marketEventQueue": "27S2wSYqEkMg5m1SHuMuRKUPkK9vBzWvMY9UXkQugH37" - }, - { - "id": "3MgVSAY7ALTnbM6ZbSP86zgKDueyAkRPS3sSTJgTzQvj", - "baseMint": "Ma4dse7fmzXLQYymNsDDjq6VgRXtEFTJw1CvmRrBoKN", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "52r4p6MRogVZUvotzJKxJ791dEptu847jnMA4TWiA44d", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6zuaxf2Jryr5qq2hFQ1PwBctvdwEQp3dPs1DeY3rDm46", - "targetOrders": "G8XnvZBhRHXwC9qSzopKDf9CJeesbCihmKhT2y2CvD26", - "baseVault": "9w3w34ddujx9VG5ZpFHwmecKEq3kiCpk5yx7nupFVsyz", - "quoteVault": "9jqgYXnpGhjZbprwgXxiYuV91PUyW5ghZsPSJRiXPZhQ", - "withdrawQueue": "2Qb3j8qRMjcDe8g1yvE95ZPBY7pokLNxMezw6rMxK4zV", - "lpVault": "EV4VNuwHDWe2zgcmofgm6TewNujvaBwvY9jr1mSGZL1X", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8Sg9bFtgJhWFNrkxW2KSq4SN8KPPwsvRTc7iytRDjD5g", - "marketAuthority": "33vVNt2MEWmSPrScMw9pat7ghbuDKtWLamaXu5ebcXrD", - "marketBaseVault": "G73cSaMF9kzy64dfUWxfaWELvtCTmmjkzRrL9jV5FvZZ", - "marketQuoteVault": "sy7uwPuBnfrGoE39PYo1EfctrdZKc214YAmJFCbYwyB", - "marketBids": "AvdzhhRQXVRhi2sAhTmyyzM3z77PyG6VffwgVPDm9NmR", - "marketAsks": "EXVrcA1pemMpy3deZmiujiq2RThf5tWZiPbn7D4vpyGL", - "marketEventQueue": "AVbQ3mpoNgjq8yjx49NFAHwejvzu3tCAom8DvQAoF5oD" - }, - { - "id": "3MqAq9HS4DJv7BhVy5CtAa6jeojFdw7NBTavc6Kmvvi5", - "baseMint": "H6JocWxg5g1Lcs4oPnBecmjQ4Y1bkZhGJHtjMunmjyrp", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "2UrwLH5LhzT5eG1huHqMpwoGzpfBE2WdVrgWmtxLi1Y2", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6HhBooPw1tERE3sFAn15tx7tuUKBhhukwJJijSJET6SH", - "targetOrders": "Ge6oCPB4z58mwyc41ZWwgPv8XwLu88dRAMZDWkcwHH2b", - "baseVault": "EuE73LYpFDdACzs9ddq83SSai2B78kgVu9EJrR7uA89T", - "quoteVault": "5hzn8243WEoykdp5iGPuzN3fiLE2W9vbpko6CCPFAaZ", - "withdrawQueue": "GCbUxDf933hLRnZw2pZAsUS1qgpzP5sXs5ZPZy1sAujh", - "lpVault": "2QF2RUCQs5xkBDGsr6zPEDKhkWSXAphWdaUH5QiHRmrf", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AYBvYyww6EVXdBn24MLh2KQUQRV464pXGkv5Fnr39ywv", - "marketAuthority": "AfJbS5vzB6N4rsNQkGHDANydXmP3wZ3VZUVkgz7BEtUV", - "marketBaseVault": "F4RJhjH4fFM23ZqeqhAy8m6veUvHVngSDBzU58PnYWYs", - "marketQuoteVault": "2psGfk21psZeDJEmv7zgzbBorw219UDUvNnj6GERQZxn", - "marketBids": "2SfzcsVR2XNuC8Kxzbd7pyP57ZsZpthqmFzFHqG4Un6c", - "marketAsks": "2eWtrBScup7pFcpT3MGiPmJaJAxrHrrBDaY7A2JC54qz", - "marketEventQueue": "GmFpU2U3aMCYpKk5ChwLs8t4YGQ4C6BstRYpV2T1ro9A" - }, - { - "id": "3NkP31mEhLvvn6aGZf7LmQk4kmH3mW6qE7fmEKMypeuX", - "baseMint": "BB33fYoeBVA2uv119be9tKvmXeuwtcx1W25N9KFNd2ca", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9SmrxEDnWfKRDqMXjNdQR5DsTjFs72AuJszRJoDKuUre", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GJvWGBF4juZYtoRfLwd6ykTvyQDbfY3ZmF3AmqyDrPQj", - "targetOrders": "2Z6mDU8bBEmWGWuJMMvrf6YAgDiRx9zbnsQW8xGdQ3Cc", - "baseVault": "A8Cer6tq4JxVbaPZmPgcKR5dCZsGFd7HhDSrsf1zmryK", - "quoteVault": "EbuFYayFvptXnY2xVHVfLhYQZ2uYU2c8cy1t9XCp2G1v", - "withdrawQueue": "F3F9KvXsMX1ha1t21HY2sEW4StJ3TZRWxvhWMwk6YpnN", - "lpVault": "6FDqLs3paFRfLtACS1UrfVifzBd9fbTV5bLc3XhcDmDf", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7Bs6nRwGuaGYCV2euhNvqqoc6YrjqZcAMxHmi8KWWuh5", - "marketAuthority": "6qijt1Y1es1NtWcJrh7vCZoMwXBaeMeFCwp3XVY5RLBV", - "marketBaseVault": "3a1awU5LQz4TRLzSsLqDtf6igaTxruA3mKiVx8EaunEe", - "marketQuoteVault": "3qyCapc3Qji3BydDMfbNJCb7a3kpUVfT5CLxt44SCwH6", - "marketBids": "HwDpYcmcA5VGSXguLadWHQ4B6ywmNuhat6H6VDdn3uXM", - "marketAsks": "36aAB78eQnmmt98wuZZZZHyeKs2Ev5nPadoTCSggWvG1", - "marketEventQueue": "8ajKavZdZzKX9a88CBiHuN3Yaxw7vGBEARt8RJfBdL24" - }, - { - "id": "3nLXB3hyU4Er1kQWU1yFgZVgFuhcDWTnCCb4nYbwKXFB", - "baseMint": "9iz45n44TQUPyoRymdZXEunqvZUksZyhzS6zQ7sLMadj", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "5YiPWD5aoycKRsDVU9qdn2AnLBMvuoLJE8QLTF8t4Qhw", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "89pcbyKnVAkWM8aqEzZEqEd12x6HQUQ57JFHxKcXFygx", - "targetOrders": "38DDrLBtomHfsU8JM9PC5pLEURYbniq6HV1vwfQuoDpi", - "baseVault": "2mTYUTXAYBB8Hsobck9LqfL3hLH5DKNv9RoMbSjPtmhz", - "quoteVault": "C9zvbRDDG6dSta9XPbE7AsgzfwF9dC1hr7uKbMMHegvf", - "withdrawQueue": "BBcyZseDsr1WmRe7U4H6DmEaBqq3QHMTBxia4PLccfZg", - "lpVault": "AQ7F8K5cr97Sp5UctPGRrhjThCanqBLFakHZBc69tEjF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Ca7rUNW8SvmXUCwdPEg8TmfKZc17fFSV8TEWirSU8bpX", - "marketAuthority": "EuPBKfTK8ewu9h8PApJaRt2S64TMaiRpqYTPnXSqvWSf", - "marketBaseVault": "BpG6DjzHwd8Bo5ZHaNxauJfML71V6c3MB9QskSYq7Hmu", - "marketQuoteVault": "DWRhxAqpTn37TWqjh5mAW6ktPCpkBSSfZmUMpzjyo8p3", - "marketBids": "EppeZXoXimNUPbR8QpEfXkhHdsD3TPh8U41qrGfGKVMv", - "marketAsks": "9DohenJKFevBQzRkrH1T5SH2rwTdjzonrpx5WJQ1pjbR", - "marketEventQueue": "F7SWr3bEPbB6KfzJwtmep7bZVWvtGNB7d2vzhjLdm83h" - }, - { - "id": "3Nu9sKSKfCy6pexCQ9pLMmeED7rgYQGHkDSiqm2QkKPZ", - "baseMint": "95KN8q3qubEVjPf9trgyur2nHx8T5RCmztRbLuQ5E5i", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "97sZJEdsLZYFCMhPWSs2ah1KxA7RuqapyXqVea17JZfw", - "baseDecimals": 0, - "quoteDecimals": 9, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FWLFF5p8WSeHpqV3aiJa4YMcaDR34pyq7mFCWryBs1hS", - "targetOrders": "4KDSYcY5svnmWwXz4K14sSZ3mNjxhQDvJbyGYUi26q8Y", - "baseVault": "BwFjYWSS9kdQUjVQ9bSx49SEkLNXtSTM545DC7CBFxLC", - "quoteVault": "HyLpiiNG9YcyPscqW4FjKWBB5t48JoGwgcDUxSbkUwjA", - "withdrawQueue": "ENydBkKbLTSAJqcgScnDzAk6FyfTkXRru1QuVYyYj9wc", - "lpVault": "9AnV5hZxnhdoLwedD4annjzGkp9QggRyjb9HoWUpzA6t", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FmQPnFoDEdyg8AN5JC87J48U1DykxA5w7rcMExovuMxE", - "marketAuthority": "Dofc1APx7vKJFsAxpSwsQMSWAZFWJ3enkqrjMRkeZM3G", - "marketBaseVault": "CiZb7KG41K5ft7fStJgty7AjXaCrGP274SUPQKu7GBty", - "marketQuoteVault": "36CQtx7nB4Ax6dxKst9txCBNt4Y8tS8dCQc24VG9GN66", - "marketBids": "FrmtdCQaw4Rh8pqZYhtzE4vyai2RkRgXBet7KL7sxNwM", - "marketAsks": "2A69wF55CXPbQSgqLNG2yL85sf4HV3pYRZNMA5oqcdks", - "marketEventQueue": "46rdL7fAsnCBmaU1GvmpCjhwjazYAZrZm7W7envxyVSq" - }, - { - "id": "3nUoJE9HPLrNUWmWcPGqVdp16MjLZdDvSMbwijr68Y46", - "baseMint": "2TxM6S3ZozrBHZGHEPh9CtM74a9SVXbr7NQ7UxkRvQij", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7mucM5LX1ZAUz7nf3cuUnLnG9q8AKeicUeYzt8X99vFU", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4HSdX6VhE9Z5eiHzEyqCCZwnYeDu7GWW28HGLihwFWt7", - "targetOrders": "5wmhDri5jV7Ru6XGwNnjFEdUnwtQbH1Kdu4NWNG5KMLv", - "baseVault": "AdVP3hpY86Xb1Amf38PuBp4PDPYcqyiztC17NEUj8aKG", - "quoteVault": "4BQHTyVzid2cJa6p2XsfjLhFXfPX86dp2GgZsWmhtu1e", - "withdrawQueue": "Fn9VRoZfrTu9kNbHeFU24eDWBuP3RKF8T4Xx6cvPTgUq", - "lpVault": "4RY7o2LmNHNbcMGaXvXbLCd9omaeLF1nUJJHrqV3LnNc", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "wtePW13tTkiuFH2R8qgGLVBdEqXUin61VhZpBWBZDVs", - "marketAuthority": "GSXTZVMBhpHErLorZuQxHMTHmvXo7Mme4w38FKVeX3XK", - "marketBaseVault": "EKAivjjRJunPy2gyUyoraGGrcrnGyXeyN7V2XxDrM8dP", - "marketQuoteVault": "Fc4vjVaBG6cEb41AfSYkT4GXsfuK6uVpKn87NM3dJGGM", - "marketBids": "5NhaafXWtS8mfafphQUghuuZjazVC1JAUu7DhjiFYQyP", - "marketAsks": "3P3XpmJYdAxW5wPPujy4AfVCjM6KyuKLLaGtJHpHR4Fm", - "marketEventQueue": "DD85PbiCTuJy1cizrooVZg82Y3NX6NEGECucRzZcRbEi" - }, - { - "id": "3NVTxj3fbycrkgzxU1KchobQBbitgGGFB62kGQQhJDiZ", - "baseMint": "B6NyNs3k2DZm6XYNL5wyC8sWEkEL4S8eekonRaSjjD7B", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9VzTW7CT1SdYuiSEEhsAnyRHz2ZSHhH7gcjx4HwqWQ43", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4nTnrwULPFadDKKZqFKrNuv72QybenJeiC9te3zuRRBL", - "targetOrders": "9q9nTu6zaq4AZLvfu4Be744bTpa3CW7Y44ejZ8oUqjty", - "baseVault": "BCTisgeCktovRDazDPyzDuC1yQtPTRqNQvyFsCXZLcwK", - "quoteVault": "FHDmHTZfXVmrFWQKnPXMykh6gs8fEokQoNUubzZXsZ7v", - "withdrawQueue": "GXJQrCX9WMWwaoFEmnHcjYZJi1JbJemsvyoBNWC9aRFG", - "lpVault": "BrgJqj6xfk6KfmgJSEZX8pe3xDotmPoaL6QpiPrPS5st", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CXCWMBdCb8tacvM1A2JX1h6gnvqZKrFD6PAX2oUusvrC", - "marketAuthority": "6b7CHUNJEK7eCXGV9VZvgde5xtijpRpjyZ4BF3TLys4j", - "marketBaseVault": "GJ8kL44ALazLsBNqtJ1qYzevo6QbPxzHyg6fc45mv5ok", - "marketQuoteVault": "Cb9MetAhGWwP1o8F318T4uKd8AhnNuLy5NWzfTZe8TpG", - "marketBids": "49H23dGF5wNaRuutuTm3p8rjjLsKRbNawRctH6rDghem", - "marketAsks": "TNcyMJ7MiZogvC2Gm6G3x2HwrLYfC1Rt3RA8twSwHew", - "marketEventQueue": "4UvS7yeuRErVjn36UFBZqCwz48Jb6TsFskTBDUrMmXdU" - }, - { - "id": "3NwAjbY7K7qmFBvaXESGEbzCSX7WZMRZSFQzEEJiM7Qb", - "baseMint": "665t3SYTfoVtaRPP7QRbBG3V7ePVtWVKQXYkSaUfxS7u", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8WmxuwQrpH23aCyjsxGXHyThs5TGmYmNu7mQv9E5Bdgi", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HsN6Z7ZieqHYZ5B9M9FXgsTx62na2Cgj5qrokFn9fTrk", - "targetOrders": "FqmVZXij2C2Yxtv1WJGaStMiLZCA5mnjXefcofPFFLn1", - "baseVault": "DmP6SwKqxMHmFauW2UWYPkshdv1sXZhqHjn2LtmpbUgM", - "quoteVault": "BhsyhCATeZpHktxhSDUJRNCPc4c9CGuA7LdJRy2Wdk1V", - "withdrawQueue": "HEt9i5Hy9Bde4EbPiLKTckWebfVj3XJYcdKzoVKYf9FB", - "lpVault": "FvhEKdqSsbh6YH7E5RYyn2erwDaFHeG8ohLULNDBRM8S", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "G1wxDiuaTRzBf81PfAEfEDn7YQu7tFp4uujwvDwxRTq9", - "marketAuthority": "32NRGPepgLTF6Us1JSq7mZerPyZ6sYXQFP9g4FentUhJ", - "marketBaseVault": "6b92rkSRNrJyz3nXHhNXQnhi9cYUJMm8XoRcGSkhkDe9", - "marketQuoteVault": "BRMibJaz6ejupYj4x6C2BbdrYyW19Ru4QsGooZRCLWkv", - "marketBids": "EEX4MC6jg8BUgx8wXTBk16wS4QhzyjW2QZQgsXFKaTpS", - "marketAsks": "TkNT5kRDvnhupbBjRzxssx7EdsFmVEokYuwjvTfB8td", - "marketEventQueue": "FyFf6CGfDCtTZKuZ7RdH7cxi6Qq9qGbGNxxw22TgZqY8" - }, - { - "id": "3obyhwwRXNRi2J389fKrhfyPuxht4rBgVf7hYG8cmwLd", - "baseMint": "3mXx1bNiB5bhgwznk4eeqM9eoy6DU3CeCkm1LPabeoEh", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CHQ7KnrAJ3SoRccApWrMrigj3tFWtsemkUBtwb2ucgdT", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7vgAhQ3JmP3vkdAjQAUcyLev99DQPFaRU7qn9aYhGpPb", - "targetOrders": "CCjBVpLpjph1RMr1dqLNgCTxqWgJdM5y3MHET1GYc1RY", - "baseVault": "4tAVJzmzMACrp91sCRJVRPkdmuCbAfE86cJddxcAAo7m", - "quoteVault": "DWrx9U6hvpz8L828eMP7tvZJELDSrKVNdU9Kg21VrZYf", - "withdrawQueue": "D65zpAmK4Uk6eWfEibF8P1YDTov79GV55Zivb8CCrceB", - "lpVault": "3VSCYwdaUFaxGoxVhoFzm1WgyH8iEsRbqCZL84B3JL6c", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4rUG5qCdWB7AyrWBQuwC4SLTSDMoY95kB5vUL9WP8h4L", - "marketAuthority": "9pC49UNb6GbMX1EdjWmY6fa46o1LJFrd8ruBTrjBRpTc", - "marketBaseVault": "Bvx8bAiLrQ51ojtHnFQL89zHCqnsogCgFdsZan855uDu", - "marketQuoteVault": "GdfMBHTYt8CdeY9tPNAjkggDnjG5oxdz5ebxUuDkPrFy", - "marketBids": "GscMFHbgVPDLRAPEFhP3jqHLdxz2oXumq5WvsDsfZijR", - "marketAsks": "HgB2ByaefKUNkUKtnV2j4AURTdn44QVmEdftybeTxB7V", - "marketEventQueue": "7GDUZu7FqTbYJuRqyfpm3qa3dtr24gUkHQ5bfVAJd252" - }, - { - "id": "3oJhrSjhhHu3kCdz7QsDcsuEiKPxwxRKs75M8n2ksfuu", - "baseMint": "de1QJkP1qDCk5JYCCXCeq27bQQUdCaiv7xVKFrhPSzF", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FCCG8sp58EUmkVUJay318Dmgpb3PTdsp6Jxpx6hjuHxY", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6U1GRK8Yo6H9zCnjRRmnKKf4E8nMm7mRWm9jWQru2kjA", - "targetOrders": "G9KikhFrfUNEnEoZvwQRYhev4t6iD2AxrJo4rawoYKza", - "baseVault": "6yvHtutsULuBiNaNyoYbmyr5iLBQhqPkdV2RWKCFU45C", - "quoteVault": "DbPs2QeSKYjvybFBmjsLedtW2xA5k1DqHUp1PNHSKnaG", - "withdrawQueue": "8f9NEcFpsdWayJGSgoYfqByQe8XhVWhAUnQZoWeZ1Mja", - "lpVault": "FU5abkkrtUqdH2SYMbynYqwKinW1MwdHtxWzjh2KUT9m", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2Vn1MPTujMar4JMvijG6qwbyedLgPydPFm4Haqbe6Dua", - "marketAuthority": "3AJWGMc6fq75pvmsMoe6dhvuyDudSk99mzrKRarmxT8V", - "marketBaseVault": "AYvtq3wYpbWbEwFSk7MT2BcrFd42oU2BdtmLWXyi7hRb", - "marketQuoteVault": "CQKruH44UrtSb2xrSD9EN5oPNe1ozCsg31MnFF6hyqcB", - "marketBids": "4zXrmfxQFQTESbhKL7HLkeJLpMawmN55PJM9RZjirUHt", - "marketAsks": "77vca56tQ8DjTVfEWkRghvu1FZp51MSsafssZMhwWeRK", - "marketEventQueue": "75rD3qhGQt3Ah7onVUMGQCDGsHEeWGjf5KbSmASpqU4q" - }, - { - "id": "3opprsQ3aH6gkrfGseWGjcxdYeUtFnG8btHGR7NLmqyq", - "baseMint": "3avjHqW8dqBL7oK335saFJGajLW22AijMm8B9voZ6GdC", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AfoiQyn4kbDWoUTv8o6sxyrbUNabSZxQJzcmMWrddz7J", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AvD9NEx3hEeuoaUUhi63xsz7Ds7XGPQUse8JofxV7Wfq", - "targetOrders": "4VTBq4GYJf6vNH319isTUU963ehpp9hZLCRxNRTPY5UW", - "baseVault": "DFZsbkqPTBKNwLHBK2sjz17ZwkA8xa96x569Mmv5nQrB", - "quoteVault": "NNn39iq68dAGc4CDPWjprBHnxKnDbkNn88xyt3FiU2x", - "withdrawQueue": "3LcGbcGxsKxvz6Na4gg8gzdeQuvN6VX8XJVXDNFq5wYh", - "lpVault": "Bp3SVAsHyNPKtD2V5bhkbfhPaaWeSc5uNq3XEANfZttb", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4VMuCWoAMivughLtB1p94nk7jb3jFWxVL36qUKrCTNaP", - "marketAuthority": "FxQTUK6LgjkcNYaKMwzChv47LgnQsEMbMaKAmfiAB3ty", - "marketBaseVault": "D9UYobMwpNiPKxsVMiUPXHwNpWohPzu6CdLf47dbtqBS", - "marketQuoteVault": "7Aq9HtmajNALRaDebCnPbr9NgnVo2BLW2YCfGRq21Zm5", - "marketBids": "3HEe6kpVqBvzwQe5UyYwB9basMCgnq6CxbZLZhWxR8Rf", - "marketAsks": "B2pXxoPGiV1xBD9vG4kmCbEwf5bxEAus7M4o5kv1WBw9", - "marketEventQueue": "CAcKCu4GQFM9Mf1Q2FC82y1gZEJpcLsvuvimCGwbxRqS" - }, - { - "id": "3osa4CdDuzJru1EuomSd1UxidacCE9FgWJXQaikxxXZw", - "baseMint": "ELSnGFd5XnSdYFFSgYQp7n89FEbDqxN4npuRLW4PPPLv", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "Hz8tTctqjLj5jY2RWdCKhTKqRX24B97oDW26SoPT9Fiq", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HypgPjznUt8XLvzcSDEmyTXCiBjphqDmmD9jA8dE21bU", - "targetOrders": "CZiFexLJzrgJoaYCXEsJT17ryPifYjUmwhXktdAdRKDb", - "baseVault": "Aj5SqPhW1YQCYLseHS4DtBa3TWTcHXdQVoNwwcvYoZyX", - "quoteVault": "DXCEtH7edx6ns43L6LLxV6WVhEniHjRzCp8JMfGEqHko", - "withdrawQueue": "3iYPeweLjQ1cmutk9EdZhuk7yZz4XGRWTZprSbeHGFhF", - "lpVault": "9FG5mY12yX5i3fobyZkrFmxWyapRhuZHwnQmUkzJC3NC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4LsEDMN8uTkFvfHYN7e6PUQSySc1QsBWXL5SzvPj25Be", - "marketAuthority": "ABivFCGSUX2SXCpTtuR91wddbc59MF2WmqVaTjJgkCJG", - "marketBaseVault": "6LteLz2aX2gt3Lh8jawt6Z7kkL2zbhTck8otbVMWpDAz", - "marketQuoteVault": "ATBu36oWrfJ8RkcS2uGBjHBbPdFdmYXj2PB7b2wafpvE", - "marketBids": "GUiFRdxSWCnk6WhYUZwWv9m85dJ9KynvoXWRBjKePiJc", - "marketAsks": "9L6rpA7odMHsVLCddLWmfuaGqmFxEyn3WmmcDNR9BSPv", - "marketEventQueue": "HekEhdd7ZSqZkBXnrBQyiGA17jANyJXoHVno9mZv8U9R" - }, - { - "id": "3p3pdTjXV1dW9VE8i6nb4j9XzSJPnuAkhu5GkCNVbRxX", - "baseMint": "5y1YcGVPFy8bEiCJi79kegF9igahmvDe5UrqswFvnpMJ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "p1Xn8AhPy8eniX7dtAVz67vEkQvYxTEYyCbF2UVxrga", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "374sBgqU4sp22rcTHHingbnmffpEv8HqtGbjXHGN5MqS", - "targetOrders": "26B5UKWcmPouK9Br3E6JZLzEvjMRW6CrTN3s2bfeHJEZ", - "baseVault": "5aZC1NLBGRGWC7NyUjabCtH98iVUHLjCvmeyM9huG5vg", - "quoteVault": "3azANPxcG5Xq8PXBJRS1sTSgoVRpH3KPX4AEVGBQKpr7", - "withdrawQueue": "318Xg8gSxRWF7jVybu33LAQ6fZvg78bxn2XX4gbzXTbn", - "lpVault": "7tA9G3S8e2tv6EEc4aEBAd9aHSiBzZitsNbeJT5cBGTa", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5TL64aPK46am9PtwcRcNsXjNF9d2pUHPU8N44qh8BDJh", - "marketAuthority": "AeCRnfknFM5JcY61n1kNx2CfuLte5JGQVkwGgYyUYSed", - "marketBaseVault": "HY2ehipYMNDVoa6mk8mk4ESYqYsESH386btJiZRM5h3e", - "marketQuoteVault": "32NiWBPBWrSxMGeQJQJE1oxbwh6CSbMppaq1uTNto1cw", - "marketBids": "BfiY9gZZR81SWDuXoetrw3fPCEbFUusUj5M2HJkYbgid", - "marketAsks": "CyoNQ8TXinGQ2o69vgujFHfT5C7MpQnHwaQ8Css9z1Pm", - "marketEventQueue": "GbWxaNDV7K6dQet931mingzT2fVdUqbcAcSDXEQTqwtN" - }, - { - "id": "3pgFcZhae2UeMFXHThsSx41x1VTwrcfCPNobJPN6sxme", - "baseMint": "6j28waP2NyoCBJrrVNHZuEzLDL25DXdNxMFsMNMxYht7", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "8PhtiQPWo7dv8hampSYasTadbhqsBz44LeB2Hkv3jEXq", - "baseDecimals": 3, - "quoteDecimals": 9, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7uX7xWpu1m7X1iN74Gvbcyqr4FFSPjXAyrVswHRA7Ats", - "targetOrders": "Hyt9uRhaEZ3VPvPy3o35zYE3gvHbuTheqFcr82dWiUzX", - "baseVault": "5dSnyzFYt8dioriQYoNTkUumEto7swbgCDQRBA4Tm7mg", - "quoteVault": "q8RTLdQhp8h7on8ceDW9QxzZvLyGzrNGUXQGj2YScNv", - "withdrawQueue": "HTFksUSLG38kpfidAV3eB7LmkYKNqNLQiH3FNZJWvu1S", - "lpVault": "hJqhXU2oHFsjwQaBBABNm3nTbZdbMUYArCyRpJUFiAX", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "xhEYoNpaipa1966JdN89zK4a3hEFWiireJT1TZEtKEB", - "marketAuthority": "5B6bQz4DMcr8WTxQrnimHVbgX84cZRa4MCng5FWoRueY", - "marketBaseVault": "EwkUZoYyPgbcQ8qnqFqbLfDDsEffyH6WGRxqowu9SGpu", - "marketQuoteVault": "5GYiKAfhVAk9WHMc24NLzT1VBEMPihznBXAeU1wm8e3o", - "marketBids": "4bNuTbEc67uRv52kMBw71hKyRc1ssBaiDofe2F61EzzG", - "marketAsks": "HT1c1EpLqnH8XpijeweE4EkwQYp3fVPom7WZdGrsvVgp", - "marketEventQueue": "H6JaR5w1i25fQF7taXb3dahaweEaABbjLfEraiP87JDr" - }, - { - "id": "3PhjEuXsufThq4y9aAvM7wiMrQaaNTKqJT3XCRM8YwTS", - "baseMint": "HWSqJdwemji7TNiKQPudUj86LXyF3vGAtWm5ePk5KzgD", - "quoteMint": "FnKE9n6aGjQoNWRBZXy4RW6LZVao7qwBonUbiD7edUmZ", - "lpMint": "Gd2kk9rtmZ8UYypZ499jpGMGNo3t8GdCNdm4rW9CD3hJ", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AKJzZdrbmV3uKy9zbe5atsR6hMNskoNnQFb5cvwjJRzU", - "targetOrders": "GL7B5TwgkxUCEK6M2vcKDfhHyoeAchM7hx97g2rGzvEt", - "baseVault": "6QxHRmyE9DiZUyp6RkkMTLo53S4jDgDZcEFU3mVVp6ie", - "quoteVault": "4o5BMxXN8qi9C4cNku4tZXGN5vNLZomTpj2htkr5PaC8", - "withdrawQueue": "A74jJaXVMAqyUjWhbAe94CUwAoQfT4h2S9pNg7EqVjbG", - "lpVault": "7EenMS4BqB9NXbPGCEkdTvaY3GxcjHdsdypJxcNVM66A", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "E1ye95NWm5uHDGv5BcmfqmUhNktzP2UJ6ooBAgosztn5", - "marketAuthority": "4mTEhMXDrdA6B2Rx4RJcGAkeemxn8UezwWe8FLCk6jNc", - "marketBaseVault": "5QZrF7WAo4HaKFsovCC334M11vmBQgEyupQADVqNMKbL", - "marketQuoteVault": "ETTK7P93VL6xeayT2BG4upKfUvyNpN4LBzctYn3JvaCp", - "marketBids": "5ngfMsMZguFvm2bfHqTBp4gFUwsm9uicKn5sRBYNdhSp", - "marketAsks": "8DFdztf1ZEEUURCC1LTQ28JaiL7ttvproDfLPPiSNn7v", - "marketEventQueue": "5bktKWTEPd5ANw4NENHpCmtG7qmhKSDwUd2tcExT7L7T" - }, - { - "id": "3PR6etu7CDMJPCT4DPmJybrXjU2xkY3NU7TcM9gnGUn5", - "baseMint": "cqNTpypmbwghrf1G9VGvSENcw7M7wGSQ7JS8UTQWXwb", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "692JPToZtj87c2L8w1MNPXUGTBBcbr8VFrZDNMJTEnXY", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6Ur66Jqco66crxE8N5kVUcF5NA3DBWrSaBDAQ8xwpcW5", - "targetOrders": "F7gsSNUgKuVy5fVmtffj4DXzgz7MzuDWPGVQFycNN3db", - "baseVault": "F1UJGQ53Jyn6CX1dqPiQmaiPjcHjFCSaAJ9Ny5AY5USw", - "quoteVault": "7FBKijjFX76RmY1bqEAaccWEJhFJxjnqczKgbZmHcGV9", - "withdrawQueue": "6nMAgWPbzuyAKhaNrcjdhNnSgfko5qBddLNNnQByDCzc", - "lpVault": "mYqSHMXZdJCxoMCbcdf5upP5Y69v9RxqoP2NWzm4y54", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ArKuemtzjpqP5H3P4S21nzhtLZtsq7nMCN6ecA9yvMX9", - "marketAuthority": "2jS5Y5jADUfKCG7XuY85RK9NNcL93vwYyik8ZBytKKai", - "marketBaseVault": "GumXUwjW15zK2ZJrfHrLrGmTBhJUhF3WXfkZVpbktjN4", - "marketQuoteVault": "146wrWVEuyquRq8qQ2gvETFagwn3nFv2fJBbvMmeWa9s", - "marketBids": "BU8ah1ZPFaK1y5YqJY7bkzZNRi26cAcwrKArZCZJLeBy", - "marketAsks": "DFXTm9CiiS4fSwJ6TxTc3hiyCjsfuGdwUqjnVwjduebt", - "marketEventQueue": "BkN1wVoFw79SeCbsjTP7z8yMCvxmDgerDdA5xT3FiFp" - }, - { - "id": "3pTmke3WPkKS1x9ufd5p3MSryMFtz8qmUVkBTHxr7gyB", - "baseMint": "FZgL5motNWEDEa24xgfSdBDfXkB9Ru9KxfEsey9S58bb", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FTrF9gCowg5LLbWv86pC38vHjzhWvMvd4nVLj1Cg4zxC", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3U4P3x118syn6v7vSgcrxpeJVDHnuUNUk9LWZ8fSa4fN", - "targetOrders": "7rmLnYkkCuDcSmZpGZKvpSbrEDq1gSFJKubJavSVGLz9", - "baseVault": "G3asrp8Xrqa5UfiJR79HFNZBrVvQGeE6LUZVraCvnQVn", - "quoteVault": "799v7iFKktfH7TF4g4jzF6vQQo4nBFCJo4K5MBZdde7D", - "withdrawQueue": "8uJH1yvr29icEgc6jZVMUbZ6HsPHZZqDYDxmPof1ZQoo", - "lpVault": "Dkz3SMTmNFn224skauwHoqMCfP4B3CLNZaATTdzYaYST", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FHHnUm8MQapT8kqny7kSSRmCVqyWCeQ8b8hL7Ugn1xPG", - "marketAuthority": "CdVsArtx9FzLChH4yiFGAnCf2Jy3vx5L5LZQ42xJc1Yv", - "marketBaseVault": "6gpWsNFiXpfdSyXbEYe6x8BpAZxXgWdtxZHNmYZiiLX4", - "marketQuoteVault": "6Yb2gFQUy1i6X2gjhQhL6KqMqnEiTAHLEa2hgoCskE1F", - "marketBids": "89kBm7VCdrKyQngoBh3ZkYD7Wjwa1R4eKaHKf6kC5Z11", - "marketAsks": "6LZcdCcRrCd1FgQLmtW3Gjhm9knoso9bygkvJSLJ9UT5", - "marketEventQueue": "A41Fku4jRVTtfoZGBHQo2SLGCHt5rGJwBqKRcL9JdHuL" - }, - { - "id": "3pV37oomFKcYLy2QqYnTE31FeVpg7cW67QVsrZgY1i5C", - "baseMint": "14AB7dXTdiNAwqAtWC7NmSW9u74SkCXU1X6DSejxkFEg", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "4koGSohHQi32mLGTZXxvdANAxQHia9iRTv93WTg8wbqP", - "baseDecimals": 3, - "quoteDecimals": 9, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EnjVk8aLZGuvPNDuf7YTvjZxNk1EQ5JqUXrnPAF8SJ6r", - "targetOrders": "3aGYZ8RLWzwVRSX8DVcQfWEpG5mJeAedXBVdWit1dKJV", - "baseVault": "4NpWmR4przfXKKu5rTBxT8tMA5F8PwowoBpiTan9jcHu", - "quoteVault": "5bEeCMGmeiGZhRF4VmBkdR839ggrJg6SvKP3dZamGH2q", - "withdrawQueue": "4eNGA6aLrpXJynq866i8H9s1dEW4dJ3XMa7KM92wgJZp", - "lpVault": "7x7vjeNwSJNG9q7GkQXRHfi3t5hSv6MydMBiXka1aY1N", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6JtryMVM4P7NoznLagszgvuFEp6GsdKBFGSn2wpoMWgo", - "marketAuthority": "FgFWNcQff9Df4QVTsFMh2fJeHkL7asype5FXhkpagqGE", - "marketBaseVault": "2yUpphZc6n5ZmVcYTfqjDMLcxZxREi6JFWoGp5ZDiZBy", - "marketQuoteVault": "9AZRBpzLtqBoUVPhMG6grnB2nzvzxn3ACsH5cL84pCmW", - "marketBids": "Gs1gP6GCVMJmuesVboGwnz6Mw5nGSZi5KJkYQ4qhPW9Q", - "marketAsks": "4n1owjXvTpJU8EjovHeXxGGM9P18xuhN9xbBmHgyCAdV", - "marketEventQueue": "BkvGECbgcQC4EmeRwPweLm5pdyqC3SsbvJqUq8QuteLn" - }, - { - "id": "3QB4453oSmKoqgxcA5QxW2s77bqMqzHDrPLwmATi6NLV", - "baseMint": "SM6xoaArJtczHFuEEeHBTLba2dLxZimURxwkrNVnkNd", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "H9raCTSX6K1x5G7xZjd7XjQCSXrPPqgw6HrKtQiLz833", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3B62jjEnhoJSLAZoHrXP4pDysjPhiVMHTxK3JpXfhJb7", - "targetOrders": "EMLKmQoL7k2Q3nrz8mMeJoVnMixeQYbyiGfurdNiwo4w", - "baseVault": "2ZAmvCGNr9iD3MK2mWKnVYVjAcQ6QzEwPgq8QE76Hwpo", - "quoteVault": "AZsRV8mSC2Kdz9cLmYbVnXjM6HwTjMB2aoeCr35R8cqB", - "withdrawQueue": "G11JuTQbdWFEnhQ1SqCCX3qNKNEPopUf4FkwmFmHPJq8", - "lpVault": "DXwpwr37vFwhhv1t44Af9avZAsDAE8fynenpY3nonBDj", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "39wcsfjufSqQ9sMd9KDLXfwUhG7dvptniNoeDeWFiagh", - "marketAuthority": "4XK8RoV8P9D9JkiPPc33BMkbxbZRaGd3VxvcRLBAh3AJ", - "marketBaseVault": "9wKsQVQCTBVMHWjgusH7J2597HYyFWDJ3BQuGYFahdeo", - "marketQuoteVault": "7nQLH9hiCQLjtmxGpHTy82EqChNLLAAidqvXs2PCQ7JQ", - "marketBids": "8J8zKyKn9F5PoZWgu55odCny7ugC7jVnFzziNDQxqcmX", - "marketAsks": "JXC2vaN3NETTG9m7XHWfCBTeJSRefqXVKfcbUdiHfj7", - "marketEventQueue": "5mv3WfL8mo7Bq3Th1KJtKKMLCwNdPTNK8ceSYweFXkBt" - }, - { - "id": "3QBmBRABxG8PLv4YeeGrreaTp9Bx4fc61eo24fZV45au", - "baseMint": "9A6dgXm79ASFyG42tui86F4gQTC56Ydw3mrNL61xhdr", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "9nprHAyLur3vW2re8EiaoAka3nUnwARfutoeEEw7QMf6", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "QypPNLv4ipbdsfasZryR6mesCU6ehDV96x5SgCVpHrH", - "targetOrders": "4m1CGUS33rR6asf3dyqyFm5G7Vtpsy7VxrfJaFVjf7V1", - "baseVault": "BG21TgK8WcWLctxNSho4mc7csS9aZuSZY3x6WLKUSNWg", - "quoteVault": "B6omeBNwL5ZNrgLnGPj9m4TmwJdE3sgqJUX6k5bEnbgw", - "withdrawQueue": "Cf45Bs56N4qKJYaHzm1umRNY7EtRcuEoLQw1GUgZiehM", - "lpVault": "36Gy6FgTQd1ZzVoKojZ9uapQj2Mo2WqauQeYpThmBR67", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "QrdeB5hcNpBzL8L9w8NvoocqqDiAPPPxaTgTaz6xNCH", - "marketAuthority": "G8SzYNKFysxW8CgbJjnN2zFrJEX4CrHZ6mCmdP7PTJ8G", - "marketBaseVault": "F2xkP9RbpuZRFQeFgkG6KumX8C6sCJSjgcGq78XHrNdT", - "marketQuoteVault": "HM23SD2NVh8hiVLXnrEfq6wW58pPgYpAzJU6JRvS8GUG", - "marketBids": "GJ4Wr1WQPJazKyd1D1Qo33CXRkhoEaUjmMJ8WqoH9q5V", - "marketAsks": "6ip64ANskYkyH1RQvpAuGb7dD2o43DP6jxz3XNkvR48X", - "marketEventQueue": "96NXmrgWqZ14zMQmcwDtuudz8RM1ngyJ6KSoC8E9AJM5" - }, - { - "id": "3QucYt6uMh6iF1pGK3bfhbnrz6f3pYTQeh3zqyAcmQT8", - "baseMint": "HUmD5w8w6MvEeH59xQobQG9VJoYEQrZKjRBFuQCtCA7i", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "411HStkJfXJKdCQN8VD8G8Nsw1qHKmKTqHEfHXjC9JBe", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6macRtzu8uvxv8KCMCt4T8hbiKtnGqJQvL9EPcnoeBpH", - "targetOrders": "62e7jSrcu4JkdU76RWmgw3Pzz7CraPcUeFuv2C4qVeJN", - "baseVault": "BFDoB4fbz91yy7KYriL8GCDLPVq3w8DPn9FNp2wZZaut", - "quoteVault": "5dKxvA9vSGuEk3DYAzugEsfeRPatzYPzxkFFpQDGWDGS", - "withdrawQueue": "DXf86NeqrHk9WF4gQbUYrXsqYJUWm2T2crPRbrP3u7aj", - "lpVault": "Eh6h82k35Rorga37LoYWtQz2Z4zfD1KGKMzrnEDyjXhr", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DEn26jW8PdvR6ixiseQjDZUxy9oX5GAbvpvMjcYgyUj4", - "marketAuthority": "2k6tEy8EUhF4S8pQP7ri8SC15vPrETP6k6BPh6nVhMXA", - "marketBaseVault": "9pNJ4pPdxZky2m7Hv8fAKSUvYndyBi6XYyTpM34cTNkS", - "marketQuoteVault": "A6iYcKjhunDrfxWB546uwuXA8iCb6RB5EbEfNdUNmDGE", - "marketBids": "5vUoPPWvQ3ftsY4FLrJuE9hKdm1wYdyDVaCcnf5vUEWS", - "marketAsks": "26husmN7b6Q29mhJX3Q7zMY3TSSWZ6j3nQQyEUbP7Gk4", - "marketEventQueue": "Bgc5dPLsr7cvU7uCwrJLJWcJ94eRsR27SLMttCiod5u3" - }, - { - "id": "3QWFARcboAMpYAvzZ3otsX4h7n2BKq5XMMBBC8ybMpYJ", - "baseMint": "4ZEDNmqoLbzwJVAJZNhRgz31Da8DauDkpSfH9iU2vXA4", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GSuWHYBJNLiSmGiGcb3Dt72H3NToHHokTni4MjVDF1Gy", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3xqcMFPA1XVjyZSL7Vc6k3arTp9KpUithsBtPpUJBh3t", - "targetOrders": "GYMXgX6RFQJJZND9bG7vqYF55RPQ5nA5P1pmAzqknp7q", - "baseVault": "JAf8YKwDfGqWTDsQMpGYica8tLDHVFmFN79vcNwMFFEi", - "quoteVault": "5YMFCQDFd38E4EpyNk2ajmW5uzqqRuEs77W89B9dasbH", - "withdrawQueue": "BeygnpsQ8mectswJbfVK2potqnL8DDGoY9LfXjzfWaGw", - "lpVault": "6eUjonsD5P7p8kBvFmAeE1UffPNdhFNmAN9Po7TpVzLK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FFJpw24jsFWgjcJKffjBc9FzAeoMpzedHBn9WhwwtcmD", - "marketAuthority": "Ek6bXrGZkghRzv9SCnHpSfLUTgcGqbYpByp6vVz6LDao", - "marketBaseVault": "EmHGQUniVRBnZKDX26SEi2AenCg3LtqGyAbbjwQBkAyM", - "marketQuoteVault": "BzewDhasR9tTLsTHpyRaLu632YbUKRSip53ATtFkarx3", - "marketBids": "AAQbhew87Qc8LPi6k29YfY9GdVC8ffuZJxTZgnZcprLg", - "marketAsks": "DJqfuwqjzXLPxrP2wiHftuQy2qbjdC8HM9WBEuhCewVz", - "marketEventQueue": "H5PRpn3yQeg7pQHHi3kEUELz4rW4RjJJS1j9T8NxyWwe" - }, - { - "id": "3Ri76KJNN8UHgZqeA7bkcFKDqh6ezRPws2KUmAqATD8X", - "baseMint": "HnZiKrSKYQkEfzjQs6qkvuGbBmrBP9YzjB1SMM7tiGZ1", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HWNFUo8CVte9h28CzDFJ222XRuC7WLw173q21rp8Lo25", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "cY1JtrvxRVoxwrnDMyeiik5E3iZvyvsXrWUjJPWQVBm", - "targetOrders": "Fwbzbt1iS2oRm5FVLmBEve9Ck7mYGmX8qv8ajBSjUjvW", - "baseVault": "33P5VkBCAzkGQd6N1F3qcx8n2bHX2fXGvjXDZjx6HZug", - "quoteVault": "mWPzao9Au6RrsetNXvS6EkQnEpmdcDjGfYB6fuJHAjz", - "withdrawQueue": "cYTRtnPXgozTzFN45fiUEssmp377iYzSojYfqtSGjx2", - "lpVault": "Fu6zt7gKKRcGpmxR8BVDNRBxj7y7zbykxLKMymk5iXUY", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EA4HfbBKmRnVNkwjHx14e6hjXsyYp5xirwbLGhvrWokg", - "marketAuthority": "3onVMGRwjMaBALeo2CYsMPH2L5E6zQryj5gZgwUhyTti", - "marketBaseVault": "Di8g4Jqf4E8om3zHmLT3e3LzT7BAb4mZWLAiEkSMXCGY", - "marketQuoteVault": "9JYiL3meh7Mm8wpWXb251sF2PS8N3rUgHHzuxBiH75Ww", - "marketBids": "3QjdQ3m8L2ZEv3GAd2DtE1doPWAz8NFnZfK6169Xhn38", - "marketAsks": "J1zyvmch7gY3CZi6bFfovkgXXEeEwV1xiPWjgiH5pRBW", - "marketEventQueue": "3dwtySGBjJvah6dB3xbwxVcAvbH5AekqW35i8oYyWrhN" - }, - { - "id": "3SaJxkE2uxY3rHbpXpxn12WtAL8FjM64xB8SmUn5DVwv", - "baseMint": "CYbXZ7U1AeV8kjtJG3YqKMLaWtdMLa24JojrikZZdXAG", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FyXTYfH5j9RiuuJuCrGbU6WKbz5zdKvjXqYrenFQBfRQ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Ca6qto5Sns6CMfKd8xchV2vC2XChGkEnLwQ67i7EdqrD", - "targetOrders": "43j5KBAqyMK2XpaLMRQ1QB9DD4YpPbuPPELLAopiL5ys", - "baseVault": "HwrpCdUpsPxs7vYqrwiJpgHax52sV41ox9HbPRWsuxBa", - "quoteVault": "Fyn9QvRohi3DwcWWGqrL2QWVMSVioDcKUr7jgkUKoKny", - "withdrawQueue": "Djo6aHznPqWR5WRVRgNrmJUKCWa4PR3dVn7mLvop1LCX", - "lpVault": "H4oWBbVUjgXPaxxGFxwkLbiEuBH3sq29pSThU1ibH3Ce", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7fFPopPCj2yJCDoa85gKsJgUky1BnQNUA95B92jkD9b7", - "marketAuthority": "6wXwJCKYRcKvkJLHDfXNuaTiYW9wg2yPuCQ4EUfvEmJA", - "marketBaseVault": "CTXwfYN3Q95NYX7S24kv5fZXkvW2vcsJT4u8jzVYDa69", - "marketQuoteVault": "J7VqCGDuhiVdS5JxojbbkTkkaKLHSbXhsSS2MtmbJfZK", - "marketBids": "76xSxVigJGauQN1GwD2VD433ukg65roRFqnyyr45Bd23", - "marketAsks": "4A8ZEbg7BthCUxHYQyrA3BWafssWNcejVC2LEajU4Qgg", - "marketEventQueue": "2sKpnRGpYHCmqBpnRgk5Ec6X5wogGf7sJ7u1os2MHoG6" - }, - { - "id": "3SPkNxJKHRFdDY3m38EvQNh2edzAqzwn5K7gRgAw5NZ6", - "baseMint": "7rawfN7VYn7hHsWpQEy6p6YmCNZFk5XPzegycmzcSCS7", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CKUjWLKJRDQPcTfDn997b7BNRnh1TuMPJdx2nRgo7RiM", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8Hrw3pWS7uwpyhwg88uBt4y1K5NUBoDGg8JqWMiR1RXn", - "targetOrders": "9LaCdu2Xx6b8VvkXTWJDqup8GtgeJeZ33XVHU2XHbhUr", - "baseVault": "AdGkiQq9R6AKRgKojjdNvRcfz9jhhzsXYio9EJMrinyH", - "quoteVault": "EDKMyouVP2zBbiLXF8ttFemXRzEUoAEGJ5Pxp17KL5VR", - "withdrawQueue": "CzfkKs6dA6xrUokRQexjmnVLrSyjXdoqftwFPT7sQiFQ", - "lpVault": "HLBpzeMexLWUyVp6df86h1Mkh62tfEN8CjobUqb7NcpK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "A7PVWbX1xci7qK6rrnTtHRRCUCopoZERujLbKy12nD5e", - "marketAuthority": "EbRxQq8w5MkUfehwcSDkTTPdPrCRYGXM5Dqvt4jUKHDX", - "marketBaseVault": "9x7SeYERU8rExPgjUzSxtmMxZcTUV7znmniRjKjKL377", - "marketQuoteVault": "5ChGGXA8TLdcCob3LUHbrMrqeqiZpQ27F4wNhzHtYWsV", - "marketBids": "Ap1EE9MkusRdK3R6wZ5PvaHzTqYKnPbnLrSxoBQ2NByd", - "marketAsks": "8f9Mc7yFWeVZo6T1Ry4H65sAQw6uZAKYYtBcmJ6kE72o", - "marketEventQueue": "Fx3CpkyQiEVHu2HQF97oTWWRj4Dp92v5UQu4izAaiuL4" - }, - { - "id": "3T9DFG93AdkccwEvVmKvVFbPLiyPkniLxT5VN7A8oNYs", - "baseMint": "RLBxxFkseAZ4RgJH3Sqn8jXxhmGoz9jWxDNJMh8pL7a", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EBS1kPnpeQWZAPZNzebqdRqTfiAPvZR4De5zSP5jfmLB", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4eyr6DuMYzRkAEcPHiCqLW8R1UXxHR6V1SfdjUoEe3W9", - "targetOrders": "BftjnnwEnCdpzZ2Dbharfh6JvYnnTJpJKiCvJTzgwbYx", - "baseVault": "CafiauJSQfnLUxznhJMphbpkVc1v29wSciVQdr6vqBD1", - "quoteVault": "J2XqLQXUHQkSrpAFGBiAzSQNBzQPNutKuadSbJG6vRNi", - "withdrawQueue": "13xe3rDGaRBtyUF4iYYkUFao3YAWjzs3wRxjtGx6PhAs", - "lpVault": "6mkZGz54iDBFN3rSfTLb9Zn1SWTqHvLkpSDrHzVsFp5F", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DFdcGFcAVWZ3UgVgpbBChFKen3URZdZ8dmju8GTXQgCE", - "marketAuthority": "D227Vt14iY4KHvWYcim2s78MRtsWXMNYmR2CCwRjqZ4U", - "marketBaseVault": "6YpcMmanweNSgWo6b18JeemotCeY3g4CW32K76ahMKbu", - "marketQuoteVault": "4TmGW66uZjFuJQ2E2hpS6AWkKBxep3iq49q4Po7Jx2cA", - "marketBids": "5bcY6Uww1b88EFMZpS3yuvSTrh7NgbzTpTwhhowgVQbF", - "marketAsks": "49aW6hKZHRiu8TNSe2pA5ew5aZmcQfBqTreVSZ8uAMLk", - "marketEventQueue": "5BuK1uAJRibE4U9L7W7SCP3E4iXq8RHHanbHVb69K6xH" - }, - { - "id": "3u5sgVw5pPUFH47gBnmi5ZXrsJ3ftTQCXqX6xHDv9oB2", - "baseMint": "DogscQVvNVj7ndEnhWiCXPVPKKwNy9fJd4ATF7mVi5J", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5yJcvpoJRPx47WWHi83vrx9XsPkVJS8gzEANUq3HHEYb", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FRDE5qKpHiFyTHC8Hutd8yc79CU2u2y1g2YHx3G9TuXD", - "targetOrders": "AMneJcoNpyoXk3PpFx5pcjeyir7Sus1fF9BjyxryncZ5", - "baseVault": "J2SSwyqkBvmiN2u5aRqgZQFYMG2nk8KB2EwrkUw98xPS", - "quoteVault": "BJq412nKEpKBxJ5qViTwUHAy2X48pjwb79opjsB3csXK", - "withdrawQueue": "7dN3LqpHo2n37WQjGAbcgxdzeVENy5es489X48QvQRtK", - "lpVault": "7x8Y8Zw1yi68gMhJhoSD2wbboQbMxzQvg3xPPFKTsg2G", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "36wb7iVPv5Rn5Q1ppqVmtJaxLdwgUYkr6U3SGa9iL3W1", - "marketAuthority": "3gKBMA9XfT5TUJtsBDkTaenatx6t3hzfjHktUhAuAaRE", - "marketBaseVault": "6AEvV8Lpi95yWQocZdkjhbChUh9Ar6rSVihzJzNXcDQ", - "marketQuoteVault": "2UL8WzSnNTjpQgSUG8miDka3Ncqa171Lxjcn2xaHzrU9", - "marketBids": "6iPVB3sDbbW4gJvgcHcQe1gh3z55yUt2vzQ8SaxvE221", - "marketAsks": "Bq5XxLjbKWZpydmF91BpeDZTDGrQeFPGJri3P77S6MjD", - "marketEventQueue": "3oNJBZZ9uuZjuFrRT936ZJv2cwafYg7fxLzhYszFHra9" - }, - { - "id": "3U5u6Rw3k2iLU5XRKJiJYTu9F8DHmtJ1WAyAqw6jkcQw", - "baseMint": "DcvJP16Cw5oqTbtHmpJ4JGXaqBvV5m6eMZj5rGsFLpwU", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "ALYVgT2ie8ifY4iVomVhSTVKoMrH6QGVtTAp8rCRTqio", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4Z1dH2rsqqxPKbKgX2vAZX5xwp62sYwozPqDBQU6P5Dw", - "targetOrders": "GRAQvXg5wuQbNvt1GHXieqPEaE4a2rWAj3LKUctF5x98", - "baseVault": "3HpCw7gmVuYJNtbwAg6eH7dBrdEzDK72snBEiu2GJGPW", - "quoteVault": "5CfZVyfEf9bX6XXaeM46PHCv4weAez5gL1RW2yU1aRh9", - "withdrawQueue": "5yXgch7z6e86j9p5i15Cm57855q6TJ58Yvq1aVCwoSej", - "lpVault": "4eouPcL1engeiWN25MZTkFnX811gYgsSgSSG3ofJSn5w", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "93UQQszU4nBnQ9fFtFzkhBwhtPwZdDKrudY4o6Vo5S33", - "marketAuthority": "2ayoTjz5d8LD96aD6be4vj1aCTS2JwWGVewQr5QEamtd", - "marketBaseVault": "5xwMSn8x2KSqCfQtqiFDNr4rc4zbejmpBKHz7fKR3RWi", - "marketQuoteVault": "C7W9nitDHiCmEHQJBNBgbL1fMmoz1vSstQT5MFXDMMR5", - "marketBids": "HgB6aQrb6Y3ud7vbW3w46nvMCVfqt6frFMmteJ7RgHLS", - "marketAsks": "2B3wsL5WAHDxg6LZatv4RPhcFgskDS1wtsmF2xYd2kFF", - "marketEventQueue": "R2cUr37pvvenvhKCi8e6p7RhE4C1UoPcEBnaP7MTP4o" - }, - { - "id": "3u9uNWPwCA4XPyqsxqgCPCP7z5mLMuVXjesH58jfJF8J", - "baseMint": "2G1MvHDHqsDd1uXQhditZS7ZSdkeGtM9iSqPt97G4QzY", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2MYHCtciSH5L9FNFyE7s6d4s5KiGEWRsP2zZHzY1We7B", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "29h6NwbAcoZSw2w4Bs8SMK7Jxo7foC8HoaeKj9HxHLuP", - "targetOrders": "ExzqnpUhm8ZSTSNZLf7brp3fSmFakCiyoZvREkyYziw6", - "baseVault": "HuW4sRBVt12zcaYhP7FyGLp32bDzMweW9LnjYFbEY6Ls", - "quoteVault": "8HLuyzAnRSmPV5MmCbE6vN7VZTxJHqvmMcMhgrpZp6x6", - "withdrawQueue": "FsDeapTgBV7NDtUQqjNByr9viFrFzVrap7sZya4GJ4xq", - "lpVault": "D5VBHetPbWizgUcYDzP5iMzA1DXJ78ZgjSU36yor1jg3", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4JQ6VVUvJKNF3WUj9SLNNCCHf6fGobTgPE6kK9wenzP1", - "marketAuthority": "Agr7k9ewkjNJatZVy3RWanTHQBWVNNmCuSpYsnLRmTV", - "marketBaseVault": "9mSXDqAy9adyTWo3tjFWLpWGQp3fYVVpsG32f2QLMdK2", - "marketQuoteVault": "144yQod6npWMqs83sGxoBCXZim94d42H88bZ2M4g1Fxo", - "marketBids": "8KWBwQoQug1QqAzHEehzvmbucZiwfqPQVevpagZAdHzy", - "marketAsks": "A9ZqMXQBXPoFP6TKJCVMNWAp5DhQxJFTvXHd8fiMs6Bw", - "marketEventQueue": "C85ePyZDbAWok24JD1fEXrvofXFYEuyCNpqgmLTBn1uQ" - }, - { - "id": "3uytC382vDDmMuLMwSjeLZF2DFLPRhnwTP5mZT4MjiE7", - "baseMint": "4ZwWddrPzfgMxyEgQ7kzVrqoqX5D9BQJPwduQUBMmePs", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3xNihCyxS4mAFAQMKkM4uBbpkev5AEGjMr6RcaGCnypt", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4UN4D1c9K2WU9K8AKEVQWvkjFNEb2HgmXRh5Wcoxan2M", - "targetOrders": "Bf6Fyd56f6zd4agvb8Rgau6o6PCvbMfVHxBBSgSftvRU", - "baseVault": "3KamiG6DsGJmvKTRc2yFRToMERuB82ieMVSx1duDb8h9", - "quoteVault": "PuKXLP3tPvutPWdjAbPXZwnGAxdS8WY3UKpK7NosS3p", - "withdrawQueue": "ArgGmLuGEs3VL4ZjcQzY4upn5w7zo3nudmRgmnNuy4Yy", - "lpVault": "AwSvtPTYcU422uG6xZR4zXMmUU5qEoqmhQyYH2pLqmf7", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EpACq4XicHGdyDpumDKRU9K3jc3tV7MHjUNga7M9VZTm", - "marketAuthority": "3kXw63729MRP7u8v97waKdaxbiKEQqAnw2frcQR8e9JM", - "marketBaseVault": "AP4btdxN6rnkD8ZWh9cWGFikxs7ZE877HaNMtmysTmHt", - "marketQuoteVault": "Hv4e4LYWvebSYrjMCzUv827kurVav5VsCCLQ3AKCNbht", - "marketBids": "6N4RaCQwcBBUsJq3JwEZ2GE5upXbtuUVZqcYGexw8vzT", - "marketAsks": "Cc63eyJ9Pu2m5WnUxwPe4q8LMb98mHrExPChAPvRfUb5", - "marketEventQueue": "G1VruMv29UuCgk1DSNLR4AXRiU9g2EAPMeTmSRdrVawc" - }, - { - "id": "3v6cZRVjAJ62Zxi1cYn5nrqgkcp2veKpMi7EPHWXWiCW", - "baseMint": "ineFWP6VUVh3kr42aTjxYoPvNwbha5BjuhvBk6JHZsB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "ckAxQPyr86PiWUaDeD3VUVA3MYsp92ApG7L7YAA9CbH", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GT4PM7SrPeUA5DAmPrEtYxkLaGPSDWB7kLFbdpqsT6os", - "targetOrders": "AExbF1zEXjED7i7QcPK6wei2pFCG6UvvKsXgQDgXVs5v", - "baseVault": "bFGUobVHaJcRd44YeJQsbfnq36HjZ6j58yTgSUFPRXo", - "quoteVault": "G9cYurf5GSNotk9thLBhYcA4yq8nbKndPitWKLaAKntw", - "withdrawQueue": "9P5GzCxCPTgB7CmqqaDFyugKbLBh3oGp1XZqqhFQ83Hb", - "lpVault": "9BMN8iiVZ8n4qSQRvmroaHgzm7uLTCS7vpMzw1mzbPPw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9weQdVQAwy7NWdC3jQSgCUkWZRefHhVFFq8gRkT6DHca", - "marketAuthority": "28dRtuFYZHSPuH1B7tHTjH2Mk96NpmDmm27w2iKKjyXN", - "marketBaseVault": "9Q9LnCJFs1PxHwXSEqqxemDE25U7TFzwv4TurraQw29p", - "marketQuoteVault": "2FYdcZc2qLiAYxMqVd3XKwW8CV6eB9gh7Z5e8RAQ2wnS", - "marketBids": "DXHPuAWX8TSZZtKhAhE9jUrpAnKQJKmK5C32rGd4zXsk", - "marketAsks": "3x1gUYtL2Hxd2mCeSdm1iQhyQooajgbxChTsyE21gW9c", - "marketEventQueue": "6ZnM1rd2KwogaXCGfXApNCxcZXqDPi5du7tpWBbyzqF7" - }, - { - "id": "3v95X2ANDtR8VJRkHR5iEyq4xauBBkqhBWoPKEH2twnV", - "baseMint": "ECPAzxsa4VBALQ4kh4i9mtUdRTBRhGwrzu7Y2YqwZjsi", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CE4T9GN9WG5Ctnu8s1MkULgFTJiFxhENa1o4xjRQM2z2", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3t6eK4g2p9Z2FHudssGBgeXNuSNh3V8PFhE7LEgr9NxX", - "targetOrders": "2nhATHT1pfWDTULCwFhz2hJnMknAiPmsWhZtFvDAUuuW", - "baseVault": "8ngdNVqneprjNe21KMRk7dQZsrgb27x366JEjvHBokPF", - "quoteVault": "2TWUwChQpddUyMwfT7xeStgaDb2KsuQqjMpV7xoXDuL3", - "withdrawQueue": "ASTMpVT2s9SCkxmPa4RRS4dPySfxRrsMjpXQBHB2EHf3", - "lpVault": "5LPXCSv9nVybcnh6AHeZRkwdteuxYKeXMbLzf1nLACvj", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "B31pzVH9XMYD7LVSrvCQA3TMa1CdWBc9n6EDrGLi9GD3", - "marketAuthority": "9CfZtJuUBandEz7rrWDdPF8vmXkxTVXogdem9DaRVMNA", - "marketBaseVault": "GoqGHVC9GS6TQVCmKJZoPNUAhMdBPq2GKWyieDrAVXQJ", - "marketQuoteVault": "4Symmju6i92oc98ss47oRV6A4yszyjnQGBXQSdfZ7358", - "marketBids": "EGH5NkXs5PmcwZD5vmvsetwYa6xkxFEx3UcvxQ4PMGue", - "marketAsks": "BQ3DpDo6XgK8xvRozcmVZVk2pevPAKknTuTDPahNHcGb", - "marketEventQueue": "8kR9Tb8SXZyT6LrfnnFF91cKrLUMqNcPBUjtqTtgGuh4" - }, - { - "id": "3VAFXW27AYfBVdFtzUfEQXChRi5URuzV8eLHdC8rGcxq", - "baseMint": "BNTY5DaMP9CZhEtmQfMLHfUwwkXropHuCz4m96YqpqKm", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "GKzrwxdyVB6GYryHv5vrWRVVa8oE9MCHqzCQ9pjUxoLQ", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2Fkv5ThdHBJcLWYqDhYHh3QBjnDDovmzdKavsKGfcu1F", - "targetOrders": "2wVKByaX2xPexBBJEDx4CFpUy4NPgwWcWw2JtjXZitFh", - "baseVault": "CY6KYx77RnD2pKMQxBAEQRRFFzyiVRiLFMvN2i6kbVX7", - "quoteVault": "5XvcuQMpzfvUFCshWmWTpYYYYkXnb4AQ5Ntx3VUxHnYm", - "withdrawQueue": "4bC2ZECpvJgEVevwBsggUQ2PFUAPqaiVxjJUgwQuP5eR", - "lpVault": "8BPsc2zMAzePrZUYqCskZntRkxdMMPfHa5zev1DDv4f4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CWMgDd1kuVLRyeH1u5HP3gTHHJydqab56mQwviejfXqm", - "marketAuthority": "7zYARCanMk7dHbWpx8Pf2rA2BdMPTzxMVFvZoTSLiVzU", - "marketBaseVault": "HHRf7G3q6mfTX32WG9zwnqibNoYAr3LnnZaEyMYhbgyc", - "marketQuoteVault": "32edRzGhVfWzBTcGeZaoAbVRZECAbp9qGLtg2q5HU9WW", - "marketBids": "2J1gjcYJFh4UZENX59MZ6BKjE8dthzsdozfwqbq8t7eU", - "marketAsks": "5pEm82zk757nWDSBX8TKSm3RL3HfqbWLdBBk89MTSYV", - "marketEventQueue": "EuRofGRS4ctnhfDhTJbHvpUPU5Zd7NUtL1rZErUtsSyn" - }, - { - "id": "3vBCQNd3YVhMTsQiKg2zNmpQFhwdgJPHpu9x8mZyPi5i", - "baseMint": "76aYNHbDfHemxSS7vmh6eJGfjodK8m7srCxiYCrKxzY1", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FTXsrept22Ub4MjDSPgXaAboRi13GmKJhuaauoAXWeZJ", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BVSEVyeXWMY6xaEN5MuTR9L2i7BfQoXXqMAe2qdRHkBL", - "targetOrders": "Cz57g7DBqHr4vXPvSeiV2kN3Jpj8paKvvFkWipQRWhPy", - "baseVault": "CHHM4qKPpAaPH5JRAV1yoAf96tb3Pxs3pFrTiu2SYzjW", - "quoteVault": "nvLFmHw4xHrf8Cz6hcv3ZQGLGi6idNaJdfS4Z1Ys7Zy", - "withdrawQueue": "9brH9a1rDG3foexrmzcmgQCUmKAmdW9C59grtRPLVgjU", - "lpVault": "HXAtUVbZGSLLDEGEGegePNPhvkHXs4u49v77XSsaGyb6", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7S1pauEg5VWSXeEFQk9WZqBkGozZFUGiEAS5nub29krn", - "marketAuthority": "4ymfP2hbJyyTQ6MQvevm38fSFiGQc21dYkfzuumy4k8Y", - "marketBaseVault": "7L2ASqqcEzKEy7G95RYPo9zr8LdhHLikHN7DHPGXEg5e", - "marketQuoteVault": "4deVxT5TMDUW8R8zdhzveZ59kosX2iJGSs2VACLZy5s2", - "marketBids": "CNvTVDq3cNrCcEaefT9sWCShuFtiqE2MxnSMjQMbNuew", - "marketAsks": "3W7ddNLtt8fDEf2ZX4aWL8AEAap2XCpir7SEM7zt2ym3", - "marketEventQueue": "ADGUg2TnHQYENsBq7XEQu6Bw51Epzz5HDb3nnm8wp9oR" - }, - { - "id": "3Vca7HHGesSXNpFWKpLEcXj9NMpsUhLPSD9eVW593e7Q", - "baseMint": "8cwRn9NdRp4WZKYcy1aRbzNjNcgDpMgXGxkUb9w3otxu", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "FqyWTiqHFFSjaJQiozUvsBRnygJaSXe9mtuj5LfwdenU", - "baseDecimals": 0, - "quoteDecimals": 9, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4Sr5auU2q2FUxWJmWaPu3FUtnzN4xHBuvsMr5Qw7hNym", - "targetOrders": "Hw3FyGLS1jSfnSMg17n1exgDpTHZ9E4wyVtWVXqXaADb", - "baseVault": "GXuv7QLiy9QnpwCJ5JyDHnbpigi51kZgGqVEj36pBtfg", - "quoteVault": "69XTfVQxfXfyDTmEKU7HJPro3mrXk1ktZxb6KG7TwBoZ", - "withdrawQueue": "HwsTxzoYQ753hGP2gYrh5XkoxW9GX5oA3jJfNd9rSkVW", - "lpVault": "5qzpuU465vSqMWMwQoqdPm5nmxBdtw4fVdjkMskqNXGS", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "85KcARYHcszAeX6jd43tUfNHtSBTCigKLB3nFKNbRzPA", - "marketAuthority": "HHUcqnuVWc84HRixuCdoUGb4AX2fEC81VEgrU6jXGiZh", - "marketBaseVault": "9irfyTtFRL45TV4yhrCfcA6Rqr8VLZ6W7Dg7FBYphSwb", - "marketQuoteVault": "6sYKxe1cyttGzqpqeqqTQPZD2YhJoELJcHshhTsGSyG4", - "marketBids": "Abu5fQ6pMbM8Uggghg7yBJcser5FLEZ5vZz7iWEHgnfZ", - "marketAsks": "5ppBH8CpXaLWX9DVkntpSo2B1tLTZrW5bsJLhcMH92R6", - "marketEventQueue": "9QmEnjHAUhX9CxQzRvpQeDTWp4oiKXViF18pzKBVt1eK" - }, - { - "id": "3vQuMexWBfLKe5iY1eZrorrBbJ9RWRnheQe4Jc3irWZs", - "baseMint": "4TT62MBAWgE1m9hJ7ABG7VvgGvnth3eXe6N3MB6xKSqt", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2PHefxR1uxuMZ94qP1vVME3Kcd48AHPCCu4mkc3or256", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8RJwq3VkERgMeKdpbLdTmcCxNNydvS6bxmke9uFMbD9M", - "targetOrders": "AmKxJDuKdeMeSduwEferEddUAqq2eUTwMVsEFi1zA7PR", - "baseVault": "8fBbQjS26FwpvV9ehxc5y8RpiVJYkNLpi6ymEauNDaiR", - "quoteVault": "7P2dX8bDFaSkev4pdDovbctgYMXtmJDET4S91P4ZS1Kp", - "withdrawQueue": "GtwhZJybXENFED6mTUiXGCoq1JeXnvmVWCh9WAUx41tL", - "lpVault": "3f8Nbu82ezRq7chJQhqsvGXRCibDGUfws79eE3vKBj1t", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3MPMjUEGQE3dCYoo3kpuKuXdRF7vCuL4HBDdHaBoBh2f", - "marketAuthority": "CtTZsGKZN5aggdoV1nfCSjmpQsWneVyidZgeKzNkcEeh", - "marketBaseVault": "DQt1N4vpuc65pMBaj8N5iCMAPWyjwho9ECqY7iNtvfPt", - "marketQuoteVault": "5X2x1gF9pNZUbjaUKeKSJjrYRv83E3phe3LwWXt2XRgU", - "marketBids": "9UqnZmtrhumToM6nvXMujyX2dHR6g6uEfZ34rszMCsKJ", - "marketAsks": "9qmFsKdkys7cuy82Qp5EP3PUGTJsHohV1LnWo5BJE6yP", - "marketEventQueue": "BQ2gMtW7vin6iExPzD1SYAqGDScJHMTdWtXgWc2sTKew" - }, - { - "id": "3vrvcEt2WitDwUnN1jGhdNLzeDUfGTTHyGynC2EQ6CAr", - "baseMint": "5fTwKZP2AK39LtFN9Ayppu6hdCVKfMGVm79F2EgHCtsi", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8DAd59ZyUkcv5HYQxMvcNYNBsPWtmUGr78yAyDcuFWJL", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "uVQzGrA1GefAmqso3haQG5psiCJuaASu3iPsHoh1qvN", - "targetOrders": "5raYpgtcyGPV9BmQStMhMp9uMorcXKdUX1Btc6uN6rjU", - "baseVault": "9HHMyRMeYSyeR45LSnHHvpofq8cnX2dShUg5zmHsDpiA", - "quoteVault": "6DfcYNaBE5FUEYNWrZt2tssdtacLvduxCsaNQWx3WAKa", - "withdrawQueue": "2mj5YGXqUVvRaupTrXH8BA3JeKJF9nfoDQkPq9xtWerF", - "lpVault": "3t2sG4cJh4NeBrGuKCgGPUCReMy3sKLTehiixkNGgy3C", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8dUZBSu31bPXa6Ub7JR5FeZfYfZUxCqpZ5DRWYG6m8Wk", - "marketAuthority": "HsBox6jseQ7TfXZ6FBzJrXbWGRrCWMvP6S5RYYAAW8yu", - "marketBaseVault": "4rG6Qw65WXWrqTMYhcBtivDVqaF6TuTvSHSKhhT47cnX", - "marketQuoteVault": "2PotSZeqwVaMUdrvA83tm5bxRxC3Hqbhv884WSyQWgiW", - "marketBids": "HtvZEyHgZozwjib1Cd4VeDaKF6iCediNjVKuSSbcUuuu", - "marketAsks": "Dpip1hAzA5sasRoateDeq5jfEezF52tKydjb7FjD8joN", - "marketEventQueue": "3L2ruf5wxUjGzZP6dcEHfjdoTzJC1XCBJQXLA1bmNQrq" - }, - { - "id": "3vs14NuhsLrZB2bVP7cuP95z75XEyQNhHtkFC2LAZ51e", - "baseMint": "zwqe1Nd4eiWyCcqdo4FgCq7LYZHdSeGKKudv6RwiAEn", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FRLngQu5G4wDzymNiCxHpo23YUXbgTXawfPgPBGqY2cp", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Gp5CYbKXm1HvwmcpcS79h2du9kTnutUSpcaKwA8wansX", - "targetOrders": "EyRZH1vDYxaxNjfDPY4bYD8ayQgAdazc1AnCt4rXF68T", - "baseVault": "FDo26fLMJbbMRCtfHaeBnQmWPEy51SfERiNpcDGsiEP", - "quoteVault": "2JUiZdN1GYjSEQFDJPTwFFZ9dc6LqSqKgd1KPHsP2CzJ", - "withdrawQueue": "FBVpMNqsnVucujvMfxgWAdSj9akT1fu38Lbrcmuc63dQ", - "lpVault": "HV6USByruUD8Cd8AbSgzmd4GCVCbuXj3heJb6tW1LFfv", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DcmvhCKp2k7nNwcyoF42trzvatKudsArWR5NCaQY7bQh", - "marketAuthority": "DUbZkJ7UPVeLqXkKAvEv6z9hjr8VP3x5JWNbYzfoDyhz", - "marketBaseVault": "5bQBo4XspBeVTmFguihuqCkEjHtgNN1GpiPGtWAwjLzd", - "marketQuoteVault": "CYps3nYHjLAqvJJRYX7cYLSEJ8iikuPAgxnMoQMNajn7", - "marketBids": "9LZGus91hikboLDuUHvi1JqYycgYmriCiT8VBNy65tAL", - "marketAsks": "E5YJUaXnBowTEZR97uZp5jvwH6Mek6VAm8Csm7pv25BQ", - "marketEventQueue": "6QNHKHDt8iUnhjSiNXwdqyLX5JxGM7yvq1Rv32YBvxJT" - }, - { - "id": "3VvLNse4bHQfQS5H3LVRmreSFzUc48ZCUWfnAh6haoBm", - "baseMint": "Gro98oTmXxCVX8HKr3q2tMnP5ztoC77q6KehFDnAB983", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6Ysrg4UnwzCTtWkCGGEnTA8Qx88u9jW8hbbWWTtSgTs1", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2JDiRdp96tQVxZtF43VaWjpadYdrVmhgsfCe1TX8c3A5", - "targetOrders": "4JyQe9UzxfLAEFahydzWnRq8QutxNCnMBEQtJwp5RyUU", - "baseVault": "DfB56N6QSi1zf8vzzu56DUsf34XUZNsWCtPzMQAJe7sS", - "quoteVault": "6W1FtC66c8qSQLEji7XFX8KTVK9Tw48uZbCdZnWh59vE", - "withdrawQueue": "zfzEzy3Kv3bfghoJX6J2sd9wtKA43Lxnq8JUNv3wFrr", - "lpVault": "HC4to7hECX7kZQuJdFCgmsbR1B1KwxPAn9dMy94y6tgU", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FZAn2H4kzz4bFuez3Hqgg2qz1sHRQ5mPZkowiWMk95sX", - "marketAuthority": "KkCVhKnwpNwP2E7F41jkPSRaVYaMw6g7kYmZdLpvJxE", - "marketBaseVault": "5kBC9HnFdQVXAaSwWQchAE4hn2Zyp4TZSmbEjSHUVmKB", - "marketQuoteVault": "Bx2o6q9vssQzQ3EyyxHYRmVF9gADWvDXbw9PaQi61o1r", - "marketBids": "2yRgkvRNBigtbchLwsz15N8AUhd9kUpMQCHi983Z7NCe", - "marketAsks": "6ZBs8CWaMqLU8V9dUCFZevotChutuFbhyWfwpnmZFcZY", - "marketEventQueue": "wV9xhZExE6WfZ8cMCFKE1RD4ceZUg2ZA57VDPj15eVn" - }, - { - "id": "3wAByQHB9avAFCt5rwMkXz72GGQFZztrgYVNHj3RcNHj", - "baseMint": "7xzovRepzLvXbbpVZLYKzEBhCNgStEv1xpDqf1rMFFKX", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AaT21ncrYisNoMY8FM9Utorsc39u29nShqcCChQT8d9q", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DmfjHKU4k9yrxGCFUwyVmzZ4623MgnPbL6rERyvYxyd1", - "targetOrders": "6u2yu1jxojgqargXtNfFxsxojPyHe2v1Y6nhfGfrtpEt", - "baseVault": "2kiqbjLcRiZmUCAs88n87k4E1MHFi4uhJQ8LhmPVkRuF", - "quoteVault": "J34iLVYk81bzVUdWtr6T4aW2Kt5tZsyHeKX5U23V4JZK", - "withdrawQueue": "65wsRQypSWy4imUrt4F58haWpD3jVcphFf7iW2D3jVys", - "lpVault": "5s9YHPxenQHfmrP8k1k7JSZR2GbrRf2mLUzjwHLniXUV", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EmyoFKQQyALv7mMDL681vV5oanPsLhFggvgJh5gE29vn", - "marketAuthority": "8PvdL79hJgpUHGvuGrDcqqwZkTqWemWncBEAKzs6fWjE", - "marketBaseVault": "GiMPcnqeG1o2MWuPJjgJaEzBei3QyLYM3k33SjnzBLnF", - "marketQuoteVault": "FMYEeocobuc1YePeGY1DFziEivveGAmCQaA3ugGXiXew", - "marketBids": "4xK52hxSWHcdoYw6oXhX4qqRD1g6DfvqVD9MRiP4pwH4", - "marketAsks": "Ff9TzbMqKYLaJYKRUNtNuXRR2qGgMLi4BEr4k5poigni", - "marketEventQueue": "E4PCUdiXZN2niqh79SERmk755i59sN5eqFNCrcFUN2Pg" - }, - { - "id": "3WXoLoA87bTy1SrLcYhx1hZUMnib4aQqXrWvBtvyhd2o", - "baseMint": "2V1AVjDVM2gZn72ZufG2HfFHDKXzS5XaCupNeKrdcruT", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9KjyRxUqHQmtXoFazont3taZCvdSuKsT7Jr3GxetkDzH", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "H7w1PJydFJYezjGGF1qHzBjhJuu5VeoHZ6BGVcMUZQ2G", - "targetOrders": "Brcqk2njT3cTFxAQZp6YajSf7PpJPcwjMJKP9mKkvgSS", - "baseVault": "8o6YVzbZTGZTra1miUv7TtaRoUQbLrtwo5mzRdr1QexS", - "quoteVault": "37H2aVEK3Jr7aU6PDJFwrZiar5iwTvb2ifKGZvee8r6B", - "withdrawQueue": "Ecex66RiRehmpti5XGHyDL4GXyvxeSS9m2fYczDEeAdw", - "lpVault": "44FPtwaTpNTgFFb6TgrZEdGqEcsy5CbbrbWPU9ApR2eV", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ENveZ6Xhhx2UKdSkakovLyWsSH5k7Wf9CBoyvzoijPmJ", - "marketAuthority": "4tYfiKE1P89uSpV7U2LrrVidTGybWajjCtrH9Chp8XZU", - "marketBaseVault": "6ffqmmCt2JRRds4bwweLS5aHCx9s9R68fjoWkWX5anBr", - "marketQuoteVault": "7Ds8mZYLNuzbrHJ1B13i35XGKy4tr867PifAqWJJvNDH", - "marketBids": "EDEhXmWQHaWg6W9H6TJzW4iKRVL2CzPBkgFfQTC3R3ij", - "marketAsks": "4EKqG1aUSeDQ5KNB5Vxq5k1TFLPWx6keUK1CUz81BZeS", - "marketEventQueue": "2DgoZveHKsuYxT9cUWUgzcP66QRLKk5quwdZVzMQDfFe" - }, - { - "id": "3X6H5FocZjSGSyWLaGEW4ZsbkxqoKb7WdgGSmD1sXTcD", - "baseMint": "4bgRUBC4gPoTs38TytDwujhcdn7reRoKynecvK7fJ5VW", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8kFTivc1CmQQrVazeTywRDjZwCqQpcvwQ4hZUnjwWx2S", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BxTyCgpT1pFzwVAXLWfaHWBpFAZiW2T2JtHGMwM8dM6H", - "targetOrders": "BP6dYPgYqrYuTTvMgoyH5eKQV6N9hZ6tVygoF7z1azmn", - "baseVault": "HK3z6qnNFjYmXZuqSzG4Fo8mmWkr2bpUMdoQwQJxDMbB", - "quoteVault": "3bur61a2wgfAEKNUBm1BDG9hRLLVCiSL1UvzaVGAc3H5", - "withdrawQueue": "6YyHnaaFj6yqNrFZ5J744eq33bnqohVppACx7kMCp9Le", - "lpVault": "HhHdX4eBGdSdTxvtbigR9jkzZaCf5vJbwpcFsErj3rzN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FeAF8ELC1zwcG6skvYuuKC16rC6xE9qi7WVWz9gCJ6nS", - "marketAuthority": "BYGHzsqgrTaYMDixZg9PcrV1Jbo5RvQPezk4q5USKG9L", - "marketBaseVault": "B2xgjWwooaUKrXfJ1HsriZXWVkomSwVYcTuhrvSR5QvH", - "marketQuoteVault": "FeojzjHP474BVoBPZCpwf91npDNVDjLmTkmDm73i3ge7", - "marketBids": "2TMaF6FhZeQ7inUDJWjm9JUS5FV9qcq9tRVzMBxAHugr", - "marketAsks": "D3vWJSFwoL2k4vDnB56RnXXMD87mn1Y1Yp78zNH8tcJq", - "marketEventQueue": "BjStBxe3W7zXJ773vNJFubeEz6Edc9CtpSFA14bwGMtW" - }, - { - "id": "3xffj563mp1UBTUbGpv4QafVP9b6DVirh1DVcCocsKke", - "baseMint": "4h4LvS6NsVjZ87uBwrYyTeppTm1ii5PtRN9A6Ld2kZjw", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "AeP9hSGLsYvaT7NpayfwgRsrDGbrSZfBedxnaDsiQnQ5", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "42MCfaamXLn2hC8GB2DQr3yoVtae18cMAR7rXmG5nm3Y", - "targetOrders": "937BP3NQBwJAEMoqgZ39ZV32MRTvbAS5tBJjRbHY87Ux", - "baseVault": "6hggzNQGsCwdoJuRAvcEhc3Yt2bPGDrkKU6qAwgiiqCD", - "quoteVault": "21R6n1DV9QQpK9fDgMvnpNJ5M8AqCxXdbUEQHmRNyiBu", - "withdrawQueue": "GcnWM1KHsqGojV1a2QSV9Mrwv39kkei14W6XEmhNNkYr", - "lpVault": "6AKoXEJZHwYgpbBK16dHB5V54R1Yi4yfwF8DpUNFsgke", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "58fq8TRRFmy3EMM6d1NWy3MoJAJv1ksdcvMZBuhGYbRX", - "marketAuthority": "5jiasEBcFgDdJfhreXYLYgU98h2cqyFSBjX84CADbGWo", - "marketBaseVault": "3utnrcZwuSDK7JUUpoE7e2uE1gKRJWbrHaic4deiCRUH", - "marketQuoteVault": "9hET2p2kFn5sbBpoFvuBvbcgZCLPiRC5HqpGt6Z8a2Ma", - "marketBids": "EUDkHPzS8bQdgTY67QTmGUrvTz5L6ng9FLMyXep1WWav", - "marketAsks": "4qBioBJgDqRPTBvS9ytT5v1XyuYAPZxTT7rc8TWkHKKd", - "marketEventQueue": "DbDH1J7QF975UC7tJv7cFA2PuyutqX6J9LFQMhTjZoi8" - }, - { - "id": "3xjwgFESqGPhaDWRxMUgkNnK81LQ7WRyuFaNhkxiSRen", - "baseMint": "xkqjobmo1kUgN4P7jcsWe5ud657oA3co4PnwKoQKG12", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "YZJuqgEvi9DT1YtFytoXLwt2VfaUDfxzWEhszzTSo3h", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ARnetYJ1ZPRuXAxGr3k4t3UaEHgaDLLG71mzCo9tJQaQ", - "targetOrders": "Dg63sBnapPTtvvF2C1gpzAD29LE3qgfGiSnkx26up2KN", - "baseVault": "5owP9oEUxXhL1qJzFKy7zRyLjEYeRk4PS3spHQoSXoB", - "quoteVault": "zv2coD5UXUvcnRLPjXkp7U8JFLs2HQWe2eypa9px1RC", - "withdrawQueue": "C3pKZ8WtgFSi2hkmkoaVrmBawxSjuwi3hueeNcmwNpLD", - "lpVault": "A7A93JLaUkL6Wd1cwr7K6wFG3Rao9Sd5b1apXYBrXTS5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BE2QcADLhvReug3sx4rzq8x3DgwXjhAvvUxrbH41dAtT", - "marketAuthority": "5KgZAbLNqxUPg46oiWSbQdwp2DKLwj9UYozVbkP2S8kF", - "marketBaseVault": "BnrjrnPkTRqUyjMWJJFuDPLSzPkstyueBsZXrLyaDBWz", - "marketQuoteVault": "2q4kCY6YH7A1eBZMaU2nok88WPrASoknTARjmKinXCHC", - "marketBids": "9zsXQjh9cZHaZ2AxDCZ1J1SqUVKw1dFatNnA3KLkoALi", - "marketAsks": "536arG5y4mUdhCmyLFMavtd1g6H38BuHhqZUcaXi8g71", - "marketEventQueue": "A8gEaZPEMtvBh7UBUiUPuqLfRKTWc4FJfyy6mNpw6pcB" - }, - { - "id": "3ZfriFZXsKkBj6aVoRKPKNq9M5K4uNNyXrigiB1jvmMQ", - "baseMint": "Ch9NFVk5sqEPQHtw2gJVgnHfTm7FW1JspYwc7SxLi6q3", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4EUov6eb7oPuc4iScq74bN6M1QnPcU13zWE6iCmmi2Jc", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BVToxnJSdV1hBgSMdKCp5faBZr5y3M1pJZnzMuNhK4d1", - "targetOrders": "5S7pb6y91BVkTfxfzNsgASYiaf4iN9tdcSo61Bc5wcsT", - "baseVault": "4DMGduqSo64akbpt7KM5VEBnQKRrSe8AcMMbjHfTEAg4", - "quoteVault": "52QcVmYgs4Ge7MX95T86tbQctupWN9DkgeYAPcDksqCn", - "withdrawQueue": "3ghvawVtsiWaMn8ehJKvy8U5CLgqbq4AqYgBtjuoy3ST", - "lpVault": "FMNENyTkS96d5q6MaWVEoJKuYcgWGr8sgyuGqnSSgCqD", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "v2Tqp1qkCrEmZm3GDduBVVaFZ69VmGdPLnDdYvmw4Kg", - "marketAuthority": "DDxwhHkbjuQvEDunur3CXorqEeH4oVh7ZVQnPEB4skmU", - "marketBaseVault": "8o37TDyB8B1BD9Nom8pF7VMXgyFrfTNbxDrHkVbuxEEc", - "marketQuoteVault": "D86xXsWPtRJ5F54RNbMETSM6AHciHY4mwEqNvsnsSUEL", - "marketBids": "8wX2kcqZw9T2zkj9DVtSdJbCXvAKiMs7WYsoeB477kzk", - "marketAsks": "6tCqkywG8TasjdDSLtANtTjXR3ELtifLSqphQt7Lrx38", - "marketEventQueue": "DfgGZydJmANCrcc1FdBkvfC4aPeBS9vSak9Y1p7dAnHS" - }, - { - "id": "3ZmaLWQucqTy7BWCNYyqYvURaE6fVQ3ctv5w4V5ySU7p", - "baseMint": "GYCVdmDthkf3jSz5ns6fkzCmHub7FSZxjVCfbfGqkH7P", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5HcN6nedJcbwLwnRy2He66zhCdkdjTxVdGMQky8acMZ1", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GBBsQ1SwxPZMf3u3gtQ1uVabbaFMeR78ZMJqmWYbGXMh", - "targetOrders": "4XisefFqzdP1K8tKW78cGBxWjRY4EXa5tiQdCQ2FHHnX", - "baseVault": "8Ejkj1QH1Mkmr7bN3CnA96nGUNb1zDznGgiEzrYo8weA", - "quoteVault": "DDYQgskHg7qmdmEwLtWrvWxSK3wNukDreTG67QwuKHgF", - "withdrawQueue": "62g4DKiinFLkdW8ae5FuNJERmVDYXaNs3cpSZLJnxxEy", - "lpVault": "hS1UBVmKo3h2ZiCjMYJjf9yD7sqe7fMzDhm2f33hrQi", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6vsgiAyqEVpzx4wdGRGopjXqwfDngmde81QQknMcanE7", - "marketAuthority": "42qsy6bMHPDvuMMRMPUgb6SK1gtyKpbuHCvsqMcng62D", - "marketBaseVault": "BD7bK9pspWQWXSzZiEz3HY7Z8ZzYMs2YDnWg7jTmZCz2", - "marketQuoteVault": "EjMNMH5dwehRvh2bvak4srmmQJMmTrXtpnKMCgQ1rYoQ", - "marketBids": "AhCegdD4rKKReeXgNKEUT5BgEB6GYyHBUtX4AZ9vauHo", - "marketAsks": "F5S4rMoRY8ykGvHHqddLwkt7jJacpxWidPtL1EKNvAQr", - "marketEventQueue": "HzqBzuHLTCVCRSK5RzBEHCM4UynXkMoPkUYMDmj8ovYM" - }, - { - "id": "3zrq2oXNi3SKsWnoUQQh2aNKPrqA7hPqdA9VvDgTr9eX", - "baseMint": "8EDaoeBqpcVACwvkYXh1vAcU29HiBiNhqoF4pRsuUsZS", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "2gd6YHQh2ZpB6nxLyUb4YUfKMEq81i48WPPSpnnvW7UX", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CoWpzGAXH7VCfDLhayNz6ovLyxaS3HGaEJcKezg6JRjC", - "targetOrders": "8ksNQZr5DnYDspXXDXUc7bdh1e1ZhkJoKRPzDQKXJczp", - "baseVault": "8czBqwDTG7RkdVx6hLJoahYM4qVqgy994uZb87RqazkB", - "quoteVault": "8L5Dat8zWbKHamABYtLQRBoyf73iKY5Bgmbuj7HJNV8X", - "withdrawQueue": "BGzTS1cvKmwWezgdap5wNpvCiwbADGnydS62rNRKWp9L", - "lpVault": "64g4dbsyrDXcQKu3DrCBRs6K3sh5sSrch6ucNcPY35E8", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3dCnhVwEfAh8fvQPcWvtUZouH4VUmbLmcbUVCVeGkgXy", - "marketAuthority": "4QbCeTuaTG5VB83hhYS7zmhCTXzwKL25Kwf6UXoVr9hW", - "marketBaseVault": "FMbjTq3yFp1zCh5sG9EvzMRZM7NxZvSuiC9BChvBunWV", - "marketQuoteVault": "4uHzZq7P3PdZbHTyYxEktFvKLxKoJ99z4dr7ph2NuZrd", - "marketBids": "EBatuBsCFNa8s2X7rE8pXVF9DNFZCsyZMtBj3fDVLsSD", - "marketAsks": "J4fL72xbgpxrNcvFu7NQQmmc6GLtwacJaQCNJAA1ZJ4W", - "marketEventQueue": "FpCHyReqwPPFzRS3L1XcUgBpHd7naXjzyRCq8qXdSXpw" - }, - { - "id": "41PFxAnhF26HGYb2E5GsPFQEUasegUFuhRtLDnM6kmF1", - "baseMint": "5RRQKdF4MSicGSgx2HiGf9Fr4SN5m5743S3qpbcEc5fk", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "GckM5SBU1Z6PGUNtkd5yhoFWi2u8aHFm6EdSusmrdQB1", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3Q3ZwfcxUQy2GbFTH2HmLpmd932gaDWSWHdqWHYsevUk", - "targetOrders": "9ZQS5wBrpcptua2om48WPW6mNEs4fRAuoWKgdF1ySnjf", - "baseVault": "ANanxUDuB3QPfucvUfP7ACUQQUqeyyNo1jLuZx15Ab58", - "quoteVault": "BA9yZn8Mmb164JsDCsZ6fp9RbBXU3oizKgLVuwwJXwwQ", - "withdrawQueue": "Ggzm5PyeYYSyUnfZJp6PaTXPr2S3AEKdpGf5Nhi68484", - "lpVault": "FjtkLeGaxftMMWxQubGGKY3ufpPJrv2v4omKW4LqXFHx", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "98Vp8moVQMGBG6SDPbKppM37oxe8t9naAPQe3QBcUrnk", - "marketAuthority": "CDGDfKCRs1qQ69ebgfv59rwGkvoJffu9xnRQrUZxujie", - "marketBaseVault": "DzNHatPt5qEvnLcSkARCCDvNgXvVTTknDZLdckrhu71q", - "marketQuoteVault": "iWk8Xw3Y8QhcNExTe8Tj8zwxUQbV4b3fcFejbFQrkMG", - "marketBids": "CYqhafUwLeVjZGs1BiA4H3vXFzjPSd7NHJ8avRBePPVw", - "marketAsks": "EUv1DsMV8mqDgQC2VZxyXf1ryG3wNGU5AtW3UFmx32Kc", - "marketEventQueue": "69rCenWT2onedSAxQioTDnjFMUm3g4SmPp6L9MDKMDTU" - }, - { - "id": "423GQTZTT6PAomPcgV5NnFCYVocqDR9hbAntiYsdB4aM", - "baseMint": "5PmpMzWjraf3kSsGEKtqdUsCoLhptg4yriZ17LKKdBBy", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4hGLLTBx4BJVjHQhiwg5yb2Pck4JZKsTGQjKwrCWtQ3j", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4HxSLk6DwDF5EbJRd2roVzyJ6dBMzo6cCwjYLNK8AHoj", - "targetOrders": "6YYncmHMaAHwb82WFFGsCjGrQorshh6LZUUH48xWFwuB", - "baseVault": "HReWshH4aWP1igSMLifiFp4ZJ7D7F7nEbjPEzxqYwKW7", - "quoteVault": "9o4TtfHfzjoMVLKi34hvz6D1RuVUEBefb6mXNB2s8sxT", - "withdrawQueue": "Fpjep45AQU51bXKiksEE46w4atppdvHgE4MM9h6KzuVe", - "lpVault": "7VFmVh6X1Zkcfn23tNypnwGsFTCqQiT4B7otF5sVG51T", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7HrUmsVM7poJdjgoteTVzx3VMFyLcAhdR8JMbuFD6VNq", - "marketAuthority": "CYKfcwT1dGGcSpHSPkqYkRUUR1EdMrUpmikYHtVonmCN", - "marketBaseVault": "H7zTjR5nQXATcjep625G4d3dw8JEXgTcrDbcxYxt7Gsr", - "marketQuoteVault": "39sEwbtyacyUyiNVKw2Y8AbyjDyfNm2D2jrcmfsgCw2q", - "marketBids": "GPkAZA11ksG631WHcPFViVVGwRYzPEpZyDkQSa3VDEsR", - "marketAsks": "12eQjX6AXmfkPFNR23jF3vf6tErKzRnVqbdswTSSKniB", - "marketEventQueue": "G6kxp1CGyczLg7iYjg9iGg8XQze4adhM7SZ51NvMVqSR" - }, - { - "id": "42DrSpfDLPf4Li6XcMdbitLNV4kKtRVndUtScYB6JZwM", - "baseMint": "ALKiRVrfLgzeAV2mCT7cJHKg3ZoPvsCRSV7VCRWnE8zQ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7byiNMDMsm2XSNYu5WpqhPyX3WHLXEXG3auGkDSdKCTe", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8ueJKNkirW72Cg2opgnHBTCxXsC3koDqv9L6JyZNagj4", - "targetOrders": "3pFFCbgQop1KUiWh38ZGd7F1HtJ1kP9xmohsLkAUVQeJ", - "baseVault": "CSYBTLHRWtg4kQAiA7cXWDDfa2GiXYd291PkQWtA3wi2", - "quoteVault": "8ToZUjgoUuRX8XdQjgakmefDsfTarmEA5yb8M9Q3QhC5", - "withdrawQueue": "ES2p7ko2trQ4xgHWnCSdJSaCPvL7JaJbsuWt9VK6d2vy", - "lpVault": "C9t8EvwU1TomWLqA7hnxBq9NzPxx8MrRWVyBRwfTaXjq", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "13SiVjqfxqfWZ3i2AbDZpiDmL7oxuf1wWfbqNcWBJ52S", - "marketAuthority": "DXj3Ye9nFMr7xtPsndfwDJmN29Ae6dJSGB3QU7BSWaLK", - "marketBaseVault": "8pUnn7ZnvWEEBwxa63LD3KeULspF8pMsKfD4zuG2AuGd", - "marketQuoteVault": "6a22aVRMXinbpviNxASRm57nwdf1BVawTaJCZtErim1j", - "marketBids": "DmDXLa5arESoJwmQukM2iSUqfw1FbfzBNAUBf4CAPGtb", - "marketAsks": "DWSwP9tmDrMXvE51qhx3dNfTFrkr4SiC5bXQa6oPSPdd", - "marketEventQueue": "A6UjhYZDatVJTgvM3cEyHXnQZdgT48LkGRFJtgY7NecF" - }, - { - "id": "43SY7LEDj4tgRirjdXyWbD69osXwx7DJCgdhKa9w38Zh", - "baseMint": "939KAUTAyNdmpahj1vQmbS67D7auhyJnkMt4sv2tzBwU", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8VRQ9DmMNXBHb68tHZyG32opkEYETqDDJhkWi8CcK9te", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7SSTDBMmFVWbGzFQAbzdTWQARuFaovDRxsqgS9HDDsRo", - "targetOrders": "Bq6FXPxN3VRRong7GYfNKbEeWZgfrK34QLUbCsWoVCxw", - "baseVault": "6JXqkFD76mytuGBmRvoXJP9SUo2y7ACf7jhN38LiKJxj", - "quoteVault": "CRUDRn1N4nTZh3Mcd9mpHUMknc2Z2hX68GZLikXxnzyz", - "withdrawQueue": "3spU4fpQfR84JeZf7Bv4f7ijoBb64T6EeK4o52qKfFeY", - "lpVault": "BTUUa5N7dnnB86ArWiBaNrNnSTqvYwKK4AifsqoKLKxw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BfThHLywNgPkdHxY7Da6EKPwedTAqRyiAV8nC9HvQCRj", - "marketAuthority": "H36L4ZpzeX6sZGuTeTcq8ApkJkRC9DqFzoqHjDGhDaaf", - "marketBaseVault": "8kucHZvuC64wQGA7XWRsEcwThnfk5YsbHFACJq7xbZPz", - "marketQuoteVault": "47xLMDyyGwNnVomV7VbdVSUuHDZMyv8uRCsxysaApCob", - "marketBids": "3FfvY7BedDcB8VEfDViQwPnBRgpg2C837qx6kqq9RnVu", - "marketAsks": "6VhemL4kygVGC9DRUyrKkwiTJYQsf7j5ABcZz3EeVczk", - "marketEventQueue": "BdoZ2fwE96VsoGS3m93W9WqBLcgsQNfYDGCoeQFZboVQ" - }, - { - "id": "44c6BGj9rGFWq7ky3fct3Di6F5BBuvCKGmdXaZudFGgP", - "baseMint": "aYZPYgohjK6LYM8o1v6pnr3ZinhuRzSHd6TRDVDUBkK", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6mZHaw5C6gq3bmgSqxxqCbYBNUv7PEKuWZ4n6MchRuZq", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "C8ubRoTW5a6f86judmyDMvJ4ip5U4kVfYGw3rbTq7Ymo", - "targetOrders": "B3uCYYmXisodeUkofRRXDQPxWMxhZxMm2poFQ494SGnC", - "baseVault": "84qyNxz3yeWoiHEvrcYyakQA347GcJst5jkXjoU2ivzU", - "quoteVault": "92bweub3jYPHJGYTc6XoGvrmBYpitxexRnPrWVQAETD8", - "withdrawQueue": "GAEauDNA515cJosnXiNH1VNd5zRxRJ6X5MoivNWDPm9", - "lpVault": "68jxcPQFCPpoMFE2jqE1JcRjvDwZaME2Lqpm1Sw6pdKG", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8FxSiPp1pn3C7Rkh27TykKokFrUSRbPerrQYEQzFkUBr", - "marketAuthority": "9Gd2FSXTgCqfe7XaBJgDw93ooRY57G2Q27pgzfuC9j11", - "marketBaseVault": "5KAgCGZ9bgp9DRiymSNAaYL7re6ipA3NdXgs7fTdV9x4", - "marketQuoteVault": "Ea6yuVDMydTccJ2DDte1mBD4fK2dhgKiQpckwm5QhLLA", - "marketBids": "DsjRzP9pDaLCi4g1hzRxpXctgtyD9Nj4cNE9q1QdUvsh", - "marketAsks": "BvZwPTYRcxajcUukxB2JafJuu83JvrbNej8KSYnx9WnZ", - "marketEventQueue": "BuUvBarGZqM6LQ3mQJKJDNBR7eC8ZeYMau1KbbLKM8PY" - }, - { - "id": "45asEFwHSUHXXVDDyNz8QWuewjQbX6YdqTgB2HeMD4z3", - "baseMint": "3HaDnJ2PEt7v7RE8dPaSzSCgBL5dWvWtTkGaEGs5ap3N", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "pCEbJbLbYDBGG5Q5kwiXU4JBN8J2NYUBKsjb7CBxc2m", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3kbWUkkcbwbMcjHx2TtKd7KTs1PdWC8fu5gWSLTzStVd", - "targetOrders": "DqmXddPoP9Qw7yf9suvNhjghzVvD7osyvtDxqNmTxr2b", - "baseVault": "Zhn8oeWDjWBKCFCJnTB3LzcYNFy3s4NqkpC1f1Uf5YV", - "quoteVault": "7WNdLAHCczpVd6itepqGqVJtmLRx5DddJwq2MnvZpSoq", - "withdrawQueue": "4eAeWGJ9dnTGMEiMtDWLEXZDkNyoykwWmsWmP4emFxsb", - "lpVault": "CS8NLmTnRsGmGNx8bDjgfFMnyf5nGwW5tjod6x7bwC6J", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9DYhG2UdY3S3av1YfqaPzUC6VSczsfvqcwHzHaJ2xz25", - "marketAuthority": "7uBShMGgMWGrcRwVanL6Xb65XHu5odAnzYcTA1iCR4Pi", - "marketBaseVault": "Av2tx6vpAdsFXCkiGadJLMwwQFEpHYuALctGe6v3trJH", - "marketQuoteVault": "FXFHz67ACy3iGL3ksPF291Vz1BZQj4nj3v7vfstwdbnB", - "marketBids": "HZKaAwbWnvFGcnuwBXfxdnnHFonNWVW7xy8k6AmJ6ANy", - "marketAsks": "BwAuLiky26wNEdAkuuTjo39j5XGEbBfoQfzGBv5Wbgj6", - "marketEventQueue": "GRXByXVKXvteYnma5BqNUJdpAMLXZNdmfnGB6xAauqwa" - }, - { - "id": "45oVpbGCZ4peMxGTFPeYtJXhq9oPEiw9ha7iWrvz3JeU", - "baseMint": "3UcBMHnSTCXaxUbP6B96kHcED98DgEnNa9rGKzwXKMf4", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "By2FnCJpi1QMdvtw83mvcS6V4VG5AMBGAE1FUUzP37qA", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "t7LNRRWCBapTFSeoauF1rt6obF97TZLYhZ3ZEDCvvon", - "targetOrders": "YjeCsjWggfSvPKJyBm5UjwW8drmxcswGapEqHMLwshU", - "baseVault": "EZP9M8k3fDMoGNhPvmnB6Wf3b45hsjawoUpL5KDYNR2z", - "quoteVault": "5GrsyW8v4BNEVEwCDWmue7NR2TGjUWCjJVDLbKmKpWrV", - "withdrawQueue": "HRFMg5EsJh917yQS8rQJF4wzJr5AnSaDghFPzc1iXuW5", - "lpVault": "HZiS8y68W1JSYZ5T9PhnfwJY9ycHETYugiNeVvP7xbVs", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5xzQRJdvJJUpK8MNmVPdqgpzh9hd1bCvJEagxnHMCoFY", - "marketAuthority": "8kUFxUsNuhVBjWWniuuz5xxSLeVVFJRGGqxcPpbir538", - "marketBaseVault": "Eb8X8Dy6gKfmSupkzzC5qw1MeTkCMUm4EFCkB1djAaxF", - "marketQuoteVault": "BJfbCrnhQGwPcnde7PbFNrqBuoNaCFtCr7GuNtsDTZV6", - "marketBids": "BoVGi7bHL2HA5YsjFBZoxcffstu7Hk7fUPTPVd4xur1W", - "marketAsks": "4u1k3dKagDhodX13HhNqrRbZqqPLp2Kh239JKERcUiTC", - "marketEventQueue": "5q9f3j7jm5v5VEqDkAs2ocfxaXBN6VqsbuyiKBtrkySv" - }, - { - "id": "46mRnwdtD8G94TR4Le3EgBy41umqgYB1223H2kghG29P", - "baseMint": "nQRrWF1yWpYzgpndtGRMFYQJxWtauTeUJYWAfULHRSx", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3iyPpiymrmv5Suop5MC5vXHTjAV3TvcTPVXQwqJaxmcq", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "59zTtLQFdeDYg99aJDK9bXBsULBsRBRF1JkTHd5MQU24", - "targetOrders": "F7aXuAL2gLzRnq2Aq7QAzSXTYGmdwqqxPivCHcPPdZje", - "baseVault": "2fnKxRNAg2EeXzdZg87w2mAxNwvqwhR4TbEfUm956xKq", - "quoteVault": "2GA4Rh8MQ6ehCLj9TC19tJCsM1FFveTTx7JRQ99DQMAi", - "withdrawQueue": "3FY1QRPvbrtZEDgQiaxYwAovm3uVpY278aSCTr5yc8Vd", - "lpVault": "4Z6ki38eiQ4KT38cU3smc7NhL3ToC33MEAia9N6mSsB3", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6jkA13GqVSNPX5N7TSx1wSsPAopRkWtfMzx9rEVEtEvj", - "marketAuthority": "873PtGcmrtaDABP2UuU7b7a717x8kJfevAXMwg39oJGS", - "marketBaseVault": "DmQnTe8MjjeZj2ZbG5PpxkFKWirQAgcahRgFMTzG2qCZ", - "marketQuoteVault": "6DiEuLVJF6w3UTF7W8vdTZ6Kz3o2tgAcGmtjjmpy71RR", - "marketBids": "2Xs6aeiSBsvX3ripz8uunX5iCohpJUZsksfJk7U1E5MX", - "marketAsks": "8AeLAxJ1V9MeVzxNsYxAbjwVzDs7irgDiMaVAKybgHG5", - "marketEventQueue": "BG5Dtz5rF9sv61EE6N4hDCB4NdBRD9TDxZpkR5jnumMn" - }, - { - "id": "47Hk1DZysq2WJS1ZinhSe3c9Qg51sDS4f1Te3mDAhbkq", - "baseMint": "F3nefJBcejYbtdREjui1T9DPh5dBgpkKq7u2GAAMXs5B", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "CuRZaiwYqFqQRehoiUK1KEeThXEGo5UysD2kzNhc7H2H", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5AgTcN1UZF6wcENSu1ns8sqA1zN5yZdCkMmhnZSoowiK", - "targetOrders": "5TE7ftyqor38L5z42mxp6qTrwGe9bTurRNBZtay3PE8e", - "baseVault": "8UX8FibmXXCvn84WrDQmrRSPXCQv9ejUUJDg5aeKEaac", - "quoteVault": "8eNNFphbJm88DXMvNoDQkCgREBdiRPBS2bUmYkYCQ8wJ", - "withdrawQueue": "6sqQZXGferSaEB6uiBjgM2i6zr8JziyPs3dPXxAUYNVR", - "lpVault": "8scn99LZbCzBuPq8SZpD2BXWc3Ux36rozwKR3Bcsrrry", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7d8t7bd5v8G9BKpG13hPaWq392Djnh8ZnvqcJtpJHdPG", - "marketAuthority": "F3E2yz5Kk2z5JMkdYQyXZJSBEuPApkZgr7dBwBngHhx6", - "marketBaseVault": "Fc1XntiTRBYPPiZQVwpJCLJKUCyys3XvM5ac9hJNL3wX", - "marketQuoteVault": "D99dNgXmkLzSuExKS8E5LjmxPeXWwBxS96xkjYaBKUCW", - "marketBids": "8K3c2Fwm53pHR3kmPAbhuTD7fRQsysw5QzgYamov3Nz4", - "marketAsks": "AYKMCPavXdwimXS7UvVbMdEYNNWyLTe8ZBnPF8zkpiFC", - "marketEventQueue": "Acwgx1Jn4JSqPXQoAwhvQ9pbBLNNqRLfhCgjF8YbMUGA" - }, - { - "id": "47MjW7EG8Y7c7A9nD7qyTyZ9Q6giYuwoFgFEnZc8ecky", - "baseMint": "EBQ6gWBQNxA2zB4twR5GWP6CkeAhqZZZeDgeP7BTtdM3", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "5WB46ZuCjvgmCGFxiZLXVeDP2ddzaFTeYjLRDdZvBXRb", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Exih5hHGzshmvBRfoYJ1K6fLsL2oa87qtHZ2HMXAdeSm", - "targetOrders": "ETdfJyBFbXuUfXYiihpXN3fD7fra7uA8kEneKagcgWbW", - "baseVault": "5VkeL9FfY7XdCBGBFMKKAx8v5enPu85c8DUjRG4a9SmM", - "quoteVault": "7FM6GinsthTVX4pzWPLgoeTnNZPKbArrFREgnHdstxYb", - "withdrawQueue": "4YfcjHi9eUYDya2ur9jFdL1mhfK7MstLGgUDTKikUGno", - "lpVault": "5ph15fz1Cms3vL484noXLwzRsvgvcPg8b9Ksz2tAFN6u", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Cym4Uw6Zh2eQ6W5vFmq19Q5E35PZ6JAJNAwcywJQpCks", - "marketAuthority": "8ZnUv1H5yZ32aPXFMgVpAKRJiuLhBoybiAiw9aiCXJ1q", - "marketBaseVault": "CT11vgv2spHL25p8Di7MXmkWJvz5HPyhzfUxxa42nPmB", - "marketQuoteVault": "AkDnErcFnL1fheCcegksc5svfn7JX7ocMuiytdrthJce", - "marketBids": "5xej2GSq6fmZurXWSpvTviKwTvAHZ4jHznW8ENww8sfN", - "marketAsks": "588nwHmyqCrLGjbhG9Hmzdj2vX38BqmJmE57nrDPpcNp", - "marketEventQueue": "C1fReXu5cpFJ447gSZkhvd7ebaBw2JRF23nZATSHWP3Q" - }, - { - "id": "48bqboJP4J6VvbLDbzUvrpNg2N9dCRsdkCpP3M7FfeKF", - "baseMint": "CJze5X3G3V6nqqrfeALTpb1HbkKvspjiUGR12rVchL3T", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "tFN6XhwVzRLHJjMxjNv3JmBw7SpoWC6YLQMbsVu99HF", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FWkEgqov1fguAvSEzBdPXq8CJcmgGyStVPjbgcV7x3vW", - "targetOrders": "FU8jir9kpyK75cCYT2XKDGHWWCqnseNDL8Ky8R9iouBr", - "baseVault": "5YYkZaxGhovuKmHiN6YeCdxkTmc6X8hKfYKYSgeGQd6d", - "quoteVault": "Fm1nL2ndFUZUTRK2FhiNTnrUcTQ2MSFLb7w2qNPZaknh", - "withdrawQueue": "APTU1B2BS3z1HZZdnH49w1ofhrddsAf5G8SdnA6FBs9m", - "lpVault": "AKDr2bsm2ZhuX6Sjn892mDLF5Non74QRv4Ah4tyiwCEz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GxxsmUdqnis1ZpUfpxJ7PPHHsdpMgEufJUBmZQy3EqpK", - "marketAuthority": "4XRvrmSXWSb3aSAornTdrSpAqxvorgZXQXbiCXXmH7pA", - "marketBaseVault": "b2eXhWKXom24ZprihLF75DWNXCt4A769G3RB3P2Btwz", - "marketQuoteVault": "HjB4X1wgQU2wq22RjAsgrsvkjRNck7n6eeGQ76Tq7Udv", - "marketBids": "8tKPLYzzaZXFq4iQgV11ewnp3Fjbd21t1CTx7xnDjPnL", - "marketAsks": "7145RUivyw7DK6iYoY1erxSMcRcNdD5fsB8j8VUhBiAZ", - "marketEventQueue": "7hhxpV5mtc18guXCXZLCgbJcELqkq8qy7kQbmzARS2DH" - }, - { - "id": "48wtrXTx7d8Vbgw8mK7DKz4Y6PDtttcJ1zCfVyYC5Yr7", - "baseMint": "Hjc6Ku7VpMD8TqPUuimDXWvT3RWpnbm1viaUe3dUco3L", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "GHtyvTA3YWaWSoEMH2yzkwe6oqTYXUXjKUitBJ4Zp81S", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "C6ZBMkjbmENC2wDCNGepEf7N2iEuZEPu8jnfBwBeoTV6", - "targetOrders": "GFJKQpg135cqjpFc5BeFdAG5sZsjtxQznSBh12PasdQ6", - "baseVault": "2ZtkGYq6LKePRujeeYsi3MV9rdb63pbpB6FAwjfHpWeP", - "quoteVault": "EcHinMRd8eyuMngvZJN6ZLcZnjYPhM2vfVt5Z1ruCgYK", - "withdrawQueue": "FJABHYMfD4rb4urNDWmuyu3omed2vTp2ifqEAi4h9y4k", - "lpVault": "61XbUx9VrdzqC4WqGXJNynUpjVYe64HBiw3J2sxpdmxK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8wq3NMbn7en6cTeYvpTHh5EDhU2rPM937b244yuTK4R1", - "marketAuthority": "FHrZtCkaC1ptWGSLEGr2Xt5ZNCGHCDPVZ7cP33EQ6oGm", - "marketBaseVault": "FjygDwR9TJJQjBW3FS8MdHM9JZADucCcervDuXj63U6f", - "marketQuoteVault": "6kLNfdwbgTKpDuaXdXvdXethHW6xmYFfhh6Rt6xVA9mW", - "marketBids": "HZWSR1GNygdf7hYnqheGaEgDw5rFTpyYfyWf4rv3Q43G", - "marketAsks": "F81s1bHQ3RD3d67LDq8XcKEHMJ41SF4fL8k9LycE7Lmb", - "marketEventQueue": "ur5YMUJRCf72Z18zZcQnCPRdSZqEHzskPutBwNbaAUz" - }, - { - "id": "48XXbh3KHoxVLKZ6EYQsiFpwdp8TDUjBi6gBtzMJnour", - "baseMint": "CMdr2YEhJbnf82NSPci8PdG1zfViQPGExbbZoy5LJL7v", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BWGkndBstYQgBBxhCr1BCSRSJ866L9HfAecS1LBuBtFs", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2wru3jmTatmNXfySH8VH6SeMhaGw6ESKd8Yrd67PdXUL", - "targetOrders": "4wyfgUceyuGyE4dGErhWSFQPWQ8myMZ3zGfA8N9TAMj", - "baseVault": "J6AkjwM38gqpmxa9k8Q9SpcN6YAM51f8U8dYrVMpEriQ", - "quoteVault": "Fv8EmKNQf4UFoEhPCiHnFVF6xtzjQZAZXitSttAU1TRr", - "withdrawQueue": "DrhGh1w5c1EgTA5CME48rH83CYX4q6f5rGgfAkFwEAFN", - "lpVault": "AfqKvFrLUYBUCnttf2Wx3mPo4que2asvzL956sz96dtE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FLntpJBYvHfq4wPacu1pR9rZ5kUDH1xfwhLvCpck5EgV", - "marketAuthority": "iLBWp4PuJmQjSeZQ5xg2TyAnwSka5TvctoyanatqPMq", - "marketBaseVault": "JDBJHhcPAkwnsjKsCrgpfBtY19NpXQQuXFW7M9SRSFFE", - "marketQuoteVault": "H6Yyoacd1yuiDgGh9hSZHNnxn11yC9SjiBeaZmwmu9K7", - "marketBids": "9HgSKfUbVURzJ5KPWujaBGAqCT9onjxGCZVuYTYtgzau", - "marketAsks": "E9okMbzkLhBQgZgazcaCzTxA3rH3dxxToWbP54smQTSW", - "marketEventQueue": "E4Kie5Jf9oFNV6sizMiUHP5i74zRm5NoLaGgXJSTRd3R" - }, - { - "id": "48yaEzz1JSHoghWYg3RGE31srN66ubfPgm4Wc5556YTG", - "baseMint": "GEJpt3Wjmr628FqXxTgxMce1pLntcPV4uFi8ksxMyPQh", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AZCinfHTXwohov8Mtu1kQT54zWJUmRyN92f6yKs3u8oZ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4bT5BPA9uKnnVTopczr4gwVKPFYHv2ECDWbVo3NU22dy", - "targetOrders": "8GP2jzm6yPGRSuJE26xTBGZuDVhM2Mim5xTYuurVyBCs", - "baseVault": "79rPqur8V5VAyK6fN4S53CZXRB6pBqMNjGwXa9SxnTud", - "quoteVault": "Ez2Tf3UtyxzSUk4tT6pEdfgzgUVc43wRxhpfNsrme6Sv", - "withdrawQueue": "A4Ksz8keeXM3JtP92DbCANS9yNtVU2tqKEez2M136V4N", - "lpVault": "4QBUzcUhZ6qctXJfhQthPxozVVpayJc1YWAbhQbwjLN5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8mGtAoxqxJGZQGFgUWZrzxvRrB6rQU6J6NQLjCBiiVmg", - "marketAuthority": "HzCkrpp44PWXuxX4oLcPvg7fCbAM1JWp3qKz4WxqGu5n", - "marketBaseVault": "8PzubcUXfjc2paG1Lgf8LcHzvK9nBJTbor9eWMpjeCvr", - "marketQuoteVault": "3HmYCVghvJ6BcN8Uy43wEnVsC18PAnm7ubXYupSHmQ69", - "marketBids": "CjZF5Kwh3L9H2YZg5i4eJytmeAmpDokmSL2nrTEeqSCn", - "marketAsks": "2aBRvJJN3EdfhbRSNLg9xUTphyJvD9p8gKdhbLNRzBna", - "marketEventQueue": "3hXNKs13S4Wi8NxdpRqh8uUjEkxqMBaJMZFMQAGabCbR" - }, - { - "id": "48zrNWq9EtHwAUWLK18ZcznpZQbPd7Mxt7zr7Bt5Ct7Q", - "baseMint": "5dWmnUa5cnPWTv5gkwboqTV3ZwTj4HgAMkeEsXUKE9kB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Hq1HNwE1LtqtM2Dar1o31NkjJJH5vtkP4mku41SfZReJ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DvEV8qC1SYVbthE5mSA9YXJbcaZq7wq1NbdGD9vf8grz", - "targetOrders": "G6FZVbpwfUjYx58TtsGxL9dt1gKddYoRb3P2ECBbBtXW", - "baseVault": "HECSv7Ju3qpw1iJ7PsjgQys1rhBotEB236moBZXHMKhS", - "quoteVault": "EstZAR4MrGsSFBVPx7MRbvDmf6bfEvcDRaBvxNgvxYEX", - "withdrawQueue": "Dv8EYEKdtJSiV9U5pxJjBf1UtNPsCHJR3fJ2M8a4s5pX", - "lpVault": "FZYaXerxaLvaArPbZ5pWxy76mu2FVKE1rWLhWz4sQwGW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BhiokWKGgr4dx1QQQSUZhEn77YbJpB3xUPW5fWALR4Yv", - "marketAuthority": "Fmzo8ZnE2C6XtGg6jP96ZgtBgmn2GLsmDuWUwwES6mZ6", - "marketBaseVault": "F1Jb3VrxNDQK7gwLmPVZLF78qFZpbWAFZjHUUaBquK5h", - "marketQuoteVault": "GXdRLM93SDyfBaa9RwdFZThL3eX7eWTZ4LuHVPaTweBF", - "marketBids": "AVV9ueacgZwbv3H2Ljf2ecxh9KLDC1yU6XomPYGhG6t8", - "marketAsks": "E3RpnDcys1zcUvVrSmCgiTMXpbWyrCWYtx4pyCiT9fBd", - "marketEventQueue": "DMmSzwpgFCQtf4tGiD8n4fDudb8vmhF5rfEu3qEyRe8E" - }, - { - "id": "49paWR5FcVjbLJzykYpZYtiu4vMYW9WcStpHUHQf7TFc", - "baseMint": "3QmXpCzCfHZVnWfjHsEKHpLgJf39fCD3xrD2z2My45my", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HsuGe6wLZNk6KVBv6SrkLNpKtqxFCCwYuXNMFWDFxn8", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FSzUFrnDaiFCxBvJW2E4iN1sMXj4yRLco9zoXmKAuorq", - "targetOrders": "BKsnyCriqnmk4ULXotpSKUmXW14j9ZnnRoVneCkqZHPk", - "baseVault": "7E7mFZkCRm8y5bB6bWndujpKTRkzjP1t8erLpJLFfB6R", - "quoteVault": "5aSz5AJjqX88rPLKx5cm9wpL7xiHQXAbYEdZrFZvXK5v", - "withdrawQueue": "AtvRRszfaPy7es2NxJvPFNaWAW915tDpkZ5YaUz3MC93", - "lpVault": "HL4LHdF1A9FozmRwsdStwLUB2aaTQNxDGe6uDrJ3mn4p", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HxFmMTg837eDr3z6EcHF9geSNsxS4Az8X5AER5J6eGQz", - "marketAuthority": "56Jr6Z42f2deGLzg4nwCjd7wU4R5nRG6XSbTj4zqxQLJ", - "marketBaseVault": "F5oJ1y1TCLwWRsECgp4DAqpJGNkaMAhjvjUKjoM6tWJS", - "marketQuoteVault": "CzdvctAxjB34qkuQLveaPKJH9VTHLbhNCa5jNa4kXJ5e", - "marketBids": "DbfBA5DCn7k9XAQKCywaqDx8PCtWSBGJ89XGBnHz99PU", - "marketAsks": "GRwuxMCsCx73AmRXcCKHK1GiggSSD7uGH8Lhm8S48r6m", - "marketEventQueue": "EiQdAy7cKozk4AFRU3TLGZhP6YARrgr7iPuzcgDzQ6Ks" - }, - { - "id": "49PYRSd31fgvy8KgQJViHLAgStt7VtfM5rUjTPyBm4vr", - "baseMint": "5SZSVgnQDgKKxtCe3UA3x4T7tcSRNDaL3NmfdEqpuLzo", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2bxfSoLmya1d4e47AsrHMK2LowbrXyk7xoeu9BA9o5we", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Ae29P3rsS7ZdTL3gVHLWe9Kz5E3RK1WNszsA64i9EGqQ", - "targetOrders": "BXySpDYMTj5VvRabMvoRyKvZE24ZjUDeiiqcYEf1jDep", - "baseVault": "4YsyfphkANUXDzoVvqmjZg3UvyY9MtsDASRyoQ5aKZgM", - "quoteVault": "4a7yEkxxqtbV9f6Jszw1FoBXXXRg8BMKiKK3KBtFkrYk", - "withdrawQueue": "rUAYR5WAfuycfJw7ujNkMYwg3tT7Gj7iK5H3eAoSnG2", - "lpVault": "Dmz1o1tEVMShXXfCnXVxYxshXJhwHwb9xjw6xvYiRA7d", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AcEL2zSgvuEHNboFVjMUEfDQRPjCHthHj87TFz419TJ8", - "marketAuthority": "47VW6e7tA6qqCdP6vgkKya7GDpV64U25JaLestDJFrZd", - "marketBaseVault": "9Rbq7Fj5E7eZuJ9G6fEiZ1oAo2m8y3hfR6T1k3w3PAjN", - "marketQuoteVault": "DYLFfduZrZuNC4roedrZniXgohpi6gzpadLyUK2mk81a", - "marketBids": "9ADgQzaBBj3nJgSPsFuNqLez4TXvvkL8ttXTHqBQy56M", - "marketAsks": "ABH2nghzja8MQPRPWwyTqsoVRkTwWGfqsaQPoDFr3GTH", - "marketEventQueue": "7QH1AFuLnpnSnYktWDLPevgdbJs1Xf2ypUJZMVqkSVgn" - }, - { - "id": "4aRbFx1tR5zTHhfSEj7ofK5VNWPx32jcbzqCNwC37tRZ", - "baseMint": "HavbxBPK1uY9kMNqKPkWDEQXWw6FYERrLxeMtWiXnwko", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "9yCdSfmCcEmJ3NC8nhEuuPih83icbn12GwbXEE7kwoAF", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FRdu9EZYb1ozuNXJFHG56pxdZckjEQrnFNfoFS1Pn45x", - "targetOrders": "5ct6JnDS1CzTn5ffz2n7iiMKD7auXbX4sTFhJCoTqaBX", - "baseVault": "CKvkG9NGPY1SswFi79EUbjvdzdTfRVdgk6AbwnSC9G5M", - "quoteVault": "HCQWhM13vPz8Z9q796j9ihcD8FTNQKpZb1KkQu5VZ2CL", - "withdrawQueue": "JkSZ26f585RYwvjw55UkjWqTLxDjuLxx2kp3U52q6yu", - "lpVault": "7jkptixjW2TiHmbuDcVQKwoQuWfDHnYXoUAeGyBwhtAL", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "uJoktMRRta3Qe3o88YCq8wLmdveUpNwS9HZfzyP1ZhL", - "marketAuthority": "5QKh1MtSFUPyW3qHdAtJUUNsgNNmwPzWvNfnrdA3u4X1", - "marketBaseVault": "22bSLKKFivP8DaYMuA6Zu53of69v7d24t7UwNvB7ATe5", - "marketQuoteVault": "8xra97g18CGJqeeDgWj6EvzV8PcfoDi8EH1uJRJM52rq", - "marketBids": "J8H5kQ4tDCCn5MuNZ6eUzCQEA6NgGpmA8GfxEU9y5wek", - "marketAsks": "CA75SKKNLQX4FscWYjMkjcFcrRYb6VwUFDNcRugNJkJy", - "marketEventQueue": "8RCn8QPqa3BL9Sv3sqwdpCEMLawZzVmGMQtg6XttLnmF" - }, - { - "id": "4buwZvMXuwtmS6r9YzZkKf4tkbQAi4yAh4ZaosTvd2zW", - "baseMint": "Fv3ZG56M2cWvF8sy9VWzWyvtHPhugNc1BAzpyoAPvL7r", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3UHj4XzBumGrjpepFGmieht9XnNihAvHAw2eSeyvQG6M", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "gcUcKjzB7uQinTqaFtXTVCy5ofsxCtxHstbfCqRnm89", - "targetOrders": "CqCzeah9fyja9tvti2BdvHphJ8PfZwR2NGL86pa1Z3ts", - "baseVault": "HcV9VuHHnZ7w3sf6cXmqbwxwawZcvKx2Yhhuq8vjZN9n", - "quoteVault": "4jgNBztV6UVcV3TezCXtAmN9ibKKaEobszme1Xb79H18", - "withdrawQueue": "3aRXQqBskahQLRYQztHoFaV3RdKB6F7NuuC6dLL3LMw4", - "lpVault": "Co31wMei9wnLBv5KNk8uxdJ5yNoJRP1qG6YJUUGyhVyf", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CUttKiPJyu3dsfNwzaEHusGqY36qNkuWcZrVGrnPe9KQ", - "marketAuthority": "6LF3CLcctGvbX1tF3VyPNroQZRRn5c1R5pkRhSzwWLMN", - "marketBaseVault": "7JLWVwm7iX5c5Cts41HwKbFvbkeA8q6zXSAfXmpm6U3k", - "marketQuoteVault": "3UtXSAXUZtp7avbmBWPzuzrzSGVkwXydvyYz7zpBELoN", - "marketBids": "BZN75jK6cefQfSEtkRcdUHKhN7aHaCYrmEvKKFsAk3MY", - "marketAsks": "2FhrfQawkmPfYEpbrPAJrtxzPzmEn9iRLrkuuEzqoiqz", - "marketEventQueue": "BUNx9sPhnASaET8TwzHFjdu5aroPM56KgZS4GuksNw2f" - }, - { - "id": "4c6GbeoDJDr6BWaVeHax1iLJRrTfbUpiCsrW6Fhyj3WL", - "baseMint": "PRT88RkA4Kg5z7pKnezeNH4mafTvtQdfFgpQTGRjz44", - "quoteMint": "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS", - "lpMint": "3gp9TwRz43dJyosVRp1YvHWioaPyha6CbEHAmBboxWui", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CDgDuWerxJEPw9jJj45HbH287iTXeymPcmizQMZ7cPa8", - "targetOrders": "HFNP6MiNzEiwfT8t5UH898Sms1BFhRXrMvHvGF3VQ4z4", - "baseVault": "Hg4CkG88M36qYDSNBk8NY1TbpPF9eaJqPZ5mDVY6Q3Rw", - "quoteVault": "FENX7MQSGJe25JBxgjumvTa1hMHZPzUBoEKfNmJrdBx7", - "withdrawQueue": "BMB4Xp7BxorjptrhEGMYePsnfu4hscqf2ULPCoRP8HXF", - "lpVault": "4ubqduT3cNyjDTv7EV2kitQLuTBp8exd28GfxSAAFqtf", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3W4xKEziGezrSWUP6Sw8suCQCtH2knzGYbwyvEtLTks4", - "marketAuthority": "HFxhDFr6bQjpZ2JSgxdaiXKnsEArPVhyF6uTqA8Jq6ah", - "marketBaseVault": "93L2JQT6pUvsH7QE59u5eBUs3AgkdDTjQgEPGaz3TDby", - "marketQuoteVault": "BWPk2Sg8eqnvbkcLBTQCiamCfPdqznfLDfGH6YBaGREC", - "marketBids": "6Ey2nd1Z5W4Ld9xfd9sPR5T5K1Ywxfu4ktkL8F4HeKJx", - "marketAsks": "4gQAKutqeBDZtPfVv5d15LqFV6Hhd936QY3meUbAPXsR", - "marketEventQueue": "Awgj98YJKtfPmeo29YaQtfE7kNnNqmv31C2Caor256y3" - }, - { - "id": "4Cfry39xVaQ7Yrj3jg1PUZhEz6utN7HMJ2BZXBYFBR5M", - "baseMint": "FYfQ9uaRaYvRiaEGUmct45F9WKam3BYXArTrotnTNFXF", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CDUFZfoineBVH49Ktjy5iEY2zUM2g52dF8c12GSuDTfw", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4Uy9zt3piYS1Azxcvbi2RyoAPBt4XBiNTByLaesFp8WT", - "targetOrders": "DwywGeWnyiJseS42seves6mTXWRn5UveUp8xESUTHsbg", - "baseVault": "44CmHUwbJCRwcxGDkNkSFtcpkWUmUY2AzruNahDDFmUx", - "quoteVault": "9HtPCnDJ3WU3TEcXt5caYwQiJuMGbMTFg5K9HgHGcBDv", - "withdrawQueue": "EvF92H3SuoX3dqGUhnSd9EGXWCMovvxJBu5Xxac6rVDg", - "lpVault": "HFJeifWaGfuCDQpgZi8KMyL3en9EMa471kq4vCpn4rCq", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4RZ27tjRnSwrtRqsJxDEgsERnDKFs7yx6Ra3HsJvkboy", - "marketAuthority": "7Sx9635i24dKnZTmr3n49wL7JyhMQv7RMuc9okFLRuDu", - "marketBaseVault": "DahZDkfEeXwx6F4EKP93tDBBXtnverKpgyrJ8moGaZhy", - "marketQuoteVault": "EzDEuxQUFAj6f1Z8AgG6ByNeP37AUx1hGW3QKgZsHks", - "marketBids": "8BY7tMQzo8iRizRKVwBD7KY9nkCofagmyDS4cupaSi9f", - "marketAsks": "ny7m9oP8o3Qpm335h8gDEZmyK8ZyfgvtXExrBgXQUBJ", - "marketEventQueue": "7x9hv1po3HtWtCzhqk5mAXsJK2w1k9kJBau2MocbBUPk" - }, - { - "id": "4CoHfJaC5EPjxwJZuSDp8GnWYo1GpLnYqLchWgG3DKSZ", - "baseMint": "3iXydLpqi38CeGDuLFF1WRbPrrkNbUsgVf98cNSg6NaA", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "CQi73TejNTy5ybmG98BenC7W7bZxJeBHQ9AMDzboFh6K", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GJmWoe9vDKn9rtsZa9sUBJ5JsvaahCsPvYifgK9iJZdr", - "targetOrders": "DW49bFMk1EkdNGCJP3GuPXSYqnWJMb3Uq8yr2mkqhvuX", - "baseVault": "9bZbaCjE2XWtStcR2UHTn4UaAom2rqvynWV9FXcU6fqe", - "quoteVault": "HuciNKSK3RE1mTJ6rYjCy5MUpsxYDujwGTYRPvDnHQPz", - "withdrawQueue": "AN4sGCtHDyGeAJSnvVwn9kGoMXYzQeAXNWDWJ8PiFZQy", - "lpVault": "EY25PXhGYmjGTMBvAuQnFWPJ9wcD8HLa6Y9P48YwG4Vo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GWAa1Jpx9Y7oxv2ECxPVVt7YDMc64KUAZk9YevAGHhhz", - "marketAuthority": "B9N9CGf2qs1tbRkCx8t2RcqsnDFh2XpRzq6tuQUQZjqi", - "marketBaseVault": "7yoCydrKLfYq44KVqkQPN2kGXJnDjaNGis3JSEthQnkj", - "marketQuoteVault": "3XbqnVF5qyr9RucALMZjSSGswcgPtaeip7hJaJmFcRD8", - "marketBids": "GW8CUGGdXTeWEQHpYrZK44W4fntVP1yHZqRxPP9DBhZg", - "marketAsks": "E4wyAxryYs76AqadWsuDxf7NCmgPPB2UCYuqomtvL9RQ", - "marketEventQueue": "4JmZp1NVuRDpXPC8qV5R5X9t2xEDW1BznYDFG9W4WM3C" - }, - { - "id": "4CQyiZMop5sCmTfuKnQdcpqo8hz9XLys2QvK7FN6LiEj", - "baseMint": "PZ39hXihAjqNLCBsSSN87U9nZVNzafejGoLpU3QLrVu", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "FqAyirfvhSN9nmDJnKFbYmqvtCsRvBfj4PEX1A1Brg8h", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HWtfsfHvHg8VZovsatmXZxePhsFutoCLNeALRR5JcJxT", - "targetOrders": "DF6iRBWcy2vo4BnjcPkggsiZ6Tba4jPiJNU7VugwZirG", - "baseVault": "tkwzVPGPbz19KejuW3VTmLF49LaDu7jXaD5X3nn3DFr", - "quoteVault": "7f9qawpmS2GCDgwfRht42tSF57nbYaiiBZ7CugLN5ZQm", - "withdrawQueue": "DidPju2yf5yXgC5N8efqoeWyQibz977JgheXZoaUGHEm", - "lpVault": "5R22FBvPBJ69LGGs6cf3Eiw1efgvZMJmJD4yD1T3j7Pz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EFvGFbi72J2aibxu7EowiiPhYneeZmMgp9RKCF7oBdRE", - "marketAuthority": "C9EPsqLSqyaUtRA1bPgtbHVG8kz1TpGTBnfQsyhAM4Ar", - "marketBaseVault": "5HNXzwhGxabyYCYoFBFrYQwqZ5oDi2pTJQn1pDmmJrUB", - "marketQuoteVault": "F92dYVX6NqWk7xrzZShQQxFQ27fEzR9LeL82EiiZUHPF", - "marketBids": "FWDCxnnrLbXzTaMv1vxUwmAqCCzU1xiGWtqy4gPEjGyV", - "marketAsks": "C8neBGdbVUQgxQS7BcJqsBaWJwgKmW9gVGMnnpqNsjAe", - "marketEventQueue": "DfAAHvCKmBRoTpkbxwKr9ZAwLa6oCuXxBa7pHcvwnKen" - }, - { - "id": "4dg3eBr1m7JR46Fxb6fN664DfuoST12K2En4LHXdoHim", - "baseMint": "GZo8tEKu73c5t5XTMZwsGgwuA5HtrXgbcLwMe2w67v9R", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "ForEAuqXHUDRW4QxgLgdKptccxCqYxaPeacgAP63R74Y", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HRBs8t1WK83o4Z9KavXD8NR3xwegmX4foEuwSs9GgVcv", - "targetOrders": "71eSD8fHxP6YPD7nadhGXzJRbpiZcDRGenS2vkVUzBuC", - "baseVault": "BxYChyjYpccvaF3ZEdA8Yr7hKA9gBCYL8uzTEPkyYAWG", - "quoteVault": "SFqbEtXW21UoLcm5SjHyixdVMVpjcHrpkkrWu3JAUE4", - "withdrawQueue": "ECm7GfWkuagiJJYpe2KPFcQMKEL5Hgponrq4uAR7uxMX", - "lpVault": "3qYiYy1eHDX7FXwiZdpMtSivckb7Yhwk4KjGjhn8iG4i", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4BeWZpLq5MR4eYLW9bx8YFTL9uASsxiKsra6ak3fvqqU", - "marketAuthority": "5HZ8BztMdrjVctPAsMumov6pCJYMeeKoSDddT6raxx1z", - "marketBaseVault": "3yWhrmNZRsCQ9wJiFvT5e8cnF3Bpndg9VQmec1eEbea4", - "marketQuoteVault": "wsBhCR5tpW6Bo85oNVb1hJNugFXB5BBahVYAwD1Da7q", - "marketBids": "Ew8tkDqnPjH8ewmt9M245cK61zaWyy4YCvkaqzbNZ6hx", - "marketAsks": "HU1w1nvB9BLbTxiwJmbH9wC11qqK6PTptLk6cL2ydsMF", - "marketEventQueue": "DUkWRwf1VVwVDyU2GVpsQEqCSdcN9RSEpTvSCykm2bdk" - }, - { - "id": "4dGHaBqeKWis1dwzmc6SeWDc33VJ6zeJyUdmVmwitG68", - "baseMint": "9yM42HMJnN69rhMGr8nCYSRtFxjWTWm5Z6GeucyLBEHg", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "7pLig9DwAATmR7npdb2aexpoVob7UX2LKtC9JwqpVGjZ", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "H7xT55Y9DyGCdYFVtcRnnFnkVLThuiz5vTtCDFPa3hn2", - "targetOrders": "CZrvMSm12S6fEp8NfJAXG5FjKVQMBb5TGcb826Z7pxPH", - "baseVault": "8vDaTU7RZfcEsS979oHRkuYhe31Q6GNjhyoP9XtQYKDe", - "quoteVault": "2ZknbbnGLpEfKQwCCwTGB62omhmfCzDnipiT7VBW2n5F", - "withdrawQueue": "HuceYuNF6wxRmJ9oE21EAVDt34wVZC2DBVnWmkviYy8f", - "lpVault": "EMa7QSTdy9NuMM1gkhZhE46gRcNeY12agfSyCabKFnnh", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "G8R18nUTwyZTK7qyxDMBBvSxhdhfWtKN2jkXs9o35m6g", - "marketAuthority": "8PZosuqubHGHciZQycHvxinfSB7UR3gPdE8JNvNB9moP", - "marketBaseVault": "3ohqNxrFAYzG4B5QRVixVDFToSwkCDCmaApXFUNq6opy", - "marketQuoteVault": "GfovbVPwvnZyNi3fNPVt3xwWMi7vJszFq1CHL5QP993c", - "marketBids": "FG5raeXJxut3XoiHpwrrvRzVEYsv1aSTZF1AkVEo3M66", - "marketAsks": "5Srcdm7B5grMBkrmP6eirCq8QLzvjEhtXhbu6y2TFoTw", - "marketEventQueue": "FRZGKRptwo8x1HV3MrFdmgjuSqDxhAh2gCFniwYYkN1Y" - }, - { - "id": "4dmwixBbycC39EoRsVK9umpNZUrz2UVmz1eS7AU7VkaZ", - "baseMint": "ErGB9xa24Szxbk1M28u2Tx8rKPqzL6BroNkkzk5rG4zj", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7MgzqVTGeA4wENme81QPTrPy45NJMKVL9XGwxmNT87cG", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AYFEX8ccdhc4rRktfDLTDp66H8SA2WSAp3PTVX5isqww", - "targetOrders": "2LS2TRu29kEBLievEEpyiTntg9AHbooxb7va8ymCjJc1", - "baseVault": "EiVSVVNR9CqJaDZuGeFzhjBcsjaGTLbuVUiSbrjSjuXH", - "quoteVault": "14KfoYws2g7nxRWjdAQLXAnscxqgmKXwvHat7srm1SqV", - "withdrawQueue": "FR4szKPceUbmHhaSiWCNLj7abDazrfgL5119dCZ9B8jf", - "lpVault": "81Ytzop5maPp74VxYeQ2SNBauqzEqhe6CFzTudwiBmRE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8inqBe7D12XJ6tMAzpLCGYpjazWFXG1Ue5q3UZ6X1FM3", - "marketAuthority": "CjVc3riMBYD8rJkLJKiffvF96GPXjKdyKmKA2BswD96E", - "marketBaseVault": "9p9fYpYwiVappGhQhqwGNkbxtjyNjEMdVMJK8Ds1jgBT", - "marketQuoteVault": "5qtsW5BHttXcVCTsRMex8unuczceQ71btMa38QdfuSSP", - "marketBids": "BRdC6FQR7BzjG7v5wgg743RXoo8odpyP6kKVUEHzcZrw", - "marketAsks": "B9H8pTZHv1vjALHbNy5G6VGM73VScHe5ib51eSKXaPgU", - "marketEventQueue": "5wauBJidiPCtmG8cdbH6NSm9L3N2W6Y6VfYpdK8YRoUe" - }, - { - "id": "4EakQxNUZkDvf9vnLfSgQAP9u5ffb4ys4Z9u7oe5gCyW", - "baseMint": "FvaExVNHCACXXeTDj6hpZFLCyhYekT8zxpfPXiMtba51", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4rXR4KYcC67cA9xC4dS9WQLEFqg1QAuFnqtnv8nDmngL", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5zJmqeqmVgGNMchbP4owmL2cp1R1EViXHiEHHGkaMiKE", - "targetOrders": "9C6YwrHt34TPXBzjfp3ZtvS7Lb1JJeBb6X6TgMKChsJv", - "baseVault": "CuAFdv5fMcq3x777mF5bYaP1cT9QmvVXkf1HgcNA4CeV", - "quoteVault": "8mzBQFCGdMs7LCjiedxZV6Nj2ThgGovN1HmMkck9Bxy9", - "withdrawQueue": "2vKhbpjR2VXQ2qQXVXRXQ399vP5ShTiSiXoeGnfi1Qtf", - "lpVault": "5E4gtLhf66PJKA5u7mjsy7BA4aYshHnuQtKWGKoki664", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AwQy25ifGXBt2D8tEjyyyp4LR6SKUHcnyHr8NC1vMRoC", - "marketAuthority": "ut9v3kTLf7UcGbH8rhtyFr9d81A6JqmSgt4BjrU5jd6", - "marketBaseVault": "Xx9xCCFgmgWz51YbGsUBW3QFSfqwJh24wJn1UEcCgsV", - "marketQuoteVault": "7gwHiWYK8M4m6ZkcTh3ZVHkY94zjV4fjc63aEKdhVuEE", - "marketBids": "CoRTxXpY3kbyDhzkPfUarVz373ALyt95m3xT7WnbKy8M", - "marketAsks": "4oHSG24pkTcWQBRNWhaUsmARycMoRybxowKvwPnyBfAP", - "marketEventQueue": "6Pvy464E7c4eGRA48gLjq6bSWa5QnJR8WPp9es3e25HN" - }, - { - "id": "4EbdAfaShVDNeHm6GbXZX3xsKccRHdTbR5962Bvya8xt", - "baseMint": "9LzCMqDgTKYz9Drzqnpgee3SGa89up3a247ypMj2xrqM", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CKLsdFF42CU2BzKkFczu8MtFJvcaj8HjSZr2y6ogj7fD", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7uvYqyiiqEw3vKkFdnRUbmZgMNSsDXZMo57ZmEeDUavg", - "targetOrders": "2h1wdnSCAtYw3VZRjzjo4YdKd3YVR6FWioCBVp6kdp5x", - "baseVault": "CmMV3U4QYsykzM1fEYi3zoZh6A3ktmTKQpJxgignK1YR", - "quoteVault": "DD3baZQb3PFkk7NmJXRj9Ab7o1oq2h1mUae2FmEnJCs3", - "withdrawQueue": "A2MN389RaoJbMbaB5y7Egbn1gQT6zjWzdtFoWmU6Mihc", - "lpVault": "8H5wRgtCBu7oNYRtzbptKxEJoPzkCHapfR3oeU4TY1nH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FxquLRmVMPXiS84FFSp8q5fbVExhLkX85yiXucyu7xSC", - "marketAuthority": "6bhvdkoTfqfmLxiMhTBU9quSVDgRHYhmRbFBpTNQVvxF", - "marketBaseVault": "G7zZ6ckemdo3BnktA2UKbChZ2sPrY9C2MSEQjk8oFGoi", - "marketQuoteVault": "DJ1NitJTAfkHeyE1cp7mwyE4ygJ9DfgxU4YE4W3Vx7YR", - "marketBids": "EJuyU8fVJfB93KQKRsVDZ2pEMrKc5kxqKg77L7Bryjwg", - "marketAsks": "9vGD6d1BRYLPjqnig5BUkTeJLs4nuPeN9XTsuq8Gi1wH", - "marketEventQueue": "F43jnzWtZ78AfQFTdypysdJYTQtEznyC9RMzRUSS7Rmv" - }, - { - "id": "4EDYy44TbtY2tE8RUa1DzFyYAHNbPKCVFTt7iV69Z5Vv", - "baseMint": "55t1PfJngPgMS4c4HeSHPy54VWfkMEk7XBQhSkdz6Cm6", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "F4q8EktoFuj6ScZikt8DyVNfCk766S8Y48eB6hMfFUJY", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3fdAv5pdjzcpJErgD7JCxU3L1NfvJjDyVXdrMJzEgHVd", - "targetOrders": "iwxfp1v9TKSdREtJzF6M5VhdBW7YKS7ixDUoJ4LeDPj", - "baseVault": "HZ46DErRtG8c5J7rFy2U9VwxLAUV7751Z3HX35HB1ve", - "quoteVault": "5Dmdni6hSuyBWPs3MxbMprXebwdZFzSgZB3LQjkijntT", - "withdrawQueue": "BqsxJ22fAfuF8avxqRE2cp8Ny5K8RkrNBhfiCBBwpiF2", - "lpVault": "7GwwV5g2P6f38pSKsLg1rQT8W6a8Ao6jHspRp3utsgbr", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AVRst2QogwZ5VjCtzaLMSmQYNdmQBsfs7pMoXgxB9Uuy", - "marketAuthority": "9VGwX5DDgjHavVgbZfqZzVGfgZyVyVYdd6DYxDKrJt19", - "marketBaseVault": "4ni2dvAsBqUi4tLHsZbPBoo97Byh4xAFXKT7nwvYG3nZ", - "marketQuoteVault": "FvPH4LZoK52TPisUTGUWcTooYpdQce6LJXKghADnPKP6", - "marketBids": "xrTuKLTnTKftfAW3YK2rToartUt2bjQwpwt3Sa1PM4S", - "marketAsks": "2Vqteaf8rnCmg1SqRqjuXsjuDg3F1wg6Buf2SYZSZtGu", - "marketEventQueue": "3p16imv8EMhVtFMjHbRoLaLSeeijjX8ATWqi7osp69zr" - }, - { - "id": "4ehB5vHhjjzpArtYijcQqEyyt7XAcZAF5MGKSAeErxC3", - "baseMint": "8oiPhiFrmXS93iC98M4ATev8emQ6XGtf8pz8sntbbqGt", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AAa11BmwBjLsg2ENho1x9YprHGzNsSKCt8EUEpoovuHk", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BuJDADWzy9kPmjwFW2oBCSq6g56L4B1eRHeZsreeQ4ph", - "targetOrders": "EsRM2z1ELELF22AmXBZSzXBq1F9PtaC9EJFwBFzcaBmV", - "baseVault": "CowEpHud5Xdv5WLteKzrLXFD9VfCE8gENJidnKmaCnDV", - "quoteVault": "8ggtjBeQnA5xF3phPZXgjxqrAn8iea8RB46Xnq9CpMaC", - "withdrawQueue": "7Jw3rRKzsBD3No69xu4bi1GRLyouM9jdmFnKZJLPDanC", - "lpVault": "ASz1L8aJmqyq6g6MbZZyvPGYBBWwjsVua1NLetvTxdoW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HQgTyZMZvJWRGAeYQcRQvNSj3VzCycxy6zQZQ1gK6SDK", - "marketAuthority": "6FCoufqWmKsBRCHN7G6YrYf8ciPiATjUsFPRmnh5QGzA", - "marketBaseVault": "9wufNLPsqVH9oWzRKjcGfEGhY5QjasEF8S341EyQH234", - "marketQuoteVault": "DqMgBWrmkCjmHuFnQnx39cS35zEEwF13NG3612pY7S1S", - "marketBids": "5Amr2brSZ617PJiDwChcwE6E24BZg2QJietGVC8QxuVP", - "marketAsks": "6Lgzh5cmYr8stnM7wcwjVwNyL8rgXhwNYZZEoSe5DGRM", - "marketEventQueue": "HCvB772GkViZJjd4PcaLjmDNwDTrtHWe2pxnhho8Upd3" - }, - { - "id": "4fCeH3XwXDeRmJBQZ1LcjvZMtC6gApySo1n5e3voJ72M", - "baseMint": "CZtYQvMEQdtFFdF39PtMxGVMditE76AwbXqJYFEhYFvA", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "9xtR3RucFKSTFF9SXieUA9GqUeAAUv2FNFv6UP1H1E5", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6EaECuKEfJRseNiWwtevuY63vcWK1g5FxPFyYocWndKg", - "targetOrders": "HHBib4BDhiMyJ5uzGPY88iCpm4ppMDzzXovQZm4kUo7Y", - "baseVault": "8GM8GZEHjMr9QFiVyJ1uYAHiE1HCR4megaW8P4zWVtv7", - "quoteVault": "FvYCtd5Vj8ko1YG4bcxQXat4vWgcyfSgBuL9ZBriCzNh", - "withdrawQueue": "DfebtAtBaTe2VWYzbMTtGxBNocncwLJAq3J7kHnLFQzm", - "lpVault": "FHehhrpShpyGnmnWGTPUfSe5WwjHkNDdVRD2xMHijFLJ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GH97hTwvBj56QnbwQHDqqEnu1SsJPGzZte8AM5f5KSXK", - "marketAuthority": "77xJjXHxXEhGvkQCYN3aJTUzGtdnrVyJn6VKTVipLgvY", - "marketBaseVault": "8JJNqv63VxJoGhUSDr1BNCbdwbfdEUvNcNcdjfNF1S3g", - "marketQuoteVault": "B2Xc44KU7VvvTJ9vftiEkPqFcXvqSyWjd55YAcyCMMd3", - "marketBids": "5QETAauVByhooYVMeGPafhzj4qdkG6oHAuMAC3hTurjq", - "marketAsks": "9eSgLPZj3ZNArm4hozad6yEjhS4TFrXyb9vDDPPn6dw8", - "marketEventQueue": "39y2aaWE5Up5GsF5ejyHk9EK8aJFvL32nQhSrmzNLcKG" - }, - { - "id": "4fgcxFdrxpFT38T5VGKjErQiPG95EqNen1YsVk3418E5", - "baseMint": "95bzgMCtKw2dwaWufV9iZyu64DQo1eqw6QWnFMUSnsuF", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "44VZgCfnrzgrRbWPbR1z6T7pCBg74zLhBj3ogf759xwy", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DMeUutWaHQoAKiZPp4rXznFCydtAnPrUM55cAu4amXEp", - "targetOrders": "9qvftXu1ZP3bXG7JuX4qDX9txHKwn2ZfFqSj3yN1WvNE", - "baseVault": "3ok35P2iUGfV5K9n2Pstb9QLg7TeyPFbyqstaweHkhHv", - "quoteVault": "5pjruNk3Qgazhqh3NHn2G3R3UJwGB4Y29dafhSoqg9nt", - "withdrawQueue": "7CvbH3jbcxZAyVymR6DKzCCx4aB28GkBFvtKjeNdFH8c", - "lpVault": "DjW62EmYoFrkbwyjTCQSxU5xBgEPVayb1pc2ppNCt9np", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "74egdfDDBhrCqGMXxB7ykpNRT2qgpy9xwxc1cECT9Edw", - "marketAuthority": "AKeWcr2M8cFxSWy5YZJ1yH7etDzaU65buCnzXsTGiM3L", - "marketBaseVault": "D9ts5SFpRUeV2ZTnxytbEufDk88uSUn5vKKMng17v6po", - "marketQuoteVault": "CE9XBg5dVXYxtq4BURu2YujTVRXMzozQd1dfR8jQ8rmh", - "marketBids": "GARAVB8NdaBy1F7TzBt7HHxuU1dWant4QHT8GNfpoKY3", - "marketAsks": "8ZTpphVEePcAsA8XCDuk35AadALUdVsEjYdoyA5d63JY", - "marketEventQueue": "8etEJkmUXmc996dqNtdoTv5mwT1FRbDgHTJaY2sLScRh" - }, - { - "id": "4frN6RBpnDwPbvwUyNiLtTZTiE92F5J831anATceEBJV", - "baseMint": "DuSyBCGuhPvyGu6cSvbZonvQvh8JLyGvXJn1TmkJh6Zn", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "AzMG81UXowPinBYvP21XG7prfVpZA7fn1LF1GKBoCwTK", - "baseDecimals": 0, - "quoteDecimals": 9, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EvcB8vu8ZUQfJkcBdFjurwZWdDEW2mBPme33cPmJbGzk", - "targetOrders": "286o9cRTQXQYX8863DKLSLrBBw9dvKSJe8iY3Pgu58nM", - "baseVault": "2VRUf3FiYCTupoT1kR5G2PF7tvKhXufd9pMxuQL13LDL", - "quoteVault": "B5VX26ENmerWWyiuwcSJi7eyVxnJqhgNyPFr3imuv1Rk", - "withdrawQueue": "GEoX5bWneuzxjw8ngNbqmuXzeLXhiiVQWegKWo9EPgoQ", - "lpVault": "6dHay15Un3t7aU7MaRw3mJKdRioU7JJb6jcoJyddXrxf", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9MQKBuVXzHwTS2efdRV3r3sVwkJaD8Qdr5S359PTdGaP", - "marketAuthority": "F2JuaQWZfqmwDypj6R1UZqR8bHHj5tijH2AdGuR5n7LG", - "marketBaseVault": "4UPEqCntp7uMaD7CgGPm3zXkXJjKPiTQKCH346aWWZAQ", - "marketQuoteVault": "6KD1tEvGXoDiU7G4856yjMJFG6Z82J6zNezDfCtz9YCR", - "marketBids": "48URDfR9TwnZY4C73TdLQYR8RcsmQCW7gngzKmm5n15K", - "marketAsks": "GUijjSTxyft266XjUPyoxc5xn9UijaPm1NFtRmCUNfsQ", - "marketEventQueue": "3oCeyHyVttTxgPwBbgtXt7ggxcCVGRrabDTxX8Fgqdbw" - }, - { - "id": "4gukEky95dbBKBdkhffoKZVbZPkuNvjZsPnXkvzZTZ4v", - "baseMint": "Fd68Pjyuy9ngzwfALtfYDNzgoTCaYVPHPZv1LzJm2Ay9", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "DYAAPCh8vqJPA855scwkW2byTAr2q9uvW2A1ixVmJEhv", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "j6yeTNyN8EKVJMLHPcS9GrDQ3EQJBzex5KfgPPAm9tN", - "targetOrders": "6nm3V5UL97mrTUeKJ6yQMbFyh9t1xh7zs1roDWZPsCcm", - "baseVault": "Fsdu1QGAEa2DMyvbDV5NEqHcmvDPqknVmY3pjtbd3LWQ", - "quoteVault": "DDhr3FPiz6q6RM6Tk8ZzyhrWWE8BTHJ5Rt8bXiSRcVWU", - "withdrawQueue": "AqfBvmWXQDx8umU9Z4Xvr2LwhfJV9YFc68pjY8xBbt6t", - "lpVault": "883YWnaE3CTTgzfMW4xJXDhTJR3po6JLt5ziLcf2RWci", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7de9pB2tDQnP1dVtTJ5P3xvtsBsjhiiSAhBkyDHVkaiz", - "marketAuthority": "BMw47ScRX61eaooMSULuoENU6yMrPoKsJVacchpYRgSN", - "marketBaseVault": "3RUhwwFQHXce4T2rtTKzU6GHMYE3Y31fnGM7EXfdjGFT", - "marketQuoteVault": "5eSvmVSghTZgLT6XPp2ygXdZXP23ncZoUmEciAEnCpGs", - "marketBids": "25YR2nd24ToSKQC2tqN1FjU7jAA1t8gTMYjAiRjjkUg2", - "marketAsks": "27fqZYCzgs5wFkhjrAQgTd9399uUspsquSyFwss2t2pj", - "marketEventQueue": "FpyCckxd8wuBRYqpiXUpuDtnTS2RXQ5gpdBUU7spuVzd" - }, - { - "id": "4gVUfGTgEbtUVExJ5awB6hHGZ54tAFjLvQqeRZd9CQP8", - "baseMint": "hone3CJTYjczb5nJh45KCNMkjrKMt7SCnHkWGWsVfVu", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EDjgZJq3ic4mPAkBGeZGkWeKiRkEBAkycPXegbxWKV4C", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7TzsRaT2uWnkM2NsT1Q7saAyZyU9E7BZB2s4A9AkJsmE", - "targetOrders": "9ejsvgHb3cZztu6svAVs5eADJvHAemH3pG5a2TfG2Rdg", - "baseVault": "84gEf6awnsVvcPPWRW55nzL3fiYJBNGQUH6NuduzpVB2", - "quoteVault": "aXCmLC3adrhQtioAvCWzZFHghTLquBfPCrrcShK6KG7", - "withdrawQueue": "GF8FhLThy3D4eV8eshGCbDFGfa3hypvsm7nCpKy6v47w", - "lpVault": "6jzpoApnzQ6MLqRVZSLE6ZeMabhpS7EJnwP6AXTHRPA1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Bw7wZWa2FGUbmqmPsHnihoELYga5qpNhA3tX4nuR4PxK", - "marketAuthority": "GwJzZc98YgR8nL6ePqBmmMqSNd3um5AJuD73g6canfZT", - "marketBaseVault": "72C3ggHci6pmnPdPdVxAXPDDhH9YNfkR76fdU5TKa5zo", - "marketQuoteVault": "FDrBfmQci8vSRGgXpKawRvgJJQakAP2nE33wvvWG8wec", - "marketBids": "CMXCc62AKwe8SJ2ZEer44QLnPfUXhqbpdCmvbjvYGgwn", - "marketAsks": "zwjUrdbU4zSg91tVVTgADPUuDi1UuLuPM1Stqy1P3hh", - "marketEventQueue": "EC5agWMD3gtmkEvyHsGDSjGhnwpuZPb1nW8yxyB5qC4C" - }, - { - "id": "4ibwLXc4YyPn7zbuCZBmh8A5bj5zcSwrB3zpNFTPJq7s", - "baseMint": "4nhQdXfoHvCCVnyZQg3awXqPrKL89Ys7Rbe77oXM47GG", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "HktE7uFm3RzwQgz2Po6NxJt7ZskYXxQ7rxZCaZ9QvZJi", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3VxdchK9Z8Tck2rayrPmp3bWxcjPNfciwRa7UaKEBxuN", - "targetOrders": "7B8G8MLjRfrHNq1W2J4bogFKcN573ymKF3m3CeaFPPiG", - "baseVault": "9kPJAQ3BbZWidqYXjWxffmFwtPKH8shcCa1EPJFRR5xZ", - "quoteVault": "Dm7oXXX3Kxp2Gi12MrRweKmDuT4cfUdMnfy7st6o3Bs1", - "withdrawQueue": "3UG3jTAMJYCXFiu66Yu4x26D2kPhxxMQFpyehdMddLNs", - "lpVault": "6DE56ejjNGAfZidNqRSqbHWQqMvsgqan227d8XvDekEk", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BrqD3AkEVVmz4PSqoUapyxBd6kK3YJ2bxDA3qJCYNVbW", - "marketAuthority": "Deau5tR3dDuRL4M9CyFuBtS3XJU9bmHhdpuQKtiTzndN", - "marketBaseVault": "3Hh8ofhT3dBUg7KsdtUGRNbH7pnJKY6Q5zvVkBS8CBuH", - "marketQuoteVault": "HDXhPrTYxi2C1Wutw4sViKR2sreuCLodnAsbf8vvUvvr", - "marketBids": "9t1FuQa4w2z2r18A7MD1886FBhR3zvjJCj8JVdhdHj1Y", - "marketAsks": "77yiai4n8DP3TaWj2MHr9kJG4MCY75rNroZt2e4cbkFo", - "marketEventQueue": "84DCzW9KLp2C8c1BwzG7SgFjA1V2uiZjWyNs2LMDroJY" - }, - { - "id": "4igoYR6KR8qgaj1EkToLMZqhA5BwgoYAXHQvCtJJbZHS", - "baseMint": "9VgfFUFkGGrRePvpKLPkp9DR3crRepf6CJsYU3UmudtY", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7WVNpXYPpt8Gdk4KWP192uYzYLLKF1c7jtzmztv4RTgq", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4mm1MZH1xH3FZJpJcmVuNLSyxnUQcNNtDWyjSX4vScFw", - "targetOrders": "H5aTzVSrYk4d1KBki9tdFLghd1nFcR6KrKvD1ePP4XaA", - "baseVault": "5xCbeu1ZKg1wYdCQDDNEXKFbZPVk5paKG2V5ux4A3Qhu", - "quoteVault": "8cWvxCPVty7ScqPSivSyctc8STJxSiivusvTGiqSRcUV", - "withdrawQueue": "7m7HPPhdq5xD9fxtxAU6xgfA9m2JRVvcT49BqktAfLKa", - "lpVault": "EitZpE3GBP2R7DXoVA1sKtZK1ZPGirdLU6WDgYrUwt6L", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5zu139pjwmUeYrk3vyFzmycdv99612Gb8kD1CanHqKAa", - "marketAuthority": "VU2ZT1KBFHUT9zvVtfte3PRVheiyBQgGYqPeVAzMaGA", - "marketBaseVault": "pqj6NJayHFVoTVus4FjeCkEjHzxMykLHWgXuWfppYhn", - "marketQuoteVault": "73jooyJntToCcq1HdnF5NLTHCRbeshFjyQCeL34mv8Q", - "marketBids": "EruYLNXuyffPDapjHV1zhxcEHi7Cq12W6vsXDkqHncQx", - "marketAsks": "8guWkxapZYxLh3dWE9VJ2FSioif7XYN5zNcybwxrjmyC", - "marketEventQueue": "33TkUX3GzH8bTv6CT4noPW7ijn7RV4rjkEvkRV1oi1Ds" - }, - { - "id": "4in7jrz4exQriMniYPrYbq3UUjDdDzKTTgxdY7KXKEDD", - "baseMint": "379WD5JJmV8LgcTyu4i6CPxNbm9WdTXF9WYnkHoz9nNF", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7PndemqeELAuT4zF5gE3vN6yZtUptt2qn7EeWp4bJyKJ", - "baseDecimals": 1, - "quoteDecimals": 6, - "lpDecimals": 1, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "27ahMJuKJTK1gaqsDCoR8NuyHKKwbtgcAntrSMBYxZST", - "targetOrders": "ARCGMcD9Tib4VBRSjdKgn5Edg37978PQfD2ynEAWjrwn", - "baseVault": "E5PEeag2SUfU5CQKKTDK8P2cTYfoW9SiaGPuEqRmYobs", - "quoteVault": "HYZNiyf2Pt13RUDnyUfZ4cFsq8N9zcqhRJ9XaZgSP8oP", - "withdrawQueue": "6hcy2nCYu36giAsdoYFwpkBWWo7g8RRSo7XoPj6XcrQv", - "lpVault": "CWwp2tvNRtrUytBs8amKDwNd9t8c8TdSrJaXMkWxLZJD", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2kKFRYSjKjB8eJsZp2E8G4bWAPNSg2VjoTn6v9it8Nzc", - "marketAuthority": "3J4utAHYaPEjHmMk1jRWh5ercoV8MTMEpMsSAunDjVjq", - "marketBaseVault": "79KRSvRHp2KxqJuQXbvTPdsyQVy1hP7CUB7xAAHhWyfB", - "marketQuoteVault": "GDgtR4f5jB7xs1jWmUhw3PRrjG4pkRoLD8hKPPv52DpC", - "marketBids": "D96LQtqQoC7R8HxUPFg3T3r8j4YzHEgbmBdE4jQeB1bK", - "marketAsks": "CGM2DpLknPn3s1LL4LQaFwsWYhRagqdugpac5uYf3GBP", - "marketEventQueue": "vwgaF8mRTxnMVvnPNhroNUsn9cFEfUMaZxSrLi6MHQ6" - }, - { - "id": "4kXghpfHncBK3MXH1oR7h97nHGhhT4KfNLm6iEjt6h8e", - "baseMint": "BLyV6szCZ7Ypye8AHXyHDmjC4uC73sGvEJoMwoVQw3Te", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "4cZXfQerrSbgPwjq5ADEEz7nMdUNHfpkBeoPDxwEfVVs", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DEepXmKYppTKJANHoDgxbiYCVhFAgRJZYFQrnfkkDq3u", - "targetOrders": "8teFfAM7jwuDpLzeVKkmfDoxPBZsig3Y29Pf8B9Lzf8s", - "baseVault": "FUWqd5gw4E3Tuw6TeQqxgGr1rAcWbAPGRbK1HVQboDe1", - "quoteVault": "4RZg3jzQYvSaX27hRU6JXiiDGjAtgGq3avwjaJAJYCUt", - "withdrawQueue": "3SXVK1YL9Bb7e2MML4GeZGfRFvcQx43yKJDpQzjysuae", - "lpVault": "25WwCPUtNaNp2oY7gVirdWwB7RYUU1dx2XLfUjjy5T5f", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AmKRfiM6nR1fF2G6gMnQDUroxbw2ajRv1gg7wFTfp62K", - "marketAuthority": "6Q3HqMFgXduGdYwT1CJNw5DiWBht6ZAsdUTJKtu6aQxq", - "marketBaseVault": "EGM7bGJiriNWa4FonRfWDobXbcf4Y7Udz1on9ofpjqCa", - "marketQuoteVault": "FtEv6ruvP4HTQkYGZsTef9M93cUn1khRA4sJooPd9Ndo", - "marketBids": "BCKu2ETeASyLpY55eq86qArmL3XByiohj5UeNhXCpALa", - "marketAsks": "2JiRDU3DeztHkHFNk8ovLFpr8hR5AEwwSf23eJEJVgka", - "marketEventQueue": "H5MwwLdXmx4EDDiAwhaKrpEeUsyP3U6ULiNkaLuUnXQS" - }, - { - "id": "4LJN486prPUAQGrxhoi9SJGiL8wmYoiTMxUSw2HrLQn4", - "baseMint": "32NkWgx6KaLpTEYb9ape4XNWff1n6Bt9rsmwepiJzxop", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "92uL8gmnwjAGFarEu9MhMqcDxKzU1EmYUHoc9TWTZDoY", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FEvKk3EQfBYNQs8w3puPVbGo8pABjg3RUZFStbHee1ce", - "targetOrders": "2aoyGCi9N7A9GqvBLEWyKmcPMn8HiurZsxqGSGZHZfvB", - "baseVault": "42jaqgfsizTfyxQ7W8Go5c4FRbNRExKJ8jg3MFv3eKZB", - "quoteVault": "3bqsiFDAMdkEdc1bZtRWzsYW2BUfADmPgPdyb81ruBXN", - "withdrawQueue": "7AARg4pK6cMhQ2PJQdAamhYzffPC8jtr3bshcVssRE4S", - "lpVault": "dmGndka5WjLWbaZMcgopEwnwAe45pQ3XcZG85LkPcWG", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "B917dV5j1N7S3zDNrv7dQRM7Jh8VbACEWvejnfmyJRs1", - "marketAuthority": "8HitrdYC8oBeb9Mwrpbfi3oqoFuDJX2YZ6fGTJxxZLk4", - "marketBaseVault": "EfVp2jD1gBzznSc5dzBKcAJfTpXGSmm55YRSS8ktYMzi", - "marketQuoteVault": "38aAq6yi4X3XzWDH6JDj56LrqU6faJMeKWJfPcHhSzsg", - "marketBids": "9dd7tfhprk4QG7HzPJvoggK9EiaezhpWJ3SbmEVZcvnT", - "marketAsks": "5zbtAaevyedeyWkxtnq9NQ6sZx7tKMmjayoB48k2o1ya", - "marketEventQueue": "6TWdEXdtqUWyWQzaguReniBLCD5K9NBPb5qmRWJrHN5p" - }, - { - "id": "4M1exGfFG8AnVXn7xwScN9Jno49pfChpa7e9jF6k9QYK", - "baseMint": "HbrmyoumgcK6sDFBi6EZQDi4i4ZgoN16eRB2JseKc7Hi", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5A5pnWypcimySyspEaEKyWp9f3Jg5nmGgQosZurA26bB", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FEXUvj7a46shp9PJryKBtvJBgGMbZF59uMGh4JWyEeK6", - "targetOrders": "GeG2zCvcNdou9EmaAEBH9gAtoBTPqLY94oumWuBmGyoX", - "baseVault": "DrbL99oPdR2N2bLcLm6gv3yWaaHPgv2vNAYXHeXHQ5U5", - "quoteVault": "BooXF6Jz9kyo3ctMF8Htupx8KVXRjaZioTBEnheUD51a", - "withdrawQueue": "AuWvgG4Wp3DiJuSm9iS4jveiPQhdxttBdKoTwM77JoLp", - "lpVault": "5w4unZHMmQ26d27yGkr7uToUPE8tpC17noZWvLqvGWZw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "H3e7YziokpHJfFAMAy2PK6sNph72f38P1ELd5TUQaocv", - "marketAuthority": "5HyCX2R85WND3hp1vwBDxNNm7aURMWkto9hz2g8D2NdL", - "marketBaseVault": "3LTZSGwfow1tqrrvjsRJHctNeJGWrWp963udbvYozxPz", - "marketQuoteVault": "BdkX34nKCDzDPwqwZV83M3Po6pdeyEWz8vEBsJC2W1T7", - "marketBids": "DeuADu1KZnjnAxWF1m1L8wMY5YS41a2k5yhmeuK5qH2g", - "marketAsks": "DJ7dveECpu9RPLtdiSfoKbiKb2kCqc9S5oynjqZvMNf", - "marketEventQueue": "2yBg1ruTqTctjSj3aNgL9Z4j2ZBG9Q8ei7ktpAfyootX" - }, - { - "id": "4M7aKwu4YiRJsx8rVNk8kYZZ7VcaKSzFdLjrwZ1kQtW9", - "baseMint": "DsVPH4mAppxKrmdzcizGfPtLYEBAkQGK4eUch32wgaHY", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2KX1cPcjC2Vbo3mxsBsPFTJxgYHL5Wmo4cYFFkh4AG4w", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EomnDsi2H9S9UeEMYtHLrsnma6s6pXzxdsTLw2v5YkfQ", - "targetOrders": "2Vwh5zeLg6UukhM7VR3jGpGrgcysvP9tgudFoBqWTB8r", - "baseVault": "ytxvdJrzFodM1FjzzfiRkto1hh3Q7YLc9piPGDDbiDU", - "quoteVault": "82dsNXXPC2Qp7xaQmEykHcHq6C5ywUbjbbrXyb3bBSvj", - "withdrawQueue": "Gh3GHAfPXLxmgjeed7EwV6uP9ErZZveq4zc9Qmk98pwK", - "lpVault": "3B8roTkHs2MwFLPioVZTPsbCD6yVh2yd84AkLCCAoVci", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5BnkVi46Q48udbMy9kW5EyLaRXydfx3vqW82BHftfz4H", - "marketAuthority": "3A8sjMs1u1GjDCb3iMNwJngWfpM49q5P3bXYP1GMGFcy", - "marketBaseVault": "69eccf1x3TUE9rnCBdfjd8xh1rmSRXVfpynCr7QHfgM7", - "marketQuoteVault": "37Rb2T3iwCfDkDn8p1dT861htUCG7QhGF1cM9T3AB6si", - "marketBids": "7PUQmwC8L6z6KrKFbtxrdF4KJSvhxwq1frihQPjC34ti", - "marketAsks": "87wmPbKhcvWmGsM7rfHDYMubqKzhv7Asbd4pP5v7gNKG", - "marketEventQueue": "Fw1FBdxBi5qN9H3bPVDTfKPCsXdk8WDEGfvekxbrG1JV" - }, - { - "id": "4McViNZyEBBRYad61iz5TMAahLDUzkuoUrWPWCSpHZSx", - "baseMint": "BABYsocP6cB95xvBDXnjXKX96VBNC37dmNWUtaV9Jk6v", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3WqAEmF8hmKZkrs4mPLUS8ZnSCicqFmKZUhQAreGht3N", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5J8nBKHDBMRooSwNx7GizhDsuwoHT66NzrU8NhtDs6ML", - "targetOrders": "5J65HxNoGLEaRVZuAz3LWqzzS23UbxXrQNa3W1nnMWMS", - "baseVault": "EgcJBqWVJfKUhx76YQ3m6cH7AWCE3Hbo5CnrS6ve4Km7", - "quoteVault": "7Qv1xax8B4jrynQPxNxCsZ84NPRB6SM2ZW3FUtHYod5U", - "withdrawQueue": "2fkpy9LsC1QqjxcrWtbJcSJhqPjp1jdcaB3hGZA74RZX", - "lpVault": "FZ7WujwFckXvhmiasYPz98v5KH6S52yuzE8gyY2CRmQM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GCmfmqvNbY9LXWJ39fD8wNDn1HLj4sF2m9WAoNVVYaFt", - "marketAuthority": "EdWeSAokpkfZukPtLJ26hooM7Q1CPp4PkNiZifDzmcvR", - "marketBaseVault": "Eo9yjZ22wwbQ8NW5CwXBAch8EdfikcydTHjdd8Ga5scR", - "marketQuoteVault": "6XoeVfRbe1xbyDhHpk6adudhC568ti1jNvsjv4CxPKqp", - "marketBids": "BXmm2SppbYjQXUgNTDAob86csq6t83RG3hjkBRHkU4ko", - "marketAsks": "89kNhcGkxPfDgjGtB17y7N4nU8JGyeEt8UYfGk517Ejf", - "marketEventQueue": "6H7MosLfu2nDJrQL7hLELwKqgP5b8eH3a1VH3TNY7Nyg" - }, - { - "id": "4mEUynJWot814JBYzUTN1h7mVXe65Hu3L6yMwRsDUGJM", - "baseMint": "7uENff26kbM3zP9YhYj4MdSzS5nGoEDSeHs81zQ7Gp2J", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "Azv9uoS4PjBNrXNNeHsZMh6dxPcTkCh4edQLWUukLXAa", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CfAe8VP9P6FoGKCJefGyiXSsy6B5w8h767Fwy44ybEZQ", - "targetOrders": "6dYWaJdPvnLX6cY4bddVHszuAHorKnKUeh3QQPkPsUbr", - "baseVault": "2MM2qs5AKDQBnYWnjYLtL9CAfWrxpRRTyxtTHBxM77aY", - "quoteVault": "27caf82TtSbssiuSYU3KuJVuornQZvr6dqVHGu9mFY6t", - "withdrawQueue": "F8yTVz2SRZMdyQD1vki2pGxd1fAk5Poi3UJhrbe4umV6", - "lpVault": "HNrV6Y7L5r5dsZ7KYX1kNocxu5HyxcfV8jcGbbsu4uSB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7JpVS2GDnzut3e23wUmcSRJsAVYQ2GJQ9VgF5gUcWS2L", - "marketAuthority": "G3ujV4kCCgHrhgZtHQbGVCD9HBqtVKfWX55G4bbE9tzi", - "marketBaseVault": "8tGsfLkAED7T6nhcyCGBXqzN8xmWC65ZKiXUe8piHRbK", - "marketQuoteVault": "EZvjuD7Vdjprqt77cu7rivjW4LYRDxs2sps3Dx6AMpo1", - "marketBids": "5tWxQXAm3YFuFzsrbd1fwGiiVjvvWEdxje4L6bs9tngu", - "marketAsks": "2jWdesMHXAfvhpiv3Gcq8KhH6TxLWNN5aYHrfPVD5ZzL", - "marketEventQueue": "DsqWXSjUoG2o355L5WJsSA8hJFHra2F2tL9XGVZGuk2e" - }, - { - "id": "4mv1kUtA8CpdNx4h36uq6WiYtboYQwJunJSCzxrEiHjr", - "baseMint": "Eeybx9mpk4zoSHUftcJje97xr939Djdzvmo7E7koHGCA", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Bbt9pYW49DtQyicpADwVeeDaYBQZP9yuQ8zGRpJbKhLJ", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3bHNc6ZpeF2c9bS1S9divuckuZAPkdR9SCJxHr8GTxFq", - "targetOrders": "6r8nDxXcckPTvm1SzEHzZDL2FZbpsWucu9cdz6ixBPTG", - "baseVault": "DhDKKztmkPpnMtCD12yko9GUMa79bcGzTSR5BUCsMuVf", - "quoteVault": "G6KeM7aMC6d7VJ4X8t7wrguiNw4WK9f2YRQ5rD7L5eS8", - "withdrawQueue": "DVHuxVWxw2CATTuZweV4M8oHPBPSY8U5HfSUYdPSj7rw", - "lpVault": "699X3cHQA7TJAYAS98GtHLfz41yoDVUo62PaQ4vThkdb", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6tJ3hdkzvPUtECLAUzLevqjFNxB4mPSfk6cYbSN8A9Y6", - "marketAuthority": "FAywrygaARzryNSHbRAWdBcmieqiyT8Js7oDYtKTDnDQ", - "marketBaseVault": "BBwpd8DerdTpWW28UfMQoE3UY5EJ4Gh9k9MsyrVCx6rJ", - "marketQuoteVault": "5JR4SyjD9m2vgqJzgcwxnqZjRwhZpekvmip8H5Nh9qG3", - "marketBids": "Cg91XbBEvfjB3TsfJDEUQnFCuKy4XPnYkR2gmn7mdJSk", - "marketAsks": "5GSzV6tVMBj9iTagssheUR6kdYzb2dyXKK6dpsrUZ5wK", - "marketEventQueue": "9X6WMKtGTybawmGAA24CcaW1LTh55hJqKvLNaxdZmGKP" - }, - { - "id": "4nMe3XYXvy3kqnPwLMDZFHfpFu6KHoFwub7oCf3GJEzn", - "baseMint": "k5Ybbtmnd1eAtBZoTqB9uzd24bVPz8Aip5EGVCJXQCM", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9XB6pXssKzPKQr4Jdji3tASjMf5y7TAvetTGegoM7TcL", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8Y7cJU2pqzvPDWzjdKM8dzM6LmgC42Q6DpVvsq2gU892", - "targetOrders": "C2E4SQfYo4b73mHfy93d75t5Lw581RisbzXkpimoEDkK", - "baseVault": "CVAR7FQx3nM9qQB4ps3a82zhNNUVQu2Y1nBeMwQyBA8q", - "quoteVault": "EcRRhPUumt58NFLQnvDCpzFyR8BbkdQApZWR7vJ9BdPo", - "withdrawQueue": "AZhToT5zuPYvS3sVNHfiGbJDqMFCdaSatq8qZY7dUxmw", - "lpVault": "Et5G6JRmhApzcECndNB2NxeTkdPYrjUBEuAE3qAeY38s", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5FdAUr2cjEren2GpkHPZAVjKxEebca1bdRLZFL6SYr6r", - "marketAuthority": "GcwDhTEHtZUVM1CVywmMjBsTYqwPGveuEC8RS9heK4Cg", - "marketBaseVault": "Actd5dSGqoxUs4aRKc2LCTy3sXC6bN6vVbBtnm5CtLQ5", - "marketQuoteVault": "Cj1x9QBpE6zZXcg4qhk6CP1jKngTVwCfpptdWAgVWkYg", - "marketBids": "5Ur1mYoqwFJEhgGngRBFwkwEf5S4pL63nFFaXHYw6Gj5", - "marketAsks": "J8crgV9WPSY7rNFWR3wd9hU3wAiFmAPe3nGtisJf5hE8", - "marketEventQueue": "2mo7PMYQHbjxwdQPaSKBtBoqc4sYN9gF3uZkj4LGLgMb" - }, - { - "id": "4P5HFkPKGf7enuzMv3NL1K77jQ6mUHUe3mPLtvG7S56W", - "baseMint": "6nKUU36URHkewHg5GGGAgxs6szkE4VTioGUT5txQqJFU", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "8m3jgRnwv7vxbdZUnUxhCBRxpUTwXKkncrSfUJtvhV1y", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5pqAwLvBzpYhaHJER1h9Eu9eCafVXde1WrvxKxWVkw7c", - "targetOrders": "BTP7HhwNtQ5tpoGT3jYT3UKWPEjLEq8pynxa4HEmqPN", - "baseVault": "BFeMaTMpvTWC71aTkcGk29kU8MhjQw6pTFaa3vneTTyn", - "quoteVault": "6iBMqJi8asyhSvF6fMrLqJX929qs5ZSHqjvmFW4QTC3c", - "withdrawQueue": "2dR3JNtpaTrmX3SBbiPy378Wu56mQJ97i2AdRFfDjniQ", - "lpVault": "DecFzB4iZWPdg3azbpNxga2P36nadJ3B8HfLdPEJjGae", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DTMtV2JvKUyBev1qHXmy3mXaNveMdf8tnx3nqT9niGUk", - "marketAuthority": "68An4FVBiJy8d22EuDaZEYWNufNwAH4zzQGoCSA9nv5x", - "marketBaseVault": "D3ibvpNw5yKZSst3Pq9Y3r47ELP2udaGhNjJptmpDMN1", - "marketQuoteVault": "FZ7v8Ptmq6itvHqqw5Gp7d5UWNkbyXrj2M64BPm1AMFR", - "marketBids": "GDmD2TdQDn6yjoZa1GTTAZvPfiNGiWnfim42LsvEjkE9", - "marketAsks": "DsGPAM6L6oFKHozG2kcNcnCAqqBW5XqLCGH7DdfHDknC", - "marketEventQueue": "25EGKtzHJShhpsKqFq4Zsy4sVAJJXtUydFinEXMmJBWm" - }, - { - "id": "4PmuNgERzM9qQbkeFa8pLax9xG6yc97vnrDTo7XqBx8q", - "baseMint": "2wmKXX1xsxLfrvjEPrt2UHiqj8Gbzwxvffr9qmNjsw8g", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DSVV9b3uADvfNZZempxoexqLP8kw98gEytt3YttqMUhF", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FddRTfbzSVbjtLMhJPPrM3yYyoxDo3p1jHAFZ1kos87r", - "targetOrders": "33d6Vq9UWaXjAVb8D2CiKAVd8QyNxC17oJoeBWdEgcim", - "baseVault": "9bUEUhxRHZ43hzwXMemrY8FXiWSTyRw2ojci2t43CmqQ", - "quoteVault": "EbQR3k8Zy8uFJQt7WukXr97ee2nnAzWzjkXohAJvhfXV", - "withdrawQueue": "693uvYcJntb8HniHMi5LJbcJ5obMpqsAPeog8zVX7L3Y", - "lpVault": "8ZvHnNJztmxusKQNVp6EmQtTKSdgawKbfDJqDyomn8hx", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BHfFJM36MirbBtLCcnZokwRvxUPxk7Ez6EAT6k44q6Go", - "marketAuthority": "BVQQ2YfWraUweJVQpDCbJLAcLCEST4PT6A7KcW1xriuq", - "marketBaseVault": "6GEzQjXwNWGdB1kxXxvo8DYt2kJddREnpQqS7rVn15yT", - "marketQuoteVault": "5WU7xsa3jiFj4HDtjcCXxDXfM5WqSFgHdJpQEh1HC5Gt", - "marketBids": "1Uix5bSERsWvgvGd6tMjPrjX5LpwBo8V3sSDoMt3r4K", - "marketAsks": "Avmss7Bp9mxvmTJtb5NRh4h7quJ4u7KajY79iyP6hR6c", - "marketEventQueue": "37QiUaFuG7VvmpDD5qytK3QReQGFyqxXRYFXEVJkCs7C" - }, - { - "id": "4QfbDf72w26uTNUm3gLpB7tZwt1Fp7rbMLxNG8scHgT5", - "baseMint": "q4bpaRKw3fJB1AJBeeBaKv3TjYzWsmntLgnSB275YUb", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "G7QtoQra4VucrMDYMYhUh8Utn5cAWgRoavkbWG4wCqXs", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8UrSiDXwacSGQRJtxJ9BsTbM4y2jKpWL84Abf15N1W1u", - "targetOrders": "2gceJTcvLUVypAfeGC9vYLGWiTSvJb6gvZZUjJqQmxqh", - "baseVault": "ADRHxUXUDhkcgi6Lnj8xXW3Naaos5R6hVBUMnP5Kd6fH", - "quoteVault": "5P7tWtwL8uqCgKRPB4RK496gtsLznqiphdQE3fYrMDqT", - "withdrawQueue": "51LUKNqpgFxPvfxfhm3TJvkemgpH5BdvqxxvQ3M4y98b", - "lpVault": "52BrkatJ751vNM5NGUu4g2raTJQ6Dq1s5pwPQmX2fvNb", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BGkFj6TmB8E31zSK7yyQMRVkmpMpsZMFwjE1NoghF4qx", - "marketAuthority": "4eZEod4JxEoRWo6nWuhoWoPknincbs2WozZZgbs58qzJ", - "marketBaseVault": "BB9CzRojDV4VgRxdBvzz5z53RjLu8rdFs9MWj4zzAFwt", - "marketQuoteVault": "ceYRpME5nPLYPkN9uqDHfUK3atGm6MCPuYWvyyaa7cx", - "marketBids": "CcynqTnJ5vw7aR9u4RS2Snck9vLdT2KQYPDidfazXA57", - "marketAsks": "7UqcAXho376j1nRsK22Sc7cEMeVqA9aAcqBfBJZdw3jj", - "marketEventQueue": "JBsEusB3hmJU2rRXjpeDzKH1Eow7xjN47kpsygS3g9a9" - }, - { - "id": "4RyL5Knr3UjiCnFfyVo2gdCRKTdroXB7fRPWL7tKUnDj", - "baseMint": "6PpMNAudfuoqJadwoVrQTC7QfqN2Xugo8HAejy9EtocK", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "BbhGECKHGKZh2ji3XSn366X5R3hXPoDEg746qWhGncW9", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CghX6iePmWn6HsszLoh7QtspCgEe2x4hrcXqjscc53u2", - "targetOrders": "GSVGcApA5QpZdbPriJ4HaWLGKxFaohP1dRh277WSzk45", - "baseVault": "9kWxe7Bcnd1mbBmauQxjhAXRMtP46PCzQrSDjBMTQqCh", - "quoteVault": "6RA8E4DjJK8xdDbmksYUdUHFbkTd54hhhtzPpiCSJHQ2", - "withdrawQueue": "9QTbVS39REDsZr5o8qLoDjKLqZyZxqAoKQVKKa9hw7E3", - "lpVault": "HCxSDctBZo3KGNPqV3SWfYk528L1e8Tc6w2guKUojRJn", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BFoiMicGDwrmoMyYTwc9JGYup2U5eR5rNDJjvPRxxmze", - "marketAuthority": "G8UTbaFYJS1A9rccLmPKK183fjEqbBtobUFi8x1qNQRi", - "marketBaseVault": "64Z8ejfrH2wJEMuFRhCMddELr7aTdg38KxfyhN7uSZa5", - "marketQuoteVault": "HKURF6Er9vspEJ5ki3WN9DiR4QwGt4TCbDAzAAzgH58r", - "marketBids": "GfBxw9L9BGrEF6UHzydAH84edEE1cgifMSRa5HDTLyP5", - "marketAsks": "2j943DcgsSZKmZ8qNRLEid1zGJouHBMeFWeWecn9Xdd9", - "marketEventQueue": "2LHUpaGDwTYWgkGjEvUGvVdjMbGNDaY67cNnPa4Xhzwr" - }, - { - "id": "4tp6nSFc85ju5UqrqJsrJsENJkj38Qt8kJyndtDyKSPY", - "baseMint": "3KnVxWhoYdc9UwDr5WMVkZp2LpF7gnojg7We7MUd6ixQ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2cVfsk5bL6AGy88dQErdjt2S7qqML1t4i6h2KG7rDr4o", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "B6TxvDXPpQypfyStf4oYrjzyvWuhP5YVVssDnqRd4Fut", - "targetOrders": "95s6qx57qtP5BMoWwHeWZ73H9TbBe6xkefme1YzPKuVC", - "baseVault": "GLd8DPg3S3xRbTZFQ16Kxc83LK4KRqzZdK9yZVrfGbaZ", - "quoteVault": "Bxj8TsuiphM7kyMo6e3UEoid8J6XMQvAFaopHWwEi3yY", - "withdrawQueue": "4wkGAkvQwndUxWX3WinrzsKSaGefwmWqKH3hDK1ZG86Z", - "lpVault": "xa7PT4BB4Dj1cGnWCp6nRh4BmAbXwvGnsq2XGWzTeyB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GnyLLWcJf6adJbMBdzDSATkEc9gFa1LHyVPXuEuqUNdQ", - "marketAuthority": "93xD25zm7E5z4UB194uCLWV6AKemJxuiznXXCEVWBVtd", - "marketBaseVault": "GXsrBygcPZMSSMN4fPSwGJVQs9tdA4UChExzpDBKk5xv", - "marketQuoteVault": "HYfSY3WYByyp33W7dzyxfwzQVEHUGLGURggd1ambbBwP", - "marketBids": "GCTmWo8C1McjxSCcahP4HbmCLL5w4MDz1BUA8sQQTDwB", - "marketAsks": "7dauaAeyQtkkJafYqZM36pLGUmMAj1Um2nfs2GvCoX7j", - "marketEventQueue": "8YHusPnTqy9WRKx8zH5QHnee3SM5wJEeDLHo8brbUAwT" - }, - { - "id": "4TV3PMXfpC7bjqn8Trgb1B9fea91b3bQWTwidJit9iDn", - "baseMint": "ADj2YoHjZvv9HhAD32orJEzhYUsEBKbgTLD8c6FPUz4T", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "hcA86uTHRmqBA1LiGaSVkkvYXq7SvPjfTnbrojXVKt7", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CaxyQHdNEFmugyV89yv16vma6c5xDeGaqaw7cx19QaTR", - "targetOrders": "2MVHuaoMcQLs92Re6YRJSc89CEacRNu4H4FovhLyKXVA", - "baseVault": "9QZgHCkvv1MrtCCKzQhxJsqocPbSpZzBSyRwCumdq9HM", - "quoteVault": "BHBaDM3JQDEc5GuLyH81n83bwgEq75JQnubditM4mYta", - "withdrawQueue": "72PsyLyg4mR3uGJyEKScwVLBEw3kSziH4EdhkMugJoFZ", - "lpVault": "2sR9YaYBU121XMfPq721QVDSWCzqnq43oD7h8VTtFDw6", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4PRcwv9aGB5qoivMKx9Q74nAgJUpA5Bkg4SWBzTNq3ND", - "marketAuthority": "56c5A933ACX4ch1Qhz4zddo5ceDQQ3zpraNtLBhjGW6d", - "marketBaseVault": "3Uew6mSiEZtYLLHb4CBxztScWaRND2rg7vZSrTtX6xQr", - "marketQuoteVault": "Epe7r23xMzsGVWmAd5RJZCKDs6aRLrV4ksZ6nWwSHfbw", - "marketBids": "4dGFuEKUDeMSqrVUN3bN5G47AFzbBWNdGLLaijBbvdgU", - "marketAsks": "B2Rnt3siGNaXWCPUMd4itFMMxEZHa7RfC5Z61wQ5kwYM", - "marketEventQueue": "D8bQjJXNu5N1SJhh8L1jhLLGUMVgVNHT2uqLAyzX1oa4" - }, - { - "id": "4TwfdKtNp8L2cQjPuyV3gebGw6yrMi5ojkJyodL3JuGW", - "baseMint": "EYDEQW4xQzLqHcFwHTgGvpdjsa5EFn74KzuqLX5emjD2", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BsUKh4x9diADq35sad6597ZYigXqHRqtm7vmMCFkdwzC", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EQMVw9zbCvhWmGMp55oA27v6pVVT1eYLNJsYeoF7beqj", - "targetOrders": "HwvxxHuPtoJCMAEu5RQVfbwEvw99qr9tE3feASRCS1hQ", - "baseVault": "CuWTdGwwGF2TaxuddQwB6yHFjQbDpLLE762yhUfVse5f", - "quoteVault": "DwNodiwvYAXJxfyNVs3V3mzRkn5PdEbHTZKtomLe9Xfk", - "withdrawQueue": "Aw3wBeX9F22ir3ZPE6D3sy26dsjdc1rauXukSADa7txW", - "lpVault": "EcQnAryeVASJ51nDm5cWWkNEEuDYdH3jQipJZde9rHXS", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Hq2tZzrdNrMtDsdXeCf9CrN3aS3geJTEqtLRPyiYRZc", - "marketAuthority": "CQMVFsjqL4XvpdJ4tMFNrqvTwU48GtFwZr2GKtJzCn3E", - "marketBaseVault": "8yWXkDRBUTqdYKsoY334tmJoyCFrApspnkrMwnJKvuF6", - "marketQuoteVault": "2t8kFqWGAY6Btot5VZz2KCLwPBNLdtVMMB62X6zm8PPz", - "marketBids": "DBb2xbhszaYUe74rxB2DDWCgbXW1WDRKevXF1QCMMqpV", - "marketAsks": "GpGvEqz4Bp83UhvfkWK84bMXc75ZRdTcD1qmJQNgDgKF", - "marketEventQueue": "Hu8F4iXc3Y9oJQrxp3yME4jPyGsGEySeBEYCMiE5hm6n" - }, - { - "id": "4UFaDBpxTd5ZPvxTgSGQ4sSgcXdWZ92aSmtBL6gmVkBu", - "baseMint": "MM7s2bggZvq2DBFyBVKBBHb9DYAo3A2WGkP6L5cPzxC", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6gEkKJ5siRPN8o9CCXSupxtyLjXFwXyE8dCrrZjWShRk", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "F27w3Jnk4JvG5j2AHAEeniv3eGp5CAmn3az5yQUwCT5M", - "targetOrders": "FxRhNtqbSNDaLhQz5fHYE7Lx5y3FMJYzuXBUGiVdmuR1", - "baseVault": "5w9tCGcZUkHX7UXYwXJMhe9Kq2SykcYa763GuCSvxKSX", - "quoteVault": "AtmUq9KNeypEuG63n175cg1gAh71b8qJxw7BUe8gP91P", - "withdrawQueue": "C9Ue4To7YcKkK7u52R5UFozGV9UbwXyGoXvUrDqm5uD7", - "lpVault": "FgVr6qoq9RFQJSY4nLXLYF8XcQDGAvkz3y7bALzNwGar", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CpwsCH2NKGTq3ESVTQwVEGjKTnmxNsZ4KjTPJnUYCKyw", - "marketAuthority": "Gbf9scVxFKVWHGWGE2LUTn1i5KqQhDM2XZyr5KkFA3ze", - "marketBaseVault": "BRhBMa5gusV43wT4YV8Bwy3gZ8BgXr3cqNDbvE3xQadV", - "marketQuoteVault": "6wsJW4QHnRLfQ4KSNpuFCVR81QTvZiHjT7BC75vdaUdQ", - "marketBids": "H98a31BeYS5vactxb4qzEMXWcUgMbSgmCLPpSBf9JAtp", - "marketAsks": "4J2qDHyenND3KGF7GtCSDFws6NrbfkxmteMzUZEVr6ey", - "marketEventQueue": "BpQa72uMhhDRhe5v1gap6NwqTRQSF6xa3dV55od3k9NY" - }, - { - "id": "4ukv1PdbqHd2S972dXSHCcST8cFN4ZzUsYRznnS5JfZ9", - "baseMint": "8XkS7ZDPR9zXcNcYR884tBScnQRyFcWRb7WcLtCR6zEZ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6ZHzLNqJdgotWWVYnFduY6C7oWYyiWsoSuRUMMp9kmeY", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8eEY3VspcnnnPJrZDT3uWCJ3VgeWHqcEMbKMetzGngD8", - "targetOrders": "725mo5oRh7oXkyoBc3srt3oAkppocog3GuxmJbFLB84U", - "baseVault": "78y4J23emAsZMyMekZdy1NimpNA3AuDPX8ZFmTxWCyXw", - "quoteVault": "6jeJxPH6vMFGNC69g2L7ijHDgGuxV1YUVDHKrSH6D8e3", - "withdrawQueue": "Dudj8PBgs1AEzjEyZMTJ1tkmzneEcaTrvFLgLVSc4kVH", - "lpVault": "AfVm1kj2NHfwJzy3HKek1abbfFJn1BRytvxa3f3pxtPC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CvDrvPiQyDH1iDUPaaU7cuCTb5gSn9LqCb2HAWeJDvaJ", - "marketAuthority": "C4erFLZayjmyP3EknxAS7fUEjT1gropQAuuekATsaTYp", - "marketBaseVault": "9eko6b94vRrn2CnWxwjtRmoYkK4Cacd9RbqmbRpHTidn", - "marketQuoteVault": "HCZmssgjdDCAHwijFxgCm5ERaN31d2ioJp1HncX4ot6", - "marketBids": "B8Zsvx5vrY8mBQhNCe6nm61HrUDJ9LnBhdVKSduY4fnm", - "marketAsks": "BvW45MZub21nBe9P5xu1ypHLoJVyHeWhM2ap4MN8AVas", - "marketEventQueue": "3Y3QY7RzxfvRBdZQGDfqh2HTiVsKabcEuv5KMedRD2Uo" - }, - { - "id": "4VhwJCWb4rQHf5zL2RwBY95buW4ifMdhU3LeCWtDxV3F", - "baseMint": "DYbRXaQcnj44SH9woxvyFdtcKkSoPoCEshRTQDZSjsBm", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8kpbrXU37e87W1yXy1ydJxiTYGpHwoMSVcG1JebufdXq", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DScvwoQcW4qQxApwJgMUr5KQF75qNPjXHUAhJXzNuSYD", - "targetOrders": "HUvtffXem6TRCYAjyncwU9mWWGp5h23rF4Cvg7GjC4tT", - "baseVault": "9ZKCDbqR1DcqfUqp4ViQbqfBMRpbe2s7fA9KJnoTMFYJ", - "quoteVault": "GAjd7HLhU32ve4EXaQz7zpUj1sNXPMToL8me7ijHWXsr", - "withdrawQueue": "9M29ZPpW1YhguJXAUJ3jZbPaBCyME22dY9cbc8nTLQ66", - "lpVault": "AtUixUWE4HWryCHUbPaEqCih7nB48GyiN1tZavamsYnW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3R33PbQMpyvMuYceKx3xsLFVLJR3Szm9oBsPKBNWD21Z", - "marketAuthority": "7WmCEJ5vSyNnMN4PcGjqnthL2aBmWkpLK3uxRa7dnLt6", - "marketBaseVault": "CQykNYRkjYpJcnN1X63EUEJ2bJsAQy7de5BA9oi3STMi", - "marketQuoteVault": "9CYYY4cjUue8bcqAabGuUf2SD6zVD23eovTQ12LU1u5p", - "marketBids": "HV6DwgECSCsBqyZZePY1iKna5H2m2LTA69Hwpf7BAhQt", - "marketAsks": "G47cSyyZ62yxfte7W9bA2LEAvCyswWyUDZ8g8bSwkW6z", - "marketEventQueue": "Ba7z5bSQZ2PKztdpFsEGTMRpLaCP7Yyf7GESCnPTEHJg" - }, - { - "id": "4vxrs1ERieqNBN3rGX23TY2W5x2vDCLcua7LZNUUKHWM", - "baseMint": "DrogoV6nuMsCGfhqcVMCVxGZASajgXoxN7ytUcRCQgQs", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3ZkNjUxDyawqWQG6o8Rf6WHNXA122J6sqSXCwC2d2Amx", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5XARYisebeNbqdwHDykJ4qbHPs4UDsiLLwDXxFA119yo", - "targetOrders": "CMyybomfNuytRFTPYabxWpm7fx7GxVWEuz1Kp4mo2bge", - "baseVault": "7eoajx96v8WZcbaejeSWwHLb2iBsvdsBgMfbjWgEJHn", - "quoteVault": "9rmCDLzTWjbnbHNG1WeDWQTFT8oYt5MKVfvTeGTCkC85", - "withdrawQueue": "2rwBrEzqL8H1qyzmpBx1gzMfKzxoU2TprxQaCGZzSQoy", - "lpVault": "84BLHgbbYhpDdPkegTNQkw7NT1KcXZ55J52yT7FjD9Bk", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EvcVuTtRSfKA4qX6H3nKgJBxNCFST8y8mySubVwnBc23", - "marketAuthority": "DvNoindEojVbCZLBYV1WhUBRojS2M9QWdxxPBoi1YK9E", - "marketBaseVault": "GmtxVMAbMpFb2YA1ZyhcsLRJ6dmeeeNheBmfuRGkHQHp", - "marketQuoteVault": "GEuLWLCZs79UGF6FJrZoyPBoocKM3uz5f4tniKhZUH5n", - "marketBids": "CxTaGAU1vnRibxEBCc1xU4rEGfiKeLg5KsvXtp86nA8H", - "marketAsks": "CMKyv9iois7s436gLoZLZgb4F4RtgTbkHDXyV5ZmPqwc", - "marketEventQueue": "BB5FH8odcu3QjB1qWjKFVhVBmP2hQeDzjJSWHjB8VkKA" - }, - { - "id": "4W9BeAbMBQnnFdBbVxU5fiK2jsauJhog2pabPExBmVQX", - "baseMint": "HxPoEHMt1vKeqjKCePcqTj6yYgn6Xqq1fKTY3Pjx4YrX", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "GFhuDHMS4roDgCTBQ5ywmkSeVTdgN93FwjanbUUn1JFT", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3Xe8C88NA2B75cUAnAe6afsXtsg5DCgnLdeWy7bz5ds7", - "targetOrders": "EzQTRNaDVYukf6gH5khRXcErX7VTRgtxUrCVpURHe2PJ", - "baseVault": "AUndu2tP6obZVFAtMXtR4FLigQ6jVvrCvpkk9pHQtBKA", - "quoteVault": "TBxsQ3xvCQBJcxN3LzAiWD9XTXsc1XxoRtT99DMUPeX", - "withdrawQueue": "2jYohQ4dhkrvMTbjGoXAxXS2PAowWxapSNNcHpoY5eBi", - "lpVault": "4bR9D4CpU9n2BW4WX5AonGcSqzShqi6AZYRhUE7s6Gt9", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DtLQ2D3L3c7VWJVYPiWwBFapeXTQoGjhmJC6dxZBSzAo", - "marketAuthority": "7WFDVLwLBGTgWvnVaDbzc6xXWoyTBVfYTgB85XApQyYe", - "marketBaseVault": "EsupUn7wtR4RoFNvieB8v9t3z8DCQdKEFHCSihgkhyat", - "marketQuoteVault": "7jZ3B95FpUMZRBGwW1VjZoGrewde1DyG6jDNoBEt9M63", - "marketBids": "8esNUX6NVVVZHUcbPziLMKdfGUDdgs4vuU5nNSGHohXo", - "marketAsks": "Fmd8V1T9xAXCQjQgKGG9s3M8rzW7yWg5fpATaDDwd4Lf", - "marketEventQueue": "4QhJjrYSe5Y8pP6Fzuj8bg2xm7xN8zyasNSAF6mmpguF" - }, - { - "id": "4WoLaP18gBn4fjLDUPMt1J4eDdb5CgE3KbmGKi3jKm8C", - "baseMint": "woTu6cugnrEw6tZqePeXrHGbSJJVsBdHgmQwxTER4R3", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "ERg2SYSr5RFHPqfZMQAPwUyskGQqr2m6CpEq2vLS5QoR", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GmwgQwvhLqGvmV2XKtM3TLHcEAAg39xEbf2qY9X1G92J", - "targetOrders": "72u38DAsbzgRmkaL3yGG4B758nVbxcx4q8eHrm7MKRDL", - "baseVault": "DggVtNRVMKJF8T6pEmE9SVS3ZNQ58CbwuaTwWTfgUZo", - "quoteVault": "9AB3ysxkpyEPxgbwnBCPq31RQcTDRk3JV7oHrCw35Wy7", - "withdrawQueue": "A8vsvCu7GxhFWa5T3D3n1pnWdkodjyHmTZh3QCTUCZxx", - "lpVault": "Deo7xQ9GTHyaxFPxVhaoxqURJxUXehmj96HagFgXZKMF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6kMQN3cTHXKG2cH9Jn44QGqXNdiSpXfQEGKZwMDAsa5s", - "marketAuthority": "FZ5HHvwTWyqREnaeSnGJGvJJnJV1MZ9quSCBJcMcH4E7", - "marketBaseVault": "FxBjJLrcgD6RQQFbxM5xGJ8rBPhSCPdqz6Pq1f8jxZf1", - "marketQuoteVault": "GMBKh6j7FCKqwcPebSor7sDWkMo8ZaJWvmc4sdfdtzQZ", - "marketBids": "5ywnhgedSe2VsbqTFTone95nQjeCH9hs64kkJgD6k1TT", - "marketAsks": "7sGfyjeG2EL46zbifLp3WBShXpwV4Mc57fVQ4ZLLvpKp", - "marketEventQueue": "FKB4i5wbnn917k13pVs1W7fL9LscHC5au68L4twXGQnS" - }, - { - "id": "4WVkYKWFhR8Hq7WHkcGCwbHVRFnnH9sN5Rb6HRLZcRT2", - "baseMint": "NpgsBSfavf5hmUeGQAbMz5pHDtXhn9ZFNRQypTr8Tfv", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "34uhQdAoHNBfa4HdkMcm6Bg2ypaPAHncoqhgCWAHXSNE", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7PWpdrSgTxmiwUP5SGpo3WgphvHex9eBBrmvdyPcTuVC", - "targetOrders": "EsCDNeHguB1ZPEQVhPkUhTmU5m7egA5RKQa7z1LoPZqq", - "baseVault": "GZdcKWuuVEFHXk1ZVfhePTMwugSbho8CnUwKQ7cgRabE", - "quoteVault": "EhKMeP2RLZ1QNeCopocHUJf91bsPpCAABYJZYmW1ZiKM", - "withdrawQueue": "3WYu765HLCHSgeu5PxGn8P2oKypXM2UEeLr8kH3jPrhv", - "lpVault": "6JCTS2zxvhSaJ4dXBFfmvYRnAtj6bbLdtgnPAivUNnvt", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BNhLczhSRtpnLNHJ7VJ4u95vebDTWvzx4yFA4tJEXPZ4", - "marketAuthority": "J5SSPnTB8rGsKXtoJsbKwtE5V95jZxYC3nX4aDuNiQKf", - "marketBaseVault": "2TNnWxxvQ1rv5UdAcKXgedGW2mwdyaXCG6bnUY3xgFrq", - "marketQuoteVault": "7Qs72FJ4uhb9SJQ9HGEni4uTNvaEZfAEgtJTK9HarXvB", - "marketBids": "4oiGLttGPMtfenpeUQAa2eu4UqQZZHH4v22mvN1qtGv6", - "marketAsks": "BTXnUHsPiy1jzTnvR9ahbJ9TZFC4VDPxqFEVGDYvxkrU", - "marketEventQueue": "FigCpqa5KuG14tthRUcJTjiJSzyURHV5EVnqYGJ6JbaU" - }, - { - "id": "4xGAMrNeXWU9jdQb1GNSLzV735naW6dGcL1ytnypsNqm", - "baseMint": "B9LtfDZWWRrihYu8jDN57thcqqi7xfWAvj8yq4o2YJxw", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AmHkoHALqcYZPQhn68YZzcLKqcVnoU9u41WyBPaw427G", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "77VySEMcMkdT3xvyWkmSJKtG638DMW1SeXmDRrspWtx4", - "targetOrders": "HEGKwa87wkkE8FEEvGBBMQmjdEhdTcbNFZa5GqnuN3hy", - "baseVault": "Cv8ntuBq569ezNWMvziTwmNepVV5ViWHsvWrVpf75ypK", - "quoteVault": "3N7EmmdXwmqeWWWk1JumJXTdKfo2piJkPmVnDN4674Dn", - "withdrawQueue": "6Hfr69SHR4piVxXPvERhytsJ4i4hfmfLp6xZx5vARE73", - "lpVault": "DCAwqG7LAiVH7R8g8YGdYMcc16rCsBHuFz3DVqxHAQp", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Gt8j6VzFCJYpBuNY5bNGT8D8QEPJhDSDrqzytVgXMd6S", - "marketAuthority": "FMH6Dygw3UNqW9Q4vSmKKSvJuNVE2yNXdBVBLWqncD3V", - "marketBaseVault": "3GaWBMnzy3fzmMWP7fydLffLFs4ZWuZYvfk829xyr1Uq", - "marketQuoteVault": "GLRBPUZTdkwgpZPKnNJJAdP3xxzyoamqxbCwrs6nTLbS", - "marketBids": "6rDBrViwos31pbszksMEvmYX6Pbpp2mmjN8vZJyErQxf", - "marketAsks": "75xNrBerhMQoTTe8X9Evsseb8rpsSu7oa7hkXH5FxipB", - "marketEventQueue": "8w4pAgPU3UMJjpRmr5cg1LMqBJdq1Hc5QaH2wXQj2k2v" - }, - { - "id": "4xGhhGHBsCDkaZVyDsmBuQp4qk9LhDs7Wp34s9qaUuMx", - "baseMint": "Ao94rg8D6oK2TAq3nm8YEQxfS73vZ2GWYw2AKaUihDEY", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "35Hd4EyxxMPitRjbnwgVQzk4DwVBsAgbKk2gzodnSiBU", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4suyj1NBXwaDrrkg8QySGLgQMM59TCnqJkvFwYRqRzoD", - "targetOrders": "9PtKBD3fDZqt6xdgjs2BwVMt4b7yGBY2iF68QWho5siZ", - "baseVault": "DsLNeZdMahTWLwpsxqA1n5ZpNupr3PBzLxGi6FDkwAoR", - "quoteVault": "2M9wcDzQhzeTHWcksw8keVSCzEyQYxvjF6CKdZu7NTLV", - "withdrawQueue": "4cM9VKSaeDvVWX9hE4ytQei5z3C5BZMuqtmFcwY2mr7M", - "lpVault": "2FhhaQ3wvNf1HykP9eJWxJiTmZ7giJkBopDQxr8CePtS", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2XkDbxW5SFSSBkVCt946vupQqrc17XXJGLDBBN7F9YV2", - "marketAuthority": "7yLUPzA8gHfp6AkK7Wk1S6m7PEnKwLqusZiqWv9yd9Rj", - "marketBaseVault": "GwVSwkwjV1iRQBEnwseCvh66iJ2ogiten9ixuMTeGGrE", - "marketQuoteVault": "E1akmRTTQbERvV5TbBmunQEHZiKBP76MSkUevKEPme9R", - "marketBids": "5Z7jWbJeDGsMNHUyQSBYrKq6ezfsyGY3WkBYV1DTxwtV", - "marketAsks": "GokEzo8WK326mz9AACQyrYuHtucZ9uNjjLfs3wJpGrTo", - "marketEventQueue": "Cgsq5yC2uAjGMqLx3ykQdAAu7vH1yKsqaej9koQhbeBG" - }, - { - "id": "4XhUS3dXXE82R5hmmgfZFkPdvF457kJfWssFmeXHN2bA", - "baseMint": "ApgNFHXMsY9qM8yaaSVzqX7xtbKkGjgo64NLGuf2hQjW", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "H1h3TgNaURKAZ94fVKjoPcnxYXbCszZg2gxSyHitoeXr", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "G6GSVuzceN1NmkpzmXezVZkukz7jopgLmUChpjJ66NF3", - "targetOrders": "5pLaopKMrgXTTpkbZy6p4M21eJfjfsMdPyWyrFFaQ2W", - "baseVault": "3p6kRHyQa2h9vrqBC1Pf22deM3f3rQs567gZ18qCrQwh", - "quoteVault": "5SHgKvFtwHuVM7JHALzaVhNHZt52wmBc3eVejPCu2SQU", - "withdrawQueue": "CjmYYb9BEKAdeR9rNTrbgj378fpB1XzkcheezJ4xHpTk", - "lpVault": "7ReosLJg9h8oEpmLrxGQd5kdB29uNJBmCr3NVM6AYq8R", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HjAopkkMwnayM3eQURhRhdAT3VHZfeDvXB4QVWJEd2jH", - "marketAuthority": "61KZrubiG9tGAMREYuMC9RXd4uotBRaGpZXGpFoQ2xTc", - "marketBaseVault": "D6vyTpxa3REvDdK2UEpWRtb8FPHAZMvBrsSHYZXiZD2K", - "marketQuoteVault": "CU4eqsNBrZGyQ1unSj8pnULAWFTqmJpufeH9XFzqsVVs", - "marketBids": "7ZXYTyLvCNVWhwdSjqHp7Zk9EFQwQssweN5eS1oLyJxn", - "marketAsks": "9dBtL1BeW7YpGAK3wvvfrPGx5kAFU7mCQL3tDvYxgpZS", - "marketEventQueue": "FQCG3oDzFt3nDLt93jxkQWV5kXy2TdGrUTcsjaSciMwD" - }, - { - "id": "4xKz9MngqEkSyHhujraeXSPGs3rEjSsW9gJHB1c4tMqb", - "baseMint": "4onzDs1X6ubktirorHB8iYbve3K4bBtkGpYehqzGm9So", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EFjHZa1kGNYrchrNGbA7kLyx7UVAppM3e3g1wSTZ5wx2", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3Ds8BSYE2ktHJfmWKEwRrj4T8acRrXuyagT2NBz4zy9C", - "targetOrders": "8hYQj18982FFf89Wkh3SdNRHVsRcavKcBqP3zhpPErH9", - "baseVault": "GaoRe45dZhf6TJQeTt3nR8jnPCULU3t9fKHPHGivRAxY", - "quoteVault": "6uQETRXbqNYAEvK4vh66QSfC5kfmUx4FsJtbHKyqVyHD", - "withdrawQueue": "Voets9FnYp7KUut8eqcrtytRqGUqFv3GNHUQyjRm7ZM", - "lpVault": "5EYTkoQCRTcrt5KDthA616nhv3YeYV3sbz3S49DvqfAs", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "95UkAoB61BmjGYPa5RJXUeaQTCBHfMzYjJXHntNmfp5v", - "marketAuthority": "377gmjZXze8TKc3suneGXgMLtCJfMfycJoEm4VWSqv78", - "marketBaseVault": "BuAqaY4Rkj47D3m2t97AZpXATvpmekJfFsfgthCrbUBV", - "marketQuoteVault": "HrzxYQXA6w3qarV9rwz3AtYsHhN2JMekqWiHJjt1p62z", - "marketBids": "HcskM1cgwuyqdmJLQbHaw5irZPvC51kb8VRhezbLd8Ex", - "marketAsks": "8JCKw47Z3oW2XLeTfReD92eQqu2XgNs5J83c8V1qAD9k", - "marketEventQueue": "Aha6FNEByyRMZDupU81JuALBjHMLXg47y4VWGf5mFEwE" - }, - { - "id": "4xnrvWCgkgNp8FM9oK5zYRts26cENyv9iY43jzsai43s", - "baseMint": "6PBE6LTeDbnP7Z4mAJNNCAjaUwa2KQFSs3xPihCded19", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FbXUnkSbYv633NN3FAFwNwfEpNqpynd7AsikZVCsgzeD", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8M472oJJ2147hhjsfHoG2qnS6LkXqnNTeTWoz9VHS3Yx", - "targetOrders": "APH1Q53F2r61tZSZUHaXnzQjEayvUR22AoWBQLDm6Rua", - "baseVault": "FT6Fd3Ck51mGgLzcHoBYqeqVjZmBwi5tXKcrFzXTXwPv", - "quoteVault": "EHNe7HAAxbLfZZNKQcxc6k94FBiJTdqptkfjhioKzwhy", - "withdrawQueue": "GhpLTT5bnr4BVWKegYoSRzosoSb7N3no6fvr16pFGJdy", - "lpVault": "3evpfgbmewja2JLGnU8Et2cgHyt2VrEE14X2mjP2PCQ1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6eCbAjVBj2ciLXPAiRhYq2AwfhyqxPi5rBGgGonY8AoR", - "marketAuthority": "7yVmbS2j11L9xhvcNhbizi82pm6M1rJJKnX8Q9P3sfZ4", - "marketBaseVault": "CWeLmrakzy9VTuXFKq4uzziEKXe4o4qrwsTt4gF9YBdT", - "marketQuoteVault": "23PQVYDabfvzFqik6sphBk3ycuwzkVZXckNPyBvepoED", - "marketBids": "3nuA8Qjn16iCmzz5eGD7afsCNS5DPx6DiYir8xfh4qjS", - "marketAsks": "CdVWA6dDU94wYkX4GTxKMWd8c6rtr26N4c1CHsd4UVj4", - "marketEventQueue": "Ae3gmDS52yzwGTkFzV9qHSxrrwqdZwQnk1P774V7cxo7" - }, - { - "id": "4xSbAxVXqseFN1cpnKZ468J97aHtET3tm9hPLdJfusrK", - "baseMint": "FZgL5motNWEDEa24xgfSdBDfXkB9Ru9KxfEsey9S58bb", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "kcz7nzPpdrQgjnCoiAoB4jLcTFibJzL1M3fMJ2q54oD", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HYJxdZcKsxcinDmMuU2uR65yt1K69qfkFM2XpNvrXTgu", - "targetOrders": "6uGnN1qvcPSDxNKeLDoFTu1GJj7EWhghxyb1EKkj2MJL", - "baseVault": "9y8DWqD4Tcg8pSK6fs3QGQ7v8mDo3UgPGSxv7Qniw8Tr", - "quoteVault": "6RnW9R3FYbKAWymqmFBcEraqL8jcymP4DqANwWgJAaXW", - "withdrawQueue": "9hcSrL9a6541VetGAmiXdRFPeVxiAJs4C7qQYkdBdvaw", - "lpVault": "2ruHzGobVfCMyyXRfBu9oFMn5wSm3yPLnufBX34Bivhe", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FbZF6hevYa8m6cQK5ApMH2fTpFboXSnutdPMn3m5akwj", - "marketAuthority": "BFmbYcpQvkhuttdvZvpmruzp8LiYTZJ4VM4RbXEwayqZ", - "marketBaseVault": "BvfPJSuHoRFH4oC3hLmehHeMZgkZd1pVQNnWXKSeozvV", - "marketQuoteVault": "9dZZaxLAa655FRtiziuixhYTKtRmSKdeXoJJf7nowS2g", - "marketBids": "FCsGJDZzYMNSBWBybn7pqdV39MPz7JPNsaqyAtWhR2SY", - "marketAsks": "AmgndCmGxDuyWNo58GJrFW5wRCMbXxYh6hKBryQdPT9L", - "marketEventQueue": "Hst5mdWZsFuAuM3awFD3xuvSgKZ5T4A94jkMHq1sk61T" - }, - { - "id": "4xvGQNbQTbCZ6QqsLSLnypMkbpWaEzPdrnNDizSoykLQ", - "baseMint": "2EyqaC7zo6TYEKTebBZCchiAdwmqEzsxLxA2MzCYhBcf", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "BQbVsebR6k422a2uC7kPBnoK9yDCfExGMawt7KRjf2JD", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BWQxSgokswQRuXDiJKSXsRL4QQKohSyuyKjLaC8djjP", - "targetOrders": "9q7EjpBK5A8UNn2vFwuuUTrNWW5wopYqsvBViQJeutKr", - "baseVault": "7KP4Ui5H96se6tsaUoX2G9R5CH5u2h9rSBHCxH16axAU", - "quoteVault": "5uFdcjp2Am1EBk9gH2ksgVo4VhP5SGwVGHKmgrvqSfLp", - "withdrawQueue": "F3eA5jq8RodJYm9uHWwP4sUeP5y5UQP5s8MGPme3rZsY", - "lpVault": "7VQZXbFUVJWESY9GqC2kjQexPx9DGUybQ4Pz6LAA2Y2s", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BkYiGzUUFPtAkKng9M4ePTg6gsGVdeYQXnXLBRBaRxNF", - "marketAuthority": "67d25rmL6uq7ehmE5mowmjBa8zUZdjtXnJfg2vEz2hQC", - "marketBaseVault": "5shjJc3xeK9Xb67agxKxhtR8SpbJx8KMVmwk6fFLcZCW", - "marketQuoteVault": "3hFdwPbywgodBbdnXRJUUq6iZjzx9b9v5GCk2wDazN9j", - "marketBids": "V4ETbkD6nVkDjQpk6gL1JvWVjsbmfPEYy2jZnGF98Tf", - "marketAsks": "8Y2LgRK9h3EQd6YWsSjE4KexfZjnEHtQ8QuSNH9SuMQm", - "marketEventQueue": "8hLz6XrMrb6ufA1R6mWAPZhBaw4TZefsGvNk6VqUv8gz" - }, - { - "id": "4Yp4oA33AsHE2KCaYjRQvqts4wcaY6jobnbUmuFXY1XE", - "baseMint": "CY2E69dSG9vBsMoaXDvYmMDSMEP4SZtRY1rqVQ9tkNDu", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Bk5uVN5QGwSBBgAyGdSnLjCiQQabdMh7ZL6SbYRE2MWS", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "48f6d6Y9kq1STmUXMCX1DKjtTZXn8KyGXmodoFDkiZwE", - "targetOrders": "F68eCSKJ3TrVAiiwLuUXRRerdny7hCEmuWsVJe3AuG5e", - "baseVault": "CEQAYqT4AXaQotFaa4vdXewrSkPM1iZmWCrhBZsCii9f", - "quoteVault": "JCAwBh9W1qGT2iDs41bDeWmgXbufEqsvAceCrzSZePna", - "withdrawQueue": "JDTSB5zEDCaHHFi3MoVcyKmeHjnzQ1e7avhvrErvKSHd", - "lpVault": "AcnGueXNfYF6BaSpHL9aHNM1dxAs8RkkJRi1mJUFkrwr", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EtEKBLqLfPcm8mXn5JdzY9rMghHnTMxpWwsdASasAMNa", - "marketAuthority": "FxuT8GeJhgrZFg8Zuuo12JPspgMFzn89s4m9gZqw2oEG", - "marketBaseVault": "CZFkvhnVcC3GEisX96JhLNcabfjDfF7ABzBt83ZEZbqw", - "marketQuoteVault": "7GTEWLWqFbv1y1ai3QyvKWP75AUutEkoZhAbJyxh9M51", - "marketBids": "4rupMSSWyahhakf84LucX27oVEh9K7aPgP7H4kxD68bJ", - "marketAsks": "7Uvbmz4fWaZ1aZS6gYYfzqpt7byas3zmerY6HrMLa6zW", - "marketEventQueue": "2cHtgrsszd3HG8gEj2VpwUW4wXCAhqYVjM3uLbCDse97" - }, - { - "id": "4Yr8CHB79GkuetTkd4crJoddLECQQuhLKVFh9ztHz4s1", - "baseMint": "DfB1NY8Ftv3rDTnyffSVj5sr3ycFjLoUeNBEkTDvPQYn", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AzpJXtiwKxocF5MRfVAzgBdakp5bMUTDQjSRjL36HWNa", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6zYTcS7yDfZZMMEYKEWBNrLRbyr19r5koyZbEjYpBuT7", - "targetOrders": "CfdaBkJJ8WFvaUqjs13TuCukFxctTEEZ4SX1qnnMKwq6", - "baseVault": "5u4866um2aXZiGWFc4C7Qu9gBfJ3K6EjE5PyHvykNBn4", - "quoteVault": "BZPuo4fiUqiB6ZWLhSzvqFzAkNWwQMuNFPuzhK1WAUJZ", - "withdrawQueue": "3K72N7iNUDg3TMfxeUJXmdbYrds8RvYwRGPurfZqCo1J", - "lpVault": "8sRv9uxui8PXEjpoam927C5PoQfK6BiDxTc7KMdjKmio", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9fViHtiJMmVn2nwRBPcPNrBkzmDYwGNa64J74GGm2ScZ", - "marketAuthority": "7jwb6S4TxLbZX8uYhm3ngeXCdMjfe7GnQY18tUu1WrCZ", - "marketBaseVault": "EXLFJRfsP3oYJPFp1vbdRVspRJVXJSD43pP1GvckHT1h", - "marketQuoteVault": "EmJ1Q7oTKi8JFimrwLXtA4czYbMX94hUcbGurM1Vh1Ki", - "marketBids": "2SX2mq2Tn4G1TPG7Wj2WwZUAcxswdF4xRLZHgVFd8BQU", - "marketAsks": "BJ3GKWyuH95yptQLRva6ipR57ZZyky4vPBsoX7tJRM8V", - "marketEventQueue": "9sknZGz2s1VxAq7WaMKqCEiJnNF5mcKn54w63Wyj4eUq" - }, - { - "id": "4z2miJAhhTQTUSficTixpBA8ZZLKXxrjqHPns3BUTBuZ", - "baseMint": "BwRU49p5FWwXvFqUXjbQqbnKvgpymxQKTJE2tQQCgLzJ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "681o5muBhdE8ss8Nxq2smcoJwQJ3nUu19bp9k8noMkNs", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8Uo6QAMbGsHUGRNhnoi4Hui6A6KKLpgiJqUZyZE32eqn", - "targetOrders": "DE8V5BpwGmQmaJ62hpw8U4oSbxn1q3coXTNSFBgy2qYe", - "baseVault": "6dAW6EnoQRuiohcVBm4FF6Vmbuf1LBu9svjvGbg47nAo", - "quoteVault": "FNeHKszt1AwXEfA5bUbFz2Szyh69WZQJFf6Xo3G8iQFy", - "withdrawQueue": "A7ahZwG7Q6oYD8PV2xJGeYR3J7C3ZWVLzJQ6XPg5X4gC", - "lpVault": "5xBS9cKaH8uZMUWymCSGpA9zT2jmqnEC2QkMC7TCe7Zc", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8JDaVcNv3e5sBx8imLSuJfbn3MtGUPm76fc6QiSoAjBs", - "marketAuthority": "9ruhL5EKyMPhQM3ropFvirZW8nxQXgc43RQy4KrrfsWc", - "marketBaseVault": "PU4HVrsAZYah49MV8LnUkQ1yQza5WfyVQGQPm1rNubu", - "marketQuoteVault": "CCKcRynVksUVRX7FhLvM63kwxfhGMqkATPdUhgYAtUPu", - "marketBids": "GYMnzEiHGaAwtJCrs9oZeKeGNAWqqvgKRtgYRHuiv417", - "marketAsks": "2hTrqcC2yDF5NuaCyNLGmqmUV1qQs7T9MwEZ7JUNrKVX", - "marketEventQueue": "8qyFUXHE8T6Dm2c5jPnM3QmW8ei8DKyjYSSwDnVxwW6v" - }, - { - "id": "4zi4prUWWvMDD2ocjGzqWxdaUeRqGivt3A2YvjkWqo5B", - "baseMint": "3NcCuwvTMnnf7TU2UEVhp6v2nzbLXQiDgzQySS6m8A7P", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "AMc64AhYZjM4zD6ScVi3UXANWtzNdmteTBHJVphJr5Qt", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CPS4f3NhqTtV3w9gmEcmqfgVdsfV1po7EXsXpomUrpdp", - "targetOrders": "G1f5qhXCFSAcFsCncuTex3PPnAanN27C1oXr8JQc1J4v", - "baseVault": "AvAfoEBa4DW58HyNHHM6GzXTU1s5dZWXrywNeasfmGFR", - "quoteVault": "8GRAiRg36gi3dPbtnR6pYrv5WGTC7rvRRCQ5QooDLoPW", - "withdrawQueue": "HJvr69VeDPYob4G1B85m2uBLz5ad6RLiQ9EFH1YcVvd8", - "lpVault": "G3r36t7njBtb4VGoSvfDp3fD1d6TYGJuR5sGdjoxhJgY", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4eo5Wz73aQ97uvEmUDhSG6KNFj3MqXMSTB4H1ERQVppG", - "marketAuthority": "92v5ZwfXhCxiNb9MzR22TQ7aJVAL6MSMVz5hdXmCUUdN", - "marketBaseVault": "GaoSmc9ZoBJsV1FH6FZRsUcV9jqsvLCmww6NfYoFF5Rz", - "marketQuoteVault": "Cuv6Fnehyg1YpkjKAjcsuVYg5hmqpaxQnzKbn9NFpYER", - "marketBids": "FUG6TjWoV2S15Gnzv6tYSqEvRjbxKzKBQJ7YrYbEasGC", - "marketAsks": "D8v3bdftarh15Ly2WzGLQknz1Dg6j1FQERWjqv7NuEwV", - "marketEventQueue": "DJKyuuvDLptZJTQKnmxw8jADbVceM4LkT57N5ris2TAU" - }, - { - "id": "4ZL3zToZT9MnvXWPuSpdaU3bU8HH8oDStoM74xUKqvqg", - "baseMint": "EK6j5Shv99xttoT3F2DfG8uQMoX6NoAZgTuYwCvrHzqo", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "5vYmbNDW33JMpqVmHvv6XZGxKko1P1xT9tiNpDSX76K7", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HTSdS8wG7ZpZy4CoifwrLdNXpChe8pqEWDPDtA9hQa7H", - "targetOrders": "9VG3rhoiy72cqky4nTX8zFmh39jHaa2F9HbKymb95SrU", - "baseVault": "J547iCSSJnoFQe6y79nCZoUWCGcm6qPBuo3YHCsHSQMn", - "quoteVault": "9Drae3fpJEUKepqg1nmRYRvMrvLokWZtZdVrNq3mQxgt", - "withdrawQueue": "EQcfNmx2KfrL5h9Pq7kWoipSLdEgDJxmHGGMKFMwHSVQ", - "lpVault": "3DukKhFauMWaBFmH3ZvgvYxvCgE66LSs8VECc2YBjdkN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9SYhuh1kUVLTXx7cste8AhGqgNyuDGEdjUBczcrUkU4B", - "marketAuthority": "2r5YUp6G2WMtAaPx5tmAfegCppReqiABTR3TMzydBRn9", - "marketBaseVault": "6xGdFp8DZ9vHqBSFW9YhWth4jcBSh5wAJnKQJLA8Bh9c", - "marketQuoteVault": "7xxJDADQ2E8Xwzv1XphtEuLQzDdFR219fGrEkNjZvukE", - "marketBids": "CTFk2beNvy8gGdt8yxkVCenDVeaiGJuADifouwbV9V4p", - "marketAsks": "8HmFwEUucXwQSPu5cbD9HJ7qFRs5jhGt5GMRibUdBtMx", - "marketEventQueue": "AV4SpVvesFav26cCJAqJ7pLGvMBcnbBw2yLCxLp6fbXn" - }, - { - "id": "4zN8W86rAHg25q8DiQANrSHiHG4VEgpsxb1FfVgwJoEB", - "baseMint": "invSTFnhB1779dyku9vKSmGPxeBNKhdf7ZfGL1vTH3u", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4PtCFaFx4rEvhz3nEEydxAfXyfDqxQkkm7ex5dTqGxpT", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6Er6firBCACiErmE49M3G7g9RWGyzH3sdR42qcL1TbzR", - "targetOrders": "cYkTphykQU83r45hz3F7Lnw1jcmy6VCqxspETqncKJJ", - "baseVault": "DZYepcfamusJGHvtgcAUEcwYEPdZLuhKKNEpzkN4CUMK", - "quoteVault": "67QfDKGxniehygMsBYSfDVKAMPCQkH1hApTfkSUyaP3M", - "withdrawQueue": "5XX8L4sZBsD1cbJ8pvUzDoRwhYND4QmtLrakitSmdeBh", - "lpVault": "BdamaUqHKsRndWwf4FTYbJGx3fYMunHyyVPxrviDDPTe", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BEELeWZWWDY5J7QrfnAxkZBi8kZHoFBn6KyrSnv7TEDp", - "marketAuthority": "HtZsStAT86LtizjnJRAYdCJGHb5RZZXDhPcRkbA4Qk9n", - "marketBaseVault": "GSZHbqbDZSLKhkd1JgeVSMJ2gS3oYueEMYgapM67vUFT", - "marketQuoteVault": "7vXRdnp2E1dRx4aS3AzbPc8qbtv4d1fqiutmveLYMnwR", - "marketBids": "C7WsD5EUqhzzrnaS3Ei9awdWAxw1JhnLxpxDrr5uAsoo", - "marketAsks": "7Q5Uco9HAbTfJ4fJJR4dm4nzxfctGb2APr4SExUvukoA", - "marketEventQueue": "G455ESRKCMBFCMpt4J8zNpSUdchAyqTgegG2C1tWqNYD" - }, - { - "id": "4zP2DqFHxzwgLf9g7FPgn7XhPmEn9t9rsTZ6VYFBJ87s", - "baseMint": "E4oEnayacCpyKLQQeRqSm8bG5wPqDMZuun6fEXgoLNwF", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "EziHGWZHer1ccYAynuRQwb8etMFaVTL2uLzEgVsW2eDQ", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3Fow6mRf7cLYMxBNdRGebiYeU2vTpodVjQRiJPsiq9tX", - "targetOrders": "imbri9MjLNUF9gyPzSg4UCMtLKBTMKQ5ZCmXbT4h4CV", - "baseVault": "722UC5SFbCa9BLYgyasSoyNnxZJiXK9gESKTMYsieL6E", - "quoteVault": "EWgc5SDbivKjTchZcBuJ7h6RxCKmvH5jZHyKpo4SAc8s", - "withdrawQueue": "68fvzpbNPRMQbHCRPEHKdG34JQGt5Wcz1M6dzPSCgKFo", - "lpVault": "7D8UsdrUJCYXAmR4y95h3V7m3ukB2aKzHmS5g5KqZDsL", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2JMiiMwUPcoQ58h4DTveKsteE9jQjdsTZaPopNKBUT3Z", - "marketAuthority": "ERpGuGa7gudR7aJqw7YyXjZMuYhYgiv9dDzvJzNMi5BA", - "marketBaseVault": "6pbssWtCvkZZW36mipcHzjHvgAcfcdkeYVuac8Ejnaqi", - "marketQuoteVault": "BTwBevdyRtNp6hjHsyypcQjpip8FUuckndQQe9AxSJH1", - "marketBids": "4qzaAPjvkuAaYBJU4T5Qh2SrwL4QR83iKN7Q1Mi1EuJq", - "marketAsks": "HhtFudGyFnHwUE81Nfeoz1LEKoEqSYrA31FUCUKb9sDh", - "marketEventQueue": "3VqxFxr41FzU2BTxeXRm4f44xeJFZb7h1fZapos38UBs" - }, - { - "id": "4zSRiTtg14n2aes5k7VPsGbf7j1QMtgeyPbSrNHxcgFx", - "baseMint": "H2rMQMa6kPpWwg2GraKyiiPwnayDBoBNg9WNVuafqXKc", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CULbnGQVYo7Ko13aJRLJrHcMs4miR84CTvBo9gutkY9V", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GDCfZPMAHa3HURtijf1hjsn2UMCWhiJ56e2QmgqqawUv", - "targetOrders": "Gdq6AhJ4V833ZDghmMUezGUtu36s9vWTtrR2TcKYawhF", - "baseVault": "4Lmgz8rmfWZaNgLJHmYChEs7x4uLBdqu5wdxEcC3u8fU", - "quoteVault": "DvFo1mbkX72MqSadqZZNbqEWLnPMMxMLqtMnfjECirKL", - "withdrawQueue": "3VudVHR7yucGV1nGXvBTN1Q6SuC3rqkdYipqqqRHiLMT", - "lpVault": "G3NVVYqM524b1NXvAfm2LwqjLRF5FXA7jXsTzmeZok5n", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AGaZeEBmv7pPosf89tEMAfKaCopTSdsKUbAmF2HxBv2z", - "marketAuthority": "EpqKjRHpsucgKbuevJdybtoMWxum1CzP5KcxmxdKPHug", - "marketBaseVault": "BSM9aKxnrVyNwPVa9z8Wkw5R1B9DviWnFqH9pWCHL5Ci", - "marketQuoteVault": "FdsRo26z2k26tAvUNTf51jsYc3pmJQnGc5PHJ8erqqAS", - "marketBids": "D2chfypcvCmUiXewXNUwefHuU3o2ykCPHTa6pyhTJzdW", - "marketAsks": "6SyNyG1wUbqMpPEgUfueAWGHDLzipShCuwz1KNunoVSs", - "marketEventQueue": "5qwEiMzDY7mpZQn5j4eVNHbuksQKDyPnM6GP2xditbse" - }, - { - "id": "51QSAAwvEpm11fv92F5xGkR8AW4LyMYdcSP29qgVAaAB", - "baseMint": "58yYYVT5FoVx2jtvD9xtX4JxE8jogtA5tjMkJudgERMS", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "26qXNQ2wRfLVem4SeAkGSTZJRKtNFwp8RHK7uaBM82Ay", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HM9YXp3qiC6uTRtqmNEpFvLYUw5NUCPr9pCGNxKopC3h", - "targetOrders": "57jv5m1fehd7SNapp3vhhaNPRU87RYfse7GwW9ap6yXf", - "baseVault": "Am5Uf31mBgbyVuVBT3je97J4mtCSETuVaJcfxu4C5Tkc", - "quoteVault": "B9YnWRNgboQVqKY3bdJrq4GzmqoB2XdpwReRKQhuNXMP", - "withdrawQueue": "6SmWh3q65C11gnbGq2JmHQypHKUuDwukcwSZKM1WSky4", - "lpVault": "HVCZf1FV3K7qiC3UCvFXAWNdQxsWzHatsfDQUQqohums", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "G16K9HX2BVarYTx954btRuG3Ve9uX7cM5giQwD1dHeAM", - "marketAuthority": "H89vJpms4vDFRBrjzcTLYnCXA4hiZqhd1XqyZNc5Z1zp", - "marketBaseVault": "EZJxLYSLovrGhkdoxCeUNPAzNQx3UYnRviej8N8TS88e", - "marketQuoteVault": "J9QQEX9aFV5Hsu38tbATGAieLrMKDW3sYe2UvS5sawYs", - "marketBids": "4zhoSoeTCZe11ta1pfdTykeqKNPUyZwLphxniSWED5fB", - "marketAsks": "J2vzysGSxVQCRSKhbZ2yimFyd2uCLZPy3rD8N4QKBEJi", - "marketEventQueue": "BmiDTXWxmCf9bBGhGbbR9VsTRRnR1VtbrahTT7u1Dejk" - }, - { - "id": "51YDwiiW8P5oEmHSUgsBziBrvRhYZxibZ5txiLxqriLh", - "baseMint": "HjeHBidBrq2NAsVTH4CeXBL1C4GnBkyoL9dhD6vbcHSK", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GNvmAPLCngGGbYdsnHrE7UhouzDDNGo1c1hCs4CsHi3", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6juxSq18GuvfYPcjVgKvSYqS52UxrRR2XszwXtw7MZhG", - "targetOrders": "n22Nogmp49vFiFqa53DkhCt8NPd2Eo6Du2TpbnZh6gt", - "baseVault": "HPnJnsLFB7V6UT9HpHrshWtzGpx6SGzwMJT1ALCrEDKh", - "quoteVault": "4oEgTXWTnNbNZ6QUm9agPu84c7hdj1L8HvaNPEGhfqs2", - "withdrawQueue": "DzJiMQA74tZwZCYyQmhkmtNhBsJcaLEwZhCH78TY2gaG", - "lpVault": "JA8VJgjcBgd9odStdJvqQnNjmsP2LF9CLgcoup6KfxF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AED4Au4iBPGwVZybgDhNKes5XFagWnJm6xjoY7QHJfAK", - "marketAuthority": "86vnufyeyQdbTVmYxzYauapEG2v5Y5mMvuphSEmL7AHe", - "marketBaseVault": "4fYmZFrBnAZtsyjxqpmLZsE8Hg9rQ6nnnxhGpZR9TjjS", - "marketQuoteVault": "6FZSqS3QKCidV7qis6sCozerDMEnaE62ys3S9WPkgc8z", - "marketBids": "7drAB9C3ieBVR46apak5bQQUvMt7jBZQxy8WoXvvh1sZ", - "marketAsks": "8eRXGsCbfEAV8ujk44N45ZxzKVwEvcWAAb5yME2Nh24k", - "marketEventQueue": "GzW9y96tnrVL3xtWLjPcMWmZrgBZ3nFVg4EpPCuv54C8" - }, - { - "id": "52DTEuGxBoMqCQAe4Qc4EgcKtbXqiSPYTeHky4p2QLox", - "baseMint": "7fCzz6ZDHm4UWC9Se1RPLmiyeuQ6kStxpcAP696EuE1E", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GnaFnTihwQFjrLeJNeVdBfEZATMdaUwZZ1RPxLwjbVwb", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FVgEg4dtZ75b5DCETPVQjkhkNdCFKKrGriV5YgtgUAsy", - "targetOrders": "D1UNgbHCLPmmJoqGitFsa1sz6DRymncHAvgi4MjjMMQQ", - "baseVault": "FUBxj2kgkYhBmJ9mxSZC1BeSx8pX3nRdthgujVjJ4ktu", - "quoteVault": "FVDJiNFWcZajNUZs9ApZ5V4NinU47M1bnmtCMWXxN5LD", - "withdrawQueue": "CtuLWNXrAvYi79N52zhL3EvvDx5d4cUcPh6vq2ZfT3ZS", - "lpVault": "AwrYVRrW1AFLmzURvP2TdxBv8jdErwpRtic1FQbqqT9", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9G2bAA5Uv8JyPZteuP73GJLUGg5CMbhMLCRSBUBLoXyt", - "marketAuthority": "79bxZNFqtNo4osNoeEMhbY8bTwgDYcEV3PCfKPa8WzPs", - "marketBaseVault": "GMdnc3ru5nKR11aC4s5QD9LYC94SfmVtnyfGCbzFzTw1", - "marketQuoteVault": "BxDrm2vjD5SqAXa41WDDuc97JEU3xCMTkYSSRE1hpnxz", - "marketBids": "2JQtEEGw2qFyQT7FUkLrg3wtVGatpmJ8DArKJGKjRoxJ", - "marketAsks": "GkS8hmQKfcUz7zSMX8SLGgNAR1ikqxF39vnhQEhnGxs2", - "marketEventQueue": "7Nw2R7k8V7mP1pTNSVasiEtQL8JTnrTK8VZzBQvFupXC" - }, - { - "id": "52EKfzX217heZf64RcJsLuLxZm6wMJF5NJWAqztog6gR", - "baseMint": "FoXyMu5xwXre7zEoSvzViRk3nGawHUp9kUh97y2NDhcq", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "A7668iTH37XzkmCNDN7UjG2NdaPrUHBv6gXbwrFZLErL", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9M6SqrhuESV2FsEkYt5uVuFsZVZwArAnbLGgArisyL3H", - "targetOrders": "6q6nmFGjfHtMQM9BqmJuwrAU6ix8LCf5MYmbQ3uSuFyD", - "baseVault": "87PvzEuWeDHWXfswie2Uacbk8Xpy1akrN7zBUjFvTNPL", - "quoteVault": "GytL5ueRKQCxGiEeA82HwYSjUBEa6qRth7DNVMS7nfB5", - "withdrawQueue": "FRjh21NR7kqNt6ukmN6GL5MJ5ZSwmvCMJ2y7uPmkhvNr", - "lpVault": "CaSZDgS4ReAK6swU4dp8YTnEAowTZDzu9jbDrmF7xQWU", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2L3TXpA5ytXq8jFC7mwmbvvTNkFJM5HRYk2pvXXDgrVR", - "marketAuthority": "AxFEgq973dNf91o67JtggTGcqMrACGpNt5TEKsa7HDR8", - "marketBaseVault": "GSDCZUHWYdthuKbkuA4jpehjk4U8s1bswdRyfgNB8XSZ", - "marketQuoteVault": "G2TYk8ViDfuNUCh9L5K11GpLwFndKgXAoeKZzLUqSK1R", - "marketBids": "FB7H8CveFSnovZC4w9ToDzNHE87svgNzCTY21e1apdCa", - "marketAsks": "61EGYj1UhZ18cU6FJNi3gtgVN3zvFNXQLjUSPvCkYews", - "marketEventQueue": "EGw8SBDUeZ2dkTUEPz7L7Zg9n8NHMV2ALzeQPJpoaG8M" - }, - { - "id": "54Fn6AKxtt8srBgJcozq6uSbNxSYgJuF5Ur6UJSdHhVS", - "baseMint": "CKaKtYvz6dKPyMvYq9Rh3UBrnNqYZAyd7iF4hJtjUvks", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4EEjyvf1QGcFw4U5EjAy3aNLSSnZExz5uv6SSvTPPTJh", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "32iRWc2ecvtsb5xEe3DtgZe7ULWXJA9mXX9eZbamEwhw", - "targetOrders": "8LrecbgqxGcEpWp5mDoajwJHz2t1ByBNv9XCTXsb1GRC", - "baseVault": "21tGt7KXjXEMeXbmc8JbSCya54nwV7pUyjTtPAqa63mU", - "quoteVault": "BvqWJcWxBEfsnZt1JDaaFtncU3y4mLjmnUMptHp7VBiX", - "withdrawQueue": "HWqNaHrEicX48Gt2YUfRLi5hrNwTBVRqrADrSHyMUink", - "lpVault": "8ts6q2D6oDxzLaqDRfX7zejyhQBS46kVQakC19ZJXy68", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CM1i8dGf2tkAFfKQGuS1gPAaMJmgGgpfCUgjc8oRSrtF", - "marketAuthority": "RWgesfB2vJNyf4a3Sm5Q29KPQXADmBvpNqy1dL6WDdr", - "marketBaseVault": "31pVfRbPE2a8HNxsma4T8bkvUta5xxrDoet9N4nUre6q", - "marketQuoteVault": "997rPwXmu8tNY4VgQV9nXtufe7DpCxaBUqowZqMo9Vus", - "marketBids": "2XLARqjVrEhZ9jfk4wPcLgTt3HMpyGX7LfrocqimSo39", - "marketAsks": "38mv4GfR1bBx5Lc3oLuNV5CWrXDoepGkhEyVWS6heHUC", - "marketEventQueue": "5S2ZmVXpasYqTEX5QazcJ8cgBSzHBENVpvpBMD4LQtV" - }, - { - "id": "55eoKTTzjBY2PzfBStyDQJiugVbzThcsQsfnamcnYf7o", - "baseMint": "Dj7qHPhVGa4JTMETZwbrTY1hdfe4TVbk2b46mFpKqb6H", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2rfFX2FbeKcSbjqtJbRn1Q2yKupUg6LM3ekqxNCrdmjU", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "JAWp5gx8GdCfkSiFUX14rtUCo7vvM4fSHTU11j3qdJeP", - "targetOrders": "vZNAoDa8VUwQqMKTi4LZawLfJziiRRh7iKbiuyQgut3", - "baseVault": "HsoM3sa5JhK3TRvomSFfstsysmiWHiT2NV38S8o81Ypn", - "quoteVault": "9PE7UjoH982nbXu4eN7w3GmYqnUYDKFtiv8Kd38tDZcU", - "withdrawQueue": "2AVaEK483xNUNfmxHjimxYSUwRuRssKsA7fAkZV2yVcX", - "lpVault": "CAhHTDaJzsduAEgbt4cXz1fBxJRsWsjp3Hdp5hjsGLCN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CwCfxXbnL2oZHef7obbPrdwgrsZ872RnDjWEaYyPQh3", - "marketAuthority": "4EqzSRD31wckDS44YHkbYjHw9eQ7JHKVqJ8rmQMUDosG", - "marketBaseVault": "8ssRExNBLh8To9TR7xGK9mHUpf4vLJEzRZaLnvGdbAsG", - "marketQuoteVault": "6ToCtMu1qH3GMaYcUPihQVTtfGZTwTf6wANxBTufGagS", - "marketBids": "FpLwhF4AmCnoor8b31bCjWz1MAj4q9xo6Zc4bpE1ozeG", - "marketAsks": "D91P7sevhDmiS7hfPrYVUoXt3Q383u2BvDok16Gu2g5c", - "marketEventQueue": "2sYE9aSwvD6UQzzFTpJ3gAaeE6nZmCXVkW78m1y1DTNv" - }, - { - "id": "55zFhDXyYP3t3sYLYQULeBErxzUa8zvM3VtgQQzLdVyk", - "baseMint": "82xYSLKQ5xBca6rkQSG3Vjt7T6bGhbiwkUeYwk6NSt4", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2jLWxoiPtfGppsw35xdExkUaCenUU4eSJx1Rwsd95LLw", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "D4Z3392KS48vnm9rpyDruwJKRC1krPjUEgqV6zkPDdHF", - "targetOrders": "Ft56b42yP5x4d1txtEf72LWbDReQjtCFcpz92SAQoMx6", - "baseVault": "J2gpQj9sp66ctHfm61W2XHV2TToZ6BPb46jbiCztXBma", - "quoteVault": "2FKhuUsuCbygGU48ALZ78bqXh6ZKwLEX5ZS7zHvMnuCx", - "withdrawQueue": "Y9DoAr92zfKAQz5oZW3m4qTQ4Egsvqhf4xX1Sw7vZdy", - "lpVault": "FQ5k7P4zCTVMGKtQVd8uGrKCscHdZZWuJRR1W4QVsrye", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "B4tEwRtWVKZTijsLAZ2aaBKnpKXmbomNbMpSz5UhE5zV", - "marketAuthority": "FunwfqkyoTfk3uV36kzcQreTdHrgu5RFMWDjNwetBibo", - "marketBaseVault": "H6JAfkHZQMhun5YU4WiAcArWhjv3rZtC14ZFDGiDt82e", - "marketQuoteVault": "2sbfqrS1BnU2TniEAXWxhPZyF1fjcfUXRZa8uqnxafWD", - "marketBids": "6VqxVGYHJ37mGHMnj21hG5tNgNEr3NogkQknojC5FFhB", - "marketAsks": "HSEFLJAzoGJBmcmKsem5wHQ8XXLUfWTocYxLshUZBjVY", - "marketEventQueue": "GR3ry4H58836tZVnGTR3ESAJfd5AxJa8YpaHs6gXzQY7" - }, - { - "id": "57CUWaWNtkTQYwZQhJE6Q52bTgv7Pvc3PvuRVfEzA3CQ", - "baseMint": "4id3Lrw5BJruX7VQ3iRbmpnt8JHYKEkFd47j9NFgirFp", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "783iD76iPZgjw8pX3EPMiuKeRtmcijF2ySpiH36aZLtn", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8xoV8L7rG3Z7ikjemaiDcLzdmePRv6thkwL8xeanibcw", - "targetOrders": "9Y5KaZo2eSx8WTeXyAMiqN7Zfo9DJr4Dr6DwMijsVevy", - "baseVault": "DJD8PKxdcBdboiKEY3KtgautVNMjKxBExJkNxLyp4ynL", - "quoteVault": "3uWvRc7nAcw1YaX9XgMKrng7WTgPoo4WNC2qDt4qQoGx", - "withdrawQueue": "DKqdciGQ9AmVgVUhC9ruBivksiNz6bRGBvKMfKaNPb9F", - "lpVault": "HWcQ9W8vAWtyBbv6x5JyWsZ1rSBhQ8KCxbZTkP9Jv4He", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "E5KMAzMZR6QJF6mRFXPvzGSLcy2M2omFRuUW9QVNTJK2", - "marketAuthority": "2s3weEJgNJ1wvsQCxvySGSYsyuTkrb7fUA18zrZM1PCx", - "marketBaseVault": "9fa7YsTZap2smSbNapaiioVhzUu68UGvo9ZmPkuQwnzs", - "marketQuoteVault": "6U7rR3QaUyrGfnW61Ri4seWDG16gukfnvSRVQ5pBKD3f", - "marketBids": "AGk2R4UqY78VzN7Jf4PumPx93aoa4U5hKTNFU6hPV8jT", - "marketAsks": "FFSGvBSDX58zPNaUUZGRntXF1zGQjEBdfCHff9ejCTD1", - "marketEventQueue": "FwSbFqtMW222wNF2AWNfbNGFDFRxTgNur7GidVKRTA3L" - }, - { - "id": "57sBQHecBZVxMdHB1pCVNEMyQXmZi7NrxgVRznkDmvKS", - "baseMint": "MEANeD3XDdUmNMsRGjASkSWdC8prLYsoRJ61pPeHctD", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "7xuP2ubqhEzbxJMZvtPqGLKRVyq4KXRKh4UGJmJaJwZr", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FKgmgQbWBpYK2BK8qoyGwuUbjFKyxEJMGY9GWtqcpFm8", - "targetOrders": "7LA5v4Cyws4MYzfzUTLQNVCjNCXa6D4aeiewcE3DsJSx", - "baseVault": "973CQhqobnzUTpc1paFYUjcyJS1jF3NE827wgGtS6gs", - "quoteVault": "V3QS3NjDEYYHNaSkE8nxL2FptztCu6nGzoCWeRejzC7", - "withdrawQueue": "DqFV9cByG3kEwAPBC62UbS3vPCAaGJ3zNfB6pSwYCAG2", - "lpVault": "HGgnEJJpoK6MGNUpAaYo45SmofS7G2VDo8CBu7VGMbEG", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8xniCsRN3KdV4mzXkGqAMwpPZuF6agYxZ24X12x9iFbd", - "marketAuthority": "6xWYdpCxYvniikiGSFyegfW6wEJgyWeW3DS2jbeQ9rDG", - "marketBaseVault": "Bgjfp3NBEkxirvw2uBofQjDppePSDJ1EHc5ZKVrq8RSf", - "marketQuoteVault": "6hQCdV7AcmGER2J7iqpJBo1WKZYdSpPRUg3K2kvGdGdy", - "marketBids": "729h94sRxPdhbcD4UQ7pQGSABVcBdw65UWV1oR4sTYDA", - "marketAsks": "5BTdJx2xoFxnetG8nVS9ep5JSEouZZLwWAsCuMdEFtB4", - "marketEventQueue": "3FBdLm2hFUjLCu3JDhsnRDnMCCyfX8z3KyrNKC7J7JbC" - }, - { - "id": "584sXs3iM11zJNk6pqd57aormUjArNR2Mz2crsKUQmcb", - "baseMint": "HDfCYKD2V9fvYJaAv4usEyDGrwyxkEeKJk4gRCtrGvXP", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "93gAshvXRrAF9gBsThh5G9zmiEJgyW6K4KoJV1St3KuG", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BoPpy5GaXZMTYgKmN2Qo4HAWQ4KhFzytJvG49sUaD3pw", - "targetOrders": "EJSe1jXcyD2WCDGDJRcU3mHWh75wELcchjsYYSgpUzuD", - "baseVault": "4kZL4trqRz7rffMwHGxEYnoxd817SHqJVJhQ6Z4V9yv7", - "quoteVault": "4YZprHu8WKX5UiikgQi9wDGRxiq7hLhWqLSqViqhqXNh", - "withdrawQueue": "Etd5es3RwQpbveXoFRTHQYLRfmdxj1TpwCLwP8bUfu59", - "lpVault": "ExSdJ8X1rj7qTbkbfUY55tw5uQhDim57U2cKkTPFBr4z", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3Sh29fMoGnwarkz6aQxQPkJhGYWuqkfpj3JkPxatnzAX", - "marketAuthority": "5VRa4fvSnTrdLkVcAJuC6nRaA256h4GQWSBRn74LiVu", - "marketBaseVault": "Gp3kVyjDUJdonueKeHBt5zoowFs9fhK1EVuxn1S8itnT", - "marketQuoteVault": "H6C5mnVcwiZuH1mR5LXaqrovHmK4hANGpHkebHxgTATC", - "marketBids": "E56ESFECaWwY2fhFFdkVK3kK4EHJs7wzGS4guJ84bLE3", - "marketAsks": "CxLt94rDBgj8nJ2uuqxGjNVLuaDznPtgMW57MgrWra23", - "marketEventQueue": "HiVDXakf46GSGnC6xa2dhgMBtgoaKoHU7uAMToF1aKzu" - }, - { - "id": "5Aeodf9qn6ubCYurdbFbMBBP3NTBAMkyKaK77i1jAEDU", - "baseMint": "4dmKkXNHdgYsXqBHCuMikNQWwVomZURhYvkkX5c4pQ7y", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "G4DjQKxNRbumS4NPcJQgsCtvfUn93uxFP7dk2azFWPCc", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9EWFZG9WZico6kbynBTiwQ8wMRvnGcxLCCF3rwTQMF9j", - "targetOrders": "7D29Re8929QcxQxbCnW4uLHmyiLPGix3Y9pDMA8mL51h", - "baseVault": "A6Agx1pDTXRLDRKYfKvuqLRRJhFi9ybZxr1jURuqPJPD", - "quoteVault": "2E5mq16HxCQF4jDV9LqsVSBJzo7chhnCZcyq1TAeBLuT", - "withdrawQueue": "AbKfeaqAWCmr4qEppDcmCcZQ5rXarrGRMbXjU1Q2G8Kf", - "lpVault": "7DMsKtgVADSJr1dbz6BMRAsQ11SEXVtsvaQFxvBwqhP1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DRSvEGJsQoPfFsuKfXZ3HqDVtshiUDRC3FGchxFi8TJ2", - "marketAuthority": "4RhgSsTzas6nic4PqgXD9H7AhcDhisVwy3xrVWXGK2v8", - "marketBaseVault": "B6s7qgUkCsbCmcnjrAjbuGn1hDLo1gCXQCRLLhYkHguu", - "marketQuoteVault": "DJ9hbt68KnSDWWmvaZ6Axc3w5jVE4V5ShxpWz3qLjCrx", - "marketBids": "CQhMjhNV6Y5CtvrargHYvkDMfkajzRbdvgvPs4N3C5mL", - "marketAsks": "47EoiaVp7dJrz6wwtkAyrnz8a1j48nKHcS68FhguwL9G", - "marketEventQueue": "4bhdA35aMGMLDfSAhHi54ybq5ukhuwfEmxc6SaftTbeu" - }, - { - "id": "5ahPy1ZA9a58EjrvvWC7BPyX8m2gfvCLoAERs9JbPwEU", - "baseMint": "Djoz8btdR7p6xWHoVtPYF3zyN9LU5BBfMoDk4HczSDqc", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BK2YNwsExxnjSUgdAzdvLV2FrthcNGGWTxDBvfBULCjG", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Fub4ACijEMsHPzPE9DXnDM2GfsVWPZL5e3phxz2FzNak", - "targetOrders": "GiTG8Mv1Xd4r9jFYGrKMk1bom7XfdeTDWpqhQnfXaZqn", - "baseVault": "AWuKYH7mtA15QhG9H9qTNjg8uUCdXenedJxXNSu6rSZm", - "quoteVault": "6NDbKwP3QfQs3HLjiaAd3Jg9XnPAe1SgwBV5ZSVP9hdN", - "withdrawQueue": "DU756yoJo14u7tgsqDquNLpK9HhpdsAdYMuUbFy51Px", - "lpVault": "Aja7aiWU4J8gQdz68aKJpJf3jAmyfqYd28LFXJRCy6Zc", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "bNbYoc2KawipbXj76BiXbUdf2NcGKWkdp4S9uDvWXB1", - "marketAuthority": "9JYWniL8bC9JzXqd9gpCH3Sh5LpiE2NLiVXsts5AUvCf", - "marketBaseVault": "2WTdJVAbMRsynj3NNy94jo3vA4PSQAvjj6SkfnEsLKRP", - "marketQuoteVault": "Bgx27Y12r1xtk1XdK3ik3pppCNo8nvTrYTFkDv7xCv7V", - "marketBids": "BCdFsibpGAKkjuBR83iavH5u1w6y6q6XKCgXT1Jk7zgG", - "marketAsks": "GQYbBKYv8jDxRVRpVBBEbaUnxLm2uZN4mz1u2ziwAuso", - "marketEventQueue": "794nb5AsP7qKKVUGWZLXF8ieuJH99MopFhFoZu11ENp" - }, - { - "id": "5B2agaTtpqosceH1Z4rP4KMCpAW4tNVcJWNEbqncCFMc", - "baseMint": "A98UDy7z8MfmWnTQt6cKjje7UfqV3pTLf4yEbuwL2HrH", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6K3EbDKd9VCR7YdFHZSdd5MfzjWZY79EqprVphrN75gf", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5s6spWppLaiHaVviGczdL5RvEmNyrDTHpAnWJPJWWMhi", - "targetOrders": "4pFaz2KnmDBs9mVNuuG4oTjfTZayTA4cw8x2HKeGmGHG", - "baseVault": "GzJePsZ1betqWDQPR2dKBF17QoQM7gCRcrVaJiGTAGCt", - "quoteVault": "KJXWvU7zF5USraV2oBFH7Rfx2wr2U2rTJrHKAcysND3", - "withdrawQueue": "HPwCQARjhmzfVf4jQ4JDxUQnQD7PmkyMjQpT8DYdkCGx", - "lpVault": "8DXngP7Ehz1m72qLm1r5kfTdtqpU2tuZMiQSmei1BCR", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3djZW2bRhEpYuu5zUs4UJfQVJ8aoruU82EpF5NWhQLmn", - "marketAuthority": "CGJ6v6ntfbWs5NXkx7r4NmE3n25wyWSVTdGRMCUYHhGV", - "marketBaseVault": "8MKwmRFHM49XdhxEjddTeMnTUk6vhuL1rer3dXEviyzs", - "marketQuoteVault": "H3sH9SYKjKtudd5fpnRRoRRBR9gdQABP85nrVXsaRPkB", - "marketBids": "GppxZH8iRqtY7PgBUrstp4oku2GV3Af2BP1LTSAeMTP2", - "marketAsks": "3oKyEt55cMLtjCXQo5B47r4espEgVjbfUBfh1vS5WnQv", - "marketEventQueue": "CfXev5xJ6G7N9ZLdhvik1ivLEyQ1TEekaf3buuC84rg4" - }, - { - "id": "5Bbn8tPfHAXJcqFmvGHorLT7JwC4ZoG1dRHqck6MQ3Uo", - "baseMint": "J5zncv7PeN3Km2BTC6hcRrZevGQX7avM9EErZtFrdTrh", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2dCyrsmKWSBcMkqBRJE5PSaw1iAhkxmzJo9B9NrHxb8q", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "97Ro7gdrE1BzVoZs1W7r2DSTBQDf4QtBusUSErZiuxef", - "targetOrders": "BMNovaHc1bYqnZefStUa7ZzGvXdnyxhaaE7G5DmhABZe", - "baseVault": "5rGb2GzYf2yLnvGmzyaXNAdG8AwVWqxCyh8Bf6oVWsBm", - "quoteVault": "CuSTBUryHQVLjUaGuFKNqYCCnrrLDHgMVm1bVqdLvfkz", - "withdrawQueue": "4wnYUe7neHNz4FU4oRR4Upos7QG6fjR2BLvCDY2MW2sa", - "lpVault": "4d83aySZZezhAA2y9EHNLMXJKJ6dWGYQroV13ZS7hWvj", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Y5D1GUrn9k3kQYUczmr4B2ZW87ZPujyz6bSjpeSENRA", - "marketAuthority": "DxbvSm48WJMk4QuvhmT9kKwvm5noVfLm9ZpuCT8GN6tS", - "marketBaseVault": "5JGW4sQtYw3Mrcq73P9ge5xx5nvgCphn5LbCACTtxuWB", - "marketQuoteVault": "CL8sH9UmVoK6ukFB2Zj93giJymUx558nPQV2Urqgrbvu", - "marketBids": "AmKN2WUAisErmaqct2nBkgFmdJuSXkna3G83HmjXvNwd", - "marketAsks": "NAMiUzqKadpPYY6opZRzhCJgUAHWr8P63jysMg4gmfe", - "marketEventQueue": "3noNWNG1onYfEPyUAApV89ad1gcg9GMjTKsy5WYs1prA" - }, - { - "id": "5BHcPEG8ZqLrVAuwbJwRikYW4CZsQv8cQwuvg3fLoSgd", - "baseMint": "DK6PWMyuZ4NMjsm9AWNCTMKrajQYrtfMjMJ3QauX2UH5", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "4wAN7KTVSyf6daDAHp6AfCz2TdJchmoaZBAbWXepbv6c", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Fmj8bTtJRk8AV9Ui2nWtBxWVkvgRbNGkVwVZJGzRRhAn", - "targetOrders": "3N9VCozB2rH1idRg4oevxNFzn47816axUVSUotmxqA8R", - "baseVault": "CniT3wVVA5zz93agsXseXT4uqXHAYTB9qKnbsDP9HsJz", - "quoteVault": "9W2zmfFyzLHW72ekqCdbbWNALJHtLpbVpptTontWW2TH", - "withdrawQueue": "Cm553iVKJoCTs7Lqq3hNEvaE8sNGbVNp64x6zEswWTRZ", - "lpVault": "14KAXCTYkEeCpCgw6HYTWC1tsaE17n1TPd9SSop9YxtC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6pBw3RY4jPbw8NgHZ3YGNECMXbudhsqoMrQG33zear2c", - "marketAuthority": "E7S4QabWzN6g2vpfCmMU9YvxZ52a5i6D2sgwFqYLc4Av", - "marketBaseVault": "Bdj7u3zNPQs6KP4SHsLCjC48bALdSs4hmUi6XZUthDZK", - "marketQuoteVault": "12mmL49E8riJvhdDzvPKAywjqSyZksaxi4GCbGUwUtxW", - "marketBids": "2Lwnz3HNtHqhLP3EN57Gf97wBGz8TpR65aY9MU1SV8AE", - "marketAsks": "FYM32txVnd2F3TMBFpJxTboDQL5FyA3YuziHp8RawqzL", - "marketEventQueue": "EPCTYn4jjgUXKYuNVsJgAsHUJP3vmm4vstMibvdmL5RE" - }, - { - "id": "5brbNWeodxtXDo8GQYzEc8qVQKrSgY3SGqMpAEBzi5VG", - "baseMint": "9EKEh1CHMKmyvBTY6qYZm7kgRJE18tCbaY1ZbpdELbVr", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4x5N5xLMhDBLQ4mhVcc2Ms4WC4NU66qgFoZWkEE1WPT1", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6QMVZCepBQds7XreUnvBuVfKdYzdPsP2UqVTBv4P2onb", - "targetOrders": "4BWmeMJK5CoZ8D54P28t1dvKvtpRfmtuRdHfbZjYSRK2", - "baseVault": "5rHasKavW1pmBpFBRPp43uW7FR7nrJg9bvqFxNqqkioY", - "quoteVault": "CX585KJVp2F2TWEQ8FA1pGrad5h4TpHN8aG3qdmDFZCp", - "withdrawQueue": "HfahThgKTJD7riYC4BrdPRxjP2QitY7z2Kewbn1khPvd", - "lpVault": "J3Yt6xXeN1gFkNXyF88U52ajmmny93zt66ejkTm5vusR", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6RwbgK5MMmaA7gnz9vkdmVjJohTChGSeT3N4tGJrM3w2", - "marketAuthority": "CDLqEanCeH4jqcnqpq7DH3mdyFkpDHnn87PYem3fEDaS", - "marketBaseVault": "D1xocGadskpmzp8qRkT394A9DefwJwos9woa3nhNDP1Z", - "marketQuoteVault": "JQ9ZXufhaM8GMqjq1oLy1TaXFH9X5XpTPpwL7DumDba", - "marketBids": "7B9yW7oLeZg11KQuACV6SKXstS6eJWnmsNzLgzGJt54U", - "marketAsks": "EqDAj3hk4cEzqrHewhwt88enfxbw2F5k4A4rjCNGMN9L", - "marketEventQueue": "6rhc9pETsX4T3EMUxSzrzNsKs31AxPobgpj2ubjUkAt8" - }, - { - "id": "5c6SMEtpJU982oTvqLEDPhMyUSJKLf4wf3xSwrzpwirk", - "baseMint": "AxXoJZhSfeVUe3qgFZTt4NwQRJB61pBQAHTdWTN9PNms", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "De6PUyCg5kCfm5o3ZB8JUxiQcVZ4WXQjqBzxR11xgWLT", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3SvKdMUUgbTv3aE2qPzhcTgytX4rnx6bnhLFLDwKJ16m", - "targetOrders": "CEqtWPttvsD9JtU3zsTr4ZE1KvKemdPfzWUYoYW6fDvH", - "baseVault": "D4smKrzkrg2SMQz28zZfZqFpP22B3YFQP7NcmkvKyP7C", - "quoteVault": "84kDEs4CC549MaFZ65uU5RNoLPrJtAzSEnq4f2qUE3HE", - "withdrawQueue": "HcPHtXnN7mcMJ26SGRd15jAf7Yy9kCXfy1RiLssue9rL", - "lpVault": "EYZXdDoe1YwZwwiFegNfkboEpS58X4kvLS3V6exq94PR", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9XY76rSTfSDNVfavma1bgwGn9FF6Sw5F4bqxKMnAFtWV", - "marketAuthority": "FnU7jr6F48QH5rcx7JPWg7XKBcMEwkXFVKaDBVXeapSo", - "marketBaseVault": "FoT7y2rM9wXR1ezWH2MUQFUqcx1Ph2XbFiVFD1qoYWc7", - "marketQuoteVault": "DBDeVMgpcCWpv9Uy7M6hURTBCEYPjgqUDAyuvbfkHnan", - "marketBids": "EBktmsXkZCv8Y1QTEa8FYQDonPGnruirnm4Zeenmid2r", - "marketAsks": "BAeSSCJoXfaV2Vinh3zUxZqhiUbzCwzWK4qSfD9qvYVr", - "marketEventQueue": "Hj779QA3aenR8xHBAu67AbNmcRqXLn7AddGMdrFzbzVZ" - }, - { - "id": "5CoMnU1Xtnrr5YrJ2mWBfVJg2hcH57QnoeyjB1gFi6sq", - "baseMint": "E7WqtfRHcY8YW8z65u9WmD7CfMmvtrm2qPVicSzDxLaT", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GjHGikfEfWvtNhwRPGTs1SPK9Lds8hto8m1BDvpz5PVH", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5MNJMTb6uN3aRB6ZGRwHfrHBjP35q71bogSz68tnV8io", - "targetOrders": "7QxZ7k5TMpAt4kiojTihk5Sn6GStQS6QL1SU2UyJTF4E", - "baseVault": "GP9FnQw6baKoKXHeSC7FauHMuaPonucbjXJoF9tUgbZd", - "quoteVault": "CdHesus7RsZhYdPBXJQc9D1jM8PUguEN4XkQqj3SmyLh", - "withdrawQueue": "BHK5iDNYBY4vn1jv9kHem9g2sQSJYi1kqWMx4BDoGnSe", - "lpVault": "BD9RDvPa33epcLtbJCDFBm5EXkwsK1e7pp4BuXAU2Fmo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AGkyBUo7pbsfJd1EEvczUbBizhiKdwBsYgpNTXJWvEoh", - "marketAuthority": "5NF388JzALnYDx4aiwhavjUBFg3nx8uqZtEGG3yB8wzT", - "marketBaseVault": "BsdfecYmE3LiPuaQhAsoLqMYniXw12nrDjzyF6T4dSuc", - "marketQuoteVault": "Ftf5Xyit8eZvkKejFZ7FxX9WRGFX9Q36VY7PqUL4CnYT", - "marketBids": "HNoQAfmPsA2TA3rpaUe9XSBqvp8HAE85ywzwwGhZi8Kq", - "marketAsks": "HqJvsbh9JLxqM4AT42NtPzBjU8x24YH3VvpKyJ3pSJ3f", - "marketEventQueue": "A1fJjEL7Hb7izdpXZ2U1qbqzHKhwYjCQuYV52SCsLq7g" - }, - { - "id": "5CR8m5tQTuVQds36S31oL1A59fEcpirZsN9NdoHcwyqk", - "baseMint": "CBV12y1pehFbhdnDpUfgPe88SbUZ5G2s1kLA449Yu3Ad", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FksejibYKL1RQPdBegNRNRmvZ2kGYhZ9GTkEYSAgCuvT", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6ZbQLbRZzsiY4HBsW7XXkEBDYWqybBRLeXUKedhtkQxf", - "targetOrders": "6qjLad9Jirq7Mf3qC7EVvyGEZrWX429g7xQYZ2aZZoPQ", - "baseVault": "2sjNTkEnCwjBg8pWTekVuSEaZ5kkYkduJN85VM7UogPo", - "quoteVault": "2pgM8p6eqXDXoJPQRsfJXEexubggXL2WLPiYTeN2Damq", - "withdrawQueue": "62U9eY77SArcFgXBDHtdJMHVJxttsGYSkaFKmzuh78zh", - "lpVault": "Tv523CRce74sB7oEoV7Mjz49t3jviQDiUYHXrP58oZc", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HsTDMJM4PTYbpphaGnjR7PggX4Ya78EmP6TxMUCeDYMK", - "marketAuthority": "EgHusSdKS26ZzvnRWSbZg3wLG6Daqux7uUkgTwg2E4Gh", - "marketBaseVault": "E5JBuQUnnXnYJXNCs33yetErDka5aTC96qFtkiwEhxVk", - "marketQuoteVault": "EPJc31Toq7r4SFvMMUj2AdbnL1ZiZ5qxAry8vUcCrcjt", - "marketBids": "9gYiGrZCWdjCh3kqA9EYsZyohGy421KkCxtJ5ee3FoT8", - "marketAsks": "AZsMYg4F8JqUpiwqZDMQc8rPp3PMc5SvoM9J4nFYTvTW", - "marketEventQueue": "EXhgeHqk6P2VAJqu5TkuTcUpu4ShpedMj7cU9hLUFrKn" - }, - { - "id": "5DB4JG8vothMpWbYBQyhv91Fcm74hFMx6iyFYqWoYrpH", - "baseMint": "8gWEnKqB4qVQgC8yAorMxhiEKqsDcxZSVKFVbQ8g1fzB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GHyX1FwMtXVMQFSY8GF9ESjejCV7RmBSS4kPMxjKxU4b", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9gzWWMzwBPWv3uVYLwHzW8AsYLEpkhJAYDZV3Yx9o8Tj", - "targetOrders": "5RXVi88LakRVc9sKftNhfGgFU7WDNTaaHYTNKQ2mUXQt", - "baseVault": "HvSV7h9akcDtSwdDpF9nkG7cdvy7HaYC4jik6bSWsXzz", - "quoteVault": "CP8VjLiwZkRBdyYzkNUyKZoxFpHUbRWNf631goyxeAQ1", - "withdrawQueue": "3iYj53H7ai6roEvM1QANsb77cvGvFc5hVUaC3vgiPNS3", - "lpVault": "2ak18hd67722T6HgL61shVJ5Y6APpJ5EuxKzvgM8eenT", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Cxzitg3c9ZZamMQYKLbnQZzo9UiGBgicyBRR2DXxfXu2", - "marketAuthority": "EDfpF7dphG5Ckus34HhgrYdGzBcj1aVyh2vQpZjwyF34", - "marketBaseVault": "HmLX1cyUDnv2iEfJDZ4AtL3B5twLPnBcyrxQ5ifQ3dc6", - "marketQuoteVault": "66YfGhpaw7AtWaJCZkrGv49oKoByD8t6y67D4p9fz1tD", - "marketBids": "2dsoz6ZwkuTAgLRm8E8Lq7Cew1AqnphJnGbct6V82KC2", - "marketAsks": "CQEoBx8Jh7jRtySnBSDfZYSknNxdq6VmDR8WayLC9qJK", - "marketEventQueue": "3BqVkwWidkAkbmMgz3SSAv9beuDiDkr8qZUrffaDfQkf" - }, - { - "id": "5dRv6pNy89zcXg3MzgTpFrPnQmEBmJa8PpYniJTggwDe", - "baseMint": "9EgSSSAkeo8S4PDX6FqQoMLcUxgLfMaJFSDmkV78LErS", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "3bCggSyaHF95ATwUsnFaCsgrLnt3fvA8SHDKEKpsvMm7", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FxCQiBfTiJBiGDi6pxQwx88Thei5BHj1GnrwFk8fBCZm", - "targetOrders": "E1cbvwKccGg7pT31yDEFDX6wAN5m2sh8u3spUTphBncK", - "baseVault": "6eoHJW8krVad4XkyW6TDLC84oapU5TzVww39HM5t9Fv9", - "quoteVault": "DEwJAeyM4UaveCxMwq2U2oVGdWkcJFn7Sb6cXuEffuUB", - "withdrawQueue": "mUD2rsxC6EXApxio6sCmSzTLadLxfoRYYSnfhthMkEm", - "lpVault": "B6VcbJunAjvwTkbu91ZprmpNAcdfB2kKLLErpqwjQn6Y", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HfZaR8MLGSsuEbPy9LS4KpiVVXGcNKkS8hyiSeMRLBBk", - "marketAuthority": "C9MLFWvo8iG32kVNVNfHHCbQrHTEhX5FvzUHMACpwLwS", - "marketBaseVault": "5G2aKk7aAFwUm2dQZtg2RvFYc9mELsWfZKbhiyAcS84j", - "marketQuoteVault": "AB1dmp6GkGvftmUhc28PJgcVASpmFGMXPH6vvo7hANFs", - "marketBids": "FvmfKh9JKM54D92ySbcnnnuSG7o4jEEfztcFnssM4Ua3", - "marketAsks": "E9Ssxkyfg5rjSAFnKnUstAHGAJynES35EActhCB6HWNp", - "marketEventQueue": "3C3rdqzXp45tmYgwrXN9i1Lcxn7CCJxXGUsJ45JELUEx" - }, - { - "id": "5egzjxA1YNqv4Lt5t3XBG2bEb8zcrcRKqTDPY4nxifmk", - "baseMint": "4xDPH7DVtDXA2eU6wp9BjhryfXEdxBuhe4hnEc9yz1pJ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3DCuiEipCMh2K1TXi4gcU1NNrxSU2dR87AdLDNxh8rdC", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5189Tqg6PzXvHkcgBcSVuy7aqhJiNGQVPdDxUGZZz6RJ", - "targetOrders": "959Z7MdjUYNxgwNg3ZxMQtUgR5s2MqtnrDGKhLf6txQa", - "baseVault": "G2r9GS5kQnAj8WVd4nwAmVBvjpEpCvLgiEmzdGYgf3Xy", - "quoteVault": "dfZyzhjAEDNsPSeEVmS7gzhJKRr5ySUpf3jgZ5zMiE2", - "withdrawQueue": "9e8sefsk2hvauLaxsidqo7TKhwLpwM8UUpApJpgzZK7o", - "lpVault": "GBoihjEawQtJsggPJMKU6umEEuY14TJWb2gazoSj4P9p", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BcmbQcG8E4Hu5KnFaqy58TjRkcsdtjfdWJVe9yC7gBjw", - "marketAuthority": "BpTLFrj1eDpDBPnmVkzNkt56eszFhS6fpMm4iYQai4eW", - "marketBaseVault": "Ch9Y8z2FXkvLVVLjVe8KpF4XSamDFAYX3FVV6vh3Afn", - "marketQuoteVault": "C8qL8J7qD8CHpks1aF2SbwkipGJWC3zXsmxQhWvWwYd5", - "marketBids": "FVWRdTtJkF8emSa6xCpwZ8WUrUAasZ1fJ563xvZYfAhB", - "marketAsks": "8TE7T9hGJyWoHtEa38AYDAiwRv9BeHfq76wswztucybd", - "marketEventQueue": "BuVsSzzZ59ZmH253NJmGMjGj6m8WnKtEQKB7HXfGVVUm" - }, - { - "id": "5ejb6zLG9qmv15nPr8u83dwrXAy8ymYk8Hko5eRSjNwv", - "baseMint": "DogeLZECE9CthXasBLFxgeA2umEyt8CcV7Jsf6P5ZTFo", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "58baECuDumoUHVFihXyCmphvrKG8UEMaLcNrg9arg5A4", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DWysdLLV7qJfsCEUXd3AyzWY3XpsGAVNRmf4bHfTdi8Y", - "targetOrders": "6fycGnUMvhGUsrDpbJWEwQxPD93uyuvSMAhqzhWJzNmp", - "baseVault": "FtTJEM1qJRpJcJXx66T544dQCRe86X7Qd2aBCyXXvuE9", - "quoteVault": "AwjhMoJxLL2aJRJBTg3DzjWrKSzGBYinAEoJA5Jbq6d2", - "withdrawQueue": "4Cd1yj7DffPVPByMJ2r5zWm2M8MSm1jMQ6ipAe4vDoZW", - "lpVault": "6YGRKAXxBUQmtLDPV96eLaQ6tVEQWFXvB3E9Mt5L5yig", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HivqaDzu9LwZ9s2wP1syHKjNvEhvuSrmZBwRepuAtp1m", - "marketAuthority": "5EA5W9Bfnbfrd8ALqMsKa3qSYwFfhnVnCSrfkfMsEWdi", - "marketBaseVault": "7jYYibi9DX9yV7Aa87yohkoELi1Y2xueduE6aUBW9Bmr", - "marketQuoteVault": "9BNx5KW2TLRoyT245fmvWdq7jQVK2UejkQwze29yJ6dJ", - "marketBids": "2cG8Fqmxdvntpdzmu4M1dYy1XjtwjhBYph5ByTHA3Np7", - "marketAsks": "9G7yfprbDzADvyJFMoCncNKCgNkHQohDgMTfH9p3yteo", - "marketEventQueue": "3UD95gp6yiEHK2m5xBgJuqM6mGckoWJaEvZCd87iaojE" - }, - { - "id": "5F811QYngDQBHvKwkJs9KjNxKGJWH9hAPNrcrPYJvqzH", - "baseMint": "SPraYi59a21jEhqvPBbWuwmjA4vdTaSLbiRTefcHJSR", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8n95gyJbo8coUUyCiLjDJqgFCwK5qne53woh5HRSDe81", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "aE9prs3aYyWxicUGUGodfJKFvXqN9mbaD7ohh9xWjo5", - "targetOrders": "CbGGtCrLivZ87ncTXFyPDauwF1a3HjLoxeJ7FidyqaRz", - "baseVault": "55veqvNTZgf69SKTqXaZUuRWJd32TZK2Cs22LQDYn9j2", - "quoteVault": "J8AVum155Ncjd1hTsNnYSfiMdCvQHkiF5SwAi5683vpK", - "withdrawQueue": "F2g6RPvQEoju8v2yVVHsjxsxYYTUkHZo5ogUrn8dY87e", - "lpVault": "3XJD4CCmtwQgMWGdoyWhHmAARP2fMopBf7rxKfLpur9z", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FddkypFJDoPMNdLxTNCgLn4WjkNcEn7cP9jkvWMNTEzh", - "marketAuthority": "BeCdQ1ar6vCpSqi33WdrcaQgcjWvn4QPRKVXAXTUVn43", - "marketBaseVault": "BBEoGonfJTJbzYqGSAJWmmxK34vApMFs9TWgpzX4F13G", - "marketQuoteVault": "GNWdrNSv7J3JNXDcoZ3mQwxTUFDagj9kSYBGVx1CwE3U", - "marketBids": "GZB58xDa3ym1fWr18DfL4kaFPe1Vyaazq1UAfuHBqXjH", - "marketAsks": "2yg4zujWdMzgLhX52SgrW2M9GLuHPpACLve22H6udKcw", - "marketEventQueue": "BMAspEgqCFmHwUvnULPVfgd2UeTYmnPmfyA6UrZiUKBR" - }, - { - "id": "5FApfRaY46gHwAcw6FDUnj6MjAirobSHeph6esPnz48T", - "baseMint": "E6UU5M1z4CvSAAF99d9wRoXsasWMEXsvHrz3JQRXtm2X", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7E4z4wyHQEupFZcfTYPRGPA1sT8DqHxhzHyrwEj6BwD3", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7ZvZtDAv4J9iN43LdZo5b5Wz4EfZJZFDP51eq5k3rQqD", - "targetOrders": "89dEWCAqPQA6pMjotNdThJu3cqs17yE6nfM1kHBiMu4A", - "baseVault": "4tAxH1P7JNCNHfhCKMeKgKyU6ePurUM3xW1SnmHxMk3o", - "quoteVault": "GaxpH9UoiKAL7VFaY69eAXfuyzE7gWKHQmkTPf61nNJm", - "withdrawQueue": "HsoJxtpuyLjWJurMTJ33UY1Q3LT4mhq1NhCtvDhpDzWQ", - "lpVault": "4cAat64AXQbvB31HiWkt1WQyvivgDFaK3TRwQRdVemoF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Cq1ddwyWSGrydBzAS7imQUiDQz66Lq9Qriz7CmpLda9s", - "marketAuthority": "Eb1skWAzdvLqTLdFUjtB97YQNsUWHR1cGXRSH8e4th7t", - "marketBaseVault": "2d1u19je6KFotBspAHsHzqmkTJdtf6vcNMdYZR66i3DX", - "marketQuoteVault": "6x25tot5wNfHhwf3c8BspVW8bCz9XRAn5Wrh4sZWGDMV", - "marketBids": "DLJbaJz7q4bMu9c1KwadT92eMrRZMaq7p9ZJ5cwwokT7", - "marketAsks": "5xCW7DmWDG3WGT1oPotaNJCm2jMr1CX2mm4LHvHS64p1", - "marketEventQueue": "GbQydMxty6hgdTj9VDYysEEYCfJjvx3ETchhjgsCQDzi" - }, - { - "id": "5fE6zk7xf6cd2fPrHDq8VQ9Nbgamg1wpnLrhzYJ9SYpV", - "baseMint": "ugKuq43fnPEcEeH12gCfETbshMRJ8nD2qXmcbyNHaEb", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "4HHFAWbmvM2SG1foPt8BAuLw7zQosfJZor3e9HXAjtXd", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "G2xcDgWrWqNghQo5xyZwABFXa4iSLL3ibjNx2UG9QoeA", - "targetOrders": "2ZEEe7agty2Jj9SyekeWmLQqYeaEDG6nMESVjrL5YGfP", - "baseVault": "AP3uSPk1VFnc9xUWvJZoYWnmS6htfUnuCr8FM9EVfBFP", - "quoteVault": "64u7z54T6cv4vLhrTs8652qmLE3H6otbkmo3BwqwxDoG", - "withdrawQueue": "2tFxNzPT24dvQ9gXPBQGDmPxZc6ix9ZZn8kBqBxzVc8P", - "lpVault": "57Ago8316p7qKuP5JPhgvwzTsbd9F5sg9AMggdXRCfXc", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9YMXphf6fS7XmQFyduoK7PnYiyrq5UHXJQLUKZUTgDB", - "marketAuthority": "2DEJCDTyw4iAgNshkmDwhJ2QPkCBrD4r7dAc7f9DFMTa", - "marketBaseVault": "GX9LuH8qZXL2o6ahasCoUoWpfKSWQSSeeZZi3M9ECr2y", - "marketQuoteVault": "G4xrfg3fteEQjw5xQGBqop6ADD9Kz4yc9bGUHDc5ei9W", - "marketBids": "EJgDJbWXgjrtDbQoVHRfEFbpJGsyFxYtZiz3zQr2CnX3", - "marketAsks": "8RAD2sS88cK1LPQoFB8tcDZkaeEdbMWPzi3KzkS3W9E5", - "marketEventQueue": "G4dGLfNC2PKNG42JQFbEtTHhFmhYjEWM57n4WUpi3ZPP" - }, - { - "id": "5Fk3tGEUJAnoyo8n48guBs5S5BX1Fso15gKcJ615V9Rs", - "baseMint": "HHjoYwUp5aU6pnrvN4s2pwEErwXNZKhxKGYjRJMoBjLw", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "41RgW7DysVdXQrmkXhaFYy582RqGeeV8hSt7KZbvrPGZ", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7i4VNjrZgBoyyJ3RA8Q6WCGAWbKpe3VhiARSkMcuZhv2", - "targetOrders": "2cGEgYJhS3JMLG7Q8a1jt6ETvFFLVu2EKXcJfLkpNQxT", - "baseVault": "6vkUw4ZpdU7iKJTu7VbbKokkg1UZntQwX4nfKeyHtrEA", - "quoteVault": "Cy4LjRFbnSf26SSufMuDcERixYyHvD55k3QojUcAcyfb", - "withdrawQueue": "3q1JtaiD8Yqr17DAd6jpbW4xaD8HnarZceUCiRVQ6Afz", - "lpVault": "29SeiKBoDJ4dtP1aAtPCRR4idcYFW2nxVwFxBD9UfKbM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BXv5kMw9Dx89AaTarGvDjkGZUsHSdEdtCTSqJKit3agw", - "marketAuthority": "DBSPA78h5u7Vst97x2adfMzX5UTniLcToBNAn5ig2Dv4", - "marketBaseVault": "BScyBnYJRnv9GU7Q4ESf7EimqdhFS1aLDhyV4V3dchjD", - "marketQuoteVault": "J57C5tKne4CrAu929h88Yw75PDDptBPgFHNb32cHaACM", - "marketBids": "3fvudoAXQR7gGDJFGWs51fukLzuqunqCusvvX1afGB68", - "marketAsks": "3zTV1GvZb642DsbQN5y2mcCyXuF7UXqe9GW7DBQzsckh", - "marketEventQueue": "Ep4SRd27bvar94V7RMjMGdYhVfgJu1qCks8rJgt64HMw" - }, - { - "id": "5FoG2w1v153J5xQuGJ9WKeoSGjEFp7y3Qhr7CdXxr7sv", - "baseMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DXRM47UzLoAB8T1LkjDtPYaUnPgsbwrCdiEcpF8TWgdj", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7SMoggYU1T235YjgTZGvoowqQQL5o29BxVTyVFV7Vy7r", - "targetOrders": "FZPEpPfn3Lu4sR1n5Q6zL9M6BtMpj4TnroYsnrvqBZW7", - "baseVault": "Hb324imURmEsdAFg7couXvKuG3JMEDUf8uhwmZ8FzCoq", - "quoteVault": "EjCbF2MmRQ3Tz8mTiSr9R8SYPxx9TLmv6fhcH8ZHGE35", - "withdrawQueue": "5WZABoFjFXeAv7BoeugkeLTzXyoLPDHvnc63Vh3vtuK", - "lpVault": "GpXwrfBCqPbn2qAQXANdjP45gPomYTbBmrCeWruUgnY5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BkY2YaqsSGd4KufXSCsgUqPFBhbt5m95SKKPByQxT5Um", - "marketAuthority": "EUEug3r6zGuVEg288GZ4hb3maCmweRLURrRKRiMfw6h4", - "marketBaseVault": "Gdaa96JLLdj7KzRrP6xUtn2mtEG2RAFMtzJXdgJUbBeM", - "marketQuoteVault": "AnK4qdXnz61f47jJG77WLEYLLheMVXFjMDLKTujThBmE", - "marketBids": "HMBQT5oeDFK6ZrCh1a2MjgjunC1eFMLfHcih1VQn5Q2a", - "marketAsks": "CLfRTV8KBZBqGREdqsCka9tiFHU82zoQcMLLBMLj48uN", - "marketEventQueue": "BqQDLkNGwq7HXjSi5F6PEpWEkbMAUam2ChcvZSfb3soo" - }, - { - "id": "5FXufAxygPxpUi4AycrJfQsiQdMbgKPCsz7wNZm8JL1y", - "baseMint": "75XracgnqjPeuexHKWQU3bBcXMZG6XLDF867tKB1T9e6", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4UbvcEAe7s5iriwY2TVpHYKdP5QGtHUjz7fz7Lak8wwk", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7UX74DqqvNKVgc7EXKcnxcFjAXNkbvD6vUJspfNpfPfT", - "targetOrders": "9T8VxrhvDJKJzLhNea4iuEadvixWQNwaAVwNQ33nwzmY", - "baseVault": "3SjtYsfkFzzyqPjko4pwPaT9Q4u1YiSx6QyQVhThoPAd", - "quoteVault": "37eyTavwq1cpUDnmGrL1b8J7rxmCQE7XS9PjcvBKQ1Nj", - "withdrawQueue": "Cdc9XWbbVvT71ELCHRcmyZLAxKvx3rgVQ7hEsvweGLUy", - "lpVault": "8J5RZLhwaVGPBz3TqcseucP73eBDRSK6uTmNadcoKjXo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HEpW2dwa5NheTKCvdqrjpRpiQ92ZgmnTYLBxQZe4eHk4", - "marketAuthority": "9TS8AbPLP5A5hhQF4na4eqEmooC4uDFjtPTAdYHzBNrD", - "marketBaseVault": "EsSpMzJnmqCEqqpwR84tD1YqeBnEwLXQdrh5PS8YtLUq", - "marketQuoteVault": "CMdVtKencsYrkRMYFrHCDi9P1UFrEy56LHgzaP7a2x4J", - "marketBids": "9Jk7mbXPZ6wLmCKmmeWD3TPbLndB27TRwvXkZNEnn9X7", - "marketAsks": "8zF3cLbsrbavmNywnYfK8ZjXebWT6q1VDTjkYXpUKLq6", - "marketEventQueue": "FFkonYtisnCCqNkhVP9fHRkBaQubAin5RAS9b4qCi6Hr" - }, - { - "id": "5fy4zrFnb3xkE3KsjNa7g9aXLgVYxRLSsYmauHD4SpQQ", - "baseMint": "H5gczCNbrtso6BqGKihF97RaWaxpUEZnFuFUKK4YX3s2", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AbW4oumokyyT9mPmLyQPpzUzwuX8YyPMeSEJ7xrNryce", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7bSpzzgH6qKNcj2pLyqFPBvgQUAi1QDSZMZEFf5MiNGa", - "targetOrders": "J2qLYTM9p8CEHBYW5Dwuvux3q1m7wacaSHhjHFXVyYbz", - "baseVault": "DQsi8RBYaddVBuSg1oHvgQv4UaPZ4TmpRWKNPo9jf7hv", - "quoteVault": "3yH3AYKiqgAkTPtvDiCnjGQjVmSSPQEVhkh6HQkJh3QH", - "withdrawQueue": "2Gc51KcfTehVMK7egu9BFpo3Ss7TqTrLT928MRnMbxqH", - "lpVault": "5PFgwUky4nRznBQo88ebuHQ9AyFRBLSMuqyw73vgWFmm", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2kQer4JyDA8wRxNpSCNG8zAne1zwWVhByTUu8Qi6BEjR", - "marketAuthority": "DNaeX4BgEuvZXDf5XDCjX9WCkyqhWW2EqKbyATfuMVsn", - "marketBaseVault": "Du2Yz2wBV9SJXebGFqmuAxb84VKYc9k1UiWsdLSAmSnL", - "marketQuoteVault": "5yRZj3rPHLGsv6TErESGQ4ZaSnenC9Ef1USPVSdEGHin", - "marketBids": "HBJmD5Gzid2netwiibvA1KzMmdxCT42gwf7N9dGbcSaP", - "marketAsks": "6Tvrcv6YweuEUQojgzqmcCgxLdZ37L5VXoeu8gaUF6L9", - "marketEventQueue": "8cfownZg8mUvgGGeZpHAq8WoFYZT1np2LRw2AC6fAFnj" - }, - { - "id": "5FyEeeYYb61irVwjCyWcQ3K3T9sK4R2fFr1H2Hxj6nGy", - "baseMint": "8udZmv2RrHpU8rPZhphUGhHpmyAqc9UzV4UihpThKvYh", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4dWtTYk3RPcGKPecFUsTUW7C7yyQaukCzxPEGrwzE9Yf", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Aa1fAUZ87LmdY9YeaWPD57Ez1y3DdNfGK23kyUkuKStN", - "targetOrders": "HWdtar74KEgEsMd7SUXc6LqKCytNsby7qGt2NSJwBGFN", - "baseVault": "DHecWQ85RLH7e9txP6QnaVXSckkRhTK35w4q2ESvmsnh", - "quoteVault": "3D22BuepLP8W5gUnyC8o11bRWv3ZTVjLDad7FjZybRXX", - "withdrawQueue": "38X8AFGSvy4m4AVY8HoMMfLio1WMfKiwaXBXhJL3ohas", - "lpVault": "Er7ahETCXJnFco2B3KsqzfNierXygQWAFL6bCaSJNDuW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3y21ohiuPeAeaW795oMqtKxrCus8BTL4mPtADa34bNuJ", - "marketAuthority": "HXyju9sjNBa4BJ3iYboionmp24fNZUK18yNztqAAej3A", - "marketBaseVault": "AkhMqvnXvVvVeYHZj5vjLmHxwW1GQYs3EYGppubMfi6N", - "marketQuoteVault": "A7aAD9jMeqheeYK4Aq3oNY7i7Kus9CyL8NhYBvtRHiqq", - "marketBids": "AJyapQZPQ8sviFFZJ6NzBRWajh2Sfyfr2msbdsMEtF2Q", - "marketAsks": "B2NFHo1bUvu7TCdTfRX8CRh4K62yQ5dyaeuQ5xuyeU5b", - "marketEventQueue": "CkFjWFZPdekaNx1vKR9NKhVdBYuvpPA7nm4FxS1Z842i" - }, - { - "id": "5GKyWWkbbt4M1E4Bm2Ld84pjBfVkAN3hbLQDUGU5BW1h", - "baseMint": "9KYMTqKY7f2cJKW2wYfNRpLb9zbB1tTyEbaTuzy4Gwwc", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "FmJtzrHVA7N8GcmrpLNsCkbVzRtrGajMn1noVLeoakSH", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EHBxMrL5GLqcS1SKmirZhjSdRT5kgVgP4rnhGpBp8EWu", - "targetOrders": "FzgqZ9A6JKukMykhuEgQ7ZfLQ291yAx2atw8KZoCct1i", - "baseVault": "FPdk3jeeCgBGT8BxeBtU4MheVdzou6BkKbextQPBHKd1", - "quoteVault": "5pcWQtBnXQeYxfUeZzpVHs1rquyeQM8GHFwXi7K43dN9", - "withdrawQueue": "2un7G64AKmmNz4KZ95NVTzYm2khtgDPKtB759UYWcXii", - "lpVault": "ErZG9VhPnGgiR2m69GEFjPSrsAVqf5JHT6YYgtwyGXMz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9sPZBX9nbuWeMXd3QWiHDW8WvvPJL56GzcXYYePo2Yad", - "marketAuthority": "7iHpXERWJEEESLzuR4BcNQDPGiaYwkEsSwMYBqPhnFGY", - "marketBaseVault": "vYMfLtAkFNQov5DJCixsTPGXYzL2uFit7X5QGxzsEWE", - "marketQuoteVault": "6YRrxpb9v1chKMgBCZFedP7CefuTtLF9FnTvy1iVQfTu", - "marketBids": "4D5ES6W2J1zcabm2au6HUZGXPaLM2zT7McL6sj4C1u1V", - "marketAsks": "CDfVHqrHNm7PCGwLLczdYF4ss1LK4Q9REkkPMXFcJghV", - "marketEventQueue": "9vJJdY1XH1LbQ9SpWWPeWjayZqNZKgC1sSxTNWban8u3" - }, - { - "id": "5Gqh3573agLj7iccr3adCdtd4DwSXv5u3pquonZiLBz3", - "baseMint": "GGFNWQ2oEzYVPu1kGSjXZWfyTibnCGJfqZ7uPx8Jkj7B", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "E69nCToiAP3SJ2auHKdkMMV2jFWhmPdn1yztmaGEcg5e", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EaAXDqTNUUhXtRkdKty4pdBbHZvHNgYjYv6ybZ9b8kPV", - "targetOrders": "HSJLv2yfZ6L3JoV3Uq8o61FfYAimFBrABVL2684AbmxE", - "baseVault": "6BdJL6Ki1QRoyGpSkZPbFzW5y3DiYpkpw5SkScTFeyBR", - "quoteVault": "86Dz38ZtfT6YQrKCWCMiV669EPfrXe28LjzLAddN2BmR", - "withdrawQueue": "CVWqXqRwKXMfVHcYSnrcpKurzywEyQVgfkLCnLJD2WAS", - "lpVault": "ERYFhhkLUa4S5TSR69p4NmTrx2NgMSUmAQFtnYQxDqW3", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DRSZihtHpPkMqivKdwcdunGC3Z4aSfQFPiUCh3Nb4HPW", - "marketAuthority": "2WfNyku3QeA68VVXLPFtYymTsxWegeXD6MWgeqZ7LC78", - "marketBaseVault": "UwLJE4Unhikn1LDyso6Ed8YLSWrZ1pYhDMbF1zopi83", - "marketQuoteVault": "2133SeCETiLxH1BummX3pWMyrGsZzza3iKHECTMSVJhU", - "marketBids": "H7zY3uHGpAi4My74n3mefk6MUnBTAfqdYKtr1Df5TMku", - "marketAsks": "A9TXWSkdAE8mSQGeWnk4FDerWFfn8WyCgrGcMovwsFKL", - "marketEventQueue": "E9SAdQoYFkzSJ1ETcVGTikJw6N95zWvt5XesdtK2bWqX" - }, - { - "id": "5gQRswDxiEQxs6e6DGuodvYYhEKZd1CdEQvpwVeJFB5B", - "baseMint": "4wjPQJ6PrkC4dHhYghwJzGBVP78DkBzA2U3kHoFNBuhj", - "quoteMint": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "lpMint": "Fgj1CvTTpJgbcVJFXRBcLzQRKhpZQCpRjHqNAotwYxfW", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GMeQ2wMcFUm2YC6mDe7MbnF88iEPMo51o1pXscSQA7DR", - "targetOrders": "CCZPJTvi8umGSTqV9ouh3XQMyXHATuoi9iC2tKKorpFR", - "baseVault": "HP2hds9tiZDfuPGxFPiba4v2Cx566kKtVuj8e6oucFgF", - "quoteVault": "BQ1r2dxzrhwKuV7z3i398xtJ6Gj2NiRugofVuV4U5cH6", - "withdrawQueue": "3mWe5fUVijpRxXnbc4nKqZeuxuwtg6Z4yEEMJ3EhiqZD", - "lpVault": "57X8LeuRmqHEV2LAYb27D7ZmHNMmo74Bw6idqjSRRGaL", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EndVw6RZpxqyVyz94oCzJuBQLT2eGU5NCVR5yDm8GFS6", - "marketAuthority": "EouXeL5wqeLGeCHTzxukmLvcLodHpZXrd7Br6pNvMA4Q", - "marketBaseVault": "13yLdK9UVwyK8Ny1N6EdQoxCNchgHdeXhvtyMQYsTeKD", - "marketQuoteVault": "CJTQjzv5zPLSSXJG7QJwEPDRPwiYFq4HtZb6ck5FYbNt", - "marketBids": "4rWcUMFdmK9GZ6NPpcBt2LxtJimAQpATqxzsWEHddyC4", - "marketAsks": "DzFhJPcXGbfwxDY9RaGdNbYv3KviaETWGi9aaGSgFrvS", - "marketEventQueue": "AuyDpGHdFAybQC1B97UYL9r2tPAfaN3RiEiqmrPBDddC" - }, - { - "id": "5gyvtEqdTKHKLq33bjVFHU624sgcYT3NXgrDi4oRt65", - "baseMint": "3oLpKntC8W9AxiFhafRGBeALGuKdimduUXVPo1GQNHuX", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "Bj6NfM6DshJztDDAhcaCzEuFCpPphN5MMnmwQohTJyNv", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ALM6zA8yUuCKHuqKu3XUjGBKLMVDpdUp6E7TUWxjq4PY", - "targetOrders": "HuFFJWDDbXnJro2o1Ua7MSkTCqK4B1KqD8xfbPsERh1J", - "baseVault": "3LMfGc1vVNu2411dzCND1URRsDaw98PkPiiz9qU9bPLL", - "quoteVault": "8gMhrshqgQ9QxzjXUD731VkuFcvz21qsiRutsXJDYwGP", - "withdrawQueue": "Fhf759JiKDGV2g3T3YG4UbyfKwZnUqujoj6GiinBUbGZ", - "lpVault": "7gNHjE1XM4inaFYjj3oCnP9hsDFMZkSBBWwunxKK7kU9", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8xhfMZpJTvuYBqzmKM3jQkzk3gcT8Pz7AnuxNUeLo6mY", - "marketAuthority": "Hp62AxoHK26d8WT1Pfsrk9HF9DYQqyCxjCLu4qcBGmA3", - "marketBaseVault": "7WLHJH6kRLKQPZcGsmKz6jrTtCrtcbYCvhrdFnteLa5U", - "marketQuoteVault": "HdXrEmNoa2Hem2AqRpw3miBKBovVfhQZ3rzYBKR5rhPx", - "marketBids": "3gnCkmRm3ZUw6qj9WQ9GSwHMjBqiXkDNoSpS7g2q1hCh", - "marketAsks": "2RpGGgmeAxjYzGrC76RkWVNpkqA9mheEFVmHjTkh7Ays", - "marketEventQueue": "FXzTVVYGXpoEg5D9ii25JTUyiEJQMAzNzkDTomGzcHSU" - }, - { - "id": "5hbCYGfGGenjeYzfWGFZ8zoXTo3fcHw5KkdsnXpXdbeX", - "baseMint": "SLCLww7nc1PD2gQPQdGayHviVVcpMthnqUz2iWKhNQV", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5jQ9jc92SUmYsQ1JVHDuyUqctdtfwNWjvdGLHKPnzFT", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AJXrpJNYTj7fkESZHHhHyXayfkwf4HujqYpz8CqVoWZk", - "targetOrders": "PN2mPb8szKvSvpNcn7ReXT9Xus95A984mS7EWT8SVot", - "baseVault": "ACZAhbqYXe2SmAhDVLrdP7YDpVQVj5w9KdQNxxxe68fa", - "quoteVault": "F37eJebRkhPu7AorCehcJbf393Ad73KcFRyL8sTBVVE9", - "withdrawQueue": "BCLpdsUhowEESTpYxfesDAjWjPbDKFbzMejm4SsR41pC", - "lpVault": "J5rZaZpen2j5JnJ1H7u8Do3wQVGw2UKtBvDG2pApefGd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9abcE8CCEbWAXCEywmpKx9ytw77HDnRZtfLDRCbaTKD7", - "marketAuthority": "Gy53vMD271z5kepQCGRX1EzNub1dy6RwaxG2ok2cpTPY", - "marketBaseVault": "HA7snrBcqugoNxxV4dkFSKZtrEbwaTtrKE4CXH6tGhon", - "marketQuoteVault": "7LZQFmE9He7JsC6c6747vSyUnSjTDTieuKWjE7BzoLnz", - "marketBids": "AfBdXWxpLs8UuXSTpUNcRkh3FtUVJLBCT3JbcMhQhWLE", - "marketAsks": "3F7XYsvXFu8GrxZq2TNvKmdGPF5i2FdNhcrD3wKW2FuM", - "marketEventQueue": "3V66qWw8iUZ7LJPxoBdLTxKnetnt3XNCsp9HRFtm9gS3" - }, - { - "id": "5hHpyiHbT51tePcGnqC2BZXGZnHaavmKbZvyLyaC9HBK", - "baseMint": "39cG39AZ4cG7oGNMe4RhD3xAzjy1nkiNgk8W6WbDCgeR", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "49EcJf14dXgLyi3n4jx5sk6YaiostApbhS6kw2hMLwHd", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "65Vx6M2SobLPpboPMauCJXqhwq22yi6fHzjhdNuDjE42", - "targetOrders": "537Qw4jMh4cXeCmtWPPaUrfa6xZESzzquwE65AcEmDzx", - "baseVault": "5SuFM2LkpnQmgS9vWW8u7T8H8FdSdDkrdCzccTEKT3bK", - "quoteVault": "2MX6y2oon9DNTF5oTfBiJsrQdh7A76X7cTpqkATu67uJ", - "withdrawQueue": "7D7fziZm6bY7JzFKrL8BbNeRr8AasmjdyeLXgDGcYzwY", - "lpVault": "78PkeibP4D6UKJiLZveS2NU6Ksrk8UF5BsmTCKizCfd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CRZCDQzYe1ikCqoDZSJnSWLUzXegcGMs468eQW4QfUpb", - "marketAuthority": "HtUzKLcRbqpapVw9nXnXSMMEb8e1fRZL9TRVNFpocieA", - "marketBaseVault": "9H39PfiRhrc9rdcDWa41KwYJ9epWwiRTvsyPQe6Qgixc", - "marketQuoteVault": "EXWmGGtGFRz4uR2bLzA7dinMrPezi28GgBctejgtTRNr", - "marketBids": "EWRHsDYoc3ytThFHuuAQ3R3GC1Hnc9k6115ZUt9s3fwV", - "marketAsks": "79FrHr9gWvpt2v1EmzGGeFoBEmwPVNZa3itqULqFEKqE", - "marketEventQueue": "CPBzPzDBNwP2dVBBkaSaFWByCTv22nnDK9ehzatNSJai" - }, - { - "id": "5i4KVnf4EkpJ4HNS5hDXVqPu4A1AYr4j5mtGiHuSkj8e", - "baseMint": "5rFmh8C6Zj1VfL7ogB6PyVDnQkqsayvEPsEbbkUPX8f", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5osKnwmJFjmfx1Z4VmjbvYXfjaMwfkaPHvdkp1DerqSp", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HP7e741VuY6ePjefWPk1LnHiCZHm9gKDfLM7MGBa8nj1", - "targetOrders": "uhAWuvREWr7shcx8vsWYjL6ChJd5D3PCfdidpgK7N5J", - "baseVault": "CtcUx5Y4ThdC4h5sykNpHW5GRsByFET8PmKvNdoW14A9", - "quoteVault": "B7FsroF3SMjmnjUePXiHsZ6jLhXM1MHHnbzRA7Y9wpZS", - "withdrawQueue": "BJMFWqmaHckviWktjsen6JnuN6ZZu5iuunmzojbivaNQ", - "lpVault": "GkonryPh64fZbwJhHrLRiqh8aszsgzAAS65J6uTHmqxR", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7tBTNaUM38y1mn1oozbL4TzNeb33ySg8W5eBer9HBPZ5", - "marketAuthority": "EdecpzPnACzGk1AKiZZK6prReVRpg3LW6F1Ya98JsqWk", - "marketBaseVault": "D6sU47XqK6P3DwxdzVgLPX4YFLrXyvAK8LcUvYbvWXSD", - "marketQuoteVault": "58hSCeQmhN7b6dHtV1dXEEJfy8NRkxx7MNZQwVZjASve", - "marketBids": "CaW5ce3t8JVFL77qdzxD8NT1AyjaJBJDfxD9y37j5jWs", - "marketAsks": "J2Fmmehi86DxnnaJ9HaRQJWaz5fFPKQEVAvcVrk4EXc2", - "marketEventQueue": "GCtPhFMngY8pKCQeQyoeASZ8vq45srbFa8ZY3cXbaZ6X" - }, - { - "id": "5iYQm1689BQXUP625LuBudqa8nk75yuo8nUNgtZqj49K", - "baseMint": "BKGp1At3yLDK1NE2gfMuwv1QMAHBwnqgSdULsyzjUagA", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "aqKYpGSFrs7m7NSbTYg6bEq3r5b7gtLAuyMLQuuiLwE", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BS4GARvD2dfQmMrJQom8Fh8pk6iZBWrzNSuF6vmbqmpL", - "targetOrders": "5gvhJk3LuW111TendVBJ7hJK3KFxqe1PQemth8uyspZL", - "baseVault": "DFyQLV8aCQ3T7ABKp8CTREoGpkpNxEiKqbmR7pNhR8fB", - "quoteVault": "DfWpV8APb8SUaypLJRPqc61DS7Ht2pHA54gFYL3XadxG", - "withdrawQueue": "Bikd8aRTwjc9Eu1UocAM8gK8AFA8Ubenm7oYXXE6kurq", - "lpVault": "EbJd6kQkyqCQ88FH89tJQ7K8k7h9BpvSnLmbXTovfMtB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "91WiupLKLjP8ENihdgiZ53j49aosNm1EYXdLbRD6GAY4", - "marketAuthority": "7KVHdu3uLrEajQgWX7PGV5scf13WG58ryCdY9jj6EpGd", - "marketBaseVault": "FHE1Memfbbu8iyzKbqzXGwtnGCtn7D9hfTbnDkLUwdNq", - "marketQuoteVault": "2JFqYMxqVyojBfyPAntjpBbuSDGigMHnrBJb8YZxB3fR", - "marketBids": "CEGJaR8oQAqzrRaK86Goi3d539hjNeeKt4LShQjFHchW", - "marketAsks": "8hP3y4Fb8Te1rh1CdZoTEi7j14FqFQwB57yD6zoyniFU", - "marketEventQueue": "HMNKAnM1WPALBxos36pdc52P4yZEaSGxZcjjThQmATWo" - }, - { - "id": "5jcGFqXyB3xUrdS7LGmJ3R5a4pYaPPFs3mjFnqgwgo4x", - "baseMint": "MEANeD3XDdUmNMsRGjASkSWdC8prLYsoRJ61pPeHctD", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7meGAxvVvBsUrFobS4prWVz1dnMZNvRRE2tJoVjFGjFc", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3nwCdXXZgdNsgpah7WtAuYGe4MJ3C74VX2pcHy1EnZBU", - "targetOrders": "EgTT1MUuyx7WwgMcMXHyyjhTJrHfgUUqTk7XGt8iGbdo", - "baseVault": "mj4ibrwroEtTsRD3SLkjeW4xP2UyBBYnPYvSUQhkDpA", - "quoteVault": "29qrNgqv95icc64pbwrxKZAtBUCfjPJ1bxeNv2aXnsYi", - "withdrawQueue": "Bq6QPkaUJvxpvab3pu5LyGhhEMjW9RHYdq1Lhv1YxVTK", - "lpVault": "2nSQrHgRhKVC2bfgHe9a1WkS356Pg12HPbKboMWoWJh4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3WXrxhrj4PXYUwW4ozBjxdSxwEp9ELKf3vETxXTqdiQJ", - "marketAuthority": "H7piNYRg7Sjx6hjHhknWX6UnXfiHKKs6akwdMY7sjjyi", - "marketBaseVault": "3cHFVJ4uh8Pwmybd4XF3iU3VdJwREG91DCfNXjm9prHy", - "marketQuoteVault": "Ec2bq25kJZf9gMh2XX5zwFukPcWNtT3HBAHhGYh2tyWc", - "marketBids": "AFh95RigWmP4aq2CrqtP4hARZZouWQZaZZXPKUrt892s", - "marketAsks": "CAUEmWVpBSeQCiBj9d88gSZvm9vNkLUYvProJ5tkY86u", - "marketEventQueue": "3JmNeH9HgbG6NabNraZTAMQmSaCyFYBqDCZGhvvr1xYj" - }, - { - "id": "5jUMQbo3GKm6bKNxnrEBPBUDXFudHTCFTweJAdMgrkT", - "baseMint": "6Km8PRUQxPmNX6EhmAuu3sFEnCP6uT2Yt42zPFR6VNnD", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5pGNw18XUiz9JzgG4JmZTdHdWmYXo5tutejtrp5S9Yih", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2iYp6vmW9ddKDVic9MLTATkCzrunKX8xYkE4rwyJrk9i", - "targetOrders": "3UgQyTMh5YRMi2nyZfLqKkrUHn3AkmpTNSrE3L2uf9T6", - "baseVault": "5vidBcmyKxVDSdQ9Be38VY7aYxMujWJSumr7Hkpt7qYu", - "quoteVault": "5dFwHBA8EuUAoCx21ZyTeaQxFjdSpZGMRgb8d1S3XHF5", - "withdrawQueue": "4Wc9Sx3YJHED8mkWVhKPqrjWYMiteoLtTkqhXjrAGmrm", - "lpVault": "EPYs76GHTH9xQTCAiJBEMPVX4sct55wVgdA8ja48ehBV", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HXaTVivvSkjRGh7yTr9JzPWgUKCuuTvZYw9SKfp3xNr9", - "marketAuthority": "12aFqKJFxRnMQF8Sajo7hcfQanTo741oTUZe4HrwxrDB", - "marketBaseVault": "GWtu2Drh8QnNrEWB8nn9Yp79GCyhYBEB4Xrt9TVxvtB5", - "marketQuoteVault": "5b1pRRjy239coFvz9oTvL57d7UB6FBzy9Ev2E9VkxwXG", - "marketBids": "83sAuPhEb4kwytuVHGh6YhPdwWskmmqiYVwm5vu1LQa8", - "marketAsks": "B1ZfjhP8JJ2EMCHMQtJaEAUZ4bcVboA2eXzaEZ1hfg9g", - "marketEventQueue": "FHYhgARH7BvXjLPkCVAxYeLcM6Bkr3g3uSF8WXs2qVTP" - }, - { - "id": "5jz1tLfFbTUDduMD399WSeHcLrmwXhpdDKtvxdMnuzDM", - "baseMint": "SKu11EypaFU3gvr8VSAbi13zEC2CPvqbz9s83N3tWHM", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9UkP2fwtMKR9QJiuhgC1qyBVCVJL8jjXVEjzVxGK1FgE", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6Jea8gkka3hVeKRmC6HfNj9A4j3869eVEEHr1qXGC3sW", - "targetOrders": "14n5uU1fzFeWW1AYvEYx1x7rRhPw8Hin5hjs9W4Jx96h", - "baseVault": "D13NdC5Cfdp2GZHXg8UaWwkp7dFsfNUzxARxQMpnG54h", - "quoteVault": "83JacBcEhGegYSy1auor8xSBF642wELu45AcKdDfxJQ", - "withdrawQueue": "DCqMmpB7mNgNdevp6uTB1AxWVN6u4DxSxsG1Q18Uv1t7", - "lpVault": "BP1bg3b9539K3faDpJogABsG5mnKHH1S6AvvreiYyE7P", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "G7UhWAnyM2qLcfdszrDq7VAQUuaLUYJkHaRShm1RuLzT", - "marketAuthority": "DNYE1TJQ2HeXnNsjjMbgVaaXZ18dCURnzGcraqfyC3RQ", - "marketBaseVault": "5PJitbFDEeu9T1YsTqtE4nhsi8NCVucfABSy9dwtM1UW", - "marketQuoteVault": "94ywUN4215AZB7o5H8BxgqFZTFv5KRjaosYnfvJmQSmJ", - "marketBids": "71CvtAXXtTC21iAc2XM1DL6JKpdwGpYEgHD3Y9oTMoFZ", - "marketAsks": "8H2kbCS4DnvQY7okF6QtrU7W2MD5AWmn4a4HYaaE5dwv", - "marketEventQueue": "E4qdrEcC7MUDiPwnFs1FziLdP8qwEt8b74B4jPHpqQkw" - }, - { - "id": "5KecunQpSCyTyogMJQQGzaMUFqvLM3fh2kC6aBWtXQ69", - "baseMint": "24JU9sgXsCKkqk9TCpBEZS4mVJR6yMTsY7xdh39HAaEd", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "8tiNrb9TCJziMFBgZfJ7ajMdHAUpx5S7ahdnAXctpVvk", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "wMeVNQL9YLfP32JJujo9n8jNZs6cWu8mdqMxXyVntC9", - "targetOrders": "FKnJg6i9PCz55dPmimkS5KnAieyobnNEjGb2PGjjHYNS", - "baseVault": "DcxwPVuvUnWxvG4W1oAkGnJhGQrDy57ixm6U1n2gQt2p", - "quoteVault": "iQDb8NHTJeXVsu1Xo65ivJxDmxqE72Aqu4cRZyqqwee", - "withdrawQueue": "4YvVKwjuTbytQtHaqWDxcF4XVzwe1VAjtsqNTBNdECZ9", - "lpVault": "484uoiP6DJitd7mgKggrjtRiBhqLcwjjhj9KqDpraFoN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BgYQrGMtMXyAeh8dwCmWwum8mGft5uQEZFdt2AHuQdSk", - "marketAuthority": "BrzcCff1PVRG6xhFbWuPZy1JQcJrkicPbWJW1hYZkPJn", - "marketBaseVault": "Tu7cwaWJDMdSDgQHbKkHfmiJYSF1ekBtyg8GHmjwufj", - "marketQuoteVault": "CQGS3t7Q3vWHiMUtq1xo4ZhMPq1nGUE6BJ1uj6aZpPKj", - "marketBids": "4ooXYdPAAw5TkonTE9v8NSPmpdhxuyEiubpuGsP1Wu9X", - "marketAsks": "7fAJ94GvBf9HugEirUrHAvCWfNc19zRg6XZbSAP44P5c", - "marketEventQueue": "3nzvV69rjxMQSV5RAFKJ3gVHEBUQdfJEoQcgHqKPzHHf" - }, - { - "id": "5kKupH5pMHQx8mxjrN2Rxxdcz78Dhdm5ggqfWawqwAn8", - "baseMint": "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DmKNpTM2g9XjSc2ntrbrHbzh4pYNqmxtHA2hgHDpDgqq", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EDTGpu4XnnMutBqd5ycPUTFtaa2EtJLTSS1QVVozSR6c", - "targetOrders": "DtEN5ZeU1noonyfbyhPZyFoxAmVTCBaiUvxDcoxJsgWh", - "baseVault": "G4Sug6usJrDgKCCvALjHJDcUQYfjsuDSGkeLBY6GiBEX", - "quoteVault": "CJu5s7x4X4pmDTnGzpeN6Bp3GsfP9eygzKgZ4W1rzLAQ", - "withdrawQueue": "BSt1kPZTj7vCm4CiP8YXDhYCQF5GniwA5FJ2jcRyC4Lw", - "lpVault": "ASnsHebx2Gnxsoe41xJZPSF25k98gvMKtmwpPjPzVT83", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "D52sefGCWho2nd5UGxWd7wCftAzeNEMNYZkdEPGEdQTb", - "marketAuthority": "B64ggwyZnMTF81Q5V459RvtJCoVMkNa7YKQ9674KG8kd", - "marketBaseVault": "HDxbowL8Xmf6eFxm4EhWqqtCeMbGko1AfeLHz5s8YF4E", - "marketQuoteVault": "37NwDEqUHhn7n2Sj876fdwgTpAn7fwi3W82cMhHSNh7u", - "marketBids": "7xEHGuK41M4gky3LDZREbXKzRPT2eqDaaFBpWqDLUMmr", - "marketAsks": "6jfWhGTDZ6rPJrnXBtonN8bwJ4CFNhADeewNkLqxAKRB", - "marketEventQueue": "J5yQS49JsXyZKa9h34DcEjQvrVcApXSswp5aRBkxE9X6" - }, - { - "id": "5KmCYmFX5uSth4bVCMSzjsiF4U2CBH4dD29Hhcr6h8Tq", - "baseMint": "Gq5xdBxA39rRN5GsnJtodAnkqvFDQ4YxkEG3N7rS8XHw", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "KyYzafrwnfzNC1yQfn7hTQBaVHNA6YjUwWhSFiivoo6", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HUZgPtzWzgKH9PUYHwvt3dkbiTc5TTUYws7pkHjqcMhQ", - "targetOrders": "4sLX7WbaakbSSxDHX3cFVGa6CD7tE9skrC7JhmrZH1Ao", - "baseVault": "3qSCHMbCbADqBXR4vfbcmrNFPwbbSYvJDcoNXbAv23RG", - "quoteVault": "ha5uh9NBH5eN1ebRcNazKZZGpccpTfFb9LNYycirqST", - "withdrawQueue": "AjZnFDct3AK7eTmH9zYX8aeTjEj7prgAPGk57UtLH6b9", - "lpVault": "5jnqeB1CvYcHKRrMRA7FCMq5MDNSGRFmrv2B5DWJpuyC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FQoYkCzcThn4xgQCbxtdgEqTuYcS7zSRRkH6q2MQrmZE", - "marketAuthority": "CygUMwR5bso2nXN468Xbj4cPsDf5Am54SPHwTkZLrP5y", - "marketBaseVault": "CA4cZYFg74dDNz2W3zktcz3No6jBYy415qSVuAR15uxi", - "marketQuoteVault": "FQJCmfJFTSKF3eRTY41QQZeHu1JvTH9NH6S1HcqxUtSH", - "marketBids": "H8sey9EuLgAxzabggiXV9mDQtKk2y5CaT6mjPanf7aL5", - "marketAsks": "CecGMi14MdrBsgW46H2MsHZc1NsFuuiwwyrqRNmjMfWd", - "marketEventQueue": "9ZwzDwSAgtFtP5e24h1V1ba5xKpeuhoiEXAmEgPK3t99" - }, - { - "id": "5L8FzZ32UVHSCwXM8jq6Gvoam8CZfxEfrjCpefQJ3DTW", - "baseMint": "AMp8Jo18ZjK2tuQGfjKAkkWnVP4NWX5sav4NJH6pXF2D", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HjhZRbYEv95CcxnrJdd7idhf67SVv9fR79aLWfyoX56L", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5xoG5w6br9zbUr5vbeXPwgis9uZM3yNF2YY55m8QLBvm", - "targetOrders": "HXeooV1r2rgcH7uKRFfHAoXBmNp4chhR1wwy6k6VhTwi", - "baseVault": "J6s3E45b5VWp4fxA3eobnmTgzzmS8J6ZXp85yty3yzJL", - "quoteVault": "AhQm8AP4RuqC7NRXovWz1hKTxXEVoTuLZiDpAX6zK6bM", - "withdrawQueue": "FpprX6qzCJUyU2ipX3HxFMsBmQSh9ZqZkUwJgAyDgDWn", - "lpVault": "28QdjsJr5aJjGhicSgdSVUKVqkKb1VyCSLtje4JE1FM6", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2VDiUJATXD5i7YX3hwWwmC2Y4ozAj7JEEWvXvr34NV8v", - "marketAuthority": "Ce5NAeYigU1GtsFKP7srYYYrMaRuw3x7c8q4Sx9CpwT7", - "marketBaseVault": "3yCc5zAESajUBtE64S14wctYV2NFDrcCm58KfwF1wXun", - "marketQuoteVault": "HZiE3f3fN3wmikfCSufMDkDenVBFZzESAWM44HmDXWAd", - "marketBids": "EFHyrmdbNXFuSwiAr3mSSf1hgvz4z6VzhjVUADxBEz36", - "marketAsks": "45DgM9tPbvf6pJLEQcLQnzXZbF6R74NvDifPNna6Vv93", - "marketEventQueue": "5p9A3EwbWZU6wEvSUgNibS6HTRGB4uTMhWJX1xGZBBWF" - }, - { - "id": "5LAh6SJ3tgG431EXGxjfEWx6MgrBKSagjBVibCXpETg9", - "baseMint": "9iLH8T7zoWhY7sBmj1WK9ENbWdS1nL8n9wAxaeRitTa6", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "83bpf7mGFEDtfKUtozCxnhh2YsV9Q5Fn5SYQFbrN2m7Z", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2513SwTEZMaTz8PB13Fs1U4BLrVJqqumrsjyCNm4qV5b", - "targetOrders": "6Up6KKvLAMECwGHJiNmhUJZfZJGgjcnWHYYQQ564dyfq", - "baseVault": "7M6sEMLnoRr4DrzXWDj3KGeRHTuLA2wEYqirSqX4ko4k", - "quoteVault": "HXs2n2bCdz49AprHV93eF1Me4Zc3hwfQT5KLUkZQHHye", - "withdrawQueue": "AndjxcXX5V3WEkv9zERLr7fPhhQA3W3tuiWBcRBsNc58", - "lpVault": "D8MEe98Q4z3hgEZjtCFSx6BsQ4D2KxXr48NSfYsfLnNw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6aRwQtvTcHeRTtGxQRhqViwMF1XPEn271CgGEx3YAyEY", - "marketAuthority": "FoQ67GmQdzs5t28uVSyrrQ99M8rYE4BvahcVQPqF9Yri", - "marketBaseVault": "3wN7BdbxdiNmfyLpCoBiunBQ1WPFvpX6ZgHum85cKDfJ", - "marketQuoteVault": "6amD1NoJa6g1UQ8PqcKNWuQS6TXUPybUdKY5x5wZ7AH", - "marketBids": "yogMj2W6kpX5rQeiUppyx2GBbkoFJLM7XXqqfoFazrq", - "marketAsks": "67THFVgaBLdEpr5VCGN841uHE2AMVxXqZedqvuAJzu6T", - "marketEventQueue": "3h6r4P3rinJA8GddapQE2pHyaNu7VzBUipe8F5Qr5Mo4" - }, - { - "id": "5Liz3WteVe98VzQkt5YnzT7Y4Kv4WjSxvK7paWy6D4vn", - "baseMint": "GRsoqmhsS7fCLpEqqE7oRM92ag3WVy8VbJAi6KfWSeHS", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "BtvKVmtrG4ftgNXVQmVKkmq93AzrME9vHwASXtETKYXf", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7vyDm4FfMcyzbkFgAVrobERDKFWn6NTN8ERduythYRXR", - "targetOrders": "ErV5Aza5sVquzR6K3N2BFJVYxJ5ZKgcGtr2geNhaFUHX", - "baseVault": "8CdkDfPrZP7ZfU4sSbEv8HDFDkvnbURASrCSNhyZirKL", - "quoteVault": "32UU754FC5kYDytJd6nmfCbLyWUBoZfJeeznhxq7ywD6", - "withdrawQueue": "9XMvEiqjbL2UoyxobN8zP53jxgsrtwd3kPyta1jxayjM", - "lpVault": "Gv5HWSKJ2FkqSTSi9qLoPK9bPRiuDBmegd93HB6exsrH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "D8g5CUZNuE1Kcwp7dcgbEoDe56onEF4K6VfvDGQV5c3M", - "marketAuthority": "DhuxGjPSKLmKifXZso35RDsGyt3botq3MsS1y1BwUZaD", - "marketBaseVault": "AL3HK28rTyU9tzxvLegQ6MG3CdZ97fVxXyayrg2PPLFj", - "marketQuoteVault": "5enzX7a1DgNgaRBgvMwnALopiwR5nxVwJb7gRsb3u7mR", - "marketBids": "5DXw4GK7EwqMA5htZd2eLJfupLLCbXhgViWa9iVib3Gv", - "marketAsks": "14Qu93ag37LNdcrGLbdPcwHwaQ9X75zPzWssdndGPxMu", - "marketEventQueue": "AhUKkMJLGCcQWGo3tqPKUo6b37E7h5sVquRojFwCH199" - }, - { - "id": "5LMZE77WD9MVkxub6RzZNJmf8MGZpGPPkgtzictfLmA9", - "baseMint": "6wFgUMohoSavTuEneDYcrb9qF3JsYVVXyB8jb3PaXCJ4", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AsFbAAiX8w9C2sYJZ9dHdz7XCP9LbNuz9k6wJ2fXwA8S", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BrgjbF6e1AELKBaPhC5NFKxip3LXuAKtDcxZdzpwRhMd", - "targetOrders": "GML7cmAqh776VSWf5cTvPve26GqKR2hFokaDDYDnRNwn", - "baseVault": "6Y5YVg8pAbrAbK2Y6oGpYqmqQq6Lb6L4vBtqgodQ2dRk", - "quoteVault": "3rxZygfuhcmxXEiNqd25pti6fYeUGFQ8TyNLomHP36t6", - "withdrawQueue": "dASgDseqTCMQEgh5FXSkLNo8QDjGQyGtEXLVBUCDHEz", - "lpVault": "4NbJ4Y9xKRiHq9ST6GT2m5Bc83J3gJRVFJe67jp9uiwh", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5kDb1Pxep1HpEBgRGhMsVbbTNREdYphoS2qyqexTLngi", - "marketAuthority": "BWcZn4M4a7A13yfaH28hDwBbdXAx5x8rVoDGcHtfFKgB", - "marketBaseVault": "kt4QKAoL26WQcVpSVH7n1oC3cGLZP9KafLFqBrkEgkD", - "marketQuoteVault": "BYFxb63ZXJ4d2SeifXNEHYqUqD3bNSjheTicUqWFrRQ4", - "marketBids": "Cna3sK984owmT2DPT4RqLWkMXVtrSr129b94u8irv5gc", - "marketAsks": "5AKrgsDABMC1ZXsWsbf2BzuWL3VNYAwjjnSV5QwjLs79", - "marketEventQueue": "DJAdMmJK4NojM7FkqpNhoc2ozEtN8QsuWAUfXnT7E1E5" - }, - { - "id": "5LpL2xCnscuAVnFEUg9fhd9zLAiTTQkdunkoWmQYxdyu", - "baseMint": "3FYzcJvLeQubLuAgacV6sDu9Ye8Eg1vFYpCxD3ogp74M", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "6shotZFV4THggQoWXjfem7eqFs7SioxDG76xqS3t5iVU", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GBaoczZS1oiRyFsPepP4PqEuRnrc8PQY8f6U1ngxUSr3", - "targetOrders": "Axvi6waUMv7NGfPtj9uNgrUFroLm6DgnvxGXz31vj5WL", - "baseVault": "5HbsULGQPdRQQ9tjF9Uiqz7TpqmGxHL8u6XpGuxgFC5n", - "quoteVault": "AZDhugRBLrRFAosMEMqCTNGAiyTpTFHd8BTVkpAq6gks", - "withdrawQueue": "7SKhVTZLJXjEZktmhvuR8yfZ8wsf9depc36zUMKbr3G1", - "lpVault": "9VuN3oVPVTtYaP7xbbxnjRPtDt4aGskTT4fHxhnWDN18", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2aThTCnXAjTTEmtnmGQEuNCSLdKCqGQZVUuNDxjoxxKw", - "marketAuthority": "7Q7To41SKUb79L7TRJKw3HJp6dYCvNmW8z7b98twRbKk", - "marketBaseVault": "HYRcKWLHSLTas3b35t9DhCg3s7D1bRPcVWNTu785BfXR", - "marketQuoteVault": "8NgYh5aSmKE5hpr4hnwAqMqsRLCJz1zwbzNhYxCocDvo", - "marketBids": "Bag1Jgux4hr1vz2f115s6H3UApwJarAZddvYmKEVRquw", - "marketAsks": "4RGVwR2tqkvaiUCNAQA1pUK4Mg72yb4s57xHd7cm5PNs", - "marketEventQueue": "E3ECHCvg4S8SHNZvXS1cQa7ogQiWVLVejWwaSoSHBxR2" - }, - { - "id": "5mDTLQ4Ldy7qxctTMqao8gcmm8f4hzjgYci9fKTXTRq7", - "baseMint": "aWXP3vpT9MhFWDoMEYG5ssYG72dZN5Cb8cLWDLLThpB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3nP1wFn8P6kSkumPv1hCn8Eg77uWFas73bPsXwe54uit", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "F3q1pYNRRp4FxxHsLqxtzhyAjt5yWg3fZXiUDijaspW", - "targetOrders": "DV6P9fvMywxLp4RQh7vyr2QdypyZug8GgzxqgnbXHCrd", - "baseVault": "7LmKHX9vZAGgZuQsJCCVGb3mExjvdaaxakro1YmUwve", - "quoteVault": "Adod1LVRfEAmGwdngU6R1pRbCSaXQDPwcch4qKR4rvKM", - "withdrawQueue": "8FoZJVKj65aDPcMpeCqEDoexFUJUYR8vPnWX19QHjhHM", - "lpVault": "5iCmYgxjj2espDvAErM8BPX2Wk8rkXaQFvbkdwA9vUFG", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "32cm7DL59v4u9NSLdpvrAN8Yxx8Tvrs3kHVcUmAWTGbt", - "marketAuthority": "geRJK6werpTqNtcGnM58KmhwmjMjYkydiywn3zpw5rf", - "marketBaseVault": "E2supQ23pffHbXEqmqRfjQ3mZHmGZQrrw1wVhvzPf7ES", - "marketQuoteVault": "DEpn4sicEGwsD4cUkPvdpWckVGeH6GobuAzAVbcj6v1c", - "marketBids": "Hg8PNiPHUXh2hvVUc8qtPQvryMi9D6JLTXdG3h3WEikS", - "marketAsks": "AjWNWBFtE8r7rjgDwJL2CogUHHaAxxEEFXnyPnyuo9xL", - "marketEventQueue": "EeJ581dLtHhvc7DLrE1gAsYHsnCxj2BrmiraHdinQd28" - }, - { - "id": "5Met8LVEBWWq8BuYuykCFEQXdiLs68YFeq1cfUwXhH3J", - "baseMint": "Gh1jKzmxf95cT5PQabNbfJskkQU8kQ5UugfpbHSnPq9z", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "79P2dHnqxX7AyhPeVukNiV8ziHX4XpM2YVwSbMXgmqyk", - "baseDecimals": 3, - "quoteDecimals": 9, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8TJSBtQK85kaRMTxmRSMGX35nC4fZRQPT9aJrVmzC8Vn", - "targetOrders": "HVDJAo6xSX4DdZrzEmKrcWFW3DFxajhB5q14wkz4NBZp", - "baseVault": "GneNsicUdVkPEPhpcUhRiw7dXXVcfKyXsj2XoUtvXD3M", - "quoteVault": "DuouEC2LkP4JVLyh5LQWQ87QNkh79v4d1rVY2SLvw6o8", - "withdrawQueue": "89be1kTznjD4M22zSoPXhZTrHVe7atfNmwFR5uAX6V7t", - "lpVault": "7AukjkZNpNs8xKhQsJiv2esb2KTycyGfPTJkEqHfDTAh", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Eznm86SgqTq5SfLYU5jxqBWqVPGY6urfLSyFeSra9FYW", - "marketAuthority": "8jsGFDkW7U4Nz27tjZKySkbHBgW25n8qMd9bNKiyAq5Z", - "marketBaseVault": "GTJYVPeaj8hyxCpcFRAjmVF89xdocZzw9pKG4c8rzfxh", - "marketQuoteVault": "5mCw2oL8jyNuVrGNzAN89LFAVRbdg72x2ZYoZNXjhhoU", - "marketBids": "5dYWQAjaeGUwFu9fKmfkc7od1Y823UEyv4fpN2tmfr6i", - "marketAsks": "H611GkXSPWzVLL2TnKsWDGYDHd5eMgXhEPpGBACcFfHW", - "marketEventQueue": "AKaMDepBP4zJPahyLjqW8RmSGZoK7E1zzKXRcSFQhDYB" - }, - { - "id": "5MgjNhPFZvWkeVzJM9qJr5xyeGLe1rhUdvzvuLgZcsGZ", - "baseMint": "6H87YFkp5LHyN3KzDXa5r3QYce7WTcwYJi9SqwH3TXkQ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "72hs5LXkf1NM5Q1rsjScJN6S3EDprXgRsfuTZkHUfAng", - "baseDecimals": 1, - "quoteDecimals": 6, - "lpDecimals": 1, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2zEc6E9ByCedgkKNxjwXWveVhPUgParrYgkvHDc66KJj", - "targetOrders": "Cz9E4Sg9TgrjhWz38P9ys8nSrRyDBTL7zocHKPY5Syqv", - "baseVault": "AZb3brcEuExKhACbgUQTHjsKrdCwvq3fqk4K1Ar4uwQ", - "quoteVault": "3yVT41RujAaAma9zVSsSLY7XqMoFozPLVDSYTkHZnpkK", - "withdrawQueue": "AhfeUej9v3EMk8c5Vr6538SJDQWz1DYKBGuMWoPsnW29", - "lpVault": "2kEhm3EaWGVvk37PbsqaFLJ5sPaoBetoHS1M3R51jqYj", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6KyTH3KawCiY9Zvx3zfBdqfDXSuTfGAjytGFxuNN8vKM", - "marketAuthority": "EWdd9pUGBtCJEnuTwThY4sGSAPeTGpBLZqpKbz1euQot", - "marketBaseVault": "DgytfHeUu1cgdEhH3XtATtoe19RkNC9phRB7TJcoCkeg", - "marketQuoteVault": "HJDWJ28M5S21mp4Dq7Qcy1t5xVQQPrhjwieFEmRDSs6Z", - "marketBids": "Bts7E8VsyKRkGqKvVBPfmSiKm2Cp5dPmK9X5ndBbf4V5", - "marketAsks": "33YSQBpmti3A2uAzxyY3P7je26b7rwgVW1bWKDN9uuBn", - "marketEventQueue": "38tMS8d272Tod5iXsgcZZtHpd7ZkVq8mXshQ9A5TAxCy" - }, - { - "id": "5MhMytsb3XwqroinVFR7yEtEnQq4NsF8VD9vuQbQEwHU", - "baseMint": "7H4Co5vUfRGuYCHFitwCr2iCvKpv7QiRA8hFfwa1y4x3", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "A3p71Ap9vasGERWLXNnTm53dkhdDgVmasV6uzQn4fJco", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "54VLzRdUiEm3ixP7jgEqxfvgLZLqBy8U5Mo98WKjD7Ra", - "targetOrders": "4UB7yXZFqwCUu8YU2wdXxnYmMpJLP1CDLw3NxC2GChrP", - "baseVault": "B5SLhqkovDJ2bjTvYy2wrpU4ZyM9Dq9rChbQFiSfai1F", - "quoteVault": "ACq4jJLENLEsHFhJkUfewHxL2uqazF2NR3qDAEY5Q1d8", - "withdrawQueue": "HuWNXPP47QkkJYHUigH4gjUAkieFT5uU66hsRqKK2c2x", - "lpVault": "DQ9ZtnXpVFeogTbWhVrcatXBNPfak5Jg7kVd42roWsKD", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9CmHPQZgJprF4SpCWwBdsaSWU7SVasaoxwiLQL9FUyyB", - "marketAuthority": "ANHM1i6z39NXhdpvoA5d5n47vJFPs9uJDs7zzE9Xvjy3", - "marketBaseVault": "6WaJhdeotSzWtNVTbUWvBXUWkTDXPDVkbcqTwJzQnjio", - "marketQuoteVault": "Crsr5mxYDzXieLhzSg1SLh4A91XJJe9F9r1vpQLXPfLE", - "marketBids": "Dx1DfgQsTGdLbZSgYXApfktYyNWCGfm43D6BwmAEGsAx", - "marketAsks": "Pz4aZ26chQrDHKthECwRPMYZ3WG3eGxnsqTXp6g12cd", - "marketEventQueue": "E2TxxhzkQwXHxkQ75tWrkNkCo4vcQUU8GUUisuaEQhn3" - }, - { - "id": "5mJpJswPgeE6GfggTkiDxBznyTLR4w97HfnsjPdy6vAF", - "baseMint": "H7NbVyqLPHWC7Da49F4CLNTgfMfYq8dF9ktJW5wwH3Ck", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "J9mKY937dbmcLyx6Qk5VTYnhQqtgqFkmV9ybgTKwNGCn", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "H1PhtcZd5Smw3wMAwrcqG1Yv6kk7ogTCSBwJaNPcoweV", - "targetOrders": "GMc1gCiyH5nFA4bLZvuiEabmZgdmzWKN36sTK1fqNGxz", - "baseVault": "DDeU6BZdzmgpTGZVbTo1Wu16jmyRxtKwDywkr4kqXeRd", - "quoteVault": "GhD8bbAhZ2U51B65NkDuE8S3Tvyot5ttBoAzZjju85aM", - "withdrawQueue": "8WEG4TmN6PoPksPzd7DeEnXKCUyshiFTkzC4RKY7MZeG", - "lpVault": "3vsB9Wax7e3rgQDZy3wUY2BfSa57knJUo3tbCntocviD", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DyZKCU9tDRqsZyfUF9brb5TtjRGSnqaxD8cSLFuP1M5r", - "marketAuthority": "4pPEUHRBRY6TdLJc6hmYhCYeA7x2BW97pZNXu4ZMoaYx", - "marketBaseVault": "BX6Co8e5ADLc1TqJ4WnigVuGaH6cbogw6AekMBv6qsW5", - "marketQuoteVault": "DLr1BTbJg84otoyixrxJhrcdzPiJJYobM5iPDBDARkFv", - "marketBids": "FuSEou98CcHjAj9h2R6r6rsrTGk7bDwxvuoHfQPfa8hg", - "marketAsks": "EX9iD9PUSgbvxpz8N3JTboKRtqqVbQWhJ4rikYVmdgdF", - "marketEventQueue": "7g2ihLcFKVYnRYGYQ1xcPeJ9srAdLNcMuuoJpjFvkKVe" - }, - { - "id": "5n2VY2CWNzhPEDtpt5fScy2MJa6qmPfJKeYLwpFHxkSM", - "baseMint": "gmdu3snwW28DmmxCseChp9owWLUhamH9eS3hWfHG8Vg", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "439TAFfy3RMPogQbgimEjMRkVpnn62JtNqTmihWkHnLr", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6Jx92aVSo82jvDeCfF1s8i21yUJV749do7DnM56mB6Ae", - "targetOrders": "4XyB99aTHvZ7aaVDoVFmNEQZHzGVNaNYALo8j7u4BU5P", - "baseVault": "8VvRe2PNju622gBfG26JgPhvTGbViCBuFduhTczSarun", - "quoteVault": "GYitDcD4yZ14PPi2D84D1oibn6ExRQVAyNapN9McUSyf", - "withdrawQueue": "8BW7k83mfxFTiJ5ig8aRXXuqCVMjCnSxZ8vGdQYVdYb", - "lpVault": "EqgvitSG7wYLkrVx27Cx1ZLFxosyaJX97Xa8nPweyVZx", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HhSZQKLenw36HTaLdpQtoopkAvNAdNXcGvzA8ySCGvEF", - "marketAuthority": "2MyjSo23d2VNAQPZrvNQgaJr1MUREgWoHsegw3pWQcTe", - "marketBaseVault": "5JKqrby5fzQDbv1H3awoZvCBrUCCBkkzQLb33tAdukW5", - "marketQuoteVault": "DEHqjjf7cd8C5kTtQvj5MuU3MJhE3PsnmyWruG5Dq9Yb", - "marketBids": "F2haczVnAGwBPXRWcrREQjvCyAwtAXdQfrAKvZURKTbU", - "marketAsks": "99sqtY7cedYR8R4LKqfXjRe69B5BaoaAMGtaBsRSsZbh", - "marketEventQueue": "4oQaCwnk5xd3UR4Ek29L3bH5tw861GRyGiapdfxLvDg6" - }, - { - "id": "5nL8ftyNwkUjGHk652rqDMbjYKam2PQufBx7GcRemnJW", - "baseMint": "BBUiBwwG2pLZFboPpbvqVXACs4r3HrNBaC73zzXspfYW", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Rt2KfE62oXhxzbN6kLoZv1wKpuMCSdEspXuZ4HjhoKe", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Fo82uUqNM7Cg7VpqtrSg3v1B8dUm7RpVGfYdZB5W6ygt", - "targetOrders": "EThq55RSqsTF9VFWif3Non8y1WHhTgrjuEwRuk2CaXpd", - "baseVault": "FCrzzELfdyBeJG2KNuPCEcGknBxamS6yrgGtLGB3JdxG", - "quoteVault": "54f4dpRsyJXrrG7HXLzBNLeUihVUjxarWR7Re3F2WknD", - "withdrawQueue": "4daZwBhawmiNedDLVSjniNF2BguqLzpdbMWfpyhSarTi", - "lpVault": "DuBPoxFJJeMa6F54PRu7nMTNcqUTr5pjGvcVngHM12Tt", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AtUeL7BJzzUpBRsRxMojVt8zdCWyrdFcPg2v3F7jyHt9", - "marketAuthority": "arVVhtEi2ZuGR7DQ37bXuxcznJcdaH2GLMKya3kFs3q", - "marketBaseVault": "GKa6Ka7peMrh2T4B8dizk4C621acp5k1JnfzwFX7CbPm", - "marketQuoteVault": "4Ny6wNTSXCpRYW6ZRWmCuFu4SM4k2zUKJaV1PmbtTk27", - "marketBids": "6nKU8sY4quwWXxtMFzekFXKKUvQZ8KB5VgxQ81XCE2mc", - "marketAsks": "6A9sdN5VzQvUg1cKyvTYi72TLw7M2zBUwRoQDFw5YNDL", - "marketEventQueue": "4FrQ65snED3qmgvqr8V3X5Ry3Fmv2624UDeRTDCnQNXz" - }, - { - "id": "5NLeMabMyuJQUbvXNfVyUPbtYKwTXBesfmFmDswbgqUz", - "baseMint": "AFbX8oGjGpmVFywbVouvhQSRmiW2aR1mohfahi4Y2AdB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "G8oQYPCaRKFVBCVDrvbog94kvnUMwUYbqrm5k1Ygw9Aj", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HdJkCfJPpR2Xqi3NUr2QMvaYSERgaJFASBd9E2pfmRst", - "targetOrders": "CBD7HCJZnnxLZtSFz2yCxdwcq7VsiGf6ezikPnmh2w9e", - "baseVault": "GaXifgJsU9UfKqmRBcTfLVmG9DCwQDEavskaZ2Q7Vr5v", - "quoteVault": "7h8cu7FqRE3MpN9hPreCzS2qYJNDxMJfBC7Are9rMc3i", - "withdrawQueue": "HQ6c2TMqoR18awctQ488evuifmbznMQzKwbCJRke8UoH", - "lpVault": "7NG6M7Kz8Dtj5hf7TGxEWk82nqXBBG1EW7D7nDC7xhvk", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2JiQd14xAjmcNEJicyU1m3TVbzQDktTvY285gkozD46J", - "marketAuthority": "CPmzWBRrY8DCnytvwEmxg6x96opzbcFAx7Dyc4CjXMur", - "marketBaseVault": "FUhWxowvm2pQN57HDse6PbLQnjDhxRH4b1GkuzBk2rxJ", - "marketQuoteVault": "EKJov6DCNg3EmMi3XqUuCTcUC5WA53ctddqbn1uJKQ2U", - "marketBids": "5gSw24yBtApkdc4dETX1aXBXDaCUb8rMR9PQCtmNr8hQ", - "marketAsks": "B3CVAFGrGQswjd5GmXQ5fbL8pWBypZFmpL6zEYe8am6r", - "marketEventQueue": "4suis45Vr2foeEBHphhN7SSoo1SG5M8gKKfKzPhmTrqJ" - }, - { - "id": "5NmNoHBw58iFVWiXsH6NiSpkivFifgLNnDFuZHdMtQF4", - "baseMint": "BGN9c9JJxMgmm7rUqeLanYwWwo2GbedjUFaXn7tAeuXK", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Eh6DDPgaps1D11K475SBMLsNAkfXJC4ssc6cMrdZ698m", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7k8nVVuKKtDCmAZPxhqQQw5S6SW7Tb6WimuVnpQivRjm", - "targetOrders": "6TxakcRg5oheQZ5628z36CpsoKSpPSZtFQ71L2KfD7bc", - "baseVault": "5TMcQNE2kd7vUETVAEhwPyHQGdr4EAfsooc49Zs5wDwh", - "quoteVault": "Fj3iktMXW7V5PaDdWm6aB2jDqEgj9aRXCC6ya6a1ffYZ", - "withdrawQueue": "8GoUzJGFsZg5yHDdJYmjRzxGRpKmmV9YnwKWTSmmvJeJ", - "lpVault": "72skXf7imz1qibf9gVGpsxZGwwwVA64BiwgD7aZzSyiV", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9xsgnFvjF1Ru94JPLJ9zP6f35Agq8woZbuBn1WLaRnqM", - "marketAuthority": "GVf2gW4hEXLA5cq5y4ZFVhvarGTPwJHA2RfPKta1Uj7A", - "marketBaseVault": "HXXrCi775xDLENecHrU6d8zSnLdt1JJB2WnhCqg2uT1s", - "marketQuoteVault": "EZ4PUvZVctSfFwE6NbSHt7C5bEybkTAqVFmMa3HZKgGi", - "marketBids": "8orZ2h3U9nDB8L4iuSRmBapq5WSPZfzQmMGDnt9MAZRV", - "marketAsks": "HJZhn4A62ritfPh8THwQVF6vu3i4eXHvL9V5MunfERJB", - "marketEventQueue": "GJmRwDuFcdmybGjEf25JxAmB8ed1WuzquXaDsUvkPjvC" - }, - { - "id": "5oADBVe4cJwscesoTALyE3pJhpznXUsswoPAb62BZHM7", - "baseMint": "2vRgBSJEVPXxayrhXoazQyCKSGFYQG3ZdfT2Gv5gZykL", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AEThqdhJPDAdLnBWctmh1hWYaAq9CazKxULzcQhzbnrP", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BdTwPNcrorPRaXqnK9QJCAA4gwToPp3vwiQJTxPJCamC", - "targetOrders": "AgzDvMELnNUZT4k33e4v5NLhwRgMLTXreJX9MWMUn4er", - "baseVault": "CYYHCPCdCWo8uHSigeLXwR7CnnxDfXvQSo1kroFrH42o", - "quoteVault": "BLuzyPRGaGTBBz2uK4VCwqCimYJ4159hm5egiPUHHjuF", - "withdrawQueue": "BKtipNBQUxMQzqFsHCHGNrJr6QUPp7fnNiqMZ1xLJiFg", - "lpVault": "3tDkAJHbJoKqWrQPgSwAntNWpGKrtgdsea64g1krcsgG", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "E9XAtU18PXeSMcz5gkAkZ6yfj1E5nzY21x576ZvEg9VA", - "marketAuthority": "Fn5CSGWsAvCSScuw1kCjE5JdQBpqwG2iwL89hJg4A1y4", - "marketBaseVault": "32ssu1y54EZiPC9oPfN7nnLtDPWBFigLzaDJAxVwULra", - "marketQuoteVault": "HxALUpNnbvR6muL3hinMjD7iBoxCjUinXtuTxL3kY7Au", - "marketBids": "Ae2yeH5LdzoJj95fwtFA6SB7W7gqZ9YsTqsQcVamXP7Q", - "marketAsks": "5TtAgVve3fpyv4nrMcMKYzDeXtnEo3nvdymNx9A6oLaq", - "marketEventQueue": "GKG3Bj4UT31qfqzp27m5K6jZxs9jHvfPE4WxFtsY4BP5" - }, - { - "id": "5P2493uDRWFD37nfaFUEzHjdEDYAX42L9pbvQdhm8t59", - "baseMint": "Do5AbqdEbj742B2Cm8BypAGg3h1skLaAVTbT2mLRcW8c", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CYSVxWVr5rJQVYuFvoSpXNweUWW9NqvBG7JzN7d8vL3r", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GvAWaqZHducWMQ5ZEopedLA7dW64V3AMVRMbmUsQggPE", - "targetOrders": "78KiiFfR2pGgTedpEZUAsPdUZvEn23hQLAGTHptVgyEF", - "baseVault": "6jLDC9naJdWfyNPt342BsFk88LJVC7DSKPR6zfSA94wd", - "quoteVault": "HQr851dpNomTQxBWTbTE85db9YzWUH19qkc4W7vUBEMQ", - "withdrawQueue": "Uz111QymKLprJCuNyck4PzywSmkSkpmK7grQcRjKBPr", - "lpVault": "2RkaHPVnH6HVSH3VQB3TygSgeT6xZcarhooNKpMGY5ba", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "xzGRCwa2f9rrsLvYnJ43PsPak9ZH76tnfigb43oCW1u", - "marketAuthority": "2s6XhvgGkTJEty8QehmoTxgNmsdZT7ccqaSLm6svKL4i", - "marketBaseVault": "DExvk1jNJE3VY1Nvkioe1Qjx7CS7F29TBnJu42CjRMrA", - "marketQuoteVault": "9gT1kT8r7cQXuR7ytuh9medtwgrqBgXDQ1gEjkStSbnJ", - "marketBids": "Ax8SVDewqKmKEtuPQqCwqoj3TsxzaoEaXG1Bx9GtExfn", - "marketAsks": "3zDgiEhfgtaQFiJgb95C5Kusa6N61ZAAGKQ7JsAJdPhq", - "marketEventQueue": "5a14VNeEjah629Q1zGT776WPSwd3PCFNjceb8uhhdGeD" - }, - { - "id": "5PE8MGcspFv44tM4rxEg6cM7xipjMqjT5YUfChJ6QVx1", - "baseMint": "ArdsPHY5LsCjvxSxZz8f3vTkv5qoYihmCCPMYvr6aQza", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8iCzQCY6RHkf4Udib89v7BHDx4cdk5AiKePoiLoFKH3z", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HAuuYFUwpLU1yp5xFJcdQfxHs3haWkstFwgDwW2wFADL", - "targetOrders": "5kjK1LEVYoWbiM4ydZkuaHxk4RidrYJzBQkxYvaDJtBD", - "baseVault": "BnZmWHBTHBfwfNYGyEBLB8H6HDcoyYE6Qjo2kxs1BoVn", - "quoteVault": "5fBqjqDvaPLV6LToPUvucWWWvjDCxwGQguzcCTWFxids", - "withdrawQueue": "4QKPA5w3XUXNDKjyZT4dbTxb6hADCn2Cvx2ZwUjUJUti", - "lpVault": "YjSP6Nj6sfBZyR5sH9avSggGbZwvezH23q5nm3jyEmZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "J6XHjm9JybM9dMoaT9D5AfVigR39UVZUoqS7UEZ7Uo6y", - "marketAuthority": "2MkoKkvDmo6k9xwLVqkzMTVqMVg2RHnSCANv8KhYxmxj", - "marketBaseVault": "FCyzR5g4SLLK4Smt7sxR3Ky2UhmUyQnDm3KUFsq3HkNS", - "marketQuoteVault": "FcrPbie3xkpkAHjeNmkYWhiNvQzofpkBvHwgo84B1uBK", - "marketBids": "EYTFHGb9ASJ8FzgAeYjfEWXmWnVW74ZGGP3u5SkwGeRP", - "marketAsks": "9tENF87rNjduPX5o6LhMr2DVAmc3YftXxK1kTGULmhEF", - "marketEventQueue": "cZWiVnLPNFNS5XFcZ4MsCDdL12pJ2CpoN5pipSfr3xU" - }, - { - "id": "5pJESWr1RG9YZNFtbVtNWXnrtWxf32e3hVuNm518Kmis", - "baseMint": "Hxk1ns5V8Lq41wzLjvq8pvNEhGh3FcCTWbawbj5SL4jj", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9PtjZvozrR5QjY1ppUzj79Y2zfQGdFy6CnmtrqaX5Fxi", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5KQbGm2ZSLx7yyUQK5sNnU87ngPmtYGkwa97A3pu9Wtx", - "targetOrders": "8BNWGTaCv5bTvHzQnHF38wNth3TjaFg3EDJyw1V537DF", - "baseVault": "DdZiEsDp5mWZVQ36RQsCYVNz3T2Dv5pBG6HySS89SdiR", - "quoteVault": "HSsek7KH5PsAdZsTPfaaKCbHuZtBNofBdxvP6mPHAHVC", - "withdrawQueue": "f8SoFLTj62x94NHokahUiiEi6HucDX6etZveLf5DidK", - "lpVault": "G7ZwSJ9w13yYHkb29dCKLZT3TzZHJ1syVuK5YctPcqC8", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4aiVaUsGXpDSCrcWfix5mbivjNfprY8YJq7ZK1sZPHur", - "marketAuthority": "ASi6SyBEqoQXo6j44NzjEwmF5P3rjmS7T7h1Cgm2S1yR", - "marketBaseVault": "Btyf9jyqwQdbBkiY1ghYxvPogqsD7SQw6oUw2f9jX6s", - "marketQuoteVault": "GRkwsUu2Yt7JQQbPcnj5mkdPMBjHKwkwr9b4zMkqzBzh", - "marketBids": "Awzaa8TQaeqDujGk1v8AXge2hy9PYcg7479oDiL79bHN", - "marketAsks": "G8Y3caDaw4EXRXgW7W3mDknDcLxz3RPuU7y38KGKD6v9", - "marketEventQueue": "2gj4rCSNcSpjkCRqLf5kPRuQwYh13PdcZR9grnz1qY73" - }, - { - "id": "5qFyj6ZGVJyzRRkoWe4wjaAVqhnAhnkJzVR7ioGLAeM6", - "baseMint": "credTHXbrCuzmy4M9ARGvz2JoSJWg8LByPbyXBhNyz7", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "FAnLhVgBCxEipmuXqXAZPJ1dVcLz7aUUzugBEW8PjALb", - "baseDecimals": 0, - "quoteDecimals": 9, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "51FdB9u3FdB99L1XZUVsiVBQRQ8s5TrWiE2RUZCn6Khu", - "targetOrders": "7mDBehM9MX5aKgBoFXLJR9sD6Zdq3fiMx9LxSsarguq5", - "baseVault": "FvCrafaoRVT2Wz8jZ5EQewFnTjYhcyYqHx917zErxXJN", - "quoteVault": "26zgKY8gxbK1r1TGmK8ZbEJDoLqqPpF1WLYXTqu8L4SB", - "withdrawQueue": "2xTRXi47SumnjvtBpJYBZLuzLrgb6sxY45zK2cirxcEK", - "lpVault": "GpJocpv4kcUEEXXT6otQ93ReSSRMZtG2rZMb2ndD7Vfu", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DBDETTKfiu2JBiQEQUdWB9TYTne8HQ3XLQXFFTFyAFXP", - "marketAuthority": "3GKeWpzpojHxTmibDFv3EU9yRKZWNgUkdpi8bSKbk7Uv", - "marketBaseVault": "3opRTgXdnb2EERBbaVwcdVedHkcJEPTvYba48aus7PBS", - "marketQuoteVault": "9SxDS7xm8oJphd1aH3zXVyjyMo7BKMv2yW6wiHHAZ5cV", - "marketBids": "AL9CyKY9sy5RWSWu9oKzm6G2M8mtJX2QhqhYrqGFzKQy", - "marketAsks": "6czmtpca67a9JTtHyaBc1Jn3NAx4fZ9at7vwcdQ8KshJ", - "marketEventQueue": "E3Xv26sgdZXy5wdnL2LwimsRo8xR5nwXdYsHjmjvjaKZ" - }, - { - "id": "5qWcKC8kRJGKBSoKnHb6tS2bWE42zzhQvox2UTNfHcJN", - "baseMint": "FniVz2YD5hiGQ8FQAosUr1LupaVxx8wifYn6XqJ8m52v", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DxszMyyud1owYd1VF2DP3XV5mRWWHGSm614rQsyxNz4r", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HAqtooV1irkeszLH6wLoTZ2m6DVbDkXn43C3R8maVXo9", - "targetOrders": "38gDki6m2c7hhULEZicFFoxarNKx5e5fzwnPWVdUUD3o", - "baseVault": "AzqxrYWcZHsDRrGKgpoKojEmczofnBzdmfJr6dSt7yuN", - "quoteVault": "3kkZuYq8D5PPAXdrFEytLHLiovL8uoWyGZKP4nyNcod8", - "withdrawQueue": "M7cJDjqfZQCSacE7G37PCkJeYc7UZKbHCxjAmeyrEAJ", - "lpVault": "9NXWbRtnMTvuMGdTRnrMv5mqhS6MhAGfBRf6PbppRpwA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EivRzmWtrRGZpkhoeQGHCA2gZtttunVJWgEPC2vvUYDb", - "marketAuthority": "8pbuomdxggiGaGDUx5XZsuAJZfzPnmfmr7F4SFxTGHGd", - "marketBaseVault": "8z7Fwfkm2iWhvdVoZSsjiZAzsVoSRLj9XEf75Ao22fuA", - "marketQuoteVault": "8LHDmQSS2PMjKLQgSrQ4AZ6hZTTnNna8a9AqitwdXbQy", - "marketBids": "K3HuZJgiVTP8e4ba7NEgkmenY52kFTcBSV2fYrziS8e", - "marketAsks": "B7hRgCAfx9eXwkPaVq34rzbBG51PubBnekRis6LEydxh", - "marketEventQueue": "2bHrJ6N8fqfgMZce6NdQoPMnbfJqStnfCEpWt1GdNXem" - }, - { - "id": "5QzPfajqrtachtDNRfpbAHVESQNzYNaZkRFxNXHz5bUf", - "baseMint": "BgBUxRsEgXur2iyhhJnWwbBMiSNiMWz1Ka5TTgVRt2Ft", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8VgzZXqn52foGKiCZeiMNopQSAeiAMeVpyQU62JiELbM", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7nKcZbsP9wcv1RPtUaUT26bjJxXSJZvoSskaQNJCX5Py", - "targetOrders": "GzeFsDxSowiZPA57ucqyv5kmpKNmHt8RaVTsCkgx1Yj2", - "baseVault": "HpWhH8EPcqrk64nn5KCA5oASwziwbaueLrQyufGaTURY", - "quoteVault": "9mvsqitqDPxq8uhw56j9CqUpVd49gTLn3Y4pkn2aMfmR", - "withdrawQueue": "97dTdK97pHcFu5tcgxPs9aa4Vqe1L23YnT3C6XxwfBQp", - "lpVault": "6vci3t52WykM16oj2WWkRLdzwgfUaJWFFffte1PRcuNt", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8HqP5WQ7eXg1ssC629SCxLsDeBY3m4JmgPr722VqYnSH", - "marketAuthority": "2gSR2qJVBcrEuSZZCG5SHEySGUhWtMJ19bSNxBFxabZf", - "marketBaseVault": "6bYC11JGrzUTU1Q2z6fSjZh5qvxHqhg2B7uhWe6oPUEW", - "marketQuoteVault": "3sJuYJs74wKtbaYx4tcyhEmWTtpR42JLz4mLrtT9z9kV", - "marketBids": "6prTm5yChdQGRdmqzTbb6c1Ri3gRKpMtfyJzGCPLtp7P", - "marketAsks": "fZHMhDz22fRnVVmTNh2LHqEFu1TH3edJbEkjj2u3t6B", - "marketEventQueue": "7J4jExzw41C2XQp3MAY4yie9h2WgMuujc6NYtKcJxSPX" - }, - { - "id": "5rE5ZbqbK2sadkxqDdKd4xPiHYZqNNuhSsFwCKg3X4Nv", - "baseMint": "N1CfKy2UEQmvQeQgELMXuHX9KRGQa6ayTrYUSqsL7TG", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6WrN9ST2kAimcohnDQXDSJJzxVVhU8eyvLvBrnrRxhSZ", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2t9k6LoxuJpGMHxt2bYhCsMcpt31MFbGf3asG4cpzx79", - "targetOrders": "6vLGfjf72VXwHBjf6VWnZTbEzVohUNi9fPYRXh8zNiwy", - "baseVault": "D3vHgtdy3q3A3MypJG2fUMZ1ggirXCp1LnEc6hjMaT3d", - "quoteVault": "3KpLdw9azuyPQGnoWgYPvyDo6HCvLvkpnuMRArav9d8v", - "withdrawQueue": "8mDaLzhUAuF3LKnsCH3269eTAzLCbvj4hcA3JwLeG18Q", - "lpVault": "GA7d1HxsGcZWiWwvfUY98sYJdsVGpXUyEGqAfHZAjkHP", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3SBGgf6ybj3CxCGKnNFuA2CCHNLRamgEyCEgQuXa6pEZ", - "marketAuthority": "9t5LpQapWdhVX6snHMwrVLubhrK4JS2LRgVyRd8FMdcP", - "marketBaseVault": "6555MTGdRzaW9S3kzVf2Ptkr8Z6EmSUp9pjyHJxM9q4s", - "marketQuoteVault": "G9V4zxCR1GCvXUVTF4dDTaKJUzCoQG5vdMNP6JEovqZU", - "marketBids": "F2PU36qb8k43HnMKixzuNUp9txy3fvZR8didC9BYjJa4", - "marketAsks": "73rRPX6SRpxYiFNxCoMM39bChM9KQCDY8FLgX5pUhDr8", - "marketEventQueue": "CHrATzyUfG24ZXUtRgLoxwprcnivTnFrLBWu14VCdM8z" - }, - { - "id": "5rie3iZiqPpTXc6ViZ8x5HHonHRLUUfe24wctyajvsLY", - "baseMint": "6fMoTH7Bad61GPzvqfq1XmRGFGv84MrvZfjDKGNuVwBz", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HzNMgJLxFeVRonpgaEXecvT3uQ2ttKi9xHz4WHao6eGi", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8eHgtHR8aXXkKcYAfeA7KX97rY6qcvqhNQunQdonJBCg", - "targetOrders": "9SckFugN8raYvWvENspMcXv815Y2UE9o8DAZ8orL7UuR", - "baseVault": "4AqYujMRZbfn5zqPmU3VqCoCj5KpBXxXFp6yw3yZVeDa", - "quoteVault": "AuQadm1EFpL3vMr6bL6K4cGs6R5SepYFHHwpRsixpt6", - "withdrawQueue": "AN3dVJgwbz5nqwdEs98ga6ymY7zMsjKVaNK3atDqcM47", - "lpVault": "GRBZ2zb7NDVn2MH5xMHSZxppYtvi7HBXypQmkPnVX1Gh", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "B7feZPwr4gFoWF7pzYkcyTCQbF8bPE9wd7FBiKCXpbtm", - "marketAuthority": "9nGF2CUGMrdPGaWFTL5wVFuuMVLpB8ASX1SF6WzKH5Ki", - "marketBaseVault": "59tfPmDmhjUjpQQXWEdxkQmHsnD14LSHtrrgroM2AGGA", - "marketQuoteVault": "APrGyaCHM88p2yfdDUfgRdLjcVyZCYNerWmr6R3a64ZB", - "marketBids": "EYGNtrFnrvFk4kvVgCxf19YpUqgP4n3MaawkTNpejwBv", - "marketAsks": "GnX6MKZXNXrrXdVj69W8TA53LbmE1qCV11N4iZ3BJx61", - "marketEventQueue": "9AChiSZmArsdx4e2g8ZVrjn3rqA5WakvcjjZsVUJDYJG" - }, - { - "id": "5rsUTRPERNWejd4icM3y97WJdRiyiDFcNxU8nnFmAhhj", - "baseMint": "FaiPGacTM7YBmacumbg4ZnDx7sKtGcG3LkcVoqfddEA7", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "McJFumVcJ6DkQQ64h4mKXdK9mLZzBXV6UxDNREPD19A", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "B95W2PrRrEwHXnv3SiS4SvBg5W84maUjsy8omZpbAxW8", - "targetOrders": "4eDEonuRwecqp8ZfYyNPYNrM5xVGcCTCt6TFbuueqPq6", - "baseVault": "8FaTYA4mX3xXh68ePk4LnkdAtRZy1FJM1T4MSHbTxY5m", - "quoteVault": "FzXuggFPQVQriHZ6bRU4YiFKj7UTaW1f9uvWWrUZBbnp", - "withdrawQueue": "7ByMXNUc9UquoxeuKwx3brCcAZqdzbJGQdYCcdGoqUCq", - "lpVault": "93Ao9KWnEisepy4tCwovKCck1xeFg8QZ2THcsM8EYJJ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7oFXusrpvDzbY6gMM81RjS6YEALETXTwWdUKXXBVojgu", - "marketAuthority": "FXNh6nbAKEkAGf3bAnMH4fiq84hJhBuZJ2E56Ty1pVeA", - "marketBaseVault": "5s3mboAgaH2jbrtq6h68oduPEvGtp71aHvapPTiFuK7B", - "marketQuoteVault": "AquoU8SXakveqAbSndo3jL8jJ4jgx5Dkzv4hqKzxTfXp", - "marketBids": "7wiqSSqgDtiERG2bTf9H232yCFVXgsin6H7aW4uWGTsL", - "marketAsks": "GjEfHwSwUU9xCuytHH9MyvBX55L5DDYQYm13GrZbyoHC", - "marketEventQueue": "CF5SS3ZTFAcaWWKuWSsMPhthaBWAqmMdeFfxtwAQA1Dg" - }, - { - "id": "5s7Hq1hoHeCxzZr1q4DTmZGx4oRkg5mkfj1RfXFBomLS", - "baseMint": "9e6nnqbsTjWx3ss6a3x7Q9ZvpupLNYLb8cTbVmm6UD2K", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "AQgsViTi1NaKyYqN1QGhLhGE1xQVtFKDUPG6a8T7DVGP", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "23BRrMLASw1B9sw9gFgwZuNvmKdn6bF9ZcsByMxgbCZV", - "targetOrders": "3Y9FmCw25rrq9DgthQpxfze8r5RT75F4mG3oRcCwEK29", - "baseVault": "3HbjPvt3KecRuQZr25tjqht1txAb3kYRH9Bo9ihs3MXj", - "quoteVault": "5cuyTFdEjLxBXXW9cFFH8Nkkq9L1KgvYUDjRfwdrRBJU", - "withdrawQueue": "DUb75F8cr5UmzAdysLbno7dUdcNQDBDJ5himj6htbJY2", - "lpVault": "6DGWXQfEPSG7LnXahXy7rTt82MY2y7vvsX2QGEfXqReE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6QnPj3M65umTKRwabxxjHZDRgFSzX4f7KBmi6CJ8httb", - "marketAuthority": "BYRMmHioMM3wWJj1Z3ndjtvnTFhTFm4cZN7sbQCXyTDQ", - "marketBaseVault": "5wc9qsivTmMKjSwJJdoyUDVeeqMRfqQ9Y1s81Pa6zjCm", - "marketQuoteVault": "2QC25jkJW86H1SZzdNYg5vGkywigp4SGQ6kcUzJEG5et", - "marketBids": "6ToY9tinCP9Yu3Xp2iv8hQMFGtpwMgEZb54d2N3ev7rH", - "marketAsks": "34USxTpaJBDbUxJJYhXEZmFZToHzKTCtV5uGSUzNAeAu", - "marketEventQueue": "FbGkSfY6y8QAiFHY37yGLQ7jBAHsCaPB7KBrBc6qpUp7" - }, - { - "id": "5sA78U9wQieXxRGMvMifUAqwMo48gyX697GHpsYNVhE2", - "baseMint": "E1zxRweqCWzviAraKjNjqupuyYTzm1bukJgb8KiBN1sN", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "J1bj5naTFHqhaMN7FLvrYNCN2UYzYJRmL23m6fEtxPui", - "baseDecimals": 5, - "quoteDecimals": 6, - "lpDecimals": 5, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5w7TyqPEBTfRj5SUxyZU8uTuGinM7KHJuJ3mQU2JnS9w", - "targetOrders": "Gdoxb4MK8vXUrxH1qTNu5gJTe3cyCtLr9AzmTqcseoxd", - "baseVault": "C4Wyf58kamTZERHCWLrJnP17MMas5ZNJuWYiZuh7Zc4Y", - "quoteVault": "EPbAw2dYZZn5k5qAW99SE5MogUWSY2gBZM4ithTRRtkw", - "withdrawQueue": "GZijpU5QCvBV6xAWHGcj3EEG6d54rdKhYSjHZWRTbgX2", - "lpVault": "CYAMXRUnascp6chqxUoQavyu6ctKjC1f4HjFS5PgvUty", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "H47iszaPjs4H6Joxw1nsgJZCRANuVT6AeZfyxoaqmAxe", - "marketAuthority": "FMbAjhCgENDhqMMbyoLcDHD8U4Uf2bBiPLGnjfppqVBU", - "marketBaseVault": "FHDXjJhxjQfB9bvsrGLMAui6Xr7wxUCHrtPCcE4wCk3i", - "marketQuoteVault": "54ToMMqidqvT63QSCihmo7gcZZz8ixvs7AfM2EMTPSCZ", - "marketBids": "BtStbDs7PKWrHR8PxCceHS4eD115FUn3Ku9NrbRumFne", - "marketAsks": "2SJJiMKsYizT7JmaxRFQLtBKGycKCttKQ4oc6LFEV8VG", - "marketEventQueue": "AW7NYbJZA3NvA2DGjbSyEh4nob2Lqw9FRgkZ4xgYkGWD" - }, - { - "id": "5t8nXfgNFUahR5v63xb6NxWKDqz5Bubccbwy7d6xsjAt", - "baseMint": "6frkvZf72wiz3uqRWhBqLftNU4PS6XXYCoNrW9P4CFdK", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Gdg3UBAT4FFRrvWriVTqUZS1EWr9xnBB7spXDDTCsqGu", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2ScozzjpPwoq2APfzkVNQZ4A1Fx8xP5Te3kbJnGZk8YD", - "targetOrders": "DPmm7XDnECHVB1Foms2WmuVDNXA6JoBgwPMRdaB8vBqT", - "baseVault": "7UkFWPVTWDtknvYb3b7CHNtPqaMsThRmVRQEosDcfm2y", - "quoteVault": "4YgcWt4kQ3KKfMf5wPKt4jDSCpeRMv9AMEmqXSwmnk9Q", - "withdrawQueue": "w9biEohWZDrCBVzLC45abAtsWoLejz9b8qrKufW4ciN", - "lpVault": "AKTKmrtW4mGLzCk3M4hLmisFaFcBp7ef1G78915fo9hf", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FMhTzjHrzpw5Tdyo14hYy4cQVEUt2g5NSbCwiPfbnGG4", - "marketAuthority": "yiSvui33QWcQAdpcYdiG7gkLV6vhSDXMmH2s5ipcNAt", - "marketBaseVault": "vr4unB5YoisDma3Bh8egnes95XH2UhqqKhRUVFTohLL", - "marketQuoteVault": "3HjQZdVZqiJ3QeUttQCm8VEtdKGfww6ESXbUWY9Gbnf9", - "marketBids": "HKyRE4NKfkGLBJ1oYDQ2q1j4aqMADtRY6A67QaXu9e3A", - "marketAsks": "3ekfxczT7VkenHLqzup6LJSYM7HJvLeZyGasc5jxcef7", - "marketEventQueue": "AWGBTMMWLbpgNCEsBtcWFRBto7tDATPMgwgH9MiqkAxn" - }, - { - "id": "5TrkecwH9ZtiGyCHGARMndAbuYQ7RHx8UGgZSQGs45w9", - "baseMint": "v7bs339b8oqXgYGJu4mX9cB8tZrFVSozBjW6QZZKE3m", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "PEtEeSySswK1u5AgiWFuse73gRWPFZ6j3sFgKYVyG5s", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GFLy1HNEmrZKfH2uHc41gQcCZj4rnmiBKE9EnvKmPh8X", - "targetOrders": "9b7uRpPMucVaXXiTxgjTD5fTvxVqXu6QW8dyKgRmcmjo", - "baseVault": "iYzRiNcKjmfvxTTYJAzyxANJyJNpAN2Loa8bFdYzJue", - "quoteVault": "4Up59TBSXFr3G9txXLTaziMfWL3zU5uEmQgJRLREmMKq", - "withdrawQueue": "BQ6MxjTWzATrAHUxcbneoGJ56S36Ci6TuBUE1XJt1TLk", - "lpVault": "CZ9cSCEeZVj5ZqvVH6S5tN5UjxXy9zhy8SzePFg4wmFm", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "D7wSJSFM9ozAmSEnvFvQKs5oUEEqg3SHYj4N8484mYde", - "marketAuthority": "3DxSwk9Br3311KBd2cmHd7EXDdqrFeyewERTqf3rhC5k", - "marketBaseVault": "Xcd19cxaAQswBomxuJM5rAgcq8GpbPK7ZVT3dzH3VgE", - "marketQuoteVault": "FK1h7sHmhLRJ6WoT75Mhk9kWaRXwF3oAadRXMo1fnnXn", - "marketBids": "BvDZ69WokHR9mWn51EcT3yNvEtSUCQ5JL8XuwMvvQDbS", - "marketAsks": "CBQEYHg2j84j55hEkXg7wD2HSNhawv5hggBMYsKwVMJe", - "marketEventQueue": "DPFyTiJbWy3K1UcP25TtSH5wBXokK5occxK1F7SKeZgj" - }, - { - "id": "5u1zTvrrRHT64QMqHX2osW1ugD322yDGXaMuwg6WAVLr", - "baseMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "Ct3gHS6qVxjwUjy7c9v8t7ooVUyUjvc4ZzN3QUff9v1C", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EAnn3fm5M32m6rcHKSaEL82H9gYm7MvB3JSnrnLNkTJF", - "targetOrders": "A14hhk2AtoQ7afpuYeoo9MYNrDmxQsYN45Z1suCPXVp3", - "baseVault": "JszJU1tKfHW99dirissCH54jfM7tKoqDDZZb2vkDMgh", - "quoteVault": "6FhDXfo7zEQk2hUqdsURUBUbnF9xrbyayKWM8Sr4axKR", - "withdrawQueue": "7TNcLbv5FFfhY9DdoEEuPYRZ6VB5MqXCNDfK5fNzzPKP", - "lpVault": "7PBCio4vuYUXSVFrpuf7nHJAAjTbsJ6EVcSRwFyYQirK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4zBRudaQMFhA6bC4zBp42MdT4o5utVQoKBctYuLZVxmu", - "marketAuthority": "HK7XLkGnMDfZCXEQmMhjxroZynMUaoDGpA4zrABNSD9m", - "marketBaseVault": "CoirUxRJPLrbaeCnX6YJ1VE1jzeqtvHZeGTpppFYYRC4", - "marketQuoteVault": "HK72ikUtxkdAFuV3xi646FuPmRwJyDEnZ4fWAcwS4GRF", - "marketBids": "CVLuHrunYJtjXcARSWcmjy2ec4NpbKXXXfZg7q9857iv", - "marketAsks": "4wa82YsMMtXaYSoLUqDhvTiViBaotG1TdeF34nw3z8bk", - "marketEventQueue": "A91i6zYQ6SE58BUxU3AE19TcvnCDQ76ZZ6bw4PGbjXD" - }, - { - "id": "5u5UCCq3DwbXyB565m9gqvkEv7qQXK9mkGYDW96LYN82", - "baseMint": "AMzmwvDRKdt5AQ3m1m28tWjzBxmQNe1PsmHnYitVZwzp", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GsjZPVZ11y8TGZUaT1MeKjkFMMjYty1M2kfFv2rMjidF", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BQ7Ps45KpwvR2rSCztFB9KxZMA5jonk6XnVYvk7teT1F", - "targetOrders": "DMLRhzEh6rLZXC53oS6yVABgPrUF3MHWoDTdupfe6TiZ", - "baseVault": "4T1LGEAapCHNhq5hMv2RHKpTvKBr3MMwSMcqQw1pktzK", - "quoteVault": "HSN31gJGSFXchwoqfKtSFifNbDMLPkwQwjtSQXya6uD7", - "withdrawQueue": "z2WuimKvYLcVLKEefY7ko1t14yDdLvXUXbRLi8o9RDN", - "lpVault": "2vH6oseQAQ9sDTRQGQDR9qYH1J1fDUC2ogChDYB5kobv", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7Z26iMB8Y3cyKV1bPWTCdot2s2DJccYi6Scf1mv64iwN", - "marketAuthority": "HtQhDeVhTbAtRmH9mDRZKAztMbbBdKUfLQ3tpAjzEiSK", - "marketBaseVault": "8A8ePK9kdVcKvHkHMmoYKsCk87L5diNgkm7rYyHRWYrX", - "marketQuoteVault": "ZFx9VMaSp1zzDgGGWr4xEAGR52Jzkup454QBq8mJHaQ", - "marketBids": "LG8tV9tyuFCctQZh4B3aFjDmExMswgTCcM9FfT9WWtT", - "marketAsks": "FiPxeuzcjadmXXQr8iFjthQqa5XXCk1tbo3HtUcQt9JP", - "marketEventQueue": "BQ9TiLm7Y5Awqea93L1ZCGq2SmUtbr4wWYdEnNcAbcLe" - }, - { - "id": "5ujaD6HFw4292jaZoBHY5ZpxvS3Ee5G8hr6pN9j2gg5j", - "baseMint": "9MjAmgHXbu5drkNa9XpzfozgsM5Dcq6bSnKZzdNrwscC", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5Y7Z6gBUYbbAAyTS4gkSygX9dmivaskABMPLCwB69EYp", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4HWKG3FmsPEEfUh95EP8t1HsPk2ncAL8k1sKozwfPhUd", - "targetOrders": "62iE4ty1Hw8LVZzn6nnsYRKvw9NRJDXy9Avef8Cnjgfs", - "baseVault": "9ED9NmhNzmmnjaCQ9XVXDH2e6tMKEspo6wLDbMzovmXV", - "quoteVault": "CkH6hHWEGeXrjtXVdPexDpazpQov6vS2QsTfYjzttpAz", - "withdrawQueue": "5JnNG2GpsUcEE5gVYpLB229X8vEfxH9G83sM1vACGaaz", - "lpVault": "133ucebPXLct63cPe4BirpgWFFxWtAJxMSfPnBmFcccN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AXERgMreWNVsynhSjLGKWadQqMPhHWmpJixHcRDF7s7J", - "marketAuthority": "Bs1tN2daVcPnk4YdQbYixLajATrXXa7rEaa8mFKM6vBw", - "marketBaseVault": "4ezaAsqjTFgCHErAgxCHbsvjLNwBTCfZPifa6oUEch8u", - "marketQuoteVault": "GoB6r6zQMBFV9JpGCQhANnFW5VEaWsG6yDBfJV27xbJ6", - "marketBids": "CM6U7V7eeZdsTFZZch8yVpVj8PPp4EaiS4dUnkmwiu3i", - "marketAsks": "2czzvw65S2PdEsgkc44pAZHCQ1uLAqMuz4yVtbbNsbk7", - "marketEventQueue": "GGUfqswtEe8YCHscEQpzThXgyJbtgrAXKcYkRxvms13T" - }, - { - "id": "5VgxW8MBCqov4Yne1C5nq1xQfi52cV1D3SgAFRXR4JyG", - "baseMint": "CcM2KGSi9XSkbg1mR1szTee2BDazbnW5Qy4prw9zJHFn", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DmLcWYMuHFkPLXMQ1E1ztphadyfdezdRPRN9sjoECEyf", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8VsoWFC1xRFPFCHtq6ECrrfWaUP4PuegaqYmrNZskmuE", - "targetOrders": "B2Mt73S4zuX4429YGnYnuS8eexL4hKwNkGbeB6hx8s8c", - "baseVault": "CkrSSBQqPR43TKRPg1a83Lui564ihC4SC8tJEMXaQhkD", - "quoteVault": "EG8wu86cdTWpzyVTsvAipgK8aUDReGtUWDP9ZBBhGSmd", - "withdrawQueue": "4bn6u3mWo8uw3GCzyFLZXM3MSwiPuSGDgSLvkdfSd3hS", - "lpVault": "HeZS6TncX6YxhVXmtsNXXCJLcvkcKbswAza6Tov7Jm1m", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9RY1SyWUfhith6F5ojMoSjfFVAWV1FBSR6FGiUiW2B9V", - "marketAuthority": "CE1r5KEvhHqGhUbKmQ8KGLhnc4zhJjQ6qvX44Xe8qhVJ", - "marketBaseVault": "Ecz1YgujJunEHkrh45yDi6RUzV5Drnxio7EzEggWm2Nu", - "marketQuoteVault": "CCsmGtac3y5tf7jVibopVisygtNYkTGUNtsGrg5hJXHu", - "marketBids": "ADFzG6BB49h6wTy6TppuYUy4m3UXmZz4wV6qCbBTUCk5", - "marketAsks": "G2Qhbdv1FjjEVhjQDdC27r64mYBq4dT7tH6MsxPSd6nC", - "marketEventQueue": "9c915c3rsWuvy4bgCe1PWphcs4CU9oe66rGXUEeBVTMf" - }, - { - "id": "5VM3EVCdPLzYiZj7sif9ssBu8yXywHJu5JeEjKsSXGk6", - "baseMint": "GHvFFSZ9BctWsEc5nujR1MTmmJWY7tgQz2AXE6WVFtGN", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FRk97KQW5PBQ2JJwoUftERPFQVMZjo6cmsLmTXDWyYz2", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6fftr4Jv7WptvbbSRM1hFDGGknDcvi7Sq12Kp7Le1No3", - "targetOrders": "CBc7j3LLMerHDYG2XUtHX9MkviUt7vCRr2kwZcR191Ds", - "baseVault": "14Cc7DnELixAbWUKmRXDK6x6kctUtpNxBCXaRRQgunjc", - "quoteVault": "6jMqxW8YAM6ra8DEmne6ap2tBQZhSCU2pvTHPEuVqs7r", - "withdrawQueue": "8xZPkLZ1M4LM4ffqJgPwHVkfz57Nrho4HqzM3Bri47o7", - "lpVault": "GKpfjz1nPh4V8E3XsFUsnCh1B7Txhvz1eHfs5US29mYi", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4zffJaPyeXZ2wr4whHgP39QyTfurqZ2BEd4M5W6SEuon", - "marketAuthority": "2BX4pErQPyGPFP7DReXT345FyU96crLH9F8mNvamW4vo", - "marketBaseVault": "AsZ34rEBBCNgK5qff4bgtLKXbYeiUWrNFiyUViTpsEmn", - "marketQuoteVault": "255VNSLW3p77tfPfMZUixVxTC2AUaK3QHrYnKiANCPdP", - "marketBids": "4tBc279hAPA7A4Uf5ufUwoxjRq4CD2JxksJKwSSBK4E4", - "marketAsks": "4CxbCgsLj1PoY9PE6eSjL2xa7w9mjLjw7FDUvehx9chn", - "marketEventQueue": "5VXWmKUo31Z25M1HskbsjSkHos2bUS1f1vj5yysAWHWM" - }, - { - "id": "5wGhobCq32hSw88qVXi69UZQMjjXtnmai7aiW2bdDMg6", - "baseMint": "EWL2aMkx1j7XcjdKniVMKmuK7Vds3CgMXJv28HohVBUx", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DDgiVSLvWXkMKgNi16UdKWQuk6GorRmCuVSBXYxBdWD5", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Hym1cANhM7pTDhjRZhD92fx8CPLSoeW41vzf3HuyPdR5", - "targetOrders": "Fbta7k5FiZEoiBTTqidsq234t9D3V5uZrednhvic76Qz", - "baseVault": "DKAVQe3tVboV7n3SgJGYNyTjdPyTSALMqR1uoFo8BX3x", - "quoteVault": "5fC1e7J76hZdfoELtBQVgC4NzbWBzRqj7QfrJtTZRtRE", - "withdrawQueue": "3NJZ3eVaBcy9K9kaySRhHtcFVmiUNpuvrBLtzH6o1bER", - "lpVault": "G8gLqPaeQ6sxn1WtC91hMTkZm8yMHYMjg6jg1zsUnBto", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FjqzMbBs6U4QfQeJKuuDMf2b344fLMxXP65zDdkLi8bq", - "marketAuthority": "ZNnn2coNkaBXHrdG9AdJTEtHRh15N7M2QSnbVW9583L", - "marketBaseVault": "6HuM6cE9hp4oCa2PCA9L5f4uBhbcRE9kgRWfrj7SRs8L", - "marketQuoteVault": "H14Fshz3WF5wTNYZGB7gaUHKSsVzgPutSv8qbi8iwNRx", - "marketBids": "EwwCcm7ZeEhzyhdAu8x9Qgw9zjmAS7iw1n4QYfPCyVsT", - "marketAsks": "Abk2eDL3F9EJ5KSZ62wCbTsiS5MSXsPp3JHCVVuA9G5P", - "marketEventQueue": "GFNj37jNS6BJh7JWQhWwwjDjQWpWoxAuHHeheTsr81ZM" - }, - { - "id": "5WGJUxhwK4NFjKti2jxzV24tDYf9cTgTa26PyGEfUixY", - "baseMint": "D5YJf7nqSp9JtQpMcZCthdEpMghK2gKmkLMLi2RhKSJt", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "J2gNc3HHz76673eVBHACcmCdU56K6rguMA14W4u2JWpn", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6Ss8KFjF6gQmSAuEbyuGyJMVEYeDCbcVZMoiqf2MqboY", - "targetOrders": "F43F4pz1wLfZQfo54pw8CtYWcyYTkNxmjv32hY3uGusr", - "baseVault": "FQGvAzrXC2CgLLvitWxYTu119NQaEnZR1ME9UkVwkpML", - "quoteVault": "FxqSpCq6o697mJ8bwSAQUfPSa9cbfSPsdCCpBMbDzqiJ", - "withdrawQueue": "EKwaLD6uBR4N2C9yE8W8LrriKdqkkDFZRBHkt4J32vrU", - "lpVault": "6GL7vZaxq5MvgdgEdk33brXe7qk58Nuvf3Sb8SY8r73a", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6nR7Q6fnBk4Y4BqRyTYFxxXzxsPUtLktm9WWSHNHvXpo", - "marketAuthority": "CinSbSviaMuV2u5odxgTekMeWx2nZ8knkSGjBy715yW6", - "marketBaseVault": "4bGumu4WZBS9zgJufaW2dBa853fNFwSuTsP27un85W6q", - "marketQuoteVault": "DVKLDgDzVdLYhYCLn7SJrXkCm1mW4kJ4R2wzAUVTfDRk", - "marketBids": "DMPB3As3WBAVFHCit6q6Y1qcJC3ZWLLoi3eMAa3RVvRk", - "marketAsks": "6KeGvBPn9QgeDrW5u8ksisRgWxqT2tTqdzmzxQenxWzu", - "marketEventQueue": "Dq7PBFPGr7S9YsYfy6riHUHKT5cQGBQu6BfugvuVMhcK" - }, - { - "id": "5WHYpqhkBpvvMaWN591o6gcEqkiBmqC2W4huYsx9jzRv", - "baseMint": "9dwrdifAVWZsyEPxi15D8LcLsdrvTbpabrGw5EVzc7pp", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Hh4NQRrgRw8NmdaA9V2zpgxUbFWsL7EmeC4TgBynNhsS", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Qvo7hFf87vfUBWhPM2pABqVpZUsFV1dao3tZTrdk63j", - "targetOrders": "FBejJP4JHiqkcNZMNdZ87kVAcjsYZ9Pa4RLeGb9RCeNQ", - "baseVault": "3KD53BPiXTw9BXPyJdwwvj2rGnFxpr8PEak6iio4ij76", - "quoteVault": "4zLsCmsPYFJPcrxpXKN7hV7iAs8rQ41ntYHc9si78QWS", - "withdrawQueue": "9vrpT45ABJM8esTYiMjaUTPHsq5z2EViUTXkBdzrz3fe", - "lpVault": "2qBMDxZCkxqHY7WSNzSPBFM29JTM8MhsaX6ehBGyA2a2", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Bm6GpVJsSfhmLEwJqQxGRLBvq4Gf5ERCsY8Xp1TZzPAk", - "marketAuthority": "yCb9r2Z6JKmNQRoP5fUA1jTeNnBocMsCCWz3yRuYSBp", - "marketBaseVault": "4hd8rWFLavtQqLweKeCuBtDtB9xM7EB4AZ1CJJcc6g5F", - "marketQuoteVault": "AwiVyqWREqX87puDXbTZrbUYdgmqgENZe3YjmWCc84Ei", - "marketBids": "5L6QNYwGScscQRMwvu2TawNXjRwyd88SJWJ4krGNXqND", - "marketAsks": "A5LZZy7wYkcbzpsRnn5TAnbRYfZmEoG9BSdXj2WjgpUS", - "marketEventQueue": "ELhTgb1Yx7VHdzutYnWEvBozfBpNTkMejBHjM7shN1WT" - }, - { - "id": "5wMAkUpWnA9wPrbdzSjnTT9T4VtKRKFTLNWHJWaSHM63", - "baseMint": "32gaR4rn9JyzoDVwMzZ5j3NgcHc5RQhMSJby55FFKnq3", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CEt8c2gRYm9VscWLpCvrMtGhV3XJLp2EoTnEptvXGiB4", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ECC4zae2nywL5d2r1Xihjni1fSo6tLzMRKmCxEH3btkB", - "targetOrders": "5pSwU7aF9zQ75mgxvj9LmjnzU2vzkqRrg8hzrJbGq9Gp", - "baseVault": "6CSePzQHbeiVs1naDYf4bVUqKJshHKwZG7ycSJR6Qa6m", - "quoteVault": "F4KXpoAUJ82TUiZKq5CQ2zct4fhCZ1h6wmo6cepBnJGj", - "withdrawQueue": "8XRJ1Z917g9x8w6gZRaRSXLwoJYrhp7adKW1BRKeEqGx", - "lpVault": "455Hhsf3NJbSzdhiBxHtCyafLjkY2banwBYWMMD9x4Hh", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "F7cC11CktjcezeR77y9jXf8pEUusGKYz3fwkfQm6YndZ", - "marketAuthority": "4NZ5uwEKsfGhDySkSApfNJhC4Lnyh3zhGzxgW3tnmjYx", - "marketBaseVault": "FjqNzezwmhevtnsykcRy6UzNQUDaojiEiDaZgAmJkCby", - "marketQuoteVault": "HWHbH5ntTGGr1VhF33qrpk9CReonEkmL5VpGQpuokxaU", - "marketBids": "8fLHuWtZvvxygytgjET5JhxK1QuubFRUnW66uPfXj2S1", - "marketAsks": "D2oDtUrRxfKadQKYBDLpmKGsVDnxDiPuWiVzhEGCnxRh", - "marketEventQueue": "38UKGM5Npw4fUnfRzPoSY7WxbHihWfjuE6nxRTmeXcp8" - }, - { - "id": "5wredNo9KMeRq6gsb54MKywYBSJ8wZqJHqYAbFiEjzU5", - "baseMint": "5L2YboFbHAUpBDDJjvDB5M6pu9CW2FRjyDB2asZyvjtE", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7iYw5gUQCK3tzvHXZFu8X2djfnLZCQSKAAdJh2w8X2ea", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "29AeJDzgyCJEibiVDU6tuzPHB9qpRngixYwzxK8iaZU6", - "targetOrders": "4S1UHo4w7gK5hLTmroTFtecYbdovpesqb2A5wSjwBhpf", - "baseVault": "F3z2DaH6wbBAUXnukkJncuMQhpH15Qq6fT5EuHqWrpgC", - "quoteVault": "2mtY7LD56dEEbs3QVYUMaXk1rQWkJ1nhLDhi3cyfN4yH", - "withdrawQueue": "4tjLqzFx47b9Q8etAf9fj64yNRqE4fzLxxhWxqoitUNW", - "lpVault": "3U7wGCsYVUX1WLT8FhyQFDzP6wtrSkbMvFAWvoKsVRDp", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ESd3PskTov69tkW5MmfdV8K7hXR35EXRYorWMNn61dD3", - "marketAuthority": "Cu3RT36M5Jxwv6ceVCLyjQj52KPJCFhCSQavtMV1ns1c", - "marketBaseVault": "FS9TVz3zCxhyExpf6o7yJAy6EJfhQQJxVtboMQs9j9tv", - "marketQuoteVault": "B9DCsL8hE6jCkE85mLoz2dv6Zso68QRHTtdKVP92mnuH", - "marketBids": "8FLLS8o6fxu74dPXU1Zwpv3J2o582fbNabxsuwDiRoYp", - "marketAsks": "DMtqhwGyJAdZKmbkckeTacwoi1a2ZqaQoaYibJk4Nhdf", - "marketEventQueue": "GooyFtQkKqhpBVbZbftqKUFuNe1rMs1ibi8LHuvBULGc" - }, - { - "id": "5x5j7AP4jooAFqjxdLv2SxmsqnTw6FoNmpXRfMgzhzMT", - "baseMint": "5ENUvV3Ur3o3Fg6LVRfHL4sowidiVTMHHsEFqNJXRz6o", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "d5zd9N4QwQJVypoAezhGZozEX2Yxm3FoS2KeoFYnKQm", - "baseDecimals": 4, - "quoteDecimals": 9, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EGhCE4HCoRY3KS6se8LvfDxgtwHybEBXboe6st112Y4a", - "targetOrders": "Hwwvt1DdoMskzLDBhZURPWxeDzy44DMGPg8jwJDRy4pU", - "baseVault": "A9BJNQPbStGn3SfWff8MeVhrKz5wQhKMLXHQTS3i42Mk", - "quoteVault": "8b34Uo7oX2Q996GfxpZwMcnA6APtq1kdbQXqEkpvzvZZ", - "withdrawQueue": "6srwsen21ujF1GnqhEHWr4DLp95pg5qtx8MjPqBkE91d", - "lpVault": "BLTCe1aXe6ijWrXBo6MwGi2ZwNQDVRGpPjNMCE3PcqTG", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3LiTmB1RCerKYca5r5fz4fK2BCrdBsmqVSwvRhEbHVxr", - "marketAuthority": "9RphBSuRfomgCtkZBxgD5nW1RctEbdLoHSh5ywzxmmdP", - "marketBaseVault": "HVHC8QKgVyv1Tzt3okxq5eRpbieAwEXJMadgXpNyLU2r", - "marketQuoteVault": "BH1uBc4S7bXqodiQhgvHviCuJgTBPeWCwsqGEssaiALr", - "marketBids": "FqeoUNASFdfuohCwtMHnXmbZcPuoDVQBc8GLgd3cpU2k", - "marketAsks": "7fyWkbfoM8iuRLR3xfrh8tWsEuDVDJGCNGGvMMHzyrjt", - "marketEventQueue": "E13tevsEMK1JZBQxtb8wJEhuD3LuHw5J8DCiZn1NNka9" - }, - { - "id": "5Xa8ryjiMzYEYhnDMQHcwmeghmGFMpsZzHoyTaXNR2bh", - "baseMint": "8BobtXuP8hD69rZTLZiubSEbmQWpbmaJwyoayzQYyxs3", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "H9GSfs8cyM7KoWoAXKJTCWLyxkPpbUDJSPZY2hF36Jfg", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "F6opNAd4KDwuhQSVBfD9rYwGAm6QUaUPh2HLidwNmTiJ", - "targetOrders": "5CnxszjCTPmLSe3CLsXUERf1z29mK5QEAc8d2gNDixr7", - "baseVault": "EG4jumH7GtVgXsqxs9ofHdYDiJqGpoSfDMv5nobUBNES", - "quoteVault": "ExUGyz9ddMQk8A4LgHuoWuazdntdoJHPNKfq4PLKRdtv", - "withdrawQueue": "3KmUMZdYi2UHZM415ox82XxrjEusJeVpEKjigbNeR7p7", - "lpVault": "7CJioUxgHV3oDoGaJ3evaUT7Rg8tG2EnbXpSKjQVFEFM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GA6xdMfL1nVLMm6s9aswHswPrhCh17HUiag19UJZ2i1P", - "marketAuthority": "HjkJYpVG6Xh7CGHd6GsdVXQi1cmNXk91QPE2QAQ7d1sJ", - "marketBaseVault": "37X5LCFYEm1a6qX7Qrq55MQecKzMXaCbusiK6YpAcwDD", - "marketQuoteVault": "7G72tVKdAxsi1FGbgbfgSYsSuct11KQjXnoTzPLc58Mj", - "marketBids": "GVm3USDpVKdAu2gXRVRZPvsWqVwhhjDcVNLbH8UngWLf", - "marketAsks": "5H83h4VLQxf1HkcwcpaoimPwkYLw4HTeSGN9JNnZ68LT", - "marketEventQueue": "GDS2zcj2XCsxKewAqBSKJrCJY6duPvFqtforUMhNfMhf" - }, - { - "id": "5Xfjt1sQe99xeSXQ8C4KjVX6uZA9Z2EFBWXhQGhaaAjw", - "baseMint": "FeVooZDV8ihVhwuHVbagriw6rtonLdysXQ52VwqTaVAd", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "ChYiShr7k5Py32nkrWQwbCYibWq4gLuTAxSFQJV794Ma", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Fknm1zjQEfRb2S6EA6LwmrT3nVQMkeeiUXTJmt5aHRDn", - "targetOrders": "3sjSGa8xLs1S1kJStFk7bXAwCqcJp4Q4bGDjexRf5M3k", - "baseVault": "CBmzYf5ynGjKMZqbnZNhokACJQpEK8KgyY6gSSeKDrGL", - "quoteVault": "HNvT9L6QuaGgvcJgeKMi1ToaNLVopmiDKTtH6VrTQGd8", - "withdrawQueue": "Bzp6tVritwRUVN2hnLdDKbGvcLxdPjJjgLpe1WVaEjqq", - "lpVault": "DFwHnQreo6JF4VuvW7mSMVgbpKqAdFgYo1W4c6oFxLqQ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "22zRKh6joBtqW3XU4NJbqyKRuDSUjcxJhXCBKQMBMMdA", - "marketAuthority": "7us4zdJ4FunbtweSGeMDJi1DB93szsoUGuS4TTmqL3sa", - "marketBaseVault": "2Xwgu68GcfESNBhXno4ea5CADUoag5vNrP7QqrYk7BKc", - "marketQuoteVault": "HXzU1WoZybiyc4W19311C3EbRqzH3aiy32b52Hq4oaUU", - "marketBids": "5whnTcBt5ZybrxXaLe147vHc6bcRbdUGbTQ7YharW6Y3", - "marketAsks": "CNUMywgUahrXKRbkNrE7s41NvndPrbn32es5GhLbVV8w", - "marketEventQueue": "EfDDNetK8yLf2SEHij4M5wANGCZK7yxAUyck9enQhvk7" - }, - { - "id": "5XPde53BKegMEHH59FwgFcG1At7ocCbwe6qSn9cTzDFv", - "baseMint": "UiWWD4yNz4h2qj5Me2Dmryfg86C3RREQavGN5VYpr6b", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9twjSS6P6NVrpyp3XeNbDPwJwvGjGTc91TwWiH81Yhfc", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8NCNhpq8invmaqWofuGEtApNxZR2KsC6TPYx7PDSsk2i", - "targetOrders": "DuMJ63s5buZ54pxJsC4X7V471w6kXmvL8wbyB2PvHANK", - "baseVault": "FTEM7Wsmnh3DRiB5XWFwjTo3CmBm481399ychQVaqVyz", - "quoteVault": "HXw47idR3ZNf1cNgz7bDDg9Tpm1GoSPoVgPbgXqJzAhv", - "withdrawQueue": "2r6oZJ5JQzMkjjYb9sAPkmwUJQvfwjA8vaeJh78uhPUu", - "lpVault": "De48CrXwazKiKUi22jqDHbwXL53kGxfFCVwvC5mybs5o", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BBqKZjZL3qhBpS9iEV9DiZ2vgVMKroZ5vhu7tPDAAp5Z", - "marketAuthority": "CNnHW5RWrvuq2YZ1Fn5hzdbPZGEhTeYrfdAxjt8QUNyK", - "marketBaseVault": "8QyFy9iBRoVrmjiTQ15Tp8QvE8T5rzaGeU7tRUEPAZ1J", - "marketQuoteVault": "ELh32WLy67u7gZTjycAXCQXvH21z2dnMkd3Su1ukiREY", - "marketBids": "BTy7CPsbuoGEg7vjCHM9TxVXtPASxWqkA6pJCNvnSwXU", - "marketAsks": "3sWxVMnmjo4e1eiiGzqtyjyRpnWohzWXb1PNdipMPzV3", - "marketEventQueue": "FWN9RyZ2pXyPExeKUkMmRBCKtkNcZZA9Vhij7Vs72fHZ" - }, - { - "id": "5y2QYKY8gQCcmG6jy4fc7wFg8L5SW7bkyvMH3jUTqBdy", - "baseMint": "ForaXiBD8K3a7C1PwxV1xqDHs5aV8y8nWRmHebafdkes", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "W4cCZR8CkNAyqvCSBvniz9N5ZbzpxduaZpXtddn35Gm", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6SwbC37EdQqToACUHae8ysNijupNp4GMX6b4qwH6VRDi", - "targetOrders": "8mHURqiJxvHgKgPHy3vaz9Ni6obPJHAGYJ82Nfdn7tjh", - "baseVault": "FubQ1Ca1SzJnVJULWz4dQ6odKM1thtBnjLDRZC8zqn8s", - "quoteVault": "qbop8WpeM77y9A21R94oaFEUdx55tnM6dotmCasTwy6", - "withdrawQueue": "DEjKeb6moUkoXhd25g6a1uNY3Fc9W3hgc5JevAtyByH7", - "lpVault": "AQQoiDnSkivbGN1j2Sjf8Wih7Lrcd28HXbWTnciPD1rL", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2HqK6oenRGVi5kY92Q2tQUk1kBkrKHQ7ZZZ2dw9GScqP", - "marketAuthority": "2c7BqzhwBCb86DprTKte7UfK6F4Xwu4B1uX7YsWZ4c7G", - "marketBaseVault": "9CgWdLCkkVY1Mi95c8p3oKvCM7Fu3JQG9EBmRPvgBfoX", - "marketQuoteVault": "4mTDtiiSvjeqEYJcQVfDgbKBVJNpwjSyTc58q7GdB8Vo", - "marketBids": "F7G6Uvk6pRT3PnhZLm5YGA4GGTWHE8AfrdTVqyPc9fuC", - "marketAsks": "83tUsZUQeXDZR7uhtWHin2epPdjMNPtdyxCNgcFyhaFS", - "marketEventQueue": "5SVX8MeCrxVjWazeD5oeWjYBurHvygpma4NyTi9hmGws" - }, - { - "id": "5YXSV7jr1ydMGupriq3bnvWjMZJZiQgweVT5riuBATsS", - "baseMint": "5xnRrqoyoLBixNwjVet6Xb2ZTyBSXhENyUWj4sqzRGrv", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3V1Ci9zVMWtWBGzr9ag5sCwuHbdM443wHkHTnHfsTS31", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4w5TTvcz3pdhKGkKkm2angLmiCTaq15oKXWw5mE8b28Z", - "targetOrders": "7YePnddS38sp5WJQ791fLChbAdZF84mNLUAcXc2tyfZb", - "baseVault": "A83YUL1WYWSxheE8uLn5owmoEFuzY3Y7sdtYRvgfVYm6", - "quoteVault": "9xVpfv5MND3A6ATTVcN5jMCZznok3mvxyFv19B7u9J7c", - "withdrawQueue": "7t3BiuX2eeMTf1sE1Ke3K5bkTkWZavUg7hqC51TwgTwj", - "lpVault": "HkGxTY1j7hRgW7LTyuo3FjMxRiB8a9ZuFV22antJdyFY", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Xbc4HTxEtsjc344dogrJpQDZLm2avMGiNwyeZGYsoKm", - "marketAuthority": "7dH4aVBnZs3tK3PAYLDP5j11fmgbC8yuD9Dfub4Y9qrQ", - "marketBaseVault": "no3jU3M6pZhRvaC1dcbzsyyboHAT2Mzb3K2FUwnSTLw", - "marketQuoteVault": "QJt41LhCSokKwmxbvZHHk3b44FkYmb2gKTza39agX7G", - "marketBids": "J4CMTZBVEqqCy3LJJTHJbPr7Cntbn9cgPwBebZuSvRdu", - "marketAsks": "J219KYfJN3qVFzV9GnA9Q2CxRVeVz7ysAFeAree9TJ8w", - "marketEventQueue": "GCLyi7vNmjbtuTJiWqhtBPnGfZxjQQErMHJQgL3gp37i" - }, - { - "id": "5ZhtdDB7Qsr31JXC2gjr2jobavVzamWKtRUsxYXrEafN", - "baseMint": "gQ4msQb2jupNnbLLiqpKJmTRUcVmct3Cn7dASrrV9jN", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "93Tr6SZhUEz8E6XL5VYkvEGNppuRgLozSySs6pimFedk", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GqtMMFoSF7fmZNjMWSnd7bv7LP9i8MN9yVGVJSEJMccM", - "targetOrders": "Cf9Lv41N8Ms674jaZUhXGpPGMc6JeTso4CdAok9TjjFy", - "baseVault": "4ZzVtqWvxCjiawx5AZDdbPwpyA8mpPujv1LBNkv7y9Xd", - "quoteVault": "DqX7qADFy3NrpNomZbC9BKs5971evRjYDzTDAp2TkCco", - "withdrawQueue": "3wwr7nQLsBMaxLbyVUZJLjUAQjmft9EVFKsrxf2Bkpsn", - "lpVault": "CMFQ77nCYnieFHWZREEH5esnhE7pini7U4r8k8KMupPM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "B6PKLGgf5rqndrfUuBWnBYogR4UWpZfwMzNAanE4cTBg", - "marketAuthority": "EQ4ZL1GKwY3MvnLbWLQiDWQdUqazB1rJKjoSYcwRbmbp", - "marketBaseVault": "F9eCTGWKquBAER5gbyPdHCatxAeceN3RCU8YNz4ph9kK", - "marketQuoteVault": "66bRz9puohtu4MthvCdxHe8duax28b9Pznf83Kz8Cntz", - "marketBids": "EqcjWjoxkfhNzLQzWcVJNQRfsrjgKcEdjXy6YbCNm6c9", - "marketAsks": "9ajf7HVAtoXyX3tTb7PoSwdkFLV9f9473AzpHgoiN2se", - "marketEventQueue": "CaoBgqb9ZxrwndALof6zqRGUqer7P5ShtZ7fQkUi7UQT" - }, - { - "id": "5ZqY7T8gCGchSHcCT146jwPu25vLFeLAGjpWF5zsge6v", - "baseMint": "EGiWZhNk3vUNJr35MbL2tY5YD6D81VVZghR2LgEFyXZh", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CtaLHs1WKB9beSUXt7TSwRy9rAtnaW1yeRSR1BBzxc6g", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DBtPJ7r4B3wiip7bczjDjEYz5bJ74aXh1exRZqvv15s3", - "targetOrders": "466cQoPVKAziaKFRDa4Cvu1p6yd7JNtR4KStmtcRRs6S", - "baseVault": "9Zm3HxE5mqqrkrymzXZt2fVnPRaFoBH5mLZRBsh5fWNP", - "quoteVault": "HMhg82WPcTBNsBTcdE6PbB9fsC3RAcmzSCQ3DX42WufN", - "withdrawQueue": "DwY5vNLZxD6zfvCF7pu6TCya4qqu6QJ8eD3ebDcf8Zxf", - "lpVault": "C3YBea88eJuHQHrS95HPYYJ46W2WSKQpNJTGAU15CmRF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8uUKyRx4Z4nDgunSpfftSvE3x7Z3Me5q7wp7T6rqfVey", - "marketAuthority": "3G6YF9PtL4aEGbcJEtiHHtFUnjfcv1eG1xRYG94ytyYn", - "marketBaseVault": "Ro2yjJNfoVenpUKPREoCQgiWHrxZQzoTW84Dp4Huzae", - "marketQuoteVault": "9UTiyyT5VQFpi2usEaKcJrhrjrwTND7uCX53SUWqJTCE", - "marketBids": "BbWK2e1kVGFCnmXH93C7daF8hxbHMg5SQFEMV5HjWNRw", - "marketAsks": "3FgSfiMtACRQqpXVD25JYks6TDvfcpetMEZ6NwGGyLJR", - "marketEventQueue": "9LDiHDoT8Rhsn2n6ni3NEgRK7sWgtGGcWdKgoGtPAY2d" - }, - { - "id": "5zUBVuXM3pwcrfi2Nj1mkT4RLKJjmBTjd4AsGs3biZBY", - "baseMint": "2Kc38rfQ49DFaKHQaWbijkE7fcymUMLY5guUiUsDmFfn", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9FeZF2pJ7cNnVD5pxrRKEaxBiA4CYbonBpXTgZDVsLXS", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "C5JCYfp6YE6JrpNkRoAGhARSUSMLMP7paPBHsiK1E5tb", - "targetOrders": "Hb52qfnmgMRfYS6rfcYPuB5AC6hr3YtZv326gd6g52Ru", - "baseVault": "DBMA8CUKosdnNvXT7phVDk8u9QCyNWnG4Z2twDS7ET17", - "quoteVault": "EjBkXsDPGmyMQavnAQQsuMAMncDYTUAL35MhvyzEX4Kx", - "withdrawQueue": "9Y5WqcYh2akt4rNEVDWpbMdA4xtWyPtXhe7o9ccW6Ehb", - "lpVault": "VFmxZGyFEiJg3wLyU2DNCJw7R3qY1er14LrCTH2FqiH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9oXkdAWFyjDH8BbYrDVJ77r6GWPmUWo9ZYYpE25SZ2td", - "marketAuthority": "5XKsQrPiQh1YznQFs9x8zMcqMSeJZBiGe7FmGfyQgC9N", - "marketBaseVault": "8N9HsqECLfZ7wHg7DW5WqYzN9UnWEgRhChG8ByNJ828Q", - "marketQuoteVault": "kvNtTHZU6vofnfdzYjN8G9gFqfjjf6yGYQJzwHb4m7h", - "marketBids": "BdAZ2q9Ct9atgYnENKTsNKyLFhPXWiKuy3god4zEKMQW", - "marketAsks": "6GBaKj1LncmZGS2B4uWjCM7pRZ9gUZWNTK7K8VCBvxaG", - "marketEventQueue": "8aVP9P8cPzCSK4hdsVVk1E2nEf53f7iWkTKmsbidp4Fm" - }, - { - "id": "63J7uzJKogFK3d3T2Y2c5NSVjSQrCbpfuBhdqH6H5pSJ", - "baseMint": "AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "HtSztKiiCGvwchSm1TvKEKCuRMChLxxfNZccm8358bQP", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3aW9jx5QZ2nnucv5LGPDLcXYGnxRytgfZqrBXyewzeew", - "targetOrders": "AJPTpB3XawHJBFYiK9TmXNza5n4urRSeXnyPS4paQEw7", - "baseVault": "CFqS3UG7TwboneHdsr46Jb7qj5b9YzeZn59X22F8HZQx", - "quoteVault": "ArsBckC8nngtBjAfvcGrXSB82M91ouukET8cNeXVMda7", - "withdrawQueue": "DheSGhkWrKpd6DvntYtiRJZqKyQ64XwaTYABRgmoaGn8", - "lpVault": "2fApsYkzfXnPNh6Cu1kruxTcm26ELmFNpFrv1KmNQPvC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BKj3ZsH2XVUVfggbAKGvdpHfcmRDkxz62wUJvUK3LuLm", - "marketAuthority": "3rVboUaiGNKfEosBxEqeVZmoJVAfXArponxRkZ4MggFa", - "marketBaseVault": "Do5pLmVcmfZaZ4DRxdvYbftJF67QVJvyL8URmrsjF7ik", - "marketQuoteVault": "AdS7BJogA3YT8CsHX9tzrau7vCrZokWDXC8vFJWd78ZZ", - "marketBids": "93nM9B4oVQGkLkrAWjdmWRbv5uoJfmbrNZjaDeqA2Xmp", - "marketAsks": "BQ2a8NeFNbe1HMSUnF5fcoRZGKwxbgaVJbMXzuXLGRix", - "marketEventQueue": "9E6mpTi2H5XJbEunyvLBpbgy16D3hvQXqSpp7fw9YbCP" - }, - { - "id": "63uJ4FNHjyCUbUv8PaPTTjkUboxwKGPsYzxKuLkFkr8j", - "baseMint": "4qagvcSsN4ovsUsSs1hBh9Qzt5SZHsfNu9BtjQsJyK7W", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "5pZCiznqE179WWgp5m2HXDuUwdnuQNGH5Evb1Xzk6dDz", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2U9jRdHrPDjzPUYcMtAVRuWYxr3zVsodfqPug9wWHq2Q", - "targetOrders": "GT7wN4xXZDdpFZNUUafPz7grzJSynQ1YU9KBSgiBufRF", - "baseVault": "4HWcY96KxcieHAkvVuJHXu9FNEde62ZtxEEpok1uyfJA", - "quoteVault": "pDmqVy7J2BDXR88ve6xiKqUq8cHp3prt8oXs9ckbo6G", - "withdrawQueue": "FnzDioikccmdZPWxPNWnh5ZmYyKsfqCayctRYVpC9efc", - "lpVault": "59w5zuBid7Bos3qijeKanPYMpNmF3PwfMenYcUQ2AcYf", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CaV25C9demMGQBG24ir1G2wvnZ7aEMcDTWAzjGazPcF9", - "marketAuthority": "DMXcfz9ZcQ6TSeeae99e7n6qb3H6w8MfWeHQu6FxXBZY", - "marketBaseVault": "9MLfSt861LKUrA5sDhqvhbYmEA3UqY477sxYU52y7poJ", - "marketQuoteVault": "7pQVi6D9iZgnkAh8iD9PhETkdqKJPfqTyiF5yZuaDLY", - "marketBids": "FuxJjWh5KMf9VYmiEx8VcReJQFMncmrQsypiNiYtbEwP", - "marketAsks": "Es4Hjd34coKG9u9c7PdJaL9EP9qnKA3qB4KE8D5aUDRC", - "marketEventQueue": "7RwyRozmq7mFn49zFwLZmU66TdgBzJHYiPyz6XRbmD1f" - }, - { - "id": "64AWwFdN4RDuMiz1dCnZsQPRt84qksyFQPNCAHBcxv27", - "baseMint": "DZmSAzjGJQPHMc1cLL1fg2YND4F4DQm75yixQTChM47h", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DtYK7VfdCkSH2CVHapJ1jqMPibJRVWeUKwuQ1aUbyxbW", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2ZSSqNAuQwZLVBb3Y8u8uSzTch1oMnr3PCaAbBt6jLq7", - "targetOrders": "AqbazLPnqq3Pqz1YAcZSyT4u9teHEiAzJQj9g9SaPuLU", - "baseVault": "5ZQNW4thjs4K1RCaBPqsXFzmHjvZSBTJ5qPDcBELCjzu", - "quoteVault": "D7hZiqeuagnnaoaCfKKJ9C6oMopTwRJwSzX7kFFdgomB", - "withdrawQueue": "HvZsvddo2eHQBqQamX2skHZU9SmptJmbgsCkNVz6iZk9", - "lpVault": "DUNnYhvuniuiXWeBvUw7nTYhGj17Xbf7r6yQJKnU9HSe", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AUS6mMVWiQYu3DJ9iopQjFYrZ7zgDbep18w8zhuU7DBn", - "marketAuthority": "DU3V6CDTibFcMQF8MPpV2GfLSrnAoNwLWLmXhq1tLsd9", - "marketBaseVault": "4DwU1YqBeYmTDsTaPPXbCCBbw6J5mSfwUo87cPzCKTf1", - "marketQuoteVault": "2222hWYysAGjVy8Cb5KSAsndiW6WCDj3WHumZCXwUeSz", - "marketBids": "FuVTVZbEPWPjSazo5WTJsCmS1DcN8C3QZ1vo2BeUsavs", - "marketAsks": "G8CWiG5fKrQuZebk4cupzkJ8T6r5EyKRmdJJpaUpmx4e", - "marketEventQueue": "FCaP3mSCiDe7xAJDEB7hENEJ9FG5XAy4LatbLvS7BAk4" - }, - { - "id": "64N6S2oL9uwrNnCMSXYtibPhWNm65XiN1q8svrwiCt1K", - "baseMint": "F3nefJBcejYbtdREjui1T9DPh5dBgpkKq7u2GAAMXs5B", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BYkCfYGDqmmeD9nRGY2QuHpVLpEfH4JaQEFA77C13rGY", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "G7iLgup912HRKbhv2AfNxBFaBWLKQjLniaQr5ZGEkFLw", - "targetOrders": "HGsG6byi84fY9xHmRpGR1LqybBTXA7n4CLG264BiCmhb", - "baseVault": "FvfPEsi2wzm3G3eLo1VHSB28jbfNpgPjvRaWZxKx1di", - "quoteVault": "BtHEbM76emNgRrSJqQgYyzrJ65FAfbW1WdpF8FKohzMJ", - "withdrawQueue": "A9e6kNQpV7s1oMbgpUjPF9bNPPFVv9rLtSq9HjyiNaK2", - "lpVault": "H3NGMViYrFBty98i8PiGgKLhhCT6Fa3tqM6UrBUNAe5Y", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HubRne1PhTa8ufcGRmS6sMJpbB5yY3BEykUuw8xXoAyy", - "marketAuthority": "AnB19NtoXeBA55HiqCpnXUr1M8x1s58EiNR2vqzeAXjV", - "marketBaseVault": "5oyjUNFAhXZ5KatSwBvWu4GmsLYA6nVpCx1yJZiBydx2", - "marketQuoteVault": "4BgCdCfQZWWPY3TocsfL2yDfondAnDSro84Cq8kQBsyT", - "marketBids": "ALg7KJCzLkDDs8NNL7rCvX9bzqekr45mnVbybXufmp9D", - "marketAsks": "E58mLmBMStcpTabnUmt3osEbDMx61o5geuboTB7ES1iL", - "marketEventQueue": "5E2acQijwMJ3TA9jgR2QhehhGNcQcLCxUANofVwGgCPq" - }, - { - "id": "64uBwyUUAQ3X4imAV9EKXUyb7PsPFDqN1BfgekEh3LAx", - "baseMint": "4BzxVoBQzwKoqm1dQc78r42Yby3EzAeZmMiYFdCjeu5Z", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BYDVcA2ykedhyzHj3Bc4rcAaQT9RXaF2octBghCztxKT", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Fb69S6d19aKeMn8yJxGfGx1a4nKJsDbdWPmcZgzosjYZ", - "targetOrders": "4uMnW4KEH6ftKADaCFg9GY9a3TN6QyuQC6mNHonWNRSU", - "baseVault": "93if7merLqUTEKEKTAFDUu8Hsv2yRpcC6zsZpo3E8zuX", - "quoteVault": "37khuexnbYXhvfkjoTfq5V1P8fNzW1LBiqfwG8DwoPX2", - "withdrawQueue": "EFdAzMzAyJio26uy7cEmMFP9727vVZtH1KJ92N4sSHB4", - "lpVault": "8KtThgKnBV52dvovf2JXPArFJEQStHqy6sbfmwhmUax6", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3SGeuz8EXsyFo4HHWXQsoo8r4r5RdZkt7TuuTZiVbKc8", - "marketAuthority": "Eazze8bLQKioqkYWZghhMtNzkjosQ1eFJHCoNZXLj6Vc", - "marketBaseVault": "F9DvjHxe2ofJJxXB2oJRrURLiZsuM6r3wui9FFcyDzuj", - "marketQuoteVault": "4oSd4gMskeV6cTHqJuhvvBXamnHhwQ3MCVLpJMbXhC9d", - "marketBids": "FiAwyvBakEJUkTRWxZDyAfmzzd1WX5ZMXpnbrCjPQNYo", - "marketAsks": "CnWPXjDerQWCjkzUFU9xAGo3BMGLVyoGRnjWmpMNZszK", - "marketEventQueue": "3QxXDeWewaRGthYajk4vzxi84gMrpSteZwKyjs9WRuYf" - }, - { - "id": "65D7AGwJZyYttmu4ZrNvwx4knRcPWw2gUD5Dc3MLdg8h", - "baseMint": "SGTdtpAiPU1Fg9a3DqUN1852V24sfo92ePEHpyqkrSN", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7kDzBa5r3UfDmWPkH9gaNxtetkLofD1zhKzu2M6HxdQ8", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "83m6uZEUz829jxmoBK8JTeuQX4HjgAznqMXJGzkBbeuc", - "targetOrders": "C2fjNNk2xUzVsp4KNUuAUEdqZuft68G2tkg4WbAHvHLN", - "baseVault": "2DHFakHLLSxALwXDM6kzWXrfXEu1n9uDci7ZXXwuDwvW", - "quoteVault": "Hd5kRCeZVam9Mstwv1EmYMoRdiWi5GGqaLMup1NdED2W", - "withdrawQueue": "4k4wcZ2AuagzQ5jY64U3vxGAvJxLkKVRKQCvKyTmerpG", - "lpVault": "5Z1WmA8RqugdL45Kxgp9v9Qcy8Lx6BW2CB1E339wq5bz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6f4rgrWZAHSgEMSmqshwtS8tyEwgEPcH7Z3YfM9L3jCz", - "marketAuthority": "55QhkpG7HdVYvr4aZ1v5ooTUSxtKUze3P7DvvbUw7yGj", - "marketBaseVault": "9BqfQS8TtFE6nsRuer5pfZ89uzCLvg1MTmQe8MJRjYb8", - "marketQuoteVault": "F9X8Yd6fJH8N1UMEAGfmpEgqcRSoNmQyT6hXVqtyjRU5", - "marketBids": "2XYXA6zGKwj12ZfnH7Qpvtmpy9qKGXsLuNP34WGbuhiw", - "marketAsks": "JC7VKSphcVdni9pvvpPDMMJdppKL5ZM3CNQrhocC9pW2", - "marketEventQueue": "CVUwGh6VAgstqJZ9YUX8jtxUWFgLoDQdVpBAkgRYfs3o" - }, - { - "id": "66ruKUbWdJyZwBgDMkjeoBYCjY9yfkibbXaTGwbENHsS", - "baseMint": "1SSBwC8hxB4GXzKKU4ENNpST7zgpTmucDe9NoAopWXX", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6b87eoyLXV1bXfzyJ4iCAkzeL93b8cyUuGBARUZJqKkA", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Fw4rx4BYZHRFpi9W1brFvctSqbVLbUs4SR9exRf1DKrM", - "targetOrders": "7NXfn21bQ8vkiN3ZmkARcpcgxcDoiAaJt2o3Rr5qCvoe", - "baseVault": "JDtTznwZNGnkM3tScUn4RukFGNvnmJWNJ6Q4jbKah2yF", - "quoteVault": "7Xv4AAvYeTtostZzUg1Sm2EpppLpjUHtWrZHh4dmXhvw", - "withdrawQueue": "43t7QSga8pvE3Z7gy1TdctsK8sAtUna3AEGkYmKm3Yk9", - "lpVault": "4jwA5kRWtMMidavKWXw1H2EySHZaXKd36mmhhD8ZnBC4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "VEwPVH2AzoqQb35DP8gvY3B6hj5mwRzGhfee977b27Z", - "marketAuthority": "4aojVyJmnYAUBk4Vb5f4ivUUUSQTikQhB3KcLub4H1X3", - "marketBaseVault": "Hvi2zYqjH6jGPWiE1DbN4Dncgsu5vy82VJVbxPafAKPP", - "marketQuoteVault": "EkRJkq2D5LKiKKJ5TCYXiFNwJgn6mxnRs49a2A8Qvqwe", - "marketBids": "7gWDo1CipU3dG1c3APEV7iMpUvpjJJpcsHh1jzyNXMJ2", - "marketAsks": "CFzYeh3etbeao7SSzmzSLhu5Ncg1d1vJ4NSAaeV1nVdP", - "marketEventQueue": "FiyHTB9ZNvavLjizXaUNwWye9Dm1rCGj9gG8zCqYNhJK" - }, - { - "id": "67DW9vmchgkbmXYDXMUjALNsHWckPTN8T9yWdkXmEpMu", - "baseMint": "7osS84AkAG2TCrUvrE1wfKwfAqWTCrHnaCsrsyVJd5pY", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "DmzeErFPEFnTf8wqTgiN1GF7p6vD49KtVK4pktowG8Uh", - "baseDecimals": 3, - "quoteDecimals": 9, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Co9DP5uJxJYFr7Byx5rckuhJtTjyj7sYeiKGkUpBmBu5", - "targetOrders": "8sKUWhAwLFaWp9GXmVFnJU4X8n3xXxk313Y9fLFYhCd7", - "baseVault": "FGT7gekxYDzKkxz1bT9bWC3u7qms6F33Ggz4FSrQxZtX", - "quoteVault": "9NAQF7wcv73zsPrFohoKSAbVcaf1cSizKyfxZLGKRfHj", - "withdrawQueue": "3pejwRePhSko67BHqLw1CXGLYm8kDTksF8NU9J5Pq8Qn", - "lpVault": "CxLdK8AiAH4PNiSxbE9aGFYxNoNG32if1jyBEfRPNc5G", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Rc2cgXLELcVoDzwxFS5jExireK3FwbHCWnXUbiaUg2W", - "marketAuthority": "HLkGZEapVCHgC4p2dKsqPfWm8YDAieuGRFCvCgMKR8Z3", - "marketBaseVault": "3RmTBMvYuzAQrQLP7N2TKrdRFc5BLqFxp3WDaSaajJoz", - "marketQuoteVault": "3d74rLXFKuHov9QXG4AKt9sp5nwkHRYwRkVdpKRG6N7f", - "marketBids": "2PUJq7uxECfkGXB77NMJV1DfQ8gAso5KPsCMTThAvC5D", - "marketAsks": "944QtH8hHyFzmPvDWirhVxaLyoPnpGYrYzNum13DgcFP", - "marketEventQueue": "Dkofngb79MbMxhHSgB29pUWCYqLoJRzVF1kJ5VN6FKPo" - }, - { - "id": "68CsunsDjVD8REy6UGYfAuQNk5GVtbiDtDjG4ogiua2L", - "baseMint": "CmSryDa4mnDYUicq7qSESsTKAdgBP26jSYcg8zavVoJd", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "HKLm7HvFSxqvQFLkFiJaBbu2GhghAMT8peoihvJ4SToW", - "baseDecimals": 7, - "quoteDecimals": 6, - "lpDecimals": 7, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FbD3vq3CEd3PEQGfLUeGy1Pu3D8ytVVrEfVQdRwPGfj6", - "targetOrders": "9AtyyA96eW6A17zYiF26unJbznKSzaTnraLA44E4Ro78", - "baseVault": "55tt1bQnXCWnBZWaM6ggW4ZNsk8rMYg5pNbTrRC6DT7a", - "quoteVault": "DwCQsoUyYwtApvCNRZ9M7smjCdMKTCkt4QxB6TQFHhim", - "withdrawQueue": "8yJUMhV5PeAU3RWCsyrTD1SHuPNBfuKkxriWZ4o8Mp1X", - "lpVault": "9bzfYjDKD4M5QyYxGiebnrRiSgzcCxMxNXLEEnEboAvA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DyP3AKirWfGrcTrYTEqgf3K51RjwWPC53mx7EEXd6iXW", - "marketAuthority": "5Dpcb2v9AK7C2dDFMPP79uiLMikNbiWSVps2ryaxnppQ", - "marketBaseVault": "Czp8ep8R3VEuibCwbYHoiU6Z7w8iVJgyE6PBA9EsD56A", - "marketQuoteVault": "9tZeA1qGs41wGRJHb1SWQ3aM3QtK4B84QAJiHfhdcwU", - "marketBids": "3YoU2DKQw4AC8CqnvA32eZJf1ETW1PEiGA54UgJj9jDv", - "marketAsks": "Bxm4QXU8Gy3Q6hWjTjpRjKWJe86xcQVVRGzPh92wKYxH", - "marketEventQueue": "FAKdc79gum8vwZvPwJpke4xEctgGrzQgCcRyTJo78cre" - }, - { - "id": "68LVZPXBjZm4FkmXYRw6rKHq1SEoSTR9hYV8MmL6gzJM", - "baseMint": "Fj4js23EXVLoUQ26VPfmwVbt76XLn6souUGis71FvNmM", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "JCt9ve8RW6ev2MuU41fpendUD8ANoGQC7XFRUo3rLiH5", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5u4s9KLbhQEXAF8Nx3zwPW84EMUcxcXaKTFEJExJcNxk", - "targetOrders": "FHcbvLXuapQbZSDe8EC2VApcYkZdtw3CnRxTGfoSQXRS", - "baseVault": "9espBfytrENMWswuNY63Jpf2S3EwFNiMx6WvYsb7gHUy", - "quoteVault": "HK296WcKcEFAKRP6ajdctBZ1YzKzBKxmBWduL76TCKzb", - "withdrawQueue": "6mpszDwT8jbAPiDcBaMYCc21XeXj6i1k5UoCKbGj59Xo", - "lpVault": "H6qKdTg3H6fwHDEJx4hCzHB9o96ccoRaa4Z8aSqgJRmK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8jKnrBbVYYNgQTGw1gGCFtw2eMgoojBg58CpPatwJ8H5", - "marketAuthority": "5YZYX3pqDSHDED6UCgmKuqPQSZsQRkfeS9xcihvETSU3", - "marketBaseVault": "J52WirNsJgxxMwR3zowYaDmnvU2MSqyuL7ZrKfSwMuXf", - "marketQuoteVault": "4rnMWedVNcitJnd6uWwBq1gUmHBSdi7o8JG3rF42XgLY", - "marketBids": "9jGuiV3L52nXZLU8igt7eqoCQ6V9Dn1MTcbTURxL48Lo", - "marketAsks": "4KvgUfG4WcX2XqsbTP4JsBzuzHRbGC9bo6jRzvUMi9hb", - "marketEventQueue": "CB3GoRjUpjsMdRKwHEEq47FX2obtmPyNgHkW6b9YMBvH" - }, - { - "id": "69kGRFgbPVYFaqAnCTsjpkL7t4WQihDikcT7nFjRced8", - "baseMint": "SUNNYWgPQmFxe9wTZzNK7iPnJ3vYDrkgnxJRJm1s3ag", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "Eqq6Xp3NTA7244j5tVqa7LFa5bquMtiZwu1752G4NWWq", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EDQPEhvCT4wKEn7dfG3GLihRgg4qBxKmcYirG6kJLZFx", - "targetOrders": "9WLmo6ppAB7yg6mS7N1DKmLY8zNxVVpSGvGMaTRA96Gt", - "baseVault": "2ofMLJjiA4851SuhHXpg8FypBAH32L5dojcifTMvDQmq", - "quoteVault": "4t6nhkUuEwv5A8pSBx3qQYcPUDCephitpwdrcwpkneUe", - "withdrawQueue": "8KDE3bJWXMuF1hdQhoFGzMCNTC4iMh32RHtX9c1aYtmi", - "lpVault": "GATvHTWFjyi2ngXKm8FXSp42RQqGj1W5NGCgj8kZNuJ1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "12iFrGLwc2XBzUVg4nr7zv8q7Nw1nYXX5javNBMyVRKR", - "marketAuthority": "7T32kgNJAYko2HqiEA4iQ5uT9w3TCu8zpEK44YnZQrsH", - "marketBaseVault": "EqsdTy8fmkJLCwwYn9SHtwQKF5P7sxghnHg19SnpQGa7", - "marketQuoteVault": "93WNrRPdRMqFmYeoqQvoY9FjcJbe9Z2NbUpEKocez2r5", - "marketBids": "5i2spiPKKYTTtSm1b56tDx23o6UACTqndhmM5Lhn3BTg", - "marketAsks": "5x1fGPdrFXva69MmZkHhi6kDTB7ffocQ63yBaVAspbzt", - "marketEventQueue": "LV68xbnD7wNA1pt5hANaDVtkt5URvZRs2b1Pgbcr4C4" - }, - { - "id": "6a9iCUaUh7nxEWLfx42uNeUGNwAatSH5pA6VDTRV3HfF", - "baseMint": "GGupQCMnyEmHKcqFu72qCTm6yEYpVyhouY9dSAMEXLsC", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Gz17BNbznKP6sujFE7QfywAQNz3ZSbNTLZrzjUYKhkxj", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2RYEKzV7JnB9iAvp1mD2RsBQ45KjtesGKYRemeFP9VQc", - "targetOrders": "FnNtmhirsMnUUizXaQabJA2nUREhm6tppiYSkFfHSEHJ", - "baseVault": "2q74q41gFQEx71Hta49vJHWmQBQczSywxWhSw3x1NPYq", - "quoteVault": "8J5YrtDiDTBDuAQg2ngG4aHM2JqwxoPrRySopkYiHCqt", - "withdrawQueue": "CxQ4hFQ3E4nbRM74zncrLrgT6dYBm1QR3LQqUye3LzDd", - "lpVault": "H9P2CsHDJf7z1b9WEXwHM9fjTAcChWRjmP7nWvwQaAgH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DpaBEJKX7sFsgApzbgfvMgbB6pi6h7xxNkCSjs6SYv3u", - "marketAuthority": "FbNFprAszAgReVxfAhb4hJi46ced8kzp3VsZPo4m33mC", - "marketBaseVault": "42zkbWvSsyxMsNUBUkDevV16EUTLECGb4Wj3KP6RaRdq", - "marketQuoteVault": "GwKz3vtkh6kA4JWvEqTmkbHZGCFoSJSzXa46JbqAY2zT", - "marketBids": "Dnx2C4fNes69pYg6nQPUYYhLrvtS5QLqJZeVHkQ5SMoh", - "marketAsks": "DTehMwaE47uvdrMiXLfF8V5KntvkoD9hsJcPzFYA3hS4", - "marketEventQueue": "3jC3F3JkM9e7axhRVwq9naTBRcL5zNQy3WCoyrHoYAwS" - }, - { - "id": "6ASbQ9vC14sxrSBs8pwjebrctz1uu1Za1mq1kGtUbAjp", - "baseMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2gLUP7yVqR5ECUvPHXBUgPaP6rFXabeB9xgiNjiZJ8TB", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "JA3ACBVzKid1PWwy8kdQH62W5EgfLzDznmzeRSjN9ToH", - "targetOrders": "6cPV1gtqDWv2CmfjgDPXBRVM2i6FbupxVkSV2s4F46x9", - "baseVault": "G1YTFtthoZCPFJANCos4nRnWe5feQvy7TK1eNQzcGbfS", - "quoteVault": "ETKEVVNnNhGPRPjHUxRYU7fTzPTRa3A9FS7qUyzKDjYr", - "withdrawQueue": "CawPjKySFzAskKW1YGEYaH559sU13XV9FCZuKuXYDUvL", - "lpVault": "Dduwscsy9oers4dHMZsRvmjA6GJiy5G6goKNtjs7Bg32", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EbNFUE5VK1jE2QpwJjqjSyodsjbLcca4uEEANzikJii6", - "marketAuthority": "32fepJDPMPe1EdUzyXMDndSAbdfZ5tDR3yLJjr8hH6bW", - "marketBaseVault": "C6LPjKnojwou45Ykg7Xyw7yupmNWxqexmdZc81rQCL2f", - "marketQuoteVault": "HpHX3PXV68UCCoGoP9r6SXrEnpdjMjhm4Df1FGkb3M5n", - "marketBids": "59RM1jUgFUuUiqEyYoYRay27t36mbfCvTnFNxnwro1Bt", - "marketAsks": "7MFLNgGgUMYgxfAUtC9Dxyg9MByJTssQqhb3ULt2hgqq", - "marketEventQueue": "9kCEkS7DtncWQPoyJvRZnfhPt1VgW4k66TwoKWJXk9Zf" - }, - { - "id": "6bbUpAHDCMDEMqyPpkqPdiz74TfqaQs9Z31s5G9TxgAS", - "baseMint": "DiJWJ6hgV7Vm5JP6SU7xvo7nULR14UvrGoWmSu34fEvZ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5prGyLKtBzo6CfA4uECGMBwBDkVn4JhZAzpBWXeDwKPP", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HdS2FpPt6DM7qxt9yr4gaMP4knNdCTc1eiP7Fsw9ckyn", - "targetOrders": "Ey3TTqCuWhUzRoDAGybMCMhNvihKCH4eeHHYZeTPGMki", - "baseVault": "35yeyUSixVKw9M7KkUBFUdWFnspYuZpGHNU1QxNTK2aV", - "quoteVault": "3KzQWGh66hpL1yL7RECnydbJxptUTeTrQBBgV8BSMnG2", - "withdrawQueue": "Gd13kDZpnmCurRAivYjsQ2nDfejDr4F4Zz5Zb43rzyAV", - "lpVault": "Em8B6HfNoGFCXNzgXov1DYedCciiXFQEBj1SxG6fsLZc", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9BrQcZ8wMDJ7ibsQKckCd85x5mkqEXL56hnTuvyziPY3", - "marketAuthority": "FKYs81GhokkCue4JPqEdhpk8uM4rTsxwY9XJXWKtRzQ5", - "marketBaseVault": "6amTXzGwU5dSKRvcsTz2V9A8GByecKMMRHhsD4YWDXfp", - "marketQuoteVault": "7uVFH3GXRdRfcWwyWz7GB8VgAtMRDwaQxai4x42jLvTm", - "marketBids": "JsPeWPQn9PhMe6cumj6fzKk55VZSy8mEHQuT6PPma9j", - "marketAsks": "ANhMuizgn9nRnXmEsa1JxNvmFe1MdWT6r4ociwiVqJsP", - "marketEventQueue": "BWkh7ECTVQG7YhrcZnWZEfs7TCruvFFjRkCiPEAzX9QU" - }, - { - "id": "6bEWxMuYHQfGS98WFir8jAon4jsZM4zjUe8eVuYRiCju", - "baseMint": "UNQtEecZ5Zb4gSSVHCAWUQEoNnSVEbWiKCi1v9kdUJJ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8xUXnSG6bCUnfqo9sm3Vfp8Dm9yv3PPDfr84Rft3nx44", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5gqQghDxzGhAxGn4URxx3iomBaf9UZfKtrxYDBwboc9H", - "targetOrders": "4CBcLi4X8srEnxgK8DYJxo5Hshyv6CjSRTcuKuxuJR5h", - "baseVault": "AvxfwJon7pUf56h8LWpmj6GRggjYtnQykcKekAvXn6Yb", - "quoteVault": "Gp78CMzsSppdqtfHiDD5fq7QVZgUDzg3TPsgfk6vHYYD", - "withdrawQueue": "EJRCxzn1U5BupMh7sEqiiS7WvcWSRjerNGbmK6kExHpf", - "lpVault": "AFhtegx2P7vhn3Vu34Avk5aaAuvQfUZYpYmGDh7wsuPQ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "snAcA1sUig2DMZ3LdkiogyMQie4iNFpAVkjY5wBLMCV", - "marketAuthority": "Cc6ca6opb3RXER12x4TNttHCggeqMEWuyZcYewrhdo3i", - "marketBaseVault": "4vHcURxrujfRgRzTz38g7K13U6CUhUsYyEx6y7Jberxm", - "marketQuoteVault": "3WqizwPMC8QSR9jpFKDdrnBRSUnkE2gh1QDAcxyo4cTU", - "marketBids": "DBuqAuHzQQh36tWRGr1w8hm3jBP2XL6GmrxkFeQ7cLwk", - "marketAsks": "7KF9M4dS7k6KtebWpkhcyVgYBw56LNuwtUYjGv8VWYjH", - "marketEventQueue": "CUSeWMPa8UBTKkxrqztP7brjeiyj7ChKDstgWvYFom3E" - }, - { - "id": "6BjaSvQQVrDsrFpnunUVHe1JYN4n33jyvHJ12GafkzxQ", - "baseMint": "3VhB8EAL8dZ457SiksLPpMUR1pyACpbNh5rTjQUEVCcH", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "4eUSRzp3D81uwdHvjKUAKT2s5Dh8x2tDDtWCP4gAjrVD", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4rPnkRJXwtnkR7awACGU4DBvNoD97rUc7bYzrQt2iQMN", - "targetOrders": "9fS4VLuzco8yxvBtkveRV8tqA7Z1bxPEzjPbkaMGbfQR", - "baseVault": "E1ueUJWfb8j6GmD8MEEFoyMxzByq6RbQyzbydy4hJw9", - "quoteVault": "Bnsjkiu7AjZPTqt57DKRwRGVc3dpyn1YGsK5pyh1Cn8n", - "withdrawQueue": "QYnvQW4abvkUoXmagaAx1mmkQWpWSG3qBGzGRvAEjbe", - "lpVault": "DMePkHaNV2pd5tbuLtL5CaCmToWkNYgdtKkdAKPC1qYm", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CtLUvMyGDEP9dkwo9yR93s4H7eibUpUHmVUd9YSKJsPJ", - "marketAuthority": "2EF11SWR5eyzyCUsWNAPbfTpaDJFRXegnC2vgu7NcTAF", - "marketBaseVault": "HffacYiGbj4DY6WpMMsY1FQZfokv6byk4pxKrt4q9DsL", - "marketQuoteVault": "CjWPaMQqUQa2Q6wEELKTArjyxyXS5hTJ86cPh4RqRWk1", - "marketBids": "J1AqjCCb6jXisxBz4UxE3kvPyNbvaeE8d3zsfbsppiNa", - "marketAsks": "EjUrRbgNxSWQWASfx4ExQx1JXZMGwiUuUKXSPVM5fSvG", - "marketEventQueue": "4ERewUuVBDGw52xmKYAVSHT4qjfQBuAUjLehXoHjQrYd" - }, - { - "id": "6BsLzbHNj86822gTryDYwDgQyhkaPkCu7fbhxLToSvNk", - "baseMint": "XwTZraiF1dVh69cZ2SpqyjDLmei2uVps5CYHD9vqK6d", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "4GAhnhdzj2KyrEq9kXnn86Fyu4tga4RBK6Ryg8Ne43vd", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6c3jJCZZqeGoU5eTL9oakCvgqR2h9yGBtJRRZRkJY4Pb", - "targetOrders": "CoMvHNQU6AdPvjixk6o16bcQ2N1oy565vAe1aWFxtrgc", - "baseVault": "8eQeb452Mfkf9SKg4qczGez7YyVFZTZhkYGesPEVFmyu", - "quoteVault": "3n7kwa3j5STCDn3jxa63uvvf4KDUHkThe9B6XDJ72fS4", - "withdrawQueue": "EgN7ibtpdQ5CzqoK5oXHrnTJEXPPBE9rKu7wXdwGso56", - "lpVault": "Ed1ChxgzgYUVB6XyvT1XeZtb1pTGoZewxg8YafWj73HW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4CrZhH8RFGsGBF1DkBkRuqVJ5JFCvQMkihnnkdbkQzpP", - "marketAuthority": "GxSr6Ge3V2kym5yktER84JPBzRoVoiSUBTyAFEcaM6Ay", - "marketBaseVault": "GJdnQaTFaF63apmdYYhJeGKduSVydYX9bqkcW9CUnLGi", - "marketQuoteVault": "Ccswfh5f1RB6F5rrECFvtuko4JCdaaU2AwcGtyo8kdbF", - "marketBids": "HPatzjNDDjvoxo5BZzxziJxppQPvVuCQtGzjMrRn9sLB", - "marketAsks": "Avo7N1B7HbWg1QdUZvU5sJMEhrUJDQysmZ1AXGeJA8CU", - "marketEventQueue": "GnFP8SE84Gz8FJNKNhFYn9qQAFxgxS58XNtqrmeHYGVz" - }, - { - "id": "6btd5ZUwABzCx22GPU6fmnkapm22gxK1Veb6Tc2thAgP", - "baseMint": "At5j3zhbEj8mfFsSy1MPbjVhrX2uNmRMPEDZiyFcETNX", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "C8iLJLZseTkfqExr3gDdr1fSgcL1C4u2nvpafXCv41yg", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DxSaCLsCvPuYF5CrewzczUgxhqZ2PNbJadFGvewXSYzm", - "targetOrders": "7o8xQBDqvzFVxS365kGWhHV9WPPC67ny44qCPaB3T27C", - "baseVault": "GEes7MNVWp2EkPtBQHVBj8jycS5MUFYpBcq46XM6nWsd", - "quoteVault": "3VkGSJNUTiXRKWjn6EF7SQWHj8rbPCvJ174UPF8WdnGu", - "withdrawQueue": "AVdWYcgLvLWd2SEY25FDsGP8zU1uAPNSGYCLNzt2yM7Y", - "lpVault": "BtmYhxzZN5CoZe7ztEwwWHTfNzz4B4koGC9MWbuRtpDK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8upczws2fhyd7XwJzpED7bFGQcEAsPb4tvHTDM84yAm4", - "marketAuthority": "DwpwTudoybm8joSUfybgHRjHSmbuRfYgBRtpj6krnpmk", - "marketBaseVault": "CQoxG65TaT6fkizDzsNug6ZhNVLac16Urgvmf49z8aVz", - "marketQuoteVault": "M4cG9vUk8xZ6MLFWpzaC3LL3JEhz6sVSm9Y2QG9CYbW", - "marketBids": "Fn6u5JKHFmnQh9Yh7a9KDwxgH9WiwYqRAZn2YcmQRsMD", - "marketAsks": "9BS3hBr3xKLm9wPNVqAbC91vcM2vGkjaRXnU5uuPAFgh", - "marketEventQueue": "81Ei6ifYzYfmZ6mp8ARwxkhkYwyZajhJPTEgSzW5d6Jj" - }, - { - "id": "6cqqNCnokurWzVacRZhe5P1mF6kR8TLRif7DaRsUAbQA", - "baseMint": "BHWmFNN3V3NabLGtJKZbbTgxgez3WZaeqREPXnvFZLJn", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "55eqLhyPB8KaCwkAL4bGp5RaVaTTyZabs4mQTztmA4xP", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7X8NbwqTDuTBE3wc14uvUo1644w3tV6yUJDExDR48gnv", - "targetOrders": "2N3B5gd6GaoW7WdBzhst49u1prUTCx9KnrvPbRXimw9t", - "baseVault": "AaHduKLLH4NQPednPMmxqnRq9yzwPyk3GDE9HKwakHgF", - "quoteVault": "4taZvd8MbgMCMDf7gg3i9uw17T5cf9pXSvodqwx63oiT", - "withdrawQueue": "BhhdeKfSsDTxzxUhfTtEqz6SaoHFAXhQPoa5SKtF1oUJ", - "lpVault": "bwT1ZSLjfMZFXGzV1GnnCYtMU26QbzogERuz5Svijnb", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DxP2y2sTcLqEzKLCM5JHA6Dx4VgPxh5Tka73jaGmMjba", - "marketAuthority": "3BqQSQ3JiYXkpw1SEaqCEV9F1XKC2YRf2AdfHgAAgKwR", - "marketBaseVault": "AQptiaugse85dRyRDNRNfQciK3zDNFyaARP2DMcXS4qB", - "marketQuoteVault": "648iLaFMDCnpr19LAUf2pv8T36G87jhEdNoamxYVEuXx", - "marketBids": "2mZHqN6b7ZYvbDkfuB9VRPQv6GMaEu2zLBDrcBFBkC8T", - "marketAsks": "CPFj7zDUiYS8jumaaGLtZfZ9fjGuw5WPzjzLBcZtptRb", - "marketEventQueue": "5rgrUZ1YwQagoYezFUd5eGd1Hwk4QzYfM2uiVG4qgsR1" - }, - { - "id": "6cuuxumHDFA6k5yi5Y4FRrKeSXZxk6jJdroSuAMAf9Tj", - "baseMint": "z3dn17yLaGMKffVogeFHQ9zWVcXgqgf3PQnDsNs2g6M", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DdEe2CrmYvsrxAWecEPt51iuvK5iFz5WbP2o3d78A4oD", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "H2JxncTHEzMUC21giAyf31BXBmKjUSPVe6SwnMQHAQts", - "targetOrders": "12xRqp9qAPDKcv785Ko7c52oN4r7GzNmAK6vhypQe1Le", - "baseVault": "8bY9f4YaW1wmoe28eRakWm2pEkaQXqXqpDJmhNWh8a5h", - "quoteVault": "AaLg8wSKiEqaX5gCgsMLzCaz9HT1LRrY4N3HxDpevDXd", - "withdrawQueue": "Fb2YFyJxuR72dtr4CKJDbNAXSw6FaJa18iuXN4C95Juk", - "lpVault": "26qweWRQcfu76hWGP964RZWZFyTPR7Tf8GpzksWkQmym", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GZ3WBFsqntmERPwumFEYgrX2B7J7G11MzNZAy7Hje27X", - "marketAuthority": "6KmfXDhx2X2mFKr3jMffZBfLv6tyWWkYegq8esjQ7L4A", - "marketBaseVault": "BtYaTetdr4vQQk6tVpQiJW6bBVVLn4HE6EnhFwFvcE4K", - "marketQuoteVault": "GzjhGTxG3FcCgG9oJsmEJ6KTqnffSwSWUZYpGieejEvN", - "marketBids": "3wxsB4sRfgCCU6F36fjKKCqf9ME3WFUim8gxMFJWRrK4", - "marketAsks": "6dGbmDoKiyc7VDJ6uCJyNM9zEymP97qWUktK5FrKaYtw", - "marketEventQueue": "GegbNE6ZfYR6couT2kg23fo68EvPR7VNqGR6aJELBkFm" - }, - { - "id": "6cVw51aB4WjtnNGWAmD67DyJDGZqKf7kifufqUtntq9B", - "baseMint": "5jFnsfx36DyGk8uVGrbXnVUMTsBkPXGpx6e69BiGFzko", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EztnhYW9j8xpLsaLyCRCwebazjfgA73eXP8rECK2wVBW", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BayoEaHS6ssa2sivrXpUPrp252XXr3bocJZQjRzH29ew", - "targetOrders": "HD2rWXBuTZBF1peLDFzMiicVowuCF3FY2BXXSq6yAndR", - "baseVault": "DK6Que2ZcWDARnCqYudVru8xVGcCYFGTcHe8hdZeP3uV", - "quoteVault": "Hw5AvLXZX36ARPCzibr4gkyj9HTrjbbp95xrkyci1FfT", - "withdrawQueue": "G4bi4JrmR9Xop9P6eJGaRsXiX5qYin5by7JnTLXJ5do5", - "lpVault": "7Loc9bZNNTMjE9r7y1S9YRdvCyAzKzpGkQt6D1bPskuZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "G3Bss3a2tif6eHNzWCh14g5k2H4rwBAmE42tbckUWG5T", - "marketAuthority": "9rLj7CgZTQFfdniLufZ9Bp53w21SyGabRhhRe7XSEo87", - "marketBaseVault": "8X13R4qM2mXqZY6ikvpTwP1JywmzhoaWxzjiGSiwQ9o8", - "marketQuoteVault": "AwHZQTt6iq6quGurDoV174oQEFS1gmK2QQQojG1md6XU", - "marketBids": "GYSnvbxxRHbrMvDLb1az6R1q7u6ykQRh1cH1WASmwqTC", - "marketAsks": "EvJMoCo76wmcZEK45CgeGQHQxAaRRCWXLxUfVN1oDENZ", - "marketEventQueue": "BKGJoK5HWMDpbgbu3jzmCG99shetX86JTve9aY9Hr79p" - }, - { - "id": "6dF5ikiPwC4cLVNvtU4rtwUrhj2qri5metfdQuvJEnET", - "baseMint": "8J7yrjW4JsZYiLUMWxyHu5V1bStvFQ7yD3jHrkTk88wk", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2uNzZwTm9Rw21p8jvdVLdMJYS4dbkECFUrB4SMD9rwoU", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7Mw3x3QWHZWPStTQnaBChe3QghFRZsZXsZGekUuv6vQn", - "targetOrders": "E7tJUefC9LShYSQmryG3pkHxZPc5picvFCtaCzwd6kfA", - "baseVault": "2pj8d6Eka8BMJ71CyMEfSXHp6di83cHjgFosjrB1XacN", - "quoteVault": "LhE9SWfFYfXZ9uPwZWiMJRyQsciFTfrhoNETQxDXDow", - "withdrawQueue": "AsmsyWgXfjBF674yeSTBZapfj5Qo8VDkRBmnkR9iZitF", - "lpVault": "FYMRkgHE86fREz8joSyQnrkuHXLPd3f4DLdn9cBSij2h", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2jVWA2kRbkebEfeajJFx8tGk2vEis6zpFE5XU36fbQ7G", - "marketAuthority": "A4aqm7AXsnHjykcwJvkf4CBHdPt8ohVpF1ZiNVbNi4sT", - "marketBaseVault": "GBbmQmVC3G4q4wJWmk2Rg6oqATk8YL1sx63hv7PogMhx", - "marketQuoteVault": "61ZWJnBzYnsRhqorxSsXPm8HqHyn1PPcFi9fe5vt1xWX", - "marketBids": "AgQ93EsMxByWDkKdexPffhLdytEGyHpY11VW4yULWfTG", - "marketAsks": "C3vJfisMZMVLPwUykDPcEXjbyPn2forPd6aizLbVEtF1", - "marketEventQueue": "1TLdCxEKLdXzyH82HUKTRC45ZAPDuwpbBEt1av28zfu" - }, - { - "id": "6dgLrWRf9egVWwbNLRSnzKpDsyRhxBNNWC9LfZ8omjF2", - "baseMint": "2XSuy8RSESbtYRBbVHxGWuoikn3B6iXKVKzN4i3owTCf", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "TULEMz16EjmGjPKqpLo73WPVZwUinhqodwzZChx9foy", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8Q4vikpoW5T9GgVi8Ux6P2XmdQvBze2vntXZ5VAAaZwA", - "targetOrders": "GgfLaEQ9cv7xyZevmajXcvphP8oUHfqH32FBbBF7zxeq", - "baseVault": "2tee226DUb5cmrHsDqqBC7MTp8ZLrwPRpBBB7hxS46HJ", - "quoteVault": "DD8fVA5xFiUEJhrM5f4DQquBJsgbxiDwNFUmijnUbdkv", - "withdrawQueue": "EQXkjjGYBT9sipJWvU3HxpEXDzH86wfDECRv5YtN2PHf", - "lpVault": "B1Qvfa6bjuWHqu2LvQiE9rk6cfB9n1YhMrfCgprL4BX3", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ADKVWUeXw81E7dzs8PuCPRxUvtWMdpjFpYbhiyNoQMwu", - "marketAuthority": "5eKxnUZwPNXGYgAfkoRHYZB2MXwLXn7CdfdHg8Pqq6Fn", - "marketBaseVault": "2ifMAHicRBSQRMFwfgU39Pgwyq4WZZ7CFiTwLh1JRhws", - "marketQuoteVault": "BqSKLbCjFfg9hWwkyxAiWHSJwMZLjKwjo51dKeZxEWyv", - "marketBids": "5At8SyfovD9hV9o4MhWYz2btqnYtmVrRMCSUjD7CESqr", - "marketAsks": "AuQLZTetMNyhxCwcQ7WXxGaR9fAKnjWqtuQGM8KarGn", - "marketEventQueue": "A1UDsPcJ7Dupz2F12SNshhzhLYQU1AocM5eTewegA4g" - }, - { - "id": "6DX194ZeSQ3627aABmcuC6tWUb2UFhVXnxaZKVMsZkFQ", - "baseMint": "AMzb4Tc7gDGHrsz1zUQzjtmQS2AXWuejveAKXKSpsoPU", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4nMEPsVzNuXCSewtxfetgtoFQcdpfXUVTP8o47XB7dRG", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FxZxntjHyxnT7wy17odqvSgCWMS5WSwo8LnkewuW1K7z", - "targetOrders": "ETMCfcgbWA2eRWTTNfi7jUP9eBuLWF4Q1RxJ7BZ7p3jc", - "baseVault": "AB8jCrJyDHYf25r9aWohdpFFmpGDt6zLNpZc8oJXEPjc", - "quoteVault": "7Y21pUkgRaaTYZj7aX8oes2kJ9ticy1Zap1WgdfcUaBf", - "withdrawQueue": "HgZz1Xk3dAUFz47HUbvmjrrFNgkn3sfApjNE8S8BFgUJ", - "lpVault": "FzhwCfXqKgqVGhnStHN99XUpGgwEq76BBaPQ2AmWkemu", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "63PTn92SL43vSdNSbKRvPxhvNr2vzsoXT2aakz1JNpCb", - "marketAuthority": "AhLktithhKW9VuBTvRbPBnXwfDMXiAVu5cu3JuvfdFHR", - "marketBaseVault": "HspdnWVXM3sowSMQqcWC4XsFvfW264Eq45SsxMSeuBRq", - "marketQuoteVault": "2TwUrBqzpGPCDfZFXXS9SRcQxwMgq5Gugde7LekwcSqi", - "marketBids": "EA7kD8eHtK42NfjSAt9ptsR3o8iti8XNnWQXQ6Ap4oFU", - "marketAsks": "CkX8fw7fkkkWLX9r7D5Yp1oMkjVGxUky9EVhZfVurTTm", - "marketEventQueue": "59hZL7zVCRr7tGnwvTeXyuRQRUeoTqffyrCxpjbDdXVo" - }, - { - "id": "6eFc2YCHKNajc4ktLbnxPqDDQ2AcZrE6XwFvs4TFikPw", - "baseMint": "4jN1ebgFRx1ukK9a5RwWcfqJpUM5LeHsQj3db7g8JiF1", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "HSk7QTtwn4cEZyoYvj8yjda2XvXsCGpL6hJcHGT1UtLV", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "F5ePZVHcHqetysmyQ3em7jifBQvtfKQFi3mSN7G1qRgH", - "targetOrders": "JDfibY2ZLhfSK6TGaNoxLXpwGTFjrbsJyVwP9RMbZvR8", - "baseVault": "GVuJD5J1igLUxceYChFrbtrfXPaLLooXZeA3NkEdtXzp", - "quoteVault": "4XxNs4Z94rhvVS2Sy8erf9C2NvwpCx9mn3qa27eubPxG", - "withdrawQueue": "68S9LL3kXMsnVudPqkG7a65hpWHFLctZrqpmWxeWqohr", - "lpVault": "4XsKgufbjrQR4BKzJf8rntNURCtxkp1YQc43wCxkqgQW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FAxzkEahm9HCKVbpp51AXiyZzjScswUygXvqUXwGzdoS", - "marketAuthority": "9tat1kPe1pxvtao41joesdTLj3VSYNn7vA4vdiBMwkmR", - "marketBaseVault": "EiCoPMZZWzZp2DAeqWQ2vhYBPe4WUu9ffTXzouNXi3ee", - "marketQuoteVault": "E3NBNkgqEVgQBLagrxN3UcmZEhzEvkaq125ER9oWctDU", - "marketBids": "BeNvPVCb3zdxDnb2BLmmW8G5pv6fN9L8kDeB3EMRycgy", - "marketAsks": "F3pSv8f5f9WHz3vKpHhdykeAZX8z7mn6oHAh4YYg6pJJ", - "marketEventQueue": "7QmAeLkKcwVJ5enidAJcgn1Q2Do3rdYnSp4Rjisq65ko" - }, - { - "id": "6ENaBob4UQXfH78z7YXxLVAkdDXrrmkquEzUo87R3sto", - "baseMint": "HBHMiauecxer5FCzPeXgE2A8ZCf7fQgxxwo4vfkFtC7s", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "B9c8bZM9ucbL3Ts11Y9kdXRmJhYZF6PU1AgrvoXcHi3L", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CWtma4SUQxx9GFw5toZwJoYbYw4gbJ8w3MpMn4RAA6ew", - "targetOrders": "HkPYUhnruiarV5QPoH7jiNhxmAQumjPZCKfGN3mCbgNM", - "baseVault": "5Ba5D4o7GUCUDgtW5JWmM6K2bbMyjKjdHPZAdrU2FEgk", - "quoteVault": "14Co6ZqYSEyChYeJr39Rgs5X1Qepe5DPmmNjjAUoUs1F", - "withdrawQueue": "ALe9cD6TWdx5rDJFDaNRffAwADgpSPMZEEnG8fPzia1h", - "lpVault": "CNsUYLjV4WakbJjbeZJyQpPcvYP2L3CX8Zghsr9CNYEh", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "F4CtSAoT1xrQSgGAJ5sVBkhofjbh4m7LcYtSKk26u9Ty", - "marketAuthority": "2Pwf7SMLsUjN6kVq1DxZ2Yd1Ge3fHw4j8xW4SfBujxpk", - "marketBaseVault": "57uzrDWQm7dvg21acftoLtCB6g1TrEdwfakieLeLaUUU", - "marketQuoteVault": "22XWrZyt2VH9DyprRAzdfQCw3viuM9J5SDP6kFxKusY6", - "marketBids": "BwNKSof4wuuevrSp8dGazC7bNK2GbB2FCkg2pKknM5bN", - "marketAsks": "F3VPnpuGoY6rYaryKmZhgt2GprbesD7B4rp8nTFwssra", - "marketEventQueue": "842qBpXuoeDQftyg863YJDAenJoTaRQkB88qcNK6ZXCi" - }, - { - "id": "6f9QyesswtuByFuXEDBqSGUGr36sREPsvu33KcuqVwEK", - "baseMint": "F9tytWqLUAPXQTy6dejGtSgvJQZWYC71naD5bCi6caGX", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6EZCYPRwmeDqZM3PjcfmJ5b2vXEVn5VmGYJKjkJNxR2i", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9FGADSBnVu6nDDHR2PiE89T84x3jCaMo9eNnWijZQDjM", - "targetOrders": "CrdXyYyTKrqtRsqDTdsaYDXC9dXZKqxZfwjBykSoyShN", - "baseVault": "Hd9HS374KDpss5GZh9cWFpqhAPLnVPRwcAQs71gmsgTL", - "quoteVault": "9qpcv2434ZPTLAXrThVU44CrHkT2zyzXxBpXmR6BURxq", - "withdrawQueue": "CuapMR7iBDMMAMP5B2eKDsHqx21fUnt4fK9N9Ev5C93y", - "lpVault": "8cLAeEyY6x1KfvkshJRHsWTdDgh4JuYP3N9wVNCduFXF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3X1bXApMdnTMc9Aye4cNWbWW2nH8arumZgwEZaTWnDPG", - "marketAuthority": "Gpg6bwxCJ8gUrh7vx9mdGbzkB9vd9Bcf3HRf2m9mv2Yq", - "marketBaseVault": "9aW9AEQCUsTDQj5qXFdJurJ41WLMAJ3kUgdcHnoiBLrD", - "marketQuoteVault": "6de6A1Sfbvv1awaWPRz3hceMrxLSJheYKnj5Z7AoSzEq", - "marketBids": "Aytfvj64uk2FmxAbhfyCSZsPWxo2etwA1TcW6MDirPFx", - "marketAsks": "GUuy6PkmUoyr2EyjuwrgrjdfL8PbmZ32AUVtZVE5BhFR", - "marketEventQueue": "5mSE5KKzi7r4btqoCdw2GnnmSV5pFF8w86H3i3D1cmmx" - }, - { - "id": "6FBLmhGwCYYuUaAsZswXgKBCLncG3Zo5jo85og8DBs3D", - "baseMint": "invSTFnhB1779dyku9vKSmGPxeBNKhdf7ZfGL1vTH3u", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "EFuspVNKSoEfyHkGpXkJai5Asm17efU5hq5KA1zD57VG", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FKwYcw3f3zcWJKEWo3SSBiuxgM91EzPuzuh4zFqr5Pes", - "targetOrders": "8JHwkaQm9eutZjRPP2pCimGUdUhGh5SLpT1FVH3HSTYa", - "baseVault": "9bx3QCeqdGw2xRw8bG3LLSUhSKivUU1r8xbecLn5NP2L", - "quoteVault": "C4ibuftqdU7Mxiiu6v2LpHmhpPZGyJAnZSTnPsQQcBYf", - "withdrawQueue": "3QtzLPc3tEM34g46rk9NuQ7W33zR4GPYDANZourHNX6F", - "lpVault": "4iaSm3izqMfSL6XVv7E22xfGeD8L6ukFFvqiMqmnFvMH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DQ4j4gBEPsd7sL9gRNSDSNSjegBGuP2TDqfFubkDD9fY", - "marketAuthority": "3h1YXUBuawQjKTYF8G92KF4YiYiukWbbLosBLiUr2gy4", - "marketBaseVault": "3GcJKDhaJTZVvkHBHACvW4dZGU568XJNxS7qwqVConoQ", - "marketQuoteVault": "AtAZSaZ8g8h1nRhPZVHegwRnqmoUhcx2k5Z6qSRzBNwF", - "marketBids": "BoqTH9pSz32sC7Qqpohki9pXmPAKKfB7i2szUiidskb8", - "marketAsks": "5hYzfA6VxCxmAb7UnryndrrGsoLjj6cyz8aK4CV35Q7A", - "marketEventQueue": "5fZahLo1RBgixdCATsLMUNczXmbzGwWVn2uS28WYvKBE" - }, - { - "id": "6Fh8b3USBRVCtYm59mrNQKHyfuf7bxEtirFLfCZmSRRp", - "baseMint": "CDxwZo3ayxvTmxin7F6o9xg6SjdE4qWEDXV6MZFBevqw", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CyEqALP4CVFUUMFtUQjB3tM5LDk8UmhuvXrFpqWHAH9Q", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DxJ9RoAM3WYBb755AoQZgjeBZ3mvoxMbLjLquB7LxnW", - "targetOrders": "3u6X5ggLB81V5FTtfqKxbf6e4Fq9bNd4nmN3hSh7x9ic", - "baseVault": "8GanaduJk3XNLRGxbXZheQQN6yu4EA7xc8MZvaTT8mcs", - "quoteVault": "41cndkKSucamjpM8N6qjEe7XtHwDFtcemrRRvQgdNcCc", - "withdrawQueue": "98k7AWq8YV8JXDLZ35fnEQxgSvm4ZL4bWgWmV1jUQZGY", - "lpVault": "nuU8aYTb1n6q7mr3wauWniKocCQDczSAur8JNNCoDsX", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8Jq8eyPaFijx6kzGvYNZ2SktofMzDM2bavWGxS1N68zh", - "marketAuthority": "CbMwz1L8WyxKFbv22CYEcc1zwQGhQnb9pXsVNuqo8xfw", - "marketBaseVault": "H73yi1jbzNNzCTzU3frdhgQxx5hyvQpg7pFUea35S2Q8", - "marketQuoteVault": "9z9azV5jQZEwyBapmfYwUEbGXwcz2g8h3KGYru9MHaim", - "marketBids": "HrrnQboyvJg6TYUHiJsHv1wAtSnhBzYGJaqbzDAbCAQ8", - "marketAsks": "9Pk2yP8HZ7BJX4Km6yJ2j2kxYgh6VnZbLMnTPc836SVD", - "marketEventQueue": "H2Un6mLRSJcjSwLhwAKKfBwe7gkZ63MHMfukcDuowLsa" - }, - { - "id": "6foyPqZZJi13Bk3pj2q9mV2jUGX13sZ5ENDxsz3T8Aob", - "baseMint": "CmAgr6XtAZsR1BGrxTrbVKXsVvvC4Y69GXR2zP8XxK3X", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "8jN6kjRjgM3bApCEY1xtKskxQErxRdXAkc1pjfsXfPP7", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GmKs8JVQHGvBLEuCXX2mU3KCUECdma2ZAKi6P8f22Nxz", - "targetOrders": "3JiAwSwLFEPCXifWLehLkQV3kyDGuWYmBVysw2vtk8fW", - "baseVault": "B97fmreBdyvaKQfcoUMGXJD5gasZzRYn1hW5QgKaovGt", - "quoteVault": "7FXmva9JbKmkQZeJWHcwp5Y15mfaxA5rzfUs4qqWAk69", - "withdrawQueue": "BnXUxHNUpkpswsrPmPfyLkzzAjnQD9pP3d5jWh7cGpX", - "lpVault": "5LFxSeGJjgXsTT7KfUa8pB17TvLdfhkAmTJAA6VSyDfT", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "B2fjcGvTPVkmaG2c5TGT78oo1gPow74SD6rWWR1reMuE", - "marketAuthority": "2vK186JU9rsAtmhWkGey8mLUx7idE1pnpzVqsdPjhfJq", - "marketBaseVault": "4aCjnopnhp1gvwRUf6ZnHxwUUMuyduPFs24Q85LPx7CQ", - "marketQuoteVault": "Bz7GviUytceHEptMgy58G4RkRKdsT1NXCjn8WxYQtuFW", - "marketBids": "DoPwcUtchKHm2NLDrBdJxwgsSXkXqdFSf7Pa9MnCeh8F", - "marketAsks": "DjsTCCV3Tj1FNTdJRb3rsqbv2yVELp4vFdUDhGjfgHU", - "marketEventQueue": "6McSG1b4VU4kGzLRhUWjviQfE3XBqQbbovZhd5q9kDZV" - }, - { - "id": "6fq8oVBhqZPPZdDLvPXWsunYUpVFDzX93usiHTCsz3qJ", - "baseMint": "HFE5CwhDzXLYrnfH41712be8Pz498v2yCjyR91jZEqpe", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6imBtqxjgNaiZQ62h6GP6SBwrpDpxHq4D6MYzWZFHNhJ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3QMi6wuzDY9yxxfcFbN96PQK3sTUTyHdhsZT5NBPUQEu", - "targetOrders": "5dNwqFarbqhzsxgwCByWdcRRV8n92t5Hh6EEvz3TNNKi", - "baseVault": "GtvfuHmV7pmQCbJe4DmTKE6ygTEpF6mjB7JwexEmDaoa", - "quoteVault": "C5yraX5UmVrZqcmqG5p78MkPV5ibdoEJ6kABkELPrYiG", - "withdrawQueue": "MUszakpf7WkYzQjczgjWMfvro8eBCuH7wT5k8oDFCU6", - "lpVault": "F1KbfhyKnw3PgNANMVdrGVCnLPq5LV2AyVXvvHTnze1w", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3YTB7XBcgBipVKCW9nTDuSfDBcwhcqsJKY1ReZV21mrt", - "marketAuthority": "8NJyhsGNectJxMbp8wF1PDwnQr77FoVijKpTWnMKtuwh", - "marketBaseVault": "9SDZvxod1ava9GsUYFGPm5iRNWxtmSz9v9xAoFsuAQRZ", - "marketQuoteVault": "iADUFHucv4u6jYuDqNiQUzExnu7Hnw4qQfXGvB3aag7", - "marketBids": "86R4uSK2bHzrJu6uCb2yNUYS4w7WYaduNc4tSpx6Pxyk", - "marketAsks": "2VH1rZ5agpXojjKTxLRkud1dxyfgK2pBiagaLx7JYUCy", - "marketEventQueue": "Ea5SeH1vCzFsfKej23BiNWzwur4zdckN2owRC8mdcB2R" - }, - { - "id": "6FuSKL5cdEzCoGGfe3EKUeVFoMprv6goSLJgU5muEK3M", - "baseMint": "BjZ5Hazjyp9LrzfapAHYZuceWm6zJZDqMH1QPCWtsouq", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7uAnVKUFDjMWfAumKvxzAfiZDjxJnCvsqYJ1y9GPNkdq", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Ds9czdex99gJCZUxi6P7xoxkabsWWgAmBBjHnzr9KF3n", - "targetOrders": "7K9QGcWTARB985uKVBVx6VuzyfVCT6LYKNdYYNX6T3o4", - "baseVault": "94QXjoENnv1b6E7MnSwZaCBHGAr7XuiWs4i1NdBGU4ak", - "quoteVault": "4uuqdhJPiz6PeqjKjZ4wS1J8STnU8LKouTLwFC8SWim6", - "withdrawQueue": "H1Pg7XxPE8Z39tgmjVQe2XaBMRsDHT9GyU6LYYgUovLa", - "lpVault": "EL9PCNPCPxeY22C32dMdyHnZqwdBVH7AUDBg2Cd2hTb1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9Nfa3UshNn5aHVirF3YCagnBFSvYms4P8w6CJi2D6hMH", - "marketAuthority": "H4cX1L97QGGU2UUXP5aVXB2NjR6ijAYAjWubyg5YmepM", - "marketBaseVault": "GEwcZVgcrHEpo71s6VKeB5TJBKFhvmXqgeK5nkLkN2qj", - "marketQuoteVault": "4KgBZpgW71hevMaaN4NpeRy1kBNToYUmgGnRS7xcqf4y", - "marketBids": "Bk3P3qnFJT1tjLyxZho9jv5QgDMjoQR5tq8WMqschkxP", - "marketAsks": "A47mp85DcEN9Dg8GpnkcvP9THG2f59AFGfspAjkVCus", - "marketEventQueue": "psfSSqbUGEPKkzhW7MzV6QHub4sHDFS99btsvk9h25R" - }, - { - "id": "6FX2dFTckHNQG4uWjiaag3fHhpP6ZnPMEgak7ZZKJx3v", - "baseMint": "8o66EVAf4u2Hr21m2tuRrPtEXFPLr8G8aL1ETStP8fDu", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8MYTDq6rbmnRnnZh1Eup2wzUbnMDiwWUASNMZmSXkseH", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4VMoy4dBcKZWzywV6pA9vj1YztSiP7A8d5pP3FZYV8YV", - "targetOrders": "Bac7zKtZBxXkX6ZCAaeia7n7xem2fefCpCDQLAm5wmW5", - "baseVault": "61KVaBa1QK2nsb4RMnnik6qgnfANFV8PvFd9bgVZ8Xza", - "quoteVault": "C6gfrxPbYJERJRgdDbwES7FT9yTWLCpfSHyHzCG1HSdN", - "withdrawQueue": "HSw6aCka1qw87rnmdp1hXEtnT44uefY7wWC7PSQKioqS", - "lpVault": "GMNtAYurMJ4q3ecaU5AUxzXeoSRbJy34jAFLWPipm5uw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4KvCseiB6zv588tLuQtwXzXp58S8RobaAtGZiQJRx3Xo", - "marketAuthority": "51qdWzbKgGrpef5B2xCUzjLSXs1LcMtVgPwrDPnhkP1", - "marketBaseVault": "31XRkBSuUGWL7vgciP1T58KL9Q2Mj3JMwxrD2HkR77Te", - "marketQuoteVault": "24UyqnRdupz3uCyCtwP6gnW46NQtj7fJqbon5KtQg9qj", - "marketBids": "H3Fp4CAkUVz8WsqdP2ab4LzHksqECA8MbMFu7G2rL8Vf", - "marketAsks": "DnU2mbKQwximNin46t7q8Jdbd5GYb3c4KtwCTKqd7Uj", - "marketEventQueue": "GUm8Vh3rG3ucWBiAi6Z8HwXmo1tWnnPuGAkDk5MFL1uj" - }, - { - "id": "6FX8NJyQDEgqQhoJXdTKcxo1oaGMtS4mwCfPVTubiLCy", - "baseMint": "credTHXbrCuzmy4M9ARGvz2JoSJWg8LByPbyXBhNyz7", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "8wAyoHmzgXTXtVadevPyZveqQprd3kWSXdcfawBDjf9w", - "baseDecimals": 0, - "quoteDecimals": 9, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5CYfXSso6RUywSKk78E84soAYEjY3nkKmP4PeA5CSDh4", - "targetOrders": "1pnriw2M5ApVdwhExK8ULJEopwGubAkFeUXKTek3xig", - "baseVault": "BRmM2BKE2u5Pk515JUpECbuQZfixowsCr1h3xT1MPFWN", - "quoteVault": "9ZeLXx6UaU5V78ftMA1K8ZXo8bv4bSVbqgrGQs9891xL", - "withdrawQueue": "3pL4ZPygPjjgtnx5krTr5XjSSvyyNcyFcsNWcr8vR3js", - "lpVault": "frMWkBRk24zAeBgVU92TsNW1ELCog9eD4nMeViGSeJt", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "JBQT9ixtsLfyuL7QMAwN7eBSnCQAFrfShQUYpNx2kJ7s", - "marketAuthority": "6CG2na8Mg5t8G85Qv2mpi2wWiegRYuUvGjLXkNL4DfAY", - "marketBaseVault": "6hqwW2Ysrp5HyEcMFjH1zMBZSMAqmgxBpKtvk5etQrds", - "marketQuoteVault": "2zDCAShTa2qap6L1dXz7gs1xX7vqDCDR6FYmAkANNqiE", - "marketBids": "GJn3XxhzPyyZhQhW7Non6dqAXf4zAj3p7sXuKdZvse9y", - "marketAsks": "ECu886mUEaHNM3uDhdCiaHe7Eq8XvqQ9CCXN661U2rgt", - "marketEventQueue": "HYMX7hRWYUevELaoZX9765WcqNjEpvYUvDKpyhoRgKiR" - }, - { - "id": "6fxBbizT2cNeEjBjL2jPrrQ6ydw7nS6ojFLfXZ4ukcVk", - "baseMint": "A88nzMeNHiaRKMMGU1Pzd1HgaBJUgzvGZYvDFzJvuTpi", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GmSc7sibSgukfm4YbHWMSNG8eQ5SPXt7NMNExCGCH4N", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DZVXtB3LuQhZ7BpmhGkiuv6tFSM19RcLAo7DwwsiXmbP", - "targetOrders": "AfUc2K5NZ7ohmKWEGHCr4WNSwrFPaM7iY6EmTRVvPWZC", - "baseVault": "3PssiYuVqqxmrtocGXntgbgkPb3JmFZ34Xk4N8ktfhoK", - "quoteVault": "BBDr4sgzi6EYSPXn3PxLjhmTy7BExTYzss4st2c4fAAA", - "withdrawQueue": "DrfPyfHjDq7fS5hTv8mgm4FqzP7vASRbPtqfMTqpD8iz", - "lpVault": "E2DXKNYKYFuvM4mLxL4yYXFzvr11WdCq2Af5Tkf1jSkd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Az72Lc6ynLMG84L3HkL1E923U41XdPDsps4Vy1M8fYKS", - "marketAuthority": "CL7S3DUuG6Z5e3fo4mQok8Zjyt25UGX7ynTajAfnT7Pr", - "marketBaseVault": "EthBYBM8gXhWVYGyrNiHwN4a24bWqiXkdmgDU6HyH6v9", - "marketQuoteVault": "2ZzbfRnhA9Wye5W4ThmMVAtbnNsaREVPctRLugm7jTe6", - "marketBids": "C2LCiyh4nZEH31AsaodxAyaXzb6GSXEr22vMahUj1GnY", - "marketAsks": "HCuDU24mPjNoLJR4QQkmY1rAS7NAuvBkwzqBxGZmcod3", - "marketEventQueue": "3mG4x6eqV3SQfTPLjG6uFXDG3qarAgHhaNzQ8tjbM5qf" - }, - { - "id": "6gM5KKZk69dPj4w3d8bW9w146mQ3Dy1Eba6NbCRA8yEa", - "baseMint": "FV66ygXAXXs556MQrofx89y2WUGt4G1NWBXL9BZGi7kF", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EzY2BX74DBaWJ793hK4bSKhgmJBEZZChSDnkGs5RxTy7", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5bNHTizjXbBBtonRwaZtmUvVL5nyaBk7C53Wxkpr8hQm", - "targetOrders": "6um2xihvCW9ZTygKaSoau1iL7FF6ub6pgD6USy9Dbzar", - "baseVault": "CF4xNKG3GFE3HE86yGC9kgyfyUUx7GztLe6oHmMVczPH", - "quoteVault": "EJnzSR7zynZVDb57BFYeKXZfy62gyVxKNRuyvf1anA93", - "withdrawQueue": "GGiWY9NZVEfijsMJ1xxQSX2obY7r8osYV2bQg9mYoqiY", - "lpVault": "EJJ3pUMVuzWGR3wUHHAAKWdwhaUnYHnTAQa2HVx8QYqD", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2TGTuf3v88SZxQPb8VDNQvwzRBo1qXZZZjk3CGCDWPwj", - "marketAuthority": "JD8hcKZkLdvVYnRLWidSYVvpE8Akvr7DibcYoTcE4HFo", - "marketBaseVault": "4oVpCFuofs78trD9fDeTzqEsDqwxMSCEtSbL3Kivrcd8", - "marketQuoteVault": "B4d5v5oEnoy2z4xKD9BoLLrrTZMkERzPt5o4YedP811w", - "marketBids": "EZivq1MnLrigm5YrWfEJqnvz2WrxDt99juTh3TpAAq49", - "marketAsks": "AuWg7Abhg2tvgs4mee5B4nzkKkprHSKvG86fNrWCNETj", - "marketEventQueue": "31AHC9nej1QwsApHJCi1PNbw12jNy61SaUpFFjD5vWuM" - }, - { - "id": "6grVhTFRFd7uZJejVBippPLRqA8pNFL8XvUYjqLniYEh", - "baseMint": "GSaiLQxREzaxUcE3v28HxBacoUQPZNtXx1eQsCFsX9Bg", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GU9ZcmekbrfxfTtx17C6RnVpP8zDe3JVHAbV8UJfwnxu", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DGBVcuL46xEX4Kjv8jgyx9K6ohE5LEFd76ryeq8Luk4w", - "targetOrders": "GAqmeaYHA9kHiGMgtmyj3Rrvq1YBzSkWXJUcN79xEGK6", - "baseVault": "AHJLMQq4Lp9WmcsrFZEw2TwVVazxF4P2CbM5wFiFKBwt", - "quoteVault": "2hVaVhQ5gPA7F8bPARARyts9mLJLRv4RmLTizqGSgD1F", - "withdrawQueue": "9B6bk9s5ZYPAWMiCsCLHAvEM98W5ppN2QHaMjN3oVvqE", - "lpVault": "58T3JUoTECJ2zhCeLrsCid9CixofjFgqP6Vq1AycGHuD", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3JR9wrufTbpT7rGzKJi3hGja7ZD9bd6VEEHhANiA9Hhu", - "marketAuthority": "DcY74t3Ra5hCtsCJmWCkyqQ5JNegWmkno2wPCowMJrHW", - "marketBaseVault": "FGHkYGAQgDwMf5Gzmz6HQYBphrzEJ4XXxom9TkZE3X46", - "marketQuoteVault": "3rp3H1mivhFCb37ySbmo1e1yGzCR64cBxd1VK4XFNB8E", - "marketBids": "A8o1xVTzkSe2g2xvELxuejrwh6fyAmxiB2qmBWSnem32", - "marketAsks": "GXSjQHATxy3C5xd2sgrit6VKFKfivHnkdzDJhoF3FLBt", - "marketEventQueue": "CiEDqvQjVqJZeFdwkejKgAPJhyzCVxm5TKER2cAWq1A4" - }, - { - "id": "6gt1iWNLaoPGMQ2XEQZ52BZFfvpH16MoBuPq7kDzf4uL", - "baseMint": "EFjEGzfrhuJx7pmyYXX4gwrE7ZfiJMuFaujfESGdB6D3", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "B8T3v5xMXTkTrCU3DuVsyvRVDL3diuSeUdjPyfdxj71y", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Cv9KJZbEcFEpRVaobsFPniLJbcaYED4vEmgQd4MjUJJ5", - "targetOrders": "3xf8YBsxNskhcgh86n3FvVzVLsRmMHxZ9otPSfmzqzRN", - "baseVault": "8e6F2jqsoQ1rmwsTSXPwzK7ipajxwiyC8Qo3oEKuzGyn", - "quoteVault": "DQFkGwjLjYNcZCYVjbPqesxy5cYd9pKyFuW8jvupUuwx", - "withdrawQueue": "GpZt8E1hw2tDTVkkHZJUBruuay4VbUTXXGaXdGFf7MTe", - "lpVault": "89RNmdV53KayzupNkvPngv7SwwtSYR17SLZJyZwK43vj", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FVf36AYPNaMAfctpN9A5W7nHGBYxpan3o2x9jMBMi8hy", - "marketAuthority": "4H7ah2YNQ6UhuQobEcpAjhdxYdQcBM5gebxnaL2bGFNv", - "marketBaseVault": "5MQitMEtD32FdapukunK59kmAxv7vas7X1GFBZTwwHqR", - "marketQuoteVault": "GnnQPcWoVf9jZzgTgSmqDWvRSa1ZoyqRwUZVgGFTpQs3", - "marketBids": "7yRqiKnqXLXJYWL29uiFoG8mTrTYohwPo2krcKQux1Di", - "marketAsks": "AHSaqfi9udaAjkcRyBSLSojP5G4ta66M99ApPzYapiWX", - "marketEventQueue": "HrC3VQ8mukjT1n9a2pRRx21vHPWAQxnXVSjgrvJahBo8" - }, - { - "id": "6gXu1vCjJkxPqZGzcnRRE4DkH44sPwwuptu1nBf3mQbE", - "baseMint": "4qcHQruwW1NcSMxQ6v2eYKGxnGSDHdEZ9i7JvaL1ZADL", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "5Vai5XbN4RvgbSTGnyo7Ji53s5ZzkvWg5i6DZioDZ8Dn", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GfksvjxZwVjC3oGq1V8CevbvT7j5hiCjSptUxFurBagA", - "targetOrders": "266EZnDavBRTSbqL9f2iS35WiCvQB5NXLEJYyeBtfSCd", - "baseVault": "GSidSBx6CBLqMTC4MAz5RR4eZ7Vb7JJWjhgvCK1XB2XW", - "quoteVault": "CssMWAJJYnSgNvqVhVnDnvB4jjz7YS2XphowusCAw6AG", - "withdrawQueue": "5m3kGsTBJVxrZcfLev3Yh583MEtkTosKicPtCQBq6hrK", - "lpVault": "EHVXGLEA5HHH3o9pFRXEwfwwwVas27sqo71htTXtp6Dp", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7kpWh7ap6LhTt2DZQMxS5DMMe8g157sCrzRCc95bk23n", - "marketAuthority": "5YtV7qbqLYRELCNNFDhBwF9oLfJcQgzfTugxkmAfDgt6", - "marketBaseVault": "3N75p5RiVTN3GXb2ycKhYvxsEz3WYsaPotPmbix6eDt7", - "marketQuoteVault": "DHuPiTaL2ofweb49wcAR1KnAgaNLJNG2BWeUmELnuYtM", - "marketBids": "4MBZiywyCAMjKByM2uV8Fo986c6nw6AtPs79DChWWWhX", - "marketAsks": "56ScyJidcqMxv4qQhrsFCb7Fk9kE7c7Ut2JbWgfPwPde", - "marketEventQueue": "8wQAWsc2CJhMrfodhLxfS8zSd8k3xQPiDCBgs9AGaHv" - }, - { - "id": "6HD7LRUwX7bdutzMtF9ZEYhUvd6bS7yMKpLh41z58Y2K", - "baseMint": "8e2G3tCTvKAosq4BnYbDczboRVhy7xaXwbTSJeXEefJX", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "FQcxZ4gavKTBNd7PwepBczNooXS6i1NuW7LwTwCM6ihK", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "D4ZBnEG39hfwbbW1JFDkNzS6QJLgJ31V1HdQGKCh8LKm", - "targetOrders": "46o5HzU1PYcfKeFwCLy7ap8HFH6d4QeGsJDhR8gATQ12", - "baseVault": "CybsVVoa19ZvxPQfayVre9sJATTtvcQ2ouoHsW2kMzQt", - "quoteVault": "F5DPcMCwvGtXeHBrjVLxyFcGYpT3rLQicDmzQqSyx8CE", - "withdrawQueue": "F3djpggo6XGDcJcmaTRSwta1QKeCUiYBvGh7dZXjs7cd", - "lpVault": "HufH8H6qJwFuyXERWSYhF2hrG3MUeu8TDwKjUyKtF3fZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BSyeikZqhYtxxUZ18VYi1zSigKsMSe28dUSGyF5biipk", - "marketAuthority": "6ppj8qf5HhtjgTeR8TowqKhka5w3QTQdQRax1JJj1Ttb", - "marketBaseVault": "6Q6VvCdp6K2unG53r2vErL62zR2iBPKSSooMAwof2LuC", - "marketQuoteVault": "9HNbjGfdk4QGPZVqwqQpVu739VmoayfYbE8XBcBAxAYz", - "marketBids": "GbXgN24E3TAuiEgb61wwQUHDtUaZHut6RHpubvvT1HyX", - "marketAsks": "HJpMgHyoydxCtSjRuWye6bcMSh8UH1erYy4aPcZSMPHH", - "marketEventQueue": "Fw848D7EeuWxVQdRQ2AXyCy8z41et1fph9xKW5uE2iJA" - }, - { - "id": "6i7xqJzsXnU4CUcqHhj8QRvBx8dhgosg9ABJ18MLhbw6", - "baseMint": "BfbhLmrhtELjfFzrtcxpB1GoTpmiVK8qcpSYf7AM914h", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6RHTWCEKVBpLTaYUodo27BwamZ1EP611gj11GG17oKFQ", - "baseDecimals": 4, - "quoteDecimals": 9, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GHknmixQTM48YVpsTopNDm9NWXuvLxQGWUyiu4vNAyH9", - "targetOrders": "8k6pC2UqzXrXhA78dqmXRS4CUmco3BFzNhngQyYHVaoe", - "baseVault": "DG6e3wgbuXB2iGzJwJ1yeUbFtMqLAevcGzpd245xL7nM", - "quoteVault": "AyVQ7R5gvaY63oUnxatuXMLQShU3MTYXCeY1xBRw8qHc", - "withdrawQueue": "75zUdw6AfszoxmHWwKRNXjHqAioKasfCyRYyPch6RU4F", - "lpVault": "AWuCN1M95LRztiEKc2AWYRtcLgTwoiiHThK3WrkYn82t", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CcWnVtBUFqY91VX6e9273WitqmBpgfzL1smXq7X1V12t", - "marketAuthority": "3HfyQzVFnG7WuQttQP9unMkufgMMovhHkeswVTwtLRgB", - "marketBaseVault": "4w2kM8DgSadqk2jQ4WmJAjhaCLAezGbDvXeGLypWSeKd", - "marketQuoteVault": "BWiCroLeCXC2Tv7nwbFrwz5uv9UBpZZWbwtXMsrcGZqo", - "marketBids": "4FAogUMpKqPfta2NHSbbR3Qkbk1mC4ucdsaD4vZvjzTb", - "marketAsks": "57JWnpr1munzjQEGJTksR9i5fgq7hX92uUb7UjHiHBv1", - "marketEventQueue": "DELJ8eHDjB1pxrsb9WJcL4Zg42TV3U11vsJxQHNYc4um" - }, - { - "id": "6i9WpVPqxTuKgQVqJ5txvvZ1MCJt9rmePFg7pvhobfQK", - "baseMint": "HiYcF68zrpU6QhMvf9AsJkXhnho26EUMWUmkVSYVym2", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "DgVbFytpjZtyWR6kbFSzPc8FVsh1E9iWh73FuJ9oEBsV", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "J79MTeqA5NJtru3mdJtrzFUh21sFeYxLGcwRuyMyBXZi", - "targetOrders": "2MedRRcWKHkrRfF1si9V4PYcGic2XDJW6Ls7Ci8KpG6F", - "baseVault": "28eWXe6BKnRQEMaRYAG8bcKqhFWMNeKqMjrGzoEDq2Mo", - "quoteVault": "HcjMbqao3MkyKY5xb8idtS8sPsLCpNyTyT3CP48DT7kt", - "withdrawQueue": "6de2cHMtybmCsphD6YYq32V6z5Yz6voYhVtyWzMgypFN", - "lpVault": "FQ2uFQ4EYYcW1vF3a8VLnRVQ33QHjvjtaY8bXJLvx1sn", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "mwXXhhuucT2GzvVvHMgBCg41gBrwWDHBFnk2TWYzGMu", - "marketAuthority": "2iyB2h6NjsRZwwyq3KTZM7bnEdvXf53gzGZxA8MFC81H", - "marketBaseVault": "AAmnLfYVn2PxVVotJHX7u2jkMBhRbpMTRrzF8JNGjcsN", - "marketQuoteVault": "AKcGUA6QGC6becsJL8AytB1Q6NzDnpBKs2g2U1p7mvyC", - "marketBids": "3KBtvcBHJGS9cvPbXkoGsAyA2CZCCmc5NUphzgyFCEPH", - "marketAsks": "GsibFtignQUZ5WvQKFraZ5iKSgZgBAG62JiZKCgm7EiK", - "marketEventQueue": "231rRoTd9VpYJxDKtnyDJEJaZbvwqbXU2TvHJxTU4UBL" - }, - { - "id": "6J1dib2h7f1tR17ATjjTQ1pv76MqpsYbtgL3xogTVAJu", - "baseMint": "EAzCTpMGRjFmGf4MaiMVNqv6KxQNoM6HEXtPZLEtEivB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "85KJ8M7Poot2dVLhAoTm11pntz2uWuhXYFAMfugQybuS", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6RQAFYdgLehA9txowwy2TVyi95gXsghym8rvbkqbST7k", - "targetOrders": "KpiMtXVo3uHmhNm2zEBfyxFjWPTvYV9JFt8TQHCbQGY", - "baseVault": "5mZVdW5PtQFXQXdRdsjcmjsgZKCv3d6zuF3t63CTVWDJ", - "quoteVault": "GVa536zQZJmgLvm9ek1cUWRggSjDPEHtyi6mS8tE34QB", - "withdrawQueue": "3XLHtCtWMfT5GkWDE3WWiBrXa4XTvjgEvMtceCF756TF", - "lpVault": "2fHi8ss3DCo2bj1jwbsUH61RjGuQe7btnUE7Jp3LMdcx", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ENho25v7FYjo1uiJ4RTZgkWiwM27TPzgLSCY91uZcopF", - "marketAuthority": "DqbRYSkS8ZcFftXiHVmzXADChXXnqJ7D865i4ht6Dq8m", - "marketBaseVault": "ETNcGqWSygVuP9vBCvUyU75soRA3UEYQgWnnzL75ZMGs", - "marketQuoteVault": "HSPZxRLMHVgZsFPmpoGLScZFhuwEMeLjzW51os5SERb1", - "marketBids": "Hxs6EQ51Wegicvhf4cGJJLDk37sjM1DzpqQjg5nugaZe", - "marketAsks": "F17yUjJ2jazneK3juu5KgwS4Pg73qGLjKf7PLPVNVHEk", - "marketEventQueue": "7tw7bj8j3vPKPAzxDyCYbjjX2AZNXupJppharqmVFMun" - }, - { - "id": "6jagrwnR6CFRhyK1Fej2VRrs4r9sroGqUapwETb1YEEC", - "baseMint": "6GVGRXC5wf7NjnTQxaqEZErtdsHupke7Fiz5pUG5VkkM", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3s941MA9M7THkfgAvGuYbMXZyNQg2eeAjkvMjQWckaj9", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4VNCdKoRxTCHRgjYjsi9jrFjQCDqhFgZKxxmcnUxPBC7", - "targetOrders": "F3puvUBek3euBajPW8zfQT5F9zCWgRZeVhkgjx6FJ7AH", - "baseVault": "GGiym6tyg6raiBKjGPttiD85sCZfKFWpAsGYpEEMHXTV", - "quoteVault": "5KECBwpNuAtoLjtMv9GaZV9qZuSShJSZLEgAY65cNF9N", - "withdrawQueue": "9XB11ZByrH9vjdMiYFXvAFXB6DGDmv2y6Um1vquxz1fN", - "lpVault": "Cv6FMrH4q2XMdzgcLbX5xuQGuiT4kYmFoPaZGnNYYDYS", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4PAXPdsi2G5e4DJ2xRhkAfeuyjZf85u3CkSGCq4abSKT", - "marketAuthority": "2mhusmvRkhTEGZ1cQ2rZo3n79UKt1qbp6f1jL11abLie", - "marketBaseVault": "AMzd19d7KRoyobnXyFjNfVfUcM3i8inZrY9PjP5VFTvA", - "marketQuoteVault": "9QdbsvGjrnJPnHViSv7DsxM2VHeAd3FCg1zRt4xCQoGt", - "marketBids": "3S1i8FbmdZNqY3mQWNNN8XzjR8xo4xnqqkLc7VLdB2sb", - "marketAsks": "CscrkT2RqmPzjD3kia1AijexBfWEuJaPPfAKxSptwRWW", - "marketEventQueue": "GDGs6fKzaSTzwWpLd3h9G2PZSuHoidgjzJXK7rjRfttt" - }, - { - "id": "6jVzLd3ufHBrtoHUTViwYoW3r8t21ZiqpKUVY6q1JS4p", - "baseMint": "wAkJboxYtboRBtz1a7ipU9eyxXw4azcCjrgwzQpHPpS", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "35hXTD9iCkXvw22T5NTqb14F37n8tSu5FeyuVALpJody", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2r9Rsxj2N89g2Ng5qZDBgJsqaEGcR6MKKMi5TcHKPanu", - "targetOrders": "HWzNMsgUXevyt1xGxCTc49trMoPUaZsPFQJTPFqoFPMi", - "baseVault": "5NoEpZd74UQY3MfQ6y8AtWytPtwsVecUZArxW6hGxamp", - "quoteVault": "H9oK432LmEAYTrtJNfq7qUCu782RcguJoTxak62T55pK", - "withdrawQueue": "7McaocXnCtxC5yZNVdqw73NG2Xn85w3D2rseiocc8ETb", - "lpVault": "Dg1QtjSf73456KnGM6XoFS2Aa1TRMoF6mDfTqY3FzNDZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Dtz4q76FQhqDU52QLCnPTwZ4mNFBwZzVcPLnJZRCeYGZ", - "marketAuthority": "GUaviR3T4QhzpSTTZNVnDk3vXEuHCEnujpsH7LJe7vsg", - "marketBaseVault": "Fc1DDPdxXZdTo93LRZjLqgfjzCUsZAMeJ4goz9vr9ihD", - "marketQuoteVault": "6rHtQRvLHtpsMHpDnHQyB6MhD5VV7FFz5ciE2f7CnMZd", - "marketBids": "6MYxFCEooPBBDNJoEBrT1yauqUBsZG1XoDNNVgBXrBM4", - "marketAsks": "J8vT2v2vBpovkGCcLmoLc7GqCpXFNp8qDn7XzX2MuApN", - "marketEventQueue": "Xw2XuWXqJP568C2tZ6i2cXgAC3AUzNuRfo6NPL5ouZw" - }, - { - "id": "6jxeFcn72T74Q7qxkMH8994Qf2xhVGmvVh5X1QgkGCWb", - "baseMint": "CYqZ4FG2Jb5Z1CWgdojej9Svhvvo8ohKEAuDvzG3iQ3N", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "CeDhySKScq6KKTVJp9NRgjiPzDHp8hdWhrKibZ4EXDa5", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FhuCr5Vdz6sCepAYSKJiZTMEvmcvJL5vsVBHgLfnNaW4", - "targetOrders": "56yAyhGPY5r29f1FbuU5EtTqoz6GoqmCDh28tEwec3bz", - "baseVault": "JDfFJ4NvJqygmx2fHH5cJaTGZXuY9o84qUU7ok6xJcr5", - "quoteVault": "Ctf66xKRrisvvBC4pi4HGkYh1DrxySPHECw9iuVCs5bK", - "withdrawQueue": "DygitHKWvC7wiT7tG8cZYBYcqVoorivYS7RaYa2h931Z", - "lpVault": "BJzqvtoAPLGkPtBdm84vkWoScyz3eufhSXjbvP6Lh2uq", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "B6GLDx2enqCk3guHPdgkKZs4RjUotgNJw39mxx2soPb9", - "marketAuthority": "ic5TJ5VifjSyfzdVK2AQEVPq4N1zvMejwnEdC4TrMXL", - "marketBaseVault": "EKZfeb5uJ8Cu3prJhPHTKziazmvpTjw5fs6aWihCeCs8", - "marketQuoteVault": "jcKsbnci5Ytu9kbg4GmVGG7pp7FTpfDYgY7FHg9yt58", - "marketBids": "EiRhT69BnPVG6KaNi9sPHgdWQbYsfB7shAECqYZfe2Zz", - "marketAsks": "HeM44DmKHr9TGQSWphXzrQWt5kHByeedckLNcw76AbC3", - "marketEventQueue": "DVYyJRX3JxoKcUYso9jqTicyFbVQCU3zQPDtibTm1XV3" - }, - { - "id": "6KiYbSCQL1PETmmTPAVowgnBBGDwKQjdtn4954soXa2", - "baseMint": "3oePHsi4fhoyuLAjqXEgBUPB1cs4bP9A8cZpc1dATS9c", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GK8u9LzoD4qATiMJmKcF6f5Av3xKMgLRcykzM95SSB91", - "baseDecimals": 3, - "quoteDecimals": 6, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FA683fEQLmWJXtYn1tQXZFnPaYr9MpaCQa1PF9XsFKLJ", - "targetOrders": "7uBT3GCaYW4rSswk76y12iK1S1DRE9Dqrv7TghSBYESu", - "baseVault": "4odYiwezRq2VC3MWoLcyhNXR3W9WWurTAAQ6AqmS3PQa", - "quoteVault": "Eydiay8FoNx8JHG434ovx24UCJ3z7q5UiGhXyAuNYPa5", - "withdrawQueue": "HRiHTBW3NNenTSCXToHFjUpRqcH8uuKqYtfWMGZxMVaV", - "lpVault": "7varqNYN8HSnnqk4jji143ZfaN2oovYW1L1x6Xjfi1o4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9LacPzDtZ8ShKArtwh58ZYE4YavdNcbg9iPaYBJetQG7", - "marketAuthority": "7EJjytmFxGSKMnqWgDTSCcx7t5wDatps6rf1cUinFSmA", - "marketBaseVault": "65vRH9RApimAhxXGUVVwVqWyYm8AYrUzR3HdYcn2i7HH", - "marketQuoteVault": "7GYT8kuFynNFSWH23rVB2YZZWGHzMyneUsFE54ZhUH2B", - "marketBids": "6pEw1Monb4Gsa7wLPk9V1FLXoBgLgvJV2TUHwwGhxfSv", - "marketAsks": "GC8AM6UZarK6opC8pjMsgBNbR222jBJud3QAAA4nE2oR", - "marketEventQueue": "HBdnPj8qQ2CjcsYqoYx96fTvjo2cJdagPiDxakevPFtb" - }, - { - "id": "6m61XzqvyVv3EiKR5gZjJNttrRcvka3pKcfod33g3gs8", - "baseMint": "9A6dgXm79ASFyG42tui86F4gQTC56Ydw3mrNL61xhdr", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "5fDj7adsBsEggFVCPqqtBx1Cvkcq8Ta7zjiVSjgEpbbe", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CFiQKpKEdbF4tN3ntE7t3qSeTtNacDe1nmHv9LRHjosp", - "targetOrders": "K5mpbi7VaTR1KbTqoJET5wnQpzhGAjCWkGe1Xz4RRYK", - "baseVault": "Ceq1NQZMT7z3eMuuFeSZX9f2FjCknvh14iZwxMaWUSPX", - "quoteVault": "95ggERgyZQsRa9pYs9iDq3mWee5JNSPPvFy7CULyUdFS", - "withdrawQueue": "8dDuxzkkN9NKp94LzjKp7Qmn1oyr6tdYZCW76z3AknbV", - "lpVault": "4D43mv5fdnr4G11QDw1MvyH5CVvycgqBz9fkfnxu9eGW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AbwkCDCzME92xa8bJu9fGbJkDS7awyDqUa7HGtBreScQ", - "marketAuthority": "9hyWJY72gE9wSUpoKsr5T2iSaf95oU5WFCtdjZdagVt", - "marketBaseVault": "Gtqa66KAkyRTi2igTzEtUFQAaqxGuJmxGXXWfE7QT6xj", - "marketQuoteVault": "ALx5XT9Y5tQNmXe9UDzBStHQaprurvR2vzRd5XFgVSW9", - "marketBids": "AM2QLBb8agAGQ3ydKiNyvi3pW88u8iPd5G5QzKTAkk2A", - "marketAsks": "FdaLWbvxj3mTrdENDNwPr1xxM7gUHoTsPt39AwMHyu7K", - "marketEventQueue": "rm3N5RfUBAQ4oEvLXFovFNdHWvQHuVvzC6ForboDc7D" - }, - { - "id": "6M71Rz6ZZJkSzPHrrFW9d7bVHZHihMPG9ppaTjEAFdSp", - "baseMint": "FgX1WD9WzMU3yLwXaFSarPfkgzjLb2DZCqmkx9ExpuvJ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4UTG7MGS7AgeRpGGZg9RmrPzByhQTnzZty9oVRt1SbdH", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ANTL2HyVRaJd26ne2oQem4hbmuD96xLJxQEdETCx4Dgw", - "targetOrders": "5od4ts3XUhy4swA811LYboc9PuGNbgucdW7zXB1rvWjS", - "baseVault": "4N2GPcRrLzyxFuHo34nWZJdLw4ZVpdzpKWLptkXA5mZX", - "quoteVault": "4cgTi1kb4AHsDhYL4kMPMBeNF1dC4nv5peZ8W6mYkHuN", - "withdrawQueue": "4CUGBPDodCMMA8gz8LABQkH8qzLoNcc8rVddznAnVr47", - "lpVault": "2nJobAJCWMKfupHDyGwkq4s2xVc7zuhX83z4JVseAbLo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "J4oPt5Q3FYxrznkXLkbosAWrJ4rZLqJpGqz7vZUL4eMM", - "marketAuthority": "Y19xjGW1M39i31dvtcaC5DXQs2zBuSGPEiBSC6PhHtS", - "marketBaseVault": "Drh2Snft94Ubw1ATW3bY6QJq8SHkWUiL7A8NSpie8nNs", - "marketQuoteVault": "2ot6efxFgLAKL6WkTP1hmND7aMmsmMB4j4ELNrTxNWm4", - "marketBids": "FbhT9oU5SNHmYKghp1vkVYJoU1Jk3hoDSB6ugBBzXaaT", - "marketAsks": "EuM6NRcgWJBpE2wbBzb19tJCnuPqzxBrbSz7KspAnxgp", - "marketEventQueue": "9ALFRpKPQwGwxZPzCQo981wPwunsKFt1NpujRnpnSERu" - }, - { - "id": "6m7pGwzi7eFqbt2D6H2t6HiWkWvuzamU9Ag4ba9guL7p", - "baseMint": "7a4cXVvVT7kF6hS5q5LDqtzWfHfys4a9PoK6pf87RKwf", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7YLuD82cr84BmfPHAdBqnytxEkWxKTATyBWUwjuPsGxH", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9eMUfpH966rsxmngKLNPCYYtt4PZebGUoyyi6LSVqJwG", - "targetOrders": "3NcmZT28WZBkMfbUnGV3NDkh9s23HxShd6qwvwTiMGUm", - "baseVault": "DuxEFAbUpFo7YwsQueRByQeraUDeBQabaug9UhcWijTt", - "quoteVault": "2nHqyQZw7dDkENWs1YrKch9TYc6Uhqun8S49gikyB4kJ", - "withdrawQueue": "Bs6nUX2ahQtyx3pJpt5DaNaWS9mqxgrn3r1hXrxa36f4", - "lpVault": "6CBssKbGfEoY1GyDMYsu86cVKKSSyHgeHV6DnKX2BuG", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GqFKHmiuKuE9egumByZaLF7ziz6VWWMUNZsRUeURQbDz", - "marketAuthority": "CTGSJ3Ni1uF4LMiiNTsdbA1xvFc1FKs4kpaMrQPWLT7w", - "marketBaseVault": "HYe5Qbrou1tdiACj9b1ceaKg4pwiFCfAeNQxSYYkG3PY", - "marketQuoteVault": "fmyuWzkVozbhLjGsQ2iN86TnK266reaFNovTcinmDJ9", - "marketBids": "4ExH8t4vR7oXeu34drBuYaY1cA67EoeEp8TNHmz7TS8q", - "marketAsks": "FwdQ34Wh6zGRhTNq8yrybMRzLJmvDbUvYzeCgidiyG8u", - "marketEventQueue": "8zexZs93kwiGyqxNowZELg1DpGazGM4dYLzFYrqGhpL4" - }, - { - "id": "6MHmAC9S4pVoRYDYXvpgsP8hQ6aFhDkBXYnM23Q8VKeb", - "baseMint": "CPvFYEMWUjw5b3za1FsV4va6QUwEL9UtXezaUjiA9DBJ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "C91trDoSNhLF5FkJzKtLSvGyf16Lj2sAzzz2hKLh3ouz", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9comv2bPfex6mHXy5T6SMp4C66UNPKRKodeenjtntYEJ", - "targetOrders": "9DvfsZ4CybpXcukHgY1tNZMZ7kotqL7Cr7NAPmHBm45M", - "baseVault": "BWAiXUa2imeZupmfWNPWN8K9abYwoXHXTecWyqwj3YZG", - "quoteVault": "mk1agsvtBfXMPYswwo6MvwLoTAHcLnfCFtdwxBDTa7N", - "withdrawQueue": "AVJDuGAYAdwTxgTBTEeVQwpErxweoNS7kE3QLMAfx8n7", - "lpVault": "7yNt1C3vpDsCq1UNjU4Ay8wZaek5ZQc8ZDfTskC4YFsb", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3LFwDpYmLUDMPJBJELWtdLkQ93sSyeVpY5qxZSoPJVWf", - "marketAuthority": "21UMMaheuG3CEk2qUJUJogGuYgZZ5r7cUpTupkFAwdhv", - "marketBaseVault": "CZDHQabFBy8B7onfFrBqLa9RJgozvWJfv7sUGK4T7Xmn", - "marketQuoteVault": "3E3jtRQdNWbtiiotNhGCh9BZzjVxWFNPsCd52L8bPP8V", - "marketBids": "35ukgdmNSbkAQqnqRMiZQqbFZac6xntHsdFLGtaenfph", - "marketAsks": "69xBRPqvMZqCdrFFDGYqZtxC5Eadrg6m4cHPvRqy5hf2", - "marketEventQueue": "D52dPZSLmEUxJXGrQrQXDq8SCF4rWXJ2Py5v671zGnna" - }, - { - "id": "6MMCYkU4h3KoseWHHmxUqscz6qqz55t9EyycRfHxmPq8", - "baseMint": "PRiME7gDoiG1vGr95a3CRMv9xHY7UGjd4JKvfSkmQu2", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "ABa9w4ziyh9PweZa3V8dH3dSdvCsAc66wWqneNGoxfMe", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HAepavewppZAden9z2cBW29EhLybyTQtC1XMyD4Dqxg5", - "targetOrders": "7bdMaLH8sDied9XrrKw8PAXCc78a6FJXUSvw3R7PoGSe", - "baseVault": "8DMksPeyQtUZUX3s7QGCTSxgnzeRfgAhhUXVoGotSwe4", - "quoteVault": "8zYaWARttBw7eqEukAL5G8Sx47LV5HkYSPLpkmgR9inS", - "withdrawQueue": "363vg4xMunmGB2QMRf75pfWeyBucoEk6P4JySPV9DuSZ", - "lpVault": "AdNYCms3TPW2ekBHkRk8ZCuw5J6FAyPRqfE5PMKXYaMd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9JpbyTSiS94VoxqC2vUfu6bDPxbToNWwTFC2jwg9B8W8", - "marketAuthority": "AwmXzZyMETTQQ7zxvdzXLUdtjbFvW3VV6XeqxmBJHmDj", - "marketBaseVault": "Fd5BceLY4pJwRKvZa1X4dWHNQPfyrFWVnTEUdwe6e2Ei", - "marketQuoteVault": "AgiSnE4NzTwiMtarRknxaLFV24eLhP3f53dpA5mf1m62", - "marketBids": "D1CXLCivhGJNHhAE4pmYGdMFjVwxsdghbMjSszxADooN", - "marketAsks": "C7bQx8AQrb9mhPRdDRtVdeGQfmBVAY1sLWBfRmukZFVD", - "marketEventQueue": "5r1s7ad1Wo61UHQMtSoLKwCJJbTRQYdgRJ6ir2nPD7Q8" - }, - { - "id": "6naYc4sqHFioLJD4HFrA2dn6qArVCeFf7RaN1SjtXfP4", - "baseMint": "FHfwNouKH37sPyvSdMU3fBPijEoV4tCtbnqANXTbuB8B", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DB932fdQGVUh37MVVTjeJ7haG1r4J8VkyQGvAaByaCga", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AX9PcnmFtJ7wmB2Lqj23aTsWu9MZUQtGNFM25qS2fgiZ", - "targetOrders": "3Hbx5hSngjRgJt6YxgE6Qd3u4ueJt3YZhS4Ug3ndmqNQ", - "baseVault": "GPUSwMWauwL6F9PjoBjBw5WCTMxk9fxumP37WYYQS7mq", - "quoteVault": "BJhYjd67YZhocPo5dAAAwgbdyaqMyet5RfJyUe2XA59N", - "withdrawQueue": "8NEDWK4hT8oVMqa2QmM1uDcHhxmrqpYrJaXpnZ6iZzWQ", - "lpVault": "3baXJQJE3WR6paJsjwe38xpQsKUtyyw51xYMJemGBsKY", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BS8bywnZ2igRf2mpT5tjahVE9sq3R9di2XH1bjDAjxsG", - "marketAuthority": "9buUJMatxhXMDKAaxnmTENG5kDNiRRhpLvLJ9JnXBURQ", - "marketBaseVault": "FRaKkY9zbaGmti43UFp69ZPFV6Y9qe2e3ybcrj2EbAHY", - "marketQuoteVault": "BayywK3JKPM1UZkUPBtx1hrwEBrqVB2JXYXFR2EGp87y", - "marketBids": "AG3QsqJR9b55oTjtUDhHuPJD1zWEys8ZETzBb9yg3XbL", - "marketAsks": "9hSg3G8h9iXYSkWdZ3oLQyyhJXUuJRxngFPPaLSZ1f1P", - "marketEventQueue": "FYaepmTNyj2udWdpFnXnrvnGyXWFTSfkPKjbkf1xkJvk" - }, - { - "id": "6NcZjR2DYW7Q33ZTP1aWKf5AA5pNUbKXaKn8uL1oPrTy", - "baseMint": "4ZEDNmqoLbzwJVAJZNhRgz31Da8DauDkpSfH9iU2vXA4", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "9T8XMdCyvRAgFgsghETZH1TfaT4tLg2npAofZPguvmaw", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DiHpUBdVJntdJf8ZhCYhNWgVW22mEBfVYGcSWuWTKrgw", - "targetOrders": "ARKb3sP3dJtKF5yzthgUKty2K716DzMQKNvPiHNnGBia", - "baseVault": "94HbbEpCd9mT558cRH3rXFbRa3weMDmYhbVLxmDSr2Nj", - "quoteVault": "5CjycD8SR6zih3HovnUv2Re97RxYVevKxTyTMeRabJxB", - "withdrawQueue": "2VCTpwcbHU4rKS5iGvw1NR3uQd6UjWBcw6Z7QmWqutSm", - "lpVault": "CGMoLr5NjVNt7V9uo3iijh6V4rHmsEsLizWTGkHwJjUc", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "fS4b4QrT6qENEYBPBrtrFiZBJc6tix1cjKkXHa1vu7E", - "marketAuthority": "7pVYSb53kL8jQnK6gdFjtJazifSPjkhEB5GfAx2rPYgc", - "marketBaseVault": "ASKuQ9Nne8W5VmWiQh4eVirEHc1o6ypg7oJ7AYTPyi5U", - "marketQuoteVault": "9RmUXZN4Ba4FLyDJLzbL9kejGFqfPLTgBfbUMUwiQMbq", - "marketBids": "12aohFJLTc7pK9Amjp9F4nA7MN7MoAZRKeyKd82SK4C1", - "marketAsks": "FExxayuiAvPv3Bu6fRrrhqKyKMMQgSZRG6DeJSSw8F8X", - "marketEventQueue": "9ca9YmzuEniQpD6wQzopRxQMw6FSMR9i2kq6UvYa4XPS" - }, - { - "id": "6nvTtyQq1m2cNnit79nenxwLm4cy7FfoCsSmDBHf6SS9", - "baseMint": "7xd71KP4HwQ4sM936xL8JQZCwE4amUko1AdCCf6Znjrt", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AjTewyw5eTJfp2hoGAavmP4Dfd8cueTur4py2vtVoYVt", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9fxAXoY24bpko9KYAujkLjaW3gdSUTKqkUUVwoEhyFoC", - "targetOrders": "Etg7e2i4ySAD7kNj1pgNYVCxRoEyx2GXQ3g4DdoVgxcm", - "baseVault": "52qfkWBm9ekh2yXv8ZJjxbE57fNDsnfX2yP9zqu2HrvJ", - "quoteVault": "97sTfTb9A347Gr6VzybcJxMMTKPxxh8no9Da2AqB7upR", - "withdrawQueue": "BLa6VZVPkpvb6z4KqH6XeGLWeiWHUjPnkApEbL3XBvaE", - "lpVault": "BEUWH8MtBCwJTAEmjJyHC2o9aSiUUjQAaNZyNG7Rt33a", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GmaUDJpPgmLq67VqQbwqhdFo6qFZ28YWJZZDumb2gtFD", - "marketAuthority": "DpufAEPhoHDhwD9Mt2jSX18vd6XtHTFtZ9NXDkeEnCiR", - "marketBaseVault": "9MXNxB6sS6fMDc5mBZWvye2mTpAvXMnBg3K2QVMNS6Fk", - "marketQuoteVault": "ERb6HvcdWTNnYj2xbt4CSJRSqSnHNARTmh9GTXqYTQF9", - "marketBids": "4nt5nQZPTn3RxE3TjeBEyoYJsjKCoojpdE3dbqyZbgYw", - "marketAsks": "AZNVu1Vy913pkTTorqJBfJGSZifT92vh9YjAJkgtGwr", - "marketEventQueue": "HdzG33y5X3mrxXj6LsTHSvzGbmSdmETktgHvz2AxTJ3s" - }, - { - "id": "6oFvjYWjin8qMYVWxctdc8kY99HDeijUcPJj8xKKTGs", - "baseMint": "EHinbFyVA4VckqJ54wxFXHWLxCCYCKxy62oVtRDTCoRD", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8cGDfztcHt3wpuaKR4PHp5UT2QJPWZJihg3wUD5K8GGY", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GcQpQNBHP4oKHDB3szPvPwfMUdyis97Ve6d8Sa8LjN5n", - "targetOrders": "CCE9WU6ehp5KfGqZMFh9DZeiX4gndVDU31JUkB5Hf8gp", - "baseVault": "D3jsoTUKCeRRh8tKYtNz98u9m3NGcrEiEyM4x9yq9tkS", - "quoteVault": "EEZ5iHch5YWaLb2RBSqRhfipq8J48rxQF86NcbLEgTdG", - "withdrawQueue": "BBQJahfJdSiidkH34KVndSejDrgTKkNQ1AEhBwr3oKrG", - "lpVault": "8nmFitMpaww14Mfp9wq3dMyLCRExNiggx28iZAPsGwgZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HG5GqQJUKF9Xd6MKxUkc92E9W9Nd1atFshWm5HyzCdHm", - "marketAuthority": "4JhTY1Rs16Dv1qSBfTAinjhi6GnY7FQ4RXY4tg49RsRR", - "marketBaseVault": "74SLq1u1DVBPYxFq5k47jnaSH6t548z4MKa4VqAQ4kgB", - "marketQuoteVault": "ErwxxyziQZSWVn3j5d5rgzsTMT9GUemedyiD3ZRELfaC", - "marketBids": "BERJCrhMQtSicsoYUhzdHtUbdiqsidQwoL2FLw5DLDnR", - "marketAsks": "CNMe9pC5q6nJux3GmNMxaKErsgdkv9i7D7bQBJtgTX2r", - "marketEventQueue": "9vRDXjRhdVrX42Tbf6FHDh8sDuUwdzZLuv7jUWmrH1Z3" - }, - { - "id": "6Php1qFvrNywxXMJnWudUB4dmy6JekE1u2kWrko8VxEG", - "baseMint": "UXRj3sUsJsQ6mkDz8xmXQxnY7DHoyZzX1UtEZriqbmC", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CDFhXDTzbmLqyoo7G8Fpp6gcMrwtM6ooA8SBE8PAcPKM", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Fb7qmYqWatSDsTUUjySon1h5BYYYKbpP4bb1xUcRrUpJ", - "targetOrders": "2H5WKGsUs2gt7W9J8Ud3DfYL8ixAHECWLoKwue4jUMDR", - "baseVault": "GSpAtyryU3hDbVfHMsiFvRhPGE415SSw9wDjDNH6wiJL", - "quoteVault": "7YA1tnrGz6sbWSg3YTgPyZxxN9dYdb9dTtPTYcRAZpox", - "withdrawQueue": "5hRYgaNWseivrny5gCQjBcbYmMGji4SPAin5rnjzXh9L", - "lpVault": "7yQw7dqAHVs6EnAeeEk8yBkvBggswyzqzpMMqzNfLwzB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BTqTFpExbykTDGnAkL9tZzraJBMZxiJPt4Z9qCQBfgP3", - "marketAuthority": "6DiG69cgtDwM41FpUiXHknbf6NZ39Q3j5y7ratD3srSd", - "marketBaseVault": "7gq4KzVMqD9F5Wgb6SYNg7cgPofNyX1obf8K2Tb6BcUA", - "marketQuoteVault": "GkcLpaUi9QwSE1msuert7ihZLuZUvBeqcXZEh2GEceyb", - "marketBids": "9ddAzzfL7ehpsKWgRQfFmLu2crsTASmd1n9hkodL6ra7", - "marketAsks": "7j2YfJEgM3FwbCsoepoPRz3YLougKgL421LKvXSufPfU", - "marketEventQueue": "7pyEVKZpid9UJ4jxgH6AAcNtqkquQiYjyLnjqKCXYpuJ" - }, - { - "id": "6PJzFb6jsbatdp8ynVAFE3ivbCFZMkqwTFaC9ZgHUWsz", - "baseMint": "uNrix3Q5g51MCEUrYBUEBDdQ96RQDQspQJJnnQ4T3Vc", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GypRuXqvJMgpfmnZrgozAVAmtDe74pa7DbtyQLabRtH9", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "A2vK2wAsLiSZrWKzeiDiMGKWjFrhyQgcnsbtgivuWNmP", - "targetOrders": "FrmZbFRkjExThRUa7HQAq1H59wVzHSDyEYc1Ay7U2ot3", - "baseVault": "78udHnJGZVwP7Z5QmGgbx6VDRDCaWDAMKyWjDYetETzZ", - "quoteVault": "6xFjcC7RCz5rNhw158WSYEoLcej96h29Dyb9wa4ouyvU", - "withdrawQueue": "BaG8dUAFFrgnmwdyTi3DnkjDKbw2u41YAAsRRvXfi6EL", - "lpVault": "7Whua9Y2d3B32WQLDUSzSNAM5PtRRKgoaedeG5CnyyFE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BJLjfdVRcbseMD1YFRGwARVGzCy1FERyzgqjFQErpuYB", - "marketAuthority": "A7St2zCJe7ANLMXSBZ24de8dr2Smji2mfjx46e3JMjWp", - "marketBaseVault": "8qKVBL8oJbNAPsKahVHBRtZaxn8eE2k8rrhzWbgazxXe", - "marketQuoteVault": "6Eah3wbD83DYpwMNAorjdV56gsFijiV3MNY1SEPSXXow", - "marketBids": "E2US8BbQ3iHpifzaVXe2SwuVysaYDJVWahLZbVFLiatA", - "marketAsks": "EeNbFzwWCSgvLmvL42YmnSLWRQY5MotJorVMkQok9wTC", - "marketEventQueue": "4Xe5WNVtLtn2zwLwctXdH38zkKHz9Vg2tQhDGhubLZy3" - }, - { - "id": "6pRoeYhWpczh5G5rhfrxz2zFFnHQzGuDbFNLkS3g3kP6", - "baseMint": "5WWRMYPchxgh3VmYGPqoq2kfzCtBLxXB9vFH2TeFeR9m", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6cf2CVHVN8hJmkQWnLPCkuLWcWjy1VZjKpd9oCGwPRdQ", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ENSdMUYzqXuKV1KZBw3Qs4Yny5t9VZdvHs5GcK2PvaxC", - "targetOrders": "J3uQSpKGrCDzVeakDd1RJ4jGxHenhmvL6NcJsZiCkq4b", - "baseVault": "9MLsejEk5abw5YCKh7ifAgFUuSDK2xJ5bsnfE1VZGitp", - "quoteVault": "DVcFxjzASk6KfBeGdooLFWQb55RFHf836PUBRESG7FMU", - "withdrawQueue": "GMTt5Eui9EY6u5LqPncsRYSWQq8PLe2pdhYo9jaQPc5L", - "lpVault": "JDzaaTjMGtYZ52fEce4ZhWBsUU3a6Vz3KNRUCLXt6K5g", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "989iWSHpw4uJmBqn9xPpP445ipwjCBLrMxzPeSwh7b19", - "marketAuthority": "34KKSRUoNw2mmeh26Q4PuNnPMrHf1Am6JG6PGaXnPRLp", - "marketBaseVault": "GM4PfJw4aVA4wfBitrGF7eV3UzAFjFAYTXaarwz3JVzn", - "marketQuoteVault": "AXCiQRS9Hpp7qDWUyeiDP6L2H9BznCDp5wUSm3HxU1ZT", - "marketBids": "dBq8VhQC1pUFT993RQk33k7UJcq5HsxzxJQ14UrJctx", - "marketAsks": "2k6D7K3n3ppwhh9gjg65sSQjYNQYbJF1R36Yrzj4qW2y", - "marketEventQueue": "FTo6QZBuQxYfxx4y19f6tUNFHY8WnShWAqDXoHsm3qE4" - }, - { - "id": "6qgCHXherZKBFqp2rdqZafk5AEK4Da6ndvRxgtcAmy86", - "baseMint": "B6aJ3TGfme3SMnLSouHXqWXjVFqYyqj7czzhzr8WJFAi", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "84QVtBcHJ3k48FXTwwgK5EdJSHs6TZTQz6ceAjHTuyvc", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DkwJptUHHrkhBTiD1W9ZQK6Rzu6Cb5SLcf7bq9zcFxuA", - "targetOrders": "brGA71YYqRdCAaiZLNNkNuJGfQCA8QJXh6d9rGTjdNr", - "baseVault": "EL9LJMa8QNtpcbHcE6ywMbKV6SDqgCBHDrpejV9Y2hQr", - "quoteVault": "HDvh1rr27tw38v48NLWQmBxTN5vbmFpjHVjsVjwZcXxa", - "withdrawQueue": "F5gXs89g9bWBTvMp57aavT6TGnrJukNvXKqP1vnBaWiJ", - "lpVault": "C9P9YhsR1rT4VcmfmgouUxzDJN1s58jLTP9MzEw2XQPj", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "F11HbEwK1HEp3eXMspjcyPyZZuAU75YHqMThcY3j2q3S", - "marketAuthority": "C3dxbTCww237rtCk8oKpb9esLMADbyDa6A1n61hQSnJF", - "marketBaseVault": "37RphEgE26YmdzWPSaaFnr61J4mCs2oHQE8drSGq4YYc", - "marketQuoteVault": "74D4rraDQxBjSPksA96GHvWLCvzJ1MV7UXas87YiQrWL", - "marketBids": "9sjH43c7Hu9CoPNgMaTWxe7H1WR5SQ3KYCUXiaZfyeV8", - "marketAsks": "4xieknXNB8NzwsEaiRWwXJ4zH3qytwFKX2ooPPZJzAeB", - "marketEventQueue": "8RSoKRJqL32juXVYL98APYi4aYCXwqSr8t3zzGFmnSfK" - }, - { - "id": "6qyxf44kWRGLJf1sX8wuS7bw8P2CSNmqfMx4nMfxhvoR", - "baseMint": "6o4f6tuvVQTa9PTrHN9pvUeXEPusN6RLgMam1Zc7tYbm", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "5dKZsKv9JLNFN9MkecXHU2S1crrES7FSZYK5mSsMe1Wt", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ChF9ghmC7M4pj6b1v4VCsfpFeDuKEAoGt7dC3fQPwCpT", - "targetOrders": "2hLtqjvJHCZdF1btJ5DduFd2uYtDUAiPfNVojxdnGKzp", - "baseVault": "51nANHm1HN6i14PrEEyrqy7sEQoX5RuCVeh32wmBsJF4", - "quoteVault": "DXFu15656ggGbB3dqDVLFPGm9zqKB6ZGsTjofi85sABb", - "withdrawQueue": "57JPeDqTadGWRyH3BMqaBzw6Zpct77wMyxcksdjHfaLe", - "lpVault": "9he975D8JZt4euQX8jDCAQ6EKa8hiZXmGnZSp5a5w1x4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9FtsCVgjreD28CoeHLp3VAFNSseqqeVBubG5Uwb9TpfD", - "marketAuthority": "6ZUUdCt9kri654aAwgWEXh1BbRwh9mukbj9gphrJK4Gg", - "marketBaseVault": "Dq4cCZ24nv5q6YRNP7djHNKq1wz4pL456kmCgA9UaXTD", - "marketQuoteVault": "7Na8RRmgYk3jXVw4j62tNJRFpjLfstnaJ6r5SyMn87M9", - "marketBids": "3xf4kwnkWHE6wfhxuyzNkcYgqqia6j3BU45gKmS2BMGo", - "marketAsks": "32ypantq3RXgA5uw4sP5q7vhU3GgFovpYfyb3WTC6p7U", - "marketEventQueue": "ENgfeq75N8fJPDaLofg2ixNfSKs9nZzcCLXGPz6x8YFR" - }, - { - "id": "6R1mfZL559ftJKB6tUyHpojusHsstHaU7tNFrEQ6FNtV", - "baseMint": "BKydRTNdaMJ8B4zPva3YhwUQcpvAsyZaGJnKA6F44fX7", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3QWkpb2ugzKTticAyvqmYSSukw5apH6jVNgMwspcphpL", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8YQBmB1phfzYiFrwgoe43y8RjDLqMTigwsENKg6Xgrmh", - "targetOrders": "Dg1DLSDcfAgqVEFQwAar8bkDaJr1NwYnYorncXRowrs6", - "baseVault": "3ijWDoqukit3iaLYNHPYztwifUs7MUmEzM8QPHX5QCJK", - "quoteVault": "5y9E8N5TCmQQSPcu6cfgbwyNyqy7oFYq8ZoWAewsfjwA", - "withdrawQueue": "4jcf3xCesChkYcRoKAms7XzfKxji3yEX5LPNCvWFwsiv", - "lpVault": "86Yju6ADtK7j4T8x8b6df924Gy5tJbp6AgZZ8BqdrHYn", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AeTCFsNppdq1d5kgu489tkamCzkbsXKTcS8hRQ8qhz7m", - "marketAuthority": "EGRgUi3j762s2Tc3Uf7QkAp7NpQd9hJMy989onExjQK9", - "marketBaseVault": "ESR4XhG8PVRi6rNseHzQ4FDT4YvFD1mfb7vursjbA8F8", - "marketQuoteVault": "2zYssn4yWpk5RZrUJbGNafqGzeGuzdXkBUoHTtmMXCXi", - "marketBids": "2gYEnVwL7PGiH7CGKEWWXFgyiP2EYHYJ5y9QmKFtXrVv", - "marketAsks": "5mE8YSbP6atSf9qbZghMEJXnGBwWZtXUbnoNf1C6rB16", - "marketEventQueue": "Ab1skWtwUG3UQk9TG6briScsrNuWKsPY4QqbhNWcvr5A" - }, - { - "id": "6R5nuhW598RGkkowNXVSKtkpA3UzHYvMATXTkD7vU8K8", - "baseMint": "Bwfe7DwmEDvjEBZGbQnDU8CrwZsuvYaed1VuQ8KDTGsS", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FwRr94JmtRNr4kB61XhN9sWKawrioSnsGDKuG5E4Cd9k", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CbZHkMVVxCuMbxpyj52PNWCbgDfRAYw1Hmgk6Y6hmSbM", - "targetOrders": "AnM2pLuj99W64bMEt9ja2fScYuNk398n7LNgMkZjE8VE", - "baseVault": "E2fjfnaNogfSNsSrRjFR78oLRDaJFfNRChjz43XzQfij", - "quoteVault": "Ax3FT4H8HHiHbhfuNGe7aVpEp6XZsLhiecyGoghX8jTM", - "withdrawQueue": "3d6WheZ9aKGhPsawQWdFh5er3UsaQpwGUos7o7MYyuGg", - "lpVault": "AnvuEL2aCfku9nffqCGP7SHXmgE1Cbq1dcsgKANbnD95", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5iQoSUFmeMpTmaiw3gCd1QMeqCy7yLtaG1QRNqwieKjL", - "marketAuthority": "DK3THgi4Hhp7yk46aoTz3bEz9N4qT7jgnb6rXX2Ep8eh", - "marketBaseVault": "8rLbN1ofgvqUPryFm2Kwjuadd8ZNmPWeCWjMrEfVTixq", - "marketQuoteVault": "AdaoN45b9F54ugNusur6NzyqEwHKMQLbsgQA7R6DHh5h", - "marketBids": "4MoNgR6s7wdWAhPhqdXDbAJbNHCU8s5mMy2vxsQzZrk8", - "marketAsks": "7NGmKYa2JpFdLERf7Uth9pmjp4jYUvNhZiErKLt4SJ1D", - "marketEventQueue": "9b7prLh9JW3SUJViF3gKAfMyuJAAmT8DiGgqFw6Tvddo" - }, - { - "id": "6roR7e6Yb4TaU7eiwJU3DvBnvbSwEWYAcLdyFhJuhobk", - "baseMint": "GdCb8jMB6mhsoiQsSoSbt7YDQzxjx4whdPvzM131jFCC", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "8NwyqSVisgQ1McCJBwaBpDhjCkrAcBo34Ca2bdqqWDx8", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HQmeFRzqhbLhDWYU4SLsF5wiYYd2Baa5GyjmhK2MuTLQ", - "targetOrders": "ArQGbTfgtfemY76qbSJ22cUK5NP7kdja2mbXss9AqFKM", - "baseVault": "2yymHhFpvJTZE6zQgxygMw7XmJwy2rEGvJuZevnzzxcR", - "quoteVault": "HNzhijejgkFKCN1c36Bu16sWcr6fzayX6wc8dqfoJie9", - "withdrawQueue": "6yPHyArsY5cvkKsYZ9KZh7xSZzcisRnSBaYNBbsTd6b", - "lpVault": "HpDH4orHhK8teFLm9WhPCjPhip1FC3NFW4w5eTKKN2fb", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "F27D1bKzCgqZ7X8zJMAxtu68CqqD44habJWqtomiJegq", - "marketAuthority": "CKn5iBUuqecbE6T5fq1tqTjKdbN8QAjDkQdBBVkhnjZn", - "marketBaseVault": "2mMa5s8bNeBPnr8Boq313w4vdLY1SBDC55KF8TvKmApN", - "marketQuoteVault": "D5WUFZ7QYU8UVjpQ4c9QmdDMS8DEbFNGtA5potyZ75AT", - "marketBids": "9vufWTJVScju2nS4sSUtrHma9do3wcyD8BfUi86K2KxM", - "marketAsks": "3BtKS6nW1kHNskbueJu8MSNfUH8DUmbEqYZC1AQYBcor", - "marketEventQueue": "Ed9244ppTuMM2z29aQw5r47rwumy6qXxLALWZtFZKY1E" - }, - { - "id": "6RPQM9fcQ35EupsrJbJU89hwQcd2NCyoGUrFNj8v55Zb", - "baseMint": "7JnHPPJBBKSTJ7iEmsiGSBcPJgbcKw28uCRXtQgimncp", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "2iHXwoH2LaMyiLL2WKDNx732rQ7CsMScNRavB1bmT5aZ", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "F91MXzkyfcXN99ENdsTRDjqSAGtxVVHnMaGnSSeCyvmc", - "targetOrders": "5JN1LbG6wyCQyX3s2cA7wMCQU2pzS5whNkthKy2NUtey", - "baseVault": "63WrZMAU7e6Uf2njzMiMbk88fifa99TAp3b3bApCqb9w", - "quoteVault": "57NCuk4cDVwuLXGmW7DRyafJM3Hxktn17LR9tR3qwRXG", - "withdrawQueue": "6kRXvzZvgJh7md8Ct2JT3dxtgYUrE2xhw7TRX9X8GXcr", - "lpVault": "612tiRRQnPjH4h74e22VXLKQEC3e5r6zT7QzbLsPtzb", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7UivYNbkerjgDYmv2s4XdFbFmCVWuyT28fxPeTVZ2ojb", - "marketAuthority": "7aokfnGVy4a1XEhhyCAkdKi2F5ZXNby8QPF6sXBVVz7k", - "marketBaseVault": "7DWHud34tESPa9AWQZ8PJAdUPZCxhGZo5kFgKSTbYEqu", - "marketQuoteVault": "CDoUS712opE4cZkYJABLg3vicEUYiQM7VFHgMcXgKoze", - "marketBids": "5PvK9pTZc1ExPaDR7B8mR3rt325YYHpjMy4gHap9V8AX", - "marketAsks": "3xE8Nf1wAwF9EKdsA26YVkXzote4nDJ3KQSQ7TCJLomX", - "marketEventQueue": "EemX4SEU4hGPGvfDfR7Kctxd6UvWJyQF6MzY3os9Z38y" - }, - { - "id": "6S1bC7zE5ZLJCKH6XJfX7NTpPbK1Gp74EEo4nx7ZfNmS", - "baseMint": "invSTFnhB1779dyku9vKSmGPxeBNKhdf7ZfGL1vTH3u", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "iUnM1NFVz5CLpdAAhAjgykRqNhjfycorASiVsGd4Rwz", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Bs5yh9HN4UtqaJDSDFNN5KdrHyKqPsXYSNDwPwv4Dzdz", - "targetOrders": "99WNu7LBHVTt9hLKjK2KSRtnisggjhgd3f89jSTaasRQ", - "baseVault": "HakeiWHgcZVahoXyBqCHxD4MNymXEb2APrAL3DMT3HAk", - "quoteVault": "3Ay8QXdYbU7QV3APMAfa83VynVzFZE4jA5StJ5EP3uoo", - "withdrawQueue": "DB4F4Etg9ii6w7wLMUW8jKuFT9YZbZGtZdZ1dDTubxkH", - "lpVault": "12dimKX42NdtKB4b9Gtm3WoqBxC5oLDkkoD97fLZPLaf", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BJteEvNuK57daBhocvUHgvqttpAVLJhBaKKbMHeZJAWR", - "marketAuthority": "9ziwmPjQVMEDBY9Jek6YYT3JgMSJomp9Z1Cr3xcpAQdf", - "marketBaseVault": "wPnMcF5759SWF1U2VB7G5r2p7Uk8h5gkUULdZU2LPYj", - "marketQuoteVault": "J8t2eX4Xi1DY75rKvAbNXGAjxSYroX9kyNpbzruzaVTY", - "marketBids": "EMijMFDeLeuLhEZKecGgdKdrm7e3ox7JWMxBMDcfiap6", - "marketAsks": "4eRKu6cmyXvmn6bFqenwT4t79MXoHAedwynnk2X3AsjY", - "marketEventQueue": "4KEo8b5xgN9FqXQSSR1xbAcLhzwHcspdMoGuzvvZMfz4" - }, - { - "id": "6S1kPEjqgG562td8JjCrFJGZM3pMf3kYMezSCtW88joU", - "baseMint": "E5WhdtYkSQPHcVbwjxGakXE5BWeHAgnh8AbgUTHSpVqt", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "FZYREipjiiMjJh3sKwsaVeZgcJdi1D8nFDo5MJx5DdWP", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2yZVcScu5c2Bopzp58ePCWMtC2WunAHgcVLA6AcgCzL5", - "targetOrders": "9iTwDCGGbvmW1qXXg2UbhK3JJYLeknxH3utTScLqwfmt", - "baseVault": "GRGzAPqQjwEhSN5BkTWKCB4g7MQ8enEQsGfhpK3RMgvH", - "quoteVault": "U44pZZu2pK378t94Ykm1x2xXtz1YLUtbkdeuPMNweYR", - "withdrawQueue": "9ygDeEhUQpsWWTAXUSnbL9Cv5KkGwjt49qckZChCwKfa", - "lpVault": "sNGbGCxELhchDgVTPS7kr34AjAEjvLGtdx3C5fMMsAE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "H1ySr3Egd3wg1K7vEMxCwbDs8pyzbPLCJjvX3qWZwMcH", - "marketAuthority": "G4U7wj45HpowCBuGekM2F5WnZCCxdULc7PUaghub3d49", - "marketBaseVault": "EJf4MYDZ5L75xS7vkLrvqTPV1waucdn7X6kPAetMT4Qg", - "marketQuoteVault": "94bzM1GdF7p6w8xHyjmiSERMeGH1Le5cj2VXAXT5AJ5V", - "marketBids": "AwQduy1tHNXX4WbP4csYVkTEZjV66pZEpQ9Svp7Zr7Fv", - "marketAsks": "GW19HX1LDGtGARzJ8jmxRWsNXNKxrzXsvvyRs7XsS6Q1", - "marketEventQueue": "4QpkVSJXMw828JwbTVG6X6oP63HyQQVV27RZaGZVBPJJ" - }, - { - "id": "6sE9wA7BtPs6n13rPBr4mnhvpch6X9wVaJMsWtWUq6HX", - "baseMint": "MMAx26JtJgSWv6yH48nEHCGZcVvRbf9Lt9ALa7jSipe", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "87CvUzsDABULGumtU4LjR4b1trSi5kvt9iDH5SYbHywB", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HTESdcVf2yemafFJt6csVovRwBPxprUeeSdGkbuN7wFa", - "targetOrders": "32yhABCaBv8xTJ6TD33VrFj8ytETFZ4T2EkG98VrmaVH", - "baseVault": "78BCsjDg4it1dooXTnxSu6vu8fkemEfFPu7dHRqbXzKp", - "quoteVault": "CLdkDGQKpKGMsfhdKJFJmHbm1esUfJdgeuZMeSHh2LWn", - "withdrawQueue": "4GmynJv1gxCR7K4b7C7brJDdhY5zXV3ycf3Ke7ETLK6j", - "lpVault": "13FLEkpcpa3UigVg35mX25pC1DMDNkX2n3Arr3cVboJs", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CbWz5gn5gUyUhjjYpCNZq78dA7zjx6q3eCnQfURcmCUD", - "marketAuthority": "4uDaNCcFFfkWVbTbGFpk9yFMGTPSpcRu3V5o12LWHoJU", - "marketBaseVault": "5uPNd8KtfHZ82d4Xy8mU6a1gRR5yDYGTcrYTeqsLuqS4", - "marketQuoteVault": "CRZQWniW3ZetGN861BpQfsF59yYw3stwjcucNV7ZowBb", - "marketBids": "Hfg86mAWQjyzXADVsC5jaSfBadojFVdQ5yptytLzmogc", - "marketAsks": "9K8SzuPubzqqGPRLUU1ANW1PMWH8ksm85ha7ReEby66F", - "marketEventQueue": "J1oNvYLUvG61YNgat7ottJeqtTUkYKHtcZ7KXBGLESrV" - }, - { - "id": "6sErpEbj39nuif4qjywR1xV38kpitpV5zmoghYVjacUp", - "baseMint": "GV3MjuGin8aTG6Rhc1vR1QFYp8gq5vW39jnNPLrbzmPi", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "F7cUrKzymQ5UgboFVhckrKPgQodf6FzMCqqYsPDLtkfJ", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CLFT9sQhB1vRgDUrEtEtmy5jYDg75yXbXujU3jNQVPS6", - "targetOrders": "8wzj9i6Tn3s1nhhvkW7vh5U96gfAwCoAkNJ3psf4KcMR", - "baseVault": "8Vhth1AjU2JAkFSSQqgQhrfCsM6w7pSCEjXHM6AXpQki", - "quoteVault": "3oEGxymKECsyWWVM2y9PcM6hHq7Rgjv9mn1ydT2XZt4B", - "withdrawQueue": "AmpBq1yDCGb4fxVXvCKVFcwyuZ18ick88caEB65ehc51", - "lpVault": "XiVL6sJybpB8Xp226tPmBvPopxraaHen7PFDybyov2P", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8NXzq2GgXJBfXswhG46tQWTjt6NpiTsBseKs46yuTrVr", - "marketAuthority": "AskmAgCgcZzVPuQHx6fKJ1DZ75YRbHmz9e4uEtPKF1CM", - "marketBaseVault": "8DCtmLHH55zQqTwK4sdGRkQrtxpMKfZGVQfhU2F3sdaD", - "marketQuoteVault": "GcnVLSUPW8Deycu5EWBwXr8eftftXssHFSoUb2ym4ts", - "marketBids": "2zaUMUiNiq93UK5fMoCJGKzkSLm541ABHu6DdqwiEctS", - "marketAsks": "2Eps6ARTdiqabzkAJ8po6vY5iiHNQDK5C4LDdUDV694i", - "marketEventQueue": "9ut9QYy4U5Qmih6QqwQBy11wy4gmaZymNN1tstB6o23r" - }, - { - "id": "6SHisoobDZbDpi5ntFhu5v7RCa2HH3AD2bjBrhHqcweK", - "baseMint": "jbyi8caTyxtzw6vPRpZCwRv9k1rZNfxTK9yRDKFgj7P", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6VbGxWCRmNe27Gj283KhCwT9t2ZWYhLvPoHGHWB6QTAf", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GxV7MD3yX5k2axAbaWFmzSjGDhnWjKowmnCCnQ79RKYV", - "targetOrders": "5XxnEK1qq3b2mk4rRoBhaKgu5Q8iYNq4Jxw5EyoaRrzw", - "baseVault": "DUQYz8wtepG7MCstwURo2JspH6mk4eScbhcv54nActFU", - "quoteVault": "GhynCGGB3nbUSpwaGGadXTNF3DRMVmj74zAEaamWRtD7", - "withdrawQueue": "GTcVpPW67CJK689UzG8m2maaxbWpK2UMZN9HBUx181vA", - "lpVault": "B5ySEkeSoKfkHcaViP873NgGPgWYUBme6c8Tiyuk6xPF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CTU6vBQYfJ8BPvQ4HZNU8hGsEFe2EChQF6MZ6dxPqSrD", - "marketAuthority": "FmQyWrDYVk2BzNsfN3y65GnnPuKay8gQQD94WUt8moHh", - "marketBaseVault": "GLD3bQMJqD9ccdQkwKUBVA3GeLSopaALGdnjaqUzedt", - "marketQuoteVault": "GRAW1bpVN3UPdPUFC9bQnSzKC8HRynu6aGTMg3hziTHT", - "marketBids": "7NvjqGTgVg3DPr7zmzNE2YnyusTaE1iHL14VFwdttLqP", - "marketAsks": "5FikAZo7EuKLj51JmyVx957JpFWqCR2Q31XaCeCrRqru", - "marketEventQueue": "EvfJVC9xRENZyvo2nsMpXY6CcBvMiHwPrxgdm2H6xMDB" - }, - { - "id": "6sKXLBCZuvgbpM77y2J8YsoCZsqRqjWDgAudEYvgzf1c", - "baseMint": "xxxxa1sKNGwFtw2kFn8XauW9xq8hBZ5kVtcSesTT9fW", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Ho32pqKpzZ9QAyrQkN9R7Q2CkLJZLZ8wQcarhNJEPEv6", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CSY2AnJP9YnQLfAPm2D5M8aFFApv9QLjSMs6sUiCRDY9", - "targetOrders": "HdRVqBeBBDa36i47XpS9WKyu7p6RN1YY1R4YPTnCAG6r", - "baseVault": "HpJ286uHrS8w7NvpDRcXY1BqHNUBdz4FuY3FRVYsRynn", - "quoteVault": "CFBmpJQBxeR9sbaB9JaLWN71UBb3ZJTdq72gQFhot4dm", - "withdrawQueue": "8JtfMTyaknxXPkVWCtDskMDtt5VjXosNjUc4wWCZKFQN", - "lpVault": "Dx76aktaJe27nNb2Sh8wMPFBPmpRW2gJhUeHpSuMwP6k", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HSfEpP3ciPBC5bBdtjBDa8BxsUW32zUzRGLPpPuDyVY4", - "marketAuthority": "FWAt84i3PrDXyJCqMbQ7qXh46RAZ3XgWwwBJvzo9mUbJ", - "marketBaseVault": "4BpAAvNNryVWEMcqmMAEhz4SXZ6rPb14yJ2U5x1Aa4EP", - "marketQuoteVault": "Jh5ABENtsHEaoz6id4AwCSiaZ6pWMBs9ZYVmTEAKV9e", - "marketBids": "7VRGwwruN3W8VggqgYZ1DYDztjZeQUfruHhQcMriykLY", - "marketAsks": "FeJ27gM7DNbweKaJuojXR1cjbAJd7DnjGj2UG9G6PboZ", - "marketEventQueue": "4Zqv9Ecegjz3r51UY2RnzJGgcwHYaMDj4iqyWGWLRs55" - }, - { - "id": "6SxKw3yTewSZma81fr3p3HFzCnZ9uTM9mzvqZHBE3PAF", - "baseMint": "938xXsPKhBAXDLUfWNYuZdsnj57oGF6fCz8P6yLom19f", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "D78yAyJ22btV7kxjR4YbHBqNhKJPF8ifQW6VMQ6LjRcW", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GfqUyduDHsF2v3SuKq1qsRjW7gSzJWJmkGXTSQPfdqCA", - "targetOrders": "4rQxp1aFGX7RuyjoVhU48fkqQeSo4uWNNp9UWVYDUzrK", - "baseVault": "2HSynY3A63ZVVzguq7JgmQ4hEaoqMzpdKuXY9wJxB8x7", - "quoteVault": "HdSVuzTCrhtmhuANHQQCjTpYehvg6Y5t7oz5VNpDY1o4", - "withdrawQueue": "BJ9yV8io9JXdy4K5VA1UL9ymYX7PNF6EAk9PU8WqTNTH", - "lpVault": "CMDWjhPSDgjpA2kwEAb7QNQeS96cExChyubxvG1ZebzW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2Vjv9sdvuSzFzxJ7mBPRibRUXKBPUnhuqX5Gr6GGY4nv", - "marketAuthority": "4EjVoFqirEJ4ZFcerCUat45yyRQrhcNvKusqknkpMSr1", - "marketBaseVault": "FrV27Ut5DANGEydbV7FKRVd1xvmvXEQWFphCadXasyTf", - "marketQuoteVault": "DrQgytBqxQxNeme2pFpZuGxNJm9jcjETt4SGXxY88NRm", - "marketBids": "Fva6ma94itzPyCpCAYPmgRjyu77Rxqw3Z9CyzVjwKAmR", - "marketAsks": "EkxELMZNYx39tiKt1CYwQDctP8dyK1PCzxmREW7CwGpa", - "marketEventQueue": "3jSefWY4UHqhtpvyRjq86cWm7uotdtCzrUZxo29s7ytD" - }, - { - "id": "6TakNum8KdGe8HkU6fhuiD3ZcDwU7dmu76KwLWeKKjY8", - "baseMint": "H5gczCNbrtso6BqGKihF97RaWaxpUEZnFuFUKK4YX3s2", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9BqdhozrnLC2zRgk6MMazodd7K2UKqeyFFhAyVpFuLmQ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5r1BkP3VKxYwpzHPmcKL3MpX2oYRS5JSSJR4kUftpQXq", - "targetOrders": "4gRpEVakB2mSvRvHpAmr1esPGS5sfvow82F4BUn9snTd", - "baseVault": "DuZvjkpLWdn1yFu4dug7VLN19EqwviYXycYNxtynAGbd", - "quoteVault": "8zPnBdeWerSwgRQPEEZDPiThsxAk1PMU91tPTHDH9a7w", - "withdrawQueue": "CACPCmBHycmCmvdYJrcsBmHUqcfLt8APXC4gnJRQnP32", - "lpVault": "3hVTnDH9ghbZERAWvihmuPBW8QsfShy99cfDGkb5RoZv", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "41ZnP6U4catotV7rFuv7JR9n53jcCGrBTBkowoBaQx5q", - "marketAuthority": "GMFmRt4562KsNuSQ9FHktizU3GTw6ujRXDmDVmDycjGQ", - "marketBaseVault": "4vgZsoA1SLUeaKCf9hP4YiM6rPjAD891xvzeyBsk84Kh", - "marketQuoteVault": "EVaBRoSj4veHaFPnz2EZ5x6umztYndCfhVuLZRcFTpnv", - "marketBids": "EV26T9LJNUDJtz68Ggc59tY4G7PjkdhK4yN6Zu6AteqJ", - "marketAsks": "5ws7rYmXzT7iexnwktu7pMuLM64X7wm9Gtk8pc3o8oe3", - "marketEventQueue": "EttJ2xsxo2fzxA4WtTFFLT33P41Lrp3q3nfd3X2oet7s" - }, - { - "id": "6tmFJbMk5yVHFcFy7X2K8RwHjKLr6KVFLYXpgpBNeAxB", - "baseMint": "UXPhBoR3qG4UCiGNJfV7MqhHyFqKN68g45GoYvAeL2M", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AyuurXCCF2KdYTURbN3JsDKzZFZSiRqKc8UcZnrgBsGm", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7AP5KPxkc9TYtYvqyXc4RK9GRVutGSne8Pj4ryKJoY4Z", - "targetOrders": "DfEhXNWDjsDNz1bqz6GinQU8RepjFneosamAM2XZ3heT", - "baseVault": "3Dtb2kDA3pJkUrULXmQa8qn1RkmgnEM4eo2nf6Uuq3K3", - "quoteVault": "Gh2YaVC1sjzZQMixnHNXDin6awBAV6p2D5zY8STMu4p4", - "withdrawQueue": "27BsfZSe59K2WXbhGGrvpySTRhd12moxxdLpYm6coFDT", - "lpVault": "2dbkq546TV6C7Dmx5HWdHx7sTf6tpetvryqDRrcsE7kQ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7KQpsp914VYnh62yV6AGfoG9hprfA14SgzEyqr6u9NY1", - "marketAuthority": "5F4DUyyDR2uH7VTADLzi1CFmsVBVqPXk4TM4yHf9WDJi", - "marketBaseVault": "9QGayBN3ycectkhLKiTPcfM9iFVtFpefSGWRr3XUoLwk", - "marketQuoteVault": "EiVf38NCvDFVJQqF5FgX1zeQ26Mzr88iELFugUSMJzu9", - "marketBids": "L6vnHnDLf8EPKXyaNAyhpkCdocvtkpNX8euVFZtqjCQ", - "marketAsks": "68xmWKfE32qDoFL4iKBsjKpDyAfaiW4efdTDSAm33sKj", - "marketEventQueue": "Cta4TEwKCKhSphkMNzXsURVr2V6mozm2SPaV8tCgDPwy" - }, - { - "id": "6u9SkZHxFJjtVCDZnrqLFuZj3teLZotvyQJQ9i25edqv", - "baseMint": "qXu8Tj65H5XR8KHuaKKoyLCWj592KbTG3YWJwsuFrPS", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5PHgMyZpEUCTeXQdb2ARm2KMZNu4rxzLXuhKwXtr8Xzc", - "baseDecimals": 3, - "quoteDecimals": 6, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "J5it9nTT9NiPLNcp1TCTky96kjSMtZEdSdG87jyFF6oG", - "targetOrders": "Dj7itqX7nZMeW6PJD1GczZLQaAvsZhKrUSsov7Fx7WhT", - "baseVault": "8qB1YAAyb8Mf1oiFxoZuGA36PWwUrYDDs2ZdHNEQjgD2", - "quoteVault": "pbu5uGaQV2niefEo7HM2dWuubeACGgac3MvK1V7HSfj", - "withdrawQueue": "6AtdkvZDqVjFJkhB3fBTYnqr2yBrugdsCHEZfWc8C1Bd", - "lpVault": "85BVNLjqwuxKBChcJhxgCNH12FcwGM35QupkP9q5n47f", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8srnqriKDYXQNSiNh3F5qhkEt8USwWcJyeR65TxavoAf", - "marketAuthority": "37F8V1PYKH4aVMESWeqW17RYqCDqAnbW7bCBFPGUaLVb", - "marketBaseVault": "57XCDi2mhjzVyJi6LXcXUsmp4fqAAvKxnuPZbCgDLFzx", - "marketQuoteVault": "C5M9w3YJm3f95Wnx2jwNqBbaKKMLwHm5ipeHKXbJw3fG", - "marketBids": "7EJNhMhtpU1TNLXrTGTougQpa2NM6PHVwTDdmVxtFzjJ", - "marketAsks": "5PRUzCAobQ7TVehDvCXKzJWogLr1gNYx94JHMZFNiUTi", - "marketEventQueue": "AiMecESf17dfuA9mGdreCtrWCkaQjXmmPEgn7Dn2WT41" - }, - { - "id": "6UoY4kBxgYwgSBHW8Us4hKMVhjPr25JHSbPiijjtuvP6", - "baseMint": "BjTUmZjNUUAPKHVdTs8yZsCmecW5isSK4AbuFihXoUwa", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "G7UL9HVWm9h9Q4oJ7tReFQpJxNubgPuNSNqEjV3qCLaw", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9J1wbqE1BHwKKxErQSMpVtCxBEXwrzc5VxmU1S82NTN4", - "targetOrders": "6xBDaGxGLWMKyUE5xQvCSuZBPz6fWJ1PJ9S4imjN3H8F", - "baseVault": "7D4wZWAQVJQJSgaBb6uHpXL3X6wjaoTtPYQEyzZyB3dm", - "quoteVault": "B37nLT6ExBw5r6BRK55BpGpBaZNskKJqVSET4CocQF2p", - "withdrawQueue": "4187bbPrChKeF7ANpyU3DUCn2pXSyQAEtsDbYADL7ndH", - "lpVault": "FfHPpLssxYf8cfKifi7QwZtLaz5W5KGAqkpJgjqV836N", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ALgq4dHm4bypcsg1JRDc6VPurwDtUsdsbpYB8kDxyZ9o", - "marketAuthority": "GzRZDR4RuMMZJBRrD8v6DH8ck5Td9kYjzPeGZZUWddpG", - "marketBaseVault": "4HVgC14YU4nd2MgSgQSeFpm6BLyxTNTVAAJrTkPyZTjL", - "marketQuoteVault": "3oEKwDWuWCDNhzvfozidf9uczH89i8anhVC6i3rkSFFa", - "marketBids": "FvYMDbm9x3kx7K324NeTKCDGnjiuhvNP9GRLnxgyEc49", - "marketAsks": "DtW4ftvpoh2syBADG2H7LNiv2x93XiA473UAzuCP2Z9s", - "marketEventQueue": "CyKYa6U6PsaNzCNZbAxUSBSEZ7frcZNdCN2tGKiWDG6B" - }, - { - "id": "6vFC84Hp38ugXW3Z6WMnjfnwfDJbqj2jmorUgsiimiwQ", - "baseMint": "8x4nE4MNzw3zhpiAB4MBWhXz4iGxNt9Q6Mm3dTdPSRyC", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2JXPBRh1y52LBEjm5ayYQEaLpq299Rpi5mqr4rnbreAD", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HCBLitR2ghp1L7ZQYx5EqhhKrQCFcYWgdVEup5GRTRDq", - "targetOrders": "8aLWgRswRASpLan2Yn6x3i8kNZSsmeSXx2ErV5w6dpCy", - "baseVault": "HZ5toAQARXJ5HNwtFbYYPDuQGiWjRxTupxw5YjcTwq3r", - "quoteVault": "HwERampzmFJRPSSi8Zod2Wc9FPDrF2DvGtKYHtW3npnp", - "withdrawQueue": "64WQGyei198x7Hc8CG4C5WCLQtUmzituWNHVUfAgQ6iP", - "lpVault": "ArVskitbEt1YwbDxZkzqJkz8vpcKXb9YrNdnxECeVJBP", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6GnPcvceJqfsUftn1jAJbM7T1c3nYE5d1FNFLp4CT9QJ", - "marketAuthority": "2EGdyzUVoZhPmYbri7uyPMgZQnxsDjHR6pn9wUGXR77C", - "marketBaseVault": "7MJbNZp4EHh2RcX9tmETyGQffRc44QrGZqvE6zuoDMZX", - "marketQuoteVault": "FXVzL6U3wfCCginboSFNFkQhWLYxLDuan5AWy2WCKZeX", - "marketBids": "DcrVS5RiTcoPTMYdFhsVHUV1JCzixQ2Dm3qjWhmHWgJq", - "marketAsks": "H7qeRBt6vphfrgEotq6qjGC5GiCniueTHvWXJwRjFZeW", - "marketEventQueue": "4FwkZ9ijSCKESPYx9etcu7jtHNybFxBHbeMRPjUvfvjK" - }, - { - "id": "6VthSrRFTqM3stYFNvh5uWZteGyn1DTcBxGpwD6B72d3", - "baseMint": "FncRHFTSigcNzH66WP3Jh7kupaEHtGV48x8RyMm9cU6d", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "99axvx6oZ3iQ9psvUhgsna6CxiMWufaWZgVPx8oQ5oGv", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DKWrPSJf6vKzKceZp5UmY9xobR6bq9FYvDYv314iF4pN", - "targetOrders": "D3Fz1rtAf6HTE5AgBpDg4hF9hLsKpHJDX3n1ZSq9C7BS", - "baseVault": "ApmgeWqj82DKvW5R3FAZPbwTvviNe8yXHPAAFXmHGEER", - "quoteVault": "6X2JE5UgbbYWkTvG1sMchnRXA8ecT6RuPZYzdk2zgXtk", - "withdrawQueue": "A9VcuwPQXfEEYKJdfDUNcAGhZsML4ZC8KRpirZsL8h4S", - "lpVault": "RzFFfrAXXTV3xFnHxvZbCwPuheM4sfvoEfYdn2b56k5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FHCxQF11LZFtrvXxZ6ozTy216mPrSENgDVDnyW6EUBdt", - "marketAuthority": "DEcQJXSBL2i1ckNbD3K23z8Bxa3S7REYYKsbJjGfy3Ke", - "marketBaseVault": "FRqt6a4odpVbxWDkgVj4ykQs1AckuSgtHXnXMhCGQyd9", - "marketQuoteVault": "BQyN8emLHz2jpVkLwwdLzvEREXpE91E5DZQyUKTF7ybc", - "marketBids": "AmFpFAKxvzqh96sXfRTBd2e5rgr2DEAqwFpwYRHVjW3Y", - "marketAsks": "6K3To7ipgMRSX9D8kS9cEuatBDcoXkwzDBnz2XWqkCBP", - "marketEventQueue": "VqcT34hdu5spbc5wuGe6h9vh7wB94sWS3whWbKFvybe" - }, - { - "id": "6W8Qgw2UamdtyyR7FYbcUm5dRGqcXxv6fmgNroH9zym5", - "baseMint": "JTTez7NDqtU4ZqZJmLLXt6K9f75izfTApQqmvMCn4jU", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Ey6y5rM9BKHZ2pgB2VAWiYXP9U6tCK2wFzYjehLxRmu1", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7CjchdJ9CYX7rqpVeiYJeo2sHHm8peoxyMJpqKfUJA5R", - "targetOrders": "J1W5LBWJfMbEb1oDxivw4XnKEUXdqz8kXxAHY7MSexkA", - "baseVault": "5oWZqE6EE4s2XuMVKUkAQDnJjZpoS2Pyaq7UkzvTPQbZ", - "quoteVault": "9bnGp7oZGThpKY3YYturmX49PkvUPVx2bqJ81Pk7KFC1", - "withdrawQueue": "FSyTBZ8E13k34TRSFT9e3QAWbXE7K9mr2ve9K1eMvY3", - "lpVault": "AEsVeUuLmBN6KHAA1qSsAfU6PnF8ND5WuWbJyMWiLUkd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6AbD8tHtqtJhUktZ7J3iMpD1amzvcqTf4HeL31bWb9a", - "marketAuthority": "7F9xmowt6tVt2q4xj7KhWsBXZoUH5MdXvzjJKMgKkdB2", - "marketBaseVault": "3R7NgqoM3X14cE2K4Aav5qhRMWvLy1iREdT9E2zfqyvQ", - "marketQuoteVault": "3aH6un1Yd2N9KowXTa9YETn7p7LdixFxyAmFJmhbHUFt", - "marketBids": "6yoow9sMz4Q9fyuy6motPEYXwr8dBSNQpEGFt5xWgY8P", - "marketAsks": "8pMobNguF9jVtdqRft2hn1xsYbJRfw6ocphSUcr6TMQC", - "marketEventQueue": "7EDsVmvhPXvMXkumVCA78CSA2LP7ebEdHFqCSGTJJYGi" - }, - { - "id": "6WBCp2CDtrgSxKD1pFhpVfRQLrGfED74eGszfoKKQU96", - "baseMint": "43q34gUCKfgBQcJSNq2M4s8uVGuGtfAFQXES1BzW5UBv", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EKwWDBXQ5PYDJU1PXuprR6tNxn6aotC7sMY4Yhsgy8Bc", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "PVt7kftiN2kiwUK6SQLSHpiun56iA5vFx7LAjvChZ9w", - "targetOrders": "2QX94WYJSe2sDJdJoQQGwP9BWHLBphqfVDwE5xDoLMCE", - "baseVault": "FP943nsXiozHHgQRnejdWWHPzf7z4t2faZHog18NTz83", - "quoteVault": "8ED1tiK9RGa9uvm6TA718hcha7ePzxRea2kNcZK7n4kE", - "withdrawQueue": "G47797JB6Uwc4sgdWJpdZvFSMgLRHxSKk4DZLZ7s2sC6", - "lpVault": "FeBvHoV4zhiy7gvdwLJYDpPsCp9VzWHQpCkNs82dJZPb", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GiUdgLYq1rmt3ryrxLvmh4WznD3PtQo3DwxpRMgiYc9a", - "marketAuthority": "HnZyH6Hwn1DhccMow8knZYoEXYAxKuGDQxKpZR5YvjN8", - "marketBaseVault": "xfixKGdMYxDD5yzfaDD56WQwpZXBd4ktb1z77eGmREq", - "marketQuoteVault": "9Me89gTpP9DJ3SLUXwfJRbN5oq3jtjh6zJUHM5dd6tLT", - "marketBids": "Egp4GAK8jor6FqkSV41TNWD7kNswkrPpUbe96CmDTEPf", - "marketAsks": "9bCBrxgKkJmT7annXju7pbYkB4X5NEwJ9RrFCqyhQLtC", - "marketEventQueue": "4Cscinh3jt38AJv5znvraL65eFjdSxsdrEgoXzp6LqBs" - }, - { - "id": "6WJgVYk2Vt5UydugJBSv5M4tqaETbvTtAM7s974zfYUn", - "baseMint": "FronkXnfBgzfhsEV2bjwoJ5VgYhpEVCSN3pzpJkvZGUf", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DQG6A5grtGSZxvnCTjKZKdQoHkKnNYC8VwJ96thrLK5s", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6Lxo2MG5NDHtCQk2MM1FfYwJsVcMLetX3ZCVuq4pq3Ee", - "targetOrders": "14TZznV5LJwbMbjRywWVyssCA5qUq4eePnFDfz2zUxyu", - "baseVault": "egDnVELjbsUomUM7HDodic7wJdnxJmTT4H8QremdQqs", - "quoteVault": "1YzjxQ1UdeSzR6awYHA3b1DJp7HLDXMwNWe2quXxw5s", - "withdrawQueue": "65fn9iNvLuK6qUre3k86eZ9m8rYu96H7m48qkAS1sWxo", - "lpVault": "JEKM17pC8i5ufJnRytB6u3CyzKYcuLUeY8LYaVP4DuiC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "E7T1dXbmYBCyyRJBEy75LYsZwDfXSNthGYMdvrL87esL", - "marketAuthority": "CogQuL5QSpVivfcAFTcXSFJ4PpqpZKhNPphFM9a7EzDT", - "marketBaseVault": "7bfhviMPTfzNGjzhbrQvUcAyPrkr1yFG4sgUPjSDukgu", - "marketQuoteVault": "7r4qF7i9udzyMEZJMEpMCdd5X9yPXAczsseDF1ssxypU", - "marketBids": "5L4Y1opYzyNjiHiEs1ypgDKTYgZUzcvb7qGck8BcGFiW", - "marketAsks": "Givp8i25p7NUFmQA5GU86puC9yoyQD41YHNqgwv1rebj", - "marketEventQueue": "GDvCZ12MJdyjngDSfAmzwCN8uGAKaBwQzUD3NsHvQ4J5" - }, - { - "id": "6wKyWstu6VkvUYHWnADVd81vZhbNaWd9qvhbi5T6Gocd", - "baseMint": "DhfF81uahANRYQ4rn8VZKSGVmLE4k2nzccgfZMazmLJ2", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AHtpZbVTPiX5jz98s1pRedhfUkJn9qKypg58xe7db6FP", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "63Bfr8LETQqcP98zBUitAzhvRxUsNqJtWacZqhfEwpN5", - "targetOrders": "E96sBRhsyEdzdscaLqacCyGu49zqusppGXCgF8cqoZFR", - "baseVault": "2Aio1aC54JVibjHf5DEKM2UaRkGVqefHxvoDsQcJ2ZFm", - "quoteVault": "4s8ytSH1JWBnRyybnHUfV2zY5YK69ySaiW24PY3Y2SnY", - "withdrawQueue": "8E5PPwFXBRLv2VMP5fEFYHcUhGgdM4yYSh4M8Zh98GSA", - "lpVault": "3QuDbsVfxEBF1Ptw6y29wgA5E1Edaj1UjREaywV4VBF4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ZCWzFvZNqcADEgCSdarLhyyvVYq8ATxiL4Yxy6aSbRg", - "marketAuthority": "7CPUHcG1cKocn66NrwHkEe34mDdDJpsenWcVUEZZvtAd", - "marketBaseVault": "5poVMRvJnPxW6YoYPWJoMvERm3oteunWTFoTMn283r2M", - "marketQuoteVault": "4sL3rkgqesFmtXC3VgsrZaamQ7QRex9NfDpLYUtdcjxs", - "marketBids": "8jyeipJBU1uZz5qkbKKts6xtXUW3AZZanqth76wmMuYi", - "marketAsks": "8vqyM4AV5EzYuM5niASdW9F7z75ukM6BYeA5DPRcuS2q", - "marketEventQueue": "Ap3hY7ZBoPaqHxGbMCU3Ny9P62WKxxHVcUttWtgXr2UJ" - }, - { - "id": "6WNUPh8qJj6VtwDnauZZgGLU82cBZ6RyPzXoAcc37d7d", - "baseMint": "6uZ7MRGGf3FJhzk9TUk3QRMR2fz83WY9BEVBukRvMRVX", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GAcydyaJzkxG5NgibQRJsQQnRo3XEoh7KADQe6gjQC46", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "51Ac445cnLasdTVvFvJg6VP2tCjB8wcpxxrNAXpxZpu3", - "targetOrders": "FoBg8Qhj9StHsFHWd5z8eyNJXWsx9qtM4LVTckWm2sSm", - "baseVault": "43CEEnj1nis1KPnZeBfeQSPTYBP61FM5K6Qt2p2GRMMX", - "quoteVault": "EgVcTBQrcoRQNUxdMRyw9JFhhX35sR3RoGKnhanJKked", - "withdrawQueue": "DicG2c426BbeMtKR6idaZ8CdGjLXp3XMZGaDkesSCTXx", - "lpVault": "4j8H4kwj723WLX2pbNiM1Z9Rv1t3oPgvJ1ce5EKq19z3", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3J7f96tjdfkhDFDsGzYZxrwiSXixFuC82Dmj8gVqkCra", - "marketAuthority": "4H8YeuMCjJSNZC4h5Jff3uPriYL6cknF1zAG2LWk5Vy2", - "marketBaseVault": "DkrqWqxNUVD5gx9ZeN77r1hnuBB4SU5rK5rRkqzGoj8B", - "marketQuoteVault": "E8KZGaioqjSn26pQVxceXp5Ji1s4xzrssNiKuypwC2U7", - "marketBids": "3sBaQqeEdDmUMSfVL7Gtwx6qmRNkMfUA7Hy5k9U27bYV", - "marketAsks": "6aSxYmuisT5A3iisjQ88mYwyGKkuQL1q2Lnm5HAGvk4W", - "marketEventQueue": "HBxmuZzaHN8Grese2k7eXUatmDVhFFtzZQeeb4dgGWdx" - }, - { - "id": "6X3iArEtkutKWgtUrRndHmu3YHxfqxUMjCzXHZb9ev2h", - "baseMint": "GtHxqAqbaZB8eo8R8pGXUhWxs6X8WQWMWTUWKTgSFbHo", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5dA788n91CjqsogbmSqet4YxogzjJ8Rj6tSbAS9wEgyE", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3toUea7k9dRQz8aBmRen5FN6BMc7jvKAfb4LhTkFChTS", - "targetOrders": "HyG96m42saS4HEoJ972jnjAapQVSVGa4ZdFmGjoiD7ky", - "baseVault": "3JorJ6nxAuQGaqnXq3vC96STZ15weWNrU4pmYoeZ3KPN", - "quoteVault": "CZLM58ivtab8puXykV33CcdsvddsratET5EV5HeuTM7U", - "withdrawQueue": "BbpyY25PPcSrfoxcaDV46p1i53jiMxmn3LPZkwEp5aZR", - "lpVault": "C35XSX3xgeengu7ojXj8CSeXDL56gAtC9pUDZk7oYgN8", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "J8ygKQH6zJmv2wT2WW3Xf7g47F5jRU6mGxHfHkaguyWG", - "marketAuthority": "Cx6QKBHL3r6G1MKpe8RZ4Ssr2BuxC6dGtPVUBqVJg88s", - "marketBaseVault": "FEo7bWzwtvfvxoJjy94sMfjWBGf9jrXXmmTJdve6iMdf", - "marketQuoteVault": "2tsgCSTKU41TzDugxNHjBbu5t56g32DfT4NdCz8VGpnd", - "marketBids": "DcaqVn77KjFXPUydG4VdktZF8btzjcjN1NVCzChVp2W7", - "marketAsks": "Fiwp7J9BdSSRP1Gtv6Gxg4fTtmtDZquKpJ9QC7d4vMk6", - "marketEventQueue": "Fd29dLpMaQCW1CjQT62YNfNSsJ5wBobj1Zyo8ekk4rCf" - }, - { - "id": "6X9cunHn7brK6DMMB9bTpQ1RsALLt4cFkaNca8iyHSW8", - "baseMint": "MonYu4GQb1dpoMs4DG1FpJt5F9nXtUy6JRyvANZFxZu", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "73uhLKoBsZRq1v6VLSTQ66wffUBHAxcr8KkoJzdqmgZo", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EA2uPNAZQouk7wcV9L4ceaZUTFrtg2XYkPoo4WLafGiX", - "targetOrders": "Czu6hHTGS8DtbLGWvZdSEgKCz1zC1M63xvKnt2ce8Ba4", - "baseVault": "9sKCCP2C6kzMbBkwriZvBL9T7P7gqpDUmZUrG6VLkBfT", - "quoteVault": "Edw2W7wJgWtwAjZVLk7T9XnRM2R8NZM19aeB3BrdvDGm", - "withdrawQueue": "8msmbyPU5utktEpNBtftnsvWf7zm3ksKK3fgKMPuiVYG", - "lpVault": "H8kuBR8CQRiSgVWjBb5MHtq2qGkE2cnDEWA3NwmeoTzu", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "P3jB9sW2e7aCpkugvibvEuDaKbBkmRvQR6NUTRafNgU", - "marketAuthority": "4oB4hNkafCpupLnihjaBRwAhZyjbYotRAwdNUJvQh3UU", - "marketBaseVault": "53vA5exbAfLRZKjj4uxDeeFyczeD76F7qnXfER31GFsh", - "marketQuoteVault": "DM9VfzeRWXqMuExVWf2WMtV8m8HnWK4oWGzh8DGToCCu", - "marketBids": "5nvdS4s5u1XUiLof8fWHvnLAoqcEo1rzKnrCzZBQNWXb", - "marketAsks": "2a6TEVhijFtmHbDnHz2V7oS65x3U933aHAouipdfiR8B", - "marketEventQueue": "6FoPLB3eTUypvc9NBFvonCsNJXURYkaNrwKAW32WWNXH" - }, - { - "id": "6XxcWJjipHmrBSEbRHbQDpBYum787xiNjzMsQoCqWtJY", - "baseMint": "HNm1VgnyhaMZZF71RjNFNiYLN76zyZTDcBZPjYveWFXX", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BYttg4BPMgLUpuT38aanaoc8k6Sw4mb6bWGMZE8mfHQ2", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BXZy9vSvENT9ty86CPzGrU3hwRBDDqymffaNTjcA38yv", - "targetOrders": "FJoUaPCTW4Z8JtKgMjNofE3AM1KJGh1DXH5Ev69nALzn", - "baseVault": "3zubXb1iVb4dYFEp6GxREoSDECVNSMXdkZ1cDZX97rPk", - "quoteVault": "grVZE53W2UKAACjbwnCA17mWjeHfg1d5hVsuyXkQhEQ", - "withdrawQueue": "FsK66E6ycbh5mjxSCVHEPZ8w1ovje8qrcGJUxvxTrLtg", - "lpVault": "GZR1ue8FYh9aMnKR2zRHAWqvdmEV73hrzVt9JbXYFWyZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BXDkXmNj6uS5YDDF56Ts7XxzzSP9MJSiuzvRCkan8YbC", - "marketAuthority": "FyG48H5Vi8SXGwBzxg78S9RWDovsBh64mJVZXRLY45w4", - "marketBaseVault": "EvXauLkHM2wsZ84Hz8Ar4iL9UbTZpj5QEuwJGZwavGHP", - "marketQuoteVault": "5Za8ocobS2zRBzUNgHYKXHAkCC2gv8K84AqGJYFepiTs", - "marketBids": "2wwQJc7okhidLba5VScTPzsoZD39nAfyVWLyYQ4KFk4o", - "marketAsks": "DqVp17WSS4kzEpZxkSSYjKhDmbGm9ZXrdNwcNTyAQtPg", - "marketEventQueue": "EVwbTXTvMib54RGGc3gDQHNYbj3CCVwh9wRXaT7Gojtu" - }, - { - "id": "6ymQFPN5UP6KibEpbphNdyNNhTqcuRgu4vc5tFqbp7GH", - "baseMint": "8JnNWJ46yfdq8sKgT1Lk4G7VWkAA8Rhh7LhqgJ6WY41G", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "7pgFoMuhVCZHJd6QabTs7sCkfnCzW1sKacRRCDutrmUB", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DpV1r19GCZfKdWhyos2TaeYe4tJ1YCpZZYzCYTG18y4T", - "targetOrders": "DGvtAvZNffeXEEwoyppH58rdk7ForXKE1ubeSsGu81oZ", - "baseVault": "Dam3pEnpDZc7nWAkXi9F3tedbFmZsBiftCuQjopCmhBt", - "quoteVault": "7LW6vsLtFiVYAxqgw9JKCGDdPbW7hFbFbokW4dP1qPkV", - "withdrawQueue": "AA2q12YdFZMKZ8J3neLr4KR1Gv2Q5iSaaRffQTAmmC3J", - "lpVault": "3rToNKNsyFfbUeLLnEwi3WVrNEnrnHfCw3mTDmuF7Pqv", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "J8fNkaWQo7to1qHFcKVjDgg4rYvzGpEkUEteJYhcgLzg", - "marketAuthority": "ChcKJq5hcizQX7h9PfKa6otA4JCaCNRhBS4GVZafaf7a", - "marketBaseVault": "4XroFmtTE9BC2YhAycKcDmo2HeXdX7FhSXCuVjA2epBS", - "marketQuoteVault": "DJe4y1sD5iGi7gZxVCUGiv8rUYBRzg3SuowAAaQEJxUA", - "marketBids": "4ECgHpeoTRsrNcTcx7B9HTGKbGEqV3TRhKU8gukFTSwe", - "marketAsks": "Ag4CHwNZ9BZyQNPa7eKAcNqdMBF6G3VmztixsyXWuN3a", - "marketEventQueue": "GtpXpRiUq5YgwcNo3di72ocYGCgKXydYUJz13f91gf4W" - }, - { - "id": "6YVuW7vjCdh8UeY5VPEgqB6ZtJbHc9hwMScAkVfcvKdn", - "baseMint": "RoLLn5qBN4juQ1D2KFpJyAcC7Deo3cYotXi4qDooHLU", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "3gLg4We1uiXBCcrCQFav3pGLMMUg8m1863cauEc2wogu", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EhK1PYwjXVtatExVbfyCukKAj6H9sZzKeBrqmdaHQiVc", - "targetOrders": "EhchDqDVxusf5jcNQD2gGQx9wE21FnRQqafy3zEK59sP", - "baseVault": "DMwYrzj3q6sv9m5F6bPLCgCwGSFBBeGPsA3FKZCRV27L", - "quoteVault": "AtNfX6f8qCCBVxYrccLbcwHmzkqUU5mCFbN7maUB4hQU", - "withdrawQueue": "7RAcwsnnP4VRHtGWvcGjcJLriegTMhoG3DxFNvYXgczv", - "lpVault": "DVR8Z32qf22ZWPg6EprpN52Hi6m3f7ZqtDX6cQFUUnXa", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FWiBHGGYhbJ6AQ16agSPo3bHBdJ4Hej1jRs1uMwywqaT", - "marketAuthority": "DfYT9ZG9Jx1NRsvwKS36HuuSBKYHjVwN4R1TUMh5gzsq", - "marketBaseVault": "GAsvGZ5y1t5ZJuE6q7TR6Np899gaY17AEhKttRvaPM3U", - "marketQuoteVault": "BXxVSUhq2NY9hSDh7oX3bJG2T7yynPdCVzoJ9R19ScXZ", - "marketBids": "ANuxZ5xZ4SkhtggHkhP9k2w4zmMMrdcsocnnhk82UCJ4", - "marketAsks": "Hz3kohqDUfmTaaEKKYewZYJoZxUoZ4b7xPYpK1qDbgdt", - "marketEventQueue": "C932XnKx3C2FtRXB7comsLHteKBh8CzRCJRR6ek3L7Q6" - }, - { - "id": "6ZKQvULigNpctYtxPiLhuQrHk4s6AGqBinmUNnBoYozm", - "baseMint": "6YeTi7npbcyMZRqjVwY7zxW53iE39rMAzLErn3mTftAc", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FgMX4NRxyAx5BerJcex5PYTMkfETu8FN5b8qCCyjHiRu", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HqzQKfuPwYv2Tu89DgpaMsjzUpGJdXUNRipcboodWgDq", - "targetOrders": "BFv7vsQ1pJeRYiVpRePZcX7N7eopbZ3E4JAxkzywMNRb", - "baseVault": "8A3moF9rUHDHxT4XXkjKjshVLuwuTLojJB9Et8FRk1Wj", - "quoteVault": "GByKNYVq36Nc9AA71rTw6qsJ1rexshi6CUGTY4vFC9gq", - "withdrawQueue": "5XcBwtyciyMnz6EF5DjWHGdNz8VNR7dqJarj1VCEZXVx", - "lpVault": "6QNZv9rkrTpLRDkYSX68CGe66UiUPKzQFM8dsLKu3d5i", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7AMWPvxWHTbb3twYEwhA3fZMyV4WMJyGV8wWUp96FPHS", - "marketAuthority": "Ef9HYnbikrs69JScLkq8UJecTjiNks5vC8JqXriYfNrb", - "marketBaseVault": "41NzFHU4iGWq3fweCFW5z1WkaNzexDTVPzPvSEA6BmW3", - "marketQuoteVault": "Eyr6akqNjhLzV39c4fAx7MAYuFGdLEgGaSmYE47hqfS", - "marketBids": "2GR53ogeZPxRhsoiWeRunLnLz3JQ7opMxh82fQLmHADX", - "marketAsks": "AQ1GhqL6Ko4cEG9Cw262x6uA5kDHsTT3x9g5LQkbkaNP", - "marketEventQueue": "5Kq3EbCAzHcfeZuDFpjpoA59hfCFBMeL2NZtrwGZgKe9" - }, - { - "id": "71gtsG46MK6fdjhWEmPQwRVLYi6EmoKfARBVSVH83ZRA", - "baseMint": "Czt7Fc4dz6BpLh2vKiSYyotNK2uPPDhvbWrrLeD9QxhV", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "484Sp6kJTpBM57p2VuAfCZrRFXFBjpQnZcHCR7jaP98f", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5K3bw47hgQtiRjU1KYD8XfVWNESKF43ak3bkMjWKcy36", - "targetOrders": "9w3M6mvXkoUFnfg2rdZfYEmMuCjYr3DHCA4kjMoc1i18", - "baseVault": "DDujXG7WmwVfvsgVZc7pCpf4euAKUHrnPSuZFN5pwBCW", - "quoteVault": "CKiKequ7aWUckRn7mUkAb27Cvj8qu4tVpJu18vcpArkk", - "withdrawQueue": "EnmyBdLbVP9FGHBz55mdQ5DtNXF2PrkBd8kA56pH4WGe", - "lpVault": "9wsjPViTQ39uz1kfmg8ffPiGW5RoLhkW81PBKGPUNqgd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9ZyhPpHwfFrXb6rqzng2hs2g3FnxpQDvKFfhNyM6Mj93", - "marketAuthority": "CVH2ux9Ah467jaKHHwTojkzE6vbEEiryABd5C5SHP9qH", - "marketBaseVault": "2nNQDWUotPMSAqUZyt1Sv1Ho2fp6cyr4JDb3eobm2FF9", - "marketQuoteVault": "4Bao4Pk1smWjhSLitCHYiAnEuZaTTD3LHJ99VhGeasRH", - "marketBids": "6aFUjMkrbKW8JtFg11ht4cDKXiZvUnsDjjT4kybAPKmC", - "marketAsks": "2iWmJA37PZHPUuGpJAJwmkbLCqNrTy3WnTD9kFUmXeVw", - "marketEventQueue": "FiYiqfdC2BE29AravDRRKD8qLx7Uf1iEcFfwUB21LidP" - }, - { - "id": "71o9NxSi4oNFpENZVUgP7xC5CNPTovcnCo78tBosP9wf", - "baseMint": "8upjSpvjcdpuzhfR1zriwg5NXkwDruejqNE9WNbPRtyA", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6pCgx6bGe7JU6F55JqDvCbfMeya6MCtCRJDbqf3F2Bu7", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "66ZXtCdB4VjX5K1UvF9eJj4Hw1BJvvgukXVjcjvXGH2x", - "targetOrders": "GhbeYuJSh7ygUKwAe6zRDJ1C2t3cTh8zx45zD24AD9GR", - "baseVault": "4cT9KHfR74qhLVMZ4de4BpPdDvFjNnVSwwqptSPmQLN8", - "quoteVault": "DY9L12V7fRhvwz4qwBdZzvidfuzbfgu665taGrVkhBSE", - "withdrawQueue": "A2tpZfMkTvbjGFRQf6Ck3GX5WcMVNHYFYmqo3xgA2uo1", - "lpVault": "Awvv8R1ZVneXWsmaPko2sHmH2WV6QGARZ452gLjXpXQZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4fmgKQNHJg4KcSgvUB8KzVFxKsSjjqQiyRUaz4iQmXco", - "marketAuthority": "FuPaM6gy6vYFy2GpZbvFMeYVMpAooLfvCi336GdZqohr", - "marketBaseVault": "4tiG1vYxQqhDG958bHn1Rw9Ktw2kKwXQyb8Qub3496Rn", - "marketQuoteVault": "FSwUCrrXupF7a7tEgn3sxEdNhEMycg51ny4bHMk5pmnX", - "marketBids": "FVYFkjxWH7bhwdJLpdbzYwxvD5YoG3D972z5CTK4LJP5", - "marketAsks": "DcwnN7Bg3j43Uv2yVQRDepv47JVioSqQZeGewzpuwciE", - "marketEventQueue": "BUqYvquvrtmzcYdMMWWV6SegwQ9ZQmimjiGuH4Kb2Ghs" - }, - { - "id": "72bNWptJcHHaebpzPLMZPJBEavM92o5hxM4Luv4UBtSn", - "baseMint": "J8n8QPsUgtdjbCcnwBiBdrafqAznieZYNFUTmBYWv1ig", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FfyQroS49LL4Q7zqj9ZbrPDnb4mqSW3NPdPFVkTbEcmE", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CZTYYwWHNRqyGmBi3EpQjWgXwpMWdzmqbrLm7wC2ndvJ", - "targetOrders": "AeN5YkzDYLGGeFkfdJzmv23nyJVUyh2AbqrgzPRMxLvL", - "baseVault": "GfNRd2Rp3M8DUWoJwUMWhtfBv1e1HvFPPR9Bh2oHUG4w", - "quoteVault": "BZ45xdDLorvtAwPkKLkK4sUwu9sNmAFQRDbr97NGHsVF", - "withdrawQueue": "3xtp2irDrdumPrw19FvVv4ZahHHt6ZUGo3FNoJGkWSXD", - "lpVault": "XT1NSEsWg4A7MpjSBgaN5Y7ov9YJYWW27mBQ4mWgo6Q", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Fxv4Y3UhqsC1ZZm8DvwpqpMGqberiNBVH32YqVLRc6nS", - "marketAuthority": "696zv5oWTgrQoLtYy7mFUrc1Rh6AnYcyG5yoHPvtAfXP", - "marketBaseVault": "3vzhLeXxiJGGkeqd6jhGS5qEBrLysVhNQa7CPsF6D8hQ", - "marketQuoteVault": "75ofm6BLQJpz79iyXjbnPjxwhPdKvPYDf1zK9mnUiWKk", - "marketBids": "57zPtzi9fw9uS5odVax8iuyFiVhD58ECoBCJ7tFrUqj2", - "marketAsks": "GmBXUXbWUS5BSWf9uRSnSsLnLGVXdLnVdm8Wyvr6LpPS", - "marketEventQueue": "EUJeLdGYDTuvzwaJp9kLXvt1rvnC4cxytiRUTh4KiZqT" - }, - { - "id": "72VVN27ycPheVfPrJ75zk5AsEaXyHTkdUKym6aTQKZV6", - "baseMint": "EZF2sPJRe26e8iyXaCrmEefrGVBkqqNGv9UPGG9EnTQz", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "FsbUy3VpxCWxoDZ9dyughzrWqHojPnMu735qRihTmSmz", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2BpgBBDy7qv6mHLAyaSLM53TAWtXBz49VikdNCVaehVU", - "targetOrders": "5L5LP2QFB594eQWmt8eQtQ5xCyKLMxXWMhndxbzKTGHC", - "baseVault": "PrWD6ZTPwD6fybQAsFzRehVTMq6x4KK3tkJbaJQUFZq", - "quoteVault": "6Q14RtEewF3ePH6YCtXphwp2XHkb8gLYs27PWuc7mrRU", - "withdrawQueue": "7DDzmS6k2GhchujAvkB5LsuvoQPcMjA4JRX3KxdLraiS", - "lpVault": "6T4UUgtFNaUjdLi2V5vwqAu7UBsBTTXFyN3UzmsnAfNF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HAHUyWa2UEAKZR3P7fSTaJa6FEwnPmR1sTMmcsPwzs3q", - "marketAuthority": "8ZGBGEhZQYiBTnfxqzggUXD4ub39KYGC9WnP8No1jWjQ", - "marketBaseVault": "75rPPq5QvXwsTvgPdz6Cx7KMcAanwHZJN5FSdY7Lm1L8", - "marketQuoteVault": "6BL2aQ5s3k8LDxgnwdwZYEhh8q1tjLDr9hp1H7FoEN7x", - "marketBids": "BgQj1Exrj8ZLQpRCDgGtP2W1hPmjZ8a4wanFbEMcWS1p", - "marketAsks": "2t3oqcbQmAaFCNu3KUmATmt5WCLJ8CWPmQXEHD1qXrMv", - "marketEventQueue": "FG5KfbWhAcfvYUTFvmWPLr8gi1WkL4SoRSamvMtYg1Mr" - }, - { - "id": "72zS4UiCZnnoXuLprd9AT36VDCtjjaBnbZig55e7agWC", - "baseMint": "53dqN1unCex98QWzLZtk1ssJptEcRwZapTrv8pakcgNB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8cCorEtMLBJuZR4x6ezUWbZG4AaMmb7NAKiinYLvFKPC", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DNjCvHVPyfXdVjrYjJk6eUqT8jekk8XTxFYqiGEk5cXT", - "targetOrders": "9pvBzriJeLYTrFb4VjpgKM6M6seZPp82Yk9qkmcDy86m", - "baseVault": "9kV6wT4Kp1AjGYAVRJz2ymK75ytXFK5LKR4X4jFM5Sxh", - "quoteVault": "GAcWo7KvMqxtnFSULCCKkkhWAGnWZMaj9reW3mZqwY6M", - "withdrawQueue": "Gcu5dDKZ9Kbhmfu6DFrSuj24upzjqgm5ckSaPNB6wG3J", - "lpVault": "CD7C199SHg7i9yjwb57a7mAFm9F8MHgAXpeE2R3tSybs", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GfRgW3GSJgo8DVTjfcbTNyAdyNG92XJVPVeqUKNQoanb", - "marketAuthority": "5D7j8RAiRYhsCZJDJ8nXEkbFZxxvLzKwd1B9oQ74CFVM", - "marketBaseVault": "FwbtyGNLBpYjPoXEsnZfD5q2BNG7gGV3dLJwrr3HGcjN", - "marketQuoteVault": "ACyRiudrDCVakcXvvgYhZKqGPZaSMQqAsHESc6VzRTib", - "marketBids": "A1bunSX7SZUw3FckbrdirC47PdPzG6TyXh5LBZ6JJTQc", - "marketAsks": "BqDUxapRqL2B2vaqsweH2wehrZHipYFpqMbaMWxUd9Jv", - "marketEventQueue": "62DoWpRt8YEKsT1jykYepn6FfSb3DQckhHfgSER7BnVL" - }, - { - "id": "74p1rVmppr6mEYSWivaAC1LrojsCJR5V4DCcCAUBSPPn", - "baseMint": "Ed1934BYVPQQ2KXbzCLxBMtNVZN3SjanTewfR9upbb7L", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6RwZinCAndkzFSDxEXCjXDGjsMLU1K3gEU5psZfJ5UfQ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Dh23b7UhXhSCeT397jq2UafxwTDXPJjQ3TCA3hNnJVrC", - "targetOrders": "GzQbqGX7z3G8Q2XVC9dP5rNvtoSmgttAQ3ADYPf64Xpv", - "baseVault": "3eLkp3t6VqhPiDupbSgZtU73Z6ECPAZZyEBYmvU97NHi", - "quoteVault": "C1ucvgRS6CchG5D3zyn35J9puAKMAa2t1Z8EpDT996sR", - "withdrawQueue": "A2Jm9qN2L4jueJ2Zy75duFQHrbS4vUynKzPxNA7a21a6", - "lpVault": "7nu3rPZnTC3HwQ8Lhso17TsdiVFJoaAy3zDNrcqmNXNQ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7ZvRxA2TXpfn73xWvbeDSxaJUJoDnSDx2orQzEC1xPPd", - "marketAuthority": "EQ1cMony5ezUCguWEjVKwUeBMnmqYZ3MqHEtpnA44YT9", - "marketBaseVault": "7AqrD8XTUSDc52BqrfQxstvMtjEgfGQ69ifJsHC2t1dQ", - "marketQuoteVault": "5qMwLhWVrYqkrzgH36ev1JY1LVvUv2S9AafR2xgxjZb", - "marketBids": "Da4S2npGfcWVJZnnDwzf2Goz4Q9ypmdSAtGyhaiswBfo", - "marketAsks": "6AEVLaY54CkPiWX4LQH2zvBedRoV2N95P6wMf5SkPGVq", - "marketEventQueue": "ESFxnW1VyXpqocpz91QJoqSyj7RQUm2xp8zEjXTXauaP" - }, - { - "id": "75UnQeZPEity7P2kFG1SkBRL5y4CG8R66VEU2aeRzBpY", - "baseMint": "TKMKgSh3aADsmjr4yFWG52tkCQvmDxsQC1he1aBsi65", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3xJFuCY5VX8frQ5iWSvCf1JY4z6eJ9P4k3AbhXB3vQfV", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3JZsPLk1gpF8pQGV7vgXkrbkzCjxRimreWqt4jQDUMvN", - "targetOrders": "6K3Lpd9Th5JneE3TfHVVJ4An4r6Dzqw3bdmfEt2iTM6L", - "baseVault": "8nvGgioS1NAQS6AofR3VW3n5772LWo6WYL4ff3CoLH9i", - "quoteVault": "By1k84W63iKWNdEn6U8gDvEeXxzZq5DDmt8xX8TTMQbx", - "withdrawQueue": "YdYLY57hneiqbJJPALQPcvcdmjAXw7YyUcqATaFrKHh", - "lpVault": "2UuowDVsgYw2wufF9NHvYqJj2bagKAN1Vog5wfMro4P5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GcuEE7dHtufcnivcKmXaFZm7HUy9cVrrKupu2LN8GbtK", - "marketAuthority": "6s5ukb9fEu1C3FBXxy6A9pCR6wLYJxzK1uGB2dXCFAHx", - "marketBaseVault": "43hevmAjLoeQRMPSf5rKgntqQVFBFwRQinVFUVXpAU89", - "marketQuoteVault": "GLxXqNzdLHnEFXWRq4VcKgfgBDXckPQJAy7GaB98QoHJ", - "marketBids": "GAXqZctZKgyfM8G6zcGDdVEoi8DGzVzWDwxMRMJnm5ZH", - "marketAsks": "DpXLcZyMV4XbEsaSBPUkR1Y35mhtGYMhMVmp9PY4uz6N", - "marketEventQueue": "6C8tLR613mxWc3nvPcQV71GBzCFJWrZt5o5Jj9c5c1NQ" - }, - { - "id": "76A3TPQRye36VuRPq17kWxSLJrjBqRAjtdE6aSeFLVtQ", - "baseMint": "HBxHiTHpmnps5ALo2jzZbVmUzPPpZsUT8wN8KtqkBU9h", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HSpBcvmMur8X8qMqrhcbRe1Wq37AK1KJyQSTbVNE8vY4", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FHam3LuKySuDiLGvNvHbxgafwYr2eNNKb7WxL51Y1eb3", - "targetOrders": "5LZVh3Lcp5X2cswAHkbetFmYTYrZJzs5SeGvK2nEYS7D", - "baseVault": "3nUAWayV9CiJyRAupFcVymb8KM43DjhUyppMF7mLj6UN", - "quoteVault": "45NGaVeuZyCsVryHYGPnB387dLvi8SLtsxriMq76G5G9", - "withdrawQueue": "TN9CGqkPwiMxxAj3x4kSyf4k2dz63CkCJ98FHDMWJ6G", - "lpVault": "4dCy7f9sFh4wk7a2U66NGRRw8gufgNFZewGiiQh7kcFc", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5jHrTN9DECRd3XL2CGFKtabay8MC3Jcq52Lx26iVzdc2", - "marketAuthority": "128S6oDHmCnycFWUXWp4A2BXU9doFQzFA1tHfwLjcTmm", - "marketBaseVault": "6taKPZPsnK9hJhGmNSe7WbW9U5DaUuHziMbwh587NmBo", - "marketQuoteVault": "8varYL7RS3rA7V3E73Zqh5f2GdDkKhkMRH7mmdhtfZSc", - "marketBids": "2FAZJhrfUh7usm9kk9byRsMPPPFRACiaXzAsm9fGsKY3", - "marketAsks": "EZG5SHSETq8WppRpXNTXADC85MQp1KDDAQ8vnCvArKnz", - "marketEventQueue": "GrTE9XPq5cdqzKoGYMawqYWM6C8nMsXvsmd1rgDNKsWr" - }, - { - "id": "76MHVVHURUS7uxvF16NRJoqbY5D5d6w6KGeK3yYSF7BA", - "baseMint": "Ac7GiHwC7vZU2y97GRh9rqCqqnKAAgopYrTAtKccHxUk", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "7RVjveatwyvq1WLy9pr1aKTcpLG9ysKMe5R4Qh3JtKiD", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6mt69FSajNr6G27kGUVQ5SHNe55e4rubJTn7DpthQQyL", - "targetOrders": "TQHL5bMCHkhoZpgAtpTMYFrB8tZAUcYqHwBNPbs11yC", - "baseVault": "HRUnzTpGnGjnbukjNcJ9o64tQM2LeBoK75727NqYytCi", - "quoteVault": "3PVyf5m3btrcb93GEddEwFvYyWLv8yTPqAGUB39hhwkR", - "withdrawQueue": "21A6h2LQU9chZNpPJGnZbqyxaXQG7ABV4NDPS2XnCXo2", - "lpVault": "8dTmkPGLubjPxBLr2eaSKFPsQqxp8DesBhmdcD2WPeuW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EXF3mbBWcFsS6bD87GDSGgCjoH8Rhxb9AbcEcJgkJw89", - "marketAuthority": "67xfWfUkuaywmPETfMJRRrEWgw9hEAGJ9L2iZHs3RmqJ", - "marketBaseVault": "BQAS7teqNQpWa7hg92E5aH2gyDv7RNGRhcj4DahvoC6b", - "marketQuoteVault": "8PRWVNqYFr8htMxEYP9D6QaQSwqoeo8JC21kBikm1nJ5", - "marketBids": "2qB5vF9w7TB7xzBqb1VPErChEwQU23RzQJfvQAgYBpDu", - "marketAsks": "6MzVurhPWdSFTW2XV9ck3QBMCz99rL19wjmDZEi4RxfF", - "marketEventQueue": "Hzr4hSGEZYD3kzkHrwvpkZQqWbAYHradJxQmfQ4aEjRX" - }, - { - "id": "79wusuhXqjC7uj2hvbr2cNPFBkumif7sA8Eq2WL2vTE3", - "baseMint": "HWXWUXUNuBd6euKDxsL3FrCZ6P9RwmVmbXHKSd4MgxoA", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "2ofYYwhMHvNaPnA6Y7khHVmy1tTpcnRiSdo4q8zxw9ds", - "baseDecimals": 4, - "quoteDecimals": 9, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "vqxTAMLzacDwnNPXRv1NdWYyytmkeJ8yX2QJpD6JSdo", - "targetOrders": "6JttyPsuuYxnSUX31B9K5eyg7VVZfyHGdPtdAYDiskLq", - "baseVault": "AwD3PcRizqXfmkPD7VN24y3PN2mcEuSyLUorLM84Ecan", - "quoteVault": "8H8KE1rHt6Pz3yoQXdfCgBD8bYNNqseddUNQYNbpDkfi", - "withdrawQueue": "DnPGWRDtmaCdSV2bqcbniqLHn23v79Dm8Afumc8jnt7T", - "lpVault": "2PWpu8TE1FCpkFvTfEqJkaRzgSTa3oWrWguhY2ehP3q9", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5ZrhTXhzeoxDK3j7wTBvoeTvYaMKHmwDGsk1rs6BrqJJ", - "marketAuthority": "DL3b7ttJKdmwNMUL4i9po1Gppmjj1Ji1DKFWNuS9Mmjp", - "marketBaseVault": "6XVCV4uqju1orb5zf7tM1bx16uLjULfxdgeZF4WETbqR", - "marketQuoteVault": "3iHUDr4wK9yeCv7MZHWFNKBo26SfoLH15ZLRWjgUcqKq", - "marketBids": "H5kC6LxYKMQRSYjng2hR6doE5Na8DFPUM3bG6PH4wz4s", - "marketAsks": "CRBV7XRtEGFgzy9AFHf1jL3n4aK18bMmUvqrWu1H3M99", - "marketEventQueue": "ERvwCZBs7FFwGvFKBF9jhFt55yv3jkVh7B1TXdFwKJmH" - }, - { - "id": "79XgJRNv9PfG547XtyVVPiPBykQtVPor1jsmiz6oFX3t", - "baseMint": "CD1p18KHEaYYjsSXeUThAweUvcp6G1PAwxb6zoErSVuM", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "DqsicnctY3VgLoDDUcG12Y3G8fMX4X68wLxm8WhKPuiX", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "H8dWE74j9eiChx9K37C6QMJnniKjTRsTfd6vQVv2vhZj", - "targetOrders": "DeqcLsFNXx2kjLxLDpi44Leuik3bRvf751cc9w3Yq1kU", - "baseVault": "B9Wp3E8DFBKmdn5nXTR6u4pPM11LXMVNXTRDDNEUiY1R", - "quoteVault": "5VbMsiQJS6ujQy9t9Vc57NwqUQ57Au7xGRXdmoXuqSaG", - "withdrawQueue": "AfKrAW5YCejbnCBxc1JBkNoLHbJKpyf4D68T4sMVVryL", - "lpVault": "5RsiZoozqQiyULwkniYFDZDENVaAbwKJS6pugevbiQY6", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6ytDRPyWBo3DNbpARyE5zTYkSWE6b5fYahYFbP1ANfcn", - "marketAuthority": "EZkVaJJTwg4iDMtcVD1wa11iwchDkeVDhUYDkDXYHaBQ", - "marketBaseVault": "FfH1D6VF1AYya5SFSgvdTCWR8bsgwTcgvUPWjdJyoP2S", - "marketQuoteVault": "5DMfNcD96ogdaVdfTgz6kvYiht67c1fRUiu1HxPs6KX2", - "marketBids": "CobKRDUes9tsReYHSUCATQRqo1e478sqzcbV2ucbdoba", - "marketAsks": "FNMTAtDpmfoMwXWnN6SeKtcJyV8neCaPnXWo3b9ERvZo", - "marketEventQueue": "2hhjdsFBxw6rttWFphJRjt3cvtzzskSe7kvDmrkETx9E" - }, - { - "id": "7a6MsbjJVs9iL7CvxeipH5j757ApRg5z19MMGFoemFBE", - "baseMint": "D3eyBjfgJMPHZyYDRtbf1cSxeLiNwKumwHzQK3h3TRRq", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HBKnTMmFADT1gtBLgM8DrKmazmz4gBgMJnwgBvQHvPk4", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "54PnvM8ULTvi1xnNCsMK4MDr6eW9ybKM32f1EUibWY9v", - "targetOrders": "24adp87H5JLJqjYHaBnZunHqNv6WkEsEdMuL9V6LxyoL", - "baseVault": "EM5WxwKBhadEDbRCeEhn8RyyBckmjpkxS1vVtnco4TFR", - "quoteVault": "J9gCwr2PgW4m1SXWptMsQRHEGYwQX9SMD1wSDJuTzmr9", - "withdrawQueue": "8PxNcfHYxPsffbFpmpSsG3BH6PumhDDmgZCWVgCzAkTW", - "lpVault": "4UtNxPJqehL7kQxx2s3oPZpFaRXukf9pDswAf1gegRcF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BPwWF2hsYkVpXbufKFC67PeDc62DC4gZ5yPeGrZDbG5u", - "marketAuthority": "H2zME1x98JVZXuSUPKFKxYC1pK8x3P1XH4D6PqthcdPZ", - "marketBaseVault": "G61Jj2pQDK4WtsZfysajmseHnsr3qzAArcJTgfgGKnbh", - "marketQuoteVault": "486aUF5gDeMDvsUtxZSvfwdcusxSJ5KPLpRjy7a6Lyis", - "marketBids": "D4CTfA5QrujtgDDi6aq5iS6WuCsh5Pq3Y7kRLb6cYyZj", - "marketAsks": "9YYK7e6VHoheShPJC4suWJNG76GYhY3drrtE3v8NWGvr", - "marketEventQueue": "BQrQGgdASKqscmLdQfDjzyqxBHNVHkDXNmcgnC4mT6ZL" - }, - { - "id": "7AGn21CYuXHLbPKzjxAAMaWGfz4Hju3DigFgaLeSQVCF", - "baseMint": "BikKd7FNs7xdKFZjFUida6KD4uKcH4mTm4DN2HoKqL2D", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3xfBHwtRnyRXnuxCh3Q4jVNqUZT4ed5rhhz5BLNL2XK1", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EV8SLdXxgtU42XdHZzg7X76rjQqfSqo8CRvYjvk7pnbi", - "targetOrders": "FXwWqda3CFNQhyw9QDFPXPRSPQJukp257NYYmErV4oD", - "baseVault": "43ApQGjXC8PTJzXdzMDwryWaAfRkC4tRZ6gTk7wjGmcz", - "quoteVault": "BHDV1RtbrkjvoDtwu231BbmgNigCKHJy16tC5p7nvv52", - "withdrawQueue": "A1Rf6Ymtyf8sPJsJdWMGANsRkMKJihgxRZJjFVKeop2A", - "lpVault": "xsxVs3pGXjgMh6knz5uWpKt3cgSeB4wgd28wkkY4NtB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BnV4mL8vNvaHm8bGTJi7MFu6gXmyYP7Eorc2inGpGMuM", - "marketAuthority": "728CgK8r5j1rKu9fbqDVQcnhq4BZszqstGZXRgei99Tn", - "marketBaseVault": "BDGaw1hoiNfHQCnsbDQ22xiz8LCEGKpwkvUVNDz22Hq2", - "marketQuoteVault": "2bS1vcQKLsnVtNvvXyEAtUbLwigJjcym3XmkcAzecmT2", - "marketBids": "37Zf1Y22fx9VpJ7fXvUgnMFgE9rewRv6vAAJU7PwDntE", - "marketAsks": "Duf9a7CzwV2hTxLDAyFrpmNkouV4a1whz9vgZCL1r8CP", - "marketEventQueue": "2SL9RZQxTen66FvY2CVMKcWRZE8SX9ity5bb274NGfir" - }, - { - "id": "7aTLpQNbp6ALe7jmaGr3aFqcQVBLUdDqCnepnhhCXBtc", - "baseMint": "8Ap9nTGPGJ1VYbMCE64f7yUTCptKk717Cns1ZfrqvdjE", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "45HD2xNL4A5eHmTBTKEe8PoZTHwFExCRYM2Q4jCJpXAY", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "G4PYxPRecc4zmDbX6KXWrKsArvdUW8GCmxN3HmWYtwJf", - "targetOrders": "3yzkffGbBz8CyMr6Sa3eH1WgfwmrXvNznnbnTPiT7jWC", - "baseVault": "7ByShUFFrsu6KJnTDc4tBXAgoLyaAbbkjDdSBAxFmLd", - "quoteVault": "7HUvAbsfR8GYg6zkkWofmqpR4mnNpPcwUWoycnUdapvV", - "withdrawQueue": "CBKPHLN933ETWfYKZNwwJX9PfiNz4YTxUBzZuzAcQkWu", - "lpVault": "9nedBH7g2LV4f2WELESkEGHdEM2NZnvmkZ2Xg9tmSH18", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "95f7mc7QwBd45AWgyLEgDkADty99Fm4bTgV4Rnc3nLfc", - "marketAuthority": "4DoQXB8raxjbJFKuaKk3yjsKGnR3pN7DGQXwizc3xmhS", - "marketBaseVault": "26dthBAQN2tkA8d3rNY9C6EcPG54WHKbYqXVhAYYaLQq", - "marketQuoteVault": "EyUbNNpZyW56PC7NXwRJdHTC8XAvDQSQk86MffwJ72h8", - "marketBids": "CoJMQFQm7huG8qGn6LcNAhhw8RtMh5fAdnPy8iryMTYF", - "marketAsks": "DYnrmnamCXAsSKDZQubdJrAdfsApA9fLxXFBqUUu7Yaq", - "marketEventQueue": "HSsL9RZZz8fjA76F1famGnFhdafzEwrpxEXEPM23WWBg" - }, - { - "id": "7bCyP5zXzZdX5sxPzsF8kGjrREpv7BuyVbGxA78U2CcR", - "baseMint": "CP8CaP7GmSVUo9j3L8dwDKVR6i1kvcCUn1ubGGhc2V2M", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "GKrdZWvrvNoe7zGbtMS5NqPFdra6BriHrU1FDvNZ1c2i", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FzDAGj898csfUg8ZpHgXXM66Q1pb6iRBjavn6A7EZ7Yr", - "targetOrders": "9SeJYPNngT1iWR3P33ReeHQiWATm8HdDTbgF7n6f6ACF", - "baseVault": "GWHCnxuj65pZ3cfDsLPqQCZRdMntkFV3Gi2uw7smZSU", - "quoteVault": "Aa7Xk5A9feWCdByfxCQk5ZNR7vyGMUfMiSanEL2v1TgK", - "withdrawQueue": "GFsJ9CXG24BeTjBuX4Ch7nwsX4FJeT588X6iSoo9sNQE", - "lpVault": "8ixYeTyoo7K5qv1QAPXxTDKjDnq1Wu7A6aBR2Etk5sBq", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8uRPVrJxjvdV6NMbgKHoZaU1jGGibHhAEkQscBcEvPrN", - "marketAuthority": "3Pdr7MZarQ3utPtxrY3JAbVWKkcFBUSGko2PcnARbrVB", - "marketBaseVault": "3xxhHuD95k7Nm56M9CBKn5cp95BdSBomqvoEV5V4aRdM", - "marketQuoteVault": "JDw4G4wZguFmYL29pTUjtwhSCKUsADC6emNGrdkiGSzw", - "marketBids": "tRCKciJqw11GGibousUP2DZsajDxQk9vsyGh5kRbrmN", - "marketAsks": "Fev9cJTwCW4TscnumFVY9UxyU2UQnJhBXdUscLkihj6F", - "marketEventQueue": "EpRGekBDaMAonWs8zWLrGxKT9AEg698SX2rvBtBjBbot" - }, - { - "id": "7BNfcuAqMVAw88rhHQG7A1MhHowKdrdbCgot7ap4C8Je", - "baseMint": "Hq9MuLDvUAWqC29JhqP2CUJP9879LfqNBHyRRREEXwtZ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FvAyC9EV4VKLUoZhR5pxdaqJ99DgCXBrdLRpqAnE2baR", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6xnGEn6FgJsR4Vd5VzZoNSdoAr6jUddxQQiWtYnoXY3b", - "targetOrders": "DZ2sk6czRd5XNuUm3Xf98wR6rcDRzETTCHsqimiV4NrY", - "baseVault": "BptzjPBw6PhAZAtxnpnzmPRqUcQt7sZZ2h41oEgAVW6C", - "quoteVault": "4GCobBXNKF82beRV32jusbgjtq2Rj7BpfgBGu6Zpqysa", - "withdrawQueue": "DguwvhuneBZnreezqH1Cj6grYiHXQxsPrLqMV3fRSeT7", - "lpVault": "GpY8oTs1V6Q3BRSgYBsngKTiFAWLNFWLPi8ozMSWiZXL", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8kP4Noxh8xdN8xrJZt5VKr4aotEGGxwpDeDTMfTuej65", - "marketAuthority": "HXvL3RxXPfK6ChMYLpNFnwZMFzZjiTSgnRJ7Zwnj7vu", - "marketBaseVault": "DV5q4NmsV1czXYTvnncqrq1Xui7jNdt5R2LKUDL2ACyA", - "marketQuoteVault": "5NiCzN5VYCjSHDvhhxczk5Rdcb8vCCkZ6AVVo778ZUpB", - "marketBids": "HoyUHvH9ku8dBumepFkunBfnmkLoMKfXsUXc3ST5aRrQ", - "marketAsks": "2fon7HCzXfDCVbX9hYeM6AqKpzLfxCFEdR9yUFBrwCvx", - "marketEventQueue": "3VSsgcxaTMVDibX2wXLcLW4JBHPzvt1LwuV6dMVsx8n9" - }, - { - "id": "7CvN7HQ83ahxDQF32B8z5XBw55Q9j5nmNYhxbfQJMqgM", - "baseMint": "3NcCuwvTMnnf7TU2UEVhp6v2nzbLXQiDgzQySS6m8A7P", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "HpkV4Lw91nttadabiwWSnRmJ1e4guQJYTVmJYP6swcU1", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CLfFts7xiHYxTUq9X1VSrVMjRmCauLuD5Wtbf5WY98Ts", - "targetOrders": "DzQJpyKVCmQqD5ouSPxPeWaxRwLYoMJf7qyj4EaTUw6j", - "baseVault": "BxzauzZeDvZtcr2e51K2YMc3QEtk7fv36BrfvtnLUYFH", - "quoteVault": "CPLt7BHTMGHv1u9SFvRqfcFZu1hdAs4YbCGTQTsCyYzb", - "withdrawQueue": "Ba379uS3QTUkTVs3QrWTHhAU5KXcURzHKAuqG9aBzRBo", - "lpVault": "8KJmxsFasN3Dm6hqtPUU3wGHWUSJVKzz5bFciGmoyaMg", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6qqStjyPfJEuhPqQnjraD4BMLiLqjEFfvEeb4D1ZukrG", - "marketAuthority": "GP6j788W9ezuYxQ34khTbXUjZpvfPeKYLkGGxQcvPpTb", - "marketBaseVault": "4M2LE5DXsxEMpT8PeRntdZetA1833jiprNMxB2CmAj58", - "marketQuoteVault": "AFkVevPvHVTAximhhJC9ixdquF5wwHBK5oqmeq8KHytk", - "marketBids": "J191akxvPDXK3TTn2gq3pQ27gHp5hDMTYY33jSVmqSbo", - "marketAsks": "BMeEJQh7BB8ievVGWNmpEmWZ8S8pWGTZdLKChML1JEiC", - "marketEventQueue": "AovtzUydM1bf4X1yBMTX1C6ERxpJcTLF8tNeKpPVBjXQ" - }, - { - "id": "7E8CVx5ASoxZbuYodPc6E7Vq3s1ay9aZZdjaG1dbCNUZ", - "baseMint": "8tbAqS4dFNEeC6YGWpNnusc3JcxoFLMiiLPyHctgGYFe", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Cg1Yznb99rrVq15ks23sckchmjUoVwYW17qwQ8tUytKG", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "D4WnHgiBD8psNYWP2T8k6t5BuoGpvV6gAHfb8ddscfR7", - "targetOrders": "HgqerafD4mBPCYe2jMUJEGotkQTtxafxnVxMwxLm8YkS", - "baseVault": "DvdCbHGw6NyCZyRMiuwsQDnVcpfAVWnjNBUHWQXPasCE", - "quoteVault": "GUwiCVwjw1YB7DPwJMMYCQEBnv1bAecx1rGZaiUnMEw8", - "withdrawQueue": "BE5U6ooiZocGwiC133QBmhcAYHSTbGjimpyjgZ8Z9dKX", - "lpVault": "DuWJ7N1HEnjV1B35ZrkHntvje4MEJMNkXSppDJqZf9W1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EHCty8rwVcE1T8Ccd6Emrd1oB2yNeMXz6kcgmE1Qa6sG", - "marketAuthority": "AkA2NUQZYh1PAF3Bv36EwJX49oPHqjPmqPbrPyabCXt2", - "marketBaseVault": "9wy7soPbJA7uK5A5nYZqBb4iq4nxdSoMKRfyWFkK4EFX", - "marketQuoteVault": "Ef3Vyg4xM7Toc4iopjum2ANkCsAK7q1k5bFLQiYLKfYr", - "marketBids": "4yb7c81uvoE9s2ccDEvr9x6teQ9sGonoSKhcD8ViTMmF", - "marketAsks": "AnXeKECCZeQXCy19imrQz1c7GLj2YPdtYBc4TD9xWiAr", - "marketEventQueue": "GDHQGVCWqdaq66huaEoKz8hobuGEHKHF5GrZ2Fnny2GU" - }, - { - "id": "7Ei5oGd8yJtrGma5N7zhc2TNVnqxQxwN2i8vZ3QSi555", - "baseMint": "2pLrCRnbYBGbhANbUvkFXDYuuRNZNkesbvc8WSMQ9unX", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "D8xW3wt3h7Sd8GxzuqVz9MaRb47jAizh5Dm5DxpPuXX3", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "827tCfVCqVoqfAfgKBEofcur7pt5Q4MaZQzCxL3fNmZG", - "targetOrders": "F1BKK3Li69dbP4WV2t5hWRuq5bdWZCA9L3RLLr3pm8mk", - "baseVault": "799z9sRrMFYXRSvuJD8twrXhYFT5LKosyxwwT3CKCQi2", - "quoteVault": "7XVXNhuHZvh9Lw5U1hbahNpfxqY4h5wQ7Xmv7ngictSa", - "withdrawQueue": "E9J2RuPyULyf7reaVmWzgGU3vgRkXcJEDcPMXowB6BdG", - "lpVault": "4AGetv4nbMoez7KzZ2fc7yC1F4F5s3ZaCMEmGNzgRc8S", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HePyPkWNhyztZccJSRY48QAXUf21syBRJ8SNqS1To4d3", - "marketAuthority": "Ftd8yjLsPY4UUdpKYAcHjbDVhwa86APF3wobSjfRAo5", - "marketBaseVault": "H7KjYv5V3qqVSzhevE4ETCC5dkQLYuXqouNfFFubjBfw", - "marketQuoteVault": "GipVffXQEywrbQ53ddaY1oFmLp83Dx1g9YQAcfbyyZG2", - "marketBids": "Cr7za8ZtQg9aTQtBFCWYtRvkMCfPryzBwaatcPQUa37V", - "marketAsks": "299vZhxk97HC36oFZeUSkB45SMd4z9Fc8CsEv41E2L7m", - "marketEventQueue": "Fx2BTc9FcTKw4KwABhF4uw3GMTNhZxfdbWKayEfbMoQj" - }, - { - "id": "7F3e8URDCJuJyHi1Yq45HECk4MD2bqtd6M3e3pfPRKVi", - "baseMint": "G9tt98aYSznRk7jWsfuz9FnTdokxS6Brohdo9hSmjTRB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Aox49moN6MugLheGwqMBTLi7aFojfhtiLxtHsaQzJgoh", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "R88qBgetn8y8yuyjaDwLKjrBRDaduVFQfBrLTS5ebck", - "targetOrders": "EJp4gza2bmqPYha6aDcurQj72D1x7zvvaMPPco5griEj", - "baseVault": "FTDBs9iTy63bg1J1Hri5dreaCu7Kjq6qgCtWxK5hKSPP", - "quoteVault": "Gax1fKsLaCdVxuEq6FQjxBfB3KUGfNqTtkgS9vM6DHMB", - "withdrawQueue": "CN4FBRT4GmCeRikSqxXgw1gfnEj2b6orb6MY783XLheJ", - "lpVault": "Gs1QqLhRNCNwFNJkfvfdLP42iErHxqG9Hpma3RR7UU6n", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FjkwTi1nxCa1S2LtgDwCU8QjrbGuiqpJvYWu3SWUHdrV", - "marketAuthority": "4equLsSUScToMkQ79iB4p4vqSMpk94Qq31EyYgnjkVgA", - "marketBaseVault": "6RYTMFBaof4HaMbZUHEBZ1BybBFKFC7YsMnSJ43AwQoW", - "marketQuoteVault": "8tUZUUrQ36nvjy2xqHK5AaXzQ48h15JdkgyQZ4UTAjW6", - "marketBids": "GL1CmwDCJGKTxq1EtMgbP4bBC9mFD4ij4zu6TtyPWMdv", - "marketAsks": "2V21eieb1yaRLac5MwBPF4mrsPfuC2xcb44oA8XBpU8J", - "marketEventQueue": "8ztLqMEfFByTUNgHZCtpU8mhPksJdmJyi8FDuMvzeD4Q" - }, - { - "id": "7FBLaoBUKcktqccrpxNJWbHxX8moW5pmyLRFawT2ZoyC", - "baseMint": "HuMShjViKhcfihmHkgvctcFAyeyxAk8hK5K58zWpuRKf", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GLHX1gPqM7hwQ78gmhz72tBg9rrz4YBDxhc1QWzuJmq7", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "58ZtePAweuhMomnC8d4WBU2VEp3zWsFAmvGX9h1EAyfB", - "targetOrders": "CeAxBxxWLSw7JxUQSJxNaWBpv9G56GGScT8hta8UgJTP", - "baseVault": "Eti48j6pjrbyJ2HpLjyJCSf76biEDGq4CSJqTC6LyCr9", - "quoteVault": "Co8NCBkjqAqFFMJY3G2Rt5jFSFEFJSZ8e69vkW2L5pMx", - "withdrawQueue": "GBvC2zEmrwfFbecziUFxbz1ADivu2gr7bidcwPJPfUUn", - "lpVault": "EmPZApAmKTsbYpaNxhkZmHv3k1Q42ha7bvtUQniqggME", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Fdf11Jsys3dppett8sHaNxstqbVUMVmvaU1E16PhEQnY", - "marketAuthority": "9gWp8G5sysZN7eYmBbpDUEdo4RSTHkC3TSufUnJdGnho", - "marketBaseVault": "FW2hCqcdVk47JXyiL8S9Mu8qrYcdjYw1sJZ3CXtduEWf", - "marketQuoteVault": "6McZFyvDivc9aPhZqACfz3mJGQmaBgXt2dmKaEtN4KdZ", - "marketBids": "67osDHVd1zzx8eqoqrSMosVfXdtgVEyQvroJRsxUdRp3", - "marketAsks": "9stdnBgc6gum8bgAmgvXiVWnR95ioSLWqcBMF7EHkeRW", - "marketEventQueue": "2z68DqAhSrhegswzBVZBS67Lq8GzLDDACTMm5w6kTQL4" - }, - { - "id": "7g9rkhy7bJrxT9NDV7KLbq1TM7mdBHK9E4VWi2p5cg1F", - "baseMint": "6cH34XtzNgCDwb7NFbiji1a1N8F3FgmXTrFxvzBZNVui", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BVJVdrPS4JjXoe6LuzpjaJjqmUgqE9swXSBoXVE4GZiF", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HHZpgRxjfN1dZyPohm1m2sEEtWF8DLMY7vXZ55mggCfM", - "targetOrders": "6ZDrjBNL6pdSTGm7TNXAcCAUDE973FHdcbJDLHFhTwGo", - "baseVault": "g4UrMYKV9z7xsTAHfgbw2zmfrTdmeLKneSosbwgjMz3", - "quoteVault": "6PQzCLvvdnBeD5A88Es4BmFjmXaRKSLeNKCYSo72Qi1s", - "withdrawQueue": "8guLj5bLqb9x2WR7TRnMM9Ti1dCxYqZvNhx37gKeh9d4", - "lpVault": "DxNueoo17d2uQbEr3pjt4a2Psdhf1yNGpft8Gjs9ntnt", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6zH7zwXKyTCUFEGGSjzr4ndegLLPGRAhT2mfcWc6wP1w", - "marketAuthority": "DmtRERAL3HQTLyx1ZhmkRVtmFf5BH7yrx7zyP3tCMNdY", - "marketBaseVault": "817U9vudoxfG31MCg1GpkLgHwxHj85jP2JupC3Wky24s", - "marketQuoteVault": "6wSWztJ4eMEJkuu5M7vTNWRHhDtPXefsrAYcmKHSSATm", - "marketBids": "8MwvBo3UeVjuLUAdmFCJyXeBMZhmJoRFh9DnVjfBooLr", - "marketAsks": "GCaJsMzVKpCcvECnv4L85uhRJFR7g7hMmEDEXos89kWX", - "marketEventQueue": "Fs9mVMqkGxTYB6hsodd9d1M1GcYTTyHksFNFZ956XRcy" - }, - { - "id": "7hUMpFAdjRDQywyNcHrVeb5z9cBBZNt8XATrfqhAv9LU", - "baseMint": "Fu35LwDtm2cnDjd4mZptfDXaXuXjNsgCMgEhpadh9HT6", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "2WwjR6dhRKo6u7EChfTXdxBguuPbTP6dwindTyHUHRjJ", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8uxCt61S9uDprss2gxCNwEG2RzVcSu5dEbwjALKtxNqZ", - "targetOrders": "8ieGFQL1Ui57gj5N6Tmnw5eaaGgW9DLQb4VRdfcXE34Y", - "baseVault": "JDeDRAcSRS6feCjsAfHS8MEpS79hstF2mSKqU2rAwLEu", - "quoteVault": "BPT4jQKVEns51CRpsou181mDWeBDiN7HEAYP8FhFfA6G", - "withdrawQueue": "7K8uyh2ajr2WgmjyXUxXgXi8TVUwBVoZhhvW9JTTgoDg", - "lpVault": "Hjr6LJY6nqw2gY6tbKDZYd481s7VP6ao35WUYWiGbDQa", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EaCbgVDAut2mC8aiWMWfP8AXGAg7QZ1yANuB8GL43P3M", - "marketAuthority": "H7QEoBELzHi6gdDS1yM2cLu9a3dvW1bMkdKJWDXHt9YX", - "marketBaseVault": "65qeMwLjSAYHtjCN7BhN9tCpZJUSn74cExCBy6K3wvoE", - "marketQuoteVault": "DzcXjWqd5HrSHp1Mr5hYMfzcsHp7TrNDK5DcEXHDChNt", - "marketBids": "DLaDWHQUTqZYckz6dSRZ5ETQii8UC5rrZDQgjXnYxKcM", - "marketAsks": "DsMea9RHF61h1aPdkPUNj71tYbxR7o35gQKneRt9jepG", - "marketEventQueue": "JCc1ZpmGsmrJWpCtnMPNBcswHCz4BhHYZenXAowvVoHm" - }, - { - "id": "7hwzgzK1xq3978Fro7XJdQaPVcDYX3yvE7PQ8zMyRqgZ", - "baseMint": "DbRA7Jp8p3tztoPWrDQeJqpKLKXJpotUzJoeiiCdxewz", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "BTPLimTVAbVMJes4ssdGeceLnpqWXiugs84iyupeur7t", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9PREBKs7RzPeiVTsZK3DdxuYBEAZqh7ERLUZH2F7BzH5", - "targetOrders": "CARYPQDXzGwPLwNCZCqZnGiVM6ZSQ5nZEfUMhcJGof74", - "baseVault": "Gi5HADUY41d11KdgQecrdxZyw3RWnLq7j7cgCht2wrbU", - "quoteVault": "3dxrsSNKwmKMVPLV2k5EWfAPxGmPKhywMFspVJNzJEo8", - "withdrawQueue": "GZZXuAPA9QifaJkyHBYEAzkp9CGVBh8niqkk2wSmuuxw", - "lpVault": "AMgiCx7iKdvWsj8zhnGrhaZFJHEvP8R9LM47fRQUPg5Y", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FoUNnH6RTVFrL92PsvgLbwTZbFHK1PUe1rb2ZWfF3VGK", - "marketAuthority": "3a98eDHgxKRpoWPNKRiJReWs1PomikQho5qcMKTEvX3s", - "marketBaseVault": "AS1THAnRGpkCTrzCSKP5DrYxBghnKmVRgBZkqyg2kW5V", - "marketQuoteVault": "Fn3pAYh3CHf4TRonfmP3w4FpMossnPWf6WpG3gFNkLCq", - "marketBids": "5kF7SfQjwzfCuHzZgH3EzL3wBpyb94UnAGf8iH3zf79", - "marketAsks": "8zwWergm4VMb5C3m7GfPA48Nrz2Ahu6xCMPBBdps3jzr", - "marketEventQueue": "FbyBpdyYJ5yCxqg3K47qeC8i7Kd3VGmiB38LoRbusPT2" - }, - { - "id": "7HYTWMLU1C1MGJUohgsahCFpL2135HyaawiYw3sAFD5w", - "baseMint": "A7DahQuHVYsAt4ik1qbrgWW5zQVcXirheCeWvrbGuJ15", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "982VjetYEPVWKbVDXMgobsSkqYQTwuxU3eyJh4L8DPPZ", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2oKyiKtPCbqrpfstrthLkWJaoR1j3LhbzvSK8yFCJUFc", - "targetOrders": "Au9iCUxkQ6JTEgj3GEfiKh6pQ4wxodPAdGbcJELpoA4c", - "baseVault": "HVr4FbDFvYvqMo5gMxPEnurN2CoykbcNzVTVPV1a8rQm", - "quoteVault": "6MV5Qg7R8cXbKth7vFWzCHFM3SomgRPEEWisWq9JeMeu", - "withdrawQueue": "5Qd4vg8HuHS944EeS7CxUU7qn3i6Zj1qB8jLJaLMNS7e", - "lpVault": "7VrJ2SLfENZpHqCnaCAEmsEZCUPmEE859PZ2Q4iFphmQ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4w1ucgJFB1jk2W5BVwWKmsEFQobwig4y3vrJmhk3zQH1", - "marketAuthority": "65t2zNFHJSXrbt7u279N91R7soFnVn3ap23XLscoCE4W", - "marketBaseVault": "2JP5BDSNJ89URRqm5KMXksqiSMGdrbbAymq96jPcGSNk", - "marketQuoteVault": "DdFvALBNFpxnokGATN8XRFBYwkdWMRrgRSRrEdPGi9Nm", - "marketBids": "ExX2S4sqjLvWaCeaep2tJToQTccBvH9TJuWxD19VhVkD", - "marketAsks": "A8M3P9UxKk7GZ58yzqyMvKpU6jdQtG2jnTRUH5F9wzKQ", - "marketEventQueue": "CMv1GMSFTDbtptpTBV2j4it1UryzZ8DQ6JKb8Z6bzFcY" - }, - { - "id": "7iQ4TKp6WwasWTrSFoTgWefz5rK7d3oRdGZMj8gdWp8X", - "baseMint": "7TidyfwBJm3sMX4Evk1pGjCTMYCXukqvdX4VNuy5PSEs", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Cw27CtdHv8u8nSxMJvMzvCNkNVzpcxuwdCtV1m6bVh8H", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Bd5yK9zSiW2KfDmn6ciMkstEbZ8CK4PJxsUnh9VPDC9K", - "targetOrders": "96SqDKztQccBBfuvJPQyNi6aWEs5GJsjEFo3B2WMYA8D", - "baseVault": "GNQp5zor66PfdrMjuie5gdYM1iepuT1U4yRmhaEhu2Ja", - "quoteVault": "4xYPcYyXMaFqfMpttGNfupUAiErGXab2U5qVA1y2pr8K", - "withdrawQueue": "5FUMmDsNAd9w65kd9RLpGZUpdKMYWyBEJX3W2PHfTLNc", - "lpVault": "G3gBPDBYGdAjTbb1AoN3S3TrmvJ6Za7fHgM4iM3GeGHq", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4ZpR9G7ziajESa1xeSXVYq8YiXxgMcRqNotDKNqQYKAB", - "marketAuthority": "39bGnxfLuiNAACqGpYo7JzWSgkCuMUFBFVZhSNzEkAyx", - "marketBaseVault": "AWXjZGTDkdJ31SuLHTwgYwkX2HtDKmEi1E1pzWEacQEC", - "marketQuoteVault": "6bugVUT18ptdiE8X6X6X7yiVX8CrwUVHc1KcvmfcBS7i", - "marketBids": "D9oAvCfsJRYeRWgDfPN76KZobYrwkLKxEYTRAsFyEf3B", - "marketAsks": "JEx3VRuFkaktepLjJevjssrTUsgXERTEMCRhxZWZUW7", - "marketEventQueue": "9HCFPQe5KAWT5WqkjiDPQsX6SpLSDZ1eZVTYLDSbBZVx" - }, - { - "id": "7izBTUoauuCXVDj4pZj7y5Pqx6GV9nTFn3ZwvjWQZ6wP", - "baseMint": "A4MgR6ANAh79AE1csJjXiRV2vYDqP8wgSUUp28HpDEyo", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BbufyUuWzK5ogiryTiaLm2usptYKdgwQ3gBYKSnCAhY8", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DVejbfCkn86Z9wyCbPweyMgPheqwyg4hoWLwG5LREFSP", - "targetOrders": "HEHvT7dGfukCwwpEawr9TcT1FL81bo12msFJD36xSACr", - "baseVault": "GQ3t2Y2HaHC5eKvUcqAvYp7jT54ogBpMr8sAUUJ7vWrr", - "quoteVault": "56hwaqRVGnbmtTQyGVSXmhtaBdsr3MVFyfoeFtCez2c6", - "withdrawQueue": "EptF175gBj2k1rhGsmdf4JdiCfF9BEz4nQoSVEYPHY6z", - "lpVault": "G4C69gGT3nncha5MbNCULfDUhWjbq2mAWZpGHZHuHJMC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "G38QJohB22eFjHCWgrfmRZfU6VRzZz5U2mbgDb8gBHr", - "marketAuthority": "2NKm2tTckj6VA1JLLe6JKYUNCCpXtTWZWVuSxnXPGkQ4", - "marketBaseVault": "AyeP5HQb5eMN3iaMCMJX7HPZqXDiga9z8HrxQb4bqmTH", - "marketQuoteVault": "8Qy7RUpc6c57vHcFs5pY12M3LPLRSA5MB8ZZoNHhGWhM", - "marketBids": "6GEMm4Fesyeni7FSsjoPD7VB1SinjySWGi9LBUakVgLv", - "marketAsks": "HeZF1U4uswmcQRLkoZcjabGHNVwm93NvFU1FPN41ZmJ7", - "marketEventQueue": "2DaMQRANGdmubbSdcHqU132Urk8WTXgSiPXeHaFw5GEZ" - }, - { - "id": "7J1rqvhNqQ9QDfDt6a4XK92ABGVeioZvu6Jm89ukhJtF", - "baseMint": "5LhNrGAfHrirRU4KcoSqWBExT29njWUrg9VZJDQr4fzy", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "Fp5oA5LjEHcAJVjA2F4EgnLRvzXkjLZxZbePPfFEfWSk", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Eb3M4iChGyA2MoYGiszKGUgBSp7eJBRfvcVyNZ1hNGbr", - "targetOrders": "9HFDCJAHPWgTCrnAUZSb8fGCVizjHJTsrbgw1ggPuvDk", - "baseVault": "9F6YsBWWFAfyy3hA4JWLSSvQW6ED6LRP3UMu1aoAsyZg", - "quoteVault": "8LtQZZ1W9JJ9u8yVoymGfYfrj9xRWKfo3wvZPC52d9ky", - "withdrawQueue": "QZkkZM7LkCsL2qhKR42fzbNNK5Ubpo2sDQVeHFL6x8r", - "lpVault": "81ZLn7uapgjbdYYjkjzsS3tHWzRgkJq2TAzDXMdrpVUq", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9vYpZEC2dH2UHe83wGFdEUk1HB5TNc2kmP38URnNj9Yi", - "marketAuthority": "4oHF8273EsLfZp6nqR5QZHCN3F6iNQYTHmS2w4hseh8d", - "marketBaseVault": "9CnZL5aRy9VccD1wnGK1kkij9HEe8jJocXDd7zLfq44f", - "marketQuoteVault": "9jZs5wbvgEe1ApZPfv2kd19PA8BcAnpPbF5Za7nYEck", - "marketBids": "8RuUpu4kAaVnuYMxFwRbw2QNJENDShsTE5fQ8mDoUQXn", - "marketAsks": "5u3dBhb1C25P877Xe7SJGN3zuAzxsgLbCLNoGm8nP1yt", - "marketEventQueue": "8MGSk8jPD8cdt7fRgAhH6XBXhScuY6A7gvvYnqCodxKR" - }, - { - "id": "7JfoxXwsuNkjg4SdQNBs2kZ3CLRQ1mB3tC5X9FEoTUYD", - "baseMint": "B8NrYG3ZGbmDS6Xv5PUSdpJmXor9VvtxibvDRKNq3rnc", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BcowVYPVQndaBeSxD7d655B9LDWHaZE2AmKAZALgaqd5", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "H9cm6UuLjBHYcV94jNVu9HcjTcZ3AqFYQkRkggAGhCiK", - "targetOrders": "EczYd9ECMgGfGp97P6NSJP6e69GgFFaHcy6R6meyZVzH", - "baseVault": "ADP314Z13XrWMf7yFXSsFFH7coEYEYXU84TQaH57mtFb", - "quoteVault": "G2S4VVxFwDngG1NJztRC7sWGuiHmoAEWwwsun1iEPuen", - "withdrawQueue": "5Nyi2x2roPsdS5QymUg7UTycFqTsJCt3CsyQfWRNGcV2", - "lpVault": "3wByoyNeQhdvVJXyvBFoftQijj6RkPVXDAKdjyRYpbGp", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "33yZYuVDyoM6vLtUEG3aStJRgKTAJ98aDuHEm6q9YyVJ", - "marketAuthority": "AQ13KmjsU4pACyA15CFJzgRsA24tgQMduWfbNwnyD28v", - "marketBaseVault": "CAnWJBBQz7KuYwGzsx5WTYt4GTRRbHrBra7XCjzg8TAQ", - "marketQuoteVault": "FC9ABZQpbhrQc2YHzoP32hZQ9UrA1XpY7p3zmxYr1XeY", - "marketBids": "5nXuDrgNW39GRXVKgzgyULzPMqyrrohEHiDENXcSVaX5", - "marketAsks": "Hx7oLuFfZRRHZ9TUfUhv5aawFnsiGKU34NCDGbPb9hMR", - "marketEventQueue": "EEP67nrvXx1J9ieRFjKN2M3qAcXfixwLhsTiuKs6nYFX" - }, - { - "id": "7JrbaznhHUFu1poH94vzRyexB83X5DNUsHcg1HB4FZmL", - "baseMint": "6j14WyX1Ag2pLWvn99euK4xp2VcZD62VeJv2iwCrYmT8", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "7CtqMVn36bCxCwzWW4fgjochBaK2Pxv7syFRop2AMg2t", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "fj6uFUCwnhpJSjqbfTEs2NmArhHKVP35q6KDUXLV8d5", - "targetOrders": "DbNccW88UqTeyjiyMaSfCjwB4iJDJ5bdGM36vYUjWvGc", - "baseVault": "93JhQDbSnUqd6NNmaRTt7BiW6Nu9xeTbipVsFKHZ7UT9", - "quoteVault": "ydiKLKALvyLb6j9cAwFUm2vPhpSQ47SSiem17Bgv1JU", - "withdrawQueue": "Ccf8hqNVTAZKS3BLwcmZRkfHSwnWH1FETrKdcs9wPDyh", - "lpVault": "5Xq3vH3zZ39vFjgKtSyNwE9PaEwp9qmCkho5jw624Dzu", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AoJxDqH9Cr92Cmxmh2zgkHffnRt2WsPQJfUshWXgQE1z", - "marketAuthority": "7gy8XVGALHL7deVLeozEHPChX9SPpbkXRGGPR98dYLE", - "marketBaseVault": "Hd5nfkoUK2gARfSJG6jQLvgvbuKhFMyrQabCeNJnBuFg", - "marketQuoteVault": "84QkbMF1MyjB92TcX3suwrQN23sgWAteQreNCRySW17C", - "marketBids": "5reeMaHkwu2bkYGe2KWKbK3yTUGzF52n87sW1VYkFAwe", - "marketAsks": "pT6WoS4SFWmYP2amwcosgojzp7mKaWPMwXjFY2XU7Qm", - "marketEventQueue": "3wyYPnUc7MXaLp42NainWBypagF2rVArBsNsrxy9sAjQ" - }, - { - "id": "7Kf4rUuUPEQ8ABeuWSrHF7KZJmrAdcdx83wQnK4vvT8", - "baseMint": "Dhg9XnzJWzSQqH2aAnhPTEJHGQAkALDfD98MA499A7pa", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "H48ZPpo7CCLPTXMVZaftMnF6HCdFvzPehY9frzDHimTN", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6LKhFXGhg3xCeSHHUCcgFv96YAjMVEsPabLZLFhWa2Wx", - "targetOrders": "A4GaJztf3XXpDQiyy7ketEkXws8eSzt4TUF3x96bndLL", - "baseVault": "Es2khjE7Zud2NMGJTwzq41o5vD41crXqNU48cLAQdS8C", - "quoteVault": "9xiCfPgYarhCkXn9BtsrJLY7hcwsB8z1avCforx9PqK8", - "withdrawQueue": "DfB9SviH4a6ooGba3MX3oRV1xij1fk6rzP5nomZv4NYR", - "lpVault": "HLJQEbfHxV9t7u8FWzfY2fvxJysCGLwWNoEpgpkXwBf", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3M8uZhLZMxFUedsEgPzywZr9qbGTv3kKNMCEfAmg8iyK", - "marketAuthority": "CUUxJDBeTx8z5LmEzHgSArDtk5PTqoTrgE9j6stxEEzb", - "marketBaseVault": "FMjUvgaL4EjyokpbsPVyJTARjfNQRpu694eH8S6kHfAE", - "marketQuoteVault": "9B6xoxBvxjJYXvvQaWW619Ugc6UT3gJS11V3pBJGfHJH", - "marketBids": "DrxjWRjksVnBW82yAkzMz46SuWxGxD2vLBheiKF3aWLm", - "marketAsks": "4NoMYc1ngibNPMHzfv4sXG5ESBcBu2cb9R5QwewAhEyJ", - "marketEventQueue": "24TPms7kkg62D8MkiUXEB6YSV3DWNrxU2ez9o8ckjKD1" - }, - { - "id": "7kL1jYN3f4h75A1wVFyDZM8UZ5ENkpeAd9sEeL5HbPJt", - "baseMint": "HY9LZ7TsDABoMzYfZvBwrLEUVEAWE1kGF8XS1JvbMN9u", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6koPm6j4QBJjGK3PVMxXsSEzccAJqJBKs2kvv3ZJfsa8", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EqGpjhYrTgKSKsDNWTZ4Y5wR7eDHAdhm7RZ6UgK1XXis", - "targetOrders": "nkg66TwLYZutB67eW2jEbKDcJUfiiEDYxfekSCZM3t3", - "baseVault": "7Sy2U1763pPtz5tuoi1PjDH6eQui8dMG52p4jKL7noKn", - "quoteVault": "8cdhYvzHMw65RjJhXKvs45HaP636CGDx4ybJV7tNtBoY", - "withdrawQueue": "HPAhvKp9yZ63bjie8x5QqfD2CAB6WaAokCpHuV47Q6ae", - "lpVault": "FyTqxjsjJzsNEyaqPwQhwchRbSoJZS3PHfyK9Vyf3d3m", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "B5BuPsZ5BbnqGQbUCRvrPNaaPmW8UJrPoFkCevpeLGWU", - "marketAuthority": "GpeiuYMzj5MByzDuQmDmMhYbtVssEcxtP4PU3EJkjHfH", - "marketBaseVault": "DZJPhrD5o56Ah9pYdYVEVj3cKHUJDQpVtPc6nZsux3CQ", - "marketQuoteVault": "7Qx8PuMHVQPyRUvBjDs5XNBYtxUbiYyJFkumaPKbzjGz", - "marketBids": "FovCaQ2H1QjzTCnEb4gztXjszixiTQGqSFqN5JZTqeKB", - "marketAsks": "B2ud3jyhjzhf3ahs4yaMKBwVfdv1AWLgxsDXoGW9brFe", - "marketEventQueue": "3zJsWP8v3Kb47BWzc9iHBzUYXwA27AnJAWoTp152L2ut" - }, - { - "id": "7L43yoT19YrafYB8q43oJrYfvwV5X8SA6peRt6KZKXNw", - "baseMint": "ER7VS5oDqmPCALdxopj7583gzUC49cBuuNUxFrfc4uCd", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AjuaUfHGSxb5NpEfn6Y8AKJVovgWxLRAQ6oh915NtuDX", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EJHeUq7xFVZZzh2QqzN2TKv5FrCm8ndeWc95My1Y2N36", - "targetOrders": "54uAeJpzwyU1b3EpEpDhxfsKSETRfHFiQv42mvibGxs7", - "baseVault": "SkVmqLKgH6gokBDAgNLxCdDkjiBAoYanGSZw1847faY", - "quoteVault": "5kKEbzbYHQPMjN9NfbMVUvZHyVtE9AVYZne6TnYdwZ85", - "withdrawQueue": "BQJeiW72tosBJrqTRfnWBWkn6r48MhM74hNXtNushcRM", - "lpVault": "AU9wGowXvAgBZFNrjgdL68jVKB1H3KBq7zqNfeP5Dgps", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7BjseW4LanA32i6PvLt7hZ3WTr2DKSg6S25gcVD1mp7A", - "marketAuthority": "J9Qws2Q2c1ZvhTpi6Yx18TKCifBQ9c4eMkjPJ4dFWVMT", - "marketBaseVault": "Fewy8HzCb8drVExpAxiF3fQbossCWgGYYAChyGGFMnP7", - "marketQuoteVault": "2LTyahwThnvRBj4JrLDCjdGvYnr68XdkYhcN99AbgsYx", - "marketBids": "HFS3sZeTPSWREGRDe1JY7WXkTscEVc9kXxpDRnhAJkf5", - "marketAsks": "6kaJfFmPPkzyrfpQ2tb9uyMdxJoJY9QzjG6u2ZZVFnqr", - "marketEventQueue": "82rrJm848bvftvDC5JS4dBxhd8vf651XxddYUwJ9Jndy" - }, - { - "id": "7mC259xL76RwSwmYeEtNFjHhKJstXEr6R5PyBvpcE1dk", - "baseMint": "BaZXh456atM5Fh7uWcbKeTPGXbMCacoxwXhbrM8eefNm", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Bei2H4MT3jobi9KNqEicVZomWxJSZBuJUrmJ6aNBoYMq", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "aBE413nvoeeU6UhnoE6gwSzrhJSvorKbKMGScpv3Ryu", - "targetOrders": "5naTBh6D8KhTPAYimXRP3o1Y8Me7XsConBWZD5eSnxxN", - "baseVault": "HzHKeLqxjfzefpXhkjGp9uao9hxdsnGFHTv4kXF1EdgB", - "quoteVault": "9ortxZxJ1qWsF7PSQCD1S6S6RUwzm8KXMQWseDUYzETW", - "withdrawQueue": "F1b47cHy2uhatbU4D5stZxZBLU1aP6nbuDut65j5mNKR", - "lpVault": "BMHrEYdi1mabZde22KABZeGqxrw6h6avBraYrFYPtmnb", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DtoU7UCyQXt76D293DbgmFtUbbJ1dRqEbB9P4HLERmHS", - "marketAuthority": "BqQ3yDBqKP1PUviEY6o9ffWprh3bL6a6eBEnCcRc2oPS", - "marketBaseVault": "2secRDV9WQH2jFXKEbfQb32eCfw2qp24UFKDrqyT599S", - "marketQuoteVault": "55AexvquP9EXcA2yG7JsaDt6dDcSkne9Xm5h28B2h1BW", - "marketBids": "BLLCXuYj4413pPisRDpqPKWiCCT1uSKbMw8c5M4nExtu", - "marketAsks": "6duEjgyCcpdaBp9hFBk8ACbydqWTofaP8ag6qLRVbkug", - "marketEventQueue": "BmBEw2j5nXQMMNnDbUqaSvpXj523GxGqJv1YX3kLUqhQ" - }, - { - "id": "7MenoSwHyaAKLoYTR1A6Mt3aD6B54RbBnEENLLKsT9DD", - "baseMint": "H5euuuZXAuFak2NVTMu53fckdkHFWuJzXXb3TfKTrLWK", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Di4oQwe4e7pHgadXEsnssTgVmmqKki9smLtkwEwLvSjg", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4eF4NunRYNArbTTxSyBwkvgQXFuKu3q7CFLJj6S5BEbQ", - "targetOrders": "Ecpxt3nETp6c4oJiCUhgDdErfiKQsXtYKbhngY1ju2Rw", - "baseVault": "AGy8Bt43z2n2NC4cTa8Z7VNCfXwLN57e5UqjK3Fo7dvZ", - "quoteVault": "AE2iEVCpRCPohzKDna82ram6z6AwYFnRMe83kZpfEWo1", - "withdrawQueue": "E8Vh7SZaezg6eD7tvKZ6CXorrfhW2AbWaf3YdmDUU7a", - "lpVault": "D4sx6k7AcVDaArYW3RTdbk56wuvX7913MJHS5NCYY7WP", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AVuTEo7ZMHcYYNbfxC1kRRHJmgkrjWnwdhddmFGd1v1y", - "marketAuthority": "HmgxXFQAs5GToAbuUezdCg7oaMo9NbEEuHGdhrhw1FDv", - "marketBaseVault": "GZmCmDMsJs5XNaG3ZHmcrk5qiBze66pWXsMWhzS5CPcm", - "marketQuoteVault": "FwJSFT9fxLQwt3QhFe2At85v8FvxWtksppY3aqu4tJ2y", - "marketBids": "7T9fuERRPJcaSkphQZfmXb49fULMwf25G2Rsiv7MviH3", - "marketAsks": "Gm58TxFWBqdoox6rfmQmDFF4Y5PtRA6jMnV3zt3bTSLT", - "marketEventQueue": "3qhpKC3HWYj9QgEcNCoLCTMxQiRW3DFix66JqcpQUKzc" - }, - { - "id": "7MhAxv1m7GNbuQGYpY2ExWK6bzQayU1vtkDJ36B4fQav", - "baseMint": "GHvFFSZ9BctWsEc5nujR1MTmmJWY7tgQz2AXE6WVFtGN", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "2jffMye77bEqW6zt1azoN89cbNw7TaJ2muQ55HEd1yzs", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DMB3AorBpHhGAmPgckD3wzREdfQrxWXaZVLCTphibfT7", - "targetOrders": "EJi2NGsNbmVc5XoLgFAFPnx1XXTVgywi5MgefPJvaQdV", - "baseVault": "C6ZDEXMBMMvx4u8Qfbyx9d8MPiURBjDE2HM68ckn6EbX", - "quoteVault": "2vECvyH9ox3jG9epVRfP5GxB2oStmbc4voKbdmrRPobh", - "withdrawQueue": "3EjjgLkXE7LtTL8fnzmq5GA9i4ZAMbhbFr4Ckkn4GejH", - "lpVault": "j3YQAWDptXygCWThwQtUZ9r7hurd4QXcuiBWDVFH8RA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Be2ZPST4oxAJYTQmxcMrUh7m5KqqF9xPfuxeAB9tSrDr", - "marketAuthority": "6FhpapVsRnpscHGeWnMXuV1x2ZjT1eTrjR6H5bYQUNgQ", - "marketBaseVault": "8csLfeiZk1NffJqES4Bb7iTHK2UQ4yWAp6k6phtnBYFu", - "marketQuoteVault": "5vtkSdBa4zXWZbcUkGgjkeidi8dweJY5kdxsRKTeJ98G", - "marketBids": "5mamUc6iQ7We3KwDWmr1rbJ3n5T3BU5zT33spAVUXATh", - "marketAsks": "4342eU6y8AgFLFP2pd2whRF1c1yLGkT2Ltnk8X9V64o4", - "marketEventQueue": "CGvCW3Qie5441otHyJkd4MokUqpBmWfBKa7hEtZzUzWp" - }, - { - "id": "7MPxBQpVPC8U14ana9fHSWr8cD98FL3T6HvKsBGsgNQD", - "baseMint": "4nQqJkBx3Dnovc6ueEdkJfFr2zi2fc77834czmoymR1b", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8qi35yzZ7WwpJg6JudoCofdSwVCrfRBNGvFDyVCyz3ja", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5mHuHaQWdYKYxV7Xbz24TNdA79oDLAuqpbQPpwBnHEsc", - "targetOrders": "7MJCC5wdn9KD1VL5PdUCRny4RDev6BGi3snQXfa29kV5", - "baseVault": "BVQXPXRPswjDqXjqU7pQ9rexpyjgzjVHsgm26rDugNmj", - "quoteVault": "52h6sihtbn6nR3o5urw3LPZq9kMavP1aoRarxj78xx6a", - "withdrawQueue": "5quQDExb6rXMiJWXEhLr81mDCXGLwWHVxJ4unfZTxRT2", - "lpVault": "34V1Cca8dHn35NHzLhZcSrTjECct2vvjoxHWFrd4NHHf", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8Bb7qoCHng8Y1N1owWw1UqASvHRoWw2Ryns5QwEb2p1v", - "marketAuthority": "4YzxbozvFK2NkVx2Z32xSpUTqDT4Ukf8akgLQMXihgeF", - "marketBaseVault": "8MmDimE7KjLZmUYvBZdeBgQkfea7icmQb1Pxg3TDVgw8", - "marketQuoteVault": "GLKrDgXEossDgoET4RVCcjpShCXJM4hAgAMJ14BLsR98", - "marketBids": "GXVQcinWJgrswJ59vew51vGpgJWQ3tTJkNpqDgHXQ65v", - "marketAsks": "DM3Zb9CsoxdLXz8Utzvh5cnhyAFPz3ettmvmSns6byDC", - "marketEventQueue": "7WBx3fUaMG7W4s984eRXM2qin3gZbSYEaRUJ9yekZdQA" - }, - { - "id": "7Mu9zK6qV3wGp5deSkhCeWqaDnL3kdD4gKL87ui6GtmX", - "baseMint": "ATLASXmbPQxBUYbxPsV97usA3fPQYEqzQBUHgiFCUsXx", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "7kY3YJSbrzaU56Xg3wEFZ7vuGQpU27fK959jqRnsfJWt", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AAL5LQpnHbSpp7R84kqP7RC8qLEBmK6tdVPwoenhE2sQ", - "targetOrders": "7icfDJTgASm1tgtMQnByqzQDP42N2mEPdTvX8gWA7ttA", - "baseVault": "CBz2GGWNissxivNRXk5UFJHiZUmm1x5pWWuhSaoM8ULK", - "quoteVault": "5VhBQ77aqytGZ8QWtV6eq4p4yNHsWrH3bALKFisTp18n", - "withdrawQueue": "7wnr5fncuVijT6Ds5WRNyudAh3kiw2e4h9zHkCkcuCKb", - "lpVault": "FapJAtfkJTXfHSJJTqWjxxdmKpBSSUF2b4GFvuEfUZJe", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DXHbH13Bk43yBFu2shKWSzbEsgN71Z9miMfDTFXMBbxD", - "marketAuthority": "6n1Wqf7g8AKcGC3eJg7QDronvncNYExCtakdwc7YZ6XY", - "marketBaseVault": "Fpk5fLsGhmVkL4ecxQag3rbq4VaByKojmaMgPZboH3ew", - "marketQuoteVault": "8pxKjkJLsyErFE5TWy32xUcNCUcWscRY3TiPejgtARHB", - "marketBids": "B2LvTmMYCK3mwY7jyxBZso2sVwBihh4NDVhYoqk95hoi", - "marketAsks": "4mnH8nPZkjvnkJUju3QM3HrAMoCZXqjpTSXSHY2eKFJo", - "marketEventQueue": "F6LoBdbU3LPTCTKjqpLQJinxNuevREBnEteE7Mrm2QGD" - }, - { - "id": "7n45btQhNu5expVQrevYxzNX5V7pikmBJvtJkKCfQxAb", - "baseMint": "6VYF5jXq6rfq4QRgGMG6co7b1Ev1Lj7KSbHBxfQ9e1L3", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "Baom6Y8DvgoHiTJMbA2zX6MTNS2GG4H3rAwWK91N3Hoa", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3qgKaQvQTQnQdHWxr5BiXLZsWz5SqLZ3akpGgzUPEKzh", - "targetOrders": "34SmKusBqJGXKLQ5XGqWAoRZCqhsdhdDhqxcXgzBPxLS", - "baseVault": "4V4s3PxgLYSq5nSGSYo1Edsu54EVTfcsmnLPhvDsY2su", - "quoteVault": "2czYCE8NXvWRBnFnvUSkZfXumu5fpRcXFaAUygDRRmXT", - "withdrawQueue": "5o2G5U8NJ3EFqaYWHUG78JgxXwj1S2uP5J16ovYdNgbw", - "lpVault": "CXYrvEH1PomP9n7QZiE5CV8WdboJvUe6He4go9aFrneC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "63E3NjZfX1QmE96mbPqS8LTPQfB1PfCqE3nkTFFvFJv2", - "marketAuthority": "GKRtquMKokTh7wMtZSnzLeZissWDLrXFc4tGiZUxHpg2", - "marketBaseVault": "J65aEtESNinT5qAqjnbJHkkpjmc3YYpZbckUZnNmXzBV", - "marketQuoteVault": "67LW3akcmp8zV21RrUhLZ2BFvqLwAqFF8ETiLk1YKTZG", - "marketBids": "4uhHFR98JVzF48eLSbksrKGxyRYVRi394WJA4y6vJFgQ", - "marketAsks": "6fNxc1jYyr88Bs79FqUGmMZZPQDdPJMjEgtDLckhFJEK", - "marketEventQueue": "Ggfq3bj5U5NQnpmCVppsSJ9yXQ3LPsJJkZHzuCajBg1J" - }, - { - "id": "7nBEkmejWKQ5VHysMRpQRpfGQXV7RDB57JKyYcddi97p", - "baseMint": "7MirouXpJ1J9wYT3jB9xSp8GKwjx9fJ2hHut5HxWxdLa", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "EjcmCUZ3RD1XYVG6bAfjuYCkQr2S9oEaAQssTGRdNDAz", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GxAA3FHEGBxcJrVMABGQuNourd5E2qFfNNgLmtSoHciP", - "targetOrders": "5Wdk8h23HcvjWVQKZC4zsANw1x1vNgBdeZmxr88jNMkZ", - "baseVault": "74PwgSPMhLVwZuxqxoQwK8MDE1jE1vkgcK2vzDtZ4fS6", - "quoteVault": "45nx7WtEBWpVKJW6bsQgihZgZM7UjTwrjBJMfvbzdAFJ", - "withdrawQueue": "Cc1Azu1ChkQrwjVG23iQaXq6gKHXJE7QWEManuheLCA3", - "lpVault": "AMH2TESpET69cfgqsYLvx4xdCuthvFJNcreX4kVPfAV1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Hp7mpSzE3PjCmCNDgNMqLh1mxsVFwoQoTY3bKy855a23", - "marketAuthority": "AjaHVFAykmzsbNagF39c2YWqSLvP38k9jCjxRgR3jZjo", - "marketBaseVault": "4uj5HpjCn1qXgPVMG27x9QmLDNLRHVvtb66V8XfpESbx", - "marketQuoteVault": "6hRYFunJZWF2QTr4ADQngWu8Hr2MLK5eMXknjdUfRsPB", - "marketBids": "GPxL9tDNW1NPP89eaJTHx7dRQnL14gZDMuDbhMuE4QeL", - "marketAsks": "GXMEtJzJXes3KB7mmubVjzksm3rt8vivNtLptkqE5mFA", - "marketEventQueue": "G86LPdVwUrVxVM6GaAvPW2Ubq3hd21LBcA6zRYdvL7Ft" - }, - { - "id": "7NDfhD9hEkQFfVXMTHEi3p4khDjBFjycc24Qn2coZwgr", - "baseMint": "DK6PWMyuZ4NMjsm9AWNCTMKrajQYrtfMjMJ3QauX2UH5", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DdoDNq6DWywK9Su13o58nPfv5JfftgP8gzQnRBadLXcT", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5FmRKxpFuWTbsfUywMZMUiJYhvhZFYFG5c5dg1syFNrC", - "targetOrders": "55LnumwZRqcsZPyKNpQZwJfjZimDoESvA93EBsHN3Nip", - "baseVault": "GJz3pWa4T3BGxM5dPzCBg1GuTFZ12PuQH9R4eBAqBUKb", - "quoteVault": "3RddYV1xRWzPDGcXysDUdWCEJpyWBMhoZx1NnTmY1zzD", - "withdrawQueue": "2qZ9Rpc4arA5pKxNnNsH5cd82H8icaogzhJkebMCgwTd", - "lpVault": "Ag2jgtebQDPgCyx4WMF8CM5AAFDYFwBktBydQcHfYi1Z", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ABydcz3WA6JH4mMkuTLQwdqrRFuvrNrQd3J83uFM5oB", - "marketAuthority": "AWvvnnnm93NC2rmLE5jzGUZ4jtAJWWdhRumjjUwwN6Ba", - "marketBaseVault": "EBzajk1GJrFNgJmL1EjLVEVe1P2NqMFd8mC1kzy1JgvU", - "marketQuoteVault": "DZK97qddNdTzPw6reoTjEn7Vf7BttrBvkHPUu6MRun6d", - "marketBids": "A8wzuUEeu4kCzrG6C5iftnvjrAop5PCRRa5LVAWhBL9X", - "marketAsks": "G8GVfkGpGqyiYTkzT9rHCvBZPDroq1kamHboFZh1Whhz", - "marketEventQueue": "FRNMnpdsBvb6nqTXXPATyEm9h5Hoh7cJUXEx7uapHXLB" - }, - { - "id": "7nePGGLXC8JXj2UYRqa9eToHEEWjpQAuoXh5HX5cRKt", - "baseMint": "2uRFEWRBQLEKpLmF8mohFZGDcFQmrkQEEZmHQvMUBvY7", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "67YxPMnsx5jqnyegtYC3yLdGDiLuEWEMGGfrY7mF9UNE", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FVSKJfGxs6uQXF6XwaXXeHTV1QsNMD9urCoY7HbfPo2X", - "targetOrders": "7wGnTM2NbPBihaX3RFan3uyWpRSnzYwC7LoYJvbMJ9ax", - "baseVault": "7LwsKiK5PLY4qQ32Wc7u4QWMM4e675dfVvcsAp2hTo6T", - "quoteVault": "HtgFVhvCV2mFjcx6LpFfEqRqZFKu6Ks3stnHTXqiUtfB", - "withdrawQueue": "7zp6tZhBdehrtbtL8EHcwvynYWsB97rWZjXwEHPQm1wX", - "lpVault": "DocZTNPxh7t4Ygc22s6S1Q5rGx5kmzHPmifw7yzLoVyF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GQk1KCwMn6SigfMjQ77Q6Mprgh4Qg54eijavDT31VJPZ", - "marketAuthority": "D2oMYFy8oJMYrSmsP4GDWGtPffgvQVzejvxQ5Ne5AYCo", - "marketBaseVault": "2peUN2jDx89jAMWAPRARwfmXJ8YCqogkaJ4ogZ8G1jKm", - "marketQuoteVault": "2GgduoEtVUWbJmm6wGXeV8AMoD5TEqk6xw4rGK4saqXN", - "marketBids": "J3ixJizd7surXQ7BJD6jGSB69Yd9FJHWQuQxk1fL5aF5", - "marketAsks": "7n153nUfSeGEduxidziJ3oCaJRmZWDmZak9oKBXhKuqE", - "marketEventQueue": "Aa4Nbbap2g7FSmUV2obUes8vNKuKjzRz9WTnv4RjcGDU" - }, - { - "id": "7o2tLTKTSfawcPMdxYgZxbggDYJzSvMkxZzsTpRR3nMA", - "baseMint": "inUKL3RQnScpiPyK6hVANpEAdFwQXJa5ZJDxPxr5aoV", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AkjnULD7iPCYht4ZonFJei7sRkcbqxa9apMnZeaK2K1f", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7LrCWh91u1mq7WPQq2jk6fap2o2eM1gxR4iPvARahJek", - "targetOrders": "25kXAtMrkpv5SQ9nP67MTV5LnJ1K2gRM9rNQovid6z6X", - "baseVault": "F9zNGa7nnx4Tcauqek7YbWWXVLtdcR47oTt53VTsSQ64", - "quoteVault": "DBM2P66EaSD9HzBxbMcmH4uGsqiBvhiLMePMYJepHmVS", - "withdrawQueue": "H4NmWkys8aMK68C4xye8sdheQRkxru87FDSDK6RTNNws", - "lpVault": "6KBvjhKFHbtqVoat9DndaPMtYCTjTjiX15caTKxmgxub", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DJUFJjF1cVyR83rDnAdqXJCg1WAoWMygBKHMKZykfCuQ", - "marketAuthority": "49Z6uTsNNUsKwF8Mzn57WJfd4pfRLcvEgfbUB7T89RSm", - "marketBaseVault": "78jP5vaE7R3RNoaQ2ZDw1gPtZaBJEsR2yWYo3naLdVi7", - "marketQuoteVault": "7jMdNzSwMetvUUnLG9DjRvYBJzcTASWm1wqydhqiyHkT", - "marketBids": "8G89DZWJEtn3b1XC78GJ3zQ8DCGajUMjJ87vvNfs7kNJ", - "marketAsks": "Fmj27LMJXr9pwUm3HrioyusW8R7zQ4jwav4SDCnUF5q7", - "marketEventQueue": "7RaxQzfYFS99rA9P62fJmJsBLEuAxiZkyLkpaPfHXHEx" - }, - { - "id": "7oVdsSj8PBWbTP13VYGu4KfKWxEaj38eFkzS8DA2FGaZ", - "baseMint": "5XiE2JApnDwGc24PSY7y7stD4JxStkYPAH5tFVKAcrow", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CsVBxssMWkxzdSPKaEeHQ4HVyaXePsFH5jfnQypBeTSU", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5egGc7nicKEbtcfUvZJjgYxuDBDiszSp4Q5Vdh6VhKYR", - "targetOrders": "AHvoHdv95gi3fqX37AzzKJ5WdmvRmLDpPr2GDkhSnC2B", - "baseVault": "8oe5GEgnz4EQwgX6cZKF7Lywyr981QJ37gHQ4mjYjtbP", - "quoteVault": "GyR9PV7c5tgiuMS5GvFh4ZzfF7dwCaAVWaBvfjzKrQjt", - "withdrawQueue": "BXsXiXb7CoCmwoQz3kGbHAYjqnpg2iQiBP9wNtYEczLu", - "lpVault": "9Giq3iHxw1Q1XwShSctg5Uf7HDqFF5DXFXScAS3MT3f9", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9WqztjZTc1R5UcjZaagNR5ViFzzQarXnprVbYbar8PTN", - "marketAuthority": "FFWpzELt7d7whyh2bESFQav6ooWPyXBXPvr7GRB9yruB", - "marketBaseVault": "3HEQbAuN25EbgonQEBTvsu9oJz9RvGR5SeoGRazxGjG1", - "marketQuoteVault": "GPtcAmnLdtvU3tFjoRkmC4YZaj8p7mzGNaXYmqvesXiT", - "marketBids": "D4fdMrUWgWyuKQn3hizgWrJXAMbTuYxeGxDsbqRwLjw7", - "marketAsks": "26Ff36SK5ryinp5vptH5NoTgpkcCMHMcPTkVf33Ua6dZ", - "marketEventQueue": "83kvsoZXNQP6wnmYrLHKvW8aNZX6YjmUXkFWttJfHjcA" - }, - { - "id": "7PAks2ozsZCeKyf3ayPVbZjqvAoP4CqCxhUFS65gWdks", - "baseMint": "vqU8NVkkgpFtt3YECwuQRD3RhX7LYaqZKrotZbdiBJn", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "H2pxEkFTBNYNw5jnYtvwkoVXCrASw5xxNGRLu356wyiz", - "baseDecimals": 3, - "quoteDecimals": 9, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6MP4wGSZS7EFjL21WZMpsBDxrBxDVaK5Nkc6o1Xppsrw", - "targetOrders": "HG26neZBq7kE6ggm7cTXMn72rZes7bo2efrzai3MRDAU", - "baseVault": "8mHhpuCs4dMU6EfuzR3WX3dhPgo4wXCLooKSDydY9jhT", - "quoteVault": "3J751hceMu51RW8Zxdi6RXm6E2kFf21AXk3pELdaehC9", - "withdrawQueue": "Ck6p8z1SMB5P31SNWa8LQP6oanNoMGkmmygmpndJ3rpt", - "lpVault": "CZRrCdzqTEmg2jKeCob3ThuFtxjp72NNPmVLWzLJX71m", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9d1xsd5DDfzWwEEy4aXRv9LGjPeBoZi7WySqqtqsc51K", - "marketAuthority": "6Bb5YQjbQxVykQEjjNb7iF8uV1JD5dUfSDD6W7JD3p5z", - "marketBaseVault": "2CiRJvp5xF1drsrvGpopPesgq29auYRsX4Fcdrfzg9qv", - "marketQuoteVault": "2AFKs2X5fsiwdua5SpxmycqRR4bRcRQns6bkzwwTMTj9", - "marketBids": "5Yh3r8U6wjw82r9xpr3qij9P6KivCwsQywMGPoNHbvWn", - "marketAsks": "6zDJQ6t5PGLXLriZwHrg6kKBWEqm3vkeVH8EqK4NQM6m", - "marketEventQueue": "FQEiR5FqV9nHPLF2ue3V89jsQRbJLcmRAYqwaZwGqSP4" - }, - { - "id": "7QGmBwN7BYpVPXnzJnDeQ1KcvSYZ8joUHpMYP2kCeCfi", - "baseMint": "GXnw9YSt6DANCt84Ti6ZpbaXvrvuEJFCYqrDjygnq4R8", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5MbViKEBZAD1LFnCXZZ8mGP6aGKuwAt8siVQEX1GL9bd", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4XKkkLhYu8Lw1fDT7NZB2GTMeB4iuWovK8Kb3b9XYMS5", - "targetOrders": "2i3wUfoP85ZUEwEvbVZw1F7eaRG3HAiXcVFLDpZ2vNj4", - "baseVault": "8dkmBxRve9myhFnZGGTL9vth9vaydNovhoZ5aFAzWPNR", - "quoteVault": "A6vxibr2M5dB5ZMgG5DV3ASV664zziHVssKpmZyu9CRH", - "withdrawQueue": "Duiy4fsK73rL8bDk12gQb7wRBVT94aYwkgCvZZknwreA", - "lpVault": "4qsVWqRwZrVX9wbTw1SJBxZSJNmNFYNzBsr9AEdFgiyp", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "H3766n3qrTDXNXAqkAbmr9x2Mnw6ujbQv9F3x2BMgvVd", - "marketAuthority": "CmGhdkdT8yKgBSgKMWdztpTxQzANASpKmin9D14pxoeX", - "marketBaseVault": "4kGNKRYLaBWrixZX2Tc4Pgf57gQPESM43w3XUPVtGxnH", - "marketQuoteVault": "ETw2FnEqcgd45UZCCNRJFh5PRZc3qFEXWJVLppUYEsN9", - "marketBids": "DBgnLWdoi8x6tJwWqaV6Sy5jZPDkzSVfZtGvoWruQCtr", - "marketAsks": "J1SfqcynR6yqjFMRMKavgrxrRwuUQ74KyuPDQG2S4rmW", - "marketEventQueue": "2MGR66Q58N7mfZPfXZZupfhmBCGqNBZzmeivZSa1nyQ4" - }, - { - "id": "7QL8ptuDZPS5txU2qdLbFfsM25y8QTtjmTgpCNbFJU21", - "baseMint": "DubwWZNWiNGMMeeQHPnMATNj77YZPZSAz2WVR5WjLJqz", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "533twDWZxCEAN1PsGEz1jgkAkG77HAVEfev34gtrbci2", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5nPNrJpScVJ1fM79ntzSHj52GyBUNAnH5vYc6vZjpTAU", - "targetOrders": "B6AwjP4hL95dDzTxXEdTj711SxZAHiRB63PiqoSBTHzm", - "baseVault": "2AhKxrcPWz1KsGUNH3Tott571VTPaHfepRkHq4sQYjR7", - "quoteVault": "8XkHX6QVRD9MaEfF9MiykPqA8W6cBurDALvhczf4BXtJ", - "withdrawQueue": "7eobNuk9SgQ1DRxR8C13FeFFYpT29KThVunqK28sXkvJ", - "lpVault": "L5VasVunjhhiqrASadCjPS1HmPJ25i5EZVHCQPBhh8S", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CtbVdocm73bgh1dSQQefZGQyVFe3wPxzmoAMLwgc113b", - "marketAuthority": "5Rv69hChz8ZRfCn29umsd4A8p3s3q2z7gf3z673WGBuU", - "marketBaseVault": "xf7zLQT4gzTiY6vCWqZPGvmgaVzMiNhYPDmijL3nUsp", - "marketQuoteVault": "Cj4FHpvFkjH2QgSRAkkSkTyCFxoK2eA4qAdBaaNMCNKz", - "marketBids": "4vCZTaZZLPjzwQFSV26xRq4z8WtwZsyG56sxWMLMyyXU", - "marketAsks": "7ezdwcr8kHv73532FPkxwnCpwy6KGjm6g4e3ERfvPn7i", - "marketEventQueue": "HWLy64cfkF8igvReEfBPG1SgHPNLTvDSsoJe9vAavKy6" - }, - { - "id": "7QSFMdfnk2hzu1N3XGsfxeBayGXwyZWf3VRbe1Yr1Acm", - "baseMint": "5xaYX8HKM8bsRwRk4WjCvku8eQAmB3jzJohn3BRa7Sg4", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6USxD39rokkEc1WoCnfiJJD9r7fZikwveyaEjCT6ekwd", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CuGxutfYtWiwuudQdfgYuixGVhX37NJomhE5qEjj3dKG", - "targetOrders": "4rG1447ktMyx9KVUMNrWRkYKq4UiDXsmufbHPN5pYkcK", - "baseVault": "7sTF5u2EcJG6L3XAKZeFJc8q3vUJQCTBfPY1EdKrnfDZ", - "quoteVault": "8faqvUao1dgJ2neyoW6EMkEoMy82a9EvH3FMYufQPn1m", - "withdrawQueue": "A6sBDGnfR9uLmUekqxYF8tP239NqQdaja7mF9WUTAiiG", - "lpVault": "4e1xZQarHWLRMGmBFDa3jL8cmwSuBS79fP7KfEoRNTp8", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2sT2YP2R5T4odmJKiY6Koyyui4mtKxzDh96VETcYnERK", - "marketAuthority": "BQikad6V6F6r5RUad58BJPCzvpGhjib5HoYJWjm2bcku", - "marketBaseVault": "7cQrTWyHHxWDXnDRLaEHGZVKLD9p4BhwK9pn22AMtC4E", - "marketQuoteVault": "9qFEBKZvkzuDZFe9byfdn16rZngmGWQ51SytSexE9GB7", - "marketBids": "F5eJeW6CHkL8Qsu7zLCyXP4uQ2fh7GuPsgrSXuvP2X54", - "marketAsks": "Bvs9818ZCqUtFTCDnVGUuoDHbtd2kXiBYckQbrTQv1nr", - "marketEventQueue": "HyfNZtojx1qVrAiPK3yGfvryo5aCLWbeEYnEGZSUc8N4" - }, - { - "id": "7rcSNYJpiY4aD3czgev8iwD2rpw9584W5Jp6uBC6UVMu", - "baseMint": "DXq8js1uxGNENn97SdtBhRDQ2TMETDxHsRabJPjVh2Q4", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7iVa1mWMhqTHHdKmtzaNZo3rGtAqqDLksG1hcCsmSMA2", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ENZKQkc6PZTze2rYQDxBnKWpEao8wSHigFeNeUJ2wHKe", - "targetOrders": "Gib29o6dBcJpZMRdMBePBwDEg9LDr8PHYxwfdYccW7pY", - "baseVault": "2WYu93e5P2QMhtLyHc3UBLwmehYC6esdb7TSfcpUmADW", - "quoteVault": "S14B8S1PMeK7i5RNna6S6KdGTUvto5SszoTi33DuRxM", - "withdrawQueue": "DMbHjVEZR7jEuKAFQ5CTtdCHpoMjjPob93JuhoyBJmAh", - "lpVault": "8NrsxVq4GkugoUakwN51VJsdvq7GFMQoFChLRhpw3xmt", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9eoC6ERBsRqCisJKmDdXwExtEuKqt7cUV9M56fqBxd9k", - "marketAuthority": "JDnXcY2h2N25iBsAuQisNEBBXMLoBecXJbj8ANoRQgCx", - "marketBaseVault": "EkXRRV9WuR9bGh6rquy63NWU8VJHS5UXwnkMmShrcirP", - "marketQuoteVault": "4thMEzjBQXHF9UFt3nJp84eSNw8H9SNcRxkryjocaCW9", - "marketBids": "EY7njQAhK5sHi64eNPdJY8DxhMHCkrDKDPD328YyFNtD", - "marketAsks": "HaWgL7Fjk17G2SY4P4vUtb8pPTG7rjQKhbZS8Gpbo7SS", - "marketEventQueue": "HSArWtR3v8aX3pbFSUWxFGVEraARs4dMfufWU3RkJ2UG" - }, - { - "id": "7SNkSWe5Ggj8PXan3UxHS1SeRSmM812dE6RxZ7TjSHH6", - "baseMint": "Ghj7ib4VJC592ybwpMK75vaX3fRu1SqtkXYMd2pNywtK", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6jeSdTbLzrgSpnATG38zQJLfEVwbrP8WXxzzgmsVpRFW", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7fPf26N1eCs4LbNqQq2TNpsB59AeWMQrjWtcKMdpyxWm", - "targetOrders": "ATp9dTk5aT6r3tYwLp9zTXXRuiH2EqseGgrPPbSohewn", - "baseVault": "CGYPnGf93GkGcEU5Y54yVckM5m4iBhCB1Jt9hcnCds8Z", - "quoteVault": "dUnFbTyCwM2SeeMSno6u6o59hLJMpPQWqw97sC9L295", - "withdrawQueue": "8QmaqpKFmbTVi6GuTourAu3iyP7AE4mVZRZu1RMzmDbz", - "lpVault": "BdzSnSpbDByv6KbkiYbC68HhoVHf74GBbEr5t4wuTVcE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9wmsybKvBWKatj7FxkYhauna6z4mcMDXQrjNvdy2kdgE", - "marketAuthority": "58L8ebTpfM4qxVwkwyAvd9GiM3wBXTqrDASDC7gdEg9a", - "marketBaseVault": "DqnKswN1NmLYUzNt9huwdRWEKPjmFDQj9NnwensX8krJ", - "marketQuoteVault": "4uB4FscuHdgbfGtM42MgJXMXVYcKx7CYmiU8DyUD4Q45", - "marketBids": "HsWoRthqfYSgXec8DGyFgAiJptQrxomZPmmkUZMgNDzf", - "marketAsks": "GoCRExvVZCooHiyBrYcSaq727d8TkM8UN3mAADMVELtz", - "marketEventQueue": "7xygL2LFLHjuEpPQfTt5sCiKosFwVXuU8u2xeQYguymW" - }, - { - "id": "7sPDo4E37dVwmFPU4Xba9YwzQHuEpYCsA9W4W9JkxBH8", - "baseMint": "EWS2ATMt5fQk89NWLJYNRmGaNoji8MhFZkUB4DiWCCcz", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Fjk75sATohxEFPNsNKn9VfV3c277gVZUdMQ94tYzrsyY", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9VwdsbBGkB7V2aBaGwcArKciuQUiM2ARtSZPSfTo3x2P", - "targetOrders": "DnG2KhjcNzFoxJVL3L4qRTxvgE9z6PNjeVaD6AkmFTfr", - "baseVault": "6H4TkDcHEWkyM2LVNkHdmBsZym4b7Hf5SYfq4HRMbtHR", - "quoteVault": "DmmSN7NH3FpKSkfNuE2MbbWPoW1uVrFdJDVtrCeuo5Wi", - "withdrawQueue": "LwtKAqyvWKcWufBzej1FzrCeoHEeDF4EgfMgBLTSF36", - "lpVault": "FT4YKMMHQryK59ubKZX8n5CuepW9EdQqMRudvaYEvn8J", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HchZzqewgC4pfsJU9uxFsrP4sLDqLsDntYRzE5RgrBak", - "marketAuthority": "68ebukwn1bqm8dTqduRyn4YipJWEFNTCkgMqCK2Mf4rK", - "marketBaseVault": "7jMC3ZYQtRQycDwSTVKxyXhvpoU5C1T4ENJoYNjWLJ6T", - "marketQuoteVault": "GjKZHWYCikFFMLUozYLzCnR5kJp61LqQkLPEtv5aJB4k", - "marketBids": "JAPtCSJgwnuPCMtHMWWnsmuHLiqxGiHnmUe2UYw3edRY", - "marketAsks": "ufLNV197ZaHDVX79ZTrMrEWy88AX4oC2msZkCfkRT2J", - "marketEventQueue": "3PRUbriFa4UD6tdY5CjwYUQvhyvUEMTHev2UMaWh5MPR" - }, - { - "id": "7sQyf63KyozfusTXHmbF2HStpLSMhXd8739ME3jahKXk", - "baseMint": "CFbdjaKonbBQTYG2GC6CmB7exofgDYGCDR8tp8KVGS7T", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BHg3gKGipkqMd4abG6nk35Aj6cDzvyW18S3ymhycTmgy", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4ibShWMgs3MYa4xpwiHjdKF7RPFKdxu6NsD2WdhcqTzn", - "targetOrders": "12g4Nk8pe56GVodVoMqdHNjCvdgbDPAJ8jLGYT5VuhgH", - "baseVault": "8ZiPDtLj8HSkbXTyosoBuTWK3w8rHax7ab3zMq4fSsNQ", - "quoteVault": "4e5uV2cKBpPXSK7LupVBMfgHv6dWmwVi6QQ5hpxBQJz6", - "withdrawQueue": "H4XS5njQ7MepC8ruwUf4pprfYSFTugULSMp3dy8YdJ5S", - "lpVault": "9qnUxkPsoaRCWDZseUCrKd21atCoaAE9PpvVF63y9fzn", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2mNbHja2Sy5TMSjKdD4qdrsXpqemoyCvpZaHkDctZa1N", - "marketAuthority": "2EqsYCxUCQTpjqtyq67iwAu5GLkU25HKgDA8RLHijSaA", - "marketBaseVault": "D5xX1FDjZ6wCYN3TMDEgguar31bpy2tszg8hPLU8rUwm", - "marketQuoteVault": "6Ez6GdSDKCbmDaxEf4yuq7TrWZhEk95p8VBUpFSNFvod", - "marketBids": "5w33NKop63gURa8Uc9msBhdak3WQFM4wavqAH1Wd1U29", - "marketAsks": "6R5N1EivqJ69YU96A8rnMerM6gNBZKJVQWps2htvS6fV", - "marketEventQueue": "GTR4xaxGBDAteJQDmhnRfLwmo5GEzPxqNy5Nnyj4x4wm" - }, - { - "id": "7TbGqz32RsuwXbXY7EyBCiAnMbJq1gm1wKmfjQjuwoyF", - "baseMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HqbxvyDnod2zTrhRJ5sSJn4CNnake6M9ksQjHxBcHBZj", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6XXvXS3meWqnftEMUgdY8hDWGJfrb8t22x2k1WyVYwhF", - "targetOrders": "AXY75qWM1t5X16FaeUovd9ZjL1W698cV843sDHV5EMqb", - "baseVault": "Enb9jGaKzgDBfEbbUN3Ytx2ZLoZuBhBpjVX6DULiRmvu", - "quoteVault": "HyyZpz1JUZjsfyiVSt3qz6E9PkwnBcyhUg4zKGthMNeH", - "withdrawQueue": "HaY8u9sVARFGegS5wrRigM5sH3uWGCfLfqiM4h4uDxbF", - "lpVault": "3TZm2bxE1W1zafxRwJG87v4c1N7DsKiEHk2xywCBi9vB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "marketAuthority": "FGBvMAu88q9d1Csz7ZECB5a2gbWwp6qicNxN2Mo7QhWG", - "marketBaseVault": "H61Y7xVnbWVXrQQx3EojTEqf3ogKVY5GfGjEn5ewyX7B", - "marketQuoteVault": "9FLih4qwFMjdqRAGmHeCxa64CgjP1GtcgKJgHHgz44ar", - "marketBids": "37m9QdvxmKRdjm3KKV2AjTiGcXMfWHQpVFnmhtb289yo", - "marketAsks": "AQKXXC29ybqL8DLeAVNt3ebpwMv8Sb4csberrP6Hz6o5", - "marketEventQueue": "9MgPMkdEHFX7DZaitSh6Crya3kCCr1As6JC75bm3mjuC" - }, - { - "id": "7uENrspgE6gmosoMra7GZ9jXePYqNE7fF8t7mKN5NxkU", - "baseMint": "8NGgmXzBzhsXz46pTC3ioSBxeE3w2EXpc741N3EQ8E6r", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Frq9PnrXbVhbFpMU3ZyXLZ16CNDnfBXV1NkJg2XTwaPG", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HHwWgx6fdKDj9WM5369kFJhr7aAXCG9rGLzgzJuJqqcV", - "targetOrders": "BBqh3iwGcC4z1BtuJEQwVWNSJVCMFc5FAqgb2LntqRHY", - "baseVault": "D42jZap4sQYzsX1RH1MHWpcUWNqRNRmkuXLS2LysxFVe", - "quoteVault": "EuHgCpbKVJA6QwVzfX7WEGcu6E7v3X2AymGk83n7fzh", - "withdrawQueue": "4pHk2uNCDAqme9ur3nNATLnBHwvPtuhRtX25qMovV3Ci", - "lpVault": "C4uStkkFkmdnwP113wVUMWaSEsxzjzurUddTrAsN9UzY", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3dFAa6MP8RToK7oLQEns1zzWLp7mEPLx4xrV7WTZ4WZW", - "marketAuthority": "DTxwwwfw8vqvYL7HNh6BaP9U6G5i9yspm8fVF1WH5AxR", - "marketBaseVault": "A5yVmm6XJy4JjCdRCetnugNkorHBPgPNZuBG4Pm5MLsy", - "marketQuoteVault": "HkNoMkLirWfpSBBSUt8Q8Q2GEfaXCZ1WYTyFWgRT9adq", - "marketBids": "7wsygy2QCiTUzELMCuJ3YBk4GhgZ8aCTgfhxbiUZgcAB", - "marketAsks": "GpWefEJX6pe8duUtwDc9dosfbX6LqwAEjZfq9zsdUWfG", - "marketEventQueue": "TWseaVY9b5nQPjVkU9faWfLCmPWJkqxmyAzjXSqVjiB" - }, - { - "id": "7uJZ9s5dzQ7zo576dtCTNsChTxMGR29FfW7BbpUrmy8", - "baseMint": "4rii94eJ9oh2rPNQY4y11gz4g7CtTfH9pULqFoCHFeCC", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "E6KFMcGHzv8ZDg28zW8ovAraZSGtu13j5keZ9Gqab2V", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HtbfZnkBDj6MRxrwiUYBjpPHeQSUp8qp1B6nbCouTAAp", - "targetOrders": "6jvNwRHZ7wn4RvKJpPWWTpqQUPfFtHMnPa6KPN8GB1pN", - "baseVault": "2jp1VzEvhwpwbHZz8QAr6DND6GBRQd55L2GameS1DwmS", - "quoteVault": "HXG9C2N5mUMVoCNZnEcY9W7TeHjg5pjNdVTVsuTgxnR4", - "withdrawQueue": "38QvBD7Ae73je1acZFattKcjmRpYtnGWX8dSJSmpbGdE", - "lpVault": "2W63yo6qS3JJh33PQEE6bNzbwxwXcPzd3yWMi4ycr5NZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9fTmwYxuXwQzPznaGbctKkKNbwxaDXTMMCS43LQTZy23", - "marketAuthority": "GEq9ShwMawb96Yrz9D4sEuMka84Tp7F2r6He7hRqGsRh", - "marketBaseVault": "BcprF1R94Ze8ZoPDfSb3ysuB6WbdMaW7h78ND4HqumtM", - "marketQuoteVault": "iHw9DyuWvo5qnWbLa5ezPhxFxgFfnwnN1muDN1W36RG", - "marketBids": "D7zTj891FDSSddrT5KPhRG8k1zgPoee4P8KSsCDjETjL", - "marketAsks": "H9tmfYwSYnuzrjMHbPKE9oAbLbGpcturVERbVpdZzjiW", - "marketEventQueue": "Bdv4vK8DqGYGwAqCEsfiqWVV6WUV5BLF24bm7tNjX3Jt" - }, - { - "id": "7Un6uzGXyiEHWU1U2ErvHsGtiN1ES9BN2yjShfnNChEg", - "baseMint": "HRBrRXGCrPro6TtryKQkLXuZqg3LdBMN9ZWx2v66pT4L", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "BJe6cY6Ak9A9xH5Cy2jAUW1QMHdxDvz4zGAZ8WovV6jR", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "97QYCQiLmEryV87iYGjfVywmLitr6BzPeTeMrWuGr13A", - "targetOrders": "2K8eeucyNsWQTDAa6d8oYv9tiJH5SckFyiRpKK5u2Wfg", - "baseVault": "HpWfXyGnB4FNbE9TgRC9p1SrMX5SMrRqywLijXmXBkGz", - "quoteVault": "4BQDMroXbZoqn334ojtPsLndnTqjqaFYzk3km32YkRQW", - "withdrawQueue": "487CTM9zJoYAmhZAux2ktrojMws4eUFYUtHLoNAhCnBX", - "lpVault": "8BQ2WaCQvAWQ97N9EFSzBmhj3uFun61tT6SFQjse2vRw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "J19tniL31wTzYMbGW1tbsKQ2cze8nATDJB3dSVgzV7vs", - "marketAuthority": "AwsumJ9pnsp5i9HxqCAmoXa1PXRUSVmFcYUesRXK4VAK", - "marketBaseVault": "CGQ48cqWXU2yJo9rWW2oHaEqLsNVEyUpEDjNF4MZ7GAu", - "marketQuoteVault": "5uBVf7QNhze52ALYSyFzSRViq2dXBDvW4MmqSrsFV2ER", - "marketBids": "7WoLdqE1g3GC4KbcpanfGLHpvrorL49Nu4F7riGTDJCL", - "marketAsks": "F9peXeHWe1uje1Jn9sPjQLhgsrgYQCPrzdb9FfbUyXeK", - "marketEventQueue": "rx4QhHhZteFLstDD2QdiXKx7yHwdQ3xy9UNeKGTqzMu" - }, - { - "id": "7UprzMfAufmgkhR7KgzVPnTu9PaTEfhKhasSvjFDty1d", - "baseMint": "EcFyPDjqpnyMvh1LhACtC6rrCZ41DMez7RZYocjhmUVS", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "AixUxKUqQvFRB7cvafhambapxh17PdvazqZXLEY5Q4mC", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CLbvzG6FAxw9gxhCGC5a7Rpjx9VB6Wru9qK9pQVHFS3J", - "targetOrders": "HiiiHRWgN1pvXEr1Kei7WhYmVA5aWCeHsy5kSjhdmYH7", - "baseVault": "DEAauQsjHCBT9VYbgpriKfgtkPANmNWV77mrBGo6CmHx", - "quoteVault": "9GvsJs8mpdJoB3BqoQsWgYYVXrfbxaxXhT1JN26XbKbs", - "withdrawQueue": "BUjq8icWoyE6cLefy7fCpu6Xx4coc29PQw22GLq6z94i", - "lpVault": "GArTrFB8gqUuaV7jTBhNujUoPaiPtp2L2quYPEkS9RVf", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9GgM6YwhdzmoY4VtVsrS3jcCx2NSRraCX1EPGvezukAz", - "marketAuthority": "LZkMqSkH3Kf3N2FSAZJyqJ8Qavo2CVGMBSrcBwSUhTG", - "marketBaseVault": "3YWTMhU5J3CW8P83WPNBCzjV68HqHLZFaeakTeww9sZv", - "marketQuoteVault": "B9Z4Kfj4vFue7RTSNKANsHd9w4m63ao5hbYGVmatTbuT", - "marketBids": "6wpM7M1maoPHFsB63ANg38DJZb1u6HDxeUkQaoDDN3fx", - "marketAsks": "DHHMx8gc71Siv6RQpsWbJhz6CAgc54Rd4QQNRYmPSV4q", - "marketEventQueue": "GCzjFLZuyJExudibHq5CkAnWoAEv7mf3JFzj4uDAcG4N" - }, - { - "id": "7UZhSpjtevrRoGtH6fuR6ykMJkW46gTmr5cu5BqAnBoP", - "baseMint": "JBK72yMfskz6tkaDCSM6bmaTf6ub7zDZUgBNxTWRAx8p", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "46CwHWQiCBaCzyYrHhaWKipJ62vgUuGtERpRcqoBvPXJ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CUESScRUJTHV4hrjZMYH7xqmKxEMeHX2mbGAWicFNWBA", - "targetOrders": "4SDab8T25TYoj52XL4ZnehfwgorhutoZ53D9siDtbWHC", - "baseVault": "6h8V9VVCEtXJKWjLuSib6bqWDutMj7PMFLiEY7mEDVZ4", - "quoteVault": "7JR9cVw6aENggxAqg9pbyr2xgn6Gw2Snx3Pta8UnJzrp", - "withdrawQueue": "7WmhbXiX4KUm3b7ncxmAZaFLKFAqJXgx1hQsY1VQfqUs", - "lpVault": "YNeohxhu1CC7Y6ovBpt8UJUfhWZy7JTrS6KpRMpUX8r", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FiJzMSWGzG5kwumYeYZNuRm9ByPj8mF1cFMeks5kRMhg", - "marketAuthority": "2BAptHEqucgjtsgSDxL6xL1CRzVyhwMnza9Fr41YjDn6", - "marketBaseVault": "85VSBDLNsSdao1n14gkF7CuAVe9sx7ggNuBz9H47936X", - "marketQuoteVault": "7fgQLcqdgaYAnGHRxhC3W5ReFjW2zcMcG7HKTyc5snrQ", - "marketBids": "3QGURcuy34yKnbBWZShQCCLA7x2fffSUKrpAUaXdQKBF", - "marketAsks": "5e2mDdMpuvZuP8oTUXWbfgQtHC697GmT1faAxxtre1T8", - "marketEventQueue": "Dkb7MRdKeF7xo9QdBNgyWUwrnr2UizFjrqg6NXmXnfva" - }, - { - "id": "7v83HLyxASMzsQVaQfNLoyobtxbhdEuvh5Fgbf3p7zhZ", - "baseMint": "Ct7mbdwLmdFC6zgVRXFidvvgYbtGo2icsntNSSgzxoLs", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "F6Lwhqfiz5oX13rZKyk5UA5xp6958Fe2mnEXqx35NcL5", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FsdEuHH87knWgdRE3KrEzm8bf1xts2x1ntUWx3ufovV4", - "targetOrders": "GLEEABQnr6Vre7gNYgHyYv4XuYGcd1UVPwwjPDdKTGzY", - "baseVault": "GUhpw2RL2kGYgNJQF96PCXLSUSsomsTLoewHNc7jqKqA", - "quoteVault": "5zvoyearSznDb6APpEDESHEun4H1KKTJgc8J4uEAzERs", - "withdrawQueue": "7XQJCPSEu6ZrTGxx8RgqCVwEbEoY51FzkHis2RySY1go", - "lpVault": "8RHrkRnnUoEmAhRFVu5gUBGPG8jrCWv27Z4bKnruZPkM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3GpGdWvyzy4z2bHAZ3jo4YPrZXueNPKyN3MAZrU9aNmM", - "marketAuthority": "EeDvbA9AoRUhvj9jC9JPnbgbX2WQkPAo2qdfjQqLVkqP", - "marketBaseVault": "4CGUw5XJZMgAhVCZQYmsmTw5rRzxcMCPtub2kZ3DW3iv", - "marketQuoteVault": "2h7BwXz9qqpZDw4KwWV7YEEY4vh1ZYeuB5VGKuhf3kky", - "marketBids": "3G5LTZ7AggeNbzkCCKkxK6rpsyRAixZ7vxYPLfDgm3N7", - "marketAsks": "4wVTJwHEpCqTRkTPWwktjQFQhLGx1vpJfks6TAzJWMLc", - "marketEventQueue": "FUuT9voRGK2uAYhz2uGas2iiUQGDpBPxteeWjjdBz6BE" - }, - { - "id": "7vAgfPC8xCKS5AzYbuKZXsPg2mAQJ74AKT8EoNJeSMt8", - "baseMint": "SLNAAQ8VT6DRDc3W9UPDjFyRt7u4mzh8Z4WYMDjJc35", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3YTPijv9hBRKdYy5X15JhbpgnPFodsZb3icJWU9XawNe", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9RhKrA8u4bWwbgcbVWa5xsdkzVPk8qxet3GXdyeQcdVx", - "targetOrders": "64uLFcPKcDxtQa5X84hJhuPX2w2Y2o7JK6bPiKwqbob6", - "baseVault": "vqvtQWcPqvqnpxrQZvkB5k1eUacbuqBxNfpCC7FiPup", - "quoteVault": "AqJtok45pXcFQzp5KoBXGd1RuYBBtavAp5fT5Z76uXx1", - "withdrawQueue": "Byca9p6KhRaiUwWVoYnXqR6cuDR8wkDEz7m1zJWFZw7U", - "lpVault": "GsFhDCoQAYQwADYVGpKteRpy3n89wXAjUwWX9mMziBjg", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AVSHNPjiTWoPwgT5dqnLpLGhQ1hbL66xNevjNm13ykWd", - "marketAuthority": "6h7cCHjmLhn4rgQXQhWmBUmoK3cjfcbP1WAZGysCwGNG", - "marketBaseVault": "ER1VHgaH1W3nhLbQcqXYCToqbHg6DRtnPbKUgiULBGz6", - "marketQuoteVault": "H9ffrb6W3R2DdJHdP6jYoJ58U1WXwjmuBgTEyGkbik9o", - "marketBids": "ApACGdzLMz9tkVKZ5BQbozRMdT7xh7uTDZPqD8BjruCS", - "marketAsks": "CWvUhHXtkAjdRApwBBnYfysz5CD4NLsd15gpXS1rx5Qf", - "marketEventQueue": "GsBvEQLFZxVhHfKvn53THLRKsWdkjLP7vLVV7tmPYDAx" - }, - { - "id": "7vcHzyG62UfqzKN7wN4L4B7e1kRKnbbeWPsn6QHedwFM", - "baseMint": "G1NChRwNJG8BJAPfRCzq7t1aH5UTjdytCEGBDbQHCYcE", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "JBvPjmENMpsJN1qYyJnDKu8KaEZs97gZMRRpQ7QmD8AP", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "cgqaowejcnfSYss4nfL8evei1ZMe7GeDUoQX2DRrELS", - "targetOrders": "h7c8g4UBVYssTmf5JXFmMinu7RdAYKVHy7sZcHF3nrt", - "baseVault": "8seKj5SfpbrpiiNQSsgwx2jhinZYuffbvh2giLZFJfKV", - "quoteVault": "5XtrGJHyC9h24orqhpXyrvxKsw8dXPYQErGMJS4Lb1WR", - "withdrawQueue": "7t2846gUNoSCcQjL2qB3XDz4CcmZTEHtSAQANkx8FZpE", - "lpVault": "Goco2sKLTZSyzSpowwNzfb5SjMCoLtjTW6fjphVvBEHP", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "F8AxERbKASKoDf6QNNtn1cyuu84ee1rW4HXHPV3yiSFR", - "marketAuthority": "s5fTXVS58c5JF5z3Ld3rjeThoc83DLsVPtkV3dDX61b", - "marketBaseVault": "HzxDckTUUAVDo3cbQ4nkySNsHXTToHTPzDNFdoMw3hwr", - "marketQuoteVault": "GkoYw5WgncAohJp2N4thxnjJGXvyMon9GFxaG7R8a8ia", - "marketBids": "Sg4GXJemHTnHy2fGiMYAS48R1Nqj59mDjb7cQ4Eqg9a", - "marketAsks": "3bMUcd4NNLJn9NgKH1SNNMhZWKwYvh2L8tXZzdMdUvM8", - "marketEventQueue": "E6oDsc62ziDQgGWDfGUkWuX7XiErLzDpgLQvwb56bLHe" - }, - { - "id": "7vdztMUduVQWvUcttZqpBguTtkDveteWt7oHHBEyt5PZ", - "baseMint": "25Vu6457o2gdZRGVVt5K8NbAvaP3esYaQNHbNDitVtw1", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "88ujhCPPwMtqi6fkkDhfbAuoUGLSUFFBHiJFywno8TVk", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9ocRA9NYH1ktQP2Xw5ikg6JCtDgZ7jujY5wcvU77xDPH", - "targetOrders": "2PGcfde2VMDVnfraq2oHYX6Dsaq7FrVrZ9XuSGjgGCHE", - "baseVault": "BY67qBmyZsvPzLo1cPayAQ6smCH1QZqHMEuQeqLAAesG", - "quoteVault": "F3MnZUMGihAiZHNk9UGY3jYWyjywPCmqBavmLep8TvPv", - "withdrawQueue": "G8b5uFbnqTfd6tXmUEgGeRvQKyzG4aMka2ek7mstARQs", - "lpVault": "66iW3342LAcP8J7cry4HfoLAs35BM13axY6qQjpb6EdV", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8GgBoTphoBifhwuybFguKevdjXTYGBLGcwpgG8cCewwk", - "marketAuthority": "DJumPAdT3rLLL7Ag43DLV882s31z9EDQQn1gYiL7Y3Bb", - "marketBaseVault": "9PKd3WdGbNA1LtberuvZryqEqkeDWWKqKmpn8Q8ybBko", - "marketQuoteVault": "HuVfjvcPvpnYTJSqDLx5eokoTjha7NyojrQoZWvyhtQ8", - "marketBids": "GjXRXnGSB5S1Y3PENkCDhjyHea2GBwxq6yiLFB3Y867w", - "marketAsks": "FpiAmNPHkM7HAzSCxyzuBZdekZcLoHGXvZspfbJ96tp8", - "marketEventQueue": "Ahisnb2yAkAB7YLz5whqgYsMEfmxHHJbcvQYAbSnbnRU" - }, - { - "id": "7vmiaZEsgaFND5ZcJVdMbwZVi5KJ46zowtY116wJXz8Y", - "baseMint": "J4tV8qjZyzwsYhGmPREDEyehCusPwa7uYm3UssQ6X4A8", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FoQJw5LVv3nJ1PV4G2DeFSBZoFBmNeYxw7MwcYHPd5Xa", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BtPwh5aUFQY6UNKZj2cpuUpD9a8JqioN61qhis8mqU6t", - "targetOrders": "BHpMS7Fdt3uq8qKVMiPCGKr8EFjL4XGAkHNjRWFPrvRx", - "baseVault": "74oaznphjUcFPQoE19wP9BoAQFrWctCjKiWjXf54XV9M", - "quoteVault": "HVLu3mkWyqaWfpbUQtMv2viCD7pg34JjZNBbU9LsLze", - "withdrawQueue": "4BkBSLp5xk9aFrriYwRWhbUB6RgCAaKUsDLN1JUkdRws", - "lpVault": "4Jd6tzJSHQJB1gt5pebfzdsyX9c6JzHbd75x4XKYUDqJ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AEgjQ1LCf7ymJ7mffDmsG8zCmvx9beoi2h3NB786VRMp", - "marketAuthority": "BrSoJU19qSqq8X9M3KZSjhxenkYN8xJBZeNT98gUCZ6h", - "marketBaseVault": "8vUvcsPUQBdChvUrXR2TbKaq7pEBDUptCJisYAg5QcSY", - "marketQuoteVault": "4x8CoBXtrG4H5gD9DqtWzYmDuLW1QAPKRrueR2Af8X5Q", - "marketBids": "7snpYzE1pTdSSnbrDr46eviH8sT5bb39YP3rCv2RiPmX", - "marketAsks": "8peWoyEcMgx1PdZYHAyKVuzC4jHY2AQX7bmEXBgYbPvW", - "marketEventQueue": "7yerGGPhmmtDpmLsQ3d3MoyYGQK9yFdicU36cp8fvTLc" - }, - { - "id": "7vN4L8DadKNnLyuLGYnVeZfaQTeVTFWgMNvZR6Z6n7GC", - "baseMint": "5gzW28JcKVkPsfRvmVoX7T38JoPDxi6EuyokbFtZjQ32", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Eti3WyaNMRqxWpEYnWqK3qywxVE3h8X4Ltw7d4ub7fr7", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BSo2qCNf6Uqw6qubRURD1kwssRug5WwEcE1R8cGdjcgs", - "targetOrders": "C93fgHcvj1ydhayDxGJJ2g6nuFYoximwRKrth9Qavrz5", - "baseVault": "2Z9kB7j4P9c6zfvP64N1Aosx44h6ALkdefXzizqtgBLs", - "quoteVault": "GCcKvZgAfc9YjzHv3Eb77DGhuuoasiA6zfPzmaEyxp1N", - "withdrawQueue": "94BkzBz9GwLudYTUtgwMBuW64Z8n6CRLVDcJYcQXrS5f", - "lpVault": "4eKK9NizAY9a7DgMH1diTDvcjkiWeeamaQFcnbHq3AHo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2MLjZU6sp6GCjfbuDJPtCkrMmpf11euiUouB3FTkPDEU", - "marketAuthority": "FgNDZCjiVaajh62ps3Szvy8E1Y1XokJqE2qDZ2gFrWhW", - "marketBaseVault": "D4EBzNv5eeCDuZKg4ULAdk18BsJov8qpMJRhC9abGHZZ", - "marketQuoteVault": "tqKG8NPzXGWLc87KkVu8aGqzpCKownL4BsbMFyDpr2v", - "marketBids": "AzFP2xTHbs6J1JJL8G5jU5BSKQ65LgMCNDLGp7KGer52", - "marketAsks": "4oHmQUpiqGU4uvFPdxkjoosW2izvbuq4xqEJC4NBtDeU", - "marketEventQueue": "A9jM5Nb1y3YCtjA58LMJiSmXgmz9ViCahVdkebRVJ1MW" - }, - { - "id": "7W1PCq3TPJMv3uwuPkcT3E5FL6Xbk8PBHPddfRMDC7g8", - "baseMint": "DjqVhVG8gQ58kBLbPjZ3R1FerTcThX5RZzcra6Fzwv2T", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Feo7AtSfw4mwjTGQbHahw6maTjMupYZ2He5JL1um53M2", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2HzeBmTeZc2MrdnuToW9vUxkDQdHdi39gTggUhwC2KEu", - "targetOrders": "9PDGKeozAUaYjqhRQnXwtuxtP8toeTpT8jGbiy882sRf", - "baseVault": "H6JfKkhav6Qkxxa2cv8iuRrePNUjdGmJhLgCLEtfniNH", - "quoteVault": "3Nk4ZhjxF6J6KoxuGWSbEzeutdqN9a1nSai6DCR6HMVv", - "withdrawQueue": "ELJXY4yEW8ZzZbBbuaDTq8gUoDR4PWgSZZZusHcVG66W", - "lpVault": "2Liv2M3yyWH4BtNGbVAHjgJTpsaZc1Aq7R9JANLTqvQm", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HC8roVaiakoq97bHmBXa4jJiDtamYngpgiSGPPmpkayZ", - "marketAuthority": "G3e6rbHzeYeAi7Ky14fcyrr2g62SqhKcDABqu31C9EWz", - "marketBaseVault": "4DbTuZ7tfffq4Amm5br2bbm9ZFJD2qtckyYq77NUkNUs", - "marketQuoteVault": "cqChukXrUEtumwHLsZrCQ6QCcbhm83BWopyf1e1kHvp", - "marketBids": "6Cs9UiEbrog1ExVQ64fgY2JG6vUP1TnGoZ2kYrnA5dff", - "marketAsks": "HMzepKjnVmxVU7VPMhPzKTLHscFKeErbbgPn5KBXaHS2", - "marketEventQueue": "B8YdNSD6R5NFGrL3sixLCpS1YGThNGghaH6mA6ANjAib" - }, - { - "id": "7WAUQFnX5gebykQhsFRxbJYx1w3MZGczFfG7Wn78UJbe", - "baseMint": "ToTuLunrMF2eQtvj7p6UtU7Jc38mbZZ8do21fg61Qg6", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "E4PfJMPnXBDwLC1jwADCnnLwCZhvkixfZYSAcvWYd1ZK", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AY36civdf3YyaRc3asQXsvLyRvmVmtdBLqUUFUj2BZWS", - "targetOrders": "9qrsss1EYp8MNQ6LjjdCUdGe7VkrjxxYdruucrXPeYTG", - "baseVault": "BPT8NN4C3biRUWGBCjTBUj28LWPzDY5dox19CyybFmvk", - "quoteVault": "CoajhFur6FVT9XaHwFtXYYR5GX5yrt2pcGmpUE77Nfou", - "withdrawQueue": "CijB9QKYGEmCXzW3uER2zHJTSLyatkQasDpQ1t4Lue6F", - "lpVault": "9piJKQvaprmXQJ7XvQkw7yCqS2757xzAmoLMZvgSJuTc", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GupLN8uN1kq7p6Y6w1gNGkK1bA75FFvNbA6WnRaumfcz", - "marketAuthority": "Ga6pSsAq8uDsDXaoR8qvQxd3uRtXXdukyYx562SSqUi6", - "marketBaseVault": "5819aG3yN5HY1stnGnoFCwghgkgZxR99fzD454YsD1Nf", - "marketQuoteVault": "C4wVoaXb23j6kFUtad7VRe5xpJ1BS6erqt6buJHwBa3", - "marketBids": "H1RniPqtMjoJMsmdbwugree7qeDrZApPViM6vD3LCg4U", - "marketAsks": "E3jwkqCmGNZXuzQbY5kzLUKySa7yAM1VqEJuS8Q5fwSV", - "marketEventQueue": "AJ7oXKCvpByZNZLeNb2iYrCoufhTK4aY1sAVSnCTVyfM" - }, - { - "id": "7Yi2wX5KKambg2vdjLDcfduZfuE2dWxAEnSASmN5diM4", - "baseMint": "BxHJqGtC629c55swCqWXFGA2rRF1igbbTmh22H8ePUWG", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "FXsXhB6iXBcCEDpFMyExnZENYBBMPpQSdCspbv489jN", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "99yofYVJD4HVzKnS5aPhmCRVZmc3nHZd4MTLgtuKd5hU", - "targetOrders": "AsaSqkavNt41qhUYNJwRyY48rePAQXnR4v7AuaxJfgQ4", - "baseVault": "epwGJ5XGzaAD7GgqezoET7HiLdBwFfMrKAW8NYSDaYV", - "quoteVault": "2fT2KzgwAWuGwRANZrWf3vwrW35qnzQF2NBvf3gRu3c6", - "withdrawQueue": "2en2Gch9DGK8AXf6sA4Bqhe7WWrBNzhU5cXVxiztq8oC", - "lpVault": "HZfE6PvQUBDZRniLk12MAVXwDbPTaEkebD6hCdqcpDzd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Co7HmUYCzchjnBtbdVLPxaXKWcGVvpq3QrxaDhceJBrN", - "marketAuthority": "CvhNj2gFgd9sMKab15GCYjSEMuUNtdV1vDdPmsgaowfu", - "marketBaseVault": "3nt8RBNPWKbvDtZtp9TmH6KNjwqnFkrwLbGD4o2vurUZ", - "marketQuoteVault": "AFn65jxZp8xsdS62Qa9GStaHh8ZPJV4YEf5iZJrbzj4u", - "marketBids": "8houodqHpTGUx1HmFvkZeiADc9JZwkTQc2QTBATCAfjh", - "marketAsks": "9EkNcjJ8uBQBwNc7s76eGZheXCNEpz4XVay9Fsnrpz8N", - "marketEventQueue": "7Rg8fMMADbQmGq82cgNBc8XQi7sdEd3xMUAj4RNhEsVf" - }, - { - "id": "7YJBAvEcwkDDQWsiPb1ti4pwAweWFqYMdztaYfZxK1ua", - "baseMint": "8yQuj5v4s72UqZi3sYZL5rAD4NPV4ueUwBKzChBDWMVf", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3vL1tzVQHrHEisN13yZraUCYdcYwZbTQSmnjmxJL2E39", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6ySvSzCATyP5HvRQVdpi63Ukfd5Z5185hhUtnAorU9R6", - "targetOrders": "7aYPNcBqej36yLxycuXxmiwgBcCNMnig8chh26iF9qDV", - "baseVault": "HdgBowageJRVtB7hQWzMp7bpBKYH58hF5R1VjnW8kt3s", - "quoteVault": "BzqSmvzNnjB1fShr7sxsMyKmz4NGhACStJkJpw5Z1zzp", - "withdrawQueue": "6TdR67HdEkVjXVcJZcDjYU7MCb8nYAioqJabhqx2zXij", - "lpVault": "HerhdU3v6g9KkvXhn5JhgxSbgQPzopCDDPziJ1sUBK5n", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "D7yyZQuX1NiNHQcPTSNuBTYGCgoHwfXyTeiVoFky8Vzt", - "marketAuthority": "cQU7yX5WRMswHiVom41piyAWKvnjicjjv11zojgoMNy", - "marketBaseVault": "5nyegi3g6yET8QU91ULer4Kh2LYrX4GhLpmHh5TFvggA", - "marketQuoteVault": "C4sbCVaHHmVfgujWsjN9Fn8PiuHDYevUV8Tvacbc82jJ", - "marketBids": "TKs1nBNc8tg1eQgG5KC5yXD8mm2KfeRgaGWrLEksHcP", - "marketAsks": "7hrCMweR81gKJzJ1vPXoR8ibYKszhUG7EkJJLPzNJ15E", - "marketEventQueue": "2M54D4n8DaxU1ynVyXkLSYa6pgvEFnNkzuug2CCaHKj6" - }, - { - "id": "7yLNwsE1mUcLXLSEHkk8RBfwTcw8VmqzQWKDfZxU3UbM", - "baseMint": "HRyyRN2GY4yxrxCx5bekuEEKvFqztr42eVRY5UdkYWGf", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8WWHgAZfkTVsLPrgShER4mJJbYdPcfKer9G4VnqKhFp2", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2CxJqXpKxZ1obeaqn1en7BFPaBYi2GKJWjy6WrmGJnmN", - "targetOrders": "J5WZo6gWGhmxbjb3xZbFLJotU3sGVq1U1hkNhYfU7Q5z", - "baseVault": "62ndZ9Gu8ShYvWHPBJLApsH9KL8WcEjUDpquxLMdWivp", - "quoteVault": "6Go6Z5LYTgWkVpSjvBryvVFs9Z98VMMzodg9n7bUFoY3", - "withdrawQueue": "41xiCbNVD7yXkz7BhbkDip6kvDwMLcLumm2ASpmtbka4", - "lpVault": "DcAKM6ByuWV8MaZwJz8m6J4cEpgmHz1ps83gVQQhuW2L", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8LjiZqCNQfD27jwR85mUQpYdt7JfocNT22iWJUEeqBsH", - "marketAuthority": "56oSnktW6w6sXtjxvP7aaz6q3ehANEHoB2HCCUo1pT7h", - "marketBaseVault": "8JT6VwMc2bH834WrtjWsbApMkTpRwxupAbeRmcMxcr9v", - "marketQuoteVault": "fpPuw1CatAvrBggHAnNxGE1gUrcVtjSUmegN8mGmnJ6", - "marketBids": "FkgBzQnRtoEHgNvL6zATLSxwaEMoFPLxosS4u4jJS4uJ", - "marketAsks": "Hqrb9vkq3EnxiUVboVjVWNFLTD5YXRuSy6p6RywtWUUG", - "marketEventQueue": "8WhACoXfK3vmPfPgzor3Giv8o9DJKw4Q7gmdwPPRCrrz" - }, - { - "id": "7YTZdaMQwjurQRZCqK7kigmu6YJhPHTBbBUQoC4T5JRt", - "baseMint": "7z1eQmEhhM9e1AVCBQc6BzMZWmCZRqHCLJtkDgHxzYnQ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HoaAwsJGpfMVzXZ3EFuoULZ84sqBGx6HMWWHTgJyidyC", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "t2dSTzncqMnksqEeE8UxtP97TaNkB977DNmTrbnFz3K", - "targetOrders": "4RToA3WTESDKrRx3aEtc8Heneox7CSkzVfKAfPMAPhQU", - "baseVault": "2jcE1m5VsMggvMde2UGgSL3uY457rmRj6bYp8VkccQva", - "quoteVault": "6S3oPfRqiuSnDExNqPocpBFCGBTiLecaKLLcNgqmR3oD", - "withdrawQueue": "MeX47TzmEMZQFcXFXvrKo7n3vZEArxk8TnxYdtPP3DB", - "lpVault": "9McrLUuUgw6q5Aw884f7562VnQHwUsJkZYSML912sk3W", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CZ2zpiJotSKAzAjUUfAVdtEX8SvbRnUDPnUicj1FEBHr", - "marketAuthority": "Be7Bv1DKjx2NMvLHY3Auy3Yr269iq8JAy9VTNqdgCAXs", - "marketBaseVault": "9VDjonnd6ynYBneqzSDFR5q2rxRbF5gL94n3zw8NJ8Ru", - "marketQuoteVault": "81qBj6BaVTcXxyhG4WL3cwxpAgiY6k6pNuGLFJwpMuX3", - "marketBids": "3ewPLoh2csEyTo7RuBhJ1e9iQFuNHY3nep2GY1e98DbH", - "marketAsks": "5BzLmoyBNxNZeC1foaFCqdU5Tzk2YTBEt8GmYS7oyW98", - "marketEventQueue": "55KLeP6hbf5gb1nXdsUnsJMtgY7bFY19owkfwPEZTFaQ" - }, - { - "id": "7YUwwt27j3PeRaBpNhodrzcfV7GUT6AsBk6aGAycYECE", - "baseMint": "3vXYrqQkKpebReDPUaD1CseA3cWiqfxgPuKTe5aGL17U", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HEynR3MsxoRVgSt2RisofyzY639LrSKSnN4sNUdWegQg", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "C5zW7BYFcPpVfb4pscz8ZZWqGi4811mCVg4TmneYoxfJ", - "targetOrders": "6KSBndN2FtDAnnCnG4bt2qfBUYbcd51ELFeFmLEMB3Mv", - "baseVault": "EEqFLCWiN8a78RsXeyv5jgimne8HvXTeQb9EJ8atPwVq", - "quoteVault": "7KeFBFTHLP3GmsbMRHDGtL35ZexMMpWxr5YXskuNGi69", - "withdrawQueue": "qeK9rmpfmucmy5zGyfBb1FkJ2DiRuwJRWD7CJwtHm5d", - "lpVault": "CjCsrLPZaeHE6SR6T2PBsDXgDtDuiJxb2w2ijUAG8mQA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9BnST8GeTdj4t6m2eUDUZ6hHawe8FYcuPJLQfwaN6X6c", - "marketAuthority": "HE14HZEKoTGxa6Y4j5ZXdsY2yGjcfigHMLL4Fy26suUv", - "marketBaseVault": "8it8sQyGzvTHa9hr3tzwhTR294L8pUSDLZr3TxDc25pB", - "marketQuoteVault": "29h3Dn4tcTLLCsfZjt8hSGHFsDmo4wgoSCJBwgShV7FC", - "marketBids": "HAoZfwCMAq8kYDDro2sAJKKfa1TkC5gkcj6svFK6qGBe", - "marketAsks": "5V9JywC1Z343ETQoqKFpcugmkigDXogXxhy9Jy6K2Ncn", - "marketEventQueue": "GmEowkvx94nGRDgTqkoxSGP5Dod9Eoa2PbNqYDH72cTu" - }, - { - "id": "7ZgaLbVxdZLXd8Ksz6yNb2RA87G1oVPLUvrEqXwKupmw", - "baseMint": "HMKSrb4Nb894wEmwYveACs3y7wHy7TKzf3kqPeiHjaqa", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6TkKz5JLQ4ZSdy3SRDpgHYB6QAxCUThHcN88VCzdJSrA", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4E3CZwxBKkZ8RjUu8St5r3AAL1UwLEiVjNBtvEYwT2PZ", - "targetOrders": "seMk3dwe4sRSiP1iY4KhRPppTH9fZ55wMBdZ9NXAwFE", - "baseVault": "5Lbb9pqjM1GjJGu8CckuSWXMqJ6W7GMwGCC114Vu8T8K", - "quoteVault": "8J3DRzFBmErxXAMKFmtUrh6FTCqxMqGRASECMgq8EwLE", - "withdrawQueue": "7L1YZHHjTs81iFgJHXkqprGQeBxgqGd4WD2iBeTiZwWb", - "lpVault": "7Uvm5T6CmkRCb8ziDaB8yh4mVhyWrR1jboMPmZPoYtua", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ygyALjhjNBA4kPhyhX9DvjdTEhd8yueYQJptabovor8", - "marketAuthority": "5QXGngYHUzxwDg6gWs5CqKmSiWubwTDK7QSBPNdiSwDe", - "marketBaseVault": "CZVKL9o1o94K8ZhvTKQGgyBGZxByYsRuNQLAZkqFnmLq", - "marketQuoteVault": "4enJmCY72R9SgvvHYaJSyNW9dcDvCkD5pUhAq1qJSELc", - "marketBids": "5VNZFw5cBpoSHuN5Xd11csJHKkGt5op52BZf7BZLmZKc", - "marketAsks": "q6hLw1wFxxC2WRjKLYRKpf26VAUPYThz784oVsuyd2d", - "marketEventQueue": "EQJFSTVRDEbgQDWGvHPaqFs39nFKMivQoC2nropLBjyL" - }, - { - "id": "7ZjauxhjBEPjU8AZwwWZkmCCCJnmVPNV6yzAK1W91rcu", - "baseMint": "LUVumGBdVkaPYbGyjjRJtsbYoVtZ1h7AaX1Hh2bcaqn", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GL14bAA4sCYr4SqPAeBMZ7RTX7sJoduUsoLJv5VVGdk", - "baseDecimals": 10, - "quoteDecimals": 6, - "lpDecimals": 10, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FnpPk8Munvte3E4CHvPRZWE7DH5xuoSDmYFajZ6DdQeW", - "targetOrders": "3EGTHu66pPkimMR4kJFeraVtngsvLR4Ni8VQhSEgzoTi", - "baseVault": "J2bcYkTq7vNYuZxkjrT9azyBQEFJ15dAwQZAMfx6yqqi", - "quoteVault": "F1jyyY9Nj5t6jgRHQ4Sr8ycMug66ZKyUi3G2dNEZ7etJ", - "withdrawQueue": "5HRLgLWjjv6ph7hFZHKsWb96CpdFrf6XicfAE4zNPLM5", - "lpVault": "Ab1G3RJk3AAB65QBBwA7DSvVFDaMwCCJULRwEChrpGF7", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "36JH12tmyRiXijVfUAc756p7GU2qWthhdDZmakcRYP8a", - "marketAuthority": "FaHzBCTKc7Aw2iPdvxVWwmPLvyQBrcv7TWmtukibGqwD", - "marketBaseVault": "ABvcD52L7r1jUy1FnXSEQao91pmQ2G9gtps5wWXi1sdE", - "marketQuoteVault": "Hh3HCXZUu73ayQUg4YvqbEFpj4GptB4aTSYnkg6YXQbo", - "marketBids": "Bz78KdK81e7iqBiUXjN4PXjXxnzpG2PLYj6UFKCwxKkn", - "marketAsks": "3daE8hysR2UZnrwuBmzHu7e1zzSpgjcNuq9cqeGy1ED2", - "marketEventQueue": "4GMA5aqQ5gUJmuVGChDeawLnFKizzEAzv6unmVvaHdWb" - }, - { - "id": "7zT5PtrhsaZvocjebSAF84Dx2NtJVh2nYWK1RgQzGeNv", - "baseMint": "ArhMyF2N8XpaujYUxTTDt9EuaBCaGaccxfwaZmkm9XeF", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "4DAJuTcvY7WHoGmYKHLHF7qTiqrG5ve168MEXcBad7Ci", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5r7y118prxMh1ENkT4Dfb8sgtkGYYxXfETCU6jH9yCUu", - "targetOrders": "AA1YruJShpiF1Tr3ANj3fjPTjcXCeJWG9ZqBsUrB5vUb", - "baseVault": "GMPm9G2PSUN92Za25eD8DvjFTEyAXqxKUfLfZEuKDFN2", - "quoteVault": "7mhWC33hwV6Qf2gq8VQapEZpniC7XLNG6CfzGmnTpiBJ", - "withdrawQueue": "8E9FmzMinXd9heLEyW84akq4cHD2AeC9hog3t6iGjQP2", - "lpVault": "6pqnA8DRSpBx5T11aCdAYMUsbEPrA1wiwTxYvrNLCcbV", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Hm5XdwsGfK8Xhq9RA5NfyfTNBfs975mdTNnbPrZPiCw", - "marketAuthority": "BVaDFNgCNBmT2xZCxBazJohnseYrMqWckGNpN587YFqp", - "marketBaseVault": "BVR5ahBybxRri29cjB8xoSB5H1oUxRgSwUPxaJDcCxjS", - "marketQuoteVault": "4t9uujDb5L3TLJJY6ehDjGQJjDiJcKV2e9LBCFNUPFxb", - "marketBids": "2QGYdjDSH1DtyNhjDJbsxGvsoa85ToD5VRhWxybapq7f", - "marketAsks": "82ewKxv5xfyx3NrCEmNzKvTJ7uHTsPajJsC1EWEWVU3Q", - "marketEventQueue": "FJjjsfSWdFNvTv5coNW2myszYMn1sBf4MxJ6cUWmwQXQ" - }, - { - "id": "81AosjyZUjGVYf7x28Zctppre94iufdPzWDPZ5P1Fbz6", - "baseMint": "C5quBbSnDjLpdVuCQnJF38Uw3arfmHUNCPGPDR2L8cyh", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GHX6YwT5LSspbhVpjKLBCZU8b65FasroH5MSAmZ81DJY", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HaP1h13PW6UCbsPYvg8aiTuP2EPK1Ptmm4ZgAbgiGRr2", - "targetOrders": "5hho12iLFAmQJPbZcwFHMeChK6Z62pcyWBmqP9BcF7Je", - "baseVault": "Cw5TQVQ75v7Thy5iECPSZEVySpZhKMn5TQThKj21ZRWh", - "quoteVault": "AdnNXJhTB44BRe1eAtr2dVNr6UD4xQg8tFqniEikSL2P", - "withdrawQueue": "47Zv4wS7g2WsH9DrLg5k7t1Dobma7fhDc9Dh65SHmpzD", - "lpVault": "88W24f3Jb9gJzavfM5Sm3mXRFcBQGkCrAYSHEhWTiJGp", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9yVmA798H7EbGwfoFnwoAwRe6eDENZfphUU5aExtCLYg", - "marketAuthority": "FEdnPb1UzqDXCZhsEJF58SXvU2prLFQ6bEEhshe3aPyA", - "marketBaseVault": "CjHFbT3nGu5UfmQLSL8NvP1ArBsUb1c2s4RD3FH3QXxL", - "marketQuoteVault": "8Ys3aDQJDcYPU7THHsVZ2WJxVmrANeCSYDcP2pEYzfX2", - "marketBids": "GYokGJcbnXU1wftYGzoBEhsw9rbLM9DJkC2FxEkU4m6f", - "marketAsks": "3tWwETLyAyvVg8Yhi3Q6Y4ZwaM8P41UVjUvCr3R9uZ2Q", - "marketEventQueue": "FaTs26xZcK5JXzsqeC7KHL6EjF71F6NGP7PAav1LCESf" - }, - { - "id": "81LGyog8REjxqMrxNVnJnjVzzxBZ1yngcVvkxJqLsSBr", - "baseMint": "j4cpRFecrtvEbdLYNZb4pg7eTLDSuxUZ1BA2ratQpNa", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "5nKNvkey5FABG393rWpU6ZW4osty2NTu2XwcZ8n3Cp2B", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Xn9qXoiMcFbNPEUE9ev9NGuZcZYRi551VFPa48Be51f", - "targetOrders": "5eCVBUt8fRPDt8ZuRuBKbJSE6D7YAzS8m4x5QuQa5GRw", - "baseVault": "Cza7Z3GmmiuG1cMyE5rdnLbrGMbxtVnGwkRTmjQa9WgL", - "quoteVault": "BgMJqNbW4wr9N6ZmVQgxv1zAfYC1XJj2PsuPUDVawreR", - "withdrawQueue": "61QWXFfgvZxHK3oDswzXKRWqoD4af9XqEmkv7YB2qS5f", - "lpVault": "B69UUNwG1SozZP7e8WcQtU6Y3xe1AdJpiUJAm4vwaMvy", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "D6LN88YUPQgAuiuDQVcta2Fh43yYjtyt6KBGqxaeMh7k", - "marketAuthority": "EvfYMAmjXn9YG78mKf2JgKr3UJPvwNouerLgHhUCbEzR", - "marketBaseVault": "53LrgAmzcHQmDnAKkSAFgmvB9S8L1igZy898Eo5guJ4P", - "marketQuoteVault": "9swGHZ1XhMrLDLuQLwqwNx4xcyxAs4bqR6jjKpUVx2js", - "marketBids": "7mmbWN3Xqpdh6AnFGbwcTmwR3CNHDPtW4Ka2JSmcgKCV", - "marketAsks": "3i6jNZZrxDQSJGoW8YpaDHfdEjTKPRp5CL1ZVgWhfZJS", - "marketEventQueue": "DDaVSK9GAojFpCMjdaJEE9DtGEcf1tghEUaVTKQPbxdo" - }, - { - "id": "81QxnQMtP5WwYCB4hZFiarYK1UrfTabu8uTbgShMSDYz", - "baseMint": "CAPYD6Lrm7bTZ6C7t7JvSxvpEcfKQ9YNB7kUjh6p6XBN", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GpmjBJ2GmhqsT5ew6c9GkqPXNBKHGkawqWx13wLFvv2J", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HUd6DstHjS8ZeqGJn83jgpyBY7iJdbRsymcBDFFekWGF", - "targetOrders": "C28T6secpgVJECMUjWZBCgu6SazKpy7qbpH8dTbUPfvb", - "baseVault": "2PFobDQr3qFShGJK3Nzzr2ZB44S2zhJDGtaizqA8hLv4", - "quoteVault": "4xdQApV1qJXd67CWA4uK2T3XsFVykkHubW1qAUC5JPyc", - "withdrawQueue": "AbuxSTn8Peo9itBUbDdPdRoxrxAD3pDLXWUkPxyMVLkw", - "lpVault": "BsDMmhFRAkDvZxX6FxTKs3G8g2f9idP5bTuSPprTZBvq", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BbvuvK8WPZeif6tHgKknijvEi3LXaipDhQegrYDqewmc", - "marketAuthority": "FQ6nAHiccZ1Gp2PKm2NDEh4XUNnUwxcL7hikYChDH1GN", - "marketBaseVault": "HZx4mKVY1stt3GTmmi9zDRyz4nU4o2Gyr6Mcsa82d1Hs", - "marketQuoteVault": "8qnYk3gp7K1oxAw9rSkLhE27mg3ENybPVTqFwKUrX6tV", - "marketBids": "DyiBGDJqqZjYhJoXCaXX7kuwmG5NiaRr2e4rraXC86Hj", - "marketAsks": "4Lzh6KyhjmXbtsER6F6C2BBewXs2iwny7zsSMQhiDaUB", - "marketEventQueue": "DBGBV4EbHao9v2B2WxsAZENq826aKNef8ymgZ1hFvYCn" - }, - { - "id": "821L241gacEqKJiCp9H7E9rqRXB31WoHLBqwhn8NMyWS", - "baseMint": "5L87fjh5XZWERN4UGbK62TM1funxFvXSRUGmvbHBGqn1", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "B6zwhP9hoFSC9PZcj5Mf74aQTafQkBWAf3NTfM9E2HGw", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3uwFLE3L9MhQQeoBGTUfQEG1jzskHSaskwRaBhPDSZPz", - "targetOrders": "3Kw6oTzhtxGWDkFV828WBnzgECB815djfUtwDuvDDYs2", - "baseVault": "DULrQmn4nga7Dy9i2nQ5RBUxJaKqyDu5CRp9kyj9e6vy", - "quoteVault": "2d75PQH9kNDpGbzDmcXq3QadfkSNAxW8434sZrKSVvNi", - "withdrawQueue": "Ah4MgcTzQxGB2JLjXNrU17Gpc1vVUdcF6gi6fkHnC8wT", - "lpVault": "C4qPHwY2j8cEi87dockc1tdprVrtDNJmwgdBEwPgs2qg", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GWEGFiX2LcCqCTjkDtJ4qrHwtE11t88haMng8yGinHGw", - "marketAuthority": "DZcJN5Cf1fArYSauecSUe2F69hHbxdziNobZZHjx3XZy", - "marketBaseVault": "2yF33EsJBC1ZaU8PRRwNyECiSuMQ3AkqxLN93qjTCsE7", - "marketQuoteVault": "4ukMEgPQAvnSp4XJq6DxFFqJPwd2KGkc8QFLcBmg6LMb", - "marketBids": "Hfobu5w1VJkTpGtqZVKDcjuKcQqo5ErEQUsSX45RrdB4", - "marketAsks": "2hwJwHngdXv5yF3PTcWXrT98UX3Nzjrn1wExo2WU4fsu", - "marketEventQueue": "BWUnhGreSTxFbpjK1kg6BwTsauaNWK5xEAEAJ7nkYpvd" - }, - { - "id": "82e7gTusZTnk6pRxfvxCNetUozhwNCPNsaRn5umDi7hw", - "baseMint": "8fY3HZy5PKFReE5ztuZnHL66yiDDe3qQuD6vxzjsqcjA", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "C4v3hcbV7Cq8LKuLbsXezJpTFcKpCedaTCWi9vBkysub", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CtABufBuoCMBpnMch7HWry5juKUMM6SMaqL969Axk6Uq", - "targetOrders": "u2iShBFLVh8JfRoNAVZYqmEobafhMaZAmzeuXRRUxZ2", - "baseVault": "hh9YxufRBRTCJsJSfeH4evdh2iyWUxycrYfkLgb7Loa", - "quoteVault": "7q1B2xQXyhRyUM9Yz5JRKsh3NfHj16tDyLMUNbdxiA9y", - "withdrawQueue": "7ePqY78CnRpZsnFwx3adNMR9eoGvRETuPK8LNatVPjxs", - "lpVault": "49R2apN62eJTy4hRCKviL1eB411UW8HpZDgVDCsMpbsg", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FDSk9jQE61KNZeXLesQZmDwYPNXo8SFvk1na8deU4c4S", - "marketAuthority": "Gdnf65Ef53XjePCyWNDrw92dnJkTuofcKqV9HZhYzNBF", - "marketBaseVault": "93KnEvjUQ2JKVSYmqu3uXjj5cQX8R5KU6niurC7zL5xj", - "marketQuoteVault": "7RYYNbPiHk3vV65KBtaPUjcGaTx536wn2LnywAXBTiwm", - "marketBids": "HaxyLngjLvFBmt9xYVAFeznTiUwao9hVwnbDQmwHijYp", - "marketAsks": "Gmh4nPRrzq3DSN9mPSw4vJaciSjZzotiatSTokBiceWf", - "marketEventQueue": "6MSjfW1VRmGt2uMPRqQeeGitJfaLU343H87Ua5dP5trp" - }, - { - "id": "84KHCpKQ2HEW4szTGR7GuEAizLyH94APtpM6ifMTELwy", - "baseMint": "8TjgDMv2Esb7YRKu1ESZv5vtgD1WqFKmzhPBgsLqwEGG", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "5Y5mpBoiD96kkY13Rtg7AueaGPQCTTthkHYoiaKRk48e", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HaDNsXzVYYwdyMo36Y7RmWpPsSM7epWL5d3n8WQtMwuo", - "targetOrders": "FvC7Vm5HD3DQczL5PqGWWcN1pkdWSVEeBYftWrXbSjxw", - "baseVault": "2WG6mkWpeASqLbMXksUpxZfgx8PwzmMGyPM65E3L4M9S", - "quoteVault": "ENtdLNBGZCSaHhbr62qDswDZsV6fW5JU4RL5iAXSaYVG", - "withdrawQueue": "BNK7JFYjM2UecT53iERt4M6eZwcXBPmw2gqtCF81d8Jf", - "lpVault": "373LxSEDPGkPU1AhrULMco8EQWtdWxW5sXbxLJSNTiYB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3qXkLj4vAT4B2dMJQgtKSrNxLfrSQawMZtAzKVEsMyYT", - "marketAuthority": "7BW4ajwkon38EYfhADgf6PZZ6ESbzSdthcHKY8bkKHy9", - "marketBaseVault": "v17A5JpxhAHdFzyCuPRjmUkKNP5h7kV2i2PMyAZrcFL", - "marketQuoteVault": "ANmEUU9sTgheqK9riYx2RE1dSLs9VZizNAfpcMsd1DF2", - "marketBids": "6KF1DYJ7v1xU4oJK2FDXZLceFk33fhu1ePdK76LqwSsi", - "marketAsks": "H5AjMapp4HZsKjN719caawNWinzEypRLBKVeDWQ8Btrx", - "marketEventQueue": "BfxgZJqqwgmoGHGugTFpB8bV1Kdd3bSMqex4VXPJJ1m1" - }, - { - "id": "84Sk8vke7cSvKeLuEv6Y59GUJi9dKZUQTc3nxnNqKaNS", - "baseMint": "METAmTMXwdb8gYzyCPfXXFmZZw4rUsXX58PNsDg7zjL", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4A3kqZBJu581eFePXL1dTLfxEkjZPWJFgj4tJmP6mQQp", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GrsptRCTC9tUhpuqeLbb6EYyGkjoGvtcpAm34vKQG4d3", - "targetOrders": "3bjQpeq4ZnCo3VnPjib1UZdgkrRHUTkuVCPQAaPTj5wD", - "baseVault": "BTVMJ1D7zc4eCNNwLmJ8nVrADJK734AicBxrMqH33y1q", - "quoteVault": "2GQb6TfLkbZ8TmidVQycmJZpkZNYaHXs6uDhFTkBnFmE", - "withdrawQueue": "DnwVtD8VqR3kmwkPvkWuxeQzbf6teKmGvgm6sY4rMo7Y", - "lpVault": "6kLwzfYVU2senh6QzJbs7rhmPxqTXkC4vBoGaJi6Jzny", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DvmDTjsdnN77q7SST7gngLydP1ASNNpUVi4cNfU95oCr", - "marketAuthority": "CaQ8qAjV44hExigiWGpiVEQM78zazMe1VNe1TKQF9cA5", - "marketBaseVault": "7HPWx59RQLAbEFYegMC1sepdTo86i9d5pg5c5yiXqPSC", - "marketQuoteVault": "DeUNDMfX7G6kXaaK5ZsaCFBoSwuJDErqK8hJzz2pdhDk", - "marketBids": "CWV58CaZXCkvaVMx2nRrx6K5CN3CafKDqYHu5HAmHJ7p", - "marketAsks": "GCHLTigMHNjCnoWwL6sAGqVLh3AWvqU8mgb2HUtcmadp", - "marketEventQueue": "EMbRLesmacYyj7a618abpTYnMCZrPpisJZL1G7FxTjNz" - }, - { - "id": "84ZNXn6PLAn6RgRim2dSA1rWBk1mS9NaraE9JD9q4DDL", - "baseMint": "CX5cv9xMgDadGQY69TGPgghgZ372FpHovrS52yipXSVr", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "F8bgA7wa3fipV8VvV4ehKw6zmsN4bXVedJAV3zh9h4CP", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2gHJMVo7uTdCHm65NXZGZvnkm4Zrz6w6kaQqSDeH5KLJ", - "targetOrders": "6g7f2Liyn1pJB8QKUfmuHPojjkwnBwn8jV9RYR7Wx2Vd", - "baseVault": "B4NLCeJxgoGyU4DnNxbuUDar9VmTVq7Uruop1wxU9ro9", - "quoteVault": "7XFy6aWr1QiBs7bWBP5eyJXinK5xBRaEM9ajCtXfdtwZ", - "withdrawQueue": "4AoPEwuBPcypYqPQxhgX8CVN3pXu4V3HiCjtfztVQ7eW", - "lpVault": "Aubr4CjgKnHagEYmVgsDLzXvdWnUvBu7Ed12YbnYpNcn", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "F6urrp99CMJszgwdh1AdSTbtGvW4fK2QeGUKBQPyLdPE", - "marketAuthority": "CJG4jwfaUPFQyVtjzD6BJRXpZgcVx2DcE8kJ52CxaiUa", - "marketBaseVault": "DFT2R2jcTnfzKdsRWYrj9wyLmkNHEkvxGXHxJkiGjnVb", - "marketQuoteVault": "A6HiFATbnaMhR9D1p4iw9Ac6JXxJfqCh2EtzXPZy9bdW", - "marketBids": "8HM7e9M3pviGNUMpdJVD3MZt4kTr7CKwUSDAGmk1C29Z", - "marketAsks": "7aUYNr7MdzrtgNp8hxoFZLxSsoPfaYPybY9rdU2FjUSU", - "marketEventQueue": "GdVczbiS4vHMbqEwL4jcGmDND4A8AUc7BnTs6LcjUhAz" - }, - { - "id": "85anbeqV36qqMvdVQw2ca7YRdJoBQ95DoUUFW9vC4Bav", - "baseMint": "meebAU3nZrU5PbUt3dVK6ExgbNWCUAkV7C3DaJKMZZ4", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "JCXxzVoRnXLHgFsV2KKwyB9UHxB79SR3m7NxejxmdNTq", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5JjtQTZcy7T4QbH3GesZdLp5YPPuF4fZoWiauimDuuBj", - "targetOrders": "88um4fz9pnYmwh1rygPY1AiqDWxTGtRPN92gc5eh9q8U", - "baseVault": "FiVE2xtWEyqdu1GhMQp2Hkc43g6QhZzrta3b4DWi3XBw", - "quoteVault": "2DEQecXPUmt5v3qX9QF7PAMNcy2VyohxNvysnteSRCBZ", - "withdrawQueue": "8G3JnbrCd4EMxE19fPRu71tqc1UcYxBJgJZXqcK9TGrH", - "lpVault": "DX3rLs8dbwU9VrRFhdAnBrcjNYJxGMTTeSqvBWTuuC6J", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "36xvFyc7Tgst5WoLzohFEPTc5jzct181HuUunrT67SRj", - "marketAuthority": "91FarzndNr67aSqM35CqEWG7fzawBppfZWPDhQcAdMzD", - "marketBaseVault": "3RBDUPNTZMG5Ac95K9qjMnx7MMTCZumpYut95YgJWV4S", - "marketQuoteVault": "H1kfFjapYcLdDW4cYMEzHKvzJZH52UH65ffBiwFzBVXy", - "marketBids": "5CgwvkH6ztddQGDH73SAYXiFf6K79AERf8XdotnY7ChX", - "marketAsks": "4hBFa7CcrywwdJyfQqxHzm6LZhYH5Bdd1CYhxe9nhaTU", - "marketEventQueue": "4BH6zomkzD4CA4tUSc9hVZC3Arwrkf3iTUDjUeRxPcvJ" - }, - { - "id": "85udk2wNKTQArwEitdJbDUKxiwb3wrd1r6VcVhDS5VnZ", - "baseMint": "4NJ1L4LHSbJpk4h4rHQnJNKZbRSYticS8sQVPbGHsj33", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "A6zv8EQELFMzBUGSsEUSyhMcXNE2iriHQypmcgbFRKSe", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GjaPw98uzWmp226Fnsk9jAScgFXqfa7V4M4WqmctGGzk", - "targetOrders": "BNPcu7R9iaKmtVgetwUDDnCd19MnVsDi57YtPzPGoNzk", - "baseVault": "CqCArnvYwUadz8UDKcUULnjjec2aWfVttps6oD5Udkqo", - "quoteVault": "Hs9neruJ7yEWADjssCoFijirvQF5h3LFU8TgCUZW9eXe", - "withdrawQueue": "9z3uYkzNzAFiVAVHzqT4CZXW1CRfLWMxZ6mPN7sumiUD", - "lpVault": "8tev7yo3SJiBziELs2gqtfqTYSy6kFZReXFYE5cnNTBX", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3kdtzcSQ9di8xNnW3uSz9f2wq4cj2vEtpzcfZ1mrYktA", - "marketAuthority": "4WdiiJRTJYKwzi72RHEru7jv7ECf3wYcNwhdkjmUkobT", - "marketBaseVault": "3Jcna8ZnMfCGGDCDg7ceUo3ij5nsg86gNcxn2v4nxfLc", - "marketQuoteVault": "3SyoxdTGPDne2UdAQ1xvymmsrLWjY2zQYRRF3xoHH7cv", - "marketBids": "5uagjmQ5kPCVcCGwBTbthDW2xBmxdoKdYjWGXP1ACrKN", - "marketAsks": "7TpbVLFCPMaYMr13twsKjbi1YetSP4CLGqz2rwvDuRyX", - "marketEventQueue": "6XNfQcS3HShocP3CjXLe9j7PirooCVsqoS15weSueScj" - }, - { - "id": "85UTLhndd3WZrhQvtQfUy4qfnbVggLJmQPB3SqgYjMoL", - "baseMint": "DubwWZNWiNGMMeeQHPnMATNj77YZPZSAz2WVR5WjLJqz", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3QZqbuDV7jxa6GUcpSX74wEidJh4Ve68EQQuVz8bRTm2", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GUMBzhhoxtNi5KedB2X6ntBCiSbutX163qi6wZr3acnu", - "targetOrders": "429EUzQyGEjNh5TYhShcsdwEtpRXCX5u7e6HMzWvFMxW", - "baseVault": "EU5ZnN5yYzcagJDYH9aMWyKwvcvFg4HLM93Hmidb1ZRC", - "quoteVault": "2qg8HoEQZPtphvM1pGcqXp2J8wYS3Y8cRYbnZLcMsABX", - "withdrawQueue": "355TZub7bs41F4T6qtcdrJvbZEL7YnFvk7zQ931EKY6J", - "lpVault": "14twNfUndjFSR1UFNvDemkWhX8TVScMhSfTPoFFYJBaZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "93mtNf4qzvytwp5sWrSC7JNUccPAomEE39ztErUq5V3F", - "marketAuthority": "2w3KjXxiZqYYT1gzEXy6bLyzAvb45H2WGrLheZFXShKf", - "marketBaseVault": "5P3thVSnx1rwhZnrXs8GHFLP5tCABjCt3jQqyGVVqx4V", - "marketQuoteVault": "GEtKdDB6DBpsptKtx1uZtYgD7GbAbfPCfAteGzUTAsRj", - "marketBids": "7ztk2qtQ77eqLzZywgqm4FLSByyLgXHQSizyStKAXa9N", - "marketAsks": "4X4zBRcAwraoFRhe7CFf2t7e5npGs3PNKrv221YKfXAs", - "marketEventQueue": "DPXCqjL2yExT62MnxXPMcQEF4buVFyTiV6TvuP3f8dS7" - }, - { - "id": "86bHsku4dxmwRphEAidzwmngTc6rUUSv83cAjcbELshy", - "baseMint": "GzHyjtEn2iZ8aQdRUGS54U3TXAQNP2egcKrAxwEcVhPT", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "TrXKQuKHq7DeKB1b3B7TCpArxWTa61bm3yMe6BmPvbc", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "pZtqfGwxXxCdxkmDRaBuYJGb3g2DDtPZzFEuCzE5UMb", - "targetOrders": "4iuB7gxy5hhHC65cqaYbkwojFYDDh386LsdzkEWs8RfG", - "baseVault": "3rPkP2S8nUJCwc2j4RCEM2Q4xq9fTg8quzPGJQQzLn61", - "quoteVault": "4ZbgZFtLqXZHvNQ6X5ZQkgY3VSdkuDjH4NRFKC5sUhxy", - "withdrawQueue": "9bB1CPb9XTFCbceQ6JybdRCfi8HiAdCUfDeru7L8QZDe", - "lpVault": "Fo7dos5PgsacapiP8uhYZ2oojdhZ89sngpA8gTsLrm13", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Ah4AxmxFTqKVfXHPwqWSyH22LKskXkwERXNzNW6Jfwih", - "marketAuthority": "39FS94ng3QYrcQYvBdNUyq2BVKdbsqgkPTF34CvohUwK", - "marketBaseVault": "BYL1gYtwQ7c6zX4EfBxcBE3gdah5S81AWqqt27jn82zD", - "marketQuoteVault": "54TddPiqnrair6Jtjq19gQ5PCzd4z59czTNfDKXSsxSR", - "marketBids": "5LmxV7EREmPpN9bLkPmChQXqTnTkiyyiKqnRx6Yw9kMK", - "marketAsks": "58GmGTKzpciGbjY8RPtBDxDd74KqBG5S5Whjqudcc4UL", - "marketEventQueue": "6uQsHzFfKxQn9Rtqc1iopxM8fuPCVmrTJAHu19hYWKPv" - }, - { - "id": "86JR7o7k8TLJfaj2U47v8eW9ttRHvTYn7rLXFYcpdikc", - "baseMint": "JEHHZr57hJ7By3dL74HB9G9R77ZrTvDr1P2vSjQCAewF", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "GdLnVLousx78DpdiFuXHPTHLoNfwceiNzU5h3zsETfeG", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7a5kXmwwQgbtGRiTR6PuHXQBvNGvYqk2BgmQhbtvUzSA", - "targetOrders": "63RMLBPYyQ4x6CsqN2TMDPVTdj8JjuMZiqs685F3jEMt", - "baseVault": "GAdF7CY9y3GtxkSPi9Gzkjg6UwGfstovUcDTTDw5WNTN", - "quoteVault": "AF9yRFho8QtWsBnuPUpuX4c9Uq3HPGSQurane9GUqT3C", - "withdrawQueue": "9EpPHRi1ZxXKgwcmSiyabaiEcwhzrSxeVKj3a6h8LHne", - "lpVault": "GW8aYUJ1fFogvAGCEndBTDvqHUKQrmqHHrcESU9pdGXL", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6N7Bu5z5ADsvaGgsgCjpf9VDqvzzLDvJUUqCFnAFPaqm", - "marketAuthority": "BHL3cT7M1Jt9YDrp2qJN3t5sUqzom1MTkmE5xsQoaq6e", - "marketBaseVault": "77efDrS2P9VcKfCeAj5HhLuTG6gxZj5Cd3TTSd8G4ei6", - "marketQuoteVault": "k6hMxvX5xmQYQs6YLixwRfHd6ft4huhLZiasLADKP3Z", - "marketBids": "C8Yp33wGKN1G521gemwopV3eYich66MvMET8yuATzzZC", - "marketAsks": "AD5SY286FNw6n9EHWNT8AiHR2MvieT28Duudn4keybru", - "marketEventQueue": "149sVqfVkoynAkGu6JWEV1KHmKZR88FwFS8AkdnHbBi2" - }, - { - "id": "86kcMN53xrpdCUVwoYj3ZK8YftF9CS2j46QRCBqa8cGJ", - "baseMint": "8WDJHzLR94ZCiJdkeGHMUY3TdWuryWgTGgWM9XRCbUG4", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "ekX9hdCvihDmkDiFqU4JkzZdJsMtXhD3M7errDuNmvK", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4BYjkkdXcKDsY2ZTko2w1hzauCBR14ioQ6qY6QijRW5s", - "targetOrders": "En5Nbd5BikhtBkWt56YEvYyUYmaeoKt5QjvQmFZRxjPv", - "baseVault": "8XPRbZSRntbLWhrnAE6rDzfFzQ7iSbUMBFTZzvewr85U", - "quoteVault": "D5UB2PH8M4jmtT3wD9CgXdW5oWG6cLEJgB5Y2PyXbwm5", - "withdrawQueue": "4qf95CehnYHduNsxWEL3kGckgU2EkBjUc2pXNwgc2GK3", - "lpVault": "CC3mnNPuyM8BEGdLT5qMVxCCEpAFgwXiPKweWW4Etz14", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BgmywEaArUmQAhsV7y2n15xqJwMv497UYB6F1bu9VTRg", - "marketAuthority": "AL2v9aniSotnVmzNCXsnax6kCDRgpgycAVp8yhLDf2Ns", - "marketBaseVault": "DaPvk23F1tzvp1CERgUUq4HtxxmWZ3KRBsGJ9EG86dgC", - "marketQuoteVault": "ueVnpNmL5xhYQy4G9nFeHRwmNzYV3eh9DBe81L6EMMX", - "marketBids": "78NYpwkWBHhjoRQMSjmbAwEF1xgEigaHb5T6gGdbBMua", - "marketAsks": "AhB83KTdEQRYkzNtxvhpUMQdqZ57TE8gtBXj8hdTT8ye", - "marketEventQueue": "3VJVxrpgxwXdHcWAQGsX2MSdtry2WQu2htQY2qPnugFE" - }, - { - "id": "88LiuexkorHtDLjcVRt7qWQQF17zekEBHKDPv3vbT86k", - "baseMint": "77A8ycvZQfwYb3h2Rc4f9masYfug1wKVRRJUPeMA7b6o", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3roMYkpLM5VuXdamffznJtba9NnvmQzGd1eGFP35QSjc", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2HQgg1yUdPJauAy3M3633AR2wMTetdkxC1jnjafunNqz", - "targetOrders": "GVonjg63MhKMbdT7tt5rQ3rMY4TX38X6iWcSw3JJ87DD", - "baseVault": "C2AxTrkCWYjgA8FSiduTdAH9yKdrBmD6q8LQ2dhJ8rjC", - "quoteVault": "3X1DgbN7erbR89uf1M7BF86UAQ5UNC994ZoYn9FCxL8D", - "withdrawQueue": "5UdEph2oKGnAvrUw8AnyeTo4FvfmMnYfXuqHFVNEhbHh", - "lpVault": "6xiZXQioQC1M55ALJ7DceXhtGwX3J75dYpXHh1qg4v5C", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "A1wXiTzcnUvVVmbXHD1Db5F2nFkeAwK7CdHiz6YrPt1c", - "marketAuthority": "H5oeZimhd6DY8svfTVVwpBLrTdN74YepyY58SwbDFbh7", - "marketBaseVault": "7kTvBkKZEGpZwuaLZgcuD8fzWUbyqEo6Fj2HjNSxfNqP", - "marketQuoteVault": "GDi1YhK8JR88jpjK8GiXWa3uoiEQz6eMMS9qdNz1AZcb", - "marketBids": "64go5nPa2iyrtLogeCRjyAgWjFyH5eBVEktxWrtonN3b", - "marketAsks": "BHyBir6j7WiB4sLwWbTA2JgQbQ1HgjoyheTqvYbYZWWG", - "marketEventQueue": "9BMEgr9mW8PnZcKMfWokgzvxRqKPQV5eiCKPhhQHLdww" - }, - { - "id": "89mFm2zW3QGLmNWzBeqgYHiEzMtbfTo2iKHE3NXmSaWD", - "baseMint": "NEo3D6MXRXf2iAfaqvZYqSmFkfutLvNjm86xmfGWNh5", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4eXLieL7t3N5qqUaWx7U9LNXsX2LAEUH638UCx73Dntq", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "B6LRyCnBiG2ga5wQ1pUw51Jpo6xmXDsC6RaHx5ZrbQR7", - "targetOrders": "ACUAVHyVZDFvMmmZkHs9ewzVwzWdhUDV4nBb4W5xqoLJ", - "baseVault": "Bcv3q1tkhpTdEC1WdMoqqwKWBJYq89NCCAv74hVminhV", - "quoteVault": "4qszK7s3BvTrAkmXGXyDvWxqmAk7WZSML7Yg8oz38e7A", - "withdrawQueue": "H8SLZD5G8Rh7x98Cc1xmaZW5tg859ExDjdF7CBgdqA9o", - "lpVault": "8vskE7m2BpzMuL4CUp9KPvyvcHpadmX4QHoYkzHnPyJF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5izw2gntzNLMUKufsbgTLqeSSQ1SfHCaCJtQefZHxNWU", - "marketAuthority": "58faQztphy7X9DZ5buUFRYNKRwFMZdGkpTk3xQU1q5Hm", - "marketBaseVault": "G9oCCE9NFWQ8isoHuynESYeVAUGqkrk36FTbKDYKuKiY", - "marketQuoteVault": "3tzZKf25DgfCLFsFnUAJgxmztQXZkHkbdHCZSGzcYfh2", - "marketBids": "HCocnL2HCtt5Jjvf73z8p6tuYJQ9HQXNyFWPrzSsKD1Q", - "marketAsks": "DPfuD9xkYn5HZhgSZUdyfh9zA3DHG9DytR7r9Fzo8rHE", - "marketEventQueue": "EkuxzgFNDb32xJffBuem5CAtCFaMSmr6QM6bvFLHpAMA" - }, - { - "id": "89q6Wtme3sPya7AnP5JnB1ue2EzUCz2Fi67RvMexCoXc", - "baseMint": "G7VgKoTadSDrMaQ85xQhh1RFdBhpWXrPzSpV99L3DTL2", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "4RdBGo4EmpusBcq1FdKN3qX2oKpi4tybdbQTE7VMoFnh", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AXvjQrz4mihnrAYPEgCB9fG4Lvv4YXDGyZgvEapZKkRb", - "targetOrders": "7MJgWz4YUPTo1iDnnsmNHyvrF225BCVM5a2uoF6SX2Uq", - "baseVault": "9Nj2gV2QokCunrb9wZShtjV68PBsaMTCGSeCuVDpZgzV", - "quoteVault": "GkEXhN4JnQVMHEruax2mpNZ8CFaFHxCEyc9eNKBeWytx", - "withdrawQueue": "A8vs4zvaSHBr1hybJg8hg8DnEJVX8PaRDXmN2P3HsGmf", - "lpVault": "Hkq7Bmr1QhdEBMz39d6JMXAy3dmpwaEhZQtWetjFNiCy", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "C1JBW7DoNCbBJd9bxT4fnGppAvJWyVrswq82SseNbCsk", - "marketAuthority": "4TxeDVLiEBDXYWYKtsWLoe2SwaUp5SiHSpuQwqMjr3rJ", - "marketBaseVault": "HWL5qzv7hE386PyiHobXgndrMVa5x3JRXQ32yMRNrxr7", - "marketQuoteVault": "BZMp51bjbb4qD9iozLM96Wu9Z2nxBVLsd1XKjF3FjwgQ", - "marketBids": "3NHM2DbkMktJ3ajmEEKi8nncKera7xFdK8TLDj2Hoys6", - "marketAsks": "Gkkydp3kcsHqqbTUTBh2ueXGMtcVRFUGbQv1WNr2WPkE", - "marketEventQueue": "GQhGzhFknLtiCe9GLudec1eJ5M4SLNpKLSHCuG6Wm1Ym" - }, - { - "id": "89UkgvWxx7QJ9FUYAQN111nBkHMa4iu2tzoHcrNowarv", - "baseMint": "AAXng5czWLNtTXHdWEn9Ef7kXMXEaraHj2JQKo7ZoLux", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5HRjr4s8e6QF8LGv1sqvedJk9sNxenSgfEuU7SNamAJJ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5ucRRq8LrLHoBCnYub1BFc1hAh9G68XhrpC1abz7rFE1", - "targetOrders": "6Mf1mgC8rdfeXc75o3HuspbMxYeZ6CVKNU7mfpccrXJa", - "baseVault": "9jRFsgZZNxZTMiKF5dL6SDDix6xikwAYGAypRc398r5z", - "quoteVault": "gL8omz7bMf191Ry1crgRwRtBMtWfkecD9Hg3XW5bEPv", - "withdrawQueue": "4zceWyr61KpQ9th7Yg7KXvGLiUaDCjbkjxWnh1aixwLB", - "lpVault": "41YN5MwhVPTQRLmtZEJSMukskTTeX6PauckEfRpacfiN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "A25EqMxhHQvDLrSKc3kNLWbqDtBGPqnxsAGjYExju2TR", - "marketAuthority": "9sEbxnyYweeSFm6oP7cTD9VBcJ8sGffw8sKSXWeSfCSX", - "marketBaseVault": "BDfHV5hfg6UmTvaaZQ8TyubtCWCVSh9zmjy3dNQSZg8B", - "marketQuoteVault": "7JP6Ci7yBd7HBn2Qmo9Wo1jN41CEhZq2MqjVYGf12DFj", - "marketBids": "7HK85N54k4dMVNEaqz9y887MFYDYDV2hw12UqHGr4zaD", - "marketAsks": "BcMfR3KggvgXWVtck8RDxB9QYYjjXWtSPbRHtbArnMGG", - "marketEventQueue": "GG8qyGuU42koXe8w33Ak6BnxwTM2Yua2K3cXExZfCKJn" - }, - { - "id": "8ae3xRLdNgPUvoat44THVWrzk6iSBQtXL7eTogSEk66b", - "baseMint": "SuperbZyz7TsSdSoFAZ6RYHfAWe9NmjXBLVQpS8hqdx", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "5gsbJQ2u7FjGnEZazkf8NLhxJKGJRioKkksKETHrygWB", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EXAN57qkF3848grCCgqAc3QtPrZW1fbd914J9vS7XSbB", - "targetOrders": "9hSEzRHxzLaJgEXuF933pQ7uBD59fRjcZMsuq2upbjUN", - "baseVault": "5AJnLquyhxU2jvy37qDeNZnx3gXo5bGro1TL5M6MRFaj", - "quoteVault": "Pk72VkEMbed3MPBiB7dovKLyPKPePBsnqjP8mxNtpQn", - "withdrawQueue": "HKdVgUBPmrfid1GvnMyvhmNYvWp4ZMSuGbFoqZ524Z4v", - "lpVault": "8fmXwD67c2t53nsWUybxR7UC7kRDqyMt1YaqnWsbUX1t", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "E3cNotFPoECwQvacT2D7u3C3tKRkGtUxv8WFYazBEx4X", - "marketAuthority": "7E1qTwZAN2RmYDUqrYxJ9ibX8o7Sn1FGUE2pGxB5T8Lo", - "marketBaseVault": "6T8R1cUE8fqEi57MJL61zhQvZZRR1i1afbHmqHoWLqti", - "marketQuoteVault": "BhKpSc5BBdMnhf3n1D1ktqwoKGJCAfkv8s5c6QJYhiEP", - "marketBids": "Azf4f61K3RprdYsykreLVACxHtMrFStmdsEKobLBpn3J", - "marketAsks": "3t1M7VFG2hqWd5hLXq3wqLevz6hJjnxWSXTiFatH9ZXV", - "marketEventQueue": "GRBRvXnGFTGygStSijn2pDMcBgLB9E27sES8a1Ztjj99" - }, - { - "id": "8aFiSEgPSaquuXudozW7Kx49f45DaLqFP1JgQ1NhKL3x", - "baseMint": "Dhtv79Gax1gwvWNQCKFW4oUCsMLcmUbsZ6vdaCFYP2Ko", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "G86ubQ11yJaCU5bY4HWmxRR5X7M1Cu98UVDiFYYExkN6", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4mgTtgSq7SbAofMyw1b3meyuvYSyzLMp5RRA1C1dbrPE", - "targetOrders": "CxcCz2xbu4A56gduoNYeWGajkpfg93QGqHbuMZX9Ypik", - "baseVault": "DRB9VsisLX3nunpV98JCcNdTy7SDbND6X6x6icG7oZA9", - "quoteVault": "FViFLjCLUW5tQBcaFFyqc6ke1psWvkU6gWvTFtu4xk8G", - "withdrawQueue": "CqJ9JNUZrrxy294aHTENCNaXuBvZor5h6iLS38qLTYWk", - "lpVault": "9ZnT78byVkt7yZzCVD4kPGeNr8sT8EqCpoD78AWAdrRZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Cya58JUnKeoTpsfCUuXGA7SLzacXvLShsMX3gD4ecwyz", - "marketAuthority": "BeBdmfrDarNQLCaryTqZiN2EE1xM6bg4mamNxwWL8cpZ", - "marketBaseVault": "2JqtTiq3MnUTE4c7SBhT87s57uRxkCJ7kjs1vWVT6AKK", - "marketQuoteVault": "99yoVQbxmxkUhcdVKARXP8SBzeTZDJfgA8aVMndCGFNM", - "marketBids": "2cbg718gbyKaUaCvcYn3pkoFLEL7mx8uB6Q6zsU1PAQq", - "marketAsks": "7HJqmXyaTrqjdDN1rQQu6XwWHvrCtf8WVoHr1CtjM1Md", - "marketEventQueue": "DqsECccchXSVPqVBKXsJzazT5ZLQNKvK1ASKmupgmCEn" - }, - { - "id": "8An77vrD9NHLRiznBiBqoMhNRXcZC2fGVsdWsVjjHQua", - "baseMint": "9ae76zqD3cgzR9gvf5Thc2NN3ACF7rqqnrLqxNzgcre6", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "88EnWEEZHtQC53E7AtjymJRJ1x4PHP86Adf7MFWaq9SQ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Da1jx7BFUeMxEPdKnGQ6aqRWMn7PAsXd9HS5jbMQGRh9", - "targetOrders": "EHkmPkZmnRTUtryuVtDQgDNHrHVCgKa3auiHNs7sZjEL", - "baseVault": "AEanj5RgWW67NaRjwHzeETbtvhYwMEkHiW6AceEsq3M4", - "quoteVault": "5EotS4QjGN2omyzQer2fPRDZf3xttEtrgrXv53Znfsa", - "withdrawQueue": "AyF9demQiRXT5Qapfgb6iaRjZ1tqgVoAxmL25xRWDZde", - "lpVault": "2nUXodMXoRYQdXYanfLgo4hkEwk6xszzdueNKWeFFU4g", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3kuUc5eTZyi7qajuFfDMMUUkqreEkUKtxQbVCjdriKVz", - "marketAuthority": "5hDWVTPuSUfdehySbVEVjNuyd8BWS5QqpPUYJddSLcMT", - "marketBaseVault": "F3y1Akx91BBPHDudcBr28vF7KUZHUUvKCbAyt1RGie3s", - "marketQuoteVault": "TAQBfCYbCqwLwHMX3ZN5HZTQfz7hnxipchYNGmD4KhQ", - "marketBids": "FDVa4p6HvmH3QfMcdCYfXpAc2EdbeQYr8fK4Eh6TN1Dt", - "marketAsks": "SeSSSViiXBL4C1cTJVvAGhQNf6ygKvXSrcYkrbNT9C9", - "marketEventQueue": "GnySFjTMktj8k6y7LWmBpjRV17Y5qNJipqm6HZsDkgoi" - }, - { - "id": "8AqF2RcJea2NbmaF6D5JCva1npFdFA7foDEQjYrABvDX", - "baseMint": "9jWgVR3Q3QjfmaXNiZ6jht2K43W7sqkn6tZFeoK9B48t", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "9kBrwj6R1MBG91jTKUK4kWBahfTNjtA3rd3dCpQWSuBf", - "baseDecimals": 3, - "quoteDecimals": 9, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "V6qpVh5UBzveAkSZcZXUAg81EUtdZ1oqr5YqpLxU36p", - "targetOrders": "8W9ZarkhPwnahdJpe1QVeRuLBtoh44XUMVya6y81RHPW", - "baseVault": "Fxz1EbGh6SRehdJU3JsCrFEMdNbfNqoroFJeBF4V4EZ1", - "quoteVault": "GPgJP4oSJt2X6j7epGUZ2HwUJBVgqT6DiwbmwrwxVK8d", - "withdrawQueue": "HNAJoDF97zf2Yq76axAfgjJtVi75uAFRxEtZQX1Cv1AE", - "lpVault": "24PWLq9JoSaWUdGMhaPKnnjk4JSyefGDZgkoYu3fDXSq", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9W86gpgJY1CDBgvnCZQH9tb1v2yyukEfM3qnFSMmuQrs", - "marketAuthority": "5FAm58vYyjJ3uQQbk4cgmFtMbQ6AaL651L6k5N6ofscj", - "marketBaseVault": "4XNajvGBnKkoQLRwpKs8sV3fV5YD5DUoUhUTVsA5yjUN", - "marketQuoteVault": "Hy4ihePsXrA48n6TxMaaJX591YYBSzE8ovoXC2WanMZU", - "marketBids": "CC47cVg8qwQNQWYkaArPcttusfySeDsxP7th3vaQAK8v", - "marketAsks": "7ThQkDgjTfWWFNQhj5GWVj79uEQ6w4YPZUC75hromnxT", - "marketEventQueue": "A2SsXWKQfq48mDNF3x3DWz4xcMAQq4WsVPwT6L9isC52" - }, - { - "id": "8arNSCmsoAD6FeLZTdcEeNp3GVUYvwQokxE5dEozEnN7", - "baseMint": "5JnZ667P3VcjDinkJFysWh2K2KtViy63FZ3oL5YghEhW", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "SuxkncUTAyELoY8WHcMxq948No8nGvmBVkfPgP6FK8S", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ANmpQUJaHVqfXFftfS7yvs6aNDaoRZ76EkPgbjtmAKqh", - "targetOrders": "25EuSPChBew9MbtwyjHczD21TnoGg3ZSMMCSipgmn3TJ", - "baseVault": "GBajq3M47QdZU4uDggcZEPd6uafCLZP3qMH76HtC8H8t", - "quoteVault": "J5Ag4sPWucY83g4VsMLreTgPb7LvZNAupZtkk4AEkzXt", - "withdrawQueue": "2DhAmcGHuFYnFduNQcHfuzygXdKXwJeadq3B3KJQi5QC", - "lpVault": "5W5yAGecbKvpWsd9ZtqSwYcnNKUTpPxRTBkAHeV8VXSV", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4wCTEd1o46VjBmRoRks5CmZywaeM8gnEr93E8nFPGBqa", - "marketAuthority": "AgF3eWaFJYqE9Q8zow8ztPF9wxFJQ5zPygUMPYfKocRL", - "marketBaseVault": "MrgBvyLwTG2LArejVkJjXYKerqaPMwKL4YngHTebPm2", - "marketQuoteVault": "C9UJPk3pSV1Thy7qs6Qnm5epZtdthstTdjCnFXfRh3ap", - "marketBids": "5ThsjFuGYLkFDAcFQCDVpsYAfjqS2AWFL9xuoSc8Dep2", - "marketAsks": "8KBLRhYS54z4N4BYx4uBCBuyvvzxDvzxPKb36thWz2Jo", - "marketEventQueue": "A5QRb569Lxebh5Pzy6doL4KxUiu5jhdUffdrFKid8xZ" - }, - { - "id": "8as76heXmqewveMQJzdBLokwn67BifHcAZYcZoH43qzq", - "baseMint": "jWWi8vp5q8hcNdxQpqbJNMJ2aDpz5t8SoB1dkzYS7CL", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "BZemXZ3cSLfum8Gw2VPgt13aYdvZQWA93SuQXgPMRPwb", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2eytwCLXzdYkT8C2QQWnqeMV6ttaHFgbNttkVGsUEWTy", - "targetOrders": "GXnz7CR1BrizTz7MrJtN2RSPrR3vsxAqhDz2zjhVPVcS", - "baseVault": "Ae1FvsRBPLAEHUneQF1JrdtoEDMPZDgPMk6Zhftesh5y", - "quoteVault": "F2sKierezWjkw8XjBXqJvzPKYHoXU85hQMdUw12XwZgC", - "withdrawQueue": "akDk77g4d9UWaxqmbcFeFafpSvxp1DamsAN8d6SybUW", - "lpVault": "DEH8dtT3Gt94wAxZY7W9AAzYL62wxwN1YWv32G4hrn3j", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Bhf1Rr8hBbFwm8PjeErd3YEmYMtPHyG57244xnrEvbq5", - "marketAuthority": "BzCDyYRcD2THTyZUiKNAhuHeVL7j6kyq7yggouM1Xd1B", - "marketBaseVault": "DUoQrxAtCUWoZp5ewHbWQatsHHiG8G7wB417YurtjqWH", - "marketQuoteVault": "G35LZZKyXzwtMPZvrxDnv2YMNJoSEQWFqN7KpZmnAXpW", - "marketBids": "AXWX6GhHJN65PjSWzXFjXFxXrSMURmP1GLYXsSKXMg9Z", - "marketAsks": "CXQPP2eX3nfudv2o4PU2PVGEA2dxp5R3dWpAN6Jm1e5v", - "marketEventQueue": "9fkrenESimq2DjY34iBTAQe6CNeBhzor9t7b5G7iX3YV" - }, - { - "id": "8B6P5ey6TLi6WuexyGhGp3sJK9u2mtm1ewsH2xK6ybgS", - "baseMint": "FanJWA4yEVUJj1r83tR7XybxmDGF6bNH8M81ag9aeUbF", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4dgoWz7abHYMxeEFKkG5pCxrNQC2S3ULdvy6zehAfi9d", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "95r8puhEgYZE9jYFXyiKJ9xMbL11FKak9udkpSQtj6Kh", - "targetOrders": "CAVJNfqbBnGeCbpJ6G8AQVg7KJEXAGeFmvn3N4UTDSz", - "baseVault": "CFo289xurZKm9rmiRyUCV68kdaWg2kSBatLAaneo8YAJ", - "quoteVault": "9yTGrgVYurPgn9R6FjuCoEMTWoXswew6A2u48FVfjbAo", - "withdrawQueue": "C6XDv4HLvJRVhMm2LwRU8eaWkL5tevbomZBXLuPRoCJn", - "lpVault": "3gaMi3zjLF9NMALYV65Lko6z2Duxh4mHW4aCU6jsfnzp", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4RGAWpXg1Xu6W8cYoCPzAEpDMRdFzHQPZcvihae8QjNc", - "marketAuthority": "fWW413fueQPksXEWMi2UtAkhMYjyLTmo5dNKATcSULL", - "marketBaseVault": "HhQGNrrxSeUpTio17EZ2WFxojd5HQrYBqtgXC7siaJH1", - "marketQuoteVault": "EcCLuWm1ji95kmth4MQ58mzYKxLLmRHu1ptj931Lktxj", - "marketBids": "873FaNuEaYCg8r2TL4m5NcrCKLM5n7QgT1DoZ4zhf8zM", - "marketAsks": "8C6vV6xJUGDqr3ZU5k5qMBfq6KfyBGDDAPA8iFiJJPzf", - "marketEventQueue": "2T9Nvhuu9qKXApuYxzBD58UXzWVsuDw1XKeuDZXHRRs8" - }, - { - "id": "8b9utPiKmQTaj9qM4nykG7a9R2Y7sDGpDqqSvD9oKacC", - "baseMint": "HNpdP2rL6FR6jM3bDxFX2Zo32D1YG2ZCztf9zzCrKMEX", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "C4esU8T1miZ6BHDdC64ArkGMkvmJuGswRWzJouDTGpt6", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EQxmjg532Bt39DQc9hEMFrQE4A1t8Qg1iumZa8ygU31H", - "targetOrders": "GWoQ9rjxwHbkbjMqozKfE6VUraAUsBenjwhy7qhNHYUn", - "baseVault": "2JoBb6mrtZ6S8i4752tGWgS3mL6UeWxNkP5vvwVinBzJ", - "quoteVault": "JC4iw4Sk1nNDzGjTV9JbeDnmZ6V3yXxLhsQ7o5MqqZDZ", - "withdrawQueue": "5zkQ3U7ce4CmptEX8qanXkTfk6Jdv8uqeci4yz6W31ja", - "lpVault": "3tWei8VCnny5ySzxzwUVrsaGUtpy2yd3bDu91XvwSxPF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Gz1J3phY5PkUmLFDWWg1AEUuHT7qs85AuZwX2pyrX7cY", - "marketAuthority": "4zu3hMArtxp915HPVoDRBxnHSUhMgcBCaJvBV3J2miPY", - "marketBaseVault": "Da5gCNSqSYjhzivnKufcXGmYK2smAGdfBJBuyhKtxei5", - "marketQuoteVault": "CQXpyN1M8Zatz7MkDACBwCbLxFrcQHcivYAh3FjSsVfz", - "marketBids": "CKLC2xE92M78JMMVqMaDAAzqzP1SppeBrzw69Ypv7ryK", - "marketAsks": "6f9ABGbvFnfcesjJLnJFJMxcaxgxY5FTHcTcrQ33ZEjm", - "marketEventQueue": "WPfgBBzsHiiMNhn4iFqN7Ygz63nVR78VrkkYqEmaR3T" - }, - { - "id": "8bAL1JX6o1gq5LZfCf4ixo797NztPXHUHoTp5QFhA3K2", - "baseMint": "3KTkQJEMJXP741EJBFcAS34Lx9t8GsBYaW2BUUWkeyDH", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "AEEj6d7F79QD8hKDCAHZM6RbAPETMTASzRKxri8Sz3oa", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6YueAsntNE2ofkpLHFgCPdCFyNtHUA1CJFmUqs8Vyc3Z", - "targetOrders": "HtV5d5riL8qvPnGtA5Ei9c2Jv8TTnY6mpRpoZ7xza42y", - "baseVault": "AAvzy3rJ7GCNSB1qcWzeCGshUa5ie1LsF5iJ33L9rJLb", - "quoteVault": "GfYqvf9o7VLDdgKN4RKdAA5EZXSLbh2vbwof5zF2npCG", - "withdrawQueue": "BaquHVrXWroVuJWfW2Kgq3C4XtapAUy28gqcXw2rN4yX", - "lpVault": "CyLgUGzcRYuQ3NS16sG8PfL9BDUkgC21Po37RTMD47EE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "B58Z2Qdru9e9tM7QhUc8R8q4FV1BHSUGMHwL1C58jtMp", - "marketAuthority": "8rjGcupQs5Y58tynt9Chgn1YyJcJ5iajxitGd7pQxHWg", - "marketBaseVault": "2tcrMszmBkZWWjmu8uJ11qYrofkraVVALVDQK61DGCjW", - "marketQuoteVault": "2J9USbjkRdPMGmmcdxGu2zhuRGZWDtTTPaoGCCBfVurb", - "marketBids": "AZLquVoQUkRDTuFsqdNSN7qxw5Ed58cTimm61kQFsPcD", - "marketAsks": "JAbPj5d4hCZmx4wuNZNgktyvT6oxLvFGRhLfoXX4RLgj", - "marketEventQueue": "Cx89P76Z39X4ciqTk2RM57WwDK8cLEwEnvh8dCwAByyK" - }, - { - "id": "8BieVAmqxhSjnH5rLZ2xvvGWW5NQDd1ftVhjgGxyd9LQ", - "baseMint": "76aYNHbDfHemxSS7vmh6eJGfjodK8m7srCxiYCrKxzY1", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "8YXJzgWrbnJDQytphH5BgDbz7ygoxQdD9aBRFZzVwJEJ", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EoNksrmXVeRVfavn1H2fqDbmWKhUnDZa9EXeSWyMojuK", - "targetOrders": "8mApii5af95jmybta45cq5z1vLp9kDkE4W723MStEQrx", - "baseVault": "7KJRrUXmi43zQQga73Yi7pbe4FxVSWyuosPXRBQZcNkb", - "quoteVault": "5Q4ctkxgMF4sQ66Mzg8dT3c7USdLJNWeEktsGHKeRSkf", - "withdrawQueue": "GQuqwx2g9otdBZctrnr3oFyTzgCHm8pJBEZuj9Aga6Vc", - "lpVault": "GaJ4bZ3Hkb8RjP6RKffWgzWSjK1riwyVdQxkkCi9VB6z", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "JCDYjsqWARYGp3JdLgck49ZmPUaVsk2cNnErSFuMcjHf", - "marketAuthority": "ByEbd6vBsA71AYZewPKq5iuJ1TkmZVczzU5foyHWLAGB", - "marketBaseVault": "94AsVVuufYrs8nmmPry3Hw5JUAZAV1eZpRvpiMTyEmT9", - "marketQuoteVault": "2qjzVXz9itdwtojVhigw7GZfuiu7pYEQbtrc1yArrQEU", - "marketBids": "2QTRfoHHhN3WC7yyCdLBkpxjQdymeywDnaMH1Axi1jYe", - "marketAsks": "51RVRQiwxc2Lq4PvQCDKfETRGAw4WKBst31o7RxNHdwJ", - "marketEventQueue": "HU3CATYgrmkRUSw6BrqbV5yxG88Nk7M3pxqqKoekFgTF" - }, - { - "id": "8c7AZcwc8MCJtyRxsD2MUZUQ7vkc8JhA4BdSKZ1nVKVf", - "baseMint": "8iQQtHVnA52oLEvf5rwRWVRh3eBRMRWGvVr5UNEPA7td", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "D2Zp5je8UiqzZrbJMaUAFxhMASJ3cfKBePbNxtXxTnpR", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9MxSkyEGjmgD6TzVWxR6DXsQKB2S1Q54U9Juxi4w7edp", - "targetOrders": "Ba2CRCpyegQL1LWJZLUV4FZYo3oxZhTesjjGL8hTTtTy", - "baseVault": "HkqhDZQteCBozCYEXWy1jStVcwzgpfm52NAUKxE3ddQv", - "quoteVault": "8sYohMP2zRQii7bSFg9GCRAuoejZU18rnA981GJ7wNhK", - "withdrawQueue": "DA3hFMRnMmAbCvw66ogZ4FzAmazdU7cfKNe9wTSEEZNE", - "lpVault": "7DY6cJUXxmMu6ht1XmDFLDHdJFeRV75UKLbadfVWYPwd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "A6qKdU5hzpMVBCMX7Yjf6zanqGq89qLyxU1PXLnjzJbc", - "marketAuthority": "4AnN7kBWjQZHURHdNZrLG2qhC8XG2dmGJHwZKXh6WPUk", - "marketBaseVault": "57ymZ5fX55q4SXZscM9JMipf7LJqF9JRLoeA9TjumD54", - "marketQuoteVault": "61MaYNcbZiUhpt1c2xsUF1fCoayQ5gyA1UZ1uqmK41ic", - "marketBids": "HgSTSnME6C3R67oFVpSVbfpPZQrTmokUGL1cKJHFyonh", - "marketAsks": "3cAWutQtHfVk1HEc56xeycwz2ahbThRsz2J2c5KnPpN7", - "marketEventQueue": "5rVpGeBzP8dXKP3gmYpqMXaxj3xJgsN4v49L7xm1NF3i" - }, - { - "id": "8cxqqGmJ4wzvMGwS2QSusnEiEBDUMsmDT8Wgrzmsd7gH", - "baseMint": "97ner9bBhnmbg1yZXMh85WNYsYSLTqUb4RvyMttD57fh", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "3iMdEqA3zV2NN3kwxfC6FyqaztHfFmiJtacdYcEom157", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7Kj3YViBTMCpjKtbzBWHLTsdBxZXkfjkB5bwdZjhfyd3", - "targetOrders": "3Xbrroyrs85vnjQGofqm3bViWyJQhDAZ9YNkvnLAVJhP", - "baseVault": "4cf6QGVCiBtCpvdTQQnE9WmhaRtAGPJmh4zehFk1BjWL", - "quoteVault": "EjyGdUzehmNj6zsyomB1YfHjQTrmDvNYzRuzpY8ejdsm", - "withdrawQueue": "ASxLsxuzHURJJYdZDt93SFCyfAMLCkt81Z7YWvsFSZps", - "lpVault": "cWPFhzMtwbGxV6g9wdMbGdXK17ewLfvcU6Auzhiv6bg", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8foomSxcVpbB5oHBsWsQwbKeSKBnYUo8aWmVaeBaP3BL", - "marketAuthority": "2gqC8otj8GNGLAcKdHAa7yyYkKp3BpErX75LajyFSt2b", - "marketBaseVault": "3NJMDvoFmnWPuvDqGpquMtgYNGCPzWJ2NnFCg8Bk6t4t", - "marketQuoteVault": "f5Uqw4xFpDdVfw5L5r2ghTJ7tGhvCMzGaAeZiZWTwui", - "marketBids": "2e31pJav9k6DPEUYUtveQ6k1c46jXMnnftkEKYgyVsCU", - "marketAsks": "Ci7FgmNwtk8rXjZktkFT2g69hTLtGRTPGhBR4Y8iZtnZ", - "marketEventQueue": "HhN4Dix3yR4upoYmmCQzp1vcczgWraRAQZffojrqWioD" - }, - { - "id": "8cyxKiRcmRA3PqQu1Rsffc7gAZayg3zrWqBmBFkJndsn", - "baseMint": "TX2FnsJkWvAyjSRoEZsCkDu4ViwZDEYMehiT6U6PXKj", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "21mUV89qFawwzj2qLEXHmzAQaQpTLNnLw7WKjN4SJNTc", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CCA3nk9qzQzSAFFRP6e6osWoPvy7sGL1a2N1FUvwCFnb", - "targetOrders": "RhyBoexneNaYgtAF57q7Ykr77XduxMzcRwRFBPcPtT1", - "baseVault": "52onQJ3oEmiyQL6yze1Xmr4W9wAxJRZ1iA7GR4ewGoat", - "quoteVault": "42J8AFrd7QMHbtzSK7FKzJ2SG4dDUUr1UqGxYtj9YUgU", - "withdrawQueue": "hrCcemNagrdWR25Zo213MMsZfsqW1LqdyZ9GvLQ7AGg", - "lpVault": "8qtcsZV2YFfJdj1epeDEYJB8GdTX2nTe57qXVk7mu7bP", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9GXxVwijTi9TT5Lia6Nq4zb7HGKSfkZ4jGvbPZqKDMFk", - "marketAuthority": "HnEGq7vkdaFqefWrtuTKwbtv51JZfrGYrDwowFYTemjA", - "marketBaseVault": "XhAjZDCEcrnDyBtmVHn7Z39o225DHYVsLQchqWKzyfK", - "marketQuoteVault": "4NXn4ts7hLrVV6LJkehBCStNkoKABFun5HCZsdHeNKs1", - "marketBids": "5Qr53j2zb9CHhkkxYXerAjuyY3zmciivdtNfJt6umYme", - "marketAsks": "HBdAFDkpnf8JfY6EHJV6rzniYBXDEqhWK41ENCBTDxeb", - "marketEventQueue": "EuJPLGHvPynbuLjw1PQw1Uz7DETTsPtuB44Rk2aTa7XS" - }, - { - "id": "8D1uFifk5huT4XLmHF5e2ctnJNkQ9sM13xCDFeXwnpbj", - "baseMint": "6PBEGe6YaKmDPw1Ebza823SuvQWQgGZ2NTANBgaKdxHq", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8MJ4shD149z5YqJVTQuhgoYdP8nKsK3NqDw3QUsU7Dra", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "fFrbCB3XeTXaLk66QKEGdJbfrJ7CGWPGYfqcjpfBW7J", - "targetOrders": "AmhhvmfZvcQdueUYFBS7r4gfZ4Jp9DBVvAMsFAtfPv1w", - "baseVault": "BnVurZBGXGq4H65vHAen4WigoZPirYboTCxnufJw5txU", - "quoteVault": "3nFo41n5khL7gxJbFFXwSgy643bSqqU7Fe5MFS1N9ABE", - "withdrawQueue": "Eu82nakCv9x5fJobdhSL9AFaonmNmhw9JTvLbdSUoZh", - "lpVault": "FqieXLLq9bLzYa41RtbhtcxyGQoFzzYkrNvxrY3KEmZj", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3jXFBpVhrmyVEKk2rQ7Cg9bW2qxhkRH23gpLk862gyoX", - "marketAuthority": "3RYUFerqBsfFdKxkkmu4URPayKDX3FgnNMfoRMdoDySb", - "marketBaseVault": "7QpC1nJXd1QRWuThqSrXsM4TPaDUL2SMQYfxCLBtMsnQ", - "marketQuoteVault": "65dhFw95ynZrtjHsFncsFEQtHWjFoSyxthVuz5t79iAZ", - "marketBids": "BABgiPeNibThikyaxC9NQjcfLZUVqpCu3nt2qkRnnPka", - "marketAsks": "9rxbLq2xR2vkdZYdnZTy7sHSA1iEjj27RFiUUPgNayhX", - "marketEventQueue": "5XD1rN39ySgxGcYZBmNK5tZkZDpJLLTnrstPXxjHRPqY" - }, - { - "id": "8D7JZ3ycGPZ8sAJVSTVa6Y62QQ9NoH1eE1fdsoc9k7pB", - "baseMint": "CyWGk1hWVQsGmDt3Na5MyNcWaEDh6MSkTCvAdA5h1Ke8", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "8v4FfRfyoWFkeWqBTonGWywLZEqghGMT3tD61EUvxzzQ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BpFaPayuSE4CxYdQRovhr3Vzmi2pa6eNZzGPXcbK2V89", - "targetOrders": "929Jwtz3UsfKrGee9smsvspSrsxHc7aL5cHWUFAP9EyR", - "baseVault": "CjffLwoUHuPng1NT9F1raNnPRUyvep8KHN38XmNU77J4", - "quoteVault": "9cApFE2PMNh5623NvaG531ATWUF5AVessq9XVet6Xxh7", - "withdrawQueue": "Gh3No4qqTPFgVHqUyTb1d8inVBh1GhH3CATXfvEfJ4v8", - "lpVault": "H8mNL1wvH6FjPtyxDTG54vGARvzSY8hwGpB8im1fAmz2", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9VHXLBbPJkT2oDmmBuQRS2rNJC9GB9ok5nNe5XdMHUuF", - "marketAuthority": "8DETXFgmTy5Y3tCKsShCkbBYqK47bX79sAX4J6Fiaho7", - "marketBaseVault": "FvKtT53VcpBtHzPgvgCA5R7bp2XfN13xayAGmrLNVwfB", - "marketQuoteVault": "BipgfNqsX8TkkTmzz1xzFkGtNpqYtpSPj76UiCtZ8dSp", - "marketBids": "BWfdj3KtY3NWRXTsq3sZgQfpcCZX2KGDu9CV4ac82MaM", - "marketAsks": "8mCFq5TCdFs3cnnE9xsRawxoDiSJ339k8S9fy8z2t2v3", - "marketEventQueue": "9NcrdErEvuDwMiNs9tgV9gCs6HCXeuYd7axCNf8NjjZY" - }, - { - "id": "8deeKADRaWgEwdfAKN9ibEMEkudH4JPSdz79N6cDdein", - "baseMint": "3eLpKZBgu6pKG2TSpvTfTeeimT294yxV2AEiBKZdY2ai", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "AQ3ccxuw8wcTGy3JgXv3eH2zHHu1TZ8t1qg5CELukesq", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GhfFcKfnuhbKjBgpFnMsPK1wjMHxFxxqnyEYyUgRS7Zm", - "targetOrders": "3ksWfzj412o1QhQi9H9aRgM1SJUqDJWHRjNBzVMS8rv1", - "baseVault": "DwZPNtpbLJEta4w172HsJkjNNbR6FjJpZX4yzeJgrFhd", - "quoteVault": "CFrGkAhf44qVDfLBBFtGKd3R5GRbYic1QsLhRyuEzbYs", - "withdrawQueue": "BqPyg5qyR94Yi7u5922TrrjEKsHK2uULjUcMAkmhHvHM", - "lpVault": "6VBk3VKuJAXPoJD4yRs39pXT2XFTwdn6serPbnSBc75F", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "rnfaw4KED48yYpoZ7JiLE7zf9s7wWeaYGAFcEfEePP1", - "marketAuthority": "GqkbW6pVXWyBxsmerYCYeU6aDaUtoi6CkTzD9Mhyqr5s", - "marketBaseVault": "E9147KXyhYS2MF7rC46PavdhuJYqNoGcheq7hXoGc35W", - "marketQuoteVault": "4Gv2HGDNncvFMVhMaKiAcfGKRZPL9dWLUm2CZ3Ln5t5r", - "marketBids": "5JNyazGGiBHFF9LSyN22MyUpSASrPdBByzXtowC5qym1", - "marketAsks": "J1GMQzijRUR151WLJN2aPBXJQQcm21zjGtuVjX9XM5UY", - "marketEventQueue": "5mTDTH2usmDB6X8u4JoYPHdqWeP3NCD8EA8PXFFaQ8Y6" - }, - { - "id": "8DfQvD1nuZ9SEyEy7TBtsh64bkVg6BLMpEJX1sRi3GjU", - "baseMint": "CbgX2r9YDYjamH85fpMcRfAUxz7wDHrcvh4VwUADFhmq", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "545HQVvgWPF3LLiwePZuJJtBMffMb4PeYYG2gDwtzsfF", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8c1voYNJUuHHLd6PTHR7CVKdL8ut9cwY1u55FsYb8LDK", - "targetOrders": "GgythqR26853Ccqd8rcdfmd4aLDGo1TxuVrDfLoVqKJj", - "baseVault": "3NuYpoxYeqKLKhLuP1qpjq2ZbjpECmbVW2Z13t6pJd1Z", - "quoteVault": "DoeZ9eGn54yUhaKuWj3tnq3suQJiNBkcF8grhSiMcAZB", - "withdrawQueue": "DMjf7nHkcWqGv9sJhpWysq9uq8ct7yXUXD63TeVEjWwo", - "lpVault": "FacfYmAUmAbGKr7QCTg3R3iipMdmioJEqxnfWHaGi6hE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AafbTxhxa3ZJppP6UNcGL2mJ8yVYGhtgGduKWSXR9s9r", - "marketAuthority": "27UfXspWsWV8KU6hFquohfcWF4pJKQbEwe9J4fWCNsV2", - "marketBaseVault": "JEDeTTnb2uGWYDRe6dRacCnGu1pbkUmdTnzoKGEyA4gs", - "marketQuoteVault": "uGoP72HD6tWuFGpeq3i2xr1rhZEnY8C6LmWRM4aoEhh", - "marketBids": "DFKbYaPR7Sf4cfNJ7Y1eE3xw5w3KkHNWgviDFemf7Zun", - "marketAsks": "7fESsaV6ceqfMmfgu9mYgVUpwwGWSRXr9MKwqVpqNNdx", - "marketEventQueue": "3S3PZRg19xkKqqz8mMKXyfkKgWDUUSKSgbwSoMsnhFrP" - }, - { - "id": "8DiLNS9wmszVvFuRgZQqWqGJvEffyBJLY6upTP1mBqbv", - "baseMint": "CYbLZDG7TexKi2axdh4gQGLV3FnXvBgfJgLtixhKVytZ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "H1giqmhr3Y8V6GiTgXhXcvac1kwyvDGSnSCVXxjwpgdV", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GqrBRU7g2DrS88pGCDFm2zTsbxby3wS6Ztz5QjKEShqu", - "targetOrders": "CY4bDVjCTbEDLmA3w7g2umkWXVyis5vSibM2qYLrYGBF", - "baseVault": "4TyDVx2gr8HhHwzDKMyrMwcGhhNgRz5FEJCPLjadvLBg", - "quoteVault": "GiBehwV6xjSEzEtSaGMvLSFS6y5nY3TXQjcYN9Y8tXQQ", - "withdrawQueue": "GTTNmHs5hG99EUb25dFzkKfBtjzA4cqaaX4f5HB32ehM", - "lpVault": "FzQZnwdSFrxZAznXoVTLKJdQSEHfPfh9HAHSvoV2qQB3", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Fcy2padmruFoaQzwC6hMLSXWJ4Loq46Y4EuD5wnPH2fe", - "marketAuthority": "GHENPpfj5NcNg13Ec1DeWRQ2jZnWsbVkDPbtXRoP2prJ", - "marketBaseVault": "7Gq1TRytbq7oqvFhrSFrtGYCsagy4a1DKgoAJegUXqXb", - "marketQuoteVault": "9PZ8PCnExYDWgAEuj4e8nH4pCiWLNPspGDDsaW3RSWhd", - "marketBids": "5mzSLZ2KduygFKvn5eAfj46A7m2DyhTuwzPJLAsuWs28", - "marketAsks": "FhnYgofiMDzEqii9zyvGZ4PTKKHAXya2hzAiAVWFFDdi", - "marketEventQueue": "HUHEL1HmtNjDRZXtHvsL4M5QBbTWPWen93NG8ayMM6wc" - }, - { - "id": "8DkM7FYjLcEPpURrKN5d5BuEmLnjVsVjdPiVFgiTmzZa", - "baseMint": "Pika2wSYzve4njHBwcqzp2QZPr8w18hRwAkugf13BxK", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "855FjfJ2VGe1Rv6dxHXRMMgmzh6Z5z8p3VnWbEKhqgpR", - "baseDecimals": 3, - "quoteDecimals": 6, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6DecMW35j1hmXGfPzhjm4wEJPiNgzfqC3Ej7XwtACyGd", - "targetOrders": "FApzmq5CjDRR1VbFKED9Q6yGg3N3kZtDUUowbe9vUM7Y", - "baseVault": "3r4KjG5YXdZHjchXZ1nj5oRYKdmCn1foEJFHmvoBtcLM", - "quoteVault": "DCXb2NWyWvyxDX7QMfWZ7tyV6t2iD6cESvEN7kxT8TK7", - "withdrawQueue": "4d16QfcLrKeL8u9DQ4truUqx1gdWz3VCo94uSvRoHAuy", - "lpVault": "BDLRzp5wLAQmPEkJE1vi5MHu2hnYu77rYx9PeAXeBsfi", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BTtbWNAVB3eYfPUBuztYpxwNQVWYKN7TKU5e8HDPXCd9", - "marketAuthority": "9uJZkv7JJmiUqDHzSkVedxTrEgzDBmebfnWSzh4wmvjN", - "marketBaseVault": "FzLfmebptN8e4aSS2kG3FJZuAB6N5FnYibZYfJcdbLPF", - "marketQuoteVault": "8CMqJtfa6TSxfaqiM77wypYvyLnumHvyZeQG5tAYWYx8", - "marketBids": "2HQw8WagSAnSih72KN1zcH5aHpbudLJMSdb99f37FpKR", - "marketAsks": "24d4K9uQEAz38SaJbMM6Wp9P4xV6rYVbH3eHtkupoU4g", - "marketEventQueue": "ERM36hZerAXYKcq8L1CBJKvnFX39jBGwcMwAxXUYmq3R" - }, - { - "id": "8dMBvs6sYdbgeRQD6r66N79buxxYCgy1Y7EA3LVEHdBd", - "baseMint": "EZF2sPJRe26e8iyXaCrmEefrGVBkqqNGv9UPGG9EnTQz", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "CXrH3nF7rXHY2vN1g1xVtyKt762XgWVzbigk3GRV889m", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7wBoX4cwR5rYdv7eeQdxm1QxQHtj3NAZYEjbPmAj3ybK", - "targetOrders": "FnpGQQ5x9JsH3HxMqMNRBkAbWpFdxATPPcnwjpKRHuuy", - "baseVault": "2wxpSRHJCuyPcW92UHXaEjsD9bjaph7xTXw5XkvP3LsT", - "quoteVault": "KjKAKQY3ZnurveXqhGQz4Z87gzDwsoFo4v8SS5ng6ER", - "withdrawQueue": "9wV7XF75jwazmyYYpdgzMmp81BYB7BySAYKX69HP2Hjy", - "lpVault": "3NGfvTHApees2mZcGRMy2xF2SvSB9QY1hPo5rGM82Ccg", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2HPLwshKLtj32rhhKpYhsmfBkSomipV1j9dBnQ4Aexv9", - "marketAuthority": "5PFnJopBNgXRvbSddX4eQyGi35Xm63DxY7dzDCvYgcLe", - "marketBaseVault": "5kJTRb3d1QzCrf222chXhyAtpMoBZAnY3EaYWeFggUoZ", - "marketQuoteVault": "3zdsXoiBivxkDwQD61PXc1SWoEbZFrxrHDcxM7qHaeGF", - "marketBids": "C88EmpndQuuSDRPBjTk7KTRkPCtxs3CAaq3FpfX9rZoW", - "marketAsks": "ARRRU3C6RjdqQZWpACdB5kGmohLq3JihR5HKgprT3w37", - "marketEventQueue": "3dWHCpYsvnuGEzQz1e4LGrJzABACLtw7qcCZBQxcnG2G" - }, - { - "id": "8EG6auLQzvmKn96YKWZiSTVwtFu7GgDzfieQDMNPFC5E", - "baseMint": "838ByxAj4QFwA6mhs7gUzYw8tKjZ5NJSw3XQudAuGZZC", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "E8ama3GvU4sLTkWvbfABJmV1sMWZwxQVvmhiLfQkCMHD", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4UQAQQAuWd48i2ucqvHgQrhpGemZF6i3BzmTxePD8mbC", - "targetOrders": "Av7bRxjYhj7zrNFg1uNnfgUiFq7z5ibM2r6CjYvpDLcR", - "baseVault": "FFYwB73bARUftwNWrFsi1pycd5ERhyBSeRcbnBH34HJ3", - "quoteVault": "6guiWzs8uGcEGHvD8gQuKwSgVkCuikjpmjWkkJBPJYeh", - "withdrawQueue": "FGsWM7TwoN1WKhw6zULFTEcP5ZUDte6zvi1CtP8mbafy", - "lpVault": "9acW6krzKDnwGkhfhq6iJP9SofvPopBCgATztK3ApsPk", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8te1jLZr54VQTj6DMZzvZ4cxfS8dSLMWhUQVq2mGMe5A", - "marketAuthority": "7tdajTx1C1H2Cm3Bvi1Eneqq7zNp3hUS1Popo72hZkVy", - "marketBaseVault": "GecNsUVSKHsDb6JNnfUNQd113chkSbsZHPkEe1Wx1saC", - "marketQuoteVault": "8BRSrNj6xEiJwrkjQiYLMXqU5n8UbJqMFYc7Uhy63HpM", - "marketBids": "HLdUhLxW9JRua3Hg95wFQ72ChJSR6pJabdYX4vxjhxvm", - "marketAsks": "Ex5AiwaWh4XT3PCpNpFqW6LfMQaCe3jacwRZcWbvsWg9", - "marketEventQueue": "DJm9bcSR1G8LyaW65J1sSLStmkVmss4s2tQqq2m7mCqQ" - }, - { - "id": "8EhoFBYTExTLRAY2fYRiYtvzEhKHrJoYtKPJYKftZE8E", - "baseMint": "AzZMJEE1u5cM2fVtPFp5K4jyL5988i72WiwQhLCXQTr2", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FBC8kGjEaV9FpLUutPmLY5N9tjhnTLsGiGvYHyuv7W7", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "53XF8xuSNB6dfb6LBAiZZyEGMeLLscLzWT9eSriBWtDX", - "targetOrders": "66yoNpDs2DXM2NgkC9LjhxYHnA2KNpQU2ySe7wETpYAB", - "baseVault": "CzxjBcFf62ACDFDUPKV3PDd965EcHQgto8F82HBLGUM8", - "quoteVault": "5f2bA9YQgYhJp2nqTFaYstqsEYsVCk6RDu9Y8hEhXBAm", - "withdrawQueue": "74NMVR8WC7Wo4MZND13Ut1DXXG2hUb96upzz4vDcPwDU", - "lpVault": "6PzE1X3SCek95njUZhB2Y6xTRLtPhLUp1CZCE5CThjpT", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9ZrPwP8eYgqQPpFUBG9RcXyAt3oJZtNmszt4v8WtF4Ei", - "marketAuthority": "G9NAmXKvtSG95ndTfnfBfB6fT4rhA8RgnVAyfRAjSjCn", - "marketBaseVault": "H4ZHx7nQkifQKLvF8puByM6KEnwY25wy1taz1tX8kZA1", - "marketQuoteVault": "GNLomS7K3MsMLGZCD36GVCw78muEh6StuBRV7AtqsBMu", - "marketBids": "Ch36NF13UtU3Q39GuZHwoQ1anpFq8VJYHRryATk7naqH", - "marketAsks": "AZrgaW3gBKokLLxrJFWccWs5LuqNyLt4BHmchNocLZ9f", - "marketEventQueue": "5Q36GJm1vbYH6Z7NNoWAdsCdDhD8RKvdR9uSeBPeW8QQ" - }, - { - "id": "8EHUn4SPxiNFPwEVWkqU4TXGVYbTXTUYW5A8J8dPar3p", - "baseMint": "GfJ3Vq2eSTYf1hJP6kKLE9RT6u7jF9gNszJhZwo5VPZp", - "quoteMint": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "lpMint": "8oT5YjNm4AKytT1WWdYtFf62f9DQHgajMru2Lt8Tn55k", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2DB1Xue3iZCDByE63agyCJAGAyTKxkyCZLKvtg7NeQFn", - "targetOrders": "FMPb3e1oAp1cRePoGfgTCoWBEXDcqNUY7eP7kprbYZL", - "baseVault": "2Cc4G7PZ1zM13or7Hiwaa4q5Naw1ykHk1n1crqVa1CfX", - "quoteVault": "Go6Qnn5wFKFZoLA9vW29jgGWyNsJ2bJhx2QZyEUGNznx", - "withdrawQueue": "HUeQL3PQzQ13TehWhKNT8kr3PSfLYkbyGPyA7dcbgMFu", - "lpVault": "Eqs5WQn3GC9aYUJswCoXZfLjKxCHmUSp3g3LRhVRj5Au", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8KiZ3ro3MsQAozkQGPKUoh87SYwh6Uwz7mcqgaBeLCUT", - "marketAuthority": "8UUEM5HkaXRNtpKoP5wpfNzr7XAxwgu19P23tbTCTtd9", - "marketBaseVault": "GbUjtNeDPDmmec3VSPjUCydcaTuGFaj8THy3CdNuKLqM", - "marketQuoteVault": "4nLHWtCvTsfiVWUKHdbQen74UgaCsABjo8ZjzLiAMfZK", - "marketBids": "4qPgTZnQLWe4vvezHDgRs7ZhPBazaThMui13At9NaREh", - "marketAsks": "Ad75fekGr2KYwi9MNQPutpQWvM7kerFrx6iUdadE72ov", - "marketEventQueue": "EGAJ5iEcKNAYmdTN3Lj3EP9tMvMcmteWHMfbP8sGqWdL" - }, - { - "id": "8EVBRobU7AistmzduabuqP3PBEPfKcU6nKFEfFJyQe9D", - "baseMint": "2KXuiuKwSxatUSN3bYG9i4Mg9T66PYBPAHvVDtiCfoLm", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "12yD8V56qKSumniwXK5hqPYc2xAWXNenx6G8iXgFpbt1", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4DeYxCpPak2nYZqiiXn2D2wrWjjw7aCKK6sJ2oLPLFk4", - "targetOrders": "HCcbNZgizUG9Xt7Qjz7faob9XQP6XXNCh3moCzVLEMSV", - "baseVault": "GUNgPk7L9CLRdwC2AVEuysMdL78gKnGWKX7wpSibX3qL", - "quoteVault": "AL2Wnpuf77qsdBuRvZgj5NB3Wb9xf8Tv5Q3i88phPFqw", - "withdrawQueue": "GM5fAARtag8P4PN2LbaX4mxqUwCugN798i1QGpwGQTo7", - "lpVault": "GRsXAi4j5GyhX4fkiohgqwuhssQUcq3i9e5EbK81nq7h", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "U3qL6MPNixA3NWV3d2mrjkHuHUyYqEzmp6V7caUHiud", - "marketAuthority": "7z1Z4QgvH6K3rQDa1W4wMkNHrYW2DHkwfYKPSSVu88FN", - "marketBaseVault": "AkaRRX8jWyN1oY6kJfBLR4BfYWq6KLpdoEc38dormJhD", - "marketQuoteVault": "58rhAXZXPYDX4fGtL786yZLmM8E7smh3CLwURJznQpum", - "marketBids": "3vrtckM6HjtkkUeLuCtSwigdnhE4knCCHZikMZz6Lsf2", - "marketAsks": "AdZeV2wwJKvYhWrnpZKhHnS56MMpnXFbQEHvPC33HYhd", - "marketEventQueue": "2yYbB89BgiqSbJaqusJEPB7EPQ8E7f32FTeFgZJT7B1o" - }, - { - "id": "8EZbdbyrukqLMC2CHbcgmLgk49AjjZ7aTRP49q6yBn51", - "baseMint": "2CdFZZF4BEEemnQSSmJF5AhYdGX7pBYX8QVzSPevtRQe", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BwjByhwNBUzzsgYEzMYcZCxzoW8cEc1eR9kGo5a3onpK", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FPacHhajByam67UWM7q2F9qemcr1k2UcomEhEWFe7fsD", - "targetOrders": "GzjsRtTcVKUfYGrZu93mYF9zPBfv3SQcBvakcgaiznKz", - "baseVault": "CNc9wZZBrGjZEE87VY2jdE21gkM2M2h5feEWnwd7SJrv", - "quoteVault": "GAmHyeyHTC6acR3WXqjXXhubYbBWhdrieCDLxGaahqc9", - "withdrawQueue": "6qBz4onmHvswFQuLXtDKX2c4kcdmG18XUphFFnkj4RKs", - "lpVault": "3os6fSjKP2D86wz9kV6EZqESqqZEvZCmRVT1P2Hwfqhr", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6SRudDyrncqfCrd1Ex1vdd8pwAiEdZHfhmJ7HRABG2t2", - "marketAuthority": "98ZLxJ5V7BZQmScK78guVfvyRwLDCGHyGYVXrmRv3PKV", - "marketBaseVault": "9u4hAXU6tQCwSB7nH7qT9MV35jJFXYsdBHGv8kWFDyyo", - "marketQuoteVault": "JBnb4eBsashnBG7Bsh7cC7vCig8cf3QYDP1qbLKyqhYU", - "marketBids": "6sUSzQxYnKAU58SmDDa5KGk4dmZQ6nc3QDimRTMFktqW", - "marketAsks": "Dtjd2nGg1fq8Wkf7wsWwdGQPYCkEMBqgwwyo4fUNbNpv", - "marketEventQueue": "GyRcWy4dSCznrYKZHxNmWGhY1ArqvRxqakPGDst9dXS" - }, - { - "id": "8fB4zYcosGSEbyYJ8AEjD9rSvywAcuMeETLN8LLjA4e4", - "baseMint": "5DfhZugS25gPf84LF5u6LjRCzW1XCFuRd88PAujoeic5", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4UQP6AhHD8v4JQ4S2M79D7zuEaAmZQK5XSE39CUeT9Sr", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2pQbh8mBD3feMpCBn6asQZbamGdrK9yFGYW5dQ126aEt", - "targetOrders": "FkPRaNMXHFRKqERE8TWUKuQdhwtkBWbK7JKZaMNScDi3", - "baseVault": "3sqSb9BgSPJEkKwFj5fgN2m1F3x47oTBFQPD2LjyQoJj", - "quoteVault": "5poiUDb24KLbdSMdVUknbzUQZioqHgP7pFNS7wND248u", - "withdrawQueue": "2suiTw29UX4GtrMpB3hqSSzDaKU2QhtV8CJKen3QsFnv", - "lpVault": "AmHh5LMNMbUqCzEDYy2RzsyKSeSCQYVQQDwA37am8AU5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2ERbMZfu11CxNyQV5A1hEcHBDSNFS67Tkwaiqf5xDvJd", - "marketAuthority": "9SpLau1wMMXkuwDYe7DTBhm69HiCH9npzEAJwhsTBsyJ", - "marketBaseVault": "6NUfANBz9r9EaMn1xkmM82xXFvgzMetEJMAqzdGVUs72", - "marketQuoteVault": "G8rsvUGpDRPzonZtTHL4o9Er55bUY5md2gEbHcXXSwoK", - "marketBids": "G5ULXVmozScHMbrXS64tjyZaFWaijSxsG2wLm4Mw7Kse", - "marketAsks": "2ZHaGxLUhQurcwVQULrXs1AKYbBkfq9UXg81FwPzTUgy", - "marketEventQueue": "Bsd4ygCKJ8UGdBUQkCmMusJgcHdqNnbRzsnvD7SuG6yL" - }, - { - "id": "8FU6WDhQBxSrXBZEXnoTQ6gvuztiWrwjHBcAYXqjKudp", - "baseMint": "7ScYHk4VDgSRnQngAUtQk4Eyf7fGat8P4wXq6e2dkzLj", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "Dpq8hKWnxbHcK2jJjRAYBM6QH4Ryjkw9d71GzfQdDWu3", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6iTXGAFi8mPrXFZV96TcDNj4NK1Xd8gCegWr9MHn6gGU", - "targetOrders": "8Gb7VA3VtEPrqciuhCxcLGBuCnFofKr86pKC2CwUt8Mw", - "baseVault": "AZvdQiR1GdTpUhQkwzoqXKgVCnHyhoR3wsMsNcZiWDP1", - "quoteVault": "SMMxR2USQVxHxj2k8WDNqZJP8jUu1FijCn8xpCamJ6U", - "withdrawQueue": "DQ7jpY9NY9pKb68y1ULYhZrtgbXKYCZvdAB6WLzTMj5G", - "lpVault": "BJMw7S8MRdDGyXcLJZQSznafUhaJ6fNym8VR1NcZm9BU", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HnYTh7fKcXN4Dz1pu7Mbybzraj8TtLvnQmw471hxX3f5", - "marketAuthority": "8ceAwuvipJUKjW8yEPujjxZdFbYENV64XtDPSuzFZpWK", - "marketBaseVault": "DU7AkryQBjazPPFv8aLzE2pCe2KYcBm6SNvQ8UGYwrAQ", - "marketQuoteVault": "5P5Tne9wdGgkMHzTWiQLdvyJX4c6oeZsJJGjBrr9pexq", - "marketBids": "HbRCfuMkxh91TfFWLxVYy7G3Mfk4joHFMh6D4SNPXJE9", - "marketAsks": "BjCEaNheizdr11nnLLbD5rmyL4nt4XsdF4EB1t3HTGBi", - "marketEventQueue": "Fj1T2fLQJ89epkxGpQycABRnR2f1Bi1h4Sfoo5WcjyCe" - }, - { - "id": "8g4Ykf8AMHPrerxbNM1DjCiVqF8niozsetUJ7wgyrHBL", - "baseMint": "GVsdtSe3E2fQoP3TzNT2M1VUchJ7sBmDBuvBZmGDGvmB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9UYXmjn3pF1SvVhZ8FNYM9thXa7waQMJd4rCcRAt2TFJ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "96XEYZZCpSXKsxEVm6htzHmCKCmMoYYTSknQVP8hghoD", - "targetOrders": "6hRXZN76Bbpzo6zQa1dhNWyQDgMPd7iiKgdKveoQksZE", - "baseVault": "ASQvhYz3jw647euA3nuXmPck3BmUoacyEFttkRQzhwms", - "quoteVault": "BfdguzMqyTNdTMo7Hp5t5dXTU8kAtsPgYc8dQyfxDWAX", - "withdrawQueue": "6bU5TbypYxLpyPqVnUoiajC1GHdgzrGFeYFUATnAvgrt", - "lpVault": "ny5LquobpLWXGTebBeC3QLEV3xFyHAaUYWtwkUfMrWA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3VYVpvYbHiDmUUE3P79RD5bb2w9EYgd1NkQw69JRWHqv", - "marketAuthority": "D1nCvG9gdjfWGDq84oQaTjKZxDT3bZHEsohcWERhG41N", - "marketBaseVault": "EwhQAF3s2Dq1dG1T5BdfTEPN69V6fmzL2N2z1agqU1HA", - "marketQuoteVault": "BucesbBHEkcAEr76HUv1TYujpij477oevdbj12zBm9yg", - "marketBids": "G826cGyt1VCsDLTsMi6EAyDq8ACSvA4s8crhqWJ8AYMf", - "marketAsks": "6huNYyCeicYSwNescUchDBq1LSgUvZcRT8idXDknbXJf", - "marketEventQueue": "9imKgy3PaWpURajsDZe961QgpJzjxhCkC8jcHCKyQqCL" - }, - { - "id": "8g871VG5zESdurdtxJg8BzBJVZuBcHVSoVrNfjhSDN7t", - "baseMint": "iVNcrNE9BRZBC9Aqf753iZiZfbszeAVUoikgT9yvr2a", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8yt1TimPfPHs1VMD76YskdSFXoBcBsUwGQd58bsB3hfx", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "88aseETCg1ttS3yYwJXby9poeQxLeSv1poWNyHrW5N4y", - "targetOrders": "GGGeHnoYLgniFBmkMhiS8mtpm2HqEWsGyNxyihufygzg", - "baseVault": "Bb2oMyWsR3CstM7q98L6biw3xv6c5aF1GyGrBXQVRr8b", - "quoteVault": "65DcFpHuX6kjv7jEGzXQXTqEF4M4DD1kaZGdUjShFsbV", - "withdrawQueue": "8HmXr9BaZRroU2Q6zvoaPRLCKth3c7ypvUL3M4t5rr3P", - "lpVault": "DaimDqpTmQ8Gokt38q4j4Lye3fWeVkSWEVRbmd8uVRSB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AdmfUBJ64BTsjaZdtu1iQHAtxJ4Ge7Zw5bNMsrLGdZu7", - "marketAuthority": "GRvzA64y2DuRFVHtwQrNjRWnf53NqEkykFSfwmzVUWDG", - "marketBaseVault": "EHiqZhT99p2PhA7SsohnPjfkR4AkUKuEAeUWDByecHG8", - "marketQuoteVault": "wdgvn2SqsR7nmNBJZWP2bDFHJA2q1D8zQti59Xv11du", - "marketBids": "13iacbPp9uLSyLT7tsE4gT4tpFgKq1Quivr8oJrh7VZS", - "marketAsks": "CdBpLjpqBPGRZ19eHBZ5Xq2m7pZkniUdLJLcK6r2xmt9", - "marketEventQueue": "TWMVPFa1swLdg67yYDPSAfhzcqzG9Q9HUsATX3MU8Nr" - }, - { - "id": "8gaKoNXnwo2Xe3QuuATvgRnk3YHsiyEgX8BtqTs2NqjG", - "baseMint": "FHeU7e7Tyw5bNcCNiM1jNVoT5UUims7zRi3o76Kdz4f6", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "CBofNNwFHSWVZqsQVpX1GMDucU55RpNN94ih1WfpLuCu", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "H39b8XgfX6NyowsEwwRmc8jwFmyYDyYCh63jtrsMjXQH", - "targetOrders": "9tAuboeAAxdyUWKgGZe2kC7sHUX6KFbbTqT6VNo2WQaj", - "baseVault": "9n1CenYyRXXjJiecoPUqfVB58Wss7txViH52V8WArxBf", - "quoteVault": "H9nRBA9xxgZBB6S1Et5uATUJzaWLKu1ZVcjkocDwS3Vz", - "withdrawQueue": "FVeDFjkJtg9Kt439CmUjYF7eWnxnGjEL5w9Xgee3zYGk", - "lpVault": "DgqiGcmV6pqzAgwyxB4e9tYkpvtPwfkPiqSKjZQMH6Q6", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7rXCxHdtgPvmptcrwCSuHEeDsJo2hSoMG342ZvVRnZJs", - "marketAuthority": "CT5ycVVpt4vFRcCeVYmUBLxWvKTd9A9PCfmSnxYvhpLy", - "marketBaseVault": "3PXpZ6zsm7qXM9aYHu1gJBs49b8vZQxyY78v8a1B93KP", - "marketQuoteVault": "83Yfag82Jda3hHenh8VfDd21BJhzVg1QDuvgLpFsFte7", - "marketBids": "9sn6huBGZHVJhnLjmf3Y39mQRpEVUY8e6o231v1mDp9v", - "marketAsks": "A2nmq1fqkvpU6y1si4eQESBkHu7EFfHBsPnyGj575uQF", - "marketEventQueue": "8Ra9AJVRzrc7KNwX3gTLh4mZL6vNnvmNV4k31nsJzu2A" - }, - { - "id": "8gC6dWQD4EsryjwnM5cDT7K75on84pgwnUuZrotnuJen", - "baseMint": "rvxo8t7TKeSmAgpdqK1CY9ddZi3NyowRCh1m2d7KrUc", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "B4pykRYk4iLumBTH46Lju4FWCzkukRS6Ezoo5X5yz5jD", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FjXwJkKMBSVikgAJDaqxYKHVtU2egNpeJmSJuCrqMwKy", - "targetOrders": "91TWskbJCeVuCAt3SaKJcJGUVizUGWBjXuCgRVexnAgD", - "baseVault": "5VL7hx6L1iGuhUjrSzafoJSmbdQJy6nHFrCKoLsDXoQ6", - "quoteVault": "AoiXGHVZEyijR2VzEWmkwkjcSkuXRMjhxsTU1nv8xY9e", - "withdrawQueue": "HvhcdwkgLdqosHN2xe2vqGBvx8KatD9ehiVbkn2mzoEq", - "lpVault": "EeTJofyGpCPZcnLRpURzjKBSEnwfiJd39cq74D2cS5GF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AuVJJQiN3awPXXmUE6H1iYGQ9f96pfrVNQkdk8wsidQu", - "marketAuthority": "FTNLYkFBGaDh7Jf9izfJU5VgRtPfkoQo6ZEzkpycNGJC", - "marketBaseVault": "Bub4jQ5Vg3eJYZaLQbUyzSsecEbuWvKmsMQp8a7jBmcM", - "marketQuoteVault": "BkBPJksmXd58931gd5YTNgwnThdquKXG1pzuDPCPUa3u", - "marketBids": "EpJ1ka9PFVJDBWFXb4KC65odHX5ZT3JCHsqEih4HXxeh", - "marketAsks": "Ch3CfwyxcaWH99irk3USoYz8pGKj6QgPwijHfoYSxJEt", - "marketEventQueue": "CmPrvHkHYueXViXhvHhv7eTWGQPCP7JJPP7vgh2wbhVG" - }, - { - "id": "8h4JdD91gyCbPDDocEU8bbGERmzGCyEZN2TVqhFPFsDF", - "baseMint": "6gp7itCTmjv8tzrhUeB3LKi6DiQBmBbqrsUxW7CitptU", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AgJdr2Ac9DG4uB1imdpyd9LVDb9nWEzZCA5njH2jYCzq", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8PNt7DawKf2xhSSTbZYbR2fqg48hqrN4FJMJgB3aNV6V", - "targetOrders": "9WihYE1yaFneCSomsVmpZYZ9YncE6qEAJfkiv1LzJuRN", - "baseVault": "Gmc9LPuVYbq88AtDycVyoJGi3KcoTUidaaVcN4gaVk97", - "quoteVault": "F2dW5U84TtbbKHWTkJ2VhPKwBRopqyJf4V7JpSpiV14L", - "withdrawQueue": "Fy7eXhRj3o2M8TPFwaAKmv8ht2ENSLy9RAvvead6bQHm", - "lpVault": "HdEYubNjd6BrUaGNRCd4m6dzWSnrP4V6g6HVjVzeftUB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AnaG1TDvV4N9Q2HSHpNAJX3RrSAsAZLnnam98Dr4ujDf", - "marketAuthority": "GjWSwMuG177vZ1ciWSaTK6YHmZ8pjJqGKphY83U9RShm", - "marketBaseVault": "EDbBarsWBFqPRt54w2ArP1CwRgF3tZU6HoCA44XPFt1L", - "marketQuoteVault": "HjPBu4aSbBWFKLET1rdv5FgtVC8QthhNqhVTBwkX6KrF", - "marketBids": "68HNMGvueF7CikydVC72BUm6GLh2FG9bt4ycY4CyPLzw", - "marketAsks": "31Ur4xtBKwTGvdxT4Gz6sbTFJksE86Pfsvc5iGoSxCwz", - "marketEventQueue": "83bgSMvYkDKZvZDN8YL9frPzuWqppQV4dXJVMjmZ1LvU" - }, - { - "id": "8hXJDTqkwXFLgYsKAAQe8yNh7FjoDQVP46duAHGLkdK2", - "baseMint": "5Wsd311hY8NXQhkt9cWHwTnqafk7BGEbLu8Py3DSnPAr", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7HnBaMZwUA8FKhsiHu1xsxvwpxcGMoDj7XFqgmFnw6ft", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CvEPvBAeyNFss1qoTnXSVpUacuC554D1C2ZChWxskBYR", - "targetOrders": "4p9GajfsABzFn1AnNd8QpcEafaxqPitK41MMivLcNDRW", - "baseVault": "AcpAfrUDJpUVSmU1ZGhdV9pVymTSZSpP5c2qW5G3yPF9", - "quoteVault": "ECrk8eDDY4MuTGKSmnkGLdB3rEqYpKwAsGY2MFH8PmZS", - "withdrawQueue": "GBnd46Uc4uHkG1ypNKHbxwrjhFjwVftyfDqEYdYBQokz", - "lpVault": "EM1aMtxKZGcA94LR9kRYoSK1NwwUBDhUrp5UeuqAXr3d", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3Mf3bxVS2zLW3bbr9BNbqdiizaUwCGwoi3xhrAXfbFnW", - "marketAuthority": "3orCMmXSuPvHidNMNdhsoKD69y7bTWzh3FDKFnbgH7Lx", - "marketBaseVault": "4q3tUtzzSATZWeJjgVUuqXazwWeNAevub2mWdck93xhM", - "marketQuoteVault": "135MoxVhmZR6dHS2a1ipRqwYtxp56ctvbQAhrMnrBtRV", - "marketBids": "CHBBEciGGKWjg9ARoBcAQGeYpeQh3FYDdyzQQvLbWGpj", - "marketAsks": "GiNA8vMMzqwzwQarFjBNEyRTdFeMKagUQZoDBWKrKUU", - "marketEventQueue": "D6mUBLknH4G3Q8at9BSegjxCmtq97e26qJEqbDRQj5xH" - }, - { - "id": "8JDbD99C5ghrCC9H2UGhcKbmgCkceQ3GR1hCxct2iE7G", - "baseMint": "HonyeYAaTPgKUgQpayL914P6VAqbQZPrbkGMETZvW4iN", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9VHdyqqANUieSs65S7pnMRVjAwW5BiYjwh4AeztoKgSp", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "57UcWNRUJdAk4z7L3Pxcaj3fLmV2SiLBRHjeMGZAEdhM", - "targetOrders": "J7ZrEjNFVQmHQ4otXiKN2z2WZv56Er5ezTueMR7mgbDu", - "baseVault": "Dr3Yd9Bxm4YsKG4Q392VU3ADhNgbAvzV7Fad6qj7b4TZ", - "quoteVault": "CezNrSE3xAj18SMAiiioAncpHG33LcxRUpaLqgvbqhFe", - "withdrawQueue": "CaPVzzUu3MvBoygWpnwuLc2HWjBGZvrabDgpx5RirqY1", - "lpVault": "GSj4NRPiS5Lree6VinXq274jR1E7DNkAhaqaxbKjjB8M", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4bhcTWnsVV6LSUJMQu4FqGL13DQmgkvj21MrFAhhSdPq", - "marketAuthority": "Db9fYaXnLuK6qgXHH5tgzw3nx35mFW11VEuHTTi9AYmT", - "marketBaseVault": "cxTr1zfqHEVvSgJz9KWehEJFx7dRDecEyz1QvcBmWza", - "marketQuoteVault": "BZFL65fVx4UWjkSoV8Ndkju1rYqanj83JhfQeDv77xvZ", - "marketBids": "FEwsaV3KvzKUYVKm3GUrXrMXgqYuSTvKcoGJrzAhYFfc", - "marketAsks": "EEML9hdBjP19ztwP8jMwvM9oyYXq4SHaQRxAmigDSboq", - "marketEventQueue": "3PkArUK3HdpkkdUb3AobizrYoTYDbban6qCm2Wn6Zrwj" - }, - { - "id": "8jvXwohR76nEf36V7ujF81BXjdgEdnBpqP5YGszxvLvg", - "baseMint": "roCKojKezC7HhPxph5qb4UBasvmZJWgegCF57PvaV2f", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2yWQvsFGZzvj3z98LWsWUQE6Enfx3aepyFmMhySXz35j", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6x7LzHFaE9DRxASAofXtGCY9wziQweCJ4cDitgFUzBvJ", - "targetOrders": "2paRN9Yh6XWWTVTF3FVhxyffPFme8KY8RJkXXstbHZti", - "baseVault": "2cn7ZXQgK2Mmo2qPaDD6NHseAQN1ip1bBV1Wo6iGc7c8", - "quoteVault": "7KTrvRbp2NLy24FPdPgJEUeaEzYDDs4jezi89aeeYiFV", - "withdrawQueue": "BLkFchivsHLyDmtSdq6ukxFZscfe6morhLhMFvhv5ECz", - "lpVault": "9Fxw9BZZEsBhRQToXZLvnfXqENNKSsbHpkTfdfbUgGD4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "26ChMq6ebUvYs5zkHbphyz7sqL8R43NG4ymT1J53R56i", - "marketAuthority": "BMFBZnhjVhVKgCAwBEPkctifrorWTtKtzjPybkscAFTH", - "marketBaseVault": "4g5fC1JgFzSJfZ66YgYEGYzkKmiRJzctvjMZ8m79Zr1N", - "marketQuoteVault": "8ccwVrgaHzpvGJivGMTqfbu4uTGz5RdggynEf4MWGquz", - "marketBids": "51ANun2i4LNvfQS77u2hAzuih3UEA8FMZMKGCevEcrky", - "marketAsks": "722xvobhYkQGNon4bufr4iodeygBHEVwpwRVTEinWARq", - "marketEventQueue": "G6nLGXqaDMBEg1cnm2gS7ZK5BGRtfmK9SRPVvobqrVTA" - }, - { - "id": "8JXuPz7mKBX7gnfjTXREz9VEEL4SaUDhbyjJLMHkjaWp", - "baseMint": "Fp4gjLpTsPqBN6xDGpDHwtnuEofjyiZKxxZxzvJnjxV6", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "HdyBxyqcAppBNXfWFTWCjz2NBwmkyoKpaPm6Mu2P6pZa", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GGUM63c3LBTAsLbzriYK3tKsRDXBPPrUMPiAvBAWNhmd", - "targetOrders": "2ArEhkM1RP9MPUNuw3h442HTQJHbfzNnj9d354rjWkM8", - "baseVault": "7qtYb8FafzMJUmFEWEdxx3V9ZHeopHPyzq5AisxVjC4w", - "quoteVault": "FAvNu91oxwyztUDwpnnfsXuWYAYifU2HU65SAtBHLer3", - "withdrawQueue": "Hu1NUFENEFKScE7pUJnwLjtjWpkd5gXezxftvNtJdP9z", - "lpVault": "CRT5FmaRCqvn7Qj9q4VuGhKCVRJgH4t3gbTYHabddo8N", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5WSgaKbwpuy18jHg7mCUXY8YhTL2zVZZkeXi844YTLob", - "marketAuthority": "CoQe4ty7rkZfjknZXTRMp2t8658WvYMJNd4t3Ay2qAzu", - "marketBaseVault": "6PotDLdb5NgFNhZsXyB7jjU2S2p3gS77cTx8xTqngcmi", - "marketQuoteVault": "A8jCz5ZvD1V1Mvvna5fNYGiQb6UDY6i8gTuzxZz5o7Gx", - "marketBids": "DhKAmaLrZL4ArnbsJHTKh47sXAUDt7cgumVJBZ4vm3mW", - "marketAsks": "D2KpWGzLCCFMCWC2cCwAJWGcazygBM9nTy54RfeTMKm5", - "marketEventQueue": "2CnGQeN9BYA43dinrLmnVpArqfMm5YDiGVF32maaCznk" - }, - { - "id": "8kaADK5uvBXENPfCUd2XAxSnfeZCpCJ4B2GimnqdA1bm", - "baseMint": "BgeRyFWWGHeVouqfHfcXUxmvfkgekhrXYVqQWf63kpJB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Dp4PsBfb3kRwCHcVswSNzgU6P3cDCBYNcCs5DhE4SyNN", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "28VGWJiWHhJWdGv9jN3bTNGsZnak1psCjhg1r4dHb9yE", - "targetOrders": "6GNdJy9apEUZtFwpqcGMCYeu4qUH9DJ8S3WXu35eMp43", - "baseVault": "E6T87aNzk9JzM3JJDfYidYnyy8k8AjiFWswTEc3Qmr9Y", - "quoteVault": "6LTCHKBZhwiCN2LQUoJfgjMhXrogB2WSag7yNc42mZn5", - "withdrawQueue": "CLowE3UkGzFezWoaVDu8fGvst27cffPQyTB71h8QCeGR", - "lpVault": "F3UGwubxN3y78vVp4T4kQkYZciXdt2Uo4XE4HSsjeAY3", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5ygcSjBuorC12JEzf5mvDzcWpdSLPDGgbDU4LompEFA", - "marketAuthority": "6qWF8tr1uskMUmpzupE7yDc6tyk3VDeNsaEd1cwKeMGN", - "marketBaseVault": "6ZibUhCPPoEmpakKebLxwsVkqBUEd8ymM9ZeiLkZPoLa", - "marketQuoteVault": "2UJbezhdBTFLdWbFw6BsytVcws7nunXsAQYisDS1WNu5", - "marketBids": "SwtZmHP59SMn3k7a9p5YTxaeaYe6gCBLbACtAjqdeh2", - "marketAsks": "7JXXRRGoUZ2fjTzoRvgqxYmUH5pyqv7bCB7hCWKeFc3q", - "marketEventQueue": "Ahy8WDP8E7UxjQGL8cRUCwnL5ELGfCZBHmgBrdDBzPtf" - }, - { - "id": "8Kq8VzrRRwSoRKcBWw7SdmZrqaxH73oYVyCcFsWXzCqN", - "baseMint": "5X6AuKY8QF2xzYUEYYCxf9t9FXhuG76hHJNAB8qUbKqz", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "F7ZLpunPQkEVXz9o7BFqNGM51JNuKfQJvTC8xu63x3Z", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "K68688bSFepaJ4yMsR3tCtmQg1QKUYYjdMRaWBGFCe6", - "targetOrders": "9Z7CV8pev6WzW8atnxgLZxWFTxbrCC4qZnetH6F2CBov", - "baseVault": "Fz9tAKrEUsmRQyecwhYV99AiBhX1Zc6ti5G8wAWoeyvY", - "quoteVault": "6Dwtf4RArC75wXq65YHseu6qSGcs9cvkV5pH72DAZhpH", - "withdrawQueue": "y6vTiaxtZwqx3ZZLZce75FsHXWVJyGuRKEcd9oLGoxa", - "lpVault": "8DMKpf2GnRxZcDtd5fS2inoXuL8pDFZ1nWKAwe8YUr8J", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DDZp6ivtNtM63JSzmv3Q5fv2K5zGaQP6ZByjhFhXcyGF", - "marketAuthority": "Hg2VnZmQshfKiv2qQfc4enfXzc9AZt6JBesNsgB9ySfM", - "marketBaseVault": "AXjMyjJFzg87AMT5b6aN5Wq3PyBbfvj8LXbnu746faDM", - "marketQuoteVault": "DJGhwHouoHRiw3LpEyRVYtjKxUFfNTKg62UrKoGysoNe", - "marketBids": "GMqUMKBZDB7wR2pT6tMyUymB6krMZYCQDRFDiVFFjkz5", - "marketAsks": "8vMiwPsdWTYqau1VFG9VuWKhqoNqgfhUmyB568FcVvj2", - "marketEventQueue": "J3VLj6dNbhdsbqkKsLJ9G2Mk5qpPrkuYX2GxuoLQL3YE" - }, - { - "id": "8LxQdphP3BuYiwKg3t2tVLDTmLWy5XurBr6u8BidSJaJ", - "baseMint": "4xU44oSF32sFXzTG2PRNhsxJidLegyGTGV8Fmu5grLFy", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2taUu4N1XC6vRp4NrEatdtuJiq3UBbjM7S4mnwULZRXF", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FKAYM9ykTANVuwZoyqukMZr75KaPJRvaXvFLoXcUbKXG", - "targetOrders": "GLF97QEZP1yGasJRyWu7CxvDACGSka5tDvg9EjYKjrD8", - "baseVault": "7h7xPRnS64Y4DSszDKAXNCrrQQPsjifrDi4TDgMcAQs1", - "quoteVault": "7WapeGCWHGgLrw4RhrQFLsb4RkNTJNLHzWQQgox1hPpi", - "withdrawQueue": "6RFYUcPf99ZbwmkUQvz98NbdBoF9zfiLbdSNkrhZnvWg", - "lpVault": "AxXd4swigcTx4XKpshb215JNStPqaitDB3Qikd3NhPxD", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CyjC7NNZtygA2gPpY2Vmneinwi22bagk4gB4LuQ93bFX", - "marketAuthority": "CFK9p7sHUk9SXGhffeNkNAWat9WnAbwqbMpMPVaUhuJo", - "marketBaseVault": "B3RioTbeRpGoPLLc9PViWf6uN7tDMkEbYqvoSGncpswR", - "marketQuoteVault": "HVJGzQMttPMNYUnQrR4k1NP1Gghtijym5dgRBY3ee59B", - "marketBids": "Btn8EErjm4hQyQvnyHtksJBpmk1nmqGabKdP7qg1e8ic", - "marketAsks": "5vzTEMevZLecg5TRGg7kjyhwDgKubZyudC9PoJ8FkpwR", - "marketEventQueue": "AqdisECP57aztULrzyZmymF8hNBvuaX2pT3ETwE8s88w" - }, - { - "id": "8nKwFyJ41BoKKdTrfNopJKs6C5PFPZJ28Z2PrMmjo7y7", - "baseMint": "GWTipxSJVPmmW2wCjBdkbnEJbCRCyrhL2x9zuHRPPTj1", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3boKEcd9pmUhEhfX42GH8VeHEGHCJx2ro6gb2r6Kh9Vd", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GEwRuDbBpgBcEKiiWQ3sxPGDwJ8pwhz1iNGdNUuBWpJT", - "targetOrders": "62XWDJkxt95J3ojKK8v6P4PTr4n29fFj27eaPjWVK1fJ", - "baseVault": "8nCcLHgSmnVTRvuLuDZvJN2MCFNQZqnBwqynn83joVM2", - "quoteVault": "HEH74VVxAPRhcSVfvAV1bvXV7Jgci7WWje9m1uKob5dt", - "withdrawQueue": "HFJBAiXLLH12NdJBGd1LXuBdA6SXznNjpZyP3xfshrbw", - "lpVault": "4hZEtTtNJCD663rR6LPtppbvenm43iYFCiRx48weuSjd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5x3bGKUXuVaespU2Ro7q1y4fNou4UNXtAKasJCogAG6x", - "marketAuthority": "CoiQxQoZfnuCWyuStvK8tbPzE16ZdtSDMbQCJJFJTxAA", - "marketBaseVault": "3ydDxkGqszo9LNidNKLJAaL854QKE8yk2RTE3nm7GvEV", - "marketQuoteVault": "CApdYk6kUTzio8eEM4YtHdq7oSdES436RqGFV3nyZBqX", - "marketBids": "EfyszAWf2esMW8s6ed33y7GAsbBXGWXuW5K56SXzTPGc", - "marketAsks": "Hxe2Q9HFJJmcoKRfFmjtL4FcTMsbEYM643T54wsr6PoN", - "marketEventQueue": "26qfwYFj6vXS81eFhcKsHec9mxj4d7Sj8GUdgoSokAFr" - }, - { - "id": "8NZ17JP5toczgFCSCECbJKo8ZDCQ3tf6RjXZT6ZfXBbG", - "baseMint": "GrTijpVPz73pvrAeMYW7RUZZw6ZcyUGGovAEdRu5dgcD", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5UqXampLEM3DLVcYuPMSuNLfqpichAKSUubuSfNXbTd2", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GCPfELwbuD9roPThpAMQ6AMLGNLhT9RwF5ZABbg9tjvP", - "targetOrders": "5baLKPbbNvGkVfJVY3HcYjH7ZwWtNV1RBunEfT9KC5aH", - "baseVault": "9ws9Hn4tpNQ27qkmY8aULzD6DRHQvY4GgmLEVNkHj9hL", - "quoteVault": "CHa9mp5nTMtioAdrTPXo6eRkq3FEPaFiQEBfJeqxfJSo", - "withdrawQueue": "pfFVn6bvU1XcZEewqPHwzCWLurw7RSUD5U2LzXeYVSm", - "lpVault": "C5jd5CZx9WUezX6mpfFM1mxr8mjuGCWK6tMz9mzgchEd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "47ESmQNouLGVEE8fmjHBC7Ni6yy5omtB9JD9Em6PGpiv", - "marketAuthority": "8CAwao8ZemZ6gNLy6pqXBgTyPmvQpbAiPRVZsr7MoeNf", - "marketBaseVault": "2GJ9cPKc1AWfasYNXYuqJqVKZXphkuYWKy2JenQGDSbC", - "marketQuoteVault": "C8RDZSJczkT5MG9SP9qws8fpLbwawmPsvRos84hUYPv1", - "marketBids": "Efp2soDtZtzbdEvRJzUJqebdQDz94z16AdJ1CV4vk5RY", - "marketAsks": "Eywb4M4wJ9RqQTvTTSZkTVjK8vZbxCpiPDFzstDksUUr", - "marketEventQueue": "93Ucg3HDjb6kKccnUr6MVGgAvjZiyVQAxwCwVGAtXPWK" - }, - { - "id": "8PjGAMT1xXFf7hBu4M4N682AP7TZpXRKzecQ58Y7ceSr", - "baseMint": "8ymi88q5DtmdNTn2sPRNFkvMkszMHuLJ1e3RVdWjPa3s", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BemeAerXa6afT4WjdF9A2A9Y6aS6crAxFSdz4MkaZbCe", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HgovbkvirqK2x5K48UsrxvVTTSBUKBDN4ts7A3PoF3tL", - "targetOrders": "4VAjF7cGr2f9kbiXmzQp2uQDH9gz9XBg6yaMURiD7Qcm", - "baseVault": "H1uVMacCaCPBswnBEnyMkZvdAEcodbvu8e1rv5v3o6a9", - "quoteVault": "FF9FPD4QDFonF5FKqSL62kj1NC9jikTwQdquVLcziy7U", - "withdrawQueue": "9MVCQUKsXEzTErUUoDGWLok5RWT4BjUQg85fHTYx5jhQ", - "lpVault": "9jeSvzzvXtHuEvirmsQsCR9iW64UaBvHmsy5e3bkLATD", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9aruV2p8cRWxybx6wMsJwPFqeN7eQVPR74RrxdM3DNdu", - "marketAuthority": "BxQkthShBQekJyRuc1J4MHBJSh1sp2tEocSfVL25ABVB", - "marketBaseVault": "F9PPDzsBCb87sCnQrVGweYErPuxExx965eJGFjKx8QZk", - "marketQuoteVault": "Eci9BKxCKgAXZbkFgFkwzT8Xs3i1ewiaBAGYUVMd7WrL", - "marketBids": "DycyhrkQZUBLGX497fjXRze25Thq3zD5sQqz8GSeP2V8", - "marketAsks": "6j9ezvTziFmrjBigcpJDGSGShUGasFzFcLQpPcKAXabk", - "marketEventQueue": "4mNEMHstCwfVLndhCGYWoZSBxyPUcrTPL1Xx8hE4JudB" - }, - { - "id": "8pQYjCbaeAi18WxqrFm1op8Y9o3eWwjWLfr1geHnjFjE", - "baseMint": "ChTE6TCqoY16dvqPjgK6Ji7zHcKricB2DHLoqWzx5v9A", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Bgtdi2iGfi8XtnFENsGY5968gtp77xEAbZ3FWvkAbWX7", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5sGvrcQfHGjxFZDdRcpiyTJCRLmxX5c8v9umBpXyCAdK", - "targetOrders": "3ZYgQz9jaN64XTuQGCZCA99AWb1wzL2gGTnZer7AA3DX", - "baseVault": "J5fwLUZrvGfwfZ57AkDoidQxyL8vezUyB2C7WVDn69bX", - "quoteVault": "9h8zLpD6dprn3d7fVbEnpdQk1yUPEJssixB9YLM8JeHe", - "withdrawQueue": "68zgEfWq5BZKohkNiQn8f6A8emYzXQXCXxDn3fVXAudo", - "lpVault": "HAcryBo6idJ4z2EdFWGfaHL9YXCxofv1Vc4yDM3uowET", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HgPcCPtRqJrUSgU3PVPkKu7bug4bn8ZJWZiDvgghw87s", - "marketAuthority": "3P5mtrYauLXhqhE7SCsv318G3P8kDd7hSd26zS7nYdid", - "marketBaseVault": "5KHf3ushnMFDouyyG2yHRrbf5YJAVvabWmdQ6T2ybtr6", - "marketQuoteVault": "DnoR1S1RkSS6X3SGjTnZLS1V6aB35fP3sq9D8h2uhoHH", - "marketBids": "Fc3T5kcfuFd7giBkeM94pWqLid481TW2yC7Xzex6nkPR", - "marketAsks": "Gd5TSTH4AHUL2po6LSWti5cfUmkQ9SigstZwrNmDi919", - "marketEventQueue": "BibGDsUgqvumuvFsdLsh1aBejbQmybB3PWbVZwWUkpKJ" - }, - { - "id": "8pRe1FXcBMun7NYZjwpWo7b9rwBpoDwwhRccqtcp3tvC", - "baseMint": "CKpuKZA219RopBMRiq3Ayd6oucNe1YH3epKMDS8e6PDA", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HNF16hLiAS97LkM4te3EdA58iuzF83kG4y3A3tUt3aBk", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Arvrxazn42Wf4ixdAuWYizzKEk3PPoLvRwhpZazogLFJ", - "targetOrders": "2gUaJQQVK8jTu6nLop2AwSXgWN1X62fdrymYUyZmEKZi", - "baseVault": "4VfDz8frasnqcuhsYX7mYxPSD6b3HfHjtH85szx7kheY", - "quoteVault": "W7D87jMoHSfCtQVmvobeX8NappTCpCzAYKJhioRYG72", - "withdrawQueue": "3nViVi3gTBgxxtyaWvSEV4XkdaWqTUQUm6mMGduJzpvD", - "lpVault": "GLANr1za9eJAbbLFsEsnFfempGW6AByV9Bm1stDpeqzW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "A8Qn68o9wiafUSP6mvNwXpSmtXkbHnnMA6WDHCBPfT6W", - "marketAuthority": "AxRV94VKcTXxcA5RySpFc5viANyC46yZffLNSemG99rC", - "marketBaseVault": "63QBo7a3E5AgfSkdpXxcJ6vNKx9qjCbV9zDs79AQ5wws", - "marketQuoteVault": "CPbTW1roWg9inHA7gB7SPgeMSmppMsdV5wXXrkQjgfiY", - "marketBids": "8jipTPqr6HB4pFzKcC21qT9J1fzt4MoDH5d1DKX5e3z7", - "marketAsks": "CFC98z3gtvr7XJjHCZWiHKNGMq7fWHjKzje9iZeafut5", - "marketEventQueue": "9cN1eJ173uiiFppSWAzWsxCMQyBMBviXEJKgZb4axDE4" - }, - { - "id": "8qRrmnhtCuPbFy31z55u6e4yRB5w7dCnFBKNgYN15tXK", - "baseMint": "GH9urVNhVzEvQFAz4NGWrjc3raGMKSmU96GV7s3QwSfq", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "4EwaFtKLbxSjmVAutNBrkVF8H44ZyyyNkz9QpDWZhLvS", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GBRBmZiAEAVnu6VZdRgUjZ24WURWw29rixGucPWJhjAw", - "targetOrders": "Gw4i3dM2HHgATEn4QuFGW9z5YJHkeBzrULQHU8W65aAP", - "baseVault": "CjFFJkMr4gPekKb5w4Mo2JnxixsqSDsdbfvsaGhoKHMZ", - "quoteVault": "DnCx16tiY9kkZYkhVDXgCcMqyQEMxH9GNgsqEEM2amfV", - "withdrawQueue": "6Ka3RpCQK4T5okutkbDEpvB4hTVFjUCTP97dG7JbqA5v", - "lpVault": "5NLbtkT8K2x3d4FCAkvTmt7UQUggsaAJSLYcGc536o4u", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6fG3zPRGL8MEu7Pq6o6huowDubMtuArwpH2ACLXZKQhw", - "marketAuthority": "3pHmiBHQRRTZHizRfvewoiXG8goA5ALqg9u6Ukrjj1JK", - "marketBaseVault": "22SaeXWvdEmBYC18htjc2r1f2qVQAwSCoUa5CioUVBtB", - "marketQuoteVault": "2CYW5ahcg6QYbBtdyARDmivywk9T7fBS6KLhmBXEgKwj", - "marketBids": "E6gvTHqkZJEcQ7LuBusqok1aB8UsbjQ72YVxwg1BNzUj", - "marketAsks": "BUYXPjx8WgDJMWBK81QG7RxDNARkwKT5ntv9FA5k3cZP", - "marketEventQueue": "DhHudCyNpegnWQPtsPs8hCaJp7vfjxFmRtZGAdYVvtZ2" - }, - { - "id": "8QZcWWfRW7upskC5S8PqTSeUxwBvJtqfdP4bSSeAq65", - "baseMint": "AZci9R148CU6hfnnE8ffm2K5mkxagbnTAZNQF5fLbvHb", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "9ph2ZAwzigVRrrXvHoGxMU7YuW59zMDtNX6WJjh927tF", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FLkLXTZQZpZ9S7qcmmKodirFqrSDaRYQdTjyq6EwrVj6", - "targetOrders": "FCrzV3sU51rwtAbAXtisZggyNEdYs7zFeHDz4QX7tCco", - "baseVault": "GvoqZdhCUBveyNNz7WB7GyoQKQmBCpFMeQQmLd7gZHGA", - "quoteVault": "ATwRnJSgopoM1YWC5jpN4nAuw5Tp8UfkLvQYZVoPsCUQ", - "withdrawQueue": "G8NaP1kXHCVeSWVL9mjH1XDvMYLoMrj2wxrvaP3aMV7D", - "lpVault": "3ZGetKBLKq7yXLVQGUcs5NMvWMzdNqrdX2MfiFQHSfcs", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FPWz4J3gTEPRqezWARNct6EwBsuv9ahs2mqEwEmsCTjX", - "marketAuthority": "CQHVEXSF2ehtY22Euj2JTiUpfMrk5Pptm8PG4WHc4K66", - "marketBaseVault": "4by5dxJ1aaArXToKfkJWWg71Qpy1ea1zkREcWezhhiM5", - "marketQuoteVault": "JDkZxjiP35q8VbAgpJsDu6QZnFCD3zcxm47VnoHtwgXw", - "marketBids": "B56iN2xq1e9u3HBauyi6EbBkMqRxLN2KCbRFZRYdAh6n", - "marketAsks": "7eLApQeEH9EK6z8n639Q1bn1ph96nL8T9tiWk5xfKGDe", - "marketEventQueue": "Bes9XrTdsaEywgdQgu7Tkzv6nbp9f8QwH5YjJf8YXppv" - }, - { - "id": "8qzemjoQ4xJhLiWB4XBPjQpVsFXEPY1mfY8ovvEeyj4p", - "baseMint": "5cPc4dx8D61JrbHqVZ8Ywsf2L6FeBMRmgstg1mWc65Ti", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8rm78Zb6bsEkmKuyp65TaUbFGWLuXVcMDvoQJ5YbUdYy", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9CyJtNbH7ZmRwUWb6Nzy1Cc5GWVFMpB8Di9PtrnvFL83", - "targetOrders": "3aByobwyQHEMGtnVuVuQ3mWTNCNJSXCzuQojt2T9KRz8", - "baseVault": "12ekkmhrKHhhp4CzydZh2gswsacpxkWUmhcaTjZfXgzT", - "quoteVault": "2T5yDtoS8iJVm91b9hbEAK9Hg6Eu98b5bJXdh4Ufmzwj", - "withdrawQueue": "7T4anqFuX9G2nRo3UXoGhYdkZ6Kd2C9fKeKqKAJVi6D9", - "lpVault": "Grxmem1PYUyDJVM7HmikhsHzeknDzEMbuFfhPNPdH19f", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Eh1VwmpgA4MsUmgq72T8YvZivSJWxtAYE1o6LrUFqKA6", - "marketAuthority": "CbiSDFUNjsA6o1iBXbWjKoxYr2SxaHqnoiYdSWbpH9Rb", - "marketBaseVault": "3LimH8BXNwn5JDZuQzCd5McWYNxMpEkGvMgSeq8nZbMv", - "marketQuoteVault": "FwtrFuxBigLztVP4p9cFYKyREvr5feo8SZrVfjRVzKio", - "marketBids": "44BT9FBkKv9rnaWH9aAXZRCjtEvxpstBQoUa7Lq4yesM", - "marketAsks": "7GFXtrkWWgGYythfTVBhrNw4BrmZJ6KRbLbdEv93s2ua", - "marketEventQueue": "485vFcZyCqqV9egoKTrhy8bxfzuaMhKATaUNsUBWimCc" - }, - { - "id": "8RehDFRHt7fh5vztSUuCyjGdRVuZ1svSenui5b8DfuQy", - "baseMint": "2y7wUCJdtqTbjnKBNEB3DpAYCuwA1atCtdfkGt9VR4sM", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "7amVgszUxqC5iM2oBYdjjh7wCkoARnQHgniYiXANtzj7", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BvRA3P8kVCkDf6PNZruuB5eP1fw4FfhdQJxYwsqnJY6b", - "targetOrders": "9p4cAY9YEbF8VHvVjWw6kn6aP49Qcd2NQLFXE62qgt5Z", - "baseVault": "Fs6EBFw5pZV2nrNvhKVR6yPFmZe6xhpG2LvjMYh4NQyf", - "quoteVault": "4qFqg9CVHy22NvHjQYH8FcF3Fe3pReiV4FNoSGvKCzMM", - "withdrawQueue": "EfxBUuG62hWvRXVkuvonMu5UoZEz54YZsZYcMucoZYRh", - "lpVault": "9McSEKCjy9iaTU25dZ5B841aqBVpTWrSPb84dicwZZhB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Dy5KkLSSXR5uqbmdxhXmF9jVuhziNikosS2B2ysSHM71", - "marketAuthority": "J5ZAUqgPvLMgWDT2qgt8iNQQSxceAuQuz3tKArQoqwKk", - "marketBaseVault": "6gXai4JY61pmG18M3uZ9JwiZWszk9qxqyuuV4UKrRYnj", - "marketQuoteVault": "JBRH8MuihoQqsT9bqe8WixYdkT7nr6Esf7S7qJDhWrPP", - "marketBids": "BXCkxJFzponh37RwA1yjiFRpQNWNsZdX3M7vQWvPni73", - "marketAsks": "C7yhE3iSKTany43dJWwmAwNfuehuSVxZxrYC6hdFZeZe", - "marketEventQueue": "8ticDcSimqQS8nqxQScetiekkGPZJBbfHxYpLKQp4Bgh" - }, - { - "id": "8RqZLdgyqU9JVWvRXP4kveCmM388KhCeaubVHstQnWLm", - "baseMint": "EdAhkbj5nF9sRM7XN7ewuW8C9XEUMs8P7cnoQ57SYE96", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DMGFHr1orq6YcERasom74PnR4NpLmR1QmUHvdA92bHGq", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Y4j92qef7C6omqnzNz53CkFKQj9n2VWPBAHnY5s9bDk", - "targetOrders": "C4KDg7LfWGc3rzyEyx8uD7UxPA6AjUHZW5zUb9UMuUDK", - "baseVault": "7moCZXdntp3uDoDN4K6kVP2cWTYTgn5vH2G25oZgtQXq", - "quoteVault": "Dg8cbQi7aQudPsLtBe6wKyrNmNbGGsobVC5gDYYQ2uqw", - "withdrawQueue": "Hrh3yj7k9Vm9WrP6Y5EBD1PoEs2ooXbWMDTe5Wr1Xi79", - "lpVault": "5bZz7mkFfwcvsYg2egCY3LbrvDq6m7Zv4WpN4ZBNymp6", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GHPhJm8F5Kg4Xq3nxHfN2SKsgPwNPMuB8FHFsLE6RP8M", - "marketAuthority": "HK4ycYG9qfPmWU8X6AoNX5LK4qco8kznGcjQybhDGGwX", - "marketBaseVault": "XDAZ5teT5wUbMT664Yjy9T2iW2C5ZHVgVCpgwshrfef", - "marketQuoteVault": "2QdGdeG6dRMC365sn9HvWNiRqhFLMM6qqGZ1cVLEYFE7", - "marketBids": "9eyLHdtZ6VrcBsagavQ6iySujh4TtGSFrwWZNTXs1P1z", - "marketAsks": "6QFLT3DGTxWF11zjiMsRU6bTvnkSScqVBddVJWtUfyHP", - "marketEventQueue": "Dtq8Ds7g2YMrh4oQza6GZoGZ4zuf3izM7spqUt6geGgW" - }, - { - "id": "8rr66eiJiy4pQbptzYRQMv9h4hsLQWjq4awghkd1k2Q5", - "baseMint": "GHvFFSZ9BctWsEc5nujR1MTmmJWY7tgQz2AXE6WVFtGN", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "FHm7j4QbgebWrfbqKYW6tJwp7vcTLLNC9D8QjcMXV4wj", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HJtvq5A34EAeagmMSNy2sHjHVFJ3kKYmWU3Pqp9xw5oU", - "targetOrders": "2kDwbHdwVaUfvfaNQMw2QRYE4LZucT6FudyJqkVkDrrJ", - "baseVault": "CsS4nbugqhqTGH5qwDNBSC1WzbcZ22nhASg7xE1eriA3", - "quoteVault": "Ho3vey2Z5hCspvC49b8mtY5Ppx2ynn5d1WxJoHybbAYd", - "withdrawQueue": "21GgRZMmcip6qRpcDLw1wndeUu9amJ6Ff98ctKFRWmG3", - "lpVault": "9az2hrnFZFSJ2gZ8x8NLpyccETrLpkWZxQcnmTFYVghB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6RSZYm1jPB5BdBgBvDhmRB1TYNsLTkTvAMH6yQr128ac", - "marketAuthority": "9zRT66RV1ipYRhaqAPkth52UZaD78Jxc8wMgDYoBw6rc", - "marketBaseVault": "B2EwZKNtSuZfufJK7wiWJNqtT4i9G1FxXcQCeZLDDiyX", - "marketQuoteVault": "HPtC9dyAAuQvBcBqM5sQNtkiGkUcSiLor4D23J27qq87", - "marketBids": "BHJb6YvhCb3RiWwkv3nAfxB7EgXf3LWFRzyiqovhHDbv", - "marketAsks": "5sHj9P7Kn9EjkASHqxxGDRgMjGZM75obxVenaTRDzziY", - "marketEventQueue": "3E18Yxgpx4ddnPdybRhzxuZ61xZ4abor4hCRVRsrYY2H" - }, - { - "id": "8RRRHtWtUPCL8u6rHj1YJa3iCFQ3FZhzJLsdZ3vgJaZc", - "baseMint": "WoLFWyFspu68aHQeKRbgYPma6H16cHPXErJK8o3sczb", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CZXbdbHuwWCK2cCtLUvFk4HSv2idgUTfpNDpMAHq7QpH", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9JWHopwXZB6ztW8weMXT66WPoqJhf1u1QEpAoxLjoX39", - "targetOrders": "FzUgu2hMQ6cDFw1f1B8s4q6ri6PaDWLxPGtvvWMzvPYP", - "baseVault": "237muUUdgveAxHHaXRJ3ntXsKumkmfb3Y4phNGYEcGTJ", - "quoteVault": "Fo4aCTRAvMv3SXhQw8JSQhmqT8zrVmfDiAFZTYvHYBhd", - "withdrawQueue": "BHwD7EQXwYxzMrSiEdJJvf2JYCPscn7p341RDdmMK5Ph", - "lpVault": "8or4yiajEFhu5fKofTzDr11HuhwHvsJcwnpebMihdX4v", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8EHwqJahya7wd97HL3bymA4pmDZFiCeMqqGdYE8ho5nH", - "marketAuthority": "Efu7unZT8SxAzK7BjCsbmDCd4LUEXus7Muc2Ahbpo1Eb", - "marketBaseVault": "9XyRHapGXsKoBFer4Yca9LTfozh8ywXbK4MEcW9dbdb8", - "marketQuoteVault": "EYotd2xFLJ5jL2F9NBoZWvTKNgVvehAuS71eYTRe59Xx", - "marketBids": "Cm5PHTEzigjuo5KF94MYiLTLy5aVzZKhP48jzHTibqyB", - "marketAsks": "ADnLsY5BX74QEVfzPdD93g99cPrZHwz5oHfAkiWCKiUm", - "marketEventQueue": "D46nrCZ3XjcpgVRdGkTzcGK5h54EECNivX44pFcaupFR" - }, - { - "id": "8RTUXqKjPmENqqVy5b3NZT2t2q5VwEK6mb12zhd35cbE", - "baseMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7nzu9YTMPQLTTi6oe3TWfgUoN18NS4ftJvmfMPgbgr8f", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8AhEnieEi1DwUneJH7sv9DLBjYDHS4qPZnRozUx7Yr8c", - "targetOrders": "6FGvXATNE4Rb6quWTrNfBVhpPCN7drmN6iG3hnMNWxho", - "baseVault": "51ePngVwquWMX8Gdmo137vnfZWqt7wyvFzZdWwh4YwWn", - "quoteVault": "F8cB8BZu6BkKuTvzVp9KFVowrceBxRYtFoEi4F2UNqBX", - "withdrawQueue": "DjvYCUBgCoCDGqTkbQLUD6hCMGRjidqeWxHKFLGABbQM", - "lpVault": "22247T1U49YWMbiTp2NYovpzxCzuWPrPKiiwSAtRvM3F", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5TaD5ktUwX8LMYiPVUfn7fbCKkF4RnjDSvR5SJkLUCUy", - "marketAuthority": "CmnPdU2G4LogEgNjii2y15aV1Yq7gGUUjQ31oFPF33Br", - "marketBaseVault": "HG9ufjLUP1W7GGPykE8LTciDp9LHvk2CuCHEB4pviY4y", - "marketQuoteVault": "GxoKBCziNnDUuJ3sW8bUVSYrNRqxfK2MqDpHnUMzwtwp", - "marketBids": "3JK1gi74sjwG2iqExLbqCBWrzTzTMrzkhv1SUbfdEHfX", - "marketAsks": "ExnidgPof7ccToaDKywcAahohSNNcx91nMLTnL1zQ2Sf", - "marketEventQueue": "TmnpCVFhaGKbwKuTherJZXDyg2WPsd34hnGJrg8YFYx" - }, - { - "id": "8rUVBtFEpNrMnakJA9rrCqEpceDz9awCt1CRMTKC2ma4", - "baseMint": "C57GUQaD4qJcUpQJWJuzz9zQ8ySQuEsfuksFhV2xyhxq", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AdfXWXqLECRWSDuYgESh4pGJaFnetkvygCBsE8HYAUPx", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3iWz3m5nkVxsDvWt3r3QkVXNre9q99DJmQnkZVFEngTn", - "targetOrders": "FFsrwVhPRGfsPQparwPc1jM6iHFjV6rezNTn3RUTbsyu", - "baseVault": "3bTHBndMZ14fZ7sCFkdZ5Viy7H15iAsTkBECd7GhR1pt", - "quoteVault": "4rsqw6U5h55bDN3U8838YVLTb5mgjSpBPk35DkWx6Z57", - "withdrawQueue": "5J7Qw9JQRNgLDHdBD9qeeo3692gJdUkw11coGfBYDS62", - "lpVault": "FSbHYxhsCmmNrmpMkUUtBdnbYPMy7oXGkeCAiF5LNWN7", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "J6EUxqoNdhnvsrkxXhGMjGJqQnYRQFxR1JtQ2HorFgP4", - "marketAuthority": "3U75pjjr2KqE7CPqVbrsASRMebBuGkKCGbGGjrgFjPcV", - "marketBaseVault": "PoLSfjZWk1wC7cRK9VBzhZpiP3qHz9J1QfjJtnVNNgp", - "marketQuoteVault": "AfpyKRRTTrirbf9q4soSAZpD74gS9RNciFR9xTMMeYB8", - "marketBids": "5PcU7opH1heCmGwZTUy6Pzsb8fCGrvzZh4JEQ7DWmm7i", - "marketAsks": "ABCbicvbL9fGvczvCq53mDqLmyEnaXd8QJzMM2vBBPoq", - "marketEventQueue": "3sAuvcRVNA8SQewTihtrr7xXJKodZDfPCBdqyNZwjVqx" - }, - { - "id": "8rvLV8GuL9ssq21PLnLp9RjNJpkxhbWRcQE2AE2NF9TD", - "baseMint": "DhYTJPmUa5kQZfLgHb1soubgaK4VLZMxb8CTNY1vZ93S", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Cd9GqnkbPjRmUaHUfa8uWQeq8Y85LJj8AgMJSWYwFKLT", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7drhuAjboDHG1MKtYb1RtUmPQXPqgS2ajS1uKRv45AEs", - "targetOrders": "BaKgwhgvr8spHb8KHSCjWyQDrovhkbqGpnp3z2wiZxAG", - "baseVault": "A2fx793sBvZArrVTq7vYdNTJq9cpKANUHKPuhSu2BviT", - "quoteVault": "FNxA5P4DpGUqAgdUL69cwb3YQWVbS1yoEXHgHfF7YfwF", - "withdrawQueue": "2rm6ZuRBRLoJyMwH3BgvdH9Adk8TDGXFYgDc63hTt5aD", - "lpVault": "8GDjb16Beh9jzMP2kvLBUpFjRpeRyGtMAfiTmR7Kfu2y", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2QpyREawoSEtntAtqVCWP2Q6yt78bp5seT2vLHkYQdMb", - "marketAuthority": "FwgfiEM36FjjtQVfA62TLTxg4bKFivN28UvcrDiMkZrX", - "marketBaseVault": "78vxWHxo6hhXeNNASn7Cq4eRDSbgP49iEDwUWiEs9m5D", - "marketQuoteVault": "5wMy6UWhTb36c5C76qcFBHiaiWZN53fzYgYYADHCbLYK", - "marketBids": "9jiRn4idyNU3bdEafqZBz6qriDaFgaDFgth872Mhf72i", - "marketAsks": "2WMU5z2dvT8NUF2QRpYeQioxzCpGXb7dYGyZ29gfNhk4", - "marketEventQueue": "2Bg6RwyNP5iJu2yY8P8TJtfSE6LXhruRYnLAqam3H6zb" - }, - { - "id": "8Skw2e6PeEvyoMGXsKAk4TLM86Qh29zRQYXzXEzxRm8Y", - "baseMint": "GePFQaZKHcWE5vpxHfviQtH5jgxokSs51Y5Q4zgBiMDs", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "J2hGHwbkpj2SVo6Bs4X2Houy7n6oauydhbh9D6HpKBU4", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HN4HKqWE6fS1EUQXy9rC9FvGYfqvbmiYbXtWV5Jkm54u", - "targetOrders": "DYgatsRMfR5LMvGXjhPfgR6agNVMFRDK7Sy1L3qfZguu", - "baseVault": "6Mm46hzAToCezYdqXLkyw7AS1LDkqdGJKE31btjLFqoR", - "quoteVault": "DweWbiZUVkrqrh9iGh5Do4kjN1iZLAStjuHfB667Sy7p", - "withdrawQueue": "2j9BrNuD3DQXZvXWqF3zP2jJa2M6TSc7XJVejEBGJH85", - "lpVault": "D537GzvWJrB7T4HVfVijuhMJLbNfUvtDK49rwVcRq4c8", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8TAd5ARuq5mYdY3t3PamRaE5Gf95JqgSpVmgTDwYyVXY", - "marketAuthority": "Czkwy2T8HCvpVrzFQjfjGT15b7VgTjN9LQAEcq6Q9KLH", - "marketBaseVault": "FJHe4GqNgL5GtoHpttytyTj8Zs3NRtByEBomJ3MrugrP", - "marketQuoteVault": "D1icBLspSLfpWDMei2MwWTaeqaFjNNTWMyH5RSsMkASW", - "marketBids": "97VrKvhhkhYvdLM7GvDdhe9nMfXQu1mwF3gMdghCZei9", - "marketAsks": "APUnXE9YAQPxpWVnJjQpPfgHNvmnGDnpquobLRdPuqxz", - "marketEventQueue": "HfJCvJz4bime2QS8xhbtMbeMFwu25Zfo4jU5gKCZAasc" - }, - { - "id": "8T4kGA7PL7DDiAZtFz6DP6Ufs9Xb2cdiwnqHzS5c1MKg", - "baseMint": "2QK9vxydd7WoDwvVFT5JSU8cwE9xmbJSzeqbRESiPGMG", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FJJT7yUJM9X9SHpkVr4wLgyfJ3vtVLoReUqTsCPWzof2", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6imoxBBoZmRdFoV3bLGwsJACHsHGVaA5avprqcAg5b44", - "targetOrders": "7QghpxhWXPxzSBcxzRheCTQF5i9ikVYHN1CD6CxKQdUg", - "baseVault": "6iJdfdwiXMN64BJUdnaJaZ1tx3eUmpVQUvFsVwaGbBps", - "quoteVault": "HfFBGEJyVMHNQLDzdBzQXCSEj3WPWB5DWGfYkMVF4VjN", - "withdrawQueue": "BJytFKVx5R99MSwUaGUuiGYm37gTmYs6Kj4TGM4pF9SM", - "lpVault": "6bnATjG1WJZBNjH4UNYxjWCqMG8W4nQo6C35zfcVjkHF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "N99ngemA29qSKqdDW7kRiZHS7h2wEFpdgRvgE3N2jy6", - "marketAuthority": "JCg7WtVvLrs39vkednBuS4ahCJ8SXyLniHAHZ7Yanpn8", - "marketBaseVault": "7UxQE7PF6PGagRFY7y2qrBcMfgyRp5RBG8ZkhoknzSuj", - "marketQuoteVault": "5Dsxhz4tTdyuZpNR3n5ANSE8BEw5fZhjKwNfqfJs3B1t", - "marketBids": "7a4dTtXmR6rZ7apo3LbMJ3KYnpue3TwBgxo4UvvKnhng", - "marketAsks": "B4PSeKSCF27uU2iHGXChYT5fygtGkQQfQikj9ik3kTtb", - "marketEventQueue": "62fqHzo6Ezz53LtLgLEuQYsP5D8S4HasvTsqnkD2wtAF" - }, - { - "id": "8TpLegYhGc5z3PAJonMH6feHChy719xtiS17pLyzUnp4", - "baseMint": "7q3AdgKuMeDRnjaMQs7ppXjaw4HUxjsdyMrrfiSZraiN", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CeKbgZy9WxLsdm1ckPG5dDawywbWLp7TNBpgbNvxa1qd", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CowWtpEwxEL5VNivwHcaPdjwVjvJnqAU4YWjsp21oEQ8", - "targetOrders": "4BD6PdGiuagDE82aMSvfVmTvsKpz7y2vGqLNEnJyrehG", - "baseVault": "6Nv41SSahp1YQkVeTkXHU7enD3Qy5X7Ny6JMnWxrM9RT", - "quoteVault": "ETAktLTSR6AherwuyVSUPHdNSePhTYBYAM5kuZY6Bfk4", - "withdrawQueue": "EBzF1mbV2DE1FCMt9t66fb5MXJaViczd6GGNQQqhuszm", - "lpVault": "FLgww4zKwCWsze6C6jEy6AV53AKy6zKxoZKyztVZCDU1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "J1U6JbTwmhtw7oXa8CBrdNvbKuMf4zoTMerEoR2G6Vvn", - "marketAuthority": "EwjuDcRK7syo8wAtZCnCuN91DowxoqKHt5jU9wANhg2U", - "marketBaseVault": "D2TFM2W7t7597kC7hmV6VbFvSEJBSkn7CcPoLd1cqJS", - "marketQuoteVault": "31995QjMoLxmZ1Tn8xu9iE6tPQf7SvdDXyGuPv4pVSqD", - "marketBids": "6zett66DwyYNQRnE9gA5Uptwc298LJKykHS3KNp5SZU", - "marketAsks": "3ncX3x3FmgGKq8RxCqPFwzF8kAXQpjG55oGNy3Cwx1wJ", - "marketEventQueue": "BJhwdyTA1iED3nqKsLKvzYnQPWTvXd47GmmHT54Lf7ck" - }, - { - "id": "8tPZXdy5VQcKYQe9YvSvDFP4LQRuySc6HT9RrNbGtfyk", - "baseMint": "PaPa6D4Rys4Lcj1d5csabmDv3QdUE2T1QQ6sWNgoeTa", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "A9H8XDNF8MXYiJadTpTgFRvGffSTPEzYxrGmVhjFY8nQ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Gm2DnPevRAy6ivrpick8yjj47iohW5hcGNUhdE4h5adT", - "targetOrders": "GRixxgVCBTNxKciDEdPVZyKaPBeqxXoPTvP358gDfnyr", - "baseVault": "4nG2NbGAgJ7bNRssHhYYHZ1CabT9tYEuUVPHdGYssdtw", - "quoteVault": "8wuZr3FSF7LByQ7U3ZY9fKVXUVRKyZR9JGNyZnDAux1Z", - "withdrawQueue": "4jv1DG78FAagk7bgsKMtxx1M9stJkwGfwVp8C2vUmNMB", - "lpVault": "1wUapa5mLWg8DJhREozg9HNn2dzkiTH9SKPhKzybvKA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3Di325zhMXPKBk5bLgjwzFvRiKjHk57VErsuQuMrthgo", - "marketAuthority": "5gTGTJEJ5tLUoVz7DHq9Wop6b1avAexmkFrgMxsV1biX", - "marketBaseVault": "56i8S9qPmFH2NgdVsrGTkQxEKE39kMuFfK2gJJDTshsW", - "marketQuoteVault": "7nefQqWGXZbVNihmTV2P62ZYTHdrRaEWeX8pKmwURYvc", - "marketBids": "HFcHfgLNNFURnULbe8gREUuPquiGNNBnf5biiwZvYvBD", - "marketAsks": "G4dTLV9Lv1kZZt3zTh8pR9DVYnYPmKnFKRKV8vV2XHT4", - "marketEventQueue": "8Lid1hHTER5y2nkDR65pZgB3VsxkA7gsjw6Y8HrzJth9" - }, - { - "id": "8TtL9Q4Huh6W52nRkztkLo7jxTKnzGGPB1ZDaonh29CG", - "baseMint": "FeLoyXk8ac2AYVmDhAWEKNWWT63Z9TczeidYbpDvxF3T", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "F5AsDcYQHFfVhMdGTNBXJJ5aPLQ9fM6a1GdqdxCmnreg", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7Ln3mdedzSXPw8wvRZNtnssxMpLihpkD6og7K9RKh6Av", - "targetOrders": "Ekqg9k7EjxXWjjRfpRQ5ozFQAg1VwHjH8oRJw2qqwdwn", - "baseVault": "FYUPKymAiZYn8LTUkjBJCQzN21gXyoRArU7Qi5TRZLXN", - "quoteVault": "4waxDseCbgqtSzf4rPLMn8nKgZuLazvwoujRUigr925n", - "withdrawQueue": "4oQwmvpjVDAT5QQhQpmKdhBjgJ6UJ4U5JEK7qtwvHjyP", - "lpVault": "5NggmLhvoLYucBjowh8ymLDxsWZ5FRw4EUHyFmjcYa4R", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AZfRcnRtDdBo858m8TU58LG4VFGwhfzkC95UXNB4qAWk", - "marketAuthority": "9iUsq8VJQbsF9A5U6kUuamFQ3mddjrEswqFRmXMtnwa8", - "marketBaseVault": "FHQy4U1NhnqCUN7Fho3uHN3DfRNs4HnFzpN66n7X6Ha9", - "marketQuoteVault": "Hu8E2siwv4oqrUtQvLcGbKq6VGsApiPxf8DGXcd1C2nD", - "marketBids": "2djw8xkFCnD7WJTX7JLSyA795j3BkVCkwuUhs7P6iapn", - "marketAsks": "77VPGrGtRCLe8nQCy7pLiy1mDbhfPyhER54FjNGheTHf", - "marketEventQueue": "AaLoRs7LMd2ua9UsujdDffnEGDS1efY5oo1XDKmLg2gX" - }, - { - "id": "8uK7Ho3oA44SNtKm86jHUYzBiJrXzeBMeJHGYdHKXGyS", - "baseMint": "9GnYb1ukBUKHobqpmNdzBE7VkYn7wWqianpKaYFPBChk", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8YYYgHxU5mjzf2f1SRmpL5m11VXC6T9STcmbpaEB35CY", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AdzmE2zrRT2zLQXrMDRugqpegkicy6tC4tePgiNWK7DC", - "targetOrders": "C3ehaYaPhQcaq1wdP7AyRfUVKx2BWtj6WE58vBh94fMr", - "baseVault": "9LesethPB1n4aMFwZ5Ycn7iF42fTA4wRUQ6SmXqzoh1K", - "quoteVault": "4r4jt1JCPjjZEGb8q8LPDKZQwRmuLcPc1VoNZbkw3xCo", - "withdrawQueue": "6H5Py9v5xUmXP4jSNvMcweNZdesLBmR8icz9BGehECER", - "lpVault": "9LQNwANcaTURC3LirqCbqp43fk5Q9Acu3UWx1koDurKR", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "B7Ngkam57Z3sLSq4VvJbDjQqMbCejKMCPqbPqEKPXgf2", - "marketAuthority": "7z3H7zPsAAd5NdnERvHchYhfZ7ZEQL2pEMnqzZLKCQAR", - "marketBaseVault": "4kpx17rhyHHiqi6R9X3eUS6AVeLAaFwbRtvAMXX3Mdph", - "marketQuoteVault": "A8ZDyzg3raH75XZs4ZMrBFwpTz9hemfWVi8c93moRvh4", - "marketBids": "FcxEfJcgzzPyhkVkimpsWvgkmTBGgQTPuK5fNHcXQyhW", - "marketAsks": "2kWe599uh1rxMKUA1EKswcEjEgccTDoBLhZ7UPMrJEUV", - "marketEventQueue": "8YRumxc1vWCemjbp7j3BMgWfFjDKKnb8w6pNyY9GVuci" - }, - { - "id": "8UQuZxc7qTzPRCivTyBLKiBiCGVUAbRNWw5PkDZT5mVK", - "baseMint": "HKfs24UEDQpHS5hUyKYkHd9q7GY5UQ679q2bokeL2whu", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Hho6ZzRDj49L4z6zog8nQZFaxMSz6FX6wNzVpMeAMen", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2qEXsczY5fph398rD6N2YFm4YbzLWiJwDqXo4gSivegN", - "targetOrders": "HGyRvvFdJEL7SzcQvm9ajycwyLCqPjKzns1ZUJUaH8dz", - "baseVault": "DT9Wqevn2MBVLToMQMcnAWFtrU9wR8ZB9gaQ81SDBt1X", - "quoteVault": "3xmCFmM5mGqRSTRRbcwU4nocRCPmtAw9wQFUuEGdn75e", - "withdrawQueue": "8bhK2jzzb4MjdJEv5EdKGAy6Q3jyj4akYfjHU5UCezpD", - "lpVault": "6TenmfzyJFesvjieRpYPi1K8obkwgCjVkChXmkfJzaKW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "998TAsB7D2FnFrri5YSVHfw7Ajgckz5skdu1qPPMFVSt", - "marketAuthority": "Fat4i3inAGe732mYhyqTXUf3ApwKE391PCHEYf3w2gVU", - "marketBaseVault": "mj8ueNesNqYigBGjYi6FxJCRCNs3u483LbTeoxxMNeG", - "marketQuoteVault": "FW3t7TeQHgVy82C34QdyG8yepP4q9bzvPsSRYysLokQJ", - "marketBids": "4BwpHhrXjQLTJwhLF3soiNLAc5P2PyX45XVFRVAMWNmZ", - "marketAsks": "6AtG3jN25xinzzbKc2TAvdP8M3qBVdd18w2T1jZBL4FT", - "marketEventQueue": "4Qfe8RuFiqXJfTN4rRQvnXP6xagvY4YCf5eBwZR7S9Db" - }, - { - "id": "8Vsy7YFJvjHhDApDRxHZ7qAEqG83LL9Fa3wFaZzhExiG", - "baseMint": "AR1Mtgh7zAtxuxGd2XPovXPVjcSdY3i4rQYisNadjfKy", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9HsjAkCMF25rbYc2Rbz8PyXHAKDB2rDWBXFE1vw2fpVr", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BmnP1DQyX5UMSa1gvYcnCKQE4dJinHG1HCr8f6hGT1hQ", - "targetOrders": "AFWCb9PgV2ivVQjDiFj24w9p9Vs7bn3bbC7RaqgRjy8W", - "baseVault": "25R5YGtXQeLMbknPc79oAiMoDPaX5jY5Q24biQXfUyWQ", - "quoteVault": "Ad9ooxtJxK1FGwzNJCsJhFzeg7ypVYPzq8tDwXPocYb7", - "withdrawQueue": "4XshFzexuoUTjprzbpRRXc63X38V2SzkcRAshCQ2vMF8", - "lpVault": "4WvAHQqJ2QwgCZRWVH56FCyQwRTetWWCQbautG6HDgL2", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "A1Q9iJDVVS8Wsswr9ajeZugmj64bQVCYLZQLra2TMBMo", - "marketAuthority": "uWhVkK44yR6V5XywVom4oWzDQACSPYHhNjkwXprtUij", - "marketBaseVault": "BJfPQ2iKTJknyWo2wtCVEpRGWVt8sgpvmSQVNwLioQrk", - "marketQuoteVault": "2UN8qfXzoUDAxZMX1KqKut93frkt5hFREL8xcw6Hgtsg", - "marketBids": "J8JVRuBojWcHFRGosQKRdDtzxwux8fy2dwfk42Z3dCaf", - "marketAsks": "6DScSyKZKBi9cXhD3mRkTkpsxrhw6HABFxebsteCP1zU", - "marketEventQueue": "Hvpz2Cv2LgWUfTtdfjpnefYrjQuaw8gGjKoDAeGxzrwE" - }, - { - "id": "8W2QHHWVsk4UFtkHmJgfThWQh7A7vVQQciC6ZXRxT6Pf", - "baseMint": "GP9zY2D8CgMreoUdYQjyn7Fo7XCq9ubVnX3u4ot1wpgt", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4mtMK1WxjPPxhfzGiYzuFuGC9AXX8eznQPXr3CADDeKg", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3CaK6zs8pnupnVGVxuskzx8LfBXNrjupdbEobJ3RLU6K", - "targetOrders": "6qzfrK4eiuvR5wEgNWVovCyPEfVCqroFM5NAmiECSrAh", - "baseVault": "9GTsbp7KcXCz91Yy8JBzerPLY8yNy66mDZ6YLE9GJuFB", - "quoteVault": "GnizQWZusKETY4xty6TtuMqWgsNZz21GjVzF6Mi7crCf", - "withdrawQueue": "52srChrLaNAooePRSu5DRAmq2jxr5a23iGXN8gfedCNy", - "lpVault": "HWjsXTBDWNCBPdoRSHccGB5Ti2VZefahDQWYFs9KWmsM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5YHCsYCe1oGsH2ePt1KAQGLyNrYg5Tr2r5oevKPJREpA", - "marketAuthority": "2QKsam426v1jDKupEu2NCZ1HRasRub36at7MgQPwBgrq", - "marketBaseVault": "6hdfu3h7N5bqG9UUFD8cZSA5FHfV1LJa2igSQf9S4MeZ", - "marketQuoteVault": "Ftfz5WWW9YN72CFuYtEKJWAcTWJR96tyig1eqXCH4SuR", - "marketBids": "EnhZrscHAbutTB3qcrrnR18g1hpQSdpCfEJNwYi4Tqta", - "marketAsks": "6xRbvzQSnAazgiT8LdWXBvmF3MpfDkmLt7JNmj5KD36r", - "marketEventQueue": "HsWuALM9M2xG3RnQ44wm2wEwqQKuGUstHEzkKmEmeh9C" - }, - { - "id": "8Wi7Uzr5oqKbC5fCCAW5zihaU8yUwiaPJMUW7HcDoMEq", - "baseMint": "EdAhkbj5nF9sRM7XN7ewuW8C9XEUMs8P7cnoQ57SYE96", - "quoteMint": "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS", - "lpMint": "74KcBut4KCr5umjUGDjADmtvch2w1owX1uS1V7KRNCCE", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FQ3zSfszjt97m95Jf8143zoNcsJh8QJajRbY26x2Y1Dq", - "targetOrders": "EhFduuK6qHhDC9HpAb4ft4iVh3nsELHnLFmFhAGBxDWo", - "baseVault": "4NVcmNL7Qt91FUAAyJuyM5Z2GVFT8ru27huf3btaNUWe", - "quoteVault": "4bWSdUWHbtoJuCEo1XiYcBa51yW2ujRVhG7qwr32tEyd", - "withdrawQueue": "472ZpBWeYjmeM53buJkDHdhkGY8t8RFHWX2K1wgyAYZe", - "lpVault": "DpXZ6HYfTunTj4yW7s4tf8TRGLaXKQgVPLiiY61d7MbX", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "95BpxiADwbKBhFKcd1aKpjpnyNBNms5oNsFvGpbANQR3", - "marketAuthority": "72E8G9UbkgzUe6HRTfh7VdDn1pDyM6fQ73p2AEuBHWt6", - "marketBaseVault": "5dpkTtvAMPvVs7e2gTBC4TcgFGbEjZ2JsDZVouMmjx4A", - "marketQuoteVault": "52Vk8quxNJ7FrGBotqQ5caZrhuXBXDjwcgFeiNPWswmy", - "marketBids": "Hye1ZfJFH3LYD1Zj5oizBmh9CTp669Zz9h7K5HpC5FkW", - "marketAsks": "9RAbJLu7sU363s384oVDF4MvvkDWyY6NQmnmKuRGfnq4", - "marketEventQueue": "57GY6vGXMPJKmEw453xGmPxpRoFAUe8A4bz8QnMuK4y9" - }, - { - "id": "8wQYmqVT7u7WvepU5giNNwbqyuYLeanfhmGmhtRjKFkL", - "baseMint": "AMdnw9H5DFtQwZowVFr4kUgSXJzLokKSinvgGiUoLSps", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5TzHTia3iCEnrp3odsb5sv1LwvtJKgPgHrzX6T1ANDH1", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "da3bNc93MjkEczBEVNUCkyL5UrbkHndFcw58weYKtq2", - "targetOrders": "DVBja2JDR5rgQE7XtTv2CpskoUZwDBbsidtTXnyGBCCA", - "baseVault": "EGBG4L7SedsbSdxWWdHMVifSqdpUvL13jJK8tFccbJDm", - "quoteVault": "BFWZGED3T2ksfLosEytUFPNNHwwdsVLhDr2nDjokYMzx", - "withdrawQueue": "9pZjzP1DB39GeqUPvVvSkiYfaqV9vyn9nQFPz2toJca8", - "lpVault": "ETBrKoPvJkurRLBiYAzjaKdR3e6nCZAM4RgdJB8AyRtK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HSpeWWRqBJ4HH2FPyfDhoN1AUq3gYoDenQGZASSqzYW1", - "marketAuthority": "DL28BCvAcbniMmSeoxzouMqvFSGdcLjEtSSpiTiB59DR", - "marketBaseVault": "HoCg3eraWyvdE9QeWtPbdtaPgMDLJyv7BcJZqJzfCWXv", - "marketQuoteVault": "4kfK3DkXZgf7ufPKKbLW5iYDqrXybvCjhtsnPPdV92wJ", - "marketBids": "6YnB9wgLjMgKY7mFoaSjse1hkChjpbxnUXhryBUor47M", - "marketAsks": "2CrZ6HZa1EhgbegoLJmyformu3vGHypKCKANRrLfKzE2", - "marketEventQueue": "9iib9Z8DACYMDyK168a6YkbVg5XLDdrx3dFf76EVy8A8" - }, - { - "id": "8xDqr9JURXRLgjTcP7ZXKg5WwcgTD2fB59yqg48CWQr", - "baseMint": "Bwn9uWEHyNyWXAAK8ecqSz5bkVbaZd8Gy2Kjcf4hdsL8", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CtZc36tw6ayc4TPtNdXpdG91fjijcYoKaeCkCQmS8XNg", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "NjSzfwPuh1ovmmdHFqg5H8e9kjALWiY4MDn5nWURdgG", - "targetOrders": "8C7FaLQHh8Ei248fqHm3rkKpDJrNKfWfsDKcPhi8e8fW", - "baseVault": "7BCDrmJC3yKsD3oQv3t4FnRfzNQvhuTMearKcGd2xJxJ", - "quoteVault": "6rEMz2q6ReUJMCjkYgccD5DqKQHoTBZXEXKmPKPrNovQ", - "withdrawQueue": "DtCektqpc8hz6uYByqmcpAP44wCqhNbS4xQ5TeeBXiRa", - "lpVault": "6KX3WcJLHoKjxNGzVaoHu1NvxFSGAqKRtmJargcftGw4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Tm4dnvCDsqnmWsqH8TFpyL7QhFC3rxZcynn7uDS7hCM", - "marketAuthority": "4SeYjHxv4ovJLtsdwD9tfvD7wKcnbgE6Ag8iMkfFvbzw", - "marketBaseVault": "AXR7gSwJ8Mm6KS4aeYFP4MLjZwDQpSS7RPN58hnARovi", - "marketQuoteVault": "BfwXsYV45ecG5aWVYErYaicZtLQFUxBD8oeWXv7vqS1X", - "marketBids": "AX9JcPJBBvGtszj6zDaKPHVsytkHqjmawn5aKwkuFP5i", - "marketAsks": "4AgyjY5zeoe82AMZhkPFnvnphA4YzwuSAMAqvhjRUhjQ", - "marketEventQueue": "2hAgaUwBYqMa4rG4Lq6DNd2kdDYA6BADmeQ3yPFBFCN7" - }, - { - "id": "8xecdSJurgaamYXTvGuRDd8GueV8KciiVAWq7zr7ak4H", - "baseMint": "Cwiv21vbFdwJRtGomuCDyWz2w6xvPwoUqTmuyrFtU4Sa", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "99kXFY3tdnKMMihqpvf9TmH7yu1MK3p7LzC1KyQiWTUw", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GuKGGyEXvHT4774cYAeeNTfKN1Ws7veFoKjkbt33hKGG", - "targetOrders": "C8moaSgYAh38u9UWiuPznvcqdqsdWGmQ1sFDC91vM5w9", - "baseVault": "517ARXJhwtRjosoDRVaruhv99MDkJRZ2dHnyukDHjFaJ", - "quoteVault": "2XLRhp24kSb4dxoGJt3FpzDSqX3SQUcAoDZoM7mGV7r1", - "withdrawQueue": "82t2KBHmnm8FjHbRzVubP5HpRFJpKCdFkLNa5r33tUeL", - "lpVault": "2nTmmavUQ3fYRzhB8xuLbARekLGQ3u1vTbd5byiEQWBG", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CSYH1Jdi2fTqoWNUdopdgLe1RNZ5cLoBsmmeriYFsRbF", - "marketAuthority": "9g4YcDgoMsFLaQJu9v1fXaPGjyNiX8pvUHeU6SRP7aQU", - "marketBaseVault": "AX5iW4HCLzZaTbRrdJ3xgU3ZLJZ7ZeFUaeyHW4QiXBR3", - "marketQuoteVault": "6yGQVMo4a5x87f98pKKTy4Rt24VpzKYZWQQe11K2ag1z", - "marketBids": "7AuHCd7gTPTjGyXFSNKtjQ4C9j7H1ihrGmUFHH7gV5jk", - "marketAsks": "Fpa6K7qnTdazM4Pdb5hqopoccnsZ861Y779BVAsJ6zgz", - "marketEventQueue": "45PUgwVUA9YyarnrbVyk5ysQUZXWJeuJfMmtbQvviRvW" - }, - { - "id": "8yJyNooujpJHZYxF9D9rBKhYiUmZN3wSH6afLHvdbv2P", - "baseMint": "Gm6szibJfB1ZzUxNYf85nXwFchugqTqNyE5fDwWfBc7K", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "C2SbXA5YrAM9zJLWPxGEpWNaUdc16YkRh9QhKnckEwBu", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DWCpQcRjduQhYizX5VgBAM35Hzgk8mkfUd36btkm3JxY", - "targetOrders": "6tZh2XT5odBHdGQp7UyjKRtTegJVc86oGGM8WckCx3LT", - "baseVault": "EHogBrv9rEBVSUTXjLiFZfMS4TJNmE6knzpvK45tYTCd", - "quoteVault": "CDsTXhXwN7EBmpJ5rekYwCJ8imrJ1u5q27AniNuyz4Go", - "withdrawQueue": "2fduPNv8aYHswThkebPr9YK2bPAUwJyL1eFS8T2V4qJD", - "lpVault": "B3LYen2dVt6jZvCBp1eSs4gr5uo2qQCtu68BLLuumNLj", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "F9FnMTB1PTN5T53jzBHSS6eoMAUpx2xwqqdY4oW3tZ2j", - "marketAuthority": "3miQohaEBkDyJkWZ48nSrBg5Cw4D5Mc4eHwgT356dCVE", - "marketBaseVault": "3DETHcUyrd1NFxKPmdhYDSq9omSkdwASFFUaJacezNq4", - "marketQuoteVault": "sNX8iXbGLCWaJrwMzB8P2So36r1641X4TeK5bipSbeb", - "marketBids": "45aiqGdUNsaVrmBjNUgnPjC55XgAgK6mYqkAziz77KAt", - "marketAsks": "HbfNbo5ArUYfp2BRo4RYPZUGfgEa9cGGuPgw3hBSXsGR", - "marketEventQueue": "72zY2951DaR49pqnR31kXFDWtp7QBY76ggozLWSkVqpd" - }, - { - "id": "8Yutg3eL1xn1EepmrokjEE3yY8heg57zFW1FGtRwmkhg", - "baseMint": "9qTA3A113oG94ppSpiJTwWCyj44wyNcgPAs5i9d7QQne", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "43c8jrnjYX7yLRu3mqnUmgfLWJhb6UNwF1QZy6gfXc73", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5u8ceLkFu5E5X64CDxgm7u2GNWkY7tHR46sS7AjReSJV", - "targetOrders": "46yFJt2sCSw7FiRnwRy2MnXkPVS2ixo9q2GdCpVJVtPc", - "baseVault": "22r396SWBG5LNuuXusFXESvaGVYeiP1uXNnJLza4QJDo", - "quoteVault": "Eh8tKbSQyrjFY7KsU3SPitTJxLKNrcAZYXBp54Gk71Wj", - "withdrawQueue": "9zrJ4aJY9wZxJmM7sGUCR3XVQxV7r4xYsf19D4zUL5pj", - "lpVault": "HkoqAjZ3EWLMc18d64sHzXPfrWkWL2gmATUEfYjGtfBH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CtgjWsoqMKh3JjYjGTPoa1mWpvt1aNa6ugNjZyN4y7MR", - "marketAuthority": "5oEhpUpt5mqnsLK2E5nefH3c4u87BCYCoiHHvZN7fvxX", - "marketBaseVault": "FFtSN4Bo9fFs5jsNE5aH9NELeqfHXybE8XCEXypr3D6d", - "marketQuoteVault": "A4vtArWwG9x6YQJrY5S6xKPYf2ue21AuAx1M1TvQSdM7", - "marketBids": "6QwjwWspMKazmaH88FH69BNVmEiTFsfrhJraWTn5aGKo", - "marketAsks": "GXVpV1a55a95JukiXywm1Drx7YSpv1xg82y4HvPyYPXj", - "marketEventQueue": "4MQjuu45RJMFQvLmhaPv8zVGfiVxYgtg8tD3HBrcykSW" - }, - { - "id": "8yWwVemXvhsWQy2JkAw5EWN4jksPYavxgtMUQeEmxQUE", - "baseMint": "FGMTuwmVVz9hUJzA8shYiEnM16wsYDoSmYoy13UZe1kk", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6wcZP6h3hdte7QwCiyHw17VUSmGTrDsVYzBvNLFfh3q", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DTuXZt1MHW8cHkwK183ZvfGrGdVV4siMdyRLRneJ3Tek", - "targetOrders": "HXuKfdZWbP7d7Zp3KVso9v5DUvBMNyVFS3HedeHzh7cF", - "baseVault": "4KUgV2RocgQXYx9uJ7NVKA1qktMXCCwNnK48xU4HYbyh", - "quoteVault": "89EVLUWy8yKaHrWcQ4BEyqTcyWhXQdyr1Lpgcz6UmnY1", - "withdrawQueue": "9F7EofukXzdAbsLGsYHu7TUUhnoRF1XYmWbAyPyUrWTp", - "lpVault": "Dkub4qtetKJV8gCbaZVy3LpvBVfJZ9Ah6GUGuVAvKLn", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "64hLk8D1Qfupb5kiAaN1v9KQJXkHoJPBDqj8X7YMUmKw", - "marketAuthority": "EupPr2jQEDuQGfKDgEs4eZ8XXbvKBDrDp12uKzUpfH5x", - "marketBaseVault": "8RrHNNDW2MhEWenmYWky8jHvFZitu7KbxfPh3RTzjSfw", - "marketQuoteVault": "23oM1pgk5vGgz8mtrgvYmuVKNuj7WZYmn5fhHLZAST7G", - "marketBids": "3oj8f7Ts6MmiYw9Pg9h1oy1ctxchxGzba4dBYqdAwr5Q", - "marketAsks": "8ZpxNYYKWAW8hS9cH2gbau1sH1VX8MrfzM5TBv7g3fhT", - "marketEventQueue": "2fkmxE5JrTqc6vRWaU5C3aU3Cz1d5tH5yccQuTqByEqM" - }, - { - "id": "8YxhK85F9Pit2KwShmU8VnmjrEfpX59ystWRH6wA3nhy", - "baseMint": "95bzgMCtKw2dwaWufV9iZyu64DQo1eqw6QWnFMUSnsuF", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CSsBERJ5gStKVXkCModXps6WpzKy8fqdedr7RaaSrazw", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GuQMWexKAKY84ijevAj3GdKLHy1J1bZET9jwD9QzK5Ky", - "targetOrders": "7PXepWLoVVXi4kaXULTN7QuHr79LEgqa2HZ8xJdb6Jvq", - "baseVault": "AuVYMzvLJxnGak3HJGoc7tgTKJ4jq7WwpsBb3MzoQ74E", - "quoteVault": "8Aer2tFFcW3SQgc2V96ngXueviJredqG4vK7hs75Luc6", - "withdrawQueue": "HExDoGLFT8JChWFu2PpYMRdm4fA6hsjwdXtgcurgt593", - "lpVault": "HcNfxvqnNBthS3MCNkRgTiz2W5SKAMwW22iQLfR1iPrT", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8nfpBgajP1UxVsK12ZQtrSEzYAPmC51y9ctHC9y9T1FE", - "marketAuthority": "JBuHjyKka6w3PCLaag4mRryeG6P9wwpnWBUQcJsVi2Yb", - "marketBaseVault": "GRife4H4C19uPpiWCEurvgs4qXSvnEyqN2a5XZiNENuw", - "marketQuoteVault": "6RSrUhWLWxYs1b7aPigU5m72nV57BiMTL56WA1Zi34u1", - "marketBids": "9wJHBWDhwVwyN9Ub2JHmd7ZntsyVf3evLmL962uGzbqm", - "marketAsks": "fpicfo6PSCcqBRvqZ9RUfqLmzeqaqQszwkBChg1hUQb", - "marketEventQueue": "3T8FEShMyYRwzZnMG3wW7S1MMUwCEWrceSWKKt9kLLo1" - }, - { - "id": "8ZYHM6VwKuDQgWeqKJBtPjngZYJcXqfDsYmmiEh8VHcv", - "baseMint": "Wurx1CQEpuo8ExhWaMYrz9KErXBrKAdz64ZoRKSjuXy", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "H9kgq2aChkLNzt5kVgnKk5UL3CUXNwwUizKWUqvpJruv", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4iAAsQYCnhpZe4g1YD5i3TS1m71ttqDxcW3M4w6wBwTm", - "targetOrders": "DrusCLx5Z33HHyoZA3gHRc8F59tgjvMsRiMzNGA9YsgQ", - "baseVault": "Hsxi8qKFiZuVWu4VWtZkWm3XaRYAyCFWDNs333HJNnDR", - "quoteVault": "BxN2eisddCCrsnbA4otioqc5RjSRquwkRVf159Ai6CBL", - "withdrawQueue": "HHSgRwGQN57zZ62UFgUqqzH1iQ3xq7Pv1eLwn6dqMEgY", - "lpVault": "HzesCUwyWBSWfc9fhJVT5XL2HB2MvV5EA11LtAp2yPc2", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AMqKRL1M3rh83CZgvQquELCoZRasfr58ZiQVAQXZEerM", - "marketAuthority": "7wTj93TcxpaFaPUAr7LwW4z9CBbNP9xTAp39LSZBBYqG", - "marketBaseVault": "ACs75pPpXeuyMAgNYG7VFpHuhboXXaZJw6UA6ZuoFSbN", - "marketQuoteVault": "GVLY9nUGFN9po53ScJ779BeLAqhf3T6Q58E71hFiyAqe", - "marketBids": "D8J28VXaX7cMfzAwvD9sFCyK27RNSPvrLapz51wewgT8", - "marketAsks": "x52TUmBUspXKkb33izDKF13WFF1MQFkdhfsZs1Fp3Vp", - "marketEventQueue": "39db1vbD4Sg7yTKGL3wpEWv8CjrTo16BwCnC6LRUYu6q" - }, - { - "id": "917TKsx83p6Bm4BhBXMwYXdbb6GnegETPNV57NpVZRKL", - "baseMint": "7ViSurf5Ve2a8qDWFYsfU8GFmRttQvS5paJ8L94QZgo7", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9zM8ek4T7i3F83nBusCf9fu4hffFmYin4r7jsziXaCQQ", - "baseDecimals": 1, - "quoteDecimals": 6, - "lpDecimals": 1, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EXYqSgkrR2C72NpboL7RY9bLTE5C1gLnqKx5xk1CRzMx", - "targetOrders": "9R2WYW1JP4FMQthtL9bMwGXhngionHe8AnfvJRmAT8u3", - "baseVault": "1Tpjb9P1ZoKrouKFmfWJCMBZ1ffWwYPyephy67CyV6d", - "quoteVault": "2cUKuZUJXCsGg9iYb8JBPon9DaroayaKPVHv5TmtZKQW", - "withdrawQueue": "5R5CRKBE2y9E3A19dhsReMPGwPnuoigrjT7Tn41iaZdN", - "lpVault": "F2nDAF4spxfN3zhtafum84CV1XXaWvRzHY8eSxehhtUm", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EdzR47iSU32hfL3MK492UzzhQAytSdNjzExmSXSM1xZ6", - "marketAuthority": "4Tf6zXiHkN67TGoya6zTztGvBsa89kXWSUr3z9iCzJzo", - "marketBaseVault": "261mjA9FRC9dwT17tEtWrYmY1PnhkRx5rVjRZ8MWtDoM", - "marketQuoteVault": "EfvXARZrCvqDgDZJ7z37D9mpmXdNCEwbnu4TiDxat53s", - "marketBids": "7ZBrhkVBN7ajsdmuuCrsvkz7vsiPuSyVAfpHAtGzWZa5", - "marketAsks": "nC2ZwmapXm3o5DC4rsszA9kZ55HoyNwVfhshqVCiJr3", - "marketEventQueue": "4hQBVdW75uP6yNPEBKUFPj9aYcmnfNs8UNeTBspg4hbH" - }, - { - "id": "919f3RABEoJbknB6ifsS3FTKi3bYi4jtevk98PxuiNng", - "baseMint": "24WQvWoqJuTS5LoqeBJpa2smqg94V6iqQDWC5cPd8tve", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AbwvDMAHEwFBebssSgCmpUzKiJWXeVXBdQr8oC63Ye5U", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "NMTk8aHjCjNHZseLH1T9ZwyJ1upmLLc83hoKDVsu1be", - "targetOrders": "GscfujctQmNT5vScdAzGDmCG8FMxcny7qtGPf4iRrzJ5", - "baseVault": "8RrRrLXewxCwpvQmJWHmwGrauJAhnkaoRaGHhqLDs42b", - "quoteVault": "4ZQ4t1DARzwkVgEd8dmEQRMra7qf5tkbHrJSMQt2zEr9", - "withdrawQueue": "HDf3oeiyu7V9LuEL3J55Q7ypmPnvPCJNYwzKSvG9wh7K", - "lpVault": "76i37i4hyVbehdVnigij9HevWYZd87xijg8gXRbjPSye", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ggZ8Gtd5ighG9osNrFJYCmDAYeuifndMkzSD9Ais4p4", - "marketAuthority": "9dEigXcWDjNjwzSWy8n3rxnQ8hLadZ9B5ZLxyB5JsjHe", - "marketBaseVault": "6cidjN9UzDtaWnK1qhRxhReXhtLd14yfyxjRe74oc3tj", - "marketQuoteVault": "ABc2bBExRL7EW9VGoqmwD7vmEYNPnoK84Yxbr3UMkp5T", - "marketBids": "5gs5wDQs1W5b41BkG5UNEuspda5Lwym4syDvVXzYeHRJ", - "marketAsks": "4htqEAUgsSqYTstm7TsPVMNKG1iLKXEkWfYSgGrLGqjo", - "marketEventQueue": "64L2iFQLv253EvJ9JhzaucESu8yrpPNvXmM8d2WA5A2p" - }, - { - "id": "91s5kBGbTeTzVPy5WgKQ3b8WhNL43CYUjkqAQyTwpdjx", - "baseMint": "8j3hXRK5rdoZ2vSpGLRmXtWmW6iYaRUw5xVk4Kzmc9Hp", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EdM6pLnKJhseKnkA5Hz1C6Jxi1siowjPy1WfShrscRNv", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DHMjt1Vy2shsiUSRoajLxhUNKW9P3XPiZuRAFkAtb8tR", - "targetOrders": "AnWtqC4JCaGftRfdWhWkrXTY7XjHHcyU5qr8MoTkDnjt", - "baseVault": "KXdrqXZiScXNtAY7cxmVhWrgPzmKD7UsaMPLnggS6cM", - "quoteVault": "4Xdj6CEEFvxKDxVdEDMuUykps5Mjv8JPze4rjG7Z6baz", - "withdrawQueue": "7oqLwAm3KGiwxMFMg3d8nLDgz2wr4S5sikjSo7niMPbA", - "lpVault": "EdXko9LccY98RzWH6UwHBMzGFRhbSwSCbXTE16QEfHYy", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CsVZwWiUQUWw22Pcc287GRY2noBJvTCkCbS81pQ4tbz4", - "marketAuthority": "2LEzNZyz7Fx5YDV3TpTgLehBvdTybTmC9yQh3RfA5gV3", - "marketBaseVault": "CZ5YhshwqFexaseNkttfgzDrt84XQ3FkCUi5X3XXGvAX", - "marketQuoteVault": "2gWfuuni56zGohQMpZmcnpZeF96MDU5LxqwJrZXe5Ss9", - "marketBids": "FXmxamTKagaXHwjXVtPBMp2JSMs5PWztEUCR8wyEKH86", - "marketAsks": "2BP2b5ZcAb8ih33JYyXA2zHcjKJy15zRXWhBeggHy742", - "marketEventQueue": "H9g9UDcbpuy1GNw4bBsibaChsZbpNNdghRy6EAnXJxgb" - }, - { - "id": "93839nPc6m7AU1d8p9FHYKVdQ8PenpuSn7mEeXAPShFK", - "baseMint": "7rmV64vLfbrbS5rTFvojYWzCVEn8dnJ9RfSRx3nD6C5E", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3Qt3kX3eNnKnxkHM9C2JuxZEVZPpcMETA6voHSZ8L5Ks", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2txPNVtwCHnWPwcXN1yCrP2RTDiZD4A7UA8xsUm4Crq6", - "targetOrders": "7GZHgT6Um7usQwaimpdLdCpD6S4fJU4jrnrKCgdsxNMH", - "baseVault": "13VrwVRxnsoMPHcvtbhS4SgK6s8s4XhZsC6fnbK1ythG", - "quoteVault": "HwuY4vrgc2mJr5zMHfQeQu35cHUf3Ngsy1dibWGHkYis", - "withdrawQueue": "H291myyTeJvnxtTSQtSrYEvvZYF69L8jhdn2MtViYdZ9", - "lpVault": "AHsuZSbn7P66wR8fUinUpK1skitzqvQ4EBNzDgkvUTQd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GN2TTgnWm7WyMEFZjbtzZL2d7NxhBk4QMZtDdLZUkcqv", - "marketAuthority": "2uQCU14kEyC3HJyymfGv1LzQ9yJLb2vJzwKcxS7ziYzb", - "marketBaseVault": "8i7LH7p9VPYBEKs6CYjCiQMHnjPhgfAWRFfHcw68wDef", - "marketQuoteVault": "Gn1LZJT9r9yv5pPPvQRiXYgPse6jsctNiBgwuNZ4GiMQ", - "marketBids": "EbajVbEbK579rf4px39fzd3aJWuHB55FYhwGH2DkQc52", - "marketAsks": "GvRMjoxaFRCUkLdcEPj42KGPKU5vLMonxooJbGKoVsyX", - "marketEventQueue": "81uJLFeyjwdCn1FMm1HUCvQWKHtNhCkd1eNJ4wYYv4cP" - }, - { - "id": "939B5289n9WWfqdTyyxLd6CFxubruU2ZX4FBgQgHE14x", - "baseMint": "boomh1LQnwDnHtKxWTFgxcbdRjPypRSjdwxkAEJkFSH", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FQfbYgPFV2wxUJ5rkS51LWDxrBwtznahJpvU4pMhSBAb", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HADTWkVzQQ5ZzSAR9fiBDnVc2d3YZqWaqPQLp9C99XAW", - "targetOrders": "bUxczEzPq1VTgcSXicRoy8ohgTvmKZuDtGXLDzQiy3V", - "baseVault": "6wQuB4vS5uT4qRdFyFcWSKkkgKoMLf3FD5cBrohfto5E", - "quoteVault": "ADa7FdEykQsZidV2LETmKmPVfthoxkGyuq2rFzAnNdTg", - "withdrawQueue": "Fuv5QLev1MDxxFQBmyXosUAzfWxcqmhceAhNDf5E329L", - "lpVault": "BTzSTaD9QCpvraFd1uzxfvbCmq2ygxRBTUqDNEnBg8zR", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6Yxgcfs3oyZcGSxAemHscLJSZ9YWHymH7MummtiTQadc", - "marketAuthority": "AtPeR8TACeSx32M77mrNf4MZG8L7LSpHHQQsbegPTwBN", - "marketBaseVault": "RQoUxhanQVh1JyZ9X5Vc4Ucv7Z7SKDLCGV1X6B6WJEG", - "marketQuoteVault": "7mHj7ewvLDnihju2DcWHV8K7mQvpX28dWFcNgN7XtyNe", - "marketBids": "7xJ6r2HiS8TVNd7XccgQXvyry64LxLLB3JpgnnVS56t9", - "marketAsks": "BShC58WuzszTxhu9bmPS4WtpaZ6hCJMugGiLFN44dpZ2", - "marketEventQueue": "8WigsFptKna8WR8kLByBUxW5fLuiSiMXvDbKxFNiKLTv" - }, - { - "id": "93KFqUEdTyyMp3rPZah7vMCqXCeADXSZgKnkbzDUzD6w", - "baseMint": "GtFtWCcLYtWQT8NLRwEfUqc9sgVnq4SbuSnMCpwcutNk", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BFX37kBuUwKp3svEa7QWDeNkfYGA2D2Pamk9X2Hgr2or", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Hqb9wYDEuXbYBYoBFfWsBxo4kjxZRVJufV8wrkYYdxff", - "targetOrders": "7dH3zJc6cwdUozxKT5mvMUNdvANPPnPmp6PcqvSR1zEi", - "baseVault": "3eJJo9qzz4uEbZcrZSNFAJbRvPtdrkazeYu5NZNKM5jq", - "quoteVault": "8Vpd68mRwnz59ZgJPUXb96Yg4TJG7BH5B586sbdBtP3g", - "withdrawQueue": "FR5GAnRi4yKQvmF9EZWDfZKBKZaNHqvwR4aqiiGiMJgf", - "lpVault": "4b3jU219ZReWN1tFucZkAU6PdasMLuEFUdP2iyQPeDwB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BxdxDSA4k1kXRHjoMMcub3dfZoBqVNPLawHBbtwDve8F", - "marketAuthority": "B2VvGWmTi8B35DHY9KgoR57TvUCzKNftsMuiTTiqks3a", - "marketBaseVault": "Ek2kc6Kket3oYsmtXkZP3gRwE73QS87tG9AyUT85CfeL", - "marketQuoteVault": "HZC2iz3oUS9GrgYNcUkBLANuMQ5XQcB7p3Dt65baVoNw", - "marketBids": "AYdyhUZi2HT7AwCENwVN7vy8DSZ7U69AxuERscmCZfhu", - "marketAsks": "TFapqCrVcNxk8mrbJtyuTvX6ryiTTHDzm7p641E5JHG", - "marketEventQueue": "7etWfwZ4cfoPZcFdG43XWGEuZH9Ltb1tJKLzqyDJdx9t" - }, - { - "id": "948WQTDASWAM9cMh3i2QgsNRwbKtVSL1ehyxomheAcuV", - "baseMint": "Am2QTz1KrLs2VP8BU4vUjRxTynxBEfNMGsAdNB5Sy8Np", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8r6ouSNRz8DXyAGNLZMnTHfFuXQ8bo52iowgzEY9x3V8", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "id8fbKVqbUWqa3yBUgroLfvvmvaU9SwWw8HnZy3GBv7", - "targetOrders": "3La6mbUTLKVte26ERNTNW9Do9ADLrXhpyFqnSyfyuayb", - "baseVault": "9vUTcT5iEAaY5urishfA2pa1Lia41g69f1yxKSTAaHmW", - "quoteVault": "33jDuPvUsouyRjxqzvZjAcHER3kXeLMRTAKBSrwSG337", - "withdrawQueue": "Ho57KYKqFJoMgT4MqNU4jBVhipP5a4yqEoCxo1YezAk", - "lpVault": "C68RbMg8xjuT7Sr32RnR7sTJjuJjP4pWrKFm2VqQ2wWE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6o89dPp9GGtdsn43GqSAajcD6Qv1nsfAd3sX5fP79a9t", - "marketAuthority": "CozBiG7Pc549id3xVZT4fqeXpFx42V96fFR4rB7qvXH3", - "marketBaseVault": "5G7TE29BspwfVZP5j1W3qTS9iya22PYxrvJL9MyWiXjf", - "marketQuoteVault": "HGrQRBchgEGGYL4vV1NBDxdAo4RLEdgT6zyHwaUef2WT", - "marketBids": "FQDKsHzk8FqZMaS4MESds3BCL4WcFUkELaNDJ9PEec68", - "marketAsks": "3Rd4FJmP3nw9WeqM51XCXLxakH8LRqE2CwSXs37JSPa5", - "marketEventQueue": "81G9yr9uvgfAR468FF3PYdmXL3831boYtFTwizJh89b3" - }, - { - "id": "94goPSQw7uRm3rVphjMK8EmUcHdQ8qfvHkdj9bUiYM9N", - "baseMint": "Fp4gjLpTsPqBN6xDGpDHwtnuEofjyiZKxxZxzvJnjxV6", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9Vy2f442WTuUW2Z6Y1CqDQn7XLZf2nJLVcbnubKQAC3W", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5JjG1Yr949RhCWL9kj8GzhqpZHMkZeSmm2EY789isfaJ", - "targetOrders": "FczoroACfEJbSkUcvSVeCUDg1dbMeh4caVTxU5xNbhRk", - "baseVault": "7qk9vwaHduuQrHkBN9Rtr8ZJwDuozXCtcfGuobJDNHNc", - "quoteVault": "H5AZY5uwRpN4KoUUNFzt4krymugd97TzL7QoW7ikA2vz", - "withdrawQueue": "2j1Je9RMboKv9GoaUNZY6WpC6RfjyKEnraKoRyXeZsZc", - "lpVault": "2QBKKpiv7e2xm2kaouwLFNRQXgfUsRH5LwGrRG2Fxgar", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AAQR6j1ftW2g6ubAkTjrYvkg3H5aPud7i1GXViHLvRVU", - "marketAuthority": "9txmtu4cBKCN8QKfzJz8xKX8xRjXbhEdnLgj6bWunVME", - "marketBaseVault": "CDzkfJ6dNdHxPRgQRLP3wgtN4u6eWirWPh6uaYucBUbx", - "marketQuoteVault": "91K4vGmhVGaPu9XanVxnYy9oaLGB7s46BnC6mB2Si1Ed", - "marketBids": "6AkzaBs5vLTQWDPTpyK3fAMAAnSZ3g2Tii2MtXhSviY1", - "marketAsks": "EmRLD1AV4Wt8P1V7R1WQqvsP2H4eXSZpyrjaYdTXfkxS", - "marketEventQueue": "AjeLwK6SPYuAbvKQEiw4g6YVcSW4wpft2e4w5GPsuaS5" - }, - { - "id": "94JaAbetzvLpXrQr83n2knvvFnejb9iwAxvMJtve71jC", - "baseMint": "7MKpy8PeNjQM3i4xWzGiZjDd97mq6m4QH6Q8jrXnsQ9L", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EUmaH4yy9jiP8QqSCEgBZDo7J2FPxDgRjp6u2F85FjRh", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8Q2qcN3y4vEacve6ZtAPxCx389UroRPhYTqEgrCbFsny", - "targetOrders": "Aj5FDX87KixSDuMRmGqX3fkBgtGYS4eZHdx4m7p2npp1", - "baseVault": "CaA875xYmJqZ4i7YzDz75VxvppL33r6kWk4hmSWWE5nW", - "quoteVault": "GnSMuLLUYmWEazDdNZSPoDpnwwr5aX1QWyKnw3N2h7xG", - "withdrawQueue": "3MPkNFLZZC1yScQY66QCsrMczJ2hsjSM4NWNHesfGC4A", - "lpVault": "2CLA2iUkFcFi2hERju9mWpgJFBeHkj1TigPPW8ow5tyD", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BcoraqyWjbQNZLSTJoeYYmyZ4wzVt7pQ95W7uUpvyq6T", - "marketAuthority": "B3jC8NM3aGdYMEDDcfNFZvGmc8JgacX7NDHKCSjoUhU7", - "marketBaseVault": "F6bCAivin9ThjBbJH6ymo71WfsC842xy4cBAUA9rjwk5", - "marketQuoteVault": "3TF4bKvan3TN153CjnurFCS6c9b1mf7SjuTewd526r3g", - "marketBids": "F3yUTRMn2YzWM68irJLBm1JU6eFxwFzDCL6iyGuiEp8s", - "marketAsks": "CSPivcvax4CBhjfB2dUbxHxTsyogtv3ZmKqDEwYjJSnC", - "marketEventQueue": "7fyEgPUYLHFNCy7H2PD3MMcCFrQcR4wLmi9JwhfUANdC" - }, - { - "id": "94zWHhLfYob5S5XUFTdb3rohqxcrN4jQexEfhGHk1a3H", - "baseMint": "MAPS41MDahZ9QdKXhVa4dWB9RuyfV4XqhyAZ8XcYepb", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8yr3APwMDBLzutthdUJhoBmibNcz53zkc8CUZASJgPzz", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DTh58bEhgpcWAf6o3KRbCCAswWR2whzQ3Te5ibbCM6GE", - "targetOrders": "GjP2RgUU6MB4wE6HJqEkhXnvGtGuophfQr9HKPY8FmWx", - "baseVault": "FkXhPNAw8N1JSiBSDiSqMqHmntKNWpVUmzWtJAyVqNws", - "quoteVault": "4XkAQCQXY8yQyhfnpeBxPPXf8ta5saSPrYMU2aVe7oPY", - "withdrawQueue": "J51F1M7Qa7rW9ZMQfCexGC9b9A1c9CFN9QLXUqkxpBDL", - "lpVault": "DCAg8xecf7KpaZ1XrCg4GD1fMQgjBbTjPu53XiM6GPUP", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3A8XQRWXC7BjLpgLDDBhQJLT5yPCzS16cGYRKHkKxvYo", - "marketAuthority": "3Y3my8we4sHh9LBZUD1yxgGBUXvN5JRGcxzWfK17ejcP", - "marketBaseVault": "5m151dijN5oGc4cTPUaP4ge17syYXG7nVZEEDMgZfpsN", - "marketQuoteVault": "9q5c8tN2bgqQYfjX3oaSseDjcJ6gwtNHXfa6GE3dGA4p", - "marketBids": "Hp2gijwekwSqBm52bN4SJq9pp9Ud1SwJJbKMykmG7PzX", - "marketAsks": "2wFENRvrY9gpnFGJBPnVrmr8NbXaU3jbK3fJQ12Xhan7", - "marketEventQueue": "2XszjcKbRGh8GM9zvAG4dYBUE2wn76iMZ2motFEEDUWL" - }, - { - "id": "959wnqPK3BX1Fx1BWf8Z9PZ5ihy5d4vaReZev2UGE26i", - "baseMint": "663rbtf1FHhz1kQFAq41z63ViigQr8zAvZpNKJbZbF6C", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "B636zCzpU7NDQyGBwbSPSZVFeWLk6YB6E4cHUVPir7Ue", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9o8Y6HGJ37infmhgBmppuzmHzNXepLeocoJzckYNoYtg", - "targetOrders": "BhmqR4fwP2kScLUA9uS6oTdJaRW5c4RT1rdc4wcSd4J2", - "baseVault": "9NCHCHMHDwBb8F393nqwV7WKcodDfmesogZ2LkP1WSG7", - "quoteVault": "BBcY69kB7Z1j1xo5fvGvHBeUiHq3pdVvUFWYFeE5odgg", - "withdrawQueue": "4jHPXrrpbCU9hz7E3FH4Hoy1oP2ovZQUSP7XNBPNhgih", - "lpVault": "BE2FkJh2hRsC8xmUxCcac2Z29duwtNfcQoB6vDKZinJz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4qhWyfhfqTFSjZdgNYxYUULfUueaypA1d7rKYxPWiL5g", - "marketAuthority": "7eXL2AY7M3r2YLb7UPy7PYkdAAFqV3QCVggsF4U4aMEn", - "marketBaseVault": "4forzq4nwJwjZ7FKp4ky8n9nrzE8NVos4NN8b3J2FVjw", - "marketQuoteVault": "A5a6uTX9DdDSBJNzmyQ7GX2LPGt9tootLmgZdbtVAL5f", - "marketBids": "89nR1S5XLkPMRx28BSGNQSLJnVNkb3vDk8S96GJwGFst", - "marketAsks": "HS78iRFkyuHKEMPdcio8AhgUv976FxbBsxt6DXHa2yUY", - "marketEventQueue": "ANr4QAMSFyhCZpeXDsp3LKt5vWy1sDqwprX9X93ArJtU" - }, - { - "id": "95j5f6VEqfgcdVEUrfUWZQmH5uDnZpB3wNutmFVZvrPU", - "baseMint": "6oQTfGCkkPyDicUqZaZC9SwveSLJ42v5R3iBSdiTuZuF", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2amhyMvDymTt4QXYxi2nuE4ugqzmrLh5DArn5P3JLyXN", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CeTguv4mvqHZxqKjXcR19pHoYrqgNDp4k8woHV7t94DU", - "targetOrders": "AhBaUMQ8LY1NUvUbpwLZPNvh91FPrpn2D5NQZQpY7ag2", - "baseVault": "FqHaKYphhsT7DGCmtR5wKpBSFeRbFHYEtVyo7o19D5R9", - "quoteVault": "DkE7jgjZvqZDc9ukuCu6xpWiXWDJrsynjVDgZ2ht1Jiq", - "withdrawQueue": "3gnwoipuch6FsSTUZUFEcbAvfitYLFw9XLhQXvjzt48z", - "lpVault": "JB9wHwB4jyN22nS5KE3HdYKjtdwdsyumhGrUWntCFHty", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HeR7tka5LwbHiZsEuBYqzqxN5Wyj5hgM5GimVS5XCYQc", - "marketAuthority": "3Fx64FryzM3e3vZAuwLi7iv17mvCiqrr8aWzfQ8wsPrq", - "marketBaseVault": "4zifj4XG86UwsQ6izGmokZtTHkZbJefBFr6bAKiYqyQG", - "marketQuoteVault": "F7rP4VdXYAjdNnEaN7b28EBPitNCi1v6qLSTe9f3BRan", - "marketBids": "52aH6khL5Z4Wur8JjMd2wDtf6Nxb9KmfsaNTJxySgsT1", - "marketAsks": "DrjRaqTWU14KdBfTTa4rPQ8787bEAA5izCDZaoWyikqe", - "marketEventQueue": "7JTYPDAniQfeu2SHA6GFTLn9xfKjhBcphiAANm87eLf4" - }, - { - "id": "95nmxRhCgsZWtaokCAAUv7YUN1gH79eNcHrRontcPmmW", - "baseMint": "4dydh8EGNEdTz6grqnGBxpduRg55eLnwNZXoNZJetadu", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5GP9p1tXkPorGFznfwn4FxR5JxxpR2P3qzfYYTjTZ1YR", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5THiQTGTDSSNgmUjeq1nxJFd6RPyhTmLyy8ngoztVd2f", - "targetOrders": "GYLsLBTT61XGQ7T3RSX2ns2X9iKR4zQvV2B6myvjU9Tx", - "baseVault": "9dufxZKsQ6dUk7EiePtU4t9TDHcgeDPhqDJTQi2CFGqM", - "quoteVault": "9Mgz1ntmxZffPaSx9H3Qe9aW9as41DYDX9Fp2KaFSqmh", - "withdrawQueue": "TbpGdXuT3fqpoZFYsBxv7C7dqXdkTkk4Ep8Vq2MaRuW", - "lpVault": "FfxGdPDQTxcLPtMPg7QKpmHBGVxJfWRHZdaDemXd3u9P", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "E4HFSXgHkTNavzG3sScGGf2p9GPjMkHZyMqzLcnRhqYY", - "marketAuthority": "5Yd7d9MyFP36uBrc6wdKVgUtNR1e87cpdL3CfG27E6Pi", - "marketBaseVault": "6qxAP1miphW7xiRmUJCGmm8j14nPakcNM6gng2ZzJSn", - "marketQuoteVault": "9t3VHUiTJwskfZCxsqP8nizSZRUqnrNZKzwHZd5bWq7a", - "marketBids": "31vsnQJYeq9bSwXmKRsDByXMu5yvSgYRUiyoVSRTtVRB", - "marketAsks": "Fc9t8hesiAtdDD5f87FNqKUJhNjP21Ck4xJ4gAiB7sMv", - "marketEventQueue": "nkjMTpLKbe3BN9o2Pqa8goR9uNDNtHzDVgnwPvZBqt1" - }, - { - "id": "95sodjgQhhGoj3zvW1n6VoTWM1KRGzUJYPFYDycDbGVT", - "baseMint": "14r8dWfzmUUBpw59w5swNRb5F1YWqmUnSPgD6djUs1Jj", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "2dW9YddityDRf8qEU2dZGg7xY2KQHjPJgYgqB7WL5zop", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "26HWQpYpiAGTFqCuzzZSToAPhWrcSKyfH59TThZp32Qh", - "targetOrders": "DLvxzjuHFydcyBDAbvZzGowAdVmKkGcv2dZLw5gCMhvV", - "baseVault": "G3etbyAfnCwmf84G8zv3C8PEiYqjmJ9nZkTSBkjbjezd", - "quoteVault": "6Nt7jpVBRVuMjQfsKpob6HwySffH9azGRjrQ9z2Kfirv", - "withdrawQueue": "GYXSuzUhhhfMN9zRAC7iuYgB739kwaW4T1ZzyY5Dznfs", - "lpVault": "6XhQHyKgkY85yBY3SzB811TXFRh1A61fp6tYqA15G7MA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8Rf2wByp67vJHoHrqZqzFRyvYcjyFV4pGX6t1tpYqx3p", - "marketAuthority": "3g29Fit8jNoh3tFnacSbURT3rcWXBJdHu9br2WrYvjGa", - "marketBaseVault": "BTtSuZ4V3D5yK1cuMyRoeJe3YeuM3MdnAfW3UCacVq1k", - "marketQuoteVault": "2kfRHeJAvbZKAHhPYVHsYUvLfBsWUed1b4JPeymdt3T3", - "marketBids": "A4crg1Jh1qUZTgs4NN2wsHQ2iUvaNRNsTGZN1iZBoZ1D", - "marketAsks": "FrA5AS7FH1NSXr4SqPCiuXLPBKiZongZqAdsXZJMNiuj", - "marketEventQueue": "77n4hCcnCBVa51NErNW6i2zRjgMEb7X6ABYZmw7ndAF3" - }, - { - "id": "964g4rpzKAybdCcvjfw9LzdwoZwZ2mASHLrXQxD7LjZw", - "baseMint": "CvzmN4HEMt2R9tsLyCV26yV2sT5tgD6nAHd7TNtWvHXq", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4yL58JJ9xXmeunM7on7CHurDiWRnSZRKs9s2pyDd2m6w", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9rNW3Vn2F7BqudZxCztLEMhWkpD2f5V9szWR7nttLzS8", - "targetOrders": "3oWdDkeMKtCuPDsf14mVzukVpu7xvZ9AQT1nDRKj2FYU", - "baseVault": "4zMYCgGFNCaW4K6SwD2x3oySLYA2PVmAyzFVF3R1Sxyb", - "quoteVault": "Sch8oR3Qm3CfAL38AoEAVYcEa3GKSsoqkSCQyPZrLYn", - "withdrawQueue": "HNupeitJd5WNaDVh2Ynf9sGK9KFs9Y2QvnRzDAFGfkSd", - "lpVault": "7Cn95tWToZJXkTMCDVEjgt8UZ8SUM99dThNPiNaghegP", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ACerKV6gL2UdcbLzjiC8mNfNoYE4UHcfLnGqaQS62tSM", - "marketAuthority": "AvtRk1nPW2iw38Rb5poQwedEcArNm7hocL7aDq2quWG8", - "marketBaseVault": "CEk5ZmCDPxrbvmCspF8NVeRmPCeKNmoJiC9yaRtwpkbS", - "marketQuoteVault": "E2x3RKoZU8KrWDhKy3mBrKmiAo1tBvEcR4uUXeCBFeFh", - "marketBids": "339bLox5zQXkqW2x8z49e8nDHHAeN2PTLHV2a9gviLFw", - "marketAsks": "Auid11XYYrLkmM7msMuq2wuAe5Zuw1b5ZGAp1qeHVKs6", - "marketEventQueue": "EiBirUUUaq68FRBEYM3iqYu3j1yXE1gX9jbSw32sVS7a" - }, - { - "id": "97yxD4MbnrNLzbFackZCKdzzjQUZfJ5WvKxgtwtHkgRR", - "baseMint": "5v6tZ1SiAi7G8Qg4rBF1ZdAn4cn6aeQtefewMr1NLy61", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AY52BFRuCKgUbFSeFkm815SxXpnMiXDaECjpxRVLe81f", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7ffdEAki9n9gwmhC9SR3DYeLbeTHMPYBjmfUF1udCD68", - "targetOrders": "HZ5UmivrgE9RbD28gRBMzhSSJZN1qoP8yZCFqAxus9NT", - "baseVault": "976xb8LQpjCRgxfTDj4NbR4TUkErgJr89mXkqKBcjM3e", - "quoteVault": "FF3CGQyyLpVTbQBXHfUXi8HzY26y7ijfMcuidG8UqPwg", - "withdrawQueue": "D7fNU5aB8pUo19ayoVhsPnqH5kTmUfn1WEGZBjnT7Ynj", - "lpVault": "6qhzeLvxpnSWtcvv5xcRV3vvWLYdYDaqqJxU25WTbgaq", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "vAqntYupVx5YepaApzeFwGBEkyKHHnKP4wwyhdoNCAA", - "marketAuthority": "5MxWTgFq49BWTtB3dSMSygR8Pmn4MtzKKquBXWUotEjB", - "marketBaseVault": "RHSeWN9EMxZUkFCgeB898jxHKn2iJrzTnBALPvyh8c3", - "marketQuoteVault": "Et9GznuGhgAgxx4jhGbnfFKhJxFtkp4zA8U2vYVXKXYo", - "marketBids": "6YaNCovnz5BNShu9zJP2jnsZuXAefJM3gmjgbxxjk8Tx", - "marketAsks": "6T4eu36gQtiLjGaWwJUpU9Ui18h5SRqbfXKsKYuSenWu", - "marketEventQueue": "8tM4NDCU5CbfExzKa9ohaqTCQPwfxTK5VdQPUcm8Yp7Y" - }, - { - "id": "98M4CDPBBfKGfLk15YckdF3jYJbPVHmg29Qvjne5LgwD", - "baseMint": "HEhMLvpSdPviukafKwVN8BnBUTamirptsQ6Wxo5Cyv8s", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5nuajXnJXwXb13Xx1peuGYNkqZEfZx7f6WCxk3VcLRCT", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Cg64FDrveb3C1D3iZXkTQ8BwskT1RwzigMsHuFxAkdw5", - "targetOrders": "CS2LgC4hdEznBFGccWcijnx5yUcMpSFQZkYAMjGCTaYQ", - "baseVault": "6jA4sD9JR3VNFjubYGDgabhYW93kMaq38TRNZkVKCPCK", - "quoteVault": "5PpX9t9HtQVmHcouusmoof5AsvLUJj9cpz2pXKmdnzSE", - "withdrawQueue": "A2qk1tDCCfdLkCAqdtccG4HbYWA7FfWejHwy3w6A3E99", - "lpVault": "4LsavBpjmmbvQ8TZpx5b1mTCjq5GDG9SfhW3BS9CLvFi", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4JP75nztBEo5rYhW1LTQyc4qfjPB33jMWEUvp2DGrQQR", - "marketAuthority": "B6vKvfKDFYtpAvYq2SXwrkEhA1dFUcdGjRL6Wu8Lu8Hq", - "marketBaseVault": "2rKjiEwYdhHbyU87kDGgsDa3dd49C2du8taCPTVWeq7q", - "marketQuoteVault": "23jtFSSfKcPZ37hFaaoUbU2HhwRjXYexvcN3XR5264RB", - "marketBids": "Bf4iJYGiczXARnreNvYBJfqf9pYv8tLRtbM8wE3gh8Ej", - "marketAsks": "7ajoGvWdCUpAGgFf2bKE832Ro5MQpFiUAnYruMFL9rkV", - "marketEventQueue": "Ae7rQLQdfgcrzsBs3nQzPBcCJTJGjg1ysR3qasNrGgLJ" - }, - { - "id": "99bMYkE1R6rLVhQ8jrRGTAJzSR2jp2YRr2B34bRSZc5s", - "baseMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "quoteMint": "4pk3pf9nJDN1im1kNwWJN1ThjE8pCYCTexXYGyFjqKVf", - "lpMint": "23Xn1Va8237TE8TL7y6DarKr4LnFcXKzSihssBEujbnB", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GyoXnuJXCy3dUuzPgDzf8irvx48q66UpFrGbWoFr71oW", - "targetOrders": "32gngVhdH4dCCsTpstTNLn3xs95EZ3ccMGfLqJky8L6R", - "baseVault": "GXjJzrSNeaxknSVtyr6yMaEQXCB4Kv5TP3YXG8HhzG5v", - "quoteVault": "HwJNTLaSc1aY9oUZndW2T7tsvKK54KeqrYwYGGrTcrXb", - "withdrawQueue": "CU7YKr7sxLk2fMLiwjoFSDFJQYCu7RvPGUzpdSRCRo8r", - "lpVault": "EbuCjcuSMk8vhSjohzyXXbrtvkPY1qY4VVNfF8pxuUFs", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9kheVGeeCSrN4jWte8oPiFaSAQn6WCdRfj6z7GhpqZwG", - "marketAuthority": "DHkFV2fo6ppohcTCCCEiaV5L2kjVzhapTA5d5bTPQePM", - "marketBaseVault": "CcUTMNsk4g7XsUUto37UVCk3Go5j7YpXMcU38VrVFfeo", - "marketQuoteVault": "BhqUNr9MU77n13CaRpxVqL8xeZtJfpv2qH1cSE1Qa8eG", - "marketBids": "BrtGnGC1DQRnhLeL1Ji1vQq3HpHMoEzJc1dVyTMcu4Nd", - "marketAsks": "6EK6MLgf9PZ6zoMhZeqL8trgjGatJsQarooCgziZ13vD", - "marketEventQueue": "BhP1hmiKQR14wt9gnETFAcNRJ8PWm5foBMg7rGjtkUHn" - }, - { - "id": "9a4aunMsT1sLZZhdWyeN4rq5YbLVusUdDq3h2BBD1Yfi", - "baseMint": "5i8C6n4VbELnTHtES83aqeh16uPiEyve4jHr2QN2WhSz", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EnV6prJEKrNAJgxtDWcf6a8JYEEKyvZ1QX7bfNNbfspx", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CaM41zdzhh4uEZ9K7mztdzMSXGi9WJRydNYK2QUzDSEN", - "targetOrders": "7LXCTF4iRXEHRmFjSj7b8BU1jNL37YYpt8qbe6gRwuRX", - "baseVault": "4VzocuY3TKzypaoiTNvg2dhTW9bF3TDJNHVG4qJPFskX", - "quoteVault": "CHtaeN5BofjKecCATfPUDCdPBymMsv43qbUQ7z2RmMVu", - "withdrawQueue": "5mCK5BUn5c5sQkfYWz9dg2uT3WEb8m1reKBupdA8enQf", - "lpVault": "2tTMTsB8uSRaDKS6KZGwaCkxgU7HNdqKqRNDK4RcTdBm", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "tFFipwre6KFJbvFJ9fBsoikmV6rGLU1xG42eNiVyfJQ", - "marketAuthority": "97QrXFExVoe1fqsu9GRaW7SmMChEAxvyQYSuvkQPydeQ", - "marketBaseVault": "GJ5Jwt1kWDGxtnjJphCKhzSPdd74DRBKCMxGcJNKipMo", - "marketQuoteVault": "8EG5nbmZMzmAjViAKMYuhpKi78VNTB36wp6H1gAyzFnA", - "marketBids": "6Q6FG9nRe32feers8oMxoTBzwFbedesiv1F8JDrPnvPg", - "marketAsks": "71PUcqgtiQa8rdjGkFwnwPgidVwfdFoLo5xLvT7zePgr", - "marketEventQueue": "4zQUXCEb9tfHSNEkayNXz4ZVShAQtBD9en9Ge2cBriUo" - }, - { - "id": "9bcwDk3mAq9NGwMx9F1hjTzV6Pycr3KRJrfGSb1m8bet", - "baseMint": "5uE8w9yoMMu88NV8wUaZMuxCiufBBoSiJbNDAEGmDx7x", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "D9AQtALD5JzRAFiKWELDwNZLQDRfgu4XEkSCJfzXuXSH", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7AZKQo6tRkYGQFBXypN8FHf6EvtZ6QfuUXbhY2E6FoQN", - "targetOrders": "8UXeVJvHCk3QHXaFBzxbjveZgf9tncUTvj47YkPc9g4G", - "baseVault": "8gQRste2RKnrhZ7QqZy7hgufkVK6RSAyYjMLhenqbyuh", - "quoteVault": "qfq7Ayr5vBCukQHzyr3HryiJHMYUFSez9FJsezsUMmB", - "withdrawQueue": "CuwzdbRA5GnLwao4ejygYa29nKoDraLxaoanyjE5zwyA", - "lpVault": "3ZpWzgmviEmNA4bzTgCp3fKusmXRuVyDAgvT6MT4DaQK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DNCvhiPffXZUuqZEyTyfD6tMeQDG133UyMFLDgrU3Z5n", - "marketAuthority": "GCe6N8SPXCSB2AarCX6S9UWTo5CseexoWVi6b5GEeSxX", - "marketBaseVault": "FZBxnEKTmQtjwozwktpvGLbzu7pLHKL2NQ8924RkbuV", - "marketQuoteVault": "7sUpVHYAo7vux3rHtDhZ1z1vJ12bYMtsiJAdZ4LsBkgm", - "marketBids": "2gTMyxvi5BYsNY4mdyk11p9usegpzKJN5CJL7vYWRUG5", - "marketAsks": "8RuuRecfpUqkBZTEQ7RyiSBypBRMre5RNWp1UGjMjtGK", - "marketEventQueue": "7W3PJeNqtmGTZLDokUZtnA3FVMzZkTmnbGBymy5Dfzmm" - }, - { - "id": "9bhv8C8KCqxYWQZvGfNcFRF7V4g8uyR2dYjGcnQX1Ucr", - "baseMint": "Fse2oFDfbwT89CqtuoFaHCBnGTMFLartDYDjPLZyc7e", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "62dTGg6iq1USiWcuFTV1rWpE7cYpWmg3fReomrdaGmBU", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DXkzQr81k1rHjZ5ZFxiF5cBc4h9fZ9eHB4XwnSfotiDa", - "targetOrders": "54azWTwE6t5JirqBHSq4tRxsC4ZsJVZhZDL9aS26tiCX", - "baseVault": "4uGACmvx22YvqxmVmYWTCZ5vKoTWcsESaAvrVcLDsRVT", - "quoteVault": "moCMHQaF3Ux7tAajgWkeMPjGqe6PFf1Z6YwYr7akKxy", - "withdrawQueue": "ApL8TxzpQ6J7WB1fL1jFDLZjPjGSoKGRt3uGjFcbcWzU", - "lpVault": "C3GFtgkXNmpVFdVweu7LBjmwCaAALdydSsP3sUxpxU8d", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3N4UgbUHUkwMU5DKFYRvz3HASbFjs3q9JLAYVRdEQvbp", - "marketAuthority": "CNZykEinWW4N85VLcKfVNuVr5Asdx7V1QYinAEF8MhD5", - "marketBaseVault": "7KPeSrbcYq2TGvhNgD1mFdbnruvH9BoPvdF51btTVKwa", - "marketQuoteVault": "6cYyGxJmnnANdJ4PDnNf52fXpNLhcmLDSAzJ7RVhW8ur", - "marketBids": "5Vz9JwmJbmUtB8Fa5asnCW7BXcRPh9jQRJyju9ru1ybL", - "marketAsks": "8wxpF5Bwq4w6N2CAmV8b7qhf78h9rXxvW8rC1jciiCWt", - "marketEventQueue": "3DrFHujsgN7aWyD5SrZnN2DmLqseoDFfW5CryqLm1brg" - }, - { - "id": "9bQSnRbDHVhCZKPmTdkjCQWa9qxRn6vpwko8aSwi4ZgQ", - "baseMint": "A4zyBooAFkpfy7osonRJMQ8a6zArGxN5fNXjXo1ZTZK2", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "J3JnqzSpp7TzSL4XR9FcK5Sagq6AhkzyotuHH8fAWRrg", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Bk9yR3794GuvndAph2AwNxnGTytoQKVfBv4SQqSnZWRY", - "targetOrders": "EP9GFR8LAmSn7GRF3CcuWoKwzWKYwUMuK7y4fMmR4Stm", - "baseVault": "GQihxnwy3kCDzRS3cZRXZqUs4xKka91THVcmfuRWBjYL", - "quoteVault": "6k7v6j4e9Vju1GdytUdigb7WZbTFZcfW9Ghe675qL97c", - "withdrawQueue": "F9P5zo5VnPXAVJPKLDYv1jD8q63nZ7D5Z5pBAUuYazSY", - "lpVault": "Ekywsc2f7bo4JDQJLfQe14ouWXQGUKBZeWgYaEcwkvLX", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8PufGMvwt3imPCPUmfN8wRu5qpzaUK8KmMN35BmFiMQS", - "marketAuthority": "A5kufz6HdTtRdkkpbQZowuk75BCKcYExKFjWmn4jUn3K", - "marketBaseVault": "2r7zHL3LEMAGYxfa12EZVZ4CFqkWtk9NDmxsAYzq8o93", - "marketQuoteVault": "G3cFS36FKhJoH4JjkVP9FaAjmcUdGFAKjjubsqPtyu58", - "marketBids": "6XMdf4REALx8TkZRBbACjWvehAuWrFNkMHAPbqjRDneY", - "marketAsks": "BRHKEgs1sb2u1f1hwDsG2qeXeQ25TYT3WL7n8gKXMeX8", - "marketEventQueue": "8TqtzaW7MByDAhsjzg1n5Z8ZU1mUvCHEq5vZXVSTpbFc" - }, - { - "id": "9CDNv9iBxwHbACrEY5sENYbpe1FAW3XfgSVQdEZT2k4V", - "baseMint": "GNC9uTx8dBun94hM8PeRmEGBb7LJ7uKrgNBnooAaQzXN", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "FLPMAkN9Rd8vYfLXuGDnVBYuH4HH46a1FgWmTVWYN2uW", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4mrsea5y72wdPT2NnwWtbtmePH5YwtDgi1LpPB6tpJzx", - "targetOrders": "GSL7TYqUsmY89u3PWwJLPWuSVaqEryy9iAWMMPaBPe6f", - "baseVault": "6131aQrU8fN1idxhkgMjdwphyqhV2VCn8kVYDvpifWv9", - "quoteVault": "3mm9frZNRaYsh51YstgP9GoiCqzj787FXRXUqKdcWAe1", - "withdrawQueue": "NGuCTJiNUW1KE8tJ7Wupdn14yTM4hVaCzpi8GPFPRkt", - "lpVault": "9icgYdEj2i8ryxTYCMWLMKymNJBBZS9Z72DNFe1YDAfK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GueqznAkfqBzVuCWhkwWH6GpBGkheVbSYz6CZt36BjoB", - "marketAuthority": "CHWFhLBbE4fLVsnzNi84P4BLYJ8Lu3HcqomQ1ksQsd89", - "marketBaseVault": "Gkux65kahoHpwoDrMDoxZkyKn1QnJo71pBbfNnBvQuDS", - "marketQuoteVault": "2zW6Lxyc8To7RsQf6RrxTdd8Zobz2kWqpGwCtoJx6V1N", - "marketBids": "5PmQUD2ffEzR5r16zP48ATsPBk3w3dstNgheEx3ULhFU", - "marketAsks": "GcUXK7RQjyYHFATi5tZouKY89Pq8auD2S5yndZLHmorN", - "marketEventQueue": "9MsAHNcLdnna3gRYJcKomdhtG7wdAJmSgsaaNJSQNuVf" - }, - { - "id": "9cwnc6o5GfsxVHU9HyHg113zMozMfZLfoJACCvxXaMww", - "baseMint": "2geYxMQ9o466tQ3JitUVR5Xmuk4a11KXs7ZmSX1hiSJp", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "G6EpAsR2KvBx4rDRFJ8S7kAhxuPKpjRCNYJBXxeLjHNM", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CykT5AEmNKGbTsUtCY6LLMiK7R6boeqFSTe5PBD3JSiG", - "targetOrders": "8BsTaNYexfCgiuDmnPycBMTKtouezE98ucJccGNhVVYP", - "baseVault": "FR3c6nNvTJdx2ACy5oxchJkRq5nq41v7n3dJeWDd1dRq", - "quoteVault": "13dNymaZvCWBxtQxyc6ZHiHHUuBE5f7sKp3cG58CQf1F", - "withdrawQueue": "GUiJ6amFtRrZ4KL8x4TDdEgbQmrPYQyiKiYACasnzGir", - "lpVault": "E195YvH5XyGRMKo2EVWSTMVo6a3Fdw8yGiJGHJRgNBwE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "23Rt8673QyBE3FUg9AECf2ZcrfiNfy5YS7KB9TtaBG7J", - "marketAuthority": "DdUJLQnhGecDJ3PBELjWMgTLCLGBz5MnGixZ1HyWUuwS", - "marketBaseVault": "9pVx9rDyPh4ABmYw7FKx8gDQuDtSfoypoKbvrVEB12Nk", - "marketQuoteVault": "Fd2tKW9UvGaC319meS6U9kjeNhnNmasF4TvW2d3n5fY3", - "marketBids": "APijE9PJmRwtyo25ueBbJj79pyQywjmkhhweRvk2axcr", - "marketAsks": "An6jDSBngj5NL6GRfQWDaBU3euez6YKnEvHsd8wKeRHF", - "marketEventQueue": "5hf6HG4j2XKy6JDHC73ZKa7CPRXnJyHpdqFySATKZAKp" - }, - { - "id": "9d8Gy76Ki1xmB4vzMbYwHXvUkopYnPd82dmxkQqqDbwT", - "baseMint": "7tE99RKS4RwQxEjvZfh4CQMoQMMTRdL5KQbugsfhNYPg", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3ZtiSWG6ksckQLwqDmsGBh1FHdTK5cgDSNGFbJ2oEp1G", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DMSLyk1iydB4MNV5hbyetEpFyRyPBsg537Xkj9xjPQeG", - "targetOrders": "4QYNsM5bGahGEkc8y2Rist18ibPZbgEn3LJFn16AAzmC", - "baseVault": "FCnuhNxh7hBDPMwguajwNeGcBN1jzeXS8CSv8yD2pTuw", - "quoteVault": "26F5WZZdzHpEbEZPUSZcuyHFULT53bUYXDftDEBwBcAR", - "withdrawQueue": "BkqV2vaZf42JeBPe4HZuvsyr3JtwCkrx1kHFT5W43hPM", - "lpVault": "Hi4oubTDoF56VUqrbbAYPi7p8vwQ511YtuKLSzi3EAGp", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Cc2K7Ao4FtgoquT2ua7zvRuYnQMBSz2s83A5zTyR8h2z", - "marketAuthority": "BVNeaLRGybbupgMRZpKD3tR9yUEUeyr8CrekhkHQfYAS", - "marketBaseVault": "14uDu7ndU8i98Ge1ShWBLTxfdGxXixQq9yeSCs27KEGe", - "marketQuoteVault": "FuhnC7cEyj1CpU7xT1cCPG1NQ9QbixskmTps5yJJ5bQA", - "marketBids": "2FcA6yy51PB5hHSwjpqXWRsUW7jPd6HmMSkjT5uGnDik", - "marketAsks": "Adazi17sX2iRAkrBheanFiq6AiucrYbwKzhi1GBbvj33", - "marketEventQueue": "C4FKrZ2kqu9SdSnnJe8GrQNHabxY8Sd2YBEV7oGEjViH" - }, - { - "id": "9DKvKbJ2cVG5BXuKxFk9cKgjioXvcFxCfkyKRp9tbBkP", - "baseMint": "HkNokfCXG33eu5vCcS49mq3jZcKZeQSQCyta964YxxYg", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FASjyHQeuoEzgFV2fc1wvi4Koj4dzmeTQKPfmvA4nCph", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "hUyVYwixweZ9s8CNbY6AGj9gLYTtmxbwh2QhKJNaBeK", - "targetOrders": "GzBG5G3B8aCN1KoCjwXJqXfKetjvanyGLiwxDyspMR1X", - "baseVault": "BiDvDuQjTBCHtwad6fakNLapyxnZRmCWZaz5koNKR6vF", - "quoteVault": "FPZZ8bRAfqy5jdXno2d8y6cjHJUZvmGoLUacjzGChH6t", - "withdrawQueue": "41k2LkzpXsVUfV1BjREHzEgVtBtV5Qo2ttomyqFZ1txD", - "lpVault": "GyTuWQNxz9rvw99sckJFec7rWH7fCeMHGbwz58ZSugaZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ECaHZqfwwAf4DCEAtnVqS35ZPNKDTFAjkD9SiARsvTrL", - "marketAuthority": "FVn56e8AGakww6btNtxkxMUcqWdVffnMwAB7TfZ329L9", - "marketBaseVault": "EhcgxVU6siXfB6Y4bwXkr6Ejh8kvr9EDoc2BPX162vdZ", - "marketQuoteVault": "3jZS1Ayjbd79zFsv8ChLyEYJBuArtCDPWb1XB58DZeR1", - "marketBids": "D7gYWqrfCs3sWEMxS1ezhr7zGVcteDuqwdxmNrfheror", - "marketAsks": "ERYtrScySoxTrNC2zWv2JsnpcynqiYmp5j6S9mwPGqrp", - "marketEventQueue": "3V1UsHtGrZU8Ee2neFnexT28ErzYCfiYSKnGLosg34Rs" - }, - { - "id": "9DTY3rv8xRa3CnoPoWJCMcQUSY7kUHZAoFKNsBhx8DDz", - "baseMint": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7GtZ2MnsH4PLFyvqWmyF3EQXgW78kBXCuAXt41vdKd1y", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 5, - "programId": "5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h", - "authority": "3uaZBfHPfmpAHW7dsimC1SnyR61X4bJqQZKWmRSCXJxv", - "openOrders": "2a1H2xUFdja6RjPJ6RKWDLraURNCEY85LdP3GXcDeg8y", - "targetOrders": "7MNfSggpTRM5uLSrKPwgTKLpxwYoqy9piHiuRFrV6Yhi", - "baseVault": "8WhX9Y6cDkVUhBmm1TT83jX2vT7ZGwXv6zAQiUg84B5U", - "quoteVault": "PH3UpBfXJNazcFtUuxHMFtwtoAYJM9trKMCTqgYX8ZA", - "withdrawQueue": "11111111111111111111111111111111", - "lpVault": "11111111111111111111111111111111", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CaFjigEgJdtGPxQxRjneA1hzNcY5MsHoAAL6Et67QrC5", - "marketAuthority": "PmGWi4jXyde5y4ed8GdF1Son68LioBRGuazkCoJM8B2", - "marketBaseVault": "3E3J4Ua9DPM5fdmRxB1AM6S5NqbhBh9exudHcs5jgumz", - "marketQuoteVault": "D6xgt4XSTRFAqctmY5byT4Ji7mvTihfnuNxjJWPETe7M", - "marketBids": "AXTKA59Xd53s5a26PNALtnmqfJUWzdyuPN1w5qFMHGio", - "marketAsks": "HUCmvkqFdwixBBMm2vMgaBfJ5ArY5b7RqfYbACjCPhpp", - "marketEventQueue": "DMPcCyyqqDhxU852FU6rP6bCy6dfWGWjg2KF21y9DFt4", - "modelDataAccount": "CDSr3ssLcRB6XYPJwAfFt18MZvEZp4LjHcvzBVZ45duo" - }, - { - "id": "9DwpNJupMHJZ5LvJ6Xxg4bzsQRN8cZ1akDhr9FGV9qGg", - "baseMint": "7FvaS3FZ3RThvFeZspkzszF9hj5Zp6SMrxjkoz74NfX", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3hon98MeH92kyCywcyM3J8nSqAmQR9acLa5iQoSVWwHG", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6VWyxj6RXsABothpVEKpX4bMWSwmbPZyUnbRfBJncrYg", - "targetOrders": "CCyjAjkFDCnFzsoeokZXHcQ1H6hKm6p8sPj1UCQymmth", - "baseVault": "6hG9U14VeLtfUSSz5E7KHYToqLkXsdmy9rLbxbgp3AQH", - "quoteVault": "Ey5wBbFLgCpaYsxysPDU5tGHmuGhnDQfMrgcoFXEkCmr", - "withdrawQueue": "77FENQTWWXFNP8AoWLybUXrh44rCNMB7dkdTdbCnJQ1G", - "lpVault": "Fmee87CPg3BDoSrpAH8MSn1zKxHmRdubBaQ3V1hdLGod", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FnFrWJHAzdGEzJo3qzxvdbKxMDcThyY7PC1rL5hpLiA7", - "marketAuthority": "CoDLWigQ38rtYAHtCL4ZSP5c9T2PDNTLzydrB7h5YQ8m", - "marketBaseVault": "DLyFaKsARuFe9rQhzKZy4f4saKRez8pK7fxaDgebni1G", - "marketQuoteVault": "AjUQD5KJRg2cnrV64QtTcDuNktY9Nnwj1tckeLRfL1t8", - "marketBids": "DimBLYn5NnuRVWsfAWpRxAM5egG1rt4KNaapGZ89eYtU", - "marketAsks": "4cLd4XZA3n1m6yUhpaiiwfc31aUgPNuwfUqAbFK64GnH", - "marketEventQueue": "6KG3V3sh2MLndv3Q6mWXZrZpwYiNCgG4AUkKiNPnrvfY" - }, - { - "id": "9eCA1LjuX45deorWu9zQdFJyciVx15CUFuELuFXGXidu", - "baseMint": "imbaePRPNVxBhTLdSWpdjYbXiPWc9spNTz4xKVkZfBJ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6LjwQFwJqdEjwkhKwuEb6DFXnPUDRzHG3Uyfb5HYK5G8", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9wnG6w4367AjKsC4WZsCCRJffdZceyjssz5WTYSqTBZJ", - "targetOrders": "2Uw2E4NcVcF8xBrtSGNtXsYdmyrRdrqmwHHo2K6HEumb", - "baseVault": "EQJnSrn6m8DpjzSaP6G4J4FfXPEspNb8PMx1K7jcYZwn", - "quoteVault": "ECkWXocJ6XjoiZxKhAS6iBzD4fxdiUbYppKX4t6YUuAv", - "withdrawQueue": "EQuQtSACjME2ZWguL5T7D1G14QpFd7ScHfQhsTzqWrek", - "lpVault": "5QvQwdghgCNWemUekcZgzymzZ9GpuvP8UVUtFsXzhQVA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DcyJbg7J1Z67S8Xo7XcSiUMHWyQPNCJvCP6h3fvkm1iy", - "marketAuthority": "D2DfQvJWbpREuUMzXx8d3dQV2XDpg86GbmThtmxnvejy", - "marketBaseVault": "ETX8JvCP7bceUwzYRkxckSGDCFVqCFRjpJuPCkWqfLq9", - "marketQuoteVault": "G7aEVTPNU1vqwh238aNKqmzscdPKtqXtDQkG2Nqg4Mps", - "marketBids": "6HSYjATR4TaYYz5sm5MUYNSW1snhcVqivozjiMMWmHWz", - "marketAsks": "4yD453z2gqpiB2wVguSucj8ERLELVtsDZG5VVkjSMBUp", - "marketEventQueue": "Hwqn9drbbUUDNEfjMAxjV4nHKgY5NUokkMPZ78zn3KmJ" - }, - { - "id": "9euZD3C1d7e2fLKnUxHc7oUUDJcYnguMT6cRzLY9y4o7", - "baseMint": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "2pdg9vAH8GsTTWSSP3Za6j5ts4Nzs6tEbNterVe9H62H", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "26YmKFtedce9kycdjo23DFA9XcMqJCjsqUTywzh5Qh52", - "targetOrders": "JYyNiaTpvS7Tq5egRS7Qeq4Xaes1qwe9fd5tXi7Rsu2", - "baseVault": "Hn7pZvyfMJ6c6h2TD2GAk6YXf1QZAeprSz9v7Qt97DWg", - "quoteVault": "6kZ4zcNxPzKAt33Hiq1GKPrSmdw1M28mzyKKmwHWUqPJ", - "withdrawQueue": "5FozwM7mGKvshoGy9CpVNTGnynRu2gVydiQczYRfLnHS", - "lpVault": "EhNGjPxTyGTwC7NmyRpqop5hAGWzQX56UpX2nmAUFCUh", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FDkK55eE6Ro9mURo4YGgHafL3D5NW8yhnkUAFFoJB8SD", - "marketAuthority": "GXZhuCYFVauwV4R9zxr7CuhNUo6bFLFcsMM233k9pdef", - "marketBaseVault": "BcySyd2CYFmVAm4qjWRPAQhpzjBYdKL44tQy81BieEUW", - "marketQuoteVault": "4ZMS58ocMSiJWoNBMrh2g2U1vS6EM6cMAoVMhkqbg717", - "marketBids": "pPHrhPTCLhxn6HGaPji6NC9mQux5NveFMuqucjr4gw8", - "marketAsks": "4kEEvo4Rh3AdqtDjrcKXYtryctjt3Y9yrdgQix6e2MTB", - "marketEventQueue": "2RtogEw3wXbmTnVKmxtWVB7fGZPbsbgShxeGgV1n1znH" - }, - { - "id": "9FBZBzQpT6YpryqSyUgK8t1Lj8XCxRUFYRYtk1Durm6M", - "baseMint": "GEJpt3Wjmr628FqXxTgxMce1pLntcPV4uFi8ksxMyPQh", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "AN7XdHrsjProBFEcmASGCFYcYmgbgE4p8gZ2hZJ2F3R2", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8tnypznLZag73JenLfVYponFigRFjxegPimMugE2fRWS", - "targetOrders": "GYAiPKyTNebK5XjM8hR658h2c9oGxF8rq6nRZm8uiffu", - "baseVault": "63X8MEcQTxC4bDhCLhbCwBVfNNVEtbKf8xVxXqf67y8", - "quoteVault": "HytJkzmodKXwr2RRGgQLp7tpvAVgevJmhXmWcaEtVw2w", - "withdrawQueue": "C6TptdanHYHG2BNmmiTKJQtKt4M3HQxMkvoPweYpmUxA", - "lpVault": "Ggs5wTzeyzAhVeMubWwF8wrTAU3qNmKpa4AVtV2ggCJX", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7YgG47K5TVgAf1thFsh4D7SpEMS5GzLrQmABtfrL5mfR", - "marketAuthority": "FXyQJuJmqgUBFNrp5mBXd2QgcgKEmVMJXbaT6mBqgJ52", - "marketBaseVault": "6dnjSKBEnh8zR7B7ruL5Yb5fq3ood2SbB5ANCbrxNCoa", - "marketQuoteVault": "48NGK7zJjaPY9C3hfrAefou4gg82V4NwwJNCZ5364hAC", - "marketBids": "ALPWrfJtBBCDiEpPUpM1YHmEhETq45cJDZ23CuWMg7R", - "marketAsks": "9TLisbpcpkBcKzAGa3eETHqUVrMQbmnjD35sGNWf8cTy", - "marketEventQueue": "Dq3qmYBSNhoYsiALZKoYU5kCKXup4YdnCc7qPXEbVQor" - }, - { - "id": "9FgjbiHsPCnMhcd2WQVQrHvx398GmU5K7mNzBEeJhxKa", - "baseMint": "GaAzf7jwEKTouDXJExH9TKfvX3Ae7fLaGwNuEajq7KsE", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4w5Gc1W9sPpLMqXJ9E254chuGufiL9xJc5xMUqNdNCLF", - "baseDecimals": 1, - "quoteDecimals": 6, - "lpDecimals": 1, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BYfP9en289m3J2tx6jpdjqEMZPsu9vFt7zi5KTbGjfCw", - "targetOrders": "BxwufkBuk1PLWeXfZesTJPoQZP2swfrqcmPZsLNVKk3r", - "baseVault": "DDuhHXyQeYy47Y7Vrwx5LPKj16DQJW3oL7CqRyhRC1c4", - "quoteVault": "4ow6FcRTyH639TQmipbMsysh4pxhLoxTsrDEHNCbXGjo", - "withdrawQueue": "DAjtFs1Miax224FgHArYibvnAzgtpWWj3MNK4yReejCC", - "lpVault": "DMBgKysGoBxywzzJkifxEGL9WRxZ61MVipJe7aMvhRP5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8VBCzWzcpwaE9GEQHvejRDy8mbQVgsFBzbz8KqPPdVKT", - "marketAuthority": "Ec2hPCPK9FePzzyypF9aZj2PP4V4xtYRGmu7RspQAhma", - "marketBaseVault": "8J6WPQ1RPit862MNrRQkDmpkA524FUEy2bshmy79yCDa", - "marketQuoteVault": "DP48r4HnqQBnTPxwzksBD2u9YHSRp4zbhEKPFUsSMCpw", - "marketBids": "U9JfkyZ7R3Hro4KuUi8zpDXdtL1pdGUupgmmH3Vrnvv", - "marketAsks": "8d9PDyhyBD4ABjaJgo9u9D3xFTri434HoJV54QHMVfam", - "marketEventQueue": "6amL1gW76jyTEt3k59YFrp4uaqttyU5NXWSS47tU8dLg" - }, - { - "id": "9FRBFiBcw3izkaqkNdTejQVec9XQR4zebk1R9wt1V1SM", - "baseMint": "9shzY9jupopFajZbKP1sdhzwVwofZRejQgq7Kvw6jQKY", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "J4qbFWfkAnftL6hFB8e7bSHtSp89RqHsH12RGMb6Jy2C", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8QLWLJP5cioh5MBSod8o9DvKPRptMr2ksYD7LeS2aYb9", - "targetOrders": "FYpjTGTk8qsi9wsh2GX2owhFY6JShdJoJuapmbeWqjAo", - "baseVault": "5zwRwVZfPyphqYFVN78r9nobSk6YC7pgQQQ6CcJZZ1QP", - "quoteVault": "6ptZkmUvDxX3rN6nz8tx1mQw358Sg18qNLgdTxm9uCa7", - "withdrawQueue": "4U4LxHtHG8L78GpTrXKAhc36C4N2sx9zLAvNK6U2GTks", - "lpVault": "GwKvythseKKjF6BU85RXBxCqwHCPcLQvriqxFBY3eKy9", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EWtridp2ArF5XGH4Ur5VCPWgqwNCPHYBMvk4mpzVSvpD", - "marketAuthority": "BqayjVhE71tphk6NmU6Hr51RC5GPMZFMEz3cF1KJ3G1y", - "marketBaseVault": "CeoKRza7TV2yc42gK3meWh7CLGM26mS5TJu4fVfvnaXe", - "marketQuoteVault": "GLAjrsrwoi2kjpgy9tSnxWeFJyi6cPdK69z6N4JaRWRU", - "marketBids": "DPoFKSwxBQK2xhha96TvM6wibKPYeagsafYeytCXvVMw", - "marketAsks": "Py3oxPXcbaCmxkH4wXBLQmBQBYgoqHvEVRVRaiAQHTN", - "marketEventQueue": "GsSwqnzN2uq2PKyWBwu7KmSKizDb3EvA5tQGvh12Q2dY" - }, - { - "id": "9FRWUijv9Xbhzpg8Sbbp3VY46WuaX3xvs8hyUzHwreDJ", - "baseMint": "5TY71D29Cyuk9UrsSxLXw2quJBpS7xDDFuFu2K9W7Wf9", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DYGsm28rLJerR6RE9rXfVuQaPimgrMWhHSYXJys2p8fB", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Eo1mEA8nHCX8aEaWZAt2L6CQzLVymTignb4k3o4nvfaC", - "targetOrders": "7Gt5pniU61K6B8zLSPGaFwiGtVjc1gWKLNVsGoVxkKWe", - "baseVault": "9KyHYRSSKnHDD8oUJu8Tdcc3omzRZ3s3i4SU8mLF4Mgf", - "quoteVault": "AXWeo3H3KAwWqpqC3fcb7umE2Th9HHy1MJf8dZX3Q3eV", - "withdrawQueue": "gMtgV8qfA6Pkx2XdTeLt77q4HvJynFAFjE7qMMucWQ5", - "lpVault": "EH6DYVyDNQVAsnew3vR8SyuaSw575mNRpxemnsnY8Xwo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "J2eCTuKaABG91kCzJset2UfQRoggHcY2Cq7Stu7natXr", - "marketAuthority": "HYCZSW4z3G1Bus5qBfGjS5tg8h2whGgiT7aB6jxsbwor", - "marketBaseVault": "CFedgdAaJZBF9QPtzNWBz3jtWQQfMhoAAu4jfc9TFxXs", - "marketQuoteVault": "Eo2MiEdsYt7xjJK76DnKPkbTpJ8zHjFBdra5Hdw5axLU", - "marketBids": "Atuch1aoCTvP51zFrVorYGT72oAWjh945FmrURpcxr12", - "marketAsks": "FvsqHEgNMbWVcJiYQfr89jC8yFUC5qrWkeJQqyFUsR4Q", - "marketEventQueue": "9rrSHh5p5fNndcD3MEwmcrgqFbQC3xsy6asQc3Sp61sn" - }, - { - "id": "9fWfbJ92CMCxC4C6d7iFGPw7DuFf4baucJ59g5jy167h", - "baseMint": "3TMdBbnXKASdx9rBcZ5HQsyqCky7Gt2ea44gYB6Ro15A", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3kdQ2e1NYUzXGoKqcGPtBMpp8oT7iyx6aGoJq3VDkthq", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4dfqVhppcJYn9NRcmx1YMvDkNy9LcAzoj65iLnyCXee3", - "targetOrders": "AXMZ94GXdnQgy41ELZ3is8rYxRn35De9wG7QYwgEiU21", - "baseVault": "55HhvCCmJr1ixQ29ubCJ5aoxcw7riVngrGAdELrKmmDx", - "quoteVault": "97kDH3P3Eu8R1CC2cAwRWbug4SjQ6aqueK7TKPCkafcL", - "withdrawQueue": "DEVhVyu8XXLSjjL1Pmi3dPgJ8oJjdj6UoiUBvytddhU6", - "lpVault": "6CheU8SCJ4aVsEprqP7q1Sxsb1NTfaeyuyzcZ36kQm1S", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "H2aauJHCUgUUY31BZpKcb3VwTCaDwcoM5UYxavUsAGk6", - "marketAuthority": "5zHQp5UpGGhADPaLxmYKtejj8tvXPQc5oayQmiTuHVFD", - "marketBaseVault": "DnbjKAVzpXB2HrineThAY7BD53PffXiVJDqG9bkJeq9G", - "marketQuoteVault": "5iyLeedFf2X178iHo1xNbFELfJ5HTcqb5rTiHzE7jYCz", - "marketBids": "GgUE9mtjy5HTLVDGgxxY2Vg8CMhDZj8TDBfByib2gZW5", - "marketAsks": "J6dVSwjUFuczFYXSByGLGZvF2bpwFrfV1PV3BEtsu1PE", - "marketEventQueue": "CUJZtbMH4U3zdn2WmNuRGR6aD23caYuibZbLt6uKjgRg" - }, - { - "id": "9fX8LVxtBUm3r6JiJ5BN7YpF9QUm2L6dASiUrWy3t98L", - "baseMint": "2VFkmFpyFm9DMKch4UdrdyY7WHLGrWgwJLAdKwHd5ekY", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5DKohj1cfAAf71NALCzPcALHMXGvEYTiQzuzoexth1Ni", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BfHLhvdEJ93imWMST2gsoKnH2qtFDYf5T5PKY8rYsVyX", - "targetOrders": "HgH3qMYr25tkb4zzbSnSjeoFHW5gsrjcZoAVZTJuSAKk", - "baseVault": "D1Vfeu1nMUXEVR8ghRryF9jJMBHHRYxbh9GxWU2pg34d", - "quoteVault": "6uw7nrCnf59d4ipVr4pFEyLWUFmxWBCW8tRqLsj69HCR", - "withdrawQueue": "4fPLyL97NPKqomwF9adnYBVo1LP6kjiNvwGCRda2nBii", - "lpVault": "86P25QhqxK1nAqAcBDJNBLwhmUySVecuynYdX936hx94", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6CNfNyUC6iMLhGCRcmUwJNJrV32wMsfTbsewkWeCnz7s", - "marketAuthority": "FRHEhCNFZMWQVuKoeGErjGXjpMoBUPC1zxn1nCkoH9x7", - "marketBaseVault": "AGDqohh6rM8JCUw5ZUR8dvBshJAvsiDBsMJMFSW5FRSs", - "marketQuoteVault": "FitvBPoT6minXhp4yDC2wjUUvfoBNYVwjiSqmoRK12nY", - "marketBids": "9k8oiXwQcRQFExWcnQ1frvcCGaJLT7sXQ6W6A47yWt4w", - "marketAsks": "73jzTTtGcusWKpyKogHnqX94vjJksu76VNmBkUB29gME", - "marketEventQueue": "2Kx14V1EuohdkKvrabH6vqzLqnD4EXwJ1sxXuDagSVs1" - }, - { - "id": "9gc3sNKpG4WUHgpNH7c5ZwSfh7zkorLYSQiadLtzZF2t", - "baseMint": "KUPoVbJmipJb1M7xzQEND5w7u1BbmBytu9wZ2QPjQx4", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "65VpbaU8okqg9iBJjcz9BKmAgCX2kRFQSyb6FoBuM4CF", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Ac75uCuvqTSe439oJEhv6ByUVovkCaHu38fjxKk7J76Q", - "targetOrders": "58fQppRtUUmdoVwHeNWgXnWTm9LgDQygfLSVXYAHwvNb", - "baseVault": "5WeeAbuDzpubPUa3nPoUaLRUSyT4T5zqTXC5jGRqFAdR", - "quoteVault": "9fTPF7JhRpHnxkBmjM1utwQbwNNp3MQodvYWqobMzsoK", - "withdrawQueue": "APGixeYRQvoCqv8EFdrC7RuwTuau2bhz988GGrD3R8Dm", - "lpVault": "HeNHXYtY355pMXtcwT3optUb5T9NowiD4Ux9tZFj26Gz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Gjxg4x8BturwnABaTeHvasgHPXvgLDVnu927ttu7BsAg", - "marketAuthority": "8hLbaPCwWoCXUeKYqeiMpABeh2Kru9MYJMtf9PYpgVk8", - "marketBaseVault": "6da4TigyU6P9j7jcdCR9ogVUf8KcArr8yeiNqDvbFD3Q", - "marketQuoteVault": "EZpakFzxCcVTx51Cyf9oE82torZHqfyceWxa8eQRc2Fs", - "marketBids": "6zZLGDn2zrEyGq5GdpNdF34AN2gKS1z2WaXDy9NSoBuQ", - "marketAsks": "4DnWmERvf3f2EprTcr9wYTWEtnL2yCKpyrpEKFy3LX3N", - "marketEventQueue": "7G4DQ846o1QA7FFpQnkYjVCDJd9iXjtZkAgQDetfKwMT" - }, - { - "id": "9GDdjzVk9C4rXKJJAXapSob5jXguacyVJj8UgxzGmyc5", - "baseMint": "DAtU322C23YpoZyWBm8szk12QyqHa9rUQe1EYXzbm1JE", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "2Yj7LAmxS9xpY3J4bTR6bhWaLtaQ8AqXaweTStkynwFJ", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6QNnn4zty1XEgucfBYdzuNKftDA6QAQ1ud8yba8mY7uY", - "targetOrders": "3CcRRPeCTpm3yorKSyeqKPgWncT34SBj8fQ8frbA3WvW", - "baseVault": "ADapaQaZGZSUaMAY8qnasp6EQgFRA1Yn2dLMcDRi4JXT", - "quoteVault": "6Di4WrQLgCYdHFu9gDApTrhviPyssVYFVqMP1WNBtk7v", - "withdrawQueue": "BK8CbCNo3Vs3pRaj44NuBAfYVbfPTvuFcf7Lys6DD6KU", - "lpVault": "BfgxxHu7Mh1DeFmb9Mf1M3zbfxEWXYhd7gngeM9qKPQS", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6DGwXer8P3iGDtqYWAqzXpA1xBapmDWJtVHLC4dJhAcT", - "marketAuthority": "H7jEPVjaMk7sZbz7vDoYFRyaze38MCX6fxKarjJvoJu1", - "marketBaseVault": "Dq5Qdotq3pnUexJTHssPiDmEBM1D5r1tAt5gqdsMiosR", - "marketQuoteVault": "2SDucJ7qha43JakLv3aox4YFowPz7UY8W94ACx8McBsF", - "marketBids": "H8gTyenfGANEFmkNGdKTFYaLAw86YNXAUYHHkC4noSof", - "marketAsks": "DcnUwhJ4WVyKTLxdS1x2Ew4LXW9eUpqx49tMqjtjWWtc", - "marketEventQueue": "BwMXdLHZp322CcZ8sR52NncLw5Ck2CpupMWZqjms7iym" - }, - { - "id": "9GWz5exH52JAHhe4MyKmo96SRAJy96ZKhEpqrnbVzYqU", - "baseMint": "AKxR1NLTtPnsVcWwPSEGat1TC9da3Z2vX7sY4G7ZLj1r", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2cCCDWGTrraH8Dn68Mzj516bGF3NBHxZV5nzvpZRvYAd", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4zCsnjqxbFn15B9gu6jXB8V3HBPz7Rs69hCz6wHp3GZ3", - "targetOrders": "3QDig9brE46s2SjfjRoPfbMD8wachzvCNvxMtHytnoTx", - "baseVault": "H2D9zNet9ybLUeCnraQPF7b37MPtsdZSdQxQGLJYskgR", - "quoteVault": "Fw1mUEqxYnQL6MTKf1UuKU6HnW64sqRn5oBtXDLzyt5Z", - "withdrawQueue": "J71hfX5N463eHiBgf6vogQjUAHrWGsp756Vw7wB7c39j", - "lpVault": "4iB5Mx44S1EM4nFXp4wGY2C9nmwJtCe2DCSsA9EygJ2y", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AcDU8kQRQv31pJxwnMim89jmCccBxB5YWNYcP6d57jfb", - "marketAuthority": "FbCmtuGoXPq6txQ4d3148xkYhtmMw4N37YxLmHyJLivY", - "marketBaseVault": "CRuwmVJKhb5qkcdSXe1YPQ6zuU7xHaaMthN8jM6hB4ov", - "marketQuoteVault": "6CQ1kcfaRN1fzZZVSC38WPM5euyoE39oeismDdTnwTDK", - "marketBids": "76QwxxyEkEKpamyjWPyF1gWfcorDQH1Bb9gBvdf6DQv3", - "marketAsks": "DQmFNYxUfCfjao8kegsjoawvxAEX56ari2tWZtgjrjd3", - "marketEventQueue": "2Qh9n6SUcef5PiRjVVdGsBNbCV3mDKoPeiQFHGGZibah" - }, - { - "id": "9HspZnNfgxT2aeaj72HVZg7i9rG6FgjHLkpVagqwsoLd", - "baseMint": "FBa9rai1T87DKPGN23Px87QXy7u3XBxNy4ANpiENmaBB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EDV8nYN3eGNT799CiqoeC5szLt4dsqPXwS4wLBba8b69", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7QscMMtgwJRToXxoA2zMFHsrx1xbb7PprdyE9EfuMWc3", - "targetOrders": "A6ZUMLnZSiviReZq2u74KfRCA5GnWpMAdKycTkAMzxyV", - "baseVault": "DjpxniDesvan5RECYvEmW4f6EqQaKesLtiZfzx9mMCfY", - "quoteVault": "6PVEo81pe3mMJhRHvGA8aFk9adu4SMvYxaP7F3pvw38C", - "withdrawQueue": "5P4ueM3BJP6K8rNW29jbNQDEcNWQDXGaB2qfa1m9147F", - "lpVault": "t3nZDWSwMzT53DcXEY4rTdYvfrCrS73ua5kcxEpyQae", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8LzuaB13x8nqFibhR9t8W1Ur79YQwefw2MMYMLoMpnPJ", - "marketAuthority": "AtbL3hYHZPVgokVmHGrXNDJYFeh1PGiHeLyjAi1PKrvx", - "marketBaseVault": "BYuZDDqiwjCMeU6AdL9LNVzyRfxTSvKhyevonAHhTa6p", - "marketQuoteVault": "5q6g8uvB4LzawEiNSbEno741LMzdzTmEc5Mt8hc3ixtj", - "marketBids": "7oFTnVpvvbK9JKTk5cT9WCCzLte5jXy6fw1fwVaR8We6", - "marketAsks": "HDdvhiWVJM4rLFLuPyQq1RcsPDi19ugP88RgkEGvK2Xd", - "marketEventQueue": "EG1gE8pf3Unojhyx3T62ekmcJu973ARgrLzmU783cKLu" - }, - { - "id": "9i4H5SfpcYQEFiHFLzH851v9ry1i7GRbXpqL7AMnByLv", - "baseMint": "Bx4ykEMurwPQBAFNvthGj73fMBVTvHa8e9cbAyaK4ZSh", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2fGkhcbbvHhM3Nx2WW19w354HZ8gsGuNjHdeeckQJZsk", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DJ4jXW1VJ6rU2PEGmoa7BQiGPkYmK3cT1LHUSiPy6WTD", - "targetOrders": "vLSTYYzYex2ibDbB2sQTUBxRCX3kfYUyG6FK3pv9Kio", - "baseVault": "JCu3baEcUyEkxFKb856eLfDiVf3D4xjDxZSdYNE91QSD", - "quoteVault": "HRwnH4XVsNKCVX8YhXHv29UXJpkjzFWahWv44PrPR9vK", - "withdrawQueue": "ARou1nFqsBRwHozF6XCpHxhhyJqJbypXV8SX7MngTjwv", - "lpVault": "4zKzucWsW2v8uWmE9xv9qdkj5cL78coHZ3PsZveHmhhd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "21PEcBLwqFceMAfPB7b8Rt224RpH6UuUrwqNTSqdPse5", - "marketAuthority": "DnkuVZzMj9Lx2PF72EeDTE7s8dN2ykdWNujiyjveDP3c", - "marketBaseVault": "ABMJKgdQirEJ57pMp9QBxTYNJvdR4wE2QLzniQPALqsk", - "marketQuoteVault": "9wqzEaW84o1GJfYpGNW7MrFtH1pDSUUydmBoG6NAzKjg", - "marketBids": "ANC4bSKfLHQsgZF3WKUjr8Fke78uvMkrne7ErEtq4vdx", - "marketAsks": "4gQAyteghaLyb48HvHUErJgXJxa4KTBPN2bPMZ6N186K", - "marketEventQueue": "wvrSEAEStM1ZawDmxtmhyji5ihQ99nnkBK35rbCNzfC" - }, - { - "id": "9ibLM6MLyuL8naAMXzjy4axXkx8Y5JJMpZkTGd89FgDo", - "baseMint": "HS2DanDUPKEnkzXDywtQKAqWKbWte3ahvwMhcfBJjGai", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "ByvNnMWHPWi1gcSh5VZqTxqS3q6h6hskJYcFbq2sj3EB", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EGm6WwTy3dS3D8MyNPAzNxPbJKYBAkHWyWG8Pt7JQDuB", - "targetOrders": "4fRkFbb5QVwhChxu44UTYPGs4i7iz9gcMbvgA4wAcodJ", - "baseVault": "3nbAdThHQAs8Zu3c6SHYsdZNtRM2GBHJaMVCFjcd4SME", - "quoteVault": "9BBZs5Wd6pSESVw4MK7XZUndtgRL3ujL6d21CkdLvzjW", - "withdrawQueue": "3R99NuKRBQQfpXA5oCiwMebscbb8nDyM32xMcdBqY5aj", - "lpVault": "EsycqXqy7QdQV9HNwWErGFedR9fuKhk78rsL6Nh9sead", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2mjpvqQbBS8W2RW5k6LdSj2KrfteAXnyFxbTtsjnbE3X", - "marketAuthority": "D5xxogxqVahZeaT5wPxHQDfnp8N2UkQBQEFZgHwR2t92", - "marketBaseVault": "EziYLgzUfvQtgq7e9ASKbk83HK7en4mFm2HE5fCjLXhc", - "marketQuoteVault": "9tADYfaquekrZyoZSVQv9MLJyxRnKotz4bTswmrKMckW", - "marketBids": "EiSK5h8ojZ1eLcqPGvTGDN4Wh6b1T1hgb57ZkDXDs7SF", - "marketAsks": "AGPwAw4vSjwMZBC596QEkrUw8gXxxkosFTJPbSduqtZp", - "marketEventQueue": "BfNf5h9mPBwgAPq2mR8TnYSce9aXBJigstVmBJT6oxcj" - }, - { - "id": "9j7yumsGcAtBzkYWNovXX9RirC5qBcA3N9JUSYQ2mDj2", - "baseMint": "7i5KKsX2weiTkry7jA4ZwSuXGhs5eJBEjY8vVxR4pfRx", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8BiXr5J1fQ3KdC7UvY86wNM5Hr6Cde5rvDuYx7sb1pS5", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "23dmgAbXyCHdL7V11m9qbCvuz2u3oqXy331991eJfgVj", - "targetOrders": "BHSvi5t1fCcgZTS8S11EJCDDawEt6jc7pxu4QsfRU3in", - "baseVault": "8cA5Vs3Po79hTeGS63rFfiKne1f4gLCugzRQqb71DsQd", - "quoteVault": "9bYCzRepgoKRDPRbt5MmyioyNR2yZT5afNwaAs7CSpKx", - "withdrawQueue": "8vpst4WquMnYFDcDEdQoAU6bZnApsyeNSwBtd7Cx7RFB", - "lpVault": "3nDynMLVEDsLqLyemKnVBRj9Lq7YFAcRfSZ8zQre2z4h", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "B9HfUpFYPTiCdeGAb79BpJPsJi9mQUkDfSrQBqZh8MBT", - "marketAuthority": "81AEaxUFTabugYjHp1yzGWMTtaVkNh14rNeifzLMhsJp", - "marketBaseVault": "14QK32hhgvSo8DT6CccL6RZ5dDaKPZfuHVNPHP5kN4Ud", - "marketQuoteVault": "F5sZdnLEXsEUzA6gwSYc8PfvVP2fBDio3hcFrPQ8rCCM", - "marketBids": "DscAuvngnKtoQxNmA3LdRVDxmt98tuJyt1r2eXsqgMCh", - "marketAsks": "BTG4BYpHtDqSYvx6UU6sngavnxYBushpG4fExeytzjbC", - "marketEventQueue": "5ez6LguttnWfh5yZ8wWhSKFbvScy7fDReQo6dxisoDzW" - }, - { - "id": "9Kofgn1ZJwMvPpafKttDdSNy9EVKXxuJfctsYgMehrMa", - "baseMint": "w71tgPPw37F7sCxxq1bcT63D3dtV6bJ7MUD3q7fpLqg", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HJQRCPX2EfRsZiZ32masAF9YFvgp9nZmEgQKSfLgvLbi", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "eNL4Ka5aJF5TDqeW79b3thohasjWPhLHRrJ9H57w14F", - "targetOrders": "AkVBxGVDfjXvHh1wXFG6mBBoPbCJtm4N9vT49mcLK8gi", - "baseVault": "9rXBimLcPhdBTSvirUJyoSNESzFfzoa9qAQMVbLVjgYn", - "quoteVault": "aax55ghCzLo5phDHxsT4SgDqA4krEgQoMzXXL2MshjD", - "withdrawQueue": "HCCBu5mKnjRLPFfGi67eANJmDsxVAfMhXsEevnwZxN49", - "lpVault": "6WWtqXgYpvEWUExX1QmBZTxWRSdbqXtKnqsas3A3e5qW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "F8E2ap49XFoQU82hFmeMWNSpaYkq7ea8wMWxHjV4ewp8", - "marketAuthority": "GnGy8NFiuaq1tFiwSe6EVsV5ACN2ixFSsHS1ayzqBDXT", - "marketBaseVault": "9cZGvB7wroRo8G65pdFQoteHAh8Dhm6p4C7Ld64bywZj", - "marketQuoteVault": "5EdtUk88xGWqBuX6YdJS9HimXVyoX4F6sxB6L1K1UVfJ", - "marketBids": "HooysGtxTGW4QaoTwtSvFHHtAsENV9G12E55Yv5vee1Q", - "marketAsks": "3X7FgUkAY5i7EF2gR9ixG6afx6YUY594kSUa7igwCRKu", - "marketEventQueue": "F2eK24hpezMdJa91AZmFut2y8jaRb1oNHZVrCFAvqwcQ" - }, - { - "id": "9kS2krr9iz2iq91k5KLKuRXLt8npxEYB5UNKw4w7yzLj", - "baseMint": "3zD9zassLocyH6Tdj2NYXw6ym1jtgaM3QDkmeJNwNjer", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "jxP7Q9gXiViCSuuTUV58etCsSM2bLqAevzXcajsnf3j", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EGSawiHh7iLgjTZw7VmZ7JqB27omrdAdcEw5NVkTkfK8", - "targetOrders": "ECbMha7h5F1tqdpQbikbA9MQi8cuhTTUStKRL4jJ9zJP", - "baseVault": "5VMRdcYhV8G2GYFjTySEhVfNmqPamkCkWsUWWXwjNGH1", - "quoteVault": "44iXx7iZ7HWQd5X4wzsipfWT6cGHvRx8GZQoR4EP5e3F", - "withdrawQueue": "9Pga57WtK7gNu54unzi843LZGZiuCta8mexDzNz7pXx8", - "lpVault": "APnxxF7yRZoAsCKiaLdCBn5hfjdez9KyQVJ63o5d3ejY", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4efkPTD3aX1bWTAhtcXJvVdZPf53EutHYGksgJMrTtoT", - "marketAuthority": "BFURhUnibhLTN9XXBmPYhAkQkRfFZYjaQdeKkMSuTQve", - "marketBaseVault": "2Ykz136pq2g8CxuN2TyAvrmB5bER1dM7mUqc2U1btgrP", - "marketQuoteVault": "6ingit9hjwudR3FAzSWmLGLE2L4ot2tNwZQ5hM9qnFPk", - "marketBids": "HWvZRg8yfsTxgJym1pXSbjoh2SKS1JUjb2tp7T8B5owN", - "marketAsks": "EHGhvcrxikjQD58K9N7ZrMWziqxcYqcDoehCdTZ8puUp", - "marketEventQueue": "HzNmPyzhTvvhEvGJv5TooF2aerXmvh1jmDNivydoWoEi" - }, - { - "id": "9LhjVRoV73bFTnpCbPtKp9HbHebyHkwNkVdzq3zfUMVU", - "baseMint": "A4Fpxz1RZGmscTxbF2Hhwywi1mGPVNaucc5gVwuM5Q5b", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "35TxzM9gX4jyx4k4jPYfGvsYPdfo5rVE4b6nmFzjyigr", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "37EFvfEKEhtm1mE9dBs4sJCquMmBrKGKhVtJSn6KQ2jn", - "targetOrders": "Aorf3VUoVVVKAA95YGAaJ8pdhuW67ge1NYq5YjK1QkZw", - "baseVault": "DMJ6Hr4GUg2HhtNtN6U4LYPznvpgL8FH6hu5AueJzvdd", - "quoteVault": "E2xki3VDNHWN8T3wnFuPLP4NBVBNv38y23fKxpDH3RMp", - "withdrawQueue": "CAcpJVFA6V52vqvpYtqrR3RDxaokkeNCo2XKhZr7CiHe", - "lpVault": "DT4ocxhygJSwuSZ6zcATSXHpS5xUf9PanvmLwnVxqQeG", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EUrDv1T95SDedFUQxakNDEyLn5AKMq36kPHW8UW4H9xy", - "marketAuthority": "4n4cnR7nQKLcYrhjY66We8693He4mMVK5VQSt8ov7BYS", - "marketBaseVault": "BEGJ42HrjUc4YuQWEVrRS4x2QZYHzDivc2VhwD8NtNu1", - "marketQuoteVault": "DLr9iqwu13tmqKoLc5vuiwPVR34JCs7XSyvGZhame76X", - "marketBids": "HoGYpm1BbEkJzJ7tzbPhPPF7Ca5rpDf58f8SVQGXDPBM", - "marketAsks": "A1PF5f3vXHFyuMQeRzDConx9sCHGBycVDcin7AVshhjY", - "marketEventQueue": "HrKBBVZzsKtcwkma6CXejgLiqvwB6Kw5TzJA9n1WNQpY" - }, - { - "id": "9MaiUCRLpXH9qjiEr6TgpG2zAmx2hLxCZp7Mpw6F1DKH", - "baseMint": "892ghevHKmmyV7vWJY6bmqA4ArxirYNRdnauUdx7q8R7", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "13nXHzPXZZ78NLdXPfTUMQeaCaWkftw2TyXsJrhCC2uk", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9QJcL82XiueKKhgV6Pk7196xZvbT5rVjLRvAQDqEkAZ8", - "targetOrders": "7NKAjwdC8y5fdCyZnh9H8sGtH1GL64A8rj3qHUnhPiTR", - "baseVault": "7K5bdCm3BTrE5vbhp13SMXmNuvp6vAHxMoADsMfGYZdp", - "quoteVault": "ArTzGsvq9vNi2xf4oR2rAZCaCmZQdrs5GiJ8ximJdKKB", - "withdrawQueue": "H1Bh7zsBzyibzCv8pMsieA9duvcGdBA7chmNYr4YK7Vk", - "lpVault": "2PDxVd41ZVwgMvLVT8YTBHhGrbukyqyMaQGn2tqBrVCi", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AV6hFsRymCo3Cr3toK628Zt5hBQCVTjSbYDA4Dohd5B1", - "marketAuthority": "HCcyhbgZeiY3mJJdt6qGBxVGtDehGxYHzuvQqLD34vmf", - "marketBaseVault": "7NLekwdJKnYXjk7c2ijRv4Pr74eNHDa2F4VpM2toCVYs", - "marketQuoteVault": "Hm9qh13zWwbrMBV8LP77TcpKhTA43epCzp3Y3okndSBx", - "marketBids": "4jiNh7KiiUjwfLM5DN2ZvejzZYAxRxyKKt7K118Qsbop", - "marketAsks": "Dd4mnALRtunnqtrYdQLfx9oy1V3d8P7dMGpb8PAkJsQ", - "marketEventQueue": "BxPRNjDkeYo4NZcFXas6vu1GQoQHr1rPvzee2b2wwKoF" - }, - { - "id": "9Mfh2q1ZUWZ99QcQTcvjkYWq8m3TSTe9cj8ZNtwrKRDQ", - "baseMint": "7zhbkbKpGaUsJW7AD4yyAfGGoy53Xx2H3Ai5BKcwGKHw", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "E7CG7AdTq8vajbnicr3VzbufSkkQNnHFHgr1ifLPbm6q", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HMeySstiecpjRBTJiCeoYorPjo455em3z3QnnGHrKjNU", - "targetOrders": "2TRfXYxYoPvfduS7qZ36pRbetsT5J94cTU2NcgsLqut5", - "baseVault": "CQRBnWoFE4qY5q6zx2qFynzTb8S55VpDHnPPxHSaSKDq", - "quoteVault": "tcikQT9fW2upXF6kC5ExVqz1GwiG3pyHDeMF7E9Cgi3", - "withdrawQueue": "2k1RVFZpBV9MEKV7LNBLux2MRfWGAs2kzRQN3esNJ2pc", - "lpVault": "FyCoybLPyhoZnCuk432C8j6ynTiZtAXzZVAqaDUYDmN4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AvVJcsk26dYHXS9Uya2tkDdSD3i59ubvo1qYKB2w2j5C", - "marketAuthority": "BLbgyUxioxCPet9mzgSDWEfvPSJjueXdFSPDq94QVEdv", - "marketBaseVault": "2UsSy56hkT1L6RrLTsS9GNFP5vQ4Fww3VfqiADQ2H6n7", - "marketQuoteVault": "ATcFQGyQi1mDs1hgVeUPmw1dijCeH7197t2urXY5MNT2", - "marketBids": "FWmfZhWvNjBPHQoEzWAzKXo4Jiz7eEricE36jz5fAsCZ", - "marketAsks": "3oR41NuA1ZE65uT1D1xKWAVbhTrWHm7kRgDWe9N1U9BN", - "marketEventQueue": "H53DJR2NZTXDrP4TNeBDyHXRy1SR5fmn4Eoqye7j6Yo2" - }, - { - "id": "9MgoYeVWvgLTLuPspL7SKstSRtmmZQzDqdn5EqFGTaNQ", - "baseMint": "CPXDs2uhNwDKAt9V3vXvtspv9U7rsQ2fVr1qAUDmuCaq", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BrNgfgPARci8BUDpn7vtJPdLzuks4yHGYSzPU2YMSQ2y", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3N1A2U7YTUMKQXcy12uSytgbkHVHsDdCe6HBJq46JABH", - "targetOrders": "2VfuzjMXR6L9v6RCFomhdL98pyrwahGbpGJ9oG3kHoEH", - "baseVault": "BS1MTRU13Da9UTAtVHtGeN2o1dghmDg81fzSGrHNkshf", - "quoteVault": "BYySA1xg6Wdc2aDGR9PqN8J2GAfib1VAjBvNYaqd6eyu", - "withdrawQueue": "EoCJCDR2j5bhwz4unaW3EGzTNKjCAtnXBeGGxw36eXmU", - "lpVault": "qdPiNeABWqBDfgtwe7rVNqQ8GJXVhU6HmQn3amwBhp9", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9qCKRivUcXaoe6BdpM6nPv2tKiNBwDiM6jxgudJuuNBE", - "marketAuthority": "5UwhxBi3UVRJ5CAbsKvHEEWohAiDiJSbiWKmDTw4k42M", - "marketBaseVault": "87fJff6w6y3btvLGBeXEZT9HqwnNb1YPraYVq5D2gkPF", - "marketQuoteVault": "7cfJhT1AW1raAUxSSRiWHt8xaVWqWLnLHuHVEN9h2KaU", - "marketBids": "EXtw12h2gT2z5hfJjMxX2qP8xw7x6qNneXEkGBChfeSb", - "marketAsks": "6Hcp885N7eiR8JdKSvvr8MfhYwGrc974YzmJq5puP2Q9", - "marketEventQueue": "CzLnLDRwYk13BVdWQ21vjuabciMya6ASYETPvhQUSTVo" - }, - { - "id": "9MsQHTj1PJzCaJompshxUjavNMvNYP5K4MH6chGQiMpn", - "baseMint": "GkppDJvtDJfE2SENMg9i6EvSTTgvmrcmnNJrNXSoZcbJ", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "CUmsxzKTQ5scePkqxt2FZPUzMYbYb2UyH2afzMFX27Q1", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3nDTyVR8yvhTNZvxnvmpZv5C5Xpk1GSyS44VLXuzXkFH", - "targetOrders": "A4AmK1XqQiHqQsqQfNEYuaZG8M7puwpBZQ3KomVM7XEw", - "baseVault": "B3vRCpu3FWsg9TQ12LFxdaYxWgdGGAux7UwQ3xkU1MaS", - "quoteVault": "CGE5zpwwoNhpUcwuQ2QwL3PPSXK2cDjFNrB13zQf9U98", - "withdrawQueue": "3idtpE4i16bV1yWFG6imWXSMYfoBf7JX8axiQbtc6pTU", - "lpVault": "8cqaUrXPF6stLctMM64mdKkG4rdzaXoDZNJ6vFGiAP1Y", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "E1WqVrRCmu6CyHiwMwBZtXG1yNWAmhujxbVMduLhf4dG", - "marketAuthority": "pmqjUWy26BzibvhMWgtJzUz5gHbWmR6Urr5fhA88fvk", - "marketBaseVault": "59apvt7Y2mqrw2QCUPZ3THry6aWQNGUFV6kEuYK18p9P", - "marketQuoteVault": "ByRJiXFhA6QFcw6XJ6KUinZjeHzRwnFRHS6HjLBkj1Dm", - "marketBids": "5H9BzXJoofb33PzaNaJpQ1ZVBE7SriLziT22Z5HFZZ2L", - "marketAsks": "EkVYNdT46AzFH2Z8GXsWM2t3UZ3dHPbkaJ1DrwHh8RpR", - "marketEventQueue": "5A3EX4C2jBFsvhnkZv4DhXnkGtTz5kPtxEdyG2Te8msg" - }, - { - "id": "9MxCZ7fJaPBGrg6d8yDynnuA1qKxn5Z2fnENndK19hRL", - "baseMint": "A3iozx9T9wgrtybnecQ9rv56y9RF8ThUrwRGWiF7hsmZ", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "6C6EQEVTnhCy3huiXtFmCGjtN1hBzXFEzKvTPpwj7NVc", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3Pnc9HixECPYS1LVTaT77kRsBKmCLZxRG8N51DUmcCnx", - "targetOrders": "6gFk5pKKFsakzQU6mTyKS6yEcixdZbxydBZxUgSFtgPR", - "baseVault": "5xuRpb5zuJGcsWCVyWfnpgR7qpQjPWemqBKD3NLkfgXx", - "quoteVault": "3sUtkXp2fXJAonVHY9Kr17VJRXHZjeJaRgp3NEyALoCn", - "withdrawQueue": "5fTZw9zdkgFpbMbchymZBFtGdPnh9M5QN9nUi51BgpTU", - "lpVault": "9vefGhyVFNLAtg5s8iPDXoVZXTQ1YTSPbNa3Z3CqB9jy", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "akME1kd6SbgyRyGNr9BB62sNhCXfnDvsYDQYyDXeaDv", - "marketAuthority": "8aA5ANC49RTkaHLJDoNucVGK3dSbgtJjaWV5wCEMoZHy", - "marketBaseVault": "AfD8nXag75gyRjcaikvZdPHgwsEsTZF9uoDmu35idCQb", - "marketQuoteVault": "5kunfTkDQTxQdxewsQG4FARHLwZZPeGKgYhj8gbXPrz9", - "marketBids": "3J2wCFCzJSH5y8cJCqgKm9nhvi4u8id33ZcAG6RjK6wg", - "marketAsks": "AxVnMSePNjmvgRZ1mSVgVj3WYD8iUyZc8NFEP2yBhP9f", - "marketEventQueue": "7q3kX6G6mGM4gGQA9EPT7gArofNgpCvESscr1h4A7XUd" - }, - { - "id": "9n3AtrNcLbjve1A29HTARcYKVdssWdnzY4Ny2xyFwzV1", - "baseMint": "Aojru8bfwZK6sgrx6exNazxASFZUjPpRY59byMrs6izt", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3TSkt3mqKCJLXkUJaQngkp2GEFBjrJ8yc3UAdhEPQVou", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "G4Fh37zGbCL9qPLWDcXXKqAuhQvB2v9fcCdab6CLfZAo", - "targetOrders": "D8DqzKd4QobPbwPGaiT6Stei4p4pM7xu3wFVpiDAYYqf", - "baseVault": "BMrDfXLTQAkNVqfdEr53kjhUmU5evfXxaUcKKF4AH1iq", - "quoteVault": "B3eGAeGRKRacLsTUy7tRgd2CeSx1icR3bBFyb7XaDTXb", - "withdrawQueue": "4ehgFby6vCYbPaboBoxn65LpLWxkTcxrarvBNFpY9b5i", - "lpVault": "fsYRUnpwywrhT1cePxvc8F2DKoDYDc8eehwrTrBGpgt", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BRBWfj1JGNBngCbgcrUbRsGSwa4VsvY73FJGHiyssgbo", - "marketAuthority": "6zKj6u3vZC7HSvXFo9K62DVtyMGSKqeB4KEnMiAT7Tdw", - "marketBaseVault": "2ZSJaimGM5auWhzg37ziPecG5DNMvHEYvjWBWufCd3Mv", - "marketQuoteVault": "CjgrKe6AGBuc653Nef9NNyG76adcrLRUmH2Rs3Q3hHzZ", - "marketBids": "5zsHerezC4x4PNLXYHik4saV3qoDixvtcuocq9QM3zB6", - "marketAsks": "3USwkhYrm5DBLDmBptN3K2pa1hqZVW2Cnx1ihqwjYTcN", - "marketEventQueue": "4LUTnwBNwsnn6TM5sckpruEpcMnUxckDMS36mjKXhpFe" - }, - { - "id": "9nTLTbc2AwQPYpoPPt5yxBeHsVH61xb1kVNSAYfry1BU", - "baseMint": "6Dujewcxn1qCd6rcj448SXQL9YYqTcqZCNQdCn3xJAKS", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HkdDd3n4bYd6xmHxJsmN84onjEzC72ZZM4wnFkwXwMgw", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GTwNzRKXKwPWqkbCXWEXfcjTcEXW7wB1bbqC7wHf24wj", - "targetOrders": "5c3WfdgLyRM3bd82kN2kSV5vXgtQsAs8HQ2mgpNfK2hf", - "baseVault": "9P7HcLyPVZqVashYrWsS6XPGjdQGrqqZXc3YutJTRitR", - "quoteVault": "F76DDHLMRpsMxVV7pkB7RCYr3egLgB2F58KYxXqMXcEp", - "withdrawQueue": "8dpMNLPWdgFvqrVuYdmUi5pS7PH7vof8kNZaNSjX6dSw", - "lpVault": "DEo73xQBjtLzuNE2ow9GyZKLy3AZ7iJDZn1SBAPjNSCn", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4wqFtfechUSNW1nJ3WK5ogy478GTa66H99RrKnz45fa9", - "marketAuthority": "CjcFkubwDUfikWsKohqF2qkDgFCKiH6rTXfZ7neiK5BJ", - "marketBaseVault": "3QpuynDqRnyhGVtQcaYDyLxXV2X8qEm3t4vNES8DwyMR", - "marketQuoteVault": "DCBBzkKmZFAkHgSAvC9vnmSNy4trBAXnPKDqUjXCm4pN", - "marketBids": "Bvae1fJRU5UdpDvk41AjMhRVfEn6Gk5dzZw924oTu87w", - "marketAsks": "4wq7Yj3TT7jWSw9xtvzcvnD1cHzegZzertJuDcDXVZTo", - "marketEventQueue": "82d2mPAXZ8i8kvdewPsdnMbFqe8hyaPu6Wn3jTSmC26M" - }, - { - "id": "9o1P7zTQcNuky1brYo25TdkoMXcSswTPbKf8BQqngfA3", - "baseMint": "9ihuaebHjvKwpWHXcnQoYjvxA4qHX1fy2SuYyCZ7Rokh", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "7TwQ3RqAnKwAgeViVVqUUsExY4aAPmK1ZXVhR2zjSfgM", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HvHGVg39bmKbmRhjo64fnmkNutpbvwfhaZfgVZYGKrFj", - "targetOrders": "AF8wGviu1VirJgoQ5t1cXvcZX53Xnv4xDZVHcDza9o8Y", - "baseVault": "CPkCmkhTCa9Yo1oPffsPhoWScrTAkf4ve1H8jMcbdZtd", - "quoteVault": "2StzN3mNEyQDQ1As5V8MYzMsM9c4FoMNcqmd78Mg6DB6", - "withdrawQueue": "CJ75oR8e3EiW5nR8QpXg5cQD2mRg3gaCnq7G1PiMFS1b", - "lpVault": "7Se4UmvvKWMxK4zvoDSVqhtGmxyDTgGBGygy6QLQbnkN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8JFWBA26sgj7861JFFi3bT2TPNbLukomrbtxm3c7gNjw", - "marketAuthority": "FmdAQdiREFJC74tJy73ypTE5CKHgK1nLKD24JdgWm54b", - "marketBaseVault": "Bf3jsJkpuXZ2cePaGvddmZkyYpV54ybPLcqoYtzu6dCK", - "marketQuoteVault": "2qqDR55opMzrz7Qu24sam21UafLprPq2eC8UCN2NbV7y", - "marketBids": "DBPKvEYbZDykdy3R5LamZki7tGzCpkg83qBFPyaVcUJM", - "marketAsks": "BPtGJzLUPHJhTYoGtkFnXX7JcC628FwxRP4Kf4DLtTzs", - "marketEventQueue": "9rCVKgpfNLr4aGU8j1M5pz9EonsuQSbCSSLeGsTrGwf6" - }, - { - "id": "9o21TY45VL8Un8DSTBZ4nR8LNDnDivwzy7M9Afz7V5B7", - "baseMint": "Y71XaLmJPvuPY4h4LnTZfFgSR6vP3qCxGLpCx25JTMA", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "C33kJFbG8YL9R3KBgbhvsnj7zzM61aLMEGEwB77LNiRi", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CR6e6agYBnBgzRjdCALGfeeP7rwbMzwEXjsKkAF4HNjp", - "targetOrders": "BzSkESEWuM2wuTCWPpA71XyFUniYpK698Q73Jyc9AvKz", - "baseVault": "Gw7bgg58b1KVdq5kyC4ws96HomFAYju2989DC87TatK9", - "quoteVault": "63soHYYVTEHbJnkucoe8mS652HcTRdWRrZbSVPRP3B3e", - "withdrawQueue": "BkM84gDs1ZPmBPqGwuXcrpkDdZikCgs7QuKUA5nsXKmB", - "lpVault": "8mTtTqQ6DRDs8t63hEV5gsjeYhgKqvMGRDwhDjqkwMQA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "LijCQQsGBu2V1CUodtcWapubqt3mto4Da4HNYVvYCYK", - "marketAuthority": "De11K2H9mQbAwGzbu1joKmX3aR6TvqiSephqcNygHEs5", - "marketBaseVault": "3bjVhcW2KjKjT9nT2zhtfxg9X51KHW3HH53SqzTHqrUe", - "marketQuoteVault": "8KUSxnzuJCoBzorMSLtrke9UNdhSCEPymfggiRQkvr7u", - "marketBids": "7fECaY3W8x2NGRBfEgJg9omTotGM5bQdyTktnx86xT4M", - "marketAsks": "FjwbY9BtJdXtCUsfJ2hw7739PswSJhXeA9XpPedsSEMk", - "marketEventQueue": "Dj5Evv71UvDxz9VpEfjMYG9Z4znsHiTjQec1wUmgumd3" - }, - { - "id": "9oYYgms43ysTKhuYP13GT6PEsugQGWWEKkb5vsoVbB91", - "baseMint": "8M7tQV4xXKnLyWCDTEV9Tu1zPvazsRxyAxrBxKh1meQd", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "Gvar6e918PM7YNfMhHbEBdAmJEgCVk4zSV2oaZwH9HoH", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GPzb6bpVwqb2DT6p6KUzt72eEvbZywEaT3jbZMZ4jyUA", - "targetOrders": "3r82SoA8QVAuekg36VCgL8opv7Ta9dKAY97tZRQ5wvsX", - "baseVault": "85AYYwv3Y9eH63N83zBXzPX9sGPcZn2Hu7LGsNadWZbG", - "quoteVault": "CkWCMeQ6aJSC3zkQWPawcxo1xvcPHNiW9spAsqt5HwKX", - "withdrawQueue": "DQjZ3aL5krzWPiMQvEoQhEeCZopvsASwBpZAs6brnYXQ", - "lpVault": "GEJxp9nR8cFhZf2ZKwreY8EN9mVDKgroxzxHX9wCz1jX", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3JWv7phZpzvLZF2av6sH5ZczmC1vuKSdnvSNXcAfFTzY", - "marketAuthority": "F1xAKy3QoqVBm5GnQGaS8fYCCfPK6dCiSH8ufvQXjynz", - "marketBaseVault": "D3JaTA5HGSY3GWsHfyGJSbXr2AtM8AgpU8ZmFBWfcE1M", - "marketQuoteVault": "9oQfkMZ96HKaKh9RMbUFLXuqzG7iaS3xmTym8XNkzYiY", - "marketBids": "7VR18fpe7JMKfj8memqyU65QUpVBUuvpG1jvCtTB1snZ", - "marketAsks": "DHnFSjvEJqV88AJ5VSRdN6o5YcwFQ9cTa1uLjGtdN2xh", - "marketEventQueue": "Fta3ZqZApfNyU7NheW3suqUWb8C3GBfXkBnPcEzFkdAA" - }, - { - "id": "9pJZpt3NEpbBhxiRxVRVF3YJRweFKB1NRjv9v9ZmhCdf", - "baseMint": "AThqqJBiMPUFQvV2f3mpc4RYdncEjkw1TX3bwqHuJrUn", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6oKsgnaFACcyMxDYGRA8TxEG3YeUyqFxvjcgwCTKZ2qV", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4a3UktDg8VuAy9SxwgJLAzFem79eFrKUdtZxAmTKwJYP", - "targetOrders": "25otfgdyLwRzJK8zsWUat7P6T3T9tJFdLX8uK2ZYXemv", - "baseVault": "FLHjj23Ppo4GdB2oBtXFFi8q7ZgXBPAGjnve4NTvrHNY", - "quoteVault": "CFWsaRNY6gyBbeY6wRexgQcLs8fYXY7taJjgwcro1H9M", - "withdrawQueue": "Dr8FaQx1pLMNC2kuMXfCyciGtSm4YuLQi1uQnvpcqDr", - "lpVault": "iuARJ1tsjtCgGC3WQuDL2X5uKN4PvtGeoo26q787JYA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BGcMVJzt78RpFjpw9E5T7BrFF9H88BVXw4Jf9npL2BER", - "marketAuthority": "Gp6UGykYkLkAj8CjF4mQEXPh1iJH89kYRx39kVySbtq8", - "marketBaseVault": "HPWEJRQoq9i3wzAoYZdNiujZL7n6Wk5RCnufS8gChSaT", - "marketQuoteVault": "9dfxHsMUMEU1a9AfX6H1EpAkrzmw4Z8w6LEPLLoWAGwg", - "marketBids": "8gCyM4b29mtp5sww5RtzqzNPk1gm4pUKphGf4574VE2Y", - "marketAsks": "3qpGeWTQwevDmsn8hhxbhgajUMrLSGRRNvLDMdm58MVj", - "marketEventQueue": "5rbMik2oG9QXvRqac3XNxy5wMJ1PeTvvMK2hPfRkPy72" - }, - { - "id": "9PVuwYtBZPfLqMVqHo2wx6U7WnEAeRKt6cda75Ydh53L", - "baseMint": "Dd7pji6EruuFPuAxuZG5LwZUdPSzYCTN6NsttrkHeedS", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "63YZjkygQ74VQmgMpB73DmWy7xwF5mZ1F3LwqCNCSy43", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4XSmHe228ezWCqvDBViP7CfV2pHp5b2J4tAWb4GNCp3w", - "targetOrders": "2WxpbH5BnMmybJLhuDdnRzHwWCJzLWrxF9Pruyiicpjh", - "baseVault": "95FBQcDDpYoajzv3zr26B3heBa73Uc2r6moQmCHTXwi6", - "quoteVault": "FAhZT8xsddo88t8e5ybNzKbiMij8Gb8kA86cZkFxYGc9", - "withdrawQueue": "BAgRbv8g8JQY5MyrfAEunhLnpdkF1SpMnLquhEFJHB82", - "lpVault": "Ct1LtDPqpi6VaVxGryotgXFtQZ7PMLqDAmhf6UU7Juoz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2Nu7fisRXCpe5HvSMJKpc277792Tun6jStruPQ8QxtvV", - "marketAuthority": "C4zDTTf4LiudL9hNfvyvAGwnWU5Jvspg4s5QkD7hQGvg", - "marketBaseVault": "6DwbFCNTJcaxYHMvCGNGvUBD8we5iQe84vouoaKY7F5F", - "marketQuoteVault": "FAbgAU1nPmRdom6odcAgTtJH7FgG6ivVxayeW1bEuddW", - "marketBids": "GzGsWNesE2NkBQdpK3NCnPVPwUxiUrFauiGQw4VziaX4", - "marketAsks": "5p87PjtAoynFiJZbtvc76XZKru1iNf4twigjjyskSxo9", - "marketEventQueue": "8RGpcJg9WsK1rbUT54RtTghHijbguzBSSC39q7u62SH8" - }, - { - "id": "9revsUtaD9ttP48KMmRx89G7HaHNt5UdM9KTF1D3pbui", - "baseMint": "wrBTCqVjkpqktbqN3CeGVSzQ9PFiPonHN98uwEpwMsy", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3d1oXrdZATm2vcZ44tUtBmWcAXPziWmZfxbsVt9smHkC", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4o9Fde3mfvkTyiZUUSMNn1bv9PZEsJEN2E8yZ2HSz7FQ", - "targetOrders": "63AjcV27Mt5jdsdA7QCRwgdpRRBHvjBL4YQpiVnfm3kh", - "baseVault": "ByNxUggAuvEq5rwbUWB1pBo4v8oVZC4nGFHLaMxrh8zM", - "quoteVault": "51jD1YhKMmQ33JSJw6NM1ssRim9sectdGzfCrZEZgcki", - "withdrawQueue": "EJFsGDnUXq8JboCZpwKqPyCx4oZdpaCF6Z7TyQ84SX6o", - "lpVault": "6MaYoCYqQ3TBkDCR897dG4dua3JbrcKs3QtqV6kzkh5P", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HwdKmPBUE1xigJKqyhLG92zWYkXFWR7T3eRHnxpVqvpQ", - "marketAuthority": "J1MwZtoV3cDdRHXPvyanP4bv5cqV7KpL85xmSzYFBd2f", - "marketBaseVault": "DFzAZXgDkAaNhoKCyU2sf3TBoKHiUkkBrEqih7SBKEUj", - "marketQuoteVault": "8dbAxqD9uGzwSUTLFDrDxsRU23SyS4ndyUvkrr8w5GHg", - "marketBids": "2QT177KkjEDgfjU5UYMswFyUynVLazYyENvMxATofidu", - "marketAsks": "9JiAnZWh6SzpQh5HjrcZx37eZAeKkv8mxJhfAxw5au4k", - "marketEventQueue": "DMnuFHnzPHgirBJGLu98VQzLo8Wegry57ZNoVtJASgag" - }, - { - "id": "9RFWpsQiKEAE9hEsQJ3cRWDnUcVzaQeo235GbiNVxZD6", - "baseMint": "2zjmVX4KDWtNWQyJhbNXgpMmsAoXwftB7sGV4qvV18xa", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "2hKggCsa3MBAQXSXBa3pZQnA2wEbcUq91orxVwM5Vxqt", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "C5Ro5qj7x4EQvgCiEHJcR6JL3uakR9nQpEmHSoKybaEa", - "targetOrders": "6FztE4MjgfpumBzADkqtG9yJmD7DhGLEm3o8Qq5nZp8U", - "baseVault": "7hLpaxyBwuzxXSg72VAh2T9ZNkRgGqTZH9JaFgTYkEw1", - "quoteVault": "JAMD2Ss5nb62ySwxc4z1xALQvCby8Pr8xpPMR24A62FY", - "withdrawQueue": "88pZMby2YzTvTzw7WCPrP6nmGQ1hAX4YKb5BkqicuFbQ", - "lpVault": "B75nBkJrFU3BeRud1nMXfCJqLo4kLpqmwwdbQQYVss8T", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FvGkruRLoSTs4B8rvnYmTdccEZGqS4wgz26i1GKLiaLs", - "marketAuthority": "FoRMTXL4sCVmq2iCGqqrSr5An5RKhD4SxnGdbn8d86Zm", - "marketBaseVault": "FzkRE14bUANoEZgDqSpDBZy1bkrztV3KqukHeJNrPVBQ", - "marketQuoteVault": "G9R2ofbiibC8SvPkK96kRqPvjc1e3CnipMREgzzo81Ry", - "marketBids": "4W3kT7NJaQ3uoSSCeTvwvUqqgtm4ZkKpHKxKCEiPMLPS", - "marketAsks": "65GJHrop7gmn6ADMyQbckG3hw9xGWvEXmppap1fusxbg", - "marketEventQueue": "5t4uZpdHEt3K23QVfmYU9u9ou6DioyyoCrkEMnNrRCRW" - }, - { - "id": "9Ro5b9F11LJrZyMGo6nHcnRLQHbcYVPVvsAq6JMrwJrw", - "baseMint": "GUohe4DJUA5FKPWo3joiPgsB7yzer7LpDmt1Vhzy3Zht", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "EbyXYpuejpCuwGJF4iEcyNF4NYvGchVLfpN5MjfnTUsE", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FawkatYW63e6UUXv1joSBJuwdZBAd13gR1pp6vVPG1NL", - "targetOrders": "DhQH9oHHPAodCH6wcoZX86LUhmWxpAxXqi8VL6CM7SRV", - "baseVault": "8sMf8D5P7BwpAX1AnnVD65fPEAxFGxA4qxsKdAHymz5Q", - "quoteVault": "J6rPUrVcxwifNhYVssaj6Gdnijkr6wEx9HN7W7nD7faQ", - "withdrawQueue": "CNArsUSBKraEZR84GiGZkYMcKbLqCntqhtNfNTATeRvU", - "lpVault": "a8KPme7iU5CJUWkyMS1pKpgu8j8dkwxxZqkHxuRWTzy", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HEGnaVL5i48ubPBqWAhodnZo8VsSLzEM3Gfc451DnFj9", - "marketAuthority": "6YZN632PJrD89NVNd1VqnExg5Bvhc94KVBtKRfXQR7UD", - "marketBaseVault": "DQBf6Svivev7aJZD3MXZxFuaLyFKnNjDsDZw5UCRKUdX", - "marketQuoteVault": "73mv3h7uWczrMxg6SRiJEpvvNWT1hWcLC2AMJq9oQguW", - "marketBids": "6yLQ4U3skgZY13zBgubWf2kArnqDuvaKW9rAeFjmbLGR", - "marketAsks": "BkEhSk6JdEsUQwvzdA9JAZvCDg2zG9o3z4sBfjkgvfyz", - "marketEventQueue": "3ioBuHJWYNLqeJ3oJxYnYAT62TddPcdHdUQJSeMNZmjk" - }, - { - "id": "9rZ8VX8bQqMngLdo5MLbnKGT5VY8EZKojyWPkzfEB45Q", - "baseMint": "8s9FCz99Wcr3dHpiauFRi6bLXzshXfcGTfgQE7UEopVx", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "9JfaXYQcyHfT1qLL9hjRRZY6w2gCoXEfyJwhwfgJ2sxH", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "332ybym86PkfF8rFDpBNKGp8LQqtzWdJv2fTNzHrJfHR", - "targetOrders": "76p8Fok6e24jreC8n5yvK53hfjvhjfNCtghsVfsUScam", - "baseVault": "FtDoxJum7BgoPSLN5xyqCWb4WxaXzy4ZqQivN4RzwPsa", - "quoteVault": "EABU4UkutrxrfW3AQGXByaPDHaJhYpKgnHnbUzC8YbR6", - "withdrawQueue": "53wSU3y9cZq4M45KhWE7KkqBGmM9ULBoGmanDFju1p4q", - "lpVault": "BjyNcifuZ2acURV7KtwbQigagCLdrngAab8X5gmprqRV", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "H4wdo8x9SuRuRNNBvr7PrrDTf9ncqASEUjDTN99SUqEo", - "marketAuthority": "FkkH5AFkxb8EoauodySruEu3Km2efxuaaoBdhApRwpDY", - "marketBaseVault": "AfwJ7s9or4fiuhHa4eMT1yn8nAareb18L8DCNJYQgAyW", - "marketQuoteVault": "7QPAQDT27rQsk3ToDBbfC6nGQ87NyAHgpccnFTujCuNc", - "marketBids": "41A8DRSx7Y7QiYpCQ4RuXvwbrrpwJGg1FBLLqqX5aEUw", - "marketAsks": "9GY2vwSL12mpwCMqR5iwG8QY1M1Q4ai9oxYdYJY8KcVk", - "marketEventQueue": "3UsX6duaiURzXUAk5taBm3Fct6WGfdn9rizV2dHWTR8D" - }, - { - "id": "9S22owbGCj8XZn29QMHWuBdzAQL9ApBuu7Kr2yNM4r2n", - "baseMint": "3uqEgKo5K2YJJi8H5e9SUWy46giMVfHfeFW8KsQcfRgT", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "H9SsHnhiiujEs2noWMUazrFdcFUUZc1pnwhaYovTojGk", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "521t1x59BGUtMFhDo1QtkRqBz1BSP87ZZxmgWoDnQiP5", - "targetOrders": "2wKHZPm2jjj5kdJopxTxK8Qn6LLi6cGEyW9BCBXiCeL4", - "baseVault": "8Qx1Qsy4eibFBFhDQoGrrcbqn22pdErWcjBPKMpyJfxT", - "quoteVault": "CcTBXU4zwVaMuiNMhA7nFA1dVUxYfmAK4JaR71rWAG5q", - "withdrawQueue": "1ApQjgNH9fKtyWkMU5nzB4U3zF6qpogc3rVa2PVRRGE", - "lpVault": "9zH9pfFzBXUur6wnozhFdVT43Hqz5Zf7Myhou3CYEXgc", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3UKstND1Kx4YvuxGAWb87cbT8RmM7no955Px1sycAffs", - "marketAuthority": "MifpCrc7XrLg7Q9KDuSYCPMioWHgXLLyqsGjjoxoWfu", - "marketBaseVault": "7ZZahCpmEzxx3dCq8bmaGYg9XKLGDvfHjSHXpMEmFbC2", - "marketQuoteVault": "CYmXgeYVbVLXAukNHeJzPZ3q2KNEGqzurQCbNzEqBTBi", - "marketBids": "9ZGC8pYrrcvcUNPJdWVKrds2DTLpUKGhUMnKQDmzBHyN", - "marketAsks": "HKGq8wzdw4gQPndGsTKJX2zswXBGVVrRTfoT4YRQFytv", - "marketEventQueue": "CJ77LvMh5bhp1VJg3HFHdtoBavputRS6haE4u5pQf6X9" - }, - { - "id": "9SYhnX2Gptj1fjzrKAYbadPgWkaTD9T4WiJNA3HSXWbb", - "baseMint": "TRENpVRAR9LiZgyYv9zWrQwYqSHa7ThCYdbpFCJixj1", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EPXu4ZmjaXQj8UsMAqNCsRyAGu6pDkWT5xmUowjTCq3B", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HwbGjmk7TpZxRNzb2LWavEX1ummQ47V9Xj2kJHf5X1vf", - "targetOrders": "E3GPLGM3yJDdnzsnq7ZXRvFTvdBreVM25yZfDyXatdeS", - "baseVault": "A1qRowRGua7Wrx5puvZptyLRg5rf3SiSRfuBoYBEjtWc", - "quoteVault": "CUAPqHa3MxA8kdku74RSgvqMonJSEpEEPjQUMvMcax6w", - "withdrawQueue": "BJnjThAQ5FRDZ6vMLwTwhWdyv3eA6V9KXMcc3u4NJbt9", - "lpVault": "6JbyzrjiLRvEC4ME7ZqHQgqT2VFjE7wdvuo3aW4sE3nP", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5Z6AYA1bV8pXxkj539HyE8BUmytq8iAu1dPhFA6XLjsV", - "marketAuthority": "14oA32iyiWEm79JxAnBMWEJHzUtAcZyZrvvEC7uthrK", - "marketBaseVault": "E9pSeXhocpUxubLC5wtEkDYYbsoRhkV1mHhA7wBbzFfo", - "marketQuoteVault": "2NjCsc25YaA1VCJwZwtqiv2eTBG1TugBPVTL8T8aCAxh", - "marketBids": "2iNTHTtEUrRQ12n5dt4L6u1FARNTVDnrZEJudXH7XgZk", - "marketAsks": "H6MHsWZs3bSxdvMa5eunQmZJ76G1DsVPFpwmp1qSy6t1", - "marketEventQueue": "EfeixLGhnLvdWPMm43StyhGRdKsjwecuwNmw162vyX9w" - }, - { - "id": "9ThFRqbzmZnEQfMcD56iim65V22yn7hRezwdF8TRJbJ1", - "baseMint": "FY6XDSCubMhpkU9FAsUjB7jmN8YHYZGezHTWo9RHBSyX", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "twpZyme3eughFFJUpb3ySYrYcChkZzgtb2nwb4u5Z6o", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9eCAoz8bFWHHERzKXvY4u8gAJfppq4VkiBPKp5dMZMFx", - "targetOrders": "6vW8yTFDTSLqmezt8KBeQFP2YznKJEyi31DNkJkfpMQJ", - "baseVault": "EsjA3i9c46w3mWKbS6MWpyUQNLXZsbgBgn6N2KQDecEm", - "quoteVault": "G7JQkrLCtvzF8ZufWugYU2oUXotAdp9fhiSFhLT2FcXw", - "withdrawQueue": "H6mPibLNLnhsyVqnmoG1eQ7FeWBLZYimUooVK9w6EgRu", - "lpVault": "ByVPWQJJjrmY6fxYfmuSowBkTXWi7oQEjfNBSCourJ2n", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "56ZFVzqMqtDmyry9bK7vi1szUV2nuQ4kT6CzFAB649wE", - "marketAuthority": "32sCyy17qYBExCa7erGVWE61PAsGwrqWpkNWAdU3TUAp", - "marketBaseVault": "63En3KJkh4DjrGCYCwmhVznGksRNBb55nuQLjsUYwKJh", - "marketQuoteVault": "9xkHoGYqHwsbq2M4oY6abb6H2BpPKEu4X6xVTn6pumXM", - "marketBids": "5ZsLbDGBYAy8xStnb63dx8iFQ7byEB8Mi76XWps2hmDh", - "marketAsks": "CeuakMy6H9MeacfCu8NbupKXQoSdb4vVvSTJ2uY3VWqH", - "marketEventQueue": "43WuYrcQRNyC28FgsFnbv8LDwFfQoqBYXSX6gQ4SXiTW" - }, - { - "id": "9TQu8wDs5gduUujy9abBRpC58bZSJgeGp7SsmXcofZt3", - "baseMint": "GUAXo4yYqY335t9esybM4wDPcDeAc7m2mW2xQ2svXzy1", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "E52oCQJx1TKH2AZMaw7CY6VzmTPaSTU5YXqfA8KMTEvj", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Cp75cbFPPUtCZh9fqSmMhrrjD9SWetw34vqy9h8X1xED", - "targetOrders": "3WVBSbJCAi1VnJqB7rD6QYWRgFGBVP8fzNoNbHtn1XG1", - "baseVault": "E5STGUQso72TKv2QcBuQ2y9znkUgWD1RRY3JJe6hmjCr", - "quoteVault": "31Nqvvu2hkupy17Py7ySR5GunWndR6Xpzckz4uGeG1Pd", - "withdrawQueue": "AfGF25eBPwHyx5Ytw8fc1ZdzRgNW86FaqMFidQmNKnyQ", - "lpVault": "J7WJFnxQciZJdSDsK2hDEa4JiptAtJdV9V9veZ5zYRwj", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "B3jPzfgedvmHn7MNmEUF3YhqQanXEModBAHuuLvS9sca", - "marketAuthority": "Hwb861JB2pmH1Y5QrvaxRqeQodZA9FBWZfs5EG2hD79g", - "marketBaseVault": "8xCum2NH381achQXcyhY4kZXRTNWxHoWmWXQo84SNQ2Y", - "marketQuoteVault": "BR3AZ9u7GGLBB1monfAAkGH4PTYXxaywdt5ABohEkd6f", - "marketBids": "AHtjYVQhnkqXa44QatEvJZu4QfvvPoHub5r7JBTxCu93", - "marketAsks": "284Yz38qLW6Hv4hzViYa3ZX6gMXLEMzmcn3pkq8GojLz", - "marketEventQueue": "A4S8zGgEU3Rc6JvQzvCjT3Y2z4fisiD5YbURvQb27P8r" - }, - { - "id": "9uMMeydQeNn2uiPheD95SELmsB4mmBfzYxfqyQwkcgiL", - "baseMint": "5bXXagtus2mrt4UQZ3k2w3cEiV5Q3b65krDefResDAAa", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "obUDBEbRBDgUPyQij46Z5orBG5mnciDJphRysH5ZVhc", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ShZybaWSTAHabSPwRBLFyGymPpiRHUwF15Bm9B5rwky", - "targetOrders": "3iGqhorTTkGvp3qhSq2Xg6Zan1hPkuEJL73bhVghP7M7", - "baseVault": "3MqRtv7zGXN6d5v6QpZAUyrPoujKTMWRHaHSpXFu14TN", - "quoteVault": "3uyVKbSgD79gF9HUybFJrWqd32ExH2DCHpRDXATBDJBG", - "withdrawQueue": "4EHpfqQK9uzrK5e4fBfbqCC55mMoVT9pXBMX1AahmEbn", - "lpVault": "Feg36GkrbWWpduHwMh4S9nJ8yxpgopQitMXt6ngopjRc", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3QCUqzus8Y7PK4YSoeyDy21s2cPjhFyDRtCQ93LYd6hV", - "marketAuthority": "BsdrzjqnHzE18cr19dSUCQWo3e26avNad3vWRcQHGUfK", - "marketBaseVault": "5rxrGi24FrNbdkZRijQoSkamUCKdZyVVi6qxUuN3kDAB", - "marketQuoteVault": "Er6oNHAZpWE4RvW4qCTjnU6iMCaSieaRc6L4TPeHFhzx", - "marketBids": "7DwenhPDNbGZHFfFfdKsXSJcTyj2E3BUCuwqjuMuS2p5", - "marketAsks": "DhHkiTQTMQwez1XFUz7WVngrCqgWjMusMN9icNjg3fJs", - "marketEventQueue": "5apKeSUEn5W7RZbmxXVmyDYKZZoUp6N9amsBZTTqeEXE" - }, - { - "id": "9UNrhHcMXthxGGH6jtg3C7bt2duZVhbAH8KEwj8cAwce", - "baseMint": "SUNNYWgPQmFxe9wTZzNK7iPnJ3vYDrkgnxJRJm1s3ag", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GwPv3KsPYE7PJSTPKwStG9brj4qY5jXe9FSRgrFWN4Xm", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CymVJ1wGNDcCTdbDCTseZ6ph8EADkXPSaomQ28yJNigg", - "targetOrders": "FezbTajpXbMzpmXNn68FZkCKJ9NWWJfgBoiFdF4PG5ud", - "baseVault": "5Xj8NZAXF2hJw4ddwKstkbbviGQqRjbov7XoLyX7khAD", - "quoteVault": "6sqL1ueoFCQWFiL9b8EizRvFiHvaRyjJbFmQ5hP7uRhZ", - "withdrawQueue": "5DLpP6iQoUJF8zrHxTxPDXq6FdG4c6yNqq9YsCoQNJXG", - "lpVault": "HDJg6QMKhCEce61vnEiPBsDm6tyM7nNmyaXZTRkxoWWL", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "14jrDhSSCUrspShwvGmCcpYZ3tLZXBWjTboUAk7MaxTa", - "marketAuthority": "HNkitcX242Xxiaa15VqsPCxKPgxqutgY1L2TqwAHa4Qs", - "marketBaseVault": "93LJwwztjrVkc67EMo5qb4LdFV1s5dQUMnTh6e8e6JC2", - "marketQuoteVault": "7idFrzbAkcHN9wXf6BdGMZmvRdLxFqZ7ikahfYNTcyBq", - "marketBids": "4ecLNiz2uKH8vTLtNPzYnRBGJn2BuJFQESzUjRApvHxE", - "marketAsks": "82TTAee5UZFiQJyJhYY2pb6MihvLScmxr21UDsjdi3yM", - "marketEventQueue": "DjYVR3mph3d12nAZSXvBGgBdxTZWBzGNcKvzCH4ir6NZ" - }, - { - "id": "9uyKYSmtYnXdmM9rshx1XhRzoBgnQfsjzy7h9UmEWxWh", - "baseMint": "2cJgFtnqjaoiu9fKVX3fny4Z4pRzuaqfJ3PBTMk2D9ur", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9NFhF5zbiDDcAwWWbt1nXZQ7DrmdvrUTAp6YbAXnUgmw", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3kHWEmtUN4pW4eWTFR3ceBkbp9inB1r7J7Aow3yL8ZaE", - "targetOrders": "2Zu1iZ758bjzbnJwKCDXhZHS8ikA9WU8uBtT3JAxehRs", - "baseVault": "4cHjP4FhRMFD4AoaBEUmVZEycquWuAdEnMaXXX84zRLV", - "quoteVault": "Fs9ZJ5RsYD6e335Tnni4XZLSoDiavy4vk34RaZTgXNQj", - "withdrawQueue": "4cvjPuNhnLNHLsuVhSNvvvtDgdi6HWBXBSZTK8maWbsB", - "lpVault": "EGw8ayopjFkSdktSK3WeisravGRyMXXFct7E8t4nL8nq", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FcAadXjF1bYQxnjFDMN6igivSYeLbabXDKjx284pagBy", - "marketAuthority": "5GfULmxxPVDZeJuLZHyH7M9Hw55FfR6ch78YAZTqdDGZ", - "marketBaseVault": "68b6d2HNxpRPjbHAaDEwbaig3nYgw8JkaehBeajGpryq", - "marketQuoteVault": "88NMch1Uc4MGsKZQLypCNcSdgGMC5VFhTGGyU9iEP3c8", - "marketBids": "DybS9uBiEHKJjSZqVskzi4abm3c1FdSxaEzgHLxfdLx8", - "marketAsks": "4XLWbRUHKKhDff5S2HExXvUB9P9Dt5i1BA7FTaXmZpwu", - "marketEventQueue": "AkYcL5W9bU28VAhGGJAiZ2E1sdEUKmJLqdTFijjHKVDH" - }, - { - "id": "9vjjsFPvWjSmFZtKkW2eqm1Mt2vXthssM79YZrid5m7Y", - "baseMint": "2rLTJzSj6J6f4poPAKojS2sbdtRry7b8k4XoEMKPwner", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FSVbtcs6FZnEhpz1Dkv3f4BDiHiQCJqa9L8FjMNCw99V", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5ustmtcWG4GKtRdz4MTTyZwcL88Zm8gcZUH4uDdDM4eV", - "targetOrders": "8Ds7u7UwzYkBARNTmJuh7huWtcbjf5U6VHWQvAYZcPnt", - "baseVault": "G9xgpK4SaBWSmsf1y7iBTzeg4stbmMJXbVPqjq5G9boG", - "quoteVault": "9ifHvDoPCxJyqdj3uMGDxhZDgjr551P7pAhvmvWtyeoU", - "withdrawQueue": "FuLuiqxCm5dHLnCENibPH7NtvYE4Jtbhira2chZpRozz", - "lpVault": "DnApJXE1ijBuVaarhTuV7EfAomuVtKCg67XfPTzd6AJ3", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DKTd2EDd9Jq7nLiGrCqcScjDFm2P6hh2D88y4QRwkQ5k", - "marketAuthority": "CcnikKJW8doQRKPFrBKmuGiYh5kYE7Zq9zG8NLYRxgiC", - "marketBaseVault": "GGi3oCczHpYaFE4WpDcbcYH4YQ3DNziecasaVWWZF7f1", - "marketQuoteVault": "GFu4gzRyuE8bCCkvUPeZytZ7tSDQHg8QnMWhskZhZ4oP", - "marketBids": "5g1Fjswa9xyqkpaDipJboUxQDNqUUC7wqKYRoJ8jBSef", - "marketAsks": "EdQHuvm2f8yW51EEFjPcMTiWAM5CHX4UZBegZbxD9FqT", - "marketEventQueue": "GiJj9f1ugA6HB3r15qb9AMEKPpbv6MeuZDwVtYALRQND" - }, - { - "id": "9vphGeFxYUctPh8kN7Kk86CStT6gPdAdSqbeoTYA3nrh", - "baseMint": "FRsyPFrp657gKPPTDNP8ZPGAPXfRJaCLkhfdPsGxJY7p", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "BKvMRzcAvMMDYomr4ieMkbrMt4uTTuXJzMPnTUURzYgc", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "64TXhBd2AsevQ8UPEgXLQ5aahpq5EMUQ4Lo3K59w2Msp", - "targetOrders": "HaWbm7hHxEa465HmyDU6RnqrvUTynjX2uexj6uhMTuuH", - "baseVault": "G6EAxZFYZ3v8o1kz4jrsxFhFt325VsrEAsPd4UiGpKCU", - "quoteVault": "3vq1PZ1XNdFNohwKXbPPoB4C8nMfSwbEg41XmJ9qXR71", - "withdrawQueue": "2mu9YHX7DzZZfT9u2Kxdua7Kaw6g3tpfZyRMqzjEg6hh", - "lpVault": "2qdZd3mCUWvjFGbfUFwp4VyRpjDL3RQLvKHwKeVspd3H", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FeixgCZfb7t8DG56Qm6VFRq8Dz6n6uEbcaMtUCgxVARJ", - "marketAuthority": "EBi6bXBTNf7rHJ3i9tRg9a3NY27KrF8gyFMNTb2HSpBY", - "marketBaseVault": "5reDgNFA2FyUVwz6dnDPjNgJmQsPmkzr4HcUVoYYrxKF", - "marketQuoteVault": "9zKL4DWUFD1kuhZsfHXp1J43NTMu5ckcXg4QQvKBxUGC", - "marketBids": "Fi5QacGrUnP5ZPfAn4qv1KEJhxqq6NGipHv4Gis3ht8N", - "marketAsks": "AWuD8ARaCRr6aUcRs3MkJzKZMY4boA3Kgq6xiQLCbQ93", - "marketEventQueue": "6YCJ45AbpYVK2h9iB1bDXGpv1AmG5kL6kqX7xwRZE42z" - }, - { - "id": "9W1cM6X35gGj4Mb2T1pFX88481HttSp3XJVWY2wTKiRw", - "baseMint": "FoRGERiW7odcCBGU1bztZi16osPBHjxharvDathL5eds", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GvZUtymRoCUSQYW4PpRzXijoMjpjae94TcCLpSw5GkgP", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "r1kerzKqXfsoAohJLSJGH7zbr7BRMTR8BPPaeycdXfQ", - "targetOrders": "ByKGSPfyJLofhG9x1DwyFXxt7nv8MFecMzPX9b4CAtW9", - "baseVault": "HPaS6aMrmn7Y8VaMLjf8qyx3o8nA3WpExmbYMdL8YdbV", - "quoteVault": "3LHxgitKrEQcWBkCF1sEfdwb89NgwBDUCnNDeGDmVPT1", - "withdrawQueue": "CNQ4jrwffEgsyqYV6xbqCSkoHPFpaHk5QL31Zbc6dsbL", - "lpVault": "BYyAzm4mBiuj5ZaBV1p1neoW8iiGYYpPWJkLBttxF6vr", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2ReqwRRdKoXszAMhrWatSf648SV7gtoYw79yY2bz7pw4", - "marketAuthority": "CwUuWTyekcV7rf83kD3bPubP4QHBK9YjFdJ17Pfcijoz", - "marketBaseVault": "BVuZuXvjTN1i4Uj7aqUAdJAGQj8gWseqopp9wE9FwEww", - "marketQuoteVault": "14mLv756VJYhowjewoyGfyYaPa2sB1sgMBKYrRcQb92L", - "marketBids": "HbegH3KFDK9VowMMH1KzEJHCyxZ9SBpt8x4hX9Nrg2FQ", - "marketAsks": "8944oVLzpHLgtbDuw47SM2DNAWDSZMsJ4scGXbURFKsY", - "marketEventQueue": "2e7HZGyHczyU6ydi4AdSXPQ5mVdHKk2mo7dyo3CASBY4" - }, - { - "id": "9w7CqRD491maRWGoEdWTEyn86nmUhfzYxuLdD7xidkcS", - "baseMint": "7puG5H5Mc6QpvaXjAVLr6GnL5hhUMnpLcUm8G3mEsgHQ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "G45ASjWvWiWy6HcczTDhxe2JcSTNVr3hEdrKVo5X6PPU", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Hu6y3hgYrSKaZbV81o2xEMdQGaoLWsfZkP7zHkDam9uD", - "targetOrders": "9nWqcznDm8X45CwFozhM3t1Vmg1mCru1TVtCMf59XYuJ", - "baseVault": "JBSk4Gb2yUg763X88XfiKiXKuEwgSgGpDyoR9oYftwEi", - "quoteVault": "Fmwt7CQNzMNfwYQKTvtYnGZ5M5ub1qjzyhamwRoXQWcD", - "withdrawQueue": "6aw5JwUkM2Mk2UUssKJ4z5QxxBGTPQHvYoUKxjMjC6aD", - "lpVault": "7kuSWSN731eTKgrQUKPq8SpFLarfhXYfufZEsko2HSEz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DTEmm1nC7n8vb3KmVabT6dEEnSNeDXNu1jWN4u2DfD7Z", - "marketAuthority": "ESW99LXoJmVxrLicgScryUh42NoA7QQyaEiS4u8bieyV", - "marketBaseVault": "6cfYDzyFTswjE1P1oyGQ3xuLraBJCmeLJoe2KbNMpEwZ", - "marketQuoteVault": "5SZM6Yei6hRbmWDqoT654LHW3soA4nFfN8ybVy4xRYss", - "marketBids": "F3AfRyyA4XhCSq9eT2bQ5xocDPzLfeu5769Uz8x31Q6P", - "marketAsks": "2XMkqo85qzx79co9E1cfuhQKqpuofaq2Dg6U62YnD8d6", - "marketEventQueue": "DMw7b8r2pchHuLuSwEdxKGj47Hd8zobZQEr1CHuopk6w" - }, - { - "id": "9w7GTH7xZHVkWbctDsQMdaJihtUfqAWk8DSgMRT7XngL", - "baseMint": "GfJ3Vq2eSTYf1hJP6kKLE9RT6u7jF9gNszJhZwo5VPZp", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "44DMeeAB744gs9fjAWE7ZL85pP6ai3QVvNzy8DGRfCX7", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DXsyJSAe58jop27ooMSxCwd69DbPYW4wWBKy8hqCCRzX", - "targetOrders": "6rGKwNeLTQ26avefXccvZ3XKuSnbAhhoYAgiCieMhfk9", - "baseVault": "85y3YduiResZeBfA2JoEEYQDEVdau8GbQJw5FPZ4rhMe", - "quoteVault": "As3EZMGSLxu9EEkXRDxJWdenbAJouWRFUqFtNAUcCR94", - "withdrawQueue": "F4n32mRmymgxLdqUkZrJvpSMwRvuQKqXFF7PiRRTZ7id", - "lpVault": "BtzhA7fbLDhcLaaiuKa1W8ZGo4CQ4inWtUQWQtGAnoc8", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HV28iFM4U6fbyBKCUBGKJzBHqgepZXebmpUvGNHFZZ8f", - "marketAuthority": "4uMPMLDHKKGbh8won2H6v5cag4b74aYpoivE6VHyZSVC", - "marketBaseVault": "Hasdqpqj8kgaL89yZb3xRZfKgBACx6APkXszwEiN2vL7", - "marketQuoteVault": "DL1pvvQyjv6VKMRbbjFFWYPJFE3EPvww5eUcmNQ8Q1C7", - "marketBids": "DX7ywuRPLZynK4qebkMEdbntsSm37R6ofcPACyCbEjam", - "marketAsks": "9YDXE3dDNeYLP9DVjN334tLHugXXaKayMd1DoAfuQ6Jg", - "marketEventQueue": "3MAz2nivEdDXjmkmxVwS3Jy1Sjq3VydrVYq5vrnuc5La" - }, - { - "id": "9WeNWQeDAnpWwLfLtWP5sPTMqGNmPu4AkdqdPQ4NVNWt", - "baseMint": "3D754wNEh8eJxayA1zzgCUa61wSPddvtArcQbaVGDpc1", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "6XSXJgGYPKjJe1HaLKtpnWFTYUmxnXJCFAtfuXs5n8Pi", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6TSUZm4AwhDK1JZaYTgjypR2TqVxkHJP3SeNX2EFQfni", - "targetOrders": "9dSgcghDWw4TQRr5UXCbLvdrwHQ5Nsqojo9mnFADtCX1", - "baseVault": "2aQQ8GuwwBuHLHgtTDivHwQSiyuDM115k7GeyzS8BSuZ", - "quoteVault": "7y6yAr6Vx2TepMKZt8fPJostsXT3mKatzbGz4N6eDN6D", - "withdrawQueue": "DRuPzaYGAAh5sXx41jPRLgHnE4DxWp1WnE8KjrqXYRma", - "lpVault": "Fn1fQjUVJcyELk542838N3Bztg1VGKaCxyPgRUehAmNS", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2mS1tRCvhFdLaGwfEpptuCQfufYztMR8CWNzbPdLuTSg", - "marketAuthority": "Am8EtSeWGBRWs5tqMy8HYSN9L3DtAbNMcRc2AQd3X24c", - "marketBaseVault": "FDntgWpZ2iW4U5CVffBxtygcce5E2vvWXCHaTAefZowj", - "marketQuoteVault": "7F473NmaPBAYP9m4E7Cn57cPnuv1y7eppMCdMxwfUS3W", - "marketBids": "7BYoSLVn9t4v4wXRdAtVimJRwWUSj27qCErpu2hi64GV", - "marketAsks": "ENRDtrGtrLrT9SiNsnYfRe8mXxj74hNe6Tsot5tSDjZH", - "marketEventQueue": "7v4p1RUzypF9QXwBPjMphXNY4eo39Lzg2ixtSEHKxNMS" - }, - { - "id": "9wF3YgaVaciWcchsVFPxte8PgVZvb8q3R1va5iipcrjs", - "baseMint": "CRSzWoeyfR8sJxB2d6LLEre92Uc59TCPX2gZidp4t3eE", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "5bifb1SKoHb1xyyAsD18ydwDL5gdbHDfCsqTCXQx7V3", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2vqrNb327yvfekyenJWkS1pUJANJAkf6w8BJEHmvUcdB", - "targetOrders": "DgK4YsiF7Fu1EaKo6trD5wi2xhw766jD1rVgDnYZYGrH", - "baseVault": "AhkhubQerD91UyvSQQst6S4a756kLoNVAU8zp8r2Lbyk", - "quoteVault": "8pRPov1uCmB1rGmGy8BPHr8kUHNz2Gh7FBKmGnbT73n7", - "withdrawQueue": "5w1SpBsfcXBAikf888EQsstQG7kF5J4TbaEGJAeBCcs7", - "lpVault": "DH9Fbb7ohjXNdeAgraKcEGw7BR1P3swTXGAbDFwfMALF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AmXREFKb2N9DNW7pCvVeuh7EQPrfx4j6c1r3m9auo9Tr", - "marketAuthority": "8RavtfvvbDUPBeLFZEdDrnxsTsfWLTstzPXD9swwEKUR", - "marketBaseVault": "5sc6CMSAUxcVhGBqYMKARpAiKxPAjpUVLqix8TaVupT5", - "marketQuoteVault": "4zWiAFecjNLD5yfjXomV1keSnkx9CsQoMHyLk4a2fte6", - "marketBids": "9HK8T2H8whJ2yGe1vK3pYDxrjT8YGxNRqsN9JZoxHXJ", - "marketAsks": "B5xhBEkwcKQCogQAgFd49jBM3VNH89KfTi58E9MD3rFc", - "marketEventQueue": "Gt7QTitgtwo6P3g8KVuS8wzNokkkfhxRhSRjhdvHQow2" - }, - { - "id": "9wPmfhGLFZCnGZvgLhTBEDSeqniAmHH3VDPwcekVZtGC", - "baseMint": "CRRPG57uFaG4Rbfauski7PuSRLQDMsoABtF3UTyhFraT", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9Lgpn5rwxyMzckCZQrwgevpjsMzi2r8j24SGoPPnAkzz", - "baseDecimals": 3, - "quoteDecimals": 6, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9RfCDk2ByzzFexBb3JorTy7fuYqSZ56vV89NBQZVqvUT", - "targetOrders": "G5fXVabqcsPX14HvCbTfoTwgfPcaDSvygChRCyFiPHkn", - "baseVault": "G3byRXABbjx9bmCfgqa4vfieVQuVhqi43UJBUV1KxiVg", - "quoteVault": "GtjSzsicrxXhSS35os2GLuymsubpgpXKFScvXfHnBBwJ", - "withdrawQueue": "HczTRydUxorQqBXVfWdRVT62nAV7jqHk4DasuazbjDhr", - "lpVault": "65nzudusQvxFSHTnpS81WxNubyFWkTemBq2RzToqJgdm", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AbT3CpcJu5V3aRLVu1urDKFtfHShHH6Rxg8RXdZnmfLi", - "marketAuthority": "7XT33xyPwF31FBkkQmrrR6GVH1E5unjm9foZLt6eVDXe", - "marketBaseVault": "7AoS6A879KpjPmVP4vMsoQFVzhq6b6dTwj5HxKGKh1u8", - "marketQuoteVault": "Gw9MkjXvhyg7DWLBziVgUDVuNjGCGvkBa7ov3n8PNoky", - "marketBids": "2XQ7TRgT4f9R9JyxBE931HFprSF6Adzg6d7AusxV4rXr", - "marketAsks": "6ANpqbZ1e1upHftrntJkLPf31gfYWKM3KFvFkMFmuA71", - "marketEventQueue": "GX6xn2M1ZjwnqV6gK9yTv3oXeFLQ1PqEkjzMwRpqBsep" - }, - { - "id": "9wWX2ENtFvnwem1aKdpr7BqAoMoTUt9hm2QaEW3L8Q64", - "baseMint": "4NPzwMK2gfgQ6rTv8x4EE1ZvKW6MYyYTSrAZCx7zxyaX", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BTszujAA5kJJT7YCWVsAXwk4eJeuycithuTeAksQC1RC", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9cUcE2Dn37pni9WQCMnjYii6DqrH7z9r8PxniLM2N5wg", - "targetOrders": "CPvZVtmycHziSsAizTMCBxYiYStNfav1Bc8SCfWdsh9f", - "baseVault": "Aj7An8E3ipkyipcHdveDNqAdTj2XWjeNuQB1mCR8AkkX", - "quoteVault": "EwomgX4beK2GYWouKGTf5HbAJ5myCVYcUBsnjJ5ahyMF", - "withdrawQueue": "A9CDasFD1MaaUsn4QgBtoeegCd5baDAAFQJJTWMUhoUH", - "lpVault": "1rXtF9px2zLgVPvnbcuqhAbnMbMwpocBpYhQBCjpF8m", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AVC5hkVjWqRzD9RXXwjcNiVAAR2rUvDGwhqoCd2TQNY8", - "marketAuthority": "6nqQKqf3tBUjJaB5y9kvBYvxZF6RDyAA8t41bivDkJec", - "marketBaseVault": "6LatREk4Qe4mFAiiq1Q3qTzurxKDL8M9ynto5PRRBPzM", - "marketQuoteVault": "86L3D7AeNXY6oVd9UqqavMDGfhtNy7j4MHBAXdAD6dN1", - "marketBids": "EaCN1RkY1vMpTyMYanwjpVcMQ3dtfc1xUfR6SsTziern", - "marketAsks": "EjRG7QxkNNruTjJ3QUyvCZcdTYBAfqq3Qd5XQw3MwgjY", - "marketEventQueue": "J3qjjqGdDeJLuvSMjidx6P33iVnnUw9qjfoCKAuHhhYV" - }, - { - "id": "9wXskbBN2Pd22xPwniYZNGojbXm3jq4j4WRXYW7YReFY", - "baseMint": "2Dm1zu8ERJGBs3NLXt8s8Vor3YHwJye5E2pYhLiMHU4L", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "8xJvaZ14tGecAuaVDPBvsTiEqHQHLaadnEVwdPBAzNgf", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7wXHgVRokNMFbvJyJr22FjdzEE3XcmTei4i3BVXEZ4MM", - "targetOrders": "7qJbcLB9UaWbMLHPKGuCRgawn6qj8ftbkCdLLHNZ3Cii", - "baseVault": "CSGebNiVWkoKuLDW7VjT363Z7bnfbFUi1ZGCguk52KbR", - "quoteVault": "3jPwv9mHcWXssGUVuwSX3uxuzLSMhXEgNkwuwGLvfXH8", - "withdrawQueue": "7CcbCMBFz3TaQnDzdawyUT2UtKbUAdz4GmWdgnDgZzxt", - "lpVault": "6DPCZFTuZL7Ejxobgze2no4AQaTveFEMiRUNTTrdKMU9", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "A5zJXeUTtG32n4q33cgwbUGzHqaQfMq6JSoT1um5nNYQ", - "marketAuthority": "2wQUGSe3sz613ibK3DRkMsFqY3ivi6R9XwBb4eqUs5mN", - "marketBaseVault": "EBj9idYg9vsrybGARXoe3hWxcGKxiTEhBCZnJcndeCbN", - "marketQuoteVault": "7zJoe2YSJafDm5JC18AMFYih43F7e4DqmZzvCNVZPPgs", - "marketBids": "6iDyGqXiWSgNb49ftMXhVD3GHzxnmJKmcNfBNnASr5Ri", - "marketAsks": "7Qd9JRxExFcf3g6P68TGpUJCAzwaxcCp3KwPnz7s35k4", - "marketEventQueue": "D6fisi7S8hKZo27iABGstnBur7DiArg4HWh3v8aE9buG" - }, - { - "id": "9X58YeSkKSSdLtegWx4ENR6kCzEy9A79QTUCMe4obNwG", - "baseMint": "3cCtnQcc81oUfjufBL6D1yXNqt99TPt8n4HinW9h58wP", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "AeC5mPft4UhMDpEvtkd29jicz9BMvVhYgXYwPkGsmUZq", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HbKjWj3V7tk5SAW9Mv7JGGZ7W7mK2DM3G4ePu8GNh7Xq", - "targetOrders": "5YQkJAjVmviapsFtyyd9YqjveHVDXbwhCfNQz3mKbRbX", - "baseVault": "3YrCD978ooEnekH4q8PzL4xjL7gn6Kngf9PSo66hUT7Q", - "quoteVault": "G7WJ6hyMcyJocv3vJeGHFUAgaRqPRSxeiWtoo6N5hj8a", - "withdrawQueue": "8HgnttXCVqjeySfGtEYSAbqT2zGDaSrZ6cE6xv6Y9w6U", - "lpVault": "89ev9tMvnxXJ8UAudjPAYJwBfErmajJuCqf525V6wg1f", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "qSUPh2yKgqfL9wLXkC6MthCRvVvbeLjBb5ihkwSpGX4", - "marketAuthority": "2j6smGkV2RCLEmsiptqcVC29U8MiQPmrnWLHDQ4uM4VS", - "marketBaseVault": "Dip3piETLKDSR9tWJWDagtT3W7dfkXwQtA8MCF4iHEpW", - "marketQuoteVault": "Eoj3g3SfC2gZQz169yF5xwEhQKhbHwLxFyvX3BUi62ko", - "marketBids": "GhFCtw4chPGzRLZbY7oGriN55aHBdCFtz1baFjWTXdd5", - "marketAsks": "2oYD7EWPw9rpK5TbEhaHnwBWVyQQs1jKwCpJnyj6noLi", - "marketEventQueue": "FCsXJ6oNbcnMfj7nLXwv4MegHD2HQxuWZv2f6PApHvBj" - }, - { - "id": "9xUWbM7zXsccied2jNXama1Z1Wh9mwn9APX1drRTPtvh", - "baseMint": "5p2zjqCd1WJzAVgcEnjhb9zWDU7b9XVhFhx4usiyN7jB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BQBiHASNhRD5C3mfbWBK7gRTrTwwGEE1Xn61Y6Nzi1bA", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "JD51bY2uLtwgzYQNYjF7m1UvWX5HdHE7orMrxogPQk1G", - "targetOrders": "4KdQjuoN5rkmauRCTH3wKjZn3EJ8bGqKimCc88TENedk", - "baseVault": "7TeWuw6WxwqLkadHGRsLFVWoe4zb9snMRZHH5nQPpUPV", - "quoteVault": "A59Pg8yemxDqUqfvfmh6e9Wmkr74v7uGeygcUkQCSoLJ", - "withdrawQueue": "BtY9v5AetLdVcB3agih4YzqNzCp84mAJ5GwWMASFDsHE", - "lpVault": "9b6edsB9vybkaQetViuJDTcPzcERxgYyRgQoB1H68X3g", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9fe1MWiKqUdwift3dEpxuRHWftG72rysCRHbxDy6i9xB", - "marketAuthority": "FPC75yXyJwF3NFEmgHrJRDNmXnukpVQgXayZVsmpEDKo", - "marketBaseVault": "26h5i4vYPinyUZ6kUp8tzhzvQtP3cNzhzaBMqySybNMF", - "marketQuoteVault": "7E5CzVnTFsTnwPqoJ8uUA8RNqCgsYy6ZEnRVmz7LURaA", - "marketBids": "4ZwKetX2m7fS3gigLa215xjveVNwLWAVJeh1zaQUbpuF", - "marketAsks": "vL2N5k5PS67MctE1Tj5u3sivBNMj6EvejskPiqtDP6n", - "marketEventQueue": "ApWLqV2xjdn2FEjYvVgf7Ltp5by9TDVEnpg5dXrZzY8k" - }, - { - "id": "9ymWfuDVWhouhqt6NQLAK3Uee4z5Xx9ZitgZico4UDnp", - "baseMint": "HQNPLVJMKZVs1BwPgn4qLe1zhZZ6QPbAUHtxkagwSfwW", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "vL6SmSNCULDm1xkGU4K954vsi8CknryoGh1mUA3eNcX", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DZTRXZhMfrXsCzs9eAd1pJaJ5fwjPUx3E9n8cbuHBxPQ", - "targetOrders": "DEtD1pvFSn7D3KNtGStpyQvcts2PMCzwS7n6EUZiPqxF", - "baseVault": "8j3LVRr4cHkArrNPjQE5fdwzqujRfvE7zR8ECAj3vpqy", - "quoteVault": "Fbk5VMhVDBcpLoR8tBn4f2hd7naCa6Ew8YToDUfvbiKk", - "withdrawQueue": "GWjZtQWs3PZzX6Vo1dWX5RMFBfn1JN6ye5tBmW6GDWXh", - "lpVault": "FPpJDqoDqARHnoSGuBuzMPSHeWjcuwNAhxvRqNs2jnHh", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4FmVhfPSrYEeU5L4yTYZ1Wj8FMmcy9UPfE8nN4SKYgD7", - "marketAuthority": "3hGJ37c4szba5HStzfDsEtADcLTxnsBK3MRdktzTXFJP", - "marketBaseVault": "5CYx5DzQuHikeMyrVvudDSSq4TpR9Q2dDobqPBw1rj3T", - "marketQuoteVault": "DZhwyL8nCVCV5gxZfmjnKNfiD7aRdxWKYsWwwPQsy3uY", - "marketBids": "MHrRpGRMeELcbqHP9wnsK6wWLR8QEyyyhC87pziYvNY", - "marketAsks": "6e3SdTmEy6obKrvGixJJmyDGbJM3tw6NraJq95b5RXgj", - "marketEventQueue": "3wyevEdZ34VWJWcotSZveizHktnqLCVDKW2kvnBh7P9z" - }, - { - "id": "9YTKj4BrbFn86MmHv56ALsM3xqjTQHUF3aRWZUiPZt4m", - "baseMint": "7xzovRepzLvXbbpVZLYKzEBhCNgStEv1xpDqf1rMFFKX", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FtQnV1EpVho2sJHCrb6DMmGwSWAkV44cA7pBD8RpTH7f", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BCFPeh4Naw4W5jZEhe6ujFbYwX2NuMFH8uTNBnTRAnWa", - "targetOrders": "EKKbq7GFEKxfx2Z2X7PE9JojXv7vVxTssCkGcCkKfGy9", - "baseVault": "6py41E6CZkkZRmgPsrmBZrSc2SztUKMQAYgWsRaiQDkw", - "quoteVault": "EMdw9soDoT42TGngcZDpdVasaMYzct2nSfTRGzTG5k7g", - "withdrawQueue": "F6TsYRG12RJ7vJYTeR3pkR1Cm5eotQdEsh21JjpM9Yuc", - "lpVault": "9ofasg9hSEFoeqsoAFdkFBGD8dFJzjSwdBoTNBpecqhe", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Ep5kFPdPFvBqxp7Hp9C8WhMJPPidcC1FXXiKAgCfK6vy", - "marketAuthority": "F9iSvxi5eTUbbzNXFetn8PReV2eGZLiVypSy8SN9wg62", - "marketBaseVault": "DMeNMsRi7YSmXZA1quP41Pjii3t9ged62ZbJQ243sWFQ", - "marketQuoteVault": "5UhhsD2Qt7PcvQ7s7NfpNxMz9GdgZc2K4Zcnw6jRLV81", - "marketBids": "eZA7zHCBnJhoRoRKAtAvN7EcABVpqgozi98Uppt4m6S", - "marketAsks": "CzC857dGyfEeeSwvDr7958Z6WkXvatndAqLJnZgmBun1", - "marketEventQueue": "GYpTerUicmPPd56Wu6MJDUwnYW2EaFjg4M1A4d3aQN1z" - }, - { - "id": "9Ztrxm4qhvbhgM2UC2B2MRKiuK2VuDUj1L6CFUjERsZS", - "baseMint": "DMCUFm2ZAnSU7UgsdVq23gRogMU3MEBjPgQF1gK53rEn", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6UjtYnDGbQ2Y2e4M8VJUeC6kXy6hdGRecMzAbjVJDAiZ", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2U1QWxVSF5RDHZBVFjGrUiGEroX264fEGsGjAypwNQgz", - "targetOrders": "DcTyJawNbveXq5X7e4a6E1QA8EbvPJxJfgt1RuBVnW5o", - "baseVault": "4iqqKanYRrVL5o9rdtM3XfmeM3NstGwvqvhi5NR3sTXu", - "quoteVault": "CcAyRf7TfU4jafyXYhwYdx4a2vbLHM1QYpLvPRrtqsGh", - "withdrawQueue": "GNiitJ9yhXr6vaHA4iFFaUGoT6oFRwYYPbgjajxoC2SH", - "lpVault": "7Q9sPTzvpU9GzHAjo7VMA2BRWo8Bs69ySBuynqmcdAay", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EtJWusSKDfxBfrQWJg6AXtqTE1NjadbjEcSNmar57ezX", - "marketAuthority": "89Fhx2186Wgu5HJvvE4dELfaYPvXETbJBXU2Jy5SnstR", - "marketBaseVault": "79jysJQLDivvNExNqdGYJdDJpTuZr7twdy1KR5Y8UDVc", - "marketQuoteVault": "5U1UdVU8et8NCZHtD3YDP3mfGSBryj3zXmkN3HGEJe7M", - "marketBids": "Du5KvubwKQr9nkB51b9e5N4TDXQ659cidd5Uitkkf7gA", - "marketAsks": "28xUKnqNWxyqCSPTgjmZRhmvuUDACL5T1agyyR57RYc6", - "marketEventQueue": "BHKb6HSpAmfxGnXh3eJ684Jc9WtNicjzAcBPGU9B7Qix" - }, - { - "id": "a2ivvQ5oWJGwnZU6bDgvj8yHr2uM2YhRvV2XVexzrve", - "baseMint": "WNZzxM1WqWFH8DpDZSqr6EoHKWXeMx9NLLd2R5RzGPA", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7pJfKhyikTeMDiPSiQgVg1sV85C3VBfqyXe9iFSkrds1", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "E4fECj9MbtM4H8quMSBuaUg85vfrYDJCeSRAm8JZ45zJ", - "targetOrders": "7frAAztcx34WpUXS9SYTcreMSzWwP4RR1wJsesww9owM", - "baseVault": "341QAnwYmGcqWuDgCchmHb1mZemQHoEjvr6Gov6oaiLs", - "quoteVault": "52hhZs3ph7EJxr6J7mpu8vy7mZcEfkzRnQ3FGNjChs7d", - "withdrawQueue": "A6MV7ki6TDWBFfP6H6joeFzPDyWMdgYSvVyGXGisnyQ1", - "lpVault": "C7x2dY34PNUuxfLq4XZZEEhF3heVh418GfxSiHKjBLg1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Etz9ryTvrz3p5bByNfaLwy1Bf95SC16uMwiynRsZRTdF", - "marketAuthority": "8rygkzSNhqHUPxdLSQkEmRftPgiEM26frbJjonKgMyVx", - "marketBaseVault": "FwYDdVJXXC5JAdnqDrvf1T9iC5NfAYAdAtcYP4YHDirN", - "marketQuoteVault": "kMEhET8QuYZsNXm1gDp5hryY7Jj3iwPtQjbG3N1J3vw", - "marketBids": "5BXjBzbmjamgKf2UdPu8fgWHnLZbwetC7JS3GURXKRMA", - "marketAsks": "5xEYhX7n96Gboto2CiMwaHmwkYob8bdWjVktRmTeYdcR", - "marketEventQueue": "FTk1zHFiHAF8QYQYD5YasXMz8QGxZm3D51oWYhNXcYeJ" - }, - { - "id": "a3ChqeduegPWZE919ucot3kCCjhjNmP1yUcfPnAdJbv", - "baseMint": "CbDwU8JrTYv3GzU7msni8qtfFkAGpcyFAzuhuGq5SVqp", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6iKbxSnjwZxrx6J4PZ7EXQXGL1E6mcAJ6yGzerLTC9FQ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HQ1FXaPvfSxk34mQvmTaEotNDMSKBuqsGR73xUG5Fywu", - "targetOrders": "CJ7dZhERE3eTy9Hpd1mT36YGfUz1e9iMPVk2iM2ywgbb", - "baseVault": "BPUNgbVox9NCz5NwnBeweeAYtmTmt3r1FuxVrSnmb97f", - "quoteVault": "Dg8AzA7cWturJQ26dXik85jUnBWCYkg9MqdremshYLLZ", - "withdrawQueue": "AzSGNT3z5xuQpgBQ9v7PKCubMZZPUPSJfonaib1GYFmp", - "lpVault": "B9MqF2KDrdD8R4mz5GM46wEKZMyprju1tS6uCpsdqVzK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7Xxxxd7yEj2pU5bcvuTBHsPXPoVzWsbh6htDzViYBawk", - "marketAuthority": "9cBt1YgkFWhy7cCf7SJzZbDvGp1pXer2MxHLmMBRJYKC", - "marketBaseVault": "9knjdJQm6PVKJm4azGCDYZPF7Jx2tj2YSVAm89ombYaT", - "marketQuoteVault": "CQMy3mCP9MkpfSmz6mvQ8asYhayPcYgTGZRwrcbSoqhy", - "marketBids": "3g1UsLkbodDQwdcTv6v4Q8owLDdmwfoUuGWF7ZpPLY6P", - "marketAsks": "DBjxVSMD9Xk1aNypu25ciwHMHs5TACF1WDQzLGubF8E1", - "marketEventQueue": "7Kh6MkJHMtfaAwqFnM21hK8Z52PFViyxysK2WaLxtQDQ" - }, - { - "id": "A5azXepxyDQytjCztKUPQVAHPcN8GU38gSMYSLDugcV", - "baseMint": "KRTapyUMe5fW92KZkYoXToFtc6Cn7UG6seaKz646oGu", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Ec63jP6Lf4BSiNjVaTKAedDik2jHo6h8Vik4WbCyEHw5", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HALsHUkCKTLCsCHBMYCqC6iHURtHCq9dXNo8MUQbaBqG", - "targetOrders": "2xxHsf1E2ujgqmwm3o7sg3qCLsNK5CxqeHFatr2M7wVU", - "baseVault": "ANAoddUw1uY3XMUdwGdupAU6KtUzBvoKwTBy9iZKaRgK", - "quoteVault": "FEPMdCxh9wb5C5xQcq4spupqmhgk6BqNtqYyKq249wWh", - "withdrawQueue": "5CeURjQC1Wm8QF9J2hXZFg8ud9TNUUrSAaxMdez4Z18M", - "lpVault": "8VGanjRD7AZDPDpXwsm3PdKHicWijXoaD5zpjhuGiRkT", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HSvfLG6shDi8p3VuFnBpv9k6ob1u1i92SaGWCRE1zyYi", - "marketAuthority": "GpYWipgcWRCS9jFabhWfRwF3vAtcbDCLkYkzFZ1ujm4i", - "marketBaseVault": "Hq6ojQWJkNiXREXdhQMN7Y2WUkwNeM6GmFAMnNRL6Mpe", - "marketQuoteVault": "WQRDfgXScvJ6nmkGSUDfhPFSXNGun1g6hwa8gogiap7", - "marketBids": "75phEAzEaUr1zHbR3wYsQiBN8Eg7gRk2RUqBaagEktJt", - "marketAsks": "CcKrWB3jAs1VBSEwJHGBYdpgKPXFhrJrXksSdQzC6W8r", - "marketEventQueue": "HTZaNS2d4YhnxWGpNyudf5H8fzVnHGxgw8X5f3JhEpUb" - }, - { - "id": "a5sAFsEMzNWZMQViXZWQhg11Wp4QxMS8fCSEYr18Qxi", - "baseMint": "YtfMZ4jg2ubdz4GasY86iuGjHdo5rCPJnFqgSf8gxAz", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GaQ5CaE3b8meA5HAbRbcU61iNNyrHARHBp9qGaQmLbD9", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6FWJMFarn3HoDUwXmMPTwAR8YSRVz9ua9iMBF6a4MUxQ", - "targetOrders": "AdAGRPU49DvEurFJBnzmBLkng8Wp7pV71H4uYfGhky1f", - "baseVault": "GrDSYK9sWaq6PbD8n3jEDxrbNXgcUmvL5jjfbwb4T9g9", - "quoteVault": "GeopUwtjLWncuWg5SzgUGpAwmTgggTCKGd6jYegKMXma", - "withdrawQueue": "CwMkJyCgrJH8peRg59aZLbiDsrU5mf4funcUmw9YS9gF", - "lpVault": "4kmzg6bQg1teBTCDrJSrQNMzc3nCBJ6secbQ8cJ7BLFB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DCfxY2cDW2woEuDkGt3PqRRAmQC9cNbKVbCZ16YAMD2o", - "marketAuthority": "FTiWNPApq8yZLW3BEWJreddTwoLdPmWUDArm1zhQ5TXB", - "marketBaseVault": "34Au4Vtjt9Yvy4uhbQxQxbwWnCKdUwgM27bZ8752y91M", - "marketQuoteVault": "EDtwTGcP3dFgL2qPzTB7AAoLE3hAVQ8RPZVJD26KBLx3", - "marketBids": "3MWS8VFd828i3TRfF8PWXVcbUvLSJNaR59TGFgHYujjK", - "marketAsks": "GAUMw4A6qogBocrLTpfUXuJhmBKyN7tsXnvppR3cMZ1t", - "marketEventQueue": "FyBJeT9bZtWYnbx4RRfxeAdj2xWFkQoe1DkU17esUgYt" - }, - { - "id": "A71dLDCvjEmDDCgvMvTdhdoPRTpqYjtbndPqFrjifazB", - "baseMint": "9K4uNquZjVSBBN6fBsp62gtYLropyAxAbdZC7D9XErih", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "zN61LteBStjNYEUg2h9xumPquGatXdZFtatd4Rsz74g", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3VEecAYiXDDEGYAS3Uh38zn7971gk2JyYyoBczESAWze", - "targetOrders": "7J74Mf7asEZnZzXau1vQWR4weJZKiNXnkPYM5SFgoEMU", - "baseVault": "4ZcBRevnYk2s3q1wtGWpH1qCQrAcFataZKpRXbpcYdv1", - "quoteVault": "DnYVWkML9qmsGgkpyDpCQxsB7YBU5eewdGRApet7gUVG", - "withdrawQueue": "BwWECQZvRoUtyfCoxKHyqVWMhstvrHDZqLnVM7A6Drkw", - "lpVault": "6qzQMtKQE5441cXxSdBRFmfLw3SCq7UMnnWgSTAb8vNs", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "C2teVE3VkayUYhxVFdHbPR8SbbXte8itb2QrEUTCivfF", - "marketAuthority": "GUNJ49t95V8VWRfSNxtEPj1thmPFZyCjY5C8WqyzCDPz", - "marketBaseVault": "CAmaeboN55gFQFUoxPnqih2Lppk9BSJ2endWXdXHPUE1", - "marketQuoteVault": "HfEBF6hoTHUmrGBdQW5crY62YwvZsAn12vZ64MmUNuoX", - "marketBids": "rXULDXpTMhXeSexnYTB5s8X1Zy3vP9gofwW3PWRcoBi", - "marketAsks": "GKPQ5EXrWW2sX76Udvj1BGXHgrcL1dMEwX5fVMxDVzQb", - "marketEventQueue": "7Uh3ftJS71bHFB8ptKUHv3YrCNFEhZUQBemaumvyoumH" - }, - { - "id": "A7D9br8XUY4zqR29CALvQmK9c9yj4CVoH61GaJUGf415", - "baseMint": "HC9qZTgTYf12cFPaK3dK2HZJ9M47r2JenrsvQ1Ewnds8", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "2MoRP3pUCrmAWq6i4G2uyNCgdYd9RgC5zeKwSPNj7SHb", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4ySafydTRJftuPDoK2NXEHWPv4HhNcvBCTyFWAyRC8jz", - "targetOrders": "KQA8f8HWdDpzNcuuaXUt9nE6CSvNwnP8rAMmrWR93fY", - "baseVault": "9DzXvJAMHVTsGNeKAC24ayJkaui5vyGsTXfiPX7NLG1p", - "quoteVault": "6c5kTStYtt8MZuMUoFe7BhGJbyEuTGG8g1BQj6RkHYwt", - "withdrawQueue": "3YJwzrJs7c13wv6ULfYBmxMRAnPKbpAsffPr7sneAhQp", - "lpVault": "RbtN8WtUW1T2HFbvByq9GkbG95ck3K2bZSaBPGRtZbs", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EkraZ5VXukTK17XRUWguhvHBKMwVoVFVfcToixV8vHGJ", - "marketAuthority": "C6rEN2zCvdJhixznmBP2QGdmLAd9TWx11VLDVCXoAP6X", - "marketBaseVault": "91zKrwQxfDHfUT5UxMZULt2fxgi5KggPahP3iDVUL35d", - "marketQuoteVault": "57QAxfANKXYPMRbhnXiYZrVMbMfPAJUhqXS6u1cBCNLq", - "marketBids": "Dmo1in5UcozfbeXyvfrhdddMkjr36kVK4S6JD2qgsR85", - "marketAsks": "1kqQXxiQ7szzbhgip5ienM8HD9mLnMgGTtUmBojALTF", - "marketEventQueue": "J1FiNW1JW1gcge7CsFhmLTqC5wu4tm7Jt2VkeMS9irLb" - }, - { - "id": "A7J9hh1iX4BdajpDC1BMr9RPTv4KnUTMi1C2FVEDY8GL", - "baseMint": "7eum6boJMYZpEjnNZ8igTJgQjizFTGFqdgUfTbJWHxxe", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "ERTAaH95ZAJKWQxCkY4FapFjzZ9Ced3u8SqtKZijyMCc", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HyQQFQHA5NgFB1txtY1Xtct3Dr5dfcQ3THzJ3Cd8kjWj", - "targetOrders": "8Bc4hqNgHLEum6Sv3wWzGfKR9tduGswUqJKCwXgLnW8R", - "baseVault": "928vYtERmVxncLPSKnPh7EiFX3zkp8Zg9U8FtvNWPAFu", - "quoteVault": "HhYXqSypmpf2ENH9noQcojVX24cpXAWefuSECexKEzN4", - "withdrawQueue": "C4VPjE73bePKsFr5ijfUbatokpGNeEuxDigpWo6Rwj7i", - "lpVault": "GtYvBJLGTxoWXsnGasHo18mDuXLAPGH3jE1UXaPFchpU", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "88VakPssDJhJfcMU4VUf4FPYexzpAjRyHTyem2jLrV4N", - "marketAuthority": "F6yXBJJXeBgD7qzLPYdUdxDkm4Cqeyebg867F2WCQRJV", - "marketBaseVault": "Fd6vQe57PV7mEpL1XjoDtj4UXR3114qastdrb9bT2ooc", - "marketQuoteVault": "6bYrP4DzRbYgRW4rzt1YKBq5UNb9djs7iQhwV9kcGhb1", - "marketBids": "5r6D7kdy9XdvJd94QndWjBW6Harcb4BS6rWhy8BT9cMN", - "marketAsks": "3VN4am6PXMtpaUojWCt8WWrHQXYNzWm1ejGPKuZEh45o", - "marketEventQueue": "B7cVavtLe2ycjBqTXzW6H8ayPpYFu34CPAikgc1c6tYj" - }, - { - "id": "AA2QhS4vHrLRcVr4kXgtUV2kBjpcUobAjJTUrdK6VQ3p", - "baseMint": "HJbNXx2YMRxgfUJ6K4qeWtjatMK5KYQT1QnsCdDWywNv", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9Yuv5ng5PwntMq4r53qXQwue4k5Qa6BxqxWgKve39duU", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AGgPFuSiiJeLBPvMvbYtYJTGgiMZSEq9hhCzRRhur7M5", - "targetOrders": "BWjfnQx5ZK94VL5K7gopERZChzCYYeM1i36CpBXSBFmx", - "baseVault": "ELrQzDYcxUk61cvygWhFTS1c36YdS86QhsNA8en3wn17", - "quoteVault": "EnkQjSk2kAkoes4wvMVnJkHSHbnt7FfoDY2kbKQNxqod", - "withdrawQueue": "9f1xPbdxdtyHqzrjkz4GMpQXeQpadbh4xXcsgtMmg92c", - "lpVault": "7srXkWP3ybDkjMrgd1fmrsjjdfxqZ2EDttMSyYh1oZCA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HXFsb7CLFQPECRjgTMiAKr53RujWsH79SGNsNLjJuzXi", - "marketAuthority": "9NFAcUzfXtxvGzE8MN2QLmp2kzvP6LgmDYTyQUyQZsWf", - "marketBaseVault": "B5o8uvNFGkGXMEmzMHsHCAq3iR11Hb8oqUDjL5pcxcRx", - "marketQuoteVault": "5u1z8Md7Zjt2mQeGDkrt18DYoDz7ptbYDk2js8B7YbYY", - "marketBids": "2q8J6xNm8BC4RoKHr5aFcQGwkrus26og6vVDYbMmigYp", - "marketAsks": "Fc6AiYdDurjCPWtvWr9STrDzMAY4iMLiK7UVRey33mLs", - "marketEventQueue": "9Kq8tWA7CzKbbEFXT6tuRDRwM7ozepYWqPAizVxCdCPr" - }, - { - "id": "AAz1G5nvVmyyzcT95ZKzUBpNo3sWqz3KJD8HsBQ94tFJ", - "baseMint": "GpYMp8eP3HADY8x1jLVfFVBVYqxFNxT5mFhZAZt9Poco", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7ccXWAntFrd1akkHgP6AHht9wsyGHKY5PTp1NASLDRsk", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AGoMwfEruoHMhsaxKMY9AvcBtBgVenZFWWg3q3uSCk8q", - "targetOrders": "ACbUh3LxTFz4cZmwodANVnb9Lxxrow31RGjLydwu2iGs", - "baseVault": "9GifXm4YLDY8zLTYEYyo3WHUduWCf9XAvJhoDGTdHUWk", - "quoteVault": "AR29qdR1u4aCf6FqMSyBMn5fpyTT1Nnqys9Xjgy1XsGR", - "withdrawQueue": "7pMq8AxCVtZLronJx6qUmsViTMcHX4c7gb1syNU4Prj1", - "lpVault": "Enp7kdniuWHQtgxYGXHj6r5ZTniiwnP3w2KdNUWJDVJP", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "85CTDt8gNfJhmqE3Xm2smDm54HmeT1jvLfPVBTkX8BTX", - "marketAuthority": "3vJMJA2wqRKg1KS4acVGNY9RU6shYcBNkjP4yxqLGhGV", - "marketBaseVault": "9DNSE2CmK9u9XceipcAPcLKWBmsvYdbHefpKauQYEDTZ", - "marketQuoteVault": "7u6vnbep1B6dWUvXiuXfXYwCjFgAHwKENAmNXZ15pwXN", - "marketBids": "72h6vshnLupEjpt87Jcnb2E1XVh3GtW5oepA1cUaoJBU", - "marketAsks": "B48Cm578c3esKkc1hz5nWnVRnifBTCjuvAUA14q8idgE", - "marketEventQueue": "BY3HkwcjDRb8cViSb6Vhn4FpEYicaB3PLdCnTQAnftsr" - }, - { - "id": "AB14dqNmj6JBNTkTdmq9p3SjAf2xL8s5WX9SPAWVi7af", - "baseMint": "21vatMcwZz53Eu2EUDCS9xoZUXdJ9ABMTQYNMKKkzoNW", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "99EHrER1bedSnhWRiGvxCq6QB8cag32BqLFbpY8384qV", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "LCHNY5Ut5Kw142wKYwR4PfGNySomFS1XE2GFQTNP3Qz", - "targetOrders": "4cVn344YAVP8DY4Xo8nCTGMb3WEbrpidSk7b8vNyHmq5", - "baseVault": "UynuQ1c8MQUTRsdwaAW4huqdYzUMHSE8TvbjZzD9drj", - "quoteVault": "63tEL1nKy7J2AtamGJpqQYdjVhtnFVVSuTSUdUuS5GmK", - "withdrawQueue": "EpohFSGmBPCXNzGNMhA1e7NDgSbz46ZSdwzpWDCKe1g8", - "lpVault": "B6kFDD1eU5UHAE6FNywTJP5CsYpZsmSzN6cg3CFUTctA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BpcjFPSSavPVCSniiXaK5Gg1FvGjXipftiacmQbSKWCN", - "marketAuthority": "FrmocuXZhzhMtjDjPD6EgQqX1cvm7JYR7uZqcnEd9Bn", - "marketBaseVault": "C9jbyB1wCHQAQtdfYnjGiWXbJmhiXtg37UeybyZif1Ww", - "marketQuoteVault": "ExxBkEyTAtGNf7HmtY6HKqCELhRAnRMn2hz788PJ9jSt", - "marketBids": "HFGXZNPGG3qRiHSTN4btiLbpZXxuv3BNiGUVhoK6u97T", - "marketAsks": "5TmxWT4uQH3CJn9JdSWPTLvwwapRfDbA1YeaUweNS87o", - "marketEventQueue": "6Ytd8sKiXcxpcrEaJ9cHYnv5E3iBEE9JLWXXdVsrm7M8" - }, - { - "id": "ABrn4ED4AvkQ79VAXqf7ooqicJPHhZDAbC9rqcQ8ePzz", - "baseMint": "xxxxa1sKNGwFtw2kFn8XauW9xq8hBZ5kVtcSesTT9fW", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "E2nhH9AgQRDDZMmwTGZapKZLRBxgwJCsZy1uTB5to7cf", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "D7CHbxSFSiEW3sPc486AGDwuwsmyZqhP7stG4Yo9ZHTC", - "targetOrders": "UBPBMX7NPfiSNAGh9PF2knqLNKB2psYrYJsggaVvjK3", - "baseVault": "5o8dopjEKEy491bVHShtG6KSSHKm2JUugVqKEK7Jw7YF", - "quoteVault": "FN3wMZUuWkM65ZtcnAoYpsq773YxrnMfM5iAroSGttBo", - "withdrawQueue": "AQqKcyDpVxLKPnc1Krw9Wfo9QJxHsnzHB2HmUmrfuogK", - "lpVault": "9vZwpc4Kh43b2neWLTnkkhyrYSkQG3xPnHeSYQM776Jm", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6uGUx583UHvFKKCnoMfnGNEFxhSWy5iXXyea4o5E9dx7", - "marketAuthority": "3ceGkbGkqQwjJsZEYzjykDcWM1FjzHGMNTyKHD1c7kqW", - "marketBaseVault": "Geoh8p8j48Efupens8TqJKj491aqk5VhPXABFAqGtAjr", - "marketQuoteVault": "EVv4jPvUxbugw8EHTDwkNBboE26DiN4Zy1CQrd5j3Sd4", - "marketBids": "Gp7wpKu9mXpxdykMD9JKW5SK2Jw1h2fttxukvcL2dnW6", - "marketAsks": "4mkSxT9MaUsUd5uSkZxohf1pbPByk7b5ptWpu4ZABvto", - "marketEventQueue": "4dDEjb4JZejtweFEJjjqqC5wwZi3jqtzoS7cPNRyPoT6" - }, - { - "id": "AbrRSuTxeQYoek2d92C1Qa4AeFFZfTuCuRmso7wLG7rh", - "baseMint": "Kir4NUgYeLoHN7aBjNTfiyn3vHwZVKiyhBqN5RYBqnA", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4jJaTyZuigcXvbYx1Y9tudZJmUZhZcCkNU2zLADqDLE8", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3f9h5xYzzbR2VHjZwUfW63NtUZZXHhV6ke1FUdrg22W7", - "targetOrders": "2vk6WijzoVHdDuVNTL7HiXrtSd5U6UWMcc2YKHXi2LWe", - "baseVault": "9vC9AeZXfDAvgktEbKv7oZ8WD61ah3np4jEs48E1LKiT", - "quoteVault": "De4HxqYSgate3etv1GNGgRg7Dd1NzGCy3Cek3nca9ac2", - "withdrawQueue": "9VJ2kCUxP87mN3CuXqJ4qToWgcvQpe6yDxjhn1EgR8F", - "lpVault": "7zzoxvYuXNWoL1XrrNDK3mxQHwukQ8JkxMiJh9ptdNeM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BbGFz2ia6VVpzCVSN2JnHjQF5xGm5MWURy6dgCC8VnxV", - "marketAuthority": "Gg6KExqGAqpezph86LGBRaDHGPaoPXWfkZj432DCrhxX", - "marketBaseVault": "GACo2BKCxd2TWFU4yigygk9RYiNJvqzyMkzNMKATeqib", - "marketQuoteVault": "7iajLrEk4cjbxDB55ks9XqHgN2HqaQbZjy3SKRECgqHq", - "marketBids": "CmpTxFxYoJACA8Qzy8rwdniZFNKwZcxJ1B6c8AcxjjVe", - "marketAsks": "4KC3FkaqZ1WMPxyy5LQFezvoM9M6Lrbo2aUvEtJVbHFg", - "marketEventQueue": "2BnFWd9Jf13565oM9nbZjGo37pdYhrZjpFn2YLg7oB9F" - }, - { - "id": "AbTi44HHEW1vdLrA9yQsx3LZ7LLZypUWfdM8swsP4QPa", - "baseMint": "DiWunPY8GfsFthdDAwiRRtCgKCB5AEcFx9edDpxZoTyo", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2wawDDKePrpFk3VVQmmjtRmiLdjUFqKeK7AR1v1aDwdy", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3nSPdEmNzXxWj2WGpWkaPXnp26e1AbDUfS1E5Wkz2qjQ", - "targetOrders": "FwsVLTqUhbhXuoM5b6rQPiCa2TujCvfmoTUVVtpouK7u", - "baseVault": "FQzudYT7PCGzvhPfRKP6fdCDENTrFZeSJZiy1weSAXSN", - "quoteVault": "3tMey9oxnytuujacZM9tpLoQ3zR35DktGptrVgzQdYnW", - "withdrawQueue": "J273JZLftvAcsugmLxEzU1umyy3S4HG35U8q196GLgTb", - "lpVault": "8N35F6sSExeb8sjNtNG6XrbbNJuKib4s3Zay4AxCiH7Y", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "D6ca2PqdmoeFGmwm6ryokFXxCEBzgRRNVXBrNqbywnqZ", - "marketAuthority": "Bei8d4RKU2QaEd3pqEHA6frwaihrjNQscw5bCB5ihJJ9", - "marketBaseVault": "71YNWXhyZ2fjjNiPJVek28XhxL2oqnFVsVd7N3rYphQD", - "marketQuoteVault": "3mbKnx5WZkx1kVEp947QfG6tyPdCYN8Y2ewtgHE5f4fi", - "marketBids": "Eonk1e95q4Tr5d98ChDMFZTc9TKs3tsYfmPMGRyuF5oc", - "marketAsks": "9GY4ZiMbuPQQphBg8qB52ZN8X3ro78Etbmovekkv6E4W", - "marketEventQueue": "91uQWpfBmuJA64Gdnq1CjoYySdPrZCimx7ZwS2NBMMpS" - }, - { - "id": "AbzWpVgH31Wtv4K6eT9PF4BJZ1aaKBXoV1tiRip2uWk8", - "baseMint": "AymKzSDznoLT7Vhsb4wSRnCj1gjcG3zkgYFY8fxsHHer", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "ENA76HKkDfDbAaeosGvfFXB6NPFY8L8V2KkBAwnT6JXF", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "weEgoZdLfgKXznGtSS8bzmngyf182q9LPEej7rKP3ut", - "targetOrders": "AsLv2Kh8RoUwe6j2t9S2qdNXTiy6Ri1Wini5LeqZExrU", - "baseVault": "4wZC3Mq88t16L1zrztbCQs5JGzEaSpSnRSB2dhNaSzha", - "quoteVault": "Bft5kYoxJCuJzmV7uCLmkNTwGZpRVHJ4k4uuHRypDuLg", - "withdrawQueue": "4V5yKKpBP8XAQrfHbK5H2BhA1dsdAAySXZeqvBvDK9L4", - "lpVault": "G3oTvuRPCdWc1GvWiBMjv1s2e8tgYWxfq8EFhDqhCjDw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HBfdGEMeQQpGogC3Li4uhRqZxGZAVLM9zimt31vdtSdA", - "marketAuthority": "A4Wux84scL8LiWqveJhvFAm2xitGFri2j5q7K2qCUGJx", - "marketBaseVault": "3FFve1WPdewF1f8LgduoY1UH6fCZ9ReNsQBX88D6UYDM", - "marketQuoteVault": "AeH4K3JkNWrPssCuJchrjadgX3NXbhvSxMT7uCzpZp9V", - "marketBids": "DPBzCcBHeLGUGFDFKa7M9fuNWWb7W3yppffyktEKnEYi", - "marketAsks": "EkJxSEst8hMy8KAtGgkeKeFGxcyH459JUFbtD91YVsY2", - "marketEventQueue": "BHCnB6hLLtEt2nCLa8ZGFCWChxDdHPjqsuup2kVJVkcz" - }, - { - "id": "AC2JjRoryPH4VToLKtToq2exHm75WXoxj9KxXekfLs3e", - "baseMint": "DubwWZNWiNGMMeeQHPnMATNj77YZPZSAz2WVR5WjLJqz", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "J7hgEa6JikwPFmKUT9VTDJGkgbbY5yoLEvozFvhCMnaF", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CVEvCG9nPonKe1vbTYKm4yPco3rk8zmhpDLm1Wwb5Xvh", - "targetOrders": "54uRc2dPMSw5uQPckW84mHEEzhTcG8sP69w4rnrTkMws", - "baseVault": "Ch8SD7DnQeR2ugJ5csCSMcnn3uWXCWPqhQhcUeoLbKaw", - "quoteVault": "FYwJtKtEbcijFCdoB7huuqoNnxArzdmWHobKVhqvn68h", - "withdrawQueue": "AyJBLgvTn7U7gBXH27kf1ZZrxYqeHu778G1wrt5xrTo3", - "lpVault": "DbgdAhV7bRi3fpJnNPszwpeAuzSUkvQ1evRcdCLtR7sn", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6K7FsYf9UQwdVmiou9MEPMjaeWstvThoYQ5jZv7c1S7R", - "marketAuthority": "BsMosftoj8tDpouuGbLBQ1hS8mjGxBxR4jEHFiRFi8zP", - "marketBaseVault": "B4T7WnJcFY8j8E9PxiDT4yM3SCkbCKirf55AcbQjTGr1", - "marketQuoteVault": "7DGEE6ACHJT2x1rHkh1gEkuDEp64m9sTKC9ZgiMJrwH8", - "marketBids": "7G1THA5aMCSDuqVXmMbBjsa8egEEMUenk1x2CWCShZz", - "marketAsks": "4DAZZvutXGto9kWUu1puTro5x1BGVBHZeyLWXK2w3YHy", - "marketEventQueue": "58uCfutXpvVv46fY6HV4mTkC1HBRkzdW3RVdt4bvi9BE" - }, - { - "id": "AceAyRTWt4PyB2pHqf2qhDgNZDtKVNaxgL8Ru3V4aN1P", - "baseMint": "zebeczgi5fSEtbpfQKVZKCJ3WgYXxjkMUkNNx7fLKAF", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AJ236J6tLen18QW8t7XLAaELyUjg57HcQgSq33aH8Qkq", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7PScpgpwSvLUJ7imuioRvQ6xEuhS1mXeiTfK8dD6AXYg", - "targetOrders": "9egU1WLbwmhqrPYm7xr8n6cXWiRv4Kmi2GWauWsZdbrW", - "baseVault": "HLHKFGKj7SrVJMCQjpEvArNoAx8QzSUb384tLN9WLhSH", - "quoteVault": "FcG8WYNNUS7EyhLZmnfRmK6vMtGqYXbWDo3QKBdmXSpS", - "withdrawQueue": "6vYN1pybopcpfRLyqXcauBut6hQyDzTfHLu316aXW8HK", - "lpVault": "3wXGKiMFS268XUEuoEpvoFC24UG6FF7DbNspPCPN8jZG", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "C3c2NZurMhwrgMAaUXewjDGTy5f93MvYbhYCYfXXmnZN", - "marketAuthority": "7gVokShRW55W9t4yR4mkmb242RguvWWxGB7KRapcnMxt", - "marketBaseVault": "ERMmp8KsdZYE5nQ8aN4ArVHR2QTXeHuHqazmJkLfb5NP", - "marketQuoteVault": "9G9Ur6KFmG1hce1pv8jMFD6Xu96tgN8iaJB6VBActSMz", - "marketBids": "HwETAvJHBVC7rRvt1QSwGqvejPiBNSC28SGDL8U8mS2f", - "marketAsks": "pc5SRd3qRbAbmwKsNBjbZL3LbLjSanPExDyjRkkdgk4", - "marketEventQueue": "CsVM1k36bfmgiuF7bKmpsMuaF2m4GPuuBNkoQoNDqXNS" - }, - { - "id": "ACGh4ck4UvWkrT9znj1ouSgGRYqG4tsx7AFkXUX7kTNB", - "baseMint": "HuManQDs2YtrRkQu4www48fFc6mz39gG6u2vUT2U9B9X", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "4AhAphjiE9M81KyHBJNHCHrYTzScm2wrxLSu5zCYKvWq", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Bov7VDcJcEzVkLtTewpN8An7uGM4aMozkMKoCxmXjn85", - "targetOrders": "22kt1JoiKCnMjRuiPoKmrU6cUFdNjG4NoVYSDTnrZSox", - "baseVault": "9Vujy6rJqCTprrDxUBEGpbRFBr3hvfZsu4A3SZvpegLC", - "quoteVault": "CfD51AL5VpX7sb6vQ8rDFKRUjVGiULeGMPbR5Y1aNnry", - "withdrawQueue": "6CvgmqkqcVLaYuhX35kqLHvcgqHkAw3jLTYTXmUz9oEn", - "lpVault": "4WGHZvhNJQ2PxrfX9ThePMENvo7CGWApjg5DE3P47epn", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "G9yXXfcVHxp4pXyuC5cBLYwRaEJ4jdm2jYBComwBiuyX", - "marketAuthority": "45mcQ6QRu3iThiXiguP9wgpUGNMvhRQBEtq6bBVcVyRh", - "marketBaseVault": "EXPFX7yMzyKU4ktrdTGzVzXCYzT74rL8trETkMjWSZaE", - "marketQuoteVault": "4qSC5Yo8U7ZErVQdoovyVTx9zVcaX4JKsQyMYyrwvikB", - "marketBids": "5CJyJCDff2ncsHyuTBMQkcHaaCBJHXKTTma6BJYQkXCR", - "marketAsks": "14FeBxDG4ngoPEhKDGHY79m3SgoEYfAr4f16wP8zRubw", - "marketEventQueue": "JC9NYp6yTofVYp9XEQEKHQmwhtE6ZfSXASEwh5v2LvZb" - }, - { - "id": "ACHivWErLp1UFpy1BrQBL2NYo5F5KxqGH9fPRZJNaxET", - "baseMint": "B9LtfDZWWRrihYu8jDN57thcqqi7xfWAvj8yq4o2YJxw", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "4LbgQ6KRYT9TKB79YSW3NqEJuvGZ9MpnqNLeUxSYA7Qn", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BeCaxJNViPRfp2gn3XjqcZGoUuzZFj4UBF9BxiUPLYLw", - "targetOrders": "8DkjbSWmKQUu69TUHs2nCW7GguWAteFS6JgwPqihdocH", - "baseVault": "A4xbPTjG4so4rixEVCnNcDA7vjeeA4FuizVWzSJ8EW3P", - "quoteVault": "8qHRfV5GCMBCdqcwUMj1yF7Mq5N1pc8LBfbi6S8kLrtm", - "withdrawQueue": "ALDoamnYeSV1onKxvVGDtZ6RHoHyxcYm9k833r1wpKZi", - "lpVault": "Hfd4WufyJhrrqsxv6WQ35ggX92kMEvhYFL4K2PdxKo7W", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5E7UZ5wpWAJNxN7hzPCzMa5gKLc7xxepj9S9y8kGTkh5", - "marketAuthority": "9HpcpK4kCpDDfbTQahQpP4Q7wsGDJGetUNz7p2Ym864S", - "marketBaseVault": "HAv2TdEw8iyn5NoWxVK15YUctzSbVhxZjC8VrSkaMSuH", - "marketQuoteVault": "3dCBuaiZyd6SKsKNxHYwnunrqx29UjRzUcLito6xDvMz", - "marketBids": "4qiFZYHdUDNo2EvsTGWxahhSrAz6KDCTwKgLv7UxiSmz", - "marketAsks": "GyoSFw4ju6JMNpfqPUYEyTEb1H8RXi4nUgmci8oHA3ey", - "marketEventQueue": "DGmuaCr3gWHS53EKhfqNvLehhCGAWuYz65WVHKnJFd2y" - }, - { - "id": "AcSryWAgzMQpgisA7kzi7zViFpqSQojJ7FgsX6sd1RtY", - "baseMint": "4NGNdLiQ1KG8GgqZimKku4WCLdXbNw6UQJvqax3fE6CJ", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "H5jemmFhZERpbVRba34BsSQqjvipydb21dspd3J36nA9", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GcNjRQenwSgwtg1Er6RzbLpTDfJpDXs659zBtCDgVMSM", - "targetOrders": "3ExweF71w2EyAuPGTAm1gHbNZ8ttJCZDYbBmaCmtJAzn", - "baseVault": "DU8wSScBNZ1RrBGRqs8J2sdjmyuQoS8KQKvwzUMwpKa5", - "quoteVault": "Hh6KwB7zHtAL1GfNmHAcvqi5xXQSQ3DmdZL4JHr4WjBx", - "withdrawQueue": "BSJcJM8tG42d48tttfDx5rpMASUFwxAGu9fvScSmCaeb", - "lpVault": "5WAq2VMFTVRJV2rxCEN3cPpNMqqGrQetfjGFjztCfPuR", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4LccpzACL9tqbfmv8mseerD3767bsPiCZLrZzgVuTugo", - "marketAuthority": "3rfj7ovmukkeyYv3bEwwgJPdmmx8ZC3GZiww5c5Kmk9q", - "marketBaseVault": "2tzSzcZWXchwbLCiumh4kB4TpTMJd2S1f5avny2EgQAp", - "marketQuoteVault": "Crhqfe963RtpC5kMgjaCjYCNahGNTPWDd87K1U9Bste8", - "marketBids": "3uPKEsjD2LyTLCKzsqWUayNTxwtbX5ZkXHT6RzMnxxci", - "marketAsks": "AxmbASPrSM7V8hL4UMRhs1h2tm4Mdm8BQD954NqNKbDS", - "marketEventQueue": "8nzwwTZ2Q9y6eDyMtRBuVqLSq1u7aRQFNTnSTrxisoa4" - }, - { - "id": "ADjtAnL1kManW9qWoBEM3fKzT2ENRYScZfrEEtd8U2LW", - "baseMint": "3LCSAo9Hf64cxtPbArLog3PKkwGkZFN7Ttz1zLdPWPTS", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "A2XBg8NDgmYvovjrTVwGJUTvAKFQUGrWFZGNkaCwc9hH", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3gSAE6JjsmZsvrzfBZ7xYjp6GBfKQFsaXVhZ853E8m2H", - "targetOrders": "BA7rvdD7XhNLrMqLWX4L3xtNg64cBmN24ZXTpGKdyjpK", - "baseVault": "5TMS7V9iyZAmBGvskpEyQ34nUQjxwfRct6NjEsajEJkz", - "quoteVault": "6EEaJshXbcn41QazrRStDU3DCthSwXBA1urJ71xdujiQ", - "withdrawQueue": "2pwRiioZLjdK9kDjyQF21SCV7DrPgcfR6kxKUPJP88ci", - "lpVault": "CLRYJdt7A3pGvgekbnJhqcsj22zqs1WEzJZLysA67UhS", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7ensK13rXHzwuDa7d6n9Asty6XptctSZ6s5h22z7RoGe", - "marketAuthority": "2piKKekpBQU6rp7231pJ1cBv2SsQgFXzkcXF3etkbSbH", - "marketBaseVault": "2kgTxNCBvZZF2m8j6eUSA1KGhMrzMp2sp1jTk49zW4so", - "marketQuoteVault": "CcDJULwZU86J1KbbmGNhkx6hgSN3RsDMfpthNHNaifyK", - "marketBids": "BuEkCcFjb5HuYxFVFrvJN6Ahx7CfxMwkWe8dt8PZPv4z", - "marketAsks": "HEDknS5icvQY8piZwUy2oAsEze8MEFCABxSQVkuaw7mK", - "marketEventQueue": "DfJJT4ZFxhmtHLz4B2k8KUQXhHoMDvLR7YggMN2s1jtw" - }, - { - "id": "AG1kioZxuXdVDKACnPoWe8ScVVkpeCm3nz9aHxBsNKBa", - "baseMint": "BiDB55p4G3n1fGhwKFpxsokBMqgctL4qnZpDH1bVQxMD", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "HimxufM5Tvu9XXwPC94dsbs1mwta5Xp7FsncZUg5M4EZ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5dz1LqrhW5A1P2ohTKvGgvMs8jyTXRRSmDpS1oxXcpqR", - "targetOrders": "4ci1Pw8riacPPfXacXhSmLtZ2F2yv6c8BZ49Ry4bPMVo", - "baseVault": "4jJ3CaiHNm5qFKCshMu2pEgGDkyxCPjFhMmg5c1zp8rP", - "quoteVault": "3YB3VYYmW23qpNCrYgDJJDdGw7xcNqqXawXBNUZAtAzm", - "withdrawQueue": "5mLWjsSLtz1ZsrM7w9pnx2cNF9ohMhJneHfLvodmKz5J", - "lpVault": "4bVnrJZgrgPu58cRWxbCTamhCE2Xse8tBaoyFU5NRic5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AhLNACGvMQk6vtDq1mdcG5gidbnH558rAD6fhxBpcKUi", - "marketAuthority": "9HiFN8iNZtTVhPyY4YtxdA6yyds4m4FHTkf6GaMxXc2N", - "marketBaseVault": "4RP5D4BSM65XMxLWJe5AekkqKJsxSatSvbdKd7NcQvTd", - "marketQuoteVault": "EABQdbwpqDL3svMoFA6vEoPncT2DevUAtxtSRqozNzp2", - "marketBids": "4t6T1bmppk1PWUtm8Vv1UsmfcC5F3vKRRFXXUYncqpcN", - "marketAsks": "6nhDhUVcTTbGvJKpU2PeEXJxbwAbTiAXBJF2E7AYZgSW", - "marketEventQueue": "AdcpcXvsossDy1REU44eKvLnAn41p5shxDQ8vhyEJUD9" - }, - { - "id": "Ag9ERpJ1xfLaGSfBynQ4ML3gUCgvp87A3H5nJD7LZcFd", - "baseMint": "ALMmmmbt5KNrPPUBFE4dAKUKSPWTop5s3kUGCdF69gmw", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9hCtjpCCMc7LxTnLk4o9skgV5wpHnSbTUc8KXKTQ164T", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ELw3pAPpPrBNK8f12utFYGfaxpe1ArofEJZpKSs3bvva", - "targetOrders": "FwpNHJn7pRpwBD7GJfDmY9wuEtQs7HLS8pfQ8a97Usau", - "baseVault": "5VDTfcomRo215SgxqNKCJppxCajhXYwBEjJbbRx9oEZu", - "quoteVault": "7sX22H88bMmnan5RYFbFCeW7hkRbX5MsJsYWfegLZZ22", - "withdrawQueue": "GKeX43BEiRhBcd4WjhJ8ZamaQ2XWVBGXNT79oJyTbsTq", - "lpVault": "CS6EoeMcYirGH7GPNV9EKAUaVVwFsHrH6S1jsAChFCLE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DNxn3qM61GZddidjrzc95398SCWhm5BUyt8Y8SdKYr8W", - "marketAuthority": "5WkxXJWLgqpYGwmdnUPwRMRezCY9KWDwJZh1GKU8UCqL", - "marketBaseVault": "3aDrVRbqFBRRXMJHjmjR9RUHNboR88EVyYWTqGTMA9fh", - "marketQuoteVault": "Awt7FWxhwXVTVsj7AkNQ1Gw1jDrphngpWtfwS9z3wo7v", - "marketBids": "BuM8gNieTJRvEer9Moxyix3X8FeKZtqgqQDpwSzH9QVW", - "marketAsks": "HpJFyNkbb9CCjeeN3fw7xXD7FNdKevHifffTJJLeTwSn", - "marketEventQueue": "8DNjxH7G7Ypp6ypARHdejPHAPUeJYow2ufsKfPVn7uaf" - }, - { - "id": "AgF1CwGFfK3qwQNGwLTEQoKQgTbptDpBPMGMknDhEAQu", - "baseMint": "HDEqEpFgTrBawzDgTG1eyH8Go9PX84LCEC8Qjt8T4jFN", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "H31CZ37o7q5W5ZMmtT9vN5xG4ABE7QRwb1MkYTh86kyj", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9LTFgC1yvtEp9DdknXDzzzuSTRXjuYXGEdccWCpxjJ1H", - "targetOrders": "C9TP1FnogxNCpW8WEj8tCroMg6izTqp2gah8jhDGLy58", - "baseVault": "4YXPbmkxQtvxEdnknbys9Mg4VGzYhFWAKyeApXVdeKar", - "quoteVault": "BCeYnL7xw9bE58ARqu5DMFXNvsga1HKk55HZwGDyMdR1", - "withdrawQueue": "5qmqT3SSsHHkoKQYywnoqoFUMgKeHChe2V8ewEdMBT8N", - "lpVault": "EPxGH6vEdjYWhskuZ5chewkbDfuRMZvYthatsm1uv16B", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4eiymGfnWXrY9cnfN2Sbii7t1dbogJUnNpzae5o8nfR7", - "marketAuthority": "BxdUPqpoVAcP3fGFFoGmVPTXw6Km97aqjh4WonESxzUC", - "marketBaseVault": "9aMYzXg24ThHQ5D1cWbMEiom9oN2SrjtLzoQX9SvCwQp", - "marketQuoteVault": "9vRkUj85f9LEKcXxL3X3g1k6YRnvRvrsijCMABrpipaS", - "marketBids": "8kzYxqfJz5GVdpcywsWtxZGBapeHg7zcuA9UM5XqAa2M", - "marketAsks": "sf9wcAcdEapWF7P4ZY5BEuCyJfSnn3euace3BcqGVa3", - "marketEventQueue": "5DgvqEs8tbcbwX669LnRMEVKqeUxNtdpzGavsxFSAacd" - }, - { - "id": "Agm5sdM3g5JRrzJLQ34cqecaNAjC1NuPXEK2wE8acH15", - "baseMint": "6xtyNYX6Rf4Kp3629X11m1jqUmkV89mf9xQakUtUQfHq", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "89stLRLhDn2F7uQtUwCuAtPpyrnjh2bKfzg4oNF3eftz", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HyV66Wfdb2QHFLj4qrUAoeHssfrDNytWNfavoTNveDzu", - "targetOrders": "3MMiDHceAC2Eud89YVDCa4JvAHNqLJUrwkwxJiiPTyHg", - "baseVault": "DpJmyGwsQY7LnGdYcqNmCB2vfW3UH1USWkUWSC9cM6NQ", - "quoteVault": "9RJAKuQUHjTncXqTcjyi2idbwgNTWpS4kSEH5nJ8Gn2E", - "withdrawQueue": "AfkCYTNBRhZvmUNwEwPJo7GyATBp3N8BSrtbUb7iziSg", - "lpVault": "8Rqi7dsWtQEsXWaQbm6tnHG8F2VUBVPYxxfxuUWRaok", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "prLiL5ZsdKxDWT6doGZ4sEYHPoFxPBEGU5vJXffzShe", - "marketAuthority": "7Yty4mPSMhy1nrEwSDpRVAuKvWBnDnEaYzNnc6Fib1eV", - "marketBaseVault": "8MzKkSF81P8NwifdgqUZC7ZQqp33tKtubdspfGdgnTyL", - "marketQuoteVault": "8TeYrFvjUgoeTknM4wGmxqtPcNj2MPR9XTrytWBztzPE", - "marketBids": "8yBXgqeeU1MfKTD2YChNiYdhGq64hMJ1NcNsYrczaXXh", - "marketAsks": "9DcwJSTGgKGgzXyQKv883StuE5WWsXjUzCDV4TTYhV3L", - "marketEventQueue": "7u656i9ahVwNy8vP2Vov1av8EmApWTMf3Mco3grwAMkf" - }, - { - "id": "AgmCC2WpzBcRpQPHum3NYumwgB5qMEGzrCwuzqESfpxz", - "baseMint": "2qq3zxV9qBenTZLWRhmcSJdPFqdTGDDgc1aVQUCTs9Bu", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "7H4kRccNb49RpShM7QbucafNm4faYPoZM9CLAhboDYd9", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BnNnWPm8aicPcbSHHkij2bTqYWMB4EZXBK4GcHHYeuwg", - "targetOrders": "3mxsZeTNQJcyQcNyFgajdkwy8jh1YYRmmo6zhJsr1KUq", - "baseVault": "2UPoRBMMwzDqa5qNTk7yRjHCMGufpQX2xho3hVy1dP25", - "quoteVault": "7VjAKsjux9mzQdgxvHMf9bAMKucH3oqYqCSM2dJiQdMY", - "withdrawQueue": "EZ2rN946Xa3GxCBye24UCPmK4zhRA6by7QhTyuTfD1ST", - "lpVault": "3nFMzDgoiFMpjwsnm2ZNkAJRJhdaBDZ8bRaeRYe66DWz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CtjbSrFnBocdn7V61PvjQrpYatgjRG4EPC4RAiN2t7kL", - "marketAuthority": "FpiM8i25UeEkjuS2adCNhJCEsb5Rh53BEbvbtuuvYgE8", - "marketBaseVault": "FsJv9pNYfB89HV2RsrPQe6vwXj3WKehnZ1myhRUdF2Tm", - "marketQuoteVault": "EBL7XGTtPcYSao9zqbxTbmhuVBxfvWi54L9NUAfP4Bjk", - "marketBids": "7qVEScm5GJ3mkwQ2Dfmiday8KgyPANdfSe6Ry9wv16PX", - "marketAsks": "Fb4Pz83PAu4DdNeNG8pkWpVcZ9Y8qatkMo9WfPrH9dfc", - "marketEventQueue": "A1LfrArwvP2PaJDzyyCurSLSxhydVPL4ToR616Ef25pE" - }, - { - "id": "AHtRf9fwzEBnq6nX4pjqPR18GF2FAUmBEGRUh1g9QXam", - "baseMint": "ETbxzGvuzVrCxVN7cNoT6QBEYwFLBwMUwSYX6pUdHyep", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "BomETiK4o5jmYnf4LB74eNaz2wKTjLUa4eMp9XjzrbAv", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AbLv5gPjb5g2mzyQJMAqwTeTpmCtRKR6TAafARkUjTgk", - "targetOrders": "9j2CpF8rLdFPth85nzzbLSpGCVoBLnWGTmybmYDMCaaj", - "baseVault": "DyYSe5ZhVYS5PsedwhvXSkXgycRBcZKfTuVnX5shfLhx", - "quoteVault": "FeRg4g5W7K1ZiorCNCkuJ9sscJvZDaddFUhAMhdsyqTq", - "withdrawQueue": "6NwKt6c3YAK7QrTFGCVcRX2dSw9ikNsn21iz3Q1QCXcF", - "lpVault": "BzYx5oEfT4LZr2kCsY5DPwMRJuYCycRpjNe9EkyfPUdJ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "22SE5CC5apx4GXhzw8Cdo9BSH8Y4SjCwwwxQ86wGyQN4", - "marketAuthority": "H5Kxe3VwkHAL3mg4rdhY98FspB6pHK3tmrwJ5fs8uBfu", - "marketBaseVault": "FfhQdCuJHgyZFWNXoBJxTgWEKXaAqK9SGs6txwepwSMN", - "marketQuoteVault": "4oi1568neokZ3uNdNPvZoNrYhVe28affSn6uZ2URpoQs", - "marketBids": "8qEu9hicVjVnewqqQ1dh2TnMtxUUfTkX8Wr5jjffULGD", - "marketAsks": "7BSUdnCPVjYT1NN9mCbBgwUwRy7sB4dE2Qf1fFTHDXhZ", - "marketEventQueue": "EqZMGBJRbHEiqNoh11Dnvh3xP2hKvJt8LdDNnJgWZxvj" - }, - { - "id": "AJ9FM1XuiXVS1WA1SnSk5ZQchnoadFtdbN224GiwjwKG", - "baseMint": "7H4Co5vUfRGuYCHFitwCr2iCvKpv7QiRA8hFfwa1y4x3", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "FJgj17NDRQV1fVZv3dG6EQtXeFkHfbHfWWa23n4gYiG1", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "34VhjVFKV8mHuJwtu3fMJW6t2xDJ2fKBjNjHgGFakqdx", - "targetOrders": "jZ6DwsQv9P9vL2Npe7GUSR84dYMNWF7m16eT7Y8DHzN", - "baseVault": "J2hS3pfBMqrHoUyfYEGyK1QvBH3PwhDLME292fBajauH", - "quoteVault": "ELngzyPZM7hbHUkRLZMC1DPget67tzj691oQVTNoiTDA", - "withdrawQueue": "4gVuGZvSkVtMFC9LLaRKYPvAULVgnaeMwrpisJBUaW92", - "lpVault": "CyH1LKphV1uLRnco7dTf4JFo4XzXqVtjziYNp6fLeF25", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CBfXAhF8Ksr1a2MSKqyHcy2GJzUQymkfPKawGzdLEQSn", - "marketAuthority": "Gq4Svj7mtTw1iYce2jBSP4xMTdqPugdcRjqK7nFZUZzr", - "marketBaseVault": "FtBxArqJE4Lav3MvX8qzZA5jgGtT26fAw9fHjmyPxcNf", - "marketQuoteVault": "DnwLWw7MrngAMRAjqSBVeg2NF3FtwenKdvLfgCVZkGaf", - "marketBids": "BWSZPGuiaazUbVKkxctk4TzbUrbHqkP14cp5RL9QSYho", - "marketAsks": "BwyUmunoRTQM6fapxwaXEfUsgmbLavfVipPLjid5LtQ7", - "marketEventQueue": "8auXZ4Fe9fUFRJqQHCtRtGxVqHHB63oAqrPaYvctByhb" - }, - { - "id": "AJHm3QXZQkdwwcfmPwRS4QRanBssE5RJt7a7QkJV4iFb", - "baseMint": "CKGZzeufghDK7Sekk4MnP34m1TuEkmhGU25rs6YGeHdP", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "414yxxDxX8fFjRk2pNraeoTDBnuPQdpbu5M9KCBzfhgT", - "baseDecimals": 1, - "quoteDecimals": 6, - "lpDecimals": 1, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AHWNfKyc9pmY9BtiGyDsD47LJbdKHnd6FuYeEoYBpvX", - "targetOrders": "8uN9gJzfaKGNjMS4cgS4M38BfN9pYGaQbzzjM1kwztBV", - "baseVault": "C6r4Ap24PzC3G6bKrpdZgcDBEMVifGfs758iLjcwnn6a", - "quoteVault": "CSTNHksojXk6UVoXsH5FhaCD6QK5qnfkQuMT2D89CA5", - "withdrawQueue": "HmB5JN9X5HY4vi5jQby8Xc5TqyohJsQx4Pa7MSafso2Z", - "lpVault": "Afotg2Y6SjZD7oAfBTqHThtUj5vh2CLEnjpJyd6yR3id", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9kHctjysEBF6BjsrAqoFpShPSXmF5mCgNHEqTwbtvjY9", - "marketAuthority": "BfFyQ2GiAofHXYD47F6WaHprCA3V5JLEyJLuiL7oinY2", - "marketBaseVault": "H3B6mjD8rHGTBVJYJn9fWUiwaLHRmuP8VijeiyRdYnB1", - "marketQuoteVault": "BZtYndDGmbXuAL3G8KqxWLPkxR9ZaHeQ4a4gjmkvxaHi", - "marketBids": "4HdZwAE9JQJqZhJaeTC5P8SYcEoAJz7WawNVMf9Lzvju", - "marketAsks": "EiWo1sLPiWhH7idJSpSB7Dk79voE6bH4kiSUDUBABcTh", - "marketEventQueue": "AjMN8VcaSXZV2eBZZ5bddBwbENobc3mfN3hZKMunbC2L" - }, - { - "id": "ajrGt5mk1EwxMM1F1L2GBRmVZmtdXTU8SU9aV9j5AKF", - "baseMint": "BnV3XcZUbNsuonNKqkQrZSvCN8tVYTJtDgfUx6DJ9riy", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "86QbN8YKcqoP84GeUYFkuA4zSE7VAtBH54CMVfLGfbDU", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6JSHGCHwtU1VPJeFPsRA4FzSpJAYpRwBm7umQEgZC39E", - "targetOrders": "FbKwuB3pRhWd8YtLaCcJvwTg6eUweqCF4oH99Navz8CH", - "baseVault": "3mrtGUCZfNgSUUHFuysLpFxAc6gJEbCwu81TVQhVc4sB", - "quoteVault": "69oRyaTwJKfDFzY3nteEUChdcyY8n1zkw3WR2CjofXwn", - "withdrawQueue": "G6dSJmBQAqSNWPQAHTtEf2dUj1C19nf7tw9biw6Py35H", - "lpVault": "9puA14Be3UbXKWvsK7kh3xHGjtG7SuJ6ajq3XpFCbKfZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2nFXPnJQJjEKg6Jwa4GvxGsGTXmtUJbx1dxtUEzwHyqc", - "marketAuthority": "J9eRwkLGDQuh4G17nM1JJPDNVBtC7iY81Uqyxa7Wmi49", - "marketBaseVault": "FUfXZLHmJJLCj57EcfsvdAK77Gr3SoVwPGqyup7uHRUg", - "marketQuoteVault": "ENdgtKWwmmksZRVJedGPFYZipCrJXAfiS4co2Reb6piG", - "marketBids": "5LhX3cF3FFufmEbk1MNc7Y446fcCfWkaUeYAbMYM1YFA", - "marketAsks": "6AfHeWKpNNGGmwrGPHqRbzHXWVNM5FkR6ktyUEa3ncqe", - "marketEventQueue": "8RjB1Rx3Bc2y8usR2WjrvkiEyXuBkxndRX7DXTYETGB5" - }, - { - "id": "AJYW4YdvrKQvZz3VMMPmpzw3b3LUEeJrnKDSpMDapYBS", - "baseMint": "8yiekaUUidqA8bQ5QuWGNgrSDCnZVf5te6ZykGeY8roa", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6231BjbJWW2kb9G2UwA4XCYgRdMmPjHLxDbg71QYS4Fc", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "54zbpd2UCsksFHZCYgbj1JQo3mLzcaqfxsjtVHJ1NMSJ", - "targetOrders": "XanY5EaMdsz81f6dCiSjEbQQkue3JyZkLPdKmtk5TSk", - "baseVault": "8db7vhXepBbQ8kbYpyJcwSe5LK7qr2bZiRB14fxwUFUZ", - "quoteVault": "HmRSMk4ChQjMqYspEw1KhDifujNy8vQCEXtBStPe1e27", - "withdrawQueue": "4HHLm8DoRPAkLvbyPRJyv14Tjoq6bPjamKi5GcFxnqr7", - "lpVault": "D55nDCk1o4Bd5LTdnZYBBbSM1bQS7mf5wLwK5Q2bw8nD", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GQNxViuLcX1xZEFDWUwKikYw85VqNQBhVLhzRMespNMJ", - "marketAuthority": "FUqWuvjqsHg6wj3WPHeR7jZLUr2QFosuMsVDJ6LFNQca", - "marketBaseVault": "2XWv6YgQXvHiwTKw4ZHMwqwyraSw7ovKgnXFjDABi5fi", - "marketQuoteVault": "2bhvThvcEisXYB8qMYXEbU7QcLmJsb6xerCSgtFSX7Nc", - "marketBids": "9G3BvHxRaRy2nr7gGRaHbBzZHh5TZztPs76jx8oJDjQx", - "marketAsks": "YuxQGRr5kvUiLSd5C4h2u9GN6kvMYYfJ7CPKveBTueo", - "marketEventQueue": "3zq6HJ1YaPmt4mN5QUhAi7jhkH45FXbF9xMbzf2R7qXf" - }, - { - "id": "AkjPBLwaj2Ref2CKdGk3djZ4TQPFrP4nBvUKB3jxBHJ2", - "baseMint": "FxTC5zYGqy9Bit5NkaxcMm2mAttdhbwf5MeZzMZHdT8h", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9Tv9RwLeHTq1CNuMS7C8bgtp3NDy7GGGcoqK1BCABTAA", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9ibwAUgj1BHjgmDWtZZ5eyVJ5ni3rbs8LnMZZ8Z4HAHt", - "targetOrders": "6sYkratBkS6nGwHpSCsYRaLjbarGy7sc9E6qKYtMQb7E", - "baseVault": "7QPpeqkpQksqHBViVRviS67whK4uzuQQ9ZXGaEQimTUS", - "quoteVault": "EZTtbToX8tRM2SzMx9mSV93FkMHTBamXoDEV348i5ren", - "withdrawQueue": "WapBhi3jcpuVFmv3KxrFnUuXg2hbjYGvgCsLJ8vVyQE", - "lpVault": "FkaJhpQNAjt4qengpHyZczbxApAZf8KVqCgVFNDFGygJ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BD1ndDcTSFrEvKSufpbZ4LXLPz3eeno36WtrGRZeYqeN", - "marketAuthority": "BkqxRs7JssGjTE82psBcXRXYqmTKQFrrDbxA8YZFFKTk", - "marketBaseVault": "6jPKjonGfb2grjS5ebDHM8x3MyXH3BhsSE6LaDAsnPVJ", - "marketQuoteVault": "CLzSWEUNWtAUf9F52gnjhFBtDJs8BKLzueweNR2veYQF", - "marketBids": "FJzj2N8C6M4MaYELnmuCmK5n6NtYFuPv8WC6qEkEAp1Y", - "marketAsks": "5f6WcmUc8yCBbQDN46EL6N4uoDXPAGJ8aJc22iUZFr35", - "marketEventQueue": "9Rfgo9zYoY7G6YHTUBR6ruvPtbXZPDErZfsZFQJr2uH2" - }, - { - "id": "AKpXWPVFwD39xFVi22UT34s6CKJnwDTAY14pDiGqmae6", - "baseMint": "FiFxBfTSqcz6vWRbp5TKbyhgfkXauSfHiRwxKqMcbuNA", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9YFuq5wSqteVYExdyUM1CVhkAEjnnBrd6FLb8Gxk4LrC", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AmVtuPsUFR8VJyTw5bDk4HCzNrwNTDQ3NHKcv5RMdvnV", - "targetOrders": "BypPSgCEMLpUMoWkUNCnmnueLCT7C4D8bmeLpH5SatEo", - "baseVault": "F6Syc69ZBt2VRRpBRCLZhfiRrMQEiMSJA2Ls5KfZsC8S", - "quoteVault": "6kxBUfyxPpBvuRDz5Gbgttx9WjjRPTqSPQLdHp2ZyXPC", - "withdrawQueue": "4NKYa3uGQCwkRJ6yqzQNfkNUz7wFMrBbHzefcTd2smbD", - "lpVault": "CUCUiCXL6nZjsYcbY5KGnNj2nTcrmoiXYMy2q3uxYxen", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DAKcttvzKZ66TdwvXF8yss1B6jHxx9reFoYScAVtLXXe", - "marketAuthority": "9fjJXLt3ASoDEExV8WyJ41m6h54ZyCCzp5EgEVpXirUE", - "marketBaseVault": "J9UG4gN1vAcTYdtC6kxqgvghctyURXsdikLkreyG1jVh", - "marketQuoteVault": "HtMwrjfDxmxGyGqXCyASRYcPxeVYjSMFtf9zBKbBYa6v", - "marketBids": "6ozdr384ZmUoVruvRaFUkDESdS47GbEa79YVx6gtVbGA", - "marketAsks": "2FMYQtL9TbWnBWDdvhjs1H58FTh6Uo1cxohvg4MeQ9Tq", - "marketEventQueue": "HDJQvAXLK1v6xv3Ww39TcJiiQyhNDntyaK9x2JrkHXci" - }, - { - "id": "ALmASHZV6HDz8UzvczJvNy1oWcnC51UZEyxYd3MKMy9P", - "baseMint": "51AA7ktYcb8yb98Tfrhs6TaDjr7cMtJVo6sEMNe87mNs", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4LChQX2D2oae4oTZwjLKS8QmNmKkehKcHQn8j5KH7WZ8", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2WJhpcgy2cvqG9Lr1CD6pRMs6ZP9qZWsQArx5PnBHY9E", - "targetOrders": "HNiKtm7J48VfbRosXKwy1utGaNvFXqMbhpf9hqxSMJgm", - "baseVault": "3wj8myVJsSKptfBZvHLTbrLZhx81Vh8ZVutBRYxogtXi", - "quoteVault": "5FD6vPxVQDex6tB4Ud8fHLLWxVDaZXja88U4zzdQMTky", - "withdrawQueue": "68qDwjkLNuY4S9R9HVPyMti3BVmGyGCGeK7hnZxNZTJz", - "lpVault": "46XWvxiWYs3w9iY8SxPLJQA4VT7ZoSrGceGPkf21twiB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6MYPELcR5Ss6XKU6tsgq7kDtX7ZyvrXaRjgQdVPE54oA", - "marketAuthority": "ArXHo4zwzButKMLTYWngyGQ214WuCekqUcFKhJNkZtuA", - "marketBaseVault": "9PN1XnGLHedD7kH2eygLLqjArSvrLiFDk1EjFkNbumV9", - "marketQuoteVault": "5RMhXwNkL9B5dMnX4x3GKybVaJxcwTfMzasrFG9mQbR1", - "marketBids": "8QFHP4TupFu7PQtA4azAv8s8xefBZKGEtyxn2r9sYDTY", - "marketAsks": "HJAsDz2LoYUE1uodLwjT13ZHeRdFqTk4xofhVtT1RPwX", - "marketEventQueue": "2orkFG1Q3Z2phgv7x7DTYNYWruSySLcM4BZeuRZksDys" - }, - { - "id": "AoXjg8ofgjQxoo3H3MBmCbJLq48XVpg1y5TBWYwXoJcx", - "baseMint": "3DHPqxdMXogNNnpqBMF8N4Zs4dn1WR31H7UjWq6FExwG", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Db4Ni28v2o2f68nrb5PtjaDskDTKBjKSPpnodUGrR4F1", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5Xqyp9yK4SpNfawU3EY33NgE7Rkp7GqHmK52xwMMdb1a", - "targetOrders": "6ZPKakcGff854z1JtDFeQXBZXfepuYsdXLfiGDyUxg4P", - "baseVault": "BZQgmhJBzgDx2x6F8FUBvv1U8FzadfUAPXZCt3LxNeTj", - "quoteVault": "B8KSZR7xgF2LdWPUyFNhGS9oaJ8E53s6V7F7w1PHzhR6", - "withdrawQueue": "EEDTfRDkXheJqN8AQk4vyZzHsdJXsZD7sUWM6Pq2pWQu", - "lpVault": "9Hpmo1VqakrnSEhTYDz499bFRCkrLGA8vsX4MFwMdAeC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GEHUWno1Kh3Wu8VKCy2dLR2Kxo5YTZUJkA33NG1bCR1j", - "marketAuthority": "Cqy25b3rL5mjrYgDnfpPebh6bGQ7AHz8zZzCgBYjfRSf", - "marketBaseVault": "CMZSbnRq3aiKc1NMaG9yAJdtwcKD8URvBrXvhWstfihV", - "marketQuoteVault": "EZ6aWQcPgM3cKVaj7nAprZR2iCxaotakajNesij81xyb", - "marketBids": "AVJbHQbMWrBVLaxYCfqFa12ssbraJ5z5ZY8itvdszGJh", - "marketAsks": "JB2y77QJ4Fzr7uj9fMmNnGVFFiUxELn6Aa3TXWjoyJoQ", - "marketEventQueue": "BwLWDcBWLezGDcn4L648nDusakFmPosuHBBtKLRvzStE" - }, - { - "id": "ApCWKVCMn2AW77NFDSgynFP2fVT78m1i4vKrjdUci5Nb", - "baseMint": "41TwwURtuv4k8TuFxp1vfFYP9noMbHXqtscse8xLM26V", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5zpCaZrcpSTkoannC6M3TMoXKpZzYVhDHobvBaGrSp7q", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7uusHUjtg9duoLZw5e1JhX3KxS1sF6Rg9CZ5Hs9MfH3R", - "targetOrders": "97HLWJD3GRkSPSmBjdkuP9MQDQJtxm1AWwi2jitQL9W3", - "baseVault": "5YjfrxtcnaFtHWJUUNjh56Tb8QBCQSpUp5s3tEynZuNm", - "quoteVault": "57im31Vy5Ve8BzQeHpxYBCZTokZYBuW1JvX4x9gBtyxd", - "withdrawQueue": "3R8WaakCHUmtWXd7spZHumBYinWXsHKLt51swd1aGuy4", - "lpVault": "G27Lm9HbPpSZinueB7tk6W8W9do3bqGb1m54xMxDTzaw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BUF1JfyS3zQMLJ3PMUX4CcLumx1vZsgAfiDzEDgi8iwL", - "marketAuthority": "5jQGB7zpNkdvn79TeESqJXVNcQ7nRWSvBaKhpvGbJsws", - "marketBaseVault": "4YN89AySBNFGcrKDhkKAdnCgkHX1TWMBkA1fBW9YFour", - "marketQuoteVault": "AgC9DW16XGh8ZH5T38vCkxN32NCaVVFWhApk35yZJNb6", - "marketBids": "4nc91ZHas5Kp6YdWs9SWKQLCe7CxdjMKNLoxdybYhUNt", - "marketAsks": "2sAw2jauqnGpjfm5yQYfyTm7AtroCKy7srxm9LsumbaX", - "marketEventQueue": "64Aj8dcHGv7K4PKkNaKThu3C2yktm9qRWxZZMqS3BL3A" - }, - { - "id": "APLBhbttnJDUcj8jxmwkCmvtofBzPg6WUEwtzuVome2X", - "baseMint": "3iBZV8gvUFxp333FFogUPVi6MP9dEZ74xUxVzEQvNPii", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3jkVPJJkRtg3MvRGFvpFdH5Sv3zRM2fsxuLTrAf3a6Gy", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DfDm8pzLqKoUqB2sHr5aTJ3vHuHKZyZ34PAdbcv2WJgG", - "targetOrders": "CCDgfNRuukzRs27eP9dhbdN7TcNTSjfw3RNF8TgTf5W6", - "baseVault": "3irhJVbFbV6KrQVWtZzLtP97bQAWGhEiMLcV4YHCWctX", - "quoteVault": "8gQ83TvoaNM3iN8Acbyuu8hm9rVr3rYLpcGWjgDe2gvk", - "withdrawQueue": "7fCP9dnUoZ8aEXux2dS9gKCfKjQ6DRi2Np3wQKP6yXcg", - "lpVault": "26kQj2EzNiXqTUyaUqDqgU4Dd729MTL6aFtiKqSESo39", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FPi6R2YAdvfu2bXmxiwNAbYA54qwd6pAVo6yt7hvKBGF", - "marketAuthority": "6qGe3amJuicdy4HDJMTsm2i7Dih6aT7cBBoR6TyvHqYA", - "marketBaseVault": "6aPDrD9RYudS4n21w45BPPTUPP9LcvoyxSeuB4y7XpP7", - "marketQuoteVault": "5X2SqrJkA3eXwk7GcT723cjhcAYK57rcd1Fb8LkYUYzo", - "marketBids": "4ZjXSHDsa6z5EakFLSKXRf5R4YVzyxMknd67rgmZwiaa", - "marketAsks": "EoazsvkrNxzWrci5a3KrcRRF9X9CCVRStY5Knc7hjkXV", - "marketEventQueue": "AJKAMd3zJyPfWbPxqHfuiy5dEvGihbNDqYRHJc8aFaFR" - }, - { - "id": "ApRSJTR8Ko7n4q9Lu24XLgHSZhkjY1w93d1yac7o5UrL", - "baseMint": "7TQTpG1qBvE9ui7J9yQWKFAYpQahkaKPKqGTsqSm1wUv", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3TUBL4SQfcKWNAELaXfVvACrvViek2AAGDidBra42JNp", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EPDMRPnyfj9DrJDxVX5bZ8FhRiXHUsvucTgdWLVwmpav", - "targetOrders": "2nE2vFEqyV2FZKLcJb61KzHTujoUTr9TETJb7PgJdJYU", - "baseVault": "E3G71rpwBfypBD6dDkRNrHzgK83dAxgeVcrJ6bVwdpLA", - "quoteVault": "35PAYUSQTDsUVoRZi8KVaSpqAmqa87gwzECdbVuo2V4B", - "withdrawQueue": "6w2VDYNjY3ZkoWCw9ABzeBffYLMjZGUCJte6qstBNzjJ", - "lpVault": "4VzuRcPQ5nraykDEV7GXMrV7BrmmRMKdrgvVuXxvQmkw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5VJR1JomXkmkzS5E7RGi6FQS2zk7uHMPJzaKHz9nUaBG", - "marketAuthority": "9ea2yaegnyNtWq9YbVCg7PvWjuwymTUqGNHxhzzTD9iB", - "marketBaseVault": "EmaPoY2mEqvKwgPn5X2qEPfXYE64T8GSJjcb3sZa8Lhg", - "marketQuoteVault": "EYjrhBLzQBJmHkmm6yToCxcer6FYpYoGpe86BRadxjCC", - "marketBids": "EQUXZq5gcCkuE4d5eL6UW8boqZHk2LbcVH9NH3vDaWmB", - "marketAsks": "C4uk5DkikTDFix7kRnWifbNGqif57QacwpYrHS4YdUGx", - "marketEventQueue": "9x1S9828ybYnJrW98agVd8SakQQ9C8YB1GpUx4wZctns" - }, - { - "id": "ApvwWsRmu2zzXVkkQXWoqj7pKvP6ZBoLfeNV51pHbNGx", - "baseMint": "87rSGrpYdmTxfNBf8o2cpyiNcxCmNhUPBXjT8aoyfob5", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "4ULSeMgPopxNe2qyXYKVaVTs1JTX9nXJix1WXiW3H1wo", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GXTLgtZpjsu6PMrHQGK5CEgwVaU3b1C31LLUUG4gCzPa", - "targetOrders": "6UGTr4TpCmzpNNY5DWvEyagdBTZefzHDmHjek4J4p8eY", - "baseVault": "2oGQHfuRjZmEdwaX9Q3w7vkPDECdr7wd2ES4ChBsMo8K", - "quoteVault": "34oArwn7ZPu8R4jRGAS63ZqcqtVfnqYM5FXVTft9WTy9", - "withdrawQueue": "8rB4sdEdDwg72kjk7VxMFtGo6qVKm3hfDamhbC2CRt8y", - "lpVault": "CV9XK6svfU2miJ5QvWjZi2UL1gnLDAM7nmCQ3LQsuE4P", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9gbPtLpx61mQVW7BrfRC8Yy4keMs8BiZEGjP4LPbKGVz", - "marketAuthority": "E1c9Y7EW44KUqvhNeuanUocVdTNRZUd5gjaF5LLZrQYh", - "marketBaseVault": "7zgM86MCGnwifsHmsNfBHYBuBe7imXr5UJfYtQsbznAM", - "marketQuoteVault": "3w4KiS1NDcb1EB8CbGEQz4V1q9nNQxiAzvGKcAfan1GY", - "marketBids": "E1qBcNZTUdDUjyGysdPpV8DcRe1XGTNE48bre1DcHvu6", - "marketAsks": "7WS8LiKn8nJZqMz32qAZUWiH2AswovsbCwPieFxsj7h", - "marketEventQueue": "BiBV1MXoqdY3429NCrYdGWieixytCMu9xoG2rHeyweJ5" - }, - { - "id": "AQ3rjwJVJcVetDFTLdbP3GWo2U6FHWmnWfHzk11RL6do", - "baseMint": "SLT3iSYKeBuCyxvnfij4RUhMfKxZCY3s12Z5pfkTXhV", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FB8mLdCtJcDCzz8Mv5yVQG3DAucBe57wxkFe8ALdqUUb", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6z71DBkkv2rQMaJpwquCdYLbSYDCpKFofLzMi9GCEX6S", - "targetOrders": "33Sq7KuADctBxpfzCd6aZ2f8enKnCZwssHeDHvQ7bF3p", - "baseVault": "4ZkH4CHGaAvXLV7PHoPAYzXqQ4Gt1NbtyVLfwowFwvbN", - "quoteVault": "5eBZm2xFsHB2pKzW5sV5JAwFG2ej8VRunL1rzRPTq9tE", - "withdrawQueue": "YxBQiLuQ9NT4z67jPy11KW6MaAXpBo1YmPiV2hxCVcY", - "lpVault": "G1MC7VErBnLS5U7JuUV4D56JSRnxHoZ3fzBp2cQ6YY5v", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DhmedYCzs57hspLjP3SKd3NRcsvDbuPSQdooSQof4vek", - "marketAuthority": "5EUwm7r9aVXFsyWJpocKH3GdfiJrJP3rnZkUYUJ7Fsft", - "marketBaseVault": "B9ESQ4w9WmjBcSKF4aPBBUf774WW2wt5bWUr2howwwnt", - "marketQuoteVault": "CnEhDttg13gHodMqE98tt12xkv93Q54r5QH8v4DVnNMm", - "marketBids": "G2zCzyVWbVdBBEEQbySAcy83p9k3b8Tw2b3wbRKdswU", - "marketAsks": "F9hSEXA6iDxdcn5FDGDFzTce9omakFvSUejYhRZo1ec9", - "marketEventQueue": "873EtXHdz8L4Cv9CWXPpUtW5N7yieC4yhzYaBJMTCavw" - }, - { - "id": "Aqj4KNN28TvvyGtDTrfwnjLb8eK1GJvM9tja5m9qdgDM", - "baseMint": "Hmatmu1ktLbobSvim94mfpZmjL5iiyoM1zidtXJRAdLZ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "72VDxvd1AyZMz1YX1daMvEEzNikuS8M6BBbFHq1FBNr4", - "baseDecimals": 7, - "quoteDecimals": 6, - "lpDecimals": 7, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CgQ5jb2ztEyM3rLY53mMBAJ4GJfkUJr3c9CVzqX6jZcn", - "targetOrders": "5rx8AFopsSWnMKcXWv5aUF3yV4ZiYDfD8PDASKdkxEA4", - "baseVault": "9aoyrobD9PWPL9xVgTwnPTFfmVA5FeygpwCDN4C6Keow", - "quoteVault": "EKVfTAkfQrSySTK77nv3TUm131dcdwhjKZWgqUca7KMS", - "withdrawQueue": "79qAQ7s7oaXtc7DqDsNxzXGM3GtXXitNqdUijDCS2RYv", - "lpVault": "6t5bSHthBAuKmtooaaHUWFQ3qaJPZV4ELSnQK8YAHiYB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DukWnNjNS1qQYUNGYj5NJViEfQW793mHwxij3wi9dazM", - "marketAuthority": "7r3zLUHskAnfn2g3KjVFCsnsqHnLpc2jV7DWqKRbc3ca", - "marketBaseVault": "cZeGkEZBfxFrjHcPtzE5FTpVwQngkufRz92zaSZrYcW", - "marketQuoteVault": "AAgz39HnuT4fjJ47h9twzm7GamCZ1aFVPNZcu4QqBb36", - "marketBids": "ENnLtfCzD3UZ6oRka8uitaBQYwusZ9dxyMpdBPjpwy26", - "marketAsks": "JutgepFP2Y79n38gsx9C3HTvySTT7cddPKGw67G3rru", - "marketEventQueue": "GuTVqSRfTtYduCyzPXP1Xs4u6GhbK1XUGkz94yvbbruy" - }, - { - "id": "AQkKSK8wSNQiuouGsFCXdU4s63DM9HgNimT9o41PRTQU", - "baseMint": "9b4BsjTzXD165MhrAsfJrqGKsBau8PS6w9HXvV71kRrP", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "EmDc8YtikbFWfaa9rqgoCDbAyGVdpG9Lgsh7NCxUfESw", - "baseDecimals": 4, - "quoteDecimals": 9, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7ozDJLSdvQNxxDAsCfS5XteXKHBZmJwWtBBX1wpXVx9z", - "targetOrders": "4XrHJi3JyDqqWzP4EjwZmkLXYm8mn9NXLPVi467gHUEF", - "baseVault": "2qbqcDgLqfYgETzbnS9yVugd8viqpbwrGN82o84UoMjV", - "quoteVault": "3GmWiTggfDgZRXUx5QMhwh6WrqQCpFVQPeqGXnn8FvJ6", - "withdrawQueue": "B3cPNfGqnARoKGL7vz6MYJiNMS9hrUuVSVSt8aNk6ric", - "lpVault": "CqgYE5KEy5Grn7SHbPJg8Q5xXjw8ovbfVzJqDedYnSPr", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Ge2TCnSHbq9ynzvJjiGSvHvbxAxFSMxSQ4nTgtUEG8yW", - "marketAuthority": "D1wM6FxWGc5ZYQh23PxUehGLWPVrvEbJDNhejXHig5gF", - "marketBaseVault": "4uFsATaPisww9RMKV6PSb6cMdqSWERquhS1jmxL9Gume", - "marketQuoteVault": "3Rr3QVq8AVE4jZRTH2a77tUwMTb1JfL9gqgmmwdhcy5S", - "marketBids": "FWxDjsxaWmPNnwbvmHkUAPVZA4DU3Wnx4bAC4pNYHMhp", - "marketAsks": "B3sTomWiBBnhzbrMP6JmTZJrNjoNFeLFEDRvoSwthQ3f", - "marketEventQueue": "AY5TMU6fKmeT6fG892XMgAGmKkfMbTN6YChmFvNW4jqT" - }, - { - "id": "ARNeapKDWuoLjr9KoG4ecmNeJWTJXi8HXz6277ZpBTZT", - "baseMint": "CGBxTQNXMmmCXAPm4dC9MQJ1q8JDDxApwFwW188SdtBu", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5KKPrHpDCVhqwZT1eAcHsxcSpGsLVmE3sv3iFsMDb37i", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7CzrZYe8cUUpvahFXiJHXorq1dYt4VNNdSDmi2XsBN8q", - "targetOrders": "D7qfRFRqinEuopehgez3nQzQDpYUxsqEB1EfzKafBwbN", - "baseVault": "6Lw2ynQ2AYNtoGMVaspV48AFdB847RB9Y89KezNuYydh", - "quoteVault": "E2oUkcF31UeFpQGFV6GzXVE3CxCNdDFz5onwGgMkvTsT", - "withdrawQueue": "Gcmr9G4Q3cwcfV9V5MyUMei4e9uXx7ra8eoF4JU8iXUt", - "lpVault": "EAT2JGC456xKxY9x7x5VPA7vkC19SPYCviFVrEnp13Fo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4kAzx9Raaw4ZThyN7PTVnc82YP2gLu6xNmH4jHWWSR7N", - "marketAuthority": "GWTwmgstXkyY6jGNM9pXyudhGdXDfz4LW6DoXGnu1WzA", - "marketBaseVault": "91ruDchktuVnHMSxzt31PYAg7p6XzcMLH5Ry38jz22JD", - "marketQuoteVault": "HX3t2Wep2rwvteQCtzc81dQCWvQjp6VeB26iaGYJmq2c", - "marketBids": "3TsjopwKabFWxkSmKKjwzUu1wXxUKuPCQz9r2rrfcGsu", - "marketAsks": "6D1ukCBDeJGt7BRFW87GGvVx3vNDN47ktdChzSoY8GZF", - "marketEventQueue": "ERXTrAJQMozDZpZPG7kkXCHMTWhqChjoTLWKSTNUbL2W" - }, - { - "id": "ARTPhapAMWSDtqshUdRkmSxzWs9dok3YydAQDD95Jw3v", - "baseMint": "2NczZKqiEtv1CCufwBCLVRCh17w8aHAhvyGTU486KMo3", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "JDPg6GhJwtNs9p7aBP2tFGimre1wYmrQZE4xxYNowvWa", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7vqyWD9GitDE86UMBPmhLrMXHwnZhLUigUVaiQGDevB", - "targetOrders": "7pQ2dz2MuKKzVCgwM4uyZ6bH8CkbMZCcLxquRfmHbfwA", - "baseVault": "4gR4HiJ46DAtccGArSF3q6scNaDkaYjP9TaXZyZezTRG", - "quoteVault": "HXpcsXBVmNgHrjGBH9Kq74ksfNMJRhCUhcqQcfJFhGCw", - "withdrawQueue": "E8p1d2LHoQq3J1MijXoX1b6Df953Vr8VnKm36NYNjwhw", - "lpVault": "Ei3W7bVdg7weieD3WQ9ZJdd82aL66CgUJN2MhMnogrtH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9oiFDG7qvbntwADmDYjXayMgma2KzawZuCYzeYcAw6Ec", - "marketAuthority": "5jV9XF11oHoB8Sy4ckq1JugJjCtwt3w6N3tEDxKaDFJ", - "marketBaseVault": "8kNx4RsaNxguRH81L1VvgkLe8SJqFnGaQJX2Tjcxn8Qi", - "marketQuoteVault": "DkBMe4GbpT8cdte2s4vVJxz6JmV13H7eaba3C8fwrGYX", - "marketBids": "HD3VsHnheHG27chP5FV8efHz1Di4iEhgS3xFghYeXTfY", - "marketAsks": "ALmv46ShJZxGpJ2wpxfyBDGT7V9BgdJjB2e1iWqVHsgm", - "marketEventQueue": "5fVCJGVZDtDieHcxv8yYNJzaDJYkBgqTB3ppkSoPesAv" - }, - { - "id": "AsA4HchyP9ksD9Rw7iAEdVa9hxD47RtNx1ETuySbAxdo", - "baseMint": "GfJ3Vq2eSTYf1hJP6kKLE9RT6u7jF9gNszJhZwo5VPZp", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "HHGwTfzZ9f1wTLZ5UBFb8qmtnFo4ZuVepMEy9SZbs1Rn", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5JpDatcTjvzZ6ahuw4Jpv1CS2u23u6ED7wz6Lb8ogPGM", - "targetOrders": "2LToQJC4z8uvsKgPwvF3KKMBhky13spiCLBNFtFsch8Q", - "baseVault": "BezLgVouqshYQ8FeVaP6ipMPDG8szpTYzg3iYCJG9gf7", - "quoteVault": "GTjxREwR8aEFyQZELdur84sWopx5WDH9V2q98D8ry2Jh", - "withdrawQueue": "91KgeSR77iSpWy1a5H5XXrdbHygQc45KtRBZUEv9MBiv", - "lpVault": "nFhgydYXeoFBTavmDkDFikiknU6nmbHdvnGHr4SCioM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7T3LrFYUW6EScECJwGuePjFuHWR2cpaQMwbsH9i1tca9", - "marketAuthority": "4HLaPRqS6U6GJcf4orzUsjymeQLbNL6Dy9AqzHBXojAJ", - "marketBaseVault": "Dxyyv9KC44Tg1ok1EC2Q4h4D6PjeBhbfqRX5YTz53bzM", - "marketQuoteVault": "HMPJ6VQ1Ay3fUmGmDvXZRJPmvMfkiDNPUYnEUZeN7nYT", - "marketBids": "7kUvEu7QKk8rRYHarwUGpxok5wHuUKi9cq655wb8rTc9", - "marketAsks": "BPUC3Zh36UGMSQeVWs7bXy4kCzTEQG9KWW3F8KLgg2yu", - "marketEventQueue": "59DxRfjee3K3RL8Hz1we319xBKpac7bRwnRP9sUh39o1" - }, - { - "id": "AshzKk6GuVP56fVZmb4UBhWCwDqwTomzJkGUuZZE2iZ2", - "baseMint": "C6qep3y7tCZUJYDXHiwuK46Gt6FsoxLi8qV1bTCRYaY1", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7YeUb51SKTuHaudcszAmSydbU5gj3teguCxR61vZGm5Z", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2Z6p4dcWHhLNrcucThWqUcaCq15jwvRThBnZDaQH5Ndo", - "targetOrders": "CUnkq4qjvbMRbE2rV2HgosvUauYiaUydueSCCLTDjPQn", - "baseVault": "6qE1oeyLQRJxNZ71PKxuaDYJD1ZdmZs4LX2jygmw8amt", - "quoteVault": "HtemMwyDYhPtpR4YtLjyTDseKiSzA9qpS1hCo2JUGLHF", - "withdrawQueue": "3yqo9rmzjLtNEnYSfCfgEVgbAq78TDRU1fizuHhYxVdH", - "lpVault": "AZt7zDLGsQTSvvxdUFpKWr6ZriDbJrErfYfedMvXNMDb", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "C6y1AH1A9Q3Xdk5yxCj5XEQaG2mmXzaqQWq5HLhjpWiT", - "marketAuthority": "CMwkV2KF5wva7J4Ufv4HdsHLsh2N9nSthjDY9kpqEX5q", - "marketBaseVault": "3qtkLRvg8XsR1VB8KxEHUURrCeqWLfpRFYrH95Zku9bR", - "marketQuoteVault": "ETNYfGMDeGRBQU8aahYJUXU3HiAmbmoMZTCv21ozBwpy", - "marketBids": "D6w1kiDgLTa7i4TxkvXdpRvpSQ3rdg7QGYKEWfUVDBwu", - "marketAsks": "8eCvxaoFDJx1VVobTte9nfWpxYH1c7EwP8eVvhbkjcKp", - "marketEventQueue": "FKHh1c1bnVoe3KfaYH5rvQc5bXJ4vQcrDa68ak7bxrSz" - }, - { - "id": "AsiBPJHP1CzNH5THFC5Mm7iABsrL8iW1AK8GsAc7Ye2f", - "baseMint": "5dgSRQ4oL8C942K4qPBuhjkbTNHtfqHMADhYE25PmhPG", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "3sRsy1FLjwBantRCg6kWjTNFrb9SJFdsxEJ5a1JQfYYR", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CDEB951Xmk24xF2WAnsvVDRJskjUA3MPxS2mMeByLged", - "targetOrders": "DqqWwyEANo8cqAMt3AiUhyRZ9WCdAGE4faLc41cpb2sz", - "baseVault": "BwixqpEi9rkYDTqYMd9pdHYhZRKCb3TEYXCfqFhassVM", - "quoteVault": "4B6afuJRpdpsCLQshsExtDJ3j2PMuLciErVhe27ydDWT", - "withdrawQueue": "ARGszKKY46QeYTTDWBcvk5rYqLtjwjQeGHHRRANAgsfH", - "lpVault": "CvTLGfMfnCh2SYmnSqWm5v5kJchRsed2b6ZXq4G1wMmC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4sfA9GCXvDCane91WYpwpy45qX67iK3C2Sk2ZSzRABRD", - "marketAuthority": "Co6dEr8Bkp9CxzGTbpFkn6AXJgN3dPucNbK882USrZYB", - "marketBaseVault": "6otNF5kkhdcWjVVfaVFwkvNww8QkyNsoHJTEZmctotLq", - "marketQuoteVault": "DXmw1ZhzTNCeWJ3L9H6cPcmn483dwPpHsE8MnSRnhdJX", - "marketBids": "52V7Hia5jS9TXVUJYGJeNa9ouN1N6zzKMbGQq1QZowVJ", - "marketAsks": "4XgVefdcyJq59BU8QEuVArJsaDMiw55saLqbBP4bHwM5", - "marketEventQueue": "BrC9EHe7qbQrbT5iAkYctj9oW52sAJeadm3JhaEmtUXA" - }, - { - "id": "AsQxZ59PrWEKv6eD5aVk4BgvkEQ7mdEf87Fh31Rr9uNS", - "baseMint": "1C2EYVrwmoXAGbiKirFFBeDFDYUBHPhDeg9trhibTND", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HQiTNLcmxh5cUnsKFysvZjkcvLGpHL6fewhPYbDwmbA4", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Ac7oo3nPb5tbAzsvK6ydMMARy5c8C2MiNMyR7B4KFn2q", - "targetOrders": "4URCV97cDxGycjyXqk4EDW1s83wAsK8PoxqQ5YzrmZ5i", - "baseVault": "82a9AvCXqrx6rJuT1QfjuiZ9qeGWuij83tDbatY96BXd", - "quoteVault": "8QnyWJaURKqgu8nMxxLYFmAz3APPG4rK7CXFyoQAPgUx", - "withdrawQueue": "4ki6bEMeg2Rgh7L76kA3ikBY9tvqv9ru9i1kdtNRZ2NM", - "lpVault": "AnFUP5mUVHyR1LYYxi6Eh2W88Ff2R5HzP8xy63QVnhz2", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5JC2kckdehvq8k2JMZE9gJzdiyhGyg5CH4HN8gxwWSyo", - "marketAuthority": "HUPHvtZ1Z5HZNZ4pK4Qua1HfdJVWnWhohugDmWFd9A8o", - "marketBaseVault": "9GUYh1FvGkEN1neYYoL74g4dN1ciKkGN2eQSaSuqiacD", - "marketQuoteVault": "3Dag4UezckaK2DLjEeVaLUkE1R64nKUc4HQxxepHSW7r", - "marketBids": "HxGbH73aEm2ES2Lnod19LqKETQvP9SVDtk1GUz3Hq1KD", - "marketAsks": "HMuNE3u1WPquC1PzWLwbwXFBBFMrGU9fnL8Cgm3c1eUF", - "marketEventQueue": "aAHtXaHEUVBkBTPZwFYk3QXt4JYaGH7z8Y1cqH5GTr5" - }, - { - "id": "ATDqZvoh9gLHk9ituBNTVGg4DGRRqEKQrKEUZ9UC1WBr", - "baseMint": "HV8RWueWwpRue86SMzXQapxDB5ZEWw5YnVbxuDcihaF5", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6UMuJiRRP6WDj8fyToYxa1pEs1LNWoL3eazjtZ6kd2Hs", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "67g4b3a65SNhDLdRoUhbR2Qc5V1GVJnCMJxnbvzzFx3Q", - "targetOrders": "4G9HyvmW2BdTCgZsmMhQ4PEz8NeN3dvDuE8fET4bFFB9", - "baseVault": "CRHvR68dGU5DwL17rGQS12DB7vAKKKCKLkM3kV3dmTC2", - "quoteVault": "7oEsdFNugSJnSnFU5myvLVMW1PUJ5RCMPRGTxF5EUrEz", - "withdrawQueue": "2fnpwRNiWNdo29FwiGYqzLMtaDg2wdQNbtKFMixWJ3ZL", - "lpVault": "4fSgW35C5AvBKVyWAscefPuHwNoYuEnKbx1dWcXj3RER", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "311Wt1nAVEprvwmnHUavskh8NjDupJDfzpmsnRp7N1Qg", - "marketAuthority": "4mFm1yYnmo8Q72mu1SDRPxkJtDxnz7CzoAT7QDXFE1yW", - "marketBaseVault": "6LtijDzn6RAVxsbhvWdzZkqwGbRUmGr1fTmbbjqLHWpj", - "marketQuoteVault": "BnsFfkUGJxttaAFZJkMC46TPoNxUHbJ2vjhUnMSFERAi", - "marketBids": "EXZgdzfzEvFqD8aofF34TZE4SpmQyMyXuqxWKUnafWU7", - "marketAsks": "H3NTXdYxwCK41foPpno1SrERRH55ptjDf7bCbC23EwGE", - "marketEventQueue": "4TH9J1GZUHmATWKTzjbPfW9KNWiM6neSppz62UHRa3o2" - }, - { - "id": "ATKUQT4ayyS1dQNLqnVBP59yfZQiN3shXgtjUdm58CfE", - "baseMint": "3e9pHUxa2nvAqso2Kr2KqJxYvZaz9qZLjoLaG77uQwB1", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "75juLkKjEk7qfwYJTPCCSYB7hFWcKF2dmFMNTMsW4Q45", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "G7Rhpa2X1RQNWKs8pAspmE1q8DBhJHKRmwt361FPd2td", - "targetOrders": "ADjLEqXXEWP9JjcYq32psVrQDLfF8ek3qiPr6xSrGuXT", - "baseVault": "3asxFhPFYhrnkbmm5kgd5xsgnuzG2mUMeQbTxFTtLjnA", - "quoteVault": "8qBh1HkpYUMRGcqU6zfSwAKYiHBz4HZkrXHfNmGDFEVU", - "withdrawQueue": "2q978Bkr1mjeUhzaTEqVDfXxu4Z65h39xjuiDTJLxhTV", - "lpVault": "3K34No637EaLfrFPhzvua4yAJkcFAVjUkeSQCY53w2Za", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3TRUem5C4hgJCmPB7cavwnRg448mkd5Y78ebKgFdaV8n", - "marketAuthority": "5zSPxoMKHtprHsgcCYFW83CYCoUYU3yJaeVW5qWhU4dc", - "marketBaseVault": "9X9mpD6FEzoTLXAbF5TmCs4kkjJqJq3sCquUCsXvwUGw", - "marketQuoteVault": "EvYS2nv7KsoxcZP37x19PvnM7PgA5Q2wXGUN6ML488wo", - "marketBids": "9rYKSRjFryRhVeADWno6Lb8Yq1vYQJpEAx7jLbuidpWG", - "marketAsks": "r6i6dDU3BMHLQbaw4Sw7fr4r3jnLHed5agjgveEBVub", - "marketEventQueue": "J5G75QB6TEJ7z8iBHDFLvB1v3vjV7mjXLeuT32jriLkT" - }, - { - "id": "ATttGHnhX6R6pcKg2FFW7FtKHzvFe342MDnzwM3zzJqB", - "baseMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "JCYTpvLv6G7dwpz2SC71CEj9EK4t6HXXqsko8h6dq5pu", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GKqCYW5gzLiUTKT8RvJ8MsCMhGL9zyKjPhuTD63XMyFi", - "targetOrders": "Gubobvr4EHgWYqKmZNvNmwfdEFEQ7ADKyGW7mztH3pzQ", - "baseVault": "9WffegRg3s4d7X65Uc3Kj7WFoH7XghX1rjS5wyAVKAdd", - "quoteVault": "FA1Js3nw8h3sYyk84STCpq7H6qg7ctZJ9udrk4q5XRgZ", - "withdrawQueue": "DPqovnGJEnfvK3urAxUZv5R34UJjUTrKbzMLNXZ6p99v", - "lpVault": "Hm2Hp5Pd1RrUdPF1A2SZ78gSW8Kwn7SRSYozrXDuidVb", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4sD6txppyEWDeFxGWjLDzT5ppoHMvgw8qYYFY7VN9QV7", - "marketAuthority": "9kHYezH6GfoWHyRHv5RZcet18kzJ1Fr8diCEnyMopsAV", - "marketBaseVault": "4kvAZ9FDFqT6A2iAgHcv1rKrAy5qJjkdBWDhx1cGXqU8", - "marketQuoteVault": "EQCAnpMfiFw5BRmAKFadefJZTmfvMdzkDN9szF8D8zio", - "marketBids": "B9VUm4ozBRJntGdLE4surTjX6i4TSZGL6fsd8ptdEaBP", - "marketAsks": "2WLtb8XJ7ZkhUN3feSkh5E2zaUWLjC92wvmhPf2NvDUq", - "marketEventQueue": "5K9EUtpBYuTQXV8MDDH45fMH2Wy9UYqCh4wwerguvAAb" - }, - { - "id": "AtZowDTfCYeny6Fbr23dHNVDf38rSJRAH1PGzFGAbsUW", - "baseMint": "76DThuyLHagfkm2ssYw6Lv7k3MYHx6tXcwPBLU9tXm4D", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6AGa31qSEeri9Vg3eTXthHt7twRsVKoLv2ETMvJjzVnk", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "B87P3tbgABNtBbiAv3PyUdMbSPN5bcUW7djD2hFMnqMU", - "targetOrders": "BKpRA4mGjyen3CMm4YBKfddiFSnhGcYWYqqGggLXTmqY", - "baseVault": "BfJPxUYQTeYHtp4gY3wue1DoYeRGfzZgB382r4RqNd6A", - "quoteVault": "9kYYz97ZXEXpM3kW6NSfS4JawWuXdnUdKPSa3Q8GqpRV", - "withdrawQueue": "44YXuakdgRVtddEg5fyzeWuogPd7V98oUbHsXKnMoXSq", - "lpVault": "3F9obgA4fey8pZmHdiHAQLkybeMC6rwWSMuaDd9MFN29", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GUhRFtTr9ngdAvXGtqmZa2nnhoEum2neWW9ccS8ggEh3", - "marketAuthority": "5HaCm3sk1A1Qc2kuaxc4VRh9mfc1UPNKn3fnD1afrf5x", - "marketBaseVault": "H54T57yM18G8AQkHGCoDknwxmdoxcMhpMDdZSW7YFKRg", - "marketQuoteVault": "5igUvNZ9ZQ7dhfaVPuaLFD8fVaSMFt6Y4JdBt7Ud8R6P", - "marketBids": "3GU7Fz3MGxQ8A3iKfk3bLa7WdiT98N5bFwBTWQfcJsyL", - "marketAsks": "HBPQxi5tuTyGibC6eoqoYNFP1z9iLabALKuawxa6uvbv", - "marketEventQueue": "Fv6EgZWC14gTzdghSv3SaaHAedPCNYrkHKYMtUF9CVna" - }, - { - "id": "AUF8FtoXWwgjc4Z9x7Y8YmAFN2Rimq3jvhnBDaKZ4zcZ", - "baseMint": "Aogv6j1wWiBAZcqRNN1Y89eozda2ke6rkc4CYy7c4iCi", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HrcbqUXqWcSE3sr6iUJpt5UH8cZBD6msFrVZatUQAYAT", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5LLsbKKZikwiYXMqRQqQczQg5BvF2iZxtSH93cngNRcm", - "targetOrders": "2YXEUeBcGXm7p5rjgu4kjysKmDaPvpMo5CkdHcbLxCLf", - "baseVault": "DhxAmMhh9rp1dkBtgZ4PLy9GzJB4cecTgd7D7cYuPYwT", - "quoteVault": "CoVwJcEgUKxhan6hmkB371xP4wCieZufancxrgzh43EP", - "withdrawQueue": "DxToJzMGZHVxvqRpAus3ZwVjQmPZJwa3ULZg3eBBLF9U", - "lpVault": "BQTdhmLzdAz6jpgjEExjNF3fRnAzZJC7K2W23W6dpqea", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3tc776fxiBNuEzr2JwrimMdUdayJx2qZ6BhEpJUB2Vf8", - "marketAuthority": "7YuRcQxz3fTwKvkUTTv7FHxj2vkGMzP5Kb4v2bK4YRaS", - "marketBaseVault": "5E1862D2XWSiv1eysiGhQwYsFncfGvppgCb3fj4Nf8RU", - "marketQuoteVault": "BBE56eRzikXf9MrKucDr5D8TBobb6m21G526zQKAZJgU", - "marketBids": "5nhFxPrrwSiTZJvT6tuwMWvvrVNYQYy9iCLXtLSMEC5w", - "marketAsks": "9PL5vdPx86nigPRrjYTHQvGyLFu2sku1ebH4Jgp7gTKZ", - "marketEventQueue": "UraPCjdn3XZTUsLbEfEH7thqgh3frb5f6Eq9hEHpVYt" - }, - { - "id": "AUMjVRrLKBBUG6XabeXPpmF2ZY5zuHrihzEWHorJLpzC", - "baseMint": "PRAxfbouRoJ9yZqhyejEAH6RvjJ86Y82vfiZTBSM3xG", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DR5ZPstTWbsdkE1UWaUgjvanB822JYmd1QcwCuqVaRYD", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5TqFDRDDTxq4ydnMKrjhpdWeCJfGdKbg76bgdv9HuTuM", - "targetOrders": "6QhzBbVFk8J9tXANwb2RHSqHe561sGHiMTfFjWh6NLzx", - "baseVault": "GK1ukLWGqU2cC7aRsApuDyRmUL3PpWWqdjjMK383ArBx", - "quoteVault": "4SE1KQ6hW3mfUXKmDCnZeEHf7ZCeH2dQHf1VoWfKGuuK", - "withdrawQueue": "CnkGt7PbBCYPqDYGNSg88xoXgJpeTw5NTiNqyankyGmK", - "lpVault": "DgdEoX4Jteyy75wAPNUiF5jgtWq7ztrBpjSw47v7rptK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BzvLdwDJPSNyXZCyRV1X6BVukS7PiVS8G7Um99ywhQkN", - "marketAuthority": "9MmyntnCgiaUb5Jg9FxjKCuu1WDCXMdpFSb85x9mqq54", - "marketBaseVault": "C6QcBiuTrVuyhqAqb3QQ5c7yyVzmccUrfPByFTKhfzbK", - "marketQuoteVault": "6tS16eZGnnsut1tWJqQrepTxzUWKdgA9UA1PNRpyGEZm", - "marketBids": "8n54MWsBALJH6xbpdxbcz11h6Qg9gD2XFTH1ULFud9Aa", - "marketAsks": "4wp2Cc8WBEdr6meJLgYCjMzHCuLaX9mVgqfTBYwBYErt", - "marketEventQueue": "AhvtL6ZRZ2y89fw3CEzVJk3BiTwVTe7wJpj35TKtdbFh" - }, - { - "id": "Av4S896b6NWm3aQUY23z8jsGPzyUsJR6CngeUeV1bUum", - "baseMint": "6naWDMGNWwqffJnnXFLBCLaYu1y5U9Rohe5wwJPHvf1p", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AgfLqFUUE6SCrPzNnYpJHwWWNVSgVRSQBF2nKqGjhvrV", - "baseDecimals": 3, - "quoteDecimals": 6, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AN5WckvqXitQHJHFZ1EXo4pQhAe41Py1dhRMKeNXBSQ5", - "targetOrders": "8qPvBx53nDg2N5XDbCUieZnNSZttnUinkGvDNHYueC2M", - "baseVault": "5Py12VsTnb1b3TZpNzW3yrmNkZrwQVkU3uDYsUwozGWt", - "quoteVault": "B2XUUJhd3rbenL2wBxevDoEPjCWdYLnLQJyp3u4A2sGD", - "withdrawQueue": "2NhSHXfvbrCBTUwZtgN9kJGCh3eDa3J1BmK1YCFHJWd4", - "lpVault": "Eaot2WcyV4czRXhkBcDGLLLkpwytmYcqLPKKjykuTCms", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GqC1DJ3xhVnYdAETnBRRYF3Aynhz351dZaefquAxQsxR", - "marketAuthority": "5nDMv9YXiqtS4ZuMmvmuWRoSRdjpFeBnzXf9snmmXXHN", - "marketBaseVault": "965BCJgPLw3uvRQQCXW5opbYUJtrayk2tCBRc2ENKQkz", - "marketQuoteVault": "A1iJDvPskxTDBTsNxb6NkPHWsKoLSQMYg71MuyDG4qrx", - "marketBids": "Dm29mH41B4BbYzfuoRwAASYPGBMo55rbqyrM4MY63Xdz", - "marketAsks": "ARFeuZ4DHXfLrZaW2mhCEJfBx7NERjZLgS4mURTNaMuf", - "marketEventQueue": "HfTeYwv464R6ReDEqYPEcUED5UU675x8mGf6dJh4PxVS" - }, - { - "id": "Av8bBcJXQ9BDoZQScQineMPQRYZgf6W49ieV5UaNMcJT", - "baseMint": "Ca6XebDSTEMFJbJMB6ob6CbMWYcL3GtJFsCVFWiMoeMD", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "HDXnziEvfmFWJdoUvuVs5Qzo1638BxzV93eWdu23sz93", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6xkWLsjFWEP6vq9bC886RCEwhUXHpWRaUn9BvxdyAR2A", - "targetOrders": "4fn6ab6VimS1nXZANbuNFTkn61jm62HZLAuTTseeCiFu", - "baseVault": "ARaoMEMZTH3q8cTn5AjqCBqGuRM7D2SKEEpraXTsKeCS", - "quoteVault": "4ek7fGj8FEMD4LE5TFoSFUm1G4BAbmJ7J3RKYmNhN8K7", - "withdrawQueue": "BAKBHmac4ttwZQJq6NHoN7pFz5qLLBMbMKtS4so7yfzB", - "lpVault": "4SiC3uptUn2FChdUCBRDYuctWNw5nizjWM2C3C22rkn8", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4aETy7f5dyaGsPJzLTXxgkgFR4C7ztjUTdumzDLQhFcB", - "marketAuthority": "5v5eUPDAwMeVA8TcCcK14S2PPF657zuPJ1FyvkzjvnyT", - "marketBaseVault": "HDixtqtR9AfdaAakfE18fqbhzpB1VQueH15hqb8cbkHW", - "marketQuoteVault": "E45E19YQqqHnYtPSnpL4TwiVCwRNEUj4hNLzxtoWBysf", - "marketBids": "Hhx89Ha9anR7PuFRbnPDXhvCBs4Vw7c5grNB1HZsurAt", - "marketAsks": "5gsKvmXPEQjJ8pYpwA1jv2abDNYrS5pHiGiy3CxV6k7n", - "marketEventQueue": "3ynRbnbpdNzuYNYvXhmqfSbHE9ryVx9beToHKAZqEwnG" - }, - { - "id": "AVgXTM1uWPwpcza1Q3d3UBazSGJngGdp8QBzd4kwmkVf", - "baseMint": "9BiqBycZWkWH21vYqCbu2bL1PjZbR5GxWGA8LQkShbyt", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9co8ZNvNRdZQuJWoTb7zbDdP8vV3CzHuZt6BK7BKvF4n", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4ujuW3k638wMX8NWsoQkTK1CApcJBYCsRfqJzSuPY27J", - "targetOrders": "24rMWh9hNfF8S8ubiQuwUiY42dVMFMYUSs2znDWSd88x", - "baseVault": "69H2GxZrVsgDCNqCyqMaMfaxttFFT4k4ZfmKkGFTfojZ", - "quoteVault": "Bqwjsv1gUmKm2jks6rvSnBkVxaQUJLQkkxy1hVFF4RuB", - "withdrawQueue": "B8DyWJZhtKMcbjFm1yDu1dCXMbrGG9vu3heMoESRcoPk", - "lpVault": "HxcRL9DnW1jAjofvyqrvWAW44T8B2DJzKoM4hvTEXvn1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9xTPHXTEnXC8eqmtDntDtKLsrq15Kbwy28ucaWJN2qzH", - "marketAuthority": "AdSRMmynwZidTooWnpKruEVStbT7LZtfGK7rzDMyeRfm", - "marketBaseVault": "HbdqnRoFx1fTw8rS4st1ppFxt2xRqnLjqSJzVcp5xvn3", - "marketQuoteVault": "GH3oQ71YvsWKd8LXF5fSUqiE6oh1xzD1BeaxjutdwwNj", - "marketBids": "AH5iiMkmU6ZLNcz4Aj6UVRgTwNGXGA3Zr4X8CM82AVyH", - "marketAsks": "AJtXdZL9crRSwmXPFnEm1p86TeeMyLAWv1umGhfcGDvH", - "marketEventQueue": "BdGqFxRLkHqSb5wPSMBoE2utQiPLWRsEGso6Ycxj4WpH" - }, - { - "id": "AVhXYnHrmRB8SYjsqPEu8Mdk6BehTHv7E2rvxgCXa7k", - "baseMint": "BLAAD2QLUgRSbQ9AB9jqAoHh55cGVcSBaCH9JGBh2zDX", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "F1HXKqNYdCmgbPhyBCQhigrBiyA5zZgy6NNj7hwtsZtw", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3ZgoBjnXhyPCLeb71xGd9EBf1JELt3kBDMceh23dBspR", - "targetOrders": "5A5drqdksi2DkctDYjthEu9r7VK8h97vUujNRbQoErSU", - "baseVault": "7Ry951HqGyQTYVQjpEr52BCpByPQE7fB67XPRqWJTphV", - "quoteVault": "4Wr8QfLXxauNWHxAuBLDTbnYWpXBsXdf1qzyRHsmvxS7", - "withdrawQueue": "35PZjg9AqpD5Nj4itVcsRuujLDXutYNAcqQxxvziasE7", - "lpVault": "HgkEF9NxeQzdLeCrujyfAJffd2x15wPzt1WpPScceCXG", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HFEFkKEwi8zQNPb6zzEp7rViBEpVZfAF9Nxyzr1ei72b", - "marketAuthority": "J5aBg19mZa3S2AJCVr3jcBgDKmyetBYTtdQyqGHX5CN7", - "marketBaseVault": "FXteU7YswUMMnKDFbcdqSJn7DCqUdCpoHQu9YLis516L", - "marketQuoteVault": "H59qRKYb1nYVdpKWDv1A6FYLPxaiqDLrVS5xPEg49dYn", - "marketBids": "5MAKhZqqBPAEU7WBhckCiHEBGTUrCqFsAd8Wpui5EPy1", - "marketAsks": "Bs1C1XkqRLymaRVhXS1S1TWXXuWcWnScQxynyMWdWPwA", - "marketEventQueue": "BHujxocKk3gN3a8qW9Rh2mAdpEV252uxUsJKLEkqMA6d" - }, - { - "id": "AvreMagEVCmJE5rEnUXQ9RDWEgZ9cEej12prY4iNYEjr", - "baseMint": "Ce3PSQfkxT5ua4r2JqCoWYrMwKWC5hEzwsrT9Hb7mAz9", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "ATyS3Yj31ioZ4eXRVkuNrNRZhGZ29CJ1UAUuBjquBzZ7", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4JAy22v17FGtbXindnU5yQ3vbnJSbeLL27JBrXT3zdJ6", - "targetOrders": "2GkudKCH2FHZ2qBbax4fH74YSd2rfuV9hMSuhZ553mT6", - "baseVault": "9Vo1JLWRRaubF8YEpcLNcBovtrNkYnNcdXDBMNUhRbgd", - "quoteVault": "AzuKQFSUxiWhJhafj8CsGtcWbq54cBLDsTQMxNqdRHXj", - "withdrawQueue": "9M8Py9qcFVZu7NTtC5WgEbGbdcPVMCb5bGvXcLJk2UAC", - "lpVault": "Cy8sYV7eC3VHSmoMsVYKJ8iqFKxpezKPLpwzx3UkczVm", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3jszawPiXjuqg5MwAAHS8wehWy1k7de5u5pWmmPZf6dM", - "marketAuthority": "6MSY81TyRSZEdxNJQ7WVno7douW6e9AV6DwkDRVT6QUN", - "marketBaseVault": "9LrpyxzRB7uGLF2Eu8PBjLKPtQMQkDfKsZC7MgydiTvk", - "marketQuoteVault": "AFKfsQKPhe2DocpATdQP4f68PCq4PTj9wDz4GogPkwxN", - "marketBids": "8gTcVqcAXLm3pqr7qCTM39QjqeFSHCWdhn1h7aH5sHnv", - "marketAsks": "ARRPvDKHKjoyT2C6o13fD21hryGovRBBNzPH2zi2TQB3", - "marketEventQueue": "28kLGyTz1auPiW8a3dUpKXGjyp23bkAN2QW6DA8jdjZK" - }, - { - "id": "Aw3dR8PpVxiJ5MqiUqyzm4dugXCRAZNLbnRAzcM1DXEj", - "baseMint": "8z4ghJPp3ccvEtuXZbceGRfoX7AZHhcdwiapYzmsxmyC", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4sMGzdJDvSdpVt2czeGfN8QB57NT6ePwLT7ogFewndGT", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "45C6zM9aijWHKouGwTvtCDS4hWKhmiQrTiJG235yTDe3", - "targetOrders": "A18i2HgD6rSD5nCHXTjT6MTxT5qizebmLt21GpCJTf89", - "baseVault": "2PQKT9cuamhzHavEha6kydt9S7snUTKv7fUgcKLfysgb", - "quoteVault": "DnPSA2t2oZcMKCQPLt44dzudF7ZSccBfrLeVfeqb3hWL", - "withdrawQueue": "a1Q48b2bB2uNnF6CMUWpVADG28uDnpTeVKzVvqpt7By", - "lpVault": "G7n4ebG2WbJqpC7fffPNBktjqa15asDtc8sCtjCcCHvj", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "F7gqqDC57zCW7swweYGqhoTaNtEx4XB2J14jiQ6hGfTg", - "marketAuthority": "3QcPtszrwMmHF4FuByHT6qsvmvBowt71HuayP8T1vJ72", - "marketBaseVault": "B8w7xvLfEE79A6MnWpK1bcRX2wmtW6vdGAUTCi2QVmsx", - "marketQuoteVault": "F2TYa6ZRaYQ46BpvCYTjdagN6UbdPK4QYWVyPP2cL1Px", - "marketBids": "2brUTFTWSHc8LswnnEyNcWzG3ep7Lh2WSMBGSip5PVE7", - "marketAsks": "B9F3SbhDXk6fWNoc997JxS8uuqDFHHqLUSQ14buJKVew", - "marketEventQueue": "AXJYVsknLNJjzSQen7VY3fsMGR97qEXPovhCWZSciKj2" - }, - { - "id": "AWd1gzvtHSygqYtHewb6QLuiKSTCWWp4bRZNkWQ1AFXZ", - "baseMint": "5KV2W2XPdSo97wQWcuAVi6G4PaCoieg4Lhhi61PAMaMJ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6FWPtezouDiY3WJaAQZtCmkmhtN5n77YU7nZ92tRhd8E", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DXymk5jZ8fbeVKVvaBNLjbiZ2zRgQKvjfyxd8rqWfRFn", - "targetOrders": "2KgAGNqKuMj5YQuDm5J4NZjS26GCS8XdZVb96KrHbEmi", - "baseVault": "3VzRrJnkNKLuwZejhxh3r1kqB9iXzjLaVdQroruRLq9r", - "quoteVault": "ABERozY4GP5fQCps9baF7rmSeVNBPjaCAYTaf5SMHz53", - "withdrawQueue": "GWZq7occMKZukU3rTJU2w836HwUvynEV9o78KPLSJePo", - "lpVault": "J9hg2UTdYtgDqYBaLnNJKaYvZSou9e7cYnA68sa9Az32", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2QXXnRnSBi4tviNUAsYv7tYDvYb17BQhK5MxR4sX5J3B", - "marketAuthority": "cpBCGQoaMbLiYqQui1qCc48XNkc5KLWNhGEp21Uf4qM", - "marketBaseVault": "GsrUykppfzzhUxRcRMWmbj8oRNy5CGikisWB8bWiRieT", - "marketQuoteVault": "EgXBu27PhvBwMMqnBtVH3ZGt9LR9MbPueRLuRAHYrnWz", - "marketBids": "6sVbjbAG4oamuGw9hfqARLPa1ipvPaBBko2J36wqfp78", - "marketAsks": "4YJhQFQbyjJkRK7xp74kHG8CCt879Lyj7jxHwonqEonn", - "marketEventQueue": "J6SCah99q94HnGqe3kUoxeZVpgE2iPb8zCdRiZWgHks4" - }, - { - "id": "AxFxfThs1MCmBgW1qvJ4NFtwuz1zLoy3Ah9hhPpeknee", - "baseMint": "J7WYVzFNynk9D28eBCccw2EYkygygiLDCVCabV7CupWL", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GCQhi6nk199J2rwvyHwqKeLZGgsF5HnkUTLJWeTb44iX", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3nzA5vS4SkZ13hh2MgUxMZaqmAbSAcMehvrhgm6pjLuL", - "targetOrders": "9NcCQVSc14x9gh62Pswom95UuvH8EYzfT7HdHyTRjQzm", - "baseVault": "8bCzAZZarHDbCbrY4UGd7BdwT5HhiVE7bgH5nQsdWBRw", - "quoteVault": "EnZbLYwd2V2pd7qaW2Hen49MMfUupBDni6uECDwTG19V", - "withdrawQueue": "FjqTDYnRprH1szEfa3iKg1kJPBkPjtAsbi1HCMRX1aNV", - "lpVault": "FZduhxWhAPKnaYVy9AVuG9HV882ijKYEb1VAoY6rzXMf", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9d2NsCGUidYc4b4JD8vc9hbhm1HdTfGpCByUAUakGHCB", - "marketAuthority": "6CvZH7mEZLmUzZLgbWqok7gunL6GcJiG2sSYB485LkHQ", - "marketBaseVault": "7uguJAiYEAKjxLnhaS76ky5ZCUbhVf7y3atn4vFf6EbY", - "marketQuoteVault": "DrmCJed3XoVXPrcF6og6D5yPGkV9WEu3fxDkkC23Wpre", - "marketBids": "G2BhCTp9cDktcYQSxWL3tpfQ3LhG5QHE2bEfgayFNzcE", - "marketAsks": "4rRB3f8dbfp7orp4S8Nk2GaLAGeQwgXuiBRDa5ZguBSd", - "marketEventQueue": "598zqJo4i8oHusM8uPJjLUHDLUztTERYLPHuNDgvPMbi" - }, - { - "id": "AXVrmQXpUKPFJRFq3fABivmkKU8kLMoGim65t1D3ZxDF", - "baseMint": "BWm92csusaUNPWu8M2aC2UTcGQVJsrhH7JYtd47zN7FA", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Az8tao2f6Z4y6Jk2RMvFvPV5Q3MR3BYsPyKJbpgDgMaH", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2NfUAszPvwqEv9ZEASt5xHjNxJSzzk4CYs99zXHj3M8H", - "targetOrders": "CZay5SNAfdKw2jrX4g6L1B8oAMF9q4KKK4LJmnocMFAH", - "baseVault": "A78c3prUoFksmSy1eHLgv2Coph183m2nNTooEA5488LJ", - "quoteVault": "AHJoS8x1AximwYNW9Uq8VhkruVm81d6ADnf3ENCkpMs1", - "withdrawQueue": "BTS4Q87FDse5S65Yd2uvUChzSfz1TpbSaFuYyNea3due", - "lpVault": "EGtqWcDpQ9qmHMAykrYnn7JgYMCG9y6fzpcctEEgynH6", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8GuddsKdraMfBiM8vcXrkYqMTkYwXDRdcKKW9xBFBDVM", - "marketAuthority": "7ZQJVG5mDbFibADkWrNYYWC4bxjRsKGSFt2JGXEeoW7D", - "marketBaseVault": "9kATk7uThKBe84pJdSqoL4wZ7JHQMZf9JeFYc9rx9P3Z", - "marketQuoteVault": "8LWBFr2w2WyG3URvPVsJ4ufa36ahqmSjkDSvkhsTHPAp", - "marketBids": "R3aaqbEVjdrXAVfiq7ozJVHXz1nPxRw8Wd9AGaRxrTf", - "marketAsks": "8QUnpDg32TxpN7NshmqVE5qducHaJ3f8FYmaKMorNf3G", - "marketEventQueue": "HoeUE351xxP1g5kvHCyGbfA8DxxyjDdWzDcjVqagAVJE" - }, - { - "id": "AY86tR2o8Hn2A25AANMqE9bS5t2Z5xBUshBHhiXCW2Kb", - "baseMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "G4CwoRZpkrZX4bAAEvkYF45horBSBjrx2z8FsWAK3i9f", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FzvVt1T8aoDPCPiE6VEh96We8HKm4wLjv4LYefkB2sMy", - "targetOrders": "EGbfMVkUCeNM7e7U7RiufsNRjY7FgU8myyryfLfjR36g", - "baseVault": "8yQvrdoWhgGjBwsfHkA1XydcwUmbG6oUWUZvu3aFimCu", - "quoteVault": "CAWy66wmUdrjF1gX3opazuJsLenXBkT1FRBwY8DyMps3", - "withdrawQueue": "EmhrbFb4abyzNuNQs1QH9BSL5QZd64hYNwpJi39cv8EE", - "lpVault": "5dp1YH2w17FGnSWxRjumSJZiHeJjpXKRJUBS6yKQWxac", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7EnDHMhsTeJzdYGqfWbe36hjwz6VCZ96xFZHJ6TiekBv", - "marketAuthority": "5y3A7tcQGTMVkEqM2CfCXHR32tetAG3YfxztiBQ3t9XZ", - "marketBaseVault": "EMrSHHSxw4hzQV6rjGRaN3MinpZEswEZBXTF9ZTG86V2", - "marketQuoteVault": "868LRqrs94zho8DaCVSAGrET9G1er1ZCU5DmP1hkqUzL", - "marketBids": "FV7MX3oS8WwhBwHWwR9aXxHGAZvt1G91V1AxTERZ1wRF", - "marketAsks": "9m82w4n8JSnCmPdsS6iCQKJ4bCahomg9utAEQ7GDGKC7", - "marketEventQueue": "CsH6oM4N15b4TYEkUa7FNcRkp8oyajZSRJ3vkdaKcpYb" - }, - { - "id": "AyBA6QeP7F575b3rJDaUXwdyRLouaDKuEh1EH1C7hS9A", - "baseMint": "BNTYkJdHkdP9eH4uGouRkqz9RifYL8knHVVVmBMgcNzx", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "5wJWiziCScRnNuJMZNcXNszaugCGqBYnYvbbYfG3AM4M", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8ghn5JohnYnYe8eriEi3s82GmkhXSXfgYzAmA8GrKHL1", - "targetOrders": "3f4R4dBXQ7CyHc8J1ctqhrLCVrioeJ6qFraZRCnA4kJA", - "baseVault": "8zbtv8duKRBVrBa22Q9zep4QBz7i7izZCrJai3t985EE", - "quoteVault": "AVyL9W1SHpvjzb4g33sYZ62ztuqeCm89HT3ghAtmD2w7", - "withdrawQueue": "FKWSDpfAzZpPayYCUjk6NAxefqp7eNuijpt12W7CpyRm", - "lpVault": "dD5iUQZMfnC8tiQKjoA3n3fPEDUwUqFPmDX38QmAeey", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HYC4AzvMvphd4DtKXSyLww188qCZrbTXFjEqDShe1GgM", - "marketAuthority": "J4fxrmJUVWn78Rd847BRMyU1DPBwgJKVtdTfHigZBmir", - "marketBaseVault": "BsWQfrvLtARJq3xcK6onx8c7CCGBRsoPJiNBfvPd1wJq", - "marketQuoteVault": "24wyyxDhGMPjNLQaun7jce8SD9AE6qizy9CQb7ewTDB9", - "marketBids": "2Dc8NJazuiBMwvkZuzJhTgVwL2z1ZVoGLhm39PGs7U92", - "marketAsks": "EXo1KwUF5xMe7fkfFGE3GiapXQDSeWoYh17op6H83Mgr", - "marketEventQueue": "Fe4AqU4uRqWRqqkgTchLoNe8frbQw5f82etuPEoMsgzV" - }, - { - "id": "AYCHSXE9xKCxmVv3wsazD4WjmejaTMyaiJw8UAtj1Sud", - "baseMint": "3mXx1bNiB5bhgwznk4eeqM9eoy6DU3CeCkm1LPabeoEh", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "GcT1Kshd5zQo96ny51rUvFYgriTK77LetxwJ5TdnaqbB", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FXJA3zKfMiWKhWSxjT7UZj8w6a9oJQ2pmCfdqB5bTFY4", - "targetOrders": "A4MxeJrunVHoyvTsQv1tAFjrabDnt2CAeqjSFUWLKY4K", - "baseVault": "X3APJ2SFTnQm84k8GaxqNm83xeDvekG781gcqniHTUb", - "quoteVault": "24fUD7wVBkhrV42J2qH6DkQgSCs25nXb3zi8iSDDck3d", - "withdrawQueue": "5jSkiGBWXFL3vkbh4FtT5HtxyZDPKZQ5nfTj3oERVAvc", - "lpVault": "2hSGhUUK3TcMGHnbgzYHgs2f3cKVY7KNS9CAxGd7DzHe", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DkZQ78JgUptAHGrhwdHb9WfY7ArG4tZ9t8eLuLGUTPkf", - "marketAuthority": "DoZ7fTHGKDPudzUrUKCXdspK2VahAUaiayKfkzS3hrdp", - "marketBaseVault": "2F7mCAM12oWF2eg2zJemfcMuNmphppqUU4zCdzWrgw4z", - "marketQuoteVault": "6UjgXCt69dueciCNo2fWDR2yUwWY5YmcLy61XacFQwb5", - "marketBids": "3Hb14nuKxtEzHP87yKNscp8Eqpe26mdjbWAqDKLP3WdY", - "marketAsks": "CpwJpHWeZR8RnATTVy7c3b3ebx4qrbNR9uHAm98TWYJ6", - "marketEventQueue": "FoaWAa6RyE6HC8B4ShtxYFQANcHgrLxg6ovVzQbT9hPc" - }, - { - "id": "AyjapZWrA2BRKWpTx94x82Q3LNP6iy8TdYWMnLfyaNGH", - "baseMint": "E5UNCyiF1xrCqKozyFuiBkYH678BhftBo8Q1GreukBq3", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "9GQvvTtE6TcDqye9dntZgR7JpkgGWTCnUTxU9JB2hP6q", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CczE32wE6qjdDkwJqA3TqMu1pDXMTEcSM1DY72kk3V32", - "targetOrders": "rFcGSgyHZC8yfmCdYMBCFoJw6YZkXi3MKgbb1rsnGTq", - "baseVault": "DbnH7bYsrvrkaQMh2hpxGQ3zjXEgHQo7u57qdnYyCCNd", - "quoteVault": "2gfQy2KtDeTkwXzxBhf1qspnFKnu5Bsq6fcResWFmr1H", - "withdrawQueue": "647ADeE9xyA6L397gA4ANKUoFQUNu3s7ozc9if8UufYR", - "lpVault": "C4tvLksu1VbD3MPZh347Fo567SBe61PKDbhCNsg3icqA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EiuUwdaybovRVRBmuCHssUk6voT1Qi5H2zUsLphe4J89", - "marketAuthority": "6snLKLKBfw56AKfqWWWhRLB5k8wNqhkWbrTscgRdnYrQ", - "marketBaseVault": "DWvex7eqxx3dyqa3CAcQGP3os6L6xKhMfPivsffCjkLj", - "marketQuoteVault": "FeFMqdK12h88VQtdpivq868Gv526K4fZGVYGe7TM1MdH", - "marketBids": "KmuJkoFqdcV7qyN99ERnyjvDc8GuYbXSFyja2K5tqz7", - "marketAsks": "BtQ3FdH6hN1azBMWB9JZmyic4Livcy1vbXMgpVH6PfUN", - "marketEventQueue": "gsewwJv2U9NtgoMxZUfrjQM3H9PURYXBxE8DhwzKRBH" - }, - { - "id": "AypBq3Vux8rSpkjrD1Rpga6qCj8wHB1aDE4xEHkfyEXz", - "baseMint": "52WyZe1pfobyq6v1t7KAKZWePcq9Aj2Aa5kJHuF2KHDM", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FaHg87MWxuf9iBjZieWR2f4YttDyWQaamzdm7owueZj7", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Gf3DB9xtNy1Kc5Tsi7ZF4yRdhM7TLSZauyJAcxCSo4is", - "targetOrders": "3kGzQcFdWhtLkZQZGjK2Ec29moUxuqarU427kHeeSZ4K", - "baseVault": "BUiLjUFN8YWNgztWgXoXe3QDvdWnZP7kKKbmBHT3C1mt", - "quoteVault": "69jQPyUH6iDThuKtn3GKecR1LCL8REtasFPNz4Rs9ek1", - "withdrawQueue": "9DPqCvKrzUXb1HuhKpWzuxS8B1b85fonCabASUys2ibs", - "lpVault": "FfeAQqE6mUVQM8CoUXTR7ByCswyxzkbT7pf8jaEJ3Gwf", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BCqJ8MbspCrJadJXUTtw76vfs1XPBB36Uc2frW7QcggH", - "marketAuthority": "Fxha4uwYVJqEjRoPaHdBRShNunZ8qLUaq8tB6xniTAZX", - "marketBaseVault": "SH6kb5MpZdrfsa6sa9pB6RmhSPauKZsCNbF933aXipd", - "marketQuoteVault": "8qxGKgXsfbd9FBpBgkFsNp8xU7Zc4REQzRtdxr3SwQKf", - "marketBids": "GdosBZqrRw7YaBDXmcDS6t19NoYLPeZ2GwSKJrf8f2hy", - "marketAsks": "6TALL47th66YVdaMpTjFqu9tmEGpn234yAFK2PyG9AJg", - "marketEventQueue": "9AByBwUvLERrFwFTjMGsZxc1d3y38yX3UE9q1gDyK5Ka" - }, - { - "id": "AYUfGWr4cacUwqgWS4dZ5UG3U4a6RMdYLPMUer2VZyHt", - "baseMint": "GfJ3Vq2eSTYf1hJP6kKLE9RT6u7jF9gNszJhZwo5VPZp", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "Bdm3853ktQoWt769eUGg4Nz3xTi9sogDYnex1j4GMKtJ", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Ci3fGceRy2QkZBoxKpqYB9FJR2HRKRmJKno7Z1WYuQ2S", - "targetOrders": "4eoLMNMVZHnSZ9okFqaSC4EK16EFEpEKdGNXSXcGByJt", - "baseVault": "2rsRx1CTK4CQd8vVdhtcyPfzEs9e2Thha7VyuutRDB9G", - "quoteVault": "fQDev3P4GvZ43jaPuxx1kJjLMoMTePu6weUE88Kg4yt", - "withdrawQueue": "2Snf15d1FwGnvvKio2WoKwUyKPbpCFi3B4Rq9JJUK6bu", - "lpVault": "BnTAWHuR9KVUHY8xWkrXdSfzqT3ekuZk9TPvPcbEpMBo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5iVyV87cLSVu1f25uTwMKwsxKy5VhNCDryVMMqU6vGYh", - "marketAuthority": "5KGdyhZRkFWHz4gju2Yba7YD5bnc9FnTGriEevMdmWGw", - "marketBaseVault": "G4HEhMuwBXAHKd2AW8hv4sCvnFHSvtMpewV1uFFNfqa8", - "marketQuoteVault": "7TDgJyAXnLTsdUbJ2rNweK5JUgoR3YshyW2i3T8UbQpm", - "marketBids": "7o7XuRHozhwQvj1oNXMy6hmCY6JhwMZAiWGtkxJaNhSV", - "marketAsks": "8uBVxxF3yTGW2MQkn5AuWkk4HJyUQs8SHYmDcU5E7Dux", - "marketEventQueue": "8xEDs26upQL1fPMXXiquVns8pv5eRBjSGYEpCgoBgWZa" - }, - { - "id": "Ayw26cWLgBtJPPnGxTLCiBqZzPLPwAvLAwFfYrVksyDy", - "baseMint": "6nY5u2KWywfY6ERXgBBr6YNfBATHi13HT1fge64vCAKo", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6jQ4Jz2asd3PuiQGd2bj2bZTGD9hxbnTU2moG17KG5Ri", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HUQEc4eVv2g4xR9iFdU4adc5Ur8vqeraRCQq8QnDxhQe", - "targetOrders": "AGQmFVQ6V38Fj7jWYLbLGHVG9NgffzAX2Rfb6o8Y1hWs", - "baseVault": "AhDMYPUqT1Uo3f4MAZVy8QowWXFWntmfcEsWjHY14FkB", - "quoteVault": "6NSLxp6vbpqppDXFVkBZbLn4PeNBfqMu5VGykFiwZcty", - "withdrawQueue": "46w8qCyppGDqxiESGMTEX42Wx1Hhsk3YWMU4rsp2CEu4", - "lpVault": "8PsZD6Qp6mykwogBvfiRrhpEBS6CD5wZ1Jbnk5aKVGyb", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7V53142iBjfEa3S5TV62HoybwU6fQ88F86RxPsPAaTAT", - "marketAuthority": "DdfBWw1uagSXZwRRKNHoAKYq8C3WrF4YPhAHirwagYGV", - "marketBaseVault": "8EHWn2qoBWetA4XTGca4vJiFBQziqyZe7x89ENxY42uW", - "marketQuoteVault": "EugicBKuyhrjPQK6zQDxv8Z4ETLT9qGqxqD2SqcC2k84", - "marketBids": "EVixZxeNdQnHeQfZeymeD4YztPv3AQBexQ86ASMdrmof", - "marketAsks": "6jT5MmsspvyQqhj7GTWbw2n2LsUMY96vsuJpeTtVcWa3", - "marketEventQueue": "3rGEncDoFAJfQapFn8PeE8iKpv8WP6eUbwuYjfbcr7Zd" - }, - { - "id": "AYzhVyxR9gmw3N6MUtfo3M2wcgjqYCUbqfbRJ6eRCuWG", - "baseMint": "SUNNYWgPQmFxe9wTZzNK7iPnJ3vYDrkgnxJRJm1s3ag", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FYAXQmAfuTBrM9BGraA6Wh77BWk4S2hWEcZUgcy2WFJR", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GpC4kHroSd7AtDkaYPyxmbtxGpeBj2TahA856ptbF92W", - "targetOrders": "9VCdQm8cesoHHaZzBSPJLFaagVDS1o7yq7ovztGLtwVD", - "baseVault": "HQqmsUnkDFfUNDSupZ3X7fF24HKoXtkYB67PAt4T5RcT", - "quoteVault": "5e8o5t4yUFpKvLRfvfxLttaqYZd8awouvL45uPSsqBmo", - "withdrawQueue": "Bn8CKXTCy4rp9guPSQZXj4g99QhUuqR8yF7bNBy3myV6", - "lpVault": "BCXofRtQNZkjfo1MDtbGRyT8AP3VixH7QU8x3UZQuxMx", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Aubv1QBFh4bwB2wbP1DaPW21YyQBLfgjg8L4PHTaPzRc", - "marketAuthority": "2wELbbGW39kx4AYR8fwPVJk1CnnZd8VMjVsYGFx1RC9t", - "marketBaseVault": "2y6J7uT5eie5es3Wbh9fWitAuYbLDswXVsJmjMZxbuA6", - "marketQuoteVault": "98FiovcJNn4LmxTViKXLExBRgP9dGVwNacAZssrFVAv6", - "marketBids": "Ar83c2A3ZTZzbSKTLEMbqaZ6nfh3wyeCqUcchdEVDXJC", - "marketAsks": "BqQBkdfJeUUGnZRRbYdoBeZFeQ3puvbdv9R7GTSM5P4b", - "marketEventQueue": "DKjKc16WyYuyp2ZTSgXm5N9UsJr2W4tCgaUSXt7LKMUh" - }, - { - "id": "Az6nuGscg3ET5AENvuWx5cyTVPSPRZSFJEKfByj5RAz1", - "baseMint": "3fYegcDSmwvf2LwCkFdspS1ymRWzXTqmuAoxnr5VA3Jv", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FWWGLmCw87bfxYN6w83z8NnZYShnRBSHG8BBwvieAgrL", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7HJHAxhcxXe8RwWugcJ7Ab3xsCyAcWk1WDnD3h8iAZse", - "targetOrders": "2pg7kpEN9L8i7psi6oxhC4KKzVfMapBeBmnHbVAgJSKB", - "baseVault": "47hy155D1bSjHm2uvmpuBXnkNayKD81ykGaC3neUYvG7", - "quoteVault": "4Kr5xkGiGmm83eXi7LC2TcRCR34RdBk2QN3e1AQJdwfK", - "withdrawQueue": "HgsQGxzdGRnB7ZJ7YXPtK6hvFwgkJvNowQxNdwutBnjn", - "lpVault": "4ZT29aD2JJPYWDtGAGgnXxKag3HW2Do6NaCJDkPTjBnG", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EZBr6HiyYNs3c5L3Q7yK8sDCMT3W5ZziegEkLEBEsj6H", - "marketAuthority": "F1xzEr66pV1qwFMENVj7enniwCAW3pxEcVpHtKCCHLjK", - "marketBaseVault": "25XqCaoGamjaRZSw7K7mFi99A6cVbp9pCxcvGoXTgroa", - "marketQuoteVault": "BbFyRS6QZ2rCLsH49DpQUJnjkcQUzQdfJL7JCt81ckEi", - "marketBids": "GzwkJa95rEpX9rDJmcp2Uzp2pLHuHJTEpzRmJFDtbsTn", - "marketAsks": "3aVbt4RjUus91eobEKesKvBk6La4sjfhGUK6pShvh6nj", - "marketEventQueue": "7C2cJt9scYLQfSufQDUBc5uBNXLjo3qxFYhP57x7QCNt" - }, - { - "id": "Az7mH54TcBfGYBMsX8VAtcE9VX2BtzKEVN61H9J9Cmtm", - "baseMint": "ELADrKrvyv7mtQ5DbCvPDGogn4fcApH3jDeTy2qpfhsA", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7bFJaVrMTMkh7hXe1ARLARnweSVHJRdyx666pyHaW8eQ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6MfajMt61DN55h4D1abuJF8LPGumLRWxi9YGwVqAoCkb", - "targetOrders": "haihqHNYPnLH9eJ8PhroCyKrY1cc78wT2PGMmRLELzU", - "baseVault": "4Ftm5Ek8zJzmhwyuFABQhi5eB7jnJ9CwDzPrME8Knebj", - "quoteVault": "G2Bg1qkvks4cd3eEMnjVDSrQc11mhAGSvWgrMYmgSjXE", - "withdrawQueue": "7zdf9X4aXMmCU4K8EZ6skt5mHhC1VLE18iDwStQcHFKh", - "lpVault": "728nFNWE7iJTHVP9Q7hcA9kbjzeyhXGUdpscL7B8L4nd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Crxw1bdPQ549BfZs6iwZScmN2zZmuCA7wPvMqWWGihUM", - "marketAuthority": "CPNiArT9AgGXDTDJy3igpfkVkqSpdNCbxD2mtJzrFyzG", - "marketBaseVault": "qHXDusVWjdB4PX6eDbPgZUDrjmPqao9dFRg9BtHQexk", - "marketQuoteVault": "HaGR8qBPf9uyXXyNAb22qtXKdQkXxvrQy9h2r54gnz8E", - "marketBids": "9et6Dhw6fNBhzqPNZqAhBDwKKHYcwiSQ27WmU57FsUHv", - "marketAsks": "AHJB8Qzg51jb9vEt9XXSBCx1cu3T4ar8BVDBRqknaejR", - "marketEventQueue": "2sXF19QRAYVMfKV6G99N43EDzWaAoD2jB3CTJ6HFLGTA" - }, - { - "id": "AZrFHvHdrNzqxCPGcXWF9kUH4zJtAkscVC7uP9LmPDYH", - "baseMint": "FsAXvJ5wrCoSh3cQvdkuceUsQUjLtRcqgoikR9jQ9FBW", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EDhPLvmVrt24inQ6XVmkrcM8uDhZ4MvT39KF4EYVCVTq", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DDCFU95YjWUTHpTFWfY3PPiTPSE4mTPGGLWiNxoHW6e4", - "targetOrders": "A9UBJnUutyaZ9SFpNNMke6yp6s56iK2yW59oSLVwq3r1", - "baseVault": "DEKfF5sXPaUtTP4PZJQcdQoJdMwtzq9YEHDqg5ALCHXC", - "quoteVault": "8JDeFfZnhh8F9QshdBLMkBToZMcaAocW7ApHAc2WM8SN", - "withdrawQueue": "F51yEkkRqv9EHd6XZSoQWo3avJNftRaBF3q17zB92a3Q", - "lpVault": "9f94fhJudrCaKJpe5cwUMgrhDHRKoUFkANPKPexy6afw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6XQmHqqp6dxry2CSBPW6B5ucrM3F6NeUaU8Q4Tg1FZ9d", - "marketAuthority": "5JWM6PuLwdfbSWtw7Np8hXR7YbDMA25K1YEK1rrM61V9", - "marketBaseVault": "AkTRShE9AVxyTHjTYqiesojhYjRkSD87fmQjKqjezkBm", - "marketQuoteVault": "2JBuY7MHJKZSPFQyo4WXk7jyVkAGq7mAw8puewSHQuys", - "marketBids": "2u3JScwJrZ6nbLD8CjNrvNx6PyPQH5GajfNySyeDRfkL", - "marketAsks": "Bib7miNsBLQaQzeF2hM259TKRHtkcDz2vr3LkiSikzCs", - "marketEventQueue": "6G6ZQAH9hstTntGyPsr4UnEVmFMz8bPjVaeXBc2HYuPx" - }, - { - "id": "B1UdciQomov1GheBVvHDJMSitSAC3EKqnHdX9gXyBMdd", - "baseMint": "8fd5eUPMNHuyKRshFbfmKRAm2gowJ75m8WjT7tLio6J3", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6PHS9dwr21d238Ae67KSswgBW4jPpbT6em9ZNWQZaJvS", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BdJMJ7tTgF6iGXtHRBYPBQj9X4ynT7WB3ebDoFGqMtVm", - "targetOrders": "9KWc8eckxQa8d5Aotaj67c9zqZehrVo8i3SFnWwj32D8", - "baseVault": "6wstkFTVHKhVyA68q3wqAcPivmpDYL3qT55v8njZJjDd", - "quoteVault": "FYJrQbbVArrznyyfmx8RLeX3qtVASsra6LyKu6EqHsqB", - "withdrawQueue": "87ceRETooJC4XPyFxvBdvyUhSFdvBJGFEhusszToNCbu", - "lpVault": "5KMHivJnwhWSrRSxmuRrgeu7xHLfSG1dGjCxE67ZfBxH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "1DeDcStP8yLorneK4wnaLokRCmGxFiSUSgUwT9V2tgj", - "marketAuthority": "BCRLxZcuVY32Uc2QQe1tSSQu3mYttY57K1ArrHWZ38LX", - "marketBaseVault": "42wQf3DRUt3XNcgSaUjxg7SN6b1y1vW1uvqZHdcoLEDV", - "marketQuoteVault": "FwPLGUPtk3JiEuaQyG3SZ9B1nnAR6QjBxkddcvLtGCXS", - "marketBids": "EVREydRCUoGeRpApY1qqHHvJmX6ikk6Tf2g3UHwxM7vP", - "marketAsks": "Ca2N4gX4KDYttTn7BBiRU4P5fdG2dgYAC8brNPxFpCYW", - "marketEventQueue": "87G8YP5Ry6VEs3QYCfVZyC8YJaNRdERtaxhvQAKjFnA9" - }, - { - "id": "B1VygxoMuDxgcnbrJBFM5QZtquRGn4wukNof29aMb1fA", - "baseMint": "FDiJY7TFSjggVru24NNy3mNHVRHXHyg8q2FeBKYQYYq2", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "36CNHrCAn1zef6n4sWNhoR6wwf3gQLLDhq8LsgXeSb17", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7UtUtK5Rz2SZfMUMtjDsc63y9tXwESN8qWg6dGpSjqrW", - "targetOrders": "FDNitAyphnfnZqfZuFNmFg6amLAwqzaW5ZpMorjAagqK", - "baseVault": "9wArRjHoA3tNAjZYe19PnE2cHyQ38TDZjnw65T9CakUG", - "quoteVault": "73FH16ADBu9oUM6Ku2vK5J2HpaYErDWLRV3nz1RRF9R7", - "withdrawQueue": "2LhFzHw7Dw4qtunHTfKEkZKdu5DRCMJbjwAB1LGXAxMA", - "lpVault": "EgYiX8iyZwsFtf7X67aLFx1HKaFMb4EMJpXCwmL6d64j", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "F5nV32xQDT4K5V36VwV9u2aLzidE7WpBqfy5npmg4fY1", - "marketAuthority": "2vbdtpXNoxDoixgmiW2sqtcZ8VEGjMC8wxSWQvdMNja2", - "marketBaseVault": "39x7zLBhyqDhh6CQL2zYS9KmnsYS1vhkw6ZLjWRHpyoZ", - "marketQuoteVault": "AnH5j14LiV6duzWaCnsRFCyqU34SkEspMxMq8zEHerCe", - "marketBids": "5sVcvfTDxeaghRz8qQwE62Lprbq4yTFno4ibZhpUfhYX", - "marketAsks": "GSqEUzYQEQ7B8SYMT5ZBSASCsY7q7ug5rzyDDMxkqSpr", - "marketEventQueue": "DectrS56Gig25MUdNneKBWjQ1Azc9BJbtBPCjv1kuiq6" - }, - { - "id": "B2f9v7Lcb9KSeCXQPt7guKZncwJzheNF7JL5FEDzsZ5F", - "baseMint": "64ExnkDhpVwKzEjuqnkGgWVEtWZvWTG7JRyqQgzTWtFV", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9wbTFP32R6NJj3yfte5FWc7hfNHM64JcVBE5wndj8LKX", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GY1xrCWupPvgJfLaCybsDaJn69SY4pJuekXxEDpYYcPn", - "targetOrders": "HwMdBVE8DHMMHK5u4ft94awNw91gCj16NKpaK3Rt3kB4", - "baseVault": "2tDhb2m1rsi8YKomYojBkavBVK7c7Dq6Tjsg699HDViJ", - "quoteVault": "CScEYimQC17jai3YV22q5Ld9Vih5HMgo5pENQHW9NLa6", - "withdrawQueue": "FcAunk3HWjKd78KsZ9BTAEw7NH3iLbT3YE27RNsAqrCr", - "lpVault": "2G1oSdy7muUr6L3DpH9MphRr4QPmHUcvntdptCi4Xhum", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6AiWDPzaAyeTHjvFSjuixsfv47vBL5bKsQtPcu5fwtUs", - "marketAuthority": "2JGGgBvNWVJTMhb6gkU3Fz7rS4E3qanVNNud4b8rDteJ", - "marketBaseVault": "3xn8G9V3Ju8wmGHj6adSoRMWqZnsAgm4LspdRbiek45M", - "marketQuoteVault": "5RNmXKrJSWu8TFbdYymygp6niPxVB8SztpPX5DypgQFw", - "marketBids": "FqJUkK8zDTqvUfKKSv6cmbiSHaf2KHARTfGQautNhfhC", - "marketAsks": "8LvSp7PFgGRjNDuPH1zW7AiEb32bBxC7s8RFVPrX1M58", - "marketEventQueue": "6SFwPTHFbPohqf9t2JPTSWXysM9vnT3yVrq7HgFMb6sE" - }, - { - "id": "B2Qa44fMoguPtD1FwZiwPfvT5HRYscaWdWWTJddhs6NC", - "baseMint": "3WV4fTWGvtWNvQb8oVU4t99By8KztDLtExqHnkPfHAA9", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "A8ncHFuhwpPzKcNmEQ9SMJmzCn3RYKRPSZ6Qe8FfQ6ta", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "H4ob8DHQRdCJjKMCRYFTANjFK7teP4YZm9fnnuT4x5rM", - "targetOrders": "82J9shcx89ZARbJxfsLsHatxvhKirRtCjWSAZGk1Seck", - "baseVault": "EgD9ZKjcksaqwN9B3NGcjydknw8BJnogUcNCQP53VaoG", - "quoteVault": "D5m9kEFhHMMCr3n35HQU9FRFvBDN5W17aExsLQyUqA23", - "withdrawQueue": "EHaK2PFxH2485JyU7efaDeCsRVa4xtXiFSEwpwYpvS3J", - "lpVault": "HrHkW8r7uFsv7ZGJYamW8ejhQ13wxZryJPpVPTnx6ytT", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8VLEgk8PPL8xdTF7sqZwvm3Xm32bqPPQsgxfZwBCxLaw", - "marketAuthority": "3nHVUHTcUQN7TTkupL9kgMauQPqw7YPGXPkgJmfXisAH", - "marketBaseVault": "EtU1Nk4MBobf3c7CEd1Hr2NwDpssgxCZWso5zrrQ7XYm", - "marketQuoteVault": "79uCruY3FyYLVSgg3rFZY4pJyKB6Ecj6unVMTt352XQQ", - "marketBids": "DpLowTJssEbB11kjaKJTcwDcCVUpMh3jBRS7s1xSRRh1", - "marketAsks": "A1Qe5WUJXjDuoUr8AMthzDbtemhTsGAg6riD2aaPLW1H", - "marketEventQueue": "7PivcfzH7KWtPwZLn5oBXbaVBDcpJFpk5Ym1DzvRVGkz" - }, - { - "id": "B2thPyCukwYJWAWnZb54i4f9pKXtzP7mZLVbKXfhzMcM", - "baseMint": "WoSZYtctzp48xcdsSfGNKUGhjNdPx2qm5J2TUNfd1a1", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2EW3C7xzjNFqgZSPZdFZiWU4Z9gSjBbjQS7CVjcTzu87", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Apu7pw5RCDRU1E1jZYsDHvk6DABsLF66ixxTAz4m1fj5", - "targetOrders": "21Aa6tuMzS34UqpH72hEeh9LttN4aAQSo1e7jsMzMjHb", - "baseVault": "FUWyNUhzXNiM3fp99oyMD46VFvEqgD8jmbf83utj1VJg", - "quoteVault": "GGgc5dg2TXvr4b9ryHz3p9hqNM7cW4RsXnNxFgwgfdrR", - "withdrawQueue": "Anwic9LdjSAuCWkZfkn3MVQRtBDm1ucSN2qyHYGhx4Vf", - "lpVault": "67rSAN3CdvLddwLx4zNucbiimm3DqXtu6CoeGM9vjFcz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6BYKnxrdqnSK9KdE6ZRzieinj8XU91xuo92TyUhAFzpc", - "marketAuthority": "ADjbu8htUqgjFAs5cVQWNeZiqypRmft1bc2jJBQGaKF7", - "marketBaseVault": "HjW2rHH3DsWtSML5tWVm6NBjhG53N6i8BsTViVoMLUuY", - "marketQuoteVault": "4TJ7aqTeHQ1T8dQh6tpSF2Pd6ShZgiy6WqHaDogVoY3n", - "marketBids": "FtNjpW1rh67gAaeVjk7rHExuYndjAcpqMrpWJk6aKiWE", - "marketAsks": "CGHModhCUMEex6Ro5TXRJJ2r6WoPbjc2B8WbXpzY6jg4", - "marketEventQueue": "D7DwqYAHfnka3FUYYigovnFvvGri1o2bqPvkmsVmgoMG" - }, - { - "id": "B3cJ1CsDj7ZYBxsjMFm6XniTUZHH88V4qNVXBMGuADqB", - "baseMint": "7fCzz6ZDHm4UWC9Se1RPLmiyeuQ6kStxpcAP696EuE1E", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "3YaHi5LwwLLm9fHqKCKR6QVqVb82zHRFh2NCvsazDT4B", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "G5qXKnbcQaSTbrZpmB5TxBFfPfidPmTJ8GKDVKp4ygh7", - "targetOrders": "2sAEVoSnzUg5sQ4sTUnD1S1VXdqfgQckGSHbPdEAU8CY", - "baseVault": "35X1HHbPVfapdaL114ou1xcsWjRGbzC7ecqsq2GToLKn", - "quoteVault": "Ejai4wLva7UZX1rEnNf8fyxdCAR4cwJWNKR1eZj4SocA", - "withdrawQueue": "2GDLYic3dw8BqEYWcfZqUbRkounBeZeapAV3sdTFx9RW", - "lpVault": "9erVzYpza2jFgrvFYxnmsZjqCUb9Kmyq8fUFyAdM4JnC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8Bv5ntwpcbvhh6xfT3tF6K5eXaMx8rin9wENin6wpp52", - "marketAuthority": "8s8iRoQHA5gXtJuS82McNpCf1jpuWMJRYFqCiJRAyYo9", - "marketBaseVault": "DPnEDdNWW1T8VQCUWJdkRvE3YSjbJvuRRJiPhXs1o3dg", - "marketQuoteVault": "D6muDiudsQnTThfvHXshaobEer9svrZwgbThb94qJ3W9", - "marketBids": "6CuipX6tMuRduekX9Y1GfMu4SM6gNVNoAb1MRRW7ZPT7", - "marketAsks": "DkzZn8UQBPhJcjWKEALXmryTzJuVxnZ41boJncxg4qpf", - "marketEventQueue": "FSGZEoywFM7Z2QvHqNgpEhzgUphVstBTp2wf5m4Y75Jm" - }, - { - "id": "B3F6yPfXTaNbiu4BvRV1Ls7YJSyryDevVGMtwSVqgGrg", - "baseMint": "FmoKY2ERGmE9NzrYphAJcqH5BPRy2Hs4VomRfu8Qgt7Y", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "DHndaNRbRwKDo5stps37bwkgNeEJUoh744MGKBk8UkDA", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8rMU2QoMV7RCW8cgUVYd468FbBKJjcVmi9FCekwm9Yme", - "targetOrders": "H2a8tNLHEDoS3rveqmDj4tEQqrb33TUnA87hHAk9nHjd", - "baseVault": "G13LhgxQM2j3gdJhPpdQag2kRCHLJRfm9cAFQVU4oX1U", - "quoteVault": "4pCdbxaWNkSneaus98Yu9s5mz3QYGPwx4UJN8cYGbd3Q", - "withdrawQueue": "8ZuPmP2d3hX8LBqeVoCUc6peKddpGhp3VbDHAWWTotSr", - "lpVault": "CFhKYXBSgsGJnZCYGHQaWm2sewSMJXhFgKjLjbC5XU6c", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "B8jD8hACNZMX4VWnsuy5FbXNUUYguykkWy2VQdWGC8Mp", - "marketAuthority": "GNB68FGKbRdcm7Gy33sio9BgV5gZ5tgEsXWEb2Vkjuqo", - "marketBaseVault": "He163sE5CMGs3rNesmUQnKQz2VigQ5DT2ANNFssMp9dk", - "marketQuoteVault": "foMn1L2mNXHJDnqA2a6SHkaRfbXVt2caNxwfENMUVLc", - "marketBids": "5tpGdaY5USp7xXsBYBx7j2i9vxuiw86UGH3qmqVfiBGi", - "marketAsks": "H2yYTSBA9BTeQLCx25hh69oqzRPWWG7PoBQL4pSDaUH9", - "marketEventQueue": "pXqZFSuZFZeZLkxYcaKFWaJ3Wdw6zCcteJZEBm9BTgV" - }, - { - "id": "B3nzRPTpUrJACR62m3HxQDJuHk2y8idh1Jzs2BwA9a5e", - "baseMint": "5hzLftaEyGTQJnoxhGxAvsLkmdjYsbx9YdjNwfNmtq2s", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6gdLbN8ktppZQZJQ7QXZDG8vVMR7YEavuhcJyb8Nvdjx", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "A33cLfAXM5F5VeRHSRrEGXGses5qEiaBgMAQXWVEWRGi", - "targetOrders": "G1Yrf9njjgysH1eUeBhga5uxt6X9X3rTG6Hyuqbk2bC6", - "baseVault": "AaYoA5wYzbRuE6xcVme5HqZP5MJy7WREQUUEpAMHwZQv", - "quoteVault": "s6VRT1sYtSdj6yxQma4wHNUD3m3zENqzKYz4xFomT5r", - "withdrawQueue": "8AVUdT4GdXj1zFddQvFtW68VWgCRHEfZ47HbvaqiXQk8", - "lpVault": "ASFvKGdrD3Hqp5hCHrQifCr4v5jzH79KN6bJeHAjZZ2v", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2zifD2VLjntbFiqhLGR8F812WDUUEiGoqB4jurxX6E2F", - "marketAuthority": "CU6BJJArmtceP9BUAMhsWvXL8gEtBfjYYV7NMVzq8jFC", - "marketBaseVault": "72ji4ruEBUcsatqpmLJ4y8VHw69c2y1rFEWk9rPtYXdg", - "marketQuoteVault": "G4ZGhcskUm3qzvKQK1sEWuEFnUGVVLvPbcsf3Xycf1ro", - "marketBids": "8v3UmXnfJgvwk4aHKcn9fxaXunFG1rx464g8RnLudDyR", - "marketAsks": "B5qUoUUzSdYMBgk2gC6X2UBREp6Mq3Qag4V9y8D3S9kg", - "marketEventQueue": "5QZUXfhyttPXtj5dnrrubgVHdEVQC5Zf29edGPVBgj6R" - }, - { - "id": "B3Y2Si26KhhBtaj4hgbW4tcY7giNkSrKx8YdRuZP1pVd", - "baseMint": "6JdcMdhqgCtcP4U9tieRqmKLhPLxRMLC67QfmdXAJBvZ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "B5iV2FtReoe1UApTP5UDMheumS4CguH6t5RMkSNMgkwL", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6R9vrY5QBDdudrNorf5VFRcWdMkChAtWcaAbGwHi8opw", - "targetOrders": "4n2a4seTJCprQCrS16ZNBGvLEmDVSp9JAKokn8CWVn4r", - "baseVault": "CdX66ToPzgQPGLtUNx6CwduqqdbZe1FncpHvDeRa4wDo", - "quoteVault": "FeqYC1Fpyon8PedGjApej9fRQUGcB94byBmsSmsifpRx", - "withdrawQueue": "45wwu4qV7Dt4HQ16tAgZCDyDmCWkaJb2vjUwRkMmTUAp", - "lpVault": "H4XWnVkgr2L3cRqWhS964tojdrj9ipsGjMPm1s3CgP24", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8bjQ8XvzrDxKxHhTccpLkqGLbBrCAAPuv6KHrgN95nDW", - "marketAuthority": "ATqFQvvG9rs2JfxX3hPZ9QGpW7gkUGBMKndexktwr3W2", - "marketBaseVault": "3LRhDqJxUBUiVvAEpHhGwU4HKgRMFEEpmFg1ccj38AE1", - "marketQuoteVault": "ESH4DyaFrxs5AaoWZ5hYSxrNLH6sHYbnbKKCdsTXTWrj", - "marketBids": "7brkBng3Yb9G7mgtnaXuWLgUyX1GRGuM3BM1EHj1Rsvy", - "marketAsks": "BpT6vDEhzig7MmHpxV9RrSmE2DArvSNWiG1uqk9E9aKk", - "marketEventQueue": "2tAW72jkwW26r9EYrCRGi24XoeLx3rwpE6TGPvoSHS1J" - }, - { - "id": "B42LM1riFEu1BHPbmHG1sVhA5pCxqHx5cH7efMzJCpfK", - "baseMint": "3He7MjkGXd9MjCu9rv7oUosi4Gav1JuzpDqk6sDX7XJo", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CLHmZg12sasC6CqSVXSLy93nqARpX7oi7MtNi4Hp2on4", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3ty1zyZB22iqfoeYQAegQ4La3CqZQFJAsxsyiTEzXVFP", - "targetOrders": "DnyQdfNew75X7KuFjks7bkZ3E5XHd8i1GaEwM7nCs4vK", - "baseVault": "3uiYqN3qeMazBbfXkjUHtYZCZwR9SDVFw98xqnYCb1aF", - "quoteVault": "F28q9EvjDnZAqUqQASGXPKhK5WA41etrknZZDaoSoWje", - "withdrawQueue": "AykYh6YutdFJ3bnRax8whQrGqZJeJxYMC6u3PoYiCakB", - "lpVault": "CYTvFLyKk7DYcKR7SRzZVTvKNXnUhPHm6sRqGAeu1H7q", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3uL5WrZnDZLK8FPa92H2yhyvK3cewuVzd8R9ZtEXmScY", - "marketAuthority": "FBhJaGXP7n71Fp72qCYER27wWZyNbPi4JttmWLGmZb5H", - "marketBaseVault": "EcApRjaQ1zPEJQdYndmVzdMgGm9X22msffZdUmKsvUgh", - "marketQuoteVault": "FcfbrUJJP9bboHzviZWhMLptVtGXHq3mVuLTaTgXXtzn", - "marketBids": "478GLMZFUx7xJKTSw8EN1M87qZM8FwEFVz7Xyv9EkE65", - "marketAsks": "82MPjiXmEYJpnwxiBWcjyeHYkQqbn3tRf7FjmznzAjdu", - "marketEventQueue": "HiA1iRWdQUjmc3GhxnAh173FeTLMzYyPU8b3T3wTa8Gu" - }, - { - "id": "B4DRWKoh3xarEfAPsyH9aW5xXKPv4XJaj5gWrcnaBu6G", - "baseMint": "4J4XAtCWWVrb4FBM4JySPWX3YWix2bTpZNtAAHH4UEba", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "CYG3DoxG81piQektLVb5THpgVcBhDUKUSHJLhUDApAyr", - "baseDecimals": 3, - "quoteDecimals": 6, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "792H7wxFfoeGrkM61AJfpBYkHcBch3swZVtT7UN3BRha", - "targetOrders": "3YUN1GpJZ1t3P6DDurWd15SSf8Y6i6BU4YP1SRxDNsqP", - "baseVault": "6GHuLNGRE2GCsp6JjpGMZXh9pk3yo9sGAF2tyRL5rboe", - "quoteVault": "7uvbBxkVbwieSPSGuJMCWSCCzvUo6BY2FGEX4KvFHTUw", - "withdrawQueue": "HLyhyzx4RfSrjmnB2ncwcrhsoz5e8NecT59KRPqDwVSH", - "lpVault": "Dk27QMSK4c5pze8CKKDCcH7ePHmnoGGquRda83PixpLJ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "KnZcqCYWmBDwDdTUKjYumEn9YTKu6GnGy525Bj5wGFq", - "marketAuthority": "2pu3rhbmwDQ6gzHJEsxsxR9HQrth73ny5NC2WATn8XAr", - "marketBaseVault": "DNsfeTCapyqoUFZuNWWzEREwbXpCBgc8DtPF9hsA5b94", - "marketQuoteVault": "EPEHh3H9bibMnB7Xtgmh6XcZfmMLCvNuP9NEh3XFwWFt", - "marketBids": "DjSBJQ7gHtVfczg853wuXFH8TpEtbgDXebhapCAZLQZd", - "marketAsks": "2zZcjpRVJZ1EdLV1zSVaJoojYziTeRfaWZ8viTPijUbU", - "marketEventQueue": "2axNT9g9qLksBNLnPN2aEKFhcwfGfVgLV7VmqMsHnXSH" - }, - { - "id": "B4MohDorYB4DJtS7oQV8YMbQWu76H2xF3jt4FaqSS5WR", - "baseMint": "TKDrcm3n4mfXFfPKZoLp5soRSdFQSmyWLdomdKL3ktU", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Fiz2vm1pJnwrDAmnvyMpoYRhfdDTpBDSZWg6LNhXwXA4", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8DEMBMLpzkpfvRMDBENWedjxju5dn1UsNGV1uda4foLD", - "targetOrders": "oLHVorQUitU3H6T9hLUcPpMVEvPRmS5tsvg5JHr7ETw", - "baseVault": "9WDUhcjMhSCzMQaL5nMAEjXjNdaKTH3mgng8PLDtybEi", - "quoteVault": "ETQVsu1KxUyKK4DzukGn9yp9Au1A2wWiDqNNxrrSdQNS", - "withdrawQueue": "H9jLJR53z9LYUXQ1VhMV1ED8RcGCuRm9DvZrom5VXKaJ", - "lpVault": "6DGejgXChbd4WFsevXdkCL6sgiVDwZBKeYYW38yF2m5i", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DnBj2xqxwjDYCNnegpFuaFqiYktvZpz9a7gvdbodjTU", - "marketAuthority": "B5pCoUr9if9equND3Ps1oUmwJj9rF84ATC8T486mV7xQ", - "marketBaseVault": "9pqDmG921TuMprrf9696fYhphdyzoK7Vxm7jdCYo4Rx6", - "marketQuoteVault": "74ZJPdd9CiToLRxYXtsg29NCTxGifwM7LsCyX9dmK7MB", - "marketBids": "FBxrDs8KiP2LBaYFtogJ7gezJaNUsJXghvDzbahNoNSf", - "marketAsks": "B852A3kCeG83x4nZQUJsfz4CnYCgJtsfQKDqMRtddocK", - "marketEventQueue": "H9WSBziE82H29wUyURq43MqBpodGRR7Nernyvca4LnEN" - }, - { - "id": "B4qmPqj43uYPuKsZnBnMCPDk4z4bY3qLnHXPnLNxgC7Y", - "baseMint": "credTHXbrCuzmy4M9ARGvz2JoSJWg8LByPbyXBhNyz7", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "DTd6ihvS7qqZoP4w3aDVH5vGgYgpT8GTKTkEYnBWTaSF", - "baseDecimals": 0, - "quoteDecimals": 9, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "NADNXaEgV2zW5HWK7ybWbSUiaNv9LoiurtykS1bJ9ph", - "targetOrders": "5TGQHapkq57ugvooV47z6Seos1unVSSgAaSCMgzqbVFV", - "baseVault": "JC3XK3AFLY1RhZz3BZ4sF2ZYCfbrPJsdVg8RjrhmEGrV", - "quoteVault": "PttUywF98atsEJaq3UhNRyMuKWzoYqSDyRyPqkXNThN", - "withdrawQueue": "DvY6cBSeJpuiSnptW8257HYrKVfSHJCaWoCHtqrYqrKw", - "lpVault": "Be4ykUaE4RN3nPamFxb5hH62rhYLiCmgXd6kNtowaps8", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DPF7yr9n58xvXzKFDwC32X3SZrpYGfCSbNcZ3EgdXQ42", - "marketAuthority": "68BwqtTp2N6CGCfSjCTNBifoQUxSGxsWU4ZFAayUPTHe", - "marketBaseVault": "7qTL3oyG81cAMTLavi9Q7h9dBGzkrFkK9PLUWAugYZF1", - "marketQuoteVault": "FeK5aSDFzkGnXfiFnJKKoHULzRvjf6vUesrhPL9YKxuJ", - "marketBids": "GjW3nRUJ8bwa4gU5yJdvivPuaG3zcA8KooxVFkFDeYc4", - "marketAsks": "Fea3nSnPM5ieug5tvWzZ1UmRS6hJnq2RvT8am5mQiFeV", - "marketEventQueue": "J4zaxUAQuF1psYZzYK8dXaRMM7ULne6vaXKwsNxoKLhm" - }, - { - "id": "B52JNRt5moeaEhHioCEjSzLgEvHbZG6t1eKuAVquf74S", - "baseMint": "StepAscQoEioFxxWGnh2sLBDFp9d8rvKz2Yp39iDpyT", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "H2vPfqPMxBeqC6bZJ8jSNzjKJPbeCcsuigDJ5wmJxry6", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "NQtCnvQVNhDo38Ecxed5JobBk5DTMfm76RpeZyg7UZS", - "targetOrders": "AveMmvTvZZvJQZo2NBHVFGVETMGv8FN5cxYhror6bbf1", - "baseVault": "7239S6XKm1oednnMsV77XvYPWuxchARCecQHWXDY5Zkb", - "quoteVault": "2FQgRuDfw4M7nXfZFR5QDmdqp2wsXY7BzUdJ7suzEdaS", - "withdrawQueue": "J29znZSaJnuGyabAWZw6hRRthWXrMQhg41U7mzgEzDhY", - "lpVault": "5S3rGMqE252tszoWgPjT6KcDzwmGSs5PdzL1be8QhMFQ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AXrnxY6mQwSW7GaMAjxYwoNs7agzWaYMeGgR52Pcb2su", - "marketAuthority": "7NvsnAG35kzVeE3H5tdzP2MxPfk3vNLvFgp3WbpQbYL", - "marketBaseVault": "J5e9NFo4ywQEDs5Gn3x513W8KoK5XhhsBY6mJQde3won", - "marketQuoteVault": "JA2tdETyiEYa7jfRE9MGJRcT7nBYVPnm62F76JbxgejQ", - "marketBids": "EHMd9sTwXPNgExdDhJtWW1jsCUEndPcx55zZNwQzysFt", - "marketAsks": "5kHAiv1JSCSFhUN83K6rtxqj3wnjKCKQWgKWCWEQbhoa", - "marketEventQueue": "AtdnomYzsjwBGttayN9tcwy9P3CptFCWDkdtFvK2vDrt" - }, - { - "id": "B5MVWa9vriRrKUsYGM8ZvV2m8aoqoLDrhGwTWAZpGsUw", - "baseMint": "SLNAAQ8VT6DRDc3W9UPDjFyRt7u4mzh8Z4WYMDjJc35", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Ev5DB4Bui2ZqxoztWSFQotiQ9YF8izygtop2JM2G9vCh", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2fw7KSzqMQ69qdg8Sdb47HV1CdU8KSdCBKJcBFh2rMaz", - "targetOrders": "3ySVLkCXPpsLLHHy7LEeYDxjcYEnnfzPnxv2QaRKSzYd", - "baseVault": "SF7g8oaVpVpVQtWvK9USRTYqPs4frQRRotj2dAFHpLp", - "quoteVault": "H5CZ8oeKD4x9GgHNCmyFoajwrymBPnTsvVWyDxux8GUy", - "withdrawQueue": "5HbMb6fXYgKNRS5rLekLqfTU6D8FZjGT3YxVwznymwQh", - "lpVault": "Jh68T9WDM1AKtn1zoeW39LE8k6ZZzvAMUMLZbVPSWML", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BTkgPM58KXsfkqtsE3kWkhVbZWogsJV3HZwYZXqRssqx", - "marketAuthority": "F1U6iFfgy9FWFc7cpc5aSwEMMNmNPsfTxkM5J8WRQfw7", - "marketBaseVault": "8X3xCqniMohKfxRjXzGmm4uwQHY8oBBm8MTVMMaCsDwb", - "marketQuoteVault": "83kjp5oLzYkeGLjgjcT9k3x5GWyoEWDVicPCoF7hYBZ1", - "marketBids": "57EzaVy9FJqZ9mm9Yq4VHPZ5RPwNkaycfxPUhA3paaPQ", - "marketAsks": "3dpvkw8GFD3MHDvwMxxeBymxuYGwabD8i5zAinnqg3pV", - "marketEventQueue": "5VWdzx2rBLfNocrgy4vYyZDQM9b8h8FVxFRph67tHhqK" - }, - { - "id": "B6zbkBhGbb5kaKDRDwMzn1rR8ADrYZNS1FuqkJR1cHZb", - "baseMint": "fLoeAqCfMiS3Uaj6aXSCGhf2ZE9znWz7WjTPCD2Rgnf", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "2e3bzsEHCdBnxjkeoR6bGVAGB6iguPpXnqWcKoCbXLsn", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9SkQtmYrFsu2uN5Dr1xGpS5EYYv2dTjryj3VASbjZYne", - "targetOrders": "D5htR1aT2r6Whpz61rNexHoVVpgNnkVsSNFRUKP6sXZ8", - "baseVault": "Fg9QcK1jEZbL2u2HP1WZEdBgcmRKsiBoHQGQ7t6GCs2L", - "quoteVault": "Aqh9z2sVDKN8iSQZQs91eV4dtSkZuHBVQqXFGuFTtnoX", - "withdrawQueue": "AoYPtB1Txa41rqzucRYEwCNEECeMMkBhcWbokzDRDC8b", - "lpVault": "6DhKbyRqCFDMWvmyLiT7zBSvc2PJEvsMhYJRf5LnFXsr", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GdhQ2FrPjrewQJj9i2WNgqA8mGSP4ntMqw4oJR71nkE7", - "marketAuthority": "AzFNyUTdUsqxNsaVMf9RxYHT3MjS9kdQmyGagsDtanJP", - "marketBaseVault": "4ZTiF6NFCNJKXnNX1jdks75bdsF586URixQPbLjxm4b3", - "marketQuoteVault": "38ae9sXz4QHg2a9mz1yzeob9YrzKQ8CVE1yCNCUjFinm", - "marketBids": "9qy1xUSnySUVg8nRxPc9EwrDdmGX1yUWap32Ki2act2P", - "marketAsks": "5bvNwyLmiW4SjkKS9PfCHnyj9D6D1Kddz6VtdAHdTDxK", - "marketEventQueue": "Gdo4xHKJYhQfVT6AJowL5m5TaPXmqYzEZD8VhZ6gyihP" - }, - { - "id": "B77U9gEgWtqEr8zFTv6jx8JFG3H83ahmTjnBTuFdSXKc", - "baseMint": "5Wsd311hY8NXQhkt9cWHwTnqafk7BGEbLu8Py3DSnPAr", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6gEoA6MSJqByf1Lt3EpxqsbvNWgJEbPVyKJD8H8PwgKk", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EkwibfKCprqJAuxGJ2Mm9mB1Aeupc1Xs52tmE7rRksih", - "targetOrders": "3RZeeWk2Ejtx3DeDaxLvpZouH7ovug3AWNBBda9jQhNW", - "baseVault": "5MMXnZoDF7CocDt3fg1FJM3n3VwddFhgkcN1gMmVEvEH", - "quoteVault": "Fc2SztTRppxycRzHQip7mFsYpLgSQqPXD9VWyWn5YaVo", - "withdrawQueue": "27PNznTXeeYQnaTCFyBLDtL9pbKUCuwqsFDdyt7jc7yG", - "lpVault": "26x2yq8B7AryCBh3R72Adb9LhmQ1GZN8voFwtEffprcj", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2VFbgk7DNLoofygFLUuAmQRV6R3o2VeiDZJNqhowYhAp", - "marketAuthority": "CAJ6fvGSP8SF4LiXoB3gXBQGiPS4p8mF6GdonCHARnzy", - "marketBaseVault": "Bium2ssyh5bFJiKMsRTKaQiKFrzTvASmY65Brm5a232r", - "marketQuoteVault": "EvhvK5DYWfcJZbWDtTmWbHQ55T56hCXUpAwodu2s1KMY", - "marketBids": "DvxFgnuc3FtVgJWL2msv8SUk4KtZCS7fRPB6eBi7HsSQ", - "marketAsks": "35M2k96sj8uAN7cDZyEeYaEH2u3418zLxPgv1bVFRAHU", - "marketEventQueue": "Fo2C7Dc8opNFKVGEwy4LBZJojUYmzZAUwdenxL8eagcr" - }, - { - "id": "B7Dap5Rntuk96ti4cZ96L3CFVN5kkbedzbzEFSj4kArw", - "baseMint": "EAefyXw6E8sny1cX3LTH6RSvtzH6E5EFy1XsE2AiH1f3", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "F6q66Tp2z98dMwHab1WLYejWZjtVA4q4L1qRhjjsdaKk", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "LJmgERkeZUA4avRjbYHxcrj13fSfXwbgnsWyC16Cp36", - "targetOrders": "9okeBMRvfNsfi6V8zUoeufbwZU2TUCRWvMhpcEY6mEDH", - "baseVault": "AVHecXevbMoJ5KoXiZgtiKFQriJJJN1wvocrrgsUkD44", - "quoteVault": "CmkmaKa4J2wvUrfSXKTKBmLD4Cbii1fGdn2BWviMr3KL", - "withdrawQueue": "8qdYn2JJrQKiCBo7qQCNkW6VsbnHZ7VSkvGvJkNsnW8B", - "lpVault": "2z4eueazPGnjZCPXzt7CHrmK5wiBDtkmhFVDQfs7eVRB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Dujraambe9WWEtgswwccoJWMtE4Rnz2Ue4X2cGJB7keB", - "marketAuthority": "qXUsLpYeMGBdvmeXbSSK1gA7VvTxfcPptL5TyoHwLHA", - "marketBaseVault": "E2zciFtHMvUv4tmm5jRGTkG1Y6AzBfgjjBSre9h2pp8G", - "marketQuoteVault": "GNNt23ZXR6n4mF1BonSqtYg59Ty52Zjb2JQ1zUNV4X7B", - "marketBids": "BgJmk77D6EK7tcsurJCErwYTSvHSHeR7phP1ZTq7Um5R", - "marketAsks": "8DyUa2k3LqZHddeLdRiZmAuq6YpgZUSJxyRNbznhgVHq", - "marketEventQueue": "2o8aUNSA7HkQDrdBWH6jZkWxbyN73BVC6FrkdpZdWxyC" - }, - { - "id": "B83Uz4LhuSE9H1YwsBm9LvE4XbxKrgAHwXzHnPojfBbB", - "baseMint": "EmvtEzATa3n766yxojGZJmpSzkTxsCdDSX2zgRMZEoaQ", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "7jcjXqp5wqxqx11Yq9oPFKx5XCJTnfMXRD31DdEP64oU", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6qxvsnAn9F8bbevJ9qcZrsU384uNDEH9K21pJP423bia", - "targetOrders": "CiFroTRs6iVMTmDGvX3g3FfwaBp68p455rBYoF6g3RY1", - "baseVault": "BEvH4VY3ifwTbg6zKXMizSyZ4kMQBNKxaLiFJDXTuV7L", - "quoteVault": "9QEu3Dd8etqKJszTRnJQHt8RsqrgjmtnGfp1s98rm3sV", - "withdrawQueue": "9CARnCgghWiCM7zmopYTD87e747hSSrKF9WUNZTfKcXj", - "lpVault": "AecaDeePPL2Uw38f9WdjuVHLatWvsdcETLoWJ3jM3C6E", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FZZ2bWrVfxBQnzJh7ihB6C6838LyH7knkF8DdTQkQe2P", - "marketAuthority": "31rUFZ6Pemrazx6sgQTK8RYgZoRkZiRA8Dx2y3TCQkNH", - "marketBaseVault": "GhQydtH7e7RXxQB18RBXFBF9UxZPoCy18BaYX4g9i7Bk", - "marketQuoteVault": "FBRbq9XM7CviLR2xjLe9QTCvnWadk3jmEvssnKj9NKjq", - "marketBids": "DM94k36XWw1Sd63ocvH2CQEi8bxrcBSNaZijcnsFToYs", - "marketAsks": "4ekApvsKuenLAtVtEs4WN7nn6nix3hzxegvfrZZps9Vt", - "marketEventQueue": "FVfsrfib3ebHDnVrjTFwhQojYKVxQ9pK4KK4utApM3HK" - }, - { - "id": "B8Qm2tEUshqkw1P9X39uNWbDgCQ83kBJ19VMMGfdkd22", - "baseMint": "2cZv8HrgcWSvC6n1uEiS48cEQGb1d3fiowP2rpa4wBL9", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "HUYZnWqa12qEMqcmJgHqZgxVrbT6ZSTX8vmL5FMsePLv", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "qRxQEHwWwEasuCMuUWNZQmkgXfMgbmNpTazkfbihbRH", - "targetOrders": "CQMDa2ymQBjUb35yUDbqTbANxwj3tpJxoW5RVEf9t8b3", - "baseVault": "7mfvcxhqSzqQ9iTHqDqugC3HVBcnvoFsdgWEjLyykx3E", - "quoteVault": "7yV62HDWCPTdDhwDBnAm8sqJz6goJnNg5TEE72ty9rEo", - "withdrawQueue": "76ELbMUQmSqNG2m3cPvXTuUdb8SxqrVBcRQLk2mi29Db", - "lpVault": "637LMQpqLDwS9hVj1Pgt576pLXBZ2YfNhdvieKoz625Y", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Ake2U29xqM2aMxf2xPGuxrcCJaJAxzCMA5uU79o9q9Z7", - "marketAuthority": "HmBXgZCWAA5cUWcGcMHAngNB4xsgmDpjxDBi3jRxHRpV", - "marketBaseVault": "23zJqFqXyn868NTcxRPyYKkWwP7n2zMLMozg9K8mwwMQ", - "marketQuoteVault": "3Ky6Mro8f5ojJ9eLnLiAAGwfSP6bduZqA68qngbMg7iZ", - "marketBids": "35142rQ2StPWW58uokFUoQSqQz2mr4BA6tu8dSELUNFr", - "marketAsks": "9FJ9PPVumyttt7my1wPox8DjwdLjaAUejeF63TftCsCW", - "marketEventQueue": "4HvQoLE96wPsUJ68C2go8vX7pJEm1sqiN7gUpSUrFuUC" - }, - { - "id": "B8QUEGYzaSxBj4QW5J2uP4uHUc1PrXq58b3sYVzm4rUw", - "baseMint": "8G1SG7q8VyqCrjH7VjG9fouDDmHYJaYBMzBomdcUZ1qX", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7ckDwP1njB9PULRpZyGzsjapbCWLPiaeSWyPrPJt12qB", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8ngLHqfqSd385KsQjJyWQbdvrgirH1y4aid2YRbrTtTm", - "targetOrders": "5jC3gFhoRfGsuMPAZBDmwQR3o2Q6BqpPitvcGSF1LB6j", - "baseVault": "DbWJqXBxtP1s1ek1uJv1FAMinSDcZxN1L2rEaJL9yn2V", - "quoteVault": "JDLbFY9Z7yzy6digm2n2GgBPqb1WefVh999webwiz5nF", - "withdrawQueue": "DfuRLGzEkoHk3Au6ZQ4jHbSTmy77d6qkys2YWESLz2dx", - "lpVault": "F9TXbfBWSxYB1sy9VfFZ5xCNmJ4JzzY18cpEmkTuwkmE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GedXgxuU9bGXmtTz6BqT5HsM84iGrhf1jx6HswoAkc2N", - "marketAuthority": "AzeG9RcoQRXBnxZSdxH2vwYamCkaMXLLczM3BbfA5RXr", - "marketBaseVault": "DZLykXWaYdZMyaoHViWKHEYZK8diEhMJdnZpC9hev6hn", - "marketQuoteVault": "zcxFP5ZuX7pXhdK1RdsigRCbsQcbH9QLtrPtcZgTUbk", - "marketBids": "EFN1G2ztPYR877iWBVBb5oGaCjm26W3DpvaFXpDQ9YYB", - "marketAsks": "GZbGrWCcesQmaxJajNryGJexNXRD52gMmpnU1S4dZZ2P", - "marketEventQueue": "5R6toSntqM3Q8L4YuLPCzH3ax3V44cacFqgDFXgieZno" - }, - { - "id": "B969rQaaVs5WfQSVzYMZHWb4viRxXWxGzVLF2RcMAfap", - "baseMint": "SNSNkV9zfG5ZKWQs6x4hxvBRV6s8SqMfSGCtECDvdMd", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "31MFXsNsBigGMudo9ZKW52H2dNm8sRFuHcBxyQamy62C", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7NmMQb8KKzeBLyZCyAtBwthjMotVGQRAijdbJvFeGzhN", - "targetOrders": "5wqsaLc7rCSgP4ubkSprdXgG4maUj5HHizEjstFR3x48", - "baseVault": "5SufLfeqEurxR7bJg44SAsheHL6CKM5hpL7SZo8Ssaeo", - "quoteVault": "FnVRMwPzEsZePR1swXMP4uJ2zkvk6452rer998NZfwXW", - "withdrawQueue": "9Q2UvuHt1dNUESBazDTfuWGMSGiwoirdyVXUegJvQ2vN", - "lpVault": "Bygh9BCf7wGg9oCDUAfGJSbLKQ5GZF3dkf4wcdbuWzG1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "J3JcSC428ahZSW1VGFggdYXqXvijAcfY3LgrgYgFTWP8", - "marketAuthority": "22xv1SiuxxeTZ1apFwdWA9S4oMXqLG4wQVuJo2mFB7hh", - "marketBaseVault": "ED5SRSVKkXAhjd7tewA7zq6beLhVLDAcisiRG2VHcvGD", - "marketQuoteVault": "7D3mpdmVfVvxCN3fBsSm2Kj7e4vg9Q8LysjF2Dhv6cs7", - "marketBids": "5DeaiMLyEPWaHnU9FHejJCmwGSuXHkVQwUx8QnUW4hns", - "marketAsks": "DiniUWMCoRw4jeQdtpyoJctt7yuXi12E36im8boBFrya", - "marketEventQueue": "zPSDRkPiDB5mKtqhwX9W81vgWfNh9pii5HuDnaoKzWT" - }, - { - "id": "B9PQhcyukNL2qbyeNvHXPD31gwCzHSkgc6TqAzFbE6jo", - "baseMint": "9npcmmL1pGREY3nzrFdDdk2u9uq1UWzaF3iStPVpmQNh", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3NFkMR3ufxr5TjkM7sr4gUfmn1RVYX6xgFNDm36NpGs6", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5THqa2PFcsqE9Jay4EZFSHKTEuL9ZXFyz2qcrrXiUBzo", - "targetOrders": "GdYkPsHNPdBM8TS8JYMpeeQ6xXdZtR5eaEUsvJMiC4gd", - "baseVault": "6N1JjQTgv6qKoJkxbowv17oBjyu2iwa7nh12fpx79Fka", - "quoteVault": "FRDVf2kzU7BFUhXuVHYJqtRaeHLEJWHRCs4SN4PhdQhm", - "withdrawQueue": "2RTEpx2XtHdc1Ew47NyMAGAfd2ajnUquW17idEqHnG7M", - "lpVault": "BNrDJw34nhuEcYEj8ZAgZRJcXTEmbRysnpvP5237hAKm", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "A8CjHCv1aUTWDTCnxfvuCXgp1p2F7m1w1WZQDvKGcd51", - "marketAuthority": "D8USZLL4ubonPJLE57FceoKAUJoyvHpn4Vhy6PpV2YTm", - "marketBaseVault": "J619oqghTvwY4334GLAP853TRsTpw4LGLQYXd8t44zms", - "marketQuoteVault": "F1ccpqrQ5d93ddQQm7bgJVe5f86xr6xZeQcxUd4bD5jY", - "marketBids": "5pN4V6mkDFWz1z3EYcuge5xiKPBPu8nqNJCw8LymLeE1", - "marketAsks": "AgjeaAuTk6G63x2D4qQDYemByfa1JpuWtgvrPLkXm1xw", - "marketEventQueue": "g7LD96Z4gykjmw7f9u4M38kdDsq5jVovUzh72EeHqez" - }, - { - "id": "B9ra7qRfXppEfhhEbs5p6wSfQmodSQv7MnLs7Wy3SRPr", - "baseMint": "BqRtfrNpvRAW3KW319hvhPoTu76wKU2LTdXJyG9CyDze", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2oSLfCBFUejLC7TfAAiGysdQKcdMy2syKZxJVN7CVWL9", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9wbW5WnkRD7Rs2kFqKWE9t6ii2tdZyDgaTRPeAKuvctx", - "targetOrders": "CYphnE1wrs8BRhhP5LAMLoAwEP1DRmpA9qVscsxAsBX9", - "baseVault": "8hagT4SrDva3AM1qoPu6NrnCUNEc7EPW1oqvCZm4Pnop", - "quoteVault": "BQR2SZ2bxWRU4qizPootjuM1rSNA59mCba6BBpetJUNG", - "withdrawQueue": "C3qu3hh8txdFEWRvch5V585K1eVns4g9AAtemDFZ6xTc", - "lpVault": "FLYxApUvyhrhBWoyaUWKCLrF4SLuKqyLrvrhKjVkRPP5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6bxErQDCNQePQL6rBzr81WEjR3ax3mF63phZk94eHLSm", - "marketAuthority": "8n56z3EhNSKWzrobikUVzk6bnJKb6T4aWDaWuHrSEBwM", - "marketBaseVault": "3uEy8T3WD1QEuL9V93XTeEqdQUfJ2k4mh15D7itx8edy", - "marketQuoteVault": "ZHVQBVULGvThi7qVdmJgpvS4qwSt9YLVfwrdzkqBVGe", - "marketBids": "HNfWvuTH7B64LxXmVhVXMARw2yJfkT2dkGdbArDJ2gUT", - "marketAsks": "8DipVmJ5J35oAv1LUXcRtAaKVv8fpLq8MKajJqkPw1DP", - "marketEventQueue": "HmQgYuqq5JiMueLPBMHNFf79Hszcag9GqDkN6yms1fJZ" - }, - { - "id": "BA95voWgthHgdFQg2DDPp1yx6XXZAzYTbgEh9yZmWMs9", - "baseMint": "5bXXagtus2mrt4UQZ3k2w3cEiV5Q3b65krDefResDAAa", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CudupXjDFx678pdSryzFUr8dif964ErPdTRp12FWfFAd", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EiD3yMVyrQ94q8LMeg3HkS7VPpdSZeHJQk5Lbz9JCPC3", - "targetOrders": "7s83F8p1R36opx6KxbGoQHz2xrngFQCArwa68hjWNMXA", - "baseVault": "DfBzZhGvuBWYeVtaC8mtm9Jabc8RiwtV12KAtvWaf6f3", - "quoteVault": "5xWyBty3TMreFwzDk1f6UFa6CJkzpZKEcadSwyYRwJPN", - "withdrawQueue": "Et6F5dCtSCrnUPPeecnxKubzPxyFG1761FKPhwQd64e3", - "lpVault": "H48qZJZDmbf984rS2n1i23JZcTqLT1EkqGL1dJWBwpmh", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CDcsNzSm3Aaxxebp5JaxrneyqMQUYhxM36wtV9GRG789", - "marketAuthority": "8TFCTZdytRiCgeaqetREYrK1ojhrfvuyt3xUBihvks4L", - "marketBaseVault": "3WK1QU3yH3FuGGvWkAT8BpU8m5utT27HXR1aH9txYYvA", - "marketQuoteVault": "DWWiDQjviLPKjxk9NMJRrYizYDPBSS566FqNhnnAWYyc", - "marketBids": "8LxsUeJVTvhjXUqtqd56n2EipdZ8UdPmAHq8n74gSNbV", - "marketAsks": "2ZNbmi41aWwzgmPsbgvW1kmgpR3WJUZSLZc2kmf8t6xZ", - "marketEventQueue": "Hz8FTryVtwL12iM1F3UYTYVcLgdqe1CronoviHnumJ1c" - }, - { - "id": "BahjNY73uP92XWszqPwq8g4xp7meSCLHi6KLzXbGDiNE", - "baseMint": "HbF9REMFTxPipoarg9owzmFpV3j6xTwFLZjJdAtPNiqq", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "C57SNgv8sQ5PhpnWnrVSHswcWiTmz1Qp6fGa8tuMXVWj", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9ecutp7aEjwajvcH4rdnDDxNWAHNbSUE6E9UMLon7kMW", - "targetOrders": "FufVr7FhKxSxnrveHaxkHSrCgjhXiUq7N7rdoWgb9pUs", - "baseVault": "B5hRWYLtCUfFkqZPza9ob391uZswqG6uC6LJZVfhRpZd", - "quoteVault": "Bxq7gAVsiJp9FiTFtZMayEKC733bkGWVcmnWpWyNWq6Y", - "withdrawQueue": "68jCuNMkYT5ACp6qbBjyoVup6vDB7CuVWZu8AKC54Uof", - "lpVault": "7GqiDFyjCQ553TTJXWp49FikdE1dfB5MhF78M1tQQnY3", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DB4c1thYSPNXApmnG81kdf7bk9n69ocrfvsmzsFgyqYK", - "marketAuthority": "GfgWsfRyGqZLQCTfazEKfTPGXBWFFK76mwLm6YMA12ff", - "marketBaseVault": "HcA5fpi1hF3cTBqGy7z1FcEmZD75xJVd9pQLFMjis7b9", - "marketQuoteVault": "3C6NCdSjkCvR4gYm36EotePDZMyhd85oJuTazgLgDjmu", - "marketBids": "FDfznCUoSEZRVz3iSqudLgJ6i6AkdhVxWx7NyZB182mf", - "marketAsks": "59hdMPutcY8NKVothruNxZ2UcpCmwfXNboKqFj8R77Fz", - "marketEventQueue": "2Vto9o52yXchMvyw3nQU2UBqiRqeEaFysvkJxafgNcuP" - }, - { - "id": "BakD6m3Zn59auUpQEyJ1FHaGAb66QoyVTaSUEoqUd3WR", - "baseMint": "4cSZkVz2S9qZqng58zd3gcMKmSZ864GAzcR8ezH1SHhw", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CvZ1pdnpBUuWuG25aLKVbGfzVc1oXGfSPkQfciMneWYv", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GckLL2xpU5T9Y8NDTz2Hp7DgG9rCsuECCJrRNUunKH5Y", - "targetOrders": "HjG19RE3acHKeqfLePJo1GZYfyMm3TU8zU9TwPoBfKf", - "baseVault": "3tfh6yEAMNWSgpuyCS6MswrEPM2R9kiKM1wiaTDRQMr9", - "quoteVault": "AR7r4LmK6Sp5hrQWXdxFefn9WK4xD1HQzVRgEZpyZP42", - "withdrawQueue": "8kyck5oGnpP9MJ8AJ4omC3Th7rA8yiCnTgkD6v2k2JRX", - "lpVault": "3jjweQAiogdfj4f8v7H4CiLUynW5HXEByjAjN59NxuJE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FBmdV1f87yRRbybjdijrVSBqQPk2mXjA2tnFETkgBsWp", - "marketAuthority": "87Hn1iJow6iZR5buXAAftTyXiKVgSNPoeB6xF18qgqKf", - "marketBaseVault": "HoV3kGMN8b8ycmbxpdiGy3vHDzUk1oVmfbhv93J2NXfc", - "marketQuoteVault": "74chDK3pnRS5CAFcvjBz2byuRX8LEPe2c5GZjypRzcBo", - "marketBids": "9ggbqow9RguSFX6iPozCV7YXxfhyVafAQG7ACjEh7iHj", - "marketAsks": "GM2xuFAFsk5EUUvTbvBMGwB29V5fkerE2bBDNaro8B1K", - "marketEventQueue": "7yM9hB7MQz4ugC15vTQDLCjZSJ1qDNhdhHCn5GUVGrB5" - }, - { - "id": "BAoNX4Y9VnFCTJVvgz2E9aJpEeQeoxLT7qeJPRez2jjQ", - "baseMint": "AamY54CmEp9CFLKCxy97x2zxhFvqSFbQuZRhLz1mbSjm", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8BtVNpXKYQVivzf7h5cBC49k6tpASy59qfbDcVTjJ6by", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AVd55gHrdb9jaWBhxHqCVeDbkbdwxk1Z5syrDHbLAFYe", - "targetOrders": "5cDJCRiStVJ3q4xZDE3g6kDGtXrAs1MFgaan9AcqvU8E", - "baseVault": "6vpw9QSMcpPH8UpdQDzwwVJoNZctrA77Q9eBFXakHhTr", - "quoteVault": "994Qq5kV9ps2hoR6B354b5WGygsjTPfxTGMoADpFZc3P", - "withdrawQueue": "Hfa6N9YnpT4PxSnc9oyqY7bBMQoCvWfoPBNQB9vi59Ca", - "lpVault": "5KYo8LLYvBuTyAckkx1Ky67eCxp1MruJG6SVX3jAW4CV", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BUzX13vKgyfXw3ut4zTHBUR3kTQc2TE8MY5dXoV4kvqr", - "marketAuthority": "4rvkr3x2RFfLoCQ2oXENiyvbvWgyXBMwqFxY1UpS5uMA", - "marketBaseVault": "7ZWWZwXKqYTbjcrWbRCE1FFH3wy1Zj9gtMv13kRFACix", - "marketQuoteVault": "EAsjQPo35dFgr4jq4NyZHkuKd592Dfdb39pCanManqK", - "marketBids": "FkYZoYHasuqZT7bTKXxWv2setfpjACTVkF65pBn7DvUN", - "marketAsks": "Gy5MTCcu4qw1i49j1e1YMjHJPLdkPnUBFzaD83mz5YXx", - "marketEventQueue": "GsSTyLx8XrHD5hXaNWeAUcSvPmxQQP6YyByP1RWtV66X" - }, - { - "id": "BBf45w11U9jRstydQKP9UcxHaK1nAo2MzRsVDH2yWvr5", - "baseMint": "JET6zMJWkCN9tpRT2v2jfAmm5VnQFDpUBCyaKojmGtz", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7KMXqNg3SqcBQSF5C7pRHJAtxD7baH6NpMFKvFuE7aUD", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FVuqGMkY57doK1d6qzo5nvrZg99Gddou6wvQP9uByQF", - "targetOrders": "EG25on6EnexwntgijD4rYee6uJ7KgsEQsxyztCqyw5oz", - "baseVault": "HXxYF6PGx3veB2ayoWA5anpEWqTurjSuoiacdE2D3kge", - "quoteVault": "9SiFkVtihMNzXaUyzjekYFHZH65Cqi4i6x8Zb8RcTzwU", - "withdrawQueue": "DoiKmaUVDqRZHkNqY2zkdgdeCJ17Kkt7piZEZy2h2KrE", - "lpVault": "8gKMAGiHmwkyijPL6MPHS35XVpezQw26UAdAy9eNfqWH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6pQMoHDC2o8eeFxyTKtfnsr8d48hKFWsRpLHAqVHH2ZP", - "marketAuthority": "2MNjUnvXNhpGTce3aMdjaz1GWVLi1eLSzzWcb4xPNPsj", - "marketBaseVault": "ARxrXhztC2oN9mHAFZhJkHpPnzu82CMvnYBN4aYxJdQR", - "marketQuoteVault": "9RPU2dxBRisma1wHRXWtccEtGmxenNeYj2HmzuaB4Zfz", - "marketBids": "DHTwoTvLWE87z8RjghuBMTBwciPMsunsJDpBubHyk9m1", - "marketAsks": "9vG5HVp8tSSkeQk9Vd7Lmu4dpWoWtiV76ziCwxa87mWS", - "marketEventQueue": "FTtrtEkcJaa84FRBwp7w5fUypBwvMsbNvS3KUD1HL97c" - }, - { - "id": "BcHrDyrBVAh1RCxc9UM2YnbTtH2LQUE7F6FVE9iESDxW", - "baseMint": "3uNAevHamuZKKQdtdLzmHNvqD8r14tXUUXx5PN48UbYC", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "H5jrh9eDAhk8rAQ7GvVnrrmNDV1WyuHEZStuJxerhSjo", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AusWMznB2P1Mx6ogAGqMVPwEf7NPo5UBwUbphXsik3EU", - "targetOrders": "3ukbDvqFVFRbgEpDem5aq6ATpJM9AYPYxg8mAEkwWcK4", - "baseVault": "BNyBqWP6cgQqkUAyeeiFmNyUu8psbRVjqaHSA5y4Hsph", - "quoteVault": "2t9uCnVBP465VdMNVzAk9c9masNXqXs6pUD5jxsUN4VJ", - "withdrawQueue": "6zMy3hizs1azq25kuGYH7WwFQdwN7iHqVs1KUwmkohhL", - "lpVault": "9PNxdDb8AmrfxPJrZ52Vq6Cv6e59KsTDid4R3wVNMxgi", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7GHn6hxC8rJGg8Wv9mWAWHHUhDZXqtHZGdDsUsDjugS7", - "marketAuthority": "DmpzefjACPcuvHNppbDiAjhupWCCV1nJnnAmGTfHzoih", - "marketBaseVault": "GxJbLMRRgz2mtK2ydTsw7rtLRoQbszxAEpCxEqWMAkh6", - "marketQuoteVault": "4DxpcqrYCKJBLSsETZJLCuANCa2eYoSk4kU2v1hzHAjW", - "marketBids": "9miG1ug2G26QaUgeCJ9mKhfG5eveHLJ59moYCaSGCN1j", - "marketAsks": "3opAFjPYxuCLBK73tByXukJviooV7vWunes89otSx8VR", - "marketEventQueue": "F8eUJF8cywEwm8hzxoxfJShcNbE1kTU4Q4p9jFZKJJd5" - }, - { - "id": "BcjFnHHzJ6Y1XzLcm3nfr6tP7TGHGh15bLZazP5dAy9p", - "baseMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4KMt5G84PvfGc698RUjQZatFVRa9ZhcdhMNnWZc3wXj1", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7GjxQYF53dTHpdXGsBKxH1viQ514T7tN9w6UDTjgvRwS", - "targetOrders": "9b372VRTvfPBLR1aa3Hq54Tov1pz9ub5CCFxHXGHXQo1", - "baseVault": "3tuEJsGLhAjLRdq7nGb6h3ar9gqcxLJThT636ixBun6N", - "quoteVault": "kW4YEeZLgq6Rmy2V8Esy9pe2KpHsreKwcSmAEzi3cUH", - "withdrawQueue": "F9Cph3kaSxD8NULVxdrq8vG8VkkenebtbdA9z4j4RCVe", - "lpVault": "2NhYvx4ycSchviqFRnm4kPkXkcfwpyzrxCqkyHnLDdKE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9XUVkBf8K38iXJPos77wsMnJoniX7YNH17Rbzw1qmh9K", - "marketAuthority": "X5ywRCsvHQAYn4SeyYPjHA4qss3TdBbJe2Fy6HsMqxx", - "marketBaseVault": "FjEq3nwy6wkggMqe6JmtuLTF2reLm8t73B3bMuwtdfqB", - "marketQuoteVault": "2REJS1M9KYZogxNSU1TPXuZnZGoL9RZE1dZ27WjSDG2R", - "marketBids": "DyvfhKB34zujb7u9QzUXSNYisZLuxQffL2tvSJiUxwxL", - "marketAsks": "hkrUaUkJAsFs766V1fagagSiMUs876zMmzsbnipbe8z", - "marketEventQueue": "GFZg1JznSv2tbH2cNL1uFicvGWbUHqRM4M37j2K8Wr83" - }, - { - "id": "BcKkahceZW86a12s9GXkfRELY3v18ogWvTB8wYrnNr5y", - "baseMint": "J5gLhk6mmQ4PSoir1Ufh8JY2ytEHA93YupzYiTFVCgcL", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "An6beheDzgi1nWEz7vDio4xr4JSSZpdyibGY7tcbirxb", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AGA88YixbxtjS3ALx7Jv4mjasgscQwxEBQnsS85paGFk", - "targetOrders": "6VWMWuCD8ju1LbKxRsUWUkEUAGeUdbs1fTBs8sLeJpc1", - "baseVault": "Fou7eHHDfbQWaPpTmrxEuQz2TRVuoCCHpXZkBwhqeDgp", - "quoteVault": "DVE82NarSuSRoUWUoSvaJUCPX2Z5gv5JE5y5JmwYgo1N", - "withdrawQueue": "24bVTHcKm4r65aF3vYJUVW3ooxDKWp8vxVRMcqgn1fDy", - "lpVault": "q5wCaDqXtemARe2rBhAR2Gbqi1DK8KbWyWoYvthefDe", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4B75Kxuqof6WLnjyHaGXRNhMF4meg9WQ73E2t6JAiZ1y", - "marketAuthority": "7nLAhqey3S8XsHkcHDjzjKKmaPcv3YM2Th8dZSsN16Me", - "marketBaseVault": "HuR1EnCZtXXGqyefpE5Guym38VdS8NLn8kbkx7yd3onc", - "marketQuoteVault": "2LgyxhZVJGaVN785TDA3HLncc3JNAyLRfNyo5nJsZ1nk", - "marketBids": "6qNaVMLhRUXTrgBfZXrsZr1uWJ9k9LsBTbAHu2U8Kek7", - "marketAsks": "EkSy2G7u9zPtAdGfxVHGYF4KyAeoqjSw6469qGK6Py7Y", - "marketEventQueue": "5c6tYpTeuGqs2EJorkJcH5qy9Noyq1tRZfzCi76Lpfp6" - }, - { - "id": "BdEoifZEduuK8pJidntFj3R911wkmxyMQVdFF5Cmqx1p", - "baseMint": "BaSkmM2e6dY8aC4oe8Rh4B7L4bNG4tjtKSinVfjfoCRK", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7urNns7JHnRfZtDXgLkwdf8jXfk8mgyky4AxY6Lsdajh", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8zMqJkVymmR1Zb2r5Qwv2DKynBXia7UV2Ekt6mVL37mz", - "targetOrders": "J365WK944KhK22tXxgMgiD8NbPVyqnY6QWoj2N4rfNRV", - "baseVault": "6QpiDd8qS2HWAfiU9DuNpqHcJVLaToZCKCdwnmcbaJqT", - "quoteVault": "9XPJ6EQohczaCSFRYeBnox8SMVNrU13SNWyqryi8YAp", - "withdrawQueue": "14YiYW3f8AGx9xgtSRybkKFLXB4HbAEq7DYqXZLo9men", - "lpVault": "6jFjxGNtzqkbckzm765dwpZhGkHiHJF5tHhMif66eu2N", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "oSz4hHaLjZ7NKq62GPPfBBmHVZrwCDtaJnWwq9aBMV1", - "marketAuthority": "DFVoQBVmw6o3ugtBPzGDujF7pMFdKKKgXuQHrtcBjbvt", - "marketBaseVault": "D94ktH7CqrQmFFLZwrSMXwLiHXWFa7DWXGATUCVuieVo", - "marketQuoteVault": "DjC8uu1qKafHo7oJudTkPQxAVPkzWCczHVsE5fRsqvf4", - "marketBids": "DZuSTpUvbs3KLYwpZ6kDg7AufE5qq8X96HThhPWP6dat", - "marketAsks": "H6sPRC4UTSvVoR2EzArqFwXbUh66Hs3zitrv3QwviXaS", - "marketEventQueue": "14apNQF6tQeyGYwuHbh2K9VvaoL9NfQPqVMy4NbQZMGe" - }, - { - "id": "BDHj3tyuV7ME8zvaML24qnZBUxqLD6qHnuaswoYATWnL", - "baseMint": "CRkwd2QedqDi5u6W2w6jeAViAUd1pR4AXs2aKvh7GW7M", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "9epCvg7NLRhKGaS6jj4hgvUF6vLzG6VAJevfia8CdMca", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "12miZnHoBRujBjAnD7RgHgmVZJCxbC18JBDSyoP8Aydo", - "targetOrders": "3nanBdYghMqMkVr1Gi3R4X1LkonUUYCMZ9xtJWHGWVaA", - "baseVault": "9CVi3JUK8Cm9s3cPyuFMJx6bDrxZ2G5RQa6xDLWZsB2E", - "quoteVault": "Gen2P3TGQEN1QdRbw7kMHqavnhxu234GS4zrcpkeArL8", - "withdrawQueue": "5RgFnDEGRToHiZny7eM1AwcieC1Kk45NvB2HUyezVwBN", - "lpVault": "12i39Z5acfHQYfCDehjyCbbqLqQH2dKvBgYea1o6X4me", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3jELZkR8j3gagYLdUVifxJN52HvswSjCxFWNMKgsrPCB", - "marketAuthority": "7HmdwYrGa3QqexvYPxBEx6maMvt3JFLrRdHDxXxsV9Lc", - "marketBaseVault": "6Dn8Ln47MZfmw3Qq7wz1pU5sWvpEgavLmchYyYzeaZFU", - "marketQuoteVault": "EhnKMMXC4TKL6L6onbicsAzDj5WBbVNbtYfYXoVEzRxC", - "marketBids": "AY2TVTQmDxEE3QpYsyEQWg1eqGtYJNx3v5iBPbKYmc24", - "marketAsks": "c8iiUdpuMTWC6N1w7CioJGmjWKMEs1E5igA7peUM5YP", - "marketEventQueue": "4iKYUD9smR173j51g152kpUnp1tCaxwxk9hbWwbvsNTr" - }, - { - "id": "BdP14i5L8X2zLHqgWfkdQaB2ttCjNeVaeb88oBUPah3H", - "baseMint": "Dz9zm3cNcvhMdkAP4WrK1ezBUGqNVkx6qASuwT4MPy5x", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "2dBciszHh3JL8mVdLQn269FY14XR4MHNddtd56rqa9Ee", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AYdRsHPmo1zRvs9jWQKf9yTcprkgR6cAywr7yYCUKybm", - "targetOrders": "GXywcKWHTJ269bc1ao2MxNNLDCWAmuwJH1y3TcRp5koz", - "baseVault": "EpBxA6WLnZH6RRNo6eHES18GSjzsxTLWybubHVyo3gKi", - "quoteVault": "9bJHVJnNsZy8L9x2dYYUJt7GUEMh3iMQesTX6iEZygyo", - "withdrawQueue": "98Wtj1a5fJuYmHEN9SWMNwQFHvu63LKTeLezntYzz8o", - "lpVault": "EXjjuTH2RpUXkxqBAkVutVvC8QrtjPqaQv4aeSaoPNKa", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3f4PxZ5aGccX5EQQJVUE7mMUSA8rgvnaiTPhWGA4Ezup", - "marketAuthority": "G1hPo5WuGY8RiuzmVagVXivkWuAAwWvGWCGkYNKDd7KQ", - "marketBaseVault": "3kdwS1yUCFgkahiRBFmDx45wH8qZ5vNHbwDjw8hC9wXB", - "marketQuoteVault": "H1f5ZufRWVvi9wQw3VCg4XZfKwqt5kYj3s1qgDQYTMDx", - "marketBids": "9oZNqB1iJkM2NA93tjtRwnbXtm7ZCEDuRoEods4GSsFh", - "marketAsks": "3zQ7PVURSiu5ZeuoZ2BHXGSm4ji4Lawv4yfeaiSotdZb", - "marketEventQueue": "FaGE7wXYfNXA34x8ajej8YSYLmQBrACqLJtGWrhaur7Z" - }, - { - "id": "BF27RKDm4BqciRYib9KSBXcoYhaBh4ynP1veC4RngFwG", - "baseMint": "B8wCsjSv3TDZcaLuhPZNDvpk2vuBtRgpgmTuvoDAJZZ7", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5ZHoGCxdgFR3Eapbj5GGiJtxhbHnQmxd2JjZUh53P7Yj", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HUe1UP2uX5xvk8VCPMnSWpAg2H5XsedrQfYQws6yx3nv", - "targetOrders": "37fi52jXJHa6hph8Jg2ngW6FsEs442geDgN9A2ewT76M", - "baseVault": "4y7W3qQH6KQYNrFTpe5QgpgbNkseKWA1xcvJeG9PHPk1", - "quoteVault": "Ayt8JU4aN5Lopy3NM6SH728ZBnGcyqsBoRoEesyeasEU", - "withdrawQueue": "GUt6bSjW8HwXcmQMVwHgt6oksh33wfTjBGFmcyhMb2k7", - "lpVault": "F1Xz5QCrj5deauY2zs7EGBrAQxTJNiCxHLVEzGGi9Qvw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Azy5zquSVip9xew1xRWVDVU26PqqGehbsF57k58s91j3", - "marketAuthority": "93LKGV3u7MkYbyuXnfCViZqhRmfdN2ZsA6fxKhBYsud", - "marketBaseVault": "CTprWQsARF3hcHNPFVvX5mg5RpgJu5ynmTWzApPg8tgx", - "marketQuoteVault": "58C586RAp5qXvbMdkYz8puCFNHW9AVy7YqxSMu5XVRzZ", - "marketBids": "EvJUgcqGnSNWg73rkzy9LVRrh8VB1HkmMNNuqAzc2HtA", - "marketAsks": "B84Stxg5AKVb9czox2ykQ4TPpg3jw1afYBnPUvxgyP7h", - "marketEventQueue": "G7946ZXpymmGAcPQSQRTxHfUveNHt13uxY4D6sceH283" - }, - { - "id": "BFL6xmjwAbPo1UDS5csgfULpSV9V1R8JunqYwHzh63dn", - "baseMint": "5RinagTvYAFtxyNudbJ17pibAoVNh16LGXymLrjWQNY5", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2ovGRgQAwbamyPBQgxwsUTBwRQV557j832A7A6qewpx9", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HB6oAj6YS33URjeXA6hXTxuvoUuXiPGFKKTHArNtRyn", - "targetOrders": "6VNQu9DUhK9Jja5QvSCsUSAQBe7nYmzgZubhvbizf8Y3", - "baseVault": "DPQ3N4XtSVjzT7kdbcukpQyrk99EgL2dDY3dszYrfFUL", - "quoteVault": "6WvpboZjaakf5heBLXrGyx81gogLvKUMmCtZCBNR6gkC", - "withdrawQueue": "2tN5DViL52xZ9por3nSFsSceyxKbNWDkdQREn1y89PJz", - "lpVault": "EmiceRofMePsEVKV2Qepz47XVW91wX1U8M9LkG6NpgXJ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8xTY7UwTZYdfcZTSVeh6namdegarwscQBzhwWGbn88cJ", - "marketAuthority": "5W6n4mb4pNmfTSa7NbYTkR29X4EusbWiozgWAZVTXack", - "marketBaseVault": "BfKv9M9BrpyWdoA1PkDzjAGvbqEQV1eetTucMUyNFe2q", - "marketQuoteVault": "8V9VgNBknJp36dwMvB5uJcTKFP9qmnuETCbEnawZRTAS", - "marketBids": "6Aq6VuqTjPJU35zBzq2PmCDendY7wZ5mYTpVm9VfmCU3", - "marketAsks": "5uiUFU9P4vh5VMRTxFLU9inVKXTzBt9wCEaUSUoqc1Uy", - "marketEventQueue": "5XPxZbDddQqcyrTzDtj9W2tvAM6XNZHd83jWdsj64hcq" - }, - { - "id": "Bgjwa6KouUhaZ4VFVezgff3CfcYRA3AohDDfMi59na4E", - "baseMint": "BVGiPUve3dtMLNw2iv3tA7NN8Jv198Ha9FmPXKMUDkjF", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "7shXmJ3SauYBgoZsNH4z5ySquu4dd3kLMi1vyP2y6fBP", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "C2S7eV7Y7tZSf7iPLQJx8kCpDpSPievEqNorCwbetaUf", - "targetOrders": "7npbWhTHgdJw1bkp3HXseQ2AYZLXee7RLx34pQ4wRF8F", - "baseVault": "Gjqea2E3B2xtu1CWvm3dNEfSAwR7PgPKpoPEzcZNGcWe", - "quoteVault": "G9M1sC877jgw3hik1KxY9XwBBMRifPhAWZ4g3JMrxJqb", - "withdrawQueue": "3d1wegWBZCqX1p5vCys17QFFgaXNYiM23NsxoSgAKnj6", - "lpVault": "BYicvRwSJxjhizBBzz7Wt8kyYveCgRcG56iBwmmSA2rT", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CgBuorU3TR8cXTUtKjUQS5kxDGDX3mGEJfWtB2tLqN4T", - "marketAuthority": "HZUM4bnJzXn4zV88iWVNU7EYKLExN6knfM9tMwpXigcE", - "marketBaseVault": "7niks7vdu6pY2JG7NkyFnbzGn3vJ6rUEgwpbJfwiVgnQ", - "marketQuoteVault": "47TvsNaGAFn5u3yck1R1JVExiFSuiyU95rM6jWaN2LA9", - "marketBids": "DeyTgYTdYVvDkDNEmnLN3snctab1KaL7PPAtymxg8ztb", - "marketAsks": "8i9FXFKJK3TpYfpV4JS37Gn6WNnH6JxguhjzxuVgRHMC", - "marketEventQueue": "CbXJ7DLZqKEkUvrekXwpnJYooseqNCS2dxGAnQLybPf4" - }, - { - "id": "BHa2ccvaQBrQLAaqTfMiYzLbwFqK5yn6qKMpn3NrSMMn", - "baseMint": "7dHX7nVDtytz5ng9DNyiDMud9gcYimfjngKHrVvH6C4", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FYitHnXg3eJggV4knwtcqAvNE3F7YV9CMWbYcg5E7484", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4e1wScuFFUc6sPvDaBDX6Qmup6k3iBwdFFdWJFnu48oz", - "targetOrders": "Hw2KdEgsimaXqAG69rtzP6tuKK5mdQr4xzUVmMGE1W7U", - "baseVault": "Gjg6s8cWBMG7K5ykXXitEB2Li2sgHDjvx5TYniV8sr9U", - "quoteVault": "7118N9nyaxVxq5pjXgFXYisocEBwC9X5R4fgApmCDHqD", - "withdrawQueue": "DK71NFqVbZP3P9ZfgF2rm9yfpMZKF7TmTLeMj3DzsdRz", - "lpVault": "5kwbX8zqpwyJ7xHBFdRMcEbYAX9GbiBGXQiQfVhkSPuL", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Gne8eeLRXF4PgY3N3L2sMsaWDGJgoWZuPDTm7n6p1oe8", - "marketAuthority": "Dxo9fJbCAEewDWki77kaPcaJtwSAvPNUHVBZzavmNSQg", - "marketBaseVault": "FZyi2Y7hbLVCaNqmzXD91Gp5PU81vNTYgm5BTYKVKi7U", - "marketQuoteVault": "FfPmgoNEDtSWi6PyMsoxjzA8NTz5kxJ1UbJN5C7ZeEZN", - "marketBids": "AwaWoXuKnnigjz6PqyNBssZmiEvhX5pRttex3EebcSfR", - "marketAsks": "7B2fX46TkMnKEruqatmC9NmMQci3ZFLxexYACQ9isvTa", - "marketEventQueue": "13XuEkQ2cYMJvVDJovU7tuUiiVaTGNpWYPt2Rk35wMxx" - }, - { - "id": "BHgbAH5rnK7R9rf4Guy36w26DNj7W7gMkrFqXebdECck", - "baseMint": "LiLyT885cG9xZKYQk9x6VWMzmcui4ueV9J1uzPDDajY", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6fyGP7sTcpYf2VXykVpmUJ3GXuQagiTonBcwa7oT9CZH", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3fMsYRbYw7UwUmKd3rWFZQuEzrfKFeezq7gmUBXUwpfs", - "targetOrders": "62eKmAKFzmQXk8w2AgiCRHQEJGzTDmvpveCg1ATrTutj", - "baseVault": "BhjGZPfoLM7LGzSCoJLWgTUDxdAdWx2QYQQKXKc87mtf", - "quoteVault": "2vDtcgwWKPhE48BtaKia35VAH92jYFQmfzdVpW3R5nVg", - "withdrawQueue": "BsJCKgXbhbSpKjZRUpHeBXbwZiDMYabNbywxeVbGqJ5t", - "lpVault": "3RG2pZP7w2pNTPbd6GZfJJysAfkgZvysVGyvBKjqs3CH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8dQkNPLATKENFCDwLLpQ54P2tZ9wC4ptFVpdi7owuYBH", - "marketAuthority": "DDuoEe1nApnRvuitQ2k2rPrK18PodiA8d6eTyGAfB64u", - "marketBaseVault": "6d16gHjqbCygBY4XbXirb457yXSLmz22BRMfLfBUECdA", - "marketQuoteVault": "CTJXrqAk2Yg1LjJ7mtWHyFShDi7ppZ8F3sNRhJjqF1Ng", - "marketBids": "EMCMtvDCGaRxfR2XT9s9JkcNy5kszWqG492yCjjixdxH", - "marketAsks": "4QCXuo6X41zzM77q6jLk5q6qPa8ESCmpxUoJMK3e2oZx", - "marketEventQueue": "HZdC7fcn6y7XMrSPVtGTBtPP9LrWARCkjRikmx4Xqpa9" - }, - { - "id": "BHHgeXxUE2ckMifWk2RQaTWKUDd5X7b35VhNoasjYsRW", - "baseMint": "AfARcLLqRHsZc4xPWHE9nXZAswZaW294Ff1xcYQbjkLq", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "B6CqUtnKTPGbZTfqEy8xpMEMPon19dLVXCyCZbu9CqEA", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2K2GkLihhVDBZKN4uy8tTKHGQHaws8Q5XvUhqRnZwAmU", - "targetOrders": "Dp71NiGAwkBhoJyYgcjeYA4SHAPU7wBR6LRPhRwrWCvh", - "baseVault": "GSfBWHRyckZtFzqYpVcL67JAbjnYY3WJhaCuz7NwTYxd", - "quoteVault": "GrJfBKuwvmoCnTfiXSzMi9Ga9Ru1HEGoHDCgyu62Jeoc", - "withdrawQueue": "Hf3hpZL4mz5cVUjMSo3mrTtJL6zHiD3ePg7kbvBtH8bM", - "lpVault": "458jCMa3NVa195nyVYueRsmDDZEa4a6cELN3uCSAzJVg", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "aGyXAmV1QBESopcEgmr52qtaQ4DuEBg7WJARh1ojSPx", - "marketAuthority": "9MdioESfdiAdAsJTPxgje9HpSku8jXqs22uVZdtr9CfS", - "marketBaseVault": "8SmZnpvoWWG9Fe3M2vVJLTgxmjLuA23d2gzdGwyBt4u3", - "marketQuoteVault": "4Jvur4mEycRohG257qhUXGjWXdWzXiUcAu7q75n9v1GU", - "marketBids": "4Mc2n87t2kynHNJghGajnYnDVRnNdhFiyk5VSq7e5FND", - "marketAsks": "5rnyaYxdrGKGavvRmuY8JC3zHF998NdMbr4ANFCN8Wzw", - "marketEventQueue": "G81S2CXcBSztjrxsshNYat2fAXPg6nDVvB8gA7s6yZyb" - }, - { - "id": "BHkrKNa6T4h3TSbQuhq8y56hLN3qmUAoTgE8bXqqosDk", - "baseMint": "6z1oue9xiJCHcDqsyeTZ3NHFVzqMHQSoZmTvVamdW2MZ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DnNwPubZoPuTVtG7JnW9UiFKZrYcEfDvVPUevGwixqhP", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "whfHZE7zr4XKP4zGUWm4FUG9TYj81xMkrpN36FAXbJ7", - "targetOrders": "9VCR1izZiTR8FqUWjZdXSHZgesAFGpd4tG3taYrmWYjq", - "baseVault": "nWEAJecqEkQagNG1mcjTNvFHiZHw8Lo7o6XLzri1nNq", - "quoteVault": "F7CniGuraGjZwyH9y3Y7qttBKPHfDUh7R3KfPShNsbem", - "withdrawQueue": "ENoMrCC7FWvMKx9Ha3NCAuzfjrYQiczHgQ9aeXJkFV8t", - "lpVault": "8sw2FjNWDLtCNoZ7oAiRsXfX9NFDVjYmyikMrNfpTYsx", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9jJWCNgtTQX9q7ycUrUQAJXm3uHD2P9y1x9x7RLvaWRg", - "marketAuthority": "BCnesT84kkd9b6BuG83Ffx2kXmW3usgBx6yqpwifRotB", - "marketBaseVault": "E1MD4RXTPLEqqAr8w6Li3in2gQxrTgqVVaemUkS5LE65", - "marketQuoteVault": "2hTbbpHxoaP9ineae6QaQ6srpP24CBEGrLZEmsFDJq3m", - "marketBids": "9ZDpm4hPjtzBLbFupDFLSzdpMwcEYW1Ws81fXcu19EP3", - "marketAsks": "61SWCmhSH78vutkZVqSW1RfcJH4ThxDWEiC6qk1Zvmnn", - "marketEventQueue": "DwpxiTZS4yTKYriXjLPXzAP8JyAPcLziuW8bqV7nKju4" - }, - { - "id": "BicXDYGdYJGvZi4wJYBt18YawGMBe5oBR6aS9JbW7iGu", - "baseMint": "48AEwauAHsJibyt3WqjQ6EoHnFBcnyHASfo7vB2eCXPS", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "ARqo3vnnPzvepc33HAPP26gDr3PD4ZaNpfS7Q4b3AykH", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "44tsDE3yEGPK4v4hS46dbGsjB7TBScrGxDTTvQaSWTQ4", - "targetOrders": "64G89A6fPus29rXa62LL9wazX1hcqnPkJaWmUuD81RMU", - "baseVault": "GVZjFSqzTqd2YRgMKn5pBvHYj3EG2xBu2Gk9zoJFpYPe", - "quoteVault": "13DtMX9xttgCv9oTSy2JsQhvBrkpZ2W6UXMzHNYLj8qa", - "withdrawQueue": "Cnmj2tsybCwoLZmF3cVtFRBuNRNLaQyaNSuCLEbfD5PY", - "lpVault": "CFzu3zwhYZNWFEY6S161NgP8Dy7BA9gNEBnXmHs81wBt", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "54wWLgwTL5zKUooScsNfxNtmR3S2cDfRUecndfJdggWG", - "marketAuthority": "9HfsnjKEXWEGojmqVMiaHxT9DMkdgmbHtZDzEyRm1YMr", - "marketBaseVault": "ACcrRqTQUWg8MaagjwKBm22ztL5J89rFsBbcJ16jPYrN", - "marketQuoteVault": "8oinHo97uATDsheX3XPepkZGSq1AfJB963NAo62VpVtv", - "marketBids": "BTMBLxGj6QkKWgwa4nq4E8F6AHSU7w1sRyKPBnZmrhxN", - "marketAsks": "3pEzxCA5xBb6EzRSUiXjKUvdVmR5Q6myYddRAgJoZw5y", - "marketEventQueue": "BaXacd6kqPm5FTQu4fQreP9fGNeEcFiGGadN3EcYKDwA" - }, - { - "id": "BiDvipZbTfRvchqGoN77f6tuYgvbJ6Uk3gVGY1v7mbQi", - "baseMint": "BDrL8huis6S5tpmozaAaT5zhE5A7ZBAB2jMMvpKEeF8A", - "quoteMint": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "lpMint": "6pZr6uJJoMcGtdbABfdGH4rmcbTHQA6YcBaV3ndddRay", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "NyzE3cpSZ9Mo9soEPH5LWVNDutQLqxwQou7gHdWwqGn", - "targetOrders": "GrXbHb3L9AbBy3FFR4uXNU7jg4i1WYzJ2HsAQo4ZtyUW", - "baseVault": "AtvTmDkVPRvZwtiwzW8vwAtvwqu9XFBbHBiVQobVmCF6", - "quoteVault": "8tVVPshgkHbmyUgk2CJ6fZ2zpy1Ki3koNjy5iq4qKGEZ", - "withdrawQueue": "5gRiXbTSy2usi4g2zePQ6kZdBY3GvXbaH8MujK9baCFB", - "lpVault": "GCo6iuq4s52nXjwsSoHhAKsefGqpyQMYHqUBqfhAJ5qF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CxYXvEQfSVMyzjThdh251uP1fco1844K3TXJ6p1Fzxgu", - "marketAuthority": "9Bonbax4uaxvfptKCibYTVtbyztRodWLFAc8CYWU3Yid", - "marketBaseVault": "E1rERycT1uT5ZLdMpLDvZXWLFSrvpBsGCJekbgwBeBWw", - "marketQuoteVault": "AAHKdANBjRpU7XUtLh6ZekbUrVXvFfb1KiTTG2zWyvkB", - "marketBids": "8t3YB52xMj74LqG3HU1BuEeMLU3wkAVhUVUEmZcG1Hhe", - "marketAsks": "62ZqZJk1AG3mbKMdwvQF9NHzdRYXW9G5kUzsyYywVz6R", - "marketEventQueue": "3bEctBdhQJ2Q91nqRhgwZtXRMQREdn7SP2C5MFC713ZC" - }, - { - "id": "BimPSEV2PwioDzgFJ91LvvmmbxTZoMM9GDzRGywyFt3m", - "baseMint": "EctmRn2jMAdTDvQdG7mxadyiTvhGZiGYNrt9PWe6zioG", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8H7HtGE64veAWYyLPSZ9mUFqwKBn67mhWd2wGVLiGxET", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "56HhJwFnrq9CJ6RLatdtQoMmnyZc8fsdDFHa3npy823o", - "targetOrders": "4cqsrALFyZkdphsnxtVASvhkHc2dKSp7ZcYGrt2zmvG1", - "baseVault": "GkHj2FVc56yDomub7GK8gDkQqG2P42WJsxEcnJRbntqL", - "quoteVault": "jZ4WdBEFmS33mF5vAVKpHMigLbJkJgWKGGfm45nmbHt", - "withdrawQueue": "9wSSQNGQtfWqwwhobeTRAXacrHH8uK9YVf2MRnSr3NDr", - "lpVault": "BayB4aG3aPhnEqaWGvBw6cpJDN6Ams9qUbjvRZ3etqt5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4PpTChD7EUPRcTJtyXmL5QYJHtkZp6GfCm6DsVnqqR27", - "marketAuthority": "2GKEar7SVnPvLGPnm2yhdEEXSNFxh7a8rXZDcJAXK79b", - "marketBaseVault": "B4SarMCkDv9eDgb7HaESxL3fkD5joGiN9FpVAYKTZ1EW", - "marketQuoteVault": "4iTW3qN14BgRgS7Yvz8GufdHnmFZFLXP2fgVMSnmMgst", - "marketBids": "F7tbBND4QwFLuUC16mREsJsBP5rsgsXYyDNRd8qpuz4", - "marketAsks": "B9ghiqoQFZkgcqZcQHP8eKUcrBVW8V2bSBFRbWb683qT", - "marketEventQueue": "HuXriFjXMZ2eZ7VryamN5tD9YnfNbKPAcniTXyZaXMDk" - }, - { - "id": "BizWTSjfp8XTgkJdVhyyHCnhrLw6CiCmFgMW2cQUMAq4", - "baseMint": "invYVY53mcmBtf2RbVudoqKDyAgZGofkLYodvnQwQep", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "EJrVpY9YzfX4xkE6aunuadGAxBxwPebfQSANYy7GvoGo", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "786guNjxbsXyry4Vz78TkCakwNi9J7CqeHU7Mm7jJ7FA", - "targetOrders": "7MjZj4reTgAPXoKMVBepw6nHtPWCsgYcFobBTtm5hUK3", - "baseVault": "2tAkPWgCwpJrsuo8kQpQ5LxQ1rqtPXnEqGpARqPwkWQE", - "quoteVault": "DDZntGwetsmGV2ujkRCg7VZFfRag7q8TsXTfgMyXLprw", - "withdrawQueue": "AVZ2iS4HLVq534WTepZy7zjSnTeu4w7RtnwWu1sXMWYv", - "lpVault": "AP7gsZeqzj9dTWgWzoKkneMUMsKKaY6MpLmDA8HxXUz2", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4pztxkTnMtgqeeAbERskZwDKn4DsGebu5ieUg3cPcMAC", - "marketAuthority": "H8Rtts9vECjHwwYUaMY1q2tZjBUgoDaLPCQYRspykbyG", - "marketBaseVault": "9ERi2tDGvBVfUFv7XHiSxNbca3MSwwvWsgW7EnReuY9X", - "marketQuoteVault": "6Fo84ZSHo7u1uqdLaLUiMR5J9UdTvm2gc2r1UwHf3vBw", - "marketBids": "5ZpQQrbpBc46oucd6Nyn5xYeUP2C6QZjTk1SWNAE71gd", - "marketAsks": "CNgWbx196DubFggFugkCsd5QVxEXUYaNg28D6s66Dvko", - "marketEventQueue": "2vTZ2urpQ7ZCAPRSA9V7CdTPmRhpFyaeLUQQFd4YApp9" - }, - { - "id": "BJfjJGBEfVonWvF4ES1B1QNGNfA2jQSRRbr3n5TrKqAr", - "baseMint": "FTPnEQ3NfRRZ9tvmpDW6JFrvweBE5sanxnXSpJL1dvbB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4C2mSn5TddupwGnBqRVTzoMykYfuMX8ZyHDAv1kU5TSR", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Da81DLj7dRtVbhNU7Fs7hszh9GRzAomSZMH4q6gopnW2", - "targetOrders": "ExXLuRQtvdDZxs5rFm1pbba6xKtZFZEbt51bDR2VME5X", - "baseVault": "AmiHa3zSVxupS6y5p45Mtj78PnkUfL4t95YvmVkk1tYW", - "quoteVault": "xjQqCFoQH41tH9FcqCVdh5ANAUQy2FBcjC8iMcCDtMX", - "withdrawQueue": "EtQTkjYan8gStZGEvEj5nbQ2mB3a5BogoUR3MtpEgVrA", - "lpVault": "GWf3pmUMsqQySYjgL9mBNbcWNVmfX1M1jRKy7RoCp5Dm", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "82jpxEY8AHUaBQJF5RpKVQTRUNhmixTf1seYH6chLHsU", - "marketAuthority": "2D1zUTRGD6BmjomryEju9qSjARVz1rkYbpEzbwYk85mC", - "marketBaseVault": "6sUEvyVnPEapgSRRwDg2t8UhUbdUhKoXARDNaKydBu7u", - "marketQuoteVault": "DLczw8Psnti7NCpQDbpZVkGTGTwrsRpS7xf7NHUMQ4bg", - "marketBids": "chjG2mPL1NxTc3XSUW9ZDFzqokQhUxtndUrunWG86MZ", - "marketAsks": "Hj3F1ECHotJypo5WXGpQaWywZo8V4iCoQRJbD1UF88Si", - "marketEventQueue": "CjnGdeAXC2VUb2koGe6MeHAtdaY6wgnLwB5CE6qE8SCP" - }, - { - "id": "BjUX4i8XAGtjTM5JCNWAqsFMtGj2pKicY9FXyesWRsfA", - "baseMint": "5U9QqCPhqXAJcEv9uyzFJd5zhN93vuPk1aNNkXnUfPnt", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "B7WUYJ53gda2qF6t7ekkxQK9tMpX6mhgmaMg8pGR76sb", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "E25rJiriEPnpFJk6iPw8vFKuDsNNyjLvbHRUAKL5sAmt", - "targetOrders": "3FZZEh9x8e5t3KzxGnL7c1am5sRM1ejXNwUtFYKGHqLG", - "baseVault": "5aVTRrwmX6QwDVpih9XMaUL3Lx6ETDR2tWwqfpetVNaA", - "quoteVault": "13BR7GXtYbzdgPMUQRBzfQJLPJJhbpZGU4ekC525pDsC", - "withdrawQueue": "7rsaeWsCkYR16iPDsPfLPSgmgazPdifL6Y5kbqsB54KU", - "lpVault": "2p6bJ5GiqoKbqnRzNcoxsu2c2Bk3H6ZRRCAhZUrrVAhg", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "41UQxR6MBKfkXEpeiXvouagiAZWZsEbcrGyNHHDa4LnK", - "marketAuthority": "GaM3rhGmnSrRHkZbxuFWGWe4hbNuqbKyFk4ZmRePMZQC", - "marketBaseVault": "8MKV1GumvTxdJHVrQ2HFNSTUfkGvM5eycZPwrcXduaei", - "marketQuoteVault": "WGVpTxyWHS5u7uK2m76mWjRYBBYj9iaggDfDXkh8Gvo", - "marketBids": "H3CzVGoPAxF7fQppYQ5rUfXxEKiHquMmUbFnHUwW8h26", - "marketAsks": "74485rGrN63JSE6hmTRXEPFiD4KYEMukNY9ToXg9ohu8", - "marketEventQueue": "BfKHZ2dqzZtXnqweASUWZug6fAmwv1UhyzFkHvhqU1z7" - }, - { - "id": "bjZiK6giRX6Xdk5DbDtMWumXymCGd3wWNDT716H3RBF", - "baseMint": "3HDyDDvRTmSMa5QxhUod5gEgVKmTujncwKomxrWxSb8j", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "13wzkP9tMoZ7LFBsH1Htzkvj1wXqU9fnC46Uq8XYAxEJ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8qc6WvKALgPZ7R1d78vnn3xJoZqpyTW6aa8TWSV1WMzQ", - "targetOrders": "9k79QMyyzwcN78xPS8zM6PdMotERqfRMxD8rc3HfxsA5", - "baseVault": "3WPe3e7RDasZqK9F7mSwdWaAPC5h97zyG1Zy9gCxaCjS", - "quoteVault": "BkbaehbCoFLeeaoopm3vTTzBxsgBwMCnK6Hga8xtcPxF", - "withdrawQueue": "4FaYad9TBSfekqKFQVvdBeV3MzXZPNqgXDJgpnG93xUR", - "lpVault": "3uuSXsmMpC1etL6jnQjpWxQ65XnttjuWPpNDSKPrv818", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "E5AfMWp4wtJ6TRKGwvLLBWDwKiFDnpc64AzFF34QYqpS", - "marketAuthority": "ERmrdUojjy4LVLbEhc2Fw4K6C4dWnXQpdDKwy4drAjy7", - "marketBaseVault": "Btad6qY3qCBkCoSh3cNuVJaZAmwvfu9V5gHtJigtxW9t", - "marketQuoteVault": "DSXb9L1p5cjNHYVa9pdeU5oKKUSucjh8uwN1pKgYsrt", - "marketBids": "BxjmMTriT8yp2QEJVkCKhL6S6QY6ugGSWMevbwcNvDTp", - "marketAsks": "AUCuZ9TLM7QPACizupyYmRygBXkQR7RRDo7NhNLAnHmg", - "marketEventQueue": "4y7W6pihu3rPzqj1Sv3RhGn8sx8WQw3RfQZ4no1FVRT" - }, - { - "id": "BK4Gr3DEtQFFsg9dNW31JbZAwssF4RvGj5Mj11oDg3xP", - "baseMint": "DnYLfTsnLMYVdDhnZuzekdGf8AMQ3crDR2qRfpHRe47i", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BB87jXuQ7oqXjHKdM1eTTsReoj69GVWsAt2MJRzTjM3G", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8SQ1cQep9GM29y25vFx8K4FAucLwV2Jk1xN7cRgRgdZj", - "targetOrders": "33eDvsMAG29AoyMxNBRfhBbLDV9f2RqJboVstZenmhW5", - "baseVault": "45AN8LR6oLto6Nau4vQ8qbKFhdRHtyzHLdMnhpYq8i8D", - "quoteVault": "4NrD3EDBLexZWz4notyS5mwH8YoBbesE37WxeiscJBPS", - "withdrawQueue": "7hpZkDuPBqWyAQyYNRiyDrngZsYevGfd749dbhnx8HjU", - "lpVault": "5hLYR8D3LCiFWdSePMN3gQbiF4BPFybxrCGqGYXcU2Mv", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Ea9gCEver8DBYUGSCVtFkftkF4xSeWmJG8qDbUHrv4NQ", - "marketAuthority": "6PX2RWybuq9So86qWfcxKwrBv8U6Fw1b9vfJBtkV4huq", - "marketBaseVault": "H6nArPk53iSUwuxFCb2SjGB1jYZFUk87ZyR4Gk9cp3tK", - "marketQuoteVault": "3EC15P8bkdD6RTm4f1XWdfXJ4wPvMhEtA6J6pHmaBj7p", - "marketBids": "BTyUPoAzmtyY1UUhaTztfA5Hxf2FZCqF3mxxniwRPQA3", - "marketAsks": "DjwdVjwEim2oyn4PCA8WMnCkTm257buECiFWXDEFaB6a", - "marketEventQueue": "24khTiut4grrxvQjwwCfoaZVZ6vaMoauSKcWWe1bQPQV" - }, - { - "id": "BKa1wLq7YDHPM7ZZdexVdeVjTe5Hxn7ZC178k5xVHJof", - "baseMint": "4B619RbcXbXrKTzNVgDSRiUn9wfxWgA1w1oFLveGacNy", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Dcm7wdWTgdg8ZTTXtDFhz2v8tPgqMs6d7dbuX2cdGPRZ", - "baseDecimals": 3, - "quoteDecimals": 6, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9YhBPT462iMWTuTTR3n3Zfg6pF9JMaHodHhG5c1Mscze", - "targetOrders": "9Kh4HBAbQqxrNjy89K7dAKJa88EMynWcyqwAgwi74xWe", - "baseVault": "4jhHTNFQHqPqVzuoLVVbNzWq9USUqV8iioAM6rphkRAE", - "quoteVault": "FvbrW34uG8FGP7gxSGjJZXKJUgy9rr8sSAGxYdAm9xX", - "withdrawQueue": "AmU34frX4fAGt7J3CctorRWKBKnHCi4MDJyL8NbrEahe", - "lpVault": "4bMomgcSer3Xx6sr7geMCNTXBUSJswi1khDd1igFdbNA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BJwssx5h7FqnuDnrJ3LTRb5qukJ1erUY5BfjQbpXedNG", - "marketAuthority": "CdTpv3QnyKdoCP6RUXnJXX1rjEWs9JLbUwBCXLrqRAFY", - "marketBaseVault": "29c98wfVN7i74xUy8x4Wrba1Cqin6X7LTEJE2noP8xHN", - "marketQuoteVault": "7cNamcuXYdHHgHSc47E6RWM8arGeitALWsuozCHH194Z", - "marketBids": "5BF8JeASoibFx7t4rYf5ZVUAssSWpmqcktENsQLeCJwG", - "marketAsks": "Hra161bZqT4ff8FxVaX8qHJn9BKn6wnAENMZA53VSuZg", - "marketEventQueue": "Dh8VZgPkUbd9oLaZb1rUtaMoyDCzsbUsLbxeofNou3MV" - }, - { - "id": "BkCHwbRJktSjxHbrrf9DcGFiHiXs91uRRGH6XqAy4Bny", - "baseMint": "HDLRMKW1FDz2q5Zg778CZx26UgrtnqpUDkNNJHhmVUFr", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "C3uD1e8cryqe5JTKmN93xE2mV73zscJhfVY3dyKqkfFU", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7w7UGLTv8tfRnVmYNwpo74Xau4yMaTfmm1brR3ZRxnM2", - "targetOrders": "DYyD2TahkgAHPjjspjdv1U6Bm2JpTMMQypfAfCHHN4rv", - "baseVault": "J3e8YRZfX4jL9re9BLEzoM3hrRwCRtPYDra12knX8Kg7", - "quoteVault": "5YDFweae8bYzDvLgatdsURi3UZUzQ8kgFakJvY3CJaGw", - "withdrawQueue": "EcDSXLCpfkSqJMp4fnEoRaPpXEChheinF2QKmQwDxXEV", - "lpVault": "8pu2PFpsCqTHFZ1UepVkamc3BnagmLDasiXQ9mEvcRPs", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6Ncr1AW66ttss8fM8uHCt9vdqVgD1sGz83MrEBbhKeZM", - "marketAuthority": "72fc5X4FgPoYov3NmwL2kFst1CYaMDXqM9GPn34Vpmik", - "marketBaseVault": "G45HrGzvCSC8nXaydW6fXVkJFDMY3LPptzhWAJb9yg1k", - "marketQuoteVault": "9h5pf8KLzXBKEA9jaCLHDUwzFe9dcx9bBPhxPPgBxDu9", - "marketBids": "4N9auMwnLW6rxDhbwg4jfp8XZv5vRfiwXxsbCutnxiAw", - "marketAsks": "CFJgpAsUt6dkvUMxybrLWacoBGncE5nJrh4mCXDtTuev", - "marketEventQueue": "99BPPMiQ8uQJ5PmRMiy74ogdGLTSeECbdQVgzA2neoc2" - }, - { - "id": "BkHCFaEcfDMzKNzw6q7s9dobN2erJ2Mzh9uprZeBVQA", - "baseMint": "5LSFpvLDkcdV2a3Kiyzmg5YmJsj2XDLySaXvnfP1cgLT", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "DCM5hR1xcWzsMVa85mkH5CzCYr2b23dYG87uvQMi7UZS", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3PDSQStsxMVn72ouRXLCh2e6ApvnyCRrDcmiBoVcCZCV", - "targetOrders": "5z38cqSABSuap81Dz482b6JiQLeAExSY3S2PRX3dQqW", - "baseVault": "2JvQPtg6ccWvrNAkz9o4BYrAZG4uyZJn72RPQfaGfbzo", - "quoteVault": "CB9uEgUHkjvd9pJvMHq9R2ChvSJmKymUvzSeiXHbzbju", - "withdrawQueue": "3oPQuzJhpcp7PQBLgQE4cLvSmyZWMmLfAEp7FUKWKWQF", - "lpVault": "BsTaypsnCMjVr8EcRU7GDo1QiaJvSTVfHYtwX2ocgQRD", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2UcTbUXcGgcgDPycXpshxAnpJrZxzU9rFNXYBVdDVDLG", - "marketAuthority": "GNus5NPjPJtCBfbLfffGPedWrXFCNcKgF6qCDpkhc3kK", - "marketBaseVault": "Fu41Mm4QZRagGYefvNKvGUcnpeNgQ6FPiPiGYPt3S3x1", - "marketQuoteVault": "396PGx7TPEKYGCdksPApTd4M5Sgx3Sk2RWSEyUs8s2dp", - "marketBids": "Gft2dFWaZnYBCpL7jcowjqedFRLgjicwWMisHwqn5MBp", - "marketAsks": "5kzg8yDxJeXeb34vF4Y6QsJ14uGu9rQpHtE2eZnYMd1S", - "marketEventQueue": "8DUERaZHQBYjcg44mad866EXYEoKW3V4yP5jeQbLnera" - }, - { - "id": "BKmDvZr7gMXPupF4fhpqJSXWbf7YDBnnordujgMeSucW", - "baseMint": "78ZnfsncDVyhE2HVPe5LscUrgKsJpwP3wJDHRF2TuC1v", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Gm3nGKVVkUN1CBvsXNC2x7VQGgHeBNCNHqzqudT4y1pm", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3XpUvAVrLJw5YKavwEnjtp3ppGUrNTA9htjNQ19PSP7m", - "targetOrders": "HKZTcPkvhqe9yiXERipje7yGaL1x6H7ZzVGmCmHmZWfH", - "baseVault": "Bxx5N4uRzGewTvAhL2VU2amoVm9Kr48efHn5uM3bUbr6", - "quoteVault": "54SCHx4Kb5meNSJH4HD1Ukzwp3RJSHrvAvU2KUHgXsSQ", - "withdrawQueue": "AZ6xfJtASjn1J5zEcmzR5B59hcGBDjwMGjuiy81rzgA", - "lpVault": "BNwU54C7vD2PXdrLvVHtNoeQzRLPAZ9yHUJ74y94bKKY", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4XstKPuovfMAHcoMj3cJEeFeFZQh77BKcfaGng3FGsPw", - "marketAuthority": "EQ9KzqwtReS3pTyNGoUF8Jp3s64x1ZCTQyxd2pfv6HCn", - "marketBaseVault": "6BbGLQysDHnPBUrehRiPePKz5Qo6TF79Q6cfdAUG91xs", - "marketQuoteVault": "5wy5stQsubUfJjEyLu8ZMvt4YGC8eHRaDDpQFvRHsr3x", - "marketBids": "DHBGGpaxPXRQz2w4ZdAUmBe1t9EN7evy93eiK4VjqNVk", - "marketAsks": "CSuR98B5abLHUBhYM6nPqcULrTHuUVZkPkTxsGpHzBBk", - "marketEventQueue": "ASaijAywb4r4hRErwnUeYi3NKSXh5sy7uiAWsay7PHAT" - }, - { - "id": "BLESJZE1vSBUNqzgWSDEvtgzvXZwmyW17La5ch971yGs", - "baseMint": "2FkuyFr3N9RzvVahPqzXKfa8H9KhYpChwQZSeMKkkVPJ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BsmpDKH9PGhDAmPWaCTnp24MaX8cNy17BRHG4USADGRZ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "JBSTdjrfE397Wqem1rpmCuTcfUYzCxqpex3gLin4mPNv", - "targetOrders": "7gESBq93aYZPZFnq3QHAiARerp6iuFr1RYDxc9x1drhs", - "baseVault": "DEuyCFhpAAWTXGt1VgwgYGQT25vr9xMmkguqBwsD2me8", - "quoteVault": "CEs56zmErqyJAYf9ABtuwLJmEk7UNtJ2t9VDnsvruUBD", - "withdrawQueue": "7WhEzGbEYyQrued9x76NDxBr36rhsWDegoQ4sUvUcFsA", - "lpVault": "G8fnYpfvHZbZwgb3yjJxv6xjuJTJn2qV8tTd2pbjY7bm", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ENetSmU7WTBTcTXC7Q4WcYYw3WjgwmSFTaTECBtY1Wz9", - "marketAuthority": "CZFmtd5JNozdr11675Mo6jZQgs8QFhN3AWQPLEPQQWdW", - "marketBaseVault": "8zK4zCg4KuMWQjXcN7Gphw24kzMqNF5pwbzxiVNXhAW8", - "marketQuoteVault": "AdFLjDeM89X6w7sfD6Qj7msuBrTKbRkKbGyUksBd97SL", - "marketBids": "4Q7iWfnsP8dgs8qEFbrxhAa3tVk2QMqvDTSYhKwqiG2E", - "marketAsks": "HxJRjmfCXVzb5FcXp2cGPrEq84zkRW3B9CBGbyNWNXex", - "marketEventQueue": "BXcbsmLTe6BVGfvgUyEZazq18CDzv5RemRtq9bHHmmyS" - }, - { - "id": "BLQzSWz414GQ7VuuJhKyh3755RFcgHrxmqcWEuaXbNZG", - "baseMint": "7Nu9ZwWesTxsp6fAiPKDRZs5d8MJdVLwzGNuSURLbL1r", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GxXztxZRcRcNeuTLQFckcuPQCyY9Prqogzp6MWJbUBEn", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6rk2j9TzCUXBStHaN9M3FhTgEkMREHMwQ8BHCZjqJkXU", - "targetOrders": "3BNSYLPY26fZfNMryWRWjgLERKtsudkF2TYdmSKZkVFA", - "baseVault": "2ubntS6KyxaFS65PaT41crnW5BFs2vS5CaEZSQtg9wnq", - "quoteVault": "DdfewW9sEDJyAswebnUvtjVz5Eqx4sPn8Gv29Taupe3q", - "withdrawQueue": "CZCgBxPb2nUhBGpknXWKMrxuy4q9t2KdYpfwdDzq2GMY", - "lpVault": "Fub7YWPvp11Y3Y3KKesB47Mk4gSzgk7SKWYvkhvtVxsw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BWooNkEzGZrCjiPLd7mFv483nfPUftrCphRpYfn3hTeM", - "marketAuthority": "5ssKv5n8FwTf3TccbADi3eNVjxiSBHo5pkTp7VDaeRSL", - "marketBaseVault": "57DYt7ArYxn1huqM9sBAXyK9pwri4urL8bocjrVuMV6g", - "marketQuoteVault": "BawS4Pg3jyaNuFviUrNsSmnvTkoXL5rov2jT6ZXtnUgc", - "marketBids": "5gwroRCEoSNXtgovTocu5sgUy3GDrYpwxt32SspaubbT", - "marketAsks": "ACxt8BLdB21LJhSekXjTspm7Cz5n9iPFCHm7h2i5oYoe", - "marketEventQueue": "Foqe1wP6Ext989NotGB6HWTvBLfTH82kByaxhEB1EC9b" - }, - { - "id": "BLR7Kae1QnryMyX196WRo6nvg5hzQpcRs2LpfTCYX77U", - "baseMint": "iVNcrNE9BRZBC9Aqf753iZiZfbszeAVUoikgT9yvr2a", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "62K4P3BdZhPjzkF8rjgvX7adZ7j82ijZbG2dg8JEy7BJ", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7Prd335q7gBkJvor1wVRH4rnuAtqKZYg1Pa4g6xWHEXM", - "targetOrders": "6mNKzgYvtQ4UwixNvCstaVQvxZyMxufHQwLyxVumYDTs", - "baseVault": "HNLcv94duK6MkLFuoTCN8pEgZXgh9EyaeohimdkoRfZx", - "quoteVault": "Gb51dCpBDpjJFF6nL2Du7PwNczAsr2hFXLZLU6rCAEfU", - "withdrawQueue": "9EvpGNnjytA45c61a7NuoVJ1coNYLuhBdnFZdvBX6WbH", - "lpVault": "6JFsYcPxtwJEphHNisrJER68ySXfQkiADqCtgwai7Qb9", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4JDhmLVobWpUaV8tr3ZGAXmSp3vMf24a2D2dVfoH1E5T", - "marketAuthority": "Eos7UyWRrfuU5PB4D2D3kY5ZVj3YdSNoYSK7WosCsVSF", - "marketBaseVault": "GXQb7pVCzcRxburpaeY3utfA1sz1pgSK4GPRugjQ6Mmr", - "marketQuoteVault": "7L6WzCKKSeGyZ1P8L9UK9zzCnoJSFguH2wHfWGfPTWJM", - "marketBids": "BD6mgaiQTC13YCMWmT9hV2TTH9VpWMG8JGNCn8rLx14M", - "marketAsks": "CAfG1TSFihYBVHhwAy6Ys2CAD9rkkb3wiv7dLNu67g9r", - "marketEventQueue": "3mJbEYfyyBLGPqexGGFgW5CPVqJC1nZ7FVtav7BBJFGn" - }, - { - "id": "BmaeKh1q4Z1BMwpspXxMYbSSqEki61K1kbi8SSsBn14S", - "baseMint": "Foxy7Df6VEc1dUCr1ExZfRAqqHaifNFDd8ccvAs59DNr", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Js4jCzsTR4ijZPQpyyGm8Q5H55xFDzqG1GoL4ymxdMb", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BiK2jarQHonJYmhgGGgMoQNmxzdVphTYPGWuWEvVbL8F", - "targetOrders": "ADPJGxf6uiZUhWor8ssGvttyAf8YZbZHMa2ssaL3j3rA", - "baseVault": "5mJgEbQX9tWJdjLv5isanNw2enBtn4C7TjcQmG2NyYpY", - "quoteVault": "9a42mRsLaV8pRUN4miFeCzSJHPDbJTRr1gQHHichNwMN", - "withdrawQueue": "Bc6rNhjxrudfefyyhC6xhzvmv7Vrg4UmREB9toFpQDD7", - "lpVault": "hftcEQJ5Ba33SPJuYeqYabQnu2Zec3Hi9JT5YieTtkk", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DRpMGXJ6PB33x3G1sEJYZBMVjZmDBpGySyxZro6Fjofp", - "marketAuthority": "CnQ6EdMx9QJcBaKNDvi42KDR46VVHARp3qtAcR6ZYLHH", - "marketBaseVault": "6AzAJmBKgKfh56mPQQExjmcfhFQtXPxxA5z7Tggpb278", - "marketQuoteVault": "F8rgfoYsb44eZ72KRzo9yMJ5mdFZNxjPXjYRaN45Kd1S", - "marketBids": "BA2hEzVQdXpMUbw6NtoGmCWuntMFjkCUipdRxgePv7vN", - "marketAsks": "98CzkYPTV3njk62VseK2pk9KTj2Cydc4h7FfWz1JNbZ8", - "marketEventQueue": "CNPwu1Gt1eXpej2ScXtMSWLN4kfv4XLoueRoVC8SzC9p" - }, - { - "id": "BmbcyUrA1UUY6thZwea3NAdxcKCQxPhkvVTtQJbR4nGv", - "baseMint": "Amt5wUJREJQC5pX7Z48YSK812xmu4j3sQVupNhtsEuY8", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FAomnbJiAT9UFLKMnLtxxJkAroyjakKwUDSfnisDs34C", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8ebg2NagqUn79YdLKUuH24swLiQKNDxYZiAoqSkGKpFM", - "targetOrders": "4xXrBCf4PDSc9BmCHzgAX2izotYdVe7fDpcTbJ32Qq6y", - "baseVault": "H8K9xW1YLaARTDBnev114KLg84dpQqLsuhL1Eag8W7wK", - "quoteVault": "CHgNRY4zC5NeBM5ExCTmNDEiwcDAiTdvJHipsMuuzqBs", - "withdrawQueue": "7Ssk3GsweCkf2QuUhDGDuisbksKL7A8pTcACpdm93ogs", - "lpVault": "FAooR3kqh5WmA1vpJ2nZ3XfnG6ndUcs9tXctuP5grWY1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2Si6XDdpv5zcvYna221eZZrsjsp5xeYoz9W1TVdMdbnt", - "marketAuthority": "BguqxrQEYraiJSCnPFGj983BRckHBigXqCfrRopTqskk", - "marketBaseVault": "ADhWQdFbXNA1vhxUJ4SiUzKeXhWDB72HfEUtQjQky1jz", - "marketQuoteVault": "CFS8g6HL3A6XmoDcKRFghpGAhsgzyCUR2kqniFTdmWRv", - "marketBids": "2fnqFLoAz7R64dBDTeNs9fncjNvGaX4R8tQDEqzgkLah", - "marketAsks": "EFGUNDgtV6V7c1ZVPvuwVQCXsEacMPVudmsrwT97MUt", - "marketEventQueue": "4WR9p3LKMnZtnRe6fMcnvtLd2YsFdV13eqHVYT9Jdvor" - }, - { - "id": "BMNLN6os7pupRVfxjg46HkWFxFvgcet41hmsYMwykCZq", - "baseMint": "Avc1X8iAWLVrsnRtDK6aTyPDichkqe8YAn6ePGTuPAKH", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "9FkMwcUhGxdBgiKWaYcYyaEsSLZRzxRBvXb5dKVNjvJH", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ExTYcen9UX9meLz2NZ1Ppo1BhX4qpeuMkYVPi9AjLD7T", - "targetOrders": "C9anhjB2NHbcUeKcEUkCMhScnnM99GTNV15NFfFj7Xdc", - "baseVault": "Ba8CTmAgV2tVAD2oLyxUTDdCVN6XJjF5Hew4fVptcSKa", - "quoteVault": "EcLAQZCfYBLENUV9FLDSN489Bp7heewDM4Zg1KBxqcE", - "withdrawQueue": "CAZbjbq42E1mRoFo7B2a3iUPqKcuc4WCF6GqjwR6rSQq", - "lpVault": "DFpP7B7yhXXnAs7CytjNANiX95f267hBHGTbFV4sm4V2", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ADBLL3ZyHLR1aJsUdqa6u5XShsG4vt5vYTxhpeRLgUJ", - "marketAuthority": "HszMYtHny2nPcQiWbzxDVcJPrR51NNpwPbnWXE4YFm3U", - "marketBaseVault": "88EuU9y5SWPurXLu4ixR92j1azV7VrAsJemuBdWWuFDV", - "marketQuoteVault": "HLdLydvB6RvkjYQW3yEAAtr8Xt4vdJYqdqdntN3ogVnW", - "marketBids": "DYPpSXsYb4NE56i8MFPt8zMKhAVwoePdfmuvArjWvdce", - "marketAsks": "ts8iJtjnTPhWgpm427exNztaS63fnTfLPt3PmQMcThH", - "marketEventQueue": "ZMCAzYoBM1UCmvEb6zikruAqKjbhV96MyX5LWdskvaR" - }, - { - "id": "Bn2roC3p6j1Aunomhs92wwaK9kYhYDAZfh5dydNd4xbH", - "baseMint": "2VFkmFpyFm9DMKch4UdrdyY7WHLGrWgwJLAdKwHd5ekY", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "FyKN2ubz3ra4BWK1cAyDDvBJEVebcppzmWvGvjYQpZz5", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ADzxMYN2AE1BqmuPvMsF3ZQKSmjnbgpUXQLT4dsoPzRP", - "targetOrders": "Hyza8MhnwtuSeW1sdf36g3DenURJZXPsY3W8QmPhhsrn", - "baseVault": "GVksPTkCVPa5y4mtuBht6fLm9KkNi8UR3iqgwB7phR5k", - "quoteVault": "23BHNzEf66m2EN1omSssNZXAVCZahLN53gGNqp5NyAGD", - "withdrawQueue": "8XH1x3FPHAuLa2ztYXgqjkS4cybGNqZY6gZVD1eWEg4B", - "lpVault": "DY9Ystfp2p8kSTsCHi8Hqr3MqkxRF3HLxr5BdJ5WdJjQ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AcNYXy1KLE3F39UWKxDXBaqcXEKdnovSTkZzCm8PYQp", - "marketAuthority": "FDbAEvhWYcmS2ZMPNx9u3MLvmgkQrzKHtfgdaMREhDa3", - "marketBaseVault": "8GwNRh4XuBVyimwr9hFAtHf3Q7jJJTLYqWbtj4QgY93Q", - "marketQuoteVault": "AizDWwQPUFWvpb3kMtD5Z8pRRjmdsP6m8URZQ9QCdYL9", - "marketBids": "7BJP6wrySe2rPa1tfA5JnvYZe4yXJjm6tkcGTbmLYRw4", - "marketAsks": "DsQHJBYVLsgzjguefGtDoqLb4ycqdLL9KrQsDcHC2XwH", - "marketEventQueue": "HbMUMP6o8FRb3fEQEKGDnGNhgFrRp8YQcy6MAj3HH5RF" - }, - { - "id": "Bn4PcNqCge1PNYUTip3ycqRum1svfggAvHbjdEutP5Xz", - "baseMint": "5grpAJejHkwUaSRedSUw4vWerFGpgtc4gjVxu8GxuVRe", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "46qmQ2d3QXMs8HmSLrqFrFLx26Dws4bcFM2wqVZq7bJ2", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Eb1Ef8R3ecxvgrCKVUj9dVM8kPvc9YzW7RM6YxbxfVMa", - "targetOrders": "4Zspf3ca7SfdWwMQUYf7crg2qqLCBSkMMwnZbaGvZXt7", - "baseVault": "BjxpAZUuute45UjRTzrNFWgksBgNdXTRwtt5uP5efvmU", - "quoteVault": "HUTroG5crDaedGvF32QRw8HzkbRmWfWToVodXaqsWtUL", - "withdrawQueue": "FnhCHcCY2LXM54pwveSFu3nL5NJbdByLQYBXYQAuy36K", - "lpVault": "8x3ELtTB7VBwfWPRce64QZaHtDBmJXhnJpMxSpSpUpV5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "G6ADqeqzRU8pmFTwvEgpS5PXPgpMfGPLTLYcgTZNKqSB", - "marketAuthority": "C3ZEa21ZECnAwTw8xQ9eZShD3Cwos2tYM17rZPn33hiz", - "marketBaseVault": "87UrXWtf4QXYZYJcuiaKoR7WehzTkB8NTbbdiQo5mUhd", - "marketQuoteVault": "C3MhuQZnAA1KpwSHZWWpVpfdDSKq7Wf1tgK2d3y6c1dJ", - "marketBids": "9n59rvoW9FDp479j1q6Eus8XNuLCEpYK5ba5zUCpCFqN", - "marketAsks": "B8c356CkGKJXUvavjZr2gGYVybZoj8XPyupXigkzQCQ2", - "marketEventQueue": "Hf63wZ7E9nJwVP37ShuGbRJnftsiYn3dhbP7kYK55sNE" - }, - { - "id": "BNoQh2TeEAreYtS8D8nSDv1NpCAEBuuN253jbne2SCkW", - "baseMint": "8nHQb1ojhhVh7YRG85LDt83RUpbE9HyFWcuFhRqrY3jg", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "9wNMQ9Zgo1YseuAvNeBHin7PhyCexQpryj855FZQEGU1", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HaBZ7FmzjCxtrBMxzKb7sX4Bp9x3b4e1GYKosLQkwYRq", - "targetOrders": "8pScEjzp15qZHV47FyDRuZzeMAoRbgrqoUexoqwbLn8V", - "baseVault": "9sULRpf1kU55gB8PcA3K4YjFbr9rFYRLnMctXsw1rdBb", - "quoteVault": "3ZrZzbP89EKn4kCYXVzMNtEjKPjztdNhb1KTXfSNZXuT", - "withdrawQueue": "7MmxEX14rPpUTcLH7NG8o41F91KdRfUq2VkUxoEtZbS9", - "lpVault": "DBA2QtmkNpLeQyymdwMM5jjtmZEbvinwVUCK8uAQ6eho", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ATAw2tE7sXGtByrLk2wjxY6ajDCVkBJGxXkLwSqtSEhk", - "marketAuthority": "FvBbsKyfy4atfVooSp61PgCWUaNW4UoaRW3u4uzkgRMC", - "marketBaseVault": "28tcuqGYP4BZorFVB6NayxXUqHFew5iUrHnMji35MWSp", - "marketQuoteVault": "2wFvyDYu9ZRZVvhRW7ciE3fUz7qBD5U4wEnV3w7WCPrw", - "marketBids": "FJz1nH2Kd4UQKWjz7rfCTyZXrUGjRgKjQN2cWXnP2rry", - "marketAsks": "zxbKPA5cgdtDEoE8eYPLXqzwbennKaq9Gj4dxdBhVMw", - "marketEventQueue": "F5J6XHd61jWYDVn4b3m4qadnBUWs4dmVBv71TP1MH56f" - }, - { - "id": "BnSzvciRMQ1Vrk6QTFwhcbcMkXi9BNzqvC83zn9NR5S", - "baseMint": "BgeRyFWWGHeVouqfHfcXUxmvfkgekhrXYVqQWf63kpJB", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "Gc6LHZkYjkH3MLuFov2PPXE6twkF8FEJfnjDy4k5uqtt", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CXjDxcJyZvfeKeHR6Q4p9H8TzeHAzakkiokUp3Ke5sbB", - "targetOrders": "A4X5SL1ryP7LbAfFwLps3Cgj6UWNJ2vyyMJ6HW8x8HRE", - "baseVault": "6der6rjjcGHkkhD4S9giotazeUbVmrY9QaWuGHKTQX9K", - "quoteVault": "25GrbQ2Ypi8qti1uHnYyDiNBPmynLhN1gwZRN8X6AwbK", - "withdrawQueue": "6Qb4ofXkLRg1zrDfkoynijCJRfeXJCku6PTQZvyCpYtV", - "lpVault": "6DgedQtpw4SK5VRCSW7ZDkpjcTjVmXxauPreUsQTuqqf", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3sE4RXDyX7zj5EmjpcogEykf7e83e3fwPxiigBi3wERh", - "marketAuthority": "GYAPZwh2gSwwWvPtH4ZMczufo4kAvNcHe9jAMo4fzXkt", - "marketBaseVault": "Akyq8QVE5amhiYCQhfoyV1qctHmz6mngfYGpV8aEseaZ", - "marketQuoteVault": "6dEyCj6GATLvGeHLPw5UNbvLvmZE9SP1gBQVwGgsv8Gq", - "marketBids": "CrQAq3VuV1gUGmgqkCDSibxhwV9yWzdDovQi5EELMsPD", - "marketAsks": "HFdRPi3opwVekkrfZz3adAEsWaungTc2tqbwtBChuRjb", - "marketEventQueue": "CsxVxgcBfhDzF5vxqvRVkAEKi5FfeMEJPGnCVerCctfA" - }, - { - "id": "Bnvq1ceJM2a78hS8A6EBwHDqnXtv7q3ko9iAHwz15acc", - "baseMint": "D7cVVcfMUXXcZwkvxipRhf1etTVv8LG4k2L452NqPYJ8", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CasbV8hPoawfPEf7Y4DgeGBPJyffngFp1P6kqpzuMBZb", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Gm4R4ccVgEuwhJbWHAbbnfdugqVnviNshcThu55wD13w", - "targetOrders": "6dNz78GwqV7s8ydipUwXkxXXA4wFdcRRhBwBiVQJGqJ3", - "baseVault": "H9PoTHERfbL2RUpAXkGgY3s4HsrwrEdr8oTCEQurnekw", - "quoteVault": "4NYP4y8y6qJ9GufnQF8ySmAaD96DfgHUA2avZc9f3xwV", - "withdrawQueue": "7FrmQFirYBSzGKWmN6uSSEwtVd5YHJGyovgz1XLuLqXD", - "lpVault": "GSrhDRaNARyLbPWYKMrf8ZM6KFAB7JgqrnmsiPRM3vYP", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FCQEtJts1Sj8KTbV7R5Gd8Y3eEzv5uaCcLDgrcJHYK8k", - "marketAuthority": "4F4hfpxY1Cn8gMEjndm7tw8vWMNX7n3i6QCq1HNxEv5v", - "marketBaseVault": "6Hw9QSbyCnRbfZt45TM8smJ12dHu7na52v8S98NJJc4y", - "marketQuoteVault": "FtwVSMFYeF3uJPmMWhfVcBzxhpBzrSoxqwZzZAfSNS8M", - "marketBids": "6NjUcUhHvXagQWoJBgujrXibaSzJ6bojfXFuL7dHXPRV", - "marketAsks": "7sWr13ibuDZ6EGUKqHmpfULpzPJsBLj3DwUHNyiKijLK", - "marketEventQueue": "BKJxEcHrxxJ2jW6Wf6ASZbSXWegLs1Fy3Ys8BfbFXxDn" - }, - { - "id": "BoNxnJbMCGXyBXVFgrZATaJpRttzL4AhHdev3Q9uqfkq", - "baseMint": "FTkj421DxbS1wajE74J34BJ5a1o9ccA97PkK6mYq9hNQ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BhD64vmMzMbh1xcbukDsKjtUXQdWJ4sy6wB3zTzZULSC", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BT5xNgWJaGiA4LfdwJMxvwppkhv3vy7MKnK5oEbRZ9Mj", - "targetOrders": "FChS4eByXTrx7RWSqf8xQFvEg6BrjzLTNc3FdT4PLexc", - "baseVault": "BtmJSLBhPXEN32kUkRUQTkepHnsukzTyLU2xmw6K8m4H", - "quoteVault": "HdVL8JhZMpJ38CDLdqgioeoiWaSVszxiJJP4NVpzm65k", - "withdrawQueue": "AVgArR32rWLgvXNsv6pBpYK3nTaUTJMUnkyAHGSv9vYD", - "lpVault": "ErxY9CQX4BHkNTp6ad7b8AerNaNoQLwENaHWa7xxiH8G", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HYH4sxk2pCZMJV7pSzg1davjfJbSTVzg5onJUMAMo83r", - "marketAuthority": "9dMx5uboUkpmuVDe8F6NScBXreC27PcUKJKLx474yXeE", - "marketBaseVault": "2rpzUGdgZqsk3urVLBv13pD4i2vmxfDAJNRHJs9EUNZd", - "marketQuoteVault": "AeGkX7rZvWCS7FQHTyyccTxtBqNkrh8DUzx6fccJQDn4", - "marketBids": "Cx4cQCi8FsQ8P2dbvj3m61GvxZPnPUMUWopGpP6Sucg1", - "marketAsks": "5fdBvvjn49RTRkPz4TEaYzvHE7XvtJZxciNcqDjNtoND", - "marketEventQueue": "6RKm392kiWjeCRhSpYqP73rgJwUPWiQhuDsReWNcFtgM" - }, - { - "id": "BptuzCV7Jwc8JrAzcn6uKtdujf8np9QPmKGgSZrsPoZU", - "baseMint": "GCxgQbbvJc4UyqGCsUAUa38npzZX27EMxZwckLuWeEkt", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HHoNXyhQHoXKtCit5HgS2ABL9xhiwikumcX14ugLxj7a", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CvXXp3mhLJUqiND8UBzMdhzz1imB7U6EKtB3TXNFmf7", - "targetOrders": "CjcSsyX793pKLJ2neorkovA6k3tvMp8Uyz16YL3zjdoQ", - "baseVault": "GprtLJzBBFp7H8mXygnH48LGWrSAifL8kbRejGrxfv8h", - "quoteVault": "8wPPp2ocAmekvJjDpa5BdNm9VVR8FbCgQzTA6MGf31jv", - "withdrawQueue": "BasNAKWG7oaGT4CCmPqmvQKtegGsoyqXhpPiaRuWkUGR", - "lpVault": "8iei2Z8Zc19QPjHJzDbzYXZRCy496aqXu53RbfZJWXG7", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EVf94rka4PVbir2o8cSSqaCyB7tMSbpVyvDxW6n6DsEB", - "marketAuthority": "F6pUSzLVCgH3yrA4CMjgRcJwuaTbkYapxGPvvioJuY1s", - "marketBaseVault": "8Y7jec9Mt9ZC2ztKENsQTMvSvrZj7MKgeURBK4qNwNkp", - "marketQuoteVault": "3KCGmcV6aBKgCcMaDkoAdN7DmXAWb8UjznZ5zApL2BJV", - "marketBids": "5CvYAtD5VQR8uVVmjqwGcsv52KhXWMJirWE78cxznZLW", - "marketAsks": "6M5egLbUwKPFDzvxUfMYh283qJE8gEvqDNYpjfxbYE9X", - "marketEventQueue": "3NjegpTaonRmaQEjTTGrnWmRTKfiPxAT5kC18i4CNAcy" - }, - { - "id": "BPy8JPWpvafZMANbY6zsGT9cgYgpnAKpEEn9axgJmVTn", - "baseMint": "FZTfdpD9DzgqMDjgNrmShDsyd5MYkwQ4k1jLq1ecrmnd", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "84dA5jbXH4HPyG5MnvVuQXmAFQJ5zot3diJzDAf4TPuh", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EjAMww1cu3uTsdoUXR9JZ2XGDmeHKB3SR5m1VSmjR9RQ", - "targetOrders": "21m7Tcg8fMfY7pPT2heESq8ZXawFUL74iP1kqnZZeVNv", - "baseVault": "BpnDCy69t4ty9bF4ytNimLfg4RUFqmVt9fNwkhSU89a", - "quoteVault": "8TehLkKZ4VMFc2i4YEepGzeV3oo2aMMG99A7iWiyGdvd", - "withdrawQueue": "A5EeruuuUgHpuLy3nxiJdqBzmXaa8frFtU7QhVo2Ncee", - "lpVault": "ADod3ystEna3zT28Kwnw3CPaM6DkTK1T1X1itaaDmLaF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "G5YMJ4xjvsuqkHN5Z9time5YNyNzZLEo2MsfmCYiaQHf", - "marketAuthority": "6TsuKBjKWHRbW3Q38ZuKEbP5DyXnSSjY8h1QaA4Z6QB8", - "marketBaseVault": "61NHU9DDJUzqzkaqSSEcPWvFNeeoRGM7wX28NYd6grFb", - "marketQuoteVault": "4igTvLsrBdLgbbtKfZaT38D9F1HgNA34jtqWghy39wZa", - "marketBids": "C5zdKJK99UpnLVJhQfbDRqLhkWQ4i2iuNTHjRtc54kyi", - "marketAsks": "2k62B1RVxqT5bW9ERBrNCLrRAH3DgmEnQurNoxWcCxE4", - "marketEventQueue": "AqKL2YMjvKmpnuMgHYp89mU5BPTFZMTYw8tpRudKsWmL" - }, - { - "id": "BQf3zmrfxTqkhP7wvKHGcDMgw9niaZnB46QboosbAVuG", - "baseMint": "icex2Fy2KtXjfiAAUEHLPHu7XKDLvwiyVUPP9PNpSkF", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DVH8sqyyQ4Vdv3dpyvcZ29WETPDuxxVoL3Hoa1qQifn8", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ajpWsTXui4UpH2cEyGN7GZPr73mBhsD8AVhHAibc1Qf", - "targetOrders": "g1C1nyy25BAUW7DYKN98VZ4vxi9WUAFSAtdBcEGCDsy", - "baseVault": "7ZL7dPQEfvcQPtxPXwNaUWv9uuNLm8HiqhWdCS2LrQwJ", - "quoteVault": "6TxnY8rfozRX26zRR7xBbU9vs8ZP94DH1SfB1oUd7sS4", - "withdrawQueue": "317QvuAh3ZMkY14CM1De7XQfRaZjrUx35Jz4XDg3ApnX", - "lpVault": "912sJXXmmXYMd1mcrZrC4n1fNSyyk3u71B2jk9yUsYBi", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5A74otc6t6YCD8XGEmEnzAcENvaxujp7ZeD3d2Epr8G4", - "marketAuthority": "BsWQxA2AJXCZjprm4jhV8Dx6z7iyB4wsQiK9RVoi1MwJ", - "marketBaseVault": "F4w4wNQQm4PUH4pHhK5Uq9VuoJWgWRRdJQr9UtGE1dqf", - "marketQuoteVault": "GLCZBBrncnihzffpTiL3mQ7uGWXBhnBnFNLLDS4HmbkG", - "marketBids": "E7DEnjuNRkoaf4ST1rcCAbiWCeuYTnmWMW9xbiQVmTpy", - "marketAsks": "6C64U8VqbPwAz9JKXMgvDyhg8M41oty7i7FNCd7qDBx8", - "marketEventQueue": "Etw5n7dyjhvP5oXkyJZrdjbFwuWWssYhePFMi3EPc4Mc" - }, - { - "id": "BQhc4uUc32om6J1xJ2wpE99v2aHvbq58eC5ua4hbnwHc", - "baseMint": "3aAYh35n81F8HPG2QBdE48aYdzGFj2fsLccg91X4AcRc", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "7jfxoKZ5cT7SEPrDMv6i69PoTbuWWfmjH8CG38Q6FYwz", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "77pT4fuuFofBCSarcMCCPgqJ8RfJsw2krFGdMEaJTrGg", - "targetOrders": "hYxLFokMfzvCfDAQR11P2yR5TGsUaojzi8wYvMyVE5C", - "baseVault": "3CCNnxJ72zm4zLBabK9fqfmGtr8iW923ExgxyLdxwEKF", - "quoteVault": "681hEtNc5qcGctyoMQxfhx8oxFT2Cd6fWHYqFg37e215", - "withdrawQueue": "9F5LrYsnubEK9GhpAxo89jKHBbUWSLCUvcKTakAtQhUX", - "lpVault": "3akyop9raw6Eo6finx8JWv2Txv9Ab5ouFGqEqaNdNjZj", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3vKVpr6i1NPs82PZDRPAcdYdjdpiE2xohLs1qX397wBz", - "marketAuthority": "gAn9d7iD5iXMV2ft6mYDg3SJkDvQdPUac1vFMLVFq7f", - "marketBaseVault": "8PqkRLkE2L9r1tqYuCtB3p2aWUoyM4dEcQCwSsLDABF9", - "marketQuoteVault": "CzKp1pydtEEpdLftPuRcnjH76SXersXcf463PRjqB3E2", - "marketBids": "3SCPgtHUbQ6dQbwfft5g4xvmdMR6eBuCyQuLnGZZmxeP", - "marketAsks": "7YHokfZTCDwqbXi2Hg8ikC4By82BfsYTxeB5kjn2Uj5g", - "marketEventQueue": "J7hbZneVeToEhrQnh2WeapbZqrxKASinsFhQwBFbG4jt" - }, - { - "id": "BQo9PKAQG5kg9DJA7qQjVgdLGMPpBeqXP1TCq14ygLwH", - "baseMint": "NaFJTgvemQFfTTGAq2PR1uBny3NENWMur5k6eBsG5ii", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9QZN6uu4XnBL4BSMJXZnsdSqLLoYidyFSaH7wa2hdnmp", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GKERsJzTzV3FLcucBSTs2mAvUMtTRVEUKLEJsjdVziKj", - "targetOrders": "FJ1Wc8rcjZPeFKzXrUwJawPnYHwh4C4XXtnYJxo7CVPP", - "baseVault": "4XBkGMduAzBaUe3tddG7b2XTTwSB25cufV2sr4cJ5gDb", - "quoteVault": "AhrCzdaiKAADmM7Z76PUrtXKvEEP4dhw24mWz4m2TPeZ", - "withdrawQueue": "5kovS7iV2LKrAv6CTtGZmuRGV2ZLh33tF2a2QdawTvsa", - "lpVault": "7q2T2zKcgmjdR78Gb8VeCXu4UCn3ebJ1aUmQhAC1d8az", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "huVJXwRntbeSi6cZpEkane7wvCZo4gcmN3WNxr6gw89", - "marketAuthority": "Btj7zg3u6eSwnXw4AZAvnSHvCPLW7ymPJmujv8zYU5D", - "marketBaseVault": "BzWq3GjdnF1jfESsqcSsM2bGJQHgR9is8iZTffAerPhV", - "marketQuoteVault": "FKiUPobS5Y3kTKEgsvhgHvxEJh4SnyRz7KFs6o8b4spz", - "marketBids": "5BkFcV2Fn4hwrRvd1gZD8qy7pVG7idcUEpfbwH5Ayri9", - "marketAsks": "5JUpK8mkJWUbUNUfrNTyEAQVxK4E19KHGYHabxPVq2PK", - "marketEventQueue": "5zw1kejAMzMjqCrkXZGKfHgZS2i2HKBKZXdv3RP78TFd" - }, - { - "id": "BqPDaKeCcsT4i3PgaN4sKUvgtKLXyTC2xrKkZjMJ6GyC", - "baseMint": "ESrrTHaNKiC9saxaudX2j9iCM9r8qHRcLSrW5ypQ3W64", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "5P6Yk3HcRGJ81V8p3ZS5yF5LXD2W9Fdow8QtvkC7ya4j", - "baseDecimals": 3, - "quoteDecimals": 9, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6HRCMk7hnTmTh4sfeRQQZqoY5pLgiNP9dwBZAEwGUEwu", - "targetOrders": "8ajG9SHJgjGpRwZXKQ7W4iq3QYvdXz2c4XPoL1b6JJvL", - "baseVault": "27UZNpoiovA6FL5GnUeFpcM87PDNPWCfhK53E743a1kW", - "quoteVault": "8r4nEoLvAyqhdJqknsnUPFKHofhuND6xYLZXmC9MBCaw", - "withdrawQueue": "3VPX9GpoYrDmzJPTY5oWu49CWgPBYwRqxJv5JvEpfhcc", - "lpVault": "HwYqLnzqxoVEDMNHvbqYPZuqGfhq8UsaK2dqCQZp9W1b", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2yoDhmTVdH9kc7v6pr4bWgUEzcd9pdF2tsWtSDhSeYPf", - "marketAuthority": "EojNc4zJFUWgXkwy67qN3vhiC4bKo6TDDvjykVNYDtTp", - "marketBaseVault": "DBxVy58yeZd9ZMtncABS2yscq3pDvPdeUdWCe6Nc5G91", - "marketQuoteVault": "E83JXgL8BkTTsC9W5E9uU73ACNBUmArio1Xv1cdfGcoq", - "marketBids": "7QiVBUTKHeRrGW2y2UAoXMsdPEgrFqkUFdFbntvzmvMz", - "marketAsks": "FMiCKT3FUPDEyYpS7qtTkqsB3CXhcBN4i24ETHW57X9q", - "marketEventQueue": "5V18Yymug6LKw5LN2A79s5wrLEYYqLphEShZpGDZoHgh" - }, - { - "id": "BQu2mCsDcp9aRDCMJoi3ttVKX6rJ3oJ6h5y8sygB7Gjk", - "baseMint": "AvB7Ffmt3H16bhq7ToXb839ynKzFgJxu2WDHsR1S9Yft", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7qWSgogLDCaspzaioZrqeTdfhybsehB4f2nx2bysivKG", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7qYTPrrh5o2yiyGERQ6hKktey16Z18fe5Eei5ymhGdNb", - "targetOrders": "7txgRSwUoyXZYJaRCf5enTzrWJqfuaC34v8AAcA8dxCg", - "baseVault": "5YjN2PJTqCU5XcJqsDqfAn8JoDyjwZG1t2TcBS6pgbqX", - "quoteVault": "99yyXppyQP6rwkw6VsRZ9hHHNCTWkmuTZFag4Mkx64sG", - "withdrawQueue": "37KLRx33d3TuEMvVJJ9Z7JLqNyVQt1eG1UCBqhSqaWXz", - "lpVault": "DcPTS6aCbyJ5KP3qTGxzedDHt23KccLDSQgjyoCZVQT5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Hu2r9hfojRBM5bRXNsSAmxKx3HmUcdTn12RvdTyGn6E5", - "marketAuthority": "E6Lwx2uYGJMRNumTmRWd2Epkf7ZzpC2AAW657xnaG4Uh", - "marketBaseVault": "6doJ21Rp1HWKGcNzVTF52j922SFSjK2Yae1jNULaTG5B", - "marketQuoteVault": "7PSAHULyPzGsxyS1i47JmU5ycTSuv8Z21JXPVpnPoYei", - "marketBids": "CoKkPuF7zevgvjPDmUMJZnKDn7XmEehcPNKc3kD3Jih", - "marketAsks": "2w6BbDM5PXnL6bX5AtaucukGymgPAgcKUGxom3NV99Um", - "marketEventQueue": "EjVE2yU1vHAFWW2eMXBtMiWh9N8bttZMr8rf4zCcxrsK" - }, - { - "id": "bqUBESJfXkX1eNugzfax1XWBmLJR6G9CJSFBHmXvUDL", - "baseMint": "roCKojKezC7HhPxph5qb4UBasvmZJWgegCF57PvaV2f", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "F6FZxw1YMQ7jswLNN2TSszBhryyxjXRxFsbEXz6cQHeD", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Dpohwe2dpCCJPvMKrFf2C78KQpeCATAQ51svaSsSp6i1", - "targetOrders": "9GbYpTode3TbRrQpvBfWtiop86hak2BJ8RSGGZDz5Dfa", - "baseVault": "37qjs4qBUmJ7oA7xQozgPpSEr23EZWrCpBfxttKtpPb1", - "quoteVault": "FVLJa5oX2JAre6sk2HAGZf19UUA9oZHbKGjF6FdGs1x7", - "withdrawQueue": "2He1cAY5wobP3M3xU3Tc5tgu9VcczDuR3ixVZhAgFPEP", - "lpVault": "5Njimz3Y4t2pxUz2FKBZpa9N2b48HKTepHm7zrHtSCt5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DjxhqEq89oFnzDbv44TcGzvRcdaYSCSewb7nEzXWNuDR", - "marketAuthority": "HwYGBrZbWhezcAAm5dKfsuraBAaEw6evM6aEnhvfsQq8", - "marketBaseVault": "46N63Cx9vnfjM9jcPUp4NSyFSE5n9LndJpwsPEi2CG6i", - "marketQuoteVault": "DJXfdoEL1PFpA4QaWvK79rMn3q5nkwLrA257myts9Gig", - "marketBids": "HvrVJ3cwUfCUpDRozytafEfaD3iqLY5V7B6rjjcJUAZN", - "marketAsks": "CbSTm8bY49AWMpfjdokp26LhgSaQWGriPiWgJPbXdkUe", - "marketEventQueue": "Hyq8E2qm5UPbj7PbxAmQs6XDwHfTF5M2WPSWdSiTA35A" - }, - { - "id": "BsHVYPEvAHM7dnSdRhZSvDN5hmdDrEZUtsuckoKzTFnf", - "baseMint": "3fFHsncY59ue2HPduo1KhbZRWYRd8iek5tj88sPXMgFk", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4dkcUxtxh1fSxoN9aymndaGfFtH8VnU5i7aVUjZXmbpY", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CdLXsjUk6X8amGHxqBuTee3vyrgriiL3TUZv9uQrdj5", - "targetOrders": "9PYX7HTJGxxbELEkKYs5194TNFJSv41wF4jaoTNBQp4m", - "baseVault": "JycBKCHUfsaHBVr2CkbQQpR8MscyZvNBQmUPzokGhRx", - "quoteVault": "ARAXLAyon6i2fAA2WjWu1CZkGX1EjDuBaA6jiRHLWqg7", - "withdrawQueue": "EjicvmkVCqUqaPNDZq72rpPDXZZGb7Y9s1Ga5AB2Q9Zt", - "lpVault": "2jkE5LjDVE1QJ3yCy131tXKgFXfExi891TvE3eLXbZvB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6Z5hwBDGGfKKcEM8n5N3VtJsLjYTH8roX5v5CaGnExyQ", - "marketAuthority": "5RASGYfypHi7ebkr3XG1mBhzBfT7zk8Se7cxuTqt5ejv", - "marketBaseVault": "G8QHRZT9YVgtv6GdPsbN4PhXWmFswiv1rGkXTDyATvef", - "marketQuoteVault": "HUT3jLZi1JR6GWGvXJ8kWGXtf7iTGX922fxkLonNBLW3", - "marketBids": "776nc2Xv2KvK5TJiFHhu4xJkqLVDBWHcR8ZP4xcqPh9S", - "marketAsks": "FfJE8YR4w9TZszrHQp2X2eGrcHZv5TKdnLaNCh5eXCu1", - "marketEventQueue": "GXnt95wtfZiEcp2ZtPGmd9WtgabTms9UPSRvsFZVSosH" - }, - { - "id": "BSjutQ4SNYoSaBKovSmmkMhf3v7i6h2CKrrNpJoC76C", - "baseMint": "2XSuy8RSESbtYRBbVHxGWuoikn3B6iXKVKzN4i3owTCf", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6kzAfmLPGz8ynx9bXhXWS3YzMYx4tSwvP7ES2ayBBeuv", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AAh1c3iwbu4ns2YvxBRkE58VkDEu1vt7MdPxQKQqTSa4", - "targetOrders": "FfoJ1bSG33N36MogdnsAZZDa6oavwrHfPSmrgzUEuusR", - "baseVault": "EK1MRgnyMYsCFf6LCj3RdjMJekadwYkbTVfh8TzgDMn", - "quoteVault": "35vZzSoEUBhUZnKYDvyaei5GQ83mP1bv2WcMdmhsAThH", - "withdrawQueue": "GXHbScqSW3YT9ZmoeWpMNyjmyjrDgQunj2QQ1bzN4MR", - "lpVault": "Cyo8n4278AmYcQZDop4Zj9JLpx9Ex6DxGC1Sqn6EuWCo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AohqcP9t8y9ttheks7PWWf41ny3Zahy3WLF7mNLBuUHJ", - "marketAuthority": "Auhy86FphXAhTV9ubACUA1v4RX9uzMUYQbuwwqRBCE79", - "marketBaseVault": "6HgBSW6CNFLkToU6L5zTf77EuhgfAgkzQyjEyeRjustp", - "marketQuoteVault": "HNparEtr4qWznuvhCAEV582SB3bK1QimgVZNPEFcuNsS", - "marketBids": "7gPvhk17M2DS8CiD2YF5ZVnmPJmbU1gD3DH9uPdVD9mf", - "marketAsks": "6uK3Je6rdJxnENzNebhBmsVjG7ZXgrQ5X3yG8u9RKTQW", - "marketEventQueue": "7B1ocwotVgzMmyhQo8AVRefU2kDqoSHpaiKXqJyEdDF1" - }, - { - "id": "BstK6jhox6PfGjPcGBkW3TUQU5hsAQ6Bk4LgBrn9HbYD", - "baseMint": "DPuGqV7jq9PEbcRU7bWzuaJx5bGiaVj4cNWhWjTdWAKi", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7xsh9vnF2wmnNDtnnsmRLhQPAir6m1jLt2PCqiHERDSM", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5CTcUtnzRf1SHmJ5vKoZQtM4suybsAa9cwjaj14vt1Uo", - "targetOrders": "EvFDHcmvdQvbVC7JEsSkBZyFqLghFLxam12eD3rcY2EK", - "baseVault": "Gcn9KoNg8cecdLpH3yB343yYXDa33ubmw7D8vjbz67xv", - "quoteVault": "4aZZN5p4VjopT2EgepiLA3s31uJdAbyXfNtmK8Bm8Sj2", - "withdrawQueue": "FzzuFHXfCxL9tUDanvqJT8QBne6FTNd7AGUo8TDayM38", - "lpVault": "BadqEq9yMXZjpsGNyL4AXg1ifVfK3e1Hw2mv7U7LqhvH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5E1Bf3bei9epqu2UoPGw6gcnRPD3CKbH6huKGMJdSV5Z", - "marketAuthority": "EwtHLa2YThAC2Ei6veWuiAPAA1aQhg4ZXFax5Lu2ikEW", - "marketBaseVault": "BYm3JLdQ3yhkoaH1EH1d86dXtejf63W5WdbaoRjcbwBM", - "marketQuoteVault": "8yr325rfsm2TyeZF7c5TdhbwYAYT2jP5aMzXiMcmXp3f", - "marketBids": "4VxbYyF9sobUVx1uGqi7wMCZ8aVbRttHCusw84Gnwhc6", - "marketAsks": "7asBi8XjaPHUYMbEMh3z3deWnH7cqeY2Z8Z1XmkCwGqh", - "marketEventQueue": "8k1oJ7hSEtrCff6o4JEcKngGXgpqzV3MT9NZQZZ7wos7" - }, - { - "id": "BSZmKjRxe1SD3QXirFzx4tZvhsKoBTfYNgFJP1XWMCeR", - "baseMint": "3EkHyexJLGCvSxzn5umbtd9N69GoT4p5pfdLTFqCNP9Y", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FZHMHUi8EZFK1XNsetbGLn5HVQ3MS4kP8Qz165tQhbbK", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GWGoJyxjZMr54jcxzpVi1ZBoU3zQhrDwkuP9THdhjvmz", - "targetOrders": "Enp835Sw6YbrrYR161M5dMasSPZeMwVjEG7hxvVvwrBP", - "baseVault": "Gfv1dbLmGr3r6pmiYtHE2gr3xBC4uwzCgEDJ6Eh1PfHr", - "quoteVault": "AVb8sSTQj2ri5WziJu4YhA3N7sMFExfpCsGY1pAvNmPA", - "withdrawQueue": "4ZQdMQLih2AiuB68RkvVf3rr8WdnTptYYXppfq4BK4D3", - "lpVault": "GRtNkh2DGdgVhefXiEJr5Mk1jzWVNN7FkK8fMyPyGQS9", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HnLKrfMN64ccSbYCj4DxjgPYveSkFujYrnMr4cvPfL8", - "marketAuthority": "36ejDjDRym4qTMyTJt841aL9oj2igSFwTvS8tG6sPrEm", - "marketBaseVault": "7qmBK4WL6pNQEX6oVkcFfsK75bpg8YV7dhtvh7VVtek", - "marketQuoteVault": "EY31Je6KDbCVPKBUNVVyc6WYmYFHuhcZdhr6WmmejX1e", - "marketBids": "E8gQAvF5pMAVfqF9titGH2N5KjUgzPX6bQgRbwzSQ8yU", - "marketAsks": "84uJPqaZEmN43MmTwVvRmhTtyFCvHH2JXuxt2sakHfa8", - "marketEventQueue": "Fmf6BZEiz3hYxXePHiTZ1R1Vi6DTBk6XkfhjFDKHZwJ3" - }, - { - "id": "Bt2h6PAdRV4du4pRXh8Rs43B7bJ1ZftYP9M9vmQALUDr", - "baseMint": "52Y1RGnRFvRFUQq5r2AWpFLLFvokiiqxRocsWVpmPTU4", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3RoCa9Gh5MfbeDr9umLjb2j5DpxFERMFtYZNZd5JZ4jD", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EuXiikg4u6JWbvYGHyVR21KEmZCr1WmsdZYJwYjWEu2B", - "targetOrders": "9B1jT4oaQoT8zxV19tysVniu4mLn8kU8Axbq6i9UR1Ly", - "baseVault": "7Vf5zYRSRzyb3uVPkSZ9NwSgmH5GFSi1UCaNLJiJykkq", - "quoteVault": "3wG8FwfN2CqaQ2TQZ3Ks2JHk6fniWKEwjSXTkLrFuYYd", - "withdrawQueue": "Gt6bABqUnwrc49D9RZgfoX8GhuS8zvph3GkLASTyJTJ8", - "lpVault": "7Dykki4zgk7wN8exxad9sBvTnNaLX1JTQ684hTMRs4GQ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "D8hdjnx7KGKWDuJ3mmasWMbg1dVyf1sBR8zPnejqqz2s", - "marketAuthority": "43hqVPbhep6n4ZXc5FuESpAUH8RmpV8QoPf1Z1bgymU7", - "marketBaseVault": "GXFBYGt2DE6eFapZ9GHkmbapSeVW4FfVLj7FXUtqjTU5", - "marketQuoteVault": "78k2QeRejmZKUzDYahJam8AHxUKYVZMYMR7cFvA24Yha", - "marketBids": "ESk3Rdrg4aRW5KFR7GRqTd9g5WgYtSA84gsgMeoNFqzN", - "marketAsks": "FFo6NsaZLYAaEdS9iNEXzRpQ6docw7NF26CVPSp2cRez", - "marketEventQueue": "DC7QENBi86y28e9yNTdfoHDD2H9eWPQVhxSYMEZAD1Bn" - }, - { - "id": "Bt6PxAEgeeJQDtWdyZraFk7v1e4dUi1RR9N5xzdTpL6r", - "baseMint": "8PMHT4swUMtBzgHnh5U564N5sjPSiUz2cjEQzFnnP1Fo", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FE1grkqExgEGCEFwR4G5wrfKwRUc8BasV2Xs6yzdWxj1", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3omKUred83zTxETjaoAVF2aRnxxaTGwXaTuqKcd8N4kc", - "targetOrders": "9De3CXWpSyRzs7NWQxh3Ro3Cea9qeYwTBvy78KGGnAeo", - "baseVault": "9LTwRRvcAvXFGiae3rH6tb1vLYariPq28s6TKNfMEtbb", - "quoteVault": "ELrSxaCLdSN6dYenAQqqi46gmthjAy6nPDh4TyHBevjP", - "withdrawQueue": "4PQdyZvjDKxcP9fpuwr9d7i8E4dAnyXpwENVtiqh5dtp", - "lpVault": "DCNHWCk9QvqTLzba4V9ngFv1nKdVQpVtqpk8DrmQ5coe", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4Sg1g8U2ZuGnGYxAhc6MmX9MX7yZbrrraPkCQ9MdCPtF", - "marketAuthority": "rCFXUwdmQvRK9jtnCip3SdDm1cLn8nB6HHgEHngzfjQ", - "marketBaseVault": "F8PdvS5QFhSqgVdUFo6ivXdXC4nDEiKGc4XU97ZhCKgH", - "marketQuoteVault": "61zxdnLpgnFgdk9Jom5f6d6cZ6cTbwnC6QqmJag1N9jB", - "marketBids": "BDYAnAUSoBTtX7c8TKHeqmSy7U91V2pDg8ojvLs2fnCb", - "marketAsks": "Bdm3R8X7Vt1FpTruE9SQVESSd3BjAyFhcobPwAoK2LSw", - "marketEventQueue": "HVzqLTfcZKVC2PanNpyt8jVRJfDW8M5LgDs5NVVDa4G3" - }, - { - "id": "BtdoojsmWp8gGDo4iNfwjQFXaLbAkyo4fdkxxZbE19ay", - "baseMint": "GM4CTEsNsU5Kg22JNKkANTannrBU9Ah6SNa3BcyBA6Kj", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6bCg4frJK7HZz9yEXwzYnFjEfMzPFC7wm1aDxqcwjL66", - "baseDecimals": 3, - "quoteDecimals": 9, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FUAbwkA1xDDC4TdM55w1DwDT9NJEpBgPHaGFZFmKv4rn", - "targetOrders": "78ca4kMR63RjEj22dHzdC1jogQf4utuxc9PDHELf62DF", - "baseVault": "5Bdp9ajTqT8LzNdhMuCL3bYjsNzepj6saEU8GH4QNhdP", - "quoteVault": "3xTpyJCv6pVLRxmnCNdwGFzk1DHvBcMfS6yntdWbMfuM", - "withdrawQueue": "CqhQgacgq6VGcYSgMUK67RnwEmSFyLpgSeWwDP49rop5", - "lpVault": "BUFCSzufYqpRyPKXPtYjyHL4xGenhMhx7oTxfXqdrcNY", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3abMGQofw6nheHt3DZQa3yRT7bbZmQWu1qxHasQWotDt", - "marketAuthority": "D2SuQz9ULK1tSgKkwwSwoELFa2vVi9ZzZ7XHNABYYVDm", - "marketBaseVault": "4UKJgUAhMeHGs2JwR2GN2K6R3Ym8LxnaSPKap9yKqaz8", - "marketQuoteVault": "DpgRyfPpJtnG1jsqJK9twKGhVi28FyVTZerkmQhr5fek", - "marketBids": "26u1VoGnCjBtn9uTY6K3jk1xGcQGLCkX2cZ2pffeDURD", - "marketAsks": "7GwXfC4D4Y61eCD4aroKqq4jiHq7sMYV1PMHY6TMYskd", - "marketEventQueue": "4ZucrCZ7kCQgozt2qHckrmjRDMJjghZrnKN3r2ydqtBy" - }, - { - "id": "BtG6wY4a3tM19nW5rfzRuQ8X2EhKCn7LzUbTaUXPeQED", - "baseMint": "pH5wWJc3KhdeVQSt86DU31pdcL9c8P88x2FQoKEJVHC", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BqeoXQaX5xc6CJTZd7yw5V6iVk7cP97XNvDNQYqDvysr", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FSa9LswLNCSoaMs8qik2xEwhWAVmhpVhvYHcgURWzDC2", - "targetOrders": "JDaMTXFiSBYBYY1pPX8XtmB36t1pvq7t4SJkfw81cMsH", - "baseVault": "459jTmL9m1x7bnskd4TwAXzgw29T2b5djTc6sqRvHqRd", - "quoteVault": "6mwr8n8Psv4QipEv1rGktVtD1sZSshnVpz5SvU3Ni1PY", - "withdrawQueue": "6MvMnjrebwoESjumfwtAFNu4gdd45KVvD39mpe6eMfQc", - "lpVault": "5mKm7mzYhVsJGHajDxXb4T78T8sWT6rTzouzkSpxXbPv", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6w834mFswag84MNozv13hSBK9bvAErsh7Y5SHkWh5HVs", - "marketAuthority": "BBLfkT3gnnSEm4EjTvbEPpbeRwbuccjwHNXaWsCwAKm9", - "marketBaseVault": "E1JeChb8UNhfidE4RKWpnKT7cQwGsnF7rjYni1F5e1hc", - "marketQuoteVault": "7zdsGfA6exf4nfsrnFoFxt8vQP1ukvydeBM6ZwETLk2X", - "marketBids": "GLh8hfn3BMovAXGUNx1ejHZJF85mWfSzLUuypiaTFhyi", - "marketAsks": "LhjYfAF6EKLyFATVNF9mJnKCjDRSN5eRzu5TZhVmAKZ", - "marketEventQueue": "D1SWsTEgnrfcoGy1rByczryd89xKUmyf1HS2MBwvXHEk" - }, - { - "id": "BuAfcRjGxpZVHb9w6j68MTqL79cy6iwQmP87f2Cwsobc", - "baseMint": "tABbYiZsg2msMsPx9wZeJVJpBdCBdGBKDMTuy3XnH2V", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "J2d5zh3nUCVwvdyvSxGmA3TTB4jti9oxHhXTtZgia2fg", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GUy1SHaMAsduQGdTEDNPYUiuakCZBhu1TtS7zBYgTD8D", - "targetOrders": "G8YzzS4cT85JsGdeTVhjdrmBkB2vVusxnrKwAb3135uq", - "baseVault": "GhkXjoTMmYAzwt92eW6bSu54FoQ5aPtkPbWTVKHo644R", - "quoteVault": "CQasREP1DTGZptvWidtAMpzgydKBTQ2e9jvrdtVQpxiL", - "withdrawQueue": "4pHjQsHWupZavoAEgqQoviPb7gncMNMR3B8rgfgmr8yr", - "lpVault": "9tPTcYzfa185dTcLzWDFjwgfsLjMfe1C8hrEFnWMfJPh", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DZYL3cGUpyBfecCMm6gfduQJsoYU4XJ26X9w9jzvtEpD", - "marketAuthority": "7EWYhBgyNN8meFQ2eX4S82GZshENYJzP7YpwaoQRhGrp", - "marketBaseVault": "CWhfxnwqrWo7aZweRY3fGQrDrWaA3BeX6DZ6jqo5SsaL", - "marketQuoteVault": "JDsb3JjSvJafgSB9ywAhDrUi1WWwwX7wgGuq5Bp5hxtt", - "marketBids": "6aRxk47c46yxnU86pkpQSVfsCh86D2CjskQ9zg1hpDpo", - "marketAsks": "43TQvtSsTWadJcUhSG9vVsbRjvEYgiKvRBWjah6LS7WJ", - "marketEventQueue": "jEhZmYuwuoUzFjyPXAre7WFGy5irxgvzbxXgX2PpcMZ" - }, - { - "id": "BvigCmrpePqZXk8XmjQofgrsBP5cJhRMWiwwPTFz56zN", - "baseMint": "CpFE715P5DnDoJj9FbCRcuyHHeTXNdRnvzNkHvq1o23U", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "FdDe4kdDZkh3moVDyM8v5D285JKWJipWP8LqmVyzqXYE", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2zprdmTZ8476wowtfesmuwvK738uKrZdbEBxEwu5LQVV", - "targetOrders": "3ae6kEdjA7d6w7ycTBa9bSWuxAsfSeBgMki6Y8fkmMnZ", - "baseVault": "9pXpbc8gJ4CyqDYgddNXwnKDBiAK35awwW7bnAwjGbV3", - "quoteVault": "5YaPup9cvPJHScXDXvSWuerdLjZ1EFp47M3121REzNAy", - "withdrawQueue": "ETmJybHwU5FK2ijyEqA1emfV7nsehRBkrTnM6Pgth35Z", - "lpVault": "3ygK5P7prHUfZ759RjfH1hyWmahdssVsRoaJdTrErY8d", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9oBxugWkcbdNwVnpQyXva7LuGY1tqcrHcmzez5ss7XBJ", - "marketAuthority": "7dNhM9XQA8Nbj93kCxNrEck6CFKhSXvZeu3cd2uHxEoT", - "marketBaseVault": "GpFcnHWabkjnN47pSy4eisbfDEPMM3H9CrmynPdNUoJV", - "marketQuoteVault": "4HvuGmu7H6cSU1hyc1V6rVa2ySi3vt9QmBKNupFMTNTv", - "marketBids": "7fsdCJyyXAWWmqKXjzE8CmRGpGesxWu45583mwGBGh7Q", - "marketAsks": "Faj6qep8Yd4sjmq3id4UYnhbkJxrPAENV88c7BdjAUn1", - "marketEventQueue": "AwnTXFKE2GmVoZFy1Ld42v7owbiMwspWqQNZBVzpMKGo" - }, - { - "id": "BvoSg6occPvh9kcJVDvAtaUL6iPtTgTA4e2jbqFDvSHh", - "baseMint": "CBPfSGeSf76o3r4628k7BcZ5YBNxHh7hkCzu4AmVgk2Q", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "DqQ4M4Zs94exx1MkNXx1rtjKJ3mYV52YdLRJhEb6oTxk", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HcwB6ti2doh4GUt8DE75sGf9n1v3HJ5jEQs5t3ogKorz", - "targetOrders": "3udWtBza11giE4Ns11uzqsEgDYYrvrDaAvaKsViBRJqJ", - "baseVault": "8Y14FEPPqexMr4R3JVRQZDVjgs5GALpfoLRENoQJ6kdZ", - "quoteVault": "HCEHupL1nvtgHAQFrx3XV3RFMn9Q1iES6NLdHGQSCgb8", - "withdrawQueue": "DsT2vgPdegSNBSyfLbyMA4zjkAXazvf2QpG9JwBehNwQ", - "lpVault": "EFWaH5XZtp6KNrmNqN3hpmBuoaSTVLCQPgmdJePvX6zE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3qgfzDmQzxg8V3Yu397EWeSqotVcWTiVtZ26FWcC82iQ", - "marketAuthority": "AysDPkfbbd4Y8WQSbDAF7Q5bStWRQLqY7tNRaeFe8s7Z", - "marketBaseVault": "DSZg9699tZHwQK9TRH1rrSCgRsPs6rYLFmYtx7r4ijUT", - "marketQuoteVault": "83ciytLFvJwFjBP196BvRC82YmYGPSELygU9hDufrbhU", - "marketBids": "5bkaC6F5Pk4zz2HWpKAeCycog7Fy8uhdtnBaA1F4ctRw", - "marketAsks": "7rpgxowDjaiZDyVsYvbJbis88WJqKQvmUWmRBLphFZZ7", - "marketEventQueue": "6bUgQkwxDKexvMfiMmLquLkAhdpDmiVSit1vCQSPYHtg" - }, - { - "id": "BvtrDbuRoeSYUJDYTXZWiFasjR2hjXdBVLaeCQ3nqKKz", - "baseMint": "5LSFpvLDkcdV2a3Kiyzmg5YmJsj2XDLySaXvnfP1cgLT", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "23Ki3fss6htv8ZVGjobe4cYJffJP1UjwK1PyVmtxE1eh", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EwB2ePgPsbQsvF2RxDCV7kZZt8i7NQEXRFmdMme3gJVs", - "targetOrders": "8Z2F9PgmJVQUvgxELwue3jWMBKd1VenpH389XJd5aECn", - "baseVault": "C3oajqHLEVscU8HTJC4sn486DvLboUaCoxKuN8jZRxur", - "quoteVault": "G68qiJRc35ND6YVexBf4EAfSgq5peHDR9YTrXaLRwd7h", - "withdrawQueue": "4fZaxjV7KhEhdXctFVEaLWqkxGLeG5n4WkCPPupFo4Hn", - "lpVault": "73MT7RFqJEpKj1tiyVWdQHseGWxXsidcFZ5tRjuM23zZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DAjtDAPrxDEKND4zT5iCqn9A9NhxpCoqqSUxHnrrFEcD", - "marketAuthority": "8hVLDbXoXD4N1gwsXDqoMfUSEXknVGpGvgbdnm5jdSxM", - "marketBaseVault": "ELuLpRX1KsaSnVSa5tnASy6rNbqnw4FsZg1SUwriY9Jr", - "marketQuoteVault": "9gUMSWCNMDyu5JBJwe39AifRLr3G7HWNWvZLqT1cJ2jy", - "marketBids": "7EgimkCc5XWccX4xvMtwYc21ZaRLuPf43iowqG9TdJwi", - "marketAsks": "CJ6shRJaEePNBhVw7yTNBYxTCoVTpfBjrZQieGW3S98c", - "marketEventQueue": "CHFnmnzNYkszNZgb7ggxhqq2vjQQ3jLGjFzS5RRJYoS3" - }, - { - "id": "BvUSV8yF6iGtzzoeGZBjeBNrwXBFZLEAmZvo9T2pHMCS", - "baseMint": "dq26LhG3MJWXFsiq9NSvK3XPF6euds4uzd2qfxrYbT9", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "GgA1eL6Wrz58u6hW8sceA159Ur9kSUXiKcivL1Evb1w2", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8xjBwfP39G6dhWooVwvheMjN9yrUxcj4yDm6pHH4zRyg", - "targetOrders": "5ds5fRe4okHGSJUiYtkerHdhwJ9jEyNrLsAPYvyL1HGZ", - "baseVault": "4r2rbTFTx4GFawGj7ahzWbiHWD8S8D7AUrRFBs9NxvMb", - "quoteVault": "FsVfudzNpoErYFkDuiNrJ7q3hW2DvBH6YWytQN2r3m42", - "withdrawQueue": "AHxp9m1c5qEix6ChapK29fvcXJNu7GLuVQR8r9PDsqiS", - "lpVault": "6nU85dJfCita3b4h28KwWHiyv3zCqPiCAVrxEdtN7sy1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Dds2nDDUpo2fhkkLvdfHUk54JvTPBdj3yyg3YxJB3AMg", - "marketAuthority": "6dc7RBrw8vWFPd2k5VH7EYz1v48Aei7nsjotFmih9Zzi", - "marketBaseVault": "DtquA6oXsYcHfvEDPdos617s9s84DqXuvnPt2FGC4VJu", - "marketQuoteVault": "Hn7MrF41fohD61G5DhezpAD5VV7rZ4ErDEKWNESRZTd5", - "marketBids": "36RuShiDEHkUfBHJ9yMFzbZDtuh6M3T3BNiL43ZYVsBm", - "marketAsks": "E9bXAHWyvUeQr11FR9HodUyQmgE443QN8ZKFaV8i2YEr", - "marketEventQueue": "42khyP8SXQtVxN81fhWLVgdmF2SPkZp5WCn1hkYpKGux" - }, - { - "id": "BvwNiLSXKGuxH5WuMo7f8K8EXbsJ4D94uFQdcGmNNgdH", - "baseMint": "BzY2yoAPi3tD5xqVqEzrSPu5CSv9Vk7V2fsjJAQLqLv8", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DEgw2xwzE8ozL7CFhwv463WpKhxD5mEt9kfZNsgnsm9i", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2H3rU1UmEgHBz54ei48G93p2ASDXjrptnCF4UtWrUbct", - "targetOrders": "FJzn53VFcxwQSGWeES8JTffkxQhgeLw47qECSkYCJeG9", - "baseVault": "Bd8gxzB8EyUMzg9fMd7KGRLt2RmTvC61oGiKh6gkTdBf", - "quoteVault": "ETkh8WmdLoWxu16WZuFBcc9v3CNSEdGpCc4hfWvbog8U", - "withdrawQueue": "BkXjQ5tG6wZUgJmc3wVRWzqA1tQ9CExd2E6DhLDkVtz2", - "lpVault": "9VtP5EFSQ8WyDeLH2NxdoX9fYsh1MkdhJpUGU9mGBRNX", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AgUSpr5zSppSY3Gdz8j1HeKZuyntd3Q9KkjkT2KcYsj", - "marketAuthority": "9nCpLwZJopBsvo6DQ7i43ZckRPpq8fz6NSBggRk4JUNk", - "marketBaseVault": "GPeajjL1hrP5WZotQKUys6VNvHTDbV8aREAzSj2RyGG7", - "marketQuoteVault": "7ufMkqMFVwLPLY8wAeuHqwxZAisRgQNfFT4cFbEVPbKS", - "marketBids": "83rdn8LjVnninxgav1vjvSMZxnUX8aCwaFxJ3SgDnA4k", - "marketAsks": "7EaXXJJ48PRKaEGZMZ5Hm5q6wbmyLf1TwEFSPN6hXBYm", - "marketEventQueue": "HoKAD4USxithBVuUCJQFm8M9GkRzvxqnSn44fMbAe2iY" - }, - { - "id": "BWQcLyhYJxcbCySaUSWRQ5ccVdzaReYzQaFAr2F7W3vj", - "baseMint": "DZhUwiHsKDNDwF2J6ibnCeULrjwXcfr8nBvpRbAHXjcC", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "8QZrsCvjJJU6PRRuiDQE7drKxCYaRrfVWz1eXwMQCdrr", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4auVuWek9KjeqyJ2j1Phuj5mGobumbQWTVsULn9JYkWx", - "targetOrders": "C1epPYzZf1hPWnB5L64RtNwQDr1mzUgJHajFhYta9vqN", - "baseVault": "5EQrW4v8eLScdYjTEnV5w1F2HhoUfiLQ5mSUppDG2bP3", - "quoteVault": "EC5hmugJ2pUXHbcwnMRuAGawFGDR4erRSoyem9FFStAp", - "withdrawQueue": "6pqTYfDRVD7ZcREQwZ5suQMh4cz3GpMNU4XyeeqQkuo9", - "lpVault": "FSuJvAcDKFT4NXMi8sxm8K2kL7Eh89MwWS3hon7i7ENv", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Hecx16CrpypJpnspJFh4uQQmCsX8BcDUmfesTMsAahKh", - "marketAuthority": "89teb85Vydcg5NG1c38nMevfnpwiDYPKfxXL4d6MuQoi", - "marketBaseVault": "CthhHMsfnVCb8pyo9L9JHKfogudpg5m6fGB2aCT51hTq", - "marketQuoteVault": "DFRbejsPuJ6k7mQUgMczL8H5wSt1hbQhvJQTcvuvdrev", - "marketBids": "8t5kuzPbevoZ8VrTHzVAJLcwawcUF4FikeW2BBdCoGTw", - "marketAsks": "2zzkkMfmBUiE8tuCWMFkjVonDympJpBMeGEpWdUMT1hU", - "marketEventQueue": "KAFXSYLQvBaDL7tgSNK4L1Vf9xgTBTKEUUvysF2F3qm" - }, - { - "id": "BwviR9neCtzNFrbKhDAYf6xwbnzoW5qNRhdeVMCMBEBR", - "baseMint": "2A5esErqMaJXhrs1i6CtjbVxTbgsY9JbDedVsuVMQ6aY", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "4dkrCPUDyA8Jd5ogCtBfybYRv16brev4rLG5XUgBKPef", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3B6hZv9P6w1S4gkZR4Ytk8SEoS6eq9DZhFAkPWpsyPVQ", - "targetOrders": "6pWR7bNqUUmgvtJpfSz63To1ftnsdfT8DEHiWQVg2Ey9", - "baseVault": "EUb2JAMTBDXTy5Cz6peetnpspLCkbtQnKQd8QA9dNN1r", - "quoteVault": "6bmxMvQ6v7LCdpBLTAxzskVyjY9b4AR2ybjUjdMnZi8S", - "withdrawQueue": "7bHT3i5gSEjrrWJjhFMBHhf9XTmqgyPqMNck5nBx9haM", - "lpVault": "BqQNtP9rao2VZYqWbvbzFyx5KdL88QEnRJbdQw8CiySw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8vas3inDTQqNwpGvMFQMV8QCriPDjUcoDiQQK9p4iXcR", - "marketAuthority": "DmtBu6LZhJNWrdsPD3SJiZJXr24VMUEAcYDpwa7jbLVG", - "marketBaseVault": "FLFRbsn9TybjdXngqYQxXP5krgopQ3dA3ipyFxJHkYxf", - "marketQuoteVault": "3txyjphJvCBb7uv83tHfwsHat8rBdqKELgmmpfnbGd3e", - "marketBids": "Dg6ZcmnztdPUbtBVmTpyianCoqoEA4SFTHVcBQwgXkSd", - "marketAsks": "89PeAhHbwfSJXnKqepuBVBRsNKDAtjwQJK1uR4RrzzG8", - "marketEventQueue": "28J3zfRBWfHzMtuRSXSaHtRr7Z12Ka7KoyRjVnyN97rS" - }, - { - "id": "BxyEMhCBgU2yNZDWZvTnQJpnoJBywCTkcNaJt58ojQbk", - "baseMint": "GmY2Rp9t5S4yD5jhgJrc47VSAa6hQiikkYi3sr9HLNZr", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "784gRnTiiqWDwu1VnfV5Vb6DruaZVpi2jUwQs4gZxSXi", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9HBwoqF6FEHfnBVNeMmzuiZYU6xHxak13iXtcyKdd2ER", - "targetOrders": "FCsm4UktsM4Std9W7qcMAPztqpewYyVBpLcatwsRPyV1", - "baseVault": "84U6GNVtEwF8iCo1bFHAbbuR3soNMDzUH6PJ2qE3Didp", - "quoteVault": "A3EmGECE4rrion1vbFZ6xmdPno5m6XVtUPtgABgAiUvS", - "withdrawQueue": "GpGmCgqUkQrFTcuZw9QqLXT2W15WEZC3o3rBsYBiP5BZ", - "lpVault": "BAX3MSGe3ydzdqjZWrMA7rbPMUzjdoDuV8PpcAP9fCKo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "NkmN7iZvKAs5kFbJUffDUSCoTNy49br6TwmriBZti1L", - "marketAuthority": "AToj9piGqW541BoE4T4WmRWrbyeezaef5dtSPN98xPkS", - "marketBaseVault": "EC87rRczfWcccpqMZ29bzEmym3xt15cL1rVnWmTwJZTH", - "marketQuoteVault": "4WXNsW6FmczN6dvX85c5inkQTHALtjKhhcL9hqQishWh", - "marketBids": "8SXh43UUrz1UT98yaSPBs1Rq6ynP6SxnXm3wKKe7A49p", - "marketAsks": "CiESiYfR2numszgHLka1STmkNu4XuVPHdKDpkGFwsZss", - "marketEventQueue": "3g8Sd9FfWkbM1qJVw5XpiXMvwmxzh9hjYDsG5PRRhS9r" - }, - { - "id": "BY3XjDsriGB6uLboLz9TVvV5B5zeeRGcRQ9yJLtd5jL8", - "baseMint": "9gUTU6idUX5CD5Doxh21YdczhaiAqKKA1BSWSPMVqKDN", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "CP5urZjrTf4tnwe9d61KYw5DEqHs1M8aE6YKNPYP63Xn", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Gg9QQMosDkQLLHwa9vCJaaL5hrzrMjV9TmgCGN4PYZ53", - "targetOrders": "3ogoqYUuvLaG8Nsfh36tzcVn1h7n515JS3fuwxCp5tsE", - "baseVault": "BLUWwN9UMFWb2NG8b82YsucJ4VxoCDtyEW2oJd7MJWiC", - "quoteVault": "DnXdTqGSpU8nRuqauHT6n9GjcbqM1wB3CirNTqvU2idg", - "withdrawQueue": "CNkunZCWY5bKbKWR9BzZ7Uz2pcEVUMeRQ4CcLqgqX4DP", - "lpVault": "DEVaDxfktS1e5URRUCdsQGPfwvooHEiSCrUnh3qVvTnD", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HhUXkcRLEik5fa2FWHax49QQVuSn9dCqfCBE827WXVx6", - "marketAuthority": "CKhGyMegiyGcdoxdkaCqYwdq1XCHdFNhm1xiJBvbkMLB", - "marketBaseVault": "FSipqq4uGuhedGj2WNNtPrYM4cPbHsCK9MqNGxhK3zC5", - "marketQuoteVault": "BFHBwmWmqAv4hkNdSvNiGiiat88DJhTSni5bJFBXhUaf", - "marketBids": "6nW4b3bL8CffgZoePqUCWMLDyXwHXCA46bE1CABUjYCq", - "marketAsks": "8dxfhCxCxbAsjdv3sGpoaP53JjpA6uxCDfVd6rnXPcoQ", - "marketEventQueue": "HSpsZDZrR88yddGdXnz4r9qsHF7PAim1VkPWcDvXK9Uj" - }, - { - "id": "BYfA7rMFCMdvtpbVVZNk2i1TMBmpW1zA1D5P9e7mpFJa", - "baseMint": "5yw793FZPCaPcuUN4F61VJh2ehsFX87zvHbCA4oRebfn", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8jxZ2hPZGTBw2KAxKj9FqkfDkoi6PdgmdjMEqdjkk8Rg", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ERPc9D6coA6LJLTwvWeShBLcMF9kTNnXkYgPpityA9f7", - "targetOrders": "CYP8BvZFoz3rynWM5r7rzAa73ULtdqUmThBxZzGY17Tw", - "baseVault": "6uF8f2ea1dDMyAoMxivypvvaKz769PxM4msBX5ZDGKKT", - "quoteVault": "E2HKubMpE3mLM1pGJAUxCzq8dDekunaAgopaDxLi1dPd", - "withdrawQueue": "HRoWXVG8pewzUcryGu9Y3Tn9JPDhFGuYLBA12uSjL3yC", - "lpVault": "BK5qkd4oakW595ZdRLv5vKDpVmCWTFGiaLsomM7kXza", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BhubUpBxgKHyaiEEEhthri8otx63aHuyHRpJKgfmkU9y", - "marketAuthority": "3JWz65TMGbWPpHynEq7VtxViFUjnxXsXUUqAqp1Wg3ge", - "marketBaseVault": "598KA6cqYiKN7pCHiWo4NNjo81cFQiGAfcyRYDk8srth", - "marketQuoteVault": "DRirawVJ99PoCy3pUazVvmf7cdgZRcZgmM13BdJVMsor", - "marketBids": "4x4MKqTy8YY11w41EaQWCab6KptxVzw5wfmetfiZo4au", - "marketAsks": "6grwqsuM2XCUKXW16v6om4fV6FT1aR729KpQ9VfzqPUQ", - "marketEventQueue": "7sbkP2P7tQbA7zx2fdVrpQNuosuZuE48aNDoy5diHtwo" - }, - { - "id": "BymuYxU1jYQSk2FCQG6XUv7fXyAt25cMnwdENSLt234w", - "baseMint": "2Tp4hCJ24aRnsLShz9U96VtTSDHuaKL7eD7vj8Stvxhn", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "87QbZLS2DHmWZvHEewCynJRatR6cbfxqgMADPiqwB7gj", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DgA7bPv6Jhcukk8Xym18fh7LMh1opJHcuFHCxQjp38uX", - "targetOrders": "J8hcPf47EA13Mc6n8LbM1GBcBLh1TrTFGoebcPXpeFgb", - "baseVault": "9S7VR64nwWNhKpWsNwGaHZz3Nqb28RYz9EXbgrjPqvF7", - "quoteVault": "Ctjfg1sCfB8Hdsx4tUHi6U8qZDoU9UQvdHCy9nzq2dzw", - "withdrawQueue": "CzezprtLSMNY5cg7KzXUmJawufiJjFSwiFQiPyyBZLAi", - "lpVault": "AK57UYi4DpTHeijrBLteYdH4njAcXEAG7jxNEk4wR7xz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FKG37ejEcvpayYJfGz76srcbkB3bGUscspT1syLvYBGE", - "marketAuthority": "5MRsc9KqRNm6qoQRmNuiViF3sjTi1DPNLaxRvi3hZUge", - "marketBaseVault": "9iakjapf5mBnt5Txb7y37WVDNqPodLgJFhucbE5fawDR", - "marketQuoteVault": "cGbb7Ppi9GTfLdB9FSLfQ1eorufKcfn9SSHbqzsBCgx", - "marketBids": "9CXLNrx8ct8G8cJYJtceA7dSax9HYYp5zz6G9S7nr8Hq", - "marketAsks": "7RszHa5wU3JvSAkbBQaVyAoEhD6KU8USBRKMHKzWZSSS", - "marketEventQueue": "Aau9LyFq8dpUdyDcdwLdvaoPZbyiRTBYFBWtAWgqbXeD" - }, - { - "id": "ByPWPwR2bhVxyHHdyiDkQXoA2k7X74y4GVQWMLi9x8oB", - "baseMint": "ARg9wfeLN4qZTxgYTYeuGtGFMmYdk5zFhBuSnTfXXUvb", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "51W88emb8QtUWYaV4u5RMc9H6cr2n4DTkzYtfUk69PDX", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "sWYVu6kFkTU9tqLs1jatsoDjR12ZkpCH3qGyyaLCL64", - "targetOrders": "6cDYiy1FgnLjYEqsbaDLrP8GFZSe5XZp1b9VxJbo1mwA", - "baseVault": "EULKyAiiMBfNuCkJotZZLyjCBh8R7txwoa43NuBRYEYn", - "quoteVault": "5Lhe8g5Am47bt2WtsUfDZp2DT93e55xJwT7qtwGpdT1o", - "withdrawQueue": "3LdVf7uS9ZJZSPMYC2nNhkiZaHsQZ1VQg6gnMnDF2i7E", - "lpVault": "5TRTQj5Zujj2uigQyHTAcR6G48qHWU8fBhuT8UQS3zBC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8jrJB3xg4FB6fgbsX9cAA62Xfg4pxVaEDU2VAy1j1Fj2", - "marketAuthority": "8xoMiLPBtstEgbXGP8uBvjCVpToVZxUEgZTp5v4PZwvg", - "marketBaseVault": "8LLceScDTLWNckfmtoKJNTPEbVu66ftPaa3jj6cQgZYR", - "marketQuoteVault": "HS4vgeok7NTGCZkEYi9ZDrUhExmwWBj294XtJCNXP6fr", - "marketBids": "6g23y6Qdv767pp2dfsMntrEYkbGsAu9hZhxBhLxUXmam", - "marketAsks": "6JF8sUqqzUJqhEwrdCHuQ4gKRJcjNyeojP1dAVFfREuG", - "marketEventQueue": "3ZQ3C5KuTdeeYe11ZEqjuFaYKkj6uie3YgLVQ9SH4MPX" - }, - { - "id": "BYy9Tf1sWxocF8QjcsKyqTxxS8rDGg7Vv7yJuNMX9Snr", - "baseMint": "Fg3NLKzwfnhtiEjnbn86wcZiGckuL5bzf61JGSqFi4ot", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "J6xX5YCRnZh6WgCztaBpCGPEdeZkuUWjwatddT2zNSnE", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "44uqhvzMj9mDEP89tKg3PJqguEo5unjp4hVQToCz7mhj", - "targetOrders": "2YZTDDXGghi1ZwQaimDsG2hv6fW7vyi3TZeCiE5BCrwK", - "baseVault": "6DtB8qSwgm6uZb1fpCVX5Mey4wRRYqzWj6CHEKWDFcat", - "quoteVault": "54fudaEqMyAdyZpETS7qR1uq3mT7V3mmPRvhpL4LjbBn", - "withdrawQueue": "F3ZatHXzRC1C3xPXccmFRqGqvfrDYbs943voU59ZAHSe", - "lpVault": "CSTWcDqFZeecPBGJYojhiN4V4ihtykGfZizqrXJxPh91", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6kz87cE7FRawuR2SrZJfZSCTg66UvcoTHpUr3W1mCuE7", - "marketAuthority": "5rBB424fmwAMKAbjuMCyEWTQ3nUCMMJygnwRPRHVDBGw", - "marketBaseVault": "AkrevTHkxedjFmPQH3WHFopCbvXHK5vBwHQ9Qsr55vED", - "marketQuoteVault": "7mVMyUWq6xrW7JVXqhywpoHBADhkgupQxamDmDo5GqEN", - "marketBids": "8Lh8LXnqirFqJX6EW8vT8x33p4FYcS2Mk4aZLrXG2mM6", - "marketAsks": "hfQCcTQ1fjHUhaLuZsvzaK6GboQpDZJW2utDfiusfKF", - "marketEventQueue": "GXwxiVkBNc7RsdV2t8rRpuDwPR6NzGzJ9wxoxXYC7x4F" - }, - { - "id": "Bz5o1k1Wgwp62rWFWeKmZS2QXpadksYWnweRqbHkB2Uw", - "baseMint": "3x7UeXDF4imKSKnizK9mYyx1M5bTNzpeALfPeB8S6XT9", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8kFRCmQTKzvtVTVEVizjP8x3WamJpuQdZaPSGeqRJJnW", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GXk8zB2jfx261MYL9CZVQWE6QvZWW7XsCZDAWY62WeAT", - "targetOrders": "CiCsab4QtCCXojhvZhDgUkVsqtXMdk75wk1rom4kyGa", - "baseVault": "GUoLosh1vELogtRCdVXQ6cCsv3fWysptbaLscoQbHTTa", - "quoteVault": "CydoNE6xVdveAkAfhF6h3oC9ETetprNc7JXxnUJZViQd", - "withdrawQueue": "BSRAyGgtuzsiqkVpe7sbRexxJYcrCXx9et7ak8tYXgx", - "lpVault": "6WEggDPA8oqcjsucNAXwhRtWf8XZGpFFbazL8XuESYt4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HkYJ3dX8CLSGyGZzfuqYiuoDjDmrDiu1vZhPtFJZa5Vt", - "marketAuthority": "3BUJDi8zccvPmuLebPgPgTT7Ezpd4Rm1bEYNzP52fvGy", - "marketBaseVault": "APHWaJSc3VSmnyqrE5eGiUkGwmenDm8wvmaa5JjLcA93", - "marketQuoteVault": "9D8ipUumTaf3GzxKq8odeAadpzwP8x2FpXT8n5DvPggx", - "marketBids": "EwkGPoRmdbqNw2jNHezF1ffKDD4RAZvk5pA3hcz1ySoL", - "marketAsks": "7qbmk2hor617sTMaqsybAx4PvhnAj5HaAddkKbfNnfgt", - "marketEventQueue": "FamSMDsKX3SYRAM6LijkjsQYN7srmv5YaxBg7QA4xTd8" - }, - { - "id": "BZB9Zy5Wm1dBkwdtdP6rTyS7HV3shMa2AgoAULtt5jUR", - "baseMint": "BrwgXmUtNd32dTKdP5teie68EmBnjGq8Wp3MukHehUBY", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6tc2NrgfGp5V9pz3ctMHs3CHnp8nHcQs3B57p2RwPCxh", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CcX36J9vyGdP7Q5JKj4ZpAqxgG48Tg3VFS35L7p29uBr", - "targetOrders": "HUGZkPdX2VVwYsx5aLAhtqQv8orb4FX5Vrp3WL372X1C", - "baseVault": "ATgU2LMfX5b1DWpaYGHh3yfrR2dW26UzG59Poey89Chd", - "quoteVault": "EQyNL22G8xhfdw5nqZe4AC4f7toWZAZxfUNgLXpic7GA", - "withdrawQueue": "3SzxqxVCoAMAmytajqxUj9y8LuEpyZwrNRF156b5xPtt", - "lpVault": "2yaqPyaDg92VL5ei31RdEZTajeWJb3o4yuycEtThgTRZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3nc3JGZJH2t7v4CDsUrVTuyB1CVPGUXksN77j17gFwjz", - "marketAuthority": "84Lsub7p5i2ruQhRpb6BZr3Y22u8k236vughNZSxhGL6", - "marketBaseVault": "71JoMnKcRSbgQLqNynhF1uRCWiFrq9fhykeSZ6xEv2xV", - "marketQuoteVault": "CAxGcTjiS2hQtJiNEgpkhaSBDAnWrZZe9s85PbzR8TjK", - "marketBids": "7PuBLfhub8zXweXrvdjAqeVt4yenfhYD3CoMwJoDaE3W", - "marketAsks": "FtYBS65jSe1xia4P3yeYexUSwytyHoHBzwcGBAynU3WU", - "marketEventQueue": "Cn5868vUhdpKFKTBJJXq5ZSKSxj5XfotoBCjsTFyUZxx" - }, - { - "id": "C1SfUdgxNMVbuXJn7z4xqZYk5S1BtnmKeHsexmTpGAeV", - "baseMint": "9z8UpvjyH17UC8FoWFvmkke4hCfMjpFyVExZy61WHH2L", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6rYHThD7ZQAWJmseRzvFro98Pg11K4hYmsHEn9nuM69", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Fua6vR45W9J7WNsUXp737zGCH8HSevjDFZE5YeLCrPP7", - "targetOrders": "BiCz1uQd16je7G7vaa3REnVoaRjTSE8hwRn4bZXYeHUY", - "baseVault": "2o2pvnrP3FKUh1vVGryWdeKMtAbusaUpGStSkoGxmiu9", - "quoteVault": "GZ1RDHmv8FDuSHoe7ztWGdfhd78wgHyN8YCLkvyBUF32", - "withdrawQueue": "CATvU3n5mRnTCEhptcG3MCQxAeYUxKr688x5RT1pXj9c", - "lpVault": "2pksNQdoap6yTrxkKGZr5FecuLdSGXDRnKmg9RYPkgJi", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3zDXVXLUPct73U5CxhW7iCASrgdqAfja2xyhsFNjnHUZ", - "marketAuthority": "4JyqkhJtBhqpY218s3WLzM3R41tzUyxTA9uiNrGZ9XoK", - "marketBaseVault": "2c5PxMFj33CaPaoQy1Lq9jb1GoSydBtVFCc96Bfc5Lx8", - "marketQuoteVault": "7a32nyb6UvZEvhE6VndjHdNFPsdaWthw56gyvtwSmBkN", - "marketBids": "J2v61VPSuV97pEqJCLQVntPaZgYVwLyHKZBiPq5RFA4p", - "marketAsks": "FRoE7fZtBFdRmwoKWvsHLtqcuBh2zk4NMG5BNwfD6KSq", - "marketEventQueue": "GZpAAJ6nNkC8CTEauCDDHg6TXbd1mVHRg1zTKyM1cGwE" - }, - { - "id": "C1xzXvvMNQ4K1NnZgoSd7nPgptMnGUxnX3NTnDxQUcGf", - "baseMint": "ERPueLaiBW48uBhqX1CvCYBv2ApHN6ZFuME1MeQGTdAi", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Dwy7vZbbPRK71pNdMM9aCBusCgRmSctm3moBXAaHJcte", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Ezp1EXmqxk8cPH6qEg5poSHTBUtVB9YcBiDEwmxrWDdL", - "targetOrders": "6XLpXU3TC3cboSycqzBrDyMhaYo57h8GUJrktGt1SiGu", - "baseVault": "B2Fih8n2H3z2F4oL1MCZRzJdtSsQbxvkfnSe8ZejTXyK", - "quoteVault": "izS526488sjjCekGfmaNsKvLGyujFT1yZohWbR23kjZ", - "withdrawQueue": "6qPQyWr367qUR7NefmCTHCtFbt8e8TdVKHzGkazkw3cz", - "lpVault": "Ea783JT4te3gECNYA74TKJ3B4KRDC7C7KwveDD38JJYp", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3mhrhTFrHtxe7uZhvzBhzneR3bD3hDyWcgEkR8EcvNZk", - "marketAuthority": "7UFdjYaDgjm86sxdc9GVxLLYUVAqE6obbvB9ZrwreP8J", - "marketBaseVault": "8TxzzY8PvvwvXaUyoLjzAhQh4BiL58WRNwHFfMTTZRme", - "marketQuoteVault": "GcrQmbPw82nWtzAbKwEq4Kaot1dLkvXbgDiYrcHffztD", - "marketBids": "5DYgsEAb4mwL6DHsnA4VP1meysXvZFvMSUhAAf2d9uB9", - "marketAsks": "36P1xPNbL363s7peiGgbR1L8vmihPQba4JuP4uzm4PDA", - "marketEventQueue": "8iVxTHr4CCYhyxMHc5aCBddmgKB5PTT3xXyGV3iv2Lbz" - }, - { - "id": "C2UNGnZqNpZxWBJRvu138mJnsN2Q38KNMyM4tvzU7kZA", - "baseMint": "873KLxCbz7s9Kc4ZzgYRtNmhfkQrhfyWGZJBmyCbC3ei", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BF5TZxLAZVaLo334UGMCP7tHB2ECSwTBVs5h1JNyoaDU", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Di35aMnEzSSHSksT65eAfjLYqM3mmL1fDgA4rNqBYJit", - "targetOrders": "8Mdd8vrCjhR6brw66H3rh14UpteeRc4JsRMYFbeF65U7", - "baseVault": "DzWWSZBDDr8TvKQ9Wst1KqSGy4vHK8qpWf5M8pimtYs", - "quoteVault": "Aeyq74gwRiXaMtPqSQvJpsKePddEz76mkPTxNsZxJa1A", - "withdrawQueue": "GwuHxBdNqCWCQVY58c9kA8925fwE2EofLPyPqv5P27N8", - "lpVault": "Fax3qyqWn53kuzjpFF6EWnxFu6Hz5kRBC5qje848Mj7n", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2wr3Ab29KNwGhtzr5HaPCyfU1qGJzTUAN4amCLZWaD1H", - "marketAuthority": "Ecof1owe4G3sSGXtWPRD1MA9hp5UvZPUeV8Dq4LTWpKh", - "marketBaseVault": "Hz4sxELQ8JmTbJsaty5q8dqPHw3AfnVSmrUR5BsyjYFd", - "marketQuoteVault": "9a7gWP81bDZ1pXPB2kcSWTDPz1zwfscsE3KpwVPeQNvW", - "marketBids": "6aEywQGbb4Vppecesy5cbUMgxdMkgV1VMbKcgaX1ZRuY", - "marketAsks": "2RdSD91fYL4uG1fva4SFrpWL9HuXMJyQZPF9mxFufFQ6", - "marketEventQueue": "BXdcgd5iXt2ftv6CHA5eepFAvK2Pra5iDifhUrDbjqhD" - }, - { - "id": "C3knsxEBqAGuWoCJufjcFEpiXpCwu6pmQxvtH2ewbbZ7", - "baseMint": "7xfKgh8vtX2RrZn21wFTQSP9jsjh7Fqo8P4igYfmxxD3", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "H1xJ8UotgfYRToUxZZZSYzfjSz8kyvtxkvdfD5FHRqGq", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8q1PuePCKNBBAcXgr4SdQB4Jx5PZvj4EeW1UHGuRLqQM", - "targetOrders": "B9zyh9hZ8Jq8nrcshSipqoQh65RMff7X3my956Te6dFz", - "baseVault": "Bhfzrvxfnkfu3CopEFQtM57B6SGQQytQ7qvswMWTLqEJ", - "quoteVault": "3TjU9hHCQhdAUxdpdWfdhtxam5U1SbJRpJZuMPjvvYVW", - "withdrawQueue": "2A3b1V1dVGrLAVF5ZxLsrpocQVGFP2Q3rUu2BFJ3DeMu", - "lpVault": "5NXvyerwktU9y7H3HpJHrPyDrKHXrWRXzXcAVoUUZLQo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "D59KvDWY6JYZ8bc9sACMPyGQh4MFT2zStTZqV1LMxYZd", - "marketAuthority": "4fXxFTz1B1imPuGLGbXEMDKZqtvYjzKHgbRdeE6h8i76", - "marketBaseVault": "EJPpGw4aH9s9r2D9wrNJY5dRZ6RnySbvSa2rqkD5a9RV", - "marketQuoteVault": "4YXCc17PrptfTrqa1ETs2aPJChAF2pVtWbhB6FTWki1j", - "marketBids": "4CDTyR9gUN8LXu8dsPQr3TZrhogWFnL2S8p7wigD5Pg4", - "marketAsks": "HWuQznfwaKa6XmdRf3PQ59zBASynVkvMDduCuknAAnaY", - "marketEventQueue": "9tAMtraccokoLw3u8x8V9Ln8a1PAM22mVF1WqPEWCwPk" - }, - { - "id": "C3N3AQXZk4L5vEAby2G1ZknCGKBBkkPWhRyGkMcNg8zB", - "baseMint": "3nrkg2aTzCNHFRVu5DjXzenxxwn2NNoTYzjkyorAHTQc", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "73U95eLmbyyvYPvvE45mFx4cmckAMNLnp63jyZM5eQYp", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Dr1g3yxaQUNcbeqmeme9CMYgcZJ9C2UkNp941Uxrp4qg", - "targetOrders": "ASTN8g3G6pvPq65fSxN37VDq1ci3SfmgcQWzS8nfagK", - "baseVault": "7aNdZpaWwweuEH91rhSaC4Bc3ZC5XkYa29X7cC4vt4B3", - "quoteVault": "5kmRrpC2PmPgXRpdx3AbSJPQDn31JDz1EdkfxHgQZRhp", - "withdrawQueue": "J6d5JrQhmPWcDK9ULZHUzrKr5nxpcchbMRCmiyNLanPi", - "lpVault": "5BXidrpREzusreRdZubeddqKMGJNFfHyziuejd95nqqx", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "21HqJUmNCfiR9aXdBHiZv1Q438AX2hfFDw1BaCPzveWB", - "marketAuthority": "F5MdbBmcGAArHmwAPkZG4CNX3ZaLCywqASuByKDw4gos", - "marketBaseVault": "6mRE1DmiASrP9W4sENZ38T6NQuTcspWmaiVhatway8bp", - "marketQuoteVault": "J5vMqyVC2pc6QDKnRkXaVj3a4f6WgbbfaWpTSCWXDire", - "marketBids": "BhyEcumudDLtcbqZ8guTMPdAiUwm2DZoHvieiSNk8gVa", - "marketAsks": "HE6Fsp8aMqZxbn11s17AUEejkJQt8yxc55eAxAGJmREL", - "marketEventQueue": "Ev6aMNMuu6bEJM7bN8cx9CkdKU2Bu2KwBgHMuQDtLtAu" - }, - { - "id": "C3rfpYF9CT4KLH9GKz1qHCFAd8DrqAXxTjuCjr8NpxFy", - "baseMint": "EAX2qUFdjw73NxJRdh2WMzD3KMdzJiie1qqVw452DCFu", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "HTL9JiMujr2DqQrSdBYU5Xk6V3NvBVDwtEvVUTpuPac7", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3hNJvd6FyQBzpWBCWGZUVuk7RN1i1dMWaJ3NggvvVvpb", - "targetOrders": "3qEJwZBW9DvoQ1Ghx8ftzRB1UHdKGo1vj3kM9TecB2mW", - "baseVault": "4yEMXahgWrjXA9HGxv53LtRYMonmS5VpMuhs6eEqLqpA", - "quoteVault": "7eSxK8sGu4ApoLDTtEXHJargEHbdFzY3fWdaMFatXqb3", - "withdrawQueue": "J441E79KiasEzwb3Vo2Npn7HugnY2nzUZZPZDbuKV4gJ", - "lpVault": "95MJChSk2aPooN7rg1p8PqKdwcy22D2m5GDbh3pRWW8c", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GfmBdzLaHeyejHMCoujRiACYegHjyWgaR9VpnMnFZsho", - "marketAuthority": "DBB3bN8xWpBGmZWqxYyBMvHUKKnt5Qhm1q85VWuFQmi9", - "marketBaseVault": "DQ2NWJziUov6psSdvsmCpMV8BecRq1Zm6J4K42eJ4aar", - "marketQuoteVault": "FdsH6LewidqTv7jNeYyUTTJGbnvpQwVjGfvQH2HxJfbK", - "marketBids": "3NQbqkyHPjBaezxdX8P2piJPfDAXvUMRmcyQseR8AJo5", - "marketAsks": "6iU9Pm6nhFYL5pKRaTomFTqLBgEuY2fttFRNaXhd4g6F", - "marketEventQueue": "CJ9TYfpJwXRTnr1tMvxobxnzVj2zqsoVDUThfza3QfcS" - }, - { - "id": "C3xgybqHGjqChuR1PxWbrNRT3da1uBZY5yKqpLB8NiUe", - "baseMint": "5iS7mxXm5cTCt93Bq4dgQpA3LU8LFLSyFfbEKJEwS9wS", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FwPVbjxS4Nc4h1Zg6dxUR5XfNhX8ZeQpVxeFJvPUAvxP", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Deo1v8gEdYdNC7XdL4qTjLcwQP9T2xgot1xsDMRrEKqG", - "targetOrders": "HbXZgKgsWDsX2KDVjamP968Y31Abx4mwtqDcXviNVsDt", - "baseVault": "Dbc4Ah5b5wGU4fDt5aNswWbGAw4PUyvzTBYVkaQeL2Dg", - "quoteVault": "DQzFo4AkDFFedr1DNiSPhVb2rQ1Bd66hUQ6DtyjcBMMG", - "withdrawQueue": "Bv7Y5WqvMhvr3HGR3LLWmK66BPKaiuuwZc1NWw5kHHnp", - "lpVault": "GyQduYSqxHCFL82dvnHoxUP9ouQvrzyNyVN9J7bpmxo2", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Hp3AVtSLcv9gztdsJyYcmuZQCkqC595QFg2qbzS2nmoQ", - "marketAuthority": "MTA6wV5E6YK51HHm2Z1bZ1jycKCZypSL3ey9RiD92S1", - "marketBaseVault": "CV5x6R7wtok8baSkkeaRJB9LtavpdUhYBEgEkxa61gDe", - "marketQuoteVault": "WChpSX2BeJ7GH8CMj8jZ4jG9M1kErT6RxxBKSwKdECV", - "marketBids": "EUcAF3SoshrT9azTiN3km1W8UxbXSBVVwyXPucgvr6Gm", - "marketAsks": "CfMUabJn1JTFkHzTYwfes22nMf2eJ1eMFEZ211akVSWB", - "marketEventQueue": "591D2wyzXm38tUxbWMLbdz55pFPSq1wqGFx5BkESmSmu" - }, - { - "id": "C4B9f4o7MBUXpo2AN6hMEdzdu6u57sXLa3Y8xiRJbKUX", - "baseMint": "H36ykN443TZ6pC8oryicCYr5YB1em4fuSyezu5aoskNv", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "X9iHSmZCc5UKCKP2d7YjKMhzo7NcGQXoK9Q1iD269dz", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "41FJkNc6Qihf8XcJb6hRM9HRsiyCokSpREKGzZypbTPE", - "targetOrders": "DmCXJFExDrmCKbZq183aGqqMrgo5fLXDVuRu6Cknt5hr", - "baseVault": "8QsZLCGfNnjgPypUHNnnCQNrsZgnCVsPnpFsTreLWpAN", - "quoteVault": "BcUUKVfopxtr3p7f3J8Lg8UwHAePQwdbeprbrB95eLiS", - "withdrawQueue": "7uHKKSpCQVzCTMifFjhfsmVkdEmH1CbfeKvRnA9Mt2qV", - "lpVault": "6seFGtknGhz4tfqUTSF2TCFH9vJjwBKaMzR3aDB5JXgA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GL2M3XXPxA3BxpbMTy7j7ajTfRUreJNEvQhUnjU1r9fF", - "marketAuthority": "75XrYFrcDQxZ4spqBD2U8PZmG6CBQ5Vij5sp569zKAYx", - "marketBaseVault": "1r5xufQNnngUW5QoRAuzMbUefBK4eBap2Ysk5gu1xuj", - "marketQuoteVault": "BurC6UT1Sg3kLhu27W4cHDKdbSfrJHGhgmgVv1aGysUr", - "marketBids": "HmMGSifwkStJqVhrkHaoWD5pdRFgxQ92EdfytUt4Mj7D", - "marketAsks": "MWEMqLjeDyYbT8t1Pwk6wrrQhCaGFACgCCAL1MC3UxG", - "marketEventQueue": "CN1vJF2gohaWuhYYz3aM9CS92wdvdRfGYCUAaTq4s6jC" - }, - { - "id": "C4kxEHz6cooVEJtaw5xRSvAfowdFh78BxE5mLy4VusrL", - "baseMint": "E1zxRweqCWzviAraKjNjqupuyYTzm1bukJgb8KiBN1sN", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "4ESp74GWAwMnddYkA7TqQLg1BypDBJDqhh2wKv2V4kn6", - "baseDecimals": 5, - "quoteDecimals": 9, - "lpDecimals": 5, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2yw4VvL5EA17Z5u7qfD7ZKcS2oz68NNiqsuArEu5fSf3", - "targetOrders": "9cbabGCFGXx7nSUX1hYUDFaYKUd5tKf82nZVc9w5KEx7", - "baseVault": "FD7igpaHwif6FTSNA3eXiLQdCayFvQ2DrMjaUt22HVo9", - "quoteVault": "4Qi2QxDwRwpCRAPfKQJ1x1wCJkvE3VuwoxDH9rqr4HLa", - "withdrawQueue": "3RbjnoXfkBiyzi2KrhcsmTwFPTkVHkoNrinfpFWFhQsQ", - "lpVault": "CFA7UrkiqCiRWH2yAV7fBV8bUviu1jZNT9RqM3MjrouX", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9Ps19oxr2jcHVUwt23WKL1YvsF2b71GBj7QfKTFrkQFH", - "marketAuthority": "2R8tNpyPhdvgGxTJxFb3uFwon3a5cjSMABSK9T89ryWp", - "marketBaseVault": "CXinxudYxdvFQF7Dzv6nkNJcwXLBLroWWrx6oSxfafzz", - "marketQuoteVault": "E4NZLaJiJv2Vpzk8QibqLrdsxESPwH6FsFySmqAZYbnB", - "marketBids": "9zmPD4jXAYX2GQ4eM12zzVd3f1gFinF2CM9rdwtWMFBn", - "marketAsks": "5cxSiXaVqZaqHkek3uEiQLZB23hmtrGB65xFidLxh3LD", - "marketEventQueue": "B17xuhJnQNQrBMy751rYJGezTkMoZwBkfdTe4DQDn75t" - }, - { - "id": "C4Y3PXGFbhqnU81YXFav8S4kSXopUBW9zeWWqkhJvf53", - "baseMint": "CerCpUTyYsyEJiq33X2dReEfXPQ5JonJFS9Pzd6u2F55", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "Ab77uuHUpVskWJ2hVyTN5AztMA4trU2u4erKcwWjv5CF", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "m2CeBK4tpZZ9Vv94bv8nsdnArnfPaowUiDToWBRfQXd", - "targetOrders": "DXQifjRpzXbiUAXw1XUfRFJzp2xSwMPdwVBYZAwjge95", - "baseVault": "5CvxMUX4RYcAExLwWRHCV689f753gjwDWy2TZswTpLC", - "quoteVault": "2QNqtGsSGcs1xR2JZ4qKXfGzoM4XVthEWeyLAvbzWnoD", - "withdrawQueue": "G9FDLAjxYacrmcXeep4WUHNy2voxFEyLFPwQHsLoG1iW", - "lpVault": "EZqkscBwNnu7grnCCRPMvTKHF4f4aNQgtDVnF4i5vokn", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3GQKSGznA6AkyAnhTQorUCwsu811z9hptAvm43Eszcmx", - "marketAuthority": "8b17YhJbixUwm3QnVypa5J2Fe5shzkZyGcCDPDVeWiYa", - "marketBaseVault": "6eeqiUXSEsfQzgXZ5FaSjhx9xbUzQ5HvT3nxz7BiYJM6", - "marketQuoteVault": "4ZpkzaUv2k4hqMoARsjf7QPM5QkXzLcgaZcnFez29sLQ", - "marketBids": "FBc6orr1PB7GNcQqG8Ds6EmzResVPHCsJnVi6B1RKtZD", - "marketAsks": "756o7CGfCuJ8bgd255VcjtEPrVZTVMnLMj84AjWDRFQE", - "marketEventQueue": "Bwkcwovdh5Jctit5s7ZqcPiUQZzYw7QUXgY4dkx8282t" - }, - { - "id": "C5yXRTp39qv5WZrfiqoqeyK6wvbqS97oBqbsDUqfZyu", - "baseMint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "D8M2wnkRwcXtiERrM9rGK7kQB58cYwZDZDhFAAYF3bT", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BUwThGpiXwei6xeAZyeSofZYAsQRwnqhyyZ3Xe3J1YAB", - "targetOrders": "3g7Ef2aZzvWo57Cggv8o8dnMLGz2NSB1BRNyvVnb8AYm", - "baseVault": "48uXZgcnxxDSipQoXMdFmvDsu3xwDsEjHnhKXVYpeHvF", - "quoteVault": "8eLo3ppAUnjwa4HekixbZ6wTkKGgcMXF3NzxYpduV3if", - "withdrawQueue": "EXmZiHK4PyJqaKTPoiNotCnugXcwvE2mwy9rperRb4p2", - "lpVault": "AasePKBkBS7ts4DqABW28jUDf7gJUe6hHdjUfspW5dqe", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8N1KkhaCYDpj3awD58d85n973EwkpeYnRp84y1kdZpMX", - "marketAuthority": "Dtz4cysczNNTUbHMqnZW2UfUm87bGecR98snGZePt2ot", - "marketBaseVault": "4noUQEJF15yMVWHc7JkWid5EKoE6XLjQEHfdN3pT43NZ", - "marketQuoteVault": "38DxyYjp4ZqAqjrvAPvDhdALYd4y91jxcpnj28hbvyky", - "marketBids": "HaAjqsdR6CzDJAioL6s9RGYL7tNC84Hv65S1Gm6MeS9s", - "marketAsks": "BQUychhbQfWHsAdTtrcy3DxPRm3dbqZTfYy1W7PQS9e", - "marketEventQueue": "3ajZQLGpAiTnX9quZyoRw1T4E5emWbTAjFtdVyfevXds" - }, - { - "id": "C614Uy93kGJrmuMRkPBUXtYu6E9MMRieKLcK3YUZGgxG", - "baseMint": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "quoteMint": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "lpMint": "D7F986x22g9uckCbQabpcw8HuJk8zRcAteDLbcCUVjm1", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "C7h3WTBikJd7675TMbuT4M5texkKz7shybVZawC5QrMj", - "targetOrders": "BLTAfLN5LMqZeg6mMRUXPQzndv7Ye69hq9jSdL6AoWT2", - "baseVault": "FBQ9mkHny2KZjfhWsjWxUYMVjYntnGN8BMPj8CBqBrSu", - "quoteVault": "4GH1jox59DJfYQJfLh3bRxguZayC8wcinSNxkRntk8pM", - "withdrawQueue": "7gz2C7rRpfD9fHe9MLPXvQ6krVQW3CwvWkt5nQqQWieq", - "lpVault": "7S8HVLmr2LJaAtuhGjBrSoi47FzbX75553ogXk69PhnR", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4qfL1GChg519LEgm8jWNuFqL3aEYLHYvcFn9i1oracr8", - "marketAuthority": "2VBsfJWzaWcCz9ZQFRG3sdsKZKEErCa9JVhPXDX54smX", - "marketBaseVault": "BXGVzHarHXSPtg46oXL4QVZANywmV9hDS4CA5iqW1b7U", - "marketQuoteVault": "DfdyA5FqHZmZZDnrSVD6nNSR4VrbZygCjNu78AuHtGoU", - "marketBids": "7T42t9FDSzH7VfK73RwutRETcQhYEm1rKn44F4ZHBVjs", - "marketAsks": "8Vhp6xyFWCs6nyHqcNohq5TVCC5oNqaEJtWd8K1nbdUh", - "marketEventQueue": "EU755FEtEmJSvMuW1H6a9BT1dryeh1mQ1FtMtpfQ29tr" - }, - { - "id": "C6j9TdnKqcZG9jfQiZ7qcVyaJYARzEkJFxHnfNDhwaYH", - "baseMint": "AR1AwFBUTQ2QNrKaY1vAMmHqqwQWGfX3bzxSaqJ76uPd", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "48UJgUS9kB21ZAG87JDC9ecSDSKVQa3G4kKxf6B6v5we", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GYtD19gPaTG17VijAwG9sdV8EytRE1AWYbDJZht38dEA", - "targetOrders": "6qmMzpp4hKPtGaPG2kY7C56Xb8TfKJgFMWaBb3t9mseR", - "baseVault": "BDDB6xyZbuUeZbBV6Js1DBV9souYHPJGn3uezCQVTN3v", - "quoteVault": "86P9hUJV5HFcbH2m9FGmL9tuG7XoXqtmPMJQc8VVrEqE", - "withdrawQueue": "HtJ4mpwLL8Myh2wqBPodirXo8EJcJt2hRMrbTeWWWtYg", - "lpVault": "5Xcx24Dm1nYtcnQ294Be3MWtk7Kg9X5GPriuw5TH8yrW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "JhfvMyGfqpYSMZBkbzY1zHW9yMmUsNPpMk1gijrBJGc", - "marketAuthority": "F32aVLH8muYPBpoPmsR8yhaJi2JyUnLmaMaWFpxerzkK", - "marketBaseVault": "46LuWsyWK2cTcz9zeDsj98d4EmgKa9NpzBhsZPYUSXxv", - "marketQuoteVault": "DMVEocomeHt73CpgxiJtLQHdsKs3KhiPYys1d8brLZEM", - "marketBids": "689dVVRsMV8TqUipnKGPc2PX311v3EPyaDsnmortjPiv", - "marketAsks": "Gdupog5bnQtPRRp58Txr5tX1ShTmQ1FM7tutstvwHptU", - "marketEventQueue": "HfyzGQzNuv2yXRQJ3vgFukh9iahRPBgQ4robeYzHw9wK" - }, - { - "id": "C6k9GBQnaLZoF7SiDS9JquMjeNyzdkGjj3QCX5Q8wLZf", - "baseMint": "9oCf3dx1PoSP1tnhNS6LBQXzixU1vkzNHvFwY1oFCD8M", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5bJkJuXHLcpgGQnbFkJgs5NmFKxcLfvwTN22xi65T5Sk", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "353WPHUsdtNkZ1a5r5yuZktbiGwfYYR3Rz5RWUuzJkww", - "targetOrders": "G6HxxW9vTEqn9w4gcQ48LeoCBewFXHFuCBJbRwWwuUxB", - "baseVault": "3BNkKjhTGbLWfALvyvijrYy29zVAfeQBBXhkGnK2BKK1", - "quoteVault": "E3jC79gnnZmoZCWk8861Y8mhPUoLmX9FewmYUqExR6pw", - "withdrawQueue": "BkiJA8fk5Y8MsDGvNpWRxu6Lnn6V81aQbivmEqChUy9z", - "lpVault": "2vDo1d7h4GQLdCerbVQpPSSdpapi4ph41AkGySVmZXot", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7ZrmgcS98TTgdxPwf2cMtCT3rysGmK3vh8NZCgVgwJdy", - "marketAuthority": "3vZLx1u36tDqxh58iikPqwqorBqLWD1nKTHG6qSm581h", - "marketBaseVault": "EqVSVRFNprCxma268F7PYrbtspBBb9GAdRnKFWGKEcxM", - "marketQuoteVault": "DZsWp5xg5YtDPtD7oojA7kFYNpBNxhw587FgdP1K7xL5", - "marketBids": "A5MfaWBuNZTqAUD9PsbxTGHhunNg5pCwQNaSNRMSXckT", - "marketAsks": "HUWEaJ3u8gVDYHqfH9RyrEPL8EVjH9H29Ba39bqFn7xv", - "marketEventQueue": "HbV8HKEcyRWcCyT7BSvP2YuTzKsh1Yc4ER7khdcgGiV4" - }, - { - "id": "C6oJob6ecXJk9GSmpY6TosrkZ4UXicaGomzqLe5ZjZMY", - "baseMint": "9k27FY1wmxKEyoMGqK4zJMT2Y8dvkiYRGM2ijjLLTrjq", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "8zjsLseeABgqtyDw2UC8RvjrAFU1P3w1wxmHaJtv7Sif", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HWpadLMSF1Lysjj4jhqvxSq3Q2q8F3Ktsvhe9oZBagve", - "targetOrders": "4sw5FGFQ5ZCf2pXAjJ8MdoM8TGgNzEXFfJfy781wLdS2", - "baseVault": "6DwjZa8uumNcEWn7jp7YaS8dV8uwrxGAEC2TQi75B4mB", - "quoteVault": "Au2Vuhug5Zx8YTNMke18Xk99iX3GBW1ohH3danGxQggV", - "withdrawQueue": "E1pu7ixZTk8YmsswpizvRazwLx9UfT7VX8SLpxR9Hjy4", - "lpVault": "3naaj7x9juQth6cTRm14Rji2YijZXD2ygFmqEdWb8ELK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BwujVUpoUY5kyvEnmT5f9BQCVykP9hZLzfDJisppuM9u", - "marketAuthority": "8rj2EQoY6uRuTM7NW11JxE5Deyp8tRu1zqFVLRcN5dnx", - "marketBaseVault": "9BLKdpvGtazcmE231UBwzjdN5ZherwJ58tXrApad5euN", - "marketQuoteVault": "DT1SvGbMXMaUZpYwggeqy94WnSMYmrGwp8nBjspmVT9E", - "marketBids": "FubTjAgzjQabmdJhwbAB4DPcwaLbpe5SpCQThQ1ZKqak", - "marketAsks": "E1uQC8Ef7ESoQqmJiACdVjAfK23vt9QYqvFo5RUBpjpX", - "marketEventQueue": "AYq1xx8p4AViYVXam7JrekzsoRt4fHXpiJoiffN7ZVhc" - }, - { - "id": "C6zmdMJmFvy5Fy8RGKkZ7Y3xvh9V1fhoWxcgPk84uAhh", - "baseMint": "5s4BYUXLuvs9ZcVDTxkTpKhThWFSpaU8GG55q2iySe2N", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HtegcusEi4s4Agny9aJT5xxP5Jb9jY2PdVmkGYkaiNq1", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7F7otJswH3yJufmcKPVGUabWZbzNyWxq2pQUpAYnssVi", - "targetOrders": "7AY5DUwZ4bFSAht4Usnf61EuTAD3c8SovXC4EUtNhH8Z", - "baseVault": "HbFo6e9PedBP93rSz2FBcWERCGWtWnesHfmMVY1xY3mM", - "quoteVault": "J4dH2JKSyhNXda5Nch4XFUyJJtHQsqFYKtyra8mWDX4X", - "withdrawQueue": "GGGGkAaStkHVCmoXB9oW5HVe3o6EqdsbCts8gVUfEvBZ", - "lpVault": "E7DtYfWKiFqyqs4i4sHBBeJWV3XT28mdkHFEeBeyKrci", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GweS5JZ6VYujdcsemAfQFaMKbCeQPsZBufFuGQixv8se", - "marketAuthority": "GYC78Hh3npXTNnwuE1osH7yxmU2MVAqUizo2qGWBQDuT", - "marketBaseVault": "BSuFgwDvYkuVRVFsB9sv2JpdVptZKEvevD2EQ7mko4rk", - "marketQuoteVault": "FX7T5BFxErLkzBJtcaaUjcnbzaSqnp54vF4K95UqUb9E", - "marketBids": "EC43yWRNbi4hDDBTkm6EomLbQb1KeAQAjwu9AJtEjriC", - "marketAsks": "6qwBiKABuDdoeDyxN2YrgUFKK9MeyVYYgUutcnDveq8q", - "marketEventQueue": "foSFALHYjHfGLXmuCuqxy6mYjPqaNtgF3s9nM2xWxYg" - }, - { - "id": "C7vDH2VTDrx8Bifw6X5Eb3Faz5TURBoRWxoCT4yokbWX", - "baseMint": "4dydh8EGNEdTz6grqnGBxpduRg55eLnwNZXoNZJetadu", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DEqEYAvZ7ixmVrb6zpm3JsDkYHXtUJiAxqXsn6yTBxLx", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3sj7J9ddtLyDuGRwZoigrE8CCRwQjCVbgRfmK23puTgT", - "targetOrders": "2cqJect4hGXffvArP1wqd3mhpfSHWZJ9FQTEw6L5Qyhd", - "baseVault": "32EcDFUxGFuWh5dzegCvN3DUgMq6AmUF1wJfZ8k6b7QW", - "quoteVault": "AtyD8NFcHbJZcWXfENY4oGqHGYT8T72Yb2qtXzi2AwBy", - "withdrawQueue": "HRU1AcDgNYvV4oBBsLrvPUzgDaGPrT6L9X5h7Pgx987i", - "lpVault": "12RetdJ6LYpDwL7FisKD278dCDqLGFnQ66rxnXnRR9N3", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FPUQrHZsPMkRErshp35Y2oFmy8Ec5xGMoC2V2hNeFoML", - "marketAuthority": "4njE4SYZzj78j9w3f1DDBUnFsWrZcbrBzvPKNJpU43dZ", - "marketBaseVault": "5XNZPpdJiE16hjkgVPeLPzgxdTiGUmnxGreYSycWUBaa", - "marketQuoteVault": "F8tgnavUFQ7JMeyESX7wgfJVmRDubwbeueJGHirjj7yD", - "marketBids": "8LvAb9dvYyYp86NEt6RduK5RPXaFJXT27A9UMRHAMTN9", - "marketAsks": "LkuuLZUJrsY8Yhqu2LngSW661BCyWDwvB1tDdHJP5EM", - "marketEventQueue": "CacUHHaJjsDELXvUjnfudFq8TLcG7xLqiLYf9Lh5AuVm" - }, - { - "id": "C7ww7uVeQceFAFnxSQBEnbbhcQKL1sqX4dywoMRSGhKg", - "baseMint": "37qK4Nc6ryVZYfNFufx97nJU6QD2hskToSdgL7VXwoJ4", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "2QQSvZYmMRBvqmJXWeSBNhDvRWQ6b4PgB5cYhVkE1xjt", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "H4WKCEgrd6TpKsga9tG3bEqMfW3Fsf3FBoMi7FDEnaoc", - "targetOrders": "8vV8bDRhm6YT5x2JruJEkLoarZc39VszJzKnGhEZF55S", - "baseVault": "7Wzh8MWzzM7GjETuEX1HHcqhbYrqR9JoCdqSmKRBAmKG", - "quoteVault": "BHR33CxrqGtgBoE7yfHZ8BbV9JQek4NFAoxh2Jp1onRW", - "withdrawQueue": "9UQX2cmGk372p1bMvrDWt7qdmkq5rDfzHTdbqx9pe35m", - "lpVault": "3EYom4fcFC8afEZKagfVQ6krZduxbKL5pL5s2FUvP7ZU", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "B1xa9PTP3kp94UN1Hb5RMywgsYgY7W7o1LG8aXBAxRTh", - "marketAuthority": "Gg75ur5tkAhdFPqhkbUZdsuLVAwkXrL35sDetNjEQByP", - "marketBaseVault": "GBV3cqYpUWw5csxu6UZay8MVriWd2Cvnw16ZBfLZFZgH", - "marketQuoteVault": "273bbejyAvuEEm3meNtXMS6pEDsZXtMnNHS5nNixHDFD", - "marketBids": "71PPyzFd8geHQFXQ9SbtVgwq3EhqMuXzM4EmsJkRCyPV", - "marketAsks": "GyJLnHuJBhhjoHHj8XHv3LS27q3YS17ZhGN6krKMauRY", - "marketEventQueue": "CvmPZznYCgRp7NXooAAry5AxTVUwoPoWpJ5yTk5Revwq" - }, - { - "id": "C9b6zwj5JkASE5Do3QzmxtCD9woNXDQBhQaMWvCazARQ", - "baseMint": "DTXaynZKH68U9jUNeRugyjVDA5nWQMM1THjBnY92XRrh", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "HkLaM4N2Yisg5RueA3bcY6EKMUmZEGFPq1YtbQntwQpS", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FZqFrrmy9H1KyDe8xpt81RCAts3ze6vL5QZd3PRTFuG1", - "targetOrders": "FPU4Sv9hh6BT23W5yo7iPQ33V6BMxWKXwEnRTeCeg6vr", - "baseVault": "JBvUtm87REB8M1hR8q9iqPMkgnBfeL1Q7PeaPkchiYvu", - "quoteVault": "2SrJpfGDwYrBvZVEGsb4CaupVzDeR5mwqfBkQerrGTk6", - "withdrawQueue": "88dMDpnh8GopxZykFEfuMtZsxXdemJC69ubEzrrnJcXt", - "lpVault": "9bu6fvwxavjh4yyxdfzJHe276bQGZzpQYLRrdXovsazd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BnWsqVB9GH3sFLi8CzEj2Kx4amaLKDg9pBETFSCoDoQD", - "marketAuthority": "GgPcFMyC1ax6uuktUihyKAZxGCzbGkboj1oRpRWmrDnt", - "marketBaseVault": "9eeZx2UEbXe59ocGucskqpffjirDkem2Mj4LdWZPFsi4", - "marketQuoteVault": "GLyatFP21AtDbn4oZihysmdU9rNUYAYijyGskDRdNVbW", - "marketBids": "RVYxR5uwZZhPyAQbFXxgKA9k2LgHM7YjAzvigtqvtW9", - "marketAsks": "F2iz6Z9KTszTBGveTVr9hFHua7toydXTy1P19MkjRYYF", - "marketEventQueue": "76CzUpyog7kk7E4xtbFVfMJgGpFPLgDnHd8BmGnyexgE" - }, - { - "id": "C9w5vDPR3ngVMgV5J8vicZaRrzSA9hm4ZEZKcVBcqztc", - "baseMint": "6Kuq8rShSWmYhrzCvymB5GyfQeKfcUb18VHsACw9E7Hf", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "CMXPq3wH4hYyhU5H2znjHmHoHwnGX727cWojsyBTRePS", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Harnbfrs3EiDYx1irsHQdAdCJbe9zNrFvs6jBuD6jsmk", - "targetOrders": "8hk5YKLeDSMAPr6kvsQyGmu2tNqGd8Tv9UstcsTf3LDP", - "baseVault": "3UMtuQeD2Tkm2VFkSr7LjLAwQkgPNuHS6Rfh2ik7vVxh", - "quoteVault": "ACKxR431wXEuic1tYtR1Hq52nirns2VHJQUUfAHeErLh", - "withdrawQueue": "E2jE4bjXACqCAuP4Es3mkgAvUsy59r6dq6XdtQabbwsh", - "lpVault": "8oH3FFpHLzPq5xScyyYp3aNkW4nSzJRHx794UCB1AzE6", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Boz65M69RRbQjRGMyMDNWo5d7gyKrKhoYVJ3okxiQbeK", - "marketAuthority": "14aggAqt5iGZ9Be7P9Gs2HyiSSMniiYH3CUN55RWcUTs", - "marketBaseVault": "F54seSEqnwdBWV1uphKuQPMn1q7v34o7MQ2K68qh6QDM", - "marketQuoteVault": "G7uCUoZcnmSwi5eBpXgfeA6VrGzwPh7f5s2BdZgnMsjm", - "marketBids": "AU9gEXshRV9f26wzvNLkF3SQEYRziD5NRF3W9Eykjj2V", - "marketAsks": "FCjebDMWnYCtxw8geVnAiB8LMVmXezxMRkwc2GeUhYQt", - "marketEventQueue": "HZSLfkzu6BtbXwnLvSjJgSGQBxTGtMCYCSPkSbkWNqp3" - }, - { - "id": "CaMxU4h9U1PfvaP2vpkJXiHuyWTqN4RNbKYqp9EaP7D6", - "baseMint": "EpnJLu5oc1UWG25jNvSzuezz1ENrxbDnLg1wQDC7Hfbw", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BWCA2HTeRrgtqaW98dKmBUrYfxuwuEUQTjizPKEhBj3q", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HSYSEzaSUKFaBXaEcJeZCdmZ92qcA1tp1RPjBMJtJHce", - "targetOrders": "EdPg9AySrnC8Uved5UZHgBhJ32SnG7L3hrbt9wWcziXg", - "baseVault": "H2QymDNUoMzADP6yu1tkn29c9GmxYopcptqCs1SbkZNz", - "quoteVault": "DnumfGssAXdbbitwYBtiCx35XgiFaAkiBxjM8mLNMYFM", - "withdrawQueue": "AYrfByAgaHoSfKsume9z98Se69rdeWE6ATW25V4d4Lp5", - "lpVault": "9RG3k4gtn9neEtkBHVHpvVDytUMMY8v78Dk7nzhwMj2Y", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EfEkcEGwfA55i6RmLNHC3PDNnYvpoM7p26DPSHeaYsEV", - "marketAuthority": "9vpEXQy8ZRf89EPkR6dv6HDhG7sksqGywytoAPAUK3Td", - "marketBaseVault": "HpatKW2tUt2EE9HyMonNCQeVgK6dQwvLhbFg3GZFRqVL", - "marketQuoteVault": "5dZVj5Uofzu98gveZqZv29J7xBJ82Q4LFsMVBNSnH9rC", - "marketBids": "EUD3NphuGRvHaeesq6AAejFL2xpbqdXCqZtNF2aG9eLK", - "marketAsks": "9CRqFr4qsvrVCUMZhPUTVkqYQk2XpHhzqzZr5Pve5NtL", - "marketEventQueue": "CxXBkVNp8GykXoq9zdoC1TssJHfrqG8fvwAY3gKq3eGy" - }, - { - "id": "CaQVYCtt3a2o611aZtZpVsgZx5368bdjD4DCf1DTWFcc", - "baseMint": "HfMVgG3fQr45JtrQD3jpVki6E5H5BSdjN8kCAvDEDKMQ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CH5r9DMz8UosyYWrdmRpFJAm42yZgjB5BeLN36rYNqKw", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DmtC5HcHEYy6SstxUeqkCXbAyrgtcSYKEb3kjMVUtaDp", - "targetOrders": "9VAYtdwfyVQtyssWUoHWQv2LLnkYBP7GRjFEppEKSpTg", - "baseVault": "bQ8Rbv4eKodfL1hkqF3kX74JxQ5h86FdzbFtwXSXMLV", - "quoteVault": "59v9YiNpHrRWNBiMPdqjKkdR2CGohWyhfuJfzPeWepQX", - "withdrawQueue": "7dGhorF7sitQuQxySExr4EKuPZ9yowoJ9JqFr9yr4PJ2", - "lpVault": "5juP5hcRH6ZeC3avRn9SCrEtY46XTnq2NQ8nijFjgufm", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FQm9ZQk68TAZv3BuvWUiRPq8V9CrB1VTQy6LJD7QFMEK", - "marketAuthority": "6f9YN54GJf8DmtPZ2AP2XZmdoqwMhpJXvBDCAHUCv9gL", - "marketBaseVault": "4m4JtJuSXTCqsuUybVQkz8msKEJtUJ7bdBnU7w2rPWME", - "marketQuoteVault": "5bGTAJ7m5EAiB3rvMc73rGAcVhHDruwVbk2HpyAyP6Sw", - "marketBids": "8HhJ536MtCBRajE5x8NfjCYqoecyNfEjUQH4j8bSvLSk", - "marketAsks": "DK7kQcvXfCrLaFAACHmDA1NfsT4eUCdvDipN85AsQg15", - "marketEventQueue": "AY6xGqs7AiFDddyjfgfCernpZZUh6vQjGjKdrbMTopzK" - }, - { - "id": "CauBeD45Ku4wUrSZsmKfHkows3qsQfAwfRVPHCaiewS7", - "baseMint": "ANAxByE6G2WjFp7A4NqtWYXb3mgruyzZYg3spfxe6Lbo", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "43tpizYYFViTme53wXApbdYyFQf2BpBUpwbMm5qXMrTo", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "vqYjbzYohFdpwgjtqJCVTpCXHrTNDwDNvgbRZkcq3vr", - "targetOrders": "ERGXAgc5wEyJa4cWrjnX1w4DBjzztgbcQMR8FS6fUsJ4", - "baseVault": "Fev3U9JzLWWgdsMHCcu5iEWS3kgZL5ukczeF2At42zRP", - "quoteVault": "6Vz9sNP2eLPevfYqxkRmEiA6SxNPf1KYt9pLmPLjaXke", - "withdrawQueue": "DTHLLbY5SJjZbSnz7MUS3jsYxZTcK7TwBKJK58kpnGX7", - "lpVault": "CY4TsteEmPyA8DyivxWuzjgsBJenWWQYko9UWFFwHjwu", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GLTFEZNsQ2RunG96ZpxpcqYXAc9sswNZNEQPnpCVQqh3", - "marketAuthority": "EkaLM98QNy4tA7iHhKH4qc7UN6a762BVFLYzEhz37MyJ", - "marketBaseVault": "C9sLJLzCeELkW2AwX1wjg1mBeo1aSAxbhkEESaw3R4LS", - "marketQuoteVault": "5fXZg1bJAcQHKj2mv8Di8k7ZMUQTEbfpne9H2rJm7nFW", - "marketBids": "9xih3cZS2PdYahmKkyNbQeeVhhQCPbqTSQEh5KDk7JJ5", - "marketAsks": "HYuXVGJRVChtk74sES6mLiysQeDqz7fPPSQJQRDzBjK5", - "marketEventQueue": "CvGSZwRi3CGEAxoANV2fQp6nhUBfNBWjDNRqnHT6fFQe" - }, - { - "id": "CccDCNEVUeaABF8x3Wc1puaBUPDZDmZcUpSHw9XDPM1E", - "baseMint": "49jpm8SpyTwaGaJfUa4AmU28hmW1HoKuqzXkgykysowU", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "58NSCWTWie7MFSb9QHEpT6QewUZ8DgG2BcaonpVAv1Vh", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BpfQpbtkxCeVx9mnrSi89N2MrvFZtt1fqoEV52PdDSNp", - "targetOrders": "4JUwP7uTfhXhXsg5Fg8UjUysDAzPgnrztrJnBkmwsDJn", - "baseVault": "2EcNomP45CWwSHfMQxE2YHXh53kJ3wmYuG1NGz8enVax", - "quoteVault": "2LLoXoZdxikpWP42KQVUVcsmHCFAGUZszQHMntJM53kM", - "withdrawQueue": "62GqiJuzqzYaDZdANBq48FyrLyu2C3ZcQ9EVvwgy56Jw", - "lpVault": "B1tH4mhjeDQLiwP4mmQ77g4Pi48ASMw2gyWg8iP7QdEZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7L1quXJb53Gwki9TiGVsEf8jrFzBJVPNMZrSJeZ7rKk5", - "marketAuthority": "C1esWppjo8HjxQpwRsTpj7jzmBBwLoY3a65DNGotSLwU", - "marketBaseVault": "4DQQBuABFcDGrQpca6vQDBMWbBxmWBAPHEg67cpvzA4R", - "marketQuoteVault": "5dm6WKQYyjXxt6iEVQKUbt3HXySJvr6oMtQe9MXTi9yL", - "marketBids": "KLPPrPDyoxGNw5cYExJDtFkDHFHugHtmdpSqKZd9ovH", - "marketAsks": "GqgpWbkcdxhnQEguCyLaJeXfkzHEAkLriANTuYMkeSzG", - "marketEventQueue": "8ZHpxw62XfzRgeTt6B3aZXwLAiBA92FcagY2fMiSJQQE" - }, - { - "id": "CcjiVqYn7aB98XSfufnVEqEVJqieSZLcCT8xftyWnKf6", - "baseMint": "FSu46jRsf9bEzX86XBkoXwF4MWqnYTRXAFiebvVuST2d", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Gdgnj6FzQpYRNxHqFvzAGSe8weihfcphsir23c8uhnBj", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4y2FyyZELHNLrF6uXYJF21LJGfeo2UxDP9Dv1HeAogmy", - "targetOrders": "9nTFujrwcrHiwd5i3rfBjz9d1by2WnDzked9K2XJ1dwV", - "baseVault": "J7BHxpYBsyGUrTe9M8vKRddgjxN2eBJ4QLHzC3PNnxMH", - "quoteVault": "HDTpW4xm162To8UmBiuAqSzhrNyogkJjNgJueGtnC4H8", - "withdrawQueue": "49as7xwDtYxWVSoVzuYHRQrfi4yhPKkZmHY5pbnkXHqo", - "lpVault": "96g6TQcUDF7kvYL7rhXNZTRdF3kE7nATu26Ptx7bkE76", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AGuz7MeE9ExpmJRvpymtSZPXFmqBoBsrnA7N2JnRSCcs", - "marketAuthority": "YGLDRoqrLv8TeZZtjGbcxox1hZnJNqgnaf71ARZ765o", - "marketBaseVault": "BxmmTShv7KepUdEjwwPUtZ6KiW7seWG3e7vZNiKUQmxZ", - "marketQuoteVault": "45szw1d5YMkKcNN3CNWSRSEjwzmx1KKahnKXiTcgotCx", - "marketBids": "BcXYrKUHdt3FqPWzyTDmNKPhzG7g31HUVYtYHDeBRnf9", - "marketAsks": "Fa2xPjcZuZzXZ4Zbk2BFe3xDx6GEVjURMLzWmJWhk1BC", - "marketEventQueue": "EsMQz7vPAm6QF1DGAPrDH7FJGwhA77GxFPkxTh9RBFxm" - }, - { - "id": "CcLTtxjvPvf4bK6qGoVz1xUSVNt5xoZ3DbF111pXtJLG", - "baseMint": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "quoteMint": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "lpMint": "9Dc6HWJ6hdbSGbCwjXhmr76xrzioCWZcxipAaADmoyNS", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6BtbmcvR8AtPnZCvmEizeep7QD8ExddmGn9xkbNzNKPW", - "targetOrders": "FVi3aTZYJwL9xBQ3f3P9HYrBwJGi8RSxVFJdBThhEnau", - "baseVault": "6E2uunrfPms6kqAk5sJDaDAHYVQHgV7MYriyBemFLiGA", - "quoteVault": "ELVghdtJ6khio2ksrMswjD4aSmRx97FV7PDmC9ZjYqmS", - "withdrawQueue": "7Kozr7Vb1aWATnNQC5Xa3GB35Mzf2G1F2XhLtusdqvxp", - "lpVault": "CZDW4tgwTcqNwpSM3DqwTzp2bhM1NvHtN2v16VVHBk52", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Ew4txCzxaWzDAaWMSPNEdjfM9sBbsH4mj1Ji3XGQyHsr", - "marketAuthority": "6k5rqdUe3LsdjFB6sTjynUYXyucm5PRUfeN6AfbXxF7b", - "marketBaseVault": "F6L2KXEGNvagM1AgFJiA1BQ8NYjH8CmQ6zWsrKj7fjuJ", - "marketQuoteVault": "GT8NHdbizUw9S9ghxjhEoaeyimW3ZR5V4CLtv55uqnWk", - "marketBids": "AFvkxyZSXnaWMW1zVKkCrN6TAVCxTqbRV31hmQQFyFmA", - "marketAsks": "Bi623hRo5R9fVWBFcGFtBQ5CtK1E8gUDJAdtVBJyHvV1", - "marketEventQueue": "FbpR2TMa3FmXsQLbL43e6PuiKRQyewBwecMKZ2F1eDax" - }, - { - "id": "CCpaZPgmDYQ5FtbCmJJDCs6ZAmD1aCLGvixjLBYLGLHC", - "baseMint": "7SEsxCsiNiYqCpYG16wx4c9u2YGLZphnEFTAU9ENAizD", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "GgCkFni9gcHzMBMEbQp3zXyH13VxH8H9oGdXP1ktYCLz", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DJXTWtSZ1cRQapC8F1gwfDi8bBRjmsMzfFAMQagmFw4W", - "targetOrders": "C9Ar87Xa2TQVF55eGn7xvHjjJbou6R4rnGiDUtd4Z2Xu", - "baseVault": "AWJ7bCTCCpcr7qroKFFLoR2DsAU2wrGWs4oVqjpBoANz", - "quoteVault": "GUNX4Vx5GGEcDgtCK586fJr7UyDzhVACuTZaTssuRFRc", - "withdrawQueue": "GzLjsE9Afu5qPuHQSXEGM5sx3aDfbLbhCt2jaPwTq14G", - "lpVault": "BTB9w4TQ7pbTyLkV7hDV5BMPayHjtFiqpr4DJ5PAJuAY", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "12xKiU24RoenM68KDGUFNbtUCPfex5FBySUyCeYe9Dfp", - "marketAuthority": "BBUzHNM7aCku9RiaRzosWfvHwgvDtZgoRgY9cNQgEH3k", - "marketBaseVault": "Ej55K2EtJqJdYjyZKWeyReAEzqFiuF1WH14KZ2qFgybw", - "marketQuoteVault": "G4z2fBzQuedWY6Pfov7v3vKvTRFp4iThBFWX3sj9xGC4", - "marketBids": "D2bQ2vbYWQB78eeoLguAdwLsv8AListZMTRix5Pr6oii", - "marketAsks": "3q7bUzDuQN7YaLyjkj8tFHfVNCVq1CFxkgUBdcWZ5vUj", - "marketEventQueue": "7S2ymnaNkGCokjbvfzoWsxtmpdGcWUpiKpWP2kMS7A6u" - }, - { - "id": "CDQ6qzTNbbndt5ECWSYjCpdj2VEsL5cd83ejvqXxwa3e", - "baseMint": "4mJ6N65rD9w6sFPQ17UDWot2H64UtzR31biVLaKpZT6J", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Kb3hFm9RUvMuSksiER8bYgxpceTPTHyiff7oUsGG7Ae", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9r2SDqPNhuKo6mU5LkPWdAXZkdymC6eqzQSfZtVHDc2z", - "targetOrders": "2a2QBhXPwUi7orVVuscCHtpGPVJpRrX3HHiQ17XrChEY", - "baseVault": "D3BeYxpFgs1JmFr7VffEMPifKxPFtfSwhYe6wbAqHekU", - "quoteVault": "Hg76yrbhWRP3ceoKZijkyzwYEjm4cDuaha4c1kifwYug", - "withdrawQueue": "7qJqf5kdpPSCdYpkbvYNTGmKyKHsqT7Xv7uvvrSAT4B6", - "lpVault": "2EWTecfnvhVgmXhsoGXa6bor3ASp8xTSicWSNGqtXU5b", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "47GG67qzLQSyxgK6NjP18BfokCAWmt6RfP3bihjGuhUe", - "marketAuthority": "DFtaLZ1AsjnCn8vje2WqEYwq6ot86a81vbSpbFqoJcN9", - "marketBaseVault": "AvCYu5BJnyQjJoXXZvd3BQEtFvFr2f6Bay7dYk1Ss3je", - "marketQuoteVault": "A9ZT4o8XXp3NQzAE7JS3po1V1Fh1uj3fdti31Bq18DyT", - "marketBids": "93Bjp4E36cetX4YsqQqE5wEXVr2iB1YykaJ2UstUFV2n", - "marketAsks": "EphSPF3f7kTiuxTNUPeLPC4f2q7ZLwa5h5NAfDMidaFK", - "marketEventQueue": "CCQtdf4Wq7b4uzWu62osWBKSivVNkoyeUzKzfT8VQh3X" - }, - { - "id": "CdWDS9CwicQ8TzhR61fGgBStd3L9YaZZ7Nux6abqaTJU", - "baseMint": "BtndwmZJ6QSJpb2dQFm9VyuaQPfKGFB9NrLXeY7rHvT8", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DWXDRm1TbZBxy4Gtyg746Ms2moW7HtNT6j8dYtKs8u8y", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CojB5SFgychVPg9ztWMwc3oYFeRG7fEfQAAQ2rkfN6CF", - "targetOrders": "HgvSYvAd34jfhKKGziwG4YYn37mAGMtyFfcLB6psErs2", - "baseVault": "94VsfpFPqYdRxLQMJjpy7Vc11Ds1MaKB3Ftf7W4E2gt5", - "quoteVault": "DzrJNGWxDAGqzXHcPUtM7BuSzQc32AhZEZCsuCJ72fSn", - "withdrawQueue": "ApFqXTtYGagy4VcdYfkarXCmVxk7K3hHkUVhz11qBwGA", - "lpVault": "GXVtqE5SpLsH4HgLvKKo4bkxqqXwnEQn98sayq3RVSGu", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9d9c6nXdTjgYr336UCmu8cBE8HNfVgseNgDMY6gHHUmk", - "marketAuthority": "H7S8ma4Mq3b2LqJM8kRwfLcE4h7WaWPHQcuZ2KQwLnkT", - "marketBaseVault": "8kAAQVsWXzyToHpxy7qjHaKTLCHaQ5FpvHBiniiAigtY", - "marketQuoteVault": "cNE9aXN4n3hSNpRHsPVnacsJGf2ptMKAhbHMYav9HEp", - "marketBids": "3uy79Zy4suXx3FxnAXuKARbCMiosPXCJfq232cFWL9Ud", - "marketAsks": "6qEVevob6fYRY7jA8DJRZ1YZmedqNi26c4hUjunsqvU2", - "marketEventQueue": "84BH6xgaHpdiQa54QUMTFo3BUQMyGRh9qykos5gFbraA" - }, - { - "id": "CEmBdGcayBiU5PYZm77U2RkVfnEicDyRx193UeaqWz5f", - "baseMint": "4uRn7vxRPWYP4HuAa4UNXwEPLRL8oQ71YByMhr6yBnL4", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6e32iPj4Nu1qoWHtggWxeGW55kNPhhPzdyMz2zsVetSg", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AhmqG8miHDiewRK5sMSsxARo75mnkkzpPQbQH6CXNFsF", - "targetOrders": "Cr2wx78ha7TymGKphdtcXTbyVPEe9f7jU8wWJnZqmfa5", - "baseVault": "7psrSgA3CZAux9tNTp5adyS3S67MDyasH4KzwNf88m3h", - "quoteVault": "G2YR51PJ7egCNsEArpkjWwgnAu2LA6Y9fMJ4YRPBKDA7", - "withdrawQueue": "xiGAGoeajb5fNZoCh7FvNKhLSktbPFyEreEB4oNZB9D", - "lpVault": "6QCV7JpLdow2NpQXn32zpYfumBwpvpeCG1XNTBoyZZiy", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6Asv3yPJBANJtNDya5B8jXLr9h4GoT5heP4hcthD2xwt", - "marketAuthority": "ABufVt1HgTvs3sGjuYNm3u9SSkajVax79yKNvpHDHMSi", - "marketBaseVault": "6Au1eUk3vZAPYVnnuqheenZ4iwLk1CZZMkKe3U9Tmhiz", - "marketQuoteVault": "5LBDBZF9wKiwStGiVNsNH655swCuXNmxH2A6xon2hDft", - "marketBids": "4hvg8LvNcSEcCL3sX1VyXo14G3RUt7PBp8ff2NR6ugyc", - "marketAsks": "wa69kgYhv7XiYcTZrda75CgveQNikJHfyfjtFjnPs7Z", - "marketEventQueue": "H4MUX4rcN2g4jh7UCQ6d7MBkwVHnY6u3S7JcDybhbMNW" - }, - { - "id": "CENxbCc2hKZUGLwr3hcaEmCuP7yt9UW8EJ2kGpQYynsj", - "baseMint": "Au6EdrSDubCUc34awy9c6iQAg5GSos9pPBXyZQtyZewV", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GnoBgvQHra7UxzkpnaUXqfPtrgi5jtugCfvchLzpZNZk", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "96YakVtvLGsiv5EGm4yS8M52sWdMZZpQFkeMjHDDURCq", - "targetOrders": "5qV6cEya2dTPMsDM3tGUimopys2zriS4SvvTdoQDunjU", - "baseVault": "G4y2yF9DhyV2wojACbX4iN6rhjsdbJbJ8gMiZWoKPegC", - "quoteVault": "DGQAiBjEy4LvQggvVftZdMcichwdphGegavrBK6ShrUe", - "withdrawQueue": "CdGxbQjsRAd6XsaTD73ZRPdnN7gnXFfK2Dnf7TmFReaz", - "lpVault": "9bHB6XNS6o3CD97FHCv1QCMALLv6Pd3ukizSr9D27w3t", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4RnYHByMqmrmwu5M4aArX16nAKDg9RWh9Qo3yoRfd3Py", - "marketAuthority": "DM519t5yd3ZBKEoTWUx8Lmg9sejTZkHPAAd5AYJiRoGy", - "marketBaseVault": "Hf4pqW4B2e13wRkz4G9BcbPYNU74v1fcTKMzYN1d1PFp", - "marketQuoteVault": "EqLb8ghTmuzxHcoLeRm7fWxH9Jutcve7j2BebWzz8bCS", - "marketBids": "66MfjNnNceJL5SvNpGvG3F8z9ZTNBW3AH6S46J6Yr5Q9", - "marketAsks": "4MsCKgwMUc1EM1xRUgvgP3XRSsSbwGHANvCE79ENiy7b", - "marketEventQueue": "ArLEuMWyd7Sudgk3LxBWSGDp9ruX12Ktv4oApcraaP5w" - }, - { - "id": "CeukZz6Ri1ScKiBVgoaX4nmnakGhCVSUKAJZNAYo4Wfz", - "baseMint": "GsNzxJfFn6zQdJGeYsupJWzUAm57Ba7335mfhWvFiE9Z", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "765hrUSZNusSQgXuc77kwg611fdtkUxpqN2zQatpeZMq", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8a8eAcPNvA9ZWEgPwUSKUxeYB2XniYFAX6J425GY2KBT", - "targetOrders": "ARsoB5dNnNrrHaDJhpZpHjHsULfAKm3FnkvKAVFN3bbn", - "baseVault": "BsLmVsTtipTWn2JZ8yM5y8bkmCgaikTuuTmcnG4kxqgw", - "quoteVault": "ADV2oaafkSNUpDTnLAGvzsWSJyH8yxcif6p2rvoS3aJj", - "withdrawQueue": "8zLSVdburxujhvof12rLYFTTeZy8E1PDxHU3W8YaZhr2", - "lpVault": "HNq5TbrGAwbP3CN6HbTRJs1C4SU79HyNwPFgJ2xG6nke", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6fwZ9L21aPUyo6nvBwfARndboqjxzYLR5uRPs6j9dAda", - "marketAuthority": "Eh29NHjCEXf9VegK7HB4eeNSs4DmwySnrnjQHoxdxSEX", - "marketBaseVault": "2CafCmtaDRkQXS34Y6oESSUXoRQ8uLr3u1fQHrzu16UB", - "marketQuoteVault": "7BK2Usouf7oNdiAiRE7ee1A6Bd48VhKAYrrqqBPrRVBy", - "marketBids": "vtSdo8u6VvLCNhjYPYgEv6kyh1PxWbvGoowMmDQw1ma", - "marketAsks": "8Lpko7J73z75xg4iehSGEgE4WGDH7oDqZLLESZnr29go", - "marketEventQueue": "Eq2hpGaWg6Qnjhx7EsWDtnWbBZogBFT1eKUCm7nzXcyG" - }, - { - "id": "Cf3iEc7Fr88Eg5dUAP9XRTe98LtEtZHwGXpY9YYSodxG", - "baseMint": "5iEgPvFyVMyiR5iecrWSg7rRfXp2iTiUDzKRne9S9b4X", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "C3dz7f4Fv8QYuQDQjXBQifSaDgYhKY3WrWFdba6Lghsx", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6vDCnXeEWNmmhMer2bf4ph4vjnBifLZfEq94r3uTB61T", - "targetOrders": "62fMx4CfmEXAFqH2mvnWDi9ksNxthqJvzvDxjLobMKnt", - "baseVault": "8Zw9sve2L1xT8S4cvgxVCss147t7jcCYa5DazQBd2Fn2", - "quoteVault": "CJsCkmt9c8SPHmhaMRSuodgLugp12PqUv13kZNZPbwU8", - "withdrawQueue": "HZb9XVpD2rHoddMqouMN7Wd9D3M9VbANvagUwQ8BvgDd", - "lpVault": "HyBpK8dqTb1yi1j93HKtjCaNdRb5A8xwXKvJYMQksQBA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9CRgeHNXbfQfbdpYFN8ajghJ1wz3hsUoFkAArmMZo16x", - "marketAuthority": "Gf5Ks1zbDcG6sxUcBnWzNeXTxMgiJoETFrcuZ5ibTxe1", - "marketBaseVault": "CHUD1s7DCXidhRVkMMM5kUbrn2XSxXe2W42WHKTDR2Hr", - "marketQuoteVault": "ZkBBB6F54uGYrZWs7hLmogzDKR2vqUdr2yDKRhhzpCV", - "marketBids": "AVJuVUYK7UyFbeNiFnp8PyFGr37i8obTrN9yB9a1jscL", - "marketAsks": "ESvJuyeaBBpGuuRQaeK3XmR1uNwywk6BmjcG56rVWapC", - "marketEventQueue": "Gx4461TPS4uEqfzy43MSauNNGULz8QtjjAteVFSevxFg" - }, - { - "id": "CF7EMosrT1UBLMFY4qU9cfonHNuJuaXary285Wv4e8Zb", - "baseMint": "2ZLYEWypSrQhruqsTDqWNWuzFXe5G75dX9PoHQWtKZ31", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9djyMuBtdUSo5xW7exfjwsuob5WknqJgf2muvGHuLxee", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8yPVL5nHy2py9dQ79XXX9wnzxLdTKGjwvAKMm2DZtBMG", - "targetOrders": "F7Q1zTti1jwsRkwCHwNYsdzR9VdLTS4xx8Pi7HQN4EaD", - "baseVault": "GDAUFv2sf4y5vXmpmH7kvzHM3GxtmFPYWPbiMK5r3Yun", - "quoteVault": "5aFvKjwZNRuYxcPnb2wR51LfmxePDrgDijGNFaj6Nukt", - "withdrawQueue": "H2m7RVTeugmar8JQi9bKVwfEvsunmnPjAx7BHKznkqst", - "lpVault": "7k1VRjc4g2cawfPBZQipt5qT2Ns8KDDgRzUBtShaRVSA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CLFDkiawJGZi2QnKXwEidhbQYvxLM2ZFrANuziyVV941", - "marketAuthority": "E1qv7CNag1dFV5o8PPkeCD39uBhdHdYFpN5omzA9zK7y", - "marketBaseVault": "5P6YGyTeVC7nfuwKsNr67hKDSUkDgzxRPWC5Xqoaeqix", - "marketQuoteVault": "7BnvZLe5CnFrJcrCYLi9Abh3FvTxdkxUR86AvQL8t3J4", - "marketBids": "3cX3ugVbHmZ7uRqptbDjGgC6qUPxPRm5kpTCAJasN6XF", - "marketAsks": "ZZJxdWiKw5egK4VLUFYfJAduJZ5uY2qackBZ6nvBMxj", - "marketEventQueue": "EsiP94D69TkEZ4XJG6VvxaVtE12CYFshyQG2EQy76SE6" - }, - { - "id": "CfE2ojzDPu9MX6vnho64KqjWdA75aeaHDZzujbfNP5qy", - "baseMint": "GkDg1ZfoFkroLAwLqtJNXhxCDg8gmKxHAGxSUZagYFfE", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BhDdahyzUr4C3EKkcPVK82Kqmpouu9XUmPLJJmi6jLVs", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FgExrA6AjcSkFMsyawTh7yoeiu1tuH5f4kMrDTj2LNcZ", - "targetOrders": "DPy1USQgVd863sxCjhLFRv6D2CT2JoRMnEc3aQkzUKKh", - "baseVault": "HUxSRRnKgcDMte4Ugb9n3QKNQQdartWvXyoFKxwVxfXA", - "quoteVault": "G6vU99Zd2CcDEwQSiSoTtToKNsRQTPtcqvUNwpNUcao9", - "withdrawQueue": "8MgKeEx2RAfGL5GE9TFk6ogumVG21Xqh1FWcqBPFhBRk", - "lpVault": "6pmu6xo8M4rtTtKG7GwVQLwapBZ8fX9QBvn1Q3Qxipi", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8WoPkAps3uBz5Uz2CA8aL9qgYzUozLCffK6L294bkMid", - "marketAuthority": "B6Tv6k1Kw5wc7AxsehZbQFWJBMxtRiJUPf8zbFGJANmU", - "marketBaseVault": "yrvD2d7EHAr9Crx6MiDbn4XhBJKve2UiH1DVqGXF5KT", - "marketQuoteVault": "77ujAsjJuaRQ6BrYiymS1Skdu1Lc9qo8RHYGH3W5NaH8", - "marketBids": "62JVMB2mmthJqPsEQJpdZxbnt5GfLZNFVbTqofD7p53R", - "marketAsks": "HBxa3jdco1MuasArcfbxj7TNFVTCXuAbB7qU14HDJYRE", - "marketEventQueue": "8wDnFtB3D2HFfbmKqrCv1yQ9hQugNVPHYdP9y3XLyWPM" - }, - { - "id": "CFsqEdxre4xQ7h1N4PnnnMoFiCrSGYeSxSvYCFq5sjLE", - "baseMint": "7H4Co5vUfRGuYCHFitwCr2iCvKpv7QiRA8hFfwa1y4x3", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "EGkxrgj2FN2M4UKLgHGfghcegn8RTPfGhohcgSMPMPLr", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6tTwXmYRaC5FZfFbYMWQYXriUXK5j8X54rYG5txg12r2", - "targetOrders": "H8s8YciDxqWKgFEam7EoBqCZV8TQAmBEPnyKURwoCynz", - "baseVault": "C6nmFb3GFDCELrYj6gYBhcemD8c32FMcBvkJ5eoHjKfB", - "quoteVault": "VDi2Ddd1VzfjGxBxCUdVHd1rGAoKADc8CPzEbFrMciy", - "withdrawQueue": "3T6uoHhAqKaP1Z4CpJhc2WTJ2KH9zHzYjjVvDDAkV2HG", - "lpVault": "8356LLrhyG4Z2XYXTLbeJKdgTcpSXJNt3NcrEq6dnhhe", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3Vg5JK9Hme4Ez4CgUSSN9dGKNe15fP98HxupNS5Ek6va", - "marketAuthority": "61SFAxzCbH58U7bh6G32zeeCQFAsj63ndbn3dHJVbRuJ", - "marketBaseVault": "B4r9dBd3CfwXWQbVA7a1va4XhCU4qVVxZzGd4UW4t5PA", - "marketQuoteVault": "2GSbSSSUHo8yegatTaa9f23UK5ewUBtTmhs6c3FRWDaG", - "marketBids": "8PDfxwNdGsH6WX8Fpw1SS5NHonny2WhKSXAQ2ec6CSt2", - "marketAsks": "8p6MVnzm58VgKmFdzFaXomaakPE68gsBXQJVxqtpfWGm", - "marketEventQueue": "9DqqY5GZ9VaG2h5dPZDEeoC5ZogmJ87wHsjR6ezjyp69" - }, - { - "id": "CGp4zP1BsRJayb9PZWzSQTabPawtQBhsV2Ur7NRnXsq6", - "baseMint": "MERt85fc5boKw3BW1eYdxonEuJNvXbiMbs6hvheau5K", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "DcjKf2Fw957uuiPJH434QcNeaZhpsqntgUqh5ZZC48gV", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4DwWBjRGuKZydKQMHgGXWizRxXJFnDe6VqcV7q3Z6abW", - "targetOrders": "6xXf95ZdVnT4fomxBdkBZ3LB3G2eH8QLAMyTPcgNbcq5", - "baseVault": "G6xKAkCqzNmkWJHCDznC4HJQgiLSQvjiC3CrXuajhv78", - "quoteVault": "75A2RPNeQW9qGy2vF4ifKyKvgGrWrnnQofX1WnT49cbn", - "withdrawQueue": "6txLNagP4SyWBvcvD9QLqMu7s6kQTMZesmjevhpgnSVW", - "lpVault": "kRD9aH7kxVxoNuMTF2nBtVJhpq7Rj7FHMQiYtUfiwbe", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6HwcY27nbeb933UkEcxqJejtjWLfNQFWkGCjAVNes6g7", - "marketAuthority": "7UDYmyTd4nj84QqXM4aZVS3nAibXjCT5mozoAdH5xuvC", - "marketBaseVault": "GpaSFJdugwds4248cMSQymVn6GzBrTn5R29obBoTZYWV", - "marketQuoteVault": "8bCnx4rqoFU7eeeTt7Px1JBgYVG4tjXYENzQtQwK2zXA", - "marketBids": "DULsZ2xzGgDtfxzVkTc6xB2QbNo9hBDrrnUy23gD113i", - "marketAsks": "43HriJFtHxd94EFG7Zrh9eAwYo4DayNPg2j53Pnmkqeo", - "marketEventQueue": "2KHhLvD7hJ3Wy64Po428g67n7LB8WFUNN9JCn7CxvCnm" - }, - { - "id": "Cgr7HzhB56E84eBku3jQciJZSNATrwribLs1p2hFcnA", - "baseMint": "EzL6LLmv4vgfF7irkjG7ZxM92bTJ9f6nFopDXJTow7zj", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4CuEQQNC9L8mR2PZsMsdZUDr5dNXusKeC85ccbCfgHP6", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Fo9LbJqwQbjZQqaatypy3qM6wnbMddmd4nVYSF7xs2iD", - "targetOrders": "BqTCwEetAKRYgAFHPQPAosHZm59eqNzU7vjjKdvQgz5q", - "baseVault": "4iD3dywg6u4geKzvugBn7x1ANDvFjSSLpK4upZKCSLjx", - "quoteVault": "Gm89eHx6PgrMC9Nx8yWF4GVi396Da9bdahhZLG7WzAQT", - "withdrawQueue": "9TuAp5uu6uTNDv9izJAWFkJJhKsFrP8CLVSU3uj3x572", - "lpVault": "BQeL2icpW22gdACWtif1pEguzJPcMWMqmRmsJJC5fw2P", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FitnUARvYB9LRXJtECe2YjLzPgLD88fDRGQgqKwLDqtV", - "marketAuthority": "2nE9EoegHbeHjoL1uFJ4FRLWD761zcSsbDu8jp6qjarC", - "marketBaseVault": "7FnEXpXcdKE4PrYXeUxdWG6SdAxFS7KxAbFzp5o1Wyk9", - "marketQuoteVault": "AFmbW3Eo1GmqQgYp1L9qdWBt96vKkCmPy6UyXnXJXCnb", - "marketBids": "2ekz8cbtSxJGfMgk8T5mEKQd3FcLh7Hjyaz1WGefq7cK", - "marketAsks": "9PPYCf2CGrqeerexjbWi7WEFnjrQsq4TvPbtdJSeHtbf", - "marketEventQueue": "AMDxRcRUW7vo9gV1js2dyP1WbxBnaVF6rMXLhnRRf4X7" - }, - { - "id": "Ch21N1nLXFh9DEPGvu5VxWyfnS6C2n8CzuuL2f28bZh5", - "baseMint": "7j7H7sgsnNDeCngAPjpaCN4aaaru4HS7NAFYSEUyzJ3k", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Bvg2RCdwFpm84CftpMbickvBZpxdakhRvnrUzfp4f2Mr", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CjDGfdD1WZGVbkYcXTKDVk693Xo2afQViFqimGQv3PRU", - "targetOrders": "Ex1NyGrrKLdPmU8g3wNWwDn4K5Qnz4T7RccSnBKeuTLx", - "baseVault": "5AtujK4anv4GrEwDUm4WAsHU9zwJsmannQVpDmcY2GQR", - "quoteVault": "9jgVdv6m9h8BShSRnkuyb6xQwWxfnsHCzpCNA4p7zcwq", - "withdrawQueue": "2nav1wRL78iGBKh4xUHKNBcPdTCJPgjwWA53zvDTkiWJ", - "lpVault": "3SPNtPhouKDKr3GbM63oUzs49HBiCDCfegcZThWEw9qM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4gr78LzJgL3RuCwomj1RzSsXwPpc1pzbMEG54idYFUqe", - "marketAuthority": "EYjpGncc5UFqHuVD4mNvMLJKzqQ6Psq8nLiBX6t31V5G", - "marketBaseVault": "8J7oNSRB6NMb62czUj7Tjz5KTvGm3zbE2KbxkWfv3NkV", - "marketQuoteVault": "Fxg6GEWK5RwZoJfGV7yfJzovyhDbEHL9dLZ4nEufr95f", - "marketBids": "5asyn7g8UYexzhHi7Fw4zBDBReLxagLJfrVPaXndnf3x", - "marketAsks": "AE6UWuiQAdEde6SYHCy1SSedkdVorpUJ4Us823P36erx", - "marketEventQueue": "7FPYajNbkEQbLTxxTyEFUazoe1odw3b4EJD2vNw5ExK5" - }, - { - "id": "Chh61AeNKxfHAennhJTLtSZGybaMt8bYurn68Hp6vBV2", - "baseMint": "EK1rBdnucX4yf8JDCFQEC7rTejXEUqsjazDxHZaHSKT7", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GeF5WVPR1fPM4Gmf6gAAS4B1drLFyTLmdijFxsPbCDP8", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9hmcLwnmf4uqpgsBZ7kpt5MQPUigwrH2TALPMSkKaia", - "targetOrders": "HDNXRGM5dZZRZe5G9inaeaXfGWC6fnieQHeq9M4SXZZA", - "baseVault": "5sfLtYcANaSXaQ5Z3NyJVpFVX2q9Z572vnXdnQ9VWb6E", - "quoteVault": "9kc2yrjWvhqfx2LxHmJKqCUJkjzMECQq7zDEeLdepEcV", - "withdrawQueue": "FAKzL6AgKpCu1KGicVPuthVxkhmBw75qEq8vuKU84JS3", - "lpVault": "A76fXRZnAvmmDutH1JHDuzQq1M49NMUfCgyHXsW4Hrpr", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3VBjGQof9v15UNgjYTEoNJ1gG1KGbdh1o9Q1NJAU7wem", - "marketAuthority": "DnGQXobFMPHTjfrMhTdsZycta2TC6LTqZe5mnJ372qE7", - "marketBaseVault": "AhJF49LkWhrx1dPt3kdZGHJZPfUZQwJUeNvuCC3nLAW4", - "marketQuoteVault": "CbW4diqe4qpNVHtZJXXYDLsiWGvN9byeP6f8Ezz7w4uD", - "marketBids": "FAfYwdYPVWbKrjqQYXGQgUWobkFkUizwSwopJSopHMzF", - "marketAsks": "EuC4y2cBPGyxsVFL8eepo4ywTXfZDD2WZxoSnjAr792X", - "marketEventQueue": "2Ygm6ZdfaqptpwtTHcYyqBQ6hn3EcPmgdnDvDqqxDic9" - }, - { - "id": "CHysU24s4X74Whqb57kpsr4YpWy7JQQ1dKGSNZ4MuAQL", - "baseMint": "2qfSePaCqvWkYnYUsYSm1VZYKtbzKYHh7gsnKcyrgspp", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6Jgpp5L9nRmLYV1kA4wirZVG3LB6tBEv9ZJhBJ129iZV", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BUvctsZupRQgN415DuWiQm3CdZMbQEC42tYCU2cv9UcV", - "targetOrders": "EPhAjTMvcLrEataSET8RWAykz2X2CPPcXBYfnkUZZ2R1", - "baseVault": "5m7rEnqsoBruXrhHgEHRbaubRSC8oviY4CdxXev6bzbf", - "quoteVault": "Hw8qknsDUdm8i7N65LoENnC1nKvkj9n1VKhYTogBz8JZ", - "withdrawQueue": "2RoJXFSP89wns5frNuLrN4akYW9sbB9NB6brnTQCpbav", - "lpVault": "9N89vkZJN7TZ6DZKfqLLJE2N8uRjn2RZnuiYMZHkVgqQ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9n5MEV72JxUukZpS4JPwxc6PdB1stFdFucMXK6yShmZM", - "marketAuthority": "HNhTT3263oTv9YB2CynPinHho5XgcJ8e2bvQ7poZBAAA", - "marketBaseVault": "DxjKZpD5cBRYdjSs4Hi6gY7HdssaxGnATocCZXfkUZZ1", - "marketQuoteVault": "DcfMuD8dLSppyZsvshp2rpVRt8yyPJKRXunRRbG9SZSn", - "marketBids": "3TULxpnwAv7eBDtRTiJ8B8SbbLufjouin8KZJTGKBSD1", - "marketAsks": "14cvZYe5rmkAnpch1yciunCzEyH5XN7L2Aq6QCiDiFRQ", - "marketEventQueue": "7uc7cuqzhYuf4bH3UUXjKWJu39WnZkVpvCnHdf9sgSrx" - }, - { - "id": "Cj4EkCBXSy1EsgaKnm5jibYHk6VcMc4zz93DVinLHnPA", - "baseMint": "3m7A2A8HHdqmiDrjAfaddj7Hxd88FrBHA1KSoqjoELtu", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Au3WbwrENYxPp7GZ6fbfkurDP13LnKcqCAskuBab9bbU", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BfioysFSPUAQhNpPedMgoT7k1nGbkaAju28YkmbdUV92", - "targetOrders": "13xmAZQnrEgC6zSnXF2rD8cGPCrYLuB5QBZX3poocyjE", - "baseVault": "ChbDnhhp9XocaZ5T4su7ZFN4YnJZZGTwX9e5C3UDM9M9", - "quoteVault": "Fdh7esSmXbjod8h21ZHDhkbKfU1ucy8JXKCoQZfuGf8G", - "withdrawQueue": "6d7qm1yfXvu4YV3mptQ1nKARcnK2aNmDYPPCAEQBYkZ8", - "lpVault": "AQ7DN7EvC5VG5a2rT2WkhoNwuzJomJyN8p9h8P78ww2V", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "eju5JDyaf29jYNfq7VrVAocVxGayDEHVHHiM7MYc331", - "marketAuthority": "2aGjFjLUGWZzuhW7s7Qrmsse9h6EsRnfTeBbSwLPrVyj", - "marketBaseVault": "CsBcAK2LDkbEmvyreCBArHsX7NJE7fvatrG2oUBtsy3p", - "marketQuoteVault": "2MvsftfbDnbqDLoQ2P3Z2gWf5BcE5aQEK2avSgxedSWG", - "marketBids": "GZfcQgXhqTt5ZM7vZcbMGsFa9RjGDUjXZ26KXA3zQjoB", - "marketAsks": "5VGmpWs4VfGDasJESUMrYJhsVLc8WVK41EmhkX5RHSDt", - "marketEventQueue": "CnG7TZ1oXAxGkz1K3FRzTMKTQp4kvipzN1dKpyrrtnYD" - }, - { - "id": "CJnJiNvHnb1h6SVPiwNU31QogB7t9dmV8ALhVzV6ZwXj", - "baseMint": "7V5AaqHTwiySegaAmNPLekQfTAoK4WvEVgfi2R8V44tB", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "9Twek5YnaqbB5nNdCANSopi799tDDykfoHZMPK1pWENZ", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GU8iFdZqLMZag5q63QWhznKXegFRS52zJ2TaY2fLrCD4", - "targetOrders": "Dn1BzSnfq5tfzartHHTNpBh6SWBHPG1U52eGkyBg5ZUa", - "baseVault": "4BXbs7hDo3NbwXxcke5GdbEQud12Fxy65gUCQ4WnQtj7", - "quoteVault": "5V2ebjh7y79xMmBdRLt6S22ipj8CpPEZLX4avzw9zUuk", - "withdrawQueue": "6Trz8y1Mgo4WvrrkRhc89XhRRgzX3oj7kLvBHjcSRRLq", - "lpVault": "GkvskDACmdTWNvJkfkRARQLJsKfEGpB9p427An4w1F3C", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7ETZA87R9ofv6M9BHD5RLqbyYnKTKWGskNKmvrew9pzW", - "marketAuthority": "G5yDtcsXRvhy3HD7qwKzzuzo6cCpqLJQZUnFgt2QY6Kg", - "marketBaseVault": "AD9tWMR9XBcrDucm1j2Jm4Xh5goGV8qkD6n8qUuuRmAq", - "marketQuoteVault": "8KHHQTXzNbFNg44BHJg5LbHMovKwdzQdFkkpsV4eVGUN", - "marketBids": "8sNRZuSrJz9VUdYuujZi2tiHE71zhGct9utDpaMuacBP", - "marketAsks": "FLUKh8ZKVEqMuMV2uNUauo6pXYyQGxbC3uToAAyPaG9h", - "marketEventQueue": "AnGLxPHVmw8PZWQQwKN6ehMyLpSoQJyqudf1jL8nFQsS" - }, - { - "id": "CjxSwpbwdHNUrgHhScc4rn9RaYjvHRtpoXzmipHqXz3R", - "baseMint": "Hi4WKXqmeoNVz8Nf7pxCCQrdFfxdLDLGFudHXmV95oU9", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "CacnqfMZwKBFijhUdDC5cKS11uBPVPTtcapMsi1vJtrA", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DKGbg23pt3nk2EZPAuQeoQmfbukadATjqsFafnvArXJ7", - "targetOrders": "GtnCgmiVjqvnBKfJwkh6bjsWTc3Z1DWjDYdMjq8Bn8H5", - "baseVault": "7rCe3mMFNuJFdWQWNZX91qqESu7S5tLpktiVACsno4a4", - "quoteVault": "Cs8sUKxLQEZNkMBoehbp3RvNnb9fRHCxEzSfgADWFDJf", - "withdrawQueue": "DugbHy7bbw4LiBqSZPUucQcqAK8t1mTCWwR83Yn3BRiz", - "lpVault": "DqkgUuwe5oMrBvDXhoRwWQBzForzs638LKfa1VBhouEw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2cErRJXQf4w4r1QwyKnfBgLJY2HxGeQt4jYwreRwMCN4", - "marketAuthority": "DYLYvzmSrqmSvtX1iZnqtFS9cCshKXsmgUEWkTDCMcmD", - "marketBaseVault": "GoM5yLaGMPv8btTR9LLxHL29AxQhMLXXwkSGzKwjFVEs", - "marketQuoteVault": "4A3UPKWZQtWDCwZ2XRG9VZBQJbPn4fDnNDMB5HsHfkK3", - "marketBids": "5kUGGYSU5U2WhsgbAVQvnURP6XPmkERmNZfhfi8QDZkc", - "marketAsks": "mPpkphB9oGMcypfoYVPx6mvJga2TxFfoMfK6XNRhSCx", - "marketEventQueue": "5pxYsvbfzB7qSLD9axqEMfqGz4TxwUNbEnK2p8q1vDU6" - }, - { - "id": "CLsexzxEQdCcFn9Nch7HY97fytguTQjqxJ1XeS7o4dWy", - "baseMint": "14UMe2amWfXj1CrM7C9kFkTQ6PtX5aT1fdsVGqBZaXCT", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "56UHDghUhsmVfmNvSgN1MnGUjt1CgjsMLeKmAMawdd89", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3bvZB6DHmUCdS9MqPpdPCZnNuJBMC6rueXYseQrpUgiC", - "targetOrders": "B3sRVJ1TzF3arpdhkGamnFZDh53czia7g1BqG8wkn7Kn", - "baseVault": "6XzWDFY6tHrpUVTZ2Y5TYKtgJBxvFwPLW3sggLxhmGdh", - "quoteVault": "5cKfz2LXrz3Ut3jmMxJVtoZVukJnFLuJxLM2UxkZBvgW", - "withdrawQueue": "HHhj1HN5ccmcdRqon3bsF2ciaaEftsmig6VijhSvH1DX", - "lpVault": "FitxJhWjgWC7ftYG4NoVJ1KuZSABnGAmsQ1NUpuhGqpQ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "79ur55niVK3mfDaWzoJyChT2uyQD2XokbuF51HWT3G1Z", - "marketAuthority": "4heMUAMbyPYryiTbBfagfzPyYEBBnAJiLPZjW2i3U9R7", - "marketBaseVault": "BBwmc4i2XSEd7t6qwL2JiKEqCYs6z9GzTZUy64YGMtX9", - "marketQuoteVault": "6HkAobD47ryJVC9fstU81n3JJzz7y6vZBt43vdYL6mW4", - "marketBids": "CUbugnyM9jQkS94ifLRvDuxLoyk2K6xyd6G4MBcTDSC", - "marketAsks": "3CwukXxewDnTQnjpGPdcFTD3S83Q7xDNeWPTpXwZmaD6", - "marketEventQueue": "HAkAK2DBg7C68PZ8zjcTZMqU3p2N7pkF336dke1NDB6p" - }, - { - "id": "CLspEtUcPXQt3ft9hXtbYK4PAGbwED72359FzGRnwoTZ", - "baseMint": "4dydh8EGNEdTz6grqnGBxpduRg55eLnwNZXoNZJetadu", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "DibyiPuyLpuVwZw2HWDtQhLq4Un6MPt29tjapyGoifcJ", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GNkfoH8R2HXJiuksiHTXBPvJNHyY4PxbK8AKi6xQzms5", - "targetOrders": "AAbAkEWKqfGt2KYUiHnaYfnUxGcRcSfreM4NaUDJ3eAs", - "baseVault": "DF26mgFbJcAur2dpevWUbPWCocfKo2aCszqs2TwYch7M", - "quoteVault": "6nPkAzrAgHUL34NpGF7vaxxDEWYxbwqWak55cX1wq6Ae", - "withdrawQueue": "BKeLQG8jiyN5gtwWNuEJmkx12iqXfi1PTqJr8HKaKFUn", - "lpVault": "4YA8UrwpabNg1p2MVMeqBWR4mfdGP5MULW6CsRsiGwZw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8GaWdgZ5yPxQpxGii2HCWKQj1JgabH9SGCHx2fFwZK6t", - "marketAuthority": "5e7g4BNpuhJuNKdnbhxdKzzwhUNp9DgHLiQZN2Xohikx", - "marketBaseVault": "6zmsx1SK5VTSdehYbQCgFiBGJvVMRyR5CAzfv2A6updx", - "marketQuoteVault": "3tPPPYNWZMrxSn2LZg8BuHBjczpMG33H8DaJbfi6w7rK", - "marketBids": "9WC7QuNJu2tALshkawy4nHNXiAyERjFQXDJASCqJDRY", - "marketAsks": "8xpzyHzZmT5jbcMVmme4Mzkgx7df3zEeqd6f7njZ4haT", - "marketEventQueue": "2QBM5CpEMLbaryjk8jzxiS2rTG9y2YBJdF7F8ALYYvt6" - }, - { - "id": "CLYyw5SCFPsTv8BRoquJWJYk3xMM7ZYHzzuDpWhFhRuX", - "baseMint": "BoFxKXdyiEYJReWGZAT4tavuAo3D1BmDyXK5VFSXd4EF", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "A7zzSYnqrQ5gcukJLvfUoAxFx83EBq1vpFr9tjgAbAt9", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GB8bFx7gE4qSf5gYQgvHHuT6UBYynaFE4Yud1aP4S8Jc", - "targetOrders": "5TacGsY6uNtuTvJQJYwCErMBUuevpnt2qKLZ2SbwtLKf", - "baseVault": "6cEecjXhmW6w634QELVZgdzNkCGmtT98GEXiJ8W8GVZK", - "quoteVault": "F9kxmXqwPc7EPRP4Dm1LjAsZvq53abTgXDXwjwBuPxj7", - "withdrawQueue": "KtLHb1MCvdvnyknXksPMNjYS43NpYJNbh2ccKEwBgbf", - "lpVault": "AjZsQ4czYgRuE8zZzcUtwCPmsjYgCk9ywyV2KKd35xWk", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "46iCxsmzw2ZUFNDAmJheUp5hSKJPSMWfXUKz4P4UoRE9", - "marketAuthority": "HbbsvFBjyhmrxnZ7JTjpzinfcUpGKUGGuKzL3YAPuQqn", - "marketBaseVault": "A2wVJ8Q5dtUnk546CY5XxY5w8DQpgXeHZDpbzXDex5rg", - "marketQuoteVault": "4KGzZ5rzvmcGJTSLrXnPbKHJNPdKYgmpUDyp4wNxRjS2", - "marketBids": "9buLjdKSnrLdPB7CJQNWyn9d6mXKkdkKNP3FNSJ1CGNH", - "marketAsks": "nDLzWRYNmqb27HUnc7fthqzWYpVSrinpqa7GEUdN8jT", - "marketEventQueue": "4c8Rvqh4P8tDbxDdcdDpWRkP4mRpsEUxyALDTtpLHJwN" - }, - { - "id": "CmNVzpjCfLYrxji7VpK9mLKHCADXtQ8rcNE4CnoSeWf9", - "baseMint": "Gh1jKzmxf95cT5PQabNbfJskkQU8kQ5UugfpbHSnPq9z", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HQcEovut75uDicSBdj7RrYNZw4hFJLKWDSmASyr5ksmP", - "baseDecimals": 3, - "quoteDecimals": 6, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HWTaP1eyRN2JfHCJLLuxz497P13bL9VT7Rqx3nS7PZzo", - "targetOrders": "J3kMkBpcS2go9mzhNs8oN4AFZ5ySDJHXfy8YrjrC8zYE", - "baseVault": "ABwwhgZ3mRtGFQo6cftQuaZwGDa3tP6EQroafxVmEd6v", - "quoteVault": "5rUU8Kpgc78HrFNsU4oeiVCHPJz7Xi7Q8j73XL4z96ZK", - "withdrawQueue": "61ntpmstZJwANbPzz8vB9RonDpkkfkntbHudAnNJ4BPQ", - "lpVault": "Hm6SJPKUUVwMMhdNrwiQQU6hUuaWGnjUqcsrWMHmjZo3", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HbS2k9vhMbF5sNhLa5k5NUReLGxWAuiqPwUtAut83CkA", - "marketAuthority": "ASp59EKP4sfbUpzjU9kiTRTE2ahZCNpAnxLurMTTydn4", - "marketBaseVault": "ALu8qAEURyuu85D2DxiSzdSZmyS6sX1btKCYMm7K54pU", - "marketQuoteVault": "B8dyTkxgvBYBBgELjXTsbqc19V44MsL8EB68fWq1Aiyy", - "marketBids": "AwwEhk234PqWnBFRBkaKB4UVnrobvZPMri3iLGKymXtH", - "marketAsks": "BQw8V3eJmWZvHbNVqK6gpCKHwZ2wZLGsaakJoSThXZvW", - "marketEventQueue": "VmEf2cUt98y47Yzh3HcfvTKSK9kikYMNqyr2LVsXeUE" - }, - { - "id": "CmqQmnD8AXaaADZvvKMfoCE9tPq8tELwSAZdmRnYs8Kt", - "baseMint": "A9UhP1xfQHWUhSd54NgKPub2XB3ZuQMdPEvf9aMTHxGT", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AgkuqTg387erQNacYJpSPfkAdwW9zr2H6kbYtQAj4W18", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DTyoukHrczFNp5U89pdmNMSTVvFMLY7gemHoYksqmcrr", - "targetOrders": "2YcRWUyhX6gCX7UfdsyjiZSFwFepfEvi4zFXCne61ADB", - "baseVault": "AjF5GsH7KaQyhC3cTS3JN4fuczuftWXpnLWusSPnGbeF", - "quoteVault": "2BXS3XJMTFWgSLf8d12bKwNsyXuUX7RnSsRfYdtLYxoR", - "withdrawQueue": "7T6cyAZ8LmdyPkzeQaCJbHdLLjyKrxv1s6XfNdyL4PRE", - "lpVault": "34LyktmL4LDMBGwRKFBBZk8G6duvEyZYr9Zyqgze7m6y", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "1VFShHoNGtMxgSqQwgPi7BmytRvy74Mi616WMMKAVAe", - "marketAuthority": "H7VqEtLYY214koRLQWYUgWcePr2EyaZrR2wRGtuxZFXa", - "marketBaseVault": "2xQ6oLw4rTaRtKiECkBtkF97bWYWSJDpakuVQcdphA4A", - "marketQuoteVault": "ALzC8xk9RhzpEX9aqxxGmsBSe82z5xCpsafkHsxBwzXS", - "marketBids": "AjDU9ks3Cyy1tfF9EZVFDXa7Vn7GKhHNf39YaeCbPsth", - "marketAsks": "4rhRUDQvUm3QPpa3LucUexqR5T6oLUG7ptZCkMDu4QDy", - "marketEventQueue": "GquXDi9595tcY65jmwheGXmePieTdcbf3vFo7bDnaAyk" - }, - { - "id": "CMyCeZXVkaukyb4r3NPSo8aRkseCSSgZEnhS9vGVtEAG", - "baseMint": "CT81fJ8ReVt3aNPqZr3xZvgJ7jjEfrzaXh3condAXHXP", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "7gpkVUMy6xXfXPACtnd2GufYWn5kfaNxfbvfCBerZry8", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "J9CAdcAtEdfnWSRu4LF6hq6mZ2J1XCW1WZaJwjSXWY7k", - "targetOrders": "JAsc2aQEEfMa6HgZSJDX5zPFrVsKMib8zrXacvKvu3jW", - "baseVault": "9oHhirCBispro4PoxntE9Suw3EFMfkaQ6q6n7Ntw3RtY", - "quoteVault": "BEZbNA9bcMnWZnrEbJ6kBhCqwJAjiD4t9iCTwjoUtZru", - "withdrawQueue": "HF23zje4y9SqwDT14At3rgAc6D1cx5kffj3pMUQ7tmUU", - "lpVault": "3iYnGaF9U6SgeABGvunGj9sfwfi4GZ5uZwsshaJvo3SD", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Cx6wPU4YJi4Fyx8nnfVff5iFJif66FxFVojxF6HFJMvu", - "marketAuthority": "3apQ7sWoDDYmV2Yvvfdj4nN5dL3jbinQpsUBr34CXCHa", - "marketBaseVault": "FGZzeVBvZYrjcjMrNtXBjRdsSbfLbinW8BwvR5sR8GC8", - "marketQuoteVault": "9i19XhQRYXRZW54ugs9GUCYyP3QJi3rFBxSTWwTUKSQB", - "marketBids": "2yxJYcghRcwvV98kkvjG9cRH4avPcSVtv3yMwmxwyPWm", - "marketAsks": "ErYXVUiN3VLrLCczDQVEL2yci4UcFjTWDs4XkzEoFBAJ", - "marketEventQueue": "GGyiAq7wPpZJmwfFQipEkwDBcjVyjwvxFHT6TaWarBLE" - }, - { - "id": "CNufMwugMy94SvkD9F8mmZMv11PPawU2GnAUaqD2my6a", - "baseMint": "AAoJ5eYd61QsUBRBxjCcAdsQZpQYxrob2wS4Hzoaeoas", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HzFuk33jokbGU5EsqYj1ymXqXAcPW4kmXo1GmfFskPCX", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CWu7MYZVhKYxDiNNY9Wi67z31khPdsUgdSfBcT6uca6i", - "targetOrders": "5sXf6v2RyxQ4SLak68XE4rP4ZqsBRKmrWUkVFReCHpWB", - "baseVault": "7Ac24hSSdQjVc2d2w1ywA89AFmLte4wgPFcBbGEsjcqz", - "quoteVault": "Aj1fExgE72SAcAqqjDtZ2qoxCpjMMx4wni9FVQqXE4o7", - "withdrawQueue": "6cRnPRfDFyK3LxAFx1EFXteXPE2r5PTWTLdes7JdYq8H", - "lpVault": "85hnYwg8FAJxgRDKH72oWsohn4rS7dokPb25qYyMvT6b", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5CWfbdCLQGoWGy4qV91BUG2bjVbBQcZiLbRbamh7uRUy", - "marketAuthority": "4ZJmnUHwcM1Y7MnV2ZeueUBnDAApFnhRXZgxBX9RakWh", - "marketBaseVault": "2YEXasMK9fybjdbfsHSUCuN4hY57Pb5bCmfKLtr8tmbB", - "marketQuoteVault": "FWAefM2t3P9JipVjVjVMLLz4J9b5yx9qH5552hfvLAoq", - "marketBids": "7WZi4fHPmVbagdW3Ja9AUZGSPm6VaD12SuCzgfU4Urdw", - "marketAsks": "9oYRUCPVS7EVxQzkyVeeV1rgnb85yqLQnyU7WDs468og", - "marketEventQueue": "65bJpumsKJABi41gw21af4BbN2wYoEEMpcUcEJERkEuR" - }, - { - "id": "CojgUqgkzHPGtb957Fwuv1kNLbyk9nH1Kg44tyisa787", - "baseMint": "9qTA3A113oG94ppSpiJTwWCyj44wyNcgPAs5i9d7QQne", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "2DKeJf4c6Rr4axRAn1H6P49epCy5dCAQjnLcDa1ajzds", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5zpHqjTAptnaXVqG77LR5vYSi9or7h3qdio21ucaFPE", - "targetOrders": "CWpLVMf5Z69VqYSwRAmfc52gn3H4iiVbQr5u67XbKFRS", - "baseVault": "6c7273jUYu4rrFXd7j4fbBYJUftmecSeQg19PAY5rfkD", - "quoteVault": "4Fh3TX2SQrQs2GgqnZpnpQkRuSaHJchpfG4jxJ1KEPAp", - "withdrawQueue": "BoHnYwqo1g2h9DBsPRokySAud8b65VS1zQyyXG2sPfsB", - "lpVault": "AppfSaA44V8erpPhLnrKi7n1mPgYfoZoiMhFFRcMWmjk", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BknXQyamiFnWXKkQsQpkGs7QCiChtBwwvVo4emukxrBf", - "marketAuthority": "F5S44q1tr7bCh8b9CyGAkwvNVhUciNoFGSj34XjTa7Ut", - "marketBaseVault": "5rsgx5BYNeuz1h2sJgSeW2FPeaSbvbEomLB7jZ3aBiDx", - "marketQuoteVault": "3BsgBitBKYmJbw27Jv85WpGSNwU6mfFe1UE2tLAbBmmM", - "marketBids": "Cn22Jr7Z3r72K96DXeoKgja5o2SEBUFX6rUAREEX5FFT", - "marketAsks": "ELdMwBCJzEjLJKJPZUoKwK6RFY94SmKe59qTeuPUWDyD", - "marketEventQueue": "FFjSLX7C6Z7Z4YP8dTn3pwjeTR6ywp8JrrSNXphGCVcc" - }, - { - "id": "CorQpntNfxCjSnj1DXwWmGxNrRoxAMjZzet5jz4xQgdL", - "baseMint": "CdcRwbFuj3YNJYdfUqh3hnxFz1fuF6he1Wgz7JvZMHda", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GjhqsdjdtsSubWVx1qSqybzeV3QtqGAz5V1idZ2E73op", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7BHiRTyo6vVdzgPJbMu1t9YhLaKDiwZkiNnyZg6YSprk", - "targetOrders": "8m2vYCxgKiDQRA4XJYdujLYLFbsWZHeDfV6YbUGy78VU", - "baseVault": "7mJDupRA4op8e6H5G12SDiQt38BDNi3N5ES1YHrkHqbs", - "quoteVault": "B4vcZCjKZPbwbh41XpXryCAjkvh96S67zXX5Rpf7TY7q", - "withdrawQueue": "FJB1k2jjnV7vzoh9MEUmGQjtniwJN5ffqEgwZE6H2zfc", - "lpVault": "J1PEaKABacRXDdsQs2WaZWrneSxDoCTem8SEVyU1fUpw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9dww2xBBe4obtBq8tNih839PCgna5kPsyjRHDabPjU5f", - "marketAuthority": "YYCcDdCX9LknRGUruGZFRLquNkb5o9fuKwjygQUd6Wc", - "marketBaseVault": "BfRnZJnUy1AQsXx8eCFKeMRJB4dr5AviwB8NsCYwrk2A", - "marketQuoteVault": "E2iRUo26bnmhY5SBszv81wMuuLUziKT1YqVCtkxHhy9T", - "marketBids": "577QyGBmzFgBfR4NPsXoArET7g4DD6rM6ykRnAyKtjFb", - "marketAsks": "EQfahT8FyD2dgTHjv92EawS7Xoie1HfhdfDEc4uksXLg", - "marketEventQueue": "w2z2ChP42NFL2CP2752ZEgbxskcuYi1zCG2Ch1gX7CN" - }, - { - "id": "CoumXu4kzSEFFeTtuvocr5uKiY79D9oZoiHXCF4hzomM", - "baseMint": "XenomnZ7kLQxfENcKKpfC8tov3GoZiW4XrDmPc8HRxd", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BxStWubYRBQk5SASpYrRrWZyoxt2YJvnX25KSA1fYitD", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8i4jFjEvpF39SF7DCBswHtJAZtbtSS7mD9BHTpYq7yXt", - "targetOrders": "CbuHRnycp1CuYRZ7q5PgManWB2KRom3j4zdVGUkeB6x3", - "baseVault": "9LxBiroQtXBoHxwtBRJfz69my5P2ku9wwcKf14zW9zk1", - "quoteVault": "AXECDL5fU1qVRHZd4z5oqvUMYSfi6h3Rtjx6RwnoHXkk", - "withdrawQueue": "GAeJHR7zYPr9fySN7ovNdiQgeEuR9NK7zsDU284yYeph", - "lpVault": "DQVs9bynscuGntmZTVvUyXQbTrBsscY7xR4BWxSUbcoX", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DY3aH3pey7HYCgQ9wFfA9L5QCm79kcmXNAV4MTFuquUh", - "marketAuthority": "5d5EGZtizTfgHbGo1Mww9vbvqSbFULj9ZCxCD2zSiRZp", - "marketBaseVault": "4FWLGWQRXsSTkqmhRSsKKt3QL1kV5R9uNHMC745Ekpbf", - "marketQuoteVault": "4YrYDwEC1nwcn8uJJmfkUmnjyCpbdqpubuzRuuZjQC7T", - "marketBids": "6FfUrRnBThJ9vsno4nPm4rWEaoih1AXwEmsjz6qnMLmW", - "marketAsks": "CFHS71R8j4ETxhVmy2Emo5s91dCzPnGR4zLcqhUVzpK1", - "marketEventQueue": "24vaEgFQi5QzXW2E4BGe7CcExVvthNd4LV2mrpvBs7H9" - }, - { - "id": "CP1tyHuKo1Ph3kT96eUEh2tftNZSh7GQkBEgDf7A1U9q", - "baseMint": "CgbJxXyaHeU8VsquBpySuFXA94b6LWXxioZ28wRr8fs9", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "8UF1DNUAzTe2ZZF2WtSWKizy9MUKHcEhT1dHRvQbXFUA", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3fe7HT8MTS2yAGv9SoTXMJrjLrsPeqiAWNSCU3asy8X2", - "targetOrders": "2zkAk5x1gHZhLt5qyjGE7zuCDtgMGYmq1MX2gsCgeTvL", - "baseVault": "2xDgq7W3oaUF9WvpLDgbqCXQ8VEiBBHxgsJMnCqk8zqT", - "quoteVault": "qL9tWuDH6N5JKCDporriqcvsXBXmdHMnqmMCCFHftb3", - "withdrawQueue": "6CpE2Tj6bDjrKtzEkXpX4JCd795PaAfYUpNv18TEvbDA", - "lpVault": "C7uwqmcvMZvamwUCJiLQA7YTh6WK1KhYPLX3eYanKVLD", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7W9pEftZmMvq9wm9tf5fLfMGMAY3bSa362ve1LzGDZq9", - "marketAuthority": "3TeD56mJcSHPJ5LNmUxhjGdousMbJWD9U7sjzXrd4x7c", - "marketBaseVault": "AWuRh6RFpyrnneNF43LrJj4ncfrqcnGgJSN1dA5eTDyk", - "marketQuoteVault": "4Gea6NHwWaJfgbYHfkLFDtALmB4XxJUwiuQHcgp6quRf", - "marketBids": "7goFANokqPLJYBspdsKZLxoXuFA16ZyeMba3newKjVbu", - "marketAsks": "uyoFdpkmx4JwEJ45NLXdjfwZSbnc1bbpGwd7oaSFix9", - "marketEventQueue": "D4TtWUaNVCZDAnFUptqsd4ZMmHpVARojQ8tsUJ2c4wza" - }, - { - "id": "CPdsZ3DLTmVfCMh7xGMtBhYcN2toVhun2cwVvVb8e5EL", - "baseMint": "BhPXDQio8xtNC6k5Bg5fnUVL9kGN8uvRDNwW8MZBu8DL", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "D3nthaHwgXLZGPsYcRydEXRFeEwCz5scAC8UNj7nLmWL", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6gRcnkrhMHHn5QA5hQHP6WtZ68eZ9vfxobWfN1ZCtkJD", - "targetOrders": "DM55Bfs2RSgMHtBD124rAkzXGL5JKax7b8KpUgzNSn9L", - "baseVault": "J37bZpQeHuN5zNjUQZd5gUiquJiyFivQNr9QoNgHc9nZ", - "quoteVault": "5AokXS79YYbaqV5TERgQWnL7N8VpAvdM3A3uWfowcwF9", - "withdrawQueue": "3RkSWqwPLT4E7YUhZWfFSA1ikLh8yEqShUMKt8H3V9ym", - "lpVault": "BqeRUpWCcFedcBw6QxYvJd3rnakck6z2pbCkZGBNPb55", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2Emb4Niq8j4dPLYeoKecvGms8P2GWXYCiao14DpKu1b9", - "marketAuthority": "45XEQ7V2B5jyybU3hu5Z4CC4USdqDGeDhb61qyqZCG46", - "marketBaseVault": "EGR5ryv3DmrhX26DX6e5iRPN1TSKCBCyFCZNLwpB3Tnk", - "marketQuoteVault": "AKv7CzV8DVeckTWueSXKm28BxwrYhhYFcGvKUCRnMTy7", - "marketBids": "8xMJ1Mghaiz99BthxgAf7AoXUKdQm1e4HPcYwzVT8ikc", - "marketAsks": "BZgb8Zo1YqkuhjYrWXSfbggRNJpefp9HrbyvXR2FN7af", - "marketEventQueue": "8YZn3dC8unWmcB2kATiwavF7cQ6y2WwBGR7oFm99XFAj" - }, - { - "id": "CpzMNgZPyNr2A2SBHTYwLoBSTCmo2ULBPQfHkEEjbMnN", - "baseMint": "H5gczCNbrtso6BqGKihF97RaWaxpUEZnFuFUKK4YX3s2", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6H4oec4siJxBUQ7WVW1MtrXYnQvGGH1xqZBjxdeakZUW", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2m4xK5wyj5Cw9K2hC27EykmYfuhNY6auuyCK7C4wvrq1", - "targetOrders": "9XYvYdwWuSg2LaSpqLpxxZdvoCf9wJiZzTQPa8miZ4iy", - "baseVault": "CnRW7mJNUxn3LZABXdDUze8fAQ9avLNeQiC4k42Z4zvr", - "quoteVault": "5KvbWu83jiXDaj8dPmYqAAYVuyKJCd2HgvWNNK2N5FeG", - "withdrawQueue": "Bg3H94tofWvEMcjDBQK7cBVuRMzUHXFK9Xa1TCF2mJXA", - "lpVault": "4ajxNLqZYzz3u5KFS925rKLJrQnDS4abj8T1SiQBHRe4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BYXvAQJoiPb3355yFWeiGiRLpoBgcJfgzNttoGrrgA7A", - "marketAuthority": "CeikRu5Vtg8bb4amdpYMD1NFDTNhd2un1WzcrGSvhL6v", - "marketBaseVault": "3eaNTEHy4AGNrgbE4sfXiE2htsnurwuF5xoH7y9imoEw", - "marketQuoteVault": "64EDUwL7uPdPdZYNtXNzC9hukwBm2LGdBeJ5Gn2aiiN6", - "marketBids": "5Snqe4CBSR1FcA7GKm8o6XYh3HypCLSVQMwGzrPcufMA", - "marketAsks": "48hzkgawQEmUUsVo2PJtKgQpFP7jc1AJSwjXP7GmFmr8", - "marketEventQueue": "FZVhhNjEU6XwtXxH1SZVpnaUu3nkuSxJvGUZCBRAfoXQ" - }, - { - "id": "CqfV89b9qJVgT6sbT9VMKCjnfX6CFrDcre96zzcpP1gR", - "baseMint": "Bqd2ujCTEzpKzfjb1FHL7FKrdM6n1rZSnRecJK57EoKz", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FM8yfVgaEHrpSzNZeZ1o4v5iLZuT9soNuqaWD72bJyqs", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6NgVqHeuxNe7vhiTC1ybaeTT9YRE1Duz7qrsLoLYc7bn", - "targetOrders": "8VdySmFkQ4RAF5mranzWtZmcbNwmTQaVpDE9LadcjREq", - "baseVault": "3Si9vQ7PateE95bXRVxVimXpDwmHjrPsP6yhg3CYpSGB", - "quoteVault": "7RNB7fz7ftexwUqbX7iVpEoug3SQ4VB3GhnM1nfvgf9L", - "withdrawQueue": "3dDH8Gf81dYYeGZTP5TJcWRYF54J5NKVtJwSeJW9LqHC", - "lpVault": "GRJ6dsVPJ2awUaRAP2doARbK8poFf977bYP3f2RsXrir", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "76d1Gv8649Fhn7HtZTxaPCMFA4fYxaQ3jbna7pGMGA6", - "marketAuthority": "3zGnhvahdbBCAcdR5r5wxRV3RghorMXVF7rpAUnPSDjD", - "marketBaseVault": "9xgGG8UqS8AkpoKQnLh8KyUqtZ27LxNQjBJA86xAkERK", - "marketQuoteVault": "B6T4vXvievtxFoZ8R7mV6LD5r2ENXThRoW4iitsPVThm", - "marketBids": "EaPDUExizGZrshEitFrzB9FbXFWn5W5WH9SomW68NC15", - "marketAsks": "4ApBti9Y2Wxs8Ac5ZobWH9v7ho9vYpnhujdpWkJjxAAN", - "marketEventQueue": "GudfKdSZZdvunbJsXHHm9Rn6uomAPKfa3d337sQJqAU8" - }, - { - "id": "CQJZwDYDs9buNxGZJWLcu54Fuob9n9CP8PFPeJWUzNMz", - "baseMint": "8AN7mWuw6M81w3gDcxvvQR2Kr5RGKJjzh7ZKAPPmrcJG", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2QR7Dp8GUZkg5gG9tF6A3N3ST5zW3nfFvPbtR8YJy4Sj", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2PkpG6jSepSCN7yeG1cNKTbL76ttRbrAwsAcmSzmkDVe", - "targetOrders": "GqHErrGjzTP7N9mx1aimK4ULXAgNH95bwVupykToPpgV", - "baseVault": "6BAKQjrCWK3xDK4qkEdrWj9Lz9mP6E4eaVVtqb56ri8E", - "quoteVault": "F8ijCmT4wHtAttsVTpHrB6UCXnB4YBqqGLYc288VUUVb", - "withdrawQueue": "8UEC5eLs9Qnzf72hFjBgRDm46W31WgUVtgkrD4Q5qDAV", - "lpVault": "Etyg5tx9sJcYnb3uBirEPhxGsTSQnjR9JV1LQjb4zmZg", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DSBGNeUVBJ5EUKHfB8zJsbgyP1wPfY2sMW3ENtFHScgm", - "marketAuthority": "657J3RrSnAziTFR6maNY4oMkCnggokYx5JtBczwHwZmB", - "marketBaseVault": "J1KV5pCfcYNnUSSyfNFibWBh3xrP8LFNhfyGKHXWiy9h", - "marketQuoteVault": "85pC6FhB6r6nM8iuyRYqxuxUrmujgbatDGBXwzcSDfEJ", - "marketBids": "j6RtLm3YJFSZe4rBNNwvVHxSYCRcQJHUEVpvWQFEzHp", - "marketAsks": "GAejGTEhgftQwEaKGhLN3QeictGMqHqFBXkT8k1yCBk8", - "marketEventQueue": "6cY7x38ZzkxDkHvo5uW4nGUnbLvpjzopofRhkRUM2UtR" - }, - { - "id": "CqkwivktV3dnEn6mhGKXpXn8i35W8UFNHEadBgvccJ8s", - "baseMint": "G7uYedVqFy97mzjygebnmmaMUVxWHFhNZotY6Zzsprvf", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "Dvw9fSiY7EDHikZcSzKEQGJ7fF1GsDPesEQFHNYZKQJm", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4VVUBxP6oit976mbCzFQwxLgdZ36puRpAFxUDNWkX6Ln", - "targetOrders": "J2fF8QGPKSNLtEUx29JgWZitRNTD1b7A1ZWtiXBDq3g4", - "baseVault": "9GfvgpETT8nstHxasqeYqJyoJH2FTFh24geySDu26TVq", - "quoteVault": "BKeLWhtEFgYjasU4rafZKwfaikmgCZPPdnLXcwTuY6r1", - "withdrawQueue": "HTLiEKz4VN7y8HGZGm5c667c6KxbmoSBk4YWzU8dUMK", - "lpVault": "E5PdQdt3HJjStVdryaiZxN1ceMwPEkfYG6ChF9XC2mkT", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2aDYzSM9y2kAoECWdPbBU8cpnjn196mEqBbDETZEKiNW", - "marketAuthority": "3wn31Fff4awRbam6yBD3ktvMmJyaJYhDrXTor4fB7uHL", - "marketBaseVault": "HUVJ7ndCiPwDDpt7MzzxAs3qHgxFooHfUhcEuXbpW519", - "marketQuoteVault": "376udbwdKB21VzKFr8HUMXyy2X98RpuUGJjvAhBWtNy5", - "marketBids": "9inJu53wSkqHY71V3yvTCPpbBJqTK9bhyHTE47aV7gz4", - "marketAsks": "8Z4ggUiBYVzU5DWff447DcsN1zWLvghV8FTzqMmmHD2Y", - "marketEventQueue": "6zPGhWsNE9m9XuvD9Xd6Ka5UAwzKnQCnZ55chMpFhRFP" - }, - { - "id": "CR2r2DXpG9x7U3bak2ZQAoQJxe3CZUbU5XWqdYMXmSLf", - "baseMint": "StepAscQoEioFxxWGnh2sLBDFp9d8rvKz2Yp39iDpyT", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BvS2kGRcRpHerwrqqv9qSKwHBniudLgLHqmmiHpsLNQZ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BsPoX81BWSfSTHK7fca8wUc1bZmfaT4r9yKHxHRYQYfD", - "targetOrders": "RBjAfDA2Ac6WRHhfMTiBaUkTFq989vMxKZeWZx6JCaJ", - "baseVault": "FLDE4dBfaKqQXpyrwh89QXgZPeDZoEq7oYtNjGFv8kof", - "quoteVault": "8TzNGQfNM77njYVPWrrXaKtmZ2vJB1HQsFQgfyzxW2uM", - "withdrawQueue": "5RAg26V9JgJveAvmMgsSzF21wF9N4hU7KCFhxc42DGs1", - "lpVault": "BrprZXDv1E6w275AE55ZohrLmPg1JYN5BKah3bFokSEm", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "97qCB4cAVSTthvJu3eNoEx6AY6DLuRDtCoPm5Tdyg77S", - "marketAuthority": "FbwU5U1Doj2PSKRJi7pnCny4dFPPJURwALkFhHwdHaMW", - "marketBaseVault": "CVNye3Xr9Jv26c8TVqZZHq4F43BhoWWfmrzyp1M9YA67", - "marketQuoteVault": "AnGbReAhCDFkR83nB8mXTDX5dQJFB8Pwicu6pGMfCLjt", - "marketBids": "5Xdpf7CMGFDkJj1smcVQAAZG6GY9gqAns18QLKbPZKsw", - "marketAsks": "6Tqwg8nrKJrcqsr4zR9wJuPv3iXsHAMN65FxwJ3RMH8S", - "marketEventQueue": "5frw4m8pEZHorTKVzmMzvf8xLUrj65vN7wA57KzaZFK3" - }, - { - "id": "CRtnNX53xLUsftgJJrpeq9i8RSAvqAiNhqw5TxWhN2zA", - "baseMint": "NXH66NhJZ3woe1KCYFGwSJHTtpELuv4Mf8YoVthWtce", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "KQ75qCAYCD29fY98aX26KuB5T7zQT9EdRQuABkUjsD9", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CCLXZdLr3hnoRghuXendLEKxJ94qEaibbxpt9EforQCo", - "targetOrders": "DJAcRBkyeig4EjmYrsnshdWohGNWDw5Wvf5dDFaDskTy", - "baseVault": "AdWrAfmkwjaxj73ynPGd7dcFwvCjec2dTKmJpGvfDm7D", - "quoteVault": "B8fpgRXHi3vwTW85fKVC29M1EoM9tsZfVgjqCvxkfg3e", - "withdrawQueue": "EBUKsxLPqsC87DhpkGbrEh19eB7bmQL7MMAsk8E267Pb", - "lpVault": "gNrUmYnZptTGYvAVu8yzMou5qrH2yV9mxxTUBFWpfkP", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3p4KCdzcWSbeH3b94X3pvizTonaqxJHjo3NfhiM2Uo2U", - "marketAuthority": "GQ6UWuoTWPwT83TSHkA7NYTTLwJqmr6uGSs5UeUTcrsZ", - "marketBaseVault": "6dWmgREcxFP5gMnrwknhJaj5EKigqBnUyHBp59F9D4A1", - "marketQuoteVault": "ErQmqbMhSH7DCnv66vfCMh889ouoyxvHscebHTm1b3wX", - "marketBids": "9UAGEXbp7VK7GWa7SmyXyxT4VZ4qwZcgX7Y93NUQDU4k", - "marketAsks": "HTangWQvzGND9gZe93dHqoFGUegPSx3NVusd7LR4S5Sb", - "marketEventQueue": "C4j5DnHc8y7v8yJGgyKAsZMHxXK3gnUvitaEuy1oTXk2" - }, - { - "id": "CrVQ4QaRZsgFYwwtQu8JauqWk395nm9qXaZS6ZKMGsA6", - "baseMint": "45wdSjpSqZCk9mkqmq5Nh7beCEqqUJMJcVduwYCip5eq", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "G22bXHFnusGybWDPoX2fadQJzRWgaNuTkCvwLgdVuPxS", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "D6zg2WENNmZUnT4rnTiiUw7iTiLgiipGEN9mNvpMwfgy", - "targetOrders": "CfSx78wBwqdfKqsCodaj56XCccgDaBgtL4UWX5QqZNxk", - "baseVault": "7GRZgikJx52eTZcjet4LztnkXyViUHJgoGRSvq1Tgd2d", - "quoteVault": "6xe1BSu4b14vQmocWQE47FdyQZ6cf2wTU2VDVP9A1gqj", - "withdrawQueue": "AzNRnxibbymgi5gGj1pdUEzCKLCjqN6S7DCRdCT9wwK8", - "lpVault": "3n67XjudTNHwkau6vQrbRwvNtXx9NacApK1yWxNFCtBN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9sjSvnDEa3GSSUjaHqCnHao27ZPB2Kn1JJ7WoZTRe94G", - "marketAuthority": "4dPHwFnZt8GF8Xrxq7223YDmTKk2ReNWM8uP7HPY5gCM", - "marketBaseVault": "nq4NzBKpNDxJzb6n5tQWepY7YtNvEDcEmyKW2DpEz81", - "marketQuoteVault": "3VqwG3Yk6Jg7WsjxWJ2B44dhnJ7cb9wshjgKkzNiJ53g", - "marketBids": "6aQSDT8Ver3o6ikCoLXVrmooFL32QxozNf8dbt4vnKWb", - "marketAsks": "GQRYe76AeY8ayaoDRSo2h2WjCwLw6SiyXYYx5am1TnRa", - "marketEventQueue": "CkyqibGYNSzuzERvNdren3PEdgJ8wPUFT4Z9pgUCDNhL" - }, - { - "id": "CsDfMCRdKb7Bd67dNB5qMfBQxWiauSzXeQS3zkdscXQT", - "baseMint": "CVj6FV4HmhEsn7xQXCjj5iqbDQHB7hQ8AwZjB6P8UMDu", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "FYqysn78Xo9B6AZyfDDwaQgM7RKgDb9sCnmfKLEz7GMh", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3aPu4pGBGnvWxnnhHApL2qEEeToVTw262umW3HXG3K2C", - "targetOrders": "29P9MqPFLmL5AwixXDaXzWBjtPUfGbcWBFfGo4zmtwEV", - "baseVault": "EcwUZWkQEkEZRNqFZ647zrLHWF5ofLHqHHcWMGFnJPU4", - "quoteVault": "5cQgjNoMJtAWUokQBSatoMY6vqzwMAaBpECy9Y95T6Mv", - "withdrawQueue": "B7p51Mg9XWnKyh9tx9VBrUSpvc5RMhAvvq6pTc7bHtXU", - "lpVault": "2ZJ9LBp7KBYe9uTRvSzXUg4U6rH5EqPRxwcevYUatbPV", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "96TeJEPXefatFJXZegQvNiJaP23Jp7FCZpxwbvLERRAK", - "marketAuthority": "CvP6khdQ32R3cwVFzbQdgNkR8DY1Tkb9iRxBG7umEKML", - "marketBaseVault": "A3krM6V4dP8npFUV4N8FsDzbPJv1NnpSe3sD7PVHmyZK", - "marketQuoteVault": "sPBXPbitQ4rjYVLL7GkAjiAbBLAXmyrrudRSiM4rEH4", - "marketBids": "6uz9KaXURMHnXa9gAmVPLxPygQ99Qk4hnzTLYTCpvBuk", - "marketAsks": "Ek9yhe4zKJUpWQXKtZsnxsFEjVKWziaY8zRZ7Zbfh1Af", - "marketEventQueue": "6JPrdXwpVhRGHsyVPcUJBewStbpa415g5g69Jme5xuE6" - }, - { - "id": "Csdu9NFbhrdpnmeaXygi7jUem9KnVrYAYpQ2vKm9Whfv", - "baseMint": "apnggFw6CdVzxjdVC3KbfT6qVYfNi4VgQBuW7hVM9us", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4MhR9ABsuNNt2QazPTXug8dw74qEibdxC7MGyepbt58h", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9MJR4JEMMmsduM2MkveP1ZRiqBqKKwSrq4U6kipMYoeD", - "targetOrders": "BrDeUYkiDqJmYmBnec9tibcWGq8FZg24nt5weQNyuiSP", - "baseVault": "69vBCmqwDoMoSUCoA9GjGmZwWrYQJqZTudtpNUAXgD5W", - "quoteVault": "BBjQHrywV8MQ7LRB5LRPDzesehdsAXmWnGJAz6XkrupP", - "withdrawQueue": "cofWUVa7pghxELhY1U54NM8642uCFRBnpTDiQiLYsKA", - "lpVault": "9dbMwvSiAZ9vQCYFEF2kjzHi7J2T7kUf6AikHp5bAM2F", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "D2dgZSc3PECDLuEGd6WLRc4MDy5nNyt3amaukXiPJVb3", - "marketAuthority": "7tiMekv6uWVKNqL6hPVb9PcaGzMKHEcvPTfGkQxWUWqE", - "marketBaseVault": "9hLq8myysZxYhJG3SDpa2s1HFejntGZWcyGwCW1wWEbY", - "marketQuoteVault": "9seLbLTk639GVcU4RSmhUE81RX6st5F4jCF674zcJHXq", - "marketBids": "634KY7CrBg6UL7vmibUxqK1EFArtyoaiq6KAJoEBdbuV", - "marketAsks": "86tPjnuskkNYFxFyney16vWandFq7cGmHksE4frCb45s", - "marketEventQueue": "5otrG574XRzwPnVW5EqF17L7yyKfVmjDp4jGV1dLXwfa" - }, - { - "id": "CSeDvBLkMmDpiB7821BDt45Wo7ZU2MZ5rosGroTbUpSX", - "baseMint": "G8aJx17Wzgwc9pnSJAkmWwBVPUxsRELryWwDENMszNuQ", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "AV4PZZrKDu7uEjfeFB3MF34ZhwtMLaR3SKLmr4qUeP7j", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GSpQ9QCzY1jv4PdxgDEzaqith5mbHtKi1ce5bUzZvdXo", - "targetOrders": "4nNPGM62ctTbQbLsweF3aDiZ7d3k2VTDRByC5c1P8wi1", - "baseVault": "8m9f9TJVtVnTATu9y89whh9Rn29Lm61VoPB9r4TayLJ1", - "quoteVault": "Hb2rnL7kfq7vb5SB3m7rjDSLoZGEG5UreoM1kQbYE1UY", - "withdrawQueue": "HHpsxaVuGje4iWtYN2z946FBMrCQqooMw1JbMGdpnra2", - "lpVault": "CmCdkXiA9qF3q8KvetHh96ajYiJiJ8FcDMMGAiuviGbJ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "65juXh7jDpxVKaD8SDBjCiG5dLWvRPTeXo4k2gupy58t", - "marketAuthority": "GMXfwuQqVj2oZwnYdXTmQj68cKq4AoGrtaQfXrJaJKm3", - "marketBaseVault": "G6vYQFE5mHsEfUTmMFt2mq6xPvLNi1jR7w8uQa5oAcJr", - "marketQuoteVault": "3hGgcfR3Jiny3gyVRpGW6jkxZQPsxY64cTXcBK8s5VHH", - "marketBids": "477r6MTkUgJ2EvjBHrTj5kkQWtHZ76TfBDzP9B9FBf7N", - "marketAsks": "2iJi8P4Tx1fL4n6WvCFyMEdemBpaMFVyWKKkjCLCSAAF", - "marketEventQueue": "GxsQeutZsQFPUzm14cvd1oqzjzt9M3enzHm9ACMbS1ET" - }, - { - "id": "CsrwaXBpBjUFBUZgJTp9NdxKtNzXPCgXzkXbVb4p2f4V", - "baseMint": "4PhPtyBhmMYBLjiJPr3wef2syoMSJYn5WcNgXxvmG3NZ", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "FstPepuEp81A2GzUkxJbBXw6wH1TyjiXTQXXfkUPJQbw", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BCqxzjQzdoFDrvKwc8YVxF44kqN3kZuE6Xv3JY6GvCHV", - "targetOrders": "4zUAHQc5fuWVD6TMEthSMe77GCjzd1frxWwVukhScf2i", - "baseVault": "FZjiWQhRUsaCJq7EaZZpL4R8VhpgMGWJb1WmBAFYwX6D", - "quoteVault": "6kQcJuAfkpLuEEbBaceg9XJsovjvNeKNAmbnfWXGz71N", - "withdrawQueue": "5rmkHaDomQVzH5KpszrcxnRsq1etbJjNZjYrYovqbZ8k", - "lpVault": "H9Bvue8RWHc53mNPvffnLTg63drzdFyDkab87yTTcc1T", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "jYEYoUvgFaoGgs4WdGEJKUp2NphNmqVvLKZjAEGoKLk", - "marketAuthority": "AZySQyqLeBYYpJKYMqmePJGLsxUKMGEqursPveDfvUzK", - "marketBaseVault": "zECWg196fCRjYyjb1txLxmRx4J4jDUNwD9X2zC4wR7H", - "marketQuoteVault": "GHcWqRbZSrtjHGUgVhSc66dP8PQDaPbXmHHS1SAEYFkq", - "marketBids": "A5KxVWLU28TJ9umncVNiMKJoTnf8VgcQb8iZgcyXpFhY", - "marketAsks": "2Bo5ABxfTbn7qStjDMbmA5EuzUu4g82gse43AD8Ukzpy", - "marketEventQueue": "33L99QowWZX92rUijUQbo8TEkDEh1fonLjZH6D9GipPp" - }, - { - "id": "CSVNLrP9eSdbY5SpxWwiBdaQJfrcvHvLffTHsznWXbjJ", - "baseMint": "WCGXaSoSWgwBwpFzCq42eFpLFemLTCNPrAYEQt2eVmm", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "FfopfSbSLqULRg44bBm5ZAMAFAdyrsLeSRVuBwTUWAVu", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GXeegyHQAhSeeQaDb8j78bb9c2NHE3TG8TgyDsngUUoH", - "targetOrders": "CxrMYsQNNNh2DgHD5kz9UjMB96cWerZrfXFd1KY22yQi", - "baseVault": "73uJLooZLwJUJpuB3xn2qytYAJ1dxPWA33JXaahboPa5", - "quoteVault": "53ao2wgBJb9XoLrUdBXnugS3UnU468XL47WnyoDcQDxi", - "withdrawQueue": "GY5C2E25ARaaFVjCumD45SMDfgLj4zGfaXQwPcFwC7Ux", - "lpVault": "6Zn6VVRQJcS9yvNFTwVdutUCYaWmsfBiAydeh8d8DkhL", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "E3Brmq2jhmLCHrCGxSVp7a2gV5N7JjkGfezoAUUYjUVv", - "marketAuthority": "sj53dRn92sARV5T7Q6PdcG9KYuq11VHEn6dqvosY6PZ", - "marketBaseVault": "En4UxsbVRgWUnMU9w55xWvdzzvJjHHEDwTTz9ZMJRJVp", - "marketQuoteVault": "FKsknEE8QfzVKDKYKtW5XMMbXrnGeVH2YGvmic5WvuD1", - "marketBids": "FJdK389ATsgqKeRAZvnd839ZBzMggs2raCrLT8Zmg13S", - "marketAsks": "3cNH65PBu9U958GN9dzbdAE8Mcte49yXjJJPLLedVeEE", - "marketEventQueue": "AVa8mYi8Nr53CETS4jAgd6YUSc2Dyc6ErogVwktd4uKc" - }, - { - "id": "CT4eAfwgNoeZn8pFgcWp5GUVpjyyXpYdaYnyU6YiUfkY", - "baseMint": "HAgX1HSfok8DohiNCS54FnC2UJkDSrRVnT38W3iWFwc8", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "eTtpHQRkiZfabQ73wCbEgxsSDjvcJWDek7S5JotnDMA", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "E5QTdBG49CEkmsg2qG1Di22S6gcyBLMrfzpQEcagGjxx", - "targetOrders": "4ptNnQ8FYHR3ET4f6igrRjDMXauThGaGn2s1L81KJ8kb", - "baseVault": "B1cxBZZ4LeWrJpvXMboHzs98KhQUfuHjpDcoCTjJCoxw", - "quoteVault": "C6dnRNVmAmoKAPhki8k8esqyNCB7XGcxsmw2jy5dSNg7", - "withdrawQueue": "3auV7EvNFGFHr8VNPGprgPENunnSkq1Mwp4btQzjLWaR", - "lpVault": "FMTcrGvNDPxE7f7cP3xeVPBisgbQxDRPDCiRC5WKeYJE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FhiqrjSsQuEEe2FUMxzkwFadsAwA9ea9YMJLivEFKFbQ", - "marketAuthority": "9G5gVDhDZ2P5mAtTo4SynnkT6yigStTHYJgtppZG7fa3", - "marketBaseVault": "7arECNW2epjngJrKtxvrPtrJAHiV6izuRBdX1XTsqPQb", - "marketQuoteVault": "9HSK1MACBtSbw4WSZArEmR9jBnWs5qHoHbaw1jaSbKmJ", - "marketBids": "Aeamopuh8npJzr8mvmTqJkGUqDLypmTPW1TBZAPBNi12", - "marketAsks": "2rY2LBXvDnG7Bkp9J3RBr8BX79WKuiwAmShSAE2ubyaX", - "marketEventQueue": "G2rLjttUcvtArsNshq3nrrhrWAwt92c6442F7mAz7YZm" - }, - { - "id": "CThyGgPR3Q8PgjPjiJvkcswMxMGX6344kTcLhB85aPvF", - "baseMint": "3XUmHsyDaZFCuhJ21fbZ4YWqcmNeajumGEkSDVs5FUos", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6CwUQDsAFBb7UxW1RpwwakUruo5dsHg7d4mL76k7bPKv", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8T9JNcjLSBbYp14nbhBeQnH9UmCZ93Us7r51NTkQRfEt", - "targetOrders": "D7VGen72oZTyE2kwbMxK3et7BNzhT5sVSWon2rX3YrsA", - "baseVault": "4QaEyjaXkCtgpmgKTvyVhoSHweibPASSBpWgRd4eZchU", - "quoteVault": "CcSnWdHMT7B4FVGQ47jH8iVs6uQytDsGCPFHSw4f2PTz", - "withdrawQueue": "2Rubjsv5Q3Mxo6eVpNu1TmQ1NSTxWDdiqiEvWopRAdYR", - "lpVault": "BKLdYw7Ui8u3ow76fx3nNo3C3yW1p5xs5MTsFSJ98saH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9V1dXbBZCYuXpwMEcidrvf3nDP7XGRV9ZamJzzPSp37d", - "marketAuthority": "2S5Agt9DMbqxQnqYAGJVPR3uYXPSbGQJ4nqc6MH54HF2", - "marketBaseVault": "67kcCgPcF1Rn126qL5LTssfKtXt6FVFrVxKPXcLsczYM", - "marketQuoteVault": "F8wDyQ5mkcVhEbKr1BwBdAjUp6TU9yJF9yWju3wLSZ78", - "marketBids": "9TTjf1RxH5qpo5CU8F4MccaGLneqAoWSJkkUahxEKUwr", - "marketAsks": "4GwxsvdPide76DGeGS55rPiNRmGW4zzEALmXPADtKm64", - "marketEventQueue": "HC9ByvwHLUz9HcBChaWx6nBdjCipSWKgwCTM6Go1HXnQ" - }, - { - "id": "CTNM9E4qeV3BrST4THSPs8JXi6m5j1wsHP6FsMn5H36Z", - "baseMint": "6qLSf4cz5gb9xw9H7E3sHw3sbpAW8stvGHXePMvEa63F", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "2hziJ7WZd59x64MxCNSYisvcNNZ8rsjDqNCTBznFYyYY", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HN8r6ba7f5u9KgM3v63Hgtyt6YmnYvTGRZAhc88YKzVs", - "targetOrders": "5ukapw27Vpv7TrLw8Fz4XP5hzKyJqnEU7RPwZPLEtnjq", - "baseVault": "Gc4Zh7FTDfPHb1QtB8eacAyUp7Q9nudXYCX7c31TZtoj", - "quoteVault": "9NSfAQM24rUqa1qoqiByFZB5rTUXUFyFfNVzTUnJGYPs", - "withdrawQueue": "HUeGEgbGyJvXVeiz7zdcxzD4T3XxYrH6uABb9N88NBJ2", - "lpVault": "AyXCRSk4ya5URXqTbk5nh35KuxvgrwrCPF4bM8Gf3fMT", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7iTvzDN2Pg739LFr5gBuGmZkq7uCAEiMC6aMX3KQeqUw", - "marketAuthority": "6khSg4C2rFHj1YauMwZhBHpzxRjck8xtNbiQwFBLBwhP", - "marketBaseVault": "5LuMNbq7m8TzKTgRuwNa1hyJ2n3ZooA2op7pwf1pV13W", - "marketQuoteVault": "4scoACRqzq1G9xbyLsQVncnyCMXtaio6A2upg4ZdYHTW", - "marketBids": "DMy8ThHDnEzoU53EZ2MXsNEkHR3swKiXqUhSfCp3Jrko", - "marketAsks": "ULKmgsryNYfQcLbX8V6mCUJ7WH9YbKGYUSySVmAFQYE", - "marketEventQueue": "B5cYfh83tXPRZXTD91fuJjFmExdMRvXG9HJ1kaezutVt" - }, - { - "id": "CUMR6rEhCr1DMrvtMyzCdoQk72Cy6exkvFARi9hEkTso", - "baseMint": "6TgvYd7eApfcZ7K5Mur7MaUQ2xT7THB4cLHWuMkQdU5Z", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BEcTPZpJ4SGb7kLkPsWQHHuaj6bhD9NPJGQuvb1Qokwo", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3iHJRRu3A9UBuLfYcYpkc3dUi7TgfNMHZfdfZwWEj6Kk", - "targetOrders": "6FpYArMkdZK2YNWZVH9M6Hd8pNxz6DYnUnJTwLd4GfeK", - "baseVault": "26aybs75dwZr9ocToaHuJ8xPz6hKdae3hu9nE9aW719d", - "quoteVault": "9pznirquDirypujRniXVC6mCQvTJVGTZ79GKgXzFJJS", - "withdrawQueue": "7wBq4yQ1qjibczmkkMGCcidLJ93ZDru6ruBnZAZhANFQ", - "lpVault": "9moW59TFaoEpSob1SeT2uMUnFifC6KyHrxyTfNRPPFE4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4k4WXdmrWjCG71E4pxMs6SQRRB5cypGNYatKb2iMnqN4", - "marketAuthority": "AxcnrofCo17GRre9trtRDndit1TrnXcfJ9o2gcTJ6sxd", - "marketBaseVault": "7dvyE5EeZ4TxXMR7mWM6dFCKAtkPZPKzHcyWA3AJfEov", - "marketQuoteVault": "4yNnF8JqG8WLi55o3cfq65ahSER1ceeiakVAeS8CGp4U", - "marketBids": "BA3HxvtCnSvuuBy48yxooiBe5mSmXx665V8CiSznoBdz", - "marketAsks": "BV8yXfPtmQD7uT5ZBdtANJ2inPq5Ln1vxHfenCWpn6Vh", - "marketEventQueue": "FZTGYh3zcAZKarh2U5vuF5Tnud21ngMvKS8wvzYqnq3g" - }, - { - "id": "CVG8k68D3EFpAnGCMtNTyzcobaVmRyBJkdQeGGmPSWMA", - "baseMint": "CpFE715P5DnDoJj9FbCRcuyHHeTXNdRnvzNkHvq1o23U", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HJNkGg6pdsB3wawRQeKB1tiaPDdMmoBkP5JrXEq79tED", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3R5wKJyW61MjrnPebMS9bD3EaRnJwcTG89ckY5Yrjjce", - "targetOrders": "B7SQztkdDztJ8BkJw8bbTP8GhT35jgJA4RQ11NHTta3R", - "baseVault": "GZMbPDKsfJDobqNAsZz8qyQQCWv8t2ycDnhNdrcjPonS", - "quoteVault": "C5H9oC6JSkkDwMyc37z8i5DXczbfaeUZ2UCRDS7BGG62", - "withdrawQueue": "DSDfGjyz36ouQQeSEnnYcGrUeyBtCKwZwqryxVCMSQfc", - "lpVault": "5pENMsA6pim8fLHSYBw99uCPU7yMeSsQHX65jFtpzm7J", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CYtQvUfn1x77ESHWPZw5UkxeypRGyFQK9WQJVGjidkxG", - "marketAuthority": "CF6NT8euvHbgKU8DziBGyFByWNcNGXAUytLKydnS1XtC", - "marketBaseVault": "DbwQvqwAu93RLP4g8ex6W2TUG11dk4z6sf96XtQSquCG", - "marketQuoteVault": "AeyTnFrSDqiUD3YyANMzYo8SLBj4ANGFJfZgyfhWMnZN", - "marketBids": "HWoamKW1bHcVTXzSsgAjbkUR6txp18YZ3AMZmopnVweH", - "marketAsks": "AFC23iZkhtSNDq55FsjF5zV9vNuYyiv4CAsKSpSzjoXS", - "marketEventQueue": "Dysv5EwiHqVjngvqQbURc5fnt9xFuDZpaw7PyKrAdmUA" - }, - { - "id": "CW7rK819B8ib9xiFC7bCqSQgXywpPQTomd6S9yuQBVFH", - "baseMint": "H1QvHLhmk4rL36FBphnFUaQszf6RHGU8RLptPSuPcQwX", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "43Cbs1JTwnMq9L8t33nUrGxEeqbcyY2rfYfpe4BiR7sP", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AWMbmKk2a746zeiQGEC7Sf9jGM4GsZPvveBHU9NVgB65", - "targetOrders": "28XvSoCJPQJne8ZCTQjsjLJgtHvtk2AmUaPxnJJm3oNv", - "baseVault": "CGZEkWjqdtQhYdENjRpBboZgHUKh4SzBFCPVpwAsR8NK", - "quoteVault": "H3PLnswRY5RNWCeXzVnaTQgQx9Ni1oNNa2x7DUE9VtLF", - "withdrawQueue": "EWqk9G89DHzvFtNdA1XUaky13FuWsYrjqGBsMqrnC5U1", - "lpVault": "HoMwuYUqoaiPfxFA5xXzkA6p1GjCDw5g8GoTG1UiggSp", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GLK11nNeszbYBvxvMe6h9PJnBqbuB5iBLPCbiXhoojFj", - "marketAuthority": "CPTqxYQouXSTsDxfh6s9WpWSeDy6EkvyLk9ca9S62grF", - "marketBaseVault": "Bn2jJt4JywL4eNqSoNj59b5JNrUg7qdysWdxTJWV7EVZ", - "marketQuoteVault": "DWziWvi9npvX1eTNqaJUaYTRR5YLy75DYxq6ssB3N6Vu", - "marketBids": "Cv81ToL6mrYiAbsNshTGdK9WSpiCr4Lwh4WeE8RoDZrW", - "marketAsks": "EXGGpvN72n4A1fdPnWHeXnyUcEyykdyysQFgi6cy71XL", - "marketEventQueue": "73cwp28UnhdVqALqkg6qdCVdYt5jyz5cm388Kx4JmBLW" - }, - { - "id": "cW87vtbsZkRLMnX9aBFJ4e98Da7xBc8tEbsK5cxABfw", - "baseMint": "9CzmA137fzLtdyfaBY63Sa85uY8ZvBiX3MrAJypzsDGR", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "EAeWLsYednxSQBP6dAjtZC1JSvBnSpgnhrZzRNn1SyrP", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "hNEZqbSy4jRydbmdG3zFm7jQKuRQ8ZzzNftaxbVXLBZ", - "targetOrders": "6qDtrcgoUSDgvRd15wWYim579khvr8skFNAtFBBY6Ttv", - "baseVault": "GVc5unXd1cBugEcVkVtEu5B8VaMqt6tULRzZhtjS5QLA", - "quoteVault": "ALHn71ibxnSfZW69CJ8DFwN5zpfNFcsXMDBzxwnrkWTN", - "withdrawQueue": "8pWf5Ph85PxY7LT3RWFKB9HF3XKN2HJKJ4haF4iemMCy", - "lpVault": "GyHvzT3EYhvqWqZW8pD3UPyrYb5dUMxcQY6X1sLgKcK4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DVKBb7LmyxSzVX3B9kmiCJTH1hydF4yhN7J7a3VTn33d", - "marketAuthority": "9Kc5Khf2FCSuMrBGCu9NTB6DLccQCXhZBqz5TmCbfchd", - "marketBaseVault": "ELHpgq9Wq3CEakvaDZbKiWTV9rv22YCJ2RjTCmxSwTgz", - "marketQuoteVault": "58872dBzpP5qhm2YniKzc5NyjpZY43Z5Df52f7fe5HA4", - "marketBids": "9NgYgr36AAPFEt8y5sidhrcyEsdCTc7RbFrLeUnBfCRw", - "marketAsks": "2iRcSvZ64RNa96QU9Giia2MgKWW4aqbVF6V992NnvqyN", - "marketEventQueue": "4ycBMSFxVMVU6YRDTjLrbkf2C8BcDEBJD3wU1tkMgmFA" - }, - { - "id": "CW9wzMhiRNNFTiCMRhPbxMeYVs996nv1rNDVSkyi2Dvb", - "baseMint": "HDLRMKW1FDz2q5Zg778CZx26UgrtnqpUDkNNJHhmVUFr", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FN7sAY66R9VpnFbAzdxZHTwWGgAcfvd76hFY1VGwmKuR", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "45q2yQGudGW8RM1hFatnH8Z7GeJBsZ6chjddqNUPYcHz", - "targetOrders": "7r4P6YSxTMRQFB7R6kUm1chX2Dn4nitYVCgWPzH9mv6s", - "baseVault": "746yt891gMfkwqRNdVvswBGp8nVYcWpEXPeMEPkknhid", - "quoteVault": "HSrYiiSw75JogqcKCUqcoayu8DViJTJw33uaMmkskA53", - "withdrawQueue": "DnCjFadaEon6yhejEHXpG5Vxe6VHGoTYw6wXA7bqJd5X", - "lpVault": "6aVyMKz1SsNkfnrQwSKGMNCA3p1aVcYnj6uz7CRgSkCy", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Tffy1yynZ7Q12jTim9JjnbPWuMpKRY6sivUkZEj6KL4", - "marketAuthority": "BiotKm7UcwL8fYGX2p4qaZrtwt6DABLs56vjmJnWdh6i", - "marketBaseVault": "5r3jdZCWaC4aSut6XAY8XSF6cqRGUqAKiLVHbY4Li6ic", - "marketQuoteVault": "4o9woa2K6Eg4V3n71QUjXJvTeukJLtDZbdt3tEny6pMF", - "marketBids": "3T4G71YU3vFcSJtqf16wLacdGNtzgYcJbFkdJjbYq6Bt", - "marketAsks": "rhSC1gjev7wE2rvwTMi6Z1p6snz13dupiRh38PXTcV3", - "marketEventQueue": "6d5BHFrNACYZ36uha5SP8bVSNyukJZyFe7PhmwwJMXot" - }, - { - "id": "CwdzWzrxfDb4TxLA722R6Lxnw8maChHJKLrqxJ1oaVLt", - "baseMint": "BLAAD2QLUgRSbQ9AB9jqAoHh55cGVcSBaCH9JGBh2zDX", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "2iqUybdfvci49cwLvDd5FbNp959abxWwhHnN9euAySiS", - "baseDecimals": 0, - "quoteDecimals": 9, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7bzDa1zrJxgaoRkVBciSpwBYUFNR7vvZYHFr9JbbkUuo", - "targetOrders": "HqUqCvY5cs2ceugho7jDVkQTTa6Cmw5iVrQeyCCoQBGH", - "baseVault": "87JxKRRdEUX7YhWWDFydJLUFPd3fhj2wFQ4kouLG9UYg", - "quoteVault": "hPL6aLP1gwVvBZtBp9y5zaxiPnnRT9JLdKTgTK8p6T4", - "withdrawQueue": "2saVb3T5zsowTbd8EpVAD1Yjxbn9f7Gz3UaH3viAmcVW", - "lpVault": "EVGtxRgQ1aLd9NwXnY3RSvGHUgVdQ9wLqo4rz3LwMGiw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9pqB1R6vdW9DFXqCtu6x9XgMUg69fEYFr5ourqLjmm4f", - "marketAuthority": "84yDMW7Aq8gBwFCi9F1fwEGh2Vtgp7C6V5A8UFmPjtnF", - "marketBaseVault": "FM7qv8ZRAfDvkx5T74cBrg9Pm2qHausZX51AJXytCLLB", - "marketQuoteVault": "DtwaAkcukBt3nCqX8Z5XE7LZxHR8S7i7ZZRaojZsAe68", - "marketBids": "EkVTG9Lz8SnagoY5SZskZHG3tPBdPfgUPM2pLAcEmf9M", - "marketAsks": "6niDJ2ZVDrfhMurfCV1dGuQvmkfdZG3wyLe3HEaGh2R", - "marketEventQueue": "5e4FCmam8XNmHYjtCLjDaSkk5o7yBzo5UerA33Gbi9yQ" - }, - { - "id": "CwPQ7GFk3rwjpAJSDftamkQzYH4VZbb4Bspzz4fTGTzJ", - "baseMint": "9k27FY1wmxKEyoMGqK4zJMT2Y8dvkiYRGM2ijjLLTrjq", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5dy8eF7KhrrmFPob5bn7PvNE1offvBQC9shoipJ52bjU", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EJy2E3nrGhmM1PcC6SNG782j7ugaUqJNGoBaSXy7nZnR", - "targetOrders": "vLtLGKWQ6EnJ2SGBe8dUkfacw1efLYmEwmaCeNdnKZf", - "baseVault": "4eq3AM1bL9WoA4xFwPLeXRCGAFHLrkQXiNuuFhxx5y4Y", - "quoteVault": "HNDoGxAMwzyPCPD9tpUFkd4Uu4FdftuwTBNM73ZaJfsF", - "withdrawQueue": "FAQHVwC7BskrLgRF7RU13PnbYjQyKyz6eHkud1kCurFi", - "lpVault": "5qrjkxrCZ5dA8xJGnZfokHxCKzCREMUYCsM36SE5m3e8", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "E8ACwLMWx3FZK3kXh34GWmqVzyGg7zh2fFx6ka9Nm5Nn", - "marketAuthority": "2u9RQBVm9ZzozFy8XcKHRCHfy1W29q5uxfezcmQYdSRy", - "marketBaseVault": "B4v4W2zUd1xJaLHqmRAj4CP8wNQmu8sjjg9vSgFHD3zd", - "marketQuoteVault": "5j9Z7Sc6BbDGPqN3TzSXd4wy9C4PFmwAzYCzu5WJy2RA", - "marketBids": "J4Mp9LpWPYzABvCZ1UB7ZqKBxqzErKFn1QDDy13DUy61", - "marketAsks": "12ziHhGbjadomVrzUZ9NPkwchmZg9zWEBYoJSb6PmAqb", - "marketEventQueue": "CdSvQu7WNWyXyRSK1wcVgjRron2uFgSxQXP7cPUyj3zm" - }, - { - "id": "Cx8ayQM9jmFY1bZPPNBXomaHhBxaZHUE3NT3uXQuxGSH", - "baseMint": "p9tNnBf4PDA7WSSFj5EVZddai6WoEiNk5B5FMyeQLtu", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "3M7XwBsjkGKx5zd4thEsJ2bsPbxR3Z8tFfi856Nkr9Bp", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9HFxCzsswzbdtg6FvrVdjen1ByTWfn8MecFu3ey4qWuW", - "targetOrders": "28jRWwPLey1NVupac9tGiJtwojzLFt5V4dK1jkrT3JtV", - "baseVault": "6E6rB6jQVo5XFZXfUTJHqJeDyUx7J3uaT5b8rSqLe4gD", - "quoteVault": "7Rj8ei7BMDjuPJvxNFzDyFfsReURfRs6fEMUo16VJtNw", - "withdrawQueue": "CpHBXcF45oUPgakD7BDNYTqrPVKCKU7hQsMPBPL6X1vc", - "lpVault": "C3beG1hmPRr4pRkRPfMBbM5obTwDSm5VPNycCuv9mH9W", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "vEMJyNXVt7siJx4BgdXCzXwUukXqZTpyLYPmJ2vVr1F", - "marketAuthority": "GcGXCZwvHbrGaWRj4TcVeh8hMeocRrLTtobsSykiSKCX", - "marketBaseVault": "4nD1S4w4qVSCyV8mVyhaL1VWi6Vc8ZC1LzZ5kDUMHnC8", - "marketQuoteVault": "CNKocsjAbmN27aXv1aYc4iTbrgUdJhu1sv7QHj6fMMQt", - "marketBids": "8YGYHk8Zf4XiHE5nctbjn9Kxmn3ymVCFtpKAPTsY5YK2", - "marketAsks": "ExMt9QovkkvXywwcdhbeUWJh6UncuXX63PadMcwExbMM", - "marketEventQueue": "BqqrjcMxb9wtRj6yYGWdhiyhmFB55V6TEwTwbgiXD4x1" - }, - { - "id": "CxZeyKhY35xd4HwxnCVhuwyW14ZiwacFduUteCXpFCyX", - "baseMint": "E6eCEE3KqjRD5UxcBYQTdV8Z535hyaBuFin9Udm6s6bz", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "ufjxNBCLWwSYi9JMtP7eqRqMXRnDk8d7v68ZkWoKrwA", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "phUca8RvQTaMkxMLGeANeojeVPrcq1HS7GSsx2nymdP", - "targetOrders": "7adioscpkF3nJ3QYWi45qLsTfgw9Lf8L2BZyD1TZKkx6", - "baseVault": "nfR54T4MbQdUpcBWaRoBSLifnWSko2pJiHf4yZJpAiu", - "quoteVault": "Bb7ahndSKwqQdxLLLinErvUcE7ZJr795rLaJdmZ4iXsx", - "withdrawQueue": "DG87bMpZFQ4XbzuykhKsdwh8QHAuzQ1yKnvPbSUgTfqF", - "lpVault": "7TPGos9vbXeBNRA542NWL6Tre1H7CRSGJ9zU2deK6fqr", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2kmbE9hq1krbqrZ6AHvJc8fceGV79DVrVpoWMJokLeWn", - "marketAuthority": "HGsAfTsngphZ6UAj9Lp3VZbG5uKEY1gJPD5uia5TcdoG", - "marketBaseVault": "7a3miXQzvXMgSdaPnuF4kASvUS5gcNbJJrBBhyF93gW7", - "marketQuoteVault": "88jRsw7AB687R2EJzv5Zb3ANWDF4gQJqt3xCwoiqvDbU", - "marketBids": "FK9jiZaM6KWBSHAYart69TSqx5FZcsXB5q6tY9fdXUwt", - "marketAsks": "CC7aXASRpeN585U5cHHJNYKbXi3vT355LgXG9D1CnudR", - "marketEventQueue": "93VZ7HsymrxziHNNrUQUpBRVkTbmcv4bTMKLjFw2VoJD" - }, - { - "id": "CYEQZRJd66sq31hNquT9ssa3y9Szqq2YqmKECSHnKqWw", - "baseMint": "8iSagwHZNj4Hx4CMeoZwLLMVbWt4mUT6qk42TxiHkRtn", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9zvVZysEcyvY9WGZk3NsSjUwRTaCrFw77dbQ5nsiL9uF", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8q32qhfMpg1DScQQWg7HwTGxAFo2gb8mD8fkPFyrieCm", - "targetOrders": "2JBFsvbZhMpw8PAs5LieKVNU9hEzyrw4PQUdSkNhoEmh", - "baseVault": "FhJ5RGweR5WTqepJH8tyyGtugX8QBzSS538m5R81L1WX", - "quoteVault": "3tY8WLe9Pzw4onDmSeKd4VXmWC7fRp4wGbwHbvuEF3GZ", - "withdrawQueue": "9cos9LwRoEVBSF7CfZcc4RaMXoaboocns8UkXMcis97v", - "lpVault": "BJCU53A8C6WDCSg3kn6FYTiqCT5deo9x49vwUK9om53J", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "67zJDzu9yCjHsQQE7aBXsvXH9TPL9MNbTr8X9WeqFQcC", - "marketAuthority": "6y1b1YakGavmVy82YDNDetwC1DJeD8km2a43RcK2fhGB", - "marketBaseVault": "47aA1WMFtsnkzFePJUYRFb4XWj6xp83FHgRRpc7Eyny7", - "marketQuoteVault": "A4Hg8Q44neXZR45rKHAFkqJpR4yttM66deTKYThJTKgh", - "marketBids": "HvQVBfHU2UY3BmaBXJBsz8zM7qbhh2bkSjhw839GJrzc", - "marketAsks": "BuJwt3AWcMd7xYp65Cyxz71uTAAzeKYbgTdiyuhvNacY", - "marketEventQueue": "5239qQdJytFCTqQ6z5C514a1CzGJgDqZz9z9z5HRPGoS" - }, - { - "id": "CYEr1pD8qVfzAFQibTRazY4fFBZumJU5txs4m1s6oJ8a", - "baseMint": "94jMUy411XNUw1CnkFr2514fq6KRc49W3kAmrjJiuZLx", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4oFCqtM7UjZFBVwkN9bocJgPGK4CABLcBy6oPiXfJiNy", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9cdWGKEycCNEYxVskmsh8VGfzx4V8hxfRnxjhrUbNsr4", - "targetOrders": "EqwKj64EjSdNFPFgnECrdrUTG6d2sxYZMyqztgpzkqb6", - "baseVault": "GJxseoJapQHe2zsXN2WuPriuRNqnMrR2nnfQafzNNfVB", - "quoteVault": "6Usx4nujuGHne7PFcjV16WwFGKs5MGcPfTvp4m611JrJ", - "withdrawQueue": "27RZKxzrQh1Djz8GxPWJ9gU7KAabPGZ7xe1FXuNLk5Kv", - "lpVault": "MKJiXuqvCcZ3c32oKsyzDzjGDvJu8rzT3AAhqwTet7E", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5nBgHudwWorsegYBxNsFBUFdYVmmZjUUwPJgQ2n3pFMH", - "marketAuthority": "EibPMLo1buS7yjtE6ELFwfT21NHwoAmRMG7JkggJWWSv", - "marketBaseVault": "BGzwTWdceniVSUwHWCLM3mSiYNZEYwydkj4tJomKkXEF", - "marketQuoteVault": "C6jZQLNXMF7tCsNAwsXp4xVWmAEPWyNL9XZN3MnbsTqa", - "marketBids": "3hgKDM1edVmiYCnVwGsDLyRNsUxnxuhQ6Tdb2vs8zyx2", - "marketAsks": "8wDskzfpNaqWRqkuJiyuS2XuYTHCQwkPbxneHitAfwsP", - "marketEventQueue": "867BpqjYrQJiXoibbRQJUYW8FDoGX6cVhrpFM18vgduR" - }, - { - "id": "CyrgnWfdQG27mGjGLPh6wQ7i8WiEAWbFahpoXZKfK182", - "baseMint": "HBB111SCo9jkCejsZfz8Ec8nH7T6THF8KEKSnvwT6XK6", - "quoteMint": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "lpMint": "5mNdSmZEiX9jGZFPVpp9nFFQHDKWF2sHZuoU3uuC9wPN", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9xX5LWvujwVssBMikZh4rMHpy2ZDWJNbm2gzeJhkxAKm", - "targetOrders": "7v4PfgPeHzP73mogSK4n5xre5XzVfm3fjhupGjrXe4dA", - "baseVault": "6yrHfxgSMYheUp6ZMxhKQMhkqPK31w8vkK5Wq38r4Hfr", - "quoteVault": "BtPXULYwtKvCtuojvZcSCC6YoyRNTaK89ryLAj4ywnoD", - "withdrawQueue": "5o1q8J7b8qWN2adMiPt17UimQaZ56tFpLQVa3UUfuwAp", - "lpVault": "7z3GDCBz7YuGBMSskEBH7VNakAjBrmZZi6zgh9VgX9JH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Hv5PaMRtoLoaQWof8ULw9KfaqDEFgh3N8nMjAybiNXEE", - "marketAuthority": "87d9q1BRvzUkamSzYNBE8SQ6fHCpEE4NWbfkTpG4Yqf", - "marketBaseVault": "2N3qE4dhQe1d2yCZdsriM2yTEmqjohRabdvq49uqDfRc", - "marketQuoteVault": "GiLxnkwc9xtzmHASoXq4YrEZuiQjD8xeR9K4AwFU8wZH", - "marketBids": "ELah2pPbwozitVejx5KRYMtFz1bEhTWvvdye7sbaS6Xg", - "marketAsks": "GDaAqnu6SwoahipnNXcduChSYApK8Pc9B6jrqc6ggN4M", - "marketEventQueue": "Cw4bDyXbr5g2AYTxZundNEfzALVgVA2DYYasHyKn9ZbU" - }, - { - "id": "CZ5E9MwhozrRKB1hmaikjzo1HCghLR1hTmYe7DrgnDY6", - "baseMint": "yvbrxE6zjrA8SxxSpL7oojDBB5QDmF5CVqJWea8JcQE", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3YsqMPRLnrQDpVWXSJGioWnDnA9nmexJ7ZGWTFfSiW7e", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "A4bB8P2JTMHPrrUKVfThrMisrfpkxH68Xx1D86NCH1hE", - "targetOrders": "GcvpSZcqV9YGc8ePNnK3tkYdT2VtcexfoHvEYbuRE6sw", - "baseVault": "TmpkX8FtNpgRefL7ws3UKwztdK4o4YFrLJQR7ZE6y98", - "quoteVault": "ESPAQRo232MBWzLkY9zZUzSbwVh4KiXoKZC8BZWAjrjW", - "withdrawQueue": "3ib1kpTqhDNF4uYwY48uZ1f9gUziC2NGXuznpmaoNU7g", - "lpVault": "4upLFRDhxrwh6T56D4uYjDriBW79D5u2XpcjYtK6Yeee", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7ewFm6sVHtjpUvCVc1MNtwLuKtidDZLYvF7eq4c2xWha", - "marketAuthority": "5SgX1g6Kekn5XAuyhnJQWXMd96JbwXecXDcZ7ScTuLqY", - "marketBaseVault": "DF8bKEMJc166MmxWBYdJUje8rjBhk6ccpZjSAdJSsEET", - "marketQuoteVault": "2tutqf3TQ4hoDUX5f3PioiNru93ZHUXW2PcvGa2wSKeP", - "marketBids": "CyEWuqA6oPoy7WwwDqqq7dxxdDMjvMWrmU4YCvqufVko", - "marketAsks": "565osnjNJxf2qNmfCSekFc9pJn4uZMkk9ddFyg3k79nS", - "marketEventQueue": "F7uGZ97iyZG2p5g44nSR7iKqQEznhPJCV9CdsJVukAsR" - }, - { - "id": "CzHTkDVXF9hLi6zZutAJWRcLxYnfbEqFUceP3pzmBYfr", - "baseMint": "Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "FeR6niSzr5QkrhMjTomss51gxSnkUNfrgX1qqN1Vi1qV", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5W4asi5B8kmUdggjyZjZwCJL56UUTkTVcdmWanJiFdmJ", - "targetOrders": "3DW1DPY9dEi2ZGfH6t7N6Y6eMDUDnSGxLQGc8i4RA1u4", - "baseVault": "4rW23y5ufkwCJ97MThFmxYmGtdWmtpmg9FsbmVAx6tie", - "quoteVault": "BG3cYgufSTzURBE9DGbwwHQB8XutsQoVb9sH4cYfhaCa", - "withdrawQueue": "GctivxD1kYZnZw6Bwtw4msrMq145x8ecx3oF6pKrsoi9", - "lpVault": "FpEPE2TAUNWbNsLLKYD26JcHHXroaiYaWTqrmpKJ1Nnb", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5SVEELhhXzQcCv82tjqoXwmuaPUMkLEKwPQAX5FuDJGG", - "marketAuthority": "CELPxXfXADWWkJzcfDEUzZVuvstC16S7SkUqUh2115rG", - "marketBaseVault": "5DBXTbkEaLGgRAk9ymW9tS9vt3YWrXbwVucz12fWvjtS", - "marketQuoteVault": "ArWJ6jD6nsDgmXAZ5hCPRPS3iHBtYfwzHsHAUydUxqZS", - "marketBids": "7rPmrUz1TCyfYjiiv6cXH2v5SKcKumDjm4UqWaieCiuf", - "marketAsks": "6gEiuEBdMKBS7Hf9R8DF67UPcTs24ryCcHbgKME9HjgE", - "marketEventQueue": "2qeWSwJJ98qnGXCzswpocNkM2mjey1tZNduLmW9HVzxy" - }, - { - "id": "D1s28G7n2ahynP25953B3QxCZDCd4vd6etcBF2dUKPTh", - "baseMint": "NovNrxPNjmLVFscH5rjMbec7C4BdAHms9WK21xjsP3p", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "12dDdLrhsGrWA7UoFnDdVLCGScMKmgJ4KeLzN9GhWeEA", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GNUztHh3pCGQcvv36PiXkLDz3RndoaapriwZDC8FBjPR", - "targetOrders": "5KH8mZ1WBfzgbUR5Z5ri9CW9Cbzr32kt6eZJ8rWtiEpy", - "baseVault": "CzARwENk8wqF8K98zme5t4zbyGeAu3WJvDLx9vtCXxcS", - "quoteVault": "tT5ewEDccbV3ekD7VeVpSR1uCCnFidv1uEqXzQKbLPb", - "withdrawQueue": "2ajLuHoTykphsGv5xTuTAPRhsJ4wbqczKRRtguyfo4HY", - "lpVault": "DCPhofJKqSmG7d57BVcZYXwJYJKA5MUKtEqpFVmzru5T", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "C7fbA7uo4yUsNq9KwFBB6LUpipMUBJzWZXttG5qraSpH", - "marketAuthority": "2xReN9TCgMtDqGxouiLjdy691q2wTxprRtiV4ksmTJdX", - "marketBaseVault": "3NAZCd4EYbXU4t6YnJEZyvDQ7xDeLeUgudoY3LojbCdm", - "marketQuoteVault": "3zeTn9UcsW6sB7HTMTXL8HP1ZUdnrtMitNqmatF1oF9d", - "marketBids": "B1eNm4uxcw2MZdiPY7TgDUcMi7JEEqHZeL3BmPEQqbNM", - "marketAsks": "EcbdwgZEdvUw7y7kssWM1c63wS5beimHihZT9XEB7hAx", - "marketEventQueue": "3FqcRbQf5upbCNZFdBENdNa4hvjULnujFFFWJQYifTc6" - }, - { - "id": "D4bpdxkpw9CM5kv49MtRmVUT2vPTdKUsEtw8mBrJv1JE", - "baseMint": "74YedyBSKbjYzWMhwuBQz3mwsN6vuSSdAfzX9WLZQUtq", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Ej3okum8XhNvgPZSt2NeZU9aaxu4ZEgB7pDBjpKb8hwd", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HWHje65HEzWsU79J1mgbWrHPht6PRrPL76iFvj7mossL", - "targetOrders": "Dz27DrJgosiy38YpVNW5yrgm5aGc8zzcvWVuciAF5wJX", - "baseVault": "64Qo3azcKqtXwuFAvGHaBaruahD4GTbq8HAXB8mLcPrg", - "quoteVault": "7cRw2uic5cMoBeBJCYcCeYj9u7XQ4DvwHbE5ZQYhAzgF", - "withdrawQueue": "6sU9oXxeg6S9YyJsZ2fksqDMe9VFzPSy5N6TFD31biH8", - "lpVault": "HQBjdpVGqam1Sc72FQev54VJyagXSNbhDaSt2gGf8hw2", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "F1EWyyPhRsDMhYBLQwhZib2MCKqd9RYSd9PKnGjRUtPp", - "marketAuthority": "CW3GgrF49SUBzD2JPYGjbbSXvprZJQ6tKxn5aZZfnCJT", - "marketBaseVault": "EMfiXmRgqjgtUwwcn29mWz5jid3kAo67sAKfrtKCNvhi", - "marketQuoteVault": "CP4wXPHAayeURJWxBHJFUtEaZb5LLN43o6u2Ghns5gAE", - "marketBids": "CJ7ZW9JBPcBiwgrVtR9ETbZ8qiKwfAYHHgEz47nxirMk", - "marketAsks": "8Z6kACWFBnPtWzzrmi71sMBxRRvmQFQvMa3qE9wfqJyk", - "marketEventQueue": "2eAiSSABCiwJdkPtXBrkzR9q3mWaemyivk62ibgdKpQb" - }, - { - "id": "D5N6L8VwiETD4uXsTA9BPE4WXvskVxsH8xmLJZMcijnF", - "baseMint": "93iJG6TY2bXb8zUe6gscx3fwvUCZPHVMCrVRg6uFz6ZU", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AfsWwjECWYoqeoe3BbXUQqPcVkTEzBWEKdYTLxqbGWu8", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AmVSc93TLF1zoNFgd6fsdqTK3ripzSpowZ4ReveqUKSM", - "targetOrders": "3Ar6YXcPhd9UiAevWRCHLRsWMa6jVYNuE3NnveMZ6zTQ", - "baseVault": "5ihCSBsXarVpd6SfHk9a9bZUCTr9naUbBBmW7K84LsoR", - "quoteVault": "ArGDm9nmM7zj1hzBRELnMxDUw1RJNRuiU1ZFSz6vQoHS", - "withdrawQueue": "HgQgaM2YodQsN7dzu4d85x6N3cFGS5PJcgrFNAvrGbbt", - "lpVault": "13WUHCJcQ13vigzqecccAUfmMeXRVtyfFw27ytTcK9yM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FE3B77xzKKNxPcxKWF3tZc2FyPvBcLyHEjsmjjKC2Zib", - "marketAuthority": "GqoVSNg9vnA1Fq4SLGuob8qGcmjqZKGm2uKtCEziUXw", - "marketBaseVault": "ZThuM1VzUgm9ZUJm9wgdGRsRu9ksQzCVSUzdGfubbju", - "marketQuoteVault": "7XZZqMhFoUcQCttUnbC996ds8JUtCxCbHCovCVfPCJL7", - "marketBids": "B7CfTodpsK88kYpg2zdhYSjkYHgR8jZVRsf531hE7aji", - "marketAsks": "9s48w6T7WDkhd1HpdXR7i6YsWUQjs2nDfSbtbNmNNugi", - "marketEventQueue": "DYWumvdsPpUwuKo9XV1E2b9RUbaRKnvyfHTkovPM6Wub" - }, - { - "id": "D5uSJSXvi94xsmVyHPcbRGEpf8uny9DauPrQkN4dZ7Ko", - "baseMint": "88YqDBWxYhhwPbExF966EdaCYBKP51xVm1oGBcbWzcf2", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "32ZLNK9pAf8oHWCMBbeMbdGEtBpipsJ7wvwprettLydq", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CV8yV6ZzgFF7PYZgKxaMfgS1G4ThZykLYg9pdbDQanip", - "targetOrders": "Gcz9xFChQHHU2g2wVocH8EZ44VTpwvTR7Wr6KRsothTw", - "baseVault": "7Ja1f33Ad72ufwZFMf51fdVHQ6EXb5xHDxcVLaA8iwRw", - "quoteVault": "HeMpThYKcwCjLTix7rZ2vARFGb2eRdztf6KhWZ1LZNuz", - "withdrawQueue": "86LmQdsTZ2jBodhxP1BG8JU4MANQgBjCiWiPPNbgH2Ry", - "lpVault": "HEXvTXsZ3ZdbFF6oA3uq3G3sX3hSriHhNdSzs7EY6Qy4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2tzuvkr2GEfGw6JygTTg7jWk6Qk19qFnnW6WrqSTxxFJ", - "marketAuthority": "5GpzGFRe7tM2Rz57ZMQLBHg51miESxaewMK7UpKtxzCg", - "marketBaseVault": "7JS6hkPtGPhFLp2uyMotAGPduJJETrEGMAg4Eq3RC52", - "marketQuoteVault": "3SF2Ff19cnTBaMQx4LzzaknWXy8GLUyyzL5WQpdhff7w", - "marketBids": "7LbxXDVKsTiiG2ZwCF3iKkz8wjf9SiAdLx2k2rwaY93e", - "marketAsks": "5zRsV77eDnZc9GujiMGhZacuTomBRvZAb3Vrm7zQgexg", - "marketEventQueue": "7st6JP66yDAqAYZEmWwWyrm1rphu2Ni4EdX8GgMvDfNd" - }, - { - "id": "D5XavoU2QGMxeKMYyeS4pzcVBad8XgfVHwhs3auiGMx", - "baseMint": "3H3AeG7BRmCmCJuQ21Am24SYcgFBkgpX6miSSDM7YmW7", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "89k46LQP1P9wuiUdxi5u9FumGutCsuR3NNJWLjyCVGpw", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "B4JcVgzJhEk47LBkzsWYiGHEkyANWHBXJaxMKWey8H5g", - "targetOrders": "9cLUgQzmNcnK2au8e1VQ839LBPHsVLwe3wUDDHNjiDfX", - "baseVault": "9dkVrC3EdKJ5W8NUPL85zQKsAoHQg5xM3YAjudZdbcrs", - "quoteVault": "77t2a1wyEK9USApgRWCbJsT3mgdSNMvWSHvyjrRqsVsb", - "withdrawQueue": "9FmUke1yaNYZoAf4iPig9LF8NwobbZ1A4FW6MsYgF1MW", - "lpVault": "9V7fWndq1VxqJtv3ChhcuWyvoNAPHW2PSpAmz3tb7Lo4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4Mv2Bc8o32i6pPdWQNuU7Ciw9FSqqtd4pDi52PmMgZJ4", - "marketAuthority": "131UL5zC3SyihoLHSruqZUUx7uqCWyLiNQG6CyRBG4ww", - "marketBaseVault": "215U9VrhVNQ7Dpgvo5psaYHD6NiALdxujGb6rVVCXMCp", - "marketQuoteVault": "BhUW257n4xUT9MLLp5EQexittx3ADtBs78tHn2MhfWw8", - "marketBids": "5bE1xqc7ca1AUv8ZqAKApp2ojEuNCz7SjSLioymTmQ83", - "marketAsks": "779rgkuuNy8uWoqVRc4JsxLUAT2ahtyj8FLGqe5LusDk", - "marketEventQueue": "31U6RoBkrQ5m73T29P1CESaomNmm96cvd32gkr1VbZBg" - }, - { - "id": "D6DCG1g5nhqCzdjxDxzvydE3qkgNwoJQGCBrbrzgfoHn", - "baseMint": "8PBKt389RtKAJALsmMSdjBCUe7qaXAJAn94mGSB6nnKR", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "G1kF7xigvcYSGZuYYunKsVFjqV94ZgNCoS5tnfFs53mw", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "QeVQm4YvB5BiVgcZ1GQt7EeF1Q3GbtQADgmfZignF5e", - "targetOrders": "12UK4mEAAF9hwfQTqXr15k2WkYnBCqz4Kc1GSgvN54vW", - "baseVault": "5eMgjbeaeFiNCc65z7sgGdfoQeY8ziUpuCy8W78AW1H8", - "quoteVault": "2H42G2ZGyxpzvpANgUb5i58skhJHKdjxwpe4asNUa416", - "withdrawQueue": "9gjinuUiRqNSHmnQ8gpVEAt7JxhLHZbUdcxJW5TzkKZ2", - "lpVault": "FN5khXCumjFJeNEb8Gha5kFU1oabMojGsbNFdAS3Czn6", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "C6mD2NzmoSRw83VTPKJENCAdoEzkCXwgMg8h3mS5LDvB", - "marketAuthority": "6S3THpPydm6jpJ8iPRbQj1YHcKrxCBfYxCCRHG8nc8FR", - "marketBaseVault": "6WGPXJ9cLazwuPZ4RLSDv3VebSbcEJtknYzUaFpkj4XS", - "marketQuoteVault": "7K3a8xZzW4ru2mUE7fCUQhCQ4mBpTP5Hecc6FMwNVynu", - "marketBids": "BtB4ZRutMVnghrVkHRTpuesBu1fM7waGEco7reSfCfwF", - "marketAsks": "BuTNwbLY5HuLhJ1rNMAuY5yYRcDTiB3s3c368HxDZAQq", - "marketEventQueue": "DjmnvXVhzoSkN65rUoVeC36dbEeeYmoY5PY1CrqNDFu7" - }, - { - "id": "D6Hg2My2V2SDb2X4CThVT8X1HjhngBMV6zKjRnFP7o9x", - "baseMint": "F5f9hLQ6FNHwuU3dS8CUCRy9r2deJXYCinDL6RAxsPeX", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FsJ3wESUukNnnM4EkGB8XtuG8b1Vb6jEfW1R3GehgQ4E", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5MwBioMzxfHcoaxfq6udXiZg5KHk7Hi445v5uLAjArrX", - "targetOrders": "4NJUyH2LJNK1vmjV7qt6tLtxmEk44HRZbTSB1ixiDQXJ", - "baseVault": "4SJsTDZDdbnAob9vrxNEU4Mjmx9ejLmgBi7zMawdegH4", - "quoteVault": "3WSVMxQbcfxy1M62sL9dBk6THeKv4UiD42Gfkz73YzpP", - "withdrawQueue": "HuivmbuDCeUs6fprnQw5cn57hVpxJpsFi95cKdSo2DgR", - "lpVault": "FxAkuUx7qbTWJ3yuTj9pPAZLbxpPwk2kgxRWS4BmEV1u", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8g8XBbTxhFqtLtWd6vfEWKtHufb5SnBhUAknjaw3x6GW", - "marketAuthority": "ECFL4grXCAxzEXqFJhTFdKG61PeQxDBp4tq7DsWEiEcf", - "marketBaseVault": "79oGjDMfS1yoUNNtSVnvr4T6jNS6xJKVL8En5rzRvT3B", - "marketQuoteVault": "3RtFYYeLZkuWthrM32e3VLkmd7DUAX1QSCWLghFvVWyt", - "marketBids": "37Gr5pRBBh8tZ5i4MPAFRjMRo59HdH67ctMMQ1NDQkHF", - "marketAsks": "3pgJxcwbztkSu7G2XB4HtV6RvxnkGDAGJjsFcec3UwE5", - "marketEventQueue": "27miZawxGV3MzfSpD9ouayCNL7QHQrefUtCj7pqBK3a1" - }, - { - "id": "D7ghZmwKUAqXfFFSvU7YZ5MZnCZmc6S519W5sa9E5QDK", - "baseMint": "CMxFXak2h8fsqVHcnSvxMUFLSzabX28dvXzDMeMFpPSq", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9ionqJP2PjMvAuG1e7pAK3gYTzcjKR5s7XGM6bJkFNjA", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "43BZtSfQqWzowj1Db4kxFRfrYJNyfAztdRVHdkN943Zr", - "targetOrders": "83YFrqKyWMSf3AmhczbgG4C75KtiV7HajExwqXtV3kd4", - "baseVault": "4rRYtf8H17JnLgwNr4nURMWcRrUg6kzueSkrQ65u4RzC", - "quoteVault": "AvdLP9Se39ajmUvQLzyHcpAFEXfQnW2NzZS23YPextzB", - "withdrawQueue": "5dtxZ4HYxzicFyNcDbdRXu5zWi4uQWmxwpqh2czMbFXg", - "lpVault": "8dYpqZtQtWScY4Qd2qYyXrWMnwfGSM6nYWsHeQnXMDrN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4jizvyYXB14CFyaSA4c7L5r4CUCa1njPnoJ1rNxAk3qu", - "marketAuthority": "6B1YxBp5zB1w9HttxZGSPJT3aqFFXdmNm25MZ4zPLv5a", - "marketBaseVault": "3DRZPp9ZcTwDASkvFGXfebkhHPzRzb3vL6vBDSnrXW9h", - "marketQuoteVault": "2itLahNEM2VoMPN3AbVpzNXEVGa93VSFEJj9Akdp6Zwu", - "marketBids": "F7HhUk37iP7GyodvGnuYhzCrRqqdb5MULGTvTpDR2dT8", - "marketAsks": "veMJ5WUJLvYiLrLhUS2XY4DYFNTqcWHUTjHRqtZjLUf", - "marketEventQueue": "65CUBwRSqnh9HhHe4voCPh9fMh5UM1HYpHAou5CfoyYL" - }, - { - "id": "D7JDqAHDguipobhisVZhkxP4fPb9adjzetSoQCGf8kjF", - "baseMint": "7GNyprqrpvJHNwzWSj4KVkqw9cKyV5aR3ehM2HeE5pw", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GMLxmamEWcuZxu5QHfVfZGfYmPTXAFzKoPycLd9TmgPy", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7bujV6ytS8bXCptKkWEet2YYgvBY8kyxTi6m69hN9MSX", - "targetOrders": "gqpJSduoTWsW4Lx52JsAs83oS8NV1XPgjqgcgLS8FJ4", - "baseVault": "9TxXjLAn4B7HQLCXdSRPdscizyVyeiXbsx1i1t85TnG9", - "quoteVault": "CdXDg6GSF2hnSj93nCeSUt4AdpLWt9rTyi4wB5rbJCKy", - "withdrawQueue": "J5GwUfuDK7KdYRDXfxtMtPT7EsSDYK3HUA1jGfT48VQs", - "lpVault": "7hJ8hdz81VS4MBeTZjFkjq7JXwBoyYsZRgUBStNmXRRK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9zaBhbv9MJjwmy6XcRTk6WqipFNftUkYoB3MpTJGu58C", - "marketAuthority": "2tNB1dhyU9ntsVv4R1mqRPoTT4yzrCSojh4x5fron7ub", - "marketBaseVault": "6XWPJMURm85Lzs5pAvfkVLyXSCWxt6gyX937RqgnVQUB", - "marketQuoteVault": "5MX48bVxqXcSnRvXJfsMNUZ34bubxhpSdoLWm7oYgWNU", - "marketBids": "GsJsbE63uDaiypwoTE8jMvT3gXimwC5CNPLPTjcE4NiE", - "marketAsks": "5U39NSRGaqmESajg79kCaL5ZHCpH9sS9HF88qf9dTZUc", - "marketEventQueue": "5Y9TWBpBCt54qqMzJoG6k1mTeMcxHNAh726nwbgZXSWf" - }, - { - "id": "D855NQKXcuozcakjwxLaTvmmqcZmDAF1vH3UVUuBRiGA", - "baseMint": "2YCQcQgy9nNhgukjAur1jCvMXgSTQ5FVDc3ae3BcspXS", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9rHSKgVayFMXjgNKYKwdVXJwxBHXbpW8nut1fTUs1cj8", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2BFxxU2EDxQnUrbxbXQgmP7h3RGRxUHNEEaWT7rXFgeM", - "targetOrders": "Fo6t8DZj9ywbYZ2brcd8C1BSVszqDRRJAUTdamtE9mTH", - "baseVault": "8zURtrtjsoqRAgGS14SYHGJ7mUx9sQFzCRtP11LhPwUr", - "quoteVault": "DGkV887peH5FZTUJJdvMwt7BcYaKY5GHMsoiCGVxK19E", - "withdrawQueue": "74rChVqhcyaYF5ZPrhpFpPbMAMVwXX1MWAc4tRTwPAuZ", - "lpVault": "7P18UWf5q1D2mKyi5dLrm69Y9t5X3f543WLiaypXYgMm", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GowU5bsuEKoU624PEyaR5JRMaabup8HwdGBKBPmM4eeh", - "marketAuthority": "39dsD6VrY2cC5EWcjaLXKHtSVd7rqngeAheMVhuXZNXu", - "marketBaseVault": "APtdKFQuV3qQu9hSFWqNZpYk91n2Qje5QLRvJugkSbS9", - "marketQuoteVault": "EQj1yzRNdESSpFsF9sRACDoFgCh217aMvmCy5jHdXi3c", - "marketBids": "Gh9SMRHfiT7LY4fbsyX8dnZkQPQZZpDgq8P1fkDWx14x", - "marketAsks": "8GfJQHebeydvc4Tam3gyxtxPf3uzhNs86dW5578fFpLE", - "marketEventQueue": "89ejTPjeDwKVGAPYcpE7yJMpjXjqN8NW9YHxDiV4Ptqw" - }, - { - "id": "Daf98haeG4bbupFhnAK7TQ3aK27jr4zgUaHtGtsPSpQx", - "baseMint": "8StwRjjYtPQMXYDSEM4amjNfYaxXjUKfHBLUxWBgyypX", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BAWHBdWCtm2SASWKisP6bm4ScJ5rGUsbY87grkFJbdVj", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Eya8SNBWhYYTg5fgXHNmtoH4HzsaTrURW4ZEudp7cXRr", - "targetOrders": "9NvX9cyJc1gDpgTv6dJQM82bqCEWuaWXtqnsUsoYST7f", - "baseVault": "2AxpogwnnVtugkLGB3dpG4pYvvarRMqB5YrS3Q5A2mh7", - "quoteVault": "9LJJBvBxCGvYMVR1mGXddoeTeSjhx6u1xTVFpr5aC3v3", - "withdrawQueue": "Enqi7S8H1ETbktfAk7MPV2c7dZEJekcnZVLhB6RMhr45", - "lpVault": "FUzzZpNneCPUczJdmqxiZn6LjNfFjbv4ui5hnwWjFcXa", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "31QR7KWfYF4unseMWJZxDWMiowGtvXw28VuxfsxGn3LB", - "marketAuthority": "AjTwxxLnaZ6gSxmxgfY6pXfE3jrRbgaJNMTDQaCx8xQr", - "marketBaseVault": "E3G5JNMJDn43Pkj2Z1PzMAB11BFT8Wce6WmJSKaBtECC", - "marketQuoteVault": "5ant6MGs6jKWLPxkyfMfUyF73Ttu5JMeHYfXutCY34bX", - "marketBids": "8FYruhmsymFrvk2AvnxPPfvUH3nugEg1LncgGaU2zdnH", - "marketAsks": "EyzGnBS7khhLt75VfQELB77RcNVTfHcEQ8ndAfjk6WhH", - "marketEventQueue": "xGKYnbqiYQzWrvvaR3kWJXLURMH49Dv7rZKkV6nwRKe" - }, - { - "id": "DAGkHuEhHYTPtyE4bvgqdwzDW1XUDi7bMy3yYwVDqwnR", - "baseMint": "4odRRaeqc9uKBryGFPFcv5LbBxTX3jGmhC9buoRFAwry", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AotyPG23VtBZJvPAHNWeurchxWRPNddHjQhABVe8TMxW", - "baseDecimals": 3, - "quoteDecimals": 6, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CDmTcrB73fEdn1Q3eiCo4AkRJePqLMc1CanjyaiUk5Yu", - "targetOrders": "4DHjGa9N6EKgskU8GtTie736SiwpSerKeqanW2KZhJBt", - "baseVault": "FHftYNS31Ee7rL1XkkAMQ5zHQyFmvPWUV9ZSjGxWMYgC", - "quoteVault": "BjRkPU91wbBgQLAiQwJfW6Sk9tjetD5GQJKrahCirPMJ", - "withdrawQueue": "9FEAzpoi9uNfedMsnUpZMWauwiSRgxETLnhiAUZ6KWVM", - "lpVault": "8U1d4bWKVcJVhP5h2xSBtXTo2bhCysMBc3tn1PYBSEdn", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Fvk2L2BxNi6X1PmNsdBm7eqGmD5xNY482YM92GzffDio", - "marketAuthority": "3EE9S1m1AyzWuo3tkebogXMb6bSnS3pgqXpqb3De1jst", - "marketBaseVault": "BC2pfGhTYCdB8NVjfLjE9y2MVZcYGK8xSUW5o3T7bxbc", - "marketQuoteVault": "22HURW4sgS7BojnCtC8so3QMPtUd477EJspxyfdHUvza", - "marketBids": "92mobTp2EfsjiPyiGF1SkzQ37owewjbVBRRwkGaBpy2W", - "marketAsks": "EHeCA7HSXVuGjUCRVdqKppoUn8amLrwxsmBJNWtrFBAF", - "marketEventQueue": "BjrqfTYFAcHMZPPwnM8xPRZtnPgwhAKv4NQ6RFXVdVws" - }, - { - "id": "DaMv5dPdajqvvWertZ7AHigvQkf864FCRH5e8JtUZERj", - "baseMint": "Exz2u9EhSXzGDef4v8bfXVjcUbsFm4kMKoXxn58fDUSa", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "5ZFyMrDLmCkBo4MtXHh12PBNGhTgzZHm9eAoSPAXrBDM", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Awd9V1Bj2GbN6XDvRx9faeqvbJM5eyCTD9QYAD4Psocp", - "targetOrders": "HC9CYqWrwyyZYkKDjHw8cxpii91n4XpBxiJqACe67GWT", - "baseVault": "6nxNXJuTLoncMM8RM5miNyBm3SvzchNx24BRnsqiVhUW", - "quoteVault": "AsABH9JwNJHVnbATfrKQh5GyzwBD4SXP1MrU2BNvr7sA", - "withdrawQueue": "G8LU6dKxkQpWoBNESwdjLywTn8YrY8BsV8QFAVTJqZBJ", - "lpVault": "3Ndm5v4MFEgJrNxx5iLzpTXXNaX7WPNbWCm8pp7FvUcu", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "E9NwJCeToBJLELCafTsGHk8oMEtQaUWdh7wSxBprUUH5", - "marketAuthority": "HNYpNjbQFJ44ALaewAsFGHGjjPoMWreWuUwT1bieFKRh", - "marketBaseVault": "7o8Tg5trf67AZvEAhj82oRWK9k2sAz6MGmZHwHKKD4Ki", - "marketQuoteVault": "AVb6ueMjBxabMZJfTXu17Ya4gpxZXPCY4PEMfBoTzFUi", - "marketBids": "4Vin7SS2GLyK4ZD7gKN4aQQMj6b6g8L76csfFUd1FVDj", - "marketAsks": "E3epFYSiMmCEHyZ28gaDt3nvmLiVQhYrggU4Y3qjyXWc", - "marketEventQueue": "GzXFA7c7dhB1GgTJVARHLBpzq6VSjTNYfc6pUqK9wR2j" - }, - { - "id": "Db4zLg5qSjT4wWhsRhbjZ8yvkt8jawpJoEZYFCSjAyYa", - "baseMint": "sodaNXUbtjMvHe9c5Uw7o7VAcVpXPHAvtaRaiPVJQuE", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HKLBSZbkfeB8LoaLLrK7CDepPHLWQEoj1jbunT1T2wYg", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4bUmzxSysDjuGjLiEqFzAdUBRYmoYRAsKBJbJrTmCf3o", - "targetOrders": "2ASG5F4mSj8xkqdVW2vKmjLhqrZZE3qsENTzmCr1yKfi", - "baseVault": "2ctQCdFKGwLX1WHEnERpziAtCQY8a7B2mn2PbfhkoAPb", - "quoteVault": "6wFBEMo3ENUWn4KGF8kdrz79MH2Qoq4X3wdxSr42oE4Y", - "withdrawQueue": "HwGN7QYjhHeEtspn6b6HTpYkrT5unp4gT4URzkU9vpF8", - "lpVault": "BhMvpsWcjB8FjRBjdXPo2TTsQhnXTGftXCipC4uwCPYG", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6KFs2wUzME8Z3AeWL4HfKkXbtik5zVvebdg5qCxqt4hB", - "marketAuthority": "EQ4Pb2YhBASioKphzoSUXoFvjBCQnCD14yd5FYwjsXdj", - "marketBaseVault": "7cchcXKrrzLoCadjSPGjdsaJsKbuEWejteVxMdRP8BzG", - "marketQuoteVault": "CKqoVqmDdEs5swSf1NVvbNSa2S2S49Yb4uZEKhGR3tyN", - "marketBids": "A6RSnESirAzjxmdEwQFUjxWfYZxbMBUPp1ZzApHN46rU", - "marketAsks": "3DrsgbjkdbYRVeULxAvZTapC4dBG7mYwaK6rQCcVte4j", - "marketEventQueue": "inMf9Jv6cMFoB3FyhZQC8NYzKFTWXthZUSU6rFy15KR" - }, - { - "id": "DbNU9ckfcViTgY6KXXEFjbLvatAMMrXKvdff9dMNb2RB", - "baseMint": "GfJ3Vq2eSTYf1hJP6kKLE9RT6u7jF9gNszJhZwo5VPZp", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "4b36U4ntDpqzcRJ69oakAoPvCGFMBozdkL4bGRVbEtyN", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6Pr5B24WCXX1dcZoaXbjxUxyWnivBEF6jCYxP7DrUFhk", - "targetOrders": "2GKEENMujkt8XRPTs3yEimyGucRMK7mjhErLduHcaTyk", - "baseVault": "6FCByonc6aA3segH8qdaZpadat9YqYXEhGq3M3PJMaRv", - "quoteVault": "7RJADYmqPphD4FMPM7XEQLihfTTi3nMcantntGK5bx81", - "withdrawQueue": "6g8QkHaFUbxr1bo4UFeaMq9gebeJhNWrKyaicN7bkRPD", - "lpVault": "8VDXL8h8zYndFzgNqyLh332HdW2L1sjrYT2L19Xfp5fJ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6E1AMtmUZaa4GADeWXshvXC5miVPDJ9SmBoGYxWigPDW", - "marketAuthority": "54YZMFZ1xo7KP9ejcKeiA9CsjdRsKXhH5Zu2qynAzKaw", - "marketBaseVault": "5qcdsVGRe5MFYxsuSdZ1PsGf6qo3Gv9TFKBWBYDrGTdE", - "marketQuoteVault": "EWVBjdRfNgQ8v2ZyV3r7LF6V14SRp4cGJPXWdfUF7LE", - "marketBids": "Drp95HA3vP9efRxH15GXgUHXQe1nSYamk4PW2Kjm7nTZ", - "marketAsks": "D1qAJMjQg394ZZnNaTbHhnHukDqpB5sFw414cq3DD4JD", - "marketEventQueue": "2EDoNmMnbZCCHuFRtoEgMVeoGvfgaLv4YWDVfohLkNAg" - }, - { - "id": "DbVxkavxwgUDpyniGmRdRJdEa2kczYPuqgcb9FXP4vd4", - "baseMint": "9F9fNTT6qwjsu4X4yWYKZpsbw5qT7o6yR2i57JF2jagy", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "HJqY5tftzfCyNkBft9DromCYWSdDmYbUS3LHYJGaxrtu", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5drW5ZM1yKmHTBZGtzPMue3oxjbvmeDkX1eaTnCQ13D", - "targetOrders": "8pGFci4rPSJJqGjgyjSWBn2LTPFYGrWsFKpzA3oiaE1u", - "baseVault": "8E1W1seswMLNMKaLhbz9obcv9mdz63KuPyHTmJ53ojfU", - "quoteVault": "5mt2ded9pY3p6Zq2cRf8GadKkhmvxhCp4QtYZ551WHmt", - "withdrawQueue": "3JXD9UN9uCsLmK6M8FKpzNeFQFrr988jMPk4s42dDKYk", - "lpVault": "9BM2MaY6Q8UsasJ2gTHr91ATTBACjLJmEzY71chnuEv4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "J2XSt77XWim5HwtUM8RUwQvmRXNZsbMKpp5GTKpHafvf", - "marketAuthority": "CR2QYdRg9w22TCcTckvYZTyKgjEQvdo8ZB7J8FqyLMTz", - "marketBaseVault": "92fVuRxVLsu6NhEEo5WUB21hFdavArsRAFTbrPgU4fSS", - "marketQuoteVault": "DmB2qmpTt5UVJpX6TuPR1Ca32gc4jjRKLUUGWGtws5Ww", - "marketBids": "6DHAyFGxncqmZd8kU7tUQbYUc23Pv2e2HxTYupK6JpjA", - "marketAsks": "GmAznGJuZGPXJJG17e6XNAcjtf71UBZaffnj43ibSj1q", - "marketEventQueue": "BmgrQ2LeBPLBgCJTYpQ1Ek9EAFTZBVNJk2qxAjUunJoi" - }, - { - "id": "DCom1Au93WGNVcTgUoFuZdYCFQ5VeGd8a58kcmMQyqrG", - "baseMint": "HDLRMKW1FDz2q5Zg778CZx26UgrtnqpUDkNNJHhmVUFr", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "CbzjxLyFowVhG43Lhh53qB77kADdz4xyVRW6Kxym6Z5b", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CaTFWCJuch3fgF7FGBSRz8fpEHhVm3A5TtwmABg9qaC7", - "targetOrders": "3W6tiNNbxA1dDcDtC8dUYjqFXQFzfKDLVPK8AkgnjWRh", - "baseVault": "G1Xo2GjaKZEqhBcT88pD83mzWFgFX983BFmEJ2UiCQdi", - "quoteVault": "BWnz2BvKFZK7YPJWBnJXPMziV7FSwkWzS5d3chKhX8uq", - "withdrawQueue": "C5gW1t6iPHqQfayeXwZhc9hURZU2sXnvazgUk2zYUU3o", - "lpVault": "DzeV7hydFGGKyx3G3eNkofsD8amByRfC1wQym8X8Pyco", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8aEV8E4ZH7CU24N7tULbw1NFNEgW1EsopEv4dD2Bxr9C", - "marketAuthority": "H8YAvXW2Qh76HXreaxwmQHufrWwVZmc9GXfNgaNhfnip", - "marketBaseVault": "4oD3cSBP4Jf9YmTpNrgu15mgrzWi2qznUuQ8SYVQeeSZ", - "marketQuoteVault": "2rXtBgaEZwoC7CDFa7spBYnfx9vw7iLL5S8bC9xPidYd", - "marketBids": "kEMedpZv3gYqa8MStuFDJXMqPBkJQKZ6LRDunw3Bh9W", - "marketAsks": "176ZifGMNEy3YQRWK15ciE2rJy4eRkTxJp3Jwu9rCzd", - "marketEventQueue": "Gu3zKpZUyFmBgWgBpRvx62qdLZFNVA6p2vBhNBNYQC63" - }, - { - "id": "Dcrs2G8BuTr9VocEVuYxLkp9BY3Kya7Q8v9m1oXbE2hE", - "baseMint": "8XUTstViEpLfhxaA88A6oWKraHm8V444bnSq6hm79vYh", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "EPPTvLp4Q6CsECM9Nt8LLkdu9sg9Mw3BK9ppBktSwUTn", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7JBoVxfwFAzFXu5CaH4XXboz4L4LEXYETNW2xpQduieK", - "targetOrders": "6m4JzXYnVFtP1DGpSCMj8EbJARUaw7Hf2GKTbVVt9wno", - "baseVault": "9KReqzB2MbQeiyxZmw7EPaNQ39PpXaNx4usWbCXnbELL", - "quoteVault": "nt6VL2UBbzWQfRa5ocQZBf1Pg2i9mejBnYn7bcRG6k4", - "withdrawQueue": "2kYFvTM4NwTHS53sxzckeX2bwdb9JeQAt9pb527g5Tne", - "lpVault": "6Fus4GyrC5cxsFxMEe8bdU7uocwN7159WUvoo7VYurV5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3KrPVomWoEe7VSGwSMks1FLEzDY4f1EU7UCk6PzrTWLm", - "marketAuthority": "5r9H64ERm26FLsJ2mhsavXFrPgH2J3dPuovczZbfC4dd", - "marketBaseVault": "CjYqDYXAiwLXEb9kTRNHKTwDYhqkUPh9oy32qBWNXuTE", - "marketQuoteVault": "9YAc5hYXZERyiA3MXtc6Nth9ZZ7Z4N7TvGx8yTpvCjo6", - "marketBids": "BYjx4TvZrejcyNQmv4dNtSpxP2FRMf8zwfXBTG8ui7vC", - "marketAsks": "539wQvKroBS2ja75xF5YRFtDxstmPx65VHzEo8YTtbs1", - "marketEventQueue": "GpGEYYBWmEkhzo9eKwGVWFjPf1acmAQxF7rVQ76vwk2j" - }, - { - "id": "DCvWVc3ARpeuQwa4WsJYxGFiWZFSZucBSEZdXQ9BB97c", - "baseMint": "CSQn7G3SmbBVFRMvNH5SJV5sd2HipWSCphfDVcXwY3K6", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "H7KvuJWjxaEe4XBUo26vhyFXZDtensPCP2QfePY9QEGZ", - "baseDecimals": 5, - "quoteDecimals": 6, - "lpDecimals": 5, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7KSgfYRPFrZs7a4Bzjsr1BVH7MKY4Qg7hBk7h9msF756", - "targetOrders": "HGGNJPBVo4v34hvJ2tbNBdqmeG4WL75ZVTbaLx4KQ9nK", - "baseVault": "FZwreKq624pJa6L1MWXURqQ1yJ3HCAAccpVgGoRWAJDN", - "quoteVault": "BnT5wSJnuM8DXp3TAP9zXDo6MvBRYSLxQqNmc7on5izz", - "withdrawQueue": "RNpesSibUQZ8VyYPXFWfFfAG8KE6nrAfbu3cYuTHVxs", - "lpVault": "2YkLCEw3JBycTCHHVRinviV1fR1QDzT1zXtDAM1Ubs3q", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DXdaDgH8fGZG74cKjSubTufHB7eD8vrijwekt9jqEV8j", - "marketAuthority": "25p3LbpawfBtmJhrMrR5kha5NxpPyvh43fh9srv6EtVe", - "marketBaseVault": "BbwVrX6JK8sVcPA6up9emqsjAaJ9qhrs6o3sw3qYk3yQ", - "marketQuoteVault": "6BUCPoksSXFAXLUmK7imDKJJC9kjbxyRZCnBGKZHJ8AA", - "marketBids": "7nWQzkZ6hrHGZguTSxSo1eCp633TRLHSAMSKPnPtrk8z", - "marketAsks": "8kxw7B4C4HdSWCgQwPjDZjS749Ny5j1m8SjthrkmrDGD", - "marketEventQueue": "97zgKfmzCR5VV7iaNePqNy4zM9t4RkjmyAmeqXXnW2Qc" - }, - { - "id": "DD1Q4eo9DgqbLAMKgWzbPvNEQgCKZREjUX4h75vn4sQS", - "baseMint": "4ktGVhz9DhUiCj2p4ZYE5foHTtMATtG47PyNqeGHx7ev", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "GJ6nijD6xjD6HBrGyZ9MMMwJLUPGSnhED3fjMg4f9vHM", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BemEPoRj3zo83Qjkx5DpfPZHhZWHSjLYDquVqD1PZbhh", - "targetOrders": "H82y6W9pD8rhBvzxfHchCj3AWxwxgKxAqGY5U9UBqbkP", - "baseVault": "CjckAhDxvwoCD61DZ2LASaRL3CGttKiaP4Z9hDzgDYbp", - "quoteVault": "5pPbcwUoFjKNQNJ1xgNzeD2ZybgdLgKgPdYzC8vszKHv", - "withdrawQueue": "YX6BFdsHBwzpqVfmTJQT9o362DYd2BqDWALhPq6CwHR", - "lpVault": "CfTNV8St7C1S2UwD7xFfKGoXE4uwtRG82VPrTcg5HmuB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BZaeoYWZj76NBikrjjUhWe6zU9sSuUT8v1LzzNCcgg6L", - "marketAuthority": "CcmBHEcQohMxc9nbRpBekGhAYYw6VtwztgswHQqHfqa7", - "marketBaseVault": "erMgzncSjhvW4dXQ7hD9z3peC8NJqJkLeEw9Kb277FZ", - "marketQuoteVault": "4CPGVSx81cwqAazLfSkRZZyyuJbPNM3SN58eh7Y5EYYN", - "marketBids": "5d1rxkpzzoVG3r59yaFfscQyuCxX9zTeW7KdjqBtAZLK", - "marketAsks": "CV8dqpZzHXPRTAYcgMVLbptYNyBBravpZT7Ha4XGhXau", - "marketEventQueue": "GfxpvCFDfGodyT7JA4Hhho3oRe9q8w9sXxY5oZdKvBAh" - }, - { - "id": "DDjxdNVExWu8o5seis563m4ZLFD5GpPqAxLNhWfdGvcQ", - "baseMint": "GLmaRDRmYd4u3YLfnj9eq1mrwxa1YfSweZYYZXZLTRdK", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BhFA38bJqmWdwrVncAgE6MgPjW5zHgB9Eo8Tva7zJsoa", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AGHZBdRfLgThuU3RAELjkFgkKLcM7CeqbihS11KitWNB", - "targetOrders": "J1nFziREJVuWUg3W8Rmbm4i3rKqQ8EEzEELhq9RPK9oh", - "baseVault": "BQkDe3nc2UpvUryccDysS6N5e8LB24WQ6wnZXda5f7ye", - "quoteVault": "GV1JLBCxksXSGvMLBfD2t4RsNpRzy3M2DXUrCAwwPtcn", - "withdrawQueue": "58m8qSovDk1LJqRU6EYx3xnzAGtabyc3HAnRHUQEp6Vu", - "lpVault": "GqgC44quqipc5rNddHr1W3QCMBkjDo76xFbf9oxBWxQw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5m7CdEhV6Tq5KnSCy5Cg4w6ug5DFCcHrUJ8JMzKVDdav", - "marketAuthority": "DEVmU3dzv7cU38GmHUYsWZU42J2ftBbJRoS5dckTLg2B", - "marketBaseVault": "BPup5tqrSqji3k3mi3xNWiNMcT7u1nT2xYNyWgswaBwZ", - "marketQuoteVault": "CEp4s6mKK1V18uznqmtNJy3aQw3F3vxh2hUnebreRDTr", - "marketBids": "8Qxy9AuK9zi1Haw6XVtje9dsHuGxanH9ouvSbk5L6gXT", - "marketAsks": "7Y2snQVWzASCU14BMjaeDFWPiTBmzarZDkNXMy4wW1At", - "marketEventQueue": "2LLEWdvVAeNwewNmjU15jkScgqpWeXEJvo6E57yM4N7a" - }, - { - "id": "De8GZezyhXNDNjBWLoUbDotwqWfMvwX41ZUzKpkPsGQU", - "baseMint": "6D7nXHAhsRbwj8KFZR2agB6GEjMLg4BM7MAqZzRT8F1j", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "CvqPFuXFCJMRkEdbEGtRRLzusGKbZrGvGW5kX8T7bwUd", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "36VnArKPwDWhjYeCb21HgTGxA21wPDcDUpPmNJwN3gPZ", - "targetOrders": "BCzuVaZZF5pr5dDfiK9U4LZYwxbFELCT4GAcUoBDN1gg", - "baseVault": "H73HwdKweEmnjjCqz4iPwBR5CK6jgASK35qFs6fF9cXX", - "quoteVault": "AeMRGE3Hc6avxWg681evmmf8Uk83c4BBCQ86s7W9UeXj", - "withdrawQueue": "94qYdJzU3VYuNUU4ZS5agnHfgeeWQqy4FmmU29aXjohm", - "lpVault": "62BysbmKnQzx8D1FEYoC6aTpH2bkKyVR6zNWvRUPZL3J", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4JzDsFFcXGF4g2cTCs7kUWmesLY75QqWdgThTDoXjKDK", - "marketAuthority": "AySCZLc5Bi3NVnaDXLnFZUE34wsx9anFQzZ7QcGqW3rD", - "marketBaseVault": "J8skJGPwuA1fq7vww8bigsJsLtAYnJCq6aA2bjxCepSk", - "marketQuoteVault": "GvPqge99FH9bjdN5x1z1u6j5W6yGVenEz87vqaiHHXco", - "marketBids": "D4rb2oGRwchYqi6TLhFYRTy8jPajqdZb3Pg226BacU94", - "marketAsks": "Eu3bab8zaacqb1hsN9Q7Y9VVEh5Uo2PDNwwNP5NnE7PX", - "marketEventQueue": "G2Cf4rVTKBBMa2Vb6X961RT5s6kTBPwq7vaR31PZAzR" - }, - { - "id": "Dea5zHhLQoFc4LD36Xr2XvoK88XuNawjdXYRrvL4Q7ar", - "baseMint": "FXesQTFmN2Lr4M8ScxBTpe2k3M6HjRAsUUbZXubQ3U92", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "5upNFiv9ZU13wMQcFuaodP2QJGiTBS6ataW4mjnJPSc2", - "baseDecimals": 3, - "quoteDecimals": 9, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DAD4gEgSRvSFVGYCUSSZGn5YUTs6hPnN1TG8rPBeEg9W", - "targetOrders": "12hpXvE4dP7ApKYABoMnyoe22KdV615ZwY5nsd2jFUca", - "baseVault": "35jrvkwoLZw26kpAukDGTvSzycQXapmQP9hBPGo5kner", - "quoteVault": "325gtczKum41tsRnhvuUnGkh9fkGi5foAax9RrKqqUCt", - "withdrawQueue": "AYdwFsnMLNYWB1V4YjndzTGX7s1AVizAsRTzEDPbTRE3", - "lpVault": "956sectrzyEk2wrsGCFSTBkF5hLh2M21HGwNqgpbViYh", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9FRqMB36dsrKVr78auFnMrXk2rWWAzcEpsXPf3Fj3kd3", - "marketAuthority": "8TkJscfyh6XSagEdejHpC3uwJu9ioV6Wiq1wfM2T7aNF", - "marketBaseVault": "7rxLrrGoqSw91pZ88KrMhZfnxTf9eVHkh468Pw4xnJmw", - "marketQuoteVault": "BHo2Fiig6BMcbZsAmMVLa8cQz2qkLP8SwitXkfq8CWSZ", - "marketBids": "HCiUcFdkdTPMZd4dYDsWFFhG7FrZp9cPdbMsJbF3B8Jp", - "marketAsks": "9oqvsLsHcPqU9KcMZmjJiBytufT8tuARgPFVVxeaJhcn", - "marketEventQueue": "DxtQviQXjYe8AMhwfNSNDVx3JeXruS7BVsf6iaKj5ejx" - }, - { - "id": "DeeYLRZhBFZbZjYdLEHARkdLUvYfUfXXKdwm94GE7QxC", - "baseMint": "DAZbw2FG5PCssV24SsP1E3m1whDn8paXZMwBdfVHRt5w", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "A4S5ozztLzuQpSVJm1usomZnJ83a11UfeELBkwa6Zpnt", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DW4wxwE2XGUsCLeZzVzFhtVjXm54ftfAKLATfPWjGAjo", - "targetOrders": "1VHmteow7iteCLtiGidjget9RafK3hXbEw37eyoJkBh", - "baseVault": "86j7GkK6HoXUSoMPp8fsxnaoHsNfgYFhte4kuKJMLB64", - "quoteVault": "3RsMKLLusHbaFax1njYRMC1ENCbmiNdaQiKwB8ED6zRc", - "withdrawQueue": "2ixR9kKBuyshNBWk7qL3KNMPAuKqEcBaeNyFtrKWSTXY", - "lpVault": "FjFxMrq1YsGjVJPW1mN3tMhccaCiC6dJmmFjm7UitFbw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CBeuo6eH9NoFpzVaYxVH8TDLGQZqTNGTkxb3uR4stt7a", - "marketAuthority": "2XFcbj5GjLTdExZ9evR44QDYoH9wGBY7bbVFeuk8iFZJ", - "marketBaseVault": "DHv8iv4d7dxkzqHWXvrkiE3W7KjAfcKrmQGYBXsSvYSK", - "marketQuoteVault": "HfmFWEehSmL7WLeZYLBMPcgwHBvST3sntxgyDw1fXY9Q", - "marketBids": "ARZJCYo2S7muBWvqHcUBiqdoDFT1epfky8gE8yQiQHJ6", - "marketAsks": "8Z8p4bQjXuuAGPJPtb2Nephwqq3jonAeoJ4F1K4LjQmh", - "marketEventQueue": "6qBmgvCqRyytgabfFBVpLXbJ745LTG4fkXCKS4NhKvrd" - }, - { - "id": "DEfXxr1nZNuFi1GQPCpSACwBc5KoLLeLMPuWDFFR66o9", - "baseMint": "Dh2WZdzcpoGuYgwbRUqt9feBwNiwkE6yg38zNSuV3Kmv", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8CDY4kq8kYnDNVy45RQW7eEfMsxM1sqMMC21zk2SP319", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "53XnGE2CbBnUzvkyoiWeNNc9uHQFiebGFLoGmGutZ8dJ", - "targetOrders": "6wvGg2a856rWGwPR2SEWSh9pcjRrYpTcLcRA4goUet5B", - "baseVault": "E1LzWyiyztw5VAoU7CVHpgXDZoJkXKP9ao86ZG1RW5N9", - "quoteVault": "FRNcyDnwMuh4nkHHVp648kjT8phm43r9C5vTjdxSALw8", - "withdrawQueue": "8h51E6eDWWxq4xDcp59oqLQzJYmM4MzpTL2NYzfcXBYk", - "lpVault": "BW7tc6MU9w3JugimgvaLtDqdzjuG5Bx1x9VmsK3YRR6v", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7q3yWfmQFSac8ohmk2mowfyTPhurcYF45ryeii5Fb2CU", - "marketAuthority": "ER3DndtPabrjZ3mafnsUJCWk4G2spesoX9vStCAF7wv9", - "marketBaseVault": "5P2DyZAxvn4fhebgF3jLQsYAq7p9gwsaKiiJXsDLNjzk", - "marketQuoteVault": "EvzHaLBy645fXXxoSLU7F56sVp3DUdZ55aC1FkcX9vkD", - "marketBids": "ETKpNAVRCkYeBRreQDqPdGJoyaC3zjtWpMLXfuHBMrvp", - "marketAsks": "Haei39vKNFnbSKHpeGJa6QB1JrASHDQUxuAi9d7eLq17", - "marketEventQueue": "4kQbA9BYsf8oCr2BZZGFcFtX1JS19Nhvzrm7NpK86rJJ" - }, - { - "id": "DEGzAFAEHyqdLYZniWMNFGY5UwqMez5GWBa9Bas1bThN", - "baseMint": "mmKTDQDGA7sUVgE5PS3A5429gq9kRxhsWFdrDws45zR", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "7unMaCTCgHnzUaTMzJjbu6NW9N3hnbshVBHREWGdBtCe", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ExAaC6gx7Pf9tnrLJYR4YpVXnr9AW4Rb3735nAUxNHn7", - "targetOrders": "5ux4tzEgQXQMWzL6SYW4nvN5DfrfhrNU6R2DkdU8xHr8", - "baseVault": "33J4nqzhjb7s3D83t1g8DCPtDPjJ493hAyzZAnwhxfoN", - "quoteVault": "HRQyV5zdBWYaC5WS6aje3ESTFxiGbAo3iorSrFKfGMS6", - "withdrawQueue": "2QALN9advVitVnck7VKkYWPGZy38SbpESfmjbEWnsUmd", - "lpVault": "Db4uAWR71cBgCm836wgkBZMTi4cBfoz8dGFbgj2aVXzg", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9hhPHbUWqsUynqRx1Hbe2LzrV9nFKE2RnKeu2uHkQNkP", - "marketAuthority": "EXzrinMZ5McqSMkToLYnUiQpRFSvxFCZtTFXCAeCAf4J", - "marketBaseVault": "4YdTxzJFjw5BJbDotcSpCvq32CXZ214tztTShtCHBnam", - "marketQuoteVault": "HwJTLuLGQhEW1DJ6HF2o7KN7L4EZaQSmeY8WNGWZUKKr", - "marketBids": "E8xBEc8e1iFSn4PBZjG3c6eeS9QsEsYSC7Aam46HPdK7", - "marketAsks": "7a9Md7BWeJJo6gyKiAREtRyBiLzQu4VB78DTcAWytGkb", - "marketEventQueue": "Ep9goAVU1hUpfh2GJbDrdbhj9sVRgzFWvsfde9w8qddD" - }, - { - "id": "DejSxmK417wbnQybreDTcPGiw2nY56z6qxpFWrqaBLHz", - "baseMint": "unknXbA1bDg39nuBqVgMNZ5qSZa8pw5HditgkPe5eFA", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BWkgMEcZ8qVhBHrbbnjX9U1g5Ufd7ktTRA1r3rpR2FG4", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3sPKgXe2YuZ72arLpq513Z37HpC2495f9VXGDw98r21w", - "targetOrders": "H5txXDi2BExXPuwNj8wXvj5ak5Dc1oV2Pb13UrppWHQr", - "baseVault": "Ere5Gingf9kTWagy2eY4SfQ9vXHbZvTG4R93SVDNsJeq", - "quoteVault": "DsuZVD2vPxKjfn1a1PJqJS9apUw5iTigAM3AsD8cn3J5", - "withdrawQueue": "FMmDbKSPUQZPSF1bUiybdhCtsZTam8QjYaxwQTzN1o3W", - "lpVault": "z58TM9LaUvu79y5F5b7gu2pUUYFmdLR6RNPAXxy7y9x", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EKstCuE4DgPLU1n9u3YqjY5VSANEBtLEC7dCHGRrCHFn", - "marketAuthority": "J2e69reKCgaN8yinTr3m7oc7BxXknCEiFWX2NYeYfY68", - "marketBaseVault": "Avig4wGyPKpn5Hp4EJoGKMFWKjyumxR3Hy8RY4q71Ny8", - "marketQuoteVault": "4orZvxprUSmKSmwpu3pvLzX5QcGFC2VLz9eMrCBDiejV", - "marketBids": "7hyeyqBeR1W27atH7yH9x9JbjUXS57ojTPhHs1RAoRZR", - "marketAsks": "13aDq77tvZATghp4tNKbfMomGhp4hS2JiRSdWAaFCMQm", - "marketEventQueue": "BwpaZ2rZv4T2iMMvWVyMzBmgT3sVHt1eaXBttoo1mU8V" - }, - { - "id": "DFkVA9wCMfo85gArRxZ587K7wNwejstJYSZ1ChSQ5geT", - "baseMint": "4J4XAtCWWVrb4FBM4JySPWX3YWix2bTpZNtAAHH4UEba", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5A9HywNjGFn6Xhdd8SqNibgFWKahCLgBVQmDDDHqUD28", - "baseDecimals": 3, - "quoteDecimals": 6, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "67q5HmRe2XN7qAbscWzd4TYTnGDeEZ7j7S2ehKsPtUTq", - "targetOrders": "7AnSrU4aB8pr1m7bUjStviyoPAztCXGZxzzcbXM7YY8U", - "baseVault": "DK9CL4L96bDVXRevkGh7PGy8nuyd5c4TvU8XQ3Xz4BE2", - "quoteVault": "DeVLqQqAM8Nj3y31Q6RPzkeqDAR9hgm64xMtkE7EbKGV", - "withdrawQueue": "6hoPDZZ3S2ctUKpgkhrjfmwvtU566awGYUh3hdzaeTvq", - "lpVault": "BLVfXJtMciQE8LvNqhBv5a8vQtT8JFY7Fa4xNWU7CBp8", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "44G3qqjiApZffNu7CAMZN71nyfE9CtSGuSa82RLPaPom", - "marketAuthority": "F28JXgcpwNwVmTA26n46QUcY4kYAcu49jw416WimZwq8", - "marketBaseVault": "2vygHHaoPbkTJNyTx3dNvgZ8Ghebo5FXUkFX6vyzvSsU", - "marketQuoteVault": "6rrS821qw1GWQxQVeT26xHM8KKMUJedHRrP4yp81MfvQ", - "marketBids": "8yo3fjjg5dkpDBXif6DpDQLNt2Wj1FLCDLgS7oYuWY8n", - "marketAsks": "2cKnfDcyB5JRCDUVUdxPw5P3CnhdTU4PnrGbBK2LSyHx", - "marketEventQueue": "5w18ro3nBJVx2bsxBvJYZd7zzAn59UZfjmwCHadwoBpu" - }, - { - "id": "DfVHjpeccXCBaLh8raL9KX4rSYbumsSsjNN6f3xVzNJr", - "baseMint": "EEhosSQvC2yVDRXRGpkonGFF2WNjtUdzb48GV8TSmhfA", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "4x6wWG5bH9t5DhoUGYNp3XrduyfYvHy3xsLenqrPxaEF", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DejoTPes83aKNGK4ZUeBbQkG4h61Ge41ZbVvEuRRxGVF", - "targetOrders": "GNMe41bunFRYsCHvYqNwFm56h6pZaQRqogyqNJMSoKLg", - "baseVault": "6njBdJ3PZSxncboJWBiQzkegNjfyeHoHZNyiu9Cbe8wy", - "quoteVault": "9jfHGRpN3XuaVYx3o74ktW1Sq2nUfSj9MLAiV7uUjxPR", - "withdrawQueue": "5rfF6mhwkxKD6qNWHHWG6SV2SAyKvkv1haArzGVV2BSp", - "lpVault": "HEH2fgrY2UmSVAU2uPzcfPM2JPKdrQQkhLyCrVtDGY29", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6XZG8qSf6TX8ux313h4HkBWLHDJco3dB11Vmwj7KyHVo", - "marketAuthority": "72DJpZS9jnnS95TR1JS1yMuB58xGxuMSGwroLq6gm4Ag", - "marketBaseVault": "DoSmx3eJuwRKhA7BJkFERyR1eXNfkS9dt9DR5y7RwJS", - "marketQuoteVault": "Ff6wADjRuRn4UxrA6saPdN4inwmxuYpXi5vtRT2mCciF", - "marketBids": "5UC6yZd12bRfTteNEV6fSyBqbJS9asiECeLScvqazs8W", - "marketAsks": "49Hhry9RLccgmHZVbvkeuZVAFTj4aYCKZ9JJ9eoaR4qS", - "marketEventQueue": "BwyWiyuZbyPw7zhKKnbFrpyPTXBPscSXY6CcZyXsqKbz" - }, - { - "id": "DfyVPxqnxcL9qFQczb3rSsaGWZ3wVy9SemqDa8Pw9rTv", - "baseMint": "BLwTnYKqf7u4qjgZrrsKeNs2EzWkMLqVCu6j8iHyrNA3", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3ZKD7kuHd5C896n4Jcsgdh7G34jS1dCF3tdj8n2PdKL3", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8c1X6MX3uY5xkTWuk71VzPbxTEkCNspb3oRChdkAKVH8", - "targetOrders": "3xphwsybYsJafw8tHs1t9NHcmbpTBLNnCbawiHkXEnnf", - "baseVault": "8j2bp8skUBxMoD1ejtY2iwiCq8eoQKXBdCfoLgF1ZqR1", - "quoteVault": "E4tHveyWyTR9n9v3NENwYoZz1AvfFTLNmwS3DafKf9Jr", - "withdrawQueue": "BM55BshJ7j435362PXkk5qYoHGVAsZ5QTjoVwSF9eUiX", - "lpVault": "BpxPusFRs5KWmPGAEKEHbtrPBmc4LBzxrrmzJZUbPepy", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7MmPwD1K56DthW14P1PnWZ4zPCbPWemGs3YggcT1KzsM", - "marketAuthority": "2nrPJiAdKs9gfdNCicx8LLD3Cq7U7i18smokVKSaSX9H", - "marketBaseVault": "8a73K53T4H6Grvxe2yaNGk2jNr9zUaDDUzm7NvcdN8Lr", - "marketQuoteVault": "5cuUphe5U9FDdTFNsdJmpqpTnVzRnsdb2HVHC4cX1gAd", - "marketBids": "5n23ktKjEEYciTp8hvvdYySTZXWsVEuNywVyUzwBFR4M", - "marketAsks": "Du5w7i3mdhG3E8UuY4fRKX1Uk7tZkg7qbuGW5cCArLD2", - "marketEventQueue": "G3BrayCziPUKF1ohkzJ3qJeVUUMA8HX4QWCbCxB7hHmx" - }, - { - "id": "DG7GRg3ykZHdj36BDiYtjowW1hh5kKpuRgWQxHrQSd8F", - "baseMint": "EjSwAfwi4F6uYtoi2WuCSYSWPVUPJCdemmShZ9tdy65P", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "A3oXJwUpWNY7rK5MTzx3AqsNBGa48WMaxwWS3ZWdZfL1", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5qP7X4fHtTf2gdnrHjJErHwG89k29tQneypDjMf8csjF", - "targetOrders": "6bqQxp3nspRrCM7C67ykDKoagdftb5FVoysv3b3NP5Tr", - "baseVault": "FiAu9Tit3vg72opiuWt3kuY8qUCeEYyzdQnV4HXASqDU", - "quoteVault": "GCRSVz3Hi58cdAgnNt6jpxsMvyqM7rTyHcFyFBHwiwhF", - "withdrawQueue": "Bfv7dnrgjo8JfUazHooC5soMuFC4aGyqgb7E2VyijVHK", - "lpVault": "4xDVYqBUYXS9rBAx7cELgjjETqvrLugStvUoSM6YuHT8", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2gxF2PAHuW46bNcwiH7AbjfocvereNBkJT7gas3vbeiu", - "marketAuthority": "DEJqHqtQf65xNrS4ZzB8ppqbuxmpTfjtqRgz9jCoy7W9", - "marketBaseVault": "5NgZoeHfkpQpb3vL1mGBgJWj6cQ7Uf21ChV8uumbiUrG", - "marketQuoteVault": "6jePDJjkiC9xMRQayWb79Jm3mauUcuuxTQe2t7kkPt8P", - "marketBids": "7Fwv8KDHWVuB9Qaa4PALwqi9e4X6DjMUyAmK3w69wKk1", - "marketAsks": "AkRKEzNYpJPYsiy21CnppS5vcqjffB5cmPE2uQveS33n", - "marketEventQueue": "3EpnjGwqdkRfxrWEvU2ETxLWari9ejyqyLofQUxFeRth" - }, - { - "id": "DGaRR6z1TF9ay5taUEeUaSRGcLUyqEDrLGZzbKKX8cVQ", - "baseMint": "FyNuYGBBry5LAtPEkh8Y73izjTUNT2td2J3sGCK7E9Ju", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GNdoT4Tar2wz42LnREF11KzY6FpGkztqXk6x8i22xkWS", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4A2EBA3ujr664m2fSaUpmGAi6HKxr7yeAFruuti1HjV6", - "targetOrders": "CtHrHBipz8naLhwFjgqJrxQKNW8SYZZRTnrN69Rhia5v", - "baseVault": "BCvnpEjwyZbi3uUQ286a9ppStfjz9PePKbFSczStHLRH", - "quoteVault": "4orCLYwq68ZvQSy78SBYr27k8NRBrKJwjMeGvfraAGYC", - "withdrawQueue": "2126r2mSguqgNme6YgSRgemSpsoVi4RXwsH1kJRrguBo", - "lpVault": "EQD9nC5DD5zeJtcXJzw8HTARj5SPeiWjnjNTEk2gNJLx", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HxQW1ZR6MsEmz6h2j2oXCu53WbbWtqCtyNjhFHtdMLKn", - "marketAuthority": "A5cQCukPYRWHPdjjSeKg7PT1Ef9nd38CsSW92kcfiZuf", - "marketBaseVault": "C9uyPAzPMK2WJzYF3D3MPnZ3GvLaKDXjWURNrrfCUsoq", - "marketQuoteVault": "4up4gBNPf7tEpH3WoovVwtfSDybfsHQTVCFATw1irHtF", - "marketBids": "BT4tYdJKya3m9NTYyyUxHZ3rzZgujg5njwmLKcShURGH", - "marketAsks": "73beFpertKfLReNRNTPqRtWLonVkNUimoEeYHZj6UtyU", - "marketEventQueue": "Yr6YN1VNTv2ByUQDpa4ghk4FeLNRagFEpDTJcbFkJju" - }, - { - "id": "DGcywAKXnWBdqXwqyJuiNZkE9QVN77vBdWABYGn5v48H", - "baseMint": "4Te4KJgjtnZe4aE2zne8G4NPfrPjCwDmaiEx9rKnyDVZ", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6cmRySD9BEDsH3cJc6vCuWaL15JNv5HbwdxAEiaNB18z", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7wPbKL8HYXPSFW5qzVti5xcfjLA14ch4CQ88BCzGctoX", - "targetOrders": "BZWdHsRLrUrdP1z2UwJDL2tPM26vURiNPTrRKxddnqH3", - "baseVault": "3Zthh6aDCCHJADUjzxSUYwWUpkLzyDHYN3fkMJDhK1vU", - "quoteVault": "GwMY7fHMnvAQWdRZfJejJhWs2cjuJ4t5Y8JhPe23fJSk", - "withdrawQueue": "3UEFSxqzY9uUftgSQStbJYks48e9crxioNRUg57n1mpc", - "lpVault": "8t5WDZHM2KrdrnyRg4Wg9xpuqu4fHGo4e3EyKfXN9iwQ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FCbU7K36jUbC4LjJMqwHU3HmrsLfNhXvhUjRBMbubodL", - "marketAuthority": "AA1WPKPtA31sJr7MrYtxetMvvezJWCbUEqNyj7yAc9sY", - "marketBaseVault": "EAMuK1Qfp63SCYJptAheA1yBsw9GZmXmkMjQiEcdEhU7", - "marketQuoteVault": "8UwVRgAjifrf6B8NE1HAbbsmmNbZiutsooEnwRM1zjft", - "marketBids": "4ftTQVQ8sJqVHk9obArbhgtho2KQk9wvJ5JjUktijqp6", - "marketAsks": "2cRNirswJQvfuMy2Q5sKTCMoibJjsfQtwcVfkUXnjNkj", - "marketEventQueue": "9iSDYKdhabN3oJRhY4AJDFzhitikAMbV9gooHkd2tJ1C" - }, - { - "id": "DgNhGHz3he17Pv5nzjZwGycRvvTahRL6BxFn91h9wUpw", - "baseMint": "CWhr7vJ1rCSgSMCcwMxdLVWdCf4KkSjZEeSmmh1poVXb", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "FkktBKJhHp2U5Ap5rGk2NcnzNqqypWgcXhvQVCuCFXPB", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GUAqsmDjZxMZQKegDgzNdy7buYvuCDhFziUiAebvZsBb", - "targetOrders": "7YSpSzVgm9aKmTfZUZuVJSuswhMMWbructhCXi9fkKaz", - "baseVault": "FTedpAqWhh8tULxbpCAdhHuJ7DipU71VgWkWhGE7tjQv", - "quoteVault": "5WuNSGNK37ygWe9yQRYv4cU389kahGYVpfzZCyFSfySA", - "withdrawQueue": "6eGwyVLEqvXLPXR35PeW8W5GuozvrPeyB2kFqJ9QbbER", - "lpVault": "9Ayeb6xfFeiDkrxuqCwRREBhWyXyMVg86GBhFLGQVX28", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6bkg2yNSYtaGAJZ8Ja7W6qXrGCTEbQwjPHhPC8Fa4tuK", - "marketAuthority": "ECg3fn7rUSTQtmkqgJiW1okcP3BmbrkvhseWFYzaHAhZ", - "marketBaseVault": "CMN9njy4Ndt5QVt9jZsWQaWuMmExhaCdmBLK9iZDCw4e", - "marketQuoteVault": "2WjQvDqUvjqXoa3iJsxvgHMXyV18obkz2PQuTndJBSnp", - "marketBids": "2AwgLdwUhtrSeCyEzdp8wUcbqj43vWKv1LDfcPsjRwNR", - "marketAsks": "9wZHRuvUQgDLT7X9UCoCmkvrFJHmdCBNNzQn4CaywFir", - "marketEventQueue": "CZURdbd5gTRT5NBRvP7d1pyG6B3VeogvdpJ5iHta81wQ" - }, - { - "id": "DgYcFy2PbBe3sA4MH6RTkKyP3vdz26ehbwyaMa9GCngv", - "baseMint": "Vjq9T5xmqRzLXQRyvigzyZzpHCGCsbYAJ7afLVuF8j9", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "HnVAUeqH3jyKBw1ppSGrMvo6uDqfPzDVN43Gk2wtSGFU", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3ud98B9VEA3rGCzfZrXsbCheqAsSBY7RvwtbRdRyGGap", - "targetOrders": "8Nk332ML7Pt947D1De7GisCnmkvgRhUAwG9QBv8N2m6V", - "baseVault": "Fs8co2VVTNZLGGs66u4Fix2AemDpRmkxT3hDo91rZPfz", - "quoteVault": "CuiDUiAwRA2WKai6XFKRtUNhHd6qwDtyfdQ2iTZA4AZt", - "withdrawQueue": "4CC32wHT44jD4JRuByzEDAN9jEiCeANrgjUVQk9QWMtZ", - "lpVault": "5EMFtMxbTYhZLRuoz2cDPv7GnGMG3LwPsfXB2hicRYt1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5NGK79dPwHwwFkmGFRiDLrA9Z8yDUY8DksrY9cenAcmN", - "marketAuthority": "F1NDVqkMZGZqUDdXTKpUrmen7Txs57X5i6sgc2LE3skY", - "marketBaseVault": "Ga9KpZXuPSpFRyB1A5z4YLCcfB6nSsC91NysN6evUh9M", - "marketQuoteVault": "9L2UimZvjMAvjmdGe6QDfjtxxLiDiahfyDAVr3ktXYNN", - "marketBids": "6qXx9g6DMQrnJw6shVXUS8GzF2a9J3szdH3a5bF8FVFq", - "marketAsks": "FfYVaEeDBiSwfWvaXSYDThk8HcYNGTCQZpREnho3TeEK", - "marketEventQueue": "swzP38YyiGiTNwUXbQpNJs8z6vhCkePk2Up1vPumFEi" - }, - { - "id": "DGZnFkBHBcwrZskhoswJCht8GMLxk5JXLHhssGkhDwvo", - "baseMint": "32CHtMAuGaCAZx8Rgp54jSFG3ihbpN5brSvRAWpwEHPv", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "iUrQfdv3jDYwzDXpUHyx1HfznXxD8N2gVuS47Fw3SXk", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5Eb1Gm5Zrsqv3BQvnTyJR1s4Daqh5JdXnWjMHfDQp5HU", - "targetOrders": "FetsLFmn9MzGgiaiadaNRKjskr9NkH8vy8oADxCHm7rB", - "baseVault": "rbqwpe6AYzj2EAXkrtSfiLRotEBs3DJTtwAqaYQqMBy", - "quoteVault": "598hutN3VSVeZJZ8n53XvEVJYBqavutiTBtgZxKpsgfB", - "withdrawQueue": "Cx5fW2Xi6P49AaUCbMVf5oFynjmBE3o7woBJ5EANWi4w", - "lpVault": "AjxbmgnpMysisCVEVNFEAcJJYcsQfSXJmWZSpRxEsUZ8", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5AtKkmD6jUnjM5XpUiLNsP6cvyzFQ7Ap7Sjs3UQ1MZXu", - "marketAuthority": "DEXDHWDs5mwhs9PUvFa4muLQfkUwE5DxintYrvZmMWv5", - "marketBaseVault": "BEM9rqvs2gAisgNHEz2PqbwnZvxwrL76y5hvUyzMxCxU", - "marketQuoteVault": "DbkQJSTzsFtW45q9aeJ8SEet2G7XoD1zDSu4Czc9mr63", - "marketBids": "9K39T8utVeicYjLfL6Aqd5vNasqLKLx4b8WPCvbu8Fdh", - "marketAsks": "BPfUrd1gCpttA6Lu1hxUfihHhNTP1ZEvA1LbiS4r9Xj9", - "marketEventQueue": "GeXZEHghepxZCRdmeQGXcY5Zc6XGUrb9FhtZAFVqG9oD" - }, - { - "id": "Dh5husapuAh3XHswC9JP5HXBnmSNs8swqyTRbvvCusWg", - "baseMint": "Gz3u6eJaKEviYpPC5AwUziz891kNX76PNdsmJrnaNNY4", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8yaEcvVVc7n8psKUg4VEKEyXDeUMVSz5Jpb2UfqZ28KJ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9j9ykLyCnf6gEoSkpByyikZ7UX3o5K3NXU8rdUBuc2qB", - "targetOrders": "CiPLuoPGNHHziadLb5Un2rzsrACEdJfkwr2LJBfjWshB", - "baseVault": "CusuJiSAgxhK7MfbUdebaaTj5zELP5kcDTP3muCdyioM", - "quoteVault": "HCu8uHJbjkw9LVbQbG5hCEyG2kHpo6UKANqStdhHixo9", - "withdrawQueue": "4x8pBAK7DgPbtCrMwvnNAkpCzFXn6dwyWDvQr7gyjsgT", - "lpVault": "8VLdmaCSFx5ga66oU1EFh63agA3iPsJjSDC9PiqCFkyF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EmKW38yeXHetYYGVnfnuHJB7WEv11dcrofD4sdqZ2SSV", - "marketAuthority": "tZXhg42ftpPtjLWvFEvjwf84txbmfdTXe5maZ1mP5RV", - "marketBaseVault": "GWVXYmdRvuC7q28tJSGJKd9yFDDBVmesZDrQjtwNejmL", - "marketQuoteVault": "ExPW9AUt9RWEZCVGRnpYSzZXcMvZKkbfDxypR91MTwUR", - "marketBids": "5UA3V1rH9xySgX4fU3LP7YYtqeTHVC7tuK5aRMfiVaTL", - "marketAsks": "9wsjmaZtgwFR2nCAUnF9s5cM1CiKxhhS9NzUvmp2EwUe", - "marketEventQueue": "C2hUgpoie8k4SuxZFP5t5npJyw44sqKrtzvXfk1Ejksx" - }, - { - "id": "DHQVCu6dAax6asQzY2M2GPaSJCpVktwUGo9uWmNF7Jf4", - "baseMint": "DAYuWa1frwNjF4vxty17LcBraZNtBmFeixByEf6enBQe", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "2cdc9eGiuxAqmwMsnDNUXsiogsxRQpTUWayQY6twztyN", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HUrKR5ERR29p6TiBRDVgi82AutvxqDxVFw5nUbtAJAPF", - "targetOrders": "EUvdDh2pzzFurs7PMmjdAC8tepJWqSHF6Uw1vEWVeboZ", - "baseVault": "EPrZAAqX9pWmzKfPMAZrhMArzyKW6NpEcH3jawLjwBjH", - "quoteVault": "DTB2Hs1rNa4PRoDscYkoDDDvzAo4cfiXctyBco6qJwab", - "withdrawQueue": "GCK6DB8HjqfZKDyNUNxrFZAuCU1vCNMfsrSGNyZ3CMxT", - "lpVault": "GEQcpMHG43Frw81KWrqrjpna7zfCy5py99qzyGKkfSyQ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AycJGpJ7fFZGQStHMoMEueXcCJAEtCmbKVw6MVzeQNFP", - "marketAuthority": "9t8Mme9L6LGxUbbUFMGhfVmAZy4xFFEm7XkwLXtF7qNa", - "marketBaseVault": "Dd1XPTqjsqKdzrxe11LcgkryvoYpeygQcuX2y5q9VYgK", - "marketQuoteVault": "5aWWNXu2RaY7Xz5udJ4Aks876uj8HU9T4u4ii394Xe3R", - "marketBids": "3vN16RrkqrLcvepZc5yrLhY22tidvxREfH9iDubpayB2", - "marketAsks": "86goJqtyjiLDap1nWvLTt96YdAMtm3jd6wDvPfmsy2az", - "marketEventQueue": "9HCDegU71BUk1g3tSXJKuT2GSk6WuTBfFz7qdf7qK8DJ" - }, - { - "id": "DhZ4E8JfwX5Yv1sqFJmJS9gBaBbK1viuRxJ1DMabpmHH", - "baseMint": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3Ep9LD6gZu836p9j3RWGfnRCL748PTM5DrFUGCpTC8Ph", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2p9U2sMRfBn2gVTvMUTNEQ3ydnUgenM8TwziGH62QeWv", - "targetOrders": "GZ7h6XxFuA7qNeGbjaW3qUHaTmf4UuAeDL96KoR9YUS6", - "baseVault": "5sfTphYSrehjM3Kc1XB7SuLz6kvmcL69kmtKLXNuXJLN", - "quoteVault": "DpWWUrWzKsL4djyaAu6A4fZq7C6DKBu4gwWXhiYWLs3y", - "withdrawQueue": "BDPLGquv8kjBTxiZ4a3CYHfpVZqPujhccFb4Z4igiU6W", - "lpVault": "FDarD5XNMdTk97VCn4fhBFhwdwEuBk6d9tyjw6jUZv1f", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "marketAuthority": "4JShLxwAnnh6SP788Fc9JgqQLZ4LjeRc9Xa6vES7tjxT", - "marketBaseVault": "HnWhVtYy1jamCZQHCeRQWmvyyUEejezfJLZStoUxHeqH", - "marketQuoteVault": "DxA4WZdWNAphrWykNfshfWmrZUGDwMppFpn3EQqnAmjg", - "marketBids": "6oEBnLi2PRUnU6hQZAt4fNfv9jrAqSaXsKdEkLLDX1HB", - "marketAsks": "5bHdPknF6ecXwEQUtajsbR2UpuCvyy8arF59HQEByWQA", - "marketEventQueue": "H7PcVAr89znWNM7zcRqSTJevjUmB4r9bt6pbtzz2ZvAN" - }, - { - "id": "Di7gDy9EjqcPD2FJiZ3agoG9h5LCEGz5c858CPVfeXDQ", - "baseMint": "FmpqmVcT4hSUfNhach31YUpf6M75bBYaC59JLMyCVNHH", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Edqjr54XcQHkALXYMJCkjEd5LSZ4csPe7H51tp5mYt4E", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GYwaoWfk2YdC8Tvyk5CFH44AUUfXFzX9gxn3JCxuTVMk", - "targetOrders": "GQNiZ5U2z3ic9CYKduNbPkGWZwD1ytrYg2Bb7JfWkTdN", - "baseVault": "4f2o8hCDuB3qpyhXhe56iBQk5MHWYG2duC4S19muCDp9", - "quoteVault": "6XXYf24qrpRwpn496KKdqsfoMNdoG5yvQCcnHGjgg5Jw", - "withdrawQueue": "85tJ7xs5WqeS2JUBXAjxLPQuF4DUbxyFa6yMAY7AXp5u", - "lpVault": "CZkYqaU2gwyQ5efJ4rgSAB7rziFTgb7e5CornXL9W73F", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "J6DomL29PEwiwB95iZ484G4fPQBHVDx4g2baiBV8vayb", - "marketAuthority": "75XJ7NjSxRKmbnDEBhX5PQoWLYnTqDNd3ZQPhpYJJJMa", - "marketBaseVault": "9QmS7aYeRTZqenhYPyPuBn7wuaM7eyRpWCBEcvHvLGCS", - "marketQuoteVault": "6hfknKd8KWH4BHBD2yVE3dkSJHAwCcSsjD5jHDLtUwHi", - "marketBids": "AJv1PyozPKikaAgWt4hKqhozEky6rPVE9i8uoMWbkDpw", - "marketAsks": "EShkbLeTqjrc9HUMUvqcTDDzfwPqeS3YnFduKfo7URhw", - "marketEventQueue": "AjJqfEP5DM4qgDJJkNGG8836C938kxQ35ku1Ez8MZHWZ" - }, - { - "id": "DiHURjQH9nbEd2JVpmcvGnwQnrN668aPa1V4xx4SMwR", - "baseMint": "7sWMHQaJJPn1rkeizq41iPiW5gG7Ry7PXYAVHaUwY4qu", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4WvXueNnByL1SYRkUN8Rfa2aXS2xecS7LbesWsrtSETd", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7zf5Yua9U9M7f6cmJJsB1jXU6xs9dHwq4MPeetYBsQvT", - "targetOrders": "7Tq2LGMJ4Q9PgWR6wWbDmiPFTAV4LeAFPqs9U9JVpwPr", - "baseVault": "GTbQ9thvvK6pN9PwTTcMaEJRYy8qK4UhbM49HFpmrudk", - "quoteVault": "4VEt6Qzo3Q46qTS8SQk7QmW5MycpM24TzJkY564Zos2M", - "withdrawQueue": "GNe72PaFzePVnTPjaUw8jFw73LWsBeaFYGK8CoifVist", - "lpVault": "iWah8SGdVRjpq3XGv49LUm4tUvGsncZfXpUdKF5rqfV", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8ByPRhCLXzA58NpuKV7XZw5YBtSB9B26qmCwGnoFhSPQ", - "marketAuthority": "4HG6Tz1L71EySwAt8Mk5KnvfjPTu2QJqGGh4W2TAneGA", - "marketBaseVault": "FYu7Urq9E7Z6XVZaJnV4GspqfHQYwrqE2MQJjPxa8jjM", - "marketQuoteVault": "BFPNm6fJniGVFbVrsnXksvWtUCxyre4ZK8GNExFomg3h", - "marketBids": "ABk3WChfVjoS5p6K1m2M6PNWUFN1FuYNWND6e5vv6J2y", - "marketAsks": "FC8RFBgaSX22U1X1so4EccrdJn5EjchrUyAzJzkncpTW", - "marketEventQueue": "3vEhvqku1f1FVFBiUnuq1EiEp4yZmMrw86msHawLFyQt" - }, - { - "id": "Dj7RoSwsYaWDHbPojPVrMsNzRETDcJ4DxL1pN3ejy9Sv", - "baseMint": "45ojchnvC3agGNvs86MWBq8N4miiTY6X8ECQzgQNDE4v", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CvHiyBTnGGsFuNAkcCFUjy8UPyPLR2o2taGDYXaj3ynK", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4LpihykXueSDreJTeEghCskbjmWRrVEqFKkAknd31Ad6", - "targetOrders": "HJNPXZaSuZJLR79bnJ8RtTZd6fyXnsVyMZmMBBUJSNPN", - "baseVault": "gZfSUXJnNEzpr7SafcVguLepyoXsV5LH3agNFVvsjwy", - "quoteVault": "C7d12SaqMj47vwhrmVd81Ziyn5A3aQAsSBeKnmNH9S8H", - "withdrawQueue": "ATkp1MsV88dHhJRKSUNRjVAavnxNomr3s7xozQpBuQpx", - "lpVault": "2ku9Z82BjTh7oRybvgXnYLytC4fRZNLUPcpDow9EdNnB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5PqLnysygwZt6i6Quf1aNC2J4676DSbDroff94W7oYod", - "marketAuthority": "Ccivdb82pxRJp2ToLcywcjPRFdWQFKLPHhoZtuRUhAx1", - "marketBaseVault": "9cSWJesHpn6vHXb7SQNyC8gBP86eke11HvqDfhGKVPCb", - "marketQuoteVault": "DTtwyuT4QxHG5EULsWckth7k45fQeLUJ3wQbYbuAR5dD", - "marketBids": "CmD6UHj3TC6MCpJezuLG3bZNo1kgmtiaNtvqjKMARPkH", - "marketAsks": "2SRjiNcj99j3DLquMWA1tNVYtHRiuEusP7TWNkk1pbPr", - "marketEventQueue": "CY3RVjdqg9gN82Y5Bqv8xJq83yVeHfa4mpK8CqQ3BiCk" - }, - { - "id": "DJezzNnRSAXEBnKCzs5wPaksh6wyYLFUKQkTFpepFQdb", - "baseMint": "J8K4k3wPtpeimFxzQ3fLAe963Sy8rH33H7XB6pTa6D22", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "43hin2tdpLC1DoVqVb2kNVxAr4Wnen88Ukqec6Y2KSjR", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5X9h9VBqjdLEfX18vtZVzeJqk34vSzvJorbehrctLJM6", - "targetOrders": "59ZeXZs7Xa7qpDPxGTi1fNBv9394tB5fpoJ16JgxWZV2", - "baseVault": "J2dZfjtu6ZmWWKhMZkSxA3ijrWW8HJF6BpFV5otkzqTz", - "quoteVault": "BYpYbuqcDjb31KSuP5eQpPK16JNnyYDwouaWqqsJi4Vv", - "withdrawQueue": "GH1dhKRhekMxQzGMbXb2NPanX32YTSdxRXw3YDbtE7WZ", - "lpVault": "Fh7LhZvGTLhqHs4QfdnVcWdUTPdpT8XoSzgqEvB8esKA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7MtgLYSEgsq626pvcEAwaDqs2KiZsaJUX2qGpRZbcDWY", - "marketAuthority": "HNe5G9aM2pSfetFDxSfqGKcrawC2HkFeM8fkA4pqToSB", - "marketBaseVault": "4D97RJvK67o4Pf93bXrpCwbPwXmsx44MtB2WFJFVRt7S", - "marketQuoteVault": "D5W8ibw35zQuA6CDKEGKAjuvmag9uEv22n2qrkAdfu1a", - "marketBids": "G2aScFzY9Ghoeo6WhHx7b9PRfwZmviMjRhdDsyVWpnx9", - "marketAsks": "99DoWFUr2MJcRM4h73Za74zFGYPDw9rMFdpbtVb7HJiH", - "marketEventQueue": "ATB5rXobDyQvff1ABMn6AWrJN1AQihoUApJo9RoGQSqM" - }, - { - "id": "djy5bV6Nt3Ux81ayf7sGsCpxvsJzjSAfAVRi3DB2ihH", - "baseMint": "4SpfLz9RrF55WKEUBHFcMssFexpmdhymhcDoPSpAEwvi", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "zg8pnLyvXRrAa5daZzkrYiuyDui5TCyMBSAniJcJ44g", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8gTUVrgSBRjFg5VUGxv2Gxcz2hChqPfKD3KaWtpn2Sg8", - "targetOrders": "5qGckQQmypANaE9FETaWz9CiPMVc54rrTAwUd4bRWjkQ", - "baseVault": "BEEnP6g1s9knukfk5iXbcdXefY4KrZDgLkxHSLubPGWc", - "quoteVault": "5rp2hHYqwZcNwJ655gbSc7pZ12bnub5pePDhZmXoDb93", - "withdrawQueue": "499B9EmSNS9e1qbfySzKcRLc71Yg4fYgi5oRrKcY5BM6", - "lpVault": "5jAUuoJZ3d6ovx8htDEXKmHv2UEbDeXVd3apz1xzp5SS", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Ca64F2RHC9Jovq2xehMPa4JvppADZQzhjn4qEx5CyeYT", - "marketAuthority": "7phwyZo5ZHVztuxe3AWJDPPqYGFbEjfEECNj6QdW85nj", - "marketBaseVault": "AZQqcQUZuDLYB5B5nPgLr9sY2CBqVsW7MztRABahy1nY", - "marketQuoteVault": "6VqaUR3C6MA3ccX8bc9wZz48nr6Z2wDgB92druWTfaLE", - "marketBids": "D1qtyiYtEFe87tKLNrDjD4LU5GL3oUS4s4VQ2Y4Hvwvz", - "marketAsks": "6oNyVq4RSk1Yri9ECczN6PUV7Mf2YRxSiEnXCpBA3Lzt", - "marketEventQueue": "6M3QtwATMcxtDgR6Vf8bidnSipQksB8m17fRLuQSXEgZ" - }, - { - "id": "DkEa1hKCyWaGUzpZGi5iRYNL9CzzhDJdUHP6pHmfmrw5", - "baseMint": "6VYF5jXq6rfq4QRgGMG6co7b1Ev1Lj7KSbHBxfQ9e1L3", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5v3VGHczyawXLfLHjK1n8nysSuCdXVrKkmSxz23kRU7E", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3KKpYy23gCeFAfSa6dYHyJVPL8mjFt2yUFVLNCTLr9TW", - "targetOrders": "Bh2yWp1pu636qxA7NMfb3dKVhyyLtjRzAAnBZtTsv5pR", - "baseVault": "ABotYfM4icizvD4bcN57rStcBPowkJjPSAAyXCmMbm5o", - "quoteVault": "FQ8zyPBLezkYo1ZKqXansNHbJwX5PEhZxo6dVQJe6Ttt", - "withdrawQueue": "GNbeEANgazbRo75Mq4iosBEr59aEexYTiMbJ1iu1UNob", - "lpVault": "EHp9pWRacH27qyP9GTgfVywpiX5kbRssx2Tn87P5vovB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4YQaQDi4hte7Aj7GB3pfHXjv4WTfn4eRDYmL3AtVuC8R", - "marketAuthority": "6ku64ETcyNy8PL2FvUiB6tmC9zV9AU7aQTxPnLUTt6rx", - "marketBaseVault": "FYLPeULn3Q5atLd3BPDMWmFphRyM2voivk2f5P6PtFKY", - "marketQuoteVault": "3GXSHTx6gFxvonWT8W5a7stK8px94Qa7VAcsh3iGFzwC", - "marketBids": "9qPjs8vW4UjQSoXCiTppgHaZEVreLDUVPBmqETxcMizv", - "marketAsks": "B888HWtQ1nVNmq9R9FcV37wfG8SbNRfz3VHunzny8XnW", - "marketEventQueue": "7Uq5MXABpbNDpXh4dgMtWancNfYb4xqf7tYy2cdFcZ1Y" - }, - { - "id": "DLPtB6V8sT4bbEdMwbnVPe13PMX8vsgmuD2ENbjYPxGn", - "baseMint": "Code7hV6DaK5Werof8c7vPwBxLvhmEWVUbU2AfhBZArB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "drC5W6QK26kCNqwHXcKLvQxT3n3xP6iAW7NAX2kY2Eh", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "G9gfNCwLBeob8SoVPQ7MUewF1ikjrUUueLgeCq6LfBdb", - "targetOrders": "J6gXcFpARbYcCdPqpwaGzyGwSHCcFdgb13KKSMCYe3eh", - "baseVault": "2rgtjG2degxvdqBTqhHuMLzYzpBknMhvxaPcSEVoXgF5", - "quoteVault": "A6ETGyphyeas32NkTZxqPmgeSvPxJBHC6DnGPayCYk4c", - "withdrawQueue": "AKBSvrqMKRtuwkz4dBzuWv5iMdH654hrU6AZvBUA4jNt", - "lpVault": "FyfD5Fmta7DfbB3xYPvzJPWHQh8xqGqwQXwZXegzmiaC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "E6VQHawoPZXNWJsyZNM4BYCycpgBE75jBafy81DmNd4r", - "marketAuthority": "EPwy7rdSm2HnnqmiXaLU5XzkkhQdqNdaEfU3TcHHmnue", - "marketBaseVault": "96mJHBHdP4voWcNy5AxVPZJAHAvYoV9bj7DiWUc1wSBS", - "marketQuoteVault": "2jR9QBMxf41CC4E41wckw151oNMpqW4eoVa4aDsAXaoo", - "marketBids": "EWyAKSZStPUeWR7w7PbSn4QoWixPH58HHX3LqtP1Phhj", - "marketAsks": "9fpMTMg31FP2jLomvBBrFJxGAAVjJ6JU4Nk8Jyj5LRja", - "marketEventQueue": "9Tpgt64n4sSkLPKMcV87sgrqBn4P4UJJNjVe9hLkf9NT" - }, - { - "id": "DmLHcT6ntudwq4bkUxbkE7ZWNDCEWaMuQAwrQPQTTMwQ", - "baseMint": "RLYv2ubRMDLcGG2UyvPmnPmkfuQTsMbg4Jtygc7dmnq", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "5m2eRqPzpjbVbF4RRD8QR9rqQQyz6Kk3emRrgqMVsCUG", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BLgj8tUSZLFMqBTDUuuyAQtsHUiCq1MMzML4pSKDrmhr", - "targetOrders": "CRKeVE5KcbHRuUPbgrCgzAXPGZVDuxc5mRvwdEyEvSDg", - "baseVault": "AKWkdn9b7Z1vPZBDHfqETr4sodNnLRoXHepQAkyoVzi9", - "quoteVault": "HyDfMNoBV8QUgGuv3GnYAHtvMtc6tYysv54UrKF2caw4", - "withdrawQueue": "CxeHmruDbM5U2UTcr8urNnJRosRvU2sfjUS7feFPVkUe", - "lpVault": "9h2FDMfbdkxFWPeRF41uBEo5EbHjY969YZitTyypvuAc", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "D36Ao9RJp77hbfkv9iYS4eaHPDR3AW9mhtahsoej7FE7", - "marketAuthority": "Q11FqKrnqyW2w3dD7g14NfHgu4Knii2Y2ERrVrZAkEU", - "marketBaseVault": "DYmoSNjDhgSZ7marAgzQ2vLw4udyDe3uPZcugmPzVukZ", - "marketQuoteVault": "H1RWWsj3Lw4e7voQPiV7da7XNRFJBeyEhnfuFUyGRMdN", - "marketBids": "DStjgLbyXfo7YT6xNub5DxYWHPShsFfkPtkQfE1SvbmZ", - "marketAsks": "5qri3JdVNCsgrJ88A5nJZJjJm27kHqNdrfQEwFN9FmZd", - "marketEventQueue": "CpsPDWYYmwJf4kgJnn8XHSo7Wm3cP8mkPgsv9XwXNdNP" - }, - { - "id": "DMNKNLMnZcyS7BiNUDnFXiGo5r9E58rES8QVi1jt1ZGZ", - "baseMint": "DHVUoxNqv3D7EgktBxUsxFF2Wx83hVDmD2wBBpUaw3jn", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "48TTDN2CR2wdhfVd2rR4yTjZ7Z7N9XCh6k9AGE3uZL8Z", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5caTssEUFY3Z14oFT84iAbDa3xf7Q1hNNNesFBq43uTB", - "targetOrders": "4skcQwbyLEjKWTpztRQ32buwptcRWfNF7qer1kxxWDHb", - "baseVault": "Hx42Hys68GGw5Nb4upf6rWhaPr3eBdYV6uGTPeRPSPDh", - "quoteVault": "843oXQ3dVHSjDjFqJsVeUYxUKM5fiHh6QUq6AMoqbH7Q", - "withdrawQueue": "GZmZyE45PUXXLR241LJvW1WoaMQnNyNEjjQ7fbe2MHUU", - "lpVault": "5PzxHJYhuygRp9Z72fw8r9ESWM7pxhxdcJeYsFZoTAB6", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6VUjhwMgqUdwg7V1d2CEtELcTmHZ4HXUCKPWZkxzkYk2", - "marketAuthority": "2UQfT9ik5GS7KKZRRf8khcBA3i4yuxssZAPFj3v5ah7u", - "marketBaseVault": "7mkRK2U9bXhJBZLhKHn1iCtRycqVYke6bN4wBhUwVPws", - "marketQuoteVault": "3918YbEAKSUQuUvtXEMFFMWhM5BJHmWVaTQCGDrauxyK", - "marketBids": "BAizpnjFLCFfYotwzrFaGGRvKZ4ZZWoEYy5d3up8u9GB", - "marketAsks": "4e7HCq8qX1wE48HThLhfPc1DP9Kjv1ZozaKPQFTfou35", - "marketEventQueue": "4xQdfpYeajMp3cN6ukEKEzALgMi3sbZ45PMroZjeTYJd" - }, - { - "id": "DmoTAHZ5PZNncpi4whhvBwXctEkzo9BheAM9ydMnuN3B", - "baseMint": "FDWmQxD9hQruYKtFK8wt6UhKGv6frPvU8EhjKiEPQoyD", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3qP5FHEsQJtt6mM59CA5ibmCEh84xYaFWmrBTRABtdDA", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9kKCxxKcXKjiNCggMftvzT8Vo1WQpNMNpNh6wAGeV8v9", - "targetOrders": "H5627tXZgyjwtXyqUd4c3bPjVV75PBEdNWegw8n4zuTS", - "baseVault": "GpS17rm1xPZSDEz9M7Ref3sXWg23QuUoq99pQC9NLvqd", - "quoteVault": "7gECYAP9Hxn8AziuAnKJ4FgFeTv2UvoZwQFJpsxfDUYm", - "withdrawQueue": "768r7qwhu5ta5mMmnd546u1To3zMKoecV572LRUfPhNM", - "lpVault": "EMT31qesCYEtnVxLGp9eYboVCM7s6HoT8UZLDKAqmW8G", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EaCAHWp27nLnvRiM5CLtMuGTrc2UWmELJmX9ZLgyn8ER", - "marketAuthority": "B887a5XMopj5dnUr7PVbNzQQ3aX3curdAsS2vRGho5CE", - "marketBaseVault": "32NQwJn89CUMiUP2kpAhH1AHieHFmngMjaM7PoL3VADm", - "marketQuoteVault": "2KrjCHLuocgQgsxfantxmN2EL9NABWX61uaAsE4vW5yb", - "marketBids": "2YxRGLX73LLBdcLQdqStfpMVoiCx7ecvXfE3GVQ8wx9H", - "marketAsks": "DaTsiUqeLkHXuXX5oUrqYMTX6QcUsrJyuoj3apXpGTxp", - "marketEventQueue": "EENyoU7mR8diAL6VhC3t7ykt8RpqfCRCAnwhRxF3Q8dF" - }, - { - "id": "DN1Rqx5AE5jHV8pTPiwUcSYVAK15YrLGkfVdU8GxhWn1", - "baseMint": "StepAscQoEioFxxWGnh2sLBDFp9d8rvKz2Yp39iDpyT", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6wXCStTxZTkz8gv3nrS1adJAKitUH6TVVrBF3XETGtKy", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2bzaNYPMZXAXZRTKMPicB76wwfiuZrvxo9qbXvzgg4Mh", - "targetOrders": "aToiSVQym48z5LaV9dsfHtqAWLRnWudGuSt6FxbTj8r", - "baseVault": "74cQrLwSHqWLe9cbtZsq9Lyc1hoeLkXjzXjpGitijqKX", - "quoteVault": "Hr7yHnCCWH7Rz5FDc5rKMRga5v4zLvn4r1s9ZppQfM4H", - "withdrawQueue": "7skkQNxqSR6xX4adTjgTtjujW86Vzjug73CyXSfbaQxD", - "lpVault": "A6KZ7EzDg6SLycr5CbSXyKxHbaswvb8uEGt3AYerKPmQ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BCnac98Juvh67YxrTJgB2yc1k5PcMLDJrz9Y3AWwA14e", - "marketAuthority": "BfQGbUZ3oF9GHfTvhVEf1DXYKaT6KJ7HP2zpRiw5q4hY", - "marketBaseVault": "BVNZarvqYtyTeTc2zzEsfqopyC3G2WvcutZajLqXGbyu", - "marketQuoteVault": "7rqKWgHdjokcbA1mqRQKre2WcxUyinUpgihvW5h6Vro3", - "marketBids": "67gMCnsgDeWeWwUK3vgqXExXYhsnmcqg7KWQoCkZAfzw", - "marketAsks": "Hu3CF6B65uvt4NwrpLLsVeRRGpkYFxxnyMpdGNowiEio", - "marketEventQueue": "9PLiK3NgJN7eaVXTLAFNxmtunqWojfFYZQU52MMxNHWp" - }, - { - "id": "DnFtpogW2MwpXZTiwf1PQ8xAoZYfg8KvNo27isoSHDgG", - "baseMint": "FDKBUXKxCdNQnDrqP7DLe8Kri3hzFRxcXyoskoPa74rk", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "w65LjidKx9Cqf4Ba5bsHvYqt8jQjG4Qqr1o8138xMVF", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4kUdTiYY3brFVWuZ8dAD9pUPWLyBY8x2MHfpZhwurf1F", - "targetOrders": "21oYkmxKJxxoQVWTc8VMdN4McnXVEEFVpZqq4Qxd5JTu", - "baseVault": "AKE9LpXSMg59ZYWwqUxwxUbfmBYYHQ1pvzyuE7Bn56B", - "quoteVault": "8hPJpLkjSBt5z3MDV7u8Hqw6G7FeBS8KBy36fz9F8G4L", - "withdrawQueue": "7n3cfatbB1ee953KXPzw8Pk7wR5Mr4FqL7b8MSfueK1w", - "lpVault": "98KsmMDtNiYcuwLDrR4Ufw7r6P3RohJXXWwD8h7fj5p5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7n9J9D41AQbCVLrpQRAM6kBnV14ADFWX8eQKD4xuYKWY", - "marketAuthority": "9Jr9dit5y2F957UwTZWpd388Hb1bEHsgkQLFSziNHD7x", - "marketBaseVault": "47mfx1siKx84ZdynnQFGdCkiF1JAcaTWXBn81UXbKKMJ", - "marketQuoteVault": "BsT5G1GYSj9WPW2jyWuXpg54hP8PjgRWz9iZkC3y9wSq", - "marketBids": "4aLexZHpnD2BNhEDi56wEuFnrEqe2FAjt8AgeguH5RDC", - "marketAsks": "BPUfDdT6LqvPWHow2bsH8K9B17ugDoWAiwmr76C31hXW", - "marketEventQueue": "437FShmf2PMpkgz9HJ6byrzTRRgEyWfRyrXNzGpLqaAK" - }, - { - "id": "DNnacjG4jVTxoZFDuXHGSx5EeExoDTab4kH9fyaauqiC", - "baseMint": "D4Rn7ZqJJYW2s97PinbRioZDFZpEHjkxE6TPVenTBQVa", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "BY8NteC9EokWRXQZF3Gs7fPT73qgBC3CwqcXV5DpqZ8M", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7ZMDAzMkeCYQFN9tNUZ15Yb1StSmcxHhYLCwABhic4Dp", - "targetOrders": "CsDeSoThW5GWrSWZSaZ4B98zEgpBMyxRQ8CciMhTSR64", - "baseVault": "7wSwtSMJVrhgiPSkYuWob4YTTD8FvBXYiwkDJutr1MJN", - "quoteVault": "DXK7xu2AyXRrxQbmREQcTUUBN3qkMVXDAK81FpQcCgiU", - "withdrawQueue": "DiKJSbSBFZ6rwksdad4dFNR2dLVmTPrMg8unNFkpG38d", - "lpVault": "FKb2D7PPku8VY9Nrch2fMAPH3XG42CGEZRAB327ys7oj", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "75z4djwiCc8ZDMrWFV8WB661VWkC2jNePZfsS23PFjfp", - "marketAuthority": "H88isE61PUqB9GJfEaEDcciSwxL5mVzqweoHwPtrGVuh", - "marketBaseVault": "7TNTdBs8eALVuDsoCdwtmayarVTJNQTcpunVUtwWzceE", - "marketQuoteVault": "CThu86xFPyGq8HSTAQhyaKDq9y26ACD1APq2oKZU9vy6", - "marketBids": "2EppUgnBcVJuhEsmun1gyxYnpC67Y3UQJH2Gc3hYBxDR", - "marketAsks": "2zEdMVyVE49wD1Uu71jTd3kCLVbkSLMc9DLQYpDcmkGu", - "marketEventQueue": "4ak19fhndXouaLhbYxwUofzZiKNvzHWejX76G2FoJr1c" - }, - { - "id": "DnqYSxg3EuFKrKekTbQQfF54mDZUoBBUKE4LiCeLcsTU", - "baseMint": "GCVqke1DoiffLkgxPjmYrbjc9w3uQXst2phDoxu6NL38", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6CsSqNhFmCZgt2EoUuDkFtCsNmiH46xbjjveY1sCByCT", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AE8KnC29bgkP5pzbjVddpAaXH8JLwweX9JHDCf3fR7Jt", - "targetOrders": "9uyD1WkkjU8nrNv1bAnsqi3E9DCiNEFRkKqvv5gZxv1W", - "baseVault": "Dw3NcbRbKYfVNnwG3iCEtcp7fGeiezZG1CSzcWLoS7TG", - "quoteVault": "6T1yq9UGi645fRJu2A3WDqtrPvtHh9LWpow5J5mgkhJM", - "withdrawQueue": "24Xfc653GRFTE3nb3D6pcqTwUd7CHsvudvDMvbxYJXwV", - "lpVault": "CN9M8kD8g1FCpj1GAC2cMQ51bnMks7d5sFoMLNyUfVYY", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Ha6cvqjcA2i2WVtoubYHe4tBFjDpWcjsSaFudazuFHCJ", - "marketAuthority": "8Uu91FpjZxQX9kXn9ZxRjgHgCAHnAMVLExKe8NKihNk2", - "marketBaseVault": "DfEFdybUPxwLvrP5kHUuAtHXndmEGNBd3iHMnrDtzn8g", - "marketQuoteVault": "pnYsPxCyyCraAyChVo87x8W5PmTJPxVGC1xVe7K2xz2", - "marketBids": "yGLuoHBN5DeVVkSVK4sWEkVEXZ9MsCBUHLXN3yR5tAj", - "marketAsks": "AzPVbkcfyCRcEewr2KtXkwF6QjLt7iW1rs4Kurtu6U3M", - "marketEventQueue": "gdircbJ3zuvjffWg2x6xwcCxzcvE4K64QbFNH75gimD" - }, - { - "id": "DnX7SWzhkdNQ5RdtSFZB5eFT6JCMabTkDTRhEKMi9vfo", - "baseMint": "Frog8vt6gmuuUuuerd7ispP6yavssBUtMpEP5DCEuUgD", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4zqDf3TyUNM2KvKo5yYDTtFPDgZVY5chscz9tK226jPT", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2gZne495BZY1oNcCXguEGtZYXxHe8DcZf8PMpF9FszwV", - "targetOrders": "B16XGeZq2r2RV8SqMkDwuszgZox3VJcEpDMuXAn7fdC", - "baseVault": "8jCEoFmG2dAHGAVh3Fzw1Nje46iHnVEZp7bhgMvkeff3", - "quoteVault": "E2KPyPd7vymy8FeDvrkcd2GaCK8Uk7637Ts6Gyg2sJwg", - "withdrawQueue": "BKQmqqK4a6FDRhQhE6GkQ9femHSuzqQFMApNzLhF8Esc", - "lpVault": "C7nSqB8csWyjA13TV13Lb7KvDzwZoA1Sg2XiX5CcFZ9n", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EzPiQS7vhkFP5RsrczE4VeN6Uyfj1U8MpkaDsvqC6oeK", - "marketAuthority": "9a3qpcCLTmXsTkJY2vyrVarHnEgqBMZMEFYfDDq8RWWm", - "marketBaseVault": "Bo3Qmbdiu5zKjwS6u2DLQHF2pizzqesYPR9mwhjUvKm", - "marketQuoteVault": "4o7P3j8ZNaEajE6fadxUHt8epaH9dHFjYt5NxSfU8SFG", - "marketBids": "Dt33R4pb9RG7G2BhELr6iU74MomQjV4HeQ8gZVYEuRmd", - "marketAsks": "AujtKq4Poc3CN6VFGhZc6jhzW2ozBWdvKh58xARvCxr1", - "marketEventQueue": "8Beygx1uaTJ73M2KVDbtNyNLCreWDZWo9RQTGC2CJqGn" - }, - { - "id": "DoK5Poz9Tiag5zuJM7qvz8uAmaqksiYeiCVJa7W3V6mE", - "baseMint": "5yUX1XpjLSTDyNBTQ3N3oYpu6RH4gckqnSS6Ecg79fAL", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EXwwaHaX2EWnHEZ9BAZy75byCJ2LvXTFvazJ9DXVq1JJ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Hgavy81iQXNvSbjD5UUFs3Jr6x2SzezUHj7S416gVXCF", - "targetOrders": "9S2VdWq49Q9VkcHKJMHzDzCWtdHcxLdFpeBYvamNRVRo", - "baseVault": "FXSqfxwsEQVYLzcQNjLnLZ9aNEkYZW1iPQxXpRUStNrw", - "quoteVault": "9nqbcoc5G1oqd2NWMfAb5xjrTPb65EdrkhinaXavqEzy", - "withdrawQueue": "AdJCTvQo8dNejVGzf5BY4YcQLrgwdHkXCUKJGF43vf1k", - "lpVault": "2DTYhFcAK5iNL7HXerpe6aR26565RQdDsfN2CpapuhWQ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6VJHzMtc7hC9Etjn38DUoL52xLNzQJcp11TuN5MzMYzq", - "marketAuthority": "Ai33aHSN5qfHq3r5kHgtZUCdR6TG4HLNwUkHgFZhDbCT", - "marketBaseVault": "F33SKivEZwPkt3obNbQNuG7mJj8MuX26F6PRpYyWV8kp", - "marketQuoteVault": "7cJPnNcsDWaJenasksoLymWgcuGvRAHrLwL5mGbvYDqv", - "marketBids": "Hum5ZgvHSK2FGsG5fA5RAXu6j8AUrhdq2MTE2vNGghRa", - "marketAsks": "6mrACXvp86pNDfbUy7XKkV4bqXixCNrMeqmtDKqRuNA9", - "marketEventQueue": "3mSYFZaSufbfD43ivMTJGJ5sS5fHNGKXFVhtuTZnxte5" - }, - { - "id": "Dp9LddSLgLiqofm6RJgcZtmSbYK7WKU3cxHoyaJGXvyT", - "baseMint": "5j81MNxc3ru546HtUKq5b3qDg9qmqATZz89MYyKhdwhm", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "AcLR7HRbAaeLbo6puCZ8B1abkBW9HUFW1aYnArts3hoA", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GDAwsDbLapjrxgxueBSwUhkspKfLj3jf2qiZUJsMErgL", - "targetOrders": "9gvP12WRtJYngtEZRG6SaQZmNQqGRsy3pSnoGNp8YkyA", - "baseVault": "ArnMiGfX3YQV3XgQZH3ddhrDU6acHdPbXK9cziQs7wRx", - "quoteVault": "G6WaL5hJ21NSTV2SLWy6YzYfPBobezX6R9zyiurbvwYf", - "withdrawQueue": "DEKQ9VCPjUkGdv6BMRg1TuhUAxS1GMauBhwcMnrwtpzL", - "lpVault": "5KzR2biWQupGmTTCDxxKq4fVXjJpsm8DgRMgeoHhU9Y3", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "F5MBSXS9W5U5ZmAQVh89aaDiP7p1wXzRf28ShJ15388V", - "marketAuthority": "8mC6byMnhww3kT6jLFC4vkcGPYc7WbJdfEN8sj6Anur2", - "marketBaseVault": "H4c9XkpSc8MQgCEknbUJkHifJRKFo7jSv3aLLPQEEwYH", - "marketQuoteVault": "67Srpf3DVNkRA81mWdCh7ssJ1MKoaXrqos3fuHzbXZAG", - "marketBids": "9hCSCoWxuiKraYkPo5UPNCKRtwoafW3G3rx1VqcYVtFZ", - "marketAsks": "873ajjKsKD8aeA3v3JqeceU79YdFeEHS1vJ5VQPXoUMs", - "marketEventQueue": "BDWL1hmGdBRcyefZAMrHozSkcg2bJiyV2FSWQmFSUoRk" - }, - { - "id": "DPgYdwgz7ZytfrzLeRYJwXq9JGeskaXTRrM8biFEnLs1", - "baseMint": "66edZnAPEJSxnAK4SckuupssXpbu5doV57FUcghaqPsY", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2HEdj3PkxeMhkf19TW2pZbV4bEFJ5fyZHHrswzUZg5VL", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AKtJJ9bFGcbz2pR3sJMjaohQb4hG3xjZYec5NzDsyFGC", - "targetOrders": "5WqpUFtLY2Sdd7GZ7j1auER1yQQqjHpsGqV96WYnSxwc", - "baseVault": "6QevXopZNdKS9T5esqRjvXN2WWDBvCRWXE8wUg2Kovt2", - "quoteVault": "EnRUfkGUp8bhc5u1sV7nRZ9U5b6ME5k9naKrr6CVAPr4", - "withdrawQueue": "4j5puBzVp2bR8cq6RMYLPyRjMLqS38rtUx9YTyi96LJt", - "lpVault": "DaX3FJ2juQ1P2j2tpeVkT2iWpVoeWPZ2FJGCT7EK9Vxu", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "98RguBcn2ANceoN9w4XyNQLMo3TVWNPq3BZQyKFGY9TG", - "marketAuthority": "F4tAij2Eec2TEYycHW3wm1s5noYm91PUKXrCYwh2KRwg", - "marketBaseVault": "GMoYuWQPiSvwNeXJuDnSX8x6gHqNiQ5nBTaD5p25uuvN", - "marketQuoteVault": "8rQXjVQ7ZyJVUHinBViDLZxb4bGX63ko7vPJsyjb4utb", - "marketBids": "BAsqzm6znMTKUQiVJ9sf3QEcuvQ2dDGbeEyBSRtBjaPg", - "marketAsks": "ojZC6zYb4BirHc3xDCViaQftyvcZXYMWC8ZjoiJk53f", - "marketEventQueue": "JB2L31H7xKZQ3vnxRZpVRKedaYps8Vkjfv76tYZzaFsz" - }, - { - "id": "DPmxGZ4RMuM3xb6kkv8jfZdTiKDzptHZiNoRwYf8WYQE", - "baseMint": "EFYKDdppK1FjixaxExpVhoTd8gtAmncbhQYruzWyG6Cx", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8XEd5GxWmvjUKMMM1S4yEqr57vT7JjzyhGrjvhV7fwsK", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AUqx8GFcCf63cmjxs6hTeCCrxLRfGi5MaDk61k53LXfM", - "targetOrders": "ANmu8kUfXKUaTrLLQVLmS892vYxLU8tg84KKNmVNs8Ph", - "baseVault": "1Edw2DsenZbMbujyqjM9oVuuh7oAfwK91xo4FeyqXbE", - "quoteVault": "3hP9WCQUMnHSpaKbP5izoW4h6fDWwHwCLsQZ4yrdptts", - "withdrawQueue": "D14ouUJtF8isc2ZL9VTXk2DLMGXJyse3b1HUYmVbU5dN", - "lpVault": "6ZpHurLXptzYBV4CaVHjfENyNHefESLApRsEUn8FLhV2", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8nTQLcukiGQEQ1zguvmtLx95VJmZm5WxRsdBneaTGVmN", - "marketAuthority": "Dobb738qsSamsZedsJFimp5nnF36s243d48TxSg5ZBwR", - "marketBaseVault": "S7ZAyjWAfcw6nAqaCpXE5EmmnrcL9UYzCSBAKfdFFnZ", - "marketQuoteVault": "RDpy56PkddRAxBVRn2Lm7SsmBYTcJQhPvQgKtJfzqbV", - "marketBids": "Gf9xmMknxtkyjUCeb17uNe3JFAzgiAXygpyiFrnvVj1m", - "marketAsks": "HT2KsaWnmmNYZhWb3aEf6G9QoYsQ8EvLS2PvxnCsEVwi", - "marketEventQueue": "3P5RZ17pWZzCGWz78Xq9Bvqd6Tvj76TvJrUVYGQtNRZH" - }, - { - "id": "DpNCmLN3sAN8DGfZsczBGURCQkZMoWhKTj5MjCiWt8i3", - "baseMint": "PRT88RkA4Kg5z7pKnezeNH4mafTvtQdfFgpQTGRjz44", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CDrF4dHVNaAnADk1whaGqC5ibh51UXZ1kRUvrp4ina9s", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "57v4poPyBhYKuEP7ep2eu2XwpJvrXDMmfysPJoBapBR8", - "targetOrders": "9wNXv8ZQKzuycnUj5U34j4636rDSnvQcGpSAxzRxNZSd", - "baseVault": "6FrCEW38C6yi3BQuww72iarsBq7ru6TjCGJ17sfdqGXt", - "quoteVault": "A4AX8ooPaRSPGF2YkssB6x2Jv9DEjys3DBjUzEmQPcrc", - "withdrawQueue": "gVtEPwY7pn5maDnPrkqj97tZzYSckVzXU3DqVasLjEq", - "lpVault": "GuYc4Xyj3VwSa2p7wcSiKVh7PbpyHer6RiNoKPMNuHBL", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CsNZMtypiGgxm6JrmYVJWnLnJNsERrmT3mQqujLsGZj", - "marketAuthority": "EhxnzWjqFnDCr7XxC2CCXDGfb5cVz2hGfQNg6nEGgYQJ", - "marketBaseVault": "ABgSggPV2D3zbj1NaT3GjKnHdCkdRnVNPB5gzGF44F77", - "marketQuoteVault": "JxSE5jL1SuGu9zmkq3QmhF93phkRvvv5QbLZpQS97YK", - "marketBids": "4bs4wRUtsuRdxYRkdwsG3rhe8gJd923wj74LeCt9oPbX", - "marketAsks": "5FGde3u93n7QRuWMZr5Qp8Zq5waH75bQmC3wQCmyX1jV", - "marketEventQueue": "Cm7JvoHbM73pJNdEepuoGcMjd4ck5FhS9Zssgv1orNxh" - }, - { - "id": "DPpdq8gqci9icg5va8P2Phrxg37E1KWAh2q2zi7adH4s", - "baseMint": "GLfMsvQiKxvAhf8h5vM3EUurjdvvgfXSYnEWe6UydoiR", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8XYewYYybnbz2SZ5tB4iVQSmDg6AssuMZELn2Moq9XLC", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "88dcBdLVkWCH2vDhpGaiyoTDscxzrGeJykS6nhMvcqdX", - "targetOrders": "Xn5NnFup95fGx4BaPz9ewCUtqSwmpNkdPnvDzNPaEvC", - "baseVault": "TtAkQ32ZdcEZ9EkQRTXdn9oK4SdvXzbmAXhWkWiGxFe", - "quoteVault": "9UWpLKBX4bGagBBuaCpkcYTqviauBx4XLPTpBEiobcX6", - "withdrawQueue": "483dwT5pULCstyqo4AMsRDAhFE9W8ai9vwqtRRY3EwJe", - "lpVault": "2UhqvJsV8YKEN2mrSs3ymouxgw73EumKdTkUxKHAP4G5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "nhm8jqeSxaLV3BP74aFYnzKec9hzrAL9dpN5tFgBzBq", - "marketAuthority": "BgMKAGHT3hi9z62S2RqM6sXmSg52fZ4Cv5t71WFHWS7Y", - "marketBaseVault": "8xu4kZGTinPmkfwS1Kq6k56hu8NEQZ3Y68XfmsWhDjE2", - "marketQuoteVault": "5j5UP8TqBwBgzDPYqebNmfVVaNKZ11sm3kPJLW8GXSZp", - "marketBids": "G7U1M93czi7Pa2fcFZnqTci6vWkLiSD6T1ST5QzFUmyf", - "marketAsks": "9Jt7yM8QT5r9Y96ht7aHniBLfVp9FqK3bhqfpvzCTJ6B", - "marketEventQueue": "2649p2pf9XFPQPAz6jEQ1duzM9MF5o4RmYRpyJLFPNUC" - }, - { - "id": "DpsgPrkujaDCi5CtziXgH9rfFNx6Yqs2igY1oAVen5E2", - "baseMint": "DM8WStrzE7XHLr5EeuE8693VAqAx3MiTcAqfH6WcsSSC", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "HFxZpDzZp6ojBjMei3pwSqa9r5e8xTdht8FeQZDMgkgt", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7RJFm6VrrXmVsgy1Shak5RNzEKRqwzDVRCUkX9kYZ8aW", - "targetOrders": "HaSn3wb69zywv563LxD1ZGM3foQvDy9e53AaCbzCgPav", - "baseVault": "8mvEL48Lyp96HEt2UtVsh5bEVsWb8TNZrE2V29XkRgUc", - "quoteVault": "Co7GZenAWck6ZH3cnkkVwScHX8w8pbsNEb9H9oeD79FC", - "withdrawQueue": "BETmzsXrxqnWZ9kGE2PCYCr2wJAp6muYXhKTgBmqeKga", - "lpVault": "5xR8TqXrBHgY4FWbkcKF2SNDX4yirb9aU2RHsyuFFccN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "JDohEqBnBYL1ScJtSGHW2hwB8V8aCMkU3zsmuzEddTRw", - "marketAuthority": "8LsDU7fdqxdKtpW2q33t1VPrTtjsYKsQR96wHjEfrZRf", - "marketBaseVault": "8pWw6mcUf1ZCepxMoSehBu1HbXgi1umoxhbVTrw2rGXr", - "marketQuoteVault": "67FXGCS4eRzoUB3vvKCTvLge8a7irW2wVgYLoCmHKvot", - "marketBids": "GYAZDrWZhDAr9CpvHeuYG9LKYZe7afaupHGR5AiM6CH2", - "marketAsks": "6UjGw1Zy7hKuLy8bhYcDmAm4MMP41qTEVoUwB1rRed9b", - "marketEventQueue": "DkdxfPfoaGmMxnYSZtwVxAkDC1a2ry92aeafrXb6ET6R" - }, - { - "id": "DPv8Gw4F3yb8ztJG7LrNuarwmv5w2baZy9wdQeHhc4pm", - "baseMint": "3xXMjiMyu4hthrVWmsxvBrKtehBWFgSKRnGB9Je4mmdA", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Bfhrg4PodmsyMv9RnemPxFUXQEzuFMzsed6kUsN71jqe", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HWybVNMHmrtjhFJicQaVu9to5NEaYWgJV6LggR9RtS1H", - "targetOrders": "Hrm9WNympgS3H3z1XW5XuzGSSb1vkT4WMbh54AdBjsFS", - "baseVault": "BfwnCuJw2TJFvctzcYkHtQFZPzJdHdMQ6tsZnMXGn66r", - "quoteVault": "5uAB7PpZgzygLsEFod7QPjG3fYueMs1CRinAmW3uSxEf", - "withdrawQueue": "9p5EgcVsFx8SLzfyPHuDGU5MuNABVsc2Bn2nP5djGm9c", - "lpVault": "79wP6WPiEcEkQ3EQcidrUo75CsT7eAJMu8DPFBYJvLq9", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5zhVvTJVLhbrDbJ9jg1YN5peAEmhscMRt7zxvzCKEJNa", - "marketAuthority": "FujoGnNoTLbFNRMsC5UEYxYd15Q9fPxhnW9FZCvkp4Tg", - "marketBaseVault": "7BGySeWYv2joaE5X2ssK7UD9yhbv1dDYyj8Ksy46XU6P", - "marketQuoteVault": "8Jchdg1QiuRUtfacjBdnSjSME32o8PAcpkLpeuGW2Q69", - "marketBids": "4tm6NiWjEtjG2a8Y36kEBzdki4v9LxdLUAodVpTPmvKb", - "marketAsks": "44iRZ4icj8gbcYvRiEJ3VfK9F5u8nNFjX9xeYSpq5TXs", - "marketEventQueue": "GKr6Qyur5xvtTUpbJzh1SJaXgnAGUVburxB4PQzoLZrV" - }, - { - "id": "DpzvrBB3d14scFQPaJkdX7pjcEXw9kve1D2gYMNFFVu8", - "baseMint": "6VNKqgz9hk7zRShTFdg5AnkfKwZUcojzwAkzxSH3bnUm", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "dsFCTELFFzBrkDuM4QUP8EcKgbx3US9VaQ8oPm8iLxz", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Do8Vm24tr5yJJX2L6GoQyz5YHKiYPwLQrZzGEndKriCX", - "targetOrders": "CxZYu73GjnV4LMDLXvKPLDSa3rjKn4RWrXf8TqJiEpkX", - "baseVault": "kcPwGbXhMHCTp6ZAzi6bRRLLVfYUpXP1RQ4su8j1cgz", - "quoteVault": "9A2bXsgS4LgpPPWFXDWBjfRXK7qNSSkLJPPvVMiR8mS", - "withdrawQueue": "GzEHpTjXEjDJLqPiBmsoAxKsMPjfsxJwUGmabkSrfexD", - "lpVault": "12MqNTgpBhCrkkyiLJ4a2HX5htb693CUkUUQBDbwLxgH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DUBkHgX4L2sHrakn8hGq7qEtN4trecM1V1BDoM3kAKih", - "marketAuthority": "982XdfFHFvwCTxyrgqUv9tSP5ZAy9AU2nPR3M3XWLdNN", - "marketBaseVault": "8VPyesc8qP8JuWw7oXj1LP856W4iGam7UggfW9b3eVv8", - "marketQuoteVault": "6nSmKq1LbvU5bi6iTtcbxdgbSF3sbNvaNW2KH1n313ap", - "marketBids": "591K9XrxNXpHztXEKvV2sAPukPZP9isjdxVTx5zaTiiT", - "marketAsks": "Hw7hG3cyQAMkXV5PkZrfhzMV8M65fxjezegFRJ9ecnx6", - "marketEventQueue": "HRgDksmmLPPmz6iFMb4x9s5xNxyQxmzJ9tJW78GDCHqf" - }, - { - "id": "DqFyoby5g1FZvo5fhmJgirBi5fGUiqtzFsygXCrF81LD", - "baseMint": "4BzxVoBQzwKoqm1dQc78r42Yby3EzAeZmMiYFdCjeu5Z", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GB4usprkovX64LHpoLXLfKKYaJfP4xk5bK6mfRbzusat", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GSDcjGB5EGfPoxfWgezT1HDmWDu4RNHoXSi3B8KVAtoz", - "targetOrders": "7XFcbXboPBGY57mDcHCXXrU9TF4rgiD4Q4TAMyf9wwzz", - "baseVault": "7132ASSpuRDtkTc3x73E6fmUyXcFsaRSTyxNefKPVpB", - "quoteVault": "AjhU2nq9BrBWTB2bGmD2eH2Wo3Hp3ymY3JHajkvfapG", - "withdrawQueue": "DfGURtN28jaVf2xv4Xj85U756bkpLpTmruunePzwsEfr", - "lpVault": "HUqMTGrHQFLzFU5wdEohL12d7CtGJDA6zhMPukJP2oZC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6TsoBrrCz37Ga8KLR6TUEh1dn3Y3yWBg7SqWZcukiLTs", - "marketAuthority": "5FHx63L9HmdERZQMDwcixwK7wVmm5Jc9ph1PdQXXbDrc", - "marketBaseVault": "4mRtZDGBQRsoKVH4Z2DnMU9vfyu4KDpGHpFG4F7rZok6", - "marketQuoteVault": "D4TahF8BHh1K2Et6wdZnmwP63H1PwUd9uFWVvhX6ZKMD", - "marketBids": "D6FdLdCsVNzRrzomUeaCMe7LhXR4myzNJgrWVtZz4tWZ", - "marketAsks": "2ZetYF7sXQGLad33dW3weDqpspydYMBGJWRAG6SqD6ke", - "marketEventQueue": "8eGkjeNmkpu58RsyT7CyUaHGs8iALSLAY26xQVGZZd1P" - }, - { - "id": "DqgfRD17ebaEBFExkZjSTCbeC9xfZLhYKUSiVxNJd4VZ", - "baseMint": "BRg8CLYEStYAFQad3CVMCYy1cgeuvUnarAZLV8K8Hyfv", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2fXFJAvAeW3eNGzi4J3oCf1jiufvgFBsYE5gEmMbXjig", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4bREsaes9a6xXRCajMkm6PK9VssTJ9WEevFBvmKa2zPi", - "targetOrders": "AapN4yDFcz4Nkjrt9A8n4tDabjXYQgDyks8KzoigEibq", - "baseVault": "6CCYoknrgFN1zaZH6pkdaVqqqik196ErdKbWJc9swZZM", - "quoteVault": "fUsgo5wwKwqrZ7fNPyVJp4V46VSkQPBzYHz8v6tCXbE", - "withdrawQueue": "HDkyRcx6bmgtJFbNUwGb3pPXYSHwkpUf5YLoF34vhALp", - "lpVault": "2qJu6HoxGBK6gHwrpkF1FLvub7XspR9QR655u8C2XNqW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GNiPY2dhydkUE662pyMUbfDLZ5MLvVKi7jzi2HKj7cM2", - "marketAuthority": "G9MtQnwif5aHYtRAtbbhHa8YsGBiKf9R1U4cD4BZK3F9", - "marketBaseVault": "BUnMiWHDKA4NawsnLnbDCZYa1Q8oJjzruST1bTqs7S3M", - "marketQuoteVault": "9kzihQ9H2w4nHfAesBKiRaMuRW7esnHzETTFrwKPkD2Y", - "marketBids": "DkQGQNFZ3xpkUaR2MBmzXFwg5EdY7NC86X5618D9KwHf", - "marketAsks": "HSbbFgsNwYk82paPc18gYQT3ULHwTfMxM99wk1NGZ4BD", - "marketEventQueue": "FwhfKKDJffH3BaSFdQqGF1udzF3T2K764FpDLdys1rGJ" - }, - { - "id": "DQk6AwbUfmS2rR7on7Edsc8LB1PTf5kMgXfLyajLkw14", - "baseMint": "37mG5XYuwMSutQnvERDUZqxumes5hYp89X2gpBbedpZ2", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AemCMbiHpCKNX5WbQR8DRV5ciXQW6BCgSQutbVmcRD34", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "38HZyriMium9LkHMpu7dmEhE2TwMLzJKjESxN7PT26b5", - "targetOrders": "BfG3ESxzDzf7XaqcHXr9EobbKn7vu3BxwdxuBn4WPP2F", - "baseVault": "4KDHScqTcVZ4wff6piS3svZAFPTHuhmJDWFaB3n1kHRb", - "quoteVault": "5n6d6AdGWDqHhAtrBdkpYPaQ8m24i9hUd7KCyw5PwLDC", - "withdrawQueue": "4hsZqfHTNKbdpctzPQi5y9Rqi3ob9q6WBXbXoWLZF7cJ", - "lpVault": "DGMN1Zotrf4dBG5hMLjZgPKTPQ7Xr4MUks1QZmCKc4JN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "41BVFzrwTZRABn14ZuzbTs5U5wN2KCNybAw8omvpKGeU", - "marketAuthority": "76FtkqShYFREmkjbzsjjh4zsxYaeRiu2qN6VQiaEH9e4", - "marketBaseVault": "4hGcoCtKEtJcBFaaNhK3FKbTNjgzRXRYC27TvsrfXzff", - "marketQuoteVault": "Fu75cKPReJcBcDwZmxwrqC96Wiq3dL6gMDUWNheBZq4a", - "marketBids": "AVX46CNJcSbyXuKGREXGHRTwjSJuQM71u9aMhcE5bRo9", - "marketAsks": "3MZgwGGTJ9bQcAHqYi7VmKuVysD5bZVf7r6vAGn1hdDs", - "marketEventQueue": "9u8NxTb9RnqiwLdYKQZRGpJCHrMeoytMt4dt21gRRfbo" - }, - { - "id": "DqMPkcRT22dPTTsj2rxhCNxg44D93NXiSBWiACAAXd2Q", - "baseMint": "ErGB9xa24Szxbk1M28u2Tx8rKPqzL6BroNkkzk5rG4zj", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "GNp5bH6pmTdAT4FFkF7BNEbkwAJKDTmTN7SKyjJX5YS5", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FDtrsRcf7f1DYKhYGEVR1WwVEh71aiSfxKpqQB59exZ4", - "targetOrders": "71YANt54Qi1bxy6roRAg7nTj3vBN3zvtbzqQyK4kF3qb", - "baseVault": "BGUZXmqRJ1yoC8gQ3iWUQoH9a6JwMgcs9GUoehTj5qVP", - "quoteVault": "CPLXnP3rFzFDAXrWPnKzjGfiPJTsveXHto9CQPfa9J5z", - "withdrawQueue": "94TxJBerJBRPtpWM9rEnnk2idT9kcreSv3XGotixxBYp", - "lpVault": "FT6QZi6e9ArxQmBSzgcjATG4KGELt9R1FRjjtJ8NQZzh", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HriXoSdPPwxHSJ68KUw4tPLogvFWh6WnwoLSsgvYCbE", - "marketAuthority": "kiPniQXgeHJrFWouxa8cuapwZ7wQkrVEswcx5ZA4HkE", - "marketBaseVault": "DmezaW7Q5TgUodKJ7FbZEYf7w5B9w3L7pzkMqfZ22Q23", - "marketQuoteVault": "8YvzWWQWNHTfpwbzv3DVxH2UxyFiC5ZuPhMVup48E8U9", - "marketBids": "HqfbewFNyAVc34LpT5uzLzqHTapo9edJXazY92KEBgwU", - "marketAsks": "BMDUB95xfoeC4Qj22Kf2fFPLWzcBdABswbxwFgTHYck1", - "marketEventQueue": "97Lqc4Zmbiij3tdRCsw1vjQiqPjy5XGpMB7fkKGmrUqj" - }, - { - "id": "DQqhxUM3G7kVs6UxAGvsVJ2PVywM9UXcaFHaspmT3sH", - "baseMint": "AAmGoPDFLG6bE82BgZWjVi8k95tj9Tf3vUN7WvtUm2BU", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "nJvReYR6dS3jsNGbJW4g2zxGMVa9CZXxT34n25nsLxh", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BES7sQJ7dLRpFXRNSSbX8KYbVnrSn6gCghU8opDVhSMp", - "targetOrders": "Hh9DUJJrXsZQRJB3XxCWuiQBtRBToNzeWW5B1uYtZbAJ", - "baseVault": "5JRXbAVbUJQkRSbjM2EBPscKSqjJSyjt8FxgjoHX9E5z", - "quoteVault": "3ioxsWgpnpMx6GBZBojaoZ7w8ob6kGSud5UkS1s7HrTH", - "withdrawQueue": "BH52XSi6xxRVD4cGXBpmxmLYg2v4bx6D9FaqsszMDEXv", - "lpVault": "3ozKfbf87Vr28G4x5QmEKzqvqLxESXmp46sgYCpuSrnq", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4iQ4BRcg6E7hNB384TzhQAjjVYnweMkQh5WFC2t8JNjw", - "marketAuthority": "Gq8bjgAjd3CRjbqLzPs3WXEgZ3W2xHBSPdZU6WH4y4Cm", - "marketBaseVault": "4ZX1pH9FtK61PR9XUeokuwq4igBPJrnDwB8wa3Rtizbz", - "marketQuoteVault": "GQnsLw42g5StU9w2h5UfttGKuXN1cq67F2vhzXwWegMu", - "marketBids": "3wsTixsxvBinYvnEfb3bgUQw55QzvF3WmJKkoYNuKyW9", - "marketAsks": "4RAJxGpGehdR8fyR2cavbGCd6x2KHFaxVtR1ZMoipq33", - "marketEventQueue": "5nRCyhMDTDiVrDrAGqykQp2vdoHnVrBkA9sWnuLmpjF3" - }, - { - "id": "DrnBwH6fvzgq5snfAhBuViRGoHz1oT56xQ4U7zZDvL8g", - "baseMint": "7TXxsfjYt8gR1XZh9vZZNRxhA4t2VxtYbsy9JWHRjFhJ", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "bhgVpYmAfvqtmwpdeEFtS6KSM6j6LBs86HSRdM9Xv1x", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9ug1C7XrJ4tyyDycoh6i4Aq6NA6trwcSgGfoFin9vNkC", - "targetOrders": "EXyUnUzquTNo7tf58rAi8ktwkgKTwp3JbVpC1fitYrNN", - "baseVault": "ALpbjgepfiM3gy66AfjsiKXt2xzUsMU6ze9izPLMJHUX", - "quoteVault": "4RRdhAfMPCxmGseDmFBYm3uTmD5BhxiG62aykb5ZMySe", - "withdrawQueue": "9kRb55gPViKoFAn25qZvh14zz2RC14WpptWMu3P7394X", - "lpVault": "Dp9D1aajHaj2RrcUhrEdmmuezbGCwonvcWMY99GsMyPZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7HZzFBKVtU2fN3KGmLCaL7WgnZhVgGYWCZVmBUYRjLck", - "marketAuthority": "7gmiG2dUEQSiPDfQhHyFGp4Yp35vyT4H4jNjjYFedn2b", - "marketBaseVault": "77jwbA8ceiaaWmSev7Q1hhWugr9fRHvqXcNL6aCKT2ic", - "marketQuoteVault": "6UuXHtv2Rv7KmKNYGCWud9DjVKzWH4LJGNGGE6H39P1w", - "marketBids": "AR5pnQcPdYQKeRVhPKWaRetNYtyYvpbGdwfcnK4nYwUS", - "marketAsks": "2gVT8gCJ8NW22HDR23ERPHGNPECbZaSuugM5cAmG8ka8", - "marketEventQueue": "BCiNBDYBBXpQqZw8mkqG1k3hxEiTgirMVvMGAesdk7fg" - }, - { - "id": "DSevcuMBhb5bRd7FwFxEcv1a8ttJkwjMTnkqi9kbiJ4S", - "baseMint": "6FLsSkF4AqQeDuqEmGPyBZvVebc4WWWntnZP2QZyBzG8", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "6qTt96zcCmAyHagLFhmHBbcvWGhRfv4ajmMvuUN1cRnj", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3b1vrErK7dUjBCTfHcfMRL2pXdZY71DbDCvh38zQhie4", - "targetOrders": "8c5T3kzHbAJ4bt1Nt7Z16R6C1UibnFSG6bzyKBHwFhYr", - "baseVault": "AcnFpK11tUG4hukfiBn5pQ3Q6mnihfdseRjzj1Xfzgon", - "quoteVault": "GoRmtiuap5wC1mxzb8YqeQW3AZeJvRrp66PNSKvTrnzS", - "withdrawQueue": "33NW47kFULwpbBuiFSRbJj1stw8t1j3P9d5ud7ChVGJn", - "lpVault": "6yT1nvgZXDkFWnimTGK6bQ7SLJdeu3q8GRJT7a2ZgB2P", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4j1C6pXC7fAW4mpT33pP8rr6fFDNk9McsdRJ8sz4zuwJ", - "marketAuthority": "7PjozifGWf2dHfS7zwKCpHYPJ1iNZD8yZqzEWEKHjF2q", - "marketBaseVault": "FFEVu3RQtGMn3fRHM9fCo17CXHG1roEuUfmE7WvRqXqh", - "marketQuoteVault": "6snZPpmh6ecfcKgqkvZ2nqyV62CnG96XBniUZAHruxYc", - "marketBids": "8QcKJVzxT48eFyw5nfntVva8kQaZoEk19YjzZESqs19h", - "marketAsks": "4Adj5ou3V7GjXbjchvgnDGdshY8HXMMiqS54G8WRVYh7", - "marketEventQueue": "FwwSpmYuxHxfrUj2XX5fAvcmCTcYCibQHP7QXLK7L2HD" - }, - { - "id": "DSTb1goZv9yGk6mav6CuSFRjjPbNATuxDw4nW1UyfkzW", - "baseMint": "B87r1e6PsztnS5fHFCHhQP86dtd9ASfKWCUytLBpudLi", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Rm6VuqxM3XaEVN1eHPmwYMuTeqny2BkPKdUwhA9J7CF", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BqYGg8wtuMa5p5jZQYDSAUC2Keu43TCa5VdNkFVVZd9n", - "targetOrders": "5fQpWrwtDncBtbDtm7boP9Mb1K2j84aqVP6fX18DFF98", - "baseVault": "3NAD832tBc217Df78dsig3P62y8uw8tfL9wweZiqRGhC", - "quoteVault": "DeoBdhbH9g5P8dB9XhkoeodjLkBQptCvFjAfR6YEox5x", - "withdrawQueue": "FZmAV1truBvdcwPDBLVh8qw3u4c6pKmKDd4eX1R97cFc", - "lpVault": "AsoD6f4fWnE9pT4i4MYoG12GCG5sGBxhgAy6adXLGzAy", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9Kg8QQ3DBRhYLp8tbZH3oRrTRdL7dqoevdHDK5nXb7JC", - "marketAuthority": "CEXhVa4FJz7ug2oxox52k9aDmpQfTUVTBEZZHSjiMbQo", - "marketBaseVault": "6rEVzhEHmugFe5nxzwndoyU5wbuvQCFGnQJBvCJV2ky5", - "marketQuoteVault": "5eBqvBKHZMAQprTeHrSuMKMGePjRMuUuXXTBYd3sztTk", - "marketBids": "3yXJhkCmQwbvavRbzTDLf27EydyYiCb5RHWeVbUfDNRj", - "marketAsks": "BQeF9SxAYrmBkxkzGveemGWoe1ntFL9aEAeMF1zc7Mrn", - "marketEventQueue": "DXDJLQ14LsDwMRWG6Q7USr6rB3V7NxXiYDgf94TYqDXB" - }, - { - "id": "DTbQwQvAvdhdgRfm5ytmJ29yJzo17JdpdXybShFJJ3Tf", - "baseMint": "seedEDBqu63tJ7PFqvcbwvThrYUkQeqT6NLf81kLibs", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5XwLgkEZYuMai7D5tRv4kseYjvisqztdotuWGvyo3aBn", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FnQUo9kdhiutXCMTbyDseRhC1xkLuGSfmHi6o9xHDkdz", - "targetOrders": "A3uhnNateaFrdSRNTj3XnERHku2uXCpHCwx7h2gn7oiD", - "baseVault": "5qrV3fkjRPGQHr8RztJZPQ6CcetBUSVFgVdSY3vCNuFj", - "quoteVault": "GvcZydhy1UZDKdsREj468shtW4e7GbJVECYcpD6KLC4v", - "withdrawQueue": "ACwicJMtBegCjaiBsN2hJ2mpe8AiFv1aAmMiJ5ihnv9K", - "lpVault": "4B39U8AQ663p9pFAfwbxkNS4jMTb8yyW5K3H6hKRz2ey", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4tmqy49UB7Kf7PNfpcsqqTVBWJ2LM3mLzqbSh76wVz8p", - "marketAuthority": "GNQWmxz297Y1HHMrfktCJrfeGzm4V8MLwTruhc2n5mj6", - "marketBaseVault": "Fb9goPy81mGBmdB4RHERLHsUKoPmQEH9S6hfpXW778zK", - "marketQuoteVault": "7rTLnLSX677egCcfgQxPmFj63Khxj3fMpCo13oEBJbbE", - "marketBids": "A993YmUj9rcRxzXRomB7AiafJdJwG4zCv3tJLYQmACJR", - "marketAsks": "8cT35THocz3mVETP13AnfVG3vekp62enaJmw63py6vph", - "marketEventQueue": "FSFxjGc8y8GTzJARjSDVM1iCM5By37KBfKLGPut9UyPZ" - }, - { - "id": "DtdfT1ynZmUF7BmgSxFDJJXmYH564uJopt3LENohfWSH", - "baseMint": "4JWktLr39ZbyutVnym7wKxV1RDoJz7ifDYxMUHDmAbPB", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "3diHfhWjH9ATFkcBdxsGQFWpJ1jaZVZjsjSP5uf627xr", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BTcdHyVzMAoQnttX7yXNQUGESnFcaEKF3vXyTg3A71ZE", - "targetOrders": "6wanofYAvvADJj4iiYSBzYooTNuAQL8bdDdCwwMNLASM", - "baseVault": "3pkyM46FyKecG9NkoCcTTPSHWqSvuhfaEpPno4cojkpH", - "quoteVault": "CW9AWXkEQoPyierLhs8WhMLHBibzTQSrdbHR9Zmyaigc", - "withdrawQueue": "6nSgWXDxcVAADqFfYvEZpubidiPUWaZaZWWJRcv2tttz", - "lpVault": "6T7hk36kwyC7XpFNwKeVwDLq1HmRM1CTPvDmwHHad8UZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Asf3bgFY7hjrEvaWcrW1PngYgoLxqKYQo2yi35N9ZfGh", - "marketAuthority": "BtHPB9yyY78KcspSjk4QF9gMsZrq3bFFzpcTJ9ZpXJzg", - "marketBaseVault": "F8aEPx9rTuWZaVLMuENgRBMeo1UDT1sj25G9wMTJH4RV", - "marketQuoteVault": "9wpvsbcfDW7u3TZHRTvum9EqCbxRXDFLwRpAjyDzZhRA", - "marketBids": "Gh1BdHSi73QGstK98rbygAJkGVRLNJRsAXwfQPT9E82Q", - "marketAsks": "CkAm8QB92qHmx5RopEGevyGH7ku3urtkRBkesrKQqVri", - "marketEventQueue": "7EFrYJByF6Nxc43kRG3rMkxkPMZhBrx6rHRyCVApyefQ" - }, - { - "id": "DTsspojpVdW5oKgC7XJ3818TahG5jPe1EDh4tpHLNiAW", - "baseMint": "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "quoteMint": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "lpMint": "94Y3jaf96ysGqebzRP71isD7RKxmuhkyXK88b16ToJhE", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8fGzBAEXkratQhxFUc8hh6WTeW5zPadfbK73Df42PY2m", - "targetOrders": "A2bKVEWmMqmPTFLAJERLvTryRbJ9nvUTxfV1kgULfSgp", - "baseVault": "ASKnVDWHMMhAp9sq9NoxdQg5gHj3htCrE9rHefbehrqH", - "quoteVault": "HjsRkZBbmRp8otBGyUoH5YAFkZQXmxtRwCwWJNcGaTyM", - "withdrawQueue": "TWWB4Venv1K5AGfVEBDorsouyjU6zneyt6APETJWZcz", - "lpVault": "FyHh9nFYKmPucpuu5eYSE7m4zdy7tJFkvzg6doCgd7AH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "D9BxjK5f2JBfiRnRiY8aGCJ9M96PEXVbsJo2RWSTbVbw", - "marketAuthority": "4uDVMqN48UnQW5Wxn8sCCM3o2avicwrmJETJzpUAEMrx", - "marketBaseVault": "Gr3ELGcnAnZZVx5JtgfwDagL1dNfJZes3DBhv8Ljm52k", - "marketQuoteVault": "6kxeXjeAPqy8cZa4KckKzGa1Hd99ppgtTeJmYJvZZBt2", - "marketBids": "ACHGYLvFAPQdVuVnaH3ANR84j5LSNadb35W7JY8HQVix", - "marketAsks": "5j8GZ5kmb1pAHJvg3smdGknE9gA1cF6desktPLJx9vHR", - "marketEventQueue": "41wY7BG6anKUumb3TYw5ehhnHCfXyy3JdCY49nTozkHv" - }, - { - "id": "DTVaZE3CqjdmvMQCN2hLzQzBNr4PfMrys4UH25khEo3F", - "baseMint": "5HHv6HAyBtaihyHEapCJvjE6iRbGLRmm3F5EZjz6EzHV", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FJVQkofY4bJTnh5vUxPWhZWz3KcwPgBZgcpqY44DieC3", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6W4JMYjVF5hciZSJqPTXs4Up89iqiCz5cBuMq7SmRQfi", - "targetOrders": "BBycbr46t9MceqXuinnjnw6WPNroSHuw4J5PkZ3xWVtg", - "baseVault": "2F1hFSSXjS6BnWteavUPohjqPGCziC16c54SSFMppBfm", - "quoteVault": "Ej8kNnRhhohupWN7ywde8N3guHtdUJYEZT1SvjXg4pBx", - "withdrawQueue": "7grmUa2C2N9yDjGoQH59j6dWYK3oVCyo69iFPKEtMsvT", - "lpVault": "ECcqemqt5yAAj5pewbiFmZ7ij9R7x2NnCMp5NEQKN62g", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HwQ4ar5qe2QGB3MBQqPB3DVi2U3FJSLBnVYcazPaAFyN", - "marketAuthority": "943AZjGUpFskeQEwvt2P1ph56QS3VkXTu8dMYWG3SwNv", - "marketBaseVault": "CsE963RnZFzoaYwgysXiY2FtiP3oBzhR741J5ikZCfc1", - "marketQuoteVault": "7DW9srMdL9is3BXyGAJWaMQjCubaKMCHvCu2Ebhxx77W", - "marketBids": "DAH9mKu23uFvSAnLYScJUzyGgwgYN3xLs9zoLsTRytmC", - "marketAsks": "CRFfJBtK8PKrgTUY86zr4c3tpwJ5Mhycdcz8hM9V5XUU", - "marketEventQueue": "Hv57ozKvqTKYZEtf4F6Jap88p8K3AvveTsvJ8fMBEZ2y" - }, - { - "id": "DtxZ22CwdBrPmE2pxJenETBeg9291JPQW2T8QQCnSFSh", - "baseMint": "5fhXkD8tXyDB9rmYZSNJ6LneLr2nMteMpCVxeDDEgXa3", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3qNAGmAvaSJE32nXSFLR9zBp98zpZGVebmCZ9t1fJnBC", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8Unc7ztWnFTC5nwVL3GkXKdRMYM3FQGwj7G9vCiS3Veu", - "targetOrders": "5xtv1n8WzUYywoho27Ham3zNn2qa92RXYZKeU3kMghV7", - "baseVault": "3CdGxZYQyCnPnZnoLse7yqFd2Hrp5eMtYzTiq82i8Usz", - "quoteVault": "9M3FLXpx5pkBqSQk8X7U2KoX43xMdnPZ32PouZLYLP7y", - "withdrawQueue": "8W3LqpANnRjdo7C4cZdULEHa1rF4uQXhk3yVUxACPn7S", - "lpVault": "3ickoLa8su6zMcUwiD3acVLz64F7G8c8jb8MLiihM6np", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5rc3qjJTh8y5ZsES3eMyTDpxtzk1ncvS6rrfp7Vg3w1x", - "marketAuthority": "7o52bWyqvSaLgG5YBrdyZRZVTGjMAjc2bx4vXvfJysWj", - "marketBaseVault": "8zVQS4sZownAbtixf4P19V3UuPdcNy3G3nMD3XGyht7E", - "marketQuoteVault": "78afJaUrpUQxJinRipNErKP23zUsnBYYaVQBJRjy5sKc", - "marketBids": "gVckkBzK4NoQXyWQA2ZDK28t3WUhGdhynR8tuDZ5VCt", - "marketAsks": "4qqTntUqYz43xTo16VJUP1uNsRoSa6MzUUbSyHyMHhfY", - "marketEventQueue": "7bvLqiJ9iUpHpoGLQJmg9M2zisHpHBdwznhDzXD9jiTh" - }, - { - "id": "Du1qMtbVmRv7fmfFQf7LjN9cWAbhQqBWrodh1175f5zw", - "baseMint": "DrcPRJPBiakQcWqon3gZms7sviAqdQS5zS5wvaG5v6wu", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BA9T48nFSZ86Mf1Rj4SwRBPRD1VLMdGHUqcxjuSbnUei", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7Gi5WjNfT2QGiNMA7cXbFGtdcFvjWVuWoAqd21LkXQ57", - "targetOrders": "5C9cEtqxe4mGzVs7dr44r1P5QMHBUKWNYUwR5qia5rbw", - "baseVault": "8f9qDuxaK65t4oSdhoiftefRYSJQut8dq6934wrAc3i6", - "quoteVault": "6nAieP2ttadAixgtFDo5Gz6BQqj7aQERWr758Pk6HESF", - "withdrawQueue": "6DDZ4n4v3L4ZQspk5ykb33YEeh4jkd8w8XKmV96dnTdB", - "lpVault": "6ji9xZSszsZZnyA83tRTXq1SoDgumNrfi7MgZFHNUXVR", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AkZyEsKBeGshQSqim8R5y8WsR4Wci9t1dGtisMdiJTqG", - "marketAuthority": "HkTq6Ct4S9BjqDqHHjD41hPjpZ8JkJ1oHWwgkJpYMFt4", - "marketBaseVault": "FapU27hhMEJJArrdbaCu67pddzwG8dVbukegM1SCVu8s", - "marketQuoteVault": "Gxg7D8jxVKXgMtdupS8MNP59BPQkgkMCuqCZY5hRa3SH", - "marketBids": "Fg6GZJcR1mfGuJJc1UHQNhY3QpVoAVEvUyFtu4WA1Nbc", - "marketAsks": "AQTQyE3PJXaBhemf3pbt5Y524V542BrA3yFZrjvTMR5q", - "marketEventQueue": "EryiBveHVoB5FLNK9xvp983RGR4pb6Qkgx91U1R1Q2HH" - }, - { - "id": "DudevotmDLN3KDHA1uTV1AyTYdwGnKUDFEXS9AXLjQ1z", - "baseMint": "Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Pxjdp9tJwouUT4c9UC8Lu6YCYuuvSHmKcFuj1GG8UkR", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3dTC22bCbA6cLr7npckvknxeBuUugqFRj6RP9jhrNHyE", - "targetOrders": "BEjcspDwC27jthE9Tm8w9oNde9LJUDPJ7znU1k3C9u3q", - "baseVault": "272j93C1vUfVyHDiC1FrcwM4ogUZasCfgyciUFNJUg9D", - "quoteVault": "J3SwSfRqHfWbcpHD2UU8VxnsFFpFQpFCxwUW4QUDWUqv", - "withdrawQueue": "8yXHrkaqExgS7VGHKHmhMiDEdECMdqTVoaWNR1gpwjmS", - "lpVault": "8JS1E2bBfEdrCMZ6jvCw5KF1xbXP5utuzHocnCGUeGjj", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6qC4GyqzzoLYeye9GKQyJTG4HjRMiq967Z1Jt6Eee8rd", - "marketAuthority": "41CWKMtDX8FDbuRZCRPmBNEboNWmPkZKePVQy3f2dhRA", - "marketBaseVault": "9GfyCNoVdnKaZDfC7Bema53NsVDuNxVfwh3F7LXm1hwh", - "marketQuoteVault": "FvZnJA8vYDLYGYNYxn3rXdPHSUJL3nWmr7kqGUvRpG6x", - "marketBids": "8Y7vgzDauidz65TbPs9U3aqcjUGEjhFVR172ZggxXSkv", - "marketAsks": "Yz2HZcXweCw6U4kBeMRcZb1ednJdejrvkBxhw45YPQG", - "marketEventQueue": "FeEAqsvJTf9dCB2CJsL6YQ5pFeyMyrWxd5VP5YRT58fB" - }, - { - "id": "DUPCtaZ8fcL2WbsoLYNWaC2vRazpNp8Gs9hEhHQ5axBj", - "baseMint": "m6XGr58ATHSS7BvThRCDkqnsAeXLhpammhCrDo1amxq", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3GFi2Z55XAdDYsuwiXLX8bvEAGKySCKVqdMSWUFskdg5", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AkLLHQiot7D6pZ4BDuUhW65YPiMgAd2GJ34KDyxD3f63", - "targetOrders": "EBD6sM8dxoeRSgYu88L1Wbqe8WTg6N1GN2RaAX9uvSjR", - "baseVault": "4S9FgXLyuHXn2XUKANr72HwDUpCVfNKbm7zYE8yJKM9n", - "quoteVault": "4gWJR4f2SyJGbsBYMKK9Me5mVcEzVU7gw8r7WpKHC5tM", - "withdrawQueue": "2w7iPQ4Nznop5FfYwiwVM61ficP4uGCZMT1VBovpsSh4", - "lpVault": "e4YNsdbS43tMm4RwumaVSTgqRpbEnEBz956LHFRiL4s", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "A16cz6xbCz9Xbrc9Mnn4RYD1d9jb1m6t2L1FRwwf9zoj", - "marketAuthority": "3BT9PYzbCbzeboF1WLXMPCNd4qy3iZxdJsdFdbBFpWNn", - "marketBaseVault": "GVBSAzSkGKi9TuD9wtL8BFHqDvHFptr2ko27KALCMu3M", - "marketQuoteVault": "4iaLCTFAHmScd2fk3xTJuZ96qsGTC5K19mvgxYi34f8C", - "marketBids": "8qpJ9uWj72at64WSRauXJRqELgPyVmpk15rqBvwf2cLt", - "marketAsks": "B6ktDq9dzMkZBwKLFdhqBXH9pZWM8GTNZqmwGZQz3DuP", - "marketEventQueue": "BywcfbQAReYKZrSzLELme4YVDdqsyPZBxSjoYf5uCxAQ" - }, - { - "id": "DUtMvVLAsvcPL8PcTnKLgc3LNUQMu28Ri6TRXKw1PRJg", - "baseMint": "GTuDe5yneFKaWSsPqqKgu413KTk8WyDnUZcZUGxuNYsT", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DweCgtgJBT9GtQsLDZK6c5zMSSHp85uaNLSq7gxUu4RU", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HmyBeZrSUN5MVnWE7uJn6vEckwnmiimTM2ZixDyJtLRm", - "targetOrders": "A7dSEJ3maZA1SPGRXHKyix3uq7VJvqDQnUZSW4GmeSKZ", - "baseVault": "U4UKYc3ASQygSoiM6YXUAkdZYZZgf8n1vnaBVroM59h", - "quoteVault": "6XTzvoYLeQugXQZ1i1oNidaPXT1XHBZYoP1RAm735Fvo", - "withdrawQueue": "9aobRK3fAirEsPGnw9beFXjPt1okKrsezahAMo1mjPoj", - "lpVault": "8NLVSauBMrPWZh7pgE49LAmjBt5zv91SvxsMGZ5STjd5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "osQxMajHixoPUPTRNpQfdo9dxLMphHVVJSfw1LjQxMx", - "marketAuthority": "BbzCsFtkJXtPzeWQ6qEK63v5GWJZVhanff8JyYziajNp", - "marketBaseVault": "dgzZfUr3WuzMqrh3Qo57CgX7SDwmR74AzDBqzU53LAg", - "marketQuoteVault": "8ePiC4ANAhc4R2HMiZ91kVQw7Vtvq8DdnmjpuTUhkvyh", - "marketBids": "C34rJxGFzctCbJ46kvP3vM3NzjWt73VCNQGp7KyDtniV", - "marketAsks": "7KJqvvUgypaycpUdTEWcjDVzsPBZuBzczuq7JoxSxfSF", - "marketEventQueue": "6m3n5Mhmgs4oxVpohKp8dT9n4WtpvErhrUprDbsMfdgK" - }, - { - "id": "DuYCVcXhgDUpwMPTLdGkdaR3jfSXTu53874mjayoMHAd", - "baseMint": "FoRGERiW7odcCBGU1bztZi16osPBHjxharvDathL5eds", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6nmWLEVu5FHEmyVdM1Arb6xAt3z5ZwkBRQ3mjye1cV6Y", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6DV7k7Xf63g8VRmdtU8A9KFy1FJwVdLksRKmE7ENaBfj", - "targetOrders": "CLFMfrx1Cm8C2xHkFz7qGyRj6Tzz3AxXqMSTgbCWt1Eu", - "baseVault": "CHEg2jyU7oGwuG7JjCB5ktUrbL8RqshuuxThv9S8RFCi", - "quoteVault": "CzQVmNkzZfpyaAJ3gmJXD3uiqMe9SGirARncMQsGxnnX", - "withdrawQueue": "886qTCTDpGBPQkTVavggWNGgwqHi7wzmSojX59NXYrRU", - "lpVault": "7jjgigtx6UfWiMSUSnDAMp1jPx9AcnyjqG1Fu6h1C2RY", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BNtNYTU19s8N8f7trL81MezZ5RiZFp7YqKLC3TAzdibR", - "marketAuthority": "CaZuZ9pFugEUyPQzFX1BZhFLtkBMzxGimq5gpGyufEvA", - "marketBaseVault": "B5oduN8UvMBk5qboUtprJAPfFcTmEiLwXyXT99nzLmRB", - "marketQuoteVault": "89g1Pb2HUhc6mM9DXbDpeDinfxQEuGRWDDyzAKLpwViu", - "marketBids": "C7iHrQniPu8htAimvaowSdwXqBjzuGnFMZhSfUSvJALE", - "marketAsks": "9AuWoyexwkH2HaLxESUL3gvss7Dw7iFtxv9EneJMv3p8", - "marketEventQueue": "CNLTe8we7jy7usMunpDS9otvjF2qLXw9jMxUMnhVmKt6" - }, - { - "id": "DVa42bgLAyZrzu9PzDHPkrJwoDTSHJbzcRnE3U5yk5pQ", - "baseMint": "DVPWKGLFHK73PwgKgTtW28iCZGewQdva2N5HeBLDorVJ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9DonXja1bLsiAD1vUsBVg7xhTuoeR4NFEjR4GBSuLdJC", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CdjCUmsJxMFjXzgphp8FXrSUMZxNqUPdQwfWVryTY8E4", - "targetOrders": "BzvzyZDQix6stM3bcZdHs9Q7TuhwWBT4gcCucBa2dHQs", - "baseVault": "7G9QKjbexnsADbeJGhGW5pLrFcJZydouU4UKo6VYqgU7", - "quoteVault": "EoqRd3nD9735urpFPPcXhr275D4jrVNoXTXbvuh2j7Vn", - "withdrawQueue": "CsEGRyopSHewxSzn8pu3aMMCcAYmWPKFQvm7dNNShVtx", - "lpVault": "3NLuA6FybLyFkcQeQkDd2d3KDt5Y8qALFT4tzFdYuV8q", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9vzm3Qc6x3DTeoU8Ui8XZvEsg4vLRqV4dTVrQgPAa19G", - "marketAuthority": "EXJzbqqqqDNUSiBWrmwMrHtCWLjWdR8kv6L9rqsJ3kUa", - "marketBaseVault": "2fL7s1ioxtK767JgZrUCVuvFan1mUYLUqRzUQXMvsX6f", - "marketQuoteVault": "5fcvJTTCSmHVryMfcA63yaZFW3g6XGbk8u7NLw9uRuLA", - "marketBids": "2hKuvbwfJuGG4ULS3ytecbua76opzwYsyF654mZaZvms", - "marketAsks": "6JA4e4UZhPr6nefuB9KwQpyZzD1YXywxqngSZT7my77i", - "marketEventQueue": "4tq835tLyewhVJrPKVVyZaH1HDhuiFFiBvc6gbC8BeUT" - }, - { - "id": "DVfdZ2ZMDDVcpqQWejhkTzhvxsBREqzQ2EphoMZbMHhX", - "baseMint": "43VWkd99HjqkhFTZbWBpMpRhjG469nWa7x7uEsgSH7We", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CYoDRA6bsEJkaPY7UPHsbda2hxT5R5R9kFkTKoNEKA6d", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "F9WHXEzqD8XCXBgbkpY3WuyAq8JaWT3k4rbcVxk5BxWJ", - "targetOrders": "BCKpF67husuAr5F9hYK2W1TBg4HmQE98wXMJpGyanmQc", - "baseVault": "6oZh1EuWPwxnVkrS8YJrqQ7jRU3LaZgBAToAi398Hvft", - "quoteVault": "A2N8HoACVZaYfFePip3vC78XXqaoiWEqE9976GJ1hD7S", - "withdrawQueue": "GqtiM7qRwqUo73mBmuLpxYn6dnU35m8uMXB8LuHCeGPS", - "lpVault": "2fxnuJvx9uGpvAbHrCRs4xQEVKHF1nSzHRXAYiFb2cVa", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7vJhxNnkPBTJKNHsbjZUhmCVCxmYKgV6vgJ56eH2MQaC", - "marketAuthority": "4e8XZwcrnbULePcLLhKBxUPjXrqwbLh7cVAohfcFSk5J", - "marketBaseVault": "2Pxr2oZcxxWXmhsY2ggiRG2qkcDsVKHrFJKzfpiVfdHj", - "marketQuoteVault": "3qeYdSxjjrySVLsA72aprsgaMSsFxQMaxTiH2itXUBNC", - "marketBids": "FYdyGUFC9akA3q5Dd36kqN7H77vgj2HNaFHFmVsvdSL8", - "marketAsks": "p1ro69nzGhFeqebgC1qQDzWBb3v5nB26ouSP5pzAyg1", - "marketEventQueue": "4zfojMEyV2ApehaBsiMoKF18fpHf8cFBsFrEWNa2x4MB" - }, - { - "id": "DvH6NEbPAF6f34kupXwLrhsD1mW6vZXf7VZR73LXwE7s", - "baseMint": "7SEsxCsiNiYqCpYG16wx4c9u2YGLZphnEFTAU9ENAizD", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "YZZpR6JpJD8TGtiXSgKuk9cBgn88cAwLRVcd7zUD6L9", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ETykHzgT4VfUUURaQmftjaTgNBGRdpUfpugv4G3iHqtN", - "targetOrders": "96QJNa9eW7EbCjxB6AjbgDCoo8jSVQdTrAUG22s7i4Wu", - "baseVault": "2SBc4pW2bWc46Do6hPEeTHYCCUf84kx86GGVy12UUKuh", - "quoteVault": "5kbYXeTyNx7BZoMi8FWBqjZba7T9apDWiHrzDp4bYqh", - "withdrawQueue": "4kGH7NtsRnwc6HTYBPMZNULB2obzb17x5RsLpghTDUnk", - "lpVault": "6FJwMgs16o9kWPxDRbLCcDTcSvs6p2B2ubK7ZPBQuhKe", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Em4KNC1KW2g2YBtq13GiRRPmo4SNPpbAgWLmyNZpkVtE", - "marketAuthority": "9ocrJQnyPJpR3FpyB5vpQyiurxwgnwMGnRdVVRLJrF6b", - "marketBaseVault": "Gtp6jpttmZdgq6pm4bCgirrGAKE31bVtpUR3xLJfP5su", - "marketQuoteVault": "47nf76XnpQK69ScVqgPRgE3JfifGYxC5pYVnWmL2Er2M", - "marketBids": "4J9kxkhQ9CWWgvNtRJn62kFEEJanmocpx1gpCyvcfSgd", - "marketAsks": "2FBkZL5poreoagXaytP3YoaWb4X1X9UEwWbw2cR7gv3N", - "marketEventQueue": "BmfNRemauTECsJQMLWdVNn8WqZPrmrzoyQDFFeY3WLh2" - }, - { - "id": "DVmm9FqK3jHNo36ft81w5U2tE7Jt7raikbamjQNBMtBT", - "baseMint": "6GK4nhV3h2RDKmjY4u43N3HJWNs6nYSB1qSBnsj6a2px", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FExy4ZgUdvJeAcb7E2kciNEfz8wzvr4uVUufvX6jMHX7", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7v6BHvhCFmACKnEZNcFGbpnWxmQMmartMUD5pv8pV31J", - "targetOrders": "GL6BdncZrxAteBu9nr8E68Mgpv7grawfJKyTxM2P18M5", - "baseVault": "3Kx1GpaNTgUEq5Qz51D2zKRWDqfAd2DZ2R1MLN1QYh2V", - "quoteVault": "5N3ZNoCDwPzQ1U8KH4vsKgQmZZXKUxQ3KWs7WwLA5EsP", - "withdrawQueue": "67L3yNVA4ab6Shxzc8hCrzacYhTcmCeGAJgqzov2WvqM", - "lpVault": "74JA7hgD6nUiXi7EijG8RKpGRHT3tBKEYZRBcfLTkNCg", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7uHeXXknyws9iazNGh5JZjfqFFCKeihAYcgzSW3AfqkN", - "marketAuthority": "CkuCyrwgHNPSMDUdBBKqtjnfgAPpRA2akxf6gFQDTVv7", - "marketBaseVault": "AtNmKQxDy7t1iKa7bbA3FivbyQYLLa9m6rPxgqbVCuUm", - "marketQuoteVault": "4gfaTbySWgWNeJdE9ekaBCNim6e9eviNNHzwCVKr5uLm", - "marketBids": "9FXABpqHTviNnZ5vK4SnZjfmr32JVjV1iGigpMM1FJW7", - "marketAsks": "CB1MBnuSVawwXr6wLVuuRgGzCPhCCRM4VVD2snFurCkB", - "marketEventQueue": "68hThTYhPLKT7ZenuXZceHukwHSJGBbU9jdupfhjaitR" - }, - { - "id": "DvVijge9HpEpfNVk8cTzdq2GuuF1eUcpVPGLf871HXFz", - "baseMint": "6bLp99VoqKU1C3Qp6VTNvSoCoc78jMGxPkGSSopq8wHB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Ekdy1G6AeKgK4W1t2The5epRxMwgJ9xLEvqASeyrtwPR", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "83wre7dTbbNKoV4E4HEVQBn3N7h3evWiuGLh3tg9PuWh", - "targetOrders": "HfrxzQfXoj6Xm6xSuq7i4jdULawzNS2P4YtgvrAEYEfS", - "baseVault": "9Nahi6Kdh8BAPMjQ8hKqmDRSPUtzw5rb44Y4Sa3kRYMy", - "quoteVault": "6b5tQh5GTf4Rt2VMMDqrr84EfXezUMPj3KTpVgebzbUt", - "withdrawQueue": "F9JAkWsymoQeCMvE3RKk635dkgGNaexQWjVJh1iznm2E", - "lpVault": "5VfPwGdM6LjFVuvcQnw93QpSF1BxmCiHvhQWZDzp5fxp", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FDvJeLH6tT1sFJWVtP9y8ygu5CqbiLGQgcRWbVTMpzs3", - "marketAuthority": "F3jr4dcaiBb8Wz76AvubicfAUcwxq4NdZrQYQLnigkAy", - "marketBaseVault": "BJ7ktmu7q8UXCBt7hEpt2LfeDBp5QK2pJH336aBx5S96", - "marketQuoteVault": "AeWiHMwoDSGUkmLuQK3XtUWZcKyjHVpZumdPD7JHTvYA", - "marketBids": "DXxjHdhEP5MVbmWu17YkWrhuFkiGoN78hhcsjN7PEsCz", - "marketAsks": "3HrLCqyfPxUDnEXVuPU9B8TJ4F4HXvgMMhMYtaVhHUEj", - "marketEventQueue": "824dX9cd7aS9cg6KZMDvimDpFmFw3H1ZvDW4S2kE14SK" - }, - { - "id": "Dw2gZpUPWqVnVm3WT8Ww7YLVWmNGg51H4k5UuB2L429o", - "baseMint": "CNMvWLKc8r1wRrQ1Xws6v43x5ttTnaf2pccLkUqsfXVf", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "9ovxUx1RZWQewowMa4CWp2J4ubn3tts45Qxn8gBouAdR", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6uiryhKJ3b5ZcgRxQhkUqK2i3m9XXeGaCV5hEhrd8HGy", - "targetOrders": "63yxhBs15VU2Z8TD9K6NnBehC1BVZ5vLqSfc2zbJhhnY", - "baseVault": "DJwaZUF81LcyDKY2yUJiqTnYvMdAsKQ5FqgSh9EF5hLL", - "quoteVault": "9gAJpCGJMWNHrFZuXYjysM4Q7TyxQbguEc5ogBeAoPkR", - "withdrawQueue": "AEQkGkpiNzr2kqS1iDgTDwGYvkikuG5K1FckGYTYnxgZ", - "lpVault": "HxawBebwkJwd651TirwtgPnqeaN9UKr59kgTsq6ksoRi", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "26tsVhAHkTYEbcwqHr9cWUDgHjHWCHbJYdhrfGLaMTFD", - "marketAuthority": "67vtzmqXjZDG4agRyHNCEfjcSXgEFzEVaNL6s6umhFV3", - "marketBaseVault": "4kWoSmR2XKEeaQUZHHPmxTbvTCJBVuWicAqavnxFbFws", - "marketQuoteVault": "8U5NvcdWuVgEHHuGvdG3ST4WW92karGUYM3U2x4oSgVF", - "marketBids": "8h5SWSqg9AjMNV85upJiNsfNhbTvVDYNDp8JkNgGe6VL", - "marketAsks": "4q1f3nhndrxDeNkbtunJMTHA1juwDbQYzZaTeNfZdJmJ", - "marketEventQueue": "BffmWd7thqM79qU6ahPTBX273qXTa5gYnn89KLPEkgvR" - }, - { - "id": "DwZhErmU7T36T5b1mGFbV1kzm2REFb3AnwNBb3h89tby", - "baseMint": "8BLiujyxu5gJajWBXoZQkwSsamdeHNKWQbu1ApAao8Ps", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "ELNtCBZ4Xhjdu6DznvXYjjMK4Z7LTmWyrEdGsXyb5Zme", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HHCdnAVywcJ9F8MpS3D9137v5Tg1tZ6gp2mSgYN8Am71", - "targetOrders": "66N2fZrLWqJ9G4H3v8Nz1wVVCTC5AVAdQUFWuW9jgVEL", - "baseVault": "BKdSYsKkmp46TvTxiK9kUdm54X6KVsS9tCwueY53aix7", - "quoteVault": "BTfMbBx5j5HePQ3WuQ2J2BUaRE6dg7TqKxwtFWFhnFy4", - "withdrawQueue": "31v1ZAa7vwhckPJrH3sJm6wW58vxJZUnvRYLjmboNHyt", - "lpVault": "vNpzoLVLAWbe5u2j7aevHm7eJoKTNpocAxSsddNTBDk", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BeA8Jr7LeED8T8G6E2icuKaRXd9rt98dfpDFPJUxN7Ud", - "marketAuthority": "9ieS95ane63YB2cjvP7ntinABWuwmpcCRLnQ2jvmandm", - "marketBaseVault": "6tFkDTqtgY7DBWmh15szYARAn6qp8s4w5bZVHRiEFHrc", - "marketQuoteVault": "F9qRbycx7ggZ8DxSakkCE1ZbZdeG5wrDiekt8MzruBoe", - "marketBids": "56ZH8sVRWDZTd8Hetmo67js8i1YwW38Sr7iZacbhKQCR", - "marketAsks": "7M9rqxohF3NhFpftE2dyuHyuJ8kgpRjes5HMLZXfBY7x", - "marketEventQueue": "4ixYkJ4h3RJFepdnsKDQx9gHeEgRVR3kFp3ffKCffrKN" - }, - { - "id": "Dx4qTRyBWRzHSTCeiPpthsaApuHRLJsCh4v6RhipeVxo", - "baseMint": "SCYfrGCw8aDiqdgcpdGjV6jp4UVVQLuphxTDLNWu36f", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EcYk7t6Vw59HDnY2u6H1KDPkk8juMeA1NpGpHiGk1LDf", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EANzBeHhErogoLud8tsZ2ooh8XuKaX2ak56ugKeCy9iW", - "targetOrders": "ESgKRmKS1aCKdwRqj7YU62wGecfgQHYsXgXhRz7vFRF6", - "baseVault": "GdzS2yRb369DmRWgKyVpj6Wk1anmEEJjC8pkbPXMe5SA", - "quoteVault": "326xgaUCmb9X4CRL5bao4d5qNqZhqYoZWLKw263HX1ee", - "withdrawQueue": "G6smHrTU1qYscaJ89ercWBCU3nNXqtSxEtfvNnNDbzdq", - "lpVault": "FZmRZGtNGjjy1mvLNdkvu5KiWnGJ8wATQFAcU9wTf4Cm", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DR8V2wUCSFKCGjML6AZvUB2eYWDPVQ5xju3DeXGgpSaB", - "marketAuthority": "CpQvP7x1Xf7jPGssduuwHEDk1mJ752TWnPthvCpa1fSB", - "marketBaseVault": "2NBPDsvGfkihebZapZKqCi4MN4MGf1AwQ8ydvn1yTmCf", - "marketQuoteVault": "CFXDVnwwz6fXMwVVT5kgRdNfLc8FnQGyKCi9zf9hzaLq", - "marketBids": "9QUAbs22seMf2ZDbDsvRrQxopaPXQdvEbH61WmQkHf9s", - "marketAsks": "EQ3oEzmxQ4BSFKbip5AYzhbgju8FPuDNFd1Y6ALBsnct", - "marketEventQueue": "5J9VjmWJ9Fyc8v5JboL8Pi3o3NwF7Wi5qt21KJzBoH96" - }, - { - "id": "Dx9kLdQz1qJB3hSdcJBQdNfBntvapmRwSfsL6AEry8MP", - "baseMint": "7rYHNNU1Quk56mzxXxGiaTWV6Hb1Dh1QNUyShVEdi2Qp", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DYPPcCWnAPFm1ayAFanfwtJhY9QiQpMHnodaarSJV1GS", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8NKDV1bKmTnGsu9XUAdLvGFTJnuXqiH1uiagTUJK2xDa", - "targetOrders": "EGv4nzRdH9prDjjM9GqeppSowpeXkVETSyzt1HW3hQGB", - "baseVault": "7hhfw5YNocBFNeCeFzJyaH68Hrwb33JabWj6qQGo22WN", - "quoteVault": "atKAjbjaJR7dd4F598vFvouMgFM63b4avtVw26xJhhp", - "withdrawQueue": "H5XiQttZsC9wfKDAtDu1HrXo2FPHsW37mcUQ4gZBsUYA", - "lpVault": "CLeBzznVyVK4py6f2EcUFjSe9Ztwdy48hBaoS69JYge8", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HKb1rUozHVnPMupTW9Pi387MYES2jpSjpca9kYZCuSva", - "marketAuthority": "6yFCYSdwk67xq6H2xjMbcV2D4UoHPTaZFppopANyJoCU", - "marketBaseVault": "CGtfecVFC3sJfn36AN7X5SvybmL2ZhpX7zVNMFydNjkj", - "marketQuoteVault": "9XJzFT97GRHDbJDLZ5uCWUXv4L9Wnjx7P73sUdeVxajq", - "marketBids": "FvxyMyobkrpKf61jtFRJ8XfUTmYzseodGxzisDb1h4sD", - "marketAsks": "FUML8HhxAz6q6NBGjvxYq4fxCKHy1pKy6zFGWhfrwqdA", - "marketEventQueue": "CnknbwF57SV2s9QDp59ycHQozCpuJyzsLLp96camTokJ" - }, - { - "id": "DXBneWkSJFUokRQsHkKDmXXjeHp8kSboVkHHTUmfJQZP", - "baseMint": "CU4euyVfS4kbBJJVHgmTnXosAPQEFRmwn39Xm45BuzKj", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6Mk5GqqdvozdKECfKx3HAdnGAi2SjaqE52raBRa84npN", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GGaXw2wyGKh1p9GdRmnd8oRkGAS6M6yzQBCE8ZtmWdrr", - "targetOrders": "HLBExYi9tKFtE7uTf4tPJpuBbjyNM3fqhXz3xHJ7z35A", - "baseVault": "F45KdwpXA8dYYEUbcRB9a4dvmiqymHacUEKDY3DAc7xm", - "quoteVault": "9YhtPR7izR4URmVRXePd2HYq4kLQHzzCdH3cdpmEZAqD", - "withdrawQueue": "7JnpymZcEHzEeJ6E5aSwiWT6yRaSzsb1j3Gf1rF1xy3D", - "lpVault": "D8BxdVmL97pAXcXSoe45FF1RM2iHX7385DJWUk7ziV3B", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4fpQPAugsrbGYDdPjBKTrJwjoWeLV5SwZBH7Uk64aXNs", - "marketAuthority": "H3Pd68b3ZM2g7xyEshJEeronNzvp4uGNP3iiVFGJ6CSa", - "marketBaseVault": "3r24zTjdEMvbyETXYhCNHofF585XKPaZY3dC86BjRrRe", - "marketQuoteVault": "9KdwJQcoTgwpZuYJa8qggTHx5MidfvGDvW1nZaKhkLK7", - "marketBids": "HhUp3ZWzuvwrUgnUJNZ41BEcj67dm2DNc2pPKZcMzdHu", - "marketAsks": "2HUkoYUzizEsPxFscKK3ZeSBxpjdySguw4KJn5y7gBH5", - "marketEventQueue": "6R9v16YB3TVUwwVVvfjp8jnqr9p5NgBWW6gMCW4PrN7E" - }, - { - "id": "DxHibSiuvezCSaEgeiGcv5iEog54UuPh2KaizoKZZH9T", - "baseMint": "8Qc1ZtQeR46aq6CEcf16XngA4dASqNHMrejfkmZPXy9z", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Gb7pz2u4W8joQKehgBvVBzWRHrkD3bX3AtFkdFSqH1kt", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2VV5XdwayhVkaXswbEVeEbPrUfQQgUMbyX8HoJ2WW94f", - "targetOrders": "FoThCX4qviwdree85zk4PwasoJpvMNEzJu8t5nbsRyXZ", - "baseVault": "Fox8SCiqVAXg4XtBqjSVk6FqwwCCbWUx4uhCLxMZVvgy", - "quoteVault": "H5NszL2FdMQGn6L6H7ijL5SPRbcGKx68avpkCD2p7d9g", - "withdrawQueue": "7MXXZwP4iDsuZuHgvdouMoctNqHyXrGqigdR9Ub2JyEV", - "lpVault": "2xKdH7YLdnKYscKeKzR4svoa8zSuTPkqkBnXAfEx4GYN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9MEyeVeeCJVGtaoogxT385vQjpZDVV2PENRpZHuhpUqc", - "marketAuthority": "6hFXfq9iZHb8fhzYa2d5dUz2vbsktkLjzSm7jpn2Rehe", - "marketBaseVault": "7K9g43AE7nmsYaMPHMdfNt7g8Km6fQC9xvNSsuk7ntFd", - "marketQuoteVault": "9kj64zieT2UeeoKKFNaeTbYJUAMoNS5SqFYMA91G7cE4", - "marketBids": "8KerqnYMrbDf7nSaUamHv7XmqgeFb9bJAFUTq2KQfJoB", - "marketAsks": "7CSJDTi2Wzke5dnzqE5gz9PVtW5qsAKh1YmN7ZuDjWhP", - "marketEventQueue": "4woT5G1p5jKxLRpux5bWvXJFekE2KX9mTVvztef1jCfQ" - }, - { - "id": "DXjJVNv7sR4r2HYj557BRu4xPYEPL1cLCJbTykk8eCmw", - "baseMint": "7UvcxpsYpDov3Q9GJU3HiHUVnVCEnY96XPAkD1LTDcLe", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "G5cBD2NNMFuDfka8sZxoqYJyFDzrz5r96ko7FqBxGkgS", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4jyaWUTyfGSgwGaff324mkyS7VXMuP76Ai2iJ1Y2zyQd", - "targetOrders": "HSuX6KjPq18gV7jSLGhrozGLUvJxV2RT3iiAmLuHLFrE", - "baseVault": "Eyn672yNbG5LnVfLsjCAD8iEkNnVYRTgV82nPnouZDnu", - "quoteVault": "AZtDgsBT1Qpwfhx2mAjNrsE2yeZNwFu4BUKrxqh9EiVZ", - "withdrawQueue": "8ogrTKx8r1kEnRpAkZbDEBSrc3RLPhXE1xdvAyuhbrv9", - "lpVault": "CofKVkzzfuw1DDVhBUUiEWnnhzYmMnbwD5JyVmhLXX3P", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Awgpy4KEhykYdx6EcgfSomh5b12Q82PzyE7QHxSgim9", - "marketAuthority": "3JiWnHXrSCJ9HBnmX5JbMskuYVEftQ7CuVF3oma2uWCy", - "marketBaseVault": "8LnmDGmhDg6r86ttenkp9t5LvFqXu26gkbGJ13d755CN", - "marketQuoteVault": "F4QNSaghnKg2gB8d5BAZJVGTsVusExfd66hcVTmc3vf1", - "marketBids": "Fuq4bj1y2qieBmjYPtWABvupUfpqjuYgDKsS7AVC8rUC", - "marketAsks": "4CGwfsRRgE1en9drmf46h8oXjYueHt6c9iCnKhyrfRZj", - "marketEventQueue": "4K3Xz5g6HD4GkSMKtZeHgvgyktWFqc1kxDJkDGmaXnhf" - }, - { - "id": "DXyoPww6dunLcYgGZvvLGEJrsHrapFkJWku8ToHrBedS", - "baseMint": "8E5W9PMhnEvdvM2Q9XBLMJW7UsFiieXnRHPj8zhtB23h", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7g51525gZpCPPqtKfAXjymEVBkaMMcj7rdqdGobcDC19", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "E1UAt3CKcfVqqKNy1Aamf5n2vdgw22dHZyB4VwV5SoTB", - "targetOrders": "9ZPfCquak4VBJi4GSMaWGGyFANgffkPpLjibfAhohQoD", - "baseVault": "aJTYJhTX2ZYRaHWp7QKu6yH2fSvnk9yFDi1odeZnT3P", - "quoteVault": "7iAWJemXTRm6K3syU8YLbcK1zXG42EgZr9HN1LC9QKdb", - "withdrawQueue": "2n6FoZMbzWpFZ67WhL5mZBuunTrzTLyehULiF8ahDyRz", - "lpVault": "AvQzezHSC3Zcq4ZQURHpcknB5KWNUsLfVR7hcKrnRtSh", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EfNw2rVeteCFEjRPaBumGEygTRo8sS1wrVeWyP6W5HTp", - "marketAuthority": "4xd8Ufd3TydotE7bCaXEZdjaGwpSj8XwrGpip4nJhaBQ", - "marketBaseVault": "5ird3RjvjZgW5fnszy3rL4ewmKxbqjLfTB9pxSep8cpC", - "marketQuoteVault": "EzNiCyhjFrUuJLPjq5qFBVgMVY96ZiL7mn9iJVHKBqaA", - "marketBids": "4Tw42tWg613Ap5arur8QLR95YcFRATEirY6Qbxt4wFqV", - "marketAsks": "zfC4J2kPW7rAf1rqEGKpfLVFMvd5dTGALxJ6M75qVFg", - "marketEventQueue": "3r65iBWu5DjTedUtRfumhpiMsuTV9tt6TZKvMFoym1h7" - }, - { - "id": "DY9DeyKj9T6yCXf8UM6FGMGeh7arfmmePf9E9jzdaymg", - "baseMint": "SHDWyBxihqiCj6YekG2GUr7wqKLeLAMK1gHZck9pL6y", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "BWXhKpYbjYwdzFqKvW9WVHExNBL95CE4XoJQzRTiQFnP", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5gTJDU2uA81Nsf6dWGrmo7Z6dfZ5pkPbr8kdcFJ4BGVV", - "targetOrders": "yWgBSxQeo3tBW3u3yYpAruNm9gZQRVVipozGLHGPxg4", - "baseVault": "GVzektnh6TDocY4FTdLm3F5Aha5XBfXmYKadc82BHJEV", - "quoteVault": "7naoUqLwTWYpQSDj259mRb7hAqCAmiKG3og1MWYoMqBu", - "withdrawQueue": "FRkxxScsPMjJGivJA9A9aSx1y1pcKvVXiDk1kFA8naXy", - "lpVault": "2mXx696wf7GkfmjMhLrPYpkAbrtH9w1dvKBzvNnCeqmt", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CiDPLzvb5Ua8XwuRJJPjj2cPWsUeAicKVP4a6vCJsBib", - "marketAuthority": "2aLJUUqUGTHc6YhMwqBis8Q14Vw4XBYZDcVS9NKrMVfU", - "marketBaseVault": "GyUvd5EBm5imPuzqLzifh8wEvWMXcJsb2LVfYpqxsphA", - "marketQuoteVault": "Dn4s6F49i28oVUN4YYPR8GLhQCvng4FF1kezZJcKavt7", - "marketBids": "BCR5hey6DhmFz4o2CKBgBqXn6wF1fUSsVoV39N8irdX4", - "marketAsks": "8jNxh8Ga4F8mH1kjGmiKXQz6RcKq3pAR9afEd3iaaBvW", - "marketEventQueue": "CDD3bP27M1C4bT88MHbaqcvkpzdQfgQfoSPQNEpvcPeb" - }, - { - "id": "DYE2NPoUBxfTioWKYJVVDhE8NSDZMDrLEKgeQQe439rk", - "baseMint": "2uRFEWRBQLEKpLmF8mohFZGDcFQmrkQEEZmHQvMUBvY7", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "BKnUXt52LmwTfZ3bUZugJ7PGL1ZdpxzjqopWePeFNZPE", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8za1Koj6crNH8xeTMz7gFLUp1uw5evhiHvbMSTGPAbEG", - "targetOrders": "GLb7nWs4VpG3aqRNfJa6NYqcFh54HeEtGrfu3cbVEDMG", - "baseVault": "9kkLJgNuH3d15BTFdiNZct6hUEF6Kb4LmzT6zFwqJ73A", - "quoteVault": "9D6RguaNUnPJqKUm4fm62pYF3g3d8XDXMfgMfnQhr3o1", - "withdrawQueue": "H8gfNzXieYQY6nNSqAnendb69trZostoe94FbjcgqNDN", - "lpVault": "BiAY5N6TuoBqJ7c6yVESu9jebnoPKfo5tfATk8FFRyUq", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7jbVj4hSWRM5vcf2riAojBBnERy6Fj4AobKA4VwLtEU5", - "marketAuthority": "Eh223BmDP9isAuJdC1XYRHN78hfUQoBvWgNLp8sZcWkd", - "marketBaseVault": "4FRrGkt1oomxmM33VFDck1ciENb437zXZiHnU124DBm4", - "marketQuoteVault": "D3tHDdJZjVUdQX5DywJFBooqRpVS4hiDUb12VubTMx58", - "marketBids": "4THfy6puvD57APPhZmGNc7U8q7PztvUsCQtM5bykRUhq", - "marketAsks": "3XmVphMQKiG4Q6MDo47pWMKxvgqmbk9iD481QNAwij2M", - "marketEventQueue": "2A4HpUFcL8t8janEeALhQPshUPahjCR4jLM5nyp7GVKH" - }, - { - "id": "DYm1kbtFJtYjZXpfwTyD4HfL8ieHwnJVouzrW5iP5w5q", - "baseMint": "GYCVdmDthkf3jSz5ns6fkzCmHub7FSZxjVCfbfGqkH7P", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "B4q9HzAWEiUAhiXHNxrbJVxJEcXGLZ6VNb5VrZarWbGY", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6x8jKydguKcXUqDu8mGBw2VyT1Mgiqe819XhMjB9QTQ1", - "targetOrders": "8tHLo78WS5sdmy6oiNLgctYvBxuJMLJTVcKXzD9BHx7r", - "baseVault": "vQviaGbLsfLVoFSUPW1hyDJVzwxC7tx6Urw3NLGdKrK", - "quoteVault": "34yGMUFYUrhkvfVRv24fDdS5zaj5XUsZJfLMwciTiC2w", - "withdrawQueue": "CL1zmEDH3EYqAqTWa66b1gmoA5zyvZAARHwd1ED5uqBi", - "lpVault": "HuHcYVGLuscAWday9GmfupwfJ2HCkvozF47kHG1jDHGE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "39niW2SSETN9Sdj56ZreuNsAKYuhwawAVrC8gMTdGutY", - "marketAuthority": "GqFKHE5X1NMu4fU25rfXe4ghRNPmJ6ML79XsqcnERihH", - "marketBaseVault": "2jY3G69KSZtiGw5CMiCctKnY5nyJLk9zUagmTGtXLXuP", - "marketQuoteVault": "DrWyfESnGQsnfh81yWQgxFsMSbgNgKBSGgLd1ZeXty32", - "marketBids": "8t8Lwp5h5xZteatsTkGMrTH1XSRWBAsdQucf5oR1p3jT", - "marketAsks": "HPfeKvQ4pxSF6YKPjakURnKQyFwFyibVcatw8VdRYKK1", - "marketEventQueue": "3ZXhUaeP9aXof9XCkbCNwTiCFsXp1aeSK46SCWvyem91" - }, - { - "id": "DySLzKey6Aqwaydi3QgpauewUtKjURaAza4rJZxkznHN", - "baseMint": "DUSTawucrTsGU8hcqRdHDCbuYhCPADMLM2VcCb8VnFnQ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5GiHazu2LhbfwsCr6Z9pGfqZCgmjAxJwj15ucBwcihuH", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HCv99otJPcRxejGyju7T5asZZ1RBUnv33rv9rMK3BCcM", - "targetOrders": "2eN4YEzUVzu47P2jffz9rkCBLvqHexekdb44SBQEcsmX", - "baseVault": "6iixLoYUjfMiaBGwbL8z5NotDFFvKakFScy4xhD1REKx", - "quoteVault": "95S9Mr7jgrrjeTfUqqYGSfdaUEjdzFG4Bnh7vFYe5rqF", - "withdrawQueue": "BW9d1vHnxQACUKCJGoVJxM8CT3HHXpZNwi2cSkvLSHKR", - "lpVault": "7jruWSUZ6Lc7Ncz5mQSfGZVci1c9AmE3mSPXQCEaSK7P", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6uCCYVogMFvTjnSk3itNEAsVUmpJxj9F6kyTJwRTJy63", - "marketAuthority": "7J3qja7S6J2cjxKJbyEmox26NXTy9bReFLEFB7MvQETY", - "marketBaseVault": "DQBuEVyovy2UtuJh7BzZ8f7YV8t9Ug81xpejcQHs3GrC", - "marketQuoteVault": "BN6CVzkEy2ejtsg624Jkci5KVBpimh38Bsc3UTdFgoek", - "marketBids": "ABEQuaZYjuSN4BZ8Ae1tzVLPKYsMR2wDV427anHbVncg", - "marketAsks": "7SKiiu8Q6gq1ygok1SK6rvy1wfGARtfJw5QvdAgSWxrb", - "marketEventQueue": "DAseee7Kc8y7CidCSiRKRsiAjAQAxh7CNchtNBUQfQnp" - }, - { - "id": "DytAqwL6v5Tu7pHQJxJ3ozJQJFKrczip2MerXtNoFgF6", - "baseMint": "EP2aYBDD4WvdhnwWLUMyqU69g1ePtEjgYK6qyEAFCHTx", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6MLGHP6mLcXssY8ak12QSoLmjoQMxVPdRGdyvbJGZ3Ti", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CGMyJYRgDwFQ1Fv5sgEGgoHBoEsZDTxA8mtsMhHiq5au", - "targetOrders": "5xvYDBM5WahFHBBNHFPUHHh58Cs7hf67QhRSJ32wPuS5", - "baseVault": "4ZWcBJdKwMNnwdFhXLguzVxM4QGDsAditPJhbovBbyWL", - "quoteVault": "5xHUgpLvifjGnGEVFNFjC971e9xhZhJ9b6yCD6bW8yqe", - "withdrawQueue": "5b9unbYbkYJGYDuMgG8wDaU6gekAKfXj4LCBxFnW34eD", - "lpVault": "GcZNgLDXCrXZLGNCH5fQnsJannsLCZdjjkL74LSdgHbF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Esa41QArfMrdbyrsbnEgfBoviyDiLUzpNN77gmDp5qHH", - "marketAuthority": "BbwGfRrwH1WiF5pwb3NhXCqqvyTnTVci39Uhverprdj8", - "marketBaseVault": "Gp6XY6xB3VKrmEa9EJnKiqYJF53Ru7Dv6ESiJhb7bjLk", - "marketQuoteVault": "HCMwQYQzXtckJYhowZXYFqBwUMEVHK2banqR27v3H7YQ", - "marketBids": "2Jc4iRgDN8abjcnUBrbaUkBRY64AW7bZKNxZEoZgMdqQ", - "marketAsks": "EiAZYjiKoo2BzUYdCmXPr7x888ZDzCwMCamEamtj3Zh8", - "marketEventQueue": "ENMSUGiQjCvhVXYAHnMf422GBd2k5UNLJT2scXSb1bBi" - }, - { - "id": "DZF1Uo6eXMucVhaGvmzMQ3KJmCPyNocjgJ6SSQqqZRjJ", - "baseMint": "F14Cp89oAXMrNnaC4mKMNKHPWw2p2R4DRFAZEdJhUBkD", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FUj1pX5TwDfEmcghUnvRDCpUrC7bPgsUrr5WSSddRrKU", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CZWaRZ7XNWpGRJGqtWBrYcH8RsBHTAGBMSWqtSNTsXHH", - "targetOrders": "6vMYaD1bVRrBba2mrHNtouRkvLRy713ZYX1UAibtZnBo", - "baseVault": "GYUCmaoGipdVKfAzg3hi6DHfYA7YudzZ7XPdJixNSPC9", - "quoteVault": "77WKmkjPaujjmoEqSswtqpv8fdsT3W5NEGpL3HdtcRok", - "withdrawQueue": "CoDeTbXEJEBunJkcDwUjDL5bL5jRfnEbC3489Wp53fSN", - "lpVault": "CJZTySNK9fm54J8Ddx2fLVnTYwgS6E9crZAdKmwx6eo2", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DhvLMZbWamf3DgsoD1k47pBdnJJFSeByBg5xJvgbuTHR", - "marketAuthority": "2mP1D1xHLqLw3q1fSsfd16y1ucuqXFR7JQW1ZJzuVrqM", - "marketBaseVault": "2sPCbAgdCmazY3tQQBjAhPkDQLHVN5MRuWBTtXgXCqUL", - "marketQuoteVault": "J4awkXiqfoPGbC4R5ojPeznhSy6QXLGJPFsKmMriL2FB", - "marketBids": "FBFUShnQ66GjpUxZuHyDEAdtz6avWehZX1eEoo631PZE", - "marketAsks": "99AKUfY7cbd9A49cnXogjLnmrZQ44Gbppf9LyZyoc6VW", - "marketEventQueue": "KW38Z5M55LknS79ZvygvEwwuXowqa8xeBE4HuqY7qet" - }, - { - "id": "E1evCUi9Fmcd8VAmHhoM7NNkdwN7WmicwZ3jDdyvpcfm", - "baseMint": "6thBfacY24FpPwwtE91awkBQ2qrnHuyUX5BxpX9YsSdF", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "4rvPvYbuPK3FdBSgQGvcCsznyMeJXzPnEkMf1rQFMy6r", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HpRHHXF4ptRFHmmnMrUkiuqVThzPJ1crtZfcmPzDwdpf", - "targetOrders": "FAfYXX8tfuQDxEXTHbdk1r6vF5XTw1k59ccyiW3GttgD", - "baseVault": "FNyUpi8gXDR7v3PMWQshg5VYbukLkCPhCcwcyuaocNQH", - "quoteVault": "D8W9YN25a1DLVfKUc1VJGYJEq6YiXytwZEQqQEjwBYcZ", - "withdrawQueue": "Ax7w4EvzV2kPaNoPdHirpUiK6sg3Uib55yARWu8FZ4Ry", - "lpVault": "9d46NXVVwLWhnriLRZBxwDjk6KqwCBAEspKUPFdgnoq3", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2ETgAm9hcDrPDfVZEWpkPXgBx1dkbN8w2bvcFNGCZm64", - "marketAuthority": "DhJEDiU4pw8RcnByxx4rLmXxhKUPPLjkt1UCdfRCJxxV", - "marketBaseVault": "EB6YuEbw76gmL8ALZ4bpEeRmY84EyYFtKRmAnL1yfqZn", - "marketQuoteVault": "Jcx6H7YL7nhSrU75PNQxfVvkp8UtueB1SZiLWWZZ8fM", - "marketBids": "8iHX83qCpdC4hPwr2QjHWAp5pM9Keg8ehP5cZfgFoCP6", - "marketAsks": "25UAYCAQ3bJ19jpzCVRiJFwJ1xG2zGitqmKGEppXjeiS", - "marketEventQueue": "C2UE69vGLesAm5tRjpNyGcw9Gub5gJ7gUbHnWuDqkA1Q" - }, - { - "id": "E1QgGoLsFzSguzTuFk1jbVzMJE6bmrEVFgqd44HYcx1L", - "baseMint": "EQ8XnCvwZvhdJZZZeJeRv5bYyNTz5vQ4TL9VFxwCPcZc", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "97G31HASpJVMYf6W3BnaFSq8ABBskYoJVehiD4iFNxUP", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GtDBMBuNYNUPzx1bapFps2debbm7EXt46HBRZyLK8mfC", - "targetOrders": "71F78MG77zMXJhGzS9YLuMUYt3hVPPtfLLXyUzUL6nQA", - "baseVault": "6cT2WjfUxBuRcUpqBYfDxQdax7nUvmk3iSu9nbLN7WtT", - "quoteVault": "HN4sNXRCUTp1WkvW4b8F1u5SnEXFxXjuHJHW47W3NUn8", - "withdrawQueue": "4Eu9WhhTZyj3oaS4997u9z9Nuyv7qJoE5N5rKiiyDDWM", - "lpVault": "AvxSTJYmoK8k662LhpdG12US8wdJzKPszqyuruRojZbp", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GejDVUEfPPFRgbP6bzZsDJfUT3GTPzpM6gSePSA6kL2w", - "marketAuthority": "GGwCjD2zYb4bUp5uwK9ojvLf8t56UKFc9tKQCD5znctM", - "marketBaseVault": "8QpzQTwD1XWzF2UKEz7PV9fj6x1tUgwwb1iEjBXaaU15", - "marketQuoteVault": "A3RkXSuwFAhNrJMy7FvT98aEXYWK3ff3FaSa3tVz8dSJ", - "marketBids": "GV28gheXiKvhxVx3Df3Hy8KhoDF1UYqmQH5ooSa52Yjr", - "marketAsks": "CSC1iXSzZwQk8fg32HrVPqjNnVgmoi9fXi4tjLH7qpY4", - "marketEventQueue": "9W2envaTJKYk2dsv8zu31PzVz9qpUWwnT16esxau27Yg" - }, - { - "id": "E27xLfr5oX39P4RpTfYzmYBQRUargqJbEx3cYhdC2DDv", - "baseMint": "EiNEYyUcPHpGt2btoMeuTrLtsAeayY74ECvPRYzcdPpo", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "784Y44Yt2VakkeDAZzSWewJkL3SXrAQYF2u2e49cnZeW", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3ifXoSZgDDeKeZwgmmh11LLJsvLjNqxLskjUsC62BquJ", - "targetOrders": "Ko5KR9u6iYFskktrGfdp3ihkJh7TrostP5UXDAZvaFM", - "baseVault": "5PBC6DZf9K5F48qfaJWv4FG2ysip9C31HfK9QQjnnY7k", - "quoteVault": "ESdEGALfUdEwDiKFaiZ69QuNSkFrPsEkodVREtY6kM8T", - "withdrawQueue": "2XFigbi8JLTx9jxGELkGKxD7nbnAkBoB9jSLPMd88NeH", - "lpVault": "BVTuvQTE7eW2XMNDHKzvvGtt9wFFY3H9tKoXzsSVjJEQ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EVeJpdMig7ZtazkUctvjnJJwqvVYG5zLhSuByDebauWM", - "marketAuthority": "2MqQewAKqbAPxVmVMaBaiEiopFRNWVN8A5bMNXgdYuus", - "marketBaseVault": "8ZkUQARYJFU1UFTBCripwa9weLo2PGVgvTCxhwuWPngW", - "marketQuoteVault": "BHfaHaYdpGUgajao4ghNqa85pQojYqqJ7aLG1VaCgyvP", - "marketBids": "DDBhtU9bb6xtNRnaFQqdLazZTUCPMB4PENqhoAdq5u4M", - "marketAsks": "Hr8g8UtBEcgRDTKuUctjiZnG636R22wLZ5rYfWgMRMNV", - "marketEventQueue": "9zcbLyBgi1eisX7zE26qttCQqsybpbgKkKvYsFodHRww" - }, - { - "id": "E2CQxL2EFN2tCiCXQ9cb6n9edWukbjETigWH5LBg8WsM", - "baseMint": "EPob4xUwQY1yukFcMbAhaY4Tgo2nwgkAzz42WYXKs5PR", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4FAHUJqK7viVHWFhbNk7EjzXo8fPwUdnkvASko18H7JW", - "baseDecimals": 5, - "quoteDecimals": 6, - "lpDecimals": 5, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CeiN7aSNBAX1BSWMcNw6LB1vHLAoB9DMW2jUAvubJKzy", - "targetOrders": "7xRCTrZFjYd6wGBsVmwvR8M6xXiLJqKaYLaJDvuLWFA", - "baseVault": "7FRzJQaxVFoAUXAMqfrKr9JfmhfC2XD3uRYqUaqPUMsG", - "quoteVault": "F6Xe6LUhCtU2FdMiyQpcvmkAsDgEBJqvn5cg4cLuYXBa", - "withdrawQueue": "CHJm3HBLeRHcnUvGucczmdnXUZUYzvjYGuNERpz78Fub", - "lpVault": "FyCjoJYmEPu6BnwfBeeU42NRcNgW1MMP8NpjCjadLXFw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AhZiz73w6YEoJQmE8ty9ogyUHKje5keL2hNa6GvMEspG", - "marketAuthority": "5Job3ei1pJ8yviHNuymhTVrwAB3Yio8XUYN6oumszCN9", - "marketBaseVault": "8kUCWhAgJaLafWDxYTvCpZ3KbrdJS6qdEvmsyKm17P9B", - "marketQuoteVault": "7jBoph1uzTSFFf6r8ewLjsqymPNocdL8QhKJqGTz92oD", - "marketBids": "3BdHtYEYGtc9L3taD8G4nSZGftCkqH7MkG9YHRVHqRFh", - "marketAsks": "79mgXQgQqj9sPesJ7ovFL8LSwS8PfXKxzL3DzLAFJRU", - "marketEventQueue": "ALkLBTnjPkCFB9m1xtYe2yWPJzXWUVZJx5tCPFfreRUj" - }, - { - "id": "E2rJubQidkhuhTTjfqWYjTkHouA5EADzQ6LBRrqmZ4LR", - "baseMint": "7mNihWEjzWv9yCZc8capE4mS8v5Xvp5YH2yQhtZrQV5B", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Gu2nD36SLSL9wtwTFiiWB6pb7irKMefi1Qx83Wti5eGC", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7YLPUCDgfNAzZyxSgiys9egpdDkJeJsbjL2qQ4apNEW3", - "targetOrders": "DtmBuHF76sPzJBxRfh2AVbSp7jnX2L9rMNVaBm9c79bd", - "baseVault": "kUNt6Ar1wnBA1VGcvjcmfTvTLuYT9bsQtWs8qDRqyNp", - "quoteVault": "6iV2Dn1RZyq1LqZmNfYrBtAeC3PWhG5BxY2CzJBafGc9", - "withdrawQueue": "CSXW2fkzUYKwFSLZeBjYKQGzhKC6S36vgmUL1diiNqpN", - "lpVault": "HegNz7UpSxh831NatbK27hRKAFzqJzvzLDyLbZSmMLBy", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6JGtPrToaw9AXRMeni76onDNiF1YEcFeW1ZXRJzG5bzx", - "marketAuthority": "7DY2yvqsfypfoEaFNfDnXHmyiQ5KnMpkyawpymtwHeax", - "marketBaseVault": "467hrypYkxRDRJPJoa6SNPRWQLdNXXnAvBPqJW2JJzQ7", - "marketQuoteVault": "EYUwcoaXgccgf1sdf1ZnpULNJmqQfhxiYjxaAM6vnNeQ", - "marketBids": "92G6eFwGL5EkQkEc6YQB4FaJCqwvrfNcxT4vBMfGkZZw", - "marketAsks": "FXXHpCm7crsqciHZfERXzAk8WY2h2enKV3K1zPLL2siY", - "marketEventQueue": "7fAg6s8QLwrnwoT1x7akKyNSFRF7AJyUADDewxnotrKx" - }, - { - "id": "E2rSTHFX7iCz9b7rcAU2pBPhQW439GgoKNkZym2uE57F", - "baseMint": "HAfTjdSjZiquZiAkmsYBmcFR5NM7cP8HtMqjQRk8eVTX", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "57AQYJUBSJDYmH7KPSRWGUGupF2Y4AXyd5H6oq46gKD9", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Dagtf1ZyNtgLUVGhT1s24giJN13HtKtPbRWB2DTyJRXv", - "targetOrders": "3ewM7XNX6zyJEpJQKCVCAsKsny8k1MzkYsXYJ1TjT3Mn", - "baseVault": "BK83MUQpWovyWh1XZdtYRgYGBPGaYRwNjhoQKswhaibE", - "quoteVault": "77JFU9x7wzEGNkYoWAxqeUoMKeMHkvsyoX9YhVXLMttZ", - "withdrawQueue": "49h6f4MbzTpGEd2TKLcDvXhSdqX6AYNJM6LDM42NsG9x", - "lpVault": "BJQ6DND6B4qLbM3wtzcs9tFHvHNVRCsaQsWkREj9n3D4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ECrAWHqTcqpsiTKm3whiZGzYmkMwoEqy6ELKkyQg8kie", - "marketAuthority": "2cHwvfnP4o3xMRWWi5tTCACHJyGNgnCSTB5Ngbgf4nM9", - "marketBaseVault": "J2GDPKA7ReiH5iM1QtjtMcufZYJgWkY2DiMRCM6VLSJG", - "marketQuoteVault": "B2QbiHYpyzTL6WpfyFCiD3fxy2KwhQLJRFYeGp6PU13N", - "marketBids": "EHyckc11RzT1ZmakaTQZbQ13DtRXaMiHKhdTYPBjRENV", - "marketAsks": "7vYKzfdoqJ72XR5V2cRESXVRekXQLKDYs3fThY5kEK1R", - "marketEventQueue": "Gnmzva1QiYyPCnUHoqasDGNCc6JZ32dqAdAiKtr1fTh4" - }, - { - "id": "E2vi6fNF5J6DKhFvKU3MSDQb2pb9KA6QYtLBd41uVGPt", - "baseMint": "8ZepSXp47WFyDK21QbvMiiKVWRHnGrAegiwDr71PfGi3", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7nK3axopLsqM7ArFwqL6hLbXUAketQwTTYjvhpESqhh9", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "77AjXqPo9JDipkBfMcKdAvWUydkK8PFVhphUUFA8Bcve", - "targetOrders": "CyWM2thqCvRUDhHekkSWYXViEwKUcXT2wygSiEc6NSp3", - "baseVault": "5WRgP9ESmhmWUuQXpGEaKfkTk94h9QJj4tmZ87SAfQX1", - "quoteVault": "FvHZ1aczDyTXiPUpMMsorDcuMzsX6bBBPa4f2p6EvKdh", - "withdrawQueue": "7cTXBhya2fKUc5YBAortvMwShgte8Qn845jnyTcGyRhJ", - "lpVault": "FzpxYroEHXSF9eJERS6qVTw5ZDcEBt9fvGD8cjAmr9ES", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3QGQEh1WqhEicR4YJHcWf7wki21DSCDgY5S3HRAa5sZx", - "marketAuthority": "686xnDo5W33eDwTABV1bWm9DX7EcUNXd2qUQjb23D9py", - "marketBaseVault": "CaDmwBWwEkJ1UcDXrd3dCHV82Ph3LhCmia11LkVDXwYr", - "marketQuoteVault": "3gNaU6By6DjRF85Y1a6gXnBpAa2R16hjL5kKWVzURMon", - "marketBids": "7C6MjuzjigvZf853KQ2TQfmuiTah4YCXojVEw1Dkt6ot", - "marketAsks": "AM8fensQirdmtSgVZ7imdbz6kkwphvf4tnWBETsVbq6n", - "marketEventQueue": "49AgNf4AcsQytA2LaNrMtZySXPhXa1HWMge3N38dEoX1" - }, - { - "id": "E3346pPV5qnqUQ68wLHZ42Xn8oPK4rHTmoTFpPn3oadZ", - "baseMint": "2ikET9vxPYEf28XwpqRewFKizij1f1KqgyLqet8TMUsa", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "9YgacicfXzAhNfnk4Xt3LwSGq58DxHfyBK8EkprT6DJi", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6keMX3rTcqQWSRzLLqjuBiK9j8fZ82rar1iQL7q6WNgB", - "targetOrders": "ErjjTVka2VBX8YvFTPvRj8fC5zZMAbRrLABCP1E8cZCK", - "baseVault": "jSwP3Gc4LAHgdhKS8U5Xs4KX74QsF5EUdAHd6tTDMXS", - "quoteVault": "4SatNZXivAYL6VFHTqVzLpw2tSBahBRRweWKTSYs6DRu", - "withdrawQueue": "4d5qZHdPaSZQFXSRnGBk8hn9SX4mJ4JU9yDA1f9L4gaA", - "lpVault": "8fgjGtL42zeQAfd4QmWoWUxKx9uetmGYBne2GLG4kfkf", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DacuR4hUJGZQpkce1ymAyBP1NXtxY8j66TMrcu9ri8wS", - "marketAuthority": "6GkY5jDL11rvjwN1VDdpngEX2riCVuspYN8N7UFxhg1B", - "marketBaseVault": "EhDnrR8VRDXAn2sDcLN3GQvzRnNjBAGP1pZrnuPJY8Nc", - "marketQuoteVault": "Bm3EdZEiZjwp4LPN35Fqr2SH6YTHXpXniNppcU3Lr8vA", - "marketBids": "Etjy6kR8rwPjhjDZYaTAMHsCy9qW4Cm47fCqMcZ8z3GX", - "marketAsks": "DxFfqWnsJCszb7ZjWfkRKHQA1bHLz7y6Ekukow7E2ZGX", - "marketEventQueue": "9XiEt5wSAvJp9n3WRuGPJvXJHzVb1CVizTCdhya3eiX8" - }, - { - "id": "E3sxW3YW1Y5pDYFzV3FX4ibXT97Pf71HbnUNqha4rZ2", - "baseMint": "5K1JtWpdSksVKaL6R2DuLpCDAjzxK6sq2CpXaXDWHVLg", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "FMnr2ZqLYrod46oocaRCCGMK71FAGPHj2gLSM97pt2dc", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2mn4z81pM9TuyCpknULA5GwUWDuVdWzMHGpWAPMDWycc", - "targetOrders": "F57uy93DAvPFpnoYxhR22bV5qATVQ6fMuiq1nBjnabqU", - "baseVault": "5QWRwMsX78aNxC9PAgzY2qqjepHGY1wu2ezLqSwZVqm9", - "quoteVault": "94m32ErWTRFuHDvJYoHSuXpJHuvPS1Jqj8mQFR3h3GQa", - "withdrawQueue": "ADinY7dUgU7dYmQicLw9mGbJF2TJZJNxxg8eVU6AJUVN", - "lpVault": "BNAsYr7K8FYg4NvKwtzVoT3AdhG9czV7VzZU8rpXRQug", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2yAM8Vnpv3rNtN5TDunH8r5QwG9sZhQsGKcEdpRi245n", - "marketAuthority": "2LSW8jhXU3ZvmRhkfQ1EssErAY22WfKih1qtWBcrdmkZ", - "marketBaseVault": "APAiQKDacwG3c7TYw2tyMhF3oCTVXDirGAfA3VDSv78Z", - "marketQuoteVault": "9M54xcAtorhYXngkpdhJrqm5SVHSFvomdYKQLq5ABpRN", - "marketBids": "2tXGq8B9hGMfZmZR935J228WFJNqzPbUzoTwqgPwDZhH", - "marketAsks": "3zpBEHjqnbL69RnTLzDX9xW8Bepr4SxTeVCcvqy6MjSx", - "marketEventQueue": "5mjZVJcnh3A7MqXJKknS2y3Xbvtn9VTtosdK6v2P2g9c" - }, - { - "id": "E3zNWb5nzph96Ji8ETd4sNYbxpufhPTNL9siEtZoHDYy", - "baseMint": "273J3F8tD4yncTX1MA5VwHPLdxzg3VCvKYpEt34MSCBb", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "8UvHuiBws94NpausngFa8zUq7WuTtY7HyApa9Ff7i6am", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "71vzys7Ppjp3cBRSiq3eRZasYh8F3Utp6TJfQSkhbKxQ", - "targetOrders": "3YfEYVtHB9JYY4m9eNnvNGhC2WQDZXhE2WPYKjwpobbr", - "baseVault": "86RQj3rkF8Z9dPTqBhS5fbdvsHayYaDhREpcT8pZtm5y", - "quoteVault": "9tmu7SpAgMR4njAmZ6KK2H8h1Fh7TVse19np1gPYCKD8", - "withdrawQueue": "EYWxvBDugm4ScqDpdNdz47UHJHt9xmUzd3oLT3R76LGS", - "lpVault": "35zG6esCghsMmjzLJNhunk36MP3NiD6GBuiEqYkA1dxG", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EMerGMrQCSg9moxho47XzqRzuvUaeiEMKwUDjUc6idQS", - "marketAuthority": "3RFWGgaH9ayNY768xnnoZipe1Ev12PSMgxLAoaCauz8n", - "marketBaseVault": "EvuWhgbrz6w8yF8f732qhHMnHe6XiFdrr53PYoWnmuuE", - "marketQuoteVault": "DS4H29kB1k5xsS6JPbjn6LhKKYw95fm4acBructm4ZnW", - "marketBids": "9gfZtjvq5L7MY44CDZGywbUwqSnqiRnHTn7vq57jnuyo", - "marketAsks": "3pB3aPqMTFCRMGy5ga1dc3W8aEKcyZCnuHfd1E9CFGVD", - "marketEventQueue": "BBAbi1NsdZSr6mYJsqpNNN9Er2dct1M2xHyebPgFe5Kx" - }, - { - "id": "E48VbbCQDWB2C5vGPtCHycAgx555UshLNTwbaNjPY7GK", - "baseMint": "DUSTawucrTsGU8hcqRdHDCbuYhCPADMLM2VcCb8VnFnQ", - "quoteMint": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "lpMint": "8Bfg12Eu9Ca2i1G8xUBN1d7u39Nu4oBenYSEq3GeBAoj", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ER7ukgPXRpadyLVKsVft6cfvN4svJfR59zfCH3Fd9oR8", - "targetOrders": "2DuPLv6wBjENrR8GKvP47ZBpGRPErpnQwV5SNhbM3CiW", - "baseVault": "EwKjiSkFygn3aYnqrnQGwzdfBDXskdqjJGemv7nj9krx", - "quoteVault": "4fKoBSzamAwYzAiY671qtx37Axj68BdQeB4y7bNeudr8", - "withdrawQueue": "BPkkDcxyPEyebskFxHUoKJDnLQQL3FnXRgptmgkVwtQt", - "lpVault": "TTngMQLsybs2LrRQEeGgDbmMbetE3X39fd2c6qzXSnK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9JRXU2JUhEpo25SJ1YZPdoRKZEaCBUk39X6Em71qKfBk", - "marketAuthority": "GSa3nEr9MuVthiribRA2XHgktY1z2xrSCJX1PsQrcSh2", - "marketBaseVault": "ALnfdgWudZRidCoZKB65YgHNaWjHR81HzimQUqQhpjCZ", - "marketQuoteVault": "4x5YjA4hdHXuDZKDGQXDcVJNShXG3CZS1tBtvZiBHBZo", - "marketBids": "J4hbCkZBkJ4SDuZYQS8gSXG8BJnR51SEYgad36q7abkQ", - "marketAsks": "7Gkx2dwC4EayPYMtwRa9YjQ8tkpJ1QA9RHj7gYHujY5M", - "marketEventQueue": "4JFLf19Ror7k6mLwha6rhxZnAPCtYpsty84VtzAisgom" - }, - { - "id": "E4LrqfBsPX4MdgoW7gF3rCW8Hn5eV2cPyTR4d1z4AwZU", - "baseMint": "AfXLBfMZd32pN6QauazHCd7diEWoBgw1GNUALDw3suVZ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5Lo4wmbTfCyu4XVfaGDHCQZW5d54kqe9aeoX15KkfRsj", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HS4V9co1Wx32Qo7G2xw2VVadkrReiCXde8bvh8gWKdgv", - "targetOrders": "5NtfFgtQFvufYSB2hy2QP6cMvhxbdXuGHwzush36En6F", - "baseVault": "4uafeMd8VmnTKbmj4epBqVEK8kQDCLuGpeGaHBB352Si", - "quoteVault": "4BFAUFrdz2bFBnuhZiPGJDAYXGCbqonsxJA5oqqs6KFL", - "withdrawQueue": "8TfdhfRv3nf2Lm4Cn8kN58NaTyzzgb5SqjeNiot1V8YU", - "lpVault": "FBjSPnMXL1Mk85eKtJcEtinKZgNjxtcxXQEnmgf6BkCK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5p9SsXwx63eiyuXDmJv6ecdffy4xEW7iuNkqityAt285", - "marketAuthority": "93MsCeqHc3XXAvXxFzwnLVEbwnHaFdSjJ33JmXN1nxeZ", - "marketBaseVault": "DTrkgP71fzf5h8HqxzEq8TJpdUP1cnKpWBFPKZhWFrWE", - "marketQuoteVault": "D6UrMQCkzR2bzdadq9LEreqRckcvy9aVRwj6cTVKmLEN", - "marketBids": "8Mcufs3KLnjLfhXqofAF2FiM3qsnZX77o5D9FXpCAg3p", - "marketAsks": "B9uz4HaUzoar2RUrwXJ1aUYwvpoArqubnM68JkjG9pdk", - "marketEventQueue": "Eu1K8CnGob1N73JHqSxe2cuMWAPjKdsd3ZU2LYAciR6c" - }, - { - "id": "E5bWURLw3vZ8KsWVwVLyAHc6gLKumUSsFpJLiT3PcZsk", - "baseMint": "HbrmyoumgcK6sDFBi6EZQDi4i4ZgoN16eRB2JseKc7Hi", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "AZLoV2aBuV5FnosDCzoCUeXb3D56sM9KG5rP7tn9HQQv", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Bg8JKmjhdYB1BcRHJskpUXqMaPqZD4xhS7s2tYAv15ki", - "targetOrders": "CDe82yrhVPr1e1vbEg7dTEi8YoCnRs53bLwjcx5XdHjZ", - "baseVault": "61erkw7adVbndEEBUgk8KWdYTsDHPECR9Ao1fNLuJbCU", - "quoteVault": "CofSEy8dh3Rkn1FLdjwRiuY1ZZRRVY3Uu2owkcBV7AEB", - "withdrawQueue": "3QLot9WdsCQEEkhpoCER6HEi11Wz351Jc45ccToyeUgv", - "lpVault": "2CrkEMLrSytom2BQFZbAQMLLV5qpD8mC4k2h56UAZyXB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ESmbZckdRFv1F8aJ9CfcAsQ9JQchCVgXMEd2UimcujHU", - "marketAuthority": "BQd8nfxGBB6VsPkiQYSDXfVj1p4wJm52cX6MJpNGAdDR", - "marketBaseVault": "3Rz4yBfELk5Xwdj99sm4AGRtbzNK3mEFybmHbyVCCU2m", - "marketQuoteVault": "G3PCT9KkxuZjnsWRth5qz1r6JBW6Wbnbb5pFzKY4i2C9", - "marketBids": "6AhgCaFKsoRoGpkBYriDQsYvF3i8NsEP6XuWymzg14zY", - "marketAsks": "CSWqMXWbw2nVHzbNPgwzPyezitcpxqJqC7ZGGart9xpM", - "marketEventQueue": "3auJweShccf1pcPAiTqVAm64QSFeUmcEbxjdgFNnT3Dp" - }, - { - "id": "E5kK7S3LAxYuB8smUUHQikUkjAGByiqkZ53k76dfhJZL", - "baseMint": "E6Hkw5o48QfNo6iUi1aepjEBzVq4ZjQLxh7xVtdTqoyB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2ctrECkHT8bGBumAWervX5P6epS8bc1wCpofhJtZUpPL", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HYWPMJu7VLBvv6Mx1K5pDyL537t7Z9rU2CJuekiJZnor", - "targetOrders": "7mhzuZcptzteh8zzRHtb2MNuy1XoGbmmmKA9nAtbDBLU", - "baseVault": "FZXM4PjAMGXGT7WLXmUVbbZvPu8erz1fwTynqAGqDeCE", - "quoteVault": "Aujtv7r5pzG4oWVpKdAvwA9kqDVBztixN37tWvq9qHrH", - "withdrawQueue": "9Cbtbg7uDHpE1sygTTAwG2peXNZgyxXUrP9u2HAi9gcy", - "lpVault": "8CRHvQLVeoDrypSKJqUhq7V4bJmfd2oMHhVRshPjGfz9", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BmT8C9BYodHEPX8YC9ceXDugtYU2uqQiSp29786kFfd3", - "marketAuthority": "72aAvtnFjdHxvZ7w6vL7t2pVjmwUG5n17BcymMdgCNDo", - "marketBaseVault": "DrBsjZwwkLQHsfkBCFdZDhzrJRbtekrEUc6HKSRbbbJT", - "marketQuoteVault": "6GojMkamrfa2Kx5Sc5vniV6f8W6BMJMuZHkW3frypnD7", - "marketBids": "8c1TCNa3FSATApvoHmvUzYhfuDurM9YgCExxL2U2svWz", - "marketAsks": "hfdaBW1SUuLzEzCLgdpzQKgAyMWT7XRg4RUFNbzpxQQ", - "marketEventQueue": "CJ2ptoLxkgu5S3EYyyVQFZDEdtobERsgB5C7MNUfC3zT" - }, - { - "id": "E6DXqirmm4LjCu6EtW4jUkKbvPER4jhpQ7yi12jGzE44", - "baseMint": "DjPt6xxMoZx1DyyWUHGs4mwqWWX48Fwf6ZJgqv2F9qwc", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6zGdyNKvvESCreoJWF5vsjMr2BByCnigo2MNzbxJ2vq4", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Fct9dXHz4N69DJgmwZht6znCQTBxqsCfWadst1dX55k3", - "targetOrders": "FbJqUsbo2WmsaWj6fKSPqSJ7AU5S9nCE1hhXMtDmNTbo", - "baseVault": "3ZeMbjBrzGbk4Cyzot5mWtgUhpHfZdz6p97mATz7pnkm", - "quoteVault": "iAFTSMDQaszDixQPseMrp6UFj14NuBkjbinuENpueFv", - "withdrawQueue": "DK9EUsSqGBMysyTAZ9rab6vZduttQyjX43esVKrvvkHy", - "lpVault": "AkrB9HdD74uqVHURaUMt9yo3FyQ4p5tZVyH5cCMLwx3a", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "59wEKBnyrgZMhHAtCYaoWrr7rFotakUTPj9QhBu5aVyJ", - "marketAuthority": "6uALCs52RD2Zqmjdwk3ePZcCipN26Yam8j7mPpuDLTjE", - "marketBaseVault": "7d1wCxkwPknjru3EGwE3qQG9J7b4EXtN64L7QP36zRR8", - "marketQuoteVault": "42KMNyRzBEcCU6CgR7Gw8GQGWknJcuyFQkMRCG3cSC3q", - "marketBids": "wZ5hdtTwzr9f3iyLgXF7QpifoP4tEGR45AiT6jrTYWP", - "marketAsks": "71z72xhyCntf2V5Xyj3MpALpputfaNW6yaZUC738Yy9f", - "marketEventQueue": "EVCrUvRAEwb68dKHdFYMX8YrBVaKTmXUucUj57Lq8DDa" - }, - { - "id": "E6f84t8DVaBtKSsqtwtMsqwMUMxTzsskEBZQuznWQJuM", - "baseMint": "5sM9xxcBTM9rWza6nEgq2cShA87JjTBx1Cu82LjgmaEg", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Eo4SnSH1VGetKqytejZ6HyymPE3Lc3RPgX4XvxQWNQnY", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "61mBSkLSC5EuwLMusV1we2qUGzXEjiMBYhZq7KdJCVUd", - "targetOrders": "jq3nkWBrGSNR7dmQDJsEDTEqkWikfxeKMwH9aS4WkKQ", - "baseVault": "8VaQpUEk1MUnr7HEgcEc9Vt4WLpnZnAnojEkZyo7PwJi", - "quoteVault": "3AhanjeN1irZmy3FezjAKKxQcvWskXwQNbTn1rUuy8mN", - "withdrawQueue": "5QHKnmpXjVXs2NMhN84TeCN4EJzt5hUwcZySEFkjqeKn", - "lpVault": "2ZybeqiWkDFkj5NEWmkBTrANRejSMQxfqgift6WaQAjz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8dpaLWWPv6vFong1D8gHFDmYzHQreXuKcui3XCKBACCj", - "marketAuthority": "BKZ3BcAuqofQ3kgqhj2MtqyBDv6898Jjf7ouwMZgriez", - "marketBaseVault": "3swzKSVLxvsxo5G2B9mnAgFPNGabxw1j12MNbuqVGs8K", - "marketQuoteVault": "HSNe9HK5f66NMCnA4uUFrBafGvv1dwFEmZZrPoZzq9n4", - "marketBids": "CYGo3GHc1K8xaqzmBfKsWgxjXZMbvE85LoKpvkdp3TEZ", - "marketAsks": "5QAUQHPNLx3fq82yJjVJPUBF7H6Pt7aNxrwJ81hMtEWM", - "marketEventQueue": "DLsUePYMUaw5p5rUsafHqXVFoZzbnQmEWovH2UKxbmAb" - }, - { - "id": "E8ckBB7xgj81TeCFzvpY9hLJh7bx22kT4seCUF53TFVE", - "baseMint": "FSBXL2BBztFT9zJ5Uhyqz3ZJEoAS3uAdTExVSwqcTWbv", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5bad5w2CHb1H5bVm8N2EXCcAGgZbtGT8ESoQHzsErDUr", - "baseDecimals": 5, - "quoteDecimals": 6, - "lpDecimals": 5, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8K9qRYDDeexWN2kYmurpE46Bc64ZrDBQAp8HwFYbYTwm", - "targetOrders": "BB66t1ZYS7kAWPruzCDH8HrfoHWDtJ9k1DZWiZ1UMypg", - "baseVault": "H8AJ6vn2QT8NdLHo96KqtRHf2KESRBsBBdH7gEMFxgH2", - "quoteVault": "6raAUnrxJqo675bpnU1sy4xdPcffDJedKNXQqzGFnXSy", - "withdrawQueue": "2QsBLFfWFL8Tq6wij6NyVj7KyZ7eLLhUYmbWVgoUDqdS", - "lpVault": "9EwVhRXBRJZ59GwFuU2hzAfEZYzbB68qv43VjENPF9bs", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "228P9s6b9rTnW551NVdm8UNbHQfxSTj6AnPXG8E6KxYa", - "marketAuthority": "5ZuF7wVnACsuSutHP8oR3abb2iDrtVWK7WLbxTF343rx", - "marketBaseVault": "Fpt22AnqtVNWzE9vs5nwtY7iAqARyzkQ6WdQiBoTFCPL", - "marketQuoteVault": "4xd4hgkwTDnh7zUYs1dRSEUPKrUNLoFxABNV1nHo46Ng", - "marketBids": "EhBgr6PDhvZE7SYnpWkqiiTR3ZYoKGudXFm6Skm7AWsE", - "marketAsks": "HqvywwPmQx6c3SPXXiZDgyP6C7skJqdjfPF6NdjSAzaM", - "marketEventQueue": "2jyJjf2vYih8DzbxpL2x9XN6vRHsxjn5NV3Z7SYCK9sj" - }, - { - "id": "E9Bg7Fg5TVSXge9ADN7fDjsR7MXRKsgq3STJ9aCdZoTZ", - "baseMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "quoteMint": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "lpMint": "DWk7Xg8q3jotVGuVBteJ31PjdmEn2iyjQTectbrkjBaq", - "baseDecimals": 6, - "quoteDecimals": 8, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CjxJmstrrEWWsSsB5mni7c5xpw318G6RYQedyZNrVmZ3", - "targetOrders": "fGmtAtLo69KjY4qdP46muqWk5qct6cXuaxZoaZCBjK6", - "baseVault": "2qjhBJrjrmjcdjefbz2MdPmLWTZygpGJuN4EzN8uTZMX", - "quoteVault": "9Uxt1Hc9ynje4m6CF8a72fMQWAg9Aw7mYi7Jfk4tpbgt", - "withdrawQueue": "7CjLtB7nt1hF3dJkqGR8CSnkuHA2HdtsxTYXPHx9uCH8", - "lpVault": "BtsLEy8MFUhJQAvXaw8cSXY8PomvpAJ3f6RFQNcabc5Z", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CHRHzGLaQja4dj1ysMmzkNMWGSn7wQbzeuAS6BYYL4rd", - "marketAuthority": "3a7Ch4e3thFscgvPM5DLfcMAVPZTMJziZdAg6K7xpT7V", - "marketBaseVault": "99mCLVgi9x7x6UWyoq7d11EG6q18Q3xkyMWuKdcm4mBN", - "marketQuoteVault": "HQUPs1cv8NWgnwWbftctfpvyLtTPcTJX3NWBp8hqnZKP", - "marketBids": "7EgBRZDcWJEZSyHwc2Le2YN62Sq1eL9QD1MqcgMXk89P", - "marketAsks": "BRBNSDSsPF136gNgEmrfCfgJPGQFir7HyAQ5g8Hw9xLX", - "marketEventQueue": "w8QEaxckzg9Yj5PwbRC3TrCnsJAsiw2kjY1B9AxHid5" - }, - { - "id": "E9J8sKRVrKDAw7q6aytJjFDmtocHpzkb6vDEzQKFxGWB", - "baseMint": "GX4jLVsWqmDKTsroc6MedK4zwL9VuUWt23DmaBk9XMWf", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5BEX9TMNeGg3k9hiNVj5hoE9T7rp8y58cTNDp6nD7frp", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7BsicP4DmXqhvJPvAre1ZNjjA98hLsoTGNBUnZhixQbC", - "targetOrders": "2xxkqSJ7mSujTSwR91MiAGEg55xJSzbR7UjNjJ7we9sB", - "baseVault": "AK25f3dSXBT1fNJ39UQJy2VEHecVwR9qkG6DWKZz7H7W", - "quoteVault": "5NK8H7BMymwcGseYG61DM3ia7ndTpCxpEdscGAtstsxS", - "withdrawQueue": "BxKxXviyVxDoYEgYYBExvrtGjZEhvA26isFPCY7vn52R", - "lpVault": "Gr4di9ShsxcgPXme17dcifisXEdVMdnDWpeFcuWHo5ZM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "92GwhustMUXCzHFoYbadkViaH9K35kLb9tepJ5bqiwvB", - "marketAuthority": "8sidHqXdguxAtSvmHzNziKTE9z3cyxvHhrr9T4GNR66j", - "marketBaseVault": "29qToXKnHeRp8WpQQVDMsJ1V4Ye6dvVg16Mfg2AJHBKZ", - "marketQuoteVault": "C9ztLpYe8pRpD5AvMcaDNn1q7UX4HpQkhWppPVA4c73F", - "marketBids": "2TzM5tyv1yeDcuedWGgrDwmfM1g1ihuWvqJuy239omAQ", - "marketAsks": "9UaqJHf9cX8Xh1zprF2cvMYniWmJQfP6PZH7F7s4a7rV", - "marketEventQueue": "ER66UKwpYDNkQpFu1Zkfz7762WNmQrJwtNP2cJiAA67h" - }, - { - "id": "E9WGh5GQ7zrF2e4VGE9hh1CnoVQ8r8kt4sBn41tgLnvU", - "baseMint": "9mXZ54YnJJRmUN2MaMEtWCfFyoncP4ZhKz7U9DZ4JY2X", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Egsdc91TcSypf6WP1m7frxKwxxmA9zfXgBBd3ZF8c6rQ", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HWXn4joUz1gDc3JxyFzhyL19ZTCyZNuYPvErJRFPRcCX", - "targetOrders": "5k5BX9Sfm6pzafbA6ULrAzFCTjargfv6PpJguYFvjH7o", - "baseVault": "KrNDRstCXyMtjA2VFExdMPkJwv3Mc2vYvpp4WJq2yLA", - "quoteVault": "7sTViGs7LNVqvAg4yXEcLWswHmiwbhwb9wLtjMucuKms", - "withdrawQueue": "7JyGWUsAFF5BjEtZuW3sHGKzNNFFZg6Unmcg2P9gU9Te", - "lpVault": "EEqsc4Y6TgBgzNAUkBRrvvBNuZ1ng6eCUSNoaafvzhZF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "51sm2KNSA61wVgtoXuV3d3j4AXZeGxcVb8JnH9yxXWGF", - "marketAuthority": "CoDXn7pPGQrPj5KWZWctSYXy47ZzGteYz3vdzC9htNA2", - "marketBaseVault": "Ea9PEkGCpNDugHagCLf6yLejSXt7VV8B1vMxD8sFcrr4", - "marketQuoteVault": "4RQ6FetKKo5FBRsY9sahuQWBBpVw2RSpfTrVbJJNoo5B", - "marketBids": "5PYqt9yEwmb85bTeC4NUgFRpABmivU9arzSv7qjUG4rF", - "marketAsks": "C4GFEgqMBK41X8KqC2qD5wn7SfbhF4FtnbZFvvGUCyoN", - "marketEventQueue": "FYVTy7jXikLLchas7pK18aZMkuGmKD4Xi56aC5t4wJj9" - }, - { - "id": "E9xzKQTLz7pMfTxFJVokTCRLuAARdG57PpaR8ghrajVJ", - "baseMint": "FiCiuX9DetEE89PgRAU1hmoptnem8b1fkpEq8PGYTYkd", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DrEVMihkfczEKZkJiHamH4ZYUiASg76qS2xW3PUdbXZN", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "86AZTdvHwXoBHrUEj81x39E6vgfLmeiEwgaz2ceuwVYT", - "targetOrders": "AxAW92VoQY627J4VLEtsNBmPs2BxPZWQyBgcdwQkssF2", - "baseVault": "GMrBw1zhu13tZtxiT7YsB1pJqGbPnXu3ku8wbhBosjKK", - "quoteVault": "G8WCv5DWMAGzQ5E2WfYUK5J5yN9DoiniUiH1grhcB2v2", - "withdrawQueue": "77yi74gginvQpq3mcWa5VYhJXtRmmif2g1k9H1EV4k4c", - "lpVault": "3GAapmhQSjQpFBARrJ3NNE3JYqXEVYTjvLZ6eiHqqHGo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ByjsSVF1FLHrMDVR1tw8tpMwSjR9hnW9YBHjzwGPbjhx", - "marketAuthority": "27nrbv4m7YFk7d32T7aBxiDxgBDPLcKcRA2S4bN4AC95", - "marketBaseVault": "D8JUNpwBYLMvcixhC9Fj1ndMzQUPo5AWWDLzZYcYEK6u", - "marketQuoteVault": "CuTYVsmRTXZyqLDjFrFPwxVN3pNWZ5gPTL378gdxo61o", - "marketBids": "FJJMGwCKiYzrTAotDngrYcENHWF1LswJj5tkfmDAACKV", - "marketAsks": "CocUoWPDiocYNSL1R4peRAHshaVkvWj21maHgnTYdsA5", - "marketEventQueue": "2p8QzSGZFuHfSVA79xiN7cjGfeiAi65kLDc8U6hPKgMp" - }, - { - "id": "EBdyZ4vV5zSCWVsVmkexbPr3VrTUTx7ej2bPa89x1ons", - "baseMint": "9XYbEGVjBK2BWvtvjoJBZtnoHtkkdGiw321tdN6eLa4A", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "r5LNFUiHZfiXur9Sp7NXLMrR2QgVJFGPX8RgQRhv7t7", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2LEx8C8CdPgTP1tTzSr7h7w6KRMSwxdkXe5KsS46VURc", - "targetOrders": "4cUPgEKMh8hU8WE7x5d9zfGSeET1pXuGuNEbqWMM8iuh", - "baseVault": "WMNMBGKGjCxJ7UVU1CqAFiy89HTGhP3Hhn8sxTLrwLF", - "quoteVault": "5VPG6vtqhwGoJfAJYjep5GpogXWffkqVmAYXQGgyUSm", - "withdrawQueue": "1fTYzVzemL1aZJZsP5rsyTs12KexEnJDNbCiKdX5iN4", - "lpVault": "FyE6QXNiNWaPiiCqpwx71ndBKB9YxAKt2xKZEwRCqUHL", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2gVQsPiQH4fLyB4C1QRBdv92vDM2edQkeyaVLr8kk7cM", - "marketAuthority": "HFob32SEVMz4qsECVbGf4zY6Gu8eudUCSsXyPugapaET", - "marketBaseVault": "GRoKofA6qjWx3TU3hTUDGxxB53w8MMdD5fGUT7s4z17p", - "marketQuoteVault": "8oBzFTSN1XfSvvpavLMSxZANf7DXg6UU8CiGhavYqMVC", - "marketBids": "DqZpT93zWLC68p4JHKwehLQVFzhkXc5Vu8JvK8DfayVY", - "marketAsks": "JDMmvc3BdqqutoohbmWv2SkC1ej7UYuaT9PZDwCz6MWC", - "marketEventQueue": "3hWhWC2Yp6zh8wtqXCV3mFS9nea9xrLCLJdLCm8gTkDt" - }, - { - "id": "EbScGGiM8AP5QtPm6XNkKEsfgPTSpA7LSnY4n9ntMXxz", - "baseMint": "7Mfsbr8vS2LjWTFspTgfLPWm7s77zvJsevBuW4P9MZ3m", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "DDEkWEjwBC1eVB4tUZ4F73Y1gWG6g2uE1RD4TAbrN6At", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EPMuV74PXkTN7JwtDkeMRSUuiTQQz4k8Su5JiLUpi9kS", - "targetOrders": "4HjWbBY9QBiTmX11sW33e4h1AHeJLJp74BpydfPEeguY", - "baseVault": "76fvZVeryY1cCqP7oeH2jsZ8J5kovSugHYPUgdSUXTNq", - "quoteVault": "5goxLKaeZNzTzRRPh5GQcd2ATP6FcDGDb7JoCc9UczD3", - "withdrawQueue": "E5xiNXXca8Y5C3vBKaeC73DsKrc2oyaWPPzKK57UFVo7", - "lpVault": "5vVjEMmR1w9zQRtp1RV4EbuKG9nWVaz1KY5qymfUXKoP", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Ch4YQikpTQot7kjtmfiCwxc99U4Cih9mkvSWYkvbs5Ce", - "marketAuthority": "E9TyW99uHN8rnQJNgSJqHPhAYVgGzmm8S3MsyfcNHxRp", - "marketBaseVault": "ECct7Qws64kVKqXyqQESejYVmkesBvdE6wuXaHVDkDZN", - "marketQuoteVault": "9pk2g2Au8mvjJzKx99ZNCDRzTs6orV6P4QhAyovtzp64", - "marketBids": "Bz16PVQ9N5kvqnueC5DsieHoxUubPUjh9wzhyD5VtGmg", - "marketAsks": "C4faFBLYLLE1YmgcWdRjsDUX1VipgorGaGaJ97HxEbmq", - "marketEventQueue": "9wVHdji1Yz6BPkm5vd7zVhiTqMNkfi7Z1o8xKSk2o6i" - }, - { - "id": "EBZbhPp7du59gpzAwrhFRtBo3MLiG224WwnbsGPPPu9v", - "baseMint": "invYVY53mcmBtf2RbVudoqKDyAgZGofkLYodvnQwQep", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2DHm4faSoxag3vE6Bxz2Y4pmxLVTQ6hrWjeg9kM3JD8u", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3uccDQT99dxWcrx7DzrAvKYofSLxzDL5PqrJkvhusrK6", - "targetOrders": "4FmVLdpMdbt1a6N1wFBJqxjzsQyWxtF4QA3ezmnhVPrk", - "baseVault": "Dtkby2gjGRNvX254EYE216KbLjX51jFxJLRg5QfG3U6K", - "quoteVault": "9DDMc2KvK1LLtfoRet2FL8WU9eXVnNfr7tKH8oy7P9s6", - "withdrawQueue": "BmqNuzSFXLHFr8Q3vLHMUa1CN42Yxhjd597Ppztifer8", - "lpVault": "384WWvvAHTFQBxuVd3YY1QkC1h1gayCJBWVqzcVeeZhC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HFYZGQVGuSoF1NTW9gWSvZ7mPhxYt63intGQAhJLH96G", - "marketAuthority": "3uXPQBezRjBksKgKvPLdFAArrvAwAqraRyxMMc6ijVdT", - "marketBaseVault": "Dy29WMUGkPn8F1BqzmoYSHiNyb41x7MSwMf6nmdC6ARF", - "marketQuoteVault": "HkNBL7Rn5kZ8mf6uYSjYn98rHzg5wC2q73aYmg9d5zDf", - "marketBids": "1txac7wSdmbjaA3TPEZQ94p2im68gm4zP3eUXoq2ktj", - "marketAsks": "EywpSWUHfGKKKK8uJ3wMhGTeCNPmWgbBEhdXeuzT5H25", - "marketEventQueue": "6iYveViLDckK936nyukKVfJCYpxxvkKcjL5sAxmcoEAY" - }, - { - "id": "EccDHEaV7rU41CxZx1Dx2h8An5V2KAYtjA3EqAz8bfDQ", - "baseMint": "2fgYu8vYZhvVsocNM4y4HcrZCCPXYcoo8mZof5hJ3miw", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "CCvQkMGii4cyH3W3huwf8GsWZ8QoQt73gAi7xSWkx5He", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5WzuqKgQNJfzLxv3j7ETxf9Kb4UoXmut7zEkuzp8uqcZ", - "targetOrders": "4ucZcEUtr49oCf1K3NvarN2k8dSWxDKTREBapp3jScvo", - "baseVault": "BAZhVTT7Nn4nD6dgjxK15ibmYBXjbiGXGpfoHvunaCpC", - "quoteVault": "CSKppuc7i1Qzvw24xyKEkMYJThXsmWEJSR1W9ghHJBd9", - "withdrawQueue": "EcEzeocKharXDjuGrD4hcjJeJiDgTJfi3iQQCTMWmhrb", - "lpVault": "Ak6pnrD9xasDH7LdfoWz6nYBKrRi1ziYPmMB82XKBQNE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8S3338PhWkJKzA4tHpgZn9pmC4Z4vTqesGtA9rEXwgJ", - "marketAuthority": "FuEGgrVgysv952tV66V3zzMWiZvsLkBBf9ssWsZ7DJMq", - "marketBaseVault": "HcyfaxSGfTSaQd87rVPuwSUGf6Q4gBEpgerDr5rRS7yK", - "marketQuoteVault": "37zBZj67PTBBjVrnGEiWWrnmyJqBcwW5pKo9MMLUVKEL", - "marketBids": "4rgvRQkCqYBeKtyCY8uZMj9sNzBhTcQ5WzCMcovg1Xm2", - "marketAsks": "5fKH5bddFduqttpRqo2bLtuCLA6y9PchaTgKf5kXVVA1", - "marketEventQueue": "8eiyHXBukCQF8ThP2sHnzAzhaXx9rM2AmCPEuCbzfwM9" - }, - { - "id": "EcoRYmUvwykYzta7hTwxqmk25oYWdpQQpTDrp7RYBDJD", - "baseMint": "5abCYCzwJLtazvtAZEPcHaEoB2zZ6xNFEmM36o6qyAHy", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AYjXvcxRPJBp76jyHK1xWpDZmtHrohsMpHgswcGMGaK6", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5M4DSYjNu7bPTN4jkopATXp5pUDXsC3HY2ZVKMAx911W", - "targetOrders": "CBdnZxhfnNWzesrgmibKtD2QsxvpWjxvofwURvZzNHnL", - "baseVault": "5hP6DHXXVdNTcN3J9jqXvpzuwVsxGBaEdhwLbVQM4wch", - "quoteVault": "Ath4Yfj3R1VQZirYh2bgQpShYThQZRAWD1F8wHdFrPoB", - "withdrawQueue": "Dah8DWfHRx8u9oKSVGDjSkvACF2k1Prdi1vSMw9ygqzn", - "lpVault": "DXKe9ugc5bEJ5yVK7yUsXrjWEmu6UGApQdpx5GomCMui", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2ceEgK8EVErJWLx6B1KtiDYmD3YZmXgpvsXdzqXVdrZN", - "marketAuthority": "4FLV8JhQYVvhcYBDzy1B69FWMa9HS1kwvqKHEPmjakoa", - "marketBaseVault": "DBwv8cyUHt1KTLAMqxyUeeE8g53K3FVMjZzD63CYD1mx", - "marketQuoteVault": "Ce74n1rQFqj1xdbTR2sM6efygLoCtTXYYaNUfJE6wpxv", - "marketBids": "H2W54WADJQiyDhea38vGhfZeg4DzppYMX1zbNd17x4AG", - "marketAsks": "3QfUhdPPnnHmM28wN5XyuFGs1fYDKZJGjhjGs5cm98dJ", - "marketEventQueue": "8BqLtXUjQhpysakQHeswJfeKu3wPKNkKo92btp3Sh7br" - }, - { - "id": "EDudY1AYk9t72DtzhagzM9y6G8HBN7aY6eVu3XWG4WT9", - "baseMint": "6ybxMQpMgQhtsTLhvHZqk8uqao7kvoexY6e8JmCTqAB1", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "8koDKfrrjN5Yiu8JHybCDcSk5vHECesfw7a8kUQ9iqi4", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5tmWmkHRiP4zvUE8wgChnXjPzt8HUkQ91Y3d883GZ7TB", - "targetOrders": "6wHd8aPkHnhZ9GBLwM8e33ecQz55X936dV8nYCSNQDqU", - "baseVault": "BCxN7WybFJP6QHxYTFjtha2zvKKs4hJqrMKAfkJuLvyx", - "quoteVault": "6PqJJKEymy1bc7kWCjfwq1u1mRV9rvaXnAWn1UE6TisD", - "withdrawQueue": "Ef9qtVgmEkTgTHGAxGPMrEPXRRBwLaerzd2idrWqgkqs", - "lpVault": "Huu5UqMcpZtxk2RHsYtbx1aSB6dQPceGuXVFBBJQ8WwD", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7QwEMFeKS8mPACndc9EzpgoqKbQhpBm1N4JCtzjGEyR7", - "marketAuthority": "GkTErK2hTz4mg2krfsLBpuaph7poXCtF9n4uLPTJ5FVy", - "marketBaseVault": "z3ufqeHPVhoojVk8QNJhvic6MCK2FTC5TZFyY7LvNX2", - "marketQuoteVault": "CZWVfBKcYVFqZgEYUCGugDFxFNoxCZw2ZE7q3M9S6R4c", - "marketBids": "6U4UaRjCw8FqChb6SSD8mhe5UMvgeifSac75utH7o6a5", - "marketAsks": "3uneY7d7zH2RZQ3RJA6RYipSF8zmhTZ2EBzqRoAqCw3b", - "marketEventQueue": "FfEU9CmquUFKQ3k6agUDi8fsK88ET1F6To8dtn89qkWQ" - }, - { - "id": "EdyzWYpV6G3hyW7eLE5egiqecGteMiVZWr5dceXngmRP", - "baseMint": "Ab8bg8XBXfdvT81kKpzWay6L3hVGfcH7G9xNhibxQYKk", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "51vAvjgvL7PgBNxzFaSsMXk4ntLmc4uZe5FixtABWrfT", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CVMA2vaJnUPLy1zo9kLCqUQXjQhqq2PxBeEfaMGzDFfd", - "targetOrders": "G7xQHC4oUvcJH873bM7P1RUyXkFTbHACKWrkT7MrqNdR", - "baseVault": "Fj1NxCbV8wdoBfC4JjQxb5pP3eTyJ4cA8gEnUYUVTDf7", - "quoteVault": "7zPybivB3vE38is6a77kyw6a6VLycEvpbPwyeyTkViH4", - "withdrawQueue": "5GZzWXZZ8Wqzm8xF1vsDjjSMYjvD82P6zfaLAoiqo5e", - "lpVault": "8TfeaowXvYoA6aNufT8YYw3ghmKZpsneL1cc6ZpLJhFd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DWxuasHXZwnEUJb5aABe2b1PXTjhKJDVJqeHVihtx6Ay", - "marketAuthority": "AdXN3jhGRbj9eLNHrBtLTuehuAs1no98bPEhJHnZXAgA", - "marketBaseVault": "8Go67mqjnescZH4XwEnsATYUMmMLsiFnEA448tuwq29v", - "marketQuoteVault": "Dvq3EiVRL9pu7Pr5WKmTuTcVkN3dWQxg2Y4KcmYJq29J", - "marketBids": "2WcQGjzFAnyYsP7GgNbhM5aB5eD67CXBwoAoBfmuqyf2", - "marketAsks": "7m5VpyjZYcej4J3K1SHSXKHUUwaMiaNqrHgkgJSGd19M", - "marketEventQueue": "3WHNsq2B5WsFfrN5rSZoJVZWxpXnrQmCJJ7Dc28b1sk5" - }, - { - "id": "EemyJfKCCXHrf11z4TbDcma4BCzji7Cr1hw2Jvs1TXj8", - "baseMint": "4qPR3PzGAwBjNegJak4MJXcHMFsBb5GpLWEa9hvwfSJd", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "Hbuum2nLj2CDFpEJG1KYf1u7d9HZEaXwd1QPzn8wEKBt", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AZ6mjz186TysC716peAzC6cstTrhFW3kBQcEyJZ7YgmF", - "targetOrders": "5yHAxYQpYAWYABRCDG22mTVw6z7eTa2TseNdQWRtVD8D", - "baseVault": "Hww5ofbZdJpEqQukVuN7owiEGiMPn7LWzY3ssxxaFXiB", - "quoteVault": "8qdkXuuvQk9HoNeTEFJxmHnvSubo4LPjqioDbbiTSRDu", - "withdrawQueue": "G9UhYznPrF6rWPverhnCd8cGNXKZGbNB45qGLMzh6snW", - "lpVault": "AKKXuSkVCnqvVgjPfm9Tmw3DTnCkeXHa43tfn8aKCkHs", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2xQo8kpC9H2sZZ5sgVv1qrYgmdus4Mo7Q6nCS7kCSs12", - "marketAuthority": "EpGAT2yhgCx5rhJUoFAiU4n8w6hw85T2doGJhDHrvzZf", - "marketBaseVault": "ERtZb3dKD2oANPzWhVfFQjaVwPsZmRwQCYBXEM9D3Chb", - "marketQuoteVault": "BsFJ4EvYLUH4FDs7fbqbkNLcENxs4pGyZmstWs756nAV", - "marketBids": "7YgRqpBW9WiRrAfyBQQC3ejhG7xggF9pWogW4YsFjw87", - "marketAsks": "7ExhGNDtxkJtb2MF8rvspznYVuTtmbmfS5R4xn4AhDa6", - "marketEventQueue": "GF5qmYXD5esCFh7DVTsJe6mQJqHJ53MWpLwLoaGqqQqA" - }, - { - "id": "EePEbuqo7cUaYbXAqRwMvywKycHfw9bMxnSNEZrJ3EQz", - "baseMint": "Caw4P6ypHsU2grSUHEUPAKa2g6g5qT1YRcQDJXLRMfDr", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "7sKDDVz81KMnW42p6ZKq4CjiCjN3DJDHiwFfWdyGWR45", - "baseDecimals": 0, - "quoteDecimals": 9, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "43ymFLTJKUFxhqZfDcxDtfo69ZChBWtZqZoxiYA4DYyy", - "targetOrders": "482eRWtxpXKHwMZoxrMrugFghRuPxsdd7bPkCfs2iJut", - "baseVault": "8ZWYiXNGSkM2mJ4VDEJ4G4hKUhEoLWPmmZf1fdZC7KEJ", - "quoteVault": "458PTabXv9cEoKSwP9u9zPR7ANiqnjHX7KsRvjo4VnaM", - "withdrawQueue": "apMra8pwAuyE2SCgxQRiBcguvT83m7XDWXfLrejvLPe", - "lpVault": "CiVab678fRL7erTXtBPc9DT8RUESgFdSYaCo3UJMyCJQ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7uBJffZWEesPj7bYZDq9T9435eKuiZRNHLCSL8drhkn5", - "marketAuthority": "2MubM9eiEVdnxx1W5kRTHgWPUG8XJPqxjZnXwRVpzuE8", - "marketBaseVault": "ERv7XPtWPZEJxVrRATpw74EwDDjUiU3f6gFhkYFNzBxx", - "marketQuoteVault": "JCjjoNXah8te6gR46s7LnPwXwSjhmhntqnXJdhS3pU3F", - "marketBids": "DQ9Mn429KXaEafQ8Deo7V35Cdgxib7nUBQbWvMGm4k9c", - "marketAsks": "FJKea7hqW7KDc8FraCYkKa4pUUKJK4GdcEVpUdn2GkWv", - "marketEventQueue": "5xo678mn4RmP553JGK1ViUj4CTvDCfZjWQir3WP3m8JS" - }, - { - "id": "EeRhbaTtMaFt92RtvP81GHp6PkcUULsn5Jd6vGY8fXBV", - "baseMint": "BXVR8wqs8ixPMHnuUq65buJQmimwG9WG5pNKKKBRd2S4", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "HUK5dEpdzhxXu1hkk9DZ8trNFqYZHDpPFRmftchCLZYr", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HqDWJwiZ2QMZ4LfW6xb9H12P1eDwZnNcvBaHtv9decps", - "targetOrders": "AWJ9SGs6xBMqe17Vv9zUAxUkPVyUqgJJ5ykKqXFLUrky", - "baseVault": "821nvLy7sCeyVRdXkv3iyeDBVi16bc6AUyyp2QKkEb8B", - "quoteVault": "5w3cJCVx5btFqQB1rqbs21jfeaqKBMtXM4EfV6Lepsu2", - "withdrawQueue": "6mmLHR2zLWkGbCyC33UR6ir1jSXknJUbb2iW7GEGV1PB", - "lpVault": "Ay92cvrhcUiCSvTuVsmxC9QZvrSjEjnEzTo4gusKAgdP", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7jR7X2wdnYgATcVChZLvVWN44hQTaJBZrbPSmS8y9MQ", - "marketAuthority": "GmnaPdxXoC4wgkvEuXQwQscP4vGRwYoFVGVDPkb9zF3x", - "marketBaseVault": "85okD1uDuBR5cTBCc3XPvqpR5MK33Ysmktnua6J3GXbA", - "marketQuoteVault": "86CbPNJoanvVB6KN5SLKFAdUUrwqwte5otvPwrZ6YzbY", - "marketBids": "VipEgKVi9b7LhY975wggbJr6FKqV6G7vC5Bm4oiuxpz", - "marketAsks": "8nzxqbsi9N6g5ARUQ5xXNd2CHk9ZyFmB4vDLVGk15YYX", - "marketEventQueue": "C9VLddc36Rj7mxTdYGXgZ1kazKMaaRWWqPvvY5rdEfqs" - }, - { - "id": "EFVNTELdHrXAGazh1wvFhZQRCer8twFxzjCLHyFuRHVA", - "baseMint": "HWLWjsghaGQToxaz7r2ZcRPDsxwGrYiSXrm6YBoTuie7", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4cb7jhf3e5RHW5vpywA3pJemWvGeTTm78q6qnBUTum8E", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CdEG5bZUZgQfaWxhCxs3i3Wr6Dx9cx2iDqg5admosVpM", - "targetOrders": "5LnE9UqvhmVdQz3tbiWyTNBgiBu6cFoKCYDVdN4vsQWm", - "baseVault": "GY2X7yvqtjuHFSJL5JMxrsikPQQabowPGqUBzCqSvgKy", - "quoteVault": "554YEujGwmSRHRjQ2wJJm6N9PH4he5PDAtCbsjYexw3g", - "withdrawQueue": "CZ5exnqNGo32qJE44uykFMBBGCWkFzSLnmpCdSrsbvy7", - "lpVault": "3Exg4CecdECH4ZoAiQ4eANoBYRpRigCk8kvoj5jBbMNo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CJKwPrPZnE4PaHcQ5b6F9ZgCH1MMcUcQyn6BwiQVB47K", - "marketAuthority": "8b1dtv8RW4uSzS9rtunY8w5MFLVPi1Dv3ufApNaGVDHo", - "marketBaseVault": "AXsANvVGFroryiab4P6sr4kC2cviSArBRhxBzA32Bzt5", - "marketQuoteVault": "EwCxwkKL2PBhrmusPETrnzQbVmyxE7NeKbqnTXb5jm8e", - "marketBids": "HvQuk5HkXihxBpsBCLRfVRTVW2ToAK6zGc9kuua7eZh6", - "marketAsks": "5CEvgvHPQCkRJZhYyB9GkcUDoPm9AjRqaEmKUuSSMaqY", - "marketEventQueue": "24rBkEogNe2rkxJk8dvBoSc2j4PwqZCrPiW8LkyVKJRw" - }, - { - "id": "EFXcUrqFE4D8DCZdkoeGcBVfyVZrrtavpmDUWA5CCDJ2", - "baseMint": "CJ5U6wPmjxFUyTJpUTS7Rt1UqhTmSVRMvmJ8WD4nndXW", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "82Nfr9MCV9zc3rAoz1WpyuPqrUPfjUfD7CTdPfMz5Fah", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FRqC4aP2CrimDjipubVhPChfWRhuaAes5tnQZRwXLxgx", - "targetOrders": "7qRwhwn7h4rCqk9zgP5KRaGAc6iGpyGuRCdEo5iLoTHb", - "baseVault": "eJhBEEMqSMrFakETHUhYpZPTB7soJRtYZ1Tpx9WD9xA", - "quoteVault": "4W2DLESfRuekoSkAZnHdAhtX8ANAerwAo6zwWTMVTsgR", - "withdrawQueue": "3MzJMBcRydDTPcSQpn7Gay6ndm2QT5gtC5mu52HwAZF8", - "lpVault": "FR9CatYUb3iU7CBUqe8CR8kjxX6CicHzmkhE2tKkhsqa", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "D7HuVwRfDXzBiAJ17sv74ZXtFiCFeoSs6aW9ZVm8dEZT", - "marketAuthority": "AeLHgUnUgmXt5JPsKJP9a5FiFQkA2DtC9uzedyxSbMC6", - "marketBaseVault": "EyTaj78QYjcDbnge7U5uEA5EYKKapr5X4G5CHkQcJkfm", - "marketQuoteVault": "6W8BpzWmPdBaAdFKc1LqBRV8G526CoCWLzZnPj4LjU7G", - "marketBids": "7D9E78xhRRNK89oEuAs7FndvkgQphCBu9WxW2GMcLs6v", - "marketAsks": "B9n31SaBtCpwhHMvXrwW7Xk4VoSATdd91DHfwDAPRE2D", - "marketEventQueue": "HdvQaEJZBmvARgB1zYF4YGrDajZ3MKpaBsNvbL3gUcH4" - }, - { - "id": "Eg9eqJQX5JgFpwHbosPeQPx1AmYFQxXcBF9g1CMq3LMg", - "baseMint": "5y6abqRgxesWCH7xCi5efntYxoZyDxFbBvgHTJS6b2Rm", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CKfVcMSWP8JyTZfLs1UpKkSP3u4BLmMr5rwtRzaktmtP", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2YbEhuNTp9wxFN9YCF1NjoMELVKFuFWsMfWxWuNC97cd", - "targetOrders": "HT32rwaXdmLPLbs8FqV78D5cjWrFznnnopY6x7i5TdTR", - "baseVault": "4JTvTydgYJ9ftj3gAKn6pT4CRwydDNF2KZtVj3XQkuzb", - "quoteVault": "z81F41bshFzyzKhiCGkL7KcVoSiebhD33ZBpWFvfyUk", - "withdrawQueue": "BRU1KfS6xiWY2mp7cM9uzpUVCTkEde7zYGvAhGTmJZyo", - "lpVault": "GY5SfP6DBwNnZjnnu4yYxmTY6Sz844ScpkQ2V7TkYCA2", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2REv9scD6FXCn5jephHJN9fraQ3Yq4toU5RrAXcJUazd", - "marketAuthority": "BBXKvznaa4JgzKNaP5RFSZs59xMLD1eR41RgrDoCmkhu", - "marketBaseVault": "HnyatzZMg11bwyg8dsehNBQSwyhsKmeAq5e7iWYrtZDc", - "marketQuoteVault": "3FZLEtEovg7kBPyxziPopFCWu4Pmg51cnK99bWUQALGf", - "marketBids": "7d7PxT4kjUJV97FJoMPcJZ3ygFnY5KSNkjHcZqiD9brg", - "marketAsks": "AepH4AfM7YdLzxuY2eYaffjzsuUBiT8rSX8DUtSAn6y8", - "marketEventQueue": "26TpY9JgT5CNsi7pcKj5fi9RX3bK4kZWdC2rfExM4SBG" - }, - { - "id": "EgDFvbPrieM4dGExeEBT4H62U9uGWznBBTUfKrrDwYmE", - "baseMint": "AASdD9rAefJ4PP7iM89MYUsQEyCQwvBofhceZUGDh5HZ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HHpHTr55U6Hp96K9nLvh93QuDUuwYjwjbv9vb55jjYd7", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CXE1g8GVEsRPDQK3kFZdBes6eJM4p64tbTWBsv6xAArb", - "targetOrders": "5dX42rvt86egGx8sQ96gzrYw8p2P56xmYP5aK4WGrgsF", - "baseVault": "7crrpkUjVcm2TvG7RadJtB6A3gQ3JPaqEjtyzRjMRCaW", - "quoteVault": "BB9vswazquPDGu9okCdThBZWJDkhHF9r1bH7z2845UDz", - "withdrawQueue": "2N3yk1a69DHweuo2uduevHxkKywEqbc2aZcZQrHbm2RJ", - "lpVault": "2zmkPwRgrKjDMuhr6765JHQEPY9pDhPMmYHY7uqV1qp1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7xy4r55rLu2QYeSGwTGDCBKEYERDX98f6kQLn9Zre6S3", - "marketAuthority": "8vNw6Domm6KQNqEFAGK3CDib6sZqAXPXBKLMpcCrTeS", - "marketBaseVault": "ARXq6h8irTLEXDL59B3QpvUZMEA28yBDXB8UKMinq9Q5", - "marketQuoteVault": "EFpryovbaWpChMLwKo6ZxeuC3jEe3LN88d1F1HkDRmdY", - "marketBids": "CUPa62DxRSEwTRQzGSpuYkr1UKuvz67SBgZsoQBcfwMY", - "marketAsks": "9nRnTBTzquTixugMcHhZgNphdtVJzcTYyqch84nt6kyC", - "marketEventQueue": "D7TfVdBrtipGufdMqv7WJ5qPcCvDRWoCyX9XyPFo4Ccp" - }, - { - "id": "EGnbC6mKf4uVaaQKKFGGL2hUqbjoyt3B6p9C3xFV9ZB5", - "baseMint": "7eUy6MuksrBRFE4hvCE9UWxkswG4yp71jxjnaxNv7mJr", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6KQyGFZCCBEE53gWEgEQu56FpnHL8WKMa2q69DCmiCvo", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DGrkGFYu6t3brDGigvQQ4MdZz523wVif6o6AqTTqVYQs", - "targetOrders": "CU64NDbNrwxhQ3EMAa6BqFW76uWVJtThJzMMXzsk4oXi", - "baseVault": "FG7tncAuQYwZrLTEBk2Ckkq6LNjeWs4sTx97v79Dpw4m", - "quoteVault": "HGxLd6uZn37m8Gym7JnoNXYkZvbnfJrGoPFZN99okQXd", - "withdrawQueue": "F7yqXs1vfL3H3UaoTX3N4cCq1CfBC1LJv77TRhfDJyku", - "lpVault": "7iA2Dv2157fbkqStviJRRyPfixKqXWiGhSqN4evGDbME", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6K9LLZBLAacNdeQHWywotT7j4W7hWFtGaEcBm3whoxV6", - "marketAuthority": "21ewq4DTiPiHqzRw1ZXN1kRZPvmyf1YiXJ7627bDVpEM", - "marketBaseVault": "CAz9KPsf9jiVX8qoNEU1qC9zaA7qy6JsnZbPj2ZqqV17", - "marketQuoteVault": "HzL9pkvgMiDKcVobZPTLFSazTXq8MGB6pbZw9o7T5sH3", - "marketBids": "E57mixNuCFBbQwtxZATRmfdoRSTeh9y9FemxgVftTedy", - "marketAsks": "38ChRYWdrzR7W6rEoXB3KVEqWjgMP7kuB8i52C1a4dDh", - "marketEventQueue": "AG5DwK6HTcJkLnTZ4ed6Lu5vdv7RbtU9pXnUwmYHk579" - }, - { - "id": "EGrG8eSutRuRDc19Ec1oXNscJ8Gwhyg1VmvvuYaoqoNe", - "baseMint": "APERe98wcFuzQcHkX5aagTEZn2Vm8EAFE4PWBYzUT8d7", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "85EMkRt3rB161AqYtzqDPwBEeBLV9pWh8bnureaxJGeP", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FQdJykmZgS1LVK4AZ2CEZet9MVUyWQ5JA5KCy536oBVG", - "targetOrders": "CSbtADUbeMo2hUMNSB2ikyNh1mp6gVWs6fbK1yaNCeHq", - "baseVault": "52Ay4bnBqc4HfKTArSUJuJ7nqwVwgZ2cMJQ61ADm1xYz", - "quoteVault": "BvbBENbUZ3xQwiTL4UeikPJsMK6DwT3jo6TyVxQTocZm", - "withdrawQueue": "AY3AfH8H5rg8MBQkH5HDckLSnTQeHU6dbGADp5uzoqNL", - "lpVault": "jQgtuUcemZeVvwQXenXz1P5JjwJT1EEp416Dkdze7Z3", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8qEtborN8W5qpWPVGGVEm984dqJind4d7JLiRUcAwKVM", - "marketAuthority": "HakwwTsDkvNYXqvbS4kRphS9rDzQYTXgJPp8azsQA138", - "marketBaseVault": "FknmhCcp9yHTqw7YiehaGUQqZUEbGAV9mpjA2MvUM9C1", - "marketQuoteVault": "BNBhH68n9gXaQTk5qcAKkQRmcwMa2huMhkL3kis3KnCa", - "marketBids": "5M5qJfYpfjWFj9Vt8Tt2AWCQHwwQ3B3gq4YMJ1VzCotE", - "marketAsks": "YSNkJ3Y2ibJPP2GBRajVTrcqKrZviK1rghF7zK2bFnf", - "marketEventQueue": "CKGk9wXS4mCUNaPhkUJMEZ3NfdrJ7x4KwHjFcktQbgJY" - }, - { - "id": "Ehey5WkMHVmStSiVXU4W2fCmDS6d1JCxSev6BMtfSBvK", - "baseMint": "3Dy8KFyvpUJ8nfRCbvk4HLWjNRRzxiVhTeE9PQF9RARD", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7QbovkoD7pdP1DyznHkWGsMHq53YWWmAU7tKUTeqgjUb", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CzMoMJMdqRS8EpXBxqNiKnmGpwfXT21Fw37DCcgFhDcK", - "targetOrders": "6Fs6JWMKuEJbYF54UMCbjTLeBETeALrG1EW76UuMMG8y", - "baseVault": "9Bg7Kh1ga4YXXg3bjbCdryKpAY5TAEBAb3nBvzZuyYBp", - "quoteVault": "45YaJGNveBqUTojSGtU9NWP6H4KwtXLDQ41dCSP1JFxE", - "withdrawQueue": "6i1JX3NMNC1m4bnTx9Nnf6EPJHdf1PiYS2oogzsTWWbY", - "lpVault": "GYcDstGhEJCwNx1RaFQR7EAE6gsHB9qyyTeZAcgjPk81", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BqFLTxFe8mPynBrk9KFhVJj8DDWD14pnB5kuPLt9Pk7x", - "marketAuthority": "3G66RUPyDvvPVoz4addDTuMPv26npyYHwJqFupFXtqZ8", - "marketBaseVault": "6jY31cdSTaspAihHJdVH23BQ2piiKX4EQjzxSWdkcY3r", - "marketQuoteVault": "Ea6juQdVpga6KzJnGc6YSyZ9NpURH8FwBuEaAxGpzyLZ", - "marketBids": "PhnrHkw9rUgwqKoYtYyYHK6DVTpTBjJyroeTquDQJeB", - "marketAsks": "3fGPEzD4mgQpoNV2n9ssfdgWBymR5WYL5BxpWXaGr5Yy", - "marketEventQueue": "G9mRemDXF4rzFT11Wf7bbMQWY3JZFLs7efHrwwXgmNuQ" - }, - { - "id": "EhG6QNN758ySsavJy3hhxksZntpyRRopfgZh2dJs1NFf", - "baseMint": "HPeWNsBtYtfMeYS6Sqwb3uvDvuarekCnrjCq41XqMQdf", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "FBvZUmcQ1wJ8ujxUpiT25T9uzouhUVCKUk2eY51UZ6QK", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "928uPMY7ejp1faDxooBnFG5pJWTfMFbWGtrBfwbkwyP1", - "targetOrders": "6s5DfN4c1mW73ee3TYEHxGmN8QcmFD3NuqjgosCYrEVP", - "baseVault": "8oQP2dndbkw3yrxcm3ThQFnJYMiaK9hYbxZrrHx88FA2", - "quoteVault": "HHvgBoW62aMA2M8KDDyX3fsMtLSmGGTzkKXHG5xJqSEP", - "withdrawQueue": "FAGdFjK6316Sh9bAtw7tXXy63fhbphbw2JpciF3hZ57d", - "lpVault": "AuZrdzL8hSZjwgNfuNkLoqycX8bcehkp8PZQSiZ4nGzC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "A3PewNr37buuhGYCLnBAyBHppG8KkTjrH5npxZfXe83R", - "marketAuthority": "CMhCdhwVjGozQXwxw4mrR2EdjwdkBzxg45jB5jX9YgBh", - "marketBaseVault": "q6mwrqF5Mek8yPibjVyKS3gZ56uyMkYTiCYwMXpboVK", - "marketQuoteVault": "B5z9LXTA9YVqvgWaaMR5fp6P5Xf6QBEPQEVVkzFeyHgF", - "marketBids": "9bFEvnen4GBZmNgwSRH11jAFw49Tio1SzMfnzAMsFcqV", - "marketAsks": "4FXZumFKe2V71d2GNXHDSZLXdY3y1nyF68n3RLUYse86", - "marketEventQueue": "JCDhHu5TAFaRx4EVJmZCvSuEvs8773djDSQAFQLYesoJ" - }, - { - "id": "Ei63NHDMRVnq5cnQNS1edw4wRd1FBghCDFxhkzVEF6YX", - "baseMint": "6StzwSrFeQEkF2xwADqdoz63RXR8dftf9BZnk91o52rm", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "8eBH5cYrHeYumvUe4B13jMcXYaNEVzFLzyPWvgKwdWjb", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HzjNpTHtsQ1L8yUV6nC6UobRfqwk4QZZz3naeQxrZXtG", - "targetOrders": "6BWQcKCgQQ3sXv2tcyeReantDBp2iampzpxGXDwxxw4K", - "baseVault": "Aqv4hqiryJE2JjZXVFsdUZtNvbMGVVnWjMVJub9kHkek", - "quoteVault": "AHiHmj1mP5fyEVK5uxzMLN9ikXk5VPvtUt1LX8ndR6u4", - "withdrawQueue": "84fiwmnkhTZL5eoDpwBESsHKhSmhYG3C8yaJa3PhMNRg", - "lpVault": "G2BVGk8uhvZRnqNV7pnMhzQNSPphCBYHpvbajvEQRDWM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "D3L5T2kdr9Lz7QKoc5Y5C2X2M3oi8QoprvGuLUvtGrCB", - "marketAuthority": "FQavctUXM359pc7rxxyFEG9YJdn5FM588ikJWdfcP2D", - "marketBaseVault": "CntwXU6ti3L6M48iVW2mSV5eijXyA7wwabhDaRcFRhu3", - "marketQuoteVault": "FBsaa2VdjMz6wpQKCeJUHDNGbTpd1uG9AsWQLws6jf4q", - "marketBids": "8yj8SHuoZP8yBpQ9tkUgfpHi8A6njFmegfJCb556y6zm", - "marketAsks": "2jXgR7K3yjA7G1mTFtKeLs1QrbnSHLGeSCJW76HSC4Bf", - "marketEventQueue": "EExT7NRoMohzUfd1rRU8b8TZHRnu11dUVF5FkE3CYPbi" - }, - { - "id": "EJ1B9H643pgtjLpG6xV2eWBbiKAYhjnfZuxpXuaDoqQ", - "baseMint": "8mgeCL7k2cB2KTN8NhD5biqvcbkfrmBogDpYoHmn5cKQ", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "EPAQJYFZ1MudAWTsxakmikJcWCXVNNMXS6MZ1ZmhwqBr", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "JCZsUMgFW1aX8m6tCgPW9nnebaFiETA2KTBivPkzLHba", - "targetOrders": "7BEbDqorjghAmP44nFxd4dps5sKAGtcqJpk9Q4gwnCSk", - "baseVault": "44KaBJLfK8u3PsemMF6ZHGf8ByLowfLsNKQvvLtYruJ4", - "quoteVault": "3qD9Evs9tEqDQCjzZ1wfbPihXVKYnQ4d7vTWmjozRM7D", - "withdrawQueue": "4pg8ABvHb88pzBTc58Z5gdeYCv6FdFnP1j9vb7ohgGc9", - "lpVault": "DygfsNDrwRm6JGNh1WDqtjdowXK9jmxs5X3cCCZF17kp", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ErcKrcgAV3Tb1qykg6BCUh8PUVkoQahtDkwyJic8jsMn", - "marketAuthority": "BG1QA6CE5SuW3T66LFeh7CB339x1w48JbXkjfjPrEpJB", - "marketBaseVault": "6G45MWb3HqajQq5NpxXCsbt91Xvi3BgTP1D6Bb5Nn25s", - "marketQuoteVault": "EwLQjkAAvHpoaUvx59ufVj2HyGftPGDUrEpAeGfS87Vb", - "marketBids": "65aALzErYLBMJeAJHj5hE8nPNdHGgWKfBHxxeHxwtRCB", - "marketAsks": "2KfeXrVdfXs3ZQ1mTqJFsedHLcxaxj2HVPR2AUhNihWn", - "marketEventQueue": "7gdVsEveBpMmmwMmcTW9mTppZV8TPv3gccnfgmXGQ2ig" - }, - { - "id": "EjTyLvhpjoGkjSgxJxjPUYgm9cpPCwhGhvVEjJmKkpXd", - "baseMint": "DVhia9KmzYCP1URf4s8DrPsE46A5PuT5TPyVRgr4c895", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8wdHt9tCfrokKygS5UEExMyB4azM5z8aEcgshqpYNt4g", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HWy4gFXmgVnfwqg887xPFe9rXCJrha8eu6h4PA7jPjoc", - "targetOrders": "ARSD1dv8h9gMkKYeV1z2MoQ8mdGnUBdUWrsrN9YtNGam", - "baseVault": "7Lv2ce2TLadUSf85bXWvJMBEA2QXHakWTBrrRqVtrrFS", - "quoteVault": "hb8jrNf8U5GoMJ8D6iJmoDFre4kBuF5cgkHcZzULkkW", - "withdrawQueue": "86YCRH7MfT7fgEwRaycEhrgrupKhAuhBk8QJtNsK3yY2", - "lpVault": "CnYpVqPScWpfykurxiTmguUYGEFvSg9Fdc6r21pLkQay", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BQBGTapjYAYa9bY46GCByW2tjQtbHHvEMwGCDYpN3kTR", - "marketAuthority": "saim4xxFDhecHKpxnVfvUtF74C9nzUzFX7u6YhKee26", - "marketBaseVault": "EahidtSEk7Tq1Pe3rqAQjvqTz9G7q224cBCWLATMtVNj", - "marketQuoteVault": "AnGcqVHzQNaMefv9t5bSEqz8v64WdMVNZaVDsfGSGKGM", - "marketBids": "GC9k4TieYkAUBRyN94NHbrcrNdeARRiWmyMCeGKd6zPG", - "marketAsks": "EuBTc2jVYT21bN4KxgeFtn41gmFinYQard3WrbYSFpxr", - "marketEventQueue": "HuJ3P2PQi9cofaZsDV7KB3HxxMAH1HUnedK48S9CUpiC" - }, - { - "id": "EJXgq4bmoyyL5S4CnfvmVN6nz6t6rkBUN86WRbPwApQj", - "baseMint": "E7QfCszwdutZovb8rYAPUfj338M3C4szZPPY8RceTiXm", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4dmsPMVPU45Lq9QKk5J4NMK7WYGgPMPxTUXrjCvDFXkQ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DjVPSmUkJ5aYiewB8WAA4VjJFfBTaF5veMELbeFmdKxR", - "targetOrders": "EfsrjFqrgQippc3vn6ULobgwZfUyfkxzcxp6PDC43k4V", - "baseVault": "HuvPAmwk7MGpEsyYm8jF8AnpY6WbSw7SF8tDx3EKkywn", - "quoteVault": "D8N6U3K2xSRssWgAZW3D9HUAgukK65TwRV84AJ3aJYuG", - "withdrawQueue": "FQ66Kc3AT6MkmMyQT3TQjG9PKgZKEexFquY3f5Zy3o8C", - "lpVault": "BVrVtpigBbs1bboLhvY4UkG6RxJwb3wFQkKDx3pphG2n", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9SwL4YpYL3fKSmMy5JEwaLN9nYuWdaGonTvvTToRYrpc", - "marketAuthority": "3wsJM2S2bjKcvbDyiqrArfF1rfY4sFJY3HVQhbpvQ6nZ", - "marketBaseVault": "Cvmco1e81r8sswsQ41EM3KHyruomGCCb5YBGDDKtnpH4", - "marketQuoteVault": "3M9kzXGNARMgLqv5uXvYVB2bk9F3VVeGtNB6FChoAodW", - "marketBids": "9zp3NCwnLK72VibbWwCRPdcZhmwCJ11mc7MwZCfo1t1a", - "marketAsks": "7SvFKnUPhbdnB4FC2nFk19zTsCZjL3hoa6aTfaswJwP8", - "marketEventQueue": "32XdD5FRAfgw4iMTZKyUphCMvseB96bthaM2aSLmYNgS" - }, - { - "id": "EJxKyF6sRUWb5cBddKi85dbmoQzkGzqAFGsqJ2vA2JLH", - "baseMint": "E9bjYSAqabYAd2Zaev4qAMVNAiX7Z2Dp4Sn1JgsTn2b6", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CS8dse95keEdyt3Nfq5PqTYvkBJ1CWGV2C8N4Cqpetqr", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "F6ACwEmdkcYvpyXu9ooXrAjVyPS4xL2GxvC82i5b3A9R", - "targetOrders": "2mA6FrPrPCEV7FnXjBKzsrEHRbCv5ecyw3iqS1eeyVSj", - "baseVault": "3JGVbAXEbthyR27GWZBBwJw8aqe17vJihbBNtiWjNPyA", - "quoteVault": "J35uoE6Kmpd5fTs3TiVJXMwkWbLCPqCvyxtPgU2LUuH8", - "withdrawQueue": "CzkuNr1uUbn46SXxwvY3t4HWrHHWjP16gDwJtFgorLcv", - "lpVault": "ESmywsz7f3pTmKp11JFmFNBFwB8KFt9p1z1M36NSUAzA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HLsH8gTBLjBsbZ6wue61oxLexVv37UZSPccw6YWikoCA", - "marketAuthority": "BkmV5MLLivZdJCz8W2G1zQaLnwKKDdZVwh3X2Wc3MiwJ", - "marketBaseVault": "APedgQyT9FTwKpNMVx1oi2PhPHKQJs5ngLrG3WbNqLNr", - "marketQuoteVault": "DGcKvY5CgiwPAUQ13Gkcv6qWTjBFgBUZM8TBJUaKWz2G", - "marketBids": "GHbwZaac4gFy6q2rh8z63Z3HX5ZMhJoizAYvDQjyEUC2", - "marketAsks": "DJWTqeGntu1GPFwk3gDjiBU9eMhJsZu5CXVzn2mXVALs", - "marketEventQueue": "8gQ7EB6MFfuWVPVSX9wXNm7cEASA6JNgESkrg4JtdxFy" - }, - { - "id": "EKnygkn48qi8xAscEBKsKyMV712Tb9qvjkYei9Q6V5gX", - "baseMint": "DmXfDUeyRJqnpvdjssGgUXwZrRFPXvu2DfMq4jfTTC9C", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3GVqz6EWzTZpDYyr2SxUX8iaTuFmqjCYK8udw6evY4k9", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FwokjrHsbHwm3ay4uXZZGM7GjBRQvSUCMHXYmuLxgFRz", - "targetOrders": "FZFHrRg7LjpWGKsgoraQ3sAT2ofjAQ4UWuSh6gEthXZq", - "baseVault": "DPctAQZ7rr3iBx2Hm7nDegd2EAv8PfJqVqe4ZfTuDfxt", - "quoteVault": "HQjBPhPtmc36aa2tbynwHcjR2bk8AFs8Bc4c4q8DJW6S", - "withdrawQueue": "Eu2YvBPn67jENBpyQmLHQYZRbim8j5Mp9ZCGWqnBpqoK", - "lpVault": "8dqABtdUQGX5ub1osAuXHBZw4TTh7t4wGEXREJFXmtv2", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "712D8Mzmd4yFnGd7K4zPiytbPTgcLJMTGLcoQTEyt8iy", - "marketAuthority": "4Spc8koyGD1YmvNzAKxsAwuGJrYPajxwPUDZjPc1A9yY", - "marketBaseVault": "83xopHbHrDYzfzheXWLmcTkwWMbmpVihvGzeTCAJ3QLY", - "marketQuoteVault": "DPWrT8JBPm6V3K87Er8V7uQox4fNYvXr6qiGaSmpJ3rP", - "marketBids": "6KopKwd8aFTbHDTHqyWqNfCQrxVKvkLkf9GvpPnR4W3t", - "marketAsks": "7Z3SAZ8iGmuYauZWBb4wDepDgDFX52HoPFhTYWmun9Y6", - "marketEventQueue": "FNs2qGuGgzXPX81NHkCFy4ZoXYvoeGXci9aAvdSNKKvW" - }, - { - "id": "EksGabSZc3ko5QLCLJNkv9rZrg7KF197TxqqJWpGjrct", - "baseMint": "BBdrgbSeqcQsMP7Wo9Nv2Xac94UPiKjR9tEBS6Kz7NFp", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "25nYYeRXdpJGiG23nNqxeAK84b2xjoAE2MctSWopX15X", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EF6d1amztHau5XbKFt8rXFXUMnw4mUkF79wzMRKeijF2", - "targetOrders": "EJfKKBqF8LTu7vkAtVZy1PJuLY6UtWKBg5GMhbeK72sk", - "baseVault": "9kEqWt7YHXewBdohGUYWkH4ornDucstBotdqikvZn6Eq", - "quoteVault": "AXJbXMzmzhQJaWJztSQMympNN1bap8EaJr65p9JQEouH", - "withdrawQueue": "2Qj1T4VR8WUPCCzNnTxrc8XrFHvpycZRxUxWrEoH2ZJz", - "lpVault": "9tbgkButyFMdYP99pBnxNwxjdWMAbUydCjiAz2iCehbH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4Ys5bT5wbPFooProH2iyNpZrQq7bQo7NJc5LBFa4MyhC", - "marketAuthority": "6jHgSKLqp8o1xBNKPBhGeHLS59iwL91qrgiaL9iwaHPC", - "marketBaseVault": "75cdDAcK9ka6NoV11Q8mPe6bqT45xjyozWgviUHty59R", - "marketQuoteVault": "3ej4V23hUESgdXeJ4cQuGGbQ43CDWHK24BnXUZzF7XvN", - "marketBids": "BVWc9JfkqhpeQyokmcQhysKkWqBMESZPcieRwV9tzPv1", - "marketAsks": "6cxPFrdrydgqjcNrTn4KRKj274fBKZpwF85ePk5fyf7b", - "marketEventQueue": "H9darzEywVukRae5Q7w7aspTQHFXhaoD7EFw5NPdEs4T" - }, - { - "id": "EkVkEe72ZuLJ6kbRXgdq4h8z1s7bCtL1KovtpcHZ1ezD", - "baseMint": "Apn1f7P9jvhdQqzkSe5mKRCbpuHn6HXg2cra2jNUyu34", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "2nRnRa8e4qGzV2PcBFMv7NQxo7sjqoQUazjk5R6tkHey", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4wKBG8ouzSs9J79F21rYbCdQTd4AKKDUWnharrzG9SH9", - "targetOrders": "HfP47Ykr1zp6vBy3p6ZyEZFQxD4SLcMiAcfXc37ie6Ku", - "baseVault": "GAN89iSZLxS5ar5YxojkMERcVqvtZpqKXzRq6KJo6Gv1", - "quoteVault": "FyShstHP6qELeLoWYVi1aCkCiiy4dyLWL1fghVUmtCed", - "withdrawQueue": "9GvqeHVLsQT9gxHXwZwyDX9wjyv872HxgNGiD6JVzgRR", - "lpVault": "2pvBR37P7xsfEmQy4diXpnASTUqDgcMzRwsehVYn4ef1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DT6Bh7ASmKF7zkDttMNpQGGscb3cETfkKwTC4yr5VCpu", - "marketAuthority": "794YPV9a5UPdFPrNV12kMSYFccNYurJUHufG64qkmM85", - "marketBaseVault": "GmarP15czwJDo67Difct4xieRYzutBhS1gHR4AAPsu4Q", - "marketQuoteVault": "349eNqfT9TLFXf7vBmZb7yk93iYgHxaD6AdVMb6kV7pQ", - "marketBids": "D8zdBS8dey6PKQpzxgMnKo2iVfe789oRk3vc64pprciS", - "marketAsks": "AT8AEKvJ7EyXTvE831GXz4dxhzC8hWi7A7FidcmATf21", - "marketEventQueue": "3cxpigABB1q9NXE2TyhVTSADbTgMq73d29vSBxGYF2zN" - }, - { - "id": "ELN2aYLwG92CRCC6XGcWMMb1qtfnQX5deJ8d1cH6V1Zu", - "baseMint": "cxxShYRVcepDudXhe7U62QHvw8uBJoKFifmzggGKVC2", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CPzmcw81a6PDasSXhVLfDRKuTJXZPUqocS9VFf5zCFhs", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "J9FZc62NWM3nxCJm13pzfuwBpAEsPhEYMGsu9QVTP6bi", - "targetOrders": "5J4KWpuCt77N8Fnf2WhMznMEgu2HWQ4Bf3oi9CM5eVJ4", - "baseVault": "7YSGSuQFBZQh5rGoqSTwY4haLX4nvQGytutPv9owbry1", - "quoteVault": "7rWoQ3WNU2XPCGVxsRo8TyW9uUFQonT4zCMaF5mqv5H7", - "withdrawQueue": "A5bvuTnmpvWKePrzkFA8RDsNxpKi4sFFsfmK5bnCwsB9", - "lpVault": "8yNwVvDQx4DNFXoGbR7sTecquCyCZctBgtbXbm3ZL6YA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Eg8a9ZicLPSyak4CiXfiMeJK6jmHq57Xx5ag5GY6vcDj", - "marketAuthority": "DyGDH72iGBxRExo8nXNbQeGW9NUMzPsLcyEAPvNk4RRe", - "marketBaseVault": "6doW6DXNwrYm99Pxgn16NsSbTa5CWCSc2nqTgBra3w8X", - "marketQuoteVault": "GkL2Mi6Yu87ZmUaqDC981LGmRojcEQ1JwrKPEotAy7HS", - "marketBids": "v1MMhJddcrJXbZqEZiQnG3NQA86fwLJTnQSzbfUf11S", - "marketAsks": "Hs2GFsfzrEYASjZBymp5fVZAxuPGQ9JJCVwQ8UHoN81S", - "marketEventQueue": "a37ZNhk5CYMkJoQsdzSPkkFQVLx2TxgcSzWTdtWE2vp" - }, - { - "id": "EmgET1rUo2A8PW7qtUxDgQMgBdURueXWUJraMpZtCHHc", - "baseMint": "BzwERW2s5brUYtt3jvobVQn64uxXYRrz81Yx6vYpJorE", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "3XDk4j4X97a591ARzNB8Qco2UQ1snHViKyQDRbxTrV2N", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9jKkWbjf6torr9FjFyWDhqUMUPhTftChLty7pSNyDkJz", - "targetOrders": "GyjsQZYXy6ikKkxuQjf2dhyWjToW3kHvuXEu9dwsRpSi", - "baseVault": "72VFBpdaezWWApvYzTvNYF6p33g4pj3596Eg9bQJpD26", - "quoteVault": "A1LZfDjzcHs3oU3htAwueo66Bk9gyG7hFKaCJoNQ9ksV", - "withdrawQueue": "3KYCFr6KPqV7mJMi5QaVryHQJj5ZWFEVStLERboUhdZe", - "lpVault": "BvCrBSsotSZDg4zhex8rQw6nZVJddTV1eZF3Eh564rrw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DnzQ8bN7YhVLNFqQjyRs6A2V3xJ6j67CoxiDwo9DpUhK", - "marketAuthority": "FHLTiRPqnBhutZof91HjS2LTRuWAgR8wAVm1TSJqWUyv", - "marketBaseVault": "2fMP69oeYPyxJUFWFwY4d7MNX6hR7MFheqUwEoAyYfEw", - "marketQuoteVault": "PespEdqpPgFXDg8eURkSHPku5Sm4PPfA8LLZfjKxe2u", - "marketBids": "5WAe7RcV8dWUtSkZoA8K1dMPMbwtQ3KPKgPDkVwQAtpR", - "marketAsks": "4uzXjw7y5rLfJjoK5MUgE5xHP6iTaajNGXZU1vMhXZwr", - "marketEventQueue": "9ahsdRcTp7Q4wXqWwjKvTVpphLxEX2toMkkWtXtRi4jn" - }, - { - "id": "Enn6bKu1PSpRs52dRXzMgQiGH2uMU9MiPq6YqwVnEco5", - "baseMint": "G2PQTxEooYBG6TcrJ97tFrBzyYoFiRQwwTwiAkTycpwd", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2jC66AyBWFKMj31U5zZGe1vz4cihDxV9uxvR5ZvjxPYe", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EVzVjJDs46bbT5qEpSmjy4EyNjd7H6wR5gWjgwgZpf9g", - "targetOrders": "A6kpEetMcvuVaBM76wVVNqDHkh4FdFLVfKwcGH9CFHM9", - "baseVault": "GtV4UxuuEQAPXs3rPvUZx5HQY4PCBGo8Epd7wcUGvvU1", - "quoteVault": "EisQj64VazE2m8JGf6Zt2x9uUAzoWfASyFzNjiho6ykG", - "withdrawQueue": "E9Mb1YKUgyQiUsn2eNZ15jetnM2bXKpsd4srET8uLTMi", - "lpVault": "w6JSUWwQEB8JG4zN7Lq4R5eyagpEqjC1SKFyYxcAhfR", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "E8rii3h6JTqgDg2quM6qKGFhKrLrpS74yCC84FE8t6MK", - "marketAuthority": "HVrjT46hZrRawmtze2RXHqHEJHj4i8YD9TBbbHAz18fG", - "marketBaseVault": "AULqLLcsN19NUb9xX5myxQ2mum8DgVhcUNN4mqxcQsoN", - "marketQuoteVault": "5DwQMzHwBRovZqS8Bw75htaDRiyKUd7HgsNuQiJ6hNZE", - "marketBids": "2JQSEXsfjDcouTXiNpDDcDJGBJZZYpEgwmJ97bfhoZfE", - "marketAsks": "5Knb1VhqufdP53xk193byccrTz8bfd2gmpuChHPdYB8T", - "marketEventQueue": "39m3Z7mfPZzqcW9GnGvf97x6C6inuH5xgA7yADbdEHEJ" - }, - { - "id": "EnNft4s7BTHd4KaqvYS8BbyyFtuSrZ8rSiSsagYjKdaH", - "baseMint": "FLLW9PtziXxtin4bvcVKbw1roFPENi5HPADzXdcjGbY1", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2iNTMNQn9sM8oyXMYG7XUia4iABwujJeasqDjmNR6Y4G", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BMLTit6emRHmZAuhFpUuZEoR3J3mreeZvK26PoGtBXp1", - "targetOrders": "E6kNd4V89nnoSKtADBpdsAFipvdQZ94xC3xh4Zj2yTD9", - "baseVault": "GTbBYrKS3KUhoNwJziza6ehURRK1h6eLCQ2mSEvfKEvF", - "quoteVault": "HNF9muWkznmR9iDT5PxZ7YqiY1std9UtLjG1hDG9Dejn", - "withdrawQueue": "6X5YoJL6gJLNeFhEWfmiEFwvsnfdCnTP27pzPKyooyEY", - "lpVault": "HJbTfSA4gB8CJkP23b5VjMV8eWtGwYBu9cLupacHM2Be", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7bPSNiawbV9K1DkdcBuFwGkhLGPwM41bja8TAQHrsAxh", - "marketAuthority": "EzSAn1AsjMQQcuNi6kTnMrHbAeFDzmPvfGvf7g2oWNxd", - "marketBaseVault": "FZ4h9eqStYMTLHJcPWin3R584cWoLVGhDATakDYUWiLL", - "marketQuoteVault": "CbAFdyX3K592NjhcVeJxzqiLB4yFqgvM4LLHjwNCRJDt", - "marketBids": "n2uGmWibKZWbBeWT6MH9Jm5z9HrVoiQ4zy77Q5oKYBz", - "marketAsks": "292igbqcHjAVDkcxF1FXcD3mH8SCmz5xPFCYJa8Cf7BJ", - "marketEventQueue": "4kaJJBRfednKQsr2tCbq6cpzgAE4C33eJJS3UUuuzeyE" - }, - { - "id": "EnQ9HbhzWdv9bjPDLLdBPeeoKmtKAWg81bANrweSzvWx", - "baseMint": "KUPoVbJmipJb1M7xzQEND5w7u1BbmBytu9wZ2QPjQx4", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "9JcktmeR8cttoVNN6TTJN6NAf211AnFoRYZBpURmWy6v", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6uLP3GtQzTTeA7LDhJSKCiSQR6Geo2gUX5e7a6aWGS2D", - "targetOrders": "9xYtHuks3GSv7HBsVDeXdnAQV9sYxsUvoGc7c7GEmgod", - "baseVault": "3ni5SWXEEBwvVtfPcp1CDbJGEyLmVvX1NtLaVp5LvkEJ", - "quoteVault": "73L7RFbv9EUvfWCXt4L4ydZ6NiTbLr8oYZu9huQrsNnq", - "withdrawQueue": "CgG1jpEzva9K58cUPcBPfpaxLUzrLDZX7LVcvR4tQMLB", - "lpVault": "9gZXPBFXcbNkHNk5G5ptk6P2Wy3DgdPFDgaoypJEQL8s", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "A5gqK16U9FyCMbDQ7HSSsNhaqWJ1owCG8bRiNiGFwqBo", - "marketAuthority": "FhPwSdAGomCqeFAwUDfLyo8Kc2X1WqLHhKty8Y7GfEW9", - "marketBaseVault": "FV1RpMUabbGnWUa4bJbjPCmSPvqBo7uESL53ER1HWSFQ", - "marketQuoteVault": "4RpZX67jcP8GBPgiYUCScyHpm7LEjxML1wsYhBiJK3so", - "marketBids": "CzWNAUgbVFbQth8yALuwH9p9f77Y4q3mNhyQxvPebAj4", - "marketAsks": "6PCt5HQsEC8T2K9aP5bT3qd2mNQMB7SHQBLrLXPxBUZC", - "marketEventQueue": "2Ujht46ZnA1aYPkUD4JcTfkhQwBw72Z9K9kBksKzetVZ" - }, - { - "id": "ENWA7sxMZCTePFDHmt5UH1WMuk4coEPgqy1PjFBhBtLv", - "baseMint": "6zQwyDe541Ys4Q85vkhvHMMRW7ypA4PyHCSF1doWZ4tw", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7UAahaj8iTzG8z1uztQGPcZwUVs8YTNp5di5fy3V9GSy", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6m7R6n8vNi3pvZ2V63osjLPhHkvLzZJNVH1MEPGuLHEM", - "targetOrders": "9oFK6acMAhwmC8muVjopNxn5W4DXawLZiJQXaXNQ6shc", - "baseVault": "BeqGkcCee4pEyoDg98rcME19WKoQmRhwXd48LMxZ9BjP", - "quoteVault": "9YrZoAWJpokKq3fQiTGxQTWwkfPwXEqsQ95BnWFruUvg", - "withdrawQueue": "6MpMfM7dnnBLkPWtcEgJbXo9AuwMvcu97bmR1rLDpp4a", - "lpVault": "4ttjuZ2hvJYG6tdMWqaMnBBnGCayGXvLPVjzp23M4rQF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "14sCo8cwX2qUwY5bE2d72R2UWifEq62FKKn8vg3sSaaN", - "marketAuthority": "E7oqfGzjbFsF8CFikmGpk4sjXs7qToAZQYendzfUzaig", - "marketBaseVault": "6isn3HbAfmyZVaxGzbuhNZtXkmX7vwsSFpcxaHPVL1mT", - "marketQuoteVault": "Ac2tfXBan1ARggaHCKAhJAbf6qo4MPKtLQwwtc4XVSH2", - "marketBids": "GQM7EnpvX8iEESR8pXk7zfQwkXSVLY8PFsU1wbQWtp8k", - "marketAsks": "5VHZdeFiE5chmTbkgyTmX5UgAmW1roNeREUW9qb8dT5M", - "marketEventQueue": "9dtHBrYq9gzLP9f5mg3sSmy9Qz7XYuK1uinMxrsFXzGF" - }, - { - "id": "ENZgC37vWQJPyT3nL1tsFWgADeHTdTW6daaXmLX5G8Tw", - "baseMint": "EUnagPcSm2LEcGgpgn6w9orfroK6vdpvJanciKLwhfXL", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CjhhLTectWu9KoNvmMp7LGRPx7Hp1wAMwEkzneevjm25", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BvybnMbnAVHZboBGrUcctJTnwXuvFBsm95D8u4p5Mk1i", - "targetOrders": "BiMpAbdT8nCEhLcwMCyrugnDhB4pp7NdC7GNZcXqL1zF", - "baseVault": "3M3yMRm7NWmaPLWxNjueGLV2f36cnxkVv6y8EV3RWCRv", - "quoteVault": "9iSXLcevuPrEcnYLzv4E8gD2hZLrzwKB7GNXBm5aEAng", - "withdrawQueue": "Dg3dCs97fdegpZwQQMUTmVk3hYZcZ4jbRxJeRfEbTJ2h", - "lpVault": "H6uBjprMZKwn2isT2qihE5Cv22AgQykXaGvFtxYjumSk", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "67tMCa7ETL3B2J3uFeg8qgDVo2JCS1aqx9PeDtVUvje5", - "marketAuthority": "5eTPx4JMv2zmTCRUQAcoyVWfP86XwNKAQH5sYXus8C87", - "marketBaseVault": "HC6whKQ35TcaCdvhgDQCf5EGvbYo3j2eqQNhCS47zkwr", - "marketQuoteVault": "9WRCJWYM2R2u6ibFxgqqAy2F6zaADr8WCQLiewMpwpn1", - "marketBids": "6q6d9xDMBT9sduvTV3foLqcVZN8WhYVTb9CpLzgFV9F4", - "marketAsks": "5g2cXyFyqUh7L4hNFCEJyyqLJbm8Hh1mDBpRLqiuBojz", - "marketEventQueue": "DeSobkJ2jnSpgDv3gNMVrwuFErwyEhCSij1JFdm3tPHC" - }, - { - "id": "EoMqXZFJr35bKx3egxk8wAtSEWS29Gs9qX8TRAkXudVN", - "baseMint": "G7eETAaUzmsBPKhokZyfbaT4tD9igdZSmfQGEYWem8Sw", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "SUf1TZCT3XzrV6Rdjv6WJs5G317JppuWaKvcsF58sXC", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FA2f9LUu3Wg4U7iDzdDuuG6eUE2ZWnuLL8bFDt2yhLdW", - "targetOrders": "BHTPGksyvhpMDtUSbsjUcCg8wHGG6iMTgVFFX7Eh44r8", - "baseVault": "GHUkwBiJXV8A5eUVufkjAhFuqEHeBkn8DR7JwL3ZLZCf", - "quoteVault": "6QHHykyBLrf3YAg7y2pBPM1tgPqmANJyx4TBybgjnH2p", - "withdrawQueue": "4CGF1BFj68MaxEFYEhoMsm761SPtJkCYFfaCi5uPfC5N", - "lpVault": "4NaPZH4ubCgYc5U3weXwSVy4MdNMX8x47cncjXY15WC5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "87H7KsVT2yqzLBfxVJDjDeztDMNGmerrAgSSxGdSW4Ws", - "marketAuthority": "FYtgRZNeD7kTDE659UgWLFkKbjsbZ7X4cgRABLKJtuYp", - "marketBaseVault": "H2YVUvZgcqfJH5NTYhkQfjp1cR1bwbp1KYkbMemuYiPt", - "marketQuoteVault": "7uJokaKp2Xrz8V1wMUs4uxqKuH2tupXEzWBHdipZPFyN", - "marketBids": "EEw81KR9o3btXtqRkScNr5GcA7Rmxz8xmbnkFuNwaZcX", - "marketAsks": "F1ppot7Wr76dHNRpS44gj7KP8oyg4x9HbeAxb2DC2vuZ", - "marketEventQueue": "4P5JQSn5r2JBZue6DRTn2iQ1xxSHyG8pScea6sTkVm2t" - }, - { - "id": "Eor4VCHCr6FHQn3Y2Q2big5nRMfTDY7Xa1ahuHeUDmm", - "baseMint": "48A1pXHvottXTf954CMhZyoG7MdFjngLJCDKJS6iJUth", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "ALvYVexR2kMezrmxanMJgLPb7bJjcPSAi4Z25UZdK1Hf", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3PRFbmyZUQb3niYf6kSjyje4bK91zmU6EBYEtFEBMwxD", - "targetOrders": "7r5Be2zmmU3zHJwFszCE74zq6KzT4Ey7pnMned2UY1wD", - "baseVault": "8U6CukHdSR4axcnEwDyabkBmb9GPpQxitfkY6RAyQzUG", - "quoteVault": "Buem5bskEU8fQp31ZNvLzsX81JDe2qHbcBpXTxXRSKp5", - "withdrawQueue": "4G9RTMnTExnV1nN4VgDkDqw4pwDGhPXK8GqrxB6WrBZV", - "lpVault": "BQnwQ439659G1xfiaXvNCpS3qhf5yS8FY3b5st119ddm", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DPo1McyiWmbxuHZSoJEkZjaYVis1jskfsLP4TNPEFRK6", - "marketAuthority": "DUTLSb7hgtyJ6eCyd6YZEoP6KEvgkPaXjHkG7ewUcQ27", - "marketBaseVault": "C4DxtktnAivE59k2fXyfiYiibb165K6bBxSEPSuPmtmT", - "marketQuoteVault": "CmxgpSzw9fQhNStcML9raaBGVS9spB5zKWPFRzPahNUz", - "marketBids": "J9xjMSSe11PMxwWRqokTooU3JztddnUtr2ESieXPLwyr", - "marketAsks": "G2LyrouDM6BE1g756fXiAAr7Y1pMQi8mK2gvVQmoVM8X", - "marketEventQueue": "AptKouRcZytzsvFXkdsLvJAHwHBb6DS6XKK5toJRUWk6" - }, - { - "id": "EpEM5cm9AHv5aFgJdtmvaKucn5SVpLcLyd8kiXLnno2L", - "baseMint": "D8Fc2HLd9L9V2mJnEUpnys6muJUawKYFnJWcUiaGKnyP", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FbD9hY9eNURqRLcjkn4MpypPbmEsQ374DdDYtxWN5pT8", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4FF4EFYrYuf2vLrXpCDm2w7FzuXLRPuNamvboE7tSvg6", - "targetOrders": "47FBPZNh5qM7X65pomsNP1s1kNp3b7DRSbyBLiCHg235", - "baseVault": "mZqj3nPL2KFdxwULd6guFgj6xATG2v3SiThmGhoHTjh", - "quoteVault": "GpG6Hzy4Je3QUbHFQZPzE3iR5aTvGtm21Uci7RobpTqo", - "withdrawQueue": "2MiSceEtMpBuw3Q33vWiRUhBNyGBuJDeSEYkSak9VJWb", - "lpVault": "Hwsy9PEbjnrPo6ME1DZQuLRHLJ37piRNhvx1wJ9WCBVj", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "J6ih6rFbwkx7bMRZYjaFzkAUcsLrCMxZ9CCEbtyEAJbS", - "marketAuthority": "DmefaD7QRujTtktXkN7wMdEDqKCKEdKoDBfaPnfB8fMh", - "marketBaseVault": "6dLKjGp9BYU69ovG6kPKoMBUz8gbJTuyYkJjdD4r7BV4", - "marketQuoteVault": "5WAZLkRAtEYZF4opMHMvyxdSZZgNVWwUBtf7AV8JobYq", - "marketBids": "4joTJ3wi7Qtyp3Nxac7c7Dm8H8KJN1wNvEey8gpxXYZP", - "marketAsks": "Af5DkRQpbhPqbCPUgmpvkwPA3ZSW3JkR9mx7EmRFigGj", - "marketEventQueue": "GhPWrejYQq7oo1mzcPmL8ZxEWES9q5CmtqF7QV97wDPz" - }, - { - "id": "EPFdzxwyQv3tGqZBNco5Wawz4uiqh3moxvyRyurJk9KX", - "baseMint": "4c5K1DJ3TcUkHt68PrBAzrYJj35r5hv9PAVsL2owYwn5", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "5fXPRZehi6ecGLSsbo67NfQMSMniMq6vi7ePYzyTBk1X", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EZeEkE89u4LBgzfNMUsaLy1AmXSCKb1AvQnXULygQxTP", - "targetOrders": "6RBL8fWfnowUVSuUYfNXUJGiXD7RXKAutTzAKLkScAvD", - "baseVault": "CasVmmMVo8NFUZKdX7q1behxkNDNDaCqHEFsQffWqWt3", - "quoteVault": "EgYcudD3jrWUZLT4yWwoEjLmN1WGhPcz8WjLYnXYuVb2", - "withdrawQueue": "D9226Z6rzFUWaHRdVh7mvCuTqwzHnvij2wfg7BtrC7x6", - "lpVault": "AxG5XHebVKG1SUpXABGoyBBhXL39cwPAbsrxbpaxyDra", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9XT6gULkeqmBwZaiQatVEVzHA2KBDgd5UHJjLhrkybSb", - "marketAuthority": "GkVcCGp58eaa1coUBjiAUxsydHokRheezoKsoPXJ2ktb", - "marketBaseVault": "25j1rHwXtasaNrBnszsYNdmrGLR6HHsubuvVhSfusVHr", - "marketQuoteVault": "GMgK32YXFPvF7mXdVNE7mXc7KsK9VLonP5eBh38zHPhS", - "marketBids": "4CojpxS9BBbNWXuwoNbmT7qePRzH97LgxvnnHMMZ4Cww", - "marketAsks": "BVz26C6vEV7478ve3Rfqb8GJznVFjpv1AMsQUVjs1mWA", - "marketEventQueue": "H4GzgRXHNbCvfTTZ5YGChFiTrcTcSxSpwJyz29rbnsy9" - }, - { - "id": "EpJa1MJJykeLqzFJ6pWasTfDWSS2WF7kkxu4pyowmYBY", - "baseMint": "xxxxa1sKNGwFtw2kFn8XauW9xq8hBZ5kVtcSesTT9fW", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Aa8iNwvUNyE74DxSx54MHy7YpnPZFZKnfdNMQH1756gN", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AcLRtZzQJf9A26MYzzUCpPVX1hUTThRFUqHdBcvPuzRV", - "targetOrders": "DgWwzMa7zXRBh5ygC1bszkEGfHmN8fLn7suKAhxvueih", - "baseVault": "H6h8aNiZTCtgfWNeKSdeqjE25Xvnpa6p1vGaGgiafemL", - "quoteVault": "5qRZJVRBZX7FcGwoZbp39hGd9wZMXayrj2MF2vG3Snz9", - "withdrawQueue": "9hj17xVWaRo7ybmk2WJdxaQRYh4DgBCYUbu9iP12hg5s", - "lpVault": "BorHomHwrWo1PyVVhVLgfSM6FzTrWW5sQkqXRissgQA6", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "14WSrFescaoKfDJq225bYPxJeUp79SKdnSYHeXY3nLZ6", - "marketAuthority": "C2EjwgKUMYWQ8chtVJNgJ1rqSEAdADFvoLDt1mAPNt1d", - "marketBaseVault": "ERPJueQjrVTpgdZ1w4TG3mNsTjXjm1V4hsAJyoQwsy2n", - "marketQuoteVault": "FweZvHMhbLehzymYQ8yCpt8TSfV8QvGFeFtfeYJXkLRp", - "marketBids": "CszSJZk3Nas3TjPW7ZraRUfo7mDWNZj4kwvo1Nzk8tHA", - "marketAsks": "G9abnBsimC3VVbtneicZgaNMdcRzAipkfFj2FeyuT8xW", - "marketEventQueue": "ErNiDySQ65fNEtbJJA9A8FoQDqFACpeXUSnxs2UJ8Vg1" - }, - { - "id": "EPvPeiw2xusJscpnkgMYugrPJ1T7DQX1gS2kTtAAc9Yh", - "baseMint": "FMBfAxhiTwDmujiEGbexFtExHR9q7nqnRF1Rjd5UmhS7", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DbmiY8arR2fNETCxDN3sYTmC8caGcixfRjdpE9ETuT3d", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GkqWtBQvje9sDEgY47tzvb81v2CPKtwn6jcFfj2iASJj", - "targetOrders": "998JykZdGKPfwk7uws2tAniBgXBQUCRmEasWY6dr6HPr", - "baseVault": "67k5PcZzmS9YA4WJW7WgGayMJgmz1TeyhkMy3n3iwLtC", - "quoteVault": "BG4BJmHjqdTunXapSQAoEoJ9JRSyhHZRA4wGJ3RUqYYP", - "withdrawQueue": "HrnbHpTD2Fxc9uG8BgGsNcg54qxgdv9tMSR347RU1esa", - "lpVault": "HAudv4pwQhCjYyDs3AaKP668inF1v9uCNxsaGUpZHBUj", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GUJtq1g8sW1aaPr2A6qgwJqh4VZQvUUMG3TUWZrQJ3bC", - "marketAuthority": "FApMpewATwpmMwWe3SXFjWWko6j2i1Hqmme7dSw5kMdf", - "marketBaseVault": "BQtBsiNTkXvy53w4XuaAfNDTAKzwwHaUE6vWhHEzj44U", - "marketQuoteVault": "4d6oz5Pxo3mTcx16YJ6NjvUTpF9dF67xN8u411pfz9Jv", - "marketBids": "E94BdFHpeAhXfVvjmrhGoh3KNxhQHaPsp8LjxWFZqiQ8", - "marketAsks": "3xBvbWK6tFQQSJLWSzd31ph6d4ewbxqoJf3TAQtTJUot", - "marketEventQueue": "DpuX3pKbWHjTVkhvDiGcK3L1rZbizKhkWEtLVVTeSHun" - }, - { - "id": "EpykKUYJd7ZK8rJuGyxfDuZcte9bRgBdo6LybhxT3Hf2", - "baseMint": "8VLvHQ4E2t1Azptwh5p26Wg64ycnfE9BV9bDba6U14wG", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4B65mR6mNk2SNiBKJmtRy5eQRoPfhhKMraTZcKVS3KVH", - "baseDecimals": 1, - "quoteDecimals": 6, - "lpDecimals": 1, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "F1Erurw5qtpnGeaJ8nou2oC7jreuf8KC74MyKUYgZtGJ", - "targetOrders": "5fMFE9Nu7bM1d6RpmjKNbQJNcSfZuTdTnmJemU6QLJZ5", - "baseVault": "2n5v6NpXPquNBDtJEfCg5WkRHWQns2Lwzug6rSUdtmA6", - "quoteVault": "2t5ZASfbr4hGxTw9o5kRxq8XSv1y8bB5YsexnuCCHNws", - "withdrawQueue": "HLvCeSpyqnsJf1sayFrVvNmfAdYphGBKENa4uAFzUUMp", - "lpVault": "GT7CcBPVQERhtf2JzVrscFCnhEhaHwRi9pNQ5wXKKaNu", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6kY29TB5NDx6rrJQdpvKMjXC2Yyvdqiaa9eEw8jgYfZ7", - "marketAuthority": "6nUsJjBWHVRVWFRxM7xNjeVXqmG5rvRgGxSzgxAEZKys", - "marketBaseVault": "29KSSKvckxhtKMMsHcTN2iig4i3jA5gGzECXWVLUSJZh", - "marketQuoteVault": "FWo5aFPUZTY5PKWobP1pV1eU4NhPEw3fxh1wEGn5aMc4", - "marketBids": "695GauxmQjUQQf7dUsDYo3s7Ad2AwEDbEvL6qcoKXhu6", - "marketAsks": "8rtLG8kJ66dw1xGfKxrhusnfmby5fquCoYnGgqEvSaMx", - "marketEventQueue": "6YLB913xDv6Q8D3oJBNc7gkvHJNGdhfor1DJibeAiHdx" - }, - { - "id": "EQ7zubXAtx5BM21vD63NKmHKtD1nkoaL1uZAPPspvYDr", - "baseMint": "68RRPuZQrrw3whXHm9LSyC4y8iLrjkTm5Brc2tUMLNPw", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2F5StN5S3dwkYcyiCdUAgevA7ntujKx8F4gPvY9z8aDm", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Ay7RYPujcTVYtX7dBGVvxzQTADDaW7wJqwQ6DEf76cWt", - "targetOrders": "Fn5vCbv1TpiDbL7wc4fThnr37Su6iGfvWosugtGLGufa", - "baseVault": "G5rotA7tKoijn5zTFtckgc5FTfWbCGoNrQ2ovJcY8Kze", - "quoteVault": "GPbfmix6X8GUXSuqZacA5NF1Ddd2Bo4NM5EJNcYaP3EC", - "withdrawQueue": "Afr33iNVAHXEEHUXdDJXgTUojGswzsehJu9jLbrE7Yid", - "lpVault": "H9ecAWLVfYyvBABWdaGJ1p4uUv3r6rsj7kP8UMPnk6Bt", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7tbVwVtmWVfBfgKPy1URtzCDGCB3uXKYWEt21CBLaCue", - "marketAuthority": "DB5pfBkd4eSG1JheaU43uN8baZuVzQRHmUQwAP1McoHb", - "marketBaseVault": "GcaKjKHVcVgXnGSNcBChV87g17pUeyd4qHAP4PyF6ZgY", - "marketQuoteVault": "A2AWDjB2f2YxJJC32NkYysB4JLJzTNH4grDhxoKkjtrS", - "marketBids": "HNVPzS6cYoRuY53CVpMU2zszzuMUNHHDH1PiJUEx9eZj", - "marketAsks": "5wduXDfTB2XJEjRW6tPnDzpLZ2eSQqws7p83ZGDP8Cww", - "marketEventQueue": "udA9PQ6r2a1k7kMQESa5HDo9XoBAxpYZFde31VuqU9H" - }, - { - "id": "eQDRrZfVWb3FBjLKLyp34fFzyRLmMxCKWfiQdUPNTFS", - "baseMint": "FUtuibwUW4jQC9rgWfLcPM3t2XQCPEJ17QWsu7cbwQ6w", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "Gden75UniJcPhrdjHarbQ9QxPKTC7qbPJnd6CAen5hmw", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CqsQhJAkoaqvF7iuZSJTv3DsFga8BAiUNxoWeXnvdz71", - "targetOrders": "GSwkvwrRgcm8PC6iXE5XWVNd6B7kmM7znDTgLzmafVv8", - "baseVault": "CjfXyfGW2saER9i8TWhRdRPGnGQs8xTXKkJUMqKncQT7", - "quoteVault": "9k6BXTecYkjrjV9b9C3EaoQzCqmyYqcTFT7fjyoPAPui", - "withdrawQueue": "Hmz1NmSSgsiUYNx6mNoDY8x2tYoEmuGQYmm63CVr9hHh", - "lpVault": "7uVVVTSiQL51oNHAVrKVTL2Rf1AtSrFs3mLQuQuAnhbN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2yLRLoYDKXgMN5RvJ2Juu6KnSjbgEYnNhbCxPeSSLxZ1", - "marketAuthority": "AG6c6HKsHtpBtKfvmufDtsbFSf6LqifydxtqUKEmhydR", - "marketBaseVault": "DUzrLzAhm26aDY3VEW2yGW2bxRvmf9zvX3oStQZLqk8i", - "marketQuoteVault": "6QSw6DzVb4ZAMLQZMnnyGqG31dkmTc2xNkt4mQEZGXNC", - "marketBids": "3H7mbWvKsTisyTcrLESP7BgsjGZJtTuyCpxTkT35Z4sS", - "marketAsks": "J1zECeq93f212cEvqzbeLe1sjuguAeBXfv4t8Gy56eaV", - "marketEventQueue": "EdhrXYMpAawWKct2EcZB9JjxuwwKForCdeB7Sp1PqHkg" - }, - { - "id": "EqiggpHL7WUxVbb6xBF3UDnDpEE4JzT5sHsmDc849rFa", - "baseMint": "Uuc6hiKT9Y6ASoqs2phonGGw2LAtecfJu9yEohppzWH", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5pg2oqrKLsnCHBNe7U9E7pGgtUuRa4ceNAef8nQnenrz", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7z6ZgwNnQ2qTZasiT6vvN8snANo6DjSwQPsRSAzY2GVB", - "targetOrders": "BJseMTbRNxVZXc5DLqkSrBWVZVfVZptjpyqhExL7DJwB", - "baseVault": "6UNiUrpd95JCYDR45mQJ81h9wDDnQh1aN6ZNPiohKYPd", - "quoteVault": "Bfsv5ATH7bTqp2QNguLx8fxkdDkPrbem7q9iYmARJHFX", - "withdrawQueue": "8NdxRgDfjj2D24RgH1NgdQpE4gpqG1q9hjNUVVop92Rr", - "lpVault": "EGk536XTN36zfGN6QZp4hdrhGbD6WFhR8af2M9ucWCbL", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "D5fJAK85W8ve1eNDAaK2FWRQFYnrWzx23KHTe6SdNomD", - "marketAuthority": "DDcRAuNDpDhqTYwFUmQYogqimyAF8yYzmQF6Wkxu1sBi", - "marketBaseVault": "dr7TrBDJau1T8DTFFg97c65MiHozd5YL8bCij65FT14", - "marketQuoteVault": "72xhGBTRxJMcChCaAZwAzHDS9UiP9HeCmz4KoPG5TvnJ", - "marketBids": "GuzGia7tpmeBu75DzdTdpFo5AKn7CbBhK8tB7f9HwAyE", - "marketAsks": "HLUxvfoj2rVHiZ3mWqLNPa4fDQBuLfQY5yXS1hSQBeK", - "marketEventQueue": "88AneGcbdMT3ZmLNe5cyE2QUYiaCXG4pHpt6jXM3nWrk" - }, - { - "id": "EQpzg2KYUshp46vLZeLo1vJFYqYaM4XYSKZFchYeoL2h", - "baseMint": "3rH1toffQAELHo5vyRKdwEFxhPTZA7ocfRdJK2c8txoJ", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "4horpe9EZN3329myxGhQXiLporM8uoDdSrAcxc977j2b", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "WXD1ToVj58aPQXhaL9Ahp8gGdq44jQsrNF6PJjhvF29", - "targetOrders": "CDxoU2yEfAEVqDJ5NestGh6pqoWC99iahx6pdmuZBayv", - "baseVault": "4GoCk43swk72VA2mdgZsoJ8UAHMCJpTb7AAuN5nusK3r", - "quoteVault": "EYeUKC2b6UUtmAS36sp8FWeQ6cnSubLGapdMFkgczyPJ", - "withdrawQueue": "GjhMRhM7d5XkkzYauzz4cc3KnKceVy4meBYV6xNkUB1F", - "lpVault": "9ehCjbx7nsTQV6nyfx5uexc1Br4d9jC5qbGLEUBpjgSa", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8gbggkEVPuou5mPfRhJSqmunPc6FQwTRGbS11ruxntKU", - "marketAuthority": "4gMdUSmCFsDox4BmJC6Dk9ugPhrAMFz97q4qDn444RkM", - "marketBaseVault": "EYPhqd7Uae8MroJjWeCptu9vJzFMsFxFJka9fryeNtjM", - "marketQuoteVault": "FWBavsVRY9BcfGJiLw5JenWjV8MXFuLoQXKZ2b4ybw4o", - "marketBids": "54CxxqWMjrGj9tYNp4EepjyJP24SUburnoF2e8KXfPPr", - "marketAsks": "2kZancM8mEWaTkCxmfdk1spmDLHUrhaFEPgEL6m925ba", - "marketEventQueue": "3opoKok8pX7GgUgKR3pNGUYdiqYHn9ahig341cQHYJpG" - }, - { - "id": "EqTPJXtQXFUUA6zCFCRw6W6Epcpv1oLMRaQmKXPNYmkH", - "baseMint": "2PoF4gqWg97yjJk276yUYaGVkkASE7tqAU7H5faEBkeC", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GeCLe37NSTBv23MLQMxR9ovLeBQnC2PiVARrWLuhxDrS", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2QVKnD7egCPqpYseT6NmrXJubTXcdivDEyD3yJmghjQY", - "targetOrders": "4vdcVid8mzWysjsGg93j8aqSn1VGzzDFPjR7zwxDQvzk", - "baseVault": "GEqx1Z1PBtrE5KhGzRaF7rZgoAAQYA9DvZdg274Bk3cm", - "quoteVault": "2kSktaw8oxg74KV7kcdfqgyfLHRizEhBCaJPnLUCkP2g", - "withdrawQueue": "3x7udcWiX3VZu3dC2T5sjeBFKASuZpBGaob5iADXMRAZ", - "lpVault": "FzuWanNNmz1xN4VKhrPBoX6CgwdkXKvgpFmLtcnfYBF1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ETvP88NQaKaKQ68kDtWYWJehkocQSYwdEDVkoeiuY8g3", - "marketAuthority": "8SVyx4pneSMbtdQAMCCwGBNxbJawLP2WidcpwshzBcA5", - "marketBaseVault": "HsuYAJcJ89hKq2o6ksBesowxPJwBCiEtp4W4rEprcRYf", - "marketQuoteVault": "8LnatdhY1QXPZnDta28ZUgMJeX4xQcLktuV25vwZ9BD7", - "marketBids": "CPfJ8NBs7Z6GfjMWwm1pgSf1jBubghxNivMWcJKUnGgy", - "marketAsks": "4UgisMXDjvxHzRMBATkVd7dyQLj89QoLTKiC6MSCmQ9p", - "marketEventQueue": "J6Xc9R3ady7oM3w8KG6FcWqY2WNHkgantxdzQsTd7zhq" - }, - { - "id": "EswWwNzaYnqKt6pasQjr6TQVFmKMBhXuimte5eQ7xAzX", - "baseMint": "3vDfXEw3MZQgjYpLbjoZDYmgVci16CsC6ZDLgUzmcKR2", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5nKygSs1Cn92aYK9hSaW6Y531Tej9XFJpKYEgVuCFRLu", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BLR1HRE1yZE8nD8QLtyFBfjXS74JH7jEnFpsiGPnyvMA", - "targetOrders": "5p6sqvR4K57Kgtnn4ZPW8FKT9rfLfCLy17nk9cJdDXSe", - "baseVault": "8xzb96BiccXH8p1spdcbjbiEV1ZZcnyQz511SnHEzPPS", - "quoteVault": "Fjm3JP3kdvHRNwe9ZgodBLcgwfiQUwYMevw52mJ37kHj", - "withdrawQueue": "FZUj9MXQbJu4D68RLKpo4gDEuhR2Gp1iaFbepkccMiS8", - "lpVault": "BxJcGuixjxcAcciN8CvgVxxNmAHbQCsV12QdtaK5bxDV", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "F47HVATKpmFNBDM5zxaCBDa5jq9NF2KrgBXWdTSv9ZCz", - "marketAuthority": "5YTysoszA9fkVNHXfXFR9CoeXytsAXnHRT7dsTcwxfXE", - "marketBaseVault": "47w8Hg8QbjV5D3yb7E2fZtEQkev2w5SmTuRMgELoD4SE", - "marketQuoteVault": "Agt61Um4BXkYVjS3zFmz7NP4yceb85eBfqjsepSyAje", - "marketBids": "B8adG22MpJrNsvnTGKa3Cm3JCgegqT5F4cjw4HNLYroT", - "marketAsks": "6iiAv1vwxCVDzw6AmerWm5kfqD2ZND4X8DWsgKQaaxt6", - "marketEventQueue": "tMzgdfZRy4pVXY6YYxMWttBu8jHPNCCPLtnJtXqM5Rm" - }, - { - "id": "ET9Z8PYRaS2FbH6n1PRpm65DavUwUPUi5WxBMJ6eMaoa", - "baseMint": "9XtRZwKzDXEJ61A7qCqbPz8jXMYHGT3LwxqrEzB6fqxv", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2oYpzM2rcZBUWnBETTNVUBGBDVrZJ2H5JkcndZb9FT57", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "aDEaPsnx3J4iubZ7qHDKynguqkMbtK3wrQjrdpHpsn9", - "targetOrders": "J1v5d8y17PbcPQyMmL3XXrHU1YZuE3X7rB9BUATS5Uu2", - "baseVault": "Ciy7UwJWcpvmysuuaaR3E1y75Cwq8bW3zhxWmiwVbE48", - "quoteVault": "6n8W4Fig88pNBe18XhHfMP7bcA2i4WuhPB4XYqebWJuA", - "withdrawQueue": "C81vLiWHwmdL1M4j3m3KrKifCg8ko2sBURopCbt5Wqmz", - "lpVault": "32NzbYXjnopBnfGjZGsHicAaqRPt7qfFRaqTfT5W2jNy", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6toroetVLwkEE8xgLSuou5MJikEt6GBygYWdakLd7pHS", - "marketAuthority": "9UEw2Qp2HNU7Erb4mAQbX9Jsvx48L25MgcjQkjRQLVzv", - "marketBaseVault": "CFpdz6QfSufhe5oprZ9pzw1CPf84PfbbxxL5MJEKmsh1", - "marketQuoteVault": "HnFy2kqFJooT1i688GyKtpQ8sBEqc8Ek2VFiQvr5oNdS", - "marketBids": "2KJHG8d6iM4JJu2pYsZDYsiN2h79FVzQz9cGrLvjzN2a", - "marketAsks": "2haHCnqc3MmEUkX875FMWuoHRuF9e7KbrT68gjw481dx", - "marketEventQueue": "4XeHYKTbnp6YRhq8oFdQ9tphQEmHuvqs6ETht1nRJFkj" - }, - { - "id": "ETBu4r5piiD2SPmPcnSkKsEiLzYHCrG6ydRmsw88L8MW", - "baseMint": "8RSyhCxFKYVnr6PGTgKC9o86AjbQjdmLRZjYJjhdTdYH", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "95Z8Z4qj5jCRtFrK99XPovwCwD43n8nHpnW64jujdcXw", - "baseDecimals": 3, - "quoteDecimals": 6, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HCjKrsg2fuVLjtjnHxRyfYTyeTJPw9TKrP1C64jAT5ak", - "targetOrders": "GBiPXpBfPjb1m3mBSkGwYRd6jgLdwDb2rjqoFL1zTCj3", - "baseVault": "Bj1MMrC4SQ2pCHYC3rNjZJKqMdTzpRcXYxFMvpk5W7vv", - "quoteVault": "7qP2UqDKuLWMcREqam5cp8PewPbcwmW2obkTHDV1QWn5", - "withdrawQueue": "8PfargfuiH3skD54uzFVzRPJdnhxvPUfm2iftZjepizN", - "lpVault": "A959ns8W9rzsoLPtizR7PUSH1m2Xzfe84gdSKzwTTwT7", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GZhqNxSqY952x4Sjknmve1aaHaNrd2ucKBxgDqoePKgM", - "marketAuthority": "8JEtU2jfW9Qq1hyMifraiz7cSehC3zanzyW7CjabrVgn", - "marketBaseVault": "8fNQU7nzVzwt6WpYUgY3Av8qxYBUNyyC1Vf3WwP7Qiyk", - "marketQuoteVault": "HBJJ9uhvVDUa8DW6WjGSSCHhaXcQQbtdzuZGZNAnMq89", - "marketBids": "6kDk7dHwWz1ogccztqtm1NWdADNqQzAX6KPCEwUEPuW", - "marketAsks": "FC8yfMsTLsCFaeRt8EhHJtaWbiA7Qe6qTrARVBCsua9m", - "marketEventQueue": "HNBZwjXx3sWBq3iurMgMmF3SNxTKRSYpmhEZkhNMgM36" - }, - { - "id": "ETdpNNvAxAEqa2mj9RccpDM2YyyyUM83eMwAxQycUUp1", - "baseMint": "B3Ggjjj3QargPkFTAJiR6BaD8CWKFUaWRXGcDQ1nyeeD", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HbYi9g35EqRwJYJA66yCNvhycicf4H5ir5wjsrW3fYZC", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8Z7oWQpVA86QVcmgLdf1HgoMSrk6NajzgytU4MBzL8Lv", - "targetOrders": "HWAAAYmqU6ETD8GbiDf87o3UmscAffB6a4FiS9w9GzoG", - "baseVault": "8aRPw2Wf6GpQESYHLJhEfbMtsxzgxYjH6aYRjAe5x4Uu", - "quoteVault": "2ePtHVEvpemuo68YxLYjv6qkYpV9RJjWVUgRiniJfG5d", - "withdrawQueue": "efsFUUoueragkK7zmEJujkGrUJPjbvEkGqL9FJqZi76", - "lpVault": "J3uNsz8xEk7stZ73VULyrRHpH8cbWWvSWRMK85WhSDMt", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9xgxfrcUEMbyXg8FQsuyhNXxQ13Gy4kBqXJgZnXDdzSZ", - "marketAuthority": "6HNPZN9Ye3Yb3EZMdpWFQRgtBDLzzTvALWrj7Dz7QoMd", - "marketBaseVault": "9yrUeZzU9EihM2iqifYao6CpFPsvGbfkcGSnwyXcXjG8", - "marketQuoteVault": "4MbL23bCYAXagMba1C2KbWSc3pEqfeWPz5r3PRHTedey", - "marketBids": "CBFZVtNKACTkX2nRDPgbgvnGeE3JspwmXqPiBBq15PPi", - "marketAsks": "2q9iJE5DicL2so1K197rnZC5YJJzb8o9xZt1e3BJQr3i", - "marketEventQueue": "81voEKSMRTQ7EKgk7x8eS33KeMNXBM3SfbMm1JDPLbim" - }, - { - "id": "Ethd2gXKrz3CDE1Rr7Dw9DUmASZtojF4CKPP8QQKeN1G", - "baseMint": "7rrJLRar2WjZwRoF3iJKHKnA7d7d9YJT1X9HAJnwUH3Z", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Uswe3ZVFP6jzxBgC1QHfQgYRMTMjbADxcDfu4r9bKTh", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3DYKy1ZxjD737E7n48jREwa34GXRspJB779vwum1ADjY", - "targetOrders": "4WKSRkYtKrXtwwtR3AVDuoR7tCL3mv5GPEAopSXrFPTX", - "baseVault": "13L51E5Um4t9i1m3dt5rVuc1MdaoAGFVnCTuZrhk4J7i", - "quoteVault": "Dyzo9r8V9ThkpPgBLwn7eSSiCuLV5Fg7X4QGYLBs8n8", - "withdrawQueue": "91PmrcQVQJdhQg81etQ8bA1AfNQh4ve9PkwKH7mYUNZD", - "lpVault": "C4HyhWSAtAxg4UjPvX5Q5PzWoQyBKJLGPph69QGD19A1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FTSB6Zn5gi3BU6q3C9jBJM5gsEWSxixaAheX7RTQHa6w", - "marketAuthority": "2HbDS8hrqSbLdr3T5ag7XFdXbx6tJNugYewszW92tpzV", - "marketBaseVault": "2vBhAzAyk2JfXxwA8G3vNgTFMMDngkC8w1woo9mBpGEr", - "marketQuoteVault": "Bw25erDGJcxcNDubnBabn9KTNqr3SSRX86C4m8WpPsnn", - "marketBids": "3WmkdH1rV1goj3Tck1NE8AK3rLNr7GWTaYqj1FQ6MMUH", - "marketAsks": "Hmkk2sHcyLu5vLBcfRrpENEFM8VnFbqYcgiHWtXRBCzX", - "marketEventQueue": "F5L2Br3QA25xc5zmFPmjHBqLgXdtpibPGh7vzKASEKMG" - }, - { - "id": "EThRfBJAwYkayWmRGtmUj35C7e4Y5YtJ2ApMroEFbV3M", - "baseMint": "76ijxiMkj4DX8q9QMtqpzTxFnT4KPmWv47sZf2kKoVwk", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5tu1HTSL71NoLMZTeFqyovR3UTqTmiDtM3NeHrhyWozF", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Hy8Q4vDcghGu44P7jQysFfg21xg2NxtTLsXEEuvjSr6q", - "targetOrders": "EXWpLdMsbgLiN5XMoBg8fgfMs7HcPsAfvrJajUTt4VGc", - "baseVault": "Agr3biPwUvJnDXkj1LiH8RqpWjjfP4tdUxKgA72dpsZx", - "quoteVault": "7DWfi1jSa289YT2gHqcjvYmtzKkswRpsG37oh1pNL7S", - "withdrawQueue": "BbEVh1bHzeSenW8JMcMAmAXqewFmpPMP56zZAqKj2w2", - "lpVault": "5xqYQLccfMZE7khSHAjZaa5NRg5FtoNTRSshp8ggAFts", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FnRN675UCkufF4hGi4Ps3V5B55nyWqd5Qzx3aBffYq7V", - "marketAuthority": "9XeCzohyq86fRNmBeptxh6Qg3UrccsTth8ZFAirMFqrK", - "marketBaseVault": "AZbhhS9qok8LY8hFFWCaE2fbCxcpc1t65njuYG2ce1h7", - "marketQuoteVault": "A8d8N9fV5mLbUfuWwrkAeoRcW4V15ydi5FsqQn2bdiRP", - "marketBids": "HygdTf9Wz3wKBaxSCigziHCG51JfUn98hsQfGFZW25uo", - "marketAsks": "4WARYvzRWu9jbcqMqcMKjrmAoVSszuCD4PZuwxAwCR6i", - "marketEventQueue": "D39qeNoMsKczL9TY1y8VzXvbhS73Qc7UjEQFeQs19AUu" - }, - { - "id": "ETPcUPK94uq3XicjNzvwPKMvmXTfKD9CdESSXq4ej3zT", - "baseMint": "2mDJPcvv7vigZo9ZPxhHLpKQSixCkbohVY35eX6NkN6m", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7ihhmMDY5Y9PzTJC2ucDpk3ouBoMGXpJmHhLmKWEfxh2", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2V94A1UgmHbiMdUiN33BFkZKjQgKAAHQKqRB2KL2yqqr", - "targetOrders": "FQiRaSZy74QZaFQSZqjBPB29kD2vDsT3kDBtKC6DGfeG", - "baseVault": "HfEksygFhMYeZ2kQrCmsu2rqVLXPy6tRAmGFRC5STRrK", - "quoteVault": "GCY61KREuRiUmPmAu7JrgS8EEqoaRAnZWoudFg4sxdG9", - "withdrawQueue": "5QqM9n3R2WzFpyzjkfufjTPdxN4nXHb4GG1Y68gVoWjn", - "lpVault": "8VPCGt6pGw4fLQxxhFvXV3YjTAcGXs6MJc2Jqdgwo9Jx", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DoL5SXaax9LwQM9JfqFBymiUfSxH9A9cwPugPuHvNTDM", - "marketAuthority": "9HBWsKtGTspytLwvRedU1jYqYFXXmf6yrYE8uMAg1mih", - "marketBaseVault": "8QGhKMbknFh5WVhG3Cb2MKHsiMHNVWzDGVzbcaRFaprP", - "marketQuoteVault": "Dk6qmq8rZ4YhUePLReazQw4u2oe5xqcCYfkcfXCSUrtF", - "marketBids": "HDbgz5eVzvBQUvjduT6sLLRydcHwC6ykZrEyeYFWtYxV", - "marketAsks": "6aUKcRM5FuGJVkDVWjXK4oEAaT9GxSrHYPev4w9uiYAA", - "marketEventQueue": "8Sa2MDboCjVjdAezPLsDwsRyfkZPG1r12G4QjD1kxEmW" - }, - { - "id": "ETTUCM5CFZZoeTEQ8TWVb9WchqBshUw4MLeRGj13dzWV", - "baseMint": "9ajPmmLNtwFsHjeU289Y1v9MU6WwoBGVcAnRVyPcj5YY", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6vdraq2rgDBgP4mhvNMabFjcSGtLqs4jGANrykqXWNU2", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2jcT5CKQbbu17SCZRseRbCVMgDeA3QMayJqouCF7Pvv6", - "targetOrders": "2AYLtSVmfPMJX8yPAqGzGz1jxqS1HpiaifZyVTzHi197", - "baseVault": "G9Ryu99HCxrJ74EoVcDYTW7ZGbXExX8437ZuQWUSuTET", - "quoteVault": "fyoDpaPg9yX6Ys1AttATQhaucRnCDAofTpav5sz5E8C", - "withdrawQueue": "CRDFtn5TkvoAtMykGxQy8rSkmWPU2Ns4Agsr1qG4xqNn", - "lpVault": "A4ChpGAXKLWk5u7RW8RD3y4q97Wp2zx1EHRmTaCvvxYE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "62qoceMPhVCBF9RQSSgChzGpNMzaViHaSreGQDcRbh9F", - "marketAuthority": "9Zz9EH3ErrpNMiAQ7v43Z6TVKbfF4waB5vbX4nkfY6t7", - "marketBaseVault": "ZQVMZGRXNe9uNNtk79Zo9RxP14j8EnTaBVi3VTiPC99", - "marketQuoteVault": "mXhizxyVQFzhnTvfhnQxfx954YwLMuUMCDb9aeVcdA8", - "marketBids": "HVVm9BopEZFKaV54FCQnStLNcUnTbNgMSoxDiKHiEgVP", - "marketAsks": "7TgAVtSebkioitjaUWAwBp3b1e1qsw1kspVJsfgj5RMw", - "marketEventQueue": "DNnTjg6EUKfHZBaubS9tn53gy7KHgF7utFVUNSS7NL3d" - }, - { - "id": "ETuqKsXsoKW2GmzXMR4JeLHcgNJbbLa53mmXr82Yx1vZ", - "baseMint": "2viqvbN3rUbWE9P9WQkgq4ZzroRMzHM7RY4AW1VowJnE", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HXAKi4PD7vKPc4xhazvgDAskimjR6wXBxhtByy2NYo2A", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CTrNrHNxhZdvTTk7qSPHxQY7YDGJxouinhXG5KPL22mN", - "targetOrders": "EeBL6V3m5RKPRVY4jzHaoxV3upRiFqcGjmfNa4jhbX1z", - "baseVault": "8E5rZ8m6CPFmu5bkQ95C3YAKQ4cuo25po7xpT2uojTJs", - "quoteVault": "9T9PjdPt39cvsvY8DUMARxi8eektGYsTqjs7YfW7FGHW", - "withdrawQueue": "7zapHa3DNLToWHPdBkyC63CWcVhLpFSeUixKo6PP6VsN", - "lpVault": "7sAqqM6AEaY4yfnA2kbWYQQTe1UaM99q6DLmQYxp2Nwk", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ED2UxnLSMAKEewyhh9cVES4NdvvXCgmVZSrxDQHGaexk", - "marketAuthority": "DGHKbLZ5Sj687PaqimSEQ2ayiycc5rbLZDTpiGK1fVro", - "marketBaseVault": "eBG5g23SFqVduy6FP1dBL7saj7QupbCuLmu9mTbChrt", - "marketQuoteVault": "GZ2L4C3RCTeZ2h3HruHevKAmJN99kdh5n4BNx1sotgHr", - "marketBids": "F1gE4pKM5aniVqPgFn25hyj6JMA53UxVV1Jsbt9jyQUQ", - "marketAsks": "A3pzzHZEUGbiiyqZqAGSRU8Wt7udVs98zVD9efEzy5Nd", - "marketEventQueue": "FuxnQkvze1BMCq1S1gtP1KSaz7o1jgy8sUHo9cNFZ5s7" - }, - { - "id": "ETV24v3bzTHEm3ymM79MF2NHML2q13voYL9T1QzVpwMm", - "baseMint": "5R8Ai4pQuzteR1Y5HxpscQH4Es2JNWcQZbMmu9RpZwoR", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "45kwVQzxmgwdbSUzVXFetgCnNw8AYwr6yQUTdLq77axN", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HWsJYCAmz6k18rUvUBMrCAjw6HgHa7KTX69AUJZ8DUZj", - "targetOrders": "5paApsarHDQX9pAsqW8gMun6mx35Cq2J9FSi9EwptG5N", - "baseVault": "BJb14HWbS7twJiGihLTC1hQtJeDWjvEouErUVYDQ7pCa", - "quoteVault": "9kdWjY3dkaFgQnUkfMHDPN8ZPru4xHwAyUNwHVGiFSpu", - "withdrawQueue": "7Ci5L4B6GL2PfVLXMAvULCBjFBNgY2rrt8QSQGfpqHdf", - "lpVault": "HnE4YCkXSReVwR9sjsDvCyTNF7vnFg6qf9U6nTuEF6KW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6vdCK61xixqx6dFiTFGBqXt9mdb4cLuWN42TvZ66pfAz", - "marketAuthority": "4yzmgurjuUN9tziXupA15wF53QKDfzyo8zTv8oXVecCU", - "marketBaseVault": "7Ydz1oYF3r4oTHrHc7Lj9Nvq8gMoFmFLocDGs5sjuPV7", - "marketQuoteVault": "6NqfaXoNsenExctq43JTZKoo6cUAqB3NYThwX8M6XfuA", - "marketBids": "4atWwHfbcDaXYDEYS2UYLdmoBRPz6zFbZ4VM13ZiePAs", - "marketAsks": "2qSxW3wB8WRmbaKsk68A13EipZFkNygeWzCLCphjE7w3", - "marketEventQueue": "F7tTdNUbVmcEsSgw8KyxujVyWRFuvf2Wp8LKgL1HXwdd" - }, - { - "id": "ETxvTjjhShqducpRwixmdfUcUTbBFZdkWMCZctnhaWtz", - "baseMint": "HkCrU2Vk5kGvvPUUR2dirjgAx3TbyCPYXRZbefwzCyCp", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DvkEsfaL5vB6TvYRqSoZ1y8MNbb5ygpG5HEHAPFbTvyU", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FcBfk6oUd8LSpVC6u7upgdYy2XWFee4c2jhVbbSXbYFE", - "targetOrders": "2EmHsUKtMdqmMuhuS717jG2k2c6qmSXosjjVXFRjqnP3", - "baseVault": "AhmZTvkPB1mmV9ZSoFrah5LZ2bMfKHwAssLGHmrEhehU", - "quoteVault": "6ApPF757rmDqYrkwuLNRf7hiE1jAXz1NHXaPJ1MyzHxz", - "withdrawQueue": "Dka7UD9bNnWNP6jAGMCVWZ7HM4WZvi8sYF91VG1LeP5u", - "lpVault": "7BkfYcimqADhPto9VS5UsnykmG9wo1uriUA1cqZxrj2Q", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "D8uFxUK5Vu5eF38CUySWersGkoaHGuQUjqwvTHuK42uM", - "marketAuthority": "7UWPEaSuqiBMkVjPCNRwmhnT3SBLMbe99UUpdJe4aC7H", - "marketBaseVault": "GWYVV57FfECBeYQfK2NzDRuVfLzq9w9znHaaKbBZmmP1", - "marketQuoteVault": "6fjASi8V1Kz3zWF6xSWnN3PQtnZPaD9QrWzCZdmX86xE", - "marketBids": "FiwpyuGHvkLFjrJbCVLGzZ7ALh38WnKuJ2EgWTG6qkSm", - "marketAsks": "45WQhF24FprUsPpT9mS9jUny7q72PVNjpLNfaCCSeLa8", - "marketEventQueue": "GNVswzZD6xzSNhfE4ifSJJDx83FtQxfyJDjmeLzENrmw" - }, - { - "id": "EU766cQ9GopWyRHXa12NpdjwhiiGyn2jRR9Gk4K4Cb1d", - "baseMint": "DJafV9qemGp7mLMEn5wrfqaFwxsbLgUsGVS16zKRk9kc", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "N1yTsVuQA4hbdrBEazYYM5P1zhGWJYR7A5xUZANBpxA", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HdA7NhFq5MF1esv1UDA3a7Bqai1pmMpXGwi2h6N6Ho9p", - "targetOrders": "GUtLqhnCxcKvw4vSrHr9C5yBtmbV4EogpAihWrQL2pSU", - "baseVault": "FjaAVSmTvymUF8fKR6h2VMYVGZWsp8AWBbNYbATGAKtB", - "quoteVault": "EtKWGnaynC9f1UDWvy3qS5sMwFfJXi2CrHvzGsywwNZW", - "withdrawQueue": "B5wEgn28ZaXQXLcbwaxGuFc5fqFxhKJfxJPbcdXf8Ut", - "lpVault": "JBGkdbUoA8ZaKMyfDmzcLtQV24A3kGmuUYjm9Uo8gGUr", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6Pn1cSiRos3qhBf54uBP9ZQg8x3JTardm1dL3n4p29tA", - "marketAuthority": "7ujXDywk5vAC1zAJMnLSYzzfbKYVi2oRAj4JFv7v9SJH", - "marketBaseVault": "DjCXRDEZb7KesT4JQznWiHjx8UrQ3f6yjp2EUWaEJhQQ", - "marketQuoteVault": "G8qoKLtfSCiZDQLLSxWXzrMhycn6p5oLVYb8abNnQRNp", - "marketBids": "ArPsGAcWKDELFUnP6bTiUMz3PMAZUNheLH3FtnPphBkf", - "marketAsks": "Gw5DtqWFZyHqHfdv7hUefn6ku7qXCAhMU4GafYFemV6P", - "marketEventQueue": "3LBzkRkva4j7sVVPuVRhz2Q5VER69ADnGDyCjd95QndF" - }, - { - "id": "Ev9dy1FAvMK4vVKyZFXZoth677k66EiEmBAgdJaW8bvb", - "baseMint": "FBebPqy9tacKuthb1qXpNKmKbHG8mSvncH5BMH3sJBv7", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CTBSCrLD8xYGHCXB2K5Wzjr1re5hoq5FyrUzRWcbSHaa", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Ed7N3JQJoxFLiyTRbgtqEd1PxSgLbfR2wmmh9LbzxMmM", - "targetOrders": "ANFrtdQgYaXUUYMwjSynTTcbzc8rzLBbbyUECHDsNC6X", - "baseVault": "BJyAMnGro3qHNTErdFyHhyjdb3dgQPBceiyPkcfaPcMX", - "quoteVault": "8HycXdRuuFZ7cMkXwu8L24RLfJ3fVqJHGPqn5m9AEU8H", - "withdrawQueue": "3ZzgQKLRdL7ih9Z6DjjUMuz8htEX7NBs8i1mHzGpaJyE", - "lpVault": "AzTdBnxvW2HecPk8k6R2sQZp6yrEHmeb21vbrUdgPads", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6zJyhCeVmE1uxK7gw6hGJpD8TvgNuTVrBRLgbzwy55Qj", - "marketAuthority": "HjZbvuAfLN2mGCJksRJ7tjHQESms5DjuU1PJERVYYwa3", - "marketBaseVault": "8rXmzFvhPwi1DVL66hfSF6XocqHMxSMDtvyzfk8F9j4p", - "marketQuoteVault": "6LW3viBR8hfrDb4jsziNEpSwCpALeYDx6npn6BVmEUEM", - "marketBids": "6HTJw8fSfYpAnDcX7eHpRHdb3Kj13U6ArbHQr2S96Kjo", - "marketAsks": "3bM1ue4uHSzzkWup5dcnFbJg1WKy7aduATB2MuW4728D", - "marketEventQueue": "Bdfw7yeXsWfiCY3EvHc42VxnhrscjnLiSgiQgpNvbtwA" - }, - { - "id": "EvaBb7wgJw7LKzbLCMUR1cbCxdGECDZ4F2fwof9q6hdS", - "baseMint": "3vHSsV6mgvpa1JVuuDZVB72vYbeUNzW4mBxiBftwzHEA", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8A89JPf2zf2sRXbLj9aAigVsi97FTsmYszuN4iq4Ezap", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AzCZTvQnTiz2Xa83p8PvrfUDUrbeT7Hud5mEseKLfoS6", - "targetOrders": "HUjnMcF57dK8jmtZzVvc93fdCA1BPt4sbzLreTYaZeHe", - "baseVault": "Ht9KGk6C2WmNgX9DVmUCVQkMynfGgQ1TqJoZh8u7oQxY", - "quoteVault": "5oqYTxZYzDvBmgzzYqAmZCkokgdboC789eFp7BKDDgfi", - "withdrawQueue": "FHGA4EtSCcC3rTGd4mL3uHP9xkFEbLFutzVnaBeXJZ44", - "lpVault": "6qQdN8tAXsiL3SdoC2wUmuL62eicjC6wgJgatHw9mScf", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5d596UPqyCReH8SXdohkSMad6G1HdHqgfrEmUGj8waBg", - "marketAuthority": "3xiBdEwep2uyj3taPYn2hxHGMJqNfR9XH89yEKgL4ysg", - "marketBaseVault": "CcaPBW1VsePjaSTq78aZxTPvGhs6dfG86fqoeDPF5ezw", - "marketQuoteVault": "A6eGKA1sgR9B9SDViHiwwVXBBzXPHXnWTsvbMBfYNU5d", - "marketBids": "A2VMZnrwqb7JPXmV258Su6W8P9iGSkbcJhdpbhUrkoQv", - "marketAsks": "FGB1F9mSFanJygkDR6RAGTxW2ogBWRPUEjdCRaDicVdY", - "marketEventQueue": "8Xy9MbvSYkJzWDMhv1WKoa6QThBEujG31B6Xp2KAuSK9" - }, - { - "id": "EVy89kSpyFaXgJUkX5Cya84EMCBTLKGqSdAbMUuqTUVC", - "baseMint": "HCgybxq5Upy8Mccihrp7EsmwwFqYZtrHrsmsKwtGXLgW", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "G3EBZvHFw3pK1Xyb1H81fzq8u2S2RJA8f54UQfBekKrZ", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "C9Gec3ZnrckWCbCkhRsD6Qn82YBH3hgCt7tUBP3xUma1", - "targetOrders": "D2NN3UZnCNp5ooLBNnHiqRb51hbfK2A3VXwciydYBc48", - "baseVault": "7hLbEYJg5B6s5afH35o6iyKUx2UoG13xwhpshghsDJAe", - "quoteVault": "2378LxkK2NYVpk9cZRkAec5PoKnp9YpMt4PJtgoWeFdm", - "withdrawQueue": "7j8FYqKgnSXiqwSSBrTLBxNgx3FDvn6ELzfGu2FQr35C", - "lpVault": "Cavw8zZuXNDahki4XJP63EmGNao6Lkuqexagt6p4n2rr", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FtNaKcZaUJMuAWVG9TAaNdFcxH2ECVcCZRBgCZAh3skB", - "marketAuthority": "85oEaGrdyz5qQpx6CfmjY7wuTUVYkV7qVVZG4Pb4BRQe", - "marketBaseVault": "6M2P39tYbaXwfNs8oYnQsgNNJFBB3D2tXSKaUaCCaSyU", - "marketQuoteVault": "DKojN6ekQCsqnkgPtMBNBm11xAruQwcCknHkp8HFvbME", - "marketBids": "GFvJt2QuLFLHd3fVTjyTk5UnX3wsWzrqSeXZkZXJg9yv", - "marketAsks": "4NCocdtYGMQrohQSbJrx4TN3waG59hkxuxnZ8YmmzcGf", - "marketEventQueue": "6Di5SASHqeg8jcisvDAAWJb2rJrv7UcgBvgkSETVkicS" - }, - { - "id": "EvZanXqG9Q3Epnyfup15gQNwTX9hDfFmLAtX3fYm5BG5", - "baseMint": "E1s2muWwiLT2n3EQUL27hgviaPRRXWkpXD7ShpfgRvVz", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8wVmeBKQ2AmjZdJeFUKLXtU9QJFgkCFGXae6NfN86PL8", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FxLxsvevWr6Bz4q43Qy6WPyFV5LbQY9QNfxRGoEK3vmE", - "targetOrders": "5fmZWhBPgecsh6RRGxGgSY4bKrrwA7P6BE8W1Rxdk61M", - "baseVault": "EHDDh9pmyyzEN1LpdwtgKcaRwTaPD5kzyXku8P1irWP2", - "quoteVault": "NX4SRKqEh6dtGmJfmEyXYnF8wPWdqyKWXx3Gb9BzYxJ", - "withdrawQueue": "BLcn3Cthz8JxFb1PzthhWDBZRFpVGGuRbByjjTd81USn", - "lpVault": "AMkMoTsefm8W7pFMLTW4HndBLWwRzQh2xdwqprD6fjEe", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BV2LPu37BdTYr3T9x75owx7prSijaXsqX4GeqdEcbfDn", - "marketAuthority": "Bb9kxqYPpu6V1SmxJ1ejruhxFDC2nWDxJMfd9VA6fduo", - "marketBaseVault": "531nwRUJBVDWKbDAUa3S5ogFLcfV8XxytiotQstgWVWE", - "marketQuoteVault": "B93vatmHUhbU7wQZauaS47mP1TgaU5YfwTbVFbf7bie1", - "marketBids": "558NHCqrzzuQ99DAbPnJ7KqKL7TocMkCunPW8YhdbQj4", - "marketAsks": "BHvTqpmDW4FM8Epos2NXPzyDrfLzhh9Mp3P81b37AbH8", - "marketEventQueue": "A5gvK9XiSA4hg9dYiyuG4ZJTgLxBXLTRbwsQHGoBEz7g" - }, - { - "id": "Ew9cqLEcepDLhZiqzGNxQsBY3xQEaP1kKxMLxF7ABskN", - "baseMint": "CrhUSH7FDwB37BYvPsVnVbsGVeE81biBzfkD4A4fyJMv", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4Dj8qQuJaKMb3gDHT7rbQM3ZeQib8sqp1gVJ8GnwdxeK", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8xbdLTBGJGXBT9C6fKjX76kxTddYWRCBuJZFFKYTzVf", - "targetOrders": "Hii6CuG97acZrpt2gwpTHu69NqVsuQBFPW5NhkGkEzKi", - "baseVault": "C5327akaiqidv4stBwspK1gtGpsqLXBp5KFovH1NofLf", - "quoteVault": "FkAzrnKtfMttzmLRXKk8hPc8RxvsBt5jHGafccU6DtUf", - "withdrawQueue": "75VRTTeeV3mnphPvCAceyya1qDpG4935LV6ddVrTbvyG", - "lpVault": "9BeTdZNQpemL3Jfn8R9hhwewWt7mLXgC7AGviqowD4LY", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CmbSMVtqGNZhTZtVf21cCnyH5xafrdkgXXA5AcAUiTDm", - "marketAuthority": "8TGzHuDpna1u63RfahgguJ9XV8eDV7hVSSw488P3yEtj", - "marketBaseVault": "CDGkFdzhpY7KHyUphEG8Xs9p5yBwomC6BoZw57eNfYqm", - "marketQuoteVault": "5SoCaQKhAwsZoWmqMQntWkU9TuRnBtyJmLFVHLdayaDG", - "marketBids": "A5x8P7337jKnLGHG72o39WoEr7m7Dob4PnG1KujDdq47", - "marketAsks": "5d8eWNgszSGUsePhNtn9RYudRKpRwmyUNSjeSnD7d9Wx", - "marketEventQueue": "DQ8CeFmWERm8ivTfARQWEB9DnXrdCYwNnDiH5iuCr2PB" - }, - { - "id": "EWKrJjWDxTsdyfuaa5PeYw1CBFcSRet46zGasQ1JLxKC", - "baseMint": "CPL7TvVnQXQ8aN2DytF53uskyYAVxgNx5z2waJrc3Cev", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "57Va3v7E6jTZcddBrKusMvJ6KFDXaAqe29fTer7v5F97", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9Zw1YQa4jBk6ckS6F7cmex899j1iCBvbqsH6QTi8PLCr", - "targetOrders": "DWZVPWZMXuRzuYR8QTbkAouWr8eawd2taeem4ALWdSTw", - "baseVault": "53SZ2QCxUZFCXYCzYqdjV5XfiRUmtMwqunM4pwhK64fx", - "quoteVault": "9TJMkaSEAwxcCeMovE2T377ZVhhUogx7ia8kxj4Q7cw4", - "withdrawQueue": "CoWDFt52ujzamscosPnE7Z5WjPMfHMMCwwWnFM1pGeSF", - "lpVault": "F9VAQcwmKsPSFG8Xs5PPWNbc4bmJwPkHXmF7xg5SFzZy", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "G7fAg61KsTxFFBQkF176UtwyofnhMPseUZy6mQBQwBTt", - "marketAuthority": "DmgguwUDbSQjbTqLfMTwhA7oSDBZMjX6TBWq5LshzZPD", - "marketBaseVault": "97aACwrK2aq1MnZe9fDUpTXWn8PTH8Tnsb4wN72ppySC", - "marketQuoteVault": "6Q6QeZxm9VaWMSDwY1gL2yK9kxaxfTYcn7U4PmcDwBvh", - "marketBids": "HgMZbM8BDQvu1zNv5LHftdvj5GqNJuVrprt1NekoQAqr", - "marketAsks": "84xBc76Zv5kkFQHmngVNFgV5sGGcujfQCWeho1j332Sk", - "marketEventQueue": "E2M7aqzegrmAZBAhCGWt8Yku1KBymnnM7raa7Dq7E3Pj" - }, - { - "id": "ExBPb4Zy4tmuS5auZ6HEyAwh88TtMqirvw1TzQ3VDJQi", - "baseMint": "CZKnYioKuX2YzA2wnUMVXsSe3j259aaPsz7TfY2xnLmV", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7FUwJoCQJ25yvL1hiF81nbmerFPwMYBjNjsqek846DGJ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "55qXcfHzpmkdD7Exf6kWpAVKduiwxrf8nqUMU3hHz661", - "targetOrders": "8PNyP4NaoQDvXmM7VWEEecdKZ9B7fweSKdLgARN8f4GG", - "baseVault": "Bg7B8FYZG9ga84KD2hnch1kYRcguHnH3NN53GnXhTtzR", - "quoteVault": "FxQMPqyJzQrQNAPkwqBDZqGBKZDCCAizViN9EVp8UFan", - "withdrawQueue": "CZ3smf6S5XpwjPc8Hi7uTaHaYuYiN8ddHWZdKvw4J9p1", - "lpVault": "6QLmfdKnKccFUM2ZKyvTm6Az47nAwbAVWfs7Q3z95RFW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7GyuoF7awDT9mdpW67EwVR4NcsMQqpCdcvyZukgMPzFS", - "marketAuthority": "Axkoa38UdPMcpyUPb3V568ATFaLCbHyckqkWxhrY3qHc", - "marketBaseVault": "HckrP6BZuASB7KZ825NvXqMCMtcJndR9B516DkwpYE4E", - "marketQuoteVault": "fmfsTYtrVZdBkLS8RFVPAR38EogX7p6BF94bbJBYH7P", - "marketBids": "3w6sUnEQxfHk23tPoexgsVPmTyFrcRC6rd4Y8puHxRXh", - "marketAsks": "H7Jc5VD6oWYQLiEWRsrzbXgYZsVSJWqdmUTyez79rYFA", - "marketEventQueue": "GVqG9gyiw94T4EVNeysGVdMMrWJKE6BYf5KyUeYAjH5z" - }, - { - "id": "EXZGoELFNE4V8ug9DqKwp6bpuC3t2JwzbSpkdTcMs14s", - "baseMint": "32Hbw7u1CJ4FBHr11azctxAkt8Xa5TZRYuq6hXty6KXc", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "7nD1FZrRA96qkHZHjfc6NBZ6EKnK6bEp7HTZ2DNajtym", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HJ1rZ3GSASPrf1Uqef4rVXvYhLdfNrNnnGLXpW69xopC", - "targetOrders": "E4w9GEuszfqhkii3RM8ctWk8PH57riPw9nCnPVnL4LE4", - "baseVault": "EEapKXKQccus7zDnmwmcoDURYeyWhhPnfybS6hbNnWN1", - "quoteVault": "3upQCPXommm9Q3EANk8mbpVBwNxhacMWPvze5ugQEwu8", - "withdrawQueue": "DvLnjuZPW7sSoSYxTieqMYRXBR1AZuSTnc6WuZ9ZRReQ", - "lpVault": "HXgbcdee7uK8Tod2tMgqdGvS212pKEPhkdrQXTEDbgqH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4riVviDzhTvbSEvRpBHT7U9KtecgQCrjwyRzGDUkiUSC", - "marketAuthority": "9FXpNJRg4Tu98aBsqhC8srDJm6kk2wgbfdZ1kepKAMay", - "marketBaseVault": "HTTR5zx8Mr1yiu3AGELfQrd5dVHKiKBvTeyRhWcAJB67", - "marketQuoteVault": "8ih2vp8orZbj3bsyoad6YvdvQAurN4iBG4jaougtWstJ", - "marketBids": "27uGxPdqsE8mP8djwSjYhmmittHMX8KXFafW1hSDkNwK", - "marketAsks": "FPSFWs2zr9aUesaRFDk7HhDZccNY91HycCyRA8f7Q7h3", - "marketEventQueue": "HJTuSkTTTKKWUzi3ezDcADAjdcyCdpFqAnw1bFKvt7KR" - }, - { - "id": "EYi8K2z9bnnG1uxvGDSPKgXyHwGEC4opozqA4FVZduA4", - "baseMint": "7v5K9VFiqNTWnmkK4wofVfRzG7f7AGQ7WLXLmP91UibU", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "14NBTRyytdY48EVs5pMTSme28pE46PcDiyZb3mBnyB83", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8AhrEip9j7ByJKPLw6y2suSpHfu7m9s6vQ7xqWgPDS57", - "targetOrders": "ArvvrHra3KbVoYFRPzwyYPxAnyRCWHFBEVbQtBZZkRBn", - "baseVault": "4uX5ubpJJoomXb9T1C1oVQgewXctoVTKbytnRUA6qsNd", - "quoteVault": "AtQppVu7bJFywS9UL9tRn5DBwUtfpGZNNWNwqnNARMMk", - "withdrawQueue": "A1jSFgMeFSnqAHUDp31ggCvBN7yJwniB5MeVf8RFCGMe", - "lpVault": "DR8LewHDCcjdL25Y2Jw3hgh5j92HSr7bdTSPtCzePPAS", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9hHFmTmdwtNncrUQ8GtSjpqSY7SXh66XPFcTdjmdB74", - "marketAuthority": "9ZwW2jM7h9tgP8WPLs9MbYM8rB5oXpoHMjd3KYjQe362", - "marketBaseVault": "CosZ3LpyNCe5MrJQeEYQapWVXir1WmG47xWwo94UttBD", - "marketQuoteVault": "8mZymExkhLB6KJNQSoSCcrwsx4mnZJoYJt9R1R9k1AQa", - "marketBids": "4DfKavDCNQSD5tGUogDv5jkYLijjv5fQ7RpTFYVHqHPh", - "marketAsks": "EUaXQG7Eor35gjtxiq3eGuTbSr4FYsuWLAzK3WWQmoh6", - "marketEventQueue": "GnWdr6QKuqenfrpznXBEpBefRhvuVWnmNAz2Ux4rAS5v" - }, - { - "id": "EykndbPz7GMi1AzW5Vi4vT2SGnJbvxUhfRifroqwCC6J", - "baseMint": "CwChm6p9Q3yFrjzVeiLTTbsoJkooscof5SJYZc2CrNqG", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FVGKhz1BHpR8W6iGFjCoUyBUcqNgCSEV13Tg7jPQCf3Z", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8PtCGJLV7LZSqcLRCy3nHBqqkiCFE3zYFaAQhv2jTD5", - "targetOrders": "Be6CPUKrJ4cPisFVyeS4MKwhp5V9iz3PyhjoU59qUub6", - "baseVault": "37QkPrGouijU5MRSFHRfc7wjsHZTkJcak4UKVD8azzpG", - "quoteVault": "DqStRkk2Y5AwiE8JeDkWHXrf7Dzdrt41AyRjX6Jd6gLZ", - "withdrawQueue": "Co1fCrZPkG8535u4dvwAgCzjePxp6xh6jvGecATn1wx5", - "lpVault": "DajtagLQUPoLgNtp583QGVaPbWHLpYWiNTEWQLjXcQXa", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GREiyoFSEM7zMce3VugkCggdUYXVK5MijJgGwn7DkVPF", - "marketAuthority": "81hUiVRwye8BJAyDhoYqqa8LrfAgnc8oYAoPQ1ErPQsf", - "marketBaseVault": "CQUxc3nvWhu9ZsMx3p8mwJEfNAXHUZLm6a1id5b3nCZa", - "marketQuoteVault": "ATVeHWqBDbrYN8s3JMTbAMjnypgL4wCV6TrvGxvyEZ9V", - "marketBids": "8VkMWht6K1AP1UgboEYkQn2PeveBW3rwcx6989Eo6N57", - "marketAsks": "3bo9jbgWfbENphNSSkbXKWqMr7u77wHiHLJr6NiaBKVC", - "marketEventQueue": "AKbk8YaTbKr1ysuw1WRXnS5zfQ6X4JPtVMp3CWwnmEL5" - }, - { - "id": "EYYHUrTo5VUAwXjm6NZSgtrKpr53Mtbvk1Mg74cxEyq4", - "baseMint": "ALQ9KMWjFmxVbew3vMkJj3ypbAKuorSgGst6svCHEe2z", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FiEEkEspbgYWt9DTRhP7Fy18hvG4F7xJZf9qFALgTUWM", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BuzoSiBywn55fm9U2MtGnYNyahzLMinZ6Fa5xMGoAPkc", - "targetOrders": "CeonQqKXhFod6hDtYPZcUDRB6qKAbx7jC5G3NHSsopzH", - "baseVault": "APqHsFGBmoCwB9WChJ912DjewZvTYnSXVBuGu29X6uMk", - "quoteVault": "92bMnmESTUrRrV6p9uBazo23F9FbouyWxMqGRkS8PNd", - "withdrawQueue": "AtuekgoPxadfESPuSxwfrLiGefoDgE6PiCFJaDbCHNio", - "lpVault": "4kbXa5kjdgFKzBiSSBJo31bN5h4BoXwnvY3jhbBZTBgk", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2cVCrE5G45ZetnfXyK4qCUtmuJRAEk58eMVpUtkBPT9s", - "marketAuthority": "H7b9zdrMRLKR4QvJ6M2b5ajoWAQT4WENeEQVGQprYtNp", - "marketBaseVault": "DsS9KGFCvqRu3zxYQhdyhCovFG4uLsc1QupX13YSNez1", - "marketQuoteVault": "CjDT73ZtK5qSQ5y9yXscmqumuNcx9f7KnBiy2knFuqHk", - "marketBids": "B9YExUMEjidvaqqpuP2Jmm3Krw2owFQZmha9p8FaWrur", - "marketAsks": "6Tki9wh328b9ymHr3MZB3sZ2vCzozVuo18hJRDQ4z7bs", - "marketEventQueue": "AHezGJXu9hf8ZPQNKcPhHNwQQHhufsA9dzNyK44CPPXj" - }, - { - "id": "EZAbr7qSvnJpC7ETFetSr8HMK8o31hBhVtDZu1bN7EdB", - "baseMint": "5pwyQZnX8GkabzowWtFHNeKER1J1omrAdJSYqjtffaQZ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7APSorxoRZ9wx2pP2hi17cCx83H5GVbEX3GnYykicMp1", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HM7d3iWC6ex9XMaotcYADJw9DdPWQ2c8H7drGKkacKTN", - "targetOrders": "H5utSdjmzg1QiaugaPS1V1iLvmXx41UkSp5eRdyonWw5", - "baseVault": "H4EjzZGH39T6Nw8NWAgytqBCprLnqFWfyiSMESmDSuqw", - "quoteVault": "BwcVaGZbQLLMxDKGJ6EX1Qb9VwwA4DCjXyrDha2yDkTr", - "withdrawQueue": "tC4YGMUff42wcJ9j6DFCeu6btJtoTrHk6ggoirRvh1M", - "lpVault": "ARUo4cBVdBrJz8Y9WxG9R7ndm3mBJY6qBtwG3L6uV1XL", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "532Z6yeS2WKDV5PuU5oj8fdVhufpAoxGhBYAFqeSwcMw", - "marketAuthority": "64HviY5dXTbrsqgigCMjsANucFM2pYRcXfjyRjbMSo1U", - "marketBaseVault": "9qySAa278uSs6L9DZorDn3dJAQMBwE4Jp1HXsH97ZWKs", - "marketQuoteVault": "EgTPCy52HSu1kXx5M6xZEAr411Hp4MBJ68HhefcutoSY", - "marketBids": "5PFyb8GcvXWMQFmaQTcYti9R3QRoiQjJ53QR4FSPWKM3", - "marketAsks": "4jkS9BTXuHnK1MnFoiypfwXUGZNkENDUTmQUvi6JhKSQ", - "marketEventQueue": "6wVYZYVK15WJZyqcizNeHoyrogUnBKhcAHaG9DmdNn8T" - }, - { - "id": "EzN8mttBMhrAqPpjbjhVV2WxYwsvA4GLTf71VYyiqdUu", - "baseMint": "AMNoi4727tzy7adu4wnx3cN2VQbQdG71DqaPoSm7isJ3", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FnNxVndX31rigEG6ezEwzThAZVykc2W3SUMC2cwxvyv7", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5EowrDg4UfPTWRpwo73QgZR5LPZ2oU8FRzRRMwf8mWqF", - "targetOrders": "ABmKyF1GxR2gs6CHY3MLLzA22Mmk1dfby8e5M8pgF1sQ", - "baseVault": "3bViVVcUtdeMgNBrNMkK8zTXrFrNZuqGBhh8EgiNrnJf", - "quoteVault": "Egrh4WEzvDUoGGk6ZfHYns5mwqFhQ26a1SbXPUMNumNo", - "withdrawQueue": "8gwvD2rZ1jgooNBVRTJazGNBDaZGP5G8ggrqPFEDM6bo", - "lpVault": "6QvB6U5P8qBRk1QGNPQ8UdpXy6p3yWnjPqfsBX5afTWY", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2N78M8HZj2R9rSHxVXx6QWSvFvvnmhoEbsNPfrBdtdGo", - "marketAuthority": "D8ziAPb4rkWxEcbtDCzjE57VAQhTzS32QN9NdpeduZrv", - "marketBaseVault": "4XPHoZbbPXCpZfDVupUqKpZ4RAcbiacU4K1RJMUQvL3f", - "marketQuoteVault": "6ucoKrKqPmFvmVFhcVfA934PCGeyAARdH5kTc2aq9DTm", - "marketBids": "EoeaxjvgXy9BUAjZTWfSe5KvzhVfZw2WBQiDiVn4B9R5", - "marketAsks": "BZutGGpcYicmpPEGiiFzfm5td8TwQD6ZWPpuhP3PYJDE", - "marketEventQueue": "DAXcAUdS1W8UtdhSsQRNwhdQVyn18iYh1j93TS5G8uWE" - }, - { - "id": "F4i12x6vu71dhHpWBrpRjPYGnNFqH4emVPrsPZydB5c9", - "baseMint": "674PmuiDtgKx3uKuJ1B16f9m5L84eFvNwj3xDMvHcbo7", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2e9vCgqAhxAJ8zLtmaitu8Go3hT5vozMtAtCwgAN83Yu", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BrPN7xJ9Spmap5DpkanTw58BaKCR6G7XB88gFnfN4ubx", - "targetOrders": "CNg9QccDrpzpCJuPTQ5ZYTvSRm8Rkrwe983gqHGFyn8Q", - "baseVault": "2dwEo9xNZHun7ub9J85Uh7KJVLtn8d6eMYZWfbquHZQm", - "quoteVault": "zJUes5XbNwoBkqKHL98BVQJs8YcnvZLXnNaCbs2a4PM", - "withdrawQueue": "8AYTMBsyEG46PeBnFmhv2967jFS3b2wgpxeohNimCxFJ", - "lpVault": "4Wqzj95AkkoxeSZVUJRP4hSFav9SrvpMbCXfaeD3wAic", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "27vfNXchi3Pzdz7QDb1q9zcjvk5sU94U7gUNcis89Vy1", - "marketAuthority": "8JLsdPjr69qa9LcNuJfP5QUmVv5H2m3jyVuUJvym5qU8", - "marketBaseVault": "Ef4UdzYf17HWQ3uGg1e7frntnCXYTZPje6SxJQ7NmmLX", - "marketQuoteVault": "GJBMsqis5wTLLRvkdk8JLE8UWqYURJQM6Nme18MwDdXT", - "marketBids": "9bknzcLm6uzUWGhBbKdhvHBvRvHxUQ3WscWQCmPF2YRY", - "marketAsks": "F9eS9zuonxJtNhFLRjVNmZh4KNXCRdbhaoHqxne5Lqez", - "marketEventQueue": "2HkyVZdPUrMr2pW6zwumyPb7QC9rHNA9TfNzR82RbCyv" - }, - { - "id": "F4QCmk3NV3kxYtNwY3d2cSggcYh38uk7fBU4b6rpJ8aZ", - "baseMint": "72hgmvS5zFxaFJfMizq6Gp4gjBqXjTPyX9GDP38krorQ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "491ns4F3F7zbw8njpUrZRrFmb4vbr9zHjjxJGiHWsvM4", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Can9M6kvKYzqm2JcQBckQkUyZhFo3HH1yiiwSE55d4Qg", - "targetOrders": "3f7eY81DFNV9KyQwUV1ErbcyUDgWiGMz6oKEPMkrMjLa", - "baseVault": "6HtYg9mC9ZCh3r8fggz1SobdLLgZMRAAjMvCFnvh1EPj", - "quoteVault": "D43cyXCLnjGL32wCJUKnU15TpqB7c2ysyurLLxLP8R3F", - "withdrawQueue": "H92euQGAFHZPKT7L6idE9bxLgiUATpgQpPSjbJQWgZTg", - "lpVault": "BWtQ8Q2ridtdycrBBbbRPD5us5DYhdqTeLy5sMw965rX", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HCE4wQXApNyFBTK7gYa98QCYbshCz7EkH8axNz3ahvKc", - "marketAuthority": "8US29p3Q6tFnixS7eJWp14EuQ3qoe4WpFSijfW5S8qGu", - "marketBaseVault": "BqrTCss5juV27E7ifk526axDwnzu3QfrcXBCHTVwV4NH", - "marketQuoteVault": "6LMhwdVMo9xF9fgMNzmKFWzy2kkWzL9pHeYcxiDUN2yf", - "marketBids": "CmdB8MKVk38FVoRQNcmb57AGrrm4bK6gRA7M1CGazW3f", - "marketAsks": "4JHXZhHSZfpED1c7kcweN4L1r25kG3r4AB62iuFWwqEA", - "marketEventQueue": "3D8yXWdi8Eo7dTp75unD4dPM61nxY7B8k4GmsbaCAtX7" - }, - { - "id": "F4yFzL4y1xEngJpJkBtHnja4ZVjggNdzkZMBKBG2z8Qx", - "baseMint": "DCg5GuAyxRwtM2VcSAJbgHesi1XqSqV1FAtV6T3VatcR", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EQrm9jtCgZaXuDBSRymu3kCJ6b5c516S48hG3QVkLK5M", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9xvFcJNb5X5MnesSkyjHGfMmoMzT8GaBGw53ScvxQgvh", - "targetOrders": "69sw4o3nhQu3Y7RqgTgpTbtXz3FsrHRMZHNS3NJXuQN6", - "baseVault": "54NeTECZzPv4J9YXuf6Eukr3S2qJy6EqhMcxqiWrCFo9", - "quoteVault": "21Xk3md4PPN4JqQWGEvWkz2TFdkKfSMCK7d89svnqtnZ", - "withdrawQueue": "GGU62dJDese8vPbCELWkbURyYfy9yU6uMcxp3G3vr1HS", - "lpVault": "6GArrg9N4KUZGmVtQMKcKAkbM9vNvhFmjuYAcjrzkCQa", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2Xub9sfVaW7n1KRbVDhcLwc82kiELeYZZuf1ZVsnUg3h", - "marketAuthority": "YcdWDPMhTs9tRHeQY2RhehkShrko2JiAgnZPqy3E8W2", - "marketBaseVault": "EShoF4jUCHZX5q7mmaKBXoAYwcEMcQwy4kEWfZUXKmZ4", - "marketQuoteVault": "FpturQeLycRqUvfhbv8wavdnr1EKZWLviXWxfhm6GymU", - "marketBids": "XKgGLStEvr5hJGbuv1re7u2mwvCZdU5KMMkygJazU23", - "marketAsks": "Eh32a7YdoSBuQMfXASbuAAYFBxKDCU1fFYeky9KfoNsY", - "marketEventQueue": "9jnM7ewuvisTDW8iHzBZAvHYmeETok8VbJMtzo27LAHT" - }, - { - "id": "F5LysSy6PKS3uq1ds7mFVgF92Fz4j2APYXBX5NEQbLho", - "baseMint": "FbYPNQTXWYpXKmPoQMVGUUQAiCKwyeLR9wSNsiYQ7pBG", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DAsRhdNzjAxsXQtJSCh8oA1PeJEbk1Vu5ESwVWuTVYew", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5zpBTTm7Lsh9L5ouUFBjKrwEhxv1LkKZSUgghVyNosKV", - "targetOrders": "BJdW6n8P7rTwGP1Sd6jHRKWKGoAALuJyRJsdTuKfdatd", - "baseVault": "FuRAJU4vNonTG3uvzKGEMFDDTdwcfhyho35bLYyPu63j", - "quoteVault": "4rHtVNe45n7aQ465cd9bRwgmFxLnDUtuTEN3Hht5uiG7", - "withdrawQueue": "4oSD7PQvGbJBd6YPJkmQmnKHZqxWeKG3Lr7aAX52avvc", - "lpVault": "8gtqG81u2EWh1HnEZmdhm2CnXS4TQnPJCrks8pBzFE9i", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2F5jFAG1adSvhwEG1YMb5GTsSpE3oU4Y13qbsnCjYtR6", - "marketAuthority": "6x71dvjRPbGe3kaBGGoRRHwE818n6jkhzBDefJCxa3nc", - "marketBaseVault": "FEiCaCUP6zVZatCXxmrPXV6db2c1dJBtSaqgpRpHCXRp", - "marketQuoteVault": "5oiFTa7GUDuJxpLM8fhaewXhCZs4FPbxMesLqD93vXNQ", - "marketBids": "Hwh6aEhTA69EmPtaF4vY3zdBtHfxSc1prb1gmAg4zCzw", - "marketAsks": "54UBctNRzDcijZm4BvwRZE6PQix54FSScS5uLYW5xCkj", - "marketEventQueue": "JCr6jpmNUrBQ6dKRyrUVyvTgw19gQPPyRjzbNbs5LDvs" - }, - { - "id": "F7ghMK5aSS8QDBjCnD4UtbwQEkwchNRDrGMESrDWZoZf", - "baseMint": "PRT88RkA4Kg5z7pKnezeNH4mafTvtQdfFgpQTGRjz44", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HRBaRcfN6djeV9sCeFc1C8iGDcZ9QM1A6cCUPLXt3ent", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FqkiYzJyT2B6M8uZJaQMfc7HfETsZw1LD1yaY4JEwEnX", - "targetOrders": "La6BF2W8vW5jdfQ7De1APoqCtNhBKYCsFV9xrD6EoA5", - "baseVault": "EZnhuufBtzWoV5S5P1QhLGajB6JeCFYpBpeBn8PmXjog", - "quoteVault": "2U4RQq9BP3Mo8vhG7feow1gsexhFD4jq2jPQcWHGSy6f", - "withdrawQueue": "88Rq8jNSsLbWcx2Ga9faen6D1KaEvawPxhKYtjWSXQ7a", - "lpVault": "w5kfkgBVnHG1MA2985has8RBbkXLatDgA9wE3q5StUq", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HjcBZcqCDP1dQk5TLwmMoXH7xhVo29GkaSmP5qiuCSqB", - "marketAuthority": "a94pYaxAtQ7q7pYgXfNgkyS6Fj94QBJpraY8MjyvbNq", - "marketBaseVault": "3a865gAUx9KAwcfSdqNHBqJs2w7b2GzR7yZrWHmE5b1m", - "marketQuoteVault": "G5EvFamQksAGknJkmQbLc3n5vLNrpQvksFzwfpmgKi24", - "marketBids": "8SL3GkUfyZDXHBVMjoQQbzNPMKVHr9yb6SpFDthp5ox6", - "marketAsks": "HEnK2aK8R2nnrdJyvgrhK7oUgzvDkvhMGUmRcPAwrXeC", - "marketEventQueue": "3QnaZhkgWBTyiEyChfMjtmpi8R4T1gnfLgsK6KwNsp18" - }, - { - "id": "FBFiVRcoKH8YM9pD6QvyaigrZEMkxKUT1j6VVWDKW7xj", - "baseMint": "DfgYfvfW8cWumofEgRZsAYHhZVDgQbu9z8sGwcKahSho", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "4rPk8ioSwZEKQnjmvKmdCRVXik4RQWy3zzdk8PW5MHWs", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6cWLzANWX66Wvb8WvsmRoeFefafAEUYKd2YagiFXx8jD", - "targetOrders": "Bcqc3c6h8pVvPnHsjg2qjhZxN39kQGzjY6e9zLWMQhTs", - "baseVault": "CMTPCGMobbX2Mo3YKYkU1Zs9DA96zuXBcL6UsR19kq6a", - "quoteVault": "hvWnSujb4fC4NT6EzAmGt1vJPp4wBDpNmztnJ4GUyrJ", - "withdrawQueue": "2jbPZ8iQfc8sFVxvdoV8vP2M9rJ14hLwZ8TJKzfJEvN2", - "lpVault": "3YyEVxmRLMS3RGFCPJMV4hqQmUNQLQwKQWCtxHzojdvf", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "F3uaxWvcPWaQZi2ZuccmHywTtbo1FzvyaYNwbed8bHzv", - "marketAuthority": "Enyqf7CeR1xdQqjeZksEfacXq9kUJyxXig3fjbngMDnc", - "marketBaseVault": "H55EqZKaqJk4TjXrv5hipp7jKpwT4HAnj5wViYawDsbH", - "marketQuoteVault": "9VJjUFvBo3JU25cwjDHERSjm4X4UzATUUxndEaA3vqMn", - "marketBids": "DrZoNbe9jy7GNNcJk29a6ixnhP4T7B1WFPeK3PRneGio", - "marketAsks": "CpnH7fFu4FeSn1hnAcDMEBWt9GTuBLG5ttqy94azBF8m", - "marketEventQueue": "CUTBHjThmxtgeycCEF6pYmDbiyNF8obKp5jCdNUar3eo" - }, - { - "id": "FBsZM3fWdNen1zmvxyXhZZuEAArjxErUe1ySYbJK6BgY", - "baseMint": "GKNr1Gwf7AMvEMEyMzBoEALVBvCpKJue9Lzn9HfrYYhg", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3qJXEQHxX6X7UnrBpULxCFbeUPKBfj3ovVjgH8P4JoS1", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2PC3hturuK8SmF4pHc4KHNcAki7ZZsiVVdmqZX4Z1iDo", - "targetOrders": "EVpqpU5E3Qu2Dn1c9acgZS2smfzoJhp32tbMRdbxRB4L", - "baseVault": "DijHcCCJLZ8pT358qfBsMS2Q5SCmgWyKN1BnrmHCAj1U", - "quoteVault": "43h4SCwh5c31rvPszi36ke1r6teewQbbeUBBHUh28CWr", - "withdrawQueue": "3utWPfpPCrSuccvqJdBojyQDEBVx29NE1kwnsEqjgvh9", - "lpVault": "HLcbsCbPfNqoo9CpztGcBMWgo6eWze4HNRx5t459h9oz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9Ys2MEFJ8nHMu1VtVmUJnEvrVF4KsKbMZ8nqn3cmCYZ9", - "marketAuthority": "5T9WYnJcPvFBBw1vAcyCDrEyyNh2KrKUkh3nwuuhSp64", - "marketBaseVault": "5fNkwa63vtqbsUZD3YYK68yakNXHrmnmyHQ5egjVjNWf", - "marketQuoteVault": "ELuJ5U9dbTQY9pusT6pmWkPq5WQdqmoYaoS5TSYCYYUu", - "marketBids": "C1eiAg1XAzPvt8WUscweetorxAgYVFz9emxKygRbAUqH", - "marketAsks": "5G5CHkvHDc2hK1CN5iYpvqk9KXouBBJhaUgoHHMvE2d4", - "marketEventQueue": "3gBLgz8kDxMvm38uhaC7aTrw9BTjLa9PQoN8UWbXD8af" - }, - { - "id": "FbVZaiCpzC8WFKzpykRKk61JeJBnjoGuWDjwC4WaCMz7", - "baseMint": "FciGvHj9FjgSGgCBF1b9HY814FM9D28NijDd5SJrKvPo", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6CAR4m2gKLVzbDrSAKD4yQNxKfgzG4v7H1m356ky6u8D", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4M4nFs9c4AKuwjovCuJQESyZiNcCwzKwwf5xWhzBn5Bg", - "targetOrders": "87E8xLHZrPSdGebnHCiQSM3zTYR8G2MT17ZtQNZgmJ18", - "baseVault": "C9CtDeT5hp5ZzxGnUaqtwTMX45quoq28xDGJAmdiQYdw", - "quoteVault": "83fXXYsYDExAsaFRMf1bApS9NEvEyZpkwB96HNFQpWA5", - "withdrawQueue": "FLg71LBeQLr1Z7dfN2CqyXUVRQJVVU52Nv2ueU2cT1pY", - "lpVault": "4oDcp4x6xNWQP2NJoeSiVY3rjpMysEXeWzPx4L3bPF4F", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BgJZvSBcNyjxz7xk9thxZMBvXywpvcjrTyFjRoH9tbnG", - "marketAuthority": "GYXdgjC4nuxGfr3PXJ9b1jeTSNPttSSMwurNL2qDZvHg", - "marketBaseVault": "2WLEeEJa2Ss2XBGsRyeiZvpmEuxwNHhpX6rkRTR1AwHZ", - "marketQuoteVault": "E6wUukbBzH4A18TfNPKy6SWdGmoAem2c2GaTptwNRLqu", - "marketBids": "EjX1NmmCiN1zyKxD8uADs7NhnZN5Sgr2Dq4ActagXetb", - "marketAsks": "5wj6dEiZDyDLMZMtjbRkc4jEmnq6oM2LHKzGcAYXoFbZ", - "marketEventQueue": "4cBJCmpLxwonR82ESgjEkuY4RkHoNvCBe22Q86UezxCx" - }, - { - "id": "FDimiHrJfZ7UDjd8tNTMJc9W3efKpY1Lg6FyT5yFjMUo", - "baseMint": "4J4XAtCWWVrb4FBM4JySPWX3YWix2bTpZNtAAHH4UEba", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8JkXKajkNqoW5ibZfKv7QyD97wVdgprxZZ9v4yGG9oCF", - "baseDecimals": 3, - "quoteDecimals": 6, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3xGTYbZG5WhT7eUeyYLY93JKCeue9Z4UT32azoKbjK2C", - "targetOrders": "HGnPTfRHT6mG88WZhCySkNuMmDnFsd896gRXbjATkqTN", - "baseVault": "4SXdNQYAKCjeqRBfJJLhBj9wgiYQnDoegpaV4CVGJe2w", - "quoteVault": "3YehvXP2ybRdh2RvYyfqao22rGb6CKmCbizh6wc78dA1", - "withdrawQueue": "H1AR5mHvCGx3ZL4cdixbv8mzqyA1t6nKDYCwTDF9BFCh", - "lpVault": "GCS11ypzn8Lpd3P8w8wXR3ANconLgjczmcBEychKsXG6", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3YuMCBuj1qgcLVUWNFBh9ycMPFz41WyTxi9yYWTNpGVY", - "marketAuthority": "2Ejxjkjvuc7woHZwXiGpnDS1QCDym3yxbReuPXYLCkBT", - "marketBaseVault": "F97SMSGSCPMWcQnqKEP64JMRGwbQhiGFCbfPFDjGLqZi", - "marketQuoteVault": "4oYVHFiQsSCRPfGiHQicyaNPg9bXm6v9j5WXdQRA5jNo", - "marketBids": "8FqFxVQYY36dvHnZ8zbDcr6jZZAN6jnTvXHqvgP6m8TX", - "marketAsks": "831P19CrXYGrKumPvoBBz4U5sAtbjTEkDoEATYbExMPQ", - "marketEventQueue": "AcKCVx9VFLMbxRkVteXnXP7Y3NBMYzwr43UW6AnCPB1b" - }, - { - "id": "FdU3yyybuLWcNo3pLA16EzAMBw4qVCTtBjPKfxqJ6JJ6", - "baseMint": "EDSqdNvABrJkRPsDFGHg1yrcnt864bPKb325KwpyUTHw", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BU2BLi1WNpmm53Ca6Br9xhVs2QdKJHMbjR1Kqkcuvk77", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6XrQi3GRTveP3tbYHtKZR4ET29t6aApBE7zrQKonSRik", - "targetOrders": "82FHPcK1cnco8WR6ZUcn5SZzFCBiwCr7HmoaDhvqBE1Q", - "baseVault": "DXQk6Ezpmy7nYAQ6171K2WCnQGF865i3wj5Sfo4kARka", - "quoteVault": "AmzPegAx1Z8FyZdUskdYY5DTqPLtTAtXzjU7Zcq7o5An", - "withdrawQueue": "FGG8Aff7FMa6vGPqbnezthp5z7DXQwb9kUKEYoCYeZmy", - "lpVault": "JCkMkf3B1AQFwfJc1bDXrENxLiUyr4VfmcSe4WZ7XbdZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3XNyb2ZaWxzFqC3mkMoQjRhpd8PewrC9sgYQRg3i4GwA", - "marketAuthority": "7ebmkPH7aV4uEsnkAjFgUggqij1fbA6LLCRxrfB5rsW9", - "marketBaseVault": "7ikCLbgeVDzZKe3rGyyuSoA98Amqi2wMkvp7D2dq3C7c", - "marketQuoteVault": "XbaXLt1B41nFEAMh5egh59mw1Fkhrf6bDetF5n2x774", - "marketBids": "FkYa7tpigLrWkKuoCEAdTdXfQ4Hon3fRJepr6HAby9Gc", - "marketAsks": "89sWGxTRDtg44vao4P5MZnckGtSQCepFUQgpWy5QAWWt", - "marketEventQueue": "DeHcUBFNwpLMJ8FL7W5LnRD7WfS5YA4awtudsQbQCPN9" - }, - { - "id": "FdVZmm4GpK4UKD9TbXXJkEhTvo9MuHjT8FV5N9X9qR7k", - "baseMint": "FkBRohZpqx2c7zxe5cDhNq3AoFo2nPJus3xtdz9CvQmQ", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "7QoTgVJe3yvbW48GrgGdgbV93A3rLEPZK6WzNFP7tXgm", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "V7scvNJmzRLy8drgxPayBpZgJ1kyN9NJbBAVyM63hmy", - "targetOrders": "G7boQaYY3wduasqxYSJYUPN7zEY2Kkktw2YhPgEJ51wH", - "baseVault": "2pnGkXVRRoereaqwnoiyPgtGaGN7XejSxojAmw4xRVie", - "quoteVault": "Hb2jmUMFVkpxUJpSZJJaxrb1A49T6PxVGw7Uumwmhk8z", - "withdrawQueue": "6C3f1SrcDXW6r8wwiiphxUuh1nzpsZvMRDooDoSsGui1", - "lpVault": "BhNQCMRWPJHnafPcDaeyKrefVxiNLHK5HUtM3M1pu2u", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2dG5K7BwrZDPZaJfwrWtYt6HfHMUPLpkr4QUWeGX5NSE", - "marketAuthority": "5J4vRcAPr7qoneXiWUT27WUftnuYz45nJvVNWrWhnNkK", - "marketBaseVault": "DL5GfznMxMUVo4q5fV1N1pbMSjmLe4ex3VakuT2LdHDR", - "marketQuoteVault": "CqaNUxNs5PJL9ZLNyXs58nXKMdXygT8ZsqdT4oM5Wtkz", - "marketBids": "6khgzimgpiGKXuHbjsLBgUQnKthiFtHxz8ayHdids2BJ", - "marketAsks": "BL2CsEfQAxZQt75qyhqkJDoDuuo7ygiB8xD9yCvP1bSh", - "marketEventQueue": "EDmgxaufbqMKVSWtNoWsEmZ7HbcSRug4SMDnXDv4KXBp" - }, - { - "id": "FE1zSn2MgHjF1kpiocXPKzT5swcyto5sP9XB9z5SyhpC", - "baseMint": "9suNiac1u9EKsEnDqdVjTDFu2YFY4NMnhJ1ZZAtUcCJa", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8WfBis5fBhuKsz2rxfiMAndMJMpSPU9NzeLiXifFJwda", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3DzYPd4325q5vNj7EGPvTi6wrdNBipyr1Qe2HpUqTZzh", - "targetOrders": "B6TRjPtfKRGu5KFMkdZ7PYqdQRYyKGXEAJxyh3H5LKxK", - "baseVault": "8eCPb9RKHNqokDj6uDpqnpeDrQSJCz52UF51ySBMzWZN", - "quoteVault": "Fni7mwMdPwFesgMEannKaqXWhqenGF4xprUhUWuhjJrv", - "withdrawQueue": "94MAvABtb74zVnT9jBDXB57R5kDUNQUjUsfFSidyzAVW", - "lpVault": "GGBK38qdoxEaqDFi9B3bP4iAe2tkoa32THRbTN9PCSaw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9GdkdDv7xm61uhbNpJEgQbp4iqFxV4GBsxhHbSUU5oCJ", - "marketAuthority": "DFNmB6bJeJAhsD7V5fpGtKWJptyrXZ3i7tGRGta6yoZ6", - "marketBaseVault": "Hj2V2r3JRX6kV47DinQAHGSZsAPGXzfojgTXLufAysfu", - "marketQuoteVault": "GQiUaeCo97vVJVkAvjtniGEVNZJV55qADeMNn6DzDscD", - "marketBids": "DDA9E3LeGd1fxD9cEN7s6r4ztAGbu2VP3LJcyLVf9TTo", - "marketAsks": "HNRGE7VHuhT571bqNG9nt3YwYS7E9s2M97qYFk5GJg5q", - "marketEventQueue": "JABhmjwGYqsg78FoxuHbWRCDGndGWG67SFAAQGWLp5mL" - }, - { - "id": "FfdwbjVg3kxcqUogusxBVznRwJDK8BwtbRHnijjd2t63", - "baseMint": "GkSPaHdY2raetuYzsJYacHtrAtQUfWt64bpd1VzxJgSD", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "38rRmFvmxF3z4wvuBCxkZfGmAZHyNEusMfkKKCCbZzLu", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DGkz1EqEe4gzc8jZ9VGxeYwFBAXCPGSCjaMTB4M1Nq4n", - "targetOrders": "5tL4VUEXCeFVS4P5mAuPyaEN6d5QRnjCM6dNQMBAEDjS", - "baseVault": "EkTTPpwVeuRoqRmiw2YMigLQH5Uux3hdK4EvaB1a1UYo", - "quoteVault": "GMMweEnab2nf4Vw6sr7aKeajwM9DcgDdMHvMnaY4pqf3", - "withdrawQueue": "FbEVFmiuLA3PXcu7mUGcAb5gqp56Qv5xCLMp16teq3Rc", - "lpVault": "784hj7cACjapk9aWwXnLXaEgzo3EKHQMF2ADc7AoeJQn", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9YXVzyXDkPt2aby5itYuuyd8A91424sdjQyDX666X2C4", - "marketAuthority": "ECUM7wNEgPRFoA9wfWoscVtzhTJLjPXTAwwR5jZE2aUz", - "marketBaseVault": "9Mf37V8S73hYQd9UTrxVYe1RoSVqYudgitf3Mv6gBiXv", - "marketQuoteVault": "4SiGhV3wVK6tnrTDwtQMU8rgu8q8U6KsP1y8RFbDvecc", - "marketBids": "81kXq6sh3Udwo5bqmuZRU4BLQKS8ckCptmCVPsLC23jP", - "marketAsks": "2muf45FQG4TgAaixGFnAikmphnLR96vAWaa9bfeSTrdP", - "marketEventQueue": "DSBDcaLzT8nKLyqJsT8YSH8EHk1WEwdg7GqE3wwQZvyK" - }, - { - "id": "FFEzEMf1zjB3eTEJSmKdCVyxv1dPMRbtKv23LsPYSkSa", - "baseMint": "CQkTVkohEmyydNPNPH82c6aNPeXE72AatrhZcbntiAfg", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AaYF1iZBoN2J5PFM7mG2jmu8r76TdrDLvcdSVh1U6xy2", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GsfD7tgfkJfrVy8d42D2pYN9j1T3a1JxyokZV8GfmhQL", - "targetOrders": "5uo2jySjif39LjX2djzdMWjLssfZ17Gqn9EeH8ZccohZ", - "baseVault": "4bfbMaUppWGXS9XDn2aU2s1dUmRJuwhNCmTxwDk5gBfr", - "quoteVault": "EVLTvLidrn4YcC7xPe6bzoE3tdSPsAjZqRJJ6fTmfLZY", - "withdrawQueue": "FM37Qrw8n6mJajRs7iZ8AXEA7x95tWqoGb3Nk4rM3erL", - "lpVault": "HABR3ntt2Cc4nUDXcfm3ZqxgCdq8zLuPXC64xcCSMor3", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8Kw7mLsaaMHqz19AKcANov3SismfrvmduZfGQeRj1XjB", - "marketAuthority": "5mdwV4bp9edy2hQCyDjJYwvACA4QHmu9u93CKpDAe5L8", - "marketBaseVault": "E1gFNS6hRaRHcN3C4DdTZsDiBc6wkPV778kLobFREMfo", - "marketQuoteVault": "D4zKCkEqmW1HpeAsAbWSHF1NH6vCX6AG3WDgQQRpRhNE", - "marketBids": "5BNebnig5Eobz8WETZB5Fy7WyhNryVCufYtzFJ69Yy65", - "marketAsks": "DkR1Zb5iVx9DVkqZ1RdqAZHJ8r8yR3QKfSYUSGkJfJPi", - "marketEventQueue": "BQxUr5Bo8eWRv4Mv5mJ9vEeo1sQbU1pVrK79ahU2aVRK" - }, - { - "id": "FFLKq2uenREMQ9zeARixwXJDvP86mhFESRwhr8E2RZLq", - "baseMint": "fujiCeCeP9AFDVCv27P5JRcKLoH7wfs2C9xmDECs24m", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "CugVqB1qaCtQ9ZNbRM153azxHtU9ueYyxWWQ3uG2NnP7", - "baseDecimals": 3, - "quoteDecimals": 9, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DQQWw57eMN847emv69rRaydoEFjsRsSodrdYnE6CQzwK", - "targetOrders": "5U2qwPKaKuAAdoCdWzWG6EEyUU2thYdX5iSL4Ytx2duw", - "baseVault": "bJt9vfmrQJ5TMTj6jrNCfDXQJTHYff1aj14rBaiRmtH", - "quoteVault": "53hPv5zJ5CUNjxyF9Sz4wfg2Z3Yu12gjavqFw7PXBd5", - "withdrawQueue": "HQ4J6pqeY3ir3FYBrkby1WU8TBnzrpB12c3mtzL1PNv2", - "lpVault": "B6pksKkek7HkJKTgxv5cTyTbSNZi1MPXzVNm968dhFrS", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9qhuXHS7r5k2WKpbUsTQmEFo4Q38yjii12mxm31F1Hmh", - "marketAuthority": "CeFfgtwMbkaTwvcLi7XUqnab6cUADG8onMsNMJeDinPL", - "marketBaseVault": "3oh613NbV8EVAhxArdcAf5qfTbHh2BxGMXEWQ7eekKXr", - "marketQuoteVault": "DVJ6CZqcjc3BdvZa7JmXrnPdHuBKcLVynvXck115MaTA", - "marketBids": "5cKtp3WavXoAtB1HLD8Godv7c48PEFidA7JrHacJCgx1", - "marketAsks": "3r8QSN2tX4jgWZVs3XiWWVJG3dZmACXHp3r8v6tGCxw3", - "marketEventQueue": "47Qqhj3YTdc6ntsbgCY9fZhkygeZezEBsaQc9dBNRY5p" - }, - { - "id": "FfQvPJXGfzArLqhcbjRTkkfYG3xoubH5c8iDfm7g5Jy", - "baseMint": "6Y7LbYB3tfGBG6CSkyssoxdtHb77AEMTRVXe8JUJRwZ7", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BVctoQkpesBMWggrzoqrJh9V4iBa7qMaPczSXZ2yuFjG", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DdRa2wJstcyssdt1XUd7ZeNuw2pHAv1rgUCFZ3m9gYAD", - "targetOrders": "7sKUA16BFD4sQ4oLk2n17DqFEqbhkR9tTi8pGR5MwJfx", - "baseVault": "2WsvFcxGcWzy3uv2DGRPpZdd3oSRSRs7nE98YCosVQNM", - "quoteVault": "DHtHwks2DzTx6Z4tZCA3K6MexL9ht22sRCYtEA6QZjDF", - "withdrawQueue": "5CZX81oSrQXTa6oChyZ168VQGgH4Udd2x2nnwKHViAm3", - "lpVault": "EyjvffRJkFXUpbbSZK9KxBJJFE6kjHoPVoc5poci3zbj", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AC11orBo1k5PFPyhjTj9o4KjcwD9b95hauSRtExy8eKv", - "marketAuthority": "6xsTZ48NQjdJjhrvZH74hSnSE56wNcrcCAVEniR7Zpvs", - "marketBaseVault": "41eFYs9Wx1mfxdFKY4Kb9izP2of2PTAqaMBSqUywM3hJ", - "marketQuoteVault": "FgtSsHeQPF7YxZaUt5cN7LmtT2NHywMsZGvd8EB5FQA7", - "marketBids": "ajV4EKfQNNAudZRNdP3UgPMK5apJ7gjQZ4oJuTS7tQh", - "marketAsks": "Feuow7F4QF7yHGrE21LLs9JxX2wigwjgjV8c6zfWmWAL", - "marketEventQueue": "AwzfEKPg7tD5jBbDznW7CupA811asm5NCcpffTK7ibU8" - }, - { - "id": "Ffuh1XW4buMaVsN242iwiZv59JZgZh3dVXk3gpdDBAuo", - "baseMint": "Hxk1ns5V8Lq41wzLjvq8pvNEhGh3FcCTWbawbj5SL4jj", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "2UEKrL8sSWVt63eG94PuxPBs28fXfAibzRK1aDgKuohC", - "baseDecimals": 0, - "quoteDecimals": 9, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BXgQECiEtRWL2WuXNGCT9o1JjkCVscB5bhoGk78pmbBg", - "targetOrders": "A1dSbB5t7dGWsXQz3XkEX4Qkb37ZBk9H8oSRZkYUroq4", - "baseVault": "EdoW6PD9RYFa5Tnn62j6WBhmpaWTnv7nJBYRYtdoBtUA", - "quoteVault": "AiG8Ki9ZHkK93n6jdQMn6WQt8VFjvFdqtqtt19jBTprq", - "withdrawQueue": "23tAbJGp5CFVoxk5F4yJoPxSKJN9bWomKzomwmSHoUVQ", - "lpVault": "GUYWteqRBwoSoTzgh5h7hg4v82vdUC4CgGbVPNWAfDXG", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DoWPN8sLmN7cxMktyBapP9RFpCqaqD36DeS8jqwTVkT8", - "marketAuthority": "Ag1ukhe43PMMdPG53jm4Btrri8e11g5DR3Nz6AtRNgUo", - "marketBaseVault": "H66f45NJCtFt3oU4sgGD2HkqxUETkmY4fqTHPMPerVLa", - "marketQuoteVault": "CnjKY8CAJ1oKEe5fCLYPiC7M31pkhbCJm4SyTiKSDwzN", - "marketBids": "8TZLgrJXFwv5JKWAEjWccAEZkgPYkSCAU7zL6VkruPcq", - "marketAsks": "CufZ55eiTThWE7WhwFK3i3RP2j7oYms5jCGTtVgabbmm", - "marketEventQueue": "87zpEbpjMtG13dFv9M4ZZjCqau3X2aK11y57Y4SzFDpb" - }, - { - "id": "FFVSa2RM64G4rMrPM7bBvFCUyWfp9AHbPGgYfNWUA6sA", - "baseMint": "DXcnify4NrvTkauco6cciRfimqA3af4G8SJiiZKbUiFT", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "G4aZSBBkVHpU8kyemvGDGjgAjv9V3yQ7vPrLHzLw5Z1H", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8NaYWd3iPuba6xXfqw1uvdXFSVMYD2GwUg1CDTd3Km7G", - "targetOrders": "GFEaDQM2wLEmWuhSZLomNgttMvByaTFg1iN6rpU6Vhf", - "baseVault": "USTZ8tdQWwQX15dQHoYBFQE2FHX24rwmPy3rzehi43U", - "quoteVault": "KA64hpKUYMHc2miCXBGGithDWeacuxN1tZvih3uZT56", - "withdrawQueue": "Fc97DZmmued4WNmCUsbsidinMASr7hC39sjHmSnYgoMu", - "lpVault": "F2wofjhWJ5zbf9hq2LQqfvj6xVjvB59ydZncxW1up8m", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "MDycvKzFtcGiNXGSzr4uY6jaCMjBjHCYG13ud3aGMZA", - "marketAuthority": "4dqM6DzpFGC5tXypY3txjYJgkZXDXBbm5CESidJoHgZh", - "marketBaseVault": "DDunaz9z1AsEMRL8mGunMEUVMPFpphDMRETkerJngCnr", - "marketQuoteVault": "44vUqJH1vSerC2s7CFvFogyesQiuaow29xKM1rZ6PVQG", - "marketBids": "GDdP4MyMuLY165KydpnikNpRmXk6WmHybEAp7kTnWScd", - "marketAsks": "DkCrNo1xPrapYuy4opjvfU4RRfCTfRPyyezZvnFqSK1q", - "marketEventQueue": "A577uvSiw3i5pqE6L9vvnnDK1LeqnsY5HbS2voX5m19r" - }, - { - "id": "FgNJEwkHdPRknaKRWVQxNR5gPhPd3pWWigNtw2LyQi7e", - "baseMint": "CJ2K2J3HYU6ibR1JwLkUmD9RM8eytfxtMcLzYPqoQQKo", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7pYsUj2iG2Ydg3EreWfszrTAZRHBBs5LkrdYErGPDKX6", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DKSz46JXpuMkRYZt6eAzE76DpzT1xoFHm23tPznuZHHj", - "targetOrders": "8Fh3nKuRpaerXNKsuoUCPfGPBraJ3LK9Ywx3gsXAPTUS", - "baseVault": "33oFQwJ1mYtcKXYSjcRULivMuCtTAMP4X45vY8pRZYm3", - "quoteVault": "Ds14REeYipj9fNfyUTtALh41a2zLa6TrKCEgQ9qPxRWy", - "withdrawQueue": "CBHM8sG43nchzeEJt29bP7XScrpHoX46TY4BbK9wQVm9", - "lpVault": "5V45uJgKSRkPKUN7Mvg2vNtywrsFQRQ1dT6S841i3wT6", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EN1VhM7BmuqAuUDGDDnzXZdefaFpvNHFCAwjXzp6gRhJ", - "marketAuthority": "8yNA9b4h48q9DugncoNQHeeGdQSSzFRTvq2thKer8LNX", - "marketBaseVault": "77jntrDdi9mEy2uaaA8VPCG6koMkWZCZtfpvivjkG7vL", - "marketQuoteVault": "Da9AKTaNAK1mh7DLH6a7YCb6Ci7MJr3humpUe9GGCiFk", - "marketBids": "5n2Ea1AxmomLm7aX5HS8gA15JAzi57qTWbs1e7p86s8u", - "marketAsks": "55Yd35nbLrTScg6WomySHjpNcSHAh69LTMsRTFovhzan", - "marketEventQueue": "NLPSimJJm5jTRVBb86UgjY4d8sZ6NMg1NT87HpSRGBi" - }, - { - "id": "FHBvrdtb5MwrswptRwuUNXPZ4xnWiwLgSUmFg958Z5A2", - "baseMint": "64Hw4Hm4WLC1Ty6p8g5vLZNCS37msb9Qq8ZFJE6UConN", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4zBVabENJQ5tZaNQXrhCrUYsdJfyRoyjMes4pPkXjjKc", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5LmGLd5RVXeHhgy1dkeeUAQJNxcpnMHFmgUsJWkfkXyA", - "targetOrders": "6haHYkzgUeZxALH4xWDD6gcun3cDCHrLs1oLabUMm93T", - "baseVault": "2gN4FWYddqbmPV6uAc7BwiVHN57ox1MGgY4yk1aEs3kS", - "quoteVault": "C58fCuLnatMs4U92vrypwkK4Hz97PHYjrGHLYtfTfBbc", - "withdrawQueue": "D5xv3b1C5rkXRqAzSJf6Pb9yvdiC5k4MtDbhwYB2ZjT8", - "lpVault": "ESgq3C7ApsAHnwm4zevyRjZfJDa9SunbkJYDMGHD2GLZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8Rv65QMCjmvE1J9zFexp3HrmkPwkVrW77njzvqZGQ95z", - "marketAuthority": "5A7kEp919FrzPS1BM1svAiSX2WXeYtcsPj49mN1am6Qg", - "marketBaseVault": "ARdSp3RHtcRmWQpbxtfdG2idi9mgaSeGfdcg5MoNQFhg", - "marketQuoteVault": "2hUw9WBcnWxwJcWaoPU1S2hBL1nbT3uN6GN5ZZY2Ayed", - "marketBids": "37oqVNtQvQRDTYubHh8BcESTdrwyGnRc6sKtF5tpuvU7", - "marketAsks": "7Y6rKtJDFg58AJNepiJaPyJZ4Mh4J8Lvt1UM9Nqoh19Y", - "marketEventQueue": "EmqWGmTfZh5r5Fe9LzmFDKeiyTPVJiMGfTa4v8yaZbYC" - }, - { - "id": "FHGMtwrGpwRxHQCuowP4iRmVvtvZzPCnXPqfSfGQBGqo", - "baseMint": "8BLiujyxu5gJajWBXoZQkwSsamdeHNKWQbu1ApAao8Ps", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "dx4u7k4AbZHGrN2p2ggHvUKdydYpfms3R9XeUmjW1CJ", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Bd4ER8JDUYgLURdY23nvRsEx1JUZ6pBSZrpYVAdV2ML", - "targetOrders": "DsLXt1jXEgBMWJSKoFkvGk2CAa4pT1fLiKEppsBVmVNn", - "baseVault": "9HmoadjAo28JKMpnwuZBu8MAns4jrVviFhyCQULDEB9E", - "quoteVault": "CdKrX1NQywqNB4bWF1r4hqCwzSoH73K2eqmqHKbaMVi9", - "withdrawQueue": "EKpUdQg7BCaTYXuotH4zZGrKrX1nrPE4kHu4xF6DXDsC", - "lpVault": "UcYYSjDRo7uDirg6F7eJvNJdCxYmAVQKLKd14gH3Qpf", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FigeTPjS352wNWoxdPyyDGmbGydCDf2igq4meLYP7mX", - "marketAuthority": "9FCm1C425jQUY9e6dtc4wMaCyZAieGhhfdsJKXNvKVwX", - "marketBaseVault": "A4sMu2koPVLHsqnGTLM8KVCqLCPnNapDiQGcawQGu9Mc", - "marketQuoteVault": "DsJsQLE2k3NYmad1QEgURUPVoAK5vA7CoTbELGQSAzek", - "marketBids": "3FaVsnLTFNjYBeYSKVBTiVMJc6GPHXqifyDntmnD4M9Z", - "marketAsks": "Ga1zJbqcs7RKrdu47NpzgxNM5P8fLpGdpDUE7yfaPwYQ", - "marketEventQueue": "5vkZR6LYhhVpzgGanxbi9BNZwrQaVGrGGsHtKod1TLuP" - }, - { - "id": "FHmtpTQLMD9ReXbVx5wYuHCdgqe4wWigKmbYDeAsmZGN", - "baseMint": "6XWfkyg5mzGtKNftSDgYjyoPyUsLRf2rafj95XSFSFrr", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7hLsN732N9GnWYnYjZW1kbmVfXCDbQkHuRgKSeZQZJGh", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2tR1DJYXAhR1y6X85m94Ki3sfUo5Ao2CPT1vTky74mdH", - "targetOrders": "2H1SV7PaFX97Saf4u4QoyNrD7Ecc4VSNXVadCt9KpUZF", - "baseVault": "8gETtwiaNFkPPemH5bz8vUCAfgV4z2Maz3f4v4XT6bdg", - "quoteVault": "4MsBSofuDY3dCThSjBasrxuzsX3VGEjgmV6C4ZeK5wJc", - "withdrawQueue": "HLK6V564VnFji8eN3XYHQbsbiWdmtk9hWikTWU7Z9Gqd", - "lpVault": "8pJJDY6BF793bdf2qLSYdxHxZ2EQdSPwMqu7UV6X4sks", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FAHa34qbNbvtEBHgjuALk4WLJMwxJTtV6Z3V3p79XLWG", - "marketAuthority": "GYPgcLvXRud8pqduS2Qi49hQThLJrJssmhKtkvAfZqjH", - "marketBaseVault": "DmoptcnfWpC9FuhpEis1EUw8TyuwQaHrSyX8pWHNn4pL", - "marketQuoteVault": "Bgpmnkeng32uYJMAdSYc41wWZuVDWCj6pKnVRodVqFd4", - "marketBids": "Gg9jCDFU2uuhSPNM26ZfHVPus97dpKLwvMwo9FXfKEVp", - "marketAsks": "5FUcysEmXr1sgiVYT2Cvaao5JjVPUGhXvFkG1AFWdtkL", - "marketEventQueue": "3yMDemEJxZBmy8fSjZjf5HhmPRquDdg8xsPeFYZBCBhd" - }, - { - "id": "FHNPNS5b1bAdz1f22zbYYLnsHqhDrUJmeZmnADWKF87u", - "baseMint": "7AAtpqK78qbc7vx6BVWQ1D4PEjoccDbU293oGh74ovzN", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2obrfxJ5zTRcZEmCnqZqFucsDVDwLgFx2ed9bpQ94Ftp", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GEdDfStZetPksAicDLk7bG3Gyogc1Y8iv7ieddPM1Z8e", - "targetOrders": "9ifbePeA5rZoFXXPkj8Zy4kxixxYF7CinTqZQAaBXYwy", - "baseVault": "FFuojcVx5MmMFZ7rMcfsSQjV5eDdnaaM346QcGr5ia3F", - "quoteVault": "YWTZg1rFHHQFMfXrwoxqHs9Pj24esWUB3vcZfrbcWWa", - "withdrawQueue": "749R3DmFQQwobkXkeFEHvJLvaKxvFetpVPNazhaHXBLw", - "lpVault": "DHqek4n5ZDZDKtkAAcoBbJ3gPrBAM3ELkEELLW9xEgMp", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "43p36twB9Kr7keUxZpUF2MNqKkryB6V4e3yrjs368bNu", - "marketAuthority": "BUFVov7DwUdzQc8uPuCcZkMf7eUzk4pe1eEUdEBjyGVk", - "marketBaseVault": "7BvW5RbPUhjJiTXzBcgYLLVPdEdKdfULF536mm9hbeUK", - "marketQuoteVault": "ChbCY38yYCnqNaNvsUXKfgXLbNMruNvcc8tAzMhR5Ay2", - "marketBids": "2H4z3hqfSUpREkU2wokQmkTVbjiBqCHtEAivQQQZKw7d", - "marketAsks": "5ZqffcWzKVDCNkXf4Pbjof3Na9pWbLD6GS29FfT7DZzR", - "marketEventQueue": "CM4fYFSxehNdUAaJWZCBewYZFCLPRzTdUG913r85pewv" - }, - { - "id": "FhSQ2Fa8EhVYkqSVZAgVbWi26vs6XyiFjMXgYD7mGYnN", - "baseMint": "Eqekt4QF8zy9X6MZn5JUa6YYAz5MMgo7ZV5ZyX7YtjJW", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2F8tuuAF5w5PngidHprD8975ZVYTeFMvMwdaLn8gKo8W", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5XmPRneJUkcnzW9CCm4Yom8F8CGPXth834wYJq2epsUQ", - "targetOrders": "CV1sjSbbVfY8eUXFTupr3fSHGbbntaKX9k8D2kS4KgMH", - "baseVault": "FNE7fVGiLQ12joBj1sF36kAhujffUeCEqWeSL7kA81gT", - "quoteVault": "6vmhwPhvnNZ8Ar53zwv68PcnPuMayugUGwkJrmZZz1kG", - "withdrawQueue": "8MQtXjXDkt1JSuyHYpQAcuSVNtE6unhd57AmzXqGrdYi", - "lpVault": "GNZyy9mTU69nR76DuDE67FDHyyLHfVoHBgkJ2uaGhmFR", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "B7xgMZ12k4qQuz1v2DuURsGfu9uN3nwwGkExx6u9a1sG", - "marketAuthority": "6Cg5WdA5ZbQ3kDDMrXHCuWQJJkLhCeyTLF3QRZ12M4N4", - "marketBaseVault": "4tLRJS7RuAuMCjHnLVFju2zYM2Hs7f9LHuGb8woBDd5z", - "marketQuoteVault": "2t9YgLMskZZ6AUJrXzMgjaS7QF15zHZxuieFGC2Mw7AQ", - "marketBids": "4ncgu6GAVKLnKZfXaGhuLggdaKeQGKTBZXEpBthPDgSi", - "marketAsks": "8sGajiU3Y32LmxnfwmRXjSe6ueTfeL7T7Cvt8okvap43", - "marketEventQueue": "HzGyn5MQ1exDbgTktS7VHAZEuTdzaiAE7ytEtpazuqzA" - }, - { - "id": "FHZU8zQJBHvJRmduH2kRhgK1WQRsjPYALFUBZ2ezToAq", - "baseMint": "NA45Qgq1xn2EcrrKik7o9rVPMSgmDXK6kv8134Q8ADW", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "s3VmuzemCFDZd8E6auTpuwtKWFnCrXz2Pxm2evPA1ei", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3iN2aMmLjuqQTzwReJLX69yNkV2kATP7Q4VEPqeii34F", - "targetOrders": "4hyqwzRPpDdDBVcStwg4M7ZFDKdTRX1RLe3nGJfHn2ik", - "baseVault": "LSbyinewJUeMFNcUwfyqgCr6kJJ1dLZgPsjQVdouPym", - "quoteVault": "DL73LRZKeLZ9hnjndi2jWfythhtNvaxMjHAa45GwiXm5", - "withdrawQueue": "TbNZampKHDimt6DLbcpSzHT1mRnnCSnvLKDCSdp4sBe", - "lpVault": "pJuuKqDhB3Km73HcTJuFkQUb8SF8jCBmDnax6aXojN7", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7ByLFpwT6XymZRBasYDZiZgdZHzFiEYjqqmAT4Hx8mGT", - "marketAuthority": "FG3jycpkeYzMbYQHLYGdCu8Br9DbWL96CfjbPemRmcpQ", - "marketBaseVault": "G8ZAY5ErTU5E7chG8anwUgBt2Wh5rm8NHaQtoVyW4cnQ", - "marketQuoteVault": "AeK6FFGv2FxZNPVjeCVPVYoyEHpowFkGueCKchePhPRp", - "marketBids": "EmMyP36z1xCb23RTJcKcKUV5eXgQQmhYKbJT2EXyQax9", - "marketAsks": "C5FGAS5S5jf329wvGGRSagJAVm3U96hEUYRAgQmSnuVZ", - "marketEventQueue": "9S2oZz9qc3Xsg1gBq2xAL9vsfNBw3bMAa8LL576mFGYS" - }, - { - "id": "FihomaA3ohWEZQZ9a2QLFHMCFrBNPbr7KSqCk5xJahXX", - "baseMint": "EjaC7vKgimdVMyaF7SkNNaY2D8PDRVfAwThuAoeVvE7V", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "ALkJSYYZmvzEWq6SxWuLyNtArwhSGz6hvhv9EpTjQcVv", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3SR8RQNJ6b5bnDgS7Roej5XbiM6fhdJDzmz64WMhWSKB", - "targetOrders": "9gL87LxzuXiZgxFWsZfwep2LnSkpkVNKy7vzrMUMpmBK", - "baseVault": "95gjHa8BYmzbxmQKzzSUy7sWEsF3Loe1yVL6mjVs3p6N", - "quoteVault": "4bvwk836TPXSvgYS7Aghh43dzZLDZ8rbCPzvtwfHpqvf", - "withdrawQueue": "J4eBjZkqeXgi6rDhpQKaNeLaUKXdSpHHZKYKNk2bgE8S", - "lpVault": "4ynVwKTZH1NE6ywfyQJWqUTeTYzcf9FwJvravdkTkjK2", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "12Fx7NaptQ4KaVefgjXp77pJxLnfPvKA6vsLhmSF6AeQ", - "marketAuthority": "2EANdqH3kTAUa6rLVgUpby2nrmi5hc1fDGdn7uCZvPXt", - "marketBaseVault": "5wAUDzufqFKVo9we3W3M7H8GvCYMCR87FTHax335F2LN", - "marketQuoteVault": "5T5dqJ6QZLuVYeCgxzTtHGkW92qjVWyjMkASu4UEJ88V", - "marketBids": "HWfPHFuwWvoVUnz87NPxRewCZ9VWWTz4pFTVvVBshFp3", - "marketAsks": "6sx6pAD2Ju3p4iWuwHUDtHLEwW8HMag4UzMchnTJxyew", - "marketEventQueue": "BLoN1eiQSLx6bcnDQzDNhW35BiEe6BF6WXSEVanBZ7nn" - }, - { - "id": "FihSmFU6J73hxcM7H8XAAEMdBN5V5UCqszEAtyYeF9Ee", - "baseMint": "SAMUmmSvrE8yqtcG94oyP1Zu2P9t8PSRSV3vewsGtPM", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "C5dhhT2vhhp83HaNcJZ7r9FUyG7LfhB1zsdBCxT9zutL", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HveQMxVRs1Zo3bcSbT63bd32cGuc3EgHjKdiHJSSMnf8", - "targetOrders": "5afrY6siKMgiPFQWtxQqL8mWnMTtU6S9qNTTeMcrGscr", - "baseVault": "EABExwUTkPhoeUcbReHJdx4UiMLhNaqdCAPAFwD1qZPk", - "quoteVault": "CXJrKKMcS1egXMPBTeL4yZY3BLqyuPUfN7HfSLhUxCDx", - "withdrawQueue": "54DjJPGYEAxRUT85pvDXQnWupGTEBF54qoFygRhyPPoR", - "lpVault": "rfmcMJssbdPBUJLRh8jkN2FnNFw2ouniSCysgYALy7e", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7PX2k66ecaUJHJweNbdCocR4kvPotvDn2FPu69svCsnu", - "marketAuthority": "DTbqjGjMs65wPsR6Ej57RJPB3tg35GaqYscrAwh46syA", - "marketBaseVault": "9u8Qscqtt3H6THyyWr53f49wRHei7zvYGYPEpxegEjCU", - "marketQuoteVault": "4f34wFbrUetDok9xYfCSwUzUwt3rYhCAnCTLL25nyyPG", - "marketBids": "6A6VqXseGRLncs1eqQixS9GULRJe69Qkdy7SRi1duzq3", - "marketAsks": "7sfhyxkiS4h3kCnH4PgokUgTpYM7dh5WPG2ptuMU23pf", - "marketEventQueue": "DLG5txugqLfYsLyQ9z3qxfYVWzskVxWLDXNGFTyTdxyq" - }, - { - "id": "FJB4xeMJ9KoZVDZb7Pf91hggwy6hLJMQFXTMKCfugwU8", - "baseMint": "Hero6s7zJXsw9hfCXLVR5stLqgCok3E7CCkpQEoLAk2g", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "rEmtKCiw6DQL8kAaGzhSryqnqNckYabPxTNXDdj2Jur", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CWRarsFYQGJ7zugC3WecfYtFhFsTJPdfoHYN66meK7GJ", - "targetOrders": "8pcrrcCXbG3ywemLht5MSqh224tYqarereJumZ1ihQoK", - "baseVault": "CuYhvtt7bYn6qFjAF79H5owskCBvhta2QE1cPGj6TE4C", - "quoteVault": "4qZe3BVLud3rntiKjzNkbsi3V52RDKjoYsUPnJCMJ3Bg", - "withdrawQueue": "4M4dDa5GPErG8DxCqTKpQLQSX6pKEm5iohV5P5gsGZqr", - "lpVault": "BPWSTxYTFoxgFkx89RrHCwYNfz15B7kc9c7CtFea1MWH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "B5ze5A1kwjj5kJDm9HsmhnhGwRHTMDKRkSKwQgSPgS5C", - "marketAuthority": "74Z4y1KqdFKVD5JGBppRGNfvsuP8FrzvZqqb5PpzpqkL", - "marketBaseVault": "FPWEK3gUncUJSHV6frG3mxqkTi1CUjq3t1NybZNCwJcs", - "marketQuoteVault": "35htKodPbCGuWm93mZpMMvwxLQv8zVr7LL9sf36TeoHX", - "marketBids": "GhxS1oLjcU1Lkba3JoTks4W2fpYn98MfkLV9hnXL7SoZ", - "marketAsks": "2myGYyhXS6quU5fteqfiD8KHbyShaw5F9fqUQuurUZ8t", - "marketEventQueue": "6SCstR8NpjtTifS4xbTaKU63sPZrNwRgfpGE8SvTmPMW" - }, - { - "id": "FJEBPhPMJtFaJz5hn4J7LJR1QtUmsxeudUE5eUNC2bSA", - "baseMint": "EqWCKXfs3x47uVosDpTRgFniThL9Y8iCztJaapxbEaVX", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "CukCoM9MNDUS4a6eZczL3wo5A1a6tA4REtxkSBbqsRDq", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HPmFY9hpbqQRWF2pBkpwYqCoFCW75ka4niEdMvDqZyU3", - "targetOrders": "4FHzQc9PcW4sYENpRcWno1RxxNokZNv4PGGMfwwwV5RX", - "baseVault": "ySfv3kjGtNvqS3KqBKkNRZuU8c2LTcyK664HomdvUMt", - "quoteVault": "48s9biW7L4ptieB4MwnFPJhwFvtZZSYzvAW6BeiK2w1N", - "withdrawQueue": "6Qebs7iFWnW26Gtr4cZj2cbpU5Ai38KMWAvcPUnJvFAy", - "lpVault": "EAKhAq4JXRbNvM7YN7u5vfb7GFYUiGDWtwbPZbx6P6J3", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "35tV8UsHH8FnSAi3YFRrgCu4K9tb883wKnAXpnihot5r", - "marketAuthority": "Huwbj5Lp9WrEbjrtmCSkr1vxzMwgRRf53MyYLdDAijWd", - "marketBaseVault": "AYL32Pwo3FMiussnJhtMwgBGEaZwEX4fKRYgLiVvvFz2", - "marketQuoteVault": "HXxEBpBizVwVPGfUwmxT26LuswR5aPkekYapzVEZ1ayu", - "marketBids": "CQid22KsYV4JBFLXy9tWmbZo2fnSen1SnpbgNGXUskQy", - "marketAsks": "4cauJaD91DkWUDDpciDDPNg7hyjZnHKhb35P3LoPnzVe", - "marketEventQueue": "7SC5s8iWiAhSRZuc2MqPtGqhfKUa25GttJkvMt9RAVCx" - }, - { - "id": "FjMVg1f2PvHuYqeZhFH7FbzSQzwJ9HXMdhpq8WDpecdo", - "baseMint": "2Kc38rfQ49DFaKHQaWbijkE7fcymUMLY5guUiUsDmFfn", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "7YpYb55sAqCmScKbqzhqmkzA9Ju5KWqKHY8RMPjrH1UE", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FVnJHhbjyaYE7SpuWpnqP9JzDHCPt1ztXkzXcDBP9uaF", - "targetOrders": "8fZpm7wuykrRoDx78rqEkqnBNwM1nyCPVRe9eirLwNRz", - "baseVault": "5o65aNxUBkSkTnHJaJk47HxZRj2NF2hiSCdfCPXHtPB9", - "quoteVault": "ErtcgcL2WV3TkwgsKYi5uc54twk53bvuvcJeFG83gWTz", - "withdrawQueue": "2Y9Uit4wGMQ26oFpvNu6BQnRqzx8e3Wo2DoGpBAh1Js9", - "lpVault": "D8cRZNjQr514Hir625EHaBbSsGqjugcdQbtVsJ3Ubk9b", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GFs66kG93YFrQb1zfr4mzYZNfkHPwj9wRyVy5MUbThwe", - "marketAuthority": "C7nw3KFQ3abcjHyZaD1fZU4JM4vzvyAtZ3ARHdfFR4Vy", - "marketBaseVault": "Eq6hGbfxDJWJhSLf6mBWGb7NuhAQsiME1J1p8kdcrxZs", - "marketQuoteVault": "37dugUMETqTcJoo6NWNRdY5QY4WwcP1qbUTHEfpbh5rF", - "marketBids": "7jfkXqLM75HrwWxW3hdzUfqHMZxc7iqwvnE6PRLk8uL", - "marketAsks": "CiH1TZn79cy51F2P5BA4Mqq8KZuQdee6NJN3fwsUA7af", - "marketEventQueue": "EqkssVN11UNVZrDgYW76pJ89BZtv2L6AseFjc3XRnaXs" - }, - { - "id": "Fjrir1LzJpWuFo3VJDDH3hHYbY1LSvvFGdK6ooXVv7J2", - "baseMint": "2pqRgpTLSJRgqBaBAQBBAqfLsdjqWic5bi6S9UJazyaT", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "7AkMed9wJRD5jC9kQLXTwhHkxi8TG6BCKDiw5rCDf1UQ", - "baseDecimals": 3, - "quoteDecimals": 9, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9osceTnS7tr7ajn1jVtzakRSKk4FThzPLYcPJaP6MbUT", - "targetOrders": "FVe2mGMtAhc4ddj2BQ5GeJ76ET6RJ4eKaonrz5hMcPY3", - "baseVault": "9HiwYJNgtUd8zpZrDrnbWduCLtZAxkLtBEhaZM5qztFa", - "quoteVault": "BWeDSQY6XMQ7NBRn3Lvag4TGKtz2LiNjEYyLgx9GtnVq", - "withdrawQueue": "2RqFB1vihdkd548mEXytuveijeZFL6CmrJRpV9FQqaFx", - "lpVault": "CNMibXLRNzBHcLgHPusA7gocJp6VM6pSaRwQoAa1gAjx", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FCTxysCYMEUDsr29rkviYQvzepLGUVDm2DYDWmfSRh4G", - "marketAuthority": "8osqrYviMYoF4vzMYWuhfxjio8uHJoBowV3QEhqz1wi9", - "marketBaseVault": "F63FJJGVur6PJfJnifUaSRJNqX1nSXRJ7KzDziUN7nyW", - "marketQuoteVault": "6YgzcpapooEDSnEAFAkVAgVN8RHqWzKY6Eyh9W2cc3Ws", - "marketBids": "BuCALypRackEK9c42Vvcf3vCZPmAgZJrhhLpbYNBDKJJ", - "marketAsks": "FSmzdcZQzzDVd5VLmZTJfW3jC7dqxqLTeS7VQwgixV6v", - "marketEventQueue": "21CZ1LCJJCsx9EXc4zPEJSQTEzetWABhbfN77RsymAUo" - }, - { - "id": "FJUu5RPr9th9JVzRATjZ961LFWYh2EivJP9WnCSKtCgt", - "baseMint": "3CaBxqxWsP5oqS84Pkja4wLxyZYsHzMivQbnfwFJQeL1", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "ECj1Dx9znCXengQWB1cmv8PHo2wWGVuNN8ZiN7kQQt7", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9fJT5xGGFJSsuYdiz6bSEw3jiD7kyfU4mjhBe3uGnF3P", - "targetOrders": "JCZiw3uAxUPWCYPrX7C1Zmdb3xRXdRQRoNEgQR7oHRhG", - "baseVault": "AtEbnYxiyj8GHe1JapJLuodhJpPFM99DC9rLNh1xom2j", - "quoteVault": "7XzhqJF2F7sAZMdCh1EzrhDhbUwoYxBJBFrHw8TpVFmo", - "withdrawQueue": "AnQWMZ3NS2NXpSfdXjw48VU84Z1iYdZWBo7UnjwUfht6", - "lpVault": "5WuZ82k8fH3gG63Jg6VEBps7C8aQogxuBPB82kaFM6Gx", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EqimahPtpP3q9XNyJMWeqQLyXXdiGXU42X7KJr4WGaqm", - "marketAuthority": "5HiTFR63q8FtDg2dAvEzJLLwGg1auxwNYhbXEUgkmRmy", - "marketBaseVault": "ACX8SHBnzpFDsdKirGEauhWYG8AQC7vpkzDFmQHQiZaG", - "marketQuoteVault": "65hU8wPEECHPXj2Y6AQ7PLuyUEgCsvFW2SgFtHMvpBVR", - "marketBids": "AtpqScoyKr4Grkj3CwRprhKbesPKHJEkQB25NYZSH1gx", - "marketAsks": "7wA85LehnwRmw3QAQVZuGYMx6BvJEVLJS6Pfqc2bE3rR", - "marketEventQueue": "4Cjo4KZ766eR79ndNPCRcixD8yngPpLY2rep4Vrox138" - }, - { - "id": "FkE4nxg2R62x35dymgqDidZnnJZ98QKTFLiCSCRBfayc", - "baseMint": "59McpTVgyGsSu5eQutvcKLFu7wrFe3ZkE2qdAi3HnvBn", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "7r37jP26dpLS26sggRJXtaptE25JQS2vELRwLJ8siCHg", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CVJvmzkQx6dGVN9x6PZh6UNL5JVcf13hCfCEdGjPTjQ6", - "targetOrders": "DZs2aqCryGMWVcqoTnxU835Pm3jzBwWGNu4WNQHerFKS", - "baseVault": "FT6k8BQ73MGNqC5HKNoPY4QpsZejJfAXy3T4VvZJE272", - "quoteVault": "4QpaxS4yNpSTxhJE4YYixNXYq13Cf4yS8gtNdKbtnCN2", - "withdrawQueue": "HcaXjHNHGR9cpqYFkkrkM45aEtHCmfpyCGxzC7jiMBJZ", - "lpVault": "AGoW4gLsADDxG4rp4Pacg4QAjaveTMSHRUGyJ3Jm4X17", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GScfvqNrEC9UE6vEeqCYQKJtmoGrN5ZAuTzx9uTHVjZs", - "marketAuthority": "8HbShEXwQ7DpVHPs6fXo96Gsk7qiXnHkt3JcRhQiynXr", - "marketBaseVault": "B2LSNrbue62iwHj9wsx8jyj9s9hSxAGh19r8iPPCLAZi", - "marketQuoteVault": "9X9ieyTabtybgU7NcNaXuwdmFkMnLETd4UktwfL3ydWT", - "marketBids": "9GTxHht5pFhPgkWE6tRx56ZXusK4vdxgXkiCHhJiy8p7", - "marketAsks": "DuuaktgavTRBPp2UKw3cfMKZ6zECDEEmqM5hyETtH7Hg", - "marketEventQueue": "5E5ve36RCBt3Fa54UCuGdrw3nhz4ANV3L4tTZDgJVS6m" - }, - { - "id": "FKi6YxntsVquBft1NCUeQCEKSeC8atYyKiVX59GdhTFA", - "baseMint": "Bjgh4YsLdicr8WArz9ftdSmpWNcQjsZ9KV3w9fkjiLG", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "76oadXQdtvShcY39BdPDYYrQM6MkDQdWTy93JytDzN2i", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ELuRbYwo42VLXGzx9nrD6tBAjVb1ygmX2vPfT41WQiuy", - "targetOrders": "3k65Po7oTcA46MZMSEj5sfYbeX6gq6k5fSPX7XiVQuoL", - "baseVault": "AxP6hWQSw6yeMshqixw4oTE9UZXuLZrTWu1iMBUP7TcD", - "quoteVault": "5GkZPPLiU9iCB5EyFoWHj7EogcBoJpCAgHGTyT6pciBn", - "withdrawQueue": "2NcfwBPHzabTHkCxgoBXWbQpXTo9wy4K5WDvDEGCWwMZ", - "lpVault": "bxKnYSyHRSnr5DdgLGGRZeof1stksE7PtXxRY1JWoAw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EvGmrWG9SRxCpbRkJoPmm7jhGX3hxWcyLYtNkVu3aJ4r", - "marketAuthority": "4AhQ3s2cpf3b9mMRhpPFaDHQBYAqXCDC2YEP3A7eiffs", - "marketBaseVault": "Hi28bT7Dne2EaJdSRs2eZJFJKrADKGxPrMXFTdJQWrap", - "marketQuoteVault": "FTeZDX2kEtaEoWK9KqDVEmhTmBLQhCvjkviwRkScwEyW", - "marketBids": "48MvqfeEzKeaoUS28CR1j4axVFuRSDrsRWjG8xbW1hNA", - "marketAsks": "cnRwhW1RJ5NgRG35StdBqgz7g36AJCfiBja5uv4Y3eY", - "marketEventQueue": "7b5sNmvCxwF97jeccS25UFLKTPGCEH193rwM67VaqFCJ" - }, - { - "id": "FkuUTryf9FHU1tpwj2PRZdCBtwCC4uD69tanwsqBtY8R", - "baseMint": "2oDVQrNmBrJR71t2wJjq5f7Vz6ohnJheHoLMJEHcEW4J", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "EQN8U42XrqTF8izGYqRwaFv7pmTMCVMBKzv4mMXoTiAR", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9uommr5X1mrn7cJ3r7a4xVvc9KAUcJVNtaYHxYNQHesu", - "targetOrders": "C4j5CY8cBxjEQ6LwY5Hxyx3tqmT8HS54KnNQS2qjXiqC", - "baseVault": "9rzGPpgm8uU7W85gMUJspK2CpPkpAQnqsvFegnzeRKgn", - "quoteVault": "FQz8akoQixL6CndSsZZz2SXoYfxaUJzTVmcnVi2JdLUD", - "withdrawQueue": "BqgghwP9qqkw6DQ1E4NQfEddFk3nWcdh8WBHmaxvmX47", - "lpVault": "Fymf4oyYSxXqY4yxEpTAnNBScuGZyxacruBF16ikC5gz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2RUQsYLVouAyQebEnRUxrv8fhgDY2vxrDwoo7rPS4T3a", - "marketAuthority": "krbt6XGLR51UhpAJBdSqBxbygndjgGZXbCybba3L12x", - "marketBaseVault": "9nihWcQy4VUKGE4yfLjbS6dXtXX1ZA79zmQbzxUNqsgM", - "marketQuoteVault": "G2Ev44vtufhCFHw5zRquYShaYAkSWTrqHoSFNqyepNWi", - "marketBids": "5S4tpetBh4G2ThJJkgGfXN5dE2AY9g64GEY5sQiUHtSb", - "marketAsks": "2WHGS4TixP2p4wAdSGaVhy9UGQs5K1wVKMnZ4bLV2SMM", - "marketEventQueue": "DxBZqPtpVtkEPaLKi7Kd3g4X46FAhpXmL6TxHDniG5Ew" - }, - { - "id": "FkWTXnNiqb8duDJikMhxhVPr6UKN5fC21weGUFsxJCpQ", - "baseMint": "DsNADnfdnbCyuxE2mWxVu3GmAAiqVfaw9xgMMfFGRG5r", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GsZVrY6FSxmwLRDSCBArzsGtWHnt7Y6JV5ehGURyADpK", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9Svzc2pEsoKeQgFmyrDLM7pAuNYfyD5SDjNLXQWuxbKT", - "targetOrders": "9Sb4CVT6z5PT3ey4v2PmQua4jyg2d8RMQkLXPWaWkn21", - "baseVault": "4QE6mqadT18JbWiHB8RvUrhBimTpHg6xe9cV9TeAfCEB", - "quoteVault": "GpEw32rKuQ57r78apBZhNR3ayWdWhudxNeKdSvEvdte5", - "withdrawQueue": "EW9WMuggb3K9gfJ2dTwPMU95uESTfZZzPhBDuVz2N7yn", - "lpVault": "GR6EEJNyCnJ3Jvwa1QXoDP9GZe81kcpGmbSmiQ1PRuPc", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "E48DCEu8TrujmqepsbRtU8qSzyT8Km6KFDXibBLySHYk", - "marketAuthority": "8MZbmCg8hP2nasNYffHj8j3bKM4Gd2cuaRCH1ZJfTMWh", - "marketBaseVault": "75FAmoMYUjSgTTxRqmUrrGkHZ7WvDhhqMvJYE3jwn71w", - "marketQuoteVault": "6hX5LkiskveHE8grFYFYfEaUvRtM5H4WPXS7Tn4GJrMn", - "marketBids": "6dkBJXWnQDN6FCPG5a8ikQTxg7qdk3xaw4xrN73CVtu6", - "marketAsks": "CDTeFWn1mFmLvgN57LkpJbrsh93Pxne5g3zqqaNm2T9L", - "marketEventQueue": "F51eCTncsYsSU7wfmcEUSZe1W1NkRCVDMVGu2biATCdK" - }, - { - "id": "FLJa6qduXnMRqqnFTFZzUf9RBcrU2ZXLsngCmciW7az1", - "baseMint": "uL2qhMckUAroJPt2MLHwEeppJNYE3wBAGFMCs3anwXn", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "FFmnwFo5SP8v9x4MzEDDgeQvzo6R3Fp5teEhZLsENWM9", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HBfbt1NRAoUA9qzxwXsUCiXh2NFAJw6ShjtXLNQaAyfe", - "targetOrders": "debfyuG8jZukbw2LL7BvhhXN2y4XrzDNBBSFp1DpRfz", - "baseVault": "HHVQhHb6AwGyK1c18rsXakSYhLaurCdFTBq7rQixmAaq", - "quoteVault": "2dGfoPoiEXKY1Socw2ktmRV4Ug1BNRVNYjpNWe5pu3cw", - "withdrawQueue": "qGvbm6WKKs4ud6RvhTgdPduC7kHP9vbB5h8sr5tC6Jm", - "lpVault": "VvoELHxNTQ3NLA63as9x5F2UGNumPwTX6fJ5Nbnz3XJ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FcsmLu8q9LrxZWzJbzDK5vopQpfiKVqY4FroquXwqCy9", - "marketAuthority": "HBPGV4ErTDTn78VZtKxCweFF7AP2feBBBmW6RUVPCZpr", - "marketBaseVault": "Fi4nwPkdiHnmZZ6k8czp8wjKjTBMUqboXjN8PGqcrc7n", - "marketQuoteVault": "H4yB3KgnBwL21qNLz9fSVLQTB1KUCxzxSrt4vYwQDc4n", - "marketBids": "3xMJmsWhZ3PwSUsswWqJxMYx4xZsMAbV5DqpdFmQaBcw", - "marketAsks": "DMrauM3yx8qmazmETAg1F8USHEhnpD3kaacZiKs7gzkb", - "marketEventQueue": "3QLrRr5qT5CkRAKB3Z8WXnHRGb1arYDB66yaWoV6qetz" - }, - { - "id": "Fm5qQHtLSPpN1nGEV4wjfbgMHeLsXtV6YcXHVUcXheS9", - "baseMint": "3rH1toffQAELHo5vyRKdwEFxhPTZA7ocfRdJK2c8txoJ", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "HLUMhNp5DruwCSk2opZW5EcuB1SE5gdAW67EKAbcYfJ6", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "VcsNVNaQgPZyk9gXQ7PUoixJ4r2vYshAtu8tCk6abRc", - "targetOrders": "5F6STZ1rwi2DSZtvoen8zzaUUvtHk9XNanikq4932umg", - "baseVault": "5AhyWjuUs8cxnDz2kyzBErwaGMViPYQ4GsfsD1r3vaJ9", - "quoteVault": "E1BPeGUc64vbABvWqg9H8ZaFRiiNKTd3aKtFnMqCegJv", - "withdrawQueue": "Bz2fx899dCRL823BLkPMCqU1o2DaCmpoyn4ZVUxxferg", - "lpVault": "4iDJWJ1wPp5U4nH7KeygfkYsZFM141sfQ5NkzMLHWtq1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "J4zNXqQun41uKPiDvGV3TxtBjr8QgjPRMRBUCxZD4qpK", - "marketAuthority": "EZTiSEWvaqZkxbJQ3HTSvshErH4wDm166C4F4cByjbYs", - "marketBaseVault": "7vwaDX9HiWF3hb9MzED5oLNJRAzuZwynpHjrALqxHUov", - "marketQuoteVault": "9WDNjJ978Frnv5wWqbHp49eKcNmSNmMaEtsz3RBHVc7h", - "marketBids": "25GByMVon8U2Pqyan15EatWJAe4pNPZMmMVrTk4SXwy5", - "marketAsks": "J2n7fzBp4xXy2BQmu2L8aG2GANQmBnGfrR2dv58fiB3P", - "marketEventQueue": "EvJGLPqjZNqPZd7Q8zaJenJoNijp6tFYVYfqQhsge4mM" - }, - { - "id": "FMNZf4jBjDsFPrTL246jZpUVq4ku1UaP25zrTVrkhrkV", - "baseMint": "Hez5vPmjjGbGyKBYFNTK4sq9WBJgE7MsioneQkJaA3Gc", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "29DwoJQpfgK3zsgNJx2WMPRptrJG235LjSH1edvxWXM4", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "G64oo58XuDePwibYKbrbS45AiGHJAYmhR6qhe5Zcf5W9", - "targetOrders": "J4ruC9v9NwsnMedBszcnEzzR4D4V8f2fEYNp4MSN8HYw", - "baseVault": "ASKFWAq46RWZKLBs8Y7zJQcyFZdvF3tS2ykTfyW1jZvV", - "quoteVault": "5XUUJfqmA3hkb141KaMaWmev2HGGn9jZE11iNhqfTzp2", - "withdrawQueue": "9XW5tNwMSafwMKseLGDSE3PDh9H8dHcoagDUoZrxLYXf", - "lpVault": "4vD6RbnYKPpZdH9bYpP4TKdpmQo4Z3jMWbDsuBDa138E", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4RugvNk15vAbbL7QTkQ14F2UxH3AJzorTV5fhagM7oNv", - "marketAuthority": "9vrx8x3WGFJKNZuavjrFhbxxyXe9ELjiX3BV2wxYaHpV", - "marketBaseVault": "7Tj8nf5gFArvW6vusnSaF3PswDMhqgF4sidhFRpJqjQp", - "marketQuoteVault": "DJkDSv2nyaxs4zD1fXpvoqcMjSA6LXiiZt7GeCNrnmfe", - "marketBids": "5uPLt9g2mQ3Qb7fPNGvAzDRy44FfbsxmTMHfWgmJs7vP", - "marketAsks": "FwVDnrtgWtpNJiDk8qSsMDX5NSBAshEji9v6uSePrdfK", - "marketEventQueue": "7iWqheGZiVwPMfbZB5dNX9eFMmuwEpcsyf3tBs6n7beG" - }, - { - "id": "FN7R4xN8Qk7XnAA4g2nwcGwnoGrFYAEQiLz71JQDwWQM", - "baseMint": "GS6E87SLTioRDG3uSVRwQmuKKMxDmWU7fktCTJ5xkEM8", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "B3ogfHBWK1oJaSHSmc6PZpdVPeLZ72gLpR7H1cSE52mc", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "bsmU5qmuxJtLrU6THRpX5QLmzx7AStfMbmpZaKiZM8B", - "targetOrders": "F5ia9gK3JJMeYTY97NsG7vQf2cE1QoLexw7xNd7menGZ", - "baseVault": "FGk9GNKgs1dDbcoMjcrLGcm2nRW77TNNUDDevmVcVwEm", - "quoteVault": "E7hpxLs4qfzrJCKa7ggYkDVJp8Egezv2zDeeZPRrqCMF", - "withdrawQueue": "24iNDkw22xAx6Y5rjQNCMgFPsSFx9FGMe5Uq3ANCww2m", - "lpVault": "67s3FEjEJhwWFgBCs1qPdnuDtAGTDjenW3wEdXttp8Xn", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3xMQj3XzXRv2BFZuEdhH9s5Vtku66fW3P2T5vHxDUmjq", - "marketAuthority": "HDHxGkeM3YMo6Kwtv2i3tuUSaREAL7gU9BREM3LMjgWw", - "marketBaseVault": "TpWSsoPAqhbwYWdYgfDvtbx6czGc3uQmUyafe9H36bp", - "marketQuoteVault": "6MTUEJCz1HqRX7MNB6TB1tMQVTGua2fc9mF9Wq6esy2f", - "marketBids": "2UrsAF9y7R5gig5CJZS4UFf9eJaXnHG3Qxc7K1LYUpmH", - "marketAsks": "E4swdy5FoJ1QBCPvXXCZRL5QyVBp7X82Ey7fUnHzMDvk", - "marketEventQueue": "FxXUcesm9o5JSdkb5TboFNUnQFJsyDGAEgmTWwk2Kjiu" - }, - { - "id": "FNA4hNKnwWruAF9PvdCsnrUa7mZJpnKMnMzBCEwYno5d", - "baseMint": "2946ofy854iifvXCQmHX2AJgxRBoQcchy1gfD26RtkHp", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "458ydDmsoQH5PLiBF4uo3Ff3Bfm27HVLA5otmDuygKsy", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "B6jKo4fQjUGwjBsZYD7Xn99zL1e3GTMncj8TZnxgxCk7", - "targetOrders": "BYEmAVrRhNV2UuzbAxko6sQu4A4AoyvC8x2etrRFcQF6", - "baseVault": "AC6mm4nMmT5Frh662qawAbe9sh7kMUroqifS1YA8jUgX", - "quoteVault": "2u85EXDHybPLyKyKfv4uG3sFVYaMByH3PGK4PC23puQi", - "withdrawQueue": "A2tEFEQbzUMe3SsjQ7ZxMHp13Pvfq9YLfverRD26m2TF", - "lpVault": "CbFvK3nY2DuKjS2WMvNNKDKJaiJia82kKRL2VNn8qwqo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3muYjVPCnunGhXAq87oYBWWdAPWJvEKbbg1fqKZLLkni", - "marketAuthority": "BrvQSTZjPufqDoSCtr7AbdPJWPm7P32Gx3W41qf9qZ2Z", - "marketBaseVault": "6DZdnTgEnAmcZ6nV6kSNbx9PRdWznMoXsgPWW27dqZVY", - "marketQuoteVault": "8xHSnniBpJcUzAB5SajMGjs1PRYPuqLTEgcxdSUw113o", - "marketBids": "8bYmVF8yokupzptwzUVYVdkjYYbt3PAfaarPHxXxNsD4", - "marketAsks": "7QQjwWZiaicsF9vbW8CdW5jCwbyCxDAVcVrW62f3J4vZ", - "marketEventQueue": "7eieBqomozNs9wUxGr2Va7JgNAnbvc6qNfUR2xJk6nxh" - }, - { - "id": "Fndu56D2TEG4qeDp4TUU8rg3H2ekRsMYfWh5BRff1JCf", - "baseMint": "H2EJUxt2KSPk7BWGZRfLMqh56wCmWygDJVTvjTJFHeym", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8Sw78g1g5P7RbZBg1SMbGPHs1rd75GriYaptGk44cPvh", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8dmT1k1En6Uys12Gdhrnr2hqRmbCrNCneDTsJrAoWGbb", - "targetOrders": "3KhDwvY7JZp5k7fJxWAmrzwaEoKM72qUgxzWa873om7t", - "baseVault": "24WKLRhDbo62FAkDqJRWDFhtho2WEEqLx6YEAFtzr8Ld", - "quoteVault": "8vJqVRLeHHwD1eZ1kxyQHxSemhC1GQnHkEJftQoVDKMK", - "withdrawQueue": "oi7tpEgACr927h1ZEeAXrFU3Yo5aQLfHzWUL5PvpKKG", - "lpVault": "UvMYEL342kiHXC3CPGbjwuJVxZeHw1VnFhpkLgsSCbo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HyZcN5Vys6jTE8UAvNAh6mjsFG5s9uL9GnQSA9WxZHrR", - "marketAuthority": "F4r7iHRuAPqnhMhEXd9ieVAQK8WormsjnDGxg5yfdcci", - "marketBaseVault": "8bZipwUypHg2yPzr5jyHASFu8Rj74NUX1cVY1HbQUgsA", - "marketQuoteVault": "2Bcx1UghKQRqfnsPM5YfgqNAgJ4D8J8Hohe8VF5NQHGV", - "marketBids": "C1dSvmwBcNd2BTBKLhXCErUgvtSL4C6AgUJ3VQUHpR8m", - "marketAsks": "BfPsmomeMkPbcrKNZLMkKSQns5mbxMa21zGVeCouGm6h", - "marketEventQueue": "28XF8sqXvwGkSPNowRWbxkx5QarsytFwiwoeBszskjPM" - }, - { - "id": "FNUaJdbrxbQ4zssXgeEev3y8yosbP7wVbKXNH56iCipX", - "baseMint": "BvEj2MNMPsUrD4vSk7NHs4TtRcCcJd75Wx5HvVbY4rbK", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "D3LJtV1E4QnKccqkuMjmWRnFhw6ra9a1LDfRyKWpquPB", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6BrJVbWL1XmaupJk8gZByRnmVL9UnAhsUGJTkzz5A2uG", - "targetOrders": "Av2s1cLuVRwaxkGneW1uDhKjofB4TcrnJXib7pNYchUa", - "baseVault": "EN9iupkXQ4Zhx8TQhjZ2jFfqENM5eMzRPpoEe5uzgXpD", - "quoteVault": "KdN7H1rwGTeDT3TBuQiNUqDfs3QFbETPmhTnaPJcZLM", - "withdrawQueue": "8w3bphUmMeSQHFdLbGiX8S2coMHgaSGRNApNr8NCuuH3", - "lpVault": "3uTg7fcUtKHdM1J5495bTFm2BUR4xfdReTF7rY5oTBQr", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "G1DqkF41DrK29DybrjtmG4eeYrsYaGjdLu1bv7YqxWx6", - "marketAuthority": "6eEC1absVqRA8EvwAXmitHMdkqCqW3yPQYxjbMWrwatY", - "marketBaseVault": "C3T8DKoX1eV4k8iAJfoLxwbWN3sQaLWV8LiR7TbuvrLH", - "marketQuoteVault": "EsJuXSGh5Qu2VHfyZDaL8oJgABURcRLVt1NBahxgv8UZ", - "marketBids": "23HsWpBvvBShiK91wzZkf19Y8EAREh9yJaWbgbSQksHw", - "marketAsks": "9Y7hraoyEYR39MPmsbyPxNqo5bxC6QMykVtTfdDsQUrb", - "marketEventQueue": "4gfhqMYjX1uxLxeSrz8vNxBkZ9VohxydQpvGggJayAcJ" - }, - { - "id": "FNVxD993wzNhEzVJNHXspVwPH2ohAacuFzoiUqDYBx5A", - "baseMint": "6piwLtPi6sYjvE1reSEpmAXfcJqJtyGp3fahhEU7VF2C", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4Zmbr35VC1B36kDqwWYREv1p7UwsSVc6ptQxjMFXGC9k", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "72TiPDLwWEwm31AmddG3mW5rWnUrB2PqBy4J4itBkfB5", - "targetOrders": "GDVS1zDV5JztVoezgcD7H7LhxT7C4LArUyancv4dJv7u", - "baseVault": "555d7ftD2WBKuCshcdDh4WpCTshUTv3mSgbon82T4rUQ", - "quoteVault": "8YCziDT6vQfWP3JhMqsyJEn4SQoX6N5aGyTvjiNHgxKg", - "withdrawQueue": "HvQdxVDXpRRFs934yzwkfezB1SzRCieke1pEUtmMCb2b", - "lpVault": "85NDDCnY97QPjVVFKbkjx2XGDo59FUx6YNh4iMwhQLSL", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "C4PM6sRdKLh1idmVZmyuV3TfPZMb2RscZ1RUFohZpiZi", - "marketAuthority": "2JCtNsRZe4qDBJYrf77EEz1YgJhMQYkR5kfkMfqY1Z8W", - "marketBaseVault": "HS2osd5gYVsSzPEBFcW6nknPk3vUBYvm6bqdXRHDwcsW", - "marketQuoteVault": "3LZX6PZ8rX38jD37coVFVu4zKKuG4MhGzHLXCMtC5cWS", - "marketBids": "Jd1yKy6t1fhHRDL7cWdpRRxQsiSB1WW5q5WJECj3eLp", - "marketAsks": "EPTG67hsRvwDmawqDEQZAoi6TJ25Lq5mqs7ZASt9KbQv", - "marketEventQueue": "2HeYbfy7kokKwJKqgDEuSno787t9B7Da4urGiFVW98as" - }, - { - "id": "FNxLzKchv5fJH5rAzCgXuJrwgQrZ1rHkQcRHPiMAUaVc", - "baseMint": "Gsai2KN28MTGcSZ1gKYFswUpFpS7EM9mvdR9c8f6iVXJ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9riBYr8UTeGh8hdvxk4THqb8HKgDCyE5qjv8tSRNn9BM", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2cm4cXHYEcVX7kPCRWFRMWbpdbEdR4b3R3yaNAsyPfLV", - "targetOrders": "J6p9mxYepeSYC3W6mERvAPdiR6BA7NvYgw5FieqWsoXQ", - "baseVault": "4jmWNsFmwTvjAiErm5zqHjLm1wNDETLTM8KPAwRNaj9b", - "quoteVault": "CeFpEhoBKWEJFbwZRjmqwA7gYhk4FQVHnJTTjHAZLvn4", - "withdrawQueue": "DbRn3LUPxJJz3ECH2KvtQ94UbRrkxg4zZ5sfyP3p8SLu", - "lpVault": "GuRKYgT5mNcT1TeL12U5qDy3YcACdD3FsUFUHwcbeodd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2zkPyHgQkKG6qJED6MTbjfCfUbZeT9VFwLm1Ld9nKxRp", - "marketAuthority": "F8WWYgHRyeh9cqraiUwfY45W7WppV74XdsuPJqrcwfjf", - "marketBaseVault": "GDCY1JhhzYY6ERVD9gKa288HBniGCamSXGX8ZdGHPgTY", - "marketQuoteVault": "GiTJMS3fWeQaFqLNeCekzShJbqZic9xDC9ZcFCaZpACY", - "marketBids": "E3Mg2v7o2wYk5JvNFx6LJ32xGdDVRV4Yo1bQynWXTH5v", - "marketAsks": "9171uAFLk3yYShaBvrCN9hzAf68roTgdfPtTppgJPheA", - "marketEventQueue": "BHF1ecBATDXPgVhpYNjyXnDuAe8TJw2AKLmUy6FideB9" - }, - { - "id": "FpxHbS9W5vvbbHHELYAm3A6qg5ZQtgbfzSpcGZzd1PYQ", - "baseMint": "htoHLBJV1err8xP5oxyQdV2PLQhtVjxLXpKB7FsgJQD", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "3TeCKgPope1GGq5AET7u1wiqWkvB3xNangyJWQauyiua", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FRmEYJDEjRQCY9fNgRSpHtpqrXKqqKR8jU64JktzzHVm", - "targetOrders": "6C7FEnuCYxsKq6GvrHkQJRRxH3Kp4ZaotYgAZxrv3hs4", - "baseVault": "DVQbARfgF72TPwxTCJpmfiReavHqHWXxoUSG8t76fZMV", - "quoteVault": "Ak1SVFFz8rciQhT2F1ES24VhZsKqJ6kQyGoG8jBBGqaW", - "withdrawQueue": "JCDrPkxNRpH324rtKfVpaxs7BTNpSLo27JA9QmeJoeHf", - "lpVault": "3UNKsTjYReRmvpp6Ckh7kNs4rKE98bsuBqWTq8jYNw6Z", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FabccQrS3V2CpXBTxTepdRrTCJ8ZXcRbXq12uhCUqBud", - "marketAuthority": "H1uF8UxckWd3qHTLNi5reufYGyoBF1M1Z6wrKrHMf3Sk", - "marketBaseVault": "Gwvmm1Bz5MyBwbC4sWTRtfdBatKqMHAbtupKg8CYVnDE", - "marketQuoteVault": "BEcRVW8qPYSnYnhqsTu4KV8xv6WEYorbkz7yNCXqyKPd", - "marketBids": "3nKgfxNiZ4W5fNkS9b2y4qydXjnpdaTYf2EXhkb4nUCf", - "marketAsks": "DffdJKVdziqsQiDQ7FVNyozoG1ofYboc6w7RvFrhxudc", - "marketEventQueue": "64L6HhZ4PmXK7T4y1NajpD2NfTqbLP5in4MKMuvC3EmZ" - }, - { - "id": "FqCG8vhZovmFsT1iqc7G2xJHWwL2i8dsBg92c7PBfMk3", - "baseMint": "9j7pLeELCPTnXYXcHSiGSuYr1UE7cTaAd16kiH2AiNs5", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "9PodbijREfCwnvjjvRk7KiuAqUZiTVRHojGB9U2nuR4J", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "A6W3zqNEjNVRd3hgSfVRCfAHafRY4UPmm9daZ47U1zKw", - "targetOrders": "GLc1Wt3B7e7Q732U9myKwWqTa6ECyCYxd671epjXbcub", - "baseVault": "E362AASz8FJ1wbodu4n3BVYnDDDC1GcMUJm5kU93315C", - "quoteVault": "5n3SCyenZdpsGLeht226gXyKT4dcAwNdfJcuLKiky8h5", - "withdrawQueue": "ATx5yuRRiY7VDB1ierSuZu2wjyn3Kx1rKEkGjAphVdX8", - "lpVault": "5a2e8CgUgTjSd2DWQkSanHyBZaUiN99nYHHQEYGBVRmu", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DSgFoQAQDRzCLYcaz6JJ3VhW9HNA7TVdzyWX5xtqTVj2", - "marketAuthority": "3HJWj29BRBM51SrSTGUTuLzCJvzSmEqhJoSRyWwZVdpG", - "marketBaseVault": "yWuisymryxYy1wwz7vBVqo93Ts1L6aH5t2na44q29si", - "marketQuoteVault": "4Ps3PBgmQ15Fj7spDgjVNwSqPTwwLo4psiiq91TL4XRC", - "marketBids": "EohKcq7tn2nrSmg4KwPHwwKJqurH9NwYPQfXUCLdX4i7", - "marketAsks": "7554JxR5CcCDxQ64cpW1pV1B2KV2FFWzsahdmMoaN3AF", - "marketEventQueue": "HdgxcAmoaBxn3H39xUP34DYg6bhS39bQivSKbyy3FtMz" - }, - { - "id": "FqgXQkcQhHJ6QiW2o2P16nq49jxEQVkNZZJNrvbvJFX8", - "baseMint": "FLWRna1gxehQ9pSyZMzxfp4UhewvLPwuKfdUTgdZuMBY", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "21rqpdZbZTMyzsfrvNNLzhQSz3oEC714EyiRfzNBXyUz", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FvwJjbe4HcyahmZooe9k4VH9NxebsT4Tk4FpaVRD1C5S", - "targetOrders": "6pYuKFKX11dFcvzqAC18FA1v1vviqj27cTY8AtBuXepw", - "baseVault": "6FmQPcpjbsodnCpK5Y9rem6YJ4TePDnbEzbW61fBoRG6", - "quoteVault": "14BfCkNczDeLGQmHXcd6AaeM9bY7V426GJvjhC7CbGBk", - "withdrawQueue": "CXEX6DWk99VwLnmNb9mcKBb2XTDoG21NVLT7R42GNzvx", - "lpVault": "DzDEP32snRgadmtZo3KjUeuSr8aeMCCTBqQrYP5dGx9Y", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CptfkZ4ZVDosgjLAoxNApRUEBg82qQKfiqpWiJwc3iRF", - "marketAuthority": "3HrJdCNm42iVmLpM7fVEthhVSHwXbDuCZJ9pgcmCriCy", - "marketBaseVault": "J7wnvMdGhyrcrBBHkqGVcXyXEGQXkLpC6FGSEj9zN7FS", - "marketQuoteVault": "9bhjGvt4FsVxYZUT47giwproNcu9MxS58ky17sB6ik1y", - "marketBids": "ry8QKtEVpk5ofaNcXNsGXkrxhABUBkDNwkRij3YLB4N", - "marketAsks": "8TU3tmQtGT2hXta89zkdE5XUoVFfNw1oRrA3hnyoM3Qr", - "marketEventQueue": "BLMdr6ggcTT1yE7iSBHK9FeQaLTPzFqwgBG7doJ3a4Lm" - }, - { - "id": "frAsLFPXqwUAExMbsgkAetDhDh7tdQQmqxopqqExjoq", - "baseMint": "AymKzSDznoLT7Vhsb4wSRnCj1gjcG3zkgYFY8fxsHHer", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "5HF5GxkFT8QcurPAygeTejS7Mikut7JuxLpwmP7uTXX7", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "B4EVmnZ9UoUSkGBzczS2B6k5fMbAMpXvnx6aPeHR4eZr", - "targetOrders": "9WSgttgKBmZNUCrTcobar4TkA4qmpY5XzgkE6persKr7", - "baseVault": "A9xC8Sr8C92dgT2bVQRkXNiR51J2thDHhtWZ6C6Ccgy9", - "quoteVault": "4PsboUNHcQhCwhE8i1MY7uZAtdSriss47kksHbanJfXW", - "withdrawQueue": "9qB2yMjWa4C8sKnbNHar4Hy5AbM5gCvDCbekX9qu3jih", - "lpVault": "7ADYk1mPZE8oKGMLabVEek4RE7CMtW7tFfu7tG1rNoXt", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5nfMXEB6hAHmGZUMfJUhFMyT12R822iho2JSc7x1XpdN", - "marketAuthority": "VTHWGtFfyujuBXgdWNNYpcgMrz7nmeaFAxEN96fiC8W", - "marketBaseVault": "77JmbzyGqdiscjRKrPatmNCC6zLL7g1zBNnN2aBQQV6A", - "marketQuoteVault": "HjDRb2npzgcNXahRuVCX8ERJHmEriY7F4L1xSTUCSQJ7", - "marketBids": "6ftkGwVKm3dff5gTKMmVa7VEashaowcPrjbX6vkReXhh", - "marketAsks": "6tQBtVqGp9EgCQnpDTwtX94fUYxrADJSN9SAKupHKoA7", - "marketEventQueue": "Em3Xhxd8kPp8XnAxNKokFQz8EyrJj93QNts8w85Y7TjQ" - }, - { - "id": "FrD52HbjYM9wsPjfdAvjF9wrZYroPKN6rvhJM3wcYX4f", - "baseMint": "4ThReWAbAVZjNVgs5Ui9Pk3cZ5TYaD9u6Y89fp6EFzoF", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6eQurSmjzcLiVqfrM9z9u1DP8csUUcDkHrTNsAfvy3nR", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2RhCuXuV3LqvgpumYhT3YpbVFXNxiTrbYeBEZyD9yVGE", - "targetOrders": "HpQKhtvcF48W7Pht2ckk8a7ufV5cDisjnm5xp6hnCEyJ", - "baseVault": "7ewjHyt9ahmwYXjAkCsPQVQe3tMkckiNNaZqfX2TdH9p", - "quoteVault": "3E4ZFMgSrt9uRuJbLboNJpWiajY62nSom8m5PUuR2Lf3", - "withdrawQueue": "dn7pSNAw1KBp1JBksN5w53vsNpXLU8fmjh5v3ezkpf6", - "lpVault": "7MjiMnfWz647EdD3Lp1YVd2J33GD671J7YngUjwYgpn1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "wcATqqbBEymzCuCbBwUMyyQSdj65YLtcZZCJoKypXWR", - "marketAuthority": "3X4jUw3HzDJgL4KfKcroxQhAEpJYkPLUa2KjqqcV96Jj", - "marketBaseVault": "FLe5LoJBvDrdVWXYmLao1isMBityL1pPwx9Xej9bRAeQ", - "marketQuoteVault": "FmXc75eXWpFzwQSVBwRu3cdhkQxiE9foFWN27cUCqLkp", - "marketBids": "CeGFPY9XYbEGGiGEoo2684s3si2pDAayNSqu9R8MCg6d", - "marketAsks": "CtzJYJRHNWftPs3AZ5QBHoxuNrSCAdtTabjMitviQ5zi", - "marketEventQueue": "9Rc1yBwjvVc8ixwm86vM8KELtfVTKwnz4FwVsgxBjwX7" - }, - { - "id": "FrHNyCxH7zheYoeLz31thiCgHQxjuHfqzRyW1w7z32ev", - "baseMint": "AAPGc83HcJmeUpgnQvGM1VTqta1KQKdj6YJcfqgNRgEr", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9rFZZkQPQ6MnbpgcknTRGwYi6Bb5xyfRD1nLzMHALM7", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2HTsde6uaY79trUFiBpWugNZVu2FBmGqTkScDpzWW2JL", - "targetOrders": "PHGF98grC7ZRTNzy933QxyRBYKcMeCkSXrHJMdw4Yro", - "baseVault": "7tsDc9sYAHKdB7chfXutSUzVjw6KTFAknYqpLap5JHAD", - "quoteVault": "CdNA7AVSYMA8GMGUCtK4qTRuEwNDKTUkgENsavntL3v7", - "withdrawQueue": "56DvtKLsD4ed5fze3E8vxCvM7mRt3fR7zqF8hCzFDkpr", - "lpVault": "2jmL1TBMS3HHBhLUvLEme3jetB1PasfZgyiNDjq3DzTP", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BfqxHCikfSXtBqqtuDbwNFnY7wCvf5MowhgEwihxk7eq", - "marketAuthority": "AM9zPqvQCCEs3D3UxvK17BdoMZEy3pjeZEMBvF7T2TY8", - "marketBaseVault": "5Da63jmN6r5KccCpWmunwB37Qo4nNRr1ZSKGKwMkFyYJ", - "marketQuoteVault": "GuotYFzdSuZiDMPqoyqSdxSuXd4n1zx2mt5XtVBJTSeN", - "marketBids": "GkboJuNfMrNXG4T937ME3egpKJo3H5Cygi6Mfn5Yb5jq", - "marketAsks": "4Tq8cdUay8xr2VwgQAooxqJLUZJnNmGcCFdh81T6EnsY", - "marketEventQueue": "8fJkJkYEUFARSfMWYPGEU5B1CJatN2SYmNzRSVbmAWa6" - }, - { - "id": "FrZ3Nu73BLq3JrEqiUeYDXFThQQYQhdCdNYeuBSxagCs", - "baseMint": "3iBZV8gvUFxp333FFogUPVi6MP9dEZ74xUxVzEQvNPii", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "9nQUu9Z2Y5L9TTz3BhECN1BRoqdVdaPFAjGx45ExqpAt", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AMVszBw6tqWFb9s8kaEfYyo4rNqEVuiGDubTJtT8ydhf", - "targetOrders": "9mRVoeZ4NYFU8G7CVhUmsSqF74rKt8kLWHhCjsK76JNz", - "baseVault": "GnSGPQvhpJJCkLx66qfrdA398SdT6nSp8fGYRDGiumid", - "quoteVault": "2aUbphSn5aFhyZ8JnPKaD5gk1ddfWGdN5dKPG5ZEpyV6", - "withdrawQueue": "6gdYzyEaJts4m37155E5FrD54jQ3aV5v1h5VucoRZkvD", - "lpVault": "4G3aMDZGaBCpMB8Kkd9oMk4BMEzhnNrjN3PnPDPhFGfC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BeRjqt5wZ1XwK4HpsM2GcBcNBWzDaUXdRPvGDJuTFpuN", - "marketAuthority": "6vwGtEA9DvMcJrEGxZi2vn67coWXNqBh5HNNm94ND9dt", - "marketBaseVault": "DXicQJGfsN7HAscNSDvhFeocGd3ma762e5yPX6hXXMnz", - "marketQuoteVault": "5PXMKXnuKKwSpvE8p9YEqRYPbi66wr71Rs6Yu2CZK8pY", - "marketBids": "Cu2dBXRtiDkBnvCuUNbpEaDHVAMG7sJaWoYqgojvdz2T", - "marketAsks": "HNhk3hkX9jSbNmQw66WY5PGotivcMtt4DzQcAjou7bbH", - "marketEventQueue": "487EwXNkkA8Lf7rq9Ju2qRw2cKCqHSRrJEexsjyzGSjg" - }, - { - "id": "FS5t6hTY732AJASW1MzrtJJRNaJbb3jDVhBDtNMWe2zd", - "baseMint": "6YAXGyWb3hhLVQQ3vqg9ZYewXk4Cknnr1raTfDwbf8XG", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7t3D9onJT1xxBF593RTdm12wvB1ngB5dkcDe18a8Vk2o", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "F9d3RjfunDkJiCiWEYGncYZSR6JbRHqwDDCEDy5Jhkwn", - "targetOrders": "5VMTv5hsCpSJnHTZen8yuLzghV7Y86iLUukAmiwVWZ5N", - "baseVault": "A6tHrCiUxPAAXbstwqiW3B1xTMmcj67qKkqCo7yDa9XF", - "quoteVault": "FyWuXimXfykErhsKDKrUMYpwSus8zamg9Wxnwt5wavNW", - "withdrawQueue": "2aCnELbSrPUi46c3LJWHt84ariErxzH5Q2bmzc2oREWQ", - "lpVault": "9Gav8zJzK7hFXdwXhnSzpyKnbKzo1A4Yyw2b29cfKiXA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2JqDNh17QkLdY7EXvFeXQpa4r82WanAgngf6Grc96g6B", - "marketAuthority": "79uve8SrdX5R93rUgSF1vzJhXr9tHATe7VdFu8aRNNb9", - "marketBaseVault": "7EKxjjX9oFzqv8ZQDcTRSgo9SvL8mgTuWnRn33KU6uuK", - "marketQuoteVault": "C8droMJPsHCYEyrJ5nTfEzjLnZUw5cm5LXPX2eNZouBH", - "marketBids": "GiBL213DDtJiTuB7vmQs3CHVaudZ4kGMSCjyzAbbxWh8", - "marketAsks": "GxQTvPV3pL8YVejuGCeJLzCsbrXpGLJKZd6zdLe5NTUW", - "marketEventQueue": "HH8jmicMuaFZf9kGaX85LpveMHL9hLDnzyKFbk6NLiz8" - }, - { - "id": "FSQxEKPkwXwCVySp4z5VBRUtP6Jh86m8CzfevkEaS2AJ", - "baseMint": "invSTFnhB1779dyku9vKSmGPxeBNKhdf7ZfGL1vTH3u", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "3hoq2rkNdPwb2nVaMUuyJDNXHfRTzRftYdRAAKEcEow8", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Daa2aCzLmvBcJSPsVgtU7ixzo4sTWFnPgVGHCCNvX5Kh", - "targetOrders": "HZGvD8BQQ5LgKFfsUVir5LvHRkbRoVMKrpEzBsayScrq", - "baseVault": "HVfpJSkM87mr8XKVUyZCZwgmoVQ2SaSGiUsq5EwnQ8ne", - "quoteVault": "CKqfupEUjnXSJ8bmzogjcGR8j1v5juPNLBhJb6jAEZiW", - "withdrawQueue": "ACX88ka5jMGLdJbuXWvQNFR9uGdN98rDVeYNxNJFaLeW", - "lpVault": "6sCnHtYwYgqEcfNry1mzQjfdaVBWnDETqe2xM1dyN1ED", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "C2nuVBtxshTJRuxMJq5vYgM1ieUHku6AimcjRWEckLfZ", - "marketAuthority": "Ayr9yqeeHAhzgnNuGf2ykt8jWWTcPBbN4g2aitRq3u3d", - "marketBaseVault": "8ae8FSPxvCTj2NGhm1AcDpw4eoDGospXB8Tuf3WSw8cZ", - "marketQuoteVault": "FP4DjsUyAguURHW7AdqJoUp7ARTJNNtwduvoBeFgTBLn", - "marketBids": "A5Sz7scf9c7SMHHsMrtXfg9RQCpGeF1LNFutcHG5Lxak", - "marketAsks": "DX2gddhscUFEdTW6edm7QSG4veXRBjxsVAJRe2SEmvoM", - "marketEventQueue": "3xoLzUfQbo1zFztjbhAromLHmN16qKfvGGCi1QJyDpbk" - }, - { - "id": "FUkBEd6KHSfL3ELpWTx5y9JWjAaptptzcTaCUybuW1m9", - "baseMint": "45eBLJUCQf1acXdBG8daBfUudy8T7V5gDTBpiE1iezsN", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "B2zDNM8SZVyUKwbr8UV66iHnM5AQR9zwwqGzQbeTiv8L", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GWDLiuWGmU2kyu47pM1QY28W6xMJW4tPUJEm1J1QCzyM", - "targetOrders": "46AcskpYHZ3BFJtnZhNv18msRF2CRPm8x8TdFg77pASi", - "baseVault": "C5c4uC9BRJU1q89KtFbjF2othypytceUJzx7XD9DdjLk", - "quoteVault": "8KGSVJwswpohh7U1TkatLYd8KUhBwK3LKx2VnuC5VMPp", - "withdrawQueue": "FPJcuuJwAZPtkGegmARyQ3b2VVfzFkfuqjwsYHtAfzvQ", - "lpVault": "5CDrNrqVAPeDJspYBDn7pzFtvNjkecgUKEqH3ZGEkCHE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CsMQXvG3iQiCWcHVoWDM3VxLHAEhAhj2LEuEAQ4h9wJN", - "marketAuthority": "HWaX4WRzBWKNxJNCMmLuthRfRSUdkLXHgmXNrAqSDxEK", - "marketBaseVault": "GLqyyhKEKNQZARoAobrunsYGrgNfzHuRAvAUxXX7QWND", - "marketQuoteVault": "HSjcehHitc9PCxmTZrne6fTJmVMiSrRsT5QoFfHDq2Ti", - "marketBids": "FJsTpdACVmoByQW4FNxF1NQ8ue9Jh61gUmXiUh515KRc", - "marketAsks": "326sT7ZX8C6PQpBs2a9KX7gqBqcwHda5TcpnS2kyoQYu", - "marketEventQueue": "8kFjYUUT8t8TYhj75Z4PfgYrp3NUBenFtSayaGkCASNS" - }, - { - "id": "FUr5JEyPVxJreMwwkK9qzoWE16CU8KzDRwnc6nuomUK5", - "baseMint": "4UuGQgkD3rSeoXatXRWwRfRd21G87d5LiCfkVzNNv1Tt", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AdXNZLEDDV81D7PNYiiCgZLxQF1yZdjykF4uYeTf4dZL", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Jurqqf7a1ttcC1KuYNumdpj5oUUHfLoeS2Ky1nddtdd", - "targetOrders": "GtR8suuQMR2c8DKE9pCWiiA1JzjjZq346f3u5rx7kZbH", - "baseVault": "3r6pUeziXSaD2Lx8sFn3s32pdEZ2yeueAjvTfwpCzsBv", - "quoteVault": "7Um9uquJtyMukXfoA2USUyu3xmnWsQ7VNLDnJ29W2YAT", - "withdrawQueue": "4GFCms5WDRVehGbqhm6W1Y5ZW8D2H3He8S1Fmz5dfWYY", - "lpVault": "7aGa4EmxmMWEWMZCi5RWW7UifhmkP8dYgZPCSVaj2gkw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6pcGYqts3QnxLafvZ1aEAYSAgtfyLkRLXKoWDLJpDDz1", - "marketAuthority": "Hjka3ksKAF995HF33ZKuV7VfGqPUyDmt15wvTw9BjjKR", - "marketBaseVault": "553JznvgQmCB6GceP1EZDyrMKsG2qL9BFbu47ACxRgbW", - "marketQuoteVault": "CeeYr7kGMCHG4jr3An4s9ezJTrCsoVYjhD2SoDWff8b4", - "marketBids": "AGw9ZopwmkQNTDtroP4dwPUsp3sWkQMmoZsxd3oonEcw", - "marketAsks": "F7RS5RSNKBGWAkHuk78sEsPYrhvjCwxd3SvkG18RBp1Z", - "marketEventQueue": "7FmKNPoE82oQnTF5D4hxehSozCHvJ3CopYZqErNWcWyX" - }, - { - "id": "fUsHC8AGn1q71fduxNXGbDaXSmCGtEV6Vj3Cmb4jY27", - "baseMint": "DubwWZNWiNGMMeeQHPnMATNj77YZPZSAz2WVR5WjLJqz", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "1qoeCBBhnyL2uPDzdpQZ7aVi8RcXvmE3KR6R4g9EBvb", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BeVjM6EtCRCykzjzEhhP2ki8MPG23DGjYoijaVHiCy7p", - "targetOrders": "CqPa2pmQEBWC1HXPBUYTS9XjmGTMDFAy8Hg2GALgoFTU", - "baseVault": "3S1YGMVo1wuMgRXYXSaKEhgo9iWg8Up6SBUksmc3S7GL", - "quoteVault": "J7RMy13VmctGbk4ZcFyeFaMfAuBUyq9VVUkuzxbWBFcv", - "withdrawQueue": "2sHRf464jm3ropirshpsKnJFY54XJ5DaeTKi31c27D1c", - "lpVault": "21CrHNvkGJwbM6fzQBh6zqj71jjaXE6PjXSyq2zxn3ub", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ABR1yKZJjnbevPCCUCzBUAy5M4qnnWNUqn7zusv4D5CD", - "marketAuthority": "ABFCe7Kw7TgNvQMxbQ6Tii8WD2S1AGcUCsqo3CcaRKj6", - "marketBaseVault": "CmQZjXiyhGTRKd9YVQoJhsXcAdjdVsyg8TXepiZfNHbT", - "marketQuoteVault": "6N9Cd1fEdYmnz2521r17VyBiAr9wQyjuoKL3MYLfnTXY", - "marketBids": "E7dx7EyJ5RbZ7HosLRx4uwMuT1CUaMtrWnQ5Tr7NSQgM", - "marketAsks": "9qkhuXW9gjTkjh2hoyUrtmXqiV6potvzr359RY3MhNo4", - "marketEventQueue": "5JAScYrksMbCq6aNYZXK8JEF6YK133qjqRLYxaiDo1Ym" - }, - { - "id": "FuSVni88QEcviphDUrRhosYEH5hMHUB8Emi6QjafnBc4", - "baseMint": "AGkFkKgXUEP7ZXazza5a25bSKbz5dDpgafPhqywuQnpf", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9R3UQZzYk9RkBmcb3dcAoHW2TEuYwxSE4DFfjbMWPKdE", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9k48Fyi2H83ByZGSzAcMAYs3arX5jg22bWmPSUMY1RET", - "targetOrders": "5Ua3SMrYYErb2VQeoW2ZjW2QnmHvXVf4iRtUz4zyhUhs", - "baseVault": "GQUWviVatzk6fCKF4jCxgWFmR2cgTdQ6uRrHbwFnoffo", - "quoteVault": "FvKJLR446YwjHW9fvmLZUk5tzCHSQK7YRkKnNW3BiZGp", - "withdrawQueue": "A3pkUXnv3sY8AsQPr2WLgY8a33o6o4MPtPRuDbQ8nGk1", - "lpVault": "HNEaccYe64mXqrx4eRuTUVSELa5vPaBgSebMiAdNXhJ9", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3Yp1TBvheBnQnfxMLXt6NTrFs5w5SjQcgRv8r3vNGdWP", - "marketAuthority": "J2CSpJQACDwnToNE7SiW7sxAfFwmGrJYpddvyHoZ1pjy", - "marketBaseVault": "2eb7zUge755bEAQz51UgbKxDeNiqhWDoZpNd83poFxwn", - "marketQuoteVault": "5PKmtVqm4rfXKi7fYcF9tefBeDK63ZEq8KPXQJjXTWpb", - "marketBids": "BRnMmB5H6MAjK9bqYJkD1UmM7Wxr7s5NVEfxkYCenJsZ", - "marketAsks": "34kwS5Jkv2Va4qxJy1xds66Z5YL7P8m55x5By5mdhugV", - "marketEventQueue": "5aJYeiVtJeL4YXhSk1CunL7voE7gwuU9diip71YaZbWM" - }, - { - "id": "FUUhzMivovr45yXFe2JdiKnqT9YQaX2Sr8iHZfCPCdRn", - "baseMint": "5K1JtWpdSksVKaL6R2DuLpCDAjzxK6sq2CpXaXDWHVLg", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Ef1zqoesqyRi2RLvsoHBvFqjJAcF5WkN4tyff3VWk575", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9YkNYKR9gtu56RskGhMfxBhTPwTbNe2Mi6uS6v6abDnw", - "targetOrders": "BhsTHBJGxh5SERaYZeTrqgqavoZFXK5M2KyrvyEcnDXS", - "baseVault": "6n5GUBpGkgMcaaA4X5nZK89jAdrBdihfP2PCyMeRYX9T", - "quoteVault": "CPnHn9dtyNzkd1DMZZLec2QFyt48GERZWPiigph1pgCT", - "withdrawQueue": "HTyvYcJKeVUBZTgjU1eUT9y5ap1KY53M7bXmQRL8iVJe", - "lpVault": "5GLsWXhSipHwaKRT4p91BefFR4L7SCciwPJfAQz36c8f", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GFtFCchnp5kzjX6iMx1nKVteGCdozhpRrW2GiMk6pNac", - "marketAuthority": "FACmL1eeMkxE4EDZXSQqn2vsNHR75x6Lyszwx27tCxa3", - "marketBaseVault": "AULtLG4ZD9kLAek8rmKtBSynAHVjzbEB7kHeY89KcFao", - "marketQuoteVault": "3tam4PMThmdmUxXiegV2wKFKkBZXXak7vPq8iDd8h11R", - "marketBids": "41ESWfBep4jfw3qw9moGoqAdSRB65ZZugfnNxkX5gxPq", - "marketAsks": "5P7ExPksA9opsvWnKi2SyaiLiV8e7dRqdPAuHo8kcLKV", - "marketEventQueue": "3tRrqkrVhYTRDrSwqcSkZuA5BYR3Y51pmziz9ToHaDRg" - }, - { - "id": "FuupXH2L6FPWzuD8KbMoGzuNVHLgh8mD8svRD8bAhQJ9", - "baseMint": "6wShYhqA2gs3HUAZ4MyaPDpKPBWFJUQQUGaCoy2k1Tgz", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EUdyAK7YQ4XV87pUZd2WMEREzN3sBFSm8LRQZ697U9Xj", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "XboGbhjgauXm7yZaMwQAWFDB5XAHP718dpFQbio8sfZ", - "targetOrders": "74DGNwoZD8yQF43FFbDPCpF53Kq3eLsuEuRBi3xjorhY", - "baseVault": "3g1jisAQ9SCgCUtuL7ziyRy2XTwtRraZ5uCm7Xk8URep", - "quoteVault": "44uvDbN8ysMpnreECQk7UgYziirDBAjj4iqrnburrsWB", - "withdrawQueue": "3QJPYn3R8jP32NGcF1Pc7mtvYyob9UjpNxvfE1dnjMRg", - "lpVault": "5CPhrJWgBkCgdpHRASjLQGGtpsGGbVALEakRtc2wSgQa", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8UCUhDu2XvT4uMARdem8kX6hQwmefyq4fXUg7kNMNZxa", - "marketAuthority": "FTViRvboqsRDPhZDfkmLkAs4NGwDyYvjzpGUnrQKZfzF", - "marketBaseVault": "FoseS9SxcLZhYtJnoracABq5pei4gd6FWvpGvkdwJs2f", - "marketQuoteVault": "8V75ZizYtzyX4cRi3L9jBYhTFwHwwYMa5BPb6AT5ALVr", - "marketBids": "3vx44EJafFk7hhUggSbyKNe5HHxtuXkvubzqz34gd1Eq", - "marketAsks": "8gJLYSVXzukWWowiokVYABPRj7HNNBNKfYvneFWui5NM", - "marketEventQueue": "FVURxeuK2iBkrJcZLAevNdAV64CEhPfvLB6TLwFRmeLv" - }, - { - "id": "FvXeENyLT13rVYPtHGN2eRBmGJdCR6tycPkNue7mRMXZ", - "baseMint": "F2CcdH4uXVL6vwutkFMtHWFaj87dYSh9WMWNqzsMmTUG", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9ahPFAaJUvpebf7JGNDxewKZsyt2mxmqrSpJUh9TsFqy", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8FXfUXUGYpQuQ1CM1nFfNs71EAGv1UDu73Fgr84H9rUb", - "targetOrders": "9p9snQvFhTpLjYcz4wyTkoSX8gZewDRHmpYNAFYfRXXh", - "baseVault": "C4d32BYvjJg8bunAuEGTJUUHnDQkmXcBZVSZLiDByxbo", - "quoteVault": "EFU6BDcEA6cD6GiddGg6mFeLtrctp34cDjmJEnh3F5L", - "withdrawQueue": "FxciQ5Nehx55xTCpSVfXwadzHLXqP9zDsZsqZbuVKerV", - "lpVault": "BNniYNiFWsb4D9XAohEvUH8a4ta3px7BQEk3mfgnMhx4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AiKDoMjEjhso6hmwKkSm9D4LD98PUcS5TpPknidd4hoy", - "marketAuthority": "HB4pyA27NmCTBraMNpxDdk1uwCUkcnoNCFaLn843Wmr9", - "marketBaseVault": "BPvoYiptsps6LozTfHvzVn39kJE9fgT9JXvTbCZVvSJw", - "marketQuoteVault": "J2akJiYUjJSpM65e2dcrzMkC1QtE89xCVjpnSqbVXAVZ", - "marketBids": "3kDkvouCZqU9ocTQR6cV7LimyurbzMEbpJYLq4XzNaGB", - "marketAsks": "63uB339p7MF9vNJwLG5ftRuQ77Qaa3iXvsmgjFtGMW2Z", - "marketEventQueue": "7sDLkH3Dy8b5LYkKnkrckSqkCSDAShr7SgqNXcAnQXA" - }, - { - "id": "FvyjWMzQsVTjPxkjGXqjTmpywwd8vgoqG2B18judJC8V", - "baseMint": "A4zyBooAFkpfy7osonRJMQ8a6zArGxN5fNXjXo1ZTZK2", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "3Mtrqvc88RtJyLa4WUNpuRq3BvuwLfJXV591TEtChDuC", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CVKRsURR6R3AZkeqvHg2S82SU3VPRW3DoUbQRh7EbJYh", - "targetOrders": "CYNUsbNXoYc2WfkN1yZU2sBuStH5muLdR4JxqrFWoJC6", - "baseVault": "HWDwVknNbkeWgQdUZq7KW1VJ28mmwtVfCHX3wZABim1M", - "quoteVault": "97mvfFjVsYDCCBAtBWid8Nz9t9PBY5kRzneq6y7a7vqh", - "withdrawQueue": "HiusaFXpThXpTSHTvQ1HBRjC3tGYCMsu5CTKQfMhn2jF", - "lpVault": "CanFLVbG6cTCP5PGBY8nzTmdGsg9X7BWnCF3kG5tdqPw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CDKmrcehmpabuYYRPtpHyvQ3PjTJBaaZAjyJJ8n5sRB", - "marketAuthority": "EBg5HrhkAb3Kx2b9DzvNdo86LAhHSFeW33ZPrzKymBin", - "marketBaseVault": "C4Twv1rp8CReaPtV5ibpyKEW5xVcc4ySUxW8im9U6Pcg", - "marketQuoteVault": "33ofLPfgX71TjFWn9Z4vgNys12h4JDW1BTRutrjsxEoj", - "marketBids": "GsgUwHB86ZSNERzFckNhfsRfC242fHfzGnLVnoRSTWEz", - "marketAsks": "EeEENy1pwuGsHce6ndZEaKSpbS3wENHg4J5cPfoT94yE", - "marketEventQueue": "A7Gc657pn2jehbjqMPnZLbPm9yyf2oLG61woBMxsAN1o" - }, - { - "id": "FWES3DcSKbPnHZdSgfNHHNMbQ3EErChmb7YXnZysefEh", - "baseMint": "3FoUAsGDbvTD6YZ4wVKJgTB76onJUKz7GPEBNiR5b8wc", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "EUEbkmgGYpreeRqXJGD9TbtM9Rwv4gxSrmSMN6AWy9Ry", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GKRVquSR6nDv8s6Rn7ZDBUM5R3LkFx5rEkVgVctgVXnb", - "targetOrders": "ArgdueudHHGCXBAU1fhQFD2Uda6z1Hd2pbKPsLA9rdwH", - "baseVault": "8QvLkRKPHZw1c5D6arQfUVviMnJjUa9cXNELGwxZ5J9y", - "quoteVault": "2DLRiQz63nfrctE6e2bZoVCEYxGMREEuyYUezK5NBKsm", - "withdrawQueue": "2DP8GiTYiq1q7y92isxwySYCkvAGWb1pB73HMn4owp2Z", - "lpVault": "FSLaiMGuDH3zxGcNQ3Q4b8eWDjX7XC61JYopwuGJmMDK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4ZdPGj1Qrb2TecESsopR8gTHAzTRKBCnweBhdSZsMeNX", - "marketAuthority": "9misVMLNuJervXo5ETxyWsFeayE77Sm4jw4o6aUL5VBb", - "marketBaseVault": "13GGJe2iT7htTq5fQ7nddrF3txiyhZMyJQBYyCvRJWg6", - "marketQuoteVault": "BAQ2Zg517Y6kZRjnaSxGpH6gwVDM3Ge1H13U2a74mUJ6", - "marketBids": "mAu3ee9ikG4YwXqvgkvDBVusY3D5d4uPNU1r6wZKGsm", - "marketAsks": "6pgUTwpG9dNkRaS9r4qMacq6uBghwLNnThDUyoAN7qQf", - "marketEventQueue": "4r6aNW6DGcpS1p6BrNtkyo1WpguF5TWcjy7Qe5MyqBbB" - }, - { - "id": "FWgm7aAM7rST1S7BusPctHXG24wdirbk6bQfLSjPcUgw", - "baseMint": "2maDvG9nXGVstjdnsCZoSsNtjoda1SsZTLrHBVRgLR5F", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2SXg6BLBNhQxYL1X55gVCrktmrqEjwru1ZTrRdTaF51q", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ExG8WdG1kpyELBdaz9EpVmu5XiKp9exoNjBNbLrS2WKW", - "targetOrders": "5Jk71fYBokuV7QEbK8opsn4zrx31bbEtJzQ1AmpPfhsM", - "baseVault": "9YhZA8vX6h2eC8xk6yLGkpT5QNvw3k3S1yyxuR9yBCs9", - "quoteVault": "G6qRCCSjKnT6bXz5yNRteUWSHkmKaBFG1hTXf5grSp4a", - "withdrawQueue": "FworFDbmFevARkgi6ZECnGh8iUWo8MFNkez7L4o2yr87", - "lpVault": "2QVg61rpLifDuJQeCzShJAmTSbhNvAPVKLNCUdxsE6DW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9AFTyrnz19kbXGRxtkazaVd3dBCkNLLsLMzDB85sPhdG", - "marketAuthority": "4YeN175YRiF6Fmbht5aKeojuB65AbxYBha585kmCuxgR", - "marketBaseVault": "8adzXnA4D1qjZjjnUNNhaobc4Z4YZqR5t3T3NpQH7w5e", - "marketQuoteVault": "6HZsP6L2H2qXcWRPW5d3RmVhhWFDcWuC25rRC6PVnbZ3", - "marketBids": "79yKBDPcDS9D2ZSL51SaRfedzVFmJD9GfPrma1NcrUCZ", - "marketAsks": "7AS1hQYxBARaK3SS8vGygGJG6e932j3E7CEUcbD6puwB", - "marketEventQueue": "3zmGn8uCJ13CM8aP7rHopfdMrxFt9v38exU3qnWfbBzd" - }, - { - "id": "FXHLVyWLa2hQbWAHTvHKP7PARg8Q3fStZnezpydnK28s", - "baseMint": "4qw5MNc9oLKS22hiFTK6TNBHCqegDK3qzhMDgawtwnUL", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Gs3NDc5xp7XRXcKQ9pkthfqrw2MaphXVR57D9ccnidCD", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2B9rxmLkdbSASL3ZfBFX1LPC2mkvpQbwKrPRfJHmN1Q8", - "targetOrders": "CA3sdj38fUtNX9skiUoJVzciBLgXnsigC2GHjRCETY6f", - "baseVault": "ok7tUD5nxubhXm842vtpFsYp1Rzhvd59HmZ9vRPgLVC", - "quoteVault": "DyeKYAWC9CdMSP1MAVsHSteFEY8QSkSRs6uZqRvJesC9", - "withdrawQueue": "C6oQFJ5x8cYu8jg3t95FD7vyTRb9VdfBT7jDVkb1nssX", - "lpVault": "AhY5aiYpmtqSEuSXL1WFp8G6oCJmGCKw3KffCnncHSL3", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Hk5YjGvA5J1sAXQ95SyojgTBXY6NGM8AiaDahETNf8Pe", - "marketAuthority": "BAE9oSfib8b6v1kizeoZpfuqPVqxfPVw4ZcSqtRLJEub", - "marketBaseVault": "9JEGFQSByBJLW8JSxBACKfuhRRwRS6ttwa9PwH5whric", - "marketQuoteVault": "CrAUk779VwzAHgFPWJnY7y8FrPcbhSz5sdQgBqEdGNPe", - "marketBids": "Fyo4HuonkszEz3yuVZAGFtZXp43H7up9psdnws5vLxgo", - "marketAsks": "HCd3jQfDpeJ1drdmBXdxB3Gz8p75qE7FqEBt2W39LYV7", - "marketEventQueue": "EhoEV5AGs71bCGELQfCJcGMezQdjehMEuHc3ngytS5VV" - }, - { - "id": "Fxr5erjtHDrE1FhSfNWhVMf8b9G6F8KeFHMvW8Fixqbe", - "baseMint": "A9UhP1xfQHWUhSd54NgKPub2XB3ZuQMdPEvf9aMTHxGT", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "2Lro7YN3J2UapDuW3G2ux7RQm7T3iArh9edr6zdUzkE1", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9BLhyiBU3zf1VvEZh8Dfh1ufvi3xbdvzzp3oC1T6maN3", - "targetOrders": "DXF9HugC9pSYX5JGBe11phFrCuy5wLZpsjRQPXaZpuH7", - "baseVault": "B1AXt27kNPsfWxUV7gT9fHqS8oyXLU44Z5qTiH94FQbL", - "quoteVault": "HSRMdRGtnLAzQtPDuFmbAvtxzbFg5gMjBfaKYDw1hr5g", - "withdrawQueue": "EVgz7LazkKwUKPfU2gu9coG2phgio5whmWTrpMf6QpT3", - "lpVault": "CM32ucaV3Kz6XMwXoFrfm9SkjQ4oyZgtv5FBPTTX2q88", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2SYEhWKQd7fUt4x18vNnQiLasG1EPAisFyXMDwkSjkKR", - "marketAuthority": "26FfdqVWUuvTafqkgnc1YHGs8PacZfA1YYFZwRmNJSv6", - "marketBaseVault": "HTtdkefntAe9LQnwuHQU4sFjpWA7GA1XYPNUFiuSSpvf", - "marketQuoteVault": "4XEN3a8opq2KZdA66PV4QfHyRQbbd5jBG2i9eV7NYvN4", - "marketBids": "CuowyZBXaMY3h72291yxwHQRei43TW5Wss3QHHeXm15r", - "marketAsks": "C8UWCd91LEcEU1FcL59rkbBaTvvh1dWStKWH368Rn614", - "marketEventQueue": "4gGEYL86K196CxkK4J7iTmkH77uzTJ4MasBQjTinBo4R" - }, - { - "id": "FxrvZ95LZ1MyWmSRz1P4XbrjtJp95xthj4SwdrbDXUfb", - "baseMint": "3FoUAsGDbvTD6YZ4wVKJgTB76onJUKz7GPEBNiR5b8wc", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "oMj5c7gAEnwysNmFyfZfKyMs2rsFdV2FXuCuGxW3W6R", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ESUZs38n26Xbykf4pDHALpgHkGgVFiURHiNguLFj539K", - "targetOrders": "F5Hw3PTfPtd8BXtqzpdQa4FNbRS2a3TTxX6qHwk9X6hr", - "baseVault": "5BR3cP9vD5QrgWJSMqjXHNfq1fpe9VheuTuUCdv3tDq1", - "quoteVault": "HxWHVKhpw4GuDq8SGkUBbCWedzMW4EKe2FR3r1s5bwzZ", - "withdrawQueue": "FAratcCwRs5a46RsErhBUWbqfoaJhu1ctECEXzzMqFkJ", - "lpVault": "4Zz3uz7J2yGvtSPwP4HUWzaSyK8kQDbQZ6RYQQcp7ZoY", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5WVBCaUPZF4HP3io9Z56N71cPMJt8qh3c4ZwSjRDeuut", - "marketAuthority": "BCmUEpZm9t1Q7ZJpADJgi3qwaSiQyeWqvVPhy3MdmKj7", - "marketBaseVault": "Go4BzzEPsDYhyVbrkL15NfKwGHoc29PgD7z1gHoCQAdW", - "marketQuoteVault": "6uB47XDXVYQ7FCEDoNJZHxfGfDx2hy4725NsRy15sPZt", - "marketBids": "5L4kN8zdsgbtgkzCG4MnXiUVtj1dGLbbjkxyjxJnCxM7", - "marketAsks": "H9DJofZDdV3j6g9WLwysu3a4JqtJnvu5s1bxwyKvBv4r", - "marketEventQueue": "nWVsgQFWWLukYVpScb6yhd26kyytwWtin41qzD1wi6T" - }, - { - "id": "Fxux2kxvyZiy82yTSgzrUYVwSdrkuGeULvvdyxabeqb7", - "baseMint": "3GV69Lop3xdgDwti1Drta68VG2VVoUZqSBtgux5fkuvw", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BttkeyNM1K3u3dyCvf37BK3fJn7z47vtdnddTtRqi41W", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "rpqktwRsKAfoZ4VgyLrM1QChi3N6CqAuysw611RBaeT", - "targetOrders": "J7qiS2PnXUy62qi2uoTvjYhXDJapDaiQuXVqbUdKGEdW", - "baseVault": "B6sQTuKLWF2vPUnAyRKQfPCorSyrR46r5Yf4KoWE1oPJ", - "quoteVault": "6k4jMYhQEHMMwQ8D5NzYxkqvSVp8QP2PZ2wuoEZgwGVz", - "withdrawQueue": "4A5zUqkxMRsMWkHZWA7GaPv9zfeLfJ67PFmD5iygBNHr", - "lpVault": "Dj2buLCSudgQmFRwDc93dPaVXgedj1jLZp7iQ9iqT6QP", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "54geVWE4EaEWvAUuqRS5D9KfdRrJdUFc9SXRctwMZPq7", - "marketAuthority": "EkVJx67wZKqnXEkTcE9iV7sTieSzUduVZyJXHtiVSWDB", - "marketBaseVault": "9xdvgveDdrw7h3iVHrrr5sZz8VqGRtoSxCQSFrvcamdh", - "marketQuoteVault": "BmemTN5VqtveScmbwAFwvPLz6isZzh5Pmt7a6QD9oL9k", - "marketBids": "Gk59B6cg3ezGA715R393JoFDELxcuWDVEhQrrfqdoHFG", - "marketAsks": "GiceTaB1MpiqN8CnwK8sBijE1sCAWxoscZzqn2EJkUDP", - "marketEventQueue": "5HerwDwuHADwxHZRiASWwcE9uVVMSbumqaAojADKfXkn" - }, - { - "id": "FycsiddveG29cp7KrBNqQiYS1byTEXy7RVf7uGW6GdHE", - "baseMint": "q4bpaRKw3fJB1AJBeeBaKv3TjYzWsmntLgnSB275YUb", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GXXZEvfceQdkaJmCFanQF4TmrQ2yD3MTAvUBqNCLdM7", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AHBQJ8e9BtE8JzDPHDRvqx175R7dEg8DUC3QrPUzQF3N", - "targetOrders": "5VRJ9EJ8quKExFevXME74y4f44SUTrsTRqUSp6Vmnnra", - "baseVault": "4ueqwHPXZCo6DDKFfLTtNoqg9Da7DGTzVgJDdTSH5mJh", - "quoteVault": "7eREgzJWQNiYW8cece8yBgp2WrZNEaYG49PdYJkw4Zck", - "withdrawQueue": "DwaCJdTpovNAPo8gGLKG2eZcq34B4VBAhEL1monpfDEg", - "lpVault": "9bWCjhxSR8HcciaXhuWbZMpiY5x8v189PiCy8pxj3mTP", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2dKHkfJGKNxmtwdLcsqXFGcb8Xppw5RP6YVWEWjSfAHm", - "marketAuthority": "5MfUQENDWJcK51CHufXiXmfVPWeG6ShBqWUVpHHAMajd", - "marketBaseVault": "Gc1EBNUQYi5ksiE9ks9wFUEpRnPVocBvTPngmcqwAt1", - "marketQuoteVault": "SSytjVTaMjh5xvbBYZK9juxov41C5BYSFmEUiLX2Bfa", - "marketBids": "GsrEsUjSYkKxaUFS8sn8RSd25X615J8Nes6zxLLZc4J8", - "marketAsks": "3VSd26oRsushagUaWYmaEfDJYCBh5sFWwweqnuXSxn4U", - "marketEventQueue": "EXiMVtv3QXB5nxawK7z5oP2R3PEorLHhEDgiqN6a7ZDD" - }, - { - "id": "FyfdVvHxLhQcUfMHqEppnQJj5Rq7q56D1tV8sZNkqNNj", - "baseMint": "2cW8Yosn4tSYJYjfUkcpKnYBSMYDqXfJmQXVu4RJzBTw", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "BHcsEZPEZeE8ugvppVU4LWgJvuxsGWRS7JiiWHTA9Nao", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BfHa2yofsxRkz4n7GmGZ2eBrPrkycubUFRsQNQ9zodoG", - "targetOrders": "GCm3oHM3vjEyUUTU6HCXEtLcjTR4zPHRkaGu94p7qzWN", - "baseVault": "2CN19MvuegUxUX9RgRRG6LgfdDJQX2dSRo9xbbpRf26J", - "quoteVault": "BgCjgVLEbCEzRQyA74YWgK4trVuLcw8GyLFkGH3s7Tb5", - "withdrawQueue": "8QMjVb6XJeQEmqRMpKbRozKPFTNcpgFxdZaEtMPR7Pwx", - "lpVault": "HGndXKdgxZiortXa3vyfxDKe8f6eYTNwZcsnZCERNzaX", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "B2zke1dpYhecE4bWMQPPaoPMmXk7sfoEz5FpD2tYL2S3", - "marketAuthority": "wbZioWo4nonV4CAFxDHRwyo2HLySNLcq4F4rtVPceW3", - "marketBaseVault": "A8taFddSi8BG7RhMr5R8zGGEw4Nd2rPuktkEoDGX1FoN", - "marketQuoteVault": "EuedYj97sGqkmmC1GgnLMQ11NZGrkPeV7eGAt1VMpTEt", - "marketBids": "356VU8MHxTeZkfCHL6y7RMEaSkpqcTwoTXMKn9UZH6QW", - "marketAsks": "52F4mYgK5znM8rRNoFZnpX9BviDNQYcJvCdFS9JCfYYk", - "marketEventQueue": "4ZxqUt3oQAqcD4HYBL3Mdnemu8hEQRcnjD8kiYGh4aSD" - }, - { - "id": "FyqYBBJ8vhr5AtDZiyJue4Khx9Be6Xijx5nm6aL6wZZV", - "baseMint": "So11111111111111111111111111111111111111112", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FENcVvze9uZzfCbffXzPKcmYo6s2PqjpFusmXcAjPd6C", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2if3HMMqGZAKeETqAbPCxhy5obdhs2BbiMTqkGLQhRqw", - "targetOrders": "6YJqaJqVSMdcSdojokf8cwwpnQpdTGoGiWu2oYeCJMJ8", - "baseVault": "79uBcM1XJWY7NT1UfydKH2jM7nepWSidJA2Khf3jfwm9", - "quoteVault": "8KKZ4LR5Q1T1SVQ2DaCfZ83NHr56152A5NMhDDVCCdVt", - "withdrawQueue": "AB1zhHYSPYiDez5RHRzAVJRZV3cUyzVXKeDM5xpM2ZL3", - "lpVault": "3hybggn3TEDnfETjWtsmcGRHKaSyd56VKMV5LZhbMK4P", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3xGWh76WXVvxMWearhJJYtuN1NazD4eEaafAAnWXL757", - "marketAuthority": "8BJwHZek2AmYVrsomc82aSAtod4r99fVhf3L5b8AtSrb", - "marketBaseVault": "9JQsP7B8L4KiSakVDaWcDuSofUKnRweRchEnFNX8CvaB", - "marketQuoteVault": "2jT8622k6RyXkgJFvLmm7xoTrdLac9Aa6rZKP46w7E87", - "marketBids": "2UxFySzJ4TZ2UCmKj1jtTpBTXxYxzUkWYHo31MqJh1ac", - "marketAsks": "H8b5qP1JSP7XAwMDpx1ptGz66Tf21xQWhTHsKmMV7jPu", - "marketEventQueue": "7k6y9jPsmXRiK53q7hKmiLThxFt61HAuYS46vxXi9uji" - }, - { - "id": "FYrwkfPHWpHmr2w293QQpjGVXEvEk2SfmBsT6JAAcrjU", - "baseMint": "GEYrotdkRitGUK5UMv3aMttEhVAZLhRJMcG82zKYsaWB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5bei6MYoEom6LsX4roZzSU9ieRJSeuCLYE4sViTeTdHV", - "baseDecimals": 3, - "quoteDecimals": 6, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4PvgiN3ZkkXSGBVUAR2ovy7X6g5K848HXT199DKKXFrB", - "targetOrders": "GfnPb1BveCcdEG84uFidpSjdwhXipLRzQBpsEGR3fNCD", - "baseVault": "ABhvmHBabV2538tc3rkffhgrYgRDZhTndMaqmmwbECFu", - "quoteVault": "8oaPBHi5Ti1tsMsk1MAcZaRu3xTwXv2BAtpcWTaRYTmL", - "withdrawQueue": "47yrhvRKUhdLS8HewKayTCMGARveA6ZNpiN3DYRBCKLZ", - "lpVault": "4XY682r4WmjegdzbgZ6DBfViiAPxqKYUihY6QwA6yFsw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6dn7tgTHe5rZEAscMWWY3xmPGVEKVkM9s7YRV11z399z", - "marketAuthority": "9VSPvUatnzn791vxPcAgdMewD9MwGkGAPXfT4YmnMTT8", - "marketBaseVault": "APF2x2zyyJegwSbURhJ4sYr84MpN4UhEjcPuux12yWoZ", - "marketQuoteVault": "6vfGHr2SgmkN7Pdb8McenvD8eqCuSqpVwfUJeaN3xcQy", - "marketBids": "7Y6spr633BwXXgvVCdr3Fq2Efjk6oFnr134fibavEBhi", - "marketAsks": "Doe1xVtLGsNVH5dNQww9VdLiVtimy6fFp54fJWBLq5E4", - "marketEventQueue": "JABBTRyvqbNP4qnHxpARL7mehfucAGNYXW1FSQYcihMM" - }, - { - "id": "FYyFi9XjYYKRfo48WCJCbeWfx7GNpi7R672zD7ivbsZd", - "baseMint": "5hw5B7TpiQUAXMsiy6XXJm6XZt65c8cDu4XCZ6NxQebS", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "B2xAP9pSeieyi3RyNgFLKheeWVwC43YohDrzfT9D5TEH", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6iLy77dwLv2kFFT64ARDNvYiWXxAmTDZZZz1d8cW1eBM", - "targetOrders": "5w9QzyKeRGq631hQsCWLmmpRDRpbKwXUw4feNmm2GSCA", - "baseVault": "Cg8RajUB8aUSHHmYZirnZY3ciVoUZrTyZj8bUzJoruwa", - "quoteVault": "5PChn4n3MAXoyrTH8CcWjqscxpfEPA4KL1hFTVqfXs7r", - "withdrawQueue": "7Bi3PzX6f8ndzprvLQVpKExayzCK36ZAeavhz7CktyFu", - "lpVault": "AComw7QE5hPkYD5vS9dLNxhy3hKY8Hs8FeuhLfCz6n65", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8HRCZyH8giVf8V3c62oqQoJgPzVQ5S4jRJuzjut2Nvep", - "marketAuthority": "9b3h1GJYGGSyHPBtRQ7TkoB5NhMGe1w2Db1TVTrRk7Qv", - "marketBaseVault": "HZjBrNVwm3J5aZLxhq4n5Y2B4LdGma4xUtfeKK5VfqeP", - "marketQuoteVault": "EMJ1eRdnSScmhTJntNik2JFHJBce6pnxCFk1uEcPdT9C", - "marketBids": "2pdfJxyb11H5grw48JdRxai9TyuEPBZViowUUDWWQaSz", - "marketAsks": "DXgBq8izEQr4Yxx4n2EQNbZ7HLzCrxpDCPrET6AD66kY", - "marketEventQueue": "2tDBqo3Xmd9sci15vkfcowvaBY4muB9CpVSKvditoXUp" - }, - { - "id": "FZ9mjZPK2ZgAnVPEPDcf21DNSYtcWkmz8AcrPHNSeZ6e", - "baseMint": "BAJGAqB6d5BNV1ewDHTvtitYDD44nVp6Hb3jmqGUJ6r", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "8JyEjcgAusGDq7GCWh4eFhn6oAJRRd6ihCQNCKfPn5gS", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7GeBM3LeUD9WcRTKjEBk8UEuDJ5Y9meyBjwY3Zd7kQYb", - "targetOrders": "3SR8ks763A4CZKipPjvvE5BQMjLBZK2fBJu33rUBSaEn", - "baseVault": "CRYPozua31CdkYDoFBDmGjZERyo2Mkcg5BgdX5JZxBQc", - "quoteVault": "5crkWA6T7kZLypdEbGyRXNHq24aA8EVpHVTcBHH2MXPh", - "withdrawQueue": "BavTYjRp99wnzVX3a7eYy8iiXbxnYapfJfAsv3PazZFA", - "lpVault": "BrirvfVVJ837E2PRLjwgrQytH8DLUwvBPNmZKfLiyQ5F", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9QvkC9VxjXuXC6VYM8w2aY51WxdJdv688WEE6BCXuAZc", - "marketAuthority": "CXtNgte8psm6FGq3yUmWoeNoV4ew3XnutDwo1m1xXz1B", - "marketBaseVault": "HjQdw2HRk9WCkzoaRi7Z73KGpghh5iMNFAcUsyV2kQoi", - "marketQuoteVault": "DR3boQVkwiRyxLX6CqrJFNPhprqxfCQGrEj9Y6FhdiFT", - "marketBids": "96RRXTQhPmjxwBi7H9AG2eVKWX2yvxiqNGYdw6HkxrFq", - "marketAsks": "AQtFH3jBZtCazv5hdX6NPnXBU4SHFdL3KKBUUimFVKht", - "marketEventQueue": "8s2wn5yNRw1ug4bK9CT1wLbW1fiErX3va7PqmDJbhedy" - }, - { - "id": "FzQPt5mrLfHQoZiTbqdyd9EjiJE5986X7mJ52g57Zw8c", - "baseMint": "6CEH3RdzsubHF94fRuU7DWGNh5XpatXmu6jqJnh7kqfM", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7Dni6sanURg8GiUyr3QvVnJf7fdkqSzg9XQd6aL8Aj9x", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "JBMRVrpo8B3XzawBAEmQQ1ExG9kFwG49gt5sQHw1AYLP", - "targetOrders": "AqdF1rNK9XsJegsQcNFgvVAwX1uKKEdrut7ZS94SZ8Jm", - "baseVault": "HNPuK9oMhVXGnBGwnaT5eq93iLK3f4PiNHXDoewj9r8x", - "quoteVault": "8qVLUYZjuyw3vpa5NFrhGmJnRALdQTCHvuUnEEbavnrn", - "withdrawQueue": "8cvvc58FXYzKycUe9S89wvKUnN2W4Ew7ynfhembEDgN1", - "lpVault": "DCBFPJRTExSQvfFp4G9SuRKw98p4bdRbozKNHj8Y1b8V", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6ktzCgXgrDpCYf4kfirhzKskgkufLEr7PawQGrLsXvP5", - "marketAuthority": "4aK8cBkPafqn8WrgYEMYRa17v9LjP4axYAw7zVoH4zw6", - "marketBaseVault": "CxcD9VxKUSEubSrANzUBDh7687Kp63pxA14DCEo3haTM", - "marketQuoteVault": "Af5xNYM2bJJrQ4Znwme3TkEwR3zExVCYrkdMCa1inkfj", - "marketBids": "Gxckf9Tj2mmRa6qSCZDhiGQKpVqSx17dgJejwFprAYi7", - "marketAsks": "FwYnnGuNpxiMF2CQVgVZHZw1jCA5bjBmPjAk9D7Z2F3Q", - "marketEventQueue": "B3cQRVToXNWHGuru9dbPAF6kudDDqHCp3t9tHzUHpH7v" - }, - { - "id": "G11kKBcFhVMhfQqCH95sHeMeiV4AQDVNgwSQvMU23yL1", - "baseMint": "6MpQesMjehBwJzgDRDsbUXqjHetf1LGE94H7FDzRVL9Y", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9pLb4AfqF8R28uKJGXzkxxmejTwkpoeEKuQwPFcCoELF", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DpTcooGvpKZrZdKSCBpzPKxYS6NLji4FSbKT3jZ84wCY", - "targetOrders": "9kt9JRCnXovB4g62ff8DeC8AsmmYbqvPaiGBnWPts6Rr", - "baseVault": "44CkMetXG5hqSmToE3CsB1knZzSXKnmZmw2joMkjiAbY", - "quoteVault": "AFUMUVY8koP7eSMU6G2vo2q8LT5F5T4qvCDM2tW5cL5R", - "withdrawQueue": "J35o8RHxAzKbMdbp9X26adchLqqjJCShrYFdnK86YqNP", - "lpVault": "EDhypkjargxoT2FQmMUrgwavZ5mxWaH8mZc8m8HXHWrp", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HKYrwWJEhv7yTKFtraNtMWptirAPHsriMVDuUYiGgC4v", - "marketAuthority": "9m3inJAwkHFAKmgB3Fe1D4PpWpBui6p7KV3e8eXBp5Mp", - "marketBaseVault": "8xND7pksmCSGH5acLnpRwEvbtZhEJ8ahfyNZBKAqjeM7", - "marketQuoteVault": "9D3zLzmfUFjRuG5bLcpx7N4H8whe36Q4StmDPXnZZQz6", - "marketBids": "Cy6iMnT8KJn4Et6VQ8vCHCnHZ9BMUL8CZuGuGpYR1crn", - "marketAsks": "DTnUd7B3oYSErySWKqx3a1rAsRZUur6EN2RaLEQdguHo", - "marketEventQueue": "DdNjpaevnL7jeuz9SqDy8ew1NFrEhgRfmnV6aT6wgdS4" - }, - { - "id": "G1w9dP9jEKmpK5XA8jXY236vTr8ptMU9pSv9TV89E1is", - "baseMint": "6ercxSiDn2KJ8KZxmCT4eheQqAWN3z17s8eLT3VECuda", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8JnmXSuQfEWZvsnXHXf1Z2FUHbynKEUFXi7Cb2qkJ8Yu", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "92pb8nbwj6M3Ke6HvSNkivkecdPydP7YUJyNBNh28iLP", - "targetOrders": "EE7zzLmJhS1mYX7J8tmMASMLoKep76qc4a83BGB9NCj", - "baseVault": "4m96u5FBggJUUdmrp3hnV7c72PsebyJrZVs9EhmEqx4V", - "quoteVault": "5d1qtDfye8zi763YeFf2hrz32hNaFjz2oP9ztGUodJKd", - "withdrawQueue": "577YiN4HsoYgvm5RmRFdHCsbERem8YqCiWiWkuwNGQ1N", - "lpVault": "4jymGhdVn9WZbqDpPWUgwmG81jd7zMVdWzfwZXaEj1EB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CbT2sJocwpHZKu4HPgaipRyQ6fEffPrNEfvcrVML4jes", - "marketAuthority": "7bcb2NnrF4qSMFSgDvSreM3FwJZpaH5B1WvqAWmfeT9P", - "marketBaseVault": "FuceGb5mjEtNdx9z2cLeMjvFrodDBoU1hmwKnxmDAAit", - "marketQuoteVault": "DsVScEvPkEJPpEhdBf2x2zvTPjAnNgd2QgM6ZeUXu1ro", - "marketBids": "34wqkB6UB95uEaxTBSAQkDLYb1PS2uEJ7toVk94rPo96", - "marketAsks": "5LtTE4vJjmG5zwbhWqf43hJC375yfeVAqoppuMYSmG2Q", - "marketEventQueue": "GzBGEr8bxdFHbsLF9N7A5BYhsmz4rgFzyDQYWqEzyAL6" - }, - { - "id": "G2NbZKxy8AoVPEmU716x4BL8XHbTBWYaozJUduZcKiCm", - "baseMint": "DcPJa3gcEs6tyRUrGpt6sxJvNBu2GffKcGGXuwJeLr2Y", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "HmxeUNRPVrwmSS1mzjPXiXcYPAgPE61FaazzUw8EcJd6", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BmqejeMUpyHidNkdZAUk1bhuxRPf97GsoeLU2W1q3Sjy", - "targetOrders": "53kBrK1Mn3iV8wqqrcvYi1a8ZuKEghxLpVqyS3xmCDPY", - "baseVault": "5TGEkaaQf4WSHq7TUDPY1zSijMoHj6pguZ8MPUUcFTvv", - "quoteVault": "DtEPBuqxB9S9qZ89YvRrZnycgLKeRTcBXn2wgKCRbHcf", - "withdrawQueue": "C4JWKYFpvjcvqSbfKEPMU26fNNY78DxkRzknRJ36Xway", - "lpVault": "9HTT7x7huP4cEfJDkskry5Qksrha3BHjedMZSucqaU2z", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7yQuW4JkkhknH7p8AQ92Q87x8qdw1dY8CLVVF9Ljbkit", - "marketAuthority": "HbnKWxUuaiqQ8FZNSH1LPCaA2jCr43fnx31YqWUgny9w", - "marketBaseVault": "ARxBf2rSCpEGEBekQ5co5ddYjRGwtoLBSgiMqdYixhzd", - "marketQuoteVault": "3pidzZCidGJfMtL85Weq1DXX8msRrPJpXmBBUjtFUkvY", - "marketBids": "DDt9gvUp66qySE3nUUTcuts3fncYUJGayypKWW7EEdQ3", - "marketAsks": "AnembQHydKZbcu5zt23Ekxg6e9zffNCccgKmFCsHT41t", - "marketEventQueue": "DAbSJciQoYMVfXoUw9furkCtZH6DmJFJS8hbZaT8zdq2" - }, - { - "id": "G35AznHgpdRyX8QH8UikSeyoy9RZ9D6Q5JWhYJi1sL9n", - "baseMint": "BgsAQ1sXFyvW8iftJruXi1WcrHrNquhGyC2zAPqjUDAN", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "7KXVHHmZycNGrvZPU85msBsDA5qWFFXoWGRqJNU9GbyC", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3j8ty4fomPTzGi9cmbSnXHCrUd8ZvVS8MGrQdAYfG2Qt", - "targetOrders": "Awctv5tFsBj2TLALwdVrQ7iHbqQQuFpLFGsyEUVReCvk", - "baseVault": "35aR4CvjXxK7oSKbP2WPrgJFQUBDcPVoHV7EFgu3VRib", - "quoteVault": "9ZLJD3qhUsrX1ccqGNiUmgdoW1HmmKNmh1T841N3wrwy", - "withdrawQueue": "EopBNHcwiBp3vmAPez84abVMMAucZq25CpPu7SYvfuPN", - "lpVault": "fVP8K9z45bz3putnpptc33GuzAtEKxLP6TCCGBdt1aY", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Ez57njYjSvheHY3guaqtrkbVEwNeLuya5FnTUTZRgjXG", - "marketAuthority": "25RVnFz5gHHaDpos1WtGZw4eeeRgNcXke1jrQS3hwNEM", - "marketBaseVault": "7SqAcBneAWpdPj3HyQikTKWtETB7p44XSRH3u7fn38DG", - "marketQuoteVault": "4TkxhFuXn5spM5ViNniJfvRSyqJyDLkykdShyEk7d74s", - "marketBids": "DKTbSocY1rJZ2oQzLH2JFuMsPcpApr7yHPd36P1JsNmA", - "marketAsks": "BmKvErNZ6R75rCLEUMBxxKWFfpWBmstDEsvGoMusPb6o", - "marketEventQueue": "FQYBMLqaaD4Pd61wQa3NCvtPwXzvz5HMgDh8Sgurs4La" - }, - { - "id": "G3YAXm2Awq2eTuURSB4R3xnpnHjWmNzpdPY5UJXyMREW", - "baseMint": "CUvVMqXAcyFJnwMhojQ9jmGuWrijGt26HfY7b99dyBeB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4nRbkjmxNgEBjty9b2fTFT9JdW229XhKSEwL7KQDFWoR", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CiqykvFe6bgzEjQZiqFeWKzbJAygTRwV1Kba12gYSUjJ", - "targetOrders": "Cn6BZeLYa8QUeW8iycEeWuHTiK6AyqJi17s41i5J1hDT", - "baseVault": "EWzy8DA9DTFHmXnqA7JHdXJ5N3sJVuNPskaZEuatuMRf", - "quoteVault": "J5pE5rVj3uFassvQjcXfDrJUTEvFrbcv3yqdBHyEZz9n", - "withdrawQueue": "qMZQcoqzDgfyiBo9wZFgUABPrT6nJwaPJKkL9BBJL4w", - "lpVault": "7NX6E6WRyzry7YFbnMgxsLrP1YjmDPJLhfjKyVN1F76X", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AaSufn2uNb8jV6wbFWAejhgMyEctK2H1x1yvF9dMGJ61", - "marketAuthority": "BhZQXk8NAgqXyi4QfZq9DTaJer1Nf4tAeeYvBjvBacEQ", - "marketBaseVault": "E1F58URbfC9EDSdPHuAZ3pjPNzynW8yXhS63KpNy8SsY", - "marketQuoteVault": "Eua5dLCoEo17iLrRToS9amLH5uAM3eE5JkY11utep6Rm", - "marketBids": "GkF251BqWC8cE5CsGWYKpdNWcTpQka6mFksudsWu6W82", - "marketAsks": "57M8HTHtcZnUMMQyVFuronvr9PzvktYvSJcT6J7EYr1N", - "marketEventQueue": "8Ybf29Pj9DTFJaNaP2G5phCssiHwvbQ4Lr8NkuapZEQC" - }, - { - "id": "G3Yx6Bay6NWrpWjh8bSTRAEYW84Ff7WE81QmJP3JsBjd", - "baseMint": "GjdreVe7iUG4hyESSweGyFzgekWufhEwGJqAaa1hr7pf", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3NfjjU6kMFE5waJZdUt8ZYjYJ8ZZt5Ar4njvoJgnNtnh", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EYXA8APcyjRfZ56hN3hoKstmQfTS4zRwHcPtvygtktmM", - "targetOrders": "DovEL5965WVVWFYQCBmzecozvmkJpjQ4KJZHsJBeWYUc", - "baseVault": "FP6m7dkGp3DVvDXr2kqigyHpa8svNPiKn7kxs6myUqVA", - "quoteVault": "3LNk2uT58Mduzr5ZJYu3MBLnwCsJ9HfMncRKZjyrTE2s", - "withdrawQueue": "37o4zU6hK1rsujS7dZVUHmnxpjRRThDSgpwS6cBCFWMv", - "lpVault": "Am2ixsn1GisYFgvDeNApbfnDg8Ak1LniJAQ9pjGWcQHr", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HD71QHCobxriz3cMKjcsvLA896AS742WmEEQ8fZPuQFh", - "marketAuthority": "2mRAMxkCST7MTSBAMfNUc3fPnUW1YJQfero6P92ZM6ZF", - "marketBaseVault": "4fsbNzXJzJanHTcL2iFqciuSjvdqX6TAMevhK1SxGW5T", - "marketQuoteVault": "9sSWxXoVKjrGA4fHadqektjcAsj62NZdiCwGyF7zsAnz", - "marketBids": "HxwRB6WxzJUpbtAp6NT9DPAACQgcPddctT4kWVVHLy8b", - "marketAsks": "DMP6o4Bm3r3FYjQAX6GZWYHWhAsesJsfEr9EaPxjiHc", - "marketEventQueue": "CLKfBEGfaM7z8PJCtr57jauXB3txURmsgZzSFPrYDoXj" - }, - { - "id": "G4Bjsy5oYVQifvf8pRteX7Lk8YMe9EKf6BRhwGiCK76B", - "baseMint": "HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p", - "quoteMint": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "lpMint": "7vff6hQtbAC8v2i7mAGqK1HLQs9DWJ6A7GHsbovzxCNr", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Hukwk3eX2L2rDmaThLz6ihiowtnzCNs3Uerxe41ZBe4A", - "targetOrders": "2Ug2MkExgGmUa9CqMVGEucz1XYmizitXp5r4pJRoebyx", - "baseVault": "3XcFG7j5YymVHJ2ntEvbKgY3hTfY4nazSKNYQmUkJDVJ", - "quoteVault": "HdXRvcchDKhQ4eevXD13gzygt45AmRDhy2rHBGVnDd6v", - "withdrawQueue": "ACHw7iohzzmZXKMM2gvAm5E5vZwhwUNBbPsrT4NH4uDz", - "lpVault": "BV9yKVyfp3YxLR5ec63LvBzWsDqt8N5ScS994UNUE5LE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DZWSgCDNK2KhHKctAHG7AtUpsUPH6JtMwCsd6jHBJXib", - "marketAuthority": "3T2NeZ5TapimEWXC4Vx6hQXduBeH3myCoxZhnG7ZQpJ3", - "marketBaseVault": "CqNXBsZkFxXhwjnJGdREsTAV3TgoqdghyW3iYwzMDJAh", - "marketQuoteVault": "9N6K9DTMvbF9mkHFqWTQ9y3XnqRrSEZn15QYibKHiS6i", - "marketBids": "8rxjMvFyfwF1softN4rB66EFN8EPXQtskUBZ9UjuPd4E", - "marketAsks": "J25z39PaC7eE1SRRv3goQWvF9qvZuxvv4eFeiiYAnJPp", - "marketEventQueue": "HDjFYPWpgqLcSbtBJ4q4y9Gazpn8R1PU89UbZZezbchu" - }, - { - "id": "G4JUYQwa7MTDaUWxHDQhBncQTNXZEYuBgKKyYpY15TDA", - "baseMint": "Hg35Vd8K3BS2pLB3xwC2WqQV8pmpCm3oNRGYP1PEpmCM", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "BfrQvUX4Fpa6Jm7vikZ8cKtbGKA4T5AEi3FtpeAhonxM", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5hpYy9KBCQuUyodBQagM88RwPmN8xiffNmQsJqWwn6YG", - "targetOrders": "5HAzXvHojDLMyv6WDUPz6U9Q5jmKkggUnjAvMvwngQjV", - "baseVault": "2E4eKaah5cscXs5RaZtZ5p38zBo3KBGy4DXKroD9Ydao", - "quoteVault": "Dj3bV23NV3QBg14Zyo17NdjkE5Zqjm8TjT8ahi9c2EKm", - "withdrawQueue": "3NcoLHhwvdmjgqEGhpt9UKo4NAMW7TtkmzY2C5Cbv56k", - "lpVault": "BuPvPET7G7KLmoi3wWVqjKAPqHxhPkc18jGgvPWwuSmU", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FLie6t9RTJH47ypSLAFTruBb1KiKQjU1KGKt8cobwRbK", - "marketAuthority": "FnjkYHXx7PsfXmhSCisjhDLKAbCe2C7c7YJMGBGCZ4nv", - "marketBaseVault": "9Q7EJrQn73jmv2ePLpfKeaRnUGhDrpF2spCAnpRo9h5i", - "marketQuoteVault": "3ER9HbP2oKG4oJKZDm8SEGXFQXvxCnd7qdv27vGx1eze", - "marketBids": "Hfwwr3gSAkDvpydk7NekS2w3SZ2RwgH26c8S2PUPLMei", - "marketAsks": "2WLksUTPy1cyVRjAZXYytDiPvg3qBBgaEA1JamPS86rE", - "marketEventQueue": "7YNCjsRYr8KCvR2K9ry2V9pduBhWLCRdo76NgHZVBfii" - }, - { - "id": "G4m1mm9kMopWxFhkfiUhstXLwyERVZbvvr8F2vPEMr3J", - "baseMint": "7s7PKr3qhuvZjngR1Zmsy53tFLLhZA4aoMnzeE8Z2H5Z", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FeqmtUsh6Zp5R7XHaxQB4fQAMejUfNVjHhtZ4wR94kqw", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CKeQZZqDyS2awcaCDrN21BacbM8WnraWEwE8h29siJxH", - "targetOrders": "AeZRkUX4UHVe74BFu9384rmbZYZ8YzoPMTsDY2ixX5CA", - "baseVault": "9bHmLQv6D5vQTpgE556th2u7Dh8YW7J7ZqcsJA6rUbDm", - "quoteVault": "Gb7YMDtggEYDH8kbgHEn4MFywgnWmEanXrqTr6xEDDxG", - "withdrawQueue": "87EAu7k1GQUz8QQ7qs6cpL433MyK7ABLtEbackuYJ3dq", - "lpVault": "GDFZznCdMN9dUv8zieiMRcLg8K5R7eh5ZFMWE2ZmDggD", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5W4wWmXRVrrAzXXVNUHuYFHvWL8ohM2ZQat9WEgXkMsW", - "marketAuthority": "BT3orB81hCU4gPQk4aE3d9wNY8yaPUuC2FZMoshkuCr4", - "marketBaseVault": "57oLET7fzj45qKXQk3JB8jTYvjPVis6JeY76N1Pj569G", - "marketQuoteVault": "3pVBEK9XgKF2H5V71QZyC4gRkM6QtcvKsujM9DnFeHNe", - "marketBids": "3cVQJfAkr25qxjUmNjeNT8Kr8Ubk1Bu2WRZoJ8fsUZN4", - "marketAsks": "AswCyZyfnd96AJy9nqM7TigFTQ1sen2anhCjfSkbvtvB", - "marketEventQueue": "FjtQnd9KGFh99SmzkWNY9BPRPyf1quZhXmXFiNJJWJkZ" - }, - { - "id": "G5ueYZFebYqp5PZZRuw8qQYuLoi7zsY1CrozvgYGDxKo", - "baseMint": "idoLztG5ZGMVEjjoQWjeSu2eVkVsp3YnrFZKf7dNi4j", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6Z39e1MoVtTEi9wQS1JUnQPKdyoJXuofwto2XwyDd7KY", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8Yp5h6H5Y3YzCSpfBTnVCWFAD3repH9XNjALd4xRSomm", - "targetOrders": "2WnkzCCQ16WzE8ZVMsqbrh3Ks8BsTMGSq1cqtJutAsS5", - "baseVault": "CxrZD8mPGd58Gsw7tVFpvDvVoaYd3byStS2gv5DDiubL", - "quoteVault": "CsWZ3YKeCqXwJyVvPB2nKHX9t1zL7AqDSzFfKrBPq7yy", - "withdrawQueue": "67qFxd18RMXBVTuwFgaj8dc6HPW3yraYiG1utLNRkq3t", - "lpVault": "ABF6RsUWyUL34AzmH7KjTEYNyAPeKHsCuTFFxYr1dFVx", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GajaWto69bZXwCMTaZaagPxg88xsaXqYjzzRws9vTJwi", - "marketAuthority": "G37LYvemqGgsUq1fimRAwCLYruPb8PTMiSmXadQbAQS", - "marketBaseVault": "o1ZB3354G4BGo7fHj9vtkjAuCphuDx1gLJ74oecY2jz", - "marketQuoteVault": "HQkrMXqCsoC6mxrG5BzrLJKt6D1WTGaeXbnkvztn3ZwF", - "marketBids": "HrKzm66Yvez3W4oXGZL18ke57X7gnbyn9cvWnPTpfHa7", - "marketAsks": "7HBf1vJtpYCn6CT1YBvKVJXHnCysoTzvnCqwVgzgGt9D", - "marketEventQueue": "G2w4RhxjRfV25Ect9gLjRcBweZ9p4nJBpmw919edcgfN" - }, - { - "id": "G7Kv6bNqTEfwXYt5BiSbeCFY5WFgyFcSUcG1oVoKC3US", - "baseMint": "EswgBj2hZKdgovX2ihWSUDnuBg9VNbGmSGoH5yjNsPRa", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "3Mvx4nQcUNL6EcxxPBhxaCffs8nDGEuLFh3TAwdbgBCZ", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2j7637a5FPpefXQ22L1i2Eren4RKPo8QzhNMtJj6gqxt", - "targetOrders": "7VyxQNXCKYV22NKNvhSpPRuUEQWb2Mp5PV82SQVVcfNY", - "baseVault": "VwNFSShER5Wsdon62phPK67jh2KyAFCrLmG56umWmDQ", - "quoteVault": "BLF7ybYbLzibC2NTJAQjZAjvtZem4VABk3uaSiUEZ8hQ", - "withdrawQueue": "7p6hHmAzvUdPCkyKLGTmmD57zqapX9wxstBMSGpmUu4E", - "lpVault": "ENd4FTAJfXe5hEh1UqHLw6oKwUFytWNYexH4nG8qvnFP", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DrEfznVsZrzfcUd2FihUL2UMVVFTWSnrfiePd1G4jqoP", - "marketAuthority": "GjhSW2JJnq5Mk2tu85r23h2NMQUrLeFWqkMW7ZC56ba1", - "marketBaseVault": "AdfbjwFuKJN14MKP5MX2qACkynLB6kVzBytNXBSVUmsr", - "marketQuoteVault": "3bXttddKHXKhkDahemL6p3WVyRazGRjxGg9QXF9RAjjz", - "marketBids": "Cxia8t8WaC1Nxxx4NLFF4B52NY43iAcbrkN4kaeQ9Qjn", - "marketAsks": "5Y37NmBkz3uMZC4YsW7uj6GQNsh4n7T439xZBaLRXNVt", - "marketEventQueue": "Fr6JLmH18gw5CCdULPcNDQitHV4atZJVEghQUow7ZuBA" - }, - { - "id": "G7r9ipWqTjVoMfC3UYD1jYX3JgzKfQZsSjXa6zPp34wJ", - "baseMint": "6DNkUoMa6vNo3CsxAw5XMJhjmdPbPBENHJ6w35eMXESo", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CrXjKhMpngNB4uTDAJ41oqvBot1fuZwfYmTVws76ZAjj", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "59reRdRDafsmXmwC1w8Cfn5Jh7gQy7CRW4P2axMjwtQY", - "targetOrders": "GrPpXVvm3pca5dEBogYFdxUEdPq2uimMjUw8jRGp8kJf", - "baseVault": "9NQ168sxmRT4L4J7xf7uXJx2hQ81ZXwLEHw8FR1wQxKi", - "quoteVault": "7T6ko9JFjavMYqSRaaNBrJvU9SrdYE61gMjuLRsx1taL", - "withdrawQueue": "DwMPZJhdbjfdFaF1AvBnxq9b5ibGzvVyxxmPSnZUxLJQ", - "lpVault": "ToD2UjFtDygZwYkUb4Jh9o1N5rSRkVxUsQUpHmpkrdb", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GB3C6u9Bstk3JwAFwkjRm8N6b3HaTKLhdD91W9ScMTmM", - "marketAuthority": "DNSzvfuXaKAq1K7Y8iL7uEcBvjgiGhTUQRk93ynEFMt8", - "marketBaseVault": "GWu15v2meQbTZfoHmUVNRYZCDZNDxGPmCdWh7H3BmWWS", - "marketQuoteVault": "BUAteN72dipUrsuzxzDJv6nPc5BkL4ANmaqr6iU3Z2gL", - "marketBids": "Eig2krTiRKPojAuxNVwKbbScH57TXJo5a9nZdHHoFom7", - "marketAsks": "7rjPSVrKT6RaCdocG6k5iSBGVu2FhBFVwgddxdKR4HGV", - "marketEventQueue": "3D3imwtS6Vb9qSDVQKDmcP6zevUgtEyb5ubgoihEzppB" - }, - { - "id": "G94UhGPVM1fiYdeeUqnPPrdtdf4PWgkE5qHdhWMBwrPw", - "baseMint": "CGBxTQNXMmmCXAPm4dC9MQJ1q8JDDxApwFwW188SdtBu", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "4JGQCywrn8cVWJ7pDTxuQhnR6r5FMQK18BdDZsDGpCZw", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9d1ME8RqXZh4ZGVmEaVBYa82ZRmqyExuWyTpiLe5pEKq", - "targetOrders": "51EmRS9eu6jmPQKo75sf9wuhkRFEtZZ73rC1QP9d7gyK", - "baseVault": "5XQ9piX8twzyCFuyTJBWCEPGC4oYzGmpAzGhgeEgmP2W", - "quoteVault": "CdLk236Fj2t2Liq27tzJLB6fcVY65Rggh3YuQGhfGPsu", - "withdrawQueue": "DGToBVqQnXiAyVJTedcdKbbfVpB39WtkHM5QtJsMHBuW", - "lpVault": "oNJwyE3QWWg1FLkJyxUd9MBco2ryBvJJit2QDo29jcn", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3WWngZyfZV9DwLk3c2HnvkzDhBKtFzNZ7rB1sEroVcLM", - "marketAuthority": "6pwvJ1qS6KDXxMNNTN6UEwL3HWiokrgrmPsYhYscPAwW", - "marketBaseVault": "F4JkV5b3BwHazPasw45VWhC9Fu8JoapR5Z2suyThfseV", - "marketQuoteVault": "5FPsb4GbZMxaBqqaUmsVM5bTDbv2BtC26jxJxE1CYnuQ", - "marketBids": "JANTZC6M9JGM6VLVGwZtsMUdcGVBwqD5jzgPGU9ia8o6", - "marketAsks": "G9H3C81fXmB9jF18tjuXoMEKKPJDTpCY67UJXgZ9LDrc", - "marketEventQueue": "G35A1LEfGekjXZZVJxkhouK8RT49VyyeZb1Ra87CyKBq" - }, - { - "id": "G9uNh2gFKuNhA6kVLTqo5cjm7LCoKz9mAPtAVXQi4fmb", - "baseMint": "4KwJBSGtpoxGY8pUUEsjpModoYgRGgaqNEZHrd11DzsV", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BiGkmkUX3z6R1e4Wdd1RmaoqNoTw1ttxppXjaDjfshcB", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "34BB8r1bgaAhCGHaxzewJgruz7P6zPsCAFRBC5Ud8q9N", - "targetOrders": "68gN5sGqRQf6XE8UuAWJ96Yhh4GjTX7UqgcPj2hJvi4n", - "baseVault": "2kShCFXYFF945NPDWawAaiuqqbuBB6zuetZ93KGEEUvc", - "quoteVault": "SLkAxGbKRHTrbndAvfxHxEX9jj9tCs126AjRubhpexe", - "withdrawQueue": "3DdrfkwhqHBAMxkbFGcL55SyAXkoh2ke8AVsE53h3tsA", - "lpVault": "CHMxwGuV9M239naVZjxaTioztR4oBKsRz5WoDeYYc6mG", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6NSXoBQkRC6odaManSy73K2LfhsTSKSZj1AAdtS2buCz", - "marketAuthority": "E4ytU7yAYKCXDJswnAwzyyncibpw8ahWK1aLZJ31sdjz", - "marketBaseVault": "FDjRZCTWoAUX6iDJHqgik64e5jYaTQHxpq8ueFFHqhXB", - "marketQuoteVault": "HFJu7EKiS4pekL99AdF7VeDsraTEgdyWk2cNrgPkidZq", - "marketBids": "CoMU2zouegiBL8qacRAcHHLd4uyN2KCH6ibegEpx2a9J", - "marketAsks": "7rfvGPxTBKZxyDTU2pMjSupegUPNe1HPznt4ar16Jzgs", - "marketEventQueue": "7ozC8aifpM2HMSYnqTTHTPqJy7HP5Qb2oLGDCZBfHWt" - }, - { - "id": "GaBotjPEZ48n42VQYB3EDBZLmFnWpJv45WKow55mBq4N", - "baseMint": "7Edx4eDGJNKkF2ZmhaHKzfQ5AQvXAj14osQfmhMJ77AK", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "GiqDUfoyBd9GppXHJVDkRJbyZGve9kt3gy21rK5uAsd1", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EumhpDMoMaavovug7ZLeiTDL4WGt32gxXbA68ZxZaGcJ", - "targetOrders": "8PuwxwWZdtzWKFZCeWPgCrZieYrZ8JvvAsfQXHYyqbru", - "baseVault": "BnLYNvefh8Zv2ymndDn9KP7mJdPz89Q5nXcKputonw27", - "quoteVault": "DJZL3dhWPzwzD7aZCVoiiDagK8Tyfa9RPermBaMpWzCC", - "withdrawQueue": "8i86Zuu8auh73Bfe1nphxLB1ngYCEKmCLxSH3RkkdMnL", - "lpVault": "39SgF2M6a6segJt6pUZJRRQemQnq2C2dnM9A7d5Zhj86", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3hKA6xz8yhmYzqvEGno9Vp3bbSLi4cbmkB6pxWDsj6Ci", - "marketAuthority": "CogghK74TcZyYk6ftW2x33yneh7CMn5g8c8CyQbFYvud", - "marketBaseVault": "BYaLJsgcXSVT4mnbe6K6m4Gm4hAAo4AzHK4wU3hpeGSF", - "marketQuoteVault": "By5Bea8j9LTnhKpxiDGPhZYfSR6ABc7yy42hAynXp2Lb", - "marketBids": "3hNM8qXJH4Bpxw4QyeNqzE7Qo9S6t97Jvb6XkpFiuDny", - "marketAsks": "3PXsHgoNWnnytahEU12CquoMZoTd2q4L5rQqJbokrGVS", - "marketEventQueue": "5xHED6XcziTaFwow9Mi4b9XXyjeK5qKGtMWBXC1hRtn8" - }, - { - "id": "Gbb4CzNFKfSY1Dqhn4Wc4QKMPLDG1iuDmSzdm5oMQUVB", - "baseMint": "GWw447sTHYaQXGsLrb7HANASBJzQyYJXRa44T5MciX42", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DMdD29jq3LKzdPLirsMVLQQUNiSAHM3NbnthghhL44To", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EDjVpoqNJQtp7jHopK5prqfKaxkeRMVFgiyeWHPhKHzV", - "targetOrders": "8YvFRHG8irxf6EgXFx8B4bhRcs9gHotUeMgy13aNaKbD", - "baseVault": "B2FMRSFiB8w8aZRqAqC5Y7xWYssmozR3JqpMxRh6viJ2", - "quoteVault": "9oRVAovSA7QhXYn9caZpECPsSDKNArRFBFV6V6iNtDtp", - "withdrawQueue": "46e1Ym7r4nxHdr2bg9YDGytT3ZcbJ3jSLKp8cVjTXwNY", - "lpVault": "ArCxw6TEJqW63BtgFJDQbzh6M9zbkWztw4CNwaQCBFsK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "48D8ErrCdVSQBE5bwjxbxU1gsKEdJ7aRgikqNS1uRJK2", - "marketAuthority": "MJXTVhtHrYbpLnkRx56FMaFZCURBsNhknfhrhjVBy6B", - "marketBaseVault": "8VxQnVbQAoTXoHSoGVq8aNZ8mMHrfNcvHUefckmBhnhZ", - "marketQuoteVault": "EC9rQp39VdL5GbwdLnLyW7h2rEERu6PuKWzPdT5HLCfL", - "marketBids": "AP3x29BTTWEbw7bzqJi9o1xdvcjjeL4rgQz5y9ipdt9V", - "marketAsks": "AxXF589GN3QSfRpoHCSjARQPmxxNVrTwGf7B7pGLSQNN", - "marketEventQueue": "5aZFKXyTcSQY73mzJbgYvPvpYEyNFzQdUu6T3UsPXuMf" - }, - { - "id": "GbhbJ2pcjYfAVj3ikYBbjbJHdER4yJMyAf3Mxm7DymrH", - "baseMint": "8RYSc3rrS4X4bvBCtSJnhcpPpMaAJkXnVKZPzANxQHgz", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CGrLpJH8LhrFMEk5hb1JtKyEYz3fuEGY6oYfip2Wztq8", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "t6btHtYkMDR56Ga65Y6xwkdNwDNA6doperABpyZ53ft", - "targetOrders": "4M9uSYWyxTEA7BMt3a3h3ztxtm1WLE1aTVUErc7zQxCV", - "baseVault": "2iP4cfgZuTSTybJL2NGFyRr8JCEfWvxoHxhpkcuqPruT", - "quoteVault": "3ouuexPQ6azHC5eWxuo3doMDeGRCHw9W7dYcAMTxLHXM", - "withdrawQueue": "GWsy5fJXN5rFcuiiSPryjt8MLLcqRRAFhgiKT5hFgvbL", - "lpVault": "CVswZwSnmNpLJ1xJtopKyvDCTNX5fdKtPQtwYnoV1t7p", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "43qZTbWaaygZGU468gPSJsWQqSttUAXnxdrV1tDWFZUG", - "marketAuthority": "3gQppLT4Egb47d2unWtz2CUVywFVA9Z93EZmDftgtTyJ", - "marketBaseVault": "6LhpJtkJzrxJWBoLW78BuJMYwgPtZCPjHwMK8oxGqsuG", - "marketQuoteVault": "5wWzztJEeGpywoFiwpkoT7rt4NTabvFS86aPDfCk9rUz", - "marketBids": "6jgfJdvokiUtfA78HnGDXz9usCq9fhec57Qeh7eCgdb2", - "marketAsks": "DPcBCzsAAvZZBtfSjsAt6tYfJu6rRvoZRfgreGW8XfsA", - "marketEventQueue": "6Yck28QSSnQ14t6R4kLP9gvicKTqYiWTiKJoxi6kxgSK" - }, - { - "id": "GcdqA3ZasAMdzrTwWg35n3FRvfzSqM4aZn81p23yRxjj", - "baseMint": "8Au2WcQrgn1oTKfnnaFfb3iMjfdXYp7Y7CrHi8JaNSUZ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "74mXBythPB2W38gycajoQ8LnuQg8NBdRubTBRjPNwzDi", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Cwb1UM63f7hWnkqnJm2Aq42zFqEtu86oQLeyd68s5c2L", - "targetOrders": "HjyFJfqhwwDdtnFXbWgtmfZiDYRBGXmUcc3Qk5x5ozH2", - "baseVault": "5rh7LtVsy6gQYQCKvdKjEDSp8LfonsKRKDTLGcNcFAAi", - "quoteVault": "9joNi5By8LiUvhXByufjavoom6Ei2a7jstJZc8mXicbB", - "withdrawQueue": "3voiubNwauEDeF6oQPgfq8vBWxhthBxMYAz91T9ZJDZ4", - "lpVault": "9gTes1x8xFxko2XNQ7m9seVtPbgQJTd5WqLHybbh9e4D", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9UJ3AhPZjpBCupqj3Ch32MEB6RJgyYKAC8zvWLNpx5nn", - "marketAuthority": "D1f5GfunvfNxesLMcbP1zid2ag5ivHSF1tbrknRVgbgz", - "marketBaseVault": "3MX4MZSpwu9r9ALLDmxAqMqdN8Zrpd1BhKCQgGLWAm7n", - "marketQuoteVault": "Ee3t2ZvEsX9hrRAjKtNZUHiUfQLibupFqg7R9hkMosDP", - "marketBids": "6CDwPuopyqULtjEpszEdto3achYwEGY5yzd5DH1nWsiu", - "marketAsks": "9DPSda5o4vLWnBWUaD4BeSQ8RH1V9Uixy5aqGNBQMj6x", - "marketEventQueue": "Av3FP6E6D4L8mvBtHFga6vZdxqoY2VzNvKgCPjHe3TsU" - }, - { - "id": "GcqPkr1Fi7b122DCQzByBojaVW5Gx4MDQ44rbWzbBuKP", - "baseMint": "ShiBoi4JBcR1o5XY3M46hAp9zkrJyQNCk1C4WD3zjjb", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8ziU7mjaWrc7h84EB8bCM8K9Jcba3WoqRAZ74Wp6LsAq", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HnAgX17oX4nPRZUmSUTJxDU6UMKLVN2Mkzo68pn3C9hf", - "targetOrders": "6km3h7z18U534kpBEdXaeuxGWALrHFXkNjQV9qzGpyKY", - "baseVault": "9WMSRkT57gRdwghuRsAzDoTc5Dnmq3gWiUkmkyocD8xU", - "quoteVault": "HMQ2FGWhfqmN3HUhW4fBLAdJ8WTuYRNmKNH8TbDBACve", - "withdrawQueue": "F3MvbdhLDGY6kTRKvqFhurZKaDmrgy7Rj4F1mj4V3LtU", - "lpVault": "5EqSms9FLgtqFYZHBzkkgGreNns3LqkmqYLpRZUWDGiB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3FvQxsHYYZLA7zsp3y1Lq5NeATW4K2xMWec5fyQUvHTP", - "marketAuthority": "7FpLxJg3bfjs6YRtUMf9BXsAj7ajiR6RVqSSpsTr438C", - "marketBaseVault": "4acE7ARDWgd1YXH9Zpx5EHX6zizNr8AB32xEYT5ycWqK", - "marketQuoteVault": "CaencCLKdSNMn9yj5pDna7LcMriH85XAmg4Jnm3eLz6K", - "marketBids": "C5zQ1fpPKAbfduY4UWCmbto22LPn3yhfTRzUBBNoXFTH", - "marketAsks": "8ud314qV9r1uZ6GJTdt3WSrmcArw2Dqozez7JRtN9Wo2", - "marketEventQueue": "8xPx7onBje4DjxwrCnRuNNDtbn1Ztm757pbRJAgLjess" - }, - { - "id": "GcR2ZqPiiLdu3ZEDkU4mvSjECyM8XmEUKAaowSzRd4ex", - "baseMint": "42Y3CgJQLnHjdScYMu8VS4TbeZMUNVdBMKYbf7hz7aum", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3TistVzkUT99Z2ohvEe9aNW9a4N694t5WNSZq5QiZesk", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "83Q3mZxg3hoRQyGhA5no2KtL5xJdzny2DGX4oLBbEHHR", - "targetOrders": "A9z691gXUyyjX5JuQoyip4MdMh6S8EooJa6XizvJcwtQ", - "baseVault": "2AzVs7tFZviTDJQsURcNKrJA7zQ6uRtMztZ4FHhzGuBh", - "quoteVault": "J2DA9LgdtaR4zSBSTAQzcLjpDDPaGXpyXWK7t2wVfR5Z", - "withdrawQueue": "3AoMNcxTTb8FkRVNV5VKpYQhjcME8FAmehr12jX1UTCK", - "lpVault": "6zANSZkvyqzPWpP2HnDjEZFnzAiuzr6HviS943xQgFCS", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CdfZ2WryFSm1UedC1LWJcYRwQneBemKuMhwcgXU6afKW", - "marketAuthority": "E4VoK6YUXstPj4pzHBxzQSdN2tddmpuriu6Zj5a2tvec", - "marketBaseVault": "G1wreFUjVZGnU3pfwHey6nUqatmsaD4HvYHaYwUvB9cG", - "marketQuoteVault": "7aUjzBHZjDK5n5uEoFzrUZQ3iyzfCA36dcomzgGuQTZa", - "marketBids": "F38Qrb3EK4QzuQbMtJ27niJgvvwex1inrVeteUVTvr4M", - "marketAsks": "6cAPZ2Y4tfxy5MYootodpcckopLRQ9TQrDZWgxGjt3KW", - "marketEventQueue": "G4nNCta2wVvYf3HC8Tek9etwY4PT7swE5JtJBGN1Ltc9" - }, - { - "id": "GD2w4oXhDYGUB3UCj2VFvmnYVJG1QFwRpCDuP4d7XsGt", - "baseMint": "E6Hkw5o48QfNo6iUi1aepjEBzVq4ZjQLxh7xVtdTqoyB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "a4wnjj4jZkZjxqXnLs26f6VUP6zXVbcpEQkneYzSgyL", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Hrt6AafRvrcDrxPYbRvvEBb5dh8kATQzjTFWgc5VJbHe", - "targetOrders": "WswgjQe1JCvhgMaVUg67EKqarKgJPVg33HSTPm8sML9", - "baseVault": "9R5oMg6vT339KPGPYKpJBhxN9ukhegvHEdmVKrmWktWw", - "quoteVault": "F5mqFV54JZfQU4MjeM8Zn7AnAu1cQtfgzkAv7jHroZFv", - "withdrawQueue": "5effKGmviyFoLdM4K4ZNddXprfPrHscaNyxKgKscfCiP", - "lpVault": "1dAEfikZKt7uuXpAdoR4KWUZb6YvFGuBk6TBRUr2x1U", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "268qCWsD579i9nK34vEkZH8JN2P11qQitzXtzwfE321k", - "marketAuthority": "FUJpoXjMQedu8zmNhbYxZP5w6fHnqXYHvr2Tx8nx9vU5", - "marketBaseVault": "9ATW4UcwfhZGFXQ7qCyT7KVjvZVYeefS11uDq8AttqeV", - "marketQuoteVault": "AxtzGyr4xRF5mMMia7avMapAugsAqHGbqgS2gxyEr2PR", - "marketBids": "4Lwo45FsizskgQkuq5LfdSZoumh9B7ztGv6yURB1FYS7", - "marketAsks": "HBSrKbqLpVnBcdbNRZGd34rjogHX5spsx4SfcVuj3EPX", - "marketEventQueue": "8ryZTBHo5Ncbk8skaVSFCEpk7V6aCSxpZCqJ63CsaSjR" - }, - { - "id": "GD3QjBDxrLEngTj2WrLXfMPK3PKmkTiXzFpgJn9qSsdA", - "baseMint": "8EYHXgoSUy4nBLYpSUXwLTh7nX8w5mPbivJy49bJJog7", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "CKbrksSGzXSnzD2cHvRQCRH1cBirJBg69uxMRduYcfk6", - "baseDecimals": 7, - "quoteDecimals": 9, - "lpDecimals": 7, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GaU9xp2BdZFj5gpdBBLhgtaut2f6KCdTte9kfjUnYKj7", - "targetOrders": "Bz25UEsFFtx7AKRCvdtPGQ5MnCvwmu1zaqqg2KCaGaGk", - "baseVault": "CuzoMetCdW3xXHs2th9cQCDHizTnc6WrAcAe7rHPhByU", - "quoteVault": "4JMy98SribL9PtUgFCXMfiH6jQd8dTq7AXUomwxYJPMy", - "withdrawQueue": "CmTbignXkPkgUUZ2fCZLwTkspYebTs3faSgG8UotYFG7", - "lpVault": "ELozYufqZSSSAkMCqXf1cuBwvwrLQSu8hPMKvGpSUduq", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2M9GfELuZDeMgmPC7hcwbSc6kgYZufzaLtCg2enBfH7U", - "marketAuthority": "33euWMowKhjLQkpvJqDMea7fhit1Yn1suduf1vhuUqTf", - "marketBaseVault": "HNtGnDsAZTyViCGL9RQgxcpe8xFP7nyHPEfays8W6Qzo", - "marketQuoteVault": "CM1tWmgnS8MRTJNEDTHryoUqC6g92hDLuhAk1ppyxia2", - "marketBids": "FLqmzA8QrQUr2XWLHt5RGXiaVNXgARzNWP8t92sU5wg9", - "marketAsks": "AHswAi49VS3BK9J8vQdy4gMpbMBZRkKXFioZ9HeB8Q1h", - "marketEventQueue": "CGeRuif9wHTxcjTpx9Pwk13hETQ8MzZvtWdPhf8sqdVC" - }, - { - "id": "GDAdDxJnZpKn3MhtWc8NWG4CEdDy3YXsdx7Pyxwgz7FZ", - "baseMint": "3GfdtDnQC6mjkdr9cEaSr9mjS2VnSYoVypQiT2PPRBch", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "F3UxvsEBfYhC4P1iDux6CeTQun9V5CEd1xfDXdYTW7nT", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FVX5dNoE4u4jTcP6Ku6167UkahXtj4o6JibvJXogfsqi", - "targetOrders": "Bv5rxheuRQg86jZpXBkxv3mvZ2Af6U9E6pVzCBoPXrxs", - "baseVault": "H7MX9SDcoY27qxj5razbXZue8dS3eJitprkZ64HSVoDC", - "quoteVault": "3PJfSmy7kHbJBCB8PEYt8aqny5HPCZaQgYd1T3uJccqa", - "withdrawQueue": "A7PW2WYfASXq8Y2xye8at6khbwmU7BhjcBojipSxLWFY", - "lpVault": "EkH67qAnehr5b63Kw3QgyWQ85ciMrTHcmKWCvqDBzwL9", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GL5FVrZ9j5MKYpkgvf77uWFzMBXzG7iNbXRHit3q22ae", - "marketAuthority": "A2vcDCoLYGbDPYwYbPf9yqqNwFSzawDJDCjmaKvbWskE", - "marketBaseVault": "HydGpapqLPNJhD98siePodrhieo5W7CPsBX6grAicgJJ", - "marketQuoteVault": "6kUGKSBB9VYD8BkHh3sYpsVA2mS7Bv89uxgVVMSfc1WY", - "marketBids": "Hk6YVAc32UxZmAZ2YuK6PHks8WeFtFQ9WFpnaCELoeUJ", - "marketAsks": "AG1vt6oLWBTzynx2o4K2JajR3cN2MgFdvfAtUuN8Ju1J", - "marketEventQueue": "4RujMGPQDxr29RhGaLmL7E4KtxzVJ9SHaWXuxVCuMuGG" - }, - { - "id": "GdeQXD3irevdhtMrjCkCW3aXU51sbetWWx2hDfM93zCL", - "baseMint": "7HGJwFyKC5wPLZ9ctgVSgjBARJ4dZrGCjMRQmzWwe277", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "2bLc48xmbLkV3qa7f9B9ESXGNzN2y7GiBGZcPpz7Kk8A", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BXTAjJcZ8KSEVHjvcSunpbSYsc83n28NTj3foyZzqupF", - "targetOrders": "64BCxPWgtXfC17en45yCDqA8mLUujJng7gc1kM4P1Fxi", - "baseVault": "6GJcKdwn2qQ2HFrRMhjHYjCwD9HbCPBh3acCPfA6qCR9", - "quoteVault": "7bVJuLmnqQ23V3PW3J11nNAjHpUjUtZC45RpXQd8B4PW", - "withdrawQueue": "DKbudhMJ1DnSqZqmzZCCarh7nbMEt5S1ibqRnK6DFyR7", - "lpVault": "MmYPfxMk7PTyWi1xHVMGps5fY1MVTBQ6qiaLBEYWE37", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5QoAs5idujfoyDmmAg4EoYXM6rcc9vqeaxW5J13m3nyn", - "marketAuthority": "CWA4BbygY85dgDXjxhgevK3BsCSHJeHhg6awdShEsndB", - "marketBaseVault": "6WfdQywPHe7eKfiqXnbeXVfB7VP7S9RTv6wumisZfJFZ", - "marketQuoteVault": "J7JXnjKpkLVghp1RXZptUzytbTDWhf9FSq13dJSRVAYJ", - "marketBids": "3XP3rjXg2SmrVnnKFD9ccEDLHXWj6H6SAU6Dn3Y1j7QD", - "marketAsks": "FYuYk1dZAQbxanjRtsbBgtfwrWBu5DG8LqNnndBgd8ji", - "marketEventQueue": "HaVhi9ad65xMJy7KwS4hzbfzdJGYQcZvDBnhHtKMbNH6" - }, - { - "id": "GdxnGTiuRJVPgWtLzYwxVRTr2vWSRpJpaknxT5rtdSqp", - "baseMint": "2oDVQrNmBrJR71t2wJjq5f7Vz6ohnJheHoLMJEHcEW4J", - "quoteMint": "EdAhkbj5nF9sRM7XN7ewuW8C9XEUMs8P7cnoQ57SYE96", - "lpMint": "AHEianNcfVVtNY9aPqyQ61tGuF729wsStTkT5TT8HBp3", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HA72QeuEzuZisqxixcFtuyci7xvgjtjK9zoyEDmQ4wtd", - "targetOrders": "6xHAkvCzB4RrBTXSwcs5noPhMAGLRgBSAJzBHSWVXuQW", - "baseVault": "BjdFHDq7tTGwqZC6UX4JCTz2F8jqdr1n84idDz2es7se", - "quoteVault": "CgNaBXcHVut3aizo14VzkKwcLoovsM6siNcDfQPkoJYD", - "withdrawQueue": "9nJyyL2amoNbJgoAeuEWJWq4yBYkLKqjD3zS6BWDrV3w", - "lpVault": "4nogTfNnWwWSjvvXR4Ypgv6K1DVzXyVka1BK79UTN6Hf", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FHB2P9ddzJf7s3bvfWHxQht4WAr9HRZxNgDr1jpqc3qH", - "marketAuthority": "3kFDYi9b88xcMJfUNzPGao1ntFooMjhRCSpUC8BvX7zB", - "marketBaseVault": "BhNJ35J15b7xvDkHxJQq3oC4r1STeszpwPwaRCLLZKL3", - "marketQuoteVault": "HXyrnfWro9LXnt8tAbahprDCCy9Pwv29vfzYXPqS3YFT", - "marketBids": "e1HnuChfEwbCLhVyTQzAQaD3g2nyrvhvS2wpHhpTz7i", - "marketAsks": "BgVVaBbMm8JxG5kYEQrzzhDDHzLnG9ZewsxYE3zHGVnB", - "marketEventQueue": "HKeDhqi8jtNjyec7iJSTwYVojiWmCMi6gMyUwjBtDaUs" - }, - { - "id": "GEb9VCjBLsjpaeZTvw16Nft5rtCHSDZnjacRtqTUEK4v", - "baseMint": "AxXoJZhSfeVUe3qgFZTt4NwQRJB61pBQAHTdWTN9PNms", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HBiSmTYBAnpcfBL7PCymCUoaNJg94jLR3RVnpL2xPsyg", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FcKEouiW8iTpEsK7SkMUdbKyqURJeKgGfTSJ5ZgHg6mw", - "targetOrders": "G4ZtjLqoHVQvk9YHMLYtogMwku4RTSjFXZT5Wpa6RbEM", - "baseVault": "GZZWnajk8MAwMJ64QHsohMLiEtmzD7QGkJubWVQqJMmc", - "quoteVault": "2m9hszyrN1L9LcCmnt8fLuHa4SdrjYov7LqUrggcPFAB", - "withdrawQueue": "7nfrJMK8mUWzTcoaersYujGrqEViLxUviMXVo4fM7A9w", - "lpVault": "ASReeEpfDgo3VsDMX9ntBnaJTHfhv5jZbb9aBFrWSzjk", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GJ97W7yL8r1ZEH3CV5ZTywjDRTA8S5uC3UNScRV2Lwwj", - "marketAuthority": "63Tx3wcEzV7vUJj1C13SLEGDhjDdfygd32z7kHdwyhpm", - "marketBaseVault": "6YnUPB4u9s1SNYQt46fZqJMP8dL3rrcRtJVhBwfSsgj9", - "marketQuoteVault": "Bq9bQtpcLhHMjgDVLnERtFTBM2pzGw2X7ChM8HZ6LWS9", - "marketBids": "3Qwet7Bb47ABMhFdhfcbBRGwyH42kgL3RqQHeVEHBY3o", - "marketAsks": "2hpFauagbH34kjD5YwQjC9nsMRgtMtQDKFhyhvC69EKj", - "marketEventQueue": "BiZpjyUirey9Jn8YiGtgLcD5eRR8urUzSAK1ySGeqDBY" - }, - { - "id": "GeK9JZBUQSUjghdYaFK9m2iNP72tK56bwrqVksyf4quf", - "baseMint": "5j6BmiZTfHssaWPT23EQYQci3w57VTw7QypKArQZbSZ9", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2G1a6qvnaxNWp5rkE6LMfWzW9zfm8MoSCXdsDN32iNTh", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "D1XZdbj31FQz3Q2JA8PJ3MkTQfVanjWgmQMzDxLyqQ2U", - "targetOrders": "5TJKECZagwD2kMMduPLPKLVNUDpqFZaggES7AShA3fjb", - "baseVault": "4AMVPozTSoicapRWeqwu4VpiwTep9xd5hQc5xg1gWiwu", - "quoteVault": "2AB5KwHRP1JnvG8yYU4FNBzJJpNfk4uLSzeajpAuemVA", - "withdrawQueue": "2LaWjmiEfo2sbVa1d9AESLGRQK8s4mVtmB4nDSMM6FYe", - "lpVault": "GfLSMq26K28YYjGbZ1KX46gjhMkyxhnNtab5r36kBBCN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5zmZq5Ydz3R5h5kf7wVb3KPJEZrNDUHWVbtjXZTQ4fv3", - "marketAuthority": "HzJQXqEttsoGWYzVgcCXpS3S1bQQLczTYJv6ui1o1Fee", - "marketBaseVault": "2yNtUmJEJANzDq9wiF36D7oHEHTJnbkimB8pzMjVmDfZ", - "marketQuoteVault": "HTdYWVoe2Jp1CSQxko2UatNNgfXXj99ZvJ5WfcndjRTt", - "marketBids": "DGAUTtNTo7Sh9d478jtBTH8hj7a9wRLvVNxmhkEGeqAw", - "marketAsks": "2n7T8EA7p71hSrzazx3qjFwGDgDFLzg5mkVAqA2F2A7Q", - "marketEventQueue": "GJiXgN7dMx6Cg5Srhi4PyTf418pc5nnJQqocpTzw13Zm" - }, - { - "id": "GEny1oSHf9dNVFui33ZXuUzgj8EQgLV2xdoj4r27pWcB", - "baseMint": "GnvktcAWBGMg5BqJRjX3c2vEsTTSYCjqk4epfd4MVqtu", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AteKNGXPbEiupX891KY3Zn7h3os3HfPyj7aXhbwHGxxA", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2tVnh2ZKC6Hgo3nqtqNfuYzy1Mr2Ufpe8C3TsBUw885R", - "targetOrders": "CKk3F6JD9raqLzxYMTN2j1Mc2XjChsxZjAbowSqr8my7", - "baseVault": "DEUbaVVsYbpogrjtoAoVz8kbMLHaY1nbnLZfzrE35HmJ", - "quoteVault": "FPGrxkPf3ezStL15rWGeCzgBjqt3bxMYBPChCpJMehbX", - "withdrawQueue": "2GKG2NtsvxRoB8GWVxtMZSD8tU5L13B5uKzYYXQPxStJ", - "lpVault": "8TZrS7b8m9vt4RrJWc921WeHXViqsazjoBQthHdsRQ3x", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7KxwxHBgvzmospw3EX8HurZ6kxtamYymV4kJSTC2S1qF", - "marketAuthority": "AF91FLyT2gJm17ao6ovGpWQG5gMTphAZL8cAiCTyXoKc", - "marketBaseVault": "5AUQcbprSDr8oN47sL4SXpgZDjs9MtLUmBA26b5xYjXd", - "marketQuoteVault": "HmAmbp6CCbk4s5Fi45Vwjhin5cUh7jEAcUCvcHBL8oou", - "marketBids": "2YB3iKWqkUPS6Pad2ComAHzV9UupxftSzgrUAbxHkjqJ", - "marketAsks": "H8hQPU2YJcrBEBFeQa8G15bD6Sf35GrGiWxjmNELsG4P", - "marketEventQueue": "ArT5jf1UHxG84AnuepzfAjH7qjA6pyr45DDJH7euxYGn" - }, - { - "id": "GEvo5pdvzdxDc7EXerPPrQMQJjK5o9Spf43Z2h6HNjX9", - "baseMint": "6Rr2Dv17URCPzCXgcwvaEGcaBpyC1Uykndiy8x4aN75j", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5jPYLAxjHgRY2arpBTZmMa7Fhymc9ivonazZEhcCNomh", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "92NSiaPtXn79LK2iBJ4HyvUwyq9aTxKujj5SNyoBgsog", - "targetOrders": "33ttqpNDaynAcwjhrKR79viqv5WKBaTPWApQnD2sjCfZ", - "baseVault": "4yBvpd3YxX9NK9F9mj97q5fsDF68iiMyUc6TUU4tjzuu", - "quoteVault": "CQULqfAZWqy9Pr5SDyHVdSVFwVbsbc443NfmsJqRp7NP", - "withdrawQueue": "3NdD7JGUr2Ryfe3duGiykge17vJ4wYDjWZ5wkzKco8P4", - "lpVault": "8yz8gcQR6UyCbbyPXwvyqDrdpDx9nBFHR6XzpwEeZba8", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FcUma1r9kVBqLrWoHfxVRqsnXZXLgh8zTwdy1Dr47Ju2", - "marketAuthority": "7wwo2grRjqZ4R4AtbdSMhraqmCYDCkE5oferMUMDfrpu", - "marketBaseVault": "Af2hLuhAjvgWhdGxDVgywzzewoRpNftfxbYbAvwwGBGc", - "marketQuoteVault": "6DVBWmNduKc2RjsaManL11DCJwb2sQpaFpfhxombGFrF", - "marketBids": "3ikiUe1jW73TBb26GKj5VoCszeo8vSTm23xTnA7AAvj3", - "marketAsks": "BfYifpdXot2XJyD4W71Xa8rn8VRNG3nj4r5bUeNbfsbs", - "marketEventQueue": "CgE7FYp49ysEvLCekDaCZkbpr9jc5Yx9oxrd4L581Eka" - }, - { - "id": "GExkdCWExvuMfsP9KcNKRYUgaSSSXEtGh6SQrzYaonCn", - "baseMint": "9ZLBKPCzkvDv85hojKofsogsESkJMN164QCVUtxvBxEQ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "E9zsoz5WaAYzogkcxbbqTnBfhbDyUcNqWpSHLe4kMq87", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FzJjyb6pZqPz7WT6VYBKuRdK9X91z3zMK1ksVcZ9UAnJ", - "targetOrders": "4bxjGG1Xd8HJKgZvDWxifzMVguF95tbZKi7ghbQSN81i", - "baseVault": "62eoSwe8A3g29o1Tmpj5NzkxcDXZ11VG7x72NSt33REH", - "quoteVault": "HLR7EYpKjrnxtizTKHKJsCrnHPNirJKyohQqcBGTvbyA", - "withdrawQueue": "6pHHZSzkELeNzSqbHzhGeqpciPzrsU1npSo7TztcLQRT", - "lpVault": "HChzeUxVfhphYscuo3wNrTVwRh9RJYk7F95XDHbVZ6wp", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5Lya4eBUFrYrQ8Gg7E9aqWn9twkyqk57Q3adyjvBu527", - "marketAuthority": "4TWEWpU5yFznchcMQGpwA5LMPcWGwHnrezmoyto3hX4R", - "marketBaseVault": "64AiALfRq3hojmch2njZTCKHJLNCnBcbT19HWkmcShDz", - "marketQuoteVault": "2jramAiKC3EbcZuPteJ1VnX23mURbEzo4WyAqx4U5ejq", - "marketBids": "AaJmE2pXNeeWjh4kQVQHjfuUtUTE1N54gJZEJc6CVxAC", - "marketAsks": "3vibCkUghvp98iPye2etSUsGCVnaQLaH4JPkcgbXxVrD", - "marketEventQueue": "6VPCG7U9NDR9gLRFysPHaT34vac7cX3UBxgjVkhYYrtg" - }, - { - "id": "GFcpDt8Fhxgm4NYqgqg7HsAZeCZd3HhRBMtEWFd3mBMY", - "baseMint": "27nqFZqb2iPBeVA7bbE4KPZrJgi3dJdKV9VzhCguSy6Y", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5VDe8uoNGCubcYLb4tVP5fNLvHSPjjvsHwLq34CXibbD", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3Wry9cUNYq3NZ9QodJ1i2RLeEJ27bivEvbGBPCRGscyP", - "targetOrders": "8d3uv5JpNink1WXhXtSdGKwtbMg3fHZXcWFYrf2meHor", - "baseVault": "eURQnBfcFXxAKSAGwSwKYRxCifCCdT3rbvp98x7ntcr", - "quoteVault": "CFjDKGJSNvvfXRofBPAcyQkuV98uzHZcPQFNMVbAEEqM", - "withdrawQueue": "DuMZMJeWMPFB3gJxiEeuGK2mdxLQP4w8TyjRLiy48C9M", - "lpVault": "G3M6HbJA4siiFr7M1DYeTUiCSH5utPxnSMU9zXM7QpjV", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "D5pKtYUkezFQBafMFpvMr6UcA3DQtwi9eHnCG9qgTJ2S", - "marketAuthority": "JveeGriPf53Zq8kt2tiNsbNtGNZCMEqnoB2YaBXDeBC", - "marketBaseVault": "BQG1pin7pseiC1Q15B3NKAsRScxdv6Uj4UKMvnAr2Ynz", - "marketQuoteVault": "DsGsw5FxyXCJdLKCiDEHugN5tAtA6ovSrkweLttbhbUH", - "marketBids": "9wiZhMtoegghMpUahS27VKP3NZvhVvGNQ8w631AsJwV8", - "marketAsks": "3qXtWYrbqPTPaGXp75S1tReZVLFW4K9ZayHmA6NkwiU4", - "marketEventQueue": "DHFWgidjYSE3b8qS29Zy3Wngk3AG8nRiQmkBAXi7Wz6F" - }, - { - "id": "Gfs6P1FZeosrDywkMZfM9VnJe7B8MtswHGTKyjQhjfLS", - "baseMint": "FoqP7aTaibT5npFKYKQQdyonL99vkW8YALNPwWepdvf5", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7HQtk9VFYyHAiuGP1SmypfKekUH4FguhSbXrUGhMYKTD", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "H9wqFiakB7SpuxtG59kLkf6qsBKyUWdeAkKzWNSS2Paq", - "targetOrders": "3g5ZMs6tBYdDJeGTw4eVBAvh4AAVjYtT1JfG66UqNfvQ", - "baseVault": "76tSKewmHQgpkZCykDtQC7rSopQ3qNm4scZWQWuBFcWx", - "quoteVault": "9duFCP53xAzUxcKNN3CDoQPGM6wTP3JSboserUokjMqt", - "withdrawQueue": "GszdX7kAKqrJXKFtEdubxzCmEjTZ2XpEfV1YafqmkQ67", - "lpVault": "uMszxqhYq1ZE2Nbq77smJWaQLt5cxwAeFHLvNGBNUtq", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9tr5uMYHgtJ5yG4SeqHA6kJUdzXrK6QCNGYgewQevuuS", - "marketAuthority": "6w4a5YJUhfN7eycPiJLxNuDUaQJXn7zFoCECjkk7poia", - "marketBaseVault": "3ZHPeJBaQCywfgpK2WNMHKNZ3UGcYsPDBLeZnqFN6CfZ", - "marketQuoteVault": "35ZhfZWVZuLhaSYUeCL2iwkPeuwa3DXX7jYHa4V7MRF2", - "marketBids": "5rJrzX3cJNt3h7sdDXd62W9maWpoz3fXakVN7AQj6sPV", - "marketAsks": "7YCsSW1WSYQ8NqhrF7nGynXodQu6vdLrPDQCDtH1kprT", - "marketEventQueue": "54KjbnVCexudLgLAky26EFHqmG8vzpCG6XzicNJMAQth" - }, - { - "id": "GFTfxYFNPVxsa77m3CA6XdoDmKcKGGDeLnnVBNFzJngV", - "baseMint": "Br1UVUE2UcEBbMH6nkv81m3yDWdMdBHPsudDbJSBnHFZ", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "FpzBxiorgdxEDq88g9o1k7MhVbJZdcCBfQh5wrcA5bX8", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8XfCeDef7EhV57UhSvsNPA5JyLEtTaZeUq6yb6UmX2NV", - "targetOrders": "5ThBvTcYDBNa3ZgKpZ9bjSWr4Zx7RHzZSCpMvUdDwHcX", - "baseVault": "GgJ4FYNZtqiGLpTmXBG88ypcxncyJq2X3VHDDqHdzeTo", - "quoteVault": "HhVZ671KkeU5afwJRgdUgpu8brYokQTHiELiw2NUnjoN", - "withdrawQueue": "9DcEhMsgg9NjPKaARrbgLjV6n1ncvbhgBacsDE7HqiVp", - "lpVault": "3dCHyUJkLBdTKxH2tqkCmGEjKPgnNrLD1c5LZLAh8ixA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DPULTwnsaSaJ7cwcwMEND46RcRueRiQXjaXxGB8iWa8L", - "marketAuthority": "DeWumjzcwcrmyvgC5Df6xKyUCQGBBJD9rrWVi4wfasoU", - "marketBaseVault": "7RzLJbi7rUoDzSo6i69dLmvioxQJtggK8bZdqcTw7wu7", - "marketQuoteVault": "H6TBCVgMCY5RUMirbyTLxvvbqVP7Rr6hLMACcF1NbEs2", - "marketBids": "F9gVz3KLJUrU62UJZHm1WWeTZdzP3SSyLBHaiUivvPcE", - "marketAsks": "74cdmizzYYdpZckyKqj7zexVoTSvH8MA8hEyeC8rR43N", - "marketEventQueue": "8T7ZGxxZwaLPLyVoJRCYfoY4596ZswqpEQUHghDKBy5S" - }, - { - "id": "GGb42fqrkQRYPt4d4vQGBVUbxcrN4wAqkxCRwdPGGQE9", - "baseMint": "6yMw3ksuR73DypLpiEhCtcEPNBX4he7pvYSKZSRQREjd", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6fh7QpyDMACDVQh5Ug2Jyr3p9WBb8z2kRDCYkSfkMrx9", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DYPyjeKBospvLQyVSRouBMaibWbUeMBV1rX6JXEJyNjR", - "targetOrders": "GPsHw5T6NFRwVUTMaL1HGpMzMmiQxGE1RaH2qM7uzrST", - "baseVault": "7CwDPSpF2jdCpQJsLZhQYHenFjFrtsY6Za6n5VEfsFC8", - "quoteVault": "EFuoukG2RqsdbAtMfktcwEFMvPoUNLjqRBXqoHjg881n", - "withdrawQueue": "BrkhMfsWRRrqB1ziYts7cXg2JPVGnvWK9E6KA9oenyXQ", - "lpVault": "s6u6UuEv9sVadS8R1SenCjwweX72KWnULm8dkgkuqm5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EJC8oCz9reuiTBU6ZTWcrKtSxtbvrQKJBBkMrKdriNMP", - "marketAuthority": "FD4hFRMV7u8jkC5zsfrG33tfrM4v5Qk82fb8XfnCAhJK", - "marketBaseVault": "6d7m6bTE8kMThpKFNgzXAV5A9EQssz67D1ngciim1AMi", - "marketQuoteVault": "92po4sFyjgyD4SzmyvB5feHLDTKjcqkSCLeJBAM4x49t", - "marketBids": "DcLAvH6cpoBnPSBikmMAynt3VmX3Zf78QP2WzcbSDk1T", - "marketAsks": "DQwGBVwQTLm49snqy2RvUWrEdhHRqXKqw8ptDJzrHDGq", - "marketEventQueue": "7LxC66MehmPVsNQsDdmmKCrRsVaJKCPJ4tgtc4eBRhY9" - }, - { - "id": "GGjGbs5SePRx4hTmY6ap6jai84m2bPRJ2gYyF4DQ7i8Q", - "baseMint": "AVKnbqNQgXDY8kbnno9eSGfwpVz5idimBnDKiz1vbWAh", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9UfopvQwdDCmru3hnFDkRpHeBVHBC6kDqacEX2sYicms", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "65hXvGkKm2khWRkmkzTzoykM7opSeqBvvpKQ2Hq2HzmX", - "targetOrders": "24UgCdifw5a8vyzux1j6NhynWgeX5poEddXDRDbmC4Vw", - "baseVault": "HTz7HEEWN6kn3dSm6nrjQPJcXxjrVNWkxMDGULAXXrBV", - "quoteVault": "E1rv3Niaz2LHUHFrhd7CTZeEhnmpWuBASqnNzzdL3hGN", - "withdrawQueue": "G6DeyeCquaXGNndEPmFY8SW5zvNsbvtuDBCXjgiR3Tje", - "lpVault": "KMNGRx7iyRbwicFFq1djezNJkLHiwHhwpETvxQtwAmK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HY9J1nsJxrem6w4uBRaWi2A7iNruNFEooMFopfM584Mv", - "marketAuthority": "4hT4TdgodPk4D2A94KnRSoHDiWFQeDCTfdR3yxXg8tT9", - "marketBaseVault": "GHpLQQP7THC7uUcrq4MUXxWpU1NSEQvhMa4T5P71VCpR", - "marketQuoteVault": "4PXJeX8TtfbZDGsVjuF69AP3wfUq3Lohp14Y5KpW4gJC", - "marketBids": "2BvwZ9zjSHAutpVHbireGAvXtBerSJdNQaGK8oVgPcVZ", - "marketAsks": "7nugL3gUgNiA8btJg2yaZjWmPVjy9DPrqVRioNg6Lwma", - "marketEventQueue": "BGXtpVcaM2tgdFQ3hdUvGkKHodbfoyu4zCBtsm7sNhGV" - }, - { - "id": "GhD1mhcu5hzq5riH8iToyhrf3FW5BEZnzk2sKjdX8JyP", - "baseMint": "7BzULwTHqMCc9Qo7qVFn27UxHgb9SPev3EsbbmQ4YNzw", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "DYZvR4b45Gv5rRHRFwqmHZEvkKsPTpSCkMbxmBV5om54", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HWJPJwCgPEPHpLuYiP7LoPz6w7eo5qVMJrVdwUCvpj79", - "targetOrders": "FTkobfMfmbnrkG6B532wtMytf3MNCkSmEB189dzw3CdM", - "baseVault": "H81uAckDTUPqSN4amZVjn29Sq44xbuYpRqCGm4CH2RVW", - "quoteVault": "TskRz6hUb2KkiQ6TdeBwb7Pvt6KoyWrGWpxLRoh1svU", - "withdrawQueue": "6kFS2k4hMf4Yy5QEGRzBhJBgYAyiifM2d3ydDS5iQYLf", - "lpVault": "8pU83vMYENCBxvzzbtuvtgHMfMDjifX3KRjh98h5Z4Mp", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DYbZB8CWKofJERmSUHfMwxJ4v6pX9kDdYFUrHB7TzP3t", - "marketAuthority": "4ymfynCXizqigTXQDPa4Bu792YgeAhkBroYAcrY5qkth", - "marketBaseVault": "D5iv4JVX9HU1Kyt5faAkbnq2RaKWxS96yA8wVg9sToNf", - "marketQuoteVault": "D6n6wa3x8xfob1e9VrxP5EabHvLkFWbswVHDu1YXhptm", - "marketBids": "8Pk3qAvsZmUHMQzNPMkYykfGr4X3PQubz5woEEn3v6KQ", - "marketAsks": "DWhJJuQfy1u7EZcBX8p9YeQ7nZg7CLx8gL7sHTpPAskL", - "marketEventQueue": "2TbG6m3zTCUQH56DVFixy1KKoYKKauX5XFb3MdNzWJ7g" - }, - { - "id": "Gi9xcRqa8yKkJevA4b62dTEhvGmAarfrvCSqjmNj8ggH", - "baseMint": "ratioMVg27rSZbSvBopUvsdrGUzeALUfFma61mpxc8J", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DfzAJVAi6z4nUxsUY1k9yW6LVc2ecbBScdDRzXgYRRFp", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2fkozFtgexykdXRu2pafd5pF3DSX6L5bYuRNp8Thu4AX", - "targetOrders": "BtURYMuwzFNf1uEnSdkMdxYa55dhcoaTKetKpjbt3zWs", - "baseVault": "G6rJ1HwV9eizGsuRRvovM8L9HRKK63dLE1dFG151meMX", - "quoteVault": "Gxw2yHACFqFvC9T9iXSVMGWbYaejB9AfpDwNEERiCGM7", - "withdrawQueue": "523Seddx3iPNA8Eqxog5yeLkg1HKtEqXUgEZ1mU2z6pR", - "lpVault": "Gi8C8tGrbfdUpos8AkYEKTE79ZTv6Ptof6hkm1Ft7Uzu", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HtcFhAWSJnuvbJvGLoRFr36zC5y1M1RPtBCgGQfdLFw5", - "marketAuthority": "HzekXknVoo8JxWxjXfJs4ToSaqt6UmDx4UxtJwXwPHgr", - "marketBaseVault": "AmbbYtJgFoUg4DBqZH4zh8PEHAV9hdJLuvt8GVkU4W6U", - "marketQuoteVault": "2VC7xpu7tNziBpU8aJ6ZJNzgQk7Pmwi3sbQDffnvKjcX", - "marketBids": "HX4dWb2Yjdv2uFJGEpmRNXqNnMyZGoGn9gxKeaDD54U5", - "marketAsks": "C17r832RU8PStad2R7z6ciFoDY5BeychVXEd4UWrBrKM", - "marketEventQueue": "23prbATCEWqJ1gBA73d9KmyFwvEpS8JwigQ75QT8UFSE" - }, - { - "id": "GjdwhZm3boMzVdQwtGaxxpVW2sV7hVzTGzEcE81gdSwQ", - "baseMint": "6HKq7SoHESuDz5ZbjZqgQkhrTiDFTfQdJapavMv7DbFb", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GSxR6DRbS5iYqrTn8zCVVzuTa3Qb9FQrxFR6PouijUAk", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EpSQxuxdGHDRTmScYN5yV5EzJJuFAGFW9TAwtDdjj6ju", - "targetOrders": "2kSYEwBThe4iPg1pRQ7pEVJPCCmwBpttg22JrtrjpbWN", - "baseVault": "3Auk7XhwsNSaFRu3tW4sQgU5fiqiURnEbeJkzyt8Vnxb", - "quoteVault": "8YwvFuigRmsN7KYABvkfWEpdVSZ8MFNTdiwTBzZtJNHU", - "withdrawQueue": "y8G3oREHzfpG8eHNVoSrmqqY8qMQnnWgCqoST452JSE", - "lpVault": "J5S7yzJAujHbuyScR1GCRsf4mRPanXSMpAqE8BcLAGtK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3yyQrZnptLk5rbnQqu3XUyJMgZP5uFmmAZ5JjQnC6omv", - "marketAuthority": "4xcUWr2LsUqcYfHZD5V6PPhMdRkZowudphpfzMiPH5LJ", - "marketBaseVault": "3NHV1SJFryzSkeVvKoHsababFEHsvG4hpGpVyn11tYSX", - "marketQuoteVault": "74VWCsPGWUC9ZcnBtGXYQtwyaZs5SNpFaCbGRroNbc5K", - "marketBids": "2NgfYe8knUr2D34vxspXHhXRDC2rxGoxZDcgZdWj5HNE", - "marketAsks": "7Nkd2GW2y11zCJuLRpw5rwXGRPrnudEM6BvusfRga3Pz", - "marketEventQueue": "AmhmDUzi5JvsTU87GAp9hXosfWmbncnsZJYxE1UYjnT6" - }, - { - "id": "GjDZcC9UpcBUb8RGbe456Edq4C18oi1YiHcP9uB4k9xD", - "baseMint": "FriCEbw1V99GwrJRXPnSQ6su2TabHabNxiZ3VNsVFPPN", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FVyveKW4kqsNCaa5wZDKg5eL8DKnZtvkZmLuFQ5Webp8", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "78PNJrgJwoBbcDu72HWCnXPju9dd4W5KbXdRfK686TTf", - "targetOrders": "GbxBcbeqKJTm5TC6T5hkyR1YRyEQSh2U7cqthYaonsuc", - "baseVault": "9XQkNRqH8wkLa7Aziz4UrV5jraTtP2CSfejnksXSgzyV", - "quoteVault": "BfbXpjsM1nsZtJS6LffBdZe1RdwH97k386HJhWzknDCK", - "withdrawQueue": "DJjVJfmPdvEs2SQrhrZwLyorQL6dYLGaBz5beMa4znDs", - "lpVault": "FuMY6TALuf84vusEbn77UBo49dGnPWdxy8C8FDsCw3xX", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8DKD5dKmmwparxCkpV2BQFTxt164rfadK8kX3at6hWUB", - "marketAuthority": "C8Agft4wMnWFXGztiU8zVRjg7ajBUCPP316TF783D9Hz", - "marketBaseVault": "He8xLLRJ765aitD7NK9J6DpqBmRjkxDgwqwvXzrUdxBb", - "marketQuoteVault": "2zReMPh4XPV1rbHDjnGjheLcwhZDESiCXm7hu3HE3cXN", - "marketBids": "Dn223aphyPMrdnd2uHiypeNYKBdopHS3uJWH8DtH4Hsq", - "marketAsks": "F8jdy4DGumqmu83dHjGo4fq1VEpaQ3h6zDRV4UUNnscq", - "marketEventQueue": "HF7Pa1pCuSBsXeZ8WeikDyvDpf7Q37uDob2xJ6bR9PcK" - }, - { - "id": "GJjhGqCuwQwAwgxhD3p3Ww8JFdULqiX5ihUYfueRddRu", - "baseMint": "FXSrKsQ34jMmMtciuzhr3KSTG5UMZQfXBJKGqYYUTxg1", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7LLthVCZm92yEnKEDJPkVenYmwpTG54jEU2VfEpRJ3Wi", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DovLM17JHJYBQenNwoSedqw9HBL4dMEqfHJoZ9gGh7qw", - "targetOrders": "HLAc84pALcCpHKH3aWUpKizNNgCmJEUCQQ2kHjEJaVcE", - "baseVault": "6pfHE28gzrKiDT8rQQHeFsYfxjb3JXYCosPGVKRYtvwK", - "quoteVault": "6A9caGbwLtQi3ixGxKAXwQrDAFXwaZ8JCVK2KY6zRsS2", - "withdrawQueue": "9JH8gazaxXNxynwpL5pS9wZyv524E3cqRrLaYxWz52Lw", - "lpVault": "DPjabzkGHKhKRLbqtr6rPg62h4wGXr1A1dDerCz8JXVT", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3zeYbTnbBPuLC8R2512H8pSqyYHgte4gptfDJw9aZtvy", - "marketAuthority": "5dRSLWwaxYL5hDC8C2x8ZS5N13h8NUzbnymK45gmjPSj", - "marketBaseVault": "CL83P3txPMC2L6vuVGCciPbpxHrRy9bmXvZhLpXpzrR8", - "marketQuoteVault": "9LhzXczi1zYLsXa2gqaknikXomLe8wS6o6j9EvU9vPzR", - "marketBids": "DUvwPWFLotoDii8Uvhu7d57NBHPXq79GXodR9pXShuh9", - "marketAsks": "GhbAV3VvEm77wLgMUUmznb9ab6wzRHWHrmZmbdYLDLLg", - "marketEventQueue": "5BtL2szySUBzbDq39ZTYxbSfTykZiYpLWwRgC46Qi33" - }, - { - "id": "GjqEJi7STfPhp9q6fj63Csb7iTSN5Ls6Re5qbFiD7rof", - "baseMint": "EwHqbMUMX33JjWAhxSg9vsX3miWqncsgpnAbqn9nhJwZ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Fg8xM2FdotzkpLzDBobzkqbGenfwLzFqATWSnVaHkJyH", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "C3caeheUgLfX8hW3WSat9M7kdd55Sz9MwA3WQQvSTPxk", - "targetOrders": "2T8sgzB6vFBcE6Z6NW3XMK4Mx218CqfwiB3uz8MFZ1Bq", - "baseVault": "BjttS8n17GLfv92qvVS7jaZMCzgzJamWXMJDmNfkZBWP", - "quoteVault": "DcBwnYuHBE7c4yP2WgWo8jDye6cXTynpTzWgxNkLPJup", - "withdrawQueue": "FCt9Lsn4xWMn13QhudxRABG5EcVVkUuAVDwJ5p6GoFDC", - "lpVault": "8BN5wCwxJJCb1L45p2Q8xYF6CckSVfxeLNJ3ECHtnbDv", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3fxSHmDZx9zFdRucnAtTLAdFtqx2cvo4VaTix2iTgF7k", - "marketAuthority": "H9KFDXdzgo48stwuKQwhhLhq6JtY4Nu7NJymUa1cr3K", - "marketBaseVault": "EPq1i6trY4Ngt6EXcRHgv6GG9JdNMMaAipE52TrcXV7T", - "marketQuoteVault": "5vXoWFWxjd7rRqZczyUxY9ArNQtC7YXm7Qo7f4cnLjvq", - "marketBids": "3WrWAB1LpExCHMkkGhVZRnWWA6rPUyMV8WCXCWBJfYo9", - "marketAsks": "8Ao625Ych4xYzyEEnwWnrG1wS1L7oLWm5e5JUYRTWkdz", - "marketEventQueue": "FPQuWQQsGXjrxnQgyGjZJtdgombb7Twdu3THVHKdtQyc" - }, - { - "id": "GjygD5GnGj2yezMWC6epYuABEiKpG31CKmn3o2vShPoC", - "baseMint": "FCRMFcfmZTY5qekzVYAmSRcxjSp4dMqSL8Gb3s2JkCAu", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9UTKDZrberJ3qFaYRoySiSyP6kbvxsB8bgdUi97TapfN", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DDUFyA454fZyRJjX6z83i8BQoEvSjARSJQDQQQFisP3L", - "targetOrders": "6xQvQmXsDTTdRXaAWt6s5rFw6dEKfaUM3nU3m5B4W6Ac", - "baseVault": "6aRY421TCx8MFPaL8Vzhs5kZjMTmUHm8KH6eCpff4KAm", - "quoteVault": "GZ7YWdJ2wdsKBVTTzbtrdD7EGVtAxLqpDu2pcpjksHtd", - "withdrawQueue": "npGYEixttqCF1Dc5uWmsfE8QtX53LKxw37CGM1wncVs", - "lpVault": "fnMxAdZKUvUyEzZBqNNjoH5HXZVe6L6ZW7bC6Km5ERC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FonJxyh4kQqdmsZpF2Ngopx5M7gGF6D49HPhsfarBsTW", - "marketAuthority": "BKX5RzLWQH5nCuBFfiaCjqBawC9sFWh7JP3bPjqRzkxo", - "marketBaseVault": "DxKLQaqx5FhJKQcXkagj4xNCKNSpUqbZDvQKAsF39pQz", - "marketQuoteVault": "Fiv5TJZA1Yzay2cvQunAAik3me2Lnom6sKJecnbXg6ue", - "marketBids": "CDdc8vTAjQx1ZeYnA7Q5WnHXHKMbZXuURhUTbGQxKE8U", - "marketAsks": "ERdapJV2UYwby714E6HnvxW4p2J14CFFpEJ1JVqVZ8gr", - "marketEventQueue": "3mTiQoBJQW3eAL475dUURRUtaH5GXSGfgbgX1Ntovofj" - }, - { - "id": "Gk9yyaXQPcFEiuRGCL5q1yLXAPfDFBq7bZN6heoev5as", - "baseMint": "FdDEakNRY4k3orJuBXUcm9VkcXd8YXVPjuG5WuRN2tWH", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DL3Dasyw1YrDZAyDhJYurC9zjnPTchvTfewo3KLEiLXv", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4eTo5vdGVtWbMQhuJiQQ8cMU6o693HmhEZHzXYGrdBeD", - "targetOrders": "3iKQHkU4oKfcSMiC3BidnKm3XtWD3aidPXwAd5vaFLk7", - "baseVault": "8XcDgxRy5U2mNxn3htR7ayJrBKkRkcYaPP1Y1EpH57F9", - "quoteVault": "14P5a8M1y2v5WHKMR6XVpMS9ob4qGxzxrWq4LKoK5NnP", - "withdrawQueue": "CchZekh6wnJ9su2FD3kmWuz51KqwPxoogYJpQAaeuYDW", - "lpVault": "J3LwE9sTaaoye8ZcCKoBeRr4y8SMYgFKgbZi2iVv5s6V", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GPa4iZhDPJfGUj3RAdpuR1EZ4Xgmstn2CC7E9QVDukKC", - "marketAuthority": "FMR6Bur5K31itQzUEge4Z5hWgDsuT38wfQY2LLuDmw2e", - "marketBaseVault": "2HdqMTonPas44MzbweGLp4vtJz2Rymm2JWBP5rf1EFtq", - "marketQuoteVault": "4LoRSpdDyy8mmytMEPo3A8WLU439sxPznFgc2FaWSuUv", - "marketBids": "7ogDNpwtZrdTUGPwih1DLCejJ46uqf4egx2MrCqG37Vq", - "marketAsks": "AqTvaExvZmczHsTKudmtZVeTXJtQfM7Lc4LvttWg7vUf", - "marketEventQueue": "AuD56V79CUgqCkhkeoXSvQTncTz6hQqabniTXZLhCCFz" - }, - { - "id": "GkCNxMRA85b3DRUcH5pqBMjyDy2AXHfNZcUDFX45tPwj", - "baseMint": "3ZYsJZ7wb4hNEkfaDnR4JKT6Rok4hEfbxjGqDA3cRxGS", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "HFVGpdvizkiZcEyA7V5BgW7PksZaASaJEwEVKBjyE64Y", - "baseDecimals": 5, - "quoteDecimals": 9, - "lpDecimals": 5, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5MudPWPdtBCMZdDLBr3LmNQwNqiaSyxNuKWRT1FZMMCZ", - "targetOrders": "5UyV8dKiX5ScwbyYzbaRp3qohmVPJTQFCKvc9W61wa8x", - "baseVault": "6xbzqCJHwAzAit7ex6ZEKGy2u57YZ8NvJRBrVk3TBFiD", - "quoteVault": "Cj5hevWRf4CqCEbMYf5CzDAqVb9ZsKQTtQCgQ88Eha8b", - "withdrawQueue": "8tpbswkjvGA55ZXAt62vZx61h7LAEbYv8ZUEubBA8E9J", - "lpVault": "AmpQgNkmw4VhyF72ojyBaHSWVhXZuS8HfkQBYqU7ti3h", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Foo9cD5FhMK2yuoMu3JE8ywi4UdrtMdQdQREp1jKmFvJ", - "marketAuthority": "4CPRP4YaEyepEC28rqLpu9JxS9D4pAcS6qkKNx6YiBHp", - "marketBaseVault": "5cdtfXcfqMeeV3eN4ixXAh5zFHd7i898APtupvYx4GFm", - "marketQuoteVault": "C6iy8VcPt48QnFbENFZgGpRegNgQRxW9mpPHa7D8L5Zp", - "marketBids": "5kZiyUJ9kk9qa7NYdGjpCoABBF9Et5ukLtcEEJ59T9FR", - "marketAsks": "7FxCnSR8nEN3kzX4m1zR1YMcDLVi32idHxGMUsc7NWh5", - "marketEventQueue": "BkPXEbc2UFXQ8Ha9QrzmMQ6DPLmWsf5CVtXGiRUcdSSy" - }, - { - "id": "GkfWbTTtEjbHZjq6c7RhGNhGnnpRLpcDu2NSJetbetp9", - "baseMint": "C5xtJBKm24WTt3JiXrvguv7vHCe7CknDB7PNabp4eYX6", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "C3fyq8hBU7bPg4wk2Nu3ALSm6Nkp6VmkNQTJ1ETeCbXf", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DZeEsDV2h52yEsRVgRuia1ZkcPsG9cchhkMTMq7qG3G1", - "targetOrders": "GjBe1e8tJNbfxBF6xM6aDqQ36Z1dGdTbNMx3JEEP2win", - "baseVault": "T4hU59TJmLvWCBT3RtrH3CZQWspbiy2VTdkuZ8QxHkg", - "quoteVault": "EjsVmu84eZqMesN2vVMSAfk65mTA37yFN8hixtUYvWKi", - "withdrawQueue": "4cMPBFbwvCenUvwCm9Px89StBPC3vp9M4yHoWidfzVTT", - "lpVault": "2W8ZGQFZ8VjJ56PbZMeXyvKzGPL5ai76bh4CctimzSuY", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6yBghe3wATAaZyBwBgsuNjR5iPqXjuCfZogVViHNY7fq", - "marketAuthority": "5us2oZarZfoNHujwmH6fRzmc2AxWcM4VkZVGp4JNgfXd", - "marketBaseVault": "EFALybNm35UcfneiRNvSuiwUC8UNpU7ZvM1qNG4NtpaU", - "marketQuoteVault": "B1cSHSfN2ouCdeQ1Xg5hRKDZLL6zcgqjqa99ryUTsxFd", - "marketBids": "U942DdALQR7vDiAPZLXVM3fzFdQSBTiW6UKLNikrWMg", - "marketAsks": "GKnLsxkiLDRUCz1wd6hp782NFzBUbmEv8uw8NZmHAbDk", - "marketEventQueue": "CJW44VMojT9jz16N9C8r2dYZ56PGjjPiePNCvLBiCsaU" - }, - { - "id": "Gkpt3uUNsmxAvN2dUDkwrjefsLXBD6wBxx5QoHceZAQB", - "baseMint": "vqU8NVkkgpFtt3YECwuQRD3RhX7LYaqZKrotZbdiBJn", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3y6gsnTCJnQ7tke2ztu6SLHEqbuwHiCrMcme1xZi5CH4", - "baseDecimals": 3, - "quoteDecimals": 6, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5JfnpfyTcrA1tmbhdDrfn5cVPR7QbcHk1F1is7L1GiX7", - "targetOrders": "5nQs4swFfV7s7kaHvx4fdfZ7YzBFKUsQxfqTgE52eikU", - "baseVault": "H7uGQ5UL6fR8poZfimKUnJ1qii7Y8cVFbtCgzeYhSKEo", - "quoteVault": "55eih8Vkx7xk8LanveQhiyKS1r3gnfSojdgx1FLXbqWg", - "withdrawQueue": "7CLDc5DWfw2bX6rj3dmHBR2t2NDRgaT3faxhm8CHY767", - "lpVault": "CccM8jrSd5Eb7tnTooDJ5ag8ToBABsQre8fPb9g3Xii", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CPEC9YfjLY1JH8uCySjcwydPaMoKsvftBXoKwUwiaAe9", - "marketAuthority": "7oHvkAd6BVJhpRvbycLZh2u2Xixz87ueQF8aPikVgL4T", - "marketBaseVault": "4RHeeaMdCg4bUbrbZZTv8gBizuuc1Fw6zaVi1sTizZXd", - "marketQuoteVault": "AZ98xjisaANd7BU78x4gVNkTY4XmPip7tZWoJTYv2nTM", - "marketBids": "78qWfCDoBnTvozgJ66YEhY1vJLjhfNCt4WhvL93FCVuC", - "marketAsks": "FVy3EV6oJ23ehkhXraxPLh9EGai3WXdpkghQXk4RkUnL", - "marketEventQueue": "EZ7EVPvaqyfW3immagErsbzcxHLfPyBwBjFJ5UL4FXHg" - }, - { - "id": "GLi6jkW2b5wCCjE92M6RKxHTzTvMmWsbiwGw2QMiRXrc", - "baseMint": "ADcEtKSVKDxBUe3JERgSh9q458w3kRKPMHkihF13vxx2", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BBEJo7wftqBPzhJdS1EJMjSrKhYpi7YTaPNHzQ1hrKF4", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8aCWSvkYyEe3mqrDp95M7fpAvjgsTFJqgSeFZhUm8cBX", - "targetOrders": "8QwqjYVzBcWmdqpw6Xdk1nSPU5xBCpxbhiKTjPQqh4cA", - "baseVault": "BNZyaqUhechuKGdecwZgj2azbAHzZsRfwtcpHgJEu6Sq", - "quoteVault": "Fz4iZn818R53JwFHdAUcyAHZdez8ewpRVJ9VqhAfMVcM", - "withdrawQueue": "4xF1nS1W9CyhELPkURLQpF91mddxqfBshzUkkoywH3Kw", - "lpVault": "AeTDQGXmfPr8RWzWUyzqVgkmMcFFYNHLaQMr4UDSyibZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Cbpae5ypzciBnEvxTFWZ2hcXsvxzNPj6MiruTgGwgdP3", - "marketAuthority": "2sGH1XGb66mYTKqTbqzctkfv8ZYV4CpnoZcKaBYsdg25", - "marketBaseVault": "CtdNMxEzCaU5yS8LRGv8gX41pu6LUqXKg8jCPqEyLAkq", - "marketQuoteVault": "7W4xZpPyNKpEgQwcWSvX1hwMUWATe8qaqvWYuqy4d2dR", - "marketBids": "3vBsoy3E6scvSfadPyZX5JLqZKxDNJUtbSe6S3JFYhG7", - "marketAsks": "4aNumcF1Yjamq1oAEyCW2WhabYRLP1QhMEt2Pasw9wPG", - "marketEventQueue": "5MxV8Av5Y1362g6y4fE9SsrkDam55r9YB8QjLyWtAum3" - }, - { - "id": "GmVRNCNNTxqXMzAnTsGwccoqG3KzQ4yUSRm7vJjSp6pa", - "baseMint": "FLoD6AwcJCnbznnWfV6HkBHh5FYtr8wJYj3mBnwNdLLg", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2qboDCptRP3r3Dk5bbmwtLcmky1ttNCyntzUioXzfPmm", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7t1kFXiRuq5Boc7Fg9DgQnEWMFG7MC4NyVmMdfwQ9uxX", - "targetOrders": "4oCHyvaFt7hwTigsiKdbvMpqRHzxao1ZivHYmU3xbq62", - "baseVault": "5LoFoXp5Hb5niGaBX1CpzGmDXtcFqHfZCedLkLQ3jSei", - "quoteVault": "2NhukyZ4rfDjXrHNX3DEgKUi35z1NbyKsGPGM4WGTq1j", - "withdrawQueue": "4LBNrxQBJL7LMke9zcqzZ7X8Sg3P9if9pjMGWVhwb9Ur", - "lpVault": "3Qp2feF9hydUBeZPTowpnhpg3bHjPPcdqfqcyPLbo4xo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GJW4qMeUpoocpFLw1wfugex6vGyP5pu2yLTxUimX9mDK", - "marketAuthority": "JE9wd2UPQ5L2aYF9dhnWVmFvYFSndrGXXKCURwi1H7XT", - "marketBaseVault": "2rrqetPVk8fnydioAcz35DCjQsSnXXnXPZxYUmyvGjSc", - "marketQuoteVault": "368LHyWkvb6xnqjD3fEyyQJxyFYep2uLaU1DPBu6uVxQ", - "marketBids": "HRuZXUYe6GPXPRB63ySmV77s3VkF9EptrmrwQqegnwbM", - "marketAsks": "psPnxrRqoicTGiTyyeQ7LCYWvVa9Rdt6GFzk6v2EuQG", - "marketEventQueue": "Ds63jEgnEqYTPeLXHGMMkyaDuSu3i9TA7NsSjmpaDk13" - }, - { - "id": "Gn92NDQq5oGyydvGFkzK5zwJTymcH4xKr9VkoAmz5nc5", - "baseMint": "Cx7Rswv6MNyaBk354BohVvBP6mCPFo7FDjTwCYDXkajG", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BwvmZ31fEvesBifpw3R6A9dboPYxJpBayrhMwCqXnE6V", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2MDcGsPdTxroC5F9ajkZ2FfsR3DRAuPuJcwLzZc9gaAv", - "targetOrders": "3jLNYqC48HUXmLeRzTPJvxQxSAxjW8Wp6DZE9iZjNow7", - "baseVault": "Nz4mMhn5p45txu4oDJeW7igohE5XusQi4kPpds5FdsL", - "quoteVault": "GbUnWV5Ww5GEceCgyMvDkDYiDYCWSvLC2zPDYxdscQZK", - "withdrawQueue": "gJdPXZTM468cBTLMkSCcuCkHM2B1ingHLv41RVKu76S", - "lpVault": "71p3KW4EqufGpoiPuQp98489Y56CeJ5LmF6dhrS7KfLB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "gF7QkPFurpij6zkRZyhSANLjXDLKBL1KdtSzkjyt7hZ", - "marketAuthority": "75bDu6SN1VzVezwfRzpSTU6QGFJBAq9QYZkmLW4K7hZu", - "marketBaseVault": "MNreqk4vGjEaNX14RVieaz84tUuGqD3egyLSiP7njyb", - "marketQuoteVault": "B8YbZUtU44yt42cYHWF8tHuUtRbGCgmduwdMMGYtJQZS", - "marketBids": "57YZhfx71CaEs23XgCv87GaruCbXNC7YY8BaaSM2LDCf", - "marketAsks": "DB5CRQd1wqwhNRwnoUC3musE4TgnEEtrB1t3aYfoqXhd", - "marketEventQueue": "5avUZowzNmJXarDL21f23Qv38W48ZB59CDUnXPTpFpQi" - }, - { - "id": "GNgEmtZjteczyAZJ7a9DYvukJapRxfHWtg56L7S5XawJ", - "baseMint": "B8kkGiqC8XRWGGNxhYwgMbAiudEVRdXuPYtnKUctTZrF", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GGexW7zZzdYbDsTPHSQHjHWndoGsqsu4yoNXYgY4xKuJ", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BdSbeY6LN2bTHWXky2Fshuw9j5rg1yihD5MnRSuoLgt1", - "targetOrders": "EQVrgthmpwYwC1VtBpw1n9hmmT99o91N6uhKoby93cnS", - "baseVault": "FZbuy8N32xBNtQuhSpYojQn6yPy3vzhQ5oyouTTx3wLb", - "quoteVault": "CcRfmt9bpiiUhgpdtu6gjLadZqC9HbJ3zFfx2Hy8KYVG", - "withdrawQueue": "KpwxSZbwGeF5x3zchm9ibiv3AxNoqt1U9QgMCsnNR9h", - "lpVault": "GPGh1YmerFkUdihBvFcbHGkxaojo3PVhP1Sc2xmmTzXc", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CNi9NXBUx9VqSEoSaqG6BkTK95ybd2DSAyj49m56ZAM9", - "marketAuthority": "9RgHTwkJDWKhhFXqKouboWhSNCNeQE3iguYCTAck2S8X", - "marketBaseVault": "6KbG9jrqWD2Vfh3dVLhEUTuyaNKpWMTneBXXKW1bfsHz", - "marketQuoteVault": "8rSDWgyvjhgtQDX7VNKNAD1qYvASyiEH2AFZKq9y9tFx", - "marketBids": "EKjEzDoAEXoDrabsNns8Qn4bz5FpQapPNRghnjdUSNkd", - "marketAsks": "Ap1TuRMtdo2A2A3UTzDEvoHvX8eysUS3zaHYgEoQcwZD", - "marketEventQueue": "DSMw7ngVRuouYJC7sUJyXe1GrNirniWpMGsqVrMXKkkR" - }, - { - "id": "GNGwTNM2UQ4JCGURk4bk2BXACJnE8iSCeRqy4JZyLhhb", - "baseMint": "3LDAW7enNUZ4DjE1jCi1cDpXvXLrJ1rPiECPbcHpMgG2", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "8xahzsk2GZfzqnxDmEaLPRAb3ChWs7fc22H1F4yf2wsh", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3pwD5Ezk3hEfAHNVeYi2staAB6J7kSMKMtZiZP9pcDZe", - "targetOrders": "HGipzy1JhPbob4VyrrcJKHkpVascfB9NC4zXbcacTCMi", - "baseVault": "2b3MyTANhgbdqj8qHDrUaBtvLH1yu3zhUMSzSDryuXgm", - "quoteVault": "CfpzNue9hLTScQYMn6MsfPTpRJBMPFgHCaqRJpLupWhY", - "withdrawQueue": "5JF2SKabyogMM3JavoxrjVU3ahDcs3yjZChkNqrN6exg", - "lpVault": "BSdpoKhtFesPKq1DnzYePtKUNPQPfqc8kW4oFED1yxC7", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5VCeuHMKwEPHxYF7Tb2HV9MXLkeg7di1jMGpn5XU2CjY", - "marketAuthority": "CeNQqbZSNxi12Wemi11RzYBE8V6vVG44JFDU3yrihiGn", - "marketBaseVault": "7K6CRbTYicnn77mGqaZWuZ5b6Mcs8XThD2kWNZ5UZUCA", - "marketQuoteVault": "8wrF4xB5n3GdtuRzDT2b4yzAmUhAe1bcB5WJuL3cSmso", - "marketBids": "E25oCfdMxQBsYzh9urYLZbUmh6hFtHLRzpg35J4Wu7zo", - "marketAsks": "F8Wc4K7HvWDTYT1GXNwWCGPCtR2PKh9wLgGJ1HCX9NDc", - "marketEventQueue": "ATDnHoRvfH9TdGQbVj17J78k3YFQMYsQqzNwgjVn114L" - }, - { - "id": "GNtoBHpQv5Apyi8TmR9cB2KAmPvMWkTkZgiYyp7tDa8H", - "baseMint": "HZNpqL7RT9gxf9eWoWsWzC5DfjzQ41XTQgEA7p3VzaaD", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "4A2fet5sgDy36KviCH1MvwAi4AfbsRqFgJv2oYJD5hFu", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "A4nNXSYGiMKA9zU99xwJV8sct5YQWAk8tSFWJRXkVVoy", - "targetOrders": "Fyv77zHasokdJDUZmvkYQXrVfuPkLmroZRBEHMribNP9", - "baseVault": "HEzhdKDVyeSqtWPsscZuVCHefAe7azbjVioxAphbVbrG", - "quoteVault": "EK2Ng32TNoMJ8SDNrK4FHsPVsVxr1RbGetJN1NMdDhbo", - "withdrawQueue": "ngXsRF4FL57NTmnzHXs6JMWoXrkbRG5c9GVSSkfPT7o", - "lpVault": "CEXyQk44RNmTYRCLrBHPjrw6g7eG1Yk5SttL4JPgbgXL", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GWdhVam71asppkReSd7vszrJbKuBcnmcg4hhdrTPmmBX", - "marketAuthority": "4aki5utCYmvHp7HNxpjRFF5gN3xwNDBVUqdEB2bkv4Lc", - "marketBaseVault": "CzJHAz72ZzSWLzDVXjEgSvsufnfprAxovKVMgjCRFz3x", - "marketQuoteVault": "5mSe2MaTv3h2nNnJhpe4jW2ECq8hmYLvrpjtSy6nSQmc", - "marketBids": "5goUUXEJPs3G8a1LDvZ3Qr9SmyUSUjAhP6aWPXir6FvS", - "marketAsks": "DqE6zWWRn9TdxiNd4VDwRJeFgiZN4if4DvZHiMW2ga8X", - "marketEventQueue": "9PYBxdTmuvaaLHXGYi4pRL1kAv1AvKYzrbArc5hy8tPe" - }, - { - "id": "GPge2bpdRZbQ1EXDnr9yEseGtB3DuJYWuAKSGXD7tLZ6", - "baseMint": "8RSyhCxFKYVnr6PGTgKC9o86AjbQjdmLRZjYJjhdTdYH", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2eN9nnXuQaEQAy5dRBdjL6kwP8euPrdtv5cGEtTgkN5J", - "baseDecimals": 3, - "quoteDecimals": 6, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "A5Agd4vQxWaMCVhxujZco5pqLoWDCjrqTxJnk5gfAnfK", - "targetOrders": "GM2yD6fyqt7kzo1jMmzZuB5jCQPHDtyJBxRsPXk8ZNj9", - "baseVault": "DJuRNLYBGD8HcePhaoHWV9W55U3moAFzY1Te6PWf5Pbp", - "quoteVault": "5sq4BBtALL9TThcUyDLWDj6sDpgenJSpuVjCgXsB6SJU", - "withdrawQueue": "8om6EtgQ39vF8DzH39wyFxUCwkMyx3Mvnah4LR7kg4iB", - "lpVault": "8deDE1SUnsbvAggK6Jse5ycdcwddEtg4cfDN85esJL1e", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FTZmqa4egW8S1NCDgwHyLEPmnQKLzkeuWCi9wFtHubY7", - "marketAuthority": "4WQsuio7i4vAQgKdN6JCePYkZGdYJg65dvQmbEM8EHWC", - "marketBaseVault": "C2dfeFB7HD3vgwmvMA6poB5qgKRkaefP3SWsR5tCSRPS", - "marketQuoteVault": "FthkFhpnBoSeAeGfvuMwPnxroigYo3z9iX5jT4a9pzqB", - "marketBids": "DGSRkcZRWdeoeqBMTvkQWePGz7ihz6Sw9LD6Zff8n7eZ", - "marketAsks": "EJHJrd3pWPJE1qHJnoWNZWmhjKiGqrGSovdGut7rYi6n", - "marketEventQueue": "3yeccNiqpYyY1wsDfGaqE8n9PoC3syNkfy5EKVUwhtk9" - }, - { - "id": "GpmRFeSFYzpXRRMLMKL55cr6bp5xGx7R3ASn19jhT9iJ", - "baseMint": "E8bT8g4so2zPnEoragg1wLCz29VXddqjf1acoG5YwTJA", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CsvyP4YzXVG8KqtvvFgmTXRK1GTSDfB4HggdNvQZQvZL", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HkQmp5GRkFmuKVYd2QZbXoNWmryP6sXgdmBrvH1pdFzx", - "targetOrders": "2zbWTwbuHVuou9vYXLQ27F8qkU9zMJCAd5U4vguuQNQN", - "baseVault": "7w5LtCkfHonTNdqqyn9CijjEzvSsEJB1LTbSTjuP6GLo", - "quoteVault": "4baR8BZ3VyCn9WXPGSei8nUyDSJLoiQvaoNtApMTyoWs", - "withdrawQueue": "9sQKcpcwszj2PE5Zo5An8xKUcyY19cwSPAw9fLuzEUvQ", - "lpVault": "3W9p5XBerBc3NrbdKZz9cfvS8TVfTSPChQw4wR41YX2G", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Ew532ggZBH7aE7FCJBs5gEpG15QGc4NAuxaHvFmEGqvK", - "marketAuthority": "9HNhJmC2azeMoJY8tBe9qpGD713fm9R4JRCmZEe5ah82", - "marketBaseVault": "H6dugGsbdyh9o2rzueLXEFCmcVsBcubaHuSMz63yHKv3", - "marketQuoteVault": "5j9rVUKFZ7avk73svckBEXrNhC4qyCZBgMqYpRazpbdw", - "marketBids": "8CXXUHd6Q3zSHd5wxYp6gdBCx6eBvYUtAi219Tz59Pnj", - "marketAsks": "6JDefA7DLvhxTpYnLjsvGd7PUFNhad3CvanKpMWtAfLp", - "marketEventQueue": "AQ485ALTwffkoKxqjyNR3Zgvw6msKjjSogcxwKn1yMTL" - }, - { - "id": "GpXtcXzB48tsqgDhqayABCMaE2iEEvbn3v8t8p4Bvk97", - "baseMint": "mongopjRpUgnQQpQFiasgFLyo69YXUwFcw3hyqaN8RL", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4JxVG4ngdhahXFhU5x9yCamj4aPpSwzvx7gfSr3jSaUH", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9MC6iikDp3EACCXqbxb9JyQetjG2VjEEh2Bie2h98zsT", - "targetOrders": "3vYy6cgwKML1hZGVpfRZsm2p6Pb6mdkeDeJVHrquBsTn", - "baseVault": "GshMV3URhfqb55iakAEioGmQDqWgURazB7Ku3jEKEXr8", - "quoteVault": "Fj4MSUVxRDihioNW8U6t5vE9tMwVSLWD4FK34tT3h4UZ", - "withdrawQueue": "5Ee63V7Tx71aPHSjve8KXePytheWwpz3M2AB4i1RREBd", - "lpVault": "8dsQZqxuwvL6jemCejsWHFq6jJqioQJH2UKG23P87uMw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "H6NPcQVBHrRggK4z6NLLH3aE6hrHDcjL98CMwkRBCxzh", - "marketAuthority": "EYsLsuk24e452u6WuSG6G5sAtrxssRTf3LYe6DUXdhd5", - "marketBaseVault": "BVMiNZNcQ6dgqe4iYohs5wdGYgZAcwtt8d4jz8JtY9H9", - "marketQuoteVault": "68Tc57d5aP89EQsupVomimC9LnM56V8r2xyD2dvnRR1B", - "marketBids": "6SLs42zD1gzEGpqNcctzSEBzHQujxJuFy1U6DzUjXmC3", - "marketAsks": "FuUomixE9mVnA8d8pwx3SQgeABxBL6kmUGjvDxCk2xCT", - "marketEventQueue": "EKg4avHgyuBQwU1vGRokvkdei4acYjKJQKA8rTmbu63V" - }, - { - "id": "GQ1nQmfne4XQVSPyKzjRdTEbAgGupENMsB3w7sPKrEgK", - "baseMint": "8H4eH19o9yYWCGFQLe37fQhn9Jkb5TUVw8bwW9cmHNfu", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "F8qoxY54R9bvwDC51GNBug9juhMEV333KRYTMgUmv8mo", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "G8W617jMghp8WyeFw9Js3ZPYu85aXVjogBTdm8xLCezw", - "targetOrders": "NXadoAxid6qu1EhchdVEcENZn2HmUdP3EzHGsC8sMsx", - "baseVault": "CY8YFT8JW6NqdbmJ1vFJNd5SnK4o3cPpv1FWNct7aXcW", - "quoteVault": "7QNswg6Fr6742KqFn9UHsgy588u9Q23dAUFQ4b4FVoYx", - "withdrawQueue": "9pSFNV7Q4nPr1rQ5zcnxsVYR31e76CnCM6qNtSzZcKq7", - "lpVault": "8wMRpoXwsqZgKLEH2CeK9drg4zrLuqJjgiMv1cnTEJwM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "rg7cTDLMD7esJvAacmLRHwmD15HiDXsnAbCMQ8VM4kg", - "marketAuthority": "DByaPUvz3M58WjjF8Hse2hxdJMgdGrQvucgt9FsxzRgY", - "marketBaseVault": "Ho5fEsf8WbimvFX257qatCU2aSChFJqdJumwtq1D7EGw", - "marketQuoteVault": "6sh2mJnCPRzM1hUCXBP577Rni6SAgjgJGz3nxP7G1nL", - "marketBids": "7x4xpRSpWcaDCazD4dni7yAZ26guKyhttg4PZ3Uzg6HR", - "marketAsks": "D2z6ThoYJMCnLdeS2nLFePUY6WNF1s9qLQgHbFFwbvNA", - "marketEventQueue": "2eJRVRfq6FoH9jVVQRZXGXgQqgNLc8SMiiiA4jUBro8n" - }, - { - "id": "Gq2b2wBsPpuES5TZp4xyK9w1ZkvPQUwFDGnWpLFBgXY", - "baseMint": "4QV4wzDdy7S1EV6y2r9DkmaDsHeoKz6HUvFLVtAsu6dV", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "A2AVfGS4T4HEsWDn95qb7rHTU1dE4MmEYr4zRUKGLZVq", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "J37wSA7eBN3hM2GcXmKBrr4y3CEhjvDN4qLvGngVrnVr", - "targetOrders": "7SajqDVyfVcH2W8DpCYUsjGAMwSwUeeniHMiLi7rxxaR", - "baseVault": "52tVoauqQLVGmka4DnBVHqi27PeTV1ZBZmcC2HrT4JNR", - "quoteVault": "EMrgF181HegRYJc8oq8jGDWQ5SCqSSt89yF2fhhAXZW2", - "withdrawQueue": "8gpcwt4PEG9UGecVnVWoRxT4b2yfFSvQ7vrMhgYGszUH", - "lpVault": "BS66RHxvGbDC1tL27V6DJ4urpcYShbKTfxLjgFSoBNUy", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Ci3wLTY3X9iuMxDGErSNwfWKcrhwPMugk8yWTGBvEzF", - "marketAuthority": "HEo7xfd7KHoTK61N5oFbrttseXbuH1SkJWmrUX4F6JfJ", - "marketBaseVault": "CL9D2xZPAsh8o7j9VftmgB1GUetGxeuhoeE19ZkcrRLF", - "marketQuoteVault": "4nftC6U4ZbgLng8Bd7u1UiVuwuMWhiagJwgktCMYngLA", - "marketBids": "4jGviwYCPBsGdcnGFaRr8gTN2cad1kErpLdryoj9NVuK", - "marketAsks": "EPzXtTeGKd9vGyXp5vceeDqyYt3veHbqsqpET6Js8SkN", - "marketEventQueue": "EcVf58CbSMWkNsS5fq1oh2QwFpzNcJxqrgmkMDQhC6W1" - }, - { - "id": "GQ8Jnr3R3XxC9K1aNcwusTSJZQ4wS5YSP9vfdnD2sSgo", - "baseMint": "FjMQibN74kDTDVwGhMjoPP9YjsrGdULwnCdxK5U6Hxxz", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HSyab5A9AA2sENDLepAcYWV1iHojbfJtbmjLmAPanuwp", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DDRJJFyxqJ3a9fP8oVGJKqP6wqCxjZgHC9FVnHM8ZMJK", - "targetOrders": "43rrk6QjmMnDMLTaXU49Ctzb4yYhMp3c8rx3Nt9buKgC", - "baseVault": "FcycmsXt93xdVwDWdAZ6iQ1T3pvwMJpxgmvpmNfASbXY", - "quoteVault": "G8HauSwiY1W715UzfBNg8JGnupGJxAMdx7TPakGi22Uv", - "withdrawQueue": "4khHkefpV11XjkKs1qvo41Kqxq9jfEH85XnNjyjcjikm", - "lpVault": "8XSEXmYNq3Pfni4yW2nAnZoSxqTBayYKrsLkASD4HS1w", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4M3x8QZvHb5YpZHHUSG6UpFzFheNKdMpXUnpULBoFtYp", - "marketAuthority": "ELt3nd8dgqeHyiRc4VcGfASE54RMun2HQ8mMXeFebFQw", - "marketBaseVault": "9qkc5m8tH6dgk8DyDw3FJGYatTxbayBuQHHwg6ewGvoR", - "marketQuoteVault": "6a21nSSGeSpUNL4AfFFqV3aBkQnRCRrtX3FmB5kQYDcL", - "marketBids": "FhWGK6gWZXiVboYHUWh4K2bBZzZFX7F7DpUzgNqbD2NB", - "marketAsks": "2nZ21G9o1P2wen3qaRxyNjLBGfGXek9nEwqiv3uameJH", - "marketEventQueue": "CiKp24Yd2ttfBcnMz95C1eDy6b35b6M198VezGfyCJ4s" - }, - { - "id": "GqF6Lc1Geyi3LuN4SA4aNHfy7ENdKgAeunXg2PLM6pwf", - "baseMint": "EG9JDbEiCFpQ8a9LCi8AXskKvqZy757n3yFCnBvLrZRd", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "2yAxpgx8gTPVjTz2MSfm4FofnZvqNhV3VdYDLwYwCWkn", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ACGjn3p5eiRgCFadbgkSGc2ZhHLEoD9rH7BwTQaW2MCu", - "targetOrders": "HhhtSbJwVFdpybWCi9vNt1HVJNjmMEmqEysjT2KYGgWs", - "baseVault": "88DuoG4NrX6Ggx96tbX9wk7sdrQZfTDmjJuL2xDW7njU", - "quoteVault": "JyMqrEGNqvAKyeoUi3sNFENMdYbmMFSjPbBNj2zHZik", - "withdrawQueue": "76zV3sdzCRpp3Gvsr1ukQ77Rk73kN92i5vL4sg6JdxsC", - "lpVault": "Ej5FCbW6JdNsoU9zcEAm4vRM2ceombRLyWz5Yr4EvP51", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HDd6nHLTdmp9xtTqp4ZNmq5NyqYQ8xKvXp4uuNxdj59d", - "marketAuthority": "ct7XZKDSwmKT24SC7jF8XvG5mVxE1yzRruvXWZY5ezv", - "marketBaseVault": "2WTYys6GFrj6UL2y3z3qsM21ujRRgmt8tYQ8Jvs96YBj", - "marketQuoteVault": "9SmDitP1GNbGRKg5BiamnhWB6XinkwADdfvkvDDcgpqc", - "marketBids": "5nFF4teVheTwR5BDpYuDeMwatjUtzjNbDtoN3kHtaBbt", - "marketAsks": "6pmTEtuRyEnUZpJWKa54n5HFRcgUnd1YYXHSHY9GZ7mu", - "marketEventQueue": "75DL7bBDNebvMp6PDiPGARLVUgCqa1Rx2Pkw3FfkNjWP" - }, - { - "id": "GRZ69bG1L3or3pHTc1ki8bWQ1LRQsriCBQce9HBX1U4o", - "baseMint": "ByJ8a9NWk6G4Jg4iFyFNdrya1iVcusL1aL9aGXWXeoVG", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4v3XE5a8Dpev4AsWTeVyc1yQovCtSxdwDTp3hktLJody", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "53u5czE9vNsZdAEEmoqfs3iAr9TBRia6MEgp7cCrozaR", - "targetOrders": "B9YLFqL5N3iMHweFgxqo7SMi2ospVvPjKQM4BFV6znyC", - "baseVault": "DL5q7YUT6wMqsyuAF2KC8ra3opGNfn74MJebC7PH38iP", - "quoteVault": "CKk1u2SqKyCPrTH5SEXaF5Evc1Si3nqGNR5Q82QNDyvp", - "withdrawQueue": "5b9NsC7E7V259gheSW1q6dMH4mhnBydtFpmvWvaW9Aji", - "lpVault": "FZApWKkREwdWPnp4zh4pDA8fcySa1Hb1V2txFDxRjRp4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8Gdhg2SrrCFPct9zaywcmujy8vXoKp1SYGsUhVWcqD4C", - "marketAuthority": "7jf25UUQLaq5dcMrpK8SYCWQEKa51AUPYLjWzy1s5bWr", - "marketBaseVault": "2g6jaxfaAB4ieP2QPCheaGXLBiDCakTLKpMcveGDDwMW", - "marketQuoteVault": "Eq4FFSPxbMbF1BfAsiefZ7FwgiDu2sL7Q46pe2JGs4Jk", - "marketBids": "FvtYy5Py9uMriWUjQz56R6iDHjzp7XWzQv8QhBHfY1GK", - "marketAsks": "EMJfePonKCg6ppzTAw94XLR1eyHQDdGP4AziGwchFs8M", - "marketEventQueue": "8vtPRM79vfgpXWiFo5fsP7hddid71Mbw2PaytiNFBWSs" - }, - { - "id": "GSAXjFnoAi2sfkU85UESGMXuBoECqpP4dzswoadRjJm6", - "baseMint": "DubwWZNWiNGMMeeQHPnMATNj77YZPZSAz2WVR5WjLJqz", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "B84nUFEAfkXfeJfapJEm2oGbeUUoVcLgB5MzrPe6xZyW", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4zabzVZQwUzfhvUZJ15PZei7WwGgAKEYok2tpKWrnFTi", - "targetOrders": "45efhfejdZ9jwSeXHCrCDwhBTiEo5pYsroyxAy13F3sX", - "baseVault": "EqJwiEbxPvpVxCBmpBAYohCjvrChyDCfWn2yYnb2Pzf4", - "quoteVault": "DEzZ9dp1JJmRsJoKLqnYSJHz7qcQ4GEuvCaBU3atS1By", - "withdrawQueue": "5ag5s1SSmQFcebVfCevDTXTfGA4Mdam71jJFxywmMZKf", - "lpVault": "65hhXKBQWc13Lv1w7w1hsgUz1xW6B8K5aoaF9qnqRK1B", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8nXjHLfiR6wB22J7VBGeKjsRiSa54Eu7cgL17GE4kJUw", - "marketAuthority": "FkMxmqrER3mYiTYvChYUmHxXhRBgGxM5sVEamLizEwhp", - "marketBaseVault": "5KjPQbAHoMGPaZ9E65pRDRCC36keEuwzvWQF77LjWwnr", - "marketQuoteVault": "Fmt9cHaiGHu2pzeEdPuKkjQrwixV8TnjVMhC61CSYgF6", - "marketBids": "ECzFJi6Zk2Cd2BTLNwqUG43wEiuL2CGcqeB5CPujL669", - "marketAsks": "8Q4ptjSPzWJFmtnaRBcptm7Cm7uxzniJhFMsF7fjNc4", - "marketEventQueue": "GzbTX8QsuJdSJUeQKLDTpJLofY57XLBm9eYVzPEd4WHk" - }, - { - "id": "Gsmj6L3jVN8TiWBPdQSqSnrsjxovst1AbpeFZG9h4QRi", - "baseMint": "BtxmGUJHu8iqLu8rqECHhwDzbX3J4EHjA8NbtjiRXUoJ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5ZFkUwLEyH8HvRJvxP2DT8jD1gMkSVazaebNNkR9t1QX", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "C9HTgWmajkjMUG2szTNnmBtGLa2zvVHrHGopc8GUqMQX", - "targetOrders": "BS8k9idktxSTu6bSdKLzETZXHJzmbxHUrmWE6RyBqspC", - "baseVault": "XspkNcqTiieDbEF8B5zfJs6q4v6nTMA1uc6PbFXdHFL", - "quoteVault": "5eHaGAAfQf4rqXhYWyHDtd2enNW5NJxAAz6QZQzgCkh3", - "withdrawQueue": "Ad5a5ajWDNTFbU11fSn6J1KetmpLnP9Qut1pFdGhNfVN", - "lpVault": "3ywMKckH6S67GnFpPu7o9XkR7zp7VFCX3LPVUwkvEszQ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6gGrfP6Fvi4oQ2n6t7s5trmAQDSshV9ddvV1jyD6Cwtg", - "marketAuthority": "DZ3WNK4g1ALq9WVzn4crb5dSisKtYFq3W5wverP6dY4C", - "marketBaseVault": "ELUpAzF4JxmabaoGKVeUkfy8ahrTBtsWbJhJDC8rn19R", - "marketQuoteVault": "GyQyJiTFwDTREfrdZDPCpXMvhgGo8Xavrp1ZTeAPcMtw", - "marketBids": "93xt7KFEHqUPZSmLh4DUd7hXv11qRX6qA7jnG2KGFRgm", - "marketAsks": "9m38vPHCC8E8BQzHHxuUVeLtGCJGEg2cbBfQQpnYD6zW", - "marketEventQueue": "QMszJcGn4KfmSRRyv9p6dpgnj54KNRVwXkLZHvvaz2e" - }, - { - "id": "GT3y9SpLkKiJh8wVro9ZHAyxy1sPmjtbjF6FRv6mDVh2", - "baseMint": "Digi7SnUD9ddiitEqkNfby1c4BfkgokFKWu9KScbizes", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "2jJpjqyYAGNMbFdYWssVoxwGKVQb3KfDPe3W39G1iSXH", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CEdRy3tkV5MY2mS1MQi1ZfUZyD1HXybJmHW7ufQi3zTv", - "targetOrders": "2qpxSXXzNQp2TznhH9jDg9YpLTdJoPESfqFVfT7FHWKF", - "baseVault": "D2cYEbh8MsjJgfrfzbrCHvom5m6Yfbs2zAMf7qhXXnZ9", - "quoteVault": "ELhFTDoLEFo7pZSQbGJC1Wxt2veATfGekwJtbYCRED3g", - "withdrawQueue": "2oU8HPEaVzJb1nH4DugXQEUpfbc1yHqwmxrwueKS5YPu", - "lpVault": "9U4Kzzh3F3NL5CWTLLTdVHWgBac3FUvMks7kEK3DRkRh", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "E74Nt1wdgkTiTGZPEq6HdGUm66osWydVqNu53NXGqaUV", - "marketAuthority": "sidkGrQhqenEpfa8YyfFZMxegL3GSuF2z8UxfoYzcjo", - "marketBaseVault": "3kP2eiwmNgUoPNYJ8FupyEQwA6KYMmCPDbHMTcNZ9W5x", - "marketQuoteVault": "AstoUxx1gip5eGxR5yuZcDJ1j5PVTWBRoQRFVq4pHwGD", - "marketBids": "3DZ2hkAXLXAKCru6jU9rV58oc8DZZNhWmDsdYdG7p5h4", - "marketAsks": "duQjpkekRUNdjY9JZbufFjo4DRMDxddJcuULvztbZvU", - "marketEventQueue": "vmZiTBaATqgukdcJmx9fPUjNW3asj2LqpDBdbDPVVLL" - }, - { - "id": "GTg2JHaaTyz7DXknwCNVPSMPLognrqXUm6uoHA3j1JRb", - "baseMint": "HJbNXx2YMRxgfUJ6K4qeWtjatMK5KYQT1QnsCdDWywNv", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GTy3TKmh3Ejrdh7iTALUG3PYv4VC7wgwM9vGgdLj6Rus", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3atg3g6TkshhS9fsnBf9hArsHCYyUQG9fdPLC5SNzgEW", - "targetOrders": "CJ6X2FuFbDbADzZuAiTbtRsfh8j7EZzcFnMXEndnceqS", - "baseVault": "BA6pvLDkEipsxWTQTFTL76Npozy8KGmPwWBzQ4hyPxrx", - "quoteVault": "4kUo3sQMRjVwbyxPtVS4hgANXpCvXEtKVhdgijyhXv98", - "withdrawQueue": "ArSS9E1SiMabe4FJAcX35PN3B3Y1seVQed5yir8iFnYM", - "lpVault": "HmoYM5H5zTgh5WBPmnXen1GkESvNMEPLgE7ZUbxP1MuX", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6NvErACd7kKz5uPDAfXKahW9sFooUJvtfRh5Kzq6GH9z", - "marketAuthority": "HydTyLGBPmkhxhTENw1B1FEtYYccqF1SWfHa8AEkKxRh", - "marketBaseVault": "4zEPqVMTPqtGXB8ciRvdrLPEAwr4RaV3ZECuptqMxYbf", - "marketQuoteVault": "ASZPLhbA2aH6Lqjt94vbeUEQtcj17oX9tKVU7wRSiyDt", - "marketBids": "26X4cVMDaLtjBZCB61zvWfUUhBKuJxLypR3q6KxWisXD", - "marketAsks": "DasuF3LWfqooCqTnBhUKMLb5MdUbBg9sXqCDKcXksTXN", - "marketEventQueue": "D96hP36dLrTshHQb6hEcrNvhpAHeLhNxxk3tjqNSfAcG" - }, - { - "id": "GtmAXdWvDr8pDZ3WYdY7wug2B7VbpWjSmifx46mjFCGD", - "baseMint": "7Af1biRuBcAQTEU3YkWaGGtQDFoxYmqLMyrBNQKnuogn", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DsErq7dYo1CQRyQKLjPzMPKneUi7ZSMm4ZrhYvweWH7B", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "J5j7ZDGWBg8nsdrZfrfbRmfdPc7nkquCMnGG5ey6qsrw", - "targetOrders": "5bms3tFZw9Mm4WT4Jum4EgTEctqsGEaaQyohWnjCQaY4", - "baseVault": "Fai8JaBNHHeF9QEsxy9URKR7Y5UEmRQqvgS9WeESCFMW", - "quoteVault": "BbGr9mbDGChRsy51G8CbjXycQoGPh9YA5DWsxDXbHeHk", - "withdrawQueue": "9wNvzjaKRn9ELR6dyF4w9B1aeZbxKaXSuRwC6yuqukbq", - "lpVault": "uYGks77Ep5WdjLifNR8vUUyDNef7xEHmdkfLiLknZtE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3gjdidibHqrf3mUYhNLgWWaeHq2BHXHW55cyPNFvmCyu", - "marketAuthority": "41RWVL3GpQt6d2TgjbPKsLZwH2Awskmb93DqsNETuNDQ", - "marketBaseVault": "12k5DC28WrmsU6SsGtpdju2D1fofrBn1X6fAmoRSFoJw", - "marketQuoteVault": "DN2YCT6SaEd7X1adSDUJZeiDwggHwWGNZnxswGxU3rrW", - "marketBids": "2PeWpeaFsgKu25zUP2fWb9QcETnQzgeMWAE3rCbXUdE7", - "marketAsks": "6Z44EsMYHnTuJyCC2mMkqxEd1CJZcdJmgN3e9Vz1XQmR", - "marketEventQueue": "5YLSXP3HvQcMk7wQNEMK8QXZL6FNjAeLhPxwmWQAWp6h" - }, - { - "id": "GuAN6DRChdmAtkG2FQ8PYBFUU9S67hq2YefucF7LUzST", - "baseMint": "AsVNhq2nnoUgMWciCvePRyHk7xAv6i4ruV6oRHFWBcwF", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DNC4NqiWgPopt7rMG5J5sCXEB3RGxnrLxe9V41i7W5fX", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6aFvta7C3gWnE7pUjgV4nLWwiZFwyEkbrtTxTvHekpTQ", - "targetOrders": "J65sssrxmdpwmnFqSYxpyRLj29CVtiupbb6UDxGXL7Rf", - "baseVault": "DFCB4CzsoCobHynjEPqRQieVY6JBdfL54SrQCM1Z3Ryr", - "quoteVault": "EhtiqzUyJP75BnCBg6BuRJPX5K9iWzHK5HAkyvX1uGHK", - "withdrawQueue": "H8UiEq7C2rkvmW3QbcPPomfkSiiC92UCMtz8VhUoDo3L", - "lpVault": "DNjDWTiykZaojjKaj5rsfisPFQdfZmFoBVZjtXCUUSSC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Fc5co91LY2tiZAVuvCmVxDFZWA9SVBVLuxpBcYRQbH1T", - "marketAuthority": "FQDyuz5Ame3QKzrZ1hdFA7UcjTWDuQNSzBj2YSxrpCB8", - "marketBaseVault": "7cCF2iGz4jZJs6TaR4eMjo5WUiU9zDCDKaevQyTsDzjP", - "marketQuoteVault": "2NZwU43kHazT7Y6FfrnNNpvCztjPCdYbURpmWMYr5vYt", - "marketBids": "FfL8jNeBD2U16odGVNQWcF275MH8DSKPXQisx83sZExu", - "marketAsks": "CSb6sKKJPCTWvMRWzgUztEJR1BPg4FGFUujGQ88cMR4q", - "marketEventQueue": "4mZgycfJM3M2KTMwyJ3w4XQ9D3hEUQ92R6o7PAAAHi1Y" - }, - { - "id": "GuGLop8jz6GonDHLEJbTGeng6f5EbjtqdCrVaTygue3H", - "baseMint": "D3gsYhxSFAzYeyyD4VBvDYJMJH2HM7chVZXkVXUmCcKd", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "F4tKLt8EgPLbnMqeb3ycB6jBWt955BSCBgWdUvD6MpJp", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3qbde5cVC3QfRmjLPDcgGG29BadGHhn3oxfGfQJ3NMGP", - "targetOrders": "2ShwfzXyHwK5Y8Hwv3U96TAURaeDJACh8PmApggWBDaq", - "baseVault": "51Ww7Zy1cTgHU1rMPWS7ou2sHZYYx5CmJ6zsjC2MEd9n", - "quoteVault": "7wfXpedRAm2HKPkeCVTz7HbvxPVNYNdDSfTzLtRgtgmU", - "withdrawQueue": "DhgLcidtS9aaEku7E2sBVtdDKM1tFbVA9r5NGbRNYxy", - "lpVault": "9Snb1em6iYvzBhKk3XmnsHifH5oKG6H6Dp1ZybhcBKn1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9x1yYxRBx45vRmREX4m9fyBNNCXRJRUiSkcJhVsEF7cU", - "marketAuthority": "7TmAwguXVk1KN6QuXemsz84d6WUdGMZ4FsFjXLsC3Mfm", - "marketBaseVault": "VAGeMey3eyj5YP4cB9SfGWjf5wWmrrAoYbZXUSkgd7G", - "marketQuoteVault": "Dg2qdc2J1cHZXh52ejHVobateoNz4fxooYR66LSZHaTZ", - "marketBids": "6zxFm2A5NrQhTVEGBivcfTCYNFCrjNHmKusdr1SEHHCm", - "marketAsks": "ArGounDnDf4gYvEZv9TGEAHK7bYNgodPxccF6CGF6z7t", - "marketEventQueue": "4Sez72TUMbmWHi3yCqNMM4cwJ8qrnL6sR2RmUvxotuWY" - }, - { - "id": "GVFLnAdhpkDU9rXDg9btsCrSPoyJ7NzkaeLPP3P3z6qe", - "baseMint": "7vKX5rx57VPE1ozJesFzojdPjGZ3M89894PT27i6seUF", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FJYeEwNKs4rUgNkD8416uLN2cWMDatgmgaq1ShFUR489", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CoEMuJxEsZEGkngKHVrgh5A9BuHydnZpWskMH9SLCVxv", - "targetOrders": "Qu37a4cezbvyCmJWKFbKot2LeRuqGZehx17GbSgitke", - "baseVault": "BFx3Kphe7zFRnGekUHMJYFZ5WZxnjW6zq8LxQqa6AUZP", - "quoteVault": "78v8djBnV9JJqqiZJdn3psWV7aCBdTwcfP1xNnYt8Hiw", - "withdrawQueue": "5cXvdori7H5M6bgh9SzNHwo7wypCNbYt1WUJan3bqNbb", - "lpVault": "4MFMFLBCyXc5733PYTZk2GBpujqLGhEx1HrF3zVCyetV", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2iUznPCSp2j1wbHELAxdqJTrBdfoQAWGDme7hF3zCxbX", - "marketAuthority": "EwcjEyuMnXkbk6vqootd1YTpGNYdxVBRJGY9T16yq8N3", - "marketBaseVault": "Cx7mN1aCbbsYqNes345Z4ys45NveZNCzQ6GZvkqCFyVy", - "marketQuoteVault": "62AsEWdZeScKNSuM1as2yvEjmQ7VcLJRqvdaug7jnAew", - "marketBids": "D5Vmc3X5iEPf2eVoiYo74Z19LUyDyfCJ7imdrQaqcTQ9", - "marketAsks": "8wFs5KqmSNtU95J6Xn1JGsPexX6EJWF8SfQP3S48DWAq", - "marketEventQueue": "4vDJECkN9c2byFLvczLRLQom2tTkeFiLBKwjCFwtgSSB" - }, - { - "id": "GvsmaM24dz9tkcG7mzsyHTZDpvwXMA9ynXa3PAD7Yna7", - "baseMint": "3rkCq2ZAxoDGa3KWGebeiEMN92H5AV9HBLC9eVKDoPv8", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EARU68bo7eiJpM6AKW9ARzbcEUTm3xR4F5XvzNcX9zmX", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "D7bBvU8cusBAe1ZCBLh14kufzCh3MRYVkAvsNRen8mAf", - "targetOrders": "EiX2hdSycwasXa78zxgzEiha7R2mQg7JWyapyfpFymUW", - "baseVault": "6xW8c8vaZHpZGc7t4g3L8QKyC5z9BwwuMarsh7BZttmp", - "quoteVault": "9JSizLznBRigEjLreaapoLkNBGp6Snbi7CvDP2rhmQkU", - "withdrawQueue": "8EogETs2PRqhQD1CqkVZxvwMfKqYYRjFy9VoUPu2APXy", - "lpVault": "2RMB8KkLfwTuabcXtMZa6pun1EYMEGUJ9RBjfHviTsWR", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5AxX3Geo6YKvAt5FyVJJhjX8zBK7b11886ZCL3su8QXF", - "marketAuthority": "J5y4J2ynNzj3BkbLSLxrRaf2PkRmQCdAT7xMELkZV7mE", - "marketBaseVault": "9FFBEk6aEZ246xWWni6LKhMWYtE8hymF1obBK1m9M9r5", - "marketQuoteVault": "DiSVqdLT8LsR2hK9bGmN2rQY2xXggJ3JnotHdM91PVFB", - "marketBids": "4bj6TyjRjAtuGoUKLLpdDZYC6uHRpL3s4TKiTCDF5B7E", - "marketAsks": "HqiZQMoZ6Xp2WcaAxzpA2uoRMR9Lnv91chvop8FboJ2X", - "marketEventQueue": "9b4ygmdQUdapfwAee2CTNZoB6a7D14xhcFzCJf9rBM1F" - }, - { - "id": "GwdRavfhNJqrAMvVAEgjrWKvBrGmXaMaeuf3yaMh4z3Q", - "baseMint": "4BPw4jwHWqQCbkD2VWtLFL5PLBRmkHZiievTm1ebiWYJ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GNaBhn6LhFHrUfTeq9yxsUvsEMC4kLoF9DtcHjMixhPm", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2DSJFn4abiswmMzF4EDAE9NKqjFagBrVeb2eggHhHgVK", - "targetOrders": "CYVg2BSHehHWMEmQ9wAQwATGprY88yfhX5FyUt9qp7HE", - "baseVault": "2UCRuTjHTr3wjuPMDaCo7SwuekxHs6H3vWDsh1ADRDL5", - "quoteVault": "42YsxeEFHQ6yf46en7Vf6PwtKiaihewRU8YeLCp7TRVD", - "withdrawQueue": "GNnWWXrJbYU1Pe5uEPQpgGNRUtbPwAM3AJSAgiZXRNrN", - "lpVault": "CaDJK1LGsRC13uEUM5J8ejwbt8R8XZzKtD9yP1vAMuJc", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9YLPp9myNyurQiegpaxj8eYNvdGkfDCNcuaZMxhccZfx", - "marketAuthority": "cyfdhbVyqsiCPvtFWtu7VgfQhY7DLTub36A18Gch7tQ", - "marketBaseVault": "FtFmp9zXcy4bx9mGkVpa69KAwjYQFKteJubfzRdXxXQm", - "marketQuoteVault": "2kfaxUKHqQCfuwH5deM9drbGBARKBf2qrXvPuTzXdhNY", - "marketBids": "9vTmyte3tuoW3i7q2Dpw4ArfpUNbV9TkuzP2QTjEHu7M", - "marketAsks": "AYSxVfC3hAdotqgFuwJcFCoNSpvFy3ER3HH7rA7EFK6k", - "marketEventQueue": "3Lc1WyefHxdnm5yp3mzoNHFEZBsQgbDr8RHPAFsJWFao" - }, - { - "id": "GWovR3LkuJyWvN8cYzuR5rhSFyBXK7beArPzJL7xyw4e", - "baseMint": "6kwTqmdQkJd8qRr9RjSnUX9XJ24RmJRSrU1rsragP97Y", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CiaAtbtpzasiMTxeL1eBiNotW7YfCi2qBBAiBYqTmu9L", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GyqvFXrpGiAk9Z6fNTKWFNDdEWd5Fh9aKbk32hRQjLED", - "targetOrders": "GoCnDa6MLjR8Zxm9FYUpPGB7wZ4D6bqWUuufa3keku2M", - "baseVault": "5j1aW6eXNkcTta6TVpJiftAEeQhwbdeZuSGKeATXj82f", - "quoteVault": "H4vsdmHce2XXsks1e6gDasAjAfJSET9W29nLeZ5z6phN", - "withdrawQueue": "8TAiLAFs1F7eB3VdDXFBMTMXd19UJRpus3tMugEwTqJJ", - "lpVault": "E8kjAALJgh3kHcUD2oJ9DpnxXFKuwEqr8WJWEVXZyABy", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6hwK66FfUdyhncdQVxWFPRqY8y6usEvzekUaqtpKEKLr", - "marketAuthority": "8oXJkmXW4as1H29FTLPjs2UvzX8fD3EmSJ4RT2sNSZsk", - "marketBaseVault": "HM1P5PFgUA5dGdwKfCARv8FUR5rEFxUPxe1h1XhEDMbq", - "marketQuoteVault": "CsAiyJ7DkDc8ZSzoJY2Sc97o1zGZon8ueyuxnCDnwN5L", - "marketBids": "NU7QNW4GQxxs9mwVUYfT1zynDJLhzKBytVi2f6TFxVC", - "marketAsks": "79c3dthK1PHPuz5rxq8K7LdyoBdaAkSu1cqwWiFZyKem", - "marketEventQueue": "5PtVfCT2ztJN7G7RFfHahirxgQhRCG34mGF8ozKdBsTV" - }, - { - "id": "Gx512UfpxKGaxPSkYjbpo163UR188NBn37PEDMpCxC5e", - "baseMint": "5iUW2aLFsSD5oRkmxpRfKFffvKvTeFmEruABLYyY2MRX", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "FRKRXYPoiLZW3ykNBkgULvbfK61Xy89y5uWVMRU9Kh28", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3Wgp5JMHC95tGj71vDLQ9cLeDk5H7rzFv6VDXQJPZvCe", - "targetOrders": "GqZ4sToQrk2ne25QsL73HJ3DVDCRxVZdubybNt9yi91x", - "baseVault": "AkqB9qHuYqPhVrmdfgN8sv7pNU5Se8GhLECzEXigLxyi", - "quoteVault": "5AVkognAKABYCuC1AC3ASbMhUcTFWd4qxf9mTaYnA1wQ", - "withdrawQueue": "GEkmEvrK15JsafhZfU7jQkg8xjaviRM3PFwQ4bNK5yzP", - "lpVault": "4YXGA7R2Ku4xwtD1ZNxABtNUXgwdg8kxdR6BVouumULY", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "E58NGv1D6JcxyKJFuXfuxpGV1BUeF4VzzuckagHSQ9qw", - "marketAuthority": "3ypvRRJgTdqN8zq2zJNs3SFjZ1zysdncoDBCiLRsvU5E", - "marketBaseVault": "9tUyKiDqrDryKJ24oFmHyqr33qUtZv1sn4c1eu7ysY2e", - "marketQuoteVault": "F2XT8JbYTUBys778bKKFVssPwuFRPEiUME7qooadgcFT", - "marketBids": "FGcnWKVqWKb9XbgEJ8uEcmcVNC4x7KbzLByExG8L9h4r", - "marketAsks": "2LwBz9Ng3PrAXWpd38gx9wP9JbMyaBZrU4qQ26mRYoWU", - "marketEventQueue": "23PjvoFXTfUykC6ehfD5fp24SiEBJA5b57ZJhYRzZLp3" - }, - { - "id": "GX8T3Fc7xyKSankpRmMFobnBYJAX96Hw7deXt7d9XoU8", - "baseMint": "8vFjsxK4SHg2XVSB6ofqNNvkFF62fx5Uq588a7f8qrjk", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "CM9JXMCZHypszT5DEzbkYsGoE6dcPh9Y4xHmXDX3uBeq", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7bqp2KQJdBkC3C2yWGu9eGaCAadUNMiJGqRM8PWFvmeG", - "targetOrders": "8c6RpaR3araBjXs8s4qZpucSKtZJFNKXLNyVFiynT2dr", - "baseVault": "CmBAswYJ3CehRu88HYqpCVkJSRWtgttQJbpFYj1B7eFY", - "quoteVault": "Cgh1of73vFzLKRBzgFBRwbAjpVJ3TQXUCXFCYLApuCdR", - "withdrawQueue": "HubvLzAKVUermx3SkF8sgGqdZdo1Bfo5nyh4MTTEvFUc", - "lpVault": "AGjKa836p38rXfH8HhX2gfPGEXqamFHQjcN4JoqixGPF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "89szcZmRxmF4b8eb8kKfP7oD82HJtsvQ6gsQNTZGdF4m", - "marketAuthority": "CwhH5yrum37nEK5zxg6199MZwKyPWDuk1PmqwhMmW25V", - "marketBaseVault": "CaRqLYo5ytKHFxZTr1Amj4Z6C4KD9iXE5TrLEbkYvuM5", - "marketQuoteVault": "WNdi2cZZ8nU4utQfzpmZy8HUH81Z4h1mFgkjoxnp5KT", - "marketBids": "G8pMHmdeCDnSSZ7TtGQi6XpT6Minz1he7yf73gjcy62U", - "marketAsks": "CRqNYpF68GHLCwxM1wa4CSXrAMXKk2G5mebbP7fMeiq8", - "marketEventQueue": "GqqUrd47XzCiXksrZP1HQqrXqskkVUoNmZUW53KZGTwV" - }, - { - "id": "GxWhxikub2MkrvFrJT6WpENGgkGQ3a3H9NNMCuwNCrHF", - "baseMint": "DqxzPWQ2FKHn8pRoy9jCpA6M3GkEqYfieiAVwMYWVyXr", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "FiChvWAWSAeVvHyZSMWS1t938rkhEwWDNSeAdh2fiG9j", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HDGiPsZPwMMi1qGuuvQKQgAtCZSriXRhTTDKUZP2HsGL", - "targetOrders": "7EaFFRxzZzajUf7dcr4NfBrKbbsri4adGQrkXedNydh3", - "baseVault": "GMUSGd5HvJNPvBZLcThWHh6uHZQ51Fh6cLSza6zrK2Qn", - "quoteVault": "EdRvuMS7mJkW7pHoLKm9pvvHx4JvfRAtuRaZgGNprTTT", - "withdrawQueue": "7PvnV6BW517gkk5PVGF1VRxJLpDw392Z85wH9McH6iM2", - "lpVault": "A2CRd4vmEsKw9QomqC7NLzhvm1R6W39xa2kJCUigbq76", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "613VeHUMiifsBTXqxzrau2H1TQWQAFL4AoqM6CTC4iQs", - "marketAuthority": "GxCXeouJoKXtRHx2ifNVQSrerBJN2U3asv3JLLNDzqDW", - "marketBaseVault": "JASJecoFzse78B9MWNwpoteGZ4WVhioe94ybqaPWBzJW", - "marketQuoteVault": "7GGPH9kyCZFRJe4mYEvwqXKLW7VMM5kSaSbvBmdKgdED", - "marketBids": "BiBe9D4RjcGBareQWNNFycVxvw1FxuThmh1Rs8XGxuBP", - "marketAsks": "HLaQogEFWAuuYyLxDno6tjLAwjLybh6534Sf1KaoJaSg", - "marketEventQueue": "89DtefAebHptmbL8oh4PMUyugiwqausbrL4mUgKr8QTL" - }, - { - "id": "GxxEeJVPkAU2LEduy4U1rx2gVnYfcNHEUQEb4Yu3ytyP", - "baseMint": "BebGokMwTrFp2wRV4Z5CftVq7pvgMbj176VND3vTVSKJ", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "G8k2AixUAjyACafyYARXaN5ar2progSNVjiCp75PdkBj", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GBEGeoCkYufE9Kb1zFsusWbexEmbbryLKApUk5qkxYjP", - "targetOrders": "4yZxbHgHai2aDtDY5V6LehFynoWWvxG7BzfyMzsuVsEP", - "baseVault": "Dzry9rkxDCQptNjnPtPmjinUKTsHsr7VNyU8okxpxoqb", - "quoteVault": "Cu4H1QHAWR9wTV3jErTMjj2iHPj8TAtVL9fbgVA9BTuK", - "withdrawQueue": "5So9C7TeyWhvm5PGqwMLKCth9p38jgNqQgstqmiDbqg4", - "lpVault": "DtquyHF4jzjwcZJxk68y6kcPenWQWA38QVhKbZfk1zaW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CM2yspQ15ufv7aNJPXvb7FCFVmQo8y9joB66BQGFCGdv", - "marketAuthority": "81x9CZ6J1PnPbfJkYqK94TkF14hZpayn7aEaWAcrSAET", - "marketBaseVault": "6K7gXwY3DPXu6i8PVUSoYQYh5yw7ENrfvHvdUHk4yoCJ", - "marketQuoteVault": "Bv3QYHTePY9odEoE4PmvC6UodCGbbpoGdGekZCucFZXU", - "marketBids": "BJS1z5rTrw1aeupkGThM56RCMofRN2WHoo6aaZkBH5Df", - "marketAsks": "A18C6k4YYYp2SkeKvaxABNzV7xRh4K8dX99NCGRoLdRy", - "marketEventQueue": "GGKVDqMHFjoEqacbEEt41PnDsXu5p26R7uBdydpy1jcx" - }, - { - "id": "GYxhX54CnsDFU1EjovCHJvbMb95s6492342MKV7D9Po8", - "baseMint": "GnzxEyULVPQYb5F5hxGc8dEGivctVrfr5mtsdp4z5xU2", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5KymfSCPW9T28cH4zYHW7kn2DjBWrYXudgSxboQGpT47", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5v4Jrk9XnmVuRAk7xrcsQvEV9HRmyhwT79cauGcFxLWX", - "targetOrders": "15fzPujiCNrQ9rBoP71N79YiiGcshWYnJfnTAuNpjwp", - "baseVault": "7QonyYcPBJtgoTZjXyEEXzUWTTDMKiR6sZpV2BdiVBd2", - "quoteVault": "G89tPkqvwVCNFm5TqJ7ht6K8g2uYykPUn9UYqNGUPY4h", - "withdrawQueue": "6PShHGJmGSuzMDCfv5ABXbfGYfgKyJtv1K6QXxor5ups", - "lpVault": "7kEELppbRdj5nPCrTiyRgUvyHRGS9tLkeyQ8sPyk5DCF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5JL3tnvVUNn1xszdcPNwwCoNtP81aWFrLznMQNprbSfq", - "marketAuthority": "7L2iobdCU3yt4QHdoBVRcEygoCinBaLNuRa9Zs2w1CVR", - "marketBaseVault": "8o3ETWiH9DAusA8WEUjUTqbBCASw1RYnw1T1YNpduEEF", - "marketQuoteVault": "HcXnsu3exsT5mPbCmVXEcfR76uSpgo2vLdadGWJmY1Ry", - "marketBids": "GrrzDEi94noKaZAu93w4nf4Jy8iAL5yF2rWPT1e1FkPL", - "marketAsks": "2TpEFACtFD1s4heSY3CJs1ZVLLD3jWk5qJWz7jgRftZS", - "marketEventQueue": "6MrohYY2Xwu7zofoimKbEnDLM1VjMdsyrNRde19LnpE3" - }, - { - "id": "GZfYA1ofJYjQBxPQhrtbKsErfLRNaARyHUGzfB6Fwrp6", - "baseMint": "aosvsUetSY7h7hSYXPR3oCoVMpo9GeL3Gtz2aqnua7p", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6quTzFhDbDzCXFWjDdvqvcZhPFQyCWmyZ3VfkexASUdo", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8hPuuJRCGUtNy775D1hRsZ7iXZzX9ZUMBQEQuN9m4i2b", - "targetOrders": "86cQ2sdLG5czcnTdVtGr8pgtw5fQdXx2Lj52tL7dzkCR", - "baseVault": "5LdAGXniNy4ueH4di7Le9xxED4ReusLkNMFuV9ifm7C2", - "quoteVault": "8PGR9pYUFUxGCR6QirikBgrMTYVrJLsm7tGSh2v1V7n6", - "withdrawQueue": "C1dts219Z8jwwjAxiP4v9ZJEf4pkf7dDdFWkE4KPoQN3", - "lpVault": "HdBsrBWvMVYvYHDJYXQ81iMGu1o6r2N8TQM7i8FPoh17", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "A1YzRZ1FxrsD9eyznkUoVtjuhLs1jHEPp5dyR1Sfbbua", - "marketAuthority": "AQR7u6RHgiXJqaeCxFMcz6jv9jVBxUixxjorHtA3DRfZ", - "marketBaseVault": "DFP1kJ2wshG82enSvthhDp4qqYd8TJ8uRmSuoeQhCMKz", - "marketQuoteVault": "9WkexejeXjJ7TnAZh9ibiisxvvHXNAhMhiy3uQ9Qgmo7", - "marketBids": "By3Hd2yGbNH69UH5xWKqPxCQxdeWjt6fmEsyVq4qquPR", - "marketAsks": "4cxJmQrpBbyzxZxu3VheW9xhXedEJpPDcxF9VEYfE8YA", - "marketEventQueue": "CM91ReLWvVELQAvLZz2q1fVhwidGF5QibbZGENkj6p6b" - }, - { - "id": "GzK2YLiBssuahApy9EJRbFVAmVDssLBxqcz2rmCHDcb8", - "baseMint": "PsyFiqqjiv41G7o5SMRzDJCu4psptThNR2GtfeGHfSq", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Hrip9d8f6iQ4JxfB85JyGGq3u2WgpmqRSXJZursm26hd", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BH8DpRnbgo69tVrAd2MBN4ejw1edR45jWS6xCyv8TFBD", - "targetOrders": "DYqbTWydTjdWcUyBfhrVnjuv4dZBZxdUbyvGW87p18m8", - "baseVault": "8xxP3MmpFhXDVfDT8wv7rF5i8XLZvP2vhXUYrqQtKb61", - "quoteVault": "4tv2eDrjbZeZsLbrWaWzvi1GfaoYuhb4aSNDpnzdKk1T", - "withdrawQueue": "Gf539QLxminaXi851U7qVrRKiNP4vyP6Utgo1wVAyDG4", - "lpVault": "BUcVqN3qc6FjGLkXV9FVvTdoTgi2iKw8BYbbzebrKEWr", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9WDPi1uZVxBwZY4NXy7A3nGfxAzxvNaS56iHk3cBhQ3U", - "marketAuthority": "6nBbC85aNcJeGsgedHAyTMJEUiESoHDumAuMT1fLPtxG", - "marketBaseVault": "9Eb8yPbq4aPnxU3nQuHMQXdzSwmxfDUdRV95q8cqSTwJ", - "marketQuoteVault": "HRy1afedabwMbdiYAHkEbMkWcnsFVe6NaHpkguCeoJ74", - "marketBids": "9NBJ74XhuwtMQje4ihsZMQMyGt3rmzuYbYPX5R6ZKA7K", - "marketAsks": "3YQF9QpGK6MunUUV7Ge4bKNYhymkyHnU2eo56779XvJv", - "marketEventQueue": "3EDUcHFMvV5wAu3yxDBq9caKvKMiurcicTSXnEAP7P1g" - }, - { - "id": "GzMSVsyoZ8WSm97r4WwSBEuwLT3FEyMgmfHmY4FViCMP", - "baseMint": "E1PvPRPQvZNivZbXRL61AEGr71npZQ5JGxh4aWX7q9QA", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HjNGszgz7mPBnhUqVXkRJPcTFhG92we9Q9br6t4Q3GaX", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "62jQXh8L9XuCLnWB17BKTmZvZjyAbAEyjW6RJ7DUtiVm", - "targetOrders": "GGjJkJAV2y3vNWR1q381dCJyjNRTe6oyPpCJH8VKKoBH", - "baseVault": "GxEaS8MPy9jdLeZgfFqaYGkAhBbFhcSrdkwPt2tPyPW8", - "quoteVault": "FxYKMsWefBX5edqEGcWQrbWZ6P4NUd1q9eHBey2DMgqp", - "withdrawQueue": "GGCyTmmXSEG1mzy3vBC8Zaew4WJxe7fAerd7qCu6qRJC", - "lpVault": "2ZTcgzfkMPz4UiXcC3gJkFVfPLvbneUxhj2ZqYootFEs", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HyERWE8TEQmDX157oLEpwaTc59ECzmvjUgZhZ2RNtNdn", - "marketAuthority": "3YoAp7yvjPXVMv61KV3fADNs6QpoEy49hwnDoQvHKkCy", - "marketBaseVault": "Fb8KdP2rb7q1pCskwbULLDi1tBuqip1ARCi3X87RucDw", - "marketQuoteVault": "D8RS2iL1KzVLtuiwoD5h5RdrToaAhCzskckTUcGhCX2z", - "marketBids": "JCVoxzYR2DUhcZRwPUBdm6Y9Z6CkvBx5G3ZdgZKCRTGH", - "marketAsks": "3MpdCrzEXyqGb5x17rNFRYLiNrrz6cmzn5V5ZKCAyrsN", - "marketEventQueue": "GB9S3kwWjbSM4xPpi8zX6xDE1bEe8huNwuSnNJchQZoX" - }, - { - "id": "Gzq3HeipXNhYxonEzdaUNdAHjhdsWZCuLvLacSCKfUk9", - "baseMint": "4D2umdRkmjgsFj4Vf9foJGMkTjNQ41jXaGuAL3xb4dQj", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "3Xt74bX5wE7HtWTnnuFqfa7cWuqTBbCtyHzy3XBV37rv", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5Wt9ZdZFjvXHb9arKdHta7LzBt3sEz2JBS7nbWB45ggH", - "targetOrders": "8aCZog3SW75X87ncTHnC8SJJTfhuhvkJZsN2zjQ8Buke", - "baseVault": "DrNQzc5UJ2FQGJEffcCkJRXgtzsPyLedbdsmjCfN9wmP", - "quoteVault": "HeK4NVfAsBPub5aNsv3tbLyGts1SAniFYi7e5Jf3dwfA", - "withdrawQueue": "8gC2Hjo5wjbjXG91iHxwCtnYqihUbN1nivG2mdAqr6hP", - "lpVault": "8mFJCXLSBxXemZ19pxLi8QD1GufRa8rvUFQwipWxBqiy", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7Qe2Pg5iyZv725phFWvTW9A98htXtivF4HH1zFmYWrd9", - "marketAuthority": "FW7RPHkFf2t2UC9mendwC7BFicozSnoz4S9csFs2qa4q", - "marketBaseVault": "AfnevfwVER5wcQ24DyLtFea34xKfLJt6kK9TLRUYQg69", - "marketQuoteVault": "JCL8gVmrenMcY3gxhHLx3WCP3R9e9scA4FEZPyKnEWPR", - "marketBids": "4DAZU9PeyoSByvygJMQxz2Yq8TnEs5PHBX8fRHF6un5C", - "marketAsks": "AU1tvCSUMtmkkv4ertetAuPkow8SfuRG7ced1RVmhaLN", - "marketEventQueue": "Bdt7tquhJf1Ba4u3BheYabvyKzh5fxdHSMWC6Arw1C3r" - }, - { - "id": "GzRuDJgWRJkqstUAjnRxZeos8ZDvoZLuCCuzYfeXqZDC", - "baseMint": "3xVf2hPbkE5TuZNUPLQXFgFLD4LpvCM45BodbPmnpSSV", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AmNH5mb3HAfvQ6Bszypf4JEuagWoYn9Ev9kzQ82VjNoa", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "J2JvcFhYUbTuszvXAs6iEu8jYvATCdkK87s5qjcLcLST", - "targetOrders": "GmMAj99Nk4411eja57Avpj25Gn9oauSnygrwmEQBEoN4", - "baseVault": "9r3vud5trE2uRtUrjY5LVgaxcKXcpG7h7jnnTUuYpHq5", - "quoteVault": "FQnumCbTodhzTRun2ECc3Xi3bcEh6m68EWhJYFQMZase", - "withdrawQueue": "Bdn12L9MC5JRt1sjpvUzXXgdPaU3DaX8eN3AWffhFKam", - "lpVault": "9ukYi6ivLCwWpgxxSarCb6nRPrFYS2ST3wKsn1ZrjNyS", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "762pF5rK7oN7EGHCZs6jb3iKUsKsf586NYFRL1K2xnVx", - "marketAuthority": "EaqpnqGb9bEZCdAdP4dbnzGMr7nWEw7MeKBoTEdJPVJ1", - "marketBaseVault": "2RDefxHs6PTrkvGxjamCWAmEviL8UUCigfc4rUwGfypL", - "marketQuoteVault": "5GNLXZU4Y3pRGQapX8aXA8eRdg1iLAJ6D3yPCxjMVQsV", - "marketBids": "4MjCjj7sQBgUUjknwvPbKvQmZwBDjwncgpKMUWiJSXYe", - "marketAsks": "J4M3eiXzDvTYcbtdDwcS6p7Q4KdQGYJZpjrqW8Em3A8Q", - "marketEventQueue": "CC56L4LW3GgkfqxZc64GqrF1zpScD9gbj5XTqU19EK3N" - }, - { - "id": "H1yz9yZA8d78XcFtnYAiAK5UBi6dVufW2oeTXZXdLt5G", - "baseMint": "EZF2sPJRe26e8iyXaCrmEefrGVBkqqNGv9UPGG9EnTQz", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "24SDzGpMzeZA6vHHRYa2fMzuNugCPjFzaU8g29nJrLBa", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6hNjJ48Me4uLhnubuvvsMStVLXrB1qXw8qi9u7kr8apf", - "targetOrders": "BLKiS3SWeAHD1W5VEKkpHgv9DafZaC1tm65qoBsWqUYa", - "baseVault": "AdiSyFVyrNMT1FkuuazgFXPBWRWf5AHoncSgNkr5h1mc", - "quoteVault": "3gHsdLrC6i8j5d5aHRJ8k5gKaq3D9SwWdWDpSW5sRAYw", - "withdrawQueue": "GSHA4h5vzJnquS84Ppu2q27QPNEgcpbvPoSfsJTBBf8t", - "lpVault": "EwSjR3o71eTaPdsU3VtzVvBTypwyCmv7Z93p1tz6rBHs", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4M1uP9mYnbraCvw4JuiqFas63K1o74LeoJwpVDW3AAmG", - "marketAuthority": "66yMn9zGFeiLYLicbNEov8Wsf7wkR3YcN9NvgP7tu1kd", - "marketBaseVault": "s5pbbC2sWHdLBdSf5V1omPa4Q6jv4W19U4n1UoK1APu", - "marketQuoteVault": "C9uceDwNBAEP47d91guJHginx14S5BSoa4Po2cSumvvU", - "marketBids": "9n4i1cuqauXP84e5JerM7ce8nDH9ZBrX8AvbCxezo3m1", - "marketAsks": "AB5zwBZJm9yJuZ6hQWiFFudJMcajs6T8vcDBJtFrxyFA", - "marketEventQueue": "DKLT8Q9xFxeejdbDf8H6VATBJRBq6Cn2JpjD43vWRuXH" - }, - { - "id": "H2xDrXp4XzPR1ynBBTwmb8Lh6cpkpSfvHcD9cy5TEP6", - "baseMint": "HbrmyoumgcK6sDFBi6EZQDi4i4ZgoN16eRB2JseKc7Hi", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "5xwAL7gWAEGyUHD29X4apVQwhFc3VNKVk22jwXb1EkaL", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "47yaLNpSdfvNrx7hBGnkNdZnyRfn9533Y3UTV8tgGF9D", - "targetOrders": "9zS5Kvt8bGAMZ6gVwXJxmAAc5gXErHng5owe4xHnfH4Z", - "baseVault": "3fShvuoeJFEe4SiaujVvYyWmaUoGDoWhnxZgQyD2juLb", - "quoteVault": "AGzzdEUKiagSv8eG9fneih3L7BJbqCZcE1qGzb9NCRAo", - "withdrawQueue": "EMCGwnGa29b2U1BJBDr3iCCLUNU3313FV5gWjaci5oJJ", - "lpVault": "ACSKKFL8FPRVMF2nsRSdd9GPizf8YVEvege6hXtNhoVT", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8ZERQ8hq2ov1Y7SEm2fP7UC56qotwFviyaGdsqXQ7A7k", - "marketAuthority": "ae44rhL1q8f8UQEGSD4aVGrFxStmT4voGp1iZ24oXin", - "marketBaseVault": "h6YxxjTy4XZyhsTwb8mUQ2Tsr412J1ui4fe8SNhBxM2", - "marketQuoteVault": "98YnQDuFjKFDRWdSZP3SRTNhk4XxNBmfpVtzEmgq3sX3", - "marketBids": "7rxmD42wzMcHc7CoWBrVijeJB4YMR7YtYREEzTo73u1i", - "marketAsks": "74HdfBozfdAHx8RaqM4tb98Tsg9PdtehF4xmPj7a9PNK", - "marketEventQueue": "46jBWBwuBYgtupqfuZirAVXNTKevvPxuXHSGnQXjx6qM" - }, - { - "id": "H3Vw2XDRMFsMFP4fYvKxXczhza2uEpeac9ZLqobQMNSw", - "baseMint": "Ctbe3DDHMVLUs4nY3ZCU5YHQB4S2zpF94R74PutaBXUs", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "G4H9iizGgvh2CaCGurSCGk2YHJRdLmBuy5KUqKaauXvC", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3aRHUPLFQhGhePcsH1PfC3FPrDnha6PUgVrLdRJKu7ds", - "targetOrders": "2WumSq7bkNe6t8gHnbac6KuiSKB17ChLQWq7uoNxwam8", - "baseVault": "CgzzBRDebKCbZWG3a3pQe21XukDPmZaiWAvDncbBuN5U", - "quoteVault": "CGmRV28U2nNT74xpiw2Q6Sep3d61qihWztai1UWdiMLv", - "withdrawQueue": "ERqhvpvmXfnmwxXcTghbDdTCxPAJs576jNHWpauyqXyh", - "lpVault": "BKKFefYY7HbY9DW8qGqKihEuNcVb3uxww3Xuvyp7EDN7", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5vo4kBYV1RQxkjgqvfnQyui9QHfxKeRTEAPjhUNJELgX", - "marketAuthority": "HYpGtZMRVEodMgCAP6XXuaFXpLXHEgEstYVcUTSr2mfZ", - "marketBaseVault": "3S1xAV6USnTZ8NQA2U7VDpcxP2dKdxFmqurieAYdGhaz", - "marketQuoteVault": "2kdibcFh2jB15YrFAMCPM5ZUYtNcaoFsrwsQiQ8QjMih", - "marketBids": "2gMbc7PPK5N9HTXRDWBZP4Eytkf5hdbTLDp3L3gCUh72", - "marketAsks": "GKszy9kRZwQ8aJaX3CFHiV7XPjxkbuqgQQKLgRDnrzxD", - "marketEventQueue": "KFYvKUkRTrnAqEDUbyVpLZtHBksFhRwHXptQfr5V3im" - }, - { - "id": "H44kKchvMWvLhE8yff7QUiv9YZLcnidhwPcuxfXQSfoK", - "baseMint": "in1vrZokxUYpPES8njJ8x8YPsHEx5TX6vdW3WcHho98", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "C6dzJe9rQPHSVUrrJytowpHuG97WtnKn6W3Tqffwa4Cp", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "G5o9GeGpc1GQNnLPVSv2jsqUfTC6DwAhHbWT9yGFn12i", - "targetOrders": "9vidyS3ssdiDcKiZza1NUMRR9Rqf6rNa8gAofjB9U8br", - "baseVault": "7vKRac1wvHQA7ionyzeiBqjDg8g9RjuPT54PpNEk4ua8", - "quoteVault": "2VeM5GkXpz3hHbPvyYA8NqKdFTVgR5RagHUbuDW1QpZN", - "withdrawQueue": "BhFaaUiJ1ZbyRwHs68oKsRmBY6Z9fy8zSZEADKPhcfYy", - "lpVault": "2w17s62SDGLypcpf6AUsMS2xRu8rmiETJfXLDJy9q1ZT", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BKseLhcDUMV2Ymv5jLsiRkphEp6YqscaUrmpkuKHLNz3", - "marketAuthority": "DnpU9xLKD7RU4HwAe9SDcLLNHfcZXtpkqAUTX6y4y2vB", - "marketBaseVault": "2jjmdk3rzJKNK3VAWDXFqiB8MLbdQhpiDACVpDjvi3Tt", - "marketQuoteVault": "12rRvn1XZAQEGiT6XYeZdcmvwySB265UaPAZgyF7T3sn", - "marketBids": "8QxvrneyE59PEJWyYfucPPxdKTHdegqj7qJanBwxi6hG", - "marketAsks": "AsJuYhQL6NVRdM2PEtxXEdi3dCBHbLc4AKxExEDPChLZ", - "marketEventQueue": "2coucEQMB9gsyEETyrs4Br3twfcPf9SJEdBbLRGQgWoh" - }, - { - "id": "H4QcEhtwH3bWWMMg6QQAwBCHqMnBRn6HciCeKGteX2Bh", - "baseMint": "7SZUnH7H9KptyJkUhJ5L4Kee5fFAbqVgCHvt7B6wg4Xc", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EadfCWVzrUou4NLVY15Wd2biYcp2yE1D1Dwsbt9nGj8r", - "baseDecimals": 5, - "quoteDecimals": 6, - "lpDecimals": 5, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ALmEbLVPsyMSFQ9Pn28yShXSs2uPhyCFJh71ztwrky4N", - "targetOrders": "C3WV1Abz1GsRQcj2esWzcZzReWAxQoexvNKQXhZBaFK5", - "baseVault": "EmroziMgaJSzCGfaFqAPykPmkrtyfRwixzZUBPKTQMiA", - "quoteVault": "HY1WqwVHhUGfDgHE9LJRgNAv2UaKf7LEpkNtdUDpbqEZ", - "withdrawQueue": "CQvtXXXmPcypSSAF5iLTXPz92eBghs7RNSvuDvcGd3Eu", - "lpVault": "9qv2GpBSYHDrYmdKZsfkrU39LPNDtZfmxKHHWFBdGjEr", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GcUnHQMHfUB3o2sJtThGXXFeyiwbUUvkUtJYvqBFAgrQ", - "marketAuthority": "DqsmDXzYd6QsVZwVcKgYGLK45CumA7vdnxSgzQnWuivt", - "marketBaseVault": "6LVBeTrvS93ULFBVu98q5vjoXfqWM71Tjjfh8KPTFXms", - "marketQuoteVault": "3E2kchzzCRvZKaFU2iXhwEo496s4xZ7TLHEebmZXVFqe", - "marketBids": "GM9GyBgi5VAGqCjxQBc7CDvKMwnr279PTJ8cbDh3U9Qc", - "marketAsks": "Ayf8WVpWXCYWfhy4MoG1vGbo8MzEFw1hjSDaH1qDAHiv", - "marketEventQueue": "EtaYJAbLqYYsvEKk3gm6Run4uAksyQeAhKAyXEFQYpdA" - }, - { - "id": "H4TDVsBpNXgsAFwhYMqrSwdgEqfvFJvTXdhjP4gKPsHT", - "baseMint": "524PDPmUGqFomBB5ro4zZ6wpb4dTtsuJGacYuXAS1bFL", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EcKZpb8Lmh8DsjSAkSpaMwnG9fL2PhGYdZMpuzPirq7C", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4ty7FPu9JPBrvbP9ebeyxc9iDou8iS95GSKD4NB3bEwo", - "targetOrders": "EH4DMDN3kMFfDrZE2RWY1gkS9q2CQieVhhgmjznutaoT", - "baseVault": "ELKE8vghMjZCQGZtdsADXwcn5kieWVv4PxQMDMF7iaSr", - "quoteVault": "GvQ3SngoQwnBqRBFCEH55bmFbxEtweShXuPrhR5ARy9D", - "withdrawQueue": "FWBKr12ZC6QqLNrX5xYboYu3uXKpyVrxLrocubJVoohq", - "lpVault": "8ezQ9DKNZvNSUtuLHSJPBFwU9HN4FE4cV1Qh2Yvh7FQH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Hvgeugdn84FrC2NdWBHgPC2xymRzXCYBy4YRftWQZonb", - "marketAuthority": "BPaS4Da4uxDyuXJjAKjNVruoBBvHQ5cihYjZJUpVsR81", - "marketBaseVault": "3R9UGN2hVzFMYhLAMwbtWDrSF8nfjdcrsoCb1CYeGRct", - "marketQuoteVault": "4iqBBGucvQQjKvSDDPQzRwqgHhhq7nn1qaUo8JGyo1Gc", - "marketBids": "FbUZqkhTg8mWgC6hicZuktEWw42bhK4CbxXB92QnRx1n", - "marketAsks": "EsPzqrx2ejfaTH4Dte3rttnSSfp4gwZoRim7G88hQfzC", - "marketEventQueue": "poVJvKEVdVUExnLeEMrHteu9ocme2AzR3oqjfAeLhgm" - }, - { - "id": "H5s3w2vh8fKFCQjWBbFNh5WjtLU5qpWNpRBrGE9ohGjQ", - "baseMint": "8WTN3gDKgk2xfYoBZFjyBhek9DaMkqVMeSU8EcfUhHNU", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "CkqCHUJfc8xPVsNHQbZLHpmoHFZexJYsCEfZoxKMaboz", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "G7nQX8sYWEwChxGkEwQWuRGapZyGEcFuoAvHmC2nUT9G", - "targetOrders": "8tYmC31faGn4ErY2DxpfTZfHKaTPu3eRVXWBByt8jSbN", - "baseVault": "6T3GLp9KXrvKtS8TBz5FouSyguJVEX2w85jvhQHXnRHs", - "quoteVault": "CL3ut2aFX2aiEZspPviN5PvMbRsmLFgQEvkat4sjKWzb", - "withdrawQueue": "5bD6NwJRhY2MiUrKPjTa1UZwLMsnujzDvhmx1VrtPFby", - "lpVault": "2Mh7Ro8mpgKArzdC2ZAHFw2MpHz7KmG73Nj88X7StGyV", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8wRqC3GTvT2YbujfZc25HvCGMD3aSt31ZLFaupnfAjYa", - "marketAuthority": "Bw2nc4zuA7DTvFXjEzv6b7ocrYS8DyAbyVfLJ5wyfjXW", - "marketBaseVault": "3z9oYdd1V4JNNUd8HdBVV7z1bJnuGxiq61uodLTuHqeN", - "marketQuoteVault": "4o5C7tSYDffCKT52kfG1cseyfNyJdnEcaR6trfT9LSJU", - "marketBids": "C91J47dv3Xtb3FvkxC2E566HzQCgz3YuZwYVMiKXnNiK", - "marketAsks": "5FRnPKgA13mtUvAnpbmo8GSmz9BnbQkNko5vo56psfnh", - "marketEventQueue": "BrVGjZ8G5ar4wehDmiHee2euBPVdSzgRX4hhUJMk8A8U" - }, - { - "id": "H8MyCJPx6RQwJXhYMw7VptGsSL7FXqNPs7HULCuD7Zay", - "baseMint": "3Ztt53vwGhQGoEp3n1RjSu4CFnGRfqzwo6L8KN8gmXfd", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "DPzuwq1ibToumnBRFbaf38DxfKjSf6ZNhAFVRVCmVhBL", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EkeSm8b2cmYBLoPowGfManQPz6Cq7XL3wuedeDtSQnA5", - "targetOrders": "2PHV2SmdHuQFAFMexyLqo4taMWxejzRXfNYc3vn7g7vX", - "baseVault": "8sWYxHb5ZWU7QSvG5CVoprFvmTKgQCEDnin5QRqubPgF", - "quoteVault": "3mnN5mpFoPgZEqPYdWZ2SxCX2FCPSbDU77hNXYtz14YM", - "withdrawQueue": "6sVmFhjGxBhpbLJfnzZTNNrirvgXrVhmsgKaVU2mpffe", - "lpVault": "H2YLDLhVp3GbSL1Bo744mfPznWhhKaM9WR8bXA6i54ej", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AgyYQcKn5dDoH77F2wWry7UGmRuZXHY59p2BSEBAgE8", - "marketAuthority": "HjcGSLW9Bb8HPFJYC7hJ3oFv9NFuk3pLa37jhpcEc3Em", - "marketBaseVault": "6hRdqfW2gLdgKUGuaU5YGSAxt5WJW6qnjjTgLLtXyz2U", - "marketQuoteVault": "GNHruJnhJJcGhHgy99DyqhkxjrvsCyD4TnuFaE3k6SeA", - "marketBids": "3P74nxoLbs8JF4A6C7Hx76ixeoVXpj9VX7FXbpxvVrir", - "marketAsks": "8dGV7un5AEvQnDzZ93hJA1gK8FZJVqwCL4SByouKyggj", - "marketEventQueue": "HSHyCf9xESG3TzJ1iHA73VrrnD2TsJGDGd7sojAsaj7U" - }, - { - "id": "H8nUg2AusMLvrR2EAp6K5tDsR8vvgk5zXFvTPtZe8rUV", - "baseMint": "7Q9YbR4jPPaDsWsEngubW2z9PGfmWK7xn7AeewMm3qbT", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Hk44PKj21uW1XpgtENs2gkCNqr9qSbHYnDvb1WiFym7Q", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8STWhbCteQPBxBfwELxhroy4r1QMzTUZ9cw3F5HogD9v", - "targetOrders": "8fHVtyeb2qnm9Z9ne3teLU2HUXzCCEw1Hz5NwNcHPUko", - "baseVault": "2Z3sJLBmvAXNSoJi4P6YB85RFGGUwnB1z5P4mNYW1eXL", - "quoteVault": "AHxWM6zFBR9SRuskkGKchpRZafyNm8ahb52fyiMAhi7u", - "withdrawQueue": "9euovME12WPzgVhdafHu8VWv641xC9CN84B3ZDBiiTzW", - "lpVault": "EQoJzgLxtbp8HsZMywwttrZGcwa3761dyca7ZnLMwLcr", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4CFVoiC6ZGycccBX2ixm7YjystZWnD4aWgCAF2AK9hmQ", - "marketAuthority": "F9L3ApUmcQhqCyM5BFoaBT5iNHcN5hUbjC2errtE95cc", - "marketBaseVault": "6BpXrGxrL5rt5GJqgwLYCn17wuZ8V9fX8DUx6fthnT7B", - "marketQuoteVault": "5bJewmspc5zFj4dATMv2omWpCirzM7n8qxyJtubhhToi", - "marketBids": "5KmwnL7mYX5ZUNhdQtxEeHKjnYzKpMJWfVLMGaYJXsZK", - "marketAsks": "ArTxHfSz9eyzFNZetTHBpX92aFci9G9APzcpnjQaaByA", - "marketEventQueue": "DTojaNNcJCZ5yAdbBoWWWzm72HHpEFCF7RtoWWWeUhzD" - }, - { - "id": "H8PEj2Resy6Pm4tTH6QwybnCswhi5CqKPb6CyVAKYbLB", - "baseMint": "5Z7bWSvcxVeUkroSypFW3Tsw7vPoJUcCxhTFNenLxNoR", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "hyLHcKZjAhTH658KD7eWSvygXY1N2snNtYj3rUVoCgf", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AdAh4qrioN1ykoNDN3yX8vune86R7njRyqtN26DKQJGo", - "targetOrders": "CjdSac9KnHeDhC9NtqopKVdJrNNRqCmyrpZfj9WchsA6", - "baseVault": "AgWgYdQa3GfMvQeEWtLAky8SF4hxdnJ7w22bPzg6WgqY", - "quoteVault": "41HHQkHGYzgSe7bfVtLdq8eenGS1izEq1QChHUrhr3Az", - "withdrawQueue": "5NtZhiBJViedwzrso4vrqdTKLmJzhcvNs3sZ3XbbsZ7q", - "lpVault": "3cYdeo1v7yfvAPqPPpWrVjr4mUQRrZpK8hsqCm4a7qTq", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "A8G7cbfV2gQJ8wzXcYiwtB8VAVbf49fZyTACUjEARUh4", - "marketAuthority": "C4mh9VCUC5VLWE1P2ZVS7N6zSMvL7fCpUjFiKhZYFsok", - "marketBaseVault": "Dh67MKHdi5dai137DPuJTq2TLsmEaxGRvHukXN9t9hKW", - "marketQuoteVault": "6kPgbt92GH6vtNJuXuQQNPoGLJvj6c2PKXu3Sw3UDman", - "marketBids": "8oiyQwahpuJL4Lu85Hq3obKFqLVd26qHDyGXWZJE2RzG", - "marketAsks": "E58z55hLRoqCY7HkVfTYcpSWugX776LBPzy3xG2onRCk", - "marketEventQueue": "EgmH2wgo5qYBXJ6zvhe6SNxt6zTZJyx3DCd4xMabtZmZ" - }, - { - "id": "HA3KAmJLRXEqjEyS4HMnKdMFXSS7Ey49qWP8ojuhdkoQ", - "baseMint": "6RBwVuqgBsYsWXmEhV72MSBZMawuy9XxDpm9uzffxmw1", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "FhsiD9dho353MNPmz3c7U7748FRYtExwGivGQQrPxYYq", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5e3nkBPePRMRb6miNsTpPoGjaEM6H46gFEPTALZhCYd6", - "targetOrders": "ES5funqbHNPaF1YgXZvejBERY5HRM2ncey3pXzrcCAUS", - "baseVault": "GVyrHUZFpHcFGNZzaFejppZ2FiCSkYDKFjsCtDLLDrLR", - "quoteVault": "CeCsrjvxi7bZ8NxBo4piACkvXTqQ8AXxij3g3V1p1bGQ", - "withdrawQueue": "FZog4p4khchbB3X7kKdbvkagZxwVayYoBHwi7ZDbdcqh", - "lpVault": "CQotcBPcLbuPciDVYAk68tjinkArMwFErfk7LbWfcRo6", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6XRxaN19C78VY9VK2oMuA844Hd8tXDsYyA7Te1pwBB2", - "marketAuthority": "6zQoR9mbccoTsq2MWZDz9mFnPMgVGSt9fgu1Lixop8Zn", - "marketBaseVault": "D1t7TGc1XJwJMbFBbgCUtrUscQL7E96TDGbqqjv4eZPG", - "marketQuoteVault": "4kLJqsSVh18SZrme2nQ65mfgXoZxXPdbXhMbTk8BPEVi", - "marketBids": "DfLcA3d6cdov4wJUqtDRxLkbzTUXBXT2nATjD6LqU9Jd", - "marketAsks": "DZAa6b3m5qFWfnzUygK4mvVMiThPUG6cSv8XsSeHPmRs", - "marketEventQueue": "gKG1o2xtynPWJCUxbXzanf9JCkfFiEwu6TXS5hwbpLC" - }, - { - "id": "HaC6cifHFDYgWJ44RgyiHwTsybhnfHhakrfTSWUKgGGi", - "baseMint": "3PNqq4kEqgRSkV5dYdcc6mtoaoXdaun9ytoCr4BgX5yA", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "8M2xChrSXcsKNB79eBeSWvyu1htpmpH86pR85C51e9w5", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7MufAhdK4YKFpa5uVauZdUW4F2Sj6m1ktMrspBU944bE", - "targetOrders": "Hrxw9g6oZvqp1pd5ogq1zmQQ5R1y6GNe3EMNFaqrpinC", - "baseVault": "AcakerJ2jN7dR1TQu2wEK12KXPjXfF7ttrUeutuhUxVg", - "quoteVault": "fBzy7Z84iN5EbDy3dLFJjB1DJPcFTps3HbEg24GxAxs", - "withdrawQueue": "5xEMSGTEDT9aqJhYC6uTh1rxAEMvTwNGDtcU2awJnwRd", - "lpVault": "D4SAzFoPQHmHgw2Tk6TW7pY7E7mvHmM9HtwUABWdihES", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4sv77aEsQhREPFaQM69nrLvosdotgnYQ384d4bgjbV64", - "marketAuthority": "Gc4oUthQALABvdMf28zYqiMKio9oTYoeSq5AAtEV9Azw", - "marketBaseVault": "7FwXnkNXoo48ow5acLW4pCeDe7JkDrByNYGvVHWxUWD8", - "marketQuoteVault": "DfAC9MJC24WheVviyux8DfaoRNTRnqjzgsp51Rx9J1Np", - "marketBids": "BrtrGmhpNV66iXWJnamYZJDMMFZGkJzgBcZYcbbXMFpW", - "marketAsks": "AN7dnRXewxcbyCQERXVjLoioAuH8HBwSBiB5XCcF4cWT", - "marketEventQueue": "FhwFuzkMhvhK8AbHPwd8yXtuGuzJK6seZkawgL4QM513" - }, - { - "id": "HAK41FR9n8GRZaTVYmoEkaHD6TpMBNWsywd5gEGjwirn", - "baseMint": "2MStv16MMiSTGu917stHLsC1ZTUW83tmrfVjUxfx2Ev1", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "8RkzDWP7ijMVohG3VidE1UBwvigasjrZRyCSpPh7qzgj", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AHnQk9PYG3sQnDonhPwr9CyVXUYXQbzA9yFThtnqrA27", - "targetOrders": "GWsxozsahvd1tRFwyReTMSLRptCjwLNjzg9V4pVvGEqj", - "baseVault": "E4ijjjHooYMPvVFTGW25VvbFxfh4KhsCtFBvzLowZH9i", - "quoteVault": "XE2GfvLxHYhH5J1vzV1AChYHqB9DfUhesGapLpwffNf", - "withdrawQueue": "3bv9TX2r1wye5sxJRLWna49BPdqReBeu8sZPoYaqQSfL", - "lpVault": "ANTacPBUPAVAUrRZm4k1vCKsd3jvjtrsiK2ocxKqzgJ4", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "35KVcWow1rnXxKF4bCzpFGxmAZLX34cR21tHXUrdYFm5", - "marketAuthority": "DBsikBYKkFT4Wvy3F1KQTKzGV44PvoRoUUTiYUEkYa2R", - "marketBaseVault": "EwN38ktS1s2x1t8Tp8fD5g6PheqjWSeqrDRrhxFHjpJZ", - "marketQuoteVault": "ANsHSxNUaUxgAdpjkHRX5XdiW1thYwGjPMQqgA6iy9e8", - "marketBids": "6xkreBYuWqe9JhQuAMqEDDVsxc2tGttmqR6vtb14or1V", - "marketAsks": "5iaaeEF1fTAaRhmaWETgZbLLA2M8eAjd4geU29R1PCkb", - "marketEventQueue": "6y84i9mpFRJCQGRkLUbTna9r2bZBc9BkJk4pMba8ZkGT" - }, - { - "id": "HaPmUkkAz8j1YJ3ypcsNBcPqeeRZe3kdYUjVp1o4vSa6", - "baseMint": "MGM57zGF6ghF9Aax7FfoPHfxuoLKuEGM6twJALyCFqx", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BFAMYmKr8n9WE62p9BDs4qVuhPHndB43K42et1SSgroS", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "rbBxMaxkk2edMocjtG2mr5EJ14c25AFDGTsVWWvSyZM", - "targetOrders": "8EfmegSUsiYnYBhwzAu3ysJjJMcpPkhxNp44R89sQbk1", - "baseVault": "5rhpdUivGESKsnLXvEiytw4v6so8KQ8HaHPHruzu1nQ2", - "quoteVault": "6zhGtxKzVaZrzKaNU97swDtrFs7XUEwHarh1gaXU853U", - "withdrawQueue": "5NQPWVX855ysW816ooPZe9merJAWxiwQmUFqjw2aGiaS", - "lpVault": "9uikgbW3QETYfwsaa884qwCSEoXzesY8szcdAwxGVWDQ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HCTg1tW7FciEkNvs3Zcy5EmJCaPLmjHWeRrKQ8cDXYXZ", - "marketAuthority": "EasSwYYePXtfBwqGaDJLoAnrvm85JYFgwpqBCTttNuoo", - "marketBaseVault": "ENDpVL6A5H4B8KdS989qp4xXJBrX5mHw88QKSjwYKs93", - "marketQuoteVault": "533rN8g5JbPCJAkQhFMrYNosxjK7pwSFYgPi8Dqo7DBW", - "marketBids": "AEm1aAqEisGFBmAoXmRs9XZijpdSUv3oRP4TENkaDkib", - "marketAsks": "Dc8a89e9R7SBWwL1sR5HPoDpD1LERLvpnDFLan7h2WC1", - "marketEventQueue": "CtRMUcNQAYoXcFqzm9Uw1wr3VvzrrUfUgh6njEFdzb43" - }, - { - "id": "HATMTecFnLAaaTdKa3h2dzY2hCLYLQm67jQ7rzBgm8mZ", - "baseMint": "CWUUV3ym4Uphw4CVgkpNxrR7FsttF7h7mLggEUJ1J1aV", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CitxF4vfPg6jNAo1wD17Mwx3ENHQgbgR3uqeKFx14d15", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7HZXAcgpERCwmt5SARiVRspccK1gN1pso9qkHWz2Zh5e", - "targetOrders": "85nDgj1eUCaGpegTqntajPp2vKKPjaF8o7QMkqGdKuwU", - "baseVault": "3H2qJvWQ1pJEEZvK43w896amnUPf8cJwt1d5AR2efCgt", - "quoteVault": "H2tfJHLmhDMhtcnGFYBSSDDmsGvCSeepV8aGoTEFrxNt", - "withdrawQueue": "6a2YTL1UPmxYgc1EamSPvpic38ydK5S41uVyvYrTMbNQ", - "lpVault": "EKaBhBX9YewnJ2BnAxiXpLFe6yv3C7tyCAayPE5uanGo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8s9XMgvm8U4V4ifnFbUxXUN9VCJFLbzWXyJpmbh5niZY", - "marketAuthority": "2nMKh5GYYFfunbW7uqLT9yayP5Hj9gZFoR5NaMuWxV3W", - "marketBaseVault": "7USVZkwPsXpt1HMEDyDt7cJfQ7jiCBz4yi2m7xDi2Lgi", - "marketQuoteVault": "QCSmhkatTEm8uQWkMyj3paygciaXWWHu2iWfRycHhpN", - "marketBids": "Eqj7A4qYN5GrwaF4rZWsqUabZvtfqAjsn18jLRS8GmHs", - "marketAsks": "AmEjsZbJG439DDx4r991zNkC57YgQ91haQiQ28EG8iFL", - "marketEventQueue": "2h8kCaSp4KmTaXTF8aN7Nt4PkDEFAFuWiz1wQ5zAQohL" - }, - { - "id": "HaynHdMQd77Wph8vj9vsjeAV1Ci9URg97zpR8JxZ8JwJ", - "baseMint": "H7Qc9APCWWGDVxGD5fJHmLTmdEgT9GFatAKFNg6sHh8A", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2mhyVpapNJ5ZHLuqBmRM9m2uQLpFGf4vFxupfeG9DTPX", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EoCKWrk2k1RnQYDaZKUJjpyy37yJpxJTEVJ5c9zXn4jL", - "targetOrders": "2UC6obCiuxHj1ahyuCDEaSG6nGo5icQskGpU9y5ZhXtE", - "baseVault": "DqvEhY6CpwhmF7ru4gL4CBdHEkC5G1M69Npy9PHwhvvJ", - "quoteVault": "Frk48ntSNU7fjk5sexecvNi5DrsR3DgDcPvbbgK3sfE6", - "withdrawQueue": "78HPNsCtfoCAXGAan55uK2FZFnw2KxSco1r2rQKDrjfW", - "lpVault": "7jj9AB9y9EBcDRSkCh7baeLVYgdJsC5ibmsxpXyE33xC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ANUCohkG9gamUn6ofZEbnzGkjtyMexDhnjCwbLDmQ8Ub", - "marketAuthority": "DZBSTJzgRvg3pGPtQ4WPV37BYZPdxcDfc9qP9Jpr336m", - "marketBaseVault": "GsS5TtqoqKXRfQG8qXMRvMeirFSJHUqWce9FnQwXsEoH", - "marketQuoteVault": "7arP9vQchDd5SRDp6bKekaftY8rKV14swEwgT8Jbk3NR", - "marketBids": "45AkQ61XBj5ZQ6qgJihfCyhPDQfXxrLTZ8qhJMswRnrH", - "marketAsks": "9CJHCnau1cfR2XsTzGdzKKpM3RxRxeps6eGrptdgpx7F", - "marketEventQueue": "HxKFwneD2m7PreQYHwnY3VewiYCfUB7to3trNUSjZZY1" - }, - { - "id": "HBb5qqZQ8jSmeHqSwtTN8q2wpvQzKsZCrDbKyG7hLC6", - "baseMint": "MRLY2ScVMxXJTieiDi2Ywdm8VjEKeLcY4THL2UyhHRA", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DG3owVior5ZHfSyXrWMbtnsax8tqnyG5Nfz9rE4tDpz2", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HzqxkrbkjfyGxCBxg3MsUKsXmXQLusbs1TJjAuToo51g", - "targetOrders": "546ac56w1zJo7rDLBQgQohFS135YzHLHEbRmMJxKpsdy", - "baseVault": "DbxBjjTpFUNZ3Jxq82XCoTyMLSdrukEHd6ZWUbxMPiTL", - "quoteVault": "B3nBcUqqHPRM6hVCD5dnVdaNov8QLS2xMN1dbN8kgpku", - "withdrawQueue": "6PZfbV4KHFfz1NB57ynQbQRVLtRjnFh9od8LzXvrkRCN", - "lpVault": "9FCyTkWrRopEVgMWi3NAEDZNskJEKgJLihtsVwzVfPFJ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ALX7RRLhfNq7XGDj1h9yPBMqL9YFGB9Z1LfFdySqDQgb", - "marketAuthority": "B7XZ5699EjEkMMpLNBc2JnP8uUiugeayjhyKh6Vv8XVe", - "marketBaseVault": "ED5YZTFpdYwnNrs7UNuMrjatrQBsWnbKhLgFSsNs3JQB", - "marketQuoteVault": "CQAd516bHeFQcr726kBsgapHyoG1e56BGkXrJuKVt152", - "marketBids": "EyjgtZADWDZuPuqkQn1CZJFg8JdYQPhog3WmCRtyciHK", - "marketAsks": "C4vMLytExxDmQLNFD2xNeSEpq1hymmTQKex1mkz7K69U", - "marketEventQueue": "Fxi9kHGfjjznyc1A99qenDK3SgKTAhFz9AbuBtrWcKLn" - }, - { - "id": "HbbJKGMdyo9nBYukyZ3cKP9ZrG1btWS7Zj22Xtdptvor", - "baseMint": "ELXRYrf8wd4DcyXDU9QPnMdD8jn2twg7o7qEtf5z2GBW", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FoB9mdHSi97DEP2c4XC3qRVWLHidZCqgoK2xH5AHPQYd", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FNQhqHuhq6PsAMsfdT1Ujn4x5GApf15yB5CxPgMTyizE", - "targetOrders": "3LL596BpKf5FEiyrpeQn9aUUiR5EfLZv5kShzuGziAFX", - "baseVault": "ATDRr5FmJz1i7TT2KtQLQ7dzfuANjCu9Si77opJEfEWM", - "quoteVault": "GsUALwTmtMghAfUH2vfbh7ayrJfHCFkooecpBW8CjqiH", - "withdrawQueue": "Hr1WSWNQE3kMzCoKDVWuzizSRjjvvZGVUSNtnjEenD85", - "lpVault": "5SfA1NEeYEspsbPN6EtF9dTYF68ezDJ8KX5ATHuZdoRW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AQF6H1Kd4wj77PV8omE4d5t298U5zSBS7HdTNx8E3vhv", - "marketAuthority": "B4arvKf6g4Gh3DCi5kG8WDsZho6vPDcGWdbava84jMqz", - "marketBaseVault": "2Nudk47Xw69r4xT8NXiY7YgDh74Z6aeRAcWDjHfLAcZk", - "marketQuoteVault": "2zhkMwj3nvbKW798Xn1uPVE9ff2VMKUREZbZsPqaB2ni", - "marketBids": "AGoZVb8kEJJiGsJsdf3MQZXRWjKF4MrepPgCsr91YHPu", - "marketAsks": "H56dbS6RkNYSyLeexHSLihnYjLqRfuzcBSUhEkWQZvHF", - "marketEventQueue": "2so4EirCTM5nW62YdAtP8EZHe7DjMV5hvELBdfj2GJRY" - }, - { - "id": "hBEp57jBmfJXMfhh9XCqfRBatZRzX1D58wqV2NnFLkH", - "baseMint": "9pbVhTQbnM8ho5kwqr21EhWVehd1PfBt8tyBxeH2ttmz", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "A1CcKuXahzjarUFnDvbKL2NWK99wjroqUi6PKQh9gTwC", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EARUWm6FePmee2kaBPKhdjJtEaV4J512hKqbuWv3sxPa", - "targetOrders": "99pBScLTWZYskV75LxXWMqxWuEiKSQPEbG9RmW8TDXXT", - "baseVault": "CjJtTswTZGbLWWciSz3VzgoTSK568UN6LYXvXshUNhkA", - "quoteVault": "2t1JarUkGWnJ3hAPYU12TBmEnRQyzjVM4VKZW95sdwhT", - "withdrawQueue": "4h2VMCUJ24DRRXcFAga9X3eyDNcrMQy5gxHza2UY6svk", - "lpVault": "HrwYXhViwgPbdrY9Xzc6Jpem2VmgTKaLRTq6QZbEQJG5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7SqN8TDcbWMVeeP54MEkjProGYLCbDRJWHThj2LepBCP", - "marketAuthority": "C63JbXh2wket1V3SegzKnTFs9bHf7aXkUSJj47y7yzfV", - "marketBaseVault": "4bLNP6WeMv6fcBhERG4Tky8zFRFbYEr6xU5DdskCVVsS", - "marketQuoteVault": "5kZD2uu2EHWiS21SPqWq8ZBSvgH9859FWcwy2KfxWrac", - "marketBids": "ezKN6E5B6jY8S6ZksmWSt9nB3hQvmGeiCsTm75VqGmC", - "marketAsks": "CiQ4U3dV2QEDwp3cF9esTrixZ41MJ1agAUxw9BbCHERX", - "marketEventQueue": "A2P2WN1Fb8qy7ePSoPFDEXh1fZozCYFoUzL2aGBpUvEA" - }, - { - "id": "HbVSbscBGeAa9zGjVyny3ojpKfNik42bW6BLvH6bhaXX", - "baseMint": "8CmKs6xeWyrgTwBQPUtq7HdbEHvkV9F3NARx2GMX9wFZ", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "Bne1fEWRZ9PzMrCSoEF68NBbf5bntcJ8JQWmCNAa1CsX", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Gc5Me9HGAy49haaENoUZmLjKeboWYu7wr1pMGfQYekwr", - "targetOrders": "3Mum9sTMP1ddbLRmpuYfYVBpFLQAM8h5cfaYx1Ck3RKc", - "baseVault": "AFzaCokrP8sckN2gJVSAzb4y1FNEFNfWjoC9f6MPfaM9", - "quoteVault": "9NDxrnfZbgAJGfS5e6KrDrGerx7bDRJutFRN2HUW4Xy8", - "withdrawQueue": "AoLgyUozbwsVuEwxAMaYhZi6Rv9TXWrYDQUXsLiVVurx", - "lpVault": "9K3SSjbJvET7pBmgENHTevzDuAQDjrZ9HNmiyVF5W7GY", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CrJAbHuoTA1bLTjwStYxxuLmbhC6dgqJtcskLyvvDnty", - "marketAuthority": "BYYDq9XbT4rKMoPRL3GScJUgfT9vt5cYQSaWG7qxk2Ue", - "marketBaseVault": "CMqKdxF5mEePFiy4hhJ3LvzAkk4UYKyjhH7ni3RVe3fy", - "marketQuoteVault": "GPqf8u3CJVCjcXHfc4gGQ4zQHjDpy2f2jRKWqAjF2srA", - "marketBids": "A4T5Usk6bGYU3ZgujJqc38syvqBc2S3kFP8vNTRAuKLD", - "marketAsks": "DXhCu5AKwR9j5uNqT3gtUmwpWiBmPvPs4wjY6rmKVdS1", - "marketEventQueue": "FEqZgwhYe16d2rDshjgUCZUQPkh9pDAK9ibNuT5L92XS" - }, - { - "id": "Hc2ms9S5YqTpKWUZfhkrJBdx6vHZm2ew8wuvW5t47bUV", - "baseMint": "3LCSAo9Hf64cxtPbArLog3PKkwGkZFN7Ttz1zLdPWPTS", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AKoGCqq3NxdX1k6sRyfVVqBZsEeYeiKYnQrn1pQGAvtH", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Em8Sw5cXNKvfndvapDA7PrzW1NLY2ftF87PqUgQeWoJe", - "targetOrders": "6Lecbv9GeT6vVU4k5qxvS2gcUTbkv7se8kEv6giZCWkB", - "baseVault": "5Z927EcG7XnG2NJjTtorHEGszr5ThsvogKEVVTfejZvQ", - "quoteVault": "Ai3Cuatv11gB9T3AHWRjGat2LCzKCGqJPFs2XZfqtNZN", - "withdrawQueue": "33e6NA3eeUwT8fNQ2xCZXYLgTvpAJWpNg2teos45RG2V", - "lpVault": "HVLPAQn8P6SLwqFqMLkw8PF59T5pk8gCf4nv4jPGqoce", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4pGhmFUSaRm9sVTRA9H9vAJJFBs81jQkieM9D8juAjhR", - "marketAuthority": "Hw11nGqCDSAk44eaPFMZ4kdhNHCEDtVtjhcvyv5v3tVe", - "marketBaseVault": "CEW5zc1uShUpVSmXU1QNBWh7trBBc58iAkrwE2YEZ6Ak", - "marketQuoteVault": "CJGzi98N4nzPiZMrnB23wLQVMmoojoHXddKguZyhLcco", - "marketBids": "5EVLgHPsbPxc1kM1UffgaHDKSQ8JTsLwMoVCKk8TreFQ", - "marketAsks": "49KZuSpu6Q31nN4xtpKU5Amnt1CJSxV1eBRArRvhLUNa", - "marketEventQueue": "C8cAGW2MdtUj1HGmWqRGt4eQk6g6gxRb8YoSXQsZNqX3" - }, - { - "id": "HCGSZE19MX6JcxNLKWywZtGvws49h8fA5zBtnZjG43Ga", - "baseMint": "GXm9UzbAERvZsfsM8CB6sWrn74BJ6ZAfDoNdeNRCmy2E", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "V1gAG5TJum8PZvCTr2Smu3uxhXPMPyTEBVyx8QxdYbP", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "zKHqCHR7aa6ZtHjfKTynMV2V8ChoFwEjGm3VEGmw3Bm", - "targetOrders": "7nS2zgh3ZeW8xzjdpkMv9u6CzRNoZfd6GLaghF94JUAJ", - "baseVault": "9XtRxFP3wzcJmUcumGrvMvgguWYVcqfeYMvMEVTVgtG1", - "quoteVault": "GQsJAcVLTv9KuN1gH4ZFd23vTX283XmK1v9Bes6CLzbF", - "withdrawQueue": "6xaHzYFGgy4ESVtdY2QxutRKXatrApFsdVayLzUyr9qR", - "lpVault": "BWMCofnBqiDqhEoguukcgs1upbY9s3ULrfW5jHLKZJ8b", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EV53DH3GT7chnySbdXi2nx1jkB3Tesmt4eZ5mGFjnjZ3", - "marketAuthority": "J78W2MiSK7kco3PxtmBvfwNEtWnawSRo9Z7A9d7WpnAa", - "marketBaseVault": "8S4zRsj9ZLDMhZM4ox7bMJrtLnrF5UAdaCkRPXM5Qtb8", - "marketQuoteVault": "DoTXTJySpdSzTwrYv1wgBEJ4qciZ6qVMgSpHJ2x8qGr3", - "marketBids": "GV7Hyunkey7dPrVerf5CQDVzdfoW9nhm8y5wx6C6c6eZ", - "marketAsks": "D3TdMgLWeqahZ4zBCRny8NH43xip1z1JT3n5DSH7W2NE", - "marketEventQueue": "4iMHVTgugMvTGWdk3YSqMPLzeAddr5QnHvYQLKcYYJqB" - }, - { - "id": "HcPtWzbLoA8nVxjvzgp5ivdeJYNH6EDnJw7roU1TgW2d", - "baseMint": "EqWCKXfs3x47uVosDpTRgFniThL9Y8iCztJaapxbEaVX", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "7QCrEr1CEeJWELn7kGW79U6cMA8fDd2S36afW8G4Grv9", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3X3rQ8oWBLEuVQVtW1YSLn7k4WmHZ8zHbSCKE3k4NHwF", - "targetOrders": "9pHt3yytmdkWpMwU9V8gj4xSuFgbREVpUXZ2mV3gfeku", - "baseVault": "5HodrKw4WSDNzDbPLWn7EbY6GBgAFPgpgzsps4H744dv", - "quoteVault": "wQCEuQ9T6gCQXEnK5QXuPG7Bz1t7rRfWodNNTVEMzVk", - "withdrawQueue": "9K7Bk8PaeADZHjQJZ4XqYqTgcZG4Gcfmxk2Z3FFoi81j", - "lpVault": "Huq6Nb1UFYoEn9o1ekDAmY9LvN2r4Hwxxx55gTJvtN2Q", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "35tV8UsHH8FnSAi3YFRrgCu4K9tb883wKnAXpnihot5r", - "marketAuthority": "Huwbj5Lp9WrEbjrtmCSkr1vxzMwgRRf53MyYLdDAijWd", - "marketBaseVault": "AYL32Pwo3FMiussnJhtMwgBGEaZwEX4fKRYgLiVvvFz2", - "marketQuoteVault": "HXxEBpBizVwVPGfUwmxT26LuswR5aPkekYapzVEZ1ayu", - "marketBids": "CQid22KsYV4JBFLXy9tWmbZo2fnSen1SnpbgNGXUskQy", - "marketAsks": "4cauJaD91DkWUDDpciDDPNg7hyjZnHKhb35P3LoPnzVe", - "marketEventQueue": "7SC5s8iWiAhSRZuc2MqPtGqhfKUa25GttJkvMt9RAVCx" - }, - { - "id": "HcTtkYppy6wYAFSy3DmdARpCrW4CHXSF2jjrGEKPyyEg", - "baseMint": "7UUWK4HFvkFvhd6U4DxCBi1yY7XWhQguabXK1MxtANKW", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "C4KM3d9QTZt8m9GaysQ7krzviTUnz4gEANyPKhCCWo7x", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AL3GczcCbaiUmgeHJNyMzJ5oTgrUtxb9sZygwTt689H4", - "targetOrders": "FwvMLTfY5zPnz9hFMDuCshjzFMmUDwba3omQjFRPML5w", - "baseVault": "78uUwACqYPB1uC2k1XWUZGaFb6E7j5SRVcozE9z3zMFo", - "quoteVault": "AUaH1HoKyAdZWk1sMabrCfE2ncJPBzBuRcPmFUm4kg7S", - "withdrawQueue": "Bs9bGJc5fj9BfcHXakfGEgNpDBQQVwpp7YYUzG3PrfEV", - "lpVault": "8YheJ2fkkZaRctpbqp6fh8SGdHjxCjpjWu5PURB86Jfv", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2Ygu9Q8Yq2sszcuH6tToCz71AhNBWGPoKv9YWWBJER7Q", - "marketAuthority": "5FwpMYZp1Su678LPzKBsuLrkiMrb737gtyCwFHUSELae", - "marketBaseVault": "23xH4DY1RQ9YE2vgv1C7hH8VSotENHutPUzdtpZDCoJj", - "marketQuoteVault": "6u4XZKEY6JvdMaNJa3ZJopKYg9rgy6KSxest6zSBGnbN", - "marketBids": "DDaWMoeBE3n32RBpfU3ZATGZoFHqCYWaRCMAMnh5decd", - "marketAsks": "7Au3SJft6AnUDioiqKY6M2ixrMNwP9FNJ1zyexQ9Aakf", - "marketEventQueue": "AUDrTumnFDZzAtrck4L7xs9zaKKGnn5seATJge2xrmBX" - }, - { - "id": "HCY4Uq3dRouHzvyFPKGGtJ71PZDxB8WKW7yR5zJreqTe", - "baseMint": "2FKuYE5D75e9Fjg3ymGBrFfVc8tVKac4SeyvZn5dGNUz", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "1HaqfTE2Mh8DjNKCtsViQEHu4wFtzBL1LGX2LZhnfig", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HSvzp1EN7nCK5PyPfi8QmisckBoM3MTiDJChSnDpB9Gm", - "targetOrders": "3ebFpTnnQWkx8JxF4knJgERooSxixZTExDGAfEzqfkFL", - "baseVault": "3D9zsdPVrYiD7EXjn5GVF5bTrQmywuyCei8rExp6JHwZ", - "quoteVault": "6Pu19y7KurrccxmvgQ9u1Jab2FEcvisE8D9AbVy9SiTi", - "withdrawQueue": "6WTCiNH4RxDyZNrDMHhyqkiBYt2ztw99bsaDzCbyt9ye", - "lpVault": "97VWmRdBNE2JcXSibFjJTFrTLfWPrU6BTrGD5teufevd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "ESqvPXG6QYQxjk391WiFf2DVZCC6o9H5yiBiZWQpvN6S", - "marketAuthority": "GJ8YkB1rStMGWcnVFcorncXe8uytT2i8tGtbYqwcY26V", - "marketBaseVault": "AaAYy47rJfNRKtaA1N3NxHHn9Cuku25Q8Zf2c1W5TJH2", - "marketQuoteVault": "HqbY8GR9xTV6fgUbZ2Cj2NgqkzXHJgsgnt6qfZUDD2pd", - "marketBids": "5hvgiNvAGKWnrnrHEAUD26aYRLmz5Gn6heihH3nYUfVy", - "marketAsks": "EEwwKHiuMHJCYfP7mUx1ZffTrC5aJ2kaxAQLKyuFUyfK", - "marketEventQueue": "H62pvFAPZTtT79YoL92FfCNhSqrmoLS8eX57MbGj4G28" - }, - { - "id": "HdbmraBtbNKuLG5FqMZ4ocfHhCaAuV8qkTyE1iqs8BQu", - "baseMint": "2uRFEWRBQLEKpLmF8mohFZGDcFQmrkQEEZmHQvMUBvY7", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "DLYs4hagDBwMR5EBzsQYg83jAfWESREzqc91pDzoUdZ2", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Fny46PoxMHsMY5ggyc34FhzK6efg3tENbhyQfdT86wYu", - "targetOrders": "8dzhw1hK5Kvmyn2ogygrbEJ9cPzNkqCk76BCxVdfWBqw", - "baseVault": "DibUwXLNGwQSZPptSUQB4QZpKf59HmjpQAdbTdzVEAha", - "quoteVault": "GZfz366aAEUC9Lv3sghfVW13BQDm91cFjKP8arrCGSCf", - "withdrawQueue": "67CBfRaBYbhuWQdvjSKTGg6YVCXBkya2om7eHR4u358u", - "lpVault": "6ZsGhqz4XQPBYrnpESucWzAuHPJqv59Qx3PqWGL1LJuD", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "46jD4hpmvUAbhKaoAjdzFkY82VW1j9SMTEYFGcTor8Ww", - "marketAuthority": "9KWBPF6JreExEMhBeTWE3MyhCJB6U8buNEw1iQKizf4K", - "marketBaseVault": "G5PWpBDPTX48zbD7jL8gheuFCm5LdgXda4VwAMij4iMh", - "marketQuoteVault": "5qL5jnXZJUPTY5UjShFPpAQs2sSfmVrKPaFSS8Bv7681", - "marketBids": "DvLkGbT6cKJepUwp9fWBhawT2sfXp7GaNZ8EfugaHKZv", - "marketAsks": "FaRJJP7vo1m5W9JRoa8aFE3zzVKzwSGUNvQgWtpDSCyp", - "marketEventQueue": "5av5Ydbhy7HS6jUW13XYvj8iHub3muTtguukkHV5eP3Q" - }, - { - "id": "HdDjQ1sCtwxDepfAdqA7MNQcB3Y7CBK6DZ5nzWjE88VT", - "baseMint": "8ZSJTmL42LgTrC1qY7AZQkLYT1EZquQA1cA3ze4bSjvq", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5CuGKmD6ZRFnkFYDdN2TjzXEqtkcEizsWgUeSrFnZnpT", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "271NxHSVmHmQ6xD2gZM3CpCCafTFLC2EqJaV7sTp68EB", - "targetOrders": "FCYHHyYZJ3ZFAkJPe3XuXLUiYDSEfWUSycrNVSDdLxce", - "baseVault": "BSLmPwCMtdC7C5bTtXYfVFcADzXMvdEyMYsuy6Eng44o", - "quoteVault": "D97ogZW5aYsh1dEJ5s1UduhQ5jKJKZLnJACjSWCNNios", - "withdrawQueue": "2AjiTiPqFBcZRmgew8zSezE8nF7LyzzpvpYJjWKWTEjM", - "lpVault": "7Jv1XbnGFbkuKN8hgF2hus96F734HiMAScyU6BZaipEo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CVfvsbkKLzB6RDd6VeJT7FVzjsjbGxYCczBGR4XX1kQw", - "marketAuthority": "2MsTK2MEHLU9nBZE6fd5TTKxcpGRGyCEgNMNfdbq9QrL", - "marketBaseVault": "71UVEBmti3v8Dh5fpXJQAkznd4d94Mf3da9SakrnySXS", - "marketQuoteVault": "A5nuri4hBWFif3UFeJn8z67hHvacVxmaMrKcnikfApQw", - "marketBids": "3ozcjZs8u7teDyEt9nUgoy2WbHm2aNX8TKhWA4WvKUy5", - "marketAsks": "83rNgJ19TJVbYti9kRFHKWWqJgijhyWDmLNxsqfyNLTu", - "marketEventQueue": "7LB1Mj7ryRJ2hJokhHG6Nj8G2qjx2AfM8c2YrUWBSxes" - }, - { - "id": "HDQEebBRfQe5dKy694ePaNB6wbQqBpj4UX4cEp4xUo5y", - "baseMint": "7udMmYXh6cuWVY6qQVCd9b429wDVn2J71r5BdxHkQADY", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FHb3WiDZW23jHcWXq1YNRRj7SHNhHSVbJsh9gvjQLuz5", - "baseDecimals": 3, - "quoteDecimals": 6, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "UBFtqPv9QTTCAB1qTkGEKbZPP1MD5qjZshZVPgbe5b6", - "targetOrders": "DuuCTSH4BQn3AZbvQxTkZJfmmtvU8y1yN4VmwuSaWRxF", - "baseVault": "44XiK3hmWDk6wV64yevJ4gKg4NnW9dTrHmKFZYPMdWTa", - "quoteVault": "BWUt6TkznDa5kVsXvv6bmGMerjsuBdvF4TEb1Vnuym22", - "withdrawQueue": "CNuNniTBD7CmiGNhkbD4Li8VjsgNLUVJcCmJNniYQi5d", - "lpVault": "E727tQ52yW3C7s9zAS9Fi3dqcbqEK6moL6pQtS1ps4eN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4VCnuHoo6A3XhQ9YrD6YZWQKVvLxVGzHTB2opNyQi7bz", - "marketAuthority": "8p1H7TJUQQnkeNkhNqD1s8w9ifaBacNAExFFddiphPFG", - "marketBaseVault": "APsG9tyFo8epb4RMoKeY8ukRSuHQi9e8LiasvxL7f8hv", - "marketQuoteVault": "EoDgPEgR2x8RVehPUUfVa6kiTLA3KMSoj6JW2tLLM3Ct", - "marketBids": "Aj39bhoYfrVJU3mWt6DRHut33pS3kHvNcjSV2R1biNaM", - "marketAsks": "F7LM3DhagrQ8Fn2oLVG6JBitk88RE7mjWqtWjf7iX2v9", - "marketEventQueue": "DfYeyhr1KG7CVvYNfWoj6DwwXeAiV5FdevrMGHg8X9Ub" - }, - { - "id": "HF2MvXdpMGaMT5vNSf1cCkd7dM1jrxfvdeMoGwYQJBBY", - "baseMint": "7uv3ZvZcQLd95bUp5WMioxG7tyAZVXFfr8JYkwhMYrnt", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HB3hopCQZJK3vGx1YcMb5swrf7jqsiuJziBVtAikjtXj", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5UNqWWRNpfaLtag6f42prZGGLVcRWNDMohJaKEG5y7k4", - "targetOrders": "AFzxM8Fd9PeX1kyJ88pDmkocrPDrXzY2aXhKBWrkHA6s", - "baseVault": "6eRq5xJ4wyfbyYKFwdbkwGRK4jRe5ZcDGgzhYJtMHMAK", - "quoteVault": "4fNYhSTfCL54K99kTv6rvQ8CTA3LxNGNJToJBUVgD5rp", - "withdrawQueue": "67vMZpikqVJ4nKMk1p2dx5YW8LAEjJqP9twxtXTRU3WC", - "lpVault": "6ZBrKokQawdCZTnxdVwgaG4UMrL7x3MDcXMMmwsYmaCU", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9yGqsboBtvztDgGbGFEaBBT2G8dUMhxewXDQpy6T3eDm", - "marketAuthority": "Gyx83mCrpvu5a7GzDJsQkaLkMxFAwVRyfiJh39mCv5ea", - "marketBaseVault": "6EiF23znMzMei4Df4NLfF78pAVMGkA1JCQRX436j9D7U", - "marketQuoteVault": "BJt95cDLUoKeHNnVPntYCW3BBPk3V2jh3sERFASCQTRd", - "marketBids": "7BSFPz6UHfXtGboUUwzJ76SW4gFUaeASS33q9Tj414c2", - "marketAsks": "FuMkvCCvJdWrKSW8MyKob3NwAisVgtB1CapkFJrcqcML", - "marketEventQueue": "7KUXbicJHzsgTkhoC9hPKk1VQyQ8iT5d8yYW44yKjjys" - }, - { - "id": "HFDuu77A4ChRQW3Q91GqZpNH3rtucd9hDUqCTXGGUTrN", - "baseMint": "4tJZhSdGePuMEfZQ3h5LaHjTPsw1iWTRFTojnZcwsAU6", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "6DGD2tQaPPaupNKYJhp3JpqSHnY1mUqTMQsVqCASriau", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FAJUpB3Mb4ff3Q8wFtuXpN6xqfEBZzScGkBKKxecgr7N", - "targetOrders": "Du6MsaT9p9CExZBs6zKKsLFRujJtNbY2btY8bxb4iYXj", - "baseVault": "5SUaqvzTt28ov9vg8YEdvneDg7KGUkf1Ss8DmMdC4W4R", - "quoteVault": "3Nj3hxRsqxQmd9t6wVVfb2i2qPN9RmjBVPER6Y7gmWzp", - "withdrawQueue": "9wrxtgano1HYyiCMLNWy1TxQNN7ThWQXf9HXsysmVLpU", - "lpVault": "GJv6jgUf5ABrBcPggyqb1Ycbtm5WGWSARamwtbUgX4iz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Beyzdhjki9sKyhEykPPXYY1QqnbkNVUG4nxSMkD2tZFe", - "marketAuthority": "FbCXgsKQx5ixcBtYFDdNkkgokrbh37Q2WG8pgEgdAdf8", - "marketBaseVault": "HBP3fGoVSVTR7TTww21ur9HkFkiMPobrXzkaQtmHLyUh", - "marketQuoteVault": "Er3EZwx7EybtJ93N6XtKNZi4sunHrq1PtsyDVB2TGwiW", - "marketBids": "C5SaMSqmk15uMwcuCCNirEa1rbPdoBY6q64g8DpXdSk4", - "marketAsks": "HTaRRVhR26ssFHFDdJLcwTJNBxHnTCRPbjxXJzWdnZni", - "marketEventQueue": "ETtEpjzmQrThb4CBzt3EUJr5J9n2Z6Tj1LTDqJLSRPRi" - }, - { - "id": "HFf3gxt1RLiGiBDwtdzYieq4Ha8TtdTZpy5dNTJRuqW1", - "baseMint": "9QXAu7FTf7hmswBQwKxvuqGgWH42FyQjqXJanUt6y4eC", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "C2WDKecogknBujCevfXtueUS5RQAYC6U38BVMaLh9Wcf", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HcA5P4zgSnS8Wn384VP4UnxF2W4iky7kpArLew9VTDBp", - "targetOrders": "B7JBWweJ7BetLt5RtBEGkJ9stTKCPwsgQ4tigocwJctU", - "baseVault": "GEftVB9U6UVCxpSjiTMYnegsewPujNzYZtVGoA3ydnQp", - "quoteVault": "biBgQFHPMGsd6CeE8B64wVLPRbLb1vmg1EqiUVrR8ZW", - "withdrawQueue": "6REXBtQfJX1qbB9c4C99FRau22SYZUn3j2X35zCWiyz", - "lpVault": "21Xw6xXQb9pFowiT2qnicjXH3BD9JFKh3TnqRV8hb7aA", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BL3LSsxMgzV2p1Y5eWNxQ6wDvLoyDMDPXGHRKyJgp6Qa", - "marketAuthority": "6GpohfA2sioQPjtVaT7RQevCCVLFXuk2qCbEr4cvZ2PS", - "marketBaseVault": "6pAqKTFzAkGq1XEbqWpzvNpKoybBkik9o98Rd5Exo5Tz", - "marketQuoteVault": "4H62pPxQtxsTqaNUQdC3MJsESZ1qrzD4DcE1V6CbvHtK", - "marketBids": "ELi3phZAYZNcPMTwiFqqJf6VUx6KLx9VxoufLVRDAhwD", - "marketAsks": "4DdtRs2NHpgFHXaGe1q4Wpi2LCYpppAmopMSAHHpH6BZ", - "marketEventQueue": "3xXcjpEyymTY7yaPoMGPPC14viATV3jsj9bKRXP1RDTe" - }, - { - "id": "HGC4oD9DBGvwPQNLXk7ZxjmpBvjpzG2PFbducbqLdaLQ", - "baseMint": "kc1tzKnnWkGjEn5DtY77QRtm937A3gx6gxz7Z1Qc8is", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "9BQkduDewLfRkwvmavAQ7CiRjpFgT6W3guA4czdG8MFK", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8vbzwTFkkjasg3XpQpxnwkENn4CrGZy7p54CEL76oV2H", - "targetOrders": "5VVUdGwMPoPjLsikvpJpSM37foGJUc2csCCrz3m3xcoi", - "baseVault": "9SCnCFaaCbDKWA4dLRKxKG5zh7uigL4np6Et2ox46sU3", - "quoteVault": "77T7JcfLhAAQFpmRjDTxTkyfS98i3GYKwJPo71TgGjam", - "withdrawQueue": "AbqKh5WkXD3RLtSUDxQYpgChWbJW7cRUvbVGk17c2Cmb", - "lpVault": "HPPmYRv3dLjn1LX1Udoubhpou9NThRA7XYJEiVg4WENs", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2GcecaCcLrV7CoJMAKr6cVkUPDRkfB6Xp7ZtFhCHUHEY", - "marketAuthority": "9wDa8fDYJ61Yyo2KXeHZe4vW1rE1jpZi7mcemrVksayT", - "marketBaseVault": "CkPJErrR5MueykVXdvhYq6GW5AqQc9PQgaBMYugJZVzK", - "marketQuoteVault": "7QWCkecEaveqC94ntGZYWa6noJP3Yq4KiNShA7ZE3V65", - "marketBids": "raAvHyWoFRwDY3GUwoHoLySavHuKeoW1xmdYZvBrQPg", - "marketAsks": "6b2SA4xNQJ9XzW77MkPAwGBeSfSK7rrr8F3fGnPR4Hw6", - "marketEventQueue": "BxrXkpAibcvNknMdbtfHbBya9YYaGSHGjwDLBXV2RSGf" - }, - { - "id": "Hgg31Un2yiU49d2tQiQAUQtyz6P21RKQ1zvNkeFyQRiS", - "baseMint": "GoLDYyyiVeXnVf9qgoK712N5esm1cCbHEK9aNJFx47Sx", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BKbVrseY3yfzqB7fzhYbWFsMKG961rvmNx8nVZpbpzdJ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "G33hiRhYv9rm1bnGAU5H61iAKL7qJcXg5afbPwagZSVd", - "targetOrders": "BiqbR8uE2MFfVCL9rPJwXZawwjtBXXJad4see3HCg5uj", - "baseVault": "CKC6Sjfd5qYTfAuitZgJiToWbsEJmHGpdG6U9Yexvpyz", - "quoteVault": "AGCMibR6KeSHZc3MsHaQVMMSEEKJ5CZ3kM2ssMRVuiUx", - "withdrawQueue": "4TZZZwbMkQKFn8gCZTroEpaCXQJHvVCVX22gryCmw8Sx", - "lpVault": "2pr3gbyEih6FDxoHhu7wm9VC73ShYC9QAgPeaPWKazHK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7p65UwPSej8ndPAgaqYr6iAw8WCacQ4uXrKKBBkytBCA", - "marketAuthority": "5PW3xz5xvpWETtVgmmoySQ1mktdDXBqBxzLdt5wUyfRb", - "marketBaseVault": "9RFcLCUh46wk6vtUw7F9dZFGUKnLhhoZNB6rXUnH1U5y", - "marketQuoteVault": "CWu9wkCRCamF3zPvHJysKvNXZmZ1boJCtnNoJyRwEhJ5", - "marketBids": "54YC5xDN89xCBCt9T5nPF76P2quTG4GETm2tBqYqrzPG", - "marketAsks": "7gVnBmx6BGreM9rKkBaYrqVjoWRjrzNLSWrnskGuKkJL", - "marketEventQueue": "78xscSPZvVvcsN7vgvrGbiq1kaiwuYHnBZd9hZE5MPzW" - }, - { - "id": "HGUPYarmNJVehGB4UW4Mv4Zb2xtEYAqSck53yczVHPY6", - "baseMint": "CfzXjG5VCQqZ7H7hxnoZZpA1MdcGSThcm6aaipU3M46K", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "CLNnwSsEAEg7eZ2N5qJz2DtTuGUnEpnY8QrGG8A756Wf", - "baseDecimals": 3, - "quoteDecimals": 9, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "qbarzUmP5Qh8sQCAqohxA1NHmUTbpKYMDJBRSg662Qq", - "targetOrders": "2PrZYMjj8NWysgiX6t8945FzQgVgnxJXhBPHTGztboQe", - "baseVault": "4bcXHh99ci94A2Cqr2UXdiLDa6YFtE8adBbJRN7VW5kF", - "quoteVault": "A5jxsFhkp1nXno3qRgDvPQ6iGNhjtZGtXMyNWCkfZtnf", - "withdrawQueue": "4E4grjRge6FmnFF2M5T4Sfhq32vCPURNR93FaFtXqDxp", - "lpVault": "6D8NXqnVwxjeaVxRUq3ebFSDhbm7UvJvSuLfvinStLRy", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GMtsp383vCJMUjHBwVV9CnMeW2SUfa7YuNAPjU7qUugt", - "marketAuthority": "GhH8p8x52t8QofiSVDrmNDjNRVYPNcW6F4ckwxiuy5Q7", - "marketBaseVault": "BpzbEYrmxsMoocUAiCQTyLwEQW7FGauK63qmRSZs1o57", - "marketQuoteVault": "GcLQ2RR5QbaMFeuuJiaKng8N7xGqPj8Ydw3iVjcsbVTa", - "marketBids": "D94NRqmkr8SzzAFtFLNTBGbdge5UWUd2Hwq42rUZZ1j2", - "marketAsks": "9XgdijoAwGzHgFvUUwuycNHALs3oKruGB2vQb4jdv7gg", - "marketEventQueue": "GSnBZjGLVafSto1CmAFXg9TJCigFg4NmZ57evEvRyJcr" - }, - { - "id": "HhfbLT3eE3GLcuWAAfRk9yLFVtmoXkWtGFH5juDx6bim", - "baseMint": "2Dm1zu8ERJGBs3NLXt8s8Vor3YHwJye5E2pYhLiMHU4L", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "HDnZSiUK5a8iwNQeku4y2y9gYr7d5uFZAwLwRC9tYAXj", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "H8D9C2nDLtdqryRg1ezLLaxomZchSVoxunMe6wfbMzg3", - "targetOrders": "2PSFTCVKGhWGvQhXzwqb3PeEExqeYsg1Hz4YJQtcktCr", - "baseVault": "CH5RBF72bFddHe2F3sGYXMyLm1XG9XE9W1m5TzXU5ziw", - "quoteVault": "DodD9tG7mrBPWRaePA2Sz3DrpdyEWEQCuG4SUKkKJ7o", - "withdrawQueue": "8cEzXxzcnmauqRnU37Bn3RVKkJfMswPy59kWoiTWpJ95", - "lpVault": "3NpL6D2tBsn2iQewkvXqm9TmRbVjmuyF7wxL6UbBWphd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7P7zp9aEaiEj4XN5RcP6jRN3EWsZw4opRVzJwxgqDGLh", - "marketAuthority": "9PrdUfMpjoJbhEx4nhhLbuwYsKffkdu16giwGVrqbRdz", - "marketBaseVault": "6DASga8oLY9E5KovVemKiYM1nWPTvPcCDaE6FsErf3Yv", - "marketQuoteVault": "DDjnHHUdNmBV3ZjUWytFfSDDAJDq2EAdEvx3ccHP43uN", - "marketBids": "5oJdeQysXQ8N7A9iNj72cp2iVKf3yNuTgR6WxGmqvXt5", - "marketAsks": "F2piK5CZAZnVQTqMQg2RbRqE9g5jasdYd9RaJk5ukvPr", - "marketEventQueue": "D44hCvzAHidi3U74mtD2wyCsAUddNkRbVtrMA5JhLRSZ" - }, - { - "id": "Hig3YwomNMyPxS3YB895tP1V6Z8BuVqpi56kRLB5ucni", - "baseMint": "4vXidyArpT8fyQTmfXfMNHitj5ay1Fjcnbw9fJLL2zBa", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2mALRuVb71dntqfiK2p9LC8o9jgyZ4CZihpNp96LziPm", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AUwiE6eDyQ3u13UtDBmKjJaDHTwp9SBAtrWkyGJaxW7x", - "targetOrders": "kNu8NjzyBFaCgvzf2UTVvmw1eUE5D25at91GSr3wBW3", - "baseVault": "HeSjYtGrVFMQeGxRaDCgHJRL7mqg1TputPgGF3xwgpx7", - "quoteVault": "6g4AqevfdpQVbtxxHQB3MU4o5yPRnqexZytjmVC7F6ia", - "withdrawQueue": "3RXSxf4ZvmbNK4bfM3gQP12n8djogj6byAupHrYFcSQq", - "lpVault": "Eg1Wcfjitnhio9xPwDcEjJ7bUE8tJ6PL7fSnR5hsPTBw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GHueCxFTNBXomPXm2updxD23uhZqPfPXb46iWLRMiv1t", - "marketAuthority": "HVeuccTgCLAvWqyjJkTqyWCA36kNMZszL1dPvbeH1g3v", - "marketBaseVault": "G8AhsBY1ZqgUqhTykzKKh4w7ZY4KsbQYQfLYtg5wznnk", - "marketQuoteVault": "58rByU9N7WQZGnjkaib9itBNt2dU7U2XVkkVpYQJTkuW", - "marketBids": "TRCWYk9F8nk4yNQydMeARaTviiAPvqqqUS6TPNrMZVt", - "marketAsks": "DmdNFPpadSDp3Tzipjp2GgYA1FHrnnnkUhtqL9CLdg87", - "marketEventQueue": "3H6JvMC6hQcKagUkG85sRAprkDtxuGJiqUiJmKC4oE84" - }, - { - "id": "HJ63PArxvqZPW7CDKQeUwNgxs3LcR8XoT3dNcnXseM8z", - "baseMint": "4F2yutcbkabE5MJoDvrDLa5U2re5HPABSCVKA7vqrKcH", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "YiAVhzLzLyCV7rJDor79gr4vkfmFJvVKkwEuGSqJeuc", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "D1TRFTMaekiu273wWG5ixKtNAECB1Mu3b6FpHBM5iTJz", - "targetOrders": "E7phAbqfzq3WLh1SpuZi9eGFGJwZt9ob8yuXGZw8yoAk", - "baseVault": "Fp2XEU3izyBVfzoqhmfKy5c52oYnZaEpMAE4Dqe3zkSX", - "quoteVault": "D1wGyuV4ukDaWXm67bqyqTH6YrE9qHLto65vYB5mhDh8", - "withdrawQueue": "7kXwfS5i7HCs85kNmMqeMD2N2M4x1WzxypeQ3ZjppqSh", - "lpVault": "Gcb6DTWHiJHzKH5w1s6YLWtjxUXvDkJN9TtCYwAAUbHG", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EkiVxHDyBSyKSodeN9VuLJTn57rXh7uR9M5viBovDbAj", - "marketAuthority": "6i34t919oBdsSpUdk9GHBhHgG84kD8vDJm2qFCXpNxxa", - "marketBaseVault": "5r1zm1WGLXjkVuYKXr8kcJZ3Az2kGb2XpjdiKfvEVtFj", - "marketQuoteVault": "At2XMqEnix1U9inVkFPyoWUmXkDY6P44Fu9j7rsscBCn", - "marketBids": "7gny3LdWh1AxuVMzfJtkA91u9Evm1q2EQKkj3aeD2L5k", - "marketAsks": "6f5VeefnvZ6GBmpw5QY2TAui3Uc1U3H9cpbzgc4Xwops", - "marketEventQueue": "5q3aTdHA6D17HgE1dvGUjXuqyWVb8CgGSZWhu4W4VMBM" - }, - { - "id": "HJNaZ5dDrKWKqo6JiBqjNvqfDFUtPVxS2fotbCdTw7pm", - "baseMint": "MEANeD3XDdUmNMsRGjASkSWdC8prLYsoRJ61pPeHctD", - "quoteMint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "lpMint": "H9wUyrxpAErmdNVPitpHSXgwoomoh91ggJKPWtQQoCn1", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "54cnWwpSeHSoiUDahV8U1uUWSis87vtNyCeKF7K7WK1q", - "targetOrders": "DDArGWttBhSiHh5BjbVQeQ6Ts7XgFpC1x6vyccqTWtLE", - "baseVault": "83UAY6dA59L2Zv9ZL5Ft8KCKZjnRGQcJPgWNQa5VJh6q", - "quoteVault": "CoF3nAMVJf7ocpWtWGddxLLBLB3oQqT4tv8skpSyAaiT", - "withdrawQueue": "Grgij5P3stCAcQvjBfZVUHKM7sZtBeeieyqXmx9F57YW", - "lpVault": "BwUiK1qmSuKTMy7N53ATvMFoQucpbgdhJamSejBA6Ym2", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2zJKJgDb8M57J8K5JHZqJyU5ZWZHsxyFtCPi6GdRCi91", - "marketAuthority": "7pGsBYpbqW4CtPtkTVhF6YWDkKbJmHn4aA2y2wS8G3Ra", - "marketBaseVault": "6j7NED29vGpuxvP93bmboW8Xg7APeQsQxDMJN1bWcGvT", - "marketQuoteVault": "7iMFyTRDFphBP2yGMYzJ1KBRNiVGkETRtdiM3aHL3zXA", - "marketBids": "4sZWqXVCP95XWjZ4VRRXckEo7f9CHo7JqHKLb5uxHBsH", - "marketAsks": "G4veSFrG391iUoRtHk2i4n5U9mM615znFo8W8bvfiKsM", - "marketEventQueue": "3AFun7buXGinED2obUUCeaebtNswJJKaiUbAJGrLnKjY" - }, - { - "id": "Hjp82PBH2i31nGPHa75sjKgyobwtFCChWYpQtTwXmGTt", - "baseMint": "5Wgco6reiMwazERpAm3JS1xD7JBHNJJQdNEE9MrUkwtJ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2Sx6Z6ZBYfQUShK9eyHERy8e6gq9LmWtiZ1Q5oY7t4Zy", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8uBf1RSKBPy69UW5xVnfVG9aH28XQDhQ5fHDFoQE6Ago", - "targetOrders": "Cn8Maj3XDjhA3EunYvH3QbjWuEE7LNXuFx4c7qKPVkPV", - "baseVault": "GcTbq8MTQbZCYUd2Ew9w6ypwxzuMzehozYobNNADp7iS", - "quoteVault": "Ax2DfiewkhUugQ4fPq3Q6y858H6rRZ3cFihGzuFAinCE", - "withdrawQueue": "FGpH5vHtmDhGFQkXSy6WYKsNBZq9Rh7caSeFPuhUDy8k", - "lpVault": "BFEdLuhE662mfiNQ2GXtYJh8FszoyfhwzayQ252rTZFf", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FreWQfxGoyc4MGaq5P6RGB82gRxoxCrEQdCExPme4c35", - "marketAuthority": "Dn6nXX4AoprexMS9nSkhstqeJWEDWACLgnWriFFCRCS3", - "marketBaseVault": "HkfACG4iXFAY6nUrGnTa795LiYK4wAPPrA76nBFJjiQg", - "marketQuoteVault": "13cCCDQyShkgFU3atqsccbZpsooGNXN3KPsKHnLJVrDX", - "marketBids": "JAXTUk9MWfGuEGpHsYgp8LP63AYhesQEZQmhMcSMbEFN", - "marketAsks": "13GAp4rgBzMSK3YWwDUncaxCG51JuDusYLjQNoiZGGi3", - "marketEventQueue": "HLKKNwYrMD3XkEFPdWmWkMJshwZZd7JSpHW4admBY4LM" - }, - { - "id": "HkFSkhEQxiPLvP6iUqvRoUEhUKmm2qzbtcDiLCDPx95u", - "baseMint": "Aw8qLRHGhMcKq7rxs5XBNCd9oe3BvoAhpNMVz7AdGmty", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HHoWUGxVdvJdphioHECTkVYZcFazFACjPkajaeghFy9U", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5WsRMsS3ymvt1Zmp3H46agmi53WtQhyjSoPWuCRWWNyR", - "targetOrders": "8t1wnuZr3bi88xsUjBRePJwD221kEBGv9RXiQC5T6xGK", - "baseVault": "2TcyA9hAw5jVhkYFqAkeNwi2yr4qfUytA7iTpfSE8Ewn", - "quoteVault": "FdwdTtLAPWZozttF61YgvKahdcpo5iE1pHWggj9zomqK", - "withdrawQueue": "5WpDY5fBFAFPR388BPWdbHH6YDXntcAepucKUBtNZxAi", - "lpVault": "EvJKDc3Wo6Dwfi6uuHrYmLxerpwUv24hM2rG5KBuL76p", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GdmQtZpXZiasZi6TVsDHVLeNvPZY1dmuQ82KXDcKEJPy", - "marketAuthority": "ETGjLFBnbNTRycaankAPa7tyAKjrDJ3JzXZjqZ43XEVc", - "marketBaseVault": "GHiMcp7KBsoafFnhA61j4A4YtBVWs7Wz1grsZ7XuucVq", - "marketQuoteVault": "DfMmgTUShjWYYiN8v5yaVXWWKAMNhKoySwQU3cN12k7a", - "marketBids": "BwKcoYn3f1gez5nLwsrNqPbsB6xTPQJPoTQe6KFwyj88", - "marketAsks": "3aopzafwV4pzXQ8B1MtkAXYqioTf8hWHeGwtN3r9zcnq", - "marketEventQueue": "CxDEgBm5fXgBtPtxTeqEBgqxg8MucNGTnyzy2TSUN7fL" - }, - { - "id": "HLae14VwFnttvSuXEnRKqeG3b6yqihDjhG84E3MgshCL", - "baseMint": "HYoGYzMcbYq3tAvpg15d8VFYVHw6jWEVuGgpNTrG8hps", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2W5fcbuAuVhaZiQQBxsuRxK9rHBTq92hCsNxCQ8uwkFL", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "F6xEmxqQ1dD7KtUD2MgPcqe4o1K163DAXpvbtrN1zVLQ", - "targetOrders": "GZ3VBEBjXWS8QD7yorFpxcizFmWgFVwqsHnk3myehrCw", - "baseVault": "9YLqjgKd3WZVMYWqtHzGuuNx9XohVvMWxmU6eAA8mSho", - "quoteVault": "13jqgnjDZgerKKtD4tJDLE4MzmGSj1tiP57Tpt4PNkwa", - "withdrawQueue": "6WxMNhgHcMwpaacVYvNADDo6NH7nQ7sdFPKUMMC15zoS", - "lpVault": "6vuM1RPVAYSHEMpsftug24KxcreM9sxVmCuMNBtViUyo", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4M5NhdT3GBUNZvHQvifvpfp3bJfZwSKGnbFfnNy48cn6", - "marketAuthority": "dsFks9yVJRHK46JCcCdzdRdNYhKCUTJtuagC4dewqy7", - "marketBaseVault": "H2vZUuDLAQKprLkM12VZcnw3XRTGk8rDYbr9BTZ9fZeM", - "marketQuoteVault": "3Xxa1FPUpwtkQ9q2Ep7ktK2EA9Eh4vuP7MEnUQmLmHiX", - "marketBids": "6qPyCU4X6fs1uoUcV1pM8ZNxDVzoxazASp39UQdc5fKw", - "marketAsks": "4hZRu7ypJodnXtE8q4q33NMLS2qUKqNNT4RWoLyFVgCM", - "marketEventQueue": "5tVamVTcAVkzP1hvNUNVasCbrWJ8Qyz2RJ3pSrRExuPT" - }, - { - "id": "HMDDVchYSP4uJBNFnWrNHg5rV2efy84TkVf733RPHm9k", - "baseMint": "4wjPQJ6PrkC4dHhYghwJzGBVP78DkBzA2U3kHoFNBuhj", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Fx14roJm9m27zngJQwmt81npHvPc5pmF772nxDhNnsh5", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HGxwALzDb3pb4DQX8UNSXKuT2KLmfvTWQWzMuDiTM98N", - "targetOrders": "BYKU8U812mQzY9DBEDFMStR3jZubetWcji4HP3LqFWT9", - "baseVault": "5Bo6QT3tBt6etgakvJCo56pL2vfQ9qujrkqMSmb7FsHr", - "quoteVault": "7hLd9dJbp2oWC6puqZwYzmyxR3kUppRRHe4VuHxdHsvH", - "withdrawQueue": "5HXYent362UwzmD9o83WHskWg18TWbKDm4385acALiL3", - "lpVault": "EKeQYMgLfpgNEvNS7R3AjqJyKjWHfK2uNeVMokH3C1LJ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FLKUQGh9VAG4otn4njLPUf5gaUPx5aAZ2Q6xWiD3hH5u", - "marketAuthority": "5Uhcq9gGi1cywkiQTAMu34NVMmifqoAYTKxHM5VLZJud", - "marketBaseVault": "5ddzb11vFKNrvHpJfrZVMUY9Wctue4PpsWoha2Lr6mwY", - "marketQuoteVault": "BJCuUcQMqcLhQXPkbUrX2LwtiX4LxGrFSP3H7Y5e9bkT", - "marketBids": "G1zseR1WpRyFUavsJWYBQnNnTs7dwEgqzheSSjWGsa7i", - "marketAsks": "orQxKJXVMoDDPcQB11UYkd4vSAsGgtuNZp23cevizA2", - "marketEventQueue": "94Mdwn7GCfzRS47aivJyf2W4sKTcApmg34nQ8ABzJ23b" - }, - { - "id": "HMh63pCmD4FwHQhAxSv2oGzBY9B6a3mzsEwbKnC1LDxS", - "baseMint": "BKipkearSqAUdNKa1WDstvcMjoPsSKBuNyvKDQDDu9WE", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DsuahHP9WcG4wRjfj1GQydhQ58PgZkPNmwPot4QpdA9r", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "13H8F5wzN5mNXCrqYBBBSKRLBURJHcChUDxBzeRETAB8", - "targetOrders": "95VPKLGDB12UjTaDtPQ41ozime47eF8yFMwUyT1LQJKx", - "baseVault": "EGEMk53Mn2Fmt13JTCm7P2ncGqxF1Senzq9punvA3RYY", - "quoteVault": "BuC5bndEJPtPhjMA56Z5yvEC73mnQuVm9FhvVspq4F8x", - "withdrawQueue": "5B29eM2B15ft6YaJNbFJxjVbzTZUT8T2nscByRNfzuCb", - "lpVault": "GP6T8jkzMbwfE7HNnSjd8wyzawNWfEqY1LrgxKab7K16", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3wcqte9GHJQk13kxbTo8u932mJqfhBPnagq41ifqF2MM", - "marketAuthority": "6JBdd2sKhgREzB9TkpCX8gRwPmzcudChXJke2tLUqXXq", - "marketBaseVault": "3wG6hBPTXnvNtAZ6tPvQzhwdqSSNx8kXVBiBiedfYPKj", - "marketQuoteVault": "3xSzBZinL5nzcKsvgarhDQF2BMVf5nNH6f9iyrmU7eq7", - "marketBids": "7CGofX6z4AFqX5u7yh11HFivV57hJE5B7yi2XeNBHsWw", - "marketAsks": "8DTU4ai3H2uEmwYKQXKK2RgP1DS8A5Xj7ujTwAxfcAUy", - "marketEventQueue": "5uEpTBB96QnqfoPjm936S2BGiHTuyMo6TntYtejdx1up" - }, - { - "id": "HMhKqQ1fVXEhPdXeDHUWpNa7ipWqYxdRmSbkRBeggFwX", - "baseMint": "5U9QqCPhqXAJcEv9uyzFJd5zhN93vuPk1aNNkXnUfPnt", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "GajAkoSCWxzL8KvVcpCZp1woBAR3TwwpMASvHAtYTtSE", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GEf8z7JMDZse8nDSQchQ55DLe7Q2mnXMYySdWYmcd1wZ", - "targetOrders": "2N3rXG5LSSRhm5Jv9ziC7oC4DbcMd5BqRC65595xMXG2", - "baseVault": "2teNjejMpdr2nbZ8qyjcmdKDNSwrXEWmgzSineUnTtcZ", - "quoteVault": "3RpmEhmXHZ81SBWQEPYZTJxAmxgjkhw6inF7aaG1sfPs", - "withdrawQueue": "6fJJsejhWF7aEQnXRXPuNfq5s5LQzpF3yCAUujKUWmnQ", - "lpVault": "7MDn9Xw2hzZjW7qDQKuz5zvHpjtyhWxXf3WLc7yKcAmx", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GAtrxCY95c9oxN8sycCET6BRdwecKP4iULqLD2uuVLd", - "marketAuthority": "DywsJRMJYnN2wzqizWvtUQEPs2WLHt7ntZJe7STeNw6j", - "marketBaseVault": "4XemqBLZ84nPAQ4nBf7Un34SV6P8xHPhHXSnStyD7Qe1", - "marketQuoteVault": "ALkF31rRiJDugJbTJAYZ3yiwrvR6Quqn41FypqDkqVzA", - "marketBids": "CHdAeWszaUwcGdisJ9qo5ct2uNhy2hCgELSkTHBR1DKA", - "marketAsks": "Dwc8R3detoYxAFmG73DaCrFw7giVUxgbm1B9NnZkuiuf", - "marketEventQueue": "2mbXGchpjyohU7sGYDkuth8EbUZ6ToPenJyQBHt6QMG9" - }, - { - "id": "HmqmqSzKvm4LzrGGBa7aRS3K42vM91oz5MKNsvRLq8aP", - "baseMint": "Et3k45YA6ZMur4GcjuYJiiZSdnr78Jt2AhMbWs4cs3B", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DiNoQsp99V79NjFZfGB6mc6fZZK9STCXWexRTxKAaeeD", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DopVcJXv5T7Kb6fwVnVJQvzCaJjCShG4hVfkqF4iXeaT", - "targetOrders": "2mbDEy1rCCSySg2ULBdBEHUkBRmN5aTeHERfg8RQ7jAp", - "baseVault": "Di1c3JxNKZMytCwksgHaDenkYLYsU1k6p57FxgNV2ZPA", - "quoteVault": "HNkMZpLFAuxD3smhE544qMtscUPzHsi9HPRgf1k3uyV6", - "withdrawQueue": "GjFjLH5YY893zmtMmjdP9Y3K2jHBg5THjerh7vxAbxCC", - "lpVault": "7r7BDhcgpvNXChpVdyCnoJRneTjnBMMZuWNVKsc5i14i", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CUcCcPmEXWSGgbSyshhQ473iK6XSrcxvBc6219DYBwRV", - "marketAuthority": "AUz2uETedGpR9xArooxHGAKMoAmzGa8sewM17DfFHMoN", - "marketBaseVault": "7dJya9ysTU6AGtAEtCkf4aq1chwsYApQ35w2TeBQYUSb", - "marketQuoteVault": "HY9SxM6hS6uMHDhcnFFJHJKF8xQxuha5tTSvf1e5Hsvi", - "marketBids": "G9vs6akCtTmJRh2Mpf5HK1tRkB3bubJs81pmauom8Qp6", - "marketAsks": "G1smeyEAuqD4XzUVp1vCPviBCw8tKf5atS3BUg2xYp1f", - "marketEventQueue": "55DY5vw6oGeJjiLHUsftoP9NibmFReNiP6Hi4CV2TX6F" - }, - { - "id": "HNEiBup8r3s5RdAK7ZseMeTmN71L8pSD24zhrBBoT3Td", - "baseMint": "BHcuncUCUxsBw1yyENizoseEAH2Qrt4UxbcukPhQEGPQ", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "4WQKeW1NfpqTumSiRM7qNZkULGZGC2EJQZFoaRUTMVU2", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3h95eXWQoYNThJeTWspvZFMipVtSfZcX1yfi3ZSVkfXJ", - "targetOrders": "3rkeQeBPdc8F1cbX2DAdtyVh55v5yCP92r2fxKYDw86j", - "baseVault": "24AdJ6kAt6QWKBbxa6HP3buXgUu7vUECPsJfK5YRAYBV", - "quoteVault": "2XQPC3bzDuk3HXFgCNcZazDgessG583oxghigCVXj62h", - "withdrawQueue": "EoFiQwVhb4AWWsZ68NShS8SmaSBqtRSJVS2agQREquNC", - "lpVault": "BjU5vAcB1MDNUz1SuA925GgApF7DjAu7Hpo8dxpjMTtk", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2AcdR2ekHfPCwYYVUQ7XX3XUDUoEHcqdFK39Eukr3Y1m", - "marketAuthority": "ahKv8CZvQ1HAsdMCdERNySjmd8xHup8f5dVLcDTY9ck", - "marketBaseVault": "8Xk1EvZmi2nEDRkkhGfmoV2PQtq3A8zLabgq11MdEbSq", - "marketQuoteVault": "DDicSRxTXgrUz9sDvVFpRyNc25T7RG9GSqPGGBmvcwSU", - "marketBids": "22t3TbsHkPN7BRTa7LsYo8fmxbumHiXMkXrTaS2AbLXX", - "marketAsks": "H7P1Ufvfbm2LWLncKabwcKnCXSoHyPgf4ZPESCH8KPd1", - "marketEventQueue": "FS8FyNYyqPUGiAcDffRgshQSWij3rbh8ivRHNFNFkMQu" - }, - { - "id": "HngbFS7vMUeEm3JHYHJLwEuitdeKXv8oe27skwwsiYK", - "baseMint": "6j28waP2NyoCBJrrVNHZuEzLDL25DXdNxMFsMNMxYht7", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "GsH1wG8w5CJTnQSaGMYfnzFdkF9ZwyXtor9Vqm5LhpNL", - "baseDecimals": 3, - "quoteDecimals": 9, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2otSvT3dN4ZXbbEXrrYXCkbAL5jX33FUcwjukDD7LBx8", - "targetOrders": "2TJXUuKJMwxoKHXUCfrBRVkTfeRtPqXWM4JGxfdBNtbG", - "baseVault": "FKSWVnzVz4bPuZHKqQxy1QTiWd7vmiJAqFHMYe4UGTc2", - "quoteVault": "GHm9D2DSuV36q52QabUQQmYFJt9aT5N3GRZZRQPguS62", - "withdrawQueue": "J3kr2Mwfi2vhpuhwDLzsuH8d9JsBFtvFzw4CSczYkamJ", - "lpVault": "5uLh2h89HbUscRhmVd7NDrrcsTn4iQN8Si9mHegRQCMP", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EQ5XjC1neq4FbqLUaeHLx48CTougsPYdsGgti4KqEFUT", - "marketAuthority": "9RSw3FtK8xQEux4pk1xmWZh9i6KXzLXz7UBmM294X9t6", - "marketBaseVault": "4bFePSo6EKHdVXaSV93LG4PXd6k8XPtjNS9j6FukjNj9", - "marketQuoteVault": "7sBWrjs3rvfues5by2oEDGGUhGodNSZ7rg9hvxr27Ltc", - "marketBids": "Eot1AH4SQh3AoaUVQtbMJbzR62mvBksXy4pLMZyajL2M", - "marketAsks": "DrHikSXHYFBAqUq74V1QMWYgWijoTqrzXzq1aPzxwWec", - "marketEventQueue": "2akTjSCaYrZGdsVi562DsVRGYVLciUaBu1qB6x9KHfKt" - }, - { - "id": "HNigvZZsXrr83tKmnif27spxQARDA5w2PrDXenB1e7R7", - "baseMint": "DHbGBhZc1yLLgpPqAzr7KGs47oCMfbg2q6Fmg5NCSM1C", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CiPmHuJzhSFv8HNkL2Ki5A8He5jaUrRsefVoeC4xgzc8", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3tkx9qHFe8AYpEJT4htjzCh5buqUv6j4gD1VZCcEvhvr", - "targetOrders": "Dsot4LhPGwLEp32Jbcp6NVEfVZXgAa7WcmWC6ar7AoV1", - "baseVault": "67YRHuaJVGS5kuASdkhw2GD7dRbnTe3tL63vjQEdPFrn", - "quoteVault": "37DM8GEH8BRPyooTGsNWqfbH9yAKxpqPNUDXCVhy1PLu", - "withdrawQueue": "BzrYBZU3g9apxqEEiwMTJx3WXETL4XQHJcvRXZtNRSby", - "lpVault": "DNY8Y2tEhdudaP8XoDPGoSFfAEbnxXKXDF1HuHKKzPEz", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "68K1XjPhT5afNB9uazc9ov8XK3DFeuGFnKtFjX8EU3w5", - "marketAuthority": "6agunQHPpAwwC4epYzGEUDZbwaaUEReW2xZUXMsL3gyV", - "marketBaseVault": "Dqqy8gPwk7TTzzFgLgQ5rxjVnJ474UMBPLCoinv1VWVv", - "marketQuoteVault": "C6xDT4WzHZHiQuNePL74Wqwp7Rz5f43vVLcPrQCLs6JG", - "marketBids": "BqfuFc2LsoAj8fmZc8FoGDxtYWKQN4LmeKVUNxd8JbWn", - "marketAsks": "9UirCszQt3Pj5ZW5dbHTJDiCQkEi7f9cYbf4tA5HaVTY", - "marketEventQueue": "Bo8LPewKrzZKCPSd5vUf4nNsYdwD7wPvD7N7kir3qJpJ" - }, - { - "id": "HNKxthHJnJSTsrctYcmWMk9CxbCVFPpLL2Gs8dL29Lp1", - "baseMint": "BfkeTseqgoxUn8gF1fGQC4GoqHMaCfzmQUgKF4nKDFhr", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "D9yx4kaeYztJkL4umRWdkR2UCF4hd2RfLjXyQ5uMkrR", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2r4JZfUwbFMbCwtM2UmqG6fHF9hnQ63TW78Z31UBqeN6", - "targetOrders": "AUESDHU9Ecjmib2D6CgYqAFThSCvmhRTXtvrFsmLAqNi", - "baseVault": "J9qNGCsRRKQ58s9Pf37i7ubYDt7KSpuwwWwFJYoCCnME", - "quoteVault": "3G4nyQAMogtLWCMTX7PoMXwHw92ALNJjFXHcssH1tQdX", - "withdrawQueue": "5qEeRq89b3fFBGCNJmQLS5eWjvZDNXgzzAD9w8eFEAct", - "lpVault": "G8s8r3ym4MFUJoV9UrndNgmvr2mx2HczGPbnnaczwUWV", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FgffUj181tCtcLVXPhNSY4hHVq5H9supXdUp2F7wnjJj", - "marketAuthority": "712BGRV78uU6YLBC5ordwtz5WhgS2qu4pQyvcvNAXz9Y", - "marketBaseVault": "Cxt5ur3oe45NuLCUAs8veSWeiNjFuuwhYnHw9VW4mE84", - "marketQuoteVault": "2NB7QJrZ2oXPd53h3wiFcMCAdMDyNr9XLk5ryiZhCSg3", - "marketBids": "548kvE9qAta9fEyVPD8Su8DWou2Fbfqm85D563XEXjx8", - "marketAsks": "CcQYdjEi14sKiwuVB4XQt3t3d9cq1gWYt3wU17sV43D2", - "marketEventQueue": "FHxyHUrgdMTmp5uBtCWULQAaVHyGhewCBpN8Aa2kFruF" - }, - { - "id": "HntSdaHL7qAvmrrxo6BiU57dmZcLa6RcpS2jkoodUNtP", - "baseMint": "5xq71UHmPSZ5s68DkXL8wrBVsWCh4zXgcn4wTWkqFdxa", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AS2qaWDf8c7ss8tS9zfDyLfyjuDPs8Ca2jVvNoZaoodA", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4pm4io1vY37MsCkSvi7eVFd5KQyc4Fd5aDVye6AWSMVc", - "targetOrders": "3R99pUEXZRTmToCdUi2CzfkDiaHzEvayUURupLHkSmd4", - "baseVault": "Ho6mDcLbGiCNTePDWtJ6aWxbFXyPPJiBc8XyzTH6Jbcd", - "quoteVault": "FgZpmRfdHZXZqttWCHwVEr5RPXdLcKpAkC9bs8ETrEz", - "withdrawQueue": "7wUQVboaYWW1vFw4hkaLcmvqPE55ZZ4JMq6D6Bj2S2cK", - "lpVault": "4RgyegdnQSXg9Y954f4vWw5aMazi6QktzcqYbGrvM5vZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7h3Pda8GwRg83NifksuZNx9xBS6voe1DyxGrQb6JqfB7", - "marketAuthority": "FyC1K8nk7KnbWFmCQsS849v3UBsgxwYJ87AdMP6oxEm6", - "marketBaseVault": "BWvdZEVfDinfdn8MMESndjxYxJV9rmRpnmphgRMLeeWd", - "marketQuoteVault": "FjTyNFiP6Mx9n8qzcByNCP1V17e3j4Uw1ExETXP6okig", - "marketBids": "HhUx1CzeuWqC8JKTzVrEg4vbdhprbvj4NvGDMu3iEJRt", - "marketAsks": "4i1u2GdxdoujdXJWRiM7dvhkvvB7Z8x3pg1CA2tDk6fo", - "marketEventQueue": "DAE6KhUdvHBc4y51jin7p4WFDSqSt2DrVJT2eVsKYc2F" - }, - { - "id": "HnZD87NMNsCgrgpgkg6m6DWTVtyeoiYbPkeJsAYa2n23", - "baseMint": "Qikhhhg9Ta3Jg7WoDFbSYuCAE14hx9hPvdz1zVp3zUw", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HgsvwQqAPnLgcpRAfoNx4zc7SBhirgn4VM6s5H8rAFfs", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BRxceJtd6GeQPF8h8KGUAssGRgm2cBVG5HFgcvJpfdgx", - "targetOrders": "BGtoNWyVMxu9xo3zJdgBBEPxzNv1zZmghrhvWXuUtAwV", - "baseVault": "HnRxufbdYenduLdbpsGEC6nwdNbdsWfdfCoRmWcGfJAU", - "quoteVault": "J97Zuxe7JRWoT9SqHnBmU3cNDzYZog2rjPkTMEyERPwh", - "withdrawQueue": "EGPH7Ah1mMyNHgevikiY7zakz5xDFqTMRdP6DDrKjZWK", - "lpVault": "6hUFmqiJauEGBkoLGhkwoNuKLaVAwM7rAepLtMT7PBMx", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "4S5EB2oCaeqLhL8pvbebBfeuxLthW7xUv4Pa5n4nKcdp", - "marketAuthority": "GjA9vrvVc2SQ1m5pd66E6HXtSmXDCpx3Hxv6Fqutp2dz", - "marketBaseVault": "GxqKUbPkabL3Xqqby4hQmvasVQmCDnCnTSXT5vBwaMPB", - "marketQuoteVault": "8Z1HSz95m8kGFxhXFr4EmHWE5mUccDgyjGGTpMjPKrwg", - "marketBids": "98godW7mQhC1cozMQ4e3NiFRtsNPvjsTJcHr4RKN83ud", - "marketAsks": "3tXEQ6KmYAZWiygjGVKiFD4BARj6wQEp2EoNeUsCigiX", - "marketEventQueue": "EbWrz57oMaC1ymwb3DPmDac7yZ11QAdyMcRRBHitJN7i" - }, - { - "id": "Ho4oT6fxaGkTWR3bd9qh8BWei8Byb9y9wsmcVuJDyEYx", - "baseMint": "4fYo3Wj5uXhDMLRW6RKMMR3Z7WfWrDpghXjkS4xq8GcD", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FKifbEKgK12AuFucfncrQf8cE2CFX91W6gjWYybiJKSN", - "baseDecimals": 8, - "quoteDecimals": 6, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "DkQib8dHnCPBkvXS8y7TzGJfmsUd5euBfoY1STJPSoqY", - "targetOrders": "Bbai2fLMTDwB4ySHiCHVSb3ACS5u7jxzahk7LckDtDR8", - "baseVault": "6rdgfaesKNSy4VsDPvWj6gJDCPT8XGewzyuZjtmNszeG", - "quoteVault": "BYykjWYYNzfoCzBKgT7xq5fMt8rkejLQcCJPD9EqeBfw", - "withdrawQueue": "EMiETQQF7bEs7AyUguCaKXQshA99ggmonPzRPz1vGPDf", - "lpVault": "Hmb6ZGCK8iHxyYLNa28aa1hjMpnCdF8nUVUhpfEvfzjv", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Esx3MphVgVnbZb2JyAN8K4Z6K9zp374CHvG1nkXmaEDB", - "marketAuthority": "B89RspRP3J7fzwtBmw5PCb8DjmayfAFPQEfFGu7R8JnM", - "marketBaseVault": "JByt1DPTWqMN6UESSfCtwcVFepXRDrHaVHPhfifNQLYg", - "marketQuoteVault": "BFPWQGHrQfNLpsXmjTzQB4ZZf5ZnQfZCFDXNSwew6pc6", - "marketBids": "HdHeFFMsZayvzBtFh12qb8at3HkXFJJUcAN1LZLDTNqK", - "marketAsks": "7APwNQVMtnN6k6bVZEUqGMcEjHrZm5T2gKKqFQTA28KW", - "marketEventQueue": "FK3txAmmbid1M6Mc2dWm57nsgwBqVSVMsvbZixrUz5R7" - }, - { - "id": "HoP2UsqmH8NwqzhWRNEhxC3WCm2v5hxVT9g3k4bA6LuJ", - "baseMint": "GzpRsvnKXKz586kRLkjdppR4dUCFwHa2qaszKkPUQx6g", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "7b4zvhttfwcWRZKZaSJasj8Ji2x9dD5W5eMmbWtPogLv", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CseXs14hgCt9fDxaeUpqHEwy15s3owzDJiqpf1nk8e8z", - "targetOrders": "3wSXvqMdJdLMtbkCZiHEnFVhSeqiDMvnM9iYCkGU9AQz", - "baseVault": "GNp7rcnHYJrVys9VS3WMfxTnP24ktuow1y8soybn3t1v", - "quoteVault": "DEryxWjMApaiJicbhXbEfbADK2JPkT3YKx7HBWNPfTNs", - "withdrawQueue": "BzmaYqexFcwqfb6h4H2C8zaZx3J37pkddLWW3EHuMHB7", - "lpVault": "7AeZFwmhWFUapYRV1kxQSFkLvxhEaShPJnBr74VBYPCv", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3rJXc2tbWmDUJ1dFdnWWDtiSwqN89DbekTNciNydZtJf", - "marketAuthority": "2XCYZ1fcVrucZ1Dv4Q6SLkfYiSejE3u189Vm2HEqxpzy", - "marketBaseVault": "AQgJyb1zGQwLgZeX3Z8hdXVd4uJWt4fFgXHyPJhqEgGs", - "marketQuoteVault": "FtuXaW3dkx424gsX4zrp7Pgs6HRDhyPACm5ESvzQtzpV", - "marketBids": "8MHH2Y4wiaTMcGPw7ZcyVE9NwBLV7HsAfBYDuPioXMP3", - "marketAsks": "C8hGnSFxXfdMf3bBoLk7HgvpTjmfQUWxgER9RGX1GwP2", - "marketEventQueue": "En4PQuxg1p9UhFFZHrf4yvNE3iED88nCykxdmm7Vavcv" - }, - { - "id": "HPBcm8M46morZ8L3aYJA5drXtGyUzwdM2zrjSe5oNzRq", - "baseMint": "ADcEtKSVKDxBUe3JERgSh9q458w3kRKPMHkihF13vxx2", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "GVmKG2hwzE8WrFZEUspuiDEremLMTGwq74N6r1bPNFk1", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Eis9x4DEtn7AbTTEi6H5nKAWnBh3HHX6Nb1qx94L3ycy", - "targetOrders": "3wV9EyARtQWpQTh6kUawLjSYzR5DoJ9qRs1qN9tC5UGV", - "baseVault": "8QmrVKKZGukunzYhgKYotNuENpDR5mwhikVZNJvm8YuQ", - "quoteVault": "3ZdjUz1TmtjAUihgESoSgbzDSmdpzfa1vMzF1abKBTiC", - "withdrawQueue": "5FYBXC7cGWVEeHTMyifjd2BP1NR25GyN8u9U56WiMfn3", - "lpVault": "BW7dMT6hWL11GjQK8ckHVJmZ8yhNezH4pXjkYRqdeXhw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7ovzZFqi3nL82nW573hRqqRBmZjrpGcNcUg5nPWfhRFx", - "marketAuthority": "ELChBNK8zpYZwEJLqhdjiE4tR3xEnZGaZzk6yCwGMcvr", - "marketBaseVault": "7TZoXYjxq4Zv1YwDTh5qDaRrCGCvDuKiYda8z3sXrDwb", - "marketQuoteVault": "D4udVJc6mhMhUPVNuhpFJaS2FEoiN8c9b6oGc69KZEz4", - "marketBids": "CfTJNSZuNVFmybE95Uox3poT8rKh5PdpMomrKxZ7wTp6", - "marketAsks": "4ib59JLp9avuyxMTHZoDCBCgviiZF8ACEYJn2HCDVaJJ", - "marketEventQueue": "2EnutLXQfKi538gmpFpNYroyRagEqMTGzwXcy8k8eVS4" - }, - { - "id": "HPM1z8sdxVjdDXwYkDdjaPvFEtEAf979EQabhoyL4MHC", - "baseMint": "9qTA3A113oG94ppSpiJTwWCyj44wyNcgPAs5i9d7QQne", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "CUTkkoXJVszxEqSZZs7t5v5ZHfFdYSSaj935jKNRDKkp", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "69hGtqUiB6ZiHgTDUaQHyUNpb7kYYion7PwiB1nJ2dBs", - "targetOrders": "HP6MY2NJibmGsFxRngqauosg1AdSiBsUf8PfHDf9eSsN", - "baseVault": "EkcQBuxEP1Ku4QZBpUgDJXhNtcafniTsYYoxJsmfwoAm", - "quoteVault": "DEgF7gtm7qB58QE25WmsqyLPec6DKE2dJ1wEuWGv47ve", - "withdrawQueue": "4dNsPB46GupGRxin83mm3cMUyBRywFVYBVALqBmuYaUz", - "lpVault": "2zKUhBpYVBxjSuAoTuWDPnfS3M2k98tB8wbbSXn6Tp5U", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2FaqbmAZUD8mYBwi8tDf7EW4bmZhvALUyaCskpnpATuX", - "marketAuthority": "CT1Gg72oeg1TxZCtSjCUTcmkgfwGsysvhpwtmgrE5p1Q", - "marketBaseVault": "Hjtk7da9ktogbYDQ8FuJcCjsANSEvSzHtWbEtteb3LgB", - "marketQuoteVault": "CoifVLJoH4UCg22jvEKcP1tCgAxQAiZKB5zWCtcd95s7", - "marketBids": "CNutvTqqruJt6prG8SfLQvJfKWVsZcFiLKdV7JWvg8EA", - "marketAsks": "8TQPdy1ZFUoFqheb9C9VUMgADYiESaJ2drUY4PmMUFvF", - "marketEventQueue": "2dHXL2VgQWv2m31u6kF71ZXMhfiwWJpgTNskWQR5vZuN" - }, - { - "id": "HPRApKppFCq3GEK16JufrSegmg3hLtBYRrjPoTmvzzHj", - "baseMint": "EXQgN2S5baFSqBR9XijnGvtunemdhhj2f9p4K9NW4Y9F", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "14app1om2cNXdE1Dz9d4REXinQLD2G68Bxs5YYgxoiB8", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "C7RJfoCgqXZ8N95N1csSZDevXWNXA26fQKSqYVdK82pB", - "targetOrders": "A1cMXfGSL4hZPyHoen1ZV2iQuXqLubLCqvRTT9xpZZi5", - "baseVault": "5dLB89Bu6P3hMEXgXokftjPLVE8eMSCb1bjkHPYrfLPs", - "quoteVault": "ChPtx5oD253t1XFJ8TUxHc6TFpBdDxi44knbVerKM2an", - "withdrawQueue": "AQFEedXNuDgE3XuvtCaeaEwf5P954dmUHB69ChpBbzP3", - "lpVault": "2LZBe9RfyEHvJKeiTk4f5kuNMYN6yAUB5vq6eoLatF1G", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8E79yfuZQpCQNYtK8tGr3w8xuHUqCJ74EJNvBKg4gvBd", - "marketAuthority": "ArG5t6XYm8NtAJXhY6Fqq2FSWagE9PTNubJxH2fgxyJG", - "marketBaseVault": "3FQzHVGD6A1Y4LK1CnNYugAZqeNd8JPz4eDWrrYpdur9", - "marketQuoteVault": "FnbN9wL3KtGYyoH9xs97VYuCAQxLz9EsucYXyFFNUZau", - "marketBids": "5Y8nWReviJsaKxxXmWrQR3rMUcTN3cWmjnsCEmqCH3kw", - "marketAsks": "8StHsax5uyLMnQnJajXCjhkNQj1zQ4H9tBANRNex7rCH", - "marketEventQueue": "3P2QRBkEh89kgDA8MJESs7DnGRU7BuKL8ae3uhQ8QU7L" - }, - { - "id": "Hq6wRvwCqqjxTeHHRp9P7pvfB7yKUvQnVxrNCpLaPrkF", - "baseMint": "GWgwUUrgai3BFeEJZp7bdsBSYiuDqNmHf9uRusWsf3Yi", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3fpB7J7meCYbfvD8Tn3wqLTegGayvmub6jxrE7V75c7e", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AHCQdH77Lw47ubRXHMijCUzA5m7M4vpF3KLKr5qQqhKr", - "targetOrders": "2eeMqusi9mMpf64YWGPV4EGsMqKKodebMjSP3UocJZXh", - "baseVault": "EkZs43bLpgn3b3bsVtVYpfa1QdEC3vWXuPrsQWwbWKKh", - "quoteVault": "59YZYUd3BhKuaSfazMTfnAhE7N7R2yTnE1ZF4MeTHRdw", - "withdrawQueue": "36x8ZZ6dVXFEgDDBKzsXhg8DWLaCgBxuapTQoaFu7J2L", - "lpVault": "3icXoXLj7YsbyQDgxAuz8hwJEWWKxZf2h975AxWhYzLT", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "H8sjxDJWVxC3kP5uZ3p9eZncc4Czn9pTWEA6bH2XX7rM", - "marketAuthority": "Canbo2ACtYFk4C738XKnviGNbusQfCVGQTHxnGXHSu7n", - "marketBaseVault": "7C85EnGK3nGJ1oxHT5Uoup2zKq9cyxBr35TcibFu83qM", - "marketQuoteVault": "2uQKbsqAFf254SaUwcCnJARGmSnnFAYCY6R6unfBKSdt", - "marketBids": "9mA4rtPsbTo3tkFcJdqu25R7J6K1zfXxYbEo8KR3S5Qq", - "marketAsks": "FTvRRUkrVhDdteaLbSbB6xpC6bhCZCW1tjMvKjJbj6Nj", - "marketEventQueue": "3sRUsdX6LJdTWSPpC888fV3eAyWMD9P3JP5FZRcMVT9a" - }, - { - "id": "HQ9ytVJBMW7pBzMVY9ttn6nri5d68Sahi3phz5JtvnTv", - "baseMint": "6xcfmgzPgABAuAfGDhvvLLMfMDur4at7tU7j3NudUviK", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "83Zm3NbfhiFZui4C66mpV8PqMSt9i4hKqqbSdoVgzbJv", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BDFH18GTbBnusmMQ7vT3u7YgdQkWKmkLCSey7MRs2byN", - "targetOrders": "6NQM7Wa9tgMYwbdj1LuteJorxPeo8yQRJVgEEBVponDt", - "baseVault": "7iNmK1Bv6DSHmgYdDNxN94Wyg1FUAHLWRpdQ6qZRm8WD", - "quoteVault": "F9RiXdBpHdJzDiuYwS1YzxbyMGMDMBCDfBkiWXD67gND", - "withdrawQueue": "Ai7YUH9iTLTho717DjKnYEujGyR1inrkZFETq1uniQpa", - "lpVault": "8UWfuhbEAi4BKg63sDT5UH3xLzJdgkVhJu4bx5RUmdaP", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BHHvygk9aQ6P48uitEHk1eTGtXxX2Q9dh3W9U3VZhGWj", - "marketAuthority": "8JWzbZKAZkeDvy9HuLZFZLP2kM3BC6BMMXJu3b1ypE3P", - "marketBaseVault": "CmpzDsoej9PRc1T4VDEzQ6EGY6zMBc6KeYLkXcY8LhPe", - "marketQuoteVault": "H9tVsFAC1pQzgYzC3jDCBe8xkatFVa4quDbCNTt1L6Jk", - "marketBids": "Au98ULhXh49EX3BscWvCfiNKMrqtdKynZy1oNYR7Vud6", - "marketAsks": "FpzkoEeEADTqoLp7PCyfUxHKebXC1CgeTycaLcQRiXCm", - "marketEventQueue": "9JbGbU8qi57EQegGv6MsBAt8FUqSmytreN83L4A8yyjB" - }, - { - "id": "HqAqxfcbu74nXVNy7zwt2WtcrrkVsP6CcpNXh64MNn8r", - "baseMint": "D3cm6WRnyBct3p7vFqyTt2CaynsGPuVQT2zW6WHSTX6q", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BgnpARLCjDkdafwvERSkTL6yEe9z1mmuwAXmUhDP4mai", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9B4vwWt2XxknPQZ1ngjZJs762PDLyfRLrV4EoYcPuLoW", - "targetOrders": "5Ax7AjGbqmyyXh7zw1JHyL4m72aXCgecsgvcXcg478sS", - "baseVault": "8t5Q7saUpg3qBZNAVDqHX43AZSrAs3pUKW2Ryz6yoZT2", - "quoteVault": "7yGqcpqB4vpDsB5R7S64ZHtwe2S2PWpnGUT9TqFjDset", - "withdrawQueue": "Bv3i77ddaSmkaFeC3Dv4S2GMbKD16Fk7HXKLqkhLpTzZ", - "lpVault": "27PqqjtjE8ftMvEe9UwbhXrkCrKjKGwrsh56YHvktXbW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6uH2rvVUySwnVFw7CMNV4HTzuxHTUNC7pK22pXcqgSey", - "marketAuthority": "9HQE9tB4DYwpjJoHLm2y57oDCMHotVb16x6kqbFv3r9w", - "marketBaseVault": "4VyzZruyi9wtj47ofZSnkUHDb7YdGVZkUwrk2W1ryxNE", - "marketQuoteVault": "Fzxsqxab2HUWdiALxPyDFtEQ4auS5eN2F9mTduJPhJgp", - "marketBids": "FZL92K7t6ZuQkCpAJBFF7om21NgTGTjqkMof1D1wEV7", - "marketAsks": "FFQWBVPUED5gq4rngtpxqQw5xRMMdeirQNL55sfCdeag", - "marketEventQueue": "HqhkvhSW2fpq94hDct2cmo4A1fgW32bUiJRPf2BMP1q3" - }, - { - "id": "HQKDdqorVGfRMqJKYgENxaJHZtfjTrsSVBnZYMixEXWp", - "baseMint": "Dphg7WWPYPKMtVyxBJpjwP2sG8HBkG4mm89kX1jgKA2L", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "msxRcR7gCbC9ainyLkRzSgFRmHcEdpaYvshKHUQAhLh", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "49nE1FNK1ZfYPAzze2ivEVDLpTtp7Pg6yLLbxi6BQEhF", - "targetOrders": "CxVFYoZHrrAQr4H6uNaHhBaG5xeFTPNmaWjn8BmrkGA6", - "baseVault": "6zL59ceK2WWhvgEp4qADuiv3G3ANZsCEAWS8Ri8XiivD", - "quoteVault": "9aY2LrkvjR43xW7tiPtvPV5inHHLhTsAP3dMCVEWao9v", - "withdrawQueue": "6HUpx87aFTFKzKdDuC5f2jUFg7w7aJqv34xeqsqMnyiN", - "lpVault": "GT6xQDEUHzZpT1RKSaA9zV4HGQpboxzUatpAT8QiDuyf", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3QcV1JdPpXZZvD1oCKz7HmCrugTWbk9YyM3Ug3bE4Gdn", - "marketAuthority": "TVCYvZpjPEx173sZpfdRKDz1t1GuFVMccNfcQFEGWA6", - "marketBaseVault": "DrirBQaGFX111wjLb5nYrCEkmREgBuhqMQAKp2xVGtUR", - "marketQuoteVault": "EMd4Tm51CEhaYbcttUAmNNrvbmsesxAvHgsy4n7GhHpW", - "marketBids": "4EHZXc66T5iTx9NpwdXGG73du2jTyVJhh9xa2zg4aVdE", - "marketAsks": "BmDMVz9yT8iqQFZKrvinidwL4AKe5bs3eAuxzvPKaHMV", - "marketEventQueue": "7dDY8cJX6RisY1WFwfXfTruhLNAovLaKJHnUqZgmhwtJ" - }, - { - "id": "HqLyuq78CkjTMg9NEX3YnjCfdtFUvyuKHtFBFTj3Cfay", - "baseMint": "HxPoEHMt1vKeqjKCePcqTj6yYgn6Xqq1fKTY3Pjx4YrX", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "6MigzVY2VwXhuckpLpNnSX3KsH22BEtaVQR1byKArtSd", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7wT5KJV1tuUyAT73obbTXZbTHDHgju8iKJEAuBJA7BFR", - "targetOrders": "CeCbBU76UBVthZggsLekqhgiPRmgYKo9ia5F17bHfcQR", - "baseVault": "C8RzH9Ve4Tb1qWrsAEAspvY3CWFXVD7zpXkbo7GnTysu", - "quoteVault": "4X7Ln4fBKxDtiUfr4wgkJttyxmYTXT5pvfhNRvQ7uZmR", - "withdrawQueue": "C5ZTcDEhrt4nobEVYGNq4AvofmYWJAck5vNtGUGikwRF", - "lpVault": "EuU9iTbTLeygQeX8Kb3VUBmUr4CSH6BygCTg5pXwDazR", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7QFhpMs59kVHiCNWAE3TnndkNxZ3kBhZneXWqumWomiF", - "marketAuthority": "EsWu6bNaBmHega6Rqad2jZ2o6ss2L29qDmCueiTcAWwF", - "marketBaseVault": "2BpxdAmqu7My6fHnkrj7FJz8NEuYrKXwgtD5t5ibQBtp", - "marketQuoteVault": "9z7FFZFPfT8QGJhJDw4UQvnhhs1MNtRviwLAApEJREfq", - "marketBids": "7oz584krBgrtBGuHdAaKebXwJcZdgqq7FjD9ngsqq6HF", - "marketAsks": "FT3Ain5hZr7nNADLYv5NsD7wbcUUjNfsjYKWGajz1MDG", - "marketEventQueue": "CZAwmJkP7cdVr6i9kj8qVmAcFDuqUGfK6YktCnJsNBSs" - }, - { - "id": "HQP45jHFSiDRG3dnmomBxSRAD6dchRZ5TtpY5UoV2joL", - "baseMint": "EH49ziLeKhJtzUzdys5238pSKpvrgJvmi3EStrZ9QaY7", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "45WhobhNM3RmLWKhRRQwKViSwiiRw9FWfWLACowRucG6", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "83RfHQty65qhVXGw66AW3KbYUBddrdPSeYh29jNbkwht", - "targetOrders": "6ogXZMCSTPmuEBxjBiS5of7LtkW67C8amJV3VSFZQgaY", - "baseVault": "GeSGCd5NgVDLJKvDHbgPjNba6WCFfMpT9u8xfrns1NWr", - "quoteVault": "AfqFASRUuyDpfxhz9ZMMHcVL8uhbHBP2EbDhgauLJzWx", - "withdrawQueue": "6m6TYJgQwKCbVRdesaXRjJcNtySvHpy2Ra4hTye7PGhX", - "lpVault": "6v8bN9VUk37wpNT4r74ZrchcEQm71gMgaSbNRHuEeyGd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "21eq7jsx59jPFo2gt4npreKu1voURzcjyPniBdgupuQC", - "marketAuthority": "4vZWYvtYTTRDasFUSCNWvAUc54iLajEvX69BJa1is9k3", - "marketBaseVault": "4HmyNrZr95NJjXkKWQaQZCfwq1ChRp7duAhFmR5aRW6P", - "marketQuoteVault": "Cc6Qu8QG3FXDAPvackJKsQfdB8xkzz7kbgCo14xBabv4", - "marketBids": "F59rZqg8ybX61hkYExCHW7pWuz18VfEbKzGjTVHoGwjP", - "marketAsks": "BFrLMrxVeWoW43ZqnTeabkJXKBmAyY9pboPA5WycV7JY", - "marketEventQueue": "CmvfeeaXM1RwshsEnNRZbEhAoxevERrtyiSNDbnh5XjE" - }, - { - "id": "HqQmfPGuAPbnx5f8NfspzERpPisYSHppbq5rKAjyHiN7", - "baseMint": "6gDZSTqGhhUNWE2DuWUa7zSFenmQz2NpAZRpPrg61LF8", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2XURedmzFyJnUd3D8ArYTJoYSS2vi8m19T5MUKWwm8E2", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "jjFuFeS4ggtsHWGgcpzqfqwPFDezvXLAmGoaLJbXi1Y", - "targetOrders": "HdmQ6QSgk4f8HnmCsJhPEnRvdZx1Lg6JgPJ7jWS4XYv3", - "baseVault": "HdrNMsYQeCS5frwvGgCk4UQ7ZGA8xBkHVPC6arqV53Za", - "quoteVault": "2dC2dTyWZvRVBp9m913QsPJEm76Cte7pizJ71v1bjKTP", - "withdrawQueue": "6FnpeMnGPo1sAQMFJTB7WTCZUd4kF36oLCs6HHK6mD9K", - "lpVault": "8chgCRPzxa3DGmUfSg8HvJkYXmgZKXtxzqpHvTFwumw8", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "cAWyhikWB5ooHJ1rwqp7B1YaXMWPYBvhCqfQFoDN65A", - "marketAuthority": "7XrCBJfBdgF6wqELRz19Xrcy8dgGymxcYVC5hfuLFhrK", - "marketBaseVault": "AYAMRu2xb4Yd3n1nspfKwXKRo6FdkvzC6cSR2exb4Yzg", - "marketQuoteVault": "HbGq8kdTGg2Nfsg4UGyZMbuHHwbyMRZZ1Nqg5AUw1ms6", - "marketBids": "CEwu79iKA1RzTpVANGf2X6z4cWGFK6sQ6Uy7JEW71v7Z", - "marketAsks": "bHzu96o2syfnazVy6nHLs9F73oLq7EHvpoSmJe9KkZm", - "marketEventQueue": "Egd11NYpmwMo4rJB6vpjmozhSWgByDhKg7e5MYYGsdYv" - }, - { - "id": "HrDzSFaurGfJWNjy8yeGaimqXWKhRgyxfEJ7UP93r5My", - "baseMint": "6qQnzsoH89TWZirgZS9AJN3NrxS7Y4K7oNt5N93E6QDR", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "DvJW6GQ8gVLSEsfpMVoxyXoMLDGoDHJkaHMQZ3rf3byA", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CyB68F3JUc25XWgZiimd67BtgJ7XKazYXPNuTn55v3AZ", - "targetOrders": "3EMhuG3nJvDM9Pa3YDSDKMr1y4xv1Lcm7SSgMCm34utz", - "baseVault": "7GcyshASBYzZmwTTCJfENoQKqKvepr74f7tgbmuTUTdJ", - "quoteVault": "Dfee9dt7GWZeoZbN8dUB36JPcYLqZpphgUsSmDjGBVz1", - "withdrawQueue": "3KphTSZLABosob26A6ANfnYBESLJASpcFBV26CwSBhhR", - "lpVault": "GKyoGZdwAYYApu134tg89eMXBTEe7UkbY3V14hNYV44C", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "482iSeVo13oEjAZcfQ7BfSAoBdah1atioutdMKG6scB5", - "marketAuthority": "ETNcW3g4TDiaMFAeAfgr6QAYpdwAKZRT4xmWskSXWRsm", - "marketBaseVault": "FBcdsv4RmXXYqzZ8UMdp2LX8SzwcHhACQDJ2Tfk22K8H", - "marketQuoteVault": "AMZe4YzQvDYsi9fqmwMJ55rdP2x6NxmsLcFWmptFiYCd", - "marketBids": "3zeQF355oecSQZsqaZCbqVFgMioz7k2LYhFEGzQiq1Cj", - "marketAsks": "9oNn2MKsYi7gt2A3ja1H4QZKKM3yywA8RG4m3jrTLF7R", - "marketEventQueue": "69AxyHs5ZkYgnEaF7B5T28dMiZ8L6MtHh9aAub9aANfe" - }, - { - "id": "HS1ZssHcE7zEwYGpTaVE7bQJbnEUcSUNxhYQoy9pkrkC", - "baseMint": "K1Lm4h2eHqeZySJSmSA166kJj7j9s36nSaGgFJzhDnc", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "GnBzcF5SsDVUkhDxcZoRe56KYasacnzxupxrN1xydkkm", - "baseDecimals": 3, - "quoteDecimals": 9, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4SsYLW5X8hFoHwHkXJjSdyu1EEj6GEu38TathupPPa9Z", - "targetOrders": "9kPJRs93B2CzozWjF2SB5bY3mnTpeHZ6c35pGaQEvkvA", - "baseVault": "C4gxvAZqr2EGVdFAr5qQk887NeBSFE6cz4N4tbm1NEiA", - "quoteVault": "4SecGk5UQEh4JmFVv7RtZ5WYc93Y6HjaBGP9T5kyuvXE", - "withdrawQueue": "9eMEaKtjE2yBnWnwTvTxPLVbzEKhdHPPjwPxk4exEeau", - "lpVault": "Dk2Efg1YMiRY57ED9MDXakUSqTc7DvwkTsngD8EPaGue", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5EHjDZVNM76mbVa8PKS4AiBZdrAEsmLiPJB9y8DjiZav", - "marketAuthority": "4GVUZugqJpbFvKLREACxanVCwa15Bo8eSKA7MrCVA1wu", - "marketBaseVault": "ERN5PB2yqkwhNrH1Fhc7zJwL5vakfC2JsDEMba412uXo", - "marketQuoteVault": "QEvs71kbo1A9G5KDL9chYq81q7WM4ipxG2N49TkQ27g", - "marketBids": "DAEAW5ZEXFH1Mx8h3Skd3tkLGGtbZYtCzw4b9zyzahsm", - "marketAsks": "DFNv4bvnbjSsAqbMx1vVZ8BUxyxnQoQ7sBS5zyLZQemU", - "marketEventQueue": "FxPUr3DW2PByqpD6pn5Eov9dp3TYqH9PcHWCqj6YLcjs" - }, - { - "id": "HsUNWR7ghHSumwDW3MNgs2HSh94yrDuZFVR1XpykA9or", - "baseMint": "Basis9oJw9j8cw53oMV7iqsgo6ihi9ALw4QR31rcjUJa", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5bpYrWuERdLHJkgMoA3nrL98e3T3RV3sudgUPCWocirA", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EPESywMUbfkN8K2WDbxjdFmLhSz81q4xo6iCbc5qVzdS", - "targetOrders": "4JkUc9kYDxb8EoWpKgDcVTFpcD7H4k7meSXa8m8xkHDb", - "baseVault": "FiArYR1m6zpG5s9dd8qdrKbfahJjZrm9Q6Tg7s5uu9Wf", - "quoteVault": "Fnf5WDdJ21fi1bpT3QjuS7CPjgQKRN83seQkWvLygb8L", - "withdrawQueue": "9GTTwBvhy6pzWcTNTtJriHefLA7hnNRBaqTY11UxoPkb", - "lpVault": "BdP6wABbZan39xDHRwVHFaHcRUpUPtobCdyGyknK8m1d", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HCWgghHfDefcGZsPsLAdMP3NigJwBrptZnXemeQchZ69", - "marketAuthority": "2u3iPkSFarN7BNhqjk2xsaZz6cmEXouNMy9PBTm8Gox3", - "marketBaseVault": "2rn4c8UAPfagB1WrsjWmPfmvFvzUC1LxpGkeuBuzxSjW", - "marketQuoteVault": "ESaLKUAxoP2HHBFZW1sZRpjLXcVRMCTXRkNcAD5HA16J", - "marketBids": "GemRLX1JhawpfF6uSvnSVhy8pmRY8V8UtayFSYyYswHx", - "marketAsks": "4DQiSw8wHyVKjt4p9oTdPuxBN8k8tnbJhv2WDPdXxewK", - "marketEventQueue": "4dCy2mwqjyvd7Tdp63TPBtu4penLNc25gc7W1QR4ek5h" - }, - { - "id": "HsvFnjYHCLA5Du2zcotf8KBs41XaZzjBSNnXNveCiBZQ", - "baseMint": "B1ock8ufjvuEPo4eDhnTHtY1uzk2TLg9zpoLnmMpa3Ht", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4a6rurhFVXuXLKyQpcUQj8gjNeu2bc5U5U7hcJuzADd6", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "A7Y2DPH8wLRf83hZLypKZ7TXP8NsRQHi9rY6UKXSLTpG", - "targetOrders": "CzsHu5SycGN8PYYfu14fFkMBYVcUQjTqfBdK96vjih28", - "baseVault": "4g7yzzH9uzdx38YKY1rQfuzuKeFgsB4Tug8Wmq21jasZ", - "quoteVault": "3zSspyiobU2qd771HdU2mSjF5TrhZfXHLfNnEJqKZYzz", - "withdrawQueue": "9sKBRqStFzqQMWEvNDu7FxNrJ44cMpn7i6YqwjmT7Z3", - "lpVault": "9iKNSGk352wnSg5JtWEoxESPP7Q7rRGV9FihuzsGcUrR", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Ab2N4gM27BCLAio4Y8HxxbAFnhobie16SqeXGL6DKLak", - "marketAuthority": "J5w62HS8wh4af8t2xsVsPjFjjTTAfVke9Axq2mhhUnYv", - "marketBaseVault": "26Ez6kQgTPYupKTk8s1j1xGyC7Xn7JGKSECLQz1ykXU2", - "marketQuoteVault": "5HwTiAGMcVQNKBTEHCFdvqTckwLvi72eH2oQ8VLX7Rrg", - "marketBids": "1A2haBEQWESUbAHxgpzHg5Nv2cB4MCXuj28GXJ4EYvg", - "marketAsks": "6VoQm9RqanAx9jafxMqTHAxmymGrJcEqt6CeaSscNoAU", - "marketEventQueue": "4srFjMufUtKACgqnH66QAK6CshKjGj62RLQRGK2CZ4x1" - }, - { - "id": "HSzcukzFrzbEXrMf2J2fZNhkTrR2F6pcubX5cSgYQCqp", - "baseMint": "H3pWoh5Te12nHYVSQm1vQC6aAn2EbADj8zit23jP2jX3", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EU4xNtjc2Q4AwfKUwSd2shQMHpzcZe6Wy6zwknzTUDyD", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2oNccj2u9ARmQsi63pzCHHnZFCLd7YzcBqPMQGwJu6pN", - "targetOrders": "BCp22psnH1vGEdqHKvMdeB3ww4FTDCCivfH2pE9gUgSp", - "baseVault": "9YBd2tkfekUYJgMnWHMyHowyRSJnpea2erLkL6ELb4Ns", - "quoteVault": "BmaDnxa9dF5xVbrnMzTeQpBEfBosgVU1qmmbbCPML14D", - "withdrawQueue": "cTXPpxJoBH4ZYFnwi34GwyJRjPj34RC1oW3kUguDTHt", - "lpVault": "9uo7CLKJ3V9eSULDx2qaA2TTPwcBuZoCk4toLYW4mcDk", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3A1L6Gg131LJ89fZyQNECD21ZfxtMBatTNyWEtoZvmJB", - "marketAuthority": "9GfipUP4SrZM6W7XaR7WEQ6wqWU5GcEzQyriL9VdEZp9", - "marketBaseVault": "73B4L2gqJpqNRxrbyR9XuGWqEJDCpxhCx1VHcK3DrRvn", - "marketQuoteVault": "2sjFz489aWqCcrV4AsJ1ih6pRxoZ7HrmViZ3P9Bi7A5Q", - "marketBids": "Aw6CSzLFxF5pWxxNkCS4kQeUtW3xb1TNhxWgqPLmu1kJ", - "marketAsks": "DtsJPEQjhRmqYdXbVXT19bVNu1S2QRzTzUbKv6ynq12S", - "marketEventQueue": "FxgEUTwe2P3Necc5zHMdKS1y1ZhaWwcqnGY7Pdf14FRh" - }, - { - "id": "Ht7YKtj7Kki3pSxRmJydFwr6zhApvE2Vq6QCUABiC7Wb", - "baseMint": "3jzdrXXKxwkBk82u2eCWASZLCKoZs1LQTg87HBEAmBJw", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4B93e6mf7xtCpodjuzuZCqUtf2LxzmiA1WZC9nQBXZ4W", - "baseDecimals": 1, - "quoteDecimals": 6, - "lpDecimals": 1, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BKh5Tsoov1dfoSRcnqsEFxRbCexmThNBWEMkrFr5SpVV", - "targetOrders": "3ucLPYvFbdj9YDdGjcFTfwjhHNYiUKD7ib4XaQX5MJUN", - "baseVault": "EcAmT4aE7BP1ooo8ioKbtFcvmvXJ74uJQQ8yi2kkxfJt", - "quoteVault": "GcM9qac6N1s9yZuNdRgHfaWa9UNmFN4j7ZESGJA1kxgb", - "withdrawQueue": "2VWieKGW5Ss7oH8M5y3Km6HJowoqwxiXeGtoLP24qGKR", - "lpVault": "43FZyntFGhjUfkfZetXotbgAUe9zs3aZX8TWkXH6UGta", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BxcuT1p8FK9cFak4Uuf5nmoAZ7nQGu7FerCMESGqxF7b", - "marketAuthority": "FruL7LaS9oPGc3MMCSjb8bKyQrTeqeN5dRc9uChoHFC4", - "marketBaseVault": "2wJeyoXYLAEDZckhgLJGkESVeTjvk2aqksgS7g9DZFK5", - "marketQuoteVault": "3uCVHmSVvh8MnXCPmRFbojxXWrcX78k11vDUE2YXKUj9", - "marketBids": "D79gAEcjML4gPveFeT63TFTr4ct2ATY9vupyzZLY38sY", - "marketAsks": "G8Seirfz2w2nw49Qrn5evdyWTZwwrB29GF6qdgkh23ax", - "marketEventQueue": "DHNELZbq71XjLt4KgVvPPjjASA4MAFVvXnAMTikE5PEv" - }, - { - "id": "HtPg9JNDnysMhqcHNyLWo3GBCXi5v9JHL1EyYYSurjjs", - "baseMint": "9aYcmfuRJBekgwPY8DVYWdkUDS8QeB7XNasSU17yhqjD", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7W1aqccgS1eYYU3WL9RFaNEwvctvnMqUzcg18bc1keG", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8CK1JtniqxEdaFcy27ys14pwYbRJnpgWTkxUGzCXGpiJ", - "targetOrders": "G69kbhnPyfxETSdDwvAheSZpe6UYN6KbGDfsAZoAQxs8", - "baseVault": "5odFcjexwoJkUqp37xXqzJ9B2txburJn4giLfVQf77uS", - "quoteVault": "BiGkSkkRMdgdv8KUUNE5zHbCU8A9WNQJ7K9x5RVhTSry", - "withdrawQueue": "BEEYhUHu91MAnYWYaWL1EY2CfzuXJHaUUT2EADCno1N8", - "lpVault": "3TP6da4z9JSX8EaCLDRU3skM92c3ebxs8iwFY927D9th", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3S7Xzxiu6tbWwBNCDQdZY8NwSGzQtyctjgGGaCnFwcXq", - "marketAuthority": "3oMMhETdRYsThrpFCZ3zYYYAMddhAzAiynckU36naUCe", - "marketBaseVault": "J42t9XK9X5Ffp6fWPEpLgXzBj3rCKUJUCFaLrB3XF5u6", - "marketQuoteVault": "9zzhNge6svuUgf36U8JidBzNi9NxmQZN9vuRKsHDegYM", - "marketBids": "95j4aYJqJ4B4SAwHc5zBoqFrMvsMmhVzL5bBPWx6PLPJ", - "marketAsks": "CdDtJGw2ED9MX9o9vZjLtwZd6ZAzMCAsYJoh2QtYEKrs", - "marketEventQueue": "69X4VfQC5zytiUE8JbxsXEHRnTiinHq2tEH7gshMbWbD" - }, - { - "id": "HtqTEgjuqV6Vw3BjwS3YenvG8xjsLAwMnTbWzP8qEgec", - "baseMint": "X2m83B2T6y92qcq1am2z3FKXCzzmKNVxUGXxFWa7x8c", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FyxRLSp7WJ95bW2J3nGKwycfbbL7KKDaEPwFWSMfHtYJ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AfmYXXwiTYTqf2ewqwscdpovC7qmT9Egm8c47ENyBbJj", - "targetOrders": "FGzKoJmeZAMRsyusFGXgzrfStuorqAACNW9VFodQpLQ9", - "baseVault": "12gqHHt1emX4zsmPKEgbtZYmNGCoLTaH6wpduwf6s66j", - "quoteVault": "DeFnoGDFqcKmk7QP7SPue1zBPDkskKFq4fFDHoSZj27H", - "withdrawQueue": "CkmP2eMhqq6m9TeypjYinKtTQvVgye5Yc7qmkY6eEjXi", - "lpVault": "Cx4k3LSJXsDubCp9s9YJ9rBzS5to87WBFkoiSaw1HVrm", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6UowvALemBgCL5qovYC3h8vB9Y8dQTFjHBFZ2c4Aachd", - "marketAuthority": "CXqnygWGUp3YTXkHB8yYsKZESu1dCEohg7UrjTZ3tAZt", - "marketBaseVault": "9p9w1ariNaQKVHLZhK6egcAJuCnFtxhAdHjFBmQLxGJL", - "marketQuoteVault": "BsNVaEwjxS176Z4Dopi3iTMqUCyAzgC9qS7AGsMwHdit", - "marketBids": "3XRb2NCaSQpFUSqrNamJJkMWpdkDPEoC5y1ZCBS6hUgs", - "marketAsks": "69bKtnZzwGLjHaJcCEpB8u5asqAD18tbaGWqoNHs58AG", - "marketEventQueue": "Gt8h3a2aAHgFwHws7RPjYvWNdpktYAtmDK9pZWV5tEeR" - }, - { - "id": "HTYmqHipbgF6hongv9BgQardwcieDyEfaaq6gEZKNkHJ", - "baseMint": "3QuAYThYKFXSmrTcSHsdd7sAxaFBobaCkLy2DBYJLMDs", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "EdNFbzYMWiZZvMerHb9ZPaWDvuFR8V2SZAUJ4K2cBTrY", - "baseDecimals": 3, - "quoteDecimals": 9, - "lpDecimals": 3, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "43WTRRwp3z64Px8WeicPznxKLRMZ1tKXM4ip22XDZCPT", - "targetOrders": "GzPqoTFVELmoYypBXfTWsZq9gtQfd8QPoQ7UsZXXezxh", - "baseVault": "BPLKizSmUUpNJak4nuwG2au3rNzhLBZqCYjMPceFMMKj", - "quoteVault": "EAsavEL3unoi4MzcDexdfhx8P2hasthGDH3N1dvgVTb6", - "withdrawQueue": "5Jc1kDGXKxnBLySWenMLbHD3sawMoFdHeuK45axp2cxf", - "lpVault": "2ARFKrqPqmzsa9PJvecxUnLCn8LJQYd4775PyFt39Tm2", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FoL6rsAfDAqAA2rgDtGR3aqnokRQMXT3aKuMZMqXf9JN", - "marketAuthority": "5D8nvbGfVNKPGqjJ5cdZAAqMnpH1mfAqHZoui6h7bBqo", - "marketBaseVault": "4YnFsqRsDTQ2dyKeYaztwZ5Dw7Tob6VefgNW1fLQPT4K", - "marketQuoteVault": "3FVeLZhDdkQoqAC1EmEDGn7vxnfqXcozAYs4HYa5HXf9", - "marketBids": "PupGjpMnF8e6K2hUz6pRCdUnPhcVr5TR1Yhyvn45mQT", - "marketAsks": "ESyUhUaofcbhMG2SkVQL3i1Z66SfqG4U2f7HJsyYCnvM", - "marketEventQueue": "EqaAP8g33oyj3u1ns5nmFP8mwsoP3mxoS9YudBbHXVsP" - }, - { - "id": "HU1tejUtt7AZYrC9SAuqCW9MpuSqsdoedHSb1XUKjUPN", - "baseMint": "PRT88RkA4Kg5z7pKnezeNH4mafTvtQdfFgpQTGRjz44", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2LRgM4AqqXZAGXgJ2YXHvgvk3aobT9AbiUM5AtoTe3oE", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "k9zqf9pBaArKkA65vQe1Dr6rHKT11XcQfWi5MU1ZCFL", - "targetOrders": "AZ9HhHBzjNFE9AyoC73wkLdm4N5jAKdPLqyacJax7obH", - "baseVault": "9sWx4a3WL7a6YoVqfa16XQ5ysp1aHc7tpByLGinCSCqh", - "quoteVault": "6NeRghuNSZ9ujoR6Fpanso8N7XS5tpMjomyVSwCJceEp", - "withdrawQueue": "3NBVBUypiPNLQQhwena7FqTLWSbpynTKWf8qTukAPCTR", - "lpVault": "7rW5HNoHgMUXSYJm1AYfoL48EToAx6copWkr5tG3zHxZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7MLHrhu4ZJjYDju1XGH3y7CbnTRA8LvwxRwRCbvDrexs", - "marketAuthority": "GTPVt7nREBbtszyeaM1gm2FpNTks6YEQ7b26JP4jTVmk", - "marketBaseVault": "HzyyfTCJyY6iXBztZWT72SwLHuvcBo5zg8wswTekQRAT", - "marketQuoteVault": "BkJ6zW3BC4yjE3dtPctaMdbtNzBX8cSiEMkrtYtzbXnR", - "marketBids": "EVirJypZpcD9y32kCYzznKom4sZepetJA3x7AnEAAbD8", - "marketAsks": "4mcMXsUvk6F4gYZHmmBUcx4yj5d1N6LFShyvFpwVhbM7", - "marketEventQueue": "FRYbsfWbZ42J4D5jvzFuYoPP1EcuVEXjKVqY9cJvhNB1" - }, - { - "id": "HuCtiVgMb66ypCE3cfkyLvXtUVmGMsR63inyWPbSZ8q7", - "baseMint": "3in9a9yHtdjDFRjDyGTTpGUwJpT9zZBcyjQ8J7nqqNtq", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EJXmdhrDTdqijzvZUvk2QigFPcZoCgvcK8dEY4CuSuKD", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BqeMD525qVWbhrmaVGUZ3q3HYsefg8veYbN2j1wbLZEE", - "targetOrders": "6hneXe9rdWnuUVwbnpZQdiU5nkGEhULekc3jbvh83Lzs", - "baseVault": "DBXqDuHCPH5gq2wzCv9MAfxXjKj2qKo71Nb6WWrXEM6T", - "quoteVault": "9vhNmymWtaxBtRmHvA8SqAKcTCCPtuWZmoQXPfQcLvb", - "withdrawQueue": "A6KukW9ERrh2Cvh4bg4QcveE5UstvD6Xhx5uduSkfsZr", - "lpVault": "3RoK7FRi2tWMQRSJLs7eEiyxkNcHQxSdCa74jSWqEJQY", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "yzKcpbgRmwE5ULL72C4JPUZYQ2S8ZHRFJnrXgQrKyvB", - "marketAuthority": "96t225s9Jj3tBWJmLfsjQFdupSLnUXA5iVxHPWABCJjs", - "marketBaseVault": "Bw5ZdL73n65SGSE8DDFbLJqjXvHn9ZZDDLsJFzAxExHP", - "marketQuoteVault": "8a8UZjWusuhjBchBeQsDAT9kZuJittYNoyHjZr1A9bx6", - "marketBids": "7wst3KGrRJ49SsMbtRKkuaRc1yWVNV44GqJKeuzNUJ1b", - "marketAsks": "3jidpNrY8cX3Z31XUEpfGYfwixpxoVt1CpuWME1W2NDC", - "marketEventQueue": "4k4aYo6UjXQhwW88Aah3SRyKDD6CyF5XzqZHGFA2CqXk" - }, - { - "id": "HURafmKurLJDn5H4CjEqk9mEYJisBe2GmqshX12yvr9L", - "baseMint": "So11111111111111111111111111111111111111112", - "quoteMint": "4pk3pf9nJDN1im1kNwWJN1ThjE8pCYCTexXYGyFjqKVf", - "lpMint": "9xcxPYGeczznwvcnNRob97SCHDTbQWXXJvM2cuLEunKP", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GV8Sr6ypPb7oq174aWoUA9gG3h7uKiYBAijJGPCx7HfR", - "targetOrders": "DgA7gqez4dAj3jhDsa8mmCeHGTH9NLNFNizQU5ThxmHb", - "baseVault": "9kkPZ8UCJDsY45mKcu4t5JdcGcocAg2KbgYgfAYY1V3R", - "quoteVault": "BLbHeq2e1CG7xo5ziUdCccvoBNVNWDuw6YyPLBLzgSAJ", - "withdrawQueue": "FfmG22Z4gVK12DVyEwqZUwB6Ep6FAdVbUScXu4cSQ6bD", - "lpVault": "5xBsJAYghWtpjxLSLCY6VaFdNUgif1CSHzamVWWMVkCW", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CRW23rK5LksqowrfpQTEUVEFUDNDLF34STyW7gXV18Xt", - "marketAuthority": "JA3g5HU7h3FP7z5mZZ67axBNQLuimFJn4RMCvcKXPuJ8", - "marketBaseVault": "3DS5QHTvZnqFqVeBf8J2EVmyF5urAZBAFD5QurGRAkwE", - "marketQuoteVault": "EGX2293gxvNMuupjSnJ7CP89KtWtUuTKTQwqNLCiGx7x", - "marketBids": "3YBAVWZQZhu2TmiCzBQmCHZcBomtE5xfGs8WribLeUf1", - "marketAsks": "AHukPwsctwQtKJnVPGG5VS5xvrVrLkNvJF6Qje1FKiA5", - "marketEventQueue": "F6tmdQ979t74XDzqw8Zx1iunr24KcE3dZZCKCEPt1kGy" - }, - { - "id": "HUVH1pKPgyaWVst7A68n42LmHoXKPZEpDaedVWWd4QMN", - "baseMint": "61m2xv1m6zTEAS86VfjFmNKG1ZGemNu19hzMmgstowLZ", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GbP3eXe493zJwKR9wMbQ9h8hjHraaXJuaTotQVPXA7tG", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "635DJikujB8YwmaspmwdCDoTCmZ7aLMEsZ7GTZCLmxtb", - "targetOrders": "2QmzeYaJhnMc3ZQG3rD9VLnAPAy2pJjfc6QTJi8tgiYQ", - "baseVault": "5kZXQ72VHANRuXZENYuxoiZ1E8jF59gmQGLd247XBub8", - "quoteVault": "BppLxidT7ZrJ4QoR8m4rB1PMz6opmzpYGqLAF6vXxK5m", - "withdrawQueue": "BCoWaW6Hmf62YMjNvtm5Ckho3TDxXCFJgG5LpW8dy9MK", - "lpVault": "E7qXX5R9yTUi9yjc5B8Kpphf4VvaF8FAy2GHNPn8aTGL", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AvWV1HMz6unDdbrGxsv8qH8FHueQA8FbBqtYuJcyZDUk", - "marketAuthority": "jKWTNgxpzLHKLcT7At5vd5ovQk1VpyVQUPAvDi1H9LR", - "marketBaseVault": "FPSVujAmt9xGuKuQCCDYdSLFsLnFNGccQhpQxCRF2DRo", - "marketQuoteVault": "3wiCAJLxuF7h17FUqBjKeNffJBcQPX2jRCUjuiK6i5L8", - "marketBids": "22MFwCBwDF8PP6vpmoMb6sxtQy7CQ3J64JonzgXo7FKc", - "marketAsks": "kxBpwPCctAZjrRCkVPoab1KXskquzPDYVtBjvsLiaxH", - "marketEventQueue": "DSKLUC5BEndXSXkQDFNLVtKixbs9HprnBg74hxva7zbd" - }, - { - "id": "HVHUiaW5Kcd644e446TCBu9bdMB7LmSeMZPa5FjyEcW5", - "baseMint": "FMJotGUW16AzexRD3vXJQ94AL71cwrhtFaCTGtK1QHXm", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Ey5oLG62XbRLxAAhSsnq7HamT7TYR9sJwk9vMgVeSHer", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8F9J8ceVAxXafyJnftmmztMx9pZpJuWmEu5Vw6L7kMet", - "targetOrders": "6KrVJ52BTbJS9KiqqCvd87bBXfJg4N3QbACdrUiNv3g2", - "baseVault": "2mtQdRU7nTNgTMsUovZ9cAso7LGu8hLuUoppeUM91JhS", - "quoteVault": "677NvLRib73pntYZy2C5odwEBgrFBQo5v6FEdnJUDZP5", - "withdrawQueue": "DVqKYfKUmHXB8JGxt3YZj9H9a3TWRzPac9CkrJagzeqp", - "lpVault": "53RczkD93EGx6pG9R87pjQxjCbeFZNJCaFZ5inZE1ZXd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6gajxtdWsm46yy8Btedr8DHmrr78cg554eQWp4WHBbgo", - "marketAuthority": "9LsCtcPLoqASYn5a7QmrbzVBFA4jtBC1V8QM6L9bi7VB", - "marketBaseVault": "84qP2ikZM9oiF4WmyUBVUaB4UMqDMeS5kcPihMrazWPq", - "marketQuoteVault": "8DryHx9BeWoQNJZh6y9eAbCam41Vyj2EXkH6vVD7SrvS", - "marketBids": "GdApo3CtoUhmVMGtuzPGppbV8PNU1cFB18Q1wkSkRfre", - "marketAsks": "2xjhkAqKAqd7UuZxoRtUZC1BKDqE2DMS1rQx7kaRwrrR", - "marketEventQueue": "8NNDyv4PLjydAxAPDWjcd3SoGSnmMtihGr3KXLtsTi2V" - }, - { - "id": "Hvy4zm5ScEF88RDbzcUQsBrzVdBGoBpj85YfhvLk4ppu", - "baseMint": "9Z12fFM2WXLo4igtJfSDEdfkuGgzVnb4huto7MKA1JF5", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "eEF15FRABv8rXhZtzU2gYsgMEy63vqeFrs2yhvzwxQo", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GEgQUqCG4QAsJgzTncFTzag8jVVX1JNkgAB4GDEGC8RJ", - "targetOrders": "7sQbDwbFbCbsNCTyUydefJkrHppfAEjtF4jnQeUbJJyX", - "baseVault": "CRJ744aKuxAmw2gNsYb5BQHowSJbUtXS2HdhRy2yUoPh", - "quoteVault": "DhHcsJoaDk2FbMMgZ4VrvhuPn15w1Dz6Ay1PxdraMJKk", - "withdrawQueue": "GUUgATM1kQ9GdCyuweqGj6hc58Bx8GKc54tQdbZ1xq4H", - "lpVault": "GJNB98UoyCSDszwFvrjLLoSXpyDawfpSMrxrtupMnYym", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5CPbMY7BNvt4nF4fqjzpPwZC3YUzwN87sDazmGwe5eeg", - "marketAuthority": "GghiK4RJvmopzixuuqx4BAErvzA6j4qbCPW6Qy4eWp9j", - "marketBaseVault": "7NeYZMVfuomHiWfgMj8c7pf54L2VLC33vRyVmTfkSEEC", - "marketQuoteVault": "J22spg98F1wBQ9ppcYFf7iNeG7TSSScGb6wgi3TmqP58", - "marketBids": "7xGx8ngtT8ovNdcCpmtjypS8PwH1z6GXdBsMvJMiQBnb", - "marketAsks": "8ocwSu3AFArauwAhyZPGYX5NE9pynhbcK3Cy92QhozwW", - "marketEventQueue": "EsqZQxH8PMDhQpnNsG9MXgwMSFWDv2XXgdD69maCPhNd" - }, - { - "id": "HwFKiWvzePPuhAViHAEQTUzQumeahVQKiWDCLTVLtRzX", - "baseMint": "m6XGr58ATHSS7BvThRCDkqnsAeXLhpammhCrDo1amxq", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9ySrCU3STsYQwDfMSrLEMkHn1YpAFu7ocx4dNKXbqjjH", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CxownZk4p37gwduC7Ziww4CHbJxHZ93P8GKd5FvjAnSc", - "targetOrders": "4QR7FUYSP2WLbv7JAxRSXjdcmkVYbhqNwcY6XEJJJ3jT", - "baseVault": "EcmpxDZy84RoQpi7quxrtyQEvWVss19k8QmTRxGEakNZ", - "quoteVault": "FT3xhbFJuHfho6i249BqfeSKFJb3zJc12zdwXjSyhs3f", - "withdrawQueue": "HB87w6KcRWMHDHRzsQHhdYjRFBjT8P5qddhBWvtUr7iK", - "lpVault": "6ZJizYKrYFd67o5pw4G6XzHADBiu1tNgLp67WZTEeRbH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FP1ucJrPg7k9F2osbzcUtirm6SYCkwWvnTrsTegxYgmy", - "marketAuthority": "2UJ8G9Ftxs4Ab9pidGo1fVVQrCpQMVtDAUvtDQka7M21", - "marketBaseVault": "DBh9b6xAeRKfurdXwMs76mRfLL62QABUnt2q7nR762K1", - "marketQuoteVault": "AQCHuBbR7cKNW6mkbCUDxLuKoqoKaJHzgXbovq6N2hFp", - "marketBids": "6NW28cGAVojYkivRbpWVBcLZrHXVZFBNyKT97YyyAUFf", - "marketAsks": "Hciifu87AfjcJfCg6XgKqKeHXKbAsf2y8yDQS5wupyuX", - "marketEventQueue": "6j59zwLtoprzcwCyxoNdNeeYYaqKjQf8kpiN3pBJ6PHq" - }, - { - "id": "HWH1XRDpJJUdGwNxsXV42Ns6rNENDAZmZ85oLg3Amv9J", - "baseMint": "ADQauiPc85ciT33JTTpxkC5BiTt6zYukWfDYPvZE7nBD", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BgKdRXjRZzGc8BhxDvyzzeCpvcq53gAWuUKGHXPt5GXx", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HY6KXB54TZoaPmVjTdpjHDeJ74ZmohMXL1oSC1heP2yn", - "targetOrders": "6Xyo7Q1bq1adRWrL2ip4eVHVCCpb2yvLVUyPumAEk4t9", - "baseVault": "Zsjs5y4oWtfyoqTRYm9Gm9xW2Yf2dDce2EtMrcRbSEN", - "quoteVault": "3SDYUAhZC3UxBj9AdUovF7eSrvuMyQniqEnNCq3e4CyQ", - "withdrawQueue": "EUpTYkCNag2TTVZtCZSYm37pHn9LN6XNMg4Jy4ZoLafk", - "lpVault": "6QW58jmYyH2pLsV3aJf2sRw4oFyzDpd2pYPBD6LjZG55", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8WNWJueATKP75DcsQu6qRccMS3hRCK9gp1f1rRnFiVDP", - "marketAuthority": "4DrufHYTXBaM39rMG1WCd2WkC7bbwMTTrMDNHyxaSspv", - "marketBaseVault": "7bF3WcDAA2qZxq33ymQSrikycF9ZhL4hMW7HTHrECSc5", - "marketQuoteVault": "9By15dVxeBxmj8kgcFPFKNE8NjjeKCjxubUQXxQPQm9r", - "marketBids": "GGADBQLMfD7XFK43YN6Pd1De2vRR6iLPP8c9dcTuGWph", - "marketAsks": "F4UnLugkSjkNRsqdFKxcnkWXqmDLMUtCBeJ92p93mAbR", - "marketEventQueue": "6wL7cnnACDKA2oUtspWQtHmiPUeztxz3gnygmNU3tc8A" - }, - { - "id": "Hwuq1NhGNzw9NvbfTtc12oVKXPQHh3xgvJ7MpRKcL7ed", - "baseMint": "DkGCSjkUHKDPM1hjcMM8dGNDPnf5nrQU8fvsqvQkVixx", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "ASjW1v5QVYyv2VqjvhKGZreKxMQa1M6mdSeYLeV5QnSB", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "418zCBYJGvgD2EgHxo2yjnQUpwxjXFjVnHdJLU6BjoPm", - "targetOrders": "FeaVDBJX8R8WqeGwGhXam1MxR9a6uqfcVm3dyfoE2L48", - "baseVault": "LunuvXGnx4HZkbPWfZF8HSi7jer8vMaMoPNYaTcWE6W", - "quoteVault": "5gciiQGnYuLMeNkKWr14ghYS8Q7fetD4bHaiKB8JVgLK", - "withdrawQueue": "G6uwMkXvw9ib9TgSxp7mtoxGTABRbmDTvZkg94p4UbKy", - "lpVault": "8FSC8oqMtDWnxLCMvKwoRNkJF8C5DLLCE2dmaLQiPuZN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6Yehhyr95fHNMwHBfdyJ5NoaZntQMZKvvBMTox5Zzcyq", - "marketAuthority": "AAJZ1fw7NsFhonSu7etypx7At6k9E16Q9jNbSZno8yRK", - "marketBaseVault": "Cv3CjdUAfmv1ScsY8xrDCZhuN6tB4apBBpQeSMS5PzH", - "marketQuoteVault": "6BuDUif7YTyP4bZAqEasBMLtE3qVY5KbEd3gZwuTj9yb", - "marketBids": "DMco299ZzF8serWnQhjzUcWhoiNBqvXsYwybXRE3Def", - "marketAsks": "EVhJEWb845QgjnLiF6Nd8cK8aH1V4SD4VAA2vPKDXFxr", - "marketEventQueue": "BitCidZwi9eNzvCGkno5WAmhrZ6DcEB4NgD8X1qMmyz9" - }, - { - "id": "HxdzzXkT3USAVZmHfEum7t1aWL3dSj3JFcySxTB7sV7L", - "baseMint": "45HfvXJHY9msY2i4EmUpume1mSMLUvdaWsJRbctAobQM", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GUe3YNtTDLGsuxqdgVYciV3ewpKKjLod8zUTf3BhK3nq", - "baseDecimals": 0, - "quoteDecimals": 6, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BcNn5ympeqpu6Gn8vHHCttRazkjCk2Lz7fTEAM9hmSFX", - "targetOrders": "cUF9EFG8nEFuDUVTNh3kAPtbU6P6PGPNgKPJV7YfJAm", - "baseVault": "4ggyAS5D1jELuUC2psCLs7dzAFUeZoJiDRVoFpCp6k5y", - "quoteVault": "38hDp1nKrgqxphg9nAtqShBubmT4dLRCy3WiVudDGhzQ", - "withdrawQueue": "4iMk8jEh6iEPDrEMdhLGSFwZpfbRotdaumwG5nmH1kjo", - "lpVault": "GfF72mUh874TC4Dhp6xodp2K3f5Eavituo81KsvUHRaB", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DDWdVpjhC2Am2728JKQCwGSWSwFD1RuLBEBo4K6hPgQq", - "marketAuthority": "DUcumw22wfgYkXAvGiiEkA3SDPQM887mxnvSYwvXZQNn", - "marketBaseVault": "C1kF9i6PkfE1zmQoYzXTLffrkfK5k93LfL5NPhcvZc9H", - "marketQuoteVault": "BbdFoUCGq8rH3EUQ2StQgmHwfEZ44gW4uSQsqgPxkjpk", - "marketBids": "95zKibiFnFav1zy2Vrc5GLg65CKuefcpBCW4fNcd751U", - "marketAsks": "HcD4RePM8Q6sHYiBsufRUhbb1ywnG8UqTFJSGrk11KQd", - "marketEventQueue": "6uy21FinraSNhwdVxUgG6qZ1whDVsPkgr4VbQWCLZPu7" - }, - { - "id": "HXNcFGdez2uGegKzFLjtu7QXnsR1P6ZMV6Bm6d7fHhqp", - "baseMint": "8sMa1Jfcpt2eSkKDtcd6rurX27gqxkrEvXn5jHt3suGB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FiBmQHyjUdfS4cNoWRLhWj3TJt9tAj2PrfLhHYNYWSTw", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BpNGsWN2yag3ZEqCTqVVZSUrssXv13NnAGwNQRgdK4be", - "targetOrders": "8VW7pdnF79mF87S7BJXNpWXg75LxRd7STqyDqot1JXzt", - "baseVault": "G6CeDEXVXjK7mvG9DAe2mvg7RMco5H4a9J9SC3g8w4PG", - "quoteVault": "5tRLCoBGe3h7GZNCa9UX3RdciJ3SDAecg7SzRhBDCqkZ", - "withdrawQueue": "9cdSHr8JHGSppmFJvx4TPKmEFtZhj2CFEpQBuUkB3ngj", - "lpVault": "Bicb6weSHUVYHFLb9EPocRJcXn5KUimSoMhKuhPfNcdt", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CVddr3sJN4FeGf8zh95Tvs1pTb7pzQ3MgYvcywjQRcF2", - "marketAuthority": "G155RRdWRAjk6GBwo9MJR1wgLdYpRNgpY6nteGgPLdAn", - "marketBaseVault": "5XajEzm41XrgjEHu9spVv3syzH4FPgEday5fWoGUPYNm", - "marketQuoteVault": "5nMZMs3GeFGcCgUmjEN57gmQXfxdTYZqqUp2hDQZF5RL", - "marketBids": "ERneT1XsxdCsPi8gBSwshWunyHznTQTvA5cuNpXCTL1u", - "marketAsks": "4PtVB4cuTkzVaUAQsegqhsPZiyU8j3bx3DPB4h1KezX7", - "marketEventQueue": "EFACVUFz9TfRiDSycbK6gVLcC2ke1VkQdExUdtZXvKgm" - }, - { - "id": "HxoiVudE9Sdc6cHearshFBEe4gNHH6WvBm1ZxkZadeAa", - "baseMint": "3isaYVsynAVKGJgpzdNysTvaypz4E2qKUgt6pU6xRRxY", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BAgkP79BrhNoVeCHFKsmGwNTegBzy2PFo9URMgFfEuUb", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BgCPHcBC15ojkb8Dpvi6QaoeGmbWgzvVv9r7HMC6K1Wp", - "targetOrders": "J16qUFT5iYaqAB1pypYDbtT18ukp7nDifyyLybWCdhY5", - "baseVault": "BRTXLSPTWsmmFciCbHu2muGfdFLMHiL7TdAEo8PUveLw", - "quoteVault": "47p8WffRxogxJxg3fw9rJw6vk9E4gyPWEWSenZ6mng8E", - "withdrawQueue": "8EKmtMYuzB82AH8edeDEJnaedpHFCuNBzbrb5dBYfQoR", - "lpVault": "3jkPQKLw4m6AAd95RmLm7SLZBE59vNgioVzJcNqLZ3uQ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Dy4Qgcxvyr5RwKH14Pfcdsqp6Dfak4My9bCn4Sm8ptiz", - "marketAuthority": "CHjyLVmUPmhwfks67CG3YzZLpF8eZ9Z3PNBQo6J67M8m", - "marketBaseVault": "D2BACLXDgrDjugxTjxcyRYu7nTje3kXcwSeaLkkrdo4c", - "marketQuoteVault": "99f6NBhPUkw3dSs5DNwgCFZ9fnxRmetRxVQt9dxrn8E3", - "marketBids": "4M3LpJ9QhUDfiCHFCSEWfbf1wCqD2MxNAaBt1VY79iFu", - "marketAsks": "6SJ5sTE1ZbahJrvrUwao3nJQze4W9y9Hu4s61k26zsjJ", - "marketEventQueue": "DwK24QwdBM2oEk8FkBbZF5GyaVVQNPs7yScvq4SsJpxQ" - }, - { - "id": "HxSxnj8vDPKas8faehb2uPUBcnUEkScGoHgWZnMn9uDr", - "baseMint": "Cj7kya7hhhCoSnwAP9MX5o4VLJvkhc59PDvJnj7KACyY", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7YJZKQqnjNLFMswJoB3VdFEhX5hBZ5eme3aWyXtGLoHY", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "BrQwrNpcw4G13oQZVmsFq9rEZiGXVrEkh3eADdPfcHS3", - "targetOrders": "G3T4BfUvXzWeQ9fKdeFLiTXQdjycnnsgj7CwsuYXDt9A", - "baseVault": "5dnnS5JiTbWsCDTmV27eMBdYWJtFLxGkgpxqLgMLGJQw", - "quoteVault": "98dZuuNVdLbYuVHBVeoZ9wPdQbMAaxK4P72NaSDfYeVQ", - "withdrawQueue": "HQJKHpo5Ng11j49adfUKwHZqY5SryzFAq9i2x7smPsW7", - "lpVault": "7TGH5bPtRsEjUbAqF16fjZGx3gy4mo9juCHJrnuYprNr", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6k4f34fFposJ1gqRnKBKY4mjibQe48szqetHUsmCmt7D", - "marketAuthority": "EjsMHTFrLY8rpLvy9nxsdLs91Hvd4wisB7r6MZfwnTu3", - "marketBaseVault": "G6q9qCxB6Aso1NXpBfNrKP8WvCRi5BELFZ5hTXFUW1hy", - "marketQuoteVault": "EnJJNf9JXsYjKavzrmMGuN2mLhrb9HsbYotJDSLUqXY3", - "marketBids": "5Mppm5JZfRtGxeqjn5gziaLqxHWDBW3XwT8tKeky5ANd", - "marketAsks": "5q94E2eUSFwZrgv5629hAyBFd8nNHDzdiaBSZdNjQHW3", - "marketEventQueue": "4nUGds8wXBDs3Uyiwftpq2BSSr3ZkjiKcrj2M6eR5En6" - }, - { - "id": "HxTeMeh1AkjZsoGbDhpWjKJj6psNNrfPMBccwBB1Yozi", - "baseMint": "8Jdjg3xVNAAFdiDbFpWF2FX5dYwHyw5j3Myvgmzrf7z4", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "5qhv1LS3ErMaydVyFgEUos9atAtEiZUBouTBm2Z4pBiw", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "uH8PhScXsQDpbp7nwnfFUhBf3uXpPLAYBTzjLTtANUy", - "targetOrders": "3cBeVSUrjnLYvTUbujQnTECth5cBKSotEZ98m8fJmV8n", - "baseVault": "DLgh9PK4pARowq29xybbmYyMtW9vfuqZLkWxgExE79qG", - "quoteVault": "6Ys7dzXsYi4VJHdC57QYN5vsbWvFnQZMX4RAn1DsSLyj", - "withdrawQueue": "CAWh2rY2Ji8ESWryeZNygn2rSdyGTzwepV1z6gAQaunB", - "lpVault": "2ApHMnkrSroprA1FyzvsmSeTyvyhoMqnky6L5FQFMHsM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2naLjpes3SpjuSFNPtMsr7nB3MihNL8KvRArgw5zwzLY", - "marketAuthority": "5omB5G4EWr7J6b64DGDfcyS2bJFhDkPUoKD5z2iNHjKH", - "marketBaseVault": "GgLnJaYk8fVYbmQJwfazpn8sL5mCKzc9YDekcoXAeb29", - "marketQuoteVault": "63QyGTDEj4Gq5kV2eNwBVZtWiMbJg9ns7CtqhzwoX6Hr", - "marketBids": "5PAy2aAUxA5iW6wQeGthQHKZBc1jKdsxNDTc7Yf7MCca", - "marketAsks": "AwfMuCm6TsLgzJQZR9USABrKzGvSgRXo9qGCMDPQ4geM", - "marketEventQueue": "85cprpWxKJmTF1SzWeafrYzAcJKM89x5azupeZ4fh6jr" - }, - { - "id": "HxtMkadadcKbpyX1Qfa2K5KnPjqrc2ifBiEvssuBg7nB", - "baseMint": "PoRTjZMPXb9T7dyU7tpLEZRQj7e6ssfAE62j2oQuc6y", - "quoteMint": "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS", - "lpMint": "J1a472EWF7o43iw8JRNo3ChxsvAr7VTEG1rAe68ApUu9", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CXdTA7LcvGxfj48fzYXyMVx1P6oSkimLw2sSQFxUGLaX", - "targetOrders": "GxpPMhWpnf3chCPZfnETGmE3gnSbT5aByPMuwbUZVfk9", - "baseVault": "8rZt84z9CbyrQidsR4SW7g2BJURUpXvqKE9yA5wszfYH", - "quoteVault": "3bkhn28HuwzURjAz4gxG7gvUeSV963Zrof4H6GyvndZM", - "withdrawQueue": "Gt11YxH9Mcd29KjB2Fms62nrCjG64YrSm6w48gytpE29", - "lpVault": "BMziPYYP8V8RuvqmJZim3i2ao7LfRDcdxLY6MADZ4F75", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5xswMf18x4gFY3c5i3A2RwPwhfHPZ71kpzPpmQvWmm9V", - "marketAuthority": "3i79jhKvNeEspA6viZ32AVLJEZCYQWzaqEGRoSeCeKNU", - "marketBaseVault": "QbPx2GnrjzJmg5J2N8C88Vm6Dregwzmn1Y2dnBQ1xpH", - "marketQuoteVault": "42aYRgZ9DehNdtcwUuFtWT2LKyi4cMxnRqZ2vPwEAn3C", - "marketBids": "4f8Hpmxq2PgrQ6VEqmgkatm34JiMCgmhVefYASSXfYf4", - "marketAsks": "EFMJUWuDVCDXyZfLETJD79CKtaME18oj2QoVkvbB18hA", - "marketEventQueue": "Ew3PT74ErDy6cEY9xUH3pRopjeRpBg5cQiY8xEN7wFD4" - }, - { - "id": "HyvYAk3mMAZJGrHbxRLBQ2vLr6R6nBZtwGHSfbJYYGRB", - "baseMint": "A3HyGZqe451CBesNqieNPfJ4A9Mu332ui8ni6dobVSLB", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "299rsWukKLFrrDFvgoTnrbZ88G2r5EUDN4EnanPARtGz", - "baseDecimals": 5, - "quoteDecimals": 6, - "lpDecimals": 5, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "F7c4nezqaEuj8ujoPvXaDjJ4Po6jkKzWfP9D3dkiCty9", - "targetOrders": "2DRXyc35Pps41vTMbsgzSVYzE4FUzsskJSv1ricvifUF", - "baseVault": "GMrBpTo4gcr4ZogtxiVsjYVn1JrL62JgLWCamrf9Lukv", - "quoteVault": "5ULCYG7uxEVLG6nXveeUfBymqgfzfZr5JjJGiKyYmaQk", - "withdrawQueue": "CXYJ1EFKtpcsDSi1WuJ2GUsNnazcPPHSqLc5w6hp8SYS", - "lpVault": "3zm6Uw1DkLmGPHcqaQi7Mr84CNFXGY9fopLe9hHdFsJi", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DQY2Sjm3bEbrXhyGgHsXqLHU2EybBPVPLDTCrEHq9KpL", - "marketAuthority": "ksGuExtb9gWjmCDsF5kdobD9RXQcsCBBhTE8o9ianDj", - "marketBaseVault": "EzB2qzzEvjCsrTuozy1tzPdLitPh2yihgs2MrMmhDAtp", - "marketQuoteVault": "EWaYowHEPMSbooYvjoybFvFHaKZjwRXbFGs2xzrZJoXK", - "marketBids": "6o133wCSoJGU7UB8C7JmstCxs68QzwAQjpFWaKTXWi4b", - "marketAsks": "3QtgYQRQbKGCZtFoVXdFQNR6MFqAmoGLVmWFGKyEhFE2", - "marketEventQueue": "49pCtHCLJo7SJ5APuUoim16KFnEgNxRyCiYHTeooLrNw" - }, - { - "id": "HZn6xdgoZgGLf7zH5GZsr4BMW4XEuqndp3o7iYHuBPjG", - "baseMint": "r8nuuzXCchjtqsmQZVZDPXXq928tuk7KVH479GsKVpy", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "2WtVtLgQDp7kRqvn8NTMUAvaSzNte325EqJwXZdsM79V", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "78ez5yjPGrVbnyJQ5kUD3So4FcPVHqmo5pxT1xmt5sgS", - "targetOrders": "9VsZ3J2w1nHrMhWnwepRHosRiy3fiVkYSCC5ia2i9CDX", - "baseVault": "55KC986yizTHfFhCfQvJLwkzAC6frmxMPnLt2sqJP2a8", - "quoteVault": "GWGVe118LanC9b9Fm8prDxuppiLBNTe4DqhK3ifvNxRA", - "withdrawQueue": "CBYm5ubEbCvXSbgyxXW8Ek4FMEEEec6MhRGXDpB4ASQq", - "lpVault": "4yLPGfJYR4uBGZJDY5pY8Vcr8Js4vdK5Q74Np9h4vTGk", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EKW1SSfSfH8WUZ5C3xk9LFuA9hYhoBGnRrKXne5G1W21", - "marketAuthority": "GvtEitJupiEpqCmTQ1YgohqEF5C3s3DPsofdR2QefHP2", - "marketBaseVault": "6p7mjaHNSpv7vZ6wN3XsX3YegBUro6YzSWirExQ3Lv7L", - "marketQuoteVault": "DPiDDCBdVTtN8iUYw2b94GzqXSRq1hzYDKN7uLgkT7P", - "marketBids": "BYqHx4nckXMwody78LAjfgzC8QoqsQdNhLzfasMGfLVE", - "marketAsks": "F5yYDXojtNCLdGH7F5a8GbbJK3DQS4zNnVcuAbU3zsWt", - "marketEventQueue": "Ctu8LJDRKrnAzk8Krogb79tFgKKBtWLreAtg25PY5Vmk" - }, - { - "id": "i6A1rv2QXNV4LezRE91ivQ34nrUDufZbJf817L9WFZ5", - "baseMint": "cCUYsVip3Ve2EbStXE9EVncPiRdcjTH7LfFKaB8g55d", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "BWsUVeLgcarkDFpAJaz1CHXJhWxRaL29X31aVYaFM9RD", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3bFf5NKMQ9r6vsRdCv1yA8iJyJj1JwCDesw2BMniy1CE", - "targetOrders": "8rqosYrquAkgTtJfaRNsw1jztKu12Lw3ERDJXHJLD9Jg", - "baseVault": "DxcT28oqxJB4WpUE2SZqUwUUNtBEfrE6WAhjxqvuwt5k", - "quoteVault": "BaUyGZLDrVPdjnY1t8aRqwWwZTdGyycW8R6jxAdCUtak", - "withdrawQueue": "UsP487nGNsh1717hyHZhtEV9dot8cEPyef9ZoFe1qXB", - "lpVault": "E7XQmTpFDyjKBNMHADrMSAV5uVhSnKY4v9yGBEEUhsQM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "EU5n94oVHv3oPdMYHywb8exFC1nvQkWBVRWJ7htHFVK9", - "marketAuthority": "7uBnUkpoeeeRwvezJbPFJTQwKEzHmT1xawJrtUq9ie4G", - "marketBaseVault": "Fy1wAqp3vbPAVmTgQTzrkxYxF8QmonHiYzMRBZjdzUjW", - "marketQuoteVault": "2LPEbw27tXYW4nhJYqNZAugbJrdDHBWJDCHjetsc9d1u", - "marketBids": "513LFASbAPNeQCapHPBjv7xD2DwydxYND55XyJe4VmJK", - "marketAsks": "8q778WAtstP6qYR9DdVmfq4v8NV5kMyJbT4dTQ9crLMn", - "marketEventQueue": "8NhGCazxrqXEJaaytDEYNtvWuBH1LSUn6BDBCHGXrPKz" - }, - { - "id": "J3QSZ3o1xHHGEM1b7Tv4YpLXgRAyFCBN9SEpcBQAZdV2", - "baseMint": "5s4BYUXLuvs9ZcVDTxkTpKhThWFSpaU8GG55q2iySe2N", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "4QusTKEFcft5WJv3PykYsXYzyuvzDAQaXZ94cuYiMu7F", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6EAj9JmmihuXkgmekeFtWdrW69KfTYAbua2HLXtyV2WX", - "targetOrders": "CRn2zpBuJ1ELauJhCNvqdivyz3xgmtcetqamYCp3K6xi", - "baseVault": "2RHNyAZ49XmLNFj28nk5XUja9NssXA7Z5CaETxD3Hvig", - "quoteVault": "AQ6doSaCVtWt3cya3sVXPJzUxmihUjA8oqhjGrRc9dN1", - "withdrawQueue": "3kX8DYsFuPCWaNpWCFc94MLqygDMeR2CCcdzED1qTPUE", - "lpVault": "FseVVEoyutAXtZqukMRdmLapwaDzw5uQBSTw377wcDy1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3QyeyXNE9zaS7ZrGyTgfVveKmWz4ir8GDhWof2URuzhm", - "marketAuthority": "BcV7o8vA5ooe1ynNvf8FobF7nkpJ844vc1hYRZYvWe8D", - "marketBaseVault": "EUCsRrYiy7gexyfRdLy9c3BapFPQmQgbgoUynLuk9jNZ", - "marketQuoteVault": "5u1k2vSaT1mGoKphdGcisdWi9XRwtAjHrnjwZQZ1y2jD", - "marketBids": "Ei15qyag1ACgpKSo2B1bU8NGBLuLabupSdXNyku14tpN", - "marketAsks": "Gv71G81gRKfAM2TF1XcY5dX9nJhhZu15z8mJptHHwFTP", - "marketEventQueue": "25MCiUarmVudJhjSr7wvkJ1G1sdQcCR2aqTNKZBCqup2" - }, - { - "id": "J3wsRUfFCpAg6LoH45VXXyCk3X8vS2FzooZGoVgDBu1n", - "baseMint": "puppy8Lhckjh768j7vCPLr4244a64ZqioskcXxyb4rC", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "GDWmaokC4pKx3naNNSwjUicVsGt4wgkfatjuASLGB4uc", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FCeWPTvZvWUSssL3Rt2WJem5u1drmhZ8Fm4ocRJ9aq6a", - "targetOrders": "Cqjh8VfbLfbAMCwomubiZaQwd6JZbt1y1qFfN82vnFG2", - "baseVault": "HLPyMX5j2GmQWsJRBpWxRVPSXif11rxbFoVvZf8vwyDY", - "quoteVault": "FRpUajqucEKa6cvzW4jBHuQ2NdbvKWs7cnj7MyV91TMu", - "withdrawQueue": "ErtJPfmLa8vYpmm6q6mVq1GysnNc2tVupicwsVKEp8C5", - "lpVault": "HJ95kW2viSpBBo4LaU3Q6ZiCCjS6LYWWQyzz64qjtdGE", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GQQKuYXvdDV8qYMAaZDMuXYdhk1cokWhtSqULWnHZ6Gy", - "marketAuthority": "CtxSYjoFbvs3a2kKERsaguVK4v86hgcYkPDb4mK5Qbve", - "marketBaseVault": "EzDBy6eMya9iEhdTxDe8WSgj9wi7krZ6PBW6GACUnxc8", - "marketQuoteVault": "7zGXtjnxRKiyUBhPhP1n9oB48AfraVJJimAU8NJ1NLG9", - "marketBids": "2bxPExCsbasntbAvCju8a5RGnSfReaKYAjRHRkZDVzz4", - "marketAsks": "DQ6nFLNfgxxsgywBDJ1oLftMFrZN81j7hQprJ9EMivL5", - "marketEventQueue": "BSUKQazXun3LGGiJR9T8ZR3usn7VVHr1msUrmnqV6zUH" - }, - { - "id": "J5kd6Dj6xzjF6vjTpvoLxUV7q4JuBSVbLGCH3H5ju6cx", - "baseMint": "6wFgUMohoSavTuEneDYcrb9qF3JsYVVXyB8jb3PaXCJ4", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "8VUf7P8gRFsbLJSgf9Bg54YBtgxJHx3Tj79kXS2MEHTQ", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AVbavStQVYkPKgmedmsqzHFpGaY83nEWSdAnytaHgfjY", - "targetOrders": "o9ZFhj6NpfjjTiUQgDZ8Mv9NE7w2U7hpYcbYYdkEpgi", - "baseVault": "8XQtZbPC8muhLt7Lt1FFtP4kTUdrhzP72ocVwt23VKRi", - "quoteVault": "3dztzNbkiVigibdcpraCRu3fmBnTSK5vz6jh7nuapA2s", - "withdrawQueue": "8sELo2wDALH4hyEmr8FxZR8jfnx4yM1WDe6Bk7YzgQmE", - "lpVault": "HQTR27RMGvAQ7UgHZgm8o4hT76LAWngHG3BRYq9oR7Xn", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BzPYuTrnRJUvnMeZngqj7F4mL8w28zoYYWppgS6sUMb5", - "marketAuthority": "2yTYbPCDrEybkcVaAB66wD4t627d3cepEL9iQ2yZUiq7", - "marketBaseVault": "5MStJs6kMkTq6Z3qNqWRtbNSFX25MTXkfYhFCzbye2hp", - "marketQuoteVault": "DPGb9xDJDJjy9Vtpge5Vag5V3goQngPPkceccMqAm1Xk", - "marketBids": "FDxAAVQPCxYY13bT5Lrr3Lvj25LajsLE5LRRiNMGgKwh", - "marketAsks": "DvDTZsRSuJZxVaqRQLVHG3US5D7ad5XqM18UeTfypdeW", - "marketEventQueue": "4Mx5kpc3UaxapqyUgrxQNfkZvNhMspPtNmtwHEcMhUrs" - }, - { - "id": "J7Gn2eT6QZihFxdREUGrixCNJkzXEarsZypZPWgTjAYh", - "baseMint": "DysbQiM8nPdZbBhvHM1EgcSE73EwtFWDanXwY8CDD3Jn", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DGFb9vSduRUaXncSNLaWUocWj4Kx8tvXjQMmrKPczMbY", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5M6zJezj6Q1LUcd3ur6rE1Gg9GzJ2eWVp7itTjNW2GZg", - "targetOrders": "qfUtUAxsBthqkjwL5yxujkuda8P9zv1n8NkyoEJgRrC", - "baseVault": "CBdb31UyA28bSD76ujp1R7Csskxs6fLrgHYQEUaFWZuX", - "quoteVault": "3RBfKkZdeFjCuyrzk91uKWEGfqu4eftjo4UAz1H8ZVNE", - "withdrawQueue": "HKK3SRF2cvNS7xLPJdcR5u2dANCbJ7P8jJBpShSKnEq", - "lpVault": "DLfeHikEayV8JW5epZaJMhUgdhi8VYd1vwPf3Wit3nWw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "45X822mVRGqyHL5U6LASEB3S6LMzdWm9wWugZtNBeB7k", - "marketAuthority": "FH1B8FbsvLn8Lytyj4nBFQv2VmkStXuYiaM3zaX4kYvV", - "marketBaseVault": "A938jRmHTWFQC2v2mqQSpSmPbxUyGPQiCR9KieSHeD4s", - "marketQuoteVault": "89k4bd3w8c9k9LAkGq9d3GVkTUyRbp7Zm32RidToQMjQ", - "marketBids": "AWYg9abcA9KTRguv14CeifDPbvz8EcfkeK2qmBunYx2z", - "marketAsks": "4YPrVGuZhS3SbmoWkZBj5xqyZJN9pXWVZzDXTo91z1Sk", - "marketEventQueue": "C13B6DcQSsqtXpFZYweDreMQkw6vWTTwXNny11MiYRPM" - }, - { - "id": "J8bjfoZoMBon1fDgv4JXs6h52hzfCS87p7kNbJCVuVzb", - "baseMint": "5cKFNtooCQSkLhdFukk8R3PTdT4Rvm9cJr8Et49TxchR", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "8Cpeo3UzxR3qcHccYhEe1uS8AXevJ9KR2SH1hNpC85uu", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "91uMz7FiwZRqkPoyaY9QvpMi2szSvYB8Qo1rWBmHE2CX", - "targetOrders": "Fz8QoRiHbSNGypbagGpp5o47VtmGaRbyd2dsucD72KKj", - "baseVault": "ACMy4Kwoi1Ptfewuerf4S3S2o4vLMGRc8TBurxuBS5ym", - "quoteVault": "54LchDv5JDrXkeQrVRTodt8RyRQSUUat4m7kWSukgY8Z", - "withdrawQueue": "8mFqv3TppqdaexmXKakzJnM7Djsa3Q8ouokV6wtSqni9", - "lpVault": "3coFRv7UX5zHas5eVfCmpHqdymbkCRiSivb2incshJdU", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5YAwWpXeAgmMve8vVYUHVku4QnMscvBLMNAUNboSb2nX", - "marketAuthority": "4ets51ZuoYFM44AVTcrJ4gZ1EQenr9UTK3W2DA7Q4aEm", - "marketBaseVault": "5JaHcD8KxPedfzQwXWBCdp6NNeWo6YpL9REQwLiUogLo", - "marketQuoteVault": "2EAicto4x4UopsxETn97PUiiRyv6vHwPekpyDtutWXb6", - "marketBids": "9ttpkHajTYCWeJ9UzXBfWWSEz2GgRgiZQkuvLzjgNVf4", - "marketAsks": "4HRp2WU9WPEzj7SczwDmirRa66KkmpuhdUeeVpwQDWBg", - "marketEventQueue": "D1r2hbwJwaSPVJjMFe6gguDdq5uCAhk1UZzGa9BP1Hy" - }, - { - "id": "J8r2dynpYQuH6S415SPEdGuBGPmwgNuyfbxt1T371Myi", - "baseMint": "4hJ6sjwmsvvFag6TKL97yhWiBSDX9BABWoiXgb3EPXxB", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "2iqMaAsJVNc3SbfkJDSEiia2oG5LkRbfrS1AgpX4mqdx", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8wST83JAUvvRrf42Eu5wyr7g7D7D4qsUDUZJLuf7qB5", - "targetOrders": "HRAZ2fQxX9yFMCPwXZjDfhqDGocJG9shCLidaAw3KyJE", - "baseVault": "CfhKoYHSQbXdEho5fmnfewZstFAWi3CFJoVfgV1gDh4Z", - "quoteVault": "AzxNvPasRQCocbu9kjRjseaTdUEwHMuNs1SMr8iF28XG", - "withdrawQueue": "3TK7Lg9dtYiuxNFxKKS7s8hZqYzaD8eJhVWiiHBRGJnU", - "lpVault": "93Br2yJiysaf49RfjDa5v8Q4F11qC52esJHpGDcFDfof", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "3ZQhYKMo731KJcy6TJSxnz5d87ZaukKduAzs5mSrNy7b", - "marketAuthority": "6Z7DcxgNDf1XL4qKWNNQJbKuXpX4FqKM7qvaBuErphGF", - "marketBaseVault": "6h8ZDNkfKUDiJgRASh5saKZJzZbm3jakndR9v5eTnZZZ", - "marketQuoteVault": "Be23eiHJjcVvFdnTVV81BH11o3mQCB5oNUjKeivRp4Np", - "marketBids": "eeDyuvyvZz8Wm6iAStF4PJjGnxX31VayRQ5j7uXZXzc", - "marketAsks": "EtyNqrN5siMcFzN95sQJ443TvyYde3bbbrAzFBSbD5NZ", - "marketEventQueue": "9hBykWxB3e7Qf4tqA55xmVB7DxLtorVXf7t6dZNtg3Dx" - }, - { - "id": "J8ZrMooM8EhS53Q2uPpUxX53G13MZpCVTqf3TvyFRGUB", - "baseMint": "3swraHsc77KMg1tFvwH3tfYcd8SWr5fcUhtmRxjavG7H", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "H9bGMEXwN1NRfujDgsCYMyqWLw9f7DAfcmvmfHymqgwz", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CiCKmFcgdCHYytPv8s3UWgDjYxVTXmqgd5sukj4te61w", - "targetOrders": "HHUfLj4FHNYXe6FfjURxTSXkK2nmHYQuLWtbAMWgxekh", - "baseVault": "44a8Zt8YEFVz8R33gXye6J5BYQT2ksKZAcRq1Qa8qsXV", - "quoteVault": "A8K9Hf68jP6HfXwthCXUwMaCMfY6LsHSJ4LTNp9cqcvB", - "withdrawQueue": "HUb9YRrCofqAeYBKEf1HD4TLQFukSvwCVF7P1WAzjfkQ", - "lpVault": "66FvYjC9id37RbfAoAMkL4HqmE7v2m89VDTU9E7tiy2h", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BsKnqn8XxXdtuKeqm5cERJc6yoFwj15q6nvq5EecLGtM", - "marketAuthority": "FgFMqSQSmguhLKUawZKEsyULVgsCDGWZvYqMh4JRa1Pc", - "marketBaseVault": "5o4DwioASvdxpmapLLk2QgVtPsGEpKHhmtM3B3aQ2so2", - "marketQuoteVault": "GBYt6kUErNQ9asrvJUDzyppPZwiA6b1Ae9qFhYwonj9u", - "marketBids": "CiawruFmC7yWpruA4dL3HwuafGyVr8ScX6Uawp3yWN29", - "marketAsks": "2YM1JsdZdxHCwS4RG7CLiSzyoMfxpbuyoiBBRjsyUQqZ", - "marketEventQueue": "GYyWvy6Qoi4Qo12UVo4RBao8fTXJXgg6nBQYtuPySiv5" - }, - { - "id": "J99gtLGqEeg2KNCFe7Q1XSc2RLrAP3DXSyEXZzJUnxya", - "baseMint": "Bqd2ujCTEzpKzfjb1FHL7FKrdM6n1rZSnRecJK57EoKz", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "78CeyRBJSu4MFmaDi8Q8QZ3szB6Xwp93sVaMLYSy5SMZ", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "47ZTSNRAQdfztHcBQZq7Ekqfoz8ZY7yyDpNX8cJbF6NQ", - "targetOrders": "oSFCLVo3aV8BwyYnk9nKu2JdA6XyzYNtgJLzCk1dw6u", - "baseVault": "6tCdtW9wZ8VCuLV9FYehnY8LrjwyQTz1TAoGowsxPRqs", - "quoteVault": "5UGfT5VDGqZTUzPmNqif7c3vbxT1SQAaB7SgaYTNj5CD", - "withdrawQueue": "C5F1MaHRfB4ZwWnH9BAzNsrDAb9QQJGoUsH5UafrNvtb", - "lpVault": "5Ea8sKigpt5MHTMtohaoHBUUDtJdge2k9qfbmtNpU6ye", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7HZepGni7KtB39cVyuRKSgtfqr1TddS5XPk7tJWrJ6kL", - "marketAuthority": "GXyHTPGKybak9ZmUbpudV7NgkMMg2X9tzB215piz6sQ9", - "marketBaseVault": "EPEeqFiWW5NEXfKrHxRo21fVxUtCkaeFTsmRqyZrj1mW", - "marketQuoteVault": "2vRLQbxqgNcryacrRHFGsbYR8xGxdN6scvnowKPy4vo8", - "marketBids": "95wDSGpGhu3QLHUEqWZd5VzGLE9QCoMUF9R73Y5XdTXs", - "marketAsks": "SkpB4zFxzFmwyh1LFkHnZYufZJTxcMxr7bTkP86Xio2", - "marketEventQueue": "AzSFdkViisoi5M3UYvQYboQZqGCmb2VX6jXoBVN1Rq9j" - }, - { - "id": "J9vQmVKt6tn7aFFRREykZYu25nbnyi8hDoecLdBTow7", - "baseMint": "5ENUvV3Ur3o3Fg6LVRfHL4sowidiVTMHHsEFqNJXRz6o", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "6T6g7XBGkV8ykaqQtEhP5qBdTQsRA74tGRub2Wkjdcqc", - "baseDecimals": 4, - "quoteDecimals": 6, - "lpDecimals": 4, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ENrZXnf9qiRrc5RuoUUBepac7cdqUQo7dGuTUZvmyert", - "targetOrders": "9dyjHS2n3SXbZGwLsueMCHF3hf9SvcPPanN1bzX4xMcc", - "baseVault": "8JjDjehzuFDSDhY5KYbppArkW4D1mh6Wkir4PRRBdvvW", - "quoteVault": "6LdTmuybQ8Lop95MVvfgE7GVyetiQza4rxKam6mni4j2", - "withdrawQueue": "GMeoAacb4qrciugwTwjRpA7M2wL66BzMfwn8NAKMtRpi", - "lpVault": "BgZ4UMA4b8wFaWkgYG8SrRnycPg5NZWxy3u61aUsEpP7", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9HXwwjYkemjH8Yx14ezUikFcScskZncZciKv4juLD8Y7", - "marketAuthority": "4VXU73g6uJPNFCs6sthxKUrZb2QrKn87AfWrSH5D4TVn", - "marketBaseVault": "8zjthWZZeNENJFm4HnWhCfweAJ7wbuv2JMTpy58Tsh2g", - "marketQuoteVault": "3Ndmk97YyPiEJ8EZrTX8AifsZzpFYNK88fvk3TT5mvZZ", - "marketBids": "3zpgjwEMRh3B1s5tt8mGS52RhE1oDJQ4ZeLfGrTZmbsK", - "marketAsks": "CUth65ARUc4MN9qvg3oPC9jqVfYkegNvyBymKZiE1GtK", - "marketEventQueue": "2WQkLiwjbJS2EP58Hhnb61SPpnGJM3gKkM1o79T99z7H" - }, - { - "id": "J9y1erAob9xDi978ebSmZLR8Zhr8hMindBp3ieg3PwVa", - "baseMint": "GvpkzEc4kiKS3xzNLFoc3k8HUVxYCAU8CYBkhAUKsSZ5", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "BcLgbN6e7CJpmUMvyYdk5AFNMSqihiMHWxbagUJiipjv", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "C2AhNcfb2bo7zRqZj4EcZ4M6sVVfoXEZciEQZki7tGX8", - "targetOrders": "HdcBvB2M1TtTyZxt8npFs8nd39Q6FnQUmeQBD3jkKyq", - "baseVault": "CensrJoJMMG5bGEvjNUPLD2z4Xa3RBkYwoPZDQW4VJWb", - "quoteVault": "3c99E11f1g5Y3mSrVDTE65rpJatRH1MjYGkQZqZstSej", - "withdrawQueue": "BJgcnLJus7d4HPaPjf1FTHLwwrdq73J6RmjeXioicPXT", - "lpVault": "2jFd58fkDfosVMABdvcqiqCZSYjTRUfnmUA1gdkSGBTn", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9XAN9TJkhxAqSqGDBSJpTx2GkKxgwfhaWxtmybCaJqMm", - "marketAuthority": "GPozd2ndGC8mraxwR2itpwGDatxuJKtxujWyVRDqMFV4", - "marketBaseVault": "2DBx6RCVt1pEVMQU2aC9ZQoGAiRmLHKKCvCFrKGBsV6R", - "marketQuoteVault": "6kLpUMuAPG6fGVcSMmETQc5QfTCk1ZfaikEDX1sHuHBc", - "marketBids": "AiJoKPwwA5EefgZzBSfDQ3yrVHzVQeVmwXS4s7HybvxR", - "marketAsks": "CGJmJkAqBwhWhVbuUYKp3BsHkWQvD9G6ut6XPZT9PKW5", - "marketEventQueue": "Hj3Xc6WWDKMb2EqyyBW8Z9mWbsSYNAyhyv8L3a22KCw7" - }, - { - "id": "JAq4yY7k24DrJjuYvJkpounqjo4xYDoPFWQ8Q6sbancu", - "baseMint": "7CUJNc1jHfT9J391frL6CiLhwJUiFBs5SErhdBJ3KAQQ", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "8qFRuRgVWc9HPuVXBG7PiFhyHDrVSCDqek2jmcGh5Jp7", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Cqfik9hEnx7A514gH1EK85Tkum6GQNSip8fosQox9c1P", - "targetOrders": "CKGwPHXr73G7iMbnCENsgCmHxqHqpSuGhuuWcZe2FXhn", - "baseVault": "Fq7Smteibn735bHAu2YYrwzRuovBRfuGFCtRn7CfYhGx", - "quoteVault": "2WbrAuDaCHW2MV5heJMdUx9AJZS3Pc4zQDhH3feaxWMM", - "withdrawQueue": "HtMZ9yNj6NUKg4PFXxBx3HgNjYUHP97UuHtjg3ZZxxsh", - "lpVault": "71d15RQBm9avmS1JtABPaEAmyzC8Bs6BjK9bANF9cLTd", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6jzcdckWTdgzqrBBwyrnCS5jsXQ9tw4mpTF4Z15Syi8h", - "marketAuthority": "DwLqcqYmewN1VkzCdkKAvMEeBRq4XJmU3Q67gmmaN3wy", - "marketBaseVault": "5M7uMdHiAH8BNGbZ3PQ7FyGvvLRFR7MBNDSz52fFFpcD", - "marketQuoteVault": "9rwwevv1ocQP62E2grtbVp6vce2cp64ntXTJyQdxKUET", - "marketBids": "4QDUxTNxygpBqNH3GExkHGCFt8mCXZ5uGb1muDJyVvX9", - "marketAsks": "DBBGxY6BQv3ZJFkrcJC11vPSBuAJTBtnLhyuDhedj8iv", - "marketEventQueue": "F7647xzUPCUZZis4jPT8QvULXJ1v5QN4kBUHxZ1NQtpA" - }, - { - "id": "JB6vxu6AThYbGFFuL5j4uaLqYsZBVBDndogFUrLz28VE", - "baseMint": "ApFmGAcE1q8SYP7YHRvuuVoniUBHwYdkv2N12QUeHE8Q", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "5RPLVzTpiEZRwcRXxn4BNHWGE52hP5yuC21pGeX77R9P", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6JYWVv4idL4TomCq26Y79u9aAmb6BLzJPxaUxR65aGXo", - "targetOrders": "o3PpAn4QUxdXnBjghQj11F41uAJDXmAwqb7m8iWW33k", - "baseVault": "5VMnJGVgeVkpDnA8Z6GZjS1aXpWTVKd7WQVboiyTt96Q", - "quoteVault": "38Pg1ymfNa1wqwMdNfrYpxG4Ro1u7hKzcYj5K9hFf7rh", - "withdrawQueue": "CYZAak5VQgQLQL8MZYKGc3TpMfHwVRXbf1WJKmf7HsFG", - "lpVault": "9NVjgMPxBq8MuMmdRWiutEkavBk2ofFZsp5GaWuHR2w5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "GvTR7hzoBDZCnNvkMptBkyrjZszi8hx8Vrdzu8m4ULQ8", - "marketAuthority": "2th9jU8sH454QhPTBw6Kze4DdcHptCHaTWmA8UHqKwZG", - "marketBaseVault": "67RRLCNVcNoqc7aY5hoFv8JnYj2NDhEaHifH7vQZ5evs", - "marketQuoteVault": "6VK6UB6JW7ELVY1gVEFcxDRpaQqWVQY9fcZ2W7h9izUk", - "marketBids": "2rAjeSGU8BW4hhPXzZUcXPcf8YYepLgXGuM7tfx6BAyt", - "marketAsks": "HQmNeBCHJw17PRevqVVtFWk3cktwJFLkfDVTMGzz5rhd", - "marketEventQueue": "78Av12smUcdbZZrg34oTowkA82GzMhkNBvgFCC1pDBe7" - }, - { - "id": "JBAe3dHTmS4rEQWkN372XxB7pZGePFXPqKumWu9xHLE5", - "baseMint": "So11111111111111111111111111111111111111112", - "quoteMint": "BKMWPkPS8jXw59ezYwK2ueNTZRF4m8MYHDjh9HwUmkQ7", - "lpMint": "CAW6jYgcUBGhAMcjPEZthGEPQd7jpREW8eBmQTXHmtP5", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "D9WsxSod8TuLuacERypYzBrT4fD2AUB7jyEKofC2CfNP", - "targetOrders": "Gic81VCsJfYAZEq51ZGB8ffhAeevjyaFJ17JGM9sTCCA", - "baseVault": "Bz99sjaEnEx4rCEKSWn9vqtFYW3MkhL5QLZSfkf5RHTj", - "quoteVault": "D5QPwja27yNhHFzp281ZWbaDDcb8KA6YH9pu5UQGtp2X", - "withdrawQueue": "63kvtnjcWyUKAKUHV6pgBArT4ffwrte63VQeC2XUAVc5", - "lpVault": "B6WhsZQoUndanRaXFNWoeYfC8rJ4swQ1CFK6Gh2r62XM", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "89pBeyUxduWdboHHShqwWavCrnckZu4SUPg7MZo1H6Na", - "marketAuthority": "A98DNmPk6oo6xKMjswyrwywjXdfb1Z93WLGBfCEzvuW7", - "marketBaseVault": "v4kdjAQJzhv6EhL8xFVZeAxouEv13gxNhfWE46geyWc", - "marketQuoteVault": "Dg25xUxWkcewBywwFMF1oTHJvgcttM8viS7wcPwEUjCs", - "marketBids": "4dySdHtcNpfVnc8R4pQbZ7JhxLjEXADxbgkPqCubVk3h", - "marketAsks": "EZXVm5bBxqQkGLokKKQN6azTh9PUK6evavqMLjfB7FZ3", - "marketEventQueue": "6mneTEdwdbcACHFxvR9PCALUHpw2hiyNffk1GLxMYDqZ" - }, - { - "id": "JBDr7MqwoKVb8od4HiyWrZ51aJP8ohuMrS8tbu5vNrBj", - "baseMint": "DF4tgv1gDDdciLZe3HvhuVm8LL9ZqvZxiZ5mUzMg6eSs", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "DjctNci75XuqGa3mQDFzthnwsi6CnhH6egYjCxYKq8jY", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "5z4RgW2y5peRjRhGVeK1yj31U1LNmkiZwJPQV7P8WcfF", - "targetOrders": "G64QrGTWSGjt74XrCQ7EpFk5DYFQhRxthjdVnBuDk7Lf", - "baseVault": "4W1NDxq6YLarQtxa3m52t8weYB3ByxuGYxs9HZWkRB2y", - "quoteVault": "DZT5CvH41tuzBPrsBuBKG6Cd7Xz5xeVvqTPNNUMid2XL", - "withdrawQueue": "AzU4eXm7waPiNf6oK4yH3xjNeWRhCSoo9ZXB2RGPYbia", - "lpVault": "8bvmTzskFpa3TLwQeLNwWu8Bf2cbKAecTAMvMriwKXau", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "787ZBoQXJ3p8DjWgjEdQQpibnksCtct5ERgqp4wtavJt", - "marketAuthority": "8XtSJUPWsJNyZSuNJqjqoKAcrHgSZMf9PHamCYecwG58", - "marketBaseVault": "BBpy8QiHvm9TCTPbbT6bhCHuRteNcKzocJLf6Hbkn3Wm", - "marketQuoteVault": "Gy8F2J4Uj4vPQxbCR3kzhHJAhfM8LuR1moe9G5yJ5rXx", - "marketBids": "59WNS7gExB4gfaUWcQEHwDLjUmrA3gBKkRf9pWNLXpT9", - "marketAsks": "t1ZWWnhMmQ6sg4VMk2u2fX7EenY2WUAGMJCXtPKjGgD", - "marketEventQueue": "7X1FnHFaEoRRzgGJ1PMHUcQ3zbqnx6Ux5YTC5GJWBUjn" - }, - { - "id": "JDjMV39P7qWbxxQQszSA2xK3igFWFjmvr6niFQx2nJkn", - "baseMint": "CH74tuRLTYcxG7qNJCsV9rghfLXJCQJbsu7i52a8F1Gn", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3AkW1DRpkrxxwruTPjE2Ei2G4qDwN5GXpF36YNqeDo4Z", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GzPowiCiyCkoVRTvkVfwoVQaBv8xASduTKQ7YXK17fgs", - "targetOrders": "BcY6wUUHmFhvrpVGACcuXxGbHsztHywQUAkyeBd3FQA8", - "baseVault": "FrUPjQqfDbaFcRaoXFP54wcKHr3dTfTZGxjawwAVKQzG", - "quoteVault": "9GJGvbccctS6DU43mCX82eSJ4VMcq4YeJdf3s1i3M8t9", - "withdrawQueue": "Fbsfh1C6XHvSGbDDpRy2f4Pmtterf2MtH6g9F6SsG3B4", - "lpVault": "FFRbZNGPfVdy6bgFEDZDQSCBEDhG51geSQRUAdaYLCk1", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6DhnyzBiw59MgjjVE1dGwfX8PKSFmN5gagcoCAn6U6x8", - "marketAuthority": "57t3Kao4LsGPDa7m9J4geXWPEuk8gB6GeKUvTxYrNUQM", - "marketBaseVault": "EbKX1qcsHP8yjc9R9VeXPL4y8PEMYaZmerBQP6ysJhZ5", - "marketQuoteVault": "HcdjxAVDsBkWGZmcVqRb4BPJVnAkkckUXQMa86nk87kh", - "marketBids": "CoEUyt7Dq2FHWohA55BH3x9QmcBKMXZ4x78hkpfc8yAo", - "marketAsks": "rKo9pxEXHkQNkjrHxj5Ftj2tBtvkN2qYiXWGZuvUCTm", - "marketEventQueue": "D7yPKPFSQuYTtaLKNcZxwFXqgfL1Jx5nDgjAsK7nfy8n" - }, - { - "id": "JDwinWih2qpH5B5wwD9KkC2esU9D2mAKq9VAtrjbt4M7", - "baseMint": "2cJgFtnqjaoiu9fKVX3fny4Z4pRzuaqfJ3PBTMk2D9ur", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HeEYnmE923g2k3i9rmGZszxBuHy3ndAx8JM2DSdADdwb", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7WqAbFtpVj6XZ9ZBu7t7vRkLtsVMNjimEW4Eru7eycmH", - "targetOrders": "HDuGusYKkVP3MuCP9YePFqwrtrz6XXmv4JgRuzDSyKHw", - "baseVault": "DHbbj2MZPoiihzaFtzx3HpLU4fJmNXr4TJzsn9GgTqyh", - "quoteVault": "24bTyr7e7CEXzGGdcp3VC3w5QoaC8vbUsL6jRw3QtUVJ", - "withdrawQueue": "DGDW9fn8mzQhoHGzmGTeku7ePootCh1XUqFqaeZjZxcs", - "lpVault": "5YC72dqZ9PKSTKo7Poh8wbRHDQQqoVypzxEZbxxu4guq", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5ocAKeiikP1y9wZhgNQDKu3UXxrYusxmDVnp44z4jner", - "marketAuthority": "3VP4ZfL8ZhYsFk3ZoAZFps93q4Q5c9eyryEHMvDcHY9T", - "marketBaseVault": "3ALKBmDr7aTGj5t5L2BQVX3sPRwjt69dywi5gSYq6XKS", - "marketQuoteVault": "EMyoCq2zKvHBGBhnsRL71r7xRTYHj17DnkKhAQ6BcrEh", - "marketBids": "6WjihGUpCsZUr4uadL7KM3f2EYpTXnwB5QGLkWmyAaF7", - "marketAsks": "2eN8EQcPmwhLtHwxJJPzLGeZBc1cGPLUyWAZ2P254X1r", - "marketEventQueue": "EUZ9CHhfSSxXoedFQswF5sC7uGMpsbsSSHbS2JHhUZiN" - }, - { - "id": "JE1UqzwWQrSiDMfK5Vg5eEBbeCg6wEn11yadUkQUUGYd", - "baseMint": "5kANAUeHsoambmdV317Nhs8puVxfukyChr9j9TZ8ZeQq", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "BpXKAcFTi6K2G2JSpk5HW8EsTmvhYPCEqMqQJnSxdXvr", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HwPPoDkya97NVCM9EY4LXY8tcNNJ9TuMpjbJnvtuMvVy", - "targetOrders": "s6kJCWRghZ2Mjc4gMDjampXLZvMCfg3a75Gr1qoeMRq", - "baseVault": "BDh8MB3X7Yin98HHfJV7YXT4mDnqWyKBYCQvg3qPYYwk", - "quoteVault": "9Z9MPFPissKngW9FYJDPkKMv9mg8kpTShqhBMxis5fQV", - "withdrawQueue": "G2bJfoDu6oH1QTLcHpJ9mfJEJoQQ3Y15x26jMzj8dtnX", - "lpVault": "2KNJGiaVkm4ZyG2gAhhrigmg69Caz68gXTQvE4XfsC76", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6ArkbdDnk662UhJDoKsDW75R5JhDizkJQn1mKAiRBnc2", - "marketAuthority": "86X6Djf6GbcMfyxJitAGiTuGRqesXrEFcNXQwfz6VjQY", - "marketBaseVault": "4L2C1ysES1NP3Dabnsop4sEEyExLgzrwgrS1bND1jPbr", - "marketQuoteVault": "BTpFKBAQXfM9xoyK6D7E7QPouRsd1C5Jmkm6BGQZrdY", - "marketBids": "9SFgt18T92EpCpJj85RrogGNZohNfTDjJYYGvYLRL1iw", - "marketAsks": "2SMYB6FkXEDaDxeCvadimoANXNvE9ivdWtFiUjCTr5QS", - "marketEventQueue": "F2L3v9cT8f7ofCaEfhbeu827m6MJte6ZHDuQhP2RvtzK" - }, - { - "id": "JtGewtWyVqSBv6hedZghGMZpS9Ge9yWSYLJL19VyGLr", - "baseMint": "99Q3AfFWX3rdidoQCnAPPoZFjsaXr2AAk65RUgxiwfUi", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "AuCLbqgB3rqemZCLXPTVZ3iszTXY8ToHk1kpnPxKYkoo", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EB6uJv32nzjsMShAhW58MqbBaGUbFGSJzuzDJj8LW8nW", - "targetOrders": "5sqgifWBeczSQC3rokm8GwVxREozuzy3WdfpTpKB4eFn", - "baseVault": "41d6NPBJXUrPBCJAqSmTNfJw6XAHKdjP2i6sRfFKtxmT", - "quoteVault": "9qTeuHBNjGNZGts7gvRRxFFJ9tWtGaUvS3fRzqiHpRbr", - "withdrawQueue": "GvFKuk5dqqDZJUHE1jwv4Dg7cYqTCBL1khFKdCHqy11s", - "lpVault": "CBZLxbtdj2Rtph3t5WdYJZwNrprShCjegHYi828H9pe5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "U4ApHjhnwt52QmoBfDHCSyN1madA3BSaYLS26WeWvoY", - "marketAuthority": "CgdzeUbnVwgSp6wRz1NCv7uP9XJzT1PqG7WBrr8cExmD", - "marketBaseVault": "F1BGqzq2KD1vRMzupjPvrsg8yNXwod6ncAqJReNJQVgS", - "marketQuoteVault": "HBxpcBkhh91bBFVGokrRAAhKjH46Rc1JCaWVtYQnsXab", - "marketBids": "8sV4ft5V5Ei55dBnW8zc6ikTchLncREvW7NecUugHojM", - "marketAsks": "7NZveWB9uF7noQmZUiqY2zH68xHuAzi54U1fzLmGJdmV", - "marketEventQueue": "EeM9qf4hatcLrtV3CFLN43a7AUuwSutUDUJYBZrpRJjt" - }, - { - "id": "JYmFL1fJB7dwQjLZApYBKtMbPyDsfwUKd4ATgzP8UnQ", - "baseMint": "Gh6jp5U3yfcJwkZ7RoY6Ak2tgd752dSqBSYwHnfK3gft", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FmCqNdEYWziTBaAejthmt8xVEy9Ue22vHbL6wWwqK7wU", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CjSKseECnPbgvn1oYbaEhhYtQyZ14HMd4Zg4k7EB1g1M", - "targetOrders": "A1q9J8UxY9qvTyHXDvVjJvVaRf8QUfbFXoHkQurpmvUB", - "baseVault": "AFq9rsn8jMDMcTG14wTFUyJ76vJYziEY5JgU6Ez6VkVM", - "quoteVault": "3SrbAFk1puJ9UPu6zEgkFRW7UHs8eCuJm8BrEMhozTh2", - "withdrawQueue": "EwJxcZCJeYBTidHavGKyotJbWobz455khJcMo9682NUo", - "lpVault": "A43hQy7KQqMsCCrm5CoPk4ctRo7jZLWC16Zev8tnpZdV", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FJwGJFcu47vgGHEM6y124HxFuCeg9o5UAgA5skgWsSUv", - "marketAuthority": "CQYZSgyswYwHL2odUKqSB2SZ3EKcgTNfwLovcEe3zA3k", - "marketBaseVault": "8He9n56x3J1DdMr3jn34o46X6FBL48b4JBq2T28SNaTh", - "marketQuoteVault": "GkzCEfmiQrSKgpNpWaV2H6tpXUkLiHoSvSbzCiAnaaxo", - "marketBids": "2veNcAFHDUD1sDtGLm67E2jBuAWMLTSYnQRCq4Tj4UNT", - "marketAsks": "CK5HpGbUN8nPnbKvCJezGbLXBwRzRNj6jnBzstvp2RW3", - "marketEventQueue": "DDfE17H8XaLrm1R6Y9FgJXNvzXUsZNsrTMbN4GpugD6W" - }, - { - "id": "k8F1ZZy4kXSk5mBxrGpUYT5ao4kEbLibNJHRbKvpJTX", - "baseMint": "CgbJxXyaHeU8VsquBpySuFXA94b6LWXxioZ28wRr8fs9", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HqcxyNzmtoroeAGf1ki5MC2q8mH2vRoxzSETKsRAGPbv", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2t7GM25nSug1sFVhkBQw1k6VZgQBNg3NeQ5nzexXY4xV", - "targetOrders": "4Qdzdw5nRnMp7UMTmiQhF4Gz9UKuX7Mi56PaDTXYyRjt", - "baseVault": "4aYmYpVVjB9hWzsqy68yhuTgCKYmvtRFATzWZeLYdNxT", - "quoteVault": "7PFQm2NsaQofkSMc7vtX815Gqj8yvXPtSzB5SkLCkXGA", - "withdrawQueue": "FnrfZt22MJrsy9Cru5LEKLLXUeXpHNVrJcxyDcJrnpb4", - "lpVault": "8G9AwNdGXtSPuueZ2iJng8uwsbjk2rFGREKCB7gfyoxa", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5mVyYunnpv8ZdRrqNYQaecTrN4mFPK2pZjCvhMnUZiTd", - "marketAuthority": "2AD2Ym55jQ7giRvKGRHtX59LSbSeZRQepgry34QXRj3C", - "marketBaseVault": "4MB82gSFPznoBbc4nsqh7NhQjd5VZdQEj5q6upgnbjiG", - "marketQuoteVault": "GwDV11He8nLVx5zW7RtQ7eYBP1mg87RFgsp8KXz5ATQ9", - "marketBids": "2M63HahWzqGwjNkoVucc8osrBbR4NrVzeeSj2r6UnjKA", - "marketAsks": "3veSmzco8BQiNg6AQRWvuH3Zk2sQEUL7w4hTEC5WrexY", - "marketEventQueue": "53shYceQ37RaRituvSktDQ4m1KPaZ9dq1n9b1r2LLpVt" - }, - { - "id": "KHcipLVD2Ap3yJzHbVGqgjj6zsP7h9oEHaRL6Ehxz1d", - "baseMint": "EkDf4Nt89x4Usnxkj4sGHX7sWxkmmpiBzA4qdDkgEN6b", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HDCduCcicWYrKHn9qnueWEZwu2PLyTxkVgMrtrgGgDBZ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EytYPJ4rDdT6dWAdQRw82iqZgezmpKkHQgxCrZXuUqE6", - "targetOrders": "BJqRGXPUbs2JFQNgZP1GTNZwzSoVJRkERwsDQPYZB3T1", - "baseVault": "Fvsp4gb3Qc4Eea7ZpmF7sEgmigfmPCdJ231xeYCRFm4Q", - "quoteVault": "EPqH3r4wg2KZsDigAJWAeViYskBZ5HWX1gHgHSU3jkWz", - "withdrawQueue": "DX9FwnLfbn7447DEMrCz52kJUKRTNcGbpjCDPMVrgsyT", - "lpVault": "2nnNjrvDKyjq4314tJJ6rNxwg2zo2ymtoDngWe9YUGCa", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HfjS66SzVEqFxAa8nSQnqHA7SnfygWqGTVz6LFS7q4zu", - "marketAuthority": "HZDV63VoYENgHscHAAdg6cBmAZvvnTwe4UWL4qypVRNP", - "marketBaseVault": "H8y7DpJRfCopCmUtwiSJ9hYe6sCqrYtPj5KJT2jCoBy3", - "marketQuoteVault": "E7ATy1iCE9qCC4uqtm7YomYQ7xY8f1dpLmUgjT6mxACu", - "marketBids": "8at1MFCbjWQqKTD1mkUEThshzjuZBPLNgEpSxcTLriNL", - "marketAsks": "EMAJpQAcTd4EUUdzcFeVeFgwunY3wJraAnnHGeeeXj1D", - "marketEventQueue": "2UxK4LEzcwMhtoRdAqHzeYqGW7qPbBfo6srCMqiPkuQ1" - }, - { - "id": "Kit26YqvLQ2sKUyaXm1cXSFFqT3nn6ZCXnu7tLS2g9J", - "baseMint": "9XZR8Y5ZbRAvbCMMzeoSPzj8haAaUBaa9XoFBDHJAy2Z", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9nvST1WuGiYCewoNdom1Afhk66A9nuKUPi4yP64q3XPK", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "GMuDWcbPaCxjLLHuLYbwtwtkz28y32szf8LPx9nxPU4q", - "targetOrders": "AEiipfgfb3kxGsnXaE9BkDrifiMkG12ARkKxY5wCUH5K", - "baseVault": "43ZUeCgQRAhPXnHpeovwzdn8DtE7DAwWXKv7iv3fCDRP", - "quoteVault": "AcVRGUiTzPFyQdeeRPcwY3RJSn1WVbi4xyYgWAWrZEdZ", - "withdrawQueue": "GCnz42hJb6rVDsNpstTNGjpQduvgUhFbhSTmR787pbDB", - "lpVault": "EYd6tAovswkXeJPCYoqE8DpSu1Q2Bs7EYemQLSa6tn2f", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FkLgikNQuWLLvxdnYt9ywbaaD2hp2eiTXCkKr7fAc6iu", - "marketAuthority": "2u5dZFojts4QNrxyD6T9NbtiV3pZEXwX9C8oNLxTVyor", - "marketBaseVault": "2NVh199YaU1jGuhtVPa7CrBxmFFqcwWRM53RAFgGiU3A", - "marketQuoteVault": "HiHRxv4FqVvyXZFYFM85nvAeKcQ3mXRnDQakKPVWv56a", - "marketBids": "5ovL8yeUCviNVZbb6dEnH7iidJMk3GDJGgjpStW1T1hq", - "marketAsks": "6EwifWJgtSRkGnB1jCUPQy4KHgoTxAkkuvD4WDJAirSL", - "marketEventQueue": "vSGfBtwKz7X8MbTyzLkzWmDA66chutW6dmMHfCpWHS6" - }, - { - "id": "mb47q5xZJbZsh2gx95xPCzivtvXHXrDoNpJARPDP8z7", - "baseMint": "CzXF8oUJSsB9ADKV99WAi2TgytqAyKvQw6EihwiL9em4", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "H8BWkkGKpSpZVhuvuCAHBwWGWVrkAq9Dw3EH3okjy8dg", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "67AApaUXS2oxtKT1Y2bzV2YkRCdFkfYkwwzJwg9Fx3kX", - "targetOrders": "5zHQqLecNkh5Bm1yBMd7eQYGN37WEpq9bJdpXTxBfvZM", - "baseVault": "CaFv3tcD26c3jre9kVJaWfHm3ccLcWVbQGPU2ostLLjL", - "quoteVault": "EmEoA96UhGGEVi3HqpHmt78aKw2QFZqF8NCA4RrffKQY", - "withdrawQueue": "93nvy6wND3izJtsgBKUh1stuZiBc73HhUUnTWj3wttPi", - "lpVault": "HWYpfoqCpDUiRdmqCev2sMQEjQtHkh9Ctf7jVmjqds9g", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2HGYdaFBZSZ4FJFMa7tbyEAj2eAZsc3WKavk5m5As5f7", - "marketAuthority": "Do8Af6yzWsMvvbGifzPDEutVYRv8j1qhaM6cNVg8YXaH", - "marketBaseVault": "9GAYk4pas44x49s7LVHWytTmfDWpEsmYKJ9osBcW4Sma", - "marketQuoteVault": "9cnkhfcuZnxvZGyfZHNPEqJeDpd7JhthtVAB5YjxMR6z", - "marketBids": "12quDgCo7rJYyg623hzKxVxdj4AkogJzNs1ZzQDjhQPT", - "marketAsks": "DeSJXTVj6nNjoKopUiRGT58B6BBsJxd6Nxzi8Tse6wyf", - "marketEventQueue": "8aspAcDZ6cFRX4zHnES2MeNrxqMncQ2ATimG9qC6pxUG" - }, - { - "id": "Mt9C6yN6EwzwLhUew4A7i9mz8ohL4bJioh1owMJ7YKD", - "baseMint": "J2beWpqSSoFXzzotd9uWQe9xSHZkszAntjYD7xCdnu1K", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "HEPreeGmJ7PxhDU3uUNiJNTdveJNSsBX1o79pEpgFrQ5", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "AkHcP4gYFxR3rkTV3ehtN8ShqqcnBVNoovfXfmJQXVGL", - "targetOrders": "8reoPKFdiaBmUzmi6f4MMngYwSDA7SLc3qrKpTYvJndn", - "baseVault": "Dn549pbaFJj2ah9cFhkjwbq2ffmstaACuiwsgiJTigdk", - "quoteVault": "Dfr6V63p7TSoGdSHcqRGRFwzCwZTtf8Mex3tFUE8GGfv", - "withdrawQueue": "82gC3wEgqmW2tzHZ9sk9oJxM8PYnFY2d8hSRB8Acf9x4", - "lpVault": "3Z2wXwbQXTgi9ZaqmrwPWFyBax6cz8RhRXkbBaj1ph1Y", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "13aV9Zs4yAmbrsxVSvzGJuDm4b2G9bAN8CQWoXfNn38d", - "marketAuthority": "GLekJnzZB1ysBwA9VHMoL3HxqsQF5ovR4V4nbov5qGS9", - "marketBaseVault": "9Jm97jUnehHH8L8XAExaCXeJQJ9kJrgZs6du6DEZyywi", - "marketQuoteVault": "7or248pNbxWU3S92nLz1S6BPcVegyWFY2ejaJvzVgPSj", - "marketBids": "ByoSV5uh6oKnQo3BrW3edb4apWJ4toSC55UBfxu4uo6j", - "marketAsks": "5SoHgvfNiaBuNRuyUK1XToiRjyfTXzmxV5AfP58Eq7CD", - "marketEventQueue": "2hCT1w6E6ZDxewqho1dGomgm5xBaNUsQpPoSYXExLhrp" - }, - { - "id": "MVygUMULqVXk9wS3arH5pBxWQLXFG5PJxNbn9JKE5Si", - "baseMint": "4k9g62bc6iMRCb1hGaW2v1YjQfMci7hqbSVWKoaePxhF", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "7R9GjPjJ7Z7v3FFsdUamRS1q9sGTdEzmt5hoBF6WF1DF", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EXyGTyk2meD78ihvZCyWw95F6qxjWAT7UWJJ3TpQ31xX", - "targetOrders": "9sN7VifdkjK7LNWV8iapnToSPo4uRrmYPhvYm1ruHpMe", - "baseVault": "8u58onorFprYAFyF5ABFmdHtzv8ZJXkF9Zugqda3i9D7", - "quoteVault": "FNwPYgWCMXULtf5TNaz6Z8XY6u8Lzxr8TcjbeaPfbS8c", - "withdrawQueue": "6x5hotCyek2kcftZDmQar9sGCJm1NwYZWaVZT8XT3ewz", - "lpVault": "83imV9NcTMT6gkNX25UmLBTcWEgDNELnG4pSdRXJhrZL", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HmABTyBGvuueD1dzkCvXRDiLBmUtR6ociTMu248bQEX3", - "marketAuthority": "AQ1yDnjQghdMUnZQMV8dryZrrCegC3qWg4xUKHDhmk2u", - "marketBaseVault": "D2W9EAdSBtnhLeqZLFJP5ZV9bkDwXSGfS7PJkKqsoeAq", - "marketQuoteVault": "ETNtWwZk1YASTHM8Rt4HCddvZ8sK1jKNXQTm5G2RrMKk", - "marketBids": "D2d6vTdkVomHwxqkJkE8BHHEQmQCYBDLo8rC1Go1M3nt", - "marketAsks": "4MoewXreYvZdEQX5YpCHiW8fo21HK7ramm7HqRYPMkV1", - "marketEventQueue": "GsdHx5Uwm64S18zuPUwEG2XSHKnVBuik5FEHfpngQUEW" - }, - { - "id": "mZgTWFLxZNbzmEb86SkpomQeEFXxgnKPvmdvhYCq3UJ", - "baseMint": "CREAMpdDimXxj2zTCwP5wMEtba4NYaKCrTBEQTSKtqHe", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FNgZemzXiHRAaBGL6QSgGrG3nUmvAceFGSfTpMWNr2nL", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "3u99pV5xfaCLGrqqpdABR6qia5TPLKhvecGaxenB84XC", - "targetOrders": "AWUzaBREmdxk6wXXsb9muhnvYggZPVpDaEto3eWhkgRs", - "baseVault": "GTkBhXajMzLzhTKci9DwcmqxGzEBCfemywCKAjb7S4ab", - "quoteVault": "3t73W6kuVnhM6DpBetQHcn9PQyqr7KxdQRjc93qmZ7UX", - "withdrawQueue": "E1DufTx137XowUZA3JWuPzne1n1G9Mr7Xpw4Z2vm7bF6", - "lpVault": "Cf9NSeesP4jmQq7Hg9nsKPRFPoGWEb9W9TydTkA3LXNm", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "BxTfmxEQf6FQ6F1cQ3fi6o6FPG52hiZXi4DTGYRhsmPo", - "marketAuthority": "EnbrjMVhBEWjGJYTaniDEihMRSMyQbs7me7aFyYDiuS3", - "marketBaseVault": "dMUpkoSauUsZtgQ95tKTxX8H9pWnK6SsLjQnKMcdobB", - "marketQuoteVault": "ERh9AaNCBdeGfDmQJEQEksLMqSm6JLsk4YBpw5z2QU6v", - "marketBids": "KMHVuSbPdSaV4pFuYQ5k26k4RU4YBtmQKDmhCYdbWPa", - "marketAsks": "2u3m64b4DcdTML2L2fLQRPU75xWtfyHKytJ4qvH6BfTf", - "marketEventQueue": "DyHVBp9mUJDRZDt7jQRGNP5u358SKnU43xzb986KQYyQ" - }, - { - "id": "Ne4zL5jDyNz4613uhAkQoK6jSbUGD4jZw2fzdwpzs6j", - "baseMint": "7WVMpKPcpDp6ezRp5uw4R1MZchQkDuFGaudCa87MA1aR", - "quoteMint": "2nkxLptGxQCfaar541Cr87G4v6VuA6BvVWqxsHNVCYoA", - "lpMint": "G54x5tuRV12WyNkSjfNnq3jyzfcPF9EgB8c9jTzsQKVW", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "CWK5hkSyByNW6ACVfmdssosFgTvExv5FoKjhD64PbnqJ", - "targetOrders": "HThqkKoWW4yho7ZXmxpyW2kLEaFJsZDor5gUMWb4voP1", - "baseVault": "D7QqpDcM6ccqySAf5xxCQf9F7eXnQakyYtNvgpcwdPG5", - "quoteVault": "4USiN6ob8uxRGM2fCvenRtY8JdTACDx1qGCWvv8EMRgq", - "withdrawQueue": "7J15us73DVwDQz1V5xpxDNNK6fzDjpMXcuVDpwvbMncE", - "lpVault": "7fABckeXvFaDxeRE3G2imuDXwd4MJgw1PfRSV539KgHC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "LR1hgnQShE9fWvQ5LC6CA49UjhAnw4YppzmZZkriDQq", - "marketAuthority": "5aHDBzUoE1CsD8jUCxdRF8sa4Yc81ht6aYDdmqvDd44W", - "marketBaseVault": "JArSf7Sm3m6EAYxGLr2xXLnmDeT5nLcU77zd2Z5aQn6B", - "marketQuoteVault": "6NbhQ5Maup1M9aNYJFhvmae72jbPNWB2GMJpMLhTXYUg", - "marketBids": "C9eeLXmKD7yhtPVcQ5Mi8UGiWs7sAxWjjbdgRBx871rb", - "marketAsks": "BEKf824RPPjv8UA7CqkPjqquvGSu6uJk73cMPBQLMczv", - "marketEventQueue": "E9pif7XWKcJsu1CtYMpW7b6aSvHd3Rm96d2st2MncR6T" - }, - { - "id": "NMMBmzbCQBd7iBVjyBKXyZU9qFTWaZPzwijMTTeqtDy", - "baseMint": "7PEAhnmE6a5Y2DW5Ysko27rS1TXbZQomfwHtk4pBv58X", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "Hc2AHMEzqieCUZZorjdJ7PTRE6QdpFJWvPhSDZshW1Ng", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "9rS4FZzhaGf4NZhkjHncidh7oyfp62bQXe3rTzxz4bwT", - "targetOrders": "6K2XLgSCRraGxfW9HT8UC9LJLY8aKsVqYEeoNSiz3YY1", - "baseVault": "2oD7Rkjh8Gg9xpfQhAvA7kzHfULAwQR9vtYz7GK4T9h1", - "quoteVault": "5nuEjPeMhVW7WiGS34u4Ncuh27o3juTunQZ7f6EpuhVe", - "withdrawQueue": "9qZgUzBUHTPASDySAvZbtvkwD5aXpynDSxBJgT62ZSve", - "lpVault": "2ESAcQq4FYTNJPByPgxmEqjFKkBbUChhjnAFgLticDd5", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "7S47PR3smZ3hG3UvZKZDyznWajEApf5HMS3merXkrGAu", - "marketAuthority": "5xHbXrCMXtDJV6bUtpsS4zB5huUHMdW3tQ4xaF1fMtU", - "marketBaseVault": "7LB9nmqJC8p5t1MvYgHgbZ8GWpYc9NPqjtJP4mStAnJc", - "marketQuoteVault": "GgBnmcoSiRiJumohaMSC5Dm7kYLoebwYQmQRRjRRRA1T", - "marketBids": "8iRh3B926QcuFygkmYUR5iPgvQzMeKt5uciC7v2QjB5E", - "marketAsks": "4FxjFWkQ7W5hdwNU5Eu1JCgK9HnkhbnjfxD5KM3Gj5ZA", - "marketEventQueue": "2b3AFEf99KzqGMaDmFx7A6kptX7GFaiGEukhb9zaeKpx" - }, - { - "id": "NY3c5TkwfSC3eV9cAykCHid1npu9JQw3vKpWPK4euct", - "baseMint": "FADvkbzT3JY1gFqQRoaMyipfy6GvpVhbVfn3q3om7ZVG", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "EoAFw3cApCVa55sGDxhR5gA9qzCP6j6Mjthxwk9NCuvh", - "baseDecimals": 6, - "quoteDecimals": 9, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4PqBEY5G5kMctHJuNk2QEBxVRCRWSSDCDhkP1EPbDVTg", - "targetOrders": "2PcxZNdedPy13da57VEkNDTEWSedtMTJGPAw9D7P2Fri", - "baseVault": "5SuwoBBf99J2Qja17o6NbbxtAKNwSujC9fd38RnsgEGE", - "quoteVault": "7VJEFL2k54mVPzJjKax1tx1qcwNxwJWSD5hUtuy9Zw2b", - "withdrawQueue": "BQqy8FHiYdTAZJiNhtxxRTbjLiCcZD232xpyedxoFNqq", - "lpVault": "BEpUSEBNats5pbjDmKCEu3qD6TqtsJU8aGdizxM1wDRa", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CSXMm4CnPsAdeAHWN5x19h6WSgUJujfdKM3YdgHGCjXu", - "marketAuthority": "AsDeyB4GZoDLTAcabPZ6Z5V2wk9BytudSd3xNobPjLDq", - "marketBaseVault": "B8hAcK2EiKM6cpRAeGDLJyTzt64vLfm2zM1xTASavBhc", - "marketQuoteVault": "5ZkMRRRFp6meyJLxk1EsmK8RWB2vsWyTGtNQ1HKADFgx", - "marketBids": "gL7AS8Sor55k4jiHWW1qrYv4nrHDb6ycYSwr9PkGfr3", - "marketAsks": "DPpiQ2CVTxrfn6bNZnmsLMbV2GNaUtG3wJRywrabG92J", - "marketEventQueue": "G5mS6SnfvTPegqGeeRMfVUbSzgKQkyQUBiQNWT4T4bDs" - }, - { - "id": "oSDvWwRGCENWB1QneGZkpfRf93qSEWnHLse8fCJc1Qb", - "baseMint": "9fzQfEM5aq1GLugzHMM6prq8tsURN2pxQMjARaWGd2py", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "Ab6AnoxKmk5UBektQKYjMGz8EEfvMSphxJkyGGUeHL2L", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2AWX41YiCrUE21d1TJW3iFdFbR4AH8YKR6qG9qSHuobk", - "targetOrders": "6bJTfxyPfH5QarYGnC4N7yk2ikDpfjZns4nKTea4yxsL", - "baseVault": "Gi6GioppZLXqZoCD8K4RaNokZHcdVTVWyK1UdqazNefd", - "quoteVault": "AJRr5knhtZTk6DHbEatyX2a2Msr8XJ1bysKXsXzsfGk7", - "withdrawQueue": "CDcJJjQEucG48Ti4FXSuxZNUeYEFcQzehcGerXyUTMh5", - "lpVault": "BHDUKZ6gJ1c5BhjkfcEjCdzuk4DqZdHoAvBALPT7pmdV", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "C58sdvnCY1DjTrxm3ypdTwfmLwbmzuTFPpZ45fkTKd3Q", - "marketAuthority": "Hv2KcjdKjUg9LG49dUTatHfkA5NpkRcakHQhtp847bzD", - "marketBaseVault": "HBRQggaNApo61x27pEEGj5khCjvPD88uUQTeVeYD9z8N", - "marketQuoteVault": "FJwiCycLYj7VxgnkpiU9zvaSovkQRYQ8SCzswbZrUX6s", - "marketBids": "6mWtSBbwQJGNN85Gp66GP6Zu8nPugztvEGdnsH7NXsZy", - "marketAsks": "9TXMnxCGMHG4RyYqYBg9hm3TdKi9yF65eTwWko5pdJeb", - "marketEventQueue": "34zrfRQbsJzic4mnUzbuz9XZfmvLUhM2eGPTdfMV7Cg6" - }, - { - "id": "QT5fYCsg8Sy9BiG2r4pYmC7B4C61ggjsKLfURoY7dbB", - "baseMint": "2YLWDqGjhm2k6gbunqiQgzZ7iaHuMACpFV7Jb3o8NtUn", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "AKABeU8C9iM6PAbPGVSViAn1h4ELU5r3asiuS35EWVHi", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EXnsTUrB6y9dRrJvLjTqSRe6Kck98EZB7DgXkDvMmgus", - "targetOrders": "BXyW5bcHe4wZ82m1BHiUJkHFxvqHGb7uZye3Aryrweu5", - "baseVault": "3Amp2jke4tN3eNTbKoWNEDghcofwMpf4AzYFP3dcvdZ1", - "quoteVault": "62oJ7N53CfvqtuDxsciqrREKoFPYtpXtKhCoR6cdZmsE", - "withdrawQueue": "A7zy6vHEz6cHmZ3wiYSZ26NhCKRzJAa2ibBw5SvsqMTg", - "lpVault": "HexDczXj8PN9VXCtbR8FVWBRF5y25sznFfUHyRMb2N8z", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8EHKvJraqLdo9ea4Dd43gfGX8FiTeHdPyPqbg5xtCLeR", - "marketAuthority": "8BvgcKCwY6NMkdERtqhP75mjJBWLQzBTpsCm5QVwE5vj", - "marketBaseVault": "HooEfak459ez5SVer4WmfbKhgX2miP9uB1FVa3aLsVnH", - "marketQuoteVault": "FqrCUTEZEFyoizr267m88u6sDX2JJ7Ayzy2vKfY6bhpR", - "marketBids": "FQfFk7Y3Jaz1BSLSY9pnhPWdAypre9rzyPPuaMFkWu4G", - "marketAsks": "6C2FNE4gjzjP81YjzBnSxENA59am86qzwRVmYUNuf9yi", - "marketEventQueue": "AMWvzNdV3pkSxQoRAovcXVjVs7Q8NpnGfJRvyegt6tLf" - }, - { - "id": "R3NwCur94ZS1qQNV2SMSSs9gQqbD67NujwFXE77mSoU", - "baseMint": "2jw1uFmc1hhfJH3EqGhaE2rfZMMC2YBpxkZcdUbPppMn", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2TnEPHEarBGnH4GV2rBqVJaFkFGpvHhjqX2MZP1TdetZ", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "bo7rLDztYKqo2fWZW89tc51ENk87jGBayb8vKvsaDwd", - "targetOrders": "6Cbjtuc9Hh6Y5ivVFtyDkP2zcGrfwye3KPZP4KUquP9U", - "baseVault": "AqK84CjZCdVXTLpTYkD5PH8Bc84sNFFkkATyFwnJu4Vg", - "quoteVault": "G31Lb5REW8J385iytD6jC1SWvRRYz8xhwKb1868eTdrK", - "withdrawQueue": "DEUNkNG8si2fGCxLnLoPSc631ocn4nrYbvFDHtJTvFxF", - "lpVault": "6Y7XpeELfJySuBqisJhUy2npprZcZzRfA2dXVngmpiAa", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "HW8cnhkB7WiF8A6d9jy6hx1ajmcrUrQP82yZm1d4ZC3a", - "marketAuthority": "383kY85oxC4VE8N1YrrpqCvRrBDBhbqqjsH4Caz1dKZv", - "marketBaseVault": "B1tq2NnWTMLyZ81s3me9EkMNjehdzw855ENaL9BTUQxx", - "marketQuoteVault": "F5XWN1gpPm3fFFzhCie5G5P86Ab8k7BFPEGCz5dWrnMz", - "marketBids": "8VrGqqG8UgLk4AATjcaMdFqEt9ioniPfqutELSXASwsx", - "marketAsks": "A5zxfW4y3W3Gwf8pWrinjF2fY4NGnNEJidMJXQDZ8a1T", - "marketEventQueue": "A81Z9hGtQTqYdPKQepAGDKc9rzftreVEsCxwFEQaKovg" - }, - { - "id": "rdtaAMno2UmPjDNnTW4VqPbx91PPnFL29eQ6DECNLdw", - "baseMint": "DqxzPWQ2FKHn8pRoy9jCpA6M3GkEqYfieiAVwMYWVyXr", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FeLPZdsP27t1RG9keR4de1ecqViTwGBpLFqytJxN6rH", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ESuLRUtsLHtuCnPptNfxK3Rgdqx6DR5qweb18VNuTLB6", - "targetOrders": "FZC1EkZMcVMzYzNUiH1CMTcKaRbBgeXrS6jXMyf6cQxs", - "baseVault": "97Y7UJ2wWhHhn62Za3mtzDxnvLB34BaBGhqxPjr1Toho", - "quoteVault": "B1Yu7YJqNqWNqBWsC77yDxq8QC5fqjjRF4gxK2JWJ8fu", - "withdrawQueue": "AyLzpZgmgRhPy2NdbmNyBRpv8W7HGic7f69MGFAqManL", - "lpVault": "Bvst4rb59qirpvKsQrSSV11kAdeF16gsF6TEQ2HVvXGH", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AY22bWZUi6HgLjNafrEPNFLBthgGEAHWXH8wiiVhycDh", - "marketAuthority": "5wRTJpYVzFKiJi3K34JMKXmKVhUQuBBrSA2dcWm8cSo", - "marketBaseVault": "95FhAD2K5GSLXkPPF4TTtFU8VC33yaDg6Sv9snbySbYT", - "marketQuoteVault": "AttaCABrXM7rNJS8J6By2ZfbJsYsrgtZR8myEYqBt556", - "marketBids": "3SxEM1fDVs7QsdLkKRUaqCNJW3FyEMuivYDiBJWmxVvx", - "marketAsks": "Doz3VNPyPChAgukMaeyCASZ1DzrLgwZYpNch7JdKsPjk", - "marketEventQueue": "8bLZeJE9Hub4M9Mo8XenCQmBnFebqM4dJjEZKhw7ucTq" - }, - { - "id": "rKAd8xm3nisauXw8TwXm6hzE83L9xBPbJjHYr2TbH2v", - "baseMint": "FZxUbyQ9oeFiSDaabw8KfAWACsDMQhbuxR9vm2Rh7Ewm", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2uXnq84UDg9Dn8pAmM1Keah4bHpHbKW3PvFc5fWPcokG", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "7caZfG23TT8LC4VU6qx4FrccygYKatUPRiazdQeVg4Jt", - "targetOrders": "2SwwA16rnkokrHug9BJhQ68bavbRWhkvhyEWsB4pL6sB", - "baseVault": "BKFhAJm2eeemNh4YQnF1wwpEd2Tt8cnp3somUgevbTF8", - "quoteVault": "3KTQFJ55zdfsDJ3KGvf42yScAcshp9Np5ZSk13ZSPosj", - "withdrawQueue": "F1CUauWQKJf6HfrYDgaD5y4n4ME9ZebjJc3JsgVwCFr9", - "lpVault": "koXb38755ALkg4bncF1ZsvrnSf7tPyYEg9yojtSFRi6", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2YqCaodHzKRwJ6pyS2boVVmrSmDXceyGPspLhXwjEUUb", - "marketAuthority": "E49J9TP1xY8Yi3y5RjXcqzatwdAtcuR5DgbZ5iZTUHca", - "marketBaseVault": "2qCZ1MgztZRpEF3hBvTy7sCvcD91WLGmav2k2iLDy1it", - "marketQuoteVault": "3mYhJ9vZSPiUfrHDDc1e8tsuNbrHtSfhW9M14ye48LqW", - "marketBids": "J2zecjtqNF5QkyhUa9cHRDUbKwk77hE5QFX5deFqBV1y", - "marketAsks": "AjfoWFEoZcycjvoznr15uoGxQvaVwegxoqN7tZaecEQ9", - "marketEventQueue": "4E9a3RruEebu9QJEki71pFVPdbwh6JbtUVg9kWRYfyCt" - }, - { - "id": "s8DhQbd3B9DPsQ5HuF8yxsrA4pkYHhDEe6dPXsq6s17", - "baseMint": "E6oCGvmSYW7qhy7oeDfiNZLX6hEmPCVxBC8AknwAj82B", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "HMMtkf1CFKvtc9onbTpSjd8bjbXRhXRzknYqdybWvgeZ", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FuVTRbAmUnD7QitQJfLCQL2MxiWGFhBpEaMLLCVwe7Y5", - "targetOrders": "CYe92qb5yoxQxhpQDdTpLzjRCNNbBz74pdYkXPKtXuWA", - "baseVault": "5fZ6fbqbHNyby1BrebPfxHR8brf7zpqH34zCaPGou8Rs", - "quoteVault": "6pKeyh9Bq6frpkppDqtiUZAGKT69VMF9MtUUYk2U7DD4", - "withdrawQueue": "DuP8oy6k6mR7jQ65aR4AcmADFBzrLtm2RgHpTyXXn4hB", - "lpVault": "GNqWZihY5xGzBZgpr2MFpsXn3nAHB1evtafc2mUuWYWc", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "J1WBuYH5qAj5vuVedmwRPAVcm9ydZobfJdvVyPbihv9k", - "marketAuthority": "DCm5jhdPHo45u8eiRnZwmS6NzUJRHEBP2CFnncXsA1j3", - "marketBaseVault": "Ch1kpF2UpJq3Pbs7BJDg9qwRu4c4QarpZeimckXAtQPk", - "marketQuoteVault": "4SwpoyNuexz4EnCY68punywDMM2yw1PM5XkgCqJbEKqw", - "marketBids": "2UcmKSMhKQWA3Z6jyaVVtJ3wzMsjC6tw2XawswKHzSfE", - "marketAsks": "FVVoaSB1NQdtao3XZyHLXFnEFVwbcmpWBx9BfU5d4gPn", - "marketEventQueue": "3qCzsaFoaMYVHCnLz9wsQgAcZfAUxDVEx1kWz13ZRetw" - }, - { - "id": "SA1hVeLck8hYNRUrcXQXBY96NWCVDbPaJDQQd4EZ62Y", - "baseMint": "8Wmonq7dhFJXuHqFCcVgWTmmUPCBC4C6J5xbB5HhGb6n", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "F2wzyDdkLde5pxw86vUG7zXTxMPS8oYRhuY219TchdcC", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "C8zAS7FNxaHG16fcPsFnZYqQnES5yBb6Hk23vX26ArVw", - "targetOrders": "EKK3doos88ga2WaXmfTLx6DNEJELxsqBLJWac7hCeopq", - "baseVault": "7zxZKe8Ncs66FevMhT1jp3mjSST4QDHHf8QTgHkqJLx", - "quoteVault": "BQJSdg8pqY3MJJvHgyMjzzSZhLi2SK15Z9zuQyLJPEj4", - "withdrawQueue": "GPzTPMXqkuzny4TgfaPiDmw3gBGQ5sQh7zhsQiqwgqki", - "lpVault": "4Ga4MG6rJFdAhXiKNVZGBkp1h9PSqDZUuUkGPJxNntbP", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2UpuTQXrtbPwNSn8e4oXCvdVXqjGuRjvUmosq7iyBCFx", - "marketAuthority": "2zGzk9AaiDVHSAZ69ad3BYaZt1oLoRmwB7cNZFfDoAsu", - "marketBaseVault": "8jaHyEmTDw9Stgnzq5CpEFeUNAnfbBKaTmTqVcMcNNCx", - "marketQuoteVault": "Eosaz92ShdW3zZLb7YwWe6v66XaDNzdKUgV8TcG8FGBb", - "marketBids": "5sWL5zBGbrZzS8k2isJEQqZc8px1k4X38DmCcsJwiWep", - "marketAsks": "FqgP7EG9Jh32EkJaxYWq4hUxH8BK8cdY6pEYFAiTaNWz", - "marketEventQueue": "7nCa16ZZP9q3TFCZ2mgPYWqBB2pFpkJf6RYUZiPC5uoD" - }, - { - "id": "SM9q4wLvJcNcNWH7hRqWaxBcac5s2w3d7s81ery75Xx", - "baseMint": "8XkS7ZDPR9zXcNcYR884tBScnQRyFcWRb7WcLtCR6zEZ", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "96Eh1M2rwPakcZfnmJzfNcn2fKYUuwFqtRYUmYXDmZQb", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8m3KdRhUAPcJ1sBzKgn99qgohBpEMScwnbcVyWFoRHEW", - "targetOrders": "A2HNr3JTFDiwgeKhsFJ1fXDBEJNnQWHLRq7ZaeQWvngV", - "baseVault": "EEveHvk9Tb8UJrhKHP9b9AQKEykmPbL8cD363nkfZMNt", - "quoteVault": "7QiNXBtBZVJfURxE1gqmihkVEz6sXkHXuuCWkxCwzora", - "withdrawQueue": "DN3pdRXsjBsrRGxStPTZERwjk2ZHTRy8d4aZhK2BL4iM", - "lpVault": "fd3VBeuy96jMB9wa3Vsb6uW4z8zawq6vADUaB7ov4fa", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FtDSgANjvUu8vz9E7HvVjvXkg8QKHXv8nGrEmXRy58HS", - "marketAuthority": "HMaHVan5xEJ5LbcX6VW216dGRTFD2SS5B2PueahkRCFr", - "marketBaseVault": "BFaVzxhrTbcmQiCqTkGpMan1essjn9ihMvTVsV3W2Y3z", - "marketQuoteVault": "9Ngq4FcYzY2xEP6v8vGE5hB643c4eBQmf96VXiZBkaxv", - "marketBids": "5peepLczsZowyAn53HfjJTM2sVgvDu7nPX2TwMx5nZcA", - "marketAsks": "4d7zai1XyrNVRmtCxSdNSUtyFhHrZ371eo4cfBf7iPv9", - "marketEventQueue": "22cfNGJsFdzmSvpSvkaWeFpfX13F78HdKj5uZJBF3WE7" - }, - { - "id": "SP48bcmsZzydCdVJMdkSWRrHnjBAgv1L1gYUoHRw9ES", - "baseMint": "8Sc16a55YzSKpPTUN4VJEfcKU5aXSk22WyCEsr1MfdCf", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "Cid838jC21AEond7kHgNTGRbErxh1YDvZbcvZbstR8vj", - "baseDecimals": 0, - "quoteDecimals": 9, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HNgzhbutRNGMyWFg1ubzhkPpcCLpfp4AFacQ4729x6bn", - "targetOrders": "9rh29znJn3iYqA1ghgsq4BwLw1Wp63XSd1opdzH3XWyh", - "baseVault": "C4wD5MHwC72H2uHkrNoh8bgiVgj6Ar3Pe994m35ZoaBj", - "quoteVault": "7kFq28EzJ3fTksnG3r15mXgJkqpCHSQeC9kwgA7R5o1D", - "withdrawQueue": "CZqefb5jkdn7LvRmBekFJSHGhdN5SBteY8xuYcubYNdX", - "lpVault": "8FTrxPDS5gNmdLyWKqSZWuCSZwBHhiwu2JAhuRm3jL2j", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8oMEfa3wAgCi5ch3VHAk6GWD5qRyynp4hDcUY4MMNQVx", - "marketAuthority": "6mk86T8uZsFtAY92WWDmJhW67Chs9qJXXKcRZh2KSmaW", - "marketBaseVault": "6RvKSJbxnHUzPq8gm2usvVCNQ9kJG8mqXWmCbTMhxwWA", - "marketQuoteVault": "ABa4hAgGJhhAjh7xgfgPPoG5sGqya5YGdWp8chYK9J4i", - "marketBids": "iEGBKCqhL2qj7mEG4cEMdeMmmLh88aQzSeMK6hHSmMZ", - "marketAsks": "E7B2Ynt6So7VCjWVZucALvFKi7qhVieQQrQSWfVXY3zc", - "marketEventQueue": "FiPp3KHX7ai7TfRts6riRFiRhoH1Wf3SPKtj2GCC3fjY" - }, - { - "id": "syNSyUTeJf8rohN5LRZkcka4Jh78eQHwoDDrZxaYdzd", - "baseMint": "DUSTawucrTsGU8hcqRdHDCbuYhCPADMLM2VcCb8VnFnQ", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "BJttaKsmrAQU1ohkppAdmzWCZe6NERk9Ncc2Gmob6tP4", - "baseDecimals": 9, - "quoteDecimals": 9, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FRPR2nXwifKZoBpDupxnD8m29G72qi32Adyytq9gGNXT", - "targetOrders": "FTKipGxYThu1CtghNodM2g7rtLbh4n1D92peT96i3sUd", - "baseVault": "823yDgBfDqVtMQn33xqsDqADtqsNZibThd7QFE96gbbi", - "quoteVault": "45Z629voh31VufjhAMDrhRtLhptkF3eFTxp2tkJQVfJr", - "withdrawQueue": "6QAU9UYcfrZbC53vvY7B2kucZmmghvkmcUuVu7YGuC33", - "lpVault": "HkFQgm1A84zXSphsZaSJ8rJnWcpUMM3FQ7voNyjbDQsZ", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8WCzJpSNcLUYXPYeUDAXpH4hgqxFJpkYkVT6GJDSpcGx", - "marketAuthority": "DnqbDv7GaXm2Stgyp5ZT6DihfqooZr3U9egxz4PEZf8j", - "marketBaseVault": "CsKbxMcVNkPEAET2x1xkHrUWVpBotzgg86U58p1kTiVN", - "marketQuoteVault": "GvACEG6eDdv9TMJ2977o15b6pdp3PdgceQ5tVdAsxh2s", - "marketBids": "K7VgFjXCUpxGASxa9xj2L6JYVxM8uaXXe3CzfHrcQHm", - "marketAsks": "J2Ck3TZZ4ZKotaY825sd9nd5RMMiwkdP1kD1yWNo67rE", - "marketEventQueue": "EyC6cjuB7bqy2DaB3SCJTE4V1Yurz3nFiJbj2ms5cXp7" - }, - { - "id": "t7JeTSyLZzC1nkPQn3jTP6mq3YJjBz1zSJDMTGNoxy4", - "baseMint": "FatneQg39zhrG6XdwYb8fzM4VgybpgqjisJYESSBD7FV", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "2uehCEFJ1JihAup7JsC3iyq6twKtVSXY1PGfmqigDAyw", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FjBtjY6cEKihijgPobrRpyuBzgMzrjAXka9pmmuR3xCy", - "targetOrders": "EKaAmyoqDTNXeu5Trytzcc3JbyiU9dES1Ug1XEpPmbvA", - "baseVault": "6w3T3V8AH936UNT6mbnWwXwafywSB1GQLDkKGuv5Qapj", - "quoteVault": "FNLgJvcVb5QPe7DmpbAThj5KunyYeAnbekPyUXNSrKmf", - "withdrawQueue": "DiH8tYeBRgVgALBJgEn4FMK2ZmPHtdwUTG6fbkRqB3MH", - "lpVault": "DUkL4pe5vmGw2UQmgYeBdPk4CabWgigVdbEe36EzZLRK", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "AMDRYr6QHHkM3ju9JgnDLEeGwwb1nnR3hVvipaRF5Jrf", - "marketAuthority": "AoCC3UwgkqsnjTWJn2tKv3Ggp3ZGE7Ft1fN1PXCTUCVE", - "marketBaseVault": "67addxBamAHDKfaGzGZ2fUtX5d8xb9MhTytwf1P46SsB", - "marketQuoteVault": "7eYaZJcsr6RAdoqnHo7m4saeaba71tB5UfrCaiFUqqDv", - "marketBids": "Fqq3iYeTP5MQs9RqJdWeGc7SkGqKwvCkqdnEMd8Z1Frn", - "marketAsks": "2EdiJQbtwq3hTrwVugmG4EbF25dBf4er4nwCKThQLies", - "marketEventQueue": "9Bp2pefkGCG7YqGmtZJ8vc4N2Wwx1z7EKDVp1AVQZpP7" - }, - { - "id": "tCNpqaqZCvqmCtNi7c7LDa6inm4BYuFanv6vXxiqrVJ", - "baseMint": "Ax9MbdUbr7cPQhkipXnBh2QNDSzf245Sn4xKfQUDuJGD", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DS4phgdCcZByzLHiSpXQpSXeUWDwNxFoFw14dTuuf5ou", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "Fddb1cZHQfwNzKSQSHZUjx1Kb8cfRSf94sLk8i5GWmy7", - "targetOrders": "3yfckBk7H3fwmkSzEWGHCunzE3SSYJdfu8Rv4Bor6SJJ", - "baseVault": "3KkiH3HKznAkDaQMycULib3zt3DoipgDtRZ9cmWM8sb9", - "quoteVault": "8rUzXSaYrBSuU3Z1vE1BXcBYaTgunjb8KgL22TRdZESy", - "withdrawQueue": "BQRiHTj8RVWUGpWTsdVWWUaYU7Nkk7y9qgixQ2NyseLe", - "lpVault": "Ah7agZNmz8qzMTZwZVm15rFsFBUoVdsy6P26Lxb2bEmr", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "52kSHSFktf7WrxvDXtcjhD9S9124LGL3PZiigf275N5i", - "marketAuthority": "QVV6kNDK5vvYmVoD1JJUjtvpawH8mdG6kdVWvH39moS", - "marketBaseVault": "9aspoVJ4bHXs25mgzZLhgkticssVqCD5npPHJUpoR4wg", - "marketQuoteVault": "BGFu1oswRWSzEfsFLQX71Y5XMWVXtDQyTnfWVb4YkdHs", - "marketBids": "35hRH9Vpu44cPyxaHgZQdFeTPG1F5c33jBSGFGTtUa37", - "marketAsks": "7orHs3uq5Doo8D4Vg4XtP3UxYxS7W4nrsm96CGAG5DjA", - "marketEventQueue": "GBV8QGkCs1UmWzboeKLmnz2tBRRFk2LpWUkHyhHGkmdP" - }, - { - "id": "tGGSSPge6L8jZ1J6YWipPpjkjtcfEAtewxv2T63pSCg", - "baseMint": "5G9Z8LJZSFxG4HYdRB6SQqxuTePPw2sSyTJfCX4pggd7", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3QUVAgDu3ruy1fJxiD3GBFoxvVbfoxo7yju1dZjZH2Uu", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EyAdWixRwspyHyiSV58XviuqdVexa5fx8WH3i2EAoCz5", - "targetOrders": "75VpKrRs5sUo37QbzPzpMPkqWvPfNtkEoZY8U3SdYTi6", - "baseVault": "DwaTktfKudumLZzdR8v6zGsUNk9YZyCthn9R3NK4oS7y", - "quoteVault": "8i5q6kexRie6sfdZ6xMyB5ryUXLoFBE7MJqea7364upM", - "withdrawQueue": "952Mz2fmvViNohDNZA4FjW34wZpZ5qH11t6o1Zx9bYRr", - "lpVault": "Gsd3yZSPGYhuQVyioxG5xZZncM8grrLvHM9JK76uCDVN", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "E6zaqQPYLAiDGm4hoP5BqEVB7eykoYiwuMkGzBFsUJFY", - "marketAuthority": "HGrETYnKeXo3MpJdLaeGLTpDt4z6fcZS8KbtS5p7GbvQ", - "marketBaseVault": "EhdEMhU3Xq8EBhuYwmMoBfXa8JXRYvxHtxkXZD9TJDGK", - "marketQuoteVault": "7B2bRpo2fuHcr8jpbASPF4DHCCQbi19CJZDyNXkXmN8c", - "marketBids": "BT8tpF7JWJ5khbh5CnaJfCwuDcyLUvwSG36joYyg2m2f", - "marketAsks": "DBYigcNRRes4KFAfrVAvMo2oeHsvzBZnWMg9m8YZbbqF", - "marketEventQueue": "C2dYb92J9DxJD1hfkC5gmVfg72WbhFvP8eArprRMC6CL" - }, - { - "id": "UfBZ6qGGJhaRNQwToz1bGb7u4scdekKAmAgG2DhCBLm", - "baseMint": "3qvg2hSA4NHhe73Xv6rUuhFoGM77VBvZrmE4tWSHMQWe", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FNFHAwpxTiYMErvVdG3isZFi4edff96LBp2GHoUqpyfU", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8KXa1HHaLxDScs8V6GuYFKqXVAA6PhXRD2qrX2eogrkD", - "targetOrders": "5eGynFt3Y7VEvKf4WHm55yh2SZWdadHcAaumwSKZwRQc", - "baseVault": "GWH3SmjZ9Kkc8vcyXhwYvi1JfTu5Ktz67jjMtZk6vDPJ", - "quoteVault": "VZu7ms36TvGRtF1gEWL2KctGkZK5uTBxuzc5rnLaNzT", - "withdrawQueue": "7WLFh4Xfmt2UTsJR3tRKmEcDyH1cYm2XcbBidZNsH11F", - "lpVault": "HZr3cac3Terfc5ZZteCy9X8TdYxBkM8hCN5h8DaFk5Mh", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "CBKk7V2AkGk6ZnozQhM8HkneESxxoH1hLmjRWXHQq5t6", - "marketAuthority": "8BuNhvx689USYo9qRBv49xtTmriSEwjYFLqimSUVph2h", - "marketBaseVault": "Buww8iUUVpTHyzsT9jwXRfrDEnYjxKHkpwCPYAhjTypn", - "marketQuoteVault": "9x3DXAgv9LxrfH7x5rrtYL6HYxJH5sW6JSUcS87wp2Dn", - "marketBids": "H3Q1G7ymTgFh8PLy3xXDXL16eSiHqyECXwUa8SBpc1dE", - "marketAsks": "AhZSE3gutwYwhApFxWAFBnAjxLD7wy52VSnjvKcCuhU", - "marketEventQueue": "GQdd2NdbZjcyEkSNHXpk1JgKgb2KxMZ1mGem6L3KJSZt" - }, - { - "id": "uizgy4v5PLvnYB9Qzb5CR2vJXoPqkPgTXKQA3CGrrFg", - "baseMint": "9VH6kTELjTFd1RunKZJsCvtzAVLTTsb44kQzWywixLbX", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "DxeWk7712MEWkbyJk8VBSEQxiKcdynET9t4hxzP3Bq5v", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "J5Y6tFYCTW4DC8rAVhAvBrpxAagQAf8f9qxue9PvsdTs", - "targetOrders": "6rWZ3ky6s7wPyeGWLNtR6YzK8NqT9EAnFnbyLK3585B", - "baseVault": "5MJNSnsSjLEeTLn8qrocDfBYC7QPZVU54oNQQurVE74i", - "quoteVault": "3m7HuPfsepYf13bt2V15bMP4x8b3EqgMh31shpWAutFb", - "withdrawQueue": "AK2M8LnkVvwrYie689xZkcCW5igbzSwfq6dbvyHAY3Ww", - "lpVault": "AaVoAXrLZLnRoDppCQMi6o2kjfP8eJ4w9jnHmvrN22cg", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "2B6CxvMS91eNyQ1FPyEqybvjFiZtKaBqHWKfXAKn1jij", - "marketAuthority": "B5SaMNDz3FDqptKDbCAQr9Vbdw81PuGsNaWCXRaJQR7L", - "marketBaseVault": "5oe13bcyEdUrtNwNN1HA42bmh8pzoKnKCar2XhP8kUWU", - "marketQuoteVault": "9hx2W2Rt5pD8F2Wsm1FvdgwqNh7WCU8N676JtnuRdHyV", - "marketBids": "5dhp3wQ5DmUHCadRjZMfSVoPPDD1P27Ck8witmcJPf45", - "marketAsks": "FQ895ani2pCmWg1jgxGtnTX1ttBnGKxcCBhjVX9qJWEC", - "marketEventQueue": "4GYmVaqxthe1cwTukZVMD3syRYwjN79aTo6mC37Cb7Z7" - }, - { - "id": "uwCU7W55PzSXq8FqzLy9Za5i9ZEPHVXJuk27E2zW88z", - "baseMint": "BXpY6LDkmKuR2fD9mFpvZLYkBchLhfVhpBSNEd31Yjf8", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "EsrHDo753Ku4smzKoWRodiuG2YDMdQHCrcg374KnkLKv", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "25nP6Gw4txkUHVHdGtLkt5E6vTn2Wzcsd9y167S1kcZn", - "targetOrders": "Ad7jbai143AwzaFquZbvaTkMT9ZZK2cCdnp9MUV6eefh", - "baseVault": "2VuUvvSDoHyaFjpc7wDG5nvQ2PsK9ofgkY6pr7xxxrZE", - "quoteVault": "rf2cKz5cgpN9dtEmnNbbLSjvA86rCyvGFNg1TZ1J7fc", - "withdrawQueue": "ERMjdrThEH6Tpf6FAeYBgNNm7Dyk69i6tyfXQGuQozQA", - "lpVault": "Ft8KY3a6rRRqtXvrw4XtXQiQ8G8wgaruM3uVCsbTTkHs", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9m8fScYAfZtrSaAFcJkVFo94jqxY5vyhFxTTdorJEFLG", - "marketAuthority": "9YWkes9RqMnPgV5HbocyZQBoC7m8Gi319xWbFsqzLGvS", - "marketBaseVault": "29WxQxzNeDSwRXLiZcgwCsxeGraJi1RJGatEUS2ThUQo", - "marketQuoteVault": "8SUSsrMbh6qsWQEoTZLUCrb1LdG4jjE4HsErSYmjrX2W", - "marketBids": "9h95ju7BxtjfJioqstgB2URfYg5aLAkcjdTVgDyRrzzk", - "marketAsks": "F9rBcZmaU2qC9zLerVAF4aem2FGgGzojtTzj2BSV1vMo", - "marketEventQueue": "FbdmaGVTFPFFG3xBtWjfHCyotkJwfpeHNNuD2uRgn8rD" - }, - { - "id": "UwfPsuyMAehxiqEEVvw38bf3Q7QgVZzwzNEKQ8vDJv9", - "baseMint": "AYVYJVXMricXLT461niCJ9rYGKGUBcZXyKQA3mGAVTcz", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "4JmbDUu2ok3b5vbNiF2K1wjdvePJWRSYLXK4tP27KtCp", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8xqTBcazLdAEi65pD3MnBrkmGzxUpei7gzdRm41VKdC5", - "targetOrders": "8bu91yunBkNySMVLh891WNNbttK7UydDQzVmFYrjGUpi", - "baseVault": "F15RyoZnp9GESduZvdxRKY63ZhCWSWU8RZuMMEqZaSeD", - "quoteVault": "EiRLgi4LH9R1Dxohq2ajEEdNY67TckQdr3wpfvRi3TnN", - "withdrawQueue": "Aa3mxr5kRQuEkEWAQk1nDjAodNZfqeHXH9X3RpgbggrX", - "lpVault": "HRXBz6rkFpJgsnfECRriortPypexeGaARqSN2T6ZGi66", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "F9FoLuQcgvvLaoUQX4zspa63Pzy7F8MCHAgWqaHxEkr3", - "marketAuthority": "3wFX4JUUfAbubKYPEpmjp4H2LXMSEDNpbSG4DPhgSXi7", - "marketBaseVault": "orHaXyqCUFjZehqSwH3RPD62YMJ3YyPuzQNsn9Zbs8x", - "marketQuoteVault": "8QpzHXVURA26juZMUqBym7uTfV5yU2fM6W5916HmN5RL", - "marketBids": "C9AhVGGxdTNwEefx3jgSMjPaCi6TG7jiSjy7XJYuLo89", - "marketAsks": "9DqByT64NGu3uYHNJnHHMu8zp5vajuQLyzmMCAS6pKyh", - "marketEventQueue": "42NUbhwtSis9yuXJjeWQFkycZ4Gs5QXfzWt95wHWeNwq" - }, - { - "id": "VAK9QRPAUFeivYM3dsAcMw2QVEJaqAaeUt4K6wvAuFu", - "baseMint": "Fkbimv9CBGZANAqRJZQ732xEZ5EA4GidjeNRKiYoDY5y", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "FjyBbaBdZKTe3KGzros3pz94qLu99FNVtb525JMLqoUA", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HEyxM9tpVZu84NDEsvQ3sYGbAdkTSknzdHpnEnysieWB", - "targetOrders": "81u8hvzY66VoPbhJF2EMfQwbQN9BcdEuiiGLi14emAZY", - "baseVault": "6G2nhDBXTmpbtfRVTmDsvXT4DiPZUzzai2sQt81yxvaf", - "quoteVault": "BuJNML33qb5XDRbX2tpdwhUiRmdMegF7Rqa2fdQ24Suk", - "withdrawQueue": "mtwQKgpaJVdicDrivFYgoFHbGZAZXRPFD4LmhBhmV8C", - "lpVault": "3MGEoaG5JnDrhRXXE8iU8YTcsUZPjy21LXPGLz8US1zc", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "FdvpyxZc9PAixt33LnS6RqLhpP8hYZE6EXRi6grQ6Ztc", - "marketAuthority": "3ca17WCdpBgX4y5bACMbJZsfTmXRkYCKDMM3pLeVChKU", - "marketBaseVault": "GyhCJRYrYK1QVGbbAidYpJKp2WPP5EmzeUYp7MiCwfcB", - "marketQuoteVault": "J3WZmjLQQdBKU8dwemUHSvKUd53vZJvPqxE1Y46dcV9U", - "marketBids": "zSgCsCQCCPdBsGG1N3LctSw6jgvZgDJLEtHnt1eewda", - "marketAsks": "A9iAduSMJmdj5iSCm2TVcgKgu22aEwmXHcfRskjPDiKY", - "marketEventQueue": "3hyUrsCaTHfUXEATHJyenQWVb6YwP2mPG3Q8YWPzFqu8" - }, - { - "id": "vB6xrZiFJZS15Vvu2FfmL5ELJAu4e9CFTbhDUTqfzYt", - "baseMint": "7k5WRFxyHveTDVJiNj69r8pboregzRSTdoRvmBaETe3w", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "3tGkrMSgB5YYDP1ypAXzp9CWVgCpnWFdXYQikBzuvWJj", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "6wvDjgegswiD955VHx4jHn6Wr2wcMxcSbEcyN6BzbAdD", - "targetOrders": "CCD4Dj6m1rzGHAByEGNyUkzbymxSN6EpZikDT3Udsa7e", - "baseVault": "3icZg3RPgipvgmyGT5RheptfvfoALSDAgMq9MmNNwQGA", - "quoteVault": "APNcWGihFidoMWd2Q2CHkD1fPSBVdcKNoyhfvLtjQafF", - "withdrawQueue": "67snz1XTLM7um2FTuqHWCbGAECHUWry9Re5GL1z9E3z", - "lpVault": "ruC1d9p6edG1ABLeUWK6JHvvaBE3xRDzPP1T2S4q7LC", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8Ra79WDacR4eLnyMdBWSDoGDcDWHgn32CrdnaeAUYzfY", - "marketAuthority": "WMmLH5ny5nnnDPNzaXJ74mpCvdorVj1ue2XPxuJ5qvX", - "marketBaseVault": "5SRz5ar53J8G6WFajUSF9aC2m5xr9MPDovUMkn7hDzn2", - "marketQuoteVault": "Gr2RM98JJ5gConTvX2p4XSeZWxkawDmVvzc8HSYpoiU5", - "marketBids": "CkvpvodtSrdgfCNFt13W5BjBkaNqM6VqwnwzDexhjUFx", - "marketAsks": "HAnkjTMoF8H9g4xaHEdYUTop79KwQQPUoAXTmqs464ff", - "marketEventQueue": "AdJsykFQdtC6ukMSDiFq1bamsAPro3ThEMgBygFN3J1y" - }, - { - "id": "VhASzwc7jyYqCtWCDXLSXS1VhWsQUxrcc8DE88PHHsg", - "baseMint": "4q5UBXJxE91BZKX548qhU8i5QBWvZdXzS3RZwfTgLQda", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "ANcxniVcRcQNfYfcToiKuSuqNBJminbkC5BbiRCRmNYC", - "baseDecimals": 6, - "quoteDecimals": 6, - "lpDecimals": 6, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "FgZ4o99qdxJMaRqpNoehyf9UeBicJQkcA1sggVPvjG4g", - "targetOrders": "GiTZK7AQDSVQ1X4Buo73ZXRetsvvLEYe6CcZg6Wbajig", - "baseVault": "Caq59BxxbnCg78Hm5MkvYb8aZntfHHvD62gPaK3wugsg", - "quoteVault": "3Kd8T4o2abVVoXkkvbaGEXqZZhu12hdHMKBb9yezgfQN", - "withdrawQueue": "H5N1u9oXFvKJx98hB1pQUnz2ja3oXdReZYM2AWfEtmAj", - "lpVault": "6EGkGo9Xx2z1vaeGEgAfDYVayiv1d1nbFhmTYjd24TLm", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "14swEM4G2dn7gXUgnqBcJ4ZSAjBEZgavPfbderkm38D7", - "marketAuthority": "Ckbq8GKrmAfVHTcrotQHSVfE9ZQFk437Dd1x9ja575ri", - "marketBaseVault": "HKPDyfbKQ7b34Giq8bzvrhKUJi1Rs74oSdEg4y9um6NJ", - "marketQuoteVault": "99eLDvwSLDrqw5nrAPfijz2ZF8ktyvGAFbvfZajdmp3G", - "marketBids": "AUa1Adc24JkzXpJVT4eRkJET4RwY4umNHFnNvJkno3Bh", - "marketAsks": "9n7xjHib2GsE88xHi4Wcq9PMauMscNVaSgHxq2BmcQaq", - "marketEventQueue": "DutK8FSDsg6TNprUuBWPiypxangD1Gvo5QreMRHxrJz9" - }, - { - "id": "VHdfgy4CBEDPhx3C3jNQiSxsaD9aUk3zSTvHCmhJzsB", - "baseMint": "EjSwAfwi4F6uYtoi2WuCSYSWPVUPJCdemmShZ9tdy65P", - "quoteMint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "lpMint": "A1MdFdEcSHfEJiFKm6gQ6dcjyc5aZkUBfDrfVPEyJoq2", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "L6sPtdA2vXkQugRva3uN5STsm7cj6KEz1ZtbqztY2aa", - "targetOrders": "C5yqfwgGzEUqyWHVH5zH88PQriBSLdRCMigxysysdy2W", - "baseVault": "4KmKTAuwHzpJoQZwT4vVAY5m1hsiRVyY17346vJ6CD2U", - "quoteVault": "FsDWHTKB9SiwMkuPxU1jaFQpuB1H8GiyqB8qtGa4aGvx", - "withdrawQueue": "GNXZgjXiGFjB9EHDrcbHn6KvXcuX4BEk5wTrWVVv1fxy", - "lpVault": "AhiwdEAwD6Caip5Aw2uK5EiU8pgsS18cazcxtCT2qUyw", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "6BuMVf7k9NPYsX7dcVtjb3xcYyrGgqMwYHJfLBTS39Lz", - "marketAuthority": "8p1mHqR9XpqnUYeSuxNPqgenWhJtwU6c7JpMRkaCWy7G", - "marketBaseVault": "2Nkh6JGTkYcPXXfMBANDuDBhQrfT9fgsCEo3tL5gFyPh", - "marketQuoteVault": "AfSdUBqnkHxtptNnQCW7kwgNteCx7LznCscJ9DGCQxJk", - "marketBids": "BPoq6T6wHUjnCiptEb8N7fwXm8mfs2UQ4k657fGNLWSE", - "marketAsks": "Cxp731SzjTUwfSeR9c9NFQ3fqsow578wLBocyHMaviTY", - "marketEventQueue": "HHvzh5B1EE1E2mow4Y87U3FBQhwXg8oExfNVDvJ2Ks9Q" - }, - { - "id": "vPGYjFYjDXj24W7qfaA5osLEhN4UkimKtZGCv1DhQQG", - "baseMint": "73rd6Ekp1bTYzV3oBAUeL4vMDAnHTdiXhCS5pbnh9quj", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "BmYYz5iFtAsfwEgaWYonYSLvmhjnyifMCJw4mBXFsKCG", - "baseDecimals": 8, - "quoteDecimals": 9, - "lpDecimals": 8, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "A5WsC2RXpMbDcSdqik5zTAFj2tVMYVvwBHqMZ69fGJ1a", - "targetOrders": "FikRCKvLiYq7DNZ1AS1TTmLxx7g8MGSmGnzCiFd5vm6g", - "baseVault": "49BLa4NBwEG97hiEHVdPYmsNcQYLZoB6gCeccgCaL1Bn", - "quoteVault": "CWYajhRVoMBwEdaF8RJGxkgReMtWK3J5AbGVc1XBv7Sx", - "withdrawQueue": "6NFWf5REufGxASRF8aznrjj8iytM6cKidWnGrhYjLDu", - "lpVault": "53HD5V35fXWFHSxxikRJkNM3GWkm5ESBZn48i4xnjyA7", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Ew1kWM99LECzLcV7oR95G9hMejsEfkjL5cy1HcashZgN", - "marketAuthority": "FvncQkZDrUkcdmfyb2EDmiHV6PMxiv2xmuVjzs19NeNK", - "marketBaseVault": "A5kVHW1yWbMiUmjcxPSVEnNuGs6uxVJwphCdeMNbcaQu", - "marketQuoteVault": "H72EyviVsQKkGkHnTvuJK7HzHPc5XR9dctupN5Ako1Lh", - "marketBids": "BCAWwt8GVcvP7hSWz7yrNkMAQ2hmz4JHw8FTWXCroeQj", - "marketAsks": "C7VTiu2zZxdEr5rjJ3hKa3TkLyHdbFBMPtwM9DS5J5Qs", - "marketEventQueue": "5VinKxRKjWFx2x2jy4jiysqya5iGcK2LB36DnUc8CgkJ" - }, - { - "id": "wfVsuGoXdMN2gGJoWTX3ko5xoZKQ5mqMuWkWJJxZqYs", - "baseMint": "KARTdF5K68Q2nGppizG3DeCzp7AhHy6YXf2uTQjBSQx", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "8Z4thvFWvMP4VjgkRRJD23ZFBr9dBU4GeUeThAaTEq81", - "baseDecimals": 0, - "quoteDecimals": 9, - "lpDecimals": 0, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "EGXkk1yLvFSSj26He115tRk4kbQWHhHUxiTcCynpWERB", - "targetOrders": "55tER2riiFjUzyo6LTv1ejyG3bxQtQV8ckr9xVhQ2qDD", - "baseVault": "GBdS4ao6LGHvmkhgV6GhXudwWKaz1ZXBVmYjaGu6DJsX", - "quoteVault": "AU9ouqJX91cgY5omVNTypUth9LBp3pugZjM544Sojujm", - "withdrawQueue": "7B8b4a8yYe2MSKYvPLF4qrws2PyYVLNTX2spTjmQQR8Z", - "lpVault": "HvSGCn4UDm4qDGibujTjW3zcH8xgpXE2U2YDr1jaPRsm", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "8AmDKQwkw1UuvjmBmCHN5DwU1n5kMwMJ2CfFQrCA5nzE", - "marketAuthority": "EqXA8NKexqzLDzDZ4gmbojKBceyJcBhNq1XhLwfw8nd3", - "marketBaseVault": "2ZpqMcGRReTiPUVwxrXAHG8cPaxEiCMZo8ixzmERH528", - "marketQuoteVault": "4ugJpLxXmfaaB2uLPwATjBTCpsRMi6naZsHnEBJyR12b", - "marketBids": "AY5j487KyRNHmcPnmxKHtHJJN62oEfyYHN8wymTC7Vbb", - "marketAsks": "99Ns9sSqvy9WQXTcyHAu8ycCV2NUZbtRa49BHW7M38Lb", - "marketEventQueue": "5X8JFnDDY77XNqfpBLX2wURwssDJMVTJx5Yi2aK1bt4b" - }, - { - "id": "wnebnFLvgaGe2nxDgv5FvWT9Tkvk4KJqfGzumuH1mwN", - "baseMint": "HysJKMMQ4G6oEffMhf55ZPRc28zwCmpmZr63vAfUrrBq", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "44kAZPCL4Vq3BcSJ5VkhC2uGnwTF8eNSojbmC9reiKqY", - "baseDecimals": 2, - "quoteDecimals": 6, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "2QZSXyWd1AowVTkwD2nuF7SWUb4qXBUgQntXwej8oqsq", - "targetOrders": "Hhe6r3TyNjApomw3oNsD93hxqb2xTVJExiXjYQAoEafL", - "baseVault": "9AAY79Z4Ax5GPCewgJRc9NhU3CTRSqPNZT9TU5shk6Qr", - "quoteVault": "DR313J3xrMyZhVjNBcki2WTrushmmxw8NpLxmQgqN264", - "withdrawQueue": "AUGvk29NMvyBBF3YKFTC7iDtWM5UyocgLSZvEBjBPGd7", - "lpVault": "D6KPdmXcH49LBHUXHxbJ4HX4EepdirnHKGSWzoh5kqSi", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "Ceajms5t1e6MMPrcAj15seAC3bi4EamPRvuPndP4WgXG", - "marketAuthority": "6zdxJXeeqib9jD1AHTctEndKyxrCEeqvjoU7i1Su61qK", - "marketBaseVault": "DcXCYZXC9DX8mkXKCjHwnBL9LiAfwGRWkAM7cQNFKGY6", - "marketQuoteVault": "C3d2JfxW4H5Amu9kW2Xk6EG6uuHpQTpZs19C4eiZjHUC", - "marketBids": "7qXvEKkvY28CzDYz88bD89My47DPkhWjFQ5J6o9DP265", - "marketAsks": "7zckZasnJkKdZHz3tPWjTn6AKsHEyk7KR6umDnV7E8pP", - "marketEventQueue": "7pMDo86XyW5p6pQjohZHxmhf4EZyzEjrEvH2G1GgeBnK" - }, - { - "id": "WW8rsUQPahmVg1EXVm2zs9L5ofVRsoHF1BauArQk2V1", - "baseMint": "7zsKqN7Fg2s9VsqAq6XBoiShCVohpGshSUvoWBc6jKYh", - "quoteMint": "So11111111111111111111111111111111111111112", - "lpMint": "G33cpXg1ucKpPcwronkDPp9WdoxhXFPBdD9tqEc65Cry", - "baseDecimals": 2, - "quoteDecimals": 9, - "lpDecimals": 2, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "ETTEdqMUSn9UemdpJkxEB5rAv53udrFi8zc2G2pMake8", - "targetOrders": "4vpFPvLBEM6xYeus3rAztxk8Qcqo8AasNdh5angoMgA9", - "baseVault": "6VugBYiCTjd1QgrpH8VuevEFtaXmiivSNYNMXEvL37Wi", - "quoteVault": "GNZ7MnPJs4boTpPcQFjxapTUrkafZojgbd8s6dRoVUh1", - "withdrawQueue": "Ad6NUwZhpBcAweqm9SA9d5PWyYnBrwUixBYQVowMDJ7N", - "lpVault": "AemWrWu4PCzS8WmKzUNveDcnRSnGZ3KokmWvq56FfFmF", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "9uPmBwdNnfWc2fzvTQ264urJBY1JChrGcmhUeojzNfyW", - "marketAuthority": "GZjKKoPeVv79neaSRLARwsio2KnWsyJC8Cnzk5Jeumbm", - "marketBaseVault": "5mZfHcFg9FrrzJCYL9KDtUQHyrPQfmsbJsmb5SY9KchD", - "marketQuoteVault": "9upKufR1Uone2R4qqZo735mYzDS3Nmyjf3JXEG7xs8Dm", - "marketBids": "4vrex2zbndWHHqMqmBrss9JJwkfGF7f6u7jo4besD2P", - "marketAsks": "8hXWTvab5m2Ef4WkxYu6av2169yS9s89Uwt16vgNBMaD", - "marketEventQueue": "C3hV1idw4pAr5isqBpumeQL8a3wjBiXg2141SLFeWnKz" - }, - { - "id": "Z1VFmv2DSuScFAWRU7jbgX52dFQYSbwDp7me7XBMuNV", - "baseMint": "765R1rpPGVZKKJZPevTp5b2dTAHJZNX4feTiHDEqj7JV", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Brzm63jpZYur41udr7uGgDvDr55YPiEC8ELQwmCLuVrB", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "HWwqScvxJiJpYiVf9hePfMd8pNTCf6CT5DKvbsXnFtnW", - "targetOrders": "HeBbp5QBdJATWM37HFmjpTtCR9tX5oLJokp2oXCG6mv9", - "baseVault": "4ZjnoNz1F3qxf6WtDEdNSqcwKtK7yyYrxoUXpySQmCPV", - "quoteVault": "GUe8dbPTpbVKEctYhKTyoG8XbURKtXATQcT8YNSmHnoB", - "withdrawQueue": "9Mu6j6pkXQPwvEymTVHkLWGrrdP7KSN61Pa1U7fwNuX2", - "lpVault": "ACg5NmMZtfrRz58KFDUKHzaUETFuWvVdiYZSQpbi224h", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "57pr9ZdTK3WP7WzEnL4j7xNoevsS6nbjdsnAPrnJH3DA", - "marketAuthority": "71UgNKCQPUyT1q9Br2aauVXsMyDSWykB8Y4Rmbf89TUW", - "marketBaseVault": "FfxLrWx3YckSYi2KKHANrQJAEiM2XTvxdQoDKaL4JziC", - "marketQuoteVault": "6acD7vPCYa9yxoyfR8Wn7jhqPALvrJMh59tw1KmMMKWQ", - "marketBids": "4tBNXE1a7hEDtHzbnkJjLsHNa6E7uJV89od8Wwvwaong", - "marketAsks": "B8BJ6d8VrVXtKE1uoWojBToR9hpEvao1V8e6sGKtTxXn", - "marketEventQueue": "4VG3yVSbVPUSvUsKjExrjLFKfdeJQLDi3krrmz68ZYtH" - }, - { - "id": "z2KxiSejQmNNsyxLFHbrewNLDeGLFZahFNSLYht2FFs", - "baseMint": "A2T2jDe2bxyEHkKtS8AtrTRmJ9VZRwyY8Kr7oQ8xNyfb", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "9DdWQs3FtCwxxA55oDGYkqN6qMq51ntDDpCzANnnwvsx", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "8SBrLHd68sQJgYGHipfQBdvfR72VqvXozBwEdvKoYWRh", - "targetOrders": "HZQZFp1sTDMsukMJb545R9gcfuH4HZA9MRJBiLePc1q", - "baseVault": "B7tLafxXDHDLpdxuvcFEcpYZ19iGWqFDZuV7SaPPrCsi", - "quoteVault": "3kWwdn7WzysuBvCSuAPXEq4N489j4SMY9qC3QaZHAXmw", - "withdrawQueue": "5fH38pu8kEs6psrD7tk6uy4w7HQw7hDiKbJbWorsv8PV", - "lpVault": "GfeptKx3LkLacfwPcr9o1TqMJbQKN8aKev13u9oNfYcq", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "5j6hdwx4eW3QBYZtRjKiUj7aDA1dxDpveSHBznwq7kUv", - "marketAuthority": "6Vbs1AWJeD14hJ7YgCPvHDyGhf74m46zvqrRKYRRkQL4", - "marketBaseVault": "AFUN7xyZDYAK8pKpU69qLkCYXMjKyaL1nqrGX5Wy3Vh6", - "marketQuoteVault": "A4hUoxhDNwg7d7btgcC3riiCDNeMSxcHYSBUsVbmYHkV", - "marketBids": "8D1QYwSzLNdQ4nVwN279PRaXh5bFk4ZwJXscLinoKE2S", - "marketAsks": "C3X12f3PvQbjHEtpVnzKeGXf6NNMFnEMczhaEqFTiZFX", - "marketEventQueue": "7HRU2ZiKSFX6TZhoYUjWDLMuAzqKoLJ92FASxbPzRheh" - }, - { - "id": "zXkGaVV6hrY5DT8hnNcJQ7TaQXKJGqYKevHdp2Fcbud", - "baseMint": "2YJH1Y5NbdwJGEUAMY6hoTycKWrRCP6kLKs62xiSKWHM", - "quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "lpMint": "Eb1cJXD3fCT1HbiEjK3Gvs1oCoj8kPCqLpfUFacUNSMf", - "baseDecimals": 9, - "quoteDecimals": 6, - "lpDecimals": 9, - "version": 4, - "programId": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", - "authority": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", - "openOrders": "4DihZyC4mETdG8VXPgXqZ5Wmt5LNf2BsNK2kp4GEXRAv", - "targetOrders": "HtnMCFnoqmWVPStMdqWv4Z9rEos6pFuFyYXZRsh1e8qx", - "baseVault": "2zuVGhBjtgkuanhGBXfRLJeChuqXCtofimr4iLsJpZNF", - "quoteVault": "3WUfEpz66RkttEDpbjvdKVsxZF2xK5WKQGQKgbbgw1id", - "withdrawQueue": "2fYzYbWubmSLfHH8zsJr5xE8J4i3Nkut3xPaosuoGPFo", - "lpVault": "AiVxcJR7LpW5xb41dFu6stTWduzHjVNqEwDpyYjmrDSD", - "marketVersion": 3, - "marketProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", - "marketId": "DyuzpLLFiVrHJh1rsK5n7ydHyiNKMXqDdoV6FZur8qik", - "marketAuthority": "6ABWgq8xLkwarLFSARd2bFxCKxk6n6gs6m4LGperfVa6", - "marketBaseVault": "DzkNbMM4SKas3hV1uTbpfW9339sjM17kgcvH7Fz714Ps", - "marketQuoteVault": "9bPQiY7v39J1Cujhq2ZQPACv2oH23HZeXdSvTgQuPDdD", - "marketBids": "CNryMA98e5w6t154RN9SBEkNwWGMj2EmgfD79kpxZ8jN", - "marketAsks": "EnaqwCrZyyTZxCvxuSXR7cAPfVAQT8hsATQeMoWwdhAN", - "marketEventQueue": "3SBsB4eUeRkpvt82RBRfav66p1nqmAVW8gJrfA8LCevt" - } - ] -} diff --git a/farms/farm-ctrl/metadata/pools/raydium/pools_dev.json b/farms/farm-ctrl/metadata/pools/raydium/pools_dev.json deleted file mode 100644 index 6a6eb2dff7e..00000000000 --- a/farms/farm-ctrl/metadata/pools/raydium/pools_dev.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "Raydium Pools", - "pools": [ - { - "name": "COIN-PC", - "coin": "COIN", - "pc": "PC", - "lp": "LP.RDM.COIN-PC-V4", - "version": 4, - "programId": "LIQUIDITY_POOL_PROGRAM_ID_V4", - "ammId": "HeD1cekRWUNR25dcvW8c9bAHeKbr1r7qKEhv7pEegr4f", - "ammAuthority": "DhVpojXMTbZMuTaCgiiaFU7U8GvEEhnYo4G9BUdiEYGh", - "ammOpenOrders": "HboQAt9BXyejnh6SzdDNTx4WELMtRRPCr7pRSLpAW7Eq", - "ammTargetOrders": "6TzAjFPVZVMjbET8vUSk35J9U2dEWFCrnbHogsejRE5h", - "ammQuantities": "11111111111111111111111111111111", - "poolCoinTokenAccount": "3qbeXHwh9Sz4zabJxbxvYGJc57DZHrFgYMCWnaeNJENT", - "poolPcTokenAccount": "FrGPG5D4JZVF5ger7xSChFVFL8M9kACJckzyCz8tVowz", - "poolWithdrawQueue": "DD9nUbJoUbuE3FampcJeLfDPb5zKGvR7Ho7HE5rpcBGx", - "poolTempLpTokenAccount": "249BW2tWhsvwEFtWabpTXXX17Vh7NQSeHS4W7Ku6b27R", - "serumProgramId": "SERUM_PROGRAM_ID_V3", - "serumMarket": "3tsrPhKrWHWMB8RiPaqNxJ8GnBhZnDqL4wcu5EAMFeBe", - "serumBids": "ANHHchetdZVZBuwKWgz8RSfVgCDsRpW9i2BNWrmG9Jh9", - "serumAsks": "ESSri17GNbVttqrp7hrjuXtxuTcCqytnrMkEqr29gMGr", - "serumEventQueue": "FGAW7QqNJGFyhakh5jPzGowSb8UqcSJ95ZmySeBgmVwt", - "serumCoinVaultAccount": "E1E5kQqWXkXbaqVzpY5P2EQUSi8PNAHdCnqsj3mPWSjG", - "serumPcVaultAccount": "3sj6Dsw8fr8MseXpCnvuCSczR8mQjCWNyWDC5cAfEuTq", - "serumVaultSigner": "C2fDkZJqHH5PXyQ7UWBNZsmu6vDXxrEbb9Ex9KF7XsAE", - "official": true - } - ] -} diff --git a/farms/farm-ctrl/metadata/pools/saber/add_decimals_idl.json b/farms/farm-ctrl/metadata/pools/saber/add_decimals_idl.json deleted file mode 100644 index 7d5dae29f9d..00000000000 --- a/farms/farm-ctrl/metadata/pools/saber/add_decimals_idl.json +++ /dev/null @@ -1,356 +0,0 @@ -{ - "version": "0.0.0", - "name": "add_decimals", - "instructions": [ - { - "name": "initializeWrapper", - "accounts": [ - { - "name": "wrapper", - "isMut": true, - "isSigner": false - }, - { - "name": "wrapperUnderlyingTokens", - "isMut": false, - "isSigner": false - }, - { - "name": "underlyingMint", - "isMut": false, - "isSigner": false - }, - { - "name": "wrapperMint", - "isMut": false, - "isSigner": false - }, - { - "name": "payer", - "isMut": false, - "isSigner": true - }, - { - "name": "rent", - "isMut": false, - "isSigner": false - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "nonce", - "type": "u8" - } - ] - }, - { - "name": "deposit", - "accounts": [ - { - "name": "wrapper", - "isMut": false, - "isSigner": false - }, - { - "name": "wrapperMint", - "isMut": true, - "isSigner": false - }, - { - "name": "wrapperUnderlyingTokens", - "isMut": true, - "isSigner": false - }, - { - "name": "owner", - "isMut": false, - "isSigner": true - }, - { - "name": "userUnderlyingTokens", - "isMut": true, - "isSigner": false - }, - { - "name": "userWrappedTokens", - "isMut": true, - "isSigner": false - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "depositAmount", - "type": "u64" - } - ] - }, - { - "name": "withdraw", - "accounts": [ - { - "name": "wrapper", - "isMut": false, - "isSigner": false - }, - { - "name": "wrapperMint", - "isMut": true, - "isSigner": false - }, - { - "name": "wrapperUnderlyingTokens", - "isMut": true, - "isSigner": false - }, - { - "name": "owner", - "isMut": false, - "isSigner": true - }, - { - "name": "userUnderlyingTokens", - "isMut": true, - "isSigner": false - }, - { - "name": "userWrappedTokens", - "isMut": true, - "isSigner": false - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "maxBurnAmount", - "type": "u64" - } - ] - } - ], - "accounts": [ - { - "name": "WrappedToken", - "type": { - "kind": "struct", - "fields": [ - { - "name": "decimals", - "type": "u8" - }, - { - "name": "multiplier", - "type": "u64" - }, - { - "name": "wrapperUnderlyingMint", - "type": "publicKey" - }, - { - "name": "wrapperUnderlyingTokens", - "type": "publicKey" - }, - { - "name": "wrapperMint", - "type": "publicKey" - } - ] - } - } - ], - "events": [ - { - "name": "InitEvent", - "fields": [ - { - "name": "payer", - "type": "publicKey", - "index": false - }, - { - "name": "decimals", - "type": "u8", - "index": false - }, - { - "name": "multiplier", - "type": "u64", - "index": false - }, - { - "name": "wrapperUnderlyingMint", - "type": "publicKey", - "index": false - }, - { - "name": "wrapperUnderlyingTokens", - "type": "publicKey", - "index": false - }, - { - "name": "wrapperMint", - "type": "publicKey", - "index": false - } - ] - }, - { - "name": "DepositEvent", - "fields": [ - { - "name": "owner", - "type": "publicKey", - "index": false - }, - { - "name": "underlyingMint", - "type": "publicKey", - "index": false - }, - { - "name": "wrappedMint", - "type": "publicKey", - "index": false - }, - { - "name": "depositAmount", - "type": "u64", - "index": false - }, - { - "name": "mintAmount", - "type": "u64", - "index": false - } - ] - }, - { - "name": "WithdrawEvent", - "fields": [ - { - "name": "owner", - "type": "publicKey", - "index": false - }, - { - "name": "underlyingMint", - "type": "publicKey", - "index": false - }, - { - "name": "wrappedMint", - "type": "publicKey", - "index": false - }, - { - "name": "withdrawAmount", - "type": "u64", - "index": false - }, - { - "name": "burnAmount", - "type": "u64", - "index": false - }, - { - "name": "dustAmount", - "type": "u64", - "index": false - } - ] - } - ], - "errors": [ - { - "code": 300, - "name": "InitNonEmptyAccount", - "msg": "Wrapper underlying tokens account must be empty." - }, - { - "code": 301, - "name": "InitWrapperSupplyNonZero", - "msg": "Supply of the wrapper mint is non-zero" - }, - { - "code": 302, - "name": "InitWrapperUnderlyingOwnerMismatch", - "msg": "Owner of the wrapper underlying tokens account must be the wrapper" - }, - { - "code": 303, - "name": "InitWrapperUnderlyingMintMismatch", - "msg": "Underlying mint does not match underlying tokens account mint" - }, - { - "code": 304, - "name": "InitMintAuthorityMismatch", - "msg": "Mint authority mismatch" - }, - { - "code": 305, - "name": "InitMultiplierOverflow", - "msg": "Initial decimals too high" - }, - { - "code": 306, - "name": "InitWrapperDecimalsTooLow", - "msg": "The number of target decimals must be greater than or equal to the underlying asset's decimals." - }, - { - "code": 307, - "name": "MintAmountOverflow", - "msg": "Mint amount overflow. This error happens when the token cannot support this many decimals added to the token." - }, - { - "code": 308, - "name": "InvalidBurnAmount", - "msg": "Failed to convert burn amount from withdraw amount." - }, - { - "code": 309, - "name": "InvalidWithdrawAmount", - "msg": "Failed to convert withdraw amount from wrapped amount." - }, - { - "code": 310, - "name": "InsufficientUnderlyingBalance", - "msg": "User does not have enough underlying tokens" - }, - { - "code": 311, - "name": "InsufficientWrappedBalance", - "msg": "User does not have enough wrapped tokens" - }, - { - "code": 312, - "name": "ZeroAmount", - "msg": "Cannot send zero tokens" - }, - { - "code": 313, - "name": "UnknownAction", - "msg": "Unknown router action" - }, - { - "code": 314, - "name": "InitFreezeAuthorityMismatch", - "msg": "Freeze authority mismatch" - } - ], - "metadata": { - "address": "Gwuw9jkL6cXwR2eKZqt6G2g4XVPqrzJhB4g6FmfzFQ5f" - } -} diff --git a/farms/farm-ctrl/metadata/pools/saber/fetch_wrappers.js b/farms/farm-ctrl/metadata/pools/saber/fetch_wrappers.js deleted file mode 100644 index 20c27b02271..00000000000 --- a/farms/farm-ctrl/metadata/pools/saber/fetch_wrappers.js +++ /dev/null @@ -1,156 +0,0 @@ -const anchor = require("@project-serum/anchor"); - -anchor.setProvider(anchor.Provider.env()); - -async function fetch_wrapper_vault(symbol, wrapper_program, wrapper) { - const idl = JSON.parse( - require("fs").readFileSync("./add_decimals_idl.json", "utf8") - ); - const programId = new anchor.web3.PublicKey(wrapper_program); - const program = new anchor.Program(idl, programId); - console.log( - symbol, - ( - await program.account.wrappedToken.fetch(wrapper) - ).wrapperUnderlyingTokens.toString() - ); -} - -console.log("Running client."); -fetch_wrapper_vault( - "swhETH-9", - "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", - "93qsLbASEG8DmtSB2MEVaa25KvEm2afh5rzbaAJHLi5A" -).then(() => console.log("Success")); - -fetch_wrapper_vault( - "swFTT-9", - "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", - "FCgoT8RpsopdM5QT6AB98NUfUnDnu7y865MFpRx93JrS" -).then(() => console.log("Success")); - -fetch_wrapper_vault( - "srenBTC-10", - "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", - "3A85wiQg2REhBVxVS1CjDaS333TBNM2g37BbdNGSMheg" -).then(() => console.log("Success")); - -fetch_wrapper_vault( - "srenBTC-9", - "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", - "D231Uoh24bXtUtWN51ZbFAFSBmGT3zuuEAHZNuCmtRjN" -).then(() => console.log("Success")); - -fetch_wrapper_vault( - "srenLUNA-9", - "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", - "FDGtFWVhEb1zxnaW2FzogeGDxLoAV7Cu9XdNYPEVwqt" -).then(() => console.log("Success")); - -fetch_wrapper_vault( - "sUSDC-8", - "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", - "G4gRGymKo7MGzGZup12JS39YVCvy8YMM6KY9AmcKi5iw" -).then(() => console.log("Success")); - -fetch_wrapper_vault( - "sUSDC-9", - "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", - "AnKLLfpMcceM6YXtJ9nGxYekVXqfWy8WNsMZXoQTCVQk" -).then(() => console.log("Success")); - -fetch_wrapper_vault( - "sUSDT-9", - "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", - "F9TsAsh5RirU3LqyTJECLQEGXnF4RQT7ckvexCP1KNTu" -).then(() => console.log("Success")); - -fetch_wrapper_vault( - "sBTC-8", - "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", - "GpkFF2nPfjUcsavgDGscxaUEQ2hYJ563AXXtU8ohiZ7c" -).then(() => console.log("Success")); - -fetch_wrapper_vault( - "sBTC-9", - "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", - "7hWjnVC6FNkmmgjq88LEnRycrKvxVB1MsJ6FQcrvxe4n" -).then(() => console.log("Success")); - -fetch_wrapper_vault( - "sETH-8", - "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", - "fvSvtHNFuDHrAN82YEyBApRs3U6vUGCLzKGMuPmCaF8" -).then(() => console.log("Success")); - -fetch_wrapper_vault( - "sFTT-9", - "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", - "2ffwMLE4dxSv59eYXhfhfuS81kz6gzf6DZjdBxRHZz9A" -).then(() => console.log("Success")); - -fetch_wrapper_vault( - "ssoFTT-8", - "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", - "CGxMr5UrTjApBjU656N9NBAsGby4fWs1KgVtueQ8WKt6" -).then(() => console.log("Success")); - -fetch_wrapper_vault( - "sETH-9", - "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", - "93qsLbASEG8DmtSB2MEVaa25KvEm2afh5rzbaAJHLi5A" -).then(() => console.log("Success")); - -fetch_wrapper_vault( - "sagEUR-9", - "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", - "EhQqUmkUXXnxmV7yA6PDrQWvLgSd9HkrwdDKk1B5m6Tc" -).then(() => console.log("Success")); - -fetch_wrapper_vault( - "sCASH-8", - "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", - "Ffxi5TSpFV9NeV5KyNDCC7fWnFoFd2bDcL1eViSAE2M2" -).then(() => console.log("Success")); - -fetch_wrapper_vault( - "sCASH-9", - "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", - "2B5Qedoo95Pjpv9xVPw82bbmcGDGCNHroKpzQE2CNHRZ" -).then(() => console.log("Success")); - -fetch_wrapper_vault( - "sLUNA-9", - "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", - "ACvLVgR3UKdDB3b1QapsbJsPXaUrBPdJGDfiFnMYMXoz" -).then(() => console.log("Success")); - -fetch_wrapper_vault( - "sUST-8", - "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", - "EwWpia5t9Twiwdi8ghK8e8JHaf6ShNU9jmoYpvdZhBwC" -).then(() => console.log("Success")); - -fetch_wrapper_vault( - "sUST-9", - "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", - "FPuYMuodknZuQKHA8Wp4PBbp52Qu8nK2oAuwedp2WfM3" -).then(() => console.log("Success")); - -fetch_wrapper_vault( - "ssoFTT-9", - "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", - "2ffwMLE4dxSv59eYXhfhfuS81kz6gzf6DZjdBxRHZz9A" -).then(() => console.log("Success")); - -fetch_wrapper_vault( - "sUSDT-8", - "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", - "GiLSv94Wwyd6suH57Fu6HjEKsMxhNGfEwKn9vT22me1p" -).then(() => console.log("Success")); - -fetch_wrapper_vault( - "ssoETH-8", - "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", - "fvSvtHNFuDHrAN82YEyBApRs3U6vUGCLzKGMuPmCaF8" -).then(() => console.log("Success")); diff --git a/farms/farm-ctrl/metadata/pools/saber/get_pools_and_farms.sh b/farms/farm-ctrl/metadata/pools/saber/get_pools_and_farms.sh deleted file mode 100755 index 3990e00b97b..00000000000 --- a/farms/farm-ctrl/metadata/pools/saber/get_pools_and_farms.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -url="https://registry.saber.so/data/pools-info.mainnet.json" - -if hash wget 2>/dev/null; then - wget_or_curl="wget -O pools_and_farms.json $url" -elif hash curl 2>/dev/null; then - wget_or_curl="curl -o pools_and_farms.json -L $url" -else - echo "Error: Neither curl nor wget were found" >&2 - return 1 -fi - -exec $wget_or_curl \ No newline at end of file diff --git a/farms/farm-ctrl/metadata/pools/saber/get_pools_and_farms_dev.sh b/farms/farm-ctrl/metadata/pools/saber/get_pools_and_farms_dev.sh deleted file mode 100755 index 6953648b8ce..00000000000 --- a/farms/farm-ctrl/metadata/pools/saber/get_pools_and_farms_dev.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -url="https://registry.saber.so/data/pools-info.devnet.json" - -if hash wget 2>/dev/null; then - wget_or_curl="wget -O pools_and_farms_dev.json $url" -elif hash curl 2>/dev/null; then - wget_or_curl="curl -o pools_and_farms_dev.json -L $url" -else - echo "Error: Neither curl nor wget were found" >&2 - return 1 -fi - -exec $wget_or_curl \ No newline at end of file diff --git a/farms/farm-ctrl/metadata/pools/saber/pools_and_farms.json b/farms/farm-ctrl/metadata/pools/saber/pools_and_farms.json deleted file mode 100644 index 39ffa134447..00000000000 --- a/farms/farm-ctrl/metadata/pools/saber/pools_and_farms.json +++ /dev/null @@ -1,21461 +0,0 @@ -{ - "addresses": { - "landlord": "B38L5x5EszUK4iqcNMAZRyaJx8ie8cgGvxxbYmkWkjZe", - "landlordBase": "GHxgjDJgpUkugb2cPvaKQSbkdoHYHCHo2ZZsRFiFt4YL", - "rewarder": "rXhAofQCT7NN9TUqigyEAUzV1uLL4boeD8CRkNBSkYk", - "mintWrapper": "EVVDA3ZiAjTizemLGXNUN3gb6cffQFEYkFjFZokPmUPz", - "iouMint": "iouQcQBAiEXe6cKLS85zmZxUqaCqBdeHFpqKoSz615u", - "redeemer": "CL9wkGFT3SZRRNa9dgaovuRV7jrVVigBUZ6DjcgySsCU", - "sbr": "Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1" - }, - "pools": [ - { - "id": "aadai", - "name": "aaDAI-USDC", - "tokens": [ - { - "name": "Wrapped DAI (Allbridge from Avalanche)", - "symbol": "aaDAI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EgQ3yNtVhdHz7g1ZhjfGbxhFKMPPaFkz8QHXM5RBZBgi.png", - "decimals": 9, - "address": "EgQ3yNtVhdHz7g1ZhjfGbxhFKMPPaFkz8QHXM5RBZBgi", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "multi-collateral-dai", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped DAI (Allbridge from Avalanche)", - "symbol": "aaDAI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EgQ3yNtVhdHz7g1ZhjfGbxhFKMPPaFkz8QHXM5RBZBgi.png", - "decimals": 9, - "address": "EgQ3yNtVhdHz7g1ZhjfGbxhFKMPPaFkz8QHXM5RBZBgi", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "multi-collateral-dai", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped DAI (Allbridge from Avalanche)", - "symbol": "aaDAI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EgQ3yNtVhdHz7g1ZhjfGbxhFKMPPaFkz8QHXM5RBZBgi.png", - "decimals": 9, - "address": "EgQ3yNtVhdHz7g1ZhjfGbxhFKMPPaFkz8QHXM5RBZBgi", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "multi-collateral-dai", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "aaDAI-USDC", - "name": "Saber aaDAI-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/AVDuGckLavyLr5YifViaxnoveY6rwqDezHw5kiKiRQEC.png", - "decimals": 9, - "address": "AVDuGckLavyLr5YifViaxnoveY6rwqDezHw5kiKiRQEC", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/aadai", - "underlyingTokens": [ - "EgQ3yNtVhdHz7g1ZhjfGbxhFKMPPaFkz8QHXM5RBZBgi", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "source": "saber" - } - }, - "plotKey": "3Ykczfea6RPUW5oVNiZr7UFn4y9799syMCyhRTiv5jCN", - "swap": { - "config": { - "swapAccount": "SQDY9uoDoCbNq7F3HAHYYQZbrUzpKxDtdWLvYcqBLak", - "authority": "J5DTF99jm9xjWwcDcMgYxRcsPT6ydE936Qry76oLKSXe", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "AVDuGckLavyLr5YifViaxnoveY6rwqDezHw5kiKiRQEC", - "adminAccount": "AUMZDG77zj4G4Ex9bfB3TsNaCQLb1m3WTRM9Dmb6VUgU", - "tokenA": { - "adminFeeAccount": "nukUCjiUHV3XxsQGfigvxAHRLrJprpB45oQ2PHB1Bue", - "mint": "EgQ3yNtVhdHz7g1ZhjfGbxhFKMPPaFkz8QHXM5RBZBgi", - "reserve": "GiehZ4X2uQjhEKuxSm3ACmEFrabxh3RTvjbLfLjw1xGX" - }, - "tokenB": { - "adminFeeAccount": "EjFDsYacwgvHNWQR8eBRA4cFTDWxfeNrkgmdV3cjrMXH", - "mint": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "reserve": "rxDQYV77NKRKYxCjq4cECX3QQsiSyLv1T1FT2X3zNA2" - }, - "initialAmpFactor": "c8", - "targetAmpFactor": "c8", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "228rDhwVZrJkwgFiMq7AHp5L9PdHJS8p8Ta8z8DP4ABh" - }, - { - "id": "aausdc", - "name": "aaUSDC-USDC", - "tokens": [ - { - "name": "Wrapped USDC (Allbridge from Avalanche)", - "symbol": "aaUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/8Yv9Jz4z7BUHP68dz8E8m3tMe6NKgpMUKn8KVqrPA6Fr.png", - "decimals": 9, - "address": "8Yv9Jz4z7BUHP68dz8E8m3tMe6NKgpMUKn8KVqrPA6Fr", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "usd-coin", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped USDC (Allbridge from Avalanche)", - "symbol": "aaUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/8Yv9Jz4z7BUHP68dz8E8m3tMe6NKgpMUKn8KVqrPA6Fr.png", - "decimals": 9, - "address": "8Yv9Jz4z7BUHP68dz8E8m3tMe6NKgpMUKn8KVqrPA6Fr", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "usd-coin", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped USDC (Allbridge from Avalanche)", - "symbol": "aaUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/8Yv9Jz4z7BUHP68dz8E8m3tMe6NKgpMUKn8KVqrPA6Fr.png", - "decimals": 9, - "address": "8Yv9Jz4z7BUHP68dz8E8m3tMe6NKgpMUKn8KVqrPA6Fr", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "usd-coin", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "aaUSDC-USDC", - "name": "Saber aaUSDC-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/AVC7uVb6R9B34T8zWxQMEK8twvYk26U71gworsujxFNv.png", - "decimals": 9, - "address": "AVC7uVb6R9B34T8zWxQMEK8twvYk26U71gworsujxFNv", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/aausdc", - "underlyingTokens": [ - "8Yv9Jz4z7BUHP68dz8E8m3tMe6NKgpMUKn8KVqrPA6Fr", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "source": "saber" - } - }, - "plotKey": "E7FkwDpycCuU7Y9n8J1jnPTxYH5DXMis9gEP9sCEsazJ", - "swap": { - "config": { - "swapAccount": "KEVpg4SYCVrqFxKijQH6hm4QxsRdoE51ud64bEEFUC9", - "authority": "BHKzitonCpp1LBEZ2eqs3TZXB1wJxLbisS18LbE3aJos", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "AVC7uVb6R9B34T8zWxQMEK8twvYk26U71gworsujxFNv", - "adminAccount": "6ybivegrcHWjN6ec3pMos33wEpGCoM4xTFvXTewQPm7q", - "tokenA": { - "adminFeeAccount": "CNTMofwvbkcHKHKbmXBPZ6Vur81QzUPmkkt5a9KSnVvm", - "mint": "8Yv9Jz4z7BUHP68dz8E8m3tMe6NKgpMUKn8KVqrPA6Fr", - "reserve": "2bPenuBYfqzD8p5dFjCcggwkHDsc2RQDnx9AoyYGUBjA" - }, - "tokenB": { - "adminFeeAccount": "8WUjnjugE72SZp9xpNu9VBLiXk9qLxGcMV1eRUvxmVhN", - "mint": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "reserve": "AE6n6iLuX8oYu61vt5hoDYkjswpnxFxrhSehxrnQTnbx" - }, - "initialAmpFactor": "03e8", - "targetAmpFactor": "03e8", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "A8NH6Fk92PLzQAGwwAY3b2e9Zuryiisvu8WUceu95QK6" - }, - { - "id": "aausdt", - "name": "aaUSDT-USDT", - "tokens": [ - { - "name": "Wrapped USDT (Allbridge from Avalanche)", - "symbol": "aaUSDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FwEHs3kJEdMa2qZHv7SgzCiFXUQPEycEXksfBkwmS8gj.svg", - "decimals": 9, - "address": "FwEHs3kJEdMa2qZHv7SgzCiFXUQPEycEXksfBkwmS8gj", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "tether", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USDT (9 decimals)", - "address": "AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV", - "decimals": 9, - "symbol": "sUSDT-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD", - "assetContract": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "underlyingTokens": ["Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped USDT (Allbridge from Avalanche)", - "symbol": "aaUSDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FwEHs3kJEdMa2qZHv7SgzCiFXUQPEycEXksfBkwmS8gj.svg", - "decimals": 9, - "address": "FwEHs3kJEdMa2qZHv7SgzCiFXUQPEycEXksfBkwmS8gj", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "tether", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USDT (9 decimals)", - "address": "AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV", - "decimals": 9, - "symbol": "sUSDT-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD", - "assetContract": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "underlyingTokens": ["Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped USDT (Allbridge from Avalanche)", - "symbol": "aaUSDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FwEHs3kJEdMa2qZHv7SgzCiFXUQPEycEXksfBkwmS8gj.svg", - "decimals": 9, - "address": "FwEHs3kJEdMa2qZHv7SgzCiFXUQPEycEXksfBkwmS8gj", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "tether", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "USDT", - "symbol": "USDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB.svg", - "decimals": 6, - "address": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://tether.to/", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "aaUSDT-USDT", - "name": "Saber aaUSDT-USDT LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/AVTrxHq5P57fYZTYjMuCRWFqsrLmom2gGThNtgEgK1ip.png", - "decimals": 9, - "address": "AVTrxHq5P57fYZTYjMuCRWFqsrLmom2gGThNtgEgK1ip", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/aausdt", - "underlyingTokens": [ - "FwEHs3kJEdMa2qZHv7SgzCiFXUQPEycEXksfBkwmS8gj", - "AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV" - ], - "source": "saber" - } - }, - "plotKey": "EArh8iMeXdec81F6uir7yiVpkGf7amVA8RzScEq7ukZv", - "swap": { - "config": { - "swapAccount": "SEQV6QiTpvTzrceiaYg9Avnwf7oc8ZALpnQMz6TyT4A", - "authority": "EPtXq2vDbFdpxVUuS4qzh5dhnWHQeriNyz7Tvyott2DB", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "AVTrxHq5P57fYZTYjMuCRWFqsrLmom2gGThNtgEgK1ip", - "adminAccount": "9aTprpcd8G3ViCmgL2PHexTjRxDkTuvEfANqs9RZz4Kq", - "tokenA": { - "adminFeeAccount": "BBi8KR5tMQDVzTdRBXq36nGSnYLTiTumyKtBfuDhzopA", - "mint": "FwEHs3kJEdMa2qZHv7SgzCiFXUQPEycEXksfBkwmS8gj", - "reserve": "3dFMPj4r9mMmPHF32mz1gNDX7f8ftidWof7S8YiYTs1j" - }, - "tokenB": { - "adminFeeAccount": "53QXsoLfDjY6P2njBCx85zLVJZGTH6nmnZhzyYHXkvHC", - "mint": "AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV", - "reserve": "Fc1ED3YPeQfXQosHbd8DTaBd2AV5gHQtwiSAL5C5pUhi" - }, - "initialAmpFactor": "03e8", - "targetAmpFactor": "03e8", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "9chpeWW6MAjYZrgSB1AHRmJXTzBHKW2agbxqF4qMWNvz" - }, - { - "id": "aawbtc", - "name": "aaWBTC-renBTC", - "tokens": [ - { - "name": "Wrapped BTC (Allbridge from Avalanche)", - "symbol": "aaWBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Fd8xyHHRjTvxfZrBirb6MaxSmrZYw99gRSqFUKdFwFvw.png", - "decimals": 9, - "address": "Fd8xyHHRjTvxfZrBirb6MaxSmrZYw99gRSqFUKdFwFvw", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "coingeckoId": "wrapped-bitcoin", - "source": "allbridge", - "currency": "BTC", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped renBTC (9 decimals)", - "address": "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5", - "decimals": 9, - "symbol": "srenBTC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5.png", - "tags": ["saber-mkt-btc", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint", - "assetContract": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "underlyingTokens": ["CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped BTC (Allbridge from Avalanche)", - "symbol": "aaWBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Fd8xyHHRjTvxfZrBirb6MaxSmrZYw99gRSqFUKdFwFvw.png", - "decimals": 9, - "address": "Fd8xyHHRjTvxfZrBirb6MaxSmrZYw99gRSqFUKdFwFvw", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "coingeckoId": "wrapped-bitcoin", - "source": "allbridge", - "currency": "BTC", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped renBTC (9 decimals)", - "address": "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5", - "decimals": 9, - "symbol": "srenBTC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5.png", - "tags": ["saber-mkt-btc", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint", - "assetContract": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "underlyingTokens": ["CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped BTC (Allbridge from Avalanche)", - "symbol": "aaWBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Fd8xyHHRjTvxfZrBirb6MaxSmrZYw99gRSqFUKdFwFvw.png", - "decimals": 9, - "address": "Fd8xyHHRjTvxfZrBirb6MaxSmrZYw99gRSqFUKdFwFvw", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "coingeckoId": "wrapped-bitcoin", - "source": "allbridge", - "currency": "BTC", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "renBTC", - "symbol": "renBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5.png", - "decimals": 8, - "address": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "website": "https://renproject.io/", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint" - } - } - ], - "currency": "BTC", - "lpToken": { - "symbol": "aaWBTC-renBTC", - "name": "Saber aaWBTC-renBTC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/AVBDpg1UYpDYQLbzEnRY76R3u82PYHtDuc3NBdFS2k39.png", - "decimals": 9, - "address": "AVBDpg1UYpDYQLbzEnRY76R3u82PYHtDuc3NBdFS2k39", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/aawbtc", - "underlyingTokens": [ - "Fd8xyHHRjTvxfZrBirb6MaxSmrZYw99gRSqFUKdFwFvw", - "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5" - ], - "source": "saber" - } - }, - "plotKey": "AxFsScUmiukmLuwdToMCTbAWWCMisV3afc2XdptFttYU", - "swap": { - "config": { - "swapAccount": "SATqdxinH3vFiJBKv3JA6MuCXweEXr6UV1aRcvGjLD5", - "authority": "BQsXo2y2KFdPpF9v9ckb1BaxSQxqgx12WevS8BYnkYhY", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 253, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "AVBDpg1UYpDYQLbzEnRY76R3u82PYHtDuc3NBdFS2k39", - "adminAccount": "Af5NSDP2twSYUYqapmgXCEW6x72AzGNEomjaybn4WVYG", - "tokenA": { - "adminFeeAccount": "RtzSS4SK88PUSUmajnevo7gUs7zDnYU8qFBfLicaWpm", - "mint": "Fd8xyHHRjTvxfZrBirb6MaxSmrZYw99gRSqFUKdFwFvw", - "reserve": "bDVSLHopvEo45R3rR7JXoRRAcnUXKD7r14ijj1apALb" - }, - "tokenB": { - "adminFeeAccount": "EPXkgmVmpNPnrT2hZgaQwxWpnDYynvUP3n8fhPSRf581", - "mint": "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5", - "reserve": "33QrhvkyroiTxp21hbXPRowPhsgVHmrgEQbY7eHPp1h4" - }, - "initialAmpFactor": "c8", - "targetAmpFactor": "c8", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "6r6zEtUZghQmWsPpLFRwMvnoRja3SNDUaS72NUuQsFia" - }, - { - "id": "abbtcb", - "name": "abBTCB-renBTC", - "tokens": [ - { - "name": "Wrapped BTC (Allbridge from BSC)", - "symbol": "abBTCB", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/3os2M3bX9qta154PRbU9rzaPUYAKAqVpaMMS8u2hoUQu.png", - "decimals": 9, - "address": "3os2M3bX9qta154PRbU9rzaPUYAKAqVpaMMS8u2hoUQu", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "coingeckoId": "wrapped-bitcoin", - "source": "allbridge", - "currency": "BTC", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped renBTC (9 decimals)", - "address": "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5", - "decimals": 9, - "symbol": "srenBTC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5.png", - "tags": ["saber-mkt-btc", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint", - "assetContract": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "underlyingTokens": ["CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped BTC (Allbridge from BSC)", - "symbol": "abBTCB", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/3os2M3bX9qta154PRbU9rzaPUYAKAqVpaMMS8u2hoUQu.png", - "decimals": 9, - "address": "3os2M3bX9qta154PRbU9rzaPUYAKAqVpaMMS8u2hoUQu", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "coingeckoId": "wrapped-bitcoin", - "source": "allbridge", - "currency": "BTC", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped renBTC (9 decimals)", - "address": "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5", - "decimals": 9, - "symbol": "srenBTC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5.png", - "tags": ["saber-mkt-btc", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint", - "assetContract": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "underlyingTokens": ["CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped BTC (Allbridge from BSC)", - "symbol": "abBTCB", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/3os2M3bX9qta154PRbU9rzaPUYAKAqVpaMMS8u2hoUQu.png", - "decimals": 9, - "address": "3os2M3bX9qta154PRbU9rzaPUYAKAqVpaMMS8u2hoUQu", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "coingeckoId": "wrapped-bitcoin", - "source": "allbridge", - "currency": "BTC", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "renBTC", - "symbol": "renBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5.png", - "decimals": 8, - "address": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "website": "https://renproject.io/", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint" - } - } - ], - "currency": "BTC", - "lpToken": { - "symbol": "abBTCB-renBTC", - "name": "Saber abBTCB-renBTC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/ALPb4SssuKFScyUFnTcXLtF3NAkwFuFpQFric5yo4Qpo.png", - "decimals": 9, - "address": "ALPb4SssuKFScyUFnTcXLtF3NAkwFuFpQFric5yo4Qpo", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/abbtcb", - "underlyingTokens": [ - "3os2M3bX9qta154PRbU9rzaPUYAKAqVpaMMS8u2hoUQu", - "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5" - ], - "source": "saber" - } - }, - "plotKey": "7W8RmcLfWCivm73RAwXAWkgQupt6bQqUUJksEcCMJWfR", - "swap": { - "config": { - "swapAccount": "BSCc2UgHMGZcr4gdTBZcDvf7HcjVdfBDrW7gMnaqSDkx", - "authority": "J2HsPo8fNKNhSZcUn3EfPjekbwSwA3LUTS2Yj8wz8hL2", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "ALPb4SssuKFScyUFnTcXLtF3NAkwFuFpQFric5yo4Qpo", - "adminAccount": "YjkXQ6dYeZ9rVmFDvmZSbMJTZDVX881ambsYMmEhwQY", - "tokenA": { - "adminFeeAccount": "3znpKzaBHybUfyo96z9jf1D38Ciadzwrrku6iDhsdkKA", - "mint": "3os2M3bX9qta154PRbU9rzaPUYAKAqVpaMMS8u2hoUQu", - "reserve": "3aQn9HbPXwxCLEd71x81K1whfHvMe18bEwPtqPArA68d" - }, - "tokenB": { - "adminFeeAccount": "7qN4wY2ZqQQJY5PvafJFQTtzWnCvVEcD8vDpJL9P3Rfg", - "mint": "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5", - "reserve": "5KMjfTVueu78hnEaUNKPTQmKkEnUrwTGD9r8YFKXXxy7" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "4ywU1D73ip7hf5ZqLWdGsRVpLtNPnw39FDNPHQTVccC" - }, - { - "id": "abbusd", - "name": "abBUSD-USDC", - "tokens": [ - { - "name": "Wrapped BUSD (Allbridge from BSC)", - "symbol": "abBUSD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/6nuaX3ogrr2CaoAPjtaKHAoBNWok32BMcRozuf32s2QF.png", - "decimals": 9, - "address": "6nuaX3ogrr2CaoAPjtaKHAoBNWok32BMcRozuf32s2QF", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "binance-usd", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped BUSD (Allbridge from BSC)", - "symbol": "abBUSD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/6nuaX3ogrr2CaoAPjtaKHAoBNWok32BMcRozuf32s2QF.png", - "decimals": 9, - "address": "6nuaX3ogrr2CaoAPjtaKHAoBNWok32BMcRozuf32s2QF", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "binance-usd", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped BUSD (Allbridge from BSC)", - "symbol": "abBUSD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/6nuaX3ogrr2CaoAPjtaKHAoBNWok32BMcRozuf32s2QF.png", - "decimals": 9, - "address": "6nuaX3ogrr2CaoAPjtaKHAoBNWok32BMcRozuf32s2QF", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "binance-usd", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "abBUSD-USDC", - "name": "Saber abBUSD-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BUSDjE9NEQ15aRFTxKFAjUf5vzqBhEgTNbYevWcSB5qp.png", - "decimals": 9, - "address": "BUSDjE9NEQ15aRFTxKFAjUf5vzqBhEgTNbYevWcSB5qp", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/abbusd", - "underlyingTokens": [ - "6nuaX3ogrr2CaoAPjtaKHAoBNWok32BMcRozuf32s2QF", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "source": "saber" - } - }, - "plotKey": "7JxiFeTn7UrUbmHPvzgUQNz4YupH1GZXGa7Z4qTy2zPT", - "swap": { - "config": { - "swapAccount": "BSCNHw8CmxbZ8hCWWzMf5FaG2ajPT6JxfznKUNuRVrn4", - "authority": "ASniuTkvzrbk5gpV4mkibbFvyzL62ACdDBmLqeHxpvaB", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "BUSDjE9NEQ15aRFTxKFAjUf5vzqBhEgTNbYevWcSB5qp", - "adminAccount": "EwgFFpLxc4GX8NW3FkFg6z1sZNrUdxxGG9wNZFzfoNpq", - "tokenA": { - "adminFeeAccount": "fBhDGfJFCDJKe3mra22UP2Twkbh6WQQkqkafLaYgY71", - "mint": "6nuaX3ogrr2CaoAPjtaKHAoBNWok32BMcRozuf32s2QF", - "reserve": "7n9kgNL633yGzCYksgnzHyjG73ZLBAwvEae5sbAekbzW" - }, - "tokenB": { - "adminFeeAccount": "2DbTjbNJmfRNhTcajqpCQDPef3gKZN2deURXam7T2KRh", - "mint": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "reserve": "SscdxE99omdG9AiMVwmaEMQySQnCgeAh1sPj2Leutm2" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "8RA7KUL1KJaN2hgexWy6iST8XdqVv2FapB6LbkQZdkfT" - }, - { - "id": "abeth", - "name": "abETH-ETH", - "tokens": [ - { - "name": "Wrapped ETH (Allbridge from BSC)", - "symbol": "abETH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EyrnrbE5ujd3HQG5PZd9MbECN9yaQrqc8pRwGtaLoyC.png", - "decimals": 9, - "address": "EyrnrbE5ujd3HQG5PZd9MbECN9yaQrqc8pRwGtaLoyC", - "chainId": 101, - "tags": ["saber-mkt-eth"], - "extensions": { - "coingeckoId": "weth", - "source": "allbridge", - "currency": "ETH", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped Ether (Wormhole) (9 decimals)", - "address": "KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma", - "decimals": 9, - "symbol": "sETH-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma.png", - "tags": [ - "wrapped", - "wormhole", - "saber-mkt-eth", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "serumV3Usdt": "ch7kmPrtoQUSEPBggcNAvLGiMQkJagVwd3gDYfd8m7Q", - "serumV3Usdc": "8Gmi2HhZmwQPVdCwzS7CM66MGstMXPcTVHA7jF19cLZz", - "coingeckoId": "ethereum", - "source": "wormhole-v2", - "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "currency": "ETH", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "website": "https://app.saber.so", - "underlyingTokens": ["7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped ETH (Allbridge from BSC)", - "symbol": "abETH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EyrnrbE5ujd3HQG5PZd9MbECN9yaQrqc8pRwGtaLoyC.png", - "decimals": 9, - "address": "EyrnrbE5ujd3HQG5PZd9MbECN9yaQrqc8pRwGtaLoyC", - "chainId": 101, - "tags": ["saber-mkt-eth"], - "extensions": { - "coingeckoId": "weth", - "source": "allbridge", - "currency": "ETH", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped Ether (Wormhole) (9 decimals)", - "address": "KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma", - "decimals": 9, - "symbol": "sETH-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma.png", - "tags": [ - "wrapped", - "wormhole", - "saber-mkt-eth", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "serumV3Usdt": "ch7kmPrtoQUSEPBggcNAvLGiMQkJagVwd3gDYfd8m7Q", - "serumV3Usdc": "8Gmi2HhZmwQPVdCwzS7CM66MGstMXPcTVHA7jF19cLZz", - "coingeckoId": "ethereum", - "source": "wormhole-v2", - "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "currency": "ETH", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "website": "https://app.saber.so", - "underlyingTokens": ["7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped ETH (Allbridge from BSC)", - "symbol": "abETH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EyrnrbE5ujd3HQG5PZd9MbECN9yaQrqc8pRwGtaLoyC.png", - "decimals": 9, - "address": "EyrnrbE5ujd3HQG5PZd9MbECN9yaQrqc8pRwGtaLoyC", - "chainId": 101, - "tags": ["saber-mkt-eth"], - "extensions": { - "coingeckoId": "weth", - "source": "allbridge", - "currency": "ETH", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Ether (Wormhole)", - "symbol": "ETH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs.png", - "decimals": 8, - "address": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-eth", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "serumV3Usdt": "ch7kmPrtoQUSEPBggcNAvLGiMQkJagVwd3gDYfd8m7Q", - "serumV3Usdc": "8Gmi2HhZmwQPVdCwzS7CM66MGstMXPcTVHA7jF19cLZz", - "coingeckoId": "ethereum", - "source": "wormhole-v2", - "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "currency": "ETH", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "currency": "ETH", - "lpToken": { - "symbol": "abETH-ETH", - "name": "Saber abETH-ETH LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/ALPi51sXwH9kNcQuneDwz7kPzJs3hJ5xV6SmnuyqodQP.png", - "decimals": 9, - "address": "ALPi51sXwH9kNcQuneDwz7kPzJs3hJ5xV6SmnuyqodQP", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/abeth", - "underlyingTokens": [ - "EyrnrbE5ujd3HQG5PZd9MbECN9yaQrqc8pRwGtaLoyC", - "KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma" - ], - "source": "saber" - } - }, - "plotKey": "CcGGeZNo1ZD9gNkwXNnVLg8DPmgPNcqpuVYT1fsjUoPX", - "swap": { - "config": { - "swapAccount": "BSCrK1Nx9PXU9mF7STWWBqeHLxmtJDr9h7jheEy4tAWX", - "authority": "FM2ki4WkVhAEeqbnbpeAK6iZfTbGSWxZJ7cjJmzmTA69", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "ALPi51sXwH9kNcQuneDwz7kPzJs3hJ5xV6SmnuyqodQP", - "adminAccount": "Gg3592hMiqEwGn8q3RmQ4Jfwpz82CKBRVSzh8ibmNRbF", - "tokenA": { - "adminFeeAccount": "CmAmwGXwhRuBqUHzJcxghhAiw48rgiDyzA2ERt4RDWfp", - "mint": "EyrnrbE5ujd3HQG5PZd9MbECN9yaQrqc8pRwGtaLoyC", - "reserve": "FfSySSbVJPvEo5a5AvrP3nySoXpRE2QPn1uUMpJJ1x7v" - }, - "tokenB": { - "adminFeeAccount": "Fyx1ydTc4mFKibx64xdqLbxcvmknTRXU466BzvV13m3A", - "mint": "KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma", - "reserve": "HL7Vcj6838ZmvBHDbQxXfjBNckNi83WvPiZQoMQLFeRM" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "3gx2cvAG1kwCcmGHPekfGESeFKchbVdXKC5uyesb6D8S" - }, - { - "id": "abusdc", - "name": "abUSDC-USDC", - "tokens": [ - { - "name": "Wrapped USDC (Allbridge from BSC)", - "symbol": "abUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/8XSsNvaKU9FDhYWAv7Yc7qSNwuJSzVrXBNEk7AFiWF69.png", - "decimals": 9, - "address": "8XSsNvaKU9FDhYWAv7Yc7qSNwuJSzVrXBNEk7AFiWF69", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "usd-coin", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped USDC (Allbridge from BSC)", - "symbol": "abUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/8XSsNvaKU9FDhYWAv7Yc7qSNwuJSzVrXBNEk7AFiWF69.png", - "decimals": 9, - "address": "8XSsNvaKU9FDhYWAv7Yc7qSNwuJSzVrXBNEk7AFiWF69", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "usd-coin", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped USDC (Allbridge from BSC)", - "symbol": "abUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/8XSsNvaKU9FDhYWAv7Yc7qSNwuJSzVrXBNEk7AFiWF69.png", - "decimals": 9, - "address": "8XSsNvaKU9FDhYWAv7Yc7qSNwuJSzVrXBNEk7AFiWF69", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "usd-coin", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "abUSDC-USDC", - "name": "Saber abUSDC-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/ALPX6x8FkkdQyn9YuoVZjPAapL4nUC7vjJ3AtwStmj9P.png", - "decimals": 9, - "address": "ALPX6x8FkkdQyn9YuoVZjPAapL4nUC7vjJ3AtwStmj9P", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/abusdc", - "underlyingTokens": [ - "8XSsNvaKU9FDhYWAv7Yc7qSNwuJSzVrXBNEk7AFiWF69", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "source": "saber" - } - }, - "plotKey": "BYT3ChoaPk1vq3s8rUYaAM3RKC25pn2fuc9Ub1w2J37r", - "swap": { - "config": { - "swapAccount": "BSC8REUo9LpiiWUuqMuLXs2D2yJsJfGd4HdiF3wCLxk5", - "authority": "GoGTHycKo5ti1Lwyk1ZVa2Y6yka2z6Q6cLNEUQ2e1g1w", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "ALPX6x8FkkdQyn9YuoVZjPAapL4nUC7vjJ3AtwStmj9P", - "adminAccount": "EmQPm3GhtohMAEji2fLNChYCzQQLTeby4ezRgRSWrkuk", - "tokenA": { - "adminFeeAccount": "CEyUANqRyrsnxGFotH8QvfYibCU5PBWGGciWd9BqyLAN", - "mint": "8XSsNvaKU9FDhYWAv7Yc7qSNwuJSzVrXBNEk7AFiWF69", - "reserve": "AZjEH1zWVx1UJ6udMyRijGTzPteuLnaY18yNNmprJEsh" - }, - "tokenB": { - "adminFeeAccount": "GMFegvR5GGMtddaainUXQgwctFdEWuzcWq7iPHQmXpLp", - "mint": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "reserve": "Caf8ypkSVR8xYnXNhjvfvdGCC7mrM3C11rz8Xi6NA6aK" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "FTxEbVX18g592J2EjxVg1BcHfCES7pgcnFo2VPcPAKLT" - }, - { - "id": "abusdt", - "name": "abUSDT-USDT", - "tokens": [ - { - "name": "Wrapped USDT (Allbridge from BSC)", - "symbol": "abUSDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/E77cpQ4VncGmcAXX16LHFFzNBEBb2U7Ar7LBmZNfCgwL.png", - "decimals": 9, - "address": "E77cpQ4VncGmcAXX16LHFFzNBEBb2U7Ar7LBmZNfCgwL", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "tether", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USDT (9 decimals)", - "address": "AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV", - "decimals": 9, - "symbol": "sUSDT-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD", - "assetContract": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "underlyingTokens": ["Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped USDT (Allbridge from BSC)", - "symbol": "abUSDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/E77cpQ4VncGmcAXX16LHFFzNBEBb2U7Ar7LBmZNfCgwL.png", - "decimals": 9, - "address": "E77cpQ4VncGmcAXX16LHFFzNBEBb2U7Ar7LBmZNfCgwL", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "tether", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USDT (9 decimals)", - "address": "AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV", - "decimals": 9, - "symbol": "sUSDT-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD", - "assetContract": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "underlyingTokens": ["Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped USDT (Allbridge from BSC)", - "symbol": "abUSDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/E77cpQ4VncGmcAXX16LHFFzNBEBb2U7Ar7LBmZNfCgwL.png", - "decimals": 9, - "address": "E77cpQ4VncGmcAXX16LHFFzNBEBb2U7Ar7LBmZNfCgwL", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "tether", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "USDT", - "symbol": "USDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB.svg", - "decimals": 6, - "address": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://tether.to/", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "abUSDT-USDT", - "name": "Saber abUSDT-USDT LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/ALPaPPo6xmeGv3a63Pc4S8NJFAAuchhD7XnkkWJqzvXJ.png", - "decimals": 9, - "address": "ALPaPPo6xmeGv3a63Pc4S8NJFAAuchhD7XnkkWJqzvXJ", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/abusdt", - "underlyingTokens": [ - "E77cpQ4VncGmcAXX16LHFFzNBEBb2U7Ar7LBmZNfCgwL", - "AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV" - ], - "source": "saber" - } - }, - "plotKey": "EYYvECq9LVXbHcuQxWkcXGangVwYy2iBntKVuSNEKW9Z", - "swap": { - "config": { - "swapAccount": "BSCuChvaSj9b5HUSqgDVRzcnr2sSn7cXaamt1jbKH6hn", - "authority": "68VHM1QsAEQo2kCRh2Gu5ztN9fzLfuk9VpX76LCvpjxx", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "ALPaPPo6xmeGv3a63Pc4S8NJFAAuchhD7XnkkWJqzvXJ", - "adminAccount": "CTYdY7w4DHkXH8QqE4a1cBMTrhm5wzY6kcHigMUzBfFt", - "tokenA": { - "adminFeeAccount": "CVhgD36UCXPz581ZhGRwcX4tgQtTWeEkJHwCztSjZMAP", - "mint": "E77cpQ4VncGmcAXX16LHFFzNBEBb2U7Ar7LBmZNfCgwL", - "reserve": "GnKpRj5kBVPMJfiwZtEuD9GYApLzPdW5JFuZTcyX4BTc" - }, - "tokenB": { - "adminFeeAccount": "CHKcqWS3v9wL4RRXZAMHj359Kiy2DnFLwsNhzjRntnkF", - "mint": "AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV", - "reserve": "3dmwD9okkomV9nDwyuh4UMhKdUR13QpuKxRo89ycZB5t" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "AJExbb6wfD71dUD7QCcQASmHB5B6VqzWV9UjrCHsdDbU" - }, - { - "id": "aceur_ageur", - "name": "acEUR-agEUR", - "tokens": [ - { - "name": "Wrapped CEUR (Allbridge from Celo)", - "symbol": "acEUR", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7g166TuBmnoHKvS2PEkZx6kREZtbfjUxCHGWjCqoDXZv.png", - "decimals": 9, - "address": "7g166TuBmnoHKvS2PEkZx6kREZtbfjUxCHGWjCqoDXZv", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-eur"], - "extensions": { - "coingeckoId": "celo-euro", - "source": "allbridge", - "currency": "EUR", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped agEUR (Wormhole) (9 decimals)", - "address": "EU9aLffrTckFCs16da6CppHy63fAxMPF9ih1erQTuuRt", - "decimals": 9, - "symbol": "sagEUR-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EU9aLffrTckFCs16da6CppHy63fAxMPF9ih1erQTuuRt.png", - "tags": [ - "ethereum", - "wrapped", - "wormhole", - "saber-mkt-eur", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "website": "https://app.saber.so", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "CbNYA9n3927uXUukee2Hf4tm3xxkffJPPZvGazc2EAH1", - "twitter": "https://twitter.com/AngleProtocol", - "discord": "https://discord.gg/z3kCpTaKMh", - "coingeckoId": "ageur", - "description": "Angle is the first decentralized, capital efficient and over-collateralized stablecoin protocol", - "source": "wormhole-v2", - "address": "0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8", - "currency": "EUR", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "underlyingTokens": ["CbNYA9n3927uXUukee2Hf4tm3xxkffJPPZvGazc2EAH1"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped CEUR (Allbridge from Celo)", - "symbol": "acEUR", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7g166TuBmnoHKvS2PEkZx6kREZtbfjUxCHGWjCqoDXZv.png", - "decimals": 9, - "address": "7g166TuBmnoHKvS2PEkZx6kREZtbfjUxCHGWjCqoDXZv", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-eur"], - "extensions": { - "coingeckoId": "celo-euro", - "source": "allbridge", - "currency": "EUR", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped agEUR (Wormhole) (9 decimals)", - "address": "EU9aLffrTckFCs16da6CppHy63fAxMPF9ih1erQTuuRt", - "decimals": 9, - "symbol": "sagEUR-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EU9aLffrTckFCs16da6CppHy63fAxMPF9ih1erQTuuRt.png", - "tags": [ - "ethereum", - "wrapped", - "wormhole", - "saber-mkt-eur", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "website": "https://app.saber.so", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "CbNYA9n3927uXUukee2Hf4tm3xxkffJPPZvGazc2EAH1", - "twitter": "https://twitter.com/AngleProtocol", - "discord": "https://discord.gg/z3kCpTaKMh", - "coingeckoId": "ageur", - "description": "Angle is the first decentralized, capital efficient and over-collateralized stablecoin protocol", - "source": "wormhole-v2", - "address": "0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8", - "currency": "EUR", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "underlyingTokens": ["CbNYA9n3927uXUukee2Hf4tm3xxkffJPPZvGazc2EAH1"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped CEUR (Allbridge from Celo)", - "symbol": "acEUR", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7g166TuBmnoHKvS2PEkZx6kREZtbfjUxCHGWjCqoDXZv.png", - "decimals": 9, - "address": "7g166TuBmnoHKvS2PEkZx6kREZtbfjUxCHGWjCqoDXZv", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-eur"], - "extensions": { - "coingeckoId": "celo-euro", - "source": "allbridge", - "currency": "EUR", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "agEUR (Wormhole)", - "symbol": "agEUR", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CbNYA9n3927uXUukee2Hf4tm3xxkffJPPZvGazc2EAH1.png", - "decimals": 8, - "address": "CbNYA9n3927uXUukee2Hf4tm3xxkffJPPZvGazc2EAH1", - "chainId": 101, - "tags": [ - "ethereum", - "wrapped", - "wormhole", - "saber-mkt-eur", - "wormhole-v2" - ], - "extensions": { - "website": "https://www.angle.money", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8", - "twitter": "https://twitter.com/AngleProtocol", - "discord": "https://discord.gg/z3kCpTaKMh", - "coingeckoId": "ageur", - "description": "Angle is the first decentralized, capital efficient and over-collateralized stablecoin protocol", - "source": "wormhole-v2", - "address": "0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8", - "currency": "EUR", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "currency": "EUR", - "lpToken": { - "symbol": "acEUR-agEUR", - "name": "Saber acEUR-agEUR LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/WLPJD4jW6gnWKfwfL5jyJwcxEPHKLMbncNfQwMmkzKz.png", - "decimals": 9, - "address": "WLPJD4jW6gnWKfwfL5jyJwcxEPHKLMbncNfQwMmkzKz", - "chainId": 101, - "tags": [ - "saber-stableswap-lp", - "saber-lp-allbridge", - "saber-lp-wormhole-v2" - ], - "extensions": { - "website": "https://app.saber.so/pools/aceur_ageur", - "underlyingTokens": [ - "7g166TuBmnoHKvS2PEkZx6kREZtbfjUxCHGWjCqoDXZv", - "EU9aLffrTckFCs16da6CppHy63fAxMPF9ih1erQTuuRt" - ], - "source": "saber" - } - }, - "plotKey": "7mSjbjqpdh2G1kehNHg97na1tej476JsHLuZn8yXM3jm", - "swap": { - "config": { - "swapAccount": "FREDEGdjoEe5DiyVnEvSyDAX4h7LWTg7ZkSMaZiWskbp", - "authority": "DmzotTyGA8njH9b1tNuCE2wEmCoUDr3N51UXxvb1kW9g", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "WLPJD4jW6gnWKfwfL5jyJwcxEPHKLMbncNfQwMmkzKz", - "adminAccount": "4YDTr9smZzkHefThBa9HqLJFpoHcYZdvw5MwYcyMT7ac", - "tokenA": { - "adminFeeAccount": "FD781t6F5JVPHcyvqS7g1s39hG6byboswoSS86euEVAB", - "mint": "7g166TuBmnoHKvS2PEkZx6kREZtbfjUxCHGWjCqoDXZv", - "reserve": "G5KhoiuhRBEYmX89PuZMmpG3fLdomzMJZ3yEG13hVYPD" - }, - "tokenB": { - "adminFeeAccount": "3ZBk25cxRZocKJHW9qB1XoMi9LC8DpJt5yA2mwjHyHup", - "mint": "EU9aLffrTckFCs16da6CppHy63fAxMPF9ih1erQTuuRt", - "reserve": "DuSWTAh1SC43EY86daS2Cq6PNBGGujVjLyEmc5AmQKzC" - }, - "initialAmpFactor": "4b", - "targetAmpFactor": "4b", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "DSqhEUtD1kmQAaaCRFae3UUbtPsxVLy7d8o9AYXxjXxe" - }, - { - "id": "acusd", - "name": "acUSD-USDC", - "tokens": [ - { - "name": "Wrapped CUSD (Allbridge from Celo)", - "symbol": "acUSD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EwxNF8g9UfmsJVcZFTpL9Hx5MCkoQFoJi6XNWzKf1j8e.png", - "decimals": 9, - "address": "EwxNF8g9UfmsJVcZFTpL9Hx5MCkoQFoJi6XNWzKf1j8e", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "celo-dollar", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped CUSD (Allbridge from Celo)", - "symbol": "acUSD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EwxNF8g9UfmsJVcZFTpL9Hx5MCkoQFoJi6XNWzKf1j8e.png", - "decimals": 9, - "address": "EwxNF8g9UfmsJVcZFTpL9Hx5MCkoQFoJi6XNWzKf1j8e", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "celo-dollar", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped CUSD (Allbridge from Celo)", - "symbol": "acUSD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EwxNF8g9UfmsJVcZFTpL9Hx5MCkoQFoJi6XNWzKf1j8e.png", - "decimals": 9, - "address": "EwxNF8g9UfmsJVcZFTpL9Hx5MCkoQFoJi6XNWzKf1j8e", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "celo-dollar", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "acUSD-USDC", - "name": "Saber acUSD-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/cUSDDDBZRhpDW7eyUUPMuw6u1SiMnzu6i7movwf5jxk.png", - "decimals": 9, - "address": "cUSDDDBZRhpDW7eyUUPMuw6u1SiMnzu6i7movwf5jxk", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/acusd", - "underlyingTokens": [ - "EwxNF8g9UfmsJVcZFTpL9Hx5MCkoQFoJi6XNWzKf1j8e", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "source": "saber" - } - }, - "plotKey": "JCu76hLaYzExth7DebfmSyiHV3V3BiYi7yajGBzyEq2w", - "swap": { - "config": { - "swapAccount": "moFiBS1R4Lf3E3zzmBPnw3NF4RhWPkhREFviuzUaCAU", - "authority": "4RcgjJHEndsDpSniNaU392dnfjFZFGhwUT3Fd9rSEcMv", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 253, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "cUSDDDBZRhpDW7eyUUPMuw6u1SiMnzu6i7movwf5jxk", - "adminAccount": "GxrTN2EFpAXtPhgUf4CJio2nvfUycWX3mNcXp1TC3Gzg", - "tokenA": { - "adminFeeAccount": "CUqZMfuGbFuk511eytYs23Kw2Vge5fvDeR4GHsUHPNkd", - "mint": "EwxNF8g9UfmsJVcZFTpL9Hx5MCkoQFoJi6XNWzKf1j8e", - "reserve": "44ALBrpqi9PfZkBRTvbtRNtFJGsatfY4QydjtMbFWq8S" - }, - "tokenB": { - "adminFeeAccount": "GuBiPcG1V9nXZEjKi6mrigZ18UTLnMB4Z9cCJJVmdea5", - "mint": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "reserve": "2ho8qEEie1UjVwWNBo9y4oAJZMyMLx8zPj9bxyUz6uWs" - }, - "initialAmpFactor": "c8", - "targetAmpFactor": "c8", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "64Jh71Av4M5QaEyduDJigNsa4HUBwvT2cQyi5YBSp1e4" - }, - { - "id": "acusd_cash", - "name": "acUSD-CASH", - "tokens": [ - { - "name": "Wrapped CUSD (Allbridge from Celo)", - "symbol": "acUSD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EwxNF8g9UfmsJVcZFTpL9Hx5MCkoQFoJi6XNWzKf1j8e.png", - "decimals": 9, - "address": "EwxNF8g9UfmsJVcZFTpL9Hx5MCkoQFoJi6XNWzKf1j8e", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "celo-dollar", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped Cashio Dollar (9 decimals)", - "address": "C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi", - "decimals": 9, - "symbol": "sCASH-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/", - "assetContract": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "underlyingTokens": ["CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped CUSD (Allbridge from Celo)", - "symbol": "acUSD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EwxNF8g9UfmsJVcZFTpL9Hx5MCkoQFoJi6XNWzKf1j8e.png", - "decimals": 9, - "address": "EwxNF8g9UfmsJVcZFTpL9Hx5MCkoQFoJi6XNWzKf1j8e", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "celo-dollar", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped Cashio Dollar (9 decimals)", - "address": "C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi", - "decimals": 9, - "symbol": "sCASH-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/", - "assetContract": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "underlyingTokens": ["CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped CUSD (Allbridge from Celo)", - "symbol": "acUSD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EwxNF8g9UfmsJVcZFTpL9Hx5MCkoQFoJi6XNWzKf1j8e.png", - "decimals": 9, - "address": "EwxNF8g9UfmsJVcZFTpL9Hx5MCkoQFoJi6XNWzKf1j8e", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "celo-dollar", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Cashio Dollar", - "symbol": "CASH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "decimals": 6, - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://cashio.app", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "acUSD-CASH", - "name": "Saber acUSD-CASH LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CLPLCvWFycur9CysMT3pmdkUXxPfBjXVkWyxTGntzoZ7.png", - "decimals": 9, - "address": "CLPLCvWFycur9CysMT3pmdkUXxPfBjXVkWyxTGntzoZ7", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-cashio"], - "extensions": { - "website": "https://app.saber.so/pools/acusd_cash", - "underlyingTokens": [ - "EwxNF8g9UfmsJVcZFTpL9Hx5MCkoQFoJi6XNWzKf1j8e", - "C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi" - ], - "source": "saber" - } - }, - "plotKey": "3cB2wT1h34BdL2gEcmztnPAuZtom91h6gMLBj4kbrpMs", - "swap": { - "config": { - "swapAccount": "CSPcADsTSETVpGAYFnb1oEc9z9qPjC987powM59bnSF3", - "authority": "hp26j5RH1Bx7TUThh3bkYQiSCyKnwEoyCW6mYZNvhmq", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": true, - "nonce": 253, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "CLPLCvWFycur9CysMT3pmdkUXxPfBjXVkWyxTGntzoZ7", - "adminAccount": "7k1hva3vdnoYPTxFmapBKoatU3cACxGhF52XHj5q1M5Y", - "tokenA": { - "adminFeeAccount": "FAY42f8thVtwmhTpXy3GMFJ2h919BgwqqXS9z5PFD2BW", - "mint": "EwxNF8g9UfmsJVcZFTpL9Hx5MCkoQFoJi6XNWzKf1j8e", - "reserve": "49EQuSDQNz7L4a22CcnWUxExSpYW4UXSKG985S2drLsR" - }, - "tokenB": { - "adminFeeAccount": "3bAmnJxUMK5vS28edX3KQPNkMstHhkg8KgPm9kUFc3QQ", - "mint": "C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi", - "reserve": "7DH5gc5Hj1Kq4Y9z8ybEmAX1WPoHcunwiav1Za4A5J3J" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "F5VvER2JdGfbEtPJBr92qEPJhE3b8tAA3Gi9zyPx2toa" - }, - { - "id": "acusdc", - "name": "USDC-acUSDC", - "tokens": [ - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - }, - { - "name": "Wrapped USDC (Allbridge from Celo)", - "symbol": "acUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/DHpoYejUDqzByb6HAdaLWF7KZvwUv2vWYDY9cTENNZui.png", - "decimals": 9, - "address": "DHpoYejUDqzByb6HAdaLWF7KZvwUv2vWYDY9cTENNZui", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "usd-coin", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - } - ], - "tokenIcons": [ - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - }, - { - "name": "Wrapped USDC (Allbridge from Celo)", - "symbol": "acUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/DHpoYejUDqzByb6HAdaLWF7KZvwUv2vWYDY9cTENNZui.png", - "decimals": 9, - "address": "DHpoYejUDqzByb6HAdaLWF7KZvwUv2vWYDY9cTENNZui", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "usd-coin", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - } - ], - "underlyingIcons": [ - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - }, - { - "name": "Wrapped USDC (Allbridge from Celo)", - "symbol": "acUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/DHpoYejUDqzByb6HAdaLWF7KZvwUv2vWYDY9cTENNZui.png", - "decimals": 9, - "address": "DHpoYejUDqzByb6HAdaLWF7KZvwUv2vWYDY9cTENNZui", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "usd-coin", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "USDC-acUSDC", - "name": "Saber USDC-acUSDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/GEcowHQW46CrEkfAdbcsdt4SV7taCetZF4sFBXN4USDC.png", - "decimals": 9, - "address": "GEcowHQW46CrEkfAdbcsdt4SV7taCetZF4sFBXN4USDC", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/acusdc", - "underlyingTokens": [ - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "DHpoYejUDqzByb6HAdaLWF7KZvwUv2vWYDY9cTENNZui" - ], - "source": "saber" - } - }, - "plotKey": "3dQTmwVt45BvnLSbRbnEt38Wn1WDexCBSGtsHHZdeKGH", - "swap": { - "config": { - "swapAccount": "ACUSESXyNnwRLAg1dpSGMLSzUDdLjUMybY8rkXiAKhCP", - "authority": "FMGXRh8AYYy2SiPor8yzZPECNVkjwKtwYTWPsqAJrM8W", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "GEcowHQW46CrEkfAdbcsdt4SV7taCetZF4sFBXN4USDC", - "adminAccount": "58Z22rkZWuGhYxW4ddKtEntZZjhDMxaMuwCVst3a8NXv", - "tokenA": { - "adminFeeAccount": "A6SMziGsMPKFFyS3uEHFvmvD7pbLuq32dKFh3H4JMhhq", - "mint": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "reserve": "AhFPQdu8GKBsxuhiH46UmCu1YpaLgNpoP325HnYtsgas" - }, - "tokenB": { - "adminFeeAccount": "25ZZsLmP2xRsVA6BeNeeQFmfjR2RbXY48bKLhXj3qSyB", - "mint": "DHpoYejUDqzByb6HAdaLWF7KZvwUv2vWYDY9cTENNZui", - "reserve": "A8wxWpT3aFEr2XqZp1kDmbxbFfcBE95UUmdsNTDBJYbT" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "GkiBc6Vzqhdm9jeQUDpkXfAtZdfpbfaaiwVTMqM3uMc3", - "newPoolID": "acusd_cash", - "deprecationInfo": { - "newPoolID": "acusd_cash", - "message": "The Celo Optics V1 bridge has been deprecated. Please migrate your assets over to Optics V2.", - "link": "https://medium.com/@mobiusmoney/migrating-to-the-optics-v2-bridge-5f098634d3e2" - } - }, - { - "id": "aedai", - "name": "aeDAI-USDC", - "tokens": [ - { - "name": "Wrapped DAI (Allbridge from Ethereum)", - "symbol": "aeDAI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9w6LpS7RU1DKftiwH3NgShtXbkMM1ke9iNU4g3MBXSUs.png", - "decimals": 9, - "address": "9w6LpS7RU1DKftiwH3NgShtXbkMM1ke9iNU4g3MBXSUs", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "multi-collateral-dai", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped DAI (Allbridge from Ethereum)", - "symbol": "aeDAI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9w6LpS7RU1DKftiwH3NgShtXbkMM1ke9iNU4g3MBXSUs.png", - "decimals": 9, - "address": "9w6LpS7RU1DKftiwH3NgShtXbkMM1ke9iNU4g3MBXSUs", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "multi-collateral-dai", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped DAI (Allbridge from Ethereum)", - "symbol": "aeDAI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9w6LpS7RU1DKftiwH3NgShtXbkMM1ke9iNU4g3MBXSUs.png", - "decimals": 9, - "address": "9w6LpS7RU1DKftiwH3NgShtXbkMM1ke9iNU4g3MBXSUs", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "multi-collateral-dai", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "aeDAI-USDC", - "name": "Saber aeDAI-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/aeDebgky5BssqgLo426rXoQTmGrAn1JjEXp6aXFNLic.png", - "decimals": 9, - "address": "aeDebgky5BssqgLo426rXoQTmGrAn1JjEXp6aXFNLic", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/aedai", - "underlyingTokens": [ - "9w6LpS7RU1DKftiwH3NgShtXbkMM1ke9iNU4g3MBXSUs", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "source": "saber" - } - }, - "plotKey": "BmnFpVtEmYAugDUtwZRxSN2sDyFiaRRWnU1rMGruk1sn", - "swap": { - "config": { - "swapAccount": "DA1mL7dfBow33EH5yjUuZE6SH2KeUK5zEXzsyhE5r5j5", - "authority": "99Y7Y3DwALuxnbe9YkHJNK5ReLswTq1dwaEs4yRPv7ad", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "aeDebgky5BssqgLo426rXoQTmGrAn1JjEXp6aXFNLic", - "adminAccount": "3xwhFjJR71bi44zFYwpzmRYf9AzDHJwPCRfk3ckn3PcJ", - "tokenA": { - "adminFeeAccount": "9ZWsx7cNVrQ3X8vVmqJ2X8K37U8tWBFHhX7VuWHQeXM8", - "mint": "9w6LpS7RU1DKftiwH3NgShtXbkMM1ke9iNU4g3MBXSUs", - "reserve": "B4UtLRZND3D83CitRCBUyeiNr7H8m7YFRqBmiPmXjhW4" - }, - "tokenB": { - "adminFeeAccount": "CpzjDRacBu1ZddeaT2CXQy8jDGZm4Agx61aiifhjJAFW", - "mint": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "reserve": "AAmpYbuixWiSqDaJBCqYEs1pb5SrbdPr9mgXrB58Q2e" - }, - "initialAmpFactor": "c8", - "targetAmpFactor": "c8", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "GBkRWmWtDtHwnjhhDXGuHTDbVNQAs14nbUkwNpWXE2xp" - }, - { - "id": "aeeth", - "name": "ETH-aeWETH", - "tokens": [ - { - "name": "Saber Wrapped Ether (Wormhole) (9 decimals)", - "address": "KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma", - "decimals": 9, - "symbol": "sETH-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma.png", - "tags": [ - "wrapped", - "wormhole", - "saber-mkt-eth", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "serumV3Usdt": "ch7kmPrtoQUSEPBggcNAvLGiMQkJagVwd3gDYfd8m7Q", - "serumV3Usdc": "8Gmi2HhZmwQPVdCwzS7CM66MGstMXPcTVHA7jF19cLZz", - "coingeckoId": "ethereum", - "source": "wormhole-v2", - "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "currency": "ETH", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "website": "https://app.saber.so", - "underlyingTokens": ["7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs"] - } - }, - { - "name": "Wrapped ETH (Allbridge from Ethereum)", - "symbol": "aeWETH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/AaAEw2VCw1XzgvKB8Rj2DyK2ZVau9fbt2bE8hZFWsMyE.png", - "decimals": 9, - "address": "AaAEw2VCw1XzgvKB8Rj2DyK2ZVau9fbt2bE8hZFWsMyE", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-eth"], - "extensions": { - "coingeckoId": "weth", - "source": "allbridge", - "currency": "ETH", - "sourceUrl": "https://app.allbridge.io/bridge" - } - } - ], - "tokenIcons": [ - { - "name": "Saber Wrapped Ether (Wormhole) (9 decimals)", - "address": "KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma", - "decimals": 9, - "symbol": "sETH-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma.png", - "tags": [ - "wrapped", - "wormhole", - "saber-mkt-eth", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "serumV3Usdt": "ch7kmPrtoQUSEPBggcNAvLGiMQkJagVwd3gDYfd8m7Q", - "serumV3Usdc": "8Gmi2HhZmwQPVdCwzS7CM66MGstMXPcTVHA7jF19cLZz", - "coingeckoId": "ethereum", - "source": "wormhole-v2", - "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "currency": "ETH", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "website": "https://app.saber.so", - "underlyingTokens": ["7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs"] - } - }, - { - "name": "Wrapped ETH (Allbridge from Ethereum)", - "symbol": "aeWETH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/AaAEw2VCw1XzgvKB8Rj2DyK2ZVau9fbt2bE8hZFWsMyE.png", - "decimals": 9, - "address": "AaAEw2VCw1XzgvKB8Rj2DyK2ZVau9fbt2bE8hZFWsMyE", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-eth"], - "extensions": { - "coingeckoId": "weth", - "source": "allbridge", - "currency": "ETH", - "sourceUrl": "https://app.allbridge.io/bridge" - } - } - ], - "underlyingIcons": [ - { - "name": "Ether (Wormhole)", - "symbol": "ETH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs.png", - "decimals": 8, - "address": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-eth", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "serumV3Usdt": "ch7kmPrtoQUSEPBggcNAvLGiMQkJagVwd3gDYfd8m7Q", - "serumV3Usdc": "8Gmi2HhZmwQPVdCwzS7CM66MGstMXPcTVHA7jF19cLZz", - "coingeckoId": "ethereum", - "source": "wormhole-v2", - "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "currency": "ETH", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Wrapped ETH (Allbridge from Ethereum)", - "symbol": "aeWETH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/AaAEw2VCw1XzgvKB8Rj2DyK2ZVau9fbt2bE8hZFWsMyE.png", - "decimals": 9, - "address": "AaAEw2VCw1XzgvKB8Rj2DyK2ZVau9fbt2bE8hZFWsMyE", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-eth"], - "extensions": { - "coingeckoId": "weth", - "source": "allbridge", - "currency": "ETH", - "sourceUrl": "https://app.allbridge.io/bridge" - } - } - ], - "currency": "ETH", - "lpToken": { - "symbol": "ETH-aeWETH", - "name": "Saber ETH-aeWETH LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/AET3m1Mp2SLi7QX3tSypcZWyEtk1d8dUGcwhweDiZdaR.png", - "decimals": 9, - "address": "AET3m1Mp2SLi7QX3tSypcZWyEtk1d8dUGcwhweDiZdaR", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/aeeth", - "underlyingTokens": [ - "KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma", - "AaAEw2VCw1XzgvKB8Rj2DyK2ZVau9fbt2bE8hZFWsMyE" - ], - "source": "saber" - } - }, - "plotKey": "4seZECHzhFXAF3JjQ3UnV4v6PuYqSFe7PqhJgns1mchW", - "swap": { - "config": { - "swapAccount": "ALLwa5WNZbvQsRKAqe1jdRGemdYQnW8E5k4msbRFcYtu", - "authority": "4vKg9TxAmbmBQYvsv9StJYMwyDeWNyfVSumMzmemrXbZ", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "AET3m1Mp2SLi7QX3tSypcZWyEtk1d8dUGcwhweDiZdaR", - "adminAccount": "4co23umizDKQscKkeLoY5hCP6xMkd61FGb9irUANrnhg", - "tokenA": { - "adminFeeAccount": "3YtJRF3L5gzAr42sA8n5FaNqC64haw3j8c7tL78b7Ksm", - "mint": "KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma", - "reserve": "CGoM82Hbz7QVqTgvQatYtjvDWBvoUJp5qm21P8iMs9yb" - }, - "tokenB": { - "adminFeeAccount": "DqbBwHR6s7BmmK3wJ3ZD4YVXjZd748hCTefScH2dWGWj", - "mint": "AaAEw2VCw1XzgvKB8Rj2DyK2ZVau9fbt2bE8hZFWsMyE", - "reserve": "3dxNNww8TivyN5FMy5dCNdi3Zcxv6e4kUfSPxfFwpdNq" - }, - "initialAmpFactor": "0320", - "targetAmpFactor": "0320", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "8vUrnWpraPY42kucjF5xYuFHx34Tn83b7X9TZRhx95Xd" - }, - { - "id": "aeusdc", - "name": "aeUSDC-USDC", - "tokens": [ - { - "name": "Wrapped USDC (Allbridge from Ethereum)", - "symbol": "aeUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/DdFPRnccQqLD4zCHrBqdY95D6hvw6PLWp9DEXj1fLCL9.png", - "decimals": 9, - "address": "DdFPRnccQqLD4zCHrBqdY95D6hvw6PLWp9DEXj1fLCL9", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "usd-coin", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped USDC (Allbridge from Ethereum)", - "symbol": "aeUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/DdFPRnccQqLD4zCHrBqdY95D6hvw6PLWp9DEXj1fLCL9.png", - "decimals": 9, - "address": "DdFPRnccQqLD4zCHrBqdY95D6hvw6PLWp9DEXj1fLCL9", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "usd-coin", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped USDC (Allbridge from Ethereum)", - "symbol": "aeUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/DdFPRnccQqLD4zCHrBqdY95D6hvw6PLWp9DEXj1fLCL9.png", - "decimals": 9, - "address": "DdFPRnccQqLD4zCHrBqdY95D6hvw6PLWp9DEXj1fLCL9", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "usd-coin", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "aeUSDC-USDC", - "name": "Saber aeUSDC-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/AECpyKJWfXVyWnk2d9md5dUj3RuzHRKfQra8MakjuVRz.png", - "decimals": 9, - "address": "AECpyKJWfXVyWnk2d9md5dUj3RuzHRKfQra8MakjuVRz", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/aeusdc", - "underlyingTokens": [ - "DdFPRnccQqLD4zCHrBqdY95D6hvw6PLWp9DEXj1fLCL9", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "source": "saber" - } - }, - "plotKey": "3MVjy3pn7wu3gQz5pd9GoJZwCKX1XVaikyiPLjzNTvZF", - "swap": { - "config": { - "swapAccount": "WiiQFxXqp8P9Fs1rt9SVcDyA3KUdJmUsog6wnVQAwba", - "authority": "7SYgkmnr9nFhDw9BUxFc2x2ZwY98NYfvMtMLcK67vknQ", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "AECpyKJWfXVyWnk2d9md5dUj3RuzHRKfQra8MakjuVRz", - "adminAccount": "HQCkcKVCRApHYnwcoDR85UisF5Qy6sPAuc17cZgCPGnT", - "tokenA": { - "adminFeeAccount": "C9k9hNxh8ov1E7GRjipQigN6YpbrncEhYPmPRqK2FGZ5", - "mint": "DdFPRnccQqLD4zCHrBqdY95D6hvw6PLWp9DEXj1fLCL9", - "reserve": "3S2jpqSYxho6wiz3cafhjXruVY8cg4HYa2v3BqBHYFSj" - }, - "tokenB": { - "adminFeeAccount": "ERK2MLK2UrZtpjJkqPeYNScqJrhBkjknghfu83KeV86H", - "mint": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "reserve": "Dfe67M6TfrG74gKRtdqys4e6E9QirPD53BkF4FujFjuv" - }, - "initialAmpFactor": "03e8", - "targetAmpFactor": "03e8", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0050000000", - "numerator": "5", - "denominator": "100000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "HvHCpbooc8xtvAhW5gfByfhJgNbS2G265ecQT1VBBGGw" - }, - { - "id": "aeusdt", - "name": "aeUSDT-USDT", - "tokens": [ - { - "name": "Wrapped USDT (Allbridge from Ethereum)", - "symbol": "aeUSDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Bn113WT6rbdgwrm12UJtnmNqGqZjY4it2WoUQuQopFVn.svg", - "decimals": 9, - "address": "Bn113WT6rbdgwrm12UJtnmNqGqZjY4it2WoUQuQopFVn", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "tether", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USDT (9 decimals)", - "address": "AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV", - "decimals": 9, - "symbol": "sUSDT-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD", - "assetContract": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "underlyingTokens": ["Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped USDT (Allbridge from Ethereum)", - "symbol": "aeUSDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Bn113WT6rbdgwrm12UJtnmNqGqZjY4it2WoUQuQopFVn.svg", - "decimals": 9, - "address": "Bn113WT6rbdgwrm12UJtnmNqGqZjY4it2WoUQuQopFVn", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "tether", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USDT (9 decimals)", - "address": "AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV", - "decimals": 9, - "symbol": "sUSDT-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD", - "assetContract": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "underlyingTokens": ["Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped USDT (Allbridge from Ethereum)", - "symbol": "aeUSDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Bn113WT6rbdgwrm12UJtnmNqGqZjY4it2WoUQuQopFVn.svg", - "decimals": 9, - "address": "Bn113WT6rbdgwrm12UJtnmNqGqZjY4it2WoUQuQopFVn", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "tether", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "USDT", - "symbol": "USDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB.svg", - "decimals": 6, - "address": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://tether.to/", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "aeUSDT-USDT", - "name": "Saber aeUSDT-USDT LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/aeTwxcJhujVCq6rwbJri3s6ViYifsJUCFirMjLHgHZ7.png", - "decimals": 9, - "address": "aeTwxcJhujVCq6rwbJri3s6ViYifsJUCFirMjLHgHZ7", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/aeusdt", - "underlyingTokens": [ - "Bn113WT6rbdgwrm12UJtnmNqGqZjY4it2WoUQuQopFVn", - "AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV" - ], - "source": "saber" - } - }, - "plotKey": "EXqaPwXQMvzuVLEK3NvMqyuaSWQ6PvDvFGmCmZKGun9y", - "swap": { - "config": { - "swapAccount": "TETFuZgEmET6d9vYmz9iMFCxK1jKdKYxf3oPz8hSzJK", - "authority": "3LKrJtagDoUGTCzHA6JC18uWwAoMWDbDDKGrz3q46wZV", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "aeTwxcJhujVCq6rwbJri3s6ViYifsJUCFirMjLHgHZ7", - "adminAccount": "2MGooqMi8pKNYcj6ZLHirpqVxokv9jYeSQsyHsb1s6rD", - "tokenA": { - "adminFeeAccount": "36aMFXACrfUkLVgpQFti8iPTEbcrAN2dvQLraVB9ZQi5", - "mint": "Bn113WT6rbdgwrm12UJtnmNqGqZjY4it2WoUQuQopFVn", - "reserve": "Eu1Ze6Z84LWNkq7SNoAHBJbXx5t1P95EwyqYohrfCRFV" - }, - "tokenB": { - "adminFeeAccount": "FTa81yB333ifUUxFNfw9xrAhJm19sdSwYFNJZMGzA538", - "mint": "AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV", - "reserve": "ASMbv7WNu3qe4pkhREmvyEdwFNDZQ6B6iSrjkj4u8bdC" - }, - "initialAmpFactor": "03e8", - "targetAmpFactor": "03e8", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "CVjYK5fk69mj2k8ma1yCnvFzzDFGL6fziwEaxberD7n1" - }, - { - "id": "afbtc", - "name": "afBTC-renBTC", - "tokens": [ - { - "name": "Wrapped BTC (Allbridge from Fantom)", - "symbol": "afBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FdvkkCbCgYht1xTR1W9MBJhEF1JEPVhHtW1NXBYRzZts.png", - "decimals": 9, - "address": "FdvkkCbCgYht1xTR1W9MBJhEF1JEPVhHtW1NXBYRzZts", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "coingeckoId": "wrapped-bitcoin", - "source": "allbridge", - "currency": "BTC", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped renBTC (9 decimals)", - "address": "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5", - "decimals": 9, - "symbol": "srenBTC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5.png", - "tags": ["saber-mkt-btc", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint", - "assetContract": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "underlyingTokens": ["CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped BTC (Allbridge from Fantom)", - "symbol": "afBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FdvkkCbCgYht1xTR1W9MBJhEF1JEPVhHtW1NXBYRzZts.png", - "decimals": 9, - "address": "FdvkkCbCgYht1xTR1W9MBJhEF1JEPVhHtW1NXBYRzZts", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "coingeckoId": "wrapped-bitcoin", - "source": "allbridge", - "currency": "BTC", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped renBTC (9 decimals)", - "address": "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5", - "decimals": 9, - "symbol": "srenBTC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5.png", - "tags": ["saber-mkt-btc", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint", - "assetContract": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "underlyingTokens": ["CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped BTC (Allbridge from Fantom)", - "symbol": "afBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FdvkkCbCgYht1xTR1W9MBJhEF1JEPVhHtW1NXBYRzZts.png", - "decimals": 9, - "address": "FdvkkCbCgYht1xTR1W9MBJhEF1JEPVhHtW1NXBYRzZts", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "coingeckoId": "wrapped-bitcoin", - "source": "allbridge", - "currency": "BTC", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "renBTC", - "symbol": "renBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5.png", - "decimals": 8, - "address": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "website": "https://renproject.io/", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint" - } - } - ], - "currency": "BTC", - "lpToken": { - "symbol": "afBTC-renBTC", - "name": "Saber afBTC-renBTC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/ALPoQFUuKsoN6P4gLBiKXMSaYFP9YChniKwvKAFRPvn5.png", - "decimals": 9, - "address": "ALPoQFUuKsoN6P4gLBiKXMSaYFP9YChniKwvKAFRPvn5", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/afbtc", - "underlyingTokens": [ - "FdvkkCbCgYht1xTR1W9MBJhEF1JEPVhHtW1NXBYRzZts", - "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5" - ], - "source": "saber" - } - }, - "plotKey": "89HoDAtyGandicUL1dJnFERxkdV8z5SdE37H6A94fV5V", - "swap": { - "config": { - "swapAccount": "FTMBUCDa3UxVmLQwssSj2MWYUrQiyGHXqu2ZqQbaDJqk", - "authority": "F8N4t9yAkTosjWcntzhyHTqMF7nYBBPtFKAkq2XaUwgS", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 253, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "ALPoQFUuKsoN6P4gLBiKXMSaYFP9YChniKwvKAFRPvn5", - "adminAccount": "7zkZzAfs6Z658j17LvLZaK8A9woJ6A8CPNbU1np7gzv2", - "tokenA": { - "adminFeeAccount": "6UiebXq7Ko1MLHddwMfFhZkmeVmBmvzu8xVSzjr6rT3t", - "mint": "FdvkkCbCgYht1xTR1W9MBJhEF1JEPVhHtW1NXBYRzZts", - "reserve": "D7W9WJBdwThYLCEczsxwRrHoCApqEzCXSJvWVkMs3ekH" - }, - "tokenB": { - "adminFeeAccount": "AteYRhHHM7mdX51kStXkDcF4RjhJ5JarTQaHxYdyfrBQ", - "mint": "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5", - "reserve": "HF2pNCfTMvrHXcXXb8jJU245yRx9ZtK1M76ChMW3pJht" - }, - "initialAmpFactor": "c8", - "targetAmpFactor": "c8", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "2na6Do1Qj6gQAcGenFxmU6EYRdirEmCMWoAQNy5HqnRH" - }, - { - "id": "afdai", - "name": "afDAI-USDC", - "tokens": [ - { - "name": "Wrapped DAI (Allbridge from Fantom)", - "symbol": "afDAI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/HjUhUzi6fVkY1BndaSc4Dcg2mCzvnqzXjVJtXsj78ver.png", - "decimals": 9, - "address": "HjUhUzi6fVkY1BndaSc4Dcg2mCzvnqzXjVJtXsj78ver", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "dai", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped DAI (Allbridge from Fantom)", - "symbol": "afDAI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/HjUhUzi6fVkY1BndaSc4Dcg2mCzvnqzXjVJtXsj78ver.png", - "decimals": 9, - "address": "HjUhUzi6fVkY1BndaSc4Dcg2mCzvnqzXjVJtXsj78ver", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "dai", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped DAI (Allbridge from Fantom)", - "symbol": "afDAI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/HjUhUzi6fVkY1BndaSc4Dcg2mCzvnqzXjVJtXsj78ver.png", - "decimals": 9, - "address": "HjUhUzi6fVkY1BndaSc4Dcg2mCzvnqzXjVJtXsj78ver", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "dai", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "afDAI-USDC", - "name": "Saber afDAI-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/ALPqczrbEXS8k5JF69tEPyu6TTE8qJbiwrzADfjVfKov.png", - "decimals": 9, - "address": "ALPqczrbEXS8k5JF69tEPyu6TTE8qJbiwrzADfjVfKov", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/afdai", - "underlyingTokens": [ - "HjUhUzi6fVkY1BndaSc4Dcg2mCzvnqzXjVJtXsj78ver", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "source": "saber" - } - }, - "plotKey": "ED1gHgQxRscsvSmKdJEayZTWVYGpnyvXhVXpg7XcEJtU", - "swap": { - "config": { - "swapAccount": "FTMFgXfkDwZ6gvuyjsNnDZnf9pU31uRGeQe38QvvHtPh", - "authority": "5dpRCrasDo7d7aF6fgigvKS63yLpRAsSqCoN78bLER5m", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "ALPqczrbEXS8k5JF69tEPyu6TTE8qJbiwrzADfjVfKov", - "adminAccount": "FrxgCbQ5eSvmyr1VA1Wwmw2i7FmygMR9Q9vnFPFFyGSW", - "tokenA": { - "adminFeeAccount": "EmhWry6gUH5DqHSM5VAv7BFT1mqeHehnheijrQnHWS77", - "mint": "HjUhUzi6fVkY1BndaSc4Dcg2mCzvnqzXjVJtXsj78ver", - "reserve": "GJX9po4C8XxeHctdhfhwunXZ6mjXCKJ9XLMqcC2edncv" - }, - "tokenB": { - "adminFeeAccount": "8LCeXKvE8JGkaib7x3gD1eYGq49nfruxpXaQS6mpsSE2", - "mint": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "reserve": "2Aq6otuvoyZLtFSQKtbnNSU8MvPPYZu86bT7TbbQbK6V" - }, - "initialAmpFactor": "c8", - "targetAmpFactor": "c8", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "AAJRKmVKzdh2fVgLQ7Gfb3adMe88sNu4hAkciuFB3nUP" - }, - { - "id": "afeth", - "name": "afETH-ETH", - "tokens": [ - { - "name": "Wrapped ETH (Allbridge from Fantom)", - "symbol": "afETH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BiryxNvVTABRs3pEE4fvVuu4d17aAYEsNmcPnJ8E8WeT.png", - "decimals": 9, - "address": "BiryxNvVTABRs3pEE4fvVuu4d17aAYEsNmcPnJ8E8WeT", - "chainId": 101, - "tags": ["saber-mkt-eth"], - "extensions": { - "coingeckoId": "weth", - "source": "allbridge", - "currency": "ETH", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped Ether (Wormhole) (9 decimals)", - "address": "KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma", - "decimals": 9, - "symbol": "sETH-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma.png", - "tags": [ - "wrapped", - "wormhole", - "saber-mkt-eth", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "serumV3Usdt": "ch7kmPrtoQUSEPBggcNAvLGiMQkJagVwd3gDYfd8m7Q", - "serumV3Usdc": "8Gmi2HhZmwQPVdCwzS7CM66MGstMXPcTVHA7jF19cLZz", - "coingeckoId": "ethereum", - "source": "wormhole-v2", - "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "currency": "ETH", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "website": "https://app.saber.so", - "underlyingTokens": ["7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped ETH (Allbridge from Fantom)", - "symbol": "afETH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BiryxNvVTABRs3pEE4fvVuu4d17aAYEsNmcPnJ8E8WeT.png", - "decimals": 9, - "address": "BiryxNvVTABRs3pEE4fvVuu4d17aAYEsNmcPnJ8E8WeT", - "chainId": 101, - "tags": ["saber-mkt-eth"], - "extensions": { - "coingeckoId": "weth", - "source": "allbridge", - "currency": "ETH", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped Ether (Wormhole) (9 decimals)", - "address": "KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma", - "decimals": 9, - "symbol": "sETH-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma.png", - "tags": [ - "wrapped", - "wormhole", - "saber-mkt-eth", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "serumV3Usdt": "ch7kmPrtoQUSEPBggcNAvLGiMQkJagVwd3gDYfd8m7Q", - "serumV3Usdc": "8Gmi2HhZmwQPVdCwzS7CM66MGstMXPcTVHA7jF19cLZz", - "coingeckoId": "ethereum", - "source": "wormhole-v2", - "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "currency": "ETH", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "website": "https://app.saber.so", - "underlyingTokens": ["7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped ETH (Allbridge from Fantom)", - "symbol": "afETH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BiryxNvVTABRs3pEE4fvVuu4d17aAYEsNmcPnJ8E8WeT.png", - "decimals": 9, - "address": "BiryxNvVTABRs3pEE4fvVuu4d17aAYEsNmcPnJ8E8WeT", - "chainId": 101, - "tags": ["saber-mkt-eth"], - "extensions": { - "coingeckoId": "weth", - "source": "allbridge", - "currency": "ETH", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Ether (Wormhole)", - "symbol": "ETH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs.png", - "decimals": 8, - "address": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-eth", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "serumV3Usdt": "ch7kmPrtoQUSEPBggcNAvLGiMQkJagVwd3gDYfd8m7Q", - "serumV3Usdc": "8Gmi2HhZmwQPVdCwzS7CM66MGstMXPcTVHA7jF19cLZz", - "coingeckoId": "ethereum", - "source": "wormhole-v2", - "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "currency": "ETH", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "currency": "ETH", - "lpToken": { - "symbol": "afETH-ETH", - "name": "Saber afETH-ETH LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/ALPGFAuqQsWDB8NSKQ7rgQVhShj4LBCNC72ebdZrJs2e.png", - "decimals": 9, - "address": "ALPGFAuqQsWDB8NSKQ7rgQVhShj4LBCNC72ebdZrJs2e", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/afeth", - "underlyingTokens": [ - "BiryxNvVTABRs3pEE4fvVuu4d17aAYEsNmcPnJ8E8WeT", - "KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma" - ], - "source": "saber" - } - }, - "plotKey": "SWQww6cqJmcheovQNjeaEeMbdwB1GgmSfCGDu2CZEXW", - "swap": { - "config": { - "swapAccount": "FTM4CxWEZg5CxSieP5dS8gfSvfKt7kRAtn6m7BAjNUN3", - "authority": "cNJGMcyDpgzTKyWXfYuCJr1G4LnhEyoNxRXQ8CjZ1Hq", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "ALPGFAuqQsWDB8NSKQ7rgQVhShj4LBCNC72ebdZrJs2e", - "adminAccount": "Ff8S8C5U7nsLrBHhj8R9UR5zRjMrCa1uMU2FqkupRp46", - "tokenA": { - "adminFeeAccount": "3GujuQyQump2sz3mZjHqvqZ4nCDXapMnLGqjaTRyh1PL", - "mint": "BiryxNvVTABRs3pEE4fvVuu4d17aAYEsNmcPnJ8E8WeT", - "reserve": "8NPZUW1Fa5DKAmc3fZwjm8LbVjQxxt7PbcbBTVMCwGM1" - }, - "tokenB": { - "adminFeeAccount": "2hN8unYV8aWAu2Ui8XcjJnoWcNWgLwxNEwyVcbVE6f99", - "mint": "KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma", - "reserve": "AHMstoohNmj2eJf32GjG19nSAMM1CTVdxTjVG3hhrHJp" - }, - "initialAmpFactor": "c8", - "targetAmpFactor": "c8", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "AwVroXX4B2DefX6M85gA8F6Q5VBTPde2t7kzMKoz9p4y" - }, - { - "id": "afusdc", - "name": "afUSDC-USDC", - "tokens": [ - { - "name": "Wrapped USDC (Allbridge from Fantom)", - "symbol": "afUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Grk6b4UMRWkgyq4Y6S1BnNRF4hRgtnMFp7Sorkv6Ez4u.png", - "decimals": 9, - "address": "Grk6b4UMRWkgyq4Y6S1BnNRF4hRgtnMFp7Sorkv6Ez4u", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "usd-coin", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped USDC (Allbridge from Fantom)", - "symbol": "afUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Grk6b4UMRWkgyq4Y6S1BnNRF4hRgtnMFp7Sorkv6Ez4u.png", - "decimals": 9, - "address": "Grk6b4UMRWkgyq4Y6S1BnNRF4hRgtnMFp7Sorkv6Ez4u", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "usd-coin", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped USDC (Allbridge from Fantom)", - "symbol": "afUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Grk6b4UMRWkgyq4Y6S1BnNRF4hRgtnMFp7Sorkv6Ez4u.png", - "decimals": 9, - "address": "Grk6b4UMRWkgyq4Y6S1BnNRF4hRgtnMFp7Sorkv6Ez4u", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "usd-coin", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "afUSDC-USDC", - "name": "Saber afUSDC-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/ALP8mkba7FHrpn18hGMRURF1aRNS7P2y1SRzqE6ra3Zo.png", - "decimals": 9, - "address": "ALP8mkba7FHrpn18hGMRURF1aRNS7P2y1SRzqE6ra3Zo", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/afusdc", - "underlyingTokens": [ - "Grk6b4UMRWkgyq4Y6S1BnNRF4hRgtnMFp7Sorkv6Ez4u", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "source": "saber" - } - }, - "plotKey": "AA7SjnALx5QzxXNKpRLEnUMoKDzXdyrpV1w2Gi3Hzmrq", - "swap": { - "config": { - "swapAccount": "FTMDfFPjYWvSsDXMGR8Mdt4fLjDtSDwfz7GAqe5V6qwq", - "authority": "5GEQ2WAAGejTGrXJvPRw6iJhKEscd82mDKihZTEhsggJ", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "ALP8mkba7FHrpn18hGMRURF1aRNS7P2y1SRzqE6ra3Zo", - "adminAccount": "GGdMo6Cxjhttt91hmpYCxc9Bduad2ccDY7KrmBUbMpgP", - "tokenA": { - "adminFeeAccount": "C3YoucrCvkSpCxiHZr6jYhGq5GDh9qLdvv2DrxBAVBVW", - "mint": "Grk6b4UMRWkgyq4Y6S1BnNRF4hRgtnMFp7Sorkv6Ez4u", - "reserve": "2n895yX1VzrWuwrMCixUcD3SkRysj51jigxtV5N81vk6" - }, - "tokenB": { - "adminFeeAccount": "3XocEah4G5SmjLgHcGqgP4KB5zVuvVVGLcA5g6w1qrs6", - "mint": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "reserve": "HuEnD3eWBSuJtTCZMDG3P74sHPhi5UyVRV4SVefva6jS" - }, - "initialAmpFactor": "c8", - "targetAmpFactor": "c8", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "12sujUAou8V518isa7o2q8ZMrkH5ivF2UrbZdTYVGpUj" - }, - { - "id": "ahusdt", - "name": "ahUSDT-USDC", - "tokens": [ - { - "name": "Wrapped USDT (Allbridge from HECO)", - "symbol": "ahUSDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/GfzU1fLASNV3r4NtEyrnwTyTakJkYzoivnaL3Snh45oj.png", - "decimals": 9, - "address": "GfzU1fLASNV3r4NtEyrnwTyTakJkYzoivnaL3Snh45oj", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "tether", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped USDT (Allbridge from HECO)", - "symbol": "ahUSDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/GfzU1fLASNV3r4NtEyrnwTyTakJkYzoivnaL3Snh45oj.png", - "decimals": 9, - "address": "GfzU1fLASNV3r4NtEyrnwTyTakJkYzoivnaL3Snh45oj", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "tether", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped USDT (Allbridge from HECO)", - "symbol": "ahUSDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/GfzU1fLASNV3r4NtEyrnwTyTakJkYzoivnaL3Snh45oj.png", - "decimals": 9, - "address": "GfzU1fLASNV3r4NtEyrnwTyTakJkYzoivnaL3Snh45oj", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "tether", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "ahUSDT-USDC", - "name": "Saber ahUSDT-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/HLPC9r4gbeP6KagT3qJLzFj7iWcYTJs245k9tuHFQGyR.png", - "decimals": 9, - "address": "HLPC9r4gbeP6KagT3qJLzFj7iWcYTJs245k9tuHFQGyR", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/ahusdt", - "underlyingTokens": [ - "GfzU1fLASNV3r4NtEyrnwTyTakJkYzoivnaL3Snh45oj", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "source": "saber" - } - }, - "plotKey": "G1gV1vQLPdio32EaB2oh4LfnktdT32x4EtDyhFctGsLT", - "swap": { - "config": { - "swapAccount": "AUS3TCHxzec2Sf1jUhvmTGWo3oLXW1zxrDPYBBvjKtEq", - "authority": "4d9QyKXngdKVwi3PM9r9PTHTk4dVyHm3b2EF9EFUfeZD", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "HLPC9r4gbeP6KagT3qJLzFj7iWcYTJs245k9tuHFQGyR", - "adminAccount": "C289DKSGj3MjPsBDUacb538TPUGTyoEion1299uGLbze", - "tokenA": { - "adminFeeAccount": "6SK6Pi8juWs3ucEHM6fdSKQpXM1Jx6JRFejZRosxSHFs", - "mint": "GfzU1fLASNV3r4NtEyrnwTyTakJkYzoivnaL3Snh45oj", - "reserve": "DyBGrZkGJHrgbxQXo3sh5KKz7YTzYK9gN8fhRSXN2whK" - }, - "tokenB": { - "adminFeeAccount": "CnuUeP3wLSAvEBAMMdcwYnRarzw3fD5xQ5Y2FiY8nHBf", - "mint": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "reserve": "DRr3h3DF9wupahxh6vHMFCm6WGfmJWMrrBHoBvWAweAQ" - }, - "initialAmpFactor": "7d", - "targetAmpFactor": "7d", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "8T7Few94jmgsPNtG1e3Q16Bm4nQZVDjt9sUbzPaN23w4" - }, - { - "id": "ahwbtc", - "name": "ahBTC-renBTC", - "tokens": [ - { - "name": "Wrapped BTC (Allbridge from HECO)", - "symbol": "ahBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Bo4ehCeRcRj2wp5tQpjfCJxYFn4KyRacfDzSa4Aj27tH.png", - "decimals": 9, - "address": "Bo4ehCeRcRj2wp5tQpjfCJxYFn4KyRacfDzSa4Aj27tH", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-btc"], - "extensions": { - "coingeckoId": "wrapped-bitcoin", - "source": "allbridge", - "currency": "BTC", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped renBTC (9 decimals)", - "address": "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5", - "decimals": 9, - "symbol": "srenBTC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5.png", - "tags": ["saber-mkt-btc", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint", - "assetContract": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "underlyingTokens": ["CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped BTC (Allbridge from HECO)", - "symbol": "ahBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Bo4ehCeRcRj2wp5tQpjfCJxYFn4KyRacfDzSa4Aj27tH.png", - "decimals": 9, - "address": "Bo4ehCeRcRj2wp5tQpjfCJxYFn4KyRacfDzSa4Aj27tH", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-btc"], - "extensions": { - "coingeckoId": "wrapped-bitcoin", - "source": "allbridge", - "currency": "BTC", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped renBTC (9 decimals)", - "address": "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5", - "decimals": 9, - "symbol": "srenBTC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5.png", - "tags": ["saber-mkt-btc", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint", - "assetContract": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "underlyingTokens": ["CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped BTC (Allbridge from HECO)", - "symbol": "ahBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Bo4ehCeRcRj2wp5tQpjfCJxYFn4KyRacfDzSa4Aj27tH.png", - "decimals": 9, - "address": "Bo4ehCeRcRj2wp5tQpjfCJxYFn4KyRacfDzSa4Aj27tH", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-btc"], - "extensions": { - "coingeckoId": "wrapped-bitcoin", - "source": "allbridge", - "currency": "BTC", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "renBTC", - "symbol": "renBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5.png", - "decimals": 8, - "address": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "website": "https://renproject.io/", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint" - } - } - ], - "currency": "BTC", - "lpToken": { - "symbol": "ahBTC-renBTC", - "name": "Saber ahBTC-renBTC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/HLPPmd7NzTTNiqKR6rAZYgrH9VhU47kxftecQSk2oD6J.png", - "decimals": 9, - "address": "HLPPmd7NzTTNiqKR6rAZYgrH9VhU47kxftecQSk2oD6J", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/ahwbtc", - "underlyingTokens": [ - "Bo4ehCeRcRj2wp5tQpjfCJxYFn4KyRacfDzSa4Aj27tH", - "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5" - ], - "source": "saber" - } - }, - "plotKey": "6MLbjtWpBSFgveumcG8e67nuZ6epuUmqUoutD9VF4dad", - "swap": { - "config": { - "swapAccount": "HBTCrEkrCftRrXHZgSHQxRJTxG7TZ1DkC3Lq6UZiVg8E", - "authority": "EAR8LJq5ZzY5arxPBome3GeU2G9wSBiWp74u3zWaDpDQ", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "HLPPmd7NzTTNiqKR6rAZYgrH9VhU47kxftecQSk2oD6J", - "adminAccount": "FTAc9jevVeED7boiRJKWErCLV9ZqekEDPAPgPvotbSXq", - "tokenA": { - "adminFeeAccount": "6meUxJVjXp7UuVtX9jMZVMsqgmvy52PJS6t1P8aiBypX", - "mint": "Bo4ehCeRcRj2wp5tQpjfCJxYFn4KyRacfDzSa4Aj27tH", - "reserve": "56TsbS21JcCVgD8x7HDivK371QPWhNWPvH5QPA6oqmTX" - }, - "tokenB": { - "adminFeeAccount": "BgkC6okBiNua5EhLYNQxz13EUT528QvCMPzkzZpdN6zu", - "mint": "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5", - "reserve": "LRiFt5Sa2dCx2njaRMTVtkxKbiH2EJV2KN1b7FjMube" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "8mqVcEHKdGgYtnDTaK8MFDFGSrZoRddJeG46Ju9sET1G" - }, - { - "id": "apusdc", - "name": "apUSDC-USDC", - "tokens": [ - { - "name": "Wrapped USDC (Allbridge from Polygon)", - "symbol": "apUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/eqKJTf1Do4MDPyKisMYqVaUFpkEFAs3riGF3ceDH2Ca.png", - "decimals": 6, - "address": "eqKJTf1Do4MDPyKisMYqVaUFpkEFAs3riGF3ceDH2Ca", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "usd-coin", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped USDC (Allbridge from Polygon)", - "symbol": "apUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/eqKJTf1Do4MDPyKisMYqVaUFpkEFAs3riGF3ceDH2Ca.png", - "decimals": 6, - "address": "eqKJTf1Do4MDPyKisMYqVaUFpkEFAs3riGF3ceDH2Ca", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "usd-coin", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped USDC (Allbridge from Polygon)", - "symbol": "apUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/eqKJTf1Do4MDPyKisMYqVaUFpkEFAs3riGF3ceDH2Ca.png", - "decimals": 6, - "address": "eqKJTf1Do4MDPyKisMYqVaUFpkEFAs3riGF3ceDH2Ca", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "usd-coin", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "apUSDC-USDC", - "name": "Saber apUSDC-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/APUVVYA8Xf7T1PqLyDvNxLtwQ9rRDf3RUxfMttreVzHP.png", - "decimals": 6, - "address": "APUVVYA8Xf7T1PqLyDvNxLtwQ9rRDf3RUxfMttreVzHP", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/apusdc", - "underlyingTokens": [ - "eqKJTf1Do4MDPyKisMYqVaUFpkEFAs3riGF3ceDH2Ca", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "source": "saber" - } - }, - "plotKey": "E8xah3btxSw7BcizxX7u5PF1fQfNL1jdZYNqKPgbAQ5p", - "swap": { - "config": { - "swapAccount": "AUSejoEUCh2DBs9mof6BNC8Pubs22w4cJa1ccV9h44R", - "authority": "8puxJXzTyPXRsQ9PH9niMeje9M83a2bzatTzHxBWjGoP", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "APUVVYA8Xf7T1PqLyDvNxLtwQ9rRDf3RUxfMttreVzHP", - "adminAccount": "8sMyrCKaPcwAV1RCkG2L7nZXoXrNfeX7V6h7hq49TPrf", - "tokenA": { - "adminFeeAccount": "2ckZv6RqJuU9wjYGgMd4h9ZD4qBdiU7TC3sdsEdNR8fY", - "mint": "eqKJTf1Do4MDPyKisMYqVaUFpkEFAs3riGF3ceDH2Ca", - "reserve": "4xkyD7AfGQDwsQMy9MosRRNGoVJ1zosNinesxg1TzHG7" - }, - "tokenB": { - "adminFeeAccount": "EP7vfnJedUyTAVeUxDc64UFGFBupY11DWiTB3p846EfU", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "reserve": "Cbm5gsQe3nSiCsFrvepVzMCD9xLK3ri9g3ypS2hdmVJ7" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0050000000", - "numerator": "5", - "denominator": "100000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "3eNV6vLGDm9z8vKspbddEUvVcwcuHsFz5mBmVaRqYHqQ" - }, - { - "id": "apusdt", - "name": "apUSDT-USDT", - "tokens": [ - { - "name": "Wrapped USDT (Allbridge from Polygon)", - "symbol": "apUSDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/DNhZkUaxHXYvpxZ7LNnHtss8sQgdAfd1ZYS1fB7LKWUZ.png", - "decimals": 6, - "address": "DNhZkUaxHXYvpxZ7LNnHtss8sQgdAfd1ZYS1fB7LKWUZ", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "tether", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "USDT", - "symbol": "USDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB.svg", - "decimals": 6, - "address": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://tether.to/", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD" - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped USDT (Allbridge from Polygon)", - "symbol": "apUSDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/DNhZkUaxHXYvpxZ7LNnHtss8sQgdAfd1ZYS1fB7LKWUZ.png", - "decimals": 6, - "address": "DNhZkUaxHXYvpxZ7LNnHtss8sQgdAfd1ZYS1fB7LKWUZ", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "tether", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "USDT", - "symbol": "USDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB.svg", - "decimals": 6, - "address": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://tether.to/", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD" - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped USDT (Allbridge from Polygon)", - "symbol": "apUSDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/DNhZkUaxHXYvpxZ7LNnHtss8sQgdAfd1ZYS1fB7LKWUZ.png", - "decimals": 6, - "address": "DNhZkUaxHXYvpxZ7LNnHtss8sQgdAfd1ZYS1fB7LKWUZ", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "tether", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "USDT", - "symbol": "USDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB.svg", - "decimals": 6, - "address": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://tether.to/", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "apUSDT-USDT", - "name": "Saber apUSDT-USDT LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/PLYJZgSkcV8UXTWhTyf2WLCMeBoZum1Y4rXgXkoYiNj.png", - "decimals": 6, - "address": "PLYJZgSkcV8UXTWhTyf2WLCMeBoZum1Y4rXgXkoYiNj", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/apusdt", - "underlyingTokens": [ - "DNhZkUaxHXYvpxZ7LNnHtss8sQgdAfd1ZYS1fB7LKWUZ", - "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" - ], - "source": "saber" - } - }, - "plotKey": "Cfn325YmkHmxS6B1rb7WiVBqHRpod5dsafKS8noUTVxD", - "swap": { - "config": { - "swapAccount": "ALBpShJ9NLpE739pcHDF2LNVk5J4VYPvvKuV6jMPitZi", - "authority": "4S8xo3PeKfs3kY7ecS2amiffJZ4WXCAceDhUseE11q5E", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "PLYJZgSkcV8UXTWhTyf2WLCMeBoZum1Y4rXgXkoYiNj", - "adminAccount": "3mTb5EuFPHfbsNN7rTRzDCB6LykbDZKGiCpCLL6mNmSw", - "tokenA": { - "adminFeeAccount": "FyDHogJW1qWbhKYekKwd9EQSJrwZKAZN3vT6KwwnmT77", - "mint": "DNhZkUaxHXYvpxZ7LNnHtss8sQgdAfd1ZYS1fB7LKWUZ", - "reserve": "D6d156U1bPiJpDYRLextvDRccgFk7QzkQbJg42ceKEu5" - }, - "tokenB": { - "adminFeeAccount": "8FDK1MfsDpGLvWdinWRShnyvT28Q37xttHTrofgSUnNJ", - "mint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "reserve": "GNcM8U5g8RwTZffwwm3kSQqUNPSwv5d2fbN9sLxPJqt2" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "9ngf7fgxie59xAbEcMZF27QbcVgRea88RbXqjFccE4dA" - }, - { - "id": "asol", - "name": "aSOL-SOL", - "tokens": [ - { - "name": "aSOL Aggregate Solana Stake Pool", - "symbol": "aSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/ASoLXbfe7cd6igh5yiEsU8M7FW64QRxPKkxk7sjAfond.svg", - "decimals": 9, - "address": "ASoLXbfe7cd6igh5yiEsU8M7FW64QRxPKkxk7sjAfond", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://asol.so", - "twitter": "https://twitter.com/aSOLprotocol", - "github": "https://github.com/aSolHQ", - "coingeckoId": "solana", - "description": "aSOL is the standard for transacting with staked SOL tokens.", - "source": "aSOL", - "currency": "SOL", - "sourceUrl": "https://asol.so/" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "tokenIcons": [ - { - "name": "aSOL Aggregate Solana Stake Pool", - "symbol": "aSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/ASoLXbfe7cd6igh5yiEsU8M7FW64QRxPKkxk7sjAfond.svg", - "decimals": 9, - "address": "ASoLXbfe7cd6igh5yiEsU8M7FW64QRxPKkxk7sjAfond", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://asol.so", - "twitter": "https://twitter.com/aSOLprotocol", - "github": "https://github.com/aSolHQ", - "coingeckoId": "solana", - "description": "aSOL is the standard for transacting with staked SOL tokens.", - "source": "aSOL", - "currency": "SOL", - "sourceUrl": "https://asol.so/" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "underlyingIcons": [ - { - "name": "aSOL Aggregate Solana Stake Pool", - "symbol": "aSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/ASoLXbfe7cd6igh5yiEsU8M7FW64QRxPKkxk7sjAfond.svg", - "decimals": 9, - "address": "ASoLXbfe7cd6igh5yiEsU8M7FW64QRxPKkxk7sjAfond", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://asol.so", - "twitter": "https://twitter.com/aSOLprotocol", - "github": "https://github.com/aSolHQ", - "coingeckoId": "solana", - "description": "aSOL is the standard for transacting with staked SOL tokens.", - "source": "aSOL", - "currency": "SOL", - "sourceUrl": "https://asol.so/" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "currency": "SOL", - "lpToken": { - "symbol": "aSOL-SOL", - "name": "Saber aSOL-SOL LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/ALP89a89ASo1h5VosTSABtQBKLBgeoaWQexYQrRCMNfV.png", - "decimals": 9, - "address": "ALP89a89ASo1h5VosTSABtQBKLBgeoaWQexYQrRCMNfV", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/asol", - "underlyingTokens": [ - "ASoLXbfe7cd6igh5yiEsU8M7FW64QRxPKkxk7sjAfond", - "So11111111111111111111111111111111111111112" - ], - "source": "saber" - } - }, - "plotKey": "DzXvdLMtr3MVSVwxuR7pxwKQASrVWw1TUu1EBEvpU7U3", - "swap": { - "config": { - "swapAccount": "AURHmCnNwiW4uA2Qj1XvEh4iKgRUZYXtiY7FKAapUV5Y", - "authority": "GzGGc1xo457qnjmTbjMx1J7mabMSJs3VQyGnb51Yho1U", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 253, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "ALP89a89ASo1h5VosTSABtQBKLBgeoaWQexYQrRCMNfV", - "adminAccount": "GedWR7tUUKy9aMmA4dH3sd9MZmhLAB7RrbbDtKQnw2if", - "tokenA": { - "adminFeeAccount": "4e7K1sRxauEPf6XnTnnnbSKi4zjda2LyChpQB4qPJYTd", - "mint": "ASoLXbfe7cd6igh5yiEsU8M7FW64QRxPKkxk7sjAfond", - "reserve": "BKWm4TRnTeKwfWXRyuzjRHU7iZDkPuXBX5b5V5jSVfGJ" - }, - "tokenB": { - "adminFeeAccount": "BTJxL7z9CzGEvNo9oN2keWykFfErcVnBqMMZa1BNU31J", - "mint": "So11111111111111111111111111111111111111112", - "reserve": "A5Ww74HVrkj9nPeC7pHKLfgeDMEhBCpW1efQdz3TGLEg" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "8RyD4nFiZ56nVNtHM3wBfn2kr889XBrxv8Y1swJq91md" - }, - { - "id": "atust_cash", - "name": "atUST-CASH", - "tokens": [ - { - "address": "A96PoNcxa9LMxcF9HhKAfA1p3M1dGbubPMWf19gHAkgJ", - "symbol": "atUST", - "name": "Wrapped UST (Allbridge from Terra)", - "decimals": 6, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/A96PoNcxa9LMxcF9HhKAfA1p3M1dGbubPMWf19gHAkgJ.png", - "extensions": { - "coingeckoId": "terrausd", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "name": "Cashio Dollar", - "symbol": "CASH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "decimals": 6, - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://cashio.app", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/" - } - } - ], - "tokenIcons": [ - { - "address": "A96PoNcxa9LMxcF9HhKAfA1p3M1dGbubPMWf19gHAkgJ", - "symbol": "atUST", - "name": "Wrapped UST (Allbridge from Terra)", - "decimals": 6, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/A96PoNcxa9LMxcF9HhKAfA1p3M1dGbubPMWf19gHAkgJ.png", - "extensions": { - "coingeckoId": "terrausd", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "name": "Cashio Dollar", - "symbol": "CASH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "decimals": 6, - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://cashio.app", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/" - } - } - ], - "underlyingIcons": [ - { - "address": "A96PoNcxa9LMxcF9HhKAfA1p3M1dGbubPMWf19gHAkgJ", - "symbol": "atUST", - "name": "Wrapped UST (Allbridge from Terra)", - "decimals": 6, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/A96PoNcxa9LMxcF9HhKAfA1p3M1dGbubPMWf19gHAkgJ.png", - "extensions": { - "coingeckoId": "terrausd", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "name": "Cashio Dollar", - "symbol": "CASH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "decimals": 6, - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://cashio.app", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "atUST-CASH", - "name": "Saber atUST-CASH LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/ALPBPdBQf8ibRm3PRCycDC8bdFZQhFgjUwZMtnxA3rAA.png", - "decimals": 6, - "address": "ALPBPdBQf8ibRm3PRCycDC8bdFZQhFgjUwZMtnxA3rAA", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-cashio"], - "extensions": { - "website": "https://app.saber.so/pools/atust_cash", - "underlyingTokens": [ - "A96PoNcxa9LMxcF9HhKAfA1p3M1dGbubPMWf19gHAkgJ", - "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT" - ], - "source": "saber" - } - }, - "plotKey": "4Hkjh2a8FSLhCpG7A5mDigxFwqxrtakn9pGmPWGR9Lbf", - "swap": { - "config": { - "swapAccount": "ZoNxMdmUi6NAhBUGsBsZ751oDgqK863KXTNnQQ1HCkD", - "authority": "Cb5C5umtXQ7N2uPgjRSRbTZkirMt9SsTV9uParfhu8NY", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": true, - "nonce": 253, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "ALPBPdBQf8ibRm3PRCycDC8bdFZQhFgjUwZMtnxA3rAA", - "adminAccount": "DqUEupEqoS89CLiGLQm7JDxvAfG7VPQoN9TnPmMpwSYi", - "tokenA": { - "adminFeeAccount": "C73kp9FLqEC4ez8zZaLyuPiC9yHpt22Hixezcy8C5TeT", - "mint": "A96PoNcxa9LMxcF9HhKAfA1p3M1dGbubPMWf19gHAkgJ", - "reserve": "3k54TvpQN5R1MactdGnJSnXzu1Wozx76Pqvi1k6mQYPz" - }, - "tokenB": { - "adminFeeAccount": "3Q3MPaCVMK45Cfsd64PjytECaF2Zk3awUGewqsDYEkz7", - "mint": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "reserve": "417JcbvTQCRk2yowySN8MjtJuHSU8dTsGtVcFL4ECNCA" - }, - "initialAmpFactor": "012c", - "targetAmpFactor": "012c", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "HtqCusszJQPYULswQEbQ7F1PQhze3o9AFXxNi72EXgPX" - }, - { - "id": "atust_wust", - "name": "atLUNA-LUNA", - "tokens": [ - { - "name": "Wrapped Luna (Allbridge from Terra)", - "symbol": "atLUNA", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/3LKZU3iQx9KM94S4uYRdYwAHTm6odDyzGQqTBNj7J27z.png", - "decimals": 9, - "address": "3LKZU3iQx9KM94S4uYRdYwAHTm6odDyzGQqTBNj7J27z", - "chainId": 101, - "tags": ["saber-mkt-luna"], - "extensions": { - "coingeckoId": "terra-luna", - "source": "allbridge", - "currency": "LUNA", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped LUNA (Wormhole) (9 decimals)", - "address": "LUNGEjUXyP48nrC1GYY5o4eTAkwm4RdX8BxFUxWJBLB", - "decimals": 9, - "symbol": "sLUNA-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/LUNGEjUXyP48nrC1GYY5o4eTAkwm4RdX8BxFUxWJBLB.png", - "tags": [ - "wrapped", - "wormhole", - "saber-mkt-luna", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "HBTu8hNaoT3VyiSSzJYa8jwt9sDGKtJviSwFa11iXdmE", - "coingeckoId": "terra-luna", - "source": "wormhole-v2", - "address": "uluna", - "currency": "LUNA", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "website": "https://app.saber.so", - "assetContract": "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W", - "underlyingTokens": ["F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped Luna (Allbridge from Terra)", - "symbol": "atLUNA", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/3LKZU3iQx9KM94S4uYRdYwAHTm6odDyzGQqTBNj7J27z.png", - "decimals": 9, - "address": "3LKZU3iQx9KM94S4uYRdYwAHTm6odDyzGQqTBNj7J27z", - "chainId": 101, - "tags": ["saber-mkt-luna"], - "extensions": { - "coingeckoId": "terra-luna", - "source": "allbridge", - "currency": "LUNA", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped LUNA (Wormhole) (9 decimals)", - "address": "LUNGEjUXyP48nrC1GYY5o4eTAkwm4RdX8BxFUxWJBLB", - "decimals": 9, - "symbol": "sLUNA-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/LUNGEjUXyP48nrC1GYY5o4eTAkwm4RdX8BxFUxWJBLB.png", - "tags": [ - "wrapped", - "wormhole", - "saber-mkt-luna", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "HBTu8hNaoT3VyiSSzJYa8jwt9sDGKtJviSwFa11iXdmE", - "coingeckoId": "terra-luna", - "source": "wormhole-v2", - "address": "uluna", - "currency": "LUNA", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "website": "https://app.saber.so", - "assetContract": "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W", - "underlyingTokens": ["F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped Luna (Allbridge from Terra)", - "symbol": "atLUNA", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/3LKZU3iQx9KM94S4uYRdYwAHTm6odDyzGQqTBNj7J27z.png", - "decimals": 9, - "address": "3LKZU3iQx9KM94S4uYRdYwAHTm6odDyzGQqTBNj7J27z", - "chainId": 101, - "tags": ["saber-mkt-luna"], - "extensions": { - "coingeckoId": "terra-luna", - "source": "allbridge", - "currency": "LUNA", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "LUNA (Wormhole)", - "symbol": "LUNA", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W.png", - "decimals": 6, - "address": "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-luna", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "HBTu8hNaoT3VyiSSzJYa8jwt9sDGKtJviSwFa11iXdmE", - "coingeckoId": "terra-luna", - "source": "wormhole-v2", - "address": "uluna", - "currency": "LUNA", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "currency": "LUNA", - "lpToken": { - "symbol": "atLUNA-LUNA", - "name": "Saber atLUNA-LUNA LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/KWAMdUrCdQ2j1t9S1HD29Z4RxXymXkwSh2c94598amY.png", - "decimals": 9, - "address": "KWAMdUrCdQ2j1t9S1HD29Z4RxXymXkwSh2c94598amY", - "chainId": 101, - "tags": [ - "saber-stableswap-lp", - "saber-lp-allbridge", - "saber-lp-wormhole-v2" - ], - "extensions": { - "website": "https://app.saber.so/pools/atust_wust", - "underlyingTokens": [ - "3LKZU3iQx9KM94S4uYRdYwAHTm6odDyzGQqTBNj7J27z", - "LUNGEjUXyP48nrC1GYY5o4eTAkwm4RdX8BxFUxWJBLB" - ], - "source": "saber" - } - }, - "plotKey": "6aWPyMzQsU3ZjyNkgMvbJrJ8mKPVQmE7SnQuz67t7fhP", - "swap": { - "config": { - "swapAccount": "DouVMTbFTjafGAvXjUUZ2hZZbcGFsYXhH5x7GejyQmjT", - "authority": "7JCnCBfZr3VRurCp43QqQZY4UuzK4DHUUWCtPKZjVE27", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 250, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "KWAMdUrCdQ2j1t9S1HD29Z4RxXymXkwSh2c94598amY", - "adminAccount": "8cdnPMjDsQPLCtg5ry3Bb72VUmhDa3LTFUtDoFVY73hy", - "tokenA": { - "adminFeeAccount": "6syQtWWchQyWVxmm4aFWGYjhePT3GapZU3g2P6rdDeQV", - "mint": "3LKZU3iQx9KM94S4uYRdYwAHTm6odDyzGQqTBNj7J27z", - "reserve": "C5MQPbuYwVKN5VNCYkSLC8iaUkgWbM2yPxpeMhhsXukm" - }, - "tokenB": { - "adminFeeAccount": "BykDcrejZUBjkyYnrcCjvZv14rkiusJLTuSFSmLGL2pB", - "mint": "LUNGEjUXyP48nrC1GYY5o4eTAkwm4RdX8BxFUxWJBLB", - "reserve": "svkSYboqedQUS7zLxKx7VZjPJ6QAcpBQixFDdUkRCfq" - }, - "initialAmpFactor": "03e8", - "targetAmpFactor": "03e8", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "FCvKrbMgjttqUjduhW6U42xyEGxhr7Q9thmexazAobm2" - }, - { - "id": "bilira", - "name": "TRYB-TRYB", - "tokens": [ - { - "name": "BiLira (Wormhole)", - "symbol": "TRYB", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9QBTKuSCDaJjtxYnYcVzoiKENMdJ5DRei5ZUCEeWyZnj.png", - "decimals": 6, - "address": "9QBTKuSCDaJjtxYnYcVzoiKENMdJ5DRei5ZUCEeWyZnj", - "chainId": 101, - "tags": [ - "stablecoin", - "wormhole", - "wrapped", - "saber-mkt-try", - "wormhole-v2" - ], - "extensions": { - "website": "http://bilira.co", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/token/0x2c537e5624e4af88a7ae4060c022609376c8d0eb", - "github": "https://github.com/bilira-org", - "coingeckoId": "bilira", - "source": "wormhole-v2", - "address": "0x2c537e5624e4af88a7ae4060c022609376c8d0eb", - "currency": "TRY", - "instagram": "https://instagram.com/bilira_official", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "telegram": "https://t.me/BiLira_Official" - } - }, - { - "name": "BiLira", - "symbol": "TRYB", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/A94X2fRy3wydNShU4dRaDyap2UuoeWJGWyATtyp61WZf.png", - "decimals": 6, - "address": "A94X2fRy3wydNShU4dRaDyap2UuoeWJGWyATtyp61WZf", - "chainId": 101, - "tags": ["tryb", "bilira", "stablecoin", "saber-mkt-try"], - "extensions": { - "website": "http://bilira.co", - "github": "https://github.com/bilira-org", - "coingeckoId": "bilira", - "source": "biLira", - "currency": "TRY", - "instagram": "https://instagram.com/bilira_official", - "sourceUrl": "https://www.bilira.co/", - "telegram": "https://t.me/BiLira_Official" - } - } - ], - "tokenIcons": [ - { - "name": "BiLira (Wormhole)", - "symbol": "TRYB", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9QBTKuSCDaJjtxYnYcVzoiKENMdJ5DRei5ZUCEeWyZnj.png", - "decimals": 6, - "address": "9QBTKuSCDaJjtxYnYcVzoiKENMdJ5DRei5ZUCEeWyZnj", - "chainId": 101, - "tags": [ - "stablecoin", - "wormhole", - "wrapped", - "saber-mkt-try", - "wormhole-v2" - ], - "extensions": { - "website": "http://bilira.co", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/token/0x2c537e5624e4af88a7ae4060c022609376c8d0eb", - "github": "https://github.com/bilira-org", - "coingeckoId": "bilira", - "source": "wormhole-v2", - "address": "0x2c537e5624e4af88a7ae4060c022609376c8d0eb", - "currency": "TRY", - "instagram": "https://instagram.com/bilira_official", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "telegram": "https://t.me/BiLira_Official" - } - }, - { - "name": "BiLira", - "symbol": "TRYB", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/A94X2fRy3wydNShU4dRaDyap2UuoeWJGWyATtyp61WZf.png", - "decimals": 6, - "address": "A94X2fRy3wydNShU4dRaDyap2UuoeWJGWyATtyp61WZf", - "chainId": 101, - "tags": ["tryb", "bilira", "stablecoin", "saber-mkt-try"], - "extensions": { - "website": "http://bilira.co", - "github": "https://github.com/bilira-org", - "coingeckoId": "bilira", - "source": "biLira", - "currency": "TRY", - "instagram": "https://instagram.com/bilira_official", - "sourceUrl": "https://www.bilira.co/", - "telegram": "https://t.me/BiLira_Official" - } - } - ], - "underlyingIcons": [ - { - "name": "BiLira (Wormhole)", - "symbol": "TRYB", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9QBTKuSCDaJjtxYnYcVzoiKENMdJ5DRei5ZUCEeWyZnj.png", - "decimals": 6, - "address": "9QBTKuSCDaJjtxYnYcVzoiKENMdJ5DRei5ZUCEeWyZnj", - "chainId": 101, - "tags": [ - "stablecoin", - "wormhole", - "wrapped", - "saber-mkt-try", - "wormhole-v2" - ], - "extensions": { - "website": "http://bilira.co", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/token/0x2c537e5624e4af88a7ae4060c022609376c8d0eb", - "github": "https://github.com/bilira-org", - "coingeckoId": "bilira", - "source": "wormhole-v2", - "address": "0x2c537e5624e4af88a7ae4060c022609376c8d0eb", - "currency": "TRY", - "instagram": "https://instagram.com/bilira_official", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "telegram": "https://t.me/BiLira_Official" - } - }, - { - "name": "BiLira", - "symbol": "TRYB", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/A94X2fRy3wydNShU4dRaDyap2UuoeWJGWyATtyp61WZf.png", - "decimals": 6, - "address": "A94X2fRy3wydNShU4dRaDyap2UuoeWJGWyATtyp61WZf", - "chainId": 101, - "tags": ["tryb", "bilira", "stablecoin", "saber-mkt-try"], - "extensions": { - "website": "http://bilira.co", - "github": "https://github.com/bilira-org", - "coingeckoId": "bilira", - "source": "biLira", - "currency": "TRY", - "instagram": "https://instagram.com/bilira_official", - "sourceUrl": "https://www.bilira.co/", - "telegram": "https://t.me/BiLira_Official" - } - } - ], - "currency": "TRY", - "lpToken": { - "symbol": "TRYB-TRYB", - "name": "Saber TRYB-TRYB LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Lirav2gsqs7jL1PFRUBp8uKACT8LYjDBV8c6nzchoer.png", - "decimals": 6, - "address": "Lirav2gsqs7jL1PFRUBp8uKACT8LYjDBV8c6nzchoer", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"], - "extensions": { - "website": "https://app.saber.so/pools/bilira", - "underlyingTokens": [ - "9QBTKuSCDaJjtxYnYcVzoiKENMdJ5DRei5ZUCEeWyZnj", - "A94X2fRy3wydNShU4dRaDyap2UuoeWJGWyATtyp61WZf" - ], - "source": "saber" - } - }, - "plotKey": "GPG8RpDrBx8MRJK1bngqrWcBopaCzMPVSi6zGxRX4KqA", - "swap": { - "config": { - "swapAccount": "3nesbuhAwCMGtsyypYtg4oRPwJ3FmHnytC5bqskhPh1x", - "authority": "AAFwoEvGaFLW6V8E4u4NBGmGnExaboMdJTcguxDrRvDt", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "Lirav2gsqs7jL1PFRUBp8uKACT8LYjDBV8c6nzchoer", - "adminAccount": "8Lvn3TqvTdHqk9ZsrErsXyGgCfz7AA7zPfxvCeARkNHX", - "tokenA": { - "adminFeeAccount": "EJHrPrSogaFUehHo1hWWM9ii1ZZbABE9MLd3kBCo8CVY", - "mint": "9QBTKuSCDaJjtxYnYcVzoiKENMdJ5DRei5ZUCEeWyZnj", - "reserve": "GA7UoHChxwpLd1Sx4pK5jVA575zWAxNveJPPkayrvJV7" - }, - "tokenB": { - "adminFeeAccount": "D9N4wzL1JhBbPbW2UoWQuxQ3uu6DvYUnCMYwT6QFemWf", - "mint": "A94X2fRy3wydNShU4dRaDyap2UuoeWJGWyATtyp61WZf", - "reserve": "5rSTM7rrLvoWerY897n3KhbpuQyHV8ZMuS1pHJNAwMnQ" - }, - "initialAmpFactor": "fa", - "targetAmpFactor": "fa", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "HB4brmTLxoMEEzQx9ADMYtye71nc11yYq3SVXvvDbgu7" - }, - { - "id": "blazesol", - "name": "SOL-bSOL", - "tokens": [ - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - }, - { - "name": "BlazeStake Staked SOL (bSOL)", - "symbol": "bSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/bSo13r4TkiE4KumL71LsHTPpL2euBYLFx6h9HP3piy1.png", - "decimals": 9, - "address": "bSo13r4TkiE4KumL71LsHTPpL2euBYLFx6h9HP3piy1", - "chainId": 101, - "tags": [ - "utility-token", - "stake-pool", - "stake-pool-token", - "saber-mkt-sol" - ], - "extensions": { - "website": "https://stake.solblaze.org/", - "twitter": "https://twitter.com/solblaze_org", - "github": "https://github.com/SolBlazeOrg", - "coingeckoId": "solana", - "currency": "SOL", - "source": "blazestake", - "sourceUrl": "https://stake.solblaze.org" - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - }, - { - "name": "BlazeStake Staked SOL (bSOL)", - "symbol": "bSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/bSo13r4TkiE4KumL71LsHTPpL2euBYLFx6h9HP3piy1.png", - "decimals": 9, - "address": "bSo13r4TkiE4KumL71LsHTPpL2euBYLFx6h9HP3piy1", - "chainId": 101, - "tags": [ - "utility-token", - "stake-pool", - "stake-pool-token", - "saber-mkt-sol" - ], - "extensions": { - "website": "https://stake.solblaze.org/", - "twitter": "https://twitter.com/solblaze_org", - "github": "https://github.com/SolBlazeOrg", - "coingeckoId": "solana", - "currency": "SOL", - "source": "blazestake", - "sourceUrl": "https://stake.solblaze.org" - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - }, - { - "name": "BlazeStake Staked SOL (bSOL)", - "symbol": "bSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/bSo13r4TkiE4KumL71LsHTPpL2euBYLFx6h9HP3piy1.png", - "decimals": 9, - "address": "bSo13r4TkiE4KumL71LsHTPpL2euBYLFx6h9HP3piy1", - "chainId": 101, - "tags": [ - "utility-token", - "stake-pool", - "stake-pool-token", - "saber-mkt-sol" - ], - "extensions": { - "website": "https://stake.solblaze.org/", - "twitter": "https://twitter.com/solblaze_org", - "github": "https://github.com/SolBlazeOrg", - "coingeckoId": "solana", - "currency": "SOL", - "source": "blazestake", - "sourceUrl": "https://stake.solblaze.org" - } - } - ], - "currency": "SOL", - "lpToken": { - "symbol": "SOL-bSOL", - "name": "Saber SOL-bSOL LP", - "logoURI": "https://registry.saber.so/token-icons/slp.png", - "decimals": 9, - "address": "BLZsAUk4wRWFtmgYDdrLqarUMAUfNzv2hdTjzJRZ6Uvv", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/blazesol", - "underlyingTokens": [ - "So11111111111111111111111111111111111111112", - "bSo13r4TkiE4KumL71LsHTPpL2euBYLFx6h9HP3piy1" - ], - "source": "saber" - } - }, - "plotKey": "5NmmSZ4zhsVtS4Liv5ywPeqKnvtYki1mqZQG797QjZ5Q", - "swap": { - "config": { - "swapAccount": "STK75uPSyBnEhGTTzb1nwmP3n427XoXmfRhXxxhyady", - "authority": "6xbPfZF7qUvXMKF7WxHDeE96LPKG8GN5zuL5fgHL2m7Q", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 252, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "BLZsAUk4wRWFtmgYDdrLqarUMAUfNzv2hdTjzJRZ6Uvv", - "adminAccount": "CPf1u8o45ExTFHgSWY5KxcBhGMyWoTF6SfLVfoqHVwNr", - "tokenA": { - "adminFeeAccount": "6BVQ861sMH1jckZoBhL4pzTZsVJjmQ8MLT1k8TxFip2x", - "mint": "So11111111111111111111111111111111111111112", - "reserve": "6TYyD5fUmDe6N65avW1Ny2RxzRNobw2RRgKwH9CTzSAU" - }, - "tokenB": { - "adminFeeAccount": "DYvbmehrnyUpxJAWfg3QtYCK4ighJ4PkVhUNe3cU7ybP", - "mint": "bSo13r4TkiE4KumL71LsHTPpL2euBYLFx6h9HP3piy1", - "reserve": "54zDfk4cx2vGrEajPtodWpArNe5eUurytyxd4X3aZAxK" - }, - "initialAmpFactor": "0a", - "targetAmpFactor": "0a", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "82F6LccTs6gHZmziytaT4AX6yLBNjaxtfadJAoap3TwK" - }, - { - "id": "btc", - "name": "BTC-renBTC", - "tokens": [ - { - "name": "renBTC", - "symbol": "renBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5.png", - "decimals": 8, - "address": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "website": "https://renproject.io/", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint" - } - }, - { - "name": "Saber Wrapped Wrapped Bitcoin (Sollet) (8 decimals)", - "address": "SBTCB6pWqeDo6zGi9WVRMLCsKsN6JiR1RMUqvLtgSRv", - "decimals": 8, - "symbol": "sBTC-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/SBTCB6pWqeDo6zGi9WVRMLCsKsN6JiR1RMUqvLtgSRv.png", - "tags": [ - "wrapped-sollet", - "ethereum", - "saber-mkt-btc", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "serumV3Usdt": "C1EuT9VokAKLiW7i2ASnZUvxDoKuKkCpDDeNxAptuNe4", - "serumV3Usdc": "A8YFbxQYFVqKZaoYJLLUVcQiWP7G2MeEgW5wsAQgMvFw", - "coingeckoId": "bitcoin", - "source": "sollet", - "currency": "BTC", - "sourceUrl": "https://www.sollet.io/", - "website": "https://app.saber.so", - "assetContract": "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "underlyingTokens": ["9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E"] - } - } - ], - "tokenIcons": [ - { - "name": "Saber Wrapped Wrapped Bitcoin (Sollet) (8 decimals)", - "address": "SBTCB6pWqeDo6zGi9WVRMLCsKsN6JiR1RMUqvLtgSRv", - "decimals": 8, - "symbol": "sBTC-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/SBTCB6pWqeDo6zGi9WVRMLCsKsN6JiR1RMUqvLtgSRv.png", - "tags": [ - "wrapped-sollet", - "ethereum", - "saber-mkt-btc", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "serumV3Usdt": "C1EuT9VokAKLiW7i2ASnZUvxDoKuKkCpDDeNxAptuNe4", - "serumV3Usdc": "A8YFbxQYFVqKZaoYJLLUVcQiWP7G2MeEgW5wsAQgMvFw", - "coingeckoId": "bitcoin", - "source": "sollet", - "currency": "BTC", - "sourceUrl": "https://www.sollet.io/", - "website": "https://app.saber.so", - "assetContract": "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "underlyingTokens": ["9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E"] - } - }, - { - "name": "renBTC", - "symbol": "renBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5.png", - "decimals": 8, - "address": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "website": "https://renproject.io/", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint" - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped Bitcoin (Sollet)", - "symbol": "BTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E.png", - "decimals": 6, - "address": "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "chainId": 101, - "tags": ["wrapped-sollet", "ethereum", "saber-mkt-btc"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "serumV3Usdt": "C1EuT9VokAKLiW7i2ASnZUvxDoKuKkCpDDeNxAptuNe4", - "serumV3Usdc": "A8YFbxQYFVqKZaoYJLLUVcQiWP7G2MeEgW5wsAQgMvFw", - "coingeckoId": "bitcoin", - "source": "sollet", - "currency": "BTC", - "sourceUrl": "https://www.sollet.io/" - } - }, - { - "name": "renBTC", - "symbol": "renBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5.png", - "decimals": 8, - "address": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "website": "https://renproject.io/", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint" - } - } - ], - "currency": "BTC", - "lpToken": { - "symbol": "BTC-renBTC", - "name": "Saber BTC-renBTC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/SLPbsNrLHv8xG4cTc4R5Ci8kB9wUPs6yn6f7cKosoxs.png", - "decimals": 8, - "address": "SLPbsNrLHv8xG4cTc4R5Ci8kB9wUPs6yn6f7cKosoxs", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/btc", - "underlyingTokens": [ - "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "SBTCB6pWqeDo6zGi9WVRMLCsKsN6JiR1RMUqvLtgSRv" - ], - "source": "saber", - "sourceUrl": "https://bridge.renproject.io/mint" - } - }, - "plotKey": "14XHWnimCq8Hx3RBtocT1YsdytfHALUh9H1EfebbbEU4", - "swap": { - "config": { - "swapAccount": "BkwbeSfcX1h4thMDd7obGkHrPevf3QwgzJ4pCEqG18Lu", - "authority": "Fekck54VF2MdesR74trJteZbiKj1TD5AVQisXr8E7fjG", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 248, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "SLPbsNrLHv8xG4cTc4R5Ci8kB9wUPs6yn6f7cKosoxs", - "adminAccount": "E2gajrH3ztUMEiGZeqWCqaXMsWNzW6yidAb6Jiu9GKJS", - "tokenA": { - "adminFeeAccount": "BtWyCxodyYWEXED61iSZoD4cng7E7rCRuuHJj52CRcBv", - "mint": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "reserve": "35yX27bmurdebhfAb8EPmjLETDiUaEUCn9zHaDPbakH2" - }, - "tokenB": { - "adminFeeAccount": "A94zn3axQ1PyMsrFzSH6KHKkmTMkKHPwJxsczVjShu9u", - "mint": "SBTCB6pWqeDo6zGi9WVRMLCsKsN6JiR1RMUqvLtgSRv", - "reserve": "2CxECn1ZJFoESyUnQysQU8rRgT3iJ5GRs2Mdd6gZjx5g" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "4pp9vu4oVr61KmyW1byfXg613jhfsDAA6FCuLhw9ycMp" - }, - { - "id": "busd", - "name": "wBUSD_v1-USDC", - "tokens": [ - { - "name": "Binance USD (Wormhole v1)", - "symbol": "wBUSD_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/AJ1W9A9N9dEMdVyoDiam2rV44gnBm2csrPDP7xqcapgX.png", - "decimals": 9, - "address": "AJ1W9A9N9dEMdVyoDiam2rV44gnBm2csrPDP7xqcapgX", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v1"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0x4Fabb145d64652a948d72533023f6E7A623C7C53", - "coingeckoId": "binance-usd", - "source": "wormhole-v1", - "address": "0x4Fabb145d64652a948d72533023f6E7A623C7C53", - "currency": "USD", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "Binance USD (Wormhole v1)", - "symbol": "wBUSD_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/AJ1W9A9N9dEMdVyoDiam2rV44gnBm2csrPDP7xqcapgX.png", - "decimals": 9, - "address": "AJ1W9A9N9dEMdVyoDiam2rV44gnBm2csrPDP7xqcapgX", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v1"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0x4Fabb145d64652a948d72533023f6E7A623C7C53", - "coingeckoId": "binance-usd", - "source": "wormhole-v1", - "address": "0x4Fabb145d64652a948d72533023f6E7A623C7C53", - "currency": "USD", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "Binance USD (Wormhole v1)", - "symbol": "wBUSD_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/AJ1W9A9N9dEMdVyoDiam2rV44gnBm2csrPDP7xqcapgX.png", - "decimals": 9, - "address": "AJ1W9A9N9dEMdVyoDiam2rV44gnBm2csrPDP7xqcapgX", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v1"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0x4Fabb145d64652a948d72533023f6E7A623C7C53", - "coingeckoId": "binance-usd", - "source": "wormhole-v1", - "address": "0x4Fabb145d64652a948d72533023f6E7A623C7C53", - "currency": "USD", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "wBUSDv1-USDC", - "name": "Saber wBUSD_v1-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BUSDaZjarCrQJLeHpWi7aLaKptdR1S8DFpwdDuuZu9p3.png", - "decimals": 9, - "address": "BUSDaZjarCrQJLeHpWi7aLaKptdR1S8DFpwdDuuZu9p3", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"], - "extensions": { - "website": "https://app.saber.so/pools/busd", - "underlyingTokens": [ - "AJ1W9A9N9dEMdVyoDiam2rV44gnBm2csrPDP7xqcapgX", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "source": "saber" - } - }, - "plotKey": "CMMdwnzEfzbaDgaQnaQY8TFcVDb1vD4mLXQUWkwFh8i2", - "swap": { - "config": { - "swapAccount": "BkMBnJpvHKtWhUvrgRrLesXfi9RUV3ELgdBaJcdH7hcY", - "authority": "FDndRkBVpFoNBHY6Jhx7PgNpysvZjt3P2MZ95vmkSfWa", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "BUSDaZjarCrQJLeHpWi7aLaKptdR1S8DFpwdDuuZu9p3", - "adminAccount": "8GAo2n3E7jcrZeK9SyXvX7TG8xYx71U6BWRk91s4qcMQ", - "tokenA": { - "adminFeeAccount": "3WmdrG1ESnSDYes4ENnXzyp6bbHjP8badDe2qaUf2iRG", - "mint": "AJ1W9A9N9dEMdVyoDiam2rV44gnBm2csrPDP7xqcapgX", - "reserve": "5uerVwBnZQsuVhZ15igs7ZgmcqhHnYWbwoRtLyRqLvR" - }, - "tokenB": { - "adminFeeAccount": "DoEoomAbK5aFkzSF1QmdN7HAToQYGsUy6MVthUM67hzT", - "mint": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "reserve": "9YWiQh5d4jCtgMdzcGLv9bWgnLaFtzvDDh2nnhJdzhBX" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "FdefcL2FRLhz9bDnjyypuV8qRJ5p2TRKV2yUDxqFcFRN", - "newPoolID": "webusd" - }, - { - "id": "calusd", - "name": "calUSD-USDC", - "tokens": [ - { - "name": "calUSD Stablecoin", - "symbol": "calUSD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CALusHembJf3tQ69BxFbLRUSpGRwKzEnLKWUPhQo5dFk.png", - "decimals": 9, - "address": "CALusHembJf3tQ69BxFbLRUSpGRwKzEnLKWUPhQo5dFk", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://calcifer.fi/", - "twitter": "https://twitter.com/CalciferFi", - "medium": "https://medium.com/@CalciferFinance", - "discord": "https://discord.com/invite/Me2zTTdQpu", - "coingeckoId": "usd-coin", - "source": "calcifer", - "currency": "USD", - "sourceUrl": "https://calcifer.fi" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "calUSD Stablecoin", - "symbol": "calUSD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CALusHembJf3tQ69BxFbLRUSpGRwKzEnLKWUPhQo5dFk.png", - "decimals": 9, - "address": "CALusHembJf3tQ69BxFbLRUSpGRwKzEnLKWUPhQo5dFk", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://calcifer.fi/", - "twitter": "https://twitter.com/CalciferFi", - "medium": "https://medium.com/@CalciferFinance", - "discord": "https://discord.com/invite/Me2zTTdQpu", - "coingeckoId": "usd-coin", - "source": "calcifer", - "currency": "USD", - "sourceUrl": "https://calcifer.fi" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "calUSD Stablecoin", - "symbol": "calUSD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CALusHembJf3tQ69BxFbLRUSpGRwKzEnLKWUPhQo5dFk.png", - "decimals": 9, - "address": "CALusHembJf3tQ69BxFbLRUSpGRwKzEnLKWUPhQo5dFk", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://calcifer.fi/", - "twitter": "https://twitter.com/CalciferFi", - "medium": "https://medium.com/@CalciferFinance", - "discord": "https://discord.com/invite/Me2zTTdQpu", - "coingeckoId": "usd-coin", - "source": "calcifer", - "currency": "USD", - "sourceUrl": "https://calcifer.fi" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "calUSD-USDC", - "name": "Saber calUSD-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CALiTYvv4znEoywSifHsTc7yX8VeKqdgnAzqvm47sPxa.png", - "decimals": 9, - "address": "CALiTYvv4znEoywSifHsTc7yX8VeKqdgnAzqvm47sPxa", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/calusd", - "underlyingTokens": [ - "CALusHembJf3tQ69BxFbLRUSpGRwKzEnLKWUPhQo5dFk", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "source": "saber" - } - }, - "plotKey": "A5BZJm1enr1WMTZCMonYHYNikgJzoPHKywB35dNDVrRR", - "swap": { - "config": { - "swapAccount": "BerKDkt6v49dT1bHRedgnpsJS263C1DSJtEGvY9Mg35V", - "authority": "Hwashq9x4AEy9Fq51uyQxfCa4RKrdwzuSmRx8Wn9yxQq", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 250, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "CALiTYvv4znEoywSifHsTc7yX8VeKqdgnAzqvm47sPxa", - "adminAccount": "GsVQCAzyUViUhubyQMtphmyWFRtR58kHUidV7KLimDuY", - "tokenA": { - "adminFeeAccount": "4rhNyLHLCkfJ1DJQqt5cUcAfWd6oNJCUNsuni4QT5YYz", - "mint": "CALusHembJf3tQ69BxFbLRUSpGRwKzEnLKWUPhQo5dFk", - "reserve": "78XKqNb8wbfsMMrvo8WPUpdx7GEkfQutpNVH943aCGFa" - }, - "tokenB": { - "adminFeeAccount": "HHVkZP3R6vi2wfuDc2RgNpKxqW3rJF9qdr56LhaotsL9", - "mint": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "reserve": "DKYQwn4nDvFHCszi5tXbqfVMAP7DaXXp1KGTXEnYnKVH" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "AotTWCpKdh2GdHr1D73QYkjzu1GPDXEb6yot9q2z1h8A" - }, - { - "id": "cash", - "name": "CASH-USDC", - "tokens": [ - { - "name": "Cashio Dollar", - "symbol": "CASH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "decimals": 6, - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://cashio.app", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "tokenIcons": [ - { - "name": "Cashio Dollar", - "symbol": "CASH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "decimals": 6, - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://cashio.app", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "underlyingIcons": [ - { - "name": "Cashio Dollar", - "symbol": "CASH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "decimals": 6, - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://cashio.app", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "CASH-USDC", - "name": "Saber CASH-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CLPKiHjoU5HwpPK5L6MBXHKqFsuzPr47dM1w4An3Lnvv.png", - "decimals": 6, - "address": "CLPKiHjoU5HwpPK5L6MBXHKqFsuzPr47dM1w4An3Lnvv", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/cash", - "underlyingTokens": [ - "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "source": "saber" - } - }, - "plotKey": "9tXeRPuyJeQyfVSRAryxzWju4feBE8zwDg6N8D5zwSGj", - "swap": { - "config": { - "swapAccount": "CASNrsSdASV1eyEca4mnEwhMqjANkyRLnF5kEGoorBX2", - "authority": "4ofEvMGQ87LFQ9aNw6pCDocFytWBH8BYqL7MwDKfQt1U", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": true, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "CLPKiHjoU5HwpPK5L6MBXHKqFsuzPr47dM1w4An3Lnvv", - "adminAccount": "4a8uewMhD5ZzhtfKLJfL7SkJ3wUAoKNNQnVzmZJ2UPWH", - "tokenA": { - "adminFeeAccount": "6gGA2BqJqABm7pXYLp1QS8fLm9jqn88PgbFor7P3ZiQj", - "mint": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "reserve": "7EifTDGz2nEU7DiE2UuuBX9Efkbdfad47mgr7Bqrqo8Y" - }, - "tokenB": { - "adminFeeAccount": "8jga6BnwF9aNmv7FZ9dzVNZZZjBTLJMoJHRzqk77rQD5", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "reserve": "FoL4JKwgaRUnf5c8wZDYdSam98NepnZ6oJDNFqPLuRvr" - }, - "initialAmpFactor": "01f4", - "targetAmpFactor": "01f4", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "3esh4Uq1WMpdYSgBmK92C9eLVRU5MzcNPm2PJyG72Fqo" - }, - { - "id": "dai", - "name": "wDAI_v1-USDC", - "tokens": [ - { - "name": "Dai Stablecoin (Wormhole v1)", - "symbol": "wDAI_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FYpdBuyAHSbdaAyD1sKkxyLWbAP8uUW9h6uvdhK74ij1.png", - "decimals": 9, - "address": "FYpdBuyAHSbdaAyD1sKkxyLWbAP8uUW9h6uvdhK74ij1", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v1"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0x6B175474E89094C44Da98b954EedeAC495271d0F", - "coingeckoId": "dai", - "source": "wormhole-v1", - "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", - "currency": "USD", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "Dai Stablecoin (Wormhole v1)", - "symbol": "wDAI_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FYpdBuyAHSbdaAyD1sKkxyLWbAP8uUW9h6uvdhK74ij1.png", - "decimals": 9, - "address": "FYpdBuyAHSbdaAyD1sKkxyLWbAP8uUW9h6uvdhK74ij1", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v1"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0x6B175474E89094C44Da98b954EedeAC495271d0F", - "coingeckoId": "dai", - "source": "wormhole-v1", - "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", - "currency": "USD", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "Dai Stablecoin (Wormhole v1)", - "symbol": "wDAI_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FYpdBuyAHSbdaAyD1sKkxyLWbAP8uUW9h6uvdhK74ij1.png", - "decimals": 9, - "address": "FYpdBuyAHSbdaAyD1sKkxyLWbAP8uUW9h6uvdhK74ij1", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v1"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0x6B175474E89094C44Da98b954EedeAC495271d0F", - "coingeckoId": "dai", - "source": "wormhole-v1", - "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", - "currency": "USD", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "wDAIv1-USDC", - "name": "Saber wDAI_v1-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Daimhb91DY4e3aVaa7YCW5GgwaMT9j1ALSi2GriBvDNh.png", - "decimals": 9, - "address": "Daimhb91DY4e3aVaa7YCW5GgwaMT9j1ALSi2GriBvDNh", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"], - "extensions": { - "website": "https://app.saber.so/pools/dai", - "underlyingTokens": [ - "FYpdBuyAHSbdaAyD1sKkxyLWbAP8uUW9h6uvdhK74ij1", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "source": "saber" - } - }, - "plotKey": "BvYhEvAG5tFqz9SYYe6yvSWi7TqV1mpL4FVmVJPxorsj", - "swap": { - "config": { - "swapAccount": "4xeRVccqvUgiV6VeF6NkWqkAYeewcJPRWFVginvJw1n4", - "authority": "2hAy2ubWi3PWrgxSoamzonLy1bUL3BfoqW7u7791Qpj9", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "Daimhb91DY4e3aVaa7YCW5GgwaMT9j1ALSi2GriBvDNh", - "adminAccount": "DhHGEpDp8LojBkCqANpLp3D84RE8ebTh8HFh7vBy5Ug9", - "tokenA": { - "adminFeeAccount": "6Z89E44paaBKP5cvpbUjznhs5eLmUdvSKnJdASZMEu3v", - "mint": "FYpdBuyAHSbdaAyD1sKkxyLWbAP8uUW9h6uvdhK74ij1", - "reserve": "A7VkMFrnCCyeZFUrQ3TzDr4xFep7PZtxvy3jJnBjLB2a" - }, - "tokenB": { - "adminFeeAccount": "4cDRUtsATQBmK63FXYRVnS4TD16vpcf5HJiZrQW3dQNE", - "mint": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "reserve": "PhfHJ2Yu99BsEjZrefhApqUnLUiExcECcUT1YLoNUUv" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "EYbg27c9Afc1Cbxy8qnCvECw2unWajypuXAYiQq949Yy", - "newPoolID": "wdai" - }, - { - "id": "everstake_sol", - "name": "eSOL-SOL", - "tokens": [ - { - "name": "EverSOL staked SOL (eSOL)", - "symbol": "eSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Hg35Vd8K3BS2pLB3xwC2WqQV8pmpCm3oNRGYP1PEpmCM.png", - "decimals": 9, - "address": "Hg35Vd8K3BS2pLB3xwC2WqQV8pmpCm3oNRGYP1PEpmCM", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://everstake.one", - "twitter": "https://twitter.com/everstake_pool", - "medium": "https://medium.com/everstake", - "coingeckoId": "solana", - "source": "everstake", - "currency": "SOL", - "sourceUrl": "https://eversol.one/app" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "tokenIcons": [ - { - "name": "EverSOL staked SOL (eSOL)", - "symbol": "eSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Hg35Vd8K3BS2pLB3xwC2WqQV8pmpCm3oNRGYP1PEpmCM.png", - "decimals": 9, - "address": "Hg35Vd8K3BS2pLB3xwC2WqQV8pmpCm3oNRGYP1PEpmCM", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://everstake.one", - "twitter": "https://twitter.com/everstake_pool", - "medium": "https://medium.com/everstake", - "coingeckoId": "solana", - "source": "everstake", - "currency": "SOL", - "sourceUrl": "https://eversol.one/app" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "underlyingIcons": [ - { - "name": "EverSOL staked SOL (eSOL)", - "symbol": "eSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Hg35Vd8K3BS2pLB3xwC2WqQV8pmpCm3oNRGYP1PEpmCM.png", - "decimals": 9, - "address": "Hg35Vd8K3BS2pLB3xwC2WqQV8pmpCm3oNRGYP1PEpmCM", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://everstake.one", - "twitter": "https://twitter.com/everstake_pool", - "medium": "https://medium.com/everstake", - "coingeckoId": "solana", - "source": "everstake", - "currency": "SOL", - "sourceUrl": "https://eversol.one/app" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "currency": "SOL", - "lpToken": { - "symbol": "eSOL-SOL", - "name": "Saber eSOL-SOL LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/ESoLEkfqBkqti137xAmnEHXB4omZpGXUdSPpfBWe9sau.png", - "decimals": 9, - "address": "ESoLEkfqBkqti137xAmnEHXB4omZpGXUdSPpfBWe9sau", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/everstake_sol", - "underlyingTokens": [ - "Hg35Vd8K3BS2pLB3xwC2WqQV8pmpCm3oNRGYP1PEpmCM", - "So11111111111111111111111111111111111111112" - ], - "source": "saber" - } - }, - "plotKey": "8KYHNi7kyPDiy8FXUej4hrFMDgyvp2YFGQRZwPWvSTcm", - "swap": { - "config": { - "swapAccount": "SERgf3DMJpQxUifu7VoFKmfne73d2fDJxSrxUMrcNJB", - "authority": "MtvDRVATWdGwEG16kPgY5bvWVqN5zbjzzVDGxJFSW4R", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "ESoLEkfqBkqti137xAmnEHXB4omZpGXUdSPpfBWe9sau", - "adminAccount": "HaktMS5oHXg6uABCe9nQN647HUsUMsZRYw4PHZLd3jq7", - "tokenA": { - "adminFeeAccount": "ADD6MDiJru8GkJuML8BgRy4sviw1C9fRfPZdVbfiXw1J", - "mint": "Hg35Vd8K3BS2pLB3xwC2WqQV8pmpCm3oNRGYP1PEpmCM", - "reserve": "AJfM2GZ2tTB8UtN2krcyR9xufRJEx2mhSCbJyMgPo3GU" - }, - "tokenB": { - "adminFeeAccount": "pbE3un9N2fP8CtJDH6iKkuKghLgGxq1gEytkW25sD7T", - "mint": "So11111111111111111111111111111111111111112", - "reserve": "F4yRYkufQvERZcEKnKjJwRLU1btiMBUuEwq46hfm11QD" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "6yqzupus4AdYkghjsGNHxgRLNXW22oisAwCDDGGTWU4s" - }, - { - "id": "fabric_usd", - "name": "USDC-fUSD", - "tokens": [ - { - "name": "Saber Wrapped USD Coin (8 decimals)", - "address": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "decimals": 8, - "symbol": "sUSDC-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - }, - { - "name": "Synthetic USD (Fabric)", - "symbol": "fUSD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/B7mXkkZgn7abwz1A3HnKkb18Y6y18WcbeSkh1DuLMkee", - "decimals": 8, - "address": "B7mXkkZgn7abwz1A3HnKkb18Y6y18WcbeSkh1DuLMkee", - "chainId": 101, - "tags": ["fabric", "synthetics", "saber-mkt-usd"], - "extensions": { - "website": "https://app.fsynth.io/", - "twitter": "https://twitter.com/official_fabric", - "github": "https://github.com/fabric-foundation/", - "medium": "https://xfabric.medium.com/", - "coingeckoId": "usd-coin", - "source": "fabric", - "currency": "USD", - "sourceUrl": "https://fsynth.io" - } - } - ], - "tokenIcons": [ - { - "name": "Saber Wrapped USD Coin (8 decimals)", - "address": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "decimals": 8, - "symbol": "sUSDC-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - }, - { - "name": "Synthetic USD (Fabric)", - "symbol": "fUSD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/B7mXkkZgn7abwz1A3HnKkb18Y6y18WcbeSkh1DuLMkee", - "decimals": 8, - "address": "B7mXkkZgn7abwz1A3HnKkb18Y6y18WcbeSkh1DuLMkee", - "chainId": 101, - "tags": ["fabric", "synthetics", "saber-mkt-usd"], - "extensions": { - "website": "https://app.fsynth.io/", - "twitter": "https://twitter.com/official_fabric", - "github": "https://github.com/fabric-foundation/", - "medium": "https://xfabric.medium.com/", - "coingeckoId": "usd-coin", - "source": "fabric", - "currency": "USD", - "sourceUrl": "https://fsynth.io" - } - } - ], - "underlyingIcons": [ - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - }, - { - "name": "Synthetic USD (Fabric)", - "symbol": "fUSD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/B7mXkkZgn7abwz1A3HnKkb18Y6y18WcbeSkh1DuLMkee", - "decimals": 8, - "address": "B7mXkkZgn7abwz1A3HnKkb18Y6y18WcbeSkh1DuLMkee", - "chainId": 101, - "tags": ["fabric", "synthetics", "saber-mkt-usd"], - "extensions": { - "website": "https://app.fsynth.io/", - "twitter": "https://twitter.com/official_fabric", - "github": "https://github.com/fabric-foundation/", - "medium": "https://xfabric.medium.com/", - "coingeckoId": "usd-coin", - "source": "fabric", - "currency": "USD", - "sourceUrl": "https://fsynth.io" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "USDC-fUSD", - "name": "Saber USDC-fUSD LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FABBC7H9BdQKV5v8rZNLHJCnMSRcZbWoR9rF3oR65FcP.png", - "decimals": 8, - "address": "FABBC7H9BdQKV5v8rZNLHJCnMSRcZbWoR9rF3oR65FcP", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/fabric_usd", - "underlyingTokens": [ - "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "B7mXkkZgn7abwz1A3HnKkb18Y6y18WcbeSkh1DuLMkee" - ], - "source": "saber" - } - }, - "plotKey": "857x4YVXGHN4zNNyLcE3jdht3b4QHBRGAuk3FFpJPqNZ", - "swap": { - "config": { - "swapAccount": "DEDaBEWzMCXohXYXoLzB4jK1xqMsd3SS9izXp2xvg9pe", - "authority": "DNHbHTg5wnnHo2BwmwdcKyz4817QNqyRbb2EKXat2Ham", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "FABBC7H9BdQKV5v8rZNLHJCnMSRcZbWoR9rF3oR65FcP", - "adminAccount": "FDXCELsnp4bB1PkCPxbnP914mvFwbR9CvPaoGsR3H2Hy", - "tokenA": { - "adminFeeAccount": "GDSsjnL3rFjVnkCSTnegk7MsJeDSpw5DjPoqkogAyDSG", - "mint": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "reserve": "GC5zHpW5GuVdw3C7covC6viyGdLS8ZAaVGDKMeru7p78" - }, - "tokenB": { - "adminFeeAccount": "HVi87EnZeejoSucbhSkg4tCrLUgDe2YYzrzSXMjSbURG", - "mint": "B7mXkkZgn7abwz1A3HnKkb18Y6y18WcbeSkh1DuLMkee", - "reserve": "F8juxtAFueW19vxkdDArUkjVWAv9QV6yy1wCXUWQiXvh" - }, - "initialAmpFactor": "19", - "targetAmpFactor": "19", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "9oPMBb3uUEmF5ow2sYdwmQ9jRCs3zmy2z43gDfpk6D97" - }, - { - "id": "fei_cash", - "name": "aeFEI-CASH", - "tokens": [ - { - "name": "Wrapped FEI (Allbridge from Ethereum)", - "symbol": "aeFEI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BAexggGFsiLCKr17cSZF12wkHd8BkR1DBhzuSb78WTR2.png", - "decimals": 9, - "address": "BAexggGFsiLCKr17cSZF12wkHd8BkR1DBhzuSb78WTR2", - "chainId": 101, - "tags": ["saber-mkt-usd"], - "extensions": { - "coingeckoId": "fei-usd", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped Cashio Dollar (9 decimals)", - "address": "C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi", - "decimals": 9, - "symbol": "sCASH-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/", - "assetContract": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "underlyingTokens": ["CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped FEI (Allbridge from Ethereum)", - "symbol": "aeFEI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BAexggGFsiLCKr17cSZF12wkHd8BkR1DBhzuSb78WTR2.png", - "decimals": 9, - "address": "BAexggGFsiLCKr17cSZF12wkHd8BkR1DBhzuSb78WTR2", - "chainId": 101, - "tags": ["saber-mkt-usd"], - "extensions": { - "coingeckoId": "fei-usd", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped Cashio Dollar (9 decimals)", - "address": "C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi", - "decimals": 9, - "symbol": "sCASH-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/", - "assetContract": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "underlyingTokens": ["CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped FEI (Allbridge from Ethereum)", - "symbol": "aeFEI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BAexggGFsiLCKr17cSZF12wkHd8BkR1DBhzuSb78WTR2.png", - "decimals": 9, - "address": "BAexggGFsiLCKr17cSZF12wkHd8BkR1DBhzuSb78WTR2", - "chainId": 101, - "tags": ["saber-mkt-usd"], - "extensions": { - "coingeckoId": "fei-usd", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Cashio Dollar", - "symbol": "CASH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "decimals": 6, - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://cashio.app", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "aeFEI-CASH", - "name": "Saber aeFEI-CASH LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/ALPaX3bS8zPKsVN6eS7Ln7dvEbDAfDtXsLz5pe2JRddq.png", - "decimals": 9, - "address": "ALPaX3bS8zPKsVN6eS7Ln7dvEbDAfDtXsLz5pe2JRddq", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/fei_cash", - "underlyingTokens": [ - "BAexggGFsiLCKr17cSZF12wkHd8BkR1DBhzuSb78WTR2", - "C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi" - ], - "source": "saber" - } - }, - "plotKey": "35gRM8VAuqqqhzhqbCZETrpt4cAmkjvaGJZuPfZuhHin", - "swap": { - "config": { - "swapAccount": "FEiWZLDDFthHtFHhavYwdmF8RThgTNt8vzBqAwV4hTar", - "authority": "GzBuk1UQ4iCkeK8QY6mrYjjTa3KaT6RS7aiLeBdoWoEr", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": true, - "nonce": 253, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "ALPaX3bS8zPKsVN6eS7Ln7dvEbDAfDtXsLz5pe2JRddq", - "adminAccount": "AqD6LzqqdX6YJDdfKTLPUhddNC8HRW3Esdn35UK4qMsM", - "tokenA": { - "adminFeeAccount": "3GqC6iqnZEP6pVsEsCcTgrpcFbjwuJZYExU5Tk4fv7rN", - "mint": "BAexggGFsiLCKr17cSZF12wkHd8BkR1DBhzuSb78WTR2", - "reserve": "2jLa3LzFouE27ZQDnuHWUMs7ZMtkCNj8uatotPdi4Weg" - }, - "tokenB": { - "adminFeeAccount": "CQgePXshqxWW2fZEpd31nLvyAWTDNtvhmsMYv6kn8wpB", - "mint": "C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi", - "reserve": "7KFPJ4VJp9MYsHXpdm1QJhkNEdq5dFqLm6Z17gVsWTW2" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "EQqa6BGXGTg2c2mHe8AtXeNEobsZsF5u6AnKkrgUpjyr" - }, - { - "id": "fei_ust", - "name": "aeFEI-UST", - "tokens": [ - { - "name": "Wrapped FEI (Allbridge from Ethereum)", - "symbol": "aeFEI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BAexggGFsiLCKr17cSZF12wkHd8BkR1DBhzuSb78WTR2.png", - "decimals": 9, - "address": "BAexggGFsiLCKr17cSZF12wkHd8BkR1DBhzuSb78WTR2", - "chainId": 101, - "tags": ["saber-mkt-usd"], - "extensions": { - "coingeckoId": "fei-usd", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped UST (Wormhole) (9 decimals)", - "address": "UST98bfV6EASdTFQrRwCBczpehdMFwYCUdLT5tEbhpW", - "decimals": 9, - "symbol": "sUST-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/UST98bfV6EASdTFQrRwCBczpehdMFwYCUdLT5tEbhpW.png", - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "website": "https://app.saber.so", - "assetContract": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "underlyingTokens": ["9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped FEI (Allbridge from Ethereum)", - "symbol": "aeFEI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BAexggGFsiLCKr17cSZF12wkHd8BkR1DBhzuSb78WTR2.png", - "decimals": 9, - "address": "BAexggGFsiLCKr17cSZF12wkHd8BkR1DBhzuSb78WTR2", - "chainId": 101, - "tags": ["saber-mkt-usd"], - "extensions": { - "coingeckoId": "fei-usd", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped UST (Wormhole) (9 decimals)", - "address": "UST98bfV6EASdTFQrRwCBczpehdMFwYCUdLT5tEbhpW", - "decimals": 9, - "symbol": "sUST-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/UST98bfV6EASdTFQrRwCBczpehdMFwYCUdLT5tEbhpW.png", - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "website": "https://app.saber.so", - "assetContract": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "underlyingTokens": ["9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped FEI (Allbridge from Ethereum)", - "symbol": "aeFEI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BAexggGFsiLCKr17cSZF12wkHd8BkR1DBhzuSb78WTR2.png", - "decimals": 9, - "address": "BAexggGFsiLCKr17cSZF12wkHd8BkR1DBhzuSb78WTR2", - "chainId": 101, - "tags": ["saber-mkt-usd"], - "extensions": { - "coingeckoId": "fei-usd", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "UST (Wormhole)", - "symbol": "UST", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i.png", - "decimals": 6, - "address": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "chainId": 101, - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "aeFEI-UST", - "name": "Saber aeFEI-UST LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/ALPDpWSYbwNkkuVB3wd1nZx7dZBLV7fEGvbDu9KJxLik.png", - "decimals": 9, - "address": "ALPDpWSYbwNkkuVB3wd1nZx7dZBLV7fEGvbDu9KJxLik", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/fei_ust", - "underlyingTokens": [ - "BAexggGFsiLCKr17cSZF12wkHd8BkR1DBhzuSb78WTR2", - "UST98bfV6EASdTFQrRwCBczpehdMFwYCUdLT5tEbhpW" - ], - "source": "saber" - } - }, - "plotKey": "2fwv72fB82zRgQHkhacavbB6GgXLHGQrsfecRgnUMdLX", - "swap": { - "config": { - "swapAccount": "FEiKCCNftXbfmTfSaoVV2baXAnfTQRP8RrkUMEnxrYnK", - "authority": "4QyDMU9DhMy7Yf4r7YDC8s9fQcMW1EKtSZoSMFvjy2xC", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "ALPDpWSYbwNkkuVB3wd1nZx7dZBLV7fEGvbDu9KJxLik", - "adminAccount": "DhpsqCN3Z5Kfp2DLnF4C2Qk623EncpFxrL3UzGnumMi4", - "tokenA": { - "adminFeeAccount": "J5S6FLKL4kCxmtFc3vXQtuZT6rLyC9cDvYzTs9xq4bhN", - "mint": "BAexggGFsiLCKr17cSZF12wkHd8BkR1DBhzuSb78WTR2", - "reserve": "5DjHcTbdZ567fzf21YgDhKDKAu7HYoYsMW3fEx3fqDWJ" - }, - "tokenB": { - "adminFeeAccount": "7xppk4QcFD2vUpVfePKug8Ut4fB9A5NLzvvAsUkG6PPJ", - "mint": "UST98bfV6EASdTFQrRwCBczpehdMFwYCUdLT5tEbhpW", - "reserve": "Co2UdQpmfKcYqUkCBB7FBpiSbtq8woMhzmFpNhxEk2N1" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "EiMaivTu5DqfQohX8sYbFDrrumzFaSso9w3Z1sityvpP" - }, - { - "id": "frax", - "name": "wFRAX_v1-USDC", - "tokens": [ - { - "name": "Frax (Wormhole v1)", - "symbol": "wFRAX_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/8L8pDf3jutdpdr4m3np68CL9ZroLActrqwxi6s9Ah5xU.png", - "decimals": 9, - "address": "8L8pDf3jutdpdr4m3np68CL9ZroLActrqwxi6s9Ah5xU", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v1"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0x853d955aCEf822Db058eb8505911ED77F175b99e", - "coingeckoId": "frax", - "source": "wormhole-v1", - "address": "0x853d955aCEf822Db058eb8505911ED77F175b99e", - "currency": "USD", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "Frax (Wormhole v1)", - "symbol": "wFRAX_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/8L8pDf3jutdpdr4m3np68CL9ZroLActrqwxi6s9Ah5xU.png", - "decimals": 9, - "address": "8L8pDf3jutdpdr4m3np68CL9ZroLActrqwxi6s9Ah5xU", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v1"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0x853d955aCEf822Db058eb8505911ED77F175b99e", - "coingeckoId": "frax", - "source": "wormhole-v1", - "address": "0x853d955aCEf822Db058eb8505911ED77F175b99e", - "currency": "USD", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "Frax (Wormhole v1)", - "symbol": "wFRAX_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/8L8pDf3jutdpdr4m3np68CL9ZroLActrqwxi6s9Ah5xU.png", - "decimals": 9, - "address": "8L8pDf3jutdpdr4m3np68CL9ZroLActrqwxi6s9Ah5xU", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v1"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0x853d955aCEf822Db058eb8505911ED77F175b99e", - "coingeckoId": "frax", - "source": "wormhole-v1", - "address": "0x853d955aCEf822Db058eb8505911ED77F175b99e", - "currency": "USD", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "wFRAXv1-USDC", - "name": "Saber wFRAX_v1-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FRAXXvt2ucEsxYPK4nufDy5zKhb2xysieqRBE1dQTqnK.png", - "decimals": 9, - "address": "FRAXXvt2ucEsxYPK4nufDy5zKhb2xysieqRBE1dQTqnK", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"], - "extensions": { - "website": "https://app.saber.so/pools/frax", - "underlyingTokens": [ - "8L8pDf3jutdpdr4m3np68CL9ZroLActrqwxi6s9Ah5xU", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "source": "saber" - } - }, - "plotKey": "GdNLkwhFDq7JQMcui1L4qVGHwme32549F37VZyXY5ige", - "swap": { - "config": { - "swapAccount": "ZUCKWFa4LTL833dPhhpeeRWZcaAEoMeYJPi2iKn4F8N", - "authority": "GUotxHmyJVsJYWYoL8Vo6SKQweNRUZMRQcoqDe5PswHt", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "FRAXXvt2ucEsxYPK4nufDy5zKhb2xysieqRBE1dQTqnK", - "adminAccount": "5byxaarTCzxWz8yD9gY9odHjHp3qWFUPwZke3te8nQca", - "tokenA": { - "adminFeeAccount": "6zDvg7GVQuddPkhyT1wBHYanXEUchDkaiigzQgY1BGa6", - "mint": "8L8pDf3jutdpdr4m3np68CL9ZroLActrqwxi6s9Ah5xU", - "reserve": "7eEYpq6ShaJ9opZWMxitRFrdCHh6vfyHhGfoSvFht3N2" - }, - "tokenB": { - "adminFeeAccount": "GYJ4r6sSE4eMevkhpGxoYXG92W2xb1khCQF7uLaMsm3o", - "mint": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "reserve": "H8VggnHmuwd1wvwpT8eg9cUJFEfZ7HAaeYjgXrSm7A2u" - }, - "initialAmpFactor": "64", - "targetAmpFactor": "64", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "Cj4Ui8sa4CKSYZt4vVQF8QJsaa8Lgg6ykVseWXQkHTgU", - "newPoolID": "wfrax" - }, - { - "id": "frax_cash", - "name": "FRAX-CASH", - "tokens": [ - { - "name": "Frax (Wormhole)", - "symbol": "FRAX", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp.png", - "decimals": 8, - "address": "FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x853d955acef822db058eb8505911ed77f175b99e", - "coingeckoId": "frax", - "source": "wormhole-v2", - "address": "0x853d955acef822db058eb8505911ed77f175b99e", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Saber Wrapped Cashio Dollar (8 decimals)", - "address": "CASHedBw9NfhsLBXq1WNVfueVznx255j8LLTScto3S6s", - "decimals": 8, - "symbol": "sCASH-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHedBw9NfhsLBXq1WNVfueVznx255j8LLTScto3S6s.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/", - "assetContract": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "underlyingTokens": ["CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT"] - } - } - ], - "tokenIcons": [ - { - "name": "Frax (Wormhole)", - "symbol": "FRAX", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp.png", - "decimals": 8, - "address": "FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x853d955acef822db058eb8505911ed77f175b99e", - "coingeckoId": "frax", - "source": "wormhole-v2", - "address": "0x853d955acef822db058eb8505911ed77f175b99e", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Saber Wrapped Cashio Dollar (8 decimals)", - "address": "CASHedBw9NfhsLBXq1WNVfueVznx255j8LLTScto3S6s", - "decimals": 8, - "symbol": "sCASH-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHedBw9NfhsLBXq1WNVfueVznx255j8LLTScto3S6s.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/", - "assetContract": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "underlyingTokens": ["CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT"] - } - } - ], - "underlyingIcons": [ - { - "name": "Frax (Wormhole)", - "symbol": "FRAX", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp.png", - "decimals": 8, - "address": "FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x853d955acef822db058eb8505911ed77f175b99e", - "coingeckoId": "frax", - "source": "wormhole-v2", - "address": "0x853d955acef822db058eb8505911ed77f175b99e", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Cashio Dollar", - "symbol": "CASH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "decimals": 6, - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://cashio.app", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "FRAX-CASH", - "name": "Saber FRAX-CASH LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/WLPv9tHDgkx3ekW8Kyp1TC222oYpr5BMZXTyBTLbk2n.png", - "decimals": 8, - "address": "WLPv9tHDgkx3ekW8Kyp1TC222oYpr5BMZXTyBTLbk2n", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-cashio"], - "extensions": { - "website": "https://app.saber.so/pools/frax_cash", - "underlyingTokens": [ - "FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp", - "CASHedBw9NfhsLBXq1WNVfueVznx255j8LLTScto3S6s" - ], - "source": "saber" - } - }, - "plotKey": "71D6SDk62gRAPoxaJ5KUPp5BGtdxS6K7ZzNpLMyjSDaj", - "swap": { - "config": { - "swapAccount": "ZUCKP2rbfTojHnuKUkzCozccxVUWR5DBTL9QbPf9YLv", - "authority": "4f7eyeBbQkxzWtktc2cAXmUfpRq9TwTy7PmLqSBeZXUS", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": true, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "WLPv9tHDgkx3ekW8Kyp1TC222oYpr5BMZXTyBTLbk2n", - "adminAccount": "6rsCTVDP9nAi8AqpEy5hEYVMSFczgpeeoZuD7JacrSiQ", - "tokenA": { - "adminFeeAccount": "GU872PMSGjvg8ei27EutvQepH7nwX9i7Uf4JSuDXizgu", - "mint": "FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp", - "reserve": "DJZorZYrYhSwyw4oCBksDZVaUKvQtiaf5H1g285VPgqg" - }, - "tokenB": { - "adminFeeAccount": "5xzeGWjFvmavCuh7TesqLnSarq596yC5FfzWGA3cxsNx", - "mint": "CASHedBw9NfhsLBXq1WNVfueVznx255j8LLTScto3S6s", - "reserve": "GQ2YPKtfdjPJexWKFak1m4T16yHyWtbqkoGGh52QGmRX" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "2GaLgYiAejMPbhAYBxkcYDNgZXpEqqfwPKGQqjyWfyBi" - }, - { - "id": "frax_ust", - "name": "FRAX-UST", - "tokens": [ - { - "name": "Frax (Wormhole)", - "symbol": "FRAX", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp.png", - "decimals": 8, - "address": "FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x853d955acef822db058eb8505911ed77f175b99e", - "coingeckoId": "frax", - "source": "wormhole-v2", - "address": "0x853d955acef822db058eb8505911ed77f175b99e", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Saber Wrapped UST (Wormhole) (8 decimals)", - "address": "UST8SCn7jrqsq51odVLqcmvnC658HkqrKrPL3w2hHQ7", - "decimals": 8, - "symbol": "sUST-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/UST8SCn7jrqsq51odVLqcmvnC658HkqrKrPL3w2hHQ7.png", - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "website": "https://app.saber.so", - "assetContract": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "underlyingTokens": ["9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i"] - } - } - ], - "tokenIcons": [ - { - "name": "Frax (Wormhole)", - "symbol": "FRAX", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp.png", - "decimals": 8, - "address": "FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x853d955acef822db058eb8505911ed77f175b99e", - "coingeckoId": "frax", - "source": "wormhole-v2", - "address": "0x853d955acef822db058eb8505911ed77f175b99e", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Saber Wrapped UST (Wormhole) (8 decimals)", - "address": "UST8SCn7jrqsq51odVLqcmvnC658HkqrKrPL3w2hHQ7", - "decimals": 8, - "symbol": "sUST-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/UST8SCn7jrqsq51odVLqcmvnC658HkqrKrPL3w2hHQ7.png", - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "website": "https://app.saber.so", - "assetContract": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "underlyingTokens": ["9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i"] - } - } - ], - "underlyingIcons": [ - { - "name": "Frax (Wormhole)", - "symbol": "FRAX", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp.png", - "decimals": 8, - "address": "FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x853d955acef822db058eb8505911ed77f175b99e", - "coingeckoId": "frax", - "source": "wormhole-v2", - "address": "0x853d955acef822db058eb8505911ed77f175b99e", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "UST (Wormhole)", - "symbol": "UST", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i.png", - "decimals": 6, - "address": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "chainId": 101, - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "FRAX-UST", - "name": "Saber FRAX-UST LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/WLPGfDvnSsJg888FydDCRKkmKTwu4L3MHjfqBFj5LJD.png", - "decimals": 8, - "address": "WLPGfDvnSsJg888FydDCRKkmKTwu4L3MHjfqBFj5LJD", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"], - "extensions": { - "website": "https://app.saber.so/pools/frax_ust", - "underlyingTokens": [ - "FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp", - "UST8SCn7jrqsq51odVLqcmvnC658HkqrKrPL3w2hHQ7" - ], - "source": "saber" - } - }, - "plotKey": "A3YkUjZ3X5PsKXMQMobz9awAF6rohcV2gXB4zDHA4uEB", - "swap": { - "config": { - "swapAccount": "SAMyS8Jr2HJrkFwYVKbpUwsNStnQmvz3f8Tup8bWUWF", - "authority": "9tTrypFDQE3ChSPtwySjgomWDEi8XcTieGcYT3vXkgf1", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 253, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "WLPGfDvnSsJg888FydDCRKkmKTwu4L3MHjfqBFj5LJD", - "adminAccount": "9FqHS2BhCQH5Wy6ACjHXbktCbEN4RsBaVhiCBrf4hPKM", - "tokenA": { - "adminFeeAccount": "F8Bk1ZaBJz4FkMwXq8X1WiCB9wiRATiPMu37kkje7gJB", - "mint": "FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp", - "reserve": "6jPzm5TFfquvgm25sTyN3MMGBfufRaFHMxobDWv6hMFW" - }, - "tokenB": { - "adminFeeAccount": "A2JY3iRfCZrkJaZs2dUkuvpEvoMFCpQgjcyE4sV2zZDw", - "mint": "UST8SCn7jrqsq51odVLqcmvnC658HkqrKrPL3w2hHQ7", - "reserve": "Cj9ECoDmxsHTDzCY5ZA6RWrPbg9uFzEC1Qc2kso2vJG6" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "CSzKyCBEh2yxQYKavrzH9U1uiuNpeUEo691VnHrDVU5v" - }, - { - "id": "ftt", - "name": "wFTT_v1-soFTT", - "tokens": [ - { - "name": "FTT (Wormhole v1)", - "symbol": "wFTT_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/GbBWwtYTMPis4VHb8MrBbdibPhn28TSrLB53KvUmb7Gi.png", - "decimals": 9, - "address": "GbBWwtYTMPis4VHb8MrBbdibPhn28TSrLB53KvUmb7Gi", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-ftt", "wormhole-v1"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "coingeckoId": "ftx-token", - "source": "wormhole-v1", - "address": "0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "currency": "FTT", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - }, - { - "name": "Saber Wrapped Wrapped FTT (Sollet) (9 decimals)", - "address": "FTT9rBBrYwcHam4qLvkzzzhrsihYMbZ3k6wJbdoahxAt", - "decimals": 9, - "symbol": "ssoFTT-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FTT9rBBrYwcHam4qLvkzzzhrsihYMbZ3k6wJbdoahxAt.png", - "tags": [ - "wrapped-sollet", - "ethereum", - "saber-mkt-ftt", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "assetContract": "AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3", - "serumV3Usdt": "Hr3wzG8mZXNHV7TuL6YqtgfVUesCqMxGYCEyP3otywZE", - "serumV3Usdc": "2Pbh1CvRVku1TgewMfycemghf6sU9EyuFDcNXqvRmSxc", - "coingeckoId": "ftx-token", - "source": "sollet", - "currency": "FTT", - "sourceUrl": "https://www.sollet.io/", - "waterfallbot": "https://bit.ly/FTTwaterfall", - "website": "https://app.saber.so", - "underlyingTokens": ["AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3"] - } - } - ], - "tokenIcons": [ - { - "name": "FTT (Wormhole v1)", - "symbol": "wFTT_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/GbBWwtYTMPis4VHb8MrBbdibPhn28TSrLB53KvUmb7Gi.png", - "decimals": 9, - "address": "GbBWwtYTMPis4VHb8MrBbdibPhn28TSrLB53KvUmb7Gi", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-ftt", "wormhole-v1"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "coingeckoId": "ftx-token", - "source": "wormhole-v1", - "address": "0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "currency": "FTT", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - }, - { - "name": "Saber Wrapped Wrapped FTT (Sollet) (9 decimals)", - "address": "FTT9rBBrYwcHam4qLvkzzzhrsihYMbZ3k6wJbdoahxAt", - "decimals": 9, - "symbol": "ssoFTT-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FTT9rBBrYwcHam4qLvkzzzhrsihYMbZ3k6wJbdoahxAt.png", - "tags": [ - "wrapped-sollet", - "ethereum", - "saber-mkt-ftt", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "assetContract": "AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3", - "serumV3Usdt": "Hr3wzG8mZXNHV7TuL6YqtgfVUesCqMxGYCEyP3otywZE", - "serumV3Usdc": "2Pbh1CvRVku1TgewMfycemghf6sU9EyuFDcNXqvRmSxc", - "coingeckoId": "ftx-token", - "source": "sollet", - "currency": "FTT", - "sourceUrl": "https://www.sollet.io/", - "waterfallbot": "https://bit.ly/FTTwaterfall", - "website": "https://app.saber.so", - "underlyingTokens": ["AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3"] - } - } - ], - "underlyingIcons": [ - { - "name": "FTT (Wormhole v1)", - "symbol": "wFTT_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/GbBWwtYTMPis4VHb8MrBbdibPhn28TSrLB53KvUmb7Gi.png", - "decimals": 9, - "address": "GbBWwtYTMPis4VHb8MrBbdibPhn28TSrLB53KvUmb7Gi", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-ftt", "wormhole-v1"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "coingeckoId": "ftx-token", - "source": "wormhole-v1", - "address": "0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "currency": "FTT", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - }, - { - "name": "Wrapped FTT (Sollet)", - "symbol": "soFTT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3.png", - "decimals": 6, - "address": "AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3", - "chainId": 101, - "tags": ["wrapped-sollet", "ethereum", "saber-mkt-ftt"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "assetContract": "https://etherscan.io/address/0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "serumV3Usdt": "Hr3wzG8mZXNHV7TuL6YqtgfVUesCqMxGYCEyP3otywZE", - "serumV3Usdc": "2Pbh1CvRVku1TgewMfycemghf6sU9EyuFDcNXqvRmSxc", - "coingeckoId": "ftx-token", - "source": "sollet", - "currency": "FTT", - "sourceUrl": "https://www.sollet.io/", - "waterfallbot": "https://bit.ly/FTTwaterfall" - } - } - ], - "currency": "FTT", - "lpToken": { - "symbol": "wFTTv1-soFTT", - "name": "Saber wFTT_v1-soFTT LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FTXdV5wFFhceKjcd1JRrRQTT2uB7ruMerAqbj2rj1Mz7.png", - "decimals": 9, - "address": "FTXdV5wFFhceKjcd1JRrRQTT2uB7ruMerAqbj2rj1Mz7", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"], - "extensions": { - "website": "https://app.saber.so/pools/ftt", - "underlyingTokens": [ - "GbBWwtYTMPis4VHb8MrBbdibPhn28TSrLB53KvUmb7Gi", - "FTT9rBBrYwcHam4qLvkzzzhrsihYMbZ3k6wJbdoahxAt" - ], - "source": "saber" - } - }, - "plotKey": "69JS7H4E6i9TTpcA1UsH4GizxozzMttUbXFyCxiZ62Vf", - "swap": { - "config": { - "swapAccount": "SBFjafzbDXgDRsA5SUypY8FXjJ9sBdb4JbuQq2PHQDG", - "authority": "DGPFLHMzcfLeANN5m6gVoMFpo38KuU85tAGFHpLfn3gM", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "FTXdV5wFFhceKjcd1JRrRQTT2uB7ruMerAqbj2rj1Mz7", - "adminAccount": "6wBsm3V8jaYohknfs2wdhuiBEHcRdyzppCrb6QMJt8Sd", - "tokenA": { - "adminFeeAccount": "w3F7sdqZNgMGhcdoA4xY5ZXtjU9WZW8xUbGpyP768GJ", - "mint": "GbBWwtYTMPis4VHb8MrBbdibPhn28TSrLB53KvUmb7Gi", - "reserve": "46xwHtnXoQR3wCHUbm2eCAbPYWbioDQ59Te1Db8M5DDL" - }, - "tokenB": { - "adminFeeAccount": "9QGAnZgkoJTTD2i3njtmzeW4yMVSSk4kUA53pQP2NbRY", - "mint": "FTT9rBBrYwcHam4qLvkzzzhrsihYMbZ3k6wJbdoahxAt", - "reserve": "FC38fiikZwFvDt5zTjNtGfKd7LjaPz2uUAzLwKP5pRJY" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "AB17JLiVcGQ6DjRy69Pz2ydMcaJW6kNZVX2ajWT4g1Ke", - "newPoolID": "wftt" - }, - { - "id": "hbtc", - "name": "wHBTC_v1-renBTC", - "tokens": [ - { - "name": "HBTC (Wormhole v1)", - "symbol": "wHBTC_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/8pBc4v9GAwCBNWPB5XKA93APexMGAS4qMr37vNke9Ref.png", - "decimals": 9, - "address": "8pBc4v9GAwCBNWPB5XKA93APexMGAS4qMr37vNke9Ref", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-btc", "wormhole-v1"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0x0316EB71485b0Ab14103307bf65a021042c6d380", - "coingeckoId": "huobi-btc", - "source": "wormhole-v1", - "address": "0x0316EB71485b0Ab14103307bf65a021042c6d380", - "currency": "BTC", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - }, - { - "name": "Saber Wrapped renBTC (9 decimals)", - "address": "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5", - "decimals": 9, - "symbol": "srenBTC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5.png", - "tags": ["saber-mkt-btc", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint", - "assetContract": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "underlyingTokens": ["CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5"] - } - } - ], - "tokenIcons": [ - { - "name": "HBTC (Wormhole v1)", - "symbol": "wHBTC_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/8pBc4v9GAwCBNWPB5XKA93APexMGAS4qMr37vNke9Ref.png", - "decimals": 9, - "address": "8pBc4v9GAwCBNWPB5XKA93APexMGAS4qMr37vNke9Ref", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-btc", "wormhole-v1"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0x0316EB71485b0Ab14103307bf65a021042c6d380", - "coingeckoId": "huobi-btc", - "source": "wormhole-v1", - "address": "0x0316EB71485b0Ab14103307bf65a021042c6d380", - "currency": "BTC", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - }, - { - "name": "Saber Wrapped renBTC (9 decimals)", - "address": "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5", - "decimals": 9, - "symbol": "srenBTC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5.png", - "tags": ["saber-mkt-btc", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint", - "assetContract": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "underlyingTokens": ["CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5"] - } - } - ], - "underlyingIcons": [ - { - "name": "HBTC (Wormhole v1)", - "symbol": "wHBTC_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/8pBc4v9GAwCBNWPB5XKA93APexMGAS4qMr37vNke9Ref.png", - "decimals": 9, - "address": "8pBc4v9GAwCBNWPB5XKA93APexMGAS4qMr37vNke9Ref", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-btc", "wormhole-v1"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0x0316EB71485b0Ab14103307bf65a021042c6d380", - "coingeckoId": "huobi-btc", - "source": "wormhole-v1", - "address": "0x0316EB71485b0Ab14103307bf65a021042c6d380", - "currency": "BTC", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - }, - { - "name": "renBTC", - "symbol": "renBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5.png", - "decimals": 8, - "address": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "website": "https://renproject.io/", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint" - } - } - ], - "currency": "BTC", - "lpToken": { - "symbol": "wHBTCv1-renBTC", - "name": "Saber wHBTC_v1-renBTC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/HBTCNvkwjMsEtwe2PeXUuMcu8C4Hobw6HDP2m6vpWHGo.png", - "decimals": 9, - "address": "HBTCNvkwjMsEtwe2PeXUuMcu8C4Hobw6HDP2m6vpWHGo", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"], - "extensions": { - "website": "https://app.saber.so/pools/hbtc", - "underlyingTokens": [ - "8pBc4v9GAwCBNWPB5XKA93APexMGAS4qMr37vNke9Ref", - "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5" - ], - "source": "saber" - } - }, - "plotKey": "6YtaMDi2WozuD5LkWoqzdZnTyLR3KwYdwqHNf5bxaCx1", - "swap": { - "config": { - "swapAccount": "DJUn4vhv4YQHhDRfxmLtu7f8sGnZpgnKG5GHzA7wFPB9", - "authority": "G4cRef4AxEjaSV32xqQzDmHqi3iz8112LQwx8oPbZhYb", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "HBTCNvkwjMsEtwe2PeXUuMcu8C4Hobw6HDP2m6vpWHGo", - "adminAccount": "92H7ecfzcHGqoDzpg68baUFeE4NADmCGQonQxKkuu1r", - "tokenA": { - "adminFeeAccount": "FmAFsnakh4SncY4FhLFa7CdAycpUA6pMqa8ifePPpWUf", - "mint": "8pBc4v9GAwCBNWPB5XKA93APexMGAS4qMr37vNke9Ref", - "reserve": "GsizhiRtCs4QDKd2LnSQ9BpzvG8CqERMDtHZcQPDkFQB" - }, - "tokenB": { - "adminFeeAccount": "Gtv8pLuiNrYkfZnpwdPkhteETXfjo28gu8PLbKTU4JBg", - "mint": "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5", - "reserve": "CRaJHfCry6JShmF4tMr6siR2D2QNNfcUrLawTqPVCTTJ" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "HHs32Mph7a19onVvNyfPTvxs8gdjbwfd576KtRwspX2u" - }, - { - "id": "husd", - "name": "wHUSD_v1-USDC", - "tokens": [ - { - "name": "HUSD Stablecoin (Wormhole v1)", - "symbol": "wHUSD_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BybpSTBoZHsmKnfxYG47GDhVPKrnEKX31CScShbrzUhX.png", - "decimals": 8, - "address": "BybpSTBoZHsmKnfxYG47GDhVPKrnEKX31CScShbrzUhX", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v1"], - "extensions": { - "website": "https://www.stcoins.com/", - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0xdf574c24545e5ffecb9a659c229253d4111d87e1", - "coingeckoId": "husd", - "source": "wormhole-v1", - "address": "0xdf574c24545e5ffecb9a659c229253d4111d87e1", - "currency": "USD", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - }, - { - "name": "Saber Wrapped USD Coin (8 decimals)", - "address": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "decimals": 8, - "symbol": "sUSDC-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "HUSD Stablecoin (Wormhole v1)", - "symbol": "wHUSD_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BybpSTBoZHsmKnfxYG47GDhVPKrnEKX31CScShbrzUhX.png", - "decimals": 8, - "address": "BybpSTBoZHsmKnfxYG47GDhVPKrnEKX31CScShbrzUhX", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v1"], - "extensions": { - "website": "https://www.stcoins.com/", - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0xdf574c24545e5ffecb9a659c229253d4111d87e1", - "coingeckoId": "husd", - "source": "wormhole-v1", - "address": "0xdf574c24545e5ffecb9a659c229253d4111d87e1", - "currency": "USD", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - }, - { - "name": "Saber Wrapped USD Coin (8 decimals)", - "address": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "decimals": 8, - "symbol": "sUSDC-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "HUSD Stablecoin (Wormhole v1)", - "symbol": "wHUSD_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BybpSTBoZHsmKnfxYG47GDhVPKrnEKX31CScShbrzUhX.png", - "decimals": 8, - "address": "BybpSTBoZHsmKnfxYG47GDhVPKrnEKX31CScShbrzUhX", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v1"], - "extensions": { - "website": "https://www.stcoins.com/", - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0xdf574c24545e5ffecb9a659c229253d4111d87e1", - "coingeckoId": "husd", - "source": "wormhole-v1", - "address": "0xdf574c24545e5ffecb9a659c229253d4111d87e1", - "currency": "USD", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "wHUSDv1-USDC", - "name": "Saber wHUSD_v1-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/HUSDgP5YieANhAAHD42yivX9aFS1zbodTut2Dvvkj8QS.png", - "decimals": 8, - "address": "HUSDgP5YieANhAAHD42yivX9aFS1zbodTut2Dvvkj8QS", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"], - "extensions": { - "website": "https://app.saber.so/pools/husd", - "underlyingTokens": [ - "BybpSTBoZHsmKnfxYG47GDhVPKrnEKX31CScShbrzUhX", - "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy" - ], - "source": "saber" - } - }, - "plotKey": "AckM1mipndQXeBq71pA1mFFVED8DSkxks7zm7Tawt6Ub", - "swap": { - "config": { - "swapAccount": "MNkYtBe2HtgL15osfaMmyqNW3vo4J399FXXCS4a39Wf", - "authority": "ELnY6YAb1oSPGuARAV8rBJq44AXgT69GJhvWNfuabq9B", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "HUSDgP5YieANhAAHD42yivX9aFS1zbodTut2Dvvkj8QS", - "adminAccount": "7aWsoASuLaK5QqKZS8A3TGib8wx5w1XfKSAGRqPapdKu", - "tokenA": { - "adminFeeAccount": "8BRDKte3z6zq2MoNJNStbNZuuV63oeSkXNXcjLKNbsL", - "mint": "BybpSTBoZHsmKnfxYG47GDhVPKrnEKX31CScShbrzUhX", - "reserve": "2mUxDu8NrhSKhQJMgKfYLxJqZzeEbmwhQdHeHMyohyuk" - }, - "tokenB": { - "adminFeeAccount": "7EkNdJnxsCMHJ7eFaZuzCCoVpwbCPg8NaCUwgGhNkEQ", - "mint": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "reserve": "AZCBmDBcFsA2jHHhfFJBTsWCHx9XnnKmGfFsue3ZVW1t" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "4DqNHQTQTXkHgcsAQaBVYaqZUiPBqtdf73P4q2octpJH", - "newPoolID": "whusd" - }, - { - "id": "ibbtc", - "name": "wibBTC_V1-BTC", - "tokens": [ - { - "symbol": "wibBTC_V1", - "name": "ibBTC (Wormhole V1)", - "logoURI": "https://registry.saber.so/token-icons/ibbtc.svg", - "address": "66CgfJQoZkpkrEgC1z4vFJcSFc4V6T5HqbjSSNuqcNJz", - "decimals": 9, - "extensions": { - "coingeckoId": "bitcoin", - "source": "wormhole-v1", - "currency": "BTC", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "chainId": 101, - "tags": ["saber-mkt-btc", "wormhole-v1"] - }, - { - "name": "Saber Wrapped Wrapped Bitcoin (Sollet) (9 decimals)", - "address": "9999j2A8sXUtHtDoQdk528oVzhaKBsXyRGZ67FKGoi7H", - "decimals": 9, - "symbol": "sBTC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9999j2A8sXUtHtDoQdk528oVzhaKBsXyRGZ67FKGoi7H.png", - "tags": [ - "wrapped-sollet", - "ethereum", - "saber-mkt-btc", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "serumV3Usdt": "C1EuT9VokAKLiW7i2ASnZUvxDoKuKkCpDDeNxAptuNe4", - "serumV3Usdc": "A8YFbxQYFVqKZaoYJLLUVcQiWP7G2MeEgW5wsAQgMvFw", - "coingeckoId": "bitcoin", - "source": "sollet", - "currency": "BTC", - "sourceUrl": "https://www.sollet.io/", - "website": "https://app.saber.so", - "assetContract": "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "underlyingTokens": ["9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E"] - } - } - ], - "tokenIcons": [ - { - "symbol": "wibBTC_V1", - "name": "ibBTC (Wormhole V1)", - "logoURI": "https://registry.saber.so/token-icons/ibbtc.svg", - "address": "66CgfJQoZkpkrEgC1z4vFJcSFc4V6T5HqbjSSNuqcNJz", - "decimals": 9, - "extensions": { - "coingeckoId": "bitcoin", - "source": "wormhole-v1", - "currency": "BTC", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "chainId": 101, - "tags": ["saber-mkt-btc", "wormhole-v1"] - }, - { - "name": "Saber Wrapped Wrapped Bitcoin (Sollet) (9 decimals)", - "address": "9999j2A8sXUtHtDoQdk528oVzhaKBsXyRGZ67FKGoi7H", - "decimals": 9, - "symbol": "sBTC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9999j2A8sXUtHtDoQdk528oVzhaKBsXyRGZ67FKGoi7H.png", - "tags": [ - "wrapped-sollet", - "ethereum", - "saber-mkt-btc", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "serumV3Usdt": "C1EuT9VokAKLiW7i2ASnZUvxDoKuKkCpDDeNxAptuNe4", - "serumV3Usdc": "A8YFbxQYFVqKZaoYJLLUVcQiWP7G2MeEgW5wsAQgMvFw", - "coingeckoId": "bitcoin", - "source": "sollet", - "currency": "BTC", - "sourceUrl": "https://www.sollet.io/", - "website": "https://app.saber.so", - "assetContract": "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "underlyingTokens": ["9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E"] - } - } - ], - "underlyingIcons": [ - { - "symbol": "wibBTC_V1", - "name": "ibBTC (Wormhole V1)", - "logoURI": "https://registry.saber.so/token-icons/ibbtc.svg", - "address": "66CgfJQoZkpkrEgC1z4vFJcSFc4V6T5HqbjSSNuqcNJz", - "decimals": 9, - "extensions": { - "coingeckoId": "bitcoin", - "source": "wormhole-v1", - "currency": "BTC", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "chainId": 101, - "tags": ["saber-mkt-btc", "wormhole-v1"] - }, - { - "name": "Wrapped Bitcoin (Sollet)", - "symbol": "BTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E.png", - "decimals": 6, - "address": "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "chainId": 101, - "tags": ["wrapped-sollet", "ethereum", "saber-mkt-btc"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "serumV3Usdt": "C1EuT9VokAKLiW7i2ASnZUvxDoKuKkCpDDeNxAptuNe4", - "serumV3Usdc": "A8YFbxQYFVqKZaoYJLLUVcQiWP7G2MeEgW5wsAQgMvFw", - "coingeckoId": "bitcoin", - "source": "sollet", - "currency": "BTC", - "sourceUrl": "https://www.sollet.io/" - } - } - ], - "currency": "BTC", - "lpToken": { - "symbol": "wibBTCV1-BTC", - "name": "Saber wibBTC_V1-BTC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BADGsQo6rTxKZuqkY1kSoqhriQwZW3ZVgyPjgDk9mvyo.png", - "decimals": 9, - "address": "BADGsQo6rTxKZuqkY1kSoqhriQwZW3ZVgyPjgDk9mvyo", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"], - "extensions": { - "website": "https://app.saber.so/pools/ibbtc", - "underlyingTokens": [ - "66CgfJQoZkpkrEgC1z4vFJcSFc4V6T5HqbjSSNuqcNJz", - "9999j2A8sXUtHtDoQdk528oVzhaKBsXyRGZ67FKGoi7H" - ], - "source": "saber" - } - }, - "plotKey": "7mZ2N8BSXW5vM1vqxSqahe1ivvZqpChHQRzmBJAqLGmU", - "swap": { - "config": { - "swapAccount": "SAVEEos8BnE9mgk8fw6yV22Ffk1eeHEJq95ewErUhbT", - "authority": "4PHvSwhw8Gz26UZfgSjDLx8JLpJnh2kpNCtssgGUKQFe", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 253, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "BADGsQo6rTxKZuqkY1kSoqhriQwZW3ZVgyPjgDk9mvyo", - "adminAccount": "GYy4BUnHozWRxjKP8mz2T1AXv981cBvXUfZYwXDKfWph", - "tokenA": { - "adminFeeAccount": "4S4qeth7kHVRKNHo6RbmVyBgeYGK4SSvWLUY5sPDHqQV", - "mint": "66CgfJQoZkpkrEgC1z4vFJcSFc4V6T5HqbjSSNuqcNJz", - "reserve": "Fb2Zdo7hWjMmwMXn7589WbPbjVPxVUQgPgs5cAcStJm8" - }, - "tokenB": { - "adminFeeAccount": "BFV1kpikR9gCzM8KakXLN25cfMP8VsgVBFyqEHNkRStG", - "mint": "9999j2A8sXUtHtDoQdk528oVzhaKBsXyRGZ67FKGoi7H", - "reserve": "AjVXZPzFEShWkGASQv5dBp9r4Xf6V1mvyHWfH5UWF9c3" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "9D8qdTZeYupfK51k2fAXmNTSUbkhzKz12VqUVm7Y9pwi", - "newPoolID": "ibbtc_ren" - }, - { - "id": "ibbtc_ren", - "name": "wibBTC_V1-renBTC", - "tokens": [ - { - "symbol": "wibBTC_V1", - "name": "ibBTC (Wormhole V1)", - "logoURI": "https://registry.saber.so/token-icons/ibbtc.svg", - "address": "66CgfJQoZkpkrEgC1z4vFJcSFc4V6T5HqbjSSNuqcNJz", - "decimals": 9, - "extensions": { - "coingeckoId": "bitcoin", - "source": "wormhole-v1", - "currency": "BTC", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "chainId": 101, - "tags": ["saber-mkt-btc", "wormhole-v1"] - }, - { - "name": "Saber Wrapped renBTC (9 decimals)", - "address": "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5", - "decimals": 9, - "symbol": "srenBTC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5.png", - "tags": ["saber-mkt-btc", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint", - "assetContract": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "underlyingTokens": ["CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5"] - } - } - ], - "tokenIcons": [ - { - "symbol": "wibBTC_V1", - "name": "ibBTC (Wormhole V1)", - "logoURI": "https://registry.saber.so/token-icons/ibbtc.svg", - "address": "66CgfJQoZkpkrEgC1z4vFJcSFc4V6T5HqbjSSNuqcNJz", - "decimals": 9, - "extensions": { - "coingeckoId": "bitcoin", - "source": "wormhole-v1", - "currency": "BTC", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "chainId": 101, - "tags": ["saber-mkt-btc", "wormhole-v1"] - }, - { - "name": "Saber Wrapped renBTC (9 decimals)", - "address": "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5", - "decimals": 9, - "symbol": "srenBTC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5.png", - "tags": ["saber-mkt-btc", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint", - "assetContract": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "underlyingTokens": ["CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5"] - } - } - ], - "underlyingIcons": [ - { - "symbol": "wibBTC_V1", - "name": "ibBTC (Wormhole V1)", - "logoURI": "https://registry.saber.so/token-icons/ibbtc.svg", - "address": "66CgfJQoZkpkrEgC1z4vFJcSFc4V6T5HqbjSSNuqcNJz", - "decimals": 9, - "extensions": { - "coingeckoId": "bitcoin", - "source": "wormhole-v1", - "currency": "BTC", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "chainId": 101, - "tags": ["saber-mkt-btc", "wormhole-v1"] - }, - { - "name": "renBTC", - "symbol": "renBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5.png", - "decimals": 8, - "address": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "website": "https://renproject.io/", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint" - } - } - ], - "currency": "BTC", - "lpToken": { - "symbol": "wibBTCV1-renBTC", - "name": "Saber wibBTC_V1-renBTC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BRENm9SgYJZuCxM4ZJiH6CmZqEBn4MLpD9cnBZDnJgeT.png", - "decimals": 9, - "address": "BRENm9SgYJZuCxM4ZJiH6CmZqEBn4MLpD9cnBZDnJgeT", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"], - "extensions": { - "website": "https://app.saber.so/pools/ibbtc_ren", - "underlyingTokens": [ - "66CgfJQoZkpkrEgC1z4vFJcSFc4V6T5HqbjSSNuqcNJz", - "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5" - ], - "source": "saber" - } - }, - "plotKey": "4EiuieY6S4a8jAU7MVPzckVixbf3VFLgCyZxQFVYvwak", - "swap": { - "config": { - "swapAccount": "BDGnasCnLUuqHVpHipGuevAsnHuMsBLya1RZSo4ZzMUF", - "authority": "3rjYaVP4fkv4BVQsA7aaC7DZUdogkna7ACGaAhiuNYfi", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "BRENm9SgYJZuCxM4ZJiH6CmZqEBn4MLpD9cnBZDnJgeT", - "adminAccount": "4UaNQKQBPzBVrJhjfqtv4bHmcrL6DTy6KN5H6W2grNg1", - "tokenA": { - "adminFeeAccount": "4mj3SDyGGMpWGmECFiwY38CA6sLxBgLqjERJShC3B9By", - "mint": "66CgfJQoZkpkrEgC1z4vFJcSFc4V6T5HqbjSSNuqcNJz", - "reserve": "CZ48nQQ6GK8Z7hGBPdxTtMzRBA8werj5iciVJnc3vz1S" - }, - "tokenB": { - "adminFeeAccount": "DEtSQshR5MTo2wzgwACG5SjwmpAUqRTyMeqKxiRgbgCY", - "mint": "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5", - "reserve": "G3nLYyvP46npva5MEobZVJhcDNzJ4rrHgLGJMtvyad5c" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "FP4zv3sQiVLgr5j2jV6cfvLeMi7ekVQL8tNSJuyUyhdy", - "newPoolID": "ibbtc_ren" - }, - { - "id": "jsol", - "name": "JSOL-SOL", - "tokens": [ - { - "name": "JPOOL Solana Token", - "symbol": "JSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn.svg", - "decimals": 9, - "address": "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn", - "chainId": 101, - "tags": ["stake-pool-token", "utility-token", "saber-mkt-sol"], - "extensions": { - "website": "https://jpool.one/", - "twitter": "https://twitter.com/JPoolSolana", - "discord": "https://discord.gg/qR4BA9QXVR", - "coingeckoId": "solana", - "source": "jpool", - "currency": "SOL", - "sourceUrl": "https://jpool.one/", - "telegram": "https://t.me/jpoolsolana" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "tokenIcons": [ - { - "name": "JPOOL Solana Token", - "symbol": "JSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn.svg", - "decimals": 9, - "address": "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn", - "chainId": 101, - "tags": ["stake-pool-token", "utility-token", "saber-mkt-sol"], - "extensions": { - "website": "https://jpool.one/", - "twitter": "https://twitter.com/JPoolSolana", - "discord": "https://discord.gg/qR4BA9QXVR", - "coingeckoId": "solana", - "source": "jpool", - "currency": "SOL", - "sourceUrl": "https://jpool.one/", - "telegram": "https://t.me/jpoolsolana" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "underlyingIcons": [ - { - "name": "JPOOL Solana Token", - "symbol": "JSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn.svg", - "decimals": 9, - "address": "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn", - "chainId": 101, - "tags": ["stake-pool-token", "utility-token", "saber-mkt-sol"], - "extensions": { - "website": "https://jpool.one/", - "twitter": "https://twitter.com/JPoolSolana", - "discord": "https://discord.gg/qR4BA9QXVR", - "coingeckoId": "solana", - "source": "jpool", - "currency": "SOL", - "sourceUrl": "https://jpool.one/", - "telegram": "https://t.me/jpoolsolana" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "currency": "SOL", - "lpToken": { - "symbol": "JSOL-SOL", - "name": "Saber JSOL-SOL LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/son4WQ39xri8sqMqNQZAEtEEPTuUcCRHg7t1ZcYdkSw.png", - "decimals": 9, - "address": "son4WQ39xri8sqMqNQZAEtEEPTuUcCRHg7t1ZcYdkSw", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/jsol", - "underlyingTokens": [ - "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn", - "So11111111111111111111111111111111111111112" - ], - "source": "saber" - } - }, - "plotKey": "AL6i2HX3eUuAuUiUmBp2baE3R4pLBHaiyJV3MC2pWC2d", - "swap": { - "config": { - "swapAccount": "JSoLLrxK5bYdHwTEWYaGgmeycBCNXKDiBCTw5hXGBg7", - "authority": "75kJUwEvBpyvDFKrpeCmcyhADEGwfqAaLQCwhRNV2FMk", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 251, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "son4WQ39xri8sqMqNQZAEtEEPTuUcCRHg7t1ZcYdkSw", - "adminAccount": "3EXaPffAJVAfvyo8mAvGs6YkLv5VTygQDK7kdNf8hLmZ", - "tokenA": { - "adminFeeAccount": "L654oTbsHiU6suMLKmqrsCTDiurqgBmYPkbkHFTtFr6", - "mint": "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn", - "reserve": "xG4wXczA7Dk4hccJ61CHKpDHW4NrNfQwgmWgkb9BuF2" - }, - "tokenB": { - "adminFeeAccount": "7EADztM7KHFSXoZVshPGLSjBDm8jnoshM5gwqZqzBsbV", - "mint": "So11111111111111111111111111111111111111112", - "reserve": "BVR6WgfhsRr9Lob4QDnkEAiNGgAbv7ZieKcY9kSg3QYR" - }, - "initialAmpFactor": "4b", - "targetAmpFactor": "4b", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "2hk3Qcp1mDvGNdQuPN3GoFKaLeQ3QaGmfeg4UTtaZey7" - }, - { - "id": "luna", - "name": "wLUNA_v1-renLUNA", - "tokens": [ - { - "name": "Wrapped LUNA Token (Wormhole v1)", - "symbol": "wLUNA_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/2Xf2yAXJfg82sWwdLUo2x9mZXy6JCdszdMZkcF1Hf4KV.png", - "decimals": 9, - "address": "2Xf2yAXJfg82sWwdLUo2x9mZXy6JCdszdMZkcF1Hf4KV", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-luna", "wormhole-v1"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0xd2877702675e6cEb975b4A1dFf9fb7BAF4C91ea9", - "coingeckoId": "wrapped-terra", - "source": "wormhole-v1", - "address": "0xd2877702675e6cEb975b4A1dFf9fb7BAF4C91ea9", - "currency": "LUNA", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - }, - { - "name": "Saber Wrapped renLUNA (9 decimals)", - "address": "KUANeD8EQvwpT1W7QZDtDqctLEh2FfSTy5pThE9CogT", - "decimals": 9, - "symbol": "srenLUNA-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/KUANeD8EQvwpT1W7QZDtDqctLEh2FfSTy5pThE9CogT.png", - "tags": ["saber-mkt-luna", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "CxDhLbbM9uAA2AXfSPar5qmyfmC69NLj3vgJXYAsSVBT", - "coingeckoId": "terra-luna", - "source": "renbridge", - "currency": "LUNA", - "sourceUrl": "https://bridge.renproject.io/mint", - "assetContract": "8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE", - "underlyingTokens": ["8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped LUNA Token (Wormhole v1)", - "symbol": "wLUNA_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/2Xf2yAXJfg82sWwdLUo2x9mZXy6JCdszdMZkcF1Hf4KV.png", - "decimals": 9, - "address": "2Xf2yAXJfg82sWwdLUo2x9mZXy6JCdszdMZkcF1Hf4KV", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-luna", "wormhole-v1"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0xd2877702675e6cEb975b4A1dFf9fb7BAF4C91ea9", - "coingeckoId": "wrapped-terra", - "source": "wormhole-v1", - "address": "0xd2877702675e6cEb975b4A1dFf9fb7BAF4C91ea9", - "currency": "LUNA", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - }, - { - "name": "Saber Wrapped renLUNA (9 decimals)", - "address": "KUANeD8EQvwpT1W7QZDtDqctLEh2FfSTy5pThE9CogT", - "decimals": 9, - "symbol": "srenLUNA-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/KUANeD8EQvwpT1W7QZDtDqctLEh2FfSTy5pThE9CogT.png", - "tags": ["saber-mkt-luna", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "CxDhLbbM9uAA2AXfSPar5qmyfmC69NLj3vgJXYAsSVBT", - "coingeckoId": "terra-luna", - "source": "renbridge", - "currency": "LUNA", - "sourceUrl": "https://bridge.renproject.io/mint", - "assetContract": "8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE", - "underlyingTokens": ["8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped LUNA Token (Wormhole v1)", - "symbol": "wLUNA_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/2Xf2yAXJfg82sWwdLUo2x9mZXy6JCdszdMZkcF1Hf4KV.png", - "decimals": 9, - "address": "2Xf2yAXJfg82sWwdLUo2x9mZXy6JCdszdMZkcF1Hf4KV", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-luna", "wormhole-v1"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0xd2877702675e6cEb975b4A1dFf9fb7BAF4C91ea9", - "coingeckoId": "wrapped-terra", - "source": "wormhole-v1", - "address": "0xd2877702675e6cEb975b4A1dFf9fb7BAF4C91ea9", - "currency": "LUNA", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - }, - { - "name": "renLUNA", - "symbol": "renLUNA", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE.png", - "decimals": 6, - "address": "8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE", - "chainId": 101, - "tags": ["saber-mkt-luna"], - "extensions": { - "website": "https://renproject.io/", - "serumV3Usdc": "CxDhLbbM9uAA2AXfSPar5qmyfmC69NLj3vgJXYAsSVBT", - "coingeckoId": "terra-luna", - "source": "renbridge", - "currency": "LUNA", - "sourceUrl": "https://bridge.renproject.io/mint" - } - } - ], - "currency": "LUNA", - "lpToken": { - "symbol": "wLUNAv1-renLUNA", - "name": "Saber wLUNA_v1-renLUNA LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/LUNkiLcb2wxcqULmJvMjuM6YQhpFBadG5KZBe7qBpSE.png", - "decimals": 9, - "address": "LUNkiLcb2wxcqULmJvMjuM6YQhpFBadG5KZBe7qBpSE", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"], - "extensions": { - "website": "https://app.saber.so/pools/luna", - "underlyingTokens": [ - "2Xf2yAXJfg82sWwdLUo2x9mZXy6JCdszdMZkcF1Hf4KV", - "KUANeD8EQvwpT1W7QZDtDqctLEh2FfSTy5pThE9CogT" - ], - "source": "saber" - } - }, - "plotKey": "9o2JPTjrxuzF6Skg6jKo5MHCoFrZGLieFx2feukaw5qS", - "swap": { - "config": { - "swapAccount": "4EFeyTtMZZnAv3ZPs2jvps1T1J1JykbpyizrWjBQcA1S", - "authority": "4HP9xSxLcEK64zALBCP36GdfDLrMXorVk4X6DyLrBjbp", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "LUNkiLcb2wxcqULmJvMjuM6YQhpFBadG5KZBe7qBpSE", - "adminAccount": "7fzNsrhQwGqr5Lob4YsqdzTRd9KHBNptyWmEGRFrqncf", - "tokenA": { - "adminFeeAccount": "EEzYzTTAPxa67vwozPfyf5Q1pFbzhhkktPAFYkQg9Jdv", - "mint": "2Xf2yAXJfg82sWwdLUo2x9mZXy6JCdszdMZkcF1Hf4KV", - "reserve": "Au5zcSost9sXpH8AQQjULRXJ9QCJ3kdKehUr1zYzTr6G" - }, - "tokenB": { - "adminFeeAccount": "4KysWyKdL5xrziKL2m4k5AXTAsiBSGVz38bapcCcdaWT", - "mint": "KUANeD8EQvwpT1W7QZDtDqctLEh2FfSTy5pThE9CogT", - "reserve": "Gx1L7n1YhDWLNfUyCeZfzKvwHJSxhppnk4DS5cZLqyd" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "FaEnerTg1tsHKtqXfjGKtHMDkUrd4pe6i7d41qoYDUJf", - "newPoolID": "wluna" - }, - { - "id": "mai", - "name": "MAI-USDC", - "tokens": [ - { - "symbol": "MAI", - "name": "MAI Stablecoin", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9mWRABuz2x6koTPCWiCPM49WUbcrNqGTHBV9T9k7y1o7.png", - "address": "9mWRABuz2x6koTPCWiCPM49WUbcrNqGTHBV9T9k7y1o7", - "decimals": 9, - "extensions": { - "coingeckoId": "mimatic", - "website": "https://mai.finance/", - "twitter": "https://twitter.com/QiDaoProtocol", - "discord": "https://discord.com/invite/mQq55j65xJ", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "symbol": "MAI", - "name": "MAI Stablecoin", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9mWRABuz2x6koTPCWiCPM49WUbcrNqGTHBV9T9k7y1o7.png", - "address": "9mWRABuz2x6koTPCWiCPM49WUbcrNqGTHBV9T9k7y1o7", - "decimals": 9, - "extensions": { - "coingeckoId": "mimatic", - "website": "https://mai.finance/", - "twitter": "https://twitter.com/QiDaoProtocol", - "discord": "https://discord.com/invite/mQq55j65xJ", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "symbol": "MAI", - "name": "MAI Stablecoin", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9mWRABuz2x6koTPCWiCPM49WUbcrNqGTHBV9T9k7y1o7.png", - "address": "9mWRABuz2x6koTPCWiCPM49WUbcrNqGTHBV9T9k7y1o7", - "decimals": 9, - "extensions": { - "coingeckoId": "mimatic", - "website": "https://mai.finance/", - "twitter": "https://twitter.com/QiDaoProtocol", - "discord": "https://discord.com/invite/mQq55j65xJ", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "MAI-USDC", - "name": "Saber MAI-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/MAiP3Zmjhc6NYiCb2xK2893ifvTTDHciCS57Kga39pC.png", - "decimals": 9, - "address": "MAiP3Zmjhc6NYiCb2xK2893ifvTTDHciCS57Kga39pC", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/mai", - "underlyingTokens": [ - "9mWRABuz2x6koTPCWiCPM49WUbcrNqGTHBV9T9k7y1o7", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "source": "saber" - } - }, - "plotKey": "3c9AVNMwXanJ3CJSimTrDohMuHixPdensTCTJfGhKiyU", - "swap": { - "config": { - "swapAccount": "DFWzVTzNBrQZLjoQ4yQwkj9HuoXmfkuZP9V5vbymZe23", - "authority": "41gN5ZP7inB3rgqQikVxWcfofyYsxH4zWQBRWyJrdZCy", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 253, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "MAiP3Zmjhc6NYiCb2xK2893ifvTTDHciCS57Kga39pC", - "adminAccount": "34hMvpVYhYvWM6wSffNB4h1mTXkjTRXkbNDFTbkjLyUD", - "tokenA": { - "adminFeeAccount": "2tR1oPw113ZYpjFXfAGDqS8AYUd3LwYRoYCojJWHL1P2", - "mint": "9mWRABuz2x6koTPCWiCPM49WUbcrNqGTHBV9T9k7y1o7", - "reserve": "DhgiEgiNdqZdRdo195UUHnoEJUtefK8buko8nU97XJUZ" - }, - "tokenB": { - "adminFeeAccount": "2Ufi3AsrUeiJHfW1H56ifNzzaVXPovzoEvG9xPipL6MV", - "mint": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "reserve": "2K2kkXsouBHtWVjtcgkyiXd8eP3oVBvq1bTJzcVdLLr2" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "GfhJbBiT4Yfv3FvnGY42EBGReCJpbLgQZbaZ8KuPydK5" - }, - { - "id": "mim_cash", - "name": "aeMIM-CASH", - "tokens": [ - { - "name": "Wrapped MIM (Allbridge from Ethereum)", - "symbol": "aeMIM", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj.png", - "decimals": 9, - "address": "2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj", - "chainId": 101, - "tags": ["saber-mkt-usd"], - "extensions": { - "coingeckoId": "magic-internet-money", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped Cashio Dollar (9 decimals)", - "address": "C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi", - "decimals": 9, - "symbol": "sCASH-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/", - "assetContract": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "underlyingTokens": ["CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped MIM (Allbridge from Ethereum)", - "symbol": "aeMIM", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj.png", - "decimals": 9, - "address": "2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj", - "chainId": 101, - "tags": ["saber-mkt-usd"], - "extensions": { - "coingeckoId": "magic-internet-money", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped Cashio Dollar (9 decimals)", - "address": "C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi", - "decimals": 9, - "symbol": "sCASH-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/", - "assetContract": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "underlyingTokens": ["CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped MIM (Allbridge from Ethereum)", - "symbol": "aeMIM", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj.png", - "decimals": 9, - "address": "2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj", - "chainId": 101, - "tags": ["saber-mkt-usd"], - "extensions": { - "coingeckoId": "magic-internet-money", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Cashio Dollar", - "symbol": "CASH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "decimals": 6, - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://cashio.app", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "aeMIM-CASH", - "name": "Saber aeMIM-CASH LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/ALPbh25PVwDDEhmJizhrtyhfgXNjh17RtbZc4i5ZAHdh.png", - "decimals": 9, - "address": "ALPbh25PVwDDEhmJizhrtyhfgXNjh17RtbZc4i5ZAHdh", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/mim_cash", - "underlyingTokens": [ - "2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj", - "C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi" - ], - "source": "saber" - } - }, - "plotKey": "Dj1MPf57hjLz8hxQSBAo6GJ5fntTt1PHJRKgpNSRdBMz", - "swap": { - "config": { - "swapAccount": "MiMx8GQKM5CaDTCKcuK9VeTdrpEvPKR4ScyhSe4kYv1", - "authority": "FURmDMwhGoo9xJa32RPzT4o7H6vHLf2Fx7C2Wmu6hmVf", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": true, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "ALPbh25PVwDDEhmJizhrtyhfgXNjh17RtbZc4i5ZAHdh", - "adminAccount": "ATbJTL2m8jqXn6YPJSvD3RWZZBzBLcLsTbGZ7ggefJ3z", - "tokenA": { - "adminFeeAccount": "7SnAjVy9YeEoDDHS4U2N2rD9Lcyex3ppaMvCQRUDvPS7", - "mint": "2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj", - "reserve": "BDd5iphdX4nf3ZbTuERZpzqApDyBXDYF4DF51KHihT5n" - }, - "tokenB": { - "adminFeeAccount": "BJsLRUj8osHJEm7NsCUGTrrCeuSbhmQAKLRFivr8M7SK", - "mint": "C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi", - "reserve": "13XGEQDqaKt7texUGawxfTGnz2j6pTt3k9HsosfJ9uZH" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "CjpAJJw6YrmTubmQMhtvC39bcWkPbomfRn1o1hwYjfss" - }, - { - "id": "mim_ust", - "name": "aeMIM-UST", - "tokens": [ - { - "name": "Wrapped MIM (Allbridge from Ethereum)", - "symbol": "aeMIM", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj.png", - "decimals": 9, - "address": "2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj", - "chainId": 101, - "tags": ["saber-mkt-usd"], - "extensions": { - "coingeckoId": "magic-internet-money", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped UST (Wormhole) (9 decimals)", - "address": "UST98bfV6EASdTFQrRwCBczpehdMFwYCUdLT5tEbhpW", - "decimals": 9, - "symbol": "sUST-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/UST98bfV6EASdTFQrRwCBczpehdMFwYCUdLT5tEbhpW.png", - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "website": "https://app.saber.so", - "assetContract": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "underlyingTokens": ["9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped MIM (Allbridge from Ethereum)", - "symbol": "aeMIM", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj.png", - "decimals": 9, - "address": "2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj", - "chainId": 101, - "tags": ["saber-mkt-usd"], - "extensions": { - "coingeckoId": "magic-internet-money", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped UST (Wormhole) (9 decimals)", - "address": "UST98bfV6EASdTFQrRwCBczpehdMFwYCUdLT5tEbhpW", - "decimals": 9, - "symbol": "sUST-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/UST98bfV6EASdTFQrRwCBczpehdMFwYCUdLT5tEbhpW.png", - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "website": "https://app.saber.so", - "assetContract": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "underlyingTokens": ["9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped MIM (Allbridge from Ethereum)", - "symbol": "aeMIM", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj.png", - "decimals": 9, - "address": "2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj", - "chainId": 101, - "tags": ["saber-mkt-usd"], - "extensions": { - "coingeckoId": "magic-internet-money", - "source": "allbridge", - "currency": "USD", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "UST (Wormhole)", - "symbol": "UST", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i.png", - "decimals": 6, - "address": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "chainId": 101, - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "aeMIM-UST", - "name": "Saber aeMIM-UST LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/ALPfb7HJd4oenNBknjzCbVc2RooC5N1H6N391hbZ82ky.png", - "decimals": 9, - "address": "ALPfb7HJd4oenNBknjzCbVc2RooC5N1H6N391hbZ82ky", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"], - "extensions": { - "website": "https://app.saber.so/pools/mim_ust", - "underlyingTokens": [ - "2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj", - "UST98bfV6EASdTFQrRwCBczpehdMFwYCUdLT5tEbhpW" - ], - "source": "saber" - } - }, - "plotKey": "5TW99rm9xEGB4P4ypK8JHqvv4aX9AXBmZqKTVwrLeNoK", - "swap": { - "config": { - "swapAccount": "MiMuMS9C4vBqcrYeeQPph1E7oAW9aNKvW9k6Zw9XffM", - "authority": "4WLCbMH7QQdcYHCNUhH1HV69sXstkmXtAyBoKLUDTjoE", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "ALPfb7HJd4oenNBknjzCbVc2RooC5N1H6N391hbZ82ky", - "adminAccount": "8miP3vq3BuAYBa6i7bKTEzjTRzhhXon9CbfXJv5QsCqH", - "tokenA": { - "adminFeeAccount": "CibroeQ5Y8ezKTb9LKDZ7SnwrjgVEVUTxbQkUgW6rFgZ", - "mint": "2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj", - "reserve": "Afy2q2hh6Y474pshJa5fnQ6PfEchGyTbKrQpCZw2hr3m" - }, - "tokenB": { - "adminFeeAccount": "9DNEgGo4KxrJKb3ocaJxsHooyYmLsJtfoTQ6cuFZhMaA", - "mint": "UST98bfV6EASdTFQrRwCBczpehdMFwYCUdLT5tEbhpW", - "reserve": "5pXz9ksgjeL8Wgb37bksUaBFMLdFfsNNY3FQnikkCPtS" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "kjswzZghGyCPtfdivs3iEr1cVTjJrMjU512TdPnHiCd" - }, - { - "id": "monkedao", - "name": "daoSOL-SOL", - "tokens": [ - { - "name": "daoSOL Token", - "symbol": "daoSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/GEJpt3Wjmr628FqXxTgxMce1pLntcPV4uFi8ksxMyPQh.png", - "decimals": 9, - "address": "GEJpt3Wjmr628FqXxTgxMce1pLntcPV4uFi8ksxMyPQh", - "chainId": 101, - "tags": ["stake-pool-token", "saber-mkt-sol"], - "extensions": { - "website": "https://monkedao.io/", - "twitter": "https://twitter.com/MonkeDAO", - "coingeckoId": "solana", - "description": "daoSOL is the staking token issued by the MonkeDAO staking pool", - "source": "monkedao", - "currency": "SOL", - "sourceUrl": "https://daopool.monkedao.io/" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "tokenIcons": [ - { - "name": "daoSOL Token", - "symbol": "daoSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/GEJpt3Wjmr628FqXxTgxMce1pLntcPV4uFi8ksxMyPQh.png", - "decimals": 9, - "address": "GEJpt3Wjmr628FqXxTgxMce1pLntcPV4uFi8ksxMyPQh", - "chainId": 101, - "tags": ["stake-pool-token", "saber-mkt-sol"], - "extensions": { - "website": "https://monkedao.io/", - "twitter": "https://twitter.com/MonkeDAO", - "coingeckoId": "solana", - "description": "daoSOL is the staking token issued by the MonkeDAO staking pool", - "source": "monkedao", - "currency": "SOL", - "sourceUrl": "https://daopool.monkedao.io/" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "underlyingIcons": [ - { - "name": "daoSOL Token", - "symbol": "daoSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/GEJpt3Wjmr628FqXxTgxMce1pLntcPV4uFi8ksxMyPQh.png", - "decimals": 9, - "address": "GEJpt3Wjmr628FqXxTgxMce1pLntcPV4uFi8ksxMyPQh", - "chainId": 101, - "tags": ["stake-pool-token", "saber-mkt-sol"], - "extensions": { - "website": "https://monkedao.io/", - "twitter": "https://twitter.com/MonkeDAO", - "coingeckoId": "solana", - "description": "daoSOL is the staking token issued by the MonkeDAO staking pool", - "source": "monkedao", - "currency": "SOL", - "sourceUrl": "https://daopool.monkedao.io/" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "currency": "SOL", - "lpToken": { - "symbol": "daoSOL-SOL", - "name": "Saber daoSOL-SOL LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/monKYjV2bHTjbJVWCCcwhxE8C96sdTKR2HUNUHCjh4z.png", - "decimals": 9, - "address": "monKYjV2bHTjbJVWCCcwhxE8C96sdTKR2HUNUHCjh4z", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/monkedao", - "underlyingTokens": [ - "GEJpt3Wjmr628FqXxTgxMce1pLntcPV4uFi8ksxMyPQh", - "So11111111111111111111111111111111111111112" - ], - "source": "saber" - } - }, - "plotKey": "Ac2ARzZ4ypAMqZjNL2bwEsWM5ebuKGDxT3PP198A83DH", - "swap": { - "config": { - "swapAccount": "daob129AwBGn9Y5r91uLoWZeYiGzbPmksauMhFZKTze", - "authority": "41CKnj1gy1AXQ1nf2dB9Ubst3QGHxjWkFLd78KLpGYsr", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "monKYjV2bHTjbJVWCCcwhxE8C96sdTKR2HUNUHCjh4z", - "adminAccount": "9jLXonhzpyFbTT7t73jD8WNjQyiZYyUNqUntv3DB3r8u", - "tokenA": { - "adminFeeAccount": "6dwzNdDgk51HgEWH1Wfe4mikWkZjYiE3AP3JAE16bAQJ", - "mint": "GEJpt3Wjmr628FqXxTgxMce1pLntcPV4uFi8ksxMyPQh", - "reserve": "6VW5GQNyj4LStgmxEHLr5zUfW92vQnmbw8jTnCH7a38F" - }, - "tokenB": { - "adminFeeAccount": "51SdDqP9xXhj9HzcGQenKEPSQymHfebWD1Cy2WakRY1e", - "mint": "So11111111111111111111111111111111111111112", - "reserve": "4VPCCUifPeBA1c7HWK358CHn2nyjm8pdTRk6Ps3KmnMQ" - }, - "initialAmpFactor": "1e", - "targetAmpFactor": "1e", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "6rX9t63n4fWGr5AAJ2hEsuGH47UEee8dthZcJMrmbai2" - }, - { - "id": "msol_jsol", - "name": "mSOL-JSOL", - "tokens": [ - { - "name": "Marinade staked SOL (mSOL)", - "symbol": "mSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So.png", - "decimals": 9, - "address": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://marinade.finance", - "twitter": "https://twitter.com/MarinadeFinance", - "github": "https://github.com/marinade-finance", - "medium": "https://medium.com/marinade-finance", - "discord": "https://discord.gg/mGqZA5pjRN", - "serumV3Usdt": "HxkQdUnrPdHwXP5T9kewEXs3ApgvbufuTfdw9v1nApFd", - "serumV3Usdc": "6oGsL2puUgySccKzn9XA9afqF217LfxP5ocq4B3LWsjy", - "coingeckoId": "msol", - "source": "marinade", - "currency": "SOL", - "sourceUrl": "https://marinade.finance/app/staking" - } - }, - { - "name": "JPOOL Solana Token", - "symbol": "JSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn.svg", - "decimals": 9, - "address": "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn", - "chainId": 101, - "tags": ["stake-pool-token", "utility-token", "saber-mkt-sol"], - "extensions": { - "website": "https://jpool.one/", - "twitter": "https://twitter.com/JPoolSolana", - "discord": "https://discord.gg/qR4BA9QXVR", - "coingeckoId": "solana", - "source": "jpool", - "currency": "SOL", - "sourceUrl": "https://jpool.one/", - "telegram": "https://t.me/jpoolsolana" - } - } - ], - "tokenIcons": [ - { - "name": "Marinade staked SOL (mSOL)", - "symbol": "mSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So.png", - "decimals": 9, - "address": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://marinade.finance", - "twitter": "https://twitter.com/MarinadeFinance", - "github": "https://github.com/marinade-finance", - "medium": "https://medium.com/marinade-finance", - "discord": "https://discord.gg/mGqZA5pjRN", - "serumV3Usdt": "HxkQdUnrPdHwXP5T9kewEXs3ApgvbufuTfdw9v1nApFd", - "serumV3Usdc": "6oGsL2puUgySccKzn9XA9afqF217LfxP5ocq4B3LWsjy", - "coingeckoId": "msol", - "source": "marinade", - "currency": "SOL", - "sourceUrl": "https://marinade.finance/app/staking" - } - }, - { - "name": "JPOOL Solana Token", - "symbol": "JSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn.svg", - "decimals": 9, - "address": "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn", - "chainId": 101, - "tags": ["stake-pool-token", "utility-token", "saber-mkt-sol"], - "extensions": { - "website": "https://jpool.one/", - "twitter": "https://twitter.com/JPoolSolana", - "discord": "https://discord.gg/qR4BA9QXVR", - "coingeckoId": "solana", - "source": "jpool", - "currency": "SOL", - "sourceUrl": "https://jpool.one/", - "telegram": "https://t.me/jpoolsolana" - } - } - ], - "underlyingIcons": [ - { - "name": "Marinade staked SOL (mSOL)", - "symbol": "mSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So.png", - "decimals": 9, - "address": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://marinade.finance", - "twitter": "https://twitter.com/MarinadeFinance", - "github": "https://github.com/marinade-finance", - "medium": "https://medium.com/marinade-finance", - "discord": "https://discord.gg/mGqZA5pjRN", - "serumV3Usdt": "HxkQdUnrPdHwXP5T9kewEXs3ApgvbufuTfdw9v1nApFd", - "serumV3Usdc": "6oGsL2puUgySccKzn9XA9afqF217LfxP5ocq4B3LWsjy", - "coingeckoId": "msol", - "source": "marinade", - "currency": "SOL", - "sourceUrl": "https://marinade.finance/app/staking" - } - }, - { - "name": "JPOOL Solana Token", - "symbol": "JSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn.svg", - "decimals": 9, - "address": "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn", - "chainId": 101, - "tags": ["stake-pool-token", "utility-token", "saber-mkt-sol"], - "extensions": { - "website": "https://jpool.one/", - "twitter": "https://twitter.com/JPoolSolana", - "discord": "https://discord.gg/qR4BA9QXVR", - "coingeckoId": "solana", - "source": "jpool", - "currency": "SOL", - "sourceUrl": "https://jpool.one/", - "telegram": "https://t.me/jpoolsolana" - } - } - ], - "currency": "SOL", - "lpToken": { - "symbol": "mSOL-JSOL", - "name": "Saber mSOL-JSOL LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/SoLWs9Av7ss1jHXqVLDVCBiDaAYuT4o5uRNMMuBFhB9.png", - "decimals": 9, - "address": "SoLWs9Av7ss1jHXqVLDVCBiDaAYuT4o5uRNMMuBFhB9", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/msol_jsol", - "underlyingTokens": [ - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn" - ], - "source": "saber" - } - }, - "plotKey": "GQsqaGP4fAvaNKqguNb2e8ZnjfA7LVzTtFJucMbTEv79", - "swap": { - "config": { - "swapAccount": "SoNcU2iwHMw6dGzsYNQkYFkUjwN1UdAjrWVRnStrZu2", - "authority": "HdyZaku984169KxKtjwyAB2pxPc77tjR1Bqh18DX1hzJ", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "SoLWs9Av7ss1jHXqVLDVCBiDaAYuT4o5uRNMMuBFhB9", - "adminAccount": "EPuzfP28iEqr7EuXH86AxGAK8hRMrXzxVn1MCAzZ2KMh", - "tokenA": { - "adminFeeAccount": "Cq87v8cJhxJki9pzhMDHvnSEysU52u9ioDdokjrnVkDa", - "mint": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "reserve": "8ivTTid27jZnYNc4w3CTA1Z6QS2twsFb8WMwUabeDJgc" - }, - "tokenB": { - "adminFeeAccount": "6x9A5DBHLttZa4CWtqtEY7SLgDJtctfaKX3NYgFtx7vE", - "mint": "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn", - "reserve": "CyXm53PMvHCbeXJBykU46Rcbo28xk5srhMZFg7gv6EYB" - }, - "initialAmpFactor": "19", - "targetAmpFactor": "19", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "22qZzDhBckZxeZ2nojZbPqoZRoTq2NtUwDEv1jZEx2qK" - }, - { - "id": "msol_sol", - "name": "mSOL-SOL", - "tokens": [ - { - "name": "Marinade staked SOL (mSOL)", - "symbol": "mSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So.png", - "decimals": 9, - "address": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://marinade.finance", - "twitter": "https://twitter.com/MarinadeFinance", - "github": "https://github.com/marinade-finance", - "medium": "https://medium.com/marinade-finance", - "discord": "https://discord.gg/mGqZA5pjRN", - "serumV3Usdt": "HxkQdUnrPdHwXP5T9kewEXs3ApgvbufuTfdw9v1nApFd", - "serumV3Usdc": "6oGsL2puUgySccKzn9XA9afqF217LfxP5ocq4B3LWsjy", - "coingeckoId": "msol", - "source": "marinade", - "currency": "SOL", - "sourceUrl": "https://marinade.finance/app/staking" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "tokenIcons": [ - { - "name": "Marinade staked SOL (mSOL)", - "symbol": "mSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So.png", - "decimals": 9, - "address": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://marinade.finance", - "twitter": "https://twitter.com/MarinadeFinance", - "github": "https://github.com/marinade-finance", - "medium": "https://medium.com/marinade-finance", - "discord": "https://discord.gg/mGqZA5pjRN", - "serumV3Usdt": "HxkQdUnrPdHwXP5T9kewEXs3ApgvbufuTfdw9v1nApFd", - "serumV3Usdc": "6oGsL2puUgySccKzn9XA9afqF217LfxP5ocq4B3LWsjy", - "coingeckoId": "msol", - "source": "marinade", - "currency": "SOL", - "sourceUrl": "https://marinade.finance/app/staking" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "underlyingIcons": [ - { - "name": "Marinade staked SOL (mSOL)", - "symbol": "mSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So.png", - "decimals": 9, - "address": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://marinade.finance", - "twitter": "https://twitter.com/MarinadeFinance", - "github": "https://github.com/marinade-finance", - "medium": "https://medium.com/marinade-finance", - "discord": "https://discord.gg/mGqZA5pjRN", - "serumV3Usdt": "HxkQdUnrPdHwXP5T9kewEXs3ApgvbufuTfdw9v1nApFd", - "serumV3Usdc": "6oGsL2puUgySccKzn9XA9afqF217LfxP5ocq4B3LWsjy", - "coingeckoId": "msol", - "source": "marinade", - "currency": "SOL", - "sourceUrl": "https://marinade.finance/app/staking" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "currency": "SOL", - "lpToken": { - "symbol": "mSOL-SOL", - "name": "Saber mSOL-SOL LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/SoLEao8wTzSfqhuou8rcYsVoLjthVmiXuEjzdNPMnCz.png", - "decimals": 9, - "address": "SoLEao8wTzSfqhuou8rcYsVoLjthVmiXuEjzdNPMnCz", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/msol_sol", - "underlyingTokens": [ - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "So11111111111111111111111111111111111111112" - ], - "source": "saber" - } - }, - "plotKey": "3LGuvwvwLJdzsVJ324u4KSEBsJjNV3Xpu7DziXmwfqqu", - "swap": { - "config": { - "swapAccount": "Lee1XZJfJ9Hm2K1qTyeCz1LXNc1YBZaKZszvNY4KCDw", - "authority": "2Sj4MZvmLhud4uRmGHJvDxq612nmF4JJsU1R4ZjNNGMS", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 251, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "SoLEao8wTzSfqhuou8rcYsVoLjthVmiXuEjzdNPMnCz", - "adminAccount": "ApyjTYZ1354YUPnjXM6KKRyrgpjMiYitbYAxFmFNJ28r", - "tokenA": { - "adminFeeAccount": "HzZRDMiJSqS5oxzfu17c35DChnkx58LZtas16Pgmuunn", - "mint": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "reserve": "9DgFSWkPDGijNKcLGbr3p5xoJbHsPgXUTr6QvGBJ5vGN" - }, - "tokenB": { - "adminFeeAccount": "3oebZVvPqba2egfdcbNXa1uS13SfSebxMaNVE82FMk7R", - "mint": "So11111111111111111111111111111111111111112", - "reserve": "2hNHZg7XBhuhHVZ3JDEi4buq2fPQwuWBdQ9xkH7t1GQX" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0010000000", - "numerator": "1", - "denominator": "100000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "7193EeecxsPPv9TMoQATTN8i1eTqEUSNU8aDLuFCQy68" - }, - { - "id": "nirv_usdc", - "name": "NIRV-USDC", - "tokens": [ - { - "name": "NIRV", - "symbol": "NIRV", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa.png", - "decimals": 6, - "address": "NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa", - "chainId": 101, - "tags": ["currency", "saber-mkt-usd"], - "extensions": { - "website": "https://nirvana.finance/", - "twitter": "https://twitter.com/nirvana_fi", - "coingeckoId": "nirvana-nirv", - "source": "nirvana", - "currency": "USD", - "sourceUrl": "https://nirvana.finance" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "tokenIcons": [ - { - "name": "NIRV", - "symbol": "NIRV", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa.png", - "decimals": 6, - "address": "NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa", - "chainId": 101, - "tags": ["currency", "saber-mkt-usd"], - "extensions": { - "website": "https://nirvana.finance/", - "twitter": "https://twitter.com/nirvana_fi", - "coingeckoId": "nirvana-nirv", - "source": "nirvana", - "currency": "USD", - "sourceUrl": "https://nirvana.finance" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "underlyingIcons": [ - { - "name": "NIRV", - "symbol": "NIRV", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa.png", - "decimals": 6, - "address": "NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa", - "chainId": 101, - "tags": ["currency", "saber-mkt-usd"], - "extensions": { - "website": "https://nirvana.finance/", - "twitter": "https://twitter.com/nirvana_fi", - "coingeckoId": "nirvana-nirv", - "source": "nirvana", - "currency": "USD", - "sourceUrl": "https://nirvana.finance" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "NIRV-USDC", - "name": "Saber NIRV-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/NUCe3EWjkyH9MMZZzawaskzMviJHYJcqwXjK6jXaipP.png", - "decimals": 6, - "address": "NUCe3EWjkyH9MMZZzawaskzMviJHYJcqwXjK6jXaipP", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/nirv_usdc", - "underlyingTokens": [ - "NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "source": "saber" - } - }, - "plotKey": "9UvLtha3CCHWp23QjAwUxhtaLxkwf286wiuRfrxQP8kg", - "swap": { - "config": { - "swapAccount": "Cob4usZcpHEY7Qt4ZCwj6WVg9S44zvzYV2v9qYF65dTf", - "authority": "4gQzERgW7HdgfsKKbtbnDcshX75cMHYjEV5Qz2gtafwd", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "NUCe3EWjkyH9MMZZzawaskzMviJHYJcqwXjK6jXaipP", - "adminAccount": "69UavttUJLKmn8huZQLS2WYQeRyd2v9Whk4xD3X7WTif", - "tokenA": { - "adminFeeAccount": "G3W4EjbqbeeccXWKJzZvpcLzVuZLcBFJ7B6ehfxwQ5VU", - "mint": "NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa", - "reserve": "NhFM9UXE48PyNAyeyPYA3iXztqKVJwA4bTdLj4ysM8w" - }, - "tokenB": { - "adminFeeAccount": "FYyWVpGubSiCikigo5JQxDP83fbepGUKkyPxLdpx9HEH", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "reserve": "6TuFuynuBoeskxyR2cz4wxyidk8dpDK7kAWw3UkjQGx" - }, - "initialAmpFactor": "19", - "targetAmpFactor": "19", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "GzoTtZx6LHqrS8Drws8f6vb66UgQb8JRe2rm4Lj9WTtA" - }, - { - "id": "nirv_usdh", - "name": "NIRV-USDH", - "tokens": [ - { - "name": "NIRV", - "symbol": "NIRV", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa.png", - "decimals": 6, - "address": "NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa", - "chainId": 101, - "tags": ["currency", "saber-mkt-usd"], - "extensions": { - "website": "https://nirvana.finance/", - "twitter": "https://twitter.com/nirvana_fi", - "coingeckoId": "nirvana-nirv", - "source": "nirvana", - "currency": "USD", - "sourceUrl": "https://nirvana.finance" - } - }, - { - "name": "USDH Hubble Stablecoin", - "symbol": "USDH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX.svg", - "decimals": 6, - "address": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://hubbleprotocol.io/", - "twitter": "https://twitter.com/hubbleprotocol", - "discord": "https://discord.gg/d44A8WvK", - "coingeckoId": "usdh", - "source": "hubble", - "currency": "USD", - "sourceUrl": "https://app.hubbleprotocol.io/" - } - } - ], - "tokenIcons": [ - { - "name": "NIRV", - "symbol": "NIRV", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa.png", - "decimals": 6, - "address": "NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa", - "chainId": 101, - "tags": ["currency", "saber-mkt-usd"], - "extensions": { - "website": "https://nirvana.finance/", - "twitter": "https://twitter.com/nirvana_fi", - "coingeckoId": "nirvana-nirv", - "source": "nirvana", - "currency": "USD", - "sourceUrl": "https://nirvana.finance" - } - }, - { - "name": "USDH Hubble Stablecoin", - "symbol": "USDH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX.svg", - "decimals": 6, - "address": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://hubbleprotocol.io/", - "twitter": "https://twitter.com/hubbleprotocol", - "discord": "https://discord.gg/d44A8WvK", - "coingeckoId": "usdh", - "source": "hubble", - "currency": "USD", - "sourceUrl": "https://app.hubbleprotocol.io/" - } - } - ], - "underlyingIcons": [ - { - "name": "NIRV", - "symbol": "NIRV", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa.png", - "decimals": 6, - "address": "NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa", - "chainId": 101, - "tags": ["currency", "saber-mkt-usd"], - "extensions": { - "website": "https://nirvana.finance/", - "twitter": "https://twitter.com/nirvana_fi", - "coingeckoId": "nirvana-nirv", - "source": "nirvana", - "currency": "USD", - "sourceUrl": "https://nirvana.finance" - } - }, - { - "name": "USDH Hubble Stablecoin", - "symbol": "USDH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX.svg", - "decimals": 6, - "address": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://hubbleprotocol.io/", - "twitter": "https://twitter.com/hubbleprotocol", - "discord": "https://discord.gg/d44A8WvK", - "coingeckoId": "usdh", - "source": "hubble", - "currency": "USD", - "sourceUrl": "https://app.hubbleprotocol.io/" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "NIRV-USDH", - "name": "Saber NIRV-USDH LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/NUH7NPN5AYWMKXuqPsoyYcpDDWcrej6gbahSunEFK1e.png", - "decimals": 6, - "address": "NUH7NPN5AYWMKXuqPsoyYcpDDWcrej6gbahSunEFK1e", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/nirv_usdh", - "underlyingTokens": [ - "NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa", - "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX" - ], - "source": "saber" - } - }, - "plotKey": "Er5HuwQx3ubznNmqcss9NacH2bGbSBPd3gvkD32Cqfkk", - "swap": { - "config": { - "swapAccount": "SUiuyGR7SFq3xeRVJonq84fjjeFwRSsFekcevJ53tzy", - "authority": "2v9Hoi5bgtAV5ZNEwS6Lbw8RkDgEusH2T1H1sBCCCzpS", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "NUH7NPN5AYWMKXuqPsoyYcpDDWcrej6gbahSunEFK1e", - "adminAccount": "FZ6Xp7W4JyhmyQ9278WWkQthyGtHctXiwUbcHC9NFjJp", - "tokenA": { - "adminFeeAccount": "6cXuamjji2fxCgVcQNvmNKikb1kFYbJFRomN7hU2AD2V", - "mint": "NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa", - "reserve": "49GjCCPsv7fBqo6t3iKDrP1xxGDS8uWZbVCdfnp2gjMf" - }, - "tokenB": { - "adminFeeAccount": "EBTuj3ZUL3MvHnwiszXTzEXfbistoWsB4MZpaoJ2nKaS", - "mint": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "reserve": "CEwj5xEbbJEjYqM8D6Ai8ByGz1mrh8mkAVsE5fzDSSSx" - }, - "initialAmpFactor": "19", - "targetAmpFactor": "19", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "G5AyUriDUFzptFr2ipxfFqUxfQWz6kfdk3Wjkhxp7YKL" - }, - { - "id": "nirv_usdt", - "name": "NIRV-USDT", - "tokens": [ - { - "name": "NIRV", - "symbol": "NIRV", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa.png", - "decimals": 6, - "address": "NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa", - "chainId": 101, - "tags": ["currency", "saber-mkt-usd"], - "extensions": { - "website": "https://nirvana.finance/", - "twitter": "https://twitter.com/nirvana_fi", - "coingeckoId": "nirvana-nirv", - "source": "nirvana", - "currency": "USD", - "sourceUrl": "https://nirvana.finance" - } - }, - { - "name": "USDT", - "symbol": "USDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB.svg", - "decimals": 6, - "address": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://tether.to/", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD" - } - } - ], - "tokenIcons": [ - { - "name": "NIRV", - "symbol": "NIRV", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa.png", - "decimals": 6, - "address": "NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa", - "chainId": 101, - "tags": ["currency", "saber-mkt-usd"], - "extensions": { - "website": "https://nirvana.finance/", - "twitter": "https://twitter.com/nirvana_fi", - "coingeckoId": "nirvana-nirv", - "source": "nirvana", - "currency": "USD", - "sourceUrl": "https://nirvana.finance" - } - }, - { - "name": "USDT", - "symbol": "USDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB.svg", - "decimals": 6, - "address": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://tether.to/", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD" - } - } - ], - "underlyingIcons": [ - { - "name": "NIRV", - "symbol": "NIRV", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa.png", - "decimals": 6, - "address": "NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa", - "chainId": 101, - "tags": ["currency", "saber-mkt-usd"], - "extensions": { - "website": "https://nirvana.finance/", - "twitter": "https://twitter.com/nirvana_fi", - "coingeckoId": "nirvana-nirv", - "source": "nirvana", - "currency": "USD", - "sourceUrl": "https://nirvana.finance" - } - }, - { - "name": "USDT", - "symbol": "USDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB.svg", - "decimals": 6, - "address": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://tether.to/", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "NIRV-USDT", - "name": "Saber NIRV-USDT LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/NUTNJRVFqUC61uiCAKP4GqSMjzF6DsC7ygCmaDRwe7Y.png", - "decimals": 6, - "address": "NUTNJRVFqUC61uiCAKP4GqSMjzF6DsC7ygCmaDRwe7Y", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/nirv_usdt", - "underlyingTokens": [ - "NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa", - "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" - ], - "source": "saber" - } - }, - "plotKey": "iBgBfExNByxCP7B76esNrrgscD3TYpfbmQvpj99seak", - "swap": { - "config": { - "swapAccount": "KEnkcdADoLR5jS2CLLLesy8TtFsyWL37BhXNfDMzWzP", - "authority": "Ds612hXZJgqogMvgbBYksncZFL7ctAWmnKqACarky2ro", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "NUTNJRVFqUC61uiCAKP4GqSMjzF6DsC7ygCmaDRwe7Y", - "adminAccount": "GkRcVsZSiLDqPLZJAXbkJDX23RYyieRC3P7SEAmjy4Am", - "tokenA": { - "adminFeeAccount": "4sexb33owmbcmG8mdQsAM1TrhCjrAeDg42mKUrqTmwmk", - "mint": "NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa", - "reserve": "3qsjFRuw1qeLMPo4DLwaQevenGAGBj9dA3Q6rb8ax2YR" - }, - "tokenB": { - "adminFeeAccount": "D34TcUdFdSWppzByrVBMwvVVEwBoTdVqvfJAadqCKK8A", - "mint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "reserve": "77iEv8zPQAEyCcEbvBRSB6AFcUdfkhiqnAKtPxk76rNN" - }, - "initialAmpFactor": "19", - "targetAmpFactor": "19", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "4Z82JmmzXxz8tQPPJkbns52bWjvud8aWcTS3xAbcijk3" - }, - { - "id": "nirv_ust", - "name": "NIRV-UST", - "tokens": [ - { - "name": "NIRV", - "symbol": "NIRV", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa.png", - "decimals": 6, - "address": "NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa", - "chainId": 101, - "tags": ["currency", "saber-mkt-usd"], - "extensions": { - "website": "https://nirvana.finance/", - "twitter": "https://twitter.com/nirvana_fi", - "coingeckoId": "nirvana-nirv", - "source": "nirvana", - "currency": "USD", - "sourceUrl": "https://nirvana.finance" - } - }, - { - "name": "UST (Wormhole)", - "symbol": "UST", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i.png", - "decimals": 6, - "address": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "chainId": 101, - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "tokenIcons": [ - { - "name": "NIRV", - "symbol": "NIRV", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa.png", - "decimals": 6, - "address": "NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa", - "chainId": 101, - "tags": ["currency", "saber-mkt-usd"], - "extensions": { - "website": "https://nirvana.finance/", - "twitter": "https://twitter.com/nirvana_fi", - "coingeckoId": "nirvana-nirv", - "source": "nirvana", - "currency": "USD", - "sourceUrl": "https://nirvana.finance" - } - }, - { - "name": "UST (Wormhole)", - "symbol": "UST", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i.png", - "decimals": 6, - "address": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "chainId": 101, - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "underlyingIcons": [ - { - "name": "NIRV", - "symbol": "NIRV", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa.png", - "decimals": 6, - "address": "NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa", - "chainId": 101, - "tags": ["currency", "saber-mkt-usd"], - "extensions": { - "website": "https://nirvana.finance/", - "twitter": "https://twitter.com/nirvana_fi", - "coingeckoId": "nirvana-nirv", - "source": "nirvana", - "currency": "USD", - "sourceUrl": "https://nirvana.finance" - } - }, - { - "name": "UST (Wormhole)", - "symbol": "UST", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i.png", - "decimals": 6, - "address": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "chainId": 101, - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "NIRV-UST", - "name": "Saber NIRV-UST LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/NRVAGstoBkjTTuTwJrGv3789B4odyQf7Yj1psfKUkEn.png", - "decimals": 6, - "address": "NRVAGstoBkjTTuTwJrGv3789B4odyQf7Yj1psfKUkEn", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/nirv_ust", - "underlyingTokens": [ - "NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa", - "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i" - ], - "source": "saber" - } - }, - "plotKey": "FnxdDjUte4RpQDtHDBYwGyFmUd1hCS8kdbTv8j7hqBN4", - "swap": { - "config": { - "swapAccount": "Sid7E679i9ABqptiAVhkmQ27YHN8vaYT4fppPwmxFsJ", - "authority": "8GhxgLae6vY63wQ42AMzRs46qJwULTPts72NCJgH6JUT", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "NRVAGstoBkjTTuTwJrGv3789B4odyQf7Yj1psfKUkEn", - "adminAccount": "6XJsoWaKwZ6nR2aR5Yt3GU7etWUWBXoVVvrYWrQtTrtS", - "tokenA": { - "adminFeeAccount": "uoKx14yxomFBRHwAedyBKd7MurvUQf8gi7wZu6fG4hA", - "mint": "NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa", - "reserve": "GP7KB8o1bv527HG8kTzzzf4wJ5aEGHvcMQvVhLziUfmT" - }, - "tokenB": { - "adminFeeAccount": "54VfH6GnmaTcxsz9Q1F3uh6aRUvs4kWCBkNUmrjfXDzX", - "mint": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "reserve": "9gYxhAZ1M9wu5pxr8SBoa5NDm21gi3s9vMHaYTME77sa" - }, - "initialAmpFactor": "0a", - "targetAmpFactor": "0a", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "8W2qWpq5gSzTbviZRkhVPtPUywvQymKgXHXuwL1ngEM6" - }, - { - "id": "pai_cash", - "name": "PAI-CASH", - "tokens": [ - { - "name": "PAI (Parrot USD)", - "symbol": "PAI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS.svg", - "decimals": 6, - "address": "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS", - "chainId": 101, - "tags": ["utility-token", "stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://parrot.fi", - "twitter": "https://twitter.com/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "discord": "https://discord.gg/gopartyparrot", - "coingeckoId": "parrot-usd", - "source": "parrot", - "currency": "USD", - "sourceUrl": "https://parrot.fi/mint/", - "telegram": "https://t.me/gopartyparrot" - } - }, - { - "name": "Cashio Dollar", - "symbol": "CASH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "decimals": 6, - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://cashio.app", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/" - } - } - ], - "tokenIcons": [ - { - "name": "PAI (Parrot USD)", - "symbol": "PAI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS.svg", - "decimals": 6, - "address": "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS", - "chainId": 101, - "tags": ["utility-token", "stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://parrot.fi", - "twitter": "https://twitter.com/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "discord": "https://discord.gg/gopartyparrot", - "coingeckoId": "parrot-usd", - "source": "parrot", - "currency": "USD", - "sourceUrl": "https://parrot.fi/mint/", - "telegram": "https://t.me/gopartyparrot" - } - }, - { - "name": "Cashio Dollar", - "symbol": "CASH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "decimals": 6, - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://cashio.app", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/" - } - } - ], - "underlyingIcons": [ - { - "name": "PAI (Parrot USD)", - "symbol": "PAI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS.svg", - "decimals": 6, - "address": "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS", - "chainId": 101, - "tags": ["utility-token", "stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://parrot.fi", - "twitter": "https://twitter.com/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "discord": "https://discord.gg/gopartyparrot", - "coingeckoId": "parrot-usd", - "source": "parrot", - "currency": "USD", - "sourceUrl": "https://parrot.fi/mint/", - "telegram": "https://t.me/gopartyparrot" - } - }, - { - "name": "Cashio Dollar", - "symbol": "CASH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "decimals": 6, - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://cashio.app", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "PAI-CASH", - "name": "Saber PAI-CASH LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CLP2aB2bCXZEaoQjUNQdn64dCSzCVxKE3Kjgo3PcAYeY.png", - "decimals": 6, - "address": "CLP2aB2bCXZEaoQjUNQdn64dCSzCVxKE3Kjgo3PcAYeY", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-cashio"], - "extensions": { - "website": "https://app.saber.so/pools/pai_cash", - "underlyingTokens": [ - "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS", - "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT" - ], - "source": "saber" - } - }, - "plotKey": "GF7xQ7GdPqcquwY8HJnAuNgAiXx5pn93TR2kSBLqsQPc", - "swap": { - "config": { - "swapAccount": "CSPC23oTm5WqmJpAR8Eo6KyQhwq8YipgHSuDcABgoSv", - "authority": "8J8fqLWEMMSLgGFohRW5QC2Wv7Kkuw4TmHpiH4uqA43f", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": true, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "CLP2aB2bCXZEaoQjUNQdn64dCSzCVxKE3Kjgo3PcAYeY", - "adminAccount": "FHWBxWnmDJKJCKAGPWW625vvi6xvWZR34YzDnD3vVSfr", - "tokenA": { - "adminFeeAccount": "3y3DvKYguQidNubfhGhWsRuYUe5Ltn7Whv7VsU5G9x7S", - "mint": "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS", - "reserve": "F36eiDG64zYoAA9vtTvV4EWcTqYNUku7hzhUyTYcQSin" - }, - "tokenB": { - "adminFeeAccount": "BxEp68dJAAiDZjj6vCX7tDdg44bCWTpFidbyEGuWVnKP", - "mint": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "reserve": "FXJq5PZ8XshMvhcfX2y3khJyWK6S5W7ftLeMgbuFgwDG" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "3id3soDcppeYRVvfN8ZPqaLbnB83wmfmsCJupwJVBwaL" - }, - { - "id": "pbtc", - "name": "pBTC-renBTC", - "tokens": [ - { - "name": "renBTC", - "symbol": "renBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5.png", - "decimals": 8, - "address": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "website": "https://renproject.io/", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint" - } - }, - { - "name": "pBTC (Parrot BTC)", - "symbol": "pBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/DYDWu4hE4MN3aH897xQ3sRTs5EAjJDmQsKLNhbpUiKun.svg", - "decimals": 8, - "address": "DYDWu4hE4MN3aH897xQ3sRTs5EAjJDmQsKLNhbpUiKun", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-btc"], - "extensions": { - "website": "https://parrot.fi", - "twitter": "https://twitter.com/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "discord": "https://discord.gg/gopartyparrot", - "coingeckoId": "ptokens-btc", - "source": "parrot", - "currency": "BTC", - "sourceUrl": "https://parrot.fi/mint/", - "telegram": "https://t.me/gopartyparrot" - } - } - ], - "tokenIcons": [ - { - "name": "pBTC (Parrot BTC)", - "symbol": "pBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/DYDWu4hE4MN3aH897xQ3sRTs5EAjJDmQsKLNhbpUiKun.svg", - "decimals": 8, - "address": "DYDWu4hE4MN3aH897xQ3sRTs5EAjJDmQsKLNhbpUiKun", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-btc"], - "extensions": { - "website": "https://parrot.fi", - "twitter": "https://twitter.com/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "discord": "https://discord.gg/gopartyparrot", - "coingeckoId": "ptokens-btc", - "source": "parrot", - "currency": "BTC", - "sourceUrl": "https://parrot.fi/mint/", - "telegram": "https://t.me/gopartyparrot" - } - }, - { - "name": "renBTC", - "symbol": "renBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5.png", - "decimals": 8, - "address": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "website": "https://renproject.io/", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint" - } - } - ], - "underlyingIcons": [ - { - "name": "pBTC (Parrot BTC)", - "symbol": "pBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/DYDWu4hE4MN3aH897xQ3sRTs5EAjJDmQsKLNhbpUiKun.svg", - "decimals": 8, - "address": "DYDWu4hE4MN3aH897xQ3sRTs5EAjJDmQsKLNhbpUiKun", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-btc"], - "extensions": { - "website": "https://parrot.fi", - "twitter": "https://twitter.com/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "discord": "https://discord.gg/gopartyparrot", - "coingeckoId": "ptokens-btc", - "source": "parrot", - "currency": "BTC", - "sourceUrl": "https://parrot.fi/mint/", - "telegram": "https://t.me/gopartyparrot" - } - }, - { - "name": "renBTC", - "symbol": "renBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5.png", - "decimals": 8, - "address": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "website": "https://renproject.io/", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint" - } - } - ], - "currency": "BTC", - "lpToken": { - "symbol": "pBTC-renBTC", - "name": "Saber pBTC-renBTC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/pBTCmyG7FaZx4uk3Q2pT5jHKWmWDn84npdc7gZXpQ1x.png", - "decimals": 8, - "address": "pBTCmyG7FaZx4uk3Q2pT5jHKWmWDn84npdc7gZXpQ1x", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/pbtc", - "underlyingTokens": [ - "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "DYDWu4hE4MN3aH897xQ3sRTs5EAjJDmQsKLNhbpUiKun" - ], - "source": "saber", - "sourceUrl": "https://bridge.renproject.io/mint" - } - }, - "plotKey": "DTiZh4xkDzcre58Apdsnx4wFPC2ankXmVVRwyNHHsrH", - "swap": { - "config": { - "swapAccount": "AyiATPCAx5HZstcZ1jdH9rENwFb3yd9zEhkgspvDrCs4", - "authority": "2wszCpUdVDFrJcP79wpV3FdBmU38UC1YKuoSUBA5mhWu", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "pBTCmyG7FaZx4uk3Q2pT5jHKWmWDn84npdc7gZXpQ1x", - "adminAccount": "CRfwCxffJNVdA1uXtj19MmWpEJJQW5BhJ5VmPJBDwmtw", - "tokenA": { - "adminFeeAccount": "GT1dBu8tzgKuTTicMjffuHPPx4QkvCaatzdU9T4iCCF1", - "mint": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "reserve": "DvHVapj4g2Y1tJVSw2ubSPkPBsJPb8fW387ZWXwaKmZq" - }, - "tokenB": { - "adminFeeAccount": "8CjejbrxQu2GVFdP1zgCVA6NWGBBANB4ro1aHow14HxA", - "mint": "DYDWu4hE4MN3aH897xQ3sRTs5EAjJDmQsKLNhbpUiKun", - "reserve": "DKjqWWgrtDRPKrnMWtZ4UiJk4sGQVCQgFjSo7BvfngvK" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "8hnBtfEumuBh8Vd19qZ16re6wWgMZypZQoFLum7vx1bf" - }, - { - "id": "port_2pool", - "name": "pUSDT-pUSDC", - "tokens": [ - { - "name": "Port Finance USDT", - "symbol": "pUSDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/3RudPTAkfcq9Q9Jk8SVeCoecCBmdKMj6q5smsWzxqtqZ.svg", - "decimals": 6, - "address": "3RudPTAkfcq9Q9Jk8SVeCoecCBmdKMj6q5smsWzxqtqZ", - "chainId": 101, - "tags": ["port", "lending", "collateral-tokens", "saber-mkt-usd"], - "extensions": { - "website": "https://port.finance", - "coingeckoId": "tether", - "source": "port", - "currency": "USD", - "sourceUrl": "https://mainnet.port.finance/#/markets" - } - }, - { - "name": "Port Finance USDC", - "symbol": "pUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FgSsGV8GByPaMERxeQJPvZRZHf7zCBhrdYtztKorJS58.svg", - "decimals": 6, - "address": "FgSsGV8GByPaMERxeQJPvZRZHf7zCBhrdYtztKorJS58", - "chainId": 101, - "tags": ["port", "lending", "collateral-tokens", "saber-mkt-usd"], - "extensions": { - "website": "https://port.finance", - "coingeckoId": "usd-coin", - "source": "port", - "currency": "USD", - "sourceUrl": "https://mainnet.port.finance/#/markets" - } - } - ], - "tokenIcons": [ - { - "name": "Port Finance USDT", - "symbol": "pUSDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/3RudPTAkfcq9Q9Jk8SVeCoecCBmdKMj6q5smsWzxqtqZ.svg", - "decimals": 6, - "address": "3RudPTAkfcq9Q9Jk8SVeCoecCBmdKMj6q5smsWzxqtqZ", - "chainId": 101, - "tags": ["port", "lending", "collateral-tokens", "saber-mkt-usd"], - "extensions": { - "website": "https://port.finance", - "coingeckoId": "tether", - "source": "port", - "currency": "USD", - "sourceUrl": "https://mainnet.port.finance/#/markets" - } - }, - { - "name": "Port Finance USDC", - "symbol": "pUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FgSsGV8GByPaMERxeQJPvZRZHf7zCBhrdYtztKorJS58.svg", - "decimals": 6, - "address": "FgSsGV8GByPaMERxeQJPvZRZHf7zCBhrdYtztKorJS58", - "chainId": 101, - "tags": ["port", "lending", "collateral-tokens", "saber-mkt-usd"], - "extensions": { - "website": "https://port.finance", - "coingeckoId": "usd-coin", - "source": "port", - "currency": "USD", - "sourceUrl": "https://mainnet.port.finance/#/markets" - } - } - ], - "underlyingIcons": [ - { - "name": "Port Finance USDT", - "symbol": "pUSDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/3RudPTAkfcq9Q9Jk8SVeCoecCBmdKMj6q5smsWzxqtqZ.svg", - "decimals": 6, - "address": "3RudPTAkfcq9Q9Jk8SVeCoecCBmdKMj6q5smsWzxqtqZ", - "chainId": 101, - "tags": ["port", "lending", "collateral-tokens", "saber-mkt-usd"], - "extensions": { - "website": "https://port.finance", - "coingeckoId": "tether", - "source": "port", - "currency": "USD", - "sourceUrl": "https://mainnet.port.finance/#/markets" - } - }, - { - "name": "Port Finance USDC", - "symbol": "pUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FgSsGV8GByPaMERxeQJPvZRZHf7zCBhrdYtztKorJS58.svg", - "decimals": 6, - "address": "FgSsGV8GByPaMERxeQJPvZRZHf7zCBhrdYtztKorJS58", - "chainId": 101, - "tags": ["port", "lending", "collateral-tokens", "saber-mkt-usd"], - "extensions": { - "website": "https://port.finance", - "coingeckoId": "usd-coin", - "source": "port", - "currency": "USD", - "sourceUrl": "https://mainnet.port.finance/#/markets" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "pUSDT-pUSDC", - "name": "Saber pUSDT-pUSDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/PortuzxBGYMQXeNmM9Kc6AtHLBwqSrb6xWwZ4trQ1en.png", - "decimals": 6, - "address": "PortuzxBGYMQXeNmM9Kc6AtHLBwqSrb6xWwZ4trQ1en", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-port"], - "extensions": { - "website": "https://app.saber.so/pools/port_2pool", - "underlyingTokens": [ - "3RudPTAkfcq9Q9Jk8SVeCoecCBmdKMj6q5smsWzxqtqZ", - "FgSsGV8GByPaMERxeQJPvZRZHf7zCBhrdYtztKorJS58" - ], - "source": "saber" - } - }, - "plotKey": "8cHGxmX41wR3QiTtJCLM4Nx4gQuuGq2DUiNDeMv5RCVe", - "swap": { - "config": { - "swapAccount": "LeonQMdt2TUm3PL358Ny1fa7XEFwMrL4VWheT5PNCVW", - "authority": "H9zLktv9iSJz7fMopV4HXKfx4Bi2UDhR7QJ9MjQ6Hej8", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 252, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "PortuzxBGYMQXeNmM9Kc6AtHLBwqSrb6xWwZ4trQ1en", - "adminAccount": "Gz5H44p8aHShJLu4qCJ8g7knfDvsxgEBb948J44Vw7Zc", - "tokenA": { - "adminFeeAccount": "6fXQcVF5jgTtdChX7RpS7U8vhkJps8YPWwd5usN9PYc8", - "mint": "3RudPTAkfcq9Q9Jk8SVeCoecCBmdKMj6q5smsWzxqtqZ", - "reserve": "2tBpLvzYBCs7e4DrRocEnssoJANB8rDh2jt5FbeCAeK1" - }, - "tokenB": { - "adminFeeAccount": "H8y51WqpZ629U8XhB9H81xptHAyeUTLbtCdNZS58RrX4", - "mint": "FgSsGV8GByPaMERxeQJPvZRZHf7zCBhrdYtztKorJS58", - "reserve": "DLkWGoaeXw4oeGPnr2ecJze541HVKFhrhaW4iVSFEwET" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "8fneZQffsCH7QmZBaUE6JUPpaNb5Y5ggbEJ7mq6w3UCu" - }, - { - "id": "prtsol", - "name": "prtSOL-SOL", - "tokens": [ - { - "symbol": "prtSOL", - "name": "prtSOL (Parrot Staked SOL)", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BdZPG9xWrG3uFrx2KrUW1jT4tZ9VKPDWknYihzoPRJS3.svg", - "address": "BdZPG9xWrG3uFrx2KrUW1jT4tZ9VKPDWknYihzoPRJS3", - "decimals": 9, - "extensions": { - "coingeckoId": "solana", - "website": "https://parrot.fi", - "twitter": "https://twitter.com/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "discord": "https://discord.gg/gopartyparrot", - "source": "parrot", - "currency": "SOL", - "sourceUrl": "https://parrot.fi/mint/", - "telegram": "https://t.me/gopartyparrot" - }, - "chainId": 101, - "tags": ["saber-mkt-sol"] - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "tokenIcons": [ - { - "symbol": "prtSOL", - "name": "prtSOL (Parrot Staked SOL)", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BdZPG9xWrG3uFrx2KrUW1jT4tZ9VKPDWknYihzoPRJS3.svg", - "address": "BdZPG9xWrG3uFrx2KrUW1jT4tZ9VKPDWknYihzoPRJS3", - "decimals": 9, - "extensions": { - "coingeckoId": "solana", - "website": "https://parrot.fi", - "twitter": "https://twitter.com/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "discord": "https://discord.gg/gopartyparrot", - "source": "parrot", - "currency": "SOL", - "sourceUrl": "https://parrot.fi/mint/", - "telegram": "https://t.me/gopartyparrot" - }, - "chainId": 101, - "tags": ["saber-mkt-sol"] - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "underlyingIcons": [ - { - "symbol": "prtSOL", - "name": "prtSOL (Parrot Staked SOL)", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BdZPG9xWrG3uFrx2KrUW1jT4tZ9VKPDWknYihzoPRJS3.svg", - "address": "BdZPG9xWrG3uFrx2KrUW1jT4tZ9VKPDWknYihzoPRJS3", - "decimals": 9, - "extensions": { - "coingeckoId": "solana", - "website": "https://parrot.fi", - "twitter": "https://twitter.com/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "discord": "https://discord.gg/gopartyparrot", - "source": "parrot", - "currency": "SOL", - "sourceUrl": "https://parrot.fi/mint/", - "telegram": "https://t.me/gopartyparrot" - }, - "chainId": 101, - "tags": ["saber-mkt-sol"] - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "currency": "SOL", - "lpToken": { - "symbol": "prtSOL-SOL", - "name": "Saber prtSOL-SOL LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/PrsVdKtXDDf6kJQu5Ff6YqmjfE4TZXtBgHM4bjuvRnR.png", - "decimals": 9, - "address": "PrsVdKtXDDf6kJQu5Ff6YqmjfE4TZXtBgHM4bjuvRnR", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/prtsol", - "underlyingTokens": [ - "BdZPG9xWrG3uFrx2KrUW1jT4tZ9VKPDWknYihzoPRJS3", - "So11111111111111111111111111111111111111112" - ], - "source": "saber" - } - }, - "plotKey": "Gp7AahF48oWdoUU4XVb9VK4zuA7p4rYw7qySGtiQV9xQ", - "swap": { - "config": { - "swapAccount": "heyk4SZTeCUV6a65WiVA5bzic3KcxgVf1qxobfeV4tQ", - "authority": "EKwQt98muCQJq4ghRFausCbMvyLhExS5g8CxvAFHike1", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 253, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "PrsVdKtXDDf6kJQu5Ff6YqmjfE4TZXtBgHM4bjuvRnR", - "adminAccount": "DJVX3zF7jj8tSjJQyEsNAte8b2BhF5Pni1sYNJP7Re7a", - "tokenA": { - "adminFeeAccount": "26cyBk9bU1t8aDNNmnDgGDNHgvVbfuPnsXRzPfMyZfAg", - "mint": "BdZPG9xWrG3uFrx2KrUW1jT4tZ9VKPDWknYihzoPRJS3", - "reserve": "9ZDpBKPqMABtGfq66FbVribaArMvtk63xxy91onZAtDt" - }, - "tokenB": { - "adminFeeAccount": "9SfQeZ7QLL7vJEDcqV2jxyFpfgJVgrhzocBCuuLNV3Hq", - "mint": "So11111111111111111111111111111111111111112", - "reserve": "DaTP4s6N7xxSPinbNZ3FB52EpRDRt87QShTuN3VPCW52" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "3LbfNHhqvJ86u1W8TzoRg8TcozXj7HUhGvZC5gMzwzQa" - }, - { - "id": "psol", - "name": "pSOL-prtSOL", - "tokens": [ - { - "name": "pSOL (Parrot SOL)", - "symbol": "pSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9EaLkQrbjmbbuZG9Wdpo8qfNUEjHATJFSycEmw6f1rGX.svg", - "decimals": 9, - "address": "9EaLkQrbjmbbuZG9Wdpo8qfNUEjHATJFSycEmw6f1rGX", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-sol"], - "extensions": { - "website": "https://parrot.fi", - "twitter": "https://twitter.com/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "discord": "https://discord.gg/gopartyparrot", - "coingeckoId": "solana", - "source": "parrot", - "currency": "SOL", - "sourceUrl": "https://parrot.fi/mint/", - "telegram": "https://t.me/gopartyparrot" - } - }, - { - "symbol": "prtSOL", - "name": "prtSOL (Parrot Staked SOL)", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BdZPG9xWrG3uFrx2KrUW1jT4tZ9VKPDWknYihzoPRJS3.svg", - "address": "BdZPG9xWrG3uFrx2KrUW1jT4tZ9VKPDWknYihzoPRJS3", - "decimals": 9, - "extensions": { - "coingeckoId": "solana", - "website": "https://parrot.fi", - "twitter": "https://twitter.com/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "discord": "https://discord.gg/gopartyparrot", - "source": "parrot", - "currency": "SOL", - "sourceUrl": "https://parrot.fi/mint/", - "telegram": "https://t.me/gopartyparrot" - }, - "chainId": 101, - "tags": ["saber-mkt-sol"] - } - ], - "tokenIcons": [ - { - "name": "pSOL (Parrot SOL)", - "symbol": "pSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9EaLkQrbjmbbuZG9Wdpo8qfNUEjHATJFSycEmw6f1rGX.svg", - "decimals": 9, - "address": "9EaLkQrbjmbbuZG9Wdpo8qfNUEjHATJFSycEmw6f1rGX", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-sol"], - "extensions": { - "website": "https://parrot.fi", - "twitter": "https://twitter.com/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "discord": "https://discord.gg/gopartyparrot", - "coingeckoId": "solana", - "source": "parrot", - "currency": "SOL", - "sourceUrl": "https://parrot.fi/mint/", - "telegram": "https://t.me/gopartyparrot" - } - }, - { - "symbol": "prtSOL", - "name": "prtSOL (Parrot Staked SOL)", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BdZPG9xWrG3uFrx2KrUW1jT4tZ9VKPDWknYihzoPRJS3.svg", - "address": "BdZPG9xWrG3uFrx2KrUW1jT4tZ9VKPDWknYihzoPRJS3", - "decimals": 9, - "extensions": { - "coingeckoId": "solana", - "website": "https://parrot.fi", - "twitter": "https://twitter.com/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "discord": "https://discord.gg/gopartyparrot", - "source": "parrot", - "currency": "SOL", - "sourceUrl": "https://parrot.fi/mint/", - "telegram": "https://t.me/gopartyparrot" - }, - "chainId": 101, - "tags": ["saber-mkt-sol"] - } - ], - "underlyingIcons": [ - { - "name": "pSOL (Parrot SOL)", - "symbol": "pSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9EaLkQrbjmbbuZG9Wdpo8qfNUEjHATJFSycEmw6f1rGX.svg", - "decimals": 9, - "address": "9EaLkQrbjmbbuZG9Wdpo8qfNUEjHATJFSycEmw6f1rGX", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-sol"], - "extensions": { - "website": "https://parrot.fi", - "twitter": "https://twitter.com/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "discord": "https://discord.gg/gopartyparrot", - "coingeckoId": "solana", - "source": "parrot", - "currency": "SOL", - "sourceUrl": "https://parrot.fi/mint/", - "telegram": "https://t.me/gopartyparrot" - } - }, - { - "symbol": "prtSOL", - "name": "prtSOL (Parrot Staked SOL)", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BdZPG9xWrG3uFrx2KrUW1jT4tZ9VKPDWknYihzoPRJS3.svg", - "address": "BdZPG9xWrG3uFrx2KrUW1jT4tZ9VKPDWknYihzoPRJS3", - "decimals": 9, - "extensions": { - "coingeckoId": "solana", - "website": "https://parrot.fi", - "twitter": "https://twitter.com/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "discord": "https://discord.gg/gopartyparrot", - "source": "parrot", - "currency": "SOL", - "sourceUrl": "https://parrot.fi/mint/", - "telegram": "https://t.me/gopartyparrot" - }, - "chainId": 101, - "tags": ["saber-mkt-sol"] - } - ], - "currency": "SOL", - "lpToken": { - "symbol": "pSOL-prtSOL", - "name": "Saber pSOL-prtSOL LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/PSopTFPXzTRysj2H6W8oTvYBZmJHtRcVaQaDkckifAy.png", - "decimals": 9, - "address": "PSopTFPXzTRysj2H6W8oTvYBZmJHtRcVaQaDkckifAy", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/psol", - "underlyingTokens": [ - "9EaLkQrbjmbbuZG9Wdpo8qfNUEjHATJFSycEmw6f1rGX", - "BdZPG9xWrG3uFrx2KrUW1jT4tZ9VKPDWknYihzoPRJS3" - ], - "source": "saber" - } - }, - "plotKey": "ABW8Q3Bq71gDRfQPxtU29oMrHq6et8wdnNMWPbc9gnZr", - "swap": { - "config": { - "swapAccount": "parEAJhzYzHW87y9VoZAQ22dzQ2MD2ekEtTReaxbMcz", - "authority": "6rxqyX1fD27oepCCnv2uy9uJWmXHjPTeQ5PaP99JZrKx", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "PSopTFPXzTRysj2H6W8oTvYBZmJHtRcVaQaDkckifAy", - "adminAccount": "9Sd6u4j8eZwpYdEPkSk6mHeUprGhMMx6JGYnTbvXgqqn", - "tokenA": { - "adminFeeAccount": "d9bL6dHqbxsV8QVstmrgqWfNzn62eo2krm1YHfb8mkJ", - "mint": "9EaLkQrbjmbbuZG9Wdpo8qfNUEjHATJFSycEmw6f1rGX", - "reserve": "3oyc6hpjYSJEquK6dSvG72NXyz3pqLZz5D8AC71pwgQb" - }, - "tokenB": { - "adminFeeAccount": "6nJUBLpf7VkZUvaeBdPFeX5pS1a9vyh315uJ5z4VPaTF", - "mint": "BdZPG9xWrG3uFrx2KrUW1jT4tZ9VKPDWknYihzoPRJS3", - "reserve": "Di2vordgFJVZ1aj1aBpvzXtLfZgJsuLLXawGtVFwX6Rz" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "8uEjJsJ5cCbz7m4K9jZEmQB6cL3SM3V2suc6fazkgWan" - }, - { - "id": "scn_jsol", - "name": "scnSOL-JSOL", - "tokens": [ - { - "name": "Socean staked SOL", - "symbol": "scnSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm.png", - "decimals": 9, - "address": "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "chainId": 101, - "tags": ["stake-pool", "saber-mkt-sol"], - "extensions": { - "website": "https://socean.fi/", - "twitter": "https://twitter.com/soceanfinance", - "medium": "https://medium.com/@soceanfinance", - "discord": "https://discord.gg/k8ZcW27bq9", - "serumV3Usdc": "D52sefGCWho2nd5UGxWd7wCftAzeNEMNYZkdEPGEdQTb", - "coingeckoId": "socean-staked-sol", - "source": "socean", - "currency": "SOL", - "sourceUrl": "https://www.socean.fi/app" - } - }, - { - "name": "JPOOL Solana Token", - "symbol": "JSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn.svg", - "decimals": 9, - "address": "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn", - "chainId": 101, - "tags": ["stake-pool-token", "utility-token", "saber-mkt-sol"], - "extensions": { - "website": "https://jpool.one/", - "twitter": "https://twitter.com/JPoolSolana", - "discord": "https://discord.gg/qR4BA9QXVR", - "coingeckoId": "solana", - "source": "jpool", - "currency": "SOL", - "sourceUrl": "https://jpool.one/", - "telegram": "https://t.me/jpoolsolana" - } - } - ], - "tokenIcons": [ - { - "name": "Socean staked SOL", - "symbol": "scnSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm.png", - "decimals": 9, - "address": "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "chainId": 101, - "tags": ["stake-pool", "saber-mkt-sol"], - "extensions": { - "website": "https://socean.fi/", - "twitter": "https://twitter.com/soceanfinance", - "medium": "https://medium.com/@soceanfinance", - "discord": "https://discord.gg/k8ZcW27bq9", - "serumV3Usdc": "D52sefGCWho2nd5UGxWd7wCftAzeNEMNYZkdEPGEdQTb", - "coingeckoId": "socean-staked-sol", - "source": "socean", - "currency": "SOL", - "sourceUrl": "https://www.socean.fi/app" - } - }, - { - "name": "JPOOL Solana Token", - "symbol": "JSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn.svg", - "decimals": 9, - "address": "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn", - "chainId": 101, - "tags": ["stake-pool-token", "utility-token", "saber-mkt-sol"], - "extensions": { - "website": "https://jpool.one/", - "twitter": "https://twitter.com/JPoolSolana", - "discord": "https://discord.gg/qR4BA9QXVR", - "coingeckoId": "solana", - "source": "jpool", - "currency": "SOL", - "sourceUrl": "https://jpool.one/", - "telegram": "https://t.me/jpoolsolana" - } - } - ], - "underlyingIcons": [ - { - "name": "Socean staked SOL", - "symbol": "scnSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm.png", - "decimals": 9, - "address": "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "chainId": 101, - "tags": ["stake-pool", "saber-mkt-sol"], - "extensions": { - "website": "https://socean.fi/", - "twitter": "https://twitter.com/soceanfinance", - "medium": "https://medium.com/@soceanfinance", - "discord": "https://discord.gg/k8ZcW27bq9", - "serumV3Usdc": "D52sefGCWho2nd5UGxWd7wCftAzeNEMNYZkdEPGEdQTb", - "coingeckoId": "socean-staked-sol", - "source": "socean", - "currency": "SOL", - "sourceUrl": "https://www.socean.fi/app" - } - }, - { - "name": "JPOOL Solana Token", - "symbol": "JSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn.svg", - "decimals": 9, - "address": "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn", - "chainId": 101, - "tags": ["stake-pool-token", "utility-token", "saber-mkt-sol"], - "extensions": { - "website": "https://jpool.one/", - "twitter": "https://twitter.com/JPoolSolana", - "discord": "https://discord.gg/qR4BA9QXVR", - "coingeckoId": "solana", - "source": "jpool", - "currency": "SOL", - "sourceUrl": "https://jpool.one/", - "telegram": "https://t.me/jpoolsolana" - } - } - ], - "currency": "SOL", - "lpToken": { - "symbol": "scnSOL-JSOL", - "name": "Saber scnSOL-JSOL LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/SoLaUA1vvCaidtQLYwt4yszBv1LtbYJDjEbwC4bzxca.png", - "decimals": 9, - "address": "SoLaUA1vvCaidtQLYwt4yszBv1LtbYJDjEbwC4bzxca", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/scn_jsol", - "underlyingTokens": [ - "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn" - ], - "source": "saber" - } - }, - "plotKey": "8y5Dd14LDVv4oG3RRzUe32oLLW7qgHN7dWjeCYqVUdnW", - "swap": { - "config": { - "swapAccount": "SoN9GaFpSXfpyR5dth3x7PHPVhvJMpQqqDJfCSmPv1t", - "authority": "F1YPYbRoKaM16GL52MSa2rRuoK66KjAtzSKXcexj7yTC", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 252, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "SoLaUA1vvCaidtQLYwt4yszBv1LtbYJDjEbwC4bzxca", - "adminAccount": "3AdFUq4bb9A6z7S3jQTiknK9CgTZrcTQNdEadMpimXAV", - "tokenA": { - "adminFeeAccount": "5fmcaC3D7EdvhtvCgpg1255iqWCGzyQ66RjkDnHBkFaY", - "mint": "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "reserve": "9kZ9iS68ViMPtoeqtnhAKuF2iqVyfHPdZHoUNdwCELr" - }, - "tokenB": { - "adminFeeAccount": "GHGUr2qVSgcfTfw2549qYyVA6Uve6apJ3JdcRRwBs7aD", - "mint": "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn", - "reserve": "BBhm5fJLjw3HRzjtKB8uMEYjGhY6EDm9co3cqpjrSzB9" - }, - "initialAmpFactor": "19", - "targetAmpFactor": "19", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "4TL78ccjwJawVbRBLuFwXdziVs3pC5v7S4W4cRHzVm45" - }, - { - "id": "scn_msol", - "name": "scnSOL-mSOL", - "tokens": [ - { - "name": "Socean staked SOL", - "symbol": "scnSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm.png", - "decimals": 9, - "address": "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "chainId": 101, - "tags": ["stake-pool", "saber-mkt-sol"], - "extensions": { - "website": "https://socean.fi/", - "twitter": "https://twitter.com/soceanfinance", - "medium": "https://medium.com/@soceanfinance", - "discord": "https://discord.gg/k8ZcW27bq9", - "serumV3Usdc": "D52sefGCWho2nd5UGxWd7wCftAzeNEMNYZkdEPGEdQTb", - "coingeckoId": "socean-staked-sol", - "source": "socean", - "currency": "SOL", - "sourceUrl": "https://www.socean.fi/app" - } - }, - { - "name": "Marinade staked SOL (mSOL)", - "symbol": "mSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So.png", - "decimals": 9, - "address": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://marinade.finance", - "twitter": "https://twitter.com/MarinadeFinance", - "github": "https://github.com/marinade-finance", - "medium": "https://medium.com/marinade-finance", - "discord": "https://discord.gg/mGqZA5pjRN", - "serumV3Usdt": "HxkQdUnrPdHwXP5T9kewEXs3ApgvbufuTfdw9v1nApFd", - "serumV3Usdc": "6oGsL2puUgySccKzn9XA9afqF217LfxP5ocq4B3LWsjy", - "coingeckoId": "msol", - "source": "marinade", - "currency": "SOL", - "sourceUrl": "https://marinade.finance/app/staking" - } - } - ], - "tokenIcons": [ - { - "name": "Socean staked SOL", - "symbol": "scnSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm.png", - "decimals": 9, - "address": "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "chainId": 101, - "tags": ["stake-pool", "saber-mkt-sol"], - "extensions": { - "website": "https://socean.fi/", - "twitter": "https://twitter.com/soceanfinance", - "medium": "https://medium.com/@soceanfinance", - "discord": "https://discord.gg/k8ZcW27bq9", - "serumV3Usdc": "D52sefGCWho2nd5UGxWd7wCftAzeNEMNYZkdEPGEdQTb", - "coingeckoId": "socean-staked-sol", - "source": "socean", - "currency": "SOL", - "sourceUrl": "https://www.socean.fi/app" - } - }, - { - "name": "Marinade staked SOL (mSOL)", - "symbol": "mSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So.png", - "decimals": 9, - "address": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://marinade.finance", - "twitter": "https://twitter.com/MarinadeFinance", - "github": "https://github.com/marinade-finance", - "medium": "https://medium.com/marinade-finance", - "discord": "https://discord.gg/mGqZA5pjRN", - "serumV3Usdt": "HxkQdUnrPdHwXP5T9kewEXs3ApgvbufuTfdw9v1nApFd", - "serumV3Usdc": "6oGsL2puUgySccKzn9XA9afqF217LfxP5ocq4B3LWsjy", - "coingeckoId": "msol", - "source": "marinade", - "currency": "SOL", - "sourceUrl": "https://marinade.finance/app/staking" - } - } - ], - "underlyingIcons": [ - { - "name": "Socean staked SOL", - "symbol": "scnSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm.png", - "decimals": 9, - "address": "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "chainId": 101, - "tags": ["stake-pool", "saber-mkt-sol"], - "extensions": { - "website": "https://socean.fi/", - "twitter": "https://twitter.com/soceanfinance", - "medium": "https://medium.com/@soceanfinance", - "discord": "https://discord.gg/k8ZcW27bq9", - "serumV3Usdc": "D52sefGCWho2nd5UGxWd7wCftAzeNEMNYZkdEPGEdQTb", - "coingeckoId": "socean-staked-sol", - "source": "socean", - "currency": "SOL", - "sourceUrl": "https://www.socean.fi/app" - } - }, - { - "name": "Marinade staked SOL (mSOL)", - "symbol": "mSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So.png", - "decimals": 9, - "address": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://marinade.finance", - "twitter": "https://twitter.com/MarinadeFinance", - "github": "https://github.com/marinade-finance", - "medium": "https://medium.com/marinade-finance", - "discord": "https://discord.gg/mGqZA5pjRN", - "serumV3Usdt": "HxkQdUnrPdHwXP5T9kewEXs3ApgvbufuTfdw9v1nApFd", - "serumV3Usdc": "6oGsL2puUgySccKzn9XA9afqF217LfxP5ocq4B3LWsjy", - "coingeckoId": "msol", - "source": "marinade", - "currency": "SOL", - "sourceUrl": "https://marinade.finance/app/staking" - } - } - ], - "currency": "SOL", - "lpToken": { - "symbol": "scnSOL-mSOL", - "name": "Saber scnSOL-mSOL LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FP9C3p1r19tVyUDLgN98wcu4Rdzsu5hAcqFwY3MzbLpE.png", - "decimals": 9, - "address": "FP9C3p1r19tVyUDLgN98wcu4Rdzsu5hAcqFwY3MzbLpE", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/scn_msol", - "underlyingTokens": [ - "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So" - ], - "source": "saber" - } - }, - "plotKey": "6Fe6JHJNHzK4EEmzPzyaSRuiPwDCtMmXu6Cdw7Td5WeY", - "swap": { - "config": { - "swapAccount": "Dg3mAgpwDfVNnbGWcsxL8sUcSkEbjSJQhKAWNigG44Ju", - "authority": "2ENUpqrjguuLRfovPAjSVZvVz5t31xowzmNBp1wDFKcz", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "FP9C3p1r19tVyUDLgN98wcu4Rdzsu5hAcqFwY3MzbLpE", - "adminAccount": "DG4HvjNx2FaE4QDx5VTXwVXdnffJpg8nDYrknjFVkQkd", - "tokenA": { - "adminFeeAccount": "EzzhPP4AYACdAvjmiPwwkjACzNzJBYVtvoF8ZkrRoVg", - "mint": "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "reserve": "EATxwd8YA2wV93VJcKMmH2Kn2Y9XfJVUB9hHVu3udwEy" - }, - "tokenB": { - "adminFeeAccount": "BXF2ucBNZcHtSuoAcTY3rGV4PLeEijPpkKiHHoL7TZ3J", - "mint": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "reserve": "GiGvrRi7NMHfHKanG2B8xyCEqe8jaafWins8bhrLVEaa" - }, - "initialAmpFactor": "19", - "targetAmpFactor": "19", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "399RMzmnwFpxDgsKLU2fPdnMue84fLpwZntBaqw7SRJz" - }, - { - "id": "socean", - "name": "scnSOL-SOL", - "tokens": [ - { - "name": "Socean staked SOL", - "symbol": "scnSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm.png", - "decimals": 9, - "address": "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "chainId": 101, - "tags": ["stake-pool", "saber-mkt-sol"], - "extensions": { - "website": "https://socean.fi/", - "twitter": "https://twitter.com/soceanfinance", - "medium": "https://medium.com/@soceanfinance", - "discord": "https://discord.gg/k8ZcW27bq9", - "serumV3Usdc": "D52sefGCWho2nd5UGxWd7wCftAzeNEMNYZkdEPGEdQTb", - "coingeckoId": "socean-staked-sol", - "source": "socean", - "currency": "SOL", - "sourceUrl": "https://www.socean.fi/app" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "tokenIcons": [ - { - "name": "Socean staked SOL", - "symbol": "scnSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm.png", - "decimals": 9, - "address": "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "chainId": 101, - "tags": ["stake-pool", "saber-mkt-sol"], - "extensions": { - "website": "https://socean.fi/", - "twitter": "https://twitter.com/soceanfinance", - "medium": "https://medium.com/@soceanfinance", - "discord": "https://discord.gg/k8ZcW27bq9", - "serumV3Usdc": "D52sefGCWho2nd5UGxWd7wCftAzeNEMNYZkdEPGEdQTb", - "coingeckoId": "socean-staked-sol", - "source": "socean", - "currency": "SOL", - "sourceUrl": "https://www.socean.fi/app" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "underlyingIcons": [ - { - "name": "Socean staked SOL", - "symbol": "scnSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm.png", - "decimals": 9, - "address": "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "chainId": 101, - "tags": ["stake-pool", "saber-mkt-sol"], - "extensions": { - "website": "https://socean.fi/", - "twitter": "https://twitter.com/soceanfinance", - "medium": "https://medium.com/@soceanfinance", - "discord": "https://discord.gg/k8ZcW27bq9", - "serumV3Usdc": "D52sefGCWho2nd5UGxWd7wCftAzeNEMNYZkdEPGEdQTb", - "coingeckoId": "socean-staked-sol", - "source": "socean", - "currency": "SOL", - "sourceUrl": "https://www.socean.fi/app" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "currency": "SOL", - "lpToken": { - "symbol": "scnSOL-SOL", - "name": "Saber scnSOL-SOL LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/SoCJs5Qw1D3fjGbTqxxovK15FVnYVrwvTbYcBBrZmWj.png", - "decimals": 9, - "address": "SoCJs5Qw1D3fjGbTqxxovK15FVnYVrwvTbYcBBrZmWj", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/socean", - "underlyingTokens": [ - "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "So11111111111111111111111111111111111111112" - ], - "source": "saber" - } - }, - "plotKey": "aGQEdwDWCj28SppCwBev18XyRqeQ6EHGJ51QYC8HdG3", - "swap": { - "config": { - "swapAccount": "FrnkTEL6yZ5Aycq2TrEgu29dCrwKG4LPUZydfiwqspkc", - "authority": "3roMZdhjqzKF5HaZxF8a3G8bavz8EggQXFMNiPsBnMQz", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 253, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "SoCJs5Qw1D3fjGbTqxxovK15FVnYVrwvTbYcBBrZmWj", - "adminAccount": "D1kZL7xTYGfwV8qB9mheeHjRDi3Z14n9op4mzhNFJhDz", - "tokenA": { - "adminFeeAccount": "9Db5SCJNbf8oMBnb832xix6NicCCjQrZ91j3BwJDBYGW", - "mint": "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "reserve": "DjvZuMZ46fxKBoBpGMPcRcos4xdTtHFxwMh69DpA2ZFY" - }, - "tokenB": { - "adminFeeAccount": "5H71UbsXCZgoskXeBhEF2XpY5Kdj2AYUddMmfvfmNg3h", - "mint": "So11111111111111111111111111111111111111112", - "reserve": "9rvDPJLAng4uVVqnnSoEXgNDFhBZQTny9AoQioYDZbQX" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "75gshB42wbVJtFyF1PUULR6M4fegdqPLasG3HLGtTwRQ" - }, - { - "id": "solend_sol_msol", - "name": "cSOL-cmSOL", - "tokens": [ - { - "name": "Solend SOL", - "symbol": "cSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/5h6ssFpeDeRbzsEHDbTQNH7nVGgsKrZydxdSTnLm6QdV.png", - "decimals": 9, - "address": "5h6ssFpeDeRbzsEHDbTQNH7nVGgsKrZydxdSTnLm6QdV", - "chainId": 101, - "tags": ["solend", "lending", "collateral-tokens", "saber-mkt-sol"], - "extensions": { - "website": "https://solend.fi", - "coingeckoId": "solana", - "source": "solend", - "currency": "SOL", - "sourceUrl": "https://solend.fi/dashboard" - } - }, - { - "name": "Solend mSOL", - "symbol": "cmSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/3JFC4cB56Er45nWVe29Bhnn5GnwQzSmHVf6eUq9ac91h.png", - "decimals": 9, - "address": "3JFC4cB56Er45nWVe29Bhnn5GnwQzSmHVf6eUq9ac91h", - "chainId": 101, - "tags": ["solend", "lending", "collateral-tokens", "saber-mkt-sol"], - "extensions": { - "website": "https://solend.fi", - "coingeckoId": "solana", - "source": "solend", - "currency": "SOL", - "sourceUrl": "https://solend.fi/dashboard" - } - } - ], - "tokenIcons": [ - { - "name": "Solend SOL", - "symbol": "cSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/5h6ssFpeDeRbzsEHDbTQNH7nVGgsKrZydxdSTnLm6QdV.png", - "decimals": 9, - "address": "5h6ssFpeDeRbzsEHDbTQNH7nVGgsKrZydxdSTnLm6QdV", - "chainId": 101, - "tags": ["solend", "lending", "collateral-tokens", "saber-mkt-sol"], - "extensions": { - "website": "https://solend.fi", - "coingeckoId": "solana", - "source": "solend", - "currency": "SOL", - "sourceUrl": "https://solend.fi/dashboard" - } - }, - { - "name": "Solend mSOL", - "symbol": "cmSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/3JFC4cB56Er45nWVe29Bhnn5GnwQzSmHVf6eUq9ac91h.png", - "decimals": 9, - "address": "3JFC4cB56Er45nWVe29Bhnn5GnwQzSmHVf6eUq9ac91h", - "chainId": 101, - "tags": ["solend", "lending", "collateral-tokens", "saber-mkt-sol"], - "extensions": { - "website": "https://solend.fi", - "coingeckoId": "solana", - "source": "solend", - "currency": "SOL", - "sourceUrl": "https://solend.fi/dashboard" - } - } - ], - "underlyingIcons": [ - { - "name": "Solend SOL", - "symbol": "cSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/5h6ssFpeDeRbzsEHDbTQNH7nVGgsKrZydxdSTnLm6QdV.png", - "decimals": 9, - "address": "5h6ssFpeDeRbzsEHDbTQNH7nVGgsKrZydxdSTnLm6QdV", - "chainId": 101, - "tags": ["solend", "lending", "collateral-tokens", "saber-mkt-sol"], - "extensions": { - "website": "https://solend.fi", - "coingeckoId": "solana", - "source": "solend", - "currency": "SOL", - "sourceUrl": "https://solend.fi/dashboard" - } - }, - { - "name": "Solend mSOL", - "symbol": "cmSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/3JFC4cB56Er45nWVe29Bhnn5GnwQzSmHVf6eUq9ac91h.png", - "decimals": 9, - "address": "3JFC4cB56Er45nWVe29Bhnn5GnwQzSmHVf6eUq9ac91h", - "chainId": 101, - "tags": ["solend", "lending", "collateral-tokens", "saber-mkt-sol"], - "extensions": { - "website": "https://solend.fi", - "coingeckoId": "solana", - "source": "solend", - "currency": "SOL", - "sourceUrl": "https://solend.fi/dashboard" - } - } - ], - "currency": "SOL", - "lpToken": { - "symbol": "cSOL-cmSOL", - "name": "Saber cSOL-cmSOL LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/SSoxcNry3qU1wN5Vj6zMJKTSqJPyPLks5KNfCJCmUPa.png", - "decimals": 9, - "address": "SSoxcNry3qU1wN5Vj6zMJKTSqJPyPLks5KNfCJCmUPa", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-solend"], - "extensions": { - "website": "https://app.saber.so/pools/solend_sol_msol", - "underlyingTokens": [ - "5h6ssFpeDeRbzsEHDbTQNH7nVGgsKrZydxdSTnLm6QdV", - "3JFC4cB56Er45nWVe29Bhnn5GnwQzSmHVf6eUq9ac91h" - ], - "source": "saber" - } - }, - "plotKey": "2sstSyXaP9iEGXzvjzapM2FsPJZFrXCorNGtfDTLV8BX", - "swap": { - "config": { - "swapAccount": "Roockn5vpbWxKybZqMy3xaYuSaq1Lhoc7CL3C6bAUXX", - "authority": "5wYPXCAA59FnC8e2ZHszcNJ68HSeqPnHffnBrnagcJe6", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "SSoxcNry3qU1wN5Vj6zMJKTSqJPyPLks5KNfCJCmUPa", - "adminAccount": "5joKg3wtysaUiTRw1k3JshYHEpK2ws1vSdAt17acPwf2", - "tokenA": { - "adminFeeAccount": "8hJHEfc6YJRsngLtRAZAR7uKUgkgnR5YFQvtSVE6aCcJ", - "mint": "5h6ssFpeDeRbzsEHDbTQNH7nVGgsKrZydxdSTnLm6QdV", - "reserve": "DAizXCPHT5ATkKoW9XAGTdrA7Lbj3cNygjD8RQFH8nZJ" - }, - "tokenB": { - "adminFeeAccount": "5SECXwa7A4f7h5gdGDsV2BrkB5dUJJJzGcKp85jmZahb", - "mint": "3JFC4cB56Er45nWVe29Bhnn5GnwQzSmHVf6eUq9ac91h", - "reserve": "Gh4iXm7PAHjAbagz9FfbpLSuuRE8rdKkDcSukp8Dzq9R" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "7Cvc9vEFztaUEY5r27sj8BXUYpNMxRWTLSUwvQi19ug7" - }, - { - "id": "solend_usdc_usdt", - "name": "cUSDC-cUSDT", - "tokens": [ - { - "name": "Solend USDC", - "symbol": "cUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/993dVFL2uXWYeoXuEBFXR4BijeXdTv4s6BzsCjJZuwqk.png", - "decimals": 6, - "address": "993dVFL2uXWYeoXuEBFXR4BijeXdTv4s6BzsCjJZuwqk", - "chainId": 101, - "tags": ["solend", "lending", "collateral-tokens", "saber-mkt-usd"], - "extensions": { - "website": "https://solend.fi", - "coingeckoId": "usd-coin", - "source": "solend", - "currency": "USD", - "sourceUrl": "https://solend.fi/dashboard" - } - }, - { - "name": "Solend USDT", - "symbol": "cUSDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BTsbZDV7aCMRJ3VNy9ygV4Q2UeEo9GpR8D6VvmMZzNr8.png", - "decimals": 6, - "address": "BTsbZDV7aCMRJ3VNy9ygV4Q2UeEo9GpR8D6VvmMZzNr8", - "chainId": 101, - "tags": ["solend", "lending", "collateral-tokens", "saber-mkt-usd"], - "extensions": { - "website": "https://solend.fi", - "coingeckoId": "tether", - "source": "solend", - "currency": "USD", - "sourceUrl": "https://solend.fi/dashboard" - } - } - ], - "tokenIcons": [ - { - "name": "Solend USDC", - "symbol": "cUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/993dVFL2uXWYeoXuEBFXR4BijeXdTv4s6BzsCjJZuwqk.png", - "decimals": 6, - "address": "993dVFL2uXWYeoXuEBFXR4BijeXdTv4s6BzsCjJZuwqk", - "chainId": 101, - "tags": ["solend", "lending", "collateral-tokens", "saber-mkt-usd"], - "extensions": { - "website": "https://solend.fi", - "coingeckoId": "usd-coin", - "source": "solend", - "currency": "USD", - "sourceUrl": "https://solend.fi/dashboard" - } - }, - { - "name": "Solend USDT", - "symbol": "cUSDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BTsbZDV7aCMRJ3VNy9ygV4Q2UeEo9GpR8D6VvmMZzNr8.png", - "decimals": 6, - "address": "BTsbZDV7aCMRJ3VNy9ygV4Q2UeEo9GpR8D6VvmMZzNr8", - "chainId": 101, - "tags": ["solend", "lending", "collateral-tokens", "saber-mkt-usd"], - "extensions": { - "website": "https://solend.fi", - "coingeckoId": "tether", - "source": "solend", - "currency": "USD", - "sourceUrl": "https://solend.fi/dashboard" - } - } - ], - "underlyingIcons": [ - { - "name": "Solend USDC", - "symbol": "cUSDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/993dVFL2uXWYeoXuEBFXR4BijeXdTv4s6BzsCjJZuwqk.png", - "decimals": 6, - "address": "993dVFL2uXWYeoXuEBFXR4BijeXdTv4s6BzsCjJZuwqk", - "chainId": 101, - "tags": ["solend", "lending", "collateral-tokens", "saber-mkt-usd"], - "extensions": { - "website": "https://solend.fi", - "coingeckoId": "usd-coin", - "source": "solend", - "currency": "USD", - "sourceUrl": "https://solend.fi/dashboard" - } - }, - { - "name": "Solend USDT", - "symbol": "cUSDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BTsbZDV7aCMRJ3VNy9ygV4Q2UeEo9GpR8D6VvmMZzNr8.png", - "decimals": 6, - "address": "BTsbZDV7aCMRJ3VNy9ygV4Q2UeEo9GpR8D6VvmMZzNr8", - "chainId": 101, - "tags": ["solend", "lending", "collateral-tokens", "saber-mkt-usd"], - "extensions": { - "website": "https://solend.fi", - "coingeckoId": "tether", - "source": "solend", - "currency": "USD", - "sourceUrl": "https://solend.fi/dashboard" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "cUSDC-cUSDT", - "name": "Saber cUSDC-cUSDT LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/SUSeGZEV69Xy7rQfhDffyTysHgEP3nJUDMxEZJSvJr1.png", - "decimals": 6, - "address": "SUSeGZEV69Xy7rQfhDffyTysHgEP3nJUDMxEZJSvJr1", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-solend"], - "extensions": { - "website": "https://app.saber.so/pools/solend_usdc_usdt", - "underlyingTokens": [ - "993dVFL2uXWYeoXuEBFXR4BijeXdTv4s6BzsCjJZuwqk", - "BTsbZDV7aCMRJ3VNy9ygV4Q2UeEo9GpR8D6VvmMZzNr8" - ], - "source": "saber" - } - }, - "plotKey": "8yYT2m4gGGKQyvFNzMnGiXkyDzCywa4abL9QqLz9ckWA", - "swap": { - "config": { - "swapAccount": "RooZXUCc5RK1onxyVxB5G8CtGES3ptNgVnZLXMe2cws", - "authority": "CKiGW6G7mp7eyFYeby782hro9VkaSL8HGrYBPP95bXho", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "SUSeGZEV69Xy7rQfhDffyTysHgEP3nJUDMxEZJSvJr1", - "adminAccount": "G95sdzNFamfvuK2HDeskhKvBcriCSUXEpy1EF768dePf", - "tokenA": { - "adminFeeAccount": "97c3ygVrAhE4wvg8vXzud7FSryKvPwUypsVN5GF7E8vU", - "mint": "993dVFL2uXWYeoXuEBFXR4BijeXdTv4s6BzsCjJZuwqk", - "reserve": "4XqU6QN4QJKva4fF4eyCnPtJG99pKecuUuCPDax5BEqU" - }, - "tokenB": { - "adminFeeAccount": "5rXtWfRPrELaK9kWK8DGfBt8CeeL6MvWHzfsCvZjef2M", - "mint": "BTsbZDV7aCMRJ3VNy9ygV4Q2UeEo9GpR8D6VvmMZzNr8", - "reserve": "F7k8DuuawVEZ3new4A9ahWVojCkEG8BrLsCwyhRvmEHa" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "ByuGnzyRgj73HKmQnLLC61Qgn6EtteeQ7qx9TPHwDYzN" - }, - { - "id": "sollet_ftt", - "name": "soFTT-FTT", - "tokens": [ - { - "name": "Saber Wrapped Wrapped FTT (Sollet) (8 decimals)", - "address": "FTT8cGNp3rfTC6c44uPTuEFLqmsVDhjd2BhH65v2uppr", - "decimals": 8, - "symbol": "ssoFTT-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FTT8cGNp3rfTC6c44uPTuEFLqmsVDhjd2BhH65v2uppr.png", - "tags": [ - "wrapped-sollet", - "ethereum", - "saber-mkt-ftt", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "assetContract": "AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3", - "serumV3Usdt": "Hr3wzG8mZXNHV7TuL6YqtgfVUesCqMxGYCEyP3otywZE", - "serumV3Usdc": "2Pbh1CvRVku1TgewMfycemghf6sU9EyuFDcNXqvRmSxc", - "coingeckoId": "ftx-token", - "source": "sollet", - "currency": "FTT", - "sourceUrl": "https://www.sollet.io/", - "waterfallbot": "https://bit.ly/FTTwaterfall", - "website": "https://app.saber.so", - "underlyingTokens": ["AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3"] - } - }, - { - "name": "FTX Token (Wormhole)", - "symbol": "FTT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv.png", - "decimals": 8, - "address": "EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-ftt", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "serumV3Usdt": "BoHojHESAv4McZx9gXd1bWTZMq25JYyGz4qL1m5C3nvk", - "serumV3Usdc": "2wteg25ch227n4Rh1CN4WNrDZXBpRBpWJ48mEC2K7f4r", - "coingeckoId": "ftx-token", - "source": "wormhole-v2", - "address": "0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "currency": "FTT", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "tokenIcons": [ - { - "name": "Saber Wrapped Wrapped FTT (Sollet) (8 decimals)", - "address": "FTT8cGNp3rfTC6c44uPTuEFLqmsVDhjd2BhH65v2uppr", - "decimals": 8, - "symbol": "ssoFTT-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FTT8cGNp3rfTC6c44uPTuEFLqmsVDhjd2BhH65v2uppr.png", - "tags": [ - "wrapped-sollet", - "ethereum", - "saber-mkt-ftt", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "assetContract": "AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3", - "serumV3Usdt": "Hr3wzG8mZXNHV7TuL6YqtgfVUesCqMxGYCEyP3otywZE", - "serumV3Usdc": "2Pbh1CvRVku1TgewMfycemghf6sU9EyuFDcNXqvRmSxc", - "coingeckoId": "ftx-token", - "source": "sollet", - "currency": "FTT", - "sourceUrl": "https://www.sollet.io/", - "waterfallbot": "https://bit.ly/FTTwaterfall", - "website": "https://app.saber.so", - "underlyingTokens": ["AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3"] - } - }, - { - "name": "FTX Token (Wormhole)", - "symbol": "FTT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv.png", - "decimals": 8, - "address": "EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-ftt", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "serumV3Usdt": "BoHojHESAv4McZx9gXd1bWTZMq25JYyGz4qL1m5C3nvk", - "serumV3Usdc": "2wteg25ch227n4Rh1CN4WNrDZXBpRBpWJ48mEC2K7f4r", - "coingeckoId": "ftx-token", - "source": "wormhole-v2", - "address": "0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "currency": "FTT", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped FTT (Sollet)", - "symbol": "soFTT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3.png", - "decimals": 6, - "address": "AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3", - "chainId": 101, - "tags": ["wrapped-sollet", "ethereum", "saber-mkt-ftt"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "assetContract": "https://etherscan.io/address/0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "serumV3Usdt": "Hr3wzG8mZXNHV7TuL6YqtgfVUesCqMxGYCEyP3otywZE", - "serumV3Usdc": "2Pbh1CvRVku1TgewMfycemghf6sU9EyuFDcNXqvRmSxc", - "coingeckoId": "ftx-token", - "source": "sollet", - "currency": "FTT", - "sourceUrl": "https://www.sollet.io/", - "waterfallbot": "https://bit.ly/FTTwaterfall" - } - }, - { - "name": "FTX Token (Wormhole)", - "symbol": "FTT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv.png", - "decimals": 8, - "address": "EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-ftt", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "serumV3Usdt": "BoHojHESAv4McZx9gXd1bWTZMq25JYyGz4qL1m5C3nvk", - "serumV3Usdc": "2wteg25ch227n4Rh1CN4WNrDZXBpRBpWJ48mEC2K7f4r", - "coingeckoId": "ftx-token", - "source": "wormhole-v2", - "address": "0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "currency": "FTT", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "currency": "FTT", - "lpToken": { - "symbol": "soFTT-FTT", - "name": "Saber soFTT-FTT LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/WLPmZgnajNcCzYv68gQDsix4NNjTxGTPmKRMtiXMuFg.png", - "decimals": 8, - "address": "WLPmZgnajNcCzYv68gQDsix4NNjTxGTPmKRMtiXMuFg", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"], - "extensions": { - "website": "https://app.saber.so/pools/sollet_ftt", - "underlyingTokens": [ - "FTT8cGNp3rfTC6c44uPTuEFLqmsVDhjd2BhH65v2uppr", - "EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv" - ], - "source": "saber" - } - }, - "plotKey": "FXKgQqFQZcz3X4d3cQ1o7VuJxRAxzhn2Gqxy1DVhYKH5", - "swap": { - "config": { - "swapAccount": "SAMGk1Nd4haC8zQA63DG37pzuEZy8j4q13tSFtCbcRE", - "authority": "8kJzWzrvsZgHCW9Q9JFqamgf58SbjMmTe8mbDotk4ooR", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "WLPmZgnajNcCzYv68gQDsix4NNjTxGTPmKRMtiXMuFg", - "adminAccount": "6eqHBuXjU1ip4bAh69fpK7FSnus6dRoc7ZyLwdGmFHS8", - "tokenA": { - "adminFeeAccount": "XHz8BySeNPKKXhuvHfwEWBysiu5utuMo1aMkkVDmWF5", - "mint": "FTT8cGNp3rfTC6c44uPTuEFLqmsVDhjd2BhH65v2uppr", - "reserve": "9U9TnkHD3jXMAVZtynCVLgDruuqN4pTvLJTmVHCLWS8g" - }, - "tokenB": { - "adminFeeAccount": "BCVqpUsN9MrkfzvsyFoEgLaZoN1BGesXLBoeENCxgp5N", - "mint": "EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv", - "reserve": "C6zoEbvqSknmi96QWq96UBiPCyNW3YSTvKhavR2BfifE" - }, - "initialAmpFactor": "012c", - "targetAmpFactor": "012c", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "3PkM4UVVw3fuLiwfDb6gEsxiN94EcukxafYTJjqcsMyg" - }, - { - "id": "solust", - "name": "solUST-UST", - "tokens": [ - { - "symbol": "solUST", - "name": "solUST", - "address": "JAa3gQySiTi8tH3dpkvgztJWHQC1vGXr5m6SQ9LEM55T", - "decimals": 6, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JAa3gQySiTi8tH3dpkvgztJWHQC1vGXr5m6SQ9LEM55T.svg", - "extensions": { - "website": "https://soluna.money", - "twitter": "https://twitter.com/solunaDAO", - "coingeckoId": "terrausd", - "medium": "https://medium.com/solunadao", - "source": "soluna", - "currency": "USD", - "sourceUrl": "https://soluna.money/#/deposit" - }, - "chainId": 101, - "tags": ["saber-mkt-usd"] - }, - { - "name": "UST (Wormhole)", - "symbol": "UST", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i.png", - "decimals": 6, - "address": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "chainId": 101, - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "tokenIcons": [ - { - "symbol": "solUST", - "name": "solUST", - "address": "JAa3gQySiTi8tH3dpkvgztJWHQC1vGXr5m6SQ9LEM55T", - "decimals": 6, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JAa3gQySiTi8tH3dpkvgztJWHQC1vGXr5m6SQ9LEM55T.svg", - "extensions": { - "website": "https://soluna.money", - "twitter": "https://twitter.com/solunaDAO", - "coingeckoId": "terrausd", - "medium": "https://medium.com/solunadao", - "source": "soluna", - "currency": "USD", - "sourceUrl": "https://soluna.money/#/deposit" - }, - "chainId": 101, - "tags": ["saber-mkt-usd"] - }, - { - "name": "UST (Wormhole)", - "symbol": "UST", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i.png", - "decimals": 6, - "address": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "chainId": 101, - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "underlyingIcons": [ - { - "symbol": "solUST", - "name": "solUST", - "address": "JAa3gQySiTi8tH3dpkvgztJWHQC1vGXr5m6SQ9LEM55T", - "decimals": 6, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JAa3gQySiTi8tH3dpkvgztJWHQC1vGXr5m6SQ9LEM55T.svg", - "extensions": { - "website": "https://soluna.money", - "twitter": "https://twitter.com/solunaDAO", - "coingeckoId": "terrausd", - "medium": "https://medium.com/solunadao", - "source": "soluna", - "currency": "USD", - "sourceUrl": "https://soluna.money/#/deposit" - }, - "chainId": 101, - "tags": ["saber-mkt-usd"] - }, - { - "name": "UST (Wormhole)", - "symbol": "UST", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i.png", - "decimals": 6, - "address": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "chainId": 101, - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "solUST-UST", - "name": "Saber solUST-UST LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/USTKgR66nvdkCc4bUKsirzEnyFoPtRyZzT2xsqB5t7c.png", - "decimals": 6, - "address": "USTKgR66nvdkCc4bUKsirzEnyFoPtRyZzT2xsqB5t7c", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/solust", - "underlyingTokens": [ - "JAa3gQySiTi8tH3dpkvgztJWHQC1vGXr5m6SQ9LEM55T", - "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i" - ], - "source": "saber" - } - }, - "plotKey": "8xgoxX6hW6E1zC6k7HBc9hyAVUHFUTk11MFYcTzVG3r3", - "swap": { - "config": { - "swapAccount": "KysFMBBoavfov2tLpvefWW6tPFt6rAeZWDJVy1mMQae", - "authority": "54tRZ5wqJ9nccXLbEpNkxFBChJY6B2phVFQDq9YiiQtw", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "USTKgR66nvdkCc4bUKsirzEnyFoPtRyZzT2xsqB5t7c", - "adminAccount": "EFJ6QxsKK99r2PvddLfZyK7snu5Jrr4rkhmy3TRpQooq", - "tokenA": { - "adminFeeAccount": "CTVfkfM9fJw2kvSBxPzfieUuZUN6m2GNXqyZ1hAbW3AJ", - "mint": "JAa3gQySiTi8tH3dpkvgztJWHQC1vGXr5m6SQ9LEM55T", - "reserve": "B8ka2V21TH3x64dFV8ETcjuQcwmrciJ2qzy1mJUttRew" - }, - "tokenB": { - "adminFeeAccount": "DYHhVuT3656hv3HFCXgQSkM9yrn3YwqSprGhdDvJYrro", - "mint": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "reserve": "7fSf7EYxBANyxzk2s5pymFgshA91tFYQNKKs5UnLWcYS" - }, - "initialAmpFactor": "03e8", - "targetAmpFactor": "03e8", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "CavJJ3MoNvLAVd1vzGTiQk3F8D9gycvV9teyGGWCG6J9" - }, - { - "id": "solust_usdh", - "name": "solUST-USDH", - "tokens": [ - { - "symbol": "solUST", - "name": "solUST", - "address": "JAa3gQySiTi8tH3dpkvgztJWHQC1vGXr5m6SQ9LEM55T", - "decimals": 6, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JAa3gQySiTi8tH3dpkvgztJWHQC1vGXr5m6SQ9LEM55T.svg", - "extensions": { - "website": "https://soluna.money", - "twitter": "https://twitter.com/solunaDAO", - "coingeckoId": "terrausd", - "medium": "https://medium.com/solunadao", - "source": "soluna", - "currency": "USD", - "sourceUrl": "https://soluna.money/#/deposit" - }, - "chainId": 101, - "tags": ["saber-mkt-usd"] - }, - { - "name": "USDH Hubble Stablecoin", - "symbol": "USDH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX.svg", - "decimals": 6, - "address": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://hubbleprotocol.io/", - "twitter": "https://twitter.com/hubbleprotocol", - "discord": "https://discord.gg/d44A8WvK", - "coingeckoId": "usdh", - "source": "hubble", - "currency": "USD", - "sourceUrl": "https://app.hubbleprotocol.io/" - } - } - ], - "tokenIcons": [ - { - "symbol": "solUST", - "name": "solUST", - "address": "JAa3gQySiTi8tH3dpkvgztJWHQC1vGXr5m6SQ9LEM55T", - "decimals": 6, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JAa3gQySiTi8tH3dpkvgztJWHQC1vGXr5m6SQ9LEM55T.svg", - "extensions": { - "website": "https://soluna.money", - "twitter": "https://twitter.com/solunaDAO", - "coingeckoId": "terrausd", - "medium": "https://medium.com/solunadao", - "source": "soluna", - "currency": "USD", - "sourceUrl": "https://soluna.money/#/deposit" - }, - "chainId": 101, - "tags": ["saber-mkt-usd"] - }, - { - "name": "USDH Hubble Stablecoin", - "symbol": "USDH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX.svg", - "decimals": 6, - "address": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://hubbleprotocol.io/", - "twitter": "https://twitter.com/hubbleprotocol", - "discord": "https://discord.gg/d44A8WvK", - "coingeckoId": "usdh", - "source": "hubble", - "currency": "USD", - "sourceUrl": "https://app.hubbleprotocol.io/" - } - } - ], - "underlyingIcons": [ - { - "symbol": "solUST", - "name": "solUST", - "address": "JAa3gQySiTi8tH3dpkvgztJWHQC1vGXr5m6SQ9LEM55T", - "decimals": 6, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JAa3gQySiTi8tH3dpkvgztJWHQC1vGXr5m6SQ9LEM55T.svg", - "extensions": { - "website": "https://soluna.money", - "twitter": "https://twitter.com/solunaDAO", - "coingeckoId": "terrausd", - "medium": "https://medium.com/solunadao", - "source": "soluna", - "currency": "USD", - "sourceUrl": "https://soluna.money/#/deposit" - }, - "chainId": 101, - "tags": ["saber-mkt-usd"] - }, - { - "name": "USDH Hubble Stablecoin", - "symbol": "USDH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX.svg", - "decimals": 6, - "address": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://hubbleprotocol.io/", - "twitter": "https://twitter.com/hubbleprotocol", - "discord": "https://discord.gg/d44A8WvK", - "coingeckoId": "usdh", - "source": "hubble", - "currency": "USD", - "sourceUrl": "https://app.hubbleprotocol.io/" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "solUST-USDH", - "name": "Saber solUST-USDH LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/USTRHDiTkhjE1oDydHqNkPJNDeBKTTbz9crTmiYc2w9.png", - "decimals": 6, - "address": "USTRHDiTkhjE1oDydHqNkPJNDeBKTTbz9crTmiYc2w9", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/solust_usdh", - "underlyingTokens": [ - "JAa3gQySiTi8tH3dpkvgztJWHQC1vGXr5m6SQ9LEM55T", - "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX" - ], - "source": "saber" - } - }, - "plotKey": "AMjDq5Lggwjeu8kDj4XhCiixaG9Jx6UbSUJttip5g7kB", - "swap": { - "config": { - "swapAccount": "RoBgmK8CvjdHvPrqdDyVw54VwjZv2TqJ493xnqJAQHx", - "authority": "75GiSiZjXh2KosJ3KQw84cTJmFxGZdV2KPyUhQPs4PwP", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 250, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "USTRHDiTkhjE1oDydHqNkPJNDeBKTTbz9crTmiYc2w9", - "adminAccount": "Hpga6gPvXgivAqMTa72uzZVhcHp585SFFodQVqtyfz4F", - "tokenA": { - "adminFeeAccount": "5RQ1xehqqPnkVyL6scVnzPp7f4XwshKtD3GuCLwimivs", - "mint": "JAa3gQySiTi8tH3dpkvgztJWHQC1vGXr5m6SQ9LEM55T", - "reserve": "ExiHJxM7qPAcy27NDHAF6G7vnW7muNHi2sVJpnaNynGQ" - }, - "tokenB": { - "adminFeeAccount": "Hyb9mqkm8SaBUtPTWkFGPM9DTZGfGwdP2fYSFDmVqgvW", - "mint": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "reserve": "6rkPHSqZb7StM4HwS9EuVrmfkV7tRdc7dnsFhyB6cefE" - }, - "initialAmpFactor": "64", - "targetAmpFactor": "64", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0050000000", - "numerator": "5", - "denominator": "100000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "CEZw8iG7fHou9JV8v3ZqG1Ax2LbQaFYYP7aT8Tu55Xft" - }, - { - "id": "srm", - "name": "wSRM_V1-SRM", - "tokens": [ - { - "symbol": "wSRM_V1", - "name": "Serum (Wormhole V1)", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt.png", - "address": "2jXy799YnEcRXneFo2GEAB6SDRsAa767HpWmktRr1DaP", - "decimals": 6, - "extensions": { - "coingeckoId": "serum", - "source": "wormhole-v1", - "currency": "SRM", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "chainId": 101, - "tags": ["saber-mkt-srm", "wormhole-v1"] - }, - { - "name": "Serum", - "symbol": "SRM", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt.png", - "decimals": 6, - "address": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "chainId": 101, - "tags": ["saber-mkt-srm"], - "extensions": { - "website": "https://projectserum.com/", - "serumV3Usdt": "AtNnsY1AyRERWJ8xCskfz38YdvruWVJQUVXgScC1iPb", - "serumV3Usdc": "ByRys5tuUWDgL73G8JBAEfkdFf8JWBzPBDHsBVQ5vbQA", - "coingeckoId": "serum", - "currency": "SRM", - "waterfallbot": "https://bit.ly/SRMwaterfall" - } - } - ], - "tokenIcons": [ - { - "symbol": "wSRM_V1", - "name": "Serum (Wormhole V1)", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt.png", - "address": "2jXy799YnEcRXneFo2GEAB6SDRsAa767HpWmktRr1DaP", - "decimals": 6, - "extensions": { - "coingeckoId": "serum", - "source": "wormhole-v1", - "currency": "SRM", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "chainId": 101, - "tags": ["saber-mkt-srm", "wormhole-v1"] - }, - { - "name": "Serum", - "symbol": "SRM", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt.png", - "decimals": 6, - "address": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "chainId": 101, - "tags": ["saber-mkt-srm"], - "extensions": { - "website": "https://projectserum.com/", - "serumV3Usdt": "AtNnsY1AyRERWJ8xCskfz38YdvruWVJQUVXgScC1iPb", - "serumV3Usdc": "ByRys5tuUWDgL73G8JBAEfkdFf8JWBzPBDHsBVQ5vbQA", - "coingeckoId": "serum", - "currency": "SRM", - "waterfallbot": "https://bit.ly/SRMwaterfall" - } - } - ], - "underlyingIcons": [ - { - "symbol": "wSRM_V1", - "name": "Serum (Wormhole V1)", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt.png", - "address": "2jXy799YnEcRXneFo2GEAB6SDRsAa767HpWmktRr1DaP", - "decimals": 6, - "extensions": { - "coingeckoId": "serum", - "source": "wormhole-v1", - "currency": "SRM", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "chainId": 101, - "tags": ["saber-mkt-srm", "wormhole-v1"] - }, - { - "name": "Serum", - "symbol": "SRM", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt.png", - "decimals": 6, - "address": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "chainId": 101, - "tags": ["saber-mkt-srm"], - "extensions": { - "website": "https://projectserum.com/", - "serumV3Usdt": "AtNnsY1AyRERWJ8xCskfz38YdvruWVJQUVXgScC1iPb", - "serumV3Usdc": "ByRys5tuUWDgL73G8JBAEfkdFf8JWBzPBDHsBVQ5vbQA", - "coingeckoId": "serum", - "currency": "SRM", - "waterfallbot": "https://bit.ly/SRMwaterfall" - } - } - ], - "currency": "SRM", - "lpToken": { - "symbol": "wSRMV1-SRM", - "name": "Saber wSRM_V1-SRM LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/SRMKjSJpBHJ5gSVTrimci49SnXc1LVkBi9TGF9RNYdp.png", - "decimals": 6, - "address": "SRMKjSJpBHJ5gSVTrimci49SnXc1LVkBi9TGF9RNYdp", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"], - "extensions": { - "website": "https://app.saber.so/pools/srm", - "underlyingTokens": [ - "2jXy799YnEcRXneFo2GEAB6SDRsAa767HpWmktRr1DaP", - "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt" - ], - "source": "saber" - } - }, - "plotKey": "2MQ9cdqpb6NmG9ApgpRBJzyDj13eJ4VKBrwSVh44KTSd", - "swap": { - "config": { - "swapAccount": "TSMFNX73aQNb3yqszDKgyR8AVoigfbaD4cfLjjCYXZf", - "authority": "BdvYL4rH3CqJ6eX6d7iC4snNZZvJQXR67T8dHNTUeSmz", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "SRMKjSJpBHJ5gSVTrimci49SnXc1LVkBi9TGF9RNYdp", - "adminAccount": "Jq12qPsaWQPppWisRUQVA9ekT4ELTwsXWzKQHFBSiyC", - "tokenA": { - "adminFeeAccount": "88mcRBksAPnYM74JCiyVKMmEqDKRDFRJ1Ey1wuLBaujT", - "mint": "2jXy799YnEcRXneFo2GEAB6SDRsAa767HpWmktRr1DaP", - "reserve": "C5uYkVHiFduEFq8S3fr4pgUS24oYj1sjZ8WW2cb4j8SU" - }, - "tokenB": { - "adminFeeAccount": "2MaiPeRjPZc9gqG3MzeKp9DUMabbJYfV2b9M7YkV8tue", - "mint": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "reserve": "3F5DPU5ScgHiFzePYUHZovvgh3uqmM5keNvbavx2ERqV" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "2FfGDoqghYeaASLD7WbK16B4BCENGVrzxR6VQ21qZ4Xe" - }, - { - "id": "stsol", - "name": "stSOL-SOL", - "tokens": [ - { - "name": "Lido Staked SOL", - "symbol": "stSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj.png", - "decimals": 9, - "address": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.lido.fi/", - "twitter": "https://twitter.com/LidoFinance", - "serumV3Usdc": "5F7LGsP1LPtaRV7vVKgxwNYX4Vf22xvuzyXjyar7jJqp", - "coingeckoId": "solana", - "source": "lido", - "currency": "SOL", - "sourceUrl": "https://solana.lido.fi/" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "tokenIcons": [ - { - "name": "Lido Staked SOL", - "symbol": "stSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj.png", - "decimals": 9, - "address": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.lido.fi/", - "twitter": "https://twitter.com/LidoFinance", - "serumV3Usdc": "5F7LGsP1LPtaRV7vVKgxwNYX4Vf22xvuzyXjyar7jJqp", - "coingeckoId": "solana", - "source": "lido", - "currency": "SOL", - "sourceUrl": "https://solana.lido.fi/" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "underlyingIcons": [ - { - "name": "Lido Staked SOL", - "symbol": "stSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj.png", - "decimals": 9, - "address": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.lido.fi/", - "twitter": "https://twitter.com/LidoFinance", - "serumV3Usdc": "5F7LGsP1LPtaRV7vVKgxwNYX4Vf22xvuzyXjyar7jJqp", - "coingeckoId": "solana", - "source": "lido", - "currency": "SOL", - "sourceUrl": "https://solana.lido.fi/" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "currency": "SOL", - "lpToken": { - "symbol": "stSOL-SOL", - "name": "Saber stSOL-SOL LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/stSjCmjQ96BiGhTk8gkU22j1739R8YBQVMq7KXWTqUV.png", - "decimals": 9, - "address": "stSjCmjQ96BiGhTk8gkU22j1739R8YBQVMq7KXWTqUV", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/stsol", - "underlyingTokens": [ - "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "So11111111111111111111111111111111111111112" - ], - "source": "saber" - } - }, - "plotKey": "4zPQjwy9qAxfZT7ACyeaLe6uVNR4FUyCphGGveZCsueX", - "swap": { - "config": { - "swapAccount": "Lid8SLUxQ9RmF7XMqUA8c24RitTwzja8VSKngJxRcUa", - "authority": "8eyi347MTDeH5F6eVv2qjPxVnU685FFZLDGcj5QWHZ6y", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 252, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "stSjCmjQ96BiGhTk8gkU22j1739R8YBQVMq7KXWTqUV", - "adminAccount": "9BDboo12wEhsNr673sS9CSXtqdX7eCrykepsMZZeMhiX", - "tokenA": { - "adminFeeAccount": "2AbLYRQa7PV6gG6XgMjaey18RtPh85sXFmMmP4HsDdQK", - "mint": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "reserve": "4PgzyzLtds9bKZ2to9PMnKqJzKEUpjvNUaeN23phegax" - }, - "tokenB": { - "adminFeeAccount": "Cv3YNq8iY1ttMS3iDgwBxd7QxnMC2pwcXUomtR7CTD8W", - "mint": "So11111111111111111111111111111111111111112", - "reserve": "AtymwxoVN9peZo7EXTcDz9jKVc4vRmisJKKrNfe3ewBa" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0010000000", - "numerator": "1", - "denominator": "100000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "2isVhcqVVpsAeZ94d1DGVErCQ7uZQNSJ85xikN8awHeC" - }, - { - "id": "stsol_msol", - "name": "stSOL-mSOL", - "tokens": [ - { - "name": "Lido Staked SOL", - "symbol": "stSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj.png", - "decimals": 9, - "address": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.lido.fi/", - "twitter": "https://twitter.com/LidoFinance", - "serumV3Usdc": "5F7LGsP1LPtaRV7vVKgxwNYX4Vf22xvuzyXjyar7jJqp", - "coingeckoId": "solana", - "source": "lido", - "currency": "SOL", - "sourceUrl": "https://solana.lido.fi/" - } - }, - { - "name": "Marinade staked SOL (mSOL)", - "symbol": "mSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So.png", - "decimals": 9, - "address": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://marinade.finance", - "twitter": "https://twitter.com/MarinadeFinance", - "github": "https://github.com/marinade-finance", - "medium": "https://medium.com/marinade-finance", - "discord": "https://discord.gg/mGqZA5pjRN", - "serumV3Usdt": "HxkQdUnrPdHwXP5T9kewEXs3ApgvbufuTfdw9v1nApFd", - "serumV3Usdc": "6oGsL2puUgySccKzn9XA9afqF217LfxP5ocq4B3LWsjy", - "coingeckoId": "msol", - "source": "marinade", - "currency": "SOL", - "sourceUrl": "https://marinade.finance/app/staking" - } - } - ], - "tokenIcons": [ - { - "name": "Lido Staked SOL", - "symbol": "stSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj.png", - "decimals": 9, - "address": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.lido.fi/", - "twitter": "https://twitter.com/LidoFinance", - "serumV3Usdc": "5F7LGsP1LPtaRV7vVKgxwNYX4Vf22xvuzyXjyar7jJqp", - "coingeckoId": "solana", - "source": "lido", - "currency": "SOL", - "sourceUrl": "https://solana.lido.fi/" - } - }, - { - "name": "Marinade staked SOL (mSOL)", - "symbol": "mSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So.png", - "decimals": 9, - "address": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://marinade.finance", - "twitter": "https://twitter.com/MarinadeFinance", - "github": "https://github.com/marinade-finance", - "medium": "https://medium.com/marinade-finance", - "discord": "https://discord.gg/mGqZA5pjRN", - "serumV3Usdt": "HxkQdUnrPdHwXP5T9kewEXs3ApgvbufuTfdw9v1nApFd", - "serumV3Usdc": "6oGsL2puUgySccKzn9XA9afqF217LfxP5ocq4B3LWsjy", - "coingeckoId": "msol", - "source": "marinade", - "currency": "SOL", - "sourceUrl": "https://marinade.finance/app/staking" - } - } - ], - "underlyingIcons": [ - { - "name": "Lido Staked SOL", - "symbol": "stSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj.png", - "decimals": 9, - "address": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.lido.fi/", - "twitter": "https://twitter.com/LidoFinance", - "serumV3Usdc": "5F7LGsP1LPtaRV7vVKgxwNYX4Vf22xvuzyXjyar7jJqp", - "coingeckoId": "solana", - "source": "lido", - "currency": "SOL", - "sourceUrl": "https://solana.lido.fi/" - } - }, - { - "name": "Marinade staked SOL (mSOL)", - "symbol": "mSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So.png", - "decimals": 9, - "address": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://marinade.finance", - "twitter": "https://twitter.com/MarinadeFinance", - "github": "https://github.com/marinade-finance", - "medium": "https://medium.com/marinade-finance", - "discord": "https://discord.gg/mGqZA5pjRN", - "serumV3Usdt": "HxkQdUnrPdHwXP5T9kewEXs3ApgvbufuTfdw9v1nApFd", - "serumV3Usdc": "6oGsL2puUgySccKzn9XA9afqF217LfxP5ocq4B3LWsjy", - "coingeckoId": "msol", - "source": "marinade", - "currency": "SOL", - "sourceUrl": "https://marinade.finance/app/staking" - } - } - ], - "currency": "SOL", - "lpToken": { - "symbol": "stSOL-mSOL", - "name": "Saber stSOL-mSOL LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/4FKZsej5FonJWj24xhgG13wV4FSMQqTDwABBQaoQNMZF.png", - "decimals": 9, - "address": "4FKZsej5FonJWj24xhgG13wV4FSMQqTDwABBQaoQNMZF", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/stsol_msol", - "underlyingTokens": [ - "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So" - ], - "source": "saber" - } - }, - "plotKey": "4J99hTyVUQsjm8MeJdxJWK31D9QGMr7uMLyMNpsiZ3eG", - "swap": { - "config": { - "swapAccount": "7dwD9TF6uikvHXxPFK9AsSim54yJoujQjY9vU6gNFumk", - "authority": "8bopcrcYNPHHE5f5RtSMjtyecM9vMufuAY4kLDAoFiqc", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "4FKZsej5FonJWj24xhgG13wV4FSMQqTDwABBQaoQNMZF", - "adminAccount": "4Xvjkg3fPAkKHD3zRSGH3u7DfKbQCFxHuYYQ8or2Yc86", - "tokenA": { - "adminFeeAccount": "GfQjypXeKEe7vzR1skMshCZpTswHsj6XHkFGfTyzJPVB", - "mint": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "reserve": "CquVr6atkvwueDYficKjn6SSEWq4F4rH4VSiBbW4GBWU" - }, - "tokenB": { - "adminFeeAccount": "7tGC2mWMjFTzV4EdF2Hr81bSivD3FdTfkboqEsea5yqx", - "mint": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "reserve": "8BCa6ge3b7ho3TfZuM64Vk1hgbrJ3J7EPiAb9uP86CGd" - }, - "initialAmpFactor": "19", - "targetAmpFactor": "19", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "7YsjyUn53KSqi4YGfhukrTLWcM6ex7TDtNvfVYSAet3D" - }, - { - "id": "usdc_pai", - "name": "PAI-USDC", - "tokens": [ - { - "name": "PAI (Parrot USD)", - "symbol": "PAI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS.svg", - "decimals": 6, - "address": "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS", - "chainId": 101, - "tags": ["utility-token", "stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://parrot.fi", - "twitter": "https://twitter.com/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "discord": "https://discord.gg/gopartyparrot", - "coingeckoId": "parrot-usd", - "source": "parrot", - "currency": "USD", - "sourceUrl": "https://parrot.fi/mint/", - "telegram": "https://t.me/gopartyparrot" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "tokenIcons": [ - { - "name": "PAI (Parrot USD)", - "symbol": "PAI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS.svg", - "decimals": 6, - "address": "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS", - "chainId": 101, - "tags": ["utility-token", "stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://parrot.fi", - "twitter": "https://twitter.com/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "discord": "https://discord.gg/gopartyparrot", - "coingeckoId": "parrot-usd", - "source": "parrot", - "currency": "USD", - "sourceUrl": "https://parrot.fi/mint/", - "telegram": "https://t.me/gopartyparrot" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "underlyingIcons": [ - { - "name": "PAI (Parrot USD)", - "symbol": "PAI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS.svg", - "decimals": 6, - "address": "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS", - "chainId": 101, - "tags": ["utility-token", "stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://parrot.fi", - "twitter": "https://twitter.com/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "discord": "https://discord.gg/gopartyparrot", - "coingeckoId": "parrot-usd", - "source": "parrot", - "currency": "USD", - "sourceUrl": "https://parrot.fi/mint/", - "telegram": "https://t.me/gopartyparrot" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "PAI-USDC", - "name": "Saber PAI-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/PaiYwHYxr4SsEWox9YmyBNJmxVG7GdauirbBcYGB7cJ.png", - "decimals": 6, - "address": "PaiYwHYxr4SsEWox9YmyBNJmxVG7GdauirbBcYGB7cJ", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/usdc_pai", - "underlyingTokens": [ - "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "source": "saber" - } - }, - "plotKey": "GcSFMQ352X8EgX9NpXr2aNeHYoou5iUwv6cD1CeiKWNN", - "swap": { - "config": { - "swapAccount": "B2izdXFYb2sNwbWWHmh75T4aQFtfXsUxem9u2p61HGzf", - "authority": "7W9KMACQT6UmjRPEUQKXyVf4NjZ9Ux4PHs1e1P5PxDtA", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "PaiYwHYxr4SsEWox9YmyBNJmxVG7GdauirbBcYGB7cJ", - "adminAccount": "2NGhdqVQJbt8vkKEr7faxjok8p1NEQ9o1p2FQWAuthLS", - "tokenA": { - "adminFeeAccount": "ECA38NDxPqwo5997B34JL7UkC3VZSQMzRGHThetgFDwC", - "mint": "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS", - "reserve": "4DYwgJtxwuJdAjkj5RJSNH4e7U329V5cNp7d3a1nLrZv" - }, - "tokenB": { - "adminFeeAccount": "qRMfgjGkq7ribEdJtWm3FUCpzCkS2Mguh7WXshChttR", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "reserve": "EXNW64GEf1ACC6xY9BtKRiunrs6GoJSXBdxWN2eTPmrF" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0010000000", - "numerator": "1", - "denominator": "100000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000000" - } - } - } - }, - "quarry": "FR245AMbpU6Xcpad7JAVicSJRR36nWWxDw4itr2hNDHa" - }, - { - "id": "usdc_secret", - "name": "USDC-SECRET", - "tokens": [ - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - }, - { - "address": "Ez2zVjw85tZan1ycnJ5PywNNxR6Gm4jbXQtZKyQNu3Lv", - "symbol": "SECRET", - "name": "Secret Stablecoin", - "decimals": 6, - "chainId": 101, - "extensions": { - "coingeckoId": "usd-coin" - }, - "tags": [] - } - ], - "tokenIcons": [ - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - }, - { - "address": "Ez2zVjw85tZan1ycnJ5PywNNxR6Gm4jbXQtZKyQNu3Lv", - "symbol": "SECRET", - "name": "Secret Stablecoin", - "decimals": 6, - "chainId": 101, - "extensions": { - "coingeckoId": "usd-coin" - }, - "tags": [] - } - ], - "underlyingIcons": [ - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - }, - { - "address": "Ez2zVjw85tZan1ycnJ5PywNNxR6Gm4jbXQtZKyQNu3Lv", - "symbol": "SECRET", - "name": "Secret Stablecoin", - "decimals": 6, - "chainId": 101, - "extensions": { - "coingeckoId": "usd-coin" - }, - "tags": [] - } - ], - "currency": "USD", - "lpToken": { - "symbol": "USDC-SECRET", - "name": "Saber USDC-SECRET LP", - "logoURI": "https://registry.saber.so/token-icons/slp.png", - "decimals": 6, - "address": "FUDpBiyRjvh2igGk6xH3UDeBuZC8k6jtJGMLvuh8n7gJ", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/usdc_secret", - "underlyingTokens": [ - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "Ez2zVjw85tZan1ycnJ5PywNNxR6Gm4jbXQtZKyQNu3Lv" - ], - "source": "saber" - } - }, - "plotKey": "9gNtma6iFxboWaqJd6MxzJhvUpgmpySV3CdNbWKgkzRN", - "swap": { - "config": { - "swapAccount": "FLUY35bdRBEtuiBaRNgxvhnZsdnCjSfTjZtKbCpgnJuF", - "authority": "8MZNKEYqBPCy5HdDxKr5hbXVVzxC3poHHfwwJfyg97QE", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "FUDpBiyRjvh2igGk6xH3UDeBuZC8k6jtJGMLvuh8n7gJ", - "adminAccount": "3f3ERfr8rxZWoP1DbiMVUEvT1DMQJcn27SsrHfuaGWfK", - "tokenA": { - "adminFeeAccount": "F6LK9xmbXXXYGp9fEutQ9pwNfCinQLeqq64tBn9orTLU", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "reserve": "FVoNijdQ6k9FA5LPX1RWVe73YJJvz3Q48iYjd85Yz3Ln" - }, - "tokenB": { - "adminFeeAccount": "Hmm8UTCd1BspuLADp6AonNM5StXQmU7XQxRdpzpRfKTt", - "mint": "Ez2zVjw85tZan1ycnJ5PywNNxR6Gm4jbXQtZKyQNu3Lv", - "reserve": "HsorcrEakUPvUfxc4L3DB43YUS7oFeHa2JC1HtmEJVxi" - }, - "initialAmpFactor": "0a", - "targetAmpFactor": "0a", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "BgPiaXp9pd5Lc2oJutPQB3NfiBrwmtPYsxd1CYrJ6i2L" - }, - { - "id": "usdc_usdt", - "name": "USDT-USDC", - "tokens": [ - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - }, - { - "name": "USDT", - "symbol": "USDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB.svg", - "decimals": 6, - "address": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://tether.to/", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD" - } - } - ], - "tokenIcons": [ - { - "name": "USDT", - "symbol": "USDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB.svg", - "decimals": 6, - "address": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://tether.to/", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "underlyingIcons": [ - { - "name": "USDT", - "symbol": "USDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB.svg", - "decimals": 6, - "address": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://tether.to/", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "USDT-USDC", - "name": "Saber USDT-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/2poo1w1DL6yd2WNTCnNTzDqkC6MBXq7axo77P16yrBuf.png", - "decimals": 6, - "address": "2poo1w1DL6yd2WNTCnNTzDqkC6MBXq7axo77P16yrBuf", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/usdc_usdt", - "underlyingTokens": [ - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" - ], - "source": "saber" - } - }, - "plotKey": "EZEBiZieuKrMGyCd72696Vm8HuiimfQGjVrejmp7Abjd", - "swap": { - "config": { - "swapAccount": "YAkoNb6HKmSxQN9L8hiBE5tPJRsniSSMzND1boHmZxe", - "authority": "5C1k9yV7y4CjMnKv8eGYDgWND8P89Pdfj79Trk2qmfGo", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "2poo1w1DL6yd2WNTCnNTzDqkC6MBXq7axo77P16yrBuf", - "adminAccount": "7tpzQQEQFJTi32eo89yFuV4ST41NSC7c6xd9Sny36iXW", - "tokenA": { - "adminFeeAccount": "XZuQG7CQrAA6y6tHM9CLrDjDUWwuUU2SBoV7pLaGDQT", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "reserve": "CfWX7o2TswwbxusJ4hCaPobu2jLCb1hfXuXJQjVq3jQF" - }, - "tokenB": { - "adminFeeAccount": "63aJYYuZddSnCGyE8FNrCVQWnXhjh6CQSRwcDeSMhdVC", - "mint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "reserve": "EnTrdMMpdhugeH6Ban6gYZWXughWxKtVGfCwFn78ZmY3" - }, - "initialAmpFactor": "05dc", - "targetAmpFactor": "1388", - "startRampTimestamp": 1652992259, - "stopRampTimestamp": 1653251456, - "fees": { - "trade": { - "formatted": "0.0010000000", - "numerator": "1", - "denominator": "100000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000000" - }, - "withdraw": { - "formatted": "0.5000000000", - "numerator": "50000", - "denominator": "10000000" - }, - "adminWithdraw": { - "formatted": "50.0000000000", - "numerator": "5000000", - "denominator": "10000000" - } - } - } - }, - "quarry": "Hs1X5YtXwZACueUtS9azZyXFDWVxAMLvm3tttubpK7ph" - }, - { - "id": "usdh", - "name": "USDH-USDC", - "tokens": [ - { - "name": "USDH Hubble Stablecoin", - "symbol": "USDH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX.svg", - "decimals": 6, - "address": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://hubbleprotocol.io/", - "twitter": "https://twitter.com/hubbleprotocol", - "discord": "https://discord.gg/d44A8WvK", - "coingeckoId": "usdh", - "source": "hubble", - "currency": "USD", - "sourceUrl": "https://app.hubbleprotocol.io/" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "tokenIcons": [ - { - "name": "USDH Hubble Stablecoin", - "symbol": "USDH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX.svg", - "decimals": 6, - "address": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://hubbleprotocol.io/", - "twitter": "https://twitter.com/hubbleprotocol", - "discord": "https://discord.gg/d44A8WvK", - "coingeckoId": "usdh", - "source": "hubble", - "currency": "USD", - "sourceUrl": "https://app.hubbleprotocol.io/" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "underlyingIcons": [ - { - "name": "USDH Hubble Stablecoin", - "symbol": "USDH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX.svg", - "decimals": 6, - "address": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://hubbleprotocol.io/", - "twitter": "https://twitter.com/hubbleprotocol", - "discord": "https://discord.gg/d44A8WvK", - "coingeckoId": "usdh", - "source": "hubble", - "currency": "USD", - "sourceUrl": "https://app.hubbleprotocol.io/" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "USDH-USDC", - "name": "Saber USDH-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/HUBBGekfLpdZhZcqjLeecLVz39o1ysDkicZpgMgZgPFS.png", - "decimals": 6, - "address": "HUBBGekfLpdZhZcqjLeecLVz39o1ysDkicZpgMgZgPFS", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/usdh", - "underlyingTokens": [ - "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "source": "saber" - } - }, - "plotKey": "ANheWkAbXdr51fgeywyzrXg3xmERHVNKPZfnCKZ6Mzv1", - "swap": { - "config": { - "swapAccount": "MARpDPs5A7XiyCWPNH8GsMWPLxmwNn9SBmKvPa9LzgA", - "authority": "H66xGa3c5wvg5ZGF7RCwskf52iH42C8u8v8TPwQXwc3m", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "HUBBGekfLpdZhZcqjLeecLVz39o1ysDkicZpgMgZgPFS", - "adminAccount": "9pNMXt8biJLY94RthJooJWvxmQszD5nig6By67yzdV6x", - "tokenA": { - "adminFeeAccount": "EtjTwkeqBHoX9s9PVeDszVSFkmaSY6nsfRtDzoqc3c5U", - "mint": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "reserve": "6YjT74rmcfCpw8LSjPNx5JTmZoYLGrTKnf9arfSgZ4SR" - }, - "tokenB": { - "adminFeeAccount": "9fLmntYbe6E4CP1A23NMSZSpzfWx7HASybaNfAQ8GTXt", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "reserve": "F8GSmi3vA8M8TsybLya1LQ4n1aFHCRbZ6k437PeTdXtg" - }, - "initialAmpFactor": "03e8", - "targetAmpFactor": "03e8", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0010000000", - "numerator": "1", - "denominator": "100000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "H6TWopq51MkjYqtCy8xTRJrzm88esDWoNVpL87Akybwn" - }, - { - "id": "usdh_cash", - "name": "USDH-CASH", - "tokens": [ - { - "name": "USDH Hubble Stablecoin", - "symbol": "USDH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX.svg", - "decimals": 6, - "address": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://hubbleprotocol.io/", - "twitter": "https://twitter.com/hubbleprotocol", - "discord": "https://discord.gg/d44A8WvK", - "coingeckoId": "usdh", - "source": "hubble", - "currency": "USD", - "sourceUrl": "https://app.hubbleprotocol.io/" - } - }, - { - "name": "Cashio Dollar", - "symbol": "CASH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "decimals": 6, - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://cashio.app", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/" - } - } - ], - "tokenIcons": [ - { - "name": "USDH Hubble Stablecoin", - "symbol": "USDH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX.svg", - "decimals": 6, - "address": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://hubbleprotocol.io/", - "twitter": "https://twitter.com/hubbleprotocol", - "discord": "https://discord.gg/d44A8WvK", - "coingeckoId": "usdh", - "source": "hubble", - "currency": "USD", - "sourceUrl": "https://app.hubbleprotocol.io/" - } - }, - { - "name": "Cashio Dollar", - "symbol": "CASH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "decimals": 6, - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://cashio.app", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/" - } - } - ], - "underlyingIcons": [ - { - "name": "USDH Hubble Stablecoin", - "symbol": "USDH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX.svg", - "decimals": 6, - "address": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://hubbleprotocol.io/", - "twitter": "https://twitter.com/hubbleprotocol", - "discord": "https://discord.gg/d44A8WvK", - "coingeckoId": "usdh", - "source": "hubble", - "currency": "USD", - "sourceUrl": "https://app.hubbleprotocol.io/" - } - }, - { - "name": "Cashio Dollar", - "symbol": "CASH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "decimals": 6, - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://cashio.app", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "USDH-CASH", - "name": "Saber USDH-CASH LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/HUBBMrYrYpxkPbBbULdsvSrcoa6Qv526AGuosrhF8V59.png", - "decimals": 6, - "address": "HUBBMrYrYpxkPbBbULdsvSrcoa6Qv526AGuosrhF8V59", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-cashio"], - "extensions": { - "website": "https://app.saber.so/pools/usdh_cash", - "underlyingTokens": [ - "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT" - ], - "source": "saber" - } - }, - "plotKey": "4xoc4uar2ZVuriDFjeg65xUuq5XsiDZ4tDCTTccCWJQk", - "swap": { - "config": { - "swapAccount": "MAR1pJUGGmgS2WhSinrb4ta1F9w5mLhBXpoCX4jrSw7", - "authority": "GkMw7hsfDriGqu1DhYkfeAr41eG4yx74uPaiB2cGcyGh", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": true, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "HUBBMrYrYpxkPbBbULdsvSrcoa6Qv526AGuosrhF8V59", - "adminAccount": "6MHxZQhaf4r4sg5EEQAXf7N3nzg5XKz5jhXkYg8gFmJc", - "tokenA": { - "adminFeeAccount": "F2EqFwoRmdJD7KK8mSn8z5XAqxLYmeDHG2mhNjNFn1tL", - "mint": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "reserve": "9KvCDR1hzYS6ziAR7acAsX7yU2mSBWnhXgdyobma2fNq" - }, - "tokenB": { - "adminFeeAccount": "BXo1XsK1CZNpfEsqsnpw9M2XTddNfxY5RunsZ6BpsQhy", - "mint": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "reserve": "732AKGENciwszwAC876DDfTL5vPN3FTzgy5CB7xmXn8v" - }, - "initialAmpFactor": "03e8", - "targetAmpFactor": "03e8", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "EJTo9MTgthEYZE7BSwsgLC5dDocWhka5VpsqhoGSp598" - }, - { - "id": "usdh_ust", - "name": "USDH-UST", - "tokens": [ - { - "name": "USDH Hubble Stablecoin", - "symbol": "USDH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX.svg", - "decimals": 6, - "address": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://hubbleprotocol.io/", - "twitter": "https://twitter.com/hubbleprotocol", - "discord": "https://discord.gg/d44A8WvK", - "coingeckoId": "usdh", - "source": "hubble", - "currency": "USD", - "sourceUrl": "https://app.hubbleprotocol.io/" - } - }, - { - "name": "UST (Wormhole)", - "symbol": "UST", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i.png", - "decimals": 6, - "address": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "chainId": 101, - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "tokenIcons": [ - { - "name": "USDH Hubble Stablecoin", - "symbol": "USDH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX.svg", - "decimals": 6, - "address": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://hubbleprotocol.io/", - "twitter": "https://twitter.com/hubbleprotocol", - "discord": "https://discord.gg/d44A8WvK", - "coingeckoId": "usdh", - "source": "hubble", - "currency": "USD", - "sourceUrl": "https://app.hubbleprotocol.io/" - } - }, - { - "name": "UST (Wormhole)", - "symbol": "UST", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i.png", - "decimals": 6, - "address": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "chainId": 101, - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "underlyingIcons": [ - { - "name": "USDH Hubble Stablecoin", - "symbol": "USDH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX.svg", - "decimals": 6, - "address": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://hubbleprotocol.io/", - "twitter": "https://twitter.com/hubbleprotocol", - "discord": "https://discord.gg/d44A8WvK", - "coingeckoId": "usdh", - "source": "hubble", - "currency": "USD", - "sourceUrl": "https://app.hubbleprotocol.io/" - } - }, - { - "name": "UST (Wormhole)", - "symbol": "UST", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i.png", - "decimals": 6, - "address": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "chainId": 101, - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "USDH-UST", - "name": "Saber USDH-UST LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/HUTcohdsuStHyqTx6RnCrvbgeMCY1QR8eRprBMFRQaRH.png", - "decimals": 6, - "address": "HUTcohdsuStHyqTx6RnCrvbgeMCY1QR8eRprBMFRQaRH", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/usdh_ust", - "underlyingTokens": [ - "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i" - ], - "source": "saber" - } - }, - "plotKey": "4PaXnqdA1mvzf61GKCXpVbTYJ78eGe5v9xm6ngDKTWGf", - "swap": { - "config": { - "swapAccount": "MAR3XM1n9xWPQ3HJjAcC85o8DopWFP5p2WxGTaZ3fPB", - "authority": "ESoBYoCq7ej9wD6spKfSnoMoXCu7ijja3GUg7ydk95Wy", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 251, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "HUTcohdsuStHyqTx6RnCrvbgeMCY1QR8eRprBMFRQaRH", - "adminAccount": "AHzjZuadHeUn5ABtDi3kcktkuijxGMEoUeFB7PC39d3N", - "tokenA": { - "adminFeeAccount": "79V5Azs1Rp3iqJCFTJ4Dp8X5sc8ZnJNmGYBLSUhMAkXD", - "mint": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "reserve": "6qG7GUhER8Cg9gDEgnebph9LdS6eu2eoWcA4R7z9uizK" - }, - "tokenB": { - "adminFeeAccount": "2vb4XMHSB7UgPc7eP9S4XM2wgSCf2xyakTn81Fzh2PMv", - "mint": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "reserve": "4QV4CwRXVMY227KkFF9voNAfwWHVvVajXSXDKbUHkWZR" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "5sjeN4FjzoenuhTwRuij7LdWaQemRyYaAMMaXazanVs9" - }, - { - "id": "usdk", - "name": "wUSDK_V1-USDC", - "tokens": [ - { - "symbol": "wUSDK_V1", - "name": "USDK (Wormhole V1)", - "logoURI": "https://registry.saber.so/token-icons/usdk.png", - "address": "2kycGCD8tJbrjJJqWN2Qz5ysN9iB4Bth3Uic4mSB7uak", - "decimals": 9, - "extensions": { - "coingeckoId": "usdk", - "source": "wormhole-v1", - "currency": "USD", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "chainId": 101, - "tags": ["saber-mkt-usd", "wormhole-v1"] - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "symbol": "wUSDK_V1", - "name": "USDK (Wormhole V1)", - "logoURI": "https://registry.saber.so/token-icons/usdk.png", - "address": "2kycGCD8tJbrjJJqWN2Qz5ysN9iB4Bth3Uic4mSB7uak", - "decimals": 9, - "extensions": { - "coingeckoId": "usdk", - "source": "wormhole-v1", - "currency": "USD", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "chainId": 101, - "tags": ["saber-mkt-usd", "wormhole-v1"] - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "symbol": "wUSDK_V1", - "name": "USDK (Wormhole V1)", - "logoURI": "https://registry.saber.so/token-icons/usdk.png", - "address": "2kycGCD8tJbrjJJqWN2Qz5ysN9iB4Bth3Uic4mSB7uak", - "decimals": 9, - "extensions": { - "coingeckoId": "usdk", - "source": "wormhole-v1", - "currency": "USD", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "chainId": 101, - "tags": ["saber-mkt-usd", "wormhole-v1"] - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "wUSDKV1-USDC", - "name": "Saber wUSDK_V1-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/uSdKg2Cs5bCtFSeNXs7aRVNzZJauX58eCkdsfssxTdW.png", - "decimals": 9, - "address": "uSdKg2Cs5bCtFSeNXs7aRVNzZJauX58eCkdsfssxTdW", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"], - "extensions": { - "website": "https://app.saber.so/pools/usdk", - "underlyingTokens": [ - "2kycGCD8tJbrjJJqWN2Qz5ysN9iB4Bth3Uic4mSB7uak", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "source": "saber" - } - }, - "plotKey": "Gske6XTLwhsJbZgPLcjMWRZfQoHXoidJYHUYU7p8m3Bb", - "swap": { - "config": { - "swapAccount": "okgoAkj7GvBT1Q54j6Qvm6AZPritriGTjcEpkPhdWqf", - "authority": "5iGwpfXgTX2zqQuagzwLtMWEg1e8Rju7tkjYUbbHXvgj", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "uSdKg2Cs5bCtFSeNXs7aRVNzZJauX58eCkdsfssxTdW", - "adminAccount": "13gDSjF5jwfkAvQ3pQ3YNZTvo79NWVXcCmLXJWk7cL6F", - "tokenA": { - "adminFeeAccount": "4Yc7KHvZx58i6gnbSbStvufKKuEVHmrGeMGNdCQ5R1H8", - "mint": "2kycGCD8tJbrjJJqWN2Qz5ysN9iB4Bth3Uic4mSB7uak", - "reserve": "5RfXYWvxR9PUaedokXVxgJHDoD4xnLLauVtdJ27shPWG" - }, - "tokenB": { - "adminFeeAccount": "En5CJmgeXCAmSrxUY3wMzVYcq4EwQLkzN47t1nzVZ7m9", - "mint": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "reserve": "DJcFPaQjyW9Xkt7sXCbnEGj1yfykGYuLRUXFyS4LLZ5F" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "AfvTQGrJw4Wk71Lvv1uXtWbb8MF9igxtSe6yVAaXgDf7", - "newPoolID": "wusdk" - }, - { - "id": "ush", - "name": "USH-USDC", - "tokens": [ - { - "name": "Hedge USD", - "symbol": "USH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9iLH8T7zoWhY7sBmj1WK9ENbWdS1nL8n9wAxaeRitTa6.png", - "decimals": 9, - "address": "9iLH8T7zoWhY7sBmj1WK9ENbWdS1nL8n9wAxaeRitTa6", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.hedge.so/", - "twitter": "https://twitter.com/HedgeLabs", - "discord": "https://discord.gg/hedge", - "serumV3Usdc": "6aRwQtvTcHeRTtGxQRhqViwMF1XPEn271CgGEx3YAyEY", - "coingeckoId": "usd-coin", - "source": "hedge", - "currency": "USD", - "sourceUrl": "https://hedge.so" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "Hedge USD", - "symbol": "USH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9iLH8T7zoWhY7sBmj1WK9ENbWdS1nL8n9wAxaeRitTa6.png", - "decimals": 9, - "address": "9iLH8T7zoWhY7sBmj1WK9ENbWdS1nL8n9wAxaeRitTa6", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.hedge.so/", - "twitter": "https://twitter.com/HedgeLabs", - "discord": "https://discord.gg/hedge", - "serumV3Usdc": "6aRwQtvTcHeRTtGxQRhqViwMF1XPEn271CgGEx3YAyEY", - "coingeckoId": "usd-coin", - "source": "hedge", - "currency": "USD", - "sourceUrl": "https://hedge.so" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "Hedge USD", - "symbol": "USH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9iLH8T7zoWhY7sBmj1WK9ENbWdS1nL8n9wAxaeRitTa6.png", - "decimals": 9, - "address": "9iLH8T7zoWhY7sBmj1WK9ENbWdS1nL8n9wAxaeRitTa6", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.hedge.so/", - "twitter": "https://twitter.com/HedgeLabs", - "discord": "https://discord.gg/hedge", - "serumV3Usdc": "6aRwQtvTcHeRTtGxQRhqViwMF1XPEn271CgGEx3YAyEY", - "coingeckoId": "usd-coin", - "source": "hedge", - "currency": "USD", - "sourceUrl": "https://hedge.so" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "USH-USDC", - "name": "Saber USH-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/USHETMBXzMCpwLabQQe713npSbupyQrsyb2kBw6PRJi.png", - "decimals": 9, - "address": "USHETMBXzMCpwLabQQe713npSbupyQrsyb2kBw6PRJi", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/ush", - "underlyingTokens": [ - "9iLH8T7zoWhY7sBmj1WK9ENbWdS1nL8n9wAxaeRitTa6", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "source": "saber" - } - }, - "plotKey": "B8wwbsdwvwFANhEzpCijKjS3cyZZEtCegS8ZdU6CyiMY", - "swap": { - "config": { - "swapAccount": "HEDSDjj84KS7LKhZY7ejkCACTdPen62rKhCby1wXtgxc", - "authority": "AF1NU49p3KBhem97xZ2SGocQt5Nqqv949Brr2KhqoTXh", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 252, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "USHETMBXzMCpwLabQQe713npSbupyQrsyb2kBw6PRJi", - "adminAccount": "B5VQPdHQT148Tc4Q3wWWrpiSobaDnYYfgh1A7SGtda5v", - "tokenA": { - "adminFeeAccount": "EU7m6z3nGQmxqPhcjAxp5Jq12NuW8hKFRbeU89VhaeGN", - "mint": "9iLH8T7zoWhY7sBmj1WK9ENbWdS1nL8n9wAxaeRitTa6", - "reserve": "EnnjMSFttpCTywBrYNt1J5QQeoSVkvzPipJDa8Y7kJow" - }, - "tokenB": { - "adminFeeAccount": "CvSQWoxVSNCNeWrGFpYZCaSBbSQJsE38vohfxn4XccL3", - "mint": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "reserve": "6bjVT6JN2rSvpyn9PdfLYC8wJn4LWh49jpY47fnLDXZk" - }, - "initialAmpFactor": "64", - "targetAmpFactor": "64", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "6SUsK6XFMK3E1f7a1P8JGwUrxXNDiEL1wTM15ozghVJ1" - }, - { - "id": "usn", - "name": "USN-USDC", - "tokens": [ - { - "name": "USN (Allbridge from Near)", - "symbol": "USN", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/PUhuAtMHsKavMTwZsLaDeKy2jb7ciETHJP7rhbKLJGY.png", - "decimals": 9, - "address": "PUhuAtMHsKavMTwZsLaDeKy2jb7ciETHJP7rhbKLJGY", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "usd-coin", - "currency": "USD" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "USN (Allbridge from Near)", - "symbol": "USN", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/PUhuAtMHsKavMTwZsLaDeKy2jb7ciETHJP7rhbKLJGY.png", - "decimals": 9, - "address": "PUhuAtMHsKavMTwZsLaDeKy2jb7ciETHJP7rhbKLJGY", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "usd-coin", - "currency": "USD" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "USN (Allbridge from Near)", - "symbol": "USN", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/PUhuAtMHsKavMTwZsLaDeKy2jb7ciETHJP7rhbKLJGY.png", - "decimals": 9, - "address": "PUhuAtMHsKavMTwZsLaDeKy2jb7ciETHJP7rhbKLJGY", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "coingeckoId": "usd-coin", - "currency": "USD" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "USN-USDC", - "name": "Saber USN-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/NERQa8KLAt2DRAXzo3D2WbKVRkbGENr61gJmHg3Gxot.png", - "decimals": 9, - "address": "NERQa8KLAt2DRAXzo3D2WbKVRkbGENr61gJmHg3Gxot", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/usn", - "underlyingTokens": [ - "PUhuAtMHsKavMTwZsLaDeKy2jb7ciETHJP7rhbKLJGY", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "source": "saber" - } - }, - "plotKey": "ueVrPTeDJib2cALnMAkzg87nkG9DN5QW5xWu6vjjsAT", - "swap": { - "config": { - "swapAccount": "iLiUBQ7Z7im6Ew3b4ewwPcehzWgEQRJ1iQz7g6D62NW", - "authority": "9miYzKwZPcvEiuHaNowbh9Yxd5mdk9b3qXUjQR6qyPLd", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "NERQa8KLAt2DRAXzo3D2WbKVRkbGENr61gJmHg3Gxot", - "adminAccount": "BuaGV3P6Tb8Mg7Wx78kga6zQFgc1Vt4MQv58WDTD2ydV", - "tokenA": { - "adminFeeAccount": "Ag9QvRDFHMeDHgwApqrpsgpJYqDoNofJMR97ZsPsrmzQ", - "mint": "PUhuAtMHsKavMTwZsLaDeKy2jb7ciETHJP7rhbKLJGY", - "reserve": "GpugBvKWM3TVhYcZjemSdtehBWgfvuGr6uAm9iPjXT6v" - }, - "tokenB": { - "adminFeeAccount": "FNKABfFJUtaP4xzPWr9A4SxzCcdfCFp3oTdiXXD4Csvv", - "mint": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "reserve": "92fMXJ3xy8tEyMUWLHKRLyhPw2nECBo77GtDiBBbYrjX" - }, - "initialAmpFactor": "19", - "targetAmpFactor": "19", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "28Bvg71ZD3btNx2DEz8x9R4TSE7M7ckBBpW5QJjUfX9r" - }, - { - "id": "ust", - "name": "wUST_v1-USDC", - "tokens": [ - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - }, - { - "name": "Wrapped UST (Wormhole v1)", - "symbol": "wUST_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CXLBjMMcwkc17GfJtBos6rQCo1ypeH6eDbB82Kby4MRm.png", - "decimals": 9, - "address": "CXLBjMMcwkc17GfJtBos6rQCo1ypeH6eDbB82Kby4MRm", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v1"], - "extensions": { - "website": "https://terra.money", - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0xa47c8bf37f92aBed4A126BDA807A7b7498661acD", - "coingeckoId": "terrausd", - "source": "wormhole-v1", - "address": "0xa47c8bf37f92aBed4A126BDA807A7b7498661acD", - "currency": "USD", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped UST (Wormhole v1)", - "symbol": "wUST_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CXLBjMMcwkc17GfJtBos6rQCo1ypeH6eDbB82Kby4MRm.png", - "decimals": 9, - "address": "CXLBjMMcwkc17GfJtBos6rQCo1ypeH6eDbB82Kby4MRm", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v1"], - "extensions": { - "website": "https://terra.money", - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0xa47c8bf37f92aBed4A126BDA807A7b7498661acD", - "coingeckoId": "terrausd", - "source": "wormhole-v1", - "address": "0xa47c8bf37f92aBed4A126BDA807A7b7498661acD", - "currency": "USD", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - }, - { - "name": "Saber Wrapped USD Coin (9 decimals)", - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "decimals": 9, - "symbol": "sUSDC-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped UST (Wormhole v1)", - "symbol": "wUST_v1", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CXLBjMMcwkc17GfJtBos6rQCo1ypeH6eDbB82Kby4MRm.png", - "decimals": 9, - "address": "CXLBjMMcwkc17GfJtBos6rQCo1ypeH6eDbB82Kby4MRm", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v1"], - "extensions": { - "website": "https://terra.money", - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "assetContract": "https://etherscan.io/address/0xa47c8bf37f92aBed4A126BDA807A7b7498661acD", - "coingeckoId": "terrausd", - "source": "wormhole-v1", - "address": "0xa47c8bf37f92aBed4A126BDA807A7b7498661acD", - "currency": "USD", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "wUSTv1-USDC", - "name": "Saber wUST_v1-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/UST32f2JtPGocLzsL41B3VBBoJzTm1mK1j3rwyM3Wgc.png", - "decimals": 9, - "address": "UST32f2JtPGocLzsL41B3VBBoJzTm1mK1j3rwyM3Wgc", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"], - "extensions": { - "website": "https://app.saber.so/pools/ust", - "underlyingTokens": [ - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "CXLBjMMcwkc17GfJtBos6rQCo1ypeH6eDbB82Kby4MRm" - ], - "source": "saber" - } - }, - "plotKey": "2Pyj6DfsYccbLSiLia13yqENrCHybQ85MCW4AfYxvzLS", - "swap": { - "config": { - "swapAccount": "7oAd7xG4m3oC2qeWB1szghTebAZyyGPAFDJ4wwwbRSNi", - "authority": "ASpJBf8HtyrNxaMqFNpjYCqi8SsJC5h56hd3HQUNk6M7", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "UST32f2JtPGocLzsL41B3VBBoJzTm1mK1j3rwyM3Wgc", - "adminAccount": "R7BqdWNUoqf5gHLVLJmmcw5ddaGbftLiy181QEX5SUn", - "tokenA": { - "adminFeeAccount": "2TrJ87SzxmnfvFq7feKesoFwuxki1SxDLxrXJPpygwvN", - "mint": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "reserve": "D9yh4KAysxt9GLacVe4Wwh2XqghhcjTCSTV9HuM7TBJd" - }, - "tokenB": { - "adminFeeAccount": "GYiQ2bwkcTcM1FZuC5YevpXCnKyKHXfoDQfxh8XxMFce", - "mint": "CXLBjMMcwkc17GfJtBos6rQCo1ypeH6eDbB82Kby4MRm", - "reserve": "HDYfJLpZKaMFb84jM4mRytn7XLR8UFZUnQpSfhJJaNEy" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "FFfgPdrES48xe8UKGgmdc5kvQ9cv49oeu5FUKadh1i1k", - "newPoolID": "wust" - }, - { - "id": "ust_cash", - "name": "UST-CASH", - "tokens": [ - { - "name": "UST (Wormhole)", - "symbol": "UST", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i.png", - "decimals": 6, - "address": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "chainId": 101, - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Cashio Dollar", - "symbol": "CASH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "decimals": 6, - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://cashio.app", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/" - } - } - ], - "tokenIcons": [ - { - "name": "UST (Wormhole)", - "symbol": "UST", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i.png", - "decimals": 6, - "address": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "chainId": 101, - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Cashio Dollar", - "symbol": "CASH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "decimals": 6, - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://cashio.app", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/" - } - } - ], - "underlyingIcons": [ - { - "name": "UST (Wormhole)", - "symbol": "UST", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i.png", - "decimals": 6, - "address": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "chainId": 101, - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Cashio Dollar", - "symbol": "CASH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "decimals": 6, - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://cashio.app", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "UST-CASH", - "name": "Saber UST-CASH LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CLPRkuzQFiYnXddGTTKLvqgjgh4Tm7q16sVvivWNRzo8.png", - "decimals": 6, - "address": "CLPRkuzQFiYnXddGTTKLvqgjgh4Tm7q16sVvivWNRzo8", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-cashio"], - "extensions": { - "website": "https://app.saber.so/pools/ust_cash", - "underlyingTokens": [ - "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT" - ], - "source": "saber" - } - }, - "plotKey": "5kaicFEXXjFb8zZGnNqY6dHLFHqdvJyPFt4X4yKYfBGF", - "swap": { - "config": { - "swapAccount": "CSP7xvUx4mHXFHB7nGKRiGLkvkEcvo3HTTgVWJEwFTnQ", - "authority": "7K88AAbfSVHEZY87Ur3PrDhBYpwhKfTGxSWzMdh7XxUj", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": true, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "CLPRkuzQFiYnXddGTTKLvqgjgh4Tm7q16sVvivWNRzo8", - "adminAccount": "BKzRpj4ARHLgEKBpKCAR1bA2bZQHTB93oiPXTtGiSDKM", - "tokenA": { - "adminFeeAccount": "GLQ4xxVZKt3H8eo9EbUahPZhDnP94paHUZTQPtgE5QVm", - "mint": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "reserve": "JAjt8kZkTsxKA3VKnmszKHQwzuNSAXXhN3Y4NZ2kEoLU" - }, - "tokenB": { - "adminFeeAccount": "5cuGao2ULuvCUEYp161e21joadLYRsrFkdTSzYc76z84", - "mint": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "reserve": "F2NtJ1kcLLvQZ6RMH5sApf12BpGpAeGwio3WWPRZWUDu" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "HEFCUdoJRcsjD1VPacn4oYsoPne2TfdYaQNczq7Aj3iX" - }, - { - "id": "uxd", - "name": "UXD-USDC", - "tokens": [ - { - "name": "UXD Stablecoin", - "symbol": "UXD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT.png", - "decimals": 6, - "address": "7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://uxd.fi/", - "twitter": "https://twitter.com/UXDProtocol", - "medium": "https://uxdprotocol.medium.com/", - "discord": "https://discord.com/invite/BHfpYmjsBM", - "coingeckoId": "uxd-stablecoin", - "source": "UXD", - "currency": "USD", - "sourceUrl": "https://app.uxd.fi/" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "tokenIcons": [ - { - "name": "UXD Stablecoin", - "symbol": "UXD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT.png", - "decimals": 6, - "address": "7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://uxd.fi/", - "twitter": "https://twitter.com/UXDProtocol", - "medium": "https://uxdprotocol.medium.com/", - "discord": "https://discord.com/invite/BHfpYmjsBM", - "coingeckoId": "uxd-stablecoin", - "source": "UXD", - "currency": "USD", - "sourceUrl": "https://app.uxd.fi/" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "underlyingIcons": [ - { - "name": "UXD Stablecoin", - "symbol": "UXD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT.png", - "decimals": 6, - "address": "7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://uxd.fi/", - "twitter": "https://twitter.com/UXDProtocol", - "medium": "https://uxdprotocol.medium.com/", - "discord": "https://discord.com/invite/BHfpYmjsBM", - "coingeckoId": "uxd-stablecoin", - "source": "UXD", - "currency": "USD", - "sourceUrl": "https://app.uxd.fi/" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "UXD-USDC", - "name": "Saber UXD-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/UXDgmqLd1roNYkC4TmJzok61qcM9oKs5foDADiFoCiJ.png", - "decimals": 6, - "address": "UXDgmqLd1roNYkC4TmJzok61qcM9oKs5foDADiFoCiJ", - "chainId": 101, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/pools/uxd", - "underlyingTokens": [ - "7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "source": "saber" - } - }, - "plotKey": "FqTNQwqqGkWh7R5vtKqzS7JXcrTRA9ECTLeivpYu658d", - "swap": { - "config": { - "swapAccount": "KEN5P7p3asnb23Sw6yAmJRGvijfAzso3RqfyLAQhznt", - "authority": "HaNqpJUQeH2t6SB3tDJAtKV52fJM9rV1mGZrRrqMRZo1", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "UXDgmqLd1roNYkC4TmJzok61qcM9oKs5foDADiFoCiJ", - "adminAccount": "6mTaTmKgKey4i8NpYX1WwNmDTHVZjMJr8Q12jRkW7psC", - "tokenA": { - "adminFeeAccount": "3czPMjjuHNb1yAahyQVmGiN7AQAGaws8xpFcSskCj2oe", - "mint": "7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT", - "reserve": "9zj4aX38Uxf3h6AUjS4EipWS8mwbEofasHAf3a1uKGds" - }, - "tokenB": { - "adminFeeAccount": "5BEZbHQMLGyLsVTG77UoJqNsuF7PJUfeNmxwDfe6v4jy", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "reserve": "CwQDG1MWunn9cLNwcZLd8YBacweSR7ARo32w4mLua1Yr" - }, - "initialAmpFactor": "c8", - "targetAmpFactor": "0190", - "startRampTimestamp": 1652902818, - "stopRampTimestamp": 1653075542, - "fees": { - "trade": { - "formatted": "0.0010000000", - "numerator": "1", - "denominator": "100000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "BMMiE1bNCW61k3rw4Kfzx7er36JMrEsFGr1Bcng9i6Aq" - }, - { - "id": "uxd_cash", - "name": "UXD-CASH", - "tokens": [ - { - "name": "UXD Stablecoin", - "symbol": "UXD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT.png", - "decimals": 6, - "address": "7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://uxd.fi/", - "twitter": "https://twitter.com/UXDProtocol", - "medium": "https://uxdprotocol.medium.com/", - "discord": "https://discord.com/invite/BHfpYmjsBM", - "coingeckoId": "uxd-stablecoin", - "source": "UXD", - "currency": "USD", - "sourceUrl": "https://app.uxd.fi/" - } - }, - { - "name": "Cashio Dollar", - "symbol": "CASH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "decimals": 6, - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://cashio.app", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/" - } - } - ], - "tokenIcons": [ - { - "name": "UXD Stablecoin", - "symbol": "UXD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT.png", - "decimals": 6, - "address": "7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://uxd.fi/", - "twitter": "https://twitter.com/UXDProtocol", - "medium": "https://uxdprotocol.medium.com/", - "discord": "https://discord.com/invite/BHfpYmjsBM", - "coingeckoId": "uxd-stablecoin", - "source": "UXD", - "currency": "USD", - "sourceUrl": "https://app.uxd.fi/" - } - }, - { - "name": "Cashio Dollar", - "symbol": "CASH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "decimals": 6, - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://cashio.app", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/" - } - } - ], - "underlyingIcons": [ - { - "name": "UXD Stablecoin", - "symbol": "UXD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT.png", - "decimals": 6, - "address": "7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://uxd.fi/", - "twitter": "https://twitter.com/UXDProtocol", - "medium": "https://uxdprotocol.medium.com/", - "discord": "https://discord.com/invite/BHfpYmjsBM", - "coingeckoId": "uxd-stablecoin", - "source": "UXD", - "currency": "USD", - "sourceUrl": "https://app.uxd.fi/" - } - }, - { - "name": "Cashio Dollar", - "symbol": "CASH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "decimals": 6, - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://cashio.app", - "twitter": "https://twitter.com/CashioApp", - "medium": "https://medium.com/@cashioapp", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "coingeckoId": "cashio-dollar", - "source": "cashio", - "currency": "USD", - "sourceUrl": "https://cashio.app/" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "UXD-CASH", - "name": "Saber UXD-CASH LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/UXDjCH2xGyyLWa92stSUDftWPKGFFPEvqvk28gQA8bW.png", - "decimals": 6, - "address": "UXDjCH2xGyyLWa92stSUDftWPKGFFPEvqvk28gQA8bW", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-cashio"], - "extensions": { - "website": "https://app.saber.so/pools/uxd_cash", - "underlyingTokens": [ - "7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT", - "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT" - ], - "source": "saber" - } - }, - "plotKey": "DzQFtjDpNbtT2PmiSnUaGX3MwsEgYTiNSdhXFvx7zLMf", - "swap": { - "config": { - "swapAccount": "D1RyGbGF7iFupgaknywa5ThmdkdMwCJR7cQXfzTnNpFv", - "authority": "551oYh1ChowZfq2PiU7uxJugM4ywqf1JCPuTk9qEjiU5", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": true, - "nonce": 253, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "UXDjCH2xGyyLWa92stSUDftWPKGFFPEvqvk28gQA8bW", - "adminAccount": "iy51K4TnFDhz3Pf9GgKLt3XBkwLMZr5oEConYYu2fgw", - "tokenA": { - "adminFeeAccount": "2YnywCN3t6WSASNNMUTF4msB5v9kvmn2MrgxAB9fogvo", - "mint": "7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT", - "reserve": "AzN6vs3nTunrapnJTZwD3EVALcLddfKC8hYexcWAtG9F" - }, - "tokenB": { - "adminFeeAccount": "8v6S2WJQFxRkHh41uL5HW3aHff5Cz3pCwcHdaTE9ApZY", - "mint": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "reserve": "AKD1Xb4SMBMJYurhrx26mGagKeLBQAHKxdo22n33pUX5" - }, - "initialAmpFactor": "64", - "targetAmpFactor": "64", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "Fp3eynmHDXTkCtosY9g7fhhfG3HFsCepyKP2UgaZBFAG" - }, - { - "id": "wbusd", - "name": "BUSDbs-USDC", - "tokens": [ - { - "name": "BUSD Token (Wormhole from BSC)", - "symbol": "BUSDbs", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/5RpUwQ8wtdPCZHhu6MERp2RGrpobsbZ6MH5dDHkUjs2.png", - "decimals": 8, - "address": "5RpUwQ8wtdPCZHhu6MERp2RGrpobsbZ6MH5dDHkUjs2", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://bscscan.com/address/0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7", - "assetContract": "https://bscscan.com/address/0xe9e7cea3dedca5984780bafc599bd69add087d56", - "coingeckoId": "binance-usd", - "source": "wormhole-v2", - "address": "0xe9e7cea3dedca5984780bafc599bd69add087d56", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Saber Wrapped USD Coin (8 decimals)", - "address": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "decimals": 8, - "symbol": "sUSDC-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "BUSD Token (Wormhole from BSC)", - "symbol": "BUSDbs", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/5RpUwQ8wtdPCZHhu6MERp2RGrpobsbZ6MH5dDHkUjs2.png", - "decimals": 8, - "address": "5RpUwQ8wtdPCZHhu6MERp2RGrpobsbZ6MH5dDHkUjs2", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://bscscan.com/address/0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7", - "assetContract": "https://bscscan.com/address/0xe9e7cea3dedca5984780bafc599bd69add087d56", - "coingeckoId": "binance-usd", - "source": "wormhole-v2", - "address": "0xe9e7cea3dedca5984780bafc599bd69add087d56", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Saber Wrapped USD Coin (8 decimals)", - "address": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "decimals": 8, - "symbol": "sUSDC-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "BUSD Token (Wormhole from BSC)", - "symbol": "BUSDbs", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/5RpUwQ8wtdPCZHhu6MERp2RGrpobsbZ6MH5dDHkUjs2.png", - "decimals": 8, - "address": "5RpUwQ8wtdPCZHhu6MERp2RGrpobsbZ6MH5dDHkUjs2", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://bscscan.com/address/0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7", - "assetContract": "https://bscscan.com/address/0xe9e7cea3dedca5984780bafc599bd69add087d56", - "coingeckoId": "binance-usd", - "source": "wormhole-v2", - "address": "0xe9e7cea3dedca5984780bafc599bd69add087d56", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "BUSDbs-USDC", - "name": "Saber BUSDbs-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/WLPR8Sy6Fbnf2sZHVg8Z7uW1QnRThnjhb244kf4ddCS.png", - "decimals": 8, - "address": "WLPR8Sy6Fbnf2sZHVg8Z7uW1QnRThnjhb244kf4ddCS", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"], - "extensions": { - "website": "https://app.saber.so/pools/wbusd", - "underlyingTokens": [ - "5RpUwQ8wtdPCZHhu6MERp2RGrpobsbZ6MH5dDHkUjs2", - "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy" - ], - "source": "saber" - } - }, - "plotKey": "5VfcVdRGnNEzE3rx5ewqbo9UtDgbXtgXVoghaLtHFaH", - "swap": { - "config": { - "swapAccount": "BUSDgu5JdqP1rndBvXvanbEufS94FNh1w5FJcAj6vawb", - "authority": "AuGSuRwZ7qN9sG8eUdfFsW7xdxSZ8CvB4jM4RdkrU3FD", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "WLPR8Sy6Fbnf2sZHVg8Z7uW1QnRThnjhb244kf4ddCS", - "adminAccount": "3faCHWF4frSkcMBwEsagFwrCcwSDdGk9R5ARXyipcEt5", - "tokenA": { - "adminFeeAccount": "7KCb5VCg9Amc24DiFBKaqYuVKZJVyFqstvYpKuASsAcB", - "mint": "5RpUwQ8wtdPCZHhu6MERp2RGrpobsbZ6MH5dDHkUjs2", - "reserve": "Bgzr8cWubt89JQFXndVjtdKmDbGzuPxNhvjH1EhWCwbo" - }, - "tokenB": { - "adminFeeAccount": "6frEk6q3nmtRyConjCrTjZosMCRpM2bKsKEezRUTKS8v", - "mint": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "reserve": "Dxaf8xPBBQsasRKW5Aa4Sw2YrbfGofY9xZueyyF23FBW" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "7xxkhSdMVhfoekF92ojd8AM6qzyJnX5yui9Yu2fx85VP" - }, - { - "id": "wbusdc", - "name": "USDCbs-USDC", - "tokens": [ - { - "name": "USD Coin (Wormhole from BSC)", - "symbol": "USDCbs", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FCqfQSujuPxy6V42UvafBhsysWtEq1vhjfMN1PUbgaxA.png", - "decimals": 8, - "address": "FCqfQSujuPxy6V42UvafBhsysWtEq1vhjfMN1PUbgaxA", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://bscscan.com/address/0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7", - "assetContract": "https://bscscan.com/address/0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", - "coingeckoId": "usd-coin", - "source": "wormhole-v2", - "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Saber Wrapped USD Coin (8 decimals)", - "address": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "decimals": 8, - "symbol": "sUSDC-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "USD Coin (Wormhole from BSC)", - "symbol": "USDCbs", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FCqfQSujuPxy6V42UvafBhsysWtEq1vhjfMN1PUbgaxA.png", - "decimals": 8, - "address": "FCqfQSujuPxy6V42UvafBhsysWtEq1vhjfMN1PUbgaxA", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://bscscan.com/address/0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7", - "assetContract": "https://bscscan.com/address/0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", - "coingeckoId": "usd-coin", - "source": "wormhole-v2", - "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Saber Wrapped USD Coin (8 decimals)", - "address": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "decimals": 8, - "symbol": "sUSDC-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "USD Coin (Wormhole from BSC)", - "symbol": "USDCbs", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FCqfQSujuPxy6V42UvafBhsysWtEq1vhjfMN1PUbgaxA.png", - "decimals": 8, - "address": "FCqfQSujuPxy6V42UvafBhsysWtEq1vhjfMN1PUbgaxA", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://bscscan.com/address/0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7", - "assetContract": "https://bscscan.com/address/0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", - "coingeckoId": "usd-coin", - "source": "wormhole-v2", - "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "USDCbs-USDC", - "name": "Saber USDCbs-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/WLPsu8oyn1muh5nimxvBsgo6hh6t5jAdUtZ1VmJkohs.png", - "decimals": 8, - "address": "WLPsu8oyn1muh5nimxvBsgo6hh6t5jAdUtZ1VmJkohs", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"], - "extensions": { - "website": "https://app.saber.so/pools/wbusdc", - "underlyingTokens": [ - "FCqfQSujuPxy6V42UvafBhsysWtEq1vhjfMN1PUbgaxA", - "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy" - ], - "source": "saber" - } - }, - "plotKey": "9EHiJu3mcwjPBVENDs2mA1DnmjSZ7EdduvsMgmb5iPmV", - "swap": { - "config": { - "swapAccount": "BUSD5rCfUDpCxKGMvYU2yThChxgHoioK74PTPociGnv2", - "authority": "DZrJ1JztPXQtDT7X8bS8mFyQrDH2YdTsXAKnoBHv2txT", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "WLPsu8oyn1muh5nimxvBsgo6hh6t5jAdUtZ1VmJkohs", - "adminAccount": "8vd6qeoZDzb9BrPF6VGgaAjkugFsnfDnJDq8pJynvUu1", - "tokenA": { - "adminFeeAccount": "5VynBnXugWcTq1ajHouD1iP5GTcaEU6AzsqsuXwwdMKa", - "mint": "FCqfQSujuPxy6V42UvafBhsysWtEq1vhjfMN1PUbgaxA", - "reserve": "CcFHbafgYDZ8yA8Me1PdtDiVb2eeaS61LbqyKKK5CsNZ" - }, - "tokenB": { - "adminFeeAccount": "8Zw38irqChsJ99WZjLwdSFrRbAcbw47zs4xGYRM33RTM", - "mint": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "reserve": "26R9s4nmF3CFDTkiePDwRmtscn8i7r2eygbSijditJ58" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0050000000", - "numerator": "5", - "denominator": "100000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "GiZDN6QkWTGwULWwoyacaeRNEwnQHsn9ohojE2cZZ995" - }, - { - "id": "wbusdt", - "name": "USDTbs-USDT", - "tokens": [ - { - "name": "Tether USD (Wormhole from BSC)", - "symbol": "USDTbs", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/8qJSyQprMC57TWKaYEmetUR3UUiTP2M3hXdcvFhkZdmv.png", - "decimals": 8, - "address": "8qJSyQprMC57TWKaYEmetUR3UUiTP2M3hXdcvFhkZdmv", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://bscscan.com/address/0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7", - "assetContract": "https://bscscan.com/address/0x55d398326f99059ff775485246999027b3197955", - "coingeckoId": "tether", - "source": "wormhole-v2", - "address": "0x55d398326f99059ff775485246999027b3197955", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Saber Wrapped USDT (8 decimals)", - "address": "T8KdT8hDzNhbGx5sjpEUxepnbDB1TZoCa7vtC5JjsMw", - "decimals": 8, - "symbol": "sUSDT-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/T8KdT8hDzNhbGx5sjpEUxepnbDB1TZoCa7vtC5JjsMw.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD", - "assetContract": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "underlyingTokens": ["Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"] - } - } - ], - "tokenIcons": [ - { - "name": "Tether USD (Wormhole from BSC)", - "symbol": "USDTbs", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/8qJSyQprMC57TWKaYEmetUR3UUiTP2M3hXdcvFhkZdmv.png", - "decimals": 8, - "address": "8qJSyQprMC57TWKaYEmetUR3UUiTP2M3hXdcvFhkZdmv", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://bscscan.com/address/0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7", - "assetContract": "https://bscscan.com/address/0x55d398326f99059ff775485246999027b3197955", - "coingeckoId": "tether", - "source": "wormhole-v2", - "address": "0x55d398326f99059ff775485246999027b3197955", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Saber Wrapped USDT (8 decimals)", - "address": "T8KdT8hDzNhbGx5sjpEUxepnbDB1TZoCa7vtC5JjsMw", - "decimals": 8, - "symbol": "sUSDT-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/T8KdT8hDzNhbGx5sjpEUxepnbDB1TZoCa7vtC5JjsMw.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD", - "assetContract": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "underlyingTokens": ["Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"] - } - } - ], - "underlyingIcons": [ - { - "name": "Tether USD (Wormhole from BSC)", - "symbol": "USDTbs", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/8qJSyQprMC57TWKaYEmetUR3UUiTP2M3hXdcvFhkZdmv.png", - "decimals": 8, - "address": "8qJSyQprMC57TWKaYEmetUR3UUiTP2M3hXdcvFhkZdmv", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://bscscan.com/address/0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7", - "assetContract": "https://bscscan.com/address/0x55d398326f99059ff775485246999027b3197955", - "coingeckoId": "tether", - "source": "wormhole-v2", - "address": "0x55d398326f99059ff775485246999027b3197955", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "USDT", - "symbol": "USDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB.svg", - "decimals": 6, - "address": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://tether.to/", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "USDTbs-USDT", - "name": "Saber USDTbs-USDT LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/WLPAEUgB95YrU7Vk1FVPeSP5C3e66bf63frHRgsyxHv.png", - "decimals": 8, - "address": "WLPAEUgB95YrU7Vk1FVPeSP5C3e66bf63frHRgsyxHv", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"], - "extensions": { - "website": "https://app.saber.so/pools/wbusdt", - "underlyingTokens": [ - "8qJSyQprMC57TWKaYEmetUR3UUiTP2M3hXdcvFhkZdmv", - "T8KdT8hDzNhbGx5sjpEUxepnbDB1TZoCa7vtC5JjsMw" - ], - "source": "saber" - } - }, - "plotKey": "EZyPr4moLCmSPn89dzhfksmTmT3646MYxE7pBuHr8mTG", - "swap": { - "config": { - "swapAccount": "BUSDTd9WiT6uBHJRgNvFXBsA7JrifsAtWzKfioN7ERcy", - "authority": "G2NKBFb4gXDPD3PPbUPdz4QA6VdAcGrhk1PeM7D6NyLm", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "WLPAEUgB95YrU7Vk1FVPeSP5C3e66bf63frHRgsyxHv", - "adminAccount": "FDzCQy2dZLz1imSQWbnZfHG88ttQ9fF6JbJbTxk1kXT6", - "tokenA": { - "adminFeeAccount": "BEucHS8xRsZu1A9qwBaabfthp4NKa7UXfA954iXYdXms", - "mint": "8qJSyQprMC57TWKaYEmetUR3UUiTP2M3hXdcvFhkZdmv", - "reserve": "DyBxrn7gSc1EwnpWhDyhzvMHPtxpmBqRqotapLcKcfTM" - }, - "tokenB": { - "adminFeeAccount": "5iybTEkGJ7y9NPd4si3bUaTLwBLB14UrzJyxgKqQFVdW", - "mint": "T8KdT8hDzNhbGx5sjpEUxepnbDB1TZoCa7vtC5JjsMw", - "reserve": "Cds99GeBgoCpqBsoRWu1C6fF9LiUMd4pXQQD24s9LPff" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0050000000", - "numerator": "5", - "denominator": "100000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "86tqayCSmxprknt6Lu6rpJx7B7HjaurHXUmzev7Hx8v6" - }, - { - "id": "wdai", - "name": "DAI-USDC", - "tokens": [ - { - "name": "Dai Stablecoin (Wormhole)", - "symbol": "DAI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o.png", - "decimals": 8, - "address": "EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o", - "chainId": 101, - "tags": ["wrapped", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x6b175474e89094c44da98b954eedeac495271d0f", - "coingeckoId": "dai", - "source": "wormhole-v2", - "address": "0x6b175474e89094c44da98b954eedeac495271d0f", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Saber Wrapped USD Coin (8 decimals)", - "address": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "decimals": 8, - "symbol": "sUSDC-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "Dai Stablecoin (Wormhole)", - "symbol": "DAI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o.png", - "decimals": 8, - "address": "EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o", - "chainId": 101, - "tags": ["wrapped", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x6b175474e89094c44da98b954eedeac495271d0f", - "coingeckoId": "dai", - "source": "wormhole-v2", - "address": "0x6b175474e89094c44da98b954eedeac495271d0f", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Saber Wrapped USD Coin (8 decimals)", - "address": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "decimals": 8, - "symbol": "sUSDC-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "Dai Stablecoin (Wormhole)", - "symbol": "DAI", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o.png", - "decimals": 8, - "address": "EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o", - "chainId": 101, - "tags": ["wrapped", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x6b175474e89094c44da98b954eedeac495271d0f", - "coingeckoId": "dai", - "source": "wormhole-v2", - "address": "0x6b175474e89094c44da98b954eedeac495271d0f", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "DAI-USDC", - "name": "Saber DAI-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/DAihWEjhBc8LEmV1rEekTaiC2zqE5ex7nEFkmoe1Ppp3.png", - "decimals": 8, - "address": "DAihWEjhBc8LEmV1rEekTaiC2zqE5ex7nEFkmoe1Ppp3", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"], - "extensions": { - "website": "https://app.saber.so/pools/wdai", - "underlyingTokens": [ - "EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o", - "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy" - ], - "source": "saber" - } - }, - "plotKey": "jsDhpC6hBGrUqj7wMfrG1XwESTiZAsTskXcXHgwda3w", - "swap": { - "config": { - "swapAccount": "RajgMbScQbqqrdJfR2rxfHJiTiY5b6bJ2tTXiF4aPxy", - "authority": "7mupg3bhALz9TBNz8yWRroVpVqJMKDaJG1u1JasCebe8", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "DAihWEjhBc8LEmV1rEekTaiC2zqE5ex7nEFkmoe1Ppp3", - "adminAccount": "DwwBvEzAoif5TrUsBMd8b3u63UfWSocRnfAPgDNoGn8H", - "tokenA": { - "adminFeeAccount": "Hpx851G6MKmNfAawui9f7cN4jbPTE7TNWS9E4wd346Xw", - "mint": "EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o", - "reserve": "725ZA3fhyBAKb5iopNRrcbSuQa3LXA1656Q3mBvYPxeg" - }, - "tokenB": { - "adminFeeAccount": "FbBJQXecC63Ff1kQzYTxbZzrbABHTqsEaeFoxfEthM29", - "mint": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "reserve": "GLA6i1dSZpUfk2f9Nj8uiG7xyDdAR2reff8oEiZH3617" - }, - "initialAmpFactor": "02ee", - "targetAmpFactor": "02ee", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "Gr1ijg84eQWG9zsf5PaBpjrNy4iEzP6hBpUgqxWkpb9y" - }, - { - "id": "webusd", - "name": "BUSDet-USDC", - "tokens": [ - { - "name": "Binance USD (Wormhole from Ethereum)", - "symbol": "BUSDet", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/33fsBLA8djQm82RpHmE3SuVrPGtZBWNYExsEUeKX1HXX.png", - "decimals": 8, - "address": "33fsBLA8djQm82RpHmE3SuVrPGtZBWNYExsEUeKX1HXX", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x4fabb145d64652a948d72533023f6e7a623c7c53", - "coingeckoId": "binance-usd", - "source": "wormhole-v2", - "address": "0x4fabb145d64652a948d72533023f6e7a623c7c53", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Saber Wrapped USD Coin (8 decimals)", - "address": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "decimals": 8, - "symbol": "sUSDC-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "Binance USD (Wormhole from Ethereum)", - "symbol": "BUSDet", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/33fsBLA8djQm82RpHmE3SuVrPGtZBWNYExsEUeKX1HXX.png", - "decimals": 8, - "address": "33fsBLA8djQm82RpHmE3SuVrPGtZBWNYExsEUeKX1HXX", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x4fabb145d64652a948d72533023f6e7a623c7c53", - "coingeckoId": "binance-usd", - "source": "wormhole-v2", - "address": "0x4fabb145d64652a948d72533023f6e7a623c7c53", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Saber Wrapped USD Coin (8 decimals)", - "address": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "decimals": 8, - "symbol": "sUSDC-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "Binance USD (Wormhole from Ethereum)", - "symbol": "BUSDet", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/33fsBLA8djQm82RpHmE3SuVrPGtZBWNYExsEUeKX1HXX.png", - "decimals": 8, - "address": "33fsBLA8djQm82RpHmE3SuVrPGtZBWNYExsEUeKX1HXX", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x4fabb145d64652a948d72533023f6e7a623c7c53", - "coingeckoId": "binance-usd", - "source": "wormhole-v2", - "address": "0x4fabb145d64652a948d72533023f6e7a623c7c53", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "BUSDet-USDC", - "name": "Saber BUSDet-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BSCNZ4GLnpZYv4BLk5edymk4qty8a6ZpiMbfvtv9gAzL.png", - "decimals": 8, - "address": "BSCNZ4GLnpZYv4BLk5edymk4qty8a6ZpiMbfvtv9gAzL", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"], - "extensions": { - "website": "https://app.saber.so/pools/webusd", - "underlyingTokens": [ - "33fsBLA8djQm82RpHmE3SuVrPGtZBWNYExsEUeKX1HXX", - "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy" - ], - "source": "saber" - } - }, - "plotKey": "4RDTPgZiytiiP7orSnfrSpjjyLbKU1ogxir1Bb37233N", - "swap": { - "config": { - "swapAccount": "CZgvH45CRmoaNJ7395Ao5CQZXkGznvqU7cErD6n7FaRg", - "authority": "H73Bq4wPdkMyM1o1RCgFTrmCCTzkK7W9FrfyWWLZ8QCj", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "BSCNZ4GLnpZYv4BLk5edymk4qty8a6ZpiMbfvtv9gAzL", - "adminAccount": "Cb4ATbvbDNRYbHv8ax4hY8cfobPjLby2HWq2wmN3TGCr", - "tokenA": { - "adminFeeAccount": "yPocykmSvJew7HAdfxDFj9QAMjansDu5GchZoLg9twk", - "mint": "33fsBLA8djQm82RpHmE3SuVrPGtZBWNYExsEUeKX1HXX", - "reserve": "4ZjU6MKvtqVQKCiowhvZ5yUsPxXX5SCzd5eFsPeXyey5" - }, - "tokenB": { - "adminFeeAccount": "277k3jhGK79oT8HsXpzfPd7Td2TftpCB2Tdrn6MuK55S", - "mint": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "reserve": "BsyWeshjDbCvjDojry3vKDCesmFRM37WtwcR4Kfgzqr" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "4RU52YmyNaxg1zPnzALtv3aeXJJZEy5uaRXaTC7bBSgA" - }, - { - "id": "weusdc", - "name": "USDCet-USDC", - "tokens": [ - { - "name": "USD Coin (Wormhole from Ethereum)", - "symbol": "USDCet", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/A9mUU4qviSctJVPJdBJWkb28deg915LYJKrzQ19ji3FM.png", - "decimals": 6, - "address": "A9mUU4qviSctJVPJdBJWkb28deg915LYJKrzQ19ji3FM", - "chainId": 101, - "tags": ["wrapped", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - "coingeckoId": "usd-coin", - "source": "wormhole-v2", - "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "tokenIcons": [ - { - "name": "USD Coin (Wormhole from Ethereum)", - "symbol": "USDCet", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/A9mUU4qviSctJVPJdBJWkb28deg915LYJKrzQ19ji3FM.png", - "decimals": 6, - "address": "A9mUU4qviSctJVPJdBJWkb28deg915LYJKrzQ19ji3FM", - "chainId": 101, - "tags": ["wrapped", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - "coingeckoId": "usd-coin", - "source": "wormhole-v2", - "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "underlyingIcons": [ - { - "name": "USD Coin (Wormhole from Ethereum)", - "symbol": "USDCet", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/A9mUU4qviSctJVPJdBJWkb28deg915LYJKrzQ19ji3FM.png", - "decimals": 6, - "address": "A9mUU4qviSctJVPJdBJWkb28deg915LYJKrzQ19ji3FM", - "chainId": 101, - "tags": ["wrapped", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - "coingeckoId": "usd-coin", - "source": "wormhole-v2", - "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "USDCet-USDC", - "name": "Saber USDCet-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/USDCgfM1psLGhAbx99iPA72mTySvUcVq33qhCJpm65c.png", - "decimals": 6, - "address": "USDCgfM1psLGhAbx99iPA72mTySvUcVq33qhCJpm65c", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"], - "extensions": { - "website": "https://app.saber.so/pools/weusdc", - "underlyingTokens": [ - "A9mUU4qviSctJVPJdBJWkb28deg915LYJKrzQ19ji3FM", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "source": "saber" - } - }, - "plotKey": "5HtgDfdZwTgFrEZBZh5R1NHFn2ZNeA7StBsUvFpaXF6Z", - "swap": { - "config": { - "swapAccount": "GokA1R67GqSavkd15zR62QD68Tuc5AEfvjssntVDEbM8", - "authority": "7XFMgfxhDURuaPwhUkXAy6uQJCoC3HPpjiZBqcot57Ge", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "USDCgfM1psLGhAbx99iPA72mTySvUcVq33qhCJpm65c", - "adminAccount": "7ENqiPFupFXbjwBwYT1YsgWSjc3sj7fNEZbpxcSr9A6N", - "tokenA": { - "adminFeeAccount": "BBRibcSFF2AhXmtgGoZFksvpe1mpeLtCotMpNq5zNdf3", - "mint": "A9mUU4qviSctJVPJdBJWkb28deg915LYJKrzQ19ji3FM", - "reserve": "3YB7hfpBdbQEuZqLGWVDpRPmeZWCUsrrWyqGXegnQ6Cg" - }, - "tokenB": { - "adminFeeAccount": "A9oXiCQsNdaEe58STWvEEy9NQ1CyAW8WRT6ggwaYetA", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "reserve": "4DPCj6Z1DsG6HUtwSogBGqXEUxdEV5a8YVrrFtcnz7UW" - }, - "initialAmpFactor": "03e8", - "targetAmpFactor": "07d0", - "startRampTimestamp": 1651036584, - "stopRampTimestamp": 1651209366, - "fees": { - "trade": { - "formatted": "0.0010000000", - "numerator": "1", - "denominator": "100000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "7q5jvR4C6hFrC6tScyVKV4wE8km9koX537bud5iyw8ma" - }, - { - "id": "weusdt", - "name": "USDTet-USDT", - "tokens": [ - { - "name": "Tether USD (Wormhole from Ethereum)", - "symbol": "USDTet", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Dn4noZ5jgGfkntzcQSUZ8czkreiZ1ForXYoV2H8Dm7S1.png", - "decimals": 6, - "address": "Dn4noZ5jgGfkntzcQSUZ8czkreiZ1ForXYoV2H8Dm7S1", - "chainId": 101, - "tags": ["wrapped", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7", - "coingeckoId": "tether", - "source": "wormhole-v2", - "address": "0xdac17f958d2ee523a2206206994597c13d831ec7", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "USDT", - "symbol": "USDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB.svg", - "decimals": 6, - "address": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://tether.to/", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD" - } - } - ], - "tokenIcons": [ - { - "name": "Tether USD (Wormhole from Ethereum)", - "symbol": "USDTet", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Dn4noZ5jgGfkntzcQSUZ8czkreiZ1ForXYoV2H8Dm7S1.png", - "decimals": 6, - "address": "Dn4noZ5jgGfkntzcQSUZ8czkreiZ1ForXYoV2H8Dm7S1", - "chainId": 101, - "tags": ["wrapped", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7", - "coingeckoId": "tether", - "source": "wormhole-v2", - "address": "0xdac17f958d2ee523a2206206994597c13d831ec7", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "USDT", - "symbol": "USDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB.svg", - "decimals": 6, - "address": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://tether.to/", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD" - } - } - ], - "underlyingIcons": [ - { - "name": "Tether USD (Wormhole from Ethereum)", - "symbol": "USDTet", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Dn4noZ5jgGfkntzcQSUZ8czkreiZ1ForXYoV2H8Dm7S1.png", - "decimals": 6, - "address": "Dn4noZ5jgGfkntzcQSUZ8czkreiZ1ForXYoV2H8Dm7S1", - "chainId": 101, - "tags": ["wrapped", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7", - "coingeckoId": "tether", - "source": "wormhole-v2", - "address": "0xdac17f958d2ee523a2206206994597c13d831ec7", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "USDT", - "symbol": "USDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB.svg", - "decimals": 6, - "address": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://tether.to/", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "USDTet-USDT", - "name": "Saber USDTet-USDT LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/USDTJZL2vH92K5QeCvQTTzvMXUYAdvk3v46CwZyfsue.png", - "decimals": 6, - "address": "USDTJZL2vH92K5QeCvQTTzvMXUYAdvk3v46CwZyfsue", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"], - "extensions": { - "website": "https://app.saber.so/pools/weusdt", - "underlyingTokens": [ - "Dn4noZ5jgGfkntzcQSUZ8czkreiZ1ForXYoV2H8Dm7S1", - "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" - ], - "source": "saber" - } - }, - "plotKey": "7rM3yGbfGcfTpmyRwebwJd7s4qQ1H5MdVZj2RwkFqZnX", - "swap": { - "config": { - "swapAccount": "vEnkoSUkpnbRrPgBz9DfcVxNz67zjwMYBZraAvDDNSf", - "authority": "2kHUshxGYQLo7RQYdLTM6MXZq118w3TA4oak9dCwsF6B", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "USDTJZL2vH92K5QeCvQTTzvMXUYAdvk3v46CwZyfsue", - "adminAccount": "A8Hi6brMs3GJkCqVVC7fK65UKBKFEeRPa9TvPSUdpSKY", - "tokenA": { - "adminFeeAccount": "GZ6hMANQzo725wXxymdeBNiSdh4p9iSz96mXrkjNZ3tC", - "mint": "Dn4noZ5jgGfkntzcQSUZ8czkreiZ1ForXYoV2H8Dm7S1", - "reserve": "DtfyjjsZ5yCjWKLKHvwsfXs5QVsmm1QkK6Sh9JZHoq1g" - }, - "tokenB": { - "adminFeeAccount": "3WWb6c76EjCNaKqye9RPh3eyNLzxNJh4FFzEAaEDmVAM", - "mint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "reserve": "e5wrKCRv4GhHvEf1VD5Pq2KGaZDXP77nTL612Jyrxwy" - }, - "initialAmpFactor": "03e8", - "targetAmpFactor": "03e8", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0050000000", - "numerator": "5", - "denominator": "100000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "yPKVUwQxzuJ57uxW9rAJF6D1xEEButVjvRBsuN7E77P" - }, - { - "id": "wfrax", - "name": "FRAX-USDC", - "tokens": [ - { - "name": "Frax (Wormhole)", - "symbol": "FRAX", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp.png", - "decimals": 8, - "address": "FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x853d955acef822db058eb8505911ed77f175b99e", - "coingeckoId": "frax", - "source": "wormhole-v2", - "address": "0x853d955acef822db058eb8505911ed77f175b99e", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Saber Wrapped USD Coin (8 decimals)", - "address": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "decimals": 8, - "symbol": "sUSDC-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "Frax (Wormhole)", - "symbol": "FRAX", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp.png", - "decimals": 8, - "address": "FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x853d955acef822db058eb8505911ed77f175b99e", - "coingeckoId": "frax", - "source": "wormhole-v2", - "address": "0x853d955acef822db058eb8505911ed77f175b99e", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Saber Wrapped USD Coin (8 decimals)", - "address": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "decimals": 8, - "symbol": "sUSDC-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "Frax (Wormhole)", - "symbol": "FRAX", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp.png", - "decimals": 8, - "address": "FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x853d955acef822db058eb8505911ed77f175b99e", - "coingeckoId": "frax", - "source": "wormhole-v2", - "address": "0x853d955acef822db058eb8505911ed77f175b99e", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "FRAX-USDC", - "name": "Saber FRAX-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FRXsjEv4jF3r72FgbCXu8uLbPoZGLmCmg3EN1S3cfC4x.png", - "decimals": 8, - "address": "FRXsjEv4jF3r72FgbCXu8uLbPoZGLmCmg3EN1S3cfC4x", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"], - "extensions": { - "website": "https://app.saber.so/pools/wfrax", - "underlyingTokens": [ - "FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp", - "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy" - ], - "source": "saber" - } - }, - "plotKey": "BRsZ18RRzAejVEgHRzponHQKZ6sc5kPEJpZxLL2xTYTx", - "swap": { - "config": { - "swapAccount": "KZMu9QBEdL97EFgamLbN5DE1AoKBG4HdrKKJo4Vuon3", - "authority": "4DEzAUzQCmvd4LsxcQ8X2tjNH89wGby8g9UXqZB55Mwp", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "FRXsjEv4jF3r72FgbCXu8uLbPoZGLmCmg3EN1S3cfC4x", - "adminAccount": "89zGiK4DwAdesGac3PUje6Zz9muEZMsGvegGYzkr5kbp", - "tokenA": { - "adminFeeAccount": "D4ivwgj4zg3zZwBKrLaF8RdnEfh6ApY7ejzAuuj9dTjb", - "mint": "FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp", - "reserve": "DD4ACBWyVqdaKWh7v5btsgqQCCMwbKnuL2xd9pv7Gyuw" - }, - "tokenB": { - "adminFeeAccount": "HhKjJWcCZPEFgVDZ9DhFjCW1UAadHUhVLQaQR1hcExnZ", - "mint": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "reserve": "GcYqiJ1MAuYbNTNYXm1F1gQYTfTgkErACAhNU5dpVj9T" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "CEtNcKPEirS6Ns2znGmvk1Z2UYQBt5GJabwhtrv28UEN" - }, - { - "id": "wftt", - "name": "aeFTT-FTT", - "tokens": [ - { - "name": "Wrapped FTT (Allbridge from Ethereum)", - "symbol": "aeFTT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BFsCwfk8VsEbSfLkkgmoKsAPk2N6FMJjeTsuxfGa9VEf.png", - "decimals": 9, - "address": "BFsCwfk8VsEbSfLkkgmoKsAPk2N6FMJjeTsuxfGa9VEf", - "chainId": 101, - "tags": ["saber-mkt-ftt"], - "extensions": { - "coingeckoId": "ftx-token", - "source": "allbridge", - "currency": "FTT", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped FTX Token (Wormhole) (9 decimals)", - "address": "FTT9GrHBVHvDeUTgLU8FxVJouGqg9uiWGmmjETdm32Sx", - "decimals": 9, - "symbol": "sFTT-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FTT9GrHBVHvDeUTgLU8FxVJouGqg9uiWGmmjETdm32Sx.png", - "tags": [ - "wrapped", - "wormhole", - "saber-mkt-ftt", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv", - "serumV3Usdt": "BoHojHESAv4McZx9gXd1bWTZMq25JYyGz4qL1m5C3nvk", - "serumV3Usdc": "2wteg25ch227n4Rh1CN4WNrDZXBpRBpWJ48mEC2K7f4r", - "coingeckoId": "ftx-token", - "source": "wormhole-v2", - "address": "0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "currency": "FTT", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "website": "https://app.saber.so", - "underlyingTokens": ["EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv"] - } - } - ], - "tokenIcons": [ - { - "name": "Wrapped FTT (Allbridge from Ethereum)", - "symbol": "aeFTT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BFsCwfk8VsEbSfLkkgmoKsAPk2N6FMJjeTsuxfGa9VEf.png", - "decimals": 9, - "address": "BFsCwfk8VsEbSfLkkgmoKsAPk2N6FMJjeTsuxfGa9VEf", - "chainId": 101, - "tags": ["saber-mkt-ftt"], - "extensions": { - "coingeckoId": "ftx-token", - "source": "allbridge", - "currency": "FTT", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "Saber Wrapped FTX Token (Wormhole) (9 decimals)", - "address": "FTT9GrHBVHvDeUTgLU8FxVJouGqg9uiWGmmjETdm32Sx", - "decimals": 9, - "symbol": "sFTT-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FTT9GrHBVHvDeUTgLU8FxVJouGqg9uiWGmmjETdm32Sx.png", - "tags": [ - "wrapped", - "wormhole", - "saber-mkt-ftt", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv", - "serumV3Usdt": "BoHojHESAv4McZx9gXd1bWTZMq25JYyGz4qL1m5C3nvk", - "serumV3Usdc": "2wteg25ch227n4Rh1CN4WNrDZXBpRBpWJ48mEC2K7f4r", - "coingeckoId": "ftx-token", - "source": "wormhole-v2", - "address": "0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "currency": "FTT", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "website": "https://app.saber.so", - "underlyingTokens": ["EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv"] - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped FTT (Allbridge from Ethereum)", - "symbol": "aeFTT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BFsCwfk8VsEbSfLkkgmoKsAPk2N6FMJjeTsuxfGa9VEf.png", - "decimals": 9, - "address": "BFsCwfk8VsEbSfLkkgmoKsAPk2N6FMJjeTsuxfGa9VEf", - "chainId": 101, - "tags": ["saber-mkt-ftt"], - "extensions": { - "coingeckoId": "ftx-token", - "source": "allbridge", - "currency": "FTT", - "sourceUrl": "https://app.allbridge.io/bridge" - } - }, - { - "name": "FTX Token (Wormhole)", - "symbol": "FTT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv.png", - "decimals": 8, - "address": "EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-ftt", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "serumV3Usdt": "BoHojHESAv4McZx9gXd1bWTZMq25JYyGz4qL1m5C3nvk", - "serumV3Usdc": "2wteg25ch227n4Rh1CN4WNrDZXBpRBpWJ48mEC2K7f4r", - "coingeckoId": "ftx-token", - "source": "wormhole-v2", - "address": "0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "currency": "FTT", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "currency": "FTT", - "lpToken": { - "symbol": "aeFTT-FTT", - "name": "Saber aeFTT-FTT LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/FTXjwjwWqituSXEHnL5VF1mjDhZoAyJqvHiRPsRq3KWK.png", - "decimals": 9, - "address": "FTXjwjwWqituSXEHnL5VF1mjDhZoAyJqvHiRPsRq3KWK", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"], - "extensions": { - "website": "https://app.saber.so/pools/wftt", - "underlyingTokens": [ - "BFsCwfk8VsEbSfLkkgmoKsAPk2N6FMJjeTsuxfGa9VEf", - "FTT9GrHBVHvDeUTgLU8FxVJouGqg9uiWGmmjETdm32Sx" - ], - "source": "saber" - } - }, - "plotKey": "5EvyWjr7gd89AA5TfzMzZ7bxyhVcY21nwrewFu1CefXJ", - "swap": { - "config": { - "swapAccount": "TSMUBiuZXEpnqd6X21JRskACqA6oad7MsYddvLbxwDH", - "authority": "EUVmhYUvcyv4kzRE5heLtsPQWVX47RqGPeX2VMNwVSua", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "FTXjwjwWqituSXEHnL5VF1mjDhZoAyJqvHiRPsRq3KWK", - "adminAccount": "G9zHTbCCvACLoVkrNrXc4hL6AqQUaSvwUQQLWJ89Ptyn", - "tokenA": { - "adminFeeAccount": "5ffp9o3HssDVgcA4w2a7JToFHwQyiq1QyZP8u9BihnaF", - "mint": "BFsCwfk8VsEbSfLkkgmoKsAPk2N6FMJjeTsuxfGa9VEf", - "reserve": "CyFL8noR6CKMFBjZPziSmChCKJE1Jtg4hQyMhgWPgH84" - }, - "tokenB": { - "adminFeeAccount": "9v7LGaDkyiP3TwF6yuUvnVKS6YbtPkUDh7pDHLpvMWj4", - "mint": "FTT9GrHBVHvDeUTgLU8FxVJouGqg9uiWGmmjETdm32Sx", - "reserve": "5PfKQpBWUayFWSSkwjp1PLr8LiHBrvVB81qfnSP5Dvkb" - }, - "initialAmpFactor": "03e8", - "targetAmpFactor": "03e8", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "2o1fDM9y6BbrwfaTxE7MaXxescKm5QeAeknrWscHprNG" - }, - { - "id": "whbtc", - "name": "HBTC-renBTC", - "tokens": [ - { - "name": "Huobi BTC (Wormhole)", - "symbol": "HBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7dVH61ChzgmN9BwG4PkzwRP8PbYwPJ7ZPNF2vamKT2H8.png", - "decimals": 8, - "address": "7dVH61ChzgmN9BwG4PkzwRP8PbYwPJ7ZPNF2vamKT2H8", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-btc", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x0316eb71485b0ab14103307bf65a021042c6d380", - "coingeckoId": "huobi-btc", - "source": "wormhole-v2", - "address": "0x0316eb71485b0ab14103307bf65a021042c6d380", - "currency": "BTC", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "renBTC", - "symbol": "renBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5.png", - "decimals": 8, - "address": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "website": "https://renproject.io/", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint" - } - } - ], - "tokenIcons": [ - { - "name": "Huobi BTC (Wormhole)", - "symbol": "HBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7dVH61ChzgmN9BwG4PkzwRP8PbYwPJ7ZPNF2vamKT2H8.png", - "decimals": 8, - "address": "7dVH61ChzgmN9BwG4PkzwRP8PbYwPJ7ZPNF2vamKT2H8", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-btc", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x0316eb71485b0ab14103307bf65a021042c6d380", - "coingeckoId": "huobi-btc", - "source": "wormhole-v2", - "address": "0x0316eb71485b0ab14103307bf65a021042c6d380", - "currency": "BTC", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "renBTC", - "symbol": "renBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5.png", - "decimals": 8, - "address": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "website": "https://renproject.io/", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint" - } - } - ], - "underlyingIcons": [ - { - "name": "Huobi BTC (Wormhole)", - "symbol": "HBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7dVH61ChzgmN9BwG4PkzwRP8PbYwPJ7ZPNF2vamKT2H8.png", - "decimals": 8, - "address": "7dVH61ChzgmN9BwG4PkzwRP8PbYwPJ7ZPNF2vamKT2H8", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-btc", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x0316eb71485b0ab14103307bf65a021042c6d380", - "coingeckoId": "huobi-btc", - "source": "wormhole-v2", - "address": "0x0316eb71485b0ab14103307bf65a021042c6d380", - "currency": "BTC", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "renBTC", - "symbol": "renBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5.png", - "decimals": 8, - "address": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "website": "https://renproject.io/", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint" - } - } - ], - "currency": "BTC", - "lpToken": { - "symbol": "HBTC-renBTC", - "name": "Saber HBTC-renBTC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/WLP9zHZ3FcsPAcM891AQBn4ZWyS3wYgddiLPbSyzmDm.png", - "decimals": 8, - "address": "WLP9zHZ3FcsPAcM891AQBn4ZWyS3wYgddiLPbSyzmDm", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"], - "extensions": { - "website": "https://app.saber.so/pools/whbtc", - "underlyingTokens": [ - "7dVH61ChzgmN9BwG4PkzwRP8PbYwPJ7ZPNF2vamKT2H8", - "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5" - ], - "source": "saber" - } - }, - "plotKey": "5keVqD7HGVUze1oN8NT91gQdyMAT3U9YSNeNx1oPTFo6", - "swap": { - "config": { - "swapAccount": "BTCkjETHaKDoRJtD2PKwzhseFnwPVsxGFu6BD8h5Riwq", - "authority": "4LQnTsjNyKbKEqDUC8EFriiDy8QQJ15giH2wDJX6kwSC", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "WLP9zHZ3FcsPAcM891AQBn4ZWyS3wYgddiLPbSyzmDm", - "adminAccount": "EPXqRkDFU3555uGg7UjEwCppEbAtP173M8hBVyCv8Ew8", - "tokenA": { - "adminFeeAccount": "CV3HHVcfRqNdoodUBHyCaWzpFfwhAQsSsxSHKbScGtF5", - "mint": "7dVH61ChzgmN9BwG4PkzwRP8PbYwPJ7ZPNF2vamKT2H8", - "reserve": "59vRbFfiA5NoGvuPjDpNE399pm4yNWVH28yfSrWH6bL2" - }, - "tokenB": { - "adminFeeAccount": "GbnwxeLhanyDwdU9PGWaVVLXTo7CXVATiwS4NE9ic7yL", - "mint": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "reserve": "9nzCtRofJcFG2GuNtfAxNddGRKhqyKXA5iX6iUZXRT1w" - }, - "initialAmpFactor": "96", - "targetAmpFactor": "96", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "5iB8Ux2h9XD9pfCimkFMN9i8KnUzB9SERaAedoAaDFo4" - }, - { - "id": "wheth", - "name": "soETH-ETH", - "tokens": [ - { - "name": "Saber Wrapped Wrapped Ethereum (Sollet) (8 decimals)", - "address": "SL819j8K9FuFPL84UepVcFkEZqDUUvVzwDmJjCHySYj", - "decimals": 8, - "symbol": "ssoETH-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/SL819j8K9FuFPL84UepVcFkEZqDUUvVzwDmJjCHySYj.png", - "tags": [ - "wrapped-sollet", - "ethereum", - "saber-mkt-eth", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "serumV3Usdt": "7dLVkUfBVfCGkFhSXDCq1ukM9usathSgS716t643iFGF", - "serumV3Usdc": "4tSvZvnbyzHXLMTiFonMyxZoHmFqau1XArcRCVHLZ5gX", - "coingeckoId": "ethereum", - "source": "sollet", - "currency": "ETH", - "sourceUrl": "https://www.sollet.io/", - "website": "https://app.saber.so", - "assetContract": "2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk", - "underlyingTokens": ["2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk"] - } - }, - { - "name": "Ether (Wormhole)", - "symbol": "ETH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs.png", - "decimals": 8, - "address": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-eth", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "serumV3Usdt": "ch7kmPrtoQUSEPBggcNAvLGiMQkJagVwd3gDYfd8m7Q", - "serumV3Usdc": "8Gmi2HhZmwQPVdCwzS7CM66MGstMXPcTVHA7jF19cLZz", - "coingeckoId": "ethereum", - "source": "wormhole-v2", - "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "currency": "ETH", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "tokenIcons": [ - { - "name": "Saber Wrapped Wrapped Ethereum (Sollet) (8 decimals)", - "address": "SL819j8K9FuFPL84UepVcFkEZqDUUvVzwDmJjCHySYj", - "decimals": 8, - "symbol": "ssoETH-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/SL819j8K9FuFPL84UepVcFkEZqDUUvVzwDmJjCHySYj.png", - "tags": [ - "wrapped-sollet", - "ethereum", - "saber-mkt-eth", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "serumV3Usdt": "7dLVkUfBVfCGkFhSXDCq1ukM9usathSgS716t643iFGF", - "serumV3Usdc": "4tSvZvnbyzHXLMTiFonMyxZoHmFqau1XArcRCVHLZ5gX", - "coingeckoId": "ethereum", - "source": "sollet", - "currency": "ETH", - "sourceUrl": "https://www.sollet.io/", - "website": "https://app.saber.so", - "assetContract": "2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk", - "underlyingTokens": ["2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk"] - } - }, - { - "name": "Ether (Wormhole)", - "symbol": "ETH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs.png", - "decimals": 8, - "address": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-eth", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "serumV3Usdt": "ch7kmPrtoQUSEPBggcNAvLGiMQkJagVwd3gDYfd8m7Q", - "serumV3Usdc": "8Gmi2HhZmwQPVdCwzS7CM66MGstMXPcTVHA7jF19cLZz", - "coingeckoId": "ethereum", - "source": "wormhole-v2", - "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "currency": "ETH", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "underlyingIcons": [ - { - "name": "Wrapped Ethereum (Sollet)", - "symbol": "soETH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk.png", - "decimals": 6, - "address": "2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk", - "chainId": 101, - "tags": ["wrapped-sollet", "ethereum", "saber-mkt-eth"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "serumV3Usdt": "7dLVkUfBVfCGkFhSXDCq1ukM9usathSgS716t643iFGF", - "serumV3Usdc": "4tSvZvnbyzHXLMTiFonMyxZoHmFqau1XArcRCVHLZ5gX", - "coingeckoId": "ethereum", - "source": "sollet", - "currency": "ETH", - "sourceUrl": "https://www.sollet.io/" - } - }, - { - "name": "Ether (Wormhole)", - "symbol": "ETH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs.png", - "decimals": 8, - "address": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-eth", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "serumV3Usdt": "ch7kmPrtoQUSEPBggcNAvLGiMQkJagVwd3gDYfd8m7Q", - "serumV3Usdc": "8Gmi2HhZmwQPVdCwzS7CM66MGstMXPcTVHA7jF19cLZz", - "coingeckoId": "ethereum", - "source": "wormhole-v2", - "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "currency": "ETH", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "currency": "ETH", - "lpToken": { - "symbol": "soETH-ETH", - "name": "Saber soETH-ETH LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/WTHPuMavN9HBvgUafjrL65WqQytQHDwnTAmdFB9whXA.png", - "decimals": 8, - "address": "WTHPuMavN9HBvgUafjrL65WqQytQHDwnTAmdFB9whXA", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"], - "extensions": { - "website": "https://app.saber.so/pools/wheth", - "underlyingTokens": [ - "SL819j8K9FuFPL84UepVcFkEZqDUUvVzwDmJjCHySYj", - "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs" - ], - "source": "saber" - } - }, - "plotKey": "ZRzURa4wGCcwaFmuaeB2tRL2tMMQ5epfpcq9HjJK27E", - "swap": { - "config": { - "swapAccount": "wrmcMSHFi3sWpAEy4rGDvQb3ezh3PhXoV2xNjgLBkKU", - "authority": "2ctAWUAM4FUWp3iaHC5kEGktx4ThtC4tfnUEXQzxjFKm", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "WTHPuMavN9HBvgUafjrL65WqQytQHDwnTAmdFB9whXA", - "adminAccount": "GzCzKSPVYtzyH1jvYmx9eZJRMcBE4SEa4VtNC7YQxfQ4", - "tokenA": { - "adminFeeAccount": "4H6rgXCXBZQ1Zy7pjmc8D6ZAWNFMSY82ZK3p4JTDE73r", - "mint": "SL819j8K9FuFPL84UepVcFkEZqDUUvVzwDmJjCHySYj", - "reserve": "8p4mGnARWPBu6P2Gcw4adodLkNDorrXniZMhaY7eJXUn" - }, - "tokenB": { - "adminFeeAccount": "6x4neovpdTXeg9uEWNmuaqThMAmAmavfT8K4teV68P3T", - "mint": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "reserve": "AyY89zccbsgp9LKFgH4CFZMJmpSgqmPSdTfukhP227rc" - }, - "initialAmpFactor": "03e8", - "targetAmpFactor": "03e8", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "4acW2PzwAxoZLSxj6w33Wvn2Af79bwCdJLdJGPY6HD3x" - }, - { - "id": "whusd", - "name": "HUSD-USDC", - "tokens": [ - { - "name": "HUSD (Wormhole)", - "symbol": "HUSD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7VQo3HFLNH5QqGtM8eC3XQbPkJUu7nS9LeGWjerRh5Sw.png", - "decimals": 8, - "address": "7VQo3HFLNH5QqGtM8eC3XQbPkJUu7nS9LeGWjerRh5Sw", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0xdf574c24545e5ffecb9a659c229253d4111d87e1", - "coingeckoId": "husd", - "source": "wormhole-v2", - "address": "0xdf574c24545e5ffecb9a659c229253d4111d87e1", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Saber Wrapped USD Coin (8 decimals)", - "address": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "decimals": 8, - "symbol": "sUSDC-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "HUSD (Wormhole)", - "symbol": "HUSD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7VQo3HFLNH5QqGtM8eC3XQbPkJUu7nS9LeGWjerRh5Sw.png", - "decimals": 8, - "address": "7VQo3HFLNH5QqGtM8eC3XQbPkJUu7nS9LeGWjerRh5Sw", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0xdf574c24545e5ffecb9a659c229253d4111d87e1", - "coingeckoId": "husd", - "source": "wormhole-v2", - "address": "0xdf574c24545e5ffecb9a659c229253d4111d87e1", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Saber Wrapped USD Coin (8 decimals)", - "address": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "decimals": 8, - "symbol": "sUSDC-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "HUSD (Wormhole)", - "symbol": "HUSD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7VQo3HFLNH5QqGtM8eC3XQbPkJUu7nS9LeGWjerRh5Sw.png", - "decimals": 8, - "address": "7VQo3HFLNH5QqGtM8eC3XQbPkJUu7nS9LeGWjerRh5Sw", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0xdf574c24545e5ffecb9a659c229253d4111d87e1", - "coingeckoId": "husd", - "source": "wormhole-v2", - "address": "0xdf574c24545e5ffecb9a659c229253d4111d87e1", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "HUSD-USDC", - "name": "Saber HUSD-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/HUSzWddUQbavKn24cjozm65eps8rq9yhNn5edtTLWfdz.png", - "decimals": 8, - "address": "HUSzWddUQbavKn24cjozm65eps8rq9yhNn5edtTLWfdz", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"], - "extensions": { - "website": "https://app.saber.so/pools/whusd", - "underlyingTokens": [ - "7VQo3HFLNH5QqGtM8eC3XQbPkJUu7nS9LeGWjerRh5Sw", - "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy" - ], - "source": "saber" - } - }, - "plotKey": "BAeacYdQ9NDWqu4KbzYzTELZSEChg8J7FVVhtC7tSAaS", - "swap": { - "config": { - "swapAccount": "HuonfMR5ivyhX5BZBw2Lr3XuNPSTVrSmZMWgBZrMQJU2", - "authority": "Ah5zHaE8fA8GJCopa9jaCmxG8AVUtf7ae7V8znSFURAd", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "HUSzWddUQbavKn24cjozm65eps8rq9yhNn5edtTLWfdz", - "adminAccount": "EJejTQuhZFwpU2DwUqBrvA2xNQJaVA5zCHLfSdDebBGv", - "tokenA": { - "adminFeeAccount": "6gj8TSCL7EB8kwGuHdVKce1jpJusvC4gfEf5Ctwo6CMv", - "mint": "7VQo3HFLNH5QqGtM8eC3XQbPkJUu7nS9LeGWjerRh5Sw", - "reserve": "E7L8CZxreEeNwM1V8DLxa8AZQKu6oday6RvXxRo27CHi" - }, - "tokenB": { - "adminFeeAccount": "AXdMwMKAu7kqNUmaUHCytiy3gfP9qEUjLtXn8LAkHENK", - "mint": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "reserve": "48UJw19Ra8y5Kv989DsXPrfUHeUWUbHvXZmdPBbGuHdz" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "41CPKcrV6XAJ7943hN7X9znsSaiN1DEGJNEncSA3hAPw" - }, - { - "id": "wibbtc", - "name": "wibBTC-renBTC", - "tokens": [ - { - "symbol": "wibBTC", - "name": "ibBTC (Wormhole)", - "logoURI": "https://registry.saber.so/token-icons/ibbtc.svg", - "address": "Bzq68gAVedKqQkQbsM28yQ4LYpc2VComDUD9wJBywdTi", - "decimals": 8, - "extensions": { - "coingeckoId": "bitcoin", - "source": "wormhole-v2", - "currency": "BTC", - "sourceUrl": "https://wormholebridge.com/#/transfer" - }, - "chainId": 101, - "tags": ["saber-mkt-btc", "wormhole-v2"] - }, - { - "name": "renBTC", - "symbol": "renBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5.png", - "decimals": 8, - "address": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "website": "https://renproject.io/", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint" - } - } - ], - "tokenIcons": [ - { - "symbol": "wibBTC", - "name": "ibBTC (Wormhole)", - "logoURI": "https://registry.saber.so/token-icons/ibbtc.svg", - "address": "Bzq68gAVedKqQkQbsM28yQ4LYpc2VComDUD9wJBywdTi", - "decimals": 8, - "extensions": { - "coingeckoId": "bitcoin", - "source": "wormhole-v2", - "currency": "BTC", - "sourceUrl": "https://wormholebridge.com/#/transfer" - }, - "chainId": 101, - "tags": ["saber-mkt-btc", "wormhole-v2"] - }, - { - "name": "renBTC", - "symbol": "renBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5.png", - "decimals": 8, - "address": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "website": "https://renproject.io/", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint" - } - } - ], - "underlyingIcons": [ - { - "symbol": "wibBTC", - "name": "ibBTC (Wormhole)", - "logoURI": "https://registry.saber.so/token-icons/ibbtc.svg", - "address": "Bzq68gAVedKqQkQbsM28yQ4LYpc2VComDUD9wJBywdTi", - "decimals": 8, - "extensions": { - "coingeckoId": "bitcoin", - "source": "wormhole-v2", - "currency": "BTC", - "sourceUrl": "https://wormholebridge.com/#/transfer" - }, - "chainId": 101, - "tags": ["saber-mkt-btc", "wormhole-v2"] - }, - { - "name": "renBTC", - "symbol": "renBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5.png", - "decimals": 8, - "address": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "website": "https://renproject.io/", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint" - } - } - ], - "currency": "BTC", - "lpToken": { - "symbol": "wibBTC-renBTC", - "name": "Saber wibBTC-renBTC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/WLP9nwD2FUJyNeKWGEi8QnF1a5G3VC7zM9uCqE1W8tx.png", - "decimals": 8, - "address": "WLP9nwD2FUJyNeKWGEi8QnF1a5G3VC7zM9uCqE1W8tx", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"], - "extensions": { - "website": "https://app.saber.so/pools/wibbtc", - "underlyingTokens": [ - "Bzq68gAVedKqQkQbsM28yQ4LYpc2VComDUD9wJBywdTi", - "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5" - ], - "source": "saber" - } - }, - "plotKey": "3K7gykUDa34q1AMvmGVzbKn9shpPyUM1pC9zohyo8CUz", - "swap": { - "config": { - "swapAccount": "BDGpYPUKFyHzHTnbK21v66tACEVHSmRXf4LWnMqYmfEN", - "authority": "8ea2TgjGzY51QjATM9xTF5bw43uMdtyFWm8E4PTKsCXA", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "WLP9nwD2FUJyNeKWGEi8QnF1a5G3VC7zM9uCqE1W8tx", - "adminAccount": "ZfSC29nsrx9mqzuPXWuiqp9enHcMDFPcMXuxwoQXQC4", - "tokenA": { - "adminFeeAccount": "8F7ZWtL4yDmeyqbm6biaQdvMPt8vxtrBkxppUW1LM6w1", - "mint": "Bzq68gAVedKqQkQbsM28yQ4LYpc2VComDUD9wJBywdTi", - "reserve": "mp5HMG9jYnZvpe3cV1qgPzfX5aPtLQtsMjVTazvkQ28" - }, - "tokenB": { - "adminFeeAccount": "5ZW1S437vktV9uBpC5rjQroyuZ641HjaJzzBxNjj2ETo", - "mint": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "reserve": "DwDfm1YMtHT5WQLxfQdnh3WYzUHjwEviHFwDs3RBEm1B" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "AVFD1KFfbG1sc7ExxqLHaSJKbDCA6PMkUgGPovD21Dbe" - }, - { - "id": "wluna", - "name": "LUNA-renLUNA", - "tokens": [ - { - "name": "LUNA (Wormhole)", - "symbol": "LUNA", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W.png", - "decimals": 6, - "address": "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-luna", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "HBTu8hNaoT3VyiSSzJYa8jwt9sDGKtJviSwFa11iXdmE", - "coingeckoId": "terra-luna", - "source": "wormhole-v2", - "address": "uluna", - "currency": "LUNA", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "renLUNA", - "symbol": "renLUNA", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE.png", - "decimals": 6, - "address": "8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE", - "chainId": 101, - "tags": ["saber-mkt-luna"], - "extensions": { - "website": "https://renproject.io/", - "serumV3Usdc": "CxDhLbbM9uAA2AXfSPar5qmyfmC69NLj3vgJXYAsSVBT", - "coingeckoId": "terra-luna", - "source": "renbridge", - "currency": "LUNA", - "sourceUrl": "https://bridge.renproject.io/mint" - } - } - ], - "tokenIcons": [ - { - "name": "LUNA (Wormhole)", - "symbol": "LUNA", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W.png", - "decimals": 6, - "address": "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-luna", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "HBTu8hNaoT3VyiSSzJYa8jwt9sDGKtJviSwFa11iXdmE", - "coingeckoId": "terra-luna", - "source": "wormhole-v2", - "address": "uluna", - "currency": "LUNA", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "renLUNA", - "symbol": "renLUNA", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE.png", - "decimals": 6, - "address": "8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE", - "chainId": 101, - "tags": ["saber-mkt-luna"], - "extensions": { - "website": "https://renproject.io/", - "serumV3Usdc": "CxDhLbbM9uAA2AXfSPar5qmyfmC69NLj3vgJXYAsSVBT", - "coingeckoId": "terra-luna", - "source": "renbridge", - "currency": "LUNA", - "sourceUrl": "https://bridge.renproject.io/mint" - } - } - ], - "underlyingIcons": [ - { - "name": "LUNA (Wormhole)", - "symbol": "LUNA", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W.png", - "decimals": 6, - "address": "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-luna", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "HBTu8hNaoT3VyiSSzJYa8jwt9sDGKtJviSwFa11iXdmE", - "coingeckoId": "terra-luna", - "source": "wormhole-v2", - "address": "uluna", - "currency": "LUNA", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "renLUNA", - "symbol": "renLUNA", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE.png", - "decimals": 6, - "address": "8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE", - "chainId": 101, - "tags": ["saber-mkt-luna"], - "extensions": { - "website": "https://renproject.io/", - "serumV3Usdc": "CxDhLbbM9uAA2AXfSPar5qmyfmC69NLj3vgJXYAsSVBT", - "coingeckoId": "terra-luna", - "source": "renbridge", - "currency": "LUNA", - "sourceUrl": "https://bridge.renproject.io/mint" - } - } - ], - "currency": "LUNA", - "lpToken": { - "symbol": "LUNA-renLUNA", - "name": "Saber LUNA-renLUNA LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/LUN1p1dZwSBgTv1JSdn2apdUuLanHKtgNcnpDydVFTU.png", - "decimals": 6, - "address": "LUN1p1dZwSBgTv1JSdn2apdUuLanHKtgNcnpDydVFTU", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"], - "extensions": { - "website": "https://app.saber.so/pools/wluna", - "underlyingTokens": [ - "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W", - "8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE" - ], - "source": "saber" - } - }, - "plotKey": "5zrQomindJeKFw37hm6xME1FU3teBXeUmmAiVVtiXafk", - "swap": { - "config": { - "swapAccount": "Joji2GxwqNyoXMUqi4z3P4KSSpx31nwcrxxtMSN6aey", - "authority": "ubiHGBrW6aYpYdAM4f1WVJjmiC8SAKFcG4hZe1Cksa6", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "LUN1p1dZwSBgTv1JSdn2apdUuLanHKtgNcnpDydVFTU", - "adminAccount": "6G5mVcrdGX7oK3vaUWE2Eaw7xSdnezLW2LU7wBeyUWK7", - "tokenA": { - "adminFeeAccount": "8QqZBriQpUVNcwrQbPnBUMkQxh3aJuYqpBegGUzGqH4Q", - "mint": "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W", - "reserve": "GgRnQyCm22UkHQME96CqJFpsqV93QJQsWMURdsQSSAdk" - }, - "tokenB": { - "adminFeeAccount": "6JJEkJdkjrGuuFsF5MAiZHXZrBZYzdTUaNykQprn9YBf", - "mint": "8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE", - "reserve": "GrWSq33By3uf7Vqqfrscy7oJMuqGgZojd2KSzsxioxQL" - }, - "initialAmpFactor": "03e8", - "targetAmpFactor": "03e8", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "7DyHgSJ2KvjjreNFefeWxkPe8oucwbdtSb8LkjkVTarx" - }, - { - "id": "wpusdc", - "name": "USDCpo-USDC", - "tokens": [ - { - "name": "USD Coin (Wormhole from Polygon)", - "symbol": "USDCpo", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/E2VmbootbVCBkMNNxKQgCLMS1X3NoGMaYAsufaAsf7M.png", - "decimals": 6, - "address": "E2VmbootbVCBkMNNxKQgCLMS1X3NoGMaYAsufaAsf7M", - "chainId": 101, - "tags": ["wrapped", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://polygonscan.com/address/0x5a58505a96d1dbf8df91cb21b54419fc36e93fde", - "assetContract": "https://polygonscan.com/token/0x2791bca1f2de4661ed88a30c99a7a9449aa84174", - "coingeckoId": "usd-coin", - "source": "wormhole-v2", - "address": "0x2791bca1f2de4661ed88a30c99a7a9449aa84174", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "tokenIcons": [ - { - "name": "USD Coin (Wormhole from Polygon)", - "symbol": "USDCpo", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/E2VmbootbVCBkMNNxKQgCLMS1X3NoGMaYAsufaAsf7M.png", - "decimals": 6, - "address": "E2VmbootbVCBkMNNxKQgCLMS1X3NoGMaYAsufaAsf7M", - "chainId": 101, - "tags": ["wrapped", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://polygonscan.com/address/0x5a58505a96d1dbf8df91cb21b54419fc36e93fde", - "assetContract": "https://polygonscan.com/token/0x2791bca1f2de4661ed88a30c99a7a9449aa84174", - "coingeckoId": "usd-coin", - "source": "wormhole-v2", - "address": "0x2791bca1f2de4661ed88a30c99a7a9449aa84174", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "underlyingIcons": [ - { - "name": "USD Coin (Wormhole from Polygon)", - "symbol": "USDCpo", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/E2VmbootbVCBkMNNxKQgCLMS1X3NoGMaYAsufaAsf7M.png", - "decimals": 6, - "address": "E2VmbootbVCBkMNNxKQgCLMS1X3NoGMaYAsufaAsf7M", - "chainId": 101, - "tags": ["wrapped", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://polygonscan.com/address/0x5a58505a96d1dbf8df91cb21b54419fc36e93fde", - "assetContract": "https://polygonscan.com/token/0x2791bca1f2de4661ed88a30c99a7a9449aa84174", - "coingeckoId": "usd-coin", - "source": "wormhole-v2", - "address": "0x2791bca1f2de4661ed88a30c99a7a9449aa84174", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "USDCpo-USDC", - "name": "Saber USDCpo-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/WLPyXq7WRfdWLiP4fvRfSisrfDzLiPmCeVTE6okKQWE.png", - "decimals": 6, - "address": "WLPyXq7WRfdWLiP4fvRfSisrfDzLiPmCeVTE6okKQWE", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"], - "extensions": { - "website": "https://app.saber.so/pools/wpusdc", - "underlyingTokens": [ - "E2VmbootbVCBkMNNxKQgCLMS1X3NoGMaYAsufaAsf7M", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "source": "saber" - } - }, - "plotKey": "7dLiHbGVjBtyJwNJurYc5q6Hih82pTN9ghmivNUcCWch", - "swap": { - "config": { - "swapAccount": "MATgk4zXLXtYkwBH678J1xZbRDZ45LicNzkRBHkxTuY", - "authority": "F6JFfyWaKTZY94rRzR5ftrtEKBS7aNLu1vYQiKuYhTZ6", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "WLPyXq7WRfdWLiP4fvRfSisrfDzLiPmCeVTE6okKQWE", - "adminAccount": "DteVE2iRGB5YMqmmwHTEQo8vx4feAhnKQCoQpLPpceww", - "tokenA": { - "adminFeeAccount": "AtwPjP6NAzS74FzrnYY6vvDmrsQeEvXQ6dGR8gRL1b7w", - "mint": "E2VmbootbVCBkMNNxKQgCLMS1X3NoGMaYAsufaAsf7M", - "reserve": "y8dALFo1bJrSzPYjMX14HJX448pXqYmrfXHD1K8MXih" - }, - "tokenB": { - "adminFeeAccount": "GMUhSqF5wSjH1YZpgF782ZW1rkjBKQTy8KwQ1ApxCe2V", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "reserve": "GN7Yuet3UyiWS5YVkEHv6oQKi4HGBJc3XDPt9zQhAqZz" - }, - "initialAmpFactor": "012c", - "targetAmpFactor": "012c", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "Hutnp9RAkAaam3SGorHCjzYghrATZ9gkQTWdJ51QgXv" - }, - { - "id": "wpusdt", - "name": "USDTpo-USDT", - "tokens": [ - { - "name": "Tether USD (Wormhole from Polygon)", - "symbol": "USDTpo", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/5goWRao6a3yNC4d6UjMdQxonkCMvKBwdpubU3qhfcdf1.png", - "decimals": 6, - "address": "5goWRao6a3yNC4d6UjMdQxonkCMvKBwdpubU3qhfcdf1", - "chainId": 101, - "tags": ["wrapped", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://polygonscan.com/address/0x5a58505a96d1dbf8df91cb21b54419fc36e93fde", - "assetContract": "https://polygonscan.com/token/0xc2132d05d31c914a87c6611c10748aeb04b58e8f", - "coingeckoId": "tether", - "source": "wormhole-v2", - "address": "0xc2132d05d31c914a87c6611c10748aeb04b58e8f", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "USDT", - "symbol": "USDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB.svg", - "decimals": 6, - "address": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://tether.to/", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD" - } - } - ], - "tokenIcons": [ - { - "name": "Tether USD (Wormhole from Polygon)", - "symbol": "USDTpo", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/5goWRao6a3yNC4d6UjMdQxonkCMvKBwdpubU3qhfcdf1.png", - "decimals": 6, - "address": "5goWRao6a3yNC4d6UjMdQxonkCMvKBwdpubU3qhfcdf1", - "chainId": 101, - "tags": ["wrapped", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://polygonscan.com/address/0x5a58505a96d1dbf8df91cb21b54419fc36e93fde", - "assetContract": "https://polygonscan.com/token/0xc2132d05d31c914a87c6611c10748aeb04b58e8f", - "coingeckoId": "tether", - "source": "wormhole-v2", - "address": "0xc2132d05d31c914a87c6611c10748aeb04b58e8f", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "USDT", - "symbol": "USDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB.svg", - "decimals": 6, - "address": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://tether.to/", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD" - } - } - ], - "underlyingIcons": [ - { - "name": "Tether USD (Wormhole from Polygon)", - "symbol": "USDTpo", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/5goWRao6a3yNC4d6UjMdQxonkCMvKBwdpubU3qhfcdf1.png", - "decimals": 6, - "address": "5goWRao6a3yNC4d6UjMdQxonkCMvKBwdpubU3qhfcdf1", - "chainId": 101, - "tags": ["wrapped", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://polygonscan.com/address/0x5a58505a96d1dbf8df91cb21b54419fc36e93fde", - "assetContract": "https://polygonscan.com/token/0xc2132d05d31c914a87c6611c10748aeb04b58e8f", - "coingeckoId": "tether", - "source": "wormhole-v2", - "address": "0xc2132d05d31c914a87c6611c10748aeb04b58e8f", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "USDT", - "symbol": "USDT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB.svg", - "decimals": 6, - "address": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://tether.to/", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "tether", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "USDTpo-USDT", - "name": "Saber USDTpo-USDT LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/WLP59xUDvQMQdzC2SgPmZeRF1oj2RSvGZiQLksj4bwj.png", - "decimals": 6, - "address": "WLP59xUDvQMQdzC2SgPmZeRF1oj2RSvGZiQLksj4bwj", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"], - "extensions": { - "website": "https://app.saber.so/pools/wpusdt", - "underlyingTokens": [ - "5goWRao6a3yNC4d6UjMdQxonkCMvKBwdpubU3qhfcdf1", - "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" - ], - "source": "saber" - } - }, - "plotKey": "96Po9LAEjyprFBeNzwF1JkwbfJCwbHADtJi6DA3avz4M", - "swap": { - "config": { - "swapAccount": "MATSnbbiTCv7Dc3trJrkrqjx7ckKdr6fwPoVwv9q3sD", - "authority": "24nNLHx6HJutEJ27qQ6X4cKfXiDUpQPaKYEkfAYtEkW5", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "WLP59xUDvQMQdzC2SgPmZeRF1oj2RSvGZiQLksj4bwj", - "adminAccount": "E5zkqarRb558H8eBvYzHVY71qV9squp84KdVQFN8bZVr", - "tokenA": { - "adminFeeAccount": "GrFuffzk2QuPzAk57LMm3Ayn8dTuoqnQpiprx7rRDDVW", - "mint": "5goWRao6a3yNC4d6UjMdQxonkCMvKBwdpubU3qhfcdf1", - "reserve": "631WX9JizSHJm4w6VanZeJAst9T8DeUUnPLesdGkCVtK" - }, - "tokenB": { - "adminFeeAccount": "DromwU5YLyty6dzAnSrhrAe2xq7Pc1bkTWDTcrBV8agd", - "mint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "reserve": "211maUSfpnXbPuW1iBu8b4dtJv5EbN1j7JJiEX5TZKEP" - }, - "initialAmpFactor": "012c", - "targetAmpFactor": "012c", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "ECbsUoB8LfzqwNe3zA3hNrvR7WX1vJRiMcL9sMsb92BE" - }, - { - "id": "wsrm", - "name": "SRMet-SRM", - "tokens": [ - { - "name": "Serum (Wormhole from Ethereum)", - "symbol": "SRMet", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG.png", - "decimals": 6, - "address": "xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-srm", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x476c5e26a75bd202a9683ffd34359c0cc15be0ff", - "coingeckoId": "serum", - "source": "wormhole-v2", - "address": "0x476c5e26a75bd202a9683ffd34359c0cc15be0ff", - "currency": "SRM", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Serum", - "symbol": "SRM", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt.png", - "decimals": 6, - "address": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "chainId": 101, - "tags": ["saber-mkt-srm"], - "extensions": { - "website": "https://projectserum.com/", - "serumV3Usdt": "AtNnsY1AyRERWJ8xCskfz38YdvruWVJQUVXgScC1iPb", - "serumV3Usdc": "ByRys5tuUWDgL73G8JBAEfkdFf8JWBzPBDHsBVQ5vbQA", - "coingeckoId": "serum", - "currency": "SRM", - "waterfallbot": "https://bit.ly/SRMwaterfall" - } - } - ], - "tokenIcons": [ - { - "name": "Serum (Wormhole from Ethereum)", - "symbol": "SRMet", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG.png", - "decimals": 6, - "address": "xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-srm", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x476c5e26a75bd202a9683ffd34359c0cc15be0ff", - "coingeckoId": "serum", - "source": "wormhole-v2", - "address": "0x476c5e26a75bd202a9683ffd34359c0cc15be0ff", - "currency": "SRM", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Serum", - "symbol": "SRM", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt.png", - "decimals": 6, - "address": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "chainId": 101, - "tags": ["saber-mkt-srm"], - "extensions": { - "website": "https://projectserum.com/", - "serumV3Usdt": "AtNnsY1AyRERWJ8xCskfz38YdvruWVJQUVXgScC1iPb", - "serumV3Usdc": "ByRys5tuUWDgL73G8JBAEfkdFf8JWBzPBDHsBVQ5vbQA", - "coingeckoId": "serum", - "currency": "SRM", - "waterfallbot": "https://bit.ly/SRMwaterfall" - } - } - ], - "underlyingIcons": [ - { - "name": "Serum (Wormhole from Ethereum)", - "symbol": "SRMet", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG.png", - "decimals": 6, - "address": "xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-srm", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x476c5e26a75bd202a9683ffd34359c0cc15be0ff", - "coingeckoId": "serum", - "source": "wormhole-v2", - "address": "0x476c5e26a75bd202a9683ffd34359c0cc15be0ff", - "currency": "SRM", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Serum", - "symbol": "SRM", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt.png", - "decimals": 6, - "address": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "chainId": 101, - "tags": ["saber-mkt-srm"], - "extensions": { - "website": "https://projectserum.com/", - "serumV3Usdt": "AtNnsY1AyRERWJ8xCskfz38YdvruWVJQUVXgScC1iPb", - "serumV3Usdc": "ByRys5tuUWDgL73G8JBAEfkdFf8JWBzPBDHsBVQ5vbQA", - "coingeckoId": "serum", - "currency": "SRM", - "waterfallbot": "https://bit.ly/SRMwaterfall" - } - } - ], - "currency": "SRM", - "lpToken": { - "symbol": "SRMet-SRM", - "name": "Saber SRMet-SRM LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/WLP7MDjSKGWxs2s6o2d8JFvvqLJD8KHZpcTAZf9ongE.png", - "decimals": 6, - "address": "WLP7MDjSKGWxs2s6o2d8JFvvqLJD8KHZpcTAZf9ongE", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"], - "extensions": { - "website": "https://app.saber.so/pools/wsrm", - "underlyingTokens": [ - "xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG", - "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt" - ], - "source": "saber" - } - }, - "plotKey": "E5V5xnJxkKSbA6CXF6DErEHfpFe8aJs57CYPUPy2RWsz", - "swap": { - "config": { - "swapAccount": "SRMuKizofcAMicegrfSv7xs9q76tH1w8aAF7oX9FEWu", - "authority": "4VN6BM8qUa746raafkRvqwQFKYLPSAC1voCcEVHEKZBd", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 253, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "WLP7MDjSKGWxs2s6o2d8JFvvqLJD8KHZpcTAZf9ongE", - "adminAccount": "EEy2D2J4582r3WBU1HB4kAPyDKpLEzkyCXJZKjJERCDP", - "tokenA": { - "adminFeeAccount": "FXfQxtk9BbpgjuqS8YRs6TDX7QzwhaPwg4GQcmwrS9aT", - "mint": "xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG", - "reserve": "72Hj2KWntXPfbie4UgKeTPnm1XVkomDfCnRPKbvfTtPi" - }, - "tokenB": { - "adminFeeAccount": "FRv4oVoLA8hDfcwVvwtRY7bPPgGK4HcTdrmLmghmgMYG", - "mint": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "reserve": "6aqJQ5wedqpUt4fFEDUqUmXhrdxCu4bEJsQdVPCADLko" - }, - "initialAmpFactor": "01f4", - "targetAmpFactor": "01f4", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "C7faBVAJad3obMyRxXn8dqbDJT7TT2A4oidKeELCMckp" - }, - { - "id": "wusdk", - "name": "USDK-USDC", - "tokens": [ - { - "name": "USDK (Wormhole)", - "symbol": "USDK", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/43m2ewFV5nDepieFjT9EmAQnc1HRtAF247RBpLGFem5F.png", - "decimals": 8, - "address": "43m2ewFV5nDepieFjT9EmAQnc1HRtAF247RBpLGFem5F", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x1c48f86ae57291f7686349f12601910bd8d470bb", - "coingeckoId": "usdk", - "source": "wormhole-v2", - "address": "0x1c48f86ae57291f7686349f12601910bd8d470bb", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Saber Wrapped USD Coin (8 decimals)", - "address": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "decimals": 8, - "symbol": "sUSDC-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "tokenIcons": [ - { - "name": "USDK (Wormhole)", - "symbol": "USDK", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/43m2ewFV5nDepieFjT9EmAQnc1HRtAF247RBpLGFem5F.png", - "decimals": 8, - "address": "43m2ewFV5nDepieFjT9EmAQnc1HRtAF247RBpLGFem5F", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x1c48f86ae57291f7686349f12601910bd8d470bb", - "coingeckoId": "usdk", - "source": "wormhole-v2", - "address": "0x1c48f86ae57291f7686349f12601910bd8d470bb", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "Saber Wrapped USD Coin (8 decimals)", - "address": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "decimals": 8, - "symbol": "sUSDC-8", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD", - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"] - } - } - ], - "underlyingIcons": [ - { - "name": "USDK (Wormhole)", - "symbol": "USDK", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/43m2ewFV5nDepieFjT9EmAQnc1HRtAF247RBpLGFem5F.png", - "decimals": 8, - "address": "43m2ewFV5nDepieFjT9EmAQnc1HRtAF247RBpLGFem5F", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x1c48f86ae57291f7686349f12601910bd8d470bb", - "coingeckoId": "usdk", - "source": "wormhole-v2", - "address": "0x1c48f86ae57291f7686349f12601910bd8d470bb", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "USDK-USDC", - "name": "Saber USDK-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/USDKKmk1anWU1aEn6GJ6skL3ZvcB9CBAWVkmPGQEHtz.png", - "decimals": 8, - "address": "USDKKmk1anWU1aEn6GJ6skL3ZvcB9CBAWVkmPGQEHtz", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"], - "extensions": { - "website": "https://app.saber.so/pools/wusdk", - "underlyingTokens": [ - "43m2ewFV5nDepieFjT9EmAQnc1HRtAF247RBpLGFem5F", - "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy" - ], - "source": "saber" - } - }, - "plotKey": "2SEWtGYG9oAPh2f51S9kW6CpXgZrVZPSbz58zske1ztU", - "swap": { - "config": { - "swapAccount": "oKQqupM9E7SSLAFDLxr7mdsXP7znck9qRbVWc6Yyj7Q", - "authority": "2pVd6wjKqvNbv5RdLoqaBGRxTMTsCKDV8jvgpYDL3AJX", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 252, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "USDKKmk1anWU1aEn6GJ6skL3ZvcB9CBAWVkmPGQEHtz", - "adminAccount": "CqU7orrGwuawCJVV2GgrddEcdoCLZrNseAdLvmocR71L", - "tokenA": { - "adminFeeAccount": "GJ2Qyeg35bzTQui9tvfbiv8Pi3BaY3KKvcWiNcHYMSBn", - "mint": "43m2ewFV5nDepieFjT9EmAQnc1HRtAF247RBpLGFem5F", - "reserve": "CMR2J7CwfW98RpvnJmFBgRFTLAd3x8CJ1SWs8Bt3uunG" - }, - "tokenB": { - "adminFeeAccount": "7Tuih3tg3YqzFBLQ7UCma8uqEASARkk1YoG9CaZd6jZW", - "mint": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "reserve": "FmRb5jHfSNj1YWP3b45d9vvYuhwjp4om8bALmtqZpr1v" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "4g9LQYZnLjvbDyzJJUtUKTdJfUeUe1j3wKKiGfXwUPJF" - }, - { - "id": "wust", - "name": "UST-USDC", - "tokens": [ - { - "name": "UST (Wormhole)", - "symbol": "UST", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i.png", - "decimals": 6, - "address": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "chainId": 101, - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "tokenIcons": [ - { - "name": "UST (Wormhole)", - "symbol": "UST", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i.png", - "decimals": 6, - "address": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "chainId": 101, - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "underlyingIcons": [ - { - "name": "UST (Wormhole)", - "symbol": "UST", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i.png", - "decimals": 6, - "address": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "chainId": 101, - "tags": [ - "wrapped", - "wormhole", - "stablecoin", - "saber-mkt-usd", - "wormhole-v2" - ], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "coingeckoId": "terrausd", - "source": "wormhole-v2", - "address": "uusd", - "currency": "USD", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "UST-USDC", - "name": "Saber UST-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/USTCmQpbUGj5iTsXdnTYHZupY1QpftDZhLokSVk6UWi.png", - "decimals": 6, - "address": "USTCmQpbUGj5iTsXdnTYHZupY1QpftDZhLokSVk6UWi", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"], - "extensions": { - "website": "https://app.saber.so/pools/wust", - "underlyingTokens": [ - "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "source": "saber" - } - }, - "plotKey": "8sNgWmTK6SZwiZ294Hiy8feFtbtRMfj2KeJzrZBcKGM4", - "swap": { - "config": { - "swapAccount": "KwnjUuZhTMTSGAaavkLEmSyfobY16JNH4poL9oeeEvE", - "authority": "9osV5a7FXEjuMujxZJGBRXVAyQ5fJfBFNkyAf6fSz9kw", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 251, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "USTCmQpbUGj5iTsXdnTYHZupY1QpftDZhLokSVk6UWi", - "adminAccount": "E6WWiXW3HzX17ecHFjXqFG32i5qwc7f1K7T4TF6kCMfc", - "tokenA": { - "adminFeeAccount": "BYgyVxdrGa3XNj1cx1XHAVyRG8qYhBnv1DS59Bsvmg5h", - "mint": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "reserve": "J63v6qEZmQpDqCD8bd4PXu2Pq5ZbyXrFcSa3Xt1HdAPQ" - }, - "tokenB": { - "adminFeeAccount": "G9nt2GazsDj3Ey3KdA49Sfaq9K95Dc72Ejps4NKTP2SR", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "reserve": "BnKQtTdLw9qPCDgZkWX3sURkBAoKCUYL1yahh6Mw7mRK" - }, - "initialAmpFactor": "c8", - "targetAmpFactor": "0190", - "startRampTimestamp": 1651113179, - "stopRampTimestamp": 1651285974, - "fees": { - "trade": { - "formatted": "0.0010000000", - "numerator": "1", - "denominator": "100000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "BYEUtsLjYAVHRiRR3Avjqnd2RQLRL8n933N52p9kSX2y" - }, - { - "id": "xbtc", - "name": "xBTC-renBTC", - "tokens": [ - { - "name": "Synthetic BTC", - "symbol": "xBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/HWxpSV3QAGzLQzGAtvhSYAEr7sTQugQygnni1gnUGh1D.svg", - "decimals": 10, - "address": "HWxpSV3QAGzLQzGAtvhSYAEr7sTQugQygnni1gnUGh1D", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "website": "https://synthetify.io/", - "twitter": "https://twitter.com/synthetify", - "coingeckoId": "bitcoin", - "source": "synthetify", - "currency": "BTC", - "sourceUrl": "https://app.synthetify.io/staking" - } - }, - { - "name": "Saber Wrapped renBTC (10 decimals)", - "address": "BtX7AfzEJLnU8KQR1AgHrhGH5s2AHUTbfjhUQP8BhPvi", - "decimals": 10, - "symbol": "srenBTC-10", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BtX7AfzEJLnU8KQR1AgHrhGH5s2AHUTbfjhUQP8BhPvi.png", - "tags": ["saber-mkt-btc", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint", - "assetContract": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "underlyingTokens": ["CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5"] - } - } - ], - "tokenIcons": [ - { - "name": "Synthetic BTC", - "symbol": "xBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/HWxpSV3QAGzLQzGAtvhSYAEr7sTQugQygnni1gnUGh1D.svg", - "decimals": 10, - "address": "HWxpSV3QAGzLQzGAtvhSYAEr7sTQugQygnni1gnUGh1D", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "website": "https://synthetify.io/", - "twitter": "https://twitter.com/synthetify", - "coingeckoId": "bitcoin", - "source": "synthetify", - "currency": "BTC", - "sourceUrl": "https://app.synthetify.io/staking" - } - }, - { - "name": "Saber Wrapped renBTC (10 decimals)", - "address": "BtX7AfzEJLnU8KQR1AgHrhGH5s2AHUTbfjhUQP8BhPvi", - "decimals": 10, - "symbol": "srenBTC-10", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BtX7AfzEJLnU8KQR1AgHrhGH5s2AHUTbfjhUQP8BhPvi.png", - "tags": ["saber-mkt-btc", "saber-dec-wrapped"], - "extensions": { - "website": "https://app.saber.so", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint", - "assetContract": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "underlyingTokens": ["CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5"] - } - } - ], - "underlyingIcons": [ - { - "name": "Synthetic BTC", - "symbol": "xBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/HWxpSV3QAGzLQzGAtvhSYAEr7sTQugQygnni1gnUGh1D.svg", - "decimals": 10, - "address": "HWxpSV3QAGzLQzGAtvhSYAEr7sTQugQygnni1gnUGh1D", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "website": "https://synthetify.io/", - "twitter": "https://twitter.com/synthetify", - "coingeckoId": "bitcoin", - "source": "synthetify", - "currency": "BTC", - "sourceUrl": "https://app.synthetify.io/staking" - } - }, - { - "name": "renBTC", - "symbol": "renBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5.png", - "decimals": 8, - "address": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "chainId": 101, - "tags": ["saber-mkt-btc"], - "extensions": { - "website": "https://renproject.io/", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "coingeckoId": "renbtc", - "source": "renbridge", - "currency": "BTC", - "sourceUrl": "https://bridge.renproject.io/mint" - } - } - ], - "currency": "BTC", - "lpToken": { - "symbol": "xBTC-renBTC", - "name": "Saber xBTC-renBTC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/xBTCPvRuEuRgz5DuuUd3ju3VP5XtR2Dsu1AxyW9JpXK.png", - "decimals": 10, - "address": "xBTCPvRuEuRgz5DuuUd3ju3VP5XtR2Dsu1AxyW9JpXK", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-synthetify"], - "extensions": { - "website": "https://app.saber.so/pools/xbtc", - "underlyingTokens": [ - "HWxpSV3QAGzLQzGAtvhSYAEr7sTQugQygnni1gnUGh1D", - "BtX7AfzEJLnU8KQR1AgHrhGH5s2AHUTbfjhUQP8BhPvi" - ], - "source": "saber" - } - }, - "plotKey": "H8PDe6QwBdLbmFbPfXe1EEEAnMgrPL2pDDmZ8W4hAfph", - "swap": { - "config": { - "swapAccount": "NorBXypYWTkV5PMs6Q9JsvNkmRwe7H9Zr1Kz2TcJH2Y", - "authority": "2AdWk8VKBkThFohdpA1RYekfvwGbUe1t12p7hv1YdQT6", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "xBTCPvRuEuRgz5DuuUd3ju3VP5XtR2Dsu1AxyW9JpXK", - "adminAccount": "DwqndCU7GEoKW7tXXp5XWP5eaiQrZ2Ft4SbxBuUPrv4J", - "tokenA": { - "adminFeeAccount": "AQFuz3pR9Lq3vyo7Aqvw8KrBcoSJHEf1Um53D7foDK3j", - "mint": "HWxpSV3QAGzLQzGAtvhSYAEr7sTQugQygnni1gnUGh1D", - "reserve": "C82XDu1d1UjtuUwnkSTwVuWyH3AqpJ3ftb9W7en8rEUu" - }, - "tokenB": { - "adminFeeAccount": "FJ5nJw6ddQxh6GJu2Mvj6JbPeSDa6WsqDtn94vxGHp43", - "mint": "BtX7AfzEJLnU8KQR1AgHrhGH5s2AHUTbfjhUQP8BhPvi", - "reserve": "F7cZoYpWQSFuYJzW2UUFw6sVbTtaihyD5upeeHRUPABk" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "GWTy8S43vAUMCQpjNV9JBp5NPNSuCyCn34wz9Roz63YF" - }, - { - "id": "xeth", - "name": "xETH-ETH", - "tokens": [ - { - "name": "Synthetic ETH", - "symbol": "xETH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/8bqjz8DeSuim1sEAsQatjJN4zseyxSPdhHQcuuhL8PCK.svg", - "decimals": 9, - "address": "8bqjz8DeSuim1sEAsQatjJN4zseyxSPdhHQcuuhL8PCK", - "chainId": 101, - "tags": ["saber-mkt-eth"], - "extensions": { - "website": "https://synthetify.io/", - "twitter": "https://twitter.com/synthetify", - "coingeckoId": "ethereum", - "source": "synthetify", - "currency": "ETH", - "sourceUrl": "https://app.synthetify.io/staking" - } - }, - { - "name": "Saber Wrapped Ether (Wormhole) (9 decimals)", - "address": "KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma", - "decimals": 9, - "symbol": "sETH-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma.png", - "tags": [ - "wrapped", - "wormhole", - "saber-mkt-eth", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "serumV3Usdt": "ch7kmPrtoQUSEPBggcNAvLGiMQkJagVwd3gDYfd8m7Q", - "serumV3Usdc": "8Gmi2HhZmwQPVdCwzS7CM66MGstMXPcTVHA7jF19cLZz", - "coingeckoId": "ethereum", - "source": "wormhole-v2", - "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "currency": "ETH", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "website": "https://app.saber.so", - "underlyingTokens": ["7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs"] - } - } - ], - "tokenIcons": [ - { - "name": "Synthetic ETH", - "symbol": "xETH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/8bqjz8DeSuim1sEAsQatjJN4zseyxSPdhHQcuuhL8PCK.svg", - "decimals": 9, - "address": "8bqjz8DeSuim1sEAsQatjJN4zseyxSPdhHQcuuhL8PCK", - "chainId": 101, - "tags": ["saber-mkt-eth"], - "extensions": { - "website": "https://synthetify.io/", - "twitter": "https://twitter.com/synthetify", - "coingeckoId": "ethereum", - "source": "synthetify", - "currency": "ETH", - "sourceUrl": "https://app.synthetify.io/staking" - } - }, - { - "name": "Saber Wrapped Ether (Wormhole) (9 decimals)", - "address": "KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma", - "decimals": 9, - "symbol": "sETH-9", - "chainId": 101, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma.png", - "tags": [ - "wrapped", - "wormhole", - "saber-mkt-eth", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "serumV3Usdt": "ch7kmPrtoQUSEPBggcNAvLGiMQkJagVwd3gDYfd8m7Q", - "serumV3Usdc": "8Gmi2HhZmwQPVdCwzS7CM66MGstMXPcTVHA7jF19cLZz", - "coingeckoId": "ethereum", - "source": "wormhole-v2", - "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "currency": "ETH", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "website": "https://app.saber.so", - "underlyingTokens": ["7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs"] - } - } - ], - "underlyingIcons": [ - { - "name": "Synthetic ETH", - "symbol": "xETH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/8bqjz8DeSuim1sEAsQatjJN4zseyxSPdhHQcuuhL8PCK.svg", - "decimals": 9, - "address": "8bqjz8DeSuim1sEAsQatjJN4zseyxSPdhHQcuuhL8PCK", - "chainId": 101, - "tags": ["saber-mkt-eth"], - "extensions": { - "website": "https://synthetify.io/", - "twitter": "https://twitter.com/synthetify", - "coingeckoId": "ethereum", - "source": "synthetify", - "currency": "ETH", - "sourceUrl": "https://app.synthetify.io/staking" - } - }, - { - "name": "Ether (Wormhole)", - "symbol": "ETH", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs.png", - "decimals": 8, - "address": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-eth", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "serumV3Usdt": "ch7kmPrtoQUSEPBggcNAvLGiMQkJagVwd3gDYfd8m7Q", - "serumV3Usdc": "8Gmi2HhZmwQPVdCwzS7CM66MGstMXPcTVHA7jF19cLZz", - "coingeckoId": "ethereum", - "source": "wormhole-v2", - "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "currency": "ETH", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "currency": "ETH", - "lpToken": { - "symbol": "xETH-ETH", - "name": "Saber xETH-ETH LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/xETH89889mVRwsw9tSUnULsdLUPryTpijagy2YXxWyY.png", - "decimals": 9, - "address": "xETH89889mVRwsw9tSUnULsdLUPryTpijagy2YXxWyY", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-synthetify"], - "extensions": { - "website": "https://app.saber.so/pools/xeth", - "underlyingTokens": [ - "8bqjz8DeSuim1sEAsQatjJN4zseyxSPdhHQcuuhL8PCK", - "KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma" - ], - "source": "saber" - } - }, - "plotKey": "7PpoS69gVG9Y4nXm1K1eZiED1ZdiJkDtVmB27pkmHfvu", - "swap": { - "config": { - "swapAccount": "ionytDfEj1mXodptgrsKEZro7DGsfpzANUfarJdm6Qb", - "authority": "Gdnw9zSTsNjvFcYdtpA5efcGbNCeNAqMev4gGEKbvnJ2", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "xETH89889mVRwsw9tSUnULsdLUPryTpijagy2YXxWyY", - "adminAccount": "HmEhVZUzffy915JhFxrAEpKeGBBYFzUnsm3x1n7yPE41", - "tokenA": { - "adminFeeAccount": "Ay2nCiePZgKkTTwMtg5QimNLZuX2EWzKLeZASpvSF5K3", - "mint": "8bqjz8DeSuim1sEAsQatjJN4zseyxSPdhHQcuuhL8PCK", - "reserve": "3gkSjY95an9xNFSjCfsay6JZez7uv7yfW3Ad4ubc4fMK" - }, - "tokenB": { - "adminFeeAccount": "GTFPLoDJd4c2EXwbF9owKbeh4FbpKYNkEFFCzdHuxq36", - "mint": "KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma", - "reserve": "9wXqANaSuEqkKL9yHzCPEDGHwbkStVAqV5rB3QDs3Jr6" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "CipQjauQwCa2pBbavhtR67mKUHbd8ymrQsDwJHTxjPFB" - }, - { - "id": "xftt", - "name": "xFTT-FTT", - "tokens": [ - { - "name": "Synthetic FTT", - "symbol": "xFTT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Fr3W7NPVvdVbwMcHgA7Gx2wUxP43txdsn3iULJGFbKz9.svg", - "decimals": 8, - "address": "Fr3W7NPVvdVbwMcHgA7Gx2wUxP43txdsn3iULJGFbKz9", - "chainId": 101, - "tags": ["saber-mkt-ftt"], - "extensions": { - "website": "https://synthetify.io/", - "twitter": "https://twitter.com/synthetify", - "coingeckoId": "ftx-token", - "source": "synthetify", - "currency": "FTT", - "sourceUrl": "https://app.synthetify.io/staking" - } - }, - { - "name": "FTX Token (Wormhole)", - "symbol": "FTT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv.png", - "decimals": 8, - "address": "EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-ftt", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "serumV3Usdt": "BoHojHESAv4McZx9gXd1bWTZMq25JYyGz4qL1m5C3nvk", - "serumV3Usdc": "2wteg25ch227n4Rh1CN4WNrDZXBpRBpWJ48mEC2K7f4r", - "coingeckoId": "ftx-token", - "source": "wormhole-v2", - "address": "0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "currency": "FTT", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "tokenIcons": [ - { - "name": "Synthetic FTT", - "symbol": "xFTT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Fr3W7NPVvdVbwMcHgA7Gx2wUxP43txdsn3iULJGFbKz9.svg", - "decimals": 8, - "address": "Fr3W7NPVvdVbwMcHgA7Gx2wUxP43txdsn3iULJGFbKz9", - "chainId": 101, - "tags": ["saber-mkt-ftt"], - "extensions": { - "website": "https://synthetify.io/", - "twitter": "https://twitter.com/synthetify", - "coingeckoId": "ftx-token", - "source": "synthetify", - "currency": "FTT", - "sourceUrl": "https://app.synthetify.io/staking" - } - }, - { - "name": "FTX Token (Wormhole)", - "symbol": "FTT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv.png", - "decimals": 8, - "address": "EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-ftt", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "serumV3Usdt": "BoHojHESAv4McZx9gXd1bWTZMq25JYyGz4qL1m5C3nvk", - "serumV3Usdc": "2wteg25ch227n4Rh1CN4WNrDZXBpRBpWJ48mEC2K7f4r", - "coingeckoId": "ftx-token", - "source": "wormhole-v2", - "address": "0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "currency": "FTT", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "underlyingIcons": [ - { - "name": "Synthetic FTT", - "symbol": "xFTT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/Fr3W7NPVvdVbwMcHgA7Gx2wUxP43txdsn3iULJGFbKz9.svg", - "decimals": 8, - "address": "Fr3W7NPVvdVbwMcHgA7Gx2wUxP43txdsn3iULJGFbKz9", - "chainId": 101, - "tags": ["saber-mkt-ftt"], - "extensions": { - "website": "https://synthetify.io/", - "twitter": "https://twitter.com/synthetify", - "coingeckoId": "ftx-token", - "source": "synthetify", - "currency": "FTT", - "sourceUrl": "https://app.synthetify.io/staking" - } - }, - { - "name": "FTX Token (Wormhole)", - "symbol": "FTT", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv.png", - "decimals": 8, - "address": "EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-ftt", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "assetContract": "https://etherscan.io/address/0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "serumV3Usdt": "BoHojHESAv4McZx9gXd1bWTZMq25JYyGz4qL1m5C3nvk", - "serumV3Usdc": "2wteg25ch227n4Rh1CN4WNrDZXBpRBpWJ48mEC2K7f4r", - "coingeckoId": "ftx-token", - "source": "wormhole-v2", - "address": "0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "currency": "FTT", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "currency": "FTT", - "lpToken": { - "symbol": "xFTT-FTT", - "name": "Saber xFTT-FTT LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/xFTTLsMdN28XHtYTTTVWYz5zwXWBm5r1WTuZ7Cc7SyA.png", - "decimals": 8, - "address": "xFTTLsMdN28XHtYTTTVWYz5zwXWBm5r1WTuZ7Cc7SyA", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-synthetify"], - "extensions": { - "website": "https://app.saber.so/pools/xftt", - "underlyingTokens": [ - "Fr3W7NPVvdVbwMcHgA7Gx2wUxP43txdsn3iULJGFbKz9", - "EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv" - ], - "source": "saber" - } - }, - "plotKey": "Es4SyfteTBaBFHKNwCh2rdiXD3juxBYjzCMytomhTACp", - "swap": { - "config": { - "swapAccount": "Bodz3SK3pzzskFdjwG5TXoavTzNLJbMV8VDQHvxkhTa1", - "authority": "EqG6R7n6dZeRU1fDeCh5RrCAVNERHbwHz5QWjXwMfzoy", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "xFTTLsMdN28XHtYTTTVWYz5zwXWBm5r1WTuZ7Cc7SyA", - "adminAccount": "yeU5463vvSaR8dtH9ZMf25RvExa9eYjmUjFJyDkGFDS", - "tokenA": { - "adminFeeAccount": "BNEGDjUoE7Jb3MHvNYdc2Swr4srnCwAGgXV5fhvd8kak", - "mint": "Fr3W7NPVvdVbwMcHgA7Gx2wUxP43txdsn3iULJGFbKz9", - "reserve": "HHnpxMvDcXaeHXTSnWw9y8gMeUMnnCzxWfACgx839nCt" - }, - "tokenB": { - "adminFeeAccount": "7TDojHU5LqRtDBybM6aiX1q3SvJhGg3oyYBngDf7QAXd", - "mint": "EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv", - "reserve": "Hk8UFqdvVdvJRZjKJV59PkrDrpLnbCCBMgDjVwx53cwi" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "FdHVdkarMfbpPhiAhHtKK6PgH8ibN8SnGSqWhQkTyD2c" - }, - { - "id": "xluna", - "name": "xLUNA-LUNA", - "tokens": [ - { - "name": "Synthetic LUNA", - "symbol": "xLUNA", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/6MeoZEcUMhAB788YXTQN4x7K8MnwSt6RHWsLkuq9GJb2.svg", - "decimals": 6, - "address": "6MeoZEcUMhAB788YXTQN4x7K8MnwSt6RHWsLkuq9GJb2", - "chainId": 101, - "tags": ["saber-mkt-luna"], - "extensions": { - "website": "https://synthetify.io/", - "twitter": "https://twitter.com/synthetify", - "coingeckoId": "terra-luna", - "source": "synthetify", - "currency": "LUNA", - "sourceUrl": "https://app.synthetify.io/staking" - } - }, - { - "name": "LUNA (Wormhole)", - "symbol": "LUNA", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W.png", - "decimals": 6, - "address": "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-luna", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "HBTu8hNaoT3VyiSSzJYa8jwt9sDGKtJviSwFa11iXdmE", - "coingeckoId": "terra-luna", - "source": "wormhole-v2", - "address": "uluna", - "currency": "LUNA", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "tokenIcons": [ - { - "name": "Synthetic LUNA", - "symbol": "xLUNA", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/6MeoZEcUMhAB788YXTQN4x7K8MnwSt6RHWsLkuq9GJb2.svg", - "decimals": 6, - "address": "6MeoZEcUMhAB788YXTQN4x7K8MnwSt6RHWsLkuq9GJb2", - "chainId": 101, - "tags": ["saber-mkt-luna"], - "extensions": { - "website": "https://synthetify.io/", - "twitter": "https://twitter.com/synthetify", - "coingeckoId": "terra-luna", - "source": "synthetify", - "currency": "LUNA", - "sourceUrl": "https://app.synthetify.io/staking" - } - }, - { - "name": "LUNA (Wormhole)", - "symbol": "LUNA", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W.png", - "decimals": 6, - "address": "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-luna", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "HBTu8hNaoT3VyiSSzJYa8jwt9sDGKtJviSwFa11iXdmE", - "coingeckoId": "terra-luna", - "source": "wormhole-v2", - "address": "uluna", - "currency": "LUNA", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "underlyingIcons": [ - { - "name": "Synthetic LUNA", - "symbol": "xLUNA", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/6MeoZEcUMhAB788YXTQN4x7K8MnwSt6RHWsLkuq9GJb2.svg", - "decimals": 6, - "address": "6MeoZEcUMhAB788YXTQN4x7K8MnwSt6RHWsLkuq9GJb2", - "chainId": 101, - "tags": ["saber-mkt-luna"], - "extensions": { - "website": "https://synthetify.io/", - "twitter": "https://twitter.com/synthetify", - "coingeckoId": "terra-luna", - "source": "synthetify", - "currency": "LUNA", - "sourceUrl": "https://app.synthetify.io/staking" - } - }, - { - "name": "LUNA (Wormhole)", - "symbol": "LUNA", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W.png", - "decimals": 6, - "address": "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W", - "chainId": 101, - "tags": ["wrapped", "wormhole", "saber-mkt-luna", "wormhole-v2"], - "extensions": { - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "serumV3Usdc": "HBTu8hNaoT3VyiSSzJYa8jwt9sDGKtJviSwFa11iXdmE", - "coingeckoId": "terra-luna", - "source": "wormhole-v2", - "address": "uluna", - "currency": "LUNA", - "sourceUrl": "https://wormholebridge.com/#/transfer" - } - } - ], - "currency": "LUNA", - "lpToken": { - "symbol": "xLUNA-LUNA", - "name": "Saber xLUNA-LUNA LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/LUNbjQA8GAwotiHPiq9cmdVkEfYgZFGhBFnHhicjZtP.png", - "decimals": 6, - "address": "LUNbjQA8GAwotiHPiq9cmdVkEfYgZFGhBFnHhicjZtP", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-synthetify"], - "extensions": { - "website": "https://app.saber.so/pools/xluna", - "underlyingTokens": [ - "6MeoZEcUMhAB788YXTQN4x7K8MnwSt6RHWsLkuq9GJb2", - "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W" - ], - "source": "saber" - } - }, - "plotKey": "2BVYbNHN893FSQKfJpx5MBzKDCkGb8aJSpUwMydrMMtT", - "swap": { - "config": { - "swapAccount": "KWAnW2f2FYWLjfjoeu61BPfjHfkcNTKG4x8ogaLa5NL", - "authority": "EQ2deWUZGyNPcbpWH3Z7E7T2eWya5Bpg1vuSDwK6DV84", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "LUNbjQA8GAwotiHPiq9cmdVkEfYgZFGhBFnHhicjZtP", - "adminAccount": "4tH2GV7A99U4vU6YLZUovEWJdXttEESiR2Etcfv4vbz3", - "tokenA": { - "adminFeeAccount": "BYNrp8BDW2tEXyGfjk8w11AK9JvFdmiZR1g73fmK4Sq5", - "mint": "6MeoZEcUMhAB788YXTQN4x7K8MnwSt6RHWsLkuq9GJb2", - "reserve": "6QEFAL5yVfVX4fd8ty7xbgFPGhkKZ7bno6zWtfenf74M" - }, - "tokenB": { - "adminFeeAccount": "8hxkXevK23DdYSNteDa2uQiNo4pQ6nB9PDcJymkN4QTQ", - "mint": "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W", - "reserve": "F5BusnAhe2K5wv7mZd6uE2Mwknvb6NhWHuxiF8TxCvpW" - }, - "initialAmpFactor": "64", - "targetAmpFactor": "64", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "5XaTK9MV9Ab2BLP5Ug4xUfNxeMNYQqcn2mpVaZ4Mbbhh" - }, - { - "id": "xsol", - "name": "xSOL-SOL", - "tokens": [ - { - "name": "Synthetic SOL", - "symbol": "xSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BdUJucPJyjkHxLMv6ipKNUhSeY3DWrVtgxAES1iSBAov.svg", - "decimals": 9, - "address": "BdUJucPJyjkHxLMv6ipKNUhSeY3DWrVtgxAES1iSBAov", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://synthetify.io/", - "twitter": "https://twitter.com/synthetify", - "coingeckoId": "solana", - "source": "synthetify", - "currency": "SOL", - "sourceUrl": "https://app.synthetify.io/staking" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "tokenIcons": [ - { - "name": "Synthetic SOL", - "symbol": "xSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BdUJucPJyjkHxLMv6ipKNUhSeY3DWrVtgxAES1iSBAov.svg", - "decimals": 9, - "address": "BdUJucPJyjkHxLMv6ipKNUhSeY3DWrVtgxAES1iSBAov", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://synthetify.io/", - "twitter": "https://twitter.com/synthetify", - "coingeckoId": "solana", - "source": "synthetify", - "currency": "SOL", - "sourceUrl": "https://app.synthetify.io/staking" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "underlyingIcons": [ - { - "name": "Synthetic SOL", - "symbol": "xSOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/BdUJucPJyjkHxLMv6ipKNUhSeY3DWrVtgxAES1iSBAov.svg", - "decimals": 9, - "address": "BdUJucPJyjkHxLMv6ipKNUhSeY3DWrVtgxAES1iSBAov", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://synthetify.io/", - "twitter": "https://twitter.com/synthetify", - "coingeckoId": "solana", - "source": "synthetify", - "currency": "SOL", - "sourceUrl": "https://app.synthetify.io/staking" - } - }, - { - "name": "Wrapped SOL", - "symbol": "SOL", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/So11111111111111111111111111111111111111112.png", - "decimals": 9, - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "tags": ["saber-mkt-sol"], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "coingeckoId": "solana", - "currency": "SOL" - } - } - ], - "currency": "SOL", - "lpToken": { - "symbol": "xSOL-SOL", - "name": "Saber xSOL-SOL LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/xSoLVBNztDTUW8Kou2GJinHoe54Siu9Sk3e2uoU9aUi.png", - "decimals": 9, - "address": "xSoLVBNztDTUW8Kou2GJinHoe54Siu9Sk3e2uoU9aUi", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-synthetify"], - "extensions": { - "website": "https://app.saber.so/pools/xsol", - "underlyingTokens": [ - "BdUJucPJyjkHxLMv6ipKNUhSeY3DWrVtgxAES1iSBAov", - "So11111111111111111111111111111111111111112" - ], - "source": "saber" - } - }, - "plotKey": "F62bWEaqZDf2npGYF7usA9GH9zCffYsPnGANz4T6YB6v", - "swap": { - "config": { - "swapAccount": "BERTH9caDT1mFBvne1h5hHdE58vxuAVuvh5rs43AYn9r", - "authority": "5j93Lq7Txj9nEr9fUw3YJ2C4Pezm6eUJfGsUi6eYXcy", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 248, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "xSoLVBNztDTUW8Kou2GJinHoe54Siu9Sk3e2uoU9aUi", - "adminAccount": "6Wt9zummPyWcuD9r3zoNiiLcQgE1y8Lgixtko1QZitHG", - "tokenA": { - "adminFeeAccount": "5iPA8k3qTshZWz19wgPPNLvTrTXjMiv6K2feDy159VWv", - "mint": "BdUJucPJyjkHxLMv6ipKNUhSeY3DWrVtgxAES1iSBAov", - "reserve": "GSt31U8nF6WJBRG7j2EALfNTMd3J8jmotGX9szVTrzvN" - }, - "tokenB": { - "adminFeeAccount": "FtwcLBGggnpoyJDRzX3oa9ErRFSe4opbQ1KhHg9fGEJs", - "mint": "So11111111111111111111111111111111111111112", - "reserve": "7WEqRDS5Dk6kVXFZHrsW5EtdPhy4v6jWK9P5jHhi9oz" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "BB8EYouLWTWnY3cpns7zGpBwcBbWTcczKuqpkvwcdkvi" - }, - { - "id": "xusd", - "name": "xUSD-USDC", - "tokens": [ - { - "name": "Synthetic USD", - "symbol": "xUSD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/83LGLCm7QKpYZbX8q4W2kYWbtt8NJBwbVwEepzkVnJ9y.svg", - "decimals": 6, - "address": "83LGLCm7QKpYZbX8q4W2kYWbtt8NJBwbVwEepzkVnJ9y", - "chainId": 101, - "tags": ["saber-mkt-usd"], - "extensions": { - "website": "https://synthetify.io/", - "twitter": "https://twitter.com/synthetify", - "coingeckoId": "usd-coin", - "source": "synthetify", - "currency": "USD", - "sourceUrl": "https://app.synthetify.io/staking" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "tokenIcons": [ - { - "name": "Synthetic USD", - "symbol": "xUSD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/83LGLCm7QKpYZbX8q4W2kYWbtt8NJBwbVwEepzkVnJ9y.svg", - "decimals": 6, - "address": "83LGLCm7QKpYZbX8q4W2kYWbtt8NJBwbVwEepzkVnJ9y", - "chainId": 101, - "tags": ["saber-mkt-usd"], - "extensions": { - "website": "https://synthetify.io/", - "twitter": "https://twitter.com/synthetify", - "coingeckoId": "usd-coin", - "source": "synthetify", - "currency": "USD", - "sourceUrl": "https://app.synthetify.io/staking" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "underlyingIcons": [ - { - "name": "Synthetic USD", - "symbol": "xUSD", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/83LGLCm7QKpYZbX8q4W2kYWbtt8NJBwbVwEepzkVnJ9y.svg", - "decimals": 6, - "address": "83LGLCm7QKpYZbX8q4W2kYWbtt8NJBwbVwEepzkVnJ9y", - "chainId": 101, - "tags": ["saber-mkt-usd"], - "extensions": { - "website": "https://synthetify.io/", - "twitter": "https://twitter.com/synthetify", - "coingeckoId": "usd-coin", - "source": "synthetify", - "currency": "USD", - "sourceUrl": "https://app.synthetify.io/staking" - } - }, - { - "name": "USD Coin", - "symbol": "USDC", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "decimals": 6, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "tags": ["stablecoin", "saber-mkt-usd"], - "extensions": { - "website": "https://www.centre.io/", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "coingeckoId": "usd-coin", - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "xUSD-USDC", - "name": "Saber xUSD-USDC LP", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/XUSDfnsgc2QYXRdbPAbMWoXCbBCCspRSvoGJ8o7RV9n.png", - "decimals": 6, - "address": "XUSDfnsgc2QYXRdbPAbMWoXCbBCCspRSvoGJ8o7RV9n", - "chainId": 101, - "tags": ["saber-stableswap-lp", "saber-lp-synthetify"], - "extensions": { - "website": "https://app.saber.so/pools/xusd", - "underlyingTokens": [ - "83LGLCm7QKpYZbX8q4W2kYWbtt8NJBwbVwEepzkVnJ9y", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "source": "saber" - } - }, - "plotKey": "H7gz192xGR4Yr8oXCjX4rS8FUxRDQKtLC6dYAgyyCkJQ", - "swap": { - "config": { - "swapAccount": "NorjjEePhxfwLF4vZjUHCrVVKLzQjEEGQFd3wgjEJmh", - "authority": "4MKU6kajSHK6YGt39fAjvW5bPV1uwUdAP5VVEcS7JLRr", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "poolTokenMint": "XUSDfnsgc2QYXRdbPAbMWoXCbBCCspRSvoGJ8o7RV9n", - "adminAccount": "6hWfxJVt3uP3GXcrL3wZTqEC2kK64pVsJnpQcY1BFZ9Y", - "tokenA": { - "adminFeeAccount": "G8cY9ED8rJYc78ZtkiMGeaydtx96BBPuaZsirpkzkifw", - "mint": "83LGLCm7QKpYZbX8q4W2kYWbtt8NJBwbVwEepzkVnJ9y", - "reserve": "34M8pFVqgbV7aqHxvRT5tCv3vu2P1JJYT8J3VaxBK2oG" - }, - "tokenB": { - "adminFeeAccount": "87UVu2YZFmANEN7znTYVQVbZVtdE4CJnPWcfcLrnHR7u", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "reserve": "3AZWBSze3ucsY3xSeuLne3b2pauVqiaJ1SZSV5T9WGWw" - }, - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "9XAGs2YwvRqCLupFAQQyH1XnP1MP3dp9PL6JaBD7yCZp" - } - ] -} diff --git a/farms/farm-ctrl/metadata/pools/saber/pools_and_farms_dev.json b/farms/farm-ctrl/metadata/pools/saber/pools_and_farms_dev.json deleted file mode 100644 index 91cd2fcf9c7..00000000000 --- a/farms/farm-ctrl/metadata/pools/saber/pools_and_farms_dev.json +++ /dev/null @@ -1,1027 +0,0 @@ -{ - "addresses": { - "landlord": "B38L5x5EszUK4iqcNMAZRyaJx8ie8cgGvxxbYmkWkjZe", - "landlordBase": "GHxgjDJgpUkugb2cPvaKQSbkdoHYHCHo2ZZsRFiFt4YL", - "rewarder": "rXhAofQCT7NN9TUqigyEAUzV1uLL4boeD8CRkNBSkYk", - "mintWrapper": "EVVDA3ZiAjTizemLGXNUN3gb6cffQFEYkFjFZokPmUPz", - "iouMint": "iouQcQBAiEXe6cKLS85zmZxUqaCqBdeHFpqKoSz615u", - "redeemer": "CL9wkGFT3SZRRNa9dgaovuRV7jrVVigBUZ6DjcgySsCU", - "sbr": "Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1" - }, - "pools": [ - { - "id": "btc", - "name": "renBTC-WBTC", - "tokens": [ - { - "name": "Test RenBTC", - "address": "Ren3RLPCG6hpKay86d2fQccQLuGG331UNxwn2VTw3GJ", - "decimals": 8, - "chainId": 103, - "symbol": "renBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/trustwallet/assets@master/blockchains/ethereum/assets/0xEB4C2781e4ebA804CE9a9803C67d0893436bB27D/logo.png", - "tags": ["saber-mkt-btc"], - "extensions": { - "currency": "BTC" - } - }, - { - "name": "Saber Wrapped Test WBTC (8 decimals)", - "address": "BtceyXMo5kwg8u6es4NoukBWQuMwtcBCZpFWUfZgVuZs", - "decimals": 8, - "symbol": "sWBTC-8", - "chainId": 103, - "logoURI": "https://cdn.jsdelivr.net/gh/trustwallet/assets@master/blockchains/bitcoin/info/logo.png", - "tags": ["saber-mkt-btc", "saber-dec-wrapped"], - "extensions": { - "currency": "BTC", - "website": "https://app.saber.so", - "assetContract": "Wbt2CgkkD3eVckD5XxWJmT8pTnFTyWrwvGM7bUMLvsM", - "underlyingTokens": ["Wbt2CgkkD3eVckD5XxWJmT8pTnFTyWrwvGM7bUMLvsM"] - } - } - ], - "tokenIcons": [ - { - "name": "Test RenBTC", - "address": "Ren3RLPCG6hpKay86d2fQccQLuGG331UNxwn2VTw3GJ", - "decimals": 8, - "chainId": 103, - "symbol": "renBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/trustwallet/assets@master/blockchains/ethereum/assets/0xEB4C2781e4ebA804CE9a9803C67d0893436bB27D/logo.png", - "tags": ["saber-mkt-btc"], - "extensions": { - "currency": "BTC" - } - }, - { - "name": "Saber Wrapped Test WBTC (8 decimals)", - "address": "BtceyXMo5kwg8u6es4NoukBWQuMwtcBCZpFWUfZgVuZs", - "decimals": 8, - "symbol": "sWBTC-8", - "chainId": 103, - "logoURI": "https://cdn.jsdelivr.net/gh/trustwallet/assets@master/blockchains/bitcoin/info/logo.png", - "tags": ["saber-mkt-btc", "saber-dec-wrapped"], - "extensions": { - "currency": "BTC", - "website": "https://app.saber.so", - "assetContract": "Wbt2CgkkD3eVckD5XxWJmT8pTnFTyWrwvGM7bUMLvsM", - "underlyingTokens": ["Wbt2CgkkD3eVckD5XxWJmT8pTnFTyWrwvGM7bUMLvsM"] - } - } - ], - "underlyingIcons": [ - { - "name": "Test RenBTC", - "address": "Ren3RLPCG6hpKay86d2fQccQLuGG331UNxwn2VTw3GJ", - "decimals": 8, - "chainId": 103, - "symbol": "renBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/trustwallet/assets@master/blockchains/ethereum/assets/0xEB4C2781e4ebA804CE9a9803C67d0893436bB27D/logo.png", - "tags": ["saber-mkt-btc"], - "extensions": { - "currency": "BTC" - } - }, - { - "name": "Test WBTC", - "address": "Wbt2CgkkD3eVckD5XxWJmT8pTnFTyWrwvGM7bUMLvsM", - "decimals": 6, - "chainId": 103, - "symbol": "WBTC", - "logoURI": "https://cdn.jsdelivr.net/gh/trustwallet/assets@master/blockchains/bitcoin/info/logo.png", - "tags": ["saber-mkt-btc"], - "extensions": { - "currency": "BTC" - } - } - ], - "currency": "BTC", - "lpToken": { - "symbol": "renBTC-WBTC", - "name": "Saber renBTC-WBTC LP", - "logoURI": "https://registry.saber.so/token-icons/slp.png", - "decimals": 8, - "address": "bLpASoWNdsz5DsjCaxpbM2FrkMowTJCydpwiDP4Vdzm", - "chainId": 103, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/#/pools/btc", - "underlyingTokens": [ - "Ren3RLPCG6hpKay86d2fQccQLuGG331UNxwn2VTw3GJ", - "BtceyXMo5kwg8u6es4NoukBWQuMwtcBCZpFWUfZgVuZs" - ], - "source": "saber" - } - }, - "plotKey": "8c6AgGFMUT6cuU23FJuyfBtug98axAwPNXaHp6pbrqG2", - "swap": { - "config": { - "swapAccount": "AQsYrKkFLuv9Jw7kCcPH7SkeMQ2aZkP1KcBs4RYegHbv", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", - "authority": "ChFJZQK4gNpmcrbF71e5Wo2HzF8qePYGnqsgZ6u7anFA" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "adminAccount": "8U8GbmSKjygwdqmFH9rYaWxkD9G13T1RsCYfcxqkHaiy", - "tokenA": { - "adminFeeAccount": "4bCW6q6LjWmt1YgCSdFXRq9hg5vqPeLDkf4fcDeBUMVy", - "reserve": "GT9JcsFPaeDJRCeysNHWT76nvN9EWDj7z7psaADSn8QS", - "mint": "Ren3RLPCG6hpKay86d2fQccQLuGG331UNxwn2VTw3GJ" - }, - "tokenB": { - "adminFeeAccount": "F1yiwRWfjFNyVzYUEo4o9AbAF3JRUruZMSsckMMUK22c", - "reserve": "6jRUeyuRyaG1BfV5Y7fRCRhUk8P9CJwS1s5qybG6HPti", - "mint": "BtceyXMo5kwg8u6es4NoukBWQuMwtcBCZpFWUfZgVuZs" - }, - "poolTokenMint": "bLpASoWNdsz5DsjCaxpbM2FrkMowTJCydpwiDP4Vdzm", - "initialAmpFactor": "32", - "targetAmpFactor": "32", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "CeE8rNxCFx2RAgpS7trsmcTz7ydyun33wbNY7r2nEvPi" - }, - { - "id": "usdc_cash", - "name": "USDC-CASH", - "tokens": [ - { - "symbol": "USDC", - "name": "USD Coin (Saber Devnet)", - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/103/2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8.png", - "address": "2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd", "stablecoin"], - "extensions": { - "currency": "USD", - "coingeckoId": "usd-coin", - "website": "https://saber.so/" - } - }, - { - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 103, - "decimals": 6, - "extensions": { - "coingeckoId": "usd-coin", - "currency": "USD", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "medium": "https://medium.com/@cashioapp", - "source": "cashio", - "sourceUrl": "https://cashio.app/#/print", - "twitter": "https://twitter.com/CashioApp", - "website": "https://cashio.app" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "name": "Cashio Dollar", - "symbol": "CASH", - "tags": ["stablecoin", "saber-mkt-usd"] - } - ], - "tokenIcons": [ - { - "symbol": "USDC", - "name": "USD Coin (Saber Devnet)", - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/103/2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8.png", - "address": "2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd", "stablecoin"], - "extensions": { - "currency": "USD", - "coingeckoId": "usd-coin", - "website": "https://saber.so/" - } - }, - { - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 103, - "decimals": 6, - "extensions": { - "coingeckoId": "usd-coin", - "currency": "USD", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "medium": "https://medium.com/@cashioapp", - "source": "cashio", - "sourceUrl": "https://cashio.app/#/print", - "twitter": "https://twitter.com/CashioApp", - "website": "https://cashio.app" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "name": "Cashio Dollar", - "symbol": "CASH", - "tags": ["stablecoin", "saber-mkt-usd"] - } - ], - "underlyingIcons": [ - { - "symbol": "USDC", - "name": "USD Coin (Saber Devnet)", - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/103/2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8.png", - "address": "2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd", "stablecoin"], - "extensions": { - "currency": "USD", - "coingeckoId": "usd-coin", - "website": "https://saber.so/" - } - }, - { - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 103, - "decimals": 6, - "extensions": { - "coingeckoId": "usd-coin", - "currency": "USD", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "medium": "https://medium.com/@cashioapp", - "source": "cashio", - "sourceUrl": "https://cashio.app/#/print", - "twitter": "https://twitter.com/CashioApp", - "website": "https://cashio.app" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "name": "Cashio Dollar", - "symbol": "CASH", - "tags": ["stablecoin", "saber-mkt-usd"] - } - ], - "currency": "USD", - "lpToken": { - "symbol": "USDC-CASH", - "name": "Saber USDC-CASH LP", - "logoURI": "https://registry.saber.so/token-icons/slp.png", - "decimals": 6, - "address": "DALfPHRc2eKmnsEDs8fkHKNA37FwVSD6AbrLZXn1oTtJ", - "chainId": 103, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/#/pools/usdc_cash", - "underlyingTokens": [ - "2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8", - "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT" - ], - "source": "saber" - } - }, - "plotKey": "AoijvP2yrE1H9C4K1Z6TrpkjsQjfPnBVn1yKeh5Y7uyJ", - "swap": { - "config": { - "swapAccount": "B94iYzzWe7Q3ksvRnt5yJm6G5YquerRFKpsUVUvasdmA", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", - "authority": "BgktRz16U7M7gnT2mzeL1idLyndxKFHeWRdKXUD9VGRz" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "adminAccount": "AgsR6hUZitMsT7EXkJ5ahxSSui3dAtQReKsyxs2nUwNH", - "tokenA": { - "adminFeeAccount": "Am4RG99CzFaPqFUizYq66K2BxcBp3FcdxoBxM3P1FZ6w", - "reserve": "DjX8KKu5bHz3zz7oJDhZbSDoksGbDr6EZFaooYFrPK4u", - "mint": "2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8" - }, - "tokenB": { - "adminFeeAccount": "VfZCJhqCtxW6WbZCTHgotRwmDbnrXibQ1XgLgWTbAAg", - "reserve": "654z3VDWzK7BuehVQSmyftqm6TxHnJDDJF8eHdCXUEcs", - "mint": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT" - }, - "poolTokenMint": "DALfPHRc2eKmnsEDs8fkHKNA37FwVSD6AbrLZXn1oTtJ", - "initialAmpFactor": "07d0", - "targetAmpFactor": "07d0", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "2xs4gZpawFvgUojWrqWPyFERRtu7F569VvRLeFS29jpm" - }, - { - "id": "usdc_pai", - "name": "USDC-PAI", - "tokens": [ - { - "symbol": "USDC", - "name": "USD Coin (Saber Devnet)", - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/103/2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8.png", - "address": "2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd", "stablecoin"], - "extensions": { - "currency": "USD", - "coingeckoId": "usd-coin", - "website": "https://saber.so/" - } - }, - { - "symbol": "PAI", - "name": "PAI", - "logoURI": "https://registry.saber.so/token-icons/pai.svg", - "address": "4ry1pMstKzMJvMZSms62HduTyCbbqkUyrz17x1dajBmL", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd"], - "extensions": { - "currency": "USD" - } - } - ], - "tokenIcons": [ - { - "symbol": "USDC", - "name": "USD Coin (Saber Devnet)", - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/103/2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8.png", - "address": "2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd", "stablecoin"], - "extensions": { - "currency": "USD", - "coingeckoId": "usd-coin", - "website": "https://saber.so/" - } - }, - { - "symbol": "PAI", - "name": "PAI", - "logoURI": "https://registry.saber.so/token-icons/pai.svg", - "address": "4ry1pMstKzMJvMZSms62HduTyCbbqkUyrz17x1dajBmL", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd"], - "extensions": { - "currency": "USD" - } - } - ], - "underlyingIcons": [ - { - "symbol": "USDC", - "name": "USD Coin (Saber Devnet)", - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/103/2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8.png", - "address": "2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd", "stablecoin"], - "extensions": { - "currency": "USD", - "coingeckoId": "usd-coin", - "website": "https://saber.so/" - } - }, - { - "symbol": "PAI", - "name": "PAI", - "logoURI": "https://registry.saber.so/token-icons/pai.svg", - "address": "4ry1pMstKzMJvMZSms62HduTyCbbqkUyrz17x1dajBmL", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd"], - "extensions": { - "currency": "USD" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "USDC-PAI", - "name": "Saber USDC-PAI LP", - "logoURI": "https://registry.saber.so/token-icons/slp.png", - "decimals": 6, - "address": "J8fDLz5bfef14jDNC32nJLbVzpS9Rj1LBHwaSGfYn83J", - "chainId": 103, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/#/pools/usdc_pai", - "underlyingTokens": [ - "2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8", - "4ry1pMstKzMJvMZSms62HduTyCbbqkUyrz17x1dajBmL" - ], - "source": "saber" - } - }, - "plotKey": "ByDbnkzqj3QmaTmjAfgDgK4YofpQZ7cNSgkLUm8i26TS", - "swap": { - "config": { - "swapAccount": "DoycojcYVwc42yCpGb4CvkbuKJkQ6KBTugLdJXv3U8ZE", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", - "authority": "8BC6eAF59beKMctxpH7jkx8faR6jdyKc5doHB7Tiffig" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "adminAccount": "HRSUYmvwyhy8SEYvvBvwpjpTdmRiYGAEqGDbWUKT2QY", - "tokenA": { - "adminFeeAccount": "DW7sA9UxkB8GrnJAXzH28wS4G6jR34SJb38tFapsUjJD", - "reserve": "3hqDsGEp4Zp8PhXhx37ub94bHYfkjjHvZG5YJKyJ17no", - "mint": "2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8" - }, - "tokenB": { - "adminFeeAccount": "defQcSvSKgXFMEBnE1WuGfnfbLFmBp29agdYr3s3Bvp", - "reserve": "FLX3nBuu77Ld4KG9nTLgNnaqfT8BFnTRGtkwaBYWSXLQ", - "mint": "4ry1pMstKzMJvMZSms62HduTyCbbqkUyrz17x1dajBmL" - }, - "poolTokenMint": "J8fDLz5bfef14jDNC32nJLbVzpS9Rj1LBHwaSGfYn83J", - "initialAmpFactor": "64", - "targetAmpFactor": "64", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "adminTrade": { - "formatted": "50.0000000000", - "numerator": "50", - "denominator": "100" - }, - "adminWithdraw": { - "formatted": "50.0000000000", - "numerator": "50", - "denominator": "100" - }, - "trade": { - "formatted": "0.2000000000", - "numerator": "20", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.5000000000", - "numerator": "50", - "denominator": "10000" - } - } - } - }, - "quarry": "Cae9hW42nD1G89LCheaSczN6CzngYYWQ6KbZMQXhMwyq" - }, - { - "id": "usdc_test", - "name": "TEST-USDC", - "tokens": [ - { - "symbol": "TEST", - "name": "Test USD", - "logoURI": "https://registry.saber.so/token-icons/candy-usd.png", - "address": "4QgnWUPQmfGB5dTDCcc4ZFeZDK7xNVhCUFoNmmYFwAme", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd"], - "extensions": { - "currency": "USD" - } - }, - { - "symbol": "USDC", - "name": "USD Coin (Saber Devnet)", - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/103/2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8.png", - "address": "2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd", "stablecoin"], - "extensions": { - "currency": "USD", - "coingeckoId": "usd-coin", - "website": "https://saber.so/" - } - } - ], - "tokenIcons": [ - { - "symbol": "TEST", - "name": "Test USD", - "logoURI": "https://registry.saber.so/token-icons/candy-usd.png", - "address": "4QgnWUPQmfGB5dTDCcc4ZFeZDK7xNVhCUFoNmmYFwAme", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd"], - "extensions": { - "currency": "USD" - } - }, - { - "symbol": "USDC", - "name": "USD Coin (Saber Devnet)", - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/103/2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8.png", - "address": "2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd", "stablecoin"], - "extensions": { - "currency": "USD", - "coingeckoId": "usd-coin", - "website": "https://saber.so/" - } - } - ], - "underlyingIcons": [ - { - "symbol": "TEST", - "name": "Test USD", - "logoURI": "https://registry.saber.so/token-icons/candy-usd.png", - "address": "4QgnWUPQmfGB5dTDCcc4ZFeZDK7xNVhCUFoNmmYFwAme", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd"], - "extensions": { - "currency": "USD" - } - }, - { - "symbol": "USDC", - "name": "USD Coin (Saber Devnet)", - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/103/2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8.png", - "address": "2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd", "stablecoin"], - "extensions": { - "currency": "USD", - "coingeckoId": "usd-coin", - "website": "https://saber.so/" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "TEST-USDC", - "name": "Saber TEST-USDC LP", - "logoURI": "https://registry.saber.so/token-icons/slp.png", - "decimals": 6, - "address": "E2XcZ3WR9Qt19JLNjCEWkbtfJiYhWbpTbw3wZbmj2AQo", - "chainId": 103, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/#/pools/usdc_test", - "underlyingTokens": [ - "4QgnWUPQmfGB5dTDCcc4ZFeZDK7xNVhCUFoNmmYFwAme", - "2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8" - ], - "source": "saber" - } - }, - "plotKey": "CoYqTqHeZsuQqiXRdvx7TiSp7VVy8dNgWf8JM83h8bw", - "swap": { - "config": { - "swapAccount": "AqBGfWy3D9NpW8LuknrSSuv93tJUBiPWYxkBrettkG7x", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", - "authority": "CzyZPuuszgHNyxcPxWKw6r1nrVKB7LdkGZMyQx6Tohpa" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "adminAccount": "EfYCi3Uv4zg4PZqrnzXpWDbow3UuBKTudb4PdB5g9n1R", - "tokenA": { - "adminFeeAccount": "EDdsbAnrpnHWbHPHZmXhuZPScXyueCnW6dw6V7dk8vjN", - "reserve": "5t9v3eYu4qY7g9AMZ7DbxZ5feb5HcHSyKcgG9DhcJam4", - "mint": "4QgnWUPQmfGB5dTDCcc4ZFeZDK7xNVhCUFoNmmYFwAme" - }, - "tokenB": { - "adminFeeAccount": "FbZsySqXDztj5cqU5DuJoa8yyXHsjWBkzTNeuHMMrY7t", - "reserve": "Cbbs13w3R9BQhtd4BLfsAUsh1VtjM2La8chxxv5fn9by", - "mint": "2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8" - }, - "poolTokenMint": "E2XcZ3WR9Qt19JLNjCEWkbtfJiYhWbpTbw3wZbmj2AQo", - "initialAmpFactor": "64", - "targetAmpFactor": "64", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "5cX41FTaqRwdMBh1eenEKsQ1J1GwxA7sirnKsmP4i5mz" - }, - { - "id": "usdc_usdt", - "name": "USDC-USDT", - "tokens": [ - { - "symbol": "USDC", - "name": "USD Coin (Saber Devnet)", - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/103/2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8.png", - "address": "2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd", "stablecoin"], - "extensions": { - "currency": "USD", - "coingeckoId": "usd-coin", - "website": "https://saber.so/" - } - }, - { - "symbol": "USDT", - "name": "USDT (Saber Devnet)", - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/103/EJwZgeZrdC8TXTQbQBoL6bfuAnFUUy1PVCMB4DYPzVaS.svg", - "address": "EJwZgeZrdC8TXTQbQBoL6bfuAnFUUy1PVCMB4DYPzVaS", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd", "stablecoin"], - "extensions": { - "currency": "USD", - "coingeckoId": "tether", - "website": "https://saber.so/" - } - } - ], - "tokenIcons": [ - { - "symbol": "USDC", - "name": "USD Coin (Saber Devnet)", - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/103/2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8.png", - "address": "2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd", "stablecoin"], - "extensions": { - "currency": "USD", - "coingeckoId": "usd-coin", - "website": "https://saber.so/" - } - }, - { - "symbol": "USDT", - "name": "USDT (Saber Devnet)", - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/103/EJwZgeZrdC8TXTQbQBoL6bfuAnFUUy1PVCMB4DYPzVaS.svg", - "address": "EJwZgeZrdC8TXTQbQBoL6bfuAnFUUy1PVCMB4DYPzVaS", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd", "stablecoin"], - "extensions": { - "currency": "USD", - "coingeckoId": "tether", - "website": "https://saber.so/" - } - } - ], - "underlyingIcons": [ - { - "symbol": "USDC", - "name": "USD Coin (Saber Devnet)", - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/103/2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8.png", - "address": "2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd", "stablecoin"], - "extensions": { - "currency": "USD", - "coingeckoId": "usd-coin", - "website": "https://saber.so/" - } - }, - { - "symbol": "USDT", - "name": "USDT (Saber Devnet)", - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/103/EJwZgeZrdC8TXTQbQBoL6bfuAnFUUy1PVCMB4DYPzVaS.svg", - "address": "EJwZgeZrdC8TXTQbQBoL6bfuAnFUUy1PVCMB4DYPzVaS", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd", "stablecoin"], - "extensions": { - "currency": "USD", - "coingeckoId": "tether", - "website": "https://saber.so/" - } - } - ], - "currency": "USD", - "lpToken": { - "symbol": "USDC-USDT", - "name": "Saber USDC-USDT LP", - "logoURI": "https://registry.saber.so/token-icons/slp.png", - "decimals": 6, - "address": "YakofBo4X3zMxa823THQJwZ8QeoU8pxPdFdxJs7JW57", - "chainId": 103, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/#/pools/usdc_usdt", - "underlyingTokens": [ - "2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8", - "EJwZgeZrdC8TXTQbQBoL6bfuAnFUUy1PVCMB4DYPzVaS" - ], - "source": "saber" - } - }, - "plotKey": "99CaY6yjPLJzAJU3y2qhuLMFcfoCof4tnbR21FrtiGJd", - "swap": { - "config": { - "swapAccount": "VeNkoB1HvSP6bSeGybQDnx9wTWFsQb2NBCemeCDSuKL", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", - "authority": "72E8LfHqoxQCxnxmBbDG6WSHnDx1rWPUHNKwYvoL5qDm" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 254, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "adminAccount": "GSmjrpT8zNtp6Ke8y2xS5P1kREEjqZCjwxF8VbxDJAV8", - "tokenA": { - "adminFeeAccount": "6RPzht581g8QLdKaT8CSuCnj9yBhR2u6mxKFFK6Dbhgx", - "reserve": "6aFutFMWR7PbWdBQhdfrcKrAor9WYa2twtSinTMb9tXv", - "mint": "2tWC4JAdL4AxEFJySziYJfsAnW2MHKRo98vbAPiRDSk8" - }, - "tokenB": { - "adminFeeAccount": "5Z4M2yHn6LUWaK9Ka8QqByM1NimGGRMdEk7roHoQbDb9", - "reserve": "HXbhpnLTxSDDkTg6deDpsXzJRBf8j7T6Dc3GidwrLWeo", - "mint": "EJwZgeZrdC8TXTQbQBoL6bfuAnFUUy1PVCMB4DYPzVaS" - }, - "poolTokenMint": "YakofBo4X3zMxa823THQJwZ8QeoU8pxPdFdxJs7JW57", - "initialAmpFactor": "64", - "targetAmpFactor": "64", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "adminTrade": { - "formatted": "50.0000000000", - "numerator": "50", - "denominator": "100" - }, - "adminWithdraw": { - "formatted": "50.0000000000", - "numerator": "50", - "denominator": "100" - }, - "trade": { - "formatted": "0.2000000000", - "numerator": "20", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.5000000000", - "numerator": "50", - "denominator": "10000" - } - } - } - }, - "quarry": "8QfbpS8fBNcqee9qHjYG5pgBWTKyM193E7zjwzxeUZ3X" - }, - { - "id": "usdt_cash", - "name": "USDT-CASH", - "tokens": [ - { - "symbol": "USDT", - "name": "USDT (Saber Devnet)", - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/103/EJwZgeZrdC8TXTQbQBoL6bfuAnFUUy1PVCMB4DYPzVaS.svg", - "address": "EJwZgeZrdC8TXTQbQBoL6bfuAnFUUy1PVCMB4DYPzVaS", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd", "stablecoin"], - "extensions": { - "currency": "USD", - "coingeckoId": "tether", - "website": "https://saber.so/" - } - }, - { - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 103, - "decimals": 6, - "extensions": { - "coingeckoId": "usd-coin", - "currency": "USD", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "medium": "https://medium.com/@cashioapp", - "source": "cashio", - "sourceUrl": "https://cashio.app/#/print", - "twitter": "https://twitter.com/CashioApp", - "website": "https://cashio.app" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "name": "Cashio Dollar", - "symbol": "CASH", - "tags": ["stablecoin", "saber-mkt-usd"] - } - ], - "tokenIcons": [ - { - "symbol": "USDT", - "name": "USDT (Saber Devnet)", - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/103/EJwZgeZrdC8TXTQbQBoL6bfuAnFUUy1PVCMB4DYPzVaS.svg", - "address": "EJwZgeZrdC8TXTQbQBoL6bfuAnFUUy1PVCMB4DYPzVaS", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd", "stablecoin"], - "extensions": { - "currency": "USD", - "coingeckoId": "tether", - "website": "https://saber.so/" - } - }, - { - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 103, - "decimals": 6, - "extensions": { - "coingeckoId": "usd-coin", - "currency": "USD", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "medium": "https://medium.com/@cashioapp", - "source": "cashio", - "sourceUrl": "https://cashio.app/#/print", - "twitter": "https://twitter.com/CashioApp", - "website": "https://cashio.app" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "name": "Cashio Dollar", - "symbol": "CASH", - "tags": ["stablecoin", "saber-mkt-usd"] - } - ], - "underlyingIcons": [ - { - "symbol": "USDT", - "name": "USDT (Saber Devnet)", - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/103/EJwZgeZrdC8TXTQbQBoL6bfuAnFUUy1PVCMB4DYPzVaS.svg", - "address": "EJwZgeZrdC8TXTQbQBoL6bfuAnFUUy1PVCMB4DYPzVaS", - "decimals": 6, - "chainId": 103, - "tags": ["saber-mkt-usd", "stablecoin"], - "extensions": { - "currency": "USD", - "coingeckoId": "tether", - "website": "https://saber.so/" - } - }, - { - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 103, - "decimals": 6, - "extensions": { - "coingeckoId": "usd-coin", - "currency": "USD", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "medium": "https://medium.com/@cashioapp", - "source": "cashio", - "sourceUrl": "https://cashio.app/#/print", - "twitter": "https://twitter.com/CashioApp", - "website": "https://cashio.app" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "name": "Cashio Dollar", - "symbol": "CASH", - "tags": ["stablecoin", "saber-mkt-usd"] - } - ], - "currency": "USD", - "lpToken": { - "symbol": "USDT-CASH", - "name": "Saber USDT-CASH LP", - "logoURI": "https://registry.saber.so/token-icons/slp.png", - "decimals": 6, - "address": "JEETZ6QBjvtu8UYYwGWrfLiLj6hjaW4YyErxZ1NC3Fk4", - "chainId": 103, - "tags": ["saber-stableswap-lp"], - "extensions": { - "website": "https://app.saber.so/#/pools/usdt_cash", - "underlyingTokens": [ - "EJwZgeZrdC8TXTQbQBoL6bfuAnFUUy1PVCMB4DYPzVaS", - "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT" - ], - "source": "saber" - } - }, - "plotKey": "Awc4HaWid9Ev8iqWMPkDwaaB5jYxQSKRHuyi2YiGscmQ", - "swap": { - "config": { - "swapAccount": "TEJVTFTsqFEuoNNGu864ED4MJuZr8weByrsYYpZGCfQ", - "swapProgramID": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", - "tokenProgramID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", - "authority": "52ZVLaKbh1jumxHWxiNpv4igyUvfMz8TbP7Vogcw2VDE" - }, - "state": { - "isInitialized": true, - "isPaused": false, - "nonce": 255, - "futureAdminDeadline": 0, - "futureAdminAccount": "11111111111111111111111111111111", - "adminAccount": "2Wdnp1YTGwfiDLLgZ7wJFs6ySThFbMqRJzsbZCw2XcMR", - "tokenA": { - "adminFeeAccount": "HS4ht1Fu5kuwL9nQuN9nkg83Yia3STjfYLyor33oYhjV", - "reserve": "F9tk55FWRKMQFJqh9nX3ro9ePsZK6AFiNCnah3q42UQB", - "mint": "EJwZgeZrdC8TXTQbQBoL6bfuAnFUUy1PVCMB4DYPzVaS" - }, - "tokenB": { - "adminFeeAccount": "GSWNHcmVJV6as7GdpsAPT7YoRHNMBEvuTGNDbjiVAgxq", - "reserve": "5gmJrKK9BvEs1FtkrZBwwyok1a3cU6TLcFTwrJ7Lg7PU", - "mint": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT" - }, - "poolTokenMint": "JEETZ6QBjvtu8UYYwGWrfLiLj6hjaW4YyErxZ1NC3Fk4", - "initialAmpFactor": "07d0", - "targetAmpFactor": "07d0", - "startRampTimestamp": 0, - "stopRampTimestamp": 0, - "fees": { - "adminTrade": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "adminWithdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - }, - "trade": { - "formatted": "0.0400000000", - "numerator": "4", - "denominator": "10000" - }, - "withdraw": { - "formatted": "0.0000000000", - "numerator": "0", - "denominator": "10000" - } - } - } - }, - "quarry": "HTRAA85HHxsRmozFiZYv2AwQWjqHo1XnPWsc76zPbiFE" - } - ] -} diff --git a/farms/farm-ctrl/metadata/programs/programs.json b/farms/farm-ctrl/metadata/programs/programs.json deleted file mode 100644 index 682be3a7d45..00000000000 --- a/farms/farm-ctrl/metadata/programs/programs.json +++ /dev/null @@ -1,372 +0,0 @@ -{ - "name": "Solana Programs List", - "timestamp": "2021-08-22T17:25:00+0000", - "programs": [ - { - "name": "System", - "description": "", - "program_type": "System", - "address": "11111111111111111111111111111111" - }, - { - "name": "BpfLoader2", - "description": "", - "program_type": "System", - "address": "BPFLoader2111111111111111111111111111111111" - }, - { - "name": "BpfLoader", - "description": "", - "program_type": "System", - "address": "BPFLoader1111111111111111111111111111111111" - }, - { - "name": "BpfLoaderUpgradeable", - "description": "", - "program_type": "System", - "address": "BPFLoaderUpgradeab1e11111111111111111111111" - }, - { - "name": "Feature", - "description": "", - "program_type": "System", - "address": "Feature111111111111111111111111111111111111" - }, - { - "name": "Config", - "description": "", - "program_type": "System", - "address": "Config1111111111111111111111111111111111111" - }, - { - "name": "Stake", - "description": "", - "program_type": "System", - "address": "Stake11111111111111111111111111111111111111" - }, - { - "name": "StakeConfig", - "description": "", - "program_type": "System", - "address": "StakeConfig11111111111111111111111111111111" - }, - { - "name": "Vote", - "description": "", - "program_type": "System", - "address": "Vote111111111111111111111111111111111111111" - }, - { - "name": "Secp256k1", - "description": "", - "program_type": "System", - "address": "KeccakSecp256k11111111111111111111111111111" - }, - { - "name": "Sysvar", - "description": "", - "program_type": "System", - "address": "Sysvar1111111111111111111111111111111111111" - }, - { - "name": "SysvarClock", - "description": "", - "program_type": "System", - "address": "SysvarC1ock11111111111111111111111111111111" - }, - { - "name": "SysvarEpochSchedule", - "description": "", - "program_type": "System", - "address": "SysvarEpochSchedu1e111111111111111111111111" - }, - { - "name": "SysvarRent", - "description": "", - "program_type": "System", - "address": "SysvarRent111111111111111111111111111111111" - }, - { - "name": "SysvarFees", - "description": "", - "program_type": "System", - "address": "SysvarFees111111111111111111111111111111111" - }, - { - "name": "SysvarRewards", - "description": "", - "program_type": "System", - "address": "SysvarRewards111111111111111111111111111111" - }, - { - "name": "SysvarInstructions", - "description": "", - "program_type": "System", - "address": "Sysvar1nstructions1111111111111111111111111" - }, - { - "name": "SysvarSlotHashes", - "description": "", - "program_type": "System", - "address": "SysvarS1otHashes111111111111111111111111111" - }, - { - "name": "SysvarSlotHistory", - "description": "", - "program_type": "System", - "address": "SysvarS1otHistory11111111111111111111111111" - }, - { - "name": "SysvarStakeHistory", - "description": "", - "program_type": "System", - "address": "SysvarStakeHistory1111111111111111111111111" - }, - { - "name": "SysvarRecentBlockHashes", - "description": "", - "program_type": "System", - "address": "SysvarRecentB1ockHashes11111111111111111111" - }, - { - "name": "SplToken", - "description": "", - "program_type": "System", - "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - { - "name": "SplTokenMetadata", - "description": "", - "program_type": "System", - "address": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s" - }, - { - "name": "SplTokenVault", - "description": "", - "program_type": "System", - "address": "vau1zxA2LbssAUEF7Gpw91zMM1LvXrvpzJtmZ58rPsn" - }, - { - "name": "SplTokenMint", - "description": "", - "program_type": "System", - "address": "So11111111111111111111111111111111111111112" - }, - { - "name": "AssociatedToken", - "description": "", - "program_type": "System", - "address": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" - }, - { - "name": "Memo", - "description": "", - "program_type": "System", - "address": "Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo" - }, - { - "name": "Programs", - "description": "", - "program_type": "ProgramsRef", - "address": "" - }, - { - "name": "Vaults", - "description": "", - "program_type": "VaultsRef", - "address": "" - }, - { - "name": "Farms", - "description": "", - "program_type": "FarmsRef", - "address": "" - }, - { - "name": "Pools", - "description": "", - "program_type": "PoolsRef", - "address": "" - }, - { - "name": "Tokens", - "description": "", - "program_type": "TokensRef", - "address": "" - }, - { - "name": "Funds", - "description": "", - "program_type": "TokensRef", - "address": "" - }, - { - "name": "MainRouter", - "description": "", - "program_type": "MainRouter", - "address": "" - }, - { - "name": "RaydiumRouter", - "description": "", - "program_type": "Raydium", - "address": "" - }, - { - "name": "SaberRouter", - "description": "", - "program_type": "Saber", - "address": "" - }, - { - "name": "OrcaRouter", - "description": "", - "program_type": "Orca", - "address": "" - }, - { - "name": "STCVaultRaydium", - "description": "", - "program_type": "Vault", - "address": "" - }, - { - "name": "STCVaultSaber", - "description": "", - "program_type": "Vault", - "address": "" - }, - { - "name": "STCVaultOrca", - "description": "", - "program_type": "Vault", - "address": "" - }, - { - "name": "FarmGovernance", - "description": "", - "program_type": "System", - "address": "" - }, - { - "name": "FarmFund", - "description": "", - "program_type": "System", - "address": "" - }, - { - "name": "SerumV2", - "description": "", - "program_type": "Serum", - "address": "EUqojwWA2rd19FZrzeBncJsm38Jm1hEhE3zsmX3bRc2o" - }, - { - "name": "SerumV3", - "description": "", - "program_type": "Serum", - "address": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin" - }, - { - "name": "RaydiumV2", - "description": "", - "program_type": "Raydium", - "address": "RVKd61ztZW9GUwhRbbLoYVRE5Xf1B2tVscKqwZqXgEr" - }, - { - "name": "RaydiumV3", - "description": "", - "program_type": "Raydium", - "address": "27haf8L6oxUeXrHrgEgsexjSY5hbVUWEmvv9Nyxg8vQv" - }, - { - "name": "RaydiumV4", - "description": "", - "program_type": "Raydium", - "address": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8" - }, - { - "name": "RaydiumStake", - "description": "", - "program_type": "Raydium", - "address": "EhhTKczWMGQt46ynNeRX1WfeagwwJd7ufHvCDjRxjo5Q" - }, - { - "name": "RaydiumStakeV4", - "description": "", - "program_type": "Raydium", - "address": "CBuCnLe26faBpcBP2fktp4rp8abpcAnTWft6ZrP5Q4T" - }, - { - "name": "RaydiumStakeV5", - "description": "", - "program_type": "Raydium", - "address": "9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z" - }, - { - "name": "RaydiumIDO", - "description": "", - "program_type": "Raydium", - "address": "6FJon3QE27qgPVggARueB22hLvoh22VzJpXv4rBEoSLF" - }, - { - "name": "RaydiumIDOV4", - "description": "", - "program_type": "Raydium", - "address": "CC12se5To1CdEuw7fDS27B7Geo5jJyL7t5UK2B44NgiH" - }, - { - "name": "RaydiumIDOV5", - "description": "", - "program_type": "Raydium", - "address": "9HzJyW1qZsEiSfMUf6L2jo3CcTKAyBmSyKdwQeYisHrC" - }, - { - "name": "SaberStableSwap", - "description": "", - "program_type": "Saber", - "address": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ" - }, - { - "name": "SaberQuarryMine", - "description": "", - "program_type": "Saber", - "address": "QMNeHCGYnLVDn1icRAfQZpjPLBNkfGbSKRB83G5d8KB" - }, - { - "name": "SaberRedeemer", - "description": "", - "program_type": "Saber", - "address": "RDM23yr8pr1kEAmhnFpaabPny6C9UVcEcok3Py5v86X" - }, - { - "name": "SaberMintWrapper", - "description": "", - "program_type": "Saber", - "address": "QMWoBmAyJLAsA1Lh9ugMTw2gciTihncciphzdNzdZYV" - }, - { - "name": "SaberMintProxy", - "description": "", - "program_type": "Saber", - "address": "UBEBk5idELqykEEaycYtQ7iBVrCg6NmvFSzMpdr22mL" - }, - { - "name": "SaberDecimalWrapper", - "description": "", - "program_type": "Saber", - "address": "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB" - }, - { - "name": "OrcaSwap", - "description": "", - "program_type": "Orca", - "address": "9W959DqEETiGZocYWCQPaJ6sBmUzgfxXfqGeTEdp3aQP" - }, - { - "name": "OrcaStake", - "description": "", - "program_type": "Orca", - "address": "82yxjeMsvaURa4MbZZ7WZZHfobirZYkH1zF8fmeGtyaQ" - } - ] -} diff --git a/farms/farm-ctrl/metadata/programs/programs_dev.json b/farms/farm-ctrl/metadata/programs/programs_dev.json deleted file mode 100644 index b66d4492756..00000000000 --- a/farms/farm-ctrl/metadata/programs/programs_dev.json +++ /dev/null @@ -1,312 +0,0 @@ -{ - "name": "Solana Programs List", - "timestamp": "2021-08-22T17:25:00+0000", - "programs": [ - { - "name": "System", - "description": "", - "program_type": "System", - "address": "11111111111111111111111111111111" - }, - { - "name": "BpfLoader2", - "description": "", - "program_type": "System", - "address": "BPFLoader2111111111111111111111111111111111" - }, - { - "name": "BpfLoader", - "description": "", - "program_type": "System", - "address": "BPFLoader1111111111111111111111111111111111" - }, - { - "name": "BpfLoaderUpgradeable", - "description": "", - "program_type": "System", - "address": "BPFLoaderUpgradeab1e11111111111111111111111" - }, - { - "name": "Feature", - "description": "", - "program_type": "System", - "address": "Feature111111111111111111111111111111111111" - }, - { - "name": "Config", - "description": "", - "program_type": "System", - "address": "Config1111111111111111111111111111111111111" - }, - { - "name": "Stake", - "description": "", - "program_type": "System", - "address": "Stake11111111111111111111111111111111111111" - }, - { - "name": "StakeConfig", - "description": "", - "program_type": "System", - "address": "StakeConfig11111111111111111111111111111111" - }, - { - "name": "Vote", - "description": "", - "program_type": "System", - "address": "Vote111111111111111111111111111111111111111" - }, - { - "name": "Secp256k1", - "description": "", - "program_type": "System", - "address": "KeccakSecp256k11111111111111111111111111111" - }, - { - "name": "Sysvar", - "description": "", - "program_type": "System", - "address": "Sysvar1111111111111111111111111111111111111" - }, - { - "name": "SysvarClock", - "description": "", - "program_type": "System", - "address": "SysvarC1ock11111111111111111111111111111111" - }, - { - "name": "SysvarEpochSchedule", - "description": "", - "program_type": "System", - "address": "SysvarEpochSchedu1e111111111111111111111111" - }, - { - "name": "SysvarRent", - "description": "", - "program_type": "System", - "address": "SysvarRent111111111111111111111111111111111" - }, - { - "name": "SysvarFees", - "description": "", - "program_type": "System", - "address": "SysvarFees111111111111111111111111111111111" - }, - { - "name": "SysvarRewards", - "description": "", - "program_type": "System", - "address": "SysvarRewards111111111111111111111111111111" - }, - { - "name": "SysvarInstructions", - "description": "", - "program_type": "System", - "address": "Sysvar1nstructions1111111111111111111111111" - }, - { - "name": "SysvarSlotHashes", - "description": "", - "program_type": "System", - "address": "SysvarS1otHashes111111111111111111111111111" - }, - { - "name": "SysvarSlotHistory", - "description": "", - "program_type": "System", - "address": "SysvarS1otHistory11111111111111111111111111" - }, - { - "name": "SysvarStakeHistory", - "description": "", - "program_type": "System", - "address": "SysvarStakeHistory1111111111111111111111111" - }, - { - "name": "SysvarRecentBlockHashes", - "description": "", - "program_type": "System", - "address": "SysvarRecentB1ockHashes11111111111111111111" - }, - { - "name": "SplToken", - "description": "", - "program_type": "System", - "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - }, - { - "name": "SplTokenMetadata", - "description": "", - "program_type": "System", - "address": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s" - }, - { - "name": "SplTokenVault", - "description": "", - "program_type": "System", - "address": "vau1zxA2LbssAUEF7Gpw91zMM1LvXrvpzJtmZ58rPsn" - }, - { - "name": "SplTokenMint", - "description": "", - "program_type": "System", - "address": "So11111111111111111111111111111111111111112" - }, - { - "name": "AssociatedToken", - "description": "", - "program_type": "System", - "address": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" - }, - { - "name": "Memo", - "description": "", - "program_type": "System", - "address": "Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo" - }, - { - "name": "Programs", - "description": "", - "program_type": "ProgramsRef", - "address": "" - }, - { - "name": "Vaults", - "description": "", - "program_type": "VaultsRef", - "address": "" - }, - { - "name": "Farms", - "description": "", - "program_type": "FarmsRef", - "address": "" - }, - { - "name": "Pools", - "description": "", - "program_type": "PoolsRef", - "address": "" - }, - { - "name": "Tokens", - "description": "", - "program_type": "TokensRef", - "address": "" - }, - { - "name": "Funds", - "description": "", - "program_type": "TokensRef", - "address": "" - }, - { - "name": "MainRouter", - "description": "", - "program_type": "MainRouter", - "address": "" - }, - { - "name": "RaydiumRouter", - "description": "", - "program_type": "Raydium", - "address": "" - }, - { - "name": "SaberRouter", - "description": "", - "program_type": "Saber", - "address": "" - }, - { - "name": "OrcaRouter", - "description": "", - "program_type": "Orca", - "address": "" - }, - { - "name": "STCVaultRaydium", - "description": "", - "program_type": "Vault", - "address": "" - }, - { - "name": "STCVaultSaber", - "description": "", - "program_type": "Vault", - "address": "" - }, - { - "name": "STCVaultOrca", - "description": "", - "program_type": "Vault", - "address": "" - }, - { - "name": "FarmGovernance", - "description": "", - "program_type": "System", - "address": "" - }, - { - "name": "FarmFund", - "description": "", - "program_type": "System", - "address": "" - }, - { - "name": "SerumV3", - "description": "", - "program_type": "Serum", - "address": "DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY" - }, - { - "name": "RaydiumV4", - "description": "", - "program_type": "Raydium", - "address": "9rpQHSyFVM1dkkHFQ2TtTzPEW7DVmEyPmN8wVniqJtuC" - }, - { - "name": "RaydiumStakeV5", - "description": "", - "program_type": "Raydium", - "address": "EcLzTrNg9V7qhcdyXDe2qjtPkiGzDM2UbdRaeaadU5r2" - }, - { - "name": "SaberStableSwap", - "description": "", - "program_type": "Saber", - "address": "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ" - }, - { - "name": "SaberQuarryMine", - "description": "", - "program_type": "Saber", - "address": "QMNeHCGYnLVDn1icRAfQZpjPLBNkfGbSKRB83G5d8KB" - }, - { - "name": "SaberRedeemer", - "description": "", - "program_type": "Saber", - "address": "RDM23yr8pr1kEAmhnFpaabPny6C9UVcEcok3Py5v86X" - }, - { - "name": "SaberMintWrapper", - "description": "", - "program_type": "Saber", - "address": "QMWoBmAyJLAsA1Lh9ugMTw2gciTihncciphzdNzdZYV" - }, - { - "name": "SaberMintProxy", - "description": "", - "program_type": "Saber", - "address": "UBEBk5idELqykEEaycYtQ7iBVrCg6NmvFSzMpdr22mL" - }, - { - "name": "SaberDecimalWrapper", - "description": "", - "program_type": "Saber", - "address": "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB" - } - ] -} diff --git a/farms/farm-ctrl/metadata/tokens/raydium/get_tokens.sh b/farms/farm-ctrl/metadata/tokens/raydium/get_tokens.sh deleted file mode 100644 index 672f30de50a..00000000000 --- a/farms/farm-ctrl/metadata/tokens/raydium/get_tokens.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -url="https://api.raydium.io/v2/sdk/token/raydium.mainnet.json" - -if hash wget 2>/dev/null; then - wget_or_curl="wget -O tokens.json $url" -elif hash curl 2>/dev/null; then - wget_or_curl="curl -o tokens.json -L $url" -else - echo "Error: Neither curl nor wget were found" >&2 - return 1 -fi - -exec $wget_or_curl \ No newline at end of file diff --git a/farms/farm-ctrl/metadata/tokens/raydium/tokens.json b/farms/farm-ctrl/metadata/tokens/raydium/tokens.json deleted file mode 100644 index db3c45d3b78..00000000000 --- a/farms/farm-ctrl/metadata/tokens/raydium/tokens.json +++ /dev/null @@ -1,9550 +0,0 @@ -{ - "name": "Raydium Mainnet Token List", - "timestamp": "2022-06-10T07:38:09+0000", - "version": { "major": 1, "minor": 0, "patch": 0 }, - "official": [ - { - "symbol": "SOL", - "name": "Native Solana", - "mint": "11111111111111111111111111111111", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/So11111111111111111111111111111111111111112.png" - }, - { - "symbol": "PLD", - "name": "Plutonian DAO", - "mint": "2cJgFtnqjaoiu9fKVX3fny4Z4pRzuaqfJ3PBTMk2D9ur", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2cJgFtnqjaoiu9fKVX3fny4Z4pRzuaqfJ3PBTMk2D9ur.png" - }, - { - "symbol": "soETH", - "name": "Wrapped Ethereum (Sollet)", - "mint": "2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk", - "decimals": 6, - "extensions": { "coingeckoId": "wrapped-ethereum-sollet" }, - "icon": "https://img.raydium.io/icon/2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk.png" - }, - { - "symbol": "Solar", - "name": "Solar", - "mint": "2wmKXX1xsxLfrvjEPrt2UHiqj8Gbzwxvffr9qmNjsw8g", - "decimals": 9, - "extensions": { "coingeckoId": "solar" }, - "icon": "https://img.raydium.io/icon/2wmKXX1xsxLfrvjEPrt2UHiqj8Gbzwxvffr9qmNjsw8g.png" - }, - { - "symbol": "ISOLA", - "name": "ISOLA", - "mint": "333iHoRM2Awhf9uVZtSyTfU8AekdGrgQePZsKMFPgKmS", - "decimals": 6, - "extensions": { "coingeckoId": "intersola" }, - "icon": "https://img.raydium.io/icon/333iHoRM2Awhf9uVZtSyTfU8AekdGrgQePZsKMFPgKmS.png" - }, - { - "symbol": "LIKE", - "name": "LIKE", - "mint": "3bRTivrVsitbmCTGtqwp7hxXPsybkjn4XLNtPsHqa3zR", - "decimals": 9, - "extensions": { "coingeckoId": "only1" }, - "icon": "https://img.raydium.io/icon/3bRTivrVsitbmCTGtqwp7hxXPsybkjn4XLNtPsHqa3zR.png" - }, - { - "symbol": "CHEEMS", - "name": "CHEEMS", - "mint": "3FoUAsGDbvTD6YZ4wVKJgTB76onJUKz7GPEBNiR5b8wc", - "decimals": 4, - "extensions": { "coingeckoId": "cheems" }, - "icon": "https://img.raydium.io/icon/3FoUAsGDbvTD6YZ4wVKJgTB76onJUKz7GPEBNiR5b8wc.png" - }, - { - "symbol": "soYFI", - "name": "Wrapped YFI (Sollet)", - "mint": "3JSf5tPeuscJGtaCp5giEiDhv51gQ4v3zWg8DGgyLfAB", - "decimals": 6, - "extensions": { "coingeckoId": "wrapped-yfi-sollet" }, - "icon": "https://img.raydium.io/icon/3JSf5tPeuscJGtaCp5giEiDhv51gQ4v3zWg8DGgyLfAB.png" - }, - { - "symbol": "XCOPE", - "name": "XCOPE", - "mint": "3K6rftdAaQYMPunrtNRHgnK2UAtjm2JwyT2oCiTDouYE", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3K6rftdAaQYMPunrtNRHgnK2UAtjm2JwyT2oCiTDouYE.png" - }, - { - "symbol": "SAND", - "name": "Sandbox (Wormhole)", - "mint": "49c7WuCZkQgc3M4qH8WuEUNXfgwupZf1xqWkDQ7gjRGt", - "decimals": 8, - "extensions": { "coingeckoId": "the-sandbox-wormhole" }, - "icon": "https://img.raydium.io/icon/49c7WuCZkQgc3M4qH8WuEUNXfgwupZf1xqWkDQ7gjRGt.png" - }, - { - "symbol": "SNY", - "name": "SNY", - "mint": "4dmKkXNHdgYsXqBHCuMikNQWwVomZURhYvkkX5c4pQ7y", - "decimals": 6, - "extensions": { "coingeckoId": "synthetify-token" }, - "icon": "https://img.raydium.io/icon/4dmKkXNHdgYsXqBHCuMikNQWwVomZURhYvkkX5c4pQ7y.png" - }, - { - "symbol": "DYDX", - "name": "dYdX (Wormhole)", - "mint": "4Hx6Bj56eGyw8EJrrheM6LBQAvVYRikYCWsALeTrwyRU", - "decimals": 8, - "extensions": { "coingeckoId": "dydx-wormhole" }, - "icon": "https://img.raydium.io/icon/4Hx6Bj56eGyw8EJrrheM6LBQAvVYRikYCWsALeTrwyRU.png" - }, - { - "symbol": "RAY", - "name": "Raydium", - "mint": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "decimals": 6, - "extensions": { "coingeckoId": "raydium" }, - "icon": "https://img.raydium.io/icon/4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R.png" - }, - { - "symbol": "CAVE", - "name": "CAVE", - "mint": "4SZjjNABoqhbd4hnapbvoEPEqT8mnNkfbEoAwALf1V8t", - "decimals": 6, - "extensions": { "coingeckoId": "cave" }, - "icon": "https://img.raydium.io/icon/4SZjjNABoqhbd4hnapbvoEPEqT8mnNkfbEoAwALf1V8t.png" - }, - { - "symbol": "OXS", - "name": "OXS", - "mint": "4TGxgCSJQx2GQk9oHZ8dC5m3JNXTYZHjXumKAW3vLnNx", - "decimals": 9, - "extensions": { "coingeckoId": "oxbull-solana" }, - "icon": "https://img.raydium.io/icon/4TGxgCSJQx2GQk9oHZ8dC5m3JNXTYZHjXumKAW3vLnNx.png" - }, - { - "symbol": "LIQ", - "name": "LIQ", - "mint": "4wjPQJ6PrkC4dHhYghwJzGBVP78DkBzA2U3kHoFNBuhj", - "decimals": 6, - "extensions": { "coingeckoId": "liq-protocol" }, - "icon": "https://img.raydium.io/icon/4wjPQJ6PrkC4dHhYghwJzGBVP78DkBzA2U3kHoFNBuhj.png" - }, - { - "symbol": "APEX", - "name": "APEX", - "mint": "51tMb3zBKDiQhNwGqpgwbavaGH54mk8fXFzxTc1xnasg", - "decimals": 9, - "extensions": { "coingeckoId": "apexit-finance" }, - "icon": "https://img.raydium.io/icon/51tMb3zBKDiQhNwGqpgwbavaGH54mk8fXFzxTc1xnasg.png" - }, - { - "symbol": "soCREAM", - "name": "Wrapped Cream Finance (Sollet)", - "mint": "5Fu5UUgbjpUvdBveb3a1JTNirL8rXtiYeSMWvKjtUNQv", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5Fu5UUgbjpUvdBveb3a1JTNirL8rXtiYeSMWvKjtUNQv.png" - }, - { - "symbol": "XTAG", - "name": "XTAG", - "mint": "5gs8nf4wojB5EXgDUWNLwXpknzgV2YWDhveAeBZpVLbp", - "decimals": 6, - "extensions": { "coingeckoId": "xhashtag" }, - "icon": "https://img.raydium.io/icon/5gs8nf4wojB5EXgDUWNLwXpknzgV2YWDhveAeBZpVLbp.png" - }, - { - "symbol": "DOGO", - "name": "Dogemon", - "mint": "5LSFpvLDkcdV2a3Kiyzmg5YmJsj2XDLySaXvnfP1cgLT", - "decimals": 6, - "extensions": { "coingeckoId": "dogemon-go" }, - "icon": "https://img.raydium.io/icon/5LSFpvLDkcdV2a3Kiyzmg5YmJsj2XDLySaXvnfP1cgLT.png" - }, - { - "symbol": "ENRX", - "name": "Enrex", - "mint": "5s4BYUXLuvs9ZcVDTxkTpKhThWFSpaU8GG55q2iySe2N", - "decimals": 2, - "extensions": { "coingeckoId": "enrex" }, - "icon": "https://img.raydium.io/icon/5s4BYUXLuvs9ZcVDTxkTpKhThWFSpaU8GG55q2iySe2N.png" - }, - { - "symbol": "WAG", - "name": "WAG", - "mint": "5tN42n9vMi6ubp67Uy4NnmM5DMZYN8aS8GeB3bEDHr6E", - "decimals": 9, - "extensions": { "coingeckoId": "waggle-network" }, - "icon": "https://img.raydium.io/icon/5tN42n9vMi6ubp67Uy4NnmM5DMZYN8aS8GeB3bEDHr6E.png" - }, - { - "symbol": "SPWN", - "name": "SPWN", - "mint": "5U9QqCPhqXAJcEv9uyzFJd5zhN93vuPk1aNNkXnUfPnt", - "decimals": 9, - "extensions": { "coingeckoId": "bitspawn" }, - "icon": "https://img.raydium.io/icon/5U9QqCPhqXAJcEv9uyzFJd5zhN93vuPk1aNNkXnUfPnt.png" - }, - { - "symbol": "CMFI", - "name": "Compendium Finance", - "mint": "5Wsd311hY8NXQhkt9cWHwTnqafk7BGEbLu8Py3DSnPAr", - "decimals": 6, - "extensions": { "coingeckoId": "compendium-fi" }, - "icon": "https://img.raydium.io/icon/5Wsd311hY8NXQhkt9cWHwTnqafk7BGEbLu8Py3DSnPAr.png" - }, - { - "symbol": "PRGC", - "name": "ProtoReality Games Token", - "mint": "66edZnAPEJSxnAK4SckuupssXpbu5doV57FUcghaqPsY", - "decimals": 9, - "extensions": { "coingeckoId": "protoreality-games" }, - "icon": "https://img.raydium.io/icon/66edZnAPEJSxnAK4SckuupssXpbu5doV57FUcghaqPsY.png" - }, - { - "symbol": "$WOOD", - "name": "$WOOD", - "mint": "674PmuiDtgKx3uKuJ1B16f9m5L84eFvNwj3xDMvHcbo7", - "decimals": 9, - "extensions": { "coingeckoId": "mindfolk-wood" }, - "icon": "https://img.raydium.io/icon/674PmuiDtgKx3uKuJ1B16f9m5L84eFvNwj3xDMvHcbo7.png" - }, - { - "symbol": "SHILL", - "name": "SHILL", - "mint": "6cVgJUqo4nmvQpbgrDZwyfd6RwWw5bfnCamS3M9N1fd", - "decimals": 6, - "extensions": { "coingeckoId": "shill-token" }, - "icon": "https://img.raydium.io/icon/6cVgJUqo4nmvQpbgrDZwyfd6RwWw5bfnCamS3M9N1fd.png" - }, - { - "symbol": "RUN", - "name": "RUN", - "mint": "6F9XriABHfWhit6zmMUYAQBSy6XK5VF1cHXuW5LDpRtC", - "decimals": 9, - "extensions": { "coingeckoId": "run" }, - "icon": "https://img.raydium.io/icon/6F9XriABHfWhit6zmMUYAQBSy6XK5VF1cHXuW5LDpRtC.png" - }, - { - "symbol": "ROLL", - "name": "HRHC Token", - "mint": "76aYNHbDfHemxSS7vmh6eJGfjodK8m7srCxiYCrKxzY1", - "decimals": 6, - "extensions": { "coingeckoId": "high-roller-hippo-clique" }, - "icon": "https://img.raydium.io/icon/76aYNHbDfHemxSS7vmh6eJGfjodK8m7srCxiYCrKxzY1.png" - }, - { - "symbol": "MANA", - "name": "Decentraland (Wormhole)", - "mint": "7dgHoN8wBZCc5wbnQ2C47TDnBMAxG4Q5L3KjP67z8kNi", - "decimals": 8, - "extensions": { "coingeckoId": "decentraland-wormhole" }, - "icon": "https://img.raydium.io/icon/7dgHoN8wBZCc5wbnQ2C47TDnBMAxG4Q5L3KjP67z8kNi.png" - }, - { - "symbol": "stSOL", - "name": "stSOL", - "mint": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "decimals": 9, - "extensions": { "coingeckoId": "lido-staked-sol" }, - "icon": "https://img.raydium.io/icon/7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj.png" - }, - { - "symbol": "JSOL", - "name": "JSOL", - "mint": "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn", - "decimals": 9, - "extensions": { "coingeckoId": "jpool" }, - "icon": "https://img.raydium.io/icon/7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn.png" - }, - { - "symbol": "ETH", - "name": "Ether (Wormhole)", - "mint": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "decimals": 8, - "extensions": { "coingeckoId": "ethereum-wormhole" }, - "icon": "https://img.raydium.io/icon/7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs.png" - }, - { - "symbol": "SAMO", - "name": "Samoyed Coin", - "mint": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU", - "decimals": 9, - "extensions": { "coingeckoId": "samoyedcoin" }, - "icon": "https://img.raydium.io/icon/7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU.png" - }, - { - "symbol": "VI", - "name": "VI", - "mint": "7zBWymxbZt7PVHQzfi3i85frc1YRiQc23K7bh3gos8ZC", - "decimals": 9, - "extensions": { "coingeckoId": "vybit" }, - "icon": "https://img.raydium.io/icon/7zBWymxbZt7PVHQzfi3i85frc1YRiQc23K7bh3gos8ZC.png" - }, - { - "symbol": "UNI", - "name": "Uniswap (Wormhole)", - "mint": "8FU95xFJhUUkyyCLU13HSzDLs7oC4QZdXQHL6SCeab36", - "decimals": 8, - "extensions": { "coingeckoId": "uniswap-wormhole" }, - "icon": "https://img.raydium.io/icon/8FU95xFJhUUkyyCLU13HSzDLs7oC4QZdXQHL6SCeab36.png" - }, - { - "symbol": "COPE", - "name": "COPE", - "mint": "8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh", - "decimals": 6, - "extensions": { "coingeckoId": "cope" }, - "icon": "https://img.raydium.io/icon/8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh.png" - }, - { - "symbol": "ROPE", - "name": "ROPE", - "mint": "8PMHT4swUMtBzgHnh5U564N5sjPSiUz2cjEQzFnnP1Fo", - "decimals": 9, - "extensions": { "coingeckoId": "rope-token" }, - "icon": "https://img.raydium.io/icon/8PMHT4swUMtBzgHnh5U564N5sjPSiUz2cjEQzFnnP1Fo.png" - }, - { - "symbol": "GRAPE", - "name": "GRAPE", - "mint": "8upjSpvjcdpuzhfR1zriwg5NXkwDruejqNE9WNbPRtyA", - "decimals": 6, - "extensions": { "coingeckoId": "grape-2" }, - "icon": "https://img.raydium.io/icon/8upjSpvjcdpuzhfR1zriwg5NXkwDruejqNE9WNbPRtyA.png" - }, - { - "symbol": "soSWAG", - "name": "Wrapped SWAG (Sollet)", - "mint": "9F9fNTT6qwjsu4X4yWYKZpsbw5qT7o6yR2i57JF2jagy", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9F9fNTT6qwjsu4X4yWYKZpsbw5qT7o6yR2i57JF2jagy.png" - }, - { - "symbol": "BNB", - "name": "Binance Coin (Wormhole)", - "mint": "9gP2kCy3wA1ctvYWQk75guqXuHfrEomqydHLtcTCqiLa", - "decimals": 8, - "extensions": { "coingeckoId": "binance-coin-wormhole" }, - "icon": "https://img.raydium.io/icon/9gP2kCy3wA1ctvYWQk75guqXuHfrEomqydHLtcTCqiLa.png" - }, - { - "symbol": "AUDIO", - "name": "Audius (Wormhole)", - "mint": "9LzCMqDgTKYz9Drzqnpgee3SGa89up3a247ypMj2xrqM", - "decimals": 8, - "extensions": { "coingeckoId": "audius-wormhole" }, - "icon": "https://img.raydium.io/icon/9LzCMqDgTKYz9Drzqnpgee3SGa89up3a247ypMj2xrqM.png" - }, - { - "symbol": "BTC", - "name": "Wrapped Bitcoin", - "mint": "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "decimals": 6, - "extensions": { "coingeckoId": "bitcoin" }, - "icon": "https://img.raydium.io/icon/9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E.png" - }, - { - "symbol": "WOOF", - "name": "WOOF", - "mint": "9nEqaUcb16sQ3Tn1psbkWqyhPdLmfHWjKGymREjsAgTE", - "decimals": 6, - "extensions": { "coingeckoId": "woof-token" }, - "icon": "https://img.raydium.io/icon/9nEqaUcb16sQ3Tn1psbkWqyhPdLmfHWjKGymREjsAgTE.png" - }, - { - "symbol": "MIMO", - "name": "MIMO", - "mint": "9TE7ebz1dsFo1uQ2T4oYAKSm39Y6fWuHrd6Uk6XaiD16", - "decimals": 9, - "extensions": { "coingeckoId": "million-monke" }, - "icon": "https://img.raydium.io/icon/9TE7ebz1dsFo1uQ2T4oYAKSm39Y6fWuHrd6Uk6XaiD16.png" - }, - { - "symbol": "UST", - "name": "UST (Wormhole)", - "mint": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "decimals": 6, - "extensions": { "coingeckoId": "terrausd-wormhole" }, - "icon": "https://img.raydium.io/icon/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i.png" - }, - { - "symbol": "STR", - "name": "STR", - "mint": "9zoqdwEBKWEi9G5Ze8BSkdmppxGgVv1Kw4LuigDiNr9m", - "decimals": 9, - "extensions": { "coingeckoId": "solster" }, - "icon": "https://img.raydium.io/icon/9zoqdwEBKWEi9G5Ze8BSkdmppxGgVv1Kw4LuigDiNr9m.png" - }, - { - "symbol": "ABR", - "name": "ABR", - "mint": "a11bdAAuV8iB2fu7X6AxAvDTo1QZ8FXB3kk5eecdasp", - "decimals": 9, - "extensions": { "coingeckoId": "allbridge" }, - "icon": "https://img.raydium.io/icon/a11bdAAuV8iB2fu7X6AxAvDTo1QZ8FXB3kk5eecdasp.png" - }, - { - "symbol": "MODUL", - "name": "Modul", - "mint": "A98UDy7z8MfmWnTQt6cKjje7UfqV3pTLf4yEbuwL2HrH", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/A98UDy7z8MfmWnTQt6cKjje7UfqV3pTLf4yEbuwL2HrH.png" - }, - { - "symbol": "DGE", - "name": "DarleyGo Essence", - "mint": "AAXng5czWLNtTXHdWEn9Ef7kXMXEaraHj2JQKo7ZoLux", - "decimals": 9, - "extensions": { "coingeckoId": "darleygo-essence" }, - "icon": "https://img.raydium.io/icon/AAXng5czWLNtTXHdWEn9Ef7kXMXEaraHj2JQKo7ZoLux.png" - }, - { - "symbol": "REAL", - "name": "REAL", - "mint": "AD27ov5fVU2XzwsbvnFvb1JpCBaCB5dRXrczV9CqSVGb", - "decimals": 9, - "extensions": { "coingeckoId": "realy-metaverse" }, - "icon": "https://img.raydium.io/icon/AD27ov5fVU2XzwsbvnFvb1JpCBaCB5dRXrczV9CqSVGb.png" - }, - { - "symbol": "GST", - "name": "GST", - "mint": "AFbX8oGjGpmVFywbVouvhQSRmiW2aR1mohfahi4Y2AdB", - "decimals": 9, - "extensions": { "coingeckoId": "green-satoshi-token" }, - "icon": "https://img.raydium.io/icon/AFbX8oGjGpmVFywbVouvhQSRmiW2aR1mohfahi4Y2AdB.png" - }, - { - "symbol": "soFTT", - "name": "Wrapped FTT (Sollet)", - "mint": "AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3", - "decimals": 6, - "extensions": { "coingeckoId": "ftx-token" }, - "icon": "https://img.raydium.io/icon/AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3.png" - }, - { - "symbol": "BOT", - "name": "BOT", - "mint": "AkhdZGVbJXPuQZ53u2LrimCjkRP6ZyxG1SoM85T98eE1", - "decimals": 8, - "extensions": { "coingeckoId": "starbots" }, - "icon": "https://img.raydium.io/icon/AkhdZGVbJXPuQZ53u2LrimCjkRP6ZyxG1SoM85T98eE1.png" - }, - { - "symbol": "ANA", - "name": "ANA", - "mint": "ANAxByE6G2WjFp7A4NqtWYXb3mgruyzZYg3spfxe6Lbo", - "decimals": 6, - "extensions": { "coingeckoId": "nirvana-ana" }, - "icon": "https://img.raydium.io/icon/ANAxByE6G2WjFp7A4NqtWYXb3mgruyzZYg3spfxe6Lbo.png" - }, - { - "symbol": "APT", - "name": "APT", - "mint": "APTtJyaRX5yGTsJU522N4VYWg3vCvSb65eam5GrPT5Rt", - "decimals": 6, - "extensions": { "coingeckoId": "apricot" }, - "icon": "https://img.raydium.io/icon/APTtJyaRX5yGTsJU522N4VYWg3vCvSb65eam5GrPT5Rt.png" - }, - { - "symbol": "soSUSHI", - "name": "Wrapped SUSHI (Sollet)", - "mint": "AR1Mtgh7zAtxuxGd2XPovXPVjcSdY3i4rQYisNadjfKy", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/AR1Mtgh7zAtxuxGd2XPovXPVjcSdY3i4rQYisNadjfKy.png" - }, - { - "symbol": "renDOGE", - "name": "renDOGE", - "mint": "ArUkYE2XDKzqy77PRRGjo4wREWwqk6RXTfM9NeqzPvjU", - "decimals": 8, - "extensions": { "coingeckoId": "rendoge" }, - "icon": "https://img.raydium.io/icon/ArUkYE2XDKzqy77PRRGjo4wREWwqk6RXTfM9NeqzPvjU.png" - }, - { - "symbol": "ATLAS", - "name": "ATLAS", - "mint": "ATLASXmbPQxBUYbxPsV97usA3fPQYEqzQBUHgiFCUsXx", - "decimals": 8, - "extensions": { "coingeckoId": "star-atlas" }, - "icon": "https://img.raydium.io/icon/ATLASXmbPQxBUYbxPsV97usA3fPQYEqzQBUHgiFCUsXx.png" - }, - { - "symbol": "AURY", - "name": "AURY", - "mint": "AURYydfxJib1ZkTir1Jn1J9ECYUtjb6rKQVmtYaixWPP", - "decimals": 9, - "extensions": { "coingeckoId": "aurory" }, - "icon": "https://img.raydium.io/icon/AURYydfxJib1ZkTir1Jn1J9ECYUtjb6rKQVmtYaixWPP.png" - }, - { - "symbol": "BASIS", - "name": "BASIS", - "mint": "Basis9oJw9j8cw53oMV7iqsgo6ihi9ALw4QR31rcjUJa", - "decimals": 6, - "extensions": { "coingeckoId": "basis-markets" }, - "icon": "https://img.raydium.io/icon/Basis9oJw9j8cw53oMV7iqsgo6ihi9ALw4QR31rcjUJa.png" - }, - { - "symbol": "HAWK", - "name": "Hawksight", - "mint": "BKipkearSqAUdNKa1WDstvcMjoPsSKBuNyvKDQDDu9WE", - "decimals": 6, - "extensions": { "coingeckoId": "hawksight" }, - "icon": "https://img.raydium.io/icon/BKipkearSqAUdNKa1WDstvcMjoPsSKBuNyvKDQDDu9WE.png" - }, - { - "symbol": "BOP", - "name": "Boring Protocol", - "mint": "BLwTnYKqf7u4qjgZrrsKeNs2EzWkMLqVCu6j8iHyrNA3", - "decimals": 8, - "extensions": { "coingeckoId": "boring-protocol" }, - "icon": "https://img.raydium.io/icon/BLwTnYKqf7u4qjgZrrsKeNs2EzWkMLqVCu6j8iHyrNA3.png" - }, - { - "symbol": "BONES", - "name": "BONES Token", - "mint": "bonegFPgrpZ4bfVn3kQK1aMbGYddWtfMAywNt5LsuVE", - "decimals": 2, - "extensions": { "coingeckoId": "soul-dog-city-bones" }, - "icon": "https://img.raydium.io/icon/bonegFPgrpZ4bfVn3kQK1aMbGYddWtfMAywNt5LsuVE.png" - }, - { - "symbol": "soUSDT", - "name": "Wrapped USDT (Sollet)", - "mint": "BQcdHdAQW1hczDbBi9hiegXAR7A98Q9jx3X3iBBBDiq4", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BQcdHdAQW1hczDbBi9hiegXAR7A98Q9jx3X3iBBBDiq4.png" - }, - { - "symbol": "CYS", - "name": "CYS", - "mint": "BRLsMczKuaR5w9vSubF4j8HwEGGprVAyyVgS4EX7DKEg", - "decimals": 6, - "extensions": { "coingeckoId": "cyclos" }, - "icon": "https://img.raydium.io/icon/BRLsMczKuaR5w9vSubF4j8HwEGGprVAyyVgS4EX7DKEg.png" - }, - { - "symbol": "soHGET", - "name": "Wrapped Hedget (Sollet)", - "mint": "BtZQfWqDGbk9Wf2rXEiWyQBdBY1etnUUn6zEphvVS7yN", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BtZQfWqDGbk9Wf2rXEiWyQBdBY1etnUUn6zEphvVS7yN.png" - }, - { - "symbol": "SOLC", - "name": "SOLC", - "mint": "Bx1fDtvTN6NvE4kjdPHQXtmGSg582bZx9fGy4DQNMmAT", - "decimals": 9, - "extensions": { "coingeckoId": "solcubator" }, - "icon": "https://img.raydium.io/icon/Bx1fDtvTN6NvE4kjdPHQXtmGSg582bZx9fGy4DQNMmAT.png" - }, - { - "symbol": "soUSDC", - "name": "Wrapped USDC (Sollet)", - "mint": "BXXkv6z8ykpG1yuvUDPgh732wzVHB69RnB9YgSYh3itW", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BXXkv6z8ykpG1yuvUDPgh732wzVHB69RnB9YgSYh3itW.png" - }, - { - "symbol": "renBTC", - "name": "renBTC", - "mint": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "decimals": 8, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5.png" - }, - { - "symbol": "DATE", - "name": "SolDate(DATE) Token", - "mint": "Ce3PSQfkxT5ua4r2JqCoWYrMwKWC5hEzwsrT9Hb7mAz9", - "decimals": 9, - "extensions": { "coingeckoId": "soldate-token" }, - "icon": "https://img.raydium.io/icon/Ce3PSQfkxT5ua4r2JqCoWYrMwKWC5hEzwsrT9Hb7mAz9.png" - }, - { - "symbol": "SOLX", - "name": "SOLX", - "mint": "CH74tuRLTYcxG7qNJCsV9rghfLXJCQJbsu7i52a8F1Gn", - "decimals": 9, - "extensions": { "coingeckoId": "soldex" }, - "icon": "https://img.raydium.io/icon/CH74tuRLTYcxG7qNJCsV9rghfLXJCQJbsu7i52a8F1Gn.png" - }, - { - "symbol": "SUSHI", - "name": "SushiToken (Wormhole)", - "mint": "ChVzxWRmrTeSgwd3Ui3UumcN8KX7VK3WaD4KGeSKpypj", - "decimals": 8, - "extensions": { "coingeckoId": "sushi-wormhole" }, - "icon": "https://img.raydium.io/icon/ChVzxWRmrTeSgwd3Ui3UumcN8KX7VK3WaD4KGeSKpypj.png" - }, - { - "symbol": "SHIB", - "name": "SHIBA INU (Wormhole)", - "mint": "CiKu4eHsVrc1eueVQeHn7qhXTcVu95gSQmBpX4utjL9z", - "decimals": 8, - "extensions": { "coingeckoId": "shiba-inu-wormhole" }, - "icon": "https://img.raydium.io/icon/CiKu4eHsVrc1eueVQeHn7qhXTcVu95gSQmBpX4utjL9z.png" - }, - { - "symbol": "GLXY", - "name": "Astrals GLXY", - "mint": "CJ5U6wPmjxFUyTJpUTS7Rt1UqhTmSVRMvmJ8WD4nndXW", - "decimals": 9, - "extensions": { "coingeckoId": "astrals-glxy" }, - "icon": "https://img.raydium.io/icon/CJ5U6wPmjxFUyTJpUTS7Rt1UqhTmSVRMvmJ8WD4nndXW.png" - }, - { - "symbol": "GARI", - "name": "Gari", - "mint": "CKaKtYvz6dKPyMvYq9Rh3UBrnNqYZAyd7iF4hJtjUvks", - "decimals": 9, - "extensions": { "coingeckoId": "gari-network" }, - "icon": "https://img.raydium.io/icon/CKaKtYvz6dKPyMvYq9Rh3UBrnNqYZAyd7iF4hJtjUvks.png" - }, - { - "symbol": "BOKU", - "name": "BOKU", - "mint": "CN7qFa5iYkHz99PTctvT4xXUHnxwjQ5MHxCuTJtPN5uS", - "decimals": 9, - "extensions": { "coingeckoId": "boku" }, - "icon": "https://img.raydium.io/icon/CN7qFa5iYkHz99PTctvT4xXUHnxwjQ5MHxCuTJtPN5uS.png" - }, - { - "symbol": "PEOPLE", - "name": "ConstitutionDAO (Wormhole)", - "mint": "CobcsUrt3p91FwvULYKorQejgsm5HoQdv5T8RUZ6PnLA", - "decimals": 8, - "extensions": { "coingeckoId": "constitutiondao-wormhole" }, - "icon": "https://img.raydium.io/icon/CobcsUrt3p91FwvULYKorQejgsm5HoQdv5T8RUZ6PnLA.png" - }, - { - "symbol": "CRWNY", - "name": "CRWNY", - "mint": "CRWNYkqdgvhGGae9CKfNka58j6QQkaD5bLhKXvUYqnc1", - "decimals": 6, - "extensions": { "coingeckoId": "crowny-token" }, - "icon": "https://img.raydium.io/icon/CRWNYkqdgvhGGae9CKfNka58j6QQkaD5bLhKXvUYqnc1.png" - }, - { - "symbol": "soALEPH", - "name": "Wrapped ALEPH (Sollet)", - "mint": "CsZ5LZkDS7h9TDKjrbL7VAwQZ9nsRu8vJLhRYfmGaN8K", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CsZ5LZkDS7h9TDKjrbL7VAwQZ9nsRu8vJLhRYfmGaN8K.png" - }, - { - "symbol": "soLINK", - "name": "Wrapped Chainlink (Sollet)", - "mint": "CWE8jPTUYhdCTZYWPTe1o5DFqfdjzWKc9WKz6rSjQUdG", - "decimals": 6, - "extensions": { "coingeckoId": "wrapped-chainlink-sollet" }, - "icon": "https://img.raydium.io/icon/CWE8jPTUYhdCTZYWPTe1o5DFqfdjzWKc9WKz6rSjQUdG.png" - }, - { - "symbol": "CHICKS", - "name": "CHICKS", - "mint": "cxxShYRVcepDudXhe7U62QHvw8uBJoKFifmzggGKVC2", - "decimals": 9, - "extensions": { "coingeckoId": "solchicks-token" }, - "icon": "https://img.raydium.io/icon/cxxShYRVcepDudXhe7U62QHvw8uBJoKFifmzggGKVC2.png" - }, - { - "symbol": "NESTA", - "name": "Nest Arcade", - "mint": "Czt7Fc4dz6BpLh2vKiSYyotNK2uPPDhvbWrrLeD9QxhV", - "decimals": 9, - "extensions": { "coingeckoId": "nest-arcade" }, - "icon": "https://img.raydium.io/icon/Czt7Fc4dz6BpLh2vKiSYyotNK2uPPDhvbWrrLeD9QxhV.png" - }, - { - "symbol": "soUNI", - "name": "Wrapped UNI (Sollet)", - "mint": "DEhAasscXF4kEGxFgJ3bq4PpVGp5wyUxMRvn6TzGVHaw", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DEhAasscXF4kEGxFgJ3bq4PpVGp5wyUxMRvn6TzGVHaw.png" - }, - { - "symbol": "DFL", - "name": "DeFi Land", - "mint": "DFL1zNkaGPWm1BqAVqRjCZvHmwTFrEaJtbzJWgseoNJh", - "decimals": 9, - "extensions": { "coingeckoId": "defi-land" }, - "icon": "https://img.raydium.io/icon/DFL1zNkaGPWm1BqAVqRjCZvHmwTFrEaJtbzJWgseoNJh.png" - }, - { - "symbol": "VOID", - "name": "VOID Token", - "mint": "DjPt6xxMoZx1DyyWUHGs4mwqWWX48Fwf6ZJgqv2F9qwc", - "decimals": 9, - "extensions": { "coingeckoId": "void-games" }, - "icon": "https://img.raydium.io/icon/DjPt6xxMoZx1DyyWUHGs4mwqWWX48Fwf6ZJgqv2F9qwc.png" - }, - { - "symbol": "UM", - "name": "UncleMine", - "mint": "DMCUFm2ZAnSU7UgsdVq23gRogMU3MEBjPgQF1gK53rEn", - "decimals": 6, - "extensions": { "coingeckoId": "unclemine" }, - "icon": "https://img.raydium.io/icon/DMCUFm2ZAnSU7UgsdVq23gRogMU3MEBjPgQF1gK53rEn.png" - }, - { - "symbol": "GXE", - "name": "Galaxy Essential", - "mint": "DsVPH4mAppxKrmdzcizGfPtLYEBAkQGK4eUch32wgaHY", - "decimals": 9, - "extensions": { "coingeckoId": "galaxy-essential" }, - "icon": "https://img.raydium.io/icon/DsVPH4mAppxKrmdzcizGfPtLYEBAkQGK4eUch32wgaHY.png" - }, - { - "symbol": "CRP", - "name": "CRP", - "mint": "DubwWZNWiNGMMeeQHPnMATNj77YZPZSAz2WVR5WjLJqz", - "decimals": 9, - "extensions": { "coingeckoId": "cropperfinance" }, - "icon": "https://img.raydium.io/icon/DubwWZNWiNGMMeeQHPnMATNj77YZPZSAz2WVR5WjLJqz.png" - }, - { - "symbol": "DUST", - "name": "DUST Protocol", - "mint": "DUSTawucrTsGU8hcqRdHDCbuYhCPADMLM2VcCb8VnFnQ", - "decimals": 9, - "extensions": { "coingeckoId": "dust-protocol" }, - "icon": "https://img.raydium.io/icon/DUSTawucrTsGU8hcqRdHDCbuYhCPADMLM2VcCb8VnFnQ.png" - }, - { - "symbol": "RIN", - "name": "RIN", - "mint": "E5ndSkaB17Dm7CsD22dvcjfrYSDLCxFcMd6z8ddCk5wp", - "decimals": 9, - "extensions": { "coingeckoId": "aldrin" }, - "icon": "https://img.raydium.io/icon/E5ndSkaB17Dm7CsD22dvcjfrYSDLCxFcMd6z8ddCk5wp.png" - }, - { - "symbol": "WOO", - "name": "Wootrade Network", - "mint": "E5rk3nmgLUuKUiS94gg4bpWwWwyjCMtddsAXkTFLtHEy", - "decimals": 6, - "extensions": { "coingeckoId": "woo-network" }, - "icon": "https://img.raydium.io/icon/E5rk3nmgLUuKUiS94gg4bpWwWwyjCMtddsAXkTFLtHEy.png" - }, - { - "symbol": "PAI", - "name": "PAI (Parrot)", - "mint": "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS", - "decimals": 6, - "extensions": { "coingeckoId": "parrot-usd" }, - "icon": "https://img.raydium.io/icon/Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS.png" - }, - { - "symbol": "RPC", - "name": "Republic Credits", - "mint": "EAefyXw6E8sny1cX3LTH6RSvtzH6E5EFy1XsE2AiH1f3", - "decimals": 6, - "extensions": { "coingeckoId": "republic-credits" }, - "icon": "https://img.raydium.io/icon/EAefyXw6E8sny1cX3LTH6RSvtzH6E5EFy1XsE2AiH1f3.png" - }, - { - "symbol": "FIDA", - "name": "Bonfida", - "mint": "EchesyfXePKdLtoiZSL8pBe8Myagyy8ZRqsACNCFGnvp", - "decimals": 6, - "extensions": { "coingeckoId": "bonfida" }, - "icon": "https://img.raydium.io/icon/EchesyfXePKdLtoiZSL8pBe8Myagyy8ZRqsACNCFGnvp.png" - }, - { - "symbol": "soKARMA", - "name": "Wrapped KARMA (Sollet)", - "mint": "EcqExpGNFBve2i1cMJUTR4bPXj4ZoqmDD2rTkeCcaTFX", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/EcqExpGNFBve2i1cMJUTR4bPXj4ZoqmDD2rTkeCcaTFX.png" - }, - { - "symbol": "FAB", - "name": "FAB", - "mint": "EdAhkbj5nF9sRM7XN7ewuW8C9XEUMs8P7cnoQ57SYE96", - "decimals": 9, - "extensions": { "coingeckoId": "fabric" }, - "icon": "https://img.raydium.io/icon/EdAhkbj5nF9sRM7XN7ewuW8C9XEUMs8P7cnoQ57SYE96.png" - }, - { - "symbol": "KRILL", - "name": "KRILL", - "mint": "EP2aYBDD4WvdhnwWLUMyqU69g1ePtEjgYK6qyEAFCHTx", - "decimals": 9, - "extensions": { "coingeckoId": "krill" }, - "icon": "https://img.raydium.io/icon/EP2aYBDD4WvdhnwWLUMyqU69g1ePtEjgYK6qyEAFCHTx.png" - }, - { - "symbol": "USDC", - "name": "USDC", - "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "decimals": 6, - "extensions": { "coingeckoId": "usd-coin" }, - "icon": "https://img.raydium.io/icon/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png" - }, - { - "symbol": "soLUA", - "name": "Wrapped LUA (Sollet)", - "mint": "EqWCKXfs3x47uVosDpTRgFniThL9Y8iCztJaapxbEaVX", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/EqWCKXfs3x47uVosDpTRgFniThL9Y8iCztJaapxbEaVX.png" - }, - { - "symbol": "FRKT", - "name": "FRKT", - "mint": "ErGB9xa24Szxbk1M28u2Tx8rKPqzL6BroNkkzk5rG4zj", - "decimals": 8, - "extensions": { "coingeckoId": "frakt-token" }, - "icon": "https://img.raydium.io/icon/ErGB9xa24Szxbk1M28u2Tx8rKPqzL6BroNkkzk5rG4zj.png" - }, - { - "symbol": "USDT", - "name": "USDT", - "mint": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "decimals": 6, - "extensions": { "coingeckoId": "tether" }, - "icon": "https://img.raydium.io/icon/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB.png" - }, - { - "symbol": "MEDIA", - "name": "MEDIA", - "mint": "ETAtLmCmsoiEEKfNrHKJ2kYy3MoABhU6NQvpSfij5tDs", - "decimals": 6, - "extensions": { "coingeckoId": "media-network" }, - "icon": "https://img.raydium.io/icon/ETAtLmCmsoiEEKfNrHKJ2kYy3MoABhU6NQvpSfij5tDs.png" - }, - { - "symbol": "UPS", - "name": "UPS", - "mint": "EwJN2GqUGXXzYmoAciwuABtorHczTA5LqbukKXV1viH7", - "decimals": 6, - "extensions": { "coingeckoId": "upfi-network" }, - "icon": "https://img.raydium.io/icon/EwJN2GqUGXXzYmoAciwuABtorHczTA5LqbukKXV1viH7.png" - }, - { - "symbol": "CSM", - "name": "Cricket Star Manager", - "mint": "EzfnjRUKtc5vweE1GCLdHV4MkDQ3ebSpQXLobSKgQ9RB", - "decimals": 6, - "extensions": { "coingeckoId": "cricket-star-manager" }, - "icon": "https://img.raydium.io/icon/EzfnjRUKtc5vweE1GCLdHV4MkDQ3ebSpQXLobSKgQ9RB.png" - }, - { - "symbol": "AART", - "name": "AART", - "mint": "F3nefJBcejYbtdREjui1T9DPh5dBgpkKq7u2GAAMXs5B", - "decimals": 6, - "extensions": { "coingeckoId": "all-art" }, - "icon": "https://img.raydium.io/icon/F3nefJBcejYbtdREjui1T9DPh5dBgpkKq7u2GAAMXs5B.png" - }, - { - "symbol": "FANT", - "name": "FANT", - "mint": "FANTafPFBAt93BNJVpdu25pGPmca3RfwdsDsRrT3LX1r", - "decimals": 6, - "extensions": { "coingeckoId": "phantasia" }, - "icon": "https://img.raydium.io/icon/FANTafPFBAt93BNJVpdu25pGPmca3RfwdsDsRrT3LX1r.png" - }, - { - "symbol": "NINJA", - "name": "NINJA", - "mint": "FgX1WD9WzMU3yLwXaFSarPfkgzjLb2DZCqmkx9ExpuvJ", - "decimals": 6, - "extensions": { "coingeckoId": "ninja-protocol" }, - "icon": "https://img.raydium.io/icon/FgX1WD9WzMU3yLwXaFSarPfkgzjLb2DZCqmkx9ExpuvJ.png" - }, - { - "symbol": "FLWR", - "name": "Flower Token", - "mint": "FLWRna1gxehQ9pSyZMzxfp4UhewvLPwuKfdUTgdZuMBY", - "decimals": 2, - "extensions": { "coingeckoId": "sol-flowers" }, - "icon": "https://img.raydium.io/icon/FLWRna1gxehQ9pSyZMzxfp4UhewvLPwuKfdUTgdZuMBY.png" - }, - { - "symbol": "MBS", - "name": "MBS", - "mint": "Fm9rHUTF5v3hwMLbStjZXqNBBoZyGriQaFM6sTFz3K8A", - "decimals": 6, - "extensions": { "coingeckoId": "monkeyball" }, - "icon": "https://img.raydium.io/icon/Fm9rHUTF5v3hwMLbStjZXqNBBoZyGriQaFM6sTFz3K8A.png" - }, - { - "symbol": "TTT", - "name": "TabTrader", - "mint": "FNFKRV3V8DtA3gVJN6UshMiLGYA8izxFwkNWmJbFjmRj", - "decimals": 6, - "extensions": { "coingeckoId": "tabtrader" }, - "icon": "https://img.raydium.io/icon/FNFKRV3V8DtA3gVJN6UshMiLGYA8izxFwkNWmJbFjmRj.png" - }, - { - "symbol": "SYP", - "name": "SYP", - "mint": "FnKE9n6aGjQoNWRBZXy4RW6LZVao7qwBonUbiD7edUmZ", - "decimals": 9, - "extensions": { "coingeckoId": "sypool" }, - "icon": "https://img.raydium.io/icon/FnKE9n6aGjQoNWRBZXy4RW6LZVao7qwBonUbiD7edUmZ.png" - }, - { - "symbol": "FUJI", - "name": "FUJI", - "mint": "fujiCeCeP9AFDVCv27P5JRcKLoH7wfs2C9xmDECs24m", - "decimals": 3, - "extensions": { "coingeckoId": "fuji" }, - "icon": "https://img.raydium.io/icon/fujiCeCeP9AFDVCv27P5JRcKLoH7wfs2C9xmDECs24m.png" - }, - { - "symbol": "PUFF", - "name": "PUFF", - "mint": "G9tt98aYSznRk7jWsfuz9FnTdokxS6Brohdo9hSmjTRB", - "decimals": 9, - "extensions": { "coingeckoId": "puff" }, - "icon": "https://img.raydium.io/icon/G9tt98aYSznRk7jWsfuz9FnTdokxS6Brohdo9hSmjTRB.png" - }, - { - "symbol": "XRP", - "name": "Wrapped XRP", - "mint": "Ga2AXHpfAF6mv2ekZwcsJFqu7wB4NV331qNH7fW9Nst8", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Ga2AXHpfAF6mv2ekZwcsJFqu7wB4NV331qNH7fW9Nst8.png" - }, - { - "symbol": "soMATH", - "name": "Wrapped MATH (Sollet)", - "mint": "GeDS162t9yGJuLEHPWXXGrb1zwkzinCgRwnT8vHYjKza", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GeDS162t9yGJuLEHPWXXGrb1zwkzinCgRwnT8vHYjKza.png" - }, - { - "symbol": "GENE", - "name": "Genopets", - "mint": "GENEtH5amGSi8kHAtQoezp1XEXwZJ8vcuePYnXdKrMYz", - "decimals": 9, - "extensions": { "coingeckoId": "genopets" }, - "icon": "https://img.raydium.io/icon/GENEtH5amGSi8kHAtQoezp1XEXwZJ8vcuePYnXdKrMYz.png" - }, - { - "symbol": "GOFX", - "name": "GOFX", - "mint": "GFX1ZjR2P15tmrSwow6FjyDYcEkoFb4p4gJCpLBjaxHD", - "decimals": 9, - "extensions": { "coingeckoId": "goosefx" }, - "icon": "https://img.raydium.io/icon/GFX1ZjR2P15tmrSwow6FjyDYcEkoFb4p4gJCpLBjaxHD.png" - }, - { - "symbol": "DXL", - "name": "DXL", - "mint": "GsNzxJfFn6zQdJGeYsupJWzUAm57Ba7335mfhWvFiE9Z", - "decimals": 6, - "extensions": { "coingeckoId": "dexlab" }, - "icon": "https://img.raydium.io/icon/GsNzxJfFn6zQdJGeYsupJWzUAm57Ba7335mfhWvFiE9Z.png" - }, - { - "symbol": "soKEEP", - "name": "Wrapped KEEP (Sollet)", - "mint": "GUohe4DJUA5FKPWo3joiPgsB7yzer7LpDmt1Vhzy3Zht", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GUohe4DJUA5FKPWo3joiPgsB7yzer7LpDmt1Vhzy3Zht.png" - }, - { - "symbol": "soTOMO", - "name": "Wrapped TOMO (Sollet)", - "mint": "GXMvfY2jpQctDqZ9RoU3oWPhufKiCcFEfchvYumtX7jd", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GXMvfY2jpQctDqZ9RoU3oWPhufKiCcFEfchvYumtX7jd.png" - }, - { - "symbol": "OOGI", - "name": "OOGI", - "mint": "H7Qc9APCWWGDVxGD5fJHmLTmdEgT9GFatAKFNg6sHh8A", - "decimals": 9, - "extensions": { "coingeckoId": "oogi" }, - "icon": "https://img.raydium.io/icon/H7Qc9APCWWGDVxGD5fJHmLTmdEgT9GFatAKFNg6sHh8A.png" - }, - { - "symbol": "HBB", - "name": "Hubble Protocol Token", - "mint": "HBB111SCo9jkCejsZfz8Ec8nH7T6THF8KEKSnvwT6XK6", - "decimals": 6, - "extensions": { "coingeckoId": "hubble" }, - "icon": "https://img.raydium.io/icon/HBB111SCo9jkCejsZfz8Ec8nH7T6THF8KEKSnvwT6XK6.png" - }, - { - "symbol": "STARS", - "name": "STARS", - "mint": "HCgybxq5Upy8Mccihrp7EsmwwFqYZtrHrsmsKwtGXLgW", - "decimals": 6, - "extensions": { "coingeckoId": "starlaunch" }, - "icon": "https://img.raydium.io/icon/HCgybxq5Upy8Mccihrp7EsmwwFqYZtrHrsmsKwtGXLgW.png" - }, - { - "symbol": "CWAR", - "name": "CWAR", - "mint": "HfYFjMKNZygfMC8LsQ8LtpPsPxEJoXJx4M6tqi75Hajo", - "decimals": 9, - "extensions": { "coingeckoId": "cryowar-token" }, - "icon": "https://img.raydium.io/icon/HfYFjMKNZygfMC8LsQ8LtpPsPxEJoXJx4M6tqi75Hajo.png" - }, - { - "symbol": "ATS", - "name": "Atlas Dex", - "mint": "HJbNXx2YMRxgfUJ6K4qeWtjatMK5KYQT1QnsCdDWywNv", - "decimals": 9, - "extensions": { "coingeckoId": "atlas-dex" }, - "icon": "https://img.raydium.io/icon/HJbNXx2YMRxgfUJ6K4qeWtjatMK5KYQT1QnsCdDWywNv.png" - }, - { - "symbol": "TINY", - "name": "TINY", - "mint": "HKfs24UEDQpHS5hUyKYkHd9q7GY5UQ679q2bokeL2whu", - "decimals": 6, - "extensions": { "coingeckoId": "tiny-colony" }, - "icon": "https://img.raydium.io/icon/HKfs24UEDQpHS5hUyKYkHd9q7GY5UQ679q2bokeL2whu.png" - }, - { - "symbol": "FCON", - "name": "Space Falcon", - "mint": "HovGjrBGTfna4dvg6exkMxXuexB3tUfEZKcut8AWowXj", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HovGjrBGTfna4dvg6exkMxXuexB3tUfEZKcut8AWowXj.png" - }, - { - "symbol": "HTO", - "name": "HTO", - "mint": "htoHLBJV1err8xP5oxyQdV2PLQhtVjxLXpKB7FsgJQD", - "decimals": 9, - "extensions": { "coingeckoId": "heavenland-hto" }, - "icon": "https://img.raydium.io/icon/htoHLBJV1err8xP5oxyQdV2PLQhtVjxLXpKB7FsgJQD.png" - }, - { - "symbol": "AXSet", - "name": "Axie Infinity Shard (Wormhole from Ethereum)", - "mint": "HysWcbHiYY9888pHbaqhwLYZQeZrcQMXKQWRqS7zcPK5", - "decimals": 8, - "extensions": { "coingeckoId": "axie-infinity-shard-wormhole" }, - "icon": "https://img.raydium.io/icon/HysWcbHiYY9888pHbaqhwLYZQeZrcQMXKQWRqS7zcPK5.png" - }, - { - "symbol": "LDO", - "name": "Lido DAO Token (Wormhole)", - "mint": "HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p", - "decimals": 8, - "extensions": { "coingeckoId": "lido-dao" }, - "icon": "https://img.raydium.io/icon/HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p.png" - }, - { - "symbol": "IN", - "name": "IN", - "mint": "inL8PMVd6iiW3RCBJnr5AsrRN6nqr4BTrcNuQWQSkvY", - "decimals": 9, - "extensions": { "coingeckoId": "invictus" }, - "icon": "https://img.raydium.io/icon/inL8PMVd6iiW3RCBJnr5AsrRN6nqr4BTrcNuQWQSkvY.png" - }, - { - "symbol": "IVN", - "name": "IVN", - "mint": "iVNcrNE9BRZBC9Aqf753iZiZfbszeAVUoikgT9yvr2a", - "decimals": 6, - "extensions": { "coingeckoId": "investin" }, - "icon": "https://img.raydium.io/icon/iVNcrNE9BRZBC9Aqf753iZiZfbszeAVUoikgT9yvr2a.png" - }, - { - "symbol": "KKO", - "name": "KKO", - "mint": "kiNeKo77w1WBEzFFCXrTDRWGRWGP8yHvKC9rX6dqjQh", - "decimals": 9, - "extensions": { "coingeckoId": "kineko" }, - "icon": "https://img.raydium.io/icon/kiNeKo77w1WBEzFFCXrTDRWGRWGP8yHvKC9rX6dqjQh.png" - }, - { - "symbol": "KIN", - "name": "KIN", - "mint": "kinXdEcpDQeHPEuQnqmUgtYykqKGVFq6CeVX5iAHJq6", - "decimals": 5, - "extensions": { "coingeckoId": "kin" }, - "icon": "https://img.raydium.io/icon/kinXdEcpDQeHPEuQnqmUgtYykqKGVFq6CeVX5iAHJq6.png" - }, - { - "symbol": "LARIX", - "name": "LARIX", - "mint": "Lrxqnh6ZHKbGy3dcrCED43nsoLkM1LTzU2jRfWe8qUC", - "decimals": 6, - "extensions": { "coingeckoId": "larix" }, - "icon": "https://img.raydium.io/icon/Lrxqnh6ZHKbGy3dcrCED43nsoLkM1LTzU2jRfWe8qUC.png" - }, - { - "symbol": "MNGO", - "name": "Mango", - "mint": "MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac", - "decimals": 6, - "extensions": { "coingeckoId": "mango-markets" }, - "icon": "https://img.raydium.io/icon/MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac.png" - }, - { - "symbol": "MAPS", - "name": "MAPS", - "mint": "MAPS41MDahZ9QdKXhVa4dWB9RuyfV4XqhyAZ8XcYepb", - "decimals": 6, - "extensions": { "coingeckoId": "maps" }, - "icon": "https://img.raydium.io/icon/MAPS41MDahZ9QdKXhVa4dWB9RuyfV4XqhyAZ8XcYepb.png" - }, - { - "symbol": "MEAN", - "name": "MEAN", - "mint": "MEANeD3XDdUmNMsRGjASkSWdC8prLYsoRJ61pPeHctD", - "decimals": 6, - "extensions": { "coingeckoId": "meanfi" }, - "icon": "https://img.raydium.io/icon/MEANeD3XDdUmNMsRGjASkSWdC8prLYsoRJ61pPeHctD.png" - }, - { - "symbol": "MER", - "name": "Mercurial", - "mint": "MERt85fc5boKw3BW1eYdxonEuJNvXbiMbs6hvheau5K", - "decimals": 6, - "extensions": { "coingeckoId": "mercurial" }, - "icon": "https://img.raydium.io/icon/MERt85fc5boKw3BW1eYdxonEuJNvXbiMbs6hvheau5K.png" - }, - { - "symbol": "SLC", - "name": "SLC", - "mint": "METAmTMXwdb8gYzyCPfXXFmZZw4rUsXX58PNsDg7zjL", - "decimals": 6, - "extensions": { "coingeckoId": "solice" }, - "icon": "https://img.raydium.io/icon/METAmTMXwdb8gYzyCPfXXFmZZw4rUsXX58PNsDg7zjL.png" - }, - { - "symbol": "MNDE", - "name": "MNDE", - "mint": "MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey", - "decimals": 9, - "extensions": { "coingeckoId": "marinade" }, - "icon": "https://img.raydium.io/icon/MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey.png" - }, - { - "symbol": "mSOL", - "name": "Marinade staked SOL (mSOL)", - "mint": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "decimals": 9, - "extensions": { "coingeckoId": "msol" }, - "icon": "https://img.raydium.io/icon/mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So.png" - }, - { - "symbol": "MSRM", - "name": "MegaSerum", - "mint": "MSRMcoVyrFxnSgo5uXwone5SKcGhT1KEJMFEkMEWf9L", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/MSRMcoVyrFxnSgo5uXwone5SKcGhT1KEJMFEkMEWf9L.png" - }, - { - "symbol": "BLOCK", - "name": "BLOCK", - "mint": "NFTUkR4u7wKxy9QLaX2TGvd9oZSWoMo4jqSJqdMb7Nk", - "decimals": 6, - "extensions": { "coingeckoId": "blockasset" }, - "icon": "https://img.raydium.io/icon/NFTUkR4u7wKxy9QLaX2TGvd9oZSWoMo4jqSJqdMb7Nk.png" - }, - { - "symbol": "NOS", - "name": "NOS", - "mint": "nosXBVoaCTtYdLvKY6Csb4AC8JCdQKKAaWYtx2ZMoo7", - "decimals": 6, - "extensions": { "coingeckoId": "nosana" }, - "icon": "https://img.raydium.io/icon/nosXBVoaCTtYdLvKY6Csb4AC8JCdQKKAaWYtx2ZMoo7.png" - }, - { - "symbol": "ORCA", - "name": "ORCA", - "mint": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "decimals": 6, - "extensions": { "coingeckoId": "orca" }, - "icon": "https://img.raydium.io/icon/orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE.png" - }, - { - "symbol": "POLIS", - "name": "POLIS", - "mint": "poLisWXnNRwC6oBu1vHiuKQzFjGL4XDSu4g9qjz9qVk", - "decimals": 8, - "extensions": { "coingeckoId": "star-atlas-dao" }, - "icon": "https://img.raydium.io/icon/poLisWXnNRwC6oBu1vHiuKQzFjGL4XDSu4g9qjz9qVk.png" - }, - { - "symbol": "PORT", - "name": "PORT", - "mint": "PoRTjZMPXb9T7dyU7tpLEZRQj7e6ssfAE62j2oQuc6y", - "decimals": 6, - "extensions": { "coingeckoId": "port-finance" }, - "icon": "https://img.raydium.io/icon/PoRTjZMPXb9T7dyU7tpLEZRQj7e6ssfAE62j2oQuc6y.png" - }, - { - "symbol": "prANA", - "name": "PRANA", - "mint": "PRAxfbouRoJ9yZqhyejEAH6RvjJ86Y82vfiZTBSM3xG", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/PRAxfbouRoJ9yZqhyejEAH6RvjJ86Y82vfiZTBSM3xG.png" - }, - { - "symbol": "PRISM", - "name": "PRISM", - "mint": "PRSMNsEPqhGVCH1TtWiJqPjJyh2cKrLostPZTNy1o5x", - "decimals": 6, - "extensions": { "coingeckoId": "prism" }, - "icon": "https://img.raydium.io/icon/PRSMNsEPqhGVCH1TtWiJqPjJyh2cKrLostPZTNy1o5x.png" - }, - { - "symbol": "PRT", - "name": "PRT", - "mint": "PRT88RkA4Kg5z7pKnezeNH4mafTvtQdfFgpQTGRjz44", - "decimals": 6, - "extensions": { "coingeckoId": "parrot-protocol" }, - "icon": "https://img.raydium.io/icon/PRT88RkA4Kg5z7pKnezeNH4mafTvtQdfFgpQTGRjz44.png" - }, - { - "symbol": "PSY", - "name": "PsyOptions", - "mint": "PsyFiqqjiv41G7o5SMRzDJCu4psptThNR2GtfeGHfSq", - "decimals": 6, - "extensions": { "coingeckoId": "psyoptions" }, - "icon": "https://img.raydium.io/icon/PsyFiqqjiv41G7o5SMRzDJCu4psptThNR2GtfeGHfSq.png" - }, - { - "symbol": "RATIO", - "name": "Ratio Protocol", - "mint": "ratioMVg27rSZbSvBopUvsdrGUzeALUfFma61mpxc8J", - "decimals": 6, - "extensions": { "coingeckoId": "ratio-finance" }, - "icon": "https://img.raydium.io/icon/ratioMVg27rSZbSvBopUvsdrGUzeALUfFma61mpxc8J.png" - }, - { - "symbol": "SBR", - "name": "SBR", - "mint": "Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1", - "decimals": 6, - "extensions": { "coingeckoId": "saber" }, - "icon": "https://img.raydium.io/icon/Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1.png" - }, - { - "symbol": "SCY", - "name": "SCY", - "mint": "SCYfrGCw8aDiqdgcpdGjV6jp4UVVQLuphxTDLNWu36f", - "decimals": 9, - "extensions": { "coingeckoId": "synchrony" }, - "icon": "https://img.raydium.io/icon/SCYfrGCw8aDiqdgcpdGjV6jp4UVVQLuphxTDLNWu36f.png" - }, - { - "symbol": "SEEDED", - "name": "Seeded Network", - "mint": "seedEDBqu63tJ7PFqvcbwvThrYUkQeqT6NLf81kLibs", - "decimals": 9, - "extensions": { "coingeckoId": "seeded-network" }, - "icon": "https://img.raydium.io/icon/seedEDBqu63tJ7PFqvcbwvThrYUkQeqT6NLf81kLibs.png" - }, - { - "symbol": "soSXP", - "name": "Wrapped SXP (Sollet)", - "mint": "SF3oTvfWzEP3DTwGSvUXRrGTvr75pdZNnBLAH9bzMuX", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/SF3oTvfWzEP3DTwGSvUXRrGTvr75pdZNnBLAH9bzMuX.png" - }, - { - "symbol": "SHDW", - "name": "SHDW", - "mint": "SHDWyBxihqiCj6YekG2GUr7wqKLeLAMK1gHZck9pL6y", - "decimals": 9, - "extensions": { "coingeckoId": "genesysgo-shadow" }, - "icon": "https://img.raydium.io/icon/SHDWyBxihqiCj6YekG2GUr7wqKLeLAMK1gHZck9pL6y.png" - }, - { - "symbol": "SLCL", - "name": "Solcial token", - "mint": "SLCLww7nc1PD2gQPQdGayHviVVcpMthnqUz2iWKhNQV", - "decimals": 9, - "extensions": { "coingeckoId": "solcial" }, - "icon": "https://img.raydium.io/icon/SLCLww7nc1PD2gQPQdGayHviVVcpMthnqUz2iWKhNQV.png" - }, - { - "symbol": "SLND", - "name": "SLND", - "mint": "SLNDpmoWTVADgEdndyvWzroNL7zSi1dF9PC3xHGtPwp", - "decimals": 6, - "extensions": { "coingeckoId": "solend" }, - "icon": "https://img.raydium.io/icon/SLNDpmoWTVADgEdndyvWzroNL7zSi1dF9PC3xHGtPwp.png" - }, - { - "symbol": "SLRS", - "name": "SLRS", - "mint": "SLRSSpSLUTP7okbCUBYStWCo1vUgyt775faPqz8HUMr", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/SLRSSpSLUTP7okbCUBYStWCo1vUgyt775faPqz8HUMr.png" - }, - { - "symbol": "SNS", - "name": "SynesisOne", - "mint": "SNSNkV9zfG5ZKWQs6x4hxvBRV6s8SqMfSGCtECDvdMd", - "decimals": 9, - "extensions": { "coingeckoId": "synesis-one" }, - "icon": "https://img.raydium.io/icon/SNSNkV9zfG5ZKWQs6x4hxvBRV6s8SqMfSGCtECDvdMd.png" - }, - { - "symbol": "WSOL", - "name": "Wrapped Solana", - "mint": "So11111111111111111111111111111111111111112", - "decimals": 9, - "extensions": { "coingeckoId": "wrapped-solana" }, - "icon": "https://img.raydium.io/icon/So11111111111111111111111111111111111111112.png" - }, - { - "symbol": "SONAR", - "name": "SONAR", - "mint": "sonarX4VtVkQemriJeLm6CKeW3GDMyiBnnAEMw1MRAE", - "decimals": 9, - "extensions": { "coingeckoId": "sonarwatch" }, - "icon": "https://img.raydium.io/icon/sonarX4VtVkQemriJeLm6CKeW3GDMyiBnnAEMw1MRAE.png" - }, - { - "symbol": "SRM", - "name": "Serum", - "mint": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "decimals": 6, - "extensions": { "coingeckoId": "serum" }, - "icon": "https://img.raydium.io/icon/SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt.png" - }, - { - "symbol": "STEP", - "name": "STEP", - "mint": "StepAscQoEioFxxWGnh2sLBDFp9d8rvKz2Yp39iDpyT", - "decimals": 9, - "extensions": { "coingeckoId": "step-finance" }, - "icon": "https://img.raydium.io/icon/StepAscQoEioFxxWGnh2sLBDFp9d8rvKz2Yp39iDpyT.png" - }, - { - "symbol": "SB", - "name": "SB", - "mint": "SuperbZyz7TsSdSoFAZ6RYHfAWe9NmjXBLVQpS8hqdx", - "decimals": 6, - "extensions": { "coingeckoId": "superbonds" }, - "icon": "https://img.raydium.io/icon/SuperbZyz7TsSdSoFAZ6RYHfAWe9NmjXBLVQpS8hqdx.png" - }, - { - "symbol": "SVT", - "name": "SVT", - "mint": "svtMpL5eQzdmB3uqK9NXaQkq8prGZoKQFNVJghdWCkV", - "decimals": 6, - "extensions": { "coingeckoId": "solvent" }, - "icon": "https://img.raydium.io/icon/svtMpL5eQzdmB3uqK9NXaQkq8prGZoKQFNVJghdWCkV.png" - }, - { - "symbol": "TULIP", - "name": "TULIP", - "mint": "TuLipcqtGVXP9XR62wM8WWCm6a9vhLs7T1uoWBk6FDs", - "decimals": 6, - "extensions": { "coingeckoId": "solfarm" }, - "icon": "https://img.raydium.io/icon/TuLipcqtGVXP9XR62wM8WWCm6a9vhLs7T1uoWBk6FDs.png" - }, - { - "symbol": "USDH", - "name": "USDH Hubble Stablecoin", - "mint": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "decimals": 6, - "extensions": { "coingeckoId": "usdh" }, - "icon": "https://img.raydium.io/icon/USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX.png" - }, - { - "symbol": "UXP", - "name": "UXP Governance Token", - "mint": "UXPhBoR3qG4UCiGNJfV7MqhHyFqKN68g45GoYvAeL2M", - "decimals": 9, - "extensions": { "coingeckoId": "uxd-protocol-token" }, - "icon": "https://img.raydium.io/icon/UXPhBoR3qG4UCiGNJfV7MqhHyFqKN68g45GoYvAeL2M.png" - }, - { - "symbol": "$WNZ", - "name": "Winerz", - "mint": "WNZzxM1WqWFH8DpDZSqr6EoHKWXeMx9NLLd2R5RzGPA", - "decimals": 4, - "extensions": { "coingeckoId": "winerz" }, - "icon": "https://img.raydium.io/icon/WNZzxM1WqWFH8DpDZSqr6EoHKWXeMx9NLLd2R5RzGPA.png" - }, - { - "symbol": "SLIM", - "name": "SLIM", - "mint": "xxxxa1sKNGwFtw2kFn8XauW9xq8hBZ5kVtcSesTT9fW", - "decimals": 6, - "extensions": { "coingeckoId": "solanium" }, - "icon": "https://img.raydium.io/icon/xxxxa1sKNGwFtw2kFn8XauW9xq8hBZ5kVtcSesTT9fW.png" - }, - { - "symbol": "YAW", - "name": "Yawww", - "mint": "YAWtS7vWCSRPckx1agB6sKidVXiXiDUfehXdEUSRGKE", - "decimals": 6, - "extensions": { "coingeckoId": "yawww" }, - "icon": "https://img.raydium.io/icon/YAWtS7vWCSRPckx1agB6sKidVXiXiDUfehXdEUSRGKE.png" - }, - { - "symbol": "OXY", - "name": "OXY", - "mint": "z3dn17yLaGMKffVogeFHQ9zWVcXgqgf3PQnDsNs2g6M", - "decimals": 6, - "extensions": { "coingeckoId": "oxygen" }, - "icon": "https://img.raydium.io/icon/z3dn17yLaGMKffVogeFHQ9zWVcXgqgf3PQnDsNs2g6M.png" - }, - { - "symbol": "ZBC", - "name": "ZEBEC", - "mint": "zebeczgi5fSEtbpfQKVZKCJ3WgYXxjkMUkNNx7fLKAF", - "decimals": 9, - "extensions": { "coingeckoId": "zebec-protocol" }, - "icon": "https://img.raydium.io/icon/zebeczgi5fSEtbpfQKVZKCJ3WgYXxjkMUkNNx7fLKAF.png" - } - ], - "unOfficial": [ - { - "symbol": "LICKS", - "name": "LICKS Token", - "mint": "14AB7dXTdiNAwqAtWC7NmSW9u74SkCXU1X6DSejxkFEg", - "decimals": 3, - "extensions": {}, - "icon": "https://img.raydium.io/icon/14AB7dXTdiNAwqAtWC7NmSW9u74SkCXU1X6DSejxkFEg.png" - }, - { - "symbol": "TREATS", - "name": "Solana Puppy Pound Treats", - "mint": "14r8dWfzmUUBpw59w5swNRb5F1YWqmUnSPgD6djUs1Jj", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/14r8dWfzmUUBpw59w5swNRb5F1YWqmUnSPgD6djUs1Jj.png" - }, - { - "symbol": "XMON", - "name": "XMON", - "mint": "14UMe2amWfXj1CrM7C9kFkTQ6PtX5aT1fdsVGqBZaXCT", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/14UMe2amWfXj1CrM7C9kFkTQ6PtX5aT1fdsVGqBZaXCT.png" - }, - { - "symbol": "NRA", - "name": "NORA", - "mint": "1C2EYVrwmoXAGbiKirFFBeDFDYUBHPhDeg9trhibTND", - "decimals": 9, - "extensions": { "coingeckoId": "nora-token" }, - "icon": "https://img.raydium.io/icon/1C2EYVrwmoXAGbiKirFFBeDFDYUBHPhDeg9trhibTND.png" - }, - { - "symbol": "ISS", - "name": "Irish Setter Sol", - "mint": "1SSBwC8hxB4GXzKKU4ENNpST7zgpTmucDe9NoAopWXX", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/1SSBwC8hxB4GXzKKU4ENNpST7zgpTmucDe9NoAopWXX.png" - }, - { - "symbol": "CEX", - "name": "Catena X", - "mint": "21vatMcwZz53Eu2EUDCS9xoZUXdJ9ABMTQYNMKKkzoNW", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/21vatMcwZz53Eu2EUDCS9xoZUXdJ9ABMTQYNMKKkzoNW.png" - }, - { - "symbol": "JINDO", - "name": "Solana Jindo Inu", - "mint": "24WQvWoqJuTS5LoqeBJpa2smqg94V6iqQDWC5cPd8tve", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/24WQvWoqJuTS5LoqeBJpa2smqg94V6iqQDWC5cPd8tve.png" - }, - { - "symbol": "XVC", - "name": "Xverse Token", - "mint": "25Vu6457o2gdZRGVVt5K8NbAvaP3esYaQNHbNDitVtw1", - "decimals": 9, - "extensions": { "coingeckoId": "xverse" }, - "icon": "https://img.raydium.io/icon/25Vu6457o2gdZRGVVt5K8NbAvaP3esYaQNHbNDitVtw1.png" - }, - { - "symbol": "POZZ", - "name": "PozzCoin", - "mint": "27nqFZqb2iPBeVA7bbE4KPZrJgi3dJdKV9VzhCguSy6Y", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/27nqFZqb2iPBeVA7bbE4KPZrJgi3dJdKV9VzhCguSy6Y.png" - }, - { - "symbol": "SHIBT", - "name": "SHIBA LIGHT", - "mint": "2946ofy854iifvXCQmHX2AJgxRBoQcchy1gfD26RtkHp", - "decimals": 9, - "extensions": { "coingeckoId": "shiba-light" }, - "icon": "https://img.raydium.io/icon/2946ofy854iifvXCQmHX2AJgxRBoQcchy1gfD26RtkHp.png" - }, - { - "symbol": "SJP", - "name": "Stacc Job Points", - "mint": "2A5esErqMaJXhrs1i6CtjbVxTbgsY9JbDedVsuVMQ6aY", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2A5esErqMaJXhrs1i6CtjbVxTbgsY9JbDedVsuVMQ6aY.png" - }, - { - "symbol": "WAS", - "name": "Wasder", - "mint": "2cW8Yosn4tSYJYjfUkcpKnYBSMYDqXfJmQXVu4RJzBTw", - "decimals": 8, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2cW8Yosn4tSYJYjfUkcpKnYBSMYDqXfJmQXVu4RJzBTw.png" - }, - { - "symbol": "ACF", - "name": "Alien Chicken Farm", - "mint": "2cZv8HrgcWSvC6n1uEiS48cEQGb1d3fiowP2rpa4wBL9", - "decimals": 2, - "extensions": { "coingeckoId": "alien-chicken-farm" }, - "icon": "https://img.raydium.io/icon/2cZv8HrgcWSvC6n1uEiS48cEQGb1d3fiowP2rpa4wBL9.png" - }, - { - "symbol": "SOUP", - "name": "GoodSoup", - "mint": "2DDyLzN1pxVddhkgZYJdJH6YFUbeSVPFZBMSxcLswwap", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2DDyLzN1pxVddhkgZYJdJH6YFUbeSVPFZBMSxcLswwap.png" - }, - { - "symbol": "REAP", - "name": "REAP", - "mint": "2Dm1zu8ERJGBs3NLXt8s8Vor3YHwJye5E2pYhLiMHU4L", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2Dm1zu8ERJGBs3NLXt8s8Vor3YHwJye5E2pYhLiMHU4L.png" - }, - { - "symbol": "BAB", - "name": "Banana Bucks", - "mint": "2Dzzc14S1D7cEFGJyMZMACuoQRHVUYFhVE74C5o8Fwau", - "decimals": 9, - "extensions": { "coingeckoId": "banana-bucks" }, - "icon": "https://img.raydium.io/icon/2Dzzc14S1D7cEFGJyMZMACuoQRHVUYFhVE74C5o8Fwau.png" - }, - { - "symbol": "MSI", - "name": "Matrix Solana Index", - "mint": "2e7yNwrmTgXp9ABUmcPXvFJTSrEVLj4YMyrb4GUM4Pdd", - "decimals": 6, - "extensions": { "coingeckoId": "matrix-solana-index" }, - "icon": "https://img.raydium.io/icon/2e7yNwrmTgXp9ABUmcPXvFJTSrEVLj4YMyrb4GUM4Pdd.png" - }, - { - "symbol": "POMP", - "name": "Pompeizz Floor Index", - "mint": "2EyqaC7zo6TYEKTebBZCchiAdwmqEzsxLxA2MzCYhBcf", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2EyqaC7zo6TYEKTebBZCchiAdwmqEzsxLxA2MzCYhBcf.png" - }, - { - "symbol": "DRONIES", - "name": "Dronies Floor Index", - "mint": "2fgYu8vYZhvVsocNM4y4HcrZCCPXYcoo8mZof5hJ3miw", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2fgYu8vYZhvVsocNM4y4HcrZCCPXYcoo8mZof5hJ3miw.png" - }, - { - "symbol": "VITAL", - "name": "VITAL Token", - "mint": "2FKuYE5D75e9Fjg3ymGBrFfVc8tVKac4SeyvZn5dGNUz", - "decimals": 9, - "extensions": { "coingeckoId": "vitall-markets" }, - "icon": "https://img.raydium.io/icon/2FKuYE5D75e9Fjg3ymGBrFfVc8tVKac4SeyvZn5dGNUz.png" - }, - { - "symbol": "SMBT", - "name": "Monke Token", - "mint": "2FkuyFr3N9RzvVahPqzXKfa8H9KhYpChwQZSeMKkkVPJ", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2FkuyFr3N9RzvVahPqzXKfa8H9KhYpChwQZSeMKkkVPJ.png" - }, - { - "symbol": "McNoot", - "name": "McNoot", - "mint": "2geYxMQ9o466tQ3JitUVR5Xmuk4a11KXs7ZmSX1hiSJp", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2geYxMQ9o466tQ3JitUVR5Xmuk4a11KXs7ZmSX1hiSJp.png" - }, - { - "symbol": "MZB", - "name": "MnZorBashm", - "mint": "2ikET9vxPYEf28XwpqRewFKizij1f1KqgyLqet8TMUsa", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2ikET9vxPYEf28XwpqRewFKizij1f1KqgyLqet8TMUsa.png" - }, - { - "symbol": "VIVAION", - "name": "Vivaion Token", - "mint": "2jw1uFmc1hhfJH3EqGhaE2rfZMMC2YBpxkZcdUbPppMn", - "decimals": 9, - "extensions": { "coingeckoId": "vivaion" }, - "icon": "https://img.raydium.io/icon/2jw1uFmc1hhfJH3EqGhaE2rfZMMC2YBpxkZcdUbPppMn.png" - }, - { - "symbol": "KURO", - "name": "Kurobi", - "mint": "2Kc38rfQ49DFaKHQaWbijkE7fcymUMLY5guUiUsDmFfn", - "decimals": 6, - "extensions": { "coingeckoId": "kurobi" }, - "icon": "https://img.raydium.io/icon/2Kc38rfQ49DFaKHQaWbijkE7fcymUMLY5guUiUsDmFfn.png" - }, - { - "symbol": "MEN", - "name": "Mental Protocol", - "mint": "2KXuiuKwSxatUSN3bYG9i4Mg9T66PYBPAHvVDtiCfoLm", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2KXuiuKwSxatUSN3bYG9i4Mg9T66PYBPAHvVDtiCfoLm.png" - }, - { - "symbol": "BORK", - "name": "BORK", - "mint": "2LxZrcJJhzcAju1FBHuGvw929EVkX7R7Q8yA2cdp8q7b", - "decimals": 9, - "extensions": { "coingeckoId": "bork" }, - "icon": "https://img.raydium.io/icon/2LxZrcJJhzcAju1FBHuGvw929EVkX7R7Q8yA2cdp8q7b.png" - }, - { - "symbol": "CORE", - "name": "CORE", - "mint": "2maDvG9nXGVstjdnsCZoSsNtjoda1SsZTLrHBVRgLR5F", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2maDvG9nXGVstjdnsCZoSsNtjoda1SsZTLrHBVRgLR5F.png" - }, - { - "symbol": "TBK", - "name": "TokenBook", - "mint": "2mDJPcvv7vigZo9ZPxhHLpKQSixCkbohVY35eX6NkN6m", - "decimals": 9, - "extensions": { "coingeckoId": "tokenbook" }, - "icon": "https://img.raydium.io/icon/2mDJPcvv7vigZo9ZPxhHLpKQSixCkbohVY35eX6NkN6m.png" - }, - { - "symbol": "NCLR", - "name": "NCLR", - "mint": "2MStv16MMiSTGu917stHLsC1ZTUW83tmrfVjUxfx2Ev1", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2MStv16MMiSTGu917stHLsC1ZTUW83tmrfVjUxfx2Ev1.png" - }, - { - "symbol": "IVRY", - "name": "Portals Ivory Index", - "mint": "2MtPZqwNKTNsBoFCwm4ZTWk3ySz4LSd82ucDGeTk7VNu", - "decimals": 2, - "extensions": { "coingeckoId": "portals-ivory-index" }, - "icon": "https://img.raydium.io/icon/2MtPZqwNKTNsBoFCwm4ZTWk3ySz4LSd82ucDGeTk7VNu.png" - }, - { - "symbol": "ST", - "name": "Solana Tiger", - "mint": "2NczZKqiEtv1CCufwBCLVRCh17w8aHAhvyGTU486KMo3", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2NczZKqiEtv1CCufwBCLVRCh17w8aHAhvyGTU486KMo3.png" - }, - { - "symbol": "GCC", - "name": "GitCompile Coin", - "mint": "2NURMkJEkLWUXF91kbhBETkZ5E2D674DF2Wi5X2ZTsTH", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2NURMkJEkLWUXF91kbhBETkZ5E2D674DF2Wi5X2ZTsTH.png" - }, - { - "symbol": "FPUNK", - "name": "Fab Punk Index", - "mint": "2oDVQrNmBrJR71t2wJjq5f7Vz6ohnJheHoLMJEHcEW4J", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2oDVQrNmBrJR71t2wJjq5f7Vz6ohnJheHoLMJEHcEW4J.png" - }, - { - "symbol": "DEVX", - "name": "developer experience", - "mint": "2pLrCRnbYBGbhANbUvkFXDYuuRNZNkesbvc8WSMQ9unX", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2pLrCRnbYBGbhANbUvkFXDYuuRNZNkesbvc8WSMQ9unX.png" - }, - { - "symbol": "MM", - "name": "Million", - "mint": "2PoF4gqWg97yjJk276yUYaGVkkASE7tqAU7H5faEBkeC", - "decimals": 8, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2PoF4gqWg97yjJk276yUYaGVkkASE7tqAU7H5faEBkeC.png" - }, - { - "symbol": "FEAR", - "name": "The Fearless", - "mint": "2pqRgpTLSJRgqBaBAQBBAqfLsdjqWic5bi6S9UJazyaT", - "decimals": 3, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2pqRgpTLSJRgqBaBAQBBAqfLsdjqWic5bi6S9UJazyaT.png" - }, - { - "symbol": "ETD", - "name": "EntropyDex", - "mint": "2qfSePaCqvWkYnYUsYSm1VZYKtbzKYHh7gsnKcyrgspp", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2qfSePaCqvWkYnYUsYSm1VZYKtbzKYHh7gsnKcyrgspp.png" - }, - { - "symbol": "KEKW", - "name": "kekwcoin", - "mint": "2QK9vxydd7WoDwvVFT5JSU8cwE9xmbJSzeqbRESiPGMG", - "decimals": 9, - "extensions": { "coingeckoId": "kekwcoin" }, - "icon": "https://img.raydium.io/icon/2QK9vxydd7WoDwvVFT5JSU8cwE9xmbJSzeqbRESiPGMG.png" - }, - { - "symbol": "rSPTRL", - "name": "Random Sol Patrol", - "mint": "2qq3zxV9qBenTZLWRhmcSJdPFqdTGDDgc1aVQUCTs9Bu", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2qq3zxV9qBenTZLWRhmcSJdPFqdTGDDgc1aVQUCTs9Bu.png" - }, - { - "symbol": "SAMOL", - "name": "Samolana NFT", - "mint": "2qRHKgE9k7doshwy7ZfENuSHW256pDhcbyspDgU3Ek8C", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2qRHKgE9k7doshwy7ZfENuSHW256pDhcbyspDgU3Ek8C.png" - }, - { - "symbol": "PENNY", - "name": "Penny Auction", - "mint": "2rLTJzSj6J6f4poPAKojS2sbdtRry7b8k4XoEMKPwner", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2rLTJzSj6J6f4poPAKojS2sbdtRry7b8k4XoEMKPwner.png" - }, - { - "symbol": "HENDX", - "name": "Hendrix Token", - "mint": "2Tp4hCJ24aRnsLShz9U96VtTSDHuaKL7eD7vj8Stvxhn", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2Tp4hCJ24aRnsLShz9U96VtTSDHuaKL7eD7vj8Stvxhn.png" - }, - { - "symbol": "DINOEGG", - "name": "DINOEGG", - "mint": "2TxM6S3ZozrBHZGHEPh9CtM74a9SVXbr7NQ7UxkRvQij", - "decimals": 6, - "extensions": { "coingeckoId": "dinoegg" }, - "icon": "https://img.raydium.io/icon/2TxM6S3ZozrBHZGHEPh9CtM74a9SVXbr7NQ7UxkRvQij.png" - }, - { - "symbol": "SLB", - "name": "Solberg", - "mint": "2uRFEWRBQLEKpLmF8mohFZGDcFQmrkQEEZmHQvMUBvY7", - "decimals": 9, - "extensions": { "coingeckoId": "solberg" }, - "icon": "https://img.raydium.io/icon/2uRFEWRBQLEKpLmF8mohFZGDcFQmrkQEEZmHQvMUBvY7.png" - }, - { - "symbol": "ATL", - "name": "Akuma Serpent", - "mint": "2V1AVjDVM2gZn72ZufG2HfFHDKXzS5XaCupNeKrdcruT", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2V1AVjDVM2gZn72ZufG2HfFHDKXzS5XaCupNeKrdcruT.png" - }, - { - "symbol": "OODA", - "name": "OODA", - "mint": "2VFkmFpyFm9DMKch4UdrdyY7WHLGrWgwJLAdKwHd5ekY", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2VFkmFpyFm9DMKch4UdrdyY7WHLGrWgwJLAdKwHd5ekY.png" - }, - { - "symbol": "SHROOMZ", - "name": "Crypto Mushroomz", - "mint": "2vRgBSJEVPXxayrhXoazQyCKSGFYQG3ZdfT2Gv5gZykL", - "decimals": 6, - "extensions": { "coingeckoId": "crypto-mushroomz" }, - "icon": "https://img.raydium.io/icon/2vRgBSJEVPXxayrhXoazQyCKSGFYQG3ZdfT2Gv5gZykL.png" - }, - { - "symbol": "BSAMO", - "name": "BUFF SAMO", - "mint": "2XSuy8RSESbtYRBbVHxGWuoikn3B6iXKVKzN4i3owTCf", - "decimals": 9, - "extensions": { "coingeckoId": "buff-samo" }, - "icon": "https://img.raydium.io/icon/2XSuy8RSESbtYRBbVHxGWuoikn3B6iXKVKzN4i3owTCf.png" - }, - { - "symbol": "$PSYn", - "name": "PSYn", - "mint": "2y7wUCJdtqTbjnKBNEB3DpAYCuwA1atCtdfkGt9VR4sM", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "VRS", - "name": "VeraSaw Plant Token", - "mint": "2YCQcQgy9nNhgukjAur1jCvMXgSTQ5FVDc3ae3BcspXS", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2YCQcQgy9nNhgukjAur1jCvMXgSTQ5FVDc3ae3BcspXS.png" - }, - { - "symbol": "SGEM", - "name": "Sol Gems", - "mint": "2YJH1Y5NbdwJGEUAMY6hoTycKWrRCP6kLKs62xiSKWHM", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2YJH1Y5NbdwJGEUAMY6hoTycKWrRCP6kLKs62xiSKWHM.png" - }, - { - "symbol": "TBF", - "name": "The Big Five", - "mint": "2ZamLCGLPSpP2MRbeM2wXRWzTEDhr669cFycVWgzBixi", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2ZamLCGLPSpP2MRbeM2wXRWzTEDhr669cFycVWgzBixi.png" - }, - { - "symbol": "EGO", - "name": "Shear Ego Coin", - "mint": "2zjmVX4KDWtNWQyJhbNXgpMmsAoXwftB7sGV4qvV18xa", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2zjmVX4KDWtNWQyJhbNXgpMmsAoXwftB7sGV4qvV18xa.png" - }, - { - "symbol": "PTN", - "name": "Photon", - "mint": "2ZLYEWypSrQhruqsTDqWNWuzFXe5G75dX9PoHQWtKZ31", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/2ZLYEWypSrQhruqsTDqWNWuzFXe5G75dX9PoHQWtKZ31.png" - }, - { - "symbol": "SPKL", - "name": "Spookeletons Token", - "mint": "31tCNEE6LiL9yW4Bu153Dq4vi2GuorXxCA9pW9aA6ecU", - "decimals": 9, - "extensions": { "coingeckoId": "spookeletons-token" }, - "icon": "https://img.raydium.io/icon/31tCNEE6LiL9yW4Bu153Dq4vi2GuorXxCA9pW9aA6ecU.png" - }, - { - "symbol": "DAB", - "name": "DAB COIN", - "mint": "32CHtMAuGaCAZx8Rgp54jSFG3ihbpN5brSvRAWpwEHPv", - "decimals": 9, - "extensions": { "coingeckoId": "dab-coin" }, - "icon": "https://img.raydium.io/icon/32CHtMAuGaCAZx8Rgp54jSFG3ihbpN5brSvRAWpwEHPv.png" - }, - { - "symbol": "RIBBET", - "name": "RIBBET", - "mint": "32gaR4rn9JyzoDVwMzZ5j3NgcHc5RQhMSJby55FFKnq3", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/32gaR4rn9JyzoDVwMzZ5j3NgcHc5RQhMSJby55FFKnq3.png" - }, - { - "symbol": "MAGIK", - "name": "Magik Finance", - "mint": "32iV3tk9bDgf2nBHVMbD2HgZnv4vccDZhrDrK2eUkmJd", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/32iV3tk9bDgf2nBHVMbD2HgZnv4vccDZhrDrK2eUkmJd.png" - }, - { - "symbol": "GIGALAND", - "name": "Gigaland", - "mint": "32NkWgx6KaLpTEYb9ape4XNWff1n6Bt9rsmwepiJzxop", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "ELON", - "name": "Dogelon Mars", - "mint": "37mG5XYuwMSutQnvERDUZqxumes5hYp89X2gpBbedpZ2", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/37mG5XYuwMSutQnvERDUZqxumes5hYp89X2gpBbedpZ2.png" - }, - { - "symbol": "LANA", - "name": "LANA TOKEN", - "mint": "37qK4Nc6ryVZYfNFufx97nJU6QD2hskToSdgL7VXwoJ4", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/37qK4Nc6ryVZYfNFufx97nJU6QD2hskToSdgL7VXwoJ4.png" - }, - { - "symbol": "XHamster", - "name": "xHamster", - "mint": "39cG39AZ4cG7oGNMe4RhD3xAzjy1nkiNgk8W6WbDCgeR", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/39cG39AZ4cG7oGNMe4RhD3xAzjy1nkiNgk8W6WbDCgeR.png" - }, - { - "symbol": "CLASH", - "name": "Clash Of Cars", - "mint": "3aAYh35n81F8HPG2QBdE48aYdzGFj2fsLccg91X4AcRc", - "decimals": 9, - "extensions": { "coingeckoId": "clash-of-cars" }, - "icon": "https://img.raydium.io/icon/3aAYh35n81F8HPG2QBdE48aYdzGFj2fsLccg91X4AcRc.png" - }, - { - "symbol": "SOLFI", - "name": "SOLFI", - "mint": "3CaBxqxWsP5oqS84Pkja4wLxyZYsHzMivQbnfwFJQeL1", - "decimals": 9, - "extensions": { "coingeckoId": "solfina" }, - "icon": "https://img.raydium.io/icon/3CaBxqxWsP5oqS84Pkja4wLxyZYsHzMivQbnfwFJQeL1.png" - }, - { - "symbol": "STARTREK", - "name": "StarTrek Coin", - "mint": "3cCtnQcc81oUfjufBL6D1yXNqt99TPt8n4HinW9h58wP", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3cCtnQcc81oUfjufBL6D1yXNqt99TPt8n4HinW9h58wP.png" - }, - { - "symbol": "TRBL", - "name": "Tribeland Governance Token", - "mint": "3CKQgrcvwhvFqVXXxLTb1u262nh26SJ3uutkSCTtbZxH", - "decimals": 9, - "extensions": { "coingeckoId": "tribeland" }, - "icon": "https://img.raydium.io/icon/3CKQgrcvwhvFqVXXxLTb1u262nh26SJ3uutkSCTtbZxH.png" - }, - { - "symbol": "DAWG", - "name": "DAWG", - "mint": "3DHPqxdMXogNNnpqBMF8N4Zs4dn1WR31H7UjWq6FExwG", - "decimals": 9, - "extensions": { "coingeckoId": "dawg" }, - "icon": "https://img.raydium.io/icon/3DHPqxdMXogNNnpqBMF8N4Zs4dn1WR31H7UjWq6FExwG.png" - }, - { - "symbol": "88A", - "name": "Arcade '88 Token", - "mint": "3dU3xJjjPCJHvJwmqhmK4nqETfPpEGKRaWSquffAvZ5C", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3dU3xJjjPCJHvJwmqhmK4nqETfPpEGKRaWSquffAvZ5C.png" - }, - { - "symbol": "ARNM", - "name": "Arenum", - "mint": "3Dy8KFyvpUJ8nfRCbvk4HLWjNRRzxiVhTeE9PQF9RARD", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3Dy8KFyvpUJ8nfRCbvk4HLWjNRRzxiVhTeE9PQF9RARD.png" - }, - { - "symbol": "BAIL", - "name": "BAIL COIN", - "mint": "3e9pHUxa2nvAqso2Kr2KqJxYvZaz9qZLjoLaG77uQwB1", - "decimals": 9, - "extensions": { "coingeckoId": "solpatrol-bail" }, - "icon": "https://img.raydium.io/icon/3e9pHUxa2nvAqso2Kr2KqJxYvZaz9qZLjoLaG77uQwB1.png" - }, - { - "symbol": "ELONINU", - "name": "ElonInu", - "mint": "3edUPhBRqprSVdEPheVsFYb34eYPq4xZrYjN6v9fqUrd", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3edUPhBRqprSVdEPheVsFYb34eYPq4xZrYjN6v9fqUrd.png" - }, - { - "symbol": "HIPPO", - "name": "Hippo Coin", - "mint": "3EkHyexJLGCvSxzn5umbtd9N69GoT4p5pfdLTFqCNP9Y", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3EkHyexJLGCvSxzn5umbtd9N69GoT4p5pfdLTFqCNP9Y.png" - }, - { - "symbol": "SGG", - "name": "Solx Gaming Guild", - "mint": "3eLpKZBgu6pKG2TSpvTfTeeimT294yxV2AEiBKZdY2ai", - "decimals": 6, - "extensions": { "coingeckoId": "solx-gaming-guild" }, - "icon": "https://img.raydium.io/icon/3eLpKZBgu6pKG2TSpvTfTeeimT294yxV2AEiBKZdY2ai.png" - }, - { - "symbol": "FLOKI", - "name": "Floki Viking", - "mint": "3fFHsncY59ue2HPduo1KhbZRWYRd8iek5tj88sPXMgFk", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3fFHsncY59ue2HPduo1KhbZRWYRd8iek5tj88sPXMgFk.png" - }, - { - "symbol": "CCG", - "name": "Collectors Club Governance", - "mint": "3FYzcJvLeQubLuAgacV6sDu9Ye8Eg1vFYpCxD3ogp74M", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3FYzcJvLeQubLuAgacV6sDu9Ye8Eg1vFYpCxD3ogp74M.png" - }, - { - "symbol": "ORO", - "name": "Shizen Orochi - ORO", - "mint": "3GfdtDnQC6mjkdr9cEaSr9mjS2VnSYoVypQiT2PPRBch", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3GfdtDnQC6mjkdr9cEaSr9mjS2VnSYoVypQiT2PPRBch.png" - }, - { - "symbol": "METAIN", - "name": "Meta Infinity", - "mint": "3H3AeG7BRmCmCJuQ21Am24SYcgFBkgpX6miSSDM7YmW7", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3H3AeG7BRmCmCJuQ21Am24SYcgFBkgpX6miSSDM7YmW7.png" - }, - { - "symbol": "ELONCASH", - "name": "ElonCash", - "mint": "3HaDnJ2PEt7v7RE8dPaSzSCgBL5dWvWtTkGaEGs5ap3N", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3HaDnJ2PEt7v7RE8dPaSzSCgBL5dWvWtTkGaEGs5ap3N.png" - }, - { - "symbol": "GFT", - "name": "GFT Goofiez Token", - "mint": "3HDyDDvRTmSMa5QxhUod5gEgVKmTujncwKomxrWxSb8j", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3HDyDDvRTmSMa5QxhUod5gEgVKmTujncwKomxrWxSb8j.png" - }, - { - "symbol": "FRP", - "name": "Filthy Rich Pups Token", - "mint": "3HVG8MLMAsu1Rd7gEkQ2K7HrsjpzV6Em3hp5Ug1V3ds1", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3HVG8MLMAsu1Rd7gEkQ2K7HrsjpzV6Em3hp5Ug1V3ds1.png" - }, - { - "symbol": "SHIBU", - "name": "SHIBU Token", - "mint": "3iBZV8gvUFxp333FFogUPVi6MP9dEZ74xUxVzEQvNPii", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3iBZV8gvUFxp333FFogUPVi6MP9dEZ74xUxVzEQvNPii.png" - }, - { - "symbol": "DoggyStyle", - "name": "Doggy Style", - "mint": "3in9a9yHtdjDFRjDyGTTpGUwJpT9zZBcyjQ8J7nqqNtq", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3in9a9yHtdjDFRjDyGTTpGUwJpT9zZBcyjQ8J7nqqNtq.png" - }, - { - "symbol": "Spro", - "name": "Sproken Token", - "mint": "3iXydLpqi38CeGDuLFF1WRbPrrkNbUsgVf98cNSg6NaA", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3iXydLpqi38CeGDuLFF1WRbPrrkNbUsgVf98cNSg6NaA.png" - }, - { - "symbol": "FLOOF", - "name": "FLOOF", - "mint": "3jzdrXXKxwkBk82u2eCWASZLCKoZs1LQTg87HBEAmBJw", - "decimals": 1, - "extensions": { "coingeckoId": "floof" }, - "icon": "https://img.raydium.io/icon/3jzdrXXKxwkBk82u2eCWASZLCKoZs1LQTg87HBEAmBJw.png" - }, - { - "symbol": "WOLFE", - "name": "Wolfecoin", - "mint": "3KnVxWhoYdc9UwDr5WMVkZp2LpF7gnojg7We7MUd6ixQ", - "decimals": 9, - "extensions": { "coingeckoId": "wolfecoin" }, - "icon": "https://img.raydium.io/icon/3KnVxWhoYdc9UwDr5WMVkZp2LpF7gnojg7We7MUd6ixQ.png" - }, - { - "symbol": "CC", - "name": "Castle Coin", - "mint": "3KTkQJEMJXP741EJBFcAS34Lx9t8GsBYaW2BUUWkeyDH", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3KTkQJEMJXP741EJBFcAS34Lx9t8GsBYaW2BUUWkeyDH.png" - }, - { - "symbol": "MORN", - "name": "GoodMorning Token", - "mint": "3LCSAo9Hf64cxtPbArLog3PKkwGkZFN7Ttz1zLdPWPTS", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3LCSAo9Hf64cxtPbArLog3PKkwGkZFN7Ttz1zLdPWPTS.png" - }, - { - "symbol": "FEED", - "name": "FEED Token on Alien Chicken Farm", - "mint": "3LDAW7enNUZ4DjE1jCi1cDpXvXLrJ1rPiECPbcHpMgG2", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3LDAW7enNUZ4DjE1jCi1cDpXvXLrJ1rPiECPbcHpMgG2.png" - }, - { - "symbol": "WAGMI", - "name": "WAGMI", - "mint": "3m7A2A8HHdqmiDrjAfaddj7Hxd88FrBHA1KSoqjoELtu", - "decimals": 6, - "extensions": { "coingeckoId": "wagmi-on-solana" }, - "icon": "https://img.raydium.io/icon/3m7A2A8HHdqmiDrjAfaddj7Hxd88FrBHA1KSoqjoELtu.png" - }, - { - "symbol": "SAMOY", - "name": "Samoy Meme Dog", - "mint": "3mXx1bNiB5bhgwznk4eeqM9eoy6DU3CeCkm1LPabeoEh", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3mXx1bNiB5bhgwznk4eeqM9eoy6DU3CeCkm1LPabeoEh.png" - }, - { - "symbol": "SQUIDGAME", - "name": "Squid Game", - "mint": "3NcCuwvTMnnf7TU2UEVhp6v2nzbLXQiDgzQySS6m8A7P", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3NcCuwvTMnnf7TU2UEVhp6v2nzbLXQiDgzQySS6m8A7P.png" - }, - { - "symbol": "CHEEZE", - "name": "Cheeze", - "mint": "3oePHsi4fhoyuLAjqXEgBUPB1cs4bP9A8cZpc1dATS9c", - "decimals": 3, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3oePHsi4fhoyuLAjqXEgBUPB1cs4bP9A8cZpc1dATS9c.png" - }, - { - "symbol": "Otter", - "name": "Ottercoin", - "mint": "3oLpKntC8W9AxiFhafRGBeALGuKdimduUXVPo1GQNHuX", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "CSC", - "name": "Captain Shiba", - "mint": "3PNqq4kEqgRSkV5dYdcc6mtoaoXdaun9ytoCr4BgX5yA", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3PNqq4kEqgRSkV5dYdcc6mtoaoXdaun9ytoCr4BgX5yA.png" - }, - { - "symbol": "TYNA", - "name": "wTYNA", - "mint": "3QuAYThYKFXSmrTcSHsdd7sAxaFBobaCkLy2DBYJLMDs", - "decimals": 3, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3QuAYThYKFXSmrTcSHsdd7sAxaFBobaCkLy2DBYJLMDs.png" - }, - { - "symbol": "PHPC", - "name": "Philippine Coin", - "mint": "3qvg2hSA4NHhe73Xv6rUuhFoGM77VBvZrmE4tWSHMQWe", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3qvg2hSA4NHhe73Xv6rUuhFoGM77VBvZrmE4tWSHMQWe.png" - }, - { - "symbol": "FamSOL", - "name": "FamilySOL", - "mint": "3rH1toffQAELHo5vyRKdwEFxhPTZA7ocfRdJK2c8txoJ", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3rH1toffQAELHo5vyRKdwEFxhPTZA7ocfRdJK2c8txoJ.png" - }, - { - "symbol": "$EGG", - "name": "EGG", - "mint": "3rkCq2ZAxoDGa3KWGebeiEMN92H5AV9HBLC9eVKDoPv8", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3rkCq2ZAxoDGa3KWGebeiEMN92H5AV9HBLC9eVKDoPv8.png" - }, - { - "symbol": "KS", - "name": "KALISTEN - Train To Earn", - "mint": "3swraHsc77KMg1tFvwH3tfYcd8SWr5fcUhtmRxjavG7H", - "decimals": 9, - "extensions": { "coingeckoId": "kalisten" }, - "icon": "https://img.raydium.io/icon/3swraHsc77KMg1tFvwH3tfYcd8SWr5fcUhtmRxjavG7H.png" - }, - { - "symbol": "SFOX", - "name": "SOL FOX", - "mint": "3TMdBbnXKASdx9rBcZ5HQsyqCky7Gt2ea44gYB6Ro15A", - "decimals": 9, - "extensions": { "coingeckoId": "sol-fox" }, - "icon": "https://img.raydium.io/icon/3TMdBbnXKASdx9rBcZ5HQsyqCky7Gt2ea44gYB6Ro15A.png" - }, - { - "symbol": "PTR", - "name": "PARTNER COIN", - "mint": "3UcBMHnSTCXaxUbP6B96kHcED98DgEnNa9rGKzwXKMf4", - "decimals": 0, - "extensions": { "coingeckoId": "partneroid" }, - "icon": "https://img.raydium.io/icon/3UcBMHnSTCXaxUbP6B96kHcED98DgEnNa9rGKzwXKMf4.png" - }, - { - "symbol": "ALEPH", - "name": "Aleph.im (Wormhole)", - "mint": "3UCMiSnkcnkPE1pgQ5ggPCBv6dXgVUy16TmMUe1WpG9x", - "decimals": 8, - "extensions": { "coingeckoId": "aleph-im-wormhole" }, - "icon": "https://img.raydium.io/icon/3UCMiSnkcnkPE1pgQ5ggPCBv6dXgVUy16TmMUe1WpG9x.png" - }, - { - "symbol": "NLTK", - "name": "Nasi Lemak", - "mint": "3uNAevHamuZKKQdtdLzmHNvqD8r14tXUUXx5PN48UbYC", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3uNAevHamuZKKQdtdLzmHNvqD8r14tXUUXx5PN48UbYC.png" - }, - { - "symbol": "FLVR", - "name": "Flokiverse", - "mint": "3vDfXEw3MZQgjYpLbjoZDYmgVci16CsC6ZDLgUzmcKR2", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3vDfXEw3MZQgjYpLbjoZDYmgVci16CsC6ZDLgUzmcKR2.png" - }, - { - "symbol": "TUTL", - "name": "TurtleTraders", - "mint": "3VhB8EAL8dZ457SiksLPpMUR1pyACpbNh5rTjQUEVCcH", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3VhB8EAL8dZ457SiksLPpMUR1pyACpbNh5rTjQUEVCcH.png" - }, - { - "symbol": "FRNT", - "name": "Final Frontier", - "mint": "3vHSsV6mgvpa1JVuuDZVB72vYbeUNzW4mBxiBftwzHEA", - "decimals": 9, - "extensions": { "coingeckoId": "final-frontier" }, - "icon": "https://img.raydium.io/icon/3vHSsV6mgvpa1JVuuDZVB72vYbeUNzW4mBxiBftwzHEA.png" - }, - { - "symbol": "SOUL", - "name": "Lost Souls", - "mint": "3vXYrqQkKpebReDPUaD1CseA3cWiqfxgPuKTe5aGL17U", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3vXYrqQkKpebReDPUaD1CseA3cWiqfxgPuKTe5aGL17U.png" - }, - { - "symbol": "PAW", - "name": "CopyCats token", - "mint": "3WV4fTWGvtWNvQb8oVU4t99By8KztDLtExqHnkPfHAA9", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3WV4fTWGvtWNvQb8oVU4t99By8KztDLtExqHnkPfHAA9.png" - }, - { - "symbol": "SKEM", - "name": "SKEM", - "mint": "3x7UeXDF4imKSKnizK9mYyx1M5bTNzpeALfPeB8S6XT9", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3x7UeXDF4imKSKnizK9mYyx1M5bTNzpeALfPeB8S6XT9.png" - }, - { - "symbol": "sBull", - "name": "SolBull - GoPromotedToken", - "mint": "3xVf2hPbkE5TuZNUPLQXFgFLD4LpvCM45BodbPmnpSSV", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "SINGULARITY", - "name": "Singularity", - "mint": "3xXMjiMyu4hthrVWmsxvBrKtehBWFgSKRnGB9Je4mmdA", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3xXMjiMyu4hthrVWmsxvBrKtehBWFgSKRnGB9Je4mmdA.png" - }, - { - "symbol": "ULTRON", - "name": "Ultron", - "mint": "3zD9zassLocyH6Tdj2NYXw6ym1jtgaM3QDkmeJNwNjer", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3zD9zassLocyH6Tdj2NYXw6ym1jtgaM3QDkmeJNwNjer.png" - }, - { - "symbol": "METAS", - "name": "METASEER", - "mint": "3Ztt53vwGhQGoEp3n1RjSu4CFnGRfqzwo6L8KN8gmXfd", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3Ztt53vwGhQGoEp3n1RjSu4CFnGRfqzwo6L8KN8gmXfd.png" - }, - { - "symbol": "DAGE", - "name": "Dark Age", - "mint": "3ZXVxxX6zCf5Yqeq6iwdTuVwC6E8b7bs2q3D1Prg86sv", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3ZXVxxX6zCf5Yqeq6iwdTuVwC6E8b7bs2q3D1Prg86sv.png" - }, - { - "symbol": "TTCS", - "name": "TTCS Token", - "mint": "3ZYsJZ7wb4hNEkfaDnR4JKT6Rok4hEfbxjGqDA3cRxGS", - "decimals": 5, - "extensions": {}, - "icon": "https://img.raydium.io/icon/3ZYsJZ7wb4hNEkfaDnR4JKT6Rok4hEfbxjGqDA3cRxGS.png" - }, - { - "symbol": "LINU", - "name": "LittleInu Token", - "mint": "41TwwURtuv4k8TuFxp1vfFYP9noMbHXqtscse8xLM26V", - "decimals": 9, - "extensions": { "coingeckoId": "littleinu" }, - "icon": "https://img.raydium.io/icon/41TwwURtuv4k8TuFxp1vfFYP9noMbHXqtscse8xLM26V.png" - }, - { - "symbol": "GMFC", - "name": "Gamify Club", - "mint": "42Y3CgJQLnHjdScYMu8VS4TbeZMUNVdBMKYbf7hz7aum", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/42Y3CgJQLnHjdScYMu8VS4TbeZMUNVdBMKYbf7hz7aum.png" - }, - { - "symbol": "SHIWO", - "name": "ShibWolf", - "mint": "43q34gUCKfgBQcJSNq2M4s8uVGuGtfAFQXES1BzW5UBv", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/43q34gUCKfgBQcJSNq2M4s8uVGuGtfAFQXES1BzW5UBv.png" - }, - { - "symbol": "STNK", - "name": "Stonks", - "mint": "43VWkd99HjqkhFTZbWBpMpRhjG469nWa7x7uEsgSH7We", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/43VWkd99HjqkhFTZbWBpMpRhjG469nWa7x7uEsgSH7We.png" - }, - { - "symbol": "SOLP", - "name": "SOL Playground Coin", - "mint": "45eBLJUCQf1acXdBG8daBfUudy8T7V5gDTBpiE1iezsN", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/45eBLJUCQf1acXdBG8daBfUudy8T7V5gDTBpiE1iezsN.png" - }, - { - "symbol": "INU", - "name": "Monster Inu", - "mint": "45HfvXJHY9msY2i4EmUpume1mSMLUvdaWsJRbctAobQM", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/45HfvXJHY9msY2i4EmUpume1mSMLUvdaWsJRbctAobQM.png" - }, - { - "symbol": "SWERVE", - "name": "Swerve Protocol", - "mint": "45ojchnvC3agGNvs86MWBq8N4miiTY6X8ECQzgQNDE4v", - "decimals": 9, - "extensions": { "coingeckoId": "swerve-protocol" }, - "icon": "https://img.raydium.io/icon/45ojchnvC3agGNvs86MWBq8N4miiTY6X8ECQzgQNDE4v.png" - }, - { - "symbol": "BOFB", - "name": "BofB", - "mint": "45wdSjpSqZCk9mkqmq5Nh7beCEqqUJMJcVduwYCip5eq", - "decimals": 8, - "extensions": { "coingeckoId": "bofb" }, - "icon": "https://img.raydium.io/icon/45wdSjpSqZCk9mkqmq5Nh7beCEqqUJMJcVduwYCip5eq.png" - }, - { - "symbol": "$Yakuza", - "name": "Yakuza Wars", - "mint": "48A1pXHvottXTf954CMhZyoG7MdFjngLJCDKJS6iJUth", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/48A1pXHvottXTf954CMhZyoG7MdFjngLJCDKJS6iJUth.png" - }, - { - "symbol": "DRAW", - "name": "DragonWar", - "mint": "48AEwauAHsJibyt3WqjQ6EoHnFBcnyHASfo7vB2eCXPS", - "decimals": 0, - "extensions": { "coingeckoId": "dragon-war" }, - "icon": "https://img.raydium.io/icon/48AEwauAHsJibyt3WqjQ6EoHnFBcnyHASfo7vB2eCXPS.png" - }, - { - "symbol": "TRIT", - "name": "Trit", - "mint": "48FCZmKZw3iJcvuAMMShWRSimJ9DN2BBN4exgRpTp5WG", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/48FCZmKZw3iJcvuAMMShWRSimJ9DN2BBN4exgRpTp5WG.png" - }, - { - "symbol": "PSY", - "name": "PSY Coin", - "mint": "49jpm8SpyTwaGaJfUa4AmU28hmW1HoKuqzXkgykysowU", - "decimals": 9, - "extensions": { "coingeckoId": "psy-coin" }, - "icon": "https://img.raydium.io/icon/49jpm8SpyTwaGaJfUa4AmU28hmW1HoKuqzXkgykysowU.png" - }, - { - "symbol": "HCOIN", - "name": "Hydrogencoin", - "mint": "4B619RbcXbXrKTzNVgDSRiUn9wfxWgA1w1oFLveGacNy", - "decimals": 3, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4B619RbcXbXrKTzNVgDSRiUn9wfxWgA1w1oFLveGacNy.png" - }, - { - "symbol": "$NUT", - "name": "NUT", - "mint": "4bgRUBC4gPoTs38TytDwujhcdn7reRoKynecvK7fJ5VW", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4bgRUBC4gPoTs38TytDwujhcdn7reRoKynecvK7fJ5VW.png" - }, - { - "symbol": "NPC", - "name": "Nole NPC", - "mint": "4BPw4jwHWqQCbkD2VWtLFL5PLBRmkHZiievTm1ebiWYJ", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "SWOLE", - "name": "Swole Doge", - "mint": "4BzxVoBQzwKoqm1dQc78r42Yby3EzAeZmMiYFdCjeu5Z", - "decimals": 9, - "extensions": { "coingeckoId": "swole-doge" }, - "icon": "https://img.raydium.io/icon/4BzxVoBQzwKoqm1dQc78r42Yby3EzAeZmMiYFdCjeu5Z.png" - }, - { - "symbol": "PCC", - "name": "Purpose Cash", - "mint": "4c5K1DJ3TcUkHt68PrBAzrYJj35r5hv9PAVsL2owYwn5", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4c5K1DJ3TcUkHt68PrBAzrYJj35r5hv9PAVsL2owYwn5.png" - }, - { - "symbol": "COT", - "name": "Colibri Token", - "mint": "4cSZkVz2S9qZqng58zd3gcMKmSZ864GAzcR8ezH1SHhw", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4cSZkVz2S9qZqng58zd3gcMKmSZ864GAzcR8ezH1SHhw.png" - }, - { - "symbol": "FLX", - "name": "Fluxx", - "mint": "4D2umdRkmjgsFj4Vf9foJGMkTjNQ41jXaGuAL3xb4dQj", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4D2umdRkmjgsFj4Vf9foJGMkTjNQ41jXaGuAL3xb4dQj.png" - }, - { - "symbol": "SWARM", - "name": "MIM", - "mint": "4dydh8EGNEdTz6grqnGBxpduRg55eLnwNZXoNZJetadu", - "decimals": 9, - "extensions": { "coingeckoId": "mim" }, - "icon": "https://img.raydium.io/icon/4dydh8EGNEdTz6grqnGBxpduRg55eLnwNZXoNZJetadu.png" - }, - { - "symbol": "REJECT", - "name": "REJECT Token", - "mint": "4F2yutcbkabE5MJoDvrDLa5U2re5HPABSCVKA7vqrKcH", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4F2yutcbkabE5MJoDvrDLa5U2re5HPABSCVKA7vqrKcH.png" - }, - { - "symbol": "$FLY", - "name": "StayFly", - "mint": "4h4LvS6NsVjZ87uBwrYyTeppTm1ii5PtRN9A6Ld2kZjw", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4h4LvS6NsVjZ87uBwrYyTeppTm1ii5PtRN9A6Ld2kZjw.png" - }, - { - "symbol": "GTON", - "name": "Graviton", - "mint": "4hJ6sjwmsvvFag6TKL97yhWiBSDX9BABWoiXgb3EPXxB", - "decimals": 8, - "extensions": {}, - "icon": "" - }, - { - "symbol": "UREP", - "name": "UNIVERSAL REPVBLIK TOKEN", - "mint": "4id3Lrw5BJruX7VQ3iRbmpnt8JHYKEkFd47j9NFgirFp", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4id3Lrw5BJruX7VQ3iRbmpnt8JHYKEkFd47j9NFgirFp.png" - }, - { - "symbol": "SCHOLA", - "name": "Schola", - "mint": "4J4XAtCWWVrb4FBM4JySPWX3YWix2bTpZNtAAHH4UEba", - "decimals": 3, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4J4XAtCWWVrb4FBM4JySPWX3YWix2bTpZNtAAHH4UEba.png" - }, - { - "symbol": "VOXM", - "name": "VOXM", - "mint": "4k9g62bc6iMRCb1hGaW2v1YjQfMci7hqbSVWKoaePxhF", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4k9g62bc6iMRCb1hGaW2v1YjQfMci7hqbSVWKoaePxhF.png" - }, - { - "symbol": "HORO", - "name": "Horo-Ikimono", - "mint": "4ktGVhz9DhUiCj2p4ZYE5foHTtMATtG47PyNqeGHx7ev", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4ktGVhz9DhUiCj2p4ZYE5foHTtMATtG47PyNqeGHx7ev.png" - }, - { - "symbol": "NINJAS", - "name": "Blue Chips Ninjas Token", - "mint": "4KwJBSGtpoxGY8pUUEsjpModoYgRGgaqNEZHrd11DzsV", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4KwJBSGtpoxGY8pUUEsjpModoYgRGgaqNEZHrd11DzsV.png" - }, - { - "symbol": "ALIEN", - "name": "AlienUniverse Token", - "mint": "4mJ6N65rD9w6sFPQ17UDWot2H64UtzR31biVLaKpZT6J", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4mJ6N65rD9w6sFPQ17UDWot2H64UtzR31biVLaKpZT6J.png" - }, - { - "symbol": "WAV", - "name": "Fractionalized WAVE-999", - "mint": "4NGNdLiQ1KG8GgqZimKku4WCLdXbNw6UQJvqax3fE6CJ", - "decimals": 2, - "extensions": { "coingeckoId": "fractionalized-wave-999" }, - "icon": "https://img.raydium.io/icon/4NGNdLiQ1KG8GgqZimKku4WCLdXbNw6UQJvqax3fE6CJ.png" - }, - { - "symbol": "AIO", - "name": "AIO Exchange Token", - "mint": "4nhQdXfoHvCCVnyZQg3awXqPrKL89Ys7Rbe77oXM47GG", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4nhQdXfoHvCCVnyZQg3awXqPrKL89Ys7Rbe77oXM47GG.png" - }, - { - "symbol": "BNCE", - "name": "BOUNCER", - "mint": "4NJ1L4LHSbJpk4h4rHQnJNKZbRSYticS8sQVPbGHsj33", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4NJ1L4LHSbJpk4h4rHQnJNKZbRSYticS8sQVPbGHsj33.png" - }, - { - "symbol": "KLB", - "name": "Black Label", - "mint": "4NPzwMK2gfgQ6rTv8x4EE1ZvKW6MYyYTSrAZCx7zxyaX", - "decimals": 0, - "extensions": { "coingeckoId": "black-label" }, - "icon": "https://img.raydium.io/icon/4NPzwMK2gfgQ6rTv8x4EE1ZvKW6MYyYTSrAZCx7zxyaX.png" - }, - { - "symbol": "WAMO", - "name": "WAMO", - "mint": "4nQqJkBx3Dnovc6ueEdkJfFr2zi2fc77834czmoymR1b", - "decimals": 6, - "extensions": { "coingeckoId": "wamo" }, - "icon": "https://img.raydium.io/icon/4nQqJkBx3Dnovc6ueEdkJfFr2zi2fc77834czmoymR1b.png" - }, - { - "symbol": "LAVA", - "name": "LAVA Token", - "mint": "4o67Pazc9fNqEfQM66xqWngw7WdAUzsccdpPmKsANDg1", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4o67Pazc9fNqEfQM66xqWngw7WdAUzsccdpPmKsANDg1.png" - }, - { - "symbol": "BIJU", - "name": "BIJU", - "mint": "4onzDs1X6ubktirorHB8iYbve3K4bBtkGpYehqzGm9So", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4onzDs1X6ubktirorHB8iYbve3K4bBtkGpYehqzGm9So.png" - }, - { - "symbol": "rPUNK", - "name": "Random Solpunks", - "mint": "4PhPtyBhmMYBLjiJPr3wef2syoMSJYn5WcNgXxvmG3NZ", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4PhPtyBhmMYBLjiJPr3wef2syoMSJYn5WcNgXxvmG3NZ.png" - }, - { - "symbol": "oDOP", - "name": "Dominican Pesos", - "mint": "4pk3pf9nJDN1im1kNwWJN1ThjE8pCYCTexXYGyFjqKVf", - "decimals": 9, - "extensions": { "coingeckoId": "odop" }, - "icon": "https://img.raydium.io/icon/4pk3pf9nJDN1im1kNwWJN1ThjE8pCYCTexXYGyFjqKVf.png" - }, - { - "symbol": "N2H4", - "name": "Hydrazine", - "mint": "4q5UBXJxE91BZKX548qhU8i5QBWvZdXzS3RZwfTgLQda", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4q5UBXJxE91BZKX548qhU8i5QBWvZdXzS3RZwfTgLQda.png" - }, - { - "symbol": "Trippin", - "name": "Fractionalized Trippin' Ape Tribe -7656", - "mint": "4qagvcSsN4ovsUsSs1hBh9Qzt5SZHsfNu9BtjQsJyK7W", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4qagvcSsN4ovsUsSs1hBh9Qzt5SZHsfNu9BtjQsJyK7W.png" - }, - { - "symbol": "SLNK", - "name": "Solanka Coin", - "mint": "4qcHQruwW1NcSMxQ6v2eYKGxnGSDHdEZ9i7JvaL1ZADL", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4qcHQruwW1NcSMxQ6v2eYKGxnGSDHdEZ9i7JvaL1ZADL.png" - }, - { - "symbol": "AGTE", - "name": "Agronomist coin", - "mint": "4QV4wzDdy7S1EV6y2r9DkmaDsHeoKz6HUvFLVtAsu6dV", - "decimals": 9, - "extensions": { "coingeckoId": "agronomist" }, - "icon": "https://img.raydium.io/icon/4QV4wzDdy7S1EV6y2r9DkmaDsHeoKz6HUvFLVtAsu6dV.png" - }, - { - "symbol": "SSK", - "name": "SolShark", - "mint": "4qw5MNc9oLKS22hiFTK6TNBHCqegDK3qzhMDgawtwnUL", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4qw5MNc9oLKS22hiFTK6TNBHCqegDK3qzhMDgawtwnUL.png" - }, - { - "symbol": "REO", - "name": "REO", - "mint": "4rii94eJ9oh2rPNQY4y11gz4g7CtTfH9pULqFoCHFeCC", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4rii94eJ9oh2rPNQY4y11gz4g7CtTfH9pULqFoCHFeCC.png" - }, - { - "symbol": "DOMOD", - "name": "IDOMODI", - "mint": "4SpfLz9RrF55WKEUBHFcMssFexpmdhymhcDoPSpAEwvi", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4SpfLz9RrF55WKEUBHFcMssFexpmdhymhcDoPSpAEwvi.png" - }, - { - "symbol": "SCT", - "name": "SolClout", - "mint": "4Te4KJgjtnZe4aE2zne8G4NPfrPjCwDmaiEx9rKnyDVZ", - "decimals": 9, - "extensions": { "coingeckoId": "solclout" }, - "icon": "https://img.raydium.io/icon/4Te4KJgjtnZe4aE2zne8G4NPfrPjCwDmaiEx9rKnyDVZ.png" - }, - { - "symbol": "1SOL", - "name": "1sol.io Token", - "mint": "4ThReWAbAVZjNVgs5Ui9Pk3cZ5TYaD9u6Y89fp6EFzoF", - "decimals": 8, - "extensions": { "coingeckoId": "1sol-io-wormhole" }, - "icon": "https://img.raydium.io/icon/4ThReWAbAVZjNVgs5Ui9Pk3cZ5TYaD9u6Y89fp6EFzoF.png" - }, - { - "symbol": "ELU", - "name": "Elumia Crowns", - "mint": "4tJZhSdGePuMEfZQ3h5LaHjTPsw1iWTRFTojnZcwsAU6", - "decimals": 9, - "extensions": { "coingeckoId": "elumia" }, - "icon": "https://img.raydium.io/icon/4tJZhSdGePuMEfZQ3h5LaHjTPsw1iWTRFTojnZcwsAU6.png" - }, - { - "symbol": "ELL", - "name": "Elliel", - "mint": "4TT62MBAWgE1m9hJ7ABG7VvgGvnth3eXe6N3MB6xKSqt", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4TT62MBAWgE1m9hJ7ABG7VvgGvnth3eXe6N3MB6xKSqt.png" - }, - { - "symbol": "WAVES", - "name": "Playground Waves Floor Index", - "mint": "4uRn7vxRPWYP4HuAa4UNXwEPLRL8oQ71YByMhr6yBnL4", - "decimals": 2, - "extensions": { "coingeckoId": "playground-waves-floor-index" }, - "icon": "https://img.raydium.io/icon/4uRn7vxRPWYP4HuAa4UNXwEPLRL8oQ71YByMhr6yBnL4.png" - }, - { - "symbol": "XSB", - "name": "Solareum", - "mint": "4UuGQgkD3rSeoXatXRWwRfRd21G87d5LiCfkVzNNv1Tt", - "decimals": 9, - "extensions": { "coingeckoId": "solareum-wallet" }, - "icon": "https://img.raydium.io/icon/4UuGQgkD3rSeoXatXRWwRfRd21G87d5LiCfkVzNNv1Tt.png" - }, - { - "symbol": "HONSHU", - "name": "HONSHU", - "mint": "4vXidyArpT8fyQTmfXfMNHitj5ay1Fjcnbw9fJLL2zBa", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4vXidyArpT8fyQTmfXfMNHitj5ay1Fjcnbw9fJLL2zBa.png" - }, - { - "symbol": "DHAN", - "name": "Dhancoin", - "mint": "4Wk4qLfLEXFTJqH9zn2LBqccorX2K2rjV9UwyujjUByW", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4Wk4qLfLEXFTJqH9zn2LBqccorX2K2rjV9UwyujjUByW.png" - }, - { - "symbol": "BOLT", - "name": "Bolt Token", - "mint": "4xDPH7DVtDXA2eU6wp9BjhryfXEdxBuhe4hnEc9yz1pJ", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4xDPH7DVtDXA2eU6wp9BjhryfXEdxBuhe4hnEc9yz1pJ.png" - }, - { - "symbol": "BRIDGE", - "name": "Bridge Network", - "mint": "4xU44oSF32sFXzTG2PRNhsxJidLegyGTGV8Fmu5grLFy", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4xU44oSF32sFXzTG2PRNhsxJidLegyGTGV8Fmu5grLFy.png" - }, - { - "symbol": "CATOMIAOU", - "name": "Cato Miaouss", - "mint": "4ZEDNmqoLbzwJVAJZNhRgz31Da8DauDkpSfH9iU2vXA4", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4ZEDNmqoLbzwJVAJZNhRgz31Da8DauDkpSfH9iU2vXA4.png" - }, - { - "symbol": "APEM", - "name": "APEMOON", - "mint": "4ZwWddrPzfgMxyEgQ7kzVrqoqX5D9BQJPwduQUBMmePs", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/4ZwWddrPzfgMxyEgQ7kzVrqoqX5D9BQJPwduQUBMmePs.png" - }, - { - "symbol": "$GLUE", - "name": "Glue Token", - "mint": "51AA7ktYcb8yb98Tfrhs6TaDjr7cMtJVo6sEMNe87mNs", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/51AA7ktYcb8yb98Tfrhs6TaDjr7cMtJVo6sEMNe87mNs.png" - }, - { - "symbol": "SHEEP", - "name": "SolWolf Game Token", - "mint": "52WyZe1pfobyq6v1t7KAKZWePcq9Aj2Aa5kJHuF2KHDM", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/52WyZe1pfobyq6v1t7KAKZWePcq9Aj2Aa5kJHuF2KHDM.png" - }, - { - "symbol": "MHC", - "name": "Most Hyped Crypto", - "mint": "52Y1RGnRFvRFUQq5r2AWpFLLFvokiiqxRocsWVpmPTU4", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/52Y1RGnRFvRFUQq5r2AWpFLLFvokiiqxRocsWVpmPTU4.png" - }, - { - "symbol": "LGBR", - "name": "LGBR - LETS GO BRANDON", - "mint": "53dqN1unCex98QWzLZtk1ssJptEcRwZapTrv8pakcgNB", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "VOO", - "name": "VooVoo", - "mint": "55t1PfJngPgMS4c4HeSHPy54VWfkMEk7XBQhSkdz6Cm6", - "decimals": 9, - "extensions": { "coingeckoId": "voovoo" }, - "icon": "https://img.raydium.io/icon/55t1PfJngPgMS4c4HeSHPy54VWfkMEk7XBQhSkdz6Cm6.png" - }, - { - "symbol": "CRYY", - "name": "CRY Coin", - "mint": "56tNQ29XBrbovm5K5SThuQatjCy92w2wKUaUeQ8WCD9g", - "decimals": 9, - "extensions": { "coingeckoId": "cry-coin" }, - "icon": "https://img.raydium.io/icon/56tNQ29XBrbovm5K5SThuQatjCy92w2wKUaUeQ8WCD9g.png" - }, - { - "symbol": "DONKEY", - "name": "Donkey Hee Haw", - "mint": "58yYYVT5FoVx2jtvD9xtX4JxE8jogtA5tjMkJudgERMS", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/58yYYVT5FoVx2jtvD9xtX4JxE8jogtA5tjMkJudgERMS.png" - }, - { - "symbol": "TSI", - "name": "Tesla Shiba Inu", - "mint": "5cKFNtooCQSkLhdFukk8R3PTdT4Rvm9cJr8Et49TxchR", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5cKFNtooCQSkLhdFukk8R3PTdT4Rvm9cJr8Et49TxchR.png" - }, - { - "symbol": "RAINBOW", - "name": "LGBTQ COMMUNITY", - "mint": "5cPc4dx8D61JrbHqVZ8Ywsf2L6FeBMRmgstg1mWc65Ti", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5cPc4dx8D61JrbHqVZ8Ywsf2L6FeBMRmgstg1mWc65Ti.png" - }, - { - "symbol": "MZOO", - "name": "Millionaire ZOO", - "mint": "5DfhZugS25gPf84LF5u6LjRCzW1XCFuRd88PAujoeic5", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5DfhZugS25gPf84LF5u6LjRCzW1XCFuRd88PAujoeic5.png" - }, - { - "symbol": "SHARKS", - "name": "Rogue Sharks Floor Index", - "mint": "5dgSRQ4oL8C942K4qPBuhjkbTNHtfqHMADhYE25PmhPG", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5dgSRQ4oL8C942K4qPBuhjkbTNHtfqHMADhYE25PmhPG.png" - }, - { - "symbol": "MALL", - "name": "MetaMall", - "mint": "5EbpXhW7t8ypBF3Q1X7odFaHjuh7XJfCohXR3VYAW32i", - "decimals": 3, - "extensions": { "coingeckoId": "metamall" }, - "icon": "https://img.raydium.io/icon/5EbpXhW7t8ypBF3Q1X7odFaHjuh7XJfCohXR3VYAW32i.png" - }, - { - "symbol": "LIZARD", - "name": "Lizard Token", - "mint": "5ENUvV3Ur3o3Fg6LVRfHL4sowidiVTMHHsEFqNJXRz6o", - "decimals": 4, - "extensions": { "coingeckoId": "lizard-token" }, - "icon": "" - }, - { - "symbol": "ACE", - "name": "ACE", - "mint": "5fhXkD8tXyDB9rmYZSNJ6LneLr2nMteMpCVxeDDEgXa3", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5fhXkD8tXyDB9rmYZSNJ6LneLr2nMteMpCVxeDDEgXa3.png" - }, - { - "symbol": "WHEY", - "name": "WHEY", - "mint": "5fTwKZP2AK39LtFN9Ayppu6hdCVKfMGVm79F2EgHCtsi", - "decimals": 6, - "extensions": { "coingeckoId": "whey-token" }, - "icon": "https://img.raydium.io/icon/5fTwKZP2AK39LtFN9Ayppu6hdCVKfMGVm79F2EgHCtsi.png" - }, - { - "symbol": "HOM3", - "name": "Hom3 Protocol", - "mint": "5grpAJejHkwUaSRedSUw4vWerFGpgtc4gjVxu8GxuVRe", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5grpAJejHkwUaSRedSUw4vWerFGpgtc4gjVxu8GxuVRe.png" - }, - { - "symbol": "wID_v1", - "name": "Everest ID (Wormhole v1)", - "mint": "5HHv6HAyBtaihyHEapCJvjE6iRbGLRmm3F5EZjz6EzHV", - "decimals": 8, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5HHv6HAyBtaihyHEapCJvjE6iRbGLRmm3F5EZjz6EzHV.png" - }, - { - "symbol": "PARTICLES", - "name": "Particles Index", - "mint": "5hzLftaEyGTQJnoxhGxAvsLkmdjYsbx9YdjNwfNmtq2s", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5hzLftaEyGTQJnoxhGxAvsLkmdjYsbx9YdjNwfNmtq2s.png" - }, - { - "symbol": "ZDRT", - "name": "ZDRT Club Token", - "mint": "5i8C6n4VbELnTHtES83aqeh16uPiEyve4jHr2QN2WhSz", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5i8C6n4VbELnTHtES83aqeh16uPiEyve4jHr2QN2WhSz.png" - }, - { - "symbol": "CENT", - "name": "PowerStreetPro Token", - "mint": "5iEgPvFyVMyiR5iecrWSg7rRfXp2iTiUDzKRne9S9b4X", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "HELIX", - "name": "Metahelix Floor Index", - "mint": "5iUW2aLFsSD5oRkmxpRfKFffvKvTeFmEruABLYyY2MRX", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5iUW2aLFsSD5oRkmxpRfKFffvKvTeFmEruABLYyY2MRX.png" - }, - { - "symbol": "CHAD", - "name": "ChadTrader Token", - "mint": "5j6BmiZTfHssaWPT23EQYQci3w57VTw7QypKArQZbSZ9", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5j6BmiZTfHssaWPT23EQYQci3w57VTw7QypKArQZbSZ9.png" - }, - { - "symbol": "NPTC", - "name": "Neptun Coin", - "mint": "5j81MNxc3ru546HtUKq5b3qDg9qmqATZz89MYyKhdwhm", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "INU", - "name": "Solana INU", - "mint": "5jFnsfx36DyGk8uVGrbXnVUMTsBkPXGpx6e69BiGFzko", - "decimals": 9, - "extensions": { "coingeckoId": "solana-inu" }, - "icon": "https://img.raydium.io/icon/5jFnsfx36DyGk8uVGrbXnVUMTsBkPXGpx6e69BiGFzko.png" - }, - { - "symbol": "APYS", - "name": "APYSwap", - "mint": "5JnZ667P3VcjDinkJFysWh2K2KtViy63FZ3oL5YghEhW", - "decimals": 9, - "extensions": { "coingeckoId": "apyswap" }, - "icon": "https://img.raydium.io/icon/5JnZ667P3VcjDinkJFysWh2K2KtViy63FZ3oL5YghEhW.png" - }, - { - "symbol": "YORK", - "name": "Yorkipoo", - "mint": "5K1JtWpdSksVKaL6R2DuLpCDAjzxK6sq2CpXaXDWHVLg", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5K1JtWpdSksVKaL6R2DuLpCDAjzxK6sq2CpXaXDWHVLg.png" - }, - { - "symbol": "DoSC", - "name": "Dreams of SolCandy Token", - "mint": "5kANAUeHsoambmdV317Nhs8puVxfukyChr9j9TZ8ZeQq", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5kANAUeHsoambmdV317Nhs8puVxfukyChr9j9TZ8ZeQq.png" - }, - { - "symbol": "GU", - "name": "Kugle GU", - "mint": "5KV2W2XPdSo97wQWcuAVi6G4PaCoieg4Lhhi61PAMaMJ", - "decimals": 9, - "extensions": { "coingeckoId": "gu" }, - "icon": "https://img.raydium.io/icon/5KV2W2XPdSo97wQWcuAVi6G4PaCoieg4Lhhi61PAMaMJ.png" - }, - { - "symbol": "PIXL", - "name": "Pixels.so Token", - "mint": "5L2YboFbHAUpBDDJjvDB5M6pu9CW2FRjyDB2asZyvjtE", - "decimals": 8, - "extensions": { "coingeckoId": "pixels-so" }, - "icon": "https://img.raydium.io/icon/5L2YboFbHAUpBDDJjvDB5M6pu9CW2FRjyDB2asZyvjtE.png" - }, - { - "symbol": "ILUMA", - "name": "ILUMA COIN", - "mint": "5L87fjh5XZWERN4UGbK62TM1funxFvXSRUGmvbHBGqn1", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "scnSOL", - "name": "Socean staked SOL", - "mint": "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "decimals": 9, - "extensions": { "coingeckoId": "socean-staked-sol" }, - "icon": "https://img.raydium.io/icon/5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm.png" - }, - { - "symbol": "CATO", - "name": "CATO", - "mint": "5p2zjqCd1WJzAVgcEnjhb9zWDU7b9XVhFhx4usiyN7jB", - "decimals": 9, - "extensions": { "coingeckoId": "cato" }, - "icon": "https://img.raydium.io/icon/5p2zjqCd1WJzAVgcEnjhb9zWDU7b9XVhFhx4usiyN7jB.png" - }, - { - "symbol": "HDG", - "name": "Hedge Token", - "mint": "5PmpMzWjraf3kSsGEKtqdUsCoLhptg4yriZ17LKKdBBy", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5PmpMzWjraf3kSsGEKtqdUsCoLhptg4yriZ17LKKdBBy.png" - }, - { - "symbol": "LOOP", - "name": "Solana Loop", - "mint": "5pwyQZnX8GkabzowWtFHNeKER1J1omrAdJSYqjtffaQZ", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5pwyQZnX8GkabzowWtFHNeKER1J1omrAdJSYqjtffaQZ.png" - }, - { - "symbol": "NCT", - "name": "Encanto", - "mint": "5R8Ai4pQuzteR1Y5HxpscQH4Es2JNWcQZbMmu9RpZwoR", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5R8Ai4pQuzteR1Y5HxpscQH4Es2JNWcQZbMmu9RpZwoR.png" - }, - { - "symbol": "SLCAT", - "name": "Salad Cat Coin", - "mint": "5rFmh8C6Zj1VfL7ogB6PyVDnQkqsayvEPsEbbkUPX8f", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5rFmh8C6Zj1VfL7ogB6PyVDnQkqsayvEPsEbbkUPX8f.png" - }, - { - "symbol": "GNE", - "name": "Project GNE", - "mint": "5RRQKdF4MSicGSgx2HiGf9Fr4SN5m5743S3qpbcEc5fk", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5RRQKdF4MSicGSgx2HiGf9Fr4SN5m5743S3qpbcEc5fk.png" - }, - { - "symbol": "BMBO", - "name": "Bamboo", - "mint": "5sM9xxcBTM9rWza6nEgq2cShA87JjTBx1Cu82LjgmaEg", - "decimals": 9, - "extensions": { "coingeckoId": "bamboo-coin" }, - "icon": "https://img.raydium.io/icon/5sM9xxcBTM9rWza6nEgq2cShA87JjTBx1Cu82LjgmaEg.png" - }, - { - "symbol": "BBY", - "name": "BabylonDAO", - "mint": "5SZSVgnQDgKKxtCe3UA3x4T7tcSRNDaL3NmfdEqpuLzo", - "decimals": 9, - "extensions": { "coingeckoId": "babylondao" }, - "icon": "https://img.raydium.io/icon/5SZSVgnQDgKKxtCe3UA3x4T7tcSRNDaL3NmfdEqpuLzo.png" - }, - { - "symbol": "IBVOL", - "name": "IBlive", - "mint": "5TY71D29Cyuk9UrsSxLXw2quJBpS7xDDFuFu2K9W7Wf9", - "decimals": 6, - "extensions": {}, - "icon": "" - }, - { - "symbol": "SCIFI", - "name": "SciFi-Verse", - "mint": "5uE8w9yoMMu88NV8wUaZMuxCiufBBoSiJbNDAEGmDx7x", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5uE8w9yoMMu88NV8wUaZMuxCiufBBoSiJbNDAEGmDx7x.png" - }, - { - "symbol": "SOLD", - "name": "Solanax", - "mint": "5v6tZ1SiAi7G8Qg4rBF1ZdAn4cn6aeQtefewMr1NLy61", - "decimals": 9, - "extensions": { "coingeckoId": "solanax" }, - "icon": "https://img.raydium.io/icon/5v6tZ1SiAi7G8Qg4rBF1ZdAn4cn6aeQtefewMr1NLy61.png" - }, - { - "symbol": "KING", - "name": "King's token", - "mint": "5VQnKaTu522jRQyaawDNBKZjBa5SZoeetyDXEwocYxXN", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5VQnKaTu522jRQyaawDNBKZjBa5SZoeetyDXEwocYxXN.png" - }, - { - "symbol": "SP", - "name": "Space Puppy", - "mint": "5Wgco6reiMwazERpAm3JS1xD7JBHNJJQdNEE9MrUkwtJ", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5Wgco6reiMwazERpAm3JS1xD7JBHNJJQdNEE9MrUkwtJ.png" - }, - { - "symbol": "TPC", - "name": "TOYPOODLE COIN", - "mint": "5WWRMYPchxgh3VmYGPqoq2kfzCtBLxXB9vFH2TeFeR9m", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5WWRMYPchxgh3VmYGPqoq2kfzCtBLxXB9vFH2TeFeR9m.png" - }, - { - "symbol": "UPGRADE", - "name": "UPGRADE", - "mint": "5X6AuKY8QF2xzYUEYYCxf9t9FXhuG76hHJNAB8qUbKqz", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5X6AuKY8QF2xzYUEYYCxf9t9FXhuG76hHJNAB8qUbKqz.png" - }, - { - "symbol": "ORIA", - "name": "Memoria", - "mint": "5XiE2JApnDwGc24PSY7y7stD4JxStkYPAH5tFVKAcrow", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5XiE2JApnDwGc24PSY7y7stD4JxStkYPAH5tFVKAcrow.png" - }, - { - "symbol": "QUID", - "name": "Quid Token", - "mint": "5xnRrqoyoLBixNwjVet6Xb2ZTyBSXhENyUWj4sqzRGrv", - "decimals": 9, - "extensions": { "coingeckoId": "quid-token" }, - "icon": "https://img.raydium.io/icon/5xnRrqoyoLBixNwjVet6Xb2ZTyBSXhENyUWj4sqzRGrv.png" - }, - { - "symbol": "JESUS", - "name": "JESUS", - "mint": "5xq71UHmPSZ5s68DkXL8wrBVsWCh4zXgcn4wTWkqFdxa", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5xq71UHmPSZ5s68DkXL8wrBVsWCh4zXgcn4wTWkqFdxa.png" - }, - { - "symbol": "DSOL", - "name": "DecentSol", - "mint": "5y1YcGVPFy8bEiCJi79kegF9igahmvDe5UrqswFvnpMJ", - "decimals": 4, - "extensions": { "coingeckoId": "decentsol" }, - "icon": "https://img.raydium.io/icon/5y1YcGVPFy8bEiCJi79kegF9igahmvDe5UrqswFvnpMJ.png" - }, - { - "symbol": "TDX", - "name": "Tiddie Token", - "mint": "5yUX1XpjLSTDyNBTQ3N3oYpu6RH4gckqnSS6Ecg79fAL", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5yUX1XpjLSTDyNBTQ3N3oYpu6RH4gckqnSS6Ecg79fAL.png" - }, - { - "symbol": "RICE", - "name": "RICE", - "mint": "5yw793FZPCaPcuUN4F61VJh2ehsFX87zvHbCA4oRebfn", - "decimals": 2, - "extensions": { "coingeckoId": "rice" }, - "icon": "https://img.raydium.io/icon/5yw793FZPCaPcuUN4F61VJh2ehsFX87zvHbCA4oRebfn.png" - }, - { - "symbol": "MSP", - "name": "MSP", - "mint": "5Z7bWSvcxVeUkroSypFW3Tsw7vPoJUcCxhTFNenLxNoR", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/5Z7bWSvcxVeUkroSypFW3Tsw7vPoJUcCxhTFNenLxNoR.png" - }, - { - "symbol": "STEPN", - "name": "STEPN - Run To Earn", - "mint": "6156vEwBw11hGF6rkr3um5RPNWfBCYBFH7XcbEF47erH", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6156vEwBw11hGF6rkr3um5RPNWfBCYBFH7XcbEF47erH.png" - }, - { - "symbol": "SAMI", - "name": "SAMI", - "mint": "61m2xv1m6zTEAS86VfjFmNKG1ZGemNu19hzMmgstowLZ", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "BFS", - "name": "blockfilesystem", - "mint": "64ExnkDhpVwKzEjuqnkGgWVEtWZvWTG7JRyqQgzTWtFV", - "decimals": 9, - "extensions": { "coingeckoId": "blockfilesystem" }, - "icon": "https://img.raydium.io/icon/64ExnkDhpVwKzEjuqnkGgWVEtWZvWTG7JRyqQgzTWtFV.png" - }, - { - "symbol": "sAPE", - "name": "APE (Synthetic)", - "mint": "64Hw4Hm4WLC1Ty6p8g5vLZNCS37msb9Qq8ZFJE6UConN", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/64Hw4Hm4WLC1Ty6p8g5vLZNCS37msb9Qq8ZFJE6UConN.png" - }, - { - "symbol": "CTZN", - "name": "Citizens Index", - "mint": "663rbtf1FHhz1kQFAq41z63ViigQr8zAvZpNKJbZbF6C", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/663rbtf1FHhz1kQFAq41z63ViigQr8zAvZpNKJbZbF6C.png" - }, - { - "symbol": "ORNC", - "name": "Orion Coin", - "mint": "665t3SYTfoVtaRPP7QRbBG3V7ePVtWVKQXYkSaUfxS7u", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "SHOIT", - "name": "Shoit Coin", - "mint": "666YXKdQzN49gzQetYffQUhy4hLxEB31PZkRew4VrXAj", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/666YXKdQzN49gzQetYffQUhy4hLxEB31PZkRew4VrXAj.png" - }, - { - "symbol": "CLAN", - "name": "Clan Token", - "mint": "68RRPuZQrrw3whXHm9LSyC4y8iLrjkTm5Brc2tUMLNPw", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/68RRPuZQrrw3whXHm9LSyC4y8iLrjkTm5Brc2tUMLNPw.png" - }, - { - "symbol": "Paws", - "name": "Solana Paws", - "mint": "6bLp99VoqKU1C3Qp6VTNvSoCoc78jMGxPkGSSopq8wHB", - "decimals": 2, - "extensions": { "coingeckoId": "solana-paws" }, - "icon": "https://img.raydium.io/icon/6bLp99VoqKU1C3Qp6VTNvSoCoc78jMGxPkGSSopq8wHB.png" - }, - { - "symbol": "FANI", - "name": "FANITRADE", - "mint": "6c4L5nTH2sBKkfeuP3WhGp6Vq1tE4Suh4ezRp5KSu8Z7", - "decimals": 9, - "extensions": { "coingeckoId": "fanitrade" }, - "icon": "https://img.raydium.io/icon/6c4L5nTH2sBKkfeuP3WhGp6Vq1tE4Suh4ezRp5KSu8Z7.png" - }, - { - "symbol": "BUXX", - "name": "BUXX", - "mint": "6CEH3RdzsubHF94fRuU7DWGNh5XpatXmu6jqJnh7kqfM", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6CEH3RdzsubHF94fRuU7DWGNh5XpatXmu6jqJnh7kqfM.png" - }, - { - "symbol": "KINGSHIB", - "name": "King Shiba", - "mint": "6cH34XtzNgCDwb7NFbiji1a1N8F3FgmXTrFxvzBZNVui", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6cH34XtzNgCDwb7NFbiji1a1N8F3FgmXTrFxvzBZNVui.png" - }, - { - "symbol": "GOSU", - "name": "Gosu", - "mint": "6D7nXHAhsRbwj8KFZR2agB6GEjMLg4BM7MAqZzRT8F1j", - "decimals": 8, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6D7nXHAhsRbwj8KFZR2agB6GEjMLg4BM7MAqZzRT8F1j.png" - }, - { - "symbol": "MEME", - "name": "MemeMarketplace", - "mint": "6DNkUoMa6vNo3CsxAw5XMJhjmdPbPBENHJ6w35eMXESo", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6DNkUoMa6vNo3CsxAw5XMJhjmdPbPBENHJ6w35eMXESo.png" - }, - { - "symbol": "ARTE", - "name": "ARTE", - "mint": "6Dujewcxn1qCd6rcj448SXQL9YYqTcqZCNQdCn3xJAKS", - "decimals": 6, - "extensions": { "coingeckoId": "arte" }, - "icon": "https://img.raydium.io/icon/6Dujewcxn1qCd6rcj448SXQL9YYqTcqZCNQdCn3xJAKS.png" - }, - { - "symbol": "MOMO", - "name": "Momonga", - "mint": "6ercxSiDn2KJ8KZxmCT4eheQqAWN3z17s8eLT3VECuda", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6ercxSiDn2KJ8KZxmCT4eheQqAWN3z17s8eLT3VECuda.png" - }, - { - "symbol": "JJJJC", - "name": "JJC", - "mint": "6FLsSkF4AqQeDuqEmGPyBZvVebc4WWWntnZP2QZyBzG8", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6FLsSkF4AqQeDuqEmGPyBZvVebc4WWWntnZP2QZyBzG8.png" - }, - { - "symbol": "OXSQ", - "name": "Ox Squad Token", - "mint": "6fMoTH7Bad61GPzvqfq1XmRGFGv84MrvZfjDKGNuVwBz", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6fMoTH7Bad61GPzvqfq1XmRGFGv84MrvZfjDKGNuVwBz.png" - }, - { - "symbol": "QUACK", - "name": "QUACK", - "mint": "6frkvZf72wiz3uqRWhBqLftNU4PS6XXYCoNrW9P4CFdK", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6frkvZf72wiz3uqRWhBqLftNU4PS6XXYCoNrW9P4CFdK.png" - }, - { - "symbol": "SFC-BATTERY", - "name": "Solana Faction Cards Battery Pack", - "mint": "6GK4nhV3h2RDKmjY4u43N3HJWNs6nYSB1qSBnsj6a2px", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6GK4nhV3h2RDKmjY4u43N3HJWNs6nYSB1qSBnsj6a2px.png" - }, - { - "symbol": "HOOD", - "name": "HoodRatsNFT Token", - "mint": "6GVGRXC5wf7NjnTQxaqEZErtdsHupke7Fiz5pUG5VkkM", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6GVGRXC5wf7NjnTQxaqEZErtdsHupke7Fiz5pUG5VkkM.png" - }, - { - "symbol": "AINU", - "name": "Akamaru Inu", - "mint": "6H87YFkp5LHyN3KzDXa5r3QYce7WTcwYJi9SqwH3TXkQ", - "decimals": 1, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6H87YFkp5LHyN3KzDXa5r3QYce7WTcwYJi9SqwH3TXkQ.png" - }, - { - "symbol": "SBD", - "name": "Solana Bird", - "mint": "6HKq7SoHESuDz5ZbjZqgQkhrTiDFTfQdJapavMv7DbFb", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6HKq7SoHESuDz5ZbjZqgQkhrTiDFTfQdJapavMv7DbFb.png" - }, - { - "symbol": "$KSH", - "name": "Keeshond Coin", - "mint": "6j14WyX1Ag2pLWvn99euK4xp2VcZD62VeJv2iwCrYmT8", - "decimals": 9, - "extensions": { "coingeckoId": "keeshond" }, - "icon": "https://img.raydium.io/icon/6j14WyX1Ag2pLWvn99euK4xp2VcZD62VeJv2iwCrYmT8.png" - }, - { - "symbol": "BRERO", - "name": "Fraktionalized SMB 3394", - "mint": "6j28waP2NyoCBJrrVNHZuEzLDL25DXdNxMFsMNMxYht7", - "decimals": 3, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6j28waP2NyoCBJrrVNHZuEzLDL25DXdNxMFsMNMxYht7.png" - }, - { - "symbol": "KITTY", - "name": "KITTY SOLANA", - "mint": "6JdcMdhqgCtcP4U9tieRqmKLhPLxRMLC67QfmdXAJBvZ", - "decimals": 6, - "extensions": { "coingeckoId": "kitty-solana" }, - "icon": "https://img.raydium.io/icon/6JdcMdhqgCtcP4U9tieRqmKLhPLxRMLC67QfmdXAJBvZ.png" - }, - { - "symbol": "RUG", - "name": "RugCoin", - "mint": "6Km8PRUQxPmNX6EhmAuu3sFEnCP6uT2Yt42zPFR6VNnD", - "decimals": 8, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6Km8PRUQxPmNX6EhmAuu3sFEnCP6uT2Yt42zPFR6VNnD.png" - }, - { - "symbol": "SAIL", - "name": "SAIL", - "mint": "6kwTqmdQkJd8qRr9RjSnUX9XJ24RmJRSrU1rsragP97Y", - "decimals": 6, - "extensions": { "coingeckoId": "sail" }, - "icon": "https://img.raydium.io/icon/6kwTqmdQkJd8qRr9RjSnUX9XJ24RmJRSrU1rsragP97Y.png" - }, - { - "symbol": "ThugPenguin", - "name": "Thug Penguin", - "mint": "6MpQesMjehBwJzgDRDsbUXqjHetf1LGE94H7FDzRVL9Y", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6MpQesMjehBwJzgDRDsbUXqjHetf1LGE94H7FDzRVL9Y.png" - }, - { - "symbol": "SCRAP", - "name": "SCRAP", - "mint": "6naWDMGNWwqffJnnXFLBCLaYu1y5U9Rohe5wwJPHvf1p", - "decimals": 3, - "extensions": { "coingeckoId": "scrap" }, - "icon": "https://img.raydium.io/icon/6naWDMGNWwqffJnnXFLBCLaYu1y5U9Rohe5wwJPHvf1p.png" - }, - { - "symbol": "ELON", - "name": "Dogelon Mars (Wormhole)", - "mint": "6nKUU36URHkewHg5GGGAgxs6szkE4VTioGUT5txQqJFU", - "decimals": 8, - "extensions": { "coingeckoId": "dogelon-mars-wormhole" }, - "icon": "https://img.raydium.io/icon/6nKUU36URHkewHg5GGGAgxs6szkE4VTioGUT5txQqJFU.png" - }, - { - "symbol": "HOHOHO", - "name": "Santa Coin", - "mint": "6nY5u2KWywfY6ERXgBBr6YNfBATHi13HT1fge64vCAKo", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6nY5u2KWywfY6ERXgBBr6YNfBATHi13HT1fge64vCAKo.png" - }, - { - "symbol": "WEN", - "name": "WEN Token", - "mint": "6o4f6tuvVQTa9PTrHN9pvUeXEPusN6RLgMam1Zc7tYbm", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6o4f6tuvVQTa9PTrHN9pvUeXEPusN6RLgMam1Zc7tYbm.png" - }, - { - "symbol": "GOLEM", - "name": "Golem", - "mint": "6PBEGe6YaKmDPw1Ebza823SuvQWQgGZ2NTANBgaKdxHq", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6PBEGe6YaKmDPw1Ebza823SuvQWQgGZ2NTANBgaKdxHq.png" - }, - { - "symbol": "SKZ", - "name": "The SNKRZ Token", - "mint": "6piwLtPi6sYjvE1reSEpmAXfcJqJtyGp3fahhEU7VF2C", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6piwLtPi6sYjvE1reSEpmAXfcJqJtyGp3fahhEU7VF2C.png" - }, - { - "symbol": "CRYPT", - "name": "Cryptor", - "mint": "6pSK3JkbfFcQvu6TuTsRnG61jKxdbaoRRkp1H6jhxXV3", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6pSK3JkbfFcQvu6TuTsRnG61jKxdbaoRRkp1H6jhxXV3.png" - }, - { - "symbol": "PCPC", - "name": "PYROCHILL PYROCOIN", - "mint": "6qQnzsoH89TWZirgZS9AJN3NrxS7Y4K7oNt5N93E6QDR", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6qQnzsoH89TWZirgZS9AJN3NrxS7Y4K7oNt5N93E6QDR.png" - }, - { - "symbol": "rHRHC", - "name": "Random High Roller Hippo Clique", - "mint": "6RBwVuqgBsYsWXmEhV72MSBZMawuy9XxDpm9uzffxmw1", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6RBwVuqgBsYsWXmEhV72MSBZMawuy9XxDpm9uzffxmw1.png" - }, - { - "symbol": "PEACH", - "name": "PEACHO TOKEN", - "mint": "6StzwSrFeQEkF2xwADqdoz63RXR8dftf9BZnk91o52rm", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6StzwSrFeQEkF2xwADqdoz63RXR8dftf9BZnk91o52rm.png" - }, - { - "symbol": "OTR", - "name": "Otter Finance", - "mint": "6TgvYd7eApfcZ7K5Mur7MaUQ2xT7THB4cLHWuMkQdU5Z", - "decimals": 9, - "extensions": { "coingeckoId": "otter-finance" }, - "icon": "" - }, - { - "symbol": "NANA", - "name": "NANA", - "mint": "6uZ7MRGGf3FJhzk9TUk3QRMR2fz83WY9BEVBukRvMRVX", - "decimals": 9, - "extensions": { "coingeckoId": "chimp-fight" }, - "icon": "https://img.raydium.io/icon/6uZ7MRGGf3FJhzk9TUk3QRMR2fz83WY9BEVBukRvMRVX.png" - }, - { - "symbol": "wHAPI", - "name": "Wrapped HAPI", - "mint": "6VNKqgz9hk7zRShTFdg5AnkfKwZUcojzwAkzxSH3bnUm", - "decimals": 9, - "extensions": { "coingeckoId": "hapi" }, - "icon": "https://img.raydium.io/icon/6VNKqgz9hk7zRShTFdg5AnkfKwZUcojzwAkzxSH3bnUm.png" - }, - { - "symbol": "wDingocoin", - "name": "Wrapped Dingocoin", - "mint": "6VYF5jXq6rfq4QRgGMG6co7b1Ev1Lj7KSbHBxfQ9e1L3", - "decimals": 8, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6VYF5jXq6rfq4QRgGMG6co7b1Ev1Lj7KSbHBxfQ9e1L3.png" - }, - { - "symbol": "Kishu", - "name": "Kishu Inu", - "mint": "6wFgUMohoSavTuEneDYcrb9qF3JsYVVXyB8jb3PaXCJ4", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6wFgUMohoSavTuEneDYcrb9qF3JsYVVXyB8jb3PaXCJ4.png" - }, - { - "symbol": "TUT", - "name": "TUT", - "mint": "6wShYhqA2gs3HUAZ4MyaPDpKPBWFJUQQUGaCoy2k1Tgz", - "decimals": 9, - "extensions": { "coingeckoId": "turnt-up-tikis" }, - "icon": "https://img.raydium.io/icon/6wShYhqA2gs3HUAZ4MyaPDpKPBWFJUQQUGaCoy2k1Tgz.png" - }, - { - "symbol": "FOSSIL", - "name": "FOSSIL", - "mint": "6xcfmgzPgABAuAfGDhvvLLMfMDur4at7tU7j3NudUviK", - "decimals": 9, - "extensions": { "coingeckoId": "fossil" }, - "icon": "https://img.raydium.io/icon/6xcfmgzPgABAuAfGDhvvLLMfMDur4at7tU7j3NudUviK.png" - }, - { - "symbol": "CHIH", - "name": "CHIHUAHUA", - "mint": "6xtyNYX6Rf4Kp3629X11m1jqUmkV89mf9xQakUtUQfHq", - "decimals": 9, - "extensions": { "coingeckoId": "chihuahuasol" }, - "icon": "https://img.raydium.io/icon/6xtyNYX6Rf4Kp3629X11m1jqUmkV89mf9xQakUtUQfHq.png" - }, - { - "symbol": "KITTY", - "name": "Kitty Coin", - "mint": "6XWfkyg5mzGtKNftSDgYjyoPyUsLRf2rafj95XSFSFrr", - "decimals": 9, - "extensions": { "coingeckoId": "kitty-coin-solana" }, - "icon": "https://img.raydium.io/icon/6XWfkyg5mzGtKNftSDgYjyoPyUsLRf2rafj95XSFSFrr.png" - }, - { - "symbol": "DINO", - "name": "DINO", - "mint": "6Y7LbYB3tfGBG6CSkyssoxdtHb77AEMTRVXe8JUJRwZ7", - "decimals": 6, - "extensions": { "coingeckoId": "dino" }, - "icon": "https://img.raydium.io/icon/6Y7LbYB3tfGBG6CSkyssoxdtHb77AEMTRVXe8JUJRwZ7.png" - }, - { - "symbol": "MEKKA", - "name": "MEKKA", - "mint": "6YAXGyWb3hhLVQQ3vqg9ZYewXk4Cknnr1raTfDwbf8XG", - "decimals": 9, - "extensions": { "coingeckoId": "mekkafroggo" }, - "icon": "https://img.raydium.io/icon/6YAXGyWb3hhLVQQ3vqg9ZYewXk4Cknnr1raTfDwbf8XG.png" - }, - { - "symbol": "QUEST", - "name": "QUEST", - "mint": "6ybxMQpMgQhtsTLhvHZqk8uqao7kvoexY6e8JmCTqAB1", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6ybxMQpMgQhtsTLhvHZqk8uqao7kvoexY6e8JmCTqAB1.png" - }, - { - "symbol": "Eros", - "name": "Eros Project", - "mint": "6YeTi7npbcyMZRqjVwY7zxW53iE39rMAzLErn3mTftAc", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "BIG", - "name": "UNKWN", - "mint": "6z1oue9xiJCHcDqsyeTZ3NHFVzqMHQSoZmTvVamdW2MZ", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6z1oue9xiJCHcDqsyeTZ3NHFVzqMHQSoZmTvVamdW2MZ.png" - }, - { - "symbol": "FLOKIS", - "name": "Floki Shiba Solana", - "mint": "6zQwyDe541Ys4Q85vkhvHMMRW7ypA4PyHCSF1doWZ4tw", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/6zQwyDe541Ys4Q85vkhvHMMRW7ypA4PyHCSF1doWZ4tw.png" - }, - { - "symbol": "HIMA", - "name": "Himalayan Cat Coin", - "mint": "72hgmvS5zFxaFJfMizq6Gp4gjBqXjTPyX9GDP38krorQ", - "decimals": 9, - "extensions": { "coingeckoId": "himalayan-cat-coin" }, - "icon": "https://img.raydium.io/icon/72hgmvS5zFxaFJfMizq6Gp4gjBqXjTPyX9GDP38krorQ.png" - }, - { - "symbol": "QTX", - "name": "Quantex Coin (Wormhole)", - "mint": "73rd6Ekp1bTYzV3oBAUeL4vMDAnHTdiXhCS5pbnh9quj", - "decimals": 8, - "extensions": {}, - "icon": "https://img.raydium.io/icon/73rd6Ekp1bTYzV3oBAUeL4vMDAnHTdiXhCS5pbnh9quj.png" - }, - { - "symbol": "GNAR", - "name": "GNAR", - "mint": "74YedyBSKbjYzWMhwuBQz3mwsN6vuSSdAfzX9WLZQUtq", - "decimals": 2, - "extensions": { "coingeckoId": "gnar-token" }, - "icon": "https://img.raydium.io/icon/74YedyBSKbjYzWMhwuBQz3mwsN6vuSSdAfzX9WLZQUtq.png" - }, - { - "symbol": "ISL", - "name": "The Islanders", - "mint": "75XracgnqjPeuexHKWQU3bBcXMZG6XLDF867tKB1T9e6", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/75XracgnqjPeuexHKWQU3bBcXMZG6XLDF867tKB1T9e6.png" - }, - { - "symbol": "$wheat", - "name": "BCBY wheat", - "mint": "765R1rpPGVZKKJZPevTp5b2dTAHJZNX4feTiHDEqj7JV", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/765R1rpPGVZKKJZPevTp5b2dTAHJZNX4feTiHDEqj7JV.png" - }, - { - "symbol": "BASIC", - "name": "Basic Tokens", - "mint": "76DThuyLHagfkm2ssYw6Lv7k3MYHx6tXcwPBLU9tXm4D", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/76DThuyLHagfkm2ssYw6Lv7k3MYHx6tXcwPBLU9tXm4D.png" - }, - { - "symbol": "QF", - "name": "QuietFire", - "mint": "76ijxiMkj4DX8q9QMtqpzTxFnT4KPmWv47sZf2kKoVwk", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/76ijxiMkj4DX8q9QMtqpzTxFnT4KPmWv47sZf2kKoVwk.png" - }, - { - "symbol": "SCHRY", - "name": "SolChrysalis", - "mint": "77A8ycvZQfwYb3h2Rc4f9masYfug1wKVRRJUPeMA7b6o", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/77A8ycvZQfwYb3h2Rc4f9masYfug1wKVRRJUPeMA7b6o.png" - }, - { - "symbol": "SLNT", - "name": "SLNT", - "mint": "78ZnfsncDVyhE2HVPe5LscUrgKsJpwP3wJDHRF2TuC1v", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/78ZnfsncDVyhE2HVPe5LscUrgKsJpwP3wJDHRF2TuC1v.png" - }, - { - "symbol": "LUNY", - "name": "Luna Yield", - "mint": "7a4cXVvVT7kF6hS5q5LDqtzWfHfys4a9PoK6pf87RKwf", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7a4cXVvVT7kF6hS5q5LDqtzWfHfys4a9PoK6pf87RKwf.png" - }, - { - "symbol": "FLB", - "name": "Floki Baby", - "mint": "7AAtpqK78qbc7vx6BVWQ1D4PEjoccDbU293oGh74ovzN", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7AAtpqK78qbc7vx6BVWQ1D4PEjoccDbU293oGh74ovzN.png" - }, - { - "symbol": "TRAC", - "name": "Terea Coin", - "mint": "7Af1biRuBcAQTEU3YkWaGGtQDFoxYmqLMyrBNQKnuogn", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "rLLAMA", - "name": "Random Sollamas", - "mint": "7BzULwTHqMCc9Qo7qVFn27UxHgb9SPev3EsbbmQ4YNzw", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7BzULwTHqMCc9Qo7qVFn27UxHgb9SPev3EsbbmQ4YNzw.png" - }, - { - "symbol": "WSL", - "name": "webeSail", - "mint": "7CUJNc1jHfT9J391frL6CiLhwJUiFBs5SErhdBJ3KAQQ", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7CUJNc1jHfT9J391frL6CiLhwJUiFBs5SErhdBJ3KAQQ.png" - }, - { - "symbol": "SHBL", - "name": "Shoebill Coin", - "mint": "7fCzz6ZDHm4UWC9Se1RPLmiyeuQ6kStxpcAP696EuE1E", - "decimals": 9, - "extensions": { "coingeckoId": "shoebill-coin" }, - "icon": "https://img.raydium.io/icon/7fCzz6ZDHm4UWC9Se1RPLmiyeuQ6kStxpcAP696EuE1E.png" - }, - { - "symbol": "TOCO", - "name": "TownCoin", - "mint": "7FntsntzGjK9PzPBbHLDJAFcKQVU14d2SbQZhgMUf2KA", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7FntsntzGjK9PzPBbHLDJAFcKQVU14d2SbQZhgMUf2KA.png" - }, - { - "symbol": "SKUL", - "name": "SKUL", - "mint": "7FvaS3FZ3RThvFeZspkzszF9hj5Zp6SMrxjkoz74NfX", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "Miku", - "name": "Mikuko Token", - "mint": "7GNyprqrpvJHNwzWSj4KVkqw9cKyV5aR3ehM2HeE5pw", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7GNyprqrpvJHNwzWSj4KVkqw9cKyV5aR3ehM2HeE5pw.png" - }, - { - "symbol": "DOM", - "name": "Dominus", - "mint": "7H4Co5vUfRGuYCHFitwCr2iCvKpv7QiRA8hFfwa1y4x3", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7H4Co5vUfRGuYCHFitwCr2iCvKpv7QiRA8hFfwa1y4x3.png" - }, - { - "symbol": "Synapses", - "name": "Synapses", - "mint": "7HGJwFyKC5wPLZ9ctgVSgjBARJ4dZrGCjMRQmzWwe277", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7HGJwFyKC5wPLZ9ctgVSgjBARJ4dZrGCjMRQmzWwe277.png" - }, - { - "symbol": "GMT", - "name": "GMT", - "mint": "7i5KKsX2weiTkry7jA4ZwSuXGhs5eJBEjY8vVxR4pfRx", - "decimals": 9, - "extensions": { "coingeckoId": "stepn" }, - "icon": "https://img.raydium.io/icon/7i5KKsX2weiTkry7jA4ZwSuXGhs5eJBEjY8vVxR4pfRx.png" - }, - { - "symbol": "SOLR", - "name": "SolRazr", - "mint": "7j7H7sgsnNDeCngAPjpaCN4aaaru4HS7NAFYSEUyzJ3k", - "decimals": 6, - "extensions": { "coingeckoId": "solrazr" }, - "icon": "https://img.raydium.io/icon/7j7H7sgsnNDeCngAPjpaCN4aaaru4HS7NAFYSEUyzJ3k.png" - }, - { - "symbol": "Orbs", - "name": "Orbs", - "mint": "7JnHPPJBBKSTJ7iEmsiGSBcPJgbcKw28uCRXtQgimncp", - "decimals": 8, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7JnHPPJBBKSTJ7iEmsiGSBcPJgbcKw28uCRXtQgimncp.png" - }, - { - "symbol": "WEED", - "name": "Solana Weed", - "mint": "7JYZmXjHenJxgLUtBxgYsFfoABmWQFA1fW3tHQKUBThV", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7JYZmXjHenJxgLUtBxgYsFfoABmWQFA1fW3tHQKUBThV.png" - }, - { - "symbol": "4x4NFC", - "name": "RANGER", - "mint": "7k5WRFxyHveTDVJiNj69r8pboregzRSTdoRvmBaETe3w", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7k5WRFxyHveTDVJiNj69r8pboregzRSTdoRvmBaETe3w.png" - }, - { - "symbol": "rSAMO", - "name": "Random Samo", - "mint": "7Mfsbr8vS2LjWTFspTgfLPWm7s77zvJsevBuW4P9MZ3m", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7Mfsbr8vS2LjWTFspTgfLPWm7s77zvJsevBuW4P9MZ3m.png" - }, - { - "symbol": "GKC", - "name": "Ghost Coin", - "mint": "7MirouXpJ1J9wYT3jB9xSp8GKwjx9fJ2hHut5HxWxdLa", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7MirouXpJ1J9wYT3jB9xSp8GKwjx9fJ2hHut5HxWxdLa.png" - }, - { - "symbol": "ZORG", - "name": "Zorg app", - "mint": "7MKpy8PeNjQM3i4xWzGiZjDd97mq6m4QH6Q8jrXnsQ9L", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7MKpy8PeNjQM3i4xWzGiZjDd97mq6m4QH6Q8jrXnsQ9L.png" - }, - { - "symbol": "SBreakpoint", - "name": "Solana Breakpoint", - "mint": "7mNihWEjzWv9yCZc8capE4mS8v5Xvp5YH2yQhtZrQV5B", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "THUG", - "name": "Fraktionalized THUG 2856", - "mint": "7osS84AkAG2TCrUvrE1wfKwfAqWTCrHnaCsrsyVJd5pY", - "decimals": 3, - "extensions": { "coingeckoId": "fraktionalized-thug-2856" }, - "icon": "https://img.raydium.io/icon/7osS84AkAG2TCrUvrE1wfKwfAqWTCrHnaCsrsyVJd5pY.png" - }, - { - "symbol": "LEONIDAS", - "name": "Leonidas Token", - "mint": "7puG5H5Mc6QpvaXjAVLr6GnL5hhUMnpLcUm8G3mEsgHQ", - "decimals": 9, - "extensions": { "coingeckoId": "leonidas-token" }, - "icon": "https://img.raydium.io/icon/7puG5H5Mc6QpvaXjAVLr6GnL5hhUMnpLcUm8G3mEsgHQ.png" - }, - { - "symbol": "SOLV", - "name": "SOLVIEW", - "mint": "7q3AdgKuMeDRnjaMQs7ppXjaw4HUxjsdyMrrfiSZraiN", - "decimals": 6, - "extensions": { "coingeckoId": "solview" }, - "icon": "https://img.raydium.io/icon/7q3AdgKuMeDRnjaMQs7ppXjaw4HUxjsdyMrrfiSZraiN.png" - }, - { - "symbol": "DLITE", - "name": "Dino Lite", - "mint": "7Q9YbR4jPPaDsWsEngubW2z9PGfmWK7xn7AeewMm3qbT", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7Q9YbR4jPPaDsWsEngubW2z9PGfmWK7xn7AeewMm3qbT.png" - }, - { - "symbol": "WET", - "name": "Weble Ecosystem Token", - "mint": "7R7rZ7SsLDXkYAfJyRCBScLuZwizeMWaTWrwFhSZU2Jq", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7R7rZ7SsLDXkYAfJyRCBScLuZwizeMWaTWrwFhSZU2Jq.png" - }, - { - "symbol": "MARIO", - "name": "Super Mario", - "mint": "7rmV64vLfbrbS5rTFvojYWzCVEn8dnJ9RfSRx3nD6C5E", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7rmV64vLfbrbS5rTFvojYWzCVEn8dnJ9RfSRx3nD6C5E.png" - }, - { - "symbol": "WIZE", - "name": "Project Wisdom", - "mint": "7rrJLRar2WjZwRoF3iJKHKnA7d7d9YJT1X9HAJnwUH3Z", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7rrJLRar2WjZwRoF3iJKHKnA7d7d9YJT1X9HAJnwUH3Z.png" - }, - { - "symbol": "PTOC", - "name": "Pluto Coin", - "mint": "7rYHNNU1Quk56mzxXxGiaTWV6Hb1Dh1QNUyShVEdi2Qp", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "GEAR", - "name": "Gear Token", - "mint": "7s6NLX42eURZfpyuKkVLrr9ED9hJE8718cyXFsYKqq5g", - "decimals": 9, - "extensions": { "coingeckoId": "gear" }, - "icon": "https://img.raydium.io/icon/7s6NLX42eURZfpyuKkVLrr9ED9hJE8718cyXFsYKqq5g.png" - }, - { - "symbol": "GALAXY", - "name": "Galaxy", - "mint": "7s7PKr3qhuvZjngR1Zmsy53tFLLhZA4aoMnzeE8Z2H5Z", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7s7PKr3qhuvZjngR1Zmsy53tFLLhZA4aoMnzeE8Z2H5Z.png" - }, - { - "symbol": "$ALL", - "name": "ALL", - "mint": "7ScYHk4VDgSRnQngAUtQk4Eyf7fGat8P4wXq6e2dkzLj", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7ScYHk4VDgSRnQngAUtQk4Eyf7fGat8P4wXq6e2dkzLj.png" - }, - { - "symbol": "RING", - "name": "RING", - "mint": "7SEsxCsiNiYqCpYG16wx4c9u2YGLZphnEFTAU9ENAizD", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7SEsxCsiNiYqCpYG16wx4c9u2YGLZphnEFTAU9ENAizD.png" - }, - { - "symbol": "EDO", - "name": "EDO", - "mint": "7sWMHQaJJPn1rkeizq41iPiW5gG7Ry7PXYAVHaUwY4qu", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7sWMHQaJJPn1rkeizq41iPiW5gG7Ry7PXYAVHaUwY4qu.png" - }, - { - "symbol": "SDO", - "name": "TheSolanDAO", - "mint": "7SZUnH7H9KptyJkUhJ5L4Kee5fFAbqVgCHvt7B6wg4Xc", - "decimals": 5, - "extensions": { "coingeckoId": "thesolandao" }, - "icon": "https://img.raydium.io/icon/7SZUnH7H9KptyJkUhJ5L4Kee5fFAbqVgCHvt7B6wg4Xc.png" - }, - { - "symbol": "FLW", - "name": "Flow Coin", - "mint": "7tE99RKS4RwQxEjvZfh4CQMoQMMTRdL5KQbugsfhNYPg", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7tE99RKS4RwQxEjvZfh4CQMoQMMTRdL5KQbugsfhNYPg.png" - }, - { - "symbol": "GV", - "name": "Good Vibes", - "mint": "7TQTpG1qBvE9ui7J9yQWKFAYpQahkaKPKqGTsqSm1wUv", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7TQTpG1qBvE9ui7J9yQWKFAYpQahkaKPKqGTsqSm1wUv.png" - }, - { - "symbol": "MOON", - "name": "MoonSol", - "mint": "7TXxsfjYt8gR1XZh9vZZNRxhA4t2VxtYbsy9JWHRjFhJ", - "decimals": 4, - "extensions": {}, - "icon": "" - }, - { - "symbol": "COBAN", - "name": "COBAN", - "mint": "7udMmYXh6cuWVY6qQVCd9b429wDVn2J71r5BdxHkQADY", - "decimals": 3, - "extensions": { "coingeckoId": "coban" }, - "icon": "https://img.raydium.io/icon/7udMmYXh6cuWVY6qQVCd9b429wDVn2J71r5BdxHkQADY.png" - }, - { - "symbol": "rATRNT", - "name": "Random Aiternate", - "mint": "7uENff26kbM3zP9YhYj4MdSzS5nGoEDSeHs81zQ7Gp2J", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7uENff26kbM3zP9YhYj4MdSzS5nGoEDSeHs81zQ7Gp2J.png" - }, - { - "symbol": "KSD", - "name": "Kyoudai Synthetic Drug", - "mint": "7UUWK4HFvkFvhd6U4DxCBi1yY7XWhQguabXK1MxtANKW", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7UUWK4HFvkFvhd6U4DxCBi1yY7XWhQguabXK1MxtANKW.png" - }, - { - "symbol": "BOLE", - "name": "Bole Token", - "mint": "7uv3ZvZcQLd95bUp5WMioxG7tyAZVXFfr8JYkwhMYrnt", - "decimals": 4, - "extensions": { "coingeckoId": "bole-token" }, - "icon": "https://img.raydium.io/icon/7uv3ZvZcQLd95bUp5WMioxG7tyAZVXFfr8JYkwhMYrnt.png" - }, - { - "symbol": "ALBY", - "name": "Alby Coin", - "mint": "7UvcxpsYpDov3Q9GJU3HiHUVnVCEnY96XPAkD1LTDcLe", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7UvcxpsYpDov3Q9GJU3HiHUVnVCEnY96XPAkD1LTDcLe.png" - }, - { - "symbol": "rFRAKT", - "name": "Random FRAKTs", - "mint": "7V5AaqHTwiySegaAmNPLekQfTAoK4WvEVgfi2R8V44tB", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7V5AaqHTwiySegaAmNPLekQfTAoK4WvEVgfi2R8V44tB.png" - }, - { - "symbol": "DOGExTESLA", - "name": "DogeTesla", - "mint": "7v5K9VFiqNTWnmkK4wofVfRzG7f7AGQ7WLXLmP91UibU", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7v5K9VFiqNTWnmkK4wofVfRzG7f7AGQ7WLXLmP91UibU.png" - }, - { - "symbol": "BBSAMO", - "name": "BabySamoio", - "mint": "7ViSurf5Ve2a8qDWFYsfU8GFmRttQvS5paJ8L94QZgo7", - "decimals": 1, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7ViSurf5Ve2a8qDWFYsfU8GFmRttQvS5paJ8L94QZgo7.png" - }, - { - "symbol": "PAC", - "name": "PAC Coin", - "mint": "7vKX5rx57VPE1ozJesFzojdPjGZ3M89894PT27i6seUF", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7vKX5rx57VPE1ozJesFzojdPjGZ3M89894PT27i6seUF.png" - }, - { - "symbol": "FREN", - "name": "SOL Frens", - "mint": "7xd71KP4HwQ4sM936xL8JQZCwE4amUko1AdCCf6Znjrt", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7xd71KP4HwQ4sM936xL8JQZCwE4amUko1AdCCf6Znjrt.png" - }, - { - "symbol": "ASDEX", - "name": "AstraDEX", - "mint": "7xfKgh8vtX2RrZn21wFTQSP9jsjh7Fqo8P4igYfmxxD3", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7xfKgh8vtX2RrZn21wFTQSP9jsjh7Fqo8P4igYfmxxD3.png" - }, - { - "symbol": "KERMIT", - "name": "Kermit", - "mint": "7xzovRepzLvXbbpVZLYKzEBhCNgStEv1xpDqf1rMFFKX", - "decimals": 8, - "extensions": { "coingeckoId": "kermit" }, - "icon": "https://img.raydium.io/icon/7xzovRepzLvXbbpVZLYKzEBhCNgStEv1xpDqf1rMFFKX.png" - }, - { - "symbol": "BANANA", - "name": "Banana Bucks", - "mint": "7YhfUG27m7ceDCBnB48dGy4mAJab2hqi6YKkp9Ho7ybv", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7YhfUG27m7ceDCBnB48dGy4mAJab2hqi6YKkp9Ho7ybv.png" - }, - { - "symbol": "LFGO", - "name": "MEKKA FROGGO TOKEN", - "mint": "7z1eQmEhhM9e1AVCBQc6BzMZWmCZRqHCLJtkDgHxzYnQ", - "decimals": 9, - "extensions": { "coingeckoId": "mekka-froggo" }, - "icon": "https://img.raydium.io/icon/7z1eQmEhhM9e1AVCBQc6BzMZWmCZRqHCLJtkDgHxzYnQ.png" - }, - { - "symbol": "NOM", - "name": "NOM", - "mint": "7zhbkbKpGaUsJW7AD4yyAfGGoy53Xx2H3Ai5BKcwGKHw", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7zhbkbKpGaUsJW7AD4yyAfGGoy53Xx2H3Ai5BKcwGKHw.png" - }, - { - "symbol": "soARDX", - "name": "Wrapped ArdCoin (Sollet)", - "mint": "7zsKqN7Fg2s9VsqAq6XBoiShCVohpGshSUvoWBc6jKYh", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/7zsKqN7Fg2s9VsqAq6XBoiShCVohpGshSUvoWBc6jKYh.png" - }, - { - "symbol": "SORTED", - "name": "Sorted", - "mint": "82xYSLKQ5xBca6rkQSG3Vjt7T6bGhbiwkUeYwk6NSt4", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/82xYSLKQ5xBca6rkQSG3Vjt7T6bGhbiwkUeYwk6NSt4.png" - }, - { - "symbol": "soUBXT", - "name": "Wrapped Upbots (Sollet)", - "mint": "873KLxCbz7s9Kc4ZzgYRtNmhfkQrhfyWGZJBmyCbC3ei", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/873KLxCbz7s9Kc4ZzgYRtNmhfkQrhfyWGZJBmyCbC3ei.png" - }, - { - "symbol": "ENX", - "name": "Equinox", - "mint": "87rSGrpYdmTxfNBf8o2cpyiNcxCmNhUPBXjT8aoyfob5", - "decimals": 9, - "extensions": { "coingeckoId": "equinox" }, - "icon": "https://img.raydium.io/icon/87rSGrpYdmTxfNBf8o2cpyiNcxCmNhUPBXjT8aoyfob5.png" - }, - { - "symbol": "GRLC", - "name": "Garlic", - "mint": "88YqDBWxYhhwPbExF966EdaCYBKP51xVm1oGBcbWzcf2", - "decimals": 9, - "extensions": { "coingeckoId": "garlic" }, - "icon": "https://img.raydium.io/icon/88YqDBWxYhhwPbExF966EdaCYBKP51xVm1oGBcbWzcf2.png" - }, - { - "symbol": "SAKC", - "name": "Sakura Collective", - "mint": "8AN7mWuw6M81w3gDcxvvQR2Kr5RGKJjzh7ZKAPPmrcJG", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8AN7mWuw6M81w3gDcxvvQR2Kr5RGKJjzh7ZKAPPmrcJG.png" - }, - { - "symbol": "HOL", - "name": "HOLONA", - "mint": "8Ap9nTGPGJ1VYbMCE64f7yUTCptKk717Cns1ZfrqvdjE", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8Ap9nTGPGJ1VYbMCE64f7yUTCptKk717Cns1ZfrqvdjE.png" - }, - { - "symbol": "ThugShiba", - "name": "Thug Shiba", - "mint": "8Au2WcQrgn1oTKfnnaFfb3iMjfdXYp7Y7CrHi8JaNSUZ", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8Au2WcQrgn1oTKfnnaFfb3iMjfdXYp7Y7CrHi8JaNSUZ.png" - }, - { - "symbol": "ACA", - "name": "Acacia", - "mint": "8BLiujyxu5gJajWBXoZQkwSsamdeHNKWQbu1ApAao8Ps", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8BLiujyxu5gJajWBXoZQkwSsamdeHNKWQbu1ApAao8Ps.png" - }, - { - "symbol": "rNBC", - "name": "Random Bat City Underground", - "mint": "8BobtXuP8hD69rZTLZiubSEbmQWpbmaJwyoayzQYyxs3", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8BobtXuP8hD69rZTLZiubSEbmQWpbmaJwyoayzQYyxs3.png" - }, - { - "symbol": "LITJESUS", - "name": "Lit Jesus Floor Index", - "mint": "8CmKs6xeWyrgTwBQPUtq7HdbEHvkV9F3NARx2GMX9wFZ", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8CmKs6xeWyrgTwBQPUtq7HdbEHvkV9F3NARx2GMX9wFZ.png" - }, - { - "symbol": "JCATS", - "name": "Jungle Cats Floor Index", - "mint": "8e2G3tCTvKAosq4BnYbDczboRVhy7xaXwbTSJeXEefJX", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8e2G3tCTvKAosq4BnYbDczboRVhy7xaXwbTSJeXEefJX.png" - }, - { - "symbol": "APPLE", - "name": "Apple Fruit", - "mint": "8E5W9PMhnEvdvM2Q9XBLMJW7UsFiieXnRHPj8zhtB23h", - "decimals": 9, - "extensions": { "coingeckoId": "apple-fruit" }, - "icon": "https://img.raydium.io/icon/8E5W9PMhnEvdvM2Q9XBLMJW7UsFiieXnRHPj8zhtB23h.png" - }, - { - "symbol": "sSOL", - "name": "SunnySideUp staked SOL (sSOL)", - "mint": "8EDaoeBqpcVACwvkYXh1vAcU29HiBiNhqoF4pRsuUsZS", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8EDaoeBqpcVACwvkYXh1vAcU29HiBiNhqoF4pRsuUsZS.png" - }, - { - "symbol": "DLN", - "name": "Goekdln", - "mint": "8fd5eUPMNHuyKRshFbfmKRAm2gowJ75m8WjT7tLio6J3", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8fd5eUPMNHuyKRshFbfmKRAm2gowJ75m8WjT7tLio6J3.png" - }, - { - "symbol": "CACTI", - "name": "CACTI", - "mint": "8G1SG7q8VyqCrjH7VjG9fouDDmHYJaYBMzBomdcUZ1qX", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8G1SG7q8VyqCrjH7VjG9fouDDmHYJaYBMzBomdcUZ1qX.png" - }, - { - "symbol": "PORN", - "name": "Pornlana", - "mint": "8gWEnKqB4qVQgC8yAorMxhiEKqsDcxZSVKFVbQ8g1fzB", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8gWEnKqB4qVQgC8yAorMxhiEKqsDcxZSVKFVbQ8g1fzB.png" - }, - { - "symbol": "OWSOM", - "name": "Owsom Token", - "mint": "8H4eH19o9yYWCGFQLe37fQhn9Jkb5TUVw8bwW9cmHNfu", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8H4eH19o9yYWCGFQLe37fQhn9Jkb5TUVw8bwW9cmHNfu.png" - }, - { - "symbol": "DGNA", - "name": "DegenAlley", - "mint": "8iSagwHZNj4Hx4CMeoZwLLMVbWt4mUT6qk42TxiHkRtn", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8iSagwHZNj4Hx4CMeoZwLLMVbWt4mUT6qk42TxiHkRtn.png" - }, - { - "symbol": "SHARDS", - "name": "SolChicks Shards", - "mint": "8j3hXRK5rdoZ2vSpGLRmXtWmW6iYaRUw5xVk4Kzmc9Hp", - "decimals": 9, - "extensions": { "coingeckoId": "solchicks-shards" }, - "icon": "https://img.raydium.io/icon/8j3hXRK5rdoZ2vSpGLRmXtWmW6iYaRUw5xVk4Kzmc9Hp.png" - }, - { - "symbol": "DINO", - "name": "Dino Coin", - "mint": "8J7yrjW4JsZYiLUMWxyHu5V1bStvFQ7yD3jHrkTk88wk", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8J7yrjW4JsZYiLUMWxyHu5V1bStvFQ7yD3jHrkTk88wk.png" - }, - { - "symbol": "MDOA", - "name": "MDOA", - "mint": "8Jdjg3xVNAAFdiDbFpWF2FX5dYwHyw5j3Myvgmzrf7z4", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8Jdjg3xVNAAFdiDbFpWF2FX5dYwHyw5j3Myvgmzrf7z4.png" - }, - { - "symbol": "BABYTIGER", - "name": "Baby Tiger", - "mint": "8JjBJdV73zPPmZvkgC91ni8RsbXWTkhpuSdxeZgaw6hD", - "decimals": 9, - "extensions": { "coingeckoId": "babytigergold" }, - "icon": "https://img.raydium.io/icon/8JjBJdV73zPPmZvkgC91ni8RsbXWTkhpuSdxeZgaw6hD.png" - }, - { - "symbol": "SOLI", - "name": "Solana Ecosystem Index", - "mint": "8JnNWJ46yfdq8sKgT1Lk4G7VWkAA8Rhh7LhqgJ6WY41G", - "decimals": 6, - "extensions": { "coingeckoId": "solana-ecosystem-index" }, - "icon": "https://img.raydium.io/icon/8JnNWJ46yfdq8sKgT1Lk4G7VWkAA8Rhh7LhqgJ6WY41G.png" - }, - { - "symbol": "DTC", - "name": "Dintcoin", - "mint": "8KzT4VfvzULfbyAE8PS7qzD3zNv6v2Bb4sKMx2v4Qu8e", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8KzT4VfvzULfbyAE8PS7qzD3zNv6v2Bb4sKMx2v4Qu8e.png" - }, - { - "symbol": "DXB", - "name": "DefiXBet Token", - "mint": "8mgeCL7k2cB2KTN8NhD5biqvcbkfrmBogDpYoHmn5cKQ", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8mgeCL7k2cB2KTN8NhD5biqvcbkfrmBogDpYoHmn5cKQ.png" - }, - { - "symbol": "JOKE", - "name": "JOKESMEMES", - "mint": "8NGgmXzBzhsXz46pTC3ioSBxeE3w2EXpc741N3EQ8E6r", - "decimals": 9, - "extensions": { "coingeckoId": "jokes-meme" }, - "icon": "https://img.raydium.io/icon/8NGgmXzBzhsXz46pTC3ioSBxeE3w2EXpc741N3EQ8E6r.png" - }, - { - "symbol": "VIBE", - "name": "VIBE", - "mint": "8o66EVAf4u2Hr21m2tuRrPtEXFPLr8G8aL1ETStP8fDu", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8o66EVAf4u2Hr21m2tuRrPtEXFPLr8G8aL1ETStP8fDu.png" - }, - { - "symbol": "OASIS", - "name": "Oasis", - "mint": "8oiPhiFrmXS93iC98M4ATev8emQ6XGtf8pz8sntbbqGt", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8oiPhiFrmXS93iC98M4ATev8emQ6XGtf8pz8sntbbqGt.png" - }, - { - "symbol": "WSGS", - "name": "GameStonk", - "mint": "8Qc1ZtQeR46aq6CEcf16XngA4dASqNHMrejfkmZPXy9z", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8Qc1ZtQeR46aq6CEcf16XngA4dASqNHMrejfkmZPXy9z.png" - }, - { - "symbol": "FAITH", - "name": "Faith", - "mint": "8RSyhCxFKYVnr6PGTgKC9o86AjbQjdmLRZjYJjhdTdYH", - "decimals": 3, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8RSyhCxFKYVnr6PGTgKC9o86AjbQjdmLRZjYJjhdTdYH.png" - }, - { - "symbol": "YARD", - "name": "SolYard Finance", - "mint": "8RYSc3rrS4X4bvBCtSJnhcpPpMaAJkXnVKZPzANxQHgz", - "decimals": 9, - "extensions": { "coingeckoId": "solyard-finance" }, - "icon": "https://img.raydium.io/icon/8RYSc3rrS4X4bvBCtSJnhcpPpMaAJkXnVKZPzANxQHgz.png" - }, - { - "symbol": "CKC", - "name": "ChikinCoin", - "mint": "8s9FCz99Wcr3dHpiauFRi6bLXzshXfcGTfgQE7UEopVx", - "decimals": 6, - "extensions": { "coingeckoId": "chikincoin" }, - "icon": "https://img.raydium.io/icon/8s9FCz99Wcr3dHpiauFRi6bLXzshXfcGTfgQE7UEopVx.png" - }, - { - "symbol": "TREE", - "name": "Tree Token", - "mint": "8Sc16a55YzSKpPTUN4VJEfcKU5aXSk22WyCEsr1MfdCf", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8Sc16a55YzSKpPTUN4VJEfcKU5aXSk22WyCEsr1MfdCf.png" - }, - { - "symbol": "DGMOON", - "name": "DogeMoonxSOL", - "mint": "8sMa1Jfcpt2eSkKDtcd6rurX27gqxkrEvXn5jHt3suGB", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8sMa1Jfcpt2eSkKDtcd6rurX27gqxkrEvXn5jHt3suGB.png" - }, - { - "symbol": "MSARI", - "name": "Msarii Coin", - "mint": "8StwRjjYtPQMXYDSEM4amjNfYaxXjUKfHBLUxWBgyypX", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8StwRjjYtPQMXYDSEM4amjNfYaxXjUKfHBLUxWBgyypX.png" - }, - { - "symbol": "PIPANA", - "name": "Pipana", - "mint": "8tbAqS4dFNEeC6YGWpNnusc3JcxoFLMiiLPyHctgGYFe", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8tbAqS4dFNEeC6YGWpNnusc3JcxoFLMiiLPyHctgGYFe.png" - }, - { - "symbol": "NARWHAL", - "name": "Narwhal Coin", - "mint": "8TjgDMv2Esb7YRKu1ESZv5vtgD1WqFKmzhPBgsLqwEGG", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8TjgDMv2Esb7YRKu1ESZv5vtgD1WqFKmzhPBgsLqwEGG.png" - }, - { - "symbol": "SFI", - "name": "SolanaFi", - "mint": "8udZmv2RrHpU8rPZhphUGhHpmyAqc9UzV4UihpThKvYh", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8udZmv2RrHpU8rPZhphUGhHpmyAqc9UzV4UihpThKvYh.png" - }, - { - "symbol": "SIMS", - "name": "Simians Token", - "mint": "8vFjsxK4SHg2XVSB6ofqNNvkFF62fx5Uq588a7f8qrjk", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8vFjsxK4SHg2XVSB6ofqNNvkFF62fx5Uq588a7f8qrjk.png" - }, - { - "symbol": "EWS", - "name": "Enterprise Web Service", - "mint": "8WDJHzLR94ZCiJdkeGHMUY3TdWuryWgTGgWM9XRCbUG4", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8WDJHzLR94ZCiJdkeGHMUY3TdWuryWgTGgWM9XRCbUG4.png" - }, - { - "symbol": "42", - "name": "42", - "mint": "8Wmonq7dhFJXuHqFCcVgWTmmUPCBC4C6J5xbB5HhGb6n", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8Wmonq7dhFJXuHqFCcVgWTmmUPCBC4C6J5xbB5HhGb6n.png" - }, - { - "symbol": "DGENMF", - "name": "Degen MFer Floor Index", - "mint": "8WTN3gDKgk2xfYoBZFjyBhek9DaMkqVMeSU8EcfUhHNU", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8WTN3gDKgk2xfYoBZFjyBhek9DaMkqVMeSU8EcfUhHNU.png" - }, - { - "symbol": "renLUNA", - "name": "renLUNA", - "mint": "8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE.png" - }, - { - "symbol": "BIOB", - "name": "Bionic Beaver", - "mint": "8x4nE4MNzw3zhpiAB4MBWhXz4iGxNt9Q6Mm3dTdPSRyC", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "CNDR", - "name": "CondorCoin", - "mint": "8XkS7ZDPR9zXcNcYR884tBScnQRyFcWRb7WcLtCR6zEZ", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8XkS7ZDPR9zXcNcYR884tBScnQRyFcWRb7WcLtCR6zEZ.png" - }, - { - "symbol": "RUGZ", - "name": "RUGZ", - "mint": "8XUTstViEpLfhxaA88A6oWKraHm8V444bnSq6hm79vYh", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8XUTstViEpLfhxaA88A6oWKraHm8V444bnSq6hm79vYh.png" - }, - { - "symbol": "MANIAK", - "name": "Maniak NFT", - "mint": "8yiekaUUidqA8bQ5QuWGNgrSDCnZVf5te6ZykGeY8roa", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "SDOGE", - "name": "SolDoge", - "mint": "8ymi88q5DtmdNTn2sPRNFkvMkszMHuLJ1e3RVdWjPa3s", - "decimals": 0, - "extensions": { "coingeckoId": "soldoge" }, - "icon": "https://img.raydium.io/icon/8ymi88q5DtmdNTn2sPRNFkvMkszMHuLJ1e3RVdWjPa3s.png" - }, - { - "symbol": "MRX", - "name": "Maars", - "mint": "8yQuj5v4s72UqZi3sYZL5rAD4NPV4ueUwBKzChBDWMVf", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8yQuj5v4s72UqZi3sYZL5rAD4NPV4ueUwBKzChBDWMVf.png" - }, - { - "symbol": "TIGER", - "name": "TIGER COIN", - "mint": "8z4ghJPp3ccvEtuXZbceGRfoX7AZHhcdwiapYzmsxmyC", - "decimals": 9, - "extensions": { "coingeckoId": "tiger-coin" }, - "icon": "https://img.raydium.io/icon/8z4ghJPp3ccvEtuXZbceGRfoX7AZHhcdwiapYzmsxmyC.png" - }, - { - "symbol": "$ROBO", - "name": "ROBO Coin", - "mint": "8ZepSXp47WFyDK21QbvMiiKVWRHnGrAegiwDr71PfGi3", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8ZepSXp47WFyDK21QbvMiiKVWRHnGrAegiwDr71PfGi3.png" - }, - { - "symbol": "NEON", - "name": "NEON EVM", - "mint": "8ZSJTmL42LgTrC1qY7AZQkLYT1EZquQA1cA3ze4bSjvq", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/8ZSJTmL42LgTrC1qY7AZQkLYT1EZquQA1cA3ze4bSjvq.png" - }, - { - "symbol": "NURP", - "name": "NURP Coin", - "mint": "938xXsPKhBAXDLUfWNYuZdsnj57oGF6fCz8P6yLom19f", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/938xXsPKhBAXDLUfWNYuZdsnj57oGF6fCz8P6yLom19f.png" - }, - { - "symbol": "SHIMOO", - "name": "Shibi Samo Official", - "mint": "939KAUTAyNdmpahj1vQmbS67D7auhyJnkMt4sv2tzBwU", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/939KAUTAyNdmpahj1vQmbS67D7auhyJnkMt4sv2tzBwU.png" - }, - { - "symbol": "SKULL", - "name": "Spooky Skeleton Society Utility Token", - "mint": "93iJG6TY2bXb8zUe6gscx3fwvUCZPHVMCrVRg6uFz6ZU", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/93iJG6TY2bXb8zUe6gscx3fwvUCZPHVMCrVRg6uFz6ZU.png" - }, - { - "symbol": "SYXT", - "name": "SolanyxToken", - "mint": "94jMUy411XNUw1CnkFr2514fq6KRc49W3kAmrjJiuZLx", - "decimals": 9, - "extensions": { "coingeckoId": "solanyx" }, - "icon": "https://img.raydium.io/icon/94jMUy411XNUw1CnkFr2514fq6KRc49W3kAmrjJiuZLx.png" - }, - { - "symbol": "LADA", - "name": "LADA Token", - "mint": "95bzgMCtKw2dwaWufV9iZyu64DQo1eqw6QWnFMUSnsuF", - "decimals": 9, - "extensions": { "coingeckoId": "laddercaster" }, - "icon": "https://img.raydium.io/icon/95bzgMCtKw2dwaWufV9iZyu64DQo1eqw6QWnFMUSnsuF.png" - }, - { - "symbol": "SMRT", - "name": "Solminter", - "mint": "95KN8q3qubEVjPf9trgyur2nHx8T5RCmztRbLuQ5E5i", - "decimals": 0, - "extensions": { "coingeckoId": "solminter" }, - "icon": "" - }, - { - "symbol": "FJBT", - "name": "Fuck Joe Biden Token", - "mint": "97ner9bBhnmbg1yZXMh85WNYsYSLTqUb4RvyMttD57fh", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/97ner9bBhnmbg1yZXMh85WNYsYSLTqUb4RvyMttD57fh.png" - }, - { - "symbol": "GCC", - "name": "Gatsby Club Currency", - "mint": "99Q3AfFWX3rdidoQCnAPPoZFjsaXr2AAk65RUgxiwfUi", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/99Q3AfFWX3rdidoQCnAPPoZFjsaXr2AAk65RUgxiwfUi.png" - }, - { - "symbol": "CRB", - "name": "Cerebro", - "mint": "9A6dgXm79ASFyG42tui86F4gQTC56Ydw3mrNL61xhdr", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9A6dgXm79ASFyG42tui86F4gQTC56Ydw3mrNL61xhdr.png" - }, - { - "symbol": "WIPE", - "name": "WipeMyAss", - "mint": "9ae76zqD3cgzR9gvf5Thc2NN3ACF7rqqnrLqxNzgcre6", - "decimals": 9, - "extensions": { "coingeckoId": "wipemyass" }, - "icon": "https://img.raydium.io/icon/9ae76zqD3cgzR9gvf5Thc2NN3ACF7rqqnrLqxNzgcre6.png" - }, - { - "symbol": "DRW", - "name": "Dragon War", - "mint": "9ajPmmLNtwFsHjeU289Y1v9MU6WwoBGVcAnRVyPcj5YY", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9ajPmmLNtwFsHjeU289Y1v9MU6WwoBGVcAnRVyPcj5YY.png" - }, - { - "symbol": "rTRTL", - "name": "Random Turtles", - "mint": "9akvvCgpFc7LkpESHCSacrPPH7SztbvuAXNvJkzZSZWu", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9akvvCgpFc7LkpESHCSacrPPH7SztbvuAXNvJkzZSZWu.png" - }, - { - "symbol": "MEW", - "name": "Solcatcoin", - "mint": "9BiqBycZWkWH21vYqCbu2bL1PjZbR5GxWGA8LQkShbyt", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9BiqBycZWkWH21vYqCbu2bL1PjZbR5GxWGA8LQkShbyt.png" - }, - { - "symbol": "BLUFF", - "name": "Bluffcoin", - "mint": "9CzmA137fzLtdyfaBY63Sa85uY8ZvBiX3MrAJypzsDGR", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9CzmA137fzLtdyfaBY63Sa85uY8ZvBiX3MrAJypzsDGR.png" - }, - { - "symbol": "NinjaDoge", - "name": "NinjaDoge", - "mint": "9dwrdifAVWZsyEPxi15D8LcLsdrvTbpabrGw5EVzc7pp", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9dwrdifAVWZsyEPxi15D8LcLsdrvTbpabrGw5EVzc7pp.png" - }, - { - "symbol": "SHUT", - "name": "Shuttlecoin", - "mint": "9e6nnqbsTjWx3ss6a3x7Q9ZvpupLNYLb8cTbVmm6UD2K", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9e6nnqbsTjWx3ss6a3x7Q9ZvpupLNYLb8cTbVmm6UD2K.png" - }, - { - "symbol": "FLARES", - "name": "Lifinity Flares Floor Index", - "mint": "9EgSSSAkeo8S4PDX6FqQoMLcUxgLfMaJFSDmkV78LErS", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9EgSSSAkeo8S4PDX6FqQoMLcUxgLfMaJFSDmkV78LErS.png" - }, - { - "symbol": "BULLS", - "name": "Bull Solana", - "mint": "9EKEh1CHMKmyvBTY6qYZm7kgRJE18tCbaY1ZbpdELbVr", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9EKEh1CHMKmyvBTY6qYZm7kgRJE18tCbaY1ZbpdELbVr.png" - }, - { - "symbol": "ITSC", - "name": "ITS Cash", - "mint": "9fzQfEM5aq1GLugzHMM6prq8tsURN2pxQMjARaWGd2py", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9fzQfEM5aq1GLugzHMM6prq8tsURN2pxQMjARaWGd2py.png" - }, - { - "symbol": "XAL", - "name": "XAL Coin", - "mint": "9GnYb1ukBUKHobqpmNdzBE7VkYn7wWqianpKaYFPBChk", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9GnYb1ukBUKHobqpmNdzBE7VkYn7wWqianpKaYFPBChk.png" - }, - { - "symbol": "RAYS", - "name": "SUNSHINE", - "mint": "9ihuaebHjvKwpWHXcnQoYjvxA4qHX1fy2SuYyCZ7Rokh", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9ihuaebHjvKwpWHXcnQoYjvxA4qHX1fy2SuYyCZ7Rokh.png" - }, - { - "symbol": "USH", - "name": "Hedge USD", - "mint": "9iLH8T7zoWhY7sBmj1WK9ENbWdS1nL8n9wAxaeRitTa6", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9iLH8T7zoWhY7sBmj1WK9ENbWdS1nL8n9wAxaeRitTa6.png" - }, - { - "symbol": "POT", - "name": "Positron", - "mint": "9iz45n44TQUPyoRymdZXEunqvZUksZyhzS6zQ7sLMadj", - "decimals": 9, - "extensions": { "coingeckoId": "positron-token" }, - "icon": "https://img.raydium.io/icon/9iz45n44TQUPyoRymdZXEunqvZUksZyhzS6zQ7sLMadj.png" - }, - { - "symbol": "DRAKOSE", - "name": "Drakos Unchained Expansion Floor Index", - "mint": "9j7pLeELCPTnXYXcHSiGSuYr1UE7cTaAd16kiH2AiNs5", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9j7pLeELCPTnXYXcHSiGSuYr1UE7cTaAd16kiH2AiNs5.png" - }, - { - "symbol": "JRDN", - "name": "Fraktionalized Triumphant", - "mint": "9jWgVR3Q3QjfmaXNiZ6jht2K43W7sqkn6tZFeoK9B48t", - "decimals": 3, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9jWgVR3Q3QjfmaXNiZ6jht2K43W7sqkn6tZFeoK9B48t.png" - }, - { - "symbol": "UNIVERSE", - "name": "universe", - "mint": "9k27FY1wmxKEyoMGqK4zJMT2Y8dvkiYRGM2ijjLLTrjq", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9k27FY1wmxKEyoMGqK4zJMT2Y8dvkiYRGM2ijjLLTrjq.png" - }, - { - "symbol": "OPPA", - "name": "OPPA", - "mint": "9K4uNquZjVSBBN6fBsp62gtYLropyAxAbdZC7D9XErih", - "decimals": 9, - "extensions": { "coingeckoId": "oppa" }, - "icon": "https://img.raydium.io/icon/9K4uNquZjVSBBN6fBsp62gtYLropyAxAbdZC7D9XErih.png" - }, - { - "symbol": "SGP", - "name": "Stacc Gold Points", - "mint": "9KYMTqKY7f2cJKW2wYfNRpLb9zbB1tTyEbaTuzy4Gwwc", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9KYMTqKY7f2cJKW2wYfNRpLb9zbB1tTyEbaTuzy4Gwwc.png" - }, - { - "symbol": "rLGND", - "name": "Random Blockasset Legends", - "mint": "9m8E1yLHaG1B2TFSNeWahsitQh5yQRnrbyw756HFAcEa", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9m8E1yLHaG1B2TFSNeWahsitQh5yQRnrbyw756HFAcEa.png" - }, - { - "symbol": "$FORCE", - "name": "Force", - "mint": "9MjAmgHXbu5drkNa9XpzfozgsM5Dcq6bSnKZzdNrwscC", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9MjAmgHXbu5drkNa9XpzfozgsM5Dcq6bSnKZzdNrwscC.png" - }, - { - "symbol": "SPACEGOLD", - "name": "SPACEGOLD", - "mint": "9mXZ54YnJJRmUN2MaMEtWCfFyoncP4ZhKz7U9DZ4JY2X", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9mXZ54YnJJRmUN2MaMEtWCfFyoncP4ZhKz7U9DZ4JY2X.png" - }, - { - "symbol": "$FLY", - "name": "FLY", - "mint": "9oCf3dx1PoSP1tnhNS6LBQXzixU1vkzNHvFwY1oFCD8M", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9oCf3dx1PoSP1tnhNS6LBQXzixU1vkzNHvFwY1oFCD8M.png" - }, - { - "symbol": "$TNB", - "name": "TinyBear Token", - "mint": "9pbVhTQbnM8ho5kwqr21EhWVehd1PfBt8tyBxeH2ttmz", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9pbVhTQbnM8ho5kwqr21EhWVehd1PfBt8tyBxeH2ttmz.png" - }, - { - "symbol": "$CULT", - "name": "Culture Coin", - "mint": "9qTA3A113oG94ppSpiJTwWCyj44wyNcgPAs5i9d7QQne", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9qTA3A113oG94ppSpiJTwWCyj44wyNcgPAs5i9d7QQne.png" - }, - { - "symbol": "MOUNT", - "name": "MOUNT", - "mint": "9QXAu7FTf7hmswBQwKxvuqGgWH42FyQjqXJanUt6y4eC", - "decimals": 9, - "extensions": { "coingeckoId": "metamounts" }, - "icon": "https://img.raydium.io/icon/9QXAu7FTf7hmswBQwKxvuqGgWH42FyQjqXJanUt6y4eC.png" - }, - { - "symbol": "KAGD", - "name": "KAGED KOIN", - "mint": "9shzY9jupopFajZbKP1sdhzwVwofZRejQgq7Kvw6jQKY", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9shzY9jupopFajZbKP1sdhzwVwofZRejQgq7Kvw6jQKY.png" - }, - { - "symbol": "GAP", - "name": "Solana Gap", - "mint": "9sQtcMxC7zwoVm9vsbZD6XkbZMik5882sA22oc6kb6bU", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9sQtcMxC7zwoVm9vsbZD6XkbZMik5882sA22oc6kb6bU.png" - }, - { - "symbol": "WEEB", - "name": "Weeb Finance Token", - "mint": "9VgfFUFkGGrRePvpKLPkp9DR3crRepf6CJsYU3UmudtY", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9VgfFUFkGGrRePvpKLPkp9DR3crRepf6CJsYU3UmudtY.png" - }, - { - "symbol": "SHIBMOON", - "name": "Shib Moon", - "mint": "9VH6kTELjTFd1RunKZJsCvtzAVLTTsb44kQzWywixLbX", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9VH6kTELjTFd1RunKZJsCvtzAVLTTsb44kQzWywixLbX.png" - }, - { - "symbol": "SOLUM", - "name": "Solum", - "mint": "9XtRZwKzDXEJ61A7qCqbPz8jXMYHGT3LwxqrEzB6fqxv", - "decimals": 9, - "extensions": { "coingeckoId": "solum" }, - "icon": "https://img.raydium.io/icon/9XtRZwKzDXEJ61A7qCqbPz8jXMYHGT3LwxqrEzB6fqxv.png" - }, - { - "symbol": "SPORE", - "name": "Flower View", - "mint": "9XYbEGVjBK2BWvtvjoJBZtnoHtkkdGiw321tdN6eLa4A", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9XYbEGVjBK2BWvtvjoJBZtnoHtkkdGiw321tdN6eLa4A.png" - }, - { - "symbol": "SVBL", - "name": "Sievable", - "mint": "9XZR8Y5ZbRAvbCMMzeoSPzj8haAaUBaa9XoFBDHJAy2Z", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9XZR8Y5ZbRAvbCMMzeoSPzj8haAaUBaa9XoFBDHJAy2Z.png" - }, - { - "symbol": "RAMENF", - "name": "Ramen Feast Token", - "mint": "9yM42HMJnN69rhMGr8nCYSRtFxjWTWm5Z6GeucyLBEHg", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9yM42HMJnN69rhMGr8nCYSRtFxjWTWm5Z6GeucyLBEHg.png" - }, - { - "symbol": "LSHARE", - "name": "LSHARE TOKEN", - "mint": "9z8UpvjyH17UC8FoWFvmkke4hCfMjpFyVExZy61WHH2L", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/9z8UpvjyH17UC8FoWFvmkke4hCfMjpFyVExZy61WHH2L.png" - }, - { - "symbol": "SLDR", - "name": "Solderland", - "mint": "9ZLBKPCzkvDv85hojKofsogsESkJMN164QCVUtxvBxEQ", - "decimals": 6, - "extensions": { "coingeckoId": "solderland" }, - "icon": "https://img.raydium.io/icon/9ZLBKPCzkvDv85hojKofsogsESkJMN164QCVUtxvBxEQ.png" - }, - { - "symbol": "PKR2", - "name": "PKR2", - "mint": "A1C9Shy732BThWvHAN936f33N7Wm1HbFvxb2zDSoBx8F", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/A1C9Shy732BThWvHAN936f33N7Wm1HbFvxb2zDSoBx8F.png" - }, - { - "symbol": "HAMS", - "name": "Space Hamster", - "mint": "A2T2jDe2bxyEHkKtS8AtrTRmJ9VZRwyY8Kr7oQ8xNyfb", - "decimals": 9, - "extensions": { "coingeckoId": "space-hamster" }, - "icon": "https://img.raydium.io/icon/A2T2jDe2bxyEHkKtS8AtrTRmJ9VZRwyY8Kr7oQ8xNyfb.png" - }, - { - "symbol": "WOOP", - "name": "WOOP", - "mint": "A3HyGZqe451CBesNqieNPfJ4A9Mu332ui8ni6dobVSLB", - "decimals": 5, - "extensions": { "coingeckoId": "woop" }, - "icon": "https://img.raydium.io/icon/A3HyGZqe451CBesNqieNPfJ4A9Mu332ui8ni6dobVSLB.png" - }, - { - "symbol": "$SHIVER", - "name": "Shibaverse", - "mint": "A3iozx9T9wgrtybnecQ9rv56y9RF8ThUrwRGWiF7hsmZ", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/A3iozx9T9wgrtybnecQ9rv56y9RF8ThUrwRGWiF7hsmZ.png" - }, - { - "symbol": "KITCHEN", - "name": "Kitchen Token", - "mint": "A4Fpxz1RZGmscTxbF2Hhwywi1mGPVNaucc5gVwuM5Q5b", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/A4Fpxz1RZGmscTxbF2Hhwywi1mGPVNaucc5gVwuM5Q5b.png" - }, - { - "symbol": "GIS", - "name": "GeoBit", - "mint": "A4MgR6ANAh79AE1csJjXiRV2vYDqP8wgSUUp28HpDEyo", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/A4MgR6ANAh79AE1csJjXiRV2vYDqP8wgSUUp28HpDEyo.png" - }, - { - "symbol": "NTCK", - "name": "NetworkChuck Coin", - "mint": "A4zyBooAFkpfy7osonRJMQ8a6zArGxN5fNXjXo1ZTZK2", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/A4zyBooAFkpfy7osonRJMQ8a6zArGxN5fNXjXo1ZTZK2.png" - }, - { - "symbol": "SOLID", - "name": "Solid Protocol", - "mint": "A5UevXJdphkzXhRtTXj8JyoYYrWnkCLHVS986JHtRLyj", - "decimals": 9, - "extensions": { "coingeckoId": "solid-protocol" }, - "icon": "https://img.raydium.io/icon/A5UevXJdphkzXhRtTXj8JyoYYrWnkCLHVS986JHtRLyj.png" - }, - { - "symbol": "Zion", - "name": "Zion", - "mint": "A7rqejP8LKN8syXMr4tvcKjs2iJ4WtZjXNs1e6qP3m9g", - "decimals": 9, - "extensions": { "coingeckoId": "zion" }, - "icon": "https://img.raydium.io/icon/A7rqejP8LKN8syXMr4tvcKjs2iJ4WtZjXNs1e6qP3m9g.png" - }, - { - "symbol": "NERO", - "name": "Neronumis", - "mint": "A88nzMeNHiaRKMMGU1Pzd1HgaBJUgzvGZYvDFzJvuTpi", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/A88nzMeNHiaRKMMGU1Pzd1HgaBJUgzvGZYvDFzJvuTpi.png" - }, - { - "symbol": "DEGN", - "name": "Degen", - "mint": "A9UhP1xfQHWUhSd54NgKPub2XB3ZuQMdPEvf9aMTHxGT", - "decimals": 9, - "extensions": { "coingeckoId": "degen" }, - "icon": "https://img.raydium.io/icon/A9UhP1xfQHWUhSd54NgKPub2XB3ZuQMdPEvf9aMTHxGT.png" - }, - { - "symbol": "RACEFI", - "name": "RaceFi Token", - "mint": "AAmGoPDFLG6bE82BgZWjVi8k95tj9Tf3vUN7WvtUm2BU", - "decimals": 6, - "extensions": { "coingeckoId": "racefi" }, - "icon": "https://img.raydium.io/icon/AAmGoPDFLG6bE82BgZWjVi8k95tj9Tf3vUN7WvtUm2BU.png" - }, - { - "symbol": "RENNT", - "name": "RENT", - "mint": "AamY54CmEp9CFLKCxy97x2zxhFvqSFbQuZRhLz1mbSjm", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/AamY54CmEp9CFLKCxy97x2zxhFvqSFbQuZRhLz1mbSjm.png" - }, - { - "symbol": "SNAP", - "name": "SNAPSHOTS", - "mint": "AAoJ5eYd61QsUBRBxjCcAdsQZpQYxrob2wS4Hzoaeoas", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/AAoJ5eYd61QsUBRBxjCcAdsQZpQYxrob2wS4Hzoaeoas.png" - }, - { - "symbol": "SLX", - "name": "Solex Finance", - "mint": "AASdD9rAefJ4PP7iM89MYUsQEyCQwvBofhceZUGDh5HZ", - "decimals": 9, - "extensions": { "coingeckoId": "solex-finance" }, - "icon": "https://img.raydium.io/icon/AASdD9rAefJ4PP7iM89MYUsQEyCQwvBofhceZUGDh5HZ.png" - }, - { - "symbol": "SINU", - "name": "Samo INU", - "mint": "Ac7GiHwC7vZU2y97GRh9rqCqqnKAAgopYrTAtKccHxUk", - "decimals": 9, - "extensions": { "coingeckoId": "samo-inu" }, - "icon": "https://img.raydium.io/icon/Ac7GiHwC7vZU2y97GRh9rqCqqnKAAgopYrTAtKccHxUk.png" - }, - { - "symbol": "SCT", - "name": "Society Token v2", - "mint": "AcyTybdT75MhEauw1TJvRnpQjVKx6MMDyiU6FbSNKBec", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/AcyTybdT75MhEauw1TJvRnpQjVKx6MMDyiU6FbSNKBec.png" - }, - { - "symbol": "DYOR", - "name": "NERD", - "mint": "ADcEtKSVKDxBUe3JERgSh9q458w3kRKPMHkihF13vxx2", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/ADcEtKSVKDxBUe3JERgSh9q458w3kRKPMHkihF13vxx2.png" - }, - { - "symbol": "NIGGR", - "name": "RacisToken", - "mint": "ADj2YoHjZvv9HhAD32orJEzhYUsEBKbgTLD8c6FPUz4T", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/ADj2YoHjZvv9HhAD32orJEzhYUsEBKbgTLD8c6FPUz4T.png" - }, - { - "symbol": "DOGERACA", - "name": "DogeRaCa", - "mint": "ADQauiPc85ciT33JTTpxkC5BiTt6zYukWfDYPvZE7nBD", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/ADQauiPc85ciT33JTTpxkC5BiTt6zYukWfDYPvZE7nBD.png" - }, - { - "symbol": "KROOK", - "name": "Krook Coin", - "mint": "AfARcLLqRHsZc4xPWHE9nXZAswZaW294Ff1xcYQbjkLq", - "decimals": 9, - "extensions": { "coingeckoId": "krook-coin" }, - "icon": "https://img.raydium.io/icon/AfARcLLqRHsZc4xPWHE9nXZAswZaW294Ff1xcYQbjkLq.png" - }, - { - "symbol": "FIRE", - "name": "Solfire Finance", - "mint": "AfXLBfMZd32pN6QauazHCd7diEWoBgw1GNUALDw3suVZ", - "decimals": 6, - "extensions": { "coingeckoId": "solfire-finance" }, - "icon": "https://img.raydium.io/icon/AfXLBfMZd32pN6QauazHCd7diEWoBgw1GNUALDw3suVZ.png" - }, - { - "symbol": "SSU", - "name": "SunnySideUp Token", - "mint": "AGkFkKgXUEP7ZXazza5a25bSKbz5dDpgafPhqywuQnpf", - "decimals": 9, - "extensions": { "coingeckoId": "sunnysideup" }, - "icon": "https://img.raydium.io/icon/AGkFkKgXUEP7ZXazza5a25bSKbz5dDpgafPhqywuQnpf.png" - }, - { - "symbol": "EC", - "name": "EliteCoin", - "mint": "AhDt1FnEt759Tmxwa61E9FQhFnerPwMDTTt7CJjvog7L", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/AhDt1FnEt759Tmxwa61E9FQhFnerPwMDTTt7CJjvog7L.png" - }, - { - "symbol": "PNT", - "name": "PHANT", - "mint": "AKxR1NLTtPnsVcWwPSEGat1TC9da3Z2vX7sY4G7ZLj1r", - "decimals": 9, - "extensions": { "coingeckoId": "phant" }, - "icon": "https://img.raydium.io/icon/AKxR1NLTtPnsVcWwPSEGat1TC9da3Z2vX7sY4G7ZLj1r.png" - }, - { - "symbol": "NEKI", - "name": "Maneki-neko", - "mint": "ALKiRVrfLgzeAV2mCT7cJHKg3ZoPvsCRSV7VCRWnE8zQ", - "decimals": 9, - "extensions": { "coingeckoId": "maneki-neko" }, - "icon": "https://img.raydium.io/icon/ALKiRVrfLgzeAV2mCT7cJHKg3ZoPvsCRSV7VCRWnE8zQ.png" - }, - { - "symbol": "ALM", - "name": "Almond", - "mint": "ALMmmmbt5KNrPPUBFE4dAKUKSPWTop5s3kUGCdF69gmw", - "decimals": 6, - "extensions": { "coingeckoId": "almond" }, - "icon": "https://img.raydium.io/icon/ALMmmmbt5KNrPPUBFE4dAKUKSPWTop5s3kUGCdF69gmw.png" - }, - { - "symbol": "MDF", - "name": "MatrixETF DAO Finance", - "mint": "ALQ9KMWjFmxVbew3vMkJj3ypbAKuorSgGst6svCHEe2z", - "decimals": 6, - "extensions": { "coingeckoId": "matrixetf" }, - "icon": "https://img.raydium.io/icon/ALQ9KMWjFmxVbew3vMkJj3ypbAKuorSgGst6svCHEe2z.png" - }, - { - "symbol": "WCOIN", - "name": "WatchCoin", - "mint": "Am2QTz1KrLs2VP8BU4vUjRxTynxBEfNMGsAdNB5Sy8Np", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Am2QTz1KrLs2VP8BU4vUjRxTynxBEfNMGsAdNB5Sy8Np.png" - }, - { - "symbol": "MOLA", - "name": "MOONLANA", - "mint": "AMdnw9H5DFtQwZowVFr4kUgSXJzLokKSinvgGiUoLSps", - "decimals": 9, - "extensions": { "coingeckoId": "moonlana" }, - "icon": "https://img.raydium.io/icon/AMdnw9H5DFtQwZowVFr4kUgSXJzLokKSinvgGiUoLSps.png" - }, - { - "symbol": "BITCH", - "name": "Bitch Of Solana", - "mint": "AMNoi4727tzy7adu4wnx3cN2VQbQdG71DqaPoSm7isJ3", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/AMNoi4727tzy7adu4wnx3cN2VQbQdG71DqaPoSm7isJ3.png" - }, - { - "symbol": "ASTRA", - "name": "AstraPad", - "mint": "AMp8Jo18ZjK2tuQGfjKAkkWnVP4NWX5sav4NJH6pXF2D", - "decimals": 9, - "extensions": { "coingeckoId": "astrapad" }, - "icon": "https://img.raydium.io/icon/AMp8Jo18ZjK2tuQGfjKAkkWnVP4NWX5sav4NJH6pXF2D.png" - }, - { - "symbol": "FROG", - "name": "FROG", - "mint": "Amt5wUJREJQC5pX7Z48YSK812xmu4j3sQVupNhtsEuY8", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Amt5wUJREJQC5pX7Z48YSK812xmu4j3sQVupNhtsEuY8.png" - }, - { - "symbol": "GAMESHIB", - "name": "GAME SHIB COIN", - "mint": "AMzb4Tc7gDGHrsz1zUQzjtmQS2AXWuejveAKXKSpsoPU", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/AMzb4Tc7gDGHrsz1zUQzjtmQS2AXWuejveAKXKSpsoPU.png" - }, - { - "symbol": "JUNKz", - "name": "JUNK", - "mint": "AMzmwvDRKdt5AQ3m1m28tWjzBxmQNe1PsmHnYitVZwzp", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/AMzmwvDRKdt5AQ3m1m28tWjzBxmQNe1PsmHnYitVZwzp.png" - }, - { - "symbol": "ANKH", - "name": "ANKH", - "mint": "ankhim7kPXxLKVbW1Tn7vH4mLTuvCAqHjhkKuvwWJ7b", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/ankhim7kPXxLKVbW1Tn7vH4mLTuvCAqHjhkKuvwWJ7b.png" - }, - { - "symbol": "$CRECK", - "name": "CRECK", - "mint": "Ao94rg8D6oK2TAq3nm8YEQxfS73vZ2GWYw2AKaUihDEY", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Ao94rg8D6oK2TAq3nm8YEQxfS73vZ2GWYw2AKaUihDEY.png" - }, - { - "symbol": "JUNGLE", - "name": "Jungle", - "mint": "Aogv6j1wWiBAZcqRNN1Y89eozda2ke6rkc4CYy7c4iCi", - "decimals": 9, - "extensions": { "coingeckoId": "jungle" }, - "icon": "https://img.raydium.io/icon/Aogv6j1wWiBAZcqRNN1Y89eozda2ke6rkc4CYy7c4iCi.png" - }, - { - "symbol": "OINK", - "name": "OINK", - "mint": "Aojru8bfwZK6sgrx6exNazxASFZUjPpRY59byMrs6izt", - "decimals": 0, - "extensions": { "coingeckoId": "oink-token" }, - "icon": "https://img.raydium.io/icon/Aojru8bfwZK6sgrx6exNazxASFZUjPpRY59byMrs6izt.png" - }, - { - "symbol": "AOST", - "name": "AOS Token", - "mint": "aosvsUetSY7h7hSYXPR3oCoVMpo9GeL3Gtz2aqnua7p", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/aosvsUetSY7h7hSYXPR3oCoVMpo9GeL3Gtz2aqnua7p.png" - }, - { - "symbol": "VRSW", - "name": "VeraSaw", - "mint": "ApgNFHXMsY9qM8yaaSVzqX7xtbKkGjgo64NLGuf2hQjW", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/ApgNFHXMsY9qM8yaaSVzqX7xtbKkGjgo64NLGuf2hQjW.png" - }, - { - "symbol": "APN", - "name": "APN", - "mint": "apnggFw6CdVzxjdVC3KbfT6qVYfNi4VgQBuW7hVM9us", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/apnggFw6CdVzxjdVC3KbfT6qVYfNi4VgQBuW7hVM9us.png" - }, - { - "symbol": "CLIP", - "name": "Clip Finance", - "mint": "AR1AwFBUTQ2QNrKaY1vAMmHqqwQWGfX3bzxSaqJ76uPd", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/AR1AwFBUTQ2QNrKaY1vAMmHqqwQWGfX3bzxSaqJ76uPd.png" - }, - { - "symbol": "MPI", - "name": "Meta Paradise Island", - "mint": "ArdsPHY5LsCjvxSxZz8f3vTkv5qoYihmCCPMYvr6aQza", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/ArdsPHY5LsCjvxSxZz8f3vTkv5qoYihmCCPMYvr6aQza.png" - }, - { - "symbol": "CHI", - "name": "Project Paradise - CHI Token", - "mint": "ARg9wfeLN4qZTxgYTYeuGtGFMmYdk5zFhBuSnTfXXUvb", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/ARg9wfeLN4qZTxgYTYeuGtGFMmYdk5zFhBuSnTfXXUvb.png" - }, - { - "symbol": "DOGETH", - "name": "Doge Thug", - "mint": "ArhMyF2N8XpaujYUxTTDt9EuaBCaGaccxfwaZmkm9XeF", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/ArhMyF2N8XpaujYUxTTDt9EuaBCaGaccxfwaZmkm9XeF.png" - }, - { - "symbol": "SHIBL", - "name": "Shibalana Inu", - "mint": "AsVNhq2nnoUgMWciCvePRyHk7xAv6i4ruV6oRHFWBcwF", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/AsVNhq2nnoUgMWciCvePRyHk7xAv6i4ruV6oRHFWBcwF.png" - }, - { - "symbol": "BRWNDO", - "name": "BRAWNDO", - "mint": "At5j3zhbEj8mfFsSy1MPbjVhrX2uNmRMPEDZiyFcETNX", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/At5j3zhbEj8mfFsSy1MPbjVhrX2uNmRMPEDZiyFcETNX.png" - }, - { - "symbol": "NVGD", - "name": "NEOVANGUARD", - "mint": "ATC6C1AL4X51FXNFbPG5pxfjSgDQCNECtfsnyMUnk9X1", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/ATC6C1AL4X51FXNFbPG5pxfjSgDQCNECtfsnyMUnk9X1.png" - }, - { - "symbol": "NXDF", - "name": "NeXt-DeFi Protocol", - "mint": "Au6EdrSDubCUc34awy9c6iQAg5GSos9pPBXyZQtyZewV", - "decimals": 6, - "extensions": { "coingeckoId": "next-defi-protocol" }, - "icon": "https://img.raydium.io/icon/Au6EdrSDubCUc34awy9c6iQAg5GSos9pPBXyZQtyZewV.png" - }, - { - "symbol": "FLOKIS", - "name": "FlokiSol", - "mint": "AvB7Ffmt3H16bhq7ToXb839ynKzFgJxu2WDHsR1S9Yft", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/AvB7Ffmt3H16bhq7ToXb839ynKzFgJxu2WDHsR1S9Yft.png" - }, - { - "symbol": "BREAD", - "name": "BREAD Token", - "mint": "Avc1X8iAWLVrsnRtDK6aTyPDichkqe8YAn6ePGTuPAKH", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Avc1X8iAWLVrsnRtDK6aTyPDichkqe8YAn6ePGTuPAKH.png" - }, - { - "symbol": "PART", - "name": "Particle", - "mint": "AVKnbqNQgXDY8kbnno9eSGfwpVz5idimBnDKiz1vbWAh", - "decimals": 9, - "extensions": { "coingeckoId": "particle-technology" }, - "icon": "https://img.raydium.io/icon/AVKnbqNQgXDY8kbnno9eSGfwpVz5idimBnDKiz1vbWAh.png" - }, - { - "symbol": "PANDA", - "name": "Panda Coin", - "mint": "Aw8qLRHGhMcKq7rxs5XBNCd9oe3BvoAhpNMVz7AdGmty", - "decimals": 9, - "extensions": { "coingeckoId": "panda-coin" }, - "icon": "https://img.raydium.io/icon/Aw8qLRHGhMcKq7rxs5XBNCd9oe3BvoAhpNMVz7AdGmty.png" - }, - { - "symbol": "SBFC", - "name": "SBF Coin", - "mint": "AWW5UQfMBnPsTaaxCK7cSEmkj1kbX2zUrqvgKXStjBKx", - "decimals": 6, - "extensions": { "coingeckoId": "sbf-coin" }, - "icon": "https://img.raydium.io/icon/AWW5UQfMBnPsTaaxCK7cSEmkj1kbX2zUrqvgKXStjBKx.png" - }, - { - "symbol": "CIGO", - "name": "Crypto IGO", - "mint": "aWXP3vpT9MhFWDoMEYG5ssYG72dZN5Cb8cLWDLLThpB", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "EDGE", - "name": "Lord Edge Elon", - "mint": "Ax9MbdUbr7cPQhkipXnBh2QNDSzf245Sn4xKfQUDuJGD", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Ax9MbdUbr7cPQhkipXnBh2QNDSzf245Sn4xKfQUDuJGD.png" - }, - { - "symbol": "KAYAC", - "name": "Kayac", - "mint": "AxXoJZhSfeVUe3qgFZTt4NwQRJB61pBQAHTdWTN9PNms", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/AxXoJZhSfeVUe3qgFZTt4NwQRJB61pBQAHTdWTN9PNms.png" - }, - { - "symbol": "TICKET", - "name": "The Ticket Finance", - "mint": "AymKzSDznoLT7Vhsb4wSRnCj1gjcG3zkgYFY8fxsHHer", - "decimals": 8, - "extensions": { "coingeckoId": "ticket-finance" }, - "icon": "https://img.raydium.io/icon/AymKzSDznoLT7Vhsb4wSRnCj1gjcG3zkgYFY8fxsHHer.png" - }, - { - "symbol": "BTL", - "name": "BitLegacy Token", - "mint": "aYZPYgohjK6LYM8o1v6pnr3ZinhuRzSHd6TRDVDUBkK", - "decimals": 8, - "extensions": {}, - "icon": "https://img.raydium.io/icon/aYZPYgohjK6LYM8o1v6pnr3ZinhuRzSHd6TRDVDUBkK.png" - }, - { - "symbol": "CUSE", - "name": "CuseTheJuice", - "mint": "AZci9R148CU6hfnnE8ffm2K5mkxagbnTAZNQF5fLbvHb", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/AZci9R148CU6hfnnE8ffm2K5mkxagbnTAZNQF5fLbvHb.png" - }, - { - "symbol": "MHCNWS", - "name": "Most Hyped Crypto News Token", - "mint": "AzZMJEE1u5cM2fVtPFp5K4jyL5988i72WiwQhLCXQTr2", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/AzZMJEE1u5cM2fVtPFp5K4jyL5988i72WiwQhLCXQTr2.png" - }, - { - "symbol": "COBRA", - "name": "Cobra Coin", - "mint": "B1nrnT8LvkxqJFw3A9tWoXCpbLUNKYkn8gW8qYZoTRaN", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/B1nrnT8LvkxqJFw3A9tWoXCpbLUNKYkn8gW8qYZoTRaN.png" - }, - { - "symbol": "BLOCK", - "name": "BlockParty BLOCK", - "mint": "B1ock8ufjvuEPo4eDhnTHtY1uzk2TLg9zpoLnmMpa3Ht", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/B1ock8ufjvuEPo4eDhnTHtY1uzk2TLg9zpoLnmMpa3Ht.png" - }, - { - "symbol": "PARTI", - "name": "PARTI", - "mint": "B3Ggjjj3QargPkFTAJiR6BaD8CWKFUaWRXGcDQ1nyeeD", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/B3Ggjjj3QargPkFTAJiR6BaD8CWKFUaWRXGcDQ1nyeeD.png" - }, - { - "symbol": "RAD", - "name": "RAD", - "mint": "B6aJ3TGfme3SMnLSouHXqWXjVFqYyqj7czzhzr8WJFAi", - "decimals": 4, - "extensions": { "coingeckoId": "rad" }, - "icon": "https://img.raydium.io/icon/B6aJ3TGfme3SMnLSouHXqWXjVFqYyqj7czzhzr8WJFAi.png" - }, - { - "symbol": "TrumpcoinXSOL", - "name": "TRUMPXSOL", - "mint": "B6NyNs3k2DZm6XYNL5wyC8sWEkEL4S8eekonRaSjjD7B", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/B6NyNs3k2DZm6XYNL5wyC8sWEkEL4S8eekonRaSjjD7B.png" - }, - { - "symbol": "ITI", - "name": "Innovation Technology Information-Meta Learn", - "mint": "B87r1e6PsztnS5fHFCHhQP86dtd9ASfKWCUytLBpudLi", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/B87r1e6PsztnS5fHFCHhQP86dtd9ASfKWCUytLBpudLi.png" - }, - { - "symbol": "METASOL", - "name": "META SOL", - "mint": "B8NrYG3ZGbmDS6Xv5PUSdpJmXor9VvtxibvDRKNq3rnc", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/B8NrYG3ZGbmDS6Xv5PUSdpJmXor9VvtxibvDRKNq3rnc.png" - }, - { - "symbol": "CHIMP", - "name": "Chimp", - "mint": "B8wCsjSv3TDZcaLuhPZNDvpk2vuBtRgpgmTuvoDAJZZ7", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/B8wCsjSv3TDZcaLuhPZNDvpk2vuBtRgpgmTuvoDAJZZ7.png" - }, - { - "symbol": "UPB", - "name": "Upbring Token", - "mint": "B9LtfDZWWRrihYu8jDN57thcqqi7xfWAvj8yq4o2YJxw", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/B9LtfDZWWRrihYu8jDN57thcqqi7xfWAvj8yq4o2YJxw.png" - }, - { - "symbol": "SBABYDOGE", - "name": "SOL BABAY DOGE COIN", - "mint": "BABYsocP6cB95xvBDXnjXKX96VBNC37dmNWUtaV9Jk6v", - "decimals": 2, - "extensions": { "coingeckoId": "sol-baby-doge" }, - "icon": "https://img.raydium.io/icon/BABYsocP6cB95xvBDXnjXKX96VBNC37dmNWUtaV9Jk6v.png" - }, - { - "symbol": "BOTOX", - "name": "BOTOX Wellnes and Healthcare", - "mint": "BaSkmM2e6dY8aC4oe8Rh4B7L4bNG4tjtKSinVfjfoCRK", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BaSkmM2e6dY8aC4oe8Rh4B7L4bNG4tjtKSinVfjfoCRK.png" - }, - { - "symbol": "MISO", - "name": "MISO", - "mint": "BaZXh456atM5Fh7uWcbKeTPGXbMCacoxwXhbrM8eefNm", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BaZXh456atM5Fh7uWcbKeTPGXbMCacoxwXhbrM8eefNm.png" - }, - { - "symbol": "GODZ", - "name": "Godz Token", - "mint": "BB33fYoeBVA2uv119be9tKvmXeuwtcx1W25N9KFNd2ca", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BB33fYoeBVA2uv119be9tKvmXeuwtcx1W25N9KFNd2ca.png" - }, - { - "symbol": "SYX", - "name": "Solanyx", - "mint": "BBdrgbSeqcQsMP7Wo9Nv2Xac94UPiKjR9tEBS6Kz7NFp", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "FIYA", - "name": "Fiya", - "mint": "BBUiBwwG2pLZFboPpbvqVXACs4r3HrNBaC73zzXspfYW", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BBUiBwwG2pLZFboPpbvqVXACs4r3HrNBaC73zzXspfYW.png" - }, - { - "symbol": "NOVA", - "name": "NOVA FINANCE", - "mint": "BDrL8huis6S5tpmozaAaT5zhE5A7ZBAB2jMMvpKEeF8A", - "decimals": 9, - "extensions": { "coingeckoId": "nova-finance" }, - "icon": "https://img.raydium.io/icon/BDrL8huis6S5tpmozaAaT5zhE5A7ZBAB2jMMvpKEeF8A.png" - }, - { - "symbol": "BTSG", - "name": "BitSong", - "mint": "BDxWSxkMLW1nJ3VggamUKkEKrtCaVqzFxoDApM8HdBks", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BDxWSxkMLW1nJ3VggamUKkEKrtCaVqzFxoDApM8HdBks.png" - }, - { - "symbol": "GAPE", - "name": "Gapes on Sol", - "mint": "BebGokMwTrFp2wRV4Z5CftVq7pvgMbj176VND3vTVSKJ", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BebGokMwTrFp2wRV4Z5CftVq7pvgMbj176VND3vTVSKJ.png" - }, - { - "symbol": "BELE", - "name": "Baby Elephant", - "mint": "BELEkfxRkTdNexHtsJ8sk6RBx1ZuNcQmfpkKSNgq8S7N", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BELEkfxRkTdNexHtsJ8sk6RBx1ZuNcQmfpkKSNgq8S7N.png" - }, - { - "symbol": "BIRD", - "name": "SolBird2", - "mint": "BfbhLmrhtELjfFzrtcxpB1GoTpmiVK8qcpSYf7AM914h", - "decimals": 4, - "extensions": {}, - "icon": "" - }, - { - "symbol": "CLN", - "name": "Central Loyalty Network", - "mint": "BfkeTseqgoxUn8gF1fGQC4GoqHMaCfzmQUgKF4nKDFhr", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BfkeTseqgoxUn8gF1fGQC4GoqHMaCfzmQUgKF4nKDFhr.png" - }, - { - "symbol": "BUFF", - "name": "Buffaloe", - "mint": "BgBUxRsEgXur2iyhhJnWwbBMiSNiMWz1Ka5TTgVRt2Ft", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BgBUxRsEgXur2iyhhJnWwbBMiSNiMWz1Ka5TTgVRt2Ft.png" - }, - { - "symbol": "BAPE", - "name": "BAPE", - "mint": "BgeRyFWWGHeVouqfHfcXUxmvfkgekhrXYVqQWf63kpJB", - "decimals": 9, - "extensions": { "coingeckoId": "bored-ape-social-club" }, - "icon": "https://img.raydium.io/icon/BgeRyFWWGHeVouqfHfcXUxmvfkgekhrXYVqQWf63kpJB.png" - }, - { - "symbol": "Hono", - "name": "Hono", - "mint": "BGN9c9JJxMgmm7rUqeLanYwWwo2GbedjUFaXn7tAeuXK", - "decimals": 9, - "extensions": { "coingeckoId": "hono" }, - "icon": "https://img.raydium.io/icon/BGN9c9JJxMgmm7rUqeLanYwWwo2GbedjUFaXn7tAeuXK.png" - }, - { - "symbol": "FCKU", - "name": "FCKU", - "mint": "BHcuncUCUxsBw1yyENizoseEAH2Qrt4UxbcukPhQEGPQ", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BHcuncUCUxsBw1yyENizoseEAH2Qrt4UxbcukPhQEGPQ.png" - }, - { - "symbol": "BANA", - "name": "Shibana", - "mint": "BhPXDQio8xtNC6k5Bg5fnUVL9kGN8uvRDNwW8MZBu8DL", - "decimals": 4, - "extensions": { "coingeckoId": "shibana" }, - "icon": "https://img.raydium.io/icon/BhPXDQio8xtNC6k5Bg5fnUVL9kGN8uvRDNwW8MZBu8DL.png" - }, - { - "symbol": "DIO", - "name": "Decimated", - "mint": "BiDB55p4G3n1fGhwKFpxsokBMqgctL4qnZpDH1bVQxMD", - "decimals": 9, - "extensions": { "coingeckoId": "decimated" }, - "icon": "https://img.raydium.io/icon/BiDB55p4G3n1fGhwKFpxsokBMqgctL4qnZpDH1bVQxMD.png" - }, - { - "symbol": "INFH", - "name": "Inflation Hedge", - "mint": "BikKd7FNs7xdKFZjFUida6KD4uKcH4mTm4DN2HoKqL2D", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "SOLRC", - "name": "SolRaca", - "mint": "Bjgh4YsLdicr8WArz9ftdSmpWNcQjsZ9KV3w9fkjiLG", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "PUSSY", - "name": "Pussy", - "mint": "BjTUmZjNUUAPKHVdTs8yZsCmecW5isSK4AbuFihXoUwa", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BjTUmZjNUUAPKHVdTs8yZsCmecW5isSK4AbuFihXoUwa.png" - }, - { - "symbol": "AERA", - "name": "Aera Token", - "mint": "BjZ5Hazjyp9LrzfapAHYZuceWm6zJZDqMH1QPCWtsouq", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BjZ5Hazjyp9LrzfapAHYZuceWm6zJZDqMH1QPCWtsouq.png" - }, - { - "symbol": "KissMe", - "name": "Kiss Me ", - "mint": "BKGp1At3yLDK1NE2gfMuwv1QMAHBwnqgSdULsyzjUagA", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BKGp1At3yLDK1NE2gfMuwv1QMAHBwnqgSdULsyzjUagA.png" - }, - { - "symbol": "SDC", - "name": "SandDollarClassic", - "mint": "BKMWPkPS8jXw59ezYwK2ueNTZRF4m8MYHDjh9HwUmkQ7", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BKMWPkPS8jXw59ezYwK2ueNTZRF4m8MYHDjh9HwUmkQ7.png" - }, - { - "symbol": "FBZ", - "name": "FakeBiz", - "mint": "BKydRTNdaMJ8B4zPva3YhwUQcpvAsyZaGJnKA6F44fX7", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BKydRTNdaMJ8B4zPva3YhwUQcpvAsyZaGJnKA6F44fX7.png" - }, - { - "symbol": "BLOOD", - "name": "DRACULA GAME BLOOD", - "mint": "BLAAD2QLUgRSbQ9AB9jqAoHh55cGVcSBaCH9JGBh2zDX", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BLAAD2QLUgRSbQ9AB9jqAoHh55cGVcSBaCH9JGBh2zDX.png" - }, - { - "symbol": "TFOXES", - "name": "Transdimensional Fox Federation Floor Index", - "mint": "BLyV6szCZ7Ypye8AHXyHDmjC4uC73sGvEJoMwoVQw3Te", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BLyV6szCZ7Ypye8AHXyHDmjC4uC73sGvEJoMwoVQw3Te.png" - }, - { - "symbol": "HP", - "name": "Honey Pot", - "mint": "BmLvq52WKMb5MYKLScay5V9C4Sh4E67zxvwLbU6i2vTR", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BmLvq52WKMb5MYKLScay5V9C4Sh4E67zxvwLbU6i2vTR.png" - }, - { - "symbol": "BNTY", - "name": "Bounty", - "mint": "BNTY5DaMP9CZhEtmQfMLHfUwwkXropHuCz4m96YqpqKm", - "decimals": 9, - "extensions": { "coingeckoId": "bounty" }, - "icon": "https://img.raydium.io/icon/BNTY5DaMP9CZhEtmQfMLHfUwwkXropHuCz4m96YqpqKm.png" - }, - { - "symbol": "BNTY", - "name": "Bounty", - "mint": "BNTYkJdHkdP9eH4uGouRkqz9RifYL8knHVVVmBMgcNzx", - "decimals": 9, - "extensions": { "coingeckoId": "bounty" }, - "icon": "" - }, - { - "symbol": "NOIA", - "name": "NOIA", - "mint": "BnV3XcZUbNsuonNKqkQrZSvCN8tVYTJtDgfUx6DJ9riy", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BnV3XcZUbNsuonNKqkQrZSvCN8tVYTJtDgfUx6DJ9riy.png" - }, - { - "symbol": "BOFx", - "name": "BitOptionsFx", - "mint": "BoFxKXdyiEYJReWGZAT4tavuAo3D1BmDyXK5VFSXd4EF", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BoFxKXdyiEYJReWGZAT4tavuAo3D1BmDyXK5VFSXd4EF.png" - }, - { - "symbol": "BMA", - "name": "Boom Army", - "mint": "boomh1LQnwDnHtKxWTFgxcbdRjPypRSjdwxkAEJkFSH", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/boomh1LQnwDnHtKxWTFgxcbdRjPypRSjdwxkAEJkFSH.png" - }, - { - "symbol": "HOTTO", - "name": "HottoShotto", - "mint": "Bqd2ujCTEzpKzfjb1FHL7FKrdM6n1rZSnRecJK57EoKz", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Bqd2ujCTEzpKzfjb1FHL7FKrdM6n1rZSnRecJK57EoKz.png" - }, - { - "symbol": "ECHO", - "name": "EchoDao", - "mint": "BqRtfrNpvRAW3KW319hvhPoTu76wKU2LTdXJyG9CyDze", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BqRtfrNpvRAW3KW319hvhPoTu76wKU2LTdXJyG9CyDze.png" - }, - { - "symbol": "SHELL", - "name": "MetaShells", - "mint": "BRg8CLYEStYAFQad3CVMCYy1cgeuvUnarAZLV8K8Hyfv", - "decimals": 9, - "extensions": { "coingeckoId": "metashells" }, - "icon": "" - }, - { - "symbol": "GSTONKS", - "name": "Gamestonks", - "mint": "BrwgXmUtNd32dTKdP5teie68EmBnjGq8Wp3MukHehUBY", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BrwgXmUtNd32dTKdP5teie68EmBnjGq8Wp3MukHehUBY.png" - }, - { - "symbol": "CUSEGOVERNANCE", - "name": "CuseTheJuice Governance Token", - "mint": "BtndwmZJ6QSJpb2dQFm9VyuaQPfKGFB9NrLXeY7rHvT8", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BtndwmZJ6QSJpb2dQFm9VyuaQPfKGFB9NrLXeY7rHvT8.png" - }, - { - "symbol": "TIGERW3", - "name": "Web3Tiger", - "mint": "BtxmGUJHu8iqLu8rqECHhwDzbX3J4EHjA8NbtjiRXUoJ", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BtxmGUJHu8iqLu8rqECHhwDzbX3J4EHjA8NbtjiRXUoJ.png" - }, - { - "symbol": "NNI", - "name": "NeoNomad", - "mint": "buMnhMd5xSyXBssTQo15jouu8VhuEZJCfbtBUZgRcuW", - "decimals": 6, - "extensions": { "coingeckoId": "neonomad-finance" }, - "icon": "https://img.raydium.io/icon/buMnhMd5xSyXBssTQo15jouu8VhuEZJCfbtBUZgRcuW.png" - }, - { - "symbol": "DEDS", - "name": "Decimus Dynamics Token", - "mint": "BvEj2MNMPsUrD4vSk7NHs4TtRcCcJd75Wx5HvVbY4rbK", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "SKULLYS", - "name": "Disarticulated Skullys Index", - "mint": "BVGiPUve3dtMLNw2iv3tA7NN8Jv198Ha9FmPXKMUDkjF", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BVGiPUve3dtMLNw2iv3tA7NN8Jv198Ha9FmPXKMUDkjF.png" - }, - { - "symbol": "XENO", - "name": "The Xenobots Project", - "mint": "Bwfe7DwmEDvjEBZGbQnDU8CrwZsuvYaed1VuQ8KDTGsS", - "decimals": 0, - "extensions": { "coingeckoId": "the-xenobots-project" }, - "icon": "https://img.raydium.io/icon/Bwfe7DwmEDvjEBZGbQnDU8CrwZsuvYaed1VuQ8KDTGsS.png" - }, - { - "symbol": "DOELON", - "name": "Dogs Of Elon", - "mint": "BWm92csusaUNPWu8M2aC2UTcGQVJsrhH7JYtd47zN7FA", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BWm92csusaUNPWu8M2aC2UTcGQVJsrhH7JYtd47zN7FA.png" - }, - { - "symbol": "TOX", - "name": "trollbox", - "mint": "Bx4ykEMurwPQBAFNvthGj73fMBVTvHa8e9cbAyaK4ZSh", - "decimals": 9, - "extensions": { "coingeckoId": "trollbox" }, - "icon": "https://img.raydium.io/icon/Bx4ykEMurwPQBAFNvthGj73fMBVTvHa8e9cbAyaK4ZSh.png" - }, - { - "symbol": "PGNT", - "name": "PigeonSol Token", - "mint": "BxHJqGtC629c55swCqWXFGA2rRF1igbbTmh22H8ePUWG", - "decimals": 4, - "extensions": { "coingeckoId": "pigeon-sol" }, - "icon": "https://img.raydium.io/icon/BxHJqGtC629c55swCqWXFGA2rRF1igbbTmh22H8ePUWG.png" - }, - { - "symbol": "GUMA", - "name": "GUM ARABIC", - "mint": "BXVR8wqs8ixPMHnuUq65buJQmimwG9WG5pNKKKBRd2S4", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BXVR8wqs8ixPMHnuUq65buJQmimwG9WG5pNKKKBRd2S4.png" - }, - { - "symbol": "POM", - "name": "Pom Token", - "mint": "ByJ8a9NWk6G4Jg4iFyFNdrya1iVcusL1aL9aGXWXeoVG", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/ByJ8a9NWk6G4Jg4iFyFNdrya1iVcusL1aL9aGXWXeoVG.png" - }, - { - "symbol": "$SPOT", - "name": "SPOT", - "mint": "BzwERW2s5brUYtt3jvobVQn64uxXYRrz81Yx6vYpJorE", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BzwERW2s5brUYtt3jvobVQn64uxXYRrz81Yx6vYpJorE.png" - }, - { - "symbol": "ThugMonkey", - "name": "Thug Monkey", - "mint": "BzY2yoAPi3tD5xqVqEzrSPu5CSv9Vk7V2fsjJAQLqLv8", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/BzY2yoAPi3tD5xqVqEzrSPu5CSv9Vk7V2fsjJAQLqLv8.png" - }, - { - "symbol": "RZC", - "name": "RZCoin", - "mint": "C57GUQaD4qJcUpQJWJuzz9zQ8ySQuEsfuksFhV2xyhxq", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/C57GUQaD4qJcUpQJWJuzz9zQ8ySQuEsfuksFhV2xyhxq.png" - }, - { - "symbol": "Janus", - "name": "Janus Finance", - "mint": "C5quBbSnDjLpdVuCQnJF38Uw3arfmHUNCPGPDR2L8cyh", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/C5quBbSnDjLpdVuCQnJF38Uw3arfmHUNCPGPDR2L8cyh.png" - }, - { - "symbol": "T1NY", - "name": "Tiny Bonez", - "mint": "C5xtJBKm24WTt3JiXrvguv7vHCe7CknDB7PNabp4eYX6", - "decimals": 9, - "extensions": { "coingeckoId": "tiny-bonez" }, - "icon": "https://img.raydium.io/icon/C5xtJBKm24WTt3JiXrvguv7vHCe7CknDB7PNabp4eYX6.png" - }, - { - "symbol": "LSTAR", - "name": "Learning Star", - "mint": "C6qep3y7tCZUJYDXHiwuK46Gt6FsoxLi8qV1bTCRYaY1", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/C6qep3y7tCZUJYDXHiwuK46Gt6FsoxLi8qV1bTCRYaY1.png" - }, - { - "symbol": "WENSIR", - "name": "Wensircoin", - "mint": "c8JyuF2fD84G6Vk4AmeVfTUoseNRmv2A9JpymAXi4B6", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/c8JyuF2fD84G6Vk4AmeVfTUoseNRmv2A9JpymAXi4B6.png" - }, - { - "symbol": "BIRDZ", - "name": "Bit Birdz Floor Index", - "mint": "Ca6XebDSTEMFJbJMB6ob6CbMWYcL3GtJFsCVFWiMoeMD", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Ca6XebDSTEMFJbJMB6ob6CbMWYcL3GtJFsCVFWiMoeMD.png" - }, - { - "symbol": "CAPY", - "name": "Capybara", - "mint": "CAPYD6Lrm7bTZ6C7t7JvSxvpEcfKQ9YNB7kUjh6p6XBN", - "decimals": 9, - "extensions": { "coingeckoId": "capybara" }, - "icon": "https://img.raydium.io/icon/CAPYD6Lrm7bTZ6C7t7JvSxvpEcfKQ9YNB7kUjh6p6XBN.png" - }, - { - "symbol": "CHUG", - "name": "CHUG Token", - "mint": "CbDwU8JrTYv3GzU7msni8qtfFkAGpcyFAzuhuGq5SVqp", - "decimals": 9, - "extensions": { "coingeckoId": "chug-token" }, - "icon": "https://img.raydium.io/icon/CbDwU8JrTYv3GzU7msni8qtfFkAGpcyFAzuhuGq5SVqp.png" - }, - { - "symbol": "KSOL", - "name": "KITTYCOIN SOL", - "mint": "CBPfSGeSf76o3r4628k7BcZ5YBNxHh7hkCzu4AmVgk2Q", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CBPfSGeSf76o3r4628k7BcZ5YBNxHh7hkCzu4AmVgk2Q.png" - }, - { - "symbol": "GUARD", - "name": "VANGUARD", - "mint": "CBV12y1pehFbhdnDpUfgPe88SbUZ5G2s1kLA449Yu3Ad", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CBV12y1pehFbhdnDpUfgPe88SbUZ5G2s1kLA449Yu3Ad.png" - }, - { - "symbol": "MILK", - "name": "Tiddy Juice Coin", - "mint": "CCKDRAd4Xwjoovtf2s1duu3d4TPTmFRyh1hfrb3ZUGR2", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CCKDRAd4Xwjoovtf2s1duu3d4TPTmFRyh1hfrb3ZUGR2.png" - }, - { - "symbol": "NERON", - "name": "Neron", - "mint": "CcM2KGSi9XSkbg1mR1szTee2BDazbnW5Qy4prw9zJHFn", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CcM2KGSi9XSkbg1mR1szTee2BDazbnW5Qy4prw9zJHFn.png" - }, - { - "symbol": "NFTREES", - "name": "NFTrees Floor Index", - "mint": "cCUYsVip3Ve2EbStXE9EVncPiRdcjTH7LfFKaB8g55d", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/cCUYsVip3Ve2EbStXE9EVncPiRdcjTH7LfFKaB8g55d.png" - }, - { - "symbol": "HONEYBEAR", - "name": "HONEYBEAR", - "mint": "CdcRwbFuj3YNJYdfUqh3hnxFz1fuF6he1Wgz7JvZMHda", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CdcRwbFuj3YNJYdfUqh3hnxFz1fuF6he1Wgz7JvZMHda.png" - }, - { - "symbol": "SHIBS", - "name": "ShibSol", - "mint": "CDxwZo3ayxvTmxin7F6o9xg6SjdE4qWEDXV6MZFBevqw", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "BORG", - "name": "Cyborg Apes BORG", - "mint": "CFbdjaKonbBQTYG2GC6CmB7exofgDYGCDR8tp8KVGS7T", - "decimals": 6, - "extensions": { "coingeckoId": "cyborg-apes" }, - "icon": "https://img.raydium.io/icon/CFbdjaKonbBQTYG2GC6CmB7exofgDYGCDR8tp8KVGS7T.png" - }, - { - "symbol": "DR", - "name": "SOUL Coin", - "mint": "CfzXjG5VCQqZ7H7hxnoZZpA1MdcGSThcm6aaipU3M46K", - "decimals": 3, - "extensions": {}, - "icon": "" - }, - { - "symbol": "VINU", - "name": "Viral Inu", - "mint": "CgbJxXyaHeU8VsquBpySuFXA94b6LWXxioZ28wRr8fs9", - "decimals": 6, - "extensions": { "coingeckoId": "viral-inu" }, - "icon": "https://img.raydium.io/icon/CgbJxXyaHeU8VsquBpySuFXA94b6LWXxioZ28wRr8fs9.png" - }, - { - "symbol": "TiP", - "name": "CREATiP", - "mint": "CGBxTQNXMmmCXAPm4dC9MQJ1q8JDDxApwFwW188SdtBu", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CGBxTQNXMmmCXAPm4dC9MQJ1q8JDDxApwFwW188SdtBu.png" - }, - { - "symbol": "MEND", - "name": "Mend", - "mint": "Ch9NFVk5sqEPQHtw2gJVgnHfTm7FW1JspYwc7SxLi6q3", - "decimals": 9, - "extensions": { "coingeckoId": "mend" }, - "icon": "https://img.raydium.io/icon/Ch9NFVk5sqEPQHtw2gJVgnHfTm7FW1JspYwc7SxLi6q3.png" - }, - { - "symbol": "MTP", - "name": "Metapoo", - "mint": "ChTE6TCqoY16dvqPjgK6Ji7zHcKricB2DHLoqWzx5v9A", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/ChTE6TCqoY16dvqPjgK6Ji7zHcKricB2DHLoqWzx5v9A.png" - }, - { - "symbol": "BONER", - "name": "BONER", - "mint": "CJ2K2J3HYU6ibR1JwLkUmD9RM8eytfxtMcLzYPqoQQKo", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CJ2K2J3HYU6ibR1JwLkUmD9RM8eytfxtMcLzYPqoQQKo.png" - }, - { - "symbol": "SOC", - "name": "Solcrystol", - "mint": "CJze5X3G3V6nqqrfeALTpb1HbkKvspjiUGR12rVchL3T", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CJze5X3G3V6nqqrfeALTpb1HbkKvspjiUGR12rVchL3T.png" - }, - { - "symbol": "XMAS", - "name": "XMAS DAO", - "mint": "CKGZzeufghDK7Sekk4MnP34m1TuEkmhGU25rs6YGeHdP", - "decimals": 1, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CKGZzeufghDK7Sekk4MnP34m1TuEkmhGU25rs6YGeHdP.png" - }, - { - "symbol": "CHALK", - "name": "CHALK", - "mint": "CmAgr6XtAZsR1BGrxTrbVKXsVvvC4Y69GXR2zP8XxK3X", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CmAgr6XtAZsR1BGrxTrbVKXsVvvC4Y69GXR2zP8XxK3X.png" - }, - { - "symbol": "AGX", - "name": "AGX Coin", - "mint": "CMdr2YEhJbnf82NSPci8PdG1zfViQPGExbbZoy5LJL7v", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CMdr2YEhJbnf82NSPci8PdG1zfViQPGExbbZoy5LJL7v.png" - }, - { - "symbol": "GM", - "name": "GM Solana", - "mint": "CmSryDa4mnDYUicq7qSESsTKAdgBP26jSYcg8zavVoJd", - "decimals": 7, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CmSryDa4mnDYUicq7qSESsTKAdgBP26jSYcg8zavVoJd.png" - }, - { - "symbol": "$REM", - "name": "Guardian Remnants", - "mint": "CNMvWLKc8r1wRrQ1Xws6v43x5ttTnaf2pccLkUqsfXVf", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CNMvWLKc8r1wRrQ1Xws6v43x5ttTnaf2pccLkUqsfXVf.png" - }, - { - "symbol": "CODE", - "name": "Code", - "mint": "Code7hV6DaK5Werof8c7vPwBxLvhmEWVUbU2AfhBZArB", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Code7hV6DaK5Werof8c7vPwBxLvhmEWVUbU2AfhBZArB.png" - }, - { - "symbol": "SURF", - "name": "Serum Surfers Floor Index", - "mint": "CP8CaP7GmSVUo9j3L8dwDKVR6i1kvcCUn1ubGGhc2V2M", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CP8CaP7GmSVUo9j3L8dwDKVR6i1kvcCUn1ubGGhc2V2M.png" - }, - { - "symbol": "DARC", - "name": "DARC Token", - "mint": "CpFE715P5DnDoJj9FbCRcuyHHeTXNdRnvzNkHvq1o23U", - "decimals": 8, - "extensions": { "coingeckoId": "darcmatter-coin" }, - "icon": "https://img.raydium.io/icon/CpFE715P5DnDoJj9FbCRcuyHHeTXNdRnvzNkHvq1o23U.png" - }, - { - "symbol": "Cate", - "name": "CateCoin SOL", - "mint": "CPL7TvVnQXQ8aN2DytF53uskyYAVxgNx5z2waJrc3Cev", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CPL7TvVnQXQ8aN2DytF53uskyYAVxgNx5z2waJrc3Cev.png" - }, - { - "symbol": "CPX", - "name": "Circlepod Protocol Token", - "mint": "CPXDs2uhNwDKAt9V3vXvtspv9U7rsQ2fVr1qAUDmuCaq", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CPXDs2uhNwDKAt9V3vXvtspv9U7rsQ2fVr1qAUDmuCaq.png" - }, - { - "symbol": "WVIP", - "name": "The WAGMI VIP Club", - "mint": "CQkTVkohEmyydNPNPH82c6aNPeXE72AatrhZcbntiAfg", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CQkTVkohEmyydNPNPH82c6aNPeXE72AatrhZcbntiAfg.png" - }, - { - "symbol": "SCUM", - "name": "Solana CUM", - "mint": "cqNTpypmbwghrf1G9VGvSENcw7M7wGSQ7JS8UTQWXwb", - "decimals": 8, - "extensions": {}, - "icon": "https://img.raydium.io/icon/cqNTpypmbwghrf1G9VGvSENcw7M7wGSQ7JS8UTQWXwb.png" - }, - { - "symbol": "CREAMY", - "name": "Creamy", - "mint": "CREAMpdDimXxj2zTCwP5wMEtba4NYaKCrTBEQTSKtqHe", - "decimals": 9, - "extensions": { "coingeckoId": "creamy" }, - "icon": "https://img.raydium.io/icon/CREAMpdDimXxj2zTCwP5wMEtba4NYaKCrTBEQTSKtqHe.png" - }, - { - "symbol": "Vikings", - "name": "Viking Legend", - "mint": "CrhUSH7FDwB37BYvPsVnVbsGVeE81biBzfkD4A4fyJMv", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CrhUSH7FDwB37BYvPsVnVbsGVeE81biBzfkD4A4fyJMv.png" - }, - { - "symbol": "SEI", - "name": "Solanium Ecosystem Index", - "mint": "CRkwd2QedqDi5u6W2w6jeAViAUd1pR4AXs2aKvh7GW7M", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CRkwd2QedqDi5u6W2w6jeAViAUd1pR4AXs2aKvh7GW7M.png" - }, - { - "symbol": "GEC", - "name": "Green Energy", - "mint": "CRRPG57uFaG4Rbfauski7PuSRLQDMsoABtF3UTyhFraT", - "decimals": 3, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CRRPG57uFaG4Rbfauski7PuSRLQDMsoABtF3UTyhFraT.png" - }, - { - "symbol": "AGVZ", - "name": "Agave Zwolf", - "mint": "CRSzWoeyfR8sJxB2d6LLEre92Uc59TCPX2gZidp4t3eE", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CRSzWoeyfR8sJxB2d6LLEre92Uc59TCPX2gZidp4t3eE.png" - }, - { - "symbol": "DANG", - "name": "DANG", - "mint": "CSQn7G3SmbBVFRMvNH5SJV5sd2HipWSCphfDVcXwY3K6", - "decimals": 5, - "extensions": {}, - "icon": "" - }, - { - "symbol": "SXS", - "name": "SoldierXSolvivor Coin", - "mint": "Ct7mbdwLmdFC6zgVRXFidvvgYbtGo2icsntNSSgzxoLs", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Ct7mbdwLmdFC6zgVRXFidvvgYbtGo2icsntNSSgzxoLs.png" - }, - { - "symbol": "SOLPUNKS", - "name": "SolPunks Index", - "mint": "CT81fJ8ReVt3aNPqZr3xZvgJ7jjEfrzaXh3condAXHXP", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CT81fJ8ReVt3aNPqZr3xZvgJ7jjEfrzaXh3condAXHXP.png" - }, - { - "symbol": "FLWRS", - "name": "FLWRS Token", - "mint": "CUvVMqXAcyFJnwMhojQ9jmGuWrijGt26HfY7b99dyBeB", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CUvVMqXAcyFJnwMhojQ9jmGuWrijGt26HfY7b99dyBeB.png" - }, - { - "symbol": "CoW", - "name": "Culture of Women Token", - "mint": "CVj6FV4HmhEsn7xQXCjj5iqbDQHB7hQ8AwZjB6P8UMDu", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CVj6FV4HmhEsn7xQXCjj5iqbDQHB7hQ8AwZjB6P8UMDu.png" - }, - { - "symbol": "WWV", - "name": "Wild West Verse Token", - "mint": "CvzmN4HEMt2R9tsLyCV26yV2sT5tgD6nAHd7TNtWvHXq", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CvzmN4HEMt2R9tsLyCV26yV2sT5tgD6nAHd7TNtWvHXq.png" - }, - { - "symbol": "ETHBULL", - "name": "ETHBULL", - "mint": "CwChm6p9Q3yFrjzVeiLTTbsoJkooscof5SJYZc2CrNqG", - "decimals": 6, - "extensions": {}, - "icon": "" - }, - { - "symbol": "CBR", - "name": "Community Beer Run Token", - "mint": "CWhr7vJ1rCSgSMCcwMxdLVWdCf4KkSjZEeSmmh1poVXb", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CWhr7vJ1rCSgSMCcwMxdLVWdCf4KkSjZEeSmmh1poVXb.png" - }, - { - "symbol": "VDEF", - "name": "V-Defi Token", - "mint": "Cwiv21vbFdwJRtGomuCDyWz2w6xvPwoUqTmuyrFtU4Sa", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Cwiv21vbFdwJRtGomuCDyWz2w6xvPwoUqTmuyrFtU4Sa.png" - }, - { - "symbol": "GIF", - "name": "Giraffe", - "mint": "CWUUV3ym4Uphw4CVgkpNxrR7FsttF7h7mLggEUJ1J1aV", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CWUUV3ym4Uphw4CVgkpNxrR7FsttF7h7mLggEUJ1J1aV.png" - }, - { - "symbol": "STAR", - "name": "Starry Insiders", - "mint": "Cx7Rswv6MNyaBk354BohVvBP6mCPFo7FDjTwCYDXkajG", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Cx7Rswv6MNyaBk354BohVvBP6mCPFo7FDjTwCYDXkajG.png" - }, - { - "symbol": "NFD", - "name": "Feisty Doge NFT", - "mint": "CY2E69dSG9vBsMoaXDvYmMDSMEP4SZtRY1rqVQ9tkNDu", - "decimals": 8, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CY2E69dSG9vBsMoaXDvYmMDSMEP4SZtRY1rqVQ9tkNDu.png" - }, - { - "symbol": "FUEL", - "name": "Biker", - "mint": "CYbLZDG7TexKi2axdh4gQGLV3FnXvBgfJgLtixhKVytZ", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CYbLZDG7TexKi2axdh4gQGLV3FnXvBgfJgLtixhKVytZ.png" - }, - { - "symbol": "DIVX", - "name": "Dividex", - "mint": "CYbXZ7U1AeV8kjtJG3YqKMLaWtdMLa24JojrikZZdXAG", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CYbXZ7U1AeV8kjtJG3YqKMLaWtdMLa24JojrikZZdXAG.png" - }, - { - "symbol": "DRIP", - "name": "DripCoin", - "mint": "CYqZ4FG2Jb5Z1CWgdojej9Svhvvo8ohKEAuDvzG3iQ3N", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CYqZ4FG2Jb5Z1CWgdojej9Svhvvo8ohKEAuDvzG3iQ3N.png" - }, - { - "symbol": "SaSN", - "name": "SaSN Coin", - "mint": "CyWGk1hWVQsGmDt3Na5MyNcWaEDh6MSkTCvAdA5h1Ke8", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CyWGk1hWVQsGmDt3Na5MyNcWaEDh6MSkTCvAdA5h1Ke8.png" - }, - { - "symbol": "SNK", - "name": "SolSnake", - "mint": "CZKnYioKuX2YzA2wnUMVXsSe3j259aaPsz7TfY2xnLmV", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CZKnYioKuX2YzA2wnUMVXsSe3j259aaPsz7TfY2xnLmV.png" - }, - { - "symbol": "ACN", - "name": "Acorn", - "mint": "CZtYQvMEQdtFFdF39PtMxGVMditE76AwbXqJYFEhYFvA", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CZtYQvMEQdtFFdF39PtMxGVMditE76AwbXqJYFEhYFvA.png" - }, - { - "symbol": "DRGNZ", - "name": "Boryoku Genesis Dragonz Index", - "mint": "CzXF8oUJSsB9ADKV99WAi2TgytqAyKvQw6EihwiL9em4", - "decimals": 2, - "extensions": { "coingeckoId": "boryoku-genesis-dragonz-index" }, - "icon": "https://img.raydium.io/icon/CzXF8oUJSsB9ADKV99WAi2TgytqAyKvQw6EihwiL9em4.png" - }, - { - "symbol": "UMF", - "name": "UMF", - "mint": "CZY2dDTb86ARthiLP47hpmEgX1h82XCEr51XWQ5GsZoj", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/CZY2dDTb86ARthiLP47hpmEgX1h82XCEr51XWQ5GsZoj.png" - }, - { - "symbol": "THECA", - "name": "Theca", - "mint": "D3cm6WRnyBct3p7vFqyTt2CaynsGPuVQT2zW6WHSTX6q", - "decimals": 6, - "extensions": { "coingeckoId": "theca" }, - "icon": "https://img.raydium.io/icon/D3cm6WRnyBct3p7vFqyTt2CaynsGPuVQT2zW6WHSTX6q.png" - }, - { - "symbol": "BONE", - "name": "BONE", - "mint": "D3eyBjfgJMPHZyYDRtbf1cSxeLiNwKumwHzQK3h3TRRq", - "decimals": 6, - "extensions": { "coingeckoId": "bulldog-billionaires" }, - "icon": "https://img.raydium.io/icon/D3eyBjfgJMPHZyYDRtbf1cSxeLiNwKumwHzQK3h3TRRq.png" - }, - { - "symbol": "$KAIDO", - "name": "Kaidos Token", - "mint": "D5YJf7nqSp9JtQpMcZCthdEpMghK2gKmkLMLi2RhKSJt", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/D5YJf7nqSp9JtQpMcZCthdEpMghK2gKmkLMLi2RhKSJt.png" - }, - { - "symbol": "FUDAI", - "name": "FUDAI Token", - "mint": "D6xt2imesfZ1zL57o72BBzjaDs91Q72kgoSGC6qpXY9T", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/D6xt2imesfZ1zL57o72BBzjaDs91Q72kgoSGC6qpXY9T.png" - }, - { - "symbol": "OOAH", - "name": "OOAH Monkey", - "mint": "D8Fc2HLd9L9V2mJnEUpnys6muJUawKYFnJWcUiaGKnyP", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/D8Fc2HLd9L9V2mJnEUpnys6muJUawKYFnJWcUiaGKnyP.png" - }, - { - "symbol": "MCS", - "name": "Million Coin Solana", - "mint": "DAZbw2FG5PCssV24SsP1E3m1whDn8paXZMwBdfVHRt5w", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DAZbw2FG5PCssV24SsP1E3m1whDn8paXZMwBdfVHRt5w.png" - }, - { - "symbol": "GMP", - "name": "Gamerpull", - "mint": "DbRA7Jp8p3tztoPWrDQeJqpKLKXJpotUzJoeiiCdxewz", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DbRA7Jp8p3tztoPWrDQeJqpKLKXJpotUzJoeiiCdxewz.png" - }, - { - "symbol": "HKDD", - "name": "DEFINIS", - "mint": "DCg5GuAyxRwtM2VcSAJbgHesi1XqSqV1FAtV6T3VatcR", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DCg5GuAyxRwtM2VcSAJbgHesi1XqSqV1FAtV6T3VatcR.png" - }, - { - "symbol": "BOOGI", - "name": "BABY OOGI", - "mint": "DcvJP16Cw5oqTbtHmpJ4JGXaqBvV5m6eMZj5rGsFLpwU", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DcvJP16Cw5oqTbtHmpJ4JGXaqBvV5m6eMZj5rGsFLpwU.png" - }, - { - "symbol": "FLUFF", - "name": "SolSamos", - "mint": "Dd7pji6EruuFPuAxuZG5LwZUdPSzYCTN6NsttrkHeedS", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Dd7pji6EruuFPuAxuZG5LwZUdPSzYCTN6NsttrkHeedS.png" - }, - { - "symbol": "DELFI", - "name": "DeltaFi Token", - "mint": "de1QJkP1qDCk5JYCCXCeq27bQQUdCaiv7xVKFrhPSzF", - "decimals": 6, - "extensions": { "coingeckoId": "deltafi" }, - "icon": "https://img.raydium.io/icon/de1QJkP1qDCk5JYCCXCeq27bQQUdCaiv7xVKFrhPSzF.png" - }, - { - "symbol": "$DOGEVR", - "name": "Doge Very Rocket", - "mint": "DF4tgv1gDDdciLZe3HvhuVm8LL9ZqvZxiZ5mUzMg6eSs", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DF4tgv1gDDdciLZe3HvhuVm8LL9ZqvZxiZ5mUzMg6eSs.png" - }, - { - "symbol": "ERRA", - "name": "Erra", - "mint": "DfB1NY8Ftv3rDTnyffSVj5sr3ycFjLoUeNBEkTDvPQYn", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DfB1NY8Ftv3rDTnyffSVj5sr3ycFjLoUeNBEkTDvPQYn.png" - }, - { - "symbol": "CARTEL", - "name": "Cartoon Cartel Token", - "mint": "DfgYfvfW8cWumofEgRZsAYHhZVDgQbu9z8sGwcKahSho", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DfgYfvfW8cWumofEgRZsAYHhZVDgQbu9z8sGwcKahSho.png" - }, - { - "symbol": "soCEL", - "name": "Wrapped Celsius (Sollet)", - "mint": "DgHK9mfhMtUwwv54GChRrU54T2Em5cuszq2uMuen1ZVE", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DgHK9mfhMtUwwv54GChRrU54T2Em5cuszq2uMuen1ZVE.png" - }, - { - "symbol": "WAM", - "name": "WAM Token", - "mint": "Dh2WZdzcpoGuYgwbRUqt9feBwNiwkE6yg38zNSuV3Kmv", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Dh2WZdzcpoGuYgwbRUqt9feBwNiwkE6yg38zNSuV3Kmv.png" - }, - { - "symbol": "SOLAB", - "name": "SOLAB Finance", - "mint": "DH5KjPM53i7NMj69CEZ6FiF82ipbgz1U6QzNfQNY87Pr", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "BAMB", - "name": "BAMB", - "mint": "DHbGBhZc1yLLgpPqAzr7KGs47oCMfbg2q6Fmg5NCSM1C", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DHbGBhZc1yLLgpPqAzr7KGs47oCMfbg2q6Fmg5NCSM1C.png" - }, - { - "symbol": "TIPZ", - "name": "Tipzcoin", - "mint": "DhfF81uahANRYQ4rn8VZKSGVmLE4k2nzccgfZMazmLJ2", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DhfF81uahANRYQ4rn8VZKSGVmLE4k2nzccgfZMazmLJ2.png" - }, - { - "symbol": "SHIBA", - "name": "Shibalana", - "mint": "Dhg9XnzJWzSQqH2aAnhPTEJHGQAkALDfD98MA499A7pa", - "decimals": 9, - "extensions": { "coingeckoId": "shibalana" }, - "icon": "https://img.raydium.io/icon/Dhg9XnzJWzSQqH2aAnhPTEJHGQAkALDfD98MA499A7pa.png" - }, - { - "symbol": "PERTEL", - "name": "Cets Pertel", - "mint": "Dhtv79Gax1gwvWNQCKFW4oUCsMLcmUbsZ6vdaCFYP2Ko", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Dhtv79Gax1gwvWNQCKFW4oUCsMLcmUbsZ6vdaCFYP2Ko.png" - }, - { - "symbol": "CHP", - "name": "Crypto Health Plus", - "mint": "DHVUoxNqv3D7EgktBxUsxFF2Wx83hVDmD2wBBpUaw3jn", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DHVUoxNqv3D7EgktBxUsxFF2Wx83hVDmD2wBBpUaw3jn.png" - }, - { - "symbol": "TQE", - "name": "TRI NETWORK COIN", - "mint": "DHxMYFZ6hZYtX4LXLkSHRN2UHFFezE5X6GkRCQNW1un9", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DHxMYFZ6hZYtX4LXLkSHRN2UHFFezE5X6GkRCQNW1un9.png" - }, - { - "symbol": "MEK", - "name": "MEK", - "mint": "DhYTJPmUa5kQZfLgHb1soubgaK4VLZMxb8CTNY1vZ93S", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DhYTJPmUa5kQZfLgHb1soubgaK4VLZMxb8CTNY1vZ93S.png" - }, - { - "symbol": "$DIGI", - "name": "Digi Coin", - "mint": "Digi7SnUD9ddiitEqkNfby1c4BfkgokFKWu9KScbizes", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Digi7SnUD9ddiitEqkNfby1c4BfkgokFKWu9KScbizes.png" - }, - { - "symbol": "SolBullDog", - "name": "SolanaBullDog", - "mint": "DiJWJ6hgV7Vm5JP6SU7xvo7nULR14UvrGoWmSu34fEvZ", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DiJWJ6hgV7Vm5JP6SU7xvo7nULR14UvrGoWmSu34fEvZ.png" - }, - { - "symbol": "GMORNN", - "name": "gmornn", - "mint": "DiWunPY8GfsFthdDAwiRRtCgKCB5AEcFx9edDpxZoTyo", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DiWunPY8GfsFthdDAwiRRtCgKCB5AEcFx9edDpxZoTyo.png" - }, - { - "symbol": "BOOT", - "name": "Bootstrap DAO", - "mint": "Dj7qHPhVGa4JTMETZwbrTY1hdfe4TVbk2b46mFpKqb6H", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Dj7qHPhVGa4JTMETZwbrTY1hdfe4TVbk2b46mFpKqb6H.png" - }, - { - "symbol": "soHXRO", - "name": "Wrapped HXRO (Sollet)", - "mint": "DJafV9qemGp7mLMEn5wrfqaFwxsbLgUsGVS16zKRk9kc", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DJafV9qemGp7mLMEn5wrfqaFwxsbLgUsGVS16zKRk9kc.png" - }, - { - "symbol": "AUSS", - "name": "Ausshole", - "mint": "Djoz8btdR7p6xWHoVtPYF3zyN9LU5BBfMoDk4HczSDqc", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Djoz8btdR7p6xWHoVtPYF3zyN9LU5BBfMoDk4HczSDqc.png" - }, - { - "symbol": "BITXBIT", - "name": "BITXBIT", - "mint": "DK6PWMyuZ4NMjsm9AWNCTMKrajQYrtfMjMJ3QauX2UH5", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DK6PWMyuZ4NMjsm9AWNCTMKrajQYrtfMjMJ3QauX2UH5.png" - }, - { - "symbol": "BRZL", - "name": "Brezel", - "mint": "DkGCSjkUHKDPM1hjcMM8dGNDPnf5nrQU8fvsqvQkVixx", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DkGCSjkUHKDPM1hjcMM8dGNDPnf5nrQU8fvsqvQkVixx.png" - }, - { - "symbol": "SOLBEAR", - "name": "Solar Bear", - "mint": "DktNJUJAWJyeLw3ykCkFNpGohE24SoEhevKBskRi6P1y", - "decimals": 9, - "extensions": { "coingeckoId": "solar-bear" }, - "icon": "https://img.raydium.io/icon/DktNJUJAWJyeLw3ykCkFNpGohE24SoEhevKBskRi6P1y.png" - }, - { - "symbol": "KAKA", - "name": "KAKA", - "mint": "DM8WStrzE7XHLr5EeuE8693VAqAx3MiTcAqfH6WcsSSC", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DM8WStrzE7XHLr5EeuE8693VAqAx3MiTcAqfH6WcsSSC.png" - }, - { - "symbol": "WEENS", - "name": "Ween", - "mint": "DmXfDUeyRJqnpvdjssGgUXwZrRFPXvu2DfMq4jfTTC9C", - "decimals": 0, - "extensions": { "coingeckoId": "ween-token" }, - "icon": "https://img.raydium.io/icon/DmXfDUeyRJqnpvdjssGgUXwZrRFPXvu2DfMq4jfTTC9C.png" - }, - { - "symbol": "FIN", - "name": "FIN COIN", - "mint": "DnYLfTsnLMYVdDhnZuzekdGf8AMQ3crDR2qRfpHRe47i", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DnYLfTsnLMYVdDhnZuzekdGf8AMQ3crDR2qRfpHRe47i.png" - }, - { - "symbol": "HALO", - "name": "HALO", - "mint": "Do5AbqdEbj742B2Cm8BypAGg3h1skLaAVTbT2mLRcW8c", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Do5AbqdEbj742B2Cm8BypAGg3h1skLaAVTbT2mLRcW8c.png" - }, - { - "symbol": "DLANA", - "name": "Dogelana Token", - "mint": "DogeLZECE9CthXasBLFxgeA2umEyt8CcV7Jsf6P5ZTFo", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DogeLZECE9CthXasBLFxgeA2umEyt8CcV7Jsf6P5ZTFo.png" - }, - { - "symbol": "DSC", - "name": "DoggyStyle Coin", - "mint": "DogscQVvNVj7ndEnhWiCXPVPKKwNy9fJd4ATF7mVi5J", - "decimals": 9, - "extensions": { "coingeckoId": "doggystyle-coin" }, - "icon": "https://img.raydium.io/icon/DogscQVvNVj7ndEnhWiCXPVPKKwNy9fJd4ATF7mVi5J.png" - }, - { - "symbol": "AUX", - "name": "AUX Coin", - "mint": "Dphg7WWPYPKMtVyxBJpjwP2sG8HBkG4mm89kX1jgKA2L", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Dphg7WWPYPKMtVyxBJpjwP2sG8HBkG4mm89kX1jgKA2L.png" - }, - { - "symbol": "DOPIES", - "name": "DOPE", - "mint": "DPuGqV7jq9PEbcRU7bWzuaJx5bGiaVj4cNWhWjTdWAKi", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DPuGqV7jq9PEbcRU7bWzuaJx5bGiaVj4cNWhWjTdWAKi.png" - }, - { - "symbol": "ROAR", - "name": "Roar Token", - "mint": "DqxzPWQ2FKHn8pRoy9jCpA6M3GkEqYfieiAVwMYWVyXr", - "decimals": 9, - "extensions": { "coingeckoId": "roar-token" }, - "icon": "https://img.raydium.io/icon/DqxzPWQ2FKHn8pRoy9jCpA6M3GkEqYfieiAVwMYWVyXr.png" - }, - { - "symbol": "BLD", - "name": "BladesToken", - "mint": "DrcPRJPBiakQcWqon3gZms7sviAqdQS5zS5wvaG5v6wu", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DrcPRJPBiakQcWqon3gZms7sviAqdQS5zS5wvaG5v6wu.png" - }, - { - "symbol": "DRG", - "name": "Drogo", - "mint": "DrogoV6nuMsCGfhqcVMCVxGZASajgXoxN7ytUcRCQgQs", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DrogoV6nuMsCGfhqcVMCVxGZASajgXoxN7ytUcRCQgQs.png" - }, - { - "symbol": "MAGIC", - "name": "ShinLim", - "mint": "DsNADnfdnbCyuxE2mWxVu3GmAAiqVfaw9xgMMfFGRG5r", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DsNADnfdnbCyuxE2mWxVu3GmAAiqVfaw9xgMMfFGRG5r.png" - }, - { - "symbol": "$NEON", - "name": "NeonGame Credits", - "mint": "DuSyBCGuhPvyGu6cSvbZonvQvh8JLyGvXJn1TmkJh6Zn", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DuSyBCGuhPvyGu6cSvbZonvQvh8JLyGvXJn1TmkJh6Zn.png" - }, - { - "symbol": "HEXAGON", - "name": "Hexagon Protocol", - "mint": "DVhia9KmzYCP1URf4s8DrPsE46A5PuT5TPyVRgr4c895", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DVhia9KmzYCP1URf4s8DrPsE46A5PuT5TPyVRgr4c895.png" - }, - { - "symbol": "GOATS", - "name": "GOATS", - "mint": "DVPWKGLFHK73PwgKgTtW28iCZGewQdva2N5HeBLDorVJ", - "decimals": 4, - "extensions": { "coingeckoId": "goats" }, - "icon": "https://img.raydium.io/icon/DVPWKGLFHK73PwgKgTtW28iCZGewQdva2N5HeBLDorVJ.png" - }, - { - "symbol": "USAM", - "name": "UncleSam", - "mint": "DXq8js1uxGNENn97SdtBhRDQ2TMETDxHsRabJPjVh2Q4", - "decimals": 8, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DXq8js1uxGNENn97SdtBhRDQ2TMETDxHsRabJPjVh2Q4.png" - }, - { - "symbol": "MARIJUANA", - "name": "Marijuana Joint", - "mint": "DYbRXaQcnj44SH9woxvyFdtcKkSoPoCEshRTQDZSjsBm", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DYbRXaQcnj44SH9woxvyFdtcKkSoPoCEshRTQDZSjsBm.png" - }, - { - "symbol": "SOLJAV", - "name": "SOLJAV", - "mint": "Dypr2gWcVuqt3z6Uh31YD8Wm2V2ZCqWVBYEWhZNF9odk", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Dypr2gWcVuqt3z6Uh31YD8Wm2V2ZCqWVBYEWhZNF9odk.png" - }, - { - "symbol": "BOX", - "name": "Solootbox DAO", - "mint": "DysbQiM8nPdZbBhvHM1EgcSE73EwtFWDanXwY8CDD3Jn", - "decimals": 9, - "extensions": { "coingeckoId": "solootbox-dao" }, - "icon": "https://img.raydium.io/icon/DysbQiM8nPdZbBhvHM1EgcSE73EwtFWDanXwY8CDD3Jn.png" - }, - { - "symbol": "ORCT", - "name": "ORCT", - "mint": "DZmSAzjGJQPHMc1cLL1fg2YND4F4DQm75yixQTChM47h", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/DZmSAzjGJQPHMc1cLL1fg2YND4F4DQm75yixQTChM47h.png" - }, - { - "symbol": "DALM", - "name": "Dalmatian Coin", - "mint": "E1CRrNYTykhsJLUEkDEzJJexzCaoJ18fVSfvrHqRYecw", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/E1CRrNYTykhsJLUEkDEzJJexzCaoJ18fVSfvrHqRYecw.png" - }, - { - "symbol": "INO", - "name": "NoGoalToken", - "mint": "E1PvPRPQvZNivZbXRL61AEGr71npZQ5JGxh4aWX7q9QA", - "decimals": 9, - "extensions": { "coingeckoId": "nogoaltoken" }, - "icon": "https://img.raydium.io/icon/E1PvPRPQvZNivZbXRL61AEGr71npZQ5JGxh4aWX7q9QA.png" - }, - { - "symbol": "CAC", - "name": "Cosmic Ape Coin", - "mint": "E1s2muWwiLT2n3EQUL27hgviaPRRXWkpXD7ShpfgRvVz", - "decimals": 6, - "extensions": { "coingeckoId": "cosmic-ape-coin" }, - "icon": "https://img.raydium.io/icon/E1s2muWwiLT2n3EQUL27hgviaPRRXWkpXD7ShpfgRvVz.png" - }, - { - "symbol": "Met4", - "name": "Meta 4", - "mint": "E1vVoJmfr3Jyvwd8iFB7F1u9uwAeFNqkNxfzybHNyHuD", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/E1vVoJmfr3Jyvwd8iFB7F1u9uwAeFNqkNxfzybHNyHuD.png" - }, - { - "symbol": "GOLD", - "name": "SolGold", - "mint": "E1zxRweqCWzviAraKjNjqupuyYTzm1bukJgb8KiBN1sN", - "decimals": 5, - "extensions": {}, - "icon": "" - }, - { - "symbol": "MCK", - "name": "Mickey", - "mint": "E48Ueg1o9avL5s7XBjfLViercSrNSJCvmbZMvnwN873", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/E48Ueg1o9avL5s7XBjfLViercSrNSJCvmbZMvnwN873.png" - }, - { - "symbol": "ORCSFI", - "name": "The Orcs Floor Index", - "mint": "E4oEnayacCpyKLQQeRqSm8bG5wPqDMZuun6fEXgoLNwF", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/E4oEnayacCpyKLQQeRqSm8bG5wPqDMZuun6fEXgoLNwF.png" - }, - { - "symbol": "WADA", - "name": "Wada", - "mint": "E5qNsCX91wqnLQQ25yEHTo3eujWGtqLe9daJvejRxikc", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/E5qNsCX91wqnLQQ25yEHTo3eujWGtqLe9daJvejRxikc.png" - }, - { - "symbol": "ENVIRO", - "name": "Enviro Floor Index", - "mint": "E5UNCyiF1xrCqKozyFuiBkYH678BhftBo8Q1GreukBq3", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/E5UNCyiF1xrCqKozyFuiBkYH678BhftBo8Q1GreukBq3.png" - }, - { - "symbol": "AIR", - "name": "Balloonsville AIR", - "mint": "E6eCEE3KqjRD5UxcBYQTdV8Z535hyaBuFin9Udm6s6bz", - "decimals": 9, - "extensions": { "coingeckoId": "balloonsville-air" }, - "icon": "https://img.raydium.io/icon/E6eCEE3KqjRD5UxcBYQTdV8Z535hyaBuFin9Udm6s6bz.png" - }, - { - "symbol": "DICK", - "name": "Dickcoin", - "mint": "E6Hkw5o48QfNo6iUi1aepjEBzVq4ZjQLxh7xVtdTqoyB", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/E6Hkw5o48QfNo6iUi1aepjEBzVq4ZjQLxh7xVtdTqoyB.png" - }, - { - "symbol": "PLAYA", - "name": "Playground", - "mint": "E6oCGvmSYW7qhy7oeDfiNZLX6hEmPCVxBC8AknwAj82B", - "decimals": 2, - "extensions": { "coingeckoId": "playground" }, - "icon": "https://img.raydium.io/icon/E6oCGvmSYW7qhy7oeDfiNZLX6hEmPCVxBC8AknwAj82B.png" - }, - { - "symbol": "DGLN", - "name": "Dogelana", - "mint": "E6UU5M1z4CvSAAF99d9wRoXsasWMEXsvHrz3JQRXtm2X", - "decimals": 9, - "extensions": { "coingeckoId": "dogelana" }, - "icon": "https://img.raydium.io/icon/E6UU5M1z4CvSAAF99d9wRoXsasWMEXsvHrz3JQRXtm2X.png" - }, - { - "symbol": "BLEND", - "name": "blendhit", - "mint": "E7QfCszwdutZovb8rYAPUfj338M3C4szZPPY8RceTiXm", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/E7QfCszwdutZovb8rYAPUfj338M3C4szZPPY8RceTiXm.png" - }, - { - "symbol": "PPUG", - "name": "PizzaPugCoin", - "mint": "E7WqtfRHcY8YW8z65u9WmD7CfMmvtrm2qPVicSzDxLaT", - "decimals": 9, - "extensions": { "coingeckoId": "pizza-pug-coin" }, - "icon": "https://img.raydium.io/icon/E7WqtfRHcY8YW8z65u9WmD7CfMmvtrm2qPVicSzDxLaT.png" - }, - { - "symbol": "BIBLE", - "name": "THE HOLY BIBLE", - "mint": "E8bT8g4so2zPnEoragg1wLCz29VXddqjf1acoG5YwTJA", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/E8bT8g4so2zPnEoragg1wLCz29VXddqjf1acoG5YwTJA.png" - }, - { - "symbol": "WNDO", - "name": "WNDO", - "mint": "E8G4uo2i9d12aGnXDHXXcw6hU2fh2NytR5XR3qurTLBx", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/E8G4uo2i9d12aGnXDHXXcw6hU2fh2NytR5XR3qurTLBx.png" - }, - { - "symbol": "CCC", - "name": "Chairman Chow", - "mint": "E9bjYSAqabYAd2Zaev4qAMVNAiX7Z2Dp4Sn1JgsTn2b6", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/E9bjYSAqabYAd2Zaev4qAMVNAiX7Z2Dp4Sn1JgsTn2b6.png" - }, - { - "symbol": "DECI", - "name": "Decimus Token", - "mint": "EAzCTpMGRjFmGf4MaiMVNqv6KxQNoM6HEXtPZLEtEivB", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/EAzCTpMGRjFmGf4MaiMVNqv6KxQNoM6HEXtPZLEtEivB.png" - }, - { - "symbol": "PERP", - "name": "PerpeTraders", - "mint": "EBQ6gWBQNxA2zB4twR5GWP6CkeAhqZZZeDgeP7BTtdM3", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/EBQ6gWBQNxA2zB4twR5GWP6CkeAhqZZZeDgeP7BTtdM3.png" - }, - { - "symbol": "NOCH", - "name": "NodeBunch", - "mint": "EcFyPDjqpnyMvh1LhACtC6rrCZ41DMez7RZYocjhmUVS", - "decimals": 6, - "extensions": { "coingeckoId": "nodebunch" }, - "icon": "https://img.raydium.io/icon/EcFyPDjqpnyMvh1LhACtC6rrCZ41DMez7RZYocjhmUVS.png" - }, - { - "symbol": "BZT", - "name": "bZt by Electons", - "mint": "ECPAzxsa4VBALQ4kh4i9mtUdRTBRhGwrzu7Y2YqwZjsi", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/ECPAzxsa4VBALQ4kh4i9mtUdRTBRhGwrzu7Y2YqwZjsi.png" - }, - { - "symbol": "SANTA", - "name": "Santaclaus", - "mint": "EctmRn2jMAdTDvQdG7mxadyiTvhGZiGYNrt9PWe6zioG", - "decimals": 9, - "extensions": { "coingeckoId": "santaclaus" }, - "icon": "https://img.raydium.io/icon/EctmRn2jMAdTDvQdG7mxadyiTvhGZiGYNrt9PWe6zioG.png" - }, - { - "symbol": "$SAKE", - "name": "SAKE", - "mint": "Ed1934BYVPQQ2KXbzCLxBMtNVZN3SjanTewfR9upbb7L", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Ed1934BYVPQQ2KXbzCLxBMtNVZN3SjanTewfR9upbb7L.png" - }, - { - "symbol": "AMMO", - "name": "Ammo", - "mint": "EEhosSQvC2yVDRXRGpkonGFF2WNjtUdzb48GV8TSmhfA", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/EEhosSQvC2yVDRXRGpkonGFF2WNjtUdzb48GV8TSmhfA.png" - }, - { - "symbol": "SPKL", - "name": "Spookeletons Token", - "mint": "EFYKDdppK1FjixaxExpVhoTd8gtAmncbhQYruzWyG6Cx", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "OTAKU", - "name": "OTAKU Coin", - "mint": "EG9JDbEiCFpQ8a9LCi8AXskKvqZy757n3yFCnBvLrZRd", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/EG9JDbEiCFpQ8a9LCi8AXskKvqZy757n3yFCnBvLrZRd.png" - }, - { - "symbol": "BIT", - "name": "BIT Token", - "mint": "EGiWZhNk3vUNJr35MbL2tY5YD6D81VVZghR2LgEFyXZh", - "decimals": 9, - "extensions": { "coingeckoId": "bitmon" }, - "icon": "https://img.raydium.io/icon/EGiWZhNk3vUNJr35MbL2tY5YD6D81VVZghR2LgEFyXZh.png" - }, - { - "symbol": "RAC", - "name": "Rainc", - "mint": "EH49ziLeKhJtzUzdys5238pSKpvrgJvmi3EStrZ9QaY7", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/EH49ziLeKhJtzUzdys5238pSKpvrgJvmi3EStrZ9QaY7.png" - }, - { - "symbol": "$SKULL", - "name": "Skull Invasion", - "mint": "EHinbFyVA4VckqJ54wxFXHWLxCCYCKxy62oVtRDTCoRD", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/EHinbFyVA4VckqJ54wxFXHWLxCCYCKxy62oVtRDTCoRD.png" - }, - { - "symbol": "ROYALE", - "name": "Royale token", - "mint": "EiNEYyUcPHpGt2btoMeuTrLtsAeayY74ECvPRYzcdPpo", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/EiNEYyUcPHpGt2btoMeuTrLtsAeayY74ECvPRYzcdPpo.png" - }, - { - "symbol": "BSAMO", - "name": "BabySamo", - "mint": "EjaC7vKgimdVMyaF7SkNNaY2D8PDRVfAwThuAoeVvE7V", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/EjaC7vKgimdVMyaF7SkNNaY2D8PDRVfAwThuAoeVvE7V.png" - }, - { - "symbol": "KZN", - "name": "Kartazion", - "mint": "EjSwAfwi4F6uYtoi2WuCSYSWPVUPJCdemmShZ9tdy65P", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/EjSwAfwi4F6uYtoi2WuCSYSWPVUPJCdemmShZ9tdy65P.png" - }, - { - "symbol": "DRAY", - "name": "Draygon Investment", - "mint": "EK1rBdnucX4yf8JDCFQEC7rTejXEUqsjazDxHZaHSKT7", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/EK1rBdnucX4yf8JDCFQEC7rTejXEUqsjazDxHZaHSKT7.png" - }, - { - "symbol": "DAVE", - "name": "DAVE COIN", - "mint": "Ek1wxugWrFimo8NExqzYaGDnikEibuUrkEaWEs3z2aTU", - "decimals": 6, - "extensions": {}, - "icon": "" - }, - { - "symbol": "LIONESS", - "name": "Jungle Cats Lioness Index", - "mint": "EK6j5Shv99xttoT3F2DfG8uQMoX6NoAZgTuYwCvrHzqo", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/EK6j5Shv99xttoT3F2DfG8uQMoX6NoAZgTuYwCvrHzqo.png" - }, - { - "symbol": "SOB", - "name": "SolaLambo", - "mint": "EkDf4Nt89x4Usnxkj4sGHX7sWxkmmpiBzA4qdDkgEN6b", - "decimals": 9, - "extensions": { "coingeckoId": "solalambo" }, - "icon": "" - }, - { - "symbol": "VIDI", - "name": "VIDI", - "mint": "ELADrKrvyv7mtQ5DbCvPDGogn4fcApH3jDeTy2qpfhsA", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/ELADrKrvyv7mtQ5DbCvPDGogn4fcApH3jDeTy2qpfhsA.png" - }, - { - "symbol": "wHEX_v1", - "name": "HEX (Wormhole v1)", - "mint": "ELSnGFd5XnSdYFFSgYQp7n89FEbDqxN4npuRLW4PPPLv", - "decimals": 8, - "extensions": {}, - "icon": "https://img.raydium.io/icon/ELSnGFd5XnSdYFFSgYQp7n89FEbDqxN4npuRLW4PPPLv.png" - }, - { - "symbol": "ELIXIR", - "name": "ELIXIR", - "mint": "ELXRYrf8wd4DcyXDU9QPnMdD8jn2twg7o7qEtf5z2GBW", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/ELXRYrf8wd4DcyXDU9QPnMdD8jn2twg7o7qEtf5z2GBW.png" - }, - { - "symbol": "DKZ", - "name": "DarkZed Coin", - "mint": "EmPxJRmDU9y3kh1XcrzDXYRUpHh875eSWKEA529eCGDN", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/EmPxJRmDU9y3kh1XcrzDXYRUpHh875eSWKEA529eCGDN.png" - }, - { - "symbol": "rPWNG", - "name": "Random Pawnshop Gnomies", - "mint": "EmvtEzATa3n766yxojGZJmpSzkTxsCdDSX2zgRMZEoaQ", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/EmvtEzATa3n766yxojGZJmpSzkTxsCdDSX2zgRMZEoaQ.png" - }, - { - "symbol": "TYLER", - "name": "Stock Tyler Floor Index", - "mint": "EmzYLb3fwhjNp726Na5zLdhgrZjyC8GrfNGyopq6731w", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/EmzYLb3fwhjNp726Na5zLdhgrZjyC8GrfNGyopq6731w.png" - }, - { - "symbol": "TURD", - "name": "Actual Shitcoin", - "mint": "EpnJLu5oc1UWG25jNvSzuezz1ENrxbDnLg1wQDC7Hfbw", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/EpnJLu5oc1UWG25jNvSzuezz1ENrxbDnLg1wQDC7Hfbw.png" - }, - { - "symbol": "SMU", - "name": "Solana Monkey University Token", - "mint": "Eqekt4QF8zy9X6MZn5JUa6YYAz5MMgo7ZV5ZyX7YtjJW", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Eqekt4QF8zy9X6MZn5JUa6YYAz5MMgo7ZV5ZyX7YtjJW.png" - }, - { - "symbol": "BTR", - "name": "BiTrust Token", - "mint": "ER7VS5oDqmPCALdxopj7583gzUC49cBuuNUxFrfc4uCd", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/ER7VS5oDqmPCALdxopj7583gzUC49cBuuNUxFrfc4uCd.png" - }, - { - "symbol": "MIT", - "name": "Muskimum Impact Token", - "mint": "ERPueLaiBW48uBhqX1CvCYBv2ApHN6ZFuME1MeQGTdAi", - "decimals": 8, - "extensions": {}, - "icon": "https://img.raydium.io/icon/ERPueLaiBW48uBhqX1CvCYBv2ApHN6ZFuME1MeQGTdAi.png" - }, - { - "symbol": "DALI", - "name": "Fraktionalized Blockasset Legend Ali", - "mint": "ESrrTHaNKiC9saxaudX2j9iCM9r8qHRcLSrW5ypQ3W64", - "decimals": 3, - "extensions": {}, - "icon": "https://img.raydium.io/icon/ESrrTHaNKiC9saxaudX2j9iCM9r8qHRcLSrW5ypQ3W64.png" - }, - { - "symbol": "PHY", - "name": "Physis", - "mint": "EswgBj2hZKdgovX2ihWSUDnuBg9VNbGmSGoH5yjNsPRa", - "decimals": 9, - "extensions": { "coingeckoId": "physis" }, - "icon": "https://img.raydium.io/icon/EswgBj2hZKdgovX2ihWSUDnuBg9VNbGmSGoH5yjNsPRa.png" - }, - { - "symbol": "GNOM", - "name": "GnomToken", - "mint": "Et3k45YA6ZMur4GcjuYJiiZSdnr78Jt2AhMbWs4cs3B", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Et3k45YA6ZMur4GcjuYJiiZSdnr78Jt2AhMbWs4cs3B.png" - }, - { - "symbol": "sTZC", - "name": "Trezarcoin", - "mint": "ETbxzGvuzVrCxVN7cNoT6QBEYwFLBwMUwSYX6pUdHyep", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/ETbxzGvuzVrCxVN7cNoT6QBEYwFLBwMUwSYX6pUdHyep.png" - }, - { - "symbol": "NPC", - "name": "NPC DAO", - "mint": "EuD5L5XSYKzyDC1YyYzmoWC8gmJhpEh2vMj4f8LeRW8r", - "decimals": 9, - "extensions": { "coingeckoId": "nole-npc" }, - "icon": "https://img.raydium.io/icon/EuD5L5XSYKzyDC1YyYzmoWC8gmJhpEh2vMj4f8LeRW8r.png" - }, - { - "symbol": "ULA", - "name": "Solana Mobile App UlaPay Token", - "mint": "EwHqbMUMX33JjWAhxSg9vsX3miWqncsgpnAbqn9nhJwZ", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/EwHqbMUMX33JjWAhxSg9vsX3miWqncsgpnAbqn9nhJwZ.png" - }, - { - "symbol": "$GOOD", - "name": "Commit Good", - "mint": "EWL2aMkx1j7XcjdKniVMKmuK7Vds3CgMXJv28HohVBUx", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/EWL2aMkx1j7XcjdKniVMKmuK7Vds3CgMXJv28HohVBUx.png" - }, - { - "symbol": "SOLBERRY", - "name": "SOLBERRY", - "mint": "EWS2ATMt5fQk89NWLJYNRmGaNoji8MhFZkUB4DiWCCcz", - "decimals": 6, - "extensions": { "coingeckoId": "solberry" }, - "icon": "https://img.raydium.io/icon/EWS2ATMt5fQk89NWLJYNRmGaNoji8MhFZkUB4DiWCCcz.png" - }, - { - "symbol": "CRE8R", - "name": "CRE8RCOIN", - "mint": "EXQgN2S5baFSqBR9XijnGvtunemdhhj2f9p4K9NW4Y9F", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/EXQgN2S5baFSqBR9XijnGvtunemdhhj2f9p4K9NW4Y9F.png" - }, - { - "symbol": "$MCREW", - "name": "MONKE CREW", - "mint": "Exz2u9EhSXzGDef4v8bfXVjcUbsFm4kMKoXxn58fDUSa", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Exz2u9EhSXzGDef4v8bfXVjcUbsFm4kMKoXxn58fDUSa.png" - }, - { - "symbol": "BST", - "name": "Balisari", - "mint": "EYDEQW4xQzLqHcFwHTgGvpdjsa5EFn74KzuqLX5emjD2", - "decimals": 9, - "extensions": { "coingeckoId": "balisari" }, - "icon": "https://img.raydium.io/icon/EYDEQW4xQzLqHcFwHTgGvpdjsa5EFn74KzuqLX5emjD2.png" - }, - { - "symbol": "FUM", - "name": "FUMoney", - "mint": "EZF2sPJRe26e8iyXaCrmEefrGVBkqqNGv9UPGG9EnTQz", - "decimals": 9, - "extensions": { "coingeckoId": "fumoney" }, - "icon": "https://img.raydium.io/icon/EZF2sPJRe26e8iyXaCrmEefrGVBkqqNGv9UPGG9EnTQz.png" - }, - { - "symbol": "CONDOMS", - "name": "Solana Condoms", - "mint": "EzL6LLmv4vgfF7irkjG7ZxM92bTJ9f6nFopDXJTow7zj", - "decimals": 9, - "extensions": { "coingeckoId": "solcondoms" }, - "icon": "https://img.raydium.io/icon/EzL6LLmv4vgfF7irkjG7ZxM92bTJ9f6nFopDXJTow7zj.png" - }, - { - "symbol": "MOONBURN", - "name": "MOONBURN", - "mint": "F14Cp89oAXMrNnaC4mKMNKHPWw2p2R4DRFAZEdJhUBkD", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/F14Cp89oAXMrNnaC4mKMNKHPWw2p2R4DRFAZEdJhUBkD.png" - }, - { - "symbol": "ENC", - "name": "crypt", - "mint": "F2CcdH4uXVL6vwutkFMtHWFaj87dYSh9WMWNqzsMmTUG", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/F2CcdH4uXVL6vwutkFMtHWFaj87dYSh9WMWNqzsMmTUG.png" - }, - { - "symbol": "BABYFLOKISOL", - "name": "Baby Floki Doge", - "mint": "F5f9hLQ6FNHwuU3dS8CUCRy9r2deJXYCinDL6RAxsPeX", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/F5f9hLQ6FNHwuU3dS8CUCRy9r2deJXYCinDL6RAxsPeX.png" - }, - { - "symbol": "INUGAMI", - "name": "INUGAMI Coin", - "mint": "F9tytWqLUAPXQTy6dejGtSgvJQZWYC71naD5bCi6caGX", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/F9tytWqLUAPXQTy6dejGtSgvJQZWYC71naD5bCi6caGX.png" - }, - { - "symbol": "QTC", - "name": "Quantum", - "mint": "FADvkbzT3JY1gFqQRoaMyipfy6GvpVhbVfn3q3om7ZVG", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FADvkbzT3JY1gFqQRoaMyipfy6GvpVhbVfn3q3om7ZVG.png" - }, - { - "symbol": "BULL", - "name": "theBULL Coin", - "mint": "FaiPGacTM7YBmacumbg4ZnDx7sKtGcG3LkcVoqfddEA7", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FaiPGacTM7YBmacumbg4ZnDx7sKtGcG3LkcVoqfddEA7.png" - }, - { - "symbol": "BMT", - "name": "BMT", - "mint": "FanJWA4yEVUJj1r83tR7XybxmDGF6bNH8M81ag9aeUbF", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FanJWA4yEVUJj1r83tR7XybxmDGF6bNH8M81ag9aeUbF.png" - }, - { - "symbol": "MKD", - "name": "Musk Doge", - "mint": "FatneQg39zhrG6XdwYb8fzM4VgybpgqjisJYESSBD7FV", - "decimals": 9, - "extensions": { "coingeckoId": "musk-doge" }, - "icon": "https://img.raydium.io/icon/FatneQg39zhrG6XdwYb8fzM4VgybpgqjisJYESSBD7FV.png" - }, - { - "symbol": "TGT", - "name": "Twirl Governance Token", - "mint": "FciGvHj9FjgSGgCBF1b9HY814FM9D28NijDd5SJrKvPo", - "decimals": 6, - "extensions": { "coingeckoId": "twirl-governance-token" }, - "icon": "https://img.raydium.io/icon/FciGvHj9FjgSGgCBF1b9HY814FM9D28NijDd5SJrKvPo.png" - }, - { - "symbol": "TRKR", - "name": "TruckerCoin", - "mint": "FCRMFcfmZTY5qekzVYAmSRcxjSp4dMqSL8Gb3s2JkCAu", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FCRMFcfmZTY5qekzVYAmSRcxjSp4dMqSL8Gb3s2JkCAu.png" - }, - { - "symbol": "POOS", - "name": "Legend Of PooShi", - "mint": "FdDEakNRY4k3orJuBXUcm9VkcXd8YXVPjuG5WuRN2tWH", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FdDEakNRY4k3orJuBXUcm9VkcXd8YXVPjuG5WuRN2tWH.png" - }, - { - "symbol": "SK", - "name": "Silent Knight", - "mint": "FDiJY7TFSjggVru24NNy3mNHVRHXHyg8q2FeBKYQYYq2", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FDiJY7TFSjggVru24NNy3mNHVRHXHyg8q2FeBKYQYYq2.png" - }, - { - "symbol": "$YETI", - "name": "YETI", - "mint": "FDKBUXKxCdNQnDrqP7DLe8Kri3hzFRxcXyoskoPa74rk", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FDKBUXKxCdNQnDrqP7DLe8Kri3hzFRxcXyoskoPa74rk.png" - }, - { - "symbol": "FADE", - "name": "FADE", - "mint": "FDWmQxD9hQruYKtFK8wt6UhKGv6frPvU8EhjKiEPQoyD", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FDWmQxD9hQruYKtFK8wt6UhKGv6frPvU8EhjKiEPQoyD.png" - }, - { - "symbol": "ZUKI", - "name": "Zuki Token", - "mint": "FeEdorXhQh5jsr89XtD1s6txNkmXTPu9hhNpaYvPiQGJ", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FeEdorXhQh5jsr89XtD1s6txNkmXTPu9hhNpaYvPiQGJ.png" - }, - { - "symbol": "wCAPS_v1", - "name": "Wrapped Capsule Coin (Wormhole v1)", - "mint": "FeLoyXk8ac2AYVmDhAWEKNWWT63Z9TczeidYbpDvxF3T", - "decimals": 8, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FeLoyXk8ac2AYVmDhAWEKNWWT63Z9TczeidYbpDvxF3T.png" - }, - { - "symbol": "$RYO", - "name": "Shin Sengoku RYO", - "mint": "FeVooZDV8ihVhwuHVbagriw6rtonLdysXQ52VwqTaVAd", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FeVooZDV8ihVhwuHVbagriw6rtonLdysXQ52VwqTaVAd.png" - }, - { - "symbol": "VVV", - "name": "Vladimir-VS-Volodymyr", - "mint": "Fg3NLKzwfnhtiEjnbn86wcZiGckuL5bzf61JGSqFi4ot", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Fg3NLKzwfnhtiEjnbn86wcZiGckuL5bzf61JGSqFi4ot.png" - }, - { - "symbol": "SHIVER", - "name": "Shibaverse", - "mint": "FGMTuwmVVz9hUJzA8shYiEnM16wsYDoSmYoy13UZe1kk", - "decimals": 9, - "extensions": { "coingeckoId": "shibaverse-token" }, - "icon": "https://img.raydium.io/icon/FGMTuwmVVz9hUJzA8shYiEnM16wsYDoSmYoy13UZe1kk.png" - }, - { - "symbol": "VEGAS", - "name": "Vegas Token", - "mint": "FHeU7e7Tyw5bNcCNiM1jNVoT5UUims7zRi3o76Kdz4f6", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FHeU7e7Tyw5bNcCNiM1jNVoT5UUims7zRi3o76Kdz4f6.png" - }, - { - "symbol": "MM", - "name": "Million", - "mint": "FiCiuX9DetEE89PgRAU1hmoptnem8b1fkpEq8PGYTYkd", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FiCiuX9DetEE89PgRAU1hmoptnem8b1fkpEq8PGYTYkd.png" - }, - { - "symbol": "FIF", - "name": "Fifsee", - "mint": "FiFxBfTSqcz6vWRbp5TKbyhgfkXauSfHiRwxKqMcbuNA", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FiFxBfTSqcz6vWRbp5TKbyhgfkXauSfHiRwxKqMcbuNA.png" - }, - { - "symbol": "LEARN", - "name": "Solearna", - "mint": "Fj4js23EXVLoUQ26VPfmwVbt76XLn6souUGis71FvNmM", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Fj4js23EXVLoUQ26VPfmwVbt76XLn6souUGis71FvNmM.png" - }, - { - "symbol": "PANTHEON", - "name": "Olympus pantheon", - "mint": "FjMQibN74kDTDVwGhMjoPP9YjsrGdULwnCdxK5U6Hxxz", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FjMQibN74kDTDVwGhMjoPP9YjsrGdULwnCdxK5U6Hxxz.png" - }, - { - "symbol": "FLOKI", - "name": "Floki Inu SOL", - "mint": "Fkbimv9CBGZANAqRJZQ732xEZ5EA4GidjeNRKiYoDY5y", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Fkbimv9CBGZANAqRJZQ732xEZ5EA4GidjeNRKiYoDY5y.png" - }, - { - "symbol": "$MINERAL", - "name": "Mineral Token", - "mint": "FkBRohZpqx2c7zxe5cDhNq3AoFo2nPJus3xtdz9CvQmQ", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FkBRohZpqx2c7zxe5cDhNq3AoFo2nPJus3xtdz9CvQmQ.png" - }, - { - "symbol": "FELLOW", - "name": "FELLOW", - "mint": "FLLW9PtziXxtin4bvcVKbw1roFPENi5HPADzXdcjGbY1", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FLLW9PtziXxtin4bvcVKbw1roFPENi5HPADzXdcjGbY1.png" - }, - { - "symbol": "DOOK", - "name": "Dook Token", - "mint": "FLoD6AwcJCnbznnWfV6HkBHh5FYtr8wJYj3mBnwNdLLg", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FLoD6AwcJCnbznnWfV6HkBHh5FYtr8wJYj3mBnwNdLLg.png" - }, - { - "symbol": "MMCC", - "name": "Meerkats Floor Index", - "mint": "fLoeAqCfMiS3Uaj6aXSCGhf2ZE9znWz7WjTPCD2Rgnf", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/fLoeAqCfMiS3Uaj6aXSCGhf2ZE9znWz7WjTPCD2Rgnf.png" - }, - { - "symbol": "BACON", - "name": "BACON tokens", - "mint": "FMBfAxhiTwDmujiEGbexFtExHR9q7nqnRF1Rjd5UmhS7", - "decimals": 9, - "extensions": { "coingeckoId": "bacon" }, - "icon": "https://img.raydium.io/icon/FMBfAxhiTwDmujiEGbexFtExHR9q7nqnRF1Rjd5UmhS7.png" - }, - { - "symbol": "LRA", - "name": "Lumos Rewards", - "mint": "FMJotGUW16AzexRD3vXJQ94AL71cwrhtFaCTGtK1QHXm", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FMJotGUW16AzexRD3vXJQ94AL71cwrhtFaCTGtK1QHXm.png" - }, - { - "symbol": "MONKES", - "name": "SMB Index", - "mint": "FmoKY2ERGmE9NzrYphAJcqH5BPRy2Hs4VomRfu8Qgt7Y", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FmoKY2ERGmE9NzrYphAJcqH5BPRy2Hs4VomRfu8Qgt7Y.png" - }, - { - "symbol": "GOOSE", - "name": "Mongoose", - "mint": "FmpqmVcT4hSUfNhach31YUpf6M75bBYaC59JLMyCVNHH", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FmpqmVcT4hSUfNhach31YUpf6M75bBYaC59JLMyCVNHH.png" - }, - { - "symbol": "SNIPPLES", - "name": "Solana Nipples", - "mint": "FncRHFTSigcNzH66WP3Jh7kupaEHtGV48x8RyMm9cU6d", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FncRHFTSigcNzH66WP3Jh7kupaEHtGV48x8RyMm9cU6d.png" - }, - { - "symbol": "BIP", - "name": "BIP", - "mint": "FoqP7aTaibT5npFKYKQQdyonL99vkW8YALNPwWepdvf5", - "decimals": 9, - "extensions": { "coingeckoId": "the-starship-finance" }, - "icon": "https://img.raydium.io/icon/FoqP7aTaibT5npFKYKQQdyonL99vkW8YALNPwWepdvf5.png" - }, - { - "symbol": "FORA", - "name": "Fora", - "mint": "ForaXiBD8K3a7C1PwxV1xqDHs5aV8y8nWRmHebafdkes", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/ForaXiBD8K3a7C1PwxV1xqDHs5aV8y8nWRmHebafdkes.png" - }, - { - "symbol": "FORGE", - "name": "FORGE", - "mint": "FoRGERiW7odcCBGU1bztZi16osPBHjxharvDathL5eds", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FoRGERiW7odcCBGU1bztZi16osPBHjxharvDathL5eds.png" - }, - { - "symbol": "FOXY", - "name": "Foxy", - "mint": "Foxy7Df6VEc1dUCr1ExZfRAqqHaifNFDd8ccvAs59DNr", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Foxy7Df6VEc1dUCr1ExZfRAqqHaifNFDd8ccvAs59DNr.png" - }, - { - "symbol": "FOXY", - "name": "Famous Fox Federation", - "mint": "FoXyMu5xwXre7zEoSvzViRk3nGawHUp9kUh97y2NDhcq", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FoXyMu5xwXre7zEoSvzViRk3nGawHUp9kUh97y2NDhcq.png" - }, - { - "symbol": "NAXAR", - "name": "Naxar", - "mint": "Fp4gjLpTsPqBN6xDGpDHwtnuEofjyiZKxxZxzvJnjxV6", - "decimals": 4, - "extensions": { "coingeckoId": "naxar" }, - "icon": "https://img.raydium.io/icon/Fp4gjLpTsPqBN6xDGpDHwtnuEofjyiZKxxZxzvJnjxV6.png" - }, - { - "symbol": "FRIES", - "name": "Soltato FRIES", - "mint": "FriCEbw1V99GwrJRXPnSQ6su2TabHabNxiZ3VNsVFPPN", - "decimals": 9, - "extensions": { "coingeckoId": "soltato-fries" }, - "icon": "https://img.raydium.io/icon/FriCEbw1V99GwrJRXPnSQ6su2TabHabNxiZ3VNsVFPPN.png" - }, - { - "symbol": "$FROG", - "name": "Frog", - "mint": "Frog8vt6gmuuUuuerd7ispP6yavssBUtMpEP5DCEuUgD", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Frog8vt6gmuuUuuerd7ispP6yavssBUtMpEP5DCEuUgD.png" - }, - { - "symbol": "FRONK", - "name": "Fronk", - "mint": "FronkXnfBgzfhsEV2bjwoJ5VgYhpEVCSN3pzpJkvZGUf", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FronkXnfBgzfhsEV2bjwoJ5VgYhpEVCSN3pzpJkvZGUf.png" - }, - { - "symbol": "DYORNERDS", - "name": "DYOR NERDS Floor Index", - "mint": "FRsyPFrp657gKPPTDNP8ZPGAPXfRJaCLkhfdPsGxJY7p", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FRsyPFrp657gKPPTDNP8ZPGAPXfRJaCLkhfdPsGxJY7p.png" - }, - { - "symbol": "DCN", - "name": "D Coin", - "mint": "FsAXvJ5wrCoSh3cQvdkuceUsQUjLtRcqgoikR9jQ9FBW", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FsAXvJ5wrCoSh3cQvdkuceUsQUjLtRcqgoikR9jQ9FBW.png" - }, - { - "symbol": "TRPY", - "name": "Trippy Leaf", - "mint": "Fse2oFDfbwT89CqtuoFaHCBnGTMFLartDYDjPLZyc7e", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Fse2oFDfbwT89CqtuoFaHCBnGTMFLartDYDjPLZyc7e.png" - }, - { - "symbol": "DN", - "name": "Digital Nirvana", - "mint": "FT84xCFrgRbP39Yo49BiDWRii8ytb1f3rHZtQiDkC7sH", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FT84xCFrgRbP39Yo49BiDWRii8ytb1f3rHZtQiDkC7sH.png" - }, - { - "symbol": "BRZ", - "name": "BRZ", - "mint": "FtgGSFADXBtroxq8VCausXRr2of47QBf5AS1NtZCu4GD", - "decimals": 4, - "extensions": { "coingeckoId": "brz" }, - "icon": "https://img.raydium.io/icon/FtgGSFADXBtroxq8VCausXRr2of47QBf5AS1NtZCu4GD.png" - }, - { - "symbol": "MINECRAFT", - "name": "Synex Coin", - "mint": "FTkj421DxbS1wajE74J34BJ5a1o9ccA97PkK6mYq9hNQ", - "decimals": 9, - "extensions": { "coingeckoId": "synex-coin" }, - "icon": "https://img.raydium.io/icon/FTkj421DxbS1wajE74J34BJ5a1o9ccA97PkK6mYq9hNQ.png" - }, - { - "symbol": "wBIRD_v1", - "name": "Bird.Money (Wormhole v1)", - "mint": "FTPnEQ3NfRRZ9tvmpDW6JFrvweBE5sanxnXSpJL1dvbB", - "decimals": 9, - "extensions": { "coingeckoId": "bird-money" }, - "icon": "https://img.raydium.io/icon/FTPnEQ3NfRRZ9tvmpDW6JFrvweBE5sanxnXSpJL1dvbB.png" - }, - { - "symbol": "SOLNUT", - "name": "Solana Nut", - "mint": "Fv3ZG56M2cWvF8sy9VWzWyvtHPhugNc1BAzpyoAPvL7r", - "decimals": 4, - "extensions": { "coingeckoId": "solana-nut" }, - "icon": "https://img.raydium.io/icon/Fv3ZG56M2cWvF8sy9VWzWyvtHPhugNc1BAzpyoAPvL7r.png" - }, - { - "symbol": "ATGY", - "name": "A TECH GUY Token for FUN", - "mint": "FV66ygXAXXs556MQrofx89y2WUGt4G1NWBXL9BZGi7kF", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FV66ygXAXXs556MQrofx89y2WUGt4G1NWBXL9BZGi7kF.png" - }, - { - "symbol": "SWNT", - "name": "Swiss National Token", - "mint": "FvaExVNHCACXXeTDj6hpZFLCyhYekT8zxpfPXiMtba51", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FvaExVNHCACXXeTDj6hpZFLCyhYekT8zxpfPXiMtba51.png" - }, - { - "symbol": "ORKA", - "name": "ORKA Climate Solutions", - "mint": "FXSrKsQ34jMmMtciuzhr3KSTG5UMZQfXBJKGqYYUTxg1", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FXSrKsQ34jMmMtciuzhr3KSTG5UMZQfXBJKGqYYUTxg1.png" - }, - { - "symbol": "ASH", - "name": "Ashera", - "mint": "FY6XDSCubMhpkU9FAsUjB7jmN8YHYZGezHTWo9RHBSyX", - "decimals": 4, - "extensions": { "coingeckoId": "ashera" }, - "icon": "https://img.raydium.io/icon/FY6XDSCubMhpkU9FAsUjB7jmN8YHYZGezHTWo9RHBSyX.png" - }, - { - "symbol": "SOLA", - "name": "Sola Token", - "mint": "FYfQ9uaRaYvRiaEGUmct45F9WKam3BYXArTrotnTNFXF", - "decimals": 9, - "extensions": { "coingeckoId": "sola-token" }, - "icon": "https://img.raydium.io/icon/FYfQ9uaRaYvRiaEGUmct45F9WKam3BYXArTrotnTNFXF.png" - }, - { - "symbol": "VIBEZ", - "name": "VIBEZ", - "mint": "FyNuYGBBry5LAtPEkh8Y73izjTUNT2td2J3sGCK7E9Ju", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FyNuYGBBry5LAtPEkh8Y73izjTUNT2td2J3sGCK7E9Ju.png" - }, - { - "symbol": "VCC", - "name": "VentureCapital", - "mint": "FZgL5motNWEDEa24xgfSdBDfXkB9Ru9KxfEsey9S58bb", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FZgL5motNWEDEa24xgfSdBDfXkB9Ru9KxfEsey9S58bb.png" - }, - { - "symbol": "RZC", - "name": "Razzlecoin", - "mint": "FZTfdpD9DzgqMDjgNrmShDsyd5MYkwQ4k1jLq1ecrmnd", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FZTfdpD9DzgqMDjgNrmShDsyd5MYkwQ4k1jLq1ecrmnd.png" - }, - { - "symbol": "PHASE", - "name": "PHASE", - "mint": "FZxUbyQ9oeFiSDaabw8KfAWACsDMQhbuxR9vm2Rh7Ewm", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/FZxUbyQ9oeFiSDaabw8KfAWACsDMQhbuxR9vm2Rh7Ewm.png" - }, - { - "symbol": "EPC", - "name": "Elliptic", - "mint": "G1NChRwNJG8BJAPfRCzq7t1aH5UTjdytCEGBDbQHCYcE", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/G1NChRwNJG8BJAPfRCzq7t1aH5UTjdytCEGBDbQHCYcE.png" - }, - { - "symbol": "BUM", - "name": "Beach Bum Billionaire", - "mint": "G2PQTxEooYBG6TcrJ97tFrBzyYoFiRQwwTwiAkTycpwd", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "EYE", - "name": "NftEyez Coin", - "mint": "G7eETAaUzmsBPKhokZyfbaT4tD9igdZSmfQGEYWem8Sw", - "decimals": 6, - "extensions": { "coingeckoId": "nfteyez" }, - "icon": "https://img.raydium.io/icon/G7eETAaUzmsBPKhokZyfbaT4tD9igdZSmfQGEYWem8Sw.png" - }, - { - "symbol": "CSTR", - "name": "CoreStarter", - "mint": "G7uYedVqFy97mzjygebnmmaMUVxWHFhNZotY6Zzsprvf", - "decimals": 9, - "extensions": { "coingeckoId": "corestarter" }, - "icon": "https://img.raydium.io/icon/G7uYedVqFy97mzjygebnmmaMUVxWHFhNZotY6Zzsprvf.png" - }, - { - "symbol": "BARK", - "name": "Bark o Finance", - "mint": "GaAzf7jwEKTouDXJExH9TKfvX3Ae7fLaGwNuEajq7KsE", - "decimals": 1, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GaAzf7jwEKTouDXJExH9TKfvX3Ae7fLaGwNuEajq7KsE.png" - }, - { - "symbol": "NUTS", - "name": "NUTS", - "mint": "GCxgQbbvJc4UyqGCsUAUa38npzZX27EMxZwckLuWeEkt", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GCxgQbbvJc4UyqGCsUAUa38npzZX27EMxZwckLuWeEkt.png" - }, - { - "symbol": "IBC", - "name": "IsaacBurgerCoin", - "mint": "GdCb8jMB6mhsoiQsSoSbt7YDQzxjx4whdPvzM131jFCC", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GdCb8jMB6mhsoiQsSoSbt7YDQzxjx4whdPvzM131jFCC.png" - }, - { - "symbol": "Club", - "name": "Club", - "mint": "GDTVxsG41afjiJngZgFYHJkrG4PkTB9pVx7NuVsm2RcX", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GDTVxsG41afjiJngZgFYHJkrG4PkTB9pVx7NuVsm2RcX.png" - }, - { - "symbol": "daoSOL", - "name": "daoSOL Token", - "mint": "GEJpt3Wjmr628FqXxTgxMce1pLntcPV4uFi8ksxMyPQh", - "decimals": 9, - "extensions": { "coingeckoId": "daosol" }, - "icon": "https://img.raydium.io/icon/GEJpt3Wjmr628FqXxTgxMce1pLntcPV4uFi8ksxMyPQh.png" - }, - { - "symbol": "JFI", - "name": "Jungle DeFi", - "mint": "GePFQaZKHcWE5vpxHfviQtH5jgxokSs51Y5Q4zgBiMDs", - "decimals": 9, - "extensions": { "coingeckoId": "jungle-defi" }, - "icon": "https://img.raydium.io/icon/GePFQaZKHcWE5vpxHfviQtH5jgxokSs51Y5Q4zgBiMDs.png" - }, - { - "symbol": "POTATO", - "name": "POTATO", - "mint": "GEYrotdkRitGUK5UMv3aMttEhVAZLhRJMcG82zKYsaWB", - "decimals": 3, - "extensions": { "coingeckoId": "potato" }, - "icon": "https://img.raydium.io/icon/GEYrotdkRitGUK5UMv3aMttEhVAZLhRJMcG82zKYsaWB.png" - }, - { - "symbol": "SOLPAD", - "name": "Solpad Finance", - "mint": "GfJ3Vq2eSTYf1hJP6kKLE9RT6u7jF9gNszJhZwo5VPZp", - "decimals": 9, - "extensions": { "coingeckoId": "solpad-finance" }, - "icon": "https://img.raydium.io/icon/GfJ3Vq2eSTYf1hJP6kKLE9RT6u7jF9gNszJhZwo5VPZp.png" - }, - { - "symbol": "SCTT", - "name": "SOLANA CRYPT TOKEN", - "mint": "GGFNWQ2oEzYVPu1kGSjXZWfyTibnCGJfqZ7uPx8Jkj7B", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GGFNWQ2oEzYVPu1kGSjXZWfyTibnCGJfqZ7uPx8Jkj7B.png" - }, - { - "symbol": "DOGEC", - "name": "Dogecoin Cash", - "mint": "GGupQCMnyEmHKcqFu72qCTm6yEYpVyhouY9dSAMEXLsC", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GGupQCMnyEmHKcqFu72qCTm6yEYpVyhouY9dSAMEXLsC.png" - }, - { - "symbol": "NRC", - "name": "Neon Rocket Coin", - "mint": "Gh1jKzmxf95cT5PQabNbfJskkQU8kQ5UugfpbHSnPq9z", - "decimals": 3, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Gh1jKzmxf95cT5PQabNbfJskkQU8kQ5UugfpbHSnPq9z.png" - }, - { - "symbol": "Gangsta", - "name": "Gangsta", - "mint": "Gh6jp5U3yfcJwkZ7RoY6Ak2tgd752dSqBSYwHnfK3gft", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Gh6jp5U3yfcJwkZ7RoY6Ak2tgd752dSqBSYwHnfK3gft.png" - }, - { - "symbol": "SD", - "name": "DoughDAO Token", - "mint": "GH9urVNhVzEvQFAz4NGWrjc3raGMKSmU96GV7s3QwSfq", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GH9urVNhVzEvQFAz4NGWrjc3raGMKSmU96GV7s3QwSfq.png" - }, - { - "symbol": "PRMD", - "name": "Primordials Token", - "mint": "Ghj7ib4VJC592ybwpMK75vaX3fRu1SqtkXYMd2pNywtK", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Ghj7ib4VJC592ybwpMK75vaX3fRu1SqtkXYMd2pNywtK.png" - }, - { - "symbol": "SOLAPE", - "name": "SolAPE Token", - "mint": "GHvFFSZ9BctWsEc5nujR1MTmmJWY7tgQz2AXE6WVFtGN", - "decimals": 9, - "extensions": { "coingeckoId": "solape-token" }, - "icon": "https://img.raydium.io/icon/GHvFFSZ9BctWsEc5nujR1MTmmJWY7tgQz2AXE6WVFtGN.png" - }, - { - "symbol": "WATT", - "name": "WATT token", - "mint": "GjdreVe7iUG4hyESSweGyFzgekWufhEwGJqAaa1hr7pf", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GjdreVe7iUG4hyESSweGyFzgekWufhEwGJqAaa1hr7pf.png" - }, - { - "symbol": "ALTAR", - "name": "Altar", - "mint": "GJQ1iDoPWWo7pXeNKhC9BLD3FHL2tgFEVGMHYGEfQZT", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GJQ1iDoPWWo7pXeNKhC9BLD3FHL2tgFEVGMHYGEfQZT.png" - }, - { - "symbol": "ODYSSEUS", - "name": "Odysseus Coin", - "mint": "gJtYNevehYkg9VeEaWWKztWeFt4WXdQFihMXrUMeKd4", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/gJtYNevehYkg9VeEaWWKztWeFt4WXdQFihMXrUMeKd4.png" - }, - { - "symbol": "SOL100", - "name": "SOL100", - "mint": "GkDg1ZfoFkroLAwLqtJNXhxCDg8gmKxHAGxSUZagYFfE", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GkDg1ZfoFkroLAwLqtJNXhxCDg8gmKxHAGxSUZagYFfE.png" - }, - { - "symbol": "SIXY", - "name": "611Coin", - "mint": "GKNr1Gwf7AMvEMEyMzBoEALVBvCpKJue9Lzn9HfrYYhg", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GKNr1Gwf7AMvEMEyMzBoEALVBvCpKJue9Lzn9HfrYYhg.png" - }, - { - "symbol": "UTS", - "name": "UTSCoin", - "mint": "GkppDJvtDJfE2SENMg9i6EvSTTgvmrcmnNJrNXSoZcbJ", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GkppDJvtDJfE2SENMg9i6EvSTTgvmrcmnNJrNXSoZcbJ.png" - }, - { - "symbol": "BULL", - "name": "BULL", - "mint": "GkSPaHdY2raetuYzsJYacHtrAtQUfWt64bpd1VzxJgSD", - "decimals": 6, - "extensions": {}, - "icon": "" - }, - { - "symbol": "MADOG", - "name": "Mad Dog", - "mint": "GLfMsvQiKxvAhf8h5vM3EUurjdvvgfXSYnEWe6UydoiR", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GLfMsvQiKxvAhf8h5vM3EUurjdvvgfXSYnEWe6UydoiR.png" - }, - { - "symbol": "SOLAB", - "name": "Solabrador", - "mint": "GLmaRDRmYd4u3YLfnj9eq1mrwxa1YfSweZYYZXZLTRdK", - "decimals": 9, - "extensions": { "coingeckoId": "solabrador" }, - "icon": "https://img.raydium.io/icon/GLmaRDRmYd4u3YLfnj9eq1mrwxa1YfSweZYYZXZLTRdK.png" - }, - { - "symbol": "BMINUS", - "name": "Fraktionalized Solana White Paper", - "mint": "GM4CTEsNsU5Kg22JNKkANTannrBU9Ah6SNa3BcyBA6Kj", - "decimals": 3, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GM4CTEsNsU5Kg22JNKkANTannrBU9Ah6SNa3BcyBA6Kj.png" - }, - { - "symbol": "ILU", - "name": "ILoveU Token", - "mint": "Gm6szibJfB1ZzUxNYf85nXwFchugqTqNyE5fDwWfBc7K", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Gm6szibJfB1ZzUxNYf85nXwFchugqTqNyE5fDwWfBc7K.png" - }, - { - "symbol": "GMSOL", - "name": "We Say gm", - "mint": "gmdu3snwW28DmmxCseChp9owWLUhamH9eS3hWfHG8Vg", - "decimals": 9, - "extensions": { "coingeckoId": "gmsol" }, - "icon": "" - }, - { - "symbol": "BLEEP", - "name": "BLEEP", - "mint": "GmY2Rp9t5S4yD5jhgJrc47VSAa6hQiikkYi3sr9HLNZr", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GmY2Rp9t5S4yD5jhgJrc47VSAa6hQiikkYi3sr9HLNZr.png" - }, - { - "symbol": "GNC", - "name": "Gong Coin", - "mint": "GNC9uTx8dBun94hM8PeRmEGBb7LJ7uKrgNBnooAaQzXN", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GNC9uTx8dBun94hM8PeRmEGBb7LJ7uKrgNBnooAaQzXN.png" - }, - { - "symbol": "DJN", - "name": "Fenix Danjon", - "mint": "GnzxEyULVPQYb5F5hxGc8dEGivctVrfr5mtsdp4z5xU2", - "decimals": 9, - "extensions": { "coingeckoId": "fenix-danjon" }, - "icon": "https://img.raydium.io/icon/GnzxEyULVPQYb5F5hxGc8dEGivctVrfr5mtsdp4z5xU2.png" - }, - { - "symbol": "GOLDY", - "name": "DeFi Land Gold", - "mint": "GoLDYyyiVeXnVf9qgoK712N5esm1cCbHEK9aNJFx47Sx", - "decimals": 9, - "extensions": { "coingeckoId": "defi-land-gold" }, - "icon": "https://img.raydium.io/icon/GoLDYyyiVeXnVf9qgoK712N5esm1cCbHEK9aNJFx47Sx.png" - }, - { - "symbol": "DPD", - "name": "DPD", - "mint": "GP9zY2D8CgMreoUdYQjyn7Fo7XCq9ubVnX3u4ot1wpgt", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GP9zY2D8CgMreoUdYQjyn7Fo7XCq9ubVnX3u4ot1wpgt.png" - }, - { - "symbol": "SPM", - "name": "SchimmelPeter Monster", - "mint": "GpQLC7KnNgAvEpamfWi1AWFdXECZ1eQetvFYTuETLZC7", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GpQLC7KnNgAvEpamfWi1AWFdXECZ1eQetvFYTuETLZC7.png" - }, - { - "symbol": "CAPE", - "name": "Crazy Ape Coin", - "mint": "GpYMp8eP3HADY8x1jLVfFVBVYqxFNxT5mFhZAZt9Poco", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GpYMp8eP3HADY8x1jLVfFVBVYqxFNxT5mFhZAZt9Poco.png" - }, - { - "symbol": "KTR", - "name": "Kotaru", - "mint": "Gq5xdBxA39rRN5GsnJtodAnkqvFDQ4YxkEG3N7rS8XHw", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Gq5xdBxA39rRN5GsnJtodAnkqvFDQ4YxkEG3N7rS8XHw.png" - }, - { - "symbol": "SHIVX", - "name": "Shivx", - "mint": "Gqiou284yNmVtTGVVM8guof4DaQtbrEDC4kgjNHZbbo4", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Gqiou284yNmVtTGVVM8guof4DaQtbrEDC4kgjNHZbbo4.png" - }, - { - "symbol": "SOLMO", - "name": "SolMoon", - "mint": "Gro98oTmXxCVX8HKr3q2tMnP5ztoC77q6KehFDnAB983", - "decimals": 4, - "extensions": { "coingeckoId": "solmoon" }, - "icon": "https://img.raydium.io/icon/Gro98oTmXxCVX8HKr3q2tMnP5ztoC77q6KehFDnAB983.png" - }, - { - "symbol": "BBI", - "name": "Bridgesplit Brand Index", - "mint": "GRsoqmhsS7fCLpEqqE7oRM92ag3WVy8VbJAi6KfWSeHS", - "decimals": 2, - "extensions": { "coingeckoId": "bridgesplit-brand-index" }, - "icon": "https://img.raydium.io/icon/GRsoqmhsS7fCLpEqqE7oRM92ag3WVy8VbJAi6KfWSeHS.png" - }, - { - "symbol": "WAVE", - "name": "Lost At Sea WAVE", - "mint": "GS6E87SLTioRDG3uSVRwQmuKKMxDmWU7fktCTJ5xkEM8", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GS6E87SLTioRDG3uSVRwQmuKKMxDmWU7fktCTJ5xkEM8.png" - }, - { - "symbol": "gSAIL", - "name": "SolanaSail Governance Token V2", - "mint": "Gsai2KN28MTGcSZ1gKYFswUpFpS7EM9mvdR9c8f6iVXJ", - "decimals": 9, - "extensions": { "coingeckoId": "solanasail-governance-token" }, - "icon": "https://img.raydium.io/icon/Gsai2KN28MTGcSZ1gKYFswUpFpS7EM9mvdR9c8f6iVXJ.png" - }, - { - "symbol": "XgSAIL", - "name": "gSAIL DEPRECATED", - "mint": "GSaiLQxREzaxUcE3v28HxBacoUQPZNtXx1eQsCFsX9Bg", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GSaiLQxREzaxUcE3v28HxBacoUQPZNtXx1eQsCFsX9Bg.png" - }, - { - "symbol": "tuSLRS", - "name": "tuSLRS", - "mint": "GtFtWCcLYtWQT8NLRwEfUqc9sgVnq4SbuSnMCpwcutNk", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GtFtWCcLYtWQT8NLRwEfUqc9sgVnq4SbuSnMCpwcutNk.png" - }, - { - "symbol": "Potion", - "name": "Potion", - "mint": "GtHxqAqbaZB8eo8R8pGXUhWxs6X8WQWMWTUWKTgSFbHo", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GtHxqAqbaZB8eo8R8pGXUhWxs6X8WQWMWTUWKTgSFbHo.png" - }, - { - "symbol": "DASCH", - "name": "Dasch Coin", - "mint": "GTuDe5yneFKaWSsPqqKgu413KTk8WyDnUZcZUGxuNYsT", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "SOUTHPARK", - "name": "South Park Memes", - "mint": "GUAXo4yYqY335t9esybM4wDPcDeAc7m2mW2xQ2svXzy1", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GUAXo4yYqY335t9esybM4wDPcDeAc7m2mW2xQ2svXzy1.png" - }, - { - "symbol": "creatorpro", - "name": "creatorPRO", - "mint": "GV3MjuGin8aTG6Rhc1vR1QFYp8gq5vW39jnNPLrbzmPi", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GV3MjuGin8aTG6Rhc1vR1QFYp8gq5vW39jnNPLrbzmPi.png" - }, - { - "symbol": "SVIZ", - "name": "Space Vizsla", - "mint": "GV6n9Uow3XzMWSs8vwTCML8SvMA6ozbidaEfdPoSoraQ", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GV6n9Uow3XzMWSs8vwTCML8SvMA6ozbidaEfdPoSoraQ.png" - }, - { - "symbol": "LAMAS", - "name": "Sollamas Floor Index", - "mint": "GvpkzEc4kiKS3xzNLFoc3k8HUVxYCAU8CYBkhAUKsSZ5", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GvpkzEc4kiKS3xzNLFoc3k8HUVxYCAU8CYBkhAUKsSZ5.png" - }, - { - "symbol": "PEEL", - "name": "PEEL", - "mint": "GVsdtSe3E2fQoP3TzNT2M1VUchJ7sBmDBuvBZmGDGvmB", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GVsdtSe3E2fQoP3TzNT2M1VUchJ7sBmDBuvBZmGDGvmB.png" - }, - { - "symbol": "SAFU", - "name": "1SAFU", - "mint": "GWgwUUrgai3BFeEJZp7bdsBSYiuDqNmHf9uRusWsf3Yi", - "decimals": 0, - "extensions": { "coingeckoId": "1safu" }, - "icon": "https://img.raydium.io/icon/GWgwUUrgai3BFeEJZp7bdsBSYiuDqNmHf9uRusWsf3Yi.png" - }, - { - "symbol": "MINGO", - "name": "Mingo Token", - "mint": "GXm9UzbAERvZsfsM8CB6sWrn74BJ6ZAfDoNdeNRCmy2E", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "ATC", - "name": "ARTICOIN", - "mint": "GXnw9YSt6DANCt84Ti6ZpbaXvrvuEJFCYqrDjygnq4R8", - "decimals": 6, - "extensions": { "coingeckoId": "articoin" }, - "icon": "https://img.raydium.io/icon/GXnw9YSt6DANCt84Ti6ZpbaXvrvuEJFCYqrDjygnq4R8.png" - }, - { - "symbol": "GYC", - "name": "GameYoo Token", - "mint": "GYCVdmDthkf3jSz5ns6fkzCmHub7FSZxjVCfbfGqkH7P", - "decimals": 9, - "extensions": { "coingeckoId": "gameyoo" }, - "icon": "https://img.raydium.io/icon/GYCVdmDthkf3jSz5ns6fkzCmHub7FSZxjVCfbfGqkH7P.png" - }, - { - "symbol": "SOULO", - "name": "SouloCoin", - "mint": "Gz3u6eJaKEviYpPC5AwUziz891kNX76PNdsmJrnaNNY4", - "decimals": 9, - "extensions": { "coingeckoId": "soulocoin" }, - "icon": "https://img.raydium.io/icon/Gz3u6eJaKEviYpPC5AwUziz891kNX76PNdsmJrnaNNY4.png" - }, - { - "symbol": "S0L", - "name": "S0lana", - "mint": "GzHyjtEn2iZ8aQdRUGS54U3TXAQNP2egcKrAxwEcVhPT", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GzHyjtEn2iZ8aQdRUGS54U3TXAQNP2egcKrAxwEcVhPT.png" - }, - { - "symbol": "SAC", - "name": "Stoned Ape Crew Index", - "mint": "GZL4yjPohDShW4RofJ6dEWu2Fv7qEa5mBT7Dpje5hqe7", - "decimals": 2, - "extensions": { "coingeckoId": "stoned-ape-crew-index" }, - "icon": "https://img.raydium.io/icon/GZL4yjPohDShW4RofJ6dEWu2Fv7qEa5mBT7Dpje5hqe7.png" - }, - { - "symbol": "mPLAT", - "name": "SolMiner Platinum", - "mint": "GZNrMEdrt6Vg428JzvJYRGGPpVxgjUPsg6WLqKBvmNLw", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/GZNrMEdrt6Vg428JzvJYRGGPpVxgjUPsg6WLqKBvmNLw.png" - }, - { - "symbol": "LOOT", - "name": "LOOT", - "mint": "GzpRsvnKXKz586kRLkjdppR4dUCFwHa2qaszKkPUQx6g", - "decimals": 6, - "extensions": { "coingeckoId": "loot-token" }, - "icon": "https://img.raydium.io/icon/GzpRsvnKXKz586kRLkjdppR4dUCFwHa2qaszKkPUQx6g.png" - }, - { - "symbol": "BUGS", - "name": "BUGS", - "mint": "H1QvHLhmk4rL36FBphnFUaQszf6RHGU8RLptPSuPcQwX", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/H1QvHLhmk4rL36FBphnFUaQszf6RHGU8RLptPSuPcQwX.png" - }, - { - "symbol": "ROLL", - "name": "Let'sroll DAO", - "mint": "H2EJUxt2KSPk7BWGZRfLMqh56wCmWygDJVTvjTJFHeym", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/H2EJUxt2KSPk7BWGZRfLMqh56wCmWygDJVTvjTJFHeym.png" - }, - { - "symbol": "creator", - "name": "creator", - "mint": "H2rMQMa6kPpWwg2GraKyiiPwnayDBoBNg9WNVuafqXKc", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/H2rMQMa6kPpWwg2GraKyiiPwnayDBoBNg9WNVuafqXKc.png" - }, - { - "symbol": "METARARITY", - "name": "METARARITY", - "mint": "H36ykN443TZ6pC8oryicCYr5YB1em4fuSyezu5aoskNv", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/H36ykN443TZ6pC8oryicCYr5YB1em4fuSyezu5aoskNv.png" - }, - { - "symbol": "FAC", - "name": "FAC FUD Token", - "mint": "H3pWoh5Te12nHYVSQm1vQC6aAn2EbADj8zit23jP2jX3", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/H3pWoh5Te12nHYVSQm1vQC6aAn2EbADj8zit23jP2jX3.png" - }, - { - "symbol": "DEV", - "name": "DevCoin", - "mint": "H5euuuZXAuFak2NVTMu53fckdkHFWuJzXXb3TfKTrLWK", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/H5euuuZXAuFak2NVTMu53fckdkHFWuJzXXb3TfKTrLWK.png" - }, - { - "symbol": "BDE", - "name": "Big Defi Energy", - "mint": "H5gczCNbrtso6BqGKihF97RaWaxpUEZnFuFUKK4YX3s2", - "decimals": 9, - "extensions": { "coingeckoId": "big-defi-energy" }, - "icon": "https://img.raydium.io/icon/H5gczCNbrtso6BqGKihF97RaWaxpUEZnFuFUKK4YX3s2.png" - }, - { - "symbol": "SPX", - "name": "Sphinxel", - "mint": "H6JocWxg5g1Lcs4oPnBecmjQ4Y1bkZhGJHtjMunmjyrp", - "decimals": 9, - "extensions": { "coingeckoId": "sphinxel" }, - "icon": "https://img.raydium.io/icon/H6JocWxg5g1Lcs4oPnBecmjQ4Y1bkZhGJHtjMunmjyrp.png" - }, - { - "symbol": "RTRO", - "name": "RetroBit", - "mint": "H7NbVyqLPHWC7Da49F4CLNTgfMfYq8dF9ktJW5wwH3Ck", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/H7NbVyqLPHWC7Da49F4CLNTgfMfYq8dF9ktJW5wwH3Ck.png" - }, - { - "symbol": "ICON", - "name": "ICON", - "mint": "HAfTjdSjZiquZiAkmsYBmcFR5NM7cP8HtMqjQRk8eVTX", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HAfTjdSjZiquZiAkmsYBmcFR5NM7cP8HtMqjQRk8eVTX.png" - }, - { - "symbol": "MEOW", - "name": "SOL-CATS", - "mint": "HAgX1HSfok8DohiNCS54FnC2UJkDSrRVnT38W3iWFwc8", - "decimals": 9, - "extensions": { "coingeckoId": "solcats" }, - "icon": "https://img.raydium.io/icon/HAgX1HSfok8DohiNCS54FnC2UJkDSrRVnT38W3iWFwc8.png" - }, - { - "symbol": "SXP", - "name": "Stacc eXPerience Points", - "mint": "HavbxBPK1uY9kMNqKPkWDEQXWw6FYERrLxeMtWiXnwko", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HavbxBPK1uY9kMNqKPkWDEQXWw6FYERrLxeMtWiXnwko.png" - }, - { - "symbol": "SLNDN", - "name": "Solanadon", - "mint": "HBHMiauecxer5FCzPeXgE2A8ZCf7fQgxxwo4vfkFtC7s", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HBHMiauecxer5FCzPeXgE2A8ZCf7fQgxxwo4vfkFtC7s.png" - }, - { - "symbol": "CRY", - "name": "Crystal", - "mint": "HbrmyoumgcK6sDFBi6EZQDi4i4ZgoN16eRB2JseKc7Hi", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HbrmyoumgcK6sDFBi6EZQDi4i4ZgoN16eRB2JseKc7Hi.png" - }, - { - "symbol": "NAMEK", - "name": "Namek", - "mint": "HBxHiTHpmnps5ALo2jzZbVmUzPPpZsUT8wN8KtqkBU9h", - "decimals": 9, - "extensions": {}, - "icon": "" - }, - { - "symbol": "C999", - "name": "Cosmogol 999", - "mint": "HC9qZTgTYf12cFPaK3dK2HZJ9M47r2JenrsvQ1Ewnds8", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HC9qZTgTYf12cFPaK3dK2HZJ9M47r2JenrsvQ1Ewnds8.png" - }, - { - "symbol": "BOTS", - "name": "Skullbots Biker Gang Floor Index", - "mint": "HDEqEpFgTrBawzDgTG1eyH8Go9PX84LCEC8Qjt8T4jFN", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HDEqEpFgTrBawzDgTG1eyH8Go9PX84LCEC8Qjt8T4jFN.png" - }, - { - "symbol": "KSAMO", - "name": "KING SAMO", - "mint": "HDiA4quoMibAGeJQzvxajp3Z9cvnkNng99oVrnuNj6px", - "decimals": 6, - "extensions": { "coingeckoId": "king-samo" }, - "icon": "https://img.raydium.io/icon/HDiA4quoMibAGeJQzvxajp3Z9cvnkNng99oVrnuNj6px.png" - }, - { - "symbol": "MILLI", - "name": "MILLIONSY", - "mint": "HDLRMKW1FDz2q5Zg778CZx26UgrtnqpUDkNNJHhmVUFr", - "decimals": 9, - "extensions": { "coingeckoId": "millionsy" }, - "icon": "https://img.raydium.io/icon/HDLRMKW1FDz2q5Zg778CZx26UgrtnqpUDkNNJHhmVUFr.png" - }, - { - "symbol": "FTR", - "name": "Future", - "mint": "HEhMLvpSdPviukafKwVN8BnBUTamirptsQ6Wxo5Cyv8s", - "decimals": 9, - "extensions": { "coingeckoId": "future" }, - "icon": "https://img.raydium.io/icon/HEhMLvpSdPviukafKwVN8BnBUTamirptsQ6Wxo5Cyv8s.png" - }, - { - "symbol": "HERO", - "name": "Solhero Finance", - "mint": "Hero6s7zJXsw9hfCXLVR5stLqgCok3E7CCkpQEoLAk2g", - "decimals": 6, - "extensions": { "coingeckoId": "solhero" }, - "icon": "https://img.raydium.io/icon/Hero6s7zJXsw9hfCXLVR5stLqgCok3E7CCkpQEoLAk2g.png" - }, - { - "symbol": "HUNKZ", - "name": "HunkCoinz", - "mint": "HFE5CwhDzXLYrnfH41712be8Pz498v2yCjyR91jZEqpe", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HFE5CwhDzXLYrnfH41712be8Pz498v2yCjyR91jZEqpe.png" - }, - { - "symbol": "INA", - "name": "Inanna", - "mint": "HfMVgG3fQr45JtrQD3jpVki6E5H5BSdjN8kCAvDEDKMQ", - "decimals": 8, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HfMVgG3fQr45JtrQD3jpVki6E5H5BSdjN8kCAvDEDKMQ.png" - }, - { - "symbol": "eSOL", - "name": "EverSOL staked SOL (eSOL)", - "mint": "Hg35Vd8K3BS2pLB3xwC2WqQV8pmpCm3oNRGYP1PEpmCM", - "decimals": 9, - "extensions": { "coingeckoId": "eversol-staked-sol" }, - "icon": "https://img.raydium.io/icon/Hg35Vd8K3BS2pLB3xwC2WqQV8pmpCm3oNRGYP1PEpmCM.png" - }, - { - "symbol": "PIP", - "name": "PIP", - "mint": "HHjoYwUp5aU6pnrvN4s2pwEErwXNZKhxKGYjRJMoBjLw", - "decimals": 9, - "extensions": { "coingeckoId": "pip" }, - "icon": "https://img.raydium.io/icon/HHjoYwUp5aU6pnrvN4s2pwEErwXNZKhxKGYjRJMoBjLw.png" - }, - { - "symbol": "ACRE", - "name": "ACRE", - "mint": "Hi4WKXqmeoNVz8Nf7pxCCQrdFfxdLDLGFudHXmV95oU9", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Hi4WKXqmeoNVz8Nf7pxCCQrdFfxdLDLGFudHXmV95oU9.png" - }, - { - "symbol": "SNJ", - "name": "Sola Ninja", - "mint": "Hj4sTP4L4rvR9WBR6KyK99sxPptBQQczNWe4y15mxhRD", - "decimals": 9, - "extensions": { "coingeckoId": "sola-ninja" }, - "icon": "https://img.raydium.io/icon/Hj4sTP4L4rvR9WBR6KyK99sxPptBQQczNWe4y15mxhRD.png" - }, - { - "symbol": "SHLT", - "name": "Sehlat", - "mint": "Hjc6Ku7VpMD8TqPUuimDXWvT3RWpnbm1viaUe3dUco3L", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Hjc6Ku7VpMD8TqPUuimDXWvT3RWpnbm1viaUe3dUco3L.png" - }, - { - "symbol": "LFI", - "name": "Luffy Inu", - "mint": "HkCrU2Vk5kGvvPUUR2dirjgAx3TbyCPYXRZbefwzCyCp", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HkCrU2Vk5kGvvPUUR2dirjgAx3TbyCPYXRZbefwzCyCp.png" - }, - { - "symbol": "SPZ", - "name": "Solprize", - "mint": "HkNK7BL5pSUUzc6ns1mHW5JnzbSG4S9u2QdR3cUuyzSa", - "decimals": 5, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HkNK7BL5pSUUzc6ns1mHW5JnzbSG4S9u2QdR3cUuyzSa.png" - }, - { - "symbol": "CRRT", - "name": "Breezy Bunnies Carrot", - "mint": "HkNokfCXG33eu5vCcS49mq3jZcKZeQSQCyta964YxxYg", - "decimals": 0, - "extensions": {}, - "icon": "" - }, - { - "symbol": "PSOL", - "name": "Parasol", - "mint": "Hmatmu1ktLbobSvim94mfpZmjL5iiyoM1zidtXJRAdLZ", - "decimals": 7, - "extensions": { "coingeckoId": "parasol-finance" }, - "icon": "https://img.raydium.io/icon/Hmatmu1ktLbobSvim94mfpZmjL5iiyoM1zidtXJRAdLZ.png" - }, - { - "symbol": "HMKS", - "name": "Haughty Monkee Token", - "mint": "HMKSrb4Nb894wEmwYveACs3y7wHy7TKzf3kqPeiHjaqa", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HMKSrb4Nb894wEmwYveACs3y7wHy7TKzf3kqPeiHjaqa.png" - }, - { - "symbol": "FRENS", - "name": "Chimp Frens", - "mint": "HNm1VgnyhaMZZF71RjNFNiYLN76zyZTDcBZPjYveWFXX", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HNm1VgnyhaMZZF71RjNFNiYLN76zyZTDcBZPjYveWFXX.png" - }, - { - "symbol": "SER", - "name": "Secretum", - "mint": "HNpdP2rL6FR6jM3bDxFX2Zo32D1YG2ZCztf9zzCrKMEX", - "decimals": 9, - "extensions": { "coingeckoId": "secretum" }, - "icon": "https://img.raydium.io/icon/HNpdP2rL6FR6jM3bDxFX2Zo32D1YG2ZCztf9zzCrKMEX.png" - }, - { - "symbol": "SUCH", - "name": "Such Shiba", - "mint": "HnZiKrSKYQkEfzjQs6qkvuGbBmrBP9YzjB1SMM7tiGZ1", - "decimals": 9, - "extensions": { "coingeckoId": "such-shiba" }, - "icon": "https://img.raydium.io/icon/HnZiKrSKYQkEfzjQs6qkvuGbBmrBP9YzjB1SMM7tiGZ1.png" - }, - { - "symbol": "HONE", - "name": "Yokoito Crew Hone", - "mint": "hone3CJTYjczb5nJh45KCNMkjrKMt7SCnHkWGWsVfVu", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/hone3CJTYjczb5nJh45KCNMkjrKMt7SCnHkWGWsVfVu.png" - }, - { - "symbol": "$HONEY", - "name": "HONEY", - "mint": "HonyeYAaTPgKUgQpayL914P6VAqbQZPrbkGMETZvW4iN", - "decimals": 6, - "extensions": { "coingeckoId": "honey-finance" }, - "icon": "https://img.raydium.io/icon/HonyeYAaTPgKUgQpayL914P6VAqbQZPrbkGMETZvW4iN.png" - }, - { - "symbol": "LITTE", - "name": "LitteCoin", - "mint": "HPeWNsBtYtfMeYS6Sqwb3uvDvuarekCnrjCq41XqMQdf", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HPeWNsBtYtfMeYS6Sqwb3uvDvuarekCnrjCq41XqMQdf.png" - }, - { - "symbol": "FLOCK", - "name": "Flock", - "mint": "Hq9MuLDvUAWqC29JhqP2CUJP9879LfqNBHyRRREEXwtZ", - "decimals": 9, - "extensions": { "coingeckoId": "flock" }, - "icon": "https://img.raydium.io/icon/Hq9MuLDvUAWqC29JhqP2CUJP9879LfqNBHyRRREEXwtZ.png" - }, - { - "symbol": "WNAV", - "name": "Wrapped Navcoin", - "mint": "HRBrRXGCrPro6TtryKQkLXuZqg3LdBMN9ZWx2v66pT4L", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HRBrRXGCrPro6TtryKQkLXuZqg3LdBMN9ZWx2v66pT4L.png" - }, - { - "symbol": "MBM", - "name": "Bonezz Inu", - "mint": "HRyyRN2GY4yxrxCx5bekuEEKvFqztr42eVRY5UdkYWGf", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HRyyRN2GY4yxrxCx5bekuEEKvFqztr42eVRY5UdkYWGf.png" - }, - { - "symbol": "WWOLF", - "name": "WWOLF Token", - "mint": "HS2DanDUPKEnkzXDywtQKAqWKbWte3ahvwMhcfBJjGai", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HS2DanDUPKEnkzXDywtQKAqWKbWte3ahvwMhcfBJjGai.png" - }, - { - "symbol": "DKM", - "name": "DeadKnight Token", - "mint": "HtbhBYdcfXbbD2JiH6jtsTt2m2FXjn7h4k6iXfz98k5W", - "decimals": 9, - "extensions": { "coingeckoId": "dead-knight" }, - "icon": "https://img.raydium.io/icon/HtbhBYdcfXbbD2JiH6jtsTt2m2FXjn7h4k6iXfz98k5W.png" - }, - { - "symbol": "HUMAN", - "name": "HUMAN", - "mint": "HuManQDs2YtrRkQu4www48fFc6mz39gG6u2vUT2U9B9X", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HuManQDs2YtrRkQu4www48fFc6mz39gG6u2vUT2U9B9X.png" - }, - { - "symbol": "DREAM", - "name": "DREAM TOKEN", - "mint": "HuMShjViKhcfihmHkgvctcFAyeyxAk8hK5K58zWpuRKf", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HuMShjViKhcfihmHkgvctcFAyeyxAk8hK5K58zWpuRKf.png" - }, - { - "symbol": "MARMO", - "name": "MarmosetNFT", - "mint": "HV8RWueWwpRue86SMzXQapxDB5ZEWw5YnVbxuDcihaF5", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HV8RWueWwpRue86SMzXQapxDB5ZEWw5YnVbxuDcihaF5.png" - }, - { - "symbol": "SIX", - "name": "Solana Eco Index", - "mint": "HWSqJdwemji7TNiKQPudUj86LXyF3vGAtWm5ePk5KzgD", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HWSqJdwemji7TNiKQPudUj86LXyF3vGAtWm5ePk5KzgD.png" - }, - { - "symbol": "BARMY", - "name": "BARMY", - "mint": "HWXWUXUNuBd6euKDxsL3FrCZ6P9RwmVmbXHKSd4MgxoA", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HWXWUXUNuBd6euKDxsL3FrCZ6P9RwmVmbXHKSd4MgxoA.png" - }, - { - "symbol": "HEMOB", - "name": "Heatmob", - "mint": "Hxk1ns5V8Lq41wzLjvq8pvNEhGh3FcCTWbawbj5SL4jj", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Hxk1ns5V8Lq41wzLjvq8pvNEhGh3FcCTWbawbj5SL4jj.png" - }, - { - "symbol": "ZAP", - "name": "ZAP Token", - "mint": "HxPoEHMt1vKeqjKCePcqTj6yYgn6Xqq1fKTY3Pjx4YrX", - "decimals": 8, - "extensions": { "coingeckoId": "zap" }, - "icon": "https://img.raydium.io/icon/HxPoEHMt1vKeqjKCePcqTj6yYgn6Xqq1fKTY3Pjx4YrX.png" - }, - { - "symbol": "CATS", - "name": "Wise Cats Index", - "mint": "HY9LZ7TsDABoMzYfZvBwrLEUVEAWE1kGF8XS1JvbMN9u", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HY9LZ7TsDABoMzYfZvBwrLEUVEAWE1kGF8XS1JvbMN9u.png" - }, - { - "symbol": "DOGELON", - "name": "DOGELON SOLANA", - "mint": "HYoGYzMcbYq3tAvpg15d8VFYVHw6jWEVuGgpNTrG8hps", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HYoGYzMcbYq3tAvpg15d8VFYVHw6jWEVuGgpNTrG8hps.png" - }, - { - "symbol": "MORPH", - "name": "MORPH", - "mint": "HysJKMMQ4G6oEffMhf55ZPRc28zwCmpmZr63vAfUrrBq", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HysJKMMQ4G6oEffMhf55ZPRc28zwCmpmZr63vAfUrrBq.png" - }, - { - "symbol": "TWT", - "name": "Trust Wallet (Wormhole)", - "mint": "HZNpqL7RT9gxf9eWoWsWzC5DfjzQ41XTQgEA7p3VzaaD", - "decimals": 8, - "extensions": {}, - "icon": "https://img.raydium.io/icon/HZNpqL7RT9gxf9eWoWsWzC5DfjzQ41XTQgEA7p3VzaaD.png" - }, - { - "symbol": "ICE", - "name": "Fancy Diamond ICE", - "mint": "icex2Fy2KtXjfiAAUEHLPHu7XKDLvwiyVUPP9PNpSkF", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/icex2Fy2KtXjfiAAUEHLPHu7XKDLvwiyVUPP9PNpSkF.png" - }, - { - "symbol": "IDOLZ", - "name": "IDOLZ Token", - "mint": "idoLztG5ZGMVEjjoQWjeSu2eVkVsp3YnrFZKf7dNi4j", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/idoLztG5ZGMVEjjoQWjeSu2eVkVsp3YnrFZKf7dNi4j.png" - }, - { - "symbol": "IMBA", - "name": "The Lion Cats Token", - "mint": "imbaePRPNVxBhTLdSWpdjYbXiPWc9spNTz4xKVkZfBJ", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/imbaePRPNVxBhTLdSWpdjYbXiPWc9spNTz4xKVkZfBJ.png" - }, - { - "symbol": "IV", - "name": "Invoker", - "mint": "invSTFnhB1779dyku9vKSmGPxeBNKhdf7ZfGL1vTH3u", - "decimals": 9, - "extensions": { "coingeckoId": "invoke" }, - "icon": "https://img.raydium.io/icon/invSTFnhB1779dyku9vKSmGPxeBNKhdf7ZfGL1vTH3u.png" - }, - { - "symbol": "INV", - "name": "Invoke", - "mint": "invYVY53mcmBtf2RbVudoqKDyAgZGofkLYodvnQwQep", - "decimals": 9, - "extensions": { "coingeckoId": "invoke" }, - "icon": "https://img.raydium.io/icon/invYVY53mcmBtf2RbVudoqKDyAgZGofkLYodvnQwQep.png" - }, - { - "symbol": "TENU", - "name": "Tesla Inu", - "mint": "J2beWpqSSoFXzzotd9uWQe9xSHZkszAntjYD7xCdnu1K", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/J2beWpqSSoFXzzotd9uWQe9xSHZkszAntjYD7xCdnu1K.png" - }, - { - "symbol": "ATL", - "name": "Astraland", - "mint": "j4cpRFecrtvEbdLYNZb4pg7eTLDSuxUZ1BA2ratQpNa", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/j4cpRFecrtvEbdLYNZb4pg7eTLDSuxUZ1BA2ratQpNa.png" - }, - { - "symbol": "GRUNT", - "name": "GRUNT Token", - "mint": "J4tV8qjZyzwsYhGmPREDEyehCusPwa7uYm3UssQ6X4A8", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/J4tV8qjZyzwsYhGmPREDEyehCusPwa7uYm3UssQ6X4A8.png" - }, - { - "symbol": "FAROUT", - "name": "Far-Out Token", - "mint": "J5gLhk6mmQ4PSoir1Ufh8JY2ytEHA93YupzYiTFVCgcL", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/J5gLhk6mmQ4PSoir1Ufh8JY2ytEHA93YupzYiTFVCgcL.png" - }, - { - "symbol": "SOLLINX", - "name": "Sollinx", - "mint": "J5zncv7PeN3Km2BTC6hcRrZevGQX7avM9EErZtFrdTrh", - "decimals": 8, - "extensions": {}, - "icon": "https://img.raydium.io/icon/J5zncv7PeN3Km2BTC6hcRrZevGQX7avM9EErZtFrdTrh.png" - }, - { - "symbol": "MONGOOSE", - "name": "Mongoose Coin", - "mint": "J7WYVzFNynk9D28eBCccw2EYkygygiLDCVCabV7CupWL", - "decimals": 9, - "extensions": { "coingeckoId": "mongoosecoin" }, - "icon": "https://img.raydium.io/icon/J7WYVzFNynk9D28eBCccw2EYkygygiLDCVCabV7CupWL.png" - }, - { - "symbol": "ThugPandas", - "name": "Thug Pandas", - "mint": "JBK72yMfskz6tkaDCSM6bmaTf6ub7zDZUgBNxTWRAx8p", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/JBK72yMfskz6tkaDCSM6bmaTf6ub7zDZUgBNxTWRAx8p.png" - }, - { - "symbol": "ThxU", - "name": "Thank You Token", - "mint": "jbyi8caTyxtzw6vPRpZCwRv9k1rZNfxTK9yRDKFgj7P", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/jbyi8caTyxtzw6vPRpZCwRv9k1rZNfxTK9yRDKFgj7P.png" - }, - { - "symbol": "SWIM", - "name": "SWIM", - "mint": "JEHHZr57hJ7By3dL74HB9G9R77ZrTvDr1P2vSjQCAewF", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/JEHHZr57hJ7By3dL74HB9G9R77ZrTvDr1P2vSjQCAewF.png" - }, - { - "symbol": "JET", - "name": "Jet Protocol", - "mint": "JET6zMJWkCN9tpRT2v2jfAmm5VnQFDpUBCyaKojmGtz", - "decimals": 9, - "extensions": { "coingeckoId": "jet" }, - "icon": "https://img.raydium.io/icon/JET6zMJWkCN9tpRT2v2jfAmm5VnQFDpUBCyaKojmGtz.png" - }, - { - "symbol": "JTT", - "name": "Japan Travel Token", - "mint": "JTTez7NDqtU4ZqZJmLLXt6K9f75izfTApQqmvMCn4jU", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/JTTez7NDqtU4ZqZJmLLXt6K9f75izfTApQqmvMCn4jU.png" - }, - { - "symbol": "BD$", - "name": "Businessdogs Token", - "mint": "jWWi8vp5q8hcNdxQpqbJNMJ2aDpz5t8SoB1dkzYS7CL", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/jWWi8vp5q8hcNdxQpqbJNMJ2aDpz5t8SoB1dkzYS7CL.png" - }, - { - "symbol": "KITS", - "name": "Kitsune Token", - "mint": "K1Lm4h2eHqeZySJSmSA166kJj7j9s36nSaGgFJzhDnc", - "decimals": 3, - "extensions": {}, - "icon": "https://img.raydium.io/icon/K1Lm4h2eHqeZySJSmSA166kJj7j9s36nSaGgFJzhDnc.png" - }, - { - "symbol": "sBTC", - "name": "Solana Bitcoin", - "mint": "k5Ybbtmnd1eAtBZoTqB9uzd24bVPz8Aip5EGVCJXQCM", - "decimals": 8, - "extensions": {}, - "icon": "https://img.raydium.io/icon/k5Ybbtmnd1eAtBZoTqB9uzd24bVPz8Aip5EGVCJXQCM.png" - }, - { - "symbol": "VROOM", - "name": "Mushroom Racers Token", - "mint": "KARTdF5K68Q2nGppizG3DeCzp7AhHy6YXf2uTQjBSQx", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/KARTdF5K68Q2nGppizG3DeCzp7AhHy6YXf2uTQjBSQx.png" - }, - { - "symbol": "9LIVES", - "name": "9LIVES", - "mint": "KAT2oYwjN2uVj9gubM9VutCFMoX1Wq9eLiwJJEpBEX3", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/KAT2oYwjN2uVj9gubM9VutCFMoX1Wq9eLiwJJEpBEX3.png" - }, - { - "symbol": "KIRIN", - "name": "Kirin Kingdom", - "mint": "Kir4NUgYeLoHN7aBjNTfiyn3vHwZVKiyhBqN5RYBqnA", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Kir4NUgYeLoHN7aBjNTfiyn3vHwZVKiyhBqN5RYBqnA.png" - }, - { - "symbol": "OOINK", - "name": "OOINK", - "mint": "KRTapyUMe5fW92KZkYoXToFtc6Cn7UG6seaKz646oGu", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/KRTapyUMe5fW92KZkYoXToFtc6Cn7UG6seaKz646oGu.png" - }, - { - "symbol": "CUBE", - "name": "Cubecoin", - "mint": "KUPoVbJmipJb1M7xzQEND5w7u1BbmBytu9wZ2QPjQx4", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/KUPoVbJmipJb1M7xzQEND5w7u1BbmBytu9wZ2QPjQx4.png" - }, - { - "symbol": "LILY", - "name": "Solily Protocol Coin", - "mint": "LiLyT885cG9xZKYQk9x6VWMzmcui4ueV9J1uzPDDajY", - "decimals": 6, - "extensions": { "coingeckoId": "solily-protocol" }, - "icon": "https://img.raydium.io/icon/LiLyT885cG9xZKYQk9x6VWMzmcui4ueV9J1uzPDDajY.png" - }, - { - "symbol": "LUST", - "name": "Succuverse", - "mint": "LUSTdLASZy86pR6V5VjMpXxW9oVtCQt8q3fJ9iHZtPY", - "decimals": 3, - "extensions": {}, - "icon": "https://img.raydium.io/icon/LUSTdLASZy86pR6V5VjMpXxW9oVtCQt8q3fJ9iHZtPY.png" - }, - { - "symbol": "$LUV", - "name": "LUV", - "mint": "LUVumGBdVkaPYbGyjjRJtsbYoVtZ1h7AaX1Hh2bcaqn", - "decimals": 10, - "extensions": {}, - "icon": "https://img.raydium.io/icon/LUVumGBdVkaPYbGyjjRJtsbYoVtZ1h7AaX1Hh2bcaqn.png" - }, - { - "symbol": "BM", - "name": "BM", - "mint": "m6XGr58ATHSS7BvThRCDkqnsAeXLhpammhCrDo1amxq", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/m6XGr58ATHSS7BvThRCDkqnsAeXLhpammhCrDo1amxq.png" - }, - { - "symbol": "MAGA", - "name": "Magic Eggs", - "mint": "Ma4dse7fmzXLQYymNsDDjq6VgRXtEFTJw1CvmRrBoKN", - "decimals": 9, - "extensions": { "coingeckoId": "magic-eggs" }, - "icon": "https://img.raydium.io/icon/Ma4dse7fmzXLQYymNsDDjq6VgRXtEFTJw1CvmRrBoKN.png" - }, - { - "symbol": "MEEB", - "name": "Meeb Coin", - "mint": "meebAU3nZrU5PbUt3dVK6ExgbNWCUAkV7C3DaJKMZZ4", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/meebAU3nZrU5PbUt3dVK6ExgbNWCUAkV7C3DaJKMZZ4.png" - }, - { - "symbol": "MGM", - "name": "Maho Genies", - "mint": "MGM57zGF6ghF9Aax7FfoPHfxuoLKuEGM6twJALyCFqx", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/MGM57zGF6ghF9Aax7FfoPHfxuoLKuEGM6twJALyCFqx.png" - }, - { - "symbol": "NEST", - "name": "Nest Token", - "mint": "MM7s2bggZvq2DBFyBVKBBHb9DYAo3A2WGkP6L5cPzxC", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/MM7s2bggZvq2DBFyBVKBBHb9DYAo3A2WGkP6L5cPzxC.png" - }, - { - "symbol": "MMA", - "name": "mma", - "mint": "MMAx26JtJgSWv6yH48nEHCGZcVvRbf9Lt9ALa7jSipe", - "decimals": 9, - "extensions": { "coingeckoId": "mma-gaming" }, - "icon": "https://img.raydium.io/icon/MMAx26JtJgSWv6yH48nEHCGZcVvRbf9Lt9ALa7jSipe.png" - }, - { - "symbol": "MONGO", - "name": "Mongo", - "mint": "mongopjRpUgnQQpQFiasgFLyo69YXUwFcw3hyqaN8RL", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/mongopjRpUgnQQpQFiasgFLyo69YXUwFcw3hyqaN8RL.png" - }, - { - "symbol": "MONY", - "name": "Mooney Token", - "mint": "MonYu4GQb1dpoMs4DG1FpJt5F9nXtUy6JRyvANZFxZu", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/MonYu4GQb1dpoMs4DG1FpJt5F9nXtUy6JRyvANZFxZu.png" - }, - { - "symbol": "MOSHI", - "name": "MOSHI", - "mint": "MoshMwLkVu4iwrPBaWpYkh43qJiSXsnyzNLuMXFv5F4", - "decimals": 9, - "extensions": { "coingeckoId": "moshiheads" }, - "icon": "https://img.raydium.io/icon/MoshMwLkVu4iwrPBaWpYkh43qJiSXsnyzNLuMXFv5F4.png" - }, - { - "symbol": "MNRL", - "name": "MNRL", - "mint": "MRLY2ScVMxXJTieiDi2Ywdm8VjEKeLcY4THL2UyhHRA", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/MRLY2ScVMxXJTieiDi2Ywdm8VjEKeLcY4THL2UyhHRA.png" - }, - { - "symbol": "LMAO", - "name": "Solana Alien Business", - "mint": "N1CfKy2UEQmvQeQgELMXuHX9KRGQa6ayTrYUSqsL7TG", - "decimals": 6, - "extensions": {}, - "icon": "" - }, - { - "symbol": "EWOOF", - "name": "ElonWoof", - "mint": "NA45Qgq1xn2EcrrKik7o9rVPMSgmDXK6kv8134Q8ADW", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/NA45Qgq1xn2EcrrKik7o9rVPMSgmDXK6kv8134Q8ADW.png" - }, - { - "symbol": "NAGA", - "name": "Naga Kingdom", - "mint": "NaFJTgvemQFfTTGAq2PR1uBny3NENWMur5k6eBsG5ii", - "decimals": 9, - "extensions": { "coingeckoId": "naga-kingdom" }, - "icon": "https://img.raydium.io/icon/NaFJTgvemQFfTTGAq2PR1uBny3NENWMur5k6eBsG5ii.png" - }, - { - "symbol": "NEO", - "name": "NEO3D TOKEN", - "mint": "NEo3D6MXRXf2iAfaqvZYqSmFkfutLvNjm86xmfGWNh5", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/NEo3D6MXRXf2iAfaqvZYqSmFkfutLvNjm86xmfGWNh5.png" - }, - { - "symbol": "NOVAX", - "name": "NOVAX", - "mint": "NovNrxPNjmLVFscH5rjMbec7C4BdAHms9WK21xjsP3p", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/NovNrxPNjmLVFscH5rjMbec7C4BdAHms9WK21xjsP3p.png" - }, - { - "symbol": "NSPACE", - "name": "My NFT Space", - "mint": "NpgsBSfavf5hmUeGQAbMz5pHDtXhn9ZFNRQypTr8Tfv", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/NpgsBSfavf5hmUeGQAbMz5pHDtXhn9ZFNRQypTr8Tfv.png" - }, - { - "symbol": "MECH", - "name": "MECH - Art Mechanism", - "mint": "NXH66NhJZ3woe1KCYFGwSJHTtpELuv4Mf8YoVthWtce", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/NXH66NhJZ3woe1KCYFGwSJHTtpELuv4Mf8YoVthWtce.png" - }, - { - "symbol": "TMI", - "name": "TUMI", - "mint": "p9tNnBf4PDA7WSSFj5EVZddai6WoEiNk5B5FMyeQLtu", - "decimals": 8, - "extensions": {}, - "icon": "https://img.raydium.io/icon/p9tNnBf4PDA7WSSFj5EVZddai6WoEiNk5B5FMyeQLtu.png" - }, - { - "symbol": "PAPPA", - "name": "Psychic Warriors of Pappataz", - "mint": "PaPa6D4Rys4Lcj1d5csabmDv3QdUE2T1QQ6sWNgoeTa", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/PaPa6D4Rys4Lcj1d5csabmDv3QdUE2T1QQ6sWNgoeTa.png" - }, - { - "symbol": "BXS", - "name": "Bancambios AX", - "mint": "pH5wWJc3KhdeVQSt86DU31pdcL9c8P88x2FQoKEJVHC", - "decimals": 9, - "extensions": { "coingeckoId": "bancambios-ax" }, - "icon": "https://img.raydium.io/icon/pH5wWJc3KhdeVQSt86DU31pdcL9c8P88x2FQoKEJVHC.png" - }, - { - "symbol": "PIKA", - "name": "Pikachu", - "mint": "Pika2wSYzve4njHBwcqzp2QZPr8w18hRwAkugf13BxK", - "decimals": 3, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Pika2wSYzve4njHBwcqzp2QZPr8w18hRwAkugf13BxK.png" - }, - { - "symbol": "PRIME", - "name": "SolanaPrime", - "mint": "PRiME7gDoiG1vGr95a3CRMv9xHY7UGjd4JKvfSkmQu2", - "decimals": 9, - "extensions": { "coingeckoId": "solanaprime" }, - "icon": "https://img.raydium.io/icon/PRiME7gDoiG1vGr95a3CRMv9xHY7UGjd4JKvfSkmQu2.png" - }, - { - "symbol": "PUPPY", - "name": "Puppy", - "mint": "puppy8Lhckjh768j7vCPLr4244a64ZqioskcXxyb4rC", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/puppy8Lhckjh768j7vCPLr4244a64ZqioskcXxyb4rC.png" - }, - { - "symbol": "TRTLS", - "name": "Turtles Token", - "mint": "q4bpaRKw3fJB1AJBeeBaKv3TjYzWsmntLgnSB275YUb", - "decimals": 9, - "extensions": { "coingeckoId": "turtles-token" }, - "icon": "https://img.raydium.io/icon/q4bpaRKw3fJB1AJBeeBaKv3TjYzWsmntLgnSB275YUb.png" - }, - { - "symbol": "BURD", - "name": "tudaBirds Token", - "mint": "Qikhhhg9Ta3Jg7WoDFbSYuCAE14hx9hPvdz1zVp3zUw", - "decimals": 9, - "extensions": { "coingeckoId": "tudabirds" }, - "icon": "https://img.raydium.io/icon/Qikhhhg9Ta3Jg7WoDFbSYuCAE14hx9hPvdz1zVp3zUw.png" - }, - { - "symbol": "STVA", - "name": "SOLtiva", - "mint": "qXu8Tj65H5XR8KHuaKKoyLCWj592KbTG3YWJwsuFrPS", - "decimals": 3, - "extensions": {}, - "icon": "https://img.raydium.io/icon/qXu8Tj65H5XR8KHuaKKoyLCWj592KbTG3YWJwsuFrPS.png" - }, - { - "symbol": "DAOJONES", - "name": "Fractionalized SMB-2367", - "mint": "r8nuuzXCchjtqsmQZVZDPXXq928tuk7KVH479GsKVpy", - "decimals": 2, - "extensions": { "coingeckoId": "fractionalized-smb-2367" }, - "icon": "https://img.raydium.io/icon/r8nuuzXCchjtqsmQZVZDPXXq928tuk7KVH479GsKVpy.png" - }, - { - "symbol": "RLB", - "name": "Rollbit Coin", - "mint": "RLBxxFkseAZ4RgJH3Sqn8jXxhmGoz9jWxDNJMh8pL7a", - "decimals": 2, - "extensions": { "coingeckoId": "rollbit-coin" }, - "icon": "https://img.raydium.io/icon/RLBxxFkseAZ4RgJH3Sqn8jXxhmGoz9jWxDNJMh8pL7a.png" - }, - { - "symbol": "sRLY", - "name": "Rally (Solana)", - "mint": "RLYv2ubRMDLcGG2UyvPmnPmkfuQTsMbg4Jtygc7dmnq", - "decimals": 9, - "extensions": { "coingeckoId": "rally-solana" }, - "icon": "https://img.raydium.io/icon/RLYv2ubRMDLcGG2UyvPmnPmkfuQTsMbg4Jtygc7dmnq.png" - }, - { - "symbol": "ROCK", - "name": "RockDeFi", - "mint": "roCKojKezC7HhPxph5qb4UBasvmZJWgegCF57PvaV2f", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/roCKojKezC7HhPxph5qb4UBasvmZJWgegCF57PvaV2f.png" - }, - { - "symbol": "ROL", - "name": "ROL", - "mint": "RoLLn5qBN4juQ1D2KFpJyAcC7Deo3cYotXi4qDooHLU", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/RoLLn5qBN4juQ1D2KFpJyAcC7Deo3cYotXi4qDooHLU.png" - }, - { - "symbol": "SMRAI", - "name": "SMRAI", - "mint": "rvxo8t7TKeSmAgpdqK1CY9ddZi3NyowRCh1m2d7KrUc", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/rvxo8t7TKeSmAgpdqK1CY9ddZi3NyowRCh1m2d7KrUc.png" - }, - { - "symbol": "VERSE", - "name": "Verse Token", - "mint": "S8v4cS7dnKzV6LYvzFPuuiWQMM4KSz7URuGYWMGXyTG", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/S8v4cS7dnKzV6LYvzFPuuiWQMM4KSz7URuGYWMGXyTG.png" - }, - { - "symbol": "SAMU", - "name": "Samusky Token", - "mint": "SAMUmmSvrE8yqtcG94oyP1Zu2P9t8PSRSV3vewsGtPM", - "decimals": 9, - "extensions": { "coingeckoId": "samusky-token" }, - "icon": "https://img.raydium.io/icon/SAMUmmSvrE8yqtcG94oyP1Zu2P9t8PSRSV3vewsGtPM.png" - }, - { - "symbol": "RUM", - "name": "Dope Pirates RUM", - "mint": "sFA2de5kRsAmCev2WAoPCXbCKEd1ZwkvJ3MxPMojw9h", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/sFA2de5kRsAmCev2WAoPCXbCKEd1ZwkvJ3MxPMojw9h.png" - }, - { - "symbol": "SGT", - "name": "Solana Ghoest Token", - "mint": "SGTdtpAiPU1Fg9a3DqUN1852V24sfo92ePEHpyqkrSN", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/SGTdtpAiPU1Fg9a3DqUN1852V24sfo92ePEHpyqkrSN.png" - }, - { - "symbol": "SKULL", - "name": "Skeleton Crew", - "mint": "SKu11EypaFU3gvr8VSAbi13zEC2CPvqbz9s83N3tWHM", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/SKu11EypaFU3gvr8VSAbi13zEC2CPvqbz9s83N3tWHM.png" - }, - { - "symbol": "SLNA", - "name": "Soluna Governance Token", - "mint": "SLNAAQ8VT6DRDc3W9UPDjFyRt7u4mzh8Z4WYMDjJc35", - "decimals": 6, - "extensions": { "coingeckoId": "soluna" }, - "icon": "https://img.raydium.io/icon/SLNAAQ8VT6DRDc3W9UPDjFyRt7u4mzh8Z4WYMDjJc35.png" - }, - { - "symbol": "SLT", - "name": "Solit", - "mint": "SLT3iSYKeBuCyxvnfij4RUhMfKxZCY3s12Z5pfkTXhV", - "decimals": 6, - "extensions": { "coingeckoId": "solit" }, - "icon": "https://img.raydium.io/icon/SLT3iSYKeBuCyxvnfij4RUhMfKxZCY3s12Z5pfkTXhV.png" - }, - { - "symbol": "SODA", - "name": "cheesesoda token", - "mint": "sodaNXUbtjMvHe9c5Uw7o7VAcVpXPHAvtaRaiPVJQuE", - "decimals": 0, - "extensions": { "coingeckoId": "cheesesoda-token" }, - "icon": "https://img.raydium.io/icon/sodaNXUbtjMvHe9c5Uw7o7VAcVpXPHAvtaRaiPVJQuE.png" - }, - { - "symbol": "SPRAY", - "name": "SPRAY", - "mint": "SPraYi59a21jEhqvPBbWuwmjA4vdTaSLbiRTefcHJSR", - "decimals": 4, - "extensions": {}, - "icon": "https://img.raydium.io/icon/SPraYi59a21jEhqvPBbWuwmjA4vdTaSLbiRTefcHJSR.png" - }, - { - "symbol": "SUNNY", - "name": "Sunny Governance Token", - "mint": "SUNNYWgPQmFxe9wTZzNK7iPnJ3vYDrkgnxJRJm1s3ag", - "decimals": 6, - "extensions": { "coingeckoId": "sunny-aggregator" }, - "icon": "https://img.raydium.io/icon/SUNNYWgPQmFxe9wTZzNK7iPnJ3vYDrkgnxJRJm1s3ag.png" - }, - { - "symbol": "SWAN", - "name": "Swanlana", - "mint": "SWANaZUGxF82KyVsbxeeNsMaVECtimze5VyCdywkvkH", - "decimals": 9, - "extensions": { "coingeckoId": "swanlana" }, - "icon": "https://img.raydium.io/icon/SWANaZUGxF82KyVsbxeeNsMaVECtimze5VyCdywkvkH.png" - }, - { - "symbol": "TABBY", - "name": "TABBY", - "mint": "tABbYiZsg2msMsPx9wZeJVJpBdCBdGBKDMTuy3XnH2V", - "decimals": 8, - "extensions": {}, - "icon": "https://img.raydium.io/icon/tABbYiZsg2msMsPx9wZeJVJpBdCBdGBKDMTuy3XnH2V.png" - }, - { - "symbol": "TENKAI", - "name": "Tenkai Token", - "mint": "TKDrcm3n4mfXFfPKZoLp5soRSdFQSmyWLdomdKL3ktU", - "decimals": 0, - "extensions": {}, - "icon": "https://img.raydium.io/icon/TKDrcm3n4mfXFfPKZoLp5soRSdFQSmyWLdomdKL3ktU.png" - }, - { - "symbol": "TKMK", - "name": "TOKAMAK ON SOLANA", - "mint": "TKMKgSh3aADsmjr4yFWG52tkCQvmDxsQC1he1aBsi65", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/TKMKgSh3aADsmjr4yFWG52tkCQvmDxsQC1he1aBsi65.png" - }, - { - "symbol": "MRTS", - "name": "MERITS", - "mint": "ToTuLunrMF2eQtvj7p6UtU7Jc38mbZZ8do21fg61Qg6", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/ToTuLunrMF2eQtvj7p6UtU7Jc38mbZZ8do21fg61Qg6.png" - }, - { - "symbol": "TREN", - "name": "Trenbolone", - "mint": "TRENpVRAR9LiZgyYv9zWrQwYqSHa7ThCYdbpFCJixj1", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/TRENpVRAR9LiZgyYv9zWrQwYqSHa7ThCYdbpFCJixj1.png" - }, - { - "symbol": "TIEXO", - "name": "Tiexo", - "mint": "TX2FnsJkWvAyjSRoEZsCkDu4ViwZDEYMehiT6U6PXKj", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/TX2FnsJkWvAyjSRoEZsCkDu4ViwZDEYMehiT6U6PXKj.png" - }, - { - "symbol": "rTHUG", - "name": "Random Thugbirdz", - "mint": "ugKuq43fnPEcEeH12gCfETbshMRJ8nD2qXmcbyNHaEb", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/ugKuq43fnPEcEeH12gCfETbshMRJ8nD2qXmcbyNHaEb.png" - }, - { - "symbol": "DRIPP", - "name": "Drippies Floor Index", - "mint": "uL2qhMckUAroJPt2MLHwEeppJNYE3wBAGFMCs3anwXn", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/uL2qhMckUAroJPt2MLHwEeppJNYE3wBAGFMCs3anwXn.png" - }, - { - "symbol": "UNKN", - "name": "UNKN", - "mint": "unknXbA1bDg39nuBqVgMNZ5qSZa8pw5HditgkPe5eFA", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/unknXbA1bDg39nuBqVgMNZ5qSZa8pw5HditgkPe5eFA.png" - }, - { - "symbol": "UNQ", - "name": "UNQ", - "mint": "UNQtEecZ5Zb4gSSVHCAWUQEoNnSVEbWiKCi1v9kdUJJ", - "decimals": 6, - "extensions": { "coingeckoId": "unq" }, - "icon": "https://img.raydium.io/icon/UNQtEecZ5Zb4gSSVHCAWUQEoNnSVEbWiKCi1v9kdUJJ.png" - }, - { - "symbol": "SBNK", - "name": "Solbank", - "mint": "uNrix3Q5g51MCEUrYBUEBDdQ96RQDQspQJJnnQ4T3Vc", - "decimals": 6, - "extensions": { "coingeckoId": "solbank-token" }, - "icon": "https://img.raydium.io/icon/uNrix3Q5g51MCEUrYBUEBDdQ96RQDQspQJJnnQ4T3Vc.png" - }, - { - "symbol": "USDR", - "name": "RockDeFi Stablecoin", - "mint": "usdrQqxAGgWsBRzzcckAi9ZAzHp19rFCNn87p4Q8Eir", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/usdrQqxAGgWsBRzzcckAi9ZAzHp19rFCNn87p4Q8Eir.png" - }, - { - "symbol": "BABY", - "name": "Baby Samo Coin", - "mint": "Uuc6hiKT9Y6ASoqs2phonGGw2LAtecfJu9yEohppzWH", - "decimals": 9, - "extensions": { "coingeckoId": "baby-samo-coin" }, - "icon": "https://img.raydium.io/icon/Uuc6hiKT9Y6ASoqs2phonGGw2LAtecfJu9yEohppzWH.png" - }, - { - "symbol": "CHEERS", - "name": "Secret Kongz Cheers", - "mint": "UXRj3sUsJsQ6mkDz8xmXQxnY7DHoyZzX1UtEZriqbmC", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/UXRj3sUsJsQ6mkDz8xmXQxnY7DHoyZzX1UtEZriqbmC.png" - }, - { - "symbol": "GON", - "name": "MetaDrago Token", - "mint": "v7bs339b8oqXgYGJu4mX9cB8tZrFVSozBjW6QZZKE3m", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/v7bs339b8oqXgYGJu4mX9cB8tZrFVSozBjW6QZZKE3m.png" - }, - { - "symbol": "rZOOM", - "name": "Random Zaysan Raptors", - "mint": "Vjq9T5xmqRzLXQRyvigzyZzpHCGCsbYAJ7afLVuF8j9", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Vjq9T5xmqRzLXQRyvigzyZzpHCGCsbYAJ7afLVuF8j9.png" - }, - { - "symbol": "MOONRACE", - "name": "Moonrace", - "mint": "vqU8NVkkgpFtt3YECwuQRD3RhX7LYaqZKrotZbdiBJn", - "decimals": 3, - "extensions": {}, - "icon": "https://img.raydium.io/icon/vqU8NVkkgpFtt3YECwuQRD3RhX7LYaqZKrotZbdiBJn.png" - }, - { - "symbol": "SIM", - "name": "Serious Internet Money", - "mint": "w71tgPPw37F7sCxxq1bcT63D3dtV6bJ7MUD3q7fpLqg", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/w71tgPPw37F7sCxxq1bcT63D3dtV6bJ7MUD3q7fpLqg.png" - }, - { - "symbol": "CRYPTO", - "name": "Cryptocurrency Coin", - "mint": "WCGXaSoSWgwBwpFzCq42eFpLFemLTCNPrAYEQt2eVmm", - "decimals": 8, - "extensions": {}, - "icon": "https://img.raydium.io/icon/WCGXaSoSWgwBwpFzCq42eFpLFemLTCNPrAYEQt2eVmm.png" - }, - { - "symbol": "DIRE", - "name": "DireWolf", - "mint": "WoLFWyFspu68aHQeKRbgYPma6H16cHPXErJK8o3sczb", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/WoLFWyFspu68aHQeKRbgYPma6H16cHPXErJK8o3sczb.png" - }, - { - "symbol": "WOS", - "name": "World of Solana", - "mint": "WoSZYtctzp48xcdsSfGNKUGhjNdPx2qm5J2TUNfd1a1", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/WoSZYtctzp48xcdsSfGNKUGhjNdPx2qm5J2TUNfd1a1.png" - }, - { - "symbol": "BUM", - "name": "Beach Bum Billionaires", - "mint": "woTu6cugnrEw6tZqePeXrHGbSJJVsBdHgmQwxTER4R3", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/woTu6cugnrEw6tZqePeXrHGbSJJVsBdHgmQwxTER4R3.png" - }, - { - "symbol": "wrBTC", - "name": "Wrapped BTC (Player 2)", - "mint": "wrBTCqVjkpqktbqN3CeGVSzQ9PFiPonHN98uwEpwMsy", - "decimals": 6, - "extensions": {}, - "icon": "https://img.raydium.io/icon/wrBTCqVjkpqktbqN3CeGVSzQ9PFiPonHN98uwEpwMsy.png" - }, - { - "symbol": "WUR", - "name": "Wrapped WUR", - "mint": "Wurx1CQEpuo8ExhWaMYrz9KErXBrKAdz64ZoRKSjuXy", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Wurx1CQEpuo8ExhWaMYrz9KErXBrKAdz64ZoRKSjuXy.png" - }, - { - "symbol": "MRB", - "name": "MetaRoyalBank", - "mint": "X2m83B2T6y92qcq1am2z3FKXCzzmKNVxUGXxFWa7x8c", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/X2m83B2T6y92qcq1am2z3FKXCzzmKNVxUGXxFWa7x8c.png" - }, - { - "symbol": "XENO", - "name": "Xenobots Fuel", - "mint": "XenomnZ7kLQxfENcKKpfC8tov3GoZiW4XrDmPc8HRxd", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/XenomnZ7kLQxfENcKKpfC8tov3GoZiW4XrDmPc8HRxd.png" - }, - { - "symbol": "$DRAY", - "name": "DRAY", - "mint": "xkqjobmo1kUgN4P7jcsWe5ud657oA3co4PnwKoQKG12", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/xkqjobmo1kUgN4P7jcsWe5ud657oA3co4PnwKoQKG12.png" - }, - { - "symbol": "BURR", - "name": "Burrito Boyz Floor Index", - "mint": "XwTZraiF1dVh69cZ2SpqyjDLmei2uVps5CYHD9vqK6d", - "decimals": 2, - "extensions": {}, - "icon": "https://img.raydium.io/icon/XwTZraiF1dVh69cZ2SpqyjDLmei2uVps5CYHD9vqK6d.png" - }, - { - "symbol": "STEAK", - "name": "STEAK", - "mint": "Y71XaLmJPvuPY4h4LnTZfFgSR6vP3qCxGLpCx25JTMA", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/Y71XaLmJPvuPY4h4LnTZfFgSR6vP3qCxGLpCx25JTMA.png" - }, - { - "symbol": "CHB", - "name": "Charactbit", - "mint": "YtfMZ4jg2ubdz4GasY86iuGjHdo5rCPJnFqgSf8gxAz", - "decimals": 9, - "extensions": { "coingeckoId": "charactbit" }, - "icon": "https://img.raydium.io/icon/YtfMZ4jg2ubdz4GasY86iuGjHdo5rCPJnFqgSf8gxAz.png" - }, - { - "symbol": "CODI", - "name": "CODI", - "mint": "yvbrxE6zjrA8SxxSpL7oojDBB5QDmF5CVqJWea8JcQE", - "decimals": 9, - "extensions": { "coingeckoId": "codi-finance" }, - "icon": "https://img.raydium.io/icon/yvbrxE6zjrA8SxxSpL7oojDBB5QDmF5CVqJWea8JcQE.png" - }, - { - "symbol": "CRC", - "name": "Care Coin Token", - "mint": "z9WZXekbCtwoxyfAwEJn1euXybvqLzPVv3NDzJzkq7C", - "decimals": 9, - "extensions": { "coingeckoId": "care-coin" }, - "icon": "https://img.raydium.io/icon/z9WZXekbCtwoxyfAwEJn1euXybvqLzPVv3NDzJzkq7C.png" - }, - { - "symbol": "ZEE", - "name": "ZEE", - "mint": "ZEExktbqMM5ZMS569pCNbzky92KeEmiFeVwR3exfBNn", - "decimals": 0, - "extensions": { "coingeckoId": "zoints" }, - "icon": "https://img.raydium.io/icon/ZEExktbqMM5ZMS569pCNbzky92KeEmiFeVwR3exfBNn.png" - }, - { - "symbol": "JUUJUU", - "name": "JUUJUU", - "mint": "zmFoYNC3CuGY1VmgAcxXzfLMnSMVZpJF6RGJU5vDxvT", - "decimals": 9, - "extensions": {}, - "icon": "https://img.raydium.io/icon/zmFoYNC3CuGY1VmgAcxXzfLMnSMVZpJF6RGJU5vDxvT.png" - }, - { - "symbol": "SOLPAY", - "name": "SOLPAY", - "mint": "zwqe1Nd4eiWyCcqdo4FgCq7LYZHdSeGKKudv6RwiAEn", - "decimals": 9, - "extensions": { "coingeckoId": "solpay-finance" }, - "icon": "" - } - ], - "unNamed": [ - { "mint": "2nkxLptGxQCfaar541Cr87G4v6VuA6BvVWqxsHNVCYoA", "decimals": 6 }, - { "mint": "7WVMpKPcpDp6ezRp5uw4R1MZchQkDuFGaudCa87MA1aR", "decimals": 9 } - ], - "blacklist": [] -} diff --git a/farms/farm-ctrl/metadata/tokens/raydium/tokens_dev.json b/farms/farm-ctrl/metadata/tokens/raydium/tokens_dev.json deleted file mode 100644 index 00a28bf48c9..00000000000 --- a/farms/farm-ctrl/metadata/tokens/raydium/tokens_dev.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "name": "Solana Token List", - "logoURI": "https://cdn.jsdelivr.net/gh/trustwallet/assets@master/blockchains/solana/info/logo.png", - "keywords": ["solana", "spl"], - "tags": { - "stablecoin": { - "name": "stablecoin", - "description": "Tokens that are fixed to an external asset, e.g. the US dollar" - }, - "ethereum": { - "name": "ethereum", - "description": "Asset bridged from ethereum" - }, - "lp-token": { - "name": "lp-token", - "description": "Asset representing liquidity provider token" - }, - "wrapped-sollet": { - "name": "wrapped-sollet", - "description": "Asset wrapped using sollet bridge" - }, - "wrapped": { - "name": "wrapped", - "description": "Asset wrapped using wormhole bridge" - }, - "leveraged": { - "name": "leveraged", - "description": "Leveraged asset" - }, - "bull": { - "name": "bull", - "description": "Leveraged Bull asset" - }, - "bear": { - "name": "bear", - "description": "Leveraged Bear asset" - }, - "nft": { - "name": "nft", - "description": "Non-fungible token" - }, - "security-token": { - "name": "security-token", - "description": "Tokens that are used to gain access to an electronically restricted resource" - }, - "utility-token": { - "name": "utility-token", - "description": "Tokens that are designed to be spent within a certain blockchain ecosystem e.g. most of the SPL-Tokens" - }, - "tokenized-stock": { - "name": "tokenized-stock", - "description": "Tokenized stocks are tokenized derivatives that represent traditional securities, particularly shares in publicly firms traded on regulated exchanges" - } - }, - "timestamp": "2021-03-03T19:57:21+0000", - "tokens": [ - { - "chainId": 101, - "address": "So11111111111111111111111111111111111111112", - "symbol": "SOL", - "name": "Wrapped SOL", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/So11111111111111111111111111111111111111112/logo.png", - "tags": [], - "extensions": { - "website": "https://solana.com/", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "coingeckoId": "solana" - } - }, - { - "chainId": 101, - "address": "BEcGFQK1T1tSu3kvHC17cyCkQ5dvXqAJ7ExB2bb5Do7a", - "symbol": "COIN", - "name": "Wrapped COIN", - "decimals": 6, - "logoURI": "", - "tags": [], - "extensions": { - "website": "https://solana.com/" - } - }, - { - "chainId": 101, - "address": "FSRvxBNrQWX2Fy2qvKMLL3ryEdRtE3PUTZBcdKwASZTU", - "symbol": "PC", - "name": "Wrapped PC", - "decimals": 6, - "logoURI": "", - "tags": [], - "extensions": { - "website": "https://solana.com/" - } - } - ], - "version": { - "major": 0, - "minor": 2, - "patch": 2 - } -} diff --git a/farms/farm-ctrl/metadata/tokens/saber/get_tokens.sh b/farms/farm-ctrl/metadata/tokens/saber/get_tokens.sh deleted file mode 100644 index 2acd166bef0..00000000000 --- a/farms/farm-ctrl/metadata/tokens/saber/get_tokens.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -url="https://registry.saber.so/data/token-list.mainnet.json" - -if hash wget 2>/dev/null; then - wget_or_curl="wget -O tokens.json $url" -elif hash curl 2>/dev/null; then - wget_or_curl="curl -o tokens.json -L $url" -else - echo "Error: Neither curl nor wget were found" >&2 - return 1 -fi - -exec $wget_or_curl \ No newline at end of file diff --git a/farms/farm-ctrl/metadata/tokens/saber/get_tokens_dev.sh b/farms/farm-ctrl/metadata/tokens/saber/get_tokens_dev.sh deleted file mode 100644 index 89a2b476530..00000000000 --- a/farms/farm-ctrl/metadata/tokens/saber/get_tokens_dev.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -url="https://registry.saber.so/data/token-list.devnet.json" - -if hash wget 2>/dev/null; then - wget_or_curl="wget -O tokens_dev.json $url" -elif hash curl 2>/dev/null; then - wget_or_curl="curl -o tokens_dev.json -L $url" -else - echo "Error: Neither curl nor wget were found" >&2 - return 1 -fi - -exec $wget_or_curl \ No newline at end of file diff --git a/farms/farm-ctrl/metadata/tokens/saber/tokens.json b/farms/farm-ctrl/metadata/tokens/saber/tokens.json deleted file mode 100644 index 8ca696bb7a2..00000000000 --- a/farms/farm-ctrl/metadata/tokens/saber/tokens.json +++ /dev/null @@ -1,3970 +0,0 @@ -{ - "logoURI": "https://registry.saber.so/icon.png", - "name": "Saber Tokens", - "tags": { - "ethereum": { - "description": "Asset bridged from ethereum", - "name": "ethereum" - }, - "saber-dec-wrapped": { - "description": "Decimal wrapper for a different token. See `assetContract` for the mint of the underlying.", - "name": "saber-dec-wrapped" - }, - "saber-hidden": { - "description": "Hidden from main Saber UI.", - "name": "saber-hidden" - }, - "saber-mkt-btc": { - "description": "Token which trades against other representations of BTC.", - "name": "saber-mkt-btc" - }, - "saber-mkt-eth": { - "description": "Token which trades against other representations of ETH.", - "name": "saber-mkt-eth" - }, - "saber-mkt-eur": { - "description": "Token which trades against other representations of EUR.", - "name": "saber-mkt-eur" - }, - "saber-mkt-ftt": { - "description": "Token which trades against other representations of FTT.", - "name": "saber-mkt-ftt" - }, - "saber-mkt-luna": { - "description": "Token which trades against other representations of LUNA.", - "name": "saber-mkt-luna" - }, - "saber-mkt-sol": { - "description": "Token which trades against other representations of SOL.", - "name": "saber-mkt-sol" - }, - "saber-mkt-srm": { - "description": "Token which trades against other representations of SRM.", - "name": "saber-mkt-srm" - }, - "saber-mkt-try": { - "description": "Token which trades against other representations of TRY.", - "name": "saber-mkt-try" - }, - "saber-mkt-usd": { - "description": "Token which trades against other representations of USD.", - "name": "saber-mkt-usd" - }, - "saber-stableswap-lp": { - "description": "Saber StableSwap LP token.", - "name": "saber-stableswap-lp" - }, - "stablecoin": { - "description": "Tokens that are fixed to an external asset, e.g. the US dollar", - "name": "stablecoin" - }, - "utility-token": { - "description": "Tokens that are designed to be spent within a certain blockchain ecosystem e.g. most of the SPL-Tokens", - "name": "utility-token" - }, - "wormhole-v1": { - "description": "Wormhole V1 asset.", - "name": "wormhole-v1" - }, - "wormhole-v2": { - "description": "Wormhole V2 asset.", - "name": "wormhole-v2" - }, - "wrapped": { - "description": "Asset wrapped using wormhole bridge", - "name": "wrapped" - }, - "wrapped-sollet": { - "description": "Asset wrapped using sollet bridge", - "name": "wrapped-sollet" - } - }, - "timestamp": "2022-01-31T21:45:37.097Z", - "tokens": [ - { - "address": "2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "magic-internet-money", - "currency": "USD", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj.png", - "name": "Wrapped MIM (Allbridge from Ethereum)", - "symbol": "aeMIM", - "tags": ["saber-mkt-usd"] - }, - { - "address": "2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk", - "chainId": 101, - "decimals": 6, - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "coingeckoId": "ethereum", - "currency": "ETH", - "serumV3Usdc": "4tSvZvnbyzHXLMTiFonMyxZoHmFqau1XArcRCVHLZ5gX", - "serumV3Usdt": "7dLVkUfBVfCGkFhSXDCq1ukM9usathSgS716t643iFGF", - "source": "sollet", - "sourceUrl": "https://www.sollet.io/" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk.png", - "name": "Wrapped Ethereum (Sollet)", - "symbol": "soETH", - "tags": ["wrapped-sollet", "ethereum", "saber-mkt-eth"] - }, - { - "address": "2Xf2yAXJfg82sWwdLUo2x9mZXy6JCdszdMZkcF1Hf4KV", - "chainId": 101, - "decimals": 9, - "extensions": { - "address": "0xd2877702675e6cEb975b4A1dFf9fb7BAF4C91ea9", - "assetContract": "https://etherscan.io/address/0xd2877702675e6cEb975b4A1dFf9fb7BAF4C91ea9", - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "coingeckoId": "wrapped-terra", - "currency": "LUNA", - "source": "wormhole-v1", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/2Xf2yAXJfg82sWwdLUo2x9mZXy6JCdszdMZkcF1Hf4KV.png", - "name": "Wrapped LUNA Token (Wormhole v1)", - "symbol": "wLUNA_v1", - "tags": ["wrapped", "wormhole", "saber-mkt-luna", "wormhole-v1"] - }, - { - "address": "2jXy799YnEcRXneFo2GEAB6SDRsAa767HpWmktRr1DaP", - "chainId": 101, - "decimals": 6, - "extensions": { - "coingeckoId": "serum", - "currency": "SRM", - "source": "wormhole-v1", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt.png", - "name": "Serum (Wormhole V1)", - "symbol": "wSRM_V1", - "tags": ["saber-mkt-srm", "wormhole-v1"] - }, - { - "address": "2kycGCD8tJbrjJJqWN2Qz5ysN9iB4Bth3Uic4mSB7uak", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "usdk", - "currency": "USD", - "source": "wormhole-v1", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "logoURI": "https://registry.saber.so/token-icons/usdk.png", - "name": "USDK (Wormhole V1)", - "symbol": "wUSDK_V1", - "tags": ["saber-mkt-usd", "wormhole-v1"] - }, - { - "address": "2poo1dNgDaVaZbLsqq4cbNz9hWZ3MFz3hpErfT7SRWxu", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" - ], - "website": "https://app.saber.so/#/pools/YakoMPuYrybnr9R7VC7hVGxMz94fJvPFCdZ4gmW61Ed" - }, - "logoURI": "https://registry.saber.so/token-icons/slp.png", - "name": "Saber USDC-USDT LP", - "symbol": "USDC-USDT", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "2poo1w1DL6yd2WNTCnNTzDqkC6MBXq7axo77P16yrBuf", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" - ], - "website": "https://app.saber.so/#/pools/usdc_usdt" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/2poo1w1DL6yd2WNTCnNTzDqkC6MBXq7axo77P16yrBuf.png", - "name": "Saber USDT-USDC LP", - "symbol": "USDT-USDC", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "33fsBLA8djQm82RpHmE3SuVrPGtZBWNYExsEUeKX1HXX", - "chainId": 101, - "decimals": 8, - "extensions": { - "address": "0x4fabb145d64652a948d72533023f6e7a623c7c53", - "assetContract": "https://etherscan.io/address/0x4fabb145d64652a948d72533023f6e7a623c7c53", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "binance-usd", - "currency": "USD", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/33fsBLA8djQm82RpHmE3SuVrPGtZBWNYExsEUeKX1HXX.png", - "name": "Binance USD (Wormhole from Ethereum)", - "symbol": "BUSDet", - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"] - }, - { - "address": "3LKZU3iQx9KM94S4uYRdYwAHTm6odDyzGQqTBNj7J27z", - "chainId": 101, - "decimals": 9, - "extensions": { - "currency": "LUNA", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/3LKZU3iQx9KM94S4uYRdYwAHTm6odDyzGQqTBNj7J27z.png", - "name": "Wrapped Luna (Allbridge from Terra)", - "symbol": "atLUNA", - "tags": ["saber-mkt-luna"] - }, - { - "address": "3RudPTAkfcq9Q9Jk8SVeCoecCBmdKMj6q5smsWzxqtqZ", - "chainId": 101, - "decimals": 6, - "extensions": { - "currency": "USD", - "source": "port", - "sourceUrl": "https://mainnet.port.finance/#/markets", - "website": "https://port.finance" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/3RudPTAkfcq9Q9Jk8SVeCoecCBmdKMj6q5smsWzxqtqZ.svg", - "name": "Port Finance USDT", - "symbol": "pUSDT", - "tags": ["port", "lending", "collateral-tokens", "saber-mkt-usd"] - }, - { - "address": "3os2M3bX9qta154PRbU9rzaPUYAKAqVpaMMS8u2hoUQu", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "wrapped-bitcoin", - "currency": "BTC", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/3os2M3bX9qta154PRbU9rzaPUYAKAqVpaMMS8u2hoUQu.png", - "name": "Wrapped BTC (Allbridge from BSC)", - "symbol": "abBTCB", - "tags": ["saber-mkt-btc"] - }, - { - "address": "43m2ewFV5nDepieFjT9EmAQnc1HRtAF247RBpLGFem5F", - "chainId": 101, - "decimals": 8, - "extensions": { - "address": "0x1c48f86ae57291f7686349f12601910bd8d470bb", - "assetContract": "https://etherscan.io/address/0x1c48f86ae57291f7686349f12601910bd8d470bb", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "usdk", - "currency": "USD", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/43m2ewFV5nDepieFjT9EmAQnc1HRtAF247RBpLGFem5F.png", - "name": "USDK (Wormhole)", - "symbol": "USDK", - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"] - }, - { - "address": "5RpUwQ8wtdPCZHhu6MERp2RGrpobsbZ6MH5dDHkUjs2", - "chainId": 101, - "decimals": 8, - "extensions": { - "address": "0xe9e7cea3dedca5984780bafc599bd69add087d56", - "assetContract": "https://bscscan.com/address/0xe9e7cea3dedca5984780bafc599bd69add087d56", - "bridgeContract": "https://bscscan.com/address/0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7", - "coingeckoId": "binance-usd", - "currency": "USD", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/5RpUwQ8wtdPCZHhu6MERp2RGrpobsbZ6MH5dDHkUjs2.png", - "name": "BUSD Token (Wormhole from BSC)", - "symbol": "BUSDbs", - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"] - }, - { - "address": "5goWRao6a3yNC4d6UjMdQxonkCMvKBwdpubU3qhfcdf1", - "chainId": 101, - "decimals": 6, - "extensions": { - "address": "0xc2132d05d31c914a87c6611c10748aeb04b58e8f", - "assetContract": "https://polygonscan.com/token/0xc2132d05d31c914a87c6611c10748aeb04b58e8f", - "bridgeContract": "https://polygonscan.com/address/0x5a58505a96d1dbf8df91cb21b54419fc36e93fde", - "coingeckoId": "tether", - "currency": "USD", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/5goWRao6a3yNC4d6UjMdQxonkCMvKBwdpubU3qhfcdf1.png", - "name": "Tether USD (Wormhole from Polygon)", - "symbol": "USDTpo", - "tags": ["wrapped", "saber-mkt-usd", "wormhole-v2"] - }, - { - "address": "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "socean-staked-sol", - "currency": "SOL", - "discord": "https://discord.gg/k8ZcW27bq9", - "medium": "https://medium.com/@soceanfinance", - "serumV3Usdc": "D52sefGCWho2nd5UGxWd7wCftAzeNEMNYZkdEPGEdQTb", - "source": "socean", - "sourceUrl": "https://www.socean.fi/app", - "twitter": "https://twitter.com/soceanfinance", - "website": "https://socean.fi/" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm.png", - "name": "Socean staked SOL", - "symbol": "scnSOL", - "tags": ["stake-pool", "saber-mkt-sol"] - }, - { - "address": "62oPK1hKbHeNCrnZvXxKGu7DwmeNKByCS4E6ctS1rag5", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "So11111111111111111111111111111111111111112" - ], - "website": "https://app.saber.so/#/pools/4Fss9Dy3vAUBuQ4SyEZz4vcLxeQqoFLZjdXhEUr3wqz3" - }, - "logoURI": "https://registry.saber.so/token-icons/slp.png", - "name": "Saber mSOL-SOL LP", - "symbol": "mSOL-SOL", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "66CgfJQoZkpkrEgC1z4vFJcSFc4V6T5HqbjSSNuqcNJz", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "bitcoin", - "currency": "BTC", - "source": "wormhole-v1", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "logoURI": "https://registry.saber.so/token-icons/ibbtc.svg", - "name": "ibBTC (Wormhole V1)", - "symbol": "wibBTC_V1", - "tags": ["saber-mkt-btc", "wormhole-v1"] - }, - { - "address": "6MeoZEcUMhAB788YXTQN4x7K8MnwSt6RHWsLkuq9GJb2", - "chainId": 101, - "decimals": 6, - "extensions": { - "coingeckoId": "terra-luna", - "currency": "LUNA", - "source": "synthetify", - "sourceUrl": "https://app.synthetify.io/staking", - "twitter": "https://twitter.com/synthetify", - "website": "https://synthetify.io/" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/6MeoZEcUMhAB788YXTQN4x7K8MnwSt6RHWsLkuq9GJb2.svg", - "name": "Synthetic LUNA", - "symbol": "xLUNA", - "tags": ["saber-mkt-luna"] - }, - { - "address": "6nuaX3ogrr2CaoAPjtaKHAoBNWok32BMcRozuf32s2QF", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "binance-usd", - "currency": "USD", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/6nuaX3ogrr2CaoAPjtaKHAoBNWok32BMcRozuf32s2QF.png", - "name": "Wrapped BUSD (Allbridge from BSC)", - "symbol": "abBUSD", - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "address": "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn", - "chainId": 101, - "decimals": 9, - "extensions": { - "currency": "SOL", - "discord": "https://discord.gg/qR4BA9QXVR", - "source": "jpool", - "sourceUrl": "https://jpool.one/", - "telegram": "https://t.me/jpoolsolana", - "twitter": "https://twitter.com/JPoolSolana", - "website": "https://jpool.one/" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn.svg", - "name": "JPOOL Solana Token", - "symbol": "JSOL", - "tags": ["stake-pool-token", "utility-token", "saber-mkt-sol"] - }, - { - "address": "7VQo3HFLNH5QqGtM8eC3XQbPkJUu7nS9LeGWjerRh5Sw", - "chainId": 101, - "decimals": 8, - "extensions": { - "address": "0xdf574c24545e5ffecb9a659c229253d4111d87e1", - "assetContract": "https://etherscan.io/address/0xdf574c24545e5ffecb9a659c229253d4111d87e1", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "husd", - "currency": "USD", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/7VQo3HFLNH5QqGtM8eC3XQbPkJUu7nS9LeGWjerRh5Sw.png", - "name": "HUSD (Wormhole)", - "symbol": "HUSD", - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"] - }, - { - "address": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "chainId": 101, - "decimals": 9, - "extensions": { - "currency": "SOL", - "serumV3Usdc": "5F7LGsP1LPtaRV7vVKgxwNYX4Vf22xvuzyXjyar7jJqp", - "source": "Lido", - "sourceUrl": "https://solana.lido.fi/", - "twitter": "https://twitter.com/LidoFinance", - "website": "https://solana.lido.fi/" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj.png", - "name": "Lido Staked SOL", - "symbol": "stSOL", - "tags": ["saber-mkt-sol"] - }, - { - "address": "7dVH61ChzgmN9BwG4PkzwRP8PbYwPJ7ZPNF2vamKT2H8", - "chainId": 101, - "decimals": 8, - "extensions": { - "address": "0x0316eb71485b0ab14103307bf65a021042c6d380", - "assetContract": "https://etherscan.io/address/0x0316eb71485b0ab14103307bf65a021042c6d380", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "huobi-btc", - "currency": "BTC", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/7dVH61ChzgmN9BwG4PkzwRP8PbYwPJ7ZPNF2vamKT2H8.png", - "name": "Huobi BTC (Wormhole)", - "symbol": "HBTC", - "tags": ["wrapped", "wormhole", "saber-mkt-btc", "wormhole-v2"] - }, - { - "address": "7g166TuBmnoHKvS2PEkZx6kREZtbfjUxCHGWjCqoDXZv", - "chainId": 101, - "decimals": 9, - "extensions": { - "currency": "EUR", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/7g166TuBmnoHKvS2PEkZx6kREZtbfjUxCHGWjCqoDXZv.png", - "name": "Wrapped CEUR (Allbridge from Celo)", - "symbol": "acEUR", - "tags": ["stablecoin", "saber-mkt-eur"] - }, - { - "address": "7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT", - "chainId": 101, - "decimals": 6, - "extensions": { - "coingeckoId": "uxd-stablecoin", - "currency": "USD", - "discord": "https://discord.com/invite/BHfpYmjsBM", - "medium": "https://uxdprotocol.medium.com/", - "source": "UXD", - "sourceUrl": "https://app.uxd.fi/", - "twitter": "https://twitter.com/UXDProtocol", - "website": "https://uxd.fi/" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT.png", - "name": "UXD Stablecoin", - "symbol": "UXD", - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "address": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "chainId": 101, - "decimals": 8, - "extensions": { - "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "assetContract": "https://etherscan.io/address/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "ethereum", - "currency": "ETH", - "serumV3Usdc": "8Gmi2HhZmwQPVdCwzS7CM66MGstMXPcTVHA7jF19cLZz", - "serumV3Usdt": "ch7kmPrtoQUSEPBggcNAvLGiMQkJagVwd3gDYfd8m7Q", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs.png", - "name": "Ether (Wormhole)", - "symbol": "ETH", - "tags": ["wrapped", "wormhole", "saber-mkt-eth", "wormhole-v2"] - }, - { - "address": "83LGLCm7QKpYZbX8q4W2kYWbtt8NJBwbVwEepzkVnJ9y", - "chainId": 101, - "decimals": 6, - "extensions": { - "coingeckoId": "usd-coin", - "currency": "USD", - "source": "synthetify", - "sourceUrl": "https://app.synthetify.io/staking", - "twitter": "https://twitter.com/synthetify", - "website": "https://synthetify.io/" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/83LGLCm7QKpYZbX8q4W2kYWbtt8NJBwbVwEepzkVnJ9y.svg", - "name": "Synthetic USD", - "symbol": "xUSD", - "tags": ["saber-mkt-usd"] - }, - { - "address": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "chainId": 101, - "decimals": 8, - "extensions": { - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "coingeckoId": "usd-coin", - "currency": "USD", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"], - "website": "https://app.saber.so" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy.png", - "name": "Saber Wrapped USD Coin (8 decimals)", - "symbol": "sUSDC-8", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"] - }, - { - "address": "8L8pDf3jutdpdr4m3np68CL9ZroLActrqwxi6s9Ah5xU", - "chainId": 101, - "decimals": 9, - "extensions": { - "address": "0x853d955aCEf822Db058eb8505911ED77F175b99e", - "assetContract": "https://etherscan.io/address/0x853d955aCEf822Db058eb8505911ED77F175b99e", - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "coingeckoId": "frax", - "currency": "USD", - "source": "wormhole-v1", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/8L8pDf3jutdpdr4m3np68CL9ZroLActrqwxi6s9Ah5xU.png", - "name": "Frax (Wormhole v1)", - "symbol": "wFRAX_v1", - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v1"] - }, - { - "address": "8XSsNvaKU9FDhYWAv7Yc7qSNwuJSzVrXBNEk7AFiWF69", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "usd-coin", - "currency": "USD", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/8XSsNvaKU9FDhYWAv7Yc7qSNwuJSzVrXBNEk7AFiWF69.png", - "name": "Wrapped USDC (Allbridge from BSC)", - "symbol": "abUSDC", - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "address": "8Yv9Jz4z7BUHP68dz8E8m3tMe6NKgpMUKn8KVqrPA6Fr", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "usd-coin", - "currency": "USD", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/8Yv9Jz4z7BUHP68dz8E8m3tMe6NKgpMUKn8KVqrPA6Fr.png", - "name": "Wrapped USDC (Allbridge from Avalanche)", - "symbol": "aaUSDC", - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "address": "8bqjz8DeSuim1sEAsQatjJN4zseyxSPdhHQcuuhL8PCK", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "ethereum", - "currency": "ETH", - "source": "synthetify", - "sourceUrl": "https://app.synthetify.io/staking", - "twitter": "https://twitter.com/synthetify", - "website": "https://synthetify.io/" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/8bqjz8DeSuim1sEAsQatjJN4zseyxSPdhHQcuuhL8PCK.svg", - "name": "Synthetic ETH", - "symbol": "xETH", - "tags": ["saber-mkt-eth"] - }, - { - "address": "8ezDtNNhX91t1NbSLe8xV2PcCEfoQjEm2qDVGjt3rjhg", - "chainId": 101, - "decimals": 9, - "extensions": { - "currency": "SOL", - "source": "port", - "sourceUrl": "https://mainnet.port.finance/#/markets", - "website": "https://port.finance" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/8ezDtNNhX91t1NbSLe8xV2PcCEfoQjEm2qDVGjt3rjhg.svg", - "name": "Port Finance SOL", - "symbol": "pSOL", - "tags": ["port", "lending", "collateral-tokens", "saber-mkt-sol"] - }, - { - "address": "8pBc4v9GAwCBNWPB5XKA93APexMGAS4qMr37vNke9Ref", - "chainId": 101, - "decimals": 9, - "extensions": { - "address": "0x0316EB71485b0Ab14103307bf65a021042c6d380", - "assetContract": "https://etherscan.io/address/0x0316EB71485b0Ab14103307bf65a021042c6d380", - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "coingeckoId": "huobi-btc", - "currency": "BTC", - "source": "wormhole-v1", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/8pBc4v9GAwCBNWPB5XKA93APexMGAS4qMr37vNke9Ref.png", - "name": "HBTC (Wormhole v1)", - "symbol": "wHBTC_v1", - "tags": ["wrapped", "wormhole", "saber-mkt-btc", "wormhole-v1"] - }, - { - "address": "8qJSyQprMC57TWKaYEmetUR3UUiTP2M3hXdcvFhkZdmv", - "chainId": 101, - "decimals": 8, - "extensions": { - "address": "0x55d398326f99059ff775485246999027b3197955", - "assetContract": "https://bscscan.com/address/0x55d398326f99059ff775485246999027b3197955", - "bridgeContract": "https://bscscan.com/address/0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7", - "coingeckoId": "tether", - "currency": "USD", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/8qJSyQprMC57TWKaYEmetUR3UUiTP2M3hXdcvFhkZdmv.png", - "name": "Tether USD (Wormhole from BSC)", - "symbol": "USDTbs", - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"] - }, - { - "address": "8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE", - "chainId": 101, - "decimals": 6, - "extensions": { - "currency": "LUNA", - "serumV3Usdc": "CxDhLbbM9uAA2AXfSPar5qmyfmC69NLj3vgJXYAsSVBT", - "source": "renbridge", - "sourceUrl": "https://bridge.renproject.io/mint", - "website": "https://renproject.io/" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE.png", - "name": "renLUNA", - "symbol": "renLUNA", - "tags": ["saber-mkt-luna"] - }, - { - "address": "9999j2A8sXUtHtDoQdk528oVzhaKBsXyRGZ67FKGoi7H", - "chainId": 101, - "decimals": 9, - "extensions": { - "assetContract": "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "coingeckoId": "bitcoin", - "currency": "BTC", - "serumV3Usdc": "A8YFbxQYFVqKZaoYJLLUVcQiWP7G2MeEgW5wsAQgMvFw", - "serumV3Usdt": "C1EuT9VokAKLiW7i2ASnZUvxDoKuKkCpDDeNxAptuNe4", - "source": "sollet", - "sourceUrl": "https://www.sollet.io/", - "underlyingTokens": ["9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E"], - "website": "https://app.saber.so" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/9999j2A8sXUtHtDoQdk528oVzhaKBsXyRGZ67FKGoi7H.png", - "name": "Saber Wrapped Wrapped Bitcoin (Sollet) (9 decimals)", - "symbol": "sBTC-9", - "tags": [ - "wrapped-sollet", - "ethereum", - "saber-mkt-btc", - "saber-dec-wrapped" - ] - }, - { - "address": "9EaLkQrbjmbbuZG9Wdpo8qfNUEjHATJFSycEmw6f1rGX", - "chainId": 101, - "decimals": 9, - "extensions": { - "currency": "SOL", - "discord": "https://discord.gg/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "source": "parrot", - "sourceUrl": "https://parrot.fi/mint/", - "telegram": "https://t.me/gopartyparrot", - "twitter": "https://twitter.com/gopartyparrot", - "website": "https://parrot.fi" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/9EaLkQrbjmbbuZG9Wdpo8qfNUEjHATJFSycEmw6f1rGX.svg", - "name": "pSOL (Parrot SOL)", - "symbol": "pSOL", - "tags": ["stablecoin", "saber-mkt-sol"] - }, - { - "address": "9QBTKuSCDaJjtxYnYcVzoiKENMdJ5DRei5ZUCEeWyZnj", - "chainId": 101, - "decimals": 6, - "extensions": { - "address": "0x2c537e5624e4af88a7ae4060c022609376c8d0eb", - "assetContract": "https://etherscan.io/token/0x2c537e5624e4af88a7ae4060c022609376c8d0eb", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "currency": "TRY", - "github": "https://github.com/bilira-org", - "instagram": "https://instagram.com/bilira_official", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "telegram": "https://t.me/BiLira_Official", - "website": "http://bilira.co" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/9QBTKuSCDaJjtxYnYcVzoiKENMdJ5DRei5ZUCEeWyZnj.png", - "name": "BiLira (Wormhole)", - "symbol": "TRYB", - "tags": [ - "stablecoin", - "wormhole", - "wrapped", - "saber-mkt-try", - "wormhole-v2" - ] - }, - { - "address": "9mWRABuz2x6koTPCWiCPM49WUbcrNqGTHBV9T9k7y1o7", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "mimatic", - "currency": "USD", - "discord": "https://discord.com/invite/mQq55j65xJ", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge", - "twitter": "https://twitter.com/QiDaoProtocol", - "website": "https://mai.finance/" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/9mWRABuz2x6koTPCWiCPM49WUbcrNqGTHBV9T9k7y1o7.png", - "name": "MAI Stablecoin", - "symbol": "MAI", - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "address": "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "chainId": 101, - "decimals": 6, - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "coingeckoId": "bitcoin", - "currency": "BTC", - "serumV3Usdc": "A8YFbxQYFVqKZaoYJLLUVcQiWP7G2MeEgW5wsAQgMvFw", - "serumV3Usdt": "C1EuT9VokAKLiW7i2ASnZUvxDoKuKkCpDDeNxAptuNe4", - "source": "sollet", - "sourceUrl": "https://www.sollet.io/" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E.png", - "name": "Wrapped Bitcoin (Sollet)", - "symbol": "BTC", - "tags": ["wrapped-sollet", "ethereum", "saber-mkt-btc"] - }, - { - "address": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "chainId": 101, - "decimals": 6, - "extensions": { - "address": "uusd", - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "coingeckoId": "terrausd", - "currency": "USD", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i.png", - "name": "UST (Wormhole)", - "symbol": "UST", - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"] - }, - { - "address": "9w6LpS7RU1DKftiwH3NgShtXbkMM1ke9iNU4g3MBXSUs", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "multi-collateral-dai", - "currency": "USD", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/9w6LpS7RU1DKftiwH3NgShtXbkMM1ke9iNU4g3MBXSUs.png", - "name": "Wrapped DAI (Allbridge from Ethereum)", - "symbol": "aeDAI", - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "address": "A94X2fRy3wydNShU4dRaDyap2UuoeWJGWyATtyp61WZf", - "chainId": 101, - "decimals": 6, - "extensions": { - "coingeckoId": "bilira", - "currency": "TRY", - "github": "https://github.com/bilira-org", - "instagram": "https://instagram.com/bilira_official", - "source": "BiLira", - "sourceUrl": "https://www.bilira.co/", - "telegram": "https://t.me/BiLira_Official", - "website": "http://bilira.co" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/A94X2fRy3wydNShU4dRaDyap2UuoeWJGWyATtyp61WZf.png", - "name": "BiLira", - "symbol": "TRYB", - "tags": ["tryb", "bilira", "stablecoin", "saber-mkt-try"] - }, - { - "address": "A96PoNcxa9LMxcF9HhKAfA1p3M1dGbubPMWf19gHAkgJ", - "chainId": 101, - "decimals": 6, - "extensions": { - "coingeckoId": "terrausd", - "currency": "USD", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/A96PoNcxa9LMxcF9HhKAfA1p3M1dGbubPMWf19gHAkgJ.png", - "name": "Wrapped UST (Allbridge from Terra)", - "symbol": "atUST", - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "address": "A9mUU4qviSctJVPJdBJWkb28deg915LYJKrzQ19ji3FM", - "chainId": 101, - "decimals": 6, - "extensions": { - "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - "assetContract": "https://etherscan.io/address/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "usd-coin", - "currency": "USD", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/A9mUU4qviSctJVPJdBJWkb28deg915LYJKrzQ19ji3FM.png", - "name": "USD Coin (Wormhole from Ethereum)", - "symbol": "USDCet", - "tags": ["wrapped", "saber-mkt-usd", "wormhole-v2"] - }, - { - "address": "AECpyKJWfXVyWnk2d9md5dUj3RuzHRKfQra8MakjuVRz", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "DdFPRnccQqLD4zCHrBqdY95D6hvw6PLWp9DEXj1fLCL9", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "website": "https://app.saber.so/#/pools/aeusdc" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/AECpyKJWfXVyWnk2d9md5dUj3RuzHRKfQra8MakjuVRz.png", - "name": "Saber aeUSDC-USDC LP", - "symbol": "aeUSDC-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "AET3m1Mp2SLi7QX3tSypcZWyEtk1d8dUGcwhweDiZdaR", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma", - "AaAEw2VCw1XzgvKB8Rj2DyK2ZVau9fbt2bE8hZFWsMyE" - ], - "website": "https://app.saber.so/#/pools/aeeth" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/AET3m1Mp2SLi7QX3tSypcZWyEtk1d8dUGcwhweDiZdaR.png", - "name": "Saber ETH-aeWETH LP", - "symbol": "ETH-aeWETH", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV", - "chainId": 101, - "decimals": 9, - "extensions": { - "assetContract": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "coingeckoId": "tether", - "currency": "USD", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "underlyingTokens": ["Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"], - "website": "https://app.saber.so" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV.png", - "name": "Saber Wrapped USDT (9 decimals)", - "symbol": "sUSDT-9", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"] - }, - { - "address": "AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3", - "chainId": 101, - "decimals": 6, - "extensions": { - "assetContract": "https://etherscan.io/address/0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "coingeckoId": "ftx-token", - "currency": "FTT", - "serumV3Usdc": "2Pbh1CvRVku1TgewMfycemghf6sU9EyuFDcNXqvRmSxc", - "serumV3Usdt": "Hr3wzG8mZXNHV7TuL6YqtgfVUesCqMxGYCEyP3otywZE", - "source": "sollet", - "sourceUrl": "https://www.sollet.io/", - "waterfallbot": "https://bit.ly/FTTwaterfall" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3.png", - "name": "Wrapped FTT (Sollet)", - "symbol": "soFTT", - "tags": ["wrapped-sollet", "ethereum", "saber-mkt-ftt"] - }, - { - "address": "AJ1W9A9N9dEMdVyoDiam2rV44gnBm2csrPDP7xqcapgX", - "chainId": 101, - "decimals": 9, - "extensions": { - "address": "0x4Fabb145d64652a948d72533023f6E7A623C7C53", - "assetContract": "https://etherscan.io/address/0x4Fabb145d64652a948d72533023f6E7A623C7C53", - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "coingeckoId": "binance-usd", - "currency": "USD", - "source": "wormhole-v1", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/AJ1W9A9N9dEMdVyoDiam2rV44gnBm2csrPDP7xqcapgX.png", - "name": "Binance USD (Wormhole v1)", - "symbol": "wBUSD_v1", - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v1"] - }, - { - "address": "ALP66QkhMUoGeasDbitT4xUTpQrqBYAFkm6VPzWXAzxm", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "website": "https://app.saber.so/#/pools/MiMUFdSLMyCLpqpH6zkqdDrGYs7XBomwENbivdYjv9V" - }, - "logoURI": "https://registry.saber.so/token-icons/slp.png", - "name": "Saber aeMIM-USDC LP", - "symbol": "aeMIM-USDC", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "ALP74DnaoVT8DpiXBfQiTDjtcDdsmXGKDAQMkCeVM3LQ", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "8XSsNvaKU9FDhYWAv7Yc7qSNwuJSzVrXBNEk7AFiWF69", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "website": "https://app.saber.so/#/pools/BSCsJRZuzNScmNdka9rr24iFediCUYHKh3Sya7TjVBni" - }, - "logoURI": "https://registry.saber.so/token-icons/slp.png", - "name": "Saber abUSDC-USDC LP", - "symbol": "abUSDC-USDC", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "ALP89a89ASo1h5VosTSABtQBKLBgeoaWQexYQrRCMNfV", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "ASoLXbfe7cd6igh5yiEsU8M7FW64QRxPKkxk7sjAfond", - "So11111111111111111111111111111111111111112" - ], - "website": "https://app.saber.so/#/pools/asol" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/ALP89a89ASo1h5VosTSABtQBKLBgeoaWQexYQrRCMNfV.png", - "name": "Saber aSOL-SOL LP", - "symbol": "aSOL-SOL", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "ALP8mkba7FHrpn18hGMRURF1aRNS7P2y1SRzqE6ra3Zo", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "Grk6b4UMRWkgyq4Y6S1BnNRF4hRgtnMFp7Sorkv6Ez4u", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "website": "https://app.saber.so/#/pools/afusdc" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/ALP8mkba7FHrpn18hGMRURF1aRNS7P2y1SRzqE6ra3Zo.png", - "name": "Saber afUSDC-USDC LP", - "symbol": "afUSDC-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "ALPBPdBQf8ibRm3PRCycDC8bdFZQhFgjUwZMtnxA3rAA", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "A96PoNcxa9LMxcF9HhKAfA1p3M1dGbubPMWf19gHAkgJ", - "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT" - ], - "website": "https://app.saber.so/#/pools/atust_cash" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/ALPBPdBQf8ibRm3PRCycDC8bdFZQhFgjUwZMtnxA3rAA.png", - "name": "Saber atUST-CASH LP", - "symbol": "atUST-CASH", - "tags": ["saber-stableswap-lp", "saber-lp-cashio"] - }, - { - "address": "ALPDpWSYbwNkkuVB3wd1nZx7dZBLV7fEGvbDu9KJxLik", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "BAexggGFsiLCKr17cSZF12wkHd8BkR1DBhzuSb78WTR2", - "UST98bfV6EASdTFQrRwCBczpehdMFwYCUdLT5tEbhpW" - ], - "website": "https://app.saber.so/#/pools/fei_ust" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/ALPDpWSYbwNkkuVB3wd1nZx7dZBLV7fEGvbDu9KJxLik.png", - "name": "Saber aeFEI-UST LP", - "symbol": "aeFEI-UST", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "ALPGFAuqQsWDB8NSKQ7rgQVhShj4LBCNC72ebdZrJs2e", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "BiryxNvVTABRs3pEE4fvVuu4d17aAYEsNmcPnJ8E8WeT", - "KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma" - ], - "website": "https://app.saber.so/#/pools/afeth" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/ALPGFAuqQsWDB8NSKQ7rgQVhShj4LBCNC72ebdZrJs2e.png", - "name": "Saber afETH-ETH LP", - "symbol": "afETH-ETH", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "ALPX6x8FkkdQyn9YuoVZjPAapL4nUC7vjJ3AtwStmj9P", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "8XSsNvaKU9FDhYWAv7Yc7qSNwuJSzVrXBNEk7AFiWF69", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "website": "https://app.saber.so/#/pools/abusdc" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/ALPX6x8FkkdQyn9YuoVZjPAapL4nUC7vjJ3AtwStmj9P.png", - "name": "Saber abUSDC-USDC LP", - "symbol": "abUSDC-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "ALPaPPo6xmeGv3a63Pc4S8NJFAAuchhD7XnkkWJqzvXJ", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "E77cpQ4VncGmcAXX16LHFFzNBEBb2U7Ar7LBmZNfCgwL", - "AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV" - ], - "website": "https://app.saber.so/#/pools/abusdt" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/ALPaPPo6xmeGv3a63Pc4S8NJFAAuchhD7XnkkWJqzvXJ.png", - "name": "Saber abUSDT-USDT LP", - "symbol": "abUSDT-USDT", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "ALPaX3bS8zPKsVN6eS7Ln7dvEbDAfDtXsLz5pe2JRddq", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "BAexggGFsiLCKr17cSZF12wkHd8BkR1DBhzuSb78WTR2", - "C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi" - ], - "website": "https://app.saber.so/#/pools/fei_cash" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/ALPaX3bS8zPKsVN6eS7Ln7dvEbDAfDtXsLz5pe2JRddq.png", - "name": "Saber aeFEI-CASH LP", - "symbol": "aeFEI-CASH", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "ALPb4SssuKFScyUFnTcXLtF3NAkwFuFpQFric5yo4Qpo", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "3os2M3bX9qta154PRbU9rzaPUYAKAqVpaMMS8u2hoUQu", - "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5" - ], - "website": "https://app.saber.so/#/pools/abbtcb" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/ALPb4SssuKFScyUFnTcXLtF3NAkwFuFpQFric5yo4Qpo.png", - "name": "Saber abBTCB-renBTC LP", - "symbol": "abBTCB-renBTC", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "ALPbh25PVwDDEhmJizhrtyhfgXNjh17RtbZc4i5ZAHdh", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj", - "C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi" - ], - "website": "https://app.saber.so/#/pools/mim_cash" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/ALPbh25PVwDDEhmJizhrtyhfgXNjh17RtbZc4i5ZAHdh.png", - "name": "Saber aeMIM-CASH LP", - "symbol": "aeMIM-CASH", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "ALPfb7HJd4oenNBknjzCbVc2RooC5N1H6N391hbZ82ky", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj", - "UST98bfV6EASdTFQrRwCBczpehdMFwYCUdLT5tEbhpW" - ], - "website": "https://app.saber.so/#/pools/mim_ust" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/ALPfb7HJd4oenNBknjzCbVc2RooC5N1H6N391hbZ82ky.png", - "name": "Saber aeMIM-UST LP", - "symbol": "aeMIM-UST", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "ALPi51sXwH9kNcQuneDwz7kPzJs3hJ5xV6SmnuyqodQP", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "EyrnrbE5ujd3HQG5PZd9MbECN9yaQrqc8pRwGtaLoyC", - "KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma" - ], - "website": "https://app.saber.so/#/pools/abeth" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/ALPi51sXwH9kNcQuneDwz7kPzJs3hJ5xV6SmnuyqodQP.png", - "name": "Saber abETH-ETH LP", - "symbol": "abETH-ETH", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "ALPoQFUuKsoN6P4gLBiKXMSaYFP9YChniKwvKAFRPvn5", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "FdvkkCbCgYht1xTR1W9MBJhEF1JEPVhHtW1NXBYRzZts", - "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5" - ], - "website": "https://app.saber.so/#/pools/afbtc" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/ALPoQFUuKsoN6P4gLBiKXMSaYFP9YChniKwvKAFRPvn5.png", - "name": "Saber afBTC-renBTC LP", - "symbol": "afBTC-renBTC", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "ALPqczrbEXS8k5JF69tEPyu6TTE8qJbiwrzADfjVfKov", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "HjUhUzi6fVkY1BndaSc4Dcg2mCzvnqzXjVJtXsj78ver", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "website": "https://app.saber.so/#/pools/afdai" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/ALPqczrbEXS8k5JF69tEPyu6TTE8qJbiwrzADfjVfKov.png", - "name": "Saber afDAI-USDC LP", - "symbol": "afDAI-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "ALPydtnKSxX5AMZSSH8duCPSDoKa49ZwCvert6hzGera", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "website": "https://app.saber.so/#/pools/MiMy69CnJDY4V6cQWkU3HHfTyb8pqXJmhX4MisFYDnM" - }, - "logoURI": "https://registry.saber.so/token-icons/slp.png", - "name": "Saber aeMIM-USDC LP", - "symbol": "aeMIM-USDC", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "APUVVYA8Xf7T1PqLyDvNxLtwQ9rRDf3RUxfMttreVzHP", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "eqKJTf1Do4MDPyKisMYqVaUFpkEFAs3riGF3ceDH2Ca", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "website": "https://app.saber.so/#/pools/apusdc" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/APUVVYA8Xf7T1PqLyDvNxLtwQ9rRDf3RUxfMttreVzHP.png", - "name": "Saber apUSDC-USDC LP", - "symbol": "apUSDC-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "ASoLXbfe7cd6igh5yiEsU8M7FW64QRxPKkxk7sjAfond", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "solana", - "currency": "SOL", - "description": "aSOL is the standard for transacting with staked SOL tokens.", - "github": "https://github.com/aSolHQ", - "source": "aSOL", - "sourceUrl": "https://asol.so/", - "twitter": "https://twitter.com/aSOLprotocol", - "website": "https://asol.so" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/ASoLXbfe7cd6igh5yiEsU8M7FW64QRxPKkxk7sjAfond.svg", - "name": "aSOL Aggregate Solana Stake Pool", - "symbol": "aSOL", - "tags": ["saber-mkt-sol"] - }, - { - "address": "AUrMpCDYYcPuHhyNX8gEEqbmDPFUpBpHrNW3vPeCFn5Z", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "avalanche", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/AUrMpCDYYcPuHhyNX8gEEqbmDPFUpBpHrNW3vPeCFn5Z.png", - "name": "AVAX (Allbridge from Avalanche)", - "symbol": "AVAX", - "tags": [] - }, - { - "address": "AVBDpg1UYpDYQLbzEnRY76R3u82PYHtDuc3NBdFS2k39", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "Fd8xyHHRjTvxfZrBirb6MaxSmrZYw99gRSqFUKdFwFvw", - "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5" - ], - "website": "https://app.saber.so/#/pools/aawbtc" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/AVBDpg1UYpDYQLbzEnRY76R3u82PYHtDuc3NBdFS2k39.png", - "name": "Saber aaWBTC-renBTC LP", - "symbol": "aaWBTC-renBTC", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "AVC7uVb6R9B34T8zWxQMEK8twvYk26U71gworsujxFNv", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "8Yv9Jz4z7BUHP68dz8E8m3tMe6NKgpMUKn8KVqrPA6Fr", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "website": "https://app.saber.so/#/pools/aausdc" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/AVC7uVb6R9B34T8zWxQMEK8twvYk26U71gworsujxFNv.png", - "name": "Saber aaUSDC-USDC LP", - "symbol": "aaUSDC-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "AVDuGckLavyLr5YifViaxnoveY6rwqDezHw5kiKiRQEC", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "EgQ3yNtVhdHz7g1ZhjfGbxhFKMPPaFkz8QHXM5RBZBgi", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "website": "https://app.saber.so/#/pools/aadai" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/AVDuGckLavyLr5YifViaxnoveY6rwqDezHw5kiKiRQEC.png", - "name": "Saber aaDAI-USDC LP", - "symbol": "aaDAI-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "AVTrxHq5P57fYZTYjMuCRWFqsrLmom2gGThNtgEgK1ip", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "FwEHs3kJEdMa2qZHv7SgzCiFXUQPEycEXksfBkwmS8gj", - "AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV" - ], - "website": "https://app.saber.so/#/pools/aausdt" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/AVTrxHq5P57fYZTYjMuCRWFqsrLmom2gGThNtgEgK1ip.png", - "name": "Saber aaUSDT-USDT LP", - "symbol": "aaUSDT-USDT", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "AZD7BcwEPbSoVYYJ9QXjdjRpMRg7gJ81c83gU7RRtrvV", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "So11111111111111111111111111111111111111112" - ], - "website": "https://app.saber.so/#/pools/2jQoGQRixdcfuRPt9Zui7pk6ivnrQv79mf8h13Tyoa9K" - }, - "logoURI": "https://registry.saber.so/token-icons/slp.png", - "name": "Saber mSOL-SOL LP", - "symbol": "mSOL-SOL", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "AaAEw2VCw1XzgvKB8Rj2DyK2ZVau9fbt2bE8hZFWsMyE", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "weth", - "currency": "ETH", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/AaAEw2VCw1XzgvKB8Rj2DyK2ZVau9fbt2bE8hZFWsMyE.png", - "name": "Wrapped ETH (Allbridge from Ethereum)", - "symbol": "aeWETH", - "tags": ["stablecoin", "saber-mkt-eth"] - }, - { - "address": "BADGsQo6rTxKZuqkY1kSoqhriQwZW3ZVgyPjgDk9mvyo", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "66CgfJQoZkpkrEgC1z4vFJcSFc4V6T5HqbjSSNuqcNJz", - "9999j2A8sXUtHtDoQdk528oVzhaKBsXyRGZ67FKGoi7H" - ], - "website": "https://app.saber.so/#/pools/ibbtc" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/BADGsQo6rTxKZuqkY1kSoqhriQwZW3ZVgyPjgDk9mvyo.png", - "name": "Saber wibBTC_V1-BTC LP", - "symbol": "wibBTCV1-BTC", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"] - }, - { - "address": "BAexggGFsiLCKr17cSZF12wkHd8BkR1DBhzuSb78WTR2", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "fei-usd", - "currency": "USD", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/BAexggGFsiLCKr17cSZF12wkHd8BkR1DBhzuSb78WTR2.png", - "name": "Wrapped FEI (Allbridge from Ethereum)", - "symbol": "aeFEI", - "tags": ["saber-mkt-usd"] - }, - { - "address": "BFsCwfk8VsEbSfLkkgmoKsAPk2N6FMJjeTsuxfGa9VEf", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "ftx-token", - "currency": "FTT", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/BFsCwfk8VsEbSfLkkgmoKsAPk2N6FMJjeTsuxfGa9VEf.png", - "name": "Wrapped FTT (Allbridge from Ethereum)", - "symbol": "aeFTT", - "tags": ["saber-mkt-ftt"] - }, - { - "address": "BRENm9SgYJZuCxM4ZJiH6CmZqEBn4MLpD9cnBZDnJgeT", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "66CgfJQoZkpkrEgC1z4vFJcSFc4V6T5HqbjSSNuqcNJz", - "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5" - ], - "website": "https://app.saber.so/#/pools/ibbtc_ren" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/BRENm9SgYJZuCxM4ZJiH6CmZqEBn4MLpD9cnBZDnJgeT.png", - "name": "Saber wibBTC_V1-renBTC LP", - "symbol": "wibBTCV1-renBTC", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"] - }, - { - "address": "BSCNZ4GLnpZYv4BLk5edymk4qty8a6ZpiMbfvtv9gAzL", - "chainId": 101, - "decimals": 8, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "33fsBLA8djQm82RpHmE3SuVrPGtZBWNYExsEUeKX1HXX", - "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy" - ], - "website": "https://app.saber.so/#/pools/webusd" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/BSCNZ4GLnpZYv4BLk5edymk4qty8a6ZpiMbfvtv9gAzL.png", - "name": "Saber BUSDet-USDC LP", - "symbol": "BUSDet-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"] - }, - { - "address": "BUSDaZjarCrQJLeHpWi7aLaKptdR1S8DFpwdDuuZu9p3", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "AJ1W9A9N9dEMdVyoDiam2rV44gnBm2csrPDP7xqcapgX", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "website": "https://app.saber.so/#/pools/busd" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/BUSDaZjarCrQJLeHpWi7aLaKptdR1S8DFpwdDuuZu9p3.png", - "name": "Saber wBUSD_v1-USDC LP", - "symbol": "wBUSDv1-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"] - }, - { - "address": "BUSDjE9NEQ15aRFTxKFAjUf5vzqBhEgTNbYevWcSB5qp", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "6nuaX3ogrr2CaoAPjtaKHAoBNWok32BMcRozuf32s2QF", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "website": "https://app.saber.so/#/pools/abbusd" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/BUSDjE9NEQ15aRFTxKFAjUf5vzqBhEgTNbYevWcSB5qp.png", - "name": "Saber abBUSD-USDC LP", - "symbol": "abBUSD-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "BdUJucPJyjkHxLMv6ipKNUhSeY3DWrVtgxAES1iSBAov", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "solana", - "currency": "SOL", - "source": "synthetify", - "sourceUrl": "https://app.synthetify.io/staking", - "twitter": "https://twitter.com/synthetify", - "website": "https://synthetify.io/" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/BdUJucPJyjkHxLMv6ipKNUhSeY3DWrVtgxAES1iSBAov.svg", - "name": "Synthetic SOL", - "symbol": "xSOL", - "tags": ["saber-mkt-sol"] - }, - { - "address": "BdZPG9xWrG3uFrx2KrUW1jT4tZ9VKPDWknYihzoPRJS3", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "solana", - "currency": "SOL", - "source": "parrot", - "sourceUrl": "https://parrot.fi/mint/" - }, - "logoURI": "https://registry.saber.so/token-icons/prtsol.svg", - "name": "Parrot Stake Pool SOL", - "symbol": "prtSOL", - "tags": ["saber-mkt-sol"] - }, - { - "address": "BiryxNvVTABRs3pEE4fvVuu4d17aAYEsNmcPnJ8E8WeT", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "weth", - "currency": "ETH", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/BiryxNvVTABRs3pEE4fvVuu4d17aAYEsNmcPnJ8E8WeT.png", - "name": "Wrapped ETH (Allbridge from Fantom)", - "symbol": "afETH", - "tags": ["saber-mkt-eth"] - }, - { - "address": "Bn113WT6rbdgwrm12UJtnmNqGqZjY4it2WoUQuQopFVn", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "tether", - "currency": "USD", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/Bn113WT6rbdgwrm12UJtnmNqGqZjY4it2WoUQuQopFVn.svg", - "name": "Wrapped USDT (Allbridge from Ethereum)", - "symbol": "aeUSDT", - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "address": "Bo4ehCeRcRj2wp5tQpjfCJxYFn4KyRacfDzSa4Aj27tH", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "wrapped-bitcoin", - "currency": "BTC", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/Bo4ehCeRcRj2wp5tQpjfCJxYFn4KyRacfDzSa4Aj27tH.png", - "name": "Wrapped BTC (Allbridge from HECO)", - "symbol": "ahBTC", - "tags": ["stablecoin", "saber-mkt-btc"] - }, - { - "address": "BtX7AfzEJLnU8KQR1AgHrhGH5s2AHUTbfjhUQP8BhPvi", - "chainId": 101, - "decimals": 10, - "extensions": { - "assetContract": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "coingeckoId": "renbtc", - "currency": "BTC", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "source": "renbridge", - "sourceUrl": "https://bridge.renproject.io/mint", - "underlyingTokens": ["CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5"], - "website": "https://app.saber.so" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/BtX7AfzEJLnU8KQR1AgHrhGH5s2AHUTbfjhUQP8BhPvi.png", - "name": "Saber Wrapped renBTC (10 decimals)", - "symbol": "srenBTC-10", - "tags": ["saber-mkt-btc", "saber-dec-wrapped"] - }, - { - "address": "BybpSTBoZHsmKnfxYG47GDhVPKrnEKX31CScShbrzUhX", - "chainId": 101, - "decimals": 8, - "extensions": { - "address": "0xdf574c24545e5ffecb9a659c229253d4111d87e1", - "assetContract": "https://etherscan.io/address/0xdf574c24545e5ffecb9a659c229253d4111d87e1", - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "coingeckoId": "husd", - "currency": "USD", - "source": "wormhole-v1", - "sourceUrl": "https://v1.wormholebridge.com/#/move", - "website": "https://www.stcoins.com/" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/BybpSTBoZHsmKnfxYG47GDhVPKrnEKX31CScShbrzUhX.png", - "name": "HUSD Stablecoin (Wormhole v1)", - "symbol": "wHUSD_v1", - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v1"] - }, - { - "address": "Bzq68gAVedKqQkQbsM28yQ4LYpc2VComDUD9wJBywdTi", - "chainId": 101, - "decimals": 8, - "extensions": { - "coingeckoId": "bitcoin", - "currency": "BTC", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer" - }, - "logoURI": "https://registry.saber.so/token-icons/ibbtc.svg", - "name": "ibBTC (Wormhole)", - "symbol": "wibBTC", - "tags": ["saber-mkt-btc", "wormhole-v2"] - }, - { - "address": "C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi", - "chainId": 101, - "decimals": 9, - "extensions": { - "assetContract": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "currency": "USD", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "medium": "https://medium.com/@cashioapp", - "source": "Cashio", - "sourceUrl": "https://cashio.app/", - "twitter": "https://twitter.com/CashioApp", - "underlyingTokens": ["CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT"], - "website": "https://app.saber.so" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi.png", - "name": "Saber Wrapped Cashio Dollar (9 decimals)", - "symbol": "sCASH-9", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"] - }, - { - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "chainId": 101, - "decimals": 6, - "extensions": { - "currency": "USD", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "medium": "https://medium.com/@cashioapp", - "source": "Cashio", - "sourceUrl": "https://cashio.app/", - "twitter": "https://twitter.com/CashioApp", - "website": "https://cashio.app" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT.png", - "name": "Cashio Dollar", - "symbol": "CASH", - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "address": "CASHedBw9NfhsLBXq1WNVfueVznx255j8LLTScto3S6s", - "chainId": 101, - "decimals": 8, - "extensions": { - "assetContract": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "currency": "USD", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "medium": "https://medium.com/@cashioapp", - "source": "Cashio", - "sourceUrl": "https://cashio.app/", - "twitter": "https://twitter.com/CashioApp", - "underlyingTokens": ["CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT"], - "website": "https://app.saber.so" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/CASHedBw9NfhsLBXq1WNVfueVznx255j8LLTScto3S6s.png", - "name": "Saber Wrapped Cashio Dollar (8 decimals)", - "symbol": "sCASH-8", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"] - }, - { - "address": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "chainId": 101, - "decimals": 8, - "extensions": { - "coingeckoId": "renbtc", - "currency": "BTC", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "source": "renbridge", - "sourceUrl": "https://bridge.renproject.io/mint", - "website": "https://renproject.io/" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5.png", - "name": "renBTC", - "symbol": "renBTC", - "tags": ["saber-mkt-btc"] - }, - { - "address": "CLP2aB2bCXZEaoQjUNQdn64dCSzCVxKE3Kjgo3PcAYeY", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS", - "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT" - ], - "website": "https://app.saber.so/#/pools/pai_cash" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/CLP2aB2bCXZEaoQjUNQdn64dCSzCVxKE3Kjgo3PcAYeY.png", - "name": "Saber PAI-CASH LP", - "symbol": "PAI-CASH", - "tags": ["saber-stableswap-lp", "saber-lp-cashio"] - }, - { - "address": "CLPKiHjoU5HwpPK5L6MBXHKqFsuzPr47dM1w4An3Lnvv", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "website": "https://app.saber.so/#/pools/cash" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/CLPKiHjoU5HwpPK5L6MBXHKqFsuzPr47dM1w4An3Lnvv.png", - "name": "Saber CASH-USDC LP", - "symbol": "CASH-USDC", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "CLPLCvWFycur9CysMT3pmdkUXxPfBjXVkWyxTGntzoZ7", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "EwxNF8g9UfmsJVcZFTpL9Hx5MCkoQFoJi6XNWzKf1j8e", - "C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi" - ], - "website": "https://app.saber.so/#/pools/acusd_cash" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/CLPLCvWFycur9CysMT3pmdkUXxPfBjXVkWyxTGntzoZ7.png", - "name": "Saber acUSD-CASH LP", - "symbol": "acUSD-CASH", - "tags": ["saber-stableswap-lp", "saber-lp-cashio"] - }, - { - "address": "CLPRkuzQFiYnXddGTTKLvqgjgh4Tm7q16sVvivWNRzo8", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT" - ], - "website": "https://app.saber.so/#/pools/ust_cash" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/CLPRkuzQFiYnXddGTTKLvqgjgh4Tm7q16sVvivWNRzo8.png", - "name": "Saber UST-CASH LP", - "symbol": "UST-CASH", - "tags": ["saber-stableswap-lp", "saber-lp-cashio"] - }, - { - "address": "CXLBjMMcwkc17GfJtBos6rQCo1ypeH6eDbB82Kby4MRm", - "chainId": 101, - "decimals": 9, - "extensions": { - "address": "0xa47c8bf37f92aBed4A126BDA807A7b7498661acD", - "assetContract": "https://etherscan.io/address/0xa47c8bf37f92aBed4A126BDA807A7b7498661acD", - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "coingeckoId": "terrausd", - "currency": "USD", - "source": "wormhole-v1", - "sourceUrl": "https://v1.wormholebridge.com/#/move", - "website": "https://terra.money" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/CXLBjMMcwkc17GfJtBos6rQCo1ypeH6eDbB82Kby4MRm.png", - "name": "Wrapped UST (Wormhole v1)", - "symbol": "wUST_v1", - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v1"] - }, - { - "address": "CbNYA9n3927uXUukee2Hf4tm3xxkffJPPZvGazc2EAH1", - "chainId": 101, - "decimals": 8, - "extensions": { - "address": "0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8", - "assetContract": "https://etherscan.io/address/0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "ageur", - "currency": "EUR", - "description": "Angle is the first decentralized, capital efficient and over-collateralized stablecoin protocol", - "discord": "https://discord.gg/z3kCpTaKMh", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "twitter": "https://twitter.com/AngleProtocol", - "website": "https://www.angle.money" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/CbNYA9n3927uXUukee2Hf4tm3xxkffJPPZvGazc2EAH1.png", - "name": "agEUR (Wormhole)", - "symbol": "agEUR", - "tags": [ - "ethereum", - "wrapped", - "wormhole", - "saber-mkt-eur", - "wormhole-v2" - ] - }, - { - "address": "DAihWEjhBc8LEmV1rEekTaiC2zqE5ex7nEFkmoe1Ppp3", - "chainId": 101, - "decimals": 8, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o", - "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy" - ], - "website": "https://app.saber.so/#/pools/wdai" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/DAihWEjhBc8LEmV1rEekTaiC2zqE5ex7nEFkmoe1Ppp3.png", - "name": "Saber DAI-USDC LP", - "symbol": "DAI-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"] - }, - { - "address": "DHpoYejUDqzByb6HAdaLWF7KZvwUv2vWYDY9cTENNZui", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "usd-coin", - "currency": "USD", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/DHpoYejUDqzByb6HAdaLWF7KZvwUv2vWYDY9cTENNZui.png", - "name": "Wrapped USDC (Allbridge from Celo)", - "symbol": "acUSDC", - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "address": "DNhZkUaxHXYvpxZ7LNnHtss8sQgdAfd1ZYS1fB7LKWUZ", - "chainId": 101, - "decimals": 6, - "extensions": { - "coingeckoId": "tether", - "currency": "USD", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/DNhZkUaxHXYvpxZ7LNnHtss8sQgdAfd1ZYS1fB7LKWUZ.png", - "name": "Wrapped USDT (Allbridge from Polygon)", - "symbol": "apUSDT", - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "address": "DYDWu4hE4MN3aH897xQ3sRTs5EAjJDmQsKLNhbpUiKun", - "chainId": 101, - "decimals": 8, - "extensions": { - "currency": "BTC", - "discord": "https://discord.gg/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "source": "parrot", - "sourceUrl": "https://parrot.fi/mint/", - "telegram": "https://t.me/gopartyparrot", - "twitter": "https://twitter.com/gopartyparrot", - "website": "https://parrot.fi" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/DYDWu4hE4MN3aH897xQ3sRTs5EAjJDmQsKLNhbpUiKun.svg", - "name": "pBTC (Parrot BTC)", - "symbol": "pBTC", - "tags": ["stablecoin", "saber-mkt-btc"] - }, - { - "address": "Daimhb91DY4e3aVaa7YCW5GgwaMT9j1ALSi2GriBvDNh", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "FYpdBuyAHSbdaAyD1sKkxyLWbAP8uUW9h6uvdhK74ij1", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "website": "https://app.saber.so/#/pools/dai" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/Daimhb91DY4e3aVaa7YCW5GgwaMT9j1ALSi2GriBvDNh.png", - "name": "Saber wDAI_v1-USDC LP", - "symbol": "wDAIv1-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"] - }, - { - "address": "DdFPRnccQqLD4zCHrBqdY95D6hvw6PLWp9DEXj1fLCL9", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "usd-coin", - "currency": "USD", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/DdFPRnccQqLD4zCHrBqdY95D6hvw6PLWp9DEXj1fLCL9.png", - "name": "Wrapped USDC (Allbridge from Ethereum)", - "symbol": "aeUSDC", - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "address": "Dn4noZ5jgGfkntzcQSUZ8czkreiZ1ForXYoV2H8Dm7S1", - "chainId": 101, - "decimals": 6, - "extensions": { - "address": "0xdac17f958d2ee523a2206206994597c13d831ec7", - "assetContract": "https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "tether", - "currency": "USD", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/Dn4noZ5jgGfkntzcQSUZ8czkreiZ1ForXYoV2H8Dm7S1.png", - "name": "Tether USD (Wormhole from Ethereum)", - "symbol": "USDTet", - "tags": ["wrapped", "saber-mkt-usd", "wormhole-v2"] - }, - { - "address": "Dt1Cuau5m5CSmun8hZstjEh9RszxAmejnq7ZaHNcuXfA", - "chainId": 101, - "decimals": 6, - "extensions": { - "currency": "SOL", - "source": "port", - "sourceUrl": "https://mainnet.port.finance/#/markets", - "website": "https://port.finance" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/Dt1Cuau5m5CSmun8hZstjEh9RszxAmejnq7ZaHNcuXfA.svg", - "name": "Port Finance mSOL", - "symbol": "pmSOL", - "tags": ["port", "lending", "collateral-tokens", "saber-mkt-sol"] - }, - { - "address": "E2VmbootbVCBkMNNxKQgCLMS1X3NoGMaYAsufaAsf7M", - "chainId": 101, - "decimals": 6, - "extensions": { - "address": "0x2791bca1f2de4661ed88a30c99a7a9449aa84174", - "assetContract": "https://polygonscan.com/token/0x2791bca1f2de4661ed88a30c99a7a9449aa84174", - "bridgeContract": "https://polygonscan.com/address/0x5a58505a96d1dbf8df91cb21b54419fc36e93fde", - "coingeckoId": "usd-coin", - "currency": "USD", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/E2VmbootbVCBkMNNxKQgCLMS1X3NoGMaYAsufaAsf7M.png", - "name": "USD Coin (Wormhole from Polygon)", - "symbol": "USDCpo", - "tags": ["wrapped", "saber-mkt-usd", "wormhole-v2"] - }, - { - "address": "E77cpQ4VncGmcAXX16LHFFzNBEBb2U7Ar7LBmZNfCgwL", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "tether", - "currency": "USD", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/E77cpQ4VncGmcAXX16LHFFzNBEBb2U7Ar7LBmZNfCgwL.png", - "name": "Wrapped USDT (Allbridge from BSC)", - "symbol": "abUSDT", - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "chainId": 101, - "decimals": 6, - "extensions": { - "coingeckoId": "usd-coin", - "currency": "USD", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "website": "https://www.centre.io/" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png", - "name": "USD Coin", - "symbol": "USDC", - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "address": "ESoLEkfqBkqti137xAmnEHXB4omZpGXUdSPpfBWe9sau", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "Hg35Vd8K3BS2pLB3xwC2WqQV8pmpCm3oNRGYP1PEpmCM", - "So11111111111111111111111111111111111111112" - ], - "website": "https://app.saber.so/#/pools/everstake_sol" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/ESoLEkfqBkqti137xAmnEHXB4omZpGXUdSPpfBWe9sau.png", - "name": "Saber eSOL-SOL LP", - "symbol": "eSOL-SOL", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "EU9aLffrTckFCs16da6CppHy63fAxMPF9ih1erQTuuRt", - "chainId": 101, - "decimals": 9, - "extensions": { - "address": "0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8", - "assetContract": "CbNYA9n3927uXUukee2Hf4tm3xxkffJPPZvGazc2EAH1", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "ageur", - "currency": "EUR", - "description": "Angle is the first decentralized, capital efficient and over-collateralized stablecoin protocol", - "discord": "https://discord.gg/z3kCpTaKMh", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "twitter": "https://twitter.com/AngleProtocol", - "underlyingTokens": ["CbNYA9n3927uXUukee2Hf4tm3xxkffJPPZvGazc2EAH1"], - "website": "https://app.saber.so" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/EU9aLffrTckFCs16da6CppHy63fAxMPF9ih1erQTuuRt.png", - "name": "Saber Wrapped agEUR (Wormhole) (9 decimals)", - "symbol": "sagEUR-9", - "tags": [ - "ethereum", - "wrapped", - "wormhole", - "saber-mkt-eur", - "wormhole-v2", - "saber-dec-wrapped" - ] - }, - { - "address": "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS", - "chainId": 101, - "decimals": 6, - "extensions": { - "coingeckoId": "parrot-usd", - "currency": "USD", - "discord": "https://discord.gg/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "source": "parrot", - "sourceUrl": "https://parrot.fi/mint/", - "telegram": "https://t.me/gopartyparrot", - "twitter": "https://twitter.com/gopartyparrot", - "website": "https://parrot.fi" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS.svg", - "name": "PAI (Parrot USD)", - "symbol": "PAI", - "tags": ["utility-token", "stablecoin", "saber-mkt-usd"] - }, - { - "address": "EgQ3yNtVhdHz7g1ZhjfGbxhFKMPPaFkz8QHXM5RBZBgi", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "multi-collateral-dai", - "currency": "USD", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/EgQ3yNtVhdHz7g1ZhjfGbxhFKMPPaFkz8QHXM5RBZBgi.png", - "name": "Wrapped DAI (Allbridge from Avalanche)", - "symbol": "aaDAI", - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "address": "EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o", - "chainId": 101, - "decimals": 8, - "extensions": { - "address": "0x6b175474e89094c44da98b954eedeac495271d0f", - "assetContract": "https://etherscan.io/address/0x6b175474e89094c44da98b954eedeac495271d0f", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "dai", - "currency": "USD", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o.png", - "name": "Dai Stablecoin (Wormhole)", - "symbol": "DAI", - "tags": ["wrapped", "saber-mkt-usd", "wormhole-v2"] - }, - { - "address": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "chainId": 101, - "decimals": 6, - "extensions": { - "coingeckoId": "tether", - "currency": "USD", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "website": "https://tether.to/" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB.svg", - "name": "USDT", - "symbol": "USDT", - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "address": "EwxNF8g9UfmsJVcZFTpL9Hx5MCkoQFoJi6XNWzKf1j8e", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "celo-dollar", - "currency": "USD", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/EwxNF8g9UfmsJVcZFTpL9Hx5MCkoQFoJi6XNWzKf1j8e.png", - "name": "Wrapped CUSD (Allbridge from Celo)", - "symbol": "acUSD", - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "address": "EyrnrbE5ujd3HQG5PZd9MbECN9yaQrqc8pRwGtaLoyC", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "weth", - "currency": "ETH", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/EyrnrbE5ujd3HQG5PZd9MbECN9yaQrqc8pRwGtaLoyC.png", - "name": "Wrapped ETH (Allbridge from BSC)", - "symbol": "abETH", - "tags": ["saber-mkt-eth"] - }, - { - "address": "EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv", - "chainId": 101, - "decimals": 8, - "extensions": { - "address": "0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "assetContract": "https://etherscan.io/address/0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "ftx-token", - "currency": "FTT", - "serumV3Usdc": "2wteg25ch227n4Rh1CN4WNrDZXBpRBpWJ48mEC2K7f4r", - "serumV3Usdt": "BoHojHESAv4McZx9gXd1bWTZMq25JYyGz4qL1m5C3nvk", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv.png", - "name": "FTX Token (Wormhole)", - "symbol": "FTT", - "tags": ["wrapped", "wormhole", "saber-mkt-ftt", "wormhole-v2"] - }, - { - "address": "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W", - "chainId": 101, - "decimals": 6, - "extensions": { - "address": "uluna", - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "coingeckoId": "terra-luna", - "currency": "LUNA", - "serumV3Usdc": "HBTu8hNaoT3VyiSSzJYa8jwt9sDGKtJviSwFa11iXdmE", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W.png", - "name": "LUNA (Wormhole)", - "symbol": "LUNA", - "tags": ["wrapped", "wormhole", "saber-mkt-luna", "wormhole-v2"] - }, - { - "address": "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5", - "chainId": 101, - "decimals": 9, - "extensions": { - "assetContract": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "coingeckoId": "renbtc", - "currency": "BTC", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "source": "renbridge", - "sourceUrl": "https://bridge.renproject.io/mint", - "underlyingTokens": ["CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5"], - "website": "https://app.saber.so" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5.png", - "name": "Saber Wrapped renBTC (9 decimals)", - "symbol": "srenBTC-9", - "tags": ["saber-mkt-btc", "saber-dec-wrapped"] - }, - { - "address": "FAnGeAVpzeZM1zBvrB4V836UQjQ5K3EJcc6b1Zx9Jm1U", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "2kycGCD8tJbrjJJqWN2Qz5ysN9iB4Bth3Uic4mSB7uak", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "website": "https://app.saber.so/#/pools/HoNG9Z4jsA1qtkZhDRYBc67LF2cbusZahjyxXtXdKZgR" - }, - "logoURI": "https://registry.saber.so/token-icons/slp.png", - "name": "Saber wUSDK_V1-USDC LP", - "symbol": "wUSDKV1-USDC", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "FCqfQSujuPxy6V42UvafBhsysWtEq1vhjfMN1PUbgaxA", - "chainId": 101, - "decimals": 8, - "extensions": { - "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", - "assetContract": "https://bscscan.com/address/0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", - "bridgeContract": "https://bscscan.com/address/0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7", - "coingeckoId": "usd-coin", - "currency": "USD", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/FCqfQSujuPxy6V42UvafBhsysWtEq1vhjfMN1PUbgaxA.png", - "name": "USD Coin (Wormhole from BSC)", - "symbol": "USDCbs", - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"] - }, - { - "address": "FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp", - "chainId": 101, - "decimals": 8, - "extensions": { - "address": "0x853d955acef822db058eb8505911ed77f175b99e", - "assetContract": "https://etherscan.io/address/0x853d955acef822db058eb8505911ed77f175b99e", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "frax", - "currency": "USD", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp.png", - "name": "Frax (Wormhole)", - "symbol": "FRAX", - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v2"] - }, - { - "address": "FRAXXvt2ucEsxYPK4nufDy5zKhb2xysieqRBE1dQTqnK", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "8L8pDf3jutdpdr4m3np68CL9ZroLActrqwxi6s9Ah5xU", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "website": "https://app.saber.so/#/pools/frax" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/FRAXXvt2ucEsxYPK4nufDy5zKhb2xysieqRBE1dQTqnK.png", - "name": "Saber wFRAX_v1-USDC LP", - "symbol": "wFRAXv1-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"] - }, - { - "address": "FRXsjEv4jF3r72FgbCXu8uLbPoZGLmCmg3EN1S3cfC4x", - "chainId": 101, - "decimals": 8, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp", - "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy" - ], - "website": "https://app.saber.so/#/pools/wfrax" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/FRXsjEv4jF3r72FgbCXu8uLbPoZGLmCmg3EN1S3cfC4x.png", - "name": "Saber FRAX-USDC LP", - "symbol": "FRAX-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"] - }, - { - "address": "FTT8cGNp3rfTC6c44uPTuEFLqmsVDhjd2BhH65v2uppr", - "chainId": 101, - "decimals": 8, - "extensions": { - "assetContract": "AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3", - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "coingeckoId": "ftx-token", - "currency": "FTT", - "serumV3Usdc": "2Pbh1CvRVku1TgewMfycemghf6sU9EyuFDcNXqvRmSxc", - "serumV3Usdt": "Hr3wzG8mZXNHV7TuL6YqtgfVUesCqMxGYCEyP3otywZE", - "source": "sollet", - "sourceUrl": "https://www.sollet.io/", - "underlyingTokens": ["AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3"], - "waterfallbot": "https://bit.ly/FTTwaterfall", - "website": "https://app.saber.so" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3.png", - "name": "Saber Wrapped Wrapped FTT (Sollet) (8 decimals)", - "symbol": "ssoFTT-8", - "tags": [ - "wrapped-sollet", - "ethereum", - "saber-mkt-ftt", - "saber-dec-wrapped" - ] - }, - { - "address": "FTT9GrHBVHvDeUTgLU8FxVJouGqg9uiWGmmjETdm32Sx", - "chainId": 101, - "decimals": 9, - "extensions": { - "address": "0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "assetContract": "EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "ftx-token", - "currency": "FTT", - "serumV3Usdc": "2wteg25ch227n4Rh1CN4WNrDZXBpRBpWJ48mEC2K7f4r", - "serumV3Usdt": "BoHojHESAv4McZx9gXd1bWTZMq25JYyGz4qL1m5C3nvk", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "underlyingTokens": ["EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv"], - "website": "https://app.saber.so" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/FTT9GrHBVHvDeUTgLU8FxVJouGqg9uiWGmmjETdm32Sx.png", - "name": "Saber Wrapped FTX Token (Wormhole) (9 decimals)", - "symbol": "sFTT-9", - "tags": [ - "wrapped", - "wormhole", - "saber-mkt-ftt", - "wormhole-v2", - "saber-dec-wrapped" - ] - }, - { - "address": "FTT9rBBrYwcHam4qLvkzzzhrsihYMbZ3k6wJbdoahxAt", - "chainId": 101, - "decimals": 9, - "extensions": { - "assetContract": "AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3", - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "coingeckoId": "ftx-token", - "currency": "FTT", - "serumV3Usdc": "2Pbh1CvRVku1TgewMfycemghf6sU9EyuFDcNXqvRmSxc", - "serumV3Usdt": "Hr3wzG8mZXNHV7TuL6YqtgfVUesCqMxGYCEyP3otywZE", - "source": "sollet", - "sourceUrl": "https://www.sollet.io/", - "underlyingTokens": ["AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3"], - "waterfallbot": "https://bit.ly/FTTwaterfall", - "website": "https://app.saber.so" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/FTT9rBBrYwcHam4qLvkzzzhrsihYMbZ3k6wJbdoahxAt.png", - "name": "Saber Wrapped Wrapped FTT (Sollet) (9 decimals)", - "symbol": "ssoFTT-9", - "tags": [ - "wrapped-sollet", - "ethereum", - "saber-mkt-ftt", - "saber-dec-wrapped" - ] - }, - { - "address": "FTXdV5wFFhceKjcd1JRrRQTT2uB7ruMerAqbj2rj1Mz7", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "GbBWwtYTMPis4VHb8MrBbdibPhn28TSrLB53KvUmb7Gi", - "FTT9rBBrYwcHam4qLvkzzzhrsihYMbZ3k6wJbdoahxAt" - ], - "website": "https://app.saber.so/#/pools/ftt" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/FTXdV5wFFhceKjcd1JRrRQTT2uB7ruMerAqbj2rj1Mz7.png", - "name": "Saber wFTT_v1-soFTT LP", - "symbol": "wFTTv1-soFTT", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"] - }, - { - "address": "FTXjwjwWqituSXEHnL5VF1mjDhZoAyJqvHiRPsRq3KWK", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "BFsCwfk8VsEbSfLkkgmoKsAPk2N6FMJjeTsuxfGa9VEf", - "FTT9GrHBVHvDeUTgLU8FxVJouGqg9uiWGmmjETdm32Sx" - ], - "website": "https://app.saber.so/#/pools/wftt" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/FTXjwjwWqituSXEHnL5VF1mjDhZoAyJqvHiRPsRq3KWK.png", - "name": "Saber aeFTT-FTT LP", - "symbol": "aeFTT-FTT", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"] - }, - { - "address": "FYpdBuyAHSbdaAyD1sKkxyLWbAP8uUW9h6uvdhK74ij1", - "chainId": 101, - "decimals": 9, - "extensions": { - "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", - "assetContract": "https://etherscan.io/address/0x6B175474E89094C44Da98b954EedeAC495271d0F", - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "coingeckoId": "dai", - "currency": "USD", - "source": "wormhole-v1", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/FYpdBuyAHSbdaAyD1sKkxyLWbAP8uUW9h6uvdhK74ij1.png", - "name": "Dai Stablecoin (Wormhole v1)", - "symbol": "wDAI_v1", - "tags": ["wrapped", "wormhole", "saber-mkt-usd", "wormhole-v1"] - }, - { - "address": "Fd8xyHHRjTvxfZrBirb6MaxSmrZYw99gRSqFUKdFwFvw", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "wrapped-bitcoin", - "currency": "BTC", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/Fd8xyHHRjTvxfZrBirb6MaxSmrZYw99gRSqFUKdFwFvw.png", - "name": "Wrapped BTC (Allbridge from Avalanche)", - "symbol": "aaWBTC", - "tags": ["saber-mkt-btc"] - }, - { - "address": "FdvkkCbCgYht1xTR1W9MBJhEF1JEPVhHtW1NXBYRzZts", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "wrapped-bitcoin", - "currency": "BTC", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/FdvkkCbCgYht1xTR1W9MBJhEF1JEPVhHtW1NXBYRzZts.png", - "name": "Wrapped BTC (Allbridge from Fantom)", - "symbol": "afBTC", - "tags": ["saber-mkt-btc"] - }, - { - "address": "FgSsGV8GByPaMERxeQJPvZRZHf7zCBhrdYtztKorJS58", - "chainId": 101, - "decimals": 6, - "extensions": { - "currency": "USD", - "source": "port", - "sourceUrl": "https://mainnet.port.finance/#/markets", - "website": "https://port.finance" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/FgSsGV8GByPaMERxeQJPvZRZHf7zCBhrdYtztKorJS58.svg", - "name": "Port Finance USDC", - "symbol": "pUSDC", - "tags": ["port", "lending", "collateral-tokens", "saber-mkt-usd"] - }, - { - "address": "Fr3W7NPVvdVbwMcHgA7Gx2wUxP43txdsn3iULJGFbKz9", - "chainId": 101, - "decimals": 8, - "extensions": { - "coingeckoId": "ftx-token", - "currency": "FTT", - "source": "synthetify", - "sourceUrl": "https://app.synthetify.io/staking", - "twitter": "https://twitter.com/synthetify", - "website": "https://synthetify.io/" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/Fr3W7NPVvdVbwMcHgA7Gx2wUxP43txdsn3iULJGFbKz9.svg", - "name": "Synthetic FTT", - "symbol": "xFTT", - "tags": ["saber-mkt-ftt"] - }, - { - "address": "FwEHs3kJEdMa2qZHv7SgzCiFXUQPEycEXksfBkwmS8gj", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "tether", - "currency": "USD", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/FwEHs3kJEdMa2qZHv7SgzCiFXUQPEycEXksfBkwmS8gj.svg", - "name": "Wrapped USDT (Allbridge from Avalanche)", - "symbol": "aaUSDT", - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "address": "GEJpt3Wjmr628FqXxTgxMce1pLntcPV4uFi8ksxMyPQh", - "chainId": 101, - "decimals": 9, - "extensions": { - "currency": "SOL", - "description": "daoSOL is the staking token issued by the MonkeDAO staking pool", - "source": "monkedao", - "sourceUrl": "https://daopool.monkedao.io/", - "twitter": "https://twitter.com/MonkeDAO", - "website": "https://monkedao.io/" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/GEJpt3Wjmr628FqXxTgxMce1pLntcPV4uFi8ksxMyPQh.png", - "name": "daoSOL Token", - "symbol": "daoSOL", - "tags": ["stake-pool-token", "saber-mkt-sol"] - }, - { - "address": "GEcowHQW46CrEkfAdbcsdt4SV7taCetZF4sFBXN4USDC", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "DHpoYejUDqzByb6HAdaLWF7KZvwUv2vWYDY9cTENNZui" - ], - "website": "https://app.saber.so/#/pools/acusdc" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/GEcowHQW46CrEkfAdbcsdt4SV7taCetZF4sFBXN4USDC.png", - "name": "Saber USDC-acUSDC LP", - "symbol": "USDC-acUSDC", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "GbBWwtYTMPis4VHb8MrBbdibPhn28TSrLB53KvUmb7Gi", - "chainId": 101, - "decimals": 9, - "extensions": { - "address": "0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "assetContract": "https://etherscan.io/address/0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "coingeckoId": "ftx-token", - "currency": "FTT", - "source": "wormhole-v1", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/GbBWwtYTMPis4VHb8MrBbdibPhn28TSrLB53KvUmb7Gi.png", - "name": "FTT (Wormhole v1)", - "symbol": "wFTT_v1", - "tags": ["wrapped", "wormhole", "saber-mkt-ftt", "wormhole-v1"] - }, - { - "address": "GfzU1fLASNV3r4NtEyrnwTyTakJkYzoivnaL3Snh45oj", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "tether", - "currency": "USD", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/GfzU1fLASNV3r4NtEyrnwTyTakJkYzoivnaL3Snh45oj.png", - "name": "Wrapped USDT (Allbridge from HECO)", - "symbol": "ahUSDT", - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "address": "Grk6b4UMRWkgyq4Y6S1BnNRF4hRgtnMFp7Sorkv6Ez4u", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "usd-coin", - "currency": "USD", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/Grk6b4UMRWkgyq4Y6S1BnNRF4hRgtnMFp7Sorkv6Ez4u.png", - "name": "Wrapped USDC (Allbridge from Fantom)", - "symbol": "afUSDC", - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "address": "HBTCNvkwjMsEtwe2PeXUuMcu8C4Hobw6HDP2m6vpWHGo", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "8pBc4v9GAwCBNWPB5XKA93APexMGAS4qMr37vNke9Ref", - "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5" - ], - "website": "https://app.saber.so/#/pools/hbtc" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/HBTCNvkwjMsEtwe2PeXUuMcu8C4Hobw6HDP2m6vpWHGo.png", - "name": "Saber wHBTC_v1-renBTC LP", - "symbol": "wHBTCv1-renBTC", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"] - }, - { - "address": "HLPC9r4gbeP6KagT3qJLzFj7iWcYTJs245k9tuHFQGyR", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "GfzU1fLASNV3r4NtEyrnwTyTakJkYzoivnaL3Snh45oj", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "website": "https://app.saber.so/#/pools/ahusdt" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/HLPC9r4gbeP6KagT3qJLzFj7iWcYTJs245k9tuHFQGyR.png", - "name": "Saber ahUSDT-USDC LP", - "symbol": "ahUSDT-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "HLPPmd7NzTTNiqKR6rAZYgrH9VhU47kxftecQSk2oD6J", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "Bo4ehCeRcRj2wp5tQpjfCJxYFn4KyRacfDzSa4Aj27tH", - "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5" - ], - "website": "https://app.saber.so/#/pools/ahwbtc" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/HLPPmd7NzTTNiqKR6rAZYgrH9VhU47kxftecQSk2oD6J.png", - "name": "Saber ahBTC-renBTC LP", - "symbol": "ahBTC-renBTC", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "HUBBGekfLpdZhZcqjLeecLVz39o1ysDkicZpgMgZgPFS", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "website": "https://app.saber.so/#/pools/usdh" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/HUBBGekfLpdZhZcqjLeecLVz39o1ysDkicZpgMgZgPFS.png", - "name": "Saber USDH-USDC LP", - "symbol": "USDH-USDC", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "HUBBMrYrYpxkPbBbULdsvSrcoa6Qv526AGuosrhF8V59", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT" - ], - "website": "https://app.saber.so/#/pools/usdh_cash" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/HUBBMrYrYpxkPbBbULdsvSrcoa6Qv526AGuosrhF8V59.png", - "name": "Saber USDH-CASH LP", - "symbol": "USDH-CASH", - "tags": ["saber-stableswap-lp", "saber-lp-cashio"] - }, - { - "address": "HUSDgP5YieANhAAHD42yivX9aFS1zbodTut2Dvvkj8QS", - "chainId": 101, - "decimals": 8, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "BybpSTBoZHsmKnfxYG47GDhVPKrnEKX31CScShbrzUhX", - "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy" - ], - "website": "https://app.saber.so/#/pools/husd" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/HUSDgP5YieANhAAHD42yivX9aFS1zbodTut2Dvvkj8QS.png", - "name": "Saber wHUSD_v1-USDC LP", - "symbol": "wHUSDv1-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"] - }, - { - "address": "HUSzWddUQbavKn24cjozm65eps8rq9yhNn5edtTLWfdz", - "chainId": 101, - "decimals": 8, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "7VQo3HFLNH5QqGtM8eC3XQbPkJUu7nS9LeGWjerRh5Sw", - "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy" - ], - "website": "https://app.saber.so/#/pools/whusd" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/HUSzWddUQbavKn24cjozm65eps8rq9yhNn5edtTLWfdz.png", - "name": "Saber HUSD-USDC LP", - "symbol": "HUSD-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"] - }, - { - "address": "HWxpSV3QAGzLQzGAtvhSYAEr7sTQugQygnni1gnUGh1D", - "chainId": 101, - "decimals": 10, - "extensions": { - "coingeckoId": "bitcoin", - "currency": "BTC", - "source": "synthetify", - "sourceUrl": "https://app.synthetify.io/staking", - "twitter": "https://twitter.com/synthetify", - "website": "https://synthetify.io/" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/HWxpSV3QAGzLQzGAtvhSYAEr7sTQugQygnni1gnUGh1D.svg", - "name": "Synthetic BTC", - "symbol": "xBTC", - "tags": ["saber-mkt-btc"] - }, - { - "address": "Hg35Vd8K3BS2pLB3xwC2WqQV8pmpCm3oNRGYP1PEpmCM", - "chainId": 101, - "decimals": 9, - "extensions": { - "currency": "SOL", - "medium": "https://medium.com/everstake", - "source": "Everstake", - "sourceUrl": "https://eversol.one/app", - "twitter": "https://twitter.com/everstake_pool", - "website": "https://everstake.one" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/Hg35Vd8K3BS2pLB3xwC2WqQV8pmpCm3oNRGYP1PEpmCM.png", - "name": "EverSOL staked SOL (eSOL)", - "symbol": "eSOL", - "tags": ["saber-mkt-sol"] - }, - { - "address": "HjUhUzi6fVkY1BndaSc4Dcg2mCzvnqzXjVJtXsj78ver", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "dai", - "currency": "USD", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/HjUhUzi6fVkY1BndaSc4Dcg2mCzvnqzXjVJtXsj78ver.png", - "name": "Wrapped DAI (Allbridge from Fantom)", - "symbol": "afDAI", - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "chainId": 101, - "decimals": 9, - "extensions": { - "assetContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "coingeckoId": "usd-coin", - "currency": "USD", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "underlyingTokens": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"], - "website": "https://app.saber.so" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1.png", - "name": "Saber Wrapped USD Coin (9 decimals)", - "symbol": "sUSDC-9", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"] - }, - { - "address": "KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma", - "chainId": 101, - "decimals": 9, - "extensions": { - "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "assetContract": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "ethereum", - "currency": "ETH", - "serumV3Usdc": "8Gmi2HhZmwQPVdCwzS7CM66MGstMXPcTVHA7jF19cLZz", - "serumV3Usdt": "ch7kmPrtoQUSEPBggcNAvLGiMQkJagVwd3gDYfd8m7Q", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "underlyingTokens": ["7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs"], - "website": "https://app.saber.so" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma.png", - "name": "Saber Wrapped Ether (Wormhole) (9 decimals)", - "symbol": "sETH-9", - "tags": [ - "wrapped", - "wormhole", - "saber-mkt-eth", - "wormhole-v2", - "saber-dec-wrapped" - ] - }, - { - "address": "KUANeD8EQvwpT1W7QZDtDqctLEh2FfSTy5pThE9CogT", - "chainId": 101, - "decimals": 9, - "extensions": { - "assetContract": "8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE", - "currency": "LUNA", - "serumV3Usdc": "CxDhLbbM9uAA2AXfSPar5qmyfmC69NLj3vgJXYAsSVBT", - "source": "renbridge", - "sourceUrl": "https://bridge.renproject.io/mint", - "underlyingTokens": ["8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE"], - "website": "https://app.saber.so" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/KUANeD8EQvwpT1W7QZDtDqctLEh2FfSTy5pThE9CogT.png", - "name": "Saber Wrapped renLUNA (9 decimals)", - "symbol": "srenLUNA-9", - "tags": ["saber-mkt-luna", "saber-dec-wrapped"] - }, - { - "address": "KWAMdUrCdQ2j1t9S1HD29Z4RxXymXkwSh2c94598amY", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "3LKZU3iQx9KM94S4uYRdYwAHTm6odDyzGQqTBNj7J27z", - "LUNGEjUXyP48nrC1GYY5o4eTAkwm4RdX8BxFUxWJBLB" - ], - "website": "https://app.saber.so/#/pools/atust_wust" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/KWAMdUrCdQ2j1t9S1HD29Z4RxXymXkwSh2c94598amY.png", - "name": "Saber atLUNA-LUNA LP", - "symbol": "atLUNA-LUNA", - "tags": [ - "saber-stableswap-lp", - "saber-lp-allbridge", - "saber-lp-wormhole-v2" - ] - }, - { - "address": "LUN1p1dZwSBgTv1JSdn2apdUuLanHKtgNcnpDydVFTU", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W", - "8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE" - ], - "website": "https://app.saber.so/#/pools/wluna" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/LUN1p1dZwSBgTv1JSdn2apdUuLanHKtgNcnpDydVFTU.png", - "name": "Saber LUNA-renLUNA LP", - "symbol": "LUNA-renLUNA", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"] - }, - { - "address": "LUNGEjUXyP48nrC1GYY5o4eTAkwm4RdX8BxFUxWJBLB", - "chainId": 101, - "decimals": 9, - "extensions": { - "address": "uluna", - "assetContract": "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W", - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "coingeckoId": "terra-luna", - "currency": "LUNA", - "serumV3Usdc": "HBTu8hNaoT3VyiSSzJYa8jwt9sDGKtJviSwFa11iXdmE", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "underlyingTokens": ["F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W"], - "website": "https://app.saber.so" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W.png", - "name": "Saber Wrapped LUNA (Wormhole) (9 decimals)", - "symbol": "sLUNA-9", - "tags": [ - "wrapped", - "wormhole", - "saber-mkt-luna", - "wormhole-v2", - "saber-dec-wrapped" - ] - }, - { - "address": "LUNbjQA8GAwotiHPiq9cmdVkEfYgZFGhBFnHhicjZtP", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "6MeoZEcUMhAB788YXTQN4x7K8MnwSt6RHWsLkuq9GJb2", - "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W" - ], - "website": "https://app.saber.so/#/pools/xluna" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/LUNbjQA8GAwotiHPiq9cmdVkEfYgZFGhBFnHhicjZtP.png", - "name": "Saber xLUNA-LUNA LP", - "symbol": "xLUNA-LUNA", - "tags": ["saber-stableswap-lp", "saber-lp-synthetify"] - }, - { - "address": "LUNkiLcb2wxcqULmJvMjuM6YQhpFBadG5KZBe7qBpSE", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "2Xf2yAXJfg82sWwdLUo2x9mZXy6JCdszdMZkcF1Hf4KV", - "KUANeD8EQvwpT1W7QZDtDqctLEh2FfSTy5pThE9CogT" - ], - "website": "https://app.saber.so/#/pools/luna" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/LUNkiLcb2wxcqULmJvMjuM6YQhpFBadG5KZBe7qBpSE.png", - "name": "Saber wLUNA_v1-renLUNA LP", - "symbol": "wLUNAv1-renLUNA", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"] - }, - { - "address": "Lirav2gsqs7jL1PFRUBp8uKACT8LYjDBV8c6nzchoer", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "9QBTKuSCDaJjtxYnYcVzoiKENMdJ5DRei5ZUCEeWyZnj", - "A94X2fRy3wydNShU4dRaDyap2UuoeWJGWyATtyp61WZf" - ], - "website": "https://app.saber.so/#/pools/bilira" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/Lirav2gsqs7jL1PFRUBp8uKACT8LYjDBV8c6nzchoer.png", - "name": "Saber TRYB-TRYB LP", - "symbol": "TRYB-TRYB", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"] - }, - { - "address": "MAiP3Zmjhc6NYiCb2xK2893ifvTTDHciCS57Kga39pC", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "9mWRABuz2x6koTPCWiCPM49WUbcrNqGTHBV9T9k7y1o7", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "website": "https://app.saber.so/#/pools/mai" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/MAiP3Zmjhc6NYiCb2xK2893ifvTTDHciCS57Kga39pC.png", - "name": "Saber MAI-USDC LP", - "symbol": "MAI-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "PLYJZgSkcV8UXTWhTyf2WLCMeBoZum1Y4rXgXkoYiNj", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "DNhZkUaxHXYvpxZ7LNnHtss8sQgdAfd1ZYS1fB7LKWUZ", - "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" - ], - "website": "https://app.saber.so/#/pools/apusdt" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/PLYJZgSkcV8UXTWhTyf2WLCMeBoZum1Y4rXgXkoYiNj.png", - "name": "Saber apUSDT-USDT LP", - "symbol": "apUSDT-USDT", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "PSopTFPXzTRysj2H6W8oTvYBZmJHtRcVaQaDkckifAy", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "9EaLkQrbjmbbuZG9Wdpo8qfNUEjHATJFSycEmw6f1rGX", - "BdZPG9xWrG3uFrx2KrUW1jT4tZ9VKPDWknYihzoPRJS3" - ], - "website": "https://app.saber.so/#/pools/psol" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/PSopTFPXzTRysj2H6W8oTvYBZmJHtRcVaQaDkckifAy.png", - "name": "Saber pSOL-prtSOL LP", - "symbol": "pSOL-prtSOL", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "PaiYwHYxr4SsEWox9YmyBNJmxVG7GdauirbBcYGB7cJ", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "website": "https://app.saber.so/#/pools/usdc_pai" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/PaiYwHYxr4SsEWox9YmyBNJmxVG7GdauirbBcYGB7cJ.png", - "name": "Saber PAI-USDC LP", - "symbol": "PAI-USDC", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "PortuzxBGYMQXeNmM9Kc6AtHLBwqSrb6xWwZ4trQ1en", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "3RudPTAkfcq9Q9Jk8SVeCoecCBmdKMj6q5smsWzxqtqZ", - "FgSsGV8GByPaMERxeQJPvZRZHf7zCBhrdYtztKorJS58" - ], - "website": "https://app.saber.so/#/pools/port_2pool" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/PortuzxBGYMQXeNmM9Kc6AtHLBwqSrb6xWwZ4trQ1en.png", - "name": "Saber pUSDT-pUSDC LP", - "symbol": "pUSDT-pUSDC", - "tags": ["saber-stableswap-lp", "saber-lp-port"] - }, - { - "address": "PrsVdKtXDDf6kJQu5Ff6YqmjfE4TZXtBgHM4bjuvRnR", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "BdZPG9xWrG3uFrx2KrUW1jT4tZ9VKPDWknYihzoPRJS3", - "So11111111111111111111111111111111111111112" - ], - "website": "https://app.saber.so/#/pools/prtsol" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/PrsVdKtXDDf6kJQu5Ff6YqmjfE4TZXtBgHM4bjuvRnR.png", - "name": "Saber prtSOL-SOL LP", - "symbol": "prtSOL-SOL", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "SBTCB6pWqeDo6zGi9WVRMLCsKsN6JiR1RMUqvLtgSRv", - "chainId": 101, - "decimals": 8, - "extensions": { - "assetContract": "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "coingeckoId": "bitcoin", - "currency": "BTC", - "serumV3Usdc": "A8YFbxQYFVqKZaoYJLLUVcQiWP7G2MeEgW5wsAQgMvFw", - "serumV3Usdt": "C1EuT9VokAKLiW7i2ASnZUvxDoKuKkCpDDeNxAptuNe4", - "source": "sollet", - "sourceUrl": "https://www.sollet.io/", - "underlyingTokens": ["9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E"], - "website": "https://app.saber.so" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/SBTCB6pWqeDo6zGi9WVRMLCsKsN6JiR1RMUqvLtgSRv.png", - "name": "Saber Wrapped Wrapped Bitcoin (Sollet) (8 decimals)", - "symbol": "sBTC-8", - "tags": [ - "wrapped-sollet", - "ethereum", - "saber-mkt-btc", - "saber-dec-wrapped" - ] - }, - { - "address": "SL819j8K9FuFPL84UepVcFkEZqDUUvVzwDmJjCHySYj", - "chainId": 101, - "decimals": 8, - "extensions": { - "assetContract": "2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk", - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "coingeckoId": "ethereum", - "currency": "ETH", - "serumV3Usdc": "4tSvZvnbyzHXLMTiFonMyxZoHmFqau1XArcRCVHLZ5gX", - "serumV3Usdt": "7dLVkUfBVfCGkFhSXDCq1ukM9usathSgS716t643iFGF", - "source": "sollet", - "sourceUrl": "https://www.sollet.io/", - "underlyingTokens": ["2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk"], - "website": "https://app.saber.so" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/SL819j8K9FuFPL84UepVcFkEZqDUUvVzwDmJjCHySYj.png", - "name": "Saber Wrapped Wrapped Ethereum (Sollet) (8 decimals)", - "symbol": "ssoETH-8", - "tags": [ - "wrapped-sollet", - "ethereum", - "saber-mkt-eth", - "saber-dec-wrapped" - ] - }, - { - "address": "SLPbsNrLHv8xG4cTc4R5Ci8kB9wUPs6yn6f7cKosoxs", - "chainId": 101, - "decimals": 8, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "SBTCB6pWqeDo6zGi9WVRMLCsKsN6JiR1RMUqvLtgSRv" - ], - "website": "https://app.saber.so/#/pools/btc" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/SLPbsNrLHv8xG4cTc4R5Ci8kB9wUPs6yn6f7cKosoxs.png", - "name": "Saber BTC-renBTC LP", - "symbol": "BTC-renBTC", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "SPaiZAYyJBQHaSjtxFBKtLtQiCuG328r1mTfmvvydR5", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS" - ], - "website": "https://app.saber.so/#/pools/4vezWG46exH6pf9nry3n1VJ7hZHvjBJNgNeF4qEFCML5" - }, - "logoURI": "https://registry.saber.so/token-icons/slp.png", - "name": "Saber USDC-PAI LP", - "symbol": "USDC-PAI", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "SRMKjSJpBHJ5gSVTrimci49SnXc1LVkBi9TGF9RNYdp", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "2jXy799YnEcRXneFo2GEAB6SDRsAa767HpWmktRr1DaP", - "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt" - ], - "website": "https://app.saber.so/#/pools/srm" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/SRMKjSJpBHJ5gSVTrimci49SnXc1LVkBi9TGF9RNYdp.png", - "name": "Saber wSRM_V1-SRM LP", - "symbol": "wSRMV1-SRM", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"] - }, - { - "address": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "chainId": 101, - "decimals": 6, - "extensions": { - "coingeckoId": "serum", - "currency": "SRM", - "serumV3Usdc": "ByRys5tuUWDgL73G8JBAEfkdFf8JWBzPBDHsBVQ5vbQA", - "serumV3Usdt": "AtNnsY1AyRERWJ8xCskfz38YdvruWVJQUVXgScC1iPb", - "waterfallbot": "https://bit.ly/SRMwaterfall", - "website": "https://projectserum.com/" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt.png", - "name": "Serum", - "symbol": "SRM", - "tags": ["saber-mkt-srm"] - }, - { - "address": "Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1", - "chainId": 101, - "decimals": 6, - "extensions": { - "coingeckoId": "saber", - "discord": "https://chat.saber.so", - "github": "https://github.com/saber-hq", - "medium": "https://blog.saber.so", - "serumV3Usdc": "HXBi8YBwbh4TXF6PjVw81m8Z3Cc4WBofvauj5SBFdgUs", - "twitter": "https://twitter.com/saber_hq", - "waterfallbot": "https://bit.ly/SBRwaterfall", - "website": "https://saber.so" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1.svg", - "name": "Saber Protocol Token", - "symbol": "SBR", - "tags": ["saber-hidden"] - }, - { - "address": "So11111111111111111111111111111111111111112", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "solana", - "currency": "SOL", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "website": "https://solana.com/" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/So11111111111111111111111111111111111111112.png", - "name": "Wrapped SOL", - "symbol": "SOL", - "tags": ["saber-mkt-sol"] - }, - { - "address": "SoCJs5Qw1D3fjGbTqxxovK15FVnYVrwvTbYcBBrZmWj", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "So11111111111111111111111111111111111111112" - ], - "website": "https://app.saber.so/#/pools/socean" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/SoCJs5Qw1D3fjGbTqxxovK15FVnYVrwvTbYcBBrZmWj.png", - "name": "Saber scnSOL-SOL LP", - "symbol": "scnSOL-SOL", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "SoLEao8wTzSfqhuou8rcYsVoLjthVmiXuEjzdNPMnCz", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "So11111111111111111111111111111111111111112" - ], - "website": "https://app.saber.so/#/pools/msol_sol" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/SoLEao8wTzSfqhuou8rcYsVoLjthVmiXuEjzdNPMnCz.png", - "name": "Saber mSOL-SOL LP", - "symbol": "mSOL-SOL", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "SoLd9SEn8kqLHAd3HqKa35wz87LzpgxiVRBATjkn9a7", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "So11111111111111111111111111111111111111112" - ], - "website": "https://app.saber.so/#/pools/LeekqF2NMKiFNtYD6qXJHZaHx4hUdj4UiPu4t8sz7uK" - }, - "logoURI": "https://registry.saber.so/token-icons/slp.png", - "name": "Saber mSOL-SOL LP", - "symbol": "mSOL-SOL", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "T8KdT8hDzNhbGx5sjpEUxepnbDB1TZoCa7vtC5JjsMw", - "chainId": 101, - "decimals": 8, - "extensions": { - "assetContract": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "coingeckoId": "tether", - "currency": "USD", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "underlyingTokens": ["Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"], - "website": "https://app.saber.so" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/T8KdT8hDzNhbGx5sjpEUxepnbDB1TZoCa7vtC5JjsMw.png", - "name": "Saber Wrapped USDT (8 decimals)", - "symbol": "sUSDT-8", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"] - }, - { - "address": "USDCgfM1psLGhAbx99iPA72mTySvUcVq33qhCJpm65c", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "A9mUU4qviSctJVPJdBJWkb28deg915LYJKrzQ19ji3FM", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "website": "https://app.saber.so/#/pools/weusdc" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/USDCgfM1psLGhAbx99iPA72mTySvUcVq33qhCJpm65c.png", - "name": "Saber USDCet-USDC LP", - "symbol": "USDCet-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"] - }, - { - "address": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "chainId": 101, - "decimals": 6, - "extensions": { - "currency": "USD", - "discord": "https://discord.gg/d44A8WvK", - "source": "Hubble", - "sourceUrl": "https://app.hubbleprotocol.io/", - "twitter": "https://twitter.com/hubbleprotocol", - "website": "https://hubbleprotocol.io/" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX.svg", - "name": "USDH Hubble Stablecoin", - "symbol": "USDH", - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "address": "USDKKmk1anWU1aEn6GJ6skL3ZvcB9CBAWVkmPGQEHtz", - "chainId": 101, - "decimals": 8, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "43m2ewFV5nDepieFjT9EmAQnc1HRtAF247RBpLGFem5F", - "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy" - ], - "website": "https://app.saber.so/#/pools/wusdk" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/USDKKmk1anWU1aEn6GJ6skL3ZvcB9CBAWVkmPGQEHtz.png", - "name": "Saber USDK-USDC LP", - "symbol": "USDK-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"] - }, - { - "address": "USDTJZL2vH92K5QeCvQTTzvMXUYAdvk3v46CwZyfsue", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "Dn4noZ5jgGfkntzcQSUZ8czkreiZ1ForXYoV2H8Dm7S1", - "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" - ], - "website": "https://app.saber.so/#/pools/weusdt" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/USDTJZL2vH92K5QeCvQTTzvMXUYAdvk3v46CwZyfsue.png", - "name": "Saber USDTet-USDT LP", - "symbol": "USDTet-USDT", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"] - }, - { - "address": "UST32f2JtPGocLzsL41B3VBBoJzTm1mK1j3rwyM3Wgc", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "CXLBjMMcwkc17GfJtBos6rQCo1ypeH6eDbB82Kby4MRm" - ], - "website": "https://app.saber.so/#/pools/ust" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/UST32f2JtPGocLzsL41B3VBBoJzTm1mK1j3rwyM3Wgc.png", - "name": "Saber wUST_v1-USDC LP", - "symbol": "wUSTv1-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"] - }, - { - "address": "UST8SCn7jrqsq51odVLqcmvnC658HkqrKrPL3w2hHQ7", - "chainId": 101, - "decimals": 8, - "extensions": { - "address": "uusd", - "assetContract": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "coingeckoId": "terrausd", - "currency": "USD", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "underlyingTokens": ["9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i"], - "website": "https://app.saber.so" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/UST8SCn7jrqsq51odVLqcmvnC658HkqrKrPL3w2hHQ7.png", - "name": "Saber Wrapped UST (Wormhole) (8 decimals)", - "symbol": "sUST-8", - "tags": [ - "wrapped", - "wormhole", - "saber-mkt-usd", - "wormhole-v2", - "saber-dec-wrapped" - ] - }, - { - "address": "UST98bfV6EASdTFQrRwCBczpehdMFwYCUdLT5tEbhpW", - "chainId": 101, - "decimals": 9, - "extensions": { - "address": "uusd", - "assetContract": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "coingeckoId": "terrausd", - "currency": "USD", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer", - "underlyingTokens": ["9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i"], - "website": "https://app.saber.so" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/UST98bfV6EASdTFQrRwCBczpehdMFwYCUdLT5tEbhpW.png", - "name": "Saber Wrapped UST (Wormhole) (9 decimals)", - "symbol": "sUST-9", - "tags": [ - "wrapped", - "wormhole", - "saber-mkt-usd", - "wormhole-v2", - "saber-dec-wrapped" - ] - }, - { - "address": "USTCmQpbUGj5iTsXdnTYHZupY1QpftDZhLokSVk6UWi", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "website": "https://app.saber.so/#/pools/wust" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/USTCmQpbUGj5iTsXdnTYHZupY1QpftDZhLokSVk6UWi.png", - "name": "Saber UST-USDC LP", - "symbol": "UST-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"] - }, - { - "address": "UXDgmqLd1roNYkC4TmJzok61qcM9oKs5foDADiFoCiJ", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "website": "https://app.saber.so/#/pools/uxd" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/UXDgmqLd1roNYkC4TmJzok61qcM9oKs5foDADiFoCiJ.png", - "name": "Saber UXD-USDC LP", - "symbol": "UXD-USDC", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "UXDjCH2xGyyLWa92stSUDftWPKGFFPEvqvk28gQA8bW", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT", - "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT" - ], - "website": "https://app.saber.so/#/pools/uxd_cash" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/UXDjCH2xGyyLWa92stSUDftWPKGFFPEvqvk28gQA8bW.png", - "name": "Saber UXD-CASH LP", - "symbol": "UXD-CASH", - "tags": ["saber-stableswap-lp", "saber-lp-cashio"] - }, - { - "address": "WLP59xUDvQMQdzC2SgPmZeRF1oj2RSvGZiQLksj4bwj", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "5goWRao6a3yNC4d6UjMdQxonkCMvKBwdpubU3qhfcdf1", - "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB" - ], - "website": "https://app.saber.so/#/pools/wpusdt" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/WLP59xUDvQMQdzC2SgPmZeRF1oj2RSvGZiQLksj4bwj.png", - "name": "Saber USDTpo-USDT LP", - "symbol": "USDTpo-USDT", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"] - }, - { - "address": "WLP7MDjSKGWxs2s6o2d8JFvvqLJD8KHZpcTAZf9ongE", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG", - "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt" - ], - "website": "https://app.saber.so/#/pools/wsrm" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/WLP7MDjSKGWxs2s6o2d8JFvvqLJD8KHZpcTAZf9ongE.png", - "name": "Saber SRMet-SRM LP", - "symbol": "SRMet-SRM", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"] - }, - { - "address": "WLP9nwD2FUJyNeKWGEi8QnF1a5G3VC7zM9uCqE1W8tx", - "chainId": 101, - "decimals": 8, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "Bzq68gAVedKqQkQbsM28yQ4LYpc2VComDUD9wJBywdTi", - "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5" - ], - "website": "https://app.saber.so/#/pools/wibbtc" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/WLP9nwD2FUJyNeKWGEi8QnF1a5G3VC7zM9uCqE1W8tx.png", - "name": "Saber wibBTC-renBTC LP", - "symbol": "wibBTC-renBTC", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"] - }, - { - "address": "WLP9zHZ3FcsPAcM891AQBn4ZWyS3wYgddiLPbSyzmDm", - "chainId": 101, - "decimals": 8, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "7dVH61ChzgmN9BwG4PkzwRP8PbYwPJ7ZPNF2vamKT2H8", - "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5" - ], - "website": "https://app.saber.so/#/pools/whbtc" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/WLP9zHZ3FcsPAcM891AQBn4ZWyS3wYgddiLPbSyzmDm.png", - "name": "Saber HBTC-renBTC LP", - "symbol": "HBTC-renBTC", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"] - }, - { - "address": "WLPAEUgB95YrU7Vk1FVPeSP5C3e66bf63frHRgsyxHv", - "chainId": 101, - "decimals": 8, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "8qJSyQprMC57TWKaYEmetUR3UUiTP2M3hXdcvFhkZdmv", - "T8KdT8hDzNhbGx5sjpEUxepnbDB1TZoCa7vtC5JjsMw" - ], - "website": "https://app.saber.so/#/pools/wbusdt" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/WLPAEUgB95YrU7Vk1FVPeSP5C3e66bf63frHRgsyxHv.png", - "name": "Saber USDTbs-USDT LP", - "symbol": "USDTbs-USDT", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"] - }, - { - "address": "WLPGfDvnSsJg888FydDCRKkmKTwu4L3MHjfqBFj5LJD", - "chainId": 101, - "decimals": 8, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp", - "UST8SCn7jrqsq51odVLqcmvnC658HkqrKrPL3w2hHQ7" - ], - "website": "https://app.saber.so/#/pools/frax_ust" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/WLPGfDvnSsJg888FydDCRKkmKTwu4L3MHjfqBFj5LJD.png", - "name": "Saber FRAX-UST LP", - "symbol": "FRAX-UST", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"] - }, - { - "address": "WLPJD4jW6gnWKfwfL5jyJwcxEPHKLMbncNfQwMmkzKz", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "7g166TuBmnoHKvS2PEkZx6kREZtbfjUxCHGWjCqoDXZv", - "EU9aLffrTckFCs16da6CppHy63fAxMPF9ih1erQTuuRt" - ], - "website": "https://app.saber.so/#/pools/aceur_ageur" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/WLPJD4jW6gnWKfwfL5jyJwcxEPHKLMbncNfQwMmkzKz.png", - "name": "Saber acEUR-agEUR LP", - "symbol": "acEUR-agEUR", - "tags": [ - "saber-stableswap-lp", - "saber-lp-allbridge", - "saber-lp-wormhole-v2" - ] - }, - { - "address": "WLPR8Sy6Fbnf2sZHVg8Z7uW1QnRThnjhb244kf4ddCS", - "chainId": 101, - "decimals": 8, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "5RpUwQ8wtdPCZHhu6MERp2RGrpobsbZ6MH5dDHkUjs2", - "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy" - ], - "website": "https://app.saber.so/#/pools/wbusd" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/WLPR8Sy6Fbnf2sZHVg8Z7uW1QnRThnjhb244kf4ddCS.png", - "name": "Saber BUSDbs-USDC LP", - "symbol": "BUSDbs-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"] - }, - { - "address": "WLPmZgnajNcCzYv68gQDsix4NNjTxGTPmKRMtiXMuFg", - "chainId": 101, - "decimals": 8, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "FTT8cGNp3rfTC6c44uPTuEFLqmsVDhjd2BhH65v2uppr", - "EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv" - ], - "website": "https://app.saber.so/#/pools/sollet_ftt" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/WLPmZgnajNcCzYv68gQDsix4NNjTxGTPmKRMtiXMuFg.png", - "name": "Saber soFTT-FTT LP", - "symbol": "soFTT-FTT", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"] - }, - { - "address": "WLPsu8oyn1muh5nimxvBsgo6hh6t5jAdUtZ1VmJkohs", - "chainId": 101, - "decimals": 8, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "FCqfQSujuPxy6V42UvafBhsysWtEq1vhjfMN1PUbgaxA", - "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy" - ], - "website": "https://app.saber.so/#/pools/wbusdc" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/WLPsu8oyn1muh5nimxvBsgo6hh6t5jAdUtZ1VmJkohs.png", - "name": "Saber USDCbs-USDC LP", - "symbol": "USDCbs-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"] - }, - { - "address": "WLPv9tHDgkx3ekW8Kyp1TC222oYpr5BMZXTyBTLbk2n", - "chainId": 101, - "decimals": 8, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp", - "CASHedBw9NfhsLBXq1WNVfueVznx255j8LLTScto3S6s" - ], - "website": "https://app.saber.so/#/pools/frax_cash" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/WLPv9tHDgkx3ekW8Kyp1TC222oYpr5BMZXTyBTLbk2n.png", - "name": "Saber FRAX-CASH LP", - "symbol": "FRAX-CASH", - "tags": ["saber-stableswap-lp", "saber-lp-cashio"] - }, - { - "address": "WLPyXq7WRfdWLiP4fvRfSisrfDzLiPmCeVTE6okKQWE", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "E2VmbootbVCBkMNNxKQgCLMS1X3NoGMaYAsufaAsf7M", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "website": "https://app.saber.so/#/pools/wpusdc" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/WLPyXq7WRfdWLiP4fvRfSisrfDzLiPmCeVTE6okKQWE.png", - "name": "Saber USDCpo-USDC LP", - "symbol": "USDCpo-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"] - }, - { - "address": "WTHPuMavN9HBvgUafjrL65WqQytQHDwnTAmdFB9whXA", - "chainId": 101, - "decimals": 8, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "SL819j8K9FuFPL84UepVcFkEZqDUUvVzwDmJjCHySYj", - "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs" - ], - "website": "https://app.saber.so/#/pools/wheth" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/WTHPuMavN9HBvgUafjrL65WqQytQHDwnTAmdFB9whXA.png", - "name": "Saber soETH-ETH LP", - "symbol": "soETH-ETH", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v2"] - }, - { - "address": "XUSDfnsgc2QYXRdbPAbMWoXCbBCCspRSvoGJ8o7RV9n", - "chainId": 101, - "decimals": 6, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "83LGLCm7QKpYZbX8q4W2kYWbtt8NJBwbVwEepzkVnJ9y", - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" - ], - "website": "https://app.saber.so/#/pools/xusd" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/XUSDfnsgc2QYXRdbPAbMWoXCbBCCspRSvoGJ8o7RV9n.png", - "name": "Saber xUSD-USDC LP", - "symbol": "xUSD-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-synthetify"] - }, - { - "address": "aeDebgky5BssqgLo426rXoQTmGrAn1JjEXp6aXFNLic", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "9w6LpS7RU1DKftiwH3NgShtXbkMM1ke9iNU4g3MBXSUs", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "website": "https://app.saber.so/#/pools/aedai" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/aeDebgky5BssqgLo426rXoQTmGrAn1JjEXp6aXFNLic.png", - "name": "Saber aeDAI-USDC LP", - "symbol": "aeDAI-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "aeTwxcJhujVCq6rwbJri3s6ViYifsJUCFirMjLHgHZ7", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "Bn113WT6rbdgwrm12UJtnmNqGqZjY4it2WoUQuQopFVn", - "AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV" - ], - "website": "https://app.saber.so/#/pools/aeusdt" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/aeTwxcJhujVCq6rwbJri3s6ViYifsJUCFirMjLHgHZ7.png", - "name": "Saber aeUSDT-USDT LP", - "symbol": "aeUSDT-USDT", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "cUSDDDBZRhpDW7eyUUPMuw6u1SiMnzu6i7movwf5jxk", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "EwxNF8g9UfmsJVcZFTpL9Hx5MCkoQFoJi6XNWzKf1j8e", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "website": "https://app.saber.so/#/pools/acusd" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/cUSDDDBZRhpDW7eyUUPMuw6u1SiMnzu6i7movwf5jxk.png", - "name": "Saber acUSD-USDC LP", - "symbol": "acUSD-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-allbridge"] - }, - { - "address": "eqKJTf1Do4MDPyKisMYqVaUFpkEFAs3riGF3ceDH2Ca", - "chainId": 101, - "decimals": 6, - "extensions": { - "coingeckoId": "usd-coin", - "currency": "USD", - "source": "allbridge", - "sourceUrl": "https://app.allbridge.io/bridge" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/eqKJTf1Do4MDPyKisMYqVaUFpkEFAs3riGF3ceDH2Ca.png", - "name": "Wrapped USDC (Allbridge from Polygon)", - "symbol": "apUSDC", - "tags": ["stablecoin", "saber-mkt-usd"] - }, - { - "address": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "chainId": 101, - "decimals": 9, - "extensions": { - "coingeckoId": "msol", - "currency": "SOL", - "discord": "https://discord.gg/mGqZA5pjRN", - "github": "https://github.com/marinade-finance", - "medium": "https://medium.com/marinade-finance", - "serumV3Usdc": "6oGsL2puUgySccKzn9XA9afqF217LfxP5ocq4B3LWsjy", - "serumV3Usdt": "HxkQdUnrPdHwXP5T9kewEXs3ApgvbufuTfdw9v1nApFd", - "source": "marinade", - "sourceUrl": "https://marinade.finance/app/staking", - "twitter": "https://twitter.com/MarinadeFinance", - "website": "https://marinade.finance" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So.png", - "name": "Marinade staked SOL (mSOL)", - "symbol": "mSOL", - "tags": ["saber-mkt-sol"] - }, - { - "address": "monKYjV2bHTjbJVWCCcwhxE8C96sdTKR2HUNUHCjh4z", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "GEJpt3Wjmr628FqXxTgxMce1pLntcPV4uFi8ksxMyPQh", - "So11111111111111111111111111111111111111112" - ], - "website": "https://app.saber.so/#/pools/monkedao" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/monKYjV2bHTjbJVWCCcwhxE8C96sdTKR2HUNUHCjh4z.png", - "name": "Saber daoSOL-SOL LP", - "symbol": "daoSOL-SOL", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "pBTCmyG7FaZx4uk3Q2pT5jHKWmWDn84npdc7gZXpQ1x", - "chainId": 101, - "decimals": 8, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "DYDWu4hE4MN3aH897xQ3sRTs5EAjJDmQsKLNhbpUiKun" - ], - "website": "https://app.saber.so/#/pools/pbtc" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/pBTCmyG7FaZx4uk3Q2pT5jHKWmWDn84npdc7gZXpQ1x.png", - "name": "Saber pBTC-renBTC LP", - "symbol": "pBTC-renBTC", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "son4WQ39xri8sqMqNQZAEtEEPTuUcCRHg7t1ZcYdkSw", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn", - "So11111111111111111111111111111111111111112" - ], - "website": "https://app.saber.so/#/pools/jsol" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/son4WQ39xri8sqMqNQZAEtEEPTuUcCRHg7t1ZcYdkSw.png", - "name": "Saber JSOL-SOL LP", - "symbol": "JSOL-SOL", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "stSjCmjQ96BiGhTk8gkU22j1739R8YBQVMq7KXWTqUV", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "So11111111111111111111111111111111111111112" - ], - "website": "https://app.saber.so/#/pools/stsol" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/stSjCmjQ96BiGhTk8gkU22j1739R8YBQVMq7KXWTqUV.png", - "name": "Saber stSOL-SOL LP", - "symbol": "stSOL-SOL", - "tags": ["saber-stableswap-lp"] - }, - { - "address": "uSdKg2Cs5bCtFSeNXs7aRVNzZJauX58eCkdsfssxTdW", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "2kycGCD8tJbrjJJqWN2Qz5ysN9iB4Bth3Uic4mSB7uak", - "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1" - ], - "website": "https://app.saber.so/#/pools/usdk" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/uSdKg2Cs5bCtFSeNXs7aRVNzZJauX58eCkdsfssxTdW.png", - "name": "Saber wUSDK_V1-USDC LP", - "symbol": "wUSDKV1-USDC", - "tags": ["saber-stableswap-lp", "saber-lp-wormhole-v1"] - }, - { - "address": "xBTCPvRuEuRgz5DuuUd3ju3VP5XtR2Dsu1AxyW9JpXK", - "chainId": 101, - "decimals": 10, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "HWxpSV3QAGzLQzGAtvhSYAEr7sTQugQygnni1gnUGh1D", - "BtX7AfzEJLnU8KQR1AgHrhGH5s2AHUTbfjhUQP8BhPvi" - ], - "website": "https://app.saber.so/#/pools/xbtc" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/xBTCPvRuEuRgz5DuuUd3ju3VP5XtR2Dsu1AxyW9JpXK.png", - "name": "Saber xBTC-renBTC LP", - "symbol": "xBTC-renBTC", - "tags": ["saber-stableswap-lp", "saber-lp-synthetify"] - }, - { - "address": "xETH89889mVRwsw9tSUnULsdLUPryTpijagy2YXxWyY", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "8bqjz8DeSuim1sEAsQatjJN4zseyxSPdhHQcuuhL8PCK", - "KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma" - ], - "website": "https://app.saber.so/#/pools/xeth" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/xETH89889mVRwsw9tSUnULsdLUPryTpijagy2YXxWyY.png", - "name": "Saber xETH-ETH LP", - "symbol": "xETH-ETH", - "tags": ["saber-stableswap-lp", "saber-lp-synthetify"] - }, - { - "address": "xFTTLsMdN28XHtYTTTVWYz5zwXWBm5r1WTuZ7Cc7SyA", - "chainId": 101, - "decimals": 8, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "Fr3W7NPVvdVbwMcHgA7Gx2wUxP43txdsn3iULJGFbKz9", - "EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv" - ], - "website": "https://app.saber.so/#/pools/xftt" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/xFTTLsMdN28XHtYTTTVWYz5zwXWBm5r1WTuZ7Cc7SyA.png", - "name": "Saber xFTT-FTT LP", - "symbol": "xFTT-FTT", - "tags": ["saber-stableswap-lp", "saber-lp-synthetify"] - }, - { - "address": "xSoLVBNztDTUW8Kou2GJinHoe54Siu9Sk3e2uoU9aUi", - "chainId": 101, - "decimals": 9, - "extensions": { - "source": "saber", - "underlyingTokens": [ - "BdUJucPJyjkHxLMv6ipKNUhSeY3DWrVtgxAES1iSBAov", - "So11111111111111111111111111111111111111112" - ], - "website": "https://app.saber.so/#/pools/xsol" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/xSoLVBNztDTUW8Kou2GJinHoe54Siu9Sk3e2uoU9aUi.png", - "name": "Saber xSOL-SOL LP", - "symbol": "xSOL-SOL", - "tags": ["saber-stableswap-lp", "saber-lp-synthetify"] - }, - { - "address": "xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG", - "chainId": 101, - "decimals": 6, - "extensions": { - "address": "0x476c5e26a75bd202a9683ffd34359c0cc15be0ff", - "assetContract": "https://etherscan.io/address/0x476c5e26a75bd202a9683ffd34359c0cc15be0ff", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "serum", - "currency": "SRM", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer" - }, - "logoURI": "https://spl-token-icons.static-assets.ship.capital/icons/101/xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG.png", - "name": "Serum (Wormhole from Ethereum)", - "symbol": "SRMet", - "tags": ["wrapped", "wormhole", "saber-mkt-srm", "wormhole-v2"] - } - ] -} diff --git a/farms/farm-ctrl/metadata/tokens/solana_token_list/filtered_tokens.json b/farms/farm-ctrl/metadata/tokens/solana_token_list/filtered_tokens.json deleted file mode 100644 index 46bfa93b6bf..00000000000 --- a/farms/farm-ctrl/metadata/tokens/solana_token_list/filtered_tokens.json +++ /dev/null @@ -1,3692 +0,0 @@ -{ - "name": "Solana Token List", - "tokens": [ - { - "chainId": 101, - "address": "So11111111111111111111111111111111111111112", - "symbol": "SOL", - "name": "Wrapped SOL", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/So11111111111111111111111111111111111111112/logo.png", - "extensions": { - "coingeckoId": "solana", - "serumV3Usdc": "9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT", - "serumV3Usdt": "HWHvQhFmJB3NUcu1aihKmrKegfVxBEHzwVX6yZCKEsi1", - "website": "https://solana.com/" - } - }, - { - "chainId": 101, - "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "symbol": "USDC", - "name": "USD Coin", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v/logo.png", - "tags": ["stablecoin"], - "extensions": { - "coingeckoId": "usd-coin", - "serumV3Usdt": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "website": "https://www.centre.io/" - } - }, - { - "chainId": 101, - "address": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - "symbol": "USDT", - "name": "USDT", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB/logo.svg", - "tags": ["stablecoin"], - "extensions": { - "coingeckoId": "tether", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "website": "https://tether.to/" - } - }, - { - "chainId": 101, - "address": "2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk", - "symbol": "SOETH", - "name": "Wrapped Ethereum (Sollet)", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk/logo.png", - "tags": ["wrapped-sollet", "ethereum"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "coingeckoId": "ethereum", - "serumV3Usdc": "4tSvZvnbyzHXLMTiFonMyxZoHmFqau1XArcRCVHLZ5gX", - "serumV3Usdt": "7dLVkUfBVfCGkFhSXDCq1ukM9usathSgS716t643iFGF" - } - }, - { - "chainId": 101, - "address": "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", - "symbol": "RAY", - "name": "Raydium", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R/logo.png", - "extensions": { - "coingeckoId": "raydium", - "serumV3Usdc": "2xiv8A5xrJ7RnGdxXB42uFEkYHJjszEhaJyKKt4WaLep", - "serumV3Usdt": "teE55QrL4a4QSfydR9dnHF97jgCfptpuigbb53Lo95g", - "waterfallbot": "https://bit.ly/RAYwaterfall", - "website": "https://raydium.io/" - } - }, - { - "chainId": 101, - "address": "8PMHT4swUMtBzgHnh5U564N5sjPSiUz2cjEQzFnnP1Fo", - "symbol": "ROPE", - "name": "Rope Token", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/8PMHT4swUMtBzgHnh5U564N5sjPSiUz2cjEQzFnnP1Fo/logo.svg", - "extensions": { - "coingeckoId": "rope-token", - "serumV3Usdc": "4Sg1g8U2ZuGnGYxAhc6MmX9MX7yZbrrraPkCQ9MdCPtF", - "waterfallbot": "https://bit.ly/ROPEwaterfall", - "website": "https://ropesolana.com/" - } - }, - { - "chainId": 101, - "address": "StepAscQoEioFxxWGnh2sLBDFp9d8rvKz2Yp39iDpyT", - "symbol": "STEP", - "name": "Step", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/StepAscQoEioFxxWGnh2sLBDFp9d8rvKz2Yp39iDpyT/logo.png", - "tags": ["utility-token"], - "extensions": { - "coingeckoId": "step-finance", - "serumV3Usdc": "97qCB4cAVSTthvJu3eNoEx6AY6DLuRDtCoPm5Tdyg77S", - "twitter": "https://twitter.com/StepFinance_", - "waterfallbot": "https://bit.ly/STEPwaterfall", - "website": "https://step.finance/" - } - }, - { - "chainId": 101, - "address": "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt", - "symbol": "SRM", - "name": "Serum", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt/logo.png", - "extensions": { - "coingeckoId": "serum", - "serumV3Usdc": "ByRys5tuUWDgL73G8JBAEfkdFf8JWBzPBDHsBVQ5vbQA", - "serumV3Usdt": "AtNnsY1AyRERWJ8xCskfz38YdvruWVJQUVXgScC1iPb", - "waterfallbot": "https://bit.ly/SRMwaterfall", - "website": "https://projectserum.com/" - } - }, - { - "chainId": 101, - "address": "AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3", - "symbol": "SOFTT", - "name": "Wrapped FTT (Sollet)", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3/logo.png", - "tags": ["wrapped-sollet", "ethereum"], - "extensions": { - "assetContract": "https://etherscan.io/address/0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "coingeckoId": "ftx-token", - "serumV3Usdc": "2Pbh1CvRVku1TgewMfycemghf6sU9EyuFDcNXqvRmSxc", - "serumV3Usdt": "Hr3wzG8mZXNHV7TuL6YqtgfVUesCqMxGYCEyP3otywZE", - "waterfallbot": "https://bit.ly/FTTwaterfall" - } - }, - { - "chainId": 101, - "address": "8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh", - "symbol": "COPE", - "name": "COPE", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh/logo.png", - "tags": ["trading", "index", "Algos"], - "extensions": { - "coingeckoId": "cope", - "serumV3Usdc": "6fc7v3PmjZG9Lk2XTot6BywGyYLkBQuzuFKd4FpCsPxk", - "website": "https://www.unlimitedcope.com/" - } - }, - { - "chainId": 101, - "address": "z3dn17yLaGMKffVogeFHQ9zWVcXgqgf3PQnDsNs2g6M", - "symbol": "OXY", - "name": "Oxygen Protocol", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/z3dn17yLaGMKffVogeFHQ9zWVcXgqgf3PQnDsNs2g6M/logo.svg", - "extensions": { - "coingeckoId": "oxygen", - "serumV3Usdc": "GZ3WBFsqntmERPwumFEYgrX2B7J7G11MzNZAy7Hje27X", - "serumV3Usdt": "GKLev6UHeX1KSDCyo2bzyG6wqhByEzDBkmYTxEdmYJgB", - "waterfallbot": "https://bit.ly/OXYwaterfall", - "website": "https://www.oxygen.org/" - } - }, - { - "chainId": 101, - "address": "9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E", - "symbol": "BTC", - "name": "Wrapped Bitcoin (Sollet)", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E/logo.png", - "tags": ["wrapped-sollet", "ethereum"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "coingeckoId": "bitcoin", - "serumV3Usdc": "A8YFbxQYFVqKZaoYJLLUVcQiWP7G2MeEgW5wsAQgMvFw", - "serumV3Usdt": "C1EuT9VokAKLiW7i2ASnZUvxDoKuKkCpDDeNxAptuNe4" - } - }, - { - "chainId": 101, - "address": "MERt85fc5boKw3BW1eYdxonEuJNvXbiMbs6hvheau5K", - "symbol": "MER", - "name": "Mercurial", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/MERt85fc5boKw3BW1eYdxonEuJNvXbiMbs6hvheau5K/logo.png", - "extensions": { - "coingeckoId": "mercurial", - "serumV3Usdc": "G4LcexdCzzJUKZfqyVDQFzpkjhB1JoCNL8Kooxi9nJz5", - "waterfallbot": "https://bit.ly/MERwaterfall", - "website": "https://www.mercurial.finance/" - } - }, - { - "chainId": 101, - "address": "EchesyfXePKdLtoiZSL8pBe8Myagyy8ZRqsACNCFGnvp", - "symbol": "FIDA", - "name": "Bonfida", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EchesyfXePKdLtoiZSL8pBe8Myagyy8ZRqsACNCFGnvp/logo.svg", - "extensions": { - "coingeckoId": "bonfida", - "serumV3Usdc": "E14BKBhDWD4EuTkWj1ooZezesGxMW8LPCps4W5PuzZJo", - "serumV3Usdt": "EbV7pPpEvheLizuYX3gUCvWM8iySbSRAhu2mQ5Vz2Mxf", - "waterfallbot": "https://bit.ly/FIDAwaterfall", - "website": "https://bonfida.com/" - } - }, - { - "chainId": 101, - "address": "MAPS41MDahZ9QdKXhVa4dWB9RuyfV4XqhyAZ8XcYepb", - "symbol": "MAPS", - "name": "MAPS", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/MAPS41MDahZ9QdKXhVa4dWB9RuyfV4XqhyAZ8XcYepb/logo.svg", - "extensions": { - "coingeckoId": "maps", - "serumV3Usdc": "3A8XQRWXC7BjLpgLDDBhQJLT5yPCzS16cGYRKHkKxvYo", - "serumV3Usdt": "7cknqHAuGpfVXPtFoJpFvUjJ8wkmyEfbFusmwMfNy3FE", - "website": "https://maps.me/" - } - }, - { - "chainId": 101, - "address": "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE", - "symbol": "ORCA", - "name": "Orca", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE/logo.png", - "extensions": { - "coingeckoId": "orca", - "discord": "https://discord.com/invite/nSwGWn5KSG", - "medium": "https://orca-so.medium.com", - "serumV3Usdc": "8N1KkhaCYDpj3awD58d85n973EwkpeYnRp84y1kdZpMX", - "telegram": "https://t.me/orca_so", - "twitter": "https://twitter.com/orca_so", - "website": "https://orca.so" - } - }, - { - "chainId": 101, - "address": "kinXdEcpDQeHPEuQnqmUgtYykqKGVFq6CeVX5iAHJq6", - "symbol": "KIN", - "name": "KIN", - "decimals": 5, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/kinXdEcpDQeHPEuQnqmUgtYykqKGVFq6CeVX5iAHJq6/logo.png", - "extensions": { - "coingeckoId": "kin", - "serumV3Usdc": "Bn6NPyr6UzrFAwC4WmvPvDr2Vm8XSUnFykM2aQroedgn", - "serumV3Usdt": "4nCFQr8sahhhL4XJ7kngGFBmpkmyf3xLzemuMhn6mWTm", - "waterfallbot": "https://bit.ly/KINwaterfall" - } - }, - { - "chainId": 101, - "address": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU", - "symbol": "SAMO", - "name": "Samoyed Coin", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU/logo.png", - "extensions": { - "coingeckoId": "samoyedcoin", - "serumV3Usdc": "FR3SPJmgfRSKKQ2ysUZBu7vJLpzTixXnjzb84bY3Diif", - "website": "https://samoyedcoin.com/" - } - }, - { - "chainId": 101, - "address": "4wjPQJ6PrkC4dHhYghwJzGBVP78DkBzA2U3kHoFNBuhj", - "symbol": "LIQ", - "name": "LIQ Protocol", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/4wjPQJ6PrkC4dHhYghwJzGBVP78DkBzA2U3kHoFNBuhj/logo.png", - "extensions": { - "coingeckoId": "liq-protocol", - "discord": "https://discord.gg/MkfjambeU7", - "serumV3Usdc": "D7p7PebNjpkH6VNHJhmiDFNmpz9XE7UaTv9RouxJMrwb", - "twitter": "https://twitter.com/liqsolana", - "website": "https://liqsolana.com/" - } - }, - { - "chainId": 101, - "address": "4dmKkXNHdgYsXqBHCuMikNQWwVomZURhYvkkX5c4pQ7y", - "symbol": "SNY", - "name": "Synthetify", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/4dmKkXNHdgYsXqBHCuMikNQWwVomZURhYvkkX5c4pQ7y/logo.png", - "extensions": { - "coingeckoId": "synthetify-token", - "serumV3Usdc": "DPfj2jYwPaezkCmUNm5SSYfkrkz8WFqwGLcxDDUsN3gA", - "twitter": "https://twitter.com/synthetify", - "website": "https://synthetify.io/" - } - }, - { - "chainId": 101, - "address": "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", - "symbol": "MSOL", - "name": "Marinade staked SOL (mSOL)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So/logo.png", - "extensions": { - "coingeckoId": "msol", - "discord": "https://discord.gg/mGqZA5pjRN", - "github": "https://github.com/marinade-finance", - "medium": "https://medium.com/marinade-finance", - "serumV3Usdc": "6oGsL2puUgySccKzn9XA9afqF217LfxP5ocq4B3LWsjy", - "serumV3Usdt": "HxkQdUnrPdHwXP5T9kewEXs3ApgvbufuTfdw9v1nApFd", - "twitter": "https://twitter.com/MarinadeFinance", - "website": "https://marinade.finance" - } - }, - { - "chainId": 101, - "address": "SLRSSpSLUTP7okbCUBYStWCo1vUgyt775faPqz8HUMr", - "symbol": "SLRS", - "name": "Solrise Finance", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/SLRSSpSLUTP7okbCUBYStWCo1vUgyt775faPqz8HUMr/logo.png", - "extensions": { - "coingeckoId": "solrise-finance", - "discord": "https://discord.gg/xNbGgMUJfU", - "medium": "https://blog.solrise.finance", - "serumV3Usdc": "2Gx3UfV831BAh8uQv1FKSPKS9yajfeeD8GJ4ZNb2o2YP", - "telegram": "https://t.me/solrisefinance", - "twitter": "https://twitter.com/SolriseFinance", - "website": "https://solrise.finance" - } - }, - { - "chainId": 101, - "address": "PoRTjZMPXb9T7dyU7tpLEZRQj7e6ssfAE62j2oQuc6y", - "symbol": "PORT", - "name": "Port Finance Token", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/PoRTjZMPXb9T7dyU7tpLEZRQj7e6ssfAE62j2oQuc6y/PORT.png", - "extensions": { - "coingeckoId": "port-finance", - "discord": "https://discord.gg/nAMXAYhTb2", - "github": "https://github.com/port-finance/", - "medium": "https://medium.com/port-finance", - "serumV3Usdc": "8x8jf7ikJwgP9UthadtiGFgfFuyyyYPHL3obJAuxFWko", - "telegram": "https://t.me/port_finance", - "twitter": "https://twitter.com/port_finance", - "waterfallbot": "https://bit.ly/PORTwaterfall", - "website": "https://port.finance/" - } - }, - { - "chainId": 101, - "address": "Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1", - "symbol": "SBR", - "name": "Saber Protocol Token", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1/logo.svg", - "extensions": { - "coingeckoId": "saber", - "discord": "https://chat.saber.so", - "github": "https://github.com/saber-hq", - "medium": "https://blog.saber.so", - "serumV3Usdc": "HXBi8YBwbh4TXF6PjVw81m8Z3Cc4WBofvauj5SBFdgUs", - "twitter": "https://twitter.com/saber_hq", - "waterfallbot": "https://bit.ly/SBRwaterfall", - "website": "https://saber.so" - } - }, - { - "chainId": 101, - "address": "5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm", - "symbol": "SCNSOL", - "name": "Socean staked SOL", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm/logo.png", - "tags": ["stake-pool"], - "extensions": { - "coingeckoId": "socean-staked-sol", - "discord": "https://discord.gg/k8ZcW27bq9", - "medium": "https://medium.com/@soceanfinance", - "serumV3Usdc": "D52sefGCWho2nd5UGxWd7wCftAzeNEMNYZkdEPGEdQTb", - "twitter": "https://twitter.com/soceanfinance", - "website": "https://socean.fi/" - } - }, - { - "chainId": 101, - "address": "9EaLkQrbjmbbuZG9Wdpo8qfNUEjHATJFSycEmw6f1rGX", - "symbol": "PSOL", - "name": "pSOL (Parrot SOL)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/9EaLkQrbjmbbuZG9Wdpo8qfNUEjHATJFSycEmw6f1rGX/logo.svg", - "tags": ["stablecoin"], - "extensions": { - "discord": "https://discord.gg/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "telegram": "https://t.me/gopartyparrot", - "twitter": "https://twitter.com/gopartyparrot", - "website": "https://parrot.fi" - } - }, - { - "chainId": 101, - "address": "Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS", - "symbol": "PAI", - "name": "PAI (Parrot USD)", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Ea5SjE2Y6yvCeW5dYTn7PYMuW5ikXkvbGdcmSnXeaLjS/logo.svg", - "tags": ["utility-token", "stablecoin"], - "extensions": { - "coingeckoId": "parrot-usd", - "discord": "https://discord.gg/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "telegram": "https://t.me/gopartyparrot", - "twitter": "https://twitter.com/gopartyparrot", - "website": "https://parrot.fi" - } - }, - { - "chainId": 101, - "address": "ATLASXmbPQxBUYbxPsV97usA3fPQYEqzQBUHgiFCUsXx", - "symbol": "ATLAS", - "name": "Star Atlas", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/ATLASXmbPQxBUYbxPsV97usA3fPQYEqzQBUHgiFCUsXx/logo.png", - "tags": ["utility-token"], - "extensions": { - "coingeckoId": "star-atlas", - "description": "Star Atlas Token", - "serumV3Usdc": "Di66GTLsV64JgCCYGVcY21RZ173BHkjJVgPyezNN7P1K", - "waterfallbot": "https://bit.ly/ATLASwaterfall", - "website": "https://staratlas.com" - } - }, - { - "chainId": 101, - "address": "poLisWXnNRwC6oBu1vHiuKQzFjGL4XDSu4g9qjz9qVk", - "symbol": "POLIS", - "name": "Star Atlas DAO", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/poLisWXnNRwC6oBu1vHiuKQzFjGL4XDSu4g9qjz9qVk/logo.png", - "tags": ["utility-token"], - "extensions": { - "coingeckoId": "star-atlas-dao", - "description": "Star Atlas DAO Token", - "serumV3Usdc": "HxFLKUAmAMLz1jtT3hbvCMELwH5H9tpM2QugP8sKyfhW", - "waterfallbot": "https://bit.ly/POLISwaterfall", - "website": "https://staratlas.com" - } - }, - { - "chainId": 101, - "address": "BLwTnYKqf7u4qjgZrrsKeNs2EzWkMLqVCu6j8iHyrNA3", - "symbol": "BOP", - "name": "Boring Protocol", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/boringprotocol/brand-assets/main/boplogo.png", - "tags": ["security-token", "utility-token"], - "extensions": { - "coingeckoId": "boring-protocol", - "serumV3Usdc": "7MmPwD1K56DthW14P1PnWZ4zPCbPWemGs3YggcT1KzsM", - "twitter": "https://twitter.com/BoringProtocol", - "website": "https://boringprotocol.io" - } - }, - { - "chainId": 101, - "address": "FgX1WD9WzMU3yLwXaFSarPfkgzjLb2DZCqmkx9ExpuvJ", - "symbol": "NINJA", - "name": "NINJA", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/FgX1WD9WzMU3yLwXaFSarPfkgzjLb2DZCqmkx9ExpuvJ/logo.png", - "extensions": { - "coingeckoId": "ninja-protocol", - "serumV3Usdc": "J4oPt5Q3FYxrznkXLkbosAWrJ4rZLqJpGqz7vZUL4eMM", - "website": "https://www.ninjaprotocol.io/" - } - }, - { - "chainId": 101, - "address": "xxxxa1sKNGwFtw2kFn8XauW9xq8hBZ5kVtcSesTT9fW", - "symbol": "SLIM", - "name": "Solanium", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/xxxxa1sKNGwFtw2kFn8XauW9xq8hBZ5kVtcSesTT9fW/logo.png", - "extensions": { - "coingeckoId": "solanium", - "telegram": "https://t.me/solanium_io", - "twitter": "https://twitter.com/solanium_io", - "website": "https://www.solanium.io/" - } - }, - { - "chainId": 101, - "address": "6VNKqgz9hk7zRShTFdg5AnkfKwZUcojzwAkzxSH3bnUm", - "symbol": "WHAPI", - "name": "Wrapped HAPI", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/6VNKqgz9hk7zRShTFdg5AnkfKwZUcojzwAkzxSH3bnUm/logo.png", - "tags": ["wrapped", "utility-token"], - "extensions": { - "coingeckoId": "hapi", - "github": "https://github.com/HAPIprotocol/HAPI/", - "medium": "https://medium.com/i-am-hapi", - "telegram": "https://t.me/hapiHF", - "twitter": "https://twitter.com/i_am_hapi_one", - "website": "https://hapi.one" - } - }, - { - "chainId": 101, - "address": "SUNNYWgPQmFxe9wTZzNK7iPnJ3vYDrkgnxJRJm1s3ag", - "symbol": "SUNNY", - "name": "Sunny Governance Token", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/SUNNYWgPQmFxe9wTZzNK7iPnJ3vYDrkgnxJRJm1s3ag/logo.svg", - "extensions": { - "coingeckoId": "sunny-aggregator", - "discord": "https://chat.sunny.ag", - "github": "https://github.com/SunnyAggregator", - "medium": "https://medium.com/sunny-aggregator", - "serumV3Usdc": "Aubv1QBFh4bwB2wbP1DaPW21YyQBLfgjg8L4PHTaPzRc", - "twitter": "https://twitter.com/SunnyAggregator", - "waterfallbot": "https://bit.ly/SUNNYwaterfall", - "website": "https://sunny.ag/" - } - }, - { - "chainId": 101, - "address": "8upjSpvjcdpuzhfR1zriwg5NXkwDruejqNE9WNbPRtyA", - "symbol": "GRAPE", - "name": "Grape", - "decimals": 6, - "logoURI": "https://lh3.googleusercontent.com/y7Wsemw9UVBc9dtjtRfVilnS1cgpDt356PPAjne5NvMXIwWz9_x7WKMPH99teyv8vXDmpZinsJdgiFQ16_OAda1dNcsUxlpw9DyMkUk=s0", - "extensions": { - "coingeckoId": "grape-2", - "website": "https://grapes.network" - } - }, - { - "chainId": 101, - "address": "a11bdAAuV8iB2fu7X6AxAvDTo1QZ8FXB3kk5eecdasp", - "symbol": "ABR", - "name": "Allbridge", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/allbridge-io/media/main/token.svg", - "extensions": { - "coingeckoId": "allbridge", - "medium": "https://allbridge.medium.com/", - "telegram": "https://t.me/allbridge_announcements", - "twitter": "https://twitter.com/Allbridge_io", - "website": "https://allbridge.io/" - } - }, - { - "chainId": 101, - "address": "2Kc38rfQ49DFaKHQaWbijkE7fcymUMLY5guUiUsDmFfn", - "symbol": "KURO", - "name": "Kurobi", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/2Kc38rfQ49DFaKHQaWbijkE7fcymUMLY5guUiUsDmFfn/logo.png", - "tags": ["utility-token"], - "extensions": { - "coingeckoId": "kurobi", - "github": "https://github.com/KurobiHq/", - "medium": "https://kurobi.medium.com/", - "telegram": "https://t.me/kurobi_io", - "twitter": "https://twitter.com/kurobi_io", - "website": "https://kurobi.io/" - } - }, - { - "chainId": 101, - "address": "ETAtLmCmsoiEEKfNrHKJ2kYy3MoABhU6NQvpSfij5tDs", - "symbol": "MEDIA", - "name": "Media Network", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/ETAtLmCmsoiEEKfNrHKJ2kYy3MoABhU6NQvpSfij5tDs/logo.png", - "tags": ["utility-token"], - "extensions": { - "coingeckoId": "media-network", - "serumV3Usdc": "FfiqqvJcVL7oCCu8WQUMHLUC2dnHQPAPjTdSzsERFWjb", - "waterfallbot": "https://bit.ly/MEDIAwaterfall", - "website": "https://media.network/" - } - }, - { - "chainId": 101, - "address": "TuLipcqtGVXP9XR62wM8WWCm6a9vhLs7T1uoWBk6FDs", - "symbol": "TULIP", - "name": "Tulip", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/sol-farm/token-logos/main/tulip.png", - "tags": ["tulip", "tulip-protocol", "vaults"], - "extensions": { - "coingeckoId": "solfarm", - "serumV3Usdc": "8GufnKq7YnXKhnB3WNhgy5PzU9uvHbaaRrZWQK6ixPxW", - "twitter": "https://twitter.com/TulipProtocol", - "waterfallbot": "https://bit.ly/TULIPwaterfall", - "website": "https://tulip.garden" - } - }, - { - "chainId": 101, - "address": "MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac", - "symbol": "MNGO", - "name": "Mango", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac/token.png", - "extensions": { - "coingeckoId": "mango-markets", - "discord": "https://discord.gg/67jySBhxrg", - "serumV3Usdc": "3d4rzwpy9iGdCZvgxcu7B1YocYffVLsQXPXkBZKt2zLc", - "twitter": "https://twitter.com/mangomarkets", - "website": "https://mango.markets/" - } - }, - { - "chainId": 101, - "address": "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj", - "symbol": "STSOL", - "name": "Lido Staked SOL", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj/logo.png", - "extensions": { - "coingeckoId": "lido-staked-sol", - "coinmarketcap": "https://coinmarketcap.com/currencies/lido-for-solana/", - "discord": "https://discord.gg/w9pXXgQPu8", - "github": "https://github.com/ChorusOne/solido", - "serumV3Usdc": "5F7LGsP1LPtaRV7vVKgxwNYX4Vf22xvuzyXjyar7jJqp", - "twitter": "https://twitter.com/LidoFinance", - "website": "https://solana.lido.fi/" - } - }, - { - "chainId": 101, - "address": "ZScHuTtqZukUrtZS43teTKGs2VqkKL8k4QCouR2n6Uo", - "symbol": "WSTETH", - "name": "Lido Wrapped Staked ETH", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/ZScHuTtqZukUrtZS43teTKGs2VqkKL8k4QCouR2n6Uo/logo.png", - "tags": ["stake", "wrapped"], - "extensions": { - "discord": "https://discord.gg/WhhnWwsFXz", - "github": "https://github.com/lidofinance", - "telegram": "https://t.me/lidofinance", - "twitter": "https://twitter.com/LidoFinance", - "website": "https://lido.fi/" - } - }, - { - "chainId": 101, - "address": "FnKE9n6aGjQoNWRBZXy4RW6LZVao7qwBonUbiD7edUmZ", - "symbol": "SYP", - "name": "Sypool", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/b0e47e39f84cffb655f406eb569c57a88b5211cc/assets/mainnet/FnKE9n6aGjQoNWRBZXy4RW6LZVao7qwBonUbiD7edUmZ/logo.png", - "tags": ["platform"], - "extensions": { - "coingeckoId": "sypool", - "website": "https://www.sypool.io/" - } - }, - { - "chainId": 101, - "address": "HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p", - "symbol": "LDO", - "name": "Lido DAO Token (Portal)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/HZRCwxP2Vq9PCpPXooayhJ2bxTpo5xfpQrwB1svh332p/logo.png", - "tags": ["wrapped", "ethereum"], - "extensions": { - "address": "0x5a98fcbea516cf06857215779fd812ca3bef1b32", - "assetContract": "https://etherscan.io/address/0x5a98fcbea516cf06857215779fd812ca3bef1b32", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "lido-dao", - "twitter": "https://twitter.com/LidoFinance", - "website": "https://lido.fi/" - } - }, - { - "chainId": 101, - "address": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", - "symbol": "ETH", - "name": "Ether (Portal)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs/logo.png", - "tags": ["wrapped", "wormhole"], - "extensions": { - "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "assetContract": "https://etherscan.io/address/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "ethereum", - "serumV3Usdc": "8Gmi2HhZmwQPVdCwzS7CM66MGstMXPcTVHA7jF19cLZz", - "serumV3Usdt": "ch7kmPrtoQUSEPBggcNAvLGiMQkJagVwd3gDYfd8m7Q" - } - }, - { - "chainId": 101, - "address": "MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey", - "symbol": "MNDE", - "name": "Marinade", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey/logo.png", - "extensions": { - "coingeckoId": "marinade", - "discord": "https://discord.gg/mGqZA5pjRN", - "github": "https://github.com/marinade-finance", - "medium": "https://medium.com/marinade-finance", - "twitter": "https://twitter.com/MarinadeFinance", - "website": "https://marinade.finance" - } - }, - { - "chainId": 101, - "address": "5tN42n9vMi6ubp67Uy4NnmM5DMZYN8aS8GeB3bEDHr6E", - "symbol": "WAG", - "name": "Waggle Network", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/5tN42n9vMi6ubp67Uy4NnmM5DMZYN8aS8GeB3bEDHr6E/logo.png", - "extensions": { - "medium": "https://medium.com/@wagglenetwork", - "telegram": "https://t.me/waggle_network", - "twitter": "https://twitter.com/wagglenetwork", - "website": "https://waggle.network/" - } - }, - { - "chainId": 101, - "address": "iVNcrNE9BRZBC9Aqf753iZiZfbszeAVUoikgT9yvr2a", - "symbol": "IVN", - "name": "Investin Protocol", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/iVNcrNE9BRZBC9Aqf753iZiZfbszeAVUoikgT9yvr2a/logo.png", - "tags": ["defi", "fund-management"], - "extensions": { - "coingeckoId": "investin", - "discord": "https://discord.com/invite/Yf54h9B", - "medium": "https://medium.com/investin-pro", - "serumV3Usdc": "AdmfUBJ64BTsjaZdtu1iQHAtxJ4Ge7Zw5bNMsrLGdZu7", - "telegram": "https://t.me/Investin_pro1", - "twitter": "https://twitter.com/Investin_pro", - "website": "https://www.investin.pro/" - } - }, - { - "chainId": 101, - "address": "Lrxqnh6ZHKbGy3dcrCED43nsoLkM1LTzU2jRfWe8qUC", - "symbol": "LARIX", - "name": "Larix", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Lrxqnh6ZHKbGy3dcrCED43nsoLkM1LTzU2jRfWe8qUC/logo.jpg", - "extensions": { - "coingeckoId": "larix", - "discord": "https://discord.gg/hfnRFV9Ngt", - "github": "https://github.com/ProjectLarix/Larix-Lending-Project-Rep", - "medium": "http://projectlarix.medium.com", - "telegram": "https://t.me/projectlarix", - "twitter": "https://twitter.com/ProjectLarix", - "website": "https://projectlarix.com" - } - }, - { - "chainId": 101, - "address": "PRT88RkA4Kg5z7pKnezeNH4mafTvtQdfFgpQTGRjz44", - "symbol": "PRT", - "name": "PRT (Parrot Protocol)", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/PRT88RkA4Kg5z7pKnezeNH4mafTvtQdfFgpQTGRjz44/logo.svg", - "tags": ["utility-token"], - "extensions": { - "coingeckoId": "parrot-protocol", - "discord": "https://discord.gg/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "telegram": "https://t.me/gopartyparrot", - "twitter": "https://twitter.com/gopartyparrot", - "website": "https://parrot.fi" - } - }, - { - "chainId": 101, - "address": "JET6zMJWkCN9tpRT2v2jfAmm5VnQFDpUBCyaKojmGtz", - "symbol": "JET", - "name": "Jet Protocol", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/JET6zMJWkCN9tpRT2v2jfAmm5VnQFDpUBCyaKojmGtz/logo.png", - "extensions": { - "coingeckoId": "jet", - "serumV3Usdc": "6pQMoHDC2o8eeFxyTKtfnsr8d48hKFWsRpLHAqVHH2ZP", - "website": "https://jetprotocol.io/" - } - }, - { - "chainId": 101, - "address": "AURYydfxJib1ZkTir1Jn1J9ECYUtjb6rKQVmtYaixWPP", - "symbol": "AURY", - "name": "Aurory", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/AURYydfxJib1ZkTir1Jn1J9ECYUtjb6rKQVmtYaixWPP/logo.png", - "tags": ["utility-token"], - "extensions": { - "coingeckoId": "aurory", - "description": "Aurory Token", - "website": "https://aurory.io" - } - }, - { - "chainId": 101, - "address": "AUrMpCDYYcPuHhyNX8gEEqbmDPFUpBpHrNW3vPeCFn5Z", - "symbol": "AVAX", - "name": "AVAX (Allbridge from Avalanche)", - "decimals": 9, - "logoURI": "https://assets.coingecko.com/coins/images/12559/small/coin-round-red.png", - "extensions": { "coingeckoId": "avalanche-2" } - }, - { - "chainId": 101, - "address": "SLNDpmoWTVADgEdndyvWzroNL7zSi1dF9PC3xHGtPwp", - "symbol": "SLND", - "name": "Solend", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/SLNDpmoWTVADgEdndyvWzroNL7zSi1dF9PC3xHGtPwp/logo.png", - "tags": ["solend", "lending"], - "extensions": { - "coingeckoId": "solend", - "serumV3Usdc": "F9y9NM83kBMzBmMvNT18mkcFuNAPhNRhx7pnz9EDWwfv", - "twitter": "https://twitter.com/solendprotocol", - "website": "https://solend.fi" - } - }, - { - "chainId": 101, - "address": "GFX1ZjR2P15tmrSwow6FjyDYcEkoFb4p4gJCpLBjaxHD", - "symbol": "GOFX", - "name": "GooseFX", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/GFX1ZjR2P15tmrSwow6FjyDYcEkoFb4p4gJCpLBjaxHD/logo.png", - "tags": ["NFT", "utility-token", "dao", "governance"], - "extensions": { - "coingeckoId": "goosefx", - "coinmarketcap": "https://coinmarketcap.com/currencies/goosefx/", - "discord": "https://discord.gg/cDEPXpY26q", - "serumV3Usdc": "2wgi2FabNsSDdb8dke9mHFB67QtMYjYa318HpSqyJLDD", - "telegram": "https://t.me/goosefx", - "twitter": "https://twitter.com/GooseFX1", - "website": "https://goosefx.io" - } - }, - { - "chainId": 101, - "address": "9nEqaUcb16sQ3Tn1psbkWqyhPdLmfHWjKGymREjsAgTE", - "symbol": "WOOF", - "name": "WOOF", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/9nEqaUcb16sQ3Tn1psbkWqyhPdLmfHWjKGymREjsAgTE/logo.png", - "tags": ["community-token", "meme-token"], - "extensions": { - "coingeckoId": "woof-token", - "serumV3Usdc": "CwK9brJ43MR4BJz2dwnDM7EXCNyHhGqCJDrAdsEts8n5", - "website": "https://woofsolana.com" - } - }, - { - "chainId": 101, - "address": "8ymi88q5DtmdNTn2sPRNFkvMkszMHuLJ1e3RVdWjPa3s", - "symbol": "SDOGE", - "name": "SolDoge", - "decimals": 0, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/8ymi88q5DtmdNTn2sPRNFkvMkszMHuLJ1e3RVdWjPa3s/logo.png", - "extensions": { - "coingeckoId": "soldoge", - "discord": "https://bit.ly/SDOGEDiscord", - "serumV3Usdc": "9aruV2p8cRWxybx6wMsJwPFqeN7eQVPR74RrxdM3DNdu", - "twitter": "https://twitter.com/SolanaDoge", - "website": "https://www.soldoge.io" - } - }, - { - "chainId": 101, - "address": "5p2zjqCd1WJzAVgcEnjhb9zWDU7b9XVhFhx4usiyN7jB", - "symbol": "CATO", - "name": "CATO", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/5p2zjqCd1WJzAVgcEnjhb9zWDU7b9XVhFhx4usiyN7jB/logo.png", - "tags": ["Meme-Token"], - "extensions": { - "coingeckoId": "cato", - "serumV3Usdc": "9fe1MWiKqUdwift3dEpxuRHWftG72rysCRHbxDy6i9xB", - "telegram": "https://t.me/SolanaCATO", - "twitter": "https://twitter.com/SolanaCATO", - "website": "https://official.catodex.com" - } - }, - { - "chainId": 101, - "address": "H7Qc9APCWWGDVxGD5fJHmLTmdEgT9GFatAKFNg6sHh8A", - "symbol": "OOGI", - "name": "OOGI", - "decimals": 9, - "logoURI": "https://oogi.com/icon.png", - "extensions": { - "coingeckoId": "oogi", - "discord": "https://discord.gg/oogi", - "serumV3Usdc": "ANUCohkG9gamUn6ofZEbnzGkjtyMexDhnjCwbLDmQ8Ub", - "telegram": "https://t.me/oogicoin", - "twitter": "https://twitter.com/oogicoin", - "website": "https://oogi.com/" - } - }, - { - "chainId": 101, - "address": "sonarX4VtVkQemriJeLm6CKeW3GDMyiBnnAEMw1MRAE", - "symbol": "SONAR", - "name": "Sonar Watch", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/sonarX4VtVkQemriJeLm6CKeW3GDMyiBnnAEMw1MRAE/logo.png", - "tags": ["utility-token"], - "extensions": { - "coingeckoId": "sonarwatch", - "discord": "https://discord.gg/sonarwatch", - "twitter": "https://twitter.com/Sonarwatch", - "website": "https://sonar.watch/" - } - }, - { - "chainId": 101, - "address": "APTtJyaRX5yGTsJU522N4VYWg3vCvSb65eam5GrPT5Rt", - "symbol": "APT", - "name": "Apricot", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/APTtJyaRX5yGTsJU522N4VYWg3vCvSb65eam5GrPT5Rt/logo.svg", - "tags": ["apricot", "lending", "x-farm"], - "extensions": { - "coingeckoId": "apricot", - "discord": "https://discord.gg/Aw6MEUue", - "medium": "https://apricotfinance.medium.com/", - "twitter": "https://twitter.com/ApricotFinance", - "website": "https://apricot.one" - } - }, - { - "chainId": 101, - "address": "DFL1zNkaGPWm1BqAVqRjCZvHmwTFrEaJtbzJWgseoNJh", - "symbol": "DFL", - "name": "DeFi Land", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/DFL1zNkaGPWm1BqAVqRjCZvHmwTFrEaJtbzJWgseoNJh/logo.png", - "tags": ["utility-token"], - "extensions": { - "coingeckoId": "defi-land", - "coinmarketcap": "https://coinmarketcap.com/currencies/defi-land", - "discord": "https://discord.com/invite/defiland", - "medium": "https://defiland.medium.com/", - "serumV3Usdc": "9UBuWgKN8ZYXcZWN67Spfp3Yp67DKBq1t31WLrVrPjTR", - "telegram": "https://t.me/defiland_official", - "twitter": "https://twitter.com/DeFi_Land", - "website": "https://defiland.app/" - } - }, - { - "chainId": 101, - "address": "ErGB9xa24Szxbk1M28u2Tx8rKPqzL6BroNkkzk5rG4zj", - "symbol": "FRKT", - "name": "FRAKT Token", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/ErGB9xa24Szxbk1M28u2Tx8rKPqzL6BroNkkzk5rG4zj/logo.png", - "tags": ["utility-token"], - "extensions": { - "coingeckoId": "frakt-token", - "coinmarketcap": "https://coinmarketcap.com/currencies/frakt-token/", - "twitter": "https://twitter.com/FraktArt", - "website": "https://frakt.art" - } - }, - { - "chainId": 101, - "address": "FNFKRV3V8DtA3gVJN6UshMiLGYA8izxFwkNWmJbFjmRj", - "symbol": "TTT", - "name": "TabTrader Token", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/FNFKRV3V8DtA3gVJN6UshMiLGYA8izxFwkNWmJbFjmRj/logo.svg", - "tags": ["utility-token"], - "extensions": { - "coingeckoId": "tabtrader", - "description": "TabTrader allows users to trade anywhere and anytime from their mobile device with all the main crypto exchanges accessible through a unified interface.", - "discord": "https://discord.gg/pSMjEh7paU", - "medium": "https://medium.com/@tabtraderbtc", - "telegram": "https://t.me/tabtrader_token_en", - "twitter": "https://twitter.com/tabtraderpro", - "website": "https://tab-trader.com/", - "youtube": "https://www.youtube.com/c/TabTrader" - } - }, - { - "chainId": 101, - "address": "EwJN2GqUGXXzYmoAciwuABtorHczTA5LqbukKXV1viH7", - "symbol": "UPS", - "name": "UPS token (UPFI Network)", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EwJN2GqUGXXzYmoAciwuABtorHczTA5LqbukKXV1viH7/logo.png", - "extensions": { - "discord": "https://discord.gg/nHMDdyAggx", - "facebook": "https://www.facebook.com/UPFInetwork", - "medium": "https://upfinetwork.medium.com", - "serumV3Usdc": "DByPstQRx18RU2A8DH6S9mT7bpT6xuLgD2TTFiZJTKZP", - "telegram": "https://t.me/upfinetworkchannel", - "twitter": "https://twitter.com/upfi_network", - "website": "https://upfi.network/" - } - }, - { - "chainId": 101, - "address": "FANTafPFBAt93BNJVpdu25pGPmca3RfwdsDsRrT3LX1r", - "symbol": "FANT", - "name": "Phantasia", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/FANTafPFBAt93BNJVpdu25pGPmca3RfwdsDsRrT3LX1r/logo.png", - "tags": ["utility-token", "governance-token"], - "extensions": { - "coingeckoId": "phantasia", - "coinmarketcap": "https://coinmarketcap.com/currencies/phantasia/", - "discord": "https://t.co/Vskz9PkBBC?amp=1", - "github": "https://github.com/Phantasia-Sports", - "medium": "https://medium.com/@phantasia", - "twitter": "https://twitter.com/PhantasiaSports", - "website": "https://phantasia.app/" - } - }, - { - "chainId": 101, - "address": "NFTUkR4u7wKxy9QLaX2TGvd9oZSWoMo4jqSJqdMb7Nk", - "symbol": "BLOCK", - "name": "Blockasset", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/NFTUkR4u7wKxy9QLaX2TGvd9oZSWoMo4jqSJqdMb7Nk/logo.png", - "extensions": { - "coingeckoId": "blockasset", - "discord": "https://discord.com/invite/mynn9p6uNw", - "telegram": "https://t.me/blockassetupdates", - "twitter": "https://twitter.com/Blockassetco", - "website": "https://blockasset.co" - } - }, - { - "chainId": 101, - "address": "6F9XriABHfWhit6zmMUYAQBSy6XK5VF1cHXuW5LDpRtC", - "symbol": "RUN", - "name": "Run Token", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/6F9XriABHfWhit6zmMUYAQBSy6XK5VF1cHXuW5LDpRtC/RunGear.png", - "tags": ["utility-token"], - "extensions": { - "coingeckoId": "run", - "discord": "https://discord.com/invite/V2f74X8Zrt", - "telegram": "https://t.me/RunNode", - "twitter": "https://twitter.com/runnode", - "website": "https://runnode.com" - } - }, - { - "chainId": 101, - "address": "UXPhBoR3qG4UCiGNJfV7MqhHyFqKN68g45GoYvAeL2M", - "symbol": "UXP", - "name": "UXP Governance Token", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/UXPhBoR3qG4UCiGNJfV7MqhHyFqKN68g45GoYvAeL2M/uxp-icon-black.png", - "extensions": { - "coingeckoId": "uxd-protocol-token", - "coinmarketcap": "https://coinmarketcap.com/currencies/uxd-protocol/", - "discord": "https://discord.com/invite/BHfpYmjsBM", - "medium": "https://uxdprotocol.medium.com/", - "serumV3Usdc": "7KQpsp914VYnh62yV6AGfoG9hprfA14SgzEyqr6u9NY1", - "twitter": "https://twitter.com/UXDProtocol", - "website": "https://uxd.fi/" - } - }, - { - "chainId": 101, - "address": "cxxShYRVcepDudXhe7U62QHvw8uBJoKFifmzggGKVC2", - "symbol": "CHICKS", - "name": "SolChicks", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/cxxShYRVcepDudXhe7U62QHvw8uBJoKFifmzggGKVC2/logo.png", - "tags": ["gaming", "nfts", "utility-token", "community-token"], - "extensions": { - "coingeckoId": "solchicks-token", - "description": "The Leading Play-to-Earn Fantasy Game on Solana", - "discord": "https://discord.gg/solchicks", - "telegram": "https://t.me/solchicksnft", - "twitter": "https://twitter.com/SolChicksNFT", - "website": "https://www.solchicks.io/" - } - }, - { - "chainId": 101, - "address": "4ThReWAbAVZjNVgs5Ui9Pk3cZ5TYaD9u6Y89fp6EFzoF", - "symbol": "1SOL", - "name": "1sol.io Token", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/4ThReWAbAVZjNVgs5Ui9Pk3cZ5TYaD9u6Y89fp6EFzoF/logo.png", - "tags": ["wrapped", "utility-token", "aggregator"], - "extensions": { - "coinmarketcap": "https://coinmarketcap.com/currencies/1sol/", - "description": "1Sol aggregates DEX(s), lending, yield-farming, and cross-chain trading.", - "discord": "https://discord.gg/juvVBKnvkj", - "github": "https://github.com/1sol-io", - "medium": "https://medium.com/@1solProtocol", - "telegram": "https://t.me/onesolcommunity", - "twitter": "https://twitter.com/1solProtocol", - "website": "https://app.1sol.io/" - } - }, - { - "chainId": 101, - "address": "BygDd5LURoqztD3xETc99WCxLUbTi6WYSht9XiBgZ4HW", - "symbol": "WMP", - "name": "Whalemap", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/ssi91/crypto/main/logo.svg", - "tags": ["social-token"], - "extensions": { - "coingeckoId": "whalemap", - "website": "https://whalemap.io/" - } - }, - { - "chainId": 101, - "address": "UNQtEecZ5Zb4gSSVHCAWUQEoNnSVEbWiKCi1v9kdUJJ", - "symbol": "UNQ", - "name": "UNQ", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/UNQtEecZ5Zb4gSSVHCAWUQEoNnSVEbWiKCi1v9kdUJJ/logo.png", - "tags": ["utility-token"], - "extensions": { - "coingeckoId": "unq", - "coinmarketcap": "https://coinmarketcap.com/currencies/unqclub", - "discord": "https://discord.com/invite/unqnetwork", - "twitter": "https://twitter.com/clubunq", - "website": "https://unq.club/" - } - }, - { - "chainId": 101, - "address": "Basis9oJw9j8cw53oMV7iqsgo6ihi9ALw4QR31rcjUJa", - "symbol": "BASIS", - "name": "basis", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Basis9oJw9j8cw53oMV7iqsgo6ihi9ALw4QR31rcjUJa/logo.png", - "tags": ["utility-token"], - "extensions": { - "coingeckoId": "basis-markets", - "description": "BASIS is basis.markets' fee-sharing token. Holders are able to stake their BASIS tokens to receive a proportional share of trading fee rewards generated by the basis.markets Decentralised Basis Liquidity Pool (DBLP). BASIS tokens also give access to a high-reward liquidity mining programme, as well as, discounted future deposits into the basis.markets DBLP.", - "discord": "https://discord.gg/basismarkets", - "medium": "https://basismarkets.medium.com/", - "serumV3Usdc": "HsUNWR7ghHSumwDW3MNgs2HSh94yrDuZFVR1XpykA9or", - "twitter": "https://twitter.com/basismarkets", - "website": "https://basis.markets" - } - }, - { - "chainId": 101, - "address": "AFbX8oGjGpmVFywbVouvhQSRmiW2aR1mohfahi4Y2AdB", - "symbol": "GST", - "name": "GST", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/AFbX8oGjGpmVFywbVouvhQSRmiW2aR1mohfahi4Y2AdB/logo.png", - "extensions": { "website": "https://stepn.com/" } - }, - { - "chainId": 101, - "address": "MEANeD3XDdUmNMsRGjASkSWdC8prLYsoRJ61pPeHctD", - "symbol": "MEAN", - "name": "MEAN", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/MEANeD3XDdUmNMsRGjASkSWdC8prLYsoRJ61pPeHctD/logo.svg", - "extensions": { - "coingeckoId": "meanfi", - "discord": "https://discord.meanfi.com/", - "medium": "https://meandao.medium.com", - "serumV3Usdc": "3WXrxhrj4PXYUwW4ozBjxdSxwEp9ELKf3vETxXTqdiQJ", - "twitter": "https://twitter.com/meanfinance", - "website": "https://www.meanfi.com/" - } - }, - { - "chainId": 101, - "address": "F3nefJBcejYbtdREjui1T9DPh5dBgpkKq7u2GAAMXs5B", - "symbol": "AART", - "name": "ALL ART", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/allartprotocol/token-list/main/assets/mainnet/F3nefJBcejYbtdREjui1T9DPh5dBgpkKq7u2GAAMXs5B/logo.jpg", - "tags": ["utility-token"], - "extensions": { - "discord": "https://discord.gg/allart", - "github": "https://github.com/allartprotocol", - "medium": "https://allart.medium.com", - "telegram": "https://t.me/allartprotocol", - "twitter": "https://twitter.com/AllArtProtocol", - "website": "https://all.art" - } - }, - { - "chainId": 101, - "address": "SHDWyBxihqiCj6YekG2GUr7wqKLeLAMK1gHZck9pL6y", - "symbol": "SHDW", - "name": "Shadow Token", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/SHDWyBxihqiCj6YekG2GUr7wqKLeLAMK1gHZck9pL6y/logo.png", - "tags": ["utility-token"], - "extensions": { - "coingeckoId": "genesysgo-shadow", - "coinmarketcap": "https://coinmarketcap.com/currencies/genesysgo-shadow/", - "discord": "https://discord.gg/y86HPCkk", - "serumV3Usdc": "CVJVpXU9xksCt2uSduVDrrqVw6fLZCAtNusuqLKc5DhW", - "website": "https://www.shadowysupercoderdao.com" - } - }, - { - "chainId": 101, - "address": "SCYfrGCw8aDiqdgcpdGjV6jp4UVVQLuphxTDLNWu36f", - "symbol": "SCY", - "name": "Synchrony", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/SCYfrGCw8aDiqdgcpdGjV6jp4UVVQLuphxTDLNWu36f/logo.png", - "extensions": { - "serumV3Usdc": "DR8V2wUCSFKCGjML6AZvUB2eYWDPVQ5xju3DeXGgpSaB", - "twitter": "https://twitter.com/SynchronyFi", - "website": "https://synchrony.fi" - } - }, - { - "chainId": 101, - "address": "METAmTMXwdb8gYzyCPfXXFmZZw4rUsXX58PNsDg7zjL", - "symbol": "SLC", - "name": "Solice", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/METAmTMXwdb8gYzyCPfXXFmZZw4rUsXX58PNsDg7zjL/logo.png", - "extensions": { - "coingeckoId": "solice", - "discord": "https://discord.gg/solice", - "serumV3Usdc": "DvmDTjsdnN77q7SST7gngLydP1ASNNpUVi4cNfU95oCr", - "telegram": "https://t.me/solice_io", - "twitter": "https://twitter.com/solice_io", - "website": "https://www.solice.io/" - } - }, - { - "chainId": 101, - "address": "9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i", - "symbol": "UST", - "name": "UST (Portal)", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/9vMJfxuKxXBoEa7rM12mYLMwTacLMLDJqHozw96WQL8i/logo.png", - "tags": ["wrapped", "wormhole", "stablecoin"], - "extensions": { - "address": "uusd", - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "coingeckoId": "terrausd", - "serumV3Usdc": "8WmckvEoVGZvtN8knjdzFGbWJ3Sr4BcWdyzSYuCrD4YK" - } - }, - { - "chainId": 101, - "address": "F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W", - "symbol": "LUNA", - "name": "LUNA (Portal)", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/F6v4wfAdJB8D8p77bMXZgYt8TDKsYxLYxH5AFhUkYx9W/logo.png", - "tags": ["wrapped", "wormhole"], - "extensions": { - "address": "uluna", - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "coingeckoId": "terra-luna", - "serumV3Usdc": "HBTu8hNaoT3VyiSSzJYa8jwt9sDGKtJviSwFa11iXdmE" - } - }, - { - "chainId": 101, - "address": "7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn", - "symbol": "JSOL", - "name": "JPOOL Solana Token", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/7Q2afV64in6N6SeZsAAB81TJzwDoD6zpqmHkzi9Dcavn/logo.svg", - "tags": ["stake-pool-token", "utility-token"], - "extensions": { - "discord": "https://discord.gg/qR4BA9QXVR", - "telegram": "https://t.me/jpoolsolana", - "twitter": "https://twitter.com/JPoolSolana", - "website": "https://jpool.one/" - } - }, - { - "chainId": 101, - "address": "GEJpt3Wjmr628FqXxTgxMce1pLntcPV4uFi8ksxMyPQh", - "symbol": "DAOSOL", - "name": "daoSOL Token", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/GEJpt3Wjmr628FqXxTgxMce1pLntcPV4uFi8ksxMyPQh/logo.png", - "tags": ["stake-pool-token"], - "extensions": { - "description": "daoSOL is the staking token issued by the MonkeDAO staking pool", - "twitter": "https://twitter.com/MonkeDAO", - "website": "https://monkedao.io/" - } - }, - { - "chainId": 101, - "address": "GENEtH5amGSi8kHAtQoezp1XEXwZJ8vcuePYnXdKrMYz", - "symbol": "GENE", - "name": "Genopets", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/GENEtH5amGSi8kHAtQoezp1XEXwZJ8vcuePYnXdKrMYz/logo.png", - "tags": ["genopets", "utility-token"], - "extensions": { - "coingeckoId": "genopets", - "discord": "https://discord.gg/genopets", - "serumV3Usdc": "FwZ2GLyNNrFqXrmR8Sdkm9DQ61YnQmxS6oobeH3rrLUM", - "twitter": "https://twitter.com/genopets", - "website": "https://genopets.me" - } - }, - { - "chainId": 101, - "address": "5Wsd311hY8NXQhkt9cWHwTnqafk7BGEbLu8Py3DSnPAr", - "symbol": "CMFI", - "name": "Compendium Finance", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/5Wsd311hY8NXQhkt9cWHwTnqafk7BGEbLu8Py3DSnPAr/logo.png", - "tags": [ - "utility-token", - "community-token", - "DeFi", - "Exchange", - "Application" - ], - "extensions": { - "coingeckoId": "compendium-fi", - "discord": "https://discord.gg/64r2xtqczs", - "medium": "https://compendiumfi.medium.com/", - "serumV3Usdc": "3Mf3bxVS2zLW3bbr9BNbqdiizaUwCGwoi3xhrAXfbFnW", - "twitter": "https://twitter.com/CompendiumFi", - "website": "https://compendium.finance/", - "whitepaper": "https://compendium.finance/litepaper" - } - }, - { - "chainId": 101, - "address": "GNCjk3FmPPgZTkbQRSxr6nCvLtYMbXKMnRxg8BgJs62e", - "symbol": "CELO", - "name": "CELO (Allbridge from Celo)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/GNCjk3FmPPgZTkbQRSxr6nCvLtYMbXKMnRxg8BgJs62e/logo.png", - "extensions": { "coingeckoId": "celo" } - }, - { - "chainId": 101, - "address": "EsPKhGTMf3bGoy4Qm7pCv3UCcWqAmbC1UGHBTDxRjjD4", - "symbol": "FTM", - "name": "FTM (Allbridge from Fantom)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EsPKhGTMf3bGoy4Qm7pCv3UCcWqAmbC1UGHBTDxRjjD4/logo.png", - "extensions": { "coingeckoId": "fantom" } - }, - { - "chainId": 101, - "address": "HBB111SCo9jkCejsZfz8Ec8nH7T6THF8KEKSnvwT6XK6", - "symbol": "HBB", - "name": "Hubble Protocol Token", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/HBB111SCo9jkCejsZfz8Ec8nH7T6THF8KEKSnvwT6XK6/logo.svg", - "tags": ["stake-pool-token", "utility-token", "community-token"], - "extensions": { - "coingeckoId": "hubble", - "coinmarketcap": "https://coinmarketcap.com/currencies/hubble-protocol/", - "discord": "https://discord.gg/d44A8WvK", - "twitter": "https://twitter.com/hubbleprotocol", - "website": "https://hubbleprotocol.io/" - } - }, - { - "chainId": 101, - "address": "SuperbZyz7TsSdSoFAZ6RYHfAWe9NmjXBLVQpS8hqdx", - "symbol": "SB", - "name": "SuperBonds Token", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/SuperbZyz7TsSdSoFAZ6RYHfAWe9NmjXBLVQpS8hqdx/logo.svg", - "tags": ["defi-token"], - "extensions": { "website": "https://superbonds.finance" } - }, - { - "chainId": 101, - "address": "seedEDBqu63tJ7PFqvcbwvThrYUkQeqT6NLf81kLibs", - "symbol": "SEEDED", - "name": "Seeded Network", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/seedEDBqu63tJ7PFqvcbwvThrYUkQeqT6NLf81kLibs/logo.png", - "tags": ["lending", "defi"], - "extensions": { - "discord": "https://seeded.network/discord", - "medium": "https://blog.seeded.network/", - "reddit": "https://reddit.com/r/SeededNetwork", - "twitter": "https://twitter.com/SeededNetwork", - "website": "https://seeded.network" - } - }, - { - "chainId": 101, - "address": "9LzCMqDgTKYz9Drzqnpgee3SGa89up3a247ypMj2xrqM", - "symbol": "AUDIO", - "name": "Audius (Portal)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/9LzCMqDgTKYz9Drzqnpgee3SGa89up3a247ypMj2xrqM/logo.png", - "tags": ["wrapped", "ethereum"], - "extensions": { - "address": "0x18aAA7115705e8be94bfFEBDE57Af9BFc265B998", - "assetContract": "https://etherscan.io/address/0x18aAA7115705e8be94bfFEBDE57Af9BFc265B998", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "audius", - "serumV3Usdc": "FxquLRmVMPXiS84FFSp8q5fbVExhLkX85yiXucyu7xSC" - } - }, - { - "chainId": 101, - "address": "MMAx26JtJgSWv6yH48nEHCGZcVvRbf9Lt9ALa7jSipe", - "symbol": "MMA", - "name": "mma", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/MMAx26JtJgSWv6yH48nEHCGZcVvRbf9Lt9ALa7jSipe/logo.png", - "tags": ["utility-token"], - "extensions": { - "description": "WE PLAY, YOU EARN, By helping gamers generate an income for themselves, they create an income for you.", - "discord": "https://discord.gg/mmagaming", - "medium": "https://medium.com/@MMAGaming", - "twitter": "https://twitter.com/mmagaming_io", - "website": "https://mmagaming.io/" - } - }, - { - "chainId": 101, - "address": "G9tt98aYSznRk7jWsfuz9FnTdokxS6Brohdo9hSmjTRB", - "symbol": "PUFF", - "name": "PUFF", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/G9tt98aYSznRk7jWsfuz9FnTdokxS6Brohdo9hSmjTRB/logo.png", - "tags": ["utility-token"], - "extensions": { - "coingeckoId": "puff", - "discord": "https://discord.gg/stonedapecrew", - "serumV3Usdc": "FjkwTi1nxCa1S2LtgDwCU8QjrbGuiqpJvYWu3SWUHdrV", - "twitter": "https://twitter.com/stonedapecrew", - "website": "https://www.stonedapecrew.com/" - } - }, - { - "chainId": 101, - "address": "2HeykdKjzHKGm2LKHw8pDYwjKPiFEoXAz74dirhUgQvq", - "symbol": "SAO", - "name": "Sator", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/2HeykdKjzHKGm2LKHw8pDYwjKPiFEoXAz74dirhUgQvq/Sator_Logo.png", - "tags": ["NFT", "soical-token", "utility-token", "meta-verse"], - "extensions": { - "coingeckoId": "sator", - "github": "https://github.com/SatorNetwork", - "medium": "https://satortoken.medium.com", - "telegram": "https://t.me/SatorSAO", - "twitter": "https://twitter.com/SatorSAO", - "website": "https://sator.io" - } - }, - { - "chainId": 101, - "address": "RLYv2ubRMDLcGG2UyvPmnPmkfuQTsMbg4Jtygc7dmnq", - "symbol": "SRLY", - "name": "Rally (Solana)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/RLYv2ubRMDLcGG2UyvPmnPmkfuQTsMbg4Jtygc7dmnq/logo.png", - "extensions": { - "coingeckoId": "rally-solana", - "website": "https://rly.network" - } - }, - { - "chainId": 101, - "address": "zebeczgi5fSEtbpfQKVZKCJ3WgYXxjkMUkNNx7fLKAF", - "symbol": "ZBC", - "name": "ZEBEC", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/zebeczgi5fSEtbpfQKVZKCJ3WgYXxjkMUkNNx7fLKAF/logo.png", - "tags": ["utility-token", "veni", "vidi", "vici"], - "extensions": { - "coingeckoId": "zebec-protocol", - "description": "Zebec is a continuous Settlement Protocol that will transform payroll, cash flow, and token vesting by allowing users to send payments and distributions every second.", - "discord": "https://discord.gg/gYCe7h8p", - "telegram": "https://t.me/zebececosystem", - "twitter": "https://twitter.com/Zebec_HQ", - "website": "https://zebec.io" - } - }, - { - "chainId": 101, - "address": "7i5KKsX2weiTkry7jA4ZwSuXGhs5eJBEjY8vVxR4pfRx", - "symbol": "GMT", - "name": "GMT", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/7i5KKsX2weiTkry7jA4ZwSuXGhs5eJBEjY8vVxR4pfRx/logo.png", - "extensions": { "website": "https://stepn.com/" } - }, - { - "chainId": 101, - "address": "HfYFjMKNZygfMC8LsQ8LtpPsPxEJoXJx4M6tqi75Hajo", - "symbol": "CWAR", - "name": "Cryowar Token", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/HfYFjMKNZygfMC8LsQ8LtpPsPxEJoXJx4M6tqi75Hajo/logo.png", - "tags": ["utility-token"], - "extensions": { - "discord": "https://discord.com/invite/cryowar", - "telegram": "https://t.me/cryowar", - "twitter": "https://twitter.com/CryowarDevs", - "website": "https://cryowar.com" - } - }, - { - "chainId": 101, - "address": "4SZjjNABoqhbd4hnapbvoEPEqT8mnNkfbEoAwALf1V8t", - "symbol": "CAVE", - "name": "Crypto Cavemen", - "decimals": 6, - "logoURI": "https://ftoblquxiunjey7bu4eevlz2u7kwg5s3yvou7adgge2jbihcu7qq.arweave.net/LNwVwpdFGpJj4acISq86p9VjdlvFXU-AZjE0kKDip-E/?ext=png", - "tags": ["utility-token", "game", "play2earn"], - "extensions": { - "coingeckoId": "cave", - "discord": "https://discord.com/invite/cryptocavemen", - "twitter": "https://twitter.com/TheCavemenClub", - "website": "https://cryptocavemen.io" - } - }, - { - "chainId": 101, - "address": "YAWtS7vWCSRPckx1agB6sKidVXiXiDUfehXdEUSRGKE", - "symbol": "YAW", - "name": "Yawww", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/YAWtS7vWCSRPckx1agB6sKidVXiXiDUfehXdEUSRGKE/yaw.png", - "tags": ["utility-token"], - "extensions": { - "twitter": "https://twitter.com/YawwwNFT", - "website": "https://www.yawww.io" - } - }, - { - "chainId": 101, - "address": "ArUkYE2XDKzqy77PRRGjo4wREWwqk6RXTfM9NeqzPvjU", - "symbol": "RENDOGE", - "name": "renDOGE", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/ArUkYE2XDKzqy77PRRGjo4wREWwqk6RXTfM9NeqzPvjU/logo.png", - "extensions": { - "coingeckoId": "rendoge", - "serumV3Usdc": "5FpKCWYXgHWZ9CdDMHjwxAfqxJLdw2PRXuAmtECkzADk", - "website": "https://renproject.io/" - } - }, - { - "chainId": 101, - "address": "49c7WuCZkQgc3M4qH8WuEUNXfgwupZf1xqWkDQ7gjRGt", - "symbol": "SAND", - "name": "Sandbox (Portal)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/49c7WuCZkQgc3M4qH8WuEUNXfgwupZf1xqWkDQ7gjRGt/logo.png", - "tags": ["wrapped", "ethereum"], - "extensions": { - "address": "0x3845badade8e6dff049820680d1f14bd3903a5d0", - "assetContract": "https://etherscan.io/address/0x3845badade8e6dff049820680d1f14bd3903a5d0", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "the-sandbox", - "serumV3Usdc": "3FE2g3cadTJjN3C7gNRavwnv7Yh9Midq7h9KgTVUE7tR" - } - }, - { - "chainId": 101, - "address": "3K6rftdAaQYMPunrtNRHgnK2UAtjm2JwyT2oCiTDouYE", - "symbol": "XCOPE", - "name": "XCOPE", - "decimals": 0, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/3K6rftdAaQYMPunrtNRHgnK2UAtjm2JwyT2oCiTDouYE/logo.png", - "tags": ["trading", "index", "Algos"], - "extensions": { - "coingeckoId": "cope", - "serumV3Usdc": "7MpMwArporUHEGW7quUpkPZp5L5cHPs9eKUfKCdaPHq2", - "website": "https://www.unlimitedcope.com/" - } - }, - { - "chainId": 101, - "address": "svtMpL5eQzdmB3uqK9NXaQkq8prGZoKQFNVJghdWCkV", - "symbol": "SVT", - "name": "Solvent", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/svtMpL5eQzdmB3uqK9NXaQkq8prGZoKQFNVJghdWCkV/logo.png", - "tags": ["utility-token"], - "extensions": { - "coingeckoId": "solvent", - "discord": "https://discord.gg/thK8BCtQbM", - "github": "https://github.com/solventprotocol", - "medium": "https://medium.com/@solventprotocol", - "serumV3Usdc": "HuFKVQNyB177c9DiocQksYzBCtHMRUP5bBXZJzuLvYQm", - "telegram": "https://t.me/solventprotocol", - "twitter": "https://twitter.com/solventprotocol", - "website": "https://solvent.xyz" - } - }, - { - "chainId": 101, - "address": "51tMb3zBKDiQhNwGqpgwbavaGH54mk8fXFzxTc1xnasg", - "symbol": "APEX", - "name": "APEX", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/51tMb3zBKDiQhNwGqpgwbavaGH54mk8fXFzxTc1xnasg/logo.png", - "extensions": { - "coingeckoId": "apexit-finance", - "discord": "https://discord.gg/aASQy2dWsN", - "telegram": "https://t.me/apexit_finance", - "twitter": "https://twitter.com/apeXit_finance", - "website": "https://apexit.finance/" - } - }, - { - "chainId": 101, - "address": "CRWNYkqdgvhGGae9CKfNka58j6QQkaD5bLhKXvUYqnc1", - "symbol": "CRWNY", - "name": "Crowny token", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/CRWNYkqdgvhGGae9CKfNka58j6QQkaD5bLhKXvUYqnc1/logo.png", - "extensions": { - "coingeckoId": "crowny-token", - "discord": "https://www.discord.gg/4JvMHrgNvv", - "medium": "https://crowny.medium.com/", - "serumV3Usdc": "H8GSFzSZmPNs4ANW9dPd5XTgrzWkta3CaT57TgWYs7SV", - "telegram": "https://t.me/crownyofficial", - "twitter": "https://twitter.com/crownyio", - "website": "https://crowny.io/" - } - }, - { - "chainId": 101, - "address": "PRSMNsEPqhGVCH1TtWiJqPjJyh2cKrLostPZTNy1o5x", - "symbol": "PRISM", - "name": "PRISM", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/PRSMNsEPqhGVCH1TtWiJqPjJyh2cKrLostPZTNy1o5x/logo.svg", - "tags": ["utility-token", "DeFi", "aggregator", "governance-token"], - "extensions": { - "coingeckoId": "prism", - "description": "Solana's DEX Aggregator", - "discord": "https://discord.gg/prism-ag", - "serumV3Usdc": "2MvXnxngd1gKp6gE8Q63wiPHSpveWcx8x4wf43VpyiA6", - "twitter": "https://twitter.com/prism_ag", - "website": "https://prism.ag" - } - }, - { - "chainId": 101, - "address": "inL8PMVd6iiW3RCBJnr5AsrRN6nqr4BTrcNuQWQSkvY", - "symbol": "IN", - "name": "Sol Invictus", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/inL8PMVd6iiW3RCBJnr5AsrRN6nqr4BTrcNuQWQSkvY/logo-owl.png", - "tags": [ - "decentralizedreserve", - "utility-token", - "DeFi", - "community-token" - ], - "extensions": { - "coingeckoId": "invictus", - "discord": "https://discord.gg/invictusdao", - "serumV3Usdc": "49vwM54DX3JPXpey2daePZPmimxA4CrkXLZ6E1fGxx2Z", - "twitter": "https://twitter.com/InvictusDAO", - "website": "https://invictusdao.fi/" - } - }, - { - "chainId": 101, - "address": "AR1Mtgh7zAtxuxGd2XPovXPVjcSdY3i4rQYisNadjfKy", - "symbol": "SOSUSHI", - "name": "Wrapped SUSHI (Sollet)", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/AR1Mtgh7zAtxuxGd2XPovXPVjcSdY3i4rQYisNadjfKy/logo.png", - "tags": ["wrapped-sollet", "ethereum"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "coingeckoId": "sushi", - "serumV3Usdc": "A1Q9iJDVVS8Wsswr9ajeZugmj64bQVCYLZQLra2TMBMo", - "serumV3Usdt": "6DgQRTpJTnAYBSShngAVZZDq7j9ogRN1GfSQ3cq9tubW", - "waterfallbot": "https://bit.ly/SUSHIwaterfall", - "website": "https://www.sushi.com" - } - }, - { - "chainId": 101, - "address": "CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5", - "symbol": "RENBTC", - "name": "renBTC", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/CDJWUqTcYTVAKXAVXoQZFes5JUFc7owSeq7eMQcDSbo5/logo.png", - "extensions": { - "coingeckoId": "renbtc", - "serumV3Usdc": "74Ciu5yRzhe8TFTHvQuEVbFZJrbnCMRoohBK33NNiPtv", - "website": "https://renproject.io/" - } - }, - { - "chainId": 101, - "address": "BRLsMczKuaR5w9vSubF4j8HwEGGprVAyyVgS4EX7DKEg", - "symbol": "CYS", - "name": "Cykura", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/BRLsMczKuaR5w9vSubF4j8HwEGGprVAyyVgS4EX7DKEg/logo.svg", - "tags": ["utility-token"], - "extensions": { - "coingeckoId": "cykura", - "coinmarketcap": "https://coinmarketcap.com/currencies/cyclos/", - "discord": "https://discord.gg/gyaK56UreX", - "github": "https://github.com/cykura", - "medium": "https://cykura.medium.com/", - "serumV3Usdc": "6V6y6QFi17QZC9qNRpVp7SaPiHpCTp2skbRQkUyZZXPW", - "solanium": "https://www.solanium.io/project/cyclos/", - "telegram": "https://t.me/cykuraofficialchat", - "twitter": "https://twitter.com/cykurafi", - "website": "https://cykura.io/" - } - }, - { - "chainId": 101, - "address": "333iHoRM2Awhf9uVZtSyTfU8AekdGrgQePZsKMFPgKmS", - "symbol": "ISOLA", - "name": "Intersola", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/333iHoRM2Awhf9uVZtSyTfU8AekdGrgQePZsKMFPgKmS/logo.png", - "tags": ["utility-token"], - "extensions": { - "github": "https://github.com/Intersolaio/", - "medium": "https://intersola.medium.com/", - "serumV3Usdt": "42QVcMqoXmHT94zaBXm9KeU7pqDfBuAPHYN9ADW8weCF", - "telegram": "https://t.me/intersola", - "twitter": "https://twitter.com/intersola_io", - "website": "https://intersola.io/" - } - }, - { - "chainId": 101, - "address": "Fm9rHUTF5v3hwMLbStjZXqNBBoZyGriQaFM6sTFz3K8A", - "symbol": "MBS", - "name": "MonkeyBucks", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Fm9rHUTF5v3hwMLbStjZXqNBBoZyGriQaFM6sTFz3K8A/logo.png", - "tags": [ - "utility-token", - "game-token", - "game-currency", - "GameFi", - "Gaming" - ], - "extensions": { - "coingeckoId": "monkeyball", - "description": "MonkeyLeague is the next-gen esports metaverse empowering players to create, play, compete, and earn.", - "discord": "https://discord.gg/monkeyleague", - "facebook": "https://www.facebook.com/TheMonkeyLeague", - "instagram": "https://www.instagram.com/themonkeyleague/", - "medium": "https://medium.com/@MonkeyLeague", - "reddit": "https://www.reddit.com/r/MonkeyBallGame", - "telegram": "https://t.me/MonkeyLeague_Official", - "twitter": "https://twitter.com/TheMonkeyLeague", - "website": "https://www.monkeyleague.io/" - } - }, - { - "chainId": 101, - "address": "Bx1fDtvTN6NvE4kjdPHQXtmGSg582bZx9fGy4DQNMmAT", - "symbol": "SOLC", - "name": "Solcubator", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Bx1fDtvTN6NvE4kjdPHQXtmGSg582bZx9fGy4DQNMmAT/logo.png", - "extensions": { - "twitter": "https://twitter.com/Solcubator", - "website": "http://solcubator.io" - } - }, - { - "chainId": 101, - "address": "CWE8jPTUYhdCTZYWPTe1o5DFqfdjzWKc9WKz6rSjQUdG", - "symbol": "SOLINK", - "name": "Wrapped Chainlink (Sollet)", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/CWE8jPTUYhdCTZYWPTe1o5DFqfdjzWKc9WKz6rSjQUdG/logo.png", - "tags": ["wrapped-sollet", "ethereum"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "coingeckoId": "chainlink", - "serumV3Usdc": "3hwH1txjJVS8qv588tWrjHfRxdqNjBykM1kMcit484up", - "serumV3Usdt": "3yEZ9ZpXSQapmKjLAGKZEzUNA1rcupJtsDp5mPBWmGZR" - } - }, - { - "chainId": 101, - "address": "EdAhkbj5nF9sRM7XN7ewuW8C9XEUMs8P7cnoQ57SYE96", - "symbol": "FAB", - "name": "FABRIC", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EdAhkbj5nF9sRM7XN7ewuW8C9XEUMs8P7cnoQ57SYE96/logo.png", - "extensions": { - "coingeckoId": "fabric", - "serumV3Usdc": "Cud48DK2qoxsWNzQeTL5D8sAiHsGwG8Ev1VMNcYLayxt", - "twitter": "https://twitter.com/official_fabric", - "website": "https://fsynth.io/" - } - }, - { - "chainId": 101, - "address": "E5ndSkaB17Dm7CsD22dvcjfrYSDLCxFcMd6z8ddCk5wp", - "symbol": "RIN", - "name": "Aldrin", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/E5ndSkaB17Dm7CsD22dvcjfrYSDLCxFcMd6z8ddCk5wp/logo.png", - "extensions": { - "coingeckoId": "aldrin", - "serumV3Usdc": "7gZNLDbWE73ueAoHuAeFoSu7JqmorwCLpNTBXHtYSFTa", - "twitter": "https://twitter.com/Aldrin_Exchange", - "website": "https://rin.aldrin.com/" - } - }, - { - "chainId": 101, - "address": "7dgHoN8wBZCc5wbnQ2C47TDnBMAxG4Q5L3KjP67z8kNi", - "symbol": "MANA", - "name": "Decentraland (Portal)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/7dgHoN8wBZCc5wbnQ2C47TDnBMAxG4Q5L3KjP67z8kNi/logo.png", - "tags": ["wrapped", "ethereum"], - "extensions": { - "address": "0x0f5d2fb29fb7d3cfee444a200298f468908cc942", - "assetContract": "https://etherscan.io/address/0x0f5d2fb29fb7d3cfee444a200298f468908cc942", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "decentraland", - "serumV3Usdc": "7GSn6KQRasgPQCHwCbuDjDCsyZ3cxVHKWFmBXzJUUW8P" - } - }, - { - "chainId": 101, - "address": "3JSf5tPeuscJGtaCp5giEiDhv51gQ4v3zWg8DGgyLfAB", - "symbol": "SOYFI", - "name": "Wrapped YFI (Sollet)", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/3JSf5tPeuscJGtaCp5giEiDhv51gQ4v3zWg8DGgyLfAB/logo.png", - "tags": ["wrapped-sollet", "ethereum"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "coingeckoId": "yearn-finance", - "serumV3Usdc": "7qcCo8jqepnjjvB5swP4Afsr3keVBs6gNpBTNubd1Kr2", - "serumV3Usdt": "3Xg9Q4VtZhD4bVYJbTfgGWFV5zjE3U7ztSHa938zizte" - } - }, - { - "chainId": 101, - "address": "4TGxgCSJQx2GQk9oHZ8dC5m3JNXTYZHjXumKAW3vLnNx", - "symbol": "OXS", - "name": "Oxbull Sol", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/4TGxgCSJQx2GQk9oHZ8dC5m3JNXTYZHjXumKAW3vLnNx/logo.png", - "tags": ["utility-token"], - "extensions": { - "coingeckoId": "oxbull-solana", - "github": "https://github.com/OxBull", - "medium": "https://medium.com/@oxbull", - "telegramAnnouncements": "https://t.me/Oxbull_tech", - "twitter": "https://twitter.com/OxBull5", - "website": "https://www.oxbull.tech" - } - }, - { - "chainId": 101, - "address": "CsZ5LZkDS7h9TDKjrbL7VAwQZ9nsRu8vJLhRYfmGaN8K", - "symbol": "SOALEPH", - "name": "Wrapped ALEPH (Sollet)", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/CsZ5LZkDS7h9TDKjrbL7VAwQZ9nsRu8vJLhRYfmGaN8K/logo.png", - "tags": ["wrapped-sollet", "ethereum"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "coingeckoId": "aleph", - "serumV3Usdc": "GcoKtAmTy5QyuijXSmJKBtFdt99e6Buza18Js7j9AJ6e", - "serumV3Usdt": "Gyp1UGRgbrb6z8t7fpssxEKQgEmcJ4pVnWW3ds2p6ZPY" - } - }, - { - "chainId": 101, - "address": "8FU95xFJhUUkyyCLU13HSzDLs7oC4QZdXQHL6SCeab36", - "symbol": "UNI", - "name": "Uniswap (Portal)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/8FU95xFJhUUkyyCLU13HSzDLs7oC4QZdXQHL6SCeab36/logo.png", - "tags": ["wrapped", "wormhole"], - "extensions": { - "address": "0x1f9840a85d5af5bf1d1762f925bdaddc4201f984", - "assetContract": "https://etherscan.io/address/0x1f9840a85d5af5bf1d1762f925bdaddc4201f984", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "uniswap", - "serumV3Usdc": "B7b5rjQuqQCuGqmUBWmcCTqaL3Z1462mo4NArqty6QFR", - "serumV3Usdt": "FrKM6kJtAjXknHPEpkrQtJSXZwUxV5dq26wDpc4YjQST" - } - }, - { - "chainId": 101, - "address": "GXMvfY2jpQctDqZ9RoU3oWPhufKiCcFEfchvYumtX7jd", - "symbol": "SOTOMO", - "name": "Wrapped TOMO (Sollet)", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/GXMvfY2jpQctDqZ9RoU3oWPhufKiCcFEfchvYumtX7jd/logo.png", - "tags": ["wrapped-sollet", "ethereum"], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "coingeckoId": "tomochain", - "serumV3Usdc": "8BdpjpSD5n3nk8DQLqPUyTZvVqFu6kcff5bzUX5dqDpy", - "serumV3Usdt": "GnKPri4thaGipzTbp8hhSGSrHgG4F8MFiZVrbRn16iG2", - "waterfallbot": "https://t.me/TOMOwaterfall" - } - }, - { - "chainId": 101, - "address": "ChVzxWRmrTeSgwd3Ui3UumcN8KX7VK3WaD4KGeSKpypj", - "symbol": "SUSHI", - "name": "SushiToken (Portal)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/ChVzxWRmrTeSgwd3Ui3UumcN8KX7VK3WaD4KGeSKpypj/logo.png", - "tags": ["wrapped", "wormhole"], - "extensions": { - "address": "0x6b3595068778dd592e39a122f4f5a5cf09c90fe2", - "assetContract": "https://etherscan.io/address/0x6b3595068778dd592e39a122f4f5a5cf09c90fe2", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "sushi", - "serumV3Usdc": "3uWVMWu7cwMnYMAAdtsZNwaaqeeeZHARGZwcExnQiFay", - "serumV3Usdt": "T3aC6qcPAJtX1gqkckfSxBPdPWziz5fLYRt5Dz3Nafq" - } - }, - { - "chainId": 101, - "address": "AD27ov5fVU2XzwsbvnFvb1JpCBaCB5dRXrczV9CqSVGb", - "symbol": "REAL", - "name": "Realy Token", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/AD27ov5fVU2XzwsbvnFvb1JpCBaCB5dRXrczV9CqSVGb/logo.svg", - "tags": ["Metaverse", "Governance-token"], - "extensions": { - "serumV3Usdc": "AU8VGwd4NGRbcMz9LT6Fu2LP69LPAbWUJ6gEfEgeYM33", - "telegram": "https://t.me/realyofficial", - "twitter": "https://twitter.com/RealyOfficial", - "website": "https://realy.pro/" - } - }, - { - "chainId": 101, - "address": "GsNzxJfFn6zQdJGeYsupJWzUAm57Ba7335mfhWvFiE9Z", - "symbol": "DXL", - "name": "Dexlab", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/dexlab-project/assets/master/dexlab/dexlab_symbol_logo.svg", - "extensions": { - "coingeckoId": "dexlab", - "serumV3Usdc": "DYfigimKWc5VhavR4moPBibx9sMcWYVSjVdWvPztBPTa", - "twitter": "https://twitter.com/dexlab_official", - "website": "https://www.dexlab.space/" - } - }, - { - "chainId": 101, - "address": "5U9QqCPhqXAJcEv9uyzFJd5zhN93vuPk1aNNkXnUfPnt", - "symbol": "SPWN", - "name": "Bitspawn Token", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/5U9QqCPhqXAJcEv9uyzFJd5zhN93vuPk1aNNkXnUfPnt/logo.png", - "tags": ["utility-token"], - "extensions": { - "coingeckoId": "bitspawn", - "discord": "https://discord.gg/EAtfCq9", - "medium": "https://bitspawnprotocol.medium.com", - "telegram": "https://t.me/bitspawnprotocol", - "twitter": "https://twitter.com/bitspawngg", - "website": "https://bitspawn.io" - } - }, - { - "chainId": 101, - "address": "AkhdZGVbJXPuQZ53u2LrimCjkRP6ZyxG1SoM85T98eE1", - "symbol": "BOT", - "name": "Starbots Token", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/AkhdZGVbJXPuQZ53u2LrimCjkRP6ZyxG1SoM85T98eE1/logo.png", - "tags": ["utility-token", "governance-token", "game-token"], - "extensions": { - "coingeckoId": "starbots", - "twitter": "https://twitter.com/Starbots_game", - "website": "https://starbots.net" - } - }, - { - "chainId": 101, - "address": "4Hx6Bj56eGyw8EJrrheM6LBQAvVYRikYCWsALeTrwyRU", - "symbol": "DYDX", - "name": "dYdX (Portal)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/4Hx6Bj56eGyw8EJrrheM6LBQAvVYRikYCWsALeTrwyRU/logo.png", - "tags": ["wrapped", "ethereum"], - "extensions": { - "address": "0x92d6c1e31e14520e676a687f0a93788b716beff5", - "assetContract": "https://etherscan.io/address/0x92d6c1e31e14520e676a687f0a93788b716beff5", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "dydx", - "serumV3Usdc": "GNmTGd6iQvQApXgsyvHepDpCnvdRPiWzRr8kzFEMMNKN" - } - }, - { - "chainId": 101, - "address": "nosXBVoaCTtYdLvKY6Csb4AC8JCdQKKAaWYtx2ZMoo7", - "symbol": "NOS", - "name": "Nosana", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/nosXBVoaCTtYdLvKY6Csb4AC8JCdQKKAaWYtx2ZMoo7/logo.png", - "extensions": { - "coingeckoId": "nosana", - "discord": "https://discord.gg/nosana", - "github": "https://github.com/nosana-ci", - "medium": "https://nosana.medium.com/", - "telegram": "https://t.me/NosanaCI", - "twitter": "https://twitter.com/nosana_ci", - "website": "https://nosana.io/" - } - }, - { - "chainId": 101, - "address": "HCgybxq5Upy8Mccihrp7EsmwwFqYZtrHrsmsKwtGXLgW", - "symbol": "STARS", - "name": "StarLaunch", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/HCgybxq5Upy8Mccihrp7EsmwwFqYZtrHrsmsKwtGXLgW/logo.png", - "extensions": { - "coingeckoId": "starlaunch", - "telegram": "https://t.me/StarLaunchOfficial", - "twitter": "https://twitter.com/StarLaunchSOL", - "website": "https://www.starlaunch.com/" - } - }, - { - "chainId": 101, - "address": "3bRTivrVsitbmCTGtqwp7hxXPsybkjn4XLNtPsHqa3zR", - "symbol": "LIKE", - "name": "Only1 (LIKE)", - "decimals": 9, - "logoURI": "https://only1.io/like-token.svg", - "tags": ["utility-token"], - "extensions": { - "coingeckoId": "only1", - "discord": "https://discord.gg/SrsKwTFA", - "medium": "https://only1nft.medium.com/", - "telegram": "https://t.me/only1nft", - "twitter": "https://twitter.com/only1nft", - "website": "https://only1.io/" - } - }, - { - "chainId": 101, - "address": "9TE7ebz1dsFo1uQ2T4oYAKSm39Y6fWuHrd6Uk6XaiD16", - "symbol": "MIMO", - "name": "Million Monke", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/9TE7ebz1dsFo1uQ2T4oYAKSm39Y6fWuHrd6Uk6XaiD16/logo.png", - "extensions": { - "discord": "https://discord.com/invite/rznuTnenPJ", - "medium": "https://medium.com/@mimo_3408", - "twitter": "https://twitter.com/MillionMonke", - "website": "https://millionmonke.com/" - } - }, - { - "chainId": 101, - "address": "E5rk3nmgLUuKUiS94gg4bpWwWwyjCMtddsAXkTFLtHEy", - "symbol": "WOO", - "name": "Wootrade Network", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/E5rk3nmgLUuKUiS94gg4bpWwWwyjCMtddsAXkTFLtHEy/logo.png", - "extensions": { - "twitter": "https://twitter.com/wootraderS", - "website": "https://woo.network" - } - }, - { - "chainId": 101, - "address": "9zoqdwEBKWEi9G5Ze8BSkdmppxGgVv1Kw4LuigDiNr9m", - "symbol": "STR", - "name": "Solster", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/9zoqdwEBKWEi9G5Ze8BSkdmppxGgVv1Kw4LuigDiNr9m/logo.png", - "extensions": { - "twitter": "https://twitter.com/solster_finance", - "website": "https://solster.finance" - } - }, - { - "chainId": 101, - "address": "9gP2kCy3wA1ctvYWQk75guqXuHfrEomqydHLtcTCqiLa", - "symbol": "BNB", - "name": "Binance Coin (Portal)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/9gP2kCy3wA1ctvYWQk75guqXuHfrEomqydHLtcTCqiLa/logo.png", - "tags": ["wrapped", "wormhole"], - "extensions": { - "address": "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", - "assetContract": "https://bscscan.com/address/0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", - "bridgeContract": "https://bscscan.com/address/0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7", - "coingeckoId": "binance-coin", - "serumV3Usdc": "4UPUurKveNEJgBqJzqHPyi8DhedvpYsMXi7d43CjAg2f", - "serumV3Usdt": "FjbKNZME5yVSC1R3HJM99kB3yir3q3frS5MteMFD72sV" - } - }, - { - "chainId": 101, - "address": "CN7qFa5iYkHz99PTctvT4xXUHnxwjQ5MHxCuTJtPN5uS", - "symbol": "BOKU", - "name": "Boryoku Dragonz", - "decimals": 9, - "logoURI": "https://boryoku-dragonz-public.s3.us-east-2.amazonaws.com/BokuBrew.png", - "extensions": { - "coingeckoId": "boryoku-dragonz", - "coinmarketcap": "https://coinmarketcap.com/currencies/boku/", - "serumV3Usdc": "Dvm8jjdAy8uyXn9WXjS2p1mcPeFTuYS6yW2eUL9SJE8p", - "twitter": "https://twitter.com/BoryokuDragonz", - "website": "https://boryokudragonz.io" - } - }, - { - "chainId": 101, - "address": "6cVgJUqo4nmvQpbgrDZwyfd6RwWw5bfnCamS3M9N1fd", - "symbol": "SHILL", - "name": "Project SEED Token", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/6cVgJUqo4nmvQpbgrDZwyfd6RwWw5bfnCamS3M9N1fd/logo.png", - "tags": ["projectseedtoken"], - "extensions": { "website": "https://projectseed.io" } - }, - { - "chainId": 101, - "address": "kiNeKo77w1WBEzFFCXrTDRWGRWGP8yHvKC9rX6dqjQh", - "symbol": "KKO", - "name": "Kineko", - "decimals": 9, - "logoURI": "https://kineko.io/img/cat.jpg", - "tags": ["DeFi", "Gaming", "Gambling"] - }, - { - "chainId": 101, - "address": "CobcsUrt3p91FwvULYKorQejgsm5HoQdv5T8RUZ6PnLA", - "symbol": "PEOPLE", - "name": "ConstitutionDAO (Portal)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/CobcsUrt3p91FwvULYKorQejgsm5HoQdv5T8RUZ6PnLA/logo.png", - "tags": ["wrapped", "ethereum"], - "extensions": { - "address": "0x7a58c0be72be218b41c608b7fe7c5bb630736c71", - "assetContract": "https://etherscan.io/address/0x7a58c0be72be218b41c608b7fe7c5bb630736c71", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "constitutiondao", - "serumV3Usdc": "GsWEL352sYgQC3uAVKgEQz2TtA1RA5cgNwUQahyzwJyz" - } - }, - { - "chainId": 101, - "address": "HysWcbHiYY9888pHbaqhwLYZQeZrcQMXKQWRqS7zcPK5", - "symbol": "AXSET", - "name": "Axie Infinity Shard (Portal from Ethereum)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/HysWcbHiYY9888pHbaqhwLYZQeZrcQMXKQWRqS7zcPK5/logo.png", - "tags": ["wrapped", "ethereum"], - "extensions": { - "address": "0xbb0e17ef65f82ab018d8edd776e8dd940327b28b", - "assetContract": "https://etherscan.io/address/0xbb0e17ef65f82ab018d8edd776e8dd940327b28b", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "axie-infinity", - "serumV3Usdc": "HZCheduA4nsSuQpVww1TiyKZpXSAitqaXxjBD2ymg22X" - } - }, - { - "chainId": 101, - "address": "5gs8nf4wojB5EXgDUWNLwXpknzgV2YWDhveAeBZpVLbp", - "symbol": "XTAG", - "name": "xHashtag Token", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/5gs8nf4wojB5EXgDUWNLwXpknzgV2YWDhveAeBZpVLbp/logo.png", - "extensions": { - "twitter": "https://twitter.com/xhashtagio", - "website": "https://www.xhashtag.io/" - } - }, - { - "chainId": 101, - "address": "7zBWymxbZt7PVHQzfi3i85frc1YRiQc23K7bh3gos8ZC", - "symbol": "VI", - "name": "VI", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/7zBWymxbZt7PVHQzfi3i85frc1YRiQc23K7bh3gos8ZC/logo.png", - "tags": [ - "social-token", - "community-token", - "utility-token", - "governance-token" - ], - "extensions": { - "discord": "http://discord.gg/eWVrppgCex", - "telegram": "https://t.me/Vybit_app", - "twitter": "https://twitter.com/vybit_app", - "website": "https://vybit.app" - } - }, - { - "chainId": 101, - "address": "CiKu4eHsVrc1eueVQeHn7qhXTcVu95gSQmBpX4utjL9z", - "symbol": "SHIB", - "name": "SHIBA INU (Portal)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/CiKu4eHsVrc1eueVQeHn7qhXTcVu95gSQmBpX4utjL9z/logo.png", - "tags": ["wrapped", "ethereum"], - "extensions": { - "address": "0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce", - "assetContract": "https://etherscan.io/address/0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "shiba-inu", - "serumV3Usdc": "Er7Jp4PADPVHifykFwbVoHdkL1RtZSsx9zGJrPJTrCgW" - } - }, - { - "chainId": 101, - "address": "EgQ3yNtVhdHz7g1ZhjfGbxhFKMPPaFkz8QHXM5RBZBgi", - "symbol": "AADAI", - "name": "Wrapped DAI (Allbridge from Avalanche)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/FYpdBuyAHSbdaAyD1sKkxyLWbAP8uUW9h6uvdhK74ij1/logo.png", - "tags": ["stablecoin"], - "extensions": { "coingeckoId": "multi-collateral-dai" } - }, - { - "chainId": 101, - "address": "JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1", - "symbol": "SUSDC-9", - "name": "Saber Wrapped USD Coin (9 decimals)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/JEFFSQ3s8T3wKsvp4tnRAsUBW7Cqgnf8ukBZC4C8XBm1/icon.png", - "tags": ["stablecoin", "saber-market-usd", "saber-dec-wrapped"], - "extensions": { - "coingeckoId": "usd-coin", - "website": "https://app.saber.so" - } - }, - { - "chainId": 101, - "address": "8Yv9Jz4z7BUHP68dz8E8m3tMe6NKgpMUKn8KVqrPA6Fr", - "symbol": "AAUSDC", - "name": "Wrapped USDC (Allbridge from Avalanche)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v/logo.png", - "tags": ["stablecoin"], - "extensions": { "coingeckoId": "usd-coin" } - }, - { - "chainId": 101, - "address": "FwEHs3kJEdMa2qZHv7SgzCiFXUQPEycEXksfBkwmS8gj", - "symbol": "AAUSDT", - "name": "Wrapped USDT (Allbridge from Avalanche)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB/logo.svg", - "tags": ["stablecoin"], - "extensions": { "coingeckoId": "tether" } - }, - { - "chainId": 101, - "address": "AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV", - "symbol": "SUSDT-9", - "name": "Saber Wrapped USDT (9 decimals)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/AEUT5uFm1D575FVCoQd5Yq891FJEqkncZUbBFoFcAhTV/icon.png", - "tags": ["stablecoin", "saber-market-usd", "saber-dec-wrapped"], - "extensions": { - "coingeckoId": "tether", - "website": "https://app.saber.so" - } - }, - { - "chainId": 101, - "address": "Fd8xyHHRjTvxfZrBirb6MaxSmrZYw99gRSqFUKdFwFvw", - "symbol": "AAWBTC", - "name": "Wrapped BTC (Allbridge from Avalanche)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/qfnqNqs3nCAHjnyCgLRDbBtq4p2MtHZxw8YjSyYhPoL/logo.png", - "extensions": { "coingeckoId": "wrapped-bitcoin" } - }, - { - "chainId": 101, - "address": "FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5", - "symbol": "SRENBTC-9", - "name": "Saber Wrapped renBTC (9 decimals)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/FACTQhZBfRzC7A76antnpAoZtiwYmUfdAN8wz7e8rxC5/icon.png", - "tags": ["saber-market-btc", "saber-dec-wrapped"], - "extensions": { - "coingeckoId": "renbtc", - "website": "https://app.saber.so" - } - }, - { - "chainId": 101, - "address": "3os2M3bX9qta154PRbU9rzaPUYAKAqVpaMMS8u2hoUQu", - "symbol": "ABBTCB", - "name": "Wrapped BTC (Allbridge from BSC)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/qfnqNqs3nCAHjnyCgLRDbBtq4p2MtHZxw8YjSyYhPoL/logo.png", - "extensions": { "coingeckoId": "wrapped-bitcoin" } - }, - { - "chainId": 101, - "address": "6nuaX3ogrr2CaoAPjtaKHAoBNWok32BMcRozuf32s2QF", - "symbol": "ABBUSD", - "name": "Wrapped BUSD (Allbridge from BSC)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/AJ1W9A9N9dEMdVyoDiam2rV44gnBm2csrPDP7xqcapgX/logo.png", - "tags": ["stablecoin"], - "extensions": { "coingeckoId": "binance-usd" } - }, - { - "chainId": 101, - "address": "EyrnrbE5ujd3HQG5PZd9MbECN9yaQrqc8pRwGtaLoyC", - "symbol": "ABETH", - "name": "Wrapped ETH (Allbridge from BSC)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/FeGn77dhg1KXRRFeSwwMiykZnZPw5JXW6naf2aQgZDQf/logo.png", - "extensions": { "coingeckoId": "weth" } - }, - { - "chainId": 101, - "address": "KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma", - "symbol": "SWHETH-9", - "name": "Saber Wrapped Ether (Portal) (9 decimals)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/KNVfdSJyq1pRQk9AKKv1g5uyGuk6wpm4WG16Bjuwdma/icon.png", - "tags": ["saber-market-eth", "wormhole-v2", "saber-dec-wrapped"], - "extensions": { - "coingeckoId": "ethereum", - "website": "https://app.saber.so" - } - }, - { - "chainId": 101, - "address": "8XSsNvaKU9FDhYWAv7Yc7qSNwuJSzVrXBNEk7AFiWF69", - "symbol": "ABUSDC", - "name": "Wrapped USDC (Allbridge from BSC)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/BXXkv6z8ykpG1yuvUDPgh732wzVHB69RnB9YgSYh3itW/logo.png", - "tags": ["stablecoin"], - "extensions": { "coingeckoId": "usd-coin" } - }, - { - "chainId": 101, - "address": "E77cpQ4VncGmcAXX16LHFFzNBEBb2U7Ar7LBmZNfCgwL", - "symbol": "ABUSDT", - "name": "Wrapped USDT (Allbridge from BSC)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/BQcdHdAQW1hczDbBi9hiegXAR7A98Q9jx3X3iBBBDiq4/logo.png", - "tags": ["stablecoin"], - "extensions": { "coingeckoId": "tether" } - }, - { - "chainId": 101, - "address": "7g166TuBmnoHKvS2PEkZx6kREZtbfjUxCHGWjCqoDXZv", - "symbol": "ACEUR", - "name": "Wrapped CEUR (Allbridge from Celo)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/7g166TuBmnoHKvS2PEkZx6kREZtbfjUxCHGWjCqoDXZv/logo.png", - "tags": ["stablecoin"] - }, - { - "chainId": 101, - "address": "EU9aLffrTckFCs16da6CppHy63fAxMPF9ih1erQTuuRt", - "symbol": "SAGEUR-9", - "name": "Saber Wrapped agEUR (Portal) (9 decimals)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EU9aLffrTckFCs16da6CppHy63fAxMPF9ih1erQTuuRt/icon.png", - "tags": [ - "ethereum", - "wrapped", - "wormhole", - "saber-mkt-eur", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "address": "0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "ageur", - "description": "Angle is the first decentralized, capital efficient and over-collateralized stablecoin protocol", - "discord": "https://discord.gg/z3kCpTaKMh", - "twitter": "https://twitter.com/AngleProtocol", - "website": "https://app.saber.so" - } - }, - { - "chainId": 101, - "address": "CbNYA9n3927uXUukee2Hf4tm3xxkffJPPZvGazc2EAH1", - "symbol": "AGEUR", - "name": "agEUR (Portal)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/CbNYA9n3927uXUukee2Hf4tm3xxkffJPPZvGazc2EAH1/logo.png", - "tags": ["ethereum", "wrapped", "wormhole"], - "extensions": { - "address": "0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8", - "assetContract": "https://etherscan.io/address/0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "ageur", - "description": "Angle is the first decentralized, capital efficient and over-collateralized stablecoin protocol", - "discord": "https://discord.gg/z3kCpTaKMh", - "twitter": "https://twitter.com/AngleProtocol", - "website": "https://www.angle.money" - } - }, - { - "chainId": 101, - "address": "EwxNF8g9UfmsJVcZFTpL9Hx5MCkoQFoJi6XNWzKf1j8e", - "symbol": "ACUSD", - "name": "Wrapped CUSD (Allbridge from Celo)", - "decimals": 9, - "logoURI": "https://s2.coinmarketcap.com/static/img/coins/64x64/7236.png", - "tags": ["stablecoin"], - "extensions": { "coingeckoId": "celo-dollar" } - }, - { - "chainId": 101, - "address": "C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi", - "symbol": "SCASH-9", - "name": "Saber Wrapped CASH (9 decimals)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/C9xqJe3gMTUDKidZsZ6jJ7tL9zSLimDUKVpgUbLZnNbi/icon.png", - "tags": ["stablecoin", "saber-market-usd", "saber-dec-wrapped"], - "extensions": { - "coingeckoId": "usd-coin", - "website": "https://app.saber.so" - } - }, - { - "chainId": 101, - "address": "CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT", - "symbol": "CASH", - "name": "Cashio Dollar", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/CASHVDm2wsJXfhj6VWxb7GiMdoLc17Du7paH4bNr5woT/icon.png", - "tags": ["stablecoin"], - "extensions": { - "coingeckoId": "cashio-dollar", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "medium": "https://medium.com/@cashioapp", - "twitter": "https://twitter.com/CashioApp", - "website": "https://cashio.app" - } - }, - { - "chainId": 101, - "address": "DHpoYejUDqzByb6HAdaLWF7KZvwUv2vWYDY9cTENNZui", - "symbol": "ACUSDC", - "name": "Wrapped USDC (Allbridge from Celo)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v/logo.png", - "tags": ["stablecoin"], - "extensions": { "coingeckoId": "usd-coin" } - }, - { - "chainId": 101, - "address": "9w6LpS7RU1DKftiwH3NgShtXbkMM1ke9iNU4g3MBXSUs", - "symbol": "AEDAI", - "name": "Wrapped DAI (Allbridge from Ethereum)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/FYpdBuyAHSbdaAyD1sKkxyLWbAP8uUW9h6uvdhK74ij1/logo.png", - "tags": ["stablecoin"], - "extensions": { "coingeckoId": "multi-collateral-dai" } - }, - { - "chainId": 101, - "address": "AaAEw2VCw1XzgvKB8Rj2DyK2ZVau9fbt2bE8hZFWsMyE", - "symbol": "AEWETH", - "name": "Wrapped ETH (Allbridge from Ethereum)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/FeGn77dhg1KXRRFeSwwMiykZnZPw5JXW6naf2aQgZDQf/logo.png", - "tags": ["stablecoin"], - "extensions": { "coingeckoId": "weth" } - }, - { - "chainId": 101, - "address": "DdFPRnccQqLD4zCHrBqdY95D6hvw6PLWp9DEXj1fLCL9", - "symbol": "AEUSDC", - "name": "Wrapped USDC (Allbridge from Ethereum)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v/logo.png", - "tags": ["stablecoin"], - "extensions": { "coingeckoId": "usd-coin" } - }, - { - "chainId": 101, - "address": "Bn113WT6rbdgwrm12UJtnmNqGqZjY4it2WoUQuQopFVn", - "symbol": "AEUSDT", - "name": "Wrapped USDT (Allbridge from Ethereum)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB/logo.svg", - "tags": ["stablecoin"], - "extensions": { "coingeckoId": "tether" } - }, - { - "chainId": 101, - "address": "FdvkkCbCgYht1xTR1W9MBJhEF1JEPVhHtW1NXBYRzZts", - "symbol": "AFBTC", - "name": "Wrapped BTC (Allbridge from Fantom)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/qfnqNqs3nCAHjnyCgLRDbBtq4p2MtHZxw8YjSyYhPoL/logo.png", - "extensions": { "coingeckoId": "wrapped-bitcoin" } - }, - { - "chainId": 101, - "address": "HjUhUzi6fVkY1BndaSc4Dcg2mCzvnqzXjVJtXsj78ver", - "symbol": "AFDAI", - "name": "Wrapped DAI (Allbridge from Fantom)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/FYpdBuyAHSbdaAyD1sKkxyLWbAP8uUW9h6uvdhK74ij1/logo.png", - "tags": ["stablecoin"], - "extensions": { "coingeckoId": "dai" } - }, - { - "chainId": 101, - "address": "BiryxNvVTABRs3pEE4fvVuu4d17aAYEsNmcPnJ8E8WeT", - "symbol": "AFETH", - "name": "Wrapped ETH (Allbridge from Fantom)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/FeGn77dhg1KXRRFeSwwMiykZnZPw5JXW6naf2aQgZDQf/logo.png", - "extensions": { "coingeckoId": "weth" } - }, - { - "chainId": 101, - "address": "Grk6b4UMRWkgyq4Y6S1BnNRF4hRgtnMFp7Sorkv6Ez4u", - "symbol": "AFUSDC", - "name": "Wrapped USDC (Allbridge from Fantom)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/BXXkv6z8ykpG1yuvUDPgh732wzVHB69RnB9YgSYh3itW/logo.png", - "tags": ["stablecoin"], - "extensions": { "coingeckoId": "usd-coin" } - }, - { - "chainId": 101, - "address": "GfzU1fLASNV3r4NtEyrnwTyTakJkYzoivnaL3Snh45oj", - "symbol": "AHUSDT", - "name": "Wrapped USDT (Allbridge from HECO)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/GfzU1fLASNV3r4NtEyrnwTyTakJkYzoivnaL3Snh45oj/logo.png", - "tags": ["stablecoin"], - "extensions": { "coingeckoId": "tether" } - }, - { - "chainId": 101, - "address": "Bo4ehCeRcRj2wp5tQpjfCJxYFn4KyRacfDzSa4Aj27tH", - "symbol": "AHBTC", - "name": "Wrapped BTC (Allbridge from HECO)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Bo4ehCeRcRj2wp5tQpjfCJxYFn4KyRacfDzSa4Aj27tH/logo.png", - "tags": ["stablecoin"], - "extensions": { "coingeckoId": "wrapped-bitcoin" } - }, - { - "chainId": 101, - "address": "eqKJTf1Do4MDPyKisMYqVaUFpkEFAs3riGF3ceDH2Ca", - "symbol": "APUSDC", - "name": "Wrapped USDC (Allbridge from Polygon)", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/BXXkv6z8ykpG1yuvUDPgh732wzVHB69RnB9YgSYh3itW/logo.png", - "tags": ["stablecoin"], - "extensions": { "coingeckoId": "usd-coin" } - }, - { - "chainId": 101, - "address": "DNhZkUaxHXYvpxZ7LNnHtss8sQgdAfd1ZYS1fB7LKWUZ", - "symbol": "APUSDT", - "name": "Wrapped USDT (Allbridge from Polygon)", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/BQcdHdAQW1hczDbBi9hiegXAR7A98Q9jx3X3iBBBDiq4/logo.png", - "tags": ["stablecoin"], - "extensions": { "coingeckoId": "tether" } - }, - { - "chainId": 101, - "address": "ASoLXbfe7cd6igh5yiEsU8M7FW64QRxPKkxk7sjAfond", - "symbol": "ASOL", - "name": "aSOL Aggregate Solana Stake Pool", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/ASoLXbfe7cd6igh5yiEsU8M7FW64QRxPKkxk7sjAfond/logo.svg", - "extensions": { - "coingeckoId": "solana", - "description": "aSOL is the standard for transacting with staked SOL tokens.", - "github": "https://github.com/aSolHQ", - "twitter": "https://twitter.com/aSOLprotocol", - "website": "https://asol.so" - } - }, - { - "chainId": 101, - "address": "A96PoNcxa9LMxcF9HhKAfA1p3M1dGbubPMWf19gHAkgJ", - "symbol": "ATUST", - "name": "Wrapped UST (Allbridge from Terra)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/CXLBjMMcwkc17GfJtBos6rQCo1ypeH6eDbB82Kby4MRm/logo.png", - "tags": ["stablecoin"] - }, - { - "chainId": 101, - "address": "3LKZU3iQx9KM94S4uYRdYwAHTm6odDyzGQqTBNj7J27z", - "symbol": "ATLUNA", - "name": "Wrapped Luna (Allbridge from Terra)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/2Xf2yAXJfg82sWwdLUo2x9mZXy6JCdszdMZkcF1Hf4KV/logo.png" - }, - { - "chainId": 101, - "address": "LUNGEjUXyP48nrC1GYY5o4eTAkwm4RdX8BxFUxWJBLB", - "symbol": "SLUNA-9", - "name": "Saber Wrapped LUNA (Portal) (9 decimals)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/LUNGEjUXyP48nrC1GYY5o4eTAkwm4RdX8BxFUxWJBLB/icon.png", - "tags": [ - "wrapped", - "wormhole", - "saber-mkt-luna", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "address": "uluna", - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "coingeckoId": "terra-luna", - "serumV3Usdc": "HBTu8hNaoT3VyiSSzJYa8jwt9sDGKtJviSwFa11iXdmE", - "website": "https://app.saber.so" - } - }, - { - "chainId": 101, - "address": "9QBTKuSCDaJjtxYnYcVzoiKENMdJ5DRei5ZUCEeWyZnj", - "symbol": "WTRYB", - "name": "BiLira (Portal)", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/9QBTKuSCDaJjtxYnYcVzoiKENMdJ5DRei5ZUCEeWyZnj/logo.png", - "tags": ["stablecoin", "wormhole", "wrapped"], - "extensions": { - "address": "0x2c537e5624e4af88a7ae4060c022609376c8d0eb", - "assetContract": "https://etherscan.io/token/0x2c537e5624e4af88a7ae4060c022609376c8d0eb", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "github": "https://github.com/bilira-org", - "instagram": "https://instagram.com/bilira_official", - "telegram": "https://t.me/BiLira_Official", - "website": "http://bilira.co" - } - }, - { - "chainId": 101, - "address": "A94X2fRy3wydNShU4dRaDyap2UuoeWJGWyATtyp61WZf", - "symbol": "TRYB", - "name": "BiLira", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/A94X2fRy3wydNShU4dRaDyap2UuoeWJGWyATtyp61WZf/logo.png", - "tags": ["tryb", "bilira", "stablecoin"], - "extensions": { - "coingeckoId": "bilira", - "github": "https://github.com/bilira-org", - "instagram": "https://instagram.com/bilira_official", - "telegram": "https://t.me/BiLira_Official", - "website": "http://bilira.co" - } - }, - { - "chainId": 101, - "address": "bSo13r4TkiE4KumL71LsHTPpL2euBYLFx6h9HP3piy1", - "symbol": "BSOL", - "name": "BlazeStake Staked SOL (bSOL)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/bSo13r4TkiE4KumL71LsHTPpL2euBYLFx6h9HP3piy1/logo.png", - "tags": ["utility-token", "stake-pool", "stake-pool-token"], - "extensions": { - "github": "https://github.com/SolBlazeOrg", - "twitter": "https://twitter.com/solblaze_org", - "website": "https://stake.solblaze.org/" - } - }, - { - "chainId": 101, - "address": "SBTCB6pWqeDo6zGi9WVRMLCsKsN6JiR1RMUqvLtgSRv", - "symbol": "SBTC-8", - "name": "Saber Wrapped Bitcoin (Sollet) (8 decimals)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/SBTCB6pWqeDo6zGi9WVRMLCsKsN6JiR1RMUqvLtgSRv/icon.png", - "tags": [ - "wrapped-sollet", - "ethereum", - "saber-market-btc", - "saber-dec-wrapped" - ], - "extensions": { - "coingeckoId": "bitcoin", - "website": "https://app.saber.so" - } - }, - { - "chainId": 101, - "address": "AJ1W9A9N9dEMdVyoDiam2rV44gnBm2csrPDP7xqcapgX", - "symbol": "WBUSD_V1", - "name": "Binance USD (Wormhole v1)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/AJ1W9A9N9dEMdVyoDiam2rV44gnBm2csrPDP7xqcapgX/logo.png", - "tags": ["wrapped", "wormhole"], - "extensions": { - "address": "0x4Fabb145d64652a948d72533023f6E7A623C7C53", - "assetContract": "https://etherscan.io/address/0x4Fabb145d64652a948d72533023f6E7A623C7C53", - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "coingeckoId": "binance-usd" - } - }, - { - "chainId": 101, - "address": "CALusHembJf3tQ69BxFbLRUSpGRwKzEnLKWUPhQo5dFk", - "symbol": "CALUSD", - "name": "calUSD Stablecoin", - "decimals": 9, - "logoURI": "https://user-images.githubusercontent.com/8619106/167318344-e9ea9147-8969-4818-877c-5c75de10aecc.png", - "tags": ["stablecoin"], - "extensions": { - "discord": "https://discord.com/invite/Me2zTTdQpu", - "medium": "https://medium.com/@CalciferFinance", - "twitter": "https://twitter.com/CalciferFi", - "website": "https://calcifer.fi/" - } - }, - { - "chainId": 101, - "address": "FYpdBuyAHSbdaAyD1sKkxyLWbAP8uUW9h6uvdhK74ij1", - "symbol": "WDAI_V1", - "name": "Dai Stablecoin (Wormhole v1)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/FYpdBuyAHSbdaAyD1sKkxyLWbAP8uUW9h6uvdhK74ij1/logo.png", - "tags": ["wrapped", "wormhole"], - "extensions": { - "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", - "assetContract": "https://etherscan.io/address/0x6B175474E89094C44Da98b954EedeAC495271d0F", - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "coingeckoId": "dai" - } - }, - { - "chainId": 101, - "address": "Hg35Vd8K3BS2pLB3xwC2WqQV8pmpCm3oNRGYP1PEpmCM", - "symbol": "ESOL", - "name": "EverSOL staked SOL (eSOL)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Hg35Vd8K3BS2pLB3xwC2WqQV8pmpCm3oNRGYP1PEpmCM/logo.png", - "extensions": { - "medium": "https://medium.com/everstake", - "twitter": "https://twitter.com/everstake_pool", - "website": "https://everstake.one" - } - }, - { - "chainId": 101, - "address": "88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy", - "symbol": "SUSDC-8", - "name": "Saber Wrapped USD Coin (8 decimals)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/88881Hu2jGMfCs9tMu5Rr7Ah7WBNBuXqde4nR5ZmKYYy/icon.png", - "tags": ["stablecoin", "saber-market-usd", "saber-dec-wrapped"], - "extensions": { - "coingeckoId": "usd-coin", - "website": "https://app.saber.so" - } - }, - { - "chainId": 101, - "address": "B7mXkkZgn7abwz1A3HnKkb18Y6y18WcbeSkh1DuLMkee", - "symbol": "FUSD", - "name": "Synthetic USD (Fabric)", - "decimals": 8, - "logoURI": "https://imagedelivery.net/9NaZ0y3QBjls8_Ib2N2gQw/ec3521b6-b382-4efb-1d16-7b60c75b9100/public", - "tags": ["fabric", "synthetics"], - "extensions": { - "github": "https://github.com/fabric-foundation/", - "medium": "https://xfabric.medium.com/", - "twitter": "https://twitter.com/official_fabric", - "website": "https://app.fsynth.io/" - } - }, - { - "chainId": 101, - "address": "BAexggGFsiLCKr17cSZF12wkHd8BkR1DBhzuSb78WTR2", - "symbol": "AEFEI", - "name": "Wrapped FEI (Allbridge from Ethereum)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/BAexggGFsiLCKr17cSZF12wkHd8BkR1DBhzuSb78WTR2/logo.png", - "extensions": { "coingeckoId": "fei-usd" } - }, - { - "chainId": 101, - "address": "UST98bfV6EASdTFQrRwCBczpehdMFwYCUdLT5tEbhpW", - "symbol": "SWTUST-9", - "name": "Saber Wrapped UST (Portal) (9 decimals)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/UST98bfV6EASdTFQrRwCBczpehdMFwYCUdLT5tEbhpW/icon.png", - "tags": [ - "wrapped", - "wormhole", - "saber-mkt-usd", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "address": "uusd", - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "coingeckoId": "terra-usd", - "website": "https://app.saber.so" - } - }, - { - "chainId": 101, - "address": "8L8pDf3jutdpdr4m3np68CL9ZroLActrqwxi6s9Ah5xU", - "symbol": "WFRAX_V1", - "name": "Frax (Wormhole v1)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/8L8pDf3jutdpdr4m3np68CL9ZroLActrqwxi6s9Ah5xU/logo.png", - "tags": ["wrapped", "wormhole"], - "extensions": { - "address": "0x853d955aCEf822Db058eb8505911ED77F175b99e", - "assetContract": "https://etherscan.io/address/0x853d955aCEf822Db058eb8505911ED77F175b99e", - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "coingeckoId": "frax" - } - }, - { - "chainId": 101, - "address": "FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp", - "symbol": "FRAX", - "name": "Frax (Portal)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/FR87nWEUxVgerFGhZM8Y4AggKGLnaXswr1Pd8wZ4kZcp/logo.png", - "tags": ["wrapped", "wormhole"], - "extensions": { - "address": "0x853d955acef822db058eb8505911ed77f175b99e", - "assetContract": "https://etherscan.io/address/0x853d955acef822db058eb8505911ed77f175b99e", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "frax" - } - }, - { - "chainId": 101, - "address": "CASHedBw9NfhsLBXq1WNVfueVznx255j8LLTScto3S6s", - "symbol": "SCASH-8", - "name": "Saber Wrapped Cashio Dollar (8 decimals)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/CASHedBw9NfhsLBXq1WNVfueVznx255j8LLTScto3S6s/icon.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "coingeckoId": "usd-coin", - "discord": "https://discord.com/invite/GmkRRKJkuh", - "medium": "https://medium.com/@cashioapp", - "twitter": "https://twitter.com/CashioApp", - "website": "https://app.saber.so" - } - }, - { - "chainId": 101, - "address": "UST8SCn7jrqsq51odVLqcmvnC658HkqrKrPL3w2hHQ7", - "symbol": "SUST-8", - "name": "Saber Wrapped UST (Portal) (8 decimals)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/UST8SCn7jrqsq51odVLqcmvnC658HkqrKrPL3w2hHQ7/icon.png", - "tags": [ - "wrapped", - "wormhole", - "saber-mkt-usd", - "wormhole-v2", - "saber-dec-wrapped" - ], - "extensions": { - "address": "uusd", - "bridgeContract": "https://finder.terra.money/columbus-5/address/terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf", - "coingeckoId": "terra-usd", - "website": "https://app.saber.so" - } - }, - { - "chainId": 101, - "address": "GbBWwtYTMPis4VHb8MrBbdibPhn28TSrLB53KvUmb7Gi", - "symbol": "WFTT_V1", - "name": "FTT (Wormhole v1)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/GbBWwtYTMPis4VHb8MrBbdibPhn28TSrLB53KvUmb7Gi/logo.png", - "tags": ["wrapped", "wormhole"], - "extensions": { - "address": "0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "assetContract": "https://etherscan.io/address/0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "coingeckoId": "ftx-token" - } - }, - { - "chainId": 101, - "address": "FTT9rBBrYwcHam4qLvkzzzhrsihYMbZ3k6wJbdoahxAt", - "symbol": "SFTT-9", - "name": "Saber Wrapped Wrapped FTT (Sollet) (9 decimals)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/FTT9rBBrYwcHam4qLvkzzzhrsihYMbZ3k6wJbdoahxAt/icon.png", - "tags": [ - "wrapped-sollet", - "ethereum", - "saber-market-ftt", - "saber-dec-wrapped" - ], - "extensions": { - "coingeckoId": "ftx-token", - "website": "https://app.saber.so" - } - }, - { - "chainId": 101, - "address": "8pBc4v9GAwCBNWPB5XKA93APexMGAS4qMr37vNke9Ref", - "symbol": "WHBTC_V1", - "name": "HBTC (Wormhole v1)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/8pBc4v9GAwCBNWPB5XKA93APexMGAS4qMr37vNke9Ref/logo.png", - "tags": ["wrapped", "wormhole"], - "extensions": { - "address": "0x0316EB71485b0Ab14103307bf65a021042c6d380", - "assetContract": "https://etherscan.io/address/0x0316EB71485b0Ab14103307bf65a021042c6d380", - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "coingeckoId": "huobi-btc" - } - }, - { - "chainId": 101, - "address": "BybpSTBoZHsmKnfxYG47GDhVPKrnEKX31CScShbrzUhX", - "symbol": "WHUSD_V1", - "name": "HUSD Stablecoin (Wormhole v1)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/BybpSTBoZHsmKnfxYG47GDhVPKrnEKX31CScShbrzUhX/logo.png", - "tags": ["wrapped", "wormhole"], - "extensions": { - "address": "0xdf574c24545e5ffecb9a659c229253d4111d87e1", - "assetContract": "https://etherscan.io/address/0xdf574c24545e5ffecb9a659c229253d4111d87e1", - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "coingeckoId": "husd", - "website": "https://www.stcoins.com/" - } - }, - { - "chainId": 101, - "address": "9999j2A8sXUtHtDoQdk528oVzhaKBsXyRGZ67FKGoi7H", - "symbol": "SBTC-9", - "name": "Saber Wrapped Bitcoin (Sollet) (9 decimals)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/9999j2A8sXUtHtDoQdk528oVzhaKBsXyRGZ67FKGoi7H/icon.png", - "tags": [ - "wrapped-sollet", - "ethereum", - "saber-market-btc", - "saber-dec-wrapped" - ], - "extensions": { - "coingeckoId": "bitcoin", - "website": "https://app.saber.so" - } - }, - { - "chainId": 101, - "address": "2Xf2yAXJfg82sWwdLUo2x9mZXy6JCdszdMZkcF1Hf4KV", - "symbol": "WLUNA_V1", - "name": "Wrapped LUNA Token (Wormhole v1)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/2Xf2yAXJfg82sWwdLUo2x9mZXy6JCdszdMZkcF1Hf4KV/logo.png", - "tags": ["wrapped", "wormhole"], - "extensions": { - "address": "0xd2877702675e6cEb975b4A1dFf9fb7BAF4C91ea9", - "assetContract": "https://etherscan.io/address/0xd2877702675e6cEb975b4A1dFf9fb7BAF4C91ea9", - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "coingeckoId": "wrapped-terra" - } - }, - { - "chainId": 101, - "address": "KUANeD8EQvwpT1W7QZDtDqctLEh2FfSTy5pThE9CogT", - "symbol": "SRENLUNA-9", - "name": "Saber Wrapped renLUNA (9 decimals)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/KUANeD8EQvwpT1W7QZDtDqctLEh2FfSTy5pThE9CogT/icon.png", - "tags": ["saber-market-luna", "saber-dec-wrapped"], - "extensions": { "website": "https://app.saber.so" } - }, - { - "chainId": 101, - "address": "8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE", - "symbol": "RENLUNA", - "name": "renLUNA", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/8wv2KAykQstNAj2oW6AHANGBiFKVFhvMiyyzzjhkmGvE/logo.png", - "extensions": { - "serumV3Usdc": "CxDhLbbM9uAA2AXfSPar5qmyfmC69NLj3vgJXYAsSVBT", - "website": "https://renproject.io/" - } - }, - { - "chainId": 101, - "address": "9mWRABuz2x6koTPCWiCPM49WUbcrNqGTHBV9T9k7y1o7", - "symbol": "MAI", - "name": "MAI Stablecoin", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/0xlaozi/qidao/main/images/mimatic-red.png", - "tags": ["stablecoin"], - "extensions": { - "discord": "https://discord.com/invite/mQq55j65xJ", - "twitter": "https://twitter.com/QiDaoProtocol", - "website": "https://mai.finance/" - } - }, - { - "chainId": 101, - "address": "2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj", - "symbol": "AEMIM", - "name": "Wrapped MIM (Allbridge from Ethereum)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/2ASbApnFVSTp2RJvMLgLVfbDwJvu1FRXdhJWrGs89Lhj/logo.png", - "extensions": { "coingeckoId": "magic-internet-money" } - }, - { - "chainId": 101, - "address": "NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa", - "symbol": "NIRV", - "name": "NIRV", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/NRVwhjBQiUPYtfDT5zRBVJajzFQHaBUNtC7SNVvqRFa/NIRV.png", - "tags": ["currency"], - "extensions": { - "twitter": "https://twitter.com/nirvana_fi", - "website": "https://nirvana.finance/" - } - }, - { - "chainId": 101, - "address": "USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX", - "symbol": "USDH", - "name": "USDH Hubble Stablecoin", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/USDH1SM1ojwWUga67PGrgFWUHibbjqMvuMaDkRJTgkX/usdh.svg", - "tags": ["stablecoin"], - "extensions": { - "coingeckoId": "usdh", - "discord": "https://discord.gg/d44A8WvK", - "twitter": "https://twitter.com/hubbleprotocol", - "website": "https://hubbleprotocol.io/" - } - }, - { - "chainId": 101, - "address": "DYDWu4hE4MN3aH897xQ3sRTs5EAjJDmQsKLNhbpUiKun", - "symbol": "PBTC", - "name": "pBTC (Parrot BTC)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/DYDWu4hE4MN3aH897xQ3sRTs5EAjJDmQsKLNhbpUiKun/logo.svg", - "tags": ["stablecoin"], - "extensions": { - "discord": "https://discord.gg/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "telegram": "https://t.me/gopartyparrot", - "twitter": "https://twitter.com/gopartyparrot", - "website": "https://parrot.fi" - } - }, - { - "chainId": 101, - "address": "3RudPTAkfcq9Q9Jk8SVeCoecCBmdKMj6q5smsWzxqtqZ", - "symbol": "PUSDT", - "name": "Port Finance USDT", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/3RudPTAkfcq9Q9Jk8SVeCoecCBmdKMj6q5smsWzxqtqZ/USDT.svg", - "tags": ["port", "lending", "collateral-tokens"], - "extensions": { "website": "https://port.finance" } - }, - { - "chainId": 101, - "address": "FgSsGV8GByPaMERxeQJPvZRZHf7zCBhrdYtztKorJS58", - "symbol": "PUSDC", - "name": "Port Finance USDC", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/FgSsGV8GByPaMERxeQJPvZRZHf7zCBhrdYtztKorJS58/USDC.svg", - "tags": ["port", "lending", "collateral-tokens"], - "extensions": { "website": "https://port.finance" } - }, - { - "chainId": 101, - "address": "BdZPG9xWrG3uFrx2KrUW1jT4tZ9VKPDWknYihzoPRJS3", - "symbol": "PRTSOL", - "name": "prtSOL (Parrot Staked SOL)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/BdZPG9xWrG3uFrx2KrUW1jT4tZ9VKPDWknYihzoPRJS3/logo.svg", - "extensions": { - "discord": "https://discord.gg/gopartyparrot", - "medium": "https://gopartyparrot.medium.com/", - "telegram": "https://t.me/gopartyparrot", - "twitter": "https://twitter.com/gopartyparrot", - "website": "https://parrot.fi" - } - }, - { - "chainId": 101, - "address": "5h6ssFpeDeRbzsEHDbTQNH7nVGgsKrZydxdSTnLm6QdV", - "symbol": "CSOL", - "name": "Solend SOL", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/5h6ssFpeDeRbzsEHDbTQNH7nVGgsKrZydxdSTnLm6QdV/logo.png", - "tags": ["solend", "lending", "collateral-tokens"], - "extensions": { "website": "https://solend.fi" } - }, - { - "chainId": 101, - "address": "3JFC4cB56Er45nWVe29Bhnn5GnwQzSmHVf6eUq9ac91h", - "symbol": "CMSOL", - "name": "Solend mSOL", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/3JFC4cB56Er45nWVe29Bhnn5GnwQzSmHVf6eUq9ac91h/logo.png", - "tags": ["solend", "lending", "collateral-tokens"], - "extensions": { "website": "https://solend.fi" } - }, - { - "chainId": 101, - "address": "993dVFL2uXWYeoXuEBFXR4BijeXdTv4s6BzsCjJZuwqk", - "symbol": "CUSDC", - "name": "Solend USDC", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/993dVFL2uXWYeoXuEBFXR4BijeXdTv4s6BzsCjJZuwqk/logo.png", - "tags": ["solend", "lending", "collateral-tokens"], - "extensions": { "website": "https://solend.fi" } - }, - { - "chainId": 101, - "address": "BTsbZDV7aCMRJ3VNy9ygV4Q2UeEo9GpR8D6VvmMZzNr8", - "symbol": "CUSDT", - "name": "Solend USDT", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/BTsbZDV7aCMRJ3VNy9ygV4Q2UeEo9GpR8D6VvmMZzNr8/logo.png", - "tags": ["solend", "lending", "collateral-tokens"], - "extensions": { "website": "https://solend.fi" } - }, - { - "chainId": 101, - "address": "FTT8cGNp3rfTC6c44uPTuEFLqmsVDhjd2BhH65v2uppr", - "symbol": "SSOFTT-8", - "name": "Saber Wrapped Wrapped FTT (Sollet) (8 decimals)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/FTT8cGNp3rfTC6c44uPTuEFLqmsVDhjd2BhH65v2uppr/icon.png", - "tags": [ - "wrapped-sollet", - "ethereum", - "saber-mkt-ftt", - "saber-dec-wrapped" - ], - "extensions": { - "bridgeContract": "https://etherscan.io/address/0xeae57ce9cc1984f202e15e038b964bb8bdf7229a", - "coingeckoId": "ftx-token", - "serumV3Usdc": "2Pbh1CvRVku1TgewMfycemghf6sU9EyuFDcNXqvRmSxc", - "serumV3Usdt": "Hr3wzG8mZXNHV7TuL6YqtgfVUesCqMxGYCEyP3otywZE", - "waterfallbot": "https://bit.ly/FTTwaterfall", - "website": "https://app.saber.so" - } - }, - { - "chainId": 101, - "address": "EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv", - "symbol": "FTT", - "name": "FTX Token (Portal)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EzfgjvkSwthhgHaceR3LnKXUoRkP6NUhfghdaHAj1tUv/logo.png", - "tags": ["wrapped", "wormhole"], - "extensions": { - "address": "0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "assetContract": "https://etherscan.io/address/0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "ftx-token", - "serumV3Usdc": "2wteg25ch227n4Rh1CN4WNrDZXBpRBpWJ48mEC2K7f4r", - "serumV3Usdt": "BoHojHESAv4McZx9gXd1bWTZMq25JYyGz4qL1m5C3nvk" - } - }, - { - "chainId": 101, - "address": "JAa3gQySiTi8tH3dpkvgztJWHQC1vGXr5m6SQ9LEM55T", - "symbol": "SOLUST", - "name": "solUST", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/JAa3gQySiTi8tH3dpkvgztJWHQC1vGXr5m6SQ9LEM55T/solust.svg", - "tags": ["stablecoin"], - "extensions": { "website": "https://soluna.money/" } - }, - { - "chainId": 101, - "address": "9iLH8T7zoWhY7sBmj1WK9ENbWdS1nL8n9wAxaeRitTa6", - "symbol": "USH", - "name": "Hedge USD", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/9iLH8T7zoWhY7sBmj1WK9ENbWdS1nL8n9wAxaeRitTa6/logo.png", - "tags": ["stablecoin"], - "extensions": { - "discord": "https://discord.gg/hedge", - "serumV3Usdc": "6aRwQtvTcHeRTtGxQRhqViwMF1XPEn271CgGEx3YAyEY", - "twitter": "https://twitter.com/HedgeLabs", - "website": "https://www.hedge.so/" - } - }, - { - "chainId": 101, - "address": "PUhuAtMHsKavMTwZsLaDeKy2jb7ciETHJP7rhbKLJGY", - "symbol": "USN", - "name": "USN (Allbridge from Near)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/PUhuAtMHsKavMTwZsLaDeKy2jb7ciETHJP7rhbKLJGY/logo.png", - "tags": ["stablecoin"], - "extensions": { "coingeckoId": "usn" } - }, - { - "chainId": 101, - "address": "CXLBjMMcwkc17GfJtBos6rQCo1ypeH6eDbB82Kby4MRm", - "symbol": "WUST_V1", - "name": "Wrapped UST (Wormhole v1)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/CXLBjMMcwkc17GfJtBos6rQCo1ypeH6eDbB82Kby4MRm/logo.png", - "tags": ["wrapped", "wormhole"], - "extensions": { - "address": "0xa47c8bf37f92aBed4A126BDA807A7b7498661acD", - "assetContract": "https://etherscan.io/address/0xa47c8bf37f92aBed4A126BDA807A7b7498661acD", - "bridgeContract": "https://etherscan.io/address/0xf92cD566Ea4864356C5491c177A430C222d7e678", - "coingeckoId": "terrausd", - "website": "https://terra.money" - } - }, - { - "chainId": 101, - "address": "7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT", - "symbol": "UXD", - "name": "UXD Stablecoin", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT/uxd-icon-black.png", - "tags": ["stablecoin"], - "extensions": { - "coingeckoId": "uxd-stablecoin", - "discord": "https://discord.com/invite/BHfpYmjsBM", - "medium": "https://uxdprotocol.medium.com/", - "twitter": "https://twitter.com/UXDProtocol", - "website": "https://uxd.fi/" - } - }, - { - "chainId": 101, - "address": "5RpUwQ8wtdPCZHhu6MERp2RGrpobsbZ6MH5dDHkUjs2", - "symbol": "BUSDBS", - "name": "BUSD Token (Portal from BSC)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/5RpUwQ8wtdPCZHhu6MERp2RGrpobsbZ6MH5dDHkUjs2/logo.png", - "tags": ["wrapped", "wormhole"], - "extensions": { - "address": "0xe9e7cea3dedca5984780bafc599bd69add087d56", - "assetContract": "https://bscscan.com/address/0xe9e7cea3dedca5984780bafc599bd69add087d56", - "bridgeContract": "https://bscscan.com/address/0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7", - "coingeckoId": "binance-usd" - } - }, - { - "chainId": 101, - "address": "FCqfQSujuPxy6V42UvafBhsysWtEq1vhjfMN1PUbgaxA", - "symbol": "USDCBS", - "name": "USD Coin (Portal from BSC)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/FCqfQSujuPxy6V42UvafBhsysWtEq1vhjfMN1PUbgaxA/logo.png", - "tags": ["wrapped", "wormhole"], - "extensions": { - "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", - "assetContract": "https://bscscan.com/address/0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", - "bridgeContract": "https://bscscan.com/address/0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7", - "coingeckoId": "usd-coin" - } - }, - { - "chainId": 101, - "address": "8qJSyQprMC57TWKaYEmetUR3UUiTP2M3hXdcvFhkZdmv", - "symbol": "USDTBS", - "name": "Tether USD (Portal from BSC)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/8qJSyQprMC57TWKaYEmetUR3UUiTP2M3hXdcvFhkZdmv/logo.png", - "tags": ["wrapped", "wormhole"], - "extensions": { - "address": "0x55d398326f99059ff775485246999027b3197955", - "assetContract": "https://bscscan.com/address/0x55d398326f99059ff775485246999027b3197955", - "bridgeContract": "https://bscscan.com/address/0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7", - "coingeckoId": "tether" - } - }, - { - "chainId": 101, - "address": "T8KdT8hDzNhbGx5sjpEUxepnbDB1TZoCa7vtC5JjsMw", - "symbol": "SUSDT-8", - "name": "Saber Wrapped USDT (8 decimals)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/T8KdT8hDzNhbGx5sjpEUxepnbDB1TZoCa7vtC5JjsMw/icon.png", - "tags": ["stablecoin", "saber-mkt-usd", "saber-dec-wrapped"], - "extensions": { - "coingeckoId": "tether", - "serumV3Usdc": "77quYg4MGneUdjgXCunt9GgM1usmrxKY31twEy3WHwcS", - "website": "https://app.saber.so" - } - }, - { - "chainId": 101, - "address": "EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o", - "symbol": "DAI", - "name": "Dai Stablecoin (Portal)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o/logo.png", - "tags": ["wrapped"], - "extensions": { - "address": "0x6b175474e89094c44da98b954eedeac495271d0f", - "assetContract": "https://etherscan.io/address/0x6b175474e89094c44da98b954eedeac495271d0f", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "dai" - } - }, - { - "chainId": 101, - "address": "33fsBLA8djQm82RpHmE3SuVrPGtZBWNYExsEUeKX1HXX", - "symbol": "BUSDET", - "name": "Binance USD (Portal from Ethereum)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/33fsBLA8djQm82RpHmE3SuVrPGtZBWNYExsEUeKX1HXX/logo.png", - "tags": ["wrapped", "wormhole"], - "extensions": { - "address": "0x4fabb145d64652a948d72533023f6e7a623c7c53", - "assetContract": "https://etherscan.io/address/0x4fabb145d64652a948d72533023f6e7a623c7c53", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "binance-usd" - } - }, - { - "chainId": 101, - "address": "A9mUU4qviSctJVPJdBJWkb28deg915LYJKrzQ19ji3FM", - "symbol": "USDCET", - "name": "USD Coin (Portal from Ethereum)", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/A9mUU4qviSctJVPJdBJWkb28deg915LYJKrzQ19ji3FM/logo.png", - "tags": ["wrapped"], - "extensions": { - "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - "assetContract": "https://etherscan.io/address/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "usd-coin" - } - }, - { - "chainId": 101, - "address": "Dn4noZ5jgGfkntzcQSUZ8czkreiZ1ForXYoV2H8Dm7S1", - "symbol": "USDTET", - "name": "Tether USD (Portal from Ethereum)", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Dn4noZ5jgGfkntzcQSUZ8czkreiZ1ForXYoV2H8Dm7S1/logo.png", - "tags": ["wrapped"], - "extensions": { - "address": "0xdac17f958d2ee523a2206206994597c13d831ec7", - "assetContract": "https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "tether" - } - }, - { - "chainId": 101, - "address": "BFsCwfk8VsEbSfLkkgmoKsAPk2N6FMJjeTsuxfGa9VEf", - "symbol": "AEFTT", - "name": "Wrapped FTT (Allbridge from Ethereum)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3/logo.png", - "extensions": { "coingeckoId": "ftx-token" } - }, - { - "chainId": 101, - "address": "FTT9GrHBVHvDeUTgLU8FxVJouGqg9uiWGmmjETdm32Sx", - "symbol": "SWFTT-9", - "name": "Saber Wrapped FTT (Portal) (9 decimals)", - "decimals": 9, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/FTT9GrHBVHvDeUTgLU8FxVJouGqg9uiWGmmjETdm32Sx/icon.png", - "tags": ["saber-market-ftt", "wormhole-v2", "saber-dec-wrapped"], - "extensions": { - "coingeckoId": "ftx-token", - "website": "https://app.saber.so" - } - }, - { - "chainId": 101, - "address": "7dVH61ChzgmN9BwG4PkzwRP8PbYwPJ7ZPNF2vamKT2H8", - "symbol": "HBTC", - "name": "Huobi BTC (Portal)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/7dVH61ChzgmN9BwG4PkzwRP8PbYwPJ7ZPNF2vamKT2H8/logo.png", - "tags": ["wrapped", "wormhole"], - "extensions": { - "address": "0x0316eb71485b0ab14103307bf65a021042c6d380", - "assetContract": "https://etherscan.io/address/0x0316eb71485b0ab14103307bf65a021042c6d380", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "huobi-btc" - } - }, - { - "chainId": 101, - "address": "SL819j8K9FuFPL84UepVcFkEZqDUUvVzwDmJjCHySYj", - "symbol": "SETH-8", - "name": "Saber Wrapped Ethereum (Sollet) (8 decimals)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/SL819j8K9FuFPL84UepVcFkEZqDUUvVzwDmJjCHySYj/icon.png", - "tags": [ - "wrapped-sollet", - "ethereum", - "saber-market-eth", - "saber-dec-wrapped" - ], - "extensions": { - "coingeckoId": "ethereum", - "website": "https://app.saber.so" - } - }, - { - "chainId": 101, - "address": "7VQo3HFLNH5QqGtM8eC3XQbPkJUu7nS9LeGWjerRh5Sw", - "symbol": "HUSD", - "name": "HUSD (Portal)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/7VQo3HFLNH5QqGtM8eC3XQbPkJUu7nS9LeGWjerRh5Sw/logo.png", - "tags": ["wrapped", "wormhole"], - "extensions": { - "address": "0xdf574c24545e5ffecb9a659c229253d4111d87e1", - "assetContract": "https://etherscan.io/address/0xdf574c24545e5ffecb9a659c229253d4111d87e1", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "husd" - } - }, - { - "chainId": 101, - "address": "E2VmbootbVCBkMNNxKQgCLMS1X3NoGMaYAsufaAsf7M", - "symbol": "USDCPO", - "name": "USD Coin (Portal from Polygon)", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/E2VmbootbVCBkMNNxKQgCLMS1X3NoGMaYAsufaAsf7M/logo.png", - "tags": ["wrapped"], - "extensions": { - "address": "0x2791bca1f2de4661ed88a30c99a7a9449aa84174", - "assetContract": "https://polygonscan.com/token/0x2791bca1f2de4661ed88a30c99a7a9449aa84174", - "bridgeContract": "https://polygonscan.com/address/0x5a58505a96d1dbf8df91cb21b54419fc36e93fde", - "coingeckoId": "usd-coin" - } - }, - { - "chainId": 101, - "address": "5goWRao6a3yNC4d6UjMdQxonkCMvKBwdpubU3qhfcdf1", - "symbol": "USDTPO", - "name": "Tether USD (Portal from Polygon)", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/5goWRao6a3yNC4d6UjMdQxonkCMvKBwdpubU3qhfcdf1/logo.png", - "tags": ["wrapped"], - "extensions": { - "address": "0xc2132d05d31c914a87c6611c10748aeb04b58e8f", - "assetContract": "https://polygonscan.com/token/0xc2132d05d31c914a87c6611c10748aeb04b58e8f", - "bridgeContract": "https://polygonscan.com/address/0x5a58505a96d1dbf8df91cb21b54419fc36e93fde", - "coingeckoId": "tether" - } - }, - { - "chainId": 101, - "address": "xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG", - "symbol": "SRMET", - "name": "Serum (Portal from Ethereum)", - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/xnorPhAzWXUczCP3KjU5yDxmKKZi5cSbxytQ1LgE3kG/logo.png", - "tags": ["wrapped", "wormhole"], - "extensions": { - "address": "0x476c5e26a75bd202a9683ffd34359c0cc15be0ff", - "assetContract": "https://etherscan.io/address/0x476c5e26a75bd202a9683ffd34359c0cc15be0ff", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "serum" - } - }, - { - "chainId": 101, - "address": "43m2ewFV5nDepieFjT9EmAQnc1HRtAF247RBpLGFem5F", - "symbol": "USDK", - "name": "USDK (Portal)", - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/43m2ewFV5nDepieFjT9EmAQnc1HRtAF247RBpLGFem5F/logo.png", - "tags": ["wrapped", "wormhole"], - "extensions": { - "address": "0x1c48f86ae57291f7686349f12601910bd8d470bb", - "assetContract": "https://etherscan.io/address/0x1c48f86ae57291f7686349f12601910bd8d470bb", - "bridgeContract": "https://etherscan.io/address/0x3ee18B2214AFF97000D974cf647E7C347E8fa585", - "coingeckoId": "usdk" - } - }, - { - "chainId": 101, - "address": "HWxpSV3QAGzLQzGAtvhSYAEr7sTQugQygnni1gnUGh1D", - "symbol": "XBTC", - "name": "Synthetic BTC", - "decimals": 10, - "logoURI": "https://www.synthetify.io/icons/xbtc.svg", - "extensions": { - "coingeckoId": "bitcoin", - "twitter": "https://twitter.com/synthetify", - "website": "https://synthetify.io/" - } - }, - { - "chainId": 101, - "address": "BtX7AfzEJLnU8KQR1AgHrhGH5s2AHUTbfjhUQP8BhPvi", - "symbol": "SRENBTC-10", - "name": "Saber Wrapped renBTC (10 decimals)", - "decimals": 10, - "logoURI": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/BtX7AfzEJLnU8KQR1AgHrhGH5s2AHUTbfjhUQP8BhPvi/icon.png", - "tags": ["saber-market-btc", "saber-dec-wrapped"], - "extensions": { - "coingeckoId": "renbtc", - "website": "https://app.saber.so" - } - }, - { - "chainId": 101, - "address": "8bqjz8DeSuim1sEAsQatjJN4zseyxSPdhHQcuuhL8PCK", - "symbol": "XETH", - "name": "Synthetic ETH", - "decimals": 9, - "logoURI": "https://www.synthetify.io/icons/xeth.svg", - "extensions": { - "coingeckoId": "ethereum", - "twitter": "https://twitter.com/synthetify", - "website": "https://synthetify.io/" - } - }, - { - "chainId": 101, - "address": "Fr3W7NPVvdVbwMcHgA7Gx2wUxP43txdsn3iULJGFbKz9", - "symbol": "XFTT", - "name": "Synthetic FTT", - "decimals": 8, - "logoURI": "https://www.synthetify.io/icons/xftt.svg", - "extensions": { - "coingeckoId": "ftx-token", - "twitter": "https://twitter.com/synthetify", - "website": "https://synthetify.io/" - } - }, - { - "chainId": 101, - "address": "6MeoZEcUMhAB788YXTQN4x7K8MnwSt6RHWsLkuq9GJb2", - "symbol": "XLUNA", - "name": "Synthetic LUNA", - "decimals": 6, - "logoURI": "https://www.synthetify.io/icons/xluna.svg", - "extensions": { - "coingeckoId": "terra-luna", - "twitter": "https://twitter.com/synthetify", - "website": "https://synthetify.io/" - } - }, - { - "chainId": 101, - "address": "BdUJucPJyjkHxLMv6ipKNUhSeY3DWrVtgxAES1iSBAov", - "symbol": "XSOL", - "name": "Synthetic SOL", - "decimals": 9, - "logoURI": "https://www.synthetify.io/icons/xsol.svg", - "extensions": { - "coingeckoId": "solana", - "twitter": "https://twitter.com/synthetify", - "website": "https://synthetify.io/" - } - }, - { - "chainId": 101, - "address": "83LGLCm7QKpYZbX8q4W2kYWbtt8NJBwbVwEepzkVnJ9y", - "symbol": "XUSD", - "name": "Synthetic USD", - "decimals": 6, - "logoURI": "https://www.synthetify.io/icons/xusd.svg", - "extensions": { - "coingeckoId": "usd-coin", - "twitter": "https://twitter.com/synthetify", - "website": "https://synthetify.io/" - } - }, - { - "symbol": "wibBTC_V1", - "name": "ibBTC (Wormhole V1)", - "logoURI": "https://registry.saber.so/token-icons/ibbtc.svg", - "address": "66CgfJQoZkpkrEgC1z4vFJcSFc4V6T5HqbjSSNuqcNJz", - "decimals": 9, - "extensions": { - "coingeckoId": "bitcoin", - "currency": "BTC", - "source": "wormhole-v1", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "chainId": 101, - "tags": ["saber-mkt-btc", "wormhole-v1"] - }, - { - "symbol": "wSRM_V1", - "name": "Serum (Wormhole V1)", - "logoURI": "https://cdn.jsdelivr.net/gh/saber-hq/spl-token-icons@master/icons/101/SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt.png", - "address": "2jXy799YnEcRXneFo2GEAB6SDRsAa767HpWmktRr1DaP", - "decimals": 6, - "extensions": { - "coingeckoId": "serum", - "currency": "SRM", - "source": "wormhole-v1", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "chainId": 101, - "tags": ["saber-mkt-srm", "wormhole-v1"] - }, - { - "symbol": "wUSDK_V1", - "name": "USDK (Wormhole V1)", - "logoURI": "https://registry.saber.so/token-icons/usdk.png", - "address": "2kycGCD8tJbrjJJqWN2Qz5ysN9iB4Bth3Uic4mSB7uak", - "decimals": 9, - "extensions": { - "coingeckoId": "usdk", - "currency": "USD", - "source": "wormhole-v1", - "sourceUrl": "https://v1.wormholebridge.com/#/move" - }, - "chainId": 101, - "tags": ["saber-mkt-usd", "wormhole-v1"] - }, - { - "symbol": "wibBTC", - "name": "ibBTC (Wormhole)", - "logoURI": "https://registry.saber.so/token-icons/ibbtc.svg", - "address": "Bzq68gAVedKqQkQbsM28yQ4LYpc2VComDUD9wJBywdTi", - "decimals": 8, - "extensions": { - "coingeckoId": "bitcoin", - "currency": "BTC", - "source": "wormhole-v2", - "sourceUrl": "https://wormholebridge.com/#/transfer" - }, - "chainId": 101, - "tags": ["saber-mkt-btc", "wormhole-v2"] - }, - { - "symbol": "IOU", - "name": "IOU Coin", - "logoURI": "", - "address": "iouQcQBAiEXe6cKLS85zmZxUqaCqBdeHFpqKoSz615u", - "decimals": 6, - "chainId": 101, - "tags": [], - "extensions": {} - }, - { - "address": "Ez2zVjw85tZan1ycnJ5PywNNxR6Gm4jbXQtZKyQNu3Lv", - "symbol": "SECRET", - "name": "Secret Stablecoin", - "decimals": 6, - "chainId": 101, - "extensions": { - "coingeckoId": "usd-coin" - }, - "tags": [] - } - ] -} diff --git a/farms/farm-ctrl/metadata/tokens/solana_token_list/get_solana_tokens.sh b/farms/farm-ctrl/metadata/tokens/solana_token_list/get_solana_tokens.sh deleted file mode 100755 index 00817d7c589..00000000000 --- a/farms/farm-ctrl/metadata/tokens/solana_token_list/get_solana_tokens.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -# Solana tokens loader - -url="https://raw.githubusercontent.com/solana-labs/token-list/main/src/tokens/solana.tokenlist.json" - -if hash wget 2>/dev/null; then - wget_or_curl="wget -O tokens.json $url" -elif hash curl 2>/dev/null; then - wget_or_curl="curl -o tokens.json -L $url" -else - echo "Error: Neither curl nor wget were found" >&2 - return 1 -fi - -exec $wget_or_curl diff --git a/farms/farm-ctrl/metadata/vaults/generate_vaults.py b/farms/farm-ctrl/metadata/vaults/generate_vaults.py deleted file mode 100755 index 35670cb3aaf..00000000000 --- a/farms/farm-ctrl/metadata/vaults/generate_vaults.py +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import subprocess -import json -import sys -import os -from datetime import datetime - - -def main(): - parser = argparse.ArgumentParser(description='Vaults metadata generator') - - parser.add_argument('-v', - '--vaults-file', - help='Output file path for vaults', - default='vaults.json') - parser.add_argument('-t', - '--tokens-file', - help='Output file path for vault tokens', - default='tokens.json') - parser.add_argument('-f', - '--farm-binaries-dir', - help='Path to farm binaries, e.g. ../target/release', - default='') - parser.add_argument('-a', - '--vault-program-address', - help='Address of the vault program', - required=True) - parser.add_argument('-p', - '--protocol', - help='Protocol', - choices=['RDM', 'ORC', 'SBR'], - required=True) - args = parser.parse_args() - - vaults_out = open(args.vaults_file, 'w') - tokens_out = open(args.tokens_file, 'w') - vault_program = args.vault_program_address - bin_dir = args.farm_binaries_dir - protocol = args.protocol - - p = subprocess.Popen(os.path.join(bin_dir, 'solana-farm-client') + - ' list-all farm', - shell=True, - stdout=subprocess.PIPE) - data = '[' - for line in p.stdout.readlines(): - if line[:4].decode("utf-8") != protocol + '.': - continue - farm = line.decode("utf-8").split(':')[0] - if len('VT.' + protocol + '.STC.' + farm[4:]) >= 32: - raise ValueError("Len exceeded " + farm) - p2 = subprocess.Popen(os.path.join(bin_dir, 'solana-farm-ctrl') + - ' generate Vault ' + vault_program + ' ' + - protocol + '.STC.' + farm[4:] + ' VT.' + - protocol + '.STC.' + farm[4:], - shell=True, - stdout=subprocess.PIPE) - for log in p2.stdout.readlines(): - data += log.decode("utf-8").rstrip('\n') - if p2.wait() == 0: - data += ',' - - data = data[:-1] - data += ']' - - parsed = json.loads(data) - timestamp = datetime.now().isoformat() - vaults_out.write( - f'{{"name": "Solana Vaults List", "timestamp": "{timestamp}", "vaults":[' - ) - tokens_out.write( - f'{{"name": "Solana Token List", "timestamp": "{timestamp}", "tokens":[' - ) - first_token = True - first_vault = True - for obj in parsed: - if 'chainId' in obj: - if not first_token: - tokens_out.write(',\n') - else: - first_token = False - tokens_out.write(json.dumps(obj, indent=2, sort_keys=False)) - else: - if not first_vault: - vaults_out.write(',\n') - else: - first_vault = False - vaults_out.write(json.dumps(obj, indent=2, sort_keys=False)) - - vaults_out.write(']}') - tokens_out.write(']}') - vaults_out.close() - tokens_out.close() - - print('Done.') - - -if __name__ == '__main__': - main() diff --git a/farms/farm-ctrl/src/config.rs b/farms/farm-ctrl/src/config.rs deleted file mode 100644 index 152d9dda9c8..00000000000 --- a/farms/farm-ctrl/src/config.rs +++ /dev/null @@ -1,811 +0,0 @@ -//! Configuration and command line arguments management. - -use { - clap::{crate_description, crate_name, App, AppSettings, Arg, ArgMatches, SubCommand}, - solana_clap_utils::{input_validators::is_url, keypair::signer_from_path}, - solana_farm_sdk::{program::multisig::Multisig, refdb}, - solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey, signature::Signer}, - std::str::FromStr, -}; - -#[derive(Debug)] -pub struct Config { - pub farm_client_url: String, - pub commitment: CommitmentConfig, - pub keypair: Box, - pub max_instructions: u32, - pub no_pretty_print: bool, - pub skip_existing: bool, -} - -impl Config { - pub fn new(matches: &ArgMatches) -> Self { - let cli_config = if let Some(config_file) = matches.value_of("config_file") { - match solana_cli_config::Config::load(config_file) { - Err(e) => { - panic!("Failed to load config file \"{}\":{}", config_file, e); - } - Ok(config) => config, - } - } else { - solana_cli_config::Config::default() - }; - - let farm_client_url = matches - .value_of("farm_client_url") - .unwrap_or(&cli_config.json_rpc_url); - let keypair_path = matches - .value_of("keypair") - .unwrap_or(&cli_config.keypair_path); - let commitment = matches - .value_of("commitment") - .unwrap_or(&cli_config.commitment); - let max_instructions = matches - .value_of("max_instructions") - .unwrap() - .parse() - .unwrap(); - - Self { - farm_client_url: farm_client_url.to_string(), - commitment: CommitmentConfig::from_str(commitment).unwrap(), - keypair: signer_from_path(matches, keypair_path, "signer", &mut None).unwrap(), - max_instructions, - no_pretty_print: matches.is_present("no_pretty_print"), - skip_existing: matches.is_present("skip_existing"), - } - } -} - -pub fn get_target(matches: &ArgMatches) -> refdb::StorageType { - let target = matches.value_of("target").unwrap(); - let res = target - .parse() - .unwrap_or_else(|_| panic!("Invalid target type \"{}\"", target)); - if res == refdb::StorageType::Other { - panic!("Invalid target type: {}", res); - } - res -} - -pub fn get_str_val<'a>(matches: &ArgMatches<'a>, argname: &str) -> String { - matches - .value_of(argname) - .unwrap() - .parse::() - .unwrap() - .to_uppercase() -} - -pub fn get_str_val_raw<'a>(matches: &ArgMatches<'a>, argname: &str) -> String { - matches - .value_of(argname) - .unwrap() - .parse::() - .unwrap() -} - -pub fn get_pubkey_val<'a>(matches: &ArgMatches<'a>, argname: &str) -> Pubkey { - Pubkey::from_str(matches.value_of(argname).unwrap()).unwrap() -} - -pub fn get_pubkey_multi_val<'a>(matches: &ArgMatches<'a>, argname: &str) -> Vec { - let args: Vec<_> = matches.values_of(argname).unwrap().collect(); - let mut keys = vec![]; - for arg in &args { - keys.push(Pubkey::from_str(arg).unwrap()); - } - keys -} - -pub fn get_integer_val<'a>(matches: &ArgMatches<'a>, argname: &str) -> u64 { - matches.value_of(argname).unwrap().parse::().unwrap() -} - -pub fn get_floating_val<'a>(matches: &ArgMatches<'a>, argname: &str) -> f64 { - matches.value_of(argname).unwrap().parse::().unwrap() -} - -pub fn get_boolean_val<'a>(matches: &ArgMatches<'a>, argname: &str) -> bool { - matches.value_of(argname).unwrap().parse::().unwrap() -} - -fn get_arg(name: &str) -> Arg { - Arg::with_name(name).required(true).takes_value(true) -} - -fn get_multi_arg(name: &str, min_values: u64, max_values: u64) -> Arg { - Arg::with_name(name) - .required(true) - .takes_value(true) - .multiple(true) - .min_values(min_values) - .max_values(max_values) -} - -fn get_integer_arg(name: &str) -> Arg { - Arg::with_name(name) - .takes_value(true) - .required(true) - .validator(|p| match p.parse::() { - Err(_) => Err(String::from("Must be unsigned integer")), - Ok(_) => Ok(()), - }) -} - -fn get_floating_arg(name: &str) -> Arg { - Arg::with_name(name) - .takes_value(true) - .required(true) - .validator(|p| match p.parse::() { - Err(_) => Err(String::from("Must be floating number")), - Ok(_) => Ok(()), - }) -} - -fn get_boolean_arg(name: &str) -> Arg { - Arg::with_name(name) - .takes_value(true) - .required(true) - .validator(|p| match p.parse::() { - Err(_) => Err(String::from("Must be boolean")), - Ok(_) => Ok(()), - }) -} - -pub fn get_clap_app<'a, 'b>(version: &'b str) -> App<'a, 'b> { - let target = Arg::with_name("target") - .required(true) - .takes_value(true) - .help("Target object type (program, vault, etc.)"); - - let filename = Arg::with_name("file_name") - .required(true) - .takes_value(true) - .help("Input file name"); - - let objectname = Arg::with_name("object_name") - .required(true) - .takes_value(true) - .help("Target object name"); - - let tokenname = Arg::with_name("token_name") - .required(true) - .takes_value(true) - .help("Token name"); - - let vaultname = Arg::with_name("vault_name") - .required(true) - .takes_value(true) - .help("Vault name"); - - let fundname = Arg::with_name("fund_name") - .required(true) - .takes_value(true) - .help("Fund name"); - - let amount = Arg::with_name("amount") - .required(true) - .takes_value(true) - .validator(|p| match p.parse::() { - Err(_) => Err(String::from("Must be unsigned decimal")), - Ok(val) => { - if val >= 0.0 { - Ok(()) - } else { - Err(String::from("Must be unsigned decimal")) - } - } - }) - .help("Token amount"); - - App::new(crate_name!()) - .about(crate_description!()) - .version(version) - .arg( - Arg::with_name("log_level") - .short("L") - .long("log-level") - .takes_value(true) - .default_value("info") - .global(true) - .help("Log verbosity level") - .possible_values(&["debug", "info", "warning", "error"]) - .hide_possible_values(false), - ) - .arg({ - let arg = Arg::with_name("config_file") - .short("C") - .long("config") - .takes_value(true) - .global(true) - .help("Configuration file to use"); - if let Some(ref config_file) = *solana_cli_config::CONFIG_FILE { - arg.default_value(config_file) - } else { - arg - } - }) - .arg( - Arg::with_name("farm_client_url") - .short("f") - .long("farm-client-url") - .takes_value(true) - .global(true) - .validator(is_url) - .help("RPC URL to use with Farm Client"), - ) - .arg( - Arg::with_name("keypair") - .short("k") - .long("keypair") - .global(true) - .takes_value(true) - .help("Filepath or URL to a keypair"), - ) - .arg( - Arg::with_name("max_instructions") - .short("m") - .long("max-instructions") - .global(true) - .takes_value(true) - .default_value("1") - .validator(|p| match p.parse::() { - Err(_) => Err(String::from("Must be unsigned integer")), - Ok(_) => Ok(()), - }) - .help("Max instructions per transaction"), - ) - .arg( - Arg::with_name("commitment") - .long("commitment") - .short("c") - .takes_value(true) - .possible_values(&["processed", "confirmed", "finalized"]) - .hide_possible_values(false) - .global(true) - .help("Return information at the selected commitment level"), - ) - .arg( - Arg::with_name("no_pretty_print") - .short("n") - .long("no-pretty-print") - .global(true) - .takes_value(false) - .help("Print entire record in one line"), - ) - .arg( - Arg::with_name("skip_existing") - .short("s") - .long("skip-existing") - .global(true) - .takes_value(false) - .help("Do not update existing records on-chain"), - ) - .subcommand( - SubCommand::with_name("init") - .about("Initialize Reference DB on-chain") - .arg(target.clone()), - ) - .subcommand( - SubCommand::with_name("init-all") - .about("Initialize Reference DB of all storage types on-chain"), - ) - .subcommand( - SubCommand::with_name("get-admins") - .about("Print current admin signers for the Main Router"), - ) - .subcommand( - SubCommand::with_name("set-admins") - .about("Set new admins for the Main Router") - .arg(get_integer_arg("min_signatures")) - .arg(get_multi_arg( - "admin_signers", - 1, - Multisig::MAX_SIGNERS as u64, - )), - ) - .subcommand( - SubCommand::with_name("drop") - .about("Drop on-chain Reference DB") - .arg(target.clone()), - ) - .subcommand( - SubCommand::with_name("drop-all") - .about("Drop on-chain Reference DB for all storage types"), - ) - .subcommand( - SubCommand::with_name("load") - .about("Load objects from file and send to blockchain") - .arg(target.clone()) - .arg(filename.clone()), - ) - .subcommand( - SubCommand::with_name("load-all") - .about("Same as \"load\"") - .arg(target.clone()) - .arg(filename.clone()), - ) - .subcommand( - SubCommand::with_name("remove") - .about("Remove specified object from blockchain") - .arg(target.clone()) - .arg(objectname.clone()), - ) - .subcommand( - SubCommand::with_name("remove-ref") - .about("Remove specified reference from blockchain") - .arg(target.clone()) - .arg(objectname.clone()), - ) - .subcommand( - SubCommand::with_name("remove-all") - .about("Remove all objects of the given type from blockchain") - .arg(target.clone()), - ) - .subcommand( - SubCommand::with_name("remove-all-with-file") - .about("Remove all objects in the file from blockchain") - .arg(target.clone()) - .arg(filename.clone()), - ) - .subcommand( - SubCommand::with_name("get") - .about("Query specified object in blockchain and print") - .arg(target.clone()) - .arg(objectname.clone()), - ) - .subcommand( - SubCommand::with_name("get-ref") - .about("Query specified object by reference address and print") - .arg(target.clone()) - .arg(objectname.clone()), - ) - .subcommand( - SubCommand::with_name("get-all") - .about("Query all objects of the given type and print") - .arg(target.clone()), - ) - .subcommand( - SubCommand::with_name("list-all") - .about("Query all objects of the given type and print") - .arg(target.clone()), - ) - .subcommand( - SubCommand::with_name("program-get-admins") - .about("Print current admin signers for the program") - .arg(get_arg("program_id")), - ) - .subcommand( - SubCommand::with_name("program-set-admins") - .about("Set new admin signers for the program") - .arg(get_arg("program_id")) - .arg(get_integer_arg("min_signatures")) - .arg(get_multi_arg( - "admin_signers", - 1, - Multisig::MAX_SIGNERS as u64, - )), - ) - .subcommand( - SubCommand::with_name("program-set-single-authority") - .about("Set single upgrade authority for the program") - .arg(get_arg("program_id")) - .arg(get_arg("upgrade_authority")), - ) - .subcommand( - SubCommand::with_name("program-upgrade") - .about("Upgrade the program from the data buffer") - .arg(get_arg("program_id")) - .arg(get_arg("buffer_address")), - ) - .subcommand( - SubCommand::with_name("vault-init") - .about("Initialize the Vault") - .arg(vaultname.clone()) - .arg(get_integer_arg("step")), - ) - .subcommand( - SubCommand::with_name("vault-set-admins") - .about("Set new admins for the Vault") - .arg(vaultname.clone()) - .arg(get_integer_arg("min_signatures")) - .arg(get_multi_arg( - "admin_signers", - 1, - Multisig::MAX_SIGNERS as u64, - )), - ) - .subcommand( - SubCommand::with_name("vault-get-admins") - .about("Print current admin signers for the Vault") - .arg(vaultname.clone()), - ) - .subcommand( - SubCommand::with_name("vault-shutdown") - .about("Shutdown the Vault") - .arg(vaultname.clone()), - ) - .subcommand( - SubCommand::with_name("vault-withdraw-fees") - .about("Withdraw collected fees from the Vault") - .arg(vaultname.clone()) - .arg( - Arg::with_name("fee_token") - .required(true) - .takes_value(true) - .help("Fees token account to withdraw from - 0 or 1"), - ) - .arg(amount.clone()) - .arg( - Arg::with_name("receiver") - .required(true) - .takes_value(true) - .help("Fees receiver address"), - ), - ) - .subcommand( - SubCommand::with_name("vault-crank") - .about("Crank the Vault") - .arg(vaultname.clone()) - .arg(get_integer_arg("step")), - ) - .subcommand( - SubCommand::with_name("vault-set-fee") - .about("Set new fee percent for the Vault") - .arg(vaultname.clone()) - .arg(get_floating_arg("fee_percent")), - ) - .subcommand( - SubCommand::with_name("vault-set-external-fee") - .about("Set new external fee percent for the Vault") - .arg(vaultname.clone()) - .arg(get_floating_arg("external_fee_percent")), - ) - .subcommand( - SubCommand::with_name("vault-set-min-crank-interval") - .about("Set new min crank interval in seconds for the Vault") - .arg(vaultname.clone()) - .arg(get_integer_arg("min_crank_interval")), - ) - .subcommand( - SubCommand::with_name("vault-disable-deposits") - .about("Disable deposits for the specified object") - .arg(vaultname.clone()), - ) - .subcommand( - SubCommand::with_name("vault-enable-deposits") - .about("Enable deposits for the specified object") - .arg(vaultname.clone()), - ) - .subcommand( - SubCommand::with_name("vault-disable-withdrawals") - .about("Disable withdrawals for the specified object") - .arg(vaultname.clone()), - ) - .subcommand( - SubCommand::with_name("vault-enable-withdrawals") - .about("Enable withdrawals for the specified object") - .arg(vaultname.clone()), - ) - .subcommand( - SubCommand::with_name("vault-get-info") - .about("Print current stats for the Vault") - .arg(vaultname.clone()), - ) - .subcommand( - SubCommand::with_name("fund-init") - .about("Initialize the Fund") - .arg(fundname.clone()) - .arg(get_integer_arg("step")), - ) - .subcommand( - SubCommand::with_name("fund-set-admins") - .about("Set new admins for the Fund") - .arg(fundname.clone()) - .arg(get_integer_arg("min_signatures")) - .arg(get_multi_arg( - "admin_signers", - 1, - Multisig::MAX_SIGNERS as u64, - )), - ) - .subcommand( - SubCommand::with_name("fund-get-admins") - .about("Print current admin signers for the Fund") - .arg(fundname.clone()), - ) - .subcommand( - SubCommand::with_name("fund-set-manager") - .about("Set a new manager for the Fund") - .arg(fundname.clone()) - .arg(get_arg("manager")), - ) - .subcommand( - SubCommand::with_name("fund-add-custody") - .about("Add a new custody to the Fund") - .arg(fundname.clone()) - .arg(tokenname.clone()) - .arg(get_arg("custody_type")), - ) - .subcommand( - SubCommand::with_name("fund-remove-custody") - .about("Remove the custody from the Fund") - .arg(fundname.clone()) - .arg(tokenname.clone()) - .arg(get_arg("custody_type")), - ) - .subcommand( - SubCommand::with_name("fund-add-vault") - .about("Add a new Vault to the Fund") - .arg(fundname.clone()) - .arg(vaultname.clone()) - .arg(get_arg("vault_type")), - ) - .subcommand( - SubCommand::with_name("fund-remove-vault") - .about("Remove the Vault from the Fund") - .arg(fundname.clone()) - .arg(vaultname.clone()) - .arg(get_arg("vault_type")), - ) - .subcommand( - SubCommand::with_name("fund-set-assets-tracking-config") - .about("Set a new assets tracking config for the Fund") - .arg(fundname.clone()) - .arg(get_floating_arg("assets_limit_usd")) - .arg(get_integer_arg("max_update_age_sec")) - .arg(get_floating_arg("max_price_error")) - .arg(get_integer_arg("max_price_age_sec")) - .arg(get_boolean_arg("issue_virtual_tokens")), - ) - .subcommand( - SubCommand::with_name("fund-set-deposit-schedule") - .about("Set a new deposit schedule for the Fund") - .arg(fundname.clone()) - .arg(get_integer_arg("start_time")) - .arg(get_integer_arg("end_time")) - .arg(get_arg("approval_required")) - .arg(get_floating_arg("limit_usd")) - .arg(get_floating_arg("fee")), - ) - .subcommand( - SubCommand::with_name("fund-disable-deposits") - .about("Disables deposits to the Fund") - .arg(fundname.clone()), - ) - .subcommand( - SubCommand::with_name("fund-approve-deposit") - .about("Approve pending deposit to the Fund") - .arg(fundname.clone()) - .arg(get_arg("user_address")) - .arg(tokenname.clone()) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("fund-deny-deposit") - .about("Deny pending deposit to the Fund") - .arg(fundname.clone()) - .arg(get_arg("user_address")) - .arg(tokenname.clone()) - .arg(get_arg("deny_reason")), - ) - .subcommand( - SubCommand::with_name("fund-set-withdrawal-schedule") - .about("Set a new withdrawal schedule for the Fund") - .arg(fundname.clone()) - .arg(get_integer_arg("start_time")) - .arg(get_integer_arg("end_time")) - .arg(get_arg("approval_required")) - .arg(get_floating_arg("limit_usd")) - .arg(get_floating_arg("fee")), - ) - .subcommand( - SubCommand::with_name("fund-disable-withdrawals") - .about("Disables withdrawals from the Fund") - .arg(fundname.clone()), - ) - .subcommand( - SubCommand::with_name("fund-approve-withdrawal") - .about("Approve pending withdrawal from the Fund") - .arg(fundname.clone()) - .arg(get_arg("user_address")) - .arg(tokenname.clone()) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("fund-deny-withdrawal") - .about("Deny pending withdrawal from the Fund") - .arg(fundname.clone()) - .arg(get_arg("user_address")) - .arg(tokenname.clone()) - .arg(get_arg("deny_reason")), - ) - .subcommand( - SubCommand::with_name("fund-lock-assets") - .about("Moves assets from Deposit/Withdraw custody to the Fund") - .arg(fundname.clone()) - .arg(tokenname.clone()) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("fund-unlock-assets") - .about("Releases assets from the Fund to Deposit/Withdraw custody") - .arg(fundname.clone()) - .arg(tokenname.clone()) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("fund-withdraw-fees") - .about("Withdraw collected fees from the Fund") - .arg(fundname.clone()) - .arg(tokenname.clone()) - .arg(get_arg("custody_type")) - .arg(amount.clone()) - .arg(get_arg("receiver")), - ) - .subcommand( - SubCommand::with_name("fund-update-assets-with-custody") - .about("Update Fund assets info based on custody holdings") - .arg(fundname.clone()) - .arg(get_integer_arg("custody_id")), - ) - .subcommand( - SubCommand::with_name("fund-update-assets-with-custodies") - .about("Update Fund assets info based on all custodies") - .arg(fundname.clone()), - ) - .subcommand( - SubCommand::with_name("fund-update-assets-with-vault") - .about("Update Fund assets info based on Vault holdings") - .arg(fundname.clone()) - .arg(get_integer_arg("vault_id")), - ) - .subcommand( - SubCommand::with_name("fund-update-assets-with-vaults") - .about("Update Fund assets info based on all Vaults") - .arg(fundname.clone()), - ) - .subcommand( - SubCommand::with_name("fund-stop-liquidation") - .about("Stop the Fund liquidation") - .arg(fundname.clone()), - ) - .subcommand( - SubCommand::with_name("fund-get-info") - .about("Print current stats for the Fund") - .arg(fundname.clone()), - ) - .subcommand( - SubCommand::with_name("fund-deposit-pool") - .about("Add liquidity to the Pool in the Fund") - .arg(fundname.clone()) - .arg(get_arg("pool_name")) - .arg(get_floating_arg("max_token_a_ui_amount")) - .arg(get_floating_arg("max_token_b_ui_amount")), - ) - .subcommand( - SubCommand::with_name("fund-withdraw-pool") - .about("Remove liquidity from the Pool in the Fund") - .arg(fundname.clone()) - .arg(get_arg("pool_name")) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("fund-swap") - .about("Swap tokens in the Fund") - .arg(fundname.clone()) - .arg(get_arg("protocol")) - .arg(get_arg("from_token")) - .arg(get_arg("to_token")) - .arg(get_floating_arg("amount_in")) - .arg(get_floating_arg("min_amount_out")), - ) - .subcommand( - SubCommand::with_name("fund-stake") - .about("Stake LP tokens to the Farm in the Fund") - .arg(fundname.clone()) - .arg(get_arg("farm_name")) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("fund-unstake") - .about("Unstake LP tokens from the Farm in the Fund") - .arg(fundname.clone()) - .arg(get_arg("farm_name")) - .arg(amount.clone()), - ) - .subcommand( - SubCommand::with_name("fund-harvest") - .about("Harvest rewards from the Farm in the Fund") - .arg(fundname.clone()) - .arg(get_arg("farm_name")), - ) - .subcommand( - SubCommand::with_name("fund-deposit-vault") - .about("Add liquidity to the Vault in the Fund") - .arg(fundname.clone()) - .arg(vaultname.clone()) - .arg(get_floating_arg("max_token_a_amount")) - .arg(get_floating_arg("max_token_b_amount")), - ) - .subcommand( - SubCommand::with_name("fund-deposit-vault-locked") - .about("Add locked liquidity to the Vault in the Fund") - .arg(fundname.clone()) - .arg(vaultname.clone()) - .arg(get_floating_arg("amount")), - ) - .subcommand( - SubCommand::with_name("fund-withdraw-vault") - .about("Remove liquidity from the Vault in the Fund") - .arg(fundname.clone()) - .arg(vaultname.clone()) - .arg(get_floating_arg("amount")), - ) - .subcommand( - SubCommand::with_name("fund-withdraw-vault-unlocked") - .about("Remove unlocked liquidity from the Vault in the Fund") - .arg(fundname.clone()) - .arg(vaultname.clone()) - .arg(get_floating_arg("amount")), - ) - .subcommand( - SubCommand::with_name("print-pda-all") - .about("Derive Reference DB addresses for all objects"), - ) - .subcommand( - SubCommand::with_name("print-size") - .about("Print Reference DB and specified object sizes") - .arg(target.clone()), - ) - .subcommand( - SubCommand::with_name("print-size-all") - .about("Print Reference DB and all object sizes"), - ) - .subcommand( - SubCommand::with_name("generate") - .about("Generate json boilerplate for the specified object") - .arg(target.clone()) - .arg(objectname.clone()) - .arg( - Arg::with_name("param1") - .index(3) - .required(true) - .takes_value(true) - .help("Object specific parameter 1"), - ) - .arg( - Arg::with_name("param2") - .index(4) - .required(true) - .takes_value(true) - .help("Object specific parameter 2"), - ), - ) - .subcommand( - SubCommand::with_name("governance") - .about("Governance commands. See `solana-farm-ctrl governance help`") - .setting(AppSettings::SubcommandRequiredElseHelp) - .subcommand( - SubCommand::with_name("init") - .about("Initialize a new DAO") - .arg( - Arg::with_name("governance-program-address") - .required(true) - .takes_value(true) - .help("Address of the governance program"), - ) - .arg( - Arg::with_name("mint-ui-amount") - .required(true) - .takes_value(true) - .validator(|p| match p.parse::() { - Err(_) => Err(String::from("Must be unsigned integer")), - Ok(_) => Ok(()), - }) - .help("Amount of governance tokens to mint"), - ), - ), - ) -} diff --git a/farms/farm-ctrl/src/fund.rs b/farms/farm-ctrl/src/fund.rs deleted file mode 100644 index 1db381cb317..00000000000 --- a/farms/farm-ctrl/src/fund.rs +++ /dev/null @@ -1,844 +0,0 @@ -//! Handlers for Fund management commands - -use { - crate::config::Config, - log::info, - solana_farm_client::client::FarmClient, - solana_farm_sdk::{ - fund::{Fund, FundAssetsTrackingConfig, FundCustodyType, FundSchedule, FundVaultType}, - string::to_pretty_json, - Protocol, - }, - solana_sdk::{clock::UnixTimestamp, pubkey::Pubkey}, -}; - -pub fn init(client: &FarmClient, config: &Config, fund_names: &str, step: u64) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!("Initializing Fund {}...", fund); - info!( - "Signature: {}", - client - .init_fund(config.keypair.as_ref(), fund, step) - .unwrap() - ); - } - info!("Done.") -} - -pub fn set_admins( - client: &FarmClient, - config: &Config, - fund_names: &str, - admin_signers: &[Pubkey], - min_signatures: u8, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!("Initializing Fund {} multisig with new signers...", fund); - - info!( - "Signature: {}", - client - .set_fund_admins(config.keypair.as_ref(), fund, admin_signers, min_signatures) - .unwrap() - ); - } - info!("Done.") -} - -pub fn get_admins(client: &FarmClient, config: &Config, fund_names: &str) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - if config.no_pretty_print { - println!("{}: {}", fund, client.get_fund_admins(fund).unwrap()); - } else { - println!( - "{}: {}", - fund, - to_pretty_json(&client.get_fund_admins(fund).unwrap()).unwrap() - ); - } - } -} - -pub fn set_fund_manager(client: &FarmClient, config: &Config, fund_names: &str, manager: &Pubkey) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!("Setting manager for the Fund {}...", fund); - let fund_meta = Fund { - fund_manager: *manager, - ..client.get_fund(fund).unwrap() - }; - info!( - "Signature: {}", - client.add_fund(config.keypair.as_ref(), fund_meta).unwrap() - ); - } - info!("Done.") -} - -pub fn add_custody( - client: &FarmClient, - config: &Config, - fund_names: &str, - token_name: &str, - custody_type: FundCustodyType, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!("Adding {} custody to the Fund {}...", custody_type, fund); - info!( - "Signature: {}", - client - .add_fund_custody(config.keypair.as_ref(), fund, token_name, custody_type) - .unwrap() - ); - } - info!("Done.") -} - -pub fn remove_custody( - client: &FarmClient, - config: &Config, - fund_names: &str, - token_name: &str, - custody_type: FundCustodyType, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!( - "Removing {} custody from the Fund {}...", - custody_type, fund - ); - info!( - "Signature: {}", - client - .remove_fund_custody(config.keypair.as_ref(), fund, token_name, custody_type) - .unwrap() - ); - } - info!("Done.") -} - -pub fn add_vault( - client: &FarmClient, - config: &Config, - fund_names: &str, - vault_name: &str, - vault_type: FundVaultType, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!("Adding Vault {} to the Fund {}...", vault_name, fund); - info!( - "Signature: {}", - client - .add_fund_vault(config.keypair.as_ref(), fund, vault_name, vault_type) - .unwrap() - ); - } - info!("Done.") -} - -pub fn remove_vault( - client: &FarmClient, - config: &Config, - fund_names: &str, - vault_name: &str, - vault_type: FundVaultType, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!("Removing Vault {} from the Fund {}...", vault_name, fund); - info!( - "Signature: {}", - client - .remove_fund_vault(config.keypair.as_ref(), fund, vault_name, vault_type) - .unwrap() - ); - } - info!("Done.") -} - -#[allow(clippy::too_many_arguments)] -pub fn set_assets_tracking_config( - client: &FarmClient, - config: &Config, - fund_names: &str, - assets_limit_usd: f64, - max_update_age_sec: u64, - max_price_error: f64, - max_price_age_sec: u64, - issue_virtual_tokens: bool, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!("Setting assets tracking config for the Fund {}...", fund); - info!( - "Signature: {}", - client - .set_fund_assets_tracking_config( - config.keypair.as_ref(), - fund, - &FundAssetsTrackingConfig { - assets_limit_usd, - max_update_age_sec, - max_price_error, - max_price_age_sec, - issue_virtual_tokens - } - ) - .unwrap() - ); - } - info!("Done.") -} - -#[allow(clippy::too_many_arguments)] -pub fn set_deposit_schedule( - client: &FarmClient, - config: &Config, - fund_names: &str, - start_time: UnixTimestamp, - end_time: UnixTimestamp, - approval_required: bool, - min_amount_usd: f64, - max_amount_usd: f64, - fee: f64, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!("Setting deposit schedule for the Fund {}...", fund); - info!( - "Signature: {}", - client - .set_fund_deposit_schedule( - config.keypair.as_ref(), - fund, - &FundSchedule { - start_time, - end_time, - approval_required, - min_amount_usd, - max_amount_usd, - fee - } - ) - .unwrap() - ); - } - info!("Done.") -} - -pub fn disable_deposits(client: &FarmClient, config: &Config, fund_names: &str) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!("Disabling deposits for the Fund {}...", fund); - info!( - "Signature: {}", - client - .disable_deposits_fund(config.keypair.as_ref(), fund) - .unwrap() - ); - } - info!("Done.") -} - -pub fn approve_deposit( - client: &FarmClient, - config: &Config, - fund_names: &str, - user_address: &Pubkey, - token_name: &str, - ui_amount: f64, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!( - "Approving deposit from {} to the Fund {}...", - user_address, fund - ); - info!( - "Signature: {}", - client - .approve_deposit_fund( - config.keypair.as_ref(), - fund, - user_address, - token_name, - ui_amount - ) - .unwrap() - ); - } - info!("Done.") -} - -pub fn deny_deposit( - client: &FarmClient, - config: &Config, - fund_names: &str, - user_address: &Pubkey, - token_name: &str, - deny_reason: &str, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!( - "Denying deposit from {} to the Fund {}...", - user_address, fund - ); - info!( - "Signature: {}", - client - .deny_deposit_fund( - config.keypair.as_ref(), - fund, - user_address, - token_name, - deny_reason - ) - .unwrap() - ); - } - info!("Done.") -} - -#[allow(clippy::too_many_arguments)] -pub fn set_withdrawal_schedule( - client: &FarmClient, - config: &Config, - fund_names: &str, - start_time: UnixTimestamp, - end_time: UnixTimestamp, - approval_required: bool, - min_amount_usd: f64, - max_amount_usd: f64, - fee: f64, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!("Setting withdrawal schedule for the Fund {}...", fund); - info!( - "Signature: {}", - client - .set_fund_withdrawal_schedule( - config.keypair.as_ref(), - fund, - &FundSchedule { - start_time, - end_time, - approval_required, - min_amount_usd, - max_amount_usd, - fee - } - ) - .unwrap() - ); - } - info!("Done.") -} - -pub fn disable_withdrawals(client: &FarmClient, config: &Config, fund_names: &str) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!("Disabling withdrawals for the Fund {}...", fund); - info!( - "Signature: {}", - client - .disable_withdrawals_fund(config.keypair.as_ref(), fund) - .unwrap() - ); - } - info!("Done.") -} - -pub fn approve_withdrawal( - client: &FarmClient, - config: &Config, - fund_names: &str, - user_address: &Pubkey, - token_name: &str, - ui_amount: f64, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!( - "Approving withdrawal from {} to the Fund {}...", - user_address, fund - ); - info!( - "Signature: {}", - client - .approve_withdrawal_fund( - config.keypair.as_ref(), - fund, - user_address, - token_name, - ui_amount - ) - .unwrap() - ); - } - info!("Done.") -} - -pub fn deny_withdrawal( - client: &FarmClient, - config: &Config, - fund_names: &str, - user_address: &Pubkey, - token_name: &str, - deny_reason: &str, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!( - "Denying withdrawal from {} to the Fund {}...", - user_address, fund - ); - info!( - "Signature: {}", - client - .deny_withdrawal_fund( - config.keypair.as_ref(), - fund, - user_address, - token_name, - deny_reason - ) - .unwrap() - ); - } - info!("Done.") -} - -pub fn lock_assets( - client: &FarmClient, - config: &Config, - fund_names: &str, - token_name: &str, - ui_amount: f64, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!("Moving {} to the Fund {}...", token_name, fund); - info!( - "Signature: {}", - client - .lock_assets_fund(config.keypair.as_ref(), fund, token_name, ui_amount) - .unwrap() - ); - } - info!("Done.") -} - -pub fn unlock_assets( - client: &FarmClient, - config: &Config, - fund_names: &str, - token_name: &str, - ui_amount: f64, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!("Moving {} out of the Fund {}...", token_name, fund); - info!( - "Signature: {}", - client - .unlock_assets_fund(config.keypair.as_ref(), fund, token_name, ui_amount) - .unwrap() - ); - } - info!("Done.") -} - -pub fn withdraw_fees( - client: &FarmClient, - config: &Config, - fund_names: &str, - token_name: &str, - custody_type: FundCustodyType, - ui_amount: f64, - receiver: &Pubkey, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!( - "Withdrawing fees from {} {} custody of the Fund {} to {}...", - token_name, custody_type, fund, receiver - ); - info!( - "Signature: {}", - client - .withdraw_fees_fund( - config.keypair.as_ref(), - fund, - token_name, - custody_type, - ui_amount, - receiver - ) - .unwrap() - ); - } - info!("Done.") -} - -pub fn update_assets_with_custody( - client: &FarmClient, - config: &Config, - fund_names: &str, - custody_id: u32, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!("Updating assets with custody for the Fund {}...", fund); - info!( - "Signature: {}", - client - .update_fund_assets_with_custody(config.keypair.as_ref(), fund, custody_id) - .unwrap() - ); - } - info!("Done.") -} - -pub fn update_assets_with_custodies(client: &FarmClient, config: &Config, fund_names: &str) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!("Updating assets with custodies for the Fund {}...", fund); - info!( - "Updated: {} custodies processed", - client - .update_fund_assets_with_custodies(config.keypair.as_ref(), fund) - .unwrap() - ); - } - info!("Done.") -} - -pub fn update_assets_with_vault( - client: &FarmClient, - config: &Config, - fund_names: &str, - vault_id: u32, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!("Updating assets with Vault for the Fund {}...", fund); - info!( - "Signature: {}", - client - .update_fund_assets_with_vault(config.keypair.as_ref(), fund, vault_id) - .unwrap() - ); - } - info!("Done.") -} - -pub fn update_assets_with_vaults(client: &FarmClient, config: &Config, fund_names: &str) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!("Updating assets with Vaults for the Fund {}...", fund); - info!( - "Updated: {} Vaults processed", - client - .update_fund_assets_with_vaults(config.keypair.as_ref(), fund) - .unwrap() - ); - } - info!("Done.") -} - -pub fn stop_liquidation(client: &FarmClient, config: &Config, fund_names: &str) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!("Stopping liquidation of the Fund {}...", fund); - info!( - "Signature: {}", - client - .stop_liquidation_fund(config.keypair.as_ref(), fund) - .unwrap() - ); - } - info!("Done.") -} - -pub fn add_liquidity_pool( - client: &FarmClient, - config: &Config, - fund_names: &str, - pool_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!( - "Adding liquidity to the Pool {} in the Fund {}...", - pool_name, fund - ); - info!( - "Signature: {}", - client - .fund_add_liquidity_pool( - config.keypair.as_ref(), - fund, - pool_name, - max_token_a_ui_amount, - max_token_b_ui_amount - ) - .unwrap() - ); - } - info!("Done.") -} - -pub fn remove_liquidity_pool( - client: &FarmClient, - config: &Config, - fund_names: &str, - pool_name: &str, - ui_amount: f64, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!( - "Removing liquidity from the Pool {} in the Fund {}...", - pool_name, fund - ); - info!( - "Signature: {}", - client - .fund_remove_liquidity_pool(config.keypair.as_ref(), fund, pool_name, ui_amount) - .unwrap() - ); - } - info!("Done.") -} - -#[allow(clippy::too_many_arguments)] -pub fn swap( - client: &FarmClient, - config: &Config, - fund_names: &str, - protocol: Protocol, - from_token: &str, - to_token: &str, - ui_amount_in: f64, - min_ui_amount_out: f64, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!( - "Swapping {} to {} in the Fund {}...", - from_token, to_token, fund - ); - info!( - "Signature: {}", - client - .fund_swap( - config.keypair.as_ref(), - fund, - protocol, - from_token, - to_token, - ui_amount_in, - min_ui_amount_out - ) - .unwrap() - ); - } - info!("Done.") -} - -pub fn stake( - client: &FarmClient, - config: &Config, - fund_names: &str, - farm_name: &str, - ui_amount: f64, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!( - "Staking tokens to the Farm {} in the Fund {}...", - farm_name, fund - ); - info!( - "Signature: {}", - client - .fund_stake(config.keypair.as_ref(), fund, farm_name, ui_amount) - .unwrap() - ); - } - info!("Done.") -} - -pub fn unstake( - client: &FarmClient, - config: &Config, - fund_names: &str, - farm_name: &str, - ui_amount: f64, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!( - "Unstaking tokens from the Farm {} in the Fund {}...", - farm_name, fund - ); - info!( - "Signature: {}", - client - .fund_unstake(config.keypair.as_ref(), fund, farm_name, ui_amount) - .unwrap() - ); - } - info!("Done.") -} - -pub fn harvest(client: &FarmClient, config: &Config, fund_names: &str, farm_name: &str) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!( - "Harvesting rewards from the Farm {} in the Fund {}...", - farm_name, fund - ); - info!( - "Signature: {}", - client - .fund_harvest(config.keypair.as_ref(), fund, farm_name) - .unwrap() - ); - } - info!("Done.") -} - -pub fn add_liquidity_vault( - client: &FarmClient, - config: &Config, - fund_names: &str, - vault_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!( - "Adding liquidity to the Vault {} in the Fund {}...", - vault_name, fund - ); - info!( - "Signature: {}", - client - .fund_add_liquidity_vault( - config.keypair.as_ref(), - fund, - vault_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - ) - .unwrap() - ); - } - info!("Done.") -} - -pub fn add_locked_liquidity_vault( - client: &FarmClient, - config: &Config, - fund_names: &str, - vault_name: &str, - ui_amount: f64, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!( - "Adding locked liquidity to the Vault {} in the Fund {}...", - vault_name, fund - ); - info!( - "Signature: {}", - client - .fund_add_locked_liquidity_vault( - config.keypair.as_ref(), - fund, - vault_name, - ui_amount, - ) - .unwrap() - ); - } - info!("Done.") -} - -pub fn remove_liquidity_vault( - client: &FarmClient, - config: &Config, - fund_names: &str, - vault_name: &str, - ui_amount: f64, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!( - "Removing liquidity from the Vault {} in the Fund {}...", - vault_name, fund - ); - info!( - "Signature: {}", - client - .fund_remove_liquidity_vault(config.keypair.as_ref(), fund, vault_name, ui_amount,) - .unwrap() - ); - } - info!("Done.") -} - -pub fn remove_unlocked_liquidity_vault( - client: &FarmClient, - config: &Config, - fund_names: &str, - vault_name: &str, - ui_amount: f64, -) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!( - "Removing unlocked liquidity from the Vault {} in the Fund {}...", - vault_name, fund - ); - info!( - "Signature: {}", - client - .fund_remove_unlocked_liquidity_vault( - config.keypair.as_ref(), - fund, - vault_name, - ui_amount, - ) - .unwrap() - ); - } - info!("Done.") -} - -pub fn get_info(client: &FarmClient, config: &Config, fund_names: &str) { - let funds = fund_names.split(',').collect::>(); - for fund in funds { - info!("Retreiving stats for Fund {}...", fund); - - let info = client.get_fund_info(fund).unwrap(); - - if config.no_pretty_print { - println!("{}", info); - } else { - println!("{}", to_pretty_json(&info).unwrap()); - } - } - info!("Done.") -} diff --git a/farms/farm-ctrl/src/generate.rs b/farms/farm-ctrl/src/generate.rs deleted file mode 100644 index 45496c97ab4..00000000000 --- a/farms/farm-ctrl/src/generate.rs +++ /dev/null @@ -1,677 +0,0 @@ -//! Handlers for generate command - -use { - crate::config::Config, - log::info, - serde_json::Value, - solana_farm_client::client::FarmClient, - solana_farm_sdk::{ - farm::{FarmRoute, FarmType}, - fund::{Fund, FundType}, - id::zero, - pool::PoolRoute, - refdb::{find_target_pda, StorageType}, - string::{str_to_as64, to_pretty_json}, - token::GitToken, - vault::{Vault, VaultStrategy, VaultType}, - Protocol, - }, - solana_sdk::pubkey::Pubkey, - std::collections::HashMap, - std::str::FromStr, -}; - -pub fn generate_fund( - _client: &FarmClient, - _config: &Config, - fund_address: &Pubkey, - fund_name: &str, - token_name: &str, -) { - let fund = Fund { - name: str_to_as64(fund_name).unwrap(), - version: 1, - fund_type: FundType::General, - official: true, - refdb_index: None, - refdb_counter: 0, - metadata_bump: find_target_pda(StorageType::Fund, &str_to_as64(fund_name).unwrap()).1, - authority_bump: Pubkey::find_program_address( - &[b"fund_authority", fund_name.as_bytes()], - fund_address, - ) - .1, - fund_token_bump: Pubkey::find_program_address( - &[b"fund_token_mint", fund_name.as_bytes()], - fund_address, - ) - .1, - multisig_bump: Pubkey::find_program_address( - &[b"multisig", fund_name.as_bytes()], - fund_address, - ) - .1, - fund_program_id: *fund_address, - fund_authority: Pubkey::find_program_address( - &[b"fund_authority", fund_name.as_bytes()], - fund_address, - ) - .0, - fund_manager: zero::id(), - fund_token_ref: find_target_pda(StorageType::Token, &str_to_as64(token_name).unwrap()).0, - info_account: Pubkey::find_program_address( - &[b"info_account", fund_name.as_bytes()], - fund_address, - ) - .0, - multisig_account: Pubkey::find_program_address( - &[b"multisig", fund_name.as_bytes()], - fund_address, - ) - .0, - vaults_assets_info: Pubkey::find_program_address( - &[b"vaults_assets_info", fund_name.as_bytes()], - fund_address, - ) - .0, - custodies_assets_info: Pubkey::find_program_address( - &[b"custodies_assets_info", fund_name.as_bytes()], - fund_address, - ) - .0, - description_account: Pubkey::find_program_address( - &[b"description_account", fund_name.as_bytes()], - fund_address, - ) - .0, - }; - println!("{}", to_pretty_json(&fund).unwrap()); - - let token = GitToken { - chain_id: 101, - address: Pubkey::find_program_address( - &[b"fund_token_mint", fund_name.as_bytes()], - fund_address, - ) - .0, - symbol: token_name.to_string(), - name: fund_name.to_string() + " Token", - decimals: 6, - logo_uri: String::default(), - tags: vec!["fund-token".to_string()], - extra: HashMap::::default(), - }; - println!("{}", to_pretty_json(&token).unwrap()); -} - -pub fn generate_rdm_stc_vault( - client: &FarmClient, - _config: &Config, - vault_address: &Pubkey, - vault_name: &str, - token_name: &str, -) { - let farm_name = "RDM.".to_string() + vault_name.split('.').collect::>()[2]; - let farm = client.get_farm(&farm_name).unwrap(); - let lp_token = client - .get_token_by_ref(&farm.lp_token_ref.unwrap()) - .unwrap(); - let pool = client.find_pools_with_lp(lp_token.name.as_str()).unwrap()[0]; - let farm_second_reward_token_account = match farm.route { - FarmRoute::Raydium { - farm_second_reward_token_account, - .. - } => farm_second_reward_token_account, - _ => None, - }; - let vault = Vault { - name: str_to_as64(vault_name).unwrap(), - version: 1, - vault_type: VaultType::AmmStake, - official: true, - refdb_index: None, - refdb_counter: 0, - metadata_bump: find_target_pda(StorageType::Vault, &str_to_as64(vault_name).unwrap()).1, - authority_bump: Pubkey::find_program_address( - &[b"vault_authority", vault_name.as_bytes()], - vault_address, - ) - .1, - vault_token_bump: Pubkey::find_program_address( - &[b"vault_token_mint", vault_name.as_bytes()], - vault_address, - ) - .1, - lock_required: true, - unlock_required: true, - vault_program_id: *vault_address, - vault_authority: Pubkey::find_program_address( - &[b"vault_authority", vault_name.as_bytes()], - vault_address, - ) - .0, - vault_token_ref: find_target_pda(StorageType::Token, &str_to_as64(token_name).unwrap()).0, - info_account: Pubkey::find_program_address( - &[b"info_account", vault_name.as_bytes()], - vault_address, - ) - .0, - multisig_account: Pubkey::find_program_address( - &[b"multisig", vault_name.as_bytes()], - vault_address, - ) - .0, - fees_account_a: Some( - Pubkey::find_program_address( - &[b"fees_account_a", vault_name.as_bytes()], - vault_address, - ) - .0, - ), - fees_account_b: if farm.farm_type == FarmType::DualReward - || farm_second_reward_token_account.is_some() - { - Some( - Pubkey::find_program_address( - &[b"fees_account_b", vault_name.as_bytes()], - vault_address, - ) - .0, - ) - } else { - None - }, - strategy: VaultStrategy::StakeLpCompoundRewards { - pool_router_id: pool.router_program_id, - pool_id: match pool.route { - PoolRoute::Raydium { amm_id, .. } => amm_id, - PoolRoute::Saber { swap_account, .. } => swap_account, - PoolRoute::Orca { amm_id, .. } => amm_id, - }, - pool_ref: client.get_pool_ref(&pool.name).unwrap(), - farm_router_id: farm.router_program_id, - farm_id: match farm.route { - FarmRoute::Raydium { farm_id, .. } => farm_id, - FarmRoute::Saber { quarry, .. } => quarry, - FarmRoute::Orca { farm_id, .. } => farm_id, - }, - farm_ref: client.get_farm_ref(&farm.name).unwrap(), - lp_token_custody: Pubkey::find_program_address( - &[b"lp_token_custody", vault_name.as_bytes()], - vault_address, - ) - .0, - token_a_custody: Pubkey::find_program_address( - &[b"token_a_custody", vault_name.as_bytes()], - vault_address, - ) - .0, - token_b_custody: Some( - Pubkey::find_program_address( - &[b"token_b_custody", vault_name.as_bytes()], - vault_address, - ) - .0, - ), - token_a_reward_custody: Pubkey::find_program_address( - &[b"token_a_reward_custody", vault_name.as_bytes()], - vault_address, - ) - .0, - token_b_reward_custody: if farm.farm_type == FarmType::DualReward - || farm_second_reward_token_account.is_some() - { - Some( - Pubkey::find_program_address( - &[b"token_b_reward_custody", vault_name.as_bytes()], - vault_address, - ) - .0, - ) - } else { - None - }, - vault_stake_info: if farm.version < 4 { - Pubkey::find_program_address( - &[b"vault_stake_info", vault_name.as_bytes()], - vault_address, - ) - .0 - } else { - Pubkey::find_program_address( - &[b"vault_stake_info_v4", vault_name.as_bytes()], - vault_address, - ) - .0 - }, - vault_stake_custody: None, - reward_exchange_pool_id: None, - reward_exchange_pool_ref: None, - }, - }; - println!("{},", to_pretty_json(&vault).unwrap()); - - let token = GitToken { - chain_id: 101, - address: Pubkey::find_program_address( - &[b"vault_token_mint", vault_name.as_bytes()], - vault_address, - ) - .0, - symbol: token_name.to_string(), - name: "Raydium ".to_string() - + token_name.split('.').collect::>()[3] - + " Stake Compound Vault Token", - decimals: client - .get_token_by_ref(&farm.lp_token_ref.unwrap()) - .unwrap() - .decimals as i32, - logo_uri: String::default(), - tags: vec!["vt-token".to_string()], - extra: HashMap::::default(), - }; - println!("{}", to_pretty_json(&token).unwrap()); -} - -pub fn generate_sbr_stc_vault( - client: &FarmClient, - _config: &Config, - vault_address: &Pubkey, - vault_name: &str, - token_name: &str, -) { - let farm_name = "SBR.".to_string() + vault_name.split('.').collect::>()[2]; - let farm = client.get_farm(&farm_name).unwrap(); - let lp_token = client - .get_token_by_ref(&farm.lp_token_ref.unwrap()) - .unwrap(); - let pool = client.find_pools_with_lp(lp_token.name.as_str()).unwrap()[0]; - let (is_token_a_wrapped, is_token_b_wrapped) = client - .pool_has_saber_wrapped_tokens(pool.name.as_str()) - .unwrap(); - let token_a = client.get_token_by_ref(&pool.token_a_ref.unwrap()).unwrap(); - let token_b = client.get_token_by_ref(&pool.token_b_ref.unwrap()).unwrap(); - if &token_a.name == "SECRET" || &token_b.name == "SECRET" { - panic!("Vaults with secret token pools are not supported"); - } - let usdc_token = client.get_token("USDC").unwrap(); - if token_a.mint != usdc_token.mint && token_b.mint != usdc_token.mint { - panic!("Only USDC pools are supported",); - }; - let quarry = match farm.route { - FarmRoute::Saber { quarry, .. } => quarry, - _ => unreachable!(), - }; - let (vault_authority, authority_bump) = - Pubkey::find_program_address(&[b"vault_authority", vault_name.as_bytes()], vault_address); - - let vault = Vault { - name: str_to_as64(vault_name).unwrap(), - version: 1, - vault_type: VaultType::AmmStake, - official: true, - refdb_index: None, - refdb_counter: 0, - metadata_bump: find_target_pda(StorageType::Vault, &str_to_as64(vault_name).unwrap()).1, - authority_bump, - vault_token_bump: Pubkey::find_program_address( - &[b"vault_token_mint", vault_name.as_bytes()], - vault_address, - ) - .1, - lock_required: true, - unlock_required: false, - vault_program_id: *vault_address, - vault_authority, - vault_token_ref: find_target_pda(StorageType::Token, &str_to_as64(token_name).unwrap()).0, - info_account: Pubkey::find_program_address( - &[b"info_account", vault_name.as_bytes()], - vault_address, - ) - .0, - multisig_account: Pubkey::find_program_address( - &[b"multisig", vault_name.as_bytes()], - vault_address, - ) - .0, - fees_account_a: Some( - Pubkey::find_program_address( - &[b"fees_account_a", vault_name.as_bytes()], - vault_address, - ) - .0, - ), - fees_account_b: Some( - Pubkey::find_program_address( - &[b"fees_account_b", vault_name.as_bytes()], - vault_address, - ) - .0, - ), - strategy: VaultStrategy::StakeLpCompoundRewards { - pool_router_id: pool.router_program_id, - pool_id: match pool.route { - PoolRoute::Raydium { amm_id, .. } => amm_id, - PoolRoute::Saber { swap_account, .. } => swap_account, - PoolRoute::Orca { amm_id, .. } => amm_id, - }, - pool_ref: client.get_pool_ref(&pool.name).unwrap(), - farm_router_id: farm.router_program_id, - farm_id: match farm.route { - FarmRoute::Raydium { farm_id, .. } => farm_id, - FarmRoute::Saber { quarry, .. } => quarry, - FarmRoute::Orca { farm_id, .. } => farm_id, - }, - farm_ref: client.get_farm_ref(&farm.name).unwrap(), - lp_token_custody: Pubkey::find_program_address( - &[b"lp_token_custody", vault_name.as_bytes()], - vault_address, - ) - .0, - token_a_custody: Pubkey::find_program_address( - &[b"token_a_custody", vault_name.as_bytes()], - vault_address, - ) - .0, - token_b_custody: if is_token_a_wrapped || is_token_b_wrapped { - Some( - Pubkey::find_program_address( - &[b"token_b_custody", vault_name.as_bytes()], - vault_address, - ) - .0, - ) - } else { - None - }, - token_a_reward_custody: Pubkey::find_program_address( - &[b"token_a_reward_custody", vault_name.as_bytes()], - vault_address, - ) - .0, - token_b_reward_custody: Some( - Pubkey::find_program_address( - &[b"token_b_reward_custody", vault_name.as_bytes()], - vault_address, - ) - .0, - ), - vault_stake_info: Pubkey::find_program_address( - &[b"Miner", &quarry.to_bytes(), &vault_authority.to_bytes()], - &quarry_mine::id(), - ) - .0, - vault_stake_custody: None, - reward_exchange_pool_id: None, - reward_exchange_pool_ref: None, - }, - }; - println!("{},", to_pretty_json(&vault).unwrap()); - - let token = GitToken { - chain_id: 101, - address: Pubkey::find_program_address( - &[b"vault_token_mint", vault_name.as_bytes()], - vault_address, - ) - .0, - symbol: token_name.to_string(), - name: "Saber ".to_string() - + token_name.split('.').collect::>()[3] - + " Stake Compound Vault Token", - decimals: client - .get_token_by_ref(&farm.lp_token_ref.unwrap()) - .unwrap() - .decimals as i32, - logo_uri: String::default(), - tags: vec!["vt-token".to_string()], - extra: HashMap::::default(), - }; - println!("{}", to_pretty_json(&token).unwrap()); -} - -pub fn generate_orc_stc_vault( - client: &FarmClient, - _config: &Config, - vault_address: &Pubkey, - vault_name: &str, - token_name: &str, -) { - let farm_name = "ORC.".to_string() + vault_name.split('.').collect::>()[2]; - if farm_name.contains("-DD-") { - panic!("Orca Double Dip Farms are not yet supported"); - } - let farm = client.get_farm(&farm_name).unwrap(); - let farm_id = match farm.route { - FarmRoute::Raydium { farm_id, .. } => farm_id, - FarmRoute::Saber { quarry, .. } => quarry, - FarmRoute::Orca { farm_id, .. } => farm_id, - }; - let lp_token = client - .get_token_by_ref(&farm.lp_token_ref.unwrap()) - .unwrap(); - let pool = client.find_pools_with_lp(lp_token.name.as_str()).unwrap()[0]; - let vault_authority = - Pubkey::find_program_address(&[b"vault_authority", vault_name.as_bytes()], vault_address).0; - - // check if rewards are not in pool tokens, extra swap will be required in such case - let mut reward_exchange_pool_id = None; - let mut reward_exchange_pool_ref = None; - let pool_token_a = client.get_token_by_ref(&pool.token_a_ref.unwrap()).unwrap(); - let pool_token_b = client.get_token_by_ref(&pool.token_b_ref.unwrap()).unwrap(); - let reward_token = client - .get_token_by_ref(&farm.first_reward_token_ref.unwrap()) - .unwrap(); - if pool_token_a.mint != reward_token.mint && pool_token_b.mint != reward_token.mint { - // look-up for pools to swap from reward token to either token a or b - let pools_a = client - .find_pools(Protocol::Orca, &reward_token.name, &pool_token_a.name) - .unwrap_or_default(); - let pools_b = client - .find_pools(Protocol::Orca, &reward_token.name, &pool_token_b.name) - .unwrap_or_default(); - let rd_ex_pool = if !pools_a.is_empty() && !pools_b.is_empty() { - // if multiple pools exists pick the one with the largest lp supply - let lp_token_a = client - .get_token_by_ref(&pools_a[0].lp_token_ref.unwrap()) - .unwrap(); - let lp_token_b = client - .get_token_by_ref(&pools_b[0].lp_token_ref.unwrap()) - .unwrap(); - let lp_supply_a = client.get_token_supply(&lp_token_a.name).unwrap(); - let lp_supply_b = client.get_token_supply(&lp_token_b.name).unwrap(); - if lp_supply_a >= lp_supply_b { - pools_a[0] - } else { - pools_b[0] - } - } else if !pools_a.is_empty() { - pools_a[0] - } else if !pools_b.is_empty() { - pools_b[0] - } else { - panic!( - "No Orca pools found to convert from {} to {} or {}", - reward_token.name, pool_token_a.name, pool_token_b.name - ); - }; - reward_exchange_pool_id = match rd_ex_pool.route { - PoolRoute::Orca { amm_id, .. } => Some(amm_id), - _ => unreachable!(), - }; - reward_exchange_pool_ref = Some(client.get_pool_ref(&rd_ex_pool.name).unwrap()); - } - - let vault = Vault { - name: str_to_as64(vault_name).unwrap(), - version: 1, - vault_type: VaultType::AmmStake, - official: true, - refdb_index: None, - refdb_counter: 0, - metadata_bump: find_target_pda(StorageType::Vault, &str_to_as64(vault_name).unwrap()).1, - authority_bump: Pubkey::find_program_address( - &[b"vault_authority", vault_name.as_bytes()], - vault_address, - ) - .1, - vault_token_bump: Pubkey::find_program_address( - &[b"vault_token_mint", vault_name.as_bytes()], - vault_address, - ) - .1, - lock_required: true, - unlock_required: true, - vault_program_id: *vault_address, - vault_authority, - vault_token_ref: find_target_pda(StorageType::Token, &str_to_as64(token_name).unwrap()).0, - info_account: Pubkey::find_program_address( - &[b"info_account", vault_name.as_bytes()], - vault_address, - ) - .0, - multisig_account: Pubkey::find_program_address( - &[b"multisig", vault_name.as_bytes()], - vault_address, - ) - .0, - fees_account_a: Some( - Pubkey::find_program_address(&[b"fees_account", vault_name.as_bytes()], vault_address) - .0, - ), - fees_account_b: None, - strategy: VaultStrategy::StakeLpCompoundRewards { - pool_router_id: pool.router_program_id, - pool_id: match pool.route { - PoolRoute::Raydium { amm_id, .. } => amm_id, - PoolRoute::Saber { swap_account, .. } => swap_account, - PoolRoute::Orca { amm_id, .. } => amm_id, - }, - pool_ref: client.get_pool_ref(&pool.name).unwrap(), - farm_router_id: farm.router_program_id, - farm_id, - farm_ref: client.get_farm_ref(&farm.name).unwrap(), - lp_token_custody: Pubkey::find_program_address( - &[b"lp_token_custody", vault_name.as_bytes()], - vault_address, - ) - .0, - token_a_custody: Pubkey::find_program_address( - &[b"token_a_custody", vault_name.as_bytes()], - vault_address, - ) - .0, - token_b_custody: Some( - Pubkey::find_program_address( - &[b"token_b_custody", vault_name.as_bytes()], - vault_address, - ) - .0, - ), - token_a_reward_custody: Pubkey::find_program_address( - &[b"reward_token_custody", vault_name.as_bytes()], - vault_address, - ) - .0, - token_b_reward_custody: None, - vault_stake_info: Pubkey::find_program_address( - &[ - &farm_id.to_bytes(), - &vault_authority.to_bytes(), - &spl_token::id().to_bytes(), - ], - &farm.farm_program_id, - ) - .0, - vault_stake_custody: Some( - Pubkey::find_program_address( - &[b"vault_stake_custody", vault_name.as_bytes()], - vault_address, - ) - .0, - ), - reward_exchange_pool_id, - reward_exchange_pool_ref, - }, - }; - println!("{},", to_pretty_json(&vault).unwrap()); - - let token = GitToken { - chain_id: 101, - address: Pubkey::find_program_address( - &[b"vault_token_mint", vault_name.as_bytes()], - vault_address, - ) - .0, - symbol: token_name.to_string(), - name: "Orca ".to_string() - + token_name.split('.').collect::>()[3] - + " Stake Compound Vault Token", - decimals: client - .get_token_by_ref(&farm.lp_token_ref.unwrap()) - .unwrap() - .decimals as i32, - logo_uri: String::default(), - tags: vec!["vt-token".to_string()], - extra: HashMap::::default(), - }; - println!("{}", to_pretty_json(&token).unwrap()); -} - -pub fn generate( - client: &FarmClient, - config: &Config, - target: StorageType, - object: &str, - param1: &str, - param2: &str, -) { - info!( - "Generating json boilerplate for {} {} {}...", - target, object, param1 - ); - - match target { - StorageType::Vault => { - if param1.starts_with("RDM.") { - generate_rdm_stc_vault( - client, - config, - &Pubkey::from_str(object).unwrap(), - param1, - param2, - ); - } else if param1.starts_with("SBR.") { - generate_sbr_stc_vault( - client, - config, - &Pubkey::from_str(object).unwrap(), - param1, - param2, - ); - } else if param1.starts_with("ORC.") { - generate_orc_stc_vault( - client, - config, - &Pubkey::from_str(object).unwrap(), - param1, - param2, - ); - } else { - panic!("Unexpected Vault name: {}", param1); - } - } - StorageType::Fund => generate_fund( - client, - config, - &Pubkey::from_str(object).unwrap(), - param1, - param2, - ), - _ => { - panic!("Target is not supported: {}", target); - } - } - - info!("Done.") -} diff --git a/farms/farm-ctrl/src/get.rs b/farms/farm-ctrl/src/get.rs deleted file mode 100644 index 43a5bd59cf4..00000000000 --- a/farms/farm-ctrl/src/get.rs +++ /dev/null @@ -1,200 +0,0 @@ -//! Handlers for get and get_all command - -use { - crate::config::Config, - log::info, - serde::Serialize, - solana_farm_client::client::FarmClient, - solana_farm_sdk::{refdb::StorageType, string::to_pretty_json}, - solana_sdk::pubkey::Pubkey, - std::str::FromStr, -}; - -pub fn get(client: &FarmClient, config: &Config, target: StorageType, object: &str) { - info!("Querying {} object {}...", target, object); - - match target { - StorageType::Program => { - println!("{}: {}", object, client.get_program_id(object).unwrap()); - } - StorageType::Fund => { - print_object( - config, - &client.get_fund_ref(&object.to_uppercase()).unwrap(), - &client.get_fund(&object.to_uppercase()).unwrap(), - ); - } - StorageType::Vault => { - print_object( - config, - &client.get_vault_ref(&object.to_uppercase()).unwrap(), - &client.get_vault(&object.to_uppercase()).unwrap(), - ); - } - StorageType::Farm => { - print_object( - config, - &client.get_farm_ref(&object.to_uppercase()).unwrap(), - &client.get_farm(&object.to_uppercase()).unwrap(), - ); - } - StorageType::Pool => { - print_object( - config, - &client.get_pool_ref(&object.to_uppercase()).unwrap(), - &client.get_pool(&object.to_uppercase()).unwrap(), - ); - } - StorageType::Token => { - print_object( - config, - &client.get_token_ref(&object.to_uppercase()).unwrap(), - &client.get_token(&object.to_uppercase()).unwrap(), - ); - } - _ => { - unreachable!(); - } - } - - info!("Done.") -} - -pub fn get_ref(client: &FarmClient, config: &Config, target: StorageType, object: &str) { - info!("Querying {} object {}...", target, object); - - let pubkey = Pubkey::from_str(object).unwrap(); - - match target { - StorageType::Program => { - println!("{}: {}", client.get_program_name(&pubkey).unwrap(), object); - } - StorageType::Fund => { - print_object(config, &pubkey, &client.get_fund_by_ref(&pubkey).unwrap()); - } - StorageType::Vault => { - print_object(config, &pubkey, &client.get_vault_by_ref(&pubkey).unwrap()); - } - StorageType::Farm => { - print_object(config, &pubkey, &client.get_farm_by_ref(&pubkey).unwrap()); - } - StorageType::Pool => { - print_object(config, &pubkey, &client.get_pool_by_ref(&pubkey).unwrap()); - } - StorageType::Token => { - print_object(config, &pubkey, &client.get_token_by_ref(&pubkey).unwrap()); - } - _ => { - unreachable!(); - } - } - - info!("Done.") -} - -pub fn get_all(client: &FarmClient, config: &Config, target: StorageType) { - info!("Querying all {} objects...", target); - - match target { - StorageType::Program => { - let storage = client.get_program_ids().unwrap(); - for (name, key) in storage.iter() { - println!("{}: {}", name, key); - } - } - StorageType::Fund => { - let storage = client.get_funds().unwrap(); - for (name, key) in storage.iter() { - print_object(config, &client.get_fund_ref(name).unwrap(), key); - } - } - StorageType::Vault => { - let storage = client.get_vaults().unwrap(); - for (name, key) in storage.iter() { - print_object(config, &client.get_vault_ref(name).unwrap(), key); - } - } - StorageType::Farm => { - let storage = client.get_farms().unwrap(); - for (name, key) in storage.iter() { - print_object(config, &client.get_farm_ref(name).unwrap(), key); - } - } - StorageType::Pool => { - let storage = client.get_pools().unwrap(); - for (name, key) in storage.iter() { - print_object(config, &client.get_pool_ref(name).unwrap(), key); - } - } - StorageType::Token => { - let storage = client.get_tokens().unwrap(); - for (name, key) in storage.iter() { - print_object(config, &client.get_token_ref(name).unwrap(), key); - } - } - _ => { - unreachable!(); - } - } - - info!("Done.") -} - -pub fn list_all(client: &FarmClient, _config: &Config, target: StorageType) { - info!("Querying all {} objects...", target); - - match target { - StorageType::Program => { - let storage = client.get_program_ids().unwrap(); - for (name, key) in storage.iter() { - println!("{}: {}", name, key); - } - } - StorageType::Fund => { - let storage = client.get_fund_refs().unwrap(); - for (name, key) in storage.iter() { - println!("{}: {}", name, key); - } - } - StorageType::Vault => { - let storage = client.get_vault_refs().unwrap(); - for (name, key) in storage.iter() { - println!("{}: {}", name, key); - } - } - StorageType::Farm => { - let storage = client.get_farm_refs().unwrap(); - for (name, key) in storage.iter() { - println!("{}: {}", name, key); - } - } - StorageType::Pool => { - let storage = client.get_pool_refs().unwrap(); - for (name, key) in storage.iter() { - println!("{}: {}", name, key); - } - } - StorageType::Token => { - let storage = client.get_token_refs().unwrap(); - for (name, key) in storage.iter() { - println!("{}: {}", name, key); - } - } - _ => { - unreachable!(); - } - } - - info!("Done.") -} - -fn print_object(config: &Config, key: &Pubkey, object: &T) -where - T: ?Sized + Serialize + std::fmt::Display, -{ - if config.no_pretty_print { - println!("{}: {}", key, object); - } else { - println!("{}: {}", key, to_pretty_json(object).unwrap()); - } -} diff --git a/farms/farm-ctrl/src/governance.rs b/farms/farm-ctrl/src/governance.rs deleted file mode 100644 index 1a2ae7d8f1a..00000000000 --- a/farms/farm-ctrl/src/governance.rs +++ /dev/null @@ -1,347 +0,0 @@ -//! Handler for the governance commands - -use { - crate::config::Config, - log::info, - solana_farm_client::client::FarmClient, - solana_farm_sdk::{ - id::*, - refdb, - refdb::StorageType, - string::str_to_as64, - token::{OracleType, Token, TokenType}, - ProgramIDType, - }, - solana_sdk::{program_pack::Pack, pubkey::Pubkey}, - spl_associated_token_account::{create_associated_token_account, get_associated_token_address}, - spl_governance::instruction as dao_instruction, - spl_governance::state::{ - enums::{MintMaxVoteWeightSource, VoteThresholdPercentage, VoteWeightSource}, - governance::{get_account_governance_address, GovernanceConfig}, - realm::get_realm_address, - token_owner_record::get_token_owner_record_address, - }, -}; - -pub fn init(client: &FarmClient, config: &Config, dao_program: &Pubkey, mint_ui_amount: f64) { - info!("Initializing DAO..."); - - let wallet = config.keypair.pubkey(); - if main_router_admin::id() != wallet { - panic!( - "DAO must be initialized with the admin account {}", - main_router_admin::id() - ); - } - if mint_ui_amount < 100.0 { - panic!("Mint amount must be >= 100"); - } - - let mut inst = vec![]; - - info!(" Writing Program \"{}\" to on-chain RefDB...", dao_program); - client - .add_program_id( - config.keypair.as_ref(), - DAO_PROGRAM_NAME, - dao_program, - ProgramIDType::System, - None, - ) - .unwrap(); - - let mint_address = Pubkey::create_with_seed(&wallet, DAO_MINT_NAME, &spl_token::id()).unwrap(); - let mint_size = spl_token::state::Mint::get_packed_len(); - let dao_token_address = get_associated_token_address(&wallet, &mint_address); - - if client.rpc_client.get_account_data(&mint_address).is_err() { - info!( - " Creating governance tokens mint at {} and minting {} tokens...", - mint_address, mint_ui_amount - ); - - // record token info to the refdb - let (index, counter) = if let Ok(token) = client.get_token(DAO_TOKEN_NAME) { - (token.refdb_index, token.refdb_counter) - } else { - ( - Some( - client - .get_refdb_last_index(&StorageType::Token.to_string()) - .expect("Token RefDB query error"), - ), - 0u16, - ) - }; - let token = Token { - name: str_to_as64(DAO_TOKEN_NAME).unwrap(), - description: str_to_as64("Solana Farms Governance Token").unwrap(), - token_type: TokenType::SplToken, - refdb_index: index, - refdb_counter: counter, - decimals: 6, - chain_id: 101, - mint: mint_address, - oracle_type: OracleType::Unsupported, - oracle_account: None, - description_account: refdb::find_description_pda(StorageType::Token, DAO_TOKEN_NAME).0, - }; - - inst.push(client.new_instruction_add_token(&wallet, token).unwrap()); - - // initialize governance tokens mint - inst.push( - client - .new_instruction_create_system_account_with_seed( - &wallet, - &wallet, - DAO_MINT_NAME, - 0, - mint_size, - &spl_token::id(), - ) - .unwrap(), - ); - - inst.push( - spl_token::instruction::initialize_mint( - &spl_token::id(), - &mint_address, - &wallet, - Some(&wallet), - 6, - ) - .unwrap(), - ); - - if client - .rpc_client - .get_account_data(&dao_token_address) - .is_err() - { - inst.push(create_associated_token_account( - &wallet, - &wallet, - &mint_address, - )); - } - - // mint governance tokens to admin account first - inst.push( - spl_token::instruction::mint_to( - &spl_token::id(), - &mint_address, - &dao_token_address, - &wallet, - &[], - client - .ui_amount_to_tokens_with_decimals(mint_ui_amount, 6) - .unwrap(), - ) - .unwrap(), - ); - - info!( - " Signature: {}", - client - .sign_and_send_instructions(&[config.keypair.as_ref()], inst.as_slice()) - .unwrap() - ); - } - - info!(" Creating realm and depositing DAO tokens..."); - - // create realm - inst.clear(); - let realm_address = get_realm_address(dao_program, DAO_PROGRAM_NAME); - - if client.rpc_client.get_account_data(&realm_address).is_err() { - inst.push(dao_instruction::create_realm( - dao_program, - &wallet, - &mint_address, - &wallet, - None, - None, - DAO_PROGRAM_NAME.to_string(), - client.ui_amount_to_tokens_with_decimals(1.0, 6).unwrap(), - MintMaxVoteWeightSource::FULL_SUPPLY_FRACTION, - )); - } - - // deposit governance tokens - inst.push(dao_instruction::deposit_governing_tokens( - dao_program, - &realm_address, - &dao_token_address, - &wallet, - &wallet, - &wallet, - client.ui_amount_to_tokens_with_decimals(1.0, 6).unwrap(), - &mint_address, - )); - - info!( - " Signature: {}", - client - .sign_and_send_instructions(&[config.keypair.as_ref()], inst.as_slice()) - .unwrap() - ); - - // create router program governances - info!(" Creating router program governances..."); - inst.clear(); - let dao_config = GovernanceConfig { - vote_threshold_percentage: VoteThresholdPercentage::YesVote(60), - min_community_tokens_to_create_proposal: (mint_ui_amount * 0.01) as u64, - min_instruction_hold_up_time: 0, - max_voting_time: 259200, - vote_weight_source: VoteWeightSource::Deposit, - proposal_cool_off_time: 0, - min_council_tokens_to_create_proposal: 0, - }; - let token_owner = - get_token_owner_record_address(dao_program, &realm_address, &mint_address, &wallet); - for program_name in &[ - DAO_PROGRAM_NAME, - "MainRouter", - "RaydiumRouter", - "SaberRouter", - "OrcaRouter", - ] { - let program = if program_name == &DAO_PROGRAM_NAME { - *dao_program - } else { - client.get_program_id(program_name).unwrap() - }; - inst.push(dao_instruction::create_program_governance( - dao_program, - &realm_address, - &program, - &wallet, - &token_owner, - &wallet, - &wallet, - None, - dao_config.clone(), - true, - )); - } - - info!( - " Signature: {}", - client - .sign_and_send_instructions(&[config.keypair.as_ref()], inst.as_slice()) - .unwrap() - ); - - // create vault program governances - info!(" Creating vault program governances..."); - inst.clear(); - let vaults = client.get_vaults().unwrap(); - for (_vault_name, vault) in vaults { - inst.push(dao_instruction::create_program_governance( - dao_program, - &realm_address, - &vault.vault_program_id, - &wallet, - &token_owner, - &wallet, - &wallet, - None, - dao_config.clone(), - true, - )); - } - - info!( - " Signature: {}", - client - .sign_and_send_instructions(&[config.keypair.as_ref()], inst.as_slice()) - .unwrap() - ); - - // create DAO mint governance - info!(" Creating DAO mint governance..."); - inst.clear(); - inst.push(dao_instruction::create_mint_governance( - dao_program, - &realm_address, - &mint_address, - &wallet, - &token_owner, - &wallet, - &wallet, - None, - dao_config.clone(), - true, - )); - - info!( - " Signature: {}", - client - .sign_and_send_instructions(&[config.keypair.as_ref()], inst.as_slice()) - .unwrap() - ); - - // create token custody governance - info!(" Creating token custody governance..."); - inst.clear(); - let governed_account = - Pubkey::find_program_address(&[DAO_CUSTODY_NAME.as_bytes()], dao_program).0; - let custody_authority = - get_account_governance_address(dao_program, &realm_address, &governed_account); - - // create wsol account for custody authority - if !client.has_active_token_account(&custody_authority, "SOL") { - let wsol_token = client.get_token("SOL").unwrap(); - inst.push(create_associated_token_account( - &wallet, - &custody_authority, - &wsol_token.mint, - )); - } - - inst.push(dao_instruction::create_account_governance( - dao_program, - &realm_address, - &governed_account, - &token_owner, - &wallet, - &wallet, - None, - dao_config, - )); - - inst.push( - client - .new_instruction_transfer(&wallet, &custody_authority, 0.1) - .unwrap(), - ); - - info!( - " Signature: {}", - client - .sign_and_send_instructions(&[config.keypair.as_ref()], inst.as_slice()) - .unwrap() - ); - - // remove realm authority - info!(" Removing realm authority..."); - inst.clear(); - inst.push(dao_instruction::set_realm_authority( - dao_program, - &realm_address, - &wallet, - &None, - )); - - info!( - " Signature: {}", - client - .sign_and_send_instructions(&[config.keypair.as_ref()], inst.as_slice()) - .unwrap() - ); - - info!("Done."); -} diff --git a/farms/farm-ctrl/src/load.rs b/farms/farm-ctrl/src/load.rs deleted file mode 100644 index c7c0ab4e60d..00000000000 --- a/farms/farm-ctrl/src/load.rs +++ /dev/null @@ -1,54 +0,0 @@ -//! Handler for the load command - -use { - crate::{config::Config, loaders}, - log::info, - solana_farm_client::client::FarmClient, - solana_farm_sdk::refdb::StorageType, - std::fs, -}; - -pub fn load( - client: &FarmClient, - config: &Config, - target: StorageType, - filename: &str, - remove_mode: bool, -) { - if !remove_mode { - info!("Loading {} objects from {}...", target, filename); - } else { - info!( - "Removing all {} objects listed in file {}...", - target, filename - ); - } - - let data = fs::read_to_string(filename).unwrap(); - - match target { - StorageType::Program => { - loaders::program::load(client, config, &data, remove_mode); - } - StorageType::Fund => { - loaders::fund::load(client, config, &data, remove_mode); - } - StorageType::Vault => { - loaders::vault::load(client, config, &data, remove_mode); - } - StorageType::Farm => { - loaders::farm::load(client, config, &data, remove_mode); - } - StorageType::Pool => { - loaders::pool::load(client, config, &data, remove_mode); - } - StorageType::Token => { - loaders::token::load(client, config, &data, remove_mode); - } - _ => { - unreachable!(); - } - } - - info!("Done.") -} diff --git a/farms/farm-ctrl/src/loaders/farm.rs b/farms/farm-ctrl/src/loaders/farm.rs deleted file mode 100644 index c5331b12d8b..00000000000 --- a/farms/farm-ctrl/src/loaders/farm.rs +++ /dev/null @@ -1,492 +0,0 @@ -//! Farms loader. - -use { - crate::{config::Config, loaders::utils::*}, - log::info, - serde::Deserialize, - serde_json::{json, Value}, - solana_farm_client::client::FarmClient, - solana_farm_sdk::{ - farm::{Farm, FarmRoute, FarmType}, - pack::{optional_pubkey_deserialize, pubkey_deserialize, pubkey_slice_deserialize}, - program::protocol::orca::OrcaFarmState, - refdb::StorageType, - string::str_to_as64, - token::GitToken, - }, - solana_sdk::{hash::Hasher, pubkey::Pubkey}, - std::str::FromStr, -}; - -#[allow(dead_code)] -#[derive(Deserialize, Debug)] -struct JsonRaydiumFarmLegacy { - name: String, - lp: String, - reward: String, - #[serde(rename = "rewardB", default)] - reward_b: String, - #[serde(rename = "isStake")] - is_stake: bool, - #[allow(dead_code)] - fusion: bool, - legacy: bool, - dual: bool, - version: u8, - #[serde(rename = "programId")] - program_id: String, - #[serde(rename = "poolId", deserialize_with = "pubkey_deserialize")] - farm_id: Pubkey, - #[serde(rename = "poolAuthority", deserialize_with = "pubkey_deserialize")] - farm_authority: Pubkey, - #[serde(rename = "poolLpTokenAccount", deserialize_with = "pubkey_deserialize")] - farm_lp_token_account: Pubkey, - #[serde( - rename = "poolRewardTokenAccount", - deserialize_with = "pubkey_deserialize" - )] - farm_reward_token_account: Pubkey, - #[serde( - rename = "poolRewardTokenAccountB", - deserialize_with = "optional_pubkey_deserialize", - default - )] - farm_reward_token_account_b: Option, -} - -#[allow(dead_code)] -#[derive(Deserialize, Debug)] -struct JsonRaydiumFarm { - #[serde(deserialize_with = "pubkey_deserialize")] - id: Pubkey, - #[serde(rename = "lpMint", deserialize_with = "pubkey_deserialize")] - lp_mint: Pubkey, - #[serde(rename = "rewardMints", deserialize_with = "pubkey_slice_deserialize")] - reward_mints: Vec, - version: u8, - #[serde(rename = "programId", deserialize_with = "pubkey_deserialize")] - program_id: Pubkey, - #[serde(deserialize_with = "pubkey_deserialize")] - authority: Pubkey, - #[serde(rename = "lpVault", deserialize_with = "pubkey_deserialize")] - lp_vault: Pubkey, - #[serde(rename = "rewardVaults", deserialize_with = "pubkey_slice_deserialize")] - reward_vaults: Vec, - upcoming: bool, -} - -#[derive(Deserialize, Debug)] -struct JsonSaberFarm { - #[allow(dead_code)] - name: String, - tokens: Vec, - #[serde(rename = "lpToken")] - lp_token: GitToken, - #[serde(deserialize_with = "pubkey_deserialize")] - quarry: Pubkey, -} - -#[derive(Deserialize, Debug)] -pub struct JsonOrcaFarm { - pub name: String, - #[serde(deserialize_with = "pubkey_deserialize")] - pub address: Pubkey, - #[serde(rename = "farmTokenMint", deserialize_with = "pubkey_deserialize")] - pub farm_token_mint: Pubkey, - #[serde(rename = "rewardTokenMint", deserialize_with = "pubkey_deserialize")] - pub reward_token_mint: Pubkey, - #[serde(rename = "rewardTokenDecimals")] - pub reward_token_decimals: u8, - #[serde(rename = "baseTokenMint", deserialize_with = "pubkey_deserialize")] - pub base_token_mint: Pubkey, - #[serde(rename = "baseTokenDecimals")] - pub base_token_decimals: u8, -} - -pub fn load(client: &FarmClient, config: &Config, data: &str, remove_mode: bool) { - let parsed: Value = serde_json::from_str(data).unwrap(); - let last_index = client - .get_refdb_last_index(&StorageType::Farm.to_string()) - .expect("Farm RefDB query error"); - - if parsed["name"] == "Raydium Farms" { - load_raydium_farm_legacy(client, config, remove_mode, &parsed, last_index); - } else if parsed["name"] == "Raydium Mainnet Farm Pools" { - load_raydium_farm(client, config, remove_mode, &parsed, last_index); - } else if parsed["name"] == "Orca Farms" { - load_orca_farm(client, config, remove_mode, &parsed, last_index); - } else if parsed["pools"] != json!(null) && parsed["addresses"] != json!(null) { - load_saber_farm(client, config, remove_mode, &parsed, last_index); - } else { - panic!("Unsupported farms file"); - } -} - -fn load_raydium_farm_legacy( - client: &FarmClient, - config: &Config, - remove_mode: bool, - parsed: &Value, - last_index: u32, -) { - let mut last_index = last_index; - let router_id = client.get_program_id("RaydiumRouter").unwrap(); - let farms = parsed["farms"].as_array().unwrap(); - for val in farms { - let json_farm: JsonRaydiumFarmLegacy = serde_json::from_value(val.clone()).unwrap(); - let lp_token = client.get_token(&json_farm.lp.to_uppercase()).unwrap(); - let (pool_name, _) = if FarmClient::is_liquidity_token(&lp_token.name) { - FarmClient::extract_pool_name_and_version(&lp_token.name).unwrap() - } else { - ("RDM.".to_string() + &lp_token.name, 0) - }; - let name = format!("{}-V{}", pool_name, json_farm.version); - if !remove_mode { - if json_farm.legacy { - info!("Skipping legacy Farm \"{}\"...", name); - continue; - } - if config.skip_existing && client.get_farm(&name).is_ok() { - info!("Skipping existing Farm \"{}\"...", name); - continue; - } - info!("Writing Farm \"{}\" to on-chain RefDB...", name); - } else { - info!("Removing Farm \"{}\" from on-chain RefDB...", name); - client.remove_farm(config.keypair.as_ref(), &name).unwrap(); - continue; - } - let (index, counter) = if let Ok(farm) = client.get_farm(&name) { - (farm.refdb_index, farm.refdb_counter) - } else { - last_index += 1; - (Some(last_index - 1), 0u16) - }; - let farm = Farm { - name: str_to_as64(&name).unwrap(), - version: json_farm.version as u16, - farm_type: if json_farm.dual { - FarmType::DualReward - } else if json_farm.is_stake { - FarmType::ProtocolTokenStake - } else { - FarmType::SingleReward - }, - official: true, - refdb_index: index, - refdb_counter: counter, - lp_token_ref: Some(client.get_token_ref(&json_farm.lp.to_uppercase()).unwrap()), - first_reward_token_ref: Some( - client - .get_token_ref(&json_farm.reward.to_uppercase()) - .unwrap(), - ), - second_reward_token_ref: if json_farm.reward_b.is_empty() { - None - } else { - Some( - client - .get_token_ref(&json_farm.reward_b.to_uppercase()) - .unwrap(), - ) - }, - router_program_id: router_id, - farm_program_id: convert_raydium_program_id(client, &json_farm.program_id), - route: FarmRoute::Raydium { - farm_id: json_farm.farm_id, - farm_authority: json_farm.farm_authority, - farm_lp_token_account: json_farm.farm_lp_token_account, - farm_first_reward_token_account: json_farm.farm_reward_token_account, - farm_second_reward_token_account: json_farm.farm_reward_token_account_b, - }, - }; - - client.add_farm(config.keypair.as_ref(), farm).unwrap(); - } -} - -fn load_raydium_farm( - client: &FarmClient, - config: &Config, - remove_mode: bool, - parsed: &Value, - last_index: u32, -) { - let mut last_index = last_index; - let router_id = client.get_program_id("RaydiumRouter").unwrap(); - let farms = parsed["official"].as_array().unwrap(); - for val in farms { - let json_farm: JsonRaydiumFarm = serde_json::from_value(val.clone()).unwrap(); - let lp_token = if let Ok(token) = client.get_token_with_mint(&json_farm.lp_mint) { - token - } else { - info!( - "Skipping Farm with unrecognized lp token {}", - json_farm.lp_mint - ); - continue; - }; - let (pool_name, _) = if FarmClient::is_liquidity_token(&lp_token.name) { - FarmClient::extract_pool_name_and_version(&lp_token.name).unwrap() - } else { - ("RDM.".to_string() + &lp_token.name, 0) - }; - let name = format!("{}-V{}", pool_name, json_farm.version); - if !remove_mode { - if config.skip_existing && client.get_farm(&name).is_ok() { - info!("Skipping existing Farm \"{}\"...", name); - continue; - } - info!("Writing Farm \"{}\" to on-chain RefDB...", name); - } else { - info!("Removing Farm \"{}\" from on-chain RefDB...", name); - client.remove_farm(config.keypair.as_ref(), &name).unwrap(); - continue; - } - let (index, counter) = if let Ok(farm) = client.get_farm(&name) { - (farm.refdb_index, farm.refdb_counter) - } else { - last_index += 1; - (Some(last_index - 1), 0u16) - }; - let farm = Farm { - name: str_to_as64(&name).unwrap(), - version: json_farm.version as u16, - farm_type: if json_farm.reward_mints.len() > 1 { - FarmType::DualReward - } else if json_farm.lp_mint - == Pubkey::from_str("4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R").unwrap() - { - FarmType::ProtocolTokenStake - } else { - FarmType::SingleReward - }, - official: true, - refdb_index: index, - refdb_counter: counter, - lp_token_ref: Some(client.get_token_ref(&lp_token.name).unwrap()), - first_reward_token_ref: Some(get_token_ref_with_mint( - client, - &json_farm.reward_mints[0], - )), - second_reward_token_ref: if json_farm.reward_mints.len() < 2 { - None - } else { - Some(get_token_ref_with_mint(client, &json_farm.reward_mints[1])) - }, - router_program_id: router_id, - farm_program_id: json_farm.program_id, - route: FarmRoute::Raydium { - farm_id: json_farm.id, - farm_authority: json_farm.authority, - farm_lp_token_account: json_farm.lp_vault, - farm_first_reward_token_account: json_farm.reward_vaults[0], - farm_second_reward_token_account: if json_farm.reward_vaults.len() < 2 { - None - } else { - Some(json_farm.reward_vaults[1]) - }, - }, - }; - - client.add_farm(config.keypair.as_ref(), farm).unwrap(); - } -} - -fn load_saber_farm( - client: &FarmClient, - config: &Config, - remove_mode: bool, - parsed: &Value, - last_index: u32, -) { - let mut last_index = last_index; - let pools = parsed["pools"].as_array().unwrap(); - let router_id = client.get_program_id("SaberRouter").unwrap(); - - let farm_program_id = client.get_program_id("SaberQuarryMine").unwrap(); - let redeemer_program = client.get_program_id("SaberRedeemer").unwrap(); - let mint_proxy_program = client.get_program_id("SaberMintProxy").unwrap(); - let redeemer = json_to_pubkey(&parsed["addresses"]["redeemer"]); - let sbr_mint = client.get_token("SBR").unwrap().mint; - let sbr_vault = - spl_associated_token_account::get_associated_token_address(&redeemer, &sbr_mint); - let rewarder = json_to_pubkey(&parsed["addresses"]["rewarder"]); - let iou_mint = client.get_token("IOU").unwrap().mint; - let iou_fees_account = - spl_associated_token_account::get_associated_token_address(&rewarder, &iou_mint); - let mint_wrapper = json_to_pubkey(&parsed["addresses"]["mintWrapper"]); - let mint_wrapper_program = client.get_program_id("SaberMintWrapper").unwrap(); - - // minter - let minter = Pubkey::find_program_address( - &[ - b"MintWrapperMinter", - &mint_wrapper.to_bytes(), - &rewarder.to_bytes(), - ], - &mint_wrapper_program, - ) - .0; - - // mint_proxy_authority - let registry_signer = Pubkey::find_program_address(&[], &mint_proxy_program).0; - let mut buffer = vec![]; - buffer.extend_from_slice(®istry_signer.to_bytes()); - buffer.extend_from_slice(b"unversioned"); - buffer.extend_from_slice(&mint_proxy_program.to_bytes()); - let mut hasher = Hasher::default(); - hasher.hash(buffer.as_slice()); - let mint_proxy_authority = Pubkey::new(hasher.result().as_ref()); - - // mint_proxy_state - let mint_proxy_state = Pubkey::find_program_address( - &[b"SaberMintProxy", &mint_proxy_authority.to_bytes()], - &mint_proxy_program, - ) - .0; - - // minter info - let minter_info = - Pubkey::find_program_address(&[b"anchor", &redeemer.to_bytes()], &mint_proxy_program).0; - - for val in pools { - let json_farm: JsonSaberFarm = serde_json::from_value(val.clone()).unwrap(); - let name = get_saber_pool_name(client, &json_farm.tokens[0], &json_farm.tokens[1]); - if !remove_mode { - if config.skip_existing && client.get_farm(&name).is_ok() { - info!("Skipping existing Farm \"{}\"...", name); - continue; - } - info!("Writing Farm \"{}\" to on-chain RefDB...", name); - } else { - info!("Removing Farm \"{}\" from on-chain RefDB...", name); - client.remove_farm(config.keypair.as_ref(), &name).unwrap(); - continue; - } - let (index, counter) = if let Ok(farm) = client.get_farm(&name) { - (farm.refdb_index, farm.refdb_counter) - } else { - last_index += 1; - (Some(last_index - 1), 0u16) - }; - let farm_token_name = get_saber_token_name(client, &json_farm.lp_token); - if json_farm.tokens[0].address - != convert_pubkey(val["swap"]["state"]["tokenA"]["mint"].as_str().unwrap()) - || json_farm.tokens[1].address - != convert_pubkey(val["swap"]["state"]["tokenB"]["mint"].as_str().unwrap()) - { - panic!("Farm metadata mismatch"); - } - let farm = Farm { - name: str_to_as64(&name).unwrap(), - version: 1u16, - farm_type: FarmType::SingleReward, - official: true, - refdb_index: index, - refdb_counter: counter, - lp_token_ref: Some(client.get_token_ref(&farm_token_name).unwrap()), - first_reward_token_ref: Some(client.get_token_ref("SBR").unwrap()), - second_reward_token_ref: Some(client.get_token_ref("IOU").unwrap()), - router_program_id: router_id, - farm_program_id, - route: FarmRoute::Saber { - quarry: json_farm.quarry, - rewarder, - redeemer, - redeemer_program, - minter, - mint_wrapper, - mint_wrapper_program, - iou_fees_account, - sbr_vault, - mint_proxy_program, - mint_proxy_authority, - mint_proxy_state, - minter_info, - }, - }; - - client.add_farm(config.keypair.as_ref(), farm).unwrap(); - } -} - -fn load_orca_farm( - client: &FarmClient, - config: &Config, - remove_mode: bool, - parsed: &Value, - last_index: u32, -) { - let mut last_index = last_index; - let router_id = client.get_program_id("OrcaRouter").unwrap(); - let farm_program_id = client.get_program_id("OrcaStake").unwrap(); - let farms = parsed["farms"].as_array().unwrap(); - for val in farms { - let json_farm: JsonOrcaFarm = serde_json::from_value(val.clone()).unwrap(); - let lp_token = client - .get_token_with_mint(&json_farm.base_token_mint) - .unwrap(); - let (pool_name, _) = if FarmClient::is_liquidity_token(&lp_token.name) { - FarmClient::extract_pool_name_and_version(&lp_token.name).unwrap() - } else { - ("ORC.".to_string() + &lp_token.name, 0) - }; - let name = if pool_name.ends_with("-AQ") { - format!("{}-DD-V1", &pool_name[..pool_name.len() - 3]) - } else { - format!("{}-AQ-V1", pool_name) - }; - if !remove_mode { - if config.skip_existing && client.get_farm(&name).is_ok() { - info!("Skipping existing Farm \"{}\"...", name); - continue; - } - info!("Writing Farm \"{}\" to on-chain RefDB...", name); - } else { - info!("Removing Farm \"{}\" from on-chain RefDB...", name); - client.remove_farm(config.keypair.as_ref(), &name).unwrap(); - continue; - } - let (index, counter) = if let Ok(farm) = client.get_farm(&name) { - (farm.refdb_index, farm.refdb_counter) - } else { - last_index += 1; - (Some(last_index - 1), 0u16) - }; - let farm_data = client - .rpc_client - .get_account_data(&json_farm.address) - .unwrap(); - let farm_state = OrcaFarmState::unpack(&farm_data).unwrap(); - let farm = Farm { - name: str_to_as64(&name).unwrap(), - version: 1, - farm_type: FarmType::SingleReward, - official: true, - refdb_index: index, - refdb_counter: counter, - lp_token_ref: Some(client.get_token_ref(&lp_token.name).unwrap()), - first_reward_token_ref: Some(get_token_ref_with_mint( - client, - &json_farm.reward_token_mint, - )), - second_reward_token_ref: None, - router_program_id: router_id, - farm_program_id, - route: FarmRoute::Orca { - farm_id: json_farm.address, - farm_authority: Pubkey::find_program_address( - &[&json_farm.address.to_bytes()], - &farm_program_id, - ) - .0, - farm_token_ref: get_token_ref_with_mint(client, &json_farm.farm_token_mint), - base_token_vault: farm_state.base_token_vault, - reward_token_vault: farm_state.reward_token_vault, - }, - }; - - client.add_farm(config.keypair.as_ref(), farm).unwrap(); - } -} diff --git a/farms/farm-ctrl/src/loaders/fund.rs b/farms/farm-ctrl/src/loaders/fund.rs deleted file mode 100644 index 09bf6f7cac5..00000000000 --- a/farms/farm-ctrl/src/loaders/fund.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! Funds loader. - -use { - crate::config::Config, - log::info, - solana_farm_client::client::FarmClient, - solana_farm_sdk::{fund::Fund, refdb::StorageType}, -}; - -pub fn load(client: &FarmClient, config: &Config, data: &str, remove_mode: bool) { - let parsed: serde_json::Value = serde_json::from_str(data).unwrap(); - let mut last_index = client - .get_refdb_last_index(&StorageType::Fund.to_string()) - .expect("Fund RefDB query error"); - - if parsed["name"] != "Solana Funds List" { - panic!("Unsupported funds file"); - } - let funds = parsed["funds"].as_array().unwrap(); - for val in funds { - let json_fund: Fund = serde_json::from_value(val.clone()).unwrap(); - if !remove_mode { - if config.skip_existing && client.get_fund(&json_fund.name).is_ok() { - info!("Skipping existing Fund \"{}\"...", json_fund.name); - continue; - } - info!("Writing Fund \"{}\" to on-chain RefDB...", json_fund.name); - } else { - info!( - "Removing Fund \"{}\" from on-chain RefDB...", - json_fund.name - ); - client - .remove_fund(config.keypair.as_ref(), &json_fund.name) - .unwrap(); - continue; - } - let (index, counter) = if let Ok(fund) = client.get_fund(&json_fund.name) { - (fund.refdb_index, fund.refdb_counter) - } else { - last_index += 1; - (Some(last_index - 1), 0u16) - }; - let fund = Fund { - name: json_fund.name, - version: json_fund.version as u16, - fund_type: json_fund.fund_type, - official: json_fund.official, - refdb_index: index, - refdb_counter: counter, - metadata_bump: json_fund.metadata_bump, - authority_bump: json_fund.authority_bump, - fund_token_bump: json_fund.fund_token_bump, - multisig_bump: json_fund.multisig_bump, - fund_program_id: json_fund.fund_program_id, - fund_authority: json_fund.fund_authority, - fund_manager: json_fund.fund_manager, - fund_token_ref: json_fund.fund_token_ref, - info_account: json_fund.info_account, - multisig_account: json_fund.multisig_account, - vaults_assets_info: json_fund.vaults_assets_info, - custodies_assets_info: json_fund.custodies_assets_info, - description_account: json_fund.description_account, - }; - - client.add_fund(config.keypair.as_ref(), fund).unwrap(); - } -} diff --git a/farms/farm-ctrl/src/loaders/mod.rs b/farms/farm-ctrl/src/loaders/mod.rs deleted file mode 100644 index 8382bb07f33..00000000000 --- a/farms/farm-ctrl/src/loaders/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod farm; -pub mod fund; -pub mod pool; -pub mod program; -pub mod token; -pub mod utils; -pub mod vault; diff --git a/farms/farm-ctrl/src/loaders/pool.rs b/farms/farm-ctrl/src/loaders/pool.rs deleted file mode 100644 index dccd56a9939..00000000000 --- a/farms/farm-ctrl/src/loaders/pool.rs +++ /dev/null @@ -1,650 +0,0 @@ -//! Pools loader. - -use { - crate::{config::Config, loaders::utils::*}, - log::info, - serde::Deserialize, - serde_json::{json, Value}, - solana_farm_client::client::FarmClient, - solana_farm_sdk::{ - pack::{optional_pubkey_deserialize, pubkey_deserialize}, - pool::{Pool, PoolRoute, PoolType}, - refdb::StorageType, - string::str_to_as64, - token::GitToken, - }, - solana_sdk::pubkey::Pubkey, - std::collections::HashMap, - std::str::FromStr, -}; - -#[allow(dead_code)] -#[derive(Deserialize, Debug)] -struct JsonRaydiumPoolLegacy { - pub name: String, - pub coin: String, - pub pc: String, - pub lp: String, - pub version: u8, - #[serde(rename = "programId")] - pub program_id: String, - #[serde(rename = "ammId", deserialize_with = "pubkey_deserialize")] - pub amm_id: Pubkey, - #[serde(rename = "ammAuthority", deserialize_with = "pubkey_deserialize")] - pub amm_authority: Pubkey, - #[serde(rename = "ammOpenOrders", deserialize_with = "pubkey_deserialize")] - pub amm_open_orders: Pubkey, - #[serde(rename = "ammTargetOrders", deserialize_with = "pubkey_deserialize")] - pub amm_target_orders: Pubkey, - #[serde(rename = "ammQuantities", deserialize_with = "pubkey_deserialize")] - pub amm_quantities: Pubkey, - #[serde( - rename = "poolCoinTokenAccount", - deserialize_with = "pubkey_deserialize" - )] - pub pool_coin_token_account: Pubkey, - #[serde(rename = "poolPcTokenAccount", deserialize_with = "pubkey_deserialize")] - pub pool_pc_token_account: Pubkey, - #[serde(rename = "poolWithdrawQueue", deserialize_with = "pubkey_deserialize")] - pub pool_withdraw_queue: Pubkey, - #[serde( - rename = "poolTempLpTokenAccount", - deserialize_with = "pubkey_deserialize" - )] - pub pool_temp_lp_token_account: Pubkey, - #[serde(rename = "serumProgramId")] - pub serum_program_id: String, - #[serde(rename = "serumMarket", deserialize_with = "pubkey_deserialize")] - pub serum_market: Pubkey, - #[serde( - rename = "serumBids", - deserialize_with = "optional_pubkey_deserialize", - default - )] - pub serum_bids: Option, - #[serde( - rename = "serumAsks", - deserialize_with = "optional_pubkey_deserialize", - default - )] - pub serum_asks: Option, - #[serde( - rename = "serumEventQueue", - deserialize_with = "optional_pubkey_deserialize", - default - )] - pub serum_event_queue: Option, - #[serde( - rename = "serumCoinVaultAccount", - deserialize_with = "pubkey_deserialize" - )] - pub serum_coin_vault_account: Pubkey, - #[serde( - rename = "serumPcVaultAccount", - deserialize_with = "pubkey_deserialize" - )] - pub serum_pc_vault_account: Pubkey, - #[serde(rename = "serumVaultSigner", deserialize_with = "pubkey_deserialize")] - pub serum_vault_signer: Pubkey, - pub official: bool, -} - -#[allow(dead_code)] -#[derive(Deserialize, Debug)] -pub struct JsonRaydiumPool { - #[serde(deserialize_with = "pubkey_deserialize")] - pub id: Pubkey, - #[serde(rename = "baseMint", deserialize_with = "pubkey_deserialize")] - pub base_mint: Pubkey, - #[serde(rename = "quoteMint", deserialize_with = "pubkey_deserialize")] - pub quote_mint: Pubkey, - #[serde(rename = "lpMint", deserialize_with = "pubkey_deserialize")] - pub lp_mint: Pubkey, - #[serde(rename = "baseDecimals")] - pub base_decimals: u8, - #[serde(rename = "quoteDecimals")] - pub quote_decimals: u8, - #[serde(rename = "lpDecimals")] - pub lp_decimals: u8, - pub version: u8, - #[serde(rename = "programId", deserialize_with = "pubkey_deserialize")] - pub program_id: Pubkey, - #[serde(deserialize_with = "pubkey_deserialize")] - pub authority: Pubkey, - #[serde(rename = "openOrders", deserialize_with = "pubkey_deserialize")] - pub open_orders: Pubkey, - #[serde(rename = "targetOrders", deserialize_with = "pubkey_deserialize")] - pub target_orders: Pubkey, - #[serde(rename = "baseVault", deserialize_with = "pubkey_deserialize")] - pub base_vault: Pubkey, - #[serde(rename = "quoteVault", deserialize_with = "pubkey_deserialize")] - pub quote_vault: Pubkey, - #[serde(rename = "withdrawQueue", deserialize_with = "pubkey_deserialize")] - pub withdraw_queue: Pubkey, - #[serde(rename = "lpVault", deserialize_with = "pubkey_deserialize")] - pub lp_vault: Pubkey, - #[serde(rename = "marketVersion")] - pub market_version: u8, - #[serde(rename = "marketProgramId", deserialize_with = "pubkey_deserialize")] - pub market_program_id: Pubkey, - #[serde(rename = "marketId", deserialize_with = "pubkey_deserialize")] - pub market_id: Pubkey, - #[serde(rename = "marketAuthority", deserialize_with = "pubkey_deserialize")] - pub market_authority: Pubkey, - #[serde(rename = "marketBaseVault", deserialize_with = "pubkey_deserialize")] - pub market_base_vault: Pubkey, - #[serde(rename = "marketQuoteVault", deserialize_with = "pubkey_deserialize")] - pub market_quote_vault: Pubkey, - #[serde(rename = "marketBids", deserialize_with = "pubkey_deserialize")] - pub market_bids: Pubkey, - #[serde(rename = "marketAsks", deserialize_with = "pubkey_deserialize")] - pub market_asks: Pubkey, - #[serde(rename = "marketEventQueue", deserialize_with = "pubkey_deserialize")] - pub market_event_queue: Pubkey, -} - -#[allow(dead_code)] -#[derive(Deserialize, Debug)] -pub struct JsonSaberPool { - pub name: String, - pub tokens: Vec, - #[serde(rename = "lpToken")] - pub lp_token: GitToken, - - #[serde(deserialize_with = "pubkey_deserialize")] - pub quarry: Pubkey, -} - -#[allow(dead_code)] -#[derive(Deserialize, Debug)] -pub struct JsonOrcaToken { - pub tag: String, - pub name: String, - #[serde(deserialize_with = "pubkey_deserialize")] - pub mint: Pubkey, - pub scale: u8, - #[serde(deserialize_with = "pubkey_deserialize")] - pub addr: Pubkey, -} - -#[derive(Deserialize, Debug)] -pub struct JsonOrcaPool { - pub name: String, - #[serde(deserialize_with = "pubkey_deserialize")] - pub address: Pubkey, - pub nonce: u8, - #[serde(deserialize_with = "pubkey_deserialize")] - pub authority: Pubkey, - #[serde(rename = "poolTokenMint", deserialize_with = "pubkey_deserialize")] - pub pool_token_mint: Pubkey, - #[serde(rename = "poolTokenDecimals")] - pub pool_token_decimals: u8, - #[serde(rename = "feeAccount", deserialize_with = "pubkey_deserialize")] - pub fee_account: Pubkey, - #[serde(rename = "tokenIds")] - pub token_ids: Vec, - pub tokens: HashMap, - #[serde(rename = "curveType")] - pub curve_type: u8, - #[serde(flatten)] - pub extra: HashMap, -} - -pub fn load(client: &FarmClient, config: &Config, data: &str, remove_mode: bool) { - let parsed: Value = serde_json::from_str(data).unwrap(); - let last_index = client - .get_refdb_last_index(&StorageType::Pool.to_string()) - .expect("Pool RefDB query error"); - - if parsed["name"] == "Raydium Pools" { - load_raydium_pool_legacy(client, config, remove_mode, &parsed, last_index); - } else if parsed["name"] == "Raydium Mainnet Liquidity Pools" { - load_raydium_pool(client, config, remove_mode, &parsed, last_index); - } else if parsed["name"] == "Orca Pools" { - load_orca_pool(client, config, remove_mode, &parsed, last_index); - } else if parsed["pools"] != json!(null) && parsed["addresses"] != json!(null) { - load_saber_pool(client, config, remove_mode, &parsed, last_index); - } else { - panic!("Unsupported pools file"); - } -} - -fn load_raydium_pool_legacy( - client: &FarmClient, - config: &Config, - remove_mode: bool, - parsed: &Value, - last_index: u32, -) { - let mut last_index = last_index; - let pools = parsed["pools"].as_array().unwrap(); - let router_id = client.get_program_id("RaydiumRouter").unwrap(); - for val in pools { - let json_pool: JsonRaydiumPoolLegacy = serde_json::from_value(val.clone()).unwrap(); - let token_a = client - .get_token_with_account(&json_pool.pool_coin_token_account) - .unwrap(); - let token_b = client - .get_token_with_account(&json_pool.pool_pc_token_account) - .unwrap(); - let name = format!( - "RDM.{}-{}-V{}", - token_a.name, token_b.name, json_pool.version - ); - if !remove_mode { - if config.skip_existing && client.get_pool(&name).is_ok() { - info!("Skipping existing Pool \"{}\"...", name); - continue; - } - info!("Writing Pool \"{}\" to on-chain RefDB...", name); - } else { - info!("Removing Pool \"{}\" from on-chain RefDB...", name); - client.remove_pool(config.keypair.as_ref(), &name).unwrap(); - continue; - } - let (index, counter) = if let Ok(pool) = client.get_pool(&name) { - (pool.refdb_index, pool.refdb_counter) - } else { - last_index += 1; - (Some(last_index - 1), 0u16) - }; - - let pool = Pool { - name: str_to_as64(&name).unwrap(), - version: json_pool.version as u16, - pool_type: PoolType::Amm, - official: json_pool.official, - refdb_index: index, - refdb_counter: counter, - token_a_ref: Some(client.get_token_ref(&token_a.name).unwrap()), - token_b_ref: Some(client.get_token_ref(&token_b.name).unwrap()), - lp_token_ref: Some(client.get_token_ref(&json_pool.lp.to_uppercase()).unwrap()), - token_a_account: Some(json_pool.pool_coin_token_account), - token_b_account: Some(json_pool.pool_pc_token_account), - router_program_id: router_id, - pool_program_id: convert_raydium_program_id(client, &json_pool.program_id), - route: PoolRoute::Raydium { - amm_id: json_pool.amm_id, - amm_authority: json_pool.amm_authority, - amm_open_orders: json_pool.amm_open_orders, - amm_target: if json_pool.version == 4 { - json_pool.amm_target_orders - } else { - json_pool.amm_quantities - }, - pool_withdraw_queue: json_pool.pool_withdraw_queue, - pool_temp_lp_token_account: json_pool.pool_temp_lp_token_account, - serum_program_id: convert_serum_program_id(client, &json_pool.serum_program_id), - serum_market: json_pool.serum_market, - serum_coin_vault_account: json_pool.serum_coin_vault_account, - serum_pc_vault_account: json_pool.serum_pc_vault_account, - serum_vault_signer: json_pool.serum_vault_signer, - serum_bids: json_pool.serum_bids, - serum_asks: json_pool.serum_asks, - serum_event_queue: json_pool.serum_event_queue, - }, - }; - - client.add_pool(config.keypair.as_ref(), pool).unwrap(); - } -} - -fn load_raydium_pool( - client: &FarmClient, - config: &Config, - remove_mode: bool, - parsed: &Value, - last_index: u32, -) { - let mut last_index = last_index; - let pools = parsed["official"].as_array().unwrap(); - let router_id = client.get_program_id("RaydiumRouter").unwrap(); - for val in pools { - let json_pool: JsonRaydiumPool = serde_json::from_value(val.clone()).unwrap(); - let token_a = client.get_token_with_mint(&json_pool.base_mint).unwrap(); - let token_b = client.get_token_with_mint(&json_pool.quote_mint).unwrap(); - let lp_token = client.get_token_with_mint(&json_pool.lp_mint).unwrap(); - let pool_type = get_raydium_pool_type(&json_pool); - let name = format!( - "RDM.{}-{}-V{}", - token_a.name, token_b.name, json_pool.version - ); - if !remove_mode { - if config.skip_existing && client.get_pool(&name).is_ok() { - info!("Skipping existing Pool \"{}\"...", name); - continue; - } else if pool_type == PoolType::AmmStable { - info!("Skipping stablecoin Pool \"{}\"...", name); - continue; - } - info!("Writing Pool \"{}\" to on-chain RefDB...", name); - } else { - info!("Removing Pool \"{}\" from on-chain RefDB...", name); - client.remove_pool(config.keypair.as_ref(), &name).unwrap(); - continue; - } - let (index, counter) = if let Ok(pool) = client.get_pool(&name) { - (pool.refdb_index, pool.refdb_counter) - } else { - last_index += 1; - (Some(last_index - 1), 0u16) - }; - - let pool = Pool { - name: str_to_as64(&name).unwrap(), - version: json_pool.version as u16, - pool_type: PoolType::Amm, - official: true, - refdb_index: index, - refdb_counter: counter, - token_a_ref: Some(client.get_token_ref(&token_a.name).unwrap()), - token_b_ref: Some(client.get_token_ref(&token_b.name).unwrap()), - lp_token_ref: Some(client.get_token_ref(&lp_token.name).unwrap()), - token_a_account: Some(json_pool.base_vault), - token_b_account: Some(json_pool.quote_vault), - router_program_id: router_id, - pool_program_id: json_pool.program_id, - route: PoolRoute::Raydium { - amm_id: json_pool.id, - amm_authority: json_pool.authority, - amm_open_orders: json_pool.open_orders, - amm_target: json_pool.target_orders, - pool_withdraw_queue: json_pool.withdraw_queue, - pool_temp_lp_token_account: json_pool.lp_vault, - serum_program_id: json_pool.market_program_id, - serum_market: json_pool.market_id, - serum_coin_vault_account: json_pool.market_base_vault, - serum_pc_vault_account: json_pool.market_quote_vault, - serum_vault_signer: json_pool.market_authority, - serum_bids: if json_pool.market_bids == Pubkey::default() { - None - } else { - Some(json_pool.market_bids) - }, - serum_asks: if json_pool.market_asks == Pubkey::default() { - None - } else { - Some(json_pool.market_asks) - }, - serum_event_queue: if json_pool.market_event_queue == Pubkey::default() { - None - } else { - Some(json_pool.market_event_queue) - }, - }, - }; - - client.add_pool(config.keypair.as_ref(), pool).unwrap(); - } -} - -fn load_saber_pool( - client: &FarmClient, - config: &Config, - remove_mode: bool, - parsed: &Value, - last_index: u32, -) { - let mut last_index = last_index; - let pools = parsed["pools"].as_array().unwrap(); - let router_id = client.get_program_id("SaberRouter").unwrap(); - let decimal_wrapper_program = client.get_program_id("SaberDecimalWrapper").unwrap(); - for val in pools { - let json_pool: JsonSaberPool = serde_json::from_value(val.clone()).unwrap(); - let name = get_saber_pool_name(client, &json_pool.tokens[0], &json_pool.tokens[1]); - if !remove_mode { - if config.skip_existing && client.get_pool(&name).is_ok() { - info!("Skipping existing Pool \"{}\"...", name); - continue; - } - info!("Writing Pool \"{}\" to on-chain RefDB...", name); - } else { - info!("Removing Pool \"{}\" from on-chain RefDB...", name); - client.remove_pool(config.keypair.as_ref(), &name).unwrap(); - continue; - } - let (index, counter) = if let Ok(pool) = client.get_pool(&name) { - (pool.refdb_index, pool.refdb_counter) - } else { - last_index += 1; - (Some(last_index - 1), 0u16) - }; - let pool_token_name = get_saber_token_name(client, &json_pool.lp_token); - if json_pool.tokens[0].address - != convert_pubkey(val["swap"]["state"]["tokenA"]["mint"].as_str().unwrap()) - || json_pool.tokens[1].address - != convert_pubkey(val["swap"]["state"]["tokenB"]["mint"].as_str().unwrap()) - { - panic!("Pool metadata mismatch"); - } - - // check if there are Saber wrapped symbols - let token1_wrapped = is_saber_wrapped(&json_pool.tokens[0]); - let token2_wrapped = is_saber_wrapped(&json_pool.tokens[1]); - let token_a_symbol = get_saber_token_name(client, &json_pool.tokens[0]); - let token_b_symbol = get_saber_token_name(client, &json_pool.tokens[1]); - - // wrapped token refs - let wrapped_token_a_ref = if token1_wrapped { - Some(get_token_ref_with_mint( - client, - &json_pool.tokens[0].address, - )) - } else { - None - }; - let wrapped_token_b_ref = if token2_wrapped { - Some(get_token_ref_with_mint( - client, - &json_pool.tokens[1].address, - )) - } else { - None - }; - - // wrappers - let (decimal_wrapper_token_a, wrapped_token_a_vault) = if token1_wrapped { - let (a, b) = get_saber_wrappers(client, &json_pool.tokens[0].symbol, &token_a_symbol); - (Some(a), Some(b)) - } else { - (None, None) - }; - let (decimal_wrapper_token_b, wrapped_token_b_vault) = if token2_wrapped { - let (a, b) = get_saber_wrappers(client, &json_pool.tokens[1].symbol, &token_b_symbol); - (Some(a), Some(b)) - } else { - (None, None) - }; - - let pool = Pool { - name: str_to_as64(&name).unwrap(), - version: 1u16, - pool_type: PoolType::AmmStable, - official: true, - refdb_index: index, - refdb_counter: counter, - token_a_ref: Some(client.get_token_ref(&token_a_symbol).unwrap()), - token_b_ref: Some(client.get_token_ref(&token_b_symbol).unwrap()), - lp_token_ref: Some(client.get_token_ref(&pool_token_name).unwrap()), - token_a_account: Some(json_to_pubkey(&val["swap"]["state"]["tokenA"]["reserve"])), - token_b_account: Some(json_to_pubkey(&val["swap"]["state"]["tokenB"]["reserve"])), - router_program_id: router_id, - pool_program_id: json_to_pubkey(&val["swap"]["config"]["swapProgramID"]), - route: PoolRoute::Saber { - swap_account: json_to_pubkey(&val["swap"]["config"]["swapAccount"]), - swap_authority: json_to_pubkey(&val["swap"]["config"]["authority"]), - fees_account_a: json_to_pubkey(&val["swap"]["state"]["tokenA"]["adminFeeAccount"]), - fees_account_b: json_to_pubkey(&val["swap"]["state"]["tokenB"]["adminFeeAccount"]), - decimal_wrapper_program, - wrapped_token_a_ref, - wrapped_token_a_vault, - decimal_wrapper_token_a, - wrapped_token_b_ref, - wrapped_token_b_vault, - decimal_wrapper_token_b, - }, - }; - - client.add_pool(config.keypair.as_ref(), pool).unwrap(); - } -} - -fn load_orca_pool( - client: &FarmClient, - config: &Config, - remove_mode: bool, - parsed: &Value, - last_index: u32, -) { - let mut last_index = last_index; - let pools = parsed["pools"].as_array().unwrap(); - let router_id = client.get_program_id("OrcaRouter").unwrap(); - let pool_program_id = client.get_program_id("OrcaSwap").unwrap(); - for val in pools { - let json_pool: JsonOrcaPool = serde_json::from_value(val.clone()).unwrap(); - let token_a = client - .get_token_with_mint(&convert_pubkey(&json_pool.token_ids[0])) - .unwrap(); - let token_b = client - .get_token_with_mint(&convert_pubkey(&json_pool.token_ids[1])) - .unwrap(); - let pool_type = get_orca_pool_type(&json_pool); - let name = format!("ORC.{}-{}-V1", token_a.name, token_b.name); - if !remove_mode { - if config.skip_existing && client.get_pool(&name).is_ok() { - info!("Skipping existing Pool \"{}\"...", name); - continue; - } else if pool_type == PoolType::AmmStable { - info!("Skipping stablecoin Pool \"{}\"...", name); - continue; - } - info!("Writing Pool \"{}\" to on-chain RefDB...", name); - } else { - info!("Removing Pool \"{}\" from on-chain RefDB...", name); - client.remove_pool(config.keypair.as_ref(), &name).unwrap(); - continue; - } - let (index, counter) = if let Ok(pool) = client.get_pool(&name) { - (pool.refdb_index, pool.refdb_counter) - } else { - last_index += 1; - (Some(last_index - 1), 0u16) - }; - // validate mints - if token_a.mint != json_pool.tokens[&json_pool.token_ids[0]].mint - || token_b.mint != json_pool.tokens[&json_pool.token_ids[1]].mint - { - panic!("Pool metadata mismatch"); - } - let pool = Pool { - name: str_to_as64(&name).unwrap(), - version: 1, - pool_type: if json_pool.curve_type == 0 { - PoolType::Amm - } else { - PoolType::AmmStable - }, - official: true, - refdb_index: index, - refdb_counter: counter, - token_a_ref: Some(client.get_token_ref(&token_a.name).unwrap()), - token_b_ref: Some(client.get_token_ref(&token_b.name).unwrap()), - lp_token_ref: Some(get_token_ref_with_mint(client, &json_pool.pool_token_mint)), - token_a_account: Some(json_pool.tokens[&json_pool.token_ids[0]].addr), - token_b_account: Some(json_pool.tokens[&json_pool.token_ids[1]].addr), - router_program_id: router_id, - pool_program_id, - route: PoolRoute::Orca { - amm_id: json_pool.address, - amm_authority: json_pool.authority, - fees_account: json_pool.fee_account, - }, - }; - - client.add_pool(config.keypair.as_ref(), pool).unwrap(); - } -} - -fn get_raydium_pool_type(pool: &JsonRaydiumPool) -> PoolType { - match pool.version { - 0..=4 => PoolType::Amm, - 5 => PoolType::AmmStable, - _ => panic!("Unrecognized Raydium pool type: {}", pool.version), - } -} - -fn get_orca_pool_type(pool: &JsonOrcaPool) -> PoolType { - match pool.curve_type { - 0 => PoolType::Amm, - 2 => PoolType::AmmStable, - _ => panic!("Unrecognized Orca pool type: {}", pool.curve_type), - } -} - -fn get_saber_wrappers( - client: &FarmClient, - saber_symbol: &str, - original_symbol: &str, -) -> (Pubkey, Pubkey) { - let token = client.get_token(original_symbol).unwrap(); - let decimals = saber_symbol - .split('-') - .last() - .unwrap() - .parse::() - .unwrap(); - let decimal_wrapper_program = client.get_program_id("SaberDecimalWrapper").unwrap(); - - let wrapper = Pubkey::find_program_address( - &[b"anchor", &token.mint.to_bytes(), &[decimals]], - &decimal_wrapper_program, - ) - .0; - // wrapper_vault can be fetched with: - // async function fetch_wrapper_vault(wrapper_program, wrapper) { - // const idl = JSON.parse( - // require("fs").readFileSync( - // "./add_decimals_idl.json", "utf8" - // ) - // ); - // const programId = new anchor.web3.PublicKey(wrapper_program); - // const program = new anchor.Program(idl, programId); - // console.log( - // ( - // await program.account.wrappedToken.fetch(wrapper) - // ).wrapperUnderlyingTokens.toString() - // ); - // } - let wrapper_vault = match saber_symbol { - "swhETH-9" => "4fUL9yLbFZEuG32SaCjWqJXwDTBFNnipteBWxMvvFoC8", - "swFTT-9" => "5yugfArBAUZJJBUCRWPuiLyi6CWp1f67H9xgg3hcgSkx", - "srenBTC-10" => "764FaQrrREvNTpaH2yXyrPZgVBaXA7AXM8vyCaevXitD", - "srenBTC-9" => "C39Wq6X98TLcrnYCMkcHQhwUurkQMUdibUCpf2fVBDsm", - "srenLUNA-9" => "4R6PmC8BJcPDBsEMGpXpLCnFFkUZhEgZy6pMNtc2LqA4", - "sUSDC-8" => "AQhP39mE4o6BYNwnwYqnz7ZobkPBSLpCg8WvEESq1viZ", - "sUSDC-9" => "77XHXCWYQ76E9Q3uCuz1geTaxsqJZf9RfX5ZY7yyLDYt", - "sUSDT-8" => "3cjAWoyDcco8UVCN17keNUNHoyz37ctgDa7G6zkeb81Y", - "sUSDT-9" => "BSTjdztBrsptuxfz9JHS31Wc9CknpLeL1wqZjeVs1Ths", - "sBTC-8" => "6hYDFhZ5ddfzoqaAbzRHm8mzG2MQzYQV9295sQHsvNBV", - "sBTC-9" => "B22gDMgN2tNWmvyzhb5tamJKanWcUUUw2zN3h3qjgQg8", - "sETH-8" => "4JWyJ4ZYsQ8uiYue2tTEqcHcFXrDuaQ1rsyjNFfrZm65", - "sETH-9" => "4fUL9yLbFZEuG32SaCjWqJXwDTBFNnipteBWxMvvFoC8", - "sFTT-9" => "H5tnZcfHCzHueNnfd6foeBBUUW4g7qXKt6rKzT7wg6oP", - "ssoFTT-8" => "7dVPR6jx3hKyNfuHPo3WtWdUpH4eh4Up4rfFhLHZqwy3", - "sagEUR-9" => "8YC5eCS99umbK9K9LnHnTMMjnr7EWg1gam5maNB6uf9d", - "sCASH-8" => "5s2et753hMXV945U3p5uz6RQqMkZGCPEjKjNPdUcCLLF", - "sCASH-9" => "3YCGgStAV9H7TdPYdBnRP8yoH4Zqdmyt7xo6KB4Wa8xt", - "sLUNA-9" => "AvqMJWHsZscPWTAUcj8dZi2ch6XQEHMpiCMprfFovaU", - "sUST-8" => "9YB1zRL4ETuQFG8ZK1yD4GHBVDmH81EzwuSj75zdnKhK", - "sUST-9" => "GxpyQZi5VkZDSq5TUycMau11sCkQkVCa8xYhBgiPMsyK", - "ssoFTT-9" => "H5tnZcfHCzHueNnfd6foeBBUUW4g7qXKt6rKzT7wg6oP", - "ssoETH-8" => "4JWyJ4ZYsQ8uiYue2tTEqcHcFXrDuaQ1rsyjNFfrZm65", - _ => { - panic!( - "Unknown Saber wrapped token {} with wrapper {} and program {}", - saber_symbol, wrapper, decimal_wrapper_program - ); - } - }; - (wrapper, Pubkey::from_str(wrapper_vault).unwrap()) -} diff --git a/farms/farm-ctrl/src/loaders/program.rs b/farms/farm-ctrl/src/loaders/program.rs deleted file mode 100644 index d9a1c882b50..00000000000 --- a/farms/farm-ctrl/src/loaders/program.rs +++ /dev/null @@ -1,59 +0,0 @@ -//! Program IDs loader. - -use { - crate::config::Config, - log::info, - serde::Deserialize, - solana_farm_client::client::FarmClient, - solana_farm_sdk::{pack::pubkey_deserialize, ProgramIDType}, - solana_sdk::pubkey::Pubkey, -}; - -#[allow(dead_code)] -#[derive(Deserialize, Debug)] -struct JsonProgram { - name: String, - description: String, - program_type: ProgramIDType, - #[serde(deserialize_with = "pubkey_deserialize")] - address: Pubkey, -} - -#[allow(dead_code)] -#[derive(Deserialize, Debug)] -struct JsonPrograms { - name: String, - timestamp: String, - programs: Vec, -} - -pub fn load(client: &FarmClient, config: &Config, data: &str, remove_mode: bool) { - let parsed: JsonPrograms = serde_json::from_str(data).unwrap(); - - for program in parsed.programs.iter() { - if remove_mode { - info!( - "Removing Program \"{}\" from on-chain RefDB...", - program.name - ); - client - .remove_program_id(config.keypair.as_ref(), &program.name) - .unwrap(); - } else { - if config.skip_existing && client.get_program_id(&program.name).is_ok() { - info!("Skipping existing Program \"{}\"...", program.name); - continue; - } - info!("Writing Program \"{}\" to on-chain RefDB...", program.name); - client - .add_program_id( - config.keypair.as_ref(), - &program.name, - &program.address, - program.program_type, - None, - ) - .unwrap(); - } - } -} diff --git a/farms/farm-ctrl/src/loaders/token.rs b/farms/farm-ctrl/src/loaders/token.rs deleted file mode 100644 index b238ce4931b..00000000000 --- a/farms/farm-ctrl/src/loaders/token.rs +++ /dev/null @@ -1,533 +0,0 @@ -//! Tokens loader. - -use { - crate::{ - config::Config, - loaders::{ - farm::JsonOrcaFarm, - pool::{JsonOrcaPool, JsonRaydiumPool, JsonSaberPool}, - utils::*, - }, - }, - log::{error, info}, - serde::Deserialize, - serde_json::Value, - solana_account_decoder::parse_token::{parse_token, TokenAccountType}, - solana_farm_client::client::FarmClient, - solana_farm_sdk::{ - id::zero, - pack::{as64_deserialize, pubkey_deserialize}, - refdb, - refdb::StorageType, - string::{str_to_as64, ArrayString64}, - token::{GitToken, OracleType, Token, TokenType}, - }, - solana_sdk::pubkey::Pubkey, - std::collections::HashMap, - std::str::FromStr, -}; - -#[allow(dead_code)] -#[derive(Deserialize, Debug)] -struct JsonRaydiumLPToken { - #[serde(deserialize_with = "as64_deserialize")] - symbol: ArrayString64, - #[serde(deserialize_with = "as64_deserialize")] - name: ArrayString64, - coin: String, - pc: String, - #[serde(rename = "mintAddress", deserialize_with = "pubkey_deserialize")] - mint_address: Pubkey, - decimals: u8, -} - -pub fn load(client: &FarmClient, config: &Config, data: &str, remove_mode: bool) { - let parsed: Value = serde_json::from_str(data).unwrap(); - let last_index = client - .get_refdb_last_index(&StorageType::Token.to_string()) - .expect("Token RefDB query error"); - - if parsed.get("name").is_some() { - if parsed["name"] == "Solana Token List" - || parsed["name"] == "Saber Tokens" - || parsed["name"] == "Raydium Mainnet Token List" - { - load_solana_tokens(client, config, remove_mode, &parsed, last_index); - } else if parsed["name"] == "Raydium LP Tokens" { - load_raydium_tokens_legacy(client, config, remove_mode, &parsed, last_index); - } else if parsed["name"] == "Raydium Mainnet Liquidity Pools" { - load_raydium_pool_tokens(client, config, remove_mode, &parsed, last_index); - } else if parsed["name"] == "Orca Pools" { - load_orca_pool_tokens(client, config, remove_mode, &parsed, last_index); - } else if parsed["name"] == "Orca Farms" { - load_orca_farm_tokens(client, config, remove_mode, &parsed, last_index); - } - } else if parsed.get("pools").is_some() { - load_saber_pool_tokens(client, config, remove_mode, &parsed, last_index); - } else { - panic!("Unsupported tokens file"); - } -} - -fn check_token(client: &FarmClient, config: &Config, name: &str, mint: &Pubkey) -> bool { - if let Ok(existing_token) = client.get_token(name) { - if existing_token.mint != *mint { - error!( - "New mint for token \"{}\" doesn't match the old one: {}", - name, existing_token.mint - ) - } - if config.skip_existing { - info!("Skipping existing Token \"{}\"...", name); - return false; - } - } else if let Ok(existing_token) = client.get_token_with_mint(mint) { - error!( - "Skipping token \"{}\": Another token with mint {} already exists: \"{}\"...", - name, mint, existing_token.name - ); - return false; - } - true -} - -fn load_solana_tokens( - client: &FarmClient, - config: &Config, - remove_mode: bool, - parsed: &Value, - last_index: u32, -) { - let mut last_index = last_index; - let tokens = if parsed["name"] == "Raydium Mainnet Token List" { - parsed["official"].as_array().unwrap() - } else { - parsed["tokens"].as_array().unwrap() - }; - for val in tokens { - let git_token: GitToken = serde_json::from_value(val.clone()).unwrap(); - let token_type = if git_token.symbol.to_uppercase() == "SOL" { - TokenType::WrappedSol - } else { - get_token_type_from_tags(&git_token.tags) - }; - let name = if token_type == TokenType::VtToken || token_type == TokenType::FundToken { - git_token.symbol - } else { - normalize_name(&git_token.symbol, false) - }; - - if git_token.chain_id != 101 || token_type == TokenType::LpToken { - continue; - } - if !remove_mode { - if !check_token(client, config, &name, &git_token.address) { - continue; - } - info!("Writing Token \"{}\" to on-chain RefDB...", name); - } else { - info!("Removing Token \"{}\" from on-chain RefDB...", name); - client.remove_token(config.keypair.as_ref(), &name).unwrap(); - continue; - } - let (index, counter) = if let Ok(token) = client.get_token(&name) { - (token.refdb_index, token.refdb_counter) - } else { - last_index += 1; - (Some(last_index - 1), 0u16) - }; - let (oracle_type, oracle_account) = get_oracle_price_account(config, &name); - let token = Token { - name: str_to_as64(&name).unwrap(), - description: str_to_as64(&git_token.name).unwrap(), - token_type, - refdb_index: index, - refdb_counter: counter, - decimals: if token_type == TokenType::VtToken || token_type == TokenType::FundToken { - git_token.decimals as u8 - } else { - get_mint_decimals(client, &git_token.address) - }, - chain_id: git_token.chain_id as u16, - mint: git_token.address, - oracle_type, - oracle_account: if oracle_type != OracleType::Unsupported { - Some(oracle_account) - } else { - None - }, - description_account: refdb::find_description_pda(StorageType::Token, &name).0, - }; - - client.add_token(config.keypair.as_ref(), token).unwrap(); - } -} - -fn load_raydium_tokens_legacy( - client: &FarmClient, - config: &Config, - remove_mode: bool, - parsed: &Value, - last_index: u32, -) { - let mut last_index = last_index; - let tokens: HashMap = - serde_json::from_value(parsed["tokens"].clone()).unwrap(); - for (symbol, token) in tokens.iter() { - let name = "LP.RDM.".to_string() + &normalize_name(symbol, true); - if !remove_mode { - if !check_token(client, config, &name, &token.mint_address) { - continue; - } - info!("Writing Token \"{}\" to on-chain RefDB...", name); - } else { - info!("Removing Token \"{}\" from on-chain RefDB...", name); - let _ = client.remove_token(config.keypair.as_ref(), &name); - continue; - } - let (index, counter) = if let Ok(token) = client.get_token(&name) { - (token.refdb_index, token.refdb_counter) - } else { - last_index += 1; - (Some(last_index - 1), 0u16) - }; - let (oracle_type, oracle_account) = get_oracle_price_account(config, &name); - let token = Token { - name: str_to_as64(&name).unwrap(), - description: token.name, - token_type: TokenType::LpToken, - refdb_index: index, - refdb_counter: counter, - decimals: get_mint_decimals(client, &token.mint_address), - chain_id: 101u16, - mint: token.mint_address, - oracle_type, - oracle_account: if oracle_type != OracleType::Unsupported { - Some(oracle_account) - } else { - None - }, - description_account: refdb::find_description_pda(StorageType::Token, &name).0, - }; - - client.add_token(config.keypair.as_ref(), token).unwrap(); - } -} - -fn load_raydium_pool_tokens( - client: &FarmClient, - config: &Config, - remove_mode: bool, - parsed: &Value, - last_index: u32, -) { - let mut last_index = last_index; - let pools = parsed["official"].as_array().unwrap(); - for val in pools { - let json_pool: JsonRaydiumPool = serde_json::from_value(val.clone()).unwrap(); - let token_a = client.get_token_with_mint(&json_pool.base_mint).unwrap(); - let token_b = client.get_token_with_mint(&json_pool.quote_mint).unwrap(); - let name = format!( - "LP.RDM.{}-{}-V{}", - token_a.name, token_b.name, json_pool.version - ); - if !remove_mode { - if !check_token(client, config, &name, &json_pool.lp_mint) { - continue; - } - info!("Writing Token \"{}\" to on-chain RefDB...", name); - } else { - info!("Removing Token \"{}\" from on-chain RefDB...", name); - let _ = client.remove_token(config.keypair.as_ref(), &name); - continue; - } - let (index, counter) = if let Ok(token) = client.get_token(&name) { - (token.refdb_index, token.refdb_counter) - } else { - last_index += 1; - (Some(last_index - 1), 0u16) - }; - let (oracle_type, oracle_account) = get_oracle_price_account(config, &name); - let token = Token { - name: str_to_as64(&name).unwrap(), - description: str_to_as64(format!("Raydium {} LP Token", &name[7..]).as_str()).unwrap(), - token_type: TokenType::LpToken, - refdb_index: index, - refdb_counter: counter, - decimals: get_mint_decimals(client, &json_pool.lp_mint), - chain_id: 101u16, - mint: json_pool.lp_mint, - oracle_type, - oracle_account: if oracle_type != OracleType::Unsupported { - Some(oracle_account) - } else { - None - }, - description_account: refdb::find_description_pda(StorageType::Token, &name).0, - }; - - client.add_token(config.keypair.as_ref(), token).unwrap(); - } -} - -fn load_saber_pool_tokens( - client: &FarmClient, - config: &Config, - remove_mode: bool, - parsed: &Value, - last_index: u32, -) { - let mut last_index = last_index; - let pools = parsed["pools"].as_array().unwrap(); - for val in pools { - let json_pool: JsonSaberPool = serde_json::from_value(val.clone()).unwrap(); - let name = "LP.".to_string() - + &get_saber_pool_name(client, &json_pool.tokens[0], &json_pool.tokens[1]); - if !remove_mode { - if !check_token(client, config, &name, &json_pool.lp_token.address) { - continue; - } - info!("Writing Token \"{}\" to on-chain RefDB...", name); - } else { - info!("Removing Token \"{}\" from on-chain RefDB...", name); - let _ = client.remove_token(config.keypair.as_ref(), &name); - continue; - } - let (index, counter) = if let Ok(token) = client.get_token(&name) { - (token.refdb_index, token.refdb_counter) - } else { - last_index += 1; - (Some(last_index - 1), 0u16) - }; - let (oracle_type, oracle_account) = get_oracle_price_account(config, &name); - let token = Token { - name: str_to_as64(&name).unwrap(), - description: str_to_as64(format!("Saber {} LP Token", &name[7..]).as_str()).unwrap(), - token_type: TokenType::LpToken, - refdb_index: index, - refdb_counter: counter, - decimals: get_mint_decimals(client, &json_pool.lp_token.address), - chain_id: 101u16, - mint: json_pool.lp_token.address, - oracle_type, - oracle_account: if oracle_type != OracleType::Unsupported { - Some(oracle_account) - } else { - None - }, - description_account: refdb::find_description_pda(StorageType::Token, &name).0, - }; - - client.add_token(config.keypair.as_ref(), token).unwrap(); - } -} - -fn load_orca_pool_tokens( - client: &FarmClient, - config: &Config, - remove_mode: bool, - parsed: &Value, - last_index: u32, -) { - let mut last_index = last_index; - let pools = parsed["pools"].as_array().unwrap(); - for val in pools { - let json_pool: JsonOrcaPool = serde_json::from_value(val.clone()).unwrap(); - let token_a = client - .get_token_with_mint(&convert_pubkey(&json_pool.token_ids[0])) - .unwrap(); - let token_b = client - .get_token_with_mint(&convert_pubkey(&json_pool.token_ids[1])) - .unwrap(); - let name = format!("LP.ORC.{}-{}-V1", token_a.name, token_b.name); - if !remove_mode { - if !check_token(client, config, &name, &json_pool.pool_token_mint) { - continue; - } - info!("Writing Token \"{}\" to on-chain RefDB...", name); - } else { - info!("Removing Token \"{}\" from on-chain RefDB...", name); - let _ = client.remove_token(config.keypair.as_ref(), &name); - continue; - } - let (index, counter) = if let Ok(token) = client.get_token(&name) { - (token.refdb_index, token.refdb_counter) - } else { - last_index += 1; - (Some(last_index - 1), 0u16) - }; - let (oracle_type, oracle_account) = get_oracle_price_account(config, &name); - let token = Token { - name: str_to_as64(&name).unwrap(), - description: str_to_as64(format!("Orca {} LP Token", &name[7..]).as_str()).unwrap(), - token_type: TokenType::LpToken, - refdb_index: index, - refdb_counter: counter, - decimals: get_mint_decimals(client, &json_pool.pool_token_mint), - chain_id: 101u16, - mint: json_pool.pool_token_mint, - oracle_type, - oracle_account: if oracle_type != OracleType::Unsupported { - Some(oracle_account) - } else { - None - }, - description_account: refdb::find_description_pda(StorageType::Token, &name).0, - }; - - client.add_token(config.keypair.as_ref(), token).unwrap(); - } -} - -fn load_orca_farm_tokens( - client: &FarmClient, - config: &Config, - remove_mode: bool, - parsed: &Value, - last_index: u32, -) { - let mut last_index = last_index; - let farms = parsed["farms"].as_array().unwrap(); - for val in farms { - let json_farm: JsonOrcaFarm = serde_json::from_value(val.clone()).unwrap(); - - let lp_token = client - .get_token_with_mint(&json_farm.base_token_mint) - .unwrap(); - let (pool_name, _) = if FarmClient::is_liquidity_token(&lp_token.name) { - FarmClient::extract_pool_name_and_version(&lp_token.name).unwrap() - } else { - ("ORC.".to_string() + &lp_token.name, 0) - }; - let name = if pool_name.ends_with("-AQ") { - format!("LP.{}-DD-V1", &pool_name[..pool_name.len() - 3]) - } else { - format!("LP.{}-AQ-V1", pool_name) - }; - if !remove_mode { - if !check_token(client, config, &name, &json_farm.farm_token_mint) { - continue; - } - info!("Writing Token \"{}\" to on-chain RefDB...", name); - } else { - info!("Removing Token \"{}\" from on-chain RefDB...", name); - let _ = client.remove_token(config.keypair.as_ref(), &name); - continue; - } - let (index, counter) = if let Ok(token) = client.get_token(&name) { - (token.refdb_index, token.refdb_counter) - } else { - last_index += 1; - (Some(last_index - 1), 0u16) - }; - let (oracle_type, oracle_account) = get_oracle_price_account(config, &name); - let token = Token { - name: str_to_as64(&name).unwrap(), - description: str_to_as64(format!("Orca {} Farm LP Token", json_farm.name).as_str()) - .unwrap(), - token_type: TokenType::LpToken, - refdb_index: index, - refdb_counter: counter, - decimals: get_mint_decimals(client, &json_farm.farm_token_mint), - chain_id: 101u16, - mint: json_farm.farm_token_mint, - oracle_type, - oracle_account: if oracle_type != OracleType::Unsupported { - Some(oracle_account) - } else { - None - }, - description_account: refdb::find_description_pda(StorageType::Token, &name).0, - }; - - client.add_token(config.keypair.as_ref(), token).unwrap(); - } -} - -fn get_mint_decimals(client: &FarmClient, mint_address: &Pubkey) -> u8 { - let data = client.rpc_client.get_account_data(mint_address).unwrap(); - if let Ok(TokenAccountType::Mint(ui_mint)) = parse_token(data.as_slice(), None) { - return ui_mint.decimals; - } - panic!("Failed to parse mint data at address {}", mint_address); -} - -fn get_token_type_from_tags(tags: &[String]) -> TokenType { - if tags.contains(&String::from("Solana tokenized")) { - TokenType::WrappedSol - } else if tags.contains(&String::from("wrapped-sollet")) { - TokenType::WrappedSollet - } else if tags.contains(&String::from("wrapped")) - || tags.contains(&String::from("wormhole-v1")) - || tags.contains(&String::from("wormhole-v2")) - { - TokenType::WrappedWarmhole - } else if tags.contains(&String::from("lp-token")) - || tags.contains(&String::from("saber-stableswap-lp")) - { - TokenType::LpToken - } else if tags.contains(&String::from("vt-token")) { - TokenType::VtToken - } else if tags.contains(&String::from("fund-token")) { - TokenType::FundToken - } else { - TokenType::SplToken - } -} - -fn get_oracle_price_account(config: &Config, symbol: &str) -> (OracleType, Pubkey) { - let acc = if config.farm_client_url.contains("devnet") { - match symbol { - "SOL" => "J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix", - "WSOL" => "J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix", - "MSOL" => "9a6RNx3tCu1TSs6TBSfV2XRXEPEZXQ6WB7jRojZRvyeZ", - "USDC" => "5SSkXsEKQepHHAewytPVwdej4epN1nxgLVM84L4KXgy7", - "USDT" => "38xoQ4oeJCBrcVvca2cGk7iV1dAfrmTR1kmhSCJQ8Jto", - "RAY" => "EhgAdTrgxi4ZoVZLQx1n93vULucPpiFi2BQtz9RJr1y6", - "SRM" => "992moaMQKs32GKZ9dxi8keyM2bUmbrwBZpK4p2K6X5Vs", - "COIN" => "J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix", - "PC" => "J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix", - _ => return (OracleType::Unsupported, zero::id()), - } - } else { - match symbol { - "BCH" => "5ALDzwcRJfSyGdGyhP3kP628aqBNHZzLuVww7o9kdspe", - "LTC" => "8RMnV1eD55iqUFJLMguPkYBkq8DCtx81XcmAja93LvRR", - "BTC" => "GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU", - "BNB" => "4CkQJBxhU8EZ2UjhigbtdaPbpTe6mqf811fipYBFbSYN", - "DOGE" => "FsSM3s38PX9K7Dn6eGzuE29S2Dsk1Sss1baytTQdCaQj", - "USDT" => "3vxLXJqLqF3JG5TCbYycbKWRBbCJQLxQmBGCkyqEEefL", - "SOL" => "H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG", - "WSOL" => "H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG", - "USDC" => "Gnt27xtC473ZT2Mw5u8wZ68Z3gULkSTb5DuxJy7eJotD", - "ETH" => "JBu1AL4obBcCMqKBBxhpWCNUt136ijcuMZLFvTP7iWdB", - "SRM" => "3NBReDRTLKMQEKiLD5tGcx4kXbTf88b7f2xLS9UuGjym", - "LUNA" => "5bmWuR1dgP4avtGYMNKLuxumZTVKGgoN2BCMXWDNL9nY", - "FTT" => "8JPJJkmDScpcNmBRKGZuPuG2GYAveQgP3t5gFuMymwvF", - "MER" => "G4AQpTYKH1Fmg38VpFQbv6uKYQMpRhJzNPALhp7hqdrs", - "SABER" => "8Td9VML1nHxQK6M8VVyzsHo32D7VBk72jSpa9U861z2A", - "RAY" => "AnLf8tVYCM816gmBjiy8n53eXKKEDydT5piYjjQDPgTB", - "HXRO" => "B47CC1ULLw1jKTSsr1N1198zrUHp3LPduzepJyzgLn2g", - "COPE" => "9xYBiDWYsh2fHzpsz3aaCnNHCKWBNtfEDLtU6kS4aFD9", - "MIR" => "m24crrKFG5jw5ySpvb1k83PRFKVUgzTRm4uvK2WYZtX", - "SNY" => "BkN8hYgRjhyH5WNBQfDV73ivvdqNKfonCMhiYVJ1D9n9", - "MNGO" => "79wm3jjcPr6RaNQ4DGvP5KxG1mNd3gEBsg6FsNVFezK4", - "ADA" => "3pyn4svBbxJ9Wnn3RVeafyLWfzie6yC5eTig2S62v9SC", - "DOT" => "EcV1X1gY2yb4KXxjVQtTHTbioum2gvmPnFk4zYAt7zne", - "ATOM" => "CrCpTerNqtZvqLcKqz1k13oVeXV9WkMD2zA9hBKXrsbN", - "MSOL" => "E4v1BBgoso9s64TQvmyownAVJbhbEPGyzA3qn4n46qj9", - "UST" => "H8DvrfSaRfUyP1Ytse1exGf7VSinLWtmKNNaBhA4as9P", - "ALGO" => "HqFyq1wh1xKvL7KDqqT7NJeSPdAqsDqnmBisUC2XdXAX", - "AVAX" => "Ax9ujW5B9oqcv59N8m6f1BpTBq2rGeGaBcpKjC5UYsXU", - "ORCA" => "4ivThkX8uRxBpHsdWSqyXYihzKF3zpRGAUCqyuagnLoV", - "MATIC" => "7KVswB9vkCgeM3SHP7aGDijvdRAHK8P5wi9JXViCrtYh", - "SLND" => "HkGEau5xY1e8REXUFbwvWWvyJGywkgiAZZFpryyraWqJ", - "STSOL" => "Bt1hEbY62aMriY1SyQqbeZbm8VmSbQVGBFzSzMuVNWzN", - "PORT" => "jrMH4afMEodMqirQ7P89q5bGNJxD8uceELcsZaVBDeh", - "FIDA" => "ETp9eKXVv1dWwHSpsXRUuXHmw24PwRkttCGVgpZEY9zF", - _ => return (OracleType::Unsupported, zero::id()), - } - }; - - (OracleType::Pyth, Pubkey::from_str(acc).unwrap()) -} diff --git a/farms/farm-ctrl/src/loaders/utils.rs b/farms/farm-ctrl/src/loaders/utils.rs deleted file mode 100644 index 11c0c31d539..00000000000 --- a/farms/farm-ctrl/src/loaders/utils.rs +++ /dev/null @@ -1,111 +0,0 @@ -//! Common helpers. - -use { - serde_json::Value, solana_farm_client::client::FarmClient, solana_farm_sdk::token::GitToken, - solana_sdk::pubkey::Pubkey, std::str::FromStr, -}; - -pub fn convert_raydium_program_id(client: &FarmClient, program_id: &str) -> Pubkey { - match program_id { - "LIQUIDITY_POOL_PROGRAM_ID_V2" => client.get_program_id("RaydiumV2").unwrap(), - "LIQUIDITY_POOL_PROGRAM_ID_V3" => client.get_program_id("RaydiumV3").unwrap(), - "LIQUIDITY_POOL_PROGRAM_ID_V4" => client.get_program_id("RaydiumV4").unwrap(), - "STAKE_PROGRAM_ID" => client.get_program_id("RaydiumStake").unwrap(), - "STAKE_PROGRAM_ID_V4" => client.get_program_id("RaydiumStakeV4").unwrap(), - "STAKE_PROGRAM_ID_V5" => client.get_program_id("RaydiumStakeV5").unwrap(), - _ => convert_pubkey(program_id), - } -} - -pub fn convert_serum_program_id(client: &FarmClient, program_id: &str) -> Pubkey { - match program_id { - "SERUM_PROGRAM_ID_V2" => client.get_program_id("SerumV2").unwrap(), - "SERUM_PROGRAM_ID_V3" => client.get_program_id("SerumV3").unwrap(), - _ => convert_pubkey(program_id), - } -} - -pub fn convert_pubkey(pubkey_as_string: &str) -> Pubkey { - Pubkey::from_str(pubkey_as_string).unwrap_or_else(|_| { - panic!( - "Failed to convert the string to pubkey {}", - pubkey_as_string - ) - }) -} - -#[allow(dead_code)] -pub fn convert_optional_pubkey(pubkey_as_string: &str) -> Option { - if pubkey_as_string.is_empty() { - None - } else { - Some(Pubkey::from_str(pubkey_as_string).unwrap_or_else(|_| { - panic!( - "Failed to convert the string to pubkey {}", - pubkey_as_string - ) - })) - } -} - -pub fn json_to_pubkey(input: &Value) -> Pubkey { - if let Ok(pubkey) = Pubkey::from_str(input.as_str().unwrap()) { - return pubkey; - } - panic!("Failed to convert the input to a pubkey: {}", input); -} - -pub fn normalize_name(name: &str, allow_dashes: bool) -> String { - if allow_dashes { - name.to_uppercase() - .replace(' ', "_") - .replace('/', "_") - .replace('.', "_") - } else { - name.to_uppercase() - .replace(' ', "_") - .replace('/', "_") - .replace('.', "_") - .replace('-', "_") - } -} - -pub fn is_saber_wrapped(token: &GitToken) -> bool { - token.symbol.len() > 3 && token.tags.contains(&String::from("saber-dec-wrapped")) -} - -pub fn get_saber_token_name(client: &FarmClient, token: &GitToken) -> String { - if is_saber_wrapped(token) { - client - .get_token_with_mint(&convert_pubkey( - token.extra["extensions"]["assetContract"].as_str().unwrap(), - )) - .unwrap() - .name - .to_string() - } else { - client - .get_token_with_mint(&token.address) - .unwrap() - .name - .to_string() - } -} - -pub fn get_saber_pool_name(client: &FarmClient, token1: &GitToken, token2: &GitToken) -> String { - let token1_name = get_saber_token_name(client, token1); - let token2_name = get_saber_token_name(client, token2); - format!("SBR.{}-{}-V1", token1_name, token2_name) -} - -pub fn get_token_ref_with_mint(client: &FarmClient, token_mint: &Pubkey) -> Pubkey { - client - .get_token_ref( - client - .get_token_with_mint(token_mint) - .unwrap() - .name - .as_str(), - ) - .unwrap() -} diff --git a/farms/farm-ctrl/src/loaders/vault.rs b/farms/farm-ctrl/src/loaders/vault.rs deleted file mode 100644 index 0722bcd49bc..00000000000 --- a/farms/farm-ctrl/src/loaders/vault.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! Vaults loader. - -use { - crate::config::Config, - log::info, - solana_farm_client::client::FarmClient, - solana_farm_sdk::{refdb::StorageType, vault::Vault}, -}; - -pub fn load(client: &FarmClient, config: &Config, data: &str, remove_mode: bool) { - let parsed: serde_json::Value = serde_json::from_str(data).unwrap(); - let mut last_index = client - .get_refdb_last_index(&StorageType::Vault.to_string()) - .expect("Vault RefDB query error"); - - if parsed["name"] != "Solana Vaults List" { - panic!("Unsupported vaults file"); - } - let vaults = parsed["vaults"].as_array().unwrap(); - for val in vaults { - let json_vault: Vault = serde_json::from_value(val.clone()).unwrap(); - if !remove_mode { - if config.skip_existing && client.get_vault(&json_vault.name).is_ok() { - info!("Skipping existing Vault \"{}\"...", json_vault.name); - continue; - } - info!("Writing Vault \"{}\" to on-chain RefDB...", json_vault.name); - } else { - info!( - "Removing Vault \"{}\" from on-chain RefDB...", - json_vault.name - ); - client - .remove_vault(config.keypair.as_ref(), &json_vault.name) - .unwrap(); - continue; - } - let (index, counter) = if let Ok(vault) = client.get_vault(&json_vault.name) { - (vault.refdb_index, vault.refdb_counter) - } else { - last_index += 1; - (Some(last_index - 1), 0u16) - }; - let vault = Vault { - name: json_vault.name, - version: json_vault.version as u16, - vault_type: json_vault.vault_type, - official: json_vault.official, - refdb_index: index, - refdb_counter: counter, - metadata_bump: json_vault.metadata_bump, - authority_bump: json_vault.authority_bump, - vault_token_bump: json_vault.vault_token_bump, - lock_required: json_vault.lock_required, - unlock_required: json_vault.unlock_required, - vault_program_id: json_vault.vault_program_id, - vault_authority: json_vault.vault_authority, - vault_token_ref: json_vault.vault_token_ref, - info_account: json_vault.info_account, - multisig_account: json_vault.multisig_account, - fees_account_a: json_vault.fees_account_a, - fees_account_b: json_vault.fees_account_b, - strategy: json_vault.strategy, - }; - - client.add_vault(config.keypair.as_ref(), vault).unwrap(); - } -} diff --git a/farms/farm-ctrl/src/main.rs b/farms/farm-ctrl/src/main.rs deleted file mode 100644 index 68a4ed659da..00000000000 --- a/farms/farm-ctrl/src/main.rs +++ /dev/null @@ -1,648 +0,0 @@ -//! Solana Farms control interface. - -mod config; -mod fund; -mod generate; -mod get; -mod governance; -mod load; -mod loaders; -mod print; -mod refdb; -mod remove; -mod vault; - -use { - log::error, solana_farm_client::client::FarmClient, solana_sdk::pubkey::Pubkey, - std::str::FromStr, -}; - -fn main() { - let matches = config::get_clap_app(solana_version::version!()).get_matches(); - - // set log verbosity level - let log_level = "solana=".to_string() + matches.value_of("log_level").unwrap(); - solana_logger::setup_with_default(log_level.as_str()); - - // load config params - let config = config::Config::new(&matches); - let client = FarmClient::new_with_commitment(&config.farm_client_url, config.commitment); - - // parse commands - match matches.subcommand() { - ("init", Some(subcommand_matches)) => { - refdb::init(&client, &config, config::get_target(subcommand_matches)); - } - ("init-all", Some(_subcommand_matches)) => { - refdb::init_all(&client, &config); - } - ("set-admins", Some(subcommand_matches)) => { - refdb::set_admins( - &client, - &config, - config::get_pubkey_multi_val(subcommand_matches, "admin_signers").as_slice(), - config::get_integer_val(subcommand_matches, "min_signatures") as u8, - ); - } - ("get-admins", Some(_subcommand_matches)) => { - refdb::get_admins(&client, &config); - } - ("drop", Some(subcommand_matches)) => { - refdb::drop(&client, &config, config::get_target(subcommand_matches)); - } - ("drop-all", Some(_subcommand_matches)) => { - refdb::drop_all(&client, &config); - } - ("load", Some(subcommand_matches)) => { - load::load( - &client, - &config, - config::get_target(subcommand_matches), - &config::get_str_val_raw(subcommand_matches, "file_name"), - false, - ); - } - ("load-all", Some(subcommand_matches)) => { - load::load( - &client, - &config, - config::get_target(subcommand_matches), - &config::get_str_val_raw(subcommand_matches, "file_name"), - false, - ); - } - ("remove", Some(subcommand_matches)) => { - remove::remove( - &client, - &config, - config::get_target(subcommand_matches), - &config::get_str_val_raw(subcommand_matches, "object_name"), - ); - } - ("remove-ref", Some(subcommand_matches)) => { - remove::remove_ref( - &client, - &config, - config::get_target(subcommand_matches), - &config::get_str_val_raw(subcommand_matches, "object_name"), - ); - } - ("remove-all", Some(subcommand_matches)) => { - remove::remove_all(&client, &config, config::get_target(subcommand_matches)); - } - ("remove-all-with-file", Some(subcommand_matches)) => { - load::load( - &client, - &config, - config::get_target(subcommand_matches), - &config::get_str_val_raw(subcommand_matches, "file_name"), - true, - ); - } - ("get", Some(subcommand_matches)) => { - get::get( - &client, - &config, - config::get_target(subcommand_matches), - &config::get_str_val_raw(subcommand_matches, "object_name"), - ); - } - ("get-ref", Some(subcommand_matches)) => { - get::get_ref( - &client, - &config, - config::get_target(subcommand_matches), - &config::get_str_val_raw(subcommand_matches, "object_name"), - ); - } - ("get-all", Some(subcommand_matches)) => { - get::get_all(&client, &config, config::get_target(subcommand_matches)); - } - ("list-all", Some(subcommand_matches)) => { - get::list_all(&client, &config, config::get_target(subcommand_matches)); - } - ("program-get-admins", Some(subcommand_matches)) => { - refdb::get_program_admins( - &client, - &config, - &config::get_pubkey_val(subcommand_matches, "program_id"), - ); - } - ("program-set-admins", Some(subcommand_matches)) => { - refdb::set_program_admins( - &client, - &config, - &config::get_pubkey_val(subcommand_matches, "program_id"), - config::get_pubkey_multi_val(subcommand_matches, "admin_signers").as_slice(), - config::get_integer_val(subcommand_matches, "min_signatures") as u8, - ); - } - ("program-set-single-authority", Some(subcommand_matches)) => { - refdb::set_program_single_authority( - &client, - &config, - &config::get_pubkey_val(subcommand_matches, "program_id"), - &config::get_pubkey_val(subcommand_matches, "upgrade_authority"), - ); - } - ("program-upgrade", Some(subcommand_matches)) => { - refdb::upgrade_program( - &client, - &config, - &config::get_pubkey_val(subcommand_matches, "program_id"), - &config::get_pubkey_val(subcommand_matches, "buffer_address"), - ); - } - ("vault-init", Some(subcommand_matches)) => { - vault::init( - &client, - &config, - &config::get_str_val(subcommand_matches, "vault_name"), - config::get_integer_val(subcommand_matches, "step"), - ); - } - ("vault-set-admins", Some(subcommand_matches)) => { - vault::set_admins( - &client, - &config, - &config::get_str_val(subcommand_matches, "vault_name"), - config::get_pubkey_multi_val(subcommand_matches, "admin_signers").as_slice(), - config::get_integer_val(subcommand_matches, "min_signatures") as u8, - ); - } - ("vault-get-admins", Some(subcommand_matches)) => { - vault::get_admins( - &client, - &config, - &config::get_str_val(subcommand_matches, "vault_name"), - ); - } - ("vault-shutdown", Some(subcommand_matches)) => { - vault::shutdown( - &client, - &config, - &config::get_str_val(subcommand_matches, "vault_name"), - ); - } - ("vault-withdraw-fees", Some(subcommand_matches)) => { - vault::withdraw_fees( - &client, - &config, - &config::get_str_val(subcommand_matches, "vault_name"), - config::get_str_val_raw(subcommand_matches, "fee_token") - .parse() - .unwrap(), - config::get_floating_val(subcommand_matches, "amount"), - &config::get_pubkey_val(subcommand_matches, "receiver"), - ); - } - ("vault-crank", Some(subcommand_matches)) => { - vault::crank( - &client, - &config, - &config::get_str_val(subcommand_matches, "vault_name"), - config::get_integer_val(subcommand_matches, "step"), - ); - } - ("vault-set-fee", Some(subcommand_matches)) => { - vault::set_fee( - &client, - &config, - &config::get_str_val(subcommand_matches, "vault_name"), - config::get_floating_val(subcommand_matches, "fee_percent") as f32, - ); - } - ("vault-set-external-fee", Some(subcommand_matches)) => { - vault::set_external_fee( - &client, - &config, - &config::get_str_val(subcommand_matches, "vault_name"), - config::get_floating_val(subcommand_matches, "external_fee_percent") as f32, - ); - } - ("vault-set-min-crank-interval", Some(subcommand_matches)) => { - vault::set_min_crank_interval( - &client, - &config, - &config::get_str_val(subcommand_matches, "vault_name"), - config::get_integer_val(subcommand_matches, "min_crank_interval") as u32, - ); - } - ("vault-disable-deposits", Some(subcommand_matches)) => { - vault::disable_deposits( - &client, - &config, - &config::get_str_val(subcommand_matches, "vault_name"), - ); - } - ("vault-enable-deposits", Some(subcommand_matches)) => { - vault::enable_deposits( - &client, - &config, - &config::get_str_val(subcommand_matches, "vault_name"), - ); - } - ("vault-disable-withdrawals", Some(subcommand_matches)) => { - vault::disable_withdrawals( - &client, - &config, - &config::get_str_val(subcommand_matches, "vault_name"), - ); - } - ("vault-enable-withdrawals", Some(subcommand_matches)) => { - vault::enable_withdrawals( - &client, - &config, - &config::get_str_val(subcommand_matches, "vault_name"), - ); - } - ("vault-get-info", Some(subcommand_matches)) => { - vault::get_info( - &client, - &config, - &config::get_str_val(subcommand_matches, "vault_name"), - ); - } - ("fund-init", Some(subcommand_matches)) => { - fund::init( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - config::get_integer_val(subcommand_matches, "step"), - ); - } - ("fund-set-admins", Some(subcommand_matches)) => { - fund::set_admins( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - config::get_pubkey_multi_val(subcommand_matches, "admin_signers").as_slice(), - config::get_integer_val(subcommand_matches, "min_signatures") as u8, - ); - } - ("fund-get-admins", Some(subcommand_matches)) => { - fund::get_admins( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - ); - } - ("fund-set-manager", Some(subcommand_matches)) => { - fund::set_fund_manager( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - &config::get_pubkey_val(subcommand_matches, "manager"), - ); - } - ("fund-add-custody", Some(subcommand_matches)) => { - fund::add_custody( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - &config::get_str_val(subcommand_matches, "token_name"), - config::get_str_val_raw(subcommand_matches, "custody_type") - .parse() - .unwrap(), - ); - } - ("fund-remove-custody", Some(subcommand_matches)) => { - fund::remove_custody( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - &config::get_str_val(subcommand_matches, "token_name"), - config::get_str_val_raw(subcommand_matches, "custody_type") - .parse() - .unwrap(), - ); - } - ("fund-add-vault", Some(subcommand_matches)) => { - fund::add_vault( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - &config::get_str_val(subcommand_matches, "vault_name"), - config::get_str_val_raw(subcommand_matches, "vault_type") - .parse() - .unwrap(), - ); - } - ("fund-remove-vault", Some(subcommand_matches)) => { - fund::remove_vault( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - &config::get_str_val(subcommand_matches, "vault_name"), - config::get_str_val_raw(subcommand_matches, "vault_type") - .parse() - .unwrap(), - ); - } - ("fund-set-assets-tracking-config", Some(subcommand_matches)) => { - fund::set_assets_tracking_config( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - config::get_floating_val(subcommand_matches, "assets_limit_usd"), - config::get_integer_val(subcommand_matches, "max_update_age_sec"), - config::get_floating_val(subcommand_matches, "max_price_error"), - config::get_integer_val(subcommand_matches, "max_price_age_sec"), - config::get_boolean_val(subcommand_matches, "issue_virtual_tokens"), - ); - } - ("fund-set-deposit-schedule", Some(subcommand_matches)) => { - fund::set_deposit_schedule( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - config::get_integer_val(subcommand_matches, "start_time") as i64, - config::get_integer_val(subcommand_matches, "end_time") as i64, - config::get_str_val_raw(subcommand_matches, "approval_required") - .parse() - .unwrap(), - config::get_floating_val(subcommand_matches, "min_amount_usd"), - config::get_floating_val(subcommand_matches, "max_amount_usd"), - config::get_floating_val(subcommand_matches, "fee"), - ); - } - ("fund-disable-deposits", Some(subcommand_matches)) => { - fund::disable_deposits( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - ); - } - ("fund-approve-deposit", Some(subcommand_matches)) => { - fund::approve_deposit( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - &config::get_pubkey_val(subcommand_matches, "user_address"), - &config::get_str_val(subcommand_matches, "token_name"), - config::get_floating_val(subcommand_matches, "amount"), - ); - } - ("fund-deny-deposit", Some(subcommand_matches)) => { - fund::deny_deposit( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - &config::get_pubkey_val(subcommand_matches, "user_address"), - &config::get_str_val(subcommand_matches, "token_name"), - &config::get_str_val_raw(subcommand_matches, "deny_reason"), - ); - } - ("fund-set-withdrawal-schedule", Some(subcommand_matches)) => { - fund::set_withdrawal_schedule( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - config::get_integer_val(subcommand_matches, "start_time") as i64, - config::get_integer_val(subcommand_matches, "end_time") as i64, - config::get_str_val_raw(subcommand_matches, "approval_required") - .parse() - .unwrap(), - config::get_floating_val(subcommand_matches, "min_amount_usd"), - config::get_floating_val(subcommand_matches, "max_amount_usd"), - config::get_floating_val(subcommand_matches, "fee"), - ); - } - ("fund-disable-withdrawals", Some(subcommand_matches)) => { - fund::disable_withdrawals( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - ); - } - ("fund-approve-withdrawal", Some(subcommand_matches)) => { - fund::approve_withdrawal( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - &config::get_pubkey_val(subcommand_matches, "user_address"), - &config::get_str_val(subcommand_matches, "token_name"), - config::get_floating_val(subcommand_matches, "amount"), - ); - } - ("fund-deny-withdrawal", Some(subcommand_matches)) => { - fund::deny_withdrawal( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - &config::get_pubkey_val(subcommand_matches, "user_address"), - &config::get_str_val(subcommand_matches, "token_name"), - &config::get_str_val_raw(subcommand_matches, "deny_reason"), - ); - } - ("fund-lock-assets", Some(subcommand_matches)) => { - fund::lock_assets( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - &config::get_str_val(subcommand_matches, "token_name"), - config::get_floating_val(subcommand_matches, "amount"), - ); - } - ("fund-unlock-assets", Some(subcommand_matches)) => { - fund::unlock_assets( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - &config::get_str_val(subcommand_matches, "token_name"), - config::get_floating_val(subcommand_matches, "amount"), - ); - } - ("fund-withdraw-fees", Some(subcommand_matches)) => { - fund::withdraw_fees( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - &config::get_str_val(subcommand_matches, "token_name"), - config::get_str_val_raw(subcommand_matches, "custody_type") - .parse() - .unwrap(), - config::get_floating_val(subcommand_matches, "amount"), - &config::get_pubkey_val(subcommand_matches, "receiver"), - ); - } - ("fund-update-assets-with-custody", Some(subcommand_matches)) => { - fund::update_assets_with_custody( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - config::get_integer_val(subcommand_matches, "custody_id") as u32, - ); - } - ("fund-update-assets-with-custodies", Some(subcommand_matches)) => { - fund::update_assets_with_custodies( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - ); - } - ("fund-update-assets-with-vault", Some(subcommand_matches)) => { - fund::update_assets_with_vault( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - config::get_integer_val(subcommand_matches, "vault_id") as u32, - ); - } - ("fund-update-assets-with-vaults", Some(subcommand_matches)) => { - fund::update_assets_with_vaults( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - ); - } - ("fund-stop-liquidation", Some(subcommand_matches)) => { - fund::stop_liquidation( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - ); - } - ("fund-get-info", Some(subcommand_matches)) => { - fund::get_info( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - ); - } - ("fund-deposit-pool", Some(subcommand_matches)) => { - fund::add_liquidity_pool( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - &config::get_str_val(subcommand_matches, "pool_name"), - config::get_floating_val(subcommand_matches, "max_token_a_ui_amount"), - config::get_floating_val(subcommand_matches, "max_token_b_ui_amount"), - ); - } - ("fund-withdraw-pool", Some(subcommand_matches)) => { - fund::remove_liquidity_pool( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - &config::get_str_val(subcommand_matches, "pool_name"), - config::get_floating_val(subcommand_matches, "amount"), - ); - } - ("fund-swap", Some(subcommand_matches)) => { - fund::swap( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - config::get_str_val(subcommand_matches, "protocol") - .parse() - .expect("Failed to parse protocol argument"), - &config::get_str_val(subcommand_matches, "from_token"), - &config::get_str_val(subcommand_matches, "to_token"), - config::get_floating_val(subcommand_matches, "amount_in"), - config::get_floating_val(subcommand_matches, "min_amount_out"), - ); - } - ("fund-stake", Some(subcommand_matches)) => { - fund::stake( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - &config::get_str_val(subcommand_matches, "farm_name"), - config::get_floating_val(subcommand_matches, "amount"), - ); - } - ("fund-unstake", Some(subcommand_matches)) => { - fund::unstake( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - &config::get_str_val(subcommand_matches, "farm_name"), - config::get_floating_val(subcommand_matches, "amount"), - ); - } - ("fund-harvest", Some(subcommand_matches)) => { - fund::harvest( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - &config::get_str_val(subcommand_matches, "farm_name"), - ); - } - ("fund-deposit-vault", Some(subcommand_matches)) => { - fund::add_liquidity_vault( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - &config::get_str_val(subcommand_matches, "vault_name"), - config::get_floating_val(subcommand_matches, "max_token_a_amount"), - config::get_floating_val(subcommand_matches, "max_token_b_amount"), - ); - } - ("fund-deposit-vault-locked", Some(subcommand_matches)) => { - fund::add_locked_liquidity_vault( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - &config::get_str_val(subcommand_matches, "vault_name"), - config::get_floating_val(subcommand_matches, "amount"), - ); - } - ("fund-withdraw-vault", Some(subcommand_matches)) => { - fund::remove_liquidity_vault( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - &config::get_str_val(subcommand_matches, "vault_name"), - config::get_floating_val(subcommand_matches, "amount"), - ); - } - ("fund-withdraw-vault-unlocked", Some(subcommand_matches)) => { - fund::remove_unlocked_liquidity_vault( - &client, - &config, - &config::get_str_val(subcommand_matches, "fund_name"), - &config::get_str_val(subcommand_matches, "vault_name"), - config::get_floating_val(subcommand_matches, "amount"), - ); - } - ("print-pda", Some(subcommand_matches)) => { - print::print_pda(&client, &config, config::get_target(subcommand_matches)); - } - ("print-pda-all", Some(_subcommand_matches)) => { - print::print_pda_all(&client, &config); - } - ("print-size", Some(subcommand_matches)) => { - print::print_size(&client, &config, config::get_target(subcommand_matches)); - } - ("print-size-all", Some(_subcommand_matches)) => { - print::print_size_all(&client, &config); - } - ("generate", Some(subcommand_matches)) => { - generate::generate( - &client, - &config, - config::get_target(subcommand_matches), - &config::get_str_val_raw(subcommand_matches, "object_name"), - &config::get_str_val_raw(subcommand_matches, "param1"), - &config::get_str_val_raw(subcommand_matches, "param2"), - ); - } - ("governance", Some(subcommand_matches)) => match subcommand_matches.subcommand() { - ("init", Some(subcommand_matches)) => { - let address_str = subcommand_matches - .value_of("governance-program-address") - .unwrap(); - let dao_address = Pubkey::from_str(address_str).unwrap(); - governance::init( - &client, - &config, - &dao_address, - config::get_floating_val(subcommand_matches, "mint-ui-amount"), - ); - } - _ => unreachable!(), - }, - _ => error!("Unrecognized command. Use --help to list known commands."), - }; -} diff --git a/farms/farm-ctrl/src/print.rs b/farms/farm-ctrl/src/print.rs deleted file mode 100644 index aa9cb828cf8..00000000000 --- a/farms/farm-ctrl/src/print.rs +++ /dev/null @@ -1,88 +0,0 @@ -//! Handlers for print_pda and print_size commands - -use { - crate::config::Config, - log::info, - solana_farm_client::client::FarmClient, - solana_farm_sdk::{ - farm::Farm, - fund::Fund, - math, - pool::Pool, - refdb::{find_refdb_pda, ReferenceType, StorageType}, - token::Token, - vault::Vault, - }, -}; - -pub fn print_pda(_client: &FarmClient, _config: &Config, target: StorageType) { - info!( - "{} RefDB address: {}", - target, - find_refdb_pda(&target.to_string()).0 - ); -} - -pub fn print_pda_all(client: &FarmClient, config: &Config) { - print_pda(client, config, StorageType::Program); - print_pda(client, config, StorageType::Token); - print_pda(client, config, StorageType::Pool); - print_pda(client, config, StorageType::Farm); - print_pda(client, config, StorageType::Vault); - print_pda(client, config, StorageType::Fund); -} - -pub fn print_size(client: &FarmClient, _config: &Config, target: StorageType) { - let refdb_size = StorageType::get_storage_size_for_max_records(target, ReferenceType::Pubkey); - let target_size = match target { - StorageType::Program => 0, - StorageType::Token => Token::LEN, - StorageType::Pool => Pool::MAX_LEN, - StorageType::Farm => Farm::MAX_LEN, - StorageType::Vault => Vault::MAX_LEN, - StorageType::Fund => Fund::LEN, - _ => 0, - }; - let target_max_recs = StorageType::get_default_max_records(target, ReferenceType::Pubkey); - let refdb_cost = client - .rpc_client - .get_minimum_balance_for_rent_exemption(refdb_size) - .unwrap(); - let target_cost = client - .rpc_client - .get_minimum_balance_for_rent_exemption(target_size) - .unwrap(); - - info!("{} recs / size / cost:", target.to_string()); - info!( - "RefDB: {} / {} / {}", - target_max_recs, - refdb_size, - lam_to_sol(refdb_cost) - ); - info!( - "Target: {} / {} / {}", - 1, - target_size, - lam_to_sol(target_cost) - ); - info!( - "Target Max: {} / {} / {}\n", - target_max_recs, - target_size * target_max_recs, - lam_to_sol(target_cost * (target_max_recs as u64)) - ); -} - -pub fn print_size_all(client: &FarmClient, config: &Config) { - print_size(client, config, StorageType::Program); - print_size(client, config, StorageType::Token); - print_size(client, config, StorageType::Pool); - print_size(client, config, StorageType::Farm); - print_size(client, config, StorageType::Vault); - print_size(client, config, StorageType::Fund); -} - -fn lam_to_sol(amount: u64) -> f64 { - (amount as f64) / math::checked_powi(10f64, spl_token::native_mint::DECIMALS as i32).unwrap() -} diff --git a/farms/farm-ctrl/src/refdb.rs b/farms/farm-ctrl/src/refdb.rs deleted file mode 100644 index 5a9ece3e764..00000000000 --- a/farms/farm-ctrl/src/refdb.rs +++ /dev/null @@ -1,178 +0,0 @@ -//! Handlers for refdb_init and refdb_drop commands - -use { - crate::config::Config, - log::info, - solana_farm_client::client::FarmClient, - solana_farm_sdk::{refdb::ReferenceType, refdb::StorageType, string::to_pretty_json}, - solana_sdk::pubkey::Pubkey, -}; - -pub fn init(client: &FarmClient, config: &Config, target: StorageType) { - if client.is_refdb_initialized(&target.to_string()).unwrap() { - info!("Already initialized RefDB found for {} objects...", target); - return; - } - info!("Initializing RefDB for {} objects", target); - - info!( - "Signature: {}", - client - .initialize_refdb( - config.keypair.as_ref(), - &target.to_string(), - ReferenceType::Pubkey, - StorageType::get_default_max_records(target, ReferenceType::Pubkey), - true, - ) - .unwrap() - ); - - info!("Done.") -} - -pub fn init_all(client: &FarmClient, config: &Config) { - init(client, config, StorageType::Program); - init(client, config, StorageType::Token); - init(client, config, StorageType::Pool); - init(client, config, StorageType::Farm); - init(client, config, StorageType::Vault); - init(client, config, StorageType::Fund); -} - -pub fn set_admins( - client: &FarmClient, - config: &Config, - admin_signers: &[Pubkey], - min_signatures: u8, -) { - info!("Initializing Main Router multisig with new signers..."); - - info!( - "Signature: {}", - client - .set_admins(config.keypair.as_ref(), admin_signers, min_signatures) - .unwrap() - ); - - info!("Done.") -} - -pub fn get_admins(client: &FarmClient, config: &Config) { - if config.no_pretty_print { - println!("Main Router: {}", client.get_admins().unwrap()); - } else { - println!( - "Main Router: {}", - to_pretty_json(&client.get_admins().unwrap()).unwrap() - ); - } -} - -pub fn set_program_admins( - client: &FarmClient, - config: &Config, - program_id: &Pubkey, - admin_signers: &[Pubkey], - min_signatures: u8, -) { - info!( - "Setting new admin signers for the program {}...", - program_id - ); - - info!( - "Signature: {}", - client - .set_program_admins( - config.keypair.as_ref(), - program_id, - admin_signers, - min_signatures - ) - .unwrap() - ); - - info!("Done.") -} - -pub fn get_program_admins(client: &FarmClient, config: &Config, program_id: &Pubkey) { - if config.no_pretty_print { - println!( - "{}: {}", - client.get_program_multisig_account(program_id).unwrap(), - client.get_program_admins(program_id).unwrap() - ); - } else { - println!( - "{}: {}", - client.get_program_multisig_account(program_id).unwrap(), - to_pretty_json(&client.get_program_admins(program_id).unwrap()).unwrap() - ); - } -} - -pub fn set_program_single_authority( - client: &FarmClient, - config: &Config, - program_id: &Pubkey, - upgrade_authority: &Pubkey, -) { - info!( - "Setting single upgrade authority for the program {}...", - program_id - ); - - info!( - "Signature: {}", - client - .set_program_single_authority(config.keypair.as_ref(), program_id, upgrade_authority) - .unwrap() - ); - - info!("Done.") -} - -pub fn upgrade_program( - client: &FarmClient, - config: &Config, - program_id: &Pubkey, - buffer_address: &Pubkey, -) { - info!("Upgrading program {}...", program_id); - - info!( - "Signature: {}", - client - .upgrade_program(config.keypair.as_ref(), program_id, buffer_address) - .unwrap() - ); - - info!("Done.") -} - -pub fn drop(client: &FarmClient, config: &Config, target: StorageType) { - if !client.is_refdb_initialized(&target.to_string()).unwrap() { - info!("No initialized RefDB found for {} objects...", target); - return; - } - info!("Removing RefDB for {} objects", target); - - info!( - "Signature: {}", - client - .drop_refdb(config.keypair.as_ref(), &target.to_string(), true) - .unwrap() - ); - - info!("Done.") -} - -pub fn drop_all(client: &FarmClient, config: &Config) { - drop(client, config, StorageType::Fund); - drop(client, config, StorageType::Vault); - drop(client, config, StorageType::Farm); - drop(client, config, StorageType::Pool); - drop(client, config, StorageType::Token); - drop(client, config, StorageType::Program); -} diff --git a/farms/farm-ctrl/src/remove.rs b/farms/farm-ctrl/src/remove.rs deleted file mode 100644 index c6cfe70d8ea..00000000000 --- a/farms/farm-ctrl/src/remove.rs +++ /dev/null @@ -1,101 +0,0 @@ -//! Handlers for remove and remove_all commands - -use { - crate::config::Config, log::info, solana_farm_client::client::FarmClient, - solana_farm_sdk::refdb::StorageType, -}; - -pub fn remove(client: &FarmClient, config: &Config, target: StorageType, object: &str) { - info!("Removing {} object {}...", target, object); - - match target { - StorageType::Program => { - client - .remove_program_id(config.keypair.as_ref(), object) - .unwrap(); - } - StorageType::Fund => { - client - .remove_fund(config.keypair.as_ref(), &object.to_uppercase()) - .unwrap(); - } - StorageType::Vault => { - client - .remove_vault(config.keypair.as_ref(), &object.to_uppercase()) - .unwrap(); - } - StorageType::Farm => { - client - .remove_farm(config.keypair.as_ref(), &object.to_uppercase()) - .unwrap(); - } - StorageType::Pool => { - client - .remove_pool(config.keypair.as_ref(), &object.to_uppercase()) - .unwrap(); - } - StorageType::Token => { - client - .remove_token(config.keypair.as_ref(), &object.to_uppercase()) - .unwrap(); - } - _ => { - unreachable!(); - } - } - - info!("Done.") -} - -pub fn remove_ref(client: &FarmClient, config: &Config, target: StorageType, object: &str) { - info!("Removing {} reference {}...", target, object); - client - .remove_reference(config.keypair.as_ref(), target, object) - .unwrap(); - - info!("Done.") -} - -pub fn remove_all(client: &FarmClient, config: &Config, target: StorageType) { - info!("Removing all {} objects...", target); - - match target { - StorageType::Program => { - for (name, _) in client.get_program_ids().unwrap() { - client - .remove_program_id(config.keypair.as_ref(), &name) - .unwrap(); - } - } - StorageType::Fund => { - for (name, _) in client.get_fund_refs().unwrap() { - client.remove_fund(config.keypair.as_ref(), &name).unwrap(); - } - } - StorageType::Vault => { - for (name, _) in client.get_vault_refs().unwrap() { - client.remove_vault(config.keypair.as_ref(), &name).unwrap(); - } - } - StorageType::Farm => { - for (name, _) in client.get_farm_refs().unwrap() { - client.remove_farm(config.keypair.as_ref(), &name).unwrap(); - } - } - StorageType::Pool => { - for (name, _) in client.get_pool_refs().unwrap() { - client.remove_pool(config.keypair.as_ref(), &name).unwrap(); - } - } - StorageType::Token => { - for (name, _) in client.get_token_refs().unwrap() { - client.remove_token(config.keypair.as_ref(), &name).unwrap(); - } - } - _ => { - unreachable!(); - } - } - - info!("Done.") -} diff --git a/farms/farm-ctrl/src/vault.rs b/farms/farm-ctrl/src/vault.rs deleted file mode 100644 index 070e0f59ed5..00000000000 --- a/farms/farm-ctrl/src/vault.rs +++ /dev/null @@ -1,251 +0,0 @@ -//! Handlers for feature toggling commands - -use { - crate::config::Config, - log::info, - solana_farm_client::client::FarmClient, - solana_farm_sdk::{string::to_pretty_json, token::TokenSelector}, - solana_sdk::pubkey::Pubkey, -}; - -pub fn init(client: &FarmClient, config: &Config, vault_names: &str, step: u64) { - let vaults = get_vaults_list(client, vault_names); - for vault in vaults { - info!("Initializing Vault {}...", vault); - info!( - "Signature: {}", - client - .init_vault(config.keypair.as_ref(), &vault, step) - .unwrap() - ); - } - info!("Done.") -} - -pub fn set_admins( - client: &FarmClient, - config: &Config, - vault_names: &str, - admin_signers: &[Pubkey], - min_signatures: u8, -) { - let vaults = get_vaults_list(client, vault_names); - for vault in vaults { - info!("Initializing Vault {} multisig with new signers...", vault); - - info!( - "Signature: {}", - client - .set_vault_admins( - config.keypair.as_ref(), - &vault, - admin_signers, - min_signatures - ) - .unwrap() - ); - } - info!("Done.") -} - -pub fn get_admins(client: &FarmClient, config: &Config, vault_names: &str) { - let vaults = get_vaults_list(client, vault_names); - for vault in vaults { - if config.no_pretty_print { - println!("{}: {}", vault, client.get_vault_admins(&vault).unwrap()); - } else { - println!( - "{}: {}", - vault, - to_pretty_json(&client.get_vault_admins(&vault).unwrap()).unwrap() - ); - } - } -} - -pub fn shutdown(client: &FarmClient, config: &Config, vault_names: &str) { - let vaults = get_vaults_list(client, vault_names); - for vault in vaults { - info!("Shutting down Vault {}...", vault); - info!( - "Signature: {}", - client - .shutdown_vault(config.keypair.as_ref(), &vault) - .unwrap() - ); - } - info!("Done.") -} - -pub fn withdraw_fees( - client: &FarmClient, - config: &Config, - vault_names: &str, - fee_token: TokenSelector, - amount: f64, - receiver: &Pubkey, -) { - let vaults = get_vaults_list(client, vault_names); - for vault in vaults { - info!("Withdrawing fees from the Vault {}...", vault); - info!( - "Signature: {}", - client - .withdraw_fees_vault(config.keypair.as_ref(), &vault, fee_token, amount, receiver) - .unwrap() - ); - } - info!("Done.") -} - -pub fn crank(client: &FarmClient, config: &Config, vault_names: &str, step: u64) { - let vaults = get_vaults_list(client, vault_names); - for vault in vaults { - info!("Cranking step {} for the Vault {}...", step, vault); - info!( - "Signature: {}", - client - .crank_vault(config.keypair.as_ref(), &vault, step) - .unwrap() - ); - } - info!("Done.") -} - -pub fn set_fee(client: &FarmClient, config: &Config, vault_names: &str, fee_percent: f32) { - let vaults = get_vaults_list(client, vault_names); - for vault in vaults { - info!("Setting fee to {} for the Vault {}...", fee_percent, vault); - info!( - "Signature: {}", - client - .set_fee_vault(config.keypair.as_ref(), &vault, fee_percent) - .unwrap() - ); - } - info!("Done.") -} - -pub fn set_external_fee( - client: &FarmClient, - config: &Config, - vault_names: &str, - external_fee_percent: f32, -) { - let vaults = get_vaults_list(client, vault_names); - for vault in vaults { - info!( - "Setting external fee to {} for the Vault {}...", - external_fee_percent, vault - ); - info!( - "Signature: {}", - client - .set_external_fee_vault(config.keypair.as_ref(), &vault, external_fee_percent) - .unwrap() - ); - } - info!("Done.") -} - -pub fn set_min_crank_interval( - client: &FarmClient, - config: &Config, - vault_names: &str, - min_crank_interval: u32, -) { - let vaults = get_vaults_list(client, vault_names); - for vault in vaults { - info!( - "Setting min crank interval to {} for the Vault {}...", - min_crank_interval, vault - ); - info!( - "Signature: {}", - client - .set_min_crank_interval_vault(config.keypair.as_ref(), &vault, min_crank_interval) - .unwrap() - ); - } - info!("Done.") -} - -pub fn disable_deposits(client: &FarmClient, config: &Config, vault_names: &str) { - let vaults = get_vaults_list(client, vault_names); - for vault in vaults { - info!("Disabling deposits for the Vault {}...", vault); - info!( - "Signature: {}", - client - .disable_deposits_vault(config.keypair.as_ref(), &vault) - .unwrap() - ); - } - info!("Done.") -} - -pub fn enable_deposits(client: &FarmClient, config: &Config, vault_names: &str) { - let vaults = get_vaults_list(client, vault_names); - for vault in vaults { - info!("Enabling deposits for the Vault {}...", vault); - info!( - "Signature: {}", - client - .enable_deposits_vault(config.keypair.as_ref(), &vault) - .unwrap() - ); - } - info!("Done.") -} - -pub fn disable_withdrawals(client: &FarmClient, config: &Config, vault_names: &str) { - let vaults = get_vaults_list(client, vault_names); - for vault in vaults { - info!("Disabling withdrawals for the Vault {}...", vault); - info!( - "Signature: {}", - client - .disable_withdrawals_vault(config.keypair.as_ref(), &vault) - .unwrap() - ); - } - info!("Done.") -} - -pub fn enable_withdrawals(client: &FarmClient, config: &Config, vault_names: &str) { - let vaults = get_vaults_list(client, vault_names); - for vault in vaults { - info!("Enabling withdrawals for the Vault {}...", vault); - info!( - "Signature: {}", - client - .enable_withdrawals_vault(config.keypair.as_ref(), &vault) - .unwrap() - ); - } - info!("Done.") -} - -pub fn get_info(client: &FarmClient, config: &Config, vault_names: &str) { - let vaults = get_vaults_list(client, vault_names); - for vault in vaults { - info!("Retreiving stats for the Vault {}...", vault); - - let info = client.get_vault_info(&vault).unwrap(); - - if config.no_pretty_print { - println!("{}", info); - } else { - println!("{}", to_pretty_json(&info).unwrap()); - } - } - info!("Done.") -} - -fn get_vaults_list(client: &FarmClient, vault_names: &str) -> Vec { - if vault_names.to_lowercase() == "all" { - client.get_vaults().unwrap().keys().cloned().collect() - } else { - vault_names.split(',').map(|s| s.into()).collect() - } -} diff --git a/farms/farm-rpc/.gitignore b/farms/farm-rpc/.gitignore deleted file mode 100644 index 32488d8632e..00000000000 --- a/farms/farm-rpc/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/target -_*.yml -Cargo.lock diff --git a/farms/farm-rpc/Cargo.toml b/farms/farm-rpc/Cargo.toml deleted file mode 100644 index 962380f42bf..00000000000 --- a/farms/farm-rpc/Cargo.toml +++ /dev/null @@ -1,44 +0,0 @@ -[package] -name = "solana-farm-rpc" -version = "1.1.3" -description = "Solana Farm RPC" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana-program-library/farms" -license = "Apache-2.0" -homepage = "https://solana.com/" -edition = "2021" - -[features] -debug = [] - -[dependencies] -log = "0.4.16" -bs58 = "0.4.0" -clap = "2.34.0" -dirs-next = "2.0.0" -lazy_static = "1.4.0" -reqwest = "0.11.10" -rocket = { version = "0.5.0-rc.1", features = ["json"] } -serde = "1.0.136" -serde_derive = "1.0.136" -serde_json = "1.0.79" -serde_yaml = "0.8.23" -solana-client = "1.9.18" -solana-logger = "1.9.18" -solana-version = "1.9.18" -solana-clap-utils = "1.9.18" -solana-sdk = "1.9.18" -solana-farm-sdk = "1.1.3" -solana-farm-client = "1.1.3" -solana-account-decoder = "1.9.18" -solana-cli-config = "1.9.18" -rusqlite = "0.27.0" -url = "2.2.2" - -[[bin]] -name = "solana-farm-rpc" -path = "src/rpc/main.rs" - -[[bin]] -name = "solana-farm-stats" -path = "src/stats/main.rs" \ No newline at end of file diff --git a/farms/farm-rpc/README.md b/farms/farm-rpc/README.md deleted file mode 120000 index ccd27901fd5..00000000000 --- a/farms/farm-rpc/README.md +++ /dev/null @@ -1 +0,0 @@ -../docs/crate.md \ No newline at end of file diff --git a/farms/farm-rpc/src/rpc/config.rs b/farms/farm-rpc/src/rpc/config.rs deleted file mode 100644 index 243b813d393..00000000000 --- a/farms/farm-rpc/src/rpc/config.rs +++ /dev/null @@ -1,107 +0,0 @@ -//! Configuration management - -use { - serde_derive::{Deserialize, Serialize}, - std::{ - fs::{create_dir_all, File}, - io::{self, Write}, - path::Path, - }, -}; - -lazy_static! { - pub static ref CONFIG_FILE: Option = { - dirs_next::home_dir().map(|mut path| { - path.extend(&[".config", "solana", "farm", "rpc_config.yml"]); - path.to_str().unwrap().to_string() - }) - }; -} - -#[derive(Serialize, Deserialize, Debug, PartialEq)] -pub struct Config { - pub http_rpc_url: String, - pub websocket_url: String, - pub max_threads: u32, - pub token_list_url: String, - pub farm_client_url: String, - pub sqlite_db_path: String, -} - -impl Default for Config { - fn default() -> Self { - let http_rpc_url = "http://127.0.0.1:9000".to_string(); - let websocket_url = "wss://127.0.0.1:9001".to_string(); - let token_list_url = "https://raw.githubusercontent.com/solana-labs/token-list/main/src/tokens/solana.tokenlist.json".to_string(); - let farm_client_url = "http://127.0.0.1:8899".to_string(); - let sqlite_db_path = "fund_stats.db".to_string(); - let max_threads = 4; - - Self { - http_rpc_url, - websocket_url, - max_threads, - token_list_url, - farm_client_url, - sqlite_db_path, - } - } -} - -impl Config { - pub fn load(&mut self, config_file: &str) -> Result<(), io::Error> { - let file = File::open(config_file)?; - *self = serde_yaml::from_reader(file) - .map_err(|err| io::Error::new(io::ErrorKind::Other, format!("{:?}", err)))?; - Ok(()) - } - - pub fn save(&self, config_file: &str) -> Result<(), io::Error> { - let serialized = serde_yaml::to_string(self) - .map_err(|err| io::Error::new(io::ErrorKind::Other, format!("{:?}", err)))?; - - if let Some(outdir) = Path::new(config_file).parent() { - create_dir_all(outdir)?; - } - let mut file = File::create(config_file)?; - file.write_all(&serialized.into_bytes())?; - Ok(()) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_default() { - let config: Config = Default::default(); - assert_eq!(config.http_rpc_url, "http://127.0.0.1:9000"); - assert_eq!(config.websocket_url, "wss://127.0.0.1:9001"); - assert_eq!(config.farm_client_url, "http://127.0.0.1:8899"); - assert_eq!(config.sqlite_db_path, "fund_stats.db"); - assert_eq!(config.max_threads, 4); - } - - #[test] - fn test_load_save() { - let config = Config { - http_rpc_url: "http://test:9000".to_string(), - websocket_url: "wss://test:9001".to_string(), - max_threads: 99, - token_list_url: "none".to_string(), - farm_client_url: "http://test_farm:8899".to_string(), - sqlite_db_path: "test.db".to_string(), - }; - let _ = config.save("_test_config.yml"); - - let mut config2: Config = Default::default(); - let _ = config2.load("_test_config.yml"); - - assert_eq!(config.http_rpc_url, config2.http_rpc_url); - assert_eq!(config.websocket_url, config2.websocket_url); - assert_eq!(config.max_threads, config2.max_threads); - assert_eq!(config.farm_client_url, config2.farm_client_url); - assert_eq!(config.sqlite_db_path, config2.sqlite_db_path); - } -} diff --git a/farms/farm-rpc/src/rpc/http_rpc.rs b/farms/farm-rpc/src/rpc/http_rpc.rs deleted file mode 100644 index 7bc61a86ee4..00000000000 --- a/farms/farm-rpc/src/rpc/http_rpc.rs +++ /dev/null @@ -1,5157 +0,0 @@ -//! JSON RPC service - -use { - crate::{ - config::Config, - fund_stats::{FundStats, FundStatsRecord}, - }, - rocket::{ - fairing::{AdHoc, Fairing, Info, Kind}, - form::{ - error::{Error, Errors}, - FromFormField, ValueField, - }, - fs::{relative, FileServer}, - http::{ContentType, Header}, - request::{FromParam, Request}, - response, - response::{status::NotFound, Responder, Response}, - serde::json::Json, - Build, Rocket, State, - }, - serde_json::{from_str, from_value, json, Value}, - solana_account_decoder::parse_token::UiTokenAccount, - solana_farm_client::client::{ - FarmClient, FarmMap, FundMap, PoolMap, PubkeyMap, TokenMap, VaultMap, - }, - solana_farm_sdk::{ - farm::Farm, - fund::{ - Fund, FundAssets, FundCustody, FundCustodyWithBalance, FundInfo, FundSchedule, - FundUserInfo, FundUserRequests, FundVault, - }, - pool::Pool, - program::multisig::Multisig, - string::{instruction_to_string, pubkey_map_to_string}, - token::{GitToken, Token}, - vault::{Vault, VaultInfo, VaultUserInfo}, - ProtocolInfo, - }, - solana_sdk::{ - commitment_config::CommitmentConfig, instruction::Instruction, pubkey::Pubkey, - signature::Keypair, - }, - std::{ - collections::HashMap, - convert::Into, - str::FromStr, - sync::{Arc, Mutex}, - }, -}; - -type Result = std::result::Result; -type GitTokens = HashMap; -type FarmClientArc = Arc>; -type Signature = String; - -pub struct Cors; - -#[rocket::async_trait] -impl Fairing for Cors { - fn info(&self) -> Info { - Info { - name: "Add CORS headers to responses", - kind: Kind::Response, - } - } - - async fn on_response<'r>(&self, _request: &'r Request<'_>, response: &mut Response<'r>) { - response.set_header(Header::new("Access-Control-Allow-Origin", "*")); - response.set_header(Header::new( - "Access-Control-Allow-Methods", - "POST, GET, OPTIONS", - )); - response.set_header(Header::new("Access-Control-Allow-Headers", "*")); - response.set_header(Header::new("Access-Control-Allow-Credentials", "true")); - } -} - -// Pubkey parameters handling -struct PubkeyParam { - key: Pubkey, -} - -impl<'r> FromParam<'r> for PubkeyParam { - type Error = &'r str; - fn from_param(param: &'r str) -> Result { - Pubkey::from_str(param) - .map(|value| PubkeyParam { key: value }) - .map_err(|_| "Failed to convert string parameter to Pubkey") - } -} - -impl<'r> FromFormField<'r> for PubkeyParam { - fn from_value(field: ValueField<'r>) -> rocket::form::Result<'r, Self> { - Pubkey::from_str(field.value) - .map(|value| PubkeyParam { key: value }) - .map_err(|_| { - Errors::from(Error::validation( - "Failed to convert string argument to Pubkey", - )) - }) - } -} - -// Keypair parameters handling -struct KeypairParam { - key: Keypair, -} - -impl<'r> FromParam<'r> for KeypairParam { - type Error = &'r str; - fn from_param(param: &'r str) -> Result { - let v = &bs58::decode(param) - .into_vec() - .map_err(|_| "Failed to convert parameter to Keypair")?; - Keypair::from_bytes(v) - .map(|value| KeypairParam { key: value }) - .map_err(|_| "Failed to convert parameter to Keypair") - } -} - -impl<'r> FromFormField<'r> for KeypairParam { - fn from_value(field: ValueField<'r>) -> rocket::form::Result<'r, Self> { - let v = &bs58::decode(field.value).into_vec().map_err(|_| { - Errors::from(Error::validation( - "Failed to convert string argument to Pubkey", - )) - })?; - Keypair::from_bytes(v) - .map(|value| KeypairParam { key: value }) - .map_err(|_| { - Errors::from(Error::validation( - "Failed to convert string argument to Pubkey", - )) - }) - } -} - -fn check_unwrap_pubkey( - pubkey_param: Option, - param_name: &str, -) -> Result> { - if let Some(pubkey) = pubkey_param { - Ok(pubkey.key) - } else { - Err(NotFound(format!("Invalid {} argument", param_name))) - } -} - -fn check_unwrap_keypair( - keypair_param: Option, - param_name: &str, -) -> Result> { - if let Some(keypair) = keypair_param { - Ok(keypair.key) - } else { - Err(NotFound(format!("Invalid {} argument", param_name))) - } -} -// Custom Json responders -#[derive(Debug)] -struct JsonWithPubkeyMap { - data: String, -} - -impl JsonWithPubkeyMap { - pub fn new(data: &PubkeyMap) -> Self { - Self { - data: pubkey_map_to_string(data), - } - } -} - -impl<'r> Responder<'r, 'static> for JsonWithPubkeyMap { - fn respond_to(self, request: &'r Request<'_>) -> response::Result<'static> { - Response::build() - .merge(self.data.respond_to(request)?) - .header(ContentType::JSON) - .ok() - } -} - -#[derive(Debug)] -struct JsonWithInstruction { - data: String, -} - -impl JsonWithInstruction { - pub fn new(data: &Instruction) -> Self { - Self { - data: instruction_to_string(data), - } - } -} - -impl<'r> Responder<'r, 'static> for JsonWithInstruction { - fn respond_to(self, request: &'r Request<'_>) -> response::Result<'static> { - Response::build() - .merge(self.data.respond_to(request)?) - .header(ContentType::JSON) - .ok() - } -} - -#[derive(Debug)] -struct JsonWithInstructions { - data: String, -} - -impl JsonWithInstructions { - pub fn new(data: &[Instruction]) -> Self { - let mut res = ::default(); - for inst in data { - if res.is_empty() { - res = "[".to_string() + &instruction_to_string(inst); - } else { - res += &(",".to_string() + &instruction_to_string(inst)); - } - } - Self { data: res + "]" } - } -} - -impl<'r> Responder<'r, 'static> for JsonWithInstructions { - fn respond_to(self, request: &'r Request<'_>) -> response::Result<'static> { - Response::build() - .merge(self.data.respond_to(request)?) - .header(ContentType::JSON) - .ok() - } -} - -// Routes - -/// Returns description and stats of all supported protocols -#[get("/protocols")] -async fn get_protocols( - farm_client: &State, -) -> Result>, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let protocols = farm_client - .get_protocols() - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(protocols)) -} - -/// Returns current admin signers for the Main Router -#[get("/admins")] -async fn get_admins( - farm_client: &State, -) -> Result, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let admins = farm_client - .get_admins() - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(admins)) -} - -/// Returns program upgrade signers -#[get("/program_admins?")] -async fn get_program_admins( - program_id: Option, - farm_client: &State, -) -> Result, NotFound> { - let program_id = check_unwrap_pubkey(program_id, "program_id")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let admins = farm_client - .get_program_admins(&program_id) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(admins)) -} - -/// Returns Token metadata from Github -#[get("/git_token?")] -async fn get_git_token( - name: &str, - git_tokens: &State, -) -> Result, NotFound> { - if !git_tokens.inner().contains_key(name) { - return Err(NotFound(format!("Record not found: Token {}", name))); - } - Ok(Json(git_tokens.inner()[name].clone())) -} - -/// Returns all Tokens from Github -#[get("/git_tokens")] -async fn get_git_tokens(git_tokens: &State) -> Result> { - Ok(Json(git_tokens.inner().clone())) -} - -/// Returns the Fund struct for the given name -#[get("/fund?")] -async fn get_fund( - name: &str, - farm_client: &State, -) -> Result, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let fund = farm_client - .get_fund(name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(fund)) -} - -/// Returns all Funds available -#[get("/funds")] -async fn get_funds(farm_client: &State) -> Result, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let funds = farm_client - .get_funds() - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(funds)) -} - -/// Returns the Fund metadata address for the given name -#[get("/fund_ref?")] -async fn get_fund_ref( - name: &str, - farm_client: &State, -) -> Result> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let fund_ref = farm_client - .get_fund_ref(name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(fund_ref.to_string()) -} - -/// Returns Fund refs: a map of Fund name to account address with metadata -#[get("/fund_refs")] -async fn get_fund_refs( - farm_client: &State, -) -> Result> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let fund_refs = farm_client - .get_fund_refs() - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithPubkeyMap::new(&fund_refs)) -} - -/// Returns the Fund metadata at the specified address -#[get("/fund_by_ref?")] -async fn get_fund_by_ref( - fund_ref: Option, - farm_client: &State, -) -> Result, NotFound> { - let fund_ref = check_unwrap_pubkey(fund_ref, "fund_ref")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let fund = farm_client - .get_fund_by_ref(&fund_ref) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(fund)) -} - -/// Returns the Fund name for the given metadata address -#[get("/fund_name?")] -async fn get_fund_name( - fund_ref: Option, - farm_client: &State, -) -> Result> { - let fund_ref = check_unwrap_pubkey(fund_ref, "fund_ref")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let fund_name = farm_client - .get_fund_name(&fund_ref) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(fund_name) -} - -/// Returns all Funds that have Vaults with the name matching the pattern sorted by version -#[get("/find_funds?")] -async fn find_funds( - vault_name_pattern: &str, - farm_client: &State, -) -> Result>, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let funds = farm_client - .find_funds(vault_name_pattern) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(funds)) -} - -/// Returns the Vault struct for the given name -#[get("/vault?")] -async fn get_vault( - name: &str, - farm_client: &State, -) -> Result, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let vault = farm_client - .get_vault(name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(vault)) -} - -/// Returns all Vaults available -#[get("/vaults")] -async fn get_vaults( - farm_client: &State, -) -> Result, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let vaults = farm_client - .get_vaults() - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(vaults)) -} - -/// Returns the Vault metadata address for the given name -#[get("/vault_ref?")] -async fn get_vault_ref( - name: &str, - farm_client: &State, -) -> Result> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let vault_ref = farm_client - .get_vault_ref(name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(vault_ref.to_string()) -} - -/// Returns Vault refs: a map of Vault name to account address with metadata -#[get("/vault_refs")] -async fn get_vault_refs( - farm_client: &State, -) -> Result> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let vault_refs = farm_client - .get_vault_refs() - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithPubkeyMap::new(&vault_refs)) -} - -/// Returns the Vault metadata at the specified address -#[get("/vault_by_ref?")] -async fn get_vault_by_ref( - vault_ref: Option, - farm_client: &State, -) -> Result, NotFound> { - let vault_ref = check_unwrap_pubkey(vault_ref, "vault_ref")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let vault = farm_client - .get_vault_by_ref(&vault_ref) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(vault)) -} - -/// Returns the Vault name for the given metadata address -#[get("/vault_name?")] -async fn get_vault_name( - vault_ref: Option, - farm_client: &State, -) -> Result> { - let vault_ref = check_unwrap_pubkey(vault_ref, "vault_ref")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let vault_name = farm_client - .get_vault_name(&vault_ref) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(vault_name) -} - -/// Returns all Vaults with tokens A and B sorted by version -#[get("/find_vaults?&")] -async fn find_vaults( - token_a: &str, - token_b: &str, - farm_client: &State, -) -> Result>, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let vaults = farm_client - .find_vaults(token_a, token_b) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(vaults)) -} - -/// Returns all Vaults with tokens A and B sorted by version -#[get("/find_vaults_with_vt?")] -async fn find_vaults_with_vt( - vt_token_name: &str, - farm_client: &State, -) -> Result>, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let vaults = farm_client - .find_vaults_with_vt(vt_token_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(vaults)) -} - -/// Returns the Pool struct for the given name -#[get("/pool?")] -async fn get_pool( - name: &str, - farm_client: &State, -) -> Result, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let pool = farm_client - .get_pool(name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(pool)) -} - -/// Returns all Pools available -#[get("/pools")] -async fn get_pools(farm_client: &State) -> Result, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let pool_map = farm_client - .get_pools() - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(pool_map)) -} - -/// Returns the Pool metadata address for the given name -#[get("/pool_ref?")] -async fn get_pool_ref( - name: &str, - farm_client: &State, -) -> Result> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let pool_ref = farm_client - .get_pool_ref(name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(pool_ref.to_string()) -} - -/// Returns Pool refs: a map of Pool name to account address with metadata -#[get("/pool_refs")] -async fn get_pool_refs( - farm_client: &State, -) -> Result> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let pool_refs = farm_client - .get_pool_refs() - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithPubkeyMap::new(&pool_refs)) -} - -/// Returns the Pool metadata at the specified address -#[get("/pool_by_ref?")] -async fn get_pool_by_ref( - pool_ref: Option, - farm_client: &State, -) -> Result, NotFound> { - let pool_ref = check_unwrap_pubkey(pool_ref, "pool_ref")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let pool = farm_client - .get_pool_by_ref(&pool_ref) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(pool)) -} - -/// Returns the Pool name for the given metadata address -#[get("/pool_name?")] -async fn get_pool_name( - pool_ref: Option, - farm_client: &State, -) -> Result> { - let pool_ref = check_unwrap_pubkey(pool_ref, "pool_ref")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let pool_name = farm_client - .get_pool_name(&pool_ref) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(pool_name) -} - -/// Returns all Pools with tokens A and B sorted by version for the given protocol -#[get("/find_pools?&&")] -async fn find_pools( - protocol: &str, - token_a: &str, - token_b: &str, - farm_client: &State, -) -> Result>, NotFound> { - let protocol = protocol - .parse() - .map_err(|_| NotFound("Invalid protocol argument".to_string()))?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let pools = farm_client - .find_pools(protocol, token_a, token_b) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(pools)) -} - -/// Returns all Pools sorted by version for the given LP token -#[get("/find_pools_with_lp?")] -async fn find_pools_with_lp( - lp_token: &str, - farm_client: &State, -) -> Result>, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let pools = farm_client - .find_pools_with_lp(lp_token) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(pools)) -} - -/// Returns pair's price based on the ratio of tokens in the pool -#[get("/pool_price?")] -async fn get_pool_price( - name: &str, - farm_client: &State, -) -> Result> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let pool_price = farm_client - .get_pool_price(name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(pool_price.to_string()) -} - -/// Returns oracle address for the given token -#[get("/oracle?")] -async fn get_oracle( - symbol: &str, - farm_client: &State, -) -> Result, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let oracle = farm_client - .get_oracle(symbol) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(oracle.1.ok_or_else(|| { - NotFound(format!("Oracle for {} is not configured", symbol)) - })?)) -} - -/// Returns the price in USD for the given token -#[get("/oracle_price?&&")] -async fn get_oracle_price( - symbol: &str, - max_price_age_sec: u64, - max_price_error: f64, - farm_client: &State, -) -> Result> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let oracle_price = farm_client - .get_oracle_price(symbol, max_price_age_sec, max_price_error) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(oracle_price.to_string()) -} - -/// Returns the Farm struct for the given name -#[get("/farm?")] -async fn get_farm( - name: &str, - farm_client: &State, -) -> Result, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let farm = farm_client - .get_farm(name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(farm)) -} - -/// Returns all Farms available -#[get("/farms")] -async fn get_farms(farm_client: &State) -> Result, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let farms = farm_client - .get_farms() - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(farms)) -} - -/// Returns the Farm metadata address for the given name -#[get("/farm_ref?")] -async fn get_farm_ref( - name: &str, - farm_client: &State, -) -> Result> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let farm_ref = farm_client - .get_farm_ref(name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(farm_ref.to_string()) -} - -/// Returns Farm refs: a map of Farm name to account address with metadata -#[get("/farm_refs")] -async fn get_farm_refs( - farm_client: &State, -) -> Result> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let farm_refs = farm_client - .get_farm_refs() - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithPubkeyMap::new(&farm_refs)) -} - -/// Returns the Farm metadata at the specified address -#[get("/farm_by_ref?")] -async fn get_farm_by_ref( - farm_ref: Option, - farm_client: &State, -) -> Result, NotFound> { - let farm_ref = check_unwrap_pubkey(farm_ref, "farm_ref")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let farm = farm_client - .get_farm_by_ref(&farm_ref) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(farm)) -} - -/// Returns the Farm name for the given metadata address -#[get("/farm_name?")] -async fn get_farm_name( - farm_ref: Option, - farm_client: &State, -) -> Result> { - let farm_ref = check_unwrap_pubkey(farm_ref, "farm_ref")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let farm_name = farm_client - .get_farm_name(&farm_ref) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(farm_name) -} - -/// Returns all Farms for the given LP token -#[get("/find_farms_with_lp?")] -async fn find_farms_with_lp( - lp_token: &str, - farm_client: &State, -) -> Result>, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let farms = farm_client - .find_farms_with_lp(lp_token) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(farms)) -} - -/// Returns the Token struct for the given name -#[get("/token?")] -async fn get_token( - name: &str, - farm_client: &State, -) -> Result, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let token = farm_client - .get_token(name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(token)) -} - -/// Returns all Tokens available -#[get("/tokens")] -async fn get_tokens( - farm_client: &State, -) -> Result, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let token = farm_client - .get_tokens() - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(token)) -} - -/// Returns the Token metadata address for the given name -#[get("/token_ref?")] -async fn get_token_ref( - name: &str, - farm_client: &State, -) -> Result> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let token_ref = farm_client - .get_token_ref(name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(token_ref.to_string()) -} - -/// Returns Token refs: a map of Token name to account address with metadata -#[get("/token_refs")] -async fn get_token_refs( - farm_client: &State, -) -> Result> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let token_refs = farm_client - .get_token_refs() - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithPubkeyMap::new(&token_refs)) -} - -/// Returns the Token metadata at the specified address -#[get("/token_by_ref?")] -async fn get_token_by_ref( - token_ref: Option, - farm_client: &State, -) -> Result, NotFound> { - let token_ref = check_unwrap_pubkey(token_ref, "token_ref")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let token = farm_client - .get_token_by_ref(&token_ref) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(token)) -} - -/// Returns the Token name for the given metadata address -#[get("/token_name?")] -async fn get_token_name( - token_ref: Option, - farm_client: &State, -) -> Result> { - let token_ref = check_unwrap_pubkey(token_ref, "token_ref")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let token_name = farm_client - .get_token_name(&token_ref) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(token_name) -} - -/// Returns the Token metadata for the specified mint -#[get("/token_with_mint?")] -async fn get_token_with_mint( - token_mint: Option, - farm_client: &State, -) -> Result, NotFound> { - let token_mint = check_unwrap_pubkey(token_mint, "token_mint")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let token = farm_client - .get_token_with_mint(&token_mint) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(token)) -} - -/// Returns the Token metadata for the specified token account -#[get("/token_with_account?")] -async fn get_token_with_account( - token_account: Option, - farm_client: &State, -) -> Result, NotFound> { - let token_account = check_unwrap_pubkey(token_account, "token_account")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let token = farm_client - .get_token_with_account(&token_account) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(token)) -} - -/// Returns the official Program ID for the given name -#[get("/program_id?")] -async fn get_program_id( - name: &str, - farm_client: &State, -) -> Result> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let program_id = farm_client - .get_program_id(name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(program_id.to_string()) -} - -/// Returns all official Program IDs available -#[get("/program_ids")] -async fn get_program_ids( - farm_client: &State, -) -> Result> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let program_ids = farm_client - .get_program_ids() - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithPubkeyMap::new(&program_ids)) -} - -/// Returns the official program name for the given Program ID -#[get("/program_name?")] -async fn get_program_name( - prog_id: Option, - farm_client: &State, -) -> Result> { - let prog_id = check_unwrap_pubkey(prog_id, "prog_id")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let program_name = farm_client - .get_program_name(&prog_id) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(program_name) -} - -/// Checks if the given address is the official Program ID -#[get("/is_official_id?")] -async fn is_official_id( - prog_id: Option, - farm_client: &State, -) -> Result, NotFound> { - let prog_id = check_unwrap_pubkey(prog_id, "prog_id")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let is_official = farm_client - .is_official_id(&prog_id) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(is_official)) -} - -/// Checks if the given address is the Fund manager -#[get("/is_fund_manager?")] -async fn is_fund_manager( - wallet_address: Option, - farm_client: &State, -) -> Result, NotFound> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let is_fund_manager = farm_client - .is_fund_manager(&wallet_address) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(is_fund_manager)) -} - -/// Returns all Funds managed by the given address -#[get("/managed_funds?")] -async fn get_managed_funds( - wallet_address: Option, - farm_client: &State, -) -> Result>, NotFound> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let funds = farm_client - .get_funds() - .map_err(|e| NotFound(e.to_string()))? - .values() - .filter(|&f| f.fund_manager == wallet_address) - .copied() - .collect::>(); - - Ok(Json(funds)) -} - -/// Creates a new system account -#[post("/create_system_account?&&&&")] -async fn create_system_account( - wallet_keypair: Option, - new_account_keypair: Option, - lamports: u64, - space: usize, - owner: Option, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let new_account_keypair = check_unwrap_keypair(new_account_keypair, "new_account_keypair")?; - let owner = check_unwrap_pubkey(owner, "owner")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .create_system_account( - &wallet_keypair, - &new_account_keypair, - lamports, - space, - &owner, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Creates a new system account with seed -#[post("/create_system_account_with_seed?&&&&&")] -async fn create_system_account_with_seed( - wallet_keypair: Option, - base_address: Option, - seed: &str, - lamports: u64, - space: usize, - owner: Option, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let base_address = check_unwrap_pubkey(base_address, "base_address")?; - let owner = check_unwrap_pubkey(owner, "owner")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .create_system_account_with_seed( - &wallet_keypair, - &base_address, - seed, - lamports, - space, - &owner, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Assigns system account to a program -#[post("/assign_system_account?&")] -async fn assign_system_account( - wallet_keypair: Option, - program_address: Option, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let program_address = check_unwrap_pubkey(program_address, "program_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .assign_system_account(&wallet_keypair, &program_address) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Closes existing system account -#[post("/close_system_account?&")] -async fn close_system_account( - wallet_keypair: Option, - target_account_keypair: Option, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let target_account_keypair = - check_unwrap_keypair(target_account_keypair, "target_account_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .close_system_account(&wallet_keypair, &target_account_keypair) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Transfers native SOL from the wallet to the destination -#[post("/transfer?&&")] -async fn transfer( - wallet_keypair: Option, - destination_wallet: Option, - sol_ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let destination_wallet = check_unwrap_pubkey(destination_wallet, "destination_wallet")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .transfer(&wallet_keypair, &destination_wallet, sol_ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Transfers tokens from the wallet to the destination -#[post("/token_transfer?&&&")] -async fn token_transfer( - wallet_keypair: Option, - token_name: &str, - destination_wallet: Option, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let destination_wallet = check_unwrap_pubkey(destination_wallet, "destination_wallet")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .token_transfer(&wallet_keypair, token_name, &destination_wallet, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Transfers native SOL from the wallet to the associated Wrapped SOL account -#[post("/wrap_sol?&")] -async fn wrap_sol( - wallet_keypair: Option, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .wrap_sol(&wallet_keypair, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Transfers Wrapped SOL back to SOL by closing the associated Wrapped SOL account -#[post("/unwrap_sol?")] -async fn unwrap_sol( - wallet_keypair: Option, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .unwrap_sol(&wallet_keypair) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Updates token balance of the account, usefull after transfer SOL to WSOL account -#[post("/sync_token_balance?&")] -async fn sync_token_balance( - wallet_keypair: Option, - token_name: &str, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .sync_token_balance(&wallet_keypair, token_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Returns the associated token account for the given user's main account or creates one -#[post("/create_token_account?&")] -async fn get_or_create_token_account( - wallet_keypair: Option, - token_name: &str, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .get_or_create_token_account(&wallet_keypair, token_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Closes existing token account associated with the given user's main account -#[post("/close_token_account?&")] -async fn close_token_account( - wallet_keypair: Option, - token_name: &str, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .close_token_account(&wallet_keypair, token_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Returns token supply as UI amount -#[get("/token_supply?")] -async fn get_token_supply( - token_name: &str, - farm_client: &State, -) -> Result> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let token_supply = farm_client - .get_token_supply(token_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(token_supply.to_string()) -} - -/// Returns the associated token account address for the given token name -#[get("/associated_token_address?&")] -async fn get_associated_token_address( - wallet_address: Option, - token_name: &str, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let token_address = farm_client - .get_associated_token_address(&wallet_address, token_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(token_address.to_string()) -} - -/// Returns all tokens with active account in the wallet -#[get("/wallet_tokens?")] -async fn get_wallet_tokens( - wallet_address: Option, - farm_client: &State, -) -> Result>, NotFound> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let tokens = farm_client - .get_wallet_tokens(&wallet_address) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(tokens)) -} - -/// Returns UiTokenAccount struct data for the associated token account address -#[get("/token_account_data?&")] -async fn get_token_account_data( - wallet_address: Option, - token_name: &str, - farm_client: &State, -) -> Result, NotFound> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let token_data = farm_client - .get_token_account_data(&wallet_address, token_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(token_data)) -} - -/// Returns native SOL balance -#[get("/account_balance?")] -async fn get_account_balance( - wallet_address: Option, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let balance = farm_client - .get_account_balance(&wallet_address) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(balance.to_string()) -} - -/// Returns token balance for the associated token account address -#[get("/token_account_balance?&")] -async fn get_token_account_balance( - wallet_address: Option, - token_name: &str, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let token_balance = farm_client - .get_token_account_balance(&wallet_address, token_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(token_balance.to_string()) -} - -/// Returns token balance for the specified token account address -#[get("/token_account_balance_with_address?")] -async fn get_token_account_balance_with_address( - token_account: Option, - farm_client: &State, -) -> Result> { - let token_account = check_unwrap_pubkey(token_account, "token_account")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let token_balance = farm_client - .get_token_account_balance_with_address(&token_account) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(token_balance.to_string()) -} - -/// Returns true if the associated token account exists and is initialized -#[get("/has_active_token_account?&")] -async fn has_active_token_account( - wallet_address: Option, - token_name: &str, - farm_client: &State, -) -> Result, NotFound> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let has_active_account = farm_client.has_active_token_account(&wallet_address, token_name); - - Ok(Json(has_active_account)) -} - -/// Returns current admin signers for the Fund -#[get("/fund_admins?")] -async fn get_fund_admins( - name: &str, - farm_client: &State, -) -> Result, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let admins = farm_client - .get_fund_admins(name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(admins)) -} - -/// Returns user stats for specific Fund -#[get("/fund_user_info?&")] -async fn get_fund_user_info( - wallet_address: Option, - fund_name: &str, - farm_client: &State, -) -> Result, NotFound> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let user_info = farm_client - .get_fund_user_info(&wallet_address, fund_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(user_info)) -} - -/// Returns user stats for all Funds -#[get("/all_fund_user_infos?")] -async fn get_all_fund_user_infos( - wallet_address: Option, - farm_client: &State, -) -> Result>, NotFound> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let user_infos = farm_client - .get_all_fund_user_infos(&wallet_address) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(user_infos)) -} - -/// Returns user requests for specific Fund and token -#[get("/fund_user_requests?&&")] -async fn get_fund_user_requests( - wallet_address: Option, - fund_name: &str, - token_name: &str, - farm_client: &State, -) -> Result, NotFound> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let user_requests = farm_client - .get_fund_user_requests(&wallet_address, fund_name, token_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(user_requests)) -} - -/// Returns user requests for all tokens accepted by the Fund -#[get("/all_fund_user_requests?")] -async fn get_all_fund_user_requests( - fund_name: &str, - farm_client: &State, -) -> Result>, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let user_requests = farm_client - .get_all_fund_user_requests(fund_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(user_requests)) -} - -/// Returns Fund stats and config -#[get("/fund_info?")] -async fn get_fund_info( - fund_name: &str, - farm_client: &State, -) -> Result, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let fund_info = farm_client - .get_fund_info(fund_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(fund_info)) -} - -/// Returns Fund info and config for all Funds -#[get("/all_fund_infos")] -async fn get_all_fund_infos( - farm_client: &State, -) -> Result>, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let fund_infos = farm_client - .get_all_fund_infos() - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(fund_infos)) -} - -/// Returns the Fund assets info -#[get("/fund_assets?&")] -async fn get_fund_assets( - fund_name: &str, - asset_type: &str, - farm_client: &State, -) -> Result, NotFound> { - let asset_type = asset_type - .parse() - .map_err(|_| NotFound("Invalid asset_type argument".to_string()))?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let fund_assets = farm_client - .get_fund_assets(fund_name, asset_type) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(fund_assets)) -} - -/// Returns the Fund custody info -#[get("/fund_custody?&&")] -async fn get_fund_custody( - fund_name: &str, - token_name: &str, - custody_type: &str, - farm_client: &State, -) -> Result, NotFound> { - let custody_type = custody_type - .parse() - .map_err(|_| NotFound("Invalid custody_type argument".to_string()))?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let fund_custody = farm_client - .get_fund_custody(fund_name, token_name, custody_type) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(fund_custody)) -} - -/// Returns the Fund custody extended info -#[get("/fund_custody_with_balance?&&")] -async fn get_fund_custody_with_balance( - fund_name: &str, - token_name: &str, - custody_type: &str, - farm_client: &State, -) -> Result, NotFound> { - let custody_type = custody_type - .parse() - .map_err(|_| NotFound("Invalid custody_type argument".to_string()))?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let fund_custody = farm_client - .get_fund_custody_with_balance(fund_name, token_name, custody_type) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(fund_custody)) -} - -/// Returns all custodies belonging to the Fund sorted by custody_id -#[get("/fund_custodies?")] -async fn get_fund_custodies( - fund_name: &str, - farm_client: &State, -) -> Result>, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let fund_custodies = farm_client - .get_fund_custodies(fund_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(fund_custodies)) -} - -/// Returns all custodies belonging to the Fund with extended info -#[get("/fund_custodies_with_balance?")] -async fn get_fund_custodies_with_balance( - fund_name: &str, - farm_client: &State, -) -> Result>, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let fund_custodies = farm_client - .get_fund_custodies_with_balance(fund_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(fund_custodies)) -} - -/// Returns the Fund Vault info -#[get("/fund_vault?&&")] -async fn get_fund_vault( - fund_name: &str, - vault_name: &str, - vault_type: &str, - farm_client: &State, -) -> Result, NotFound> { - let vault_type = vault_type - .parse() - .map_err(|_| NotFound("Invalid vault_type argument".to_string()))?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let fund_vault = farm_client - .get_fund_vault(fund_name, vault_name, vault_type) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(fund_vault)) -} - -/// Returns all Vaults belonging to the Fund sorted by vault_id -#[get("/fund_vaults?")] -async fn get_fund_vaults( - fund_name: &str, - farm_client: &State, -) -> Result>, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let fund_vaults = farm_client - .get_fund_vaults(fund_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(fund_vaults)) -} - -/// Returns Fund's historical performance -#[get("/fund_stats?&&&")] -async fn get_fund_stats( - fund_name: &str, - timeframe: &str, - start_time: i64, - limit: u32, - fund_stats: &State>>, -) -> Result>, NotFound> { - let timeframe = timeframe - .parse() - .map_err(|_| NotFound("Invalid timeframe argument".to_string()))?; - let fund_stats = fund_stats - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let data = fund_stats - .select(fund_name, timeframe, start_time, limit) - .map_err(NotFound)?; - - Ok(Json(data)) -} - -/// Returns User's stacked balance -#[get("/user_stake_balance?&")] -async fn get_user_stake_balance( - wallet_address: Option, - farm_name: &str, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let balance = farm_client - .get_user_stake_balance(&wallet_address, farm_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(balance.to_string()) -} - -/// Returns Vault's stacked balance -#[get("/vault_stake_balance?")] -async fn get_vault_stake_balance( - vault_name: &str, - farm_client: &State, -) -> Result> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let balance = farm_client - .get_vault_stake_balance(vault_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(balance.to_string()) -} - -/// Returns current admin signers for the Vault -#[get("/vault_admins?")] -async fn get_vault_admins( - name: &str, - farm_client: &State, -) -> Result, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let admins = farm_client - .get_vault_admins(name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(admins)) -} - -/// Returns user stats for specific Vault -#[get("/vault_user_info?&")] -async fn get_vault_user_info( - wallet_address: Option, - vault_name: &str, - farm_client: &State, -) -> Result, NotFound> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let user_info = farm_client - .get_vault_user_info(&wallet_address, vault_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(user_info)) -} - -/// Returns Vault stats -#[get("/vault_info?")] -async fn get_vault_info( - vault_name: &str, - farm_client: &State, -) -> Result, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let vault_info = farm_client - .get_vault_info(vault_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(vault_info)) -} - -/// Returns Vault stats for all Vaults -#[get("/all_vault_infos")] -async fn get_all_vault_infos( - farm_client: &State, -) -> Result>, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let vault_infos = farm_client - .get_all_vault_infos() - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(vault_infos)) -} - -/// Returns number of decimal digits of the Vault token -#[get("/vault_token_decimals?")] -async fn get_vault_token_decimals( - vault_name: &str, - farm_client: &State, -) -> Result> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let decimals = farm_client - .get_vault_token_decimals(vault_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(decimals.to_string()) -} - -/// Returns number of decimal digits of the Vault token -#[get("/pool_tokens_decimals?")] -async fn get_pool_tokens_decimals( - pool_name: &str, - farm_client: &State, -) -> Result>, NotFound> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let decimals = farm_client - .get_pool_tokens_decimals(pool_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(Json(decimals)) -} - -/// Initializes a new User for the Vault -#[post("/user_init_vault?&")] -async fn user_init_vault( - wallet_keypair: Option, - vault_name: &str, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .user_init_vault(&wallet_keypair, vault_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Adds liquidity to the Vault -#[post("/add_liquidity_vault?&&&")] -async fn add_liquidity_vault( - wallet_keypair: Option, - vault_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .add_liquidity_vault( - &wallet_keypair, - vault_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Adds locked liquidity to the Vault -#[post("/add_locked_liquidity_vault?&&")] -async fn add_locked_liquidity_vault( - wallet_keypair: Option, - vault_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .add_locked_liquidity_vault(&wallet_keypair, vault_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Removes liquidity from the Vault -#[post("/remove_liquidity_vault?&&")] -async fn remove_liquidity_vault( - wallet_keypair: Option, - vault_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .remove_liquidity_vault(&wallet_keypair, vault_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Removes unlocked liquidity from the Vault -#[post("/remove_unlocked_liquidity_vault?&&")] -async fn remove_unlocked_liquidity_vault( - wallet_keypair: Option, - vault_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .remove_unlocked_liquidity_vault(&wallet_keypair, vault_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Adds liquidity to the Pool -#[post("/add_liquidity_pool?&&&")] -async fn add_liquidity_pool( - wallet_keypair: Option, - pool_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .add_liquidity_pool( - &wallet_keypair, - pool_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Removes liquidity from the Pool -#[post("/remove_liquidity_pool?&&")] -async fn remove_liquidity_pool( - wallet_keypair: Option, - pool_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .remove_liquidity_pool(&wallet_keypair, pool_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Swaps tokens -#[post( - "/swap?&&&&&" -)] -async fn swap( - wallet_keypair: Option, - protocol: &str, - from_token: &str, - to_token: &str, - ui_amount_in: f64, - min_ui_amount_out: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let protocol = protocol - .parse() - .map_err(|_| NotFound("Invalid protocol argument".to_string()))?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .swap( - &wallet_keypair, - protocol, - from_token, - to_token, - ui_amount_in, - min_ui_amount_out, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Initializes a new User for the Farm -#[post("/user_init?&")] -async fn user_init( - wallet_keypair: Option, - farm_name: &str, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .user_init(&wallet_keypair, farm_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Stakes tokens to the Farm -#[post("/stake?&&")] -async fn stake( - wallet_keypair: Option, - farm_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .stake(&wallet_keypair, farm_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Unstakes tokens from the Farm -#[post("/unstake?&&")] -async fn unstake( - wallet_keypair: Option, - farm_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .unstake(&wallet_keypair, farm_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Harvests rewards from the Farm -#[post("/harvest?&")] -async fn harvest( - wallet_keypair: Option, - farm_name: &str, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .harvest(&wallet_keypair, farm_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Cranks single Vault -#[post("/crank_vault?&&")] -async fn crank_vault( - wallet_keypair: Option, - vault_name: &str, - step: u64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .crank_vault(&wallet_keypair, vault_name, step) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Cranks all Vaults -#[post("/crank_vaults?&")] -async fn crank_vaults( - wallet_keypair: Option, - step: u64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let cranked = farm_client - .crank_vaults(&wallet_keypair, step) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(cranked.to_string()) -} - -/// Clears cache records to force re-pull from blockchain -#[post("/reset_cache")] -async fn reset_cache(farm_client: &State) -> Result> { - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - farm_client.reset_cache(); - - Ok("OK".to_string()) -} - -/// Initializes a new User for the Fund -#[post("/user_init_fund?&&")] -async fn user_init_fund( - wallet_keypair: Option, - fund_name: &str, - token_name: &str, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .user_init_fund(&wallet_keypair, fund_name, token_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Requests a new deposit to the Fund -#[post("/request_deposit_fund?&&&")] -async fn request_deposit_fund( - wallet_keypair: Option, - fund_name: &str, - token_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .request_deposit_fund(&wallet_keypair, fund_name, token_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Cancels pending deposit to the Fund -#[post("/cancel_deposit_fund?&&")] -async fn cancel_deposit_fund( - wallet_keypair: Option, - fund_name: &str, - token_name: &str, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .cancel_deposit_fund(&wallet_keypair, fund_name, token_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Requests a new withdrawal from the Fund -#[post("/request_withdrawal_fund?&&&")] -async fn request_withdrawal_fund( - wallet_keypair: Option, - fund_name: &str, - token_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .request_withdrawal_fund(&wallet_keypair, fund_name, token_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Cancels pending deposit to the Fund -#[post("/cancel_withdrawal_fund?&&")] -async fn cancel_withdrawal_fund( - wallet_keypair: Option, - fund_name: &str, - token_name: &str, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .cancel_withdrawal_fund(&wallet_keypair, fund_name, token_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Starts the Fund liquidation -#[post("/start_liquidation_fund?&")] -async fn start_liquidation_fund( - wallet_keypair: Option, - fund_name: &str, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .start_liquidation_fund(&wallet_keypair, fund_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Sets a new deposit schedule for the Fund -#[post("/set_fund_deposit_schedule?&&&&&&&")] -#[allow(clippy::too_many_arguments)] -async fn set_fund_deposit_schedule( - wallet_keypair: Option, - fund_name: &str, - start_time: i64, - end_time: i64, - approval_required: bool, - min_amount_usd: f64, - max_amount_usd: f64, - fee: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .set_fund_deposit_schedule( - &wallet_keypair, - fund_name, - &FundSchedule { - start_time, - end_time, - approval_required, - min_amount_usd, - max_amount_usd, - fee, - }, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Disables deposits to the Fund -#[post("/disable_deposits_fund?&")] -async fn disable_deposits_fund( - wallet_keypair: Option, - fund_name: &str, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .disable_deposits_fund(&wallet_keypair, fund_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Approves pending deposit to the Fund -#[post( - "/approve_deposit_fund?&&&&" -)] -async fn approve_deposit_fund( - wallet_keypair: Option, - fund_name: &str, - user_address: Option, - token_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let user_address = check_unwrap_pubkey(user_address, "user_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .approve_deposit_fund( - &wallet_keypair, - fund_name, - &user_address, - token_name, - ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Denies pending deposit to the Fund -#[post("/deny_deposit_fund?&&&&")] -async fn deny_deposit_fund( - wallet_keypair: Option, - fund_name: &str, - user_address: Option, - token_name: &str, - deny_reason: &str, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let user_address = check_unwrap_pubkey(user_address, "user_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .deny_deposit_fund( - &wallet_keypair, - fund_name, - &user_address, - token_name, - deny_reason, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Sets a new withdrawal schedule for the Fund -#[post("/set_fund_withdrawal_schedule?&&&&&&&")] -#[allow(clippy::too_many_arguments)] -async fn set_fund_withdrawal_schedule( - wallet_keypair: Option, - fund_name: &str, - start_time: i64, - end_time: i64, - approval_required: bool, - min_amount_usd: f64, - max_amount_usd: f64, - fee: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .set_fund_withdrawal_schedule( - &wallet_keypair, - fund_name, - &FundSchedule { - start_time, - end_time, - approval_required, - min_amount_usd, - max_amount_usd, - fee, - }, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Disables withdrawals from the Fund -#[post("/disable_withdrawals_fund?&")] -async fn disable_withdrawals_fund( - wallet_keypair: Option, - fund_name: &str, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .disable_withdrawals_fund(&wallet_keypair, fund_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Approves pending withdrawal from the Fund -#[post( - "/approve_withdrawal_fund?&&&&" -)] -async fn approve_withdrawal_fund( - wallet_keypair: Option, - fund_name: &str, - user_address: Option, - token_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let user_address = check_unwrap_pubkey(user_address, "user_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .approve_withdrawal_fund( - &wallet_keypair, - fund_name, - &user_address, - token_name, - ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Denies pending withdrawal from the Fund -#[post( - "/deny_withdrawal_fund?&&&&" -)] -async fn deny_withdrawal_fund( - wallet_keypair: Option, - fund_name: &str, - user_address: Option, - token_name: &str, - deny_reason: &str, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let user_address = check_unwrap_pubkey(user_address, "user_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .deny_withdrawal_fund( - &wallet_keypair, - fund_name, - &user_address, - token_name, - deny_reason, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Moves deposited assets from Deposit/Withdraw custody to the Fund -#[post("/lock_assets_fund?&&&")] -async fn lock_assets_fund( - wallet_keypair: Option, - fund_name: &str, - token_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .lock_assets_fund(&wallet_keypair, fund_name, token_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Releases assets from the Fund to Deposit/Withdraw custody -#[post("/unlock_assets_fund?&&&")] -async fn unlock_assets_fund( - wallet_keypair: Option, - fund_name: &str, - token_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .unlock_assets_fund(&wallet_keypair, fund_name, token_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Update Fund assets info based on custody holdings -#[post("/update_fund_assets_with_custody?&&")] -async fn update_fund_assets_with_custody( - wallet_keypair: Option, - fund_name: &str, - custody_id: u32, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .update_fund_assets_with_custody(&wallet_keypair, fund_name, custody_id) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Update Fund assets info based on all custodies -#[post("/update_fund_assets_with_custodies?&")] -async fn update_fund_assets_with_custodies( - wallet_keypair: Option, - fund_name: &str, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let updated = farm_client - .update_fund_assets_with_custodies(&wallet_keypair, fund_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(updated.to_string()) -} - -/// Update Fund assets info based on Vault holdings -#[post("/update_fund_assets_with_vault?&&")] -async fn update_fund_assets_with_vault( - wallet_keypair: Option, - fund_name: &str, - vault_id: u32, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .update_fund_assets_with_vault(&wallet_keypair, fund_name, vault_id) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Update Fund assets info based on Vault holdings -#[post("/update_fund_assets_with_vaults?&")] -async fn update_fund_assets_with_vaults( - wallet_keypair: Option, - fund_name: &str, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let updated = farm_client - .update_fund_assets_with_vaults(&wallet_keypair, fund_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(updated.to_string()) -} - -/// Swaps tokens in the Fund -#[post( - "/fund_swap?&&&&&&" -)] -#[allow(clippy::too_many_arguments)] -async fn fund_swap( - wallet_keypair: Option, - fund_name: &str, - protocol: &str, - from_token: &str, - to_token: &str, - ui_amount_in: f64, - min_ui_amount_out: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let protocol = protocol - .parse() - .map_err(|_| NotFound("Invalid protocol argument".to_string()))?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .fund_swap( - &wallet_keypair, - fund_name, - protocol, - from_token, - to_token, - ui_amount_in, - min_ui_amount_out, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Adds liquidity to the Pool in the Fund -#[post("/fund_add_liquidity_pool?&&&&")] -async fn fund_add_liquidity_pool( - wallet_keypair: Option, - fund_name: &str, - pool_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .fund_add_liquidity_pool( - &wallet_keypair, - fund_name, - pool_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Removes liquidity from the Pool in the Fund -#[post("/fund_remove_liquidity_pool?&&&")] -async fn fund_remove_liquidity_pool( - wallet_keypair: Option, - fund_name: &str, - pool_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .fund_remove_liquidity_pool(&wallet_keypair, fund_name, pool_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Initializes a new User for the Farm in the Fund -#[post("/fund_user_init_farm?&&")] -async fn fund_user_init_farm( - wallet_keypair: Option, - fund_name: &str, - farm_name: &str, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .fund_user_init_farm(&wallet_keypair, fund_name, farm_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Stakes tokens to the Farm in the Fund -#[post("/fund_stake?&&&")] -async fn fund_stake( - wallet_keypair: Option, - fund_name: &str, - farm_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .fund_stake(&wallet_keypair, fund_name, farm_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Unstakes tokens from the Farm in the Fund -#[post("/fund_unstake?&&&")] -async fn fund_unstake( - wallet_keypair: Option, - fund_name: &str, - farm_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .fund_unstake(&wallet_keypair, fund_name, farm_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Harvests rewards from the Farm in the Fund -#[post("/fund_harvest?&&")] -async fn fund_harvest( - wallet_keypair: Option, - fund_name: &str, - farm_name: &str, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .fund_harvest(&wallet_keypair, fund_name, farm_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Initializes a new User for the Vault in the Fund -#[post("/fund_user_init_vault?&&")] -async fn fund_user_init_vault( - wallet_keypair: Option, - fund_name: &str, - vault_name: &str, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .fund_user_init_vault(&wallet_keypair, fund_name, vault_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Adds liquidity to the Vault in the Fund -#[post("/fund_add_liquidity_vault?&&&&")] -async fn fund_add_liquidity_vault( - wallet_keypair: Option, - fund_name: &str, - vault_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .fund_add_liquidity_vault( - &wallet_keypair, - fund_name, - vault_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Adds locked liquidity to the Vault in the Fund -#[post("/fund_add_locked_liquidity_vault?&&&")] -async fn fund_add_locked_liquidity_vault( - wallet_keypair: Option, - fund_name: &str, - vault_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .fund_add_locked_liquidity_vault(&wallet_keypair, fund_name, vault_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Removes liquidity from the Vault in the Fund -#[post("/fund_remove_liquidity_vault?&&&")] -async fn fund_remove_liquidity_vault( - wallet_keypair: Option, - fund_name: &str, - vault_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .fund_remove_liquidity_vault(&wallet_keypair, fund_name, vault_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Removes unlocked liquidity from the Vault in the Fund -#[post( - "/fund_remove_unlocked_liquidity_vault?&&&" -)] -async fn fund_remove_unlocked_liquidity_vault( - wallet_keypair: Option, - fund_name: &str, - vault_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_keypair = check_unwrap_keypair(wallet_keypair, "wallet_keypair")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let signature = farm_client - .fund_remove_unlocked_liquidity_vault(&wallet_keypair, fund_name, vault_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(signature.to_string()) -} - -/// Returns a new Instruction for creating system account -#[get("/new_instruction_create_system_account?&&&&")] -async fn new_instruction_create_system_account( - wallet_address: Option, - new_address: Option, - lamports: u64, - space: usize, - owner: Option, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let new_address = check_unwrap_pubkey(new_address, "new_address")?; - let owner = check_unwrap_pubkey(owner, "owner")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_create_system_account( - &wallet_address, - &new_address, - lamports, - space, - &owner, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for creating system account with seed -#[get("/new_instruction_create_system_account_with_seed?&&&&&")] -async fn new_instruction_create_system_account_with_seed( - wallet_address: Option, - base_address: Option, - seed: &str, - lamports: u64, - space: usize, - owner: Option, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let base_address = check_unwrap_pubkey(base_address, "base_address")?; - let owner = check_unwrap_pubkey(owner, "owner")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_create_system_account_with_seed( - &wallet_address, - &base_address, - seed, - lamports, - space, - &owner, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for closing system account -#[get("/new_instruction_close_system_account?&")] -async fn new_instruction_close_system_account( - wallet_address: Option, - target_address: Option, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let target_address = check_unwrap_pubkey(target_address, "target_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_close_system_account(&wallet_address, &target_address) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns the native SOL transfer instruction -#[get("/new_instruction_transfer?&&")] -async fn new_instruction_transfer( - wallet_address: Option, - destination_wallet: Option, - sol_ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let destination_wallet = check_unwrap_pubkey(destination_wallet, "destination_wallet")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_transfer(&wallet_address, &destination_wallet, sol_ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a tokens transfer instruction -#[get("/new_instruction_token_transfer?&&&")] -async fn new_instruction_token_transfer( - wallet_address: Option, - token_name: &str, - destination_wallet: Option, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let destination_wallet = check_unwrap_pubkey(destination_wallet, "destination_wallet")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_token_transfer(&wallet_address, token_name, &destination_wallet, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for syncing token balance for the specified account -#[get("/new_instruction_sync_token_balance?&")] -async fn new_instruction_sync_token_balance( - wallet_address: Option, - token_name: &str, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_sync_token_balance(&wallet_address, token_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for creating associated token account -#[get("/new_instruction_create_token_account?&")] -async fn new_instruction_create_token_account( - wallet_address: Option, - token_name: &str, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_create_token_account(&wallet_address, token_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for closing associated token account -#[get("/new_instruction_close_token_account?&")] -async fn new_instruction_close_token_account( - wallet_address: Option, - token_name: &str, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_close_token_account(&wallet_address, token_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for initializing a new User for the Vault -#[get("/new_instruction_user_init_vault?&")] -async fn new_instruction_user_init_vault( - wallet_address: Option, - vault_name: &str, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_user_init_vault(&wallet_address, vault_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for adding liquidity to the Vault -#[get("/new_instruction_add_liquidity_vault?&&&")] -async fn new_instruction_add_liquidity_vault( - wallet_address: Option, - vault_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_add_liquidity_vault( - &wallet_address, - vault_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for locking liquidity in the Vault -#[get("/new_instruction_lock_liquidity_vault?&&")] -async fn new_instruction_lock_liquidity_vault( - wallet_address: Option, - vault_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_lock_liquidity_vault(&wallet_address, vault_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for unlocking liquidity from the Vault -#[get("/new_instruction_unlock_liquidity_vault?&&")] -async fn new_instruction_unlock_liquidity_vault( - wallet_address: Option, - vault_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_unlock_liquidity_vault(&wallet_address, vault_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for removing liquidity from the Vault -#[get("/new_instruction_remove_liquidity_vault?&&")] -async fn new_instruction_remove_liquidity_vault( - wallet_address: Option, - vault_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_remove_liquidity_vault(&wallet_address, vault_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for adding liquidity to the Pool -#[get("/new_instruction_add_liquidity_pool?&&&")] -async fn new_instruction_add_liquidity_pool( - wallet_address: Option, - pool_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_add_liquidity_pool( - &wallet_address, - pool_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for removing liquidity from the Pool -#[get("/new_instruction_remove_liquidity_pool?&&")] -async fn new_instruction_remove_liquidity_pool( - wallet_address: Option, - pool_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_remove_liquidity_pool(&wallet_address, pool_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for wrapping the token into protocol specific token -#[get("/new_instruction_wrap_token?&&&")] -async fn new_instruction_wrap_token( - wallet_address: Option, - pool_name: &str, - token_to_wrap: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let token_to_wrap = token_to_wrap - .parse() - .map_err(|_| NotFound("Invalid token_to_wrap argument".to_string()))?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_wrap_token(&wallet_address, pool_name, token_to_wrap, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for unwrapping the token from protocol specific token -#[get("/new_instruction_unwrap_token?&&&")] -async fn new_instruction_unwrap_token( - wallet_address: Option, - pool_name: &str, - token_to_unwrap: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let token_to_unwrap = token_to_unwrap - .parse() - .map_err(|_| NotFound("Invalid token_to_unwrap argument".to_string()))?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_unwrap_token(&wallet_address, pool_name, token_to_unwrap, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for tokens swap -#[get("/new_instruction_swap?&&&&&")] -async fn new_instruction_swap( - wallet_address: Option, - protocol: &str, - from_token: &str, - to_token: &str, - ui_amount_in: f64, - min_ui_amount_out: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let protocol = protocol - .parse() - .map_err(|_| NotFound("Invalid protocol argument".to_string()))?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_swap( - &wallet_address, - protocol, - from_token, - to_token, - ui_amount_in, - min_ui_amount_out, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for initializing a new User in the Farm -#[get("/new_instruction_user_init?&")] -async fn new_instruction_user_init( - wallet_address: Option, - farm_name: &str, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_user_init(&wallet_address, farm_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for tokens staking -#[get("/new_instruction_stake?&&")] -async fn new_instruction_stake( - wallet_address: Option, - farm_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_stake(&wallet_address, farm_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for tokens unstaking -#[get("/new_instruction_unstake?&&")] -async fn new_instruction_unstake( - wallet_address: Option, - farm_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_unstake(&wallet_address, farm_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for rewards harvesting -#[get("/new_instruction_harvest?&")] -async fn new_instruction_harvest( - wallet_address: Option, - farm_name: &str, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_harvest(&wallet_address, farm_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Vault Crank Instruction -#[get("/new_instruction_crank_vault?&&")] -async fn new_instruction_crank_vault( - wallet_address: Option, - vault_name: &str, - step: u64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_crank_vault(&wallet_address, vault_name, step) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for initializing a new User for the Fund -#[get("/new_instruction_user_init_fund?&&")] -async fn new_instruction_user_init_fund( - wallet_address: Option, - fund_name: &str, - token_name: &str, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_user_init_fund(&wallet_address, fund_name, token_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for requesting deposit to the Fund -#[get( - "/new_instruction_request_deposit_fund?&&&" -)] -async fn new_instruction_request_deposit_fund( - wallet_address: Option, - fund_name: &str, - token_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_request_deposit_fund(&wallet_address, fund_name, token_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for canceling pending deposit to the Fund -#[get("/new_instruction_cancel_deposit_fund?&&")] -async fn new_instruction_cancel_deposit_fund( - wallet_address: Option, - fund_name: &str, - token_name: &str, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_cancel_deposit_fund(&wallet_address, fund_name, token_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for requesting withdrawal from the Fund -#[get("/new_instruction_request_withdrawal_fund?&&&")] -async fn new_instruction_request_withdrawal_fund( - wallet_address: Option, - fund_name: &str, - token_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_request_withdrawal_fund(&wallet_address, fund_name, token_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for canceling pending withdrawal from the Fund -#[get("/new_instruction_cancel_withdrawal_fund?&&")] -async fn new_instruction_cancel_withdrawal_fund( - wallet_address: Option, - fund_name: &str, - token_name: &str, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_cancel_withdrawal_fund(&wallet_address, fund_name, token_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for initiating liquidation of the Fund -#[get("/new_instruction_start_liquidation_fund?&")] -async fn new_instruction_start_liquidation_fund( - wallet_address: Option, - fund_name: &str, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_start_liquidation_fund(&wallet_address, fund_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new set deposit schedule Instruction -#[get("/new_instruction_set_fund_deposit_schedule?&&&&&&&")] -#[allow(clippy::too_many_arguments)] -async fn new_instruction_set_fund_deposit_schedule( - wallet_address: Option, - fund_name: &str, - start_time: i64, - end_time: i64, - approval_required: bool, - min_amount_usd: f64, - max_amount_usd: f64, - fee: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_set_fund_deposit_schedule( - &wallet_address, - fund_name, - &FundSchedule { - start_time, - end_time, - approval_required, - min_amount_usd, - max_amount_usd, - fee, - }, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for disabling deposits to the Fund -#[get("/new_instruction_disable_deposits_fund?&")] -async fn new_instruction_disable_deposits_fund( - wallet_address: Option, - fund_name: &str, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_disable_deposits_fund(&wallet_address, fund_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for approving deposit to the Fund -#[get("/new_instruction_approve_deposit_fund?&&&&")] -async fn new_instruction_approve_deposit_fund( - wallet_address: Option, - user_address: Option, - fund_name: &str, - token_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let user_address = check_unwrap_pubkey(user_address, "user_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_approve_deposit_fund( - &wallet_address, - &user_address, - fund_name, - token_name, - ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for denying deposit to the Fund -#[get("/new_instruction_deny_deposit_fund?&&&&")] -async fn new_instruction_deny_deposit_fund( - wallet_address: Option, - user_address: Option, - fund_name: &str, - token_name: &str, - deny_reason: &str, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let user_address = check_unwrap_pubkey(user_address, "user_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_deny_deposit_fund( - &wallet_address, - &user_address, - fund_name, - token_name, - deny_reason, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new set withdrawal schedule Instruction -#[get("/new_instruction_set_fund_withdrawal_schedule?&&&&&&&")] -#[allow(clippy::too_many_arguments)] -async fn new_instruction_set_fund_withdrawal_schedule( - wallet_address: Option, - fund_name: &str, - start_time: i64, - end_time: i64, - approval_required: bool, - min_amount_usd: f64, - max_amount_usd: f64, - fee: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_set_fund_withdrawal_schedule( - &wallet_address, - fund_name, - &FundSchedule { - start_time, - end_time, - approval_required, - min_amount_usd, - max_amount_usd, - fee, - }, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for disabling withdrawals from the Fund -#[get("/new_instruction_disable_withdrawals_fund?&")] -async fn new_instruction_disable_withdrawals_fund( - wallet_address: Option, - fund_name: &str, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_disable_withdrawals_fund(&wallet_address, fund_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for approving withdrawal from the Fund -#[get("/new_instruction_approve_withdrawal_fund?&&&&")] -async fn new_instruction_approve_withdrawal_fund( - wallet_address: Option, - user_address: Option, - fund_name: &str, - token_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let user_address = check_unwrap_pubkey(user_address, "user_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_approve_withdrawal_fund( - &wallet_address, - &user_address, - fund_name, - token_name, - ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for denying withdrawal from the Fund -#[get("/new_instruction_deny_withdrawal_fund?&&&&")] -async fn new_instruction_deny_withdrawal_fund( - wallet_address: Option, - user_address: Option, - fund_name: &str, - token_name: &str, - deny_reason: &str, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let user_address = check_unwrap_pubkey(user_address, "user_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_deny_withdrawal_fund( - &wallet_address, - &user_address, - fund_name, - token_name, - deny_reason, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for moving deposited assets to the Fund -#[get("/new_instruction_lock_assets_fund?&&&")] -async fn new_instruction_lock_assets_fund( - wallet_address: Option, - fund_name: &str, - token_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_lock_assets_fund(&wallet_address, fund_name, token_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for releasing assets from the Fund to Deposit/Withdraw custody -#[get("/new_instruction_unlock_assets_fund?&&&")] -async fn new_instruction_unlock_assets_fund( - wallet_address: Option, - fund_name: &str, - token_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_unlock_assets_fund(&wallet_address, fund_name, token_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for updating Fund assets based on custody holdings -#[get("/new_instruction_update_fund_assets_with_custody?&&")] -async fn new_instruction_update_fund_assets_with_custody( - wallet_address: Option, - fund_name: &str, - custody_id: u32, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_update_fund_assets_with_custody(&wallet_address, fund_name, custody_id) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for updating Fund assets with Vault holdings -#[get("/new_instruction_update_fund_assets_with_vault?&&")] -async fn new_instruction_update_fund_assets_with_vault( - wallet_address: Option, - fund_name: &str, - vault_id: u32, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_update_fund_assets_with_vault(&wallet_address, fund_name, vault_id) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for tokens swap in the Fund -#[get("/new_instruction_fund_swap?&&&&&&")] -#[allow(clippy::too_many_arguments)] -async fn new_instruction_fund_swap( - wallet_address: Option, - fund_name: &str, - protocol: &str, - from_token: &str, - to_token: &str, - ui_amount_in: f64, - min_ui_amount_out: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let protocol = protocol - .parse() - .map_err(|_| NotFound("Invalid protocol argument".to_string()))?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_fund_swap( - &wallet_address, - fund_name, - protocol, - from_token, - to_token, - ui_amount_in, - min_ui_amount_out, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for adding liquidity to the Pool in the Fund -#[get("/new_instruction_fund_add_liquidity_pool?&&&&")] -async fn new_instruction_fund_add_liquidity_pool( - wallet_address: Option, - fund_name: &str, - pool_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_fund_add_liquidity_pool( - &wallet_address, - fund_name, - pool_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for removing liquidity from the Pool in the Fund -#[get("/new_instruction_fund_remove_liquidity_pool?&&&")] -async fn new_instruction_fund_remove_liquidity_pool( - wallet_address: Option, - fund_name: &str, - pool_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_fund_remove_liquidity_pool( - &wallet_address, - fund_name, - pool_name, - ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for initializing a new User for the Farm in the Fund -#[get("/new_instruction_fund_user_init_farm?&&")] -async fn new_instruction_fund_user_init_farm( - wallet_address: Option, - fund_name: &str, - farm_name: &str, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_fund_user_init_farm(&wallet_address, fund_name, farm_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for tokens staking to the Farm in the Fund -#[get("/new_instruction_fund_stake?&&&")] -async fn new_instruction_fund_stake( - wallet_address: Option, - fund_name: &str, - farm_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_fund_stake(&wallet_address, fund_name, farm_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for tokens unstaking from the Farm in the Fund -#[get("/new_instruction_fund_unstake?&&&")] -async fn new_instruction_fund_unstake( - wallet_address: Option, - fund_name: &str, - farm_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_fund_unstake(&wallet_address, fund_name, farm_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for rewards harvesting from the Farm in the Fund -#[get("/new_instruction_fund_harvest?&&")] -async fn new_instruction_fund_harvest( - wallet_address: Option, - fund_name: &str, - farm_name: &str, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_fund_harvest(&wallet_address, fund_name, farm_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for initializing a new User for the Vault in the Fund -#[get("/new_instruction_fund_user_init_vault?&&")] -async fn new_instruction_fund_user_init_vault( - wallet_address: Option, - fund_name: &str, - vault_name: &str, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_fund_user_init_vault(&wallet_address, fund_name, vault_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for adding liquidity to the Vault in the Fund -#[get("/new_instruction_fund_add_liquidity_vault?&&&&")] -async fn new_instruction_fund_add_liquidity_vault( - wallet_address: Option, - fund_name: &str, - vault_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_fund_add_liquidity_vault( - &wallet_address, - fund_name, - vault_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for locking liquidity in the Vault in the Fund -#[get("/new_instruction_fund_lock_liquidity_vault?&&&")] -async fn new_instruction_fund_lock_liquidity_vault( - wallet_address: Option, - fund_name: &str, - vault_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_fund_lock_liquidity_vault( - &wallet_address, - fund_name, - vault_name, - ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for unlocking liquidity from the Vault in the Fund -#[get("/new_instruction_fund_unlock_liquidity_vault?&&&")] -async fn new_instruction_fund_unlock_liquidity_vault( - wallet_address: Option, - fund_name: &str, - vault_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_fund_unlock_liquidity_vault( - &wallet_address, - fund_name, - vault_name, - ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new Instruction for removing liquidity from the Vault in the Fund -#[get("/new_instruction_fund_remove_liquidity_vault?&&&")] -async fn new_instruction_fund_remove_liquidity_vault( - wallet_address: Option, - fund_name: &str, - vault_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instruction = farm_client - .new_instruction_fund_remove_liquidity_vault( - &wallet_address, - fund_name, - vault_name, - ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstruction::new(&instruction)) -} - -/// Returns a new complete set of instructions for tokens transfer -#[get("/all_instructions_token_transfer?&&&")] -async fn all_instructions_token_transfer( - wallet_address: Option, - token_name: &str, - destination_wallet: Option, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let destination_wallet = check_unwrap_pubkey(destination_wallet, "destination_wallet")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_token_transfer( - &wallet_address, - token_name, - &destination_wallet, - ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of instructions for SOL wrapping -#[get("/all_instructions_wrap_sol?&")] -async fn all_instructions_wrap_sol( - wallet_address: Option, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_wrap_sol(&wallet_address, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of instructions for SOL unwrapping -#[get("/all_instructions_unwrap_sol?")] -async fn all_instructions_unwrap_sol( - wallet_address: Option, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_unwrap_sol(&wallet_address) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of instructions for adding liquidity to the Vault -#[get("/all_instructions_add_liquidity_vault?&&&")] -async fn all_instructions_add_liquidity_vault( - wallet_address: Option, - vault_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_add_liquidity_vault( - &wallet_address, - vault_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of instructions for adding locked liquidity to the Vault -#[get("/all_instructions_add_locked_liquidity_vault?&&")] -async fn all_instructions_add_locked_liquidity_vault( - wallet_address: Option, - vault_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_add_locked_liquidity_vault(&wallet_address, vault_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of Instructions for removing liquidity from the Vault -#[get("/all_instructions_remove_liquidity_vault?&&")] -async fn all_instructions_remove_liquidity_vault( - wallet_address: Option, - vault_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_remove_liquidity_vault(&wallet_address, vault_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of Instructions for removing unlocked liquidity from the Vault -#[get( - "/all_instructions_remove_unlocked_liquidity_vault?&&" -)] -async fn all_instructions_remove_unlocked_liquidity_vault( - wallet_address: Option, - vault_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_remove_unlocked_liquidity_vault(&wallet_address, vault_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of Instructions for adding liquidity to the Pool -#[get( - "/all_instructions_add_liquidity_pool?&&&" -)] -async fn all_instructions_add_liquidity_pool( - wallet_address: Option, - pool_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_add_liquidity_pool( - &wallet_address, - pool_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of Instructions for removing liquidity from the Pool -#[get("/all_instructions_remove_liquidity_pool?&&")] -async fn all_instructions_remove_liquidity_pool( - wallet_address: Option, - pool_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_remove_liquidity_pool(&wallet_address, pool_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of Instructions for swapping tokens -#[get("/all_instructions_swap?&&&&&")] -async fn all_instructions_swap( - wallet_address: Option, - protocol: &str, - from_token: &str, - to_token: &str, - ui_amount_in: f64, - min_ui_amount_out: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let protocol = protocol - .parse() - .map_err(|_| NotFound("Invalid protocol argument".to_string()))?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_swap( - &wallet_address, - protocol, - from_token, - to_token, - ui_amount_in, - min_ui_amount_out, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of Instructions for staking tokens to the Farm -#[get("/all_instructions_stake?&&")] -async fn all_instructions_stake( - wallet_address: Option, - farm_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_stake(&wallet_address, farm_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of Instructions for unstaking tokens from the Farm -#[get("/all_instructions_unstake?&&")] -async fn all_instructions_unstake( - wallet_address: Option, - farm_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_unstake(&wallet_address, farm_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of Instructions for harvesting rewards from the Farm -#[get("/all_instructions_harvest?&")] -async fn all_instructions_harvest( - wallet_address: Option, - farm_name: &str, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_harvest(&wallet_address, farm_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of Instructions for requesting a new deposit to the Fund -#[get( - "/all_instructions_request_deposit_fund?&&&" -)] -async fn all_instructions_request_deposit_fund( - wallet_address: Option, - fund_name: &str, - token_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_request_deposit_fund(&wallet_address, fund_name, token_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of Instructions for requesting a new withdrawal from the Fund -#[get( - "/all_instructions_request_withdrawal_fund?&&&" -)] -async fn all_instructions_request_withdrawal_fund( - wallet_address: Option, - fund_name: &str, - token_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_request_withdrawal_fund(&wallet_address, fund_name, token_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of Instructions for swapping tokens in the Fund -#[get("/all_instructions_fund_swap?&&&&&&")] -#[allow(clippy::too_many_arguments)] -async fn all_instructions_fund_swap( - wallet_address: Option, - fund_name: &str, - protocol: &str, - from_token: &str, - to_token: &str, - ui_amount_in: f64, - min_ui_amount_out: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let protocol = protocol - .parse() - .map_err(|_| NotFound("Invalid protocol argument".to_string()))?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_fund_swap( - &wallet_address, - fund_name, - protocol, - from_token, - to_token, - ui_amount_in, - min_ui_amount_out, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of Instructions for adding liquidity to the Pool in the Fund -#[get( - "/all_instructions_fund_add_liquidity_pool?&&&&" -)] -async fn all_instructions_fund_add_liquidity_pool( - wallet_address: Option, - fund_name: &str, - pool_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_fund_add_liquidity_pool( - &wallet_address, - fund_name, - pool_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of Instructions for removing liquidity from the Pool in the Fund -#[get("/all_instructions_fund_remove_liquidity_pool?&&&")] -async fn all_instructions_fund_remove_liquidity_pool( - wallet_address: Option, - fund_name: &str, - pool_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_fund_remove_liquidity_pool( - &wallet_address, - fund_name, - pool_name, - ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of Instructions for staking tokens to the Farm in the Fund -#[get("/all_instructions_fund_stake?&&&")] -async fn all_instructions_fund_stake( - wallet_address: Option, - fund_name: &str, - farm_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_fund_stake(&wallet_address, fund_name, farm_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of Instructions for unstaking tokens from the Farm in the Fund -#[get("/all_instructions_fund_unstake?&&&")] -async fn all_instructions_fund_unstake( - wallet_address: Option, - fund_name: &str, - farm_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_fund_unstake(&wallet_address, fund_name, farm_name, ui_amount) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of Instructions for harvesting rewards from the Farm in the Fund -#[get("/all_instructions_fund_harvest?&&")] -async fn all_instructions_fund_harvest( - wallet_address: Option, - fund_name: &str, - farm_name: &str, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_fund_harvest(&wallet_address, fund_name, farm_name) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of instructions for adding liquidity to the Vault in the Fund -#[get("/all_instructions_fund_add_liquidity_vault?&&&&")] -async fn all_instructions_fund_add_liquidity_vault( - wallet_address: Option, - fund_name: &str, - vault_name: &str, - max_token_a_ui_amount: f64, - max_token_b_ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_fund_add_liquidity_vault( - &wallet_address, - fund_name, - vault_name, - max_token_a_ui_amount, - max_token_b_ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of instructions for adding locked liquidity to the Vault in the Fund -#[get( - "/all_instructions_fund_add_locked_liquidity_vault?&&&" -)] -async fn all_instructions_fund_add_locked_liquidity_vault( - wallet_address: Option, - fund_name: &str, - vault_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_fund_add_locked_liquidity_vault( - &wallet_address, - fund_name, - vault_name, - ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of Instructions for removing liquidity from the Vault in the Fund -#[get("/all_instructions_fund_remove_liquidity_vault?&&&")] -async fn all_instructions_fund_remove_liquidity_vault( - wallet_address: Option, - fund_name: &str, - vault_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_fund_remove_liquidity_vault( - &wallet_address, - fund_name, - vault_name, - ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Returns a new complete set of Instructions for removing unlocked liquidity from the Vault in the Fund -#[get( - "/all_instructions_fund_remove_unlocked_liquidity_vault?&&&" -)] -async fn all_instructions_fund_remove_unlocked_liquidity_vault( - wallet_address: Option, - fund_name: &str, - vault_name: &str, - ui_amount: f64, - farm_client: &State, -) -> Result> { - let wallet_address = check_unwrap_pubkey(wallet_address, "wallet_address")?; - let farm_client = farm_client - .inner() - .lock() - .map_err(|e| NotFound(e.to_string()))?; - let instructions = farm_client - .all_instructions_fund_remove_unlocked_liquidity_vault( - &wallet_address, - fund_name, - vault_name, - ui_amount, - ) - .map_err(|e| NotFound(e.to_string()))?; - - Ok(JsonWithInstructions::new(&instructions)) -} - -/// Retrieves data from URL as JSON -async fn get_url_data_as_json(url: &str) -> Result { - let response = reqwest::get(url).await.map_err(|err| err.to_string())?; - let text = response.text().await.map_err(|err| err.to_string())?; - let value = from_str(text.as_str()).map_err(|err| err.to_string())?; - Ok(value) -} - -/// Initializes network service -async fn init_rpc(rocket: Rocket) -> Rocket { - rocket -} - -/// Initilizes data to be served -async fn init_db( - config: &Config, - farm_client: &FarmClientArc, - git_tokens: &mut GitTokens, -) -> Result<()> { - // load tokens from GitHub - info!("Loading tokens from {}", config.token_list_url); - let dict: Value = get_url_data_as_json(&config.token_list_url).await.unwrap(); - assert!(dict.is_object()); - assert_ne!(dict["tokens"], json!(null)); - let loaded_tokens = dict["tokens"].as_array().unwrap(); - - info!("Loading data from the blockchain, this may take a few mins..."); - let farm_client = farm_client.lock().map_err(|e| e.to_string())?; - info!("Loading pools..."); - let _ = farm_client.get_pools().unwrap(); - info!("Loading farms..."); - let _ = farm_client.get_farms().unwrap(); - info!("Loading vaults..."); - let _ = farm_client.get_vaults().unwrap(); - info!("Loading funds..."); - let _ = farm_client.get_funds().unwrap(); - info!("Loading programs..."); - let _ = farm_client.get_program_ids().unwrap(); - info!("Loading tokens..."); - let _ = farm_client.get_tokens().unwrap(); - - for val in loaded_tokens { - let git_token: GitToken = from_value(val.clone()).unwrap(); - if git_token.chain_id == 101 { - if let Ok(spl_token) = farm_client.get_token(&git_token.symbol) { - if spl_token.mint == git_token.address { - git_tokens.insert(git_token.symbol.clone(), git_token.clone()); - } - } - } - } - - info!("Done!"); - - Ok(()) -} - -/// Entry point for JSON RPC, called from main -pub async fn stage(config: &Config) -> AdHoc { - info!("Connecting Farm Client to {}", config.farm_client_url); - let client_mutex = Arc::new(Mutex::new(FarmClient::new_with_commitment( - &config.farm_client_url, - CommitmentConfig::confirmed(), - ))); - // check Cluster connectivity and version - { - let farm_client = client_mutex - .lock() - .expect("Failed to get lock on Farm Client"); - let version = farm_client - .rpc_client - .get_version() - .expect("Failed to get Cluster version; Check Farm Client URL"); - info!("Cluster version: {}", version); - } - - let fund_stats = Arc::new(Mutex::new(FundStats::new(&config.sqlite_db_path).unwrap())); - - let mut git_tokens: GitTokens = GitTokens::new(); - init_db(config, &client_mutex, &mut git_tokens) - .await - .unwrap(); - - AdHoc::on_ignite("JSON RPC Stage", |rocket| async { - rocket - .manage(git_tokens) - .manage(client_mutex) - .manage(fund_stats) - .attach(Cors) - .attach(AdHoc::on_ignite("JSON RPC Init", init_rpc)) - .mount("/", FileServer::from(relative!("static"))) - .mount( - "/api/v1", - routes![ - get_admins, - get_program_admins, - get_git_token, - get_git_tokens, - get_fund, - get_funds, - get_fund_refs, - get_fund_by_ref, - get_fund_name, - find_funds, - get_vault, - get_vaults, - get_vault_refs, - get_vault_by_ref, - get_vault_name, - find_vaults, - find_vaults_with_vt, - get_pool, - get_pools, - get_pool_refs, - get_pool_by_ref, - get_pool_name, - find_pools, - find_pools_with_lp, - get_farm, - get_farms, - get_farm_refs, - get_farm_by_ref, - get_farm_name, - find_farms_with_lp, - get_token, - get_tokens, - get_token_refs, - get_token_by_ref, - get_token_name, - get_token_with_mint, - get_token_with_account, - get_program_id, - get_program_ids, - get_program_name, - get_fund_ref, - get_vault_ref, - get_pool_ref, - get_farm_ref, - get_token_ref, - get_vault_admins, - get_vault_user_info, - get_vault_info, - get_all_vault_infos, - get_fund_admins, - get_fund_user_info, - get_all_fund_user_infos, - get_fund_user_requests, - get_all_fund_user_requests, - get_fund_info, - get_all_fund_infos, - get_fund_assets, - get_fund_custody, - get_fund_custodies, - get_fund_custody_with_balance, - get_fund_custodies_with_balance, - get_fund_vault, - get_fund_vaults, - get_fund_stats, - get_pool_price, - get_oracle, - get_oracle_price, - get_account_balance, - get_protocols, - is_official_id, - is_fund_manager, - get_managed_funds, - create_system_account, - create_system_account_with_seed, - assign_system_account, - close_system_account, - transfer, - token_transfer, - wrap_sol, - unwrap_sol, - sync_token_balance, - get_or_create_token_account, - close_token_account, - get_token_supply, - get_associated_token_address, - get_wallet_tokens, - get_token_account_data, - get_token_account_balance, - get_token_account_balance_with_address, - has_active_token_account, - get_user_stake_balance, - get_vault_stake_balance, - get_vault_token_decimals, - get_pool_tokens_decimals, - user_init_vault, - add_liquidity_vault, - add_locked_liquidity_vault, - remove_liquidity_vault, - remove_unlocked_liquidity_vault, - add_liquidity_pool, - remove_liquidity_pool, - swap, - user_init, - stake, - unstake, - harvest, - crank_vault, - crank_vaults, - reset_cache, - user_init_fund, - request_deposit_fund, - cancel_deposit_fund, - request_withdrawal_fund, - cancel_withdrawal_fund, - start_liquidation_fund, - set_fund_deposit_schedule, - disable_deposits_fund, - approve_deposit_fund, - deny_deposit_fund, - set_fund_withdrawal_schedule, - disable_withdrawals_fund, - approve_withdrawal_fund, - deny_withdrawal_fund, - lock_assets_fund, - unlock_assets_fund, - update_fund_assets_with_custody, - update_fund_assets_with_custodies, - update_fund_assets_with_vault, - update_fund_assets_with_vaults, - fund_swap, - fund_add_liquidity_pool, - fund_remove_liquidity_pool, - fund_user_init_farm, - fund_stake, - fund_unstake, - fund_harvest, - fund_user_init_vault, - fund_add_liquidity_vault, - fund_add_locked_liquidity_vault, - fund_remove_liquidity_vault, - fund_remove_unlocked_liquidity_vault, - new_instruction_create_system_account, - new_instruction_create_system_account_with_seed, - new_instruction_close_system_account, - new_instruction_transfer, - new_instruction_token_transfer, - new_instruction_sync_token_balance, - new_instruction_create_token_account, - new_instruction_close_token_account, - new_instruction_user_init_vault, - new_instruction_add_liquidity_vault, - new_instruction_lock_liquidity_vault, - new_instruction_unlock_liquidity_vault, - new_instruction_remove_liquidity_vault, - new_instruction_crank_vault, - new_instruction_add_liquidity_pool, - new_instruction_remove_liquidity_pool, - new_instruction_wrap_token, - new_instruction_unwrap_token, - new_instruction_swap, - new_instruction_user_init, - new_instruction_stake, - new_instruction_unstake, - new_instruction_harvest, - new_instruction_user_init_fund, - new_instruction_request_deposit_fund, - new_instruction_cancel_deposit_fund, - new_instruction_request_withdrawal_fund, - new_instruction_cancel_withdrawal_fund, - new_instruction_start_liquidation_fund, - new_instruction_set_fund_deposit_schedule, - new_instruction_disable_deposits_fund, - new_instruction_approve_deposit_fund, - new_instruction_deny_deposit_fund, - new_instruction_set_fund_withdrawal_schedule, - new_instruction_disable_withdrawals_fund, - new_instruction_approve_withdrawal_fund, - new_instruction_deny_withdrawal_fund, - new_instruction_lock_assets_fund, - new_instruction_unlock_assets_fund, - new_instruction_update_fund_assets_with_custody, - new_instruction_update_fund_assets_with_vault, - new_instruction_fund_swap, - new_instruction_fund_add_liquidity_pool, - new_instruction_fund_remove_liquidity_pool, - new_instruction_fund_user_init_farm, - new_instruction_fund_stake, - new_instruction_fund_unstake, - new_instruction_fund_harvest, - new_instruction_fund_user_init_vault, - new_instruction_fund_add_liquidity_vault, - new_instruction_fund_lock_liquidity_vault, - new_instruction_fund_remove_liquidity_vault, - new_instruction_fund_unlock_liquidity_vault, - all_instructions_token_transfer, - all_instructions_wrap_sol, - all_instructions_unwrap_sol, - all_instructions_add_liquidity_vault, - all_instructions_add_locked_liquidity_vault, - all_instructions_remove_liquidity_vault, - all_instructions_remove_unlocked_liquidity_vault, - all_instructions_add_liquidity_pool, - all_instructions_remove_liquidity_pool, - all_instructions_swap, - all_instructions_stake, - all_instructions_unstake, - all_instructions_harvest, - all_instructions_request_deposit_fund, - all_instructions_request_withdrawal_fund, - all_instructions_fund_swap, - all_instructions_fund_add_liquidity_pool, - all_instructions_fund_remove_liquidity_pool, - all_instructions_fund_stake, - all_instructions_fund_unstake, - all_instructions_fund_harvest, - all_instructions_fund_add_liquidity_vault, - all_instructions_fund_add_locked_liquidity_vault, - all_instructions_fund_remove_liquidity_vault, - all_instructions_fund_remove_unlocked_liquidity_vault, - ], - ) - }) -} diff --git a/farms/farm-rpc/src/rpc/main.rs b/farms/farm-rpc/src/rpc/main.rs deleted file mode 100644 index 709a248ebfb..00000000000 --- a/farms/farm-rpc/src/rpc/main.rs +++ /dev/null @@ -1,179 +0,0 @@ -//! Solana Farms RPC Backend. - -#[macro_use] -extern crate lazy_static; -#[macro_use] -extern crate rocket; - -mod config; -mod http_rpc; - -#[path = "../stats/fund_stats.rs"] -mod fund_stats; - -use { - clap::{crate_description, crate_name, App, Arg}, - log::{debug, info}, - solana_clap_utils::input_validators::is_url, - url::Url, -}; - -#[rocket::main] -async fn main() { - let matches = App::new(crate_name!()) - .about(crate_description!()) - .version(solana_version::version!()) - .arg( - Arg::with_name("config_file") - .short("C") - .long("config-file") - .value_name("PATH") - .takes_value(true) - .help("Configuration file to use"), - ) - .arg( - Arg::with_name("save_config") - .short("S") - .long("save-config") - .value_name("PATH") - .takes_value(true) - .help("Write current config to a file"), - ) - .arg( - Arg::with_name("log_level") - .short("L") - .long("log-level") - .takes_value(true) - .help("Log verbosity level (debug, info, warning, error)") - .validator(|p| { - let allowed = ["debug", "info", "warning", "error"]; - if allowed.contains(&p.as_str()) { - Ok(()) - } else { - Err(String::from("Must be one of: debug, info, warning, error")) - } - }), - ) - .arg( - Arg::with_name("http_rpc_url") - .short("u") - .long("http-rpc-url") - .value_name("STR") - .takes_value(true) - .validator(is_url) - .help("URL for HTTP RPC service"), - ) - .arg( - Arg::with_name("websocket_url") - .short("w") - .long("websocket-url") - .value_name("STR") - .takes_value(true) - .validator(is_url) - .help("URL for Websocket service"), - ) - .arg( - Arg::with_name("max_threads") - .short("m") - .long("max-threads") - .value_name("NUM") - .takes_value(true) - .validator(|p| match p.parse::() { - Err(_) => Err(String::from("Must be unsigned integer")), - Ok(_) => Ok(()), - }) - .help("Max threads for incoming connections"), - ) - .arg( - Arg::with_name("token_list_url") - .short("t") - .long("token-list-url") - .value_name("STR") - .takes_value(true) - .validator(is_url) - .help("URL for Solana's tokens list"), - ) - .arg( - Arg::with_name("farm_client_url") - .short("f") - .long("farm-client-url") - .value_name("STR") - .takes_value(true) - .validator(is_url) - .help("RPC URL to use with Farm Client"), - ) - .arg( - Arg::with_name("sqlite_db_path") - .short("s") - .long("sqlite-db-path") - .value_name("STR") - .takes_value(true) - .help("RPC URL to use with Farm Client"), - ) - .get_matches(); - - // set log verbosity level - let mut log_level = String::from("solana=info"); - if let Some(level) = matches.value_of("log_level") { - log_level = "solana=".to_string() + level; - } - solana_logger::setup_with_default(log_level.as_str()); - - info!("Loading configuration..."); - - // start with default config settings - let mut config: config::Config = Default::default(); - // if config path is explicitly specified, load config from there and stop - // on error. Otherwise try to load from default path and allow to proceed - // with default config if file not found. - if let Some(config_file) = matches.value_of("config_file") { - config.load(config_file).unwrap(); - } else if let Some(ref config_file) = *config::CONFIG_FILE { - let _ = config.load(config_file); - } - // override loaded or default params with explicit cmd line arguments - if let Some(http_rpc_url) = matches.value_of("http_rpc_url") { - config.http_rpc_url = http_rpc_url.to_string(); - } - if let Some(websocket_url) = matches.value_of("websocket_url") { - config.websocket_url = websocket_url.to_string(); - } - if let Some(max_threads) = matches.value_of("max_threads") { - config.max_threads = max_threads.parse().unwrap(); - } - if let Some(token_list_url) = matches.value_of("token_list_url") { - config.token_list_url = token_list_url.to_string(); - } - if let Some(farm_client_url) = matches.value_of("farm_client_url") { - config.farm_client_url = farm_client_url.to_string(); - } - if let Some(sqlite_db_path) = matches.value_of("sqlite_db_path") { - config.sqlite_db_path = sqlite_db_path.to_string(); - } - // save config to a file - if let Some(config_file) = matches.value_of("save_config") { - config.save(config_file).unwrap(); - info!("Configuration saved to: {}", config_file); - } - - debug!("http_rpc_url: {}", config.http_rpc_url); - debug!("websocket_url: {}", config.websocket_url); - debug!("farm_client_url: {}", config.farm_client_url); - debug!("sqlite_db_path: {}", config.sqlite_db_path); - debug!("max_threads: {}", config.max_threads); - - info!("Starting HTTP RPC on {}", config.http_rpc_url); - let parsed_url: Url = config.http_rpc_url.parse().unwrap(); - let figment = rocket::Config::figment() - .merge(("port", parsed_url.port().unwrap())) - .merge(("address", parsed_url.host_str().unwrap())) - .merge(("workers", config.max_threads)) - .merge(("ident", "Farms HTTP RPC")); - - let http_rpc = rocket::custom(figment) - .attach(http_rpc::stage(&config).await) - .launch(); - let _ = http_rpc.await.unwrap(); - - info!("Shutting down..."); -} diff --git a/farms/farm-rpc/src/stats/collector.rs b/farms/farm-rpc/src/stats/collector.rs deleted file mode 100644 index a6e44774ca0..00000000000 --- a/farms/farm-rpc/src/stats/collector.rs +++ /dev/null @@ -1,53 +0,0 @@ -use { - crate::fund_stats::{FundStats, FundStatsRecord}, - log::{debug, info}, - solana_farm_client::client::FarmClient, - std::{collections::HashMap, thread, time::Duration}, -}; - -pub fn collect( - farm_client_url: &str, - sqlite_db_path: &str, - update_interval_sec: u64, -) -> Result<(), String> { - let db = FundStats::new(sqlite_db_path)?; - let client = FarmClient::new(farm_client_url); - let mut last_updates: HashMap = HashMap::new(); - - loop { - let funds = client.get_funds().map_err(|e| e.to_string())?; - - for fund_name in funds.keys() { - let fund_stats = client.get_fund_info(fund_name).map_err(|e| e.to_string())?; - let last_update = *last_updates.get(fund_name).unwrap_or(&0); - if fund_stats.assets_update_time > 0 && last_update != fund_stats.assets_update_time { - debug!( - "Updating Fund \"{}\" with {}...", - fund_name, - FundStatsRecord { - timestamp: fund_stats.assets_update_time, - assets_usd: fund_stats.current_assets_usd, - deposits_usd: fund_stats.amount_invested_usd, - withdrawals_usd: fund_stats.amount_removed_usd, - } - ); - db.update( - fund_name, - fund_stats.assets_update_time, - fund_stats.current_assets_usd, - fund_stats.amount_invested_usd, - fund_stats.amount_removed_usd, - )?; - last_updates.insert(fund_name.clone(), last_update); - } - } - - if update_interval_sec > 1 { - info!( - "Update complete, next check in {} secs...", - update_interval_sec - ); - } - thread::sleep(Duration::from_secs(update_interval_sec)); - } -} diff --git a/farms/farm-rpc/src/stats/fund_stats.rs b/farms/farm-rpc/src/stats/fund_stats.rs deleted file mode 100644 index 1a275662c03..00000000000 --- a/farms/farm-rpc/src/stats/fund_stats.rs +++ /dev/null @@ -1,205 +0,0 @@ -use { - log::info, - rusqlite::{Connection, OptionalExtension}, - serde::{Deserialize, Serialize}, - serde_json::to_string, - solana_sdk::program_error::ProgramError, -}; - -#[allow(dead_code)] -pub const QUERY_LIMIT: u32 = 500; - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)] -pub enum Timeframe { - Ticks, - Hourly, - Daily, -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)] -pub struct FundStatsRecord { - pub timestamp: i64, - pub assets_usd: f64, - pub deposits_usd: f64, - pub withdrawals_usd: f64, -} - -pub struct FundStats { - conn: Connection, -} - -#[allow(dead_code)] -impl FundStats { - pub fn new(db_path: &str) -> Result { - info!("Opening database {}...", db_path); - Ok(Self { - conn: Connection::open(db_path).map_err(|e| e.to_string())?, - }) - } - - pub fn update( - &self, - fund_name: &str, - timestamp: i64, - assets_usd: f64, - deposits_usd: f64, - withdrawals_usd: f64, - ) -> Result { - if !self.is_table_exists(fund_name)? { - info!( - "No existing tables found for the Fund \"{}\", creating new...", - fund_name - ); - self.init_table(fund_name)?; - self.init_view( - &(fund_name.to_string() + "_H"), - fund_name, - Timeframe::Hourly, - )?; - self.init_view(&(fund_name.to_string() + "_D"), fund_name, Timeframe::Daily)?; - } - - self.conn.execute( - &format!("REPLACE INTO '{}' (timestamp, assets_usd, deposits_usd, withdrawals_usd) values (?1, ?2, ?3, ?4)", fund_name), - &[×tamp.to_string(), &assets_usd.to_string(), &deposits_usd.to_string(), &withdrawals_usd.to_string()], - ).map_err(|e| e.to_string()) - } - - pub fn select( - &self, - fund_name: &str, - timeframe: Timeframe, - start_time: i64, - limit: u32, - ) -> Result, String> { - let table_name = fund_name.to_string() - + match timeframe { - Timeframe::Ticks => "", - Timeframe::Hourly => "_H", - Timeframe::Daily => "_D", - }; - let limit = if limit == 0 { - QUERY_LIMIT - } else { - std::cmp::min(limit, QUERY_LIMIT) - }; - - let mut query = if start_time > 0 { - self.conn - .prepare(&format!( - "SELECT * FROM '{}' WHERE timestamp >= {} LIMIT {}", - table_name, start_time, limit - )) - .map_err(|e| e.to_string())? - } else { - self.conn - .prepare(&format!("SELECT * FROM '{}' LIMIT {}", table_name, limit)) - .map_err(|e| e.to_string())? - }; - let res = query - .query_map([], |row| { - Ok(FundStatsRecord { - timestamp: row.get(0)?, - assets_usd: row.get(1)?, - deposits_usd: row.get(2)?, - withdrawals_usd: row.get(3)?, - }) - }) - .map_err(|e| e.to_string())? - .filter_map(|stat| stat.ok()) - .collect(); - - Ok(res) - } - - fn is_table_exists(&self, table_name: &str) -> Result { - let res: Option = self - .conn - .query_row( - &format!( - "SELECT name FROM sqlite_master WHERE type='table' AND name='{}'", - table_name - ), - [], - |row| row.get(0), - ) - .optional() - .map_err(|e| e.to_string())?; - if let Some(row) = res { - Ok(row == table_name) - } else { - Ok(false) - } - } - - fn init_table(&self, table_name: &str) -> Result { - self.conn - .execute( - &format!( - "CREATE TABLE IF NOT EXISTS '{}' ( - timestamp integer primary key, - assets_usd real not null, - deposits_usd real not null, - withdrawals_usd real not null - )", - table_name - ), - [], - ) - .map_err(|e| e.to_string()) - } - - fn init_view( - &self, - view_name: &str, - source_table: &str, - timeframe: Timeframe, - ) -> Result { - if matches!(timeframe, Timeframe::Ticks) {} - let timeframe = match timeframe { - Timeframe::Ticks => { - return Err(format!("Invalid timeframe for the view {}", view_name)); - } - Timeframe::Hourly => "%H", - Timeframe::Daily => "%D", - }; - self.conn - .execute( - &format!( - "CREATE VIEW IF NOT EXISTS '{}' as WITH windows AS (SELECT *, ROW_NUMBER() OVER (PARTITION BY strftime('{}', timestamp, 'unixepoch') ORDER BY timestamp) idx FROM '{}') SELECT * FROM windows WHERE idx = 1;", - view_name, timeframe, source_table - ), - [], - ) - .map_err(|e| e.to_string()) - } -} - -impl std::fmt::Display for Timeframe { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match *self { - Timeframe::Ticks => write!(f, "Ticks"), - Timeframe::Hourly => write!(f, "Hourly"), - Timeframe::Daily => write!(f, "Daily"), - } - } -} - -impl std::str::FromStr for Timeframe { - type Err = ProgramError; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "ticks" => Ok(Timeframe::Ticks), - "hourly" => Ok(Timeframe::Hourly), - "daily" => Ok(Timeframe::Daily), - _ => Err(ProgramError::InvalidArgument), - } - } -} - -impl std::fmt::Display for FundStatsRecord { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", to_string(&self).unwrap()) - } -} diff --git a/farms/farm-rpc/src/stats/main.rs b/farms/farm-rpc/src/stats/main.rs deleted file mode 100644 index 2735b0b21a9..00000000000 --- a/farms/farm-rpc/src/stats/main.rs +++ /dev/null @@ -1,110 +0,0 @@ -//! Funds performance stats collection program - -mod collector; -mod fund_stats; - -use { - clap::{crate_description, crate_name, App, Arg}, - log::{error, info}, - solana_clap_utils::input_validators::is_url, - std::{thread, time::Duration}, -}; - -fn main() { - let matches = App::new(crate_name!()) - .about(crate_description!()) - .version(solana_version::version!()) - .arg( - Arg::with_name("log_level") - .short("L") - .long("log-level") - .takes_value(true) - .default_value("info") - .global(true) - .help("Log verbosity level") - .possible_values(&["debug", "info", "warning", "error"]) - .hide_possible_values(false), - ) - .arg({ - let arg = Arg::with_name("config_file") - .short("C") - .long("config") - .takes_value(true) - .global(true) - .help("Configuration file to use"); - if let Some(ref config_file) = *solana_cli_config::CONFIG_FILE { - arg.default_value(config_file) - } else { - arg - } - }) - .arg( - Arg::with_name("update_interval_sec") - .short("i") - .long("update-interval-sec") - .value_name("SEC") - .takes_value(true) - .default_value("900") - .validator(|p| match p.parse::() { - Err(_) => Err(String::from("Must be unsigned integer")), - Ok(_) => Ok(()), - }) - .help("Stats update interval in seconds"), - ) - .arg( - Arg::with_name("farm_client_url") - .short("f") - .long("farm-client-url") - .value_name("STR") - .takes_value(true) - .validator(is_url) - .help("RPC URL to use with Farm Client"), - ) - .arg( - Arg::with_name("sqlite_db_path") - .short("s") - .long("sqlite-db-path") - .value_name("STR") - .takes_value(true) - .required(true) - .help("RPC URL to use with Farm Client"), - ) - .get_matches(); - - // set log verbosity level - let log_level = "solana=".to_string() + matches.value_of("log_level").unwrap(); - solana_logger::setup_with_default(log_level.as_str()); - - // load config params - let farm_client_url = if let Some(farm_client_url) = matches.value_of("farm_client_url") { - farm_client_url.to_string() - } else { - let cli_config = if let Some(config_file) = matches.value_of("config_file") { - match solana_cli_config::Config::load(config_file) { - Err(e) => { - panic!("Failed to load config file \"{}\":{}", config_file, e); - } - Ok(config) => config, - } - } else { - solana_cli_config::Config::default() - }; - cli_config.json_rpc_url - }; - - loop { - if let Err(e) = collector::collect( - &farm_client_url, - matches.value_of("sqlite_db_path").unwrap(), - matches - .value_of("update_interval_sec") - .unwrap() - .parse() - .unwrap(), - ) { - error!("Error: {}", e); - info!("Waiting for 20 secs before restarting the process..."); - thread::sleep(Duration::from_secs(20)); - } - } -} diff --git a/farms/farm-rpc/static/favicon.ico b/farms/farm-rpc/static/favicon.ico deleted file mode 100644 index da4839396bd..00000000000 Binary files a/farms/farm-rpc/static/favicon.ico and /dev/null differ diff --git a/farms/farm-rpc/static/index.html b/farms/farm-rpc/static/index.html deleted file mode 100644 index 24bb2277041..00000000000 --- a/farms/farm-rpc/static/index.html +++ /dev/null @@ -1,640 +0,0 @@ - - - - - - - - - - - - - Solana Farms RPC Service - - - -
-

Solana Farms RPC Service

-

Get:

-

Returns description and stats of all supported protocols

- /api/v1/protocols -

Returns current admin signers for the Main Router

- /api/v1/admins -

Returns program upgrade signers

- /api/v1/program_admins?program_id=[program_id] -

Returns Token metadata from Github

- /api/v1/git_token?name=[name] -

Returns all Tokens from Github

- /api/v1/git_tokens -

Returns the Fund struct for the given name

- /api/v1/fund?name=[name] -

Returns all Funds available

- /api/v1/funds -

Returns the Fund metadata address for the given name

- /api/v1/fund_ref?name=[name] -

Returns Fund refs: a map of Fund name to account address with metadata

- /api/v1/fund_refs -

Returns the Fund metadata at the specified address

- /api/v1/fund_by_ref?fund_ref=[fund_ref] -

Returns the Fund name for the given metadata address

- /api/v1/fund_name?fund_ref=[fund_ref] -

Returns all Funds that have Vaults with the name matching the pattern sorted by version

- /api/v1/find_funds?vault_name_pattern=[vault_name_pattern] -

Returns the Vault struct for the given name

- /api/v1/vault?name=[name] -

Returns all Vaults available

- /api/v1/vaults -

Returns the Vault metadata address for the given name

- /api/v1/vault_ref?name=[name] -

Returns Vault refs: a map of Vault name to account address with metadata

- /api/v1/vault_refs -

Returns the Vault metadata at the specified address

- /api/v1/vault_by_ref?vault_ref=[vault_ref] -

Returns the Vault name for the given metadata address

- /api/v1/vault_name?vault_ref=[vault_ref] -

Returns all Vaults with tokens A and B sorted by version

- /api/v1/find_vaults?token_a=[token_a]&token_b=[token_b] -

Returns all Vaults with tokens A and B sorted by version

- /api/v1/find_vaults_with_vt?vt_token_name=[vt_token_name] -

Returns the Pool struct for the given name

- /api/v1/pool?name=[name] -

Returns all Pools available

- /api/v1/pools -

Returns the Pool metadata address for the given name

- /api/v1/pool_ref?name=[name] -

Returns Pool refs: a map of Pool name to account address with metadata

- /api/v1/pool_refs -

Returns the Pool metadata at the specified address

- /api/v1/pool_by_ref?pool_ref=[pool_ref] -

Returns the Pool name for the given metadata address

- /api/v1/pool_name?pool_ref=[pool_ref] -

Returns all Pools with tokens A and B sorted by version for the given protocol

- /api/v1/find_pools?protocol=[protocol]&token_a=[token_a]&token_b=[token_b] -

Returns all Pools sorted by version for the given LP token

- /api/v1/find_pools_with_lp?lp_token=[lp_token] -

Returns pair's price based on the ratio of tokens in the pool

- /api/v1/pool_price?name=[name] -

Returns oracle address for the given token

- /api/v1/oracle?symbol=[symbol] -

Returns the price in USD for the given token

- /api/v1/oracle_price?symbol=[symbol]&max_price_age_sec=[max_price_age_sec]&max_price_error=[max_price_error] -

Returns the Farm struct for the given name

- /api/v1/farm?name=[name] -

Returns all Farms available

- /api/v1/farms -

Returns the Farm metadata address for the given name

- /api/v1/farm_ref?name=[name] -

Returns Farm refs: a map of Farm name to account address with metadata

- /api/v1/farm_refs -

Returns the Farm metadata at the specified address

- /api/v1/farm_by_ref?farm_ref=[farm_ref] -

Returns the Farm name for the given metadata address

- /api/v1/farm_name?farm_ref=[farm_ref] -

Returns all Farms for the given LP token

- /api/v1/find_farms_with_lp?lp_token=[lp_token] -

Returns the Token struct for the given name

- /api/v1/token?name=[name] -

Returns all Tokens available

- /api/v1/tokens -

Returns the Token metadata address for the given name

- /api/v1/token_ref?name=[name] -

Returns Token refs: a map of Token name to account address with metadata

- /api/v1/token_refs -

Returns the Token metadata at the specified address

- /api/v1/token_by_ref?token_ref=[token_ref] -

Returns the Token name for the given metadata address

- /api/v1/token_name?token_ref=[token_ref] -

Returns the Token metadata for the specified mint

- /api/v1/token_with_mint?token_mint=[token_mint] -

Returns the Token metadata for the specified token account

- /api/v1/token_with_account?token_account=[token_account] -

Returns the official Program ID for the given name

- /api/v1/program_id?name=[name] -

Returns all official Program IDs available

- /api/v1/program_ids -

Returns the official program name for the given Program ID

- /api/v1/program_name?prog_id=[prog_id] -

Checks if the given address is the official Program ID

- /api/v1/is_official_id?prog_id=[prog_id] -

Checks if the given address is the Fund manager

- /api/v1/is_fund_manager?wallet_address=[wallet_address] -

Returns all Funds managed by the given address

- /api/v1/managed_funds?wallet_address=[wallet_address] -

Returns token supply as UI amount

- /api/v1/token_supply?token_name=[token_name] -

Returns the associated token account address for the given token name

- /api/v1/associated_token_address?wallet_address=[wallet_address]&token_name=[token_name] -

Returns all tokens with active account in the wallet

- /api/v1/wallet_tokens?wallet_address=[wallet_address] -

Returns UiTokenAccount struct data for the associated token account address

- /api/v1/token_account_data?wallet_address=[wallet_address]&token_name=[token_name] -

Returns native SOL balance

- /api/v1/account_balance?wallet_address=[wallet_address] -

Returns token balance for the associated token account address

- /api/v1/token_account_balance?wallet_address=[wallet_address]&token_name=[token_name] -

Returns token balance for the specified token account address

- /api/v1/token_account_balance_with_address?token_account=[token_account] -

Returns true if the associated token account exists and is initialized

- /api/v1/has_active_token_account?wallet_address=[wallet_address]&token_name=[token_name] -

Returns current admin signers for the Fund

- /api/v1/fund_admins?name=[name] -

Returns user stats for specific Fund

- /api/v1/fund_user_info?wallet_address=[wallet_address]&fund_name=[fund_name] -

Returns user stats for all Funds

- /api/v1/all_fund_user_infos?wallet_address=[wallet_address] -

Returns user requests for specific Fund and token

- /api/v1/fund_user_requests?wallet_address=[wallet_address]&fund_name=[fund_name]&token_name=[token_name] -

Returns user requests for all tokens accepted by the Fund

- /api/v1/all_fund_user_requests?fund_name=[fund_name] -

Returns Fund stats and config

- /api/v1/fund_info?fund_name=[fund_name] -

Returns Fund info and config for all Funds

- /api/v1/all_fund_infos -

Returns the Fund assets info

- /api/v1/fund_assets?fund_name=[fund_name]&asset_type=[asset_type] -

Returns the Fund custody info

- /api/v1/fund_custody?fund_name=[fund_name]&token_name=[token_name]&custody_type=[custody_type] -

Returns the Fund custody extended info

- /api/v1/fund_custody_with_balance?fund_name=[fund_name]&token_name=[token_name]&custody_type=[custody_type] -

Returns all custodies belonging to the Fund sorted by custody_id

- /api/v1/fund_custodies?fund_name=[fund_name] -

Returns all custodies belonging to the Fund with extended info

- /api/v1/fund_custodies_with_balance?fund_name=[fund_name] -

Returns the Fund Vault info

- /api/v1/fund_vault?fund_name=[fund_name]&vault_name=[vault_name]&vault_type=[vault_type] -

Returns all Vaults belonging to the Fund sorted by vault_id

- /api/v1/fund_vaults?fund_name=[fund_name] -

Returns Fund's historical performance

- /api/v1/fund_stats?fund_name=[fund_name]&timeframe=[timeframe]&start_time=[start_time]&limit=[limit] -

Returns User's stacked balance

- /api/v1/user_stake_balance?wallet_address=[wallet_address]&farm_name=[farm_name] -

Returns Vault's stacked balance

- /api/v1/vault_stake_balance?vault_name=[vault_name] -

Returns current admin signers for the Vault

- /api/v1/vault_admins?name=[name] -

Returns user stats for specific Vault

- /api/v1/vault_user_info?wallet_address=[wallet_address]&vault_name=[vault_name] -

Returns Vault stats

- /api/v1/vault_info?vault_name=[vault_name] -

Returns Vault stats for all Vaults

- /api/v1/all_vault_infos -

Returns number of decimal digits of the Vault token

- /api/v1/vault_token_decimals?vault_name=[vault_name] -

Returns number of decimal digits of the Vault token

- /api/v1/pool_tokens_decimals?pool_name=[pool_name] -

Returns a new Instruction for creating system account

- /api/v1/new_instruction_create_system_account?wallet_address=[wallet_address]&new_address=[new_address]&lamports=[lamports]&space=[space]&owner=[owner] -

Returns a new Instruction for creating system account with seed

- /api/v1/new_instruction_create_system_account_with_seed?wallet_address=[wallet_address]&base_address=[base_address]&seed=[seed]&lamports=[lamports]&space=[space]&owner=[owner] -

Returns a new Instruction for closing system account

- /api/v1/new_instruction_close_system_account?wallet_address=[wallet_address]&target_address=[target_address] -

Returns the native SOL transfer instruction

- /api/v1/new_instruction_transfer?wallet_address=[wallet_address]&destination_wallet=[destination_wallet]&sol_ui_amount=[sol_ui_amount] -

Returns a tokens transfer instruction

- /api/v1/new_instruction_token_transfer?wallet_address=[wallet_address]&token_name=[token_name]&destination_wallet=[destination_wallet]&ui_amount=[ui_amount] -

Returns a new Instruction for syncing token balance for the specified account

- /api/v1/new_instruction_sync_token_balance?wallet_address=[wallet_address]&token_name=[token_name] -

Returns a new Instruction for creating associated token account

- /api/v1/new_instruction_create_token_account?wallet_address=[wallet_address]&token_name=[token_name] -

Returns a new Instruction for closing associated token account

- /api/v1/new_instruction_close_token_account?wallet_address=[wallet_address]&token_name=[token_name] -

Returns a new Instruction for initializing a new User for the Vault

- /api/v1/new_instruction_user_init_vault?wallet_address=[wallet_address]&vault_name=[vault_name] -

Returns a new Instruction for adding liquidity to the Vault

- /api/v1/new_instruction_add_liquidity_vault?wallet_address=[wallet_address]&vault_name=[vault_name]&max_token_a_ui_amount=[max_token_a_ui_amount]&max_token_b_ui_amount=[max_token_b_ui_amount] -

Returns a new Instruction for locking liquidity in the Vault

- /api/v1/new_instruction_lock_liquidity_vault?wallet_address=[wallet_address]&vault_name=[vault_name]&ui_amount=[ui_amount] -

Returns a new Instruction for unlocking liquidity from the Vault

- /api/v1/new_instruction_unlock_liquidity_vault?wallet_address=[wallet_address]&vault_name=[vault_name]&ui_amount=[ui_amount] -

Returns a new Instruction for removing liquidity from the Vault

- /api/v1/new_instruction_remove_liquidity_vault?wallet_address=[wallet_address]&vault_name=[vault_name]&ui_amount=[ui_amount] -

Returns a new Instruction for adding liquidity to the Pool

- /api/v1/new_instruction_add_liquidity_pool?wallet_address=[wallet_address]&pool_name=[pool_name]&max_token_a_ui_amount=[max_token_a_ui_amount]&max_token_b_ui_amount=[max_token_b_ui_amount] -

Returns a new Instruction for removing liquidity from the Pool

- /api/v1/new_instruction_remove_liquidity_pool?wallet_address=[wallet_address]&pool_name=[pool_name]&ui_amount=[ui_amount] -

Returns a new Instruction for wrapping the token into protocol specific token

- /api/v1/new_instruction_wrap_token?wallet_address=[wallet_address]&pool_name=[pool_name]&token_to_wrap=[token_to_wrap]&ui_amount=[ui_amount] -

Returns a new Instruction for unwrapping the token from protocol specific token

- /api/v1/new_instruction_unwrap_token?wallet_address=[wallet_address]&pool_name=[pool_name]&token_to_unwrap=[token_to_unwrap]&ui_amount=[ui_amount] -

Returns a new Instruction for tokens swap

- /api/v1/new_instruction_swap?wallet_address=[wallet_address]&protocol=[protocol]&from_token=[from_token]&to_token=[to_token]&ui_amount_in=[ui_amount_in]&min_ui_amount_out=[min_ui_amount_out] -

Returns a new Instruction for initializing a new User in the Farm

- /api/v1/new_instruction_user_init?wallet_address=[wallet_address]&farm_name=[farm_name] -

Returns a new Instruction for tokens staking

- /api/v1/new_instruction_stake?wallet_address=[wallet_address]&farm_name=[farm_name]&ui_amount=[ui_amount] -

Returns a new Instruction for tokens unstaking

- /api/v1/new_instruction_unstake?wallet_address=[wallet_address]&farm_name=[farm_name]&ui_amount=[ui_amount] -

Returns a new Instruction for rewards harvesting

- /api/v1/new_instruction_harvest?wallet_address=[wallet_address]&farm_name=[farm_name] -

Returns a new Vault Crank Instruction

- /api/v1/new_instruction_crank_vault?wallet_address=[wallet_address]&vault_name=[vault_name]&step=[step] -

Returns a new Instruction for initializing a new User for the Fund

- /api/v1/new_instruction_user_init_fund?wallet_address=[wallet_address]&fund_name=[fund_name]&token_name=[token_name] -

Returns a new Instruction for requesting deposit to the Fund

- /api/v1/new_instruction_request_deposit_fund?wallet_address=[wallet_address]&fund_name=[fund_name]&token_name=[token_name]&ui_amount=[ui_amount] -

Returns a new Instruction for canceling pending deposit to the Fund

- /api/v1/new_instruction_cancel_deposit_fund?wallet_address=[wallet_address]&fund_name=[fund_name]&token_name=[token_name] -

Returns a new Instruction for requesting withdrawal from the Fund

- /api/v1/new_instruction_request_withdrawal_fund?wallet_address=[wallet_address]&fund_name=[fund_name]&token_name=[token_name]&ui_amount=[ui_amount] -

Returns a new Instruction for canceling pending withdrawal from the Fund

- /api/v1/new_instruction_cancel_withdrawal_fund?wallet_address=[wallet_address]&fund_name=[fund_name]&token_name=[token_name] -

Returns a new Instruction for initiating liquidation of the Fund

- /api/v1/new_instruction_start_liquidation_fund?wallet_address=[wallet_address]&fund_name=[fund_name] -

Returns a new set deposit schedule Instruction

- /api/v1/new_instruction_set_fund_deposit_schedule?wallet_address=[wallet_address]&fund_name=[fund_name]&start_time=[start_time]&end_time=[end_time]&approval_required=[approval_required]&min_amount_usd=[min_amount_usd]&max_amount_usd=[max_amount_usd]&fee=[fee] -

Returns a new Instruction for disabling deposits to the Fund

- /api/v1/new_instruction_disable_deposits_fund?wallet_address=[wallet_address]&fund_name=[fund_name] -

Returns a new Instruction for approving deposit to the Fund

- /api/v1/new_instruction_approve_deposit_fund?wallet_address=[wallet_address]&user_address=[user_address]&fund_name=[fund_name]&token_name=[token_name]&ui_amount=[ui_amount] -

Returns a new Instruction for denying deposit to the Fund

- /api/v1/new_instruction_deny_deposit_fund?wallet_address=[wallet_address]&user_address=[user_address]&fund_name=[fund_name]&token_name=[token_name]&deny_reason=[deny_reason] -

Returns a new set withdrawal schedule Instruction

- /api/v1/new_instruction_set_fund_withdrawal_schedule?wallet_address=[wallet_address]&fund_name=[fund_name]&start_time=[start_time]&end_time=[end_time]&approval_required=[approval_required]&min_amount_usd=[min_amount_usd]&max_amount_usd=[max_amount_usd]&fee=[fee] -

Returns a new Instruction for disabling withdrawals from the Fund

- /api/v1/new_instruction_disable_withdrawals_fund?wallet_address=[wallet_address]&fund_name=[fund_name] -

Returns a new Instruction for approving withdrawal from the Fund

- /api/v1/new_instruction_approve_withdrawal_fund?wallet_address=[wallet_address]&user_address=[user_address]&fund_name=[fund_name]&token_name=[token_name]&ui_amount=[ui_amount] -

Returns a new Instruction for denying withdrawal from the Fund

- /api/v1/new_instruction_deny_withdrawal_fund?wallet_address=[wallet_address]&user_address=[user_address]&fund_name=[fund_name]&token_name=[token_name]&deny_reason=[deny_reason] -

Returns a new Instruction for moving deposited assets to the Fund

- /api/v1/new_instruction_lock_assets_fund?wallet_address=[wallet_address]&fund_name=[fund_name]&token_name=[token_name]&ui_amount=[ui_amount] -

Returns a new Instruction for releasing assets from the Fund to Deposit/Withdraw custody

- /api/v1/new_instruction_unlock_assets_fund?wallet_address=[wallet_address]&fund_name=[fund_name]&token_name=[token_name]&ui_amount=[ui_amount] -

Returns a new Instruction for updating Fund assets based on custody holdings

- /api/v1/new_instruction_update_fund_assets_with_custody?wallet_address=[wallet_address]&fund_name=[fund_name]&custody_id=[custody_id] -

Returns a new Instruction for updating Fund assets with Vault holdings

- /api/v1/new_instruction_update_fund_assets_with_vault?wallet_address=[wallet_address]&fund_name=[fund_name]&vault_id=[vault_id] -

Returns a new Instruction for tokens swap in the Fund

- /api/v1/new_instruction_fund_swap?wallet_address=[wallet_address]&fund_name=[fund_name]&protocol=[protocol]&from_token=[from_token]&to_token=[to_token]&ui_amount_in=[ui_amount_in]&min_ui_amount_out=[min_ui_amount_out] -

Returns a new Instruction for adding liquidity to the Pool in the Fund

- /api/v1/new_instruction_fund_add_liquidity_pool?wallet_address=[wallet_address]&fund_name=[fund_name]&pool_name=[pool_name]&max_token_a_ui_amount=[max_token_a_ui_amount]&max_token_b_ui_amount=[max_token_b_ui_amount] -

Returns a new Instruction for removing liquidity from the Pool in the Fund

- /api/v1/new_instruction_fund_remove_liquidity_pool?wallet_address=[wallet_address]&fund_name=[fund_name]&pool_name=[pool_name]&ui_amount=[ui_amount] -

Returns a new Instruction for initializing a new User for the Farm in the Fund

- /api/v1/new_instruction_fund_user_init_farm?wallet_address=[wallet_address]&fund_name=[fund_name]&farm_name=[farm_name] -

Returns a new Instruction for tokens staking to the Farm in the Fund

- /api/v1/new_instruction_fund_stake?wallet_address=[wallet_address]&fund_name=[fund_name]&farm_name=[farm_name]&ui_amount=[ui_amount] -

Returns a new Instruction for tokens unstaking from the Farm in the Fund

- /api/v1/new_instruction_fund_unstake?wallet_address=[wallet_address]&fund_name=[fund_name]&farm_name=[farm_name]&ui_amount=[ui_amount] -

Returns a new Instruction for rewards harvesting from the Farm in the Fund

- /api/v1/new_instruction_fund_harvest?wallet_address=[wallet_address]&fund_name=[fund_name]&farm_name=[farm_name] -

Returns a new Instruction for initializing a new User for the Vault in the Fund

- /api/v1/new_instruction_fund_user_init_vault?wallet_address=[wallet_address]&fund_name=[fund_name]&vault_name=[vault_name] -

Returns a new Instruction for adding liquidity to the Vault in the Fund

- /api/v1/new_instruction_fund_add_liquidity_vault?wallet_address=[wallet_address]&fund_name=[fund_name]&vault_name=[vault_name]&max_token_a_ui_amount=[max_token_a_ui_amount]&max_token_b_ui_amount=[max_token_b_ui_amount] -

Returns a new Instruction for locking liquidity in the Vault in the Fund

- /api/v1/new_instruction_fund_lock_liquidity_vault?wallet_address=[wallet_address]&fund_name=[fund_name]&vault_name=[vault_name]&ui_amount=[ui_amount] -

Returns a new Instruction for unlocking liquidity from the Vault in the Fund

- /api/v1/new_instruction_fund_unlock_liquidity_vault?wallet_address=[wallet_address]&fund_name=[fund_name]&vault_name=[vault_name]&ui_amount=[ui_amount] -

Returns a new Instruction for removing liquidity from the Vault in the Fund

- /api/v1/new_instruction_fund_remove_liquidity_vault?wallet_address=[wallet_address]&fund_name=[fund_name]&vault_name=[vault_name]&ui_amount=[ui_amount] -

Returns a new complete set of instructions for tokens transfer

- /api/v1/all_instructions_token_transfer?wallet_address=[wallet_address]&token_name=[token_name]&destination_wallet=[destination_wallet]&ui_amount=[ui_amount] -

Returns a new complete set of instructions for SOL wrapping

- /api/v1/all_instructions_wrap_sol?wallet_address=[wallet_address]&ui_amount=[ui_amount] -

Returns a new complete set of instructions for SOL unwrapping

- /api/v1/all_instructions_unwrap_sol?wallet_address=[wallet_address] -

Returns a new complete set of instructions for adding liquidity to the Vault

- /api/v1/all_instructions_add_liquidity_vault?wallet_address=[wallet_address]&vault_name=[vault_name]&max_token_a_ui_amount=[max_token_a_ui_amount]&max_token_b_ui_amount=[max_token_b_ui_amount] -

Returns a new complete set of instructions for adding locked liquidity to the Vault

- /api/v1/all_instructions_add_locked_liquidity_vault?wallet_address=[wallet_address]&vault_name=[vault_name]&ui_amount=[ui_amount] -

Returns a new complete set of Instructions for removing liquidity from the Vault

- /api/v1/all_instructions_remove_liquidity_vault?wallet_address=[wallet_address]&vault_name=[vault_name]&ui_amount=[ui_amount] -

Returns a new complete set of Instructions for removing unlocked liquidity from the Vault

- /api/v1/all_instructions_remove_unlocked_liquidity_vault?wallet_address=[wallet_address]&vault_name=[vault_name]&ui_amount=[ui_amount] -

Returns a new complete set of Instructions for adding liquidity to the Pool

- /api/v1/all_instructions_add_liquidity_pool?wallet_address=[wallet_address]&pool_name=[pool_name]&max_token_a_ui_amount=[max_token_a_ui_amount]&max_token_b_ui_amount=[max_token_b_ui_amount] -

Returns a new complete set of Instructions for removing liquidity from the Pool

- /api/v1/all_instructions_remove_liquidity_pool?wallet_address=[wallet_address]&pool_name=[pool_name]&ui_amount=[ui_amount] -

Returns a new complete set of Instructions for swapping tokens

- /api/v1/all_instructions_swap?wallet_address=[wallet_address]&protocol=[protocol]&from_token=[from_token]&to_token=[to_token]&ui_amount_in=[ui_amount_in]&min_ui_amount_out=[min_ui_amount_out] -

Returns a new complete set of Instructions for staking tokens to the Farm

- /api/v1/all_instructions_stake?wallet_address=[wallet_address]&farm_name=[farm_name]&ui_amount=[ui_amount] -

Returns a new complete set of Instructions for unstaking tokens from the Farm

- /api/v1/all_instructions_unstake?wallet_address=[wallet_address]&farm_name=[farm_name]&ui_amount=[ui_amount] -

Returns a new complete set of Instructions for harvesting rewards from the Farm

- /api/v1/all_instructions_harvest?wallet_address=[wallet_address]&farm_name=[farm_name] -

Returns a new complete set of Instructions for requesting a new deposit to the Fund

- /api/v1/all_instructions_request_deposit_fund?wallet_address=[wallet_address]&fund_name=[fund_name]&token_name=[token_name]&ui_amount=[ui_amount] -

Returns a new complete set of Instructions for requesting a new withdrawal from the Fund

- /api/v1/all_instructions_request_withdrawal_fund?wallet_address=[wallet_address]&fund_name=[fund_name]&token_name=[token_name]&ui_amount=[ui_amount] -

Returns a new complete set of Instructions for swapping tokens in the Fund

- /api/v1/all_instructions_fund_swap?wallet_address=[wallet_address]&fund_name=[fund_name]&protocol=[protocol]&from_token=[from_token]&to_token=[to_token]&ui_amount_in=[ui_amount_in]&min_ui_amount_out=[min_ui_amount_out] -

Returns a new complete set of Instructions for adding liquidity to the Pool in the Fund

- /api/v1/all_instructions_fund_add_liquidity_pool?wallet_address=[wallet_address]&fund_name=[fund_name]&pool_name=[pool_name]&max_token_a_ui_amount=[max_token_a_ui_amount]&max_token_b_ui_amount=[max_token_b_ui_amount] -

Returns a new complete set of Instructions for removing liquidity from the Pool in the Fund

- /api/v1/all_instructions_fund_remove_liquidity_pool?wallet_address=[wallet_address]&fund_name=[fund_name]&pool_name=[pool_name]&ui_amount=[ui_amount] -

Returns a new complete set of Instructions for staking tokens to the Farm in the Fund

- /api/v1/all_instructions_fund_stake?wallet_address=[wallet_address]&fund_name=[fund_name]&farm_name=[farm_name]&ui_amount=[ui_amount] -

Returns a new complete set of Instructions for unstaking tokens from the Farm in the Fund

- /api/v1/all_instructions_fund_unstake?wallet_address=[wallet_address]&fund_name=[fund_name]&farm_name=[farm_name]&ui_amount=[ui_amount] -

Returns a new complete set of Instructions for harvesting rewards from the Farm in the Fund

- /api/v1/all_instructions_fund_harvest?wallet_address=[wallet_address]&fund_name=[fund_name]&farm_name=[farm_name] -

Returns a new complete set of instructions for adding liquidity to the Vault in the Fund

- /api/v1/all_instructions_fund_add_liquidity_vault?wallet_address=[wallet_address]&fund_name=[fund_name]&vault_name=[vault_name]&max_token_a_ui_amount=[max_token_a_ui_amount]&max_token_b_ui_amount=[max_token_b_ui_amount] -

Returns a new complete set of instructions for adding locked liquidity to the Vault in the Fund -

- /api/v1/all_instructions_fund_add_locked_liquidity_vault?wallet_address=[wallet_address]&fund_name=[fund_name]&vault_name=[vault_name]&ui_amount=[ui_amount] -

Returns a new complete set of Instructions for removing liquidity from the Vault in the Fund

- /api/v1/all_instructions_fund_remove_liquidity_vault?wallet_address=[wallet_address]&fund_name=[fund_name]&vault_name=[vault_name]&ui_amount=[ui_amount] -

Returns a new complete set of Instructions for removing unlocked liquidity from the Vault in the - Fund

- /api/v1/all_instructions_fund_remove_unlocked_liquidity_vault?wallet_address=[wallet_address]&fund_name=[fund_name]&vault_name=[vault_name]&ui_amount=[ui_amount] -

Post:

-

Creates a new system account

-

Creates a new system account with seed

-

Assigns system account to a program

-

Closes existing system account

-

Transfers native SOL from the wallet to the destination

-

Transfers tokens from the wallet to the destination

-

Transfers native SOL from the wallet to the associated Wrapped SOL account

-

Transfers Wrapped SOL back to SOL by closing the associated Wrapped SOL account

-

Updates token balance of the account, usefull after transfer SOL to WSOL account

-

Returns the associated token account for the given user's main account or creates one

-

Closes existing token account associated with the given user's main account

-

Initializes a new User for the Vault

-

Adds liquidity to the Vault

-

Adds locked liquidity to the Vault

-

Removes liquidity from the Vault

-

Removes unlocked liquidity from the Vault

-

Adds liquidity to the Pool

-

Removes liquidity from the Pool

-

Swaps tokens

-

Initializes a new User for the Farm

-

Stakes tokens to the Farm

-

Unstakes tokens from the Farm

-

Harvests rewards from the Farm

-

Cranks single Vault

-

Cranks all Vaults

-

Clears cache records to force re-pull from blockchain

-

Initializes a new User for the Fund

-

Requests a new deposit to the Fund

-

Cancels pending deposit to the Fund

-

Requests a new withdrawal from the Fund

-

Cancels pending deposit to the Fund

-

Starts the Fund liquidation

-

Sets a new deposit schedule for the Fund

-

Disables deposits to the Fund

-

Approves pending deposit to the Fund

-

Denies pending deposit to the Fund

-

Sets a new withdrawal schedule for the Fund

-

Disables withdrawals from the Fund

-

Approves pending withdrawal from the Fund

-

Denies pending withdrawal from the Fund

-

Moves deposited assets from Deposit/Withdraw custody to the Fund

-

Releases assets from the Fund to Deposit/Withdraw custody

-

Update Fund assets info based on custody holdings

-

Update Fund assets info based on all custodies

-

Update Fund assets info based on Vault holdings

-

Update Fund assets info based on Vault holdings

-

Swaps tokens in the Fund

-

Adds liquidity to the Pool in the Fund

-

Removes liquidity from the Pool in the Fund

-

Initializes a new User for the Farm in the Fund

-

Stakes tokens to the Farm in the Fund

-

Unstakes tokens from the Farm in the Fund

-

Harvests rewards from the Farm in the Fund

-

Initializes a new User for the Vault in the Fund

-

Adds liquidity to the Vault in the Fund

-

Adds locked liquidity to the Vault in the Fund

-

Removes liquidity from the Vault in the Fund

-

Removes unlocked liquidity from the Vault in the Fund

-
- - diff --git a/farms/farm-rpc/static/manifest.json b/farms/farm-rpc/static/manifest.json deleted file mode 100644 index fd882ef77e5..00000000000 --- a/farms/farm-rpc/static/manifest.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "short_name": "Solana Farms", - "name": "Solana Farms RPC Service", - "icons": [ - { - "src": "favicon.ico", - "sizes": "64x64 32x32 24x24 16x16", - "type": "image/x-icon" - }, - { - "src": "rainbow192.png", - "type": "image/png", - "sizes": "192x192" - } - ], - "start_url": ".", - "display": "standalone", - "theme_color": "#75FBB4", - "background_color": "#ffffff" -} diff --git a/farms/farm-rpc/static/rainbow192.png b/farms/farm-rpc/static/rainbow192.png deleted file mode 100644 index bb7d3cea7ed..00000000000 Binary files a/farms/farm-rpc/static/rainbow192.png and /dev/null differ diff --git a/farms/farm-rpc/swagger.yaml b/farms/farm-rpc/swagger.yaml deleted file mode 100644 index f9aa06b0927..00000000000 --- a/farms/farm-rpc/swagger.yaml +++ /dev/null @@ -1,3807 +0,0 @@ -openapi: 3.0.1 -info: - title: Solana Farms RPC Service - description: RPC service for interaction with Pools, Farms, Vaults, and Funds built on Solana - version: "0.1" -servers: - - url: "http://127.0.0.1:9000" - - url: "http://localhost:9000" -paths: - /api/v1/protocols: - get: - description: "Returns description and stats of all supported protocols" - responses: - default: - description: The result will be an array of ProtocolInfo objects in Json or 404 status code with error description. - - /api/v1/admins: - get: - description: "Returns current admin signers for the Main Router" - responses: - default: - description: The result will be a Multisig object in Json or 404 status code with error description. - - /api/v1/program_admins: - get: - description: "Returns program upgrade signers" - parameters: - - name: program_id - in: query - schema: - type: string - responses: - default: - description: The result will be a Multisig object in Json or 404 status code with error description. - - /api/v1/git_token: - get: - description: "Returns Token metadata from Github" - parameters: - - name: name - in: query - schema: - type: string - responses: - default: - description: The result will be a GitToken object in Json or 404 status code with error description. - - /api/v1/git_tokens: - get: - description: "Returns all Tokens from Github" - responses: - default: - description: The result will be a GitTokens object in Json or 404 status code with error description. - - /api/v1/fund: - get: - description: "Returns the Fund struct for the given name" - parameters: - - name: name - in: query - schema: - type: string - responses: - default: - description: The result will be a Fund object in Json or 404 status code with error description. - - /api/v1/funds: - get: - description: "Returns all Funds available" - responses: - default: - description: The result will be a FundMap object in Json or 404 status code with error description. - - /api/v1/fund_ref: - get: - description: "Returns the Fund metadata address for the given name" - parameters: - - name: name - in: query - schema: - type: string - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/fund_refs: - get: - description: "Returns Fund refs: a map of Fund name to account address with metadata" - responses: - default: - description: The result will be a PubkeyMap object in Json or 404 status code with error description. - - /api/v1/fund_by_ref: - get: - description: "Returns the Fund metadata at the specified address" - parameters: - - name: fund_ref - in: query - schema: - type: string - responses: - default: - description: The result will be a Fund object in Json or 404 status code with error description. - - /api/v1/fund_name: - get: - description: "Returns the Fund name for the given metadata address" - parameters: - - name: fund_ref - in: query - schema: - type: string - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/find_funds: - get: - description: "Returns all Funds that have Vaults with the name matching the pattern sorted by version" - parameters: - - name: vault_name_pattern - in: query - schema: - type: string - responses: - default: - description: The result will be an array of Fund objects in Json or 404 status code with error description. - - /api/v1/vault: - get: - description: "Returns the Vault struct for the given name" - parameters: - - name: name - in: query - schema: - type: string - responses: - default: - description: The result will be a Vault object in Json or 404 status code with error description. - - /api/v1/vaults: - get: - description: "Returns all Vaults available" - responses: - default: - description: The result will be a VaultMap object in Json or 404 status code with error description. - - /api/v1/vault_ref: - get: - description: "Returns the Vault metadata address for the given name" - parameters: - - name: name - in: query - schema: - type: string - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/vault_refs: - get: - description: "Returns Vault refs: a map of Vault name to account address with metadata" - responses: - default: - description: The result will be a PubkeyMap object in Json or 404 status code with error description. - - /api/v1/vault_by_ref: - get: - description: "Returns the Vault metadata at the specified address" - parameters: - - name: vault_ref - in: query - schema: - type: string - responses: - default: - description: The result will be a Vault object in Json or 404 status code with error description. - - /api/v1/vault_name: - get: - description: "Returns the Vault name for the given metadata address" - parameters: - - name: vault_ref - in: query - schema: - type: string - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/find_vaults: - get: - description: "Returns all Vaults with tokens A and B sorted by version" - parameters: - - name: token_a - in: query - schema: - type: string - - name: token_b - in: query - schema: - type: string - responses: - default: - description: The result will be an array of Vault objects in Json or 404 status code with error description. - - /api/v1/find_vaults_with_vt: - get: - description: "Returns all Vaults with tokens A and B sorted by version" - parameters: - - name: vt_token_name - in: query - schema: - type: string - responses: - default: - description: The result will be an array of Vault objects in Json or 404 status code with error description. - - /api/v1/pool: - get: - description: "Returns the Pool struct for the given name" - parameters: - - name: name - in: query - schema: - type: string - responses: - default: - description: The result will be a Pool object in Json or 404 status code with error description. - - /api/v1/pools: - get: - description: "Returns all Pools available" - responses: - default: - description: The result will be a PoolMap object in Json or 404 status code with error description. - - /api/v1/pool_ref: - get: - description: "Returns the Pool metadata address for the given name" - parameters: - - name: name - in: query - schema: - type: string - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/pool_refs: - get: - description: "Returns Pool refs: a map of Pool name to account address with metadata" - responses: - default: - description: The result will be a PubkeyMap object in Json or 404 status code with error description. - - /api/v1/pool_by_ref: - get: - description: "Returns the Pool metadata at the specified address" - parameters: - - name: pool_ref - in: query - schema: - type: string - responses: - default: - description: The result will be a Pool object in Json or 404 status code with error description. - - /api/v1/pool_name: - get: - description: "Returns the Pool name for the given metadata address" - parameters: - - name: pool_ref - in: query - schema: - type: string - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/find_pools: - get: - description: "Returns all Pools with tokens A and B sorted by version for the given protocol" - parameters: - - name: protocol - in: query - schema: - type: string - - name: token_a - in: query - schema: - type: string - - name: token_b - in: query - schema: - type: string - responses: - default: - description: The result will be an array of Pool objects in Json or 404 status code with error description. - - /api/v1/find_pools_with_lp: - get: - description: "Returns all Pools sorted by version for the given LP token" - parameters: - - name: lp_token - in: query - schema: - type: string - responses: - default: - description: The result will be an array of Pool objects in Json or 404 status code with error description. - - /api/v1/pool_price: - get: - description: "Returns pair's price based on the ratio of tokens in the pool" - parameters: - - name: name - in: query - schema: - type: string - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/oracle: - get: - description: "Returns oracle address for the given token" - parameters: - - name: symbol - in: query - schema: - type: string - responses: - default: - description: The result will be a Pubkey object in Json or 404 status code with error description. - - /api/v1/oracle_price: - get: - description: "Returns the price in USD for the given token" - parameters: - - name: symbol - in: query - schema: - type: string - - name: max_price_age_sec - in: query - schema: - type: integer - - name: max_price_error - in: query - schema: - type: number - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/farm: - get: - description: "Returns the Farm struct for the given name" - parameters: - - name: name - in: query - schema: - type: string - responses: - default: - description: The result will be a Farm object in Json or 404 status code with error description. - - /api/v1/farms: - get: - description: "Returns all Farms available" - responses: - default: - description: The result will be a FarmMap object in Json or 404 status code with error description. - - /api/v1/farm_ref: - get: - description: "Returns the Farm metadata address for the given name" - parameters: - - name: name - in: query - schema: - type: string - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/farm_refs: - get: - description: "Returns Farm refs: a map of Farm name to account address with metadata" - responses: - default: - description: The result will be a PubkeyMap object in Json or 404 status code with error description. - - /api/v1/farm_by_ref: - get: - description: "Returns the Farm metadata at the specified address" - parameters: - - name: farm_ref - in: query - schema: - type: string - responses: - default: - description: The result will be a Farm object in Json or 404 status code with error description. - - /api/v1/farm_name: - get: - description: "Returns the Farm name for the given metadata address" - parameters: - - name: farm_ref - in: query - schema: - type: string - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/find_farms_with_lp: - get: - description: "Returns all Farms for the given LP token" - parameters: - - name: lp_token - in: query - schema: - type: string - responses: - default: - description: The result will be an array of Farm objects in Json or 404 status code with error description. - - /api/v1/token: - get: - description: "Returns the Token struct for the given name" - parameters: - - name: name - in: query - schema: - type: string - responses: - default: - description: The result will be a Token object in Json or 404 status code with error description. - - /api/v1/tokens: - get: - description: "Returns all Tokens available" - responses: - default: - description: The result will be a TokenMap object in Json or 404 status code with error description. - - /api/v1/token_ref: - get: - description: "Returns the Token metadata address for the given name" - parameters: - - name: name - in: query - schema: - type: string - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/token_refs: - get: - description: "Returns Token refs: a map of Token name to account address with metadata" - responses: - default: - description: The result will be a PubkeyMap object in Json or 404 status code with error description. - - /api/v1/token_by_ref: - get: - description: "Returns the Token metadata at the specified address" - parameters: - - name: token_ref - in: query - schema: - type: string - responses: - default: - description: The result will be a Token object in Json or 404 status code with error description. - - /api/v1/token_name: - get: - description: "Returns the Token name for the given metadata address" - parameters: - - name: token_ref - in: query - schema: - type: string - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/token_with_mint: - get: - description: "Returns the Token metadata for the specified mint" - parameters: - - name: token_mint - in: query - schema: - type: string - responses: - default: - description: The result will be a Token object in Json or 404 status code with error description. - - /api/v1/token_with_account: - get: - description: "Returns the Token metadata for the specified token account" - parameters: - - name: token_account - in: query - schema: - type: string - responses: - default: - description: The result will be a Token object in Json or 404 status code with error description. - - /api/v1/program_id: - get: - description: "Returns the official Program ID for the given name" - parameters: - - name: name - in: query - schema: - type: string - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/program_ids: - get: - description: "Returns all official Program IDs available" - responses: - default: - description: The result will be a PubkeyMap object in Json or 404 status code with error description. - - /api/v1/program_name: - get: - description: "Returns the official program name for the given Program ID" - parameters: - - name: prog_id - in: query - schema: - type: string - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/is_official_id: - get: - description: "Checks if the given address is the official Program ID" - parameters: - - name: prog_id - in: query - schema: - type: string - responses: - default: - description: The result will be a bool object in Json or 404 status code with error description. - - /api/v1/is_fund_manager: - get: - description: "Checks if the given address is the Fund manager" - parameters: - - name: wallet_address - in: query - schema: - type: string - responses: - default: - description: The result will be a bool object in Json or 404 status code with error description. - - /api/v1/managed_funds: - get: - description: "Returns all Funds managed by the given address" - parameters: - - name: wallet_address - in: query - schema: - type: string - responses: - default: - description: The result will be an array of Fund objects in Json or 404 status code with error description. - - /api/v1/token_supply: - get: - description: "Returns token supply as UI amount" - parameters: - - name: token_name - in: query - schema: - type: string - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/associated_token_address: - get: - description: "Returns the associated token account address for the given token name" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/wallet_tokens: - get: - description: "Returns all tokens with active account in the wallet" - parameters: - - name: wallet_address - in: query - schema: - type: string - responses: - default: - description: The result will be an array of String objects in Json or 404 status code with error description. - - /api/v1/token_account_data: - get: - description: "Returns UiTokenAccount struct data for the associated token account address" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - responses: - default: - description: The result will be a UiTokenAccount object in Json or 404 status code with error description. - - /api/v1/account_balance: - get: - description: "Returns native SOL balance" - parameters: - - name: wallet_address - in: query - schema: - type: string - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/token_account_balance: - get: - description: "Returns token balance for the associated token account address" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/token_account_balance_with_address: - get: - description: "Returns token balance for the specified token account address" - parameters: - - name: token_account - in: query - schema: - type: string - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/has_active_token_account: - get: - description: "Returns true if the associated token account exists and is initialized" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - responses: - default: - description: The result will be a bool object in Json or 404 status code with error description. - - /api/v1/fund_admins: - get: - description: "Returns current admin signers for the Fund" - parameters: - - name: name - in: query - schema: - type: string - responses: - default: - description: The result will be a Multisig object in Json or 404 status code with error description. - - /api/v1/fund_user_info: - get: - description: "Returns user stats for specific Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - responses: - default: - description: The result will be a FundUserInfo object in Json or 404 status code with error description. - - /api/v1/all_fund_user_infos: - get: - description: "Returns user stats for all Funds" - parameters: - - name: wallet_address - in: query - schema: - type: string - responses: - default: - description: The result will be an array of FundUserInfo objects in Json or 404 status code with error description. - - /api/v1/fund_user_requests: - get: - description: "Returns user requests for specific Fund and token" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - responses: - default: - description: The result will be a FundUserRequests object in Json or 404 status code with error description. - - /api/v1/all_fund_user_requests: - get: - description: "Returns user requests for all tokens accepted by the Fund" - parameters: - - name: fund_name - in: query - schema: - type: string - responses: - default: - description: The result will be an array of FundUserRequests objects in Json or 404 status code with error description. - - /api/v1/fund_info: - get: - description: "Returns Fund stats and config" - parameters: - - name: fund_name - in: query - schema: - type: string - responses: - default: - description: The result will be a FundInfo object in Json or 404 status code with error description. - - /api/v1/all_fund_infos: - get: - description: "Returns Fund info and config for all Funds" - responses: - default: - description: The result will be an array of FundInfo objects in Json or 404 status code with error description. - - /api/v1/fund_assets: - get: - description: "Returns the Fund assets info" - parameters: - - name: fund_name - in: query - schema: - type: string - - name: asset_type - in: query - schema: - type: string - responses: - default: - description: The result will be a FundAssets object in Json or 404 status code with error description. - - /api/v1/fund_custody: - get: - description: "Returns the Fund custody info" - parameters: - - name: fund_name - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - - name: custody_type - in: query - schema: - type: string - responses: - default: - description: The result will be a FundCustody object in Json or 404 status code with error description. - - /api/v1/fund_custody_with_balance: - get: - description: "Returns the Fund custody extended info" - parameters: - - name: fund_name - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - - name: custody_type - in: query - schema: - type: string - responses: - default: - description: The result will be a FundCustodyWithBalance object in Json or 404 status code with error description. - - /api/v1/fund_custodies: - get: - description: "Returns all custodies belonging to the Fund sorted by custody_id" - parameters: - - name: fund_name - in: query - schema: - type: string - responses: - default: - description: The result will be an array of FundCustody objects in Json or 404 status code with error description. - - /api/v1/fund_custodies_with_balance: - get: - description: "Returns all custodies belonging to the Fund with extended info" - parameters: - - name: fund_name - in: query - schema: - type: string - responses: - default: - description: The result will be an array of FundCustodyWithBalance objects in Json or 404 status code with error description. - - /api/v1/fund_vault: - get: - description: "Returns the Fund Vault info" - parameters: - - name: fund_name - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: vault_type - in: query - schema: - type: string - responses: - default: - description: The result will be a FundVault object in Json or 404 status code with error description. - - /api/v1/fund_vaults: - get: - description: "Returns all Vaults belonging to the Fund sorted by vault_id" - parameters: - - name: fund_name - in: query - schema: - type: string - responses: - default: - description: The result will be an array of FundVault objects in Json or 404 status code with error description. - - /api/v1/fund_stats: - get: - description: "Returns Fund's historical performance" - parameters: - - name: fund_name - in: query - schema: - type: string - - name: timeframe - in: query - schema: - type: string - - name: start_time - in: query - schema: - type: integer - - name: limit - in: query - schema: - type: integer - responses: - default: - description: The result will be an array of FundStatsRecord objects in Json or 404 status code with error description. - - /api/v1/user_stake_balance: - get: - description: "Returns User's stacked balance" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: farm_name - in: query - schema: - type: string - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/vault_stake_balance: - get: - description: "Returns Vault's stacked balance" - parameters: - - name: vault_name - in: query - schema: - type: string - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/vault_admins: - get: - description: "Returns current admin signers for the Vault" - parameters: - - name: name - in: query - schema: - type: string - responses: - default: - description: The result will be a Multisig object in Json or 404 status code with error description. - - /api/v1/vault_user_info: - get: - description: "Returns user stats for specific Vault" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - responses: - default: - description: The result will be a VaultUserInfo object in Json or 404 status code with error description. - - /api/v1/vault_info: - get: - description: "Returns Vault stats" - parameters: - - name: vault_name - in: query - schema: - type: string - responses: - default: - description: The result will be a VaultInfo object in Json or 404 status code with error description. - - /api/v1/all_vault_infos: - get: - description: "Returns Vault stats for all Vaults" - responses: - default: - description: The result will be an array of VaultInfo objects in Json or 404 status code with error description. - - /api/v1/vault_token_decimals: - get: - description: "Returns number of decimal digits of the Vault token" - parameters: - - name: vault_name - in: query - schema: - type: string - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/pool_tokens_decimals: - get: - description: "Returns number of decimal digits of the Vault token" - parameters: - - name: pool_name - in: query - schema: - type: string - responses: - default: - description: The result will be an array of u8 objects in Json or 404 status code with error description. - - /api/v1/new_instruction_create_system_account: - get: - description: "Returns a new Instruction for creating system account" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: new_address - in: query - schema: - type: string - - name: lamports - in: query - schema: - type: integer - - name: space - in: query - schema: - type: integer - - name: owner - in: query - schema: - type: string - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_create_system_account_with_seed: - get: - description: "Returns a new Instruction for creating system account with seed" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: base_address - in: query - schema: - type: string - - name: seed - in: query - schema: - type: string - - name: lamports - in: query - schema: - type: integer - - name: space - in: query - schema: - type: integer - - name: owner - in: query - schema: - type: string - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_close_system_account: - get: - description: "Returns a new Instruction for closing system account" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: target_address - in: query - schema: - type: string - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_transfer: - get: - description: "Returns the native SOL transfer instruction" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: destination_wallet - in: query - schema: - type: string - - name: sol_ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_token_transfer: - get: - description: "Returns a tokens transfer instruction" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - - name: destination_wallet - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_sync_token_balance: - get: - description: "Returns a new Instruction for syncing token balance for the specified account" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_create_token_account: - get: - description: "Returns a new Instruction for creating associated token account" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_close_token_account: - get: - description: "Returns a new Instruction for closing associated token account" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_user_init_vault: - get: - description: "Returns a new Instruction for initializing a new User for the Vault" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_add_liquidity_vault: - get: - description: "Returns a new Instruction for adding liquidity to the Vault" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: max_token_a_ui_amount - in: query - schema: - type: number - - name: max_token_b_ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_lock_liquidity_vault: - get: - description: "Returns a new Instruction for locking liquidity in the Vault" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_unlock_liquidity_vault: - get: - description: "Returns a new Instruction for unlocking liquidity from the Vault" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_remove_liquidity_vault: - get: - description: "Returns a new Instruction for removing liquidity from the Vault" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_add_liquidity_pool: - get: - description: "Returns a new Instruction for adding liquidity to the Pool" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: pool_name - in: query - schema: - type: string - - name: max_token_a_ui_amount - in: query - schema: - type: number - - name: max_token_b_ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_remove_liquidity_pool: - get: - description: "Returns a new Instruction for removing liquidity from the Pool" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: pool_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_wrap_token: - get: - description: "Returns a new Instruction for wrapping the token into protocol specific token" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: pool_name - in: query - schema: - type: string - - name: token_to_wrap - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_unwrap_token: - get: - description: "Returns a new Instruction for unwrapping the token from protocol specific token" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: pool_name - in: query - schema: - type: string - - name: token_to_unwrap - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_swap: - get: - description: "Returns a new Instruction for tokens swap" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: protocol - in: query - schema: - type: string - - name: from_token - in: query - schema: - type: string - - name: to_token - in: query - schema: - type: string - - name: ui_amount_in - in: query - schema: - type: number - - name: min_ui_amount_out - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_user_init: - get: - description: "Returns a new Instruction for initializing a new User in the Farm" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: farm_name - in: query - schema: - type: string - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_stake: - get: - description: "Returns a new Instruction for tokens staking" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: farm_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_unstake: - get: - description: "Returns a new Instruction for tokens unstaking" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: farm_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_harvest: - get: - description: "Returns a new Instruction for rewards harvesting" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: farm_name - in: query - schema: - type: string - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_crank_vault: - get: - description: "Returns a new Vault Crank Instruction" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: step - in: query - schema: - type: integer - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_user_init_fund: - get: - description: "Returns a new Instruction for initializing a new User for the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_request_deposit_fund: - get: - description: "Returns a new Instruction for requesting deposit to the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_cancel_deposit_fund: - get: - description: "Returns a new Instruction for canceling pending deposit to the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_request_withdrawal_fund: - get: - description: "Returns a new Instruction for requesting withdrawal from the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_cancel_withdrawal_fund: - get: - description: "Returns a new Instruction for canceling pending withdrawal from the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_start_liquidation_fund: - get: - description: "Returns a new Instruction for initiating liquidation of the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_disable_deposits_fund: - get: - description: "Returns a new Instruction for disabling deposits to the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_approve_deposit_fund: - get: - description: "Returns a new Instruction for approving deposit to the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: user_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_deny_deposit_fund: - get: - description: "Returns a new Instruction for denying deposit to the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: user_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - - name: deny_reason - in: query - schema: - type: string - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_disable_withdrawals_fund: - get: - description: "Returns a new Instruction for disabling withdrawals from the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_approve_withdrawal_fund: - get: - description: "Returns a new Instruction for approving withdrawal from the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: user_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_deny_withdrawal_fund: - get: - description: "Returns a new Instruction for denying withdrawal from the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: user_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - - name: deny_reason - in: query - schema: - type: string - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_lock_assets_fund: - get: - description: "Returns a new Instruction for moving deposited assets to the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_unlock_assets_fund: - get: - description: "Returns a new Instruction for releasing assets from the Fund to Deposit/Withdraw custody" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_update_fund_assets_with_custody: - get: - description: "Returns a new Instruction for updating Fund assets based on custody holdings" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: custody_id - in: query - schema: - type: integer - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_update_fund_assets_with_vault: - get: - description: "Returns a new Instruction for updating Fund assets with Vault holdings" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: vault_id - in: query - schema: - type: integer - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_fund_add_liquidity_pool: - get: - description: "Returns a new Instruction for adding liquidity to the Pool in the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: pool_name - in: query - schema: - type: string - - name: max_token_a_ui_amount - in: query - schema: - type: number - - name: max_token_b_ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_fund_remove_liquidity_pool: - get: - description: "Returns a new Instruction for removing liquidity from the Pool in the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: pool_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_fund_user_init_farm: - get: - description: "Returns a new Instruction for initializing a new User for the Farm in the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: farm_name - in: query - schema: - type: string - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_fund_stake: - get: - description: "Returns a new Instruction for tokens staking to the Farm in the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: farm_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_fund_unstake: - get: - description: "Returns a new Instruction for tokens unstaking from the Farm in the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: farm_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_fund_harvest: - get: - description: "Returns a new Instruction for rewards harvesting from the Farm in the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: farm_name - in: query - schema: - type: string - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_fund_user_init_vault: - get: - description: "Returns a new Instruction for initializing a new User for the Vault in the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_fund_add_liquidity_vault: - get: - description: "Returns a new Instruction for adding liquidity to the Vault in the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: max_token_a_ui_amount - in: query - schema: - type: number - - name: max_token_b_ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_fund_lock_liquidity_vault: - get: - description: "Returns a new Instruction for locking liquidity in the Vault in the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_fund_unlock_liquidity_vault: - get: - description: "Returns a new Instruction for unlocking liquidity from the Vault in the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/new_instruction_fund_remove_liquidity_vault: - get: - description: "Returns a new Instruction for removing liquidity from the Vault in the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an Instruction object in Json or 404 status code with error description. - - /api/v1/all_instructions_token_transfer: - get: - description: "Returns a new complete set of instructions for tokens transfer" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - - name: destination_wallet - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/all_instructions_wrap_sol: - get: - description: "Returns a new complete set of instructions for SOL wrapping" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/all_instructions_unwrap_sol: - get: - description: "Returns a new complete set of instructions for SOL unwrapping" - parameters: - - name: wallet_address - in: query - schema: - type: string - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/all_instructions_add_liquidity_vault: - get: - description: "Returns a new complete set of instructions for adding liquidity to the Vault" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: max_token_a_ui_amount - in: query - schema: - type: number - - name: max_token_b_ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/all_instructions_add_locked_liquidity_vault: - get: - description: "Returns a new complete set of instructions for adding locked liquidity to the Vault" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/all_instructions_remove_liquidity_vault: - get: - description: "Returns a new complete set of Instructions for removing liquidity from the Vault" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/all_instructions_remove_unlocked_liquidity_vault: - get: - description: "Returns a new complete set of Instructions for removing unlocked liquidity from the Vault" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/all_instructions_add_liquidity_pool: - get: - description: "Returns a new complete set of Instructions for adding liquidity to the Pool" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: pool_name - in: query - schema: - type: string - - name: max_token_a_ui_amount - in: query - schema: - type: number - - name: max_token_b_ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/all_instructions_remove_liquidity_pool: - get: - description: "Returns a new complete set of Instructions for removing liquidity from the Pool" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: pool_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/all_instructions_swap: - get: - description: "Returns a new complete set of Instructions for swapping tokens" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: protocol - in: query - schema: - type: string - - name: from_token - in: query - schema: - type: string - - name: to_token - in: query - schema: - type: string - - name: ui_amount_in - in: query - schema: - type: number - - name: min_ui_amount_out - in: query - schema: - type: number - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/all_instructions_stake: - get: - description: "Returns a new complete set of Instructions for staking tokens to the Farm" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: farm_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/all_instructions_unstake: - get: - description: "Returns a new complete set of Instructions for unstaking tokens from the Farm" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: farm_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/all_instructions_harvest: - get: - description: "Returns a new complete set of Instructions for harvesting rewards from the Farm" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: farm_name - in: query - schema: - type: string - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/all_instructions_request_deposit_fund: - get: - description: "Returns a new complete set of Instructions for requesting a new deposit to the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/all_instructions_request_withdrawal_fund: - get: - description: "Returns a new complete set of Instructions for requesting a new withdrawal from the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/all_instructions_fund_add_liquidity_pool: - get: - description: "Returns a new complete set of Instructions for adding liquidity to the Pool in the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: pool_name - in: query - schema: - type: string - - name: max_token_a_ui_amount - in: query - schema: - type: number - - name: max_token_b_ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/all_instructions_fund_remove_liquidity_pool: - get: - description: "Returns a new complete set of Instructions for removing liquidity from the Pool in the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: pool_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/all_instructions_fund_stake: - get: - description: "Returns a new complete set of Instructions for staking tokens to the Farm in the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: farm_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/all_instructions_fund_unstake: - get: - description: "Returns a new complete set of Instructions for unstaking tokens from the Farm in the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: farm_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/all_instructions_fund_harvest: - get: - description: "Returns a new complete set of Instructions for harvesting rewards from the Farm in the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: farm_name - in: query - schema: - type: string - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/all_instructions_fund_add_liquidity_vault: - get: - description: "Returns a new complete set of instructions for adding liquidity to the Vault in the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: max_token_a_ui_amount - in: query - schema: - type: number - - name: max_token_b_ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/all_instructions_fund_add_locked_liquidity_vault: - get: - description: "Returns a new complete set of instructions for adding locked liquidity to the Vault in the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/all_instructions_fund_remove_liquidity_vault: - get: - description: "Returns a new complete set of Instructions for removing liquidity from the Vault in the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/all_instructions_fund_remove_unlocked_liquidity_vault: - get: - description: "Returns a new complete set of Instructions for removing unlocked liquidity from the Vault in the Fund" - parameters: - - name: wallet_address - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be an array of Instruction objects in Json or 404 status code with error description. - - /api/v1/create_system_account: - post: - description: "Creates a new system account" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: new_account_keypair - in: query - schema: - type: string - - name: lamports - in: query - schema: - type: integer - - name: space - in: query - schema: - type: integer - - name: owner - in: query - schema: - type: string - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/create_system_account_with_seed: - post: - description: "Creates a new system account with seed" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: base_address - in: query - schema: - type: string - - name: seed - in: query - schema: - type: string - - name: lamports - in: query - schema: - type: integer - - name: space - in: query - schema: - type: integer - - name: owner - in: query - schema: - type: string - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/assign_system_account: - post: - description: "Assigns system account to a program" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: program_address - in: query - schema: - type: string - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/close_system_account: - post: - description: "Closes existing system account" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: target_account_keypair - in: query - schema: - type: string - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/transfer: - post: - description: "Transfers native SOL from the wallet to the destination" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: destination_wallet - in: query - schema: - type: string - - name: sol_ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/token_transfer: - post: - description: "Transfers tokens from the wallet to the destination" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - - name: destination_wallet - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/wrap_sol: - post: - description: "Transfers native SOL from the wallet to the associated Wrapped SOL account" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/unwrap_sol: - post: - description: "Transfers Wrapped SOL back to SOL by closing the associated Wrapped SOL account" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/sync_token_balance: - post: - description: "Updates token balance of the account, usefull after transfer SOL to WSOL account" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/create_token_account: - post: - description: "Returns the associated token account for the given user's main account or creates one" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/close_token_account: - post: - description: "Closes existing token account associated with the given user's main account" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/user_init_vault: - post: - description: "Initializes a new User for the Vault" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/add_liquidity_vault: - post: - description: "Adds liquidity to the Vault" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: max_token_a_ui_amount - in: query - schema: - type: number - - name: max_token_b_ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/add_locked_liquidity_vault: - post: - description: "Adds locked liquidity to the Vault" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/remove_liquidity_vault: - post: - description: "Removes liquidity from the Vault" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/remove_unlocked_liquidity_vault: - post: - description: "Removes unlocked liquidity from the Vault" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/add_liquidity_pool: - post: - description: "Adds liquidity to the Pool" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: pool_name - in: query - schema: - type: string - - name: max_token_a_ui_amount - in: query - schema: - type: number - - name: max_token_b_ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/remove_liquidity_pool: - post: - description: "Removes liquidity from the Pool" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: pool_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/swap: - post: - description: "Swaps tokens" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: protocol - in: query - schema: - type: string - - name: from_token - in: query - schema: - type: string - - name: to_token - in: query - schema: - type: string - - name: ui_amount_in - in: query - schema: - type: number - - name: min_ui_amount_out - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/user_init: - post: - description: "Initializes a new User for the Farm" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: farm_name - in: query - schema: - type: string - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/stake: - post: - description: "Stakes tokens to the Farm" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: farm_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/unstake: - post: - description: "Unstakes tokens from the Farm" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: farm_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/harvest: - post: - description: "Harvests rewards from the Farm" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: farm_name - in: query - schema: - type: string - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/crank_vault: - post: - description: "Cranks single Vault" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: step - in: query - schema: - type: integer - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/crank_vaults: - post: - description: "Cranks all Vaults" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: step - in: query - schema: - type: integer - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/reset_cache: - post: - description: "Clears cache records to force re-pull from blockchain" - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/user_init_fund: - post: - description: "Initializes a new User for the Fund" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/request_deposit_fund: - post: - description: "Requests a new deposit to the Fund" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/cancel_deposit_fund: - post: - description: "Cancels pending deposit to the Fund" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/request_withdrawal_fund: - post: - description: "Requests a new withdrawal from the Fund" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/cancel_withdrawal_fund: - post: - description: "Cancels pending deposit to the Fund" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/start_liquidation_fund: - post: - description: "Starts the Fund liquidation" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/disable_deposits_fund: - post: - description: "Disables deposits to the Fund" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/approve_deposit_fund: - post: - description: "Approves pending deposit to the Fund" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: user_address - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/deny_deposit_fund: - post: - description: "Denies pending deposit to the Fund" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: user_address - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - - name: deny_reason - in: query - schema: - type: string - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/disable_withdrawals_fund: - post: - description: "Disables withdrawals from the Fund" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/approve_withdrawal_fund: - post: - description: "Approves pending withdrawal from the Fund" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: user_address - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/deny_withdrawal_fund: - post: - description: "Denies pending withdrawal from the Fund" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: user_address - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - - name: deny_reason - in: query - schema: - type: string - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/lock_assets_fund: - post: - description: "Moves deposited assets from Deposit/Withdraw custody to the Fund" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/unlock_assets_fund: - post: - description: "Releases assets from the Fund to Deposit/Withdraw custody" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: token_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/update_fund_assets_with_custody: - post: - description: "Update Fund assets info based on custody holdings" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: custody_id - in: query - schema: - type: integer - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/update_fund_assets_with_custodies: - post: - description: "Update Fund assets info based on all custodies" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/update_fund_assets_with_vault: - post: - description: "Update Fund assets info based on Vault holdings" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: vault_id - in: query - schema: - type: integer - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/update_fund_assets_with_vaults: - post: - description: "Update Fund assets info based on Vault holdings" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - responses: - default: - description: The result will be a String object or 404 status code with error description. - - /api/v1/fund_add_liquidity_pool: - post: - description: "Adds liquidity to the Pool in the Fund" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: pool_name - in: query - schema: - type: string - - name: max_token_a_ui_amount - in: query - schema: - type: number - - name: max_token_b_ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/fund_remove_liquidity_pool: - post: - description: "Removes liquidity from the Pool in the Fund" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: pool_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/fund_user_init_farm: - post: - description: "Initializes a new User for the Farm in the Fund" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: farm_name - in: query - schema: - type: string - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/fund_stake: - post: - description: "Stakes tokens to the Farm in the Fund" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: farm_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/fund_unstake: - post: - description: "Unstakes tokens from the Farm in the Fund" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: farm_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/fund_harvest: - post: - description: "Harvests rewards from the Farm in the Fund" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: farm_name - in: query - schema: - type: string - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/fund_user_init_vault: - post: - description: "Initializes a new User for the Vault in the Fund" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/fund_add_liquidity_vault: - post: - description: "Adds liquidity to the Vault in the Fund" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: max_token_a_ui_amount - in: query - schema: - type: number - - name: max_token_b_ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/fund_add_locked_liquidity_vault: - post: - description: "Adds locked liquidity to the Vault in the Fund" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/fund_remove_liquidity_vault: - post: - description: "Removes liquidity from the Vault in the Fund" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. - - /api/v1/fund_remove_unlocked_liquidity_vault: - post: - description: "Removes unlocked liquidity from the Vault in the Fund" - parameters: - - name: wallet_keypair - in: query - schema: - type: string - - name: fund_name - in: query - schema: - type: string - - name: vault_name - in: query - schema: - type: string - - name: ui_amount - in: query - schema: - type: number - responses: - default: - description: The result will be a Signature object or 404 status code with error description. diff --git a/farms/farm-sdk/.gitignore b/farms/farm-sdk/.gitignore deleted file mode 100644 index 96ef6c0b944..00000000000 --- a/farms/farm-sdk/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -Cargo.lock diff --git a/farms/farm-sdk/Cargo.toml b/farms/farm-sdk/Cargo.toml deleted file mode 100644 index 93b62b1d11e..00000000000 --- a/farms/farm-sdk/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -[package] -name = "solana-farm-sdk" -version = "1.1.3" -description = "Solana Farm SDK" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana-program-library/farms" -license = "Apache-2.0" -homepage = "https://solana.com/" -edition = "2021" - -[features] -debug = [] - -[dependencies] -solana-program = "1.9.18" -arrayref = "0.3.6" -arraystring = "0.3.0" -serde = "1.0.136" -serde_derive = "1.0.136" -serde_json = "1.0.79" -thiserror = "1.0.30" -num_enum = "0.5.7" -num-traits = "0.2.14" -spl-token-swap = { version = "2.1.0", features = ["no-entrypoint"] } -spl-token = { version = "3.2.0", features = ["no-entrypoint"] } -spl-associated-token-account = { version = "=1.0.3", features = ["no-entrypoint"] } -quarry-mine = { version = "5.0.2", features = ["no-entrypoint"] } -quarry-mint-wrapper = { version = "5.0.2", features = ["no-entrypoint"] } -quarry-redeemer = { version = "5.0.2", features = ["no-entrypoint"] } -pyth-client = { version = "=0.5.0", features = ["no-entrypoint"] } -stable-swap-client = "1.8.1" -uint = "0.9.1" -lazy_static = "1.4.0" -ahash = "0.7.6" - -[build-dependencies] -solana-program = "1.9.18" - -[dev-dependencies] -solana-program-test = "1.9.18" - diff --git a/farms/farm-sdk/README.md b/farms/farm-sdk/README.md deleted file mode 120000 index ccd27901fd5..00000000000 --- a/farms/farm-sdk/README.md +++ /dev/null @@ -1 +0,0 @@ -../docs/crate.md \ No newline at end of file diff --git a/farms/farm-sdk/build.rs b/farms/farm-sdk/build.rs deleted file mode 100644 index 9aec28bcf1c..00000000000 --- a/farms/farm-sdk/build.rs +++ /dev/null @@ -1,118 +0,0 @@ -//! Creates a file that will set constants captured from the environment. -//! These constants represent official accounts, program ids, and names. -//! Normally lazy_static! would work, but it is not supported with build-bpf. - -use { - solana_program::pubkey::Pubkey, - std::{env, fs::File, io::Write, path::Path, str::FromStr}, -}; - -fn main() { - // create output file - let out_dir = env::var("OUT_DIR") - .expect("Please set OUT_DIR environment variable to the build script output path"); - let dest_path = Path::new(&out_dir).join("constants.rs"); - let mut f = File::create(&dest_path).unwrap_or_else(|_| { - panic!( - "Could not create file \"{}\" for the build script output", - dest_path.to_string_lossy() - ) - }); - - // read variables - let main_router_id = - option_env!("MAIN_ROUTER_ID").unwrap_or("RepLaceThisWithVaLidMainRouterProgramPubkey"); - if main_router_id == "RepLaceThisWithVaLidMainRouterProgramPubkey" { - println!("cargo:warning=Please set MAIN_ROUTER_ID environment variable to the router-main program address"); - } - - let main_router_admin = - option_env!("MAIN_ROUTER_ADMIN").unwrap_or("RepLaceThisWithCorrectMainRouterAdminPubkey"); - if main_router_admin == "RepLaceThisWithCorrectMainRouterAdminPubkey" { - println!("cargo:warning=Please set MAIN_ROUTER_ADMIN environment variable to the router-main program admin"); - } - - let main_router_multisig = - Pubkey::find_program_address(&[b"multisig"], &Pubkey::from_str(main_router_id).unwrap()).0; - - // ID that represents the unset Pubkey. This is to avoid passing Pubkey::default() which - // is equal to system_program::id(). - // Default is [14, 196, 109, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - let zero_id = option_env!("ZERO_ID").unwrap_or("zeRosMEYuuABXv5y2LNUbgmPp62yFD5CULW5soHS9HR"); - - let dao_token_name = option_env!("DAO_TOKEN_NAME").unwrap_or("FARM_DAO"); - let dao_program_name = option_env!("DAO_PROGRAM_NAME").unwrap_or("FarmGovernance"); - let dao_mint_name = option_env!("DAO_MINT_NAME").unwrap_or("FarmMintGovernance"); - let dao_custody_name = option_env!("DAO_CUSTODY_NAME").unwrap_or("FarmCustodyGovernance"); - - // write the file - let write_error = format!( - "Could not write to the build script output file: {}", - dest_path.to_string_lossy() - ); - - writeln!( - &mut f, - "pub mod main_router {{solana_program::declare_id!(\"{}\"); }}", - main_router_id - ) - .expect(&write_error); - - writeln!( - &mut f, - "pub mod main_router_admin {{solana_program::declare_id!(\"{}\"); }}", - main_router_admin - ) - .expect(&write_error); - - writeln!( - &mut f, - "pub mod main_router_multisig {{solana_program::declare_id!(\"{}\"); }}", - main_router_multisig - ) - .expect(&write_error); - - writeln!( - &mut f, - "pub mod zero {{solana_program::declare_id!(\"{}\"); }}", - zero_id - ) - .expect(&write_error); - - writeln!( - &mut f, - "pub const DAO_TOKEN_NAME: &str = \"{}\";", - dao_token_name - ) - .expect(&write_error); - - writeln!( - &mut f, - "pub const DAO_PROGRAM_NAME: &str = \"{}\";", - dao_program_name - ) - .expect(&write_error); - - writeln!( - &mut f, - "pub const DAO_MINT_NAME: &str = \"{}\";", - dao_mint_name - ) - .expect(&write_error); - - writeln!( - &mut f, - "pub const DAO_CUSTODY_NAME: &str = \"{}\";", - dao_custody_name - ) - .expect(&write_error); - - // specify when to re-create - println!("cargo:rerun-if-env-changed=MAIN_ROUTER_ID"); - println!("cargo:rerun-if-env-changed=MAIN_ROUTER_ADMIN"); - println!("cargo:rerun-if-env-changed=ZERO_ID"); - println!("cargo:rerun-if-env-changed=DAO_TOKEN_NAME"); - println!("cargo:rerun-if-env-changed=DAO_PROGRAM_NAME"); - println!("cargo:rerun-if-env-changed=DAO_MINT_NAME"); - println!("cargo:rerun-if-env-changed=DAO_CUSTODY_NAME"); -} diff --git a/farms/farm-sdk/src/error.rs b/farms/farm-sdk/src/error.rs deleted file mode 100644 index f0d9b101a48..00000000000 --- a/farms/farm-sdk/src/error.rs +++ /dev/null @@ -1,57 +0,0 @@ -//! Error types -use {solana_program::program_error::ProgramError, thiserror::Error}; - -/// General error -#[derive(Copy, Clone, Debug, Eq, Error, PartialEq)] -pub enum FarmError { - #[error("Checked math operation overflow")] - MathOverflow, - #[error("Invalid argument value")] - InvalidValue, - #[error("Invalid RefDB record")] - InvalidRefdbRecord, - #[error("RefDB is too large to clear")] - RefdbTooLarge, - #[error("RefDB record counter mismatch")] - RefdbRecordCounterMismatch, - #[error("RefDB record name mismatch")] - RefdbRecordNameMismatch, - #[error("RefDB record type mismatch")] - RefdbRecordTypeMismatch, - #[error("RefDB record not found")] - RefdbRecordNotFound, - #[error("Unexpected token balance decrease")] - UnexpectedBalanceDecrease, - #[error("Unexpected token balance increase")] - UnexpectedBalanceIncrease, - #[error("Invoked program overspent")] - ProgramOverspent, - #[error("Invoked program didn't return enough tokens")] - ProgramInsufficientTransfer, - #[error("Liquidity Pool is empty")] - EmptyPool, - #[error("Invalid Oracle account")] - OracleInvalidAccount, - #[error("Invalid Oracle State")] - OracleInvalidState, - #[error("Stale Oracle price")] - OracleStalePrice, - #[error("Invalid Oracle price")] - OracleInvalidPrice, - #[error("Incorrect account address")] - IncorrectAccountAddress, - #[error("Account not authorized")] - AccountNotAuthorized, - #[error("Already signed")] - AlreadySigned, - #[error("Already executed")] - AlreadyExecuted, - #[error("Too early")] - TooEarly, -} - -impl From for ProgramError { - fn from(e: FarmError) -> Self { - ProgramError::Custom(1000u32 + e as u32) - } -} diff --git a/farms/farm-sdk/src/farm.rs b/farms/farm-sdk/src/farm.rs deleted file mode 100644 index 75ac319ed7c..00000000000 --- a/farms/farm-sdk/src/farm.rs +++ /dev/null @@ -1,638 +0,0 @@ -//! Stake Farms - -use { - crate::{pack::*, string::ArrayString64, traits::*}, - arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}, - num_enum::TryFromPrimitive, - serde::{Deserialize, Serialize}, - serde_json::to_string, - solana_program::{program_error::ProgramError, pubkey::Pubkey}, -}; - -#[allow(clippy::large_enum_variant)] -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq)] -pub enum FarmRoute { - Raydium { - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - farm_id: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - farm_authority: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - farm_lp_token_account: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - farm_first_reward_token_account: Pubkey, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - farm_second_reward_token_account: Option, - }, - Saber { - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - quarry: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - rewarder: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - redeemer: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - redeemer_program: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - minter: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - mint_wrapper: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - mint_wrapper_program: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - iou_fees_account: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - sbr_vault: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - mint_proxy_program: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - mint_proxy_authority: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - mint_proxy_state: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - minter_info: Pubkey, - }, - Orca { - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - farm_id: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - farm_authority: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - farm_token_ref: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - base_token_vault: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - reward_token_vault: Pubkey, - }, -} - -#[repr(u8)] -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)] -pub enum FarmRouteType { - Raydium, - Saber, - Orca, -} - -#[repr(u8)] -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)] -pub enum FarmType { - SingleReward, - DualReward, - ProtocolTokenStake, -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq)] -pub struct Farm { - #[serde( - serialize_with = "as64_serialize", - deserialize_with = "as64_deserialize" - )] - pub name: ArrayString64, - pub version: u16, - pub farm_type: FarmType, - pub official: bool, - pub refdb_index: Option, - pub refdb_counter: u16, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - pub lp_token_ref: Option, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - pub first_reward_token_ref: Option, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - pub second_reward_token_ref: Option, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub router_program_id: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub farm_program_id: Pubkey, - pub route: FarmRoute, -} - -impl Named for Farm { - fn name(&self) -> ArrayString64 { - self.name - } -} - -impl Versioned for Farm { - fn version(&self) -> u16 { - self.version - } -} - -impl Farm { - pub const MAX_LEN: usize = 655; - pub const RAYDIUM_FARM_LEN: usize = 400; - pub const SABER_FARM_LEN: usize = 655; - pub const ORCA_FARM_LEN: usize = 399; - - fn pack_raydium(&self, output: &mut [u8]) -> Result { - check_data_len(output, Farm::RAYDIUM_FARM_LEN)?; - - if let FarmRoute::Raydium { - farm_id, - farm_authority, - farm_lp_token_account, - farm_first_reward_token_account, - farm_second_reward_token_account, - } = self.route - { - let output = array_mut_ref![output, 0, Farm::RAYDIUM_FARM_LEN]; - - let ( - farm_route_type_out, - name_out, - version_out, - farm_type_out, - official_out, - refdb_index_out, - refdb_counter_out, - lp_token_ref_out, - first_reward_token_ref_out, - second_reward_token_ref_out, - router_program_id_out, - farm_program_id_out, - farm_id_out, - farm_authority_out, - farm_lp_token_account_out, - farm_first_reward_token_account_out, - farm_second_reward_token_account_out, - ) = mut_array_refs![ - output, 1, 64, 2, 1, 1, 5, 2, 33, 33, 33, 32, 32, 32, 32, 32, 32, 33 - ]; - - farm_route_type_out[0] = FarmRouteType::Raydium as u8; - - pack_array_string64(&self.name, name_out); - *version_out = self.version.to_le_bytes(); - farm_type_out[0] = self.farm_type as u8; - official_out[0] = self.official as u8; - pack_option_u32(self.refdb_index, refdb_index_out); - *refdb_counter_out = self.refdb_counter.to_le_bytes(); - pack_option_key(&self.lp_token_ref, lp_token_ref_out); - pack_option_key(&self.first_reward_token_ref, first_reward_token_ref_out); - pack_option_key(&self.second_reward_token_ref, second_reward_token_ref_out); - router_program_id_out.copy_from_slice(self.router_program_id.as_ref()); - farm_program_id_out.copy_from_slice(self.farm_program_id.as_ref()); - farm_id_out.copy_from_slice(farm_id.as_ref()); - farm_authority_out.copy_from_slice(farm_authority.as_ref()); - farm_lp_token_account_out.copy_from_slice(farm_lp_token_account.as_ref()); - farm_first_reward_token_account_out - .copy_from_slice(farm_first_reward_token_account.as_ref()); - pack_option_key( - &farm_second_reward_token_account, - farm_second_reward_token_account_out, - ); - - Ok(Farm::RAYDIUM_FARM_LEN) - } else { - Err(ProgramError::InvalidAccountData) - } - } - - fn pack_saber(&self, output: &mut [u8]) -> Result { - check_data_len(output, Farm::SABER_FARM_LEN)?; - - if let FarmRoute::Saber { - quarry, - rewarder, - redeemer, - redeemer_program, - minter, - mint_wrapper, - mint_wrapper_program, - iou_fees_account, - sbr_vault, - mint_proxy_program, - mint_proxy_authority, - mint_proxy_state, - minter_info, - } = self.route - { - let output = array_mut_ref![output, 0, Farm::SABER_FARM_LEN]; - - let ( - farm_route_type_out, - name_out, - version_out, - farm_type_out, - official_out, - refdb_index_out, - refdb_counter_out, - lp_token_ref_out, - first_reward_token_ref_out, - second_reward_token_ref_out, - router_program_id_out, - farm_program_id_out, - quarry_out, - rewarder_out, - redeemer_out, - redeemer_program_out, - minter_out, - mint_wrapper_out, - mint_wrapper_program_out, - iou_fees_account_out, - sbr_vault_out, - mint_proxy_program_out, - mint_proxy_authority_out, - mint_proxy_state_out, - minter_info_out, - ) = mut_array_refs![ - output, 1, 64, 2, 1, 1, 5, 2, 33, 33, 33, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32 - ]; - - farm_route_type_out[0] = FarmRouteType::Saber as u8; - - pack_array_string64(&self.name, name_out); - *version_out = self.version.to_le_bytes(); - farm_type_out[0] = self.farm_type as u8; - official_out[0] = self.official as u8; - pack_option_u32(self.refdb_index, refdb_index_out); - *refdb_counter_out = self.refdb_counter.to_le_bytes(); - pack_option_key(&self.lp_token_ref, lp_token_ref_out); - pack_option_key(&self.first_reward_token_ref, first_reward_token_ref_out); - pack_option_key(&self.second_reward_token_ref, second_reward_token_ref_out); - router_program_id_out.copy_from_slice(self.router_program_id.as_ref()); - farm_program_id_out.copy_from_slice(self.farm_program_id.as_ref()); - quarry_out.copy_from_slice(quarry.as_ref()); - rewarder_out.copy_from_slice(rewarder.as_ref()); - redeemer_out.copy_from_slice(redeemer.as_ref()); - redeemer_program_out.copy_from_slice(redeemer_program.as_ref()); - minter_out.copy_from_slice(minter.as_ref()); - mint_wrapper_out.copy_from_slice(mint_wrapper.as_ref()); - mint_wrapper_program_out.copy_from_slice(mint_wrapper_program.as_ref()); - iou_fees_account_out.copy_from_slice(iou_fees_account.as_ref()); - sbr_vault_out.copy_from_slice(sbr_vault.as_ref()); - mint_proxy_program_out.copy_from_slice(mint_proxy_program.as_ref()); - mint_proxy_authority_out.copy_from_slice(mint_proxy_authority.as_ref()); - mint_proxy_state_out.copy_from_slice(mint_proxy_state.as_ref()); - minter_info_out.copy_from_slice(minter_info.as_ref()); - - Ok(Farm::SABER_FARM_LEN) - } else { - Err(ProgramError::InvalidAccountData) - } - } - - fn pack_orca(&self, output: &mut [u8]) -> Result { - check_data_len(output, Farm::ORCA_FARM_LEN)?; - - if let FarmRoute::Orca { - farm_id, - farm_authority, - farm_token_ref, - base_token_vault, - reward_token_vault, - } = self.route - { - let output = array_mut_ref![output, 0, Farm::ORCA_FARM_LEN]; - - let ( - farm_route_type_out, - name_out, - version_out, - farm_type_out, - official_out, - refdb_index_out, - refdb_counter_out, - lp_token_ref_out, - first_reward_token_ref_out, - second_reward_token_ref_out, - router_program_id_out, - farm_program_id_out, - farm_id_out, - farm_authority_out, - farm_token_ref_out, - base_token_vault_out, - reward_token_vault_out, - ) = mut_array_refs![ - output, 1, 64, 2, 1, 1, 5, 2, 33, 33, 33, 32, 32, 32, 32, 32, 32, 32 - ]; - - farm_route_type_out[0] = FarmRouteType::Orca as u8; - - pack_array_string64(&self.name, name_out); - *version_out = self.version.to_le_bytes(); - farm_type_out[0] = self.farm_type as u8; - official_out[0] = self.official as u8; - pack_option_u32(self.refdb_index, refdb_index_out); - *refdb_counter_out = self.refdb_counter.to_le_bytes(); - pack_option_key(&self.lp_token_ref, lp_token_ref_out); - pack_option_key(&self.first_reward_token_ref, first_reward_token_ref_out); - pack_option_key(&self.second_reward_token_ref, second_reward_token_ref_out); - router_program_id_out.copy_from_slice(self.router_program_id.as_ref()); - farm_program_id_out.copy_from_slice(self.farm_program_id.as_ref()); - farm_id_out.copy_from_slice(farm_id.as_ref()); - farm_authority_out.copy_from_slice(farm_authority.as_ref()); - farm_token_ref_out.copy_from_slice(farm_token_ref.as_ref()); - base_token_vault_out.copy_from_slice(base_token_vault.as_ref()); - reward_token_vault_out.copy_from_slice(reward_token_vault.as_ref()); - - Ok(Farm::ORCA_FARM_LEN) - } else { - Err(ProgramError::InvalidAccountData) - } - } - - fn unpack_raydium(input: &[u8]) -> Result { - check_data_len(input, Farm::RAYDIUM_FARM_LEN)?; - - let input = array_ref![input, 1, Farm::RAYDIUM_FARM_LEN - 1]; - #[allow(clippy::ptr_offset_with_cast)] - let ( - name, - version, - farm_type, - official, - refdb_index, - refdb_counter, - lp_token_ref, - first_reward_token_ref, - second_reward_token_ref, - router_program_id, - farm_program_id, - farm_id, - farm_authority, - farm_lp_token_account, - farm_first_reward_token_account, - farm_second_reward_token_account, - ) = array_refs![input, 64, 2, 1, 1, 5, 2, 33, 33, 33, 32, 32, 32, 32, 32, 32, 33]; - - Ok(Self { - name: unpack_array_string64(name)?, - version: u16::from_le_bytes(*version), - farm_type: FarmType::try_from_primitive(farm_type[0]) - .or(Err(ProgramError::InvalidAccountData))?, - official: unpack_bool(official)?, - refdb_index: unpack_option_u32(refdb_index)?, - refdb_counter: u16::from_le_bytes(*refdb_counter), - lp_token_ref: unpack_option_key(lp_token_ref)?, - first_reward_token_ref: unpack_option_key(first_reward_token_ref)?, - second_reward_token_ref: unpack_option_key(second_reward_token_ref)?, - router_program_id: Pubkey::new_from_array(*router_program_id), - farm_program_id: Pubkey::new_from_array(*farm_program_id), - route: FarmRoute::Raydium { - farm_id: Pubkey::new_from_array(*farm_id), - farm_authority: Pubkey::new_from_array(*farm_authority), - farm_lp_token_account: Pubkey::new_from_array(*farm_lp_token_account), - farm_first_reward_token_account: Pubkey::new_from_array( - *farm_first_reward_token_account, - ), - farm_second_reward_token_account: unpack_option_key( - farm_second_reward_token_account, - )?, - }, - }) - } - - fn unpack_saber(input: &[u8]) -> Result { - check_data_len(input, Farm::SABER_FARM_LEN)?; - - let input = array_ref![input, 1, Farm::SABER_FARM_LEN - 1]; - #[allow(clippy::ptr_offset_with_cast)] - let ( - name, - version, - farm_type, - official, - refdb_index, - refdb_counter, - lp_token_ref, - first_reward_token_ref, - second_reward_token_ref, - router_program_id, - farm_program_id, - quarry, - rewarder, - redeemer, - redeemer_program, - minter, - mint_wrapper, - mint_wrapper_program, - iou_fees_account, - sbr_vault, - mint_proxy_program, - mint_proxy_authority, - mint_proxy_state, - minter_info, - ) = array_refs![ - input, 64, 2, 1, 1, 5, 2, 33, 33, 33, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32 - ]; - - Ok(Self { - name: unpack_array_string64(name)?, - version: u16::from_le_bytes(*version), - farm_type: FarmType::try_from_primitive(farm_type[0]) - .or(Err(ProgramError::InvalidAccountData))?, - official: unpack_bool(official)?, - refdb_index: unpack_option_u32(refdb_index)?, - refdb_counter: u16::from_le_bytes(*refdb_counter), - lp_token_ref: unpack_option_key(lp_token_ref)?, - first_reward_token_ref: unpack_option_key(first_reward_token_ref)?, - second_reward_token_ref: unpack_option_key(second_reward_token_ref)?, - router_program_id: Pubkey::new_from_array(*router_program_id), - farm_program_id: Pubkey::new_from_array(*farm_program_id), - route: FarmRoute::Saber { - quarry: Pubkey::new_from_array(*quarry), - rewarder: Pubkey::new_from_array(*rewarder), - redeemer: Pubkey::new_from_array(*redeemer), - redeemer_program: Pubkey::new_from_array(*redeemer_program), - minter: Pubkey::new_from_array(*minter), - mint_wrapper: Pubkey::new_from_array(*mint_wrapper), - mint_wrapper_program: Pubkey::new_from_array(*mint_wrapper_program), - iou_fees_account: Pubkey::new_from_array(*iou_fees_account), - sbr_vault: Pubkey::new_from_array(*sbr_vault), - mint_proxy_program: Pubkey::new_from_array(*mint_proxy_program), - mint_proxy_authority: Pubkey::new_from_array(*mint_proxy_authority), - mint_proxy_state: Pubkey::new_from_array(*mint_proxy_state), - minter_info: Pubkey::new_from_array(*minter_info), - }, - }) - } - - fn unpack_orca(input: &[u8]) -> Result { - check_data_len(input, Farm::ORCA_FARM_LEN)?; - - let input = array_ref![input, 1, Farm::ORCA_FARM_LEN - 1]; - #[allow(clippy::ptr_offset_with_cast)] - let ( - name, - version, - farm_type, - official, - refdb_index, - refdb_counter, - lp_token_ref, - first_reward_token_ref, - second_reward_token_ref, - router_program_id, - farm_program_id, - farm_id, - farm_authority, - farm_token_ref, - base_token_vault, - reward_token_vault, - ) = array_refs![input, 64, 2, 1, 1, 5, 2, 33, 33, 33, 32, 32, 32, 32, 32, 32, 32]; - - Ok(Self { - name: unpack_array_string64(name)?, - version: u16::from_le_bytes(*version), - farm_type: FarmType::try_from_primitive(farm_type[0]) - .or(Err(ProgramError::InvalidAccountData))?, - official: unpack_bool(official)?, - refdb_index: unpack_option_u32(refdb_index)?, - refdb_counter: u16::from_le_bytes(*refdb_counter), - lp_token_ref: unpack_option_key(lp_token_ref)?, - first_reward_token_ref: unpack_option_key(first_reward_token_ref)?, - second_reward_token_ref: unpack_option_key(second_reward_token_ref)?, - router_program_id: Pubkey::new_from_array(*router_program_id), - farm_program_id: Pubkey::new_from_array(*farm_program_id), - route: FarmRoute::Orca { - farm_id: Pubkey::new_from_array(*farm_id), - farm_authority: Pubkey::new_from_array(*farm_authority), - farm_token_ref: Pubkey::new_from_array(*farm_token_ref), - base_token_vault: Pubkey::new_from_array(*base_token_vault), - reward_token_vault: Pubkey::new_from_array(*reward_token_vault), - }, - }) - } -} - -impl Packed for Farm { - fn get_size(&self) -> usize { - match self.route { - FarmRoute::Raydium { .. } => Farm::RAYDIUM_FARM_LEN, - FarmRoute::Saber { .. } => Farm::SABER_FARM_LEN, - FarmRoute::Orca { .. } => Farm::ORCA_FARM_LEN, - } - } - - fn pack(&self, output: &mut [u8]) -> Result { - match self.route { - FarmRoute::Raydium { .. } => self.pack_raydium(output), - FarmRoute::Saber { .. } => self.pack_saber(output), - FarmRoute::Orca { .. } => self.pack_orca(output), - } - } - - fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; Farm::MAX_LEN] = [0; Farm::MAX_LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidAccountData) - } - } - - fn unpack(input: &[u8]) -> Result { - check_data_len(input, 1)?; - let farm_route_type = FarmRouteType::try_from_primitive(input[0]) - .or(Err(ProgramError::InvalidAccountData))?; - match farm_route_type { - FarmRouteType::Raydium => Farm::unpack_raydium(input), - FarmRouteType::Saber => Farm::unpack_saber(input), - FarmRouteType::Orca => Farm::unpack_orca(input), - } - } -} - -impl std::fmt::Display for FarmType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match *self { - FarmType::SingleReward => write!(f, "SingleReward"), - FarmType::DualReward => write!(f, "DualReward"), - FarmType::ProtocolTokenStake => write!(f, "ProtocolTokenStake"), - } - } -} - -impl std::fmt::Display for Farm { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", to_string(&self).unwrap()) - } -} diff --git a/farms/farm-sdk/src/fund.rs b/farms/farm-sdk/src/fund.rs deleted file mode 100644 index 8097946d8f6..00000000000 --- a/farms/farm-sdk/src/fund.rs +++ /dev/null @@ -1,927 +0,0 @@ -//! Solana Fund - -use { - crate::{pack::*, string::ArrayString64, traits::*}, - arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}, - num_enum::TryFromPrimitive, - serde::{Deserialize, Serialize}, - serde_json::to_string, - solana_program::{clock::UnixTimestamp, program_error::ProgramError, pubkey::Pubkey}, -}; - -pub const DISCRIMINATOR_FUND_CUSTODY: u64 = 15979585294446943865; -pub const DISCRIMINATOR_FUND_VAULT: u64 = 10084386823844633785; -pub const DISCRIMINATOR_FUND_USER_REQUESTS: u64 = 13706702285134686038; - -#[repr(u8)] -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)] -pub enum FundType { - General, -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq)] -pub struct Fund { - #[serde( - serialize_with = "as64_serialize", - deserialize_with = "as64_deserialize" - )] - pub name: ArrayString64, - pub version: u16, - pub fund_type: FundType, - pub official: bool, - #[serde(skip_serializing, skip_deserializing)] - pub refdb_index: Option, - #[serde(skip_serializing, skip_deserializing)] - pub refdb_counter: u16, - pub metadata_bump: u8, - pub authority_bump: u8, - pub fund_token_bump: u8, - pub multisig_bump: u8, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub fund_program_id: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub fund_authority: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub fund_manager: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub fund_token_ref: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub info_account: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub multisig_account: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub vaults_assets_info: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub custodies_assets_info: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub description_account: Pubkey, -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Default, Eq, PartialEq)] -pub struct FundUserAction { - pub time: UnixTimestamp, - pub amount: u64, -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Default, Eq, PartialEq)] -pub struct FundUserInfo { - pub virtual_tokens_balance: u64, -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Default, Eq, PartialEq)] -pub struct FundUserRequests { - pub discriminator: u64, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub fund_ref: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub token_ref: Pubkey, - pub deposit_request: FundUserAction, - pub last_deposit: FundUserAction, - pub withdrawal_request: FundUserAction, - pub last_withdrawal: FundUserAction, - #[serde( - serialize_with = "as64_serialize", - deserialize_with = "as64_deserialize" - )] - pub deny_reason: ArrayString64, - pub bump: u8, -} - -#[repr(u8)] -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)] -pub enum FundAssetType { - Vault, - Custody, -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)] -pub struct FundAssets { - pub asset_type: FundAssetType, - pub target_hash: u64, - pub current_hash: u64, - pub current_cycle: u64, - pub current_assets_usd: f64, - pub cycle_start_time: UnixTimestamp, - pub cycle_end_time: UnixTimestamp, - pub bump: u8, -} - -#[repr(u8)] -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)] -pub enum FundCustodyType { - DepositWithdraw, - Trading, -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq)] -pub struct FundCustody { - pub discriminator: u64, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub fund_ref: Pubkey, - pub custody_id: u32, - pub custody_type: FundCustodyType, - pub is_vault_token: bool, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub token_ref: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub address: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub fees_address: Pubkey, - pub bump: u8, -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)] -pub struct FundCustodyWithBalance { - pub discriminator: u64, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub fund_ref: Pubkey, - #[serde( - serialize_with = "as64_serialize", - deserialize_with = "as64_deserialize" - )] - pub fund_name: ArrayString64, - pub custody_id: u32, - pub custody_type: FundCustodyType, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub token_ref: Pubkey, - #[serde( - serialize_with = "as64_serialize", - deserialize_with = "as64_deserialize" - )] - pub token_name: ArrayString64, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub address: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub fees_address: Pubkey, - pub balance: f64, - pub fees_balance: f64, - pub bump: u8, -} - -#[repr(u8)] -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)] -pub enum FundVaultType { - Pool, - Farm, - Vault, -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq)] -pub struct FundVault { - pub discriminator: u64, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub fund_ref: Pubkey, - pub vault_id: u32, - pub vault_type: FundVaultType, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub vault_ref: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub router_program_id: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub underlying_pool_id: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub underlying_pool_ref: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub underlying_lp_token_mint: Pubkey, - pub lp_balance: u64, - pub balance_update_time: UnixTimestamp, - pub bump: u8, -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Default, PartialEq)] -pub struct FundSchedule { - pub start_time: UnixTimestamp, - pub end_time: UnixTimestamp, - pub approval_required: bool, - pub min_amount_usd: f64, - pub max_amount_usd: f64, - pub fee: f64, -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Default, PartialEq)] -pub struct FundAssetsTrackingConfig { - pub assets_limit_usd: f64, - pub max_update_age_sec: u64, - pub max_price_error: f64, - pub max_price_age_sec: u64, - pub issue_virtual_tokens: bool, -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Default, PartialEq)] -pub struct FundInfo { - pub deposit_schedule: FundSchedule, - pub withdrawal_schedule: FundSchedule, - pub assets_config: FundAssetsTrackingConfig, - pub virtual_tokens_supply: u64, - pub amount_invested_usd: f64, - pub amount_removed_usd: f64, - pub current_assets_usd: f64, - pub assets_update_time: UnixTimestamp, - pub admin_action_time: UnixTimestamp, - pub last_trade_time: UnixTimestamp, - pub liquidation_start_time: UnixTimestamp, - pub liquidation_amount_usd: f64, - pub liquidation_amount_tokens: u64, -} - -impl Named for Fund { - fn name(&self) -> ArrayString64 { - self.name - } -} - -impl Versioned for Fund { - fn version(&self) -> u16 { - self.version - } -} - -impl FundUserAction { - pub const LEN: usize = 16; -} - -impl Packed for FundUserAction { - fn get_size(&self) -> usize { - Self::LEN - } - - fn pack(&self, output: &mut [u8]) -> Result { - check_data_len(output, Self::LEN)?; - - let output = array_mut_ref![output, 0, FundUserAction::LEN]; - - let (time_out, amount_out) = mut_array_refs![output, 8, 8]; - - *time_out = self.time.to_le_bytes(); - *amount_out = self.amount.to_le_bytes(); - - Ok(Self::LEN) - } - - fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; Self::LEN] = [0; Self::LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidAccountData) - } - } - - fn unpack(input: &[u8]) -> Result { - check_data_len(input, Self::LEN)?; - - let input = array_ref![input, 0, FundUserAction::LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let (time, amount) = array_refs![input, 8, 8]; - - Ok(Self { - time: i64::from_le_bytes(*time), - amount: u64::from_le_bytes(*amount), - }) - } -} - -impl FundUserRequests { - pub const LEN: usize = 201; -} - -impl Packed for FundUserRequests { - fn get_size(&self) -> usize { - Self::LEN - } - - fn pack(&self, output: &mut [u8]) -> Result { - check_data_len(output, Self::LEN)?; - - let output = array_mut_ref![output, 0, FundUserRequests::LEN]; - - let ( - discriminator_out, - fund_ref_out, - token_ref_out, - deposit_request_out, - last_deposit_out, - withdrawal_request_out, - last_withdrawal_out, - deny_reason_out, - bump_out, - ) = mut_array_refs![output, 8, 32, 32, 16, 16, 16, 16, 64, 1]; - - *discriminator_out = self.discriminator.to_le_bytes(); - fund_ref_out.copy_from_slice(self.fund_ref.as_ref()); - token_ref_out.copy_from_slice(self.token_ref.as_ref()); - self.deposit_request.pack(deposit_request_out)?; - self.last_deposit.pack(last_deposit_out)?; - self.withdrawal_request.pack(withdrawal_request_out)?; - self.last_withdrawal.pack(last_withdrawal_out)?; - pack_array_string64(&self.deny_reason, deny_reason_out); - bump_out[0] = self.bump; - - Ok(Self::LEN) - } - - fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; Self::LEN] = [0; Self::LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidAccountData) - } - } - - fn unpack(input: &[u8]) -> Result { - check_data_len(input, Self::LEN)?; - - let input = array_ref![input, 0, FundUserRequests::LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let ( - discriminator, - fund_ref, - token_ref, - deposit_request, - last_deposit, - withdrawal_request, - last_withdrawal, - deny_reason, - bump, - ) = array_refs![input, 8, 32, 32, 16, 16, 16, 16, 64, 1]; - - Ok(Self { - discriminator: u64::from_le_bytes(*discriminator), - fund_ref: Pubkey::new_from_array(*fund_ref), - token_ref: Pubkey::new_from_array(*token_ref), - deposit_request: FundUserAction::unpack(deposit_request)?, - last_deposit: FundUserAction::unpack(last_deposit)?, - withdrawal_request: FundUserAction::unpack(withdrawal_request)?, - last_withdrawal: FundUserAction::unpack(last_withdrawal)?, - deny_reason: unpack_array_string64(deny_reason)?, - bump: bump[0], - }) - } -} - -impl FundAssets { - pub const LEN: usize = 50; -} - -impl Packed for FundAssets { - fn get_size(&self) -> usize { - Self::LEN - } - - fn pack(&self, output: &mut [u8]) -> Result { - check_data_len(output, Self::LEN)?; - - let output = array_mut_ref![output, 0, FundAssets::LEN]; - - let ( - fund_asset_type_out, - target_hash_out, - current_hash_out, - current_cycle_out, - current_assets_usd_out, - cycle_start_time_out, - cycle_end_time_out, - bump_out, - ) = mut_array_refs![output, 1, 8, 8, 8, 8, 8, 8, 1]; - - fund_asset_type_out[0] = self.asset_type as u8; - *target_hash_out = self.target_hash.to_le_bytes(); - *current_hash_out = self.current_hash.to_le_bytes(); - *current_cycle_out = self.current_cycle.to_le_bytes(); - *current_assets_usd_out = self.current_assets_usd.to_le_bytes(); - *cycle_start_time_out = self.cycle_start_time.to_le_bytes(); - *cycle_end_time_out = self.cycle_end_time.to_le_bytes(); - bump_out[0] = self.bump; - - Ok(Self::LEN) - } - - fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; Self::LEN] = [0; Self::LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidAccountData) - } - } - - fn unpack(input: &[u8]) -> Result { - check_data_len(input, Self::LEN)?; - - let input = array_ref![input, 0, FundAssets::LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let ( - asset_type, - target_hash, - current_hash, - current_cycle, - current_assets_usd, - cycle_start_time, - cycle_end_time, - bump, - ) = array_refs![input, 1, 8, 8, 8, 8, 8, 8, 1]; - - Ok(Self { - asset_type: FundAssetType::try_from_primitive(asset_type[0]) - .or(Err(ProgramError::InvalidInstructionData))?, - target_hash: u64::from_le_bytes(*target_hash), - current_hash: u64::from_le_bytes(*current_hash), - current_cycle: u64::from_le_bytes(*current_cycle), - current_assets_usd: f64::from_le_bytes(*current_assets_usd), - cycle_start_time: i64::from_le_bytes(*cycle_start_time), - cycle_end_time: i64::from_le_bytes(*cycle_end_time), - bump: bump[0], - }) - } -} - -impl FundCustody { - pub const LEN: usize = 143; -} - -impl Packed for FundCustody { - fn get_size(&self) -> usize { - Self::LEN - } - - fn pack(&self, output: &mut [u8]) -> Result { - check_data_len(output, Self::LEN)?; - - let output = array_mut_ref![output, 0, FundCustody::LEN]; - - let ( - discriminator_out, - fund_ref_out, - custody_id_out, - custody_type_out, - is_vault_token_out, - token_ref_out, - address_out, - fees_address_out, - bump_out, - ) = mut_array_refs![output, 8, 32, 4, 1, 1, 32, 32, 32, 1]; - - *discriminator_out = self.discriminator.to_le_bytes(); - fund_ref_out.copy_from_slice(self.fund_ref.as_ref()); - *custody_id_out = self.custody_id.to_le_bytes(); - custody_type_out[0] = self.custody_type as u8; - is_vault_token_out[0] = self.is_vault_token as u8; - token_ref_out.copy_from_slice(self.token_ref.as_ref()); - address_out.copy_from_slice(self.address.as_ref()); - fees_address_out.copy_from_slice(self.fees_address.as_ref()); - bump_out[0] = self.bump; - - Ok(Self::LEN) - } - - fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; Self::LEN] = [0; Self::LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidAccountData) - } - } - - fn unpack(input: &[u8]) -> Result { - check_data_len(input, Self::LEN)?; - - let input = array_ref![input, 0, FundCustody::LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let ( - discriminator, - fund_ref, - custody_id, - custody_type, - is_vault_token, - token_ref, - address, - fees_address, - bump, - ) = array_refs![input, 8, 32, 4, 1, 1, 32, 32, 32, 1]; - - Ok(Self { - discriminator: u64::from_le_bytes(*discriminator), - fund_ref: Pubkey::new_from_array(*fund_ref), - custody_id: u32::from_le_bytes(*custody_id), - custody_type: FundCustodyType::try_from_primitive(custody_type[0]) - .or(Err(ProgramError::InvalidAccountData))?, - is_vault_token: unpack_bool(is_vault_token)?, - token_ref: Pubkey::new_from_array(*token_ref), - address: Pubkey::new_from_array(*address), - fees_address: Pubkey::new_from_array(*fees_address), - bump: bump[0], - }) - } -} - -impl FundVault { - pub const LEN: usize = 222; -} - -impl Packed for FundVault { - fn get_size(&self) -> usize { - Self::LEN - } - - fn pack(&self, output: &mut [u8]) -> Result { - check_data_len(output, Self::LEN)?; - - let output = array_mut_ref![output, 0, FundVault::LEN]; - - let ( - discriminator_out, - fund_ref_out, - vault_id_out, - vault_type_out, - vault_ref_out, - router_program_id_out, - underlying_pool_id_out, - underlying_pool_ref_out, - underlying_lp_token_mint_out, - lp_balance_out, - balance_update_time_out, - bump_out, - ) = mut_array_refs![output, 8, 32, 4, 1, 32, 32, 32, 32, 32, 8, 8, 1]; - - *discriminator_out = self.discriminator.to_le_bytes(); - fund_ref_out.copy_from_slice(self.fund_ref.as_ref()); - *vault_id_out = self.vault_id.to_le_bytes(); - vault_type_out[0] = self.vault_type as u8; - vault_ref_out.copy_from_slice(self.vault_ref.as_ref()); - router_program_id_out.copy_from_slice(self.router_program_id.as_ref()); - underlying_pool_id_out.copy_from_slice(self.underlying_pool_id.as_ref()); - underlying_pool_ref_out.copy_from_slice(self.underlying_pool_ref.as_ref()); - underlying_lp_token_mint_out.copy_from_slice(self.underlying_lp_token_mint.as_ref()); - *lp_balance_out = self.lp_balance.to_le_bytes(); - *balance_update_time_out = self.balance_update_time.to_le_bytes(); - bump_out[0] = self.bump; - - Ok(Self::LEN) - } - - fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; Self::LEN] = [0; Self::LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidAccountData) - } - } - - fn unpack(input: &[u8]) -> Result { - check_data_len(input, Self::LEN)?; - - let input = array_ref![input, 0, FundVault::LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let ( - discriminator, - fund_ref, - vault_id, - vault_type, - vault_ref, - router_program_id, - underlying_pool_id, - underlying_pool_ref, - underlying_lp_token_mint, - lp_balance, - balance_update_time, - bump, - ) = array_refs![input, 8, 32, 4, 1, 32, 32, 32, 32, 32, 8, 8, 1]; - - Ok(Self { - discriminator: u64::from_le_bytes(*discriminator), - fund_ref: Pubkey::new_from_array(*fund_ref), - vault_id: u32::from_le_bytes(*vault_id), - vault_type: FundVaultType::try_from_primitive(vault_type[0]) - .or(Err(ProgramError::InvalidAccountData))?, - vault_ref: Pubkey::new_from_array(*vault_ref), - router_program_id: Pubkey::new_from_array(*router_program_id), - underlying_pool_id: Pubkey::new_from_array(*underlying_pool_id), - underlying_pool_ref: Pubkey::new_from_array(*underlying_pool_ref), - underlying_lp_token_mint: Pubkey::new_from_array(*underlying_lp_token_mint), - lp_balance: u64::from_le_bytes(*lp_balance), - balance_update_time: i64::from_le_bytes(*balance_update_time), - bump: bump[0], - }) - } -} - -impl Fund { - pub const LEN: usize = 367; -} - -impl Packed for Fund { - fn get_size(&self) -> usize { - Self::LEN - } - - fn pack(&self, output: &mut [u8]) -> Result { - check_data_len(output, Self::LEN)?; - - let output = array_mut_ref![output, 0, Fund::LEN]; - - let ( - name_out, - version_out, - fund_type_out, - official_out, - refdb_index_out, - refdb_counter_out, - metadata_bump_out, - authority_bump_out, - fund_token_bump_out, - multisig_bump_out, - fund_program_id_out, - fund_authority_out, - fund_manager_out, - fund_token_ref_out, - info_account_out, - multisig_account_out, - vaults_assets_info_out, - custodies_assets_info_out, - description_account_out, - ) = mut_array_refs![ - output, 64, 2, 1, 1, 5, 2, 1, 1, 1, 1, 32, 32, 32, 32, 32, 32, 32, 32, 32 - ]; - - pack_array_string64(&self.name, name_out); - *version_out = self.version.to_le_bytes(); - fund_type_out[0] = self.fund_type as u8; - official_out[0] = self.official as u8; - pack_option_u32(self.refdb_index, refdb_index_out); - *refdb_counter_out = self.refdb_counter.to_le_bytes(); - metadata_bump_out[0] = self.metadata_bump as u8; - authority_bump_out[0] = self.authority_bump as u8; - fund_token_bump_out[0] = self.fund_token_bump as u8; - multisig_bump_out[0] = self.multisig_bump as u8; - fund_program_id_out.copy_from_slice(self.fund_program_id.as_ref()); - fund_authority_out.copy_from_slice(self.fund_authority.as_ref()); - fund_manager_out.copy_from_slice(self.fund_manager.as_ref()); - fund_token_ref_out.copy_from_slice(self.fund_token_ref.as_ref()); - info_account_out.copy_from_slice(self.info_account.as_ref()); - multisig_account_out.copy_from_slice(self.multisig_account.as_ref()); - vaults_assets_info_out.copy_from_slice(self.vaults_assets_info.as_ref()); - custodies_assets_info_out.copy_from_slice(self.custodies_assets_info.as_ref()); - description_account_out.copy_from_slice(self.description_account.as_ref()); - - Ok(Self::LEN) - } - - fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; Self::LEN] = [0; Self::LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidAccountData) - } - } - - fn unpack(input: &[u8]) -> Result { - check_data_len(input, Self::LEN)?; - - let input = array_ref![input, 0, Fund::LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let ( - name, - version, - fund_type, - official, - refdb_index, - refdb_counter, - metadata_bump, - authority_bump, - fund_token_bump, - multisig_bump, - fund_program_id, - fund_authority, - fund_manager, - fund_token_ref, - info_account, - multisig_account, - vaults_assets_info, - custodies_assets_info, - description_account, - ) = array_refs![input, 64, 2, 1, 1, 5, 2, 1, 1, 1, 1, 32, 32, 32, 32, 32, 32, 32, 32, 32]; - - Ok(Self { - name: unpack_array_string64(name)?, - version: u16::from_le_bytes(*version), - fund_type: FundType::try_from_primitive(fund_type[0]) - .or(Err(ProgramError::InvalidAccountData))?, - official: unpack_bool(official)?, - refdb_index: unpack_option_u32(refdb_index)?, - refdb_counter: u16::from_le_bytes(*refdb_counter), - metadata_bump: metadata_bump[0], - authority_bump: authority_bump[0], - fund_token_bump: fund_token_bump[0], - multisig_bump: multisig_bump[0], - fund_program_id: Pubkey::new_from_array(*fund_program_id), - fund_authority: Pubkey::new_from_array(*fund_authority), - fund_manager: Pubkey::new_from_array(*fund_manager), - fund_token_ref: Pubkey::new_from_array(*fund_token_ref), - info_account: Pubkey::new_from_array(*info_account), - multisig_account: Pubkey::new_from_array(*multisig_account), - vaults_assets_info: Pubkey::new_from_array(*vaults_assets_info), - custodies_assets_info: Pubkey::new_from_array(*custodies_assets_info), - description_account: Pubkey::new_from_array(*description_account), - }) - } -} - -impl std::fmt::Display for FundType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match *self { - FundType::General => write!(f, "General"), - } - } -} - -impl std::fmt::Display for Fund { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", to_string(&self).unwrap()) - } -} - -impl std::fmt::Display for FundUserInfo { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", to_string(&self).unwrap()) - } -} - -impl std::fmt::Display for FundUserRequests { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", to_string(&self).unwrap()) - } -} - -impl std::fmt::Display for FundInfo { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", to_string(&self).unwrap()) - } -} - -impl std::fmt::Display for FundAssets { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", to_string(&self).unwrap()) - } -} - -impl std::fmt::Display for FundAssetType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match *self { - FundAssetType::Vault => write!(f, "Vault"), - FundAssetType::Custody => write!(f, "Custody"), - } - } -} - -impl std::str::FromStr for FundAssetType { - type Err = ProgramError; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "vault" => Ok(FundAssetType::Vault), - "custody" => Ok(FundAssetType::Custody), - _ => Err(ProgramError::InvalidArgument), - } - } -} - -impl std::fmt::Display for FundCustody { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", to_string(&self).unwrap()) - } -} - -impl std::fmt::Display for FundCustodyWithBalance { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", to_string(&self).unwrap()) - } -} - -impl std::fmt::Display for FundCustodyType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match *self { - FundCustodyType::DepositWithdraw => write!(f, "DepositWithdraw"), - FundCustodyType::Trading => write!(f, "Trading"), - } - } -} - -impl std::str::FromStr for FundCustodyType { - type Err = ProgramError; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "depositwithdraw" => Ok(FundCustodyType::DepositWithdraw), - "trading" => Ok(FundCustodyType::Trading), - _ => Err(ProgramError::InvalidArgument), - } - } -} - -impl std::fmt::Display for FundVault { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", to_string(&self).unwrap()) - } -} - -impl std::fmt::Display for FundVaultType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match *self { - FundVaultType::Pool => write!(f, "Pool"), - FundVaultType::Farm => write!(f, "Farm"), - FundVaultType::Vault => write!(f, "Vault"), - } - } -} - -impl std::str::FromStr for FundVaultType { - type Err = ProgramError; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "pool" => Ok(FundVaultType::Pool), - "farm" => Ok(FundVaultType::Farm), - "vault" => Ok(FundVaultType::Vault), - _ => Err(ProgramError::InvalidArgument), - } - } -} diff --git a/farms/farm-sdk/src/id.rs b/farms/farm-sdk/src/id.rs deleted file mode 100644 index 0baabaa8148..00000000000 --- a/farms/farm-sdk/src/id.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! Official accounts and program ids - -include!(concat!( - env!( - "OUT_DIR", - "Please set OUT_DIR environment variable to the build script output path" - ), - "/constants.rs" -)); diff --git a/farms/farm-sdk/src/instruction/amm.rs b/farms/farm-sdk/src/instruction/amm.rs deleted file mode 100644 index a1de0bd6b08..00000000000 --- a/farms/farm-sdk/src/instruction/amm.rs +++ /dev/null @@ -1,431 +0,0 @@ -//! Raydium router instructions. - -use { - crate::pack::check_data_len, - arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}, - num_enum::TryFromPrimitive, - solana_program::program_error::ProgramError, -}; - -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum AmmInstruction { - /// Initialize on-chain records for a new user - /// # Account references are protocol specific, - /// see particular Router instructions handlers for more info - UserInit, - - /// Add liquidity to the AMM Pool - /// # Account references are protocol specific, - /// see particular Router instructions handlers for more info - AddLiquidity { - max_token_a_amount: u64, - max_token_b_amount: u64, - }, - - /// Remove liquidity from the AMM Pool - /// # Account references are protocol specific, - /// see particular Router instructions handlers for more info - RemoveLiquidity { amount: u64 }, - - /// Swap tokens in the AMM Pool - /// # Account references are protocol specific, - /// see particular Router instructions handlers for more info - Swap { - token_a_amount_in: u64, - token_b_amount_in: u64, - min_token_amount_out: u64, - }, - - /// Stake LP tokens to the Farm - /// # Account references are protocol specific, - /// see particular Router instructions handlers for more info - Stake { amount: u64 }, - - /// Unstake LP tokens from the Farm - /// # Account references are protocol specific, - /// see particular Router instructions handlers for more info - Unstake { amount: u64 }, - - /// Claim pending rewards from the Farm - /// # Account references are protocol specific, - /// see particular Router instructions handlers for more info - Harvest, - - /// Wrap the token to protocol specific token - /// # Account references are protocol specific, - /// see particular Router instructions handlers for more info - WrapToken { amount: u64 }, - - /// Unwrap the token from protocol specific token - /// # Account references are protocol specific, - /// see particular Router instructions handlers for more info - UnwrapToken { amount: u64 }, -} - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)] -pub enum AmmInstructionType { - UserInit, - AddLiquidity, - RemoveLiquidity, - Swap, - Stake, - Unstake, - Harvest, - WrapToken, - UnwrapToken, -} - -impl AmmInstruction { - pub const MAX_LEN: usize = 25; - pub const USER_INIT_LEN: usize = 1; - pub const ADD_LIQUIDITY_LEN: usize = 17; - pub const REMOVE_LIQUIDITY_LEN: usize = 9; - pub const SWAP_LEN: usize = 25; - pub const STAKE_LEN: usize = 9; - pub const UNSTAKE_LEN: usize = 9; - pub const HARVEST_LEN: usize = 1; - pub const WRAP_TOKEN_LEN: usize = 9; - pub const UNWRAP_TOKEN_LEN: usize = 9; - - pub const fn get_size(&self) -> usize { - match self { - Self::UserInit { .. } => Self::USER_INIT_LEN, - Self::AddLiquidity { .. } => Self::ADD_LIQUIDITY_LEN, - Self::RemoveLiquidity { .. } => Self::REMOVE_LIQUIDITY_LEN, - Self::Swap { .. } => Self::SWAP_LEN, - Self::Stake { .. } => Self::STAKE_LEN, - Self::Unstake { .. } => Self::UNSTAKE_LEN, - Self::Harvest { .. } => Self::HARVEST_LEN, - Self::WrapToken { .. } => Self::WRAP_TOKEN_LEN, - Self::UnwrapToken { .. } => Self::UNWRAP_TOKEN_LEN, - } - } - - pub fn pack(&self, output: &mut [u8]) -> Result { - match self { - Self::UserInit { .. } => self.pack_user_init(output), - Self::AddLiquidity { .. } => self.pack_add_liquidity(output), - Self::RemoveLiquidity { .. } => self.pack_remove_liquidity(output), - Self::Swap { .. } => self.pack_swap(output), - Self::Stake { .. } => self.pack_stake(output), - Self::Unstake { .. } => self.pack_unstake(output), - Self::Harvest { .. } => self.pack_harvest(output), - Self::WrapToken { .. } => self.pack_wrap_token(output), - Self::UnwrapToken { .. } => self.pack_unwrap_token(output), - } - } - - pub fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; AmmInstruction::MAX_LEN] = [0; AmmInstruction::MAX_LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - pub fn unpack(input: &[u8]) -> Result { - check_data_len(input, 1)?; - let instruction_type = AmmInstructionType::try_from_primitive(input[0]) - .or(Err(ProgramError::InvalidInstructionData))?; - match instruction_type { - AmmInstructionType::UserInit => AmmInstruction::unpack_user_init(input), - AmmInstructionType::AddLiquidity => AmmInstruction::unpack_add_liquidity(input), - AmmInstructionType::RemoveLiquidity => AmmInstruction::unpack_remove_liquidity(input), - AmmInstructionType::Swap => AmmInstruction::unpack_swap(input), - AmmInstructionType::Stake => AmmInstruction::unpack_stake(input), - AmmInstructionType::Unstake => AmmInstruction::unpack_unstake(input), - AmmInstructionType::Harvest => AmmInstruction::unpack_harvest(input), - AmmInstructionType::WrapToken => AmmInstruction::unpack_wrap_token(input), - AmmInstructionType::UnwrapToken => AmmInstruction::unpack_unwrap_token(input), - } - } - - fn pack_user_init(&self, output: &mut [u8]) -> Result { - check_data_len(output, AmmInstruction::USER_INIT_LEN)?; - - if let AmmInstruction::UserInit = self { - let instruction_type_out = array_mut_ref![output, 0, 1]; - - instruction_type_out[0] = AmmInstructionType::UserInit as u8; - - Ok(AmmInstruction::USER_INIT_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_add_liquidity(&self, output: &mut [u8]) -> Result { - check_data_len(output, AmmInstruction::ADD_LIQUIDITY_LEN)?; - - if let AmmInstruction::AddLiquidity { - max_token_a_amount, - max_token_b_amount, - } = self - { - let output = array_mut_ref![output, 0, AmmInstruction::ADD_LIQUIDITY_LEN]; - let (instruction_type_pack, max_token_a_amount_pack, max_token_b_amount_pack) = - mut_array_refs![output, 1, 8, 8]; - - instruction_type_pack[0] = AmmInstructionType::AddLiquidity as u8; - - *max_token_a_amount_pack = max_token_a_amount.to_le_bytes(); - *max_token_b_amount_pack = max_token_b_amount.to_le_bytes(); - - Ok(AmmInstruction::ADD_LIQUIDITY_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_remove_liquidity(&self, output: &mut [u8]) -> Result { - check_data_len(output, AmmInstruction::REMOVE_LIQUIDITY_LEN)?; - - if let AmmInstruction::RemoveLiquidity { amount } = self { - let output = array_mut_ref![output, 0, AmmInstruction::REMOVE_LIQUIDITY_LEN]; - let (instruction_type_pack, amount_pack) = mut_array_refs![output, 1, 8]; - - instruction_type_pack[0] = AmmInstructionType::RemoveLiquidity as u8; - - *amount_pack = amount.to_le_bytes(); - - Ok(AmmInstruction::REMOVE_LIQUIDITY_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_swap(&self, output: &mut [u8]) -> Result { - check_data_len(output, AmmInstruction::SWAP_LEN)?; - - if let AmmInstruction::Swap { - token_a_amount_in, - token_b_amount_in, - min_token_amount_out, - } = self - { - let output = array_mut_ref![output, 0, AmmInstruction::SWAP_LEN]; - let ( - instruction_type_pack, - token_a_amount_in_pack, - token_b_amount_in_pack, - min_token_amount_out_pack, - ) = mut_array_refs![output, 1, 8, 8, 8]; - - instruction_type_pack[0] = AmmInstructionType::Swap as u8; - - *token_a_amount_in_pack = token_a_amount_in.to_le_bytes(); - *token_b_amount_in_pack = token_b_amount_in.to_le_bytes(); - *min_token_amount_out_pack = min_token_amount_out.to_le_bytes(); - - Ok(AmmInstruction::SWAP_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_stake(&self, output: &mut [u8]) -> Result { - check_data_len(output, AmmInstruction::STAKE_LEN)?; - - if let AmmInstruction::Stake { amount } = self { - let output = array_mut_ref![output, 0, AmmInstruction::STAKE_LEN]; - let (instruction_type_pack, amount_pack) = mut_array_refs![output, 1, 8]; - - instruction_type_pack[0] = AmmInstructionType::Stake as u8; - - *amount_pack = amount.to_le_bytes(); - - Ok(AmmInstruction::STAKE_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_unstake(&self, output: &mut [u8]) -> Result { - check_data_len(output, AmmInstruction::UNSTAKE_LEN)?; - - if let AmmInstruction::Unstake { amount } = self { - let output = array_mut_ref![output, 0, AmmInstruction::UNSTAKE_LEN]; - let (instruction_type_pack, amount_pack) = mut_array_refs![output, 1, 8]; - - instruction_type_pack[0] = AmmInstructionType::Unstake as u8; - - *amount_pack = amount.to_le_bytes(); - - Ok(AmmInstruction::UNSTAKE_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_harvest(&self, output: &mut [u8]) -> Result { - check_data_len(output, AmmInstruction::HARVEST_LEN)?; - - if let AmmInstruction::Harvest = self { - let instruction_type_pack = array_mut_ref![output, 0, 1]; - - instruction_type_pack[0] = AmmInstructionType::Harvest as u8; - - Ok(AmmInstruction::HARVEST_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_wrap_token(&self, output: &mut [u8]) -> Result { - check_data_len(output, AmmInstruction::WRAP_TOKEN_LEN)?; - - if let AmmInstruction::WrapToken { amount } = self { - let output = array_mut_ref![output, 0, AmmInstruction::WRAP_TOKEN_LEN]; - let (instruction_type_pack, amount_pack) = mut_array_refs![output, 1, 8]; - - instruction_type_pack[0] = AmmInstructionType::WrapToken as u8; - - *amount_pack = amount.to_le_bytes(); - - Ok(AmmInstruction::WRAP_TOKEN_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_unwrap_token(&self, output: &mut [u8]) -> Result { - check_data_len(output, AmmInstruction::UNWRAP_TOKEN_LEN)?; - - if let AmmInstruction::UnwrapToken { amount } = self { - let output = array_mut_ref![output, 0, AmmInstruction::UNWRAP_TOKEN_LEN]; - let (instruction_type_pack, amount_pack) = mut_array_refs![output, 1, 8]; - - instruction_type_pack[0] = AmmInstructionType::UnwrapToken as u8; - - *amount_pack = amount.to_le_bytes(); - - Ok(AmmInstruction::UNWRAP_TOKEN_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn unpack_user_init(input: &[u8]) -> Result { - check_data_len(input, AmmInstruction::USER_INIT_LEN)?; - Ok(Self::UserInit) - } - - fn unpack_add_liquidity(input: &[u8]) -> Result { - check_data_len(input, AmmInstruction::ADD_LIQUIDITY_LEN)?; - - let input = array_ref![input, 1, AmmInstruction::ADD_LIQUIDITY_LEN - 1]; - #[allow(clippy::ptr_offset_with_cast)] - let (max_token_a_amount, max_token_b_amount) = array_refs![input, 8, 8]; - - Ok(Self::AddLiquidity { - max_token_a_amount: u64::from_le_bytes(*max_token_a_amount), - max_token_b_amount: u64::from_le_bytes(*max_token_b_amount), - }) - } - - fn unpack_remove_liquidity(input: &[u8]) -> Result { - check_data_len(input, AmmInstruction::REMOVE_LIQUIDITY_LEN)?; - Ok(Self::RemoveLiquidity { - amount: u64::from_le_bytes(*array_ref![input, 1, 8]), - }) - } - - fn unpack_swap(input: &[u8]) -> Result { - check_data_len(input, AmmInstruction::SWAP_LEN)?; - - let input = array_ref![input, 1, AmmInstruction::SWAP_LEN - 1]; - #[allow(clippy::ptr_offset_with_cast)] - let (token_a_amount_in, token_b_amount_in, min_token_amount_out) = - array_refs![input, 8, 8, 8]; - - Ok(Self::Swap { - token_a_amount_in: u64::from_le_bytes(*token_a_amount_in), - token_b_amount_in: u64::from_le_bytes(*token_b_amount_in), - min_token_amount_out: u64::from_le_bytes(*min_token_amount_out), - }) - } - - fn unpack_stake(input: &[u8]) -> Result { - check_data_len(input, AmmInstruction::STAKE_LEN)?; - Ok(Self::Stake { - amount: u64::from_le_bytes(*array_ref![input, 1, 8]), - }) - } - - fn unpack_unstake(input: &[u8]) -> Result { - check_data_len(input, AmmInstruction::UNSTAKE_LEN)?; - Ok(Self::Unstake { - amount: u64::from_le_bytes(*array_ref![input, 1, 8]), - }) - } - - fn unpack_harvest(input: &[u8]) -> Result { - check_data_len(input, AmmInstruction::HARVEST_LEN)?; - Ok(Self::Harvest) - } - - fn unpack_wrap_token(input: &[u8]) -> Result { - check_data_len(input, AmmInstruction::WRAP_TOKEN_LEN)?; - Ok(Self::WrapToken { - amount: u64::from_le_bytes(*array_ref![input, 1, 8]), - }) - } - - fn unpack_unwrap_token(input: &[u8]) -> Result { - check_data_len(input, AmmInstruction::UNWRAP_TOKEN_LEN)?; - Ok(Self::UnwrapToken { - amount: u64::from_le_bytes(*array_ref![input, 1, 8]), - }) - } -} - -impl std::fmt::Display for AmmInstructionType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match *self { - AmmInstructionType::UserInit => write!(f, "UserInit"), - AmmInstructionType::AddLiquidity => write!(f, "AddLiquidity"), - AmmInstructionType::RemoveLiquidity => write!(f, "RemoveLiquidity"), - AmmInstructionType::Swap => write!(f, "Swap"), - AmmInstructionType::Stake => write!(f, "Stake"), - AmmInstructionType::Unstake => write!(f, "Unstake"), - AmmInstructionType::Harvest => write!(f, "Harvest"), - AmmInstructionType::WrapToken => write!(f, "WrapToken"), - AmmInstructionType::UnwrapToken => write!(f, "UnwrapToken"), - } - } -} - -#[cfg(test)] -mod tests { - #[test] - fn test_vec_serialization() { - let ri1 = super::AmmInstruction::AddLiquidity { - max_token_a_amount: 100, - max_token_b_amount: 200, - }; - - let vec = ri1.to_vec().unwrap(); - - let ri2 = super::AmmInstruction::unpack(&vec[..]).unwrap(); - - assert_eq!(ri1, ri2); - } - - #[test] - fn test_slice_serialization() { - let ri1 = super::AmmInstruction::AddLiquidity { - max_token_a_amount: 100, - max_token_b_amount: 200, - }; - - let mut output: [u8; super::AmmInstruction::ADD_LIQUIDITY_LEN] = - [0; super::AmmInstruction::ADD_LIQUIDITY_LEN]; - ri1.pack(&mut output[..]).unwrap(); - - let ri2 = super::AmmInstruction::unpack(&output).unwrap(); - - assert_eq!(ri1, ri2); - } -} diff --git a/farms/farm-sdk/src/instruction/fund.rs b/farms/farm-sdk/src/instruction/fund.rs deleted file mode 100644 index 65d1f77b124..00000000000 --- a/farms/farm-sdk/src/instruction/fund.rs +++ /dev/null @@ -1,1194 +0,0 @@ -//! Fund management instructions. - -use { - crate::{ - fund::{FundAssetsTrackingConfig, FundCustodyType, FundSchedule, FundVaultType}, - instruction::{amm::AmmInstruction, vault::VaultInstruction}, - pack::{ - check_data_len, pack_array_string64, pack_bool, unpack_array_string64, unpack_bool, - }, - string::ArrayString64, - }, - arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}, - num_enum::TryFromPrimitive, - solana_program::program_error::ProgramError, -}; - -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum FundInstruction { - /// Initialize on-chain record for a new user - UserInit, - - /// Request deposit to the Fund - RequestDeposit { amount: u64 }, - - /// Cancel pending deposit to the Fund - CancelDeposit, - - /// Request withdrawal from the Fund - RequestWithdrawal { amount: u64 }, - - /// Cancel pending withdrawal from the Fund - CancelWithdrawal, - - /// Initialize the Fund - Init { step: u64 }, - - /// Set schedule and enable deposits - SetDepositSchedule { schedule: FundSchedule }, - - /// Disable all deposits - DisableDeposits, - - /// Approve pending deposit for the user - ApproveDeposit { amount: u64 }, - - /// Deny pending deposit for the user - DenyDeposit { deny_reason: ArrayString64 }, - - /// Set schedule and enable withdrawals - SetWithdrawalSchedule { schedule: FundSchedule }, - - /// Disable all withdrawals - DisableWithdrawals, - - /// Approve pending withdrawal for the user - ApproveWithdrawal { amount: u64 }, - - /// Deny pending withdrawal for the user - DenyWithdrawal { deny_reason: ArrayString64 }, - - /// Move funds from deposit/withdrawal custody to trading custody - LockAssets { amount: u64 }, - - /// Move funds from trading custody to deposit/withdrawal custody - UnlockAssets { amount: u64 }, - - /// Initialize multisig with a new set of admin signatures - SetAdminSigners { min_signatures: u8 }, - - /// Remove Fund specific multisig, Main Router's default auth will be used - RemoveMultisig, - - /// Set parameters for assets tracking - SetAssetsTrackingConfig { config: FundAssetsTrackingConfig }, - - /// Update Fund assets with the Vault's holdings - UpdateAssetsWithVault, - - /// Update Fund assets with the Custody's holdings - UpdateAssetsWithCustody, - - /// Add a Vault to the Fund - AddVault { - target_hash: u64, - vault_id: u32, - vault_type: FundVaultType, - }, - - /// Remove a Vault from the Fund - RemoveVault { - target_hash: u64, - vault_type: FundVaultType, - }, - - /// Add a Custody to the Fund - AddCustody { - target_hash: u64, - custody_id: u32, - custody_type: FundCustodyType, - }, - - /// Remove a Custody from the Fund - RemoveCustody { - target_hash: u64, - custody_type: FundCustodyType, - }, - - /// Start Fund liquidation process - StartLiquidation, - - /// Stop Fund liquidation process - StopLiquidation, - - /// Withdraw collected fees from the Fund - WithdrawFees { amount: u64 }, - - /// Raydium pool instructions - AmmInstructionRaydium { instruction: AmmInstruction }, - - /// Raydium vault instructions - VaultInstructionRaydium { instruction: VaultInstruction }, - - /// Orca pool instructions - AmmInstructionOrca { instruction: AmmInstruction }, - - /// Orca vault instructions - VaultInstructionOrca { instruction: VaultInstruction }, -} - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)] -pub enum FundInstructionType { - UserInit, - RequestDeposit, - CancelDeposit, - RequestWithdrawal, - CancelWithdrawal, - Init, - SetDepositSchedule, - DisableDeposits, - ApproveDeposit, - DenyDeposit, - SetWithdrawalSchedule, - DisableWithdrawals, - ApproveWithdrawal, - DenyWithdrawal, - LockAssets, - UnlockAssets, - SetAdminSigners, - RemoveMultisig, - SetAssetsTrackingConfig, - UpdateAssetsWithVault, - UpdateAssetsWithCustody, - AddVault, - RemoveVault, - AddCustody, - RemoveCustody, - StartLiquidation, - StopLiquidation, - WithdrawFees, - AmmInstructionRaydium, - VaultInstructionRaydium, - AmmInstructionOrca, - VaultInstructionOrca, -} - -impl FundInstruction { - pub const MAX_LEN: usize = 65; - pub const USER_INIT_LEN: usize = 1; - pub const REQUEST_DEPOSIT_LEN: usize = 9; - pub const CANCEL_DEPOSIT_LEN: usize = 1; - pub const REQUEST_WITHDRAWAL_LEN: usize = 9; - pub const CANCEL_WITHDRAWAL_LEN: usize = 1; - pub const INIT_LEN: usize = 9; - pub const SET_DEPOSIT_SCHEDULE_LEN: usize = 42; - pub const DISABLE_DEPOSITS_LEN: usize = 1; - pub const APPROVE_DEPOSIT_LEN: usize = 9; - pub const DENY_DEPOSIT_LEN: usize = 65; - pub const SET_WITHDRAWAL_SCHEDULE_LEN: usize = 42; - pub const DISABLE_WITHDRAWALS_LEN: usize = 1; - pub const APPROVE_WITHDRAWAL_LEN: usize = 9; - pub const DENY_WITHDRAWAL_LEN: usize = 65; - pub const LOCK_ASSETS_LEN: usize = 9; - pub const UNLOCK_ASSETS_LEN: usize = 9; - pub const SET_ADMIN_SIGNERS_LEN: usize = 2; - pub const REMOVE_MULTISIG_LEN: usize = 1; - pub const SET_ASSETS_TRACKING_CONFIG_LEN: usize = 34; - pub const UPDATE_ASSETS_WITH_VAULT_LEN: usize = 1; - pub const UPDATE_ASSETS_WITH_CUSTODY_LEN: usize = 1; - pub const ADD_VAULT_LEN: usize = 14; - pub const REMOVE_VAULT_LEN: usize = 10; - pub const ADD_CUSTODY_LEN: usize = 14; - pub const REMOVE_CUSTODY_LEN: usize = 10; - pub const START_LIQUIDATION_LEN: usize = 1; - pub const STOP_LIQUIDATION_LEN: usize = 1; - pub const WITHDRAW_FEES_LEN: usize = 9; - - pub fn pack(&self, output: &mut [u8]) -> Result { - match self { - Self::UserInit { .. } => self.pack_user_init(output), - Self::RequestDeposit { .. } => self.pack_request_deposit(output), - Self::CancelDeposit { .. } => self.pack_cancel_deposit(output), - Self::RequestWithdrawal { .. } => self.pack_request_withdrawal(output), - Self::CancelWithdrawal { .. } => self.pack_cancel_withdrawal(output), - Self::Init { .. } => self.pack_init(output), - Self::SetDepositSchedule { .. } => self.pack_set_deposit_schedule(output), - Self::DisableDeposits { .. } => self.pack_disable_deposits(output), - Self::ApproveDeposit { .. } => self.pack_approve_deposit(output), - Self::DenyDeposit { .. } => self.pack_deny_deposit(output), - Self::SetWithdrawalSchedule { .. } => self.pack_set_withdrawal_schedule(output), - Self::DisableWithdrawals { .. } => self.pack_disable_withdrawals(output), - Self::ApproveWithdrawal { .. } => self.pack_approve_withdrawal(output), - Self::DenyWithdrawal { .. } => self.pack_deny_withdrawal(output), - Self::LockAssets { .. } => self.pack_accept_funds(output), - Self::UnlockAssets { .. } => self.pack_release_funds(output), - Self::SetAdminSigners { .. } => self.pack_set_admin_signers(output), - Self::RemoveMultisig { .. } => self.pack_remove_multisig(output), - Self::SetAssetsTrackingConfig { .. } => self.pack_set_assets_tracking_config(output), - Self::UpdateAssetsWithVault { .. } => self.pack_update_assets_with_vault(output), - Self::UpdateAssetsWithCustody { .. } => self.pack_update_assets_with_custody(output), - Self::AddVault { .. } => self.pack_add_vault(output), - Self::RemoveVault { .. } => self.pack_remove_vault(output), - Self::AddCustody { .. } => self.pack_add_custody(output), - Self::RemoveCustody { .. } => self.pack_remove_custody(output), - Self::StartLiquidation { .. } => self.pack_start_liquidation(output), - Self::StopLiquidation { .. } => self.pack_stop_liquidation(output), - Self::WithdrawFees { .. } => self.pack_withdraw_fees(output), - Self::AmmInstructionRaydium { .. } => self.pack_amm_instruction_raydium(output), - Self::VaultInstructionRaydium { .. } => self.pack_vault_instruction_raydium(output), - Self::AmmInstructionOrca { .. } => self.pack_amm_instruction_orca(output), - Self::VaultInstructionOrca { .. } => self.pack_vault_instruction_orca(output), - } - } - - pub fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; FundInstruction::MAX_LEN] = [0; FundInstruction::MAX_LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - pub fn unpack(input: &[u8]) -> Result { - check_data_len(input, 1)?; - let instruction_type = FundInstructionType::try_from_primitive(input[0]) - .or(Err(ProgramError::InvalidInstructionData))?; - match instruction_type { - FundInstructionType::UserInit => FundInstruction::unpack_user_init(input), - FundInstructionType::RequestDeposit => FundInstruction::unpack_request_deposit(input), - FundInstructionType::CancelDeposit => FundInstruction::unpack_cancel_deposit(input), - FundInstructionType::RequestWithdrawal => { - FundInstruction::unpack_request_withdrawal(input) - } - FundInstructionType::CancelWithdrawal => { - FundInstruction::unpack_cancel_withdrawal(input) - } - FundInstructionType::Init => FundInstruction::unpack_init(input), - FundInstructionType::SetDepositSchedule => { - FundInstruction::unpack_set_deposit_schedule(input) - } - FundInstructionType::DisableDeposits => FundInstruction::unpack_disable_deposits(input), - FundInstructionType::ApproveDeposit => FundInstruction::unpack_approve_deposit(input), - FundInstructionType::DenyDeposit => FundInstruction::unpack_deny_deposit(input), - FundInstructionType::SetWithdrawalSchedule => { - FundInstruction::unpack_set_withdrawal_schedule(input) - } - FundInstructionType::DisableWithdrawals => { - FundInstruction::unpack_disable_withdrawals(input) - } - FundInstructionType::ApproveWithdrawal => { - FundInstruction::unpack_approve_withdrawal(input) - } - FundInstructionType::DenyWithdrawal => FundInstruction::unpack_deny_withdrawal(input), - FundInstructionType::LockAssets => FundInstruction::unpack_accept_funds(input), - FundInstructionType::UnlockAssets => FundInstruction::unpack_release_funds(input), - FundInstructionType::SetAdminSigners => { - FundInstruction::unpack_set_admin_signers(input) - } - FundInstructionType::RemoveMultisig => FundInstruction::unpack_remove_multisig(input), - FundInstructionType::SetAssetsTrackingConfig => { - FundInstruction::unpack_set_assets_tracking_config(input) - } - FundInstructionType::UpdateAssetsWithVault => { - FundInstruction::unpack_update_assets_with_vault(input) - } - FundInstructionType::UpdateAssetsWithCustody => { - FundInstruction::unpack_update_assets_with_custody(input) - } - FundInstructionType::AddVault => FundInstruction::unpack_add_vault(input), - FundInstructionType::RemoveVault => FundInstruction::unpack_remove_vault(input), - FundInstructionType::AddCustody => FundInstruction::unpack_add_custody(input), - FundInstructionType::RemoveCustody => FundInstruction::unpack_remove_custody(input), - FundInstructionType::StartLiquidation => { - FundInstruction::unpack_start_liquidation(input) - } - FundInstructionType::StopLiquidation => FundInstruction::unpack_stop_liquidation(input), - FundInstructionType::WithdrawFees => FundInstruction::unpack_withdraw_fees(input), - FundInstructionType::AmmInstructionRaydium => { - FundInstruction::unpack_amm_instruction_raydium(input) - } - FundInstructionType::VaultInstructionRaydium => { - FundInstruction::unpack_vault_instruction_raydium(input) - } - FundInstructionType::AmmInstructionOrca => { - FundInstruction::unpack_amm_instruction_orca(input) - } - FundInstructionType::VaultInstructionOrca => { - FundInstruction::unpack_vault_instruction_orca(input) - } - } - } - - fn pack_user_init(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::USER_INIT_LEN)?; - - if let FundInstruction::UserInit = self { - let instruction_type_out = array_mut_ref![output, 0, 1]; - - instruction_type_out[0] = FundInstructionType::UserInit as u8; - - Ok(FundInstruction::USER_INIT_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_request_deposit(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::REQUEST_DEPOSIT_LEN)?; - - if let FundInstruction::RequestDeposit { amount } = self { - let output = array_mut_ref![output, 0, FundInstruction::REQUEST_DEPOSIT_LEN]; - let (instruction_type_out, amount_out) = mut_array_refs![output, 1, 8]; - - instruction_type_out[0] = FundInstructionType::RequestDeposit as u8; - - *amount_out = amount.to_le_bytes(); - - Ok(FundInstruction::REQUEST_DEPOSIT_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_cancel_deposit(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::CANCEL_DEPOSIT_LEN)?; - - if let FundInstruction::CancelDeposit = self { - let instruction_type_out = array_mut_ref![output, 0, 1]; - - instruction_type_out[0] = FundInstructionType::CancelDeposit as u8; - - Ok(FundInstruction::CANCEL_DEPOSIT_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_request_withdrawal(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::REQUEST_WITHDRAWAL_LEN)?; - - if let FundInstruction::RequestWithdrawal { amount } = self { - let output = array_mut_ref![output, 0, FundInstruction::REQUEST_WITHDRAWAL_LEN]; - let (instruction_type_out, amount_out) = mut_array_refs![output, 1, 8]; - - instruction_type_out[0] = FundInstructionType::RequestWithdrawal as u8; - - *amount_out = amount.to_le_bytes(); - - Ok(FundInstruction::REQUEST_WITHDRAWAL_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_cancel_withdrawal(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::CANCEL_WITHDRAWAL_LEN)?; - - if let FundInstruction::CancelWithdrawal = self { - let instruction_type_out = array_mut_ref![output, 0, 1]; - - instruction_type_out[0] = FundInstructionType::CancelWithdrawal as u8; - - Ok(FundInstruction::CANCEL_WITHDRAWAL_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_init(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::INIT_LEN)?; - - if let FundInstruction::Init { step } = self { - let output = array_mut_ref![output, 0, FundInstruction::INIT_LEN]; - let (instruction_type_out, step_out) = mut_array_refs![output, 1, 8]; - - instruction_type_out[0] = FundInstructionType::Init as u8; - - *step_out = step.to_le_bytes(); - - Ok(FundInstruction::INIT_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_set_deposit_schedule(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::SET_DEPOSIT_SCHEDULE_LEN)?; - - if let FundInstruction::SetDepositSchedule { schedule } = self { - let output = array_mut_ref![output, 0, FundInstruction::SET_DEPOSIT_SCHEDULE_LEN]; - let ( - instruction_type_out, - start_time_out, - end_time_out, - approval_required_out, - min_amount_usd_out, - max_amount_usd_out, - fee_out, - ) = mut_array_refs![output, 1, 8, 8, 1, 8, 8, 8]; - - instruction_type_out[0] = FundInstructionType::SetDepositSchedule as u8; - - *start_time_out = schedule.start_time.to_le_bytes(); - *end_time_out = schedule.end_time.to_le_bytes(); - pack_bool(schedule.approval_required, approval_required_out); - *min_amount_usd_out = schedule.min_amount_usd.to_le_bytes(); - *max_amount_usd_out = schedule.max_amount_usd.to_le_bytes(); - *fee_out = schedule.fee.to_le_bytes(); - - Ok(FundInstruction::SET_DEPOSIT_SCHEDULE_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_disable_deposits(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::DISABLE_DEPOSITS_LEN)?; - - if let FundInstruction::DisableDeposits = self { - let instruction_type_out = array_mut_ref![output, 0, 1]; - - instruction_type_out[0] = FundInstructionType::DisableDeposits as u8; - - Ok(FundInstruction::DISABLE_DEPOSITS_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_approve_deposit(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::APPROVE_DEPOSIT_LEN)?; - - if let FundInstruction::ApproveDeposit { amount } = self { - let output = array_mut_ref![output, 0, FundInstruction::APPROVE_DEPOSIT_LEN]; - let (instruction_type_out, amount_out) = mut_array_refs![output, 1, 8]; - - instruction_type_out[0] = FundInstructionType::ApproveDeposit as u8; - - *amount_out = amount.to_le_bytes(); - - Ok(FundInstruction::APPROVE_DEPOSIT_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_deny_deposit(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::DENY_DEPOSIT_LEN)?; - - if let FundInstruction::DenyDeposit { deny_reason } = self { - let output = array_mut_ref![output, 0, FundInstruction::DENY_DEPOSIT_LEN]; - let (instruction_type_out, deny_reason_out) = mut_array_refs![output, 1, 64]; - - instruction_type_out[0] = FundInstructionType::DenyDeposit as u8; - - pack_array_string64(deny_reason, deny_reason_out); - - Ok(FundInstruction::DENY_DEPOSIT_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_set_withdrawal_schedule(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::SET_WITHDRAWAL_SCHEDULE_LEN)?; - - if let FundInstruction::SetWithdrawalSchedule { schedule } = self { - let output = array_mut_ref![output, 0, FundInstruction::SET_WITHDRAWAL_SCHEDULE_LEN]; - let ( - instruction_type_out, - start_time_out, - end_time_out, - approval_required_out, - min_amount_usd_out, - max_amount_usd_out, - fee_out, - ) = mut_array_refs![output, 1, 8, 8, 1, 8, 8, 8]; - - instruction_type_out[0] = FundInstructionType::SetWithdrawalSchedule as u8; - - *start_time_out = schedule.start_time.to_le_bytes(); - *end_time_out = schedule.end_time.to_le_bytes(); - pack_bool(schedule.approval_required, approval_required_out); - *min_amount_usd_out = schedule.min_amount_usd.to_le_bytes(); - *max_amount_usd_out = schedule.max_amount_usd.to_le_bytes(); - *fee_out = schedule.fee.to_le_bytes(); - - Ok(FundInstruction::SET_WITHDRAWAL_SCHEDULE_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_disable_withdrawals(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::DISABLE_WITHDRAWALS_LEN)?; - - if let FundInstruction::DisableWithdrawals = self { - let instruction_type_out = array_mut_ref![output, 0, 1]; - - instruction_type_out[0] = FundInstructionType::DisableWithdrawals as u8; - - Ok(FundInstruction::DISABLE_WITHDRAWALS_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_approve_withdrawal(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::APPROVE_WITHDRAWAL_LEN)?; - - if let FundInstruction::ApproveWithdrawal { amount } = self { - let output = array_mut_ref![output, 0, FundInstruction::APPROVE_WITHDRAWAL_LEN]; - let (instruction_type_out, amount_out) = mut_array_refs![output, 1, 8]; - - instruction_type_out[0] = FundInstructionType::ApproveWithdrawal as u8; - - *amount_out = amount.to_le_bytes(); - - Ok(FundInstruction::APPROVE_WITHDRAWAL_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_deny_withdrawal(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::DENY_WITHDRAWAL_LEN)?; - - if let FundInstruction::DenyWithdrawal { deny_reason } = self { - let output = array_mut_ref![output, 0, FundInstruction::DENY_WITHDRAWAL_LEN]; - let (instruction_type_out, deny_reason_out) = mut_array_refs![output, 1, 64]; - - instruction_type_out[0] = FundInstructionType::DenyWithdrawal as u8; - - pack_array_string64(deny_reason, deny_reason_out); - - Ok(FundInstruction::DENY_WITHDRAWAL_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_accept_funds(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::LOCK_ASSETS_LEN)?; - - if let FundInstruction::LockAssets { amount } = self { - let output = array_mut_ref![output, 0, FundInstruction::LOCK_ASSETS_LEN]; - let (instruction_type_out, amount_out) = mut_array_refs![output, 1, 8]; - - instruction_type_out[0] = FundInstructionType::LockAssets as u8; - - *amount_out = amount.to_le_bytes(); - - Ok(FundInstruction::LOCK_ASSETS_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_release_funds(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::UNLOCK_ASSETS_LEN)?; - - if let FundInstruction::UnlockAssets { amount } = self { - let output = array_mut_ref![output, 0, FundInstruction::UNLOCK_ASSETS_LEN]; - let (instruction_type_out, amount_out) = mut_array_refs![output, 1, 8]; - - instruction_type_out[0] = FundInstructionType::UnlockAssets as u8; - - *amount_out = amount.to_le_bytes(); - - Ok(FundInstruction::UNLOCK_ASSETS_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_set_admin_signers(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::SET_ADMIN_SIGNERS_LEN)?; - - if let FundInstruction::SetAdminSigners { min_signatures } = self { - let output = array_mut_ref![output, 0, FundInstruction::SET_ADMIN_SIGNERS_LEN]; - let (instruction_type_out, min_signatures_out) = mut_array_refs![output, 1, 1]; - - instruction_type_out[0] = FundInstructionType::SetAdminSigners as u8; - min_signatures_out[0] = *min_signatures; - - Ok(FundInstruction::SET_ADMIN_SIGNERS_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_remove_multisig(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::REMOVE_MULTISIG_LEN)?; - - if let FundInstruction::RemoveMultisig = self { - let instruction_type_out = array_mut_ref![output, 0, 1]; - - instruction_type_out[0] = FundInstructionType::RemoveMultisig as u8; - - Ok(FundInstruction::REMOVE_MULTISIG_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_set_assets_tracking_config(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::SET_ASSETS_TRACKING_CONFIG_LEN)?; - - if let FundInstruction::SetAssetsTrackingConfig { config } = self { - let output = array_mut_ref![output, 0, FundInstruction::SET_ASSETS_TRACKING_CONFIG_LEN]; - let ( - instruction_type_out, - assets_limit_usd_out, - max_update_age_sec_out, - max_price_error_out, - max_price_age_sec_out, - issue_virtual_tokens_out, - ) = mut_array_refs![output, 1, 8, 8, 8, 8, 1]; - - instruction_type_out[0] = FundInstructionType::SetAssetsTrackingConfig as u8; - - *assets_limit_usd_out = config.assets_limit_usd.to_le_bytes(); - *max_update_age_sec_out = config.max_update_age_sec.to_le_bytes(); - *max_price_error_out = config.max_price_error.to_le_bytes(); - *max_price_age_sec_out = config.max_price_age_sec.to_le_bytes(); - issue_virtual_tokens_out[0] = config.issue_virtual_tokens as u8; - - Ok(FundInstruction::SET_ASSETS_TRACKING_CONFIG_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_update_assets_with_vault(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::UPDATE_ASSETS_WITH_VAULT_LEN)?; - - if let FundInstruction::UpdateAssetsWithVault = self { - let instruction_type_out = array_mut_ref![output, 0, 1]; - - instruction_type_out[0] = FundInstructionType::UpdateAssetsWithVault as u8; - - Ok(FundInstruction::UPDATE_ASSETS_WITH_VAULT_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_update_assets_with_custody(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::UPDATE_ASSETS_WITH_CUSTODY_LEN)?; - - if let FundInstruction::UpdateAssetsWithCustody = self { - let instruction_type_out = array_mut_ref![output, 0, 1]; - - instruction_type_out[0] = FundInstructionType::UpdateAssetsWithCustody as u8; - - Ok(FundInstruction::UPDATE_ASSETS_WITH_CUSTODY_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_add_vault(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::ADD_VAULT_LEN)?; - - if let FundInstruction::AddVault { - target_hash, - vault_id, - vault_type, - } = self - { - let output = array_mut_ref![output, 0, FundInstruction::ADD_VAULT_LEN]; - let (instruction_type_out, target_hash_out, vault_id_out, vault_type_out) = - mut_array_refs![output, 1, 8, 4, 1]; - - instruction_type_out[0] = FundInstructionType::AddVault as u8; - - *target_hash_out = target_hash.to_le_bytes(); - *vault_id_out = vault_id.to_le_bytes(); - vault_type_out[0] = *vault_type as u8; - - Ok(FundInstruction::ADD_VAULT_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_remove_vault(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::REMOVE_VAULT_LEN)?; - - if let FundInstruction::RemoveVault { - target_hash, - vault_type, - } = self - { - let output = array_mut_ref![output, 0, FundInstruction::REMOVE_VAULT_LEN]; - let (instruction_type_out, target_hash_out, vault_type_out) = - mut_array_refs![output, 1, 8, 1]; - - instruction_type_out[0] = FundInstructionType::RemoveVault as u8; - - *target_hash_out = target_hash.to_le_bytes(); - vault_type_out[0] = *vault_type as u8; - - Ok(FundInstruction::REMOVE_VAULT_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_add_custody(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::ADD_CUSTODY_LEN)?; - - if let FundInstruction::AddCustody { - target_hash, - custody_id, - custody_type, - } = self - { - let output = array_mut_ref![output, 0, FundInstruction::ADD_CUSTODY_LEN]; - let (instruction_type_out, target_hash_out, custody_id_out, custody_type_out) = - mut_array_refs![output, 1, 8, 4, 1]; - - instruction_type_out[0] = FundInstructionType::AddCustody as u8; - - *target_hash_out = target_hash.to_le_bytes(); - *custody_id_out = custody_id.to_le_bytes(); - custody_type_out[0] = *custody_type as u8; - - Ok(FundInstruction::ADD_CUSTODY_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_remove_custody(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::REMOVE_CUSTODY_LEN)?; - - if let FundInstruction::RemoveCustody { - target_hash, - custody_type, - } = self - { - let output = array_mut_ref![output, 0, FundInstruction::REMOVE_CUSTODY_LEN]; - let (instruction_type_out, target_hash_out, custody_type_out) = - mut_array_refs![output, 1, 8, 1]; - - instruction_type_out[0] = FundInstructionType::RemoveCustody as u8; - - *target_hash_out = target_hash.to_le_bytes(); - custody_type_out[0] = *custody_type as u8; - - Ok(FundInstruction::REMOVE_CUSTODY_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_start_liquidation(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::START_LIQUIDATION_LEN)?; - - if let FundInstruction::StartLiquidation = self { - let instruction_type_out = array_mut_ref![output, 0, 1]; - - instruction_type_out[0] = FundInstructionType::StartLiquidation as u8; - - Ok(FundInstruction::START_LIQUIDATION_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_stop_liquidation(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::STOP_LIQUIDATION_LEN)?; - - if let FundInstruction::StopLiquidation = self { - let instruction_type_out = array_mut_ref![output, 0, 1]; - - instruction_type_out[0] = FundInstructionType::StopLiquidation as u8; - - Ok(FundInstruction::STOP_LIQUIDATION_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_withdraw_fees(&self, output: &mut [u8]) -> Result { - check_data_len(output, FundInstruction::WITHDRAW_FEES_LEN)?; - - if let FundInstruction::WithdrawFees { amount } = self { - let output = array_mut_ref![output, 0, FundInstruction::WITHDRAW_FEES_LEN]; - let (instruction_type_out, amount_out) = mut_array_refs![output, 1, 8]; - - instruction_type_out[0] = FundInstructionType::WithdrawFees as u8; - - *amount_out = amount.to_le_bytes(); - - Ok(FundInstruction::WITHDRAW_FEES_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_amm_instruction_raydium(&self, output: &mut [u8]) -> Result { - if let FundInstruction::AmmInstructionRaydium { instruction } = self { - check_data_len(output, 1)?; - - let instruction_type_out = array_mut_ref![output, 0, 1]; - instruction_type_out[0] = FundInstructionType::AmmInstructionRaydium as u8; - - Ok(instruction.pack(&mut output[1..])? + 1) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_vault_instruction_raydium(&self, output: &mut [u8]) -> Result { - if let FundInstruction::VaultInstructionRaydium { instruction } = self { - check_data_len(output, 1)?; - - let instruction_type_out = array_mut_ref![output, 0, 1]; - instruction_type_out[0] = FundInstructionType::VaultInstructionRaydium as u8; - - Ok(instruction.pack(&mut output[1..])? + 1) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_amm_instruction_orca(&self, output: &mut [u8]) -> Result { - if let FundInstruction::AmmInstructionOrca { instruction } = self { - check_data_len(output, 1)?; - - let instruction_type_out = array_mut_ref![output, 0, 1]; - instruction_type_out[0] = FundInstructionType::AmmInstructionOrca as u8; - - Ok(instruction.pack(&mut output[1..])? + 1) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_vault_instruction_orca(&self, output: &mut [u8]) -> Result { - if let FundInstruction::VaultInstructionOrca { instruction } = self { - check_data_len(output, 1)?; - - let instruction_type_out = array_mut_ref![output, 0, 1]; - instruction_type_out[0] = FundInstructionType::VaultInstructionOrca as u8; - - Ok(instruction.pack(&mut output[1..])? + 1) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn unpack_user_init(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::USER_INIT_LEN)?; - Ok(Self::UserInit) - } - - fn unpack_request_deposit(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::REQUEST_DEPOSIT_LEN)?; - Ok(Self::RequestDeposit { - amount: u64::from_le_bytes(*array_ref![input, 1, 8]), - }) - } - - fn unpack_cancel_deposit(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::CANCEL_DEPOSIT_LEN)?; - Ok(Self::CancelDeposit) - } - - fn unpack_request_withdrawal(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::REQUEST_WITHDRAWAL_LEN)?; - Ok(Self::RequestWithdrawal { - amount: u64::from_le_bytes(*array_ref![input, 1, 8]), - }) - } - - fn unpack_cancel_withdrawal(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::CANCEL_WITHDRAWAL_LEN)?; - Ok(Self::CancelWithdrawal) - } - - fn unpack_init(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::INIT_LEN)?; - Ok(Self::Init { - step: u64::from_le_bytes(*array_ref![input, 1, 8]), - }) - } - - fn unpack_set_deposit_schedule(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::SET_DEPOSIT_SCHEDULE_LEN)?; - - let input = array_ref![input, 1, FundInstruction::SET_DEPOSIT_SCHEDULE_LEN - 1]; - #[allow(clippy::ptr_offset_with_cast)] - let (start_time, end_time, approval_required, min_amount_usd, max_amount_usd, fee) = - array_refs![input, 8, 8, 1, 8, 8, 8]; - - Ok(Self::SetDepositSchedule { - schedule: FundSchedule { - start_time: i64::from_le_bytes(*start_time), - end_time: i64::from_le_bytes(*end_time), - approval_required: unpack_bool(approval_required)?, - min_amount_usd: f64::from_le_bytes(*min_amount_usd), - max_amount_usd: f64::from_le_bytes(*max_amount_usd), - fee: f64::from_le_bytes(*fee), - }, - }) - } - - fn unpack_disable_deposits(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::DISABLE_DEPOSITS_LEN)?; - Ok(Self::DisableDeposits) - } - - fn unpack_approve_deposit(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::APPROVE_DEPOSIT_LEN)?; - Ok(Self::ApproveDeposit { - amount: u64::from_le_bytes(*array_ref![input, 1, 8]), - }) - } - - fn unpack_deny_deposit(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::DENY_DEPOSIT_LEN)?; - Ok(Self::DenyDeposit { - deny_reason: unpack_array_string64(array_ref![input, 1, 64])?, - }) - } - - fn unpack_set_withdrawal_schedule(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::SET_WITHDRAWAL_SCHEDULE_LEN)?; - - let input = array_ref![input, 1, FundInstruction::SET_WITHDRAWAL_SCHEDULE_LEN - 1]; - #[allow(clippy::ptr_offset_with_cast)] - let (start_time, end_time, approval_required, min_amount_usd, max_amount_usd, fee) = - array_refs![input, 8, 8, 1, 8, 8, 8]; - - Ok(Self::SetWithdrawalSchedule { - schedule: FundSchedule { - start_time: i64::from_le_bytes(*start_time), - end_time: i64::from_le_bytes(*end_time), - approval_required: unpack_bool(approval_required)?, - min_amount_usd: f64::from_le_bytes(*min_amount_usd), - max_amount_usd: f64::from_le_bytes(*max_amount_usd), - fee: f64::from_le_bytes(*fee), - }, - }) - } - - fn unpack_disable_withdrawals(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::DISABLE_WITHDRAWALS_LEN)?; - Ok(Self::DisableWithdrawals) - } - - fn unpack_approve_withdrawal(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::APPROVE_WITHDRAWAL_LEN)?; - Ok(Self::ApproveWithdrawal { - amount: u64::from_le_bytes(*array_ref![input, 1, 8]), - }) - } - - fn unpack_deny_withdrawal(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::DENY_WITHDRAWAL_LEN)?; - Ok(Self::DenyWithdrawal { - deny_reason: unpack_array_string64(array_ref![input, 1, 64])?, - }) - } - - fn unpack_accept_funds(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::LOCK_ASSETS_LEN)?; - Ok(Self::LockAssets { - amount: u64::from_le_bytes(*array_ref![input, 1, 8]), - }) - } - - fn unpack_release_funds(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::UNLOCK_ASSETS_LEN)?; - Ok(Self::UnlockAssets { - amount: u64::from_le_bytes(*array_ref![input, 1, 8]), - }) - } - - fn unpack_set_admin_signers(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::SET_ADMIN_SIGNERS_LEN)?; - - let input = array_ref![input, 1, FundInstruction::SET_ADMIN_SIGNERS_LEN - 1]; - - Ok(Self::SetAdminSigners { - min_signatures: input[0], - }) - } - - fn unpack_remove_multisig(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::REMOVE_MULTISIG_LEN)?; - Ok(Self::RemoveMultisig) - } - - fn unpack_set_assets_tracking_config(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::SET_ASSETS_TRACKING_CONFIG_LEN)?; - - let input = array_ref![ - input, - 1, - FundInstruction::SET_ASSETS_TRACKING_CONFIG_LEN - 1 - ]; - #[allow(clippy::ptr_offset_with_cast)] - let ( - assets_limit_usd, - max_update_age_sec, - max_price_error, - max_price_age_sec, - issue_virtual_tokens, - ) = array_refs![input, 8, 8, 8, 8, 1]; - - Ok(Self::SetAssetsTrackingConfig { - config: FundAssetsTrackingConfig { - assets_limit_usd: f64::from_le_bytes(*assets_limit_usd), - max_update_age_sec: u64::from_le_bytes(*max_update_age_sec), - max_price_error: f64::from_le_bytes(*max_price_error), - max_price_age_sec: u64::from_le_bytes(*max_price_age_sec), - issue_virtual_tokens: unpack_bool(issue_virtual_tokens)?, - }, - }) - } - - fn unpack_update_assets_with_vault(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::UPDATE_ASSETS_WITH_VAULT_LEN)?; - Ok(Self::UpdateAssetsWithVault) - } - - fn unpack_update_assets_with_custody(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::UPDATE_ASSETS_WITH_CUSTODY_LEN)?; - Ok(Self::UpdateAssetsWithCustody) - } - - fn unpack_add_vault(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::ADD_VAULT_LEN)?; - - let input = array_ref![input, 1, FundInstruction::ADD_VAULT_LEN - 1]; - #[allow(clippy::ptr_offset_with_cast)] - let (target_hash, vault_id, vault_type) = array_refs![input, 8, 4, 1]; - - Ok(Self::AddVault { - target_hash: u64::from_le_bytes(*target_hash), - vault_id: u32::from_le_bytes(*vault_id), - vault_type: FundVaultType::try_from_primitive(vault_type[0]) - .or(Err(ProgramError::InvalidInstructionData))?, - }) - } - - fn unpack_remove_vault(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::REMOVE_VAULT_LEN)?; - - let input = array_ref![input, 1, FundInstruction::REMOVE_VAULT_LEN - 1]; - #[allow(clippy::ptr_offset_with_cast)] - let (target_hash, vault_type) = array_refs![input, 8, 1]; - - Ok(Self::RemoveVault { - target_hash: u64::from_le_bytes(*target_hash), - vault_type: FundVaultType::try_from_primitive(vault_type[0]) - .or(Err(ProgramError::InvalidInstructionData))?, - }) - } - - fn unpack_add_custody(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::ADD_CUSTODY_LEN)?; - - let input = array_ref![input, 1, FundInstruction::ADD_CUSTODY_LEN - 1]; - #[allow(clippy::ptr_offset_with_cast)] - let (target_hash, custody_id, custody_type) = array_refs![input, 8, 4, 1]; - - Ok(Self::AddCustody { - target_hash: u64::from_le_bytes(*target_hash), - custody_id: u32::from_le_bytes(*custody_id), - custody_type: FundCustodyType::try_from_primitive(custody_type[0]) - .or(Err(ProgramError::InvalidInstructionData))?, - }) - } - - fn unpack_remove_custody(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::REMOVE_CUSTODY_LEN)?; - - let input = array_ref![input, 1, FundInstruction::REMOVE_CUSTODY_LEN - 1]; - #[allow(clippy::ptr_offset_with_cast)] - let (target_hash, custody_type) = array_refs![input, 8, 1]; - - Ok(Self::RemoveCustody { - target_hash: u64::from_le_bytes(*target_hash), - custody_type: FundCustodyType::try_from_primitive(custody_type[0]) - .or(Err(ProgramError::InvalidInstructionData))?, - }) - } - - fn unpack_start_liquidation(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::START_LIQUIDATION_LEN)?; - Ok(Self::StartLiquidation) - } - - fn unpack_stop_liquidation(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::STOP_LIQUIDATION_LEN)?; - Ok(Self::StopLiquidation) - } - - fn unpack_withdraw_fees(input: &[u8]) -> Result { - check_data_len(input, FundInstruction::WITHDRAW_FEES_LEN)?; - Ok(Self::WithdrawFees { - amount: u64::from_le_bytes(*array_ref![input, 1, 8]), - }) - } - - fn unpack_amm_instruction_raydium(input: &[u8]) -> Result { - Ok(Self::AmmInstructionRaydium { - instruction: AmmInstruction::unpack(&input[1..])?, - }) - } - - fn unpack_vault_instruction_raydium(input: &[u8]) -> Result { - Ok(Self::VaultInstructionRaydium { - instruction: VaultInstruction::unpack(&input[1..])?, - }) - } - - fn unpack_amm_instruction_orca(input: &[u8]) -> Result { - Ok(Self::AmmInstructionOrca { - instruction: AmmInstruction::unpack(&input[1..])?, - }) - } - - fn unpack_vault_instruction_orca(input: &[u8]) -> Result { - Ok(Self::VaultInstructionOrca { - instruction: VaultInstruction::unpack(&input[1..])?, - }) - } -} - -impl std::fmt::Display for FundInstructionType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match *self { - FundInstructionType::UserInit => write!(f, "UserInit"), - FundInstructionType::RequestDeposit => write!(f, "RequestDeposit"), - FundInstructionType::CancelDeposit => write!(f, "CancelDeposit"), - FundInstructionType::RequestWithdrawal => write!(f, "RequestWithdrawal"), - FundInstructionType::CancelWithdrawal => write!(f, "CancelWithdrawal"), - FundInstructionType::Init => write!(f, "Init"), - FundInstructionType::SetDepositSchedule => write!(f, "SetDepositSchedule"), - FundInstructionType::DisableDeposits => write!(f, "DisableDeposits"), - FundInstructionType::ApproveDeposit => write!(f, "ApproveDeposit"), - FundInstructionType::DenyDeposit => write!(f, "DenyDeposit"), - FundInstructionType::SetWithdrawalSchedule => write!(f, "SetWithdrawalSchedule"), - FundInstructionType::DisableWithdrawals => write!(f, "DisableWithdrawals"), - FundInstructionType::ApproveWithdrawal => write!(f, "ApproveWithdrawal"), - FundInstructionType::DenyWithdrawal => write!(f, "DenyWithdrawal"), - FundInstructionType::LockAssets => write!(f, "LockAssets"), - FundInstructionType::UnlockAssets => write!(f, "UnlockAssets"), - FundInstructionType::SetAdminSigners => write!(f, "SetAdminSigners"), - FundInstructionType::RemoveMultisig => write!(f, "RemoveMultisig"), - FundInstructionType::SetAssetsTrackingConfig => write!(f, "SetAssetsTrackingConfig"), - FundInstructionType::UpdateAssetsWithVault => write!(f, "UpdateAssetsWithVault"), - FundInstructionType::UpdateAssetsWithCustody => write!(f, "UpdateAssetsWithCustody"), - FundInstructionType::AddVault => write!(f, "AddVault"), - FundInstructionType::RemoveVault => write!(f, "RemoveVault"), - FundInstructionType::AddCustody => write!(f, "AddCustody"), - FundInstructionType::RemoveCustody => write!(f, "RemoveCustody"), - FundInstructionType::StartLiquidation => write!(f, "StartLiquidation"), - FundInstructionType::StopLiquidation => write!(f, "StopLiquidation"), - FundInstructionType::WithdrawFees => write!(f, "WithdrawFees"), - FundInstructionType::AmmInstructionRaydium => write!(f, "AmmInstructionRaydium"), - FundInstructionType::VaultInstructionRaydium => write!(f, "VaultInstructionRaydium"), - FundInstructionType::AmmInstructionOrca => write!(f, "AmmInstructionOrca"), - FundInstructionType::VaultInstructionOrca => write!(f, "VaultInstructionOrca"), - } - } -} diff --git a/farms/farm-sdk/src/instruction/main_router.rs b/farms/farm-sdk/src/instruction/main_router.rs deleted file mode 100644 index b73c452385d..00000000000 --- a/farms/farm-sdk/src/instruction/main_router.rs +++ /dev/null @@ -1,692 +0,0 @@ -//! Main Router instructions. - -use { - crate::{ - farm::Farm, - fund::Fund, - instruction::refdb::RefDbInstruction, - pack::{ - check_data_len, pack_array_string64, pack_option_u32, unpack_array_string64, - unpack_option_u32, - }, - pool::Pool, - string::ArrayString64, - token::Token, - traits::Packed, - vault::Vault, - }, - arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}, - num_enum::TryFromPrimitive, - solana_program::program_error::ProgramError, -}; - -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum MainInstruction { - /// Record Fund's metadata on-chain - /// - /// # Account references - /// 0. [SIGNER] Funding account, must be one of the multisig signers or main router admin if no multisig - /// 1. [WRITE] Multisig PDA address, must be main_router_multisig::id() - /// 2. [WRITE] Fund's RefDB refdb_index PDA - /// 3. [WRITE] Fund's RefDB data PDA - /// 4. [] Sytem program - AddFund { fund: Fund }, - - /// Delete Fund's metadata - /// - /// # Account references - /// 0. [SIGNER] Funding account, must be one of the multisig signers or main router admin if no multisig - /// 1. [WRITE] Multisig PDA address, must be main_router_multisig::id() - /// 2. [WRITE] Fund's RefDB refdb_index PDA - /// 3. [WRITE] Fund's RefDB data PDA - /// 4. [] Sytem program - RemoveFund { - name: ArrayString64, - refdb_index: Option, - }, - - /// Record Vault's metadata on-chain - /// - /// # Account references - /// 0. [SIGNER] Funding account, must be one of the multisig signers or main router admin if no multisig - /// 1. [WRITE] Multisig PDA address, must be main_router_multisig::id() - /// 2. [WRITE] Vault's RefDB refdb_index PDA - /// 3. [WRITE] Vault's RefDB data PDA - /// 4. [] Sytem program - AddVault { vault: Vault }, - - /// Delete Vault's metadata - /// - /// # Account references - /// 0. [SIGNER] Funding account, must be one of the multisig signers or main router admin if no multisig - /// 1. [WRITE] Multisig PDA address, must be main_router_multisig::id() - /// 2. [WRITE] Vault's RefDB refdb_index PDA - /// 3. [WRITE] Vault's RefDB data PDA - /// 4. [] Sytem program - RemoveVault { - name: ArrayString64, - refdb_index: Option, - }, - - /// Record Pool's metadata on-chain - /// - /// # Account references - /// 0. [SIGNER] Funding account, must be one of the multisig signers or main router admin if no multisig - /// 1. [WRITE] Multisig PDA address, must be main_router_multisig::id() - /// 2. [WRITE] Pool's RefDB refdb_index PDA - /// 3. [WRITE] Pool's RefDB data PDA - /// 4. [] Sytem program - AddPool { pool: Pool }, - - /// Delete Pool's metadata - /// - /// # Account references - /// 0. [SIGNER] Funding account, must be one of the multisig signers or main router admin if no multisig - /// 1. [WRITE] Multisig PDA address, must be main_router_multisig::id() - /// 2. [WRITE] Pool's RefDB refdb_index PDA - /// 3. [WRITE] Pool's RefDB data PDA - /// 4. [] Sytem program - RemovePool { - name: ArrayString64, - refdb_index: Option, - }, - - /// Record Farm's metadata on-chain - /// - /// # Account references - /// 0. [SIGNER] Funding account, must be one of the multisig signers or main router admin if no multisig - /// 1. [WRITE] Multisig PDA address, must be main_router_multisig::id() - /// 2. [WRITE] Farm's RefDB refdb_index PDA - /// 3. [WRITE] Farm's RefDB data PDA - /// 4. [] Sytem program - AddFarm { farm: Farm }, - - /// Delete Farm's metadata - /// - /// # Account references - /// 0. [SIGNER] Funding account, must be one of the multisig signers or main router admin if no multisig - /// 1. [WRITE] Multisig PDA address, must be main_router_multisig::id() - /// 2. [WRITE] Farm's RefDB refdb_index PDA - /// 3. [WRITE] Farm's RefDB data PDA - /// 4. [] Sytem program - RemoveFarm { - name: ArrayString64, - refdb_index: Option, - }, - - /// Record Token's metadata on-chain - /// - /// # Account references - /// 0. [SIGNER] Funding account, must be one of the multisig signers or main router admin if no multisig - /// 1. [WRITE] Multisig PDA address, must be main_router_multisig::id() - /// 2. [WRITE] Token's RefDB refdb_index PDA - /// 3. [WRITE] Token's RefDB data PDA - /// 4. [] Sytem program - AddToken { token: Token }, - - /// Delete Token's metadata - /// - /// # Account references - /// 0. [SIGNER] Funding account, must be one of the multisig signers or main router admin if no multisig - /// 1. [WRITE] Multisig PDA address, must be main_router_multisig::id() - /// 2. [WRITE] Token's RefDB refdb_index PDA - /// 3. [WRITE] Token's RefDB data PDA - /// 4. [] Sytem program - RemoveToken { - name: ArrayString64, - refdb_index: Option, - }, - - /// Perform generic RefDB instruction - /// - /// # Account references are instruction specific, - /// see RefDbInstruction definition for more info - RefDbInstruction { instruction: RefDbInstruction }, - - /// Initialize Main Router multisig with a new set of admin signatures - /// - /// # Account references - /// 0. [SIGNER] Funding account, must be one of the multisig signers or main router admin if no multisig - /// 1. [WRITE] Multisig PDA address, must be main_router_multisig::id() - /// 2. [] Sytem program - /// 3. [] First signer - /// ... [] Extra signers, up to Multisig::MAX_SIGNERS - SetAdminSigners { min_signatures: u8 }, - - /// Initialize program upgrade authority multisig with a new set of admin signatures - /// - /// # Account references - /// 0. [SIGNER] Funding account, must be one of the multisig signers or upgrade authority if no multisig - /// 1. [WRITE] Multisig PDA address, must be get_program_multisig_account() - /// 2. [] Program address - /// 3. [WRITE] Program data buffer address - /// 4. [] Sytem program - /// 5. [] BPF Loader program - /// 6. [] First signer - /// ... [] Extra signers, up to Multisig::MAX_SIGNERS - SetProgramAdminSigners { min_signatures: u8 }, - - /// Set single upgrade authority for the program removing multisig if present - /// - /// # Account references - /// 0. [SIGNER] Funding account, must be one of the multisig signers or upgrade authority if no multisig - /// 1. [WRITE] Multisig PDA address, must be get_program_multisig_account() - /// 2. [] Program address - /// 3. [WRITE] Program data buffer address - /// 4. [] New upgrade authority - /// 5. [] BPF Loader program - SetProgramSingleAuthority, - - /// Upgrade the program from the buffer - /// - /// # Account references - /// 0. [SIGNER] Funding account, must be one of the multisig signers or upgrade authority if no multisig - /// 1. [WRITE] Multisig PDA address, must be get_program_multisig_account() - /// 2. [WRITE] Program address - /// 3. [WRITE] Program data buffer address - /// 4. [WRITE] Source data buffer address - /// 5. [] Rent sysvar - /// 6. [] Clock sysvar - /// 7. [] BPF Loader program - UpgradeProgram, -} - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)] -pub enum MainInstructionType { - AddFund, - RemoveFund, - AddVault, - RemoveVault, - AddPool, - RemovePool, - AddFarm, - RemoveFarm, - AddToken, - RemoveToken, - RefDbInstruction, - SetAdminSigners, - SetProgramAdminSigners, - SetProgramSingleAuthority, - UpgradeProgram, -} - -impl MainInstruction { - pub const MAX_LEN: usize = MainInstruction::max(Vault::MAX_LEN + 1, Pool::MAX_LEN + 1); - pub const REMOVE_FUND_LEN: usize = 70; - pub const REMOVE_VAULT_LEN: usize = 70; - pub const REMOVE_POOL_LEN: usize = 70; - pub const REMOVE_FARM_LEN: usize = 70; - pub const REMOVE_TOKEN_LEN: usize = 70; - pub const SET_ADMIN_SIGNERS_LEN: usize = 2; - pub const SET_PROGRAM_ADMIN_SIGNERS_LEN: usize = 2; - pub const SET_PROGRAM_SINGLE_AUTHORITY_LEN: usize = 1; - pub const UPGRADE_PROGRAM_LEN: usize = 1; - - const fn max(a: usize, b: usize) -> usize { - [a, b][(a < b) as usize] - } - - pub fn pack(&self, output: &mut [u8]) -> Result { - check_data_len(output, 1)?; - match self { - Self::AddFund { fund } => self.pack_add_fund(output, fund), - Self::RemoveFund { name, refdb_index } => { - self.pack_remove_fund(output, name, refdb_index) - } - Self::AddVault { vault } => self.pack_add_vault(output, vault), - Self::RemoveVault { name, refdb_index } => { - self.pack_remove_vault(output, name, refdb_index) - } - Self::AddPool { pool } => self.pack_add_pool(output, pool), - Self::RemovePool { name, refdb_index } => { - self.pack_remove_pool(output, name, refdb_index) - } - Self::AddFarm { farm } => self.pack_add_farm(output, farm), - Self::RemoveFarm { name, refdb_index } => { - self.pack_remove_farm(output, name, refdb_index) - } - Self::AddToken { token } => self.pack_add_token(output, token), - Self::RemoveToken { name, refdb_index } => { - self.pack_remove_token(output, name, refdb_index) - } - Self::RefDbInstruction { instruction } => { - self.pack_refdb_instruction(output, instruction) - } - Self::SetAdminSigners { min_signatures } => { - self.pack_set_admin_signers(output, *min_signatures) - } - Self::SetProgramAdminSigners { min_signatures } => { - self.pack_set_program_admin_signers(output, *min_signatures) - } - Self::SetProgramSingleAuthority => self.pack_set_program_single_authority(output), - Self::UpgradeProgram => self.pack_upgrade_program(output), - } - } - - pub fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; MainInstruction::MAX_LEN] = [0; MainInstruction::MAX_LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - pub fn unpack(input: &[u8]) -> Result { - check_data_len(input, 1)?; - let instruction_type = MainInstructionType::try_from_primitive(input[0]) - .or(Err(ProgramError::InvalidInstructionData))?; - match instruction_type { - MainInstructionType::AddFund => MainInstruction::unpack_add_fund(input), - MainInstructionType::RemoveFund => MainInstruction::unpack_remove_fund(input), - MainInstructionType::AddVault => MainInstruction::unpack_add_vault(input), - MainInstructionType::RemoveVault => MainInstruction::unpack_remove_vault(input), - MainInstructionType::AddPool => MainInstruction::unpack_add_pool(input), - MainInstructionType::RemovePool => MainInstruction::unpack_remove_pool(input), - MainInstructionType::AddFarm => MainInstruction::unpack_add_farm(input), - MainInstructionType::RemoveFarm => MainInstruction::unpack_remove_farm(input), - MainInstructionType::AddToken => MainInstruction::unpack_add_token(input), - MainInstructionType::RemoveToken => MainInstruction::unpack_remove_token(input), - MainInstructionType::RefDbInstruction => { - MainInstruction::unpack_refdb_instruction(input) - } - MainInstructionType::SetAdminSigners => { - MainInstruction::unpack_set_admin_signers(input) - } - MainInstructionType::SetProgramAdminSigners => { - MainInstruction::unpack_set_program_admin_signers(input) - } - MainInstructionType::SetProgramSingleAuthority => { - MainInstruction::unpack_set_program_single_authority(input) - } - MainInstructionType::UpgradeProgram => MainInstruction::unpack_upgrade_program(input), - } - } - - fn pack_add_fund(&self, output: &mut [u8], fund: &Fund) -> Result { - let packed = fund.pack(&mut output[1..])?; - let instruction_type_out = array_mut_ref![output, 0, 1]; - instruction_type_out[0] = MainInstructionType::AddFund as u8; - - Ok(packed + 1) - } - - fn pack_remove_fund( - &self, - output: &mut [u8], - name: &ArrayString64, - refdb_index: &Option, - ) -> Result { - check_data_len(output, MainInstruction::REMOVE_FUND_LEN)?; - - let output = array_mut_ref![output, 0, MainInstruction::REMOVE_FUND_LEN]; - let (instruction_type_out, name_out, refdb_index_out) = mut_array_refs![output, 1, 64, 5]; - - instruction_type_out[0] = MainInstructionType::RemoveFund as u8; - pack_array_string64(name, name_out); - pack_option_u32(*refdb_index, refdb_index_out); - - Ok(MainInstruction::REMOVE_FUND_LEN) - } - - fn pack_add_vault(&self, output: &mut [u8], vault: &Vault) -> Result { - let packed = vault.pack(&mut output[1..])?; - let instruction_type_out = array_mut_ref![output, 0, 1]; - instruction_type_out[0] = MainInstructionType::AddVault as u8; - - Ok(packed + 1) - } - - fn pack_remove_vault( - &self, - output: &mut [u8], - name: &ArrayString64, - refdb_index: &Option, - ) -> Result { - check_data_len(output, MainInstruction::REMOVE_VAULT_LEN)?; - - let output = array_mut_ref![output, 0, MainInstruction::REMOVE_VAULT_LEN]; - let (instruction_type_out, name_out, refdb_index_out) = mut_array_refs![output, 1, 64, 5]; - - instruction_type_out[0] = MainInstructionType::RemoveVault as u8; - pack_array_string64(name, name_out); - pack_option_u32(*refdb_index, refdb_index_out); - - Ok(MainInstruction::REMOVE_VAULT_LEN) - } - - fn pack_add_pool(&self, output: &mut [u8], pool: &Pool) -> Result { - let packed = pool.pack(&mut output[1..])?; - let instruction_type_out = array_mut_ref![output, 0, 1]; - instruction_type_out[0] = MainInstructionType::AddPool as u8; - - Ok(packed + 1) - } - - fn pack_remove_pool( - &self, - output: &mut [u8], - name: &ArrayString64, - refdb_index: &Option, - ) -> Result { - check_data_len(output, MainInstruction::REMOVE_POOL_LEN)?; - - let output = array_mut_ref![output, 0, MainInstruction::REMOVE_POOL_LEN]; - let (instruction_type_out, name_out, refdb_index_out) = mut_array_refs![output, 1, 64, 5]; - - instruction_type_out[0] = MainInstructionType::RemovePool as u8; - pack_array_string64(name, name_out); - pack_option_u32(*refdb_index, refdb_index_out); - - Ok(MainInstruction::REMOVE_POOL_LEN) - } - - fn pack_add_farm(&self, output: &mut [u8], farm: &Farm) -> Result { - let packed = farm.pack(&mut output[1..])?; - let instruction_type_out = array_mut_ref![output, 0, 1]; - instruction_type_out[0] = MainInstructionType::AddFarm as u8; - - Ok(packed + 1) - } - - fn pack_remove_farm( - &self, - output: &mut [u8], - name: &ArrayString64, - refdb_index: &Option, - ) -> Result { - check_data_len(output, MainInstruction::REMOVE_FARM_LEN)?; - - let output = array_mut_ref![output, 0, MainInstruction::REMOVE_FARM_LEN]; - let (instruction_type_out, name_out, refdb_index_out) = mut_array_refs![output, 1, 64, 5]; - - instruction_type_out[0] = MainInstructionType::RemoveFarm as u8; - pack_array_string64(name, name_out); - pack_option_u32(*refdb_index, refdb_index_out); - - Ok(MainInstruction::REMOVE_FARM_LEN) - } - - fn pack_add_token(&self, output: &mut [u8], token: &Token) -> Result { - let packed = token.pack(&mut output[1..])?; - let instruction_type_out = array_mut_ref![output, 0, 1]; - instruction_type_out[0] = MainInstructionType::AddToken as u8; - - Ok(packed + 1) - } - - fn pack_remove_token( - &self, - output: &mut [u8], - name: &ArrayString64, - refdb_index: &Option, - ) -> Result { - check_data_len(output, MainInstruction::REMOVE_TOKEN_LEN)?; - - let output = array_mut_ref![output, 0, MainInstruction::REMOVE_TOKEN_LEN]; - let (instruction_type_out, name_out, refdb_index_out) = mut_array_refs![output, 1, 64, 5]; - - instruction_type_out[0] = MainInstructionType::RemoveToken as u8; - pack_array_string64(name, name_out); - pack_option_u32(*refdb_index, refdb_index_out); - - Ok(MainInstruction::REMOVE_TOKEN_LEN) - } - - fn pack_refdb_instruction( - &self, - output: &mut [u8], - instruction: &RefDbInstruction, - ) -> Result { - let packed = instruction.pack(&mut output[1..])?; - let instruction_type_out = array_mut_ref![output, 0, 1]; - instruction_type_out[0] = MainInstructionType::RefDbInstruction as u8; - - Ok(packed + 1) - } - - fn pack_set_admin_signers( - &self, - output: &mut [u8], - min_signatures: u8, - ) -> Result { - check_data_len(output, MainInstruction::SET_ADMIN_SIGNERS_LEN)?; - - let output = array_mut_ref![output, 0, MainInstruction::SET_ADMIN_SIGNERS_LEN]; - let (instruction_type_out, min_signatures_out) = mut_array_refs![output, 1, 1]; - - instruction_type_out[0] = MainInstructionType::SetAdminSigners as u8; - min_signatures_out[0] = min_signatures; - - Ok(MainInstruction::SET_ADMIN_SIGNERS_LEN) - } - - fn pack_set_program_admin_signers( - &self, - output: &mut [u8], - min_signatures: u8, - ) -> Result { - check_data_len(output, MainInstruction::SET_PROGRAM_ADMIN_SIGNERS_LEN)?; - - let output = array_mut_ref![output, 0, MainInstruction::SET_PROGRAM_ADMIN_SIGNERS_LEN]; - let (instruction_type_out, min_signatures_out) = mut_array_refs![output, 1, 1]; - - instruction_type_out[0] = MainInstructionType::SetProgramAdminSigners as u8; - min_signatures_out[0] = min_signatures; - - Ok(MainInstruction::SET_PROGRAM_ADMIN_SIGNERS_LEN) - } - - fn pack_set_program_single_authority(&self, output: &mut [u8]) -> Result { - check_data_len(output, MainInstruction::SET_PROGRAM_SINGLE_AUTHORITY_LEN)?; - output[0] = MainInstructionType::SetProgramSingleAuthority as u8; - - Ok(MainInstruction::SET_PROGRAM_SINGLE_AUTHORITY_LEN) - } - - fn pack_upgrade_program(&self, output: &mut [u8]) -> Result { - check_data_len(output, MainInstruction::UPGRADE_PROGRAM_LEN)?; - output[0] = MainInstructionType::UpgradeProgram as u8; - - Ok(MainInstruction::UPGRADE_PROGRAM_LEN) - } - - fn unpack_add_fund(input: &[u8]) -> Result { - let fund = Fund::unpack(&input[1..])?; - Ok(Self::AddFund { fund }) - } - - fn unpack_remove_fund(input: &[u8]) -> Result { - check_data_len(input, MainInstruction::REMOVE_FUND_LEN)?; - - let input = array_ref![input, 1, MainInstruction::REMOVE_FUND_LEN - 1]; - #[allow(clippy::ptr_offset_with_cast)] - let (name, refdb_index) = array_refs![input, 64, 5]; - - Ok(Self::RemoveFund { - name: unpack_array_string64(name)?, - refdb_index: unpack_option_u32(refdb_index)?, - }) - } - - fn unpack_add_vault(input: &[u8]) -> Result { - let vault = Vault::unpack(&input[1..])?; - Ok(Self::AddVault { vault }) - } - - fn unpack_remove_vault(input: &[u8]) -> Result { - check_data_len(input, MainInstruction::REMOVE_VAULT_LEN)?; - - let input = array_ref![input, 1, MainInstruction::REMOVE_VAULT_LEN - 1]; - #[allow(clippy::ptr_offset_with_cast)] - let (name, refdb_index) = array_refs![input, 64, 5]; - - Ok(Self::RemoveVault { - name: unpack_array_string64(name)?, - refdb_index: unpack_option_u32(refdb_index)?, - }) - } - - fn unpack_add_pool(input: &[u8]) -> Result { - let pool = Pool::unpack(&input[1..])?; - Ok(Self::AddPool { pool }) - } - - fn unpack_remove_pool(input: &[u8]) -> Result { - check_data_len(input, MainInstruction::REMOVE_POOL_LEN)?; - - let input = array_ref![input, 1, MainInstruction::REMOVE_POOL_LEN - 1]; - #[allow(clippy::ptr_offset_with_cast)] - let (name, refdb_index) = array_refs![input, 64, 5]; - - Ok(Self::RemovePool { - name: unpack_array_string64(name)?, - refdb_index: unpack_option_u32(refdb_index)?, - }) - } - - fn unpack_add_farm(input: &[u8]) -> Result { - let farm = Farm::unpack(&input[1..])?; - Ok(Self::AddFarm { farm }) - } - - fn unpack_remove_farm(input: &[u8]) -> Result { - check_data_len(input, MainInstruction::REMOVE_FARM_LEN)?; - - let input = array_ref![input, 1, MainInstruction::REMOVE_FARM_LEN - 1]; - #[allow(clippy::ptr_offset_with_cast)] - let (name, refdb_index) = array_refs![input, 64, 5]; - - Ok(Self::RemoveFarm { - name: unpack_array_string64(name)?, - refdb_index: unpack_option_u32(refdb_index)?, - }) - } - - fn unpack_add_token(input: &[u8]) -> Result { - let token = Token::unpack(&input[1..])?; - Ok(Self::AddToken { token }) - } - - fn unpack_remove_token(input: &[u8]) -> Result { - check_data_len(input, MainInstruction::REMOVE_TOKEN_LEN)?; - - let input = array_ref![input, 1, MainInstruction::REMOVE_TOKEN_LEN - 1]; - #[allow(clippy::ptr_offset_with_cast)] - let (name, refdb_index) = array_refs![input, 64, 5]; - - Ok(Self::RemoveToken { - name: unpack_array_string64(name)?, - refdb_index: unpack_option_u32(refdb_index)?, - }) - } - - fn unpack_refdb_instruction(input: &[u8]) -> Result { - let instruction = RefDbInstruction::unpack(&input[1..])?; - Ok(Self::RefDbInstruction { instruction }) - } - - fn unpack_set_admin_signers(input: &[u8]) -> Result { - check_data_len(input, MainInstruction::SET_ADMIN_SIGNERS_LEN)?; - - let input = array_ref![input, 1, MainInstruction::SET_ADMIN_SIGNERS_LEN - 1]; - - Ok(Self::SetAdminSigners { - min_signatures: input[0], - }) - } - - fn unpack_set_program_admin_signers(input: &[u8]) -> Result { - check_data_len(input, MainInstruction::SET_PROGRAM_ADMIN_SIGNERS_LEN)?; - - let input = array_ref![input, 1, MainInstruction::SET_PROGRAM_ADMIN_SIGNERS_LEN - 1]; - - Ok(Self::SetProgramAdminSigners { - min_signatures: input[0], - }) - } - - fn unpack_set_program_single_authority(_input: &[u8]) -> Result { - Ok(Self::SetProgramSingleAuthority) - } - - fn unpack_upgrade_program(_input: &[u8]) -> Result { - Ok(Self::UpgradeProgram) - } -} - -impl std::fmt::Display for MainInstructionType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match *self { - MainInstructionType::AddFund => write!(f, "AddFund"), - MainInstructionType::RemoveFund => write!(f, "RemoveFund"), - MainInstructionType::AddVault => write!(f, "AddVault"), - MainInstructionType::RemoveVault => write!(f, "RemoveVault"), - MainInstructionType::AddPool => write!(f, "AddPool"), - MainInstructionType::RemovePool => write!(f, "RemovePool"), - MainInstructionType::AddFarm => write!(f, "AddFarm"), - MainInstructionType::RemoveFarm => write!(f, "RemoveFarm"), - MainInstructionType::AddToken => write!(f, "AddToken"), - MainInstructionType::RemoveToken => write!(f, "RemoveToken"), - MainInstructionType::RefDbInstruction => write!(f, "RefDbInstruction"), - MainInstructionType::SetAdminSigners => write!(f, "SetAdminSigners"), - MainInstructionType::SetProgramAdminSigners => write!(f, "SetProgramAdminSigners"), - MainInstructionType::SetProgramSingleAuthority => { - write!(f, "SetProgramSingleAuthority") - } - MainInstructionType::UpgradeProgram => write!(f, "UpgradeProgram"), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::pool::{PoolRoute, PoolType}; - use crate::string::ArrayString64; - use solana_program::pubkey::Pubkey; - - #[test] - fn test_vec_serialization() { - let ri1 = MainInstruction::AddPool { - pool: Pool { - name: ArrayString64::from_utf8("test").unwrap(), - version: 2, - pool_type: PoolType::Amm, - official: true, - refdb_index: Some(1), - refdb_counter: 2, - token_a_ref: Some(Pubkey::new_unique()), - token_b_ref: Some(Pubkey::new_unique()), - lp_token_ref: Some(Pubkey::new_unique()), - token_a_account: None, - token_b_account: None, - router_program_id: Pubkey::new_unique(), - pool_program_id: Pubkey::new_unique(), - route: PoolRoute::Raydium { - amm_id: Pubkey::new_unique(), - amm_authority: Pubkey::new_unique(), - amm_open_orders: Pubkey::new_unique(), - amm_target: Pubkey::new_unique(), - pool_withdraw_queue: Pubkey::new_unique(), - pool_temp_lp_token_account: Pubkey::new_unique(), - serum_program_id: Pubkey::new_unique(), - serum_market: Pubkey::new_unique(), - serum_coin_vault_account: Pubkey::new_unique(), - serum_pc_vault_account: Pubkey::new_unique(), - serum_vault_signer: Pubkey::new_unique(), - serum_bids: Some(Pubkey::new_unique()), - serum_asks: Some(Pubkey::new_unique()), - serum_event_queue: Some(Pubkey::new_unique()), - }, - }, - }; - - let vec = ri1.to_vec().unwrap(); - - let ri2 = MainInstruction::unpack(&vec[..]).unwrap(); - - assert_eq!(ri1, ri2); - } -} diff --git a/farms/farm-sdk/src/instruction/mod.rs b/farms/farm-sdk/src/instruction/mod.rs deleted file mode 100644 index 700023bc49f..00000000000 --- a/farms/farm-sdk/src/instruction/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod amm; -pub mod fund; -pub mod main_router; -pub mod orca; -pub mod raydium; -pub mod refdb; -pub mod vault; diff --git a/farms/farm-sdk/src/instruction/orca.rs b/farms/farm-sdk/src/instruction/orca.rs deleted file mode 100644 index c7a0cfc821c..00000000000 --- a/farms/farm-sdk/src/instruction/orca.rs +++ /dev/null @@ -1,149 +0,0 @@ -//! Orca protocol farming instructions -//! See https://github.com/orca-so/aquafarm-sdk/blob/9ed9db0f04cf7406f1f6e9a3e316639f3d24e68c/src/instructions.ts -//! for more details and accounts references - -use { - crate::pack::check_data_len, - arrayref::{array_mut_ref, mut_array_refs}, - solana_program::program_error::ProgramError, -}; - -#[repr(u8)] -#[derive(Clone, Copy, Debug)] -pub enum OrcaInstructionType { - InitGlobalFarm, - InitUserFarm, - ConvertTokens, - RevertTokens, - Harvest, - RemoveRewards, - SetEmissionsPerSecond, -} - -#[derive(Clone, Copy, Debug)] -pub struct OrcaUserInit {} - -#[derive(Clone, Copy, Debug)] -pub struct OrcaStake { - pub amount: u64, -} - -#[derive(Clone, Copy, Debug)] -pub struct OrcaUnstake { - pub amount: u64, -} - -#[derive(Clone, Copy, Debug)] -pub struct OrcaHarvest {} - -impl OrcaUserInit { - pub const LEN: usize = 1; - - pub fn get_size(&self) -> usize { - Self::LEN - } - - pub fn pack(&self, output: &mut [u8]) -> Result { - check_data_len(output, OrcaUserInit::LEN)?; - - let output = array_mut_ref![output, 0, OrcaUserInit::LEN]; - output[0] = OrcaInstructionType::InitUserFarm as u8; - - Ok(Self::LEN) - } - - pub fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; OrcaUserInit::LEN] = [0; OrcaUserInit::LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidInstructionData) - } - } -} - -impl OrcaStake { - pub const LEN: usize = 9; - - pub fn get_size(&self) -> usize { - Self::LEN - } - - pub fn pack(&self, output: &mut [u8]) -> Result { - check_data_len(output, OrcaStake::LEN)?; - - let output = array_mut_ref![output, 0, OrcaStake::LEN]; - - let (instruction_out, amount_out) = mut_array_refs![output, 1, 8]; - - instruction_out[0] = OrcaInstructionType::ConvertTokens as u8; - *amount_out = self.amount.to_le_bytes(); - - Ok(Self::LEN) - } - - pub fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; OrcaStake::LEN] = [0; OrcaStake::LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidInstructionData) - } - } -} - -impl OrcaUnstake { - pub const LEN: usize = 9; - - pub fn get_size(&self) -> usize { - Self::LEN - } - - pub fn pack(&self, output: &mut [u8]) -> Result { - check_data_len(output, OrcaUnstake::LEN)?; - - let output = array_mut_ref![output, 0, OrcaUnstake::LEN]; - - let (instruction_out, amount_out) = mut_array_refs![output, 1, 8]; - - instruction_out[0] = OrcaInstructionType::RevertTokens as u8; - *amount_out = self.amount.to_le_bytes(); - - Ok(Self::LEN) - } - - pub fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; OrcaUnstake::LEN] = [0; OrcaUnstake::LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidInstructionData) - } - } -} - -impl OrcaHarvest { - pub const LEN: usize = 1; - - pub fn get_size(&self) -> usize { - Self::LEN - } - - pub fn pack(&self, output: &mut [u8]) -> Result { - check_data_len(output, OrcaHarvest::LEN)?; - - let output = array_mut_ref![output, 0, OrcaHarvest::LEN]; - output[0] = OrcaInstructionType::Harvest as u8; - - Ok(Self::LEN) - } - - pub fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; OrcaHarvest::LEN] = [0; OrcaHarvest::LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidInstructionData) - } - } -} diff --git a/farms/farm-sdk/src/instruction/raydium.rs b/farms/farm-sdk/src/instruction/raydium.rs deleted file mode 100644 index d90e113243b..00000000000 --- a/farms/farm-sdk/src/instruction/raydium.rs +++ /dev/null @@ -1,227 +0,0 @@ -//! Raydium protocol native instructions -//! See https://github.com/raydium-io/raydium-contract-instructions/blob/master/amm_instruction.rs -//! for more details and accounts references - -use { - crate::pack::check_data_len, - arrayref::{array_mut_ref, mut_array_refs}, - solana_program::program_error::ProgramError, -}; - -#[derive(Clone, Copy, Debug)] -pub struct RaydiumAddLiquidity { - pub instruction: u8, - pub max_coin_token_amount: u64, - pub max_pc_token_amount: u64, - pub base_side: u64, -} - -#[derive(Clone, Copy, Debug)] -pub struct RaydiumRemoveLiquidity { - pub instruction: u8, - pub amount: u64, -} - -#[derive(Clone, Copy, Debug)] -pub struct RaydiumSwap { - pub instruction: u8, - pub amount_in: u64, - pub min_amount_out: u64, -} - -#[derive(Clone, Copy, Debug)] -pub struct RaydiumStake { - pub instruction: u8, - pub amount: u64, -} - -#[derive(Clone, Copy, Debug)] -pub struct RaydiumUnstake { - pub instruction: u8, - pub amount: u64, -} - -#[derive(Clone, Copy, Debug)] -pub struct RaydiumHarvest { - pub instruction: u8, -} - -impl RaydiumAddLiquidity { - pub const LEN: usize = 25; - - pub fn get_size(&self) -> usize { - RaydiumAddLiquidity::LEN - } - - pub fn pack(&self, output: &mut [u8]) -> Result { - check_data_len(output, RaydiumAddLiquidity::LEN)?; - - let output = array_mut_ref![output, 0, RaydiumAddLiquidity::LEN]; - - let (instruction_out, max_coin_token_amount_out, max_pc_token_amount_out, base_side_out) = - mut_array_refs![output, 1, 8, 8, 8]; - - instruction_out[0] = self.instruction as u8; - *max_coin_token_amount_out = self.max_coin_token_amount.to_le_bytes(); - *max_pc_token_amount_out = self.max_pc_token_amount.to_le_bytes(); - *base_side_out = self.base_side.to_le_bytes(); - - Ok(RaydiumAddLiquidity::LEN) - } - - pub fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; RaydiumAddLiquidity::LEN] = [0; RaydiumAddLiquidity::LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidInstructionData) - } - } -} - -impl RaydiumRemoveLiquidity { - pub const LEN: usize = 9; - - pub fn get_size(&self) -> usize { - RaydiumRemoveLiquidity::LEN - } - - pub fn pack(&self, output: &mut [u8]) -> Result { - check_data_len(output, RaydiumRemoveLiquidity::LEN)?; - - let output = array_mut_ref![output, 0, RaydiumRemoveLiquidity::LEN]; - - let (instruction_out, amount_out) = mut_array_refs![output, 1, 8]; - - instruction_out[0] = self.instruction as u8; - *amount_out = self.amount.to_le_bytes(); - - Ok(RaydiumRemoveLiquidity::LEN) - } - - pub fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; RaydiumRemoveLiquidity::LEN] = [0; RaydiumRemoveLiquidity::LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidInstructionData) - } - } -} - -impl RaydiumSwap { - pub const LEN: usize = 17; - - pub fn get_size(&self) -> usize { - RaydiumSwap::LEN - } - - pub fn pack(&self, output: &mut [u8]) -> Result { - check_data_len(output, RaydiumSwap::LEN)?; - - let output = array_mut_ref![output, 0, RaydiumSwap::LEN]; - - let (instruction_out, amount_in_out, min_amount_out_out) = mut_array_refs![output, 1, 8, 8]; - - instruction_out[0] = self.instruction as u8; - *amount_in_out = self.amount_in.to_le_bytes(); - *min_amount_out_out = self.min_amount_out.to_le_bytes(); - - Ok(RaydiumSwap::LEN) - } - - pub fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; RaydiumSwap::LEN] = [0; RaydiumSwap::LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidInstructionData) - } - } -} - -impl RaydiumStake { - pub const LEN: usize = 9; - - pub fn get_size(&self) -> usize { - RaydiumStake::LEN - } - - pub fn pack(&self, output: &mut [u8]) -> Result { - check_data_len(output, RaydiumStake::LEN)?; - - let output = array_mut_ref![output, 0, RaydiumStake::LEN]; - - let (instruction_out, amount_out) = mut_array_refs![output, 1, 8]; - - instruction_out[0] = self.instruction as u8; - *amount_out = self.amount.to_le_bytes(); - - Ok(RaydiumStake::LEN) - } - - pub fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; RaydiumStake::LEN] = [0; RaydiumStake::LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidInstructionData) - } - } -} - -impl RaydiumUnstake { - pub const LEN: usize = 9; - - pub fn get_size(&self) -> usize { - RaydiumUnstake::LEN - } - - pub fn pack(&self, output: &mut [u8]) -> Result { - check_data_len(output, RaydiumUnstake::LEN)?; - - let output = array_mut_ref![output, 0, RaydiumUnstake::LEN]; - - let (instruction_out, amount_out) = mut_array_refs![output, 1, 8]; - - instruction_out[0] = self.instruction as u8; - *amount_out = self.amount.to_le_bytes(); - - Ok(RaydiumUnstake::LEN) - } - - pub fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; RaydiumUnstake::LEN] = [0; RaydiumUnstake::LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidInstructionData) - } - } -} - -impl RaydiumHarvest { - pub const LEN: usize = 1; - - pub fn get_size(&self) -> usize { - RaydiumHarvest::LEN - } - - pub fn pack(&self, output: &mut [u8]) -> Result { - check_data_len(output, RaydiumHarvest::LEN)?; - - let output = array_mut_ref![output, 0, RaydiumHarvest::LEN]; - output[0] = self.instruction as u8; - - Ok(RaydiumHarvest::LEN) - } - - pub fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; RaydiumHarvest::LEN] = [0; RaydiumHarvest::LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidInstructionData) - } - } -} diff --git a/farms/farm-sdk/src/instruction/refdb.rs b/farms/farm-sdk/src/instruction/refdb.rs deleted file mode 100644 index d991dcc5ca0..00000000000 --- a/farms/farm-sdk/src/instruction/refdb.rs +++ /dev/null @@ -1,219 +0,0 @@ -//! RefDB management instructions. - -use { - crate::{ - pack::{ - as64_deserialize, as64_serialize, check_data_len, pack_array_string64, pack_option_u32, - unpack_array_string64, unpack_bool, unpack_option_u32, - }, - refdb::{Record, Reference, ReferenceType}, - string::ArrayString64, - }, - arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}, - num_enum::TryFromPrimitive, - serde::{Deserialize, Serialize}, - solana_program::program_error::ProgramError, -}; - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)] -pub enum RefDbInstruction { - /// Initialize on-chain RefDB storage - /// - /// # Account references - /// 0. [SIGNER] Funding account, must be one of the multisig signers or main router admin if no multisig - /// 1. [WRITE] Multisig PDA address, must be main_router_multisig::id() - /// 2. [WRITE] RefDB storage PDA - /// 3. [] Sytem program - Init { - #[serde( - serialize_with = "as64_serialize", - deserialize_with = "as64_deserialize" - )] - name: ArrayString64, - reference_type: ReferenceType, - max_records: u32, - init_account: bool, - }, - - /// Delete on-chain RefDB storage - /// - /// # Account references - /// 0. [SIGNER] Funding account, must be one of the multisig signers or main router admin if no multisig - /// 1. [WRITE] Multisig PDA address, must be main_router_multisig::id() - /// 2. [WRITE] RefDB storage PDA - /// 3. [] Sytem program - Drop { close_account: bool }, - - /// Write the record into on-chain RefDB storage - /// - /// # Account references - /// 0. [SIGNER] Funding account, must be one of the multisig signers or main router admin if no multisig - /// 1. [WRITE] Multisig PDA address, must be main_router_multisig::id() - /// 2. [WRITE] RefDB storage PDA - /// 3. [] Sytem program - Write { record: Record }, - - /// Delete the record from on-chain RefDB storage - /// - /// # Account references - /// 0. [SIGNER] Funding account, must be one of the multisig signers or main router admin if no multisig - /// 1. [WRITE] Multisig PDA address, must be main_router_multisig::id() - /// 2. [WRITE] RefDB storage PDA - /// 3. [] Sytem program - Delete { record: Record }, -} - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)] -pub enum RefDbInstructionType { - Init, - Drop, - Write, - Delete, -} - -impl RefDbInstruction { - pub const MAX_LEN: usize = Record::MAX_LEN + 7; - pub const INIT_LEN: usize = 71; - pub const DROP_LEN: usize = 3; - pub const WRITE_MAX_LEN: usize = Record::MAX_LEN + 7; - pub const DELETE_MAX_LEN: usize = Record::MAX_LEN + 7; - - pub fn pack(&self, output: &mut [u8]) -> Result { - match self { - Self::Init { - name, - reference_type, - max_records, - init_account, - } => { - check_data_len(output, RefDbInstruction::INIT_LEN)?; - - output[0] = RefDbInstructionType::Init as u8; - output[1] = *reference_type as u8; - - let output = array_mut_ref![output, 2, RefDbInstruction::INIT_LEN - 2]; - - let (name_out, max_records_out, init_account_out) = - mut_array_refs![output, 64, 4, 1]; - pack_array_string64(name, name_out); - *max_records_out = max_records.to_le_bytes(); - init_account_out[0] = *init_account as u8; - - Ok(RefDbInstruction::INIT_LEN) - } - Self::Drop { close_account } => { - check_data_len(output, RefDbInstruction::DROP_LEN)?; - output[0] = RefDbInstructionType::Drop as u8; - output[1] = ReferenceType::Empty as u8; - output[2] = *close_account as u8; - Ok(RefDbInstruction::DROP_LEN) - } - Self::Write { record } => { - check_data_len(output, 7)?; - - let header = array_mut_ref![output, 0, 7]; - let (instruction_out, reference_type_out, index_out) = - mut_array_refs![header, 1, 1, 5]; - - instruction_out[0] = RefDbInstructionType::Write as u8; - reference_type_out[0] = match record.reference { - Reference::Pubkey { .. } => ReferenceType::Pubkey as u8, - Reference::U8 { .. } => ReferenceType::U8 as u8, - Reference::U16 { .. } => ReferenceType::U16 as u8, - Reference::U32 { .. } => ReferenceType::U32 as u8, - Reference::U64 { .. } => ReferenceType::U64 as u8, - Reference::F64 { .. } => ReferenceType::F64 as u8, - Reference::Empty => ReferenceType::Empty as u8, - }; - pack_option_u32(record.index, index_out); - record.pack(&mut output[7..])?; - - Ok(7 + record.get_size()) - } - Self::Delete { record } => { - check_data_len(output, 7)?; - - let header = array_mut_ref![output, 0, 7]; - let (instruction_out, reference_type_out, index_out) = - mut_array_refs![header, 1, 1, 5]; - - instruction_out[0] = RefDbInstructionType::Delete as u8; - reference_type_out[0] = match record.reference { - Reference::Pubkey { .. } => ReferenceType::Pubkey as u8, - Reference::U8 { .. } => ReferenceType::U8 as u8, - Reference::U16 { .. } => ReferenceType::U16 as u8, - Reference::U32 { .. } => ReferenceType::U32 as u8, - Reference::U64 { .. } => ReferenceType::U64 as u8, - Reference::F64 { .. } => ReferenceType::F64 as u8, - Reference::Empty => ReferenceType::Empty as u8, - }; - pack_option_u32(record.index, index_out); - record.pack(&mut output[7..])?; - - Ok(7 + record.get_size()) - } - } - } - - pub fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; RefDbInstruction::MAX_LEN] = [0; RefDbInstruction::MAX_LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - pub fn unpack(input: &[u8]) -> Result { - check_data_len(input, 3)?; - let instruction_type = RefDbInstructionType::try_from_primitive(input[0]) - .or(Err(ProgramError::InvalidInstructionData))?; - let reference_type = ReferenceType::try_from_primitive(input[1]) - .or(Err(ProgramError::InvalidInstructionData))?; - match instruction_type { - RefDbInstructionType::Init => { - check_data_len(input, RefDbInstruction::INIT_LEN)?; - - let input = array_ref![input, 2, RefDbInstruction::INIT_LEN - 2]; - #[allow(clippy::ptr_offset_with_cast)] - let (name, max_records, init_account) = array_refs![input, 64, 4, 1]; - - Ok(RefDbInstruction::Init { - name: unpack_array_string64(name)?, - reference_type, - max_records: u32::from_le_bytes(*max_records), - init_account: unpack_bool(init_account)?, - }) - } - RefDbInstructionType::Drop => Ok(RefDbInstruction::Drop { - close_account: unpack_bool(&[input[2]])?, - }), - RefDbInstructionType::Write => { - check_data_len(input, 7)?; - let index = array_ref![input, 2, 5]; - Ok(RefDbInstruction::Write { - record: Record::unpack(&input[7..], reference_type, unpack_option_u32(index)?)?, - }) - } - RefDbInstructionType::Delete => { - check_data_len(input, 7)?; - let index = array_ref![input, 2, 5]; - Ok(RefDbInstruction::Delete { - record: Record::unpack(&input[7..], reference_type, unpack_option_u32(index)?)?, - }) - } - } - } -} - -impl std::fmt::Display for RefDbInstructionType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match *self { - RefDbInstructionType::Init => write!(f, "Init"), - RefDbInstructionType::Drop => write!(f, "Drop"), - RefDbInstructionType::Write => write!(f, "Write"), - RefDbInstructionType::Delete => write!(f, "Delete"), - } - } -} diff --git a/farms/farm-sdk/src/instruction/vault.rs b/farms/farm-sdk/src/instruction/vault.rs deleted file mode 100644 index ac47c375316..00000000000 --- a/farms/farm-sdk/src/instruction/vault.rs +++ /dev/null @@ -1,659 +0,0 @@ -//! Vault management instructions. - -use { - crate::pack::check_data_len, - arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}, - num_enum::TryFromPrimitive, - solana_program::program_error::ProgramError, -}; - -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum VaultInstruction { - /// Initialize on-chain records for a new user - /// # Account references are strategy specific, - /// see particular Vault instructions handlers for more info - UserInit, - - /// Add liquidity to the Vault - /// # Account references are strategy specific, - /// see particular Vault instructions handlers for more info - AddLiquidity { - max_token_a_amount: u64, - max_token_b_amount: u64, - }, - - /// Lock liquidity in the Vault - /// # Account references are strategy specific, - /// see particular Vault instructions handlers for more info - LockLiquidity { amount: u64 }, - - /// Unlock liquidity in the Vault - /// # Account references are strategy specific, - /// see particular Vault instructions handlers for more info - UnlockLiquidity { amount: u64 }, - - /// Remove liquidity from the Vault - /// # Account references are strategy specific, - /// see particular Vault instructions handlers for more info - RemoveLiquidity { amount: u64 }, - - /// Initialize multisig with a new set of admin signatures - /// # Account references are strategy specific, - /// see particular Vault instructions handlers for more info - SetAdminSigners { min_signatures: u8 }, - - /// Remove Fund specific multisig, Main Router's default auth will be used - /// # Account references are strategy specific, - /// see particular Vault instructions handlers for more info - RemoveMultisig, - - /// Set minimum crank interval for the Vault - /// # Account references are strategy specific, - /// see particular Vault instructions handlers for more info - SetMinCrankInterval { min_crank_interval: u32 }, - - /// Set fee for the Vault - /// # Account references are strategy specific, - /// see particular Vault instructions handlers for more info - SetFee { fee: f32 }, - - /// Set underlying protocol fee for the Vault - /// # Account references are strategy specific, - /// see particular Vault instructions handlers for more info - SetExternalFee { external_fee: f32 }, - - /// Disable new deposits to the Vault - /// # Account references are strategy specific, - /// see particular Vault instructions handlers for more info - DisableDeposits, - - /// Allow new deposits to the Vault - /// # Account references are strategy specific, - /// see particular Vault instructions handlers for more info - EnableDeposits, - - /// Disable withdrawals from the Vault - /// # Account references are strategy specific, - /// see particular Vault instructions handlers for more info - DisableWithdrawals, - - /// Allow withdrawals from the Vault - /// # Account references are strategy specific, - /// see particular Vault instructions handlers for more info - EnableWithdrawals, - - /// Run crank operation on the Vault - /// # Account references are strategy specific, - /// see particular Vault instructions handlers for more info - Crank { step: u64 }, - - /// Initialize the Vault - /// # Account references are strategy specific, - /// see particular Vault instructions handlers for more info - Init { step: u64 }, - - /// Shutdown the Vault - /// # Account references are strategy specific, - /// see particular Vault instructions handlers for more info - Shutdown, - - /// Withdraw collected fees - /// # Account references are strategy specific, - /// see particular Vault instructions handlers for more info - WithdrawFees { amount: u64 }, -} - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)] -pub enum VaultInstructionType { - UserInit, - AddLiquidity, - LockLiquidity, - UnlockLiquidity, - RemoveLiquidity, - SetAdminSigners, - RemoveMultisig, - SetMinCrankInterval, - SetFee, - SetExternalFee, - DisableDeposits, - EnableDeposits, - DisableWithdrawals, - EnableWithdrawals, - Crank, - Init, - Shutdown, - WithdrawFees, -} - -impl VaultInstruction { - pub const MAX_LEN: usize = 17; - pub const USER_INIT_LEN: usize = 1; - pub const ADD_LIQUIDITY_LEN: usize = 17; - pub const LOCK_LIQUIDITY_LEN: usize = 9; - pub const UNLOCK_LIQUIDITY_LEN: usize = 9; - pub const REMOVE_LIQUIDITY_LEN: usize = 9; - pub const SET_ADMIN_SIGNERS_LEN: usize = 2; - pub const REMOVE_MULTISIG_LEN: usize = 1; - pub const SET_MIN_CRANK_INTERVAL_LEN: usize = 5; - pub const SET_FEE_LEN: usize = 5; - pub const SET_EXTERNAL_FEE_LEN: usize = 5; - pub const DISABLE_DEPOSITS_LEN: usize = 1; - pub const ENABLE_DEPOSITS_LEN: usize = 1; - pub const DISABLE_WITHDRAWALS_LEN: usize = 1; - pub const ENABLE_WITHDRAWALS_LEN: usize = 1; - pub const CRANK_LEN: usize = 9; - pub const INIT_LEN: usize = 9; - pub const SHUTDOWN_LEN: usize = 1; - pub const WITHDRAW_FEES_LEN: usize = 9; - - pub fn pack(&self, output: &mut [u8]) -> Result { - match self { - Self::UserInit { .. } => self.pack_user_init(output), - Self::AddLiquidity { .. } => self.pack_add_liquidity(output), - Self::RemoveLiquidity { .. } => self.pack_remove_liquidity(output), - Self::LockLiquidity { .. } => self.pack_lock_liquidity(output), - Self::UnlockLiquidity { .. } => self.pack_unlock_liquidity(output), - Self::SetAdminSigners { .. } => self.pack_set_admin_signers(output), - Self::RemoveMultisig { .. } => self.pack_remove_multisig(output), - Self::SetMinCrankInterval { .. } => self.pack_set_min_crank_interval(output), - Self::SetFee { .. } => self.pack_set_fee(output), - Self::SetExternalFee { .. } => self.pack_set_external_fee(output), - Self::DisableDeposits { .. } => self.pack_disable_deposits(output), - Self::EnableDeposits { .. } => self.pack_enable_deposits(output), - Self::DisableWithdrawals { .. } => self.pack_disable_withdrawals(output), - Self::EnableWithdrawals { .. } => self.pack_enable_withdrawals(output), - Self::Crank { .. } => self.pack_crank(output), - Self::Init { .. } => self.pack_init(output), - Self::Shutdown { .. } => self.pack_shutdown(output), - Self::WithdrawFees { .. } => self.pack_withdraw_fees(output), - } - } - - pub fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; VaultInstruction::MAX_LEN] = [0; VaultInstruction::MAX_LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - pub fn unpack(input: &[u8]) -> Result { - check_data_len(input, 1)?; - let instruction_type = VaultInstructionType::try_from_primitive(input[0]) - .or(Err(ProgramError::InvalidInstructionData))?; - match instruction_type { - VaultInstructionType::UserInit => VaultInstruction::unpack_user_init(input), - VaultInstructionType::AddLiquidity => VaultInstruction::unpack_add_liquidity(input), - VaultInstructionType::LockLiquidity => VaultInstruction::unpack_lock_liquidity(input), - VaultInstructionType::UnlockLiquidity => { - VaultInstruction::unpack_unlock_liquidity(input) - } - VaultInstructionType::RemoveLiquidity => { - VaultInstruction::unpack_remove_liquidity(input) - } - VaultInstructionType::SetAdminSigners => { - VaultInstruction::unpack_set_admin_signers(input) - } - VaultInstructionType::RemoveMultisig => VaultInstruction::unpack_remove_multisig(input), - VaultInstructionType::SetMinCrankInterval => { - VaultInstruction::unpack_set_min_crank_interval(input) - } - VaultInstructionType::SetFee => VaultInstruction::unpack_set_fee(input), - VaultInstructionType::SetExternalFee => { - VaultInstruction::unpack_set_external_fee(input) - } - VaultInstructionType::DisableDeposits => { - VaultInstruction::unpack_disable_deposits(input) - } - VaultInstructionType::EnableDeposits => VaultInstruction::unpack_enable_deposits(input), - VaultInstructionType::DisableWithdrawals => { - VaultInstruction::unpack_disable_withdrawals(input) - } - VaultInstructionType::EnableWithdrawals => { - VaultInstruction::unpack_enable_withdrawals(input) - } - VaultInstructionType::Crank => VaultInstruction::unpack_crank(input), - VaultInstructionType::Init => VaultInstruction::unpack_init(input), - VaultInstructionType::Shutdown => VaultInstruction::unpack_shutdown(input), - VaultInstructionType::WithdrawFees => VaultInstruction::unpack_withdraw_fees(input), - } - } - - fn pack_user_init(&self, output: &mut [u8]) -> Result { - check_data_len(output, VaultInstruction::USER_INIT_LEN)?; - - if let VaultInstruction::UserInit = self { - let instruction_type_out = array_mut_ref![output, 0, 1]; - - instruction_type_out[0] = VaultInstructionType::UserInit as u8; - - Ok(VaultInstruction::USER_INIT_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_add_liquidity(&self, output: &mut [u8]) -> Result { - check_data_len(output, VaultInstruction::ADD_LIQUIDITY_LEN)?; - - if let VaultInstruction::AddLiquidity { - max_token_a_amount, - max_token_b_amount, - } = self - { - let output = array_mut_ref![output, 0, VaultInstruction::ADD_LIQUIDITY_LEN]; - let (instruction_type_out, max_token_a_amount_out, max_token_b_amount_out) = - mut_array_refs![output, 1, 8, 8]; - - instruction_type_out[0] = VaultInstructionType::AddLiquidity as u8; - - *max_token_a_amount_out = max_token_a_amount.to_le_bytes(); - *max_token_b_amount_out = max_token_b_amount.to_le_bytes(); - - Ok(VaultInstruction::ADD_LIQUIDITY_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_lock_liquidity(&self, output: &mut [u8]) -> Result { - check_data_len(output, VaultInstruction::LOCK_LIQUIDITY_LEN)?; - - if let VaultInstruction::LockLiquidity { amount } = self { - let output = array_mut_ref![output, 0, VaultInstruction::LOCK_LIQUIDITY_LEN]; - let (instruction_type_out, amount_out) = mut_array_refs![output, 1, 8]; - - instruction_type_out[0] = VaultInstructionType::LockLiquidity as u8; - - *amount_out = amount.to_le_bytes(); - - Ok(VaultInstruction::LOCK_LIQUIDITY_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_unlock_liquidity(&self, output: &mut [u8]) -> Result { - check_data_len(output, VaultInstruction::UNLOCK_LIQUIDITY_LEN)?; - - if let VaultInstruction::UnlockLiquidity { amount } = self { - let output = array_mut_ref![output, 0, VaultInstruction::UNLOCK_LIQUIDITY_LEN]; - let (instruction_type_out, amount_out) = mut_array_refs![output, 1, 8]; - - instruction_type_out[0] = VaultInstructionType::UnlockLiquidity as u8; - - *amount_out = amount.to_le_bytes(); - - Ok(VaultInstruction::UNLOCK_LIQUIDITY_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_remove_liquidity(&self, output: &mut [u8]) -> Result { - check_data_len(output, VaultInstruction::REMOVE_LIQUIDITY_LEN)?; - - if let VaultInstruction::RemoveLiquidity { amount } = self { - let output = array_mut_ref![output, 0, VaultInstruction::REMOVE_LIQUIDITY_LEN]; - let (instruction_type_out, amount_out) = mut_array_refs![output, 1, 8]; - - instruction_type_out[0] = VaultInstructionType::RemoveLiquidity as u8; - - *amount_out = amount.to_le_bytes(); - - Ok(VaultInstruction::REMOVE_LIQUIDITY_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_set_admin_signers(&self, output: &mut [u8]) -> Result { - check_data_len(output, VaultInstruction::SET_ADMIN_SIGNERS_LEN)?; - - if let VaultInstruction::SetAdminSigners { min_signatures } = self { - let output = array_mut_ref![output, 0, VaultInstruction::SET_ADMIN_SIGNERS_LEN]; - let (instruction_type_out, min_signatures_out) = mut_array_refs![output, 1, 1]; - - instruction_type_out[0] = VaultInstructionType::SetAdminSigners as u8; - min_signatures_out[0] = *min_signatures; - - Ok(VaultInstruction::SET_ADMIN_SIGNERS_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_remove_multisig(&self, output: &mut [u8]) -> Result { - check_data_len(output, VaultInstruction::REMOVE_MULTISIG_LEN)?; - - if let VaultInstruction::RemoveMultisig = self { - let instruction_type_out = array_mut_ref![output, 0, 1]; - - instruction_type_out[0] = VaultInstructionType::RemoveMultisig as u8; - - Ok(VaultInstruction::REMOVE_MULTISIG_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_set_min_crank_interval(&self, output: &mut [u8]) -> Result { - check_data_len(output, VaultInstruction::SET_MIN_CRANK_INTERVAL_LEN)?; - - if let VaultInstruction::SetMinCrankInterval { min_crank_interval } = self { - let output = array_mut_ref![output, 0, VaultInstruction::SET_MIN_CRANK_INTERVAL_LEN]; - let (instruction_type_out, min_crank_interval_out) = mut_array_refs![output, 1, 4]; - - instruction_type_out[0] = VaultInstructionType::SetMinCrankInterval as u8; - - *min_crank_interval_out = min_crank_interval.to_le_bytes(); - - Ok(VaultInstruction::SET_MIN_CRANK_INTERVAL_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_set_fee(&self, output: &mut [u8]) -> Result { - check_data_len(output, VaultInstruction::SET_FEE_LEN)?; - - if let VaultInstruction::SetFee { fee } = self { - let output = array_mut_ref![output, 0, VaultInstruction::SET_FEE_LEN]; - let (instruction_type_out, fee_out) = mut_array_refs![output, 1, 4]; - - instruction_type_out[0] = VaultInstructionType::SetFee as u8; - - *fee_out = fee.to_le_bytes(); - - Ok(VaultInstruction::SET_FEE_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_set_external_fee(&self, output: &mut [u8]) -> Result { - check_data_len(output, VaultInstruction::SET_EXTERNAL_FEE_LEN)?; - - if let VaultInstruction::SetExternalFee { external_fee } = self { - let output = array_mut_ref![output, 0, VaultInstruction::SET_EXTERNAL_FEE_LEN]; - let (instruction_type_out, external_fee_out) = mut_array_refs![output, 1, 4]; - - instruction_type_out[0] = VaultInstructionType::SetExternalFee as u8; - - *external_fee_out = external_fee.to_le_bytes(); - - Ok(VaultInstruction::SET_EXTERNAL_FEE_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_disable_deposits(&self, output: &mut [u8]) -> Result { - check_data_len(output, VaultInstruction::DISABLE_DEPOSITS_LEN)?; - - if let VaultInstruction::DisableDeposits = self { - let instruction_type_out = array_mut_ref![output, 0, 1]; - - instruction_type_out[0] = VaultInstructionType::DisableDeposits as u8; - - Ok(VaultInstruction::DISABLE_DEPOSITS_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_enable_deposits(&self, output: &mut [u8]) -> Result { - check_data_len(output, VaultInstruction::ENABLE_DEPOSITS_LEN)?; - - if let VaultInstruction::EnableDeposits = self { - let instruction_type_out = array_mut_ref![output, 0, 1]; - - instruction_type_out[0] = VaultInstructionType::EnableDeposits as u8; - - Ok(VaultInstruction::ENABLE_DEPOSITS_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_disable_withdrawals(&self, output: &mut [u8]) -> Result { - check_data_len(output, VaultInstruction::DISABLE_WITHDRAWALS_LEN)?; - - if let VaultInstruction::DisableWithdrawals = self { - let instruction_type_out = array_mut_ref![output, 0, 1]; - - instruction_type_out[0] = VaultInstructionType::DisableWithdrawals as u8; - - Ok(VaultInstruction::DISABLE_WITHDRAWALS_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_enable_withdrawals(&self, output: &mut [u8]) -> Result { - check_data_len(output, VaultInstruction::ENABLE_WITHDRAWALS_LEN)?; - - if let VaultInstruction::EnableWithdrawals = self { - let instruction_type_out = array_mut_ref![output, 0, 1]; - - instruction_type_out[0] = VaultInstructionType::EnableWithdrawals as u8; - - Ok(VaultInstruction::ENABLE_WITHDRAWALS_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_crank(&self, output: &mut [u8]) -> Result { - check_data_len(output, VaultInstruction::CRANK_LEN)?; - - if let VaultInstruction::Crank { step } = self { - let output = array_mut_ref![output, 0, VaultInstruction::CRANK_LEN]; - let (instruction_type_out, step_out) = mut_array_refs![output, 1, 8]; - - instruction_type_out[0] = VaultInstructionType::Crank as u8; - - *step_out = step.to_le_bytes(); - - Ok(VaultInstruction::CRANK_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_init(&self, output: &mut [u8]) -> Result { - check_data_len(output, VaultInstruction::INIT_LEN)?; - - if let VaultInstruction::Init { step } = self { - let output = array_mut_ref![output, 0, VaultInstruction::INIT_LEN]; - let (instruction_type_out, step_out) = mut_array_refs![output, 1, 8]; - - instruction_type_out[0] = VaultInstructionType::Init as u8; - - *step_out = step.to_le_bytes(); - - Ok(VaultInstruction::INIT_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_shutdown(&self, output: &mut [u8]) -> Result { - check_data_len(output, VaultInstruction::SHUTDOWN_LEN)?; - - if let VaultInstruction::Shutdown = self { - let instruction_type_out = array_mut_ref![output, 0, 1]; - - instruction_type_out[0] = VaultInstructionType::Shutdown as u8; - - Ok(VaultInstruction::SHUTDOWN_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn pack_withdraw_fees(&self, output: &mut [u8]) -> Result { - check_data_len(output, VaultInstruction::WITHDRAW_FEES_LEN)?; - - if let VaultInstruction::WithdrawFees { amount } = self { - let output = array_mut_ref![output, 0, VaultInstruction::WITHDRAW_FEES_LEN]; - let (instruction_type_out, amount_out) = mut_array_refs![output, 1, 8]; - - instruction_type_out[0] = VaultInstructionType::WithdrawFees as u8; - - *amount_out = amount.to_le_bytes(); - - Ok(VaultInstruction::WITHDRAW_FEES_LEN) - } else { - Err(ProgramError::InvalidInstructionData) - } - } - - fn unpack_user_init(input: &[u8]) -> Result { - check_data_len(input, VaultInstruction::USER_INIT_LEN)?; - Ok(Self::UserInit) - } - - fn unpack_add_liquidity(input: &[u8]) -> Result { - check_data_len(input, VaultInstruction::ADD_LIQUIDITY_LEN)?; - - let input = array_ref![input, 1, VaultInstruction::ADD_LIQUIDITY_LEN - 1]; - #[allow(clippy::ptr_offset_with_cast)] - let (max_token_a_amount, max_token_b_amount) = array_refs![input, 8, 8]; - - Ok(Self::AddLiquidity { - max_token_a_amount: u64::from_le_bytes(*max_token_a_amount), - max_token_b_amount: u64::from_le_bytes(*max_token_b_amount), - }) - } - - fn unpack_lock_liquidity(input: &[u8]) -> Result { - check_data_len(input, VaultInstruction::LOCK_LIQUIDITY_LEN)?; - Ok(Self::LockLiquidity { - amount: u64::from_le_bytes(*array_ref![input, 1, 8]), - }) - } - - fn unpack_unlock_liquidity(input: &[u8]) -> Result { - check_data_len(input, VaultInstruction::UNLOCK_LIQUIDITY_LEN)?; - Ok(Self::UnlockLiquidity { - amount: u64::from_le_bytes(*array_ref![input, 1, 8]), - }) - } - - fn unpack_remove_liquidity(input: &[u8]) -> Result { - check_data_len(input, VaultInstruction::REMOVE_LIQUIDITY_LEN)?; - Ok(Self::RemoveLiquidity { - amount: u64::from_le_bytes(*array_ref![input, 1, 8]), - }) - } - - fn unpack_set_admin_signers(input: &[u8]) -> Result { - check_data_len(input, VaultInstruction::SET_ADMIN_SIGNERS_LEN)?; - - let input = array_ref![input, 1, VaultInstruction::SET_ADMIN_SIGNERS_LEN - 1]; - - Ok(Self::SetAdminSigners { - min_signatures: input[0], - }) - } - - fn unpack_remove_multisig(input: &[u8]) -> Result { - check_data_len(input, VaultInstruction::REMOVE_MULTISIG_LEN)?; - Ok(Self::RemoveMultisig) - } - - fn unpack_set_min_crank_interval(input: &[u8]) -> Result { - check_data_len(input, VaultInstruction::SET_MIN_CRANK_INTERVAL_LEN)?; - Ok(Self::SetMinCrankInterval { - min_crank_interval: u32::from_le_bytes(*array_ref![input, 1, 4]), - }) - } - - fn unpack_set_fee(input: &[u8]) -> Result { - check_data_len(input, VaultInstruction::SET_FEE_LEN)?; - Ok(Self::SetFee { - fee: f32::from_le_bytes(*array_ref![input, 1, 4]), - }) - } - - fn unpack_set_external_fee(input: &[u8]) -> Result { - check_data_len(input, VaultInstruction::SET_EXTERNAL_FEE_LEN)?; - Ok(Self::SetExternalFee { - external_fee: f32::from_le_bytes(*array_ref![input, 1, 4]), - }) - } - - fn unpack_disable_deposits(input: &[u8]) -> Result { - check_data_len(input, VaultInstruction::DISABLE_DEPOSITS_LEN)?; - Ok(Self::DisableDeposits) - } - - fn unpack_enable_deposits(input: &[u8]) -> Result { - check_data_len(input, VaultInstruction::ENABLE_DEPOSITS_LEN)?; - Ok(Self::EnableDeposits) - } - - fn unpack_disable_withdrawals(input: &[u8]) -> Result { - check_data_len(input, VaultInstruction::DISABLE_WITHDRAWALS_LEN)?; - Ok(Self::DisableWithdrawals) - } - - fn unpack_enable_withdrawals(input: &[u8]) -> Result { - check_data_len(input, VaultInstruction::ENABLE_WITHDRAWALS_LEN)?; - Ok(Self::EnableWithdrawals) - } - - fn unpack_crank(input: &[u8]) -> Result { - check_data_len(input, VaultInstruction::CRANK_LEN)?; - Ok(Self::Crank { - step: u64::from_le_bytes(*array_ref![input, 1, 8]), - }) - } - - fn unpack_init(input: &[u8]) -> Result { - check_data_len(input, VaultInstruction::INIT_LEN)?; - Ok(Self::Init { - step: u64::from_le_bytes(*array_ref![input, 1, 8]), - }) - } - - fn unpack_shutdown(input: &[u8]) -> Result { - check_data_len(input, VaultInstruction::SHUTDOWN_LEN)?; - Ok(Self::Shutdown) - } - - fn unpack_withdraw_fees(input: &[u8]) -> Result { - check_data_len(input, VaultInstruction::WITHDRAW_FEES_LEN)?; - Ok(Self::WithdrawFees { - amount: u64::from_le_bytes(*array_ref![input, 1, 8]), - }) - } -} - -impl std::fmt::Display for VaultInstructionType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match *self { - VaultInstructionType::UserInit => write!(f, "UserInit"), - VaultInstructionType::AddLiquidity => write!(f, "AddLiquidity"), - VaultInstructionType::LockLiquidity => write!(f, "LockLiquidity"), - VaultInstructionType::UnlockLiquidity => write!(f, "UnlockLiquidity"), - VaultInstructionType::RemoveLiquidity => write!(f, "RemoveLiquidity"), - VaultInstructionType::SetAdminSigners => write!(f, "SetAdminSigners"), - VaultInstructionType::RemoveMultisig => write!(f, "RemoveMultisig"), - VaultInstructionType::SetMinCrankInterval => write!(f, "SetMinCrankInterval"), - VaultInstructionType::SetFee => write!(f, "SetFee"), - VaultInstructionType::SetExternalFee => write!(f, "SetExternalFee"), - VaultInstructionType::DisableDeposits => write!(f, "DisableDeposits"), - VaultInstructionType::EnableDeposits => write!(f, "EnableDeposits"), - VaultInstructionType::DisableWithdrawals => write!(f, "DisableWithdrawals"), - VaultInstructionType::EnableWithdrawals => write!(f, "EnableWithdrawals"), - VaultInstructionType::Crank => write!(f, "Crank"), - VaultInstructionType::Init => write!(f, "Init"), - VaultInstructionType::Shutdown => write!(f, "Shutdown"), - VaultInstructionType::WithdrawFees => write!(f, "WithdrawFees"), - } - } -} diff --git a/farms/farm-sdk/src/lib.rs b/farms/farm-sdk/src/lib.rs deleted file mode 100644 index b3fa82b406b..00000000000 --- a/farms/farm-sdk/src/lib.rs +++ /dev/null @@ -1,149 +0,0 @@ -#![forbid(unsafe_code)] - -use serde::{Deserialize, Serialize}; -use serde_json::to_string; -use solana_program::program_error::ProgramError; - -pub mod error; -pub mod farm; -pub mod fund; -pub mod id; -pub mod instruction; -pub mod log; -pub mod math; -pub mod pack; -pub mod pool; -pub mod program; -pub mod refdb; -pub mod string; -pub mod token; -pub mod traits; -pub mod vault; - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq)] -pub enum ProgramIDType { - System, - ProgramsRef, - VaultsRef, - Vault, - FarmsRef, - Farm, - PoolsRef, - Pool, - TokensRef, - Token, - MainRouter, - Serum, - Raydium, - Saber, - Orca, - FundsRef, - Fund, -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq)] -pub enum Protocol { - Raydium, - Saber, - Orca, -} - -#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] -pub struct ProtocolInfo { - pub protocol: Protocol, - pub description: String, - pub link: String, - pub pools: u32, - pub farms: u32, - pub vaults: u32, -} - -impl std::fmt::Display for ProgramIDType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match *self { - ProgramIDType::System => write!(f, "System"), - ProgramIDType::ProgramsRef => write!(f, "ProgramsRef"), - ProgramIDType::VaultsRef => write!(f, "VaultsRef"), - ProgramIDType::Vault => write!(f, "Vault"), - ProgramIDType::FarmsRef => write!(f, "FarmsRef"), - ProgramIDType::Farm => write!(f, "Farm"), - ProgramIDType::PoolsRef => write!(f, "PoolsRef"), - ProgramIDType::Pool => write!(f, "Pool"), - ProgramIDType::TokensRef => write!(f, "TokensRef"), - ProgramIDType::Token => write!(f, "Token"), - ProgramIDType::MainRouter => write!(f, "MainRouter"), - ProgramIDType::Serum => write!(f, "Serum"), - ProgramIDType::Raydium => write!(f, "Raydium"), - ProgramIDType::Saber => write!(f, "Saber"), - ProgramIDType::Orca => write!(f, "Orca"), - ProgramIDType::FundsRef => write!(f, "FundsRef"), - ProgramIDType::Fund => write!(f, "Fund"), - } - } -} - -impl std::str::FromStr for ProgramIDType { - type Err = ProgramError; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "system" => Ok(ProgramIDType::System), - "programsref" => Ok(ProgramIDType::ProgramsRef), - "vaultsref" => Ok(ProgramIDType::VaultsRef), - "vault" => Ok(ProgramIDType::Vault), - "farmsref" => Ok(ProgramIDType::FarmsRef), - "farm" => Ok(ProgramIDType::Farm), - "poolsref" => Ok(ProgramIDType::PoolsRef), - "pool" => Ok(ProgramIDType::Pool), - "tokensref" => Ok(ProgramIDType::TokensRef), - "token" => Ok(ProgramIDType::Token), - "mainrouter" => Ok(ProgramIDType::MainRouter), - "serum" => Ok(ProgramIDType::Serum), - "raydium" => Ok(ProgramIDType::Raydium), - "saber" => Ok(ProgramIDType::Saber), - "orca" => Ok(ProgramIDType::Orca), - "fundsref" => Ok(ProgramIDType::FundsRef), - "fund" => Ok(ProgramIDType::Fund), - _ => Err(ProgramError::InvalidArgument), - } - } -} - -impl Protocol { - pub fn id(&self) -> &'static str { - match *self { - Protocol::Raydium => "RDM", - Protocol::Saber => "SBR", - Protocol::Orca => "ORC", - } - } -} - -impl std::fmt::Display for Protocol { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match *self { - Protocol::Raydium => write!(f, "Raydium"), - Protocol::Saber => write!(f, "Saber"), - Protocol::Orca => write!(f, "Orca"), - } - } -} - -impl std::str::FromStr for Protocol { - type Err = ProgramError; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "rdm" | "raydium" => Ok(Protocol::Raydium), - "sbr" | "saber" => Ok(Protocol::Saber), - "orc" | "orca" => Ok(Protocol::Orca), - _ => Err(ProgramError::InvalidArgument), - } - } -} - -impl std::fmt::Display for ProtocolInfo { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", to_string(&self).unwrap()) - } -} diff --git a/farms/farm-sdk/src/log.rs b/farms/farm-sdk/src/log.rs deleted file mode 100644 index cfa36626039..00000000000 --- a/farms/farm-sdk/src/log.rs +++ /dev/null @@ -1,37 +0,0 @@ -pub use solana_program::log::*; -use solana_program::{account_info::AccountInfo, msg}; - -#[macro_export] -macro_rules! debug_msg { - ($msg:expr) => { - if cfg!(feature = "debug") { - $crate::log::sol_log($msg); - $crate::log::sol_log_compute_units(); - } - }; - ($arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr, $arg5:expr) => { - if cfg!(feature = "debug") { - $crate::log::sol_log_64( - $arg1 as u64, - $arg2 as u64, - $arg3 as u64, - $arg4 as u64, - $arg5 as u64, - ); - $crate::log::sol_log_compute_units(); - } - }; - ($($arg:tt)*) => (if cfg!(feature = "debug") { - $crate::log::sol_log(&format!($($arg)*)); - $crate::log::sol_log_compute_units(); - }); -} - -#[allow(dead_code)] -pub fn sol_log_params_short(accounts: &[AccountInfo], data: &[u8]) { - msg!("Accounts:"); - for account in accounts.iter() { - account.key.log(); - } - msg!("Instruction data length: {}", data.len()); -} diff --git a/farms/farm-sdk/src/math.rs b/farms/farm-sdk/src/math.rs deleted file mode 100644 index 70028fac1e3..00000000000 --- a/farms/farm-sdk/src/math.rs +++ /dev/null @@ -1,173 +0,0 @@ -//! Common math routines. - -use { - crate::error::FarmError, - arrayref::array_ref, - solana_program::{hash::Hasher, msg, program_error::ProgramError, pubkey::Pubkey}, - std::fmt::Display, -}; - -pub fn checked_add(arg1: T, arg2: T) -> Result -where - T: num_traits::PrimInt + Display, -{ - if let Some(res) = arg1.checked_add(&arg2) { - Ok(res) - } else { - msg!("Error: Overflow in {} + {}", arg1, arg2); - Err(FarmError::MathOverflow.into()) - } -} - -pub fn checked_sub(arg1: T, arg2: T) -> Result -where - T: num_traits::PrimInt + Display, -{ - if let Some(res) = arg1.checked_sub(&arg2) { - Ok(res) - } else { - msg!("Error: Overflow in {} - {}", arg1, arg2); - Err(FarmError::MathOverflow.into()) - } -} - -pub fn checked_div(arg1: T, arg2: T) -> Result -where - T: num_traits::PrimInt + Display, -{ - if let Some(res) = arg1.checked_div(&arg2) { - Ok(res) - } else { - msg!("Error: Overflow in {} / {}", arg1, arg2); - Err(FarmError::MathOverflow.into()) - } -} - -pub fn checked_mul(arg1: T, arg2: T) -> Result -where - T: num_traits::PrimInt + Display, -{ - if let Some(res) = arg1.checked_mul(&arg2) { - Ok(res) - } else { - msg!("Error: Overflow in {} * {}", arg1, arg2); - Err(FarmError::MathOverflow.into()) - } -} - -pub fn checked_pow(arg: T, exp: usize) -> Result -where - T: num_traits::PrimInt + Display, -{ - if let Some(res) = num_traits::checked_pow(arg, exp) { - Ok(res) - } else { - msg!("Error: Overflow in {} ^ {}", arg, exp); - Err(FarmError::MathOverflow.into()) - } -} - -pub fn checked_powf(arg: f64, exp: f64) -> Result { - let res = f64::powf(arg, exp); - if res.is_finite() { - Ok(res) - } else { - msg!("Error: Overflow in {} ^ {}", arg, exp); - Err(FarmError::MathOverflow.into()) - } -} - -pub fn checked_powi(arg: f64, exp: i32) -> Result { - let res = if exp > 0 { - f64::powi(arg, exp) - } else { - // wrokaround due to f64::powi() not working properly on-chain with negative exponent - 1.0 / f64::powi(arg, -exp) - }; - if res.is_finite() { - Ok(res) - } else { - msg!("Error: Overflow in {} ^ {}", arg, exp); - Err(FarmError::MathOverflow.into()) - } -} - -pub fn checked_as_u64(arg: T) -> Result -where - T: Display + num_traits::ToPrimitive + Clone, -{ - let option: Option = num_traits::NumCast::from(arg.clone()); - if let Some(res) = option { - Ok(res) - } else { - msg!("Error: Overflow in {} as u64", arg); - Err(FarmError::MathOverflow.into()) - } -} - -pub fn checked_as_u128(arg: T) -> Result -where - T: Display + num_traits::ToPrimitive + Clone, -{ - let option: Option = num_traits::NumCast::from(arg.clone()); - if let Some(res) = option { - Ok(res) - } else { - msg!("Error: Overflow in {} as u128", arg); - Err(FarmError::MathOverflow.into()) - } -} - -/// Returns numerator and denominator for the given fee -pub fn get_fee_parts(fee: f64) -> (u64, u64) { - if fee <= 0.0 || fee > 1.0 { - return (0, 1); - } - let mut numerator = fee; - let mut denominator = 1u64; - let mut i = 0; - while numerator != (numerator as u64) as f64 && i < 6 { - numerator *= 10.0; - denominator *= 10; - i += 1; - } - if numerator as u64 == denominator { - (1, 1) - } else { - (numerator as u64, denominator) - } -} - -pub fn get_no_fee_amount( - amount: u64, - fee_numerator: u64, - fee_denominator: u64, -) -> Result { - if amount == 0 { - return Ok(0); - } - checked_sub( - amount, - std::cmp::max( - checked_as_u64(checked_div( - checked_mul(amount as u128, fee_numerator as u128)?, - fee_denominator as u128, - )?)?, - 1, - ), - ) -} - -pub fn hash_address(current_hash: u64, address: &Pubkey) -> u64 { - let mut input: Vec; - let mut hasher = Hasher::default(); - if current_hash != 0 { - input = current_hash.to_le_bytes().to_vec(); - input.extend_from_slice(address.as_ref()); - } else { - input = address.as_ref().to_vec(); - } - hasher.hash(input.as_slice()); - let hash = hasher.result(); - u64::from_le_bytes(*array_ref!(hash.as_ref(), 0, 8)) -} diff --git a/farms/farm-sdk/src/pack.rs b/farms/farm-sdk/src/pack.rs deleted file mode 100644 index 07d4d5a7a5e..00000000000 --- a/farms/farm-sdk/src/pack.rs +++ /dev/null @@ -1,239 +0,0 @@ -//! Common routines for packing/unpacking - -use { - crate::string::ArrayString64, - arrayref::{array_refs, mut_array_refs}, - serde::{ - de::{Error, SeqAccess, Visitor}, - ser::SerializeSeq, - Deserialize, Deserializer, Serializer, - }, - solana_program::{program_error::ProgramError, pubkey::Pubkey}, - std::{fmt, str::FromStr}, -}; - -struct PubkeyArrayDeserializer; - -impl<'de> Visitor<'de> for PubkeyArrayDeserializer { - type Value = Vec; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Pubkey array") - } - - fn visit_seq(self, mut seq: A) -> Result - where - A: SeqAccess<'de>, - { - let mut obj = vec![]; - while let Some(key) = seq.next_element::()? { - obj.push(Pubkey::from_str(&key).map_err(A::Error::custom)?); - } - - Ok(obj) - } -} - -/// Checks if the slice has at least min_len size -pub fn check_data_len(data: &[u8], min_len: usize) -> Result<(), ProgramError> { - if data.len() < min_len { - Err(ProgramError::AccountDataTooSmall) - } else { - Ok(()) - } -} - -/// Converts bool to a byte -pub fn pack_bool(input: bool, output: &mut [u8; 1]) { - output[0] = input as u8; -} - -/// Converts a raw byte to a bool -pub fn unpack_bool(input: &[u8; 1]) -> Result { - let result = match input { - [0] => false, - [1] => true, - _ => return Err(ProgramError::InvalidAccountData), - }; - Ok(result) -} - -pub fn pack_option_key(input: &Option, output: &mut [u8; 33]) { - let (tag, data) = mut_array_refs![output, 1, 32]; - match input { - Option::Some(key) => { - tag[0] = 1; - data.copy_from_slice(key.as_ref()); - } - Option::None => { - tag[0] = 0; - } - } -} - -pub fn unpack_option_key(input: &[u8; 33]) -> Result, ProgramError> { - let (tag, data) = array_refs![input, 1, 32]; - match *tag { - [0] => Ok(Option::None), - [1] => Ok(Option::Some(Pubkey::new_from_array(*data))), - _ => Err(ProgramError::InvalidAccountData), - } -} - -pub fn pack_option_u32(input: Option, output: &mut [u8; 5]) { - let (tag, data) = mut_array_refs![output, 1, 4]; - match input { - Option::Some(val) => { - tag[0] = 1; - *data = val.to_le_bytes(); - } - Option::None => { - tag[0] = 0; - } - } -} - -pub fn unpack_option_u32(input: &[u8; 5]) -> Result, ProgramError> { - let (tag, data) = array_refs![input, 1, 4]; - match *tag { - [0] => Ok(Option::None), - [1] => Ok(Option::Some(u32::from_le_bytes(*data))), - _ => Err(ProgramError::InvalidAccountData), - } -} - -pub fn pack_array_string64(input: &ArrayString64, output: &mut [u8; 64]) { - if !input.is_empty() { - for (dst, src) in output.iter_mut().zip(input.as_bytes()) { - *dst = *src - } - } else { - output[0] = 0; - } -} - -pub fn unpack_array_string64(input: &[u8; 64]) -> Result { - if let Some(i) = input.iter().position(|x| *x == 0) { - ArrayString64::try_from_utf8(&input[0..i]).or(Err(ProgramError::InvalidAccountData)) - } else { - ArrayString64::try_from_utf8(input).or(Err(ProgramError::InvalidAccountData)) - } -} - -/// Custom Pubkey deserializer to use with Serde -pub fn pubkey_deserialize<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - let s: String = Deserialize::deserialize(deserializer).unwrap(); - Pubkey::from_str(s.as_str()).map_err(D::Error::custom) -} - -/// Custom Pubkey serializer to use with Serde -pub fn pubkey_serialize(x: &Pubkey, s: S) -> Result -where - S: Serializer, -{ - s.serialize_str(x.to_string().as_str()) -} - -/// Custom Pubkey slice deserializer to use with Serde -pub fn pubkey_slice_deserialize<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - deserializer.deserialize_seq(PubkeyArrayDeserializer) -} - -/// Custom Pubkey slice serializer to use with Serde -pub fn pubkey_slice_serialize(x: &[Pubkey], s: S) -> Result -where - S: Serializer, -{ - let mut seq = s.serialize_seq(Some(x.len()))?; - for e in x { - seq.serialize_element(e.to_string().as_str())?; - } - seq.end() -} - -/// Custom Option deserializer to use with Serde -pub fn optional_pubkey_deserialize<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - let s: String = Deserialize::deserialize(deserializer).unwrap(); - if s.is_empty() { - Ok(None) - } else { - Ok(Some( - Pubkey::from_str(s.as_str()).map_err(D::Error::custom)?, - )) - } -} - -/// Custom Option serializer to use with Serde -pub fn optional_pubkey_serialize(x: &Option, s: S) -> Result -where - S: Serializer, -{ - if let Some(key) = x { - s.serialize_str(key.to_string().as_str()) - } else { - s.serialize_str("") - } -} - -/// Custom ArrayString64 serializer to use with Serde -pub fn as64_serialize(x: &ArrayString64, s: S) -> Result -where - S: Serializer, -{ - s.serialize_str(x.as_str()) -} - -/// Custom ArrayString64 deserializer to use with Serde -pub fn as64_deserialize<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - struct ArrayStringVisitor; - - impl<'de> Visitor<'de> for ArrayStringVisitor { - type Value = ArrayString64; - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a string") - } - fn visit_str(self, v: &str) -> Result - where - E: Error, - { - ArrayString64::try_from_str(v).map_err(E::custom) - } - } - - deserializer.deserialize_any(ArrayStringVisitor) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_as64_serialization() { - let as1 = ArrayString64::from_utf8("test").unwrap(); - let mut output: [u8; 64] = [0; 64]; - pack_array_string64(&as1, &mut output); - let as2 = unpack_array_string64(&output).unwrap(); - assert_eq!(as1, as2); - } - - #[test] - fn test_as64_serialization_utf8() { - let as1 = ArrayString64::from_utf8("тест").unwrap(); - let mut output: [u8; 64] = [0; 64]; - pack_array_string64(&as1, &mut output); - let as2 = unpack_array_string64(&output).unwrap(); - assert_eq!(as1, as2); - } -} diff --git a/farms/farm-sdk/src/pool.rs b/farms/farm-sdk/src/pool.rs deleted file mode 100644 index 3b473fc4f7a..00000000000 --- a/farms/farm-sdk/src/pool.rs +++ /dev/null @@ -1,771 +0,0 @@ -//! Liquidity Pools - -use { - crate::{pack::*, string::ArrayString64, traits::*}, - arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}, - num_enum::TryFromPrimitive, - serde::{Deserialize, Serialize}, - serde_json::to_string, - solana_program::program_error::ProgramError, - solana_program::pubkey::Pubkey, -}; - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq)] -pub enum PoolRoute { - Raydium { - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - amm_id: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - amm_authority: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - amm_open_orders: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - amm_target: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pool_withdraw_queue: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pool_temp_lp_token_account: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - serum_program_id: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - serum_market: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - serum_coin_vault_account: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - serum_pc_vault_account: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - serum_vault_signer: Pubkey, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - serum_bids: Option, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - serum_asks: Option, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - serum_event_queue: Option, - }, - Saber { - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - swap_account: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - swap_authority: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - fees_account_a: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - fees_account_b: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - decimal_wrapper_program: Pubkey, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - wrapped_token_a_ref: Option, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - wrapped_token_a_vault: Option, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - decimal_wrapper_token_a: Option, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - wrapped_token_b_ref: Option, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - wrapped_token_b_vault: Option, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - decimal_wrapper_token_b: Option, - }, - Orca { - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - amm_id: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - amm_authority: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - fees_account: Pubkey, - }, -} - -#[repr(u8)] -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)] -pub enum PoolRouteType { - Raydium, - Saber, - Orca, -} - -#[repr(u8)] -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)] -pub enum PoolType { - Amm, - AmmStable, -} - -#[repr(u8)] -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)] -pub enum PoolTokenType { - VaultToken, - PoolToken, - FarmToken, - Token, -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq)] -pub struct Pool { - #[serde( - serialize_with = "as64_serialize", - deserialize_with = "as64_deserialize" - )] - pub name: ArrayString64, - pub version: u16, - pub pool_type: PoolType, - pub official: bool, - pub refdb_index: Option, - pub refdb_counter: u16, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - pub token_a_ref: Option, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - pub token_b_ref: Option, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - pub lp_token_ref: Option, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - pub token_a_account: Option, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - pub token_b_account: Option, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub router_program_id: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub pool_program_id: Pubkey, - pub route: PoolRoute, -} - -impl Named for Pool { - fn name(&self) -> ArrayString64 { - self.name - } -} - -impl Versioned for Pool { - fn version(&self) -> u16 { - self.version - } -} - -impl Pool { - pub const MAX_LEN: usize = 756; - pub const RAYDIUM_POOL_LEN: usize = 756; - pub const SABER_POOL_LEN: usize = 663; - pub const ORCA_POOL_LEN: usize = 401; - - fn pack_raydium(&self, output: &mut [u8]) -> Result { - check_data_len(output, Pool::RAYDIUM_POOL_LEN)?; - - if let PoolRoute::Raydium { - amm_id, - amm_authority, - amm_open_orders, - amm_target, - pool_withdraw_queue, - pool_temp_lp_token_account, - serum_program_id, - serum_market, - serum_coin_vault_account, - serum_pc_vault_account, - serum_vault_signer, - serum_bids, - serum_asks, - serum_event_queue, - } = self.route - { - let output = array_mut_ref![output, 0, Pool::RAYDIUM_POOL_LEN]; - - let ( - pool_route_type_out, - name_out, - version_out, - pool_type_out, - official_out, - refdb_index_out, - refdb_counter_out, - token_a_ref_out, - token_b_ref_out, - lp_token_ref_out, - token_a_account_out, - token_b_account_out, - router_program_id_out, - pool_program_id_out, - amm_id_out, - amm_authority_out, - amm_open_orders_out, - amm_target_out, - pool_withdraw_queue_out, - pool_temp_lp_token_account_out, - serum_program_id_out, - serum_market_out, - serum_coin_vault_account_out, - serum_pc_vault_account_out, - serum_vault_signer_out, - serum_bids_out, - serum_asks_out, - serum_event_queue_out, - ) = mut_array_refs![ - output, 1, 64, 2, 1, 1, 5, 2, 33, 33, 33, 33, 33, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 33, 33, 33 - ]; - - pool_route_type_out[0] = PoolRouteType::Raydium as u8; - - pack_array_string64(&self.name, name_out); - *version_out = self.version.to_le_bytes(); - pool_type_out[0] = self.pool_type as u8; - official_out[0] = self.official as u8; - pack_option_u32(self.refdb_index, refdb_index_out); - *refdb_counter_out = self.refdb_counter.to_le_bytes(); - pack_option_key(&self.token_a_ref, token_a_ref_out); - pack_option_key(&self.token_b_ref, token_b_ref_out); - pack_option_key(&self.lp_token_ref, lp_token_ref_out); - pack_option_key(&self.token_a_account, token_a_account_out); - pack_option_key(&self.token_b_account, token_b_account_out); - router_program_id_out.copy_from_slice(self.router_program_id.as_ref()); - pool_program_id_out.copy_from_slice(self.pool_program_id.as_ref()); - amm_id_out.copy_from_slice(amm_id.as_ref()); - amm_authority_out.copy_from_slice(amm_authority.as_ref()); - amm_open_orders_out.copy_from_slice(amm_open_orders.as_ref()); - amm_target_out.copy_from_slice(amm_target.as_ref()); - pool_withdraw_queue_out.copy_from_slice(pool_withdraw_queue.as_ref()); - pool_temp_lp_token_account_out.copy_from_slice(pool_temp_lp_token_account.as_ref()); - serum_program_id_out.copy_from_slice(serum_program_id.as_ref()); - serum_market_out.copy_from_slice(serum_market.as_ref()); - serum_coin_vault_account_out.copy_from_slice(serum_coin_vault_account.as_ref()); - serum_pc_vault_account_out.copy_from_slice(serum_pc_vault_account.as_ref()); - serum_vault_signer_out.copy_from_slice(serum_vault_signer.as_ref()); - pack_option_key(&serum_bids, serum_bids_out); - pack_option_key(&serum_asks, serum_asks_out); - pack_option_key(&serum_event_queue, serum_event_queue_out); - - Ok(Pool::RAYDIUM_POOL_LEN) - } else { - Err(ProgramError::InvalidAccountData) - } - } - - fn pack_saber(&self, output: &mut [u8]) -> Result { - check_data_len(output, Pool::SABER_POOL_LEN)?; - - if let PoolRoute::Saber { - swap_account, - swap_authority, - fees_account_a, - fees_account_b, - decimal_wrapper_program, - wrapped_token_a_ref, - wrapped_token_a_vault, - decimal_wrapper_token_a, - wrapped_token_b_ref, - wrapped_token_b_vault, - decimal_wrapper_token_b, - } = self.route - { - let output = array_mut_ref![output, 0, Pool::SABER_POOL_LEN]; - - let ( - pool_route_type_out, - name_out, - version_out, - pool_type_out, - official_out, - refdb_index_out, - refdb_counter_out, - token_a_ref_out, - token_b_ref_out, - lp_token_ref_out, - token_a_account_out, - token_b_account_out, - router_program_id_out, - pool_program_id_out, - swap_account_out, - swap_authority_out, - fees_account_a_out, - fees_account_b_out, - decimal_wrapper_program_out, - wrapped_token_a_ref_out, - wrapped_token_a_vault_out, - decimal_wrapper_token_a_out, - wrapped_token_b_ref_out, - wrapped_token_b_vault_out, - decimal_wrapper_token_b_out, - ) = mut_array_refs![ - output, 1, 64, 2, 1, 1, 5, 2, 33, 33, 33, 33, 33, 32, 32, 32, 32, 32, 32, 32, 33, - 33, 33, 33, 33, 33 - ]; - - pool_route_type_out[0] = PoolRouteType::Saber as u8; - - pack_array_string64(&self.name, name_out); - *version_out = self.version.to_le_bytes(); - pool_type_out[0] = self.pool_type as u8; - official_out[0] = self.official as u8; - pack_option_u32(self.refdb_index, refdb_index_out); - *refdb_counter_out = self.refdb_counter.to_le_bytes(); - pack_option_key(&self.token_a_ref, token_a_ref_out); - pack_option_key(&self.token_b_ref, token_b_ref_out); - pack_option_key(&self.lp_token_ref, lp_token_ref_out); - pack_option_key(&self.token_a_account, token_a_account_out); - pack_option_key(&self.token_b_account, token_b_account_out); - router_program_id_out.copy_from_slice(self.router_program_id.as_ref()); - pool_program_id_out.copy_from_slice(self.pool_program_id.as_ref()); - swap_account_out.copy_from_slice(swap_account.as_ref()); - swap_authority_out.copy_from_slice(swap_authority.as_ref()); - fees_account_a_out.copy_from_slice(fees_account_a.as_ref()); - fees_account_b_out.copy_from_slice(fees_account_b.as_ref()); - decimal_wrapper_program_out.copy_from_slice(decimal_wrapper_program.as_ref()); - pack_option_key(&wrapped_token_a_ref, wrapped_token_a_ref_out); - pack_option_key(&wrapped_token_a_vault, wrapped_token_a_vault_out); - pack_option_key(&decimal_wrapper_token_a, decimal_wrapper_token_a_out); - pack_option_key(&wrapped_token_b_ref, wrapped_token_b_ref_out); - pack_option_key(&wrapped_token_b_vault, wrapped_token_b_vault_out); - pack_option_key(&decimal_wrapper_token_b, decimal_wrapper_token_b_out); - - Ok(Pool::SABER_POOL_LEN) - } else { - Err(ProgramError::InvalidAccountData) - } - } - - fn pack_orca(&self, output: &mut [u8]) -> Result { - check_data_len(output, Pool::ORCA_POOL_LEN)?; - - if let PoolRoute::Orca { - amm_id, - amm_authority, - fees_account, - } = self.route - { - let output = array_mut_ref![output, 0, Pool::ORCA_POOL_LEN]; - - let ( - pool_route_type_out, - name_out, - version_out, - pool_type_out, - official_out, - refdb_index_out, - refdb_counter_out, - token_a_ref_out, - token_b_ref_out, - lp_token_ref_out, - token_a_account_out, - token_b_account_out, - router_program_id_out, - pool_program_id_out, - amm_id_out, - amm_authority_out, - fees_account_out, - ) = mut_array_refs![ - output, 1, 64, 2, 1, 1, 5, 2, 33, 33, 33, 33, 33, 32, 32, 32, 32, 32 - ]; - - pool_route_type_out[0] = PoolRouteType::Orca as u8; - - pack_array_string64(&self.name, name_out); - *version_out = self.version.to_le_bytes(); - pool_type_out[0] = self.pool_type as u8; - official_out[0] = self.official as u8; - pack_option_u32(self.refdb_index, refdb_index_out); - *refdb_counter_out = self.refdb_counter.to_le_bytes(); - pack_option_key(&self.token_a_ref, token_a_ref_out); - pack_option_key(&self.token_b_ref, token_b_ref_out); - pack_option_key(&self.lp_token_ref, lp_token_ref_out); - pack_option_key(&self.token_a_account, token_a_account_out); - pack_option_key(&self.token_b_account, token_b_account_out); - router_program_id_out.copy_from_slice(self.router_program_id.as_ref()); - pool_program_id_out.copy_from_slice(self.pool_program_id.as_ref()); - amm_id_out.copy_from_slice(amm_id.as_ref()); - amm_authority_out.copy_from_slice(amm_authority.as_ref()); - fees_account_out.copy_from_slice(fees_account.as_ref()); - - Ok(Pool::ORCA_POOL_LEN) - } else { - Err(ProgramError::InvalidAccountData) - } - } - - fn unpack_raydium(input: &[u8]) -> Result { - check_data_len(input, Pool::RAYDIUM_POOL_LEN)?; - - let input = array_ref![input, 1, Pool::RAYDIUM_POOL_LEN - 1]; - #[allow(clippy::ptr_offset_with_cast)] - let ( - name, - version, - pool_type, - official, - refdb_index, - refdb_counter, - token_a_ref, - token_b_ref, - lp_token_ref, - token_a_account, - token_b_account, - router_program_id, - pool_program_id, - amm_id, - amm_authority, - amm_open_orders, - amm_target, - pool_withdraw_queue, - pool_temp_lp_token_account, - serum_program_id, - serum_market, - serum_coin_vault_account, - serum_pc_vault_account, - serum_vault_signer, - serum_bids, - serum_asks, - serum_event_queue, - ) = array_refs![ - input, 64, 2, 1, 1, 5, 2, 33, 33, 33, 33, 33, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 33, 33, 33 - ]; - - Ok(Self { - name: unpack_array_string64(name)?, - version: u16::from_le_bytes(*version), - pool_type: PoolType::try_from_primitive(pool_type[0]) - .or(Err(ProgramError::InvalidAccountData))?, - official: unpack_bool(official)?, - refdb_index: unpack_option_u32(refdb_index)?, - refdb_counter: u16::from_le_bytes(*refdb_counter), - token_a_ref: unpack_option_key(token_a_ref)?, - token_b_ref: unpack_option_key(token_b_ref)?, - lp_token_ref: unpack_option_key(lp_token_ref)?, - token_a_account: unpack_option_key(token_a_account)?, - token_b_account: unpack_option_key(token_b_account)?, - router_program_id: Pubkey::new_from_array(*router_program_id), - pool_program_id: Pubkey::new_from_array(*pool_program_id), - route: PoolRoute::Raydium { - amm_id: Pubkey::new_from_array(*amm_id), - amm_authority: Pubkey::new_from_array(*amm_authority), - amm_open_orders: Pubkey::new_from_array(*amm_open_orders), - amm_target: Pubkey::new_from_array(*amm_target), - pool_withdraw_queue: Pubkey::new_from_array(*pool_withdraw_queue), - pool_temp_lp_token_account: Pubkey::new_from_array(*pool_temp_lp_token_account), - serum_program_id: Pubkey::new_from_array(*serum_program_id), - serum_market: Pubkey::new_from_array(*serum_market), - serum_coin_vault_account: Pubkey::new_from_array(*serum_coin_vault_account), - serum_pc_vault_account: Pubkey::new_from_array(*serum_pc_vault_account), - serum_vault_signer: Pubkey::new_from_array(*serum_vault_signer), - serum_bids: unpack_option_key(serum_bids)?, - serum_asks: unpack_option_key(serum_asks)?, - serum_event_queue: unpack_option_key(serum_event_queue)?, - }, - }) - } - - fn unpack_saber(input: &[u8]) -> Result { - check_data_len(input, Pool::SABER_POOL_LEN)?; - - let input = array_ref![input, 1, Pool::SABER_POOL_LEN - 1]; - #[allow(clippy::ptr_offset_with_cast)] - let ( - name, - version, - pool_type, - official, - refdb_index, - refdb_counter, - token_a_ref, - token_b_ref, - lp_token_ref, - token_a_account, - token_b_account, - router_program_id, - pool_program_id, - swap_account, - swap_authority, - fees_account_a, - fees_account_b, - decimal_wrapper_program, - wrapped_token_a_ref, - wrapped_token_a_vault, - decimal_wrapper_token_a, - wrapped_token_b_ref, - wrapped_token_b_vault, - decimal_wrapper_token_b, - ) = array_refs![ - input, 64, 2, 1, 1, 5, 2, 33, 33, 33, 33, 33, 32, 32, 32, 32, 32, 32, 32, 33, 33, 33, - 33, 33, 33 - ]; - - Ok(Self { - name: unpack_array_string64(name)?, - version: u16::from_le_bytes(*version), - pool_type: PoolType::try_from_primitive(pool_type[0]) - .or(Err(ProgramError::InvalidAccountData))?, - official: unpack_bool(official)?, - refdb_index: unpack_option_u32(refdb_index)?, - refdb_counter: u16::from_le_bytes(*refdb_counter), - token_a_ref: unpack_option_key(token_a_ref)?, - token_b_ref: unpack_option_key(token_b_ref)?, - lp_token_ref: unpack_option_key(lp_token_ref)?, - token_a_account: unpack_option_key(token_a_account)?, - token_b_account: unpack_option_key(token_b_account)?, - router_program_id: Pubkey::new_from_array(*router_program_id), - pool_program_id: Pubkey::new_from_array(*pool_program_id), - route: PoolRoute::Saber { - swap_account: Pubkey::new_from_array(*swap_account), - swap_authority: Pubkey::new_from_array(*swap_authority), - fees_account_a: Pubkey::new_from_array(*fees_account_a), - fees_account_b: Pubkey::new_from_array(*fees_account_b), - decimal_wrapper_program: Pubkey::new_from_array(*decimal_wrapper_program), - wrapped_token_a_ref: unpack_option_key(wrapped_token_a_ref)?, - wrapped_token_a_vault: unpack_option_key(wrapped_token_a_vault)?, - decimal_wrapper_token_a: unpack_option_key(decimal_wrapper_token_a)?, - wrapped_token_b_ref: unpack_option_key(wrapped_token_b_ref)?, - wrapped_token_b_vault: unpack_option_key(wrapped_token_b_vault)?, - decimal_wrapper_token_b: unpack_option_key(decimal_wrapper_token_b)?, - }, - }) - } - - fn unpack_orca(input: &[u8]) -> Result { - check_data_len(input, Pool::ORCA_POOL_LEN)?; - - let input = array_ref![input, 1, Pool::ORCA_POOL_LEN - 1]; - #[allow(clippy::ptr_offset_with_cast)] - let ( - name, - version, - pool_type, - official, - refdb_index, - refdb_counter, - token_a_ref, - token_b_ref, - lp_token_ref, - token_a_account, - token_b_account, - router_program_id, - pool_program_id, - amm_id, - amm_authority, - fees_account, - ) = array_refs![input, 64, 2, 1, 1, 5, 2, 33, 33, 33, 33, 33, 32, 32, 32, 32, 32]; - - Ok(Self { - name: unpack_array_string64(name)?, - version: u16::from_le_bytes(*version), - pool_type: PoolType::try_from_primitive(pool_type[0]) - .or(Err(ProgramError::InvalidAccountData))?, - official: unpack_bool(official)?, - refdb_index: unpack_option_u32(refdb_index)?, - refdb_counter: u16::from_le_bytes(*refdb_counter), - token_a_ref: unpack_option_key(token_a_ref)?, - token_b_ref: unpack_option_key(token_b_ref)?, - lp_token_ref: unpack_option_key(lp_token_ref)?, - token_a_account: unpack_option_key(token_a_account)?, - token_b_account: unpack_option_key(token_b_account)?, - router_program_id: Pubkey::new_from_array(*router_program_id), - pool_program_id: Pubkey::new_from_array(*pool_program_id), - route: PoolRoute::Orca { - amm_id: Pubkey::new_from_array(*amm_id), - amm_authority: Pubkey::new_from_array(*amm_authority), - fees_account: Pubkey::new_from_array(*fees_account), - }, - }) - } -} - -impl Packed for Pool { - fn get_size(&self) -> usize { - match self.route { - PoolRoute::Raydium { .. } => Pool::RAYDIUM_POOL_LEN, - PoolRoute::Saber { .. } => Pool::SABER_POOL_LEN, - PoolRoute::Orca { .. } => Pool::ORCA_POOL_LEN, - } - } - - fn pack(&self, output: &mut [u8]) -> Result { - match self.route { - PoolRoute::Raydium { .. } => self.pack_raydium(output), - PoolRoute::Saber { .. } => self.pack_saber(output), - PoolRoute::Orca { .. } => self.pack_orca(output), - } - } - - fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; Pool::MAX_LEN] = [0; Pool::MAX_LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidAccountData) - } - } - - fn unpack(input: &[u8]) -> Result { - check_data_len(input, 1)?; - let pool_route_type = PoolRouteType::try_from_primitive(input[0]) - .or(Err(ProgramError::InvalidAccountData))?; - match pool_route_type { - PoolRouteType::Raydium => Pool::unpack_raydium(input), - PoolRouteType::Saber => Pool::unpack_saber(input), - PoolRouteType::Orca => Pool::unpack_orca(input), - } - } -} - -impl std::fmt::Display for PoolType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match *self { - PoolType::Amm => write!(f, "Amm"), - PoolType::AmmStable => write!(f, "AmmStable"), - } - } -} - -impl std::fmt::Display for Pool { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", to_string(&self).unwrap()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_vec_serialization() { - let ri1 = Pool { - name: ArrayString64::from_utf8("test").unwrap(), - version: 2, - pool_type: PoolType::Amm, - official: true, - refdb_index: Some(1), - refdb_counter: 2, - token_a_ref: Some(Pubkey::new_unique()), - token_b_ref: Some(Pubkey::new_unique()), - lp_token_ref: Some(Pubkey::new_unique()), - token_a_account: None, - token_b_account: None, - router_program_id: Pubkey::new_unique(), - pool_program_id: Pubkey::new_unique(), - route: PoolRoute::Raydium { - amm_id: Pubkey::new_unique(), - amm_authority: Pubkey::new_unique(), - amm_open_orders: Pubkey::new_unique(), - amm_target: Pubkey::new_unique(), - pool_withdraw_queue: Pubkey::new_unique(), - pool_temp_lp_token_account: Pubkey::new_unique(), - serum_program_id: Pubkey::new_unique(), - serum_market: Pubkey::new_unique(), - serum_coin_vault_account: Pubkey::new_unique(), - serum_pc_vault_account: Pubkey::new_unique(), - serum_vault_signer: Pubkey::new_unique(), - serum_bids: Some(Pubkey::new_unique()), - serum_asks: Some(Pubkey::new_unique()), - serum_event_queue: Some(Pubkey::new_unique()), - }, - }; - - let vec = ri1.to_vec().unwrap(); - - let ri2 = Pool::unpack(&vec[..]).unwrap(); - - assert_eq!(ri1, ri2); - } -} diff --git a/farms/farm-sdk/src/program/account.rs b/farms/farm-sdk/src/program/account.rs deleted file mode 100644 index 46063f18abd..00000000000 --- a/farms/farm-sdk/src/program/account.rs +++ /dev/null @@ -1,696 +0,0 @@ -//! Common accounts management functions - -use { - crate::{ - error::FarmError, - id::zero, - math, - pack::check_data_len, - program::clock, - token::{OraclePrice, OracleType}, - traits::Packed, - }, - arrayref::{array_ref, array_refs}, - pyth_client::{PriceStatus, PriceType}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program::invoke, - program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, system_instruction, - sysvar, sysvar::Sysvar, - }, - spl_token::state::{Account, Mint}, - std::cmp::Ordering, -}; - -/// Returns Token Mint supply. -/// Extrats supply field without unpacking entire struct. -pub fn get_token_supply(token_mint: &AccountInfo) -> Result { - let data = token_mint.try_borrow_data()?; - check_data_len(&data, spl_token::state::Mint::get_packed_len())?; - let supply = array_ref![data, 36, 8]; - - Ok(u64::from_le_bytes(*supply)) -} - -/// Returns Token decimals. -/// Extrats decimals field without unpacking entire struct. -pub fn get_token_decimals(token_mint: &AccountInfo) -> Result { - let data = token_mint.try_borrow_data()?; - check_data_len(&data, spl_token::state::Mint::get_packed_len())?; - let decimals = array_ref![data, 44, 1]; - - Ok(decimals[0]) -} - -/// Returns Tokens balance. -/// Extrats balance field without unpacking entire struct. -pub fn get_token_balance(token_account: &AccountInfo) -> Result { - let data = token_account.try_borrow_data()?; - check_data_len(&data, spl_token::state::Account::get_packed_len())?; - let amount = array_ref![data, 64, 8]; - - Ok(u64::from_le_bytes(*amount)) -} - -/// Returns Token account owner. -/// Extrats owner field without unpacking entire struct. -pub fn get_token_account_owner(token_account: &AccountInfo) -> Result { - let data = token_account.try_borrow_data()?; - check_data_len(&data, spl_token::state::Account::get_packed_len())?; - let owner = array_ref![data, 32, 32]; - - Ok(Pubkey::new_from_array(*owner)) -} - -/// Checks Token account owner -pub fn check_token_account_owner( - token_account: &AccountInfo, - expected_owner: &Pubkey, -) -> Result { - Ok(token_account.owner == &spl_token::id() - && get_token_account_owner(token_account)? == *expected_owner) -} - -/// Checks Token account owner -pub fn check_token_account_owner_or_zero( - token_account: &AccountInfo, - expected_owner: &Pubkey, -) -> Result { - Ok(token_account.key == &zero::id() - || (token_account.owner == &spl_token::id() - && get_token_account_owner(token_account)? == *expected_owner)) -} - -/// Returns Token account mint. -/// Extrats mint field without unpacking entire struct. -pub fn get_token_account_mint(token_account: &AccountInfo) -> Result { - let data = token_account.try_borrow_data()?; - check_data_len(&data, spl_token::state::Account::get_packed_len())?; - let mint = array_ref![data, 0, 32]; - - Ok(Pubkey::new_from_array(*mint)) -} - -/// Returns Mint authority. -/// Extrats authority field without unpacking entire struct. -pub fn get_mint_authority(token_mint: &AccountInfo) -> Result, ProgramError> { - let data = token_mint.try_borrow_data()?; - check_data_len(&data, spl_token::state::Mint::get_packed_len())?; - - let data = array_ref![data, 0, 36]; - let (tag, authority) = array_refs![data, 4, 32]; - match *tag { - [0, 0, 0, 0] => Ok(None), - [1, 0, 0, 0] => Ok(Some(Pubkey::new_from_array(*authority))), - _ => Err(ProgramError::InvalidAccountData), - } -} - -/// Checks mint authority -pub fn check_mint_authority( - mint_account: &AccountInfo, - expected_authority: Option, -) -> Result { - Ok(mint_account.owner == &spl_token::id() - && get_mint_authority(mint_account)? == expected_authority) -} - -pub fn is_empty(account: &AccountInfo) -> Result { - Ok(account.data_is_empty() || account.try_lamports()? == 0) -} - -pub fn exists(account: &AccountInfo) -> Result { - Ok(account.try_lamports()? > 0) -} - -pub fn get_balance_increase( - account: &AccountInfo, - previous_balance: u64, -) -> Result { - let balance = get_token_balance(account)?; - if let Some(res) = balance.checked_sub(previous_balance) { - Ok(res) - } else { - msg!( - "Error: Balance decrease was not expected. Account: {}", - account.key - ); - Err(FarmError::UnexpectedBalanceDecrease.into()) - } -} - -pub fn get_balance_decrease( - account: &AccountInfo, - previous_balance: u64, -) -> Result { - let balance = get_token_balance(account)?; - if let Some(res) = previous_balance.checked_sub(balance) { - Ok(res) - } else { - msg!( - "Error: Balance increase was not expected. Account: {}", - account.key - ); - Err(FarmError::UnexpectedBalanceIncrease.into()) - } -} - -pub fn check_tokens_spent( - account: &AccountInfo, - previous_balance: u64, - max_amount_spent: u64, -) -> Result { - let tokens_spent = get_balance_decrease(account, previous_balance)?; - if tokens_spent > max_amount_spent { - msg!( - "Error: Invoked program overspent. Account: {}, max expected: {}, actual: {}", - account.key, - max_amount_spent, - tokens_spent - ); - Err(FarmError::ProgramOverspent.into()) - } else { - Ok(tokens_spent) - } -} - -pub fn check_tokens_received( - account: &AccountInfo, - previous_balance: u64, - min_amount_received: u64, -) -> Result { - let tokens_received = get_balance_increase(account, previous_balance)?; - if tokens_received < min_amount_received { - msg!( - "Error: Not enough tokens returned by invoked program. Account: {}, min expected: {}, actual: {}", - account.key, - min_amount_received, - tokens_received - ); - Err(FarmError::ProgramInsufficientTransfer.into()) - } else { - Ok(tokens_received) - } -} - -/// Returns Token Mint data. -pub fn get_token_mint(token_mint: &AccountInfo) -> Result { - let data = token_mint.try_borrow_data()?; - Mint::unpack(&data) -} - -/// Returns Token Account data. -pub fn get_token_account(token_account: &AccountInfo) -> Result { - let data = token_account.try_borrow_data()?; - Account::unpack(&data) -} - -/// Returns token pair ratio, optimized for on-chain. -pub fn get_token_ratio<'a, 'b>( - token_a_balance: u64, - token_b_balance: u64, - token_a_mint: &'a AccountInfo<'b>, - token_b_mint: &'a AccountInfo<'b>, -) -> Result { - get_token_ratio_with_decimals( - token_a_balance, - token_b_balance, - get_token_decimals(token_a_mint)?, - get_token_decimals(token_b_mint)?, - ) -} - -/// Returns token pair ratio, uses decimals instead of mints -pub fn get_token_ratio_with_decimals( - token_a_balance: u64, - token_b_balance: u64, - token_a_decimals: u8, - token_b_decimals: u8, -) -> Result { - if token_a_balance == 0 || token_b_balance == 0 { - return Ok(0.0); - } - - Ok(token_b_balance as f64 / token_a_balance as f64 - * math::checked_powi(10.0, token_a_decimals as i32 - token_b_decimals as i32)?) -} - -/// Returns token pair ratio -pub fn get_token_pair_ratio<'a, 'b>( - token_a_account: &'a AccountInfo<'b>, - token_b_account: &'a AccountInfo<'b>, -) -> Result { - let token_a_balance = get_token_balance(token_a_account)?; - let token_b_balance = get_token_balance(token_b_account)?; - if token_a_balance == 0 || token_b_balance == 0 { - return Ok(0.0); - } - Ok(token_b_balance as f64 / token_a_balance as f64) -} - -pub fn to_ui_amount(amount: u64, decimals: u8) -> f64 { - let mut ui_amount = amount as f64; - for _ in 0..decimals { - ui_amount /= 10.0; - } - ui_amount -} - -pub fn to_token_amount(ui_amount: f64, decimals: u8) -> Result { - let mut amount = ui_amount; - for _ in 0..decimals { - amount *= 10.0; - } - math::checked_as_u64(amount) -} - -pub fn to_amount_with_new_decimals( - amount: u64, - original_decimals: u8, - new_decimals: u8, -) -> Result { - match new_decimals.cmp(&original_decimals) { - Ordering::Greater => { - let exponent = new_decimals.checked_sub(original_decimals).unwrap(); - math::checked_mul(amount, math::checked_pow(10u64, exponent as usize)?) - } - Ordering::Less => { - let exponent = original_decimals.checked_sub(new_decimals).unwrap(); - math::checked_div(amount, math::checked_pow(10u64, exponent as usize)?) - } - Ordering::Equal => Ok(amount), - } -} - -pub fn init_token_account<'a, 'b>( - funding_account: &'a AccountInfo<'b>, - target_account: &'a AccountInfo<'b>, - mint_account: &'a AccountInfo<'b>, - owner_account: &'a AccountInfo<'b>, - rent_program: &'a AccountInfo<'b>, - seed: &str, -) -> ProgramResult { - if exists(target_account)? { - if !check_token_account_owner(target_account, owner_account.key)? { - return Err(ProgramError::IllegalOwner); - } - if target_account.data_len() != spl_token::state::Account::get_packed_len() - || mint_account.key != &get_token_account_mint(target_account)? - { - return Err(ProgramError::InvalidAccountData); - } - return Ok(()); - } - - init_system_account( - funding_account, - target_account, - &spl_token::id(), - seed, - spl_token::state::Account::get_packed_len(), - )?; - - invoke( - &spl_token::instruction::initialize_account( - &spl_token::id(), - target_account.key, - mint_account.key, - owner_account.key, - )?, - &[ - target_account.clone(), - mint_account.clone(), - owner_account.clone(), - rent_program.clone(), - ], - ) -} - -pub fn close_token_account<'a, 'b>( - receiving_account: &'a AccountInfo<'b>, - target_account: &'a AccountInfo<'b>, - authority_account: &'a AccountInfo<'b>, -) -> ProgramResult { - if !exists(target_account)? { - return Ok(()); - } - - invoke( - &spl_token::instruction::close_account( - &spl_token::id(), - target_account.key, - receiving_account.key, - authority_account.key, - &[], - )?, - &[ - target_account.clone(), - receiving_account.clone(), - authority_account.clone(), - ], - ) -} - -pub fn transfer_sol_from_owned<'a, 'b>( - program_owned_source_account: &'a AccountInfo<'b>, - destination_account: &'a AccountInfo<'b>, - amount: u64, -) -> ProgramResult { - **destination_account.try_borrow_mut_lamports()? = destination_account - .try_lamports()? - .checked_add(amount) - .ok_or(ProgramError::InsufficientFunds)?; - let source_balance = program_owned_source_account.try_lamports()?; - if source_balance < amount { - msg!( - "Error: Not enough funds to withdraw {} lamports from {}", - amount, - program_owned_source_account.key - ); - return Err(ProgramError::InsufficientFunds); - } - **program_owned_source_account.try_borrow_mut_lamports()? = source_balance - .checked_sub(amount) - .ok_or(ProgramError::InsufficientFunds)?; - - Ok(()) -} - -pub fn transfer_sol<'a, 'b>( - source_account: &'a AccountInfo<'b>, - destination_account: &'a AccountInfo<'b>, - amount: u64, -) -> ProgramResult { - if source_account.try_lamports()? < amount { - msg!( - "Error: Not enough funds to withdraw {} lamports from {}", - amount, - source_account.key - ); - return Err(ProgramError::InsufficientFunds); - } - invoke( - &system_instruction::transfer(source_account.key, destination_account.key, amount), - &[source_account.clone(), destination_account.clone()], - ) -} - -pub fn transfer_tokens<'a, 'b>( - source_account: &'a AccountInfo<'b>, - destination_account: &'a AccountInfo<'b>, - authority_account: &'a AccountInfo<'b>, - amount: u64, -) -> ProgramResult { - invoke( - &spl_token::instruction::transfer( - &spl_token::id(), - source_account.key, - destination_account.key, - authority_account.key, - &[], - amount, - )?, - &[ - source_account.clone(), - destination_account.clone(), - authority_account.clone(), - ], - ) -} - -pub fn burn_tokens<'a, 'b>( - from_token_account: &'a AccountInfo<'b>, - mint_account: &'a AccountInfo<'b>, - authority_account: &'a AccountInfo<'b>, - amount: u64, -) -> ProgramResult { - invoke( - &spl_token::instruction::burn( - &spl_token::id(), - from_token_account.key, - mint_account.key, - authority_account.key, - &[], - amount, - )?, - &[ - from_token_account.clone(), - mint_account.clone(), - authority_account.clone(), - ], - ) -} - -pub fn approve_delegate<'a, 'b>( - source_account: &'a AccountInfo<'b>, - delegate_account: &'a AccountInfo<'b>, - authority_account: &'a AccountInfo<'b>, - amount: u64, -) -> ProgramResult { - invoke( - &spl_token::instruction::approve( - &spl_token::id(), - source_account.key, - delegate_account.key, - authority_account.key, - &[], - amount, - )?, - &[ - source_account.clone(), - delegate_account.clone(), - authority_account.clone(), - ], - ) -} - -pub fn revoke_delegate<'a, 'b>( - source_account: &'a AccountInfo<'b>, - authority_account: &'a AccountInfo<'b>, -) -> ProgramResult { - invoke( - &spl_token::instruction::revoke( - &spl_token::id(), - source_account.key, - authority_account.key, - &[], - )?, - &[source_account.clone(), authority_account.clone()], - ) -} - -pub fn init_system_account<'a, 'b>( - funding_account: &'a AccountInfo<'b>, - target_account: &'a AccountInfo<'b>, - owner_key: &Pubkey, - seed: &str, - data_size: usize, -) -> ProgramResult { - if exists(target_account)? { - if target_account.owner != owner_key { - return Err(ProgramError::IllegalOwner); - } - if target_account.data_len() != data_size { - return Err(ProgramError::InvalidAccountData); - } - return Ok(()); - } - - let derived_account = Pubkey::create_with_seed(funding_account.key, seed, owner_key)?; - if target_account.key != &derived_account { - return Err(ProgramError::InvalidSeeds); - } - - let min_balance = sysvar::rent::Rent::get() - .unwrap() - .minimum_balance(data_size); - invoke( - &system_instruction::create_account_with_seed( - funding_account.key, - target_account.key, - funding_account.key, - seed, - min_balance, - data_size as u64, - owner_key, - ), - &[funding_account.clone(), target_account.clone()], - ) -} - -pub fn close_system_account<'a, 'b>( - receiving_account: &'a AccountInfo<'b>, - target_account: &'a AccountInfo<'b>, - authority_account: &Pubkey, -) -> ProgramResult { - if *target_account.owner != *authority_account { - return Err(ProgramError::IllegalOwner); - } - let cur_balance = target_account.try_lamports()?; - transfer_sol_from_owned(target_account, receiving_account, cur_balance)?; - - if target_account.data_len() > 2000 { - target_account.try_borrow_mut_data()?[..2000].fill(0); - } else { - target_account.try_borrow_mut_data()?.fill(0); - } - - Ok(()) -} - -pub fn get_oracle_price( - oracle_type: OracleType, - oracle_account: &AccountInfo, - max_price_error: f64, - max_price_age_sec: u64, -) -> Result { - match oracle_type { - OracleType::Pyth => get_pyth_price(oracle_account, max_price_error, max_price_age_sec), - _ => Err(ProgramError::UnsupportedSysvar), - } -} - -pub fn get_pyth_price( - pyth_price_info: &AccountInfo, - max_price_error: f64, - max_price_age_sec: u64, -) -> Result { - if is_empty(pyth_price_info)? { - msg!("Error: Invalid Pyth oracle account"); - return Err(FarmError::OracleInvalidAccount.into()); - } - - let pyth_price_data = &pyth_price_info.try_borrow_data()?; - let pyth_price = pyth_client::load_price(pyth_price_data)?; - - if !matches!(pyth_price.agg.status, PriceStatus::Trading) - || !matches!(pyth_price.ptype, PriceType::Price) - { - msg!("Error: Pyth oracle price has invalid state"); - return Err(FarmError::OracleInvalidState.into()); - } - - let last_update_age_sec = math::checked_mul( - math::checked_sub(clock::get_slot()?, pyth_price.valid_slot)?, - solana_program::clock::DEFAULT_MS_PER_SLOT, - )? / 1000; - if last_update_age_sec > max_price_age_sec { - msg!("Error: Pyth oracle price is stale"); - return Err(FarmError::OracleStalePrice.into()); - } - - if pyth_price.agg.price <= 0 - || pyth_price.agg.conf as f64 / pyth_price.agg.price as f64 > max_price_error - { - msg!("Error: Pyth oracle price is out of bounds"); - return Err(FarmError::OracleInvalidPrice.into()); - } - - Ok(OraclePrice { - // price is i64 and > 0 per check above - price: pyth_price.agg.price as u64, - exponent: pyth_price.expo, - }) -} - -// Converts token amount to USD using price oracle -pub fn get_asset_value_usd( - amount: u64, - decimals: u8, - oracle_type: OracleType, - oracle_account: &AccountInfo, - max_price_error: f64, - max_price_age_sec: u64, -) -> Result { - if amount == 0 { - return Ok(0.0); - } - let oracle_price = get_oracle_price( - oracle_type, - oracle_account, - max_price_error, - max_price_age_sec, - )?; - - Ok(amount as f64 * oracle_price.price as f64 - / math::checked_powi(10.0, decimals as i32 - oracle_price.exponent)?) -} - -// Converts USD amount to tokens using price oracle -pub fn get_asset_value_tokens( - usd_amount: f64, - token_decimals: u8, - oracle_type: OracleType, - oracle_account: &AccountInfo, - max_price_error: f64, - max_price_age_sec: u64, -) -> Result { - if usd_amount == 0.0 { - return Ok(0); - } - let oracle_price = get_oracle_price( - oracle_type, - oracle_account, - max_price_error, - max_price_age_sec, - )?; - - // oracle_price.price guaranteed > 0 - math::checked_as_u64( - usd_amount as f64 / oracle_price.price as f64 - * math::checked_powi(10.0, token_decimals as i32 - oracle_price.exponent)?, - ) -} - -pub fn unpack(account: &AccountInfo, name: &str) -> Result { - if let Ok(object) = T::unpack(&account.try_borrow_data()?) { - Ok(object) - } else { - msg!("Error: Failed to load {} metadata", name); - Err(ProgramError::InvalidAccountData) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use spl_token::state::{Account, Mint}; - - #[test] - fn test_mint_supply_offset() { - let mint = Mint { - supply: 1234567891011, - ..Mint::default() - }; - let mut packed: [u8; 82] = [0; 82]; - Mint::pack(mint, &mut packed).unwrap(); - - let supply = array_ref![packed, 36, 8]; - assert_eq!(1234567891011, u64::from_le_bytes(*supply)); - } - - #[test] - fn test_mint_decimals_offset() { - let mint = Mint { - decimals: 123, - ..Mint::default() - }; - let mut packed: [u8; 82] = [0; 82]; - Mint::pack(mint, &mut packed).unwrap(); - - let decimals = array_ref![packed, 44, 1]; - assert_eq!(123, decimals[0]); - } - - #[test] - fn test_account_amount_offset() { - let account = Account { - amount: 1234567891011, - ..Account::default() - }; - let mut packed: [u8; 165] = [0; 165]; - Account::pack(account, &mut packed).unwrap(); - - let amount = array_ref![packed, 64, 8]; - assert_eq!(1234567891011, u64::from_le_bytes(*amount)); - } -} diff --git a/farms/farm-sdk/src/program/clock.rs b/farms/farm-sdk/src/program/clock.rs deleted file mode 100644 index 6c96e465f58..00000000000 --- a/farms/farm-sdk/src/program/clock.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! Timing functions - -use { - crate::math, - solana_program::{clock::UnixTimestamp, program_error::ProgramError, sysvar, sysvar::Sysvar}, -}; - -pub fn get_time() -> Result { - Ok(sysvar::clock::Clock::get()?.unix_timestamp) -} - -pub fn get_time_as_u64() -> Result { - math::checked_as_u64(sysvar::clock::Clock::get()?.unix_timestamp) -} - -pub fn get_slot() -> Result { - Ok(sysvar::clock::Clock::get()?.slot) -} - -/* -pub fn unix_timestamp_to_string(unix_timestamp: UnixTimestamp) -> String { - match NaiveDateTime::from_timestamp_opt(unix_timestamp, 0) { - Some(ndt) => DateTime::::from_utc(ndt, Utc).to_rfc3339_opts(SecondsFormat::Secs, true), - None => format!("UnixTimestamp {}", unix_timestamp), - } -} -*/ diff --git a/farms/farm-sdk/src/program/mod.rs b/farms/farm-sdk/src/program/mod.rs deleted file mode 100644 index 9f43fa86629..00000000000 --- a/farms/farm-sdk/src/program/mod.rs +++ /dev/null @@ -1,46 +0,0 @@ -pub mod account; -pub mod clock; -pub mod multisig; -pub mod pda; -pub mod protocol; - -use solana_program::{ - account_info::AccountInfo, program_error::ProgramError, sysvar::instructions, -}; - -/// Returns true if currently executing instruction is the only instruction in the transaction -pub fn is_single_instruction(sysvar_account: &AccountInfo) -> Result { - if &instructions::id() != sysvar_account.key { - return Err(ProgramError::UnsupportedSysvar); - } - Ok( - instructions::load_current_index_checked(sysvar_account)? == 0 - && instructions::load_instruction_at_checked(1, sysvar_account).is_err(), - ) -} - -/// Returns true if currently executing instruction is first or last instruction in the transaction -pub fn is_first_or_last_instruction(sysvar_account: &AccountInfo) -> Result { - if &instructions::id() != sysvar_account.key { - return Err(ProgramError::UnsupportedSysvar); - } - let instruction_index = instructions::load_current_index_checked(sysvar_account)?; - Ok(instruction_index == 0 - || instructions::load_instruction_at_checked( - instruction_index as usize + 1, - sysvar_account, - ) - .is_err()) -} - -/// Returns true if currently executing instruction is the last instruction in the transaction -pub fn is_last_instruction(sysvar_account: &AccountInfo) -> Result { - if &instructions::id() != sysvar_account.key { - return Err(ProgramError::UnsupportedSysvar); - } - let instruction_index = instructions::load_current_index_checked(sysvar_account)?; - Ok( - instructions::load_instruction_at_checked(instruction_index as usize + 1, sysvar_account) - .is_err(), - ) -} diff --git a/farms/farm-sdk/src/program/multisig.rs b/farms/farm-sdk/src/program/multisig.rs deleted file mode 100644 index 30a87d4ed86..00000000000 --- a/farms/farm-sdk/src/program/multisig.rs +++ /dev/null @@ -1,477 +0,0 @@ -//! Multisignatures handling routines - -use { - crate::{ - error::FarmError, - id::{main_router_admin, zero}, - pack::*, - program::account, - traits::*, - }, - ahash::AHasher, - arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}, - serde::{Deserialize, Serialize}, - serde_json::to_string, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - pubkey::Pubkey, - }, - std::hash::Hasher, -}; - -#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] -pub struct Multisig { - pub num_signers: u8, - pub num_signed: u8, - pub min_signatures: u8, - pub instruction_accounts_len: u8, - pub instruction_data_len: u16, - pub instruction_hash: u64, - #[serde(serialize_with = "pubkey_slice_serialize")] - pub signers: [Pubkey; Multisig::MAX_SIGNERS], - pub signed: [bool; Multisig::MAX_SIGNERS], -} - -/// Returns instruction accounts and data hash. -/// Hash is not cryptographic and is meant to perform a fast check that admins are signing -/// the same instruction. -pub fn get_instruction_hash(instruction_accounts: &[AccountInfo], instruction_data: &[u8]) -> u64 { - let mut hasher = AHasher::new_with_keys(697533735114380, 537268678243635); - for account in instruction_accounts { - hasher.write(account.key.as_ref()); - } - if !instruction_data.is_empty() { - hasher.write(instruction_data); - } - hasher.finish() -} - -/// Initializes multisig PDA with a new set of signers -pub fn set_signers( - multisig_account: &AccountInfo, - admin_signers: &[AccountInfo], - min_signatures: u8, -) -> Result { - if admin_signers.is_empty() || min_signatures == 0 { - msg!("Error: At least one signer is required"); - return Err(ProgramError::MissingRequiredSignature); - } - if (min_signatures as usize) > admin_signers.len() { - msg!( - "Error: Number of min signatures ({}) exceeded number of signers ({})", - min_signatures, - admin_signers.len(), - ); - return Err(ProgramError::InvalidArgument); - } - if admin_signers.len() > Multisig::MAX_SIGNERS { - msg!( - "Error: Number of signers ({}) exceeded max ({})", - admin_signers.len(), - Multisig::MAX_SIGNERS - ); - return Err(ProgramError::InvalidArgument); - } - - let mut signers: [Pubkey; Multisig::MAX_SIGNERS] = Default::default(); - let mut signed: [bool; Multisig::MAX_SIGNERS] = Default::default(); - - for idx in 0..admin_signers.len() as usize { - if signers.contains(admin_signers[idx].key) { - msg!("Error: Duplicate signer {}", admin_signers[idx].key); - return Err(FarmError::IncorrectAccountAddress.into()); - } - signers[idx] = *admin_signers[idx].key; - signed[idx] = false; - } - - Multisig { - num_signers: admin_signers.len() as u8, - num_signed: 0, - min_signatures, - instruction_accounts_len: 0, - instruction_data_len: 0, - instruction_hash: 0, - signers, - signed, - } - .pack(*multisig_account.try_borrow_mut_data()?) -} - -/// Signs multisig and returns Ok(0) if there are enough signatures to continue or Ok(signatures_left) otherwise. -/// If Err() is returned then signature was not recognized and transaction must be aborted. -pub fn sign_multisig( - multisig_account: &AccountInfo, - signer_account: &AccountInfo, - fallback_admin_account: &Pubkey, - instruction_accounts: &[AccountInfo], - instruction_data: &[u8], -) -> Result { - // return early if not a signer - if !signer_account.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - // if multisig is empty check that signer is a main router admin - if !account::exists(multisig_account)? { - if signer_account.key != fallback_admin_account { - msg!("Error: Account is not authorized to sign this instruction"); - return Err(FarmError::AccountNotAuthorized.into()); - } else { - return Ok(0); - } - } - - // unpack multisig PDA - let mut multisig = account::unpack::(multisig_account, "multisig_account")?; - - // find index of current signer or return error if not found - let signer_idx = if let Ok(idx) = get_signer_index(&multisig, signer_account.key) { - idx - } else { - msg!("Error: Account is not a signer in this multisig"); - return Err(FarmError::AccountNotAuthorized.into()); - }; - - // if single signer return Ok to continue - if multisig.num_signers <= 1 { - return Ok(0); - } - - let instruction_hash = get_instruction_hash(instruction_accounts, instruction_data); - if instruction_hash != multisig.instruction_hash - || instruction_accounts.len() != multisig.instruction_accounts_len as usize - || instruction_data.len() != multisig.instruction_data_len as usize - { - // if this is a new instruction reset the data - multisig.num_signed = 1; - multisig.instruction_accounts_len = instruction_accounts.len() as u8; - multisig.instruction_data_len = instruction_data.len() as u16; - multisig.instruction_hash = instruction_hash; - multisig.signed.fill(false); - multisig.signed[signer_idx] = true; - multisig.pack(*multisig_account.try_borrow_mut_data()?)?; - - Ok(multisig.min_signatures - 1) - } else if multisig.signed[signer_idx] { - msg!("Error: Account has already signed this instruction"); - Err(FarmError::AlreadySigned.into()) - } else if multisig.num_signed < multisig.min_signatures { - // count the signature in - multisig.num_signed += 1; - multisig.signed[signer_idx] = true; - multisig.pack(*multisig_account.try_borrow_mut_data()?)?; - - if multisig.num_signed == multisig.min_signatures { - Ok(0) - } else { - Ok(multisig.min_signatures - multisig.num_signed) - } - } else { - msg!("Error: This instruction has already been executed"); - Err(FarmError::AlreadyExecuted.into()) - } -} - -/// Removes admin signature from the multisig -pub fn unsign_multisig( - multisig_account: &AccountInfo, - signer_account: &AccountInfo, -) -> ProgramResult { - // return early if not a signer - if !signer_account.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - // if multisig doesn't exist return - if !account::exists(multisig_account)? { - return Ok(()); - } - - // unpack multisig PDA - let mut multisig = account::unpack::(multisig_account, "multisig_account")?; - - // if single signer return - if multisig.num_signers <= 1 || multisig.num_signed == 0 { - return Ok(()); - } - - // find index of current signer or return error if not found - let signer_idx = if let Ok(idx) = get_signer_index(&multisig, signer_account.key) { - idx - } else { - msg!("Error: Account is not a signer in this multisig"); - return Err(FarmError::AccountNotAuthorized.into()); - }; - - // if not signed by this account return - if !multisig.signed[signer_idx] { - return Ok(()); - } - - // remove signature - multisig.num_signed -= 1; - multisig.signed[signer_idx] = false; - - multisig.pack(*multisig_account.try_borrow_mut_data()?)?; - - Ok(()) -} - -/// Returns the array index of the provided signer -pub fn get_signer_index(multisig: &Multisig, signer: &Pubkey) -> Result { - for i in 0..Multisig::MAX_SIGNERS { - if &multisig.signers[i] == signer { - return Ok(i); - } - } - Err(FarmError::AccountNotAuthorized.into()) -} - -/// Checks if provided account is one of multisig signers -pub fn is_signer( - multisig_account: &AccountInfo, - fallback_admin_account: &Pubkey, - key: &Pubkey, -) -> Result { - if !account::exists(multisig_account)? { - return Ok(key == fallback_admin_account); - } - - // unpack multisig PDA - let multisig = account::unpack::(multisig_account, "multisig_account")?; - - Ok(get_signer_index(&multisig, key).is_ok()) -} - -impl Multisig { - pub const MAX_SIGNERS: usize = 6; - pub const LEN: usize = 14 + Multisig::MAX_SIGNERS * 33; -} - -impl Packed for Multisig { - fn get_size(&self) -> usize { - Self::LEN - } - - fn pack(&self, output: &mut [u8]) -> Result { - check_data_len(output, Self::LEN)?; - - let output = array_mut_ref![output, 0, Multisig::LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let ( - num_signers_out, - num_signed_out, - min_signatures_out, - instruction_accounts_len_out, - instruction_data_len_out, - instruction_hash_out, - signers_out, - signed_out, - ) = mut_array_refs![ - output, - 1, - 1, - 1, - 1, - 2, - 8, - 32usize * Multisig::MAX_SIGNERS, - Multisig::MAX_SIGNERS - ]; - - num_signers_out[0] = self.num_signers; - num_signed_out[0] = self.num_signed; - min_signatures_out[0] = self.min_signatures; - instruction_accounts_len_out[0] = self.instruction_accounts_len; - *instruction_data_len_out = self.instruction_data_len.to_le_bytes(); - *instruction_hash_out = self.instruction_hash.to_le_bytes(); - for idx in 0..self.num_signers as usize { - signers_out[idx * 32..idx * 32 + 32].copy_from_slice(self.signers[idx].as_ref()); - signed_out[idx] = self.signed[idx] as u8; - } - signers_out[(self.num_signers * 32) as usize..].fill(0); - signed_out[self.num_signers as usize..].fill(0); - - Ok(Self::LEN) - } - - fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; Self::LEN] = [0; Self::LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidAccountData) - } - } - - fn unpack(input: &[u8]) -> Result { - check_data_len(input, Self::LEN)?; - - let input = array_ref![input, 0, Multisig::LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let ( - num_signers, - num_signed, - min_signatures, - instruction_accounts_len, - instruction_data_len, - instruction_hash, - signers_ref, - signed_ref, - ) = array_refs![ - input, - 1, - 1, - 1, - 1, - 2, - 8, - 32 * Multisig::MAX_SIGNERS, - Multisig::MAX_SIGNERS - ]; - - let mut signers: [Pubkey; Multisig::MAX_SIGNERS] = Default::default(); - let mut signed: [bool; Multisig::MAX_SIGNERS] = Default::default(); - let num_signers = num_signers[0]; - let num_signed = num_signed[0]; - let min_signatures = min_signatures[0]; - if num_signers as usize > Multisig::MAX_SIGNERS - || num_signed > num_signers - || min_signatures > num_signers - || (num_signers > 0 && min_signatures == 0) - { - return Err(ProgramError::InvalidAccountData); - } - - for idx in 0..num_signers as usize { - signers[idx] = Pubkey::new(&signers_ref[idx * 32..idx * 32 + 32]); - signed[idx] = match signed_ref[idx] { - 0 => false, - 1 => true, - _ => return Err(ProgramError::InvalidAccountData), - }; - } - for idx in (num_signers as usize)..Multisig::MAX_SIGNERS { - signers[idx] = zero::id(); - signed[idx] = false; - } - - Ok(Self { - num_signers, - num_signed, - min_signatures, - instruction_accounts_len: instruction_accounts_len[0], - instruction_data_len: u16::from_le_bytes(*instruction_data_len), - instruction_hash: u64::from_le_bytes(*instruction_hash), - signers, - signed, - }) - } -} - -impl Default for Multisig { - fn default() -> Self { - Self { - num_signers: 1, - num_signed: 0, - min_signatures: 1, - instruction_accounts_len: 0, - instruction_data_len: 0, - instruction_hash: 0, - signers: [ - main_router_admin::id(), - zero::id(), - zero::id(), - zero::id(), - zero::id(), - zero::id(), - ], - signed: [false, false, false, false, false, false], - } - } -} - -impl std::fmt::Display for Multisig { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", to_string(&self).unwrap()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_vec_serialization() { - let ri1 = Multisig { - num_signers: 2, - num_signed: 1, - min_signatures: 2, - instruction_accounts_len: 3, - instruction_data_len: 123, - instruction_hash: 123456789, - signers: [ - Pubkey::new_unique(), - Pubkey::new_unique(), - zero::id(), - zero::id(), - zero::id(), - zero::id(), - ], - signed: [false, true, false, false, false, false], - }; - - let vec = ri1.to_vec().unwrap(); - - let ri2 = Multisig::unpack(&vec[..]).unwrap(); - - assert_eq!(ri1, ri2); - - let ri1 = Multisig { - num_signers: 6, - num_signed: 1, - min_signatures: 6, - instruction_accounts_len: 10, - instruction_data_len: 123, - instruction_hash: 987654321, - signers: [ - Pubkey::new_unique(), - Pubkey::new_unique(), - Pubkey::new_unique(), - Pubkey::new_unique(), - Pubkey::new_unique(), - Pubkey::new_unique(), - ], - signed: [false, false, false, false, false, true], - }; - - let vec = ri1.to_vec().unwrap(); - - let ri2 = Multisig::unpack(&vec[..]).unwrap(); - - assert_eq!(ri1, ri2); - - let ri1 = Multisig { - num_signers: 0, - num_signed: 0, - min_signatures: 0, - instruction_accounts_len: 0, - instruction_data_len: 0, - instruction_hash: 0, - signers: [ - zero::id(), - zero::id(), - zero::id(), - zero::id(), - zero::id(), - zero::id(), - ], - signed: [false, false, false, false, false, false], - }; - - let vec = ri1.to_vec().unwrap(); - - let ri2 = Multisig::unpack(&vec[..]).unwrap(); - - assert_eq!(ri1, ri2); - } -} diff --git a/farms/farm-sdk/src/program/pda.rs b/farms/farm-sdk/src/program/pda.rs deleted file mode 100644 index 03b132af372..00000000000 --- a/farms/farm-sdk/src/program/pda.rs +++ /dev/null @@ -1,518 +0,0 @@ -//! Common PDA functions - -use { - crate::program::account, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, program, program_error::ProgramError, - program_pack::Pack, pubkey::Pubkey, rent::Rent, system_instruction, sysvar, sysvar::Sysvar, - }, -}; - -pub fn init_token_account<'a, 'b>( - funding_account: &'a AccountInfo<'b>, - target_account: &'a AccountInfo<'b>, - mint_account: &'a AccountInfo<'b>, - owner_account: &'a AccountInfo<'b>, - rent_program: &'a AccountInfo<'b>, - base_address: &Pubkey, - seeds: &[&[u8]], -) -> ProgramResult { - if account::exists(target_account)? { - if !account::check_token_account_owner(target_account, owner_account.key)? { - return Err(ProgramError::IllegalOwner); - } - if target_account.data_len() != spl_token::state::Account::get_packed_len() - || mint_account.key != &account::get_token_account_mint(target_account)? - { - return Err(ProgramError::InvalidAccountData); - } - return Ok(()); - } - - init_system_account( - funding_account, - target_account, - &spl_token::id(), - base_address, - seeds, - spl_token::state::Account::get_packed_len(), - )?; - - program::invoke( - &spl_token::instruction::initialize_account( - &spl_token::id(), - target_account.key, - mint_account.key, - owner_account.key, - )?, - &[ - target_account.clone(), - mint_account.clone(), - owner_account.clone(), - rent_program.clone(), - ], - ) -} - -pub fn init_associated_token_account<'a, 'b>( - funding_account: &'a AccountInfo<'b>, - wallet_account: &'a AccountInfo<'b>, - target_account: &'a AccountInfo<'b>, - mint_account: &'a AccountInfo<'b>, - rent_program: &'a AccountInfo<'b>, -) -> ProgramResult { - if account::exists(target_account)? { - if !account::check_token_account_owner(target_account, wallet_account.key)? { - return Err(ProgramError::IllegalOwner); - } - if target_account.data_len() != spl_token::state::Account::get_packed_len() - || mint_account.key != &account::get_token_account_mint(target_account)? - { - return Err(ProgramError::InvalidAccountData); - } - return Ok(()); - } - - program::invoke( - &spl_associated_token_account::create_associated_token_account( - funding_account.key, - wallet_account.key, - mint_account.key, - ), - &[ - funding_account.clone(), - target_account.clone(), - wallet_account.clone(), - mint_account.clone(), - rent_program.clone(), - ], - ) -} - -pub fn close_token_account_with_seeds<'a, 'b>( - receiving_account: &'a AccountInfo<'b>, - target_account: &'a AccountInfo<'b>, - authority_account: &'a AccountInfo<'b>, - seeds: &[&[&[u8]]], -) -> ProgramResult { - if !account::exists(target_account)? { - return Ok(()); - } - - program::invoke_signed( - &spl_token::instruction::close_account( - &spl_token::id(), - target_account.key, - receiving_account.key, - authority_account.key, - &[], - )?, - &[ - target_account.clone(), - receiving_account.clone(), - authority_account.clone(), - ], - seeds, - ) -} - -pub fn close_token_account<'a, 'b>( - receiving_account: &'a AccountInfo<'b>, - target_account: &'a AccountInfo<'b>, - authority_account: &'a AccountInfo<'b>, - base_address: &Pubkey, - seeds: &[&[u8]], -) -> Result { - let (_, bump) = Pubkey::find_program_address(seeds, base_address); - - close_token_account_with_seeds( - receiving_account, - target_account, - authority_account, - &[&[seeds, &[&[bump]]].concat()], - )?; - - Ok(bump) -} - -pub fn transfer_tokens_with_seeds<'a, 'b>( - source_account: &'a AccountInfo<'b>, - destination_account: &'a AccountInfo<'b>, - authority_account: &'a AccountInfo<'b>, - seeds: &[&[&[u8]]], - amount: u64, -) -> ProgramResult { - if source_account.key == destination_account.key { - return Err(ProgramError::InvalidArgument); - } - program::invoke_signed( - &spl_token::instruction::transfer( - &spl_token::id(), - source_account.key, - destination_account.key, - authority_account.key, - &[], - amount, - )?, - &[ - source_account.clone(), - destination_account.clone(), - authority_account.clone(), - ], - seeds, - ) -} - -pub fn transfer_tokens<'a, 'b>( - source_account: &'a AccountInfo<'b>, - destination_account: &'a AccountInfo<'b>, - authority_account: &'a AccountInfo<'b>, - base_address: &Pubkey, - seeds: &[&[u8]], - amount: u64, -) -> Result { - let (_, bump) = Pubkey::find_program_address(seeds, base_address); - - transfer_tokens_with_seeds( - source_account, - destination_account, - authority_account, - &[&[seeds, &[&[bump]]].concat()], - amount, - )?; - - Ok(bump) -} - -pub fn init_system_account<'a, 'b>( - funding_account: &'a AccountInfo<'b>, - target_account: &'a AccountInfo<'b>, - owner_key: &Pubkey, - base_address: &Pubkey, - seeds: &[&[u8]], - data_size: usize, -) -> Result { - if account::exists(target_account)? { - if target_account.owner != owner_key { - return Err(ProgramError::IllegalOwner); - } - if target_account.data_len() != data_size { - return Err(ProgramError::InvalidAccountData); - } - return Ok(Pubkey::find_program_address(seeds, base_address).1); - } - - let (key, bump) = Pubkey::find_program_address(seeds, base_address); - if target_account.key != &key { - return Err(ProgramError::InvalidSeeds); - } - - let min_balance = sysvar::rent::Rent::get() - .unwrap() - .minimum_balance(data_size); - program::invoke_signed( - &system_instruction::create_account( - funding_account.key, - target_account.key, - min_balance, - data_size as u64, - owner_key, - ), - &[funding_account.clone(), target_account.clone()], - &[&[seeds, &[&[bump]]].concat()], - )?; - - Ok(bump) -} - -pub fn init_mint<'a, 'b>( - funding_account: &'a AccountInfo<'b>, - mint_account: &'a AccountInfo<'b>, - authority_account: &'a AccountInfo<'b>, - rent_program: &'a AccountInfo<'b>, - base_address: &Pubkey, - seeds: &[&[u8]], - decimals: u8, -) -> ProgramResult { - if account::exists(mint_account)? { - if !account::check_mint_authority(mint_account, Some(*authority_account.key))? { - return Err(ProgramError::IllegalOwner); - } - if mint_account.data_len() != spl_token::state::Mint::get_packed_len() { - return Err(ProgramError::InvalidAccountData); - } - return Ok(()); - } - - let acc_size = spl_token::state::Mint::get_packed_len(); - init_system_account( - funding_account, - mint_account, - &spl_token::id(), - base_address, - seeds, - acc_size, - )?; - - program::invoke( - &spl_token::instruction::initialize_mint( - &spl_token::id(), - mint_account.key, - authority_account.key, - Some(authority_account.key), - decimals, - )?, - &[ - mint_account.clone(), - authority_account.clone(), - rent_program.clone(), - ], - ) -} - -pub fn mint_to_with_seeds<'a, 'b>( - target_token_account: &'a AccountInfo<'b>, - mint_account: &'a AccountInfo<'b>, - mint_authority_account: &'a AccountInfo<'b>, - seeds: &[&[&[u8]]], - amount: u64, -) -> ProgramResult { - solana_program::program::invoke_signed( - &spl_token::instruction::mint_to( - &spl_token::id(), - mint_account.key, - target_token_account.key, - mint_authority_account.key, - &[], - amount, - )?, - &[ - mint_account.clone(), - target_token_account.clone(), - mint_authority_account.clone(), - ], - seeds, - ) -} - -pub fn mint_to<'a, 'b>( - target_token_account: &'a AccountInfo<'b>, - mint_account: &'a AccountInfo<'b>, - mint_authority_account: &'a AccountInfo<'b>, - base_address: &Pubkey, - seeds: &[&[u8]], - amount: u64, -) -> Result { - let (_, bump) = Pubkey::find_program_address(seeds, base_address); - - mint_to_with_seeds( - target_token_account, - mint_account, - mint_authority_account, - &[&[seeds, &[&[bump]]].concat()], - amount, - )?; - - Ok(bump) -} - -pub fn burn_tokens_with_seeds<'a, 'b>( - from_token_account: &'a AccountInfo<'b>, - mint_account: &'a AccountInfo<'b>, - authority_account: &'a AccountInfo<'b>, - seeds: &[&[&[u8]]], - amount: u64, -) -> ProgramResult { - solana_program::program::invoke_signed( - &spl_token::instruction::burn( - &spl_token::id(), - from_token_account.key, - mint_account.key, - authority_account.key, - &[], - amount, - )?, - &[ - from_token_account.clone(), - mint_account.clone(), - authority_account.clone(), - ], - seeds, - ) -} - -pub fn burn_tokens<'a, 'b>( - from_token_account: &'a AccountInfo<'b>, - mint_account: &'a AccountInfo<'b>, - authority_account: &'a AccountInfo<'b>, - base_address: &Pubkey, - seeds: &[&[u8]], - amount: u64, -) -> Result { - let (_, bump) = Pubkey::find_program_address(seeds, base_address); - - burn_tokens_with_seeds( - from_token_account, - mint_account, - authority_account, - &[&[seeds, &[&[bump]]].concat()], - amount, - )?; - - Ok(bump) -} - -pub fn approve_delegate_with_seeds<'a, 'b>( - source_account: &'a AccountInfo<'b>, - delegate_account: &'a AccountInfo<'b>, - authority_account: &'a AccountInfo<'b>, - seeds: &[&[&[u8]]], - amount: u64, -) -> ProgramResult { - solana_program::program::invoke_signed( - &spl_token::instruction::approve( - &spl_token::id(), - source_account.key, - delegate_account.key, - authority_account.key, - &[], - amount, - )?, - &[ - source_account.clone(), - delegate_account.clone(), - authority_account.clone(), - ], - seeds, - ) -} - -pub fn approve_delegate<'a, 'b>( - source_account: &'a AccountInfo<'b>, - delegate_account: &'a AccountInfo<'b>, - authority_account: &'a AccountInfo<'b>, - base_address: &Pubkey, - seeds: &[&[u8]], - amount: u64, -) -> Result { - let (_, bump) = Pubkey::find_program_address(seeds, base_address); - - approve_delegate_with_seeds( - source_account, - delegate_account, - authority_account, - &[&[seeds, &[&[bump]]].concat()], - amount, - )?; - - Ok(bump) -} - -pub fn revoke_delegate_with_seeds<'a, 'b>( - source_account: &'a AccountInfo<'b>, - authority_account: &'a AccountInfo<'b>, - seeds: &[&[&[u8]]], -) -> ProgramResult { - solana_program::program::invoke_signed( - &spl_token::instruction::revoke( - &spl_token::id(), - source_account.key, - authority_account.key, - &[], - )?, - &[source_account.clone(), authority_account.clone()], - seeds, - ) -} - -pub fn revoke_delegate<'a, 'b>( - source_account: &'a AccountInfo<'b>, - authority_account: &'a AccountInfo<'b>, - base_address: &Pubkey, - seeds: &[&[u8]], -) -> Result { - let (_, bump) = Pubkey::find_program_address(seeds, base_address); - - revoke_delegate_with_seeds( - source_account, - authority_account, - &[&[seeds, &[&[bump]]].concat()], - )?; - - Ok(bump) -} - -pub fn check_pda_data_size<'a, 'b>( - target_account: &'a AccountInfo<'b>, - seeds: &[&[u8]], - data_size: usize, - fix: bool, -) -> ProgramResult { - if fix && target_account.data_is_empty() { - program::invoke_signed( - &system_instruction::allocate(target_account.key, data_size as u64), - &[target_account.clone()], - &[seeds], - )?; - } - if target_account.data_len() < data_size { - Err(ProgramError::AccountDataTooSmall) - } else { - Ok(()) - } -} - -pub fn check_pda_rent_exempt<'a, 'b>( - signer_account: &'a AccountInfo<'b>, - target_account: &'a AccountInfo<'b>, - seeds: &[&[u8]], - data_size: usize, - fix: bool, -) -> ProgramResult { - let rent = Rent::get()?; - let cur_balance = target_account.try_lamports()?; - let min_balance = rent.minimum_balance(data_size); - if cur_balance < min_balance { - let signer_balance = signer_account.try_lamports()?; - let signer_min_balance = rent.minimum_balance(signer_account.data_len()); - if !fix - || signer_balance <= signer_min_balance - || min_balance.checked_sub(cur_balance).unwrap() - > signer_balance.checked_sub(signer_min_balance).unwrap() - { - return Err(ProgramError::InsufficientFunds); - } - program::invoke_signed( - &system_instruction::transfer( - signer_account.key, - target_account.key, - min_balance.checked_sub(cur_balance).unwrap(), - ), - &[signer_account.clone(), target_account.clone()], - &[seeds], - )?; - assert!(target_account.try_lamports()? >= min_balance); - } - Ok(()) -} - -pub fn check_pda_owner<'a, 'b>( - program_id: &Pubkey, - target_account: &'a AccountInfo<'b>, - seeds: &[&[u8]], - fix: bool, -) -> ProgramResult { - if *target_account.owner != *program_id { - if fix { - program::invoke_signed( - &system_instruction::assign(target_account.key, program_id), - &[target_account.clone()], - &[seeds], - )?; - assert!(*target_account.owner == *program_id); - } else { - return Err(ProgramError::IllegalOwner); - } - } - Ok(()) -} diff --git a/farms/farm-sdk/src/program/protocol/mod.rs b/farms/farm-sdk/src/program/protocol/mod.rs deleted file mode 100644 index 8590c4ec0f0..00000000000 --- a/farms/farm-sdk/src/program/protocol/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod orca; -pub mod raydium; -pub mod saber; diff --git a/farms/farm-sdk/src/program/protocol/orca.rs b/farms/farm-sdk/src/program/protocol/orca.rs deleted file mode 100644 index d279f59d43e..00000000000 --- a/farms/farm-sdk/src/program/protocol/orca.rs +++ /dev/null @@ -1,706 +0,0 @@ -//! Orca specific functions - -use { - crate::{ - error::FarmError, - instruction::orca::{OrcaHarvest, OrcaStake, OrcaUnstake}, - math, - pack::check_data_len, - program::account, - }, - arrayref::{array_ref, array_refs}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::{invoke, invoke_signed}, - program_error::ProgramError, - pubkey::Pubkey, - }, - spl_token_swap::instruction, -}; - -pub mod orca_swap { - solana_program::declare_id!("9W959DqEETiGZocYWCQPaJ6sBmUzgfxXfqGeTEdp3aQP"); -} - -pub mod orca_stake { - solana_program::declare_id!("82yxjeMsvaURa4MbZZ7WZZHfobirZYkH1zF8fmeGtyaQ"); -} - -pub const ORCA_FEE: f64 = 0.003; -pub const ORCA_FEE_NUMERATOR: u64 = 3; -pub const ORCA_FEE_DENOMINATOR: u64 = 1000; - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct OrcaUserStakeInfo { - pub is_initialized: u8, - pub account_type: u8, - pub global_farm: Pubkey, - pub owner: Pubkey, - pub base_tokens_converted: u64, - pub cumulative_emissions_checkpoint: [u8; 32], -} - -impl OrcaUserStakeInfo { - pub const LEN: usize = 106; - - pub fn unpack(input: &[u8]) -> Result { - check_data_len(input, OrcaUserStakeInfo::LEN)?; - - let input = array_ref![input, 0, OrcaUserStakeInfo::LEN]; - - #[allow(clippy::ptr_offset_with_cast)] - let ( - is_initialized, - account_type, - global_farm, - owner, - base_tokens_converted, - cumulative_emissions_checkpoint, - ) = array_refs![input, 1, 1, 32, 32, 8, 32]; - - Ok(Self { - is_initialized: is_initialized[0], - account_type: account_type[0], - global_farm: Pubkey::new_from_array(*global_farm), - owner: Pubkey::new_from_array(*owner), - base_tokens_converted: u64::from_le_bytes(*base_tokens_converted), - cumulative_emissions_checkpoint: *cumulative_emissions_checkpoint, - }) - } -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct OrcaFarmState { - pub is_initialized: u8, - pub account_type: u8, - pub nonce: u8, - pub token_program: Pubkey, - pub emissions_authority: Pubkey, - pub remove_rewards_authority: Pubkey, - pub base_token_mint: Pubkey, - pub base_token_vault: Pubkey, - pub reward_token_vault: Pubkey, - pub farm_token_mint: Pubkey, - pub emissions_per_sec_numerator: u64, - pub emissions_per_sec_denominator: u64, - pub last_updated_timestamp: u64, - pub cumulative_emissions_per_farm_token: [u8; 32], -} - -impl OrcaFarmState { - pub const LEN: usize = 283; - - pub fn unpack(input: &[u8]) -> Result { - check_data_len(input, OrcaFarmState::LEN)?; - - let input = array_ref![input, 0, OrcaFarmState::LEN]; - - #[allow(clippy::ptr_offset_with_cast)] - let ( - is_initialized, - account_type, - nonce, - token_program, - emissions_authority, - remove_rewards_authority, - base_token_mint, - base_token_vault, - reward_token_vault, - farm_token_mint, - emissions_per_sec_numerator, - emissions_per_sec_denominator, - last_updated_timestamp, - cumulative_emissions_per_farm_token, - ) = array_refs![input, 1, 1, 1, 32, 32, 32, 32, 32, 32, 32, 8, 8, 8, 32]; - - Ok(Self { - is_initialized: is_initialized[0], - account_type: account_type[0], - nonce: nonce[0], - token_program: Pubkey::new_from_array(*token_program), - emissions_authority: Pubkey::new_from_array(*emissions_authority), - remove_rewards_authority: Pubkey::new_from_array(*remove_rewards_authority), - base_token_mint: Pubkey::new_from_array(*base_token_mint), - base_token_vault: Pubkey::new_from_array(*base_token_vault), - reward_token_vault: Pubkey::new_from_array(*reward_token_vault), - farm_token_mint: Pubkey::new_from_array(*farm_token_mint), - emissions_per_sec_numerator: u64::from_le_bytes(*emissions_per_sec_numerator), - emissions_per_sec_denominator: u64::from_le_bytes(*emissions_per_sec_denominator), - last_updated_timestamp: u64::from_le_bytes(*last_updated_timestamp), - cumulative_emissions_per_farm_token: *cumulative_emissions_per_farm_token, - }) - } -} - -pub fn check_pool_program_id(program_id: &Pubkey) -> bool { - program_id == &orca_swap::id() -} - -pub fn check_stake_program_id(program_id: &Pubkey) -> bool { - program_id == &orca_stake::id() -} - -/// Returns amount of LP tokens staked as recorded in the specified stake account -pub fn get_stake_account_balance(stake_account: &AccountInfo) -> Result { - let data = stake_account.try_borrow_data()?; - Ok(OrcaUserStakeInfo::unpack(&data)?.base_tokens_converted) -} - -pub fn get_pool_token_balances<'a, 'b>( - pool_token_a_account: &'a AccountInfo<'b>, - pool_token_b_account: &'a AccountInfo<'b>, -) -> Result<(u64, u64), ProgramError> { - Ok(( - account::get_token_balance(pool_token_a_account)?, - account::get_token_balance(pool_token_b_account)?, - )) -} - -pub fn get_pool_deposit_amounts<'a, 'b>( - pool_token_a_account: &'a AccountInfo<'b>, - pool_token_b_account: &'a AccountInfo<'b>, - lp_token_mint: &'a AccountInfo<'b>, - max_token_a_amount: u64, - max_token_b_amount: u64, -) -> Result<(u64, u64, u64), ProgramError> { - if max_token_a_amount == 0 && max_token_b_amount == 0 { - msg!("Error: At least one of token amounts must be non-zero"); - return Err(ProgramError::InvalidArgument); - } - let mut token_a_amount = max_token_a_amount; - let mut token_b_amount = max_token_b_amount; - let (token_a_balance, token_b_balance) = - get_pool_token_balances(pool_token_a_account, pool_token_b_account)?; - - if token_a_balance == 0 || token_b_balance == 0 { - if max_token_a_amount == 0 || max_token_b_amount == 0 { - msg!("Error: Both amounts must be specified for the initial deposit to an empty pool"); - return Err(ProgramError::InvalidArgument); - } else { - return Ok((1, max_token_a_amount, max_token_b_amount)); - } - } - - if max_token_a_amount == 0 { - let estimated_coin_amount = math::checked_as_u64(math::checked_div( - math::checked_mul(token_a_balance as u128, max_token_b_amount as u128)?, - token_b_balance as u128, - )?)?; - token_a_amount = if estimated_coin_amount > 1 { - estimated_coin_amount - 1 - } else { - 0 - }; - } else if max_token_b_amount == 0 { - token_b_amount = math::checked_add( - math::checked_as_u64(math::checked_div( - math::checked_mul(token_b_balance as u128, max_token_a_amount as u128)?, - token_a_balance as u128, - )?)?, - 1, - )?; - } - - let min_lp_tokens_out = estimate_lp_tokens_amount( - lp_token_mint, - token_a_amount, - token_b_amount, - token_a_balance, - token_b_balance, - )?; - - Ok((min_lp_tokens_out, token_a_amount, token_b_amount)) -} - -pub fn get_pool_withdrawal_amounts<'a, 'b>( - pool_token_a_account: &'a AccountInfo<'b>, - pool_token_b_account: &'a AccountInfo<'b>, - lp_token_mint: &'a AccountInfo<'b>, - lp_token_amount: u64, -) -> Result<(u64, u64), ProgramError> { - if lp_token_amount == 0 { - msg!("Error: LP token amount must be non-zero"); - return Err(ProgramError::InvalidArgument); - } - let (token_a_balance, token_b_balance) = - get_pool_token_balances(pool_token_a_account, pool_token_b_account)?; - if token_a_balance == 0 && token_b_balance == 0 { - return Ok((0, 0)); - } - let lp_token_supply = account::get_token_supply(lp_token_mint)?; - if lp_token_supply == 0 { - return Ok((0, 0)); - } - Ok(( - math::checked_as_u64(math::checked_div( - math::checked_mul(token_a_balance as u128, lp_token_amount as u128)?, - lp_token_supply as u128, - )?)?, - math::checked_as_u64(math::checked_div( - math::checked_mul(token_b_balance as u128, lp_token_amount as u128)?, - lp_token_supply as u128, - )?)?, - )) -} - -pub fn get_pool_swap_amounts<'a, 'b>( - pool_token_a_account: &'a AccountInfo<'b>, - pool_token_b_account: &'a AccountInfo<'b>, - token_a_amount_in: u64, - token_b_amount_in: u64, -) -> Result<(u64, u64), ProgramError> { - if (token_a_amount_in == 0 && token_b_amount_in == 0) - || (token_a_amount_in > 0 && token_b_amount_in > 0) - { - msg!("Error: One and only one of token amounts must be non-zero"); - return Err(ProgramError::InvalidArgument); - } - let (token_a_balance, token_b_balance) = - get_pool_token_balances(pool_token_a_account, pool_token_b_account)?; - if token_a_balance == 0 || token_b_balance == 0 { - msg!("Error: Can't swap in an empty pool"); - return Err(FarmError::EmptyPool.into()); - } - let token_a_balance = token_a_balance as u128; - let token_b_balance = token_b_balance as u128; - if token_a_amount_in == 0 { - // b to a - let amount_in_no_fee = - math::get_no_fee_amount(token_b_amount_in, ORCA_FEE_NUMERATOR, ORCA_FEE_DENOMINATOR)? - as u128; - let estimated_token_a_amount = math::checked_as_u64(math::checked_div( - math::checked_mul(token_a_balance, amount_in_no_fee)?, - math::checked_add(token_b_balance, amount_in_no_fee)?, - )?)?; - - Ok(( - token_b_amount_in, - math::get_no_fee_amount(estimated_token_a_amount, 3, 100)?, - )) - } else { - // a to b - let amount_in_no_fee = - math::get_no_fee_amount(token_a_amount_in, ORCA_FEE_NUMERATOR, ORCA_FEE_DENOMINATOR)? - as u128; - let estimated_token_b_amount = math::checked_as_u64(math::checked_div( - math::checked_mul(token_b_balance as u128, amount_in_no_fee)?, - math::checked_add(token_a_balance as u128, amount_in_no_fee)?, - )?)?; - - Ok(( - token_a_amount_in, - math::get_no_fee_amount(estimated_token_b_amount, 3, 100)?, - )) - } -} - -pub fn estimate_lp_tokens_amount( - lp_token_mint: &AccountInfo, - token_a_deposit: u64, - token_b_deposit: u64, - pool_token_a_balance: u64, - pool_token_b_balance: u64, -) -> Result { - if pool_token_a_balance != 0 && pool_token_b_balance != 0 { - Ok(std::cmp::min( - math::checked_as_u64(math::checked_div( - math::checked_mul( - token_a_deposit as u128, - account::get_token_supply(lp_token_mint)? as u128, - )?, - pool_token_a_balance as u128, - )?)?, - math::checked_as_u64(math::checked_div( - math::checked_mul( - token_b_deposit as u128, - account::get_token_supply(lp_token_mint)? as u128, - )?, - pool_token_b_balance as u128, - )?)?, - )) - } else if pool_token_a_balance != 0 { - math::checked_as_u64(math::checked_div( - math::checked_mul( - token_a_deposit as u128, - account::get_token_supply(lp_token_mint)? as u128, - )?, - pool_token_a_balance as u128, - )?) - } else if pool_token_b_balance != 0 { - math::checked_as_u64(math::checked_div( - math::checked_mul( - token_b_deposit as u128, - account::get_token_supply(lp_token_mint)? as u128, - )?, - pool_token_b_balance as u128, - )?) - } else { - Ok(0) - } -} - -pub fn add_liquidity( - accounts: &[AccountInfo], - max_token_a_amount: u64, - max_token_b_amount: u64, - min_lp_token_amount: u64, -) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - user_token_a_account, - user_token_b_account, - user_lp_token_account, - pool_program_id, - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - _spl_token_id, - amm_id, - amm_authority - ] = accounts - { - if !check_pool_program_id(pool_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - - let data = instruction::DepositAllTokenTypes { - pool_token_amount: min_lp_token_amount, - maximum_token_a_amount: max_token_a_amount, - maximum_token_b_amount: max_token_b_amount, - }; - - let instruction = instruction::deposit_all_token_types( - pool_program_id.key, - &spl_token::id(), - amm_id.key, - amm_authority.key, - user_account.key, - user_token_a_account.key, - user_token_b_account.key, - pool_token_a_account.key, - pool_token_b_account.key, - lp_token_mint.key, - user_lp_token_account.key, - data, - )?; - - invoke(&instruction, accounts) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} - -pub fn add_liquidity_with_seeds( - accounts: &[AccountInfo], - seeds: &[&[&[u8]]], - max_token_a_amount: u64, - max_token_b_amount: u64, - min_lp_token_amount: u64, -) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - authority_account, - token_a_custody_account, - token_b_custody_account, - lp_token_custody_account, - pool_program_id, - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - _spl_token_id, - amm_id, - amm_authority - ] = accounts - { - if !check_pool_program_id(pool_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - - let data = instruction::DepositAllTokenTypes { - pool_token_amount: min_lp_token_amount, - maximum_token_a_amount: max_token_a_amount, - maximum_token_b_amount: max_token_b_amount, - }; - - let instruction = instruction::deposit_all_token_types( - pool_program_id.key, - &spl_token::id(), - amm_id.key, - amm_authority.key, - authority_account.key, - token_a_custody_account.key, - token_b_custody_account.key, - pool_token_a_account.key, - pool_token_b_account.key, - lp_token_mint.key, - lp_token_custody_account.key, - data, - )?; - - invoke_signed(&instruction, accounts, seeds) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} - -pub fn remove_liquidity_with_seeds( - accounts: &[AccountInfo], - seeds: &[&[&[u8]]], - lp_amount: u64, - min_token_a_amount: u64, - min_token_b_amount: u64, -) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - authority_account, - token_a_custody_account, - token_b_custody_account, - lp_token_custody_account, - pool_program_id, - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - _spl_token_id, - amm_id, - amm_authority, - fees_account - ] = accounts - { - if !check_pool_program_id(pool_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - - let data = instruction::WithdrawAllTokenTypes { - pool_token_amount: lp_amount, - minimum_token_a_amount: min_token_a_amount, - minimum_token_b_amount: min_token_b_amount, - }; - - let instruction = instruction::withdraw_all_token_types( - pool_program_id.key, - &spl_token::id(), - amm_id.key, - amm_authority.key, - authority_account.key, - lp_token_mint.key, - fees_account.key, - lp_token_custody_account.key, - pool_token_a_account.key, - pool_token_b_account.key, - token_a_custody_account.key, - token_b_custody_account.key, - data, - )?; - - invoke_signed(&instruction, accounts, seeds) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} - -pub fn stake_with_seeds( - accounts: &[AccountInfo], - seeds: &[&[&[u8]]], - amount: u64, -) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - authority_account, - stake_info_account, - lp_token_custody_account, - reward_token_custody_account, - farm_lp_token_custody_account, - farm_lp_token_mint, - farm_program_id, - base_token_vault, - reward_token_vault, - _spl_token_id, - farm_id, - farm_authority - ] = accounts - { - if !check_stake_program_id(farm_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - - let orca_accounts = vec![ - AccountMeta::new_readonly(*authority_account.key, true), - AccountMeta::new(*lp_token_custody_account.key, false), - AccountMeta::new(*base_token_vault.key, false), - AccountMeta::new_readonly(*authority_account.key, true), - AccountMeta::new(*farm_lp_token_mint.key, false), - AccountMeta::new(*farm_lp_token_custody_account.key, false), - AccountMeta::new(*farm_id.key, false), - AccountMeta::new(*stake_info_account.key, false), - AccountMeta::new(*reward_token_vault.key, false), - AccountMeta::new(*reward_token_custody_account.key, false), - AccountMeta::new_readonly(*farm_authority.key, false), - AccountMeta::new_readonly(spl_token::id(), false), - ]; - - let instruction = Instruction { - program_id: *farm_program_id.key, - accounts: orca_accounts, - data: OrcaStake { amount }.to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} - -pub fn harvest_with_seeds(accounts: &[AccountInfo], seeds: &[&[&[u8]]]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - authority_account, - stake_info_account, - reward_token_custody_account, - farm_program_id, - base_token_vault, - reward_token_vault, - _spl_token_id, - farm_id, - farm_authority - ] = accounts - { - if !check_stake_program_id(farm_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - - let orca_accounts = vec![ - AccountMeta::new_readonly(*authority_account.key, true), - AccountMeta::new(*farm_id.key, false), - AccountMeta::new(*stake_info_account.key, false), - AccountMeta::new_readonly(*base_token_vault.key, false), - AccountMeta::new(*reward_token_vault.key, false), - AccountMeta::new(*reward_token_custody_account.key, false), - AccountMeta::new_readonly(*farm_authority.key, false), - AccountMeta::new_readonly(spl_token::id(), false), - ]; - - let instruction = Instruction { - program_id: *farm_program_id.key, - accounts: orca_accounts, - data: OrcaHarvest {}.to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} - -pub fn swap_with_seeds( - accounts: &[AccountInfo], - seeds: &[&[&[u8]]], - amount_in: u64, - min_amount_out: u64, -) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - authority_account, - token_a_custody_account, - token_b_custody_account, - pool_program_id, - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - _spl_token_id, - amm_id, - amm_authority, - fees_account - ] = accounts - { - if !check_pool_program_id(pool_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - - let data = instruction::Swap { - amount_in, - minimum_amount_out: min_amount_out, - }; - - let instruction = instruction::swap( - pool_program_id.key, - &spl_token::id(), - amm_id.key, - amm_authority.key, - authority_account.key, - token_a_custody_account.key, - pool_token_a_account.key, - pool_token_b_account.key, - token_b_custody_account.key, - lp_token_mint.key, - fees_account.key, - None, - data, - )?; - - invoke_signed(&instruction, accounts, seeds) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} - -pub fn unstake_with_seeds( - accounts: &[AccountInfo], - seeds: &[&[&[u8]]], - amount: u64, -) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - authority_account, - stake_info_account, - lp_token_custody_account, - reward_token_custody_account, - farm_lp_token_custody_account, - farm_lp_token_mint, - farm_program_id, - base_token_vault, - reward_token_vault, - _spl_token_id, - farm_id, - farm_authority - ] = accounts - { - if !check_stake_program_id(farm_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - - let orca_accounts = vec![ - AccountMeta::new_readonly(*authority_account.key, true), - AccountMeta::new(*lp_token_custody_account.key, false), - AccountMeta::new(*base_token_vault.key, false), - AccountMeta::new(*farm_lp_token_mint.key, false), - AccountMeta::new(*farm_lp_token_custody_account.key, false), - AccountMeta::new_readonly(*authority_account.key, true), - AccountMeta::new(*farm_id.key, false), - AccountMeta::new(*stake_info_account.key, false), - AccountMeta::new(*reward_token_vault.key, false), - AccountMeta::new(*reward_token_custody_account.key, false), - AccountMeta::new_readonly(*farm_authority.key, false), - AccountMeta::new_readonly(spl_token::id(), false), - ]; - - let instruction = Instruction { - program_id: *farm_program_id.key, - accounts: orca_accounts, - data: OrcaUnstake { amount }.to_vec()?, - }; - invoke_signed(&instruction, accounts, seeds) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/farm-sdk/src/program/protocol/raydium.rs b/farms/farm-sdk/src/program/protocol/raydium.rs deleted file mode 100644 index c71b98333f5..00000000000 --- a/farms/farm-sdk/src/program/protocol/raydium.rs +++ /dev/null @@ -1,859 +0,0 @@ -//! Raydium specific functions - -use { - crate::{ - error::FarmError, - id::zero, - instruction::raydium::{ - RaydiumAddLiquidity, RaydiumRemoveLiquidity, RaydiumStake, RaydiumSwap, RaydiumUnstake, - }, - math, - pack::check_data_len, - program::account, - }, - arrayref::{array_ref, array_refs}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::{invoke, invoke_signed}, - program_error::ProgramError, - pubkey::Pubkey, - }, -}; - -pub mod raydium_v2 { - solana_program::declare_id!("RVKd61ztZW9GUwhRbbLoYVRE5Xf1B2tVscKqwZqXgEr"); -} -pub mod raydium_v3 { - solana_program::declare_id!("27haf8L6oxUeXrHrgEgsexjSY5hbVUWEmvv9Nyxg8vQv"); -} -pub mod raydium_v4 { - solana_program::declare_id!("675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"); -} -pub mod raydium_stake { - solana_program::declare_id!("EhhTKczWMGQt46ynNeRX1WfeagwwJd7ufHvCDjRxjo5Q"); -} -pub mod raydium_stake_v4 { - solana_program::declare_id!("CBuCnLe26faBpcBP2fktp4rp8abpcAnTWft6ZrP5Q4T"); -} -pub mod raydium_stake_v5 { - solana_program::declare_id!("9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z"); -} - -pub const RAYDIUM_FEE: f64 = 0.0025; -pub const RAYDIUM_FEE_NUMERATOR: u64 = 25; -pub const RAYDIUM_FEE_DENOMINATOR: u64 = 10000; - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct RaydiumUserStakeInfo { - pub state: u64, - pub farm_id: Pubkey, - pub stake_owner: Pubkey, - pub deposit_balance: u64, - pub reward_debt: u64, -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct RaydiumUserStakeInfoV4 { - pub state: u64, - pub farm_id: Pubkey, - pub stake_owner: Pubkey, - pub deposit_balance: u64, - pub reward_debt: u64, - pub reward_debt_b: u64, -} - -impl RaydiumUserStakeInfo { - pub const LEN: usize = 88; - - pub fn get_size(&self) -> usize { - RaydiumUserStakeInfo::LEN - } - - pub fn unpack(input: &[u8]) -> Result { - check_data_len(input, RaydiumUserStakeInfo::LEN)?; - - let input = array_ref![input, 0, RaydiumUserStakeInfo::LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let (state, farm_id, stake_owner, deposit_balance, reward_debt) = - array_refs![input, 8, 32, 32, 8, 8]; - - Ok(Self { - state: u64::from_le_bytes(*state), - farm_id: Pubkey::new_from_array(*farm_id), - stake_owner: Pubkey::new_from_array(*stake_owner), - deposit_balance: u64::from_le_bytes(*deposit_balance), - reward_debt: u64::from_le_bytes(*reward_debt), - }) - } -} - -impl RaydiumUserStakeInfoV4 { - pub const LEN: usize = 96; - - pub fn get_size(&self) -> usize { - RaydiumUserStakeInfoV4::LEN - } - - pub fn unpack(input: &[u8]) -> Result { - check_data_len(input, RaydiumUserStakeInfoV4::LEN)?; - - let input = array_ref![input, 0, RaydiumUserStakeInfoV4::LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let (state, farm_id, stake_owner, deposit_balance, reward_debt, reward_debt_b) = - array_refs![input, 8, 32, 32, 8, 8, 8]; - - Ok(Self { - state: u64::from_le_bytes(*state), - farm_id: Pubkey::new_from_array(*farm_id), - stake_owner: Pubkey::new_from_array(*stake_owner), - deposit_balance: u64::from_le_bytes(*deposit_balance), - reward_debt: u64::from_le_bytes(*reward_debt), - reward_debt_b: u64::from_le_bytes(*reward_debt_b), - }) - } -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct AmmInfoV4 { - pub status: u64, - pub nonce: u64, - pub order_num: u64, - pub depth: u64, - pub coin_decimals: u64, - pub pc_decimals: u64, - pub state: u64, - pub reset_flag: u64, - pub min_size: u64, - pub vol_max_cut_ratio: u64, - pub amount_wave: u64, - pub coin_lot_size: u64, - pub pc_lot_size: u64, - pub min_price_multiplier: u64, - pub max_price_multiplier: u64, - pub sys_decimal_value: u64, - pub min_separate_numerator: u64, - pub min_separate_denominator: u64, - pub trade_fee_numerator: u64, - pub trade_fee_denominator: u64, - pub pnl_numerator: u64, - pub pnl_denominator: u64, - pub swap_fee_numerator: u64, - pub swap_fee_denominator: u64, - pub need_take_pnl_coin: u64, - pub need_take_pnl_pc: u64, - pub total_pnl_pc: u64, - pub total_pnl_coin: u64, - pub pool_total_deposit_pc: u128, - pub pool_total_deposit_coin: u128, - pub swap_coin_in_amount: u128, - pub swap_pc_out_amount: u128, - pub swap_coin_to_pc_fee: u64, - pub swap_pc_in_amount: u128, - pub swap_coin_out_amount: u128, - pub swap_pc_to_coin_fee: u64, - pub token_coin: Pubkey, - pub token_pc: Pubkey, - pub coin_mint: Pubkey, - pub pc_mint: Pubkey, - pub lp_mint: Pubkey, - pub open_orders: Pubkey, - pub market: Pubkey, - pub serum_dex: Pubkey, - pub target_orders: Pubkey, - pub withdraw_queue: Pubkey, - pub token_temp_lp: Pubkey, - pub amm_owner: Pubkey, - pub pnl_owner: Pubkey, -} - -impl AmmInfoV4 { - pub const LEN: usize = 752; - - pub fn get_size(&self) -> usize { - AmmInfoV4::LEN - } - - pub fn unpack(input: &[u8]) -> Result { - check_data_len(input, AmmInfoV4::LEN)?; - - let input = array_ref![input, 0, AmmInfoV4::LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let ( - status, - nonce, - order_num, - depth, - coin_decimals, - pc_decimals, - state, - reset_flag, - min_size, - vol_max_cut_ratio, - amount_wave, - coin_lot_size, - pc_lot_size, - min_price_multiplier, - max_price_multiplier, - sys_decimal_value, - min_separate_numerator, - min_separate_denominator, - trade_fee_numerator, - trade_fee_denominator, - pnl_numerator, - pnl_denominator, - swap_fee_numerator, - swap_fee_denominator, - need_take_pnl_coin, - need_take_pnl_pc, - total_pnl_pc, - total_pnl_coin, - pool_total_deposit_pc, - pool_total_deposit_coin, - swap_coin_in_amount, - swap_pc_out_amount, - swap_coin_to_pc_fee, - swap_pc_in_amount, - swap_coin_out_amount, - swap_pc_to_coin_fee, - token_coin, - token_pc, - coin_mint, - pc_mint, - lp_mint, - open_orders, - market, - serum_dex, - target_orders, - withdraw_queue, - token_temp_lp, - amm_owner, - pnl_owner, - ) = array_refs![ - input, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 16, 16, 16, 16, 8, 16, 16, 8, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 - ]; - - Ok(Self { - status: u64::from_le_bytes(*status), - nonce: u64::from_le_bytes(*nonce), - order_num: u64::from_le_bytes(*order_num), - depth: u64::from_le_bytes(*depth), - coin_decimals: u64::from_le_bytes(*coin_decimals), - pc_decimals: u64::from_le_bytes(*pc_decimals), - state: u64::from_le_bytes(*state), - reset_flag: u64::from_le_bytes(*reset_flag), - min_size: u64::from_le_bytes(*min_size), - vol_max_cut_ratio: u64::from_le_bytes(*vol_max_cut_ratio), - amount_wave: u64::from_le_bytes(*amount_wave), - coin_lot_size: u64::from_le_bytes(*coin_lot_size), - pc_lot_size: u64::from_le_bytes(*pc_lot_size), - min_price_multiplier: u64::from_le_bytes(*min_price_multiplier), - max_price_multiplier: u64::from_le_bytes(*max_price_multiplier), - sys_decimal_value: u64::from_le_bytes(*sys_decimal_value), - min_separate_numerator: u64::from_le_bytes(*min_separate_numerator), - min_separate_denominator: u64::from_le_bytes(*min_separate_denominator), - trade_fee_numerator: u64::from_le_bytes(*trade_fee_numerator), - trade_fee_denominator: u64::from_le_bytes(*trade_fee_denominator), - pnl_numerator: u64::from_le_bytes(*pnl_numerator), - pnl_denominator: u64::from_le_bytes(*pnl_denominator), - swap_fee_numerator: u64::from_le_bytes(*swap_fee_numerator), - swap_fee_denominator: u64::from_le_bytes(*swap_fee_denominator), - need_take_pnl_coin: u64::from_le_bytes(*need_take_pnl_coin), - need_take_pnl_pc: u64::from_le_bytes(*need_take_pnl_pc), - total_pnl_pc: u64::from_le_bytes(*total_pnl_pc), - total_pnl_coin: u64::from_le_bytes(*total_pnl_coin), - pool_total_deposit_pc: u128::from_le_bytes(*pool_total_deposit_pc), - pool_total_deposit_coin: u128::from_le_bytes(*pool_total_deposit_coin), - swap_coin_in_amount: u128::from_le_bytes(*swap_coin_in_amount), - swap_pc_out_amount: u128::from_le_bytes(*swap_pc_out_amount), - swap_coin_to_pc_fee: u64::from_le_bytes(*swap_coin_to_pc_fee), - swap_pc_in_amount: u128::from_le_bytes(*swap_pc_in_amount), - swap_coin_out_amount: u128::from_le_bytes(*swap_coin_out_amount), - swap_pc_to_coin_fee: u64::from_le_bytes(*swap_pc_to_coin_fee), - token_coin: Pubkey::new_from_array(*token_coin), - token_pc: Pubkey::new_from_array(*token_pc), - coin_mint: Pubkey::new_from_array(*coin_mint), - pc_mint: Pubkey::new_from_array(*pc_mint), - lp_mint: Pubkey::new_from_array(*lp_mint), - open_orders: Pubkey::new_from_array(*open_orders), - market: Pubkey::new_from_array(*market), - serum_dex: Pubkey::new_from_array(*serum_dex), - target_orders: Pubkey::new_from_array(*target_orders), - withdraw_queue: Pubkey::new_from_array(*withdraw_queue), - token_temp_lp: Pubkey::new_from_array(*token_temp_lp), - amm_owner: Pubkey::new_from_array(*amm_owner), - pnl_owner: Pubkey::new_from_array(*pnl_owner), - }) - } -} - -pub fn check_pool_program_id(program_id: &Pubkey) -> bool { - program_id == &raydium_v2::id() - || program_id == &raydium_v3::id() - || program_id == &raydium_v4::id() -} - -pub fn check_stake_program_id(program_id: &Pubkey) -> bool { - program_id == &raydium_stake::id() - || program_id == &raydium_stake_v4::id() - || program_id == &raydium_stake_v5::id() -} - -/// Returns amount of LP tokens staked as recorded in the specified stake account -pub fn get_stake_account_balance(stake_account: &AccountInfo) -> Result { - let data = stake_account.try_borrow_data()?; - if data.len() == RaydiumUserStakeInfoV4::LEN { - Ok(RaydiumUserStakeInfoV4::unpack(&data)?.deposit_balance) - } else if data.len() == RaydiumUserStakeInfo::LEN { - Ok(RaydiumUserStakeInfo::unpack(&data)?.deposit_balance) - } else { - Err(ProgramError::InvalidAccountData) - } -} - -pub fn get_pool_token_balances<'a, 'b>( - pool_coin_token_account: &'a AccountInfo<'b>, - pool_pc_token_account: &'a AccountInfo<'b>, - amm_open_orders: &'a AccountInfo<'b>, - amm_id: &'a AccountInfo<'b>, -) -> Result<(u64, u64), ProgramError> { - // get token balances - let mut token_a_balance = account::get_token_balance(pool_coin_token_account)?; - let mut token_b_balance = account::get_token_balance(pool_pc_token_account)?; - - // adjust with open orders - if amm_open_orders.data_len() == 3228 { - let open_orders_data = amm_open_orders.try_borrow_data()?; - let base_token_total = array_ref![open_orders_data, 85, 8]; - let quote_token_total = array_ref![open_orders_data, 101, 8]; - - token_a_balance = - math::checked_add(token_a_balance, u64::from_le_bytes(*base_token_total))?; - token_b_balance = - math::checked_add(token_b_balance, u64::from_le_bytes(*quote_token_total))?; - } - - // adjust with amm take pnl - let (pnl_coin_offset, pnl_pc_offset) = if amm_id.data_len() == 624 { - (136, 144) - } else if amm_id.data_len() == 680 { - (144, 152) - } else if amm_id.data_len() == 752 { - (192, 200) - } else { - (0, 0) - }; - if pnl_coin_offset > 0 { - let amm_id_data = amm_id.try_borrow_data()?; - let need_take_pnl_coin = u64::from_le_bytes(*array_ref![amm_id_data, pnl_coin_offset, 8]); - let need_take_pnl_pc = u64::from_le_bytes(*array_ref![amm_id_data, pnl_pc_offset, 8]); - - token_a_balance = if let Some(res) = token_a_balance.checked_sub(need_take_pnl_coin) { - res - } else { - 0 - }; - - token_b_balance = if let Some(res) = token_b_balance.checked_sub(need_take_pnl_pc) { - res - } else { - 0 - }; - } - - Ok((token_a_balance, token_b_balance)) -} - -pub fn get_pool_deposit_amounts<'a, 'b>( - pool_coin_token_account: &'a AccountInfo<'b>, - pool_pc_token_account: &'a AccountInfo<'b>, - lp_token_mint: &'a AccountInfo<'b>, - amm_open_orders: &'a AccountInfo<'b>, - amm_id: &'a AccountInfo<'b>, - max_coin_token_amount: u64, - max_pc_token_amount: u64, -) -> Result<(u64, u64, u64), ProgramError> { - if max_coin_token_amount == 0 && max_pc_token_amount == 0 { - msg!("Error: At least one of token amounts must be non-zero"); - return Err(ProgramError::InvalidArgument); - } - let mut coin_token_amount = max_coin_token_amount; - let mut pc_token_amount = max_pc_token_amount; - let (coin_balance, pc_balance) = get_pool_token_balances( - pool_coin_token_account, - pool_pc_token_account, - amm_open_orders, - amm_id, - )?; - if coin_balance == 0 || pc_balance == 0 { - if max_coin_token_amount == 0 || max_pc_token_amount == 0 { - msg!("Error: Both amounts must be specified for the initial deposit to an empty pool"); - return Err(ProgramError::InvalidArgument); - } else { - return Ok((1, max_coin_token_amount, max_pc_token_amount)); - } - } - if max_coin_token_amount == 0 { - let estimated_coin_amount = math::checked_as_u64(math::checked_div( - math::checked_mul(coin_balance as u128, max_pc_token_amount as u128)?, - pc_balance as u128, - )?)?; - coin_token_amount = if estimated_coin_amount > 1 { - estimated_coin_amount - 1 - } else { - 0 - }; - } else if max_pc_token_amount == 0 { - pc_token_amount = math::checked_add( - math::checked_as_u64(math::checked_div( - math::checked_mul(pc_balance as u128, max_coin_token_amount as u128)?, - coin_balance as u128, - )?)?, - 1, - )?; - } - - let min_lp_tokens_out = estimate_lp_tokens_amount( - lp_token_mint, - coin_token_amount, - pc_token_amount, - coin_balance, - pc_balance, - )?; - - Ok((min_lp_tokens_out, coin_token_amount, pc_token_amount)) -} - -pub fn get_pool_withdrawal_amounts<'a, 'b>( - pool_coin_token_account: &'a AccountInfo<'b>, - pool_pc_token_account: &'a AccountInfo<'b>, - amm_open_orders: &'a AccountInfo<'b>, - amm_id: &'a AccountInfo<'b>, - lp_token_mint: &'a AccountInfo<'b>, - lp_token_amount: u64, -) -> Result<(u64, u64), ProgramError> { - if lp_token_amount == 0 { - msg!("Error: LP token amount must be non-zero"); - return Err(ProgramError::InvalidArgument); - } - let (coin_balance, pc_balance) = get_pool_token_balances( - pool_coin_token_account, - pool_pc_token_account, - amm_open_orders, - amm_id, - )?; - if coin_balance == 0 && pc_balance == 0 { - return Ok((0, 0)); - } - let lp_token_supply = account::get_token_supply(lp_token_mint)?; - if lp_token_supply == 0 { - return Ok((0, 0)); - } - Ok(( - math::checked_as_u64(math::checked_div( - math::checked_mul(coin_balance as u128, lp_token_amount as u128)?, - lp_token_supply as u128, - )?)?, - math::checked_as_u64(math::checked_div( - math::checked_mul(pc_balance as u128, lp_token_amount as u128)?, - lp_token_supply as u128, - )?)?, - )) -} - -pub fn get_pool_swap_amounts<'a, 'b>( - pool_coin_token_account: &'a AccountInfo<'b>, - pool_pc_token_account: &'a AccountInfo<'b>, - amm_open_orders: &'a AccountInfo<'b>, - amm_id: &'a AccountInfo<'b>, - coin_token_amount_in: u64, - pc_token_amount_in: u64, -) -> Result<(u64, u64), ProgramError> { - if (coin_token_amount_in == 0 && pc_token_amount_in == 0) - || (coin_token_amount_in > 0 && pc_token_amount_in > 0) - { - msg!("Error: One and only one of token amounts must be non-zero"); - return Err(ProgramError::InvalidArgument); - } - let (coin_balance, pc_balance) = get_pool_token_balances( - pool_coin_token_account, - pool_pc_token_account, - amm_open_orders, - amm_id, - )?; - if coin_balance == 0 || pc_balance == 0 { - msg!("Error: Can't swap in an empty pool"); - return Err(FarmError::EmptyPool.into()); - } - if coin_token_amount_in == 0 { - // pc to coin - let amount_in_no_fee = math::get_no_fee_amount( - pc_token_amount_in, - RAYDIUM_FEE_NUMERATOR, - RAYDIUM_FEE_DENOMINATOR, - )? as u128; - let estimated_coin_amount = math::checked_as_u64(math::checked_div( - math::checked_mul(coin_balance as u128, amount_in_no_fee)?, - math::checked_add(pc_balance as u128, amount_in_no_fee)?, - )?)?; - Ok(( - pc_token_amount_in, - math::get_no_fee_amount(estimated_coin_amount, 3, 100)?, - )) - } else { - // coin to pc - let amount_in_no_fee = math::get_no_fee_amount( - coin_token_amount_in, - RAYDIUM_FEE_NUMERATOR, - RAYDIUM_FEE_DENOMINATOR, - )? as u128; - let estimated_pc_amount = math::checked_as_u64(math::checked_div( - math::checked_mul(pc_balance as u128, amount_in_no_fee)?, - math::checked_add(coin_balance as u128, amount_in_no_fee)?, - )?)?; - Ok(( - coin_token_amount_in, - math::get_no_fee_amount(estimated_pc_amount, 3, 100)?, - )) - } -} - -pub fn estimate_lp_tokens_amount( - lp_token_mint: &AccountInfo, - token_a_deposit: u64, - token_b_deposit: u64, - pool_coin_balance: u64, - pool_pc_balance: u64, -) -> Result { - if pool_coin_balance != 0 && pool_pc_balance != 0 { - Ok(std::cmp::min( - math::checked_as_u64(math::checked_div( - math::checked_mul( - token_a_deposit as u128, - account::get_token_supply(lp_token_mint)? as u128, - )?, - pool_coin_balance as u128, - )?)?, - math::checked_as_u64(math::checked_div( - math::checked_mul( - token_b_deposit as u128, - account::get_token_supply(lp_token_mint)? as u128, - )?, - pool_pc_balance as u128, - )?)?, - )) - } else if pool_coin_balance != 0 { - math::checked_as_u64(math::checked_div( - math::checked_mul( - token_a_deposit as u128, - account::get_token_supply(lp_token_mint)? as u128, - )?, - pool_coin_balance as u128, - )?) - } else if pool_pc_balance != 0 { - math::checked_as_u64(math::checked_div( - math::checked_mul( - token_b_deposit as u128, - account::get_token_supply(lp_token_mint)? as u128, - )?, - pool_pc_balance as u128, - )?) - } else { - Ok(0) - } -} - -pub fn add_liquidity( - accounts: &[AccountInfo], - max_coin_token_amount: u64, - max_pc_token_amount: u64, -) -> ProgramResult { - if let [user_account, user_token_a_account, user_token_b_account, user_lp_token_account, pool_program_id, pool_coin_token_account, pool_pc_token_account, lp_token_mint, spl_token_id, amm_id, amm_authority, amm_open_orders, amm_target, serum_market] = - accounts - { - if !check_pool_program_id(pool_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - - let raydium_accounts = vec![ - AccountMeta::new_readonly(*spl_token_id.key, false), - AccountMeta::new(*amm_id.key, false), - AccountMeta::new_readonly(*amm_authority.key, false), - AccountMeta::new_readonly(*amm_open_orders.key, false), - AccountMeta::new(*amm_target.key, false), - AccountMeta::new(*lp_token_mint.key, false), - AccountMeta::new(*pool_coin_token_account.key, false), - AccountMeta::new(*pool_pc_token_account.key, false), - AccountMeta::new_readonly(*serum_market.key, false), - AccountMeta::new(*user_token_a_account.key, false), - AccountMeta::new(*user_token_b_account.key, false), - AccountMeta::new(*user_lp_token_account.key, false), - AccountMeta::new_readonly(*user_account.key, true), - ]; - - let instruction = Instruction { - program_id: *pool_program_id.key, - accounts: raydium_accounts, - data: RaydiumAddLiquidity { - instruction: 3, - max_coin_token_amount, - max_pc_token_amount, - base_side: 0, - } - .to_vec()?, - }; - invoke(&instruction, accounts) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} - -pub fn add_liquidity_with_seeds( - accounts: &[AccountInfo], - seeds: &[&[&[u8]]], - max_coin_token_amount: u64, - max_pc_token_amount: u64, -) -> ProgramResult { - if let [authority_account, token_a_custody_account, token_b_custody_account, lp_token_custody_account, pool_program_id, pool_coin_token_account, pool_pc_token_account, lp_token_mint, spl_token_id, amm_id, amm_authority, amm_open_orders, amm_target, serum_market] = - accounts - { - if !check_pool_program_id(pool_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - - let raydium_accounts = vec![ - AccountMeta::new_readonly(*spl_token_id.key, false), - AccountMeta::new(*amm_id.key, false), - AccountMeta::new_readonly(*amm_authority.key, false), - AccountMeta::new_readonly(*amm_open_orders.key, false), - AccountMeta::new(*amm_target.key, false), - AccountMeta::new(*lp_token_mint.key, false), - AccountMeta::new(*pool_coin_token_account.key, false), - AccountMeta::new(*pool_pc_token_account.key, false), - AccountMeta::new_readonly(*serum_market.key, false), - AccountMeta::new(*token_a_custody_account.key, false), - AccountMeta::new(*token_b_custody_account.key, false), - AccountMeta::new(*lp_token_custody_account.key, false), - AccountMeta::new_readonly(*authority_account.key, true), - ]; - - let instruction = Instruction { - program_id: *pool_program_id.key, - accounts: raydium_accounts, - data: RaydiumAddLiquidity { - instruction: 3, - max_coin_token_amount, - max_pc_token_amount, - base_side: 0, - } - .to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} - -pub fn remove_liquidity_with_seeds( - accounts: &[AccountInfo], - seeds: &[&[&[u8]]], - amount: u64, -) -> ProgramResult { - if let [authority_account, token_a_custody_account, token_b_custody_account, lp_token_custody_account, pool_program_id, pool_withdraw_queue, pool_temp_lp_token_account, pool_coin_token_account, pool_pc_token_account, lp_token_mint, spl_token_id, amm_id, amm_authority, amm_open_orders, amm_target, serum_market, serum_program_id, serum_bids, serum_asks, serum_event_queue, serum_coin_vault_account, serum_pc_vault_account, serum_vault_signer] = - accounts - { - if !check_pool_program_id(pool_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - - let raydium_accounts = vec![ - AccountMeta::new_readonly(*spl_token_id.key, false), - AccountMeta::new(*amm_id.key, false), - AccountMeta::new_readonly(*amm_authority.key, false), - AccountMeta::new(*amm_open_orders.key, false), - AccountMeta::new(*amm_target.key, false), - AccountMeta::new(*lp_token_mint.key, false), - AccountMeta::new(*pool_coin_token_account.key, false), - AccountMeta::new(*pool_pc_token_account.key, false), - AccountMeta::new(*pool_withdraw_queue.key, false), - AccountMeta::new(*pool_temp_lp_token_account.key, false), - AccountMeta::new_readonly(*serum_program_id.key, false), - AccountMeta::new(*serum_market.key, false), - AccountMeta::new(*serum_coin_vault_account.key, false), - AccountMeta::new(*serum_pc_vault_account.key, false), - AccountMeta::new_readonly(*serum_vault_signer.key, false), - AccountMeta::new(*lp_token_custody_account.key, false), - AccountMeta::new(*token_a_custody_account.key, false), - AccountMeta::new(*token_b_custody_account.key, false), - AccountMeta::new_readonly(*authority_account.key, true), - AccountMeta::new(*serum_event_queue.key, false), - AccountMeta::new(*serum_bids.key, false), - AccountMeta::new(*serum_asks.key, false), - ]; - - let instruction = Instruction { - program_id: *pool_program_id.key, - accounts: raydium_accounts, - data: RaydiumRemoveLiquidity { - instruction: 4, - amount, - } - .to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} - -pub fn stake_with_seeds( - accounts: &[AccountInfo], - seeds: &[&[&[u8]]], - amount: u64, -) -> ProgramResult { - if let [authority_account, stake_info_account, lp_token_custody_account, token_a_custody_account, token_b_custody_account, pool_program_id, farm_lp_token_account, farm_first_reward_token_account, farm_second_reward_token_account, clock_id, spl_token_id, farm_id, farm_authority] = - accounts - { - if !check_stake_program_id(pool_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - - let mut raydium_accounts = vec![ - AccountMeta::new(*farm_id.key, false), - AccountMeta::new_readonly(*farm_authority.key, false), - AccountMeta::new(*stake_info_account.key, false), - AccountMeta::new_readonly(*authority_account.key, true), - AccountMeta::new(*lp_token_custody_account.key, false), - AccountMeta::new(*farm_lp_token_account.key, false), - AccountMeta::new(*token_a_custody_account.key, false), - AccountMeta::new(*farm_first_reward_token_account.key, false), - AccountMeta::new_readonly(*clock_id.key, false), - AccountMeta::new_readonly(*spl_token_id.key, false), - ]; - if *farm_second_reward_token_account.key != zero::id() { - raydium_accounts.push(AccountMeta::new(*token_b_custody_account.key, false)); - raydium_accounts.push(AccountMeta::new( - *farm_second_reward_token_account.key, - false, - )); - } - - let instruction = Instruction { - program_id: *pool_program_id.key, - accounts: raydium_accounts, - data: RaydiumStake { - instruction: 1, - amount, - } - .to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} - -pub fn swap_with_seeds( - accounts: &[AccountInfo], - seeds: &[&[&[u8]]], - amount_in: u64, - min_amount_out: u64, -) -> ProgramResult { - if let [authority_account, token_a_custody_account, token_b_custody_account, pool_program_id, pool_coin_token_account, pool_pc_token_account, spl_token_id, amm_id, amm_authority, amm_open_orders, amm_target, serum_market, serum_program_id, serum_bids, serum_asks, serum_event_queue, serum_coin_vault_account, serum_pc_vault_account, serum_vault_signer] = - accounts - { - if !check_pool_program_id(pool_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - - let raydium_accounts = vec![ - AccountMeta::new_readonly(*spl_token_id.key, false), - AccountMeta::new(*amm_id.key, false), - AccountMeta::new_readonly(*amm_authority.key, false), - AccountMeta::new(*amm_open_orders.key, false), - AccountMeta::new(*amm_target.key, false), - AccountMeta::new(*pool_coin_token_account.key, false), - AccountMeta::new(*pool_pc_token_account.key, false), - AccountMeta::new_readonly(*serum_program_id.key, false), - AccountMeta::new(*serum_market.key, false), - AccountMeta::new(*serum_bids.key, false), - AccountMeta::new(*serum_asks.key, false), - AccountMeta::new(*serum_event_queue.key, false), - AccountMeta::new(*serum_coin_vault_account.key, false), - AccountMeta::new(*serum_pc_vault_account.key, false), - AccountMeta::new_readonly(*serum_vault_signer.key, false), - AccountMeta::new(*token_a_custody_account.key, false), - AccountMeta::new(*token_b_custody_account.key, false), - AccountMeta::new_readonly(*authority_account.key, true), - ]; - - let instruction = Instruction { - program_id: *pool_program_id.key, - accounts: raydium_accounts, - data: RaydiumSwap { - instruction: 9, - amount_in, - min_amount_out, - } - .to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} - -pub fn unstake_with_seeds( - accounts: &[AccountInfo], - seeds: &[&[&[u8]]], - amount: u64, -) -> ProgramResult { - if let [authority_account, stake_info_account, lp_token_custody_account, token_a_custody_account, token_b_custody_account, pool_program_id, farm_lp_token_account, farm_first_reward_token_account, farm_second_reward_token_account, clock_id, spl_token_id, farm_id, farm_authority] = - accounts - { - if !check_stake_program_id(pool_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - - let mut raydium_accounts = vec![ - AccountMeta::new(*farm_id.key, false), - AccountMeta::new_readonly(*farm_authority.key, false), - AccountMeta::new(*stake_info_account.key, false), - AccountMeta::new_readonly(*authority_account.key, true), - AccountMeta::new(*lp_token_custody_account.key, false), - AccountMeta::new(*farm_lp_token_account.key, false), - AccountMeta::new(*token_a_custody_account.key, false), - AccountMeta::new(*farm_first_reward_token_account.key, false), - AccountMeta::new_readonly(*clock_id.key, false), - AccountMeta::new_readonly(*spl_token_id.key, false), - ]; - if *farm_second_reward_token_account.key != zero::id() { - raydium_accounts.push(AccountMeta::new(*token_b_custody_account.key, false)); - raydium_accounts.push(AccountMeta::new( - *farm_second_reward_token_account.key, - false, - )); - } - - let instruction = Instruction { - program_id: *pool_program_id.key, - accounts: raydium_accounts, - data: RaydiumUnstake { - instruction: 2, - amount, - } - .to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/farm-sdk/src/program/protocol/saber.rs b/farms/farm-sdk/src/program/protocol/saber.rs deleted file mode 100644 index d5be18c5e2f..00000000000 --- a/farms/farm-sdk/src/program/protocol/saber.rs +++ /dev/null @@ -1,643 +0,0 @@ -//! Saber specific functions - -use { - crate::{id::zero, pack::check_data_len, program::account}, - arrayref::{array_ref, array_refs}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - hash::Hasher, - instruction::{AccountMeta, Instruction}, - program::{invoke, invoke_signed}, - program_error::ProgramError, - pubkey::Pubkey, - system_program, - }, - stable_swap_client::instruction, -}; - -pub const SABER_FEE: f64 = 0.1; - -pub mod saber_redeemer { - solana_program::declare_id!("RDM23yr8pr1kEAmhnFpaabPny6C9UVcEcok3Py5v86X"); -} - -pub mod saber_decimal_wrapper { - solana_program::declare_id!("DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB"); -} - -pub mod saber_to_usdc_amm { - solana_program::declare_id!("5cmAS6Mj4pG2Vp9hhyu3kpK9yvC7P6ejh9HiobpTE6Jc"); -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct Miner { - /// Key of the [Quarry] this [Miner] works on. - pub quarry_key: Pubkey, - /// Authority who manages this [Miner]. - /// All withdrawals of tokens must accrue to [TokenAccount]s owned by this account. - pub authority: Pubkey, - - /// Bump. - pub bump: u8, - - /// [TokenAccount] to hold the [Miner]'s staked LP tokens. - pub token_vault_key: Pubkey, - - /// Stores the amount of tokens that the [Miner] may claim. - /// Whenever the [Miner] claims tokens, this is reset to 0. - pub rewards_earned: u64, - - /// A checkpoint of the [Quarry]'s reward tokens paid per staked token. - /// - /// When the [Miner] is initialized, this number starts at 0. - /// On the first [quarry_mine::stake_tokens], the [Quarry]#update_rewards_and_miner - /// method is called, which updates this checkpoint to the current quarry value. - /// - /// On a [quarry_mine::claim_rewards], the difference in checkpoints is used to calculate - /// the amount of tokens owed. - pub rewards_per_token_paid: u128, - - /// Number of tokens the [Miner] holds. - pub balance: u64, - - /// Index of the [Miner]. - pub index: u64, -} - -impl Miner { - pub const LEN: usize = 145; - - pub fn get_size(&self) -> usize { - Miner::LEN - } - - pub fn unpack(input: &[u8]) -> Result { - check_data_len(input, Miner::LEN)?; - - let input = array_ref![input, 8, Miner::LEN - 8]; - #[allow(clippy::ptr_offset_with_cast)] - let ( - quarry_key, - authority, - bump, - token_vault_key, - rewards_earned, - rewards_per_token_paid, - balance, - index, - ) = array_refs![input, 32, 32, 1, 32, 8, 16, 8, 8]; - - Ok(Self { - quarry_key: Pubkey::new_from_array(*quarry_key), - authority: Pubkey::new_from_array(*authority), - bump: bump[0], - token_vault_key: Pubkey::new_from_array(*token_vault_key), - rewards_earned: u64::from_le_bytes(*rewards_earned), - rewards_per_token_paid: u128::from_le_bytes(*rewards_per_token_paid), - balance: u64::from_le_bytes(*balance), - index: u64::from_le_bytes(*index), - }) - } -} - -/// Returns amount of LP tokens staked as recorded in the specified stake account -pub fn get_stake_account_balance(stake_account: &AccountInfo) -> Result { - let data = stake_account.try_borrow_data()?; - Ok(Miner::unpack(&data)?.balance) -} - -pub fn get_pool_token_balances<'a, 'b>( - pool_token_a_account: &'a AccountInfo<'b>, - pool_token_b_account: &'a AccountInfo<'b>, -) -> Result<(u64, u64), ProgramError> { - Ok(( - account::get_token_balance(pool_token_a_account)?, - account::get_token_balance(pool_token_b_account)?, - )) -} - -#[allow(clippy::too_many_arguments)] -pub fn wrap_token<'a, 'b>( - wrapper: &'a AccountInfo<'b>, - wrapped_token_mint: &'a AccountInfo<'b>, - wrapper_vault: &'a AccountInfo<'b>, - owner: &'a AccountInfo<'b>, - underlying_token_account: &'a AccountInfo<'b>, - wrapped_token_account: &'a AccountInfo<'b>, - decimal_wrapper_program: &Pubkey, - amount: u64, -) -> ProgramResult { - decimal_wrapper_invoke( - wrapper, - wrapped_token_mint, - wrapper_vault, - owner, - underlying_token_account, - wrapped_token_account, - decimal_wrapper_program, - "global:deposit", - &[&[&[]]], - amount, - ) -} - -#[allow(clippy::too_many_arguments)] -pub fn unwrap_token<'a, 'b>( - wrapper: &'a AccountInfo<'b>, - wrapped_token_mint: &'a AccountInfo<'b>, - wrapper_vault: &'a AccountInfo<'b>, - owner: &'a AccountInfo<'b>, - underlying_token_account: &'a AccountInfo<'b>, - wrapped_token_account: &'a AccountInfo<'b>, - decimal_wrapper_program: &Pubkey, - amount: u64, -) -> ProgramResult { - decimal_wrapper_invoke( - wrapper, - wrapped_token_mint, - wrapper_vault, - owner, - underlying_token_account, - wrapped_token_account, - decimal_wrapper_program, - "global:withdraw", - &[&[&[]]], - amount, - ) -} - -#[allow(clippy::too_many_arguments)] -pub fn wrap_token_with_seeds<'a, 'b>( - wrapper: &'a AccountInfo<'b>, - wrapped_token_mint: &'a AccountInfo<'b>, - wrapper_vault: &'a AccountInfo<'b>, - authority: &'a AccountInfo<'b>, - underlying_token_account: &'a AccountInfo<'b>, - wrapped_token_account: &'a AccountInfo<'b>, - decimal_wrapper_program: &Pubkey, - seeds: &[&[&[u8]]], - amount: u64, -) -> ProgramResult { - decimal_wrapper_invoke( - wrapper, - wrapped_token_mint, - wrapper_vault, - authority, - underlying_token_account, - wrapped_token_account, - decimal_wrapper_program, - "global:deposit", - seeds, - amount, - ) -} - -#[allow(clippy::too_many_arguments)] -pub fn unwrap_token_with_seeds<'a, 'b>( - wrapper: &'a AccountInfo<'b>, - wrapped_token_mint: &'a AccountInfo<'b>, - wrapper_vault: &'a AccountInfo<'b>, - authority: &'a AccountInfo<'b>, - underlying_token_account: &'a AccountInfo<'b>, - wrapped_token_account: &'a AccountInfo<'b>, - decimal_wrapper_program: &Pubkey, - seeds: &[&[&[u8]]], - amount: u64, -) -> ProgramResult { - decimal_wrapper_invoke( - wrapper, - wrapped_token_mint, - wrapper_vault, - authority, - underlying_token_account, - wrapped_token_account, - decimal_wrapper_program, - "global:withdraw", - seeds, - amount, - ) -} - -#[allow(clippy::too_many_arguments)] -fn decimal_wrapper_invoke<'a, 'b>( - wrapper: &'a AccountInfo<'b>, - wrapped_token_mint: &'a AccountInfo<'b>, - wrapper_vault: &'a AccountInfo<'b>, - owner: &'a AccountInfo<'b>, - underlying_token_account: &'a AccountInfo<'b>, - wrapped_token_account: &'a AccountInfo<'b>, - decimal_wrapper_program: &Pubkey, - instruction: &str, - seeds: &[&[&[u8]]], - amount: u64, -) -> ProgramResult { - if &saber_decimal_wrapper::id() != decimal_wrapper_program { - return Err(ProgramError::IncorrectProgramId); - } - - let mut hasher = Hasher::default(); - hasher.hash(instruction.as_bytes()); - - let mut data = hasher.result().as_ref()[..8].to_vec(); - data.extend_from_slice(&amount.to_le_bytes()); - - let accounts = vec![ - AccountMeta::new_readonly(*wrapper.key, false), - AccountMeta::new(*wrapped_token_mint.key, false), - AccountMeta::new(*wrapper_vault.key, false), - AccountMeta::new_readonly(*owner.key, true), - AccountMeta::new(*underlying_token_account.key, false), - AccountMeta::new(*wrapped_token_account.key, false), - AccountMeta::new_readonly(spl_token::id(), false), - ]; - - if seeds[0][0].is_empty() { - invoke( - &Instruction { - program_id: *decimal_wrapper_program, - data, - accounts, - }, - &[ - wrapper.clone(), - wrapped_token_mint.clone(), - wrapper_vault.clone(), - owner.clone(), - underlying_token_account.clone(), - wrapped_token_account.clone(), - ], - ) - } else { - invoke_signed( - &Instruction { - program_id: *decimal_wrapper_program, - data, - accounts, - }, - &[ - wrapper.clone(), - wrapped_token_mint.clone(), - wrapper_vault.clone(), - owner.clone(), - underlying_token_account.clone(), - wrapped_token_account.clone(), - ], - seeds, - ) - } -} - -pub fn user_init_with_seeds(accounts: &[AccountInfo], seeds: &[&[&[u8]]]) -> ProgramResult { - if let [authority_account, funding_account, farm_program_id, lp_token_mint, miner, miner_vault, quarry, rewarder] = - accounts - { - if &quarry_mine::id() != farm_program_id.key { - return Err(ProgramError::IncorrectProgramId); - } - - let (miner_derived, bump) = Pubkey::find_program_address( - &[ - b"Miner", - &quarry.key.to_bytes(), - &authority_account.key.to_bytes(), - ], - &quarry_mine::id(), - ); - - if &miner_derived != miner.key { - return Err(ProgramError::InvalidSeeds); - } - - let mut hasher = Hasher::default(); - hasher.hash(b"global:create_miner"); - - let mut data = hasher.result().as_ref()[..8].to_vec(); - data.push(bump); - - let saber_accounts = vec![ - AccountMeta::new(*authority_account.key, true), - AccountMeta::new(*miner.key, false), - AccountMeta::new(*quarry.key, false), - AccountMeta::new(*rewarder.key, false), - AccountMeta::new_readonly(system_program::id(), false), - AccountMeta::new(*funding_account.key, true), - AccountMeta::new(*lp_token_mint.key, false), - AccountMeta::new(*miner_vault.key, false), - AccountMeta::new_readonly(spl_token::id(), false), - ]; - - let instruction = Instruction { - program_id: quarry_mine::id(), - accounts: saber_accounts, - data, - }; - - invoke_signed(&instruction, accounts, seeds) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} - -pub fn add_liquidity( - accounts: &[AccountInfo], - max_token_a_amount: u64, - max_token_b_amount: u64, -) -> ProgramResult { - if let [user_account, user_token_a_account, user_token_b_account, user_lp_token_account, pool_program_id, pool_token_a_account, pool_token_b_account, lp_token_mint, _spl_token_id, _clock_id, swap_account, swap_authority] = - accounts - { - if &stable_swap_client::id() != pool_program_id.key { - return Err(ProgramError::IncorrectProgramId); - } - - let instruction = instruction::deposit( - &spl_token::id(), - swap_account.key, - swap_authority.key, - user_account.key, - user_token_a_account.key, - user_token_b_account.key, - pool_token_a_account.key, - pool_token_b_account.key, - lp_token_mint.key, - user_lp_token_account.key, - max_token_a_amount, - max_token_b_amount, - 1, - )?; - - invoke(&instruction, accounts) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} - -pub fn add_liquidity_with_seeds( - accounts: &[AccountInfo], - seeds: &[&[&[u8]]], - max_token_a_amount: u64, - max_token_b_amount: u64, -) -> ProgramResult { - if let [authority_account, token_a_custody_account, token_b_custody_account, lp_token_custody_account, pool_program_id, pool_token_a_account, pool_token_b_account, lp_token_mint, _spl_token_id, _clock_id, swap_account, swap_authority] = - accounts - { - if &stable_swap_client::id() != pool_program_id.key { - return Err(ProgramError::IncorrectProgramId); - } - - let instruction = instruction::deposit( - &spl_token::id(), - swap_account.key, - swap_authority.key, - authority_account.key, - token_a_custody_account.key, - token_b_custody_account.key, - pool_token_a_account.key, - pool_token_b_account.key, - lp_token_mint.key, - lp_token_custody_account.key, - max_token_a_amount, - max_token_b_amount, - 1, - )?; - - invoke_signed(&instruction, accounts, seeds) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} - -pub fn remove_liquidity_with_seeds( - accounts: &[AccountInfo], - seeds: &[&[&[u8]]], - amount: u64, -) -> ProgramResult { - if let [authority_account, token_a_custody_account, token_b_custody_account, lp_token_custody_account, pool_program_id, pool_token_a_account, pool_token_b_account, lp_token_mint, _spl_token_id, swap_account, swap_authority, fees_account_a, fees_account_b] = - accounts - { - if &stable_swap_client::id() != pool_program_id.key { - return Err(ProgramError::IncorrectProgramId); - } - - let instruction = instruction::withdraw( - &spl_token::id(), - swap_account.key, - swap_authority.key, - authority_account.key, - lp_token_mint.key, - lp_token_custody_account.key, - pool_token_a_account.key, - pool_token_b_account.key, - token_a_custody_account.key, - token_b_custody_account.key, - fees_account_a.key, - fees_account_b.key, - amount, - 1, - 1, - )?; - - invoke_signed(&instruction, accounts, seeds) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} - -pub fn stake_with_seeds( - accounts: &[AccountInfo], - seeds: &[&[&[u8]]], - amount: u64, -) -> ProgramResult { - if let [authority_account, lp_token_custody_account, farm_program_id, _spl_token_id, miner, miner_vault, quarry, rewarder] = - accounts - { - if &quarry_mine::id() != farm_program_id.key { - return Err(ProgramError::IncorrectProgramId); - } - - let mut hasher = Hasher::default(); - hasher.hash(b"global:stake_tokens"); - - let mut data = hasher.result().as_ref()[..8].to_vec(); - data.extend_from_slice(&amount.to_le_bytes()); - - let saber_accounts = vec![ - AccountMeta::new_readonly(*authority_account.key, true), - AccountMeta::new(*miner.key, false), - AccountMeta::new(*quarry.key, false), - AccountMeta::new(*miner_vault.key, false), - AccountMeta::new(*lp_token_custody_account.key, false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new_readonly(*rewarder.key, false), - ]; - - let instruction = Instruction { - program_id: quarry_mine::id(), - accounts: saber_accounts, - data, - }; - - invoke_signed(&instruction, accounts, seeds) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} - -pub fn claim_rewards_with_seeds(accounts: &[AccountInfo], seeds: &[&[&[u8]]]) -> ProgramResult { - if let [authority_account, iou_token_custody_account, farm_program_id, _spl_token_id, _zero_id, miner, rewarder, minter, mint_wrapper, mint_wrapper_program, iou_token_mint, iou_fees_account, quarry] = - accounts - { - if &quarry_mine::id() != farm_program_id.key - || &quarry_mint_wrapper::id() != mint_wrapper_program.key - { - return Err(ProgramError::IncorrectProgramId); - } - - // harvest IOU rewards - let mut hasher = Hasher::default(); - hasher.hash(b"global:claim_rewards"); - - let data = hasher.result().as_ref()[..8].to_vec(); - - let saber_accounts = vec![ - AccountMeta::new(*mint_wrapper.key, false), - AccountMeta::new_readonly(*mint_wrapper_program.key, false), - AccountMeta::new(*minter.key, false), - AccountMeta::new(*iou_token_mint.key, false), - AccountMeta::new(*iou_token_custody_account.key, false), - AccountMeta::new(*iou_fees_account.key, false), - AccountMeta::new_readonly(*authority_account.key, true), - AccountMeta::new(*miner.key, false), - AccountMeta::new(*quarry.key, false), - AccountMeta::new(zero::id(), false), - AccountMeta::new(zero::id(), false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new_readonly(*rewarder.key, false), - ]; - - let instruction = Instruction { - program_id: quarry_mine::id(), - accounts: saber_accounts, - data, - }; - - invoke_signed(&instruction, accounts, seeds) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} - -pub fn redeem_rewards_with_seeds(accounts: &[AccountInfo], seeds: &[&[&[u8]]]) -> ProgramResult { - if let [authority_account, iou_token_custody_account, sbr_token_custody_account, _spl_token_id, redeemer, redeemer_program, sbr_token_mint, iou_token_mint, saber_vault, saber_mint_proxy_program, mint_proxy_authority, mint_proxy_state, minter_info] = - accounts - { - if redeemer_program.key != &saber_redeemer::id() { - return Err(ProgramError::IncorrectProgramId); - } - - // convert IOU to Saber - let mut hasher = Hasher::default(); - hasher.hash(b"global:redeem_all_tokens_from_mint_proxy"); - - let data = hasher.result().as_ref()[..8].to_vec(); - - let saber_accounts = vec![ - AccountMeta::new_readonly(*redeemer.key, false), - AccountMeta::new(*iou_token_mint.key, false), - AccountMeta::new(*sbr_token_mint.key, false), - AccountMeta::new(*saber_vault.key, false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new_readonly(*authority_account.key, true), - AccountMeta::new(*iou_token_custody_account.key, false), - AccountMeta::new(*sbr_token_custody_account.key, false), - AccountMeta::new_readonly(*mint_proxy_authority.key, false), - AccountMeta::new_readonly(*mint_proxy_state.key, false), - AccountMeta::new_readonly(*saber_mint_proxy_program.key, false), - AccountMeta::new(*minter_info.key, false), - ]; - - let instruction = Instruction { - program_id: *redeemer_program.key, - accounts: saber_accounts, - data, - }; - - invoke_signed(&instruction, accounts, seeds) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} - -pub fn swap_with_seeds( - accounts: &[AccountInfo], - seeds: &[&[&[u8]]], - amount_in: u64, - min_amount_out: u64, -) -> ProgramResult { - if let [authority_account, token_a_custody_account, token_b_custody_account, pool_program_id, pool_token_a_account, pool_token_b_account, _spl_token_id, _clock_id, swap_account, swap_authority, fees_account] = - accounts - { - if &stable_swap_client::id() != pool_program_id.key { - return Err(ProgramError::IncorrectProgramId); - } - - let instruction = instruction::swap( - &spl_token::id(), - swap_account.key, - swap_authority.key, - authority_account.key, - token_a_custody_account.key, - pool_token_a_account.key, - pool_token_b_account.key, - token_b_custody_account.key, - fees_account.key, - amount_in, - min_amount_out, - )?; - - invoke_signed(&instruction, accounts, seeds) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} - -pub fn unstake_with_seeds( - accounts: &[AccountInfo], - seeds: &[&[&[u8]]], - amount: u64, -) -> ProgramResult { - if let [authority_account, lp_token_custody_account, farm_program_id, _spl_token_id, miner, miner_vault, quarry, rewarder] = - accounts - { - if &quarry_mine::id() != farm_program_id.key { - return Err(ProgramError::IncorrectProgramId); - } - - let mut hasher = Hasher::default(); - hasher.hash(b"global:withdraw_tokens"); - - let mut data = hasher.result().as_ref()[..8].to_vec(); - data.extend_from_slice(&amount.to_le_bytes()); - - let saber_accounts = vec![ - AccountMeta::new_readonly(*authority_account.key, true), - AccountMeta::new(*miner.key, false), - AccountMeta::new(*quarry.key, false), - AccountMeta::new(*miner_vault.key, false), - AccountMeta::new(*lp_token_custody_account.key, false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new_readonly(*rewarder.key, false), - ]; - - let instruction = Instruction { - program_id: quarry_mine::id(), - accounts: saber_accounts, - data, - }; - - invoke_signed(&instruction, accounts, seeds) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/farm-sdk/src/refdb.rs b/farms/farm-sdk/src/refdb.rs deleted file mode 100644 index 1b618e5cb1c..00000000000 --- a/farms/farm-sdk/src/refdb.rs +++ /dev/null @@ -1,1388 +0,0 @@ -//! On-chain reference database - -use { - crate::{ - error::FarmError, - id::{main_router, main_router_admin}, - pack::*, - string::ArrayString64, - traits::*, - }, - arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}, - num_enum::TryFromPrimitive, - serde::{Deserialize, Serialize}, - solana_program::{entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey}, - std::mem::size_of, -}; - -/// Whether to init refdb accounts from on-chain program or off-chain. -/// Main Router admin key is used as the Base address to derive refdb address -/// if off-chain initialization is selected. -/// Off-chain is required for accounts with data size > 10K. -/// This is temporary solution until realloc is implemented. -pub const REFDB_ONCHAIN_INIT: bool = false; - -/// Derives the RefDB storage address and the bump seed for the given string -pub fn find_refdb_pda(refdb_name: &str) -> (Pubkey, u8) { - if REFDB_ONCHAIN_INIT { - Pubkey::find_program_address(&[refdb_name.as_bytes()], &main_router::id()) - } else { - ( - Pubkey::create_with_seed(&main_router_admin::id(), refdb_name, &main_router::id()) - .unwrap(), - 0, - ) - } -} - -/// Derives the target metadata object address for the given storage type and object name -pub fn find_target_pda(storage_type: StorageType, target_name: &str) -> (Pubkey, u8) { - Pubkey::find_program_address( - &[storage_type.to_string().as_bytes(), target_name.as_bytes()], - &main_router::id(), - ) -} - -/// Returns the target metadata object address for the given storage type, object name, and bump -pub fn find_target_pda_with_bump( - storage_type: StorageType, - target_name: &str, - bump: u8, -) -> Result { - Pubkey::create_program_address( - &[ - storage_type.to_string().as_bytes(), - target_name.as_bytes(), - &[bump], - ], - &main_router::id(), - ) - .map_err(|_| ProgramError::InvalidSeeds) -} - -/// Derives the description metadata object address for the given storage type and object name -pub fn find_description_pda(storage_type: StorageType, target_name: &str) -> (Pubkey, u8) { - Pubkey::find_program_address( - &[ - storage_type.to_string().as_bytes(), - target_name.as_bytes(), - b"description", - ], - &main_router::id(), - ) -} - -/// Storage Header, one per account -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq)] -pub struct Header { - pub counter: u32, - pub active_records: u32, - pub reference_type: ReferenceType, - #[serde( - serialize_with = "as64_serialize", - deserialize_with = "as64_deserialize" - )] - pub name: ArrayString64, -} - -impl Header { - pub const LEN: usize = 73; - const REF_TYPE_OFFSET: usize = 8; - const NAME_OFFSET: usize = 9; -} - -impl Packed for Header { - fn get_size(&self) -> usize { - Header::LEN - } - - fn pack(&self, output: &mut [u8]) -> Result { - check_data_len(output, Header::LEN)?; - - let output = array_mut_ref![output, 0, Header::LEN]; - - let (counter_out, active_records_out, reference_type_out, name_out) = - mut_array_refs![output, 4, 4, 1, 64]; - *counter_out = self.counter.to_le_bytes(); - *active_records_out = self.active_records.to_le_bytes(); - reference_type_out[0] = self.reference_type as u8; - pack_array_string64(&self.name, name_out); - - Ok(Header::LEN) - } - - fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; Header::LEN] = [0; Header::LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidAccountData) - } - } - - fn unpack(input: &[u8]) -> Result { - check_data_len(input, Header::LEN)?; - - let input = array_ref![input, 0, Header::LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let (counter, active_records, reference_type, name) = array_refs![input, 4, 4, 1, 64]; - - Ok(Self { - counter: u32::from_le_bytes(*counter), - active_records: u32::from_le_bytes(*active_records), - reference_type: ReferenceType::try_from_primitive(reference_type[0]) - .or(Err(ProgramError::InvalidAccountData))?, - name: unpack_array_string64(name)?, - }) - } -} - -/// Reference is a short, fixed size data field, used to store homogeneous value -/// or a link to the account with more detailed data -#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)] -pub enum Reference { - Pubkey { data: Pubkey }, - U8 { data: u8 }, - U16 { data: u16 }, - U32 { data: u32 }, - U64 { data: u64 }, - F64 { data: f64 }, - Empty, -} - -impl Reference { - pub const MAX_LEN: usize = std::mem::size_of::(); - pub const PUBKEY_LEN: usize = size_of::(); - pub const U8_LEN: usize = size_of::(); - pub const U16_LEN: usize = size_of::(); - pub const U32_LEN: usize = size_of::(); - pub const U64_LEN: usize = size_of::(); - pub const F64_LEN: usize = size_of::(); - - pub const fn get_type(&self) -> ReferenceType { - match self { - Reference::Pubkey { .. } => ReferenceType::Pubkey, - Reference::U8 { .. } => ReferenceType::U8, - Reference::U16 { .. } => ReferenceType::U16, - Reference::U32 { .. } => ReferenceType::U32, - Reference::U64 { .. } => ReferenceType::U64, - Reference::F64 { .. } => ReferenceType::F64, - Reference::Empty => ReferenceType::Empty, - } - } -} - -#[repr(u8)] -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)] -pub enum ReferenceType { - Pubkey, - U8, - U16, - U32, - U64, - F64, - Empty, -} - -impl ReferenceType { - pub const fn get_size(&self) -> usize { - match self { - ReferenceType::Pubkey => size_of::(), - ReferenceType::U8 => size_of::(), - ReferenceType::U16 => size_of::(), - ReferenceType::U32 => size_of::(), - ReferenceType::U64 => size_of::(), - ReferenceType::F64 => size_of::(), - ReferenceType::Empty => 0, - } - } -} - -impl std::fmt::Display for ReferenceType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match *self { - ReferenceType::Pubkey => write!(f, "Pubkey"), - ReferenceType::U8 => write!(f, "U8"), - ReferenceType::U16 => write!(f, "U16"), - ReferenceType::U32 => write!(f, "U32"), - ReferenceType::U64 => write!(f, "U64"), - ReferenceType::F64 => write!(f, "F64"), - ReferenceType::Empty => write!(f, "Empty"), - } - } -} - -#[repr(u8)] -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)] -pub enum StorageType { - Program, - Vault, - Pool, - Farm, - Token, - Fund, - Other, -} - -impl StorageType { - pub const fn get_default_size(storage_type: StorageType) -> usize { - match storage_type { - StorageType::Program => 25000usize, - StorageType::Fund => 10000usize, - StorageType::Vault => 50000usize, - StorageType::Pool => 50000usize, - StorageType::Farm => 50000usize, - StorageType::Token => 500000usize, - _ => 0usize, - } - } - - pub const fn get_default_max_records( - storage_type: StorageType, - reference_type: ReferenceType, - ) -> usize { - let record_size = Record::get_size_with_reference(reference_type); - (StorageType::get_default_size(storage_type) - Header::LEN) / record_size - } - - pub const fn get_storage_size_for_records( - reference_type: ReferenceType, - records_num: usize, - ) -> usize { - if records_num > u32::MAX as usize { - return 0; - } - let record_size = Record::get_size_with_reference(reference_type); - records_num * record_size + Header::LEN - } - - pub const fn get_storage_size_for_max_records( - storage_type: StorageType, - reference_type: ReferenceType, - ) -> usize { - StorageType::get_storage_size_for_records( - reference_type, - StorageType::get_default_max_records(storage_type, reference_type), - ) - } -} - -impl std::fmt::Display for StorageType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match *self { - StorageType::Program => write!(f, "Program"), - StorageType::Fund => write!(f, "Fund"), - StorageType::Vault => write!(f, "Vault"), - StorageType::Pool => write!(f, "Pool"), - StorageType::Farm => write!(f, "Farm"), - StorageType::Token => write!(f, "Token"), - StorageType::Other => write!(f, "Other"), - } - } -} - -impl std::str::FromStr for StorageType { - type Err = ProgramError; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "program" => Ok(StorageType::Program), - "fund" => Ok(StorageType::Fund), - "vault" => Ok(StorageType::Vault), - "pool" => Ok(StorageType::Pool), - "farm" => Ok(StorageType::Farm), - "token" => Ok(StorageType::Token), - "other" => Ok(StorageType::Other), - _ => Err(ProgramError::InvalidArgument), - } - } -} - -/// Data record; All records have the same reference type for single storage -#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)] -pub struct Record { - // index is the record location index [0..total_records-1] and is not stored on-chain, - // but returned to the reader for more efficient consecutive read/writes. - // if index is set to None record will be looked up by name with linear search. - pub index: Option, - pub counter: u16, - pub tag: u16, - #[serde( - serialize_with = "as64_serialize", - deserialize_with = "as64_deserialize" - )] - pub name: ArrayString64, - pub reference: Reference, -} - -impl Named for Record { - fn name(&self) -> ArrayString64 { - self.name - } -} - -impl Record { - pub const NO_REF_LEN: usize = 68; - pub const MAX_LEN: usize = Record::NO_REF_LEN + Reference::MAX_LEN; - - pub const fn get_size(&self) -> usize { - match self.reference { - Reference::Pubkey { .. } => Record::NO_REF_LEN + size_of::(), - Reference::U8 { .. } => Record::NO_REF_LEN + size_of::(), - Reference::U16 { .. } => Record::NO_REF_LEN + size_of::(), - Reference::U32 { .. } => Record::NO_REF_LEN + size_of::(), - Reference::U64 { .. } => Record::NO_REF_LEN + size_of::(), - Reference::F64 { .. } => Record::NO_REF_LEN + size_of::(), - Reference::Empty => Record::NO_REF_LEN, - } - } - - pub const fn get_size_with_reference(reference_type: ReferenceType) -> usize { - Record::NO_REF_LEN + reference_type.get_size() - } - - pub fn pack(&self, output: &mut [u8]) -> Result { - let record_size = self.get_size(); - check_data_len(output, record_size)?; - - match self.reference { - Reference::Pubkey { data } => self.pack_with_pubkey(output, &data), - Reference::U8 { data } => self.pack_with_u8(output, data), - Reference::U16 { data } => self.pack_with_u16(output, data), - Reference::U32 { data } => self.pack_with_u32(output, data), - Reference::U64 { data } => self.pack_with_u64(output, data), - Reference::F64 { data } => self.pack_with_f64(output, data), - Reference::Empty => self.pack_with_empty(output), - } - - Ok(record_size) - } - - pub fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; Record::MAX_LEN] = [0; Record::MAX_LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidAccountData) - } - } - - pub fn unpack( - input: &[u8], - reference_type: ReferenceType, - index: Option, - ) -> Result { - let record_size = Record::NO_REF_LEN + reference_type.get_size(); - check_data_len(input, record_size)?; - - match reference_type { - ReferenceType::Pubkey => Record::unpack_with_pubkey(input, index), - ReferenceType::U8 => Record::unpack_with_u8(input, index), - ReferenceType::U16 => Record::unpack_with_u16(input, index), - ReferenceType::U32 => Record::unpack_with_u32(input, index), - ReferenceType::U64 => Record::unpack_with_u64(input, index), - ReferenceType::F64 => Record::unpack_with_f64(input, index), - ReferenceType::Empty => Record::unpack_with_empty(input, index), - } - } - - pub fn unpack_counter(input: &[u8]) -> Result { - check_data_len(input, Record::NO_REF_LEN)?; - let counter = array_ref![input, 0, 2]; - Ok(u16::from_le_bytes(*counter) as usize) - } - - pub fn unpack_counter_and_name(input: &[u8]) -> Result<(usize, ArrayString64), ProgramError> { - check_data_len(input, Record::NO_REF_LEN)?; - let counter = array_ref![input, 0, 2]; - let name = array_ref![input, 4, 64]; - Ok(( - u16::from_le_bytes(*counter) as usize, - unpack_array_string64(name)?, - )) - } - - fn pack_with_pubkey(&self, output: &mut [u8], data: &Pubkey) { - let output = array_mut_ref![output, 0, Record::NO_REF_LEN + Reference::PUBKEY_LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let (counter_out, tag_out, name_out, reference_out) = - mut_array_refs![output, 2, 2, 64, Reference::PUBKEY_LEN]; - *counter_out = self.counter.to_le_bytes(); - *tag_out = self.tag.to_le_bytes(); - pack_array_string64(&self.name, name_out); - reference_out.copy_from_slice(data.as_ref()); - } - - fn pack_with_u8(&self, output: &mut [u8], data: u8) { - let output = array_mut_ref![output, 0, Record::NO_REF_LEN + Reference::U8_LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let (counter_out, tag_out, name_out, reference_out) = - mut_array_refs![output, 2, 2, 64, Reference::U8_LEN]; - *counter_out = self.counter.to_le_bytes(); - *tag_out = self.tag.to_le_bytes(); - pack_array_string64(&self.name, name_out); - *reference_out = data.to_le_bytes(); - } - - fn pack_with_u16(&self, output: &mut [u8], data: u16) { - let output = array_mut_ref![output, 0, Record::NO_REF_LEN + Reference::U16_LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let (counter_out, tag_out, name_out, reference_out) = - mut_array_refs![output, 2, 2, 64, Reference::U16_LEN]; - *counter_out = self.counter.to_le_bytes(); - *tag_out = self.tag.to_le_bytes(); - pack_array_string64(&self.name, name_out); - *reference_out = data.to_le_bytes(); - } - - fn pack_with_u32(&self, output: &mut [u8], data: u32) { - let output = array_mut_ref![output, 0, Record::NO_REF_LEN + Reference::U32_LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let (counter_out, tag_out, name_out, reference_out) = - mut_array_refs![output, 2, 2, 64, Reference::U32_LEN]; - *counter_out = self.counter.to_le_bytes(); - *tag_out = self.tag.to_le_bytes(); - pack_array_string64(&self.name, name_out); - *reference_out = data.to_le_bytes(); - } - - fn pack_with_u64(&self, output: &mut [u8], data: u64) { - let output = array_mut_ref![output, 0, Record::NO_REF_LEN + Reference::U64_LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let (counter_out, tag_out, name_out, reference_out) = - mut_array_refs![output, 2, 2, 64, Reference::U64_LEN]; - *counter_out = self.counter.to_le_bytes(); - *tag_out = self.tag.to_le_bytes(); - pack_array_string64(&self.name, name_out); - *reference_out = data.to_le_bytes(); - } - - fn pack_with_f64(&self, output: &mut [u8], data: f64) { - let output = array_mut_ref![output, 0, Record::NO_REF_LEN + Reference::F64_LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let (counter_out, tag_out, name_out, reference_out) = - mut_array_refs![output, 2, 2, 64, Reference::F64_LEN]; - *counter_out = self.counter.to_le_bytes(); - *tag_out = self.tag.to_le_bytes(); - pack_array_string64(&self.name, name_out); - *reference_out = data.to_le_bytes(); - } - - fn pack_with_empty(&self, output: &mut [u8]) { - let output = array_mut_ref![output, 0, Record::NO_REF_LEN]; - let (counter_out, tag_out, name_out) = mut_array_refs![output, 2, 2, 64]; - *counter_out = self.counter.to_le_bytes(); - *tag_out = self.tag.to_le_bytes(); - pack_array_string64(&self.name, name_out); - } - - fn unpack_with_pubkey(input: &[u8], index: Option) -> Result { - let input = array_ref![input, 0, Record::NO_REF_LEN + Reference::PUBKEY_LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let (counter, tag, name, reference) = array_refs![input, 2, 2, 64, Reference::PUBKEY_LEN]; - Ok(Self { - index, - counter: u16::from_le_bytes(*counter), - tag: u16::from_le_bytes(*tag), - name: unpack_array_string64(name)?, - reference: Reference::Pubkey { - data: Pubkey::new_from_array(*reference), - }, - }) - } - - fn unpack_with_u8(input: &[u8], index: Option) -> Result { - let input = array_ref![input, 0, Record::NO_REF_LEN + Reference::U8_LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let (counter, tag, name, reference) = array_refs![input, 2, 2, 64, Reference::U8_LEN]; - Ok(Self { - index, - counter: u16::from_le_bytes(*counter), - tag: u16::from_le_bytes(*tag), - name: unpack_array_string64(name)?, - reference: Reference::U8 { data: reference[0] }, - }) - } - - fn unpack_with_u16(input: &[u8], index: Option) -> Result { - let input = array_ref![input, 0, Record::NO_REF_LEN + Reference::U16_LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let (counter, tag, name, reference) = array_refs![input, 2, 2, 64, Reference::U16_LEN]; - Ok(Self { - index, - counter: u16::from_le_bytes(*counter), - tag: u16::from_le_bytes(*tag), - name: unpack_array_string64(name)?, - reference: Reference::U16 { - data: u16::from_le_bytes(*reference), - }, - }) - } - - fn unpack_with_u32(input: &[u8], index: Option) -> Result { - let input = array_ref![input, 0, Record::NO_REF_LEN + Reference::U32_LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let (counter, tag, name, reference) = array_refs![input, 2, 2, 64, Reference::U32_LEN]; - Ok(Self { - index, - counter: u16::from_le_bytes(*counter), - tag: u16::from_le_bytes(*tag), - name: unpack_array_string64(name)?, - reference: Reference::U32 { - data: u32::from_le_bytes(*reference), - }, - }) - } - - fn unpack_with_u64(input: &[u8], index: Option) -> Result { - let input = array_ref![input, 0, Record::NO_REF_LEN + Reference::U64_LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let (counter, tag, name, reference) = array_refs![input, 2, 2, 64, Reference::U64_LEN]; - Ok(Self { - index, - counter: u16::from_le_bytes(*counter), - tag: u16::from_le_bytes(*tag), - name: unpack_array_string64(name)?, - reference: Reference::U64 { - data: u64::from_le_bytes(*reference), - }, - }) - } - - fn unpack_with_f64(input: &[u8], index: Option) -> Result { - let input = array_ref![input, 0, Record::NO_REF_LEN + Reference::F64_LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let (counter, tag, name, reference) = array_refs![input, 2, 2, 64, Reference::F64_LEN]; - Ok(Self { - index, - counter: u16::from_le_bytes(*counter), - tag: u16::from_le_bytes(*tag), - name: unpack_array_string64(name)?, - reference: Reference::F64 { - data: f64::from_le_bytes(*reference), - }, - }) - } - - fn unpack_with_empty(input: &[u8], index: Option) -> Result { - let input = array_ref![input, 0, Record::NO_REF_LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let (counter, tag, name) = array_refs![input, 2, 2, 64]; - Ok(Self { - index, - counter: u16::from_le_bytes(*counter), - tag: u16::from_le_bytes(*tag), - name: unpack_array_string64(name)?, - reference: Reference::Empty, - }) - } -} - -/// RefDB manages homogeneous records in a given continuous storage -pub struct RefDB {} - -impl RefDB { - /// Initializes the storage, must be called before first read/write - pub fn init( - data: &mut [u8], - name: &ArrayString64, - reference_type: ReferenceType, - ) -> ProgramResult { - if RefDB::is_initialized(data) { - return Err(ProgramError::AccountAlreadyInitialized); - } - let record_size = Record::NO_REF_LEN + reference_type.get_size(); - check_data_len(data, Header::LEN + record_size)?; - let header = Header { - counter: 1, - active_records: 0, - reference_type, - name: *name, - }; - header.pack(data)?; - Ok(()) - } - - /// Clears out underlying storage - pub fn drop(data: &mut [u8]) -> Result { - check_data_len(data, Header::LEN)?; - if data.len() > 2000 { - Err(FarmError::RefdbTooLarge.into()) - } else { - data.fill(0); - Ok(data.len()) - } - } - - /// Checks if the storage is empty - pub fn is_empty(data: &[u8]) -> Result { - Ok(RefDB::get_active_records(data)? == 0) - } - - /// Checks if the storage is full - pub fn is_full(data: &[u8]) -> Result { - Ok(RefDB::get_free_records(data)? == 0) - } - - /// Checks if the storage has been updated - pub fn is_updated(data: &[u8], last_counter: usize) -> Result { - Ok(RefDB::get_storage_counter(data)? > last_counter) - } - - /// Checks if data storage has been initialized. - /// It can return false positives if storage is not managed by RefDB. - pub fn is_initialized(data: &[u8]) -> bool { - if let Ok(header) = Header::unpack(data) { - if let Ok(rec_size) = RefDB::get_record_size(data) { - if header.counter > 0 - && header.active_records as usize <= (data.len() - Header::LEN) / rec_size - { - return true; - } - } - } - false - } - - /// Returns unpacked storage header - pub fn get_storage_header(data: &[u8]) -> Result { - Header::unpack(data) - } - - /// Returns the storage updates counter - pub fn get_storage_counter(data: &[u8]) -> Result { - check_data_len(data, Header::LEN)?; - let counter = u32::from_le_bytes(*array_ref![data, 0, 4]) as usize; - if counter > 0 { - Ok(counter) - } else { - Err(ProgramError::UninitializedAccount) - } - } - - /// Sets the storage counter to the new value - pub fn set_storage_counter(data: &mut [u8], counter: usize) -> Result { - if counter == 0 { - return Err(ProgramError::InvalidArgument); - } - check_data_len(data, Header::LEN)?; - - let counter_out = array_mut_ref![data, 0, 4]; - *counter_out = (counter as u32).to_le_bytes(); - - Ok(counter) - } - - /// Returns the number of active records (not marked as deleted) - pub fn get_active_records(data: &[u8]) -> Result { - check_data_len(data, Header::LEN)?; - Ok(u32::from_le_bytes(*array_ref![data, 4, 4]) as usize) - } - - /// Sets the number of active records to the new value - pub fn set_active_records(data: &mut [u8], records: usize) -> Result { - check_data_len(data, Header::LEN)?; - - let records_out = array_mut_ref![data, 4, 4]; - *records_out = (records as u32).to_le_bytes(); - - Ok(records) - } - - /// Returns the number of free records - pub fn get_free_records(data: &[u8]) -> Result { - let rec_size = RefDB::get_record_size(data)?; - Ok((data.len() - RefDB::get_active_records(data)? * rec_size - Header::LEN) / rec_size) - } - - /// Returns total number of allocated records - pub fn get_total_records(data: &[u8]) -> Result { - Ok((data.len() - Header::LEN) / RefDB::get_record_size(data)?) - } - - /// Returns the length of a single record - pub fn get_record_size(data: &[u8]) -> Result { - Ok(Record::NO_REF_LEN + RefDB::get_reference_type(data)?.get_size()) - } - - /// Returns the type of reference data - pub fn get_reference_type(data: &[u8]) -> Result { - check_data_len(data, Header::LEN)?; - ReferenceType::try_from_primitive(data[Header::REF_TYPE_OFFSET]) - .or(Err(ProgramError::InvalidAccountData)) - } - - /// Returns the name of the DB - pub fn get_name(data: &[u8]) -> Result { - check_data_len(data, Header::LEN)?; - let name = array_ref![data, Header::NAME_OFFSET, 64]; - unpack_array_string64(name) - } - - /// Returns the record associated with the given name - pub fn read(data: &[u8], name: &ArrayString64) -> Result, ProgramError> { - if let Some(index) = RefDB::find_index(data, name)? { - RefDB::read_at(data, index) - } else { - Ok(None) - } - } - - /// Returns the record at the given index - pub fn read_at(data: &[u8], index: usize) -> Result, ProgramError> { - let offset = RefDB::get_offset(data, index)?; - let ref_type = RefDB::get_reference_type(data)?; - let record = Record::unpack(&data[offset..], ref_type, Some(index as u32))?; - if record.counter > 0 { - Ok(Some(record)) - } else { - Ok(None) - } - } - - /// Returns the record only if it has been updated - pub fn read_if_changed( - data: &[u8], - name: &ArrayString64, - last_counter: usize, - ) -> Result, ProgramError> { - if let Some(index) = RefDB::find_index(data, name)? { - RefDB::read_at_if_changed(data, index, last_counter) - } else { - Ok(None) - } - } - - /// Returns the record at the given index only if it has been updated - pub fn read_at_if_changed( - data: &[u8], - index: usize, - last_counter: usize, - ) -> Result, ProgramError> { - let offset = RefDB::get_offset(data, index)?; - let counter = RefDB::get_record_counter(data, offset)?; - if counter > last_counter { - RefDB::read_at(data, index) - } else { - Ok(None) - } - } - - /// Returns all active records in the storage - pub fn read_all(data: &[u8]) -> Result, ProgramError> { - let rec_num = RefDB::get_total_records(data)?; - let active_rec = RefDB::get_active_records(data)?; - let mut vec: Vec = vec![]; - if active_rec == 0 { - return Ok(vec); - } - for i in 0..rec_num { - if let Some(rec) = RefDB::read_at(data, i)? { - vec.push(rec); - if vec.len() == active_rec { - return Ok(vec); - } - } - } - Err(ProgramError::InvalidAccountData) - } - - /// Returns all active records in the storage if any of them was updated - pub fn read_all_if_changed( - data: &[u8], - last_counter: usize, - ) -> Result, ProgramError> { - if RefDB::get_storage_counter(data)? > last_counter { - RefDB::read_all(data) - } else { - Ok(Vec::::default()) - } - } - - /// Writes the record to the storage. - /// Uses the index if provided or searches the record by name. - /// If counter is provided it must be equal to stored value or error is returned. - pub fn write(data: &mut [u8], record: &Record) -> Result { - let offset = if let Some(idx) = record.index { - // if the index was specified we will update existing record - RefDB::get_offset(data, idx as usize)? - } else { - // otherwise either find a record with the supplied name or first available slot - RefDB::find_write_offset(data, &record.name)? - }; - let (cur_counter, cur_name) = RefDB::get_record_counter_and_name(data, offset)?; - if cur_counter > 0 { - // if the counter was specified we check that value is equal to stored, - // to make sure there were no intermediate updates - if record.counter > 0 && cur_counter != record.counter as usize { - return Err(FarmError::RefdbRecordCounterMismatch.into()); - } - // check that we are either writing to an empty slot or record name matches - if record.index.is_some() && record.name != cur_name { - return Err(FarmError::RefdbRecordNameMismatch.into()); - } - } - // check that reference data type matches storage - if RefDB::get_reference_type(data)? != record.reference.get_type() { - return Err(FarmError::RefdbRecordTypeMismatch.into()); - } - // update storage counters - let storage_counter = RefDB::get_storage_counter(data)?; - if (storage_counter as u32) < u32::MAX { - RefDB::set_storage_counter(data, storage_counter + 1)?; - } else { - RefDB::set_storage_counter(data, 1)?; - } - if cur_counter == 0 { - let active_records = RefDB::get_active_records(data)?; - if (active_records as u32) < u32::MAX { - RefDB::set_active_records(data, active_records + 1)?; - } - } - // write record - let res = record.pack(&mut data[offset..]); - // update record counter - if (cur_counter as u16) < u16::MAX { - RefDB::set_record_counter(data, offset, cur_counter + 1); - } else { - RefDB::set_record_counter(data, offset, 1); - } - res - } - - /// Updates the reference value in the storage for the record with the given name. - /// It doesn't validate storage type, counter or name. Should be used only if - /// record is active (i.e. to update existing record), you are certain that - /// the storage and index are correct, and you don't care if the record was - /// updated since last read time. - pub fn update( - data: &mut [u8], - name: &ArrayString64, - reference: &Reference, - ) -> Result { - if let Some(index) = RefDB::find_index(data, name)? { - RefDB::update_at(data, index, reference) - } else { - Err(FarmError::RefdbRecordNotFound.into()) - } - } - - /// Updates the reference value in the storage at the given index. - /// It doesn't validate storage type, counter or name. Should be used only if - /// record is active (i.e. to update existing record), you are certain that - /// the storage and index are correct, and you don't care if the record was - /// updated since last read time. - pub fn update_at( - data: &mut [u8], - index: usize, - reference: &Reference, - ) -> Result { - let offset = RefDB::get_offset(data, index)?; - let mut cur_record = Record::unpack(&data[offset..], reference.get_type(), None)?; - // update storage counters - let storage_counter = RefDB::get_storage_counter(data)?; - if (storage_counter as u32) < u32::MAX { - RefDB::set_storage_counter(data, storage_counter + 1)?; - } else { - RefDB::set_storage_counter(data, 1)?; - } - if cur_record.counter == 0 { - return Err(ProgramError::UninitializedAccount); - } - // write record - if (cur_record.counter as u16) < u16::MAX { - cur_record.counter += 1; - } else { - cur_record.counter = 1; - } - cur_record.reference = *reference; - cur_record.pack(&mut data[offset..]) - } - - /// Deletes the record from the storage. - /// Uses the index if provided or searches the record by name. - /// If counter is provided it checks that it is equal to stored or error is returned. - pub fn delete(data: &mut [u8], record: &Record) -> Result { - let offset = if let Some(idx) = record.index { - // if the index was specified we will update existing record - RefDB::get_offset(data, idx as usize)? - } else { - // otherwise either find a record with the supplied name or first available slot - RefDB::find_write_offset(data, &record.name)? - }; - let data_end = offset + record.get_size(); - check_data_len(data, data_end)?; - let (stored_counter, stored_name) = RefDB::get_record_counter_and_name(data, offset)?; - if stored_counter == 0 { - return Ok(0); - } - // if the counter was specified we check that value is equal to stored, - // to make sure there were no intermediate updates - if record.counter > 0 && stored_counter != record.counter as usize { - return Err(FarmError::RefdbRecordCounterMismatch.into()); - } - // check that we are deleting record with matching name - if record.name != stored_name { - return Err(FarmError::RefdbRecordNameMismatch.into()); - } - // update data and counters - let counter = RefDB::get_storage_counter(data)?; - if (counter as u32) < u32::MAX { - RefDB::set_storage_counter(data, counter + 1)?; - } else { - RefDB::set_storage_counter(data, 1)?; - } - let active_records = RefDB::get_active_records(data)?; - if active_records > 0 { - RefDB::set_active_records(data, active_records - 1)?; - } - data[offset..data_end].fill(0); - - Ok(record.get_size()) - } - - /// Deletes the record from the storage using the name only. - pub fn delete_with_name( - data: &mut [u8], - name: &ArrayString64, - index: Option, - ) -> Result { - RefDB::delete( - data, - &Record { - index, - counter: 0, - tag: 0, - name: *name, - reference: Reference::Empty, - }, - ) - } - - /// Returns index of the record with the given name or None if not found - pub fn find_index(data: &[u8], name: &ArrayString64) -> Result, ProgramError> { - let rec_active = RefDB::get_active_records(data)?; - if rec_active == 0 { - return Ok(None); - } - let rec_num = RefDB::get_total_records(data)?; - let rec_size = RefDB::get_record_size(data)?; - let mut offset = Header::LEN; - let mut checked = 0; - for index in 0..rec_num { - let (counter, rec_name) = RefDB::get_record_counter_and_name(data, offset)?; - if counter > 0 { - if rec_name == *name { - return Ok(Some(index)); - } - checked += 1; - if checked == rec_active { - return Ok(None); - } - } - offset += rec_size; - } - Ok(None) - } - - /// Returns the index of the first empty record at the back of the storage, - /// i.e. there will be no active records after the index - pub fn find_last_index(data: &[u8]) -> Result { - let rec_active = RefDB::get_active_records(data)?; - if rec_active == 0 { - return Ok(0); - } - let rec_num = RefDB::get_total_records(data)?; - let rec_size = RefDB::get_record_size(data)?; - let mut offset = Header::LEN; - let mut checked = 0; - for index in 0..rec_num { - let counter = RefDB::get_record_counter(data, offset)?; - if counter > 0 { - checked += 1; - if checked == rec_active { - return Ok((index + 1) as u32); - } - } - offset += rec_size; - } - Err(ProgramError::InvalidAccountData) - } - - /// Returns the index of the next empty record to write to in the storage - pub fn find_next_index(data: &[u8]) -> Result { - let rec_active = RefDB::get_active_records(data)?; - if rec_active == 0 { - return Ok(0); - } - let rec_num = RefDB::get_total_records(data)?; - let rec_size = RefDB::get_record_size(data)?; - let mut offset = Header::LEN; - let mut checked = 0; - for index in 0..rec_num { - let counter = RefDB::get_record_counter(data, offset)?; - if counter == 0 { - return Ok(index as u32); - } else { - checked += 1; - if checked == rec_active { - return Ok((index + 1) as u32); - } - } - offset += rec_size; - } - Err(ProgramError::InvalidAccountData) - } - - // private helpers - - /// Returns offset of the record given its index - fn get_offset(data: &[u8], index: usize) -> Result { - let rec_size = RefDB::get_record_size(data)?; - let offset = Header::LEN + index * rec_size; - check_data_len(data, offset)?; - Ok(offset) - } - - fn find_write_offset(data: &[u8], name: &ArrayString64) -> Result { - let rec_active = RefDB::get_active_records(data)?; - if rec_active == 0 { - return Ok(Header::LEN); - } - let rec_num = RefDB::get_total_records(data)?; - let rec_size = RefDB::get_record_size(data)?; - let mut offset = Header::LEN; - let mut checked = 0; - let mut free_slot = 0; - for _ in 0..rec_num { - let (counter, rec_name) = RefDB::get_record_counter_and_name(data, offset)?; - if counter > 0 { - if rec_name == *name { - return Ok(offset); - } - checked += 1; - if checked == rec_active { - offset += rec_size; - break; - } - } else if free_slot == 0 { - free_slot = offset; - } - offset += rec_size; - } - if free_slot > 0 { - Ok(free_slot) - } else { - Ok(offset) - } - } - - fn get_record_counter(data: &[u8], offset: usize) -> Result { - Record::unpack_counter(&data[offset..]) - } - - fn set_record_counter(data: &mut [u8], offset: usize, counter: usize) { - if counter == 0 { - return; - } - let counter_out = array_mut_ref![data, offset, 2]; - *counter_out = (counter as u16).to_le_bytes(); - } - - fn get_record_counter_and_name( - data: &[u8], - offset: usize, - ) -> Result<(usize, ArrayString64), ProgramError> { - Record::unpack_counter_and_name(&data[offset..]) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn init_test() { - let mut data = vec![0; Header::LEN + Record::MAX_LEN * 6]; - assert!(!RefDB::is_initialized(data.as_slice())); - - assert!(RefDB::init( - data.as_mut_slice(), - &ArrayString64::from_utf8("test").unwrap(), - ReferenceType::Pubkey - ) - .is_ok()); - - assert!(RefDB::is_initialized(data.as_slice())); - assert_eq!( - Header { - counter: 1, - active_records: 0, - reference_type: ReferenceType::Pubkey, - name: ArrayString64::from_utf8("test").unwrap() - }, - RefDB::get_storage_header(data.as_slice()).unwrap() - ); - assert_eq!(RefDB::get_storage_counter(data.as_slice()).unwrap(), 1); - assert_eq!(RefDB::get_active_records(data.as_slice()).unwrap(), 0); - assert_eq!( - RefDB::get_reference_type(data.as_slice()).unwrap(), - ReferenceType::Pubkey - ); - assert!(RefDB::init( - data.as_mut_slice(), - &ArrayString64::from_utf8("test").unwrap(), - ReferenceType::Pubkey - ) - .is_err()); - let _ = RefDB::drop(data.as_mut_slice()); - assert!(!RefDB::is_initialized(data.as_slice())); - - assert!(RefDB::init( - data.as_mut_slice(), - &ArrayString64::from_utf8("test2").unwrap(), - ReferenceType::U8 - ) - .is_ok()); - assert_eq!(RefDB::get_storage_counter(data.as_slice()).unwrap(), 1); - assert_eq!(RefDB::get_active_records(data.as_slice()).unwrap(), 0); - assert_eq!( - RefDB::get_reference_type(data.as_slice()).unwrap(), - ReferenceType::U8 - ); - - assert_eq!( - Header { - counter: 1, - active_records: 0, - reference_type: ReferenceType::U8, - name: ArrayString64::from_utf8("test2").unwrap() - }, - RefDB::get_storage_header(data.as_slice()).unwrap() - ); - } - - #[test] - fn read_write_test() { - // init - let mut data = vec![0; Header::LEN + Record::MAX_LEN * 3]; - assert!(RefDB::init( - data.as_mut_slice(), - &ArrayString64::from_utf8("test").unwrap(), - ReferenceType::Pubkey - ) - .is_ok()); - - // write - let mut record = Record { - index: Some(1), - counter: 0, - tag: 123, - name: ArrayString64::from_utf8("test record").unwrap(), - reference: Reference::Pubkey { - data: Pubkey::new_unique(), - }, - }; - assert_eq!( - RefDB::get_record_size(data.as_slice()).unwrap(), - Record::NO_REF_LEN + Reference::PUBKEY_LEN - ); - assert_eq!(RefDB::get_total_records(data.as_slice()).unwrap(), 3); - assert_eq!(RefDB::get_free_records(data.as_slice()).unwrap(), 3); - assert_eq!(RefDB::get_active_records(data.as_slice()).unwrap(), 0); - assert_eq!(RefDB::get_storage_counter(data.as_slice()).unwrap(), 1); - assert!(RefDB::write(data.as_mut_slice(), &record).is_ok()); - assert_eq!(RefDB::get_total_records(data.as_slice()).unwrap(), 3); - assert_eq!(RefDB::get_free_records(data.as_slice()).unwrap(), 2); - assert_eq!(RefDB::get_active_records(data.as_slice()).unwrap(), 1); - assert_eq!(RefDB::get_storage_counter(data.as_slice()).unwrap(), 2); - - let read = RefDB::read( - data.as_slice(), - &ArrayString64::from_utf8("test record").unwrap(), - ) - .unwrap() - .unwrap(); - - record.index = Some(1); - record.counter = 1; - assert_eq!(read, record); - - // update - record.tag = 321; - record.reference = Reference::Pubkey { - data: Pubkey::new_unique(), - }; - RefDB::write(data.as_mut_slice(), &record).unwrap(); - assert_eq!(RefDB::get_total_records(data.as_slice()).unwrap(), 3); - assert_eq!(RefDB::get_free_records(data.as_slice()).unwrap(), 2); - assert_eq!(RefDB::get_active_records(data.as_slice()).unwrap(), 1); - assert_eq!(RefDB::get_storage_counter(data.as_slice()).unwrap(), 3); - - let read = RefDB::read( - data.as_slice(), - &ArrayString64::from_utf8("test record").unwrap(), - ) - .unwrap() - .unwrap(); - - record.counter = 2; - assert_eq!(read, record); - - // fast update - let new_ref = Reference::Pubkey { - data: Pubkey::new_unique(), - }; - assert!( - RefDB::update( - data.as_mut_slice(), - &ArrayString64::from_utf8("test record").unwrap(), - &new_ref - ) - .unwrap() - > 0 - ); - let read = RefDB::read( - data.as_slice(), - &ArrayString64::from_utf8("test record").unwrap(), - ) - .unwrap() - .unwrap(); - assert_eq!(read.reference, new_ref); - - // update should fail if counter is stale - record.counter = 1; - assert!(RefDB::write(data.as_mut_slice(), &record).is_err()); - assert_eq!(RefDB::get_total_records(data.as_slice()).unwrap(), 3); - assert_eq!(RefDB::get_free_records(data.as_slice()).unwrap(), 2); - assert_eq!(RefDB::get_active_records(data.as_slice()).unwrap(), 1); - assert_eq!(RefDB::get_storage_counter(data.as_slice()).unwrap(), 4); - - // write another record - let mut record2 = Record { - index: None, - counter: 0, - tag: 123, - name: ArrayString64::from_utf8("test record2").unwrap(), - reference: Reference::U8 { data: 0 }, - }; - // update should fail if reference type mismatch - assert!(RefDB::write(data.as_mut_slice(), &record2).is_err()); - - record2.reference = Reference::Pubkey { - data: Pubkey::new_unique(), - }; - RefDB::write(data.as_mut_slice(), &record2).unwrap(); - assert_eq!(RefDB::get_total_records(data.as_slice()).unwrap(), 3); - assert_eq!(RefDB::get_free_records(data.as_slice()).unwrap(), 1); - assert_eq!(RefDB::get_active_records(data.as_slice()).unwrap(), 2); - assert_eq!(RefDB::get_storage_counter(data.as_slice()).unwrap(), 5); - - let read = RefDB::read( - data.as_slice(), - &ArrayString64::from_utf8("test record2").unwrap(), - ) - .unwrap() - .unwrap(); - - record2.index = Some(0); - record2.counter = 1; - assert_eq!(read, record2); - - // check old record is still there - let read = RefDB::read( - data.as_slice(), - &ArrayString64::from_utf8("test record").unwrap(), - ) - .unwrap() - .unwrap(); - - record.counter = 3; - record.reference = new_ref; - assert_eq!(read, record); - - // update record with index - record2.tag = 567; - RefDB::write(data.as_mut_slice(), &record2).unwrap(); - let read = RefDB::read_at(data.as_slice(), record2.index.unwrap() as usize) - .unwrap() - .unwrap(); - record2.counter = 2; - assert_eq!(read, record2); - - // write another - let mut record3 = Record { - index: None, - counter: 0, - tag: 3, - name: ArrayString64::from_utf8("test record3").unwrap(), - reference: Reference::Pubkey { - data: Pubkey::new_unique(), - }, - }; - RefDB::write(data.as_mut_slice(), &record3).unwrap(); - assert_eq!(RefDB::get_total_records(data.as_slice()).unwrap(), 3); - assert_eq!(RefDB::get_free_records(data.as_slice()).unwrap(), 0); - assert_eq!(RefDB::get_active_records(data.as_slice()).unwrap(), 3); - assert_eq!(RefDB::get_storage_counter(data.as_slice()).unwrap(), 7); - - // full storage write - record3.name = ArrayString64::from_utf8("test record4").unwrap(); - assert!(RefDB::write(data.as_mut_slice(), &record3).is_err()); - - // delete record - assert!(RefDB::delete_with_name( - data.as_mut_slice(), - &ArrayString64::from_utf8("test record4").unwrap(), - None - ) - .is_err()); - assert_eq!(RefDB::get_total_records(data.as_slice()).unwrap(), 3); - assert_eq!(RefDB::get_free_records(data.as_slice()).unwrap(), 0); - assert_eq!(RefDB::get_active_records(data.as_slice()).unwrap(), 3); - assert_eq!(RefDB::get_storage_counter(data.as_slice()).unwrap(), 7); - - assert!(RefDB::delete_with_name( - data.as_mut_slice(), - &ArrayString64::from_utf8("test record2").unwrap(), - None - ) - .is_ok()); - assert_eq!(RefDB::get_total_records(data.as_slice()).unwrap(), 3); - assert_eq!(RefDB::get_free_records(data.as_slice()).unwrap(), 1); - assert_eq!(RefDB::get_active_records(data.as_slice()).unwrap(), 2); - assert_eq!(RefDB::get_storage_counter(data.as_slice()).unwrap(), 8); - - assert!( - RefDB::read_at(data.as_slice(), record2.index.unwrap() as usize) - .unwrap() - .is_none() - ); - record2.index = None; - assert!(RefDB::read( - data.as_slice(), - &ArrayString64::from_utf8("test record2").unwrap(), - ) - .unwrap() - .is_none()); - - // write again - record2.counter = 0; - assert!(RefDB::write(data.as_mut_slice(), &record2).is_ok()); - assert_eq!(RefDB::get_total_records(data.as_slice()).unwrap(), 3); - assert_eq!(RefDB::get_free_records(data.as_slice()).unwrap(), 0); - assert_eq!(RefDB::get_active_records(data.as_slice()).unwrap(), 3); - assert_eq!(RefDB::get_storage_counter(data.as_slice()).unwrap(), 9); - - let read = RefDB::read( - data.as_slice(), - &ArrayString64::from_utf8("test record2").unwrap(), - ) - .unwrap() - .unwrap(); - - record2.index = Some(0); - record2.counter = 1; - assert_eq!(read, record2); - } -} diff --git a/farms/farm-sdk/src/string.rs b/farms/farm-sdk/src/string.rs deleted file mode 100644 index 9eb4d6c6ef8..00000000000 --- a/farms/farm-sdk/src/string.rs +++ /dev/null @@ -1,74 +0,0 @@ -//! Fixed length string types - -//use arrayvec::ArrayString; -use { - arraystring::{typenum::U64, ArrayString}, - serde::Serialize, - solana_program::{instruction::Instruction, program_error::ProgramError, pubkey::Pubkey}, - std::collections::HashMap, -}; - -/// Fixed size array to store UTF-8 strings on blockchain. -pub type ArrayString64 = ArrayString; - -pub fn to_pretty_json(object: &T) -> Result -where - T: ?Sized + Serialize, -{ - serde_json::to_string_pretty(&object) -} - -// Custom serializer that prints base58 addresses instead of arrays -pub fn instruction_to_string(inst: &Instruction) -> String { - let len = 145 + inst.data.len() * 4 + inst.accounts.len() * 40; - let mut s = String::with_capacity(len); - s += format!("{{\"program_id\":\"{}\",\"accounts\":[", inst.program_id).as_str(); - let mut first_object = true; - for val in &inst.accounts { - if !first_object { - s += ","; - } else { - first_object = false; - } - s += format!( - "{{\"pubkey\":\"{}\",\"is_signer\":{},\"is_writable\":{}}}", - val.pubkey, val.is_signer, val.is_writable - ) - .as_str(); - } - s += format!("],\"data\":{:?}}}", inst.data).as_str(); - s -} - -// Custom serializer that prints base58 addresses instead of arrays -pub fn pubkey_map_to_string(map: &HashMap) -> String { - if map.is_empty() { - return "{}".to_string(); - } - let mut len = 1; - for key in map.keys() { - len += key.len() + 50; - } - let mut s = String::with_capacity(len); - s += "{"; - for (key, val) in map { - if s.len() != 1 { - s += ","; - } - s += format!("\"{}\":\"{}\"", key, val).as_str(); - } - s += "}"; - s -} - -pub fn str_to_as64(input: &str) -> Result { - ArrayString64::try_from_str(input).or(Err(ProgramError::InvalidArgument)) -} - -pub fn capitalize(s: &str) -> String { - let mut c = s.chars(); - match c.next() { - None => String::new(), - Some(f) => f.to_uppercase().collect::() + c.as_str(), - } -} diff --git a/farms/farm-sdk/src/token.rs b/farms/farm-sdk/src/token.rs deleted file mode 100644 index 03b519fe118..00000000000 --- a/farms/farm-sdk/src/token.rs +++ /dev/null @@ -1,259 +0,0 @@ -//! Token - -use { - crate::{pack::*, string::ArrayString64, traits::*}, - arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}, - num_enum::TryFromPrimitive, - serde::{Deserialize, Serialize}, - serde_json::{to_string, Value}, - solana_program::{program_error::ProgramError, pubkey::Pubkey}, - std::collections::HashMap, -}; - -#[repr(u8)] -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)] -pub enum TokenType { - NativeSol, - WrappedSol, - WrappedSollet, - WrappedWarmhole, - SplToken, - LpToken, - VtToken, - FundToken, -} - -#[repr(u8)] -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)] -pub enum TokenSelector { - TokenA, - TokenB, -} - -#[repr(u8)] -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)] -pub enum OracleType { - Pyth, - Chainlink, - Unsupported, -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq)] -pub struct OraclePrice { - pub price: u64, - pub exponent: i32, -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq)] -pub struct Token { - #[serde( - serialize_with = "as64_serialize", - deserialize_with = "as64_deserialize" - )] - pub name: ArrayString64, - #[serde( - serialize_with = "as64_serialize", - deserialize_with = "as64_deserialize" - )] - pub description: ArrayString64, - pub token_type: TokenType, - pub refdb_index: Option, - pub refdb_counter: u16, - pub decimals: u8, - pub chain_id: u16, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub mint: Pubkey, - pub oracle_type: OracleType, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - pub oracle_account: Option, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub description_account: Pubkey, -} - -#[derive(Deserialize, Serialize, Debug, Clone)] -pub struct GitToken { - #[serde(rename = "chainId")] - pub chain_id: i32, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub address: Pubkey, - pub symbol: String, - pub name: String, - pub decimals: i32, - #[serde(rename = "logoURI", default)] - pub logo_uri: String, - #[serde(default)] - pub tags: Vec, - #[serde(flatten)] - pub extra: HashMap, -} - -impl Named for Token { - fn name(&self) -> ArrayString64 { - self.name - } -} - -impl Token { - pub const LEN: usize = 237; -} - -impl Packed for Token { - fn get_size(&self) -> usize { - Token::LEN - } - - fn pack(&self, output: &mut [u8]) -> Result { - check_data_len(output, Token::LEN)?; - - let output = array_mut_ref![output, 0, Token::LEN]; - - let ( - name_out, - description_out, - token_type_out, - refdb_index_out, - refdb_counter_out, - decimals_out, - chain_id_out, - mint_out, - oracle_type_out, - oracle_account_out, - description_account_out, - ) = mut_array_refs![output, 64, 64, 1, 5, 2, 1, 2, 32, 1, 33, 32]; - pack_array_string64(&self.name, name_out); - pack_array_string64(&self.description, description_out); - token_type_out[0] = self.token_type as u8; - pack_option_u32(self.refdb_index, refdb_index_out); - *refdb_counter_out = self.refdb_counter.to_le_bytes(); - decimals_out[0] = self.decimals; - *chain_id_out = self.chain_id.to_le_bytes(); - mint_out.copy_from_slice(self.mint.as_ref()); - oracle_type_out[0] = self.oracle_type as u8; - pack_option_key(&self.oracle_account, oracle_account_out); - description_account_out.copy_from_slice(self.description_account.as_ref()); - - Ok(Token::LEN) - } - - fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; Token::LEN] = [0; Token::LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidAccountData) - } - } - - fn unpack(input: &[u8]) -> Result { - check_data_len(input, Token::LEN)?; - - let input = array_ref![input, 0, Token::LEN]; - #[allow(clippy::ptr_offset_with_cast)] - let ( - name, - description, - token_type, - refdb_index, - refdb_counter, - decimals, - chain_id, - mint, - oracle_type, - oracle_account, - description_account, - ) = array_refs![input, 64, 64, 1, 5, 2, 1, 2, 32, 1, 33, 32]; - - Ok(Self { - name: unpack_array_string64(name)?, - description: unpack_array_string64(description)?, - token_type: TokenType::try_from_primitive(token_type[0]) - .or(Err(ProgramError::InvalidAccountData))?, - refdb_index: unpack_option_u32(refdb_index)?, - refdb_counter: u16::from_le_bytes(*refdb_counter), - decimals: decimals[0], - chain_id: u16::from_le_bytes(*chain_id), - mint: Pubkey::new_from_array(*mint), - oracle_type: OracleType::try_from_primitive(oracle_type[0]) - .or(Err(ProgramError::InvalidAccountData))?, - oracle_account: unpack_option_key(oracle_account)?, - description_account: Pubkey::new_from_array(*description_account), - }) - } -} - -impl std::fmt::Display for TokenType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match *self { - TokenType::NativeSol => write!(f, "NativeSol"), - TokenType::WrappedSol => write!(f, "WrappedSol"), - TokenType::WrappedSollet => write!(f, "WrappedSollet"), - TokenType::WrappedWarmhole => write!(f, "WrappedWarmhole"), - TokenType::SplToken => write!(f, "SplToken"), - TokenType::LpToken => write!(f, "LpToken"), - TokenType::VtToken => write!(f, "VtToken"), - TokenType::FundToken => write!(f, "FundToken"), - } - } -} - -impl std::fmt::Display for Token { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", to_string(&self).unwrap()) - } -} - -impl std::fmt::Display for TokenSelector { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match *self { - TokenSelector::TokenA => write!(f, "TokenA"), - TokenSelector::TokenB => write!(f, "TokenB"), - } - } -} - -impl std::str::FromStr for TokenSelector { - type Err = ProgramError; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "tokena" => Ok(TokenSelector::TokenA), - "tokenb" => Ok(TokenSelector::TokenB), - _ => Err(ProgramError::InvalidArgument), - } - } -} - -impl std::fmt::Display for OracleType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match *self { - OracleType::Pyth => write!(f, "Pyth"), - OracleType::Chainlink => write!(f, "Chainlink"), - OracleType::Unsupported => write!(f, "Unsupported"), - } - } -} - -impl std::str::FromStr for OracleType { - type Err = ProgramError; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "pyth" => Ok(OracleType::Pyth), - "chainlink" => Ok(OracleType::Chainlink), - "unsupported" => Ok(OracleType::Unsupported), - _ => Err(ProgramError::InvalidArgument), - } - } -} diff --git a/farms/farm-sdk/src/traits.rs b/farms/farm-sdk/src/traits.rs deleted file mode 100644 index 23ce4c853c9..00000000000 --- a/farms/farm-sdk/src/traits.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::string::ArrayString64; -use solana_program::program_error::ProgramError; - -pub trait Named { - fn name(&self) -> ArrayString64; -} - -pub trait Packed { - fn get_size(&self) -> usize; - - fn pack(&self, output: &mut [u8]) -> Result; - - fn to_vec(&self) -> Result, ProgramError>; - - fn unpack(input: &[u8]) -> Result - where - Self: Sized; -} - -pub trait Versioned { - fn version(&self) -> u16; -} diff --git a/farms/farm-sdk/src/vault.rs b/farms/farm-sdk/src/vault.rs deleted file mode 100644 index 96dc914c6b7..00000000000 --- a/farms/farm-sdk/src/vault.rs +++ /dev/null @@ -1,473 +0,0 @@ -//! Solana Vault - -use { - crate::{pack::*, string::ArrayString64, traits::*}, - arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}, - num_enum::TryFromPrimitive, - serde::{Deserialize, Serialize}, - serde_json::to_string, - solana_program::{clock::UnixTimestamp, program_error::ProgramError, pubkey::Pubkey}, -}; - -#[repr(u8)] -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)] -pub enum VaultType { - AmmStake, -} - -#[allow(clippy::large_enum_variant)] -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq)] -pub enum VaultStrategy { - StakeLpCompoundRewards { - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pool_router_id: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pool_id: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pool_ref: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - farm_router_id: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - farm_id: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - farm_ref: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - lp_token_custody: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - token_a_custody: Pubkey, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - token_b_custody: Option, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - token_a_reward_custody: Pubkey, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - token_b_reward_custody: Option, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - vault_stake_info: Pubkey, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - vault_stake_custody: Option, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - reward_exchange_pool_id: Option, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - reward_exchange_pool_ref: Option, - }, - DynamicHedge, -} - -#[repr(u8)] -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)] -pub enum VaultStrategyType { - StakeLpCompoundRewards, - DynamicHedge, -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq)] -pub struct Vault { - #[serde( - serialize_with = "as64_serialize", - deserialize_with = "as64_deserialize" - )] - pub name: ArrayString64, - pub version: u16, - pub vault_type: VaultType, - pub official: bool, - #[serde(skip_serializing, skip_deserializing)] - pub refdb_index: Option, - #[serde(skip_serializing, skip_deserializing)] - pub refdb_counter: u16, - pub metadata_bump: u8, - pub authority_bump: u8, - pub vault_token_bump: u8, - pub lock_required: bool, - pub unlock_required: bool, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub vault_program_id: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub vault_authority: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub vault_token_ref: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub info_account: Pubkey, - #[serde( - deserialize_with = "pubkey_deserialize", - serialize_with = "pubkey_serialize" - )] - pub multisig_account: Pubkey, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - pub fees_account_a: Option, - #[serde( - deserialize_with = "optional_pubkey_deserialize", - serialize_with = "optional_pubkey_serialize" - )] - pub fees_account_b: Option, - pub strategy: VaultStrategy, -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Default, Eq, PartialEq)] -pub struct VaultUserInfo { - pub last_deposit_time: UnixTimestamp, - pub last_withdrawal_time: UnixTimestamp, - pub tokens_a_added: u64, - pub tokens_b_added: u64, - pub tokens_a_removed: u64, - pub tokens_b_removed: u64, - pub lp_tokens_debt: u64, -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Default, PartialEq)] -pub struct VaultInfo { - pub crank_time: UnixTimestamp, - pub crank_step: u64, - pub tokens_a_added: u64, - pub tokens_b_added: u64, - pub tokens_a_removed: u64, - pub tokens_b_removed: u64, - pub tokens_a_rewards: u64, - pub tokens_b_rewards: u64, - pub stake_balance: f64, - pub deposit_allowed: bool, - pub withdrawal_allowed: bool, - pub min_crank_interval: u64, - pub fee: f64, - pub external_fee: f64, -} - -impl Named for Vault { - fn name(&self) -> ArrayString64 { - self.name - } -} - -impl Versioned for Vault { - fn version(&self) -> u16 { - self.version - } -} - -impl Vault { - pub const MAX_LEN: usize = 792; - pub const STAKE_LP_COMPOUND_REWARDS_LEN: usize = 792; - pub const DYNAMIC_HEDGE_LEN: usize = 1; - - fn pack_stake_lp_compound_rewards(&self, output: &mut [u8]) -> Result { - check_data_len(output, Vault::STAKE_LP_COMPOUND_REWARDS_LEN)?; - - if let VaultStrategy::StakeLpCompoundRewards { - pool_router_id, - pool_id, - pool_ref, - farm_router_id, - farm_id, - farm_ref, - lp_token_custody, - token_a_custody, - token_b_custody, - token_a_reward_custody, - token_b_reward_custody, - vault_stake_info, - vault_stake_custody, - reward_exchange_pool_id, - reward_exchange_pool_ref, - } = self.strategy - { - let output = array_mut_ref![output, 0, Vault::STAKE_LP_COMPOUND_REWARDS_LEN]; - - let ( - strategy_type_out, - name_out, - version_out, - vault_type_out, - official_out, - refdb_index_out, - refdb_counter_out, - metadata_bump_out, - authority_bump_out, - vault_token_bump_out, - lock_required_out, - unlock_required_out, - vault_program_id_out, - vault_authority_out, - vault_token_ref_out, - vault_info_account_out, - multisig_account_out, - fees_account_a_out, - fees_account_b_out, - pool_router_id_out, - pool_id_out, - pool_ref_out, - farm_router_id_out, - farm_id_out, - farm_ref_out, - lp_token_custody_out, - token_a_custody_out, - token_b_custody_out, - token_a_reward_custody_out, - token_b_reward_custody_out, - vault_stake_info_out, - vault_stake_custody_out, - reward_exchange_pool_id_out, - reward_exchange_pool_ref_out, - ) = mut_array_refs![ - output, 1, 64, 2, 1, 1, 5, 2, 1, 1, 1, 1, 1, 32, 32, 32, 32, 32, 33, 33, 32, 32, - 32, 32, 32, 32, 32, 32, 33, 32, 33, 32, 33, 33, 33 - ]; - - strategy_type_out[0] = VaultStrategyType::StakeLpCompoundRewards as u8; - - pack_array_string64(&self.name, name_out); - *version_out = self.version.to_le_bytes(); - vault_type_out[0] = self.vault_type as u8; - official_out[0] = self.official as u8; - pack_option_u32(self.refdb_index, refdb_index_out); - *refdb_counter_out = self.refdb_counter.to_le_bytes(); - metadata_bump_out[0] = self.metadata_bump as u8; - authority_bump_out[0] = self.authority_bump as u8; - vault_token_bump_out[0] = self.vault_token_bump as u8; - lock_required_out[0] = self.lock_required as u8; - unlock_required_out[0] = self.unlock_required as u8; - vault_program_id_out.copy_from_slice(self.vault_program_id.as_ref()); - vault_authority_out.copy_from_slice(self.vault_authority.as_ref()); - vault_token_ref_out.copy_from_slice(self.vault_token_ref.as_ref()); - vault_info_account_out.copy_from_slice(self.info_account.as_ref()); - multisig_account_out.copy_from_slice(self.multisig_account.as_ref()); - pack_option_key(&self.fees_account_a, fees_account_a_out); - pack_option_key(&self.fees_account_b, fees_account_b_out); - pool_router_id_out.copy_from_slice(pool_router_id.as_ref()); - pool_id_out.copy_from_slice(pool_id.as_ref()); - pool_ref_out.copy_from_slice(pool_ref.as_ref()); - farm_router_id_out.copy_from_slice(farm_router_id.as_ref()); - farm_id_out.copy_from_slice(farm_id.as_ref()); - farm_ref_out.copy_from_slice(farm_ref.as_ref()); - lp_token_custody_out.copy_from_slice(lp_token_custody.as_ref()); - token_a_custody_out.copy_from_slice(token_a_custody.as_ref()); - pack_option_key(&token_b_custody, token_b_custody_out); - token_a_reward_custody_out.copy_from_slice(token_a_reward_custody.as_ref()); - pack_option_key(&token_b_reward_custody, token_b_reward_custody_out); - vault_stake_info_out.copy_from_slice(vault_stake_info.as_ref()); - pack_option_key(&vault_stake_custody, vault_stake_custody_out); - pack_option_key(&reward_exchange_pool_id, reward_exchange_pool_id_out); - pack_option_key(&reward_exchange_pool_ref, reward_exchange_pool_ref_out); - - Ok(Vault::STAKE_LP_COMPOUND_REWARDS_LEN) - } else { - Err(ProgramError::InvalidAccountData) - } - } - - fn unpack_stake_lp_compound_rewards(input: &[u8]) -> Result { - check_data_len(input, Vault::STAKE_LP_COMPOUND_REWARDS_LEN)?; - - let input = array_ref![input, 1, Vault::STAKE_LP_COMPOUND_REWARDS_LEN - 1]; - #[allow(clippy::ptr_offset_with_cast)] - let ( - name, - version, - vault_type, - official, - refdb_index, - refdb_counter, - metadata_bump, - authority_bump, - vault_token_bump, - lock_required, - unlock_required, - vault_program_id, - vault_authority, - vault_token_ref, - info_account, - multisig_account, - fees_account_a, - fees_account_b, - pool_router_id, - pool_id, - pool_ref, - farm_router_id, - farm_id, - farm_ref, - lp_token_custody, - token_a_custody, - token_b_custody, - token_a_reward_custody, - token_b_reward_custody, - vault_stake_info, - vault_stake_custody, - reward_exchange_pool_id, - reward_exchange_pool_ref, - ) = array_refs![ - input, 64, 2, 1, 1, 5, 2, 1, 1, 1, 1, 1, 32, 32, 32, 32, 32, 33, 33, 32, 32, 32, 32, - 32, 32, 32, 32, 33, 32, 33, 32, 33, 33, 33 - ]; - - Ok(Self { - name: unpack_array_string64(name)?, - version: u16::from_le_bytes(*version), - vault_type: VaultType::try_from_primitive(vault_type[0]) - .or(Err(ProgramError::InvalidAccountData))?, - official: unpack_bool(official)?, - refdb_index: unpack_option_u32(refdb_index)?, - refdb_counter: u16::from_le_bytes(*refdb_counter), - metadata_bump: metadata_bump[0], - authority_bump: authority_bump[0], - vault_token_bump: vault_token_bump[0], - lock_required: unpack_bool(lock_required)?, - unlock_required: unpack_bool(unlock_required)?, - vault_program_id: Pubkey::new_from_array(*vault_program_id), - vault_authority: Pubkey::new_from_array(*vault_authority), - vault_token_ref: Pubkey::new_from_array(*vault_token_ref), - info_account: Pubkey::new_from_array(*info_account), - multisig_account: Pubkey::new_from_array(*multisig_account), - fees_account_a: unpack_option_key(fees_account_a)?, - fees_account_b: unpack_option_key(fees_account_b)?, - strategy: VaultStrategy::StakeLpCompoundRewards { - pool_router_id: Pubkey::new_from_array(*pool_router_id), - pool_id: Pubkey::new_from_array(*pool_id), - pool_ref: Pubkey::new_from_array(*pool_ref), - farm_router_id: Pubkey::new_from_array(*farm_router_id), - farm_id: Pubkey::new_from_array(*farm_id), - farm_ref: Pubkey::new_from_array(*farm_ref), - lp_token_custody: Pubkey::new_from_array(*lp_token_custody), - token_a_custody: Pubkey::new_from_array(*token_a_custody), - token_b_custody: unpack_option_key(token_b_custody)?, - token_a_reward_custody: Pubkey::new_from_array(*token_a_reward_custody), - token_b_reward_custody: unpack_option_key(token_b_reward_custody)?, - vault_stake_info: Pubkey::new_from_array(*vault_stake_info), - vault_stake_custody: unpack_option_key(vault_stake_custody)?, - reward_exchange_pool_id: unpack_option_key(reward_exchange_pool_id)?, - reward_exchange_pool_ref: unpack_option_key(reward_exchange_pool_ref)?, - }, - }) - } -} - -impl Packed for Vault { - fn get_size(&self) -> usize { - match self.strategy { - VaultStrategy::StakeLpCompoundRewards { .. } => Vault::STAKE_LP_COMPOUND_REWARDS_LEN, - VaultStrategy::DynamicHedge { .. } => Vault::DYNAMIC_HEDGE_LEN, - } - } - - fn pack(&self, output: &mut [u8]) -> Result { - match self.strategy { - VaultStrategy::StakeLpCompoundRewards { .. } => { - self.pack_stake_lp_compound_rewards(output) - } - VaultStrategy::DynamicHedge { .. } => Err(ProgramError::UnsupportedSysvar), - } - } - - fn to_vec(&self) -> Result, ProgramError> { - let mut output: [u8; Vault::MAX_LEN] = [0; Vault::MAX_LEN]; - if let Ok(len) = self.pack(&mut output[..]) { - Ok(output[..len].to_vec()) - } else { - Err(ProgramError::InvalidAccountData) - } - } - - fn unpack(input: &[u8]) -> Result { - check_data_len(input, 1)?; - let strategy_type = VaultStrategyType::try_from_primitive(input[0]) - .or(Err(ProgramError::InvalidAccountData))?; - match strategy_type { - VaultStrategyType::StakeLpCompoundRewards => { - Vault::unpack_stake_lp_compound_rewards(input) - } - VaultStrategyType::DynamicHedge { .. } => Err(ProgramError::UnsupportedSysvar), - } - } -} - -impl std::fmt::Display for VaultStrategyType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match *self { - VaultStrategyType::StakeLpCompoundRewards => write!(f, "StakeLpCompoundRewards"), - VaultStrategyType::DynamicHedge => write!(f, "DynamicHedge"), - } - } -} - -impl std::fmt::Display for VaultType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match *self { - VaultType::AmmStake => write!(f, "AmmStake"), - } - } -} - -impl std::fmt::Display for Vault { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", to_string(&self).unwrap()) - } -} - -impl std::fmt::Display for VaultUserInfo { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", to_string(&self).unwrap()) - } -} - -impl std::fmt::Display for VaultInfo { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", to_string(&self).unwrap()) - } -} diff --git a/farms/fund/.gitignore b/farms/fund/.gitignore deleted file mode 100644 index 96ef6c0b944..00000000000 --- a/farms/fund/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -Cargo.lock diff --git a/farms/fund/Cargo.toml b/farms/fund/Cargo.toml deleted file mode 100644 index 46907e448c6..00000000000 --- a/farms/fund/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "solana-fund" -version = "1.1.3" -description = "Solana Yield Farming Fund" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana-program-library/farms" -license = "Apache-2.0" -homepage = "https://solana.com/" -edition = "2021" - -[features] -no-entrypoint = [] -debug = [] - -[dependencies] -solana-farm-sdk = "1.1.3" -solana-program = "1.9.18" -solana-security-txt = "1.0.1" -spl-token = { version = "3.2.0", features = ["no-entrypoint"] } -num_enum = "0.5.7" - -[dev-dependencies] -solana-program-test = "1.9.18" -solana-farm-client = "1.1.3" -solana-sdk = "1.9.18" -solana-cli-config = "1.9.18" -solana-logger = "1.9.18" -rand = "0.8.5" -log = "0.4.16" - -[lib] -crate-type = ["cdylib", "lib"] - diff --git a/farms/fund/README.md b/farms/fund/README.md deleted file mode 120000 index ccd27901fd5..00000000000 --- a/farms/fund/README.md +++ /dev/null @@ -1 +0,0 @@ -../docs/crate.md \ No newline at end of file diff --git a/farms/fund/Xargo.toml b/farms/fund/Xargo.toml deleted file mode 100644 index 1744f098ae1..00000000000 --- a/farms/fund/Xargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.bpfel-unknown-unknown.dependencies.std] -features = [] \ No newline at end of file diff --git a/farms/fund/src/common.rs b/farms/fund/src/common.rs deleted file mode 100644 index 94c1a9cc8ba..00000000000 --- a/farms/fund/src/common.rs +++ /dev/null @@ -1,367 +0,0 @@ -//! Common functions - -use { - crate::{fund_info::FundInfo, user_info::UserInfo}, - solana_farm_sdk::{ - fund::{ - Fund, FundAssetType, FundAssets, FundCustody, FundCustodyType, FundUserRequests, - FundVault, FundVaultType, DISCRIMINATOR_FUND_CUSTODY, DISCRIMINATOR_FUND_VAULT, - }, - id::{main_router, zero}, - math, - program::{account, clock}, - token::Token, - traits::Packed, - }, - solana_program::{ - account_info::AccountInfo, clock::UnixTimestamp, entrypoint::ProgramResult, msg, - program_error::ProgramError, pubkey::Pubkey, - }, -}; - -#[allow(clippy::too_many_arguments)] -pub fn check_wd_custody_accounts<'a, 'b>( - fund_program_id: &Pubkey, - fund_metadata: &Pubkey, - custody_token: &Token, - custody_token_metadata: &'a AccountInfo<'b>, - user_wd_token_account: &'a AccountInfo<'b>, - custody_account: &'a AccountInfo<'b>, - custody_fees_account: &'a AccountInfo<'b>, - custody_metadata: &'a AccountInfo<'b>, - oracle_account: &'a AccountInfo<'b>, -) -> ProgramResult { - let deposit_token_mint = - if let Ok(mint) = account::get_token_account_mint(user_wd_token_account) { - mint - } else { - msg!("Error: Invalid user's deposit token account"); - return Err(ProgramError::Custom(500)); - }; - - let custody_account_mint = if let Ok(mint) = account::get_token_account_mint(custody_account) { - mint - } else { - msg!("Error: Invalid custody token account mint"); - return Err(ProgramError::Custom(501)); - }; - - if custody_token.mint != custody_account_mint || deposit_token_mint != custody_account_mint { - msg!("Error: Custody token mint mismatch"); - return Err(ProgramError::Custom(502)); - } - - let custody = account::unpack::(custody_metadata, "custody")?; - - if &custody.token_ref != custody_token_metadata.key - || custody_token_metadata.owner != &main_router::id() - { - msg!("Error: Invalid custody token account"); - return Err(ProgramError::Custom(503)); - } - - if custody_metadata.owner != fund_program_id - || custody.discriminator != DISCRIMINATOR_FUND_CUSTODY - || &custody.fund_ref != fund_metadata - || custody.custody_type != FundCustodyType::DepositWithdraw - || &custody.address != custody_account.key - || &custody.fees_address != custody_fees_account.key - || &custody_token.oracle_account.unwrap_or_else(zero::id) != oracle_account.key - { - msg!("Error: Invalid custody accounts"); - Err(ProgramError::Custom(504)) - } else { - Ok(()) - } -} - -#[allow(clippy::too_many_arguments)] -pub fn check_custody_account<'a, 'b>( - fund_program_id: &Pubkey, - fund_metadata: &Pubkey, - custody_token: &Token, - custody_token_metadata: &'a AccountInfo<'b>, - custody_metadata: &'a AccountInfo<'b>, - custody_type: FundCustodyType, - custody_account: &'a AccountInfo<'b>, - custody_fees_account: Option<&Pubkey>, -) -> ProgramResult { - let custody_account_mint = if let Ok(mint) = account::get_token_account_mint(custody_account) { - mint - } else { - msg!("Error: Invalid custody token account mint"); - return Err(ProgramError::Custom(501)); - }; - - if custody_token.mint != custody_account_mint { - msg!("Error: Custody token mint mismatch"); - return Err(ProgramError::Custom(502)); - } - - let custody = account::unpack::(custody_metadata, "custody")?; - - if &custody.token_ref != custody_token_metadata.key - || custody_token_metadata.owner != &main_router::id() - { - msg!("Error: Invalid custody token account"); - return Err(ProgramError::Custom(503)); - } - - if custody_metadata.owner != fund_program_id - || custody.discriminator != DISCRIMINATOR_FUND_CUSTODY - || &custody.fund_ref != fund_metadata - || custody.custody_type != custody_type - || &custody.address != custody_account.key - || &custody.fees_address != custody_fees_account.unwrap_or(&custody.fees_address) - { - msg!("Error: Invalid custody accounts"); - return Err(ProgramError::Custom(504)); - } - - Ok(()) -} - -pub fn check_and_get_fund_assets_account( - fund: &Fund, - fund_assets_account: &AccountInfo, - assets_type: FundAssetType, -) -> Result { - let fund_assets = account::unpack::(fund_assets_account, "Fund assets")?; - - let fund_assets_info_derived = Pubkey::create_program_address( - &[ - if assets_type == FundAssetType::Custody { - b"custodies_assets_info" - } else { - b"vaults_assets_info" - }, - fund.name.as_bytes(), - &[fund_assets.bump], - ], - &fund.fund_program_id, - )?; - - if &fund_assets_info_derived != fund_assets_account.key { - msg!("Error: Invalid fund assets account"); - return Err(ProgramError::Custom(505)); - } - - Ok(fund_assets) -} - -pub fn check_vault_account<'a, 'b>( - fund_program_id: &Pubkey, - fund_metadata: &'a AccountInfo<'b>, - vault_metadata: &'a AccountInfo<'b>, - vault_type: FundVaultType, -) -> ProgramResult { - if vault_metadata.owner != fund_program_id { - msg!("Error: Invalid custody owner"); - return Err(ProgramError::IllegalOwner); - } - - let vault = account::unpack::(vault_metadata, "Vault")?; - - if vault.discriminator != DISCRIMINATOR_FUND_VAULT - || vault.fund_ref != *fund_metadata.key - || vault_type != vault.vault_type - { - msg!("Error: Invalid vault metadata account"); - return Err(ProgramError::Custom(506)); - } - - Ok(()) -} - -pub fn check_unpack_target_vault<'a, 'b>( - fund_program_id: &Pubkey, - router_program_id: &Pubkey, - fund_metadata: &Pubkey, - underlying_pool_id: &Pubkey, - fund_vault_metadata: &'a AccountInfo<'b>, -) -> Result { - if fund_vault_metadata.owner != fund_program_id { - msg!("Error: Invalid Fund Vault metadata owner"); - return Err(ProgramError::IllegalOwner); - } - - let fund_vault = account::unpack::(fund_vault_metadata, "Fund Vault")?; - - if &fund_vault.fund_ref != fund_metadata { - msg!("Error: Specified Vault doesn't belong to this Fund"); - return Err(ProgramError::Custom(507)); - } - - if &fund_vault.router_program_id != router_program_id - || &fund_vault.underlying_pool_id != underlying_pool_id - { - msg!("Error: Invalid target Vault"); - return Err(ProgramError::Custom(508)); - } - - Ok(fund_vault) -} - -pub fn increase_vault_balance( - fund_vault_metadata: &AccountInfo, - vault: &FundVault, - lp_balance_increase: u64, -) -> ProgramResult { - if lp_balance_increase == 0 { - return Ok(()); - } - - let updated_lp_balance = math::checked_add(vault.lp_balance, lp_balance_increase)?; - let vault_new = FundVault { - lp_balance: updated_lp_balance, - balance_update_time: clock::get_time()?, - ..*vault - }; - vault_new.pack(*fund_vault_metadata.try_borrow_mut_data()?)?; - - Ok(()) -} - -pub fn decrease_vault_balance( - fund_vault_metadata: &AccountInfo, - vault: &FundVault, - lp_balance_decrease: u64, -) -> ProgramResult { - if lp_balance_decrease == 0 { - return Ok(()); - } - - let updated_lp_balance = math::checked_sub(vault.lp_balance, lp_balance_decrease)?; - let vault_new = FundVault { - lp_balance: updated_lp_balance, - balance_update_time: clock::get_time()?, - ..*vault - }; - vault_new.pack(*fund_vault_metadata.try_borrow_mut_data()?)?; - - Ok(()) -} - -pub fn check_user_requests_account<'a, 'b>( - fund: &Fund, - custody_token: &Token, - user_requests: &FundUserRequests, - user_account: &'a AccountInfo<'b>, - user_requests_account: &'a AccountInfo<'b>, -) -> ProgramResult { - let user_requests_derived = Pubkey::create_program_address( - &[ - b"user_requests_account", - custody_token.name.as_bytes(), - user_account.key.as_ref(), - fund.name.as_bytes(), - &[user_requests.bump], - ], - &fund.fund_program_id, - )?; - - if user_requests_account.key != &user_requests_derived { - msg!("Error: Invalid user requests address"); - Err(ProgramError::Custom(509)) - } else { - Ok(()) - } -} - -pub fn check_fund_token_mint(fund: &Fund, fund_token_mint: &AccountInfo) -> ProgramResult { - let fund_token_mint_derived = Pubkey::create_program_address( - &[ - b"fund_token_mint", - fund.name.as_bytes(), - &[fund.fund_token_bump], - ], - &fund.fund_program_id, - )?; - - if fund_token_mint.key != &fund_token_mint_derived { - msg!("Error: Invalid Fund token mint"); - Err(ProgramError::Custom(510)) - } else { - Ok(()) - } -} - -pub fn check_assets_update_time( - assets_update_time: UnixTimestamp, - max_update_age_sec: u64, -) -> ProgramResult { - let last_update_age_sec = math::checked_sub(clock::get_time()?, assets_update_time)?; - if last_update_age_sec > max_update_age_sec as i64 { - msg!("Error: Assets balance is stale. Contact Fund administrator."); - Err(ProgramError::Custom(222)) - } else { - Ok(()) - } -} - -pub fn check_assets_limit_usd( - fund_info: &FundInfo, - deposit_value_usd: f64, -) -> Result<(), ProgramError> { - let current_assets_usd = fund_info.get_current_assets_usd()?; - let assets_limit = fund_info.get_assets_limit_usd()?; - - if assets_limit > 0.0 && assets_limit < deposit_value_usd + current_assets_usd { - let amount_left = if current_assets_usd < assets_limit { - assets_limit - current_assets_usd - } else { - 0.0 - }; - msg!( - "Error: Fund assets limit reached ({}). Allowed max desposit USD: {}", - assets_limit, - amount_left - ); - return Err(ProgramError::Custom(223)); - } - - Ok(()) -} - -pub fn get_fund_token_to_mint_amount( - current_assets_usd: f64, - deposit_amount: u64, - deposit_value_usd: f64, - ft_supply_amount: u64, -) -> Result { - let ft_to_mint = if ft_supply_amount == 0 { - deposit_amount - } else if current_assets_usd <= 0.0001 { - msg!("Error: Assets balance is stale. Contact Fund administrator."); - return Err(ProgramError::Custom(222)); - } else { - math::checked_as_u64( - math::checked_mul( - math::checked_as_u128(deposit_value_usd / current_assets_usd * 1000000000.0)?, - ft_supply_amount as u128, - )? / 1000000000u128, - )? - }; - - Ok(ft_to_mint) -} - -pub fn get_fund_token_balance( - fund_token_account: &AccountInfo, - user_info: &UserInfo, -) -> Result { - math::checked_add( - account::get_token_balance(fund_token_account)?, - user_info.get_virtual_tokens_balance()?, - ) -} - -pub fn get_fund_token_supply( - fund_token_mint: &AccountInfo, - fund_info: &FundInfo, -) -> Result { - math::checked_add( - account::get_token_supply(fund_token_mint)?, - fund_info.get_virtual_tokens_supply()?, - ) -} diff --git a/farms/fund/src/entrypoint.rs b/farms/fund/src/entrypoint.rs deleted file mode 100644 index 8efe9f6a1c4..00000000000 --- a/farms/fund/src/entrypoint.rs +++ /dev/null @@ -1,622 +0,0 @@ -//! Fund entrypoint. - -#![cfg(not(feature = "no-entrypoint"))] - -solana_security_txt::security_txt! { - name: "Solana Farms", - project_url: "https://github.com/solana-labs/solana-program-library/tree/master/farms", - contacts: "email:solana.farms@protonmail.com", - policy: "", - preferred_languages: "en", - auditors: "Halborn" -} - -use { - crate::{ - fund_info::FundInfo, - instructions::{ - add_custody::add_custody, add_vault::add_vault, approve_deposit::approve_deposit, - approve_withdrawal::approve_withdrawal, cancel_deposit::cancel_deposit, - cancel_withdrawal::cancel_withdrawal, deny_deposit::deny_deposit, - deny_withdrawal::deny_withdrawal, disable_deposits::disable_deposits, - disable_withdrawals::disable_withdrawals, init::init, lock_assets::lock_assets, orca, - raydium, remove_custody::remove_custody, remove_multisig::remove_multisig, - remove_vault::remove_vault, request_deposit::request_deposit, - request_withdrawal::request_withdrawal, set_admin_signers::set_admin_signers, - set_assets_tracking_config::set_assets_tracking_config, - set_deposit_schedule::set_deposit_schedule, - set_withdrawal_schedule::set_withdrawal_schedule, start_liquidation::start_liquidation, - stop_liquidation::stop_liquidation, unlock_assets::unlock_assets, - update_assets_with_custody::update_assets_with_custody, - update_assets_with_vault::update_assets_with_vault, user_init::user_init, - withdraw_fees::withdraw_fees, - }, - }, - solana_farm_sdk::{ - error::FarmError, - fund::Fund, - id::{main_router, main_router_admin, main_router_multisig}, - instruction::{amm::AmmInstruction, fund::FundInstruction, vault::VaultInstruction}, - log::sol_log_params_short, - program::{account, multisig}, - refdb, - string::ArrayString64, - }, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint, - entrypoint::ProgramResult, - log::sol_log_compute_units, - msg, - program_error::ProgramError, - pubkey::Pubkey, - }, -}; - -fn log_start(instruction: &str, fund_name: &ArrayString64) { - msg!( - "Processing FundInstruction::{} for {}", - instruction, - fund_name.as_str() - ); - sol_log_compute_units(); -} - -fn log_end(fund_name: &ArrayString64) { - sol_log_compute_units(); - msg!("Fund {} end of instruction", fund_name.as_str()); -} - -fn check_admin_authority( - accounts: &[AccountInfo], - instruction_data: &[u8], - fund: &Fund, -) -> Result { - let account_info_iter = &mut accounts.iter(); - let admin_account = next_account_info(account_info_iter)?; - let _fund_metadata = next_account_info(account_info_iter)?; - let _fund_info_account = next_account_info(account_info_iter)?; - let multisig_account = next_account_info(account_info_iter)?; - - if multisig_account.key != &fund.multisig_account - && multisig_account.key != &main_router_multisig::id() - { - msg!("Error: Invalid multisig account"); - return Err(FarmError::IncorrectAccountAddress.into()); - } - - let signatures_left = multisig::sign_multisig( - multisig_account, - admin_account, - &main_router_admin::id(), - &accounts[1..], - instruction_data, - )?; - if signatures_left > 0 { - msg!( - "Instruction has been signed but more signatures are required: {}", - signatures_left - ); - return Ok(false); - } - - Ok(true) -} - -fn check_manager_authority(user_account: &AccountInfo, fund: &Fund) -> ProgramResult { - if user_account.key != &fund.fund_manager { - msg!( - "Error: Instruction must be performed by the fund manager {}", - fund.fund_manager - ); - Err(ProgramError::IllegalOwner) - } else if !user_account.is_signer { - Err(ProgramError::MissingRequiredSignature) - } else { - Ok(()) - } -} - -fn check_manager_authority_or_admin( - user_account: &AccountInfo, - multisig_account: &AccountInfo, - fund: &Fund, -) -> ProgramResult { - if user_account.key != &fund.fund_manager - && !multisig::is_signer(multisig_account, &main_router_admin::id(), user_account.key)? - { - msg!("Error: Instruction must be performed by the fund manager or one of admin signers",); - Err(ProgramError::IllegalOwner) - } else if !user_account.is_signer { - Err(ProgramError::MissingRequiredSignature) - } else { - Ok(()) - } -} - -fn check_manager_authority_or_liquidation( - user_account: &AccountInfo, - fund_info_account: &AccountInfo, - fund: &Fund, -) -> ProgramResult { - if FundInfo::new(fund_info_account).get_liquidation_start_time()? > 0 { - if !user_account.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } else { - return Ok(()); - } - } - check_manager_authority(user_account, fund) -} - -fn check_manager_authority_or_admin_or_liquidation( - user_account: &AccountInfo, - fund_info_account: &AccountInfo, - multisig_account: &AccountInfo, - fund: &Fund, -) -> ProgramResult { - if FundInfo::new(fund_info_account).get_liquidation_start_time()? > 0 { - if !user_account.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } else { - return Ok(()); - } - } - check_manager_authority_or_admin(user_account, multisig_account, fund) -} - -entrypoint!(process_instruction); -/// Program's entrypoint. -/// -/// # Arguments -/// * `program_id` - Public key of the fund. -/// * `accounts` - Accounts, see handlers in particular strategy for the list. -/// * `instructions_data` - Packed FundInstruction. -pub fn process_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - instruction_data: &[u8], -) -> ProgramResult { - msg!("Fund entrypoint"); - if cfg!(feature = "debug") { - sol_log_params_short(accounts, instruction_data); - } - - let account_info_iter = &mut accounts.iter(); - let user_account = next_account_info(account_info_iter)?; - let fund_metadata = next_account_info(account_info_iter)?; - let fund_info_account = next_account_info(account_info_iter)?; - - // unpack Fund's metadata and validate Fund accounts - let fund = account::unpack::(fund_metadata, "Fund")?; - let derived_fund_metadata = - refdb::find_target_pda_with_bump(refdb::StorageType::Fund, &fund.name, fund.metadata_bump)?; - if &fund.info_account != fund_info_account.key - || &derived_fund_metadata != fund_metadata.key - || fund_metadata.owner != &main_router::id() - { - msg!("Error: Invalid Fund accounts"); - return Err(ProgramError::Custom(511)); - } - if &fund.fund_program_id != program_id { - msg!("Error: Invalid Fund program id"); - return Err(ProgramError::IncorrectProgramId); - } - - // Read and unpack instruction data - let instruction = FundInstruction::unpack(instruction_data)?; - - match instruction { - FundInstruction::UserInit => { - log_start("UserInit", &fund.name); - user_init(&fund, accounts)?; - } - FundInstruction::RequestDeposit { amount } => { - log_start("RequestDeposit", &fund.name); - request_deposit(&fund, accounts, amount)?; - } - FundInstruction::CancelDeposit => { - log_start("CancelDeposit", &fund.name); - cancel_deposit(&fund, accounts)?; - } - FundInstruction::RequestWithdrawal { amount } => { - log_start("RequestWithdrawal", &fund.name); - request_withdrawal(&fund, accounts, amount)?; - } - FundInstruction::CancelWithdrawal => { - log_start("CancelWithdrawal", &fund.name); - cancel_withdrawal(&fund, accounts)?; - } - FundInstruction::Init { step } => { - log_start("Init", &fund.name); - if check_admin_authority(accounts, instruction_data, &fund)? { - init(&fund, accounts, step)?; - } - } - FundInstruction::SetDepositSchedule { schedule } => { - log_start("SetDepositSchedule", &fund.name); - check_manager_authority_or_admin( - user_account, - next_account_info(account_info_iter)?, - &fund, - )?; - set_deposit_schedule( - &fund, - &mut FundInfo::new(fund_info_account), - accounts, - &schedule, - )?; - } - FundInstruction::DisableDeposits => { - log_start("DisableDeposits", &fund.name); - check_manager_authority_or_admin( - user_account, - next_account_info(account_info_iter)?, - &fund, - )?; - disable_deposits(&fund, &mut FundInfo::new(fund_info_account), accounts)?; - } - FundInstruction::ApproveDeposit { amount } => { - log_start("ApproveDeposit", &fund.name); - check_manager_authority_or_admin( - user_account, - next_account_info(account_info_iter)?, - &fund, - )?; - approve_deposit(&fund, accounts, amount)?; - } - FundInstruction::DenyDeposit { deny_reason } => { - log_start("DenyDeposit", &fund.name); - check_manager_authority_or_admin( - user_account, - next_account_info(account_info_iter)?, - &fund, - )?; - deny_deposit(&fund, accounts, &deny_reason)?; - } - FundInstruction::SetWithdrawalSchedule { schedule } => { - log_start("SetWithdrawalSchedule", &fund.name); - check_manager_authority_or_admin( - user_account, - next_account_info(account_info_iter)?, - &fund, - )?; - set_withdrawal_schedule( - &fund, - &mut FundInfo::new(fund_info_account), - accounts, - &schedule, - )?; - } - FundInstruction::DisableWithdrawals => { - log_start("DisableWithdrawals", &fund.name); - check_manager_authority_or_admin( - user_account, - next_account_info(account_info_iter)?, - &fund, - )?; - disable_withdrawals(&fund, &mut FundInfo::new(fund_info_account), accounts)?; - } - FundInstruction::ApproveWithdrawal { amount } => { - log_start("ApproveWithdrawal", &fund.name); - check_manager_authority_or_admin( - user_account, - next_account_info(account_info_iter)?, - &fund, - )?; - approve_withdrawal(&fund, accounts, amount)?; - } - FundInstruction::DenyWithdrawal { deny_reason } => { - log_start("DenyWithdrawal", &fund.name); - check_manager_authority_or_admin( - user_account, - next_account_info(account_info_iter)?, - &fund, - )?; - deny_withdrawal(&fund, accounts, &deny_reason)?; - } - FundInstruction::LockAssets { amount } => { - log_start("LockAssets", &fund.name); - check_manager_authority_or_admin( - user_account, - next_account_info(account_info_iter)?, - &fund, - )?; - lock_assets(&fund, accounts, amount)?; - } - FundInstruction::UnlockAssets { amount } => { - log_start("UnlockAssets", &fund.name); - check_manager_authority_or_admin_or_liquidation( - user_account, - fund_info_account, - next_account_info(account_info_iter)?, - &fund, - )?; - unlock_assets(&fund, accounts, amount)?; - } - FundInstruction::SetAssetsTrackingConfig { config } => { - log_start("SetAssetsTrackingConfig", &fund.name); - if check_admin_authority(accounts, instruction_data, &fund)? { - set_assets_tracking_config( - &fund, - &mut FundInfo::new(fund_info_account), - accounts, - &config, - )?; - } - } - FundInstruction::UpdateAssetsWithVault => { - log_start("UpdateAssetsWithVault", &fund.name); - update_assets_with_vault(&fund, accounts)?; - } - FundInstruction::UpdateAssetsWithCustody => { - log_start("UpdateAssetsWithCustody", &fund.name); - update_assets_with_custody(&fund, accounts)?; - } - FundInstruction::AddVault { - target_hash, - vault_id, - vault_type, - } => { - log_start("AddVault", &fund.name); - if check_admin_authority(accounts, instruction_data, &fund)? { - add_vault(&fund, accounts, target_hash, vault_id, vault_type)?; - } - } - FundInstruction::RemoveVault { - target_hash, - vault_type, - } => { - log_start("RemoveVault", &fund.name); - if check_admin_authority(accounts, instruction_data, &fund)? { - remove_vault(&fund, accounts, target_hash, vault_type)?; - } - } - FundInstruction::AddCustody { - target_hash, - custody_id, - custody_type, - } => { - log_start("AddCustody", &fund.name); - if check_admin_authority(accounts, instruction_data, &fund)? { - add_custody(&fund, accounts, target_hash, custody_id, custody_type)?; - } - } - FundInstruction::RemoveCustody { - target_hash, - custody_type, - } => { - log_start("RemoveCustody", &fund.name); - if check_admin_authority(accounts, instruction_data, &fund)? { - remove_custody(&fund, accounts, target_hash, custody_type)?; - } - } - FundInstruction::StartLiquidation => { - log_start("StartLiquidation", &fund.name); - start_liquidation(&fund, accounts)?; - } - FundInstruction::StopLiquidation => { - log_start("StopLiquidation", &fund.name); - if check_admin_authority(accounts, instruction_data, &fund)? { - stop_liquidation(&fund, accounts)?; - } - } - FundInstruction::WithdrawFees { amount } => { - log_start("WithdrawFees", &fund.name); - if check_admin_authority(accounts, instruction_data, &fund)? { - withdraw_fees(&fund, accounts, amount)?; - } - } - FundInstruction::SetAdminSigners { min_signatures } => { - log_start("SetAdminSigners", &fund.name); - if check_admin_authority(accounts, instruction_data, &fund)? { - set_admin_signers(&fund, accounts, min_signatures)?; - } - } - FundInstruction::RemoveMultisig => { - log_start("RemoveMultisig", &fund.name); - if check_admin_authority(accounts, instruction_data, &fund)? { - remove_multisig(&fund, accounts)?; - } - } - FundInstruction::AmmInstructionRaydium { instruction } => match instruction { - AmmInstruction::UserInit => { - log_start("UserInitRaydium", &fund.name); - check_manager_authority(user_account, &fund)?; - raydium::user_init::user_init(&fund, accounts)?; - } - AmmInstruction::AddLiquidity { - max_token_a_amount, - max_token_b_amount, - } => { - log_start("AddLiquidityRaydium", &fund.name); - check_manager_authority(user_account, &fund)?; - raydium::add_liquidity::add_liquidity( - &fund, - accounts, - max_token_a_amount, - max_token_b_amount, - )?; - } - AmmInstruction::RemoveLiquidity { amount } => { - log_start("RemoveLiquidityRaydium", &fund.name); - check_manager_authority_or_liquidation(user_account, fund_info_account, &fund)?; - raydium::remove_liquidity::remove_liquidity(&fund, accounts, amount)?; - } - AmmInstruction::Swap { - token_a_amount_in, - token_b_amount_in, - min_token_amount_out, - } => { - log_start("SwapRaydium", &fund.name); - check_manager_authority_or_liquidation(user_account, fund_info_account, &fund)?; - raydium::swap::swap( - &fund, - accounts, - token_a_amount_in, - token_b_amount_in, - min_token_amount_out, - )?; - } - AmmInstruction::Stake { amount } => { - log_start("StakeRaydium", &fund.name); - check_manager_authority(user_account, &fund)?; - raydium::stake::stake(&fund, accounts, amount, false)?; - } - AmmInstruction::Unstake { amount } => { - log_start("UnstakeRaydium", &fund.name); - check_manager_authority_or_liquidation(user_account, fund_info_account, &fund)?; - raydium::unstake::unstake(&fund, accounts, amount)?; - } - AmmInstruction::Harvest => { - log_start("HarvestRaydium", &fund.name); - check_manager_authority_or_liquidation(user_account, fund_info_account, &fund)?; - raydium::stake::stake(&fund, accounts, 0, true)?; - } - _ => { - msg!("Error: Unimplemented"); - return Err(ProgramError::Custom(512)); - } - }, - FundInstruction::VaultInstructionRaydium { instruction } => match instruction { - VaultInstruction::AddLiquidity { - max_token_a_amount, - max_token_b_amount, - } => { - log_start("VaultAddLiquidityRaydium", &fund.name); - check_manager_authority(user_account, &fund)?; - raydium::vault_add_liquidity::add_liquidity( - &fund, - accounts, - max_token_a_amount, - max_token_b_amount, - )?; - } - VaultInstruction::LockLiquidity { amount } => { - log_start("VaultLockLiquidityRaydium", &fund.name); - check_manager_authority(user_account, &fund)?; - raydium::vault_lock_liquidity::lock_liquidity(&fund, accounts, amount)?; - } - VaultInstruction::UnlockLiquidity { amount } => { - log_start("VaultUnlockLiquidityRaydium", &fund.name); - check_manager_authority_or_liquidation(user_account, fund_info_account, &fund)?; - raydium::vault_unlock_liquidity::unlock_liquidity(&fund, accounts, amount)?; - } - VaultInstruction::RemoveLiquidity { amount } => { - log_start("VaultRemoveLiquidityRaydium", &fund.name); - check_manager_authority_or_liquidation(user_account, fund_info_account, &fund)?; - raydium::vault_remove_liquidity::remove_liquidity(&fund, accounts, amount)?; - } - VaultInstruction::UserInit {} => { - log_start("VaultUserInitRaydium", &fund.name); - check_manager_authority(user_account, &fund)?; - raydium::vault_user_init::user_init(&fund, accounts)?; - } - _ => { - msg!("Error: Unimplemented"); - return Err(ProgramError::Custom(513)); - } - }, - FundInstruction::AmmInstructionOrca { instruction } => match instruction { - AmmInstruction::UserInit => { - log_start("UserInitOrca", &fund.name); - check_manager_authority(user_account, &fund)?; - orca::user_init::user_init(&fund, accounts)?; - } - AmmInstruction::AddLiquidity { - max_token_a_amount, - max_token_b_amount, - } => { - log_start("AddLiquidityOrca", &fund.name); - check_manager_authority(user_account, &fund)?; - orca::add_liquidity::add_liquidity( - &fund, - accounts, - max_token_a_amount, - max_token_b_amount, - )?; - } - AmmInstruction::RemoveLiquidity { amount } => { - log_start("RemoveLiquidityOrca", &fund.name); - check_manager_authority_or_liquidation(user_account, fund_info_account, &fund)?; - orca::remove_liquidity::remove_liquidity(&fund, accounts, amount)?; - } - AmmInstruction::Swap { - token_a_amount_in, - token_b_amount_in, - min_token_amount_out, - } => { - log_start("SwapOrca", &fund.name); - check_manager_authority_or_liquidation(user_account, fund_info_account, &fund)?; - orca::swap::swap( - &fund, - accounts, - token_a_amount_in, - token_b_amount_in, - min_token_amount_out, - )?; - } - AmmInstruction::Stake { amount } => { - log_start("StakeOrca", &fund.name); - check_manager_authority(user_account, &fund)?; - orca::stake::stake(&fund, accounts, amount)?; - } - AmmInstruction::Unstake { amount } => { - log_start("UnstakeOrca", &fund.name); - check_manager_authority_or_liquidation(user_account, fund_info_account, &fund)?; - orca::unstake::unstake(&fund, accounts, amount)?; - } - AmmInstruction::Harvest => { - log_start("HarvestOrca", &fund.name); - check_manager_authority_or_liquidation(user_account, fund_info_account, &fund)?; - orca::harvest::harvest(&fund, accounts)?; - } - _ => { - msg!("Error: Unimplemented"); - return Err(ProgramError::Custom(512)); - } - }, - FundInstruction::VaultInstructionOrca { instruction } => match instruction { - VaultInstruction::AddLiquidity { - max_token_a_amount, - max_token_b_amount, - } => { - log_start("VaultAddLiquidityOrca", &fund.name); - check_manager_authority(user_account, &fund)?; - orca::vault_add_liquidity::add_liquidity( - &fund, - accounts, - max_token_a_amount, - max_token_b_amount, - )?; - } - VaultInstruction::LockLiquidity { amount } => { - log_start("VaultLockLiquidityOrca", &fund.name); - check_manager_authority(user_account, &fund)?; - orca::vault_lock_liquidity::lock_liquidity(&fund, accounts, amount)?; - } - VaultInstruction::UnlockLiquidity { amount } => { - log_start("VaultUnlockLiquidityOrca", &fund.name); - check_manager_authority_or_liquidation(user_account, fund_info_account, &fund)?; - orca::vault_unlock_liquidity::unlock_liquidity(&fund, accounts, amount)?; - } - VaultInstruction::RemoveLiquidity { amount } => { - log_start("VaultRemoveLiquidityOrca", &fund.name); - check_manager_authority_or_liquidation(user_account, fund_info_account, &fund)?; - orca::vault_remove_liquidity::remove_liquidity(&fund, accounts, amount)?; - } - VaultInstruction::UserInit {} => { - log_start("VaultUserInitOrca", &fund.name); - check_manager_authority(user_account, &fund)?; - orca::vault_user_init::user_init(&fund, accounts)?; - } - _ => { - msg!("Error: Unimplemented"); - return Err(ProgramError::Custom(513)); - } - }, - } - - log_end(&fund.name); - Ok(()) -} diff --git a/farms/fund/src/fund_info.rs b/farms/fund/src/fund_info.rs deleted file mode 100644 index 293e4e2980e..00000000000 --- a/farms/fund/src/fund_info.rs +++ /dev/null @@ -1,885 +0,0 @@ -//! Fund info account management. - -use { - solana_farm_sdk::{ - error::FarmError, - program::clock, - refdb, - refdb::{RefDB, Reference, ReferenceType, StorageType}, - string::{str_to_as64, ArrayString64}, - }, - solana_program::{ - account_info::AccountInfo, clock::UnixTimestamp, entrypoint::ProgramResult, - program_error::ProgramError, pubkey::Pubkey, - }, - std::cell::RefMut, -}; - -pub struct FundInfo<'a, 'b> { - pub key: &'a Pubkey, - pub data: RefMut<'a, &'b mut [u8]>, -} - -impl<'a, 'b> FundInfo<'a, 'b> { - pub const LEN: usize = StorageType::get_storage_size_for_records(ReferenceType::U64, 27); - pub const DEPOSIT_START_TIME_INDEX: usize = 0; - pub const DEPOSIT_END_TIME_INDEX: usize = 1; - pub const DEPOSIT_APPROVAL_REQUIRED_INDEX: usize = 2; - pub const DEPOSIT_MIN_AMOUNT_USD_INDEX: usize = 3; - pub const DEPOSIT_MAX_AMOUNT_USD_INDEX: usize = 4; - pub const DEPOSIT_FEE_INDEX: usize = 5; - pub const WITHDRAWAL_START_TIME_INDEX: usize = 6; - pub const WITHDRAWAL_END_TIME_INDEX: usize = 7; - pub const WITHDRAWAL_APPROVAL_REQUIRED_INDEX: usize = 8; - pub const WITHDRAWAL_MIN_AMOUNT_USD_INDEX: usize = 9; - pub const WITHDRAWAL_MAX_AMOUNT_USD_INDEX: usize = 10; - pub const WITHDRAWAL_FEE_INDEX: usize = 11; - pub const ASSETS_LIMIT_USD_INDEX: usize = 12; - pub const ASSETS_MAX_UPDATE_AGE_SEC_INDEX: usize = 13; - pub const ASSETS_MAX_PRICE_ERROR_INDEX: usize = 14; - pub const ASSETS_MAX_PRICE_AGE_SEC_INDEX: usize = 15; - pub const ISSUE_VIRTUAL_TOKENS_INDEX: usize = 16; - pub const VIRTUAL_TOKENS_SUPPLY_INDEX: usize = 17; - pub const AMOUNT_INVESTED_USD_INDEX: usize = 18; - pub const AMOUNT_REMOVED_USD_INDEX: usize = 19; - pub const CURRENT_ASSETS_USD_INDEX: usize = 20; - pub const ASSETS_UPDATE_TIME_INDEX: usize = 21; - pub const ADMIN_ACTION_TIME_INDEX: usize = 22; - pub const LAST_TRADE_TIME_INDEX: usize = 23; - pub const LIQUIDATION_START_TIME_INDEX: usize = 24; - pub const LIQUIDATION_AMOUNT_USD_INDEX: usize = 25; - pub const LIQUIDATION_AMOUNT_TOKENS_INDEX: usize = 26; - - pub fn new(account: &'a AccountInfo<'b>) -> Self { - Self { - key: account.key, - data: account.data.borrow_mut(), - } - } - - pub fn init(&mut self, refdb_name: &ArrayString64) -> ProgramResult { - if RefDB::is_initialized(&self.data) { - return Ok(()); - } - RefDB::init(&mut self.data, refdb_name, ReferenceType::U64)?; - - self.init_refdb_field( - FundInfo::DEPOSIT_START_TIME_INDEX, - "DepositStartTime", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - FundInfo::DEPOSIT_END_TIME_INDEX, - "DepositEndTime", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - FundInfo::DEPOSIT_APPROVAL_REQUIRED_INDEX, - "DepositApprovalRequired", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - FundInfo::DEPOSIT_MIN_AMOUNT_USD_INDEX, - "DepositMinAmountUsd", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - FundInfo::DEPOSIT_MAX_AMOUNT_USD_INDEX, - "DepositMaxAmountUsd", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - FundInfo::DEPOSIT_FEE_INDEX, - "DepositFee", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - FundInfo::WITHDRAWAL_START_TIME_INDEX, - "WithdrawalStartTime", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - FundInfo::WITHDRAWAL_END_TIME_INDEX, - "WithdrawalEndTime", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - FundInfo::WITHDRAWAL_APPROVAL_REQUIRED_INDEX, - "WithdrawalApprovalRequired", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - FundInfo::WITHDRAWAL_MIN_AMOUNT_USD_INDEX, - "WithdrawalMinAmountUsd", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - FundInfo::WITHDRAWAL_MAX_AMOUNT_USD_INDEX, - "WithdrawalMaxAmountUsd", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - FundInfo::WITHDRAWAL_FEE_INDEX, - "WithdrawalFee", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - FundInfo::ASSETS_LIMIT_USD_INDEX, - "AssetsLimitUsd", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - FundInfo::ASSETS_MAX_UPDATE_AGE_SEC_INDEX, - "AssetsMaxUpdateAgeSec", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - FundInfo::ASSETS_MAX_PRICE_ERROR_INDEX, - "AssetsMaxPriceError", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - FundInfo::ASSETS_MAX_PRICE_AGE_SEC_INDEX, - "AssetsMaxPriceAgeSec", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - FundInfo::ISSUE_VIRTUAL_TOKENS_INDEX, - "IssueVirtualTokens", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - FundInfo::VIRTUAL_TOKENS_SUPPLY_INDEX, - "VirtualTokensSupply", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - FundInfo::AMOUNT_INVESTED_USD_INDEX, - "AmountInvestedUsd", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - FundInfo::AMOUNT_REMOVED_USD_INDEX, - "AmountRemovedUsd", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - FundInfo::CURRENT_ASSETS_USD_INDEX, - "CurrentAssetsUsd", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - FundInfo::ASSETS_UPDATE_TIME_INDEX, - "AssetsUpdateTime", - Reference::U64 { - data: clock::get_time_as_u64()?, - }, - )?; - self.init_refdb_field( - FundInfo::ADMIN_ACTION_TIME_INDEX, - "AdminActionTime", - Reference::U64 { - data: clock::get_time_as_u64()?, - }, - )?; - self.init_refdb_field( - FundInfo::LAST_TRADE_TIME_INDEX, - "LastTradeTime", - Reference::U64 { - data: clock::get_time_as_u64()?, - }, - )?; - self.init_refdb_field( - FundInfo::LIQUIDATION_START_TIME_INDEX, - "LiquidationStartTime", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - FundInfo::LIQUIDATION_AMOUNT_USD_INDEX, - "LiquidationAmountUsd", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - FundInfo::LIQUIDATION_AMOUNT_TOKENS_INDEX, - "LiquidationAmountTokens", - Reference::U64 { data: 0 }, - ) - } - - pub fn set_deposit_start_time(&mut self, deposit_start_time: UnixTimestamp) -> ProgramResult { - if deposit_start_time < 0 { - return Err(FarmError::InvalidValue.into()); - } - RefDB::update_at( - &mut self.data, - FundInfo::DEPOSIT_START_TIME_INDEX, - &Reference::U64 { - data: deposit_start_time as u64, - }, - ) - .map(|_| ()) - } - - pub fn set_deposit_end_time(&mut self, deposit_end_time: UnixTimestamp) -> ProgramResult { - if deposit_end_time < 0 { - return Err(FarmError::InvalidValue.into()); - } - RefDB::update_at( - &mut self.data, - FundInfo::DEPOSIT_END_TIME_INDEX, - &Reference::U64 { - data: deposit_end_time as u64, - }, - ) - .map(|_| ()) - } - - pub fn set_deposit_approval_required( - &mut self, - deposit_approval_required: bool, - ) -> ProgramResult { - RefDB::update_at( - &mut self.data, - FundInfo::DEPOSIT_APPROVAL_REQUIRED_INDEX, - &Reference::U64 { - data: deposit_approval_required as u64, - }, - ) - .map(|_| ()) - } - - pub fn set_deposit_min_amount_usd(&mut self, deposit_min_amount_usd: f64) -> ProgramResult { - if deposit_min_amount_usd < 0.0 { - return Err(FarmError::InvalidValue.into()); - } - RefDB::update_at( - &mut self.data, - FundInfo::DEPOSIT_MIN_AMOUNT_USD_INDEX, - &Reference::U64 { - data: deposit_min_amount_usd.to_bits(), - }, - ) - .map(|_| ()) - } - - pub fn set_deposit_max_amount_usd(&mut self, deposit_max_amount_usd: f64) -> ProgramResult { - if deposit_max_amount_usd < 0.0 { - return Err(FarmError::InvalidValue.into()); - } - RefDB::update_at( - &mut self.data, - FundInfo::DEPOSIT_MAX_AMOUNT_USD_INDEX, - &Reference::U64 { - data: deposit_max_amount_usd.to_bits(), - }, - ) - .map(|_| ()) - } - - pub fn set_deposit_fee(&mut self, deposit_fee: f64) -> ProgramResult { - if !(0.0..=1.0).contains(&deposit_fee) { - return Err(FarmError::InvalidValue.into()); - } - RefDB::update_at( - &mut self.data, - FundInfo::DEPOSIT_FEE_INDEX, - &Reference::U64 { - data: deposit_fee.to_bits(), - }, - ) - .map(|_| ()) - } - - pub fn set_withdrawal_start_time( - &mut self, - withdrawal_start_time: UnixTimestamp, - ) -> ProgramResult { - if withdrawal_start_time < 0 { - return Err(FarmError::InvalidValue.into()); - } - RefDB::update_at( - &mut self.data, - FundInfo::WITHDRAWAL_START_TIME_INDEX, - &Reference::U64 { - data: withdrawal_start_time as u64, - }, - ) - .map(|_| ()) - } - - pub fn set_withdrawal_end_time(&mut self, withdrawal_end_time: UnixTimestamp) -> ProgramResult { - if withdrawal_end_time < 0 { - return Err(FarmError::InvalidValue.into()); - } - RefDB::update_at( - &mut self.data, - FundInfo::WITHDRAWAL_END_TIME_INDEX, - &Reference::U64 { - data: withdrawal_end_time as u64, - }, - ) - .map(|_| ()) - } - - pub fn set_withdrawal_approval_required( - &mut self, - withdrawal_approval_required: bool, - ) -> ProgramResult { - RefDB::update_at( - &mut self.data, - FundInfo::WITHDRAWAL_APPROVAL_REQUIRED_INDEX, - &Reference::U64 { - data: withdrawal_approval_required as u64, - }, - ) - .map(|_| ()) - } - - pub fn set_withdrawal_min_amount_usd( - &mut self, - withdrawal_min_amount_usd: f64, - ) -> ProgramResult { - if withdrawal_min_amount_usd < 0.0 { - return Err(FarmError::InvalidValue.into()); - } - RefDB::update_at( - &mut self.data, - FundInfo::WITHDRAWAL_MIN_AMOUNT_USD_INDEX, - &Reference::U64 { - data: withdrawal_min_amount_usd.to_bits(), - }, - ) - .map(|_| ()) - } - - pub fn set_withdrawal_max_amount_usd( - &mut self, - withdrawal_max_amount_usd: f64, - ) -> ProgramResult { - if withdrawal_max_amount_usd < 0.0 { - return Err(FarmError::InvalidValue.into()); - } - RefDB::update_at( - &mut self.data, - FundInfo::WITHDRAWAL_MAX_AMOUNT_USD_INDEX, - &Reference::U64 { - data: withdrawal_max_amount_usd.to_bits(), - }, - ) - .map(|_| ()) - } - - pub fn set_withdrawal_fee(&mut self, withdrawal_fee: f64) -> ProgramResult { - if !(0.0..=1.0).contains(&withdrawal_fee) { - return Err(FarmError::InvalidValue.into()); - } - RefDB::update_at( - &mut self.data, - FundInfo::WITHDRAWAL_FEE_INDEX, - &Reference::U64 { - data: withdrawal_fee.to_bits(), - }, - ) - .map(|_| ()) - } - - pub fn set_assets_limit_usd(&mut self, assets_limit_usd: f64) -> ProgramResult { - if assets_limit_usd < 0.0 { - return Err(FarmError::InvalidValue.into()); - } - RefDB::update_at( - &mut self.data, - FundInfo::ASSETS_LIMIT_USD_INDEX, - &Reference::U64 { - data: assets_limit_usd.to_bits(), - }, - ) - .map(|_| ()) - } - - pub fn set_assets_max_update_age_sec( - &mut self, - assets_max_update_age_sec: u64, - ) -> ProgramResult { - RefDB::update_at( - &mut self.data, - FundInfo::ASSETS_MAX_UPDATE_AGE_SEC_INDEX, - &Reference::U64 { - data: assets_max_update_age_sec, - }, - ) - .map(|_| ()) - } - - pub fn set_assets_max_price_error(&mut self, assets_max_price_error: f64) -> ProgramResult { - if assets_max_price_error < 0.0 { - return Err(FarmError::InvalidValue.into()); - } - RefDB::update_at( - &mut self.data, - FundInfo::ASSETS_MAX_PRICE_ERROR_INDEX, - &Reference::U64 { - data: assets_max_price_error.to_bits(), - }, - ) - .map(|_| ()) - } - - pub fn set_assets_max_price_age_sec(&mut self, assets_max_price_age_sec: u64) -> ProgramResult { - RefDB::update_at( - &mut self.data, - FundInfo::ASSETS_MAX_PRICE_AGE_SEC_INDEX, - &Reference::U64 { - data: assets_max_price_age_sec, - }, - ) - .map(|_| ()) - } - - pub fn set_issue_virtual_tokens(&mut self, issue_virtual_tokens: bool) -> ProgramResult { - RefDB::update_at( - &mut self.data, - FundInfo::ISSUE_VIRTUAL_TOKENS_INDEX, - &Reference::U64 { - data: if issue_virtual_tokens { 1 } else { 0 }, - }, - ) - .map(|_| ()) - } - - pub fn set_virtual_tokens_supply(&mut self, virtual_tokens_supply: u64) -> ProgramResult { - RefDB::update_at( - &mut self.data, - FundInfo::VIRTUAL_TOKENS_SUPPLY_INDEX, - &Reference::U64 { - data: virtual_tokens_supply, - }, - ) - .map(|_| ()) - } - - pub fn set_amount_invested_usd(&mut self, amount_invested_usd: f64) -> ProgramResult { - if amount_invested_usd < 0.0 { - return Err(FarmError::InvalidValue.into()); - } - RefDB::update_at( - &mut self.data, - FundInfo::AMOUNT_INVESTED_USD_INDEX, - &Reference::U64 { - data: amount_invested_usd.to_bits(), - }, - ) - .map(|_| ()) - } - - pub fn set_amount_removed_usd(&mut self, amount_removed_usd: f64) -> ProgramResult { - if amount_removed_usd < 0.0 { - return Err(FarmError::InvalidValue.into()); - } - RefDB::update_at( - &mut self.data, - FundInfo::AMOUNT_REMOVED_USD_INDEX, - &Reference::U64 { - data: amount_removed_usd.to_bits(), - }, - ) - .map(|_| ()) - } - - pub fn set_current_assets_usd(&mut self, current_assets_usd: f64) -> ProgramResult { - if current_assets_usd < 0.0 { - return Err(FarmError::InvalidValue.into()); - } - RefDB::update_at( - &mut self.data, - FundInfo::CURRENT_ASSETS_USD_INDEX, - &Reference::U64 { - data: current_assets_usd.to_bits(), - }, - ) - .map(|_| ()) - } - - pub fn set_assets_update_time(&mut self, assets_update_time: UnixTimestamp) -> ProgramResult { - if assets_update_time < 0 { - return Err(FarmError::InvalidValue.into()); - } - RefDB::update_at( - &mut self.data, - FundInfo::ASSETS_UPDATE_TIME_INDEX, - &Reference::U64 { - data: assets_update_time as u64, - }, - ) - .map(|_| ()) - } - - pub fn set_admin_action_time(&mut self, admin_action_time: UnixTimestamp) -> ProgramResult { - if admin_action_time < 0 { - return Err(FarmError::InvalidValue.into()); - } - RefDB::update_at( - &mut self.data, - FundInfo::ADMIN_ACTION_TIME_INDEX, - &Reference::U64 { - data: admin_action_time as u64, - }, - ) - .map(|_| ()) - } - - pub fn update_admin_action_time(&mut self) -> ProgramResult { - self.set_admin_action_time(clock::get_time()?) - } - - pub fn set_last_trade_time(&mut self, last_trade_time: UnixTimestamp) -> ProgramResult { - if last_trade_time < 0 { - return Err(FarmError::InvalidValue.into()); - } - RefDB::update_at( - &mut self.data, - FundInfo::LAST_TRADE_TIME_INDEX, - &Reference::U64 { - data: last_trade_time as u64, - }, - ) - .map(|_| ()) - } - - pub fn update_last_trade_time(&mut self) -> ProgramResult { - self.set_last_trade_time(clock::get_time()?) - } - - pub fn set_liquidation_start_time( - &mut self, - liquidation_start_time: UnixTimestamp, - ) -> ProgramResult { - if liquidation_start_time < 0 { - return Err(FarmError::InvalidValue.into()); - } - RefDB::update_at( - &mut self.data, - FundInfo::LIQUIDATION_START_TIME_INDEX, - &Reference::U64 { - data: liquidation_start_time as u64, - }, - ) - .map(|_| ()) - } - - pub fn set_liquidation_amount_usd(&mut self, liquidation_amount_usd: f64) -> ProgramResult { - if liquidation_amount_usd < 0.0 { - return Err(FarmError::InvalidValue.into()); - } - RefDB::update_at( - &mut self.data, - FundInfo::LIQUIDATION_AMOUNT_USD_INDEX, - &Reference::U64 { - data: liquidation_amount_usd.to_bits(), - }, - ) - .map(|_| ()) - } - - pub fn set_liquidation_amount_tokens( - &mut self, - liquidation_amount_tokens: u64, - ) -> ProgramResult { - RefDB::update_at( - &mut self.data, - FundInfo::LIQUIDATION_AMOUNT_TOKENS_INDEX, - &Reference::U64 { - data: liquidation_amount_tokens, - }, - ) - .map(|_| ()) - } - - pub fn is_deposit_allowed(&self) -> Result { - if self.get_liquidation_start_time()? > 0 { - return Ok(false); - } - let deposit_start_time = - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::DEPOSIT_START_TIME_INDEX)? { - if let Reference::U64 { data } = rec.reference { - data as UnixTimestamp - } else { - return Err(FarmError::InvalidRefdbRecord.into()); - } - } else { - return Err(FarmError::InvalidRefdbRecord.into()); - }; - let deposit_end_time = - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::DEPOSIT_END_TIME_INDEX)? { - if let Reference::U64 { data } = rec.reference { - data as UnixTimestamp - } else { - return Err(FarmError::InvalidRefdbRecord.into()); - } - } else { - return Err(FarmError::InvalidRefdbRecord.into()); - }; - let current_time = clock::get_time()?; - Ok(current_time > 0 - && current_time >= deposit_start_time - && current_time < deposit_end_time) - } - - pub fn is_deposit_approval_required(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::DEPOSIT_APPROVAL_REQUIRED_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(data > 0); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - pub fn get_deposit_min_amount_usd(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::DEPOSIT_MIN_AMOUNT_USD_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(f64::from_bits(data)); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - pub fn get_deposit_max_amount_usd(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::DEPOSIT_MAX_AMOUNT_USD_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(f64::from_bits(data)); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - pub fn get_deposit_fee(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::DEPOSIT_FEE_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(f64::from_bits(data)); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - pub fn is_withdrawal_allowed(&self) -> Result { - if self.get_liquidation_start_time()? > 0 { - return Ok(false); - } - let withdrawal_start_time = - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::WITHDRAWAL_START_TIME_INDEX)? { - if let Reference::U64 { data } = rec.reference { - data as UnixTimestamp - } else { - return Err(FarmError::InvalidRefdbRecord.into()); - } - } else { - return Err(FarmError::InvalidRefdbRecord.into()); - }; - let withdrawal_end_time = - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::WITHDRAWAL_END_TIME_INDEX)? { - if let Reference::U64 { data } = rec.reference { - data as UnixTimestamp - } else { - return Err(FarmError::InvalidRefdbRecord.into()); - } - } else { - return Err(FarmError::InvalidRefdbRecord.into()); - }; - let current_time = clock::get_time()?; - Ok(current_time > 0 - && current_time >= withdrawal_start_time - && current_time < withdrawal_end_time) - } - - pub fn is_withdrawal_approval_required(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::WITHDRAWAL_APPROVAL_REQUIRED_INDEX)? - { - if let Reference::U64 { data } = rec.reference { - return Ok(data > 0); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - pub fn get_withdrawal_min_amount_usd(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::WITHDRAWAL_MIN_AMOUNT_USD_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(f64::from_bits(data)); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - pub fn get_withdrawal_max_amount_usd(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::WITHDRAWAL_MAX_AMOUNT_USD_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(f64::from_bits(data)); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - pub fn get_withdrawal_fee(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::WITHDRAWAL_FEE_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(f64::from_bits(data)); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - pub fn get_assets_limit_usd(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::ASSETS_LIMIT_USD_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(f64::from_bits(data)); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - pub fn get_assets_max_update_age_sec(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::ASSETS_MAX_UPDATE_AGE_SEC_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(data); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - pub fn get_assets_max_price_error(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::ASSETS_MAX_PRICE_ERROR_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(f64::from_bits(data)); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - pub fn get_assets_max_price_age_sec(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::ASSETS_MAX_PRICE_AGE_SEC_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(data); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - pub fn get_issue_virtual_tokens(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::ISSUE_VIRTUAL_TOKENS_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(data > 0); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - pub fn get_virtual_tokens_supply(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::VIRTUAL_TOKENS_SUPPLY_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(data); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - pub fn get_amount_invested_usd(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::AMOUNT_INVESTED_USD_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(f64::from_bits(data)); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - pub fn get_amount_removed_usd(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::AMOUNT_REMOVED_USD_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(f64::from_bits(data)); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - pub fn get_current_assets_usd(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::CURRENT_ASSETS_USD_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(f64::from_bits(data)); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - pub fn get_assets_update_time(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::ASSETS_UPDATE_TIME_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(data as UnixTimestamp); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - pub fn get_admin_action_time(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::ADMIN_ACTION_TIME_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(data as UnixTimestamp); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - pub fn get_last_trade_time(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::LAST_TRADE_TIME_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(data as UnixTimestamp); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - pub fn get_liquidation_start_time(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::LIQUIDATION_START_TIME_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(data as UnixTimestamp); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - pub fn get_liquidation_amount_usd(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::LIQUIDATION_AMOUNT_USD_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(f64::from_bits(data)); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - pub fn get_liquidation_amount_tokens(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, FundInfo::LIQUIDATION_AMOUNT_TOKENS_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(data); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - // private helpers - fn init_refdb_field( - &mut self, - index: usize, - field_name: &str, - reference: Reference, - ) -> ProgramResult { - RefDB::write( - &mut self.data, - &refdb::Record { - index: Some(index as u32), - counter: 0, - tag: 0, - name: str_to_as64(field_name)?, - reference, - }, - ) - .map(|_| ()) - } -} diff --git a/farms/fund/src/instructions/add_custody.rs b/farms/fund/src/instructions/add_custody.rs deleted file mode 100644 index 1eb5ccafca7..00000000000 --- a/farms/fund/src/instructions/add_custody.rs +++ /dev/null @@ -1,188 +0,0 @@ -//! Fund AddCustody instruction handler - -use { - crate::{common, fund_info::FundInfo}, - solana_farm_sdk::{ - fund::{Fund, FundAssetType, FundCustody, FundCustodyType, DISCRIMINATOR_FUND_CUSTODY}, - id::{main_router, zero}, - program::{account, pda}, - token::{OracleType, Token}, - traits::Packed, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn add_custody( - fund: &Fund, - accounts: &[AccountInfo], - target_hash: u64, - custody_id: u32, - custody_type: FundCustodyType, -) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - admin_account, - fund_metadata, - fund_info_account, - _active_multisig_account, - fund_multisig_account, - fund_authority, - _system_program, - _spl_token_program, - _associated_token_program, - rent_program, - custodies_assets_info, - custody_account, - custody_fees_account, - custody_metadata, - custody_token_metadata, - custody_token_mint - ] = accounts - { - // validate accounts - msg!("Validate state and accounts"); - let mut fund_info = FundInfo::new(fund_info_account); - if fund_info.get_liquidation_start_time()? > 0 { - msg!("Error: Fund is in liquidation state"); - return Err(ProgramError::Custom(516)); - } - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - if custody_token_metadata.owner != &main_router::id() { - msg!("Error: Invalid custody token metadata owner"); - return Err(ProgramError::IllegalOwner); - } - - if account::exists(custody_metadata)? || account::exists(custody_account)? || - account::exists(custody_fees_account)? { - msg!("Error: Custody already initialized"); - return Err(ProgramError::AccountAlreadyInitialized); - } - - // init custody metadata account - msg!("Init custody metadata account"); - let custody_token = account::unpack::(custody_token_metadata, "custody token")?; - if &custody_token.mint != custody_token_mint.key { - msg!("Error: Custody token mint mismatch"); - return Err(ProgramError::Custom(502)); - } - let is_vault_token = - custody_token.name.len() > 3 && ["LP.", "VT."].contains(&&custody_token.name[..3]); - if !is_vault_token && custody_token.oracle_type == OracleType::Unsupported { - msg!( - "Error: Oracle is not supported for token {}", - custody_token.name - ); - return Err(ProgramError::InvalidAccountData); - } - let custody_seed_str: &[u8] = match custody_type { - FundCustodyType::DepositWithdraw => b"fund_wd_custody_info", - FundCustodyType::Trading => b"fund_td_custody_info", - }; - let custody_seeds = &[ - custody_seed_str, - custody_token.name.as_bytes(), - fund.name.as_bytes(), - ]; - let bump = pda::init_system_account( - admin_account, - custody_metadata, - &fund.fund_program_id, - &fund.fund_program_id, - custody_seeds, - FundCustody::LEN, - )?; - - let custody = FundCustody { - discriminator: DISCRIMINATOR_FUND_CUSTODY, - fund_ref: *fund_metadata.key, - custody_id, - custody_type, - is_vault_token, - token_ref: *custody_token_metadata.key, - address: *custody_account.key, - fees_address: if is_vault_token { - zero::id() - } else { - *custody_fees_account.key - }, - bump, - }; - custody.pack(*custody_metadata.try_borrow_mut_data()?)?; - - // init token accounts - msg!("Init custody token account"); - if matches!(custody_type, FundCustodyType::DepositWithdraw) { - pda::init_token_account( - admin_account, - custody_account, - custody_token_mint, - fund_authority, - rent_program, - &fund.fund_program_id, - &[ - b"fund_wd_custody_account", - custody_token.name.as_bytes(), - fund.name.as_bytes(), - ], - )?; - } else { - pda::init_associated_token_account( - admin_account, - fund_authority, - custody_account, - custody_token_mint, - rent_program, - )?; - } - - // if custody is not for a vault token then it needs a second token account - // where fees will be collected. Also, since each non-vault custody must - // be counted in update_assets_with_custody() we reset fund_assets stats. - if !is_vault_token { - msg!("Init fee custody token account"); - let custody_seed_str: &[u8] = match custody_type { - FundCustodyType::DepositWithdraw => b"fund_wd_custody_fees_account", - FundCustodyType::Trading => b"fund_td_custody_fees_account", - }; - pda::init_token_account( - admin_account, - custody_fees_account, - custody_token_mint, - fund_multisig_account, - rent_program, - &fund.fund_program_id, - &[ - custody_seed_str, - custody_token.name.as_bytes(), - fund.name.as_bytes(), - ], - )?; - - // update assets tracking account - msg!("Update Fund assets account"); - let mut fund_assets = common::check_and_get_fund_assets_account( - fund, - custodies_assets_info, - FundAssetType::Custody, - )?; - fund_assets.current_hash = 0; - fund_assets.target_hash = target_hash; - fund_assets.current_assets_usd = 0.0; - fund_assets.cycle_start_time = 0; - fund_assets.cycle_end_time = 0; - fund_assets.pack(*custodies_assets_info.try_borrow_mut_data()?)?; - } - - // update fund stats - msg!("Update Fund stats"); - fund_info.update_admin_action_time() - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/add_vault.rs b/farms/fund/src/instructions/add_vault.rs deleted file mode 100644 index 2d01564613b..00000000000 --- a/farms/fund/src/instructions/add_vault.rs +++ /dev/null @@ -1,202 +0,0 @@ -//! Fund AddVault instruction handler - -use { - crate::{common, fund_info::FundInfo}, - solana_farm_sdk::{ - farm::{Farm, FarmRoute}, - fund::{Fund, FundAssetType, FundVault, FundVaultType, DISCRIMINATOR_FUND_VAULT}, - id::main_router, - pool::{Pool, PoolRoute}, - program::{account, pda}, - token::Token, - traits::Packed, - vault::{Vault, VaultStrategy}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn add_vault( - fund: &Fund, - accounts: &[AccountInfo], - target_hash: u64, - vault_id: u32, - vault_type: FundVaultType, -) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - admin_account, - fund_metadata, - fund_info_account, - _multisig_account, - fund_authority, - _system_program, - vaults_assets_info, - fund_vault_metadata, - target_vault_metadata, - router_program_id, - underlying_pool_id, - underlying_pool_ref, - underlying_lp_token_metadata - ] = accounts - { - // validate accounts - msg!("Validate state and accounts"); - let mut fund_info = FundInfo::new(fund_info_account); - if fund_info.get_liquidation_start_time()? > 0 { - msg!("Error: Fund is in liquidation state"); - return Err(ProgramError::Custom(516)); - } - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - if underlying_pool_ref.owner != &main_router::id() { - msg!("Error: Invalid pool metadata owner"); - return Err(ProgramError::IllegalOwner); - } - if underlying_lp_token_metadata.owner != &main_router::id() { - msg!("Error: Invalid lp token metadata owner"); - return Err(ProgramError::IllegalOwner); - } - if target_vault_metadata.owner != &main_router::id() { - msg!("Error: Invalid target vault metadata owner"); - return Err(ProgramError::IllegalOwner); - } - - // target_vault_metadata represents different data structure depending on vault_type - let (vault_name, vault_router, pool_id) = match vault_type { - FundVaultType::Vault => { - let vault = account::unpack::(target_vault_metadata, "Vault")?; - if let VaultStrategy::StakeLpCompoundRewards { pool_ref, .. } = vault.strategy { - if &pool_ref != underlying_pool_ref.key { - msg!("Error: Underlying pool address mismatch"); - return Err(ProgramError::Custom(520)); - } - ( - vault.name, - vault.vault_program_id, - *target_vault_metadata.key, - ) - } else { - msg!("Error: Vault strategy unsupported"); - return Err(ProgramError::Custom(521)); - } - } - FundVaultType::Pool => { - let pool = account::unpack::(target_vault_metadata, "Pool")?; - let pool_ammid = match pool.route { - PoolRoute::Raydium { amm_id, .. } => amm_id, - PoolRoute::Orca { amm_id, .. } => amm_id, - _ => { - msg!("Error: Unsupported Pool route"); - return Err(ProgramError::Custom(522)); - } - }; - (pool.name, pool.router_program_id, pool_ammid) - } - FundVaultType::Farm => { - let farm = account::unpack::(target_vault_metadata, "Farm")?; - let farm_id = match farm.route { - FarmRoute::Raydium { farm_id, .. } => farm_id, - FarmRoute::Orca { farm_id, .. } => farm_id, - _ => { - msg!("Error: Unsupported Farm route"); - return Err(ProgramError::Custom(522)); - } - }; - (farm.name, farm.router_program_id, farm_id) - } - }; - - if &vault_router != router_program_id.key { - msg!("Error:Invalit router program id"); - return Err(ProgramError::IncorrectProgramId); - } - if &pool_id != underlying_pool_id.key { - msg!("Error: Invalid underlying pool id"); - return Err(ProgramError::Custom(523)); - } - - let underlying_pool = account::unpack::(underlying_pool_ref, "Underlying Pool")?; - let underlying_lp_token = - account::unpack::(underlying_lp_token_metadata, "Underlying LP Token")?; - if underlying_pool.lp_token_ref.is_none() - || underlying_lp_token_metadata.key != &underlying_pool.lp_token_ref.unwrap() - { - msg!("Error: Underlying LP token address mismatch"); - return Err(ProgramError::Custom(524)); - } - - if account::exists(fund_vault_metadata)? { - msg!("Error: Vault already initialized"); - return Err(ProgramError::AccountAlreadyInitialized); - } - - // init vault metadata account - msg!("Init vault metadata account"); - msg!( - "vault_name: {}, vault_id: {}, vault_type: {:?}", - vault_name, - vault_id, - vault_type - ); - - let vault_seed_str: &[u8] = match vault_type { - FundVaultType::Vault => b"fund_vault_info", - FundVaultType::Pool => b"fund_pool_info", - FundVaultType::Farm => b"fund_farm_info", - }; - let vault_seeds = &[vault_seed_str, vault_name.as_bytes(), fund.name.as_bytes()]; - let bump = pda::init_system_account( - admin_account, - fund_vault_metadata, - &fund.fund_program_id, - &fund.fund_program_id, - vault_seeds, - FundVault::LEN, - )?; - - let vault = FundVault { - discriminator: DISCRIMINATOR_FUND_VAULT, - fund_ref: *fund_metadata.key, - vault_id, - vault_type, - vault_ref: *target_vault_metadata.key, - router_program_id: *router_program_id.key, - underlying_pool_id: *underlying_pool_id.key, - underlying_pool_ref: *underlying_pool_ref.key, - underlying_lp_token_mint: underlying_lp_token.mint, - lp_balance: 0, - balance_update_time: 0, - bump, - }; - vault.pack(*fund_vault_metadata.try_borrow_mut_data()?)?; - - // since each non-farm vault must be counted in update_assets_with_vault() - // we reset fund_assets stats - if vault_type != FundVaultType::Farm { - // update assets tracking account - msg!("Update Fund assets account"); - let mut fund_assets = common::check_and_get_fund_assets_account( - fund, - vaults_assets_info, - FundAssetType::Vault, - )?; - fund_assets.current_hash = 0; - fund_assets.target_hash = target_hash; - fund_assets.current_assets_usd = 0.0; - fund_assets.cycle_start_time = 0; - fund_assets.cycle_end_time = 0; - fund_assets.pack(*vaults_assets_info.try_borrow_mut_data()?)?; - } - - // update fund stats - msg!("Update Fund stats"); - fund_info.update_admin_action_time() - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/approve_deposit.rs b/farms/fund/src/instructions/approve_deposit.rs deleted file mode 100644 index 86b1317dea5..00000000000 --- a/farms/fund/src/instructions/approve_deposit.rs +++ /dev/null @@ -1,221 +0,0 @@ -//! Approve deposit to the Fund instruction handler - -use { - crate::{common, fund_info::FundInfo, user_info::UserInfo}, - solana_farm_sdk::{ - fund::{Fund, FundUserRequests}, - math, - program::{account, pda}, - string::ArrayString64, - token::Token, - traits::Packed, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn approve_deposit(fund: &Fund, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - fund_metadata, - fund_info_account, - _multisig_account, - fund_authority, - _spl_token_program, - fund_token_mint, - user_account, - user_info_account, - user_requests_account, - user_deposit_token_account, - user_fund_token_account, - custody_account, - custody_fees_account, - custody_metadata, - custody_token_metadata, - oracle_account - ] = accounts - { - // validate params and accounts - msg!("Validate state and accounts"); - let mut fund_info = FundInfo::new(fund_info_account); - if fund_info.get_liquidation_start_time()? > 0 { - msg!("Error: Fund is in liquidation state"); - return Err(ProgramError::Custom(516)); - } - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - if !UserInfo::validate_account(fund, user_info_account, user_account.key) { - msg!("Error: Invalid user info account"); - return Err(ProgramError::Custom(140)); - } - if !account::check_token_account_owner(user_fund_token_account, user_account.key)? { - msg!("Error: Invalid Fund token account owner"); - return Err(ProgramError::IllegalOwner); - } - common::check_fund_token_mint(fund, fund_token_mint)?; - - let custody_token = account::unpack::(custody_token_metadata, "custody token")?; - common::check_wd_custody_accounts( - &fund.fund_program_id, - fund_metadata.key, - &custody_token, - custody_token_metadata, - user_deposit_token_account, - custody_account, - custody_fees_account, - custody_metadata, - oracle_account, - )?; - - let mut user_requests = account::unpack::(user_requests_account, "user requests")?; - common::check_user_requests_account( - fund, - &custody_token, - &user_requests, - user_account, - user_requests_account, - )?; - - // check if there are any pending requests - if user_requests.deposit_request.amount == 0 { - msg!("Error: No pending deposits found"); - return Err(ProgramError::Custom(525)); - } - - // compute deposit amount and fees - msg!("Compute deposit amount and fees"); - let user_token_balance = account::get_token_balance(user_deposit_token_account)?; - let amount_with_fee = if amount == 0 { - user_requests.deposit_request.amount - } else { - std::cmp::min(amount, user_requests.deposit_request.amount) - }; - // 0 <= fund_fee <= 1 - let fund_fee = fund_info.get_deposit_fee()?; - let (fee_numerator, fee_denominator) = math::get_fee_parts(fund_fee); - let deposit_fee = math::checked_as_u64(math::checked_div( - math::checked_mul(amount_with_fee as u128, fee_numerator as u128)?, - fee_denominator as u128, - )?)?; - let deposit_amount = amount_with_fee.checked_sub(deposit_fee).unwrap(); - if deposit_amount == 0 || deposit_amount > user_token_balance { - msg!("Error: Insufficient user funds"); - return Err(ProgramError::InsufficientFunds); - } - - // compute nominal value of deposited tokens and check against the limit - msg!("Compute assets value. amount_with_fee: {}", amount_with_fee); - let deposit_value_usd = account::get_asset_value_usd( - deposit_amount, - custody_token.decimals, - custody_token.oracle_type, - oracle_account, - fund_info.get_assets_max_price_error()?, - fund_info.get_assets_max_price_age_sec()?, - )?; - - // no individual deposit limit check (discretion of the Fund manager) - - msg!( - "Deposit tokens into custody. deposit_amount: {}, deposit_value_usd: {}", - deposit_amount, - deposit_value_usd - ); - - // check for total asset amount limit - common::check_assets_limit_usd(&fund_info, deposit_value_usd)?; - - // check if last assets update was not too long ago, - // stale value may lead to incorrect amount of fund tokens minted - common::check_assets_update_time( - fund_info.get_assets_update_time()?, - fund_info.get_assets_max_update_age_sec()?, - )?; - - // transfer funds - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - pda::transfer_tokens_with_seeds( - user_deposit_token_account, - custody_account, - fund_authority, - seeds, - deposit_amount, - )?; - if deposit_fee > 0 { - pda::transfer_tokens_with_seeds( - user_deposit_token_account, - custody_fees_account, - fund_authority, - seeds, - deposit_fee, - )?; - } - - // mint Fund tokens to user - let current_assets_usd = fund_info.get_current_assets_usd()?; - let ft_supply_amount = common::get_fund_token_supply(fund_token_mint, &fund_info)?; - let ft_to_mint = common::get_fund_token_to_mint_amount( - current_assets_usd, - deposit_amount, - deposit_value_usd, - ft_supply_amount, - )?; - msg!( - "Mint Fund tokens to the user. ft_to_mint: {}, ft_supply_amount: {}, current_assets_usd: {}", - ft_to_mint, ft_supply_amount, - current_assets_usd - ); - if ft_to_mint == 0 { - msg!("Error: Deposit instruction didn't result in Fund tokens mint"); - return Err(ProgramError::Custom(170)); - } - - if fund_info.get_issue_virtual_tokens()? { - let mut user_info = UserInfo::new(user_info_account); - user_info.set_virtual_tokens_balance(math::checked_add( - user_info.get_virtual_tokens_balance()?, - ft_to_mint, - )?)?; - fund_info.set_virtual_tokens_supply(math::checked_add( - fund_info.get_virtual_tokens_supply()?, - ft_to_mint, - )?)?; - } else { - pda::mint_to_with_seeds( - user_fund_token_account, - fund_token_mint, - fund_authority, - seeds, - ft_to_mint, - )?; - } - - // update stats - msg!("Update Fund stats"); - fund_info - .set_amount_invested_usd(fund_info.get_amount_invested_usd()? + deposit_value_usd)?; - fund_info.set_current_assets_usd(current_assets_usd + deposit_value_usd)?; - - // update user stats - msg!("Update user stats"); - user_requests.last_deposit.time = user_requests.deposit_request.time; - user_requests.last_deposit.amount = amount_with_fee; - user_requests.deposit_request.time = 0; - user_requests.deposit_request.amount = 0; - user_requests.deny_reason = ArrayString64::default(); - user_requests.pack(*user_requests_account.try_borrow_mut_data()?)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/approve_withdrawal.rs b/farms/fund/src/instructions/approve_withdrawal.rs deleted file mode 100644 index ec56869f89f..00000000000 --- a/farms/fund/src/instructions/approve_withdrawal.rs +++ /dev/null @@ -1,243 +0,0 @@ -//! Approve withdrawal from the Fund instruction handler - -use { - crate::{common, fund_info::FundInfo, user_info::UserInfo}, - solana_farm_sdk::{ - fund::{Fund, FundUserRequests}, - math, - program::{account, pda}, - string::ArrayString64, - token::Token, - traits::Packed, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn approve_withdrawal(fund: &Fund, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - fund_metadata, - fund_info_account, - _multisig_account, - fund_authority, - _spl_token_program, - fund_token_mint, - user_account, - user_info_account, - user_requests_account, - user_withdrawal_token_account, - user_fund_token_account, - custody_account, - custody_fees_account, - custody_metadata, - custody_token_metadata, - oracle_account - ] = accounts - { - // validate params and accounts - msg!("Validate state and accounts"); - let mut fund_info = FundInfo::new(fund_info_account); - if fund_info.get_liquidation_start_time()? > 0 { - msg!("Error: Fund is in liquidation state"); - return Err(ProgramError::Custom(516)); - } - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - if !UserInfo::validate_account(fund, user_info_account, user_account.key) { - msg!("Error: Invalid user info account"); - return Err(ProgramError::Custom(140)); - } - if !account::check_token_account_owner(user_withdrawal_token_account, user_account.key)? { - msg!("Error: Invalid withdrawal destination account owner"); - return Err(ProgramError::IllegalOwner); - } - common::check_fund_token_mint(fund, fund_token_mint)?; - - let custody_token = account::unpack::(custody_token_metadata, "custody token")?; - common::check_wd_custody_accounts( - &fund.fund_program_id, - fund_metadata.key, - &custody_token, - custody_token_metadata, - user_withdrawal_token_account, - custody_account, - custody_fees_account, - custody_metadata, - oracle_account, - )?; - - let mut user_requests = - account::unpack::(user_requests_account, "user requests")?; - common::check_user_requests_account( - fund, - &custody_token, - &user_requests, - user_account, - user_requests_account, - )?; - - // check if there are any pending requests - if user_requests.withdrawal_request.amount == 0 { - msg!("Error: No pending withdrawals found"); - return Err(ProgramError::Custom(526)); - } - - // compute withdrawal amount - msg!("Compute withdrawal amount"); - let amount_with_fee = if amount == 0 { - user_requests.withdrawal_request.amount - } else { - std::cmp::min(amount, user_requests.withdrawal_request.amount) - }; - let mut user_info = UserInfo::new(user_info_account); - let user_fund_token_balance = - common::get_fund_token_balance(user_fund_token_account, &user_info)?; - if amount_with_fee == 0 || amount_with_fee > user_fund_token_balance { - msg!("Error: Insufficient user funds"); - return Err(ProgramError::InsufficientFunds); - } - - // check if last assets update was not too long ago, - // stale value may lead to incorrect amount of tokens received - common::check_assets_update_time( - fund_info.get_assets_update_time()?, - fund_info.get_assets_max_update_age_sec()?, - )?; - - // compute nominal value of withdrawn tokens and check against the limit - msg!("Compute assets value. amount_with_fee: {}", amount_with_fee); - let ft_supply_amount = common::get_fund_token_supply(fund_token_mint, &fund_info)?; - if amount_with_fee > ft_supply_amount { - msg!("Error: Insufficient Fund supply amount"); - return Err(ProgramError::InsufficientFunds); - } - // ft_supply_amount > 0 - let withdrawal_value_usd = - fund_info.get_current_assets_usd()? * amount_with_fee as f64 / ft_supply_amount as f64; - - // no individual withdrawal limit check (discretion of the Fund manager) - - // compute tokens to transfer - msg!( - "Compute tokens to transfer. withdrawal_value_usd: {}", - withdrawal_value_usd - ); - let tokens_to_remove = account::get_asset_value_tokens( - withdrawal_value_usd, - custody_token.decimals, - custody_token.oracle_type, - oracle_account, - fund_info.get_assets_max_price_error()?, - fund_info.get_assets_max_price_age_sec()?, - )?; - - // 0 <= fund_fee <= 1 - let fund_fee = fund_info.get_withdrawal_fee()?; - let (fee_numerator, fee_denominator) = math::get_fee_parts(fund_fee); - let fee_tokens = math::checked_as_u64(math::checked_div( - math::checked_mul(tokens_to_remove as u128, fee_numerator as u128)?, - fee_denominator as u128, - )?)?; - let tokens_to_tranfer = math::checked_sub(tokens_to_remove, fee_tokens)?; - if tokens_to_tranfer == 0 { - msg!("Error: Withdrawal amount is too small"); - return Err(ProgramError::InsufficientFunds); - } - - if tokens_to_remove > account::get_token_balance(custody_account)? { - msg!("Error: Withdrawal for this amount couldn't be completed at this time. Contact Fund administrator."); - return Err(ProgramError::InsufficientFunds); - } - - // transfer tokens from custody to the user - msg!( - "Transfer tokens to user wallet. tokens_to_tranfer: {}, fee_tokens: {}", - tokens_to_tranfer, - fee_tokens, - ); - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - pda::transfer_tokens_with_seeds( - custody_account, - user_withdrawal_token_account, - fund_authority, - seeds, - tokens_to_tranfer, - )?; - if fee_tokens > 0 { - pda::transfer_tokens_with_seeds( - custody_account, - custody_fees_account, - fund_authority, - seeds, - fee_tokens, - )?; - } - - // burn Fund tokens from user - msg!( - "Burn Fund tokens from the user. amount_with_fee {}", - amount_with_fee - ); - let (amount_to_burn, amount_to_reduce) = if fund_info.get_issue_virtual_tokens()? { - let token_balance = account::get_token_balance(user_fund_token_account)?; - let amount_to_burn = std::cmp::min(amount_with_fee, token_balance); - let amount_to_reduce = math::checked_sub(amount_with_fee, amount_to_burn)?; - (amount_to_burn, amount_to_reduce) - } else { - let amount_to_reduce = - std::cmp::min(amount_with_fee, user_info.get_virtual_tokens_balance()?); - let amount_to_burn = math::checked_sub(amount_with_fee, amount_to_reduce)?; - (amount_to_burn, amount_to_reduce) - }; - pda::burn_tokens_with_seeds( - user_fund_token_account, - fund_token_mint, - fund_authority, - seeds, - amount_to_burn, - )?; - user_info.set_virtual_tokens_balance(math::checked_sub( - user_info.get_virtual_tokens_balance()?, - amount_to_reduce, - )?)?; - fund_info.set_virtual_tokens_supply(math::checked_sub( - fund_info.get_virtual_tokens_supply()?, - amount_to_reduce, - )?)?; - - // update stats - msg!("Update Fund stats"); - let current_assets_usd = fund_info.get_current_assets_usd()?; - let new_assets = if current_assets_usd > withdrawal_value_usd { - current_assets_usd - withdrawal_value_usd - } else { - 0.0 - }; - fund_info - .set_amount_removed_usd(fund_info.get_amount_removed_usd()? + withdrawal_value_usd)?; - fund_info.set_current_assets_usd(new_assets)?; - - // update user stats - msg!("Update user stats"); - user_requests.last_withdrawal.time = user_requests.withdrawal_request.time; - user_requests.last_withdrawal.amount = amount_with_fee; - user_requests.withdrawal_request.time = 0; - user_requests.withdrawal_request.amount = 0; - user_requests.deny_reason = ArrayString64::default(); - user_requests.pack(*user_requests_account.try_borrow_mut_data()?)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/cancel_deposit.rs b/farms/fund/src/instructions/cancel_deposit.rs deleted file mode 100644 index fed9cace8d9..00000000000 --- a/farms/fund/src/instructions/cancel_deposit.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! Cancel deposit to the Fund instruction handler - -use { - crate::common, - solana_farm_sdk::{ - fund::{Fund, FundUserRequests}, - id::main_router, - program::account, - string::ArrayString64, - token::Token, - traits::Packed, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn cancel_deposit(fund: &Fund, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - _fund_metadata, - _fund_info_account, - _spl_token_program, - user_requests_account, - user_deposit_token_account, - custody_token_metadata - ] = accounts - { - // validate accounts - msg!("Validate state and accounts"); - if !user_account.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - if custody_token_metadata.owner != &main_router::id() { - msg!("Error: Invalid custody token metadata owner"); - return Err(ProgramError::IllegalOwner); - } - let custody_token = account::unpack::(custody_token_metadata, "custody token")?; - let mut user_requests = account::unpack::(user_requests_account, "user requests")?; - common::check_user_requests_account( - fund, - &custody_token, - &user_requests, - user_account, - user_requests_account, - )?; - - // check if there are any pending requests - if user_requests.deposit_request.amount == 0 { - msg!("No pending deposits found"); - return Ok(()); - } - - // cancel pending deposit - msg!("Cancel pending deposit"); - account::revoke_delegate(user_deposit_token_account, user_account)?; - user_requests.deposit_request.time = 0; - user_requests.deposit_request.amount = 0; - user_requests.deny_reason = ArrayString64::default(); - user_requests.pack(*user_requests_account.try_borrow_mut_data()?)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/cancel_withdrawal.rs b/farms/fund/src/instructions/cancel_withdrawal.rs deleted file mode 100644 index 99dfd698ba0..00000000000 --- a/farms/fund/src/instructions/cancel_withdrawal.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! Cancel withdrawal from the Fund instruction handler - -use { - crate::common, - solana_farm_sdk::{ - fund::{Fund, FundUserRequests}, - id::main_router, - program::account, - string::ArrayString64, - token::Token, - traits::Packed, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn cancel_withdrawal(fund: &Fund, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - _fund_metadata, - _fund_info_account, - _spl_token_program, - user_requests_account, - user_fund_token_account, - custody_token_metadata - ] = accounts - { - // validate accounts - msg!("Validate state and accounts"); - if !user_account.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - if custody_token_metadata.owner != &main_router::id() { - msg!("Error: Invalid custody token metadata owner"); - return Err(ProgramError::IllegalOwner); - } - let custody_token = account::unpack::(custody_token_metadata, "custody token")?; - let mut user_requests = account::unpack::(user_requests_account, "user requests")?; - common::check_user_requests_account( - fund, - &custody_token, - &user_requests, - user_account, - user_requests_account, - )?; - - // check if there are any pending requests - if user_requests.withdrawal_request.amount == 0 { - msg!("No pending withdrawals found"); - return Ok(()); - } - - // cancel pending withdrawal - msg!("Cancel pending withdrawal"); - account::revoke_delegate(user_fund_token_account, user_account)?; - user_requests.withdrawal_request.time = 0; - user_requests.withdrawal_request.amount = 0; - user_requests.deny_reason = ArrayString64::default(); - user_requests.pack(*user_requests_account.try_borrow_mut_data()?)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/deny_deposit.rs b/farms/fund/src/instructions/deny_deposit.rs deleted file mode 100644 index f9859fce319..00000000000 --- a/farms/fund/src/instructions/deny_deposit.rs +++ /dev/null @@ -1,70 +0,0 @@ -//! Deny deposit to the Fund instruction handler - -use { - crate::common, - solana_farm_sdk::{ - fund::{Fund, FundUserRequests}, - id::main_router, - program::account, - string::ArrayString64, - token::Token, - traits::Packed, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn deny_deposit( - fund: &Fund, - accounts: &[AccountInfo], - deny_reason: &ArrayString64, -) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - _fund_metadata, - _fund_info_account, - _multisig_account, - user_account, - user_requests_account, - custody_token_metadata - ] = accounts - { - // validate params and accounts - msg!("Validate state and accounts"); - let mut user_requests = account::unpack::(user_requests_account, "user requests")?; - if custody_token_metadata.owner != &main_router::id() { - msg!("Error: Invalid custody token metadata owner"); - return Err(ProgramError::IllegalOwner); - } - let custody_token = account::unpack::(custody_token_metadata, "custody token")?; - common::check_user_requests_account( - fund, - &custody_token, - &user_requests, - user_account, - user_requests_account, - )?; - - // check if there are any pending requests - if user_requests.deposit_request.amount == 0 { - msg!("Error: No pending deposits found"); - return Err(ProgramError::Custom(525)); - } - - // update user stats - msg!("Update user stats"); - user_requests.last_deposit.time = user_requests.deposit_request.time; - user_requests.last_deposit.amount = user_requests.deposit_request.amount; - user_requests.deposit_request.time = 0; - user_requests.deposit_request.amount = 0; - user_requests.deny_reason = *deny_reason; - user_requests.pack(*user_requests_account.try_borrow_mut_data()?)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/deny_withdrawal.rs b/farms/fund/src/instructions/deny_withdrawal.rs deleted file mode 100644 index da6bc6d487a..00000000000 --- a/farms/fund/src/instructions/deny_withdrawal.rs +++ /dev/null @@ -1,70 +0,0 @@ -//! Deny withdrawal from the Fund instruction handler - -use { - crate::common, - solana_farm_sdk::{ - fund::{Fund, FundUserRequests}, - id::main_router, - program::account, - string::ArrayString64, - token::Token, - traits::Packed, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn deny_withdrawal( - fund: &Fund, - accounts: &[AccountInfo], - deny_reason: &ArrayString64, -) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - _fund_metadata, - _fund_info_account, - _multisig_account, - user_account, - user_requests_account, - custody_token_metadata - ] = accounts - { - // validate params and accounts - msg!("Validate state and accounts"); - let mut user_requests = account::unpack::(user_requests_account, "user requests")?; - if custody_token_metadata.owner != &main_router::id() { - msg!("Error: Invalid custody token metadata owner"); - return Err(ProgramError::IllegalOwner); - } - let custody_token = account::unpack::(custody_token_metadata, "custody token")?; - common::check_user_requests_account( - fund, - &custody_token, - &user_requests, - user_account, - user_requests_account, - )?; - - // check if there are any pending requests - if user_requests.withdrawal_request.amount == 0 { - msg!("Error: No pending withdrawals found"); - return Err(ProgramError::Custom(526)); - } - - // update user stats - msg!("Update user stats"); - user_requests.last_withdrawal.time = user_requests.withdrawal_request.time; - user_requests.last_withdrawal.amount = user_requests.withdrawal_request.amount; - user_requests.withdrawal_request.time = 0; - user_requests.withdrawal_request.amount = 0; - user_requests.deny_reason = *deny_reason; - user_requests.pack(*user_requests_account.try_borrow_mut_data()?)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/disable_deposits.rs b/farms/fund/src/instructions/disable_deposits.rs deleted file mode 100644 index a5c519ae834..00000000000 --- a/farms/fund/src/instructions/disable_deposits.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! Fund DisableDeposits instruction handler - -use { - crate::fund_info::FundInfo, - solana_farm_sdk::fund::Fund, - solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, msg}, -}; - -pub fn disable_deposits( - _fund: &Fund, - fund_info: &mut FundInfo, - _accounts: &[AccountInfo], -) -> ProgramResult { - msg!("Disable deposits to the Fund"); - - fund_info.set_deposit_start_time(0)?; - fund_info.set_deposit_end_time(0)?; - fund_info.set_deposit_approval_required(true) -} diff --git a/farms/fund/src/instructions/disable_withdrawals.rs b/farms/fund/src/instructions/disable_withdrawals.rs deleted file mode 100644 index 94729fa154f..00000000000 --- a/farms/fund/src/instructions/disable_withdrawals.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! Fund DisableWithdrawals instruction handler - -use { - crate::fund_info::FundInfo, - solana_farm_sdk::fund::Fund, - solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, msg}, -}; - -pub fn disable_withdrawals( - _fund: &Fund, - fund_info: &mut FundInfo, - _accounts: &[AccountInfo], -) -> ProgramResult { - msg!("Disable withdrawals from the Fund"); - - fund_info.set_withdrawal_start_time(0)?; - fund_info.set_withdrawal_end_time(0)?; - fund_info.set_withdrawal_approval_required(true) -} diff --git a/farms/fund/src/instructions/init.rs b/farms/fund/src/instructions/init.rs deleted file mode 100644 index 43753432044..00000000000 --- a/farms/fund/src/instructions/init.rs +++ /dev/null @@ -1,136 +0,0 @@ -//! Fund Init instruction handler - -use { - crate::fund_info::FundInfo, - solana_farm_sdk::{ - fund::{Fund, FundAssetType, FundAssets}, - program::{account, pda}, - token::Token, - traits::Packed, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn init(fund: &Fund, accounts: &[AccountInfo], _step: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - admin_account, - _fund_metadata, - fund_info_account, - _multisig_account, - fund_authority, - fund_program, - _system_program, - _spl_token_program, - rent_program, - fund_token_mint, - fund_token_ref, - vaults_assets_info, - custodies_assets_info - ] = accounts - { - // validate accounts - if fund_authority.key != &fund.fund_authority - || fund_token_ref.key != &fund.fund_token_ref - || fund_program.key != &fund.fund_program_id - { - msg!("Error: Invalid Fund accounts"); - return Err(ProgramError::Custom(511)); - } - - // init fund authority account - msg!("Init Fund authority"); - pda::init_system_account( - admin_account, - fund_authority, - &fund.fund_program_id, - &fund.fund_program_id, - &[b"fund_authority", fund.name.as_bytes()], - 0, - )?; - - // init fund info account - msg!("Init Fund info"); - pda::init_system_account( - admin_account, - fund_info_account, - &fund.fund_program_id, - &fund.fund_program_id, - &[b"info_account", fund.name.as_bytes()], - FundInfo::LEN, - )?; - let mut fund_info = FundInfo::new(fund_info_account); - fund_info.init(&fund.name)?; - - // init fund token mint - msg!("Init Fund token mint"); - let fund_token = account::unpack::(fund_token_ref, "Fund Token")?; - if fund_token_mint.key != &fund_token.mint { - msg!("Error: Invalid Fund token mint"); - return Err(ProgramError::Custom(510)); - } - pda::init_mint( - admin_account, - fund_token_mint, - fund_authority, - rent_program, - &fund.fund_program_id, - &[b"fund_token_mint", fund.name.as_bytes()], - fund_token.decimals, - )?; - - // init vaults assets info - if account::is_empty(vaults_assets_info)? { - msg!("Init vaults assets info"); - let bump = pda::init_system_account( - admin_account, - vaults_assets_info, - &fund.fund_program_id, - &fund.fund_program_id, - &[b"vaults_assets_info", fund.name.as_bytes()], - FundAssets::LEN, - )?; - let mut fund_assets = account::unpack::(vaults_assets_info, "Vaults assets")?; - fund_assets.asset_type = FundAssetType::Vault; - fund_assets.target_hash = 0; - fund_assets.current_hash = 0; - fund_assets.current_cycle = 0; - fund_assets.current_assets_usd = 0.0; - fund_assets.cycle_start_time = 0; - fund_assets.cycle_end_time = 0; - fund_assets.bump = bump; - fund_assets.pack(*vaults_assets_info.try_borrow_mut_data()?)?; - } - - // init custodies assets info - if account::is_empty(custodies_assets_info)? { - msg!("Init custodies assets info"); - let bump = pda::init_system_account( - admin_account, - custodies_assets_info, - &fund.fund_program_id, - &fund.fund_program_id, - &[b"custodies_assets_info", fund.name.as_bytes()], - FundAssets::LEN, - )?; - let mut fund_assets = - account::unpack::(custodies_assets_info, "Custodies assets")?; - fund_assets.asset_type = FundAssetType::Custody; - fund_assets.target_hash = 0; - fund_assets.current_hash = 0; - fund_assets.current_cycle = 0; - fund_assets.current_assets_usd = 0.0; - fund_assets.cycle_start_time = 0; - fund_assets.cycle_end_time = 0; - fund_assets.bump = bump; - fund_assets.pack(*custodies_assets_info.try_borrow_mut_data()?)?; - } - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/lock_assets.rs b/farms/fund/src/instructions/lock_assets.rs deleted file mode 100644 index 44b7549cd04..00000000000 --- a/farms/fund/src/instructions/lock_assets.rs +++ /dev/null @@ -1,97 +0,0 @@ -//! Move funds from deposit to trading custody instruction handler - -use { - crate::{common, fund_info::FundInfo}, - solana_farm_sdk::{ - fund::{Fund, FundCustodyType}, - program::{account, pda}, - token::Token, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn lock_assets(fund: &Fund, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - fund_metadata, - fund_info_account, - _multisig_account, - fund_authority, - _spl_token_program, - wd_custody_account, - wd_custody_metadata, - trading_custody_account, - trading_custody_metadata, - custody_token_metadata - ] = accounts - { - // validate params and accounts - msg!("Validate state and accounts"); - let fund_info = FundInfo::new(fund_info_account); - if fund_info.get_liquidation_start_time()? > 0 { - msg!("Error: Fund is in liquidation state"); - return Err(ProgramError::Custom(516)); - } - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - - let custody_token = account::unpack::(custody_token_metadata, "custody token")?; - common::check_custody_account( - &fund.fund_program_id, - fund_metadata.key, - &custody_token, - custody_token_metadata, - wd_custody_metadata, - FundCustodyType::DepositWithdraw, - wd_custody_account, - None, - )?; - common::check_custody_account( - &fund.fund_program_id, - fund_metadata.key, - &custody_token, - custody_token_metadata, - trading_custody_metadata, - FundCustodyType::Trading, - trading_custody_account, - None, - )?; - - // check if there are funds in w/d custody - let wd_custody_balance = account::get_token_balance(wd_custody_account)?; - let amount = if amount > 0 { - amount - } else { - wd_custody_balance - }; - if amount == 0 || amount < wd_custody_balance { - msg!("Error: Not enough funds in w/d custody"); - return Err(ProgramError::Custom(527)); - } - - // trandsfer tokens from w/d to trading custody - msg!("Transfer funds to trading custody"); - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - pda::transfer_tokens_with_seeds( - wd_custody_account, - trading_custody_account, - fund_authority, - seeds, - amount, - )?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/mod.rs b/farms/fund/src/instructions/mod.rs deleted file mode 100644 index c631dc2ad62..00000000000 --- a/farms/fund/src/instructions/mod.rs +++ /dev/null @@ -1,30 +0,0 @@ -pub mod add_custody; -pub mod add_vault; -pub mod approve_deposit; -pub mod approve_withdrawal; -pub mod cancel_deposit; -pub mod cancel_withdrawal; -pub mod deny_deposit; -pub mod deny_withdrawal; -pub mod disable_deposits; -pub mod disable_withdrawals; -pub mod init; -pub mod lock_assets; -pub mod orca; -pub mod raydium; -pub mod remove_custody; -pub mod remove_multisig; -pub mod remove_vault; -pub mod request_deposit; -pub mod request_withdrawal; -pub mod set_admin_signers; -pub mod set_assets_tracking_config; -pub mod set_deposit_schedule; -pub mod set_withdrawal_schedule; -pub mod start_liquidation; -pub mod stop_liquidation; -pub mod unlock_assets; -pub mod update_assets_with_custody; -pub mod update_assets_with_vault; -pub mod user_init; -pub mod withdraw_fees; diff --git a/farms/fund/src/instructions/orca/add_liquidity.rs b/farms/fund/src/instructions/orca/add_liquidity.rs deleted file mode 100644 index 471753044b3..00000000000 --- a/farms/fund/src/instructions/orca/add_liquidity.rs +++ /dev/null @@ -1,113 +0,0 @@ -//! Add liquidity to the Orca pool instruction - -use { - crate::{common, fund_info::FundInfo}, - solana_farm_sdk::{fund::Fund, instruction::amm::AmmInstruction, program::account}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke_signed, - program_error::ProgramError, - }, -}; - -pub fn add_liquidity( - fund: &Fund, - accounts: &[AccountInfo], - max_token_a_amount: u64, - max_token_b_amount: u64, -) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - fund_metadata, - fund_info_account, - fund_authority, - router_program_id, - fund_vault_metadata, - fund_token_a_account, - fund_token_b_account, - fund_lp_token_account, - pool_program_id, - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - spl_token_id, - amm_id, - amm_authority - ] = accounts - { - // validate params and accounts - msg!("Validate state and accounts"); - let fund_info = FundInfo::new(fund_info_account); - if fund_info.get_liquidation_start_time()? > 0 { - msg!("Error: Fund is in liquidation state"); - return Err(ProgramError::Custom(516)); - } - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - - let vault = common::check_unpack_target_vault( - &fund.fund_program_id, - router_program_id.key, - fund_metadata.key, - amm_id.key, - fund_vault_metadata, - )?; - - // prepare instruction and call orca router - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - - let initial_lp_balance = account::get_token_balance(fund_lp_token_account)?; - - let orca_accounts = vec![ - AccountMeta::new_readonly(*fund_authority.key, true), - AccountMeta::new(*fund_token_a_account.key, false), - AccountMeta::new(*fund_token_b_account.key, false), - AccountMeta::new(*fund_lp_token_account.key, false), - AccountMeta::new_readonly(*pool_program_id.key, false), - AccountMeta::new(*pool_token_a_account.key, false), - AccountMeta::new(*pool_token_b_account.key, false), - AccountMeta::new(*lp_token_mint.key, false), - AccountMeta::new_readonly(*spl_token_id.key, false), - AccountMeta::new_readonly(*amm_id.key, false), - AccountMeta::new_readonly(*amm_authority.key, false), - ]; - - let instruction = Instruction { - program_id: *router_program_id.key, - accounts: orca_accounts, - data: AmmInstruction::AddLiquidity { - max_token_a_amount, - max_token_b_amount, - } - .to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds)?; - - // update stats - msg!("Update vault balance"); - let lp_received = account::get_balance_increase(fund_lp_token_account, initial_lp_balance)?; - msg!( - "token_a_balance: {}, token_b_balance: {}, lp_received: {}", - account::get_token_balance(fund_token_a_account)?, - account::get_token_balance(fund_token_b_account)?, - lp_received - ); - common::increase_vault_balance(fund_vault_metadata, &vault, lp_received)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/orca/harvest.rs b/farms/fund/src/instructions/orca/harvest.rs deleted file mode 100644 index 56d20dd654d..00000000000 --- a/farms/fund/src/instructions/orca/harvest.rs +++ /dev/null @@ -1,95 +0,0 @@ -//! Harvest rewards from Orca farm instruction - -use { - crate::{common, fund_info::FundInfo}, - solana_farm_sdk::{fund::Fund, instruction::amm::AmmInstruction, program::account}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke_signed, - program_error::ProgramError, - }, -}; - -pub fn harvest(fund: &Fund, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - fund_metadata, - fund_info_account, - fund_authority, - router_program_id, - fund_vault_metadata, - fund_stake_info_account, - fund_reward_token_account, - farm_program_id, - farm_base_token_vault, - farm_reward_token_vault, - spl_token_id, - farm_id, - farm_authority - ] = accounts - { - // validate params and accounts - msg!("Validate state and accounts"); - if FundInfo::new(fund_info_account).get_liquidation_start_time()? > 0 { - msg!("Error: Fund is in liquidation state"); - return Err(ProgramError::Custom(516)); - } - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - if account::is_empty(fund_stake_info_account)? { - msg!("Error: Fund stake info account must be initialized first"); - return Err(ProgramError::UninitializedAccount); - } - - common::check_unpack_target_vault( - &fund.fund_program_id, - router_program_id.key, - fund_metadata.key, - farm_id.key, - fund_vault_metadata, - )?; - - // prepare instruction and call orca router - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - - let orca_accounts = vec![ - AccountMeta::new_readonly(*fund_authority.key, true), - AccountMeta::new(*fund_stake_info_account.key, false), - AccountMeta::new(*fund_reward_token_account.key, false), - AccountMeta::new_readonly(*farm_program_id.key, false), - AccountMeta::new(*farm_base_token_vault.key, false), - AccountMeta::new(*farm_reward_token_vault.key, false), - AccountMeta::new_readonly(*spl_token_id.key, false), - AccountMeta::new(*farm_id.key, false), - AccountMeta::new_readonly(*farm_authority.key, false), - ]; - - let instruction = Instruction { - program_id: *router_program_id.key, - accounts: orca_accounts, - data: AmmInstruction::Harvest.to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds)?; - - msg!( - "reward_balance: {}", - account::get_token_balance(fund_reward_token_account)?, - ); - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/orca/mod.rs b/farms/fund/src/instructions/orca/mod.rs deleted file mode 100644 index 0899dbfe803..00000000000 --- a/farms/fund/src/instructions/orca/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -pub mod add_liquidity; -pub mod harvest; -pub mod remove_liquidity; -pub mod stake; -pub mod swap; -pub mod unstake; -pub mod user_init; -pub mod vault_add_liquidity; -pub mod vault_lock_liquidity; -pub mod vault_remove_liquidity; -pub mod vault_unlock_liquidity; -pub mod vault_user_init; diff --git a/farms/fund/src/instructions/orca/remove_liquidity.rs b/farms/fund/src/instructions/orca/remove_liquidity.rs deleted file mode 100644 index be6c8b4031c..00000000000 --- a/farms/fund/src/instructions/orca/remove_liquidity.rs +++ /dev/null @@ -1,101 +0,0 @@ -//! Remove liquidity from the Orca pool instruction - -use { - crate::common, - solana_farm_sdk::{fund::Fund, instruction::amm::AmmInstruction, program::account}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke_signed, - program_error::ProgramError, - }, -}; - -pub fn remove_liquidity(fund: &Fund, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - fund_metadata, - _fund_info_account, - fund_authority, - router_program_id, - fund_vault_metadata, - fund_token_a_account, - fund_token_b_account, - fund_lp_token_account, - pool_program_id, - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - spl_token_id, - amm_id, - amm_authority, - pool_fees_account - ] = accounts - { - // validate params and accounts - msg!("Validate state and accounts"); - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - - let vault = common::check_unpack_target_vault( - &fund.fund_program_id, - router_program_id.key, - fund_metadata.key, - amm_id.key, - fund_vault_metadata, - )?; - - // prepare instruction and call orca router - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - - let initial_lp_balance = account::get_token_balance(fund_lp_token_account)?; - - let orca_accounts = vec![ - AccountMeta::new_readonly(*fund_authority.key, true), - AccountMeta::new(*fund_token_a_account.key, false), - AccountMeta::new(*fund_token_b_account.key, false), - AccountMeta::new(*fund_lp_token_account.key, false), - AccountMeta::new_readonly(*pool_program_id.key, false), - AccountMeta::new(*pool_token_a_account.key, false), - AccountMeta::new(*pool_token_b_account.key, false), - AccountMeta::new(*lp_token_mint.key, false), - AccountMeta::new_readonly(*spl_token_id.key, false), - AccountMeta::new_readonly(*amm_id.key, false), - AccountMeta::new_readonly(*amm_authority.key, false), - AccountMeta::new(*pool_fees_account.key, false), - ]; - - let instruction = Instruction { - program_id: *router_program_id.key, - accounts: orca_accounts, - data: AmmInstruction::RemoveLiquidity { amount }.to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds)?; - - // update stats - msg!("Update vault balance"); - let lp_removed = account::get_balance_decrease(fund_lp_token_account, initial_lp_balance)?; - msg!( - "token_a_balance: {}, token_b_balance: {}, lp_removed: {}", - account::get_token_balance(fund_token_a_account)?, - account::get_token_balance(fund_token_b_account)?, - lp_removed - ); - common::decrease_vault_balance(fund_vault_metadata, &vault, lp_removed)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/orca/stake.rs b/farms/fund/src/instructions/orca/stake.rs deleted file mode 100644 index 8211420858d..00000000000 --- a/farms/fund/src/instructions/orca/stake.rs +++ /dev/null @@ -1,103 +0,0 @@ -//! Stake LP tokens to a Orca farm instruction - -use { - crate::{common, fund_info::FundInfo}, - solana_farm_sdk::{fund::Fund, instruction::amm::AmmInstruction, program::account}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke_signed, - program_error::ProgramError, - }, -}; - -pub fn stake(fund: &Fund, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - fund_metadata, - fund_info_account, - fund_authority, - router_program_id, - fund_vault_metadata, - fund_stake_info_account, - fund_lp_token_account, - fund_reward_token_account, - fund_farm_lp_token_account, - farm_lp_token_mint, - farm_program_id, - farm_base_token_vault, - farm_reward_token_vault, - spl_token_id, - farm_id, - farm_authority - ] = accounts - { - // validate params and accounts - msg!("Validate state and accounts"); - if FundInfo::new(fund_info_account).get_liquidation_start_time()? > 0 { - msg!("Error: Fund is in liquidation state"); - return Err(ProgramError::Custom(516)); - } - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - if account::is_empty(fund_stake_info_account)? { - msg!("Error: Fund stake info account must be initialized first"); - return Err(ProgramError::UninitializedAccount); - } - - common::check_unpack_target_vault( - &fund.fund_program_id, - router_program_id.key, - fund_metadata.key, - farm_id.key, - fund_vault_metadata, - )?; - - // prepare instruction and call orca router - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - - let orca_accounts = vec![ - AccountMeta::new_readonly(*fund_authority.key, true), - AccountMeta::new(*fund_stake_info_account.key, false), - AccountMeta::new(*fund_lp_token_account.key, false), - AccountMeta::new(*fund_reward_token_account.key, false), - AccountMeta::new(*fund_farm_lp_token_account.key, false), - AccountMeta::new(*farm_lp_token_mint.key, false), - AccountMeta::new_readonly(*farm_program_id.key, false), - AccountMeta::new(*farm_base_token_vault.key, false), - AccountMeta::new(*farm_reward_token_vault.key, false), - AccountMeta::new_readonly(*spl_token_id.key, false), - AccountMeta::new(*farm_id.key, false), - AccountMeta::new_readonly(*farm_authority.key, false), - ]; - - let instruction = Instruction { - program_id: *router_program_id.key, - accounts: orca_accounts, - data: AmmInstruction::Stake { amount }.to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds)?; - - msg!( - "reward_balance: {}, farm_lp_token_balance: {}, lp_token_balance: {}", - account::get_token_balance(fund_reward_token_account)?, - account::get_token_balance(fund_farm_lp_token_account)?, - account::get_token_balance(fund_lp_token_account)? - ); - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/orca/swap.rs b/farms/fund/src/instructions/orca/swap.rs deleted file mode 100644 index 1d4e1bc90a7..00000000000 --- a/farms/fund/src/instructions/orca/swap.rs +++ /dev/null @@ -1,129 +0,0 @@ -//! Swap tokens with the Orca pool instruction - -use { - crate::{common, fund_info::FundInfo}, - solana_farm_sdk::{ - error::FarmError, - fund::Fund, - instruction::amm::AmmInstruction, - program, - program::{account, clock}, - }, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke_signed, - program_error::ProgramError, - }, -}; - -pub fn swap( - fund: &Fund, - accounts: &[AccountInfo], - token_a_amount_in: u64, - token_b_amount_in: u64, - min_token_amount_out: u64, -) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - fund_metadata, - fund_info_account, - fund_authority, - router_program_id, - fund_vault_metadata, - fund_token_a_account, - fund_token_b_account, - pool_program_id, - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - spl_token_program, - amm_id, - amm_authority, - pool_fees_account, - sysvar_account - ] = accounts - { - // validate params and accounts - msg!("Validate state and accounts"); - let mut fund_info = FundInfo::new(fund_info_account); - if fund_info.get_liquidation_start_time()? > 0 { - let curtime = clock::get_time()?; - let last_trade_time = fund_info.get_last_trade_time()?; - if last_trade_time > 0 && curtime - last_trade_time < 300 { - msg!( - "Error: Too early for another swap, please retry in {} seconds", - 300 - curtime - last_trade_time - ); - return Err(FarmError::TooEarly.into()); - } - } - if !program::is_last_instruction(sysvar_account)? { - msg!("Error: Swap must be the last instruction in the transaction"); - return Err(ProgramError::InvalidArgument); - } - - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - - common::check_unpack_target_vault( - &fund.fund_program_id, - router_program_id.key, - fund_metadata.key, - amm_id.key, - fund_vault_metadata, - )?; - - // prepare instruction and call orca router - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - - let orca_accounts = vec![ - AccountMeta::new_readonly(*fund_authority.key, true), - AccountMeta::new(*fund_token_a_account.key, false), - AccountMeta::new(*fund_token_b_account.key, false), - AccountMeta::new_readonly(*pool_program_id.key, false), - AccountMeta::new(*pool_token_a_account.key, false), - AccountMeta::new(*pool_token_b_account.key, false), - AccountMeta::new(*lp_token_mint.key, false), - AccountMeta::new_readonly(*spl_token_program.key, false), - AccountMeta::new(*amm_id.key, false), - AccountMeta::new_readonly(*amm_authority.key, false), - AccountMeta::new(*pool_fees_account.key, false), - ]; - - let instruction = Instruction { - program_id: *router_program_id.key, - accounts: orca_accounts, - data: AmmInstruction::Swap { - token_a_amount_in, - token_b_amount_in, - min_token_amount_out, - } - .to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds)?; - - msg!( - "token_a_balance: {}, token_b_balance: {}", - account::get_token_balance(fund_token_a_account)?, - account::get_token_balance(fund_token_b_account)? - ); - - // update fund stats - msg!("Update Fund stats"); - fund_info.update_last_trade_time() - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/orca/unstake.rs b/farms/fund/src/instructions/orca/unstake.rs deleted file mode 100644 index 2b3a07231dc..00000000000 --- a/farms/fund/src/instructions/orca/unstake.rs +++ /dev/null @@ -1,99 +0,0 @@ -//! Unstake LP tokens from a Orca farm instruction - -use { - crate::common, - solana_farm_sdk::{fund::Fund, instruction::amm::AmmInstruction, program::account}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke_signed, - program_error::ProgramError, - }, -}; - -pub fn unstake(fund: &Fund, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - fund_metadata, - _fund_info_account, - fund_authority, - router_program_id, - fund_vault_metadata, - fund_stake_info_account, - fund_lp_token_account, - fund_reward_token_account, - fund_farm_lp_token_account, - farm_lp_token_mint, - farm_program_id, - farm_base_token_vault, - farm_reward_token_vault, - spl_token_id, - farm_id, - farm_authority - ] = accounts - { - // validate params and accounts - msg!("Validate state and accounts"); - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - if account::is_empty(fund_stake_info_account)? { - msg!("Error: Fund stake info account must be initialized first"); - return Err(ProgramError::UninitializedAccount); - } - - common::check_unpack_target_vault( - &fund.fund_program_id, - router_program_id.key, - fund_metadata.key, - farm_id.key, - fund_vault_metadata, - )?; - - // prepare instruction and call orca router - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - - let orca_accounts = vec![ - AccountMeta::new_readonly(*fund_authority.key, true), - AccountMeta::new(*fund_stake_info_account.key, false), - AccountMeta::new(*fund_lp_token_account.key, false), - AccountMeta::new(*fund_reward_token_account.key, false), - AccountMeta::new(*fund_farm_lp_token_account.key, false), - AccountMeta::new(*farm_lp_token_mint.key, false), - AccountMeta::new_readonly(*farm_program_id.key, false), - AccountMeta::new(*farm_base_token_vault.key, false), - AccountMeta::new(*farm_reward_token_vault.key, false), - AccountMeta::new_readonly(*spl_token_id.key, false), - AccountMeta::new(*farm_id.key, false), - AccountMeta::new_readonly(*farm_authority.key, false), - ]; - - let instruction = Instruction { - program_id: *router_program_id.key, - accounts: orca_accounts, - data: AmmInstruction::Unstake { amount }.to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds)?; - - msg!( - "reward_balance: {}, farm_lp_token_balance: {}, lp_token_balance: {}", - account::get_token_balance(fund_reward_token_account)?, - account::get_token_balance(fund_farm_lp_token_account)?, - account::get_token_balance(fund_lp_token_account)? - ); - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/orca/user_init.rs b/farms/fund/src/instructions/orca/user_init.rs deleted file mode 100644 index 7d6b07a4ca8..00000000000 --- a/farms/fund/src/instructions/orca/user_init.rs +++ /dev/null @@ -1,75 +0,0 @@ -//! Initialize a new user for a Orca farm instruction - -use { - crate::{common, fund_info::FundInfo}, - solana_farm_sdk::{fund::Fund, instruction::amm::AmmInstruction}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke, - program_error::ProgramError, - }, -}; - -pub fn user_init(fund: &Fund, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - admin_account, - fund_metadata, - fund_info_account, - fund_authority, - router_program_id, - fund_vault_metadata, - _fund_wallet_account, - fund_stake_info_account, - farm_id, - farm_program_id, - system_program - ] = accounts - { - // validate accounts - msg!("Validate state and accounts"); - let fund_info = FundInfo::new(fund_info_account); - if fund_info.get_liquidation_start_time()? > 0 { - msg!("Error: Fund is in liquidation state"); - return Err(ProgramError::Custom(516)); - } - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - - common::check_unpack_target_vault( - &fund.fund_program_id, - router_program_id.key, - fund_metadata.key, - farm_id.key, - fund_vault_metadata, - )?; - - // prepare instruction and call orca router - let orca_accounts = vec![ - AccountMeta::new(*admin_account.key, true), - AccountMeta::new_readonly(*fund_authority.key, false), - AccountMeta::new(*fund_stake_info_account.key, false), - AccountMeta::new_readonly(*farm_id.key, false), - AccountMeta::new_readonly(*farm_program_id.key, false), - AccountMeta::new_readonly(*system_program.key, false), - ]; - - let instruction = Instruction { - program_id: *router_program_id.key, - accounts: orca_accounts, - data: AmmInstruction::UserInit {}.to_vec()?, - }; - - invoke(&instruction, accounts)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/orca/vault_add_liquidity.rs b/farms/fund/src/instructions/orca/vault_add_liquidity.rs deleted file mode 100644 index e6060d66467..00000000000 --- a/farms/fund/src/instructions/orca/vault_add_liquidity.rs +++ /dev/null @@ -1,116 +0,0 @@ -//! Add liquidity to the Orca Vault instruction - -use { - crate::{common, fund_info::FundInfo}, - solana_farm_sdk::{fund::Fund, instruction::vault::VaultInstruction, program::account}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke_signed, - program_error::ProgramError, - }, -}; - -pub fn add_liquidity( - fund: &Fund, - accounts: &[AccountInfo], - max_token_a_amount: u64, - max_token_b_amount: u64, -) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - fund_metadata, - fund_info_account, - fund_authority, - vault_program_id, - fund_vault_metadata, - vault_metadata, - vault_info_account, - spl_token_program, - fund_vault_user_account, - fund_token_a_custody, - fund_token_b_custody, - fund_lp_token_custody, - vault_lp_token_custody, - pool_program_id, - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - amm_id, - amm_authority, - ] = accounts - { - // validate accounts - msg!("Validate state and accounts"); - let fund_info = FundInfo::new(fund_info_account); - if fund_info.get_liquidation_start_time()? > 0 { - msg!("Error: Fund is in liquidation state"); - return Err(ProgramError::Custom(516)); - } - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - - let vault = common::check_unpack_target_vault( - &fund.fund_program_id, - vault_program_id.key, - fund_metadata.key, - vault_metadata.key, - fund_vault_metadata, - )?; - - // prepare instruction and call vault program - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - - let initial_lp_balance = account::get_token_balance(vault_lp_token_custody)?; - - let vault_accounts = vec![ - AccountMeta::new_readonly(*fund_authority.key, true), - AccountMeta::new_readonly(*vault_metadata.key, false), - AccountMeta::new(*vault_info_account.key, false), - AccountMeta::new_readonly(*spl_token_program.key, false), - AccountMeta::new(*fund_vault_user_account.key, false), - AccountMeta::new(*fund_token_a_custody.key, false), - AccountMeta::new(*fund_token_b_custody.key, false), - AccountMeta::new(*fund_lp_token_custody.key, false), - AccountMeta::new(*vault_lp_token_custody.key, false), - AccountMeta::new_readonly(*pool_program_id.key, false), - AccountMeta::new(*pool_token_a_account.key, false), - AccountMeta::new(*pool_token_b_account.key, false), - AccountMeta::new(*lp_token_mint.key, false), - AccountMeta::new(*amm_id.key, false), - AccountMeta::new_readonly(*amm_authority.key, false), - ]; - - let instruction = Instruction { - program_id: *vault_program_id.key, - accounts: vault_accounts, - data: VaultInstruction::AddLiquidity { - max_token_a_amount, - max_token_b_amount, - } - .to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds)?; - - // update stats - msg!("Update vault balance"); - let lp_received = - account::get_balance_increase(vault_lp_token_custody, initial_lp_balance)?; - common::increase_vault_balance(fund_vault_metadata, &vault, lp_received)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/orca/vault_lock_liquidity.rs b/farms/fund/src/instructions/orca/vault_lock_liquidity.rs deleted file mode 100644 index 4a63fd06fc3..00000000000 --- a/farms/fund/src/instructions/orca/vault_lock_liquidity.rs +++ /dev/null @@ -1,105 +0,0 @@ -//! Lock liquidity in the Orca Vault instruction - -use { - crate::{common, fund_info::FundInfo}, - solana_farm_sdk::{fund::Fund, instruction::vault::VaultInstruction}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke_signed, - program_error::ProgramError, - }, -}; - -pub fn lock_liquidity(fund: &Fund, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - fund_metadata, - fund_info_account, - fund_authority, - vault_program_id, - fund_vault_metadata, - vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - vault_token_mint, - fund_vault_user_account, - fund_vt_token_custody, - vault_reward_custody, - vault_lp_token_custody, - farm_program, - vault_stake_info, - vault_stake_custody, - farm_id, - farm_authority, - farm_lp_token_mint, - farm_base_token_vault, - farm_reward_token_vault, - ] = accounts - { - // validate accounts - msg!("Validate state and accounts"); - let fund_info = FundInfo::new(fund_info_account); - if fund_info.get_liquidation_start_time()? > 0 { - msg!("Error: Fund is in liquidation state"); - return Err(ProgramError::Custom(516)); - } - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - - common::check_unpack_target_vault( - &fund.fund_program_id, - vault_program_id.key, - fund_metadata.key, - vault_metadata.key, - fund_vault_metadata, - )?; - - // prepare instruction and call vault program - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - - let vault_accounts = vec![ - AccountMeta::new_readonly(*fund_authority.key, true), - AccountMeta::new_readonly(*vault_metadata.key, false), - AccountMeta::new(*vault_info_account.key, false), - AccountMeta::new_readonly(*vault_authority.key, false), - AccountMeta::new_readonly(*spl_token_program.key, false), - AccountMeta::new(*vault_token_mint.key, false), - AccountMeta::new(*fund_vault_user_account.key, false), - AccountMeta::new(*fund_vt_token_custody.key, false), - AccountMeta::new(*vault_reward_custody.key, false), - AccountMeta::new(*vault_lp_token_custody.key, false), - AccountMeta::new_readonly(*farm_program.key, false), - AccountMeta::new(*vault_stake_info.key, false), - AccountMeta::new(*vault_stake_custody.key, false), - AccountMeta::new(*farm_id.key, false), - AccountMeta::new_readonly(*farm_authority.key, false), - AccountMeta::new(*farm_lp_token_mint.key, false), - AccountMeta::new(*farm_base_token_vault.key, false), - AccountMeta::new(*farm_reward_token_vault.key, false), - ]; - - let instruction = Instruction { - program_id: *vault_program_id.key, - accounts: vault_accounts, - data: VaultInstruction::LockLiquidity { amount }.to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/orca/vault_remove_liquidity.rs b/farms/fund/src/instructions/orca/vault_remove_liquidity.rs deleted file mode 100644 index 4e08b25d9e4..00000000000 --- a/farms/fund/src/instructions/orca/vault_remove_liquidity.rs +++ /dev/null @@ -1,103 +0,0 @@ -//! Remove liquidity from the Orca Vault instruction - -use { - crate::common, - solana_farm_sdk::{fund::Fund, instruction::vault::VaultInstruction, program::account}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke_signed, - program_error::ProgramError, - }, -}; - -pub fn remove_liquidity(fund: &Fund, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - fund_metadata, - _fund_info_account, - fund_authority, - vault_program_id, - fund_vault_metadata, - vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - fund_vault_user_account, - fund_token_a_custody, - fund_token_b_custody, - vault_lp_token_custody, - pool_program_id, - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - amm_id, - amm_authority, - pool_fees_account - ] = accounts - { - // validate accounts - msg!("Validate state and accounts"); - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - - let vault = common::check_unpack_target_vault( - &fund.fund_program_id, - vault_program_id.key, - fund_metadata.key, - vault_metadata.key, - fund_vault_metadata, - )?; - - // prepare instruction and call vault program - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - - let initial_lp_balance = account::get_token_balance(vault_lp_token_custody)?; - - let vault_accounts = vec![ - AccountMeta::new_readonly(*fund_authority.key, true), - AccountMeta::new_readonly(*vault_metadata.key, false), - AccountMeta::new(*vault_info_account.key, false), - AccountMeta::new_readonly(*vault_authority.key, false), - AccountMeta::new_readonly(*spl_token_program.key, false), - AccountMeta::new(*fund_vault_user_account.key, false), - AccountMeta::new(*fund_token_a_custody.key, false), - AccountMeta::new(*fund_token_b_custody.key, false), - AccountMeta::new(*vault_lp_token_custody.key, false), - AccountMeta::new_readonly(*pool_program_id.key, false), - AccountMeta::new(*pool_token_a_account.key, false), - AccountMeta::new(*pool_token_b_account.key, false), - AccountMeta::new(*lp_token_mint.key, false), - AccountMeta::new(*amm_id.key, false), - AccountMeta::new_readonly(*amm_authority.key, false), - AccountMeta::new(*pool_fees_account.key, false), - ]; - - let instruction = Instruction { - program_id: *vault_program_id.key, - accounts: vault_accounts, - data: VaultInstruction::RemoveLiquidity { amount }.to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds)?; - - // update stats - msg!("Update vault balance"); - let lp_removed = account::get_balance_decrease(vault_lp_token_custody, initial_lp_balance)?; - common::decrease_vault_balance(fund_vault_metadata, &vault, lp_removed)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/orca/vault_unlock_liquidity.rs b/farms/fund/src/instructions/orca/vault_unlock_liquidity.rs deleted file mode 100644 index 089c531ba61..00000000000 --- a/farms/fund/src/instructions/orca/vault_unlock_liquidity.rs +++ /dev/null @@ -1,100 +0,0 @@ -//! Unlock liquidity from the Orca Vault instruction - -use { - crate::common, - solana_farm_sdk::{fund::Fund, instruction::vault::VaultInstruction}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke_signed, - program_error::ProgramError, - }, -}; - -pub fn unlock_liquidity(fund: &Fund, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - fund_metadata, - _fund_info_account, - fund_authority, - vault_program_id, - fund_vault_metadata, - vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - vault_token_mint, - fund_vault_user_account, - fund_vt_token_custody, - vault_reward_custody, - vault_lp_token_custody, - farm_program, - vault_stake_info, - vault_stake_custody, - farm_id, - farm_authority, - farm_lp_token_mint, - farm_base_token_vault, - farm_reward_token_vault, - ] = accounts - { - // validate accounts - msg!("Validate state and accounts"); - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - - common::check_unpack_target_vault( - &fund.fund_program_id, - vault_program_id.key, - fund_metadata.key, - vault_metadata.key, - fund_vault_metadata, - )?; - - // prepare instruction and call vault program - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - - let vault_accounts = vec![ - AccountMeta::new_readonly(*fund_authority.key, true), - AccountMeta::new_readonly(*vault_metadata.key, false), - AccountMeta::new(*vault_info_account.key, false), - AccountMeta::new_readonly(*vault_authority.key, false), - AccountMeta::new_readonly(*spl_token_program.key, false), - AccountMeta::new(*vault_token_mint.key, false), - AccountMeta::new(*fund_vault_user_account.key, false), - AccountMeta::new(*fund_vt_token_custody.key, false), - AccountMeta::new(*vault_reward_custody.key, false), - AccountMeta::new(*vault_lp_token_custody.key, false), - AccountMeta::new_readonly(*farm_program.key, false), - AccountMeta::new(*vault_stake_info.key, false), - AccountMeta::new(*vault_stake_custody.key, false), - AccountMeta::new(*farm_id.key, false), - AccountMeta::new_readonly(*farm_authority.key, false), - AccountMeta::new(*farm_lp_token_mint.key, false), - AccountMeta::new(*farm_base_token_vault.key, false), - AccountMeta::new(*farm_reward_token_vault.key, false), - ]; - - let instruction = Instruction { - program_id: *vault_program_id.key, - accounts: vault_accounts, - data: VaultInstruction::UnlockLiquidity { amount }.to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/orca/vault_user_init.rs b/farms/fund/src/instructions/orca/vault_user_init.rs deleted file mode 100644 index 4c921863891..00000000000 --- a/farms/fund/src/instructions/orca/vault_user_init.rs +++ /dev/null @@ -1,81 +0,0 @@ -//! Init new user in the Orca Vault instruction - -use { - crate::{common, fund_info::FundInfo}, - solana_farm_sdk::{fund::Fund, instruction::vault::VaultInstruction}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke_signed, - program_error::ProgramError, - }, -}; - -pub fn user_init(fund: &Fund, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - admin_account, - fund_metadata, - fund_info_account, - fund_authority, - vault_program_id, - fund_vault_metadata, - vault_metadata, - vault_info_account, - _fund_wallet_account, - fund_vault_user_account, - system_program - ] = accounts - { - // validate accounts - msg!("Validate state and accounts"); - let fund_info = FundInfo::new(fund_info_account); - if fund_info.get_liquidation_start_time()? > 0 { - msg!("Error: Fund is in liquidation state"); - return Err(ProgramError::Custom(516)); - } - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - - common::check_unpack_target_vault( - &fund.fund_program_id, - vault_program_id.key, - fund_metadata.key, - vault_metadata.key, - fund_vault_metadata, - )?; - - // prepare instruction and call vault program - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - - let vault_accounts = vec![ - AccountMeta::new(*admin_account.key, true), - AccountMeta::new_readonly(*vault_metadata.key, false), - AccountMeta::new(*vault_info_account.key, false), - AccountMeta::new_readonly(*fund_authority.key, false), - AccountMeta::new(*fund_vault_user_account.key, false), - AccountMeta::new_readonly(*system_program.key, false), - ]; - - let instruction = Instruction { - program_id: *vault_program_id.key, - accounts: vault_accounts, - data: VaultInstruction::UserInit {}.to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/raydium/add_liquidity.rs b/farms/fund/src/instructions/raydium/add_liquidity.rs deleted file mode 100644 index 1e72c7ba343..00000000000 --- a/farms/fund/src/instructions/raydium/add_liquidity.rs +++ /dev/null @@ -1,119 +0,0 @@ -//! Add liquidity to the Raydium pool instruction - -use { - crate::{common, fund_info::FundInfo}, - solana_farm_sdk::{fund::Fund, instruction::amm::AmmInstruction, program::account}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke_signed, - program_error::ProgramError, - }, -}; - -pub fn add_liquidity( - fund: &Fund, - accounts: &[AccountInfo], - max_coin_token_amount: u64, - max_pc_token_amount: u64, -) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - fund_metadata, - fund_info_account, - fund_authority, - router_program_id, - fund_vault_metadata, - fund_token_a_account, - fund_token_b_account, - fund_lp_token_account, - pool_program_id, - pool_coin_token_account, - pool_pc_token_account, - lp_token_mint, - spl_token_id, - amm_id, - amm_authority, - amm_open_orders, - amm_target, - serum_market - ] = accounts - { - // validate params and accounts - msg!("Validate state and accounts"); - let fund_info = FundInfo::new(fund_info_account); - if fund_info.get_liquidation_start_time()? > 0 { - msg!("Error: Fund is in liquidation state"); - return Err(ProgramError::Custom(516)); - } - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - - let vault = common::check_unpack_target_vault( - &fund.fund_program_id, - router_program_id.key, - fund_metadata.key, - amm_id.key, - fund_vault_metadata, - )?; - - // prepare instruction and call raydium router - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - - let initial_lp_balance = account::get_token_balance(fund_lp_token_account)?; - - let raydium_accounts = vec![ - AccountMeta::new_readonly(*fund_authority.key, true), - AccountMeta::new(*fund_token_a_account.key, false), - AccountMeta::new(*fund_token_b_account.key, false), - AccountMeta::new(*fund_lp_token_account.key, false), - AccountMeta::new_readonly(*pool_program_id.key, false), - AccountMeta::new(*pool_coin_token_account.key, false), - AccountMeta::new(*pool_pc_token_account.key, false), - AccountMeta::new(*lp_token_mint.key, false), - AccountMeta::new_readonly(*spl_token_id.key, false), - AccountMeta::new(*amm_id.key, false), - AccountMeta::new_readonly(*amm_authority.key, false), - AccountMeta::new_readonly(*amm_open_orders.key, false), - AccountMeta::new(*amm_target.key, false), - AccountMeta::new_readonly(*serum_market.key, false), - ]; - - let instruction = Instruction { - program_id: *router_program_id.key, - accounts: raydium_accounts, - data: AmmInstruction::AddLiquidity { - max_token_a_amount: max_coin_token_amount, - max_token_b_amount: max_pc_token_amount, - } - .to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds)?; - - // update stats - msg!("Update vault balance"); - let lp_received = account::get_balance_increase(fund_lp_token_account, initial_lp_balance)?; - msg!( - "token_a_balance: {}, token_b_balance: {}, lp_received: {}", - account::get_token_balance(fund_token_a_account)?, - account::get_token_balance(fund_token_b_account)?, - lp_received - ); - common::increase_vault_balance(fund_vault_metadata, &vault, lp_received)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/raydium/mod.rs b/farms/fund/src/instructions/raydium/mod.rs deleted file mode 100644 index 18e1c60558f..00000000000 --- a/farms/fund/src/instructions/raydium/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub mod add_liquidity; -pub mod remove_liquidity; -pub mod stake; -pub mod swap; -pub mod unstake; -pub mod user_init; -pub mod vault_add_liquidity; -pub mod vault_lock_liquidity; -pub mod vault_remove_liquidity; -pub mod vault_unlock_liquidity; -pub mod vault_user_init; diff --git a/farms/fund/src/instructions/raydium/remove_liquidity.rs b/farms/fund/src/instructions/raydium/remove_liquidity.rs deleted file mode 100644 index f638edc2815..00000000000 --- a/farms/fund/src/instructions/raydium/remove_liquidity.rs +++ /dev/null @@ -1,123 +0,0 @@ -//! Remove liquidity from the Raydium pool instruction - -use { - crate::common, - solana_farm_sdk::{fund::Fund, instruction::amm::AmmInstruction, program::account}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke_signed, - program_error::ProgramError, - }, -}; - -pub fn remove_liquidity(fund: &Fund, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - fund_metadata, - _fund_info_account, - fund_authority, - router_program_id, - fund_vault_metadata, - fund_token_a_account, - fund_token_b_account, - fund_lp_token_account, - pool_program_id, - pool_withdraw_queue, - pool_temp_lp_token_account, - pool_coin_token_account, - pool_pc_token_account, - lp_token_mint, - spl_token_id, - amm_id, - amm_authority, - amm_open_orders, - amm_target, - serum_market, - serum_program_id, - serum_bids, - serum_asks, - serum_event_queue, - serum_coin_vault_account, - serum_pc_vault_account, - serum_vault_signer - ] = accounts - { - // validate params and accounts - msg!("Validate state and accounts"); - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - - let vault = common::check_unpack_target_vault( - &fund.fund_program_id, - router_program_id.key, - fund_metadata.key, - amm_id.key, - fund_vault_metadata, - )?; - - // prepare instruction and call raydium router - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - - let initial_lp_balance = account::get_token_balance(fund_lp_token_account)?; - - let raydium_accounts = vec![ - AccountMeta::new_readonly(*fund_authority.key, true), - AccountMeta::new(*fund_token_a_account.key, false), - AccountMeta::new(*fund_token_b_account.key, false), - AccountMeta::new(*fund_lp_token_account.key, false), - AccountMeta::new_readonly(*pool_program_id.key, false), - AccountMeta::new(*pool_withdraw_queue.key, false), - AccountMeta::new(*pool_temp_lp_token_account.key, false), - AccountMeta::new(*pool_coin_token_account.key, false), - AccountMeta::new(*pool_pc_token_account.key, false), - AccountMeta::new(*lp_token_mint.key, false), - AccountMeta::new_readonly(*spl_token_id.key, false), - AccountMeta::new(*amm_id.key, false), - AccountMeta::new_readonly(*amm_authority.key, false), - AccountMeta::new(*amm_open_orders.key, false), - AccountMeta::new(*amm_target.key, false), - AccountMeta::new(*serum_market.key, false), - AccountMeta::new_readonly(*serum_program_id.key, false), - AccountMeta::new(*serum_bids.key, false), - AccountMeta::new(*serum_asks.key, false), - AccountMeta::new(*serum_event_queue.key, false), - AccountMeta::new(*serum_coin_vault_account.key, false), - AccountMeta::new(*serum_pc_vault_account.key, false), - AccountMeta::new_readonly(*serum_vault_signer.key, false), - ]; - - let instruction = Instruction { - program_id: *router_program_id.key, - accounts: raydium_accounts, - data: AmmInstruction::RemoveLiquidity { amount }.to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds)?; - - // update stats - msg!("Update vault balance"); - let lp_removed = account::get_balance_decrease(fund_lp_token_account, initial_lp_balance)?; - msg!( - "token_a_balance: {}, token_b_balance: {}, lp_removed: {}", - account::get_token_balance(fund_token_a_account)?, - account::get_token_balance(fund_token_b_account)?, - lp_removed - ); - common::decrease_vault_balance(fund_vault_metadata, &vault, lp_removed)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/raydium/stake.rs b/farms/fund/src/instructions/raydium/stake.rs deleted file mode 100644 index 53c7b6e1214..00000000000 --- a/farms/fund/src/instructions/raydium/stake.rs +++ /dev/null @@ -1,109 +0,0 @@ -//! Stake LP tokens to a Raydium farm instruction - -use { - crate::{common, fund_info::FundInfo}, - solana_farm_sdk::{fund::Fund, instruction::amm::AmmInstruction, program::account}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke_signed, - program_error::ProgramError, - }, -}; - -pub fn stake(fund: &Fund, accounts: &[AccountInfo], amount: u64, harvest: bool) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - fund_metadata, - fund_info_account, - fund_authority, - router_program_id, - fund_vault_metadata, - fund_stake_info_account, - fund_lp_token_account, - fund_first_reward_token_account, - fund_second_reward_token_account, - farm_program_id, - farm_lp_token_account, - farm_first_reward_token_account, - farm_second_reward_token_account, - clock_id, - spl_token_id, - farm_id, - farm_authority - ] = accounts - { - // validate params and accounts - msg!("Validate state and accounts"); - if !harvest && FundInfo::new(fund_info_account).get_liquidation_start_time()? > 0 { - msg!("Error: Fund is in liquidation state"); - return Err(ProgramError::Custom(516)); - } - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - if account::is_empty(fund_stake_info_account)? { - msg!("Error: Fund stake info account must be initialized first"); - return Err(ProgramError::UninitializedAccount); - } - - common::check_unpack_target_vault( - &fund.fund_program_id, - router_program_id.key, - fund_metadata.key, - farm_id.key, - fund_vault_metadata, - )?; - - // prepare instruction and call raydium router - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - - let raydium_accounts = vec![ - AccountMeta::new_readonly(*fund_authority.key, true), - AccountMeta::new(*fund_stake_info_account.key, false), - AccountMeta::new(*fund_lp_token_account.key, false), - AccountMeta::new(*fund_first_reward_token_account.key, false), - AccountMeta::new(*fund_second_reward_token_account.key, false), - AccountMeta::new_readonly(*farm_program_id.key, false), - AccountMeta::new(*farm_lp_token_account.key, false), - AccountMeta::new(*farm_first_reward_token_account.key, false), - AccountMeta::new(*farm_second_reward_token_account.key, false), - AccountMeta::new_readonly(*clock_id.key, false), - AccountMeta::new_readonly(*spl_token_id.key, false), - AccountMeta::new(*farm_id.key, false), - AccountMeta::new_readonly(*farm_authority.key, false), - ]; - - let instruction = Instruction { - program_id: *router_program_id.key, - accounts: raydium_accounts, - data: if harvest { - AmmInstruction::Harvest.to_vec()? - } else { - AmmInstruction::Stake { amount }.to_vec()? - }, - }; - - invoke_signed(&instruction, accounts, seeds)?; - - msg!( - "reward_a_balance: {}, reward_b_balance: {}, lp_token_balance: {}", - account::get_token_balance(fund_first_reward_token_account)?, - account::get_token_balance(fund_second_reward_token_account)?, - account::get_token_balance(fund_lp_token_account)? - ); - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/raydium/swap.rs b/farms/fund/src/instructions/raydium/swap.rs deleted file mode 100644 index cee2dadb07a..00000000000 --- a/farms/fund/src/instructions/raydium/swap.rs +++ /dev/null @@ -1,145 +0,0 @@ -//! Swap tokens with the Raydium pool instruction - -use { - crate::{common, fund_info::FundInfo}, - solana_farm_sdk::{ - error::FarmError, - fund::Fund, - instruction::amm::AmmInstruction, - program, - program::{account, clock}, - }, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke_signed, - program_error::ProgramError, - }, -}; - -pub fn swap( - fund: &Fund, - accounts: &[AccountInfo], - token_a_amount_in: u64, - token_b_amount_in: u64, - min_token_amount_out: u64, -) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - fund_metadata, - fund_info_account, - fund_authority, - router_program_id, - fund_vault_metadata, - fund_token_a_account, - fund_token_b_account, - pool_program_id, - pool_coin_token_account, - pool_pc_token_account, - spl_token_program, - amm_id, - amm_authority, - amm_open_orders, - amm_target, - serum_market, - serum_program_id, - serum_bids, - serum_asks, - serum_event_queue, - serum_coin_vault_account, - serum_pc_vault_account, - serum_vault_signer, - sysvar_account - ] = accounts - { - // validate params and accounts - msg!("Validate state and accounts"); - let mut fund_info = FundInfo::new(fund_info_account); - if fund_info.get_liquidation_start_time()? > 0 { - let curtime = clock::get_time()?; - let last_trade_time = fund_info.get_last_trade_time()?; - if last_trade_time > 0 && curtime - last_trade_time < 300 { - msg!( - "Error: Too early for another swap, please retry in {} seconds", - 300 - curtime - last_trade_time - ); - return Err(FarmError::TooEarly.into()); - } - } - if !program::is_last_instruction(sysvar_account)? { - msg!("Error: Swap must be the last instruction in the transaction"); - return Err(ProgramError::InvalidArgument); - } - - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - - common::check_unpack_target_vault( - &fund.fund_program_id, - router_program_id.key, - fund_metadata.key, - amm_id.key, - fund_vault_metadata, - )?; - - // prepare instruction and call raydium router - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - - let raydium_accounts = vec![ - AccountMeta::new_readonly(*fund_authority.key, true), - AccountMeta::new(*fund_token_a_account.key, false), - AccountMeta::new(*fund_token_b_account.key, false), - AccountMeta::new_readonly(*pool_program_id.key, false), - AccountMeta::new(*pool_coin_token_account.key, false), - AccountMeta::new(*pool_pc_token_account.key, false), - AccountMeta::new_readonly(*spl_token_program.key, false), - AccountMeta::new(*amm_id.key, false), - AccountMeta::new_readonly(*amm_authority.key, false), - AccountMeta::new(*amm_open_orders.key, false), - AccountMeta::new(*amm_target.key, false), - AccountMeta::new(*serum_market.key, false), - AccountMeta::new_readonly(*serum_program_id.key, false), - AccountMeta::new(*serum_bids.key, false), - AccountMeta::new(*serum_asks.key, false), - AccountMeta::new(*serum_event_queue.key, false), - AccountMeta::new(*serum_coin_vault_account.key, false), - AccountMeta::new(*serum_pc_vault_account.key, false), - AccountMeta::new_readonly(*serum_vault_signer.key, false), - ]; - - let instruction = Instruction { - program_id: *router_program_id.key, - accounts: raydium_accounts, - data: AmmInstruction::Swap { - token_a_amount_in, - token_b_amount_in, - min_token_amount_out, - } - .to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds)?; - - msg!( - "token_a_balance: {}, token_b_balance: {}", - account::get_token_balance(fund_token_a_account)?, - account::get_token_balance(fund_token_b_account)? - ); - - // update fund stats - msg!("Update Fund stats"); - fund_info.update_last_trade_time() - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/raydium/unstake.rs b/farms/fund/src/instructions/raydium/unstake.rs deleted file mode 100644 index c4b9c6c0e16..00000000000 --- a/farms/fund/src/instructions/raydium/unstake.rs +++ /dev/null @@ -1,101 +0,0 @@ -//! Unstake LP tokens from a Raydium farm instruction - -use { - crate::common, - solana_farm_sdk::{fund::Fund, instruction::amm::AmmInstruction, program::account}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke_signed, - program_error::ProgramError, - }, -}; - -pub fn unstake(fund: &Fund, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - fund_metadata, - _fund_info_account, - fund_authority, - router_program_id, - fund_vault_metadata, - fund_stake_info_account, - fund_lp_token_account, - fund_first_reward_token_account, - fund_second_reward_token_account, - farm_program_id, - farm_lp_token_account, - farm_first_reward_token_account, - farm_second_reward_token_account, - clock_id, - spl_token_id, - farm_id, - farm_authority - ] = accounts - { - // validate params and accounts - msg!("Validate state and accounts"); - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - if account::is_empty(fund_stake_info_account)? { - msg!("Error: Fund stake info account must be initialized first"); - return Err(ProgramError::UninitializedAccount); - } - - common::check_unpack_target_vault( - &fund.fund_program_id, - router_program_id.key, - fund_metadata.key, - farm_id.key, - fund_vault_metadata, - )?; - - // prepare instruction and call raydium router - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - - let raydium_accounts = vec![ - AccountMeta::new_readonly(*fund_authority.key, true), - AccountMeta::new(*fund_stake_info_account.key, false), - AccountMeta::new(*fund_lp_token_account.key, false), - AccountMeta::new(*fund_first_reward_token_account.key, false), - AccountMeta::new(*fund_second_reward_token_account.key, false), - AccountMeta::new_readonly(*farm_program_id.key, false), - AccountMeta::new(*farm_lp_token_account.key, false), - AccountMeta::new(*farm_first_reward_token_account.key, false), - AccountMeta::new(*farm_second_reward_token_account.key, false), - AccountMeta::new_readonly(*clock_id.key, false), - AccountMeta::new_readonly(*spl_token_id.key, false), - AccountMeta::new(*farm_id.key, false), - AccountMeta::new_readonly(*farm_authority.key, false), - ]; - - let instruction = Instruction { - program_id: *router_program_id.key, - accounts: raydium_accounts, - data: AmmInstruction::Unstake { amount }.to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds)?; - - msg!( - "reward_a_balance: {}, reward_b_balance: {}, lp_token_balance: {}", - account::get_token_balance(fund_first_reward_token_account)?, - account::get_token_balance(fund_second_reward_token_account)?, - account::get_token_balance(fund_lp_token_account)? - ); - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/raydium/user_init.rs b/farms/fund/src/instructions/raydium/user_init.rs deleted file mode 100644 index b8ab19af212..00000000000 --- a/farms/fund/src/instructions/raydium/user_init.rs +++ /dev/null @@ -1,92 +0,0 @@ -//! Initialize a new user for a Raydium farm instruction - -use { - crate::{common, fund_info::FundInfo}, - solana_farm_sdk::{ - farm::{Farm, FarmRoute}, - fund::Fund, - id::main_router, - instruction::amm::AmmInstruction, - program::account, - }, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke, - program_error::ProgramError, - }, -}; - -pub fn user_init(fund: &Fund, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - admin_account, - fund_metadata, - fund_info_account, - fund_authority, - router_program_id, - fund_vault_metadata, - _fund_wallet_account, - fund_stake_info_account, - farm_metadata, - system_program - ] = accounts - { - // validate accounts - msg!("Validate state and accounts"); - let fund_info = FundInfo::new(fund_info_account); - if fund_info.get_liquidation_start_time()? > 0 { - msg!("Error: Fund is in liquidation state"); - return Err(ProgramError::Custom(516)); - } - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - - if farm_metadata.owner != &main_router::id() { - msg!("Error: Invalid Farm metadata owner"); - return Err(ProgramError::IllegalOwner); - } - let farm = account::unpack::(farm_metadata, "Farm")?; - let farm_id = match farm.route { - FarmRoute::Raydium { farm_id, .. } => farm_id, - _ => { - msg!("Error: Unsupported Farm route"); - return Err(ProgramError::Custom(537)); - } - }; - - common::check_unpack_target_vault( - &fund.fund_program_id, - router_program_id.key, - fund_metadata.key, - &farm_id, - fund_vault_metadata, - )?; - - // prepare instruction and call raydium router - let raydium_accounts = vec![ - AccountMeta::new(*admin_account.key, true), - AccountMeta::new_readonly(*fund_authority.key, false), - AccountMeta::new(*fund_stake_info_account.key, false), - AccountMeta::new_readonly(*farm_metadata.key, false), - AccountMeta::new_readonly(*system_program.key, false), - ]; - - let instruction = Instruction { - program_id: *router_program_id.key, - accounts: raydium_accounts, - data: AmmInstruction::UserInit {}.to_vec()?, - }; - - invoke(&instruction, accounts)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/raydium/vault_add_liquidity.rs b/farms/fund/src/instructions/raydium/vault_add_liquidity.rs deleted file mode 100644 index f3372a2eb61..00000000000 --- a/farms/fund/src/instructions/raydium/vault_add_liquidity.rs +++ /dev/null @@ -1,122 +0,0 @@ -//! Add liquidity to the Raydium Vault instruction - -use { - crate::{common, fund_info::FundInfo}, - solana_farm_sdk::{fund::Fund, instruction::vault::VaultInstruction, program::account}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke_signed, - program_error::ProgramError, - }, -}; - -pub fn add_liquidity( - fund: &Fund, - accounts: &[AccountInfo], - max_token_a_amount: u64, - max_token_b_amount: u64, -) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - fund_metadata, - fund_info_account, - fund_authority, - vault_program_id, - fund_vault_metadata, - vault_metadata, - vault_info_account, - spl_token_program, - fund_vault_user_account, - fund_token_a_custody, - fund_token_b_custody, - fund_lp_token_custody, - vault_lp_token_custody, - pool_program_id, - pool_coin_token_account, - pool_pc_token_account, - lp_token_mint, - amm_id, - amm_authority, - amm_open_orders, - amm_target, - serum_market - ] = accounts - { - // validate accounts - msg!("Validate state and accounts"); - let fund_info = FundInfo::new(fund_info_account); - if fund_info.get_liquidation_start_time()? > 0 { - msg!("Error: Fund is in liquidation state"); - return Err(ProgramError::Custom(516)); - } - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - - let vault = common::check_unpack_target_vault( - &fund.fund_program_id, - vault_program_id.key, - fund_metadata.key, - vault_metadata.key, - fund_vault_metadata, - )?; - - // prepare instruction and call vault program - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - - let initial_lp_balance = account::get_token_balance(vault_lp_token_custody)?; - - let vault_accounts = vec![ - AccountMeta::new_readonly(*fund_authority.key, true), - AccountMeta::new_readonly(*vault_metadata.key, false), - AccountMeta::new(*vault_info_account.key, false), - AccountMeta::new_readonly(*spl_token_program.key, false), - AccountMeta::new(*fund_vault_user_account.key, false), - AccountMeta::new(*fund_token_a_custody.key, false), - AccountMeta::new(*fund_token_b_custody.key, false), - AccountMeta::new(*fund_lp_token_custody.key, false), - AccountMeta::new(*vault_lp_token_custody.key, false), - AccountMeta::new_readonly(*pool_program_id.key, false), - AccountMeta::new(*pool_coin_token_account.key, false), - AccountMeta::new(*pool_pc_token_account.key, false), - AccountMeta::new(*lp_token_mint.key, false), - AccountMeta::new(*amm_id.key, false), - AccountMeta::new_readonly(*amm_authority.key, false), - AccountMeta::new_readonly(*amm_open_orders.key, false), - AccountMeta::new(*amm_target.key, false), - AccountMeta::new_readonly(*serum_market.key, false), - ]; - - let instruction = Instruction { - program_id: *vault_program_id.key, - accounts: vault_accounts, - data: VaultInstruction::AddLiquidity { - max_token_a_amount, - max_token_b_amount, - } - .to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds)?; - - // update stats - msg!("Update vault balance"); - let lp_received = - account::get_balance_increase(vault_lp_token_custody, initial_lp_balance)?; - common::increase_vault_balance(fund_vault_metadata, &vault, lp_received)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/raydium/vault_lock_liquidity.rs b/farms/fund/src/instructions/raydium/vault_lock_liquidity.rs deleted file mode 100644 index 4ba39b04c4f..00000000000 --- a/farms/fund/src/instructions/raydium/vault_lock_liquidity.rs +++ /dev/null @@ -1,107 +0,0 @@ -//! Lock liquidity in the Raydium Vault instruction - -use { - crate::{common, fund_info::FundInfo}, - solana_farm_sdk::{fund::Fund, instruction::vault::VaultInstruction}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke_signed, - program_error::ProgramError, - }, -}; - -pub fn lock_liquidity(fund: &Fund, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - fund_metadata, - fund_info_account, - fund_authority, - vault_program_id, - fund_vault_metadata, - vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - vault_token_mint, - fund_vault_user_account, - fund_vt_token_custody, - vault_token_a_reward_custody, - vault_token_b_reward_custody, - vault_lp_token_custody, - farm_program, - vault_stake_info, - farm_id, - farm_authority, - farm_lp_token_account, - farm_first_reward_token_account, - farm_second_reward_token_account, - clock_program - ] = accounts - { - // validate accounts - msg!("Validate state and accounts"); - let fund_info = FundInfo::new(fund_info_account); - if fund_info.get_liquidation_start_time()? > 0 { - msg!("Error: Fund is in liquidation state"); - return Err(ProgramError::Custom(516)); - } - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - - common::check_unpack_target_vault( - &fund.fund_program_id, - vault_program_id.key, - fund_metadata.key, - vault_metadata.key, - fund_vault_metadata, - )?; - - // prepare instruction and call vault program - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - - let vault_accounts = vec![ - AccountMeta::new_readonly(*fund_authority.key, true), - AccountMeta::new_readonly(*vault_metadata.key, false), - AccountMeta::new(*vault_info_account.key, false), - AccountMeta::new_readonly(*vault_authority.key, false), - AccountMeta::new_readonly(*spl_token_program.key, false), - AccountMeta::new(*vault_token_mint.key, false), - AccountMeta::new(*fund_vault_user_account.key, false), - AccountMeta::new(*fund_vt_token_custody.key, false), - AccountMeta::new(*vault_token_a_reward_custody.key, false), - AccountMeta::new(*vault_token_b_reward_custody.key, false), - AccountMeta::new(*vault_lp_token_custody.key, false), - AccountMeta::new_readonly(*farm_program.key, false), - AccountMeta::new(*vault_stake_info.key, false), - AccountMeta::new(*farm_id.key, false), - AccountMeta::new_readonly(*farm_authority.key, false), - AccountMeta::new(*farm_lp_token_account.key, false), - AccountMeta::new(*farm_first_reward_token_account.key, false), - AccountMeta::new(*farm_second_reward_token_account.key, false), - AccountMeta::new_readonly(*clock_program.key, false), - ]; - - let instruction = Instruction { - program_id: *vault_program_id.key, - accounts: vault_accounts, - data: VaultInstruction::LockLiquidity { amount }.to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/raydium/vault_remove_liquidity.rs b/farms/fund/src/instructions/raydium/vault_remove_liquidity.rs deleted file mode 100644 index e7d9d79099c..00000000000 --- a/farms/fund/src/instructions/raydium/vault_remove_liquidity.rs +++ /dev/null @@ -1,125 +0,0 @@ -//! Remove liquidity from the Raydium Vault instruction - -use { - crate::common, - solana_farm_sdk::{fund::Fund, instruction::vault::VaultInstruction, program::account}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke_signed, - program_error::ProgramError, - }, -}; - -pub fn remove_liquidity(fund: &Fund, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - fund_metadata, - _fund_info_account, - fund_authority, - vault_program_id, - fund_vault_metadata, - vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - fund_vault_user_account, - fund_token_a_custody, - fund_token_b_custody, - vault_lp_token_custody, - pool_program_id, - pool_withdraw_queue, - pool_temp_lp_token_account, - pool_coin_token_account, - pool_pc_token_account, - lp_token_mint, - amm_id, - amm_authority, - amm_open_orders, - amm_target, - serum_market, - serum_program_id, - serum_bids, - serum_asks, - serum_event_queue, - serum_coin_vault_account, - serum_pc_vault_account, - serum_vault_signer - ] = accounts - { - // validate accounts - msg!("Validate state and accounts"); - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - - let vault = common::check_unpack_target_vault( - &fund.fund_program_id, - vault_program_id.key, - fund_metadata.key, - vault_metadata.key, - fund_vault_metadata, - )?; - - // prepare instruction and call vault program - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - - let initial_lp_balance = account::get_token_balance(vault_lp_token_custody)?; - - let vault_accounts = vec![ - AccountMeta::new_readonly(*fund_authority.key, true), - AccountMeta::new_readonly(*vault_metadata.key, false), - AccountMeta::new(*vault_info_account.key, false), - AccountMeta::new_readonly(*vault_authority.key, false), - AccountMeta::new_readonly(*spl_token_program.key, false), - AccountMeta::new(*fund_vault_user_account.key, false), - AccountMeta::new(*fund_token_a_custody.key, false), - AccountMeta::new(*fund_token_b_custody.key, false), - AccountMeta::new(*vault_lp_token_custody.key, false), - AccountMeta::new_readonly(*pool_program_id.key, false), - AccountMeta::new(*pool_withdraw_queue.key, false), - AccountMeta::new(*pool_temp_lp_token_account.key, false), - AccountMeta::new(*pool_coin_token_account.key, false), - AccountMeta::new(*pool_pc_token_account.key, false), - AccountMeta::new(*lp_token_mint.key, false), - AccountMeta::new(*amm_id.key, false), - AccountMeta::new_readonly(*amm_authority.key, false), - AccountMeta::new(*amm_open_orders.key, false), - AccountMeta::new(*amm_target.key, false), - AccountMeta::new(*serum_market.key, false), - AccountMeta::new_readonly(*serum_program_id.key, false), - AccountMeta::new(*serum_bids.key, false), - AccountMeta::new(*serum_asks.key, false), - AccountMeta::new(*serum_event_queue.key, false), - AccountMeta::new(*serum_coin_vault_account.key, false), - AccountMeta::new(*serum_pc_vault_account.key, false), - AccountMeta::new_readonly(*serum_vault_signer.key, false), - ]; - - let instruction = Instruction { - program_id: *vault_program_id.key, - accounts: vault_accounts, - data: VaultInstruction::RemoveLiquidity { amount }.to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds)?; - - // update stats - msg!("Update vault balance"); - let lp_removed = account::get_balance_decrease(vault_lp_token_custody, initial_lp_balance)?; - common::decrease_vault_balance(fund_vault_metadata, &vault, lp_removed)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/raydium/vault_unlock_liquidity.rs b/farms/fund/src/instructions/raydium/vault_unlock_liquidity.rs deleted file mode 100644 index fe20e2ef03f..00000000000 --- a/farms/fund/src/instructions/raydium/vault_unlock_liquidity.rs +++ /dev/null @@ -1,102 +0,0 @@ -//! Unlock liquidity from the Raydium Vault instruction - -use { - crate::common, - solana_farm_sdk::{fund::Fund, instruction::vault::VaultInstruction}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke_signed, - program_error::ProgramError, - }, -}; - -pub fn unlock_liquidity(fund: &Fund, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - fund_metadata, - _fund_info_account, - fund_authority, - vault_program_id, - fund_vault_metadata, - vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - vault_token_mint, - fund_vault_user_account, - fund_vt_token_custody, - vault_token_a_reward_custody, - vault_token_b_reward_custody, - vault_lp_token_custody, - farm_program, - vault_stake_info, - farm_id, - farm_authority, - farm_lp_token_account, - farm_first_reward_token_account, - farm_second_reward_token_account, - clock_program - ] = accounts - { - // validate accounts - msg!("Validate state and accounts"); - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - - common::check_unpack_target_vault( - &fund.fund_program_id, - vault_program_id.key, - fund_metadata.key, - vault_metadata.key, - fund_vault_metadata, - )?; - - // prepare instruction and call vault program - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - - let vault_accounts = vec![ - AccountMeta::new_readonly(*fund_authority.key, true), - AccountMeta::new_readonly(*vault_metadata.key, false), - AccountMeta::new(*vault_info_account.key, false), - AccountMeta::new_readonly(*vault_authority.key, false), - AccountMeta::new_readonly(*spl_token_program.key, false), - AccountMeta::new(*vault_token_mint.key, false), - AccountMeta::new(*fund_vault_user_account.key, false), - AccountMeta::new(*fund_vt_token_custody.key, false), - AccountMeta::new(*vault_token_a_reward_custody.key, false), - AccountMeta::new(*vault_token_b_reward_custody.key, false), - AccountMeta::new(*vault_lp_token_custody.key, false), - AccountMeta::new_readonly(*farm_program.key, false), - AccountMeta::new(*vault_stake_info.key, false), - AccountMeta::new(*farm_id.key, false), - AccountMeta::new_readonly(*farm_authority.key, false), - AccountMeta::new(*farm_lp_token_account.key, false), - AccountMeta::new(*farm_first_reward_token_account.key, false), - AccountMeta::new(*farm_second_reward_token_account.key, false), - AccountMeta::new_readonly(*clock_program.key, false), - ]; - - let instruction = Instruction { - program_id: *vault_program_id.key, - accounts: vault_accounts, - data: VaultInstruction::UnlockLiquidity { amount }.to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/raydium/vault_user_init.rs b/farms/fund/src/instructions/raydium/vault_user_init.rs deleted file mode 100644 index 2e05a4d5652..00000000000 --- a/farms/fund/src/instructions/raydium/vault_user_init.rs +++ /dev/null @@ -1,81 +0,0 @@ -//! Init new user in the Raydium Vault instruction - -use { - crate::{common, fund_info::FundInfo}, - solana_farm_sdk::{fund::Fund, instruction::vault::VaultInstruction}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke_signed, - program_error::ProgramError, - }, -}; - -pub fn user_init(fund: &Fund, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - admin_account, - fund_metadata, - fund_info_account, - fund_authority, - vault_program_id, - fund_vault_metadata, - vault_metadata, - vault_info_account, - _fund_wallet_account, - fund_vault_user_account, - system_program - ] = accounts - { - // validate accounts - msg!("Validate state and accounts"); - let fund_info = FundInfo::new(fund_info_account); - if fund_info.get_liquidation_start_time()? > 0 { - msg!("Error: Fund is in liquidation state"); - return Err(ProgramError::Custom(516)); - } - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - - common::check_unpack_target_vault( - &fund.fund_program_id, - vault_program_id.key, - fund_metadata.key, - vault_metadata.key, - fund_vault_metadata, - )?; - - // prepare instruction and call vault program - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - - let vault_accounts = vec![ - AccountMeta::new(*admin_account.key, true), - AccountMeta::new_readonly(*vault_metadata.key, false), - AccountMeta::new(*vault_info_account.key, false), - AccountMeta::new_readonly(*fund_authority.key, false), - AccountMeta::new(*fund_vault_user_account.key, false), - AccountMeta::new_readonly(*system_program.key, false), - ]; - - let instruction = Instruction { - program_id: *vault_program_id.key, - accounts: vault_accounts, - data: VaultInstruction::UserInit {}.to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/remove_custody.rs b/farms/fund/src/instructions/remove_custody.rs deleted file mode 100644 index 17a236b428c..00000000000 --- a/farms/fund/src/instructions/remove_custody.rs +++ /dev/null @@ -1,113 +0,0 @@ -//! Fund RemoveCustody instruction handler - -use { - crate::{common, fund_info::FundInfo}, - solana_farm_sdk::{ - fund::{Fund, FundAssetType, FundCustodyType}, - program::{account, pda}, - token::Token, - traits::Packed, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn remove_custody( - fund: &Fund, - accounts: &[AccountInfo], - target_hash: u64, - custody_type: FundCustodyType, -) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - admin_account, - fund_metadata, - fund_info_account, - _active_multisig_account, - fund_multisig_account, - fund_authority, - _system_program, - _spl_token_program, - custodies_assets_info, - custody_account, - custody_fees_account, - custody_metadata, - custody_token_metadata - ] = accounts - { - // validate params and accounts - msg!("Validate state and accounts"); - let mut fund_info = FundInfo::new(fund_info_account); - if fund_info.get_liquidation_start_time()? > 0 { - msg!("Error: Fund is in liquidation state"); - return Err(ProgramError::Custom(516)); - } - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - - let custody_token = account::unpack::(custody_token_metadata, "custody token")?; - let is_vault_token = - custody_token.name.len() > 3 && ["LP.", "VT."].contains(&&custody_token.name[..3]); - common::check_custody_account( - &fund.fund_program_id, - fund_metadata.key, - &custody_token, - custody_token_metadata, - custody_metadata, - custody_type, - custody_account, - Some(custody_fees_account.key), - )?; - - if account::get_token_balance(custody_account)? > 0 || - account::get_token_balance(custody_fees_account)? > 0{ - msg!("Custody token accounts must be empty"); - return Err(ProgramError::Custom(539)); - } - - // close accounts - msg!("Close custody token accounts"); - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - pda::close_token_account_with_seeds(admin_account, custody_account, fund_authority, seeds)?; - - let seeds: &[&[&[u8]]] = &[&[ - b"multisig", - fund.name.as_bytes(), - &[fund.multisig_bump], - ]]; - pda::close_token_account_with_seeds(admin_account, custody_fees_account, fund_multisig_account, seeds)?; - - msg!("Close custody metadata account"); - account::close_system_account(admin_account, custody_metadata, &fund.fund_program_id)?; - - // if this is non-vault token custody then assets stats must be reset - if !is_vault_token { - // update assets tracking account - msg!("Update Fund assets account"); - let mut fund_assets = common::check_and_get_fund_assets_account( - fund, - custodies_assets_info, - FundAssetType::Custody, - )?; - fund_assets.current_hash = 0; - fund_assets.target_hash = target_hash; - fund_assets.cycle_start_time = 0; - fund_assets.cycle_end_time = 0; - fund_assets.pack(*custodies_assets_info.try_borrow_mut_data()?)?; - } - - // update fund stats - msg!("Update Fund stats"); - fund_info.update_admin_action_time() - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/remove_multisig.rs b/farms/fund/src/instructions/remove_multisig.rs deleted file mode 100644 index 0c5a3c1e47c..00000000000 --- a/farms/fund/src/instructions/remove_multisig.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! Fund RemoveMultisig instruction handler - -use { - crate::fund_info::FundInfo, - solana_farm_sdk::{fund::Fund, program::account}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn remove_multisig(fund: &Fund, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - admin_account, - _fund_metadata, - fund_info_account, - _active_multisig_account, - fund_multisig_account, - ] = accounts - { - msg!("Close multisig account"); - account::close_system_account(admin_account, fund_multisig_account, &fund.fund_program_id)?; - - // update fund stats - msg!("Update Fund stats"); - let mut fund_info = FundInfo::new(fund_info_account); - fund_info.update_admin_action_time() - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/remove_vault.rs b/farms/fund/src/instructions/remove_vault.rs deleted file mode 100644 index cbd0ed3bb58..00000000000 --- a/farms/fund/src/instructions/remove_vault.rs +++ /dev/null @@ -1,82 +0,0 @@ -//! Fund RemoveVault instruction handler - -use { - crate::{common, fund_info::FundInfo}, - solana_farm_sdk::{ - fund::{Fund, FundAssetType, FundVaultType}, - program::account, - traits::Packed, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn remove_vault( - fund: &Fund, - accounts: &[AccountInfo], - target_hash: u64, - vault_type: FundVaultType, -) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - admin_account, - fund_metadata, - fund_info_account, - _multisig_account, - fund_authority, - _system_program, - vaults_assets_info, - vault_metadata_account - ] = accounts - { - // validate params and accounts - msg!("Validate state and accounts"); - let mut fund_info = FundInfo::new(fund_info_account); - if fund_info.get_liquidation_start_time()? > 0 { - msg!("Error: Fund is in liquidation state"); - return Err(ProgramError::Custom(516)); - } - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - - common::check_vault_account( - &fund.fund_program_id, - fund_metadata, - vault_metadata_account, - vault_type, - )?; - - // close accounts - msg!("Close vault accounts"); - account::close_system_account( - admin_account, - vault_metadata_account, - &fund.fund_program_id, - )?; - - // update assets tracking account if vault is not a farm - if vault_type != FundVaultType::Farm { - msg!("Update Fund assets account"); - let mut fund_assets = common::check_and_get_fund_assets_account( - fund, - vaults_assets_info, - FundAssetType::Vault, - )?; - fund_assets.current_hash = 0; - fund_assets.target_hash = target_hash; - fund_assets.cycle_start_time = 0; - fund_assets.cycle_end_time = 0; - fund_assets.pack(*vaults_assets_info.try_borrow_mut_data()?)?; - } - - // update fund stats - msg!("Update Fund stats"); - fund_info.update_admin_action_time() - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/request_deposit.rs b/farms/fund/src/instructions/request_deposit.rs deleted file mode 100644 index 2ece2faf0a3..00000000000 --- a/farms/fund/src/instructions/request_deposit.rs +++ /dev/null @@ -1,268 +0,0 @@ -//! Request deposit to the Fund instruction handler - -use { - crate::{common, fund_info::FundInfo, user_info::UserInfo}, - solana_farm_sdk::{ - fund::{Fund, FundUserRequests}, - math, - program::{account, clock, pda}, - string::ArrayString64, - token::Token, - traits::Packed, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn request_deposit(fund: &Fund, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - fund_metadata, - fund_info_account, - fund_authority, - _spl_token_program, - fund_token_mint, - user_info_account, - user_requests_account, - user_deposit_token_account, - user_fund_token_account, - custody_account, - custody_fees_account, - custody_metadata, - custody_token_metadata, - oracle_account - ] = accounts - { - // return early if deposits are not allowed - msg!("Validate state and accounts"); - let mut fund_info = FundInfo::new(fund_info_account); - if !fund_info.is_deposit_allowed()? { - msg!("Error: Deposits to this Fund are not allowed at this time"); - return Err(ProgramError::Custom(220)); - } - // validate accounts - if !user_account.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - if !UserInfo::validate_account(fund, user_info_account, user_account.key) { - msg!("Error: Invalid user info account"); - return Err(ProgramError::Custom(140)); - } - if !account::check_token_account_owner(user_fund_token_account, user_account.key)? { - msg!("Error: Invalid Fund token account owner"); - return Err(ProgramError::IllegalOwner); - } - common::check_fund_token_mint(fund, fund_token_mint)?; - - let custody_token = account::unpack::(custody_token_metadata, "custody token")?; - common::check_wd_custody_accounts( - &fund.fund_program_id, - fund_metadata.key, - &custody_token, - custody_token_metadata, - user_deposit_token_account, - custody_account, - custody_fees_account, - custody_metadata, - oracle_account, - )?; - - let mut user_requests = - account::unpack::(user_requests_account, "user requests")?; - common::check_user_requests_account( - fund, - &custody_token, - &user_requests, - user_account, - user_requests_account, - )?; - - // check if there are any pending requests - if user_requests.withdrawal_request.amount != 0 { - msg!("Error: Pending withdrawal must be canceled first"); - return Err(ProgramError::Custom(528)); - } - if user_requests.deposit_request.amount != 0 { - msg!("Error: Pending deposit must be canceled first"); - return Err(ProgramError::Custom(529)); - } - - // compute deposit amount and fees - msg!("Compute deposit amount and fees"); - // if specified amount is zero compute it based on user's balance - let user_token_balance = account::get_token_balance(user_deposit_token_account)?; - let amount_with_fee = if amount == 0 { - user_token_balance - } else { - amount - }; - // 0 <= fund_fee <= 1 - let fund_fee = fund_info.get_deposit_fee()?; - let (fee_numerator, fee_denominator) = math::get_fee_parts(fund_fee); - let deposit_fee = math::checked_as_u64(math::checked_div( - math::checked_mul(amount_with_fee as u128, fee_numerator as u128)?, - fee_denominator as u128, - )?)?; - let deposit_amount = amount_with_fee.checked_sub(deposit_fee).unwrap(); - if deposit_amount == 0 || amount_with_fee > user_token_balance { - msg!("Error: Insufficient user funds"); - return Err(ProgramError::InsufficientFunds); - } - - // compute nominal value of deposited tokens and check against the limit - msg!("Compute assets value. amount_with_fee: {}", amount_with_fee); - let deposit_value_usd = account::get_asset_value_usd( - deposit_amount, - custody_token.decimals, - custody_token.oracle_type, - oracle_account, - fund_info.get_assets_max_price_error()?, - fund_info.get_assets_max_price_age_sec()?, - )?; - - // check for deposit limit - let deposit_limit = fund_info.get_deposit_max_amount_usd()?; - if deposit_limit > 0.0 && deposit_limit < deposit_value_usd { - msg!( - "Error: Deposit amount {} is over the limit {}", - deposit_value_usd, - deposit_limit - ); - return Err(ProgramError::Custom(221)); - } - let deposit_limit = fund_info.get_deposit_min_amount_usd()?; - if deposit_limit > 0.0 && deposit_limit > deposit_value_usd { - msg!( - "Error: Deposit amount {} is below the minimum {}", - deposit_value_usd, - deposit_limit - ); - return Err(ProgramError::Custom(221)); - } - - if !fund_info.is_deposit_approval_required()? { - // if no approval required try to perform deposit instantly - msg!( - "Deposit tokens into custody. deposit_amount: {}, deposit_value_usd: {}", - deposit_amount, - deposit_value_usd - ); - - // check for total asset amount limit - common::check_assets_limit_usd(&fund_info, deposit_value_usd)?; - - // check if last assets update was not too long ago, - // stale value may lead to incorrect amount of fund tokens minted - common::check_assets_update_time( - fund_info.get_assets_update_time()?, - fund_info.get_assets_max_update_age_sec()?, - )?; - - // transfer funds - account::transfer_tokens( - user_deposit_token_account, - custody_account, - user_account, - deposit_amount, - )?; - if deposit_fee > 0 { - account::transfer_tokens( - user_deposit_token_account, - custody_fees_account, - user_account, - deposit_fee, - )?; - } - - // mint Fund tokens to user - let current_assets_usd = fund_info.get_current_assets_usd()?; - let ft_supply_amount = common::get_fund_token_supply(fund_token_mint, &fund_info)?; - let ft_to_mint = common::get_fund_token_to_mint_amount( - current_assets_usd, - deposit_amount, - deposit_value_usd, - ft_supply_amount, - )?; - msg!( - "Mint Fund tokens to the user. ft_to_mint: {}, ft_supply_amount: {}, current_assets_usd: {}", - ft_to_mint, ft_supply_amount, - current_assets_usd - ); - if ft_to_mint == 0 { - msg!("Error: Deposit instruction didn't result in Fund tokens mint"); - return Err(ProgramError::Custom(170)); - } - - if fund_info.get_issue_virtual_tokens()? { - let mut user_info = UserInfo::new(user_info_account); - user_info.set_virtual_tokens_balance(math::checked_add( - user_info.get_virtual_tokens_balance()?, - ft_to_mint, - )?)?; - fund_info.set_virtual_tokens_supply(math::checked_add( - fund_info.get_virtual_tokens_supply()?, - ft_to_mint, - )?)?; - } else { - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - pda::mint_to_with_seeds( - user_fund_token_account, - fund_token_mint, - fund_authority, - seeds, - ft_to_mint, - )?; - } - - // update stats - msg!("Update Fund stats"); - fund_info.set_amount_invested_usd( - fund_info.get_amount_invested_usd()? + deposit_value_usd, - )?; - fund_info.set_current_assets_usd(current_assets_usd + deposit_value_usd)?; - - msg!("Update user stats"); - user_requests.last_deposit.time = clock::get_time()?; - user_requests.last_deposit.amount = amount_with_fee; - user_requests.deposit_request.time = 0; - user_requests.deposit_request.amount = 0; - } else { - // if approval is required then we record the Fund authority as a delegate - // for the specified token amount to have tokens deposited later upon approval - msg!( - "Approve Fund as a delegate for {} tokens. deposit_value_usd: {}", - amount_with_fee, - deposit_value_usd - ); - account::approve_delegate( - user_deposit_token_account, - fund_authority, - user_account, - amount_with_fee, - )?; - - // update stats - user_requests.deposit_request.time = clock::get_time()?; - user_requests.deposit_request.amount = amount_with_fee; - } - - // update stats - user_requests.deny_reason = ArrayString64::default(); - user_requests.pack(*user_requests_account.try_borrow_mut_data()?)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/request_withdrawal.rs b/farms/fund/src/instructions/request_withdrawal.rs deleted file mode 100644 index 6686ad483d2..00000000000 --- a/farms/fund/src/instructions/request_withdrawal.rs +++ /dev/null @@ -1,292 +0,0 @@ -//! Request withdrawal from the Fund instruction handler - -use { - crate::{common, fund_info::FundInfo, user_info::UserInfo}, - solana_farm_sdk::{ - fund::{Fund, FundUserRequests}, - math, - program::{account, clock, pda}, - string::ArrayString64, - token::Token, - traits::Packed, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn request_withdrawal(fund: &Fund, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - fund_metadata, - fund_info_account, - fund_authority, - _spl_token_program, - fund_token_mint, - user_info_account, - user_requests_account, - user_withdrawal_token_account, - user_fund_token_account, - custody_account, - custody_fees_account, - custody_metadata, - custody_token_metadata, - oracle_account - ] = accounts - { - // return early if withdrawals are not allowed - msg!("Validate state and accounts"); - let mut fund_info = FundInfo::new(fund_info_account); - let liquidation = fund_info.get_liquidation_start_time()? > 0; - if !liquidation && !fund_info.is_withdrawal_allowed()? { - msg!("Error: Withdrawals from this Fund are not allowed at this time"); - return Err(ProgramError::Custom(224)); - } - // validate accounts - if !user_account.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - if !UserInfo::validate_account(fund, user_info_account, user_account.key) { - msg!("Error: Invalid user info account"); - return Err(ProgramError::Custom(140)); - } - if !account::check_token_account_owner(user_withdrawal_token_account, user_account.key)? { - msg!("Error: Invalid withdrawal destination account owner"); - return Err(ProgramError::IllegalOwner); - } - common::check_fund_token_mint(fund, fund_token_mint)?; - - let custody_token = account::unpack::(custody_token_metadata, "custody token")?; - common::check_wd_custody_accounts( - &fund.fund_program_id, - fund_metadata.key, - &custody_token, - custody_token_metadata, - user_withdrawal_token_account, - custody_account, - custody_fees_account, - custody_metadata, - oracle_account, - )?; - - let mut user_requests = account::unpack::(user_requests_account, "user requests")?; - common::check_user_requests_account( - fund, - &custody_token, - &user_requests, - user_account, - user_requests_account, - )?; - - // check if there are any pending requests - if user_requests.withdrawal_request.amount != 0 { - msg!("Error: Pending withdrawal must be canceled first"); - return Err(ProgramError::Custom(528)); - } - if user_requests.deposit_request.amount != 0 { - msg!("Error: Pending deposit must be canceled first"); - return Err(ProgramError::Custom(529)); - } - - // compute withdrawal amount - msg!("Compute withdrawal amount"); - // if specified amount is zero compute it based on user's balance - let mut user_info = UserInfo::new(user_info_account); - let user_fund_token_balance = - common::get_fund_token_balance(user_fund_token_account, &user_info)?; - let amount_with_fee = if amount == 0 { - user_fund_token_balance - } else { - amount - }; - if amount_with_fee == 0 || amount_with_fee > user_fund_token_balance { - msg!("Error: Insufficient user funds"); - return Err(ProgramError::InsufficientFunds); - } - - // check if last assets update was not too long ago, - // stale value may lead to incorrect amount of tokens received - common::check_assets_update_time( - fund_info.get_assets_update_time()?, - fund_info.get_assets_max_update_age_sec()?, - )?; - - // compute nominal value of withdrawn tokens and check against the limit - msg!("Compute assets value. amount_with_fee: {}", amount_with_fee); - let ft_supply_amount = common::get_fund_token_supply(fund_token_mint, &fund_info)?; - if amount_with_fee > ft_supply_amount { - msg!("Error: Insufficient Fund supply amount"); - return Err(ProgramError::InsufficientFunds); - } - // ft_supply_amount > 0 - let withdrawal_value_usd = - fund_info.get_current_assets_usd()? * amount_with_fee as f64 / ft_supply_amount as f64; - - // check for withdrawal limit - let withdrawal_limit = fund_info.get_withdrawal_max_amount_usd()?; - if !liquidation && withdrawal_limit > 0.0 && withdrawal_limit < withdrawal_value_usd { - msg!( - "Error: Withdrawal amount {} is over the limit {}", - withdrawal_value_usd, - withdrawal_limit - ); - return Err(ProgramError::Custom(225)); - } - let withdrawal_limit = fund_info.get_withdrawal_min_amount_usd()?; - if !liquidation && withdrawal_limit > 0.0 && withdrawal_limit > withdrawal_value_usd { - msg!( - "Error: Withdrawal amount {} is below the minimum {}", - withdrawal_value_usd, - withdrawal_limit - ); - return Err(ProgramError::Custom(225)); - } - - if liquidation || !fund_info.is_withdrawal_approval_required()? { - // if no approval required try to perform withdrawal instantly - - // compute tokens to transfer - msg!( - "Compute tokens to transfer. withdrawal_value_usd: {}", - withdrawal_value_usd - ); - let tokens_to_remove = account::get_asset_value_tokens( - withdrawal_value_usd, - custody_token.decimals, - custody_token.oracle_type, - oracle_account, - fund_info.get_assets_max_price_error()?, - fund_info.get_assets_max_price_age_sec()?, - )?; - // 0 <= fund_fee <= 1 - let fund_fee = if liquidation { - 0.0 - } else { - fund_info.get_withdrawal_fee()? - }; - let (fee_numerator, fee_denominator) = math::get_fee_parts(fund_fee); - let fee_tokens = math::checked_as_u64(math::checked_div( - math::checked_mul(tokens_to_remove as u128, fee_numerator as u128)?, - fee_denominator as u128, - )?)?; - let tokens_to_tranfer = math::checked_sub(tokens_to_remove, fee_tokens)?; - if tokens_to_tranfer == 0 { - msg!("Error: Withdrawal amount is too small"); - return Err(ProgramError::InsufficientFunds); - } - - let custody_balance = account::get_token_balance(custody_account)?; - if tokens_to_remove > custody_balance { - msg!("Error: Withdrawal for this amount couldn't be completed at this time. Contact Fund administrator."); - return Err(ProgramError::InsufficientFunds); - } - - // transfer tokens from custody to the user - msg!( - "Transfer tokens to user wallet. tokens_to_tranfer: {}, fee_tokens: {}", - tokens_to_tranfer, - fee_tokens, - ); - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - pda::transfer_tokens_with_seeds( - custody_account, - user_withdrawal_token_account, - fund_authority, - seeds, - tokens_to_tranfer, - )?; - if fee_tokens > 0 { - pda::transfer_tokens_with_seeds( - custody_account, - custody_fees_account, - fund_authority, - seeds, - fee_tokens, - )?; - } - - // burn Fund tokens from user - msg!("Burn Fund tokens from the user"); - let (amount_to_burn, amount_to_reduce) = if fund_info.get_issue_virtual_tokens()? { - let token_balance = account::get_token_balance(user_fund_token_account)?; - let amount_to_burn = std::cmp::min(amount_with_fee, token_balance); - let amount_to_reduce = math::checked_sub(amount_with_fee, amount_to_burn)?; - (amount_to_burn, amount_to_reduce) - } else { - let amount_to_reduce = - std::cmp::min(amount_with_fee, user_info.get_virtual_tokens_balance()?); - let amount_to_burn = math::checked_sub(amount_with_fee, amount_to_reduce)?; - (amount_to_burn, amount_to_reduce) - }; - account::burn_tokens( - user_fund_token_account, - fund_token_mint, - user_account, - amount_to_burn, - )?; - user_info.set_virtual_tokens_balance(math::checked_sub( - user_info.get_virtual_tokens_balance()?, - amount_to_reduce, - )?)?; - fund_info.set_virtual_tokens_supply(math::checked_sub( - fund_info.get_virtual_tokens_supply()?, - amount_to_reduce, - )?)?; - - // update stats - msg!("Update Fund stats"); - let current_assets_usd = fund_info.get_current_assets_usd()?; - let new_assets = if current_assets_usd > withdrawal_value_usd { - current_assets_usd - withdrawal_value_usd - } else { - 0.0 - }; - fund_info.set_amount_removed_usd( - fund_info.get_amount_removed_usd()? + withdrawal_value_usd, - )?; - fund_info.set_current_assets_usd(new_assets)?; - - msg!("Update user stats"); - user_requests.last_withdrawal.time = clock::get_time()?; - user_requests.last_withdrawal.amount = amount_with_fee; - user_requests.withdrawal_request.time = 0; - user_requests.withdrawal_request.amount = 0; - } else { - // if approval is required then we record the Fund authority as a delegate - // for the specified token amount to have tokens withdrawn later upon approval - msg!( - "Approve Fund as a delegate for {} Fund tokens. withdrawal_value_usd: {}", - amount_with_fee, - withdrawal_value_usd - ); - account::approve_delegate( - user_fund_token_account, - fund_authority, - user_account, - amount_with_fee, - )?; - - // update stats - user_requests.withdrawal_request.time = clock::get_time()?; - user_requests.withdrawal_request.amount = amount_with_fee; - } - - // update stats - user_requests.deny_reason = ArrayString64::default(); - user_requests.pack(*user_requests_account.try_borrow_mut_data()?)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/set_admin_signers.rs b/farms/fund/src/instructions/set_admin_signers.rs deleted file mode 100644 index bf5e86cbae4..00000000000 --- a/farms/fund/src/instructions/set_admin_signers.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! Set admin signers instruction handler - -use { - crate::fund_info::FundInfo, - solana_farm_sdk::{ - error::FarmError, - fund::Fund, - program::{account, multisig, multisig::Multisig, pda}, - }, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - }, -}; - -pub fn set_admin_signers( - fund: &Fund, - accounts: &[AccountInfo], - min_signatures: u8, -) -> ProgramResult { - msg!("Validate state and accounts"); - let accounts_iter = &mut accounts.iter(); - - let signer_account = next_account_info(accounts_iter)?; - let _fund_metadata = next_account_info(accounts_iter)?; - let fund_info_account = next_account_info(accounts_iter)?; - let _active_multisig_account = next_account_info(accounts_iter)?; - let fund_multisig_account = next_account_info(accounts_iter)?; - let _system_program = next_account_info(accounts_iter)?; - - if fund_multisig_account.key != &fund.multisig_account { - msg!("Error: Invalid fund multisig account"); - return Err(FarmError::IncorrectAccountAddress.into()); - } - - if account::is_empty(fund_multisig_account)? { - msg!("Init multisig account"); - let seeds: &[&[u8]] = &[b"multisig", fund.name.as_bytes()]; - let _bump = pda::init_system_account( - signer_account, - fund_multisig_account, - &fund.fund_program_id, - &fund.fund_program_id, - seeds, - Multisig::LEN, - )?; - } else { - msg!("Update multisig account"); - } - multisig::set_signers( - fund_multisig_account, - accounts_iter.as_slice(), - min_signatures, - )?; - - // update fund stats - msg!("Update Fund stats"); - let mut fund_info = FundInfo::new(fund_info_account); - fund_info.update_admin_action_time() -} diff --git a/farms/fund/src/instructions/set_assets_tracking_config.rs b/farms/fund/src/instructions/set_assets_tracking_config.rs deleted file mode 100644 index c359b0ccccf..00000000000 --- a/farms/fund/src/instructions/set_assets_tracking_config.rs +++ /dev/null @@ -1,24 +0,0 @@ -//! Fund SetDepositSchedule instruction handler - -use { - crate::fund_info::FundInfo, - solana_farm_sdk::fund::{Fund, FundAssetsTrackingConfig}, - solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, msg}, -}; - -pub fn set_assets_tracking_config( - _fund: &Fund, - fund_info: &mut FundInfo, - _accounts: &[AccountInfo], - config: &FundAssetsTrackingConfig, -) -> ProgramResult { - msg!("Update Fund assets tracking parameters"); - fund_info.set_assets_limit_usd(config.assets_limit_usd)?; - fund_info.set_assets_max_update_age_sec(config.max_update_age_sec)?; - fund_info.set_assets_max_price_error(config.max_price_error)?; - fund_info.set_assets_max_price_age_sec(config.max_price_age_sec)?; - fund_info.set_issue_virtual_tokens(config.issue_virtual_tokens)?; - - msg!("Update Fund stats"); - fund_info.update_admin_action_time() -} diff --git a/farms/fund/src/instructions/set_deposit_schedule.rs b/farms/fund/src/instructions/set_deposit_schedule.rs deleted file mode 100644 index 601b07cb6e6..00000000000 --- a/farms/fund/src/instructions/set_deposit_schedule.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! Fund SetDepositSchedule instruction handler - -use { - crate::fund_info::FundInfo, - solana_farm_sdk::fund::{Fund, FundSchedule}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn set_deposit_schedule( - _fund: &Fund, - fund_info: &mut FundInfo, - _accounts: &[AccountInfo], - schedule: &FundSchedule, -) -> ProgramResult { - msg!("Update Fund deposit parameters"); - if schedule.start_time >= schedule.end_time { - msg!("Error: start_time must be less than end_time"); - return Err(ProgramError::Custom(514)); - } - - fund_info.set_deposit_start_time(schedule.start_time)?; - fund_info.set_deposit_end_time(schedule.end_time)?; - fund_info.set_deposit_approval_required(schedule.approval_required)?; - fund_info.set_deposit_min_amount_usd(schedule.min_amount_usd)?; - fund_info.set_deposit_max_amount_usd(schedule.max_amount_usd)?; - fund_info.set_deposit_fee(schedule.fee) -} diff --git a/farms/fund/src/instructions/set_withdrawal_schedule.rs b/farms/fund/src/instructions/set_withdrawal_schedule.rs deleted file mode 100644 index b63f9a3822c..00000000000 --- a/farms/fund/src/instructions/set_withdrawal_schedule.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! Fund SetWithdrawalSchedule instruction handler - -use { - crate::fund_info::FundInfo, - solana_farm_sdk::fund::{Fund, FundSchedule}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn set_withdrawal_schedule( - _fund: &Fund, - fund_info: &mut FundInfo, - _accounts: &[AccountInfo], - schedule: &FundSchedule, -) -> ProgramResult { - msg!("Update Fund withdrawal parameters"); - if schedule.start_time >= schedule.end_time { - msg!("Error: start_time must be less than end_time"); - return Err(ProgramError::Custom(514)); - } - - fund_info.set_withdrawal_start_time(schedule.start_time)?; - fund_info.set_withdrawal_end_time(schedule.end_time)?; - fund_info.set_withdrawal_approval_required(schedule.approval_required)?; - fund_info.set_withdrawal_min_amount_usd(schedule.min_amount_usd)?; - fund_info.set_withdrawal_max_amount_usd(schedule.max_amount_usd)?; - fund_info.set_withdrawal_fee(schedule.fee) -} diff --git a/farms/fund/src/instructions/start_liquidation.rs b/farms/fund/src/instructions/start_liquidation.rs deleted file mode 100644 index bf180664df6..00000000000 --- a/farms/fund/src/instructions/start_liquidation.rs +++ /dev/null @@ -1,87 +0,0 @@ -//! Fund StartLiquidation instruction handler - -use { - crate::{common, fund_info::FundInfo, user_info::UserInfo}, - solana_farm_sdk::{ - fund::Fund, - program, - program::{account, clock}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn start_liquidation(fund: &Fund, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - _fund_metadata, - fund_info_account, - fund_token_mint, - user_info_account, - user_fund_token_account, - sysvar_account - ] = accounts - { - // validate accounts - msg!("Validate state and accounts"); - let mut fund_info = FundInfo::new(fund_info_account); - if fund_info.get_liquidation_start_time()? > 0 { - msg!("Error: Fund is already in liquidation state"); - return Err(ProgramError::Custom(516)); - } - if !user_account.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - if !UserInfo::validate_account(fund, user_info_account, user_account.key) { - msg!("Error: Invalid user info account"); - return Err(ProgramError::Custom(140)); - } - if !account::check_token_account_owner(user_fund_token_account, user_account.key)? { - msg!("Error: Invalid Fund token account owner"); - return Err(ProgramError::IllegalOwner); - } - common::check_fund_token_mint(fund, fund_token_mint)?; - - if !program::is_single_instruction(sysvar_account)? { - msg!("Error: StartLiquidation must be single instruction in the transaction"); - return Err(ProgramError::InvalidArgument); - } - - // check if liquidation can be started at this time - let ft_supply_amount = common::get_fund_token_supply(fund_token_mint, &fund_info)?; - let last_admin_action_time = fund_info.get_admin_action_time()?; - let user_info = UserInfo::new(user_info_account); - let curtime = clock::get_time()?; - #[allow(clippy::if_same_then_else)] - let allowed = - // check if user is roughly >= 60% stake holder - if ft_supply_amount > 0 - && common::get_fund_token_balance(user_fund_token_account, &user_info)? as f64 / ft_supply_amount as f64 >= 0.6 - { - true - } - // check if no admin activity in the past 2 weeks - else { - last_admin_action_time > 0 && curtime - last_admin_action_time >= 1209600 - }; - - if !allowed { - msg!("Error: Liquidation can be started if no admin actions performed in the next {} seconds", 1209600i64 - curtime + last_admin_action_time); - msg!("Error: Liquidation can also be started by Fund admin or user with >= 60% stake"); - return Err(ProgramError::Custom(519)); - } - - // start liquidation - msg!("Initiate liquidation"); - fund_info.set_liquidation_start_time(curtime)?; - fund_info.set_liquidation_amount_usd(fund_info.get_current_assets_usd()?)?; - fund_info.set_liquidation_amount_tokens(ft_supply_amount)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/stop_liquidation.rs b/farms/fund/src/instructions/stop_liquidation.rs deleted file mode 100644 index c13a86b7574..00000000000 --- a/farms/fund/src/instructions/stop_liquidation.rs +++ /dev/null @@ -1,36 +0,0 @@ -//! Fund StopLiquidation instruction handler - -use { - crate::fund_info::FundInfo, - solana_farm_sdk::fund::Fund, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn stop_liquidation(_fund: &Fund, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - _fund_metadata, - fund_info_account, - _active_multisig_account - ] = accounts - { - // validate accounts - msg!("Validate state and accounts"); - let mut fund_info = FundInfo::new(fund_info_account); - if fund_info.get_liquidation_start_time()? == 0 { - msg!("Error: Fund is not in liquidation state"); - return Err(ProgramError::Custom(518)); - } - - // stop liquidation - msg!("Stop liquidation"); - fund_info.set_liquidation_start_time(0)?; - fund_info.update_admin_action_time() - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/unlock_assets.rs b/farms/fund/src/instructions/unlock_assets.rs deleted file mode 100644 index 03dfa6dd08d..00000000000 --- a/farms/fund/src/instructions/unlock_assets.rs +++ /dev/null @@ -1,92 +0,0 @@ -//! Move funds from trading to withdrawal custody instruction handler - -use { - crate::common, - solana_farm_sdk::{ - fund::{Fund, FundCustodyType}, - program::{account, pda}, - token::Token, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn unlock_assets(fund: &Fund, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - fund_metadata, - _fund_info_account, - _multisig_account, - fund_authority, - _spl_token_program, - wd_custody_account, - wd_custody_metadata, - trading_custody_account, - trading_custody_metadata, - custody_token_metadata - ] = accounts - { - // validate params and accounts - msg!("Validate state and accounts"); - if fund_authority.key != &fund.fund_authority { - msg!("Error: Invalid Fund authority account"); - return Err(ProgramError::Custom(517)); - } - - let custody_token = account::unpack::(custody_token_metadata, "custody token")?; - common::check_custody_account( - &fund.fund_program_id, - fund_metadata.key, - &custody_token, - custody_token_metadata, - wd_custody_metadata, - FundCustodyType::DepositWithdraw, - wd_custody_account, - None, - )?; - common::check_custody_account( - &fund.fund_program_id, - fund_metadata.key, - &custody_token, - custody_token_metadata, - trading_custody_metadata, - FundCustodyType::Trading, - trading_custody_account, - None, - )?; - - // check if there are funds in w/d custody - let trading_custody_balance = account::get_token_balance(trading_custody_account)?; - let amount = if amount > 0 { - amount - } else { - trading_custody_balance - }; - if amount == 0 || amount < trading_custody_balance { - msg!("Error: Not enough funds in trading custody"); - return Err(ProgramError::Custom(530)); - } - - // trandsfer tokens from trading to w/d custody - msg!("Transfer funds to w/d custody"); - let seeds: &[&[&[u8]]] = &[&[ - b"fund_authority", - fund.name.as_bytes(), - &[fund.authority_bump], - ]]; - pda::transfer_tokens_with_seeds( - trading_custody_account, - wd_custody_account, - fund_authority, - seeds, - amount, - )?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/update_assets_with_custody.rs b/farms/fund/src/instructions/update_assets_with_custody.rs deleted file mode 100644 index af082b9390b..00000000000 --- a/farms/fund/src/instructions/update_assets_with_custody.rs +++ /dev/null @@ -1,130 +0,0 @@ -//! Update Fund assets with custody balance instruction handler - -use { - crate::{common, fund_info::FundInfo}, - solana_farm_sdk::{ - fund::{Fund, FundAssetType, FundCustody}, - id::zero, - math, - program::{account, clock}, - token::Token, - traits::Packed, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn update_assets_with_custody(fund: &Fund, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _user_account, - fund_metadata, - fund_info_account, - custodies_assets_info, - vaults_assets_info, - custody_account, - custody_metadata, - custody_token_metadata, - oracle_account - ] = accounts - { - // validate params and accounts - msg!("Validate state and accounts"); - let mut fund_info = FundInfo::new(fund_info_account); - if fund_info.get_liquidation_start_time()? > 0 { - msg!("Error: Fund is in liquidation state"); - return Err(ProgramError::Custom(516)); - } - - let custody_token = account::unpack::(custody_token_metadata, "custody token")?; - let custody = account::unpack::(custody_metadata, "custody")?; - if custody.is_vault_token { - msg!("Nothing to do: Custody is for vault tokens and must be processed with UpdateAssetsWithVault"); - return Ok(()); - } - common::check_custody_account( - &fund.fund_program_id, - fund_metadata.key, - &custody_token, - custody_token_metadata, - custody_metadata, - custody.custody_type, - custody_account, - None, - )?; - - if oracle_account.key != &custody_token.oracle_account.unwrap_or_else(zero::id) { - msg!("Error: Invalid oracle account"); - return Err(ProgramError::Custom(531)); - } - - // update assets tracking account - msg!("Update Fund assets account"); - let mut fund_custodies_assets = common::check_and_get_fund_assets_account( - fund, - custodies_assets_info, - FundAssetType::Custody, - )?; - - if fund_custodies_assets.target_hash == 0 { - msg!("Error: target_hash is 0. Custodies must be added before updating assets."); - return Err(ProgramError::InvalidAccountData); - } else if custody.custody_id == 0 { - fund_custodies_assets.current_hash = 0; - fund_custodies_assets.current_assets_usd = 0.0; - fund_custodies_assets.current_cycle = - math::checked_add(fund_custodies_assets.current_cycle, 1)?; - fund_custodies_assets.cycle_start_time = clock::get_time()?; - fund_custodies_assets.cycle_end_time = 0; - } else if fund_custodies_assets.cycle_end_time != 0 { - msg!("Error: Cycle has already ended. To reset start with custody_id 0."); - return Err(ProgramError::InvalidAccountData); - } - - // update running hash of processed custodies - // this mechanism is used to verify that all custodies have been processed - // before final number is recorded - fund_custodies_assets.current_hash = - math::hash_address(fund_custodies_assets.current_hash, custody_account.key); - - // update current assets value in usd - fund_custodies_assets.current_assets_usd += account::get_asset_value_usd( - account::get_token_balance(custody_account)?, - custody_token.decimals, - custody_token.oracle_type, - oracle_account, - fund_info.get_assets_max_price_error()?, - fund_info.get_assets_max_price_age_sec()?, - )?; - - // check if all custodies have been processed - if fund_custodies_assets.current_hash == fund_custodies_assets.target_hash { - fund_custodies_assets.cycle_end_time = clock::get_time()?; - - // if all vaults have been processed as well the cycle is complete - let fund_vaults_assets = common::check_and_get_fund_assets_account( - fund, - vaults_assets_info, - FundAssetType::Vault, - )?; - - if fund_vaults_assets.cycle_end_time != 0 || fund_vaults_assets.target_hash == 0 { - // update fund stats - msg!("Update Fund stats"); - fund_info.set_current_assets_usd( - fund_custodies_assets.current_assets_usd - + fund_vaults_assets.current_assets_usd, - )?; - fund_info.set_assets_update_time(clock::get_time()?)?; - } - } - - fund_custodies_assets.pack(*custodies_assets_info.try_borrow_mut_data()?)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/update_assets_with_vault.rs b/farms/fund/src/instructions/update_assets_with_vault.rs deleted file mode 100644 index eb051ce24b7..00000000000 --- a/farms/fund/src/instructions/update_assets_with_vault.rs +++ /dev/null @@ -1,246 +0,0 @@ -//! Update Fund assets with Vault balance instruction handler - -use { - crate::{common, fund_info::FundInfo}, - solana_farm_sdk::{ - fund::{Fund, FundAssetType, FundVault, FundVaultType, DISCRIMINATOR_FUND_VAULT}, - id::zero, - math, - pool::{Pool, PoolRoute}, - program, - program::{ - account, clock, - protocol::{orca, raydium}, - }, - token::Token, - traits::Packed, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn update_assets_with_vault(fund: &Fund, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _user_account, - fund_metadata, - fund_info_account, - custodies_assets_info, - vaults_assets_info, - vault_metadata_account, - vault_info_account, - underlying_pool_ref, - pool_token_a_ref, - pool_token_b_ref, - underlying_lp_token_mint, - pool_token_a_account, - pool_token_b_account, - amm_id, - amm_open_orders, - oracle_account_token_a, - oracle_account_token_b, - sysvar_account - ] = accounts - { - // validate params and accounts - msg!("Validate state and accounts"); - let mut fund_info = FundInfo::new(fund_info_account); - if fund_info.get_liquidation_start_time()? > 0 { - msg!("Error: Fund is in liquidation state"); - return Err(ProgramError::Custom(516)); - } - - // unpack and validate Vault metadata - if vault_metadata_account.owner != &fund.fund_program_id { - msg!("Error: Invalid custody owner"); - return Err(ProgramError::IllegalOwner); - } - let vault = account::unpack::(vault_metadata_account, "Vault")?; - if &vault.fund_ref != fund_metadata.key { - msg!("Error: Specified Vault doesn't belong to this Fund"); - return Err(ProgramError::Custom(507)); - } - if vault.discriminator != DISCRIMINATOR_FUND_VAULT - || &vault.underlying_pool_ref != underlying_pool_ref.key - || &vault.underlying_lp_token_mint != underlying_lp_token_mint.key - { - msg!("Error: Invalid Vault metadata account"); - return Err(ProgramError::Custom(506)); - } - match vault.vault_type { - FundVaultType::Vault => { - if vault_info_account.key != &vault.vault_ref { - msg!("Error: Invalid vault info account"); - return Err(ProgramError::Custom(532)); - } - } - FundVaultType::Pool => { - if vault_info_account.key != &vault.underlying_pool_ref { - msg!("Error: Invalid vault info account"); - return Err(ProgramError::Custom(532)); - } - } - FundVaultType::Farm => { - msg!("Nothing to do: Farms are not processed to avoid double counting"); - return Ok(()); - } - } - - if !program::is_single_instruction(sysvar_account)? { - msg!("Error: UpdateAssetsWithVault must be single instruction in the transaction"); - return Err(ProgramError::InvalidArgument); - } - - // unpack and validate underlying pool - let pool = account::unpack::(underlying_pool_ref, "underlying Pool")?; - if pool.token_a_ref.is_none() - || pool.token_b_ref.is_none() - || pool.token_a_account.is_none() - || pool.token_b_account.is_none() - || &pool.token_a_ref.unwrap() != pool_token_a_ref.key - || &pool.token_b_ref.unwrap() != pool_token_b_ref.key - || &pool.token_a_account.unwrap() != pool_token_a_account.key - || &pool.token_b_account.unwrap() != pool_token_b_account.key - { - msg!("Error: Invalid Pool metadata account"); - return Err(ProgramError::Custom(533)); - } - - match pool.route { - PoolRoute::Raydium { - amm_id: amm_id_key, - amm_open_orders: amm_open_orders_key, - .. - } => { - if &amm_open_orders_key != amm_open_orders.key || &amm_id_key != amm_id.key { - msg!("Error: Invalid Pool route metadata"); - return Err(ProgramError::Custom(534)); - } - } - PoolRoute::Orca { - amm_id: amm_id_key, .. - } => { - if &zero::id() != amm_open_orders.key || &amm_id_key != amm_id.key { - msg!("Error: Invalid Pool route metadata"); - return Err(ProgramError::Custom(534)); - } - } - _ => { - msg!("Error: Unsupported Pool route"); - return Err(ProgramError::Custom(522)); - } - } - - // unpack pool tokens - let token_a = account::unpack::(pool_token_a_ref, "token_a")?; - let token_b = account::unpack::(pool_token_b_ref, "token_b")?; - if &token_a.oracle_account.unwrap_or_else(zero::id) != oracle_account_token_a.key - || &token_b.oracle_account.unwrap_or_else(zero::id) != oracle_account_token_b.key - { - msg!("Error: Invalid oracle accounts"); - return Err(ProgramError::Custom(531)); - } - - // update assets tracking account - msg!("Update Fund assets account"); - let mut fund_vaults_assets = common::check_and_get_fund_assets_account( - fund, - vaults_assets_info, - FundAssetType::Vault, - )?; - - if fund_vaults_assets.target_hash == 0 { - msg!("Error: target_hash is 0. Vaults must be added before updating assets."); - return Err(ProgramError::Custom(535)); - } else if vault.vault_id == 0 { - fund_vaults_assets.current_hash = 0; - fund_vaults_assets.current_assets_usd = 0.0; - fund_vaults_assets.current_cycle = - math::checked_add(fund_vaults_assets.current_cycle, 1)?; - fund_vaults_assets.cycle_start_time = clock::get_time()?; - fund_vaults_assets.cycle_end_time = 0; - } else if fund_vaults_assets.cycle_end_time != 0 { - msg!("Error: Cycle has already ended. To reset start with vault_id 0."); - return Err(ProgramError::Custom(536)); - } - - // update running hash of processed vaults - // this mechanism is used to verify that all vaults have been processed - // before final number is recorded - fund_vaults_assets.current_hash = - math::hash_address(fund_vaults_assets.current_hash, &vault.vault_ref); - - if vault.lp_balance > 0 { - // compute vault balances - let (potential_token_a_balance, potential_token_b_balance) = match pool.route { - PoolRoute::Raydium { .. } => raydium::get_pool_withdrawal_amounts( - pool_token_a_account, - pool_token_b_account, - amm_open_orders, - amm_id, - underlying_lp_token_mint, - vault.lp_balance, - )?, - PoolRoute::Orca { .. } => orca::get_pool_withdrawal_amounts( - pool_token_a_account, - pool_token_b_account, - underlying_lp_token_mint, - vault.lp_balance, - )?, - _ => { - msg!("Error: Invalid Pool route"); - return Err(ProgramError::Custom(522)); - } - }; - - // update current assets value in usd - fund_vaults_assets.current_assets_usd += account::get_asset_value_usd( - potential_token_a_balance, - token_a.decimals, - token_a.oracle_type, - oracle_account_token_a, - fund_info.get_assets_max_price_error()?, - fund_info.get_assets_max_price_age_sec()?, - )?; - - fund_vaults_assets.current_assets_usd += account::get_asset_value_usd( - potential_token_b_balance, - token_b.decimals, - token_b.oracle_type, - oracle_account_token_b, - fund_info.get_assets_max_price_error()?, - fund_info.get_assets_max_price_age_sec()?, - )?; - } - - // check if all vaults have been processed - if fund_vaults_assets.current_hash == fund_vaults_assets.target_hash { - fund_vaults_assets.cycle_end_time = clock::get_time()?; - - // if all custodies have been processed as well the cycle is complete - let fund_custodies_assets = common::check_and_get_fund_assets_account( - fund, - custodies_assets_info, - FundAssetType::Custody, - )?; - - if fund_custodies_assets.cycle_end_time != 0 || fund_custodies_assets.target_hash == 0 { - // update fund stats - msg!("Update Fund stats"); - fund_info.set_current_assets_usd( - fund_custodies_assets.current_assets_usd - + fund_vaults_assets.current_assets_usd, - )?; - fund_info.set_assets_update_time(clock::get_time()?)?; - } - } - - fund_vaults_assets.pack(*vaults_assets_info.try_borrow_mut_data()?)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/instructions/user_init.rs b/farms/fund/src/instructions/user_init.rs deleted file mode 100644 index 70761aee99c..00000000000 --- a/farms/fund/src/instructions/user_init.rs +++ /dev/null @@ -1,98 +0,0 @@ -//! Initialize a new user for the Fund instruction handler -use { - crate::user_info::UserInfo, - solana_farm_sdk::{ - fund::{Fund, FundUserAction, FundUserRequests, DISCRIMINATOR_FUND_USER_REQUESTS}, - id::main_router, - program::{account, pda}, - string::ArrayString64, - token::Token, - traits::Packed, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn user_init(fund: &Fund, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - funding_account, - fund_metadata, - _fund_info_account, - user_account, - user_info_account, - user_requests_account, - custody_token_ref, - _system_program - ] = accounts - { - // validate params and accounts - if account::exists(user_requests_account)? { - msg!("Error: User already initialized"); - return Err(ProgramError::AccountAlreadyInitialized); - } - if custody_token_ref.owner != &main_router::id() { - msg!("Error: Invalid custody token metadata account"); - return Err(ProgramError::IllegalOwner); - } - - // create user info account - if account::is_empty(user_info_account)? { - msg!("Create user info account"); - let seeds: &[&[u8]] = &[ - b"user_info_account", - user_account.key.as_ref(), - fund.name.as_bytes(), - ]; - let bump = pda::init_system_account( - funding_account, - user_info_account, - &fund.fund_program_id, - &fund.fund_program_id, - seeds, - UserInfo::LEN, - )?; - let mut user_info = UserInfo::new(user_info_account); - user_info.init(&fund.name, bump)?; - } else if !UserInfo::validate_account(fund, user_info_account, user_account.key) { - msg!("Error: User info account already initialized but not valid"); - return Err(ProgramError::AccountAlreadyInitialized); - } - - // create user requests account - msg!("Create user requests account"); - let custody_token = account::unpack::(custody_token_ref, "custody token")?; - let seeds: &[&[u8]] = &[ - b"user_requests_account", - custody_token.name.as_bytes(), - user_account.key.as_ref(), - fund.name.as_bytes(), - ]; - let bump = pda::init_system_account( - funding_account, - user_requests_account, - &fund.fund_program_id, - &fund.fund_program_id, - seeds, - FundUserRequests::LEN, - )?; - let user_requests = FundUserRequests { - discriminator: DISCRIMINATOR_FUND_USER_REQUESTS, - fund_ref: *fund_metadata.key, - token_ref: *custody_token_ref.key, - deposit_request: FundUserAction::default(), - last_deposit: FundUserAction::default(), - withdrawal_request: FundUserAction::default(), - last_withdrawal: FundUserAction::default(), - deny_reason: ArrayString64::default(), - bump, - }; - user_requests.pack(*user_requests_account.try_borrow_mut_data()?)?; - } else { - return Err(ProgramError::NotEnoughAccountKeys); - } - - Ok(()) -} diff --git a/farms/fund/src/instructions/withdraw_fees.rs b/farms/fund/src/instructions/withdraw_fees.rs deleted file mode 100644 index 69e1fa6ac15..00000000000 --- a/farms/fund/src/instructions/withdraw_fees.rs +++ /dev/null @@ -1,63 +0,0 @@ -//! Fund WithdrawFees instruction handler - -use { - crate::fund_info::FundInfo, - solana_farm_sdk::{ - fund::Fund, - program::{account, pda}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn withdraw_fees(fund: &Fund, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - _fund_metadata, - fund_info_account, - _active_multisig_account, - fund_multisig_account, - _spl_token_program, - custody_fees_account, - receiver - ] = accounts - { - // validate accounts - msg!("Validate state and accounts"); - if !account::check_token_account_owner(custody_fees_account, fund_multisig_account.key)? { - msg!("Error: Invalid custody fees token account owner"); - return Err(ProgramError::IllegalOwner); - } - - // transfer tokens - msg!("Transfer fees from custody"); - let withdraw_amount = if amount > 0 { - amount - } else { - account::get_token_balance(custody_fees_account)? - }; - - let seeds: &[&[&[u8]]] = &[&[ - b"multisig", - fund.name.as_bytes(), - &[fund.multisig_bump], - ]]; - pda::transfer_tokens_with_seeds( - custody_fees_account, - receiver, - fund_multisig_account, - seeds, - withdraw_amount, - )?; - - // update fund stats - msg!("Update Fund stats"); - let mut fund_info = FundInfo::new(fund_info_account); - fund_info.update_admin_action_time() - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/fund/src/lib.rs b/farms/fund/src/lib.rs deleted file mode 100644 index 653e7ac45c1..00000000000 --- a/farms/fund/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![forbid(unsafe_code)] - -pub mod common; -mod entrypoint; -pub mod fund_info; -pub mod instructions; -pub mod user_info; diff --git a/farms/fund/src/user_info.rs b/farms/fund/src/user_info.rs deleted file mode 100644 index d7b9e3494e6..00000000000 --- a/farms/fund/src/user_info.rs +++ /dev/null @@ -1,130 +0,0 @@ -//! User info account management. - -use { - solana_farm_sdk::{ - error::FarmError, - fund::Fund, - refdb, - refdb::{RefDB, Reference, ReferenceType, StorageType}, - string::{str_to_as64, ArrayString64}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, - pubkey::Pubkey, - }, - std::cell::RefMut, -}; - -pub struct UserInfo<'a, 'b> { - pub key: &'a Pubkey, - pub data: RefMut<'a, &'b mut [u8]>, -} - -impl<'a, 'b> UserInfo<'a, 'b> { - pub const LEN: usize = StorageType::get_storage_size_for_records(ReferenceType::U64, 2); - pub const VIRTUAL_TOKENS_BALANCE_INDEX: usize = 0; - pub const USER_BUMP_INDEX: usize = 1; - - pub fn new(account: &'a AccountInfo<'b>) -> Self { - Self { - key: account.key, - data: account.data.borrow_mut(), - } - } - - pub fn init(&mut self, refdb_name: &ArrayString64, user_bump: u8) -> ProgramResult { - if RefDB::is_initialized(&self.data) { - return Ok(()); - } - RefDB::init(&mut self.data, refdb_name, ReferenceType::U64)?; - - self.init_refdb_field( - UserInfo::VIRTUAL_TOKENS_BALANCE_INDEX, - "VirtualTokensBalance", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - UserInfo::USER_BUMP_INDEX, - "UserBump", - Reference::U64 { - data: user_bump as u64, - }, - ) - } - - pub fn set_virtual_tokens_balance(&mut self, virtual_tokens_balance: u64) -> ProgramResult { - RefDB::update_at( - &mut self.data, - UserInfo::VIRTUAL_TOKENS_BALANCE_INDEX, - &Reference::U64 { - data: virtual_tokens_balance, - }, - ) - .map(|_| ()) - } - - pub fn get_virtual_tokens_balance(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, UserInfo::VIRTUAL_TOKENS_BALANCE_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(data); - } - } - Err(FarmError::InvalidRefdbRecord.into()) - } - - pub fn get_user_bump(&self) -> Result { - if let Some(user_bump_rec) = RefDB::read_at(&self.data, UserInfo::USER_BUMP_INDEX)? { - if let Reference::U64 { data } = user_bump_rec.reference { - return Ok(data as u8); - } - } - Err(ProgramError::UninitializedAccount) - } - - pub fn validate_account( - fund: &Fund, - user_info_account: &'a AccountInfo<'b>, - user_account: &Pubkey, - ) -> bool { - if let Ok(refdb) = user_info_account.try_borrow_data() { - if let Ok(Some(user_bump_rec)) = RefDB::read_at(&refdb, UserInfo::USER_BUMP_INDEX) { - if let Reference::U64 { data } = user_bump_rec.reference { - if let Ok(key) = Pubkey::create_program_address( - &[ - b"user_info_account", - user_account.as_ref(), - fund.name.as_bytes(), - &[data as u8], - ], - &fund.fund_program_id, - ) { - if user_info_account.key == &key { - return true; - } - } - } - } - } - false - } - - // private helpers - fn init_refdb_field( - &mut self, - index: usize, - field_name: &str, - reference: Reference, - ) -> ProgramResult { - RefDB::write( - &mut self.data, - &refdb::Record { - index: Some(index as u32), - counter: 0, - tag: 0, - name: str_to_as64(field_name)?, - reference, - }, - ) - .map(|_| ()) - } -} diff --git a/farms/fund/tests/fixture/mod.rs b/farms/fund/tests/fixture/mod.rs deleted file mode 100644 index 572b6152b48..00000000000 --- a/farms/fund/tests/fixture/mod.rs +++ /dev/null @@ -1,339 +0,0 @@ -use std::str::FromStr; -use { - log::info, - solana_farm_client::{client::FarmClient, error::FarmClientError}, - solana_farm_sdk::{ - farm::{FarmRoute, FarmType}, - fund::{Fund, FundType}, - pool::PoolRoute, - refdb, - refdb::{find_target_pda, StorageType}, - string::str_to_as64, - token::{OracleType, Token, TokenType}, - vault::{Vault, VaultStrategy, VaultType}, - }, - solana_sdk::{pubkey::Pubkey, signature::Keypair}, -}; - -#[allow(dead_code)] -pub fn init_fund( - client: &FarmClient, - admin_keypair: &Keypair, - manager_address: &Pubkey, - fund_name: Option<&str>, - fund_token_name: Option<&str>, -) -> Result { - let rand_name = "FUND_".to_string() + &rand::random::().to_string(); - let fund_name: &str = if let Some(name) = fund_name { - name - } else { - &rand_name - }; - - let fund_token_name = if let Some(name) = fund_token_name { - name - } else { - fund_name - }; - - client - .add_program_id( - admin_keypair, - "FarmFund", - &Pubkey::from_str("EmpaFV97uaRPXwWcq8iaHMMTCx7oWkrMSsTcRFJKXHmy").unwrap(), - solana_farm_sdk::ProgramIDType::Fund, - None, - ) - .unwrap(); - - let fund_address = client.get_program_id("FarmFund")?; - - if client.get_token(fund_token_name).is_err() { - let last_index = client.get_refdb_last_index(&StorageType::Token.to_string())?; - let token = Token { - name: str_to_as64(fund_token_name)?, - description: str_to_as64(&(fund_name.to_string() + " Token"))?, - token_type: TokenType::FundToken, - refdb_index: Some(last_index), - refdb_counter: 0u16, - decimals: 6, - chain_id: 101, - mint: Pubkey::find_program_address( - &[b"fund_token_mint", fund_name.as_bytes()], - &fund_address, - ) - .0, - oracle_type: OracleType::Unsupported, - oracle_account: None, - description_account: refdb::find_description_pda(StorageType::Token, fund_token_name).0, - }; - - info!("Recording token {}", fund_token_name); - client.add_token(admin_keypair, token)?; - } - - if client.get_fund(fund_name).is_err() { - let last_index = client.get_refdb_last_index(&StorageType::Fund.to_string())?; - let fund = Fund { - name: str_to_as64(fund_name).unwrap(), - version: 1, - fund_type: FundType::General, - official: true, - refdb_index: Some(last_index), - refdb_counter: 0u16, - metadata_bump: find_target_pda(StorageType::Fund, &str_to_as64(fund_name).unwrap()).1, - authority_bump: Pubkey::find_program_address( - &[b"fund_authority", fund_name.as_bytes()], - &fund_address, - ) - .1, - fund_token_bump: Pubkey::find_program_address( - &[b"fund_token_mint", fund_name.as_bytes()], - &fund_address, - ) - .1, - multisig_bump: Pubkey::find_program_address( - &[b"multisig", fund_name.as_bytes()], - &fund_address, - ) - .1, - fund_program_id: fund_address, - fund_authority: Pubkey::find_program_address( - &[b"fund_authority", fund_name.as_bytes()], - &fund_address, - ) - .0, - fund_manager: *manager_address, - fund_token_ref: find_target_pda( - StorageType::Token, - &str_to_as64(fund_token_name).unwrap(), - ) - .0, - info_account: Pubkey::find_program_address( - &[b"info_account", fund_name.as_bytes()], - &fund_address, - ) - .0, - multisig_account: Pubkey::find_program_address( - &[b"multisig", fund_name.as_bytes()], - &fund_address, - ) - .0, - vaults_assets_info: Pubkey::find_program_address( - &[b"vaults_assets_info", fund_name.as_bytes()], - &fund_address, - ) - .0, - custodies_assets_info: Pubkey::find_program_address( - &[b"custodies_assets_info", fund_name.as_bytes()], - &fund_address, - ) - .0, - description_account: Pubkey::find_program_address( - &[b"description_account", fund_name.as_bytes()], - &fund_address, - ) - .0, - }; - - info!("Recording Fund {}", fund_name); - client.add_fund(admin_keypair, fund)?; - - info!("Initializing Fund {}", fund_name); - client.init_fund(admin_keypair, fund_name, 0)?; - } - - Ok(fund_name.to_string()) -} - -#[allow(dead_code)] -pub fn init_vault( - client: &FarmClient, - admin_keypair: &Keypair, - vault_name: &str, - vault_token_name: &str, -) -> Result<(), FarmClientError> { - let vault_address = client.get_program_id("STCVaultRaydium")?; - - if client.get_token(vault_token_name).is_err() { - let last_index = client.get_refdb_last_index(&StorageType::Token.to_string())?; - let token = Token { - name: str_to_as64(vault_token_name)?, - description: str_to_as64(&(vault_name.to_string() + " Token"))?, - token_type: TokenType::VtToken, - refdb_index: Some(last_index), - refdb_counter: 0u16, - decimals: 6, - chain_id: 101, - mint: Pubkey::find_program_address( - &[b"vault_token_mint", vault_name.as_bytes()], - &vault_address, - ) - .0, - oracle_type: OracleType::Unsupported, - oracle_account: None, - description_account: refdb::find_description_pda(StorageType::Token, vault_token_name) - .0, - }; - - info!("Recording token {}", vault_token_name); - client.add_token(admin_keypair, token)?; - } - - if client.get_vault(vault_name).is_err() { - let farm_name = "RDM.".to_string() + vault_name.split('.').collect::>()[2]; - let farm = client.get_farm(&farm_name).unwrap(); - let lp_token = client - .get_token_by_ref(&farm.lp_token_ref.unwrap()) - .unwrap(); - let pool = client.find_pools_with_lp(lp_token.name.as_str()).unwrap()[0]; - let farm_second_reward_token_account = match farm.route { - FarmRoute::Raydium { - farm_second_reward_token_account, - .. - } => farm_second_reward_token_account, - _ => None, - }; - let last_index = client.get_refdb_last_index(&StorageType::Vault.to_string())?; - let vault = Vault { - name: str_to_as64(vault_name).unwrap(), - version: 1, - vault_type: VaultType::AmmStake, - official: true, - refdb_index: Some(last_index), - refdb_counter: 0u16, - metadata_bump: find_target_pda(StorageType::Vault, &str_to_as64(vault_name).unwrap()).1, - authority_bump: Pubkey::find_program_address( - &[b"vault_authority", vault_name.as_bytes()], - &vault_address, - ) - .1, - vault_token_bump: Pubkey::find_program_address( - &[b"vault_token_mint", vault_name.as_bytes()], - &vault_address, - ) - .1, - lock_required: true, - unlock_required: true, - vault_program_id: vault_address, - vault_authority: Pubkey::find_program_address( - &[b"vault_authority", vault_name.as_bytes()], - &vault_address, - ) - .0, - vault_token_ref: find_target_pda( - StorageType::Token, - &str_to_as64(vault_token_name).unwrap(), - ) - .0, - info_account: Pubkey::find_program_address( - &[b"info_account", vault_name.as_bytes()], - &vault_address, - ) - .0, - multisig_account: Pubkey::find_program_address( - &[b"multisig", vault_name.as_bytes()], - &vault_address, - ) - .0, - fees_account_a: Some( - Pubkey::find_program_address( - &[b"fees_account_a", vault_name.as_bytes()], - &vault_address, - ) - .0, - ), - fees_account_b: if farm.farm_type == FarmType::DualReward - || farm_second_reward_token_account.is_some() - { - Some( - Pubkey::find_program_address( - &[b"fees_account_b", vault_name.as_bytes()], - &vault_address, - ) - .0, - ) - } else { - None - }, - strategy: VaultStrategy::StakeLpCompoundRewards { - pool_router_id: pool.router_program_id, - pool_id: match pool.route { - PoolRoute::Raydium { amm_id, .. } => amm_id, - PoolRoute::Saber { swap_account, .. } => swap_account, - PoolRoute::Orca { amm_id, .. } => amm_id, - }, - pool_ref: client.get_pool_ref(&pool.name).unwrap(), - farm_router_id: farm.router_program_id, - farm_id: match farm.route { - FarmRoute::Raydium { farm_id, .. } => farm_id, - FarmRoute::Saber { quarry, .. } => quarry, - FarmRoute::Orca { farm_id, .. } => farm_id, - }, - farm_ref: client.get_farm_ref(&farm.name).unwrap(), - lp_token_custody: Pubkey::find_program_address( - &[b"lp_token_custody", vault_name.as_bytes()], - &vault_address, - ) - .0, - token_a_custody: Pubkey::find_program_address( - &[b"token_a_custody", vault_name.as_bytes()], - &vault_address, - ) - .0, - token_b_custody: Some( - Pubkey::find_program_address( - &[b"token_b_custody", vault_name.as_bytes()], - &vault_address, - ) - .0, - ), - token_a_reward_custody: Pubkey::find_program_address( - &[b"token_a_reward_custody", vault_name.as_bytes()], - &vault_address, - ) - .0, - token_b_reward_custody: if farm.farm_type == FarmType::DualReward - || farm_second_reward_token_account.is_some() - { - Some( - Pubkey::find_program_address( - &[b"token_b_reward_custody", vault_name.as_bytes()], - &vault_address, - ) - .0, - ) - } else { - None - }, - vault_stake_info: if farm.version < 4 { - Pubkey::find_program_address( - &[b"vault_stake_info", vault_name.as_bytes()], - &vault_address, - ) - .0 - } else { - Pubkey::find_program_address( - &[b"vault_stake_info_v4", vault_name.as_bytes()], - &vault_address, - ) - .0 - }, - vault_stake_custody: None, - reward_exchange_pool_id: None, - reward_exchange_pool_ref: None, - }, - }; - - info!("Recording Vault {}", vault_name); - client.add_vault(admin_keypair, vault)?; - - info!("Initializing Vault {}", vault_name); - client.init_vault(admin_keypair, vault_name, 1)?; - client.init_vault(admin_keypair, vault_name, 2)?; - client.enable_deposits_vault(admin_keypair, vault_name)?; - client.enable_withdrawals_vault(admin_keypair, vault_name)?; - } - - Ok(()) -} diff --git a/farms/fund/tests/main.rs b/farms/fund/tests/main.rs deleted file mode 100644 index 9bd79a9c83d..00000000000 --- a/farms/fund/tests/main.rs +++ /dev/null @@ -1,1497 +0,0 @@ -mod fixture; -mod utils; - -use { - log::info, - solana_farm_client::{client::FarmClient, error::FarmClientError}, - solana_farm_sdk::{ - fund::{ - FundAssetType, FundAssetsTrackingConfig, FundCustodyType, FundSchedule, FundVaultType, - DISCRIMINATOR_FUND_CUSTODY, DISCRIMINATOR_FUND_USER_REQUESTS, DISCRIMINATOR_FUND_VAULT, - }, - id::zero, - string::str_to_as64, - Protocol, - }, - solana_sdk::{ - commitment_config::{CommitmentConfig, CommitmentLevel}, - signature::Keypair, - signer::Signer, - }, -}; - -#[test] -#[ignore] -// Runs all integration tests. Default config should have rpc url set to -// localhost or devnet and kepair_path should point to the admin keypair. -fn run_tests() -> Result<(), FarmClientError> { - solana_logger::setup_with_default("main=debug,solana=debug"); - - let (endpoint, admin_keypair) = utils::get_endpoint_and_keypair(); - let user_keypair = Keypair::new(); - let manager_keypair = Keypair::new(); - let client = FarmClient::new_with_commitment(&endpoint, CommitmentConfig::confirmed()); - let wallet = user_keypair.pubkey(); - - let fund_name = fixture::init_fund( - &client, - &admin_keypair, - &manager_keypair.pubkey(), - None, - None, - )?; - //let fund_name = "FUND_2196727256".to_string(); - let vault_name = "RDM.COIN-PC-V4"; - let vault_type = FundVaultType::Pool; - let vault_name2 = "RDM.STC.COIN-PC-V5"; - let token_a = "COIN"; - let token_b = "PC"; - let lp_token = "LP.RDM.COIN-PC-V4"; - let vt_token = "VT.RDM.STC.COIN-PC-V5"; - let amount = 0.2; - let fund = client.get_fund(&fund_name)?; - let fund_token = client.get_token_by_ref(&fund.fund_token_ref)?; - let fund_info = client.get_fund_info(&fund_name)?; - println!("{:#?}", fund_info); - - // init user for SOL deposit - info!("Init user"); - let token_name = "SOL"; - assert!(client - .get_fund_user_requests(&wallet, &fund_name, token_name) - .is_err()); - client.confirm_async_transaction( - &client.rpc_client.request_airdrop( - &manager_keypair.pubkey(), - client.ui_amount_to_tokens(2.0, "SOL")?, - )?, - CommitmentLevel::Confirmed, - )?; - for _ in 0..2 { - client.confirm_async_transaction( - &client - .rpc_client - .request_airdrop(&wallet, client.ui_amount_to_tokens(2.0, "SOL")?)?, - CommitmentLevel::Confirmed, - )?; - } - client.user_init_fund(&user_keypair, &fund_name, token_name)?; - let user_requests = client.get_fund_user_requests(&wallet, &fund_name, token_name)?; - println!("{:#?}", user_requests); - assert_eq!( - user_requests.discriminator, - DISCRIMINATOR_FUND_USER_REQUESTS - ); - - // init SOL custody - // deposit should fail while custody is missing - info!("Init Deposit/Withdraw custody for SOL"); - assert!(client - .get_fund_custody(&fund_name, token_name, FundCustodyType::DepositWithdraw) - .is_err()); - assert!(client - .add_fund_custody( - &manager_keypair, - &fund_name, - token_name, - FundCustodyType::DepositWithdraw, - ) - .is_err()); - - client.add_fund_custody( - &admin_keypair, - &fund_name, - token_name, - FundCustodyType::DepositWithdraw, - )?; - let custody = - client.get_fund_custody(&fund_name, token_name, FundCustodyType::DepositWithdraw)?; - println!("{:#?}", custody); - assert_eq!(custody.discriminator, DISCRIMINATOR_FUND_CUSTODY); - assert_eq!(custody.custody_type, FundCustodyType::DepositWithdraw); - - info!("Remove and re-init custody"); - client.remove_fund_custody( - &admin_keypair, - &fund_name, - token_name, - FundCustodyType::DepositWithdraw, - )?; - assert!(client - .get_fund_custody(&fund_name, token_name, FundCustodyType::DepositWithdraw) - .is_err()); - - client.add_fund_custody( - &admin_keypair, - &fund_name, - token_name, - FundCustodyType::DepositWithdraw, - )?; - let custody = - client.get_fund_custody(&fund_name, token_name, FundCustodyType::DepositWithdraw)?; - assert_eq!(custody.custody_type, FundCustodyType::DepositWithdraw); - - // add a Vault - info!("Add a Vault"); - assert!(client - .get_fund_vault(&fund_name, vault_name, vault_type) - .is_err()); - - client.add_fund_vault(&admin_keypair, &fund_name, vault_name, vault_type)?; - let vault = client.get_fund_vault(&fund_name, vault_name, vault_type)?; - println!("{:#?}", vault); - assert_eq!(vault.discriminator, DISCRIMINATOR_FUND_VAULT); - assert_eq!(vault.vault_type, vault_type); - - info!("Remove and re-add the Vault"); - client.remove_fund_vault(&admin_keypair, &fund_name, vault_name, vault_type)?; - assert!(client - .get_fund_vault(&fund_name, vault_name, vault_type) - .is_err()); - - client.add_fund_vault(&admin_keypair, &fund_name, vault_name, vault_type)?; - let vault = client.get_fund_vault(&fund_name, vault_name, vault_type)?; - assert_eq!(vault.vault_type, vault_type); - - // set assets tracking config - info!("Set assets tracking config"); - let config = FundAssetsTrackingConfig { - assets_limit_usd: 1000.0, - max_update_age_sec: 600, - max_price_error: 0.1, - max_price_age_sec: 600, - issue_virtual_tokens: false, - }; - client.set_fund_assets_tracking_config(&admin_keypair, &fund_name, &config)?; - let fund_info = client.get_fund_info(&fund_name)?; - assert_eq!(fund_info.assets_config, config); - - // set deposit schedule - info!("Set deposit schedule"); - assert!(client - .request_deposit_fund(&user_keypair, &fund_name, token_name, 1.123) - .is_err()); - let schedule = FundSchedule { - start_time: 0, - end_time: utils::get_time() + 600, - approval_required: true, - min_amount_usd: 0.0, - max_amount_usd: client.get_oracle_price("SOL", 0, 0.0)? * 1.5, - fee: 0.01, - }; - client.set_fund_deposit_schedule(&admin_keypair, &fund_name, &schedule)?; - let fund_info = client.get_fund_info(&fund_name)?; - assert_eq!(fund_info.deposit_schedule, schedule); - - // request deposit - info!("Request deposit over the limit"); - assert!(client - .request_deposit_fund(&user_keypair, &fund_name, token_name, 1.8) - .is_err()); - info!("Request deposit"); - client.request_deposit_fund(&user_keypair, &fund_name, token_name, 1.123)?; - let user_requests = client.get_fund_user_requests(&wallet, &fund_name, token_name)?; - assert_eq!( - user_requests.deposit_request.amount, - client.ui_amount_to_tokens(1.123, "SOL")? - ); - assert!(user_requests.deposit_request.time > 0); - assert!(user_requests.deny_reason.is_empty()); - assert_eq!( - client.get_token_account_balance(&wallet, fund_token.name.as_str())?, - 0.0 - ); - - // cancel deposit - info!("Cancel deposit"); - client.cancel_deposit_fund(&user_keypair, &fund_name, token_name)?; - let user_requests = client.get_fund_user_requests(&wallet, &fund_name, token_name)?; - assert_eq!(user_requests.deposit_request.amount, 0); - assert_eq!(user_requests.deposit_request.time, 0); - assert!(user_requests.deny_reason.is_empty()); - - // request and deny - info!("Request a new deposit and deny"); - client.request_deposit_fund(&user_keypair, &fund_name, token_name, 1.123)?; - let user_balance_before = client.get_token_account_balance(&wallet, "SOL")?; - client.deny_deposit_fund(&manager_keypair, &fund_name, &wallet, token_name, "test")?; - let user_requests = client.get_fund_user_requests(&wallet, &fund_name, token_name)?; - assert_eq!(user_requests.deposit_request.amount, 0); - assert_eq!(user_requests.deposit_request.time, 0); - assert_eq!(user_requests.deny_reason, str_to_as64("test")?); - assert_eq!( - user_requests.last_deposit.amount, - client.ui_amount_to_tokens(1.123, "SOL")? - ); - assert!(user_requests.last_deposit.time > 0); - assert_eq!( - user_balance_before, - client.get_token_account_balance(&wallet, "SOL")? - ); - - // request and approve - info!("Request a new deposit and approve"); - let fund_token_balance_before = - client.get_token_account_balance(&wallet, fund_token.name.as_str())?; - let fund_token_supply_before = client.get_token_supply(fund_token.name.as_str())?; - client.request_deposit_fund(&user_keypair, &fund_name, token_name, 1.123)?; - client.approve_deposit_fund(&admin_keypair, &fund_name, &wallet, token_name, 0.123)?; - let user_requests = client.get_fund_user_requests(&wallet, &fund_name, token_name)?; - assert_eq!(user_requests.deposit_request.amount, 0); - assert_eq!(user_requests.deposit_request.time, 0); - assert!(user_requests.deny_reason.is_empty()); - assert_eq!( - user_requests.last_deposit.amount, - client.ui_amount_to_tokens(0.123, "SOL")? - ); - assert!(user_requests.last_deposit.time > 0); - let fund_token_balance = client.get_token_account_balance(&wallet, fund_token.name.as_str())?; - assert_eq!( - client.get_token_supply(fund_token.name.as_str())? - fund_token_supply_before, - fund_token_balance - ); - assert!(fund_token_balance > fund_token_balance_before); - let wd_custody_token_address = client.get_fund_custody_token_account( - &fund_name, - token_name, - FundCustodyType::DepositWithdraw, - )?; - let wd_fees_custody_token_address = client.get_fund_custody_fees_token_account( - &fund_name, - token_name, - FundCustodyType::DepositWithdraw, - )?; - let deposited_amount = client.ui_amount_to_tokens(0.123 - 0.123 * 0.01, "SOL")?; - assert_eq!( - deposited_amount, - utils::get_token_balance(&client, &wd_custody_token_address) - ); - assert_eq!( - client.ui_amount_to_tokens(0.123, "SOL")? - deposited_amount, - utils::get_token_balance(&client, &wd_fees_custody_token_address) - ); - - // update assets with vault - info!("Update assets with vaults"); - let fund_assets = client.get_fund_assets(&fund_name, FundAssetType::Vault)?; - assert!(fund_assets.target_hash > 0); - let original_cycle = fund_assets.current_cycle; - client.update_fund_assets_with_vaults(&user_keypair, &fund_name)?; - let fund_assets = client.get_fund_assets(&fund_name, FundAssetType::Vault)?; - assert_eq!(fund_assets.current_cycle, original_cycle + 1); - assert!(fund_assets.cycle_end_time > 0); - assert_eq!(fund_assets.current_assets_usd, 0.0); - - // update assets with custody - info!("Update assets with custodies"); - let fund_assets = client.get_fund_assets(&fund_name, FundAssetType::Custody)?; - assert!(fund_assets.target_hash > 0); - let original_cycle = fund_assets.current_cycle; - client.update_fund_assets_with_custodies(&user_keypair, &fund_name)?; - let fund_assets = client.get_fund_assets(&fund_name, FundAssetType::Custody)?; - assert_eq!(fund_assets.current_cycle, original_cycle + 1); - assert!(fund_assets.cycle_end_time > 0); - let expected_assets_usd = client.get_oracle_price("SOL", 0, 0.0)? * 0.123; - assert!((fund_assets.current_assets_usd - expected_assets_usd).abs() < 1.0); - - let fund_info = client.get_fund_info(&fund_name)?; - assert!((fund_info.current_assets_usd - fund_assets.current_assets_usd).abs() < 1.0); - - // init second user - let user_keypair2 = Keypair::new(); - let wallet2 = user_keypair2.pubkey(); - client.confirm_async_transaction( - &client - .rpc_client - .request_airdrop(&wallet2, client.ui_amount_to_tokens(2.0, "SOL")?)?, - CommitmentLevel::Confirmed, - )?; - - // enable fund multisig - info!("Enable Fund multisig"); - let multisig = client.get_fund_admins(&fund_name)?; - assert_eq!(multisig.num_signers, 1); - assert_eq!(multisig.signers[0], admin_keypair.pubkey()); - assert_eq!(multisig.signers[1], zero::id()); - - client.set_fund_admins(&admin_keypair, &fund_name, &[wallet, wallet2], 2)?; - - let multisig = client.get_fund_admins(&fund_name)?; - assert_eq!(multisig.num_signers, 2); - assert_eq!(multisig.num_signed, 0); - assert!(!multisig.signed[0]); - assert!(!multisig.signed[1]); - assert_eq!(multisig.min_signatures, 2); - assert_eq!(multisig.signers[0], wallet); - assert_eq!(multisig.signers[1], wallet2); - assert_eq!(multisig.signers[2], zero::id()); - - // operations under admin should fail - assert!(client - .set_fund_deposit_schedule(&admin_keypair, &fund_name, &schedule) - .is_err()); - assert!(client - .add_fund_custody( - &admin_keypair, - &fund_name, - token_name, - FundCustodyType::Trading, - ) - .is_err()); - - // multisign should go thru - info!("Test Fund multisig"); - client.add_fund_custody( - &user_keypair, - &fund_name, - token_name, - FundCustodyType::Trading, - )?; - let multisig = client.get_fund_admins(&fund_name)?; - assert_eq!(multisig.num_signed, 1); - assert!(multisig.signed[0]); - assert!(!multisig.signed[1]); - assert!(client - .get_fund_custody(&fund_name, token_name, FundCustodyType::Trading) - .is_err()); - client.add_fund_custody( - &user_keypair2, - &fund_name, - token_name, - FundCustodyType::Trading, - )?; - assert!(client - .get_fund_custody(&fund_name, token_name, FundCustodyType::Trading) - .is_ok()); - let multisig = client.get_fund_admins(&fund_name)?; - assert_eq!(multisig.num_signed, 2); - assert!(multisig.signed[0]); - assert!(multisig.signed[1]); - - // disable multisig - info!("Disable Fund multisig"); - client.set_fund_admins(&user_keypair, &fund_name, &[admin_keypair.pubkey()], 1)?; - client.set_fund_admins(&user_keypair2, &fund_name, &[admin_keypair.pubkey()], 1)?; - let multisig = client.get_fund_admins(&fund_name)?; - assert_eq!(multisig.num_signers, 1); - assert_eq!(multisig.signers[0], admin_keypair.pubkey()); - assert_eq!(multisig.signers[1], zero::id()); - - client.remove_fund_custody( - &admin_keypair, - &fund_name, - token_name, - FundCustodyType::Trading, - )?; - client.remove_fund_multisig(&admin_keypair, &fund_name)?; - - // turn off approval requirement - let schedule = FundSchedule { - start_time: 0, - end_time: utils::get_time() + 600, - approval_required: false, - min_amount_usd: 0.0, - max_amount_usd: client.get_oracle_price("SOL", 0, 0.0)? * 1.5, - fee: 0.01, - }; - client.set_fund_deposit_schedule(&manager_keypair, &fund_name, &schedule)?; - - // request instant deposit - info!("Request instant deposit"); - client.request_deposit_fund(&user_keypair2, &fund_name, token_name, 0.123)?; - let user_requests = client.get_fund_user_requests(&wallet2, &fund_name, token_name)?; - assert_eq!(user_requests.deposit_request.amount, 0); - assert_eq!(user_requests.deposit_request.time, 0); - assert!(user_requests.deny_reason.is_empty()); - assert!(user_requests.last_deposit.amount > 0); - assert!(user_requests.last_deposit.time > 0); - let fund_token_balance2 = - client.get_token_account_balance(&wallet2, fund_token.name.as_str())?; - assert!(fund_token_balance2 > 0.0); - // some tolerence needed due to potential SOL/USD price change - assert!((fund_token_balance2 - fund_token_balance).abs() / fund_token_balance < 0.01); - assert_eq!( - deposited_amount * 2, - utils::get_token_balance(&client, &wd_custody_token_address) - ); - assert_eq!( - (client.ui_amount_to_tokens(0.123, "SOL")? - deposited_amount) * 2, - utils::get_token_balance(&client, &wd_fees_custody_token_address) - ); - - // set withdrawal schedule - info!("Set withdrawal schedule"); - assert!(client - .request_withdrawal_fund(&user_keypair, &fund_name, token_name, 0.1) - .is_err()); - let schedule = FundSchedule { - start_time: 0, - end_time: utils::get_time() + 600, - approval_required: true, - min_amount_usd: 0.0, - max_amount_usd: client.get_oracle_price("SOL", 0, 0.0)? * 0.1, - fee: 0.01, - }; - client.set_fund_withdrawal_schedule(&admin_keypair, &fund_name, &schedule)?; - let fund_info = client.get_fund_info(&fund_name)?; - assert_eq!(fund_info.withdrawal_schedule, schedule); - - // request withdrawal - info!("Request withdrawal over the limit"); - let fund_token_balance_after_deposit = - client.get_token_account_balance(&wallet, fund_token.name.as_str())?; - info!("Fund token balance: {}", fund_token_balance_after_deposit); - assert!(client - .request_withdrawal_fund( - &user_keypair, - &fund_name, - token_name, - fund_token_balance_after_deposit - ) - .is_err()); - let schedule = FundSchedule { - start_time: 0, - end_time: utils::get_time() + 600, - approval_required: true, - min_amount_usd: 0.0, - max_amount_usd: client.get_oracle_price("SOL", 0, 0.0)? * 0.2, - fee: 0.01, - }; - client.set_fund_withdrawal_schedule(&manager_keypair, &fund_name, &schedule)?; - info!("Request withdrawal"); - client.request_withdrawal_fund(&user_keypair, &fund_name, token_name, 100.0)?; - let user_requests = client.get_fund_user_requests(&wallet, &fund_name, token_name)?; - assert_eq!( - user_requests.withdrawal_request.amount, - client.ui_amount_to_tokens_with_decimals(100.0, 6)? - ); - assert!(user_requests.withdrawal_request.time > 0); - assert!(user_requests.deny_reason.is_empty()); - assert_eq!( - client.get_token_account_balance(&wallet, fund_token.name.as_str())?, - fund_token_balance_after_deposit - ); - - // cancel withdrawal - info!("Cancel withdrawal"); - client.cancel_withdrawal_fund(&user_keypair, &fund_name, token_name)?; - let user_requests = client.get_fund_user_requests(&wallet, &fund_name, token_name)?; - assert_eq!(user_requests.withdrawal_request.amount, 0); - assert_eq!(user_requests.withdrawal_request.time, 0); - assert!(user_requests.deny_reason.is_empty()); - - // request and deny - info!("Request a new withdrawal and deny"); - client.request_withdrawal_fund(&user_keypair, &fund_name, token_name, 111.0)?; - client.deny_withdrawal_fund( - &admin_keypair, - &fund_name, - &wallet, - token_name, - "not allowed", - )?; - let user_requests = client.get_fund_user_requests(&wallet, &fund_name, token_name)?; - assert_eq!(user_requests.withdrawal_request.amount, 0); - assert_eq!(user_requests.withdrawal_request.time, 0); - assert_eq!(user_requests.deny_reason, str_to_as64("not allowed")?); - assert_eq!( - user_requests.last_withdrawal.amount, - client.ui_amount_to_tokens_with_decimals(111.0, 6)? - ); - assert!(user_requests.last_withdrawal.time > 0); - - // request and approve - info!("Request a new withdrawal and approve"); - let initial_sol_balance = client.get_token_account_balance(&wallet, "SOL")?; - let initial_custody_balance = utils::get_token_balance(&client, &wd_custody_token_address); - client.request_withdrawal_fund(&user_keypair, &fund_name, token_name, 121.77)?; - let user_requests = client.get_fund_user_requests(&wallet, &fund_name, token_name)?; - assert_eq!( - user_requests.withdrawal_request.amount, - client.ui_amount_to_tokens_with_decimals(121.77, 6)? - ); - assert!(user_requests.withdrawal_request.time > 0); - assert!(user_requests.deny_reason.is_empty()); - client.approve_withdrawal_fund(&manager_keypair, &fund_name, &wallet, token_name, 100.0)?; - let user_requests = client.get_fund_user_requests(&wallet, &fund_name, token_name)?; - assert_eq!(user_requests.withdrawal_request.amount, 0); - assert_eq!(user_requests.withdrawal_request.time, 0); - assert!(user_requests.deny_reason.is_empty()); - assert_eq!( - user_requests.last_withdrawal.amount, - client.ui_amount_to_tokens_with_decimals(100.0, 6)? - ); - assert!(user_requests.last_withdrawal.time > 0); - let fund_token_balance3 = - client.get_token_account_balance(&wallet, fund_token.name.as_str())?; - assert!(fund_token_balance3 > 0.0 && fund_token_balance3 < fund_token_balance_after_deposit); - assert!(client.get_token_account_balance(&wallet, "SOL")? - initial_sol_balance > 0.09); - let new_custody_balance = utils::get_token_balance(&client, &wd_custody_token_address); - assert!( - (initial_custody_balance as f64 - - new_custody_balance as f64 - - client.ui_amount_to_tokens(0.1, "SOL")? as f64) - .abs() - < 1000000.0 - ); - assert!( - (((client.ui_amount_to_tokens(0.123, "SOL")? - deposited_amount) * 2 - + client.ui_amount_to_tokens(0.1 * 0.01, "SOL")?) as f64 - - utils::get_token_balance(&client, &wd_fees_custody_token_address) as f64) - .abs() - < 10000.0 - ); - - // turn off approval requirement - let schedule = FundSchedule { - start_time: 0, - end_time: utils::get_time() + 600, - approval_required: false, - min_amount_usd: 0.0, - max_amount_usd: client.get_oracle_price("SOL", 0, 0.0)? * 1.5, - fee: 0.01, - }; - client.set_fund_withdrawal_schedule(&admin_keypair, &fund_name, &schedule)?; - - // request instant withdrawal - info!("Request instant withdrawal"); - let initial_sol_balance = client.get_token_account_balance(&wallet2, "SOL")?; - let initial_custody_balance = utils::get_token_balance(&client, &wd_custody_token_address); - client.request_withdrawal_fund(&user_keypair2, &fund_name, token_name, 100.0)?; - let user_requests = client.get_fund_user_requests(&wallet2, &fund_name, token_name)?; - assert_eq!(user_requests.withdrawal_request.amount, 0); - assert_eq!(user_requests.withdrawal_request.time, 0); - assert!(user_requests.deny_reason.is_empty()); - assert!(user_requests.last_withdrawal.amount > 0); - assert!(user_requests.last_withdrawal.time > 0); - let fund_token_balance4 = - client.get_token_account_balance(&wallet2, fund_token.name.as_str())?; - assert!(fund_token_balance4 > 0.0 && fund_token_balance4 < fund_token_balance2); - // some tolerence needed due to potential SOL/USD price change - assert!((fund_token_balance4 - fund_token_balance3).abs() / fund_token_balance3 < 0.05); - assert!(client.get_token_account_balance(&wallet2, "SOL")? - initial_sol_balance > 0.09); - let new_custody_balance = utils::get_token_balance(&client, &wd_custody_token_address); - assert!( - (initial_custody_balance as f64 - - new_custody_balance as f64 - - client.ui_amount_to_tokens(0.1, "SOL")? as f64) - .abs() - < 1000000.0 - ); - assert!( - (((client.ui_amount_to_tokens(0.123, "SOL")? - deposited_amount) * 2 - + client.ui_amount_to_tokens(0.1 * 0.01, "SOL")? * 2) as f64 - - utils::get_token_balance(&client, &wd_fees_custody_token_address) as f64) - .abs() - < 10000.0 - ); - - // init SOL trading custody - // accept should fail while custody is missing - info!("Init Trading custody for SOL"); - if client - .get_fund_custody(&fund_name, token_name, FundCustodyType::Trading) - .is_err() - { - client.add_fund_custody( - &admin_keypair, - &fund_name, - token_name, - FundCustodyType::Trading, - )?; - } - let custody = client.get_fund_custody(&fund_name, token_name, FundCustodyType::Trading)?; - println!("{:#?}", custody); - assert_eq!(custody.discriminator, DISCRIMINATOR_FUND_CUSTODY); - assert_eq!(custody.custody_type, FundCustodyType::Trading); - - // accept funds into trading custody - info!("Accept funds into trading custody"); - let trading_custody_token_address = - client.get_fund_custody_token_account(&fund_name, token_name, FundCustodyType::Trading)?; - let wd_custody_balance = utils::get_token_balance(&client, &wd_custody_token_address); - let trading_custody_balance = utils::get_token_balance(&client, &trading_custody_token_address); - assert_eq!(trading_custody_balance, 0); - client.lock_assets_fund(&manager_keypair, &fund_name, token_name, 0.0)?; - assert_eq!( - 0, - utils::get_token_balance(&client, &wd_custody_token_address) - ); - assert_eq!( - wd_custody_balance, - utils::get_token_balance(&client, &trading_custody_token_address) - ); - - // release funds into w/d custody - info!("Release funds into w/d custody"); - client.unlock_assets_fund(&admin_keypair, &fund_name, token_name, 0.0)?; - assert_eq!( - 0, - utils::get_token_balance(&client, &trading_custody_token_address) - ); - assert_eq!( - wd_custody_balance, - utils::get_token_balance(&client, &wd_custody_token_address) - ); - - // swap - info!("Update fund assets"); - info!( - "Custodies processed: {}", - client.update_fund_assets_with_custodies(&user_keypair, &fund_name)? - ); - info!( - "Vaults processed: {}", - client.update_fund_assets_with_vaults(&user_keypair, &fund_name)? - ); - - if client - .get_fund_custody(&fund_name, token_a, FundCustodyType::Trading) - .is_err() - { - info!("Init trading custody for {}", token_a); - client.add_fund_custody( - &admin_keypair, - &fund_name, - token_a, - FundCustodyType::Trading, - )?; - } - - if client - .get_fund_custody(&fund_name, token_a, FundCustodyType::DepositWithdraw) - .is_err() - { - info!("Init deposit custody for {}", token_a); - client.add_fund_custody( - &admin_keypair, - &fund_name, - token_a, - FundCustodyType::DepositWithdraw, - )?; - } - - if client - .get_fund_custody(&fund_name, token_b, FundCustodyType::Trading) - .is_err() - { - info!("Init trading custody for {}", token_b); - client.add_fund_custody( - &admin_keypair, - &fund_name, - token_b, - FundCustodyType::Trading, - )?; - } - - let trading_custody_token_a_address = - client.get_fund_custody_token_account(&fund_name, token_a, FundCustodyType::Trading)?; - let trading_custody_token_b_address = - client.get_fund_custody_token_account(&fund_name, token_b, FundCustodyType::Trading)?; - let trading_custody_token_a_balance = - utils::get_token_ui_balance(&client, &trading_custody_token_a_address); - - if trading_custody_token_a_balance < amount * 2.0 + amount * 2.0 * 0.04 { - info!("Set new deposit schedule"); - let schedule = FundSchedule { - start_time: 0, - end_time: utils::get_time() + 600, - approval_required: false, - min_amount_usd: 0.0, - max_amount_usd: f64::MAX, - fee: 0.01, - }; - client.set_fund_deposit_schedule(&admin_keypair, &fund_name, &schedule)?; - info!("Deposit {} to the Fund", token_a); - client.request_deposit_fund( - &admin_keypair, - &fund_name, - token_a, - amount * 2.0 + amount * 2.0 * 0.04, - )?; - info!("Move {} to trading custody", token_a); - client.lock_assets_fund(&admin_keypair, &fund_name, token_a, 0.0)?; - } - - let trading_custody_token_a_balance = - utils::get_token_ui_balance(&client, &trading_custody_token_a_address); - let trading_custody_token_b_balance = - utils::get_token_ui_balance(&client, &trading_custody_token_b_address); - info!( - "Trading custody balance {}: {}, {}: {}", - token_a, trading_custody_token_a_balance, token_b, trading_custody_token_b_balance - ); - - info!("Swap {} to {}", token_a, token_b); - info!( - "{}", - client.fund_swap( - &manager_keypair, - &fund_name, - Protocol::Raydium, - token_a, - token_b, - amount, - 0.0 - )? - ); - let trading_custody_token_a_balance2 = - utils::get_token_ui_balance(&client, &trading_custody_token_a_address); - let trading_custody_token_b_balance2 = - utils::get_token_ui_balance(&client, &trading_custody_token_b_address); - assert!( - (trading_custody_token_a_balance - trading_custody_token_a_balance2 - amount).abs() < 0.001 - ); - assert!(trading_custody_token_b_balance2 > trading_custody_token_b_balance); - - // add liquidity - if client - .get_fund_custody(&fund_name, lp_token, FundCustodyType::Trading) - .is_err() - { - info!("Init trading custody for {}", lp_token); - client.add_fund_custody( - &admin_keypair, - &fund_name, - lp_token, - FundCustodyType::Trading, - )?; - } - - let trading_custody_token_a_balance = - utils::get_token_ui_balance(&client, &trading_custody_token_a_address); - let trading_custody_token_b_balance = - utils::get_token_ui_balance(&client, &trading_custody_token_b_address); - let trading_custody_lp_token_address = - client.get_fund_custody_token_account(&fund_name, lp_token, FundCustodyType::Trading)?; - let trading_custody_lp_token_balance = - utils::get_token_ui_balance(&client, &trading_custody_lp_token_address); - - info!("Add liquidity to {}", vault_name); - info!( - "{}", - client.fund_add_liquidity_pool( - &manager_keypair, - &fund_name, - vault_name, - amount * 0.4, - 0.0 - )? - ); - let trading_custody_token_a_balance2 = - utils::get_token_ui_balance(&client, &trading_custody_token_a_address); - let trading_custody_token_b_balance2 = - utils::get_token_ui_balance(&client, &trading_custody_token_b_address); - let trading_custody_lp_token_balance2 = - utils::get_token_ui_balance(&client, &trading_custody_lp_token_address); - assert!( - (trading_custody_token_a_balance - trading_custody_token_a_balance2 - amount * 0.4).abs() - < 0.001 - ); - assert!(trading_custody_token_b_balance > trading_custody_token_b_balance2); - assert!(trading_custody_lp_token_balance2 > trading_custody_lp_token_balance); - - info!("Add liquidity to {}", vault_name); - info!( - "{}", - client.fund_add_liquidity_pool( - &manager_keypair, - &fund_name, - vault_name, - 0.0, - amount * 0.4, - )? - ); - let trading_custody_token_a_balance3 = - utils::get_token_ui_balance(&client, &trading_custody_token_a_address); - let trading_custody_token_b_balance3 = - utils::get_token_ui_balance(&client, &trading_custody_token_b_address); - let trading_custody_lp_token_balance3 = - utils::get_token_ui_balance(&client, &trading_custody_lp_token_address); - assert!( - (trading_custody_token_b_balance2 - trading_custody_token_b_balance3 - amount * 0.4).abs() - < 0.001 - ); - assert!(trading_custody_token_a_balance2 > trading_custody_token_a_balance3); - assert!(trading_custody_lp_token_balance3 > trading_custody_lp_token_balance2); - - // stake - let farm = client.find_farms_with_lp(lp_token)?[0]; - info!("Stake to {}", farm.name); - - if client - .get_fund_vault(&fund_name, &farm.name, FundVaultType::Farm) - .is_err() - { - info!("Add a Farm"); - assert!(client - .add_fund_vault( - &manager_keypair, - &fund_name, - &farm.name, - FundVaultType::Farm - ) - .is_err()); - client.add_fund_vault(&admin_keypair, &fund_name, &farm.name, FundVaultType::Farm)?; - let vault = client.get_fund_vault(&fund_name, &farm.name, FundVaultType::Farm)?; - println!("{:#?}", vault); - assert_eq!(vault.discriminator, DISCRIMINATOR_FUND_VAULT); - assert_eq!(vault.vault_type, FundVaultType::Farm); - } - - let trading_custody_lp_token_balance = - utils::get_token_ui_balance(&client, &trading_custody_lp_token_address); - let stake_balance = - if let Ok(stake) = client.get_user_stake_balance(&fund.fund_authority, &farm.name) { - stake - } else { - 0.0 - }; - info!( - "{}", - client.fund_stake( - &manager_keypair, - &fund_name, - &farm.name, - trading_custody_lp_token_balance * 0.5, - )? - ); - let trading_custody_lp_token_balance2 = - utils::get_token_ui_balance(&client, &trading_custody_lp_token_address); - let stake_balance2 = client.get_user_stake_balance(&fund.fund_authority, &farm.name)?; - assert!( - (trading_custody_lp_token_balance * 0.5 - trading_custody_lp_token_balance2).abs() < 0.001 - ); - assert!( - (stake_balance2 - stake_balance - trading_custody_lp_token_balance * 0.5).abs() < 0.001 - ); - - info!("Stake to {}", farm.name); - - let trading_custody_lp_token_balance = - utils::get_token_ui_balance(&client, &trading_custody_lp_token_address); - let stake_balance = - if let Ok(stake) = client.get_user_stake_balance(&fund.fund_authority, &farm.name) { - stake - } else { - 0.0 - }; - info!( - "{}", - client.fund_stake(&manager_keypair, &fund_name, &farm.name, 0.0,)? - ); - let trading_custody_lp_token_balance2 = - utils::get_token_ui_balance(&client, &trading_custody_lp_token_address); - let stake_balance2 = client.get_user_stake_balance(&fund.fund_authority, &farm.name)?; - assert!(trading_custody_lp_token_balance2 == 0.0); - assert!((stake_balance2 - stake_balance - trading_custody_lp_token_balance).abs() < 0.001); - - // harvest - info!("Harvest from {}", farm.name); - info!( - "{}", - client.fund_harvest(&manager_keypair, &fund_name, &farm.name)? - ); - - // unstake - info!("Unstake from {}", farm.name); - let trading_custody_lp_token_balance = - utils::get_token_ui_balance(&client, &trading_custody_lp_token_address); - let stake_balance = client.get_user_stake_balance(&fund.fund_authority, &farm.name)?; - info!( - "{}", - client.fund_unstake( - &manager_keypair, - &fund_name, - &farm.name, - stake_balance * 0.5 - )? - ); - let stake_balance2 = client.get_user_stake_balance(&fund.fund_authority, &farm.name)?; - let trading_custody_lp_token_balance2 = - utils::get_token_ui_balance(&client, &trading_custody_lp_token_address); - assert!( - (trading_custody_lp_token_balance2 - - trading_custody_lp_token_balance - - stake_balance * 0.5) - .abs() - < 0.001 - ); - assert!((stake_balance - stake_balance2 - stake_balance * 0.5).abs() < 0.001); - - info!("Unstake from {}", farm.name); - let trading_custody_lp_token_balance = - utils::get_token_ui_balance(&client, &trading_custody_lp_token_address); - let stake_balance = client.get_user_stake_balance(&fund.fund_authority, &farm.name)?; - info!( - "{}", - client.fund_unstake(&manager_keypair, &fund_name, &farm.name, 0.0)? - ); - let stake_balance2 = client.get_user_stake_balance(&fund.fund_authority, &farm.name)?; - let trading_custody_lp_token_balance2 = - utils::get_token_ui_balance(&client, &trading_custody_lp_token_address); - assert!( - (trading_custody_lp_token_balance2 - trading_custody_lp_token_balance - stake_balance) - .abs() - < 0.001 - ); - assert!(stake_balance2 == 0.0); - - // remove liquidity - let trading_custody_token_a_balance = - utils::get_token_ui_balance(&client, &trading_custody_token_a_address); - let trading_custody_token_b_balance = - utils::get_token_ui_balance(&client, &trading_custody_token_b_address); - let trading_custody_lp_token_balance = - utils::get_token_ui_balance(&client, &trading_custody_lp_token_address); - - info!("Remove liquidity from {}", vault_name); - info!( - "{}", - client.fund_remove_liquidity_pool( - &manager_keypair, - &fund_name, - vault_name, - trading_custody_lp_token_balance * 0.5, - )? - ); - let trading_custody_token_a_balance2 = - utils::get_token_ui_balance(&client, &trading_custody_token_a_address); - let trading_custody_token_b_balance2 = - utils::get_token_ui_balance(&client, &trading_custody_token_b_address); - let trading_custody_lp_token_balance2 = - utils::get_token_ui_balance(&client, &trading_custody_lp_token_address); - assert!(trading_custody_token_a_balance2 > trading_custody_token_a_balance); - assert!(trading_custody_token_b_balance2 > trading_custody_token_b_balance); - assert!( - (trading_custody_lp_token_balance * 0.5 - trading_custody_lp_token_balance2).abs() < 0.001 - ); - - info!("Remove liquidity from {}", vault_name); - info!( - "{}", - client.fund_remove_liquidity_pool(&manager_keypair, &fund_name, vault_name, 0.0,)? - ); - let trading_custody_token_a_balance3 = - utils::get_token_ui_balance(&client, &trading_custody_token_a_address); - let trading_custody_token_b_balance3 = - utils::get_token_ui_balance(&client, &trading_custody_token_b_address); - let trading_custody_lp_token_balance3 = - utils::get_token_ui_balance(&client, &trading_custody_lp_token_address); - assert!(trading_custody_token_a_balance3 > trading_custody_token_a_balance2); - assert!(trading_custody_token_b_balance3 > trading_custody_token_b_balance2); - assert!(trading_custody_lp_token_balance3 == 0.0); - - // init vault - fixture::init_vault(&client, &admin_keypair, vault_name2, vt_token)?; - if client - .get_fund_vault(&fund_name, vault_name2, FundVaultType::Vault) - .is_err() - { - info!("Add a Vault"); - assert!(client - .add_fund_vault( - &manager_keypair, - &fund_name, - vault_name2, - FundVaultType::Vault, - ) - .is_err()); - client.add_fund_vault( - &admin_keypair, - &fund_name, - vault_name2, - FundVaultType::Vault, - )?; - let vault = client.get_fund_vault(&fund_name, vault_name2, FundVaultType::Vault)?; - println!("{:#?}", vault); - assert_eq!(vault.discriminator, DISCRIMINATOR_FUND_VAULT); - assert_eq!(vault.vault_type, FundVaultType::Vault); - } - - // enable vault multisig - info!("Enable Vault multisig"); - let multisig = client.get_vault_admins(vault_name2)?; - assert_eq!(multisig.num_signers, 1); - assert_eq!(multisig.signers[0], admin_keypair.pubkey()); - assert_eq!(multisig.signers[1], zero::id()); - - client.set_vault_admins(&admin_keypair, vault_name2, &[wallet, wallet2], 2)?; - - let multisig = client.get_vault_admins(vault_name2)?; - assert_eq!(multisig.num_signers, 2); - assert_eq!(multisig.num_signed, 0); - assert!(!multisig.signed[0]); - assert!(!multisig.signed[1]); - assert_eq!(multisig.min_signatures, 2); - assert_eq!(multisig.signers[0], wallet); - assert_eq!(multisig.signers[1], wallet2); - assert_eq!(multisig.signers[2], zero::id()); - - // operations under admin should fail - assert!(client - .disable_withdrawals_vault(&admin_keypair, vault_name2) - .is_err()); - - // multisign should go thru - info!("Test Vault multisig"); - client.disable_withdrawals_vault(&user_keypair, vault_name2)?; - let multisig = client.get_vault_admins(vault_name2)?; - assert_eq!(multisig.num_signed, 1); - assert!(multisig.signed[0]); - assert!(!multisig.signed[1]); - assert!(client.get_vault_info(vault_name2)?.withdrawal_allowed); - client.disable_withdrawals_vault(&user_keypair2, vault_name2)?; - assert!(!client.get_vault_info(vault_name2)?.withdrawal_allowed); - let multisig = client.get_vault_admins(vault_name2)?; - assert_eq!(multisig.num_signed, 2); - assert!(multisig.signed[0]); - assert!(multisig.signed[1]); - - // disable multisig - info!("Disable Vault multisig"); - client.set_vault_admins(&user_keypair, vault_name2, &[admin_keypair.pubkey()], 1)?; - client.set_vault_admins(&user_keypair2, vault_name2, &[admin_keypair.pubkey()], 1)?; - let multisig = client.get_vault_admins(vault_name2)?; - assert_eq!(multisig.num_signers, 1); - assert_eq!(multisig.signers[0], admin_keypair.pubkey()); - assert_eq!(multisig.signers[1], zero::id()); - client.enable_withdrawals_vault(&admin_keypair, vault_name2)?; - client.remove_vault_multisig(&admin_keypair, vault_name2)?; - client.enable_withdrawals_vault(&admin_keypair, vault_name2)?; - - // add liquidity vault - if client - .get_fund_custody(&fund_name, vt_token, FundCustodyType::Trading) - .is_err() - { - info!("Init trading custody for {}", vt_token); - client.add_fund_custody( - &admin_keypair, - &fund_name, - vt_token, - FundCustodyType::Trading, - )?; - } - - let trading_custody_token_a_balance = - utils::get_token_ui_balance(&client, &trading_custody_token_a_address); - let trading_custody_token_b_balance = - utils::get_token_ui_balance(&client, &trading_custody_token_b_address); - let trading_custody_vt_token_address = - client.get_fund_custody_token_account(&fund_name, vt_token, FundCustodyType::Trading)?; - let trading_custody_vt_token_balance = - utils::get_token_ui_balance(&client, &trading_custody_vt_token_address); - - info!("Add liquidity to {}", vault_name2); - info!( - "{}", - client.fund_add_liquidity_vault( - &manager_keypair, - &fund_name, - vault_name2, - amount * 0.4, - 0.0 - )? - ); - let trading_custody_token_a_balance2 = - utils::get_token_ui_balance(&client, &trading_custody_token_a_address); - let trading_custody_token_b_balance2 = - utils::get_token_ui_balance(&client, &trading_custody_token_b_address); - let trading_custody_vt_token_balance2 = - utils::get_token_ui_balance(&client, &trading_custody_vt_token_address); - assert!( - (trading_custody_token_a_balance - trading_custody_token_a_balance2 - amount * 0.4).abs() - < 0.001 - ); - assert!(trading_custody_token_b_balance > trading_custody_token_b_balance2); - assert!(trading_custody_vt_token_balance2 > trading_custody_vt_token_balance); - - info!("Add liquidity to {}", vault_name2); - info!( - "{}", - client.fund_add_liquidity_vault( - &manager_keypair, - &fund_name, - vault_name2, - 0.0, - amount * 0.4 - )? - ); - let trading_custody_token_a_balance3 = - utils::get_token_ui_balance(&client, &trading_custody_token_a_address); - let trading_custody_token_b_balance3 = - utils::get_token_ui_balance(&client, &trading_custody_token_b_address); - let trading_custody_vt_token_balance3 = - utils::get_token_ui_balance(&client, &trading_custody_vt_token_address); - assert!( - (trading_custody_token_b_balance2 - trading_custody_token_b_balance3 - amount * 0.4).abs() - < 0.001 - ); - assert!(trading_custody_token_a_balance2 > trading_custody_token_a_balance3); - assert!(trading_custody_vt_token_balance3 > trading_custody_vt_token_balance2); - - // remove liquidity vault - let trading_custody_token_a_balance = - utils::get_token_ui_balance(&client, &trading_custody_token_a_address); - let trading_custody_token_b_balance = - utils::get_token_ui_balance(&client, &trading_custody_token_b_address); - let trading_custody_vt_token_balance = - utils::get_token_ui_balance(&client, &trading_custody_vt_token_address); - - info!("Remove liquidity from {}", vault_name2); - info!( - "{}", - client.fund_remove_liquidity_vault( - &manager_keypair, - &fund_name, - vault_name2, - trading_custody_vt_token_balance * 0.5, - )? - ); - let trading_custody_token_a_balance2 = - utils::get_token_ui_balance(&client, &trading_custody_token_a_address); - let trading_custody_token_b_balance2 = - utils::get_token_ui_balance(&client, &trading_custody_token_b_address); - let trading_custody_vt_token_balance2 = - utils::get_token_ui_balance(&client, &trading_custody_vt_token_address); - assert!(trading_custody_token_a_balance2 > trading_custody_token_a_balance); - assert!(trading_custody_token_b_balance2 > trading_custody_token_b_balance); - assert!( - (trading_custody_vt_token_balance * 0.5 - trading_custody_vt_token_balance2).abs() < 0.001 - ); - - info!("Remove liquidity from {}", vault_name2); - info!( - "{}", - client.fund_remove_liquidity_vault(&manager_keypair, &fund_name, vault_name2, 0.0)? - ); - let trading_custody_token_a_balance3 = - utils::get_token_ui_balance(&client, &trading_custody_token_a_address); - let trading_custody_token_b_balance3 = - utils::get_token_ui_balance(&client, &trading_custody_token_b_address); - let trading_custody_vt_token_balance3 = - utils::get_token_ui_balance(&client, &trading_custody_vt_token_address); - assert!(trading_custody_token_a_balance3 > trading_custody_token_a_balance2); - assert!(trading_custody_token_b_balance3 > trading_custody_token_b_balance2); - assert!(trading_custody_vt_token_balance3 == 0.0); - - // withdraw fees - info!("Withdraw collected fees"); - assert!(test_custody_withdrawal( - &client, - &manager_keypair, - &fund_name, - token_name, - FundCustodyType::DepositWithdraw, - ) - .is_err()); - test_custody_withdrawal( - &client, - &admin_keypair, - &fund_name, - token_name, - FundCustodyType::DepositWithdraw, - )?; - test_custody_withdrawal( - &client, - &admin_keypair, - &fund_name, - token_name, - FundCustodyType::Trading, - )?; - test_custody_withdrawal( - &client, - &admin_keypair, - &fund_name, - token_a, - FundCustodyType::DepositWithdraw, - )?; - test_custody_withdrawal( - &client, - &admin_keypair, - &fund_name, - token_a, - FundCustodyType::Trading, - )?; - - // test liquidation - info!("Update fund assets"); - info!( - "Custodies processed: {}", - client.update_fund_assets_with_custodies(&manager_keypair, &fund_name)? - ); - let fund_assets = client.get_fund_assets(&fund_name, FundAssetType::Custody)?; - assert!(fund_assets.cycle_end_time > 0); - info!( - "Vaults processed: {}", - client.update_fund_assets_with_vaults(&manager_keypair, &fund_name)? - ); - let fund_assets = client.get_fund_assets(&fund_name, FundAssetType::Vault)?; - assert!(fund_assets.cycle_end_time > 0); - - // request instant deposit - info!("Deposit funds to get some stake"); - let schedule = FundSchedule { - start_time: 0, - end_time: utils::get_time() + 600, - approval_required: false, - min_amount_usd: 0.0, - max_amount_usd: client.get_oracle_price("SOL", 0, 0.0)? * 3.0, - fee: 0.01, - }; - client.set_fund_deposit_schedule(&manager_keypair, &fund_name, &schedule)?; - client.request_deposit_fund(&user_keypair, &fund_name, token_name, 2.222)?; - client.fund_add_liquidity_vault( - &manager_keypair, - &fund_name, - vault_name2, - amount * 0.2, - 0.0, - )?; - - // lock funds and make withdrawals not possible - info!("Lock funds and disable withdrawals"); - let schedule = FundSchedule { - start_time: 0, - end_time: utils::get_time() + 600, - approval_required: true, - min_amount_usd: 0.0, - max_amount_usd: 0.0001, - fee: 1.0, - }; - client.lock_assets_fund(&manager_keypair, &fund_name, token_name, 0.0)?; - client.set_fund_withdrawal_schedule(&manager_keypair, &fund_name, &schedule)?; - - // unlock should fail - assert!(client - .unlock_assets_fund(&user_keypair, &fund_name, token_name, 0.0) - .is_err()); - - // initiate liquidation - info!("Start liquidation"); - assert!(fund_info.liquidation_start_time == 0); - client.start_liquidation_fund(&user_keypair, &fund_name)?; - let fund_info = client.get_fund_info(&fund_name)?; - assert!(fund_info.liquidation_start_time > 0); - - // new deposits should fail - assert!(client - .request_deposit_fund(&user_keypair, &fund_name, token_name, 0.1) - .is_err()); - assert!(client - .fund_add_liquidity_vault(&manager_keypair, &fund_name, vault_name2, amount * 0.2, 0.0) - .is_err()); - - // remove liquidity from the vault - info!("Remove liquidity from {}", vault_name2); - client.fund_remove_liquidity_vault(&user_keypair, &fund_name, vault_name2, 0.0)?; - - // unlock assets - info!("Unlock assets"); - client.unlock_assets_fund(&user_keypair, &fund_name, token_name, 0.0)?; - client.unlock_assets_fund(&user_keypair, &fund_name, token_a, 0.0)?; - - // withdraw funds - info!("Withdraw {} funds", token_a); - let wd_custody_token_address = client.get_fund_custody_token_account( - &fund_name, - token_a, - FundCustodyType::DepositWithdraw, - )?; - client.get_or_create_token_account(&user_keypair, token_a)?; - let initial_balance = client.get_token_account_balance(&wallet, token_a)?; - let initial_custody_balance = utils::get_token_ui_balance(&client, &wd_custody_token_address); - let fund_token_balance = client.get_token_account_balance(&wallet, fund_token.name.as_str())?; - let fund_token_supply = client.get_token_supply(fund_token.name.as_str())?; - let token_value_usd = initial_custody_balance * client.get_oracle_price(token_a, 0, 0.0)?; - let mut tokens_to_withdraw = - token_value_usd / fund_info.current_assets_usd * fund_token_supply * 0.99; - if tokens_to_withdraw > fund_token_balance { - tokens_to_withdraw = fund_token_balance; - } - println!("initial_balance {}", initial_balance); - println!("initial_custody_balance {}", initial_custody_balance); - println!("fund_token_balance {}", fund_token_balance); - println!("fund_token_supply {}", fund_token_supply); - println!("token_value_usd {}", token_value_usd); - println!("tokens_to_withdraw {}", tokens_to_withdraw); - println!( - "fund_info.current_assets_usd {}", - fund_info.current_assets_usd - ); - client.request_withdrawal_fund(&user_keypair, &fund_name, token_a, tokens_to_withdraw)?; - let user_requests = client.get_fund_user_requests(&wallet, &fund_name, token_a)?; - assert_eq!(user_requests.withdrawal_request.amount, 0); - assert_eq!(user_requests.withdrawal_request.time, 0); - assert!(user_requests.deny_reason.is_empty()); - println!( - "new_balance {}", - client.get_token_account_balance(&wallet, token_a)? - ); - assert!( - (client.get_token_account_balance(&wallet, token_a)? - - initial_balance - - initial_custody_balance * 0.99) - .abs() - < 0.001 - ); - assert!( - (utils::get_token_ui_balance(&client, &wd_custody_token_address) - - initial_custody_balance * 0.01) - .abs() - < 0.001 - ); - - info!("Withdraw {} funds", token_name); - let wd_custody_token_address = client.get_fund_custody_token_account( - &fund_name, - token_name, - FundCustodyType::DepositWithdraw, - )?; - let initial_balance = client.get_token_account_balance(&wallet, token_name)?; - let initial_custody_balance = utils::get_token_ui_balance(&client, &wd_custody_token_address); - client.request_withdrawal_fund(&user_keypair, &fund_name, token_name, 0.0)?; - let user_requests = client.get_fund_user_requests(&wallet, &fund_name, token_name)?; - assert_eq!(user_requests.withdrawal_request.amount, 0); - assert_eq!(user_requests.withdrawal_request.time, 0); - assert!(user_requests.deny_reason.is_empty()); - assert!(client.get_token_account_balance(&wallet, token_name)? > initial_balance); - assert!( - utils::get_token_ui_balance(&client, &wd_custody_token_address) < initial_custody_balance - ); - - client.stop_liquidation_fund(&admin_keypair, &fund_name)?; - - // test virtual tokens - info!("Disable W/D approval requirement and enable virtual tokens"); - let fund_token_balance = - client.get_token_account_balance(&wallet2, fund_token.name.as_str())?; - assert!(fund_token_balance > 0.0); - let user_info = client.get_fund_user_info(&wallet2, &fund_name)?; - assert_eq!(user_info.virtual_tokens_balance, 0); - - let config = FundAssetsTrackingConfig { - assets_limit_usd: 1000.0, - max_update_age_sec: 600, - max_price_error: 0.1, - max_price_age_sec: 600, - issue_virtual_tokens: true, - }; - client.set_fund_assets_tracking_config(&admin_keypair, &fund_name, &config)?; - let fund_info = client.get_fund_info(&fund_name)?; - assert!(fund_info.assets_config.issue_virtual_tokens); - - let schedule = FundSchedule { - start_time: 0, - end_time: utils::get_time() + 600, - approval_required: false, - min_amount_usd: 0.0, - max_amount_usd: 1000.0, - fee: 0.01, - }; - client.set_fund_withdrawal_schedule(&manager_keypair, &fund_name, &schedule)?; - client.set_fund_deposit_schedule(&manager_keypair, &fund_name, &schedule)?; - - // request new deposit - info!("Request a new deposit"); - client.request_deposit_fund(&user_keypair2, &fund_name, token_name, 0.123)?; - let user_requests = client.get_fund_user_requests(&wallet2, &fund_name, token_name)?; - assert_eq!(user_requests.deposit_request.amount, 0); - assert_eq!(user_requests.deposit_request.time, 0); - assert!(user_requests.deny_reason.is_empty()); - let fund_token_balance2 = - client.get_token_account_balance(&wallet2, fund_token.name.as_str())?; - assert_eq!(fund_token_balance2, fund_token_balance); - let user_info = client.get_fund_user_info(&wallet2, &fund_name)?; - assert!(user_info.virtual_tokens_balance > 0); - let fund_info = client.get_fund_info(&fund_name)?; - assert_eq!( - fund_info.virtual_tokens_supply, - user_info.virtual_tokens_balance - ); - - // request partial withdrawal - info!("Request partial withdrawal"); - client.request_withdrawal_fund( - &user_keypair2, - &fund_name, - token_name, - fund_token_balance / 2.0, - )?; - let user_requests = client.get_fund_user_requests(&wallet2, &fund_name, token_name)?; - assert_eq!(user_requests.withdrawal_request.amount, 0); - assert_eq!(user_requests.withdrawal_request.time, 0); - assert!(user_requests.deny_reason.is_empty()); - let fund_token_balance3 = - client.get_token_account_balance(&wallet2, fund_token.name.as_str())?; - assert!( - fund_token_balance3 > 0.0 - && fund_token_balance - fund_token_balance3 - fund_token_balance / 2.0 < 0.01 - ); - let user_info2 = client.get_fund_user_info(&wallet2, &fund_name)?; - assert_eq!( - user_info2.virtual_tokens_balance, - user_info.virtual_tokens_balance - ); - - // request full withdrawal - info!("Request full withdrawal"); - client.request_withdrawal_fund(&user_keypair2, &fund_name, token_name, 0.0)?; - let user_requests = client.get_fund_user_requests(&wallet2, &fund_name, token_name)?; - assert_eq!(user_requests.withdrawal_request.amount, 0); - assert_eq!(user_requests.withdrawal_request.time, 0); - assert!(user_requests.deny_reason.is_empty()); - let fund_token_balance = - client.get_token_account_balance(&wallet2, fund_token.name.as_str())?; - assert_eq!(fund_token_balance, 0.0); - let user_info = client.get_fund_user_info(&wallet2, &fund_name)?; - assert_eq!(user_info.virtual_tokens_balance, 0); - let fund_info = client.get_fund_info(&fund_name)?; - assert_eq!(fund_info.virtual_tokens_supply, 0); - - Ok(()) -} - -fn test_custody_withdrawal( - client: &FarmClient, - admin_keypair: &Keypair, - fund_name: &str, - token_name: &str, - custody_type: FundCustodyType, -) -> Result<(), FarmClientError> { - let receiver = client.get_fund_custody_token_account(fund_name, token_name, custody_type)?; - let custody_fees_address = - client.get_fund_custody_fees_token_account(fund_name, token_name, custody_type)?; - let custody_fees_balance = - client.get_token_account_balance_with_address(&custody_fees_address)?; - let receiver_balance = client.get_token_account_balance_with_address(&receiver)?; - info!( - "{} {} fees balance: {}", - token_name, - if custody_type == FundCustodyType::Trading { - "Trading" - } else { - "W/D" - }, - custody_fees_balance - ); - info!( - "{}", - client.withdraw_fees_fund( - admin_keypair, - fund_name, - token_name, - custody_type, - 0.0, - &receiver - )? - ); - let custody_fees_balance2 = - client.get_token_account_balance_with_address(&custody_fees_address)?; - assert_eq!(custody_fees_balance2, 0.0); - let receiver_balance2 = client.get_token_account_balance_with_address(&receiver)?; - assert!(receiver_balance2 - receiver_balance - custody_fees_balance < 0.001); - - Ok(()) -} diff --git a/farms/fund/tests/utils/mod.rs b/farms/fund/tests/utils/mod.rs deleted file mode 100644 index 72cb7a10d44..00000000000 --- a/farms/fund/tests/utils/mod.rs +++ /dev/null @@ -1,52 +0,0 @@ -//! Common functions for tests - -use { - solana_farm_client::client::FarmClient, - solana_sdk::{ - clock::UnixTimestamp, pubkey::Pubkey, signature::Keypair, - signer::keypair::read_keypair_file, - }, -}; - -#[allow(dead_code)] -pub fn get_endpoint_and_keypair() -> (String, Keypair) { - let cli_config = if let Some(ref config_file) = *solana_cli_config::CONFIG_FILE { - solana_cli_config::Config::load(config_file).unwrap() - } else { - solana_cli_config::Config::default() - }; - - ( - cli_config.json_rpc_url.to_string(), - read_keypair_file(&cli_config.keypair_path).unwrap_or_else(|_| { - panic!("Filed to read keypair from \"{}\"", cli_config.keypair_path) - }), - ) -} - -#[allow(dead_code)] -pub fn get_time() -> UnixTimestamp { - std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_secs() as UnixTimestamp -} - -#[allow(dead_code)] -pub fn get_token_balance(client: &FarmClient, token_account: &Pubkey) -> u64 { - if let Ok(balance) = client.rpc_client.get_token_account_balance(token_account) { - balance.amount.parse::().unwrap() - } else { - 0 - } -} - -#[allow(dead_code)] -pub fn get_token_ui_balance(client: &FarmClient, token_account: &Pubkey) -> f64 { - if let Ok(balance) = client.rpc_client.get_token_account_balance(token_account) { - if let Some(amount) = balance.ui_amount { - return amount; - } - } - 0.0 -} diff --git a/farms/router-main/.gitignore b/farms/router-main/.gitignore deleted file mode 100644 index 96ef6c0b944..00000000000 --- a/farms/router-main/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -Cargo.lock diff --git a/farms/router-main/Cargo.toml b/farms/router-main/Cargo.toml deleted file mode 100644 index 92b31571f15..00000000000 --- a/farms/router-main/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "solana-router-main" -version = "1.1.3" -description = "Solana Farm Main Router" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana-program-library/farms" -license = "Apache-2.0" -homepage = "https://solana.com/" -edition = "2021" - -[features] -no-entrypoint = [] -debug = [] - -[dependencies] -solana-farm-sdk = "1.1.3" -spl-token = { version = "3.2.0", features = ["no-entrypoint"] } -solana-program = "1.9.18" -solana-security-txt = "1.0.1" -arrayref = "0.3.6" -arrayvec = "0.7.2" - -[dev-dependencies] -solana-program-test = "1.9.18" - -[lib] -crate-type = ["cdylib", "lib"] - diff --git a/farms/router-main/README.md b/farms/router-main/README.md deleted file mode 120000 index ccd27901fd5..00000000000 --- a/farms/router-main/README.md +++ /dev/null @@ -1 +0,0 @@ -../docs/crate.md \ No newline at end of file diff --git a/farms/router-main/Xargo.toml b/farms/router-main/Xargo.toml deleted file mode 100644 index 1744f098ae1..00000000000 --- a/farms/router-main/Xargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.bpfel-unknown-unknown.dependencies.std] -features = [] \ No newline at end of file diff --git a/farms/router-main/src/add_farm.rs b/farms/router-main/src/add_farm.rs deleted file mode 100644 index f155623613b..00000000000 --- a/farms/router-main/src/add_farm.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! Saves Farm's metadata on-chain - -use { - crate::refdb_init::{check_or_init_refdb, check_or_init_refdb_target}, - solana_farm_sdk::{farm::Farm, refdb, refdb::RefDB, traits::Packed}, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - pubkey::Pubkey, - }, -}; - -pub fn add_farm(program_id: &Pubkey, accounts: &[AccountInfo], farm: &Farm) -> ProgramResult { - msg!("Processing MainInstruction::AddFarm {}", farm.name); - - // validate accounts - let accounts_iter = &mut accounts.iter(); - - let signer_account = next_account_info(accounts_iter)?; - let _multisig_account = next_account_info(accounts_iter)?; - let refdb_account = next_account_info(accounts_iter)?; - let target_account = next_account_info(accounts_iter)?; - - check_or_init_refdb( - program_id, - signer_account, - refdb_account, - refdb::StorageType::Farm, - 0, - false, - )?; - check_or_init_refdb_target( - program_id, - signer_account, - target_account, - refdb::StorageType::Farm, - &farm.name, - farm.get_size(), - false, - )?; - - // update refdb storage - msg!("Updating refdb storage"); - RefDB::write( - *refdb_account.try_borrow_mut_data()?, - &refdb::Record { - index: farm.refdb_index, - counter: farm.refdb_counter, - tag: refdb::StorageType::Farm as u16, - name: farm.name, - reference: refdb::Reference::Pubkey { - data: *target_account.key, - }, - }, - )?; - - // fill in data - msg!("Writing metadata account"); - farm.pack(*target_account.try_borrow_mut_data()?)?; - - msg!("AddFarm complete"); - - Ok(()) -} diff --git a/farms/router-main/src/add_fund.rs b/farms/router-main/src/add_fund.rs deleted file mode 100644 index 11b86027afb..00000000000 --- a/farms/router-main/src/add_fund.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! Saves Fund's metadata on-chain - -use { - crate::refdb_init::{check_or_init_refdb, check_or_init_refdb_target}, - solana_farm_sdk::{fund::Fund, refdb, refdb::RefDB, traits::Packed}, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - pubkey::Pubkey, - }, -}; - -pub fn add_fund(program_id: &Pubkey, accounts: &[AccountInfo], fund: &Fund) -> ProgramResult { - msg!("Processing MainInstruction::AddFund {}", fund.name); - - // validate accounts - let accounts_iter = &mut accounts.iter(); - - let signer_account = next_account_info(accounts_iter)?; - let _multisig_account = next_account_info(accounts_iter)?; - let refdb_account = next_account_info(accounts_iter)?; - let target_account = next_account_info(accounts_iter)?; - - check_or_init_refdb( - program_id, - signer_account, - refdb_account, - refdb::StorageType::Fund, - 0, - false, - )?; - check_or_init_refdb_target( - program_id, - signer_account, - target_account, - refdb::StorageType::Fund, - &fund.name, - fund.get_size(), - false, - )?; - - // update refdb storage - msg!("Updating refdb storage"); - RefDB::write( - *refdb_account.try_borrow_mut_data()?, - &refdb::Record { - index: fund.refdb_index, - counter: fund.refdb_counter, - tag: refdb::StorageType::Fund as u16, - name: fund.name, - reference: refdb::Reference::Pubkey { - data: *target_account.key, - }, - }, - )?; - - // fill in data - msg!("Writing metadata account"); - fund.pack(*target_account.try_borrow_mut_data()?)?; - - msg!("AddFund complete"); - - Ok(()) -} diff --git a/farms/router-main/src/add_pool.rs b/farms/router-main/src/add_pool.rs deleted file mode 100644 index 3901c1a042e..00000000000 --- a/farms/router-main/src/add_pool.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! Saves Pool's metadata on-chain - -use { - crate::refdb_init::{check_or_init_refdb, check_or_init_refdb_target}, - solana_farm_sdk::{pool::Pool, refdb, refdb::RefDB, traits::Packed}, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - pubkey::Pubkey, - }, -}; - -pub fn add_pool(program_id: &Pubkey, accounts: &[AccountInfo], pool: &Pool) -> ProgramResult { - msg!("Processing MainInstruction::AddPool {}", pool.name); - - // validate accounts - let accounts_iter = &mut accounts.iter(); - - let signer_account = next_account_info(accounts_iter)?; - let _multisig_account = next_account_info(accounts_iter)?; - let refdb_account = next_account_info(accounts_iter)?; - let target_account = next_account_info(accounts_iter)?; - - check_or_init_refdb( - program_id, - signer_account, - refdb_account, - refdb::StorageType::Pool, - 0, - false, - )?; - check_or_init_refdb_target( - program_id, - signer_account, - target_account, - refdb::StorageType::Pool, - &pool.name, - pool.get_size(), - false, - )?; - - // update refdb storage - msg!("Updating refdb storage"); - RefDB::write( - *refdb_account.try_borrow_mut_data()?, - &refdb::Record { - index: pool.refdb_index, - counter: pool.refdb_counter, - tag: refdb::StorageType::Pool as u16, - name: pool.name, - reference: refdb::Reference::Pubkey { - data: *target_account.key, - }, - }, - )?; - - // fill in data - msg!("Writing metadata account"); - pool.pack(*target_account.try_borrow_mut_data()?)?; - - msg!("AddPool complete"); - - Ok(()) -} diff --git a/farms/router-main/src/add_token.rs b/farms/router-main/src/add_token.rs deleted file mode 100644 index 67a990d8872..00000000000 --- a/farms/router-main/src/add_token.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! Saves Token's metadata on-chain - -use { - crate::refdb_init::{check_or_init_refdb, check_or_init_refdb_target}, - solana_farm_sdk::{refdb, refdb::RefDB, token::Token, traits::Packed}, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - pubkey::Pubkey, - }, -}; - -pub fn add_token(program_id: &Pubkey, accounts: &[AccountInfo], token: &Token) -> ProgramResult { - msg!("Processing MainInstruction::AddToken {}", token.name); - - // validate accounts - let accounts_iter = &mut accounts.iter(); - - let signer_account = next_account_info(accounts_iter)?; - let _multisig_account = next_account_info(accounts_iter)?; - let refdb_account = next_account_info(accounts_iter)?; - let target_account = next_account_info(accounts_iter)?; - - check_or_init_refdb( - program_id, - signer_account, - refdb_account, - refdb::StorageType::Token, - 0, - false, - )?; - check_or_init_refdb_target( - program_id, - signer_account, - target_account, - refdb::StorageType::Token, - &token.name, - token.get_size(), - false, - )?; - - // update refdb storage - msg!("Updating refdb storage"); - RefDB::write( - *refdb_account.try_borrow_mut_data()?, - &refdb::Record { - index: token.refdb_index, - counter: token.refdb_counter, - tag: refdb::StorageType::Token as u16, - name: token.name, - reference: refdb::Reference::Pubkey { - data: *target_account.key, - }, - }, - )?; - - // fill in data - msg!("Writing metadata account"); - token.pack(*target_account.try_borrow_mut_data()?)?; - - msg!("AddToken complete"); - - Ok(()) -} diff --git a/farms/router-main/src/add_vault.rs b/farms/router-main/src/add_vault.rs deleted file mode 100644 index d8c15ccdd90..00000000000 --- a/farms/router-main/src/add_vault.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! Saves Vault's metadata on-chain - -use { - crate::refdb_init::{check_or_init_refdb, check_or_init_refdb_target}, - solana_farm_sdk::{refdb, refdb::RefDB, traits::Packed, vault::Vault}, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - pubkey::Pubkey, - }, -}; - -pub fn add_vault(program_id: &Pubkey, accounts: &[AccountInfo], vault: &Vault) -> ProgramResult { - msg!("Processing MainInstruction::AddVault {}", vault.name); - - // validate accounts - let accounts_iter = &mut accounts.iter(); - - let signer_account = next_account_info(accounts_iter)?; - let _multisig_account = next_account_info(accounts_iter)?; - let refdb_account = next_account_info(accounts_iter)?; - let target_account = next_account_info(accounts_iter)?; - - check_or_init_refdb( - program_id, - signer_account, - refdb_account, - refdb::StorageType::Vault, - 0, - false, - )?; - check_or_init_refdb_target( - program_id, - signer_account, - target_account, - refdb::StorageType::Vault, - &vault.name, - vault.get_size(), - false, - )?; - - // update refdb storage - msg!("Updating refdb storage"); - RefDB::write( - *refdb_account.try_borrow_mut_data()?, - &refdb::Record { - index: vault.refdb_index, - counter: vault.refdb_counter, - tag: refdb::StorageType::Vault as u16, - name: vault.name, - reference: refdb::Reference::Pubkey { - data: *target_account.key, - }, - }, - )?; - - // fill in data - msg!("Writing metadata account"); - vault.pack(*target_account.try_borrow_mut_data()?)?; - - msg!("AddVault complete"); - - Ok(()) -} diff --git a/farms/router-main/src/entrypoint.rs b/farms/router-main/src/entrypoint.rs deleted file mode 100644 index 492afa07f7d..00000000000 --- a/farms/router-main/src/entrypoint.rs +++ /dev/null @@ -1,25 +0,0 @@ -//! Program entrypoint - -#![cfg(not(feature = "no-entrypoint"))] - -solana_security_txt::security_txt! { - name: "Solana Farms", - project_url: "https://github.com/solana-labs/solana-program-library/tree/master/farms", - contacts: "email:solana.farms@protonmail.com", - policy: "", - preferred_languages: "en", - auditors: "Halborn" -} - -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, pubkey::Pubkey, -}; - -entrypoint!(process_instruction); -fn process_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - instruction_data: &[u8], -) -> ProgramResult { - crate::processor::process_instruction(program_id, accounts, instruction_data) -} diff --git a/farms/router-main/src/lib.rs b/farms/router-main/src/lib.rs deleted file mode 100644 index 68e358c9933..00000000000 --- a/farms/router-main/src/lib.rs +++ /dev/null @@ -1,20 +0,0 @@ -#![forbid(unsafe_code)] - -pub mod add_farm; -pub mod add_fund; -pub mod add_pool; -pub mod add_token; -pub mod add_vault; -mod entrypoint; -pub mod processor; -mod refdb_init; -pub mod refdb_instruction; -pub mod remove_farm; -pub mod remove_fund; -pub mod remove_pool; -pub mod remove_token; -pub mod remove_vault; -pub mod set_admin_signers; -pub mod set_program_admin_signers; -pub mod set_program_single_authority; -pub mod upgrade_program; diff --git a/farms/router-main/src/processor.rs b/farms/router-main/src/processor.rs deleted file mode 100644 index 229549c0d4e..00000000000 --- a/farms/router-main/src/processor.rs +++ /dev/null @@ -1,133 +0,0 @@ -//! Main router implementation. - -use { - crate::{ - add_farm::add_farm, add_fund::add_fund, add_pool::add_pool, add_token::add_token, - add_vault::add_vault, refdb_instruction::process_refdb_instruction, - remove_farm::remove_farm, remove_fund::remove_fund, remove_pool::remove_pool, - remove_token::remove_token, remove_vault::remove_vault, - set_admin_signers::set_admin_signers, set_program_admin_signers::set_program_admin_signers, - set_program_single_authority::set_program_single_authority, - upgrade_program::upgrade_program, - }, - solana_farm_sdk::{ - error::FarmError, - id::{main_router, main_router_admin, main_router_multisig}, - instruction::main_router::MainInstruction, - log::sol_log_params_short, - program::multisig, - }, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - //hash::Hasher, - log::sol_log_compute_units, - msg, - program_error::ProgramError, - pubkey::Pubkey, - }, -}; - -/// Program's entrypoint. -/// -/// # Arguments -/// * `program_id` - Public key of the router. -/// * `accounts` - Accounts, see particular instruction handler for the list. -/// * `instructions_data` - Packed MainInstruction. -pub fn process_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - instruction_data: &[u8], -) -> ProgramResult { - msg!("Main router entrypoint"); - if cfg!(feature = "debug") { - sol_log_params_short(accounts, instruction_data); - } - - if *program_id != main_router::id() { - return Err(ProgramError::IncorrectProgramId); - } - - let accounts_iter = &mut accounts.iter(); - let signer_account = next_account_info(accounts_iter)?; - let multisig_account = next_account_info(accounts_iter)?; - - // Read and unpack instruction data - let instruction = MainInstruction::unpack(instruction_data)?; - - // multisig account and default admin are different for program specific instructions vs others - let ((expected_multisig_account, multisig_bump), fallback_admin_account) = match instruction { - MainInstruction::SetProgramAdminSigners { .. } - | MainInstruction::SetProgramSingleAuthority - | MainInstruction::UpgradeProgram => ( - Pubkey::find_program_address( - &[b"multisig", next_account_info(accounts_iter)?.key.as_ref()], - &main_router::id(), - ), - *signer_account.key, - ), - _ => ((main_router_multisig::id(), 0), main_router_admin::id()), - }; - - // validate signature and accounts - if multisig_account.key != &expected_multisig_account { - msg!("Error: Invalid multisig account"); - return Err(FarmError::IncorrectAccountAddress.into()); - } - - let signatures_left = multisig::sign_multisig( - multisig_account, - signer_account, - &fallback_admin_account, - &accounts[1..], - instruction_data, - )?; - if signatures_left > 0 { - msg!( - "Instruction has been signed but more signatures are required: {}", - signatures_left - ); - return Ok(()); - } - - // process instruction - match instruction { - MainInstruction::AddVault { vault } => add_vault(program_id, accounts, &vault)?, - MainInstruction::RemoveVault { name, refdb_index } => { - remove_vault(program_id, accounts, &name, refdb_index)? - } - MainInstruction::AddPool { pool } => add_pool(program_id, accounts, &pool)?, - MainInstruction::RemovePool { name, refdb_index } => { - remove_pool(program_id, accounts, &name, refdb_index)? - } - MainInstruction::AddFarm { farm } => add_farm(program_id, accounts, &farm)?, - MainInstruction::RemoveFarm { name, refdb_index } => { - remove_farm(program_id, accounts, &name, refdb_index)? - } - MainInstruction::AddFund { fund } => add_fund(program_id, accounts, &fund)?, - MainInstruction::RemoveFund { name, refdb_index } => { - remove_fund(program_id, accounts, &name, refdb_index)? - } - MainInstruction::AddToken { token } => add_token(program_id, accounts, &token)?, - MainInstruction::RemoveToken { name, refdb_index } => { - remove_token(program_id, accounts, &name, refdb_index)? - } - MainInstruction::RefDbInstruction { instruction } => { - process_refdb_instruction(program_id, accounts, instruction)? - } - MainInstruction::SetAdminSigners { min_signatures } => { - set_admin_signers(program_id, accounts, min_signatures)? - } - MainInstruction::SetProgramAdminSigners { min_signatures } => { - set_program_admin_signers(program_id, accounts, min_signatures)? - } - MainInstruction::SetProgramSingleAuthority => { - set_program_single_authority(program_id, accounts, multisig_bump)? - } - MainInstruction::UpgradeProgram => upgrade_program(program_id, accounts, multisig_bump)?, - } - - sol_log_compute_units(); - msg!("Main router end of instruction"); - Ok(()) -} diff --git a/farms/router-main/src/refdb_init.rs b/farms/router-main/src/refdb_init.rs deleted file mode 100644 index 84984ea888a..00000000000 --- a/farms/router-main/src/refdb_init.rs +++ /dev/null @@ -1,110 +0,0 @@ -//! Common accounts management functions - -use { - solana_farm_sdk::{ - program::pda, - refdb, - refdb::RefDB, - string::{str_to_as64, ArrayString64}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - pubkey::Pubkey, - }, -}; - -pub fn check_or_init_refdb<'a, 'b>( - program_id: &Pubkey, - signer_account: &'a AccountInfo<'b>, - refdb_account: &'a AccountInfo<'b>, - storage_type: refdb::StorageType, - storage_size: usize, - delete_mode: bool, -) -> ProgramResult { - msg!("Executing check_or_init_refdb"); - - // check address - let type_name = storage_type.to_string(); - let (derived_address, bump_seed) = refdb::find_refdb_pda(&type_name); - - if derived_address != *refdb_account.key { - msg!("Error: Invalid RefDB account"); - return Err(ProgramError::InvalidArgument); - } - let seeds = &[type_name.as_bytes(), &[bump_seed]]; - - // check if account is initialized - let data_size = if storage_size > 0 { - storage_size - } else if !refdb_account.data_is_empty() { - refdb_account.data_len() - } else { - refdb::StorageType::get_storage_size_for_max_records( - storage_type, - refdb::ReferenceType::Pubkey, - ) - }; - - if !delete_mode { - pda::check_pda_data_size(refdb_account, seeds, data_size, refdb::REFDB_ONCHAIN_INIT)?; - pda::check_pda_rent_exempt( - signer_account, - refdb_account, - seeds, - data_size, - refdb::REFDB_ONCHAIN_INIT, - )?; - } - pda::check_pda_owner(program_id, refdb_account, seeds, refdb::REFDB_ONCHAIN_INIT)?; - - if !delete_mode { - // check or init storage - let data = &mut refdb_account.try_borrow_mut_data()?; - if !RefDB::is_initialized(data) { - msg!("Executing RefDB::init for {}", type_name); - RefDB::init( - data, - &str_to_as64(&type_name)?, - refdb::ReferenceType::Pubkey, - )?; - msg!("RefDB::init complete"); - } - } - - msg!("check_or_init_refdb complete"); - - Ok(()) -} - -pub fn check_or_init_refdb_target<'a, 'b>( - program_id: &Pubkey, - signer_account: &'a AccountInfo<'b>, - target_account: &'a AccountInfo<'b>, - storage_type: refdb::StorageType, - data_name: &ArrayString64, - data_size: usize, - delete_mode: bool, -) -> ProgramResult { - msg!("Executing check_or_init_refdb_target"); - - // check address - let type_name = storage_type.to_string(); - let (derived_address, bump_seed) = refdb::find_target_pda(storage_type, data_name); - - if derived_address != *target_account.key { - msg!("Error: Invalid target RefDB account"); - return Err(ProgramError::InvalidArgument); - } - let seeds = &[type_name.as_bytes(), data_name.as_bytes(), &[bump_seed]]; - - if !delete_mode { - pda::check_pda_data_size(target_account, seeds, data_size, true)?; - pda::check_pda_rent_exempt(signer_account, target_account, seeds, data_size, true)?; - } - - pda::check_pda_owner(program_id, target_account, seeds, true)?; - - msg!("check_or_init_refdb_target complete"); - - Ok(()) -} diff --git a/farms/router-main/src/refdb_instruction.rs b/farms/router-main/src/refdb_instruction.rs deleted file mode 100644 index 154cb52d98d..00000000000 --- a/farms/router-main/src/refdb_instruction.rs +++ /dev/null @@ -1,78 +0,0 @@ -//! Processes raw RefDB instruction - -use { - solana_farm_sdk::{ - instruction::refdb::RefDbInstruction, - program::{account, pda}, - refdb, - refdb::RefDB, - }, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - program_error::ProgramError, - pubkey::Pubkey, - }, -}; - -pub fn process_refdb_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - instruction: RefDbInstruction, -) -> ProgramResult { - msg!("Processing MainInstruction::RefDbInstruction"); - - let accounts_iter = &mut accounts.iter(); - - let signer_account = next_account_info(accounts_iter)?; - let _multisig_account = next_account_info(accounts_iter)?; - let refdb_account = next_account_info(accounts_iter)?; - - match instruction { - RefDbInstruction::Init { - name, - reference_type, - max_records, - init_account, - } => { - if max_records == 0 { - return Err(ProgramError::InvalidArgument); - } - if init_account { - let (derived_address, bump_seed) = - Pubkey::find_program_address(&[name.as_bytes()], program_id); - if derived_address != *refdb_account.key { - return Err(ProgramError::IncorrectProgramId); - } - let seeds = &[name.as_bytes(), &[bump_seed]]; - - let data_size = refdb::StorageType::get_storage_size_for_records( - reference_type, - max_records as usize, - ); - pda::check_pda_data_size(refdb_account, seeds, data_size, true)?; - pda::check_pda_rent_exempt(signer_account, refdb_account, seeds, data_size, true)?; - pda::check_pda_owner(program_id, refdb_account, seeds, true)?; - } - RefDB::init(*refdb_account.try_borrow_mut_data()?, &name, reference_type)?; - } - RefDbInstruction::Drop { close_account } => { - if close_account { - account::close_system_account(signer_account, refdb_account, program_id)?; - } else { - let _ = RefDB::drop(*refdb_account.try_borrow_mut_data()?)?; - } - } - RefDbInstruction::Write { record } => { - RefDB::write(*refdb_account.try_borrow_mut_data()?, &record).map(|_v| ())?; - } - RefDbInstruction::Delete { record } => { - RefDB::delete(*refdb_account.try_borrow_mut_data()?, &record).map(|_v| ())?; - } - }; - - msg!("MainInstruction::RefDbInstruction complete"); - - Ok(()) -} diff --git a/farms/router-main/src/remove_farm.rs b/farms/router-main/src/remove_farm.rs deleted file mode 100644 index 26a35db8fee..00000000000 --- a/farms/router-main/src/remove_farm.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! Removes Farm's metadata from chain - -use { - crate::refdb_init::{check_or_init_refdb, check_or_init_refdb_target}, - solana_farm_sdk::{ - program::account::close_system_account, refdb, refdb::RefDB, string::ArrayString64, - }, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - pubkey::Pubkey, - }, -}; - -pub fn remove_farm( - program_id: &Pubkey, - accounts: &[AccountInfo], - name: &ArrayString64, - refdb_index: Option, -) -> ProgramResult { - msg!("Processing MainInstruction::RemoveFarm"); - - // validate accounts - let accounts_iter = &mut accounts.iter(); - - let signer_account = next_account_info(accounts_iter)?; - let _multisig_account = next_account_info(accounts_iter)?; - let refdb_account = next_account_info(accounts_iter)?; - let target_account = next_account_info(accounts_iter)?; - - check_or_init_refdb( - program_id, - signer_account, - refdb_account, - refdb::StorageType::Farm, - 0, - true, - )?; - check_or_init_refdb_target( - program_id, - signer_account, - target_account, - refdb::StorageType::Farm, - name, - 0, - true, - )?; - - // update ref storage - msg!("Updating refdb storage"); - let _ = RefDB::delete_with_name(*refdb_account.try_borrow_mut_data()?, name, refdb_index); - - // close metadata account - msg!("Closing metadata account"); - close_system_account(signer_account, target_account, program_id)?; - - msg!("RemoveFarm complete"); - - Ok(()) -} diff --git a/farms/router-main/src/remove_fund.rs b/farms/router-main/src/remove_fund.rs deleted file mode 100644 index ad885e177eb..00000000000 --- a/farms/router-main/src/remove_fund.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! Removes Fund's metadata from chain - -use { - crate::refdb_init::{check_or_init_refdb, check_or_init_refdb_target}, - solana_farm_sdk::{ - program::account::close_system_account, refdb, refdb::RefDB, string::ArrayString64, - }, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - pubkey::Pubkey, - }, -}; - -pub fn remove_fund( - program_id: &Pubkey, - accounts: &[AccountInfo], - name: &ArrayString64, - refdb_index: Option, -) -> ProgramResult { - msg!("Processing MainInstruction::RemoveFund"); - - // validate accounts - let accounts_iter = &mut accounts.iter(); - - let signer_account = next_account_info(accounts_iter)?; - let _multisig_account = next_account_info(accounts_iter)?; - let refdb_account = next_account_info(accounts_iter)?; - let target_account = next_account_info(accounts_iter)?; - - check_or_init_refdb( - program_id, - signer_account, - refdb_account, - refdb::StorageType::Fund, - 0, - true, - )?; - check_or_init_refdb_target( - program_id, - signer_account, - target_account, - refdb::StorageType::Fund, - name, - 0, - true, - )?; - - // update ref storage - msg!("Updating refdb storage"); - let _ = RefDB::delete_with_name(*refdb_account.try_borrow_mut_data()?, name, refdb_index); - - // close metadata account - msg!("Closing metadata account"); - close_system_account(signer_account, target_account, program_id)?; - - msg!("RemoveFund complete"); - - Ok(()) -} diff --git a/farms/router-main/src/remove_pool.rs b/farms/router-main/src/remove_pool.rs deleted file mode 100644 index 49e9f943ed8..00000000000 --- a/farms/router-main/src/remove_pool.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! Removes Pool's metadata from chain - -use { - crate::refdb_init::{check_or_init_refdb, check_or_init_refdb_target}, - solana_farm_sdk::{ - program::account::close_system_account, refdb, refdb::RefDB, string::ArrayString64, - }, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - pubkey::Pubkey, - }, -}; - -pub fn remove_pool( - program_id: &Pubkey, - accounts: &[AccountInfo], - name: &ArrayString64, - refdb_index: Option, -) -> ProgramResult { - msg!("Processing MainInstruction::RemovePool"); - - // validate accounts - let accounts_iter = &mut accounts.iter(); - - let signer_account = next_account_info(accounts_iter)?; - let _multisig_account = next_account_info(accounts_iter)?; - let refdb_account = next_account_info(accounts_iter)?; - let target_account = next_account_info(accounts_iter)?; - - check_or_init_refdb( - program_id, - signer_account, - refdb_account, - refdb::StorageType::Pool, - 0, - true, - )?; - check_or_init_refdb_target( - program_id, - signer_account, - target_account, - refdb::StorageType::Pool, - name, - 0, - true, - )?; - - // update ref storage - msg!("Updating refdb storage"); - let _ = RefDB::delete_with_name(*refdb_account.try_borrow_mut_data()?, name, refdb_index); - - // close metadata account - msg!("Closing metadata account"); - close_system_account(signer_account, target_account, program_id)?; - - msg!("RemovePool complete"); - - Ok(()) -} diff --git a/farms/router-main/src/remove_token.rs b/farms/router-main/src/remove_token.rs deleted file mode 100644 index 25d564f8d4b..00000000000 --- a/farms/router-main/src/remove_token.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! Removes Token's metadata from chain - -use { - crate::refdb_init::{check_or_init_refdb, check_or_init_refdb_target}, - solana_farm_sdk::{ - program::account::close_system_account, refdb, refdb::RefDB, string::ArrayString64, - }, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - pubkey::Pubkey, - }, -}; - -pub fn remove_token( - program_id: &Pubkey, - accounts: &[AccountInfo], - name: &ArrayString64, - refdb_index: Option, -) -> ProgramResult { - msg!("Processing MainInstruction::RemoveToken"); - - // validate accounts - let accounts_iter = &mut accounts.iter(); - - let signer_account = next_account_info(accounts_iter)?; - let _multisig_account = next_account_info(accounts_iter)?; - let refdb_account = next_account_info(accounts_iter)?; - let target_account = next_account_info(accounts_iter)?; - - check_or_init_refdb( - program_id, - signer_account, - refdb_account, - refdb::StorageType::Token, - 0, - true, - )?; - check_or_init_refdb_target( - program_id, - signer_account, - target_account, - refdb::StorageType::Token, - name, - 0, - true, - )?; - - // update ref storage - msg!("Updating refdb storage"); - let _ = RefDB::delete_with_name(*refdb_account.try_borrow_mut_data()?, name, refdb_index); - - // close metadata account - msg!("Closing metadata account"); - close_system_account(signer_account, target_account, program_id)?; - - msg!("RemoveToken complete"); - - Ok(()) -} diff --git a/farms/router-main/src/remove_vault.rs b/farms/router-main/src/remove_vault.rs deleted file mode 100644 index f9b731b6448..00000000000 --- a/farms/router-main/src/remove_vault.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! Removes Vault's metadata from chain - -use { - crate::refdb_init::{check_or_init_refdb, check_or_init_refdb_target}, - solana_farm_sdk::{ - program::account::close_system_account, refdb, refdb::RefDB, string::ArrayString64, - }, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - pubkey::Pubkey, - }, -}; - -pub fn remove_vault( - program_id: &Pubkey, - accounts: &[AccountInfo], - name: &ArrayString64, - refdb_index: Option, -) -> ProgramResult { - msg!("Processing MainInstruction::RemoveVault"); - - // validate accounts - let accounts_iter = &mut accounts.iter(); - - let signer_account = next_account_info(accounts_iter)?; - let _multisig_account = next_account_info(accounts_iter)?; - let refdb_account = next_account_info(accounts_iter)?; - let target_account = next_account_info(accounts_iter)?; - - check_or_init_refdb( - program_id, - signer_account, - refdb_account, - refdb::StorageType::Vault, - 0, - true, - )?; - check_or_init_refdb_target( - program_id, - signer_account, - target_account, - refdb::StorageType::Vault, - name, - 0, - true, - )?; - - // update ref storage - msg!("Updating refdb storage"); - let _ = RefDB::delete_with_name(*refdb_account.try_borrow_mut_data()?, name, refdb_index); - - // close metadata account - msg!("Closing metadata account"); - close_system_account(signer_account, target_account, program_id)?; - - msg!("RemoveVault complete"); - - Ok(()) -} diff --git a/farms/router-main/src/set_admin_signers.rs b/farms/router-main/src/set_admin_signers.rs deleted file mode 100644 index cc335ac9433..00000000000 --- a/farms/router-main/src/set_admin_signers.rs +++ /dev/null @@ -1,48 +0,0 @@ -//! Initializes Main Router multisig with a new set of admin signatures - -use { - solana_farm_sdk::{ - id::main_router, - program::{account, multisig, multisig::Multisig, pda}, - }, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - pubkey::Pubkey, - }, -}; - -pub fn set_admin_signers( - _program_id: &Pubkey, - accounts: &[AccountInfo], - min_signatures: u8, -) -> ProgramResult { - msg!("Processing MainInstruction::SetAdminSigners"); - - let accounts_iter = &mut accounts.iter(); - - let signer_account = next_account_info(accounts_iter)?; - let multisig_account = next_account_info(accounts_iter)?; - let _system_program = next_account_info(accounts_iter)?; - - if account::is_empty(multisig_account)? { - msg!("Init multisig account"); - let seeds: &[&[u8]] = &[b"multisig"]; - let _bump = pda::init_system_account( - signer_account, - multisig_account, - &main_router::id(), - &main_router::id(), - seeds, - Multisig::LEN, - )?; - } else { - msg!("Update multisig account"); - } - multisig::set_signers(multisig_account, accounts_iter.as_slice(), min_signatures)?; - - msg!("SetAdminSigners complete"); - - Ok(()) -} diff --git a/farms/router-main/src/set_program_admin_signers.rs b/farms/router-main/src/set_program_admin_signers.rs deleted file mode 100644 index 986af6ca6aa..00000000000 --- a/farms/router-main/src/set_program_admin_signers.rs +++ /dev/null @@ -1,69 +0,0 @@ -//! Initializes program multisig with a new set of admin signatures - -use { - solana_farm_sdk::{ - id::main_router, - program::{account, multisig, multisig::Multisig, pda}, - }, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - bpf_loader_upgradeable, - entrypoint::ProgramResult, - msg, - program::invoke, - pubkey::Pubkey, - }, -}; - -pub fn set_program_admin_signers( - _program_id: &Pubkey, - accounts: &[AccountInfo], - min_signatures: u8, -) -> ProgramResult { - msg!("Processing MainInstruction::SetProgramAdminSigners"); - - let accounts_iter = &mut accounts.iter(); - - let signer_account = next_account_info(accounts_iter)?; - let multisig_account = next_account_info(accounts_iter)?; - let target_program = next_account_info(accounts_iter)?; - let program_buffer = next_account_info(accounts_iter)?; - let _system_program = next_account_info(accounts_iter)?; - let _bpf_loader = next_account_info(accounts_iter)?; - - if account::is_empty(multisig_account)? { - // create new multisig account - msg!("Init multisig account"); - let seeds: &[&[u8]] = &[b"multisig", target_program.key.as_ref()]; - let _bump = pda::init_system_account( - signer_account, - multisig_account, - &main_router::id(), - &main_router::id(), - seeds, - Multisig::LEN, - )?; - - // change program upgrade authority to multisig - let instruction = bpf_loader_upgradeable::set_buffer_authority( - program_buffer.key, - signer_account.key, - multisig_account.key, - ); - invoke( - &instruction, - &[ - program_buffer.clone(), - signer_account.clone(), - multisig_account.clone(), - ], - )?; - } else { - msg!("Update multisig account"); - } - multisig::set_signers(multisig_account, accounts_iter.as_slice(), min_signatures)?; - - msg!("SetProgramAdminSigners complete"); - - Ok(()) -} diff --git a/farms/router-main/src/set_program_single_authority.rs b/farms/router-main/src/set_program_single_authority.rs deleted file mode 100644 index 6dc1a55179c..00000000000 --- a/farms/router-main/src/set_program_single_authority.rs +++ /dev/null @@ -1,76 +0,0 @@ -//! Sets single upgrade authority for the program removing multisig if present - -use { - solana_farm_sdk::{id::zero, program::account}, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - bpf_loader_upgradeable, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - loader_upgradeable_instruction::UpgradeableLoaderInstruction, - msg, - program::{invoke, invoke_signed}, - pubkey::Pubkey, - }, -}; - -pub fn set_program_single_authority( - program_id: &Pubkey, - accounts: &[AccountInfo], - multisig_bump: u8, -) -> ProgramResult { - msg!("Processing MainInstruction::SetProgramSingleAuthority"); - - let accounts_iter = &mut accounts.iter(); - - let signer_account = next_account_info(accounts_iter)?; - let multisig_account = next_account_info(accounts_iter)?; - let target_program = next_account_info(accounts_iter)?; - let program_buffer = next_account_info(accounts_iter)?; - let new_authority = next_account_info(accounts_iter)?; - - let current_authority = if account::is_empty(multisig_account)? { - signer_account.key - } else { - multisig_account.key - }; - - let mut metas = vec![ - AccountMeta::new(*program_buffer.key, false), - AccountMeta::new_readonly(*current_authority, true), - ]; - if new_authority.key != &zero::id() { - metas.push(AccountMeta::new_readonly(*new_authority.key, false)); - } - let instruction = Instruction::new_with_bincode( - bpf_loader_upgradeable::id(), - &UpgradeableLoaderInstruction::SetAuthority, - metas, - ); - - if account::is_empty(multisig_account)? { - invoke( - &instruction, - &[ - program_buffer.clone(), - signer_account.clone(), - new_authority.clone(), - ], - )?; - } else { - invoke_signed( - &instruction, - &[ - program_buffer.clone(), - multisig_account.clone(), - new_authority.clone(), - ], - &[&[b"multisig", target_program.key.as_ref(), &[multisig_bump]]], - )?; - account::close_system_account(signer_account, multisig_account, program_id)?; - } - - msg!("SetProgramSingleAuthority complete"); - - Ok(()) -} diff --git a/farms/router-main/src/upgrade_program.rs b/farms/router-main/src/upgrade_program.rs deleted file mode 100644 index 0e8ca210e18..00000000000 --- a/farms/router-main/src/upgrade_program.rs +++ /dev/null @@ -1,87 +0,0 @@ -//! Upgrades the program from the buffer - -use { - solana_farm_sdk::program::account, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - bpf_loader_upgradeable, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - loader_upgradeable_instruction::UpgradeableLoaderInstruction, - msg, - program::{invoke, invoke_signed}, - pubkey::Pubkey, - sysvar, - }, -}; - -pub fn upgrade_program( - _program_id: &Pubkey, - accounts: &[AccountInfo], - multisig_bump: u8, -) -> ProgramResult { - msg!("Processing MainInstruction::UpgradeProgram"); - - let accounts_iter = &mut accounts.iter(); - - let signer_account = next_account_info(accounts_iter)?; - let multisig_account = next_account_info(accounts_iter)?; - let target_program = next_account_info(accounts_iter)?; - let program_buffer = next_account_info(accounts_iter)?; - let source_buffer = next_account_info(accounts_iter)?; - let rent_program = next_account_info(accounts_iter)?; - let clock_program = next_account_info(accounts_iter)?; - - let current_authority = if account::is_empty(multisig_account)? { - signer_account.key - } else { - multisig_account.key - }; - - let instruction = Instruction::new_with_bincode( - bpf_loader_upgradeable::id(), - &UpgradeableLoaderInstruction::Upgrade, - vec![ - AccountMeta::new(*program_buffer.key, false), - AccountMeta::new(*target_program.key, false), - AccountMeta::new(*source_buffer.key, false), - AccountMeta::new(*signer_account.key, false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - AccountMeta::new_readonly(*current_authority, true), - ], - ); - - if account::is_empty(multisig_account)? { - invoke( - &instruction, - &[ - program_buffer.clone(), - target_program.clone(), - source_buffer.clone(), - signer_account.clone(), - rent_program.clone(), - clock_program.clone(), - signer_account.clone(), - ], - )?; - } else { - invoke_signed( - &instruction, - &[ - program_buffer.clone(), - target_program.clone(), - source_buffer.clone(), - signer_account.clone(), - rent_program.clone(), - clock_program.clone(), - multisig_account.clone(), - ], - &[&[b"multisig", target_program.key.as_ref(), &[multisig_bump]]], - )?; - } - - msg!("UpgradeProgram complete"); - - Ok(()) -} diff --git a/farms/router-orca/.gitignore b/farms/router-orca/.gitignore deleted file mode 100644 index da0b2a84eb6..00000000000 --- a/farms/router-orca/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/target -/include -Cargo.lock diff --git a/farms/router-orca/Cargo.toml b/farms/router-orca/Cargo.toml deleted file mode 100644 index 7ce4f96bd25..00000000000 --- a/farms/router-orca/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "solana-router-orca" -version = "1.1.3" -description = "Solana Orca Router" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana-program-library/farms" -license = "Apache-2.0" -homepage = "https://solana.com/" -edition = "2021" - -[features] -no-entrypoint = [] -debug = [] - -[dependencies] -solana-farm-sdk = "1.1.3" -solana-program = "1.9.18" -solana-security-txt = "1.0.1" -arrayref = "0.3.6" -spl-token-swap = { version = "2.1.0", features = ["no-entrypoint"] } -spl-token = { version = "3.2.0", features = ["no-entrypoint"] } - -[dev-dependencies] -solana-program-test = "1.9.18" - -[lib] -crate-type = ["cdylib", "lib"] - diff --git a/farms/router-orca/README.md b/farms/router-orca/README.md deleted file mode 120000 index ccd27901fd5..00000000000 --- a/farms/router-orca/README.md +++ /dev/null @@ -1 +0,0 @@ -../docs/crate.md \ No newline at end of file diff --git a/farms/router-orca/Xargo.toml b/farms/router-orca/Xargo.toml deleted file mode 100644 index 1744f098ae1..00000000000 --- a/farms/router-orca/Xargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.bpfel-unknown-unknown.dependencies.std] -features = [] \ No newline at end of file diff --git a/farms/router-orca/src/add_liquidity.rs b/farms/router-orca/src/add_liquidity.rs deleted file mode 100644 index 3a09a8bf757..00000000000 --- a/farms/router-orca/src/add_liquidity.rs +++ /dev/null @@ -1,101 +0,0 @@ -//! Add liquidity to the Orca pool instruction - -use { - solana_farm_sdk::program::{account, protocol::orca}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program::invoke, - program_error::ProgramError, - }, - spl_token_swap::instruction, -}; - -pub fn add_liquidity( - accounts: &[AccountInfo], - max_token_a_amount: u64, - max_token_b_amount: u64, -) -> ProgramResult { - msg!("Processing AmmInstruction::AddLiquidity"); - msg!("max_token_a_amount {} ", max_token_a_amount); - msg!("max_token_b_amount {} ", max_token_b_amount); - - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - user_token_a_account, - user_token_b_account, - user_lp_token_account, - pool_program_id, - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - _spl_token_id, - amm_id, - amm_authority - ] = accounts - { - if !orca::check_pool_program_id(pool_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - if !account::check_token_account_owner(user_lp_token_account, user_account.key)? { - return Err(ProgramError::IllegalOwner); - } - - let (lp_token_amount, token_a_amount, token_b_amount) = orca::get_pool_deposit_amounts( - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - max_token_a_amount, - max_token_b_amount, - )?; - - let initial_token_a_user_balance = account::get_token_balance(user_token_a_account)?; - let initial_token_b_user_balance = account::get_token_balance(user_token_b_account)?; - let initial_lp_token_user_balance = account::get_token_balance(user_lp_token_account)?; - - let data = instruction::DepositAllTokenTypes { - pool_token_amount: lp_token_amount, - maximum_token_a_amount: token_a_amount, - maximum_token_b_amount: token_b_amount, - }; - - msg!("Deposit tokens into the pool. lp_token_amount: {}, token_a_amount: {}, token_b_amount: {}", lp_token_amount, token_a_amount, token_b_amount); - let instruction = instruction::deposit_all_token_types( - pool_program_id.key, - &spl_token::id(), - amm_id.key, - amm_authority.key, - user_account.key, - user_token_a_account.key, - user_token_b_account.key, - pool_token_a_account.key, - pool_token_b_account.key, - lp_token_mint.key, - user_lp_token_account.key, - data, - )?; - - invoke(&instruction, accounts)?; - - account::check_tokens_spent( - user_token_a_account, - initial_token_a_user_balance, - token_a_amount, - )?; - account::check_tokens_spent( - user_token_b_account, - initial_token_b_user_balance, - token_b_amount, - )?; - account::check_tokens_received( - user_lp_token_account, - initial_lp_token_user_balance, - lp_token_amount, - )?; - } else { - return Err(ProgramError::NotEnoughAccountKeys); - } - - msg!("AmmInstruction::AddLiquidity complete"); - Ok(()) -} diff --git a/farms/router-orca/src/entrypoint.rs b/farms/router-orca/src/entrypoint.rs deleted file mode 100644 index 492afa07f7d..00000000000 --- a/farms/router-orca/src/entrypoint.rs +++ /dev/null @@ -1,25 +0,0 @@ -//! Program entrypoint - -#![cfg(not(feature = "no-entrypoint"))] - -solana_security_txt::security_txt! { - name: "Solana Farms", - project_url: "https://github.com/solana-labs/solana-program-library/tree/master/farms", - contacts: "email:solana.farms@protonmail.com", - policy: "", - preferred_languages: "en", - auditors: "Halborn" -} - -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, pubkey::Pubkey, -}; - -entrypoint!(process_instruction); -fn process_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - instruction_data: &[u8], -) -> ProgramResult { - crate::processor::process_instruction(program_id, accounts, instruction_data) -} diff --git a/farms/router-orca/src/harvest.rs b/farms/router-orca/src/harvest.rs deleted file mode 100644 index 54f87aa5e22..00000000000 --- a/farms/router-orca/src/harvest.rs +++ /dev/null @@ -1,73 +0,0 @@ -//! Harvest rewards from an Orca farm instruction - -use { - solana_farm_sdk::{ - instruction::orca::OrcaHarvest, - program::{account, protocol::orca}, - }, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke, - program_error::ProgramError, - }, -}; - -pub fn harvest(accounts: &[AccountInfo]) -> ProgramResult { - msg!("Processing AmmInstruction::Harvest"); - - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - user_info_account, - user_reward_token_account, - farm_program_id, - base_token_vault, - reward_token_vault, - _spl_token_id, - farm_id, - farm_authority - ] = accounts - { - if !orca::check_stake_program_id(farm_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - if !account::check_token_account_owner(user_reward_token_account, user_account.key)? { - return Err(ProgramError::IllegalOwner); - } - - let initial_reward_token_user_balance = - account::get_token_balance(user_reward_token_account)?; - - let orca_accounts = vec![ - AccountMeta::new_readonly(*user_account.key, true), - AccountMeta::new(*farm_id.key, false), - AccountMeta::new(*user_info_account.key, false), - AccountMeta::new_readonly(*base_token_vault.key, false), - AccountMeta::new(*reward_token_vault.key, false), - AccountMeta::new(*user_reward_token_account.key, false), - AccountMeta::new_readonly(*farm_authority.key, false), - AccountMeta::new_readonly(spl_token::id(), false), - ]; - - let instruction = Instruction { - program_id: *farm_program_id.key, - accounts: orca_accounts, - data: OrcaHarvest {}.to_vec()?, - }; - invoke(&instruction, accounts)?; - - let _ = account::get_balance_increase( - user_reward_token_account, - initial_reward_token_user_balance, - )?; - } else { - return Err(ProgramError::NotEnoughAccountKeys); - } - - msg!("AmmInstruction::Stake complete"); - Ok(()) -} diff --git a/farms/router-orca/src/lib.rs b/farms/router-orca/src/lib.rs deleted file mode 100644 index 072fa799218..00000000000 --- a/farms/router-orca/src/lib.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![forbid(unsafe_code)] - -pub mod add_liquidity; -mod entrypoint; -pub mod harvest; -pub mod processor; -pub mod remove_liquidity; -pub mod stake; -pub mod swap; -pub mod unstake; -pub mod user_init; diff --git a/farms/router-orca/src/processor.rs b/farms/router-orca/src/processor.rs deleted file mode 100644 index 389778fbdba..00000000000 --- a/farms/router-orca/src/processor.rs +++ /dev/null @@ -1,60 +0,0 @@ -//! Orca router implementation. - -use { - crate::{ - add_liquidity::add_liquidity, harvest::harvest, remove_liquidity::remove_liquidity, - stake::stake, swap::swap, unstake::unstake, user_init::user_init, - }, - solana_farm_sdk::{instruction::amm::AmmInstruction, log::sol_log_params_short}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, log::sol_log_compute_units, msg, - pubkey::Pubkey, - }, -}; - -/// Program's entrypoint. -/// -/// # Arguments -/// * `program_id` - Public key of the router. -/// * `accounts` - Accounts, see particular instruction handler for the list. -/// * `instructions_data` - Packed AmmInstruction. -pub fn process_instruction( - _program_id: &Pubkey, - accounts: &[AccountInfo], - instruction_data: &[u8], -) -> ProgramResult { - msg!("Orca router entrypoint"); - if cfg!(feature = "debug") { - sol_log_params_short(accounts, instruction_data); - } - - // Read and unpack instruction data - let instruction = AmmInstruction::unpack(instruction_data)?; - - match instruction { - AmmInstruction::UserInit => user_init(accounts)?, - AmmInstruction::AddLiquidity { - max_token_a_amount, - max_token_b_amount, - } => add_liquidity(accounts, max_token_a_amount, max_token_b_amount)?, - AmmInstruction::RemoveLiquidity { amount } => remove_liquidity(accounts, amount)?, - AmmInstruction::Swap { - token_a_amount_in, - token_b_amount_in, - min_token_amount_out, - } => swap( - accounts, - token_a_amount_in, - token_b_amount_in, - min_token_amount_out, - )?, - AmmInstruction::Stake { amount } => stake(accounts, amount)?, - AmmInstruction::Unstake { amount } => unstake(accounts, amount)?, - AmmInstruction::Harvest => harvest(accounts)?, - _ => {} - } - - sol_log_compute_units(); - msg!("Orca router end of instruction"); - Ok(()) -} diff --git a/farms/router-orca/src/remove_liquidity.rs b/farms/router-orca/src/remove_liquidity.rs deleted file mode 100644 index 4ba416ce100..00000000000 --- a/farms/router-orca/src/remove_liquidity.rs +++ /dev/null @@ -1,110 +0,0 @@ -//! Remove liquidity from the Orca pool instruction - -use { - solana_farm_sdk::program::{account, protocol::orca}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program::invoke, - program_error::ProgramError, - }, - spl_token_swap::instruction, -}; - -pub fn remove_liquidity(accounts: &[AccountInfo], amount: u64) -> ProgramResult { - msg!("Processing AmmInstruction::RemoveLiquidity"); - msg!("amount {} ", amount); - - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - user_token_a_account, - user_token_b_account, - user_lp_token_account, - pool_program_id, - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - _spl_token_id, - amm_id, - amm_authority, - fees_account - ] = accounts - { - if !orca::check_pool_program_id(pool_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - if !account::check_token_account_owner(user_token_a_account, user_account.key)? - || !account::check_token_account_owner(user_token_b_account, user_account.key)? - { - return Err(ProgramError::IllegalOwner); - } - - let initial_token_a_user_balance = account::get_token_balance(user_token_a_account)?; - let initial_token_b_user_balance = account::get_token_balance(user_token_b_account)?; - let initial_lp_token_user_balance = account::get_token_balance(user_lp_token_account)?; - - let lp_amount = if amount > 0 { - amount - } else { - account::get_token_balance(user_lp_token_account)? - }; - - let (token_a_amount, token_b_amount) = orca::get_pool_withdrawal_amounts( - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - lp_amount, - )?; - - let data = instruction::WithdrawAllTokenTypes { - pool_token_amount: lp_amount, - minimum_token_a_amount: token_a_amount, - minimum_token_b_amount: token_b_amount, - }; - - msg!( - "Removing tokens from the pool. lp_amount: {}, token_a_amount: {}, token_b_amount: {}", - lp_amount, - token_a_amount, - token_b_amount - ); - let instruction = instruction::withdraw_all_token_types( - pool_program_id.key, - &spl_token::id(), - amm_id.key, - amm_authority.key, - user_account.key, - lp_token_mint.key, - fees_account.key, - user_lp_token_account.key, - pool_token_a_account.key, - pool_token_b_account.key, - user_token_a_account.key, - user_token_b_account.key, - data, - )?; - - invoke(&instruction, accounts)?; - - account::check_tokens_spent( - user_lp_token_account, - initial_lp_token_user_balance, - lp_amount, - )?; - account::check_tokens_received( - user_token_a_account, - initial_token_a_user_balance, - token_a_amount, - )?; - account::check_tokens_received( - user_token_b_account, - initial_token_b_user_balance, - token_b_amount, - )?; - } else { - return Err(ProgramError::NotEnoughAccountKeys); - } - - msg!("AmmInstruction::RemoveLiquidity complete"); - Ok(()) -} diff --git a/farms/router-orca/src/stake.rs b/farms/router-orca/src/stake.rs deleted file mode 100644 index 09c022296d3..00000000000 --- a/farms/router-orca/src/stake.rs +++ /dev/null @@ -1,101 +0,0 @@ -//! Stake LP tokens to an Orca farm instruction - -use { - solana_farm_sdk::{ - instruction::orca::OrcaStake, - program::{account, protocol::orca}, - }, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke, - program_error::ProgramError, - }, -}; - -pub fn stake(accounts: &[AccountInfo], amount: u64) -> ProgramResult { - msg!("Processing AmmInstruction::Stake"); - msg!("amount {} ", amount); - - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - user_info_account, - user_lp_token_account, - user_reward_token_account, - user_farm_lp_token_account, - farm_lp_token_mint, - farm_program_id, - base_token_vault, - reward_token_vault, - _spl_token_id, - farm_id, - farm_authority - ] = accounts - { - if !orca::check_stake_program_id(farm_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - if !account::check_token_account_owner(user_reward_token_account, user_account.key)? - || !account::check_token_account_owner(user_farm_lp_token_account, user_account.key)? - { - return Err(ProgramError::IllegalOwner); - } - - let initial_reward_token_user_balance = - account::get_token_balance(user_reward_token_account)?; - let initial_lp_token_user_balance = account::get_token_balance(user_lp_token_account)?; - let initial_farm_token_user_balance = - account::get_token_balance(user_farm_lp_token_account)?; - - let lp_amount = if amount > 0 { - amount - } else { - initial_lp_token_user_balance - }; - - let orca_accounts = vec![ - AccountMeta::new_readonly(*user_account.key, true), - AccountMeta::new(*user_lp_token_account.key, false), - AccountMeta::new(*base_token_vault.key, false), - AccountMeta::new_readonly(*user_account.key, true), - AccountMeta::new(*farm_lp_token_mint.key, false), - AccountMeta::new(*user_farm_lp_token_account.key, false), - AccountMeta::new(*farm_id.key, false), - AccountMeta::new(*user_info_account.key, false), - AccountMeta::new(*reward_token_vault.key, false), - AccountMeta::new(*user_reward_token_account.key, false), - AccountMeta::new_readonly(*farm_authority.key, false), - AccountMeta::new_readonly(spl_token::id(), false), - ]; - - let instruction = Instruction { - program_id: *farm_program_id.key, - accounts: orca_accounts, - data: OrcaStake { amount: lp_amount }.to_vec()?, - }; - invoke(&instruction, accounts)?; - - account::check_tokens_spent( - user_lp_token_account, - initial_lp_token_user_balance, - lp_amount, - )?; - let _ = account::get_balance_increase( - user_reward_token_account, - initial_reward_token_user_balance, - )?; - let _ = account::get_balance_increase( - user_farm_lp_token_account, - initial_farm_token_user_balance, - )?; - } else { - return Err(ProgramError::NotEnoughAccountKeys); - } - - msg!("AmmInstruction::Stake complete"); - Ok(()) -} diff --git a/farms/router-orca/src/swap.rs b/farms/router-orca/src/swap.rs deleted file mode 100644 index 63c836c0c61..00000000000 --- a/farms/router-orca/src/swap.rs +++ /dev/null @@ -1,137 +0,0 @@ -//! Swap tokens with the Orca pool instruction - -use { - solana_farm_sdk::program::{account, protocol::orca}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program::invoke, - program_error::ProgramError, - }, - spl_token_swap::instruction, -}; - -pub fn swap( - accounts: &[AccountInfo], - token_a_amount_in: u64, - token_b_amount_in: u64, - min_token_amount_out: u64, -) -> ProgramResult { - msg!("Processing AmmInstruction::Swap"); - msg!("token_a_amount_in {} ", token_a_amount_in); - msg!("token_b_amount_in {} ", token_b_amount_in); - msg!("min_token_amount_out {} ", min_token_amount_out); - - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - user_token_a_account, - user_token_b_account, - pool_program_id, - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - _spl_token_id, - amm_id, - amm_authority, - fees_account - ] = accounts - { - if !orca::check_pool_program_id(pool_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - - let (amount_in, mut min_amount_out) = orca::get_pool_swap_amounts( - pool_token_a_account, - pool_token_b_account, - token_a_amount_in, - token_b_amount_in, - )?; - if min_token_amount_out > min_amount_out { - min_amount_out = min_token_amount_out; - } - if amount_in == 0 || min_amount_out == 0 { - msg!("Nothing to do: Not enough tokens to swap"); - return Ok(()); - } - - let data = instruction::Swap { - amount_in, - minimum_amount_out: min_amount_out, - }; - - msg!( - "Swap tokens in the pool. amount_in: {}, min_amount_out: {}", - amount_in, - min_amount_out - ); - - if token_a_amount_in == 0 { - if !account::check_token_account_owner(user_token_a_account, user_account.key)? { - return Err(ProgramError::IllegalOwner); - } - - let initial_balance_in = account::get_token_balance(user_token_b_account)?; - let initial_balance_out = account::get_token_balance(user_token_a_account)?; - - let instruction = instruction::swap( - pool_program_id.key, - &spl_token::id(), - amm_id.key, - amm_authority.key, - user_account.key, - user_token_b_account.key, - pool_token_b_account.key, - pool_token_a_account.key, - user_token_a_account.key, - lp_token_mint.key, - fees_account.key, - None, - data, - )?; - invoke(&instruction, accounts)?; - - account::check_tokens_spent(user_token_b_account, initial_balance_in, amount_in)?; - account::check_tokens_received( - user_token_a_account, - initial_balance_out, - min_amount_out, - )?; - } else { - if !account::check_token_account_owner(user_token_b_account, user_account.key)? { - return Err(ProgramError::IllegalOwner); - } - - let initial_balance_in = account::get_token_balance(user_token_a_account)?; - let initial_balance_out = account::get_token_balance(user_token_b_account)?; - - let instruction = instruction::swap( - pool_program_id.key, - &spl_token::id(), - amm_id.key, - amm_authority.key, - user_account.key, - user_token_a_account.key, - pool_token_a_account.key, - pool_token_b_account.key, - user_token_b_account.key, - lp_token_mint.key, - fees_account.key, - None, - data, - )?; - invoke(&instruction, accounts)?; - - account::check_tokens_spent(user_token_a_account, initial_balance_in, amount_in)?; - account::check_tokens_received( - user_token_b_account, - initial_balance_out, - min_amount_out, - )?; - } - } else { - return Err(ProgramError::NotEnoughAccountKeys); - } - - msg!("AmmInstruction::Swap complete"); - Ok(()) -} diff --git a/farms/router-orca/src/unstake.rs b/farms/router-orca/src/unstake.rs deleted file mode 100644 index 3bb8c9055fc..00000000000 --- a/farms/router-orca/src/unstake.rs +++ /dev/null @@ -1,102 +0,0 @@ -//! Unstake LP tokens from an Orca farm instruction - -use { - solana_farm_sdk::{ - instruction::orca::OrcaUnstake, - program::{account, protocol::orca}, - }, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke, - program_error::ProgramError, - }, -}; - -pub fn unstake(accounts: &[AccountInfo], amount: u64) -> ProgramResult { - msg!("Processing AmmInstruction::Unstake"); - msg!("amount {} ", amount); - - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - user_info_account, - user_lp_token_account, - user_reward_token_account, - user_farm_lp_token_account, - farm_lp_token_mint, - farm_program_id, - base_token_vault, - reward_token_vault, - _spl_token_id, - farm_id, - farm_authority - ] = accounts - { - if !orca::check_stake_program_id(farm_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - if !account::check_token_account_owner(user_lp_token_account, user_account.key)? - || !account::check_token_account_owner(user_reward_token_account, user_account.key)? - { - return Err(ProgramError::IllegalOwner); - } - - let initial_reward_token_user_balance = - account::get_token_balance(user_reward_token_account)?; - let initial_lp_token_user_balance = account::get_token_balance(user_lp_token_account)?; - let initial_farm_token_user_balance = - account::get_token_balance(user_farm_lp_token_account)?; - - let lp_amount = if amount > 0 { - amount - } else { - initial_farm_token_user_balance - }; - - let orca_accounts = vec![ - AccountMeta::new_readonly(*user_account.key, true), - AccountMeta::new(*user_lp_token_account.key, false), - AccountMeta::new(*base_token_vault.key, false), - AccountMeta::new(*farm_lp_token_mint.key, false), - AccountMeta::new(*user_farm_lp_token_account.key, false), - AccountMeta::new_readonly(*user_account.key, true), - AccountMeta::new(*farm_id.key, false), - AccountMeta::new(*user_info_account.key, false), - AccountMeta::new(*reward_token_vault.key, false), - AccountMeta::new(*user_reward_token_account.key, false), - AccountMeta::new_readonly(*farm_authority.key, false), - AccountMeta::new_readonly(spl_token::id(), false), - ]; - - let instruction = Instruction { - program_id: *farm_program_id.key, - accounts: orca_accounts, - data: OrcaUnstake { amount: lp_amount }.to_vec()?, - }; - invoke(&instruction, accounts)?; - - account::check_tokens_received( - user_lp_token_account, - initial_lp_token_user_balance, - lp_amount, - )?; - account::check_tokens_spent( - user_farm_lp_token_account, - initial_farm_token_user_balance, - lp_amount, - )?; - let _ = account::get_balance_increase( - user_reward_token_account, - initial_reward_token_user_balance, - )?; - } else { - return Err(ProgramError::NotEnoughAccountKeys); - } - - msg!("AmmInstruction::Unstake complete"); - Ok(()) -} diff --git a/farms/router-orca/src/user_init.rs b/farms/router-orca/src/user_init.rs deleted file mode 100644 index b783a0f4c81..00000000000 --- a/farms/router-orca/src/user_init.rs +++ /dev/null @@ -1,75 +0,0 @@ -//! Initialize a new user for an Orca farm instruction - -use { - solana_farm_sdk::{ - instruction::orca::OrcaUserInit, - program::{account, protocol::orca}, - }, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke, - program_error::ProgramError, - pubkey::Pubkey, - system_program, - }, -}; - -pub fn user_init(accounts: &[AccountInfo]) -> ProgramResult { - msg!("Processing AmmInstruction::UserInit"); - - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - funding_account, - user_account, - user_info_account, - farm_id, - farm_program_id, - _system_program, - ] = accounts - { - if account::exists(user_info_account)? { - return Err(ProgramError::AccountAlreadyInitialized); - } - if !orca::check_stake_program_id(farm_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - - let farmer_derived = Pubkey::find_program_address( - &[ - &farm_id.key.to_bytes(), - &user_account.key.to_bytes(), - &spl_token::id().to_bytes(), - ], - farm_program_id.key, - ) - .0; - if &farmer_derived != user_info_account.key { - msg!("Error: Invalid Farmer address"); - return Err(ProgramError::InvalidSeeds); - } - - let orca_accounts = vec![ - AccountMeta::new_readonly(*farm_id.key, false), - AccountMeta::new(*user_info_account.key, false), - AccountMeta::new(*funding_account.key, true), - AccountMeta::new_readonly(system_program::id(), false), - ]; - - let instruction = Instruction { - program_id: *farm_program_id.key, - accounts: orca_accounts, - data: OrcaUserInit {}.to_vec()?, - }; - - invoke(&instruction, accounts)?; - } else { - return Err(ProgramError::NotEnoughAccountKeys); - } - - msg!("AmmInstruction::UserInit complete"); - Ok(()) -} diff --git a/farms/router-raydium/.gitignore b/farms/router-raydium/.gitignore deleted file mode 100644 index da0b2a84eb6..00000000000 --- a/farms/router-raydium/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/target -/include -Cargo.lock diff --git a/farms/router-raydium/Cargo.toml b/farms/router-raydium/Cargo.toml deleted file mode 100644 index 47ba7c080ab..00000000000 --- a/farms/router-raydium/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "solana-router-raydium" -version = "1.1.3" -description = "Solana Raydium Router" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana-program-library/farms" -license = "Apache-2.0" -homepage = "https://solana.com/" -edition = "2021" - -[features] -no-entrypoint = [] -debug = [] - -[dependencies] -solana-farm-sdk = "1.1.3" -solana-program = "1.9.18" -solana-security-txt = "1.0.1" -arrayref = "0.3.6" - -[dev-dependencies] -solana-program-test = "1.9.18" - -[lib] -crate-type = ["cdylib", "lib"] - diff --git a/farms/router-raydium/README.md b/farms/router-raydium/README.md deleted file mode 120000 index ccd27901fd5..00000000000 --- a/farms/router-raydium/README.md +++ /dev/null @@ -1 +0,0 @@ -../docs/crate.md \ No newline at end of file diff --git a/farms/router-raydium/Xargo.toml b/farms/router-raydium/Xargo.toml deleted file mode 100644 index 1744f098ae1..00000000000 --- a/farms/router-raydium/Xargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.bpfel-unknown-unknown.dependencies.std] -features = [] \ No newline at end of file diff --git a/farms/router-raydium/src/add_liquidity.rs b/farms/router-raydium/src/add_liquidity.rs deleted file mode 100644 index a06782ed2ce..00000000000 --- a/farms/router-raydium/src/add_liquidity.rs +++ /dev/null @@ -1,113 +0,0 @@ -//! Add liquidity to the Raydium pool instruction - -use { - solana_farm_sdk::{ - instruction::raydium::RaydiumAddLiquidity, - program::{account, protocol::raydium}, - }, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke, - program_error::ProgramError, - }, -}; - -pub fn add_liquidity( - accounts: &[AccountInfo], - max_coin_token_amount: u64, - max_pc_token_amount: u64, -) -> ProgramResult { - msg!("Processing AmmInstruction::AddLiquidity"); - msg!("max_coin_token_amount {} ", max_coin_token_amount); - msg!("max_pc_token_amount {} ", max_pc_token_amount); - - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - user_token_a_account, - user_token_b_account, - user_lp_token_account, - pool_program_id, - pool_coin_token_account, - pool_pc_token_account, - lp_token_mint, - spl_token_id, - amm_id, - amm_authority, - amm_open_orders, - amm_target, - serum_market - ] = accounts - { - if !raydium::check_pool_program_id(pool_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - if !account::check_token_account_owner(user_lp_token_account, user_account.key)? { - return Err(ProgramError::IllegalOwner); - } - - let (lp_token_amount, coin_token_amount, pc_token_amount) = raydium::get_pool_deposit_amounts( - pool_coin_token_account, - pool_pc_token_account, - lp_token_mint, - amm_open_orders, - amm_id, - max_coin_token_amount, - max_pc_token_amount, - )?; - - let initial_token_a_user_balance = account::get_token_balance(user_token_a_account)?; - let initial_token_b_user_balance = account::get_token_balance(user_token_b_account)?; - let initial_lp_token_user_balance = account::get_token_balance(user_lp_token_account)?; - - let raydium_accounts = vec![ - AccountMeta::new_readonly(*spl_token_id.key, false), - AccountMeta::new(*amm_id.key, false), - AccountMeta::new_readonly(*amm_authority.key, false), - AccountMeta::new_readonly(*amm_open_orders.key, false), - AccountMeta::new(*amm_target.key, false), - AccountMeta::new(*lp_token_mint.key, false), - AccountMeta::new(*pool_coin_token_account.key, false), - AccountMeta::new(*pool_pc_token_account.key, false), - AccountMeta::new_readonly(*serum_market.key, false), - AccountMeta::new(*user_token_a_account.key, false), - AccountMeta::new(*user_token_b_account.key, false), - AccountMeta::new(*user_lp_token_account.key, false), - AccountMeta::new_readonly(*user_account.key, true) - ]; - - let instruction = Instruction { - program_id: *pool_program_id.key, - accounts: raydium_accounts, - data: RaydiumAddLiquidity { - instruction: 3, - max_coin_token_amount: coin_token_amount, - max_pc_token_amount: pc_token_amount, - base_side: 0, - } - .to_vec()?, - }; - invoke(&instruction, accounts)?; - - account::check_tokens_spent( - user_token_a_account, - initial_token_a_user_balance, - coin_token_amount, - )?; - account::check_tokens_spent( - user_token_b_account, - initial_token_b_user_balance, - pc_token_amount, - )?; - account::check_tokens_received(user_lp_token_account, initial_lp_token_user_balance, lp_token_amount)?; - } else { - return Err(ProgramError::NotEnoughAccountKeys); - } - - msg!("AmmInstruction::AddLiquidity complete"); - Ok(()) -} diff --git a/farms/router-raydium/src/entrypoint.rs b/farms/router-raydium/src/entrypoint.rs deleted file mode 100644 index 492afa07f7d..00000000000 --- a/farms/router-raydium/src/entrypoint.rs +++ /dev/null @@ -1,25 +0,0 @@ -//! Program entrypoint - -#![cfg(not(feature = "no-entrypoint"))] - -solana_security_txt::security_txt! { - name: "Solana Farms", - project_url: "https://github.com/solana-labs/solana-program-library/tree/master/farms", - contacts: "email:solana.farms@protonmail.com", - policy: "", - preferred_languages: "en", - auditors: "Halborn" -} - -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, pubkey::Pubkey, -}; - -entrypoint!(process_instruction); -fn process_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - instruction_data: &[u8], -) -> ProgramResult { - crate::processor::process_instruction(program_id, accounts, instruction_data) -} diff --git a/farms/router-raydium/src/lib.rs b/farms/router-raydium/src/lib.rs deleted file mode 100644 index c05f02a4389..00000000000 --- a/farms/router-raydium/src/lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![forbid(unsafe_code)] - -pub mod add_liquidity; -mod entrypoint; -pub mod processor; -pub mod remove_liquidity; -pub mod stake; -pub mod swap; -pub mod unstake; -pub mod user_init; diff --git a/farms/router-raydium/src/processor.rs b/farms/router-raydium/src/processor.rs deleted file mode 100644 index 6f16c987844..00000000000 --- a/farms/router-raydium/src/processor.rs +++ /dev/null @@ -1,60 +0,0 @@ -//! Raydium router implementation. - -use { - crate::{ - add_liquidity::add_liquidity, remove_liquidity::remove_liquidity, stake::stake, swap::swap, - unstake::unstake, user_init::user_init, - }, - solana_farm_sdk::{instruction::amm::AmmInstruction, log::sol_log_params_short}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, log::sol_log_compute_units, msg, - pubkey::Pubkey, - }, -}; - -/// Program's entrypoint. -/// -/// # Arguments -/// * `program_id` - Public key of the router. -/// * `accounts` - Accounts, see particular instruction handler for the list. -/// * `instructions_data` - Packed AmmInstruction. -pub fn process_instruction( - _program_id: &Pubkey, - accounts: &[AccountInfo], - instruction_data: &[u8], -) -> ProgramResult { - msg!("Raydium router entrypoint"); - if cfg!(feature = "debug") { - sol_log_params_short(accounts, instruction_data); - } - - // Read and unpack instruction data - let instruction = AmmInstruction::unpack(instruction_data)?; - - match instruction { - AmmInstruction::UserInit => user_init(accounts)?, - AmmInstruction::AddLiquidity { - max_token_a_amount, - max_token_b_amount, - } => add_liquidity(accounts, max_token_a_amount, max_token_b_amount)?, - AmmInstruction::RemoveLiquidity { amount } => remove_liquidity(accounts, amount)?, - AmmInstruction::Swap { - token_a_amount_in, - token_b_amount_in, - min_token_amount_out, - } => swap( - accounts, - token_a_amount_in, - token_b_amount_in, - min_token_amount_out, - )?, - AmmInstruction::Stake { amount } => stake(accounts, amount, false)?, - AmmInstruction::Unstake { amount } => unstake(accounts, amount)?, - AmmInstruction::Harvest => stake(accounts, 0, true)?, - _ => {} - } - - sol_log_compute_units(); - msg!("Raydium router end of instruction"); - Ok(()) -} diff --git a/farms/router-raydium/src/remove_liquidity.rs b/farms/router-raydium/src/remove_liquidity.rs deleted file mode 100644 index 03a93c40ddd..00000000000 --- a/farms/router-raydium/src/remove_liquidity.rs +++ /dev/null @@ -1,135 +0,0 @@ -//! Remove liquidity from the Raydium pool instruction - -use { - solana_farm_sdk::{ - instruction::raydium::RaydiumRemoveLiquidity, - program::{account, protocol::raydium}, - }, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke, - program_error::ProgramError, - }, -}; - -pub fn remove_liquidity(accounts: &[AccountInfo], amount: u64) -> ProgramResult { - msg!("Processing AmmInstruction::RemoveLiquidity"); - msg!("amount {} ", amount); - - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - user_token_a_account, - user_token_b_account, - user_lp_token_account, - pool_program_id, - pool_withdraw_queue, - pool_temp_lp_token_account, - pool_coin_token_account, - pool_pc_token_account, - lp_token_mint, - spl_token_id, - amm_id, - amm_authority, - amm_open_orders, - amm_target, - serum_market, - serum_program_id, - serum_bids, - serum_asks, - serum_event_queue, - serum_coin_vault_account, - serum_pc_vault_account, - serum_vault_signer - ] = accounts - { - if !raydium::check_pool_program_id(pool_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - if !account::check_token_account_owner(user_token_a_account, user_account.key)? - || !account::check_token_account_owner(user_token_b_account, user_account.key)? - { - return Err(ProgramError::IllegalOwner); - } - - let initial_token_a_user_balance = account::get_token_balance(user_token_a_account)?; - let initial_token_b_user_balance = account::get_token_balance(user_token_b_account)?; - let initial_lp_token_user_balance = account::get_token_balance(user_lp_token_account)?; - - let lp_amount = if amount > 0 { - amount - } else { - account::get_token_balance(user_lp_token_account)? - }; - - let (coin_token_amount, pc_token_amount) = raydium::get_pool_withdrawal_amounts( - pool_coin_token_account, - pool_pc_token_account, - amm_open_orders, - amm_id, - lp_token_mint, - lp_amount, - )?; - - let raydium_accounts = vec![ - AccountMeta::new_readonly(*spl_token_id.key, false), - AccountMeta::new(*amm_id.key, false), - AccountMeta::new_readonly(*amm_authority.key, false), - AccountMeta::new(*amm_open_orders.key, false), - AccountMeta::new(*amm_target.key, false), - AccountMeta::new(*lp_token_mint.key, false), - AccountMeta::new(*pool_coin_token_account.key, false), - AccountMeta::new(*pool_pc_token_account.key, false), - AccountMeta::new(*pool_withdraw_queue.key, false), - AccountMeta::new(*pool_temp_lp_token_account.key, false), - AccountMeta::new_readonly(*serum_program_id.key, false), - AccountMeta::new(*serum_market.key, false), - AccountMeta::new(*serum_coin_vault_account.key, false), - AccountMeta::new(*serum_pc_vault_account.key, false), - AccountMeta::new_readonly(*serum_vault_signer.key, false), - AccountMeta::new(*user_lp_token_account.key, false), - AccountMeta::new(*user_token_a_account.key, false), - AccountMeta::new(*user_token_b_account.key, false), - AccountMeta::new_readonly(*user_account.key, true), - AccountMeta::new(*serum_event_queue.key, false), - AccountMeta::new(*serum_bids.key, false), - AccountMeta::new(*serum_asks.key, false) - ]; - - let instruction = Instruction { - program_id: *pool_program_id.key, - accounts: raydium_accounts, - data: RaydiumRemoveLiquidity { - instruction: 4, - amount: lp_amount, - } - .to_vec()?, - }; - invoke(&instruction, accounts)?; - - account::check_tokens_spent( - user_lp_token_account, - initial_lp_token_user_balance, - lp_amount, - )?; - account::check_tokens_received( - user_token_a_account, - initial_token_a_user_balance, - coin_token_amount, - )?; - account::check_tokens_received( - user_token_b_account, - initial_token_b_user_balance, - pc_token_amount, - )?; - } else { - return Err(ProgramError::NotEnoughAccountKeys); - } - - msg!("AmmInstruction::RemoveLiquidity complete"); - Ok(()) -} diff --git a/farms/router-raydium/src/stake.rs b/farms/router-raydium/src/stake.rs deleted file mode 100644 index fb43a39bf86..00000000000 --- a/farms/router-raydium/src/stake.rs +++ /dev/null @@ -1,117 +0,0 @@ -//! Stake LP tokens to a Raydium farm instruction - -use { - solana_farm_sdk::{ - id::zero, - instruction::raydium::RaydiumStake, - program::{account, protocol::raydium}, - }, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke, - program_error::ProgramError, - }, -}; - -pub fn stake(accounts: &[AccountInfo], amount: u64, harvest: bool) -> ProgramResult { - msg!("Processing AmmInstruction::Stake"); - msg!("amount {} ", amount); - - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - user_info_account, - user_lp_token_account, - user_first_reward_token_account, - user_second_reward_token_account, - farm_program_id, - farm_lp_token_account, - farm_first_reward_token_account, - farm_second_reward_token_account, - clock_id, - spl_token_id, - farm_id, - farm_authority - ] = accounts - { - if !raydium::check_stake_program_id(farm_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - if !account::check_token_account_owner(user_first_reward_token_account, user_account.key)? - || !account::check_token_account_owner_or_zero(user_second_reward_token_account, user_account.key)? - { - return Err(ProgramError::IllegalOwner); - } - - let dual_rewards = *farm_second_reward_token_account.key != zero::id(); - let initial_token_a_user_balance = account::get_token_balance(user_first_reward_token_account)?; - let initial_token_b_user_balance = if dual_rewards { - account::get_token_balance(user_second_reward_token_account)? - } else { - 0 - }; - let initial_lp_token_user_balance = account::get_token_balance(user_lp_token_account)?; - - let mut raydium_accounts = Vec::with_capacity(12); - raydium_accounts.push(AccountMeta::new(*farm_id.key, false)); - raydium_accounts.push(AccountMeta::new_readonly(*farm_authority.key, false)); - raydium_accounts.push(AccountMeta::new(*user_info_account.key, false)); - raydium_accounts.push(AccountMeta::new_readonly(*user_account.key, true)); - raydium_accounts.push(AccountMeta::new(*user_lp_token_account.key, false)); - raydium_accounts.push(AccountMeta::new(*farm_lp_token_account.key, false)); - raydium_accounts.push(AccountMeta::new(*user_first_reward_token_account.key, false)); - raydium_accounts.push(AccountMeta::new(*farm_first_reward_token_account.key, false)); - raydium_accounts.push(AccountMeta::new_readonly(*clock_id.key, false)); - raydium_accounts.push(AccountMeta::new_readonly(*spl_token_id.key, false)); - if dual_rewards { - raydium_accounts.push(AccountMeta::new(*user_second_reward_token_account.key, false)); - raydium_accounts.push(AccountMeta::new(*farm_second_reward_token_account.key, false)); - } - - let lp_amount = if harvest { - 0 - } else if amount > 0 { - amount - } else { - initial_lp_token_user_balance - }; - - let instruction = Instruction { - program_id: *farm_program_id.key, - accounts: raydium_accounts, - data: RaydiumStake { - instruction: 1, - amount: lp_amount, - } - .to_vec()?, - }; - invoke(&instruction, accounts)?; - - account::check_tokens_spent( - user_lp_token_account, - initial_lp_token_user_balance, - lp_amount, - )?; - if user_lp_token_account.key != user_first_reward_token_account.key { - let _ = account::get_balance_increase( - user_first_reward_token_account, - initial_token_a_user_balance, - )?; - } - if dual_rewards && user_lp_token_account.key != user_second_reward_token_account.key { - let _ = account::get_balance_increase( - user_second_reward_token_account, - initial_token_b_user_balance, - )?; - } - } else { - return Err(ProgramError::NotEnoughAccountKeys); - } - - msg!("AmmInstruction::Stake complete"); - Ok(()) -} diff --git a/farms/router-raydium/src/swap.rs b/farms/router-raydium/src/swap.rs deleted file mode 100644 index 20e3613d939..00000000000 --- a/farms/router-raydium/src/swap.rs +++ /dev/null @@ -1,157 +0,0 @@ -//! Swap tokens with the Raydium pool instruction - -use { - solana_farm_sdk::{ - instruction::raydium::RaydiumSwap, - program::{account, protocol::raydium}, - }, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke, - program_error::ProgramError, - }, -}; - -pub fn swap( - accounts: &[AccountInfo], - token_a_amount_in: u64, - token_b_amount_in: u64, - min_token_amount_out: u64, -) -> ProgramResult { - msg!("Processing AmmInstruction::Swap"); - msg!("token_a_amount_in {} ", token_a_amount_in); - msg!("token_b_amount_in {} ", token_b_amount_in); - msg!("min_token_amount_out {} ", min_token_amount_out); - - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - user_token_a_account, - user_token_b_account, - pool_program_id, - pool_coin_token_account, - pool_pc_token_account, - spl_token_id, - amm_id, - amm_authority, - amm_open_orders, - amm_target, - serum_market, - serum_program_id, - serum_bids, - serum_asks, - serum_event_queue, - serum_coin_vault_account, - serum_pc_vault_account, - serum_vault_signer - ] = accounts - { - if !raydium::check_pool_program_id(pool_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - - let (amount_in, mut min_amount_out) = raydium::get_pool_swap_amounts( - pool_coin_token_account, - pool_pc_token_account, - amm_open_orders, - amm_id, - token_a_amount_in, - token_b_amount_in, - )?; - if min_token_amount_out > min_amount_out { - min_amount_out = min_token_amount_out; - } - if amount_in == 0 || min_amount_out == 0 { - msg!("Nothing to do: Not enough tokens to swap"); - return Ok(()); - } - - let initial_balance_in = if token_a_amount_in == 0 { - account::get_token_balance(user_token_b_account)? - } else { - account::get_token_balance(user_token_a_account)? - }; - let initial_balance_out = if token_a_amount_in == 0 { - account::get_token_balance(user_token_a_account)? - } else { - account::get_token_balance(user_token_b_account)? - }; - - msg!( - "Swap tokens in the pool. amount_in: {}, min_amount_out: {}", - amount_in, - min_amount_out - ); - - let mut raydium_accounts = Vec::with_capacity(18); - raydium_accounts.push(AccountMeta::new_readonly(*spl_token_id.key, false)); - raydium_accounts.push(AccountMeta::new(*amm_id.key, false)); - raydium_accounts.push(AccountMeta::new_readonly(*amm_authority.key, false)); - raydium_accounts.push(AccountMeta::new(*amm_open_orders.key, false)); - raydium_accounts.push(AccountMeta::new(*amm_target.key, false)); - raydium_accounts.push(AccountMeta::new(*pool_coin_token_account.key, false)); - raydium_accounts.push(AccountMeta::new(*pool_pc_token_account.key, false)); - raydium_accounts.push(AccountMeta::new_readonly(*serum_program_id.key, false)); - raydium_accounts.push(AccountMeta::new(*serum_market.key, false)); - raydium_accounts.push(AccountMeta::new(*serum_bids.key, false)); - raydium_accounts.push(AccountMeta::new(*serum_asks.key, false)); - raydium_accounts.push(AccountMeta::new(*serum_event_queue.key, false)); - raydium_accounts.push(AccountMeta::new(*serum_coin_vault_account.key, false)); - raydium_accounts.push(AccountMeta::new(*serum_pc_vault_account.key, false)); - raydium_accounts.push(AccountMeta::new_readonly(*serum_vault_signer.key, false)); - if token_a_amount_in == 0 { - if !account::check_token_account_owner(user_token_a_account, user_account.key)? { - return Err(ProgramError::IllegalOwner); - } - raydium_accounts.push(AccountMeta::new(*user_token_b_account.key, false)); - raydium_accounts.push(AccountMeta::new(*user_token_a_account.key, false)); - } else { - if !account::check_token_account_owner(user_token_b_account, user_account.key)? { - return Err(ProgramError::IllegalOwner); - } - raydium_accounts.push(AccountMeta::new(*user_token_a_account.key, false)); - raydium_accounts.push(AccountMeta::new(*user_token_b_account.key, false)); - } - raydium_accounts.push(AccountMeta::new_readonly(*user_account.key, true)); - - let instruction = Instruction { - program_id: *pool_program_id.key, - accounts: raydium_accounts, - data: RaydiumSwap { - instruction: 9, - amount_in, - min_amount_out, - } - .to_vec()?, - }; - invoke(&instruction, accounts)?; - - account::check_tokens_spent( - if token_a_amount_in == 0 { - user_token_b_account - } else { - user_token_a_account - }, - initial_balance_in, - amount_in, - )?; - account::check_tokens_received( - if token_a_amount_in == 0 { - user_token_a_account - } else { - user_token_b_account - }, - initial_balance_out, - min_amount_out, - )?; - } else { - return Err(ProgramError::NotEnoughAccountKeys); - } - - msg!("AmmInstruction::Swap complete"); - Ok(()) -} diff --git a/farms/router-raydium/src/unstake.rs b/farms/router-raydium/src/unstake.rs deleted file mode 100644 index 89b3d69de96..00000000000 --- a/farms/router-raydium/src/unstake.rs +++ /dev/null @@ -1,114 +0,0 @@ -//! Unstake LP tokens from a Raydium farm instruction - -use { - solana_farm_sdk::{ - id::zero, - instruction::raydium::RaydiumUnstake, - program::{account, protocol::raydium}, - }, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke, - program_error::ProgramError, - }, -}; - -pub fn unstake(accounts: &[AccountInfo], amount: u64) -> ProgramResult { - msg!("Processing AmmInstruction::Unstake"); - msg!("amount {} ", amount); - - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - user_info_account, - user_lp_token_account, - user_first_reward_token_account, - user_second_reward_token_account, - farm_program_id, - farm_lp_token_account, - farm_first_reward_token_account, - farm_second_reward_token_account, - clock_id, - spl_token_id, - farm_id, - farm_authority - ] = accounts - { - if !raydium::check_stake_program_id(farm_program_id.key) { - return Err(ProgramError::IncorrectProgramId); - } - if !account::check_token_account_owner(user_lp_token_account, user_account.key)? - || !account::check_token_account_owner(user_first_reward_token_account, user_account.key)? - || !account::check_token_account_owner_or_zero(user_second_reward_token_account, user_account.key)? - { - return Err(ProgramError::IllegalOwner); - } - - let dual_rewards = *farm_second_reward_token_account.key != zero::id(); - let initial_token_a_user_balance = account::get_token_balance(user_first_reward_token_account)?; - let initial_token_b_user_balance = if dual_rewards { - account::get_token_balance(user_second_reward_token_account)? - } else { - 0 - }; - let initial_lp_token_user_balance = account::get_token_balance(user_lp_token_account)?; - - let mut raydium_accounts = Vec::with_capacity(12); - raydium_accounts.push(AccountMeta::new(*farm_id.key, false)); - raydium_accounts.push(AccountMeta::new_readonly(*farm_authority.key, false)); - raydium_accounts.push(AccountMeta::new(*user_info_account.key, false)); - raydium_accounts.push(AccountMeta::new_readonly(*user_account.key, true)); - raydium_accounts.push(AccountMeta::new(*user_lp_token_account.key, false)); - raydium_accounts.push(AccountMeta::new(*farm_lp_token_account.key, false)); - raydium_accounts.push(AccountMeta::new(*user_first_reward_token_account.key, false)); - raydium_accounts.push(AccountMeta::new(*farm_first_reward_token_account.key, false)); - raydium_accounts.push(AccountMeta::new_readonly(*clock_id.key, false)); - raydium_accounts.push(AccountMeta::new_readonly(*spl_token_id.key, false)); - if dual_rewards { - raydium_accounts.push(AccountMeta::new(*user_second_reward_token_account.key, false)); - raydium_accounts.push(AccountMeta::new(*farm_second_reward_token_account.key, false)); - } - - let lp_amount = if amount > 0 { - amount - } else { - raydium::get_stake_account_balance(user_info_account)? - }; - - let instruction = Instruction { - program_id: *farm_program_id.key, - accounts: raydium_accounts, - data: RaydiumUnstake { - instruction: 2, - amount: lp_amount, - } - .to_vec()?, - }; - invoke(&instruction, accounts)?; - - account::check_tokens_received( - user_lp_token_account, - initial_lp_token_user_balance, - lp_amount, - )?; - let _ = account::get_balance_increase( - user_first_reward_token_account, - initial_token_a_user_balance, - )?; - if dual_rewards { - let _ = account::get_balance_increase( - user_second_reward_token_account, - initial_token_b_user_balance, - )?; - } - } else { - return Err(ProgramError::NotEnoughAccountKeys); - } - - msg!("AmmInstruction::Unstake complete"); - Ok(()) -} diff --git a/farms/router-raydium/src/user_init.rs b/farms/router-raydium/src/user_init.rs deleted file mode 100644 index ae548b882f7..00000000000 --- a/farms/router-raydium/src/user_init.rs +++ /dev/null @@ -1,71 +0,0 @@ -//! Initialize a new user for a Raydium farm instruction - -use { - solana_farm_sdk::{ - farm::{Farm, FarmRoute}, - id::main_router, - program::{account, pda, protocol::raydium}, - traits::Packed, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn user_init(accounts: &[AccountInfo]) -> ProgramResult { - msg!("Processing AmmInstruction::UserInit"); - - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - funding_account, - user_account, - user_info_account, - farm_metadata, - _system_program - ] = accounts - { - if account::exists(user_info_account)? { - return Err(ProgramError::AccountAlreadyInitialized); - } - if farm_metadata.owner != &main_router::id() { - msg!("Error: Invalid Farm metadata owner"); - return Err(ProgramError::IllegalOwner); - } - let farm = Farm::unpack(&farm_metadata.try_borrow_data()?)?; - - if !raydium::check_stake_program_id(&farm.farm_program_id) { - return Err(ProgramError::IncorrectProgramId); - } - - let farm_id = match farm.route { - FarmRoute::Raydium { farm_id, .. } => farm_id, - _ => { - return Err(ProgramError::InvalidArgument); - } - }; - let seeds: &[&[u8]] = &[ - b"Miner", - &farm_id.to_bytes(), - &user_account.key.to_bytes(), - ]; - - pda::init_system_account( - funding_account, - user_info_account, - &farm.farm_program_id, - &farm.router_program_id, - seeds, - if farm.version >= 4 { - raydium::RaydiumUserStakeInfoV4::LEN - } else { - raydium::RaydiumUserStakeInfo::LEN - }, - )?; - } else { - return Err(ProgramError::NotEnoughAccountKeys); - } - - msg!("AmmInstruction::UserInit complete"); - Ok(()) -} diff --git a/farms/router-saber/.gitignore b/farms/router-saber/.gitignore deleted file mode 100644 index da0b2a84eb6..00000000000 --- a/farms/router-saber/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/target -/include -Cargo.lock diff --git a/farms/router-saber/Cargo.toml b/farms/router-saber/Cargo.toml deleted file mode 100644 index dd83ea2e0bc..00000000000 --- a/farms/router-saber/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "solana-router-saber" -version = "1.1.3" -description = "Solana Saber Router" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana-program-library/farms" -license = "Apache-2.0" -homepage = "https://solana.com/" -edition = "2021" - -[features] -no-entrypoint = [] -debug = [] - -[dependencies] -solana-farm-sdk = "1.1.3" -solana-program = "1.9.18" -solana-security-txt = "1.0.1" -arrayref = "0.3.6" -stable-swap-client = "1.8.1" -quarry-mine = { version = "5.0.2", features = ["no-entrypoint"] } -quarry-mint-wrapper = { version = "5.0.2", features = ["no-entrypoint"] } -quarry-redeemer = { version = "5.0.2", features = ["no-entrypoint"] } -spl-token = { version = "3.2.0", features = ["no-entrypoint"] } - -[dev-dependencies] -solana-program-test = "1.9.18" - -[lib] -crate-type = ["cdylib", "lib"] - diff --git a/farms/router-saber/README.md b/farms/router-saber/README.md deleted file mode 120000 index ccd27901fd5..00000000000 --- a/farms/router-saber/README.md +++ /dev/null @@ -1 +0,0 @@ -../docs/crate.md \ No newline at end of file diff --git a/farms/router-saber/Xargo.toml b/farms/router-saber/Xargo.toml deleted file mode 100644 index 1744f098ae1..00000000000 --- a/farms/router-saber/Xargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.bpfel-unknown-unknown.dependencies.std] -features = [] \ No newline at end of file diff --git a/farms/router-saber/src/add_liquidity.rs b/farms/router-saber/src/add_liquidity.rs deleted file mode 100644 index 8db0a79bb5a..00000000000 --- a/farms/router-saber/src/add_liquidity.rs +++ /dev/null @@ -1,84 +0,0 @@ -//! Add liquidity to the Saber pool instruction - -use { - solana_farm_sdk::program::account, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program::invoke, - program_error::ProgramError, - }, - stable_swap_client::instruction, -}; - -pub fn add_liquidity( - accounts: &[AccountInfo], - max_token_a_amount: u64, - max_token_b_amount: u64, -) -> ProgramResult { - msg!("Processing AmmInstruction::AddLiquidity"); - msg!("max_token_a_amount {} ", max_token_a_amount); - msg!("max_token_b_amount {} ", max_token_b_amount); - - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - user_token_a_account, - user_token_b_account, - user_lp_token_account, - pool_program_id, - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - _spl_token_id, - _clock_id, - swap_account, - swap_authority - ] = accounts - { - if &stable_swap_client::id() != pool_program_id.key { - return Err(ProgramError::IncorrectProgramId); - } - if !account::check_token_account_owner(user_lp_token_account, user_account.key)? { - return Err(ProgramError::IllegalOwner); - } - - let initial_token_a_user_balance = account::get_token_balance(user_token_a_account)?; - let initial_token_b_user_balance = account::get_token_balance(user_token_b_account)?; - let initial_lp_token_user_balance = account::get_token_balance(user_lp_token_account)?; - - let instruction = instruction::deposit( - &spl_token::id(), - swap_account.key, - swap_authority.key, - user_account.key, - user_token_a_account.key, - user_token_b_account.key, - pool_token_a_account.key, - pool_token_b_account.key, - lp_token_mint.key, - user_lp_token_account.key, - max_token_a_amount, - max_token_b_amount, - 1, - )?; - - invoke(&instruction, accounts)?; - - account::check_tokens_spent( - user_token_a_account, - initial_token_a_user_balance, - max_token_a_amount, - )?; - account::check_tokens_spent( - user_token_b_account, - initial_token_b_user_balance, - max_token_b_amount, - )?; - account::check_tokens_received(user_lp_token_account, initial_lp_token_user_balance, 1)?; - } else { - return Err(ProgramError::NotEnoughAccountKeys); - } - - msg!("AmmInstruction::AddLiquidity complete"); - Ok(()) -} diff --git a/farms/router-saber/src/entrypoint.rs b/farms/router-saber/src/entrypoint.rs deleted file mode 100644 index 492afa07f7d..00000000000 --- a/farms/router-saber/src/entrypoint.rs +++ /dev/null @@ -1,25 +0,0 @@ -//! Program entrypoint - -#![cfg(not(feature = "no-entrypoint"))] - -solana_security_txt::security_txt! { - name: "Solana Farms", - project_url: "https://github.com/solana-labs/solana-program-library/tree/master/farms", - contacts: "email:solana.farms@protonmail.com", - policy: "", - preferred_languages: "en", - auditors: "Halborn" -} - -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, pubkey::Pubkey, -}; - -entrypoint!(process_instruction); -fn process_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - instruction_data: &[u8], -) -> ProgramResult { - crate::processor::process_instruction(program_id, accounts, instruction_data) -} diff --git a/farms/router-saber/src/harvest.rs b/farms/router-saber/src/harvest.rs deleted file mode 100644 index 7b74e75e07e..00000000000 --- a/farms/router-saber/src/harvest.rs +++ /dev/null @@ -1,137 +0,0 @@ -//! Harvest rewards from a Saber farm instruction - -use { - solana_farm_sdk::{id::zero, program::account}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - hash::Hasher, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke, - program_error::ProgramError, - }, -}; - -pub fn harvest(accounts: &[AccountInfo]) -> ProgramResult { - msg!("Processing AmmInstruction::Harvest"); - - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - user_iou_token_account, - user_sbr_token_account, - farm_program_id, - _spl_token_id, - _zero_id, - miner, - rewarder, - redeemer, - redeemer_program, - minter, - mint_wrapper, - mint_wrapper_program, - sbr_token_mint, - iou_token_mint, - iou_fees_account, - quarry, - saber_vault, - saber_mint_proxy_program, - mint_proxy_authority, - mint_proxy_state, - minter_info - ] = accounts - { - if &quarry_mine::id() != farm_program_id.key - || &quarry_mint_wrapper::id() != mint_wrapper_program.key - { - return Err(ProgramError::IncorrectProgramId); - } - if !account::check_token_account_owner(user_iou_token_account, user_account.key)? - || !account::check_token_account_owner(user_sbr_token_account, user_account.key)? - { - return Err(ProgramError::IllegalOwner); - } - - let initial_iou_token_user_balance = account::get_token_balance(user_iou_token_account)?; - let initial_sbr_token_user_balance = account::get_token_balance(user_sbr_token_account)?; - - // harvest IOU rewards - let mut hasher = Hasher::default(); - hasher.hash(b"global:claim_rewards"); - - let data = hasher.result().as_ref()[..8].to_vec(); - - let saber_accounts = vec![ - AccountMeta::new(*mint_wrapper.key, false), - AccountMeta::new_readonly(*mint_wrapper_program.key, false), - AccountMeta::new(*minter.key, false), - AccountMeta::new(*iou_token_mint.key, false), - AccountMeta::new(*user_iou_token_account.key, false), - AccountMeta::new(*iou_fees_account.key, false), - AccountMeta::new_readonly(*user_account.key, true), - AccountMeta::new(*miner.key, false), - AccountMeta::new(*quarry.key, false), - AccountMeta::new(zero::id(), false), - AccountMeta::new(zero::id(), false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new_readonly(*rewarder.key, false), - ]; - - let instruction = Instruction { - program_id: quarry_mine::id(), - accounts: saber_accounts, - data, - }; - - invoke(&instruction, accounts)?; - - let iou_rewards = - account::get_balance_increase(user_iou_token_account, initial_iou_token_user_balance)?; - - if iou_rewards == 0 { - return Ok(()); - } - - // convert IOU to Saber - let mut hasher = Hasher::default(); - hasher.hash(b"global:redeem_all_tokens_from_mint_proxy"); - - let data = hasher.result().as_ref()[..8].to_vec(); - - let saber_accounts = vec![ - AccountMeta::new_readonly(*redeemer.key, false), - AccountMeta::new(*iou_token_mint.key, false), - AccountMeta::new(*sbr_token_mint.key, false), - AccountMeta::new(*saber_vault.key, false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new_readonly(*user_account.key, true), - AccountMeta::new(*user_iou_token_account.key, false), - AccountMeta::new(*user_sbr_token_account.key, false), - AccountMeta::new_readonly(*mint_proxy_authority.key, false), - AccountMeta::new_readonly(*mint_proxy_state.key, false), - AccountMeta::new_readonly(*saber_mint_proxy_program.key, false), - AccountMeta::new(*minter_info.key, false), - ]; - - let instruction = Instruction { - program_id: *redeemer_program.key, - accounts: saber_accounts, - data, - }; - - invoke(&instruction, accounts)?; - - account::check_tokens_received( - user_sbr_token_account, - initial_sbr_token_user_balance, - iou_rewards, - )?; - } else { - return Err(ProgramError::NotEnoughAccountKeys); - } - - msg!("AmmInstruction::Harvest complete"); - Ok(()) -} diff --git a/farms/router-saber/src/lib.rs b/farms/router-saber/src/lib.rs deleted file mode 100644 index 7288e535c52..00000000000 --- a/farms/router-saber/src/lib.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![forbid(unsafe_code)] - -pub mod add_liquidity; -mod entrypoint; -pub mod harvest; -pub mod processor; -pub mod remove_liquidity; -pub mod stake; -pub mod swap; -pub mod unstake; -pub mod unwrap_token; -pub mod user_init; -pub mod wrap_token; diff --git a/farms/router-saber/src/processor.rs b/farms/router-saber/src/processor.rs deleted file mode 100644 index c387e97b485..00000000000 --- a/farms/router-saber/src/processor.rs +++ /dev/null @@ -1,62 +0,0 @@ -//! Saber router implementation. - -use { - crate::{ - add_liquidity::add_liquidity, harvest::harvest, remove_liquidity::remove_liquidity, - stake::stake, swap::swap, unstake::unstake, unwrap_token::unwrap_token, - user_init::user_init, wrap_token::wrap_token, - }, - solana_farm_sdk::{instruction::amm::AmmInstruction, log::sol_log_params_short}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, log::sol_log_compute_units, msg, - pubkey::Pubkey, - }, -}; - -/// Program's entrypoint. -/// -/// # Arguments -/// * `program_id` - Public key of the router. -/// * `accounts` - Accounts, see particular instruction handler for the list. -/// * `instructions_data` - Packed AmmInstruction. -pub fn process_instruction( - _program_id: &Pubkey, - accounts: &[AccountInfo], - instruction_data: &[u8], -) -> ProgramResult { - msg!("Saber router entrypoint"); - if cfg!(feature = "debug") { - sol_log_params_short(accounts, instruction_data); - } - - // Read and unpack instruction data - let instruction = AmmInstruction::unpack(instruction_data)?; - - match instruction { - AmmInstruction::UserInit => user_init(accounts)?, - AmmInstruction::AddLiquidity { - max_token_a_amount, - max_token_b_amount, - } => add_liquidity(accounts, max_token_a_amount, max_token_b_amount)?, - AmmInstruction::RemoveLiquidity { amount } => remove_liquidity(accounts, amount)?, - AmmInstruction::Swap { - token_a_amount_in, - token_b_amount_in, - min_token_amount_out, - } => swap( - accounts, - token_a_amount_in, - token_b_amount_in, - min_token_amount_out, - )?, - AmmInstruction::Stake { amount } => stake(accounts, amount)?, - AmmInstruction::Unstake { amount } => unstake(accounts, amount)?, - AmmInstruction::Harvest => harvest(accounts)?, - AmmInstruction::WrapToken { amount } => wrap_token(accounts, amount)?, - AmmInstruction::UnwrapToken { amount } => unwrap_token(accounts, amount)?, - } - - sol_log_compute_units(); - msg!("Saber router end of instruction"); - Ok(()) -} diff --git a/farms/router-saber/src/remove_liquidity.rs b/farms/router-saber/src/remove_liquidity.rs deleted file mode 100644 index 22ac75eb300..00000000000 --- a/farms/router-saber/src/remove_liquidity.rs +++ /dev/null @@ -1,86 +0,0 @@ -//! Remove liquidity from the Saber pool instruction - -use { - solana_farm_sdk::program::account, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program::invoke, - program_error::ProgramError, - }, - stable_swap_client::instruction, -}; - -pub fn remove_liquidity(accounts: &[AccountInfo], amount: u64) -> ProgramResult { - msg!("Processing AmmInstruction::RemoveLiquidity"); - msg!("amount {} ", amount); - - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - user_token_a_account, - user_token_b_account, - user_lp_token_account, - pool_program_id, - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - _spl_token_id, - swap_account, - swap_authority, - fees_account_a, - fees_account_b - ] = accounts - { - if &stable_swap_client::id() != pool_program_id.key { - return Err(ProgramError::IncorrectProgramId); - } - if !account::check_token_account_owner(user_token_a_account, user_account.key)? - || !account::check_token_account_owner(user_token_b_account, user_account.key)? - { - return Err(ProgramError::IllegalOwner); - } - - let initial_token_a_user_balance = account::get_token_balance(user_token_a_account)?; - let initial_token_b_user_balance = account::get_token_balance(user_token_b_account)?; - let initial_lp_token_user_balance = account::get_token_balance(user_lp_token_account)?; - - let lp_amount = if amount > 0 { - amount - } else { - account::get_token_balance(user_lp_token_account)? - }; - - let instruction = instruction::withdraw( - &spl_token::id(), - swap_account.key, - swap_authority.key, - user_account.key, - lp_token_mint.key, - user_lp_token_account.key, - pool_token_a_account.key, - pool_token_b_account.key, - user_token_a_account.key, - user_token_b_account.key, - fees_account_a.key, - fees_account_b.key, - lp_amount, - 1, - 1, - )?; - - invoke(&instruction, accounts)?; - - account::check_tokens_spent( - user_lp_token_account, - initial_lp_token_user_balance, - lp_amount, - )?; - account::check_tokens_received(user_token_a_account, initial_token_a_user_balance, 1)?; - account::check_tokens_received(user_token_b_account, initial_token_b_user_balance, 1)?; - } else { - return Err(ProgramError::NotEnoughAccountKeys); - } - - msg!("AmmInstruction::RemoveLiquidity complete"); - Ok(()) -} diff --git a/farms/router-saber/src/stake.rs b/farms/router-saber/src/stake.rs deleted file mode 100644 index a923d40b8c7..00000000000 --- a/farms/router-saber/src/stake.rs +++ /dev/null @@ -1,80 +0,0 @@ -//! Stake LP tokens to a Saber farm instruction - -use { - solana_farm_sdk::program::account, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - hash::Hasher, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke, - program_error::ProgramError, - }, -}; - -pub fn stake(accounts: &[AccountInfo], amount: u64) -> ProgramResult { - msg!("Processing AmmInstruction::Stake"); - msg!("amount {} ", amount); - - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - user_lp_token_account, - farm_program_id, - _spl_token_id, - miner, - miner_vault, - quarry, - rewarder - ] = accounts - { - if &quarry_mine::id() != farm_program_id.key { - return Err(ProgramError::IncorrectProgramId); - } - - let initial_lp_token_user_balance = account::get_token_balance(user_lp_token_account)?; - - let lp_amount = if amount > 0 { - amount - } else { - account::get_token_balance(user_lp_token_account)? - }; - - let mut hasher = Hasher::default(); - hasher.hash(b"global:stake_tokens"); - - let mut data = hasher.result().as_ref()[..8].to_vec(); - data.extend_from_slice(&lp_amount.to_le_bytes()); - - let saber_accounts = vec![ - AccountMeta::new_readonly(*user_account.key, true), - AccountMeta::new(*miner.key, false), - AccountMeta::new(*quarry.key, false), - AccountMeta::new(*miner_vault.key, false), - AccountMeta::new(*user_lp_token_account.key, false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new_readonly(*rewarder.key, false), - ]; - - let instruction = Instruction { - program_id: quarry_mine::id(), - accounts: saber_accounts, - data, - }; - - invoke(&instruction, accounts)?; - - account::check_tokens_spent( - user_lp_token_account, - initial_lp_token_user_balance, - lp_amount, - )?; - } else { - return Err(ProgramError::NotEnoughAccountKeys); - } - - msg!("AmmInstruction::Stake complete"); - Ok(()) -} diff --git a/farms/router-saber/src/swap.rs b/farms/router-saber/src/swap.rs deleted file mode 100644 index aba9ec256f3..00000000000 --- a/farms/router-saber/src/swap.rs +++ /dev/null @@ -1,125 +0,0 @@ -//! Swap tokens with the Saber pool instruction - -use { - solana_farm_sdk::program::account, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program::invoke, - program_error::ProgramError, - }, - stable_swap_client::instruction, -}; - -pub fn swap( - accounts: &[AccountInfo], - token_a_amount_in: u64, - token_b_amount_in: u64, - min_token_amount_out: u64, -) -> ProgramResult { - msg!("Processing AmmInstruction::Swap"); - msg!("token_a_amount_in {} ", token_a_amount_in); - msg!("token_b_amount_in {} ", token_b_amount_in); - msg!("min_token_amount_out {} ", min_token_amount_out); - - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - user_token_a_account, - user_token_b_account, - pool_program_id, - pool_token_a_account, - pool_token_b_account, - _spl_token_id, - _clock_id, - swap_account, - swap_authority, - fees_account_a, - fees_account_b - ] = accounts - { - if &stable_swap_client::id() != pool_program_id.key { - return Err(ProgramError::IncorrectProgramId); - } - - let amount_in = if token_a_amount_in == 0 { - token_b_amount_in - } else { - token_a_amount_in - }; - - let initial_balance_in = if token_a_amount_in == 0 { - account::get_token_balance(user_token_b_account)? - } else { - account::get_token_balance(user_token_a_account)? - }; - let initial_balance_out = if token_a_amount_in == 0 { - account::get_token_balance(user_token_a_account)? - } else { - account::get_token_balance(user_token_b_account)? - }; - - let instruction = if token_a_amount_in > 0 { - if !account::check_token_account_owner(user_token_b_account, user_account.key)? { - return Err(ProgramError::IllegalOwner); - } - - instruction::swap( - &spl_token::id(), - swap_account.key, - swap_authority.key, - user_account.key, - user_token_a_account.key, - pool_token_a_account.key, - pool_token_b_account.key, - user_token_b_account.key, - fees_account_b.key, - amount_in, - min_token_amount_out, - )? - } else { - if !account::check_token_account_owner(user_token_a_account, user_account.key)? { - return Err(ProgramError::IllegalOwner); - } - - instruction::swap( - &spl_token::id(), - swap_account.key, - swap_authority.key, - user_account.key, - user_token_b_account.key, - pool_token_b_account.key, - pool_token_a_account.key, - user_token_a_account.key, - fees_account_a.key, - amount_in, - min_token_amount_out, - )? - }; - - invoke(&instruction, accounts)?; - - account::check_tokens_spent( - if token_a_amount_in == 0 { - user_token_b_account - } else { - user_token_a_account - }, - initial_balance_in, - amount_in, - )?; - account::check_tokens_received( - if token_a_amount_in == 0 { - user_token_a_account - } else { - user_token_b_account - }, - initial_balance_out, - min_token_amount_out, - )?; - } else { - return Err(ProgramError::NotEnoughAccountKeys); - } - - msg!("AmmInstruction::Swap complete"); - Ok(()) -} diff --git a/farms/router-saber/src/unstake.rs b/farms/router-saber/src/unstake.rs deleted file mode 100644 index c8533c54cfd..00000000000 --- a/farms/router-saber/src/unstake.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! Unstake LP tokens from a Saber farm instruction - -use { - solana_farm_sdk::program::{account, protocol::saber}, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - hash::Hasher, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke, - program_error::ProgramError, - }, -}; - -pub fn unstake(accounts: &[AccountInfo], amount: u64) -> ProgramResult { - msg!("Processing AmmInstruction::Unstake"); - msg!("amount {} ", amount); - - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - user_lp_token_account, - farm_program_id, - _spl_token_id, - miner, - miner_vault, - quarry, - rewarder - ] = accounts - { - if &quarry_mine::id() != farm_program_id.key { - return Err(ProgramError::IncorrectProgramId); - } - if !account::check_token_account_owner(user_lp_token_account, user_account.key)? { - return Err(ProgramError::IllegalOwner); - } - - let initial_lp_token_user_balance = account::get_token_balance(user_lp_token_account)?; - - let lp_amount = if amount > 0 { - amount - } else { - saber::get_stake_account_balance(miner)? - }; - - let mut hasher = Hasher::default(); - hasher.hash(b"global:withdraw_tokens"); - - let mut data = hasher.result().as_ref()[..8].to_vec(); - data.extend_from_slice(&lp_amount.to_le_bytes()); - - let saber_accounts = vec![ - AccountMeta::new_readonly(*user_account.key, true), - AccountMeta::new(*miner.key, false), - AccountMeta::new(*quarry.key, false), - AccountMeta::new(*miner_vault.key, false), - AccountMeta::new(*user_lp_token_account.key, false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new_readonly(*rewarder.key, false), - ]; - - let instruction = Instruction { - program_id: quarry_mine::id(), - accounts: saber_accounts, - data, - }; - - invoke(&instruction, accounts)?; - - account::check_tokens_received( - user_lp_token_account, - initial_lp_token_user_balance, - lp_amount, - )?; - } else { - return Err(ProgramError::NotEnoughAccountKeys); - } - - msg!("AmmInstruction::Unstake complete"); - Ok(()) -} diff --git a/farms/router-saber/src/unwrap_token.rs b/farms/router-saber/src/unwrap_token.rs deleted file mode 100644 index 4e1b77015b8..00000000000 --- a/farms/router-saber/src/unwrap_token.rs +++ /dev/null @@ -1,77 +0,0 @@ -//! Unwrap token from a Saber decimal token instruction - -use { - solana_farm_sdk::program::{account, protocol::saber}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn unwrap_token(accounts: &[AccountInfo], amount: u64) -> ProgramResult { - msg!("Processing AmmInstruction::UnwrapToken"); - msg!("amount {} ", amount); - - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - user_underlying_token_account, - underlying_token_mint, - _spl_token_id, - decimal_wrapper_program, - user_wrapped_token_account, - wrapped_token_mint, - wrapped_token_vault, - decimal_wrapper - ] = accounts - { - if !account::check_token_account_owner(user_underlying_token_account, user_account.key)? { - return Err(ProgramError::IllegalOwner); - } - - let initial_underlying_token_user_balance = - account::get_token_balance(user_underlying_token_account)?; - let initial_wrapped_token_user_balance = - account::get_token_balance(user_wrapped_token_account)?; - - let underlying_decimals = account::get_token_decimals(underlying_token_mint)?; - let wrapped_decimals = account::get_token_decimals(wrapped_token_mint)?; - - let unwrap_amount = if amount > 0 { - amount - } else { - initial_wrapped_token_user_balance - }; - - saber::unwrap_token( - decimal_wrapper, - wrapped_token_mint, - wrapped_token_vault, - user_account, - user_underlying_token_account, - user_wrapped_token_account, - decimal_wrapper_program.key, - unwrap_amount, - )?; - - account::check_tokens_received( - user_underlying_token_account, - initial_underlying_token_user_balance, - account::to_amount_with_new_decimals( - unwrap_amount, - wrapped_decimals, - underlying_decimals, - )?, - )?; - account::check_tokens_spent( - user_wrapped_token_account, - initial_wrapped_token_user_balance, - unwrap_amount, - )?; - } else { - return Err(ProgramError::NotEnoughAccountKeys); - } - - msg!("AmmInstruction::UnwrapToken complete"); - Ok(()) -} diff --git a/farms/router-saber/src/user_init.rs b/farms/router-saber/src/user_init.rs deleted file mode 100644 index 7784399e132..00000000000 --- a/farms/router-saber/src/user_init.rs +++ /dev/null @@ -1,88 +0,0 @@ -//! Initialize a new user for a Saber farm instruction - -use { - solana_farm_sdk::program::account, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - hash::Hasher, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke, - program_error::ProgramError, - pubkey::Pubkey, - system_program, - }, -}; - -pub fn user_init(accounts: &[AccountInfo]) -> ProgramResult { - msg!("Processing AmmInstruction::UserInit"); - - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - funding_account, - user_account, - farm_program_id, - lp_token_mint, - _spl_token_id, - _system_program, - miner, - miner_vault, - quarry, - rewarder - ] = accounts - { - if &quarry_mine::id() != farm_program_id.key { - return Err(ProgramError::IncorrectProgramId); - } - if account::exists(miner)? { - return Err(ProgramError::AccountAlreadyInitialized); - } - - let (miner_derived, bump) = Pubkey::find_program_address( - &[ - b"Miner", - &quarry.key.to_bytes(), - &user_account.key.to_bytes(), - ], - &quarry_mine::id(), - ); - - if &miner_derived != miner.key { - msg!("Error: Invalid Miner address"); - return Err(ProgramError::InvalidSeeds); - } - - let mut hasher = Hasher::default(); - hasher.hash(b"global:create_miner"); - - let mut data = hasher.result().as_ref()[..8].to_vec(); - data.push(bump); - - let saber_accounts = vec![ - AccountMeta::new(*funding_account.key, true), - AccountMeta::new(*miner.key, false), - AccountMeta::new(*quarry.key, false), - AccountMeta::new(*rewarder.key, false), - AccountMeta::new_readonly(system_program::id(), false), - AccountMeta::new_readonly(*funding_account.key, true), - AccountMeta::new(*lp_token_mint.key, false), - AccountMeta::new(*miner_vault.key, false), - AccountMeta::new_readonly(spl_token::id(), false), - ]; - - let instruction = Instruction { - program_id: quarry_mine::id(), - accounts: saber_accounts, - data, - }; - - invoke(&instruction, accounts)?; - } else { - return Err(ProgramError::NotEnoughAccountKeys); - } - - msg!("AmmInstruction::UserInit complete"); - Ok(()) -} diff --git a/farms/router-saber/src/wrap_token.rs b/farms/router-saber/src/wrap_token.rs deleted file mode 100644 index 7a6f3de2926..00000000000 --- a/farms/router-saber/src/wrap_token.rs +++ /dev/null @@ -1,67 +0,0 @@ -//! Wrap token to a Saber decimal token instruction - -use { - solana_farm_sdk::program::{account, protocol::saber}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn wrap_token(accounts: &[AccountInfo], amount: u64) -> ProgramResult { - msg!("Processing AmmInstruction::WrapToken"); - msg!("amount {} ", amount); - - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - user_underlying_token_account, - underlying_token_mint, - _spl_token_id, - decimal_wrapper_program, - user_wrapped_token_account, - wrapped_token_mint, - wrapped_token_vault, - decimal_wrapper - ] = accounts - { - if !account::check_token_account_owner(user_wrapped_token_account, user_account.key)? { - return Err(ProgramError::IllegalOwner); - } - - let initial_underlying_token_user_balance = - account::get_token_balance(user_underlying_token_account)?; - let initial_wrapped_token_user_balance = - account::get_token_balance(user_wrapped_token_account)?; - - let underlying_decimals = account::get_token_decimals(underlying_token_mint)?; - let wrapped_decimals = account::get_token_decimals(wrapped_token_mint)?; - - saber::wrap_token( - decimal_wrapper, - wrapped_token_mint, - wrapped_token_vault, - user_account, - user_underlying_token_account, - user_wrapped_token_account, - decimal_wrapper_program.key, - amount, - )?; - - account::check_tokens_spent( - user_underlying_token_account, - initial_underlying_token_user_balance, - amount, - )?; - account::check_tokens_received( - user_wrapped_token_account, - initial_wrapped_token_user_balance, - account::to_amount_with_new_decimals(amount, underlying_decimals, wrapped_decimals)?, - )?; - } else { - return Err(ProgramError::NotEnoughAccountKeys); - } - - msg!("AmmInstruction::WrapToken complete"); - Ok(()) -} diff --git a/farms/vaults/.gitignore b/farms/vaults/.gitignore deleted file mode 100644 index 96ef6c0b944..00000000000 --- a/farms/vaults/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -Cargo.lock diff --git a/farms/vaults/Cargo.toml b/farms/vaults/Cargo.toml deleted file mode 100644 index 27099f4957b..00000000000 --- a/farms/vaults/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -name = "solana-vaults" -version = "1.1.3" -description = "Solana Vaults" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana-program-library/farms" -license = "Apache-2.0" -homepage = "https://solana.com/" -edition = "2021" - -[features] -no-entrypoint = [] -debug = [] -test-bpf = [] -RDM-STAKE-LP-COMPOUND = [] -SBR-STAKE-LP-COMPOUND = [] -ORC-STAKE-LP-COMPOUND = [] -default = ["RDM-STAKE-LP-COMPOUND"] - -[dependencies] -solana-farm-sdk = "1.1.3" -solana-program = "1.9.18" -solana-security-txt = "1.0.1" -spl-token = { version = "3.2.0", features = ["no-entrypoint"] } -arrayref = "0.3.6" - -[dev-dependencies] -solana-program-test = "1.9.18" - -[lib] -crate-type = ["cdylib", "lib"] - diff --git a/farms/vaults/README.md b/farms/vaults/README.md deleted file mode 120000 index ccd27901fd5..00000000000 --- a/farms/vaults/README.md +++ /dev/null @@ -1 +0,0 @@ -../docs/crate.md \ No newline at end of file diff --git a/farms/vaults/Xargo.toml b/farms/vaults/Xargo.toml deleted file mode 100644 index 1744f098ae1..00000000000 --- a/farms/vaults/Xargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.bpfel-unknown-unknown.dependencies.std] -features = [] \ No newline at end of file diff --git a/farms/vaults/src/entrypoint.rs b/farms/vaults/src/entrypoint.rs deleted file mode 100644 index 32424d2752e..00000000000 --- a/farms/vaults/src/entrypoint.rs +++ /dev/null @@ -1,272 +0,0 @@ -//! Vaults entrypoint. - -#![cfg(not(feature = "no-entrypoint"))] - -solana_security_txt::security_txt! { - name: "Solana Farms", - project_url: "https://github.com/solana-labs/solana-program-library/tree/master/farms", - contacts: "email:solana.farms@protonmail.com", - policy: "", - preferred_languages: "en", - auditors: "Halborn" -} - -use { - crate::{traits::*, vault_info::VaultInfo}, - solana_farm_sdk::{ - error::FarmError, - id::{main_router, main_router_admin, main_router_multisig}, - instruction::vault::VaultInstruction, - log::sol_log_params_short, - program::multisig, - refdb, - string::ArrayString64, - traits::Packed, - vault::Vault, - }, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint, - entrypoint::ProgramResult, - log::sol_log_compute_units, - msg, - program_error::ProgramError, - pubkey::Pubkey, - }, -}; - -fn log_start(instruction: &str, vault_name: &ArrayString64) { - msg!( - "Processing VaultInstruction::{} for {}", - instruction, - vault_name.as_str() - ); - sol_log_compute_units(); -} - -fn log_end(vault_name: &ArrayString64) { - sol_log_compute_units(); - msg!("Vault {} end of instruction", vault_name.as_str()); -} - -fn check_authority( - accounts: &[AccountInfo], - instruction_data: &[u8], - vault: &Vault, -) -> Result { - let account_info_iter = &mut accounts.iter(); - let admin_account = next_account_info(account_info_iter)?; - let _vault_metadata = next_account_info(account_info_iter)?; - let _vault_info_account = next_account_info(account_info_iter)?; - let multisig_account = next_account_info(account_info_iter)?; - - if multisig_account.key != &vault.multisig_account - && multisig_account.key != &main_router_multisig::id() - { - msg!("Error: Invalid multisig account"); - return Err(FarmError::IncorrectAccountAddress.into()); - } - - let signatures_left = multisig::sign_multisig( - multisig_account, - admin_account, - &main_router_admin::id(), - &accounts[1..], - instruction_data, - )?; - if signatures_left > 0 { - msg!( - "Instruction has been signed but more signatures are required: {}", - signatures_left - ); - return Ok(false); - } - - Ok(true) -} - -entrypoint!(process_instruction); -/// Program's entrypoint. -/// -/// # Arguments -/// * `program_id` - Public key of the vault. -/// * `accounts` - Accounts, see handlers in particular strategy for the list. -/// * `instructions_data` - Packed VaultInstruction. -pub fn process_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - instruction_data: &[u8], -) -> ProgramResult { - msg!("Vault entrypoint"); - if cfg!(feature = "debug") { - sol_log_params_short(accounts, instruction_data); - } - - let account_info_iter = &mut accounts.iter(); - let _user_account = next_account_info(account_info_iter)?; - let vault_metadata = next_account_info(account_info_iter)?; - let vault_info_account = next_account_info(account_info_iter)?; - - // unpack Vault's metadata and validate Vault accounts - let vault = Vault::unpack(&vault_metadata.try_borrow_data()?)?; - let derived_vault_metadata = refdb::find_target_pda_with_bump( - refdb::StorageType::Vault, - &vault.name, - vault.metadata_bump, - )?; - if &vault.info_account != vault_info_account.key - || &derived_vault_metadata != vault_metadata.key - || vault_metadata.owner != &main_router::id() - { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - if &vault.vault_program_id != program_id { - msg!("Error: Invalid Vault program id"); - return Err(ProgramError::IncorrectProgramId); - } - - // Read and unpack instruction data - let instruction = VaultInstruction::unpack(instruction_data)?; - - match instruction { - VaultInstruction::UserInit => { - log_start("UserInit", &vault.name); - VaultInstruction::user_init(&vault, accounts)?; - } - VaultInstruction::AddLiquidity { - max_token_a_amount, - max_token_b_amount, - } => { - log_start("AddLiquidity", &vault.name); - VaultInstruction::add_liquidity( - &vault, - accounts, - max_token_a_amount, - max_token_b_amount, - )?; - } - VaultInstruction::LockLiquidity { amount } => { - log_start("LockLiquidity", &vault.name); - VaultInstruction::lock_liquidity(&vault, accounts, amount)?; - } - VaultInstruction::UnlockLiquidity { amount } => { - log_start("UnlockLiquidity", &vault.name); - VaultInstruction::unlock_liquidity(&vault, accounts, amount)?; - } - VaultInstruction::RemoveLiquidity { amount } => { - log_start("RemoveLiquidity", &vault.name); - VaultInstruction::remove_liquidity(&vault, accounts, amount)?; - } - VaultInstruction::SetMinCrankInterval { min_crank_interval } => { - log_start("SetMinCrankInterval", &vault.name); - if check_authority(accounts, instruction_data, &vault)? { - VaultInstruction::set_min_crank_interval( - &vault, - &mut VaultInfo::new(vault_info_account), - accounts, - min_crank_interval as u64, - )?; - } - } - VaultInstruction::SetFee { fee } => { - log_start("SetFee", &vault.name); - if check_authority(accounts, instruction_data, &vault)? { - VaultInstruction::set_fee( - &vault, - &mut VaultInfo::new(vault_info_account), - accounts, - fee as f64, - )?; - } - } - VaultInstruction::SetExternalFee { external_fee } => { - log_start("SetExternalFee", &vault.name); - if check_authority(accounts, instruction_data, &vault)? { - VaultInstruction::set_external_fee( - &vault, - &mut VaultInfo::new(vault_info_account), - accounts, - external_fee as f64, - )?; - } - } - VaultInstruction::EnableDeposits => { - log_start("EnableDeposits", &vault.name); - if check_authority(accounts, instruction_data, &vault)? { - VaultInstruction::enable_deposits( - &vault, - &mut VaultInfo::new(vault_info_account), - accounts, - )?; - } - } - VaultInstruction::DisableDeposits => { - log_start("DisableDeposits", &vault.name); - if check_authority(accounts, instruction_data, &vault)? { - VaultInstruction::disable_deposits( - &vault, - &mut VaultInfo::new(vault_info_account), - accounts, - )?; - } - } - VaultInstruction::EnableWithdrawals => { - log_start("EnableWithdrawals", &vault.name); - if check_authority(accounts, instruction_data, &vault)? { - VaultInstruction::enable_withdrawals( - &vault, - &mut VaultInfo::new(vault_info_account), - accounts, - )?; - } - } - VaultInstruction::DisableWithdrawals => { - log_start("DisableWithdrawals", &vault.name); - if check_authority(accounts, instruction_data, &vault)? { - VaultInstruction::disable_withdrawals( - &vault, - &mut VaultInfo::new(vault_info_account), - accounts, - )?; - } - } - VaultInstruction::Crank { step } => { - log_start("Crank", &vault.name); - VaultInstruction::crank(&vault, accounts, step)?; - } - VaultInstruction::Init { step } => { - log_start("Init", &vault.name); - if check_authority(accounts, instruction_data, &vault)? { - VaultInstruction::init(&vault, accounts, step)?; - } - } - VaultInstruction::Shutdown => { - log_start("Shutdown", &vault.name); - if check_authority(accounts, instruction_data, &vault)? { - VaultInstruction::shutdown(&vault, accounts)?; - } - } - VaultInstruction::WithdrawFees { amount } => { - log_start("WithdrawFees", &vault.name); - if check_authority(accounts, instruction_data, &vault)? { - VaultInstruction::withdraw_fees(&vault, accounts, amount)?; - } - } - VaultInstruction::SetAdminSigners { min_signatures } => { - log_start("SetAdminSigners", &vault.name); - if check_authority(accounts, instruction_data, &vault)? { - VaultInstruction::set_admin_signers(&vault, accounts, min_signatures)?; - } - } - VaultInstruction::RemoveMultisig => { - log_start("RemoveMultisig", &vault.name); - if check_authority(accounts, instruction_data, &vault)? { - VaultInstruction::remove_multisig(&vault, accounts)?; - } - } - } - - log_end(&vault.name); - Ok(()) -} diff --git a/farms/vaults/src/lib.rs b/farms/vaults/src/lib.rs deleted file mode 100644 index 61fb906519d..00000000000 --- a/farms/vaults/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![forbid(unsafe_code)] - -mod entrypoint; -pub mod strategies; -pub mod traits; -pub mod user_info; -pub mod vault_info; diff --git a/farms/vaults/src/strategies/common.rs b/farms/vaults/src/strategies/common.rs deleted file mode 100644 index a8fdaa5f05c..00000000000 --- a/farms/vaults/src/strategies/common.rs +++ /dev/null @@ -1,101 +0,0 @@ -//! Common functions - -use { - crate::vault_info::VaultInfo, - solana_farm_sdk::{ - id::zero, - program::clock, - vault::{Vault, VaultStrategy}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - pubkey::Pubkey, - }, - std::cmp, -}; - -#[allow(clippy::too_many_arguments)] -pub fn check_custody_accounts<'a, 'b>( - vault: &Vault, - lp_token_custody: &'a AccountInfo<'b>, - token_a_custody: &'a AccountInfo<'b>, - token_b_custody: &'a AccountInfo<'b>, - token_a_reward_custody: &'a AccountInfo<'b>, - token_b_reward_custody: &'a AccountInfo<'b>, - vault_stake_info: &'a AccountInfo<'b>, - pool_id: Option<&Pubkey>, - farm_id: Option<&Pubkey>, - check_non_reward_custody: bool, -) -> ProgramResult { - if let VaultStrategy::StakeLpCompoundRewards { - pool_id: pool_id_key, - farm_id: farm_id_key, - lp_token_custody: lp_token_custody_key, - token_a_custody: token_a_custody_key, - token_b_custody: token_b_custody_key, - token_a_reward_custody: token_a_reward_custody_key, - token_b_reward_custody: token_b_reward_custody_key, - vault_stake_info: vault_stake_info_key, - .. - } = vault.strategy - { - if &vault_stake_info_key != vault_stake_info.key { - msg!("Error: Invalid Vault Stake Info account"); - return Err(ProgramError::InvalidArgument); - } - if &token_a_reward_custody_key != token_a_reward_custody.key - || &token_b_reward_custody_key - .or_else(|| Some(zero::id())) - .unwrap() - != token_b_reward_custody.key - || &lp_token_custody_key != lp_token_custody.key - { - msg!("Error: Invalid custody accounts"); - return Err(ProgramError::InvalidArgument); - } - if check_non_reward_custody - && (&token_a_custody_key != token_a_custody.key - || &token_b_custody_key.or_else(|| Some(zero::id())).unwrap() - != token_b_custody.key) - { - msg!("Error: Invalid custody accounts"); - return Err(ProgramError::InvalidArgument); - } - if let Some(pool_id) = pool_id { - if pool_id != &pool_id_key { - msg!("Error: Invalid pool id"); - return Err(ProgramError::InvalidArgument); - } - } - if let Some(farm_id) = farm_id { - if farm_id != &farm_id_key { - msg!("Error: Invalid farm id"); - return Err(ProgramError::InvalidArgument); - } - } - } else { - msg!("Error: Vault strategy mismatch"); - return Err(ProgramError::InvalidArgument); - } - Ok(()) -} - -pub fn check_min_crank_interval(vault_info: &VaultInfo) -> ProgramResult { - let min_crank_interval = vault_info.get_min_crank_interval()?; - if min_crank_interval == 0 { - return Ok(()); - } - let last_crank_time = vault_info.get_crank_time()?; - let cur_time = cmp::max(clock::get_time()?, last_crank_time); - if cur_time < last_crank_time.wrapping_add(min_crank_interval) { - msg!( - "Error: Too early, please wait for the additional {} sec", - last_crank_time - .wrapping_add(min_crank_interval) - .wrapping_sub(cur_time) - ); - Err(ProgramError::Custom(309)) - } else { - Ok(()) - } -} diff --git a/farms/vaults/src/strategies/mod.rs b/farms/vaults/src/strategies/mod.rs deleted file mode 100644 index cb3e99d409a..00000000000 --- a/farms/vaults/src/strategies/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -#[cfg(feature = "RDM-STAKE-LP-COMPOUND")] -pub mod rdm_stake_lp_compound; - -#[cfg(feature = "SBR-STAKE-LP-COMPOUND")] -pub mod sbr_stake_lp_compound; - -#[cfg(feature = "ORC-STAKE-LP-COMPOUND")] -pub mod orc_stake_lp_compound; - -pub mod common; diff --git a/farms/vaults/src/strategies/orc_stake_lp_compound/add_liquidity.rs b/farms/vaults/src/strategies/orc_stake_lp_compound/add_liquidity.rs deleted file mode 100644 index 207517cee9a..00000000000 --- a/farms/vaults/src/strategies/orc_stake_lp_compound/add_liquidity.rs +++ /dev/null @@ -1,166 +0,0 @@ -//! Add Liquidity to the Vault instruction handler - -use { - crate::{traits::AddLiquidity, user_info::UserInfo, vault_info::VaultInfo}, - solana_farm_sdk::{ - instruction::vault::VaultInstruction, - program::{account, protocol::orca}, - vault::{Vault, VaultStrategy}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl AddLiquidity for VaultInstruction { - fn add_liquidity( - vault: &Vault, - accounts: &[AccountInfo], - max_token_a_amount: u64, - max_token_b_amount: u64, - ) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - _vault_metadata, - vault_info_account, - spl_token_program, - user_info_account, - user_token_a_account, - user_token_b_account, - user_lp_token_account, - lp_token_custody, - pool_program_id, - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - amm_id, - amm_authority, - ] = accounts - { - // validate accounts - if !user_account.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - if !account::check_token_account_owner(user_lp_token_account, user_account.key)? { - msg!("Error: Invalid token account owner"); - return Err(ProgramError::IllegalOwner); - } - if let VaultStrategy::StakeLpCompoundRewards { - pool_id: pool_id_key, - lp_token_custody: lp_token_custody_key, - .. - } = vault.strategy - { - if &pool_id_key != amm_id.key { - msg!("Error: Invalid pool id"); - return Err(ProgramError::InvalidArgument); - } - if &lp_token_custody_key != lp_token_custody.key { - msg!("Error: Invalid custody accounts"); - return Err(ProgramError::InvalidArgument); - } - } else { - msg!("Error: Vault strategy mismatch"); - return Err(ProgramError::InvalidArgument); - } - - if !UserInfo::validate_account(vault, user_info_account, user_account.key) { - msg!("Error: Invalid user info account"); - return Err(ProgramError::Custom(140)); - } - - let mut vault_info = VaultInfo::new(vault_info_account); - if !vault_info.is_deposit_allowed()? { - msg!("Error: Deposits are not allowed for this Vault"); - return Err(ProgramError::Custom(220)); - } - - // read user balances - let initial_token_a_user_balance = account::get_token_balance(user_token_a_account)?; - let initial_token_b_user_balance = account::get_token_balance(user_token_b_account)?; - let initial_lp_user_balance = account::get_token_balance(user_lp_token_account)?; - - // calculate deposit amounts - let (min_lp_token_amount, max_token_a_deposit_amount, max_token_b_deposit_amount) = - orca::get_pool_deposit_amounts( - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - max_token_a_amount, - max_token_b_amount, - )?; - - // Deposit tokens into the pool - msg!("Deposit tokens into the pool. max_token_a_deposit_amount: {}, max_token_b_deposit_amount: {}", max_token_a_deposit_amount, max_token_b_deposit_amount); - if max_token_a_deposit_amount == 0 || max_token_b_deposit_amount == 0 { - msg!("Error: Zero deposit amount"); - return Err(ProgramError::InsufficientFunds); - } - orca::add_liquidity( - &[ - user_account.clone(), - user_token_a_account.clone(), - user_token_b_account.clone(), - user_lp_token_account.clone(), - pool_program_id.clone(), - pool_token_a_account.clone(), - pool_token_b_account.clone(), - lp_token_mint.clone(), - spl_token_program.clone(), - amm_id.clone(), - amm_authority.clone(), - ], - max_token_a_deposit_amount, - max_token_b_deposit_amount, - min_lp_token_amount, - )?; - - // check amounts spent and received - let tokens_a_spent = account::check_tokens_spent( - user_token_a_account, - initial_token_a_user_balance, - max_token_a_deposit_amount, - )?; - let tokens_b_spent = account::check_tokens_spent( - user_token_b_account, - initial_token_b_user_balance, - max_token_b_deposit_amount, - )?; - let lp_tokens_received = account::check_tokens_received( - user_lp_token_account, - initial_lp_user_balance, - min_lp_token_amount, - )?; - - // transfer LP tokens to the custody - msg!( - "Transfer LP tokens from user. tokens_a_spent: {}, tokens_b_spent: {}, lp_tokens_received: {}", - tokens_a_spent, - tokens_b_spent, - lp_tokens_received - ); - account::transfer_tokens( - user_lp_token_account, - lp_token_custody, - user_account, - lp_tokens_received, - )?; - - // update user stats - msg!("Update user stats"); - let mut user_info = UserInfo::new(user_info_account); - user_info.add_liquidity(tokens_a_spent, tokens_b_spent)?; - user_info.add_lp_tokens_debt(lp_tokens_received)?; - - // update Vault stats - msg!("Update Vault stats"); - vault_info.add_liquidity(tokens_a_spent, tokens_b_spent)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } - } -} diff --git a/farms/vaults/src/strategies/orc_stake_lp_compound/crank.rs b/farms/vaults/src/strategies/orc_stake_lp_compound/crank.rs deleted file mode 100644 index 715b52818ed..00000000000 --- a/farms/vaults/src/strategies/orc_stake_lp_compound/crank.rs +++ /dev/null @@ -1,26 +0,0 @@ -//! Vault Crank instruction handler - -use { - crate::{ - strategies::orc_stake_lp_compound::{crank1::crank1, crank2::crank2, crank3::crank3}, - traits::Crank, - }, - solana_farm_sdk::{instruction::vault::VaultInstruction, vault::Vault}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl Crank for VaultInstruction { - fn crank(vault: &Vault, accounts: &[AccountInfo], step: u64) -> ProgramResult { - match step { - 1 => crank1(vault, accounts), - 2 => crank2(vault, accounts), - 3 => crank3(vault, accounts), - _ => { - msg!("Error: Invalid Crank step"); - Err(ProgramError::InvalidArgument) - } - } - } -} diff --git a/farms/vaults/src/strategies/orc_stake_lp_compound/crank1.rs b/farms/vaults/src/strategies/orc_stake_lp_compound/crank1.rs deleted file mode 100644 index 01dd080b2e2..00000000000 --- a/farms/vaults/src/strategies/orc_stake_lp_compound/crank1.rs +++ /dev/null @@ -1,133 +0,0 @@ -//! Crank step 1 instruction handler - -use { - crate::{strategies::common, vault_info::VaultInfo}, - solana_farm_sdk::{ - math, - program::{account, pda, protocol::orca}, - vault::{Vault, VaultStrategy}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn crank1(vault: &Vault, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _funding_account, - _vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - reward_token_custody, - fees_account, - farm_program, - vault_stake_info, - farm_id, - farm_authority, - base_token_vault, - reward_token_vault - ] = accounts - { - // validate accounts - if vault_authority.key != &vault.vault_authority { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - if let VaultStrategy::StakeLpCompoundRewards { - farm_id: farm_id_key, - token_a_reward_custody: token_a_reward_custody_key, - vault_stake_info: vault_stake_info_key, - .. - } = vault.strategy - { - if &vault_stake_info_key != vault_stake_info.key { - msg!("Error: Invalid Vault Stake Info account"); - return Err(ProgramError::InvalidArgument); - } - if &token_a_reward_custody_key != reward_token_custody.key { - msg!("Error: Invalid custody accounts"); - return Err(ProgramError::InvalidArgument); - } - if farm_id.key != &farm_id_key { - msg!("Error: Invalid farm id"); - return Err(ProgramError::InvalidArgument); - } - } else { - msg!("Error: Vault strategy mismatch"); - return Err(ProgramError::InvalidArgument); - } - - if Some(*fees_account.key) != vault.fees_account_a { - msg!("Error: Invalid fee accounts"); - return Err(ProgramError::InvalidArgument); - } - - let mut vault_info = VaultInfo::new(vault_info_account); - common::check_min_crank_interval(&vault_info)?; - - // harvest - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - - let initial_reward_token_reward_balance = account::get_token_balance(reward_token_custody)?; - - msg!("Harvest rewards"); - orca::harvest_with_seeds( - &[ - vault_authority.clone(), - vault_stake_info.clone(), - reward_token_custody.clone(), - farm_program.clone(), - base_token_vault.clone(), - reward_token_vault.clone(), - spl_token_program.clone(), - farm_id.clone(), - farm_authority.clone(), - ], - seeds, - )?; - - // calculate rewards - let token_rewards = account::get_balance_increase( - reward_token_custody, - initial_reward_token_reward_balance, - )?; - msg!("Rewards received. token_rewards: {}", token_rewards); - - // take fees - let fee = vault_info.get_fee()?; - if !(0.0..=1.0).contains(&fee) { - msg!("Error: Invalid fee. fee: {}", fee); - return Err(ProgramError::Custom(260)); - } - let mut fees = math::checked_as_u64(token_rewards as f64 * fee)?; - if fees == 0 && token_rewards > 0 { - fees = 1; - } - - msg!("Apply fees. fee: {}, fees: {}", fee, fees); - pda::transfer_tokens_with_seeds( - reward_token_custody, - fees_account, - vault_authority, - seeds, - fees, - )?; - - // update Vault stats - msg!("Update Vault stats",); - vault_info.add_rewards(token_rewards, 0)?; - vault_info.update_crank_time()?; - vault_info.set_crank_step(1)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/vaults/src/strategies/orc_stake_lp_compound/crank2.rs b/farms/vaults/src/strategies/orc_stake_lp_compound/crank2.rs deleted file mode 100644 index b9c766851d9..00000000000 --- a/farms/vaults/src/strategies/orc_stake_lp_compound/crank2.rs +++ /dev/null @@ -1,327 +0,0 @@ -//! Crank step 2 instruction handler - -use { - crate::{strategies::common, vault_info::VaultInfo}, - solana_farm_sdk::{ - id::zero, - program, - program::{account, pda, protocol::orca}, - vault::{Vault, VaultStrategy}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn crank2(vault: &Vault, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _funding_account, - _vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - reward_token_custody, - token_a_custody, - token_b_custody, - pool_program_id, - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - amm_id, - amm_authority, - pool_fees_account, - rdex_pool_token_a_account, - rdex_pool_token_b_account, - rdex_lp_token_mint, - rdex_amm_id, - rdex_amm_authority, - rdex_pool_fees_account, - sysvar_account - ] = accounts - { - // validate accounts - if vault_authority.key != &vault.vault_authority { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - if let VaultStrategy::StakeLpCompoundRewards { - pool_id: pool_id_key, - token_a_custody: token_a_custody_key, - token_b_custody: token_b_custody_key, - token_a_reward_custody: token_a_reward_custody_key, - reward_exchange_pool_id, - .. - } = vault.strategy - { - if &token_a_reward_custody_key != reward_token_custody.key - || &token_a_custody_key != token_a_custody.key - || &token_b_custody_key.or_else(|| Some(zero::id())).unwrap() != token_b_custody.key - { - msg!("Error: Invalid custody accounts"); - return Err(ProgramError::InvalidArgument); - } - if &pool_id_key != amm_id.key - || &reward_exchange_pool_id - .or_else(|| Some(zero::id())) - .unwrap() - != rdex_amm_id.key - { - msg!("Error: Invalid pool id"); - return Err(ProgramError::InvalidArgument); - } - } else { - msg!("Error: Vault strategy mismatch"); - return Err(ProgramError::InvalidArgument); - } - - if !program::is_last_instruction(sysvar_account)? { - msg!("Error: Crank2 must be the last instruction in the transaction"); - return Err(ProgramError::InvalidArgument); - } - - let mut vault_info = VaultInfo::new(vault_info_account); - common::check_min_crank_interval(&vault_info)?; - vault_info.update_crank_time()?; - vault_info.set_crank_step(2)?; - - // read reward balance - let reward_token_balance = account::get_token_balance(reward_token_custody)?; - msg!( - "Read reward balance. reward_token_balance: {}", - reward_token_balance - ); - - // move rewards to token custodies - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - - let reward_token_mint = account::get_token_account_mint(reward_token_custody)?; - let token_a_custody_mint = account::get_token_account_mint(token_a_custody)?; - let token_b_custody_mint = account::get_token_account_mint(token_b_custody)?; - - if reward_token_mint == token_a_custody_mint { - pda::transfer_tokens_with_seeds( - reward_token_custody, - token_a_custody, - vault_authority, - seeds, - reward_token_balance, - )?; - } else if reward_token_mint == token_b_custody_mint { - pda::transfer_tokens_with_seeds( - reward_token_custody, - token_b_custody, - vault_authority, - seeds, - reward_token_balance, - )?; - } else if reward_token_balance > 0 { - // if rewards are not in pool tokens we need to swap - // determine swap direction - let rdex_pool_token_b_mint = - account::get_token_account_mint(rdex_pool_token_b_account)?; - let destination_token_custody = if rdex_pool_token_b_mint == token_a_custody_mint { - token_a_custody - } else if rdex_pool_token_b_mint == token_b_custody_mint { - token_b_custody - } else { - msg!("Error: Invalid reward exchange pool"); - return Err(ProgramError::InvalidArgument); - }; - // calculate amounts - let initial_tokens_spent_balance = account::get_token_balance(reward_token_custody)?; - let initial_tokens_received_balance = - account::get_token_balance(destination_token_custody)?; - let (amount_in, min_amount_out) = orca::get_pool_swap_amounts( - rdex_pool_token_a_account, - rdex_pool_token_b_account, - reward_token_balance, - 0, - )?; - // swap - msg!( - "Swap rewards. amount_in: {}, min_amount_out {}", - amount_in, - min_amount_out - ); - orca::swap_with_seeds( - &[ - vault_authority.clone(), - reward_token_custody.clone(), - destination_token_custody.clone(), - pool_program_id.clone(), - rdex_pool_token_a_account.clone(), - rdex_pool_token_b_account.clone(), - rdex_lp_token_mint.clone(), - spl_token_program.clone(), - rdex_amm_id.clone(), - rdex_amm_authority.clone(), - rdex_pool_fees_account.clone(), - ], - seeds, - amount_in, - min_amount_out, - )?; - // check results - let _ = account::check_tokens_spent( - reward_token_custody, - initial_tokens_spent_balance, - amount_in, - )?; - let _ = account::check_tokens_received( - destination_token_custody, - initial_tokens_received_balance, - min_amount_out, - )?; - } - - // read balances - let token_a_balance = account::get_token_balance(token_a_custody)?; - let token_b_balance = account::get_token_balance(token_b_custody)?; - msg!( - "Read balances. token_a_balance: {}, token_b_balance: {}", - token_a_balance, - token_b_balance - ); - if token_a_balance < 10 && token_b_balance < 10 { - msg!("Nothing to do: Not enough tokens to balance"); - return Ok(()); - } - - // rebalance - // compute and check pool ratios - let (pool_token_a_balance, pool_token_b_balance) = - orca::get_pool_token_balances(pool_token_a_account, pool_token_b_account)?; - let pool_ratio = if pool_token_a_balance != 0 { - pool_token_b_balance as f64 / pool_token_a_balance as f64 - } else { - 0.0 - }; - let custody_ratio = account::get_token_pair_ratio(token_a_custody, token_b_custody)?; - msg!( - "Compute pool ratios. custody_ratio: {}, pool_ratio: {}", - custody_ratio, - pool_ratio - ); - if pool_ratio == 0.0 { - msg!("Can't balance: Pool ratio is zero"); - return Ok(()); - } - if custody_ratio > 0.0 && (custody_ratio - pool_ratio).abs() * 100.0 / pool_ratio < 3.0 { - msg!("Nothing to do: Already balanced"); - return Ok(()); - } - - // compute ui amount to exchange - let extra_a_tokens = - (token_a_balance as f64 * pool_ratio - token_b_balance as f64) / (2.0 * pool_ratio); - let extra_b_tokens = extra_a_tokens * pool_ratio; - let reverse = extra_a_tokens < 0.0; - msg!( - "Rebalance tokens. reverse: {}, extra_a_tokens: {}, extra_b_tokens: {}", - reverse, - extra_a_tokens, - extra_b_tokens - ); - - let ( - token_a_swap_custody, - token_b_swap_custody, - pool_token_a_swap_account, - pool_token_b_swap_account, - ) = if reverse { - ( - token_b_custody, - token_a_custody, - pool_token_b_account, - pool_token_a_account, - ) - } else { - ( - token_a_custody, - token_b_custody, - pool_token_a_account, - pool_token_b_account, - ) - }; - let token_a_extra_amount_in = if !reverse { - account::to_token_amount(extra_a_tokens.abs(), 0)? - } else { - 0 - }; - let token_b_extra_amount_in = if !reverse { - 0 - } else { - account::to_token_amount(extra_b_tokens.abs(), 0)? - }; - if token_a_extra_amount_in < 2 && token_b_extra_amount_in < 2 { - msg!("Nothing to do: Not enough tokens to balance"); - return Ok(()); - } - - // get exact swap amounts - let (amount_in, min_amount_out) = orca::get_pool_swap_amounts( - pool_token_a_account, - pool_token_b_account, - token_a_extra_amount_in, - token_b_extra_amount_in, - )?; - msg!( - "Swap. amount_in: {}, min_amount_out {}", - amount_in, - min_amount_out - ); - if amount_in == 0 || min_amount_out == 0 { - msg!("Nothing to do: Not enough tokens to balance"); - return Ok(()); - } - - let initial_tokens_spent_balance = account::get_token_balance(token_a_swap_custody)?; - let initial_tokens_received_balance = account::get_token_balance(token_b_swap_custody)?; - - orca::swap_with_seeds( - &[ - vault_authority.clone(), - token_a_swap_custody.clone(), - token_b_swap_custody.clone(), - pool_program_id.clone(), - pool_token_a_swap_account.clone(), - pool_token_b_swap_account.clone(), - lp_token_mint.clone(), - spl_token_program.clone(), - amm_id.clone(), - amm_authority.clone(), - pool_fees_account.clone(), - ], - seeds, - amount_in, - min_amount_out, - )?; - let _ = account::check_tokens_spent( - token_a_swap_custody, - initial_tokens_spent_balance, - amount_in, - )?; - let tokens_received = account::check_tokens_received( - token_b_swap_custody, - initial_tokens_received_balance, - min_amount_out, - )?; - - msg!( - "Done. tokens_received: {}, token_a_balance: {}, token_b_balance: {}", - tokens_received, - account::get_token_balance(token_a_custody)?, - account::get_token_balance(token_b_custody)? - ); - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/vaults/src/strategies/orc_stake_lp_compound/crank3.rs b/farms/vaults/src/strategies/orc_stake_lp_compound/crank3.rs deleted file mode 100644 index a284a948df3..00000000000 --- a/farms/vaults/src/strategies/orc_stake_lp_compound/crank3.rs +++ /dev/null @@ -1,289 +0,0 @@ -//! Crank step 3 instruction handler - -use { - crate::{strategies::common, vault_info::VaultInfo}, - solana_farm_sdk::{ - id::zero, - program::{account, protocol::orca}, - vault::{Vault, VaultStrategy}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn crank3(vault: &Vault, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _funding_account, - _vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - reward_token_custody, - lp_token_custody, - token_a_custody, - token_b_custody, - pool_program_id, - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - amm_id, - amm_authority, - farm_program, - vault_stake_info, - vault_stake_custody, - farm_id, - farm_authority, - farm_lp_token_mint, - base_token_vault, - reward_token_vault - ] = accounts - { - if vault_authority.key != &vault.vault_authority { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - if let VaultStrategy::StakeLpCompoundRewards { - pool_id: pool_id_key, - farm_id: farm_id_key, - lp_token_custody: lp_token_custody_key, - token_a_custody: token_a_custody_key, - token_b_custody: token_b_custody_key, - token_a_reward_custody: token_a_reward_custody_key, - vault_stake_info: vault_stake_info_key, - vault_stake_custody: vault_stake_custody_key, - .. - } = vault.strategy - { - if &vault_stake_info_key != vault_stake_info.key { - msg!("Error: Invalid Vault Stake Info account"); - return Err(ProgramError::InvalidArgument); - } - if vault_stake_custody_key.is_none() - || &vault_stake_custody_key.unwrap() != vault_stake_custody.key - { - msg!("Error: Invalid Vault Stake Custody account"); - return Err(ProgramError::InvalidArgument); - } - if &token_a_reward_custody_key != reward_token_custody.key - || &lp_token_custody_key != lp_token_custody.key - { - msg!("Error: Invalid custody accounts"); - return Err(ProgramError::InvalidArgument); - } - if &token_a_custody_key != token_a_custody.key - || &token_b_custody_key.or_else(|| Some(zero::id())).unwrap() != token_b_custody.key - { - msg!("Error: Invalid custody accounts"); - return Err(ProgramError::InvalidArgument); - } - if amm_id.key != &pool_id_key { - msg!("Error: Invalid pool id"); - return Err(ProgramError::InvalidArgument); - } - if farm_id.key != &farm_id_key { - msg!("Error: Invalid farm id"); - return Err(ProgramError::InvalidArgument); - } - } else { - msg!("Error: Vault strategy mismatch"); - return Err(ProgramError::InvalidArgument); - } - - let mut vault_info = VaultInfo::new(vault_info_account); - common::check_min_crank_interval(&vault_info)?; - vault_info.update_crank_time()?; - vault_info.set_crank_step(3)?; - - // read balances - let token_a_balance = account::get_token_balance(token_a_custody)?; - let token_b_balance = account::get_token_balance(token_b_custody)?; - let lp_token_balance = account::get_token_balance(lp_token_custody)?; - msg!( - "Read balances. token_a_balance: {}, token_b_balance: {}", - token_a_balance, - token_b_balance - ); - if token_a_balance < 10 || token_b_balance < 10 { - msg!("Nothing to do: Not enough tokens to compound"); - return Ok(()); - } - - // compute and check pool ratios - let (pool_token_a_balance, pool_token_b_balance) = - orca::get_pool_token_balances(pool_token_a_account, pool_token_b_account)?; - let pool_ratio = if pool_token_a_balance != 0 { - pool_token_b_balance as f64 / pool_token_a_balance as f64 - } else { - 0.0 - }; - let custody_ratio = account::get_token_pair_ratio(token_a_custody, token_b_custody)?; - msg!( - "Compute pool ratios. custody_ratio: {}, pool_ratio: {}", - custody_ratio, - pool_ratio - ); - if custody_ratio == 0.0 || pool_ratio == 0.0 { - msg!("Pool ratio is zero"); - return Ok(()); - } - if (custody_ratio - pool_ratio).abs() * 100.0 / pool_ratio > 10.0 { - msg!("Unbalanced tokens, run Crank2 first"); - return Ok(()); - } - - // Deposit tokens into the pool - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - - // calculate deposit amounts - let (_, max_token_a_deposit_amount, max_token_b_deposit_amount) = - if custody_ratio >= pool_ratio { - orca::get_pool_deposit_amounts( - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - token_a_balance, - 0, - )? - } else { - orca::get_pool_deposit_amounts( - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - 0, - token_b_balance, - )? - }; - // one of the amounts can come out over the balance because ratios didn't reflect - // deposited volume, while get_pool_deposit_amounts does include it. - // in this case we just flip the side. - let (min_lp_token_amount, max_token_a_deposit_amount, max_token_b_deposit_amount) = - if max_token_b_deposit_amount > token_b_balance { - orca::get_pool_deposit_amounts( - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - 0, - token_b_balance, - )? - } else if max_token_a_deposit_amount > token_a_balance { - orca::get_pool_deposit_amounts( - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - token_a_balance, - 0, - )? - } else { - ( - orca::estimate_lp_tokens_amount( - lp_token_mint, - max_token_a_deposit_amount, - max_token_b_deposit_amount, - pool_token_a_balance, - pool_token_b_balance, - )?, - max_token_a_deposit_amount, - max_token_b_deposit_amount, - ) - }; - - msg!("Deposit tokens into the pool. min_lp_token_amount: {}, max_token_a_deposit_amount: {}, max_token_b_deposit_amount: {}", - min_lp_token_amount, - max_token_a_deposit_amount, - max_token_b_deposit_amount); - if max_token_a_deposit_amount == 0 - || max_token_b_deposit_amount == 0 - || min_lp_token_amount < 2 - { - msg!("Nothing to do: Tokens balance is not large enough"); - return Ok(()); - } - - orca::add_liquidity_with_seeds( - &[ - vault_authority.clone(), - token_a_custody.clone(), - token_b_custody.clone(), - lp_token_custody.clone(), - pool_program_id.clone(), - pool_token_a_account.clone(), - pool_token_b_account.clone(), - lp_token_mint.clone(), - spl_token_program.clone(), - amm_id.clone(), - amm_authority.clone(), - ], - seeds, - max_token_a_deposit_amount, - max_token_b_deposit_amount, - min_lp_token_amount, - )?; - - // Check tokens spent and return change back to user - let tokens_a_spent = account::check_tokens_spent( - token_a_custody, - token_a_balance, - max_token_a_deposit_amount, - )?; - let tokens_b_spent = account::check_tokens_spent( - token_b_custody, - token_b_balance, - max_token_b_deposit_amount, - )?; - - // Stake LP tokens - let lp_tokens_received = account::check_tokens_received( - lp_token_custody, - lp_token_balance, - min_lp_token_amount, - )?; - msg!( - "Stake LP tokens. tokens_a_spent: {}, tokens_b_spent: {}, lp_tokens_received: {}", - tokens_a_spent, - tokens_b_spent, - lp_tokens_received - ); - let reward_token_balance = account::get_token_balance(reward_token_custody)?; - - orca::stake_with_seeds( - &[ - vault_authority.clone(), - vault_stake_info.clone(), - lp_token_custody.clone(), - reward_token_custody.clone(), - vault_stake_custody.clone(), - farm_lp_token_mint.clone(), - farm_program.clone(), - base_token_vault.clone(), - reward_token_vault.clone(), - spl_token_program.clone(), - farm_id.clone(), - farm_authority.clone(), - ], - seeds, - lp_tokens_received, - )?; - if lp_token_balance != account::get_token_balance(lp_token_custody)? { - msg!("Error: Stake instruction didn't result in expected amount of LP tokens spent"); - return Err(ProgramError::Custom(165)); - } - - // update Vault stats - let token_rewards = - account::get_balance_increase(reward_token_custody, reward_token_balance)?; - msg!("Update Vault stats. token_rewards: {}", token_rewards,); - vault_info.add_rewards(token_rewards, 0)?; - vault_info.add_liquidity(tokens_a_spent, tokens_b_spent)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/vaults/src/strategies/orc_stake_lp_compound/features.rs b/farms/vaults/src/strategies/orc_stake_lp_compound/features.rs deleted file mode 100644 index d0fa54490f0..00000000000 --- a/farms/vaults/src/strategies/orc_stake_lp_compound/features.rs +++ /dev/null @@ -1,85 +0,0 @@ -//! Feature toggling instructions handlers - -use { - crate::{traits::Features, vault_info::VaultInfo}, - solana_farm_sdk::{instruction::vault::VaultInstruction, vault::Vault}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl Features for VaultInstruction { - fn set_min_crank_interval( - _vault: &Vault, - vault_info: &mut VaultInfo, - _accounts: &[AccountInfo], - min_crank_interval_sec: u64, - ) -> ProgramResult { - msg!("set_min_crank_interval: {}", min_crank_interval_sec); - vault_info.set_min_crank_interval(min_crank_interval_sec) - } - - fn set_fee( - _vault: &Vault, - vault_info: &mut VaultInfo, - _accounts: &[AccountInfo], - fee: f64, - ) -> ProgramResult { - msg!("set_fee: {}", fee); - if !(0.0..=1.0).contains(&fee) { - msg!("Error: Invalid new value for fee"); - return Err(ProgramError::InvalidArgument); - } - vault_info.set_fee(fee) - } - - fn set_external_fee( - _vault: &Vault, - vault_info: &mut VaultInfo, - _accounts: &[AccountInfo], - external_fee: f64, - ) -> ProgramResult { - msg!("external_fee: {}", external_fee); - if !(0.0..=1.0).contains(&external_fee) { - msg!("Error: Invalid new value for external_fee"); - return Err(ProgramError::InvalidArgument); - } - vault_info.set_external_fee(external_fee) - } - - fn enable_deposits( - _vault: &Vault, - vault_info: &mut VaultInfo, - _accounts: &[AccountInfo], - ) -> ProgramResult { - msg!("enable_deposits"); - vault_info.enable_deposits() - } - - fn disable_deposits( - _vault: &Vault, - vault_info: &mut VaultInfo, - _accounts: &[AccountInfo], - ) -> ProgramResult { - msg!("disable_deposits"); - vault_info.disable_deposits() - } - - fn enable_withdrawals( - _vault: &Vault, - vault_info: &mut VaultInfo, - _accounts: &[AccountInfo], - ) -> ProgramResult { - msg!("enable_withdrawals"); - vault_info.enable_withdrawals() - } - - fn disable_withdrawals( - _vault: &Vault, - vault_info: &mut VaultInfo, - _accounts: &[AccountInfo], - ) -> ProgramResult { - msg!("disable_withdrawals"); - vault_info.disable_withdrawals() - } -} diff --git a/farms/vaults/src/strategies/orc_stake_lp_compound/init.rs b/farms/vaults/src/strategies/orc_stake_lp_compound/init.rs deleted file mode 100644 index 3f023d892ad..00000000000 --- a/farms/vaults/src/strategies/orc_stake_lp_compound/init.rs +++ /dev/null @@ -1,198 +0,0 @@ -//! Vault Init instruction handler - -use { - crate::{traits::Init, vault_info::VaultInfo}, - solana_farm_sdk::{ - instruction::{orca::OrcaUserInit, vault::VaultInstruction}, - program::{account, pda, protocol::orca::OrcaUserStakeInfo}, - token::Token, - traits::Packed, - vault::Vault, - }, - solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction}, - msg, - program::invoke_signed, - program_error::ProgramError, - system_program, sysvar, - sysvar::Sysvar, - }, -}; - -impl Init for VaultInstruction { - fn init(vault: &Vault, accounts: &[AccountInfo], step: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - admin_account, - _vault_metadata, - vault_info_account, - _multisig_account, - vault_authority, - vault_program, - _system_program, - _spl_token_program, - rent_program, - farm_program, - vault_token_mint, - vault_token_ref, - vault_stake_info, - vault_stake_custody, - fees_account, - token_a_custody, - token_b_custody, - lp_token_custody, - token_a_mint, - token_b_mint, - lp_token_mint, - farm_lp_token_mint, - reward_token_custody, - reward_token_mint, - farm_id - ] = accounts - { - // validate accounts - if vault_authority.key != &vault.vault_authority - || vault_token_ref.key != &vault.vault_token_ref - || vault_program.key != &vault.vault_program_id - { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - - if step <= 1 { - // init vault info account - msg!("Init vault info"); - pda::init_system_account( - admin_account, - vault_info_account, - &vault.vault_program_id, - &vault.vault_program_id, - &[b"info_account", vault.name.as_bytes()], - VaultInfo::LEN, - )?; - let mut vault_info = VaultInfo::new(vault_info_account); - vault_info.init(&vault.name)?; - - // init vault token mint - msg!("Init vault token mint"); - let vault_token = Token::unpack(&vault_token_ref.try_borrow_data()?)?; - if vault_token_mint.key != &vault_token.mint { - msg!("Error: Invalid Vault token mint"); - return Err(ProgramError::InvalidArgument); - } - pda::init_mint( - admin_account, - vault_token_mint, - vault_authority, - rent_program, - &vault.vault_program_id, - &[b"vault_token_mint", vault.name.as_bytes()], - vault_token.decimals, - )?; - - // init stake info - if account::is_empty(vault_stake_info)? { - msg!("Init stake info"); - let min_balance = sysvar::rent::Rent::get().unwrap().minimum_balance(OrcaUserStakeInfo::LEN); - account::transfer_sol(admin_account, vault_authority, min_balance)?; - - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - let orca_accounts = vec![ - AccountMeta::new_readonly(*farm_id.key, false), - AccountMeta::new(*vault_stake_info.key, false), - AccountMeta::new(*vault_authority.key, true), - AccountMeta::new_readonly(system_program::id(), false), - ]; - - let instruction = Instruction { - program_id: *farm_program.key, - accounts: orca_accounts, - data: OrcaUserInit {}.to_vec()?, - }; - - invoke_signed(&instruction, accounts, seeds)?; - } - } - - if step == 0 || step == 2 { - // init token accounts - msg!("Init fees account"); - pda::init_token_account( - admin_account, - fees_account, - reward_token_mint, - vault_authority, - rent_program, - &vault.vault_program_id, - &[b"fees_account", vault.name.as_bytes()], - )?; - - msg!("Init lp token custody account"); - pda::init_token_account( - admin_account, - lp_token_custody, - lp_token_mint, - vault_authority, - rent_program, - &vault.vault_program_id, - &[b"lp_token_custody", vault.name.as_bytes()], - )?; - - msg!("Init token a custody account"); - pda::init_token_account( - admin_account, - token_a_custody, - token_a_mint, - vault_authority, - rent_program, - &vault.vault_program_id, - &[b"token_a_custody", vault.name.as_bytes()], - )?; - - msg!("Init token b custody account"); - pda::init_token_account( - admin_account, - token_b_custody, - token_b_mint, - vault_authority, - rent_program, - &vault.vault_program_id, - &[b"token_b_custody", vault.name.as_bytes()], - )?; - - msg!("Init reward token custody account"); - pda::init_token_account( - admin_account, - reward_token_custody, - reward_token_mint, - vault_authority, - rent_program, - &vault.vault_program_id, - &[b"reward_token_custody", vault.name.as_bytes()], - )?; - - msg!("Init vault stake custody"); - pda::init_token_account( - admin_account, - vault_stake_custody, - farm_lp_token_mint, - vault_authority, - rent_program, - &vault.vault_program_id, - &[b"vault_stake_custody", vault.name.as_bytes()], - )?; - } - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } - } -} diff --git a/farms/vaults/src/strategies/orc_stake_lp_compound/lock_liquidity.rs b/farms/vaults/src/strategies/orc_stake_lp_compound/lock_liquidity.rs deleted file mode 100644 index 7357a8a72dd..00000000000 --- a/farms/vaults/src/strategies/orc_stake_lp_compound/lock_liquidity.rs +++ /dev/null @@ -1,203 +0,0 @@ -//! Lock Liquidity in the Vault instruction handler - -use { - crate::{traits::LockLiquidity, user_info::UserInfo, vault_info::VaultInfo}, - solana_farm_sdk::{ - instruction::vault::VaultInstruction, - math, - program::{account, pda, protocol::orca}, - vault::{Vault, VaultStrategy}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl LockLiquidity for VaultInstruction { - fn lock_liquidity(vault: &Vault, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - _vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - vault_token_mint, - user_info_account, - user_vt_token_account, - reward_token_custody, - lp_token_custody, - farm_program, - vault_stake_info, - vault_stake_custody, - farm_id, - farm_authority, - farm_lp_token_mint, - base_token_vault, - reward_token_vault - ] = accounts - { - // validate accounts - if vault_authority.key != &vault.vault_authority { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - if !user_account.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - if !account::check_token_account_owner(user_vt_token_account, user_account.key)? { - msg!("Error: Invalid VT token account owner"); - return Err(ProgramError::IllegalOwner); - } - if let VaultStrategy::StakeLpCompoundRewards { - farm_id: farm_id_key, - lp_token_custody: lp_token_custody_key, - token_a_reward_custody: token_a_reward_custody_key, - vault_stake_info: vault_stake_info_key, - vault_stake_custody: vault_stake_custody_key, - .. - } = vault.strategy - { - if &vault_stake_info_key != vault_stake_info.key { - msg!("Error: Invalid Vault Stake Info account"); - return Err(ProgramError::InvalidArgument); - } - if vault_stake_custody_key.is_none() - || &vault_stake_custody_key.unwrap() != vault_stake_custody.key - { - msg!("Error: Invalid Vault Stake Custody account"); - return Err(ProgramError::InvalidArgument); - } - if &token_a_reward_custody_key != reward_token_custody.key - || &lp_token_custody_key != lp_token_custody.key - { - msg!("Error: Invalid custody accounts"); - return Err(ProgramError::InvalidArgument); - } - if farm_id.key != &farm_id_key { - msg!("Error: Invalid farm id"); - return Err(ProgramError::InvalidArgument); - } - } else { - msg!("Error: Vault strategy mismatch"); - return Err(ProgramError::InvalidArgument); - } - - if !UserInfo::validate_account(vault, user_info_account, user_account.key) { - msg!("Error: Invalid user info account"); - return Err(ProgramError::Custom(140)); - } - - let mut vault_info = VaultInfo::new(vault_info_account); - if !vault_info.is_deposit_allowed()? { - msg!("Error: Deposits are not allowed for this Vault"); - return Err(ProgramError::Custom(220)); - } - - // check lp balance - let mut user_info = UserInfo::new(user_info_account); - let lp_tokens_debt = user_info.get_lp_tokens_debt()?; - msg!("Read balances. lp_tokens_debt: {}", lp_tokens_debt); - - let lp_stake_amount = if amount > 0 { - if lp_tokens_debt < amount { - msg!("Error: Insufficient funds"); - return Err(ProgramError::InsufficientFunds); - } - amount - } else { - lp_tokens_debt - }; - if lp_stake_amount == 0 { - msg!("Error: Zero balance. Forgot to deposit funds?"); - return Err(ProgramError::InsufficientFunds); - } - - let initial_lp_custody_balance = account::get_token_balance(lp_token_custody)?; - - // Stake LP tokens - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - - let initial_reward_token_balance = account::get_token_balance(reward_token_custody)?; - - msg!("Stake LP tokens"); - let stake_balance = account::get_token_balance(vault_stake_custody)?; - - orca::stake_with_seeds( - &[ - vault_authority.clone(), - vault_stake_info.clone(), - lp_token_custody.clone(), - reward_token_custody.clone(), - vault_stake_custody.clone(), - farm_lp_token_mint.clone(), - farm_program.clone(), - base_token_vault.clone(), - reward_token_vault.clone(), - spl_token_program.clone(), - farm_id.clone(), - farm_authority.clone(), - ], - seeds, - lp_stake_amount, - )?; - let _ = account::check_tokens_spent( - lp_token_custody, - initial_lp_custody_balance, - lp_stake_amount, - )?; - - // update user stats - msg!("Update user stats"); - user_info.remove_lp_tokens_debt(lp_stake_amount)?; - - // update Vault stats - let token_rewards = account::get_balance_increase( - reward_token_custody, - initial_reward_token_balance, - )?; - msg!("Update Vault stats. token_rewards: {}", token_rewards,); - vault_info.add_rewards(token_rewards, 0)?; - - // compute Vault tokens to mint - let user_stake_amount = - account::get_balance_increase(vault_stake_custody, stake_balance)?; - let vt_supply_amount = account::get_token_supply(vault_token_mint)?; - let vt_to_mint = if vt_supply_amount == 0 || stake_balance == 0 { - user_stake_amount - } else { - math::checked_as_u64(math::checked_div( - math::checked_mul(user_stake_amount as u128, vt_supply_amount as u128)?, - stake_balance as u128, - )?)? - }; - - // mint vault tokens to user - msg!( - "Mint Vault tokens to the user. vt_to_mint: {}, vt_supply_amount: {}, stake_balance: {}", - vt_to_mint, vt_supply_amount, - stake_balance - ); - if vt_to_mint == 0 { - msg!("Error: Add liquidity instruction didn't result in Vault tokens mint"); - return Err(ProgramError::Custom(170)); - } - pda::mint_to_with_seeds( - user_vt_token_account, - vault_token_mint, - vault_authority, - seeds, - vt_to_mint, - )?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } - } -} diff --git a/farms/vaults/src/strategies/orc_stake_lp_compound/mod.rs b/farms/vaults/src/strategies/orc_stake_lp_compound/mod.rs deleted file mode 100644 index b649f8f5c13..00000000000 --- a/farms/vaults/src/strategies/orc_stake_lp_compound/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -pub mod add_liquidity; -pub mod crank; -mod crank1; -mod crank2; -mod crank3; -pub mod features; -pub mod init; -pub mod lock_liquidity; -pub mod params; -pub mod remove_liquidity; -pub mod remove_multisig; -pub mod set_admin_signers; -pub mod shutdown; -pub mod unlock_liquidity; -pub mod user_init; -pub mod withdraw_fees; diff --git a/farms/vaults/src/strategies/orc_stake_lp_compound/params.rs b/farms/vaults/src/strategies/orc_stake_lp_compound/params.rs deleted file mode 100644 index cfa9b51ea58..00000000000 --- a/farms/vaults/src/strategies/orc_stake_lp_compound/params.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! Vault related parameters and accounts - -use crate::{traits::VaultParams, vault_info::VaultInfo}; - -impl VaultParams for VaultInfo<'_, '_> { - fn default_min_crank_interval() -> u64 { - 60 - } - - fn default_fee() -> f64 { - 0.003 - } - - fn default_external_fee() -> f64 { - 0.003 - } -} diff --git a/farms/vaults/src/strategies/orc_stake_lp_compound/remove_liquidity.rs b/farms/vaults/src/strategies/orc_stake_lp_compound/remove_liquidity.rs deleted file mode 100644 index f23d833de2a..00000000000 --- a/farms/vaults/src/strategies/orc_stake_lp_compound/remove_liquidity.rs +++ /dev/null @@ -1,179 +0,0 @@ -//! Remove Liquidity from the Vault instruction handler - -use { - crate::{traits::RemoveLiquidity, user_info::UserInfo, vault_info::VaultInfo}, - solana_farm_sdk::{ - instruction::vault::VaultInstruction, - program::{account, protocol::orca}, - vault::{Vault, VaultStrategy}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl RemoveLiquidity for VaultInstruction { - fn remove_liquidity(vault: &Vault, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - _vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - user_info_account, - user_token_a_account, - user_token_b_account, - lp_token_custody, - pool_program_id, - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - amm_id, - amm_authority, - pool_fees_account - ] = accounts - { - // validate accounts - if vault_authority.key != &vault.vault_authority { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - if !user_account.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - if !account::check_token_account_owner(user_token_a_account, user_account.key)? - || !account::check_token_account_owner(user_token_b_account, user_account.key)? - { - msg!("Error: Invalid token account owner"); - return Err(ProgramError::IllegalOwner); - } - if let VaultStrategy::StakeLpCompoundRewards { - pool_id: pool_id_key, - lp_token_custody: lp_token_custody_key, - .. - } = vault.strategy - { - if &lp_token_custody_key != lp_token_custody.key { - msg!("Error: Invalid LP custody account"); - return Err(ProgramError::InvalidArgument); - } - if &pool_id_key != amm_id.key { - msg!("Error: Invalid pool id"); - return Err(ProgramError::InvalidArgument); - } - } else { - msg!("Error: Vault strategy mismatch"); - return Err(ProgramError::InvalidArgument); - } - if !UserInfo::validate_account(vault, user_info_account, user_account.key) { - msg!("Error: Invalid user info account"); - return Err(ProgramError::Custom(140)); - } - - let mut vault_info = VaultInfo::new(vault_info_account); - if !vault_info.is_withdrawal_allowed()? { - msg!("Error: Withdrawals are not allowed for this Vault"); - return Err(ProgramError::Custom(230)); - } - - // check lp balance - let mut user_info = UserInfo::new(user_info_account); - let lp_tokens_debt = user_info.get_lp_tokens_debt()?; - msg!("Read balances. lp_tokens_debt: {}", lp_tokens_debt); - - let lp_remove_amount = if amount > 0 { - if lp_tokens_debt < amount { - msg!("Error: Insufficient funds"); - return Err(ProgramError::InsufficientFunds); - } - amount - } else { - lp_tokens_debt - }; - if lp_remove_amount == 0 { - msg!("Error: Zero balance. Forgot to unlock funds?"); - return Err(ProgramError::InsufficientFunds); - } - - // remove liquidity from the pool - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - - let initial_token_a_account_balance = account::get_token_balance(user_token_a_account)?; - let initial_token_b_account_balance = account::get_token_balance(user_token_b_account)?; - let initial_lp_tokens_balance = account::get_token_balance(lp_token_custody)?; - let (min_token_a_amount, min_token_b_amount) = orca::get_pool_withdrawal_amounts( - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - lp_remove_amount, - )?; - - msg!( - "Remove liquidity from the pool. lp_remove_amount: {}, min_token_a_amount: {}, min_token_b_amount: {}", - lp_remove_amount, min_token_a_amount, min_token_b_amount - ); - orca::remove_liquidity_with_seeds( - &[ - vault_authority.clone(), - user_token_a_account.clone(), - user_token_b_account.clone(), - lp_token_custody.clone(), - pool_program_id.clone(), - pool_token_a_account.clone(), - pool_token_b_account.clone(), - lp_token_mint.clone(), - spl_token_program.clone(), - amm_id.clone(), - amm_authority.clone(), - pool_fees_account.clone(), - ], - seeds, - lp_remove_amount, - min_token_a_amount, - min_token_b_amount, - )?; - - // check tokens received - let tokens_a_received = account::get_balance_increase( - user_token_a_account, - initial_token_a_account_balance, - )?; - let tokens_b_received = account::get_balance_increase( - user_token_b_account, - initial_token_b_account_balance, - )?; - if tokens_a_received == 0 && tokens_b_received == 0 { - msg!("Error: Remove liquidity instruction didn't result in any of the tokens received"); - return Err(ProgramError::Custom(190)); - } - let _ = account::check_tokens_spent( - lp_token_custody, - initial_lp_tokens_balance, - lp_remove_amount, - )?; - - // update user stats - msg!( - "Update user stats. tokens_a_received: {}, tokens_b_received: {}", - tokens_a_received, - tokens_b_received - ); - user_info.remove_liquidity(tokens_a_received, tokens_b_received)?; - user_info.remove_lp_tokens_debt(lp_remove_amount)?; - - // update vault stats - msg!("Update Vault stats"); - vault_info.remove_liquidity(tokens_a_received, tokens_b_received)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } - } -} diff --git a/farms/vaults/src/strategies/orc_stake_lp_compound/remove_multisig.rs b/farms/vaults/src/strategies/orc_stake_lp_compound/remove_multisig.rs deleted file mode 100644 index 8bd3ca63446..00000000000 --- a/farms/vaults/src/strategies/orc_stake_lp_compound/remove_multisig.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! Vault RemoveMultisig instruction handler - -use { - crate::traits::RemoveMultisig, - solana_farm_sdk::{instruction::vault::VaultInstruction, program::account, vault::Vault}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl RemoveMultisig for VaultInstruction { - fn remove_multisig(vault: &Vault, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - admin_account, - _vault_metadata, - _vault_info_account, - _active_multisig_account, - vault_multisig_account - ] = accounts - { - msg!("Close multisig account"); - account::close_system_account(admin_account, vault_multisig_account, &vault.vault_program_id)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } - } -} diff --git a/farms/vaults/src/strategies/orc_stake_lp_compound/set_admin_signers.rs b/farms/vaults/src/strategies/orc_stake_lp_compound/set_admin_signers.rs deleted file mode 100644 index dbbae0dab56..00000000000 --- a/farms/vaults/src/strategies/orc_stake_lp_compound/set_admin_signers.rs +++ /dev/null @@ -1,60 +0,0 @@ -//! Vault SetAdminSigners instruction handler - -use { - crate::traits::SetAdminSigners, - solana_farm_sdk::{ - error::FarmError, - instruction::vault::VaultInstruction, - program::{account, multisig, multisig::Multisig, pda}, - vault::Vault, - }, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - }, -}; - -impl SetAdminSigners for VaultInstruction { - fn set_admin_signers( - vault: &Vault, - accounts: &[AccountInfo], - min_signatures: u8, - ) -> ProgramResult { - let accounts_iter = &mut accounts.iter(); - - let signer_account = next_account_info(accounts_iter)?; - let _vault_metadata = next_account_info(accounts_iter)?; - let _vault_info_account = next_account_info(accounts_iter)?; - let _active_multisig_account = next_account_info(accounts_iter)?; - let vault_multisig_account = next_account_info(accounts_iter)?; - let _system_program = next_account_info(accounts_iter)?; - - if vault_multisig_account.key != &vault.multisig_account { - msg!("Error: Invalid vault multisig account"); - return Err(FarmError::IncorrectAccountAddress.into()); - } - - if account::is_empty(vault_multisig_account)? { - msg!("Init multisig account"); - let seeds: &[&[u8]] = &[b"multisig", vault.name.as_bytes()]; - let _bump = pda::init_system_account( - signer_account, - vault_multisig_account, - &vault.vault_program_id, - &vault.vault_program_id, - seeds, - Multisig::LEN, - )?; - } else { - msg!("Update multisig account"); - } - multisig::set_signers( - vault_multisig_account, - accounts_iter.as_slice(), - min_signatures, - )?; - - Ok(()) - } -} diff --git a/farms/vaults/src/strategies/orc_stake_lp_compound/shutdown.rs b/farms/vaults/src/strategies/orc_stake_lp_compound/shutdown.rs deleted file mode 100644 index f5498bd8b39..00000000000 --- a/farms/vaults/src/strategies/orc_stake_lp_compound/shutdown.rs +++ /dev/null @@ -1,22 +0,0 @@ -//! Vault Shutdown instruction handler - -use { - crate::{traits::Shutdown, vault_info::VaultInfo}, - solana_farm_sdk::{instruction::vault::VaultInstruction, vault::Vault}, - solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, msg}, -}; - -impl Shutdown for VaultInstruction { - fn shutdown(_vault: &Vault, accounts: &[AccountInfo]) -> ProgramResult { - if let [_admin_account, _vault_metadata, vault_info_account, _multisig_account] = accounts { - // Don't do anything special on shutdown for this Vault, just disable deposits and withdrawals - let mut vault_info = VaultInfo::new(vault_info_account); - msg!("disable_deposit"); - vault_info.disable_deposits()?; - msg!("disable_withdrawal"); - vault_info.disable_withdrawals()?; - //pda::close_account(admin_account, vault_info_account) - } - Ok(()) - } -} diff --git a/farms/vaults/src/strategies/orc_stake_lp_compound/unlock_liquidity.rs b/farms/vaults/src/strategies/orc_stake_lp_compound/unlock_liquidity.rs deleted file mode 100644 index 65d6620063c..00000000000 --- a/farms/vaults/src/strategies/orc_stake_lp_compound/unlock_liquidity.rs +++ /dev/null @@ -1,202 +0,0 @@ -//! Unlock Liquidity in the Vault instruction handler - -use { - crate::{traits::UnlockLiquidity, user_info::UserInfo, vault_info::VaultInfo}, - solana_farm_sdk::{ - instruction::vault::VaultInstruction, - math, - program::{account, protocol::orca}, - vault::{Vault, VaultStrategy}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - pubkey::Pubkey, - }, -}; - -impl UnlockLiquidity for VaultInstruction { - fn unlock_liquidity(vault: &Vault, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - _vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - vault_token_mint, - user_info_account, - user_vt_token_account, - reward_token_custody, - lp_token_custody, - farm_program, - vault_stake_info, - vault_stake_custody, - farm_id, - farm_authority, - farm_lp_token_mint, - base_token_vault, - reward_token_vault - ] = accounts - { - // validate accounts - if vault_authority.key != &vault.vault_authority { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - if !user_account.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - if !account::check_token_account_owner(user_vt_token_account, user_account.key)? { - msg!("Error: Invalid VT token account owner"); - return Err(ProgramError::IllegalOwner); - } - if let VaultStrategy::StakeLpCompoundRewards { - farm_id: farm_id_key, - lp_token_custody: lp_token_custody_key, - token_a_reward_custody: token_a_reward_custody_key, - vault_stake_info: vault_stake_info_key, - vault_stake_custody: vault_stake_custody_key, - .. - } = vault.strategy - { - if &vault_stake_info_key != vault_stake_info.key { - msg!("Error: Invalid Vault Stake Info account"); - return Err(ProgramError::InvalidArgument); - } - if vault_stake_custody_key.is_none() - || &vault_stake_custody_key.unwrap() != vault_stake_custody.key - { - msg!("Error: Invalid Vault Stake Custody account"); - return Err(ProgramError::InvalidArgument); - } - if &token_a_reward_custody_key != reward_token_custody.key - || &lp_token_custody_key != lp_token_custody.key - { - msg!("Error: Invalid custody accounts"); - return Err(ProgramError::InvalidArgument); - } - if farm_id.key != &farm_id_key { - msg!("Error: Invalid farm id"); - return Err(ProgramError::InvalidArgument); - } - } else { - msg!("Error: Vault strategy mismatch"); - return Err(ProgramError::InvalidArgument); - } - - if !UserInfo::validate_account(vault, user_info_account, user_account.key) { - msg!("Error: Invalid user info account"); - return Err(ProgramError::Custom(140)); - } - - let mut vault_info = VaultInfo::new(vault_info_account); - if !vault_info.is_withdrawal_allowed()? { - msg!("Error: Withdrawals are not allowed for this Vault"); - return Err(ProgramError::Custom(230)); - } - - // calculate amounts to unstake - let vt_remove_amount = if amount > 0 { - amount - } else { - account::get_token_balance(user_vt_token_account)? - }; - let vt_supply_amount = account::get_token_supply(vault_token_mint)?; - let stake_balance = account::get_token_balance(vault_stake_custody)?; - - msg!( - "Read balances. vt_remove_amount: {}, vt_supply_amount: {}, stake_balance: {}", - vt_remove_amount, - vt_supply_amount, - stake_balance - ); - if vt_remove_amount == 0 || vt_supply_amount == 0 || stake_balance == 0 { - msg!("Error: Zero balance"); - return Err(ProgramError::InsufficientFunds); - } - let lp_remove_amount = math::checked_as_u64(math::checked_div( - math::checked_mul(stake_balance as u128, vt_remove_amount as u128)?, - vt_supply_amount as u128, - )?)?; - - // unstake - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - - let initial_reward_token_balance = account::get_token_balance(reward_token_custody)?; - let initial_lp_tokens_balance = account::get_token_balance(lp_token_custody)?; - - msg!( - "Unstake user's lp tokens. amount: {}, lp_remove_amount: {}", - amount, - lp_remove_amount - ); - orca::unstake_with_seeds( - &[ - vault_authority.clone(), - vault_stake_info.clone(), - lp_token_custody.clone(), - reward_token_custody.clone(), - vault_stake_custody.clone(), - farm_lp_token_mint.clone(), - farm_program.clone(), - base_token_vault.clone(), - reward_token_vault.clone(), - spl_token_program.clone(), - farm_id.clone(), - farm_authority.clone(), - ], - seeds, - lp_remove_amount, - )?; - let _ = account::check_tokens_received( - lp_token_custody, - initial_lp_tokens_balance, - lp_remove_amount, - )?; - - // update user stats - msg!("Update user stats"); - let mut user_info = UserInfo::new(user_info_account); - user_info.add_lp_tokens_debt(lp_remove_amount)?; - - // update Vault stats - let token_rewards = - account::get_balance_increase(reward_token_custody, initial_reward_token_balance)?; - msg!("Update Vault stats. token_rewards: {}", token_rewards,); - vault_info.add_rewards(token_rewards, 0)?; - - // burn vault tokens - msg!( - "Burn Vault tokens from the user. vt_remove_amount: {}", - vt_remove_amount - ); - let key = Pubkey::create_program_address( - &[ - b"vault_token_mint", - vault.name.as_bytes(), - &[vault.vault_token_bump], - ], - &vault.vault_program_id, - )?; - if vault_token_mint.key != &key { - msg!("Error: Invalid Vault token mint"); - return Err(ProgramError::InvalidSeeds); - } - account::burn_tokens( - user_vt_token_account, - vault_token_mint, - user_account, - vt_remove_amount, - )?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } - } -} diff --git a/farms/vaults/src/strategies/orc_stake_lp_compound/user_init.rs b/farms/vaults/src/strategies/orc_stake_lp_compound/user_init.rs deleted file mode 100644 index ad81b179dff..00000000000 --- a/farms/vaults/src/strategies/orc_stake_lp_compound/user_init.rs +++ /dev/null @@ -1,55 +0,0 @@ -//! Vault User Init instruction handler - -use { - crate::{traits::UserInit, user_info::UserInfo}, - solana_farm_sdk::{ - instruction::vault::VaultInstruction, - program::{account, pda}, - vault::Vault, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl UserInit for VaultInstruction { - fn user_init(vault: &Vault, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - funding_account, - _vault_metadata, - _vault_info_account, - user_account, - user_info_account, - _system_program - ] = accounts - { - if account::is_empty(user_info_account)? { - msg!("Create user info account"); - let seeds: &[&[u8]] = &[ - b"user_info_account", - user_account.key.as_ref(), - vault.name.as_bytes(), - ]; - let bump = pda::init_system_account( - funding_account, - user_info_account, - &vault.vault_program_id, - &vault.vault_program_id, - seeds, - UserInfo::LEN, - )?; - let mut user_info = UserInfo::new(user_info_account); - user_info.init(&vault.name, bump)?; - } else if !UserInfo::validate_account(vault, user_info_account, user_account.key) { - msg!("Error: User info account already initialized but not valid"); - return Err(ProgramError::AccountAlreadyInitialized); - } - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } - } -} diff --git a/farms/vaults/src/strategies/orc_stake_lp_compound/withdraw_fees.rs b/farms/vaults/src/strategies/orc_stake_lp_compound/withdraw_fees.rs deleted file mode 100644 index 59b8c60b83a..00000000000 --- a/farms/vaults/src/strategies/orc_stake_lp_compound/withdraw_fees.rs +++ /dev/null @@ -1,64 +0,0 @@ -//! Vault WithdrawFees instruction handler - -use { - crate::traits::WithdrawFees, - solana_farm_sdk::{ - instruction::vault::VaultInstruction, program::account, program::pda, vault::Vault, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl WithdrawFees for VaultInstruction { - fn withdraw_fees(vault: &Vault, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - _vault_metadata, - _vault_info_account, - _multisig_account, - vault_authority, - _spl_token_program, - fees_account, - destination_account - ] = accounts - { - // validate accounts - if vault_authority.key != &vault.vault_authority { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - if Some(*fees_account.key) != vault.fees_account_a - && Some(*fees_account.key) != vault.fees_account_b - { - msg!("Error: Invalid fee accounts"); - return Err(ProgramError::InvalidArgument); - } - - let withdraw_amount = if amount > 0 { - amount - } else { - account::get_token_balance(fees_account)? - }; - - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - pda::transfer_tokens_with_seeds( - fees_account, - destination_account, - vault_authority, - seeds, - withdraw_amount, - )?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } - } -} diff --git a/farms/vaults/src/strategies/rdm_stake_lp_compound/add_liquidity.rs b/farms/vaults/src/strategies/rdm_stake_lp_compound/add_liquidity.rs deleted file mode 100644 index 7d0084a2728..00000000000 --- a/farms/vaults/src/strategies/rdm_stake_lp_compound/add_liquidity.rs +++ /dev/null @@ -1,173 +0,0 @@ -//! Add Liquidity to the Vault instruction handler - -use { - crate::{traits::AddLiquidity, user_info::UserInfo, vault_info::VaultInfo}, - solana_farm_sdk::{ - instruction::vault::VaultInstruction, - program::{account, protocol::raydium}, - vault::{Vault, VaultStrategy}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl AddLiquidity for VaultInstruction { - fn add_liquidity( - vault: &Vault, - accounts: &[AccountInfo], - max_token_a_amount: u64, - max_token_b_amount: u64, - ) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - _vault_metadata, - vault_info_account, - spl_token_program, - user_info_account, - user_token_a_account, - user_token_b_account, - user_lp_token_account, - lp_token_custody, - pool_program_id, - pool_coin_token_account, - pool_pc_token_account, - lp_token_mint, - amm_id, - amm_authority, - amm_open_orders, - amm_target, - serum_market, - ] = accounts - { - // validate accounts - if !user_account.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - if !account::check_token_account_owner(user_lp_token_account, user_account.key)? { - msg!("Error: Invalid token account owner"); - return Err(ProgramError::IllegalOwner); - } - if let VaultStrategy::StakeLpCompoundRewards { - pool_id: pool_id_key, - lp_token_custody: lp_token_custody_key, - .. - } = vault.strategy - { - if &pool_id_key != amm_id.key { - msg!("Error: Invalid pool id"); - return Err(ProgramError::InvalidArgument); - } - if &lp_token_custody_key != lp_token_custody.key { - msg!("Error: Invalid custody accounts"); - return Err(ProgramError::InvalidArgument); - } - } else { - msg!("Error: Vault strategy mismatch"); - return Err(ProgramError::InvalidArgument); - } - - if !UserInfo::validate_account(vault, user_info_account, user_account.key) { - msg!("Error: Invalid user info account"); - return Err(ProgramError::Custom(140)); - } - - let mut vault_info = VaultInfo::new(vault_info_account); - if !vault_info.is_deposit_allowed()? { - msg!("Error: Deposits are not allowed for this Vault"); - return Err(ProgramError::Custom(220)); - } - - // read user balances - let initial_token_a_user_balance = account::get_token_balance(user_token_a_account)?; - let initial_token_b_user_balance = account::get_token_balance(user_token_b_account)?; - let initial_lp_user_balance = account::get_token_balance(user_lp_token_account)?; - - // calculate deposit amounts - let (min_lp_token_amount, max_token_a_deposit_amount, max_token_b_deposit_amount) = - raydium::get_pool_deposit_amounts( - pool_coin_token_account, - pool_pc_token_account, - lp_token_mint, - amm_open_orders, - amm_id, - max_token_a_amount, - max_token_b_amount, - )?; - - // Deposit tokens into the pool - msg!("Deposit tokens into the pool. max_token_a_deposit_amount: {}, max_token_b_deposit_amount: {}", max_token_a_deposit_amount, max_token_b_deposit_amount); - if max_token_a_deposit_amount == 0 || max_token_b_deposit_amount == 0 { - msg!("Error: Zero deposit amount"); - return Err(ProgramError::InsufficientFunds); - } - raydium::add_liquidity( - &[ - user_account.clone(), - user_token_a_account.clone(), - user_token_b_account.clone(), - user_lp_token_account.clone(), - pool_program_id.clone(), - pool_coin_token_account.clone(), - pool_pc_token_account.clone(), - lp_token_mint.clone(), - spl_token_program.clone(), - amm_id.clone(), - amm_authority.clone(), - amm_open_orders.clone(), - amm_target.clone(), - serum_market.clone(), - ], - max_token_a_deposit_amount, - max_token_b_deposit_amount, - )?; - - // check amounts spent and received - let tokens_a_spent = account::check_tokens_spent( - user_token_a_account, - initial_token_a_user_balance, - max_token_a_deposit_amount, - )?; - let tokens_b_spent = account::check_tokens_spent( - user_token_b_account, - initial_token_b_user_balance, - max_token_b_deposit_amount, - )?; - let lp_tokens_received = account::check_tokens_received( - user_lp_token_account, - initial_lp_user_balance, - min_lp_token_amount, - )?; - - // transfer LP tokens to the custody - msg!( - "Transfer LP tokens from user. tokens_a_spent: {}, tokens_b_spent: {}, lp_tokens_received: {}", - tokens_a_spent, - tokens_b_spent, - lp_tokens_received - ); - account::transfer_tokens( - user_lp_token_account, - lp_token_custody, - user_account, - lp_tokens_received, - )?; - - // update user stats - msg!("Update user stats"); - let mut user_info = UserInfo::new(user_info_account); - user_info.add_liquidity(tokens_a_spent, tokens_b_spent)?; - user_info.add_lp_tokens_debt(lp_tokens_received)?; - - // update Vault stats - msg!("Update Vault stats"); - vault_info.add_liquidity(tokens_a_spent, tokens_b_spent)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } - } -} diff --git a/farms/vaults/src/strategies/rdm_stake_lp_compound/crank.rs b/farms/vaults/src/strategies/rdm_stake_lp_compound/crank.rs deleted file mode 100644 index 18de582a00d..00000000000 --- a/farms/vaults/src/strategies/rdm_stake_lp_compound/crank.rs +++ /dev/null @@ -1,26 +0,0 @@ -//! Vault Crank instruction handler - -use { - crate::{ - strategies::rdm_stake_lp_compound::{crank1::crank1, crank2::crank2, crank3::crank3}, - traits::Crank, - }, - solana_farm_sdk::{instruction::vault::VaultInstruction, vault::Vault}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl Crank for VaultInstruction { - fn crank(vault: &Vault, accounts: &[AccountInfo], step: u64) -> ProgramResult { - match step { - 1 => crank1(vault, accounts), - 2 => crank2(vault, accounts), - 3 => crank3(vault, accounts), - _ => { - msg!("Error: Invalid Crank step"); - Err(ProgramError::InvalidArgument) - } - } - } -} diff --git a/farms/vaults/src/strategies/rdm_stake_lp_compound/crank1.rs b/farms/vaults/src/strategies/rdm_stake_lp_compound/crank1.rs deleted file mode 100644 index af8aecfc063..00000000000 --- a/farms/vaults/src/strategies/rdm_stake_lp_compound/crank1.rs +++ /dev/null @@ -1,168 +0,0 @@ -//! Crank step 1 instruction handler - -use { - crate::{strategies::common, vault_info::VaultInfo}, - solana_farm_sdk::{ - id::zero, - math, - program::{account, pda, protocol::raydium}, - vault::Vault, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn crank1(vault: &Vault, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _funding_account, - _vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - token_a_reward_custody, - token_b_reward_custody, - lp_token_custody, - fees_account_a, - fees_account_b, - farm_program, - vault_stake_info, - farm_id, - farm_authority, - farm_lp_token_account, - farm_first_reward_token_account, - farm_second_reward_token_account, - clock_program - ] = accounts - { - // validate accounts - if vault_authority.key != &vault.vault_authority { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - common::check_custody_accounts( - vault, - lp_token_custody, - vault_authority, - vault_authority, - token_a_reward_custody, - token_b_reward_custody, - vault_stake_info, - None, - Some(farm_id.key), - false, - )?; - - let dual_rewards = *farm_second_reward_token_account.key != zero::id(); - - if Some(*fees_account_a.key) != vault.fees_account_a - || (dual_rewards && Some(*fees_account_b.key) != vault.fees_account_b) - { - msg!("Error: Invalid fee accounts"); - return Err(ProgramError::InvalidArgument); - } - - let mut vault_info = VaultInfo::new(vault_info_account); - common::check_min_crank_interval(&vault_info)?; - - // harvest - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - - let initial_token_a_reward_balance = account::get_token_balance(token_a_reward_custody)?; - let initial_token_b_reward_balance = if dual_rewards { - account::get_token_balance(token_b_reward_custody)? - } else { - 0 - }; - let initial_lp_tokens_balance = account::get_token_balance(lp_token_custody)?; - - msg!("Harvest rewards"); - raydium::stake_with_seeds( - &[ - vault_authority.clone(), - vault_stake_info.clone(), - lp_token_custody.clone(), - token_a_reward_custody.clone(), - token_b_reward_custody.clone(), - farm_program.clone(), - farm_lp_token_account.clone(), - farm_first_reward_token_account.clone(), - farm_second_reward_token_account.clone(), - clock_program.clone(), - spl_token_program.clone(), - farm_id.clone(), - farm_authority.clone(), - ], - seeds, - 0, - )?; - let _ = account::check_tokens_spent(lp_token_custody, initial_lp_tokens_balance, 0)?; - - // calculate rewards - let token_a_rewards = - account::get_balance_increase(token_a_reward_custody, initial_token_a_reward_balance)?; - let token_b_rewards = if dual_rewards { - account::get_balance_increase(token_b_reward_custody, initial_token_b_reward_balance)? - } else { - 0 - }; - msg!( - "Rewards received. token_a_rewards: {}, token_b_rewards: {}", - token_a_rewards, - token_b_rewards - ); - // take fees - let fee = vault_info.get_fee()?; - if !(0.0..=1.0).contains(&fee) { - msg!("Error: Invalid fee. fee: {}", fee); - return Err(ProgramError::Custom(260)); - } - let mut fees_a = math::checked_as_u64(token_a_rewards as f64 * fee)?; - if fees_a == 0 && token_a_rewards > 0 { - fees_a = 1; - } - let mut fees_b = math::checked_as_u64(token_b_rewards as f64 * fee)?; - if fees_b == 0 && token_b_rewards > 0 { - fees_b = 1; - } - - msg!( - "Apply fees. fee: {}, fees_a: {}, fees_b: {}", - fee, - fees_a, - fees_b - ); - pda::transfer_tokens_with_seeds( - token_a_reward_custody, - fees_account_a, - vault_authority, - seeds, - fees_a, - )?; - if dual_rewards { - pda::transfer_tokens_with_seeds( - token_b_reward_custody, - fees_account_b, - vault_authority, - seeds, - fees_b, - )?; - } - - // update Vault stats - msg!("Update Vault stats",); - vault_info.add_rewards(token_a_rewards, token_b_rewards)?; - vault_info.update_crank_time()?; - vault_info.set_crank_step(1)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/vaults/src/strategies/rdm_stake_lp_compound/crank2.rs b/farms/vaults/src/strategies/rdm_stake_lp_compound/crank2.rs deleted file mode 100644 index 88fc85cea52..00000000000 --- a/farms/vaults/src/strategies/rdm_stake_lp_compound/crank2.rs +++ /dev/null @@ -1,300 +0,0 @@ -//! Crank step 2 instruction handler - -use { - crate::{strategies::common, vault_info::VaultInfo}, - solana_farm_sdk::{ - id::zero, - program, - program::{account, pda, protocol::raydium}, - vault::{Vault, VaultStrategy}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn crank2(vault: &Vault, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _funding_account, - _vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - token_a_reward_custody, - token_b_reward_custody, - token_a_custody, - token_b_custody, - pool_program_id, - pool_coin_token_account, - pool_pc_token_account, - amm_id, - amm_authority, - amm_open_orders, - amm_target, - serum_market, - serum_program_id, - serum_coin_vault_account, - serum_pc_vault_account, - serum_vault_signer, - serum_bids, - serum_asks, - serum_event_queue, - sysvar_account - ] = accounts - { - // validate accounts - if vault_authority.key != &vault.vault_authority { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - if let VaultStrategy::StakeLpCompoundRewards { - pool_id: pool_id_key, - token_a_custody: token_a_custody_key, - token_b_custody: token_b_custody_key, - token_a_reward_custody: token_a_reward_custody_key, - token_b_reward_custody: token_b_reward_custody_key, - .. - } = vault.strategy - { - if &token_a_reward_custody_key != token_a_reward_custody.key - || &token_b_reward_custody_key.or_else(||Some(zero::id())).unwrap() - != token_b_reward_custody.key - || &token_a_custody_key != token_a_custody.key - || &token_b_custody_key.or_else(||Some(zero::id())).unwrap() != token_b_custody.key - { - msg!("Error: Invalid custody accounts"); - return Err(ProgramError::InvalidArgument); - } - if &pool_id_key != amm_id.key { - msg!("Error: Invalid pool id"); - return Err(ProgramError::InvalidArgument); - } - } else { - msg!("Error: Vault strategy mismatch"); - return Err(ProgramError::InvalidArgument); - } - - if !program::is_last_instruction(sysvar_account)? { - msg!("Error: Crank2 must be the last instruction in the transaction"); - return Err(ProgramError::InvalidArgument); - } - - let mut vault_info = VaultInfo::new(vault_info_account); - common::check_min_crank_interval(&vault_info)?; - vault_info.update_crank_time()?; - vault_info.set_crank_step(2)?; - - // read reward balances - let dual_rewards = *token_b_reward_custody.key != zero::id(); - let token_a_reward_balance = account::get_token_balance(token_a_reward_custody)?; - let token_b_reward_balance = if dual_rewards { - account::get_token_balance(token_b_reward_custody)? - } else { - 0 - }; - msg!( - "Read reward balances. token_a_reward_balance: {}, token_b_reward_balance: {}", - token_a_reward_balance, - token_b_reward_balance - ); - - // move rewards to token custodies - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - - let token_a_reward_mint = account::get_token_account_mint(token_a_reward_custody)?; - let token_a_custody_mint = account::get_token_account_mint(token_a_custody)?; - let token_b_custody_mint = account::get_token_account_mint(token_b_custody)?; - - if token_a_reward_mint == token_a_custody_mint { - pda::transfer_tokens_with_seeds( - token_a_reward_custody, - token_a_custody, - vault_authority, - seeds, - token_a_reward_balance, - )?; - } else if token_a_reward_mint == token_b_custody_mint { - pda::transfer_tokens_with_seeds( - token_a_reward_custody, - token_b_custody, - vault_authority, - seeds, - token_a_reward_balance, - )?; - } - if dual_rewards { - let token_b_reward_mint = account::get_token_account_mint(token_b_reward_custody)?; - if token_b_reward_mint == token_b_custody_mint { - pda::transfer_tokens_with_seeds( - token_b_reward_custody, - token_b_custody, - vault_authority, - seeds, - token_b_reward_balance, - )?; - } else if token_b_reward_mint == token_a_custody_mint { - pda::transfer_tokens_with_seeds( - token_b_reward_custody, - token_a_custody, - vault_authority, - seeds, - token_b_reward_balance, - )?; - } - } - - // read balances - let token_a_balance = account::get_token_balance(token_a_custody)?; - let token_b_balance = account::get_token_balance(token_b_custody)?; - msg!( - "Read balances. token_a_balance: {}, token_b_balance: {}", - token_a_balance, - token_b_balance - ); - if token_a_balance < 10 && token_b_balance < 10 { - msg!("Nothing to do: Not enough tokens to balance"); - return Ok(()); - } - - // rebalance - // compute and check pool ratios - let (pool_coin_balance, pool_pc_balance) = raydium::get_pool_token_balances( - pool_coin_token_account, - pool_pc_token_account, - amm_open_orders, - amm_id, - )?; - let pool_ratio = if pool_coin_balance != 0 { - pool_pc_balance as f64 / pool_coin_balance as f64 - } else { - 0.0 - }; - let custody_ratio = account::get_token_pair_ratio(token_a_custody, token_b_custody)?; - msg!( - "Compute pool ratios. custody_ratio: {}, pool_ratio: {}", - custody_ratio, - pool_ratio - ); - if pool_ratio == 0.0 { - msg!("Can't balance: Pool ratio is zero"); - return Ok(()); - } - if custody_ratio > 0.0 && (custody_ratio - pool_ratio).abs() * 100.0 / pool_ratio < 3.0 { - msg!("Nothing to do: Already balanced"); - return Ok(()); - } - - // compute ui amount to exchange - let extra_a_tokens = - (token_a_balance as f64 * pool_ratio - token_b_balance as f64) / (2.0 * pool_ratio); - let extra_b_tokens = extra_a_tokens * pool_ratio; - let reverse = extra_a_tokens < 0.0; - msg!( - "Rebalance tokens. reverse: {}, extra_a_tokens: {}, extra_b_tokens: {}", - reverse, - extra_a_tokens, - extra_b_tokens - ); - - let token_a_swap_custody = if reverse { - token_b_custody - } else { - token_a_custody - }; - let token_b_swap_custody = if reverse { - token_a_custody - } else { - token_b_custody - }; - let coint_extra_amount_in = if !reverse { - account::to_token_amount(extra_a_tokens.abs(), 0)? - } else { - 0 - }; - let pc_extra_amount_in = if !reverse { - 0 - } else { - account::to_token_amount(extra_b_tokens.abs(), 0)? - }; - if coint_extra_amount_in < 2 && pc_extra_amount_in < 2 { - msg!("Nothing to do: Not enough tokens to balance"); - return Ok(()); - } - - // get exact swap amounts - let (amount_in, min_amount_out) = raydium::get_pool_swap_amounts( - pool_coin_token_account, - pool_pc_token_account, - amm_open_orders, - amm_id, - coint_extra_amount_in, - pc_extra_amount_in, - )?; - msg!( - "Swap. amount_in: {}, min_amount_out {}", - amount_in, - min_amount_out - ); - if amount_in == 0 || min_amount_out == 0 { - msg!("Nothing to do: Not enough tokens to balance"); - return Ok(()); - } - - let initial_tokens_spent_balance = account::get_token_balance(token_a_swap_custody)?; - let initial_tokens_received_balance = account::get_token_balance(token_b_swap_custody)?; - - raydium::swap_with_seeds( - &[ - vault_authority.clone(), - token_a_swap_custody.clone(), - token_b_swap_custody.clone(), - pool_program_id.clone(), - pool_coin_token_account.clone(), - pool_pc_token_account.clone(), - spl_token_program.clone(), - amm_id.clone(), - amm_authority.clone(), - amm_open_orders.clone(), - amm_target.clone(), - serum_market.clone(), - serum_program_id.clone(), - serum_bids.clone(), - serum_asks.clone(), - serum_event_queue.clone(), - serum_coin_vault_account.clone(), - serum_pc_vault_account.clone(), - serum_vault_signer.clone(), - ], - seeds, - amount_in, - min_amount_out, - )?; - let _ = account::check_tokens_spent( - token_a_swap_custody, - initial_tokens_spent_balance, - amount_in, - )?; - let tokens_received = account::check_tokens_received( - token_b_swap_custody, - initial_tokens_received_balance, - min_amount_out, - )?; - - msg!( - "Done. tokens_received: {}, token_a_balance: {}, token_b_balance: {}", - tokens_received, - account::get_token_balance(token_a_custody)?, - account::get_token_balance(token_b_custody)? - ); - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/vaults/src/strategies/rdm_stake_lp_compound/crank3.rs b/farms/vaults/src/strategies/rdm_stake_lp_compound/crank3.rs deleted file mode 100644 index f294ee69af9..00000000000 --- a/farms/vaults/src/strategies/rdm_stake_lp_compound/crank3.rs +++ /dev/null @@ -1,289 +0,0 @@ -//! Crank step 3 instruction handler - -use { - crate::{strategies::common, vault_info::VaultInfo}, - solana_farm_sdk::{ - id::zero, - program::{account, protocol::raydium}, - vault::Vault, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn crank3(vault: &Vault, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _funding_account, - _vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - token_a_reward_custody, - token_b_reward_custody, - lp_token_custody, - token_a_custody, - token_b_custody, - pool_program_id, - pool_coin_token_account, - pool_pc_token_account, - lp_token_mint, - amm_id, - amm_authority, - amm_open_orders, - amm_target, - serum_market, - farm_program, - vault_stake_info, - farm_id, - farm_authority, - farm_lp_token_account, - farm_first_reward_token_account, - farm_second_reward_token_account, - clock_program - ] = accounts - { - if vault_authority.key != &vault.vault_authority { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - common::check_custody_accounts( - vault, - lp_token_custody, - token_a_custody, - token_b_custody, - token_a_reward_custody, - token_b_reward_custody, - vault_stake_info, - Some(amm_id.key), - Some(farm_id.key), - true, - )?; - - let mut vault_info = VaultInfo::new(vault_info_account); - common::check_min_crank_interval(&vault_info)?; - vault_info.update_crank_time()?; - vault_info.set_crank_step(3)?; - - // read balances - let token_a_balance = account::get_token_balance(token_a_custody)?; - let token_b_balance = account::get_token_balance(token_b_custody)?; - let lp_token_balance = account::get_token_balance(lp_token_custody)?; - msg!( - "Read balances. token_a_balance: {}, token_b_balance: {}", - token_a_balance, - token_b_balance - ); - if token_a_balance < 10 || token_b_balance < 10 { - msg!("Nothing to do: Not enough tokens to compound"); - return Ok(()); - } - - // compute and check pool ratios - let (pool_coin_balance, pool_pc_balance) = raydium::get_pool_token_balances( - pool_coin_token_account, - pool_pc_token_account, - amm_open_orders, - amm_id, - )?; - let pool_ratio = if pool_coin_balance != 0 { - pool_pc_balance as f64 / pool_coin_balance as f64 - } else { - 0.0 - }; - let custody_ratio = account::get_token_pair_ratio(token_a_custody, token_b_custody)?; - msg!( - "Compute pool ratios. custody_ratio: {}, pool_ratio: {}", - custody_ratio, - pool_ratio - ); - if custody_ratio == 0.0 || pool_ratio == 0.0 { - msg!("Pool ratio is zero"); - return Ok(()); - } - if (custody_ratio - pool_ratio).abs() * 100.0 / pool_ratio > 10.0 { - msg!("Unbalanced tokens, run Crank2 first"); - return Ok(()); - } - - // Deposit tokens into the pool - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - - // calculate deposit amounts - let (_, max_token_a_deposit_amount, max_token_b_deposit_amount) = - if custody_ratio >= pool_ratio { - raydium::get_pool_deposit_amounts( - pool_coin_token_account, - pool_pc_token_account, - lp_token_mint, - amm_open_orders, - amm_id, - token_a_balance, - 0, - )? - } else { - raydium::get_pool_deposit_amounts( - pool_coin_token_account, - pool_pc_token_account, - lp_token_mint, - amm_open_orders, - amm_id, - 0, - token_b_balance, - )? - }; - // one of the amounts can come out over the balance because ratios didn't reflect - // deposited volume, while get_pool_deposit_amounts does include it. - // in this case we just flip the side. - let (min_lp_token_amount, max_token_a_deposit_amount, max_token_b_deposit_amount) = - if max_token_b_deposit_amount > token_b_balance { - raydium::get_pool_deposit_amounts( - pool_coin_token_account, - pool_pc_token_account, - lp_token_mint, - amm_open_orders, - amm_id, - 0, - token_b_balance, - )? - } else if max_token_a_deposit_amount > token_a_balance { - raydium::get_pool_deposit_amounts( - pool_coin_token_account, - pool_pc_token_account, - lp_token_mint, - amm_open_orders, - amm_id, - token_a_balance, - 0, - )? - } else { - ( - raydium::estimate_lp_tokens_amount( - lp_token_mint, - max_token_a_deposit_amount, - max_token_b_deposit_amount, - pool_coin_balance, - pool_pc_balance, - )?, - max_token_a_deposit_amount, - max_token_b_deposit_amount, - ) - }; - - msg!("Deposit tokens into the pool. min_lp_token_amount: {}, max_token_a_deposit_amount: {}, max_token_b_deposit_amount: {}", - min_lp_token_amount, - max_token_a_deposit_amount, - max_token_b_deposit_amount); - if max_token_a_deposit_amount == 0 - || max_token_b_deposit_amount == 0 - || min_lp_token_amount < 2 - { - msg!("Nothing to do: Tokens balance is not large enough"); - return Ok(()); - } - - raydium::add_liquidity_with_seeds( - &[ - vault_authority.clone(), - token_a_custody.clone(), - token_b_custody.clone(), - lp_token_custody.clone(), - pool_program_id.clone(), - pool_coin_token_account.clone(), - pool_pc_token_account.clone(), - lp_token_mint.clone(), - spl_token_program.clone(), - amm_id.clone(), - amm_authority.clone(), - amm_open_orders.clone(), - amm_target.clone(), - serum_market.clone(), - ], - seeds, - max_token_a_deposit_amount, - max_token_b_deposit_amount, - )?; - - // Check tokens spent and return change back to user - let tokens_a_spent = account::check_tokens_spent( - token_a_custody, - token_a_balance, - max_token_a_deposit_amount, - )?; - let tokens_b_spent = account::check_tokens_spent( - token_b_custody, - token_b_balance, - max_token_b_deposit_amount, - )?; - - // Stake LP tokens - let dual_rewards = *farm_second_reward_token_account.key != zero::id(); - let lp_tokens_received = account::check_tokens_received( - lp_token_custody, - lp_token_balance, - min_lp_token_amount, - )?; - msg!( - "Stake LP tokens. tokens_a_spent: {}, tokens_b_spent: {}, lp_tokens_received: {}", - tokens_a_spent, - tokens_b_spent, - lp_tokens_received - ); - let token_a_reward_balance = account::get_token_balance(token_a_reward_custody)?; - let token_b_reward_balance = if dual_rewards { - account::get_token_balance(token_b_reward_custody)? - } else { - 0 - }; - - raydium::stake_with_seeds( - &[ - vault_authority.clone(), - vault_stake_info.clone(), - lp_token_custody.clone(), - token_a_reward_custody.clone(), - token_b_reward_custody.clone(), - farm_program.clone(), - farm_lp_token_account.clone(), - farm_first_reward_token_account.clone(), - farm_second_reward_token_account.clone(), - clock_program.clone(), - spl_token_program.clone(), - farm_id.clone(), - farm_authority.clone(), - ], - seeds, - lp_tokens_received, - )?; - if lp_token_balance != account::get_token_balance(lp_token_custody)? { - msg!("Error: Stake instruction didn't result in expected amount of LP tokens spent"); - return Err(ProgramError::Custom(165)); - } - - // update Vault stats - let token_a_rewards = - account::get_balance_increase(token_a_reward_custody, token_a_reward_balance)?; - let token_b_rewards = if dual_rewards { - account::get_balance_increase(token_b_reward_custody, token_b_reward_balance)? - } else { - 0 - }; - msg!( - "Update Vault stats. token_a_rewards: {}, token_b_rewards: {}", - token_a_rewards, - token_b_rewards - ); - vault_info.add_rewards(token_a_rewards, token_b_rewards)?; - vault_info.add_liquidity(tokens_a_spent, tokens_b_spent)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/vaults/src/strategies/rdm_stake_lp_compound/features.rs b/farms/vaults/src/strategies/rdm_stake_lp_compound/features.rs deleted file mode 100644 index d0fa54490f0..00000000000 --- a/farms/vaults/src/strategies/rdm_stake_lp_compound/features.rs +++ /dev/null @@ -1,85 +0,0 @@ -//! Feature toggling instructions handlers - -use { - crate::{traits::Features, vault_info::VaultInfo}, - solana_farm_sdk::{instruction::vault::VaultInstruction, vault::Vault}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl Features for VaultInstruction { - fn set_min_crank_interval( - _vault: &Vault, - vault_info: &mut VaultInfo, - _accounts: &[AccountInfo], - min_crank_interval_sec: u64, - ) -> ProgramResult { - msg!("set_min_crank_interval: {}", min_crank_interval_sec); - vault_info.set_min_crank_interval(min_crank_interval_sec) - } - - fn set_fee( - _vault: &Vault, - vault_info: &mut VaultInfo, - _accounts: &[AccountInfo], - fee: f64, - ) -> ProgramResult { - msg!("set_fee: {}", fee); - if !(0.0..=1.0).contains(&fee) { - msg!("Error: Invalid new value for fee"); - return Err(ProgramError::InvalidArgument); - } - vault_info.set_fee(fee) - } - - fn set_external_fee( - _vault: &Vault, - vault_info: &mut VaultInfo, - _accounts: &[AccountInfo], - external_fee: f64, - ) -> ProgramResult { - msg!("external_fee: {}", external_fee); - if !(0.0..=1.0).contains(&external_fee) { - msg!("Error: Invalid new value for external_fee"); - return Err(ProgramError::InvalidArgument); - } - vault_info.set_external_fee(external_fee) - } - - fn enable_deposits( - _vault: &Vault, - vault_info: &mut VaultInfo, - _accounts: &[AccountInfo], - ) -> ProgramResult { - msg!("enable_deposits"); - vault_info.enable_deposits() - } - - fn disable_deposits( - _vault: &Vault, - vault_info: &mut VaultInfo, - _accounts: &[AccountInfo], - ) -> ProgramResult { - msg!("disable_deposits"); - vault_info.disable_deposits() - } - - fn enable_withdrawals( - _vault: &Vault, - vault_info: &mut VaultInfo, - _accounts: &[AccountInfo], - ) -> ProgramResult { - msg!("enable_withdrawals"); - vault_info.enable_withdrawals() - } - - fn disable_withdrawals( - _vault: &Vault, - vault_info: &mut VaultInfo, - _accounts: &[AccountInfo], - ) -> ProgramResult { - msg!("disable_withdrawals"); - vault_info.disable_withdrawals() - } -} diff --git a/farms/vaults/src/strategies/rdm_stake_lp_compound/init.rs b/farms/vaults/src/strategies/rdm_stake_lp_compound/init.rs deleted file mode 100644 index 4141e23716f..00000000000 --- a/farms/vaults/src/strategies/rdm_stake_lp_compound/init.rs +++ /dev/null @@ -1,217 +0,0 @@ -//! Vault Init instruction handler - -use { - crate::{traits::Init, vault_info::VaultInfo}, - solana_farm_sdk::{ - id::zero, - instruction::vault::VaultInstruction, - program::{ - pda, - protocol::raydium::{RaydiumUserStakeInfo, RaydiumUserStakeInfoV4}, - }, - token::Token, - traits::Packed, - vault::Vault, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl Init for VaultInstruction { - fn init(vault: &Vault, accounts: &[AccountInfo], step: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - admin_account, - _vault_metadata, - vault_info_account, - _multisig_account, - vault_authority, - vault_program, - _system_program, - _spl_token_program, - rent_program, - farm_program, - vault_token_mint, - vault_token_ref, - vault_stake_info, - vault_stake_info_v4, - fees_account_a, - fees_account_b, - token_a_custody, - token_b_custody, - lp_token_custody, - token_a_mint, - token_b_mint, - lp_token_mint, - token_a_reward_custody, - token_b_reward_custody, - token_a_reward_mint, - token_b_reward_mint - ] = accounts - { - // validate accounts - if vault_authority.key != &vault.vault_authority - || vault_token_ref.key != &vault.vault_token_ref - || vault_program.key != &vault.vault_program_id - { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - - if step <= 1 { - // init vault authority account - msg!("Init vault authority"); - pda::init_system_account( - admin_account, - vault_authority, - &vault.vault_program_id, - &vault.vault_program_id, - &[b"vault_authority", vault.name.as_bytes()], - 0, - )?; - - // init vault info account - msg!("Init vault info"); - pda::init_system_account( - admin_account, - vault_info_account, - &vault.vault_program_id, - &vault.vault_program_id, - &[b"info_account", vault.name.as_bytes()], - VaultInfo::LEN, - )?; - let mut vault_info = VaultInfo::new(vault_info_account); - vault_info.init(&vault.name)?; - - // init vault token mint - msg!("Init vault token mint"); - let vault_token = Token::unpack(&vault_token_ref.try_borrow_data()?)?; - if vault_token_mint.key != &vault_token.mint { - msg!("Error: Invalid Vault token mint"); - return Err(ProgramError::InvalidArgument); - } - pda::init_mint( - admin_account, - vault_token_mint, - vault_authority, - rent_program, - &vault.vault_program_id, - &[b"vault_token_mint", vault.name.as_bytes()], - vault_token.decimals, - )?; - - // init stake info - msg!("Init stake info"); - if vault_stake_info.key != &zero::id() { - pda::init_system_account( - admin_account, - vault_stake_info, - farm_program.key, - &vault.vault_program_id, - &[b"vault_stake_info", vault.name.as_bytes()], - RaydiumUserStakeInfo::LEN, - )?; - } else { - pda::init_system_account( - admin_account, - vault_stake_info_v4, - farm_program.key, - &vault.vault_program_id, - &[b"vault_stake_info_v4", vault.name.as_bytes()], - RaydiumUserStakeInfoV4::LEN, - )?; - } - } - - if step == 0 || step == 2 { - // init token accounts - msg!("Init fees account a"); - pda::init_token_account( - admin_account, - fees_account_a, - token_a_reward_mint, - vault_authority, - rent_program, - &vault.vault_program_id, - &[b"fees_account_a", vault.name.as_bytes()], - )?; - - if *fees_account_b.key != zero::id() { - msg!("Init fees account b"); - pda::init_token_account( - admin_account, - fees_account_b, - token_b_reward_mint, - vault_authority, - rent_program, - &vault.vault_program_id, - &[b"fees_account_b", vault.name.as_bytes()], - )?; - } - - msg!("Init lp token custody account"); - pda::init_token_account( - admin_account, - lp_token_custody, - lp_token_mint, - vault_authority, - rent_program, - &vault.vault_program_id, - &[b"lp_token_custody", vault.name.as_bytes()], - )?; - - msg!("Init token a custody account"); - pda::init_token_account( - admin_account, - token_a_custody, - token_a_mint, - vault_authority, - rent_program, - &vault.vault_program_id, - &[b"token_a_custody", vault.name.as_bytes()], - )?; - - msg!("Init token b custody account"); - pda::init_token_account( - admin_account, - token_b_custody, - token_b_mint, - vault_authority, - rent_program, - &vault.vault_program_id, - &[b"token_b_custody", vault.name.as_bytes()], - )?; - - msg!("Init token a reward custody account"); - pda::init_token_account( - admin_account, - token_a_reward_custody, - token_a_reward_mint, - vault_authority, - rent_program, - &vault.vault_program_id, - &[b"token_a_reward_custody", vault.name.as_bytes()], - )?; - - if *token_b_reward_custody.key != zero::id() { - msg!("Init token b reward custody account"); - pda::init_token_account( - admin_account, - token_b_reward_custody, - token_b_reward_mint, - vault_authority, - rent_program, - &vault.vault_program_id, - &[b"token_b_reward_custody", vault.name.as_bytes()], - )?; - } - } - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } - } -} diff --git a/farms/vaults/src/strategies/rdm_stake_lp_compound/lock_liquidity.rs b/farms/vaults/src/strategies/rdm_stake_lp_compound/lock_liquidity.rs deleted file mode 100644 index af627cb2ba9..00000000000 --- a/farms/vaults/src/strategies/rdm_stake_lp_compound/lock_liquidity.rs +++ /dev/null @@ -1,203 +0,0 @@ -//! Lock Liquidity in the Vault instruction handler - -use { - crate::{ - strategies::common, traits::LockLiquidity, user_info::UserInfo, vault_info::VaultInfo, - }, - solana_farm_sdk::{ - id::zero, - instruction::vault::VaultInstruction, - math, - program::{account, pda, protocol::raydium}, - vault::Vault, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl LockLiquidity for VaultInstruction { - fn lock_liquidity(vault: &Vault, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - _vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - vault_token_mint, - user_info_account, - user_vt_token_account, - token_a_reward_custody, - token_b_reward_custody, - lp_token_custody, - farm_program, - vault_stake_info, - farm_id, - farm_authority, - farm_lp_token_account, - farm_first_reward_token_account, - farm_second_reward_token_account, - clock_program - ] = accounts - { - // validate accounts - if vault_authority.key != &vault.vault_authority { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - if !user_account.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - if !account::check_token_account_owner(user_vt_token_account,user_account.key)? { - msg!("Error: Invalid VT token account owner"); - return Err(ProgramError::IllegalOwner); - } - common::check_custody_accounts( - vault, - lp_token_custody, - vault_authority, - vault_authority, - token_a_reward_custody, - token_b_reward_custody, - vault_stake_info, - None, - Some(farm_id.key), - false, - )?; - if !UserInfo::validate_account(vault, user_info_account, user_account.key) { - msg!("Error: Invalid user info account"); - return Err(ProgramError::Custom(140)); - } - - let mut vault_info = VaultInfo::new(vault_info_account); - if !vault_info.is_deposit_allowed()? { - msg!("Error: Deposits are not allowed for this Vault"); - return Err(ProgramError::Custom(220)); - } - - // check lp balance - let mut user_info = UserInfo::new(user_info_account); - let lp_tokens_debt = user_info.get_lp_tokens_debt()?; - msg!("Read balances. lp_tokens_debt: {}", lp_tokens_debt); - - let lp_stake_amount = if amount > 0 { - if lp_tokens_debt < amount { - msg!("Error: Insufficient funds"); - return Err(ProgramError::InsufficientFunds); - } - amount - } else { - lp_tokens_debt - }; - if lp_stake_amount == 0 { - msg!("Error: Zero balance. Forgot to deposit funds?"); - return Err(ProgramError::InsufficientFunds); - } - - let initial_lp_custody_balance = account::get_token_balance(lp_token_custody)?; - - // Stake LP tokens - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - - let dual_rewards = *farm_second_reward_token_account.key != zero::id(); - let initial_token_a_reward_balance = - account::get_token_balance(token_a_reward_custody)?; - let initial_token_b_reward_balance = if dual_rewards { - account::get_token_balance(token_b_reward_custody)? - } else { - 0 - }; - - msg!("Stake LP tokens"); - let stake_balance = raydium::get_stake_account_balance(vault_stake_info)?; - - raydium::stake_with_seeds( - &[ - vault_authority.clone(), - vault_stake_info.clone(), - lp_token_custody.clone(), - token_a_reward_custody.clone(), - token_b_reward_custody.clone(), - farm_program.clone(), - farm_lp_token_account.clone(), - farm_first_reward_token_account.clone(), - farm_second_reward_token_account.clone(), - clock_program.clone(), - spl_token_program.clone(), - farm_id.clone(), - farm_authority.clone(), - ], - seeds, - lp_stake_amount, - )?; - let _ = account::check_tokens_spent( - lp_token_custody, - initial_lp_custody_balance, - lp_stake_amount, - )?; - - // update user stats - msg!("Update user stats"); - user_info.remove_lp_tokens_debt(lp_stake_amount)?; - - // update Vault stats - let token_a_rewards = account::get_balance_increase( - token_a_reward_custody, - initial_token_a_reward_balance, - )?; - let token_b_rewards = if dual_rewards { - account::get_balance_increase( - token_b_reward_custody, - initial_token_b_reward_balance, - )? - } else { - 0 - }; - msg!( - "Update Vault stats. token_a_rewards: {}, token_b_rewards: {}", - token_a_rewards, - token_b_rewards - ); - vault_info.add_rewards(token_a_rewards, token_b_rewards)?; - - // compute Vault tokens to mint - let vt_supply_amount = account::get_token_supply(vault_token_mint)?; - let vt_to_mint = if vt_supply_amount == 0 || stake_balance == 0 { - lp_stake_amount - } else { - math::checked_as_u64(math::checked_div( - math::checked_mul(lp_stake_amount as u128, vt_supply_amount as u128)?, - stake_balance as u128 - )?)? - }; - - // mint vault tokens to user - msg!( - "Mint Vault tokens to the user. vt_to_mint: {}, vt_supply_amount: {}, stake_balance: {}", - vt_to_mint, vt_supply_amount, - stake_balance - ); - if vt_to_mint == 0 { - msg!("Error: Add liquidity instruction didn't result in Vault tokens mint"); - return Err(ProgramError::Custom(170)); - } - pda::mint_to_with_seeds( - user_vt_token_account, - vault_token_mint, - vault_authority, - seeds, - vt_to_mint, - )?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } - } -} diff --git a/farms/vaults/src/strategies/rdm_stake_lp_compound/mod.rs b/farms/vaults/src/strategies/rdm_stake_lp_compound/mod.rs deleted file mode 100644 index b649f8f5c13..00000000000 --- a/farms/vaults/src/strategies/rdm_stake_lp_compound/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -pub mod add_liquidity; -pub mod crank; -mod crank1; -mod crank2; -mod crank3; -pub mod features; -pub mod init; -pub mod lock_liquidity; -pub mod params; -pub mod remove_liquidity; -pub mod remove_multisig; -pub mod set_admin_signers; -pub mod shutdown; -pub mod unlock_liquidity; -pub mod user_init; -pub mod withdraw_fees; diff --git a/farms/vaults/src/strategies/rdm_stake_lp_compound/params.rs b/farms/vaults/src/strategies/rdm_stake_lp_compound/params.rs deleted file mode 100644 index 11e744b5763..00000000000 --- a/farms/vaults/src/strategies/rdm_stake_lp_compound/params.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! Vault related parameters and accounts - -use crate::{traits::VaultParams, vault_info::VaultInfo}; - -impl VaultParams for VaultInfo<'_, '_> { - fn default_min_crank_interval() -> u64 { - 60 - } - - fn default_fee() -> f64 { - 0.003 - } - - fn default_external_fee() -> f64 { - 0.0025 - } -} diff --git a/farms/vaults/src/strategies/rdm_stake_lp_compound/remove_liquidity.rs b/farms/vaults/src/strategies/rdm_stake_lp_compound/remove_liquidity.rs deleted file mode 100644 index 2ab469b344a..00000000000 --- a/farms/vaults/src/strategies/rdm_stake_lp_compound/remove_liquidity.rs +++ /dev/null @@ -1,190 +0,0 @@ -//! Remove Liquidity from the Vault instruction handler - -use { - crate::{traits::RemoveLiquidity, user_info::UserInfo, vault_info::VaultInfo}, - solana_farm_sdk::{ - instruction::vault::VaultInstruction, - program::{account, protocol::raydium}, - vault::{Vault, VaultStrategy}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl RemoveLiquidity for VaultInstruction { - fn remove_liquidity(vault: &Vault, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - _vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - user_info_account, - user_token_a_account, - user_token_b_account, - lp_token_custody, - pool_program_id, - pool_withdraw_queue, - pool_temp_lp_token_account, - pool_coin_token_account, - pool_pc_token_account, - lp_token_mint, - amm_id, - amm_authority, - amm_open_orders, - amm_target, - serum_market, - serum_program_id, - serum_bids, - serum_asks, - serum_event_queue, - serum_coin_vault_account, - serum_pc_vault_account, - serum_vault_signer - ] = accounts - { - // validate accounts - if vault_authority.key != &vault.vault_authority { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - if !user_account.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - if !account::check_token_account_owner(user_token_a_account, user_account.key)? - || !account::check_token_account_owner(user_token_b_account, user_account.key)? - { - msg!("Error: Invalid token account owner"); - return Err(ProgramError::IllegalOwner); - } - if let VaultStrategy::StakeLpCompoundRewards { - pool_id: pool_id_key, - lp_token_custody: lp_token_custody_key, - .. - } = vault.strategy - { - if &lp_token_custody_key != lp_token_custody.key - { - msg!("Error: Invalid LP custody account"); - return Err(ProgramError::InvalidArgument); - } - if &pool_id_key != amm_id.key { - msg!("Error: Invalid pool id"); - return Err(ProgramError::InvalidArgument); - } - } else { - msg!("Error: Vault strategy mismatch"); - return Err(ProgramError::InvalidArgument); - } - if !UserInfo::validate_account(vault, user_info_account, user_account.key) { - msg!("Error: Invalid user info account"); - return Err(ProgramError::Custom(140)); - } - - let mut vault_info = VaultInfo::new(vault_info_account); - if !vault_info.is_withdrawal_allowed()? { - msg!("Error: Withdrawals are not allowed for this Vault"); - return Err(ProgramError::Custom(230)); - } - - // check lp balance - let mut user_info = UserInfo::new(user_info_account); - let lp_tokens_debt = user_info.get_lp_tokens_debt()?; - msg!("Read balances. lp_tokens_debt: {}", lp_tokens_debt); - - let lp_remove_amount = if amount > 0 { - if lp_tokens_debt < amount { - msg!("Error: Insufficient funds"); - return Err(ProgramError::InsufficientFunds); - } - amount - } else { - lp_tokens_debt - }; - if lp_remove_amount == 0 { - msg!("Error: Zero balance. Forgot to unlock funds?"); - return Err(ProgramError::InsufficientFunds); - } - - // remove liquidity from the pool - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - - let initial_token_a_account_balance = account::get_token_balance(user_token_a_account)?; - let initial_token_b_account_balance = account::get_token_balance(user_token_b_account)?; - let initial_lp_tokens_balance = account::get_token_balance(lp_token_custody)?; - - msg!( - "Remove liquidity from the pool. lp_remove_amount: {}", - lp_remove_amount - ); - raydium::remove_liquidity_with_seeds( - &[ - vault_authority.clone(), - user_token_a_account.clone(), - user_token_b_account.clone(), - lp_token_custody.clone(), - pool_program_id.clone(), - pool_withdraw_queue.clone(), - pool_temp_lp_token_account.clone(), - pool_coin_token_account.clone(), - pool_pc_token_account.clone(), - lp_token_mint.clone(), - spl_token_program.clone(), - amm_id.clone(), - amm_authority.clone(), - amm_open_orders.clone(), - amm_target.clone(), - serum_market.clone(), - serum_program_id.clone(), - serum_bids.clone(), - serum_asks.clone(), - serum_event_queue.clone(), - serum_coin_vault_account.clone(), - serum_pc_vault_account.clone(), - serum_vault_signer.clone(), - ], - seeds, - lp_remove_amount, - )?; - - // check tokens received - let tokens_a_received = - account::get_balance_increase(user_token_a_account, initial_token_a_account_balance)?; - let tokens_b_received = - account::get_balance_increase(user_token_b_account, initial_token_b_account_balance)?; - if tokens_a_received == 0 && tokens_b_received == 0 { - msg!("Error: Remove liquidity instruction didn't result in any of the tokens received"); - return Err(ProgramError::Custom(190)); - } - let _ = account::check_tokens_spent( - lp_token_custody, - initial_lp_tokens_balance, - lp_remove_amount, - )?; - - // update user stats - msg!( - "Update user stats. tokens_a_received: {}, tokens_b_received: {}", - tokens_a_received, - tokens_b_received - ); - user_info.remove_liquidity(tokens_a_received, tokens_b_received)?; - user_info.remove_lp_tokens_debt(lp_remove_amount)?; - - // update vault stats - msg!("Update Vault stats"); - vault_info.remove_liquidity(tokens_a_received, tokens_b_received)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } - } -} diff --git a/farms/vaults/src/strategies/rdm_stake_lp_compound/remove_multisig.rs b/farms/vaults/src/strategies/rdm_stake_lp_compound/remove_multisig.rs deleted file mode 100644 index 8bd3ca63446..00000000000 --- a/farms/vaults/src/strategies/rdm_stake_lp_compound/remove_multisig.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! Vault RemoveMultisig instruction handler - -use { - crate::traits::RemoveMultisig, - solana_farm_sdk::{instruction::vault::VaultInstruction, program::account, vault::Vault}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl RemoveMultisig for VaultInstruction { - fn remove_multisig(vault: &Vault, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - admin_account, - _vault_metadata, - _vault_info_account, - _active_multisig_account, - vault_multisig_account - ] = accounts - { - msg!("Close multisig account"); - account::close_system_account(admin_account, vault_multisig_account, &vault.vault_program_id)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } - } -} diff --git a/farms/vaults/src/strategies/rdm_stake_lp_compound/set_admin_signers.rs b/farms/vaults/src/strategies/rdm_stake_lp_compound/set_admin_signers.rs deleted file mode 100644 index dbbae0dab56..00000000000 --- a/farms/vaults/src/strategies/rdm_stake_lp_compound/set_admin_signers.rs +++ /dev/null @@ -1,60 +0,0 @@ -//! Vault SetAdminSigners instruction handler - -use { - crate::traits::SetAdminSigners, - solana_farm_sdk::{ - error::FarmError, - instruction::vault::VaultInstruction, - program::{account, multisig, multisig::Multisig, pda}, - vault::Vault, - }, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - }, -}; - -impl SetAdminSigners for VaultInstruction { - fn set_admin_signers( - vault: &Vault, - accounts: &[AccountInfo], - min_signatures: u8, - ) -> ProgramResult { - let accounts_iter = &mut accounts.iter(); - - let signer_account = next_account_info(accounts_iter)?; - let _vault_metadata = next_account_info(accounts_iter)?; - let _vault_info_account = next_account_info(accounts_iter)?; - let _active_multisig_account = next_account_info(accounts_iter)?; - let vault_multisig_account = next_account_info(accounts_iter)?; - let _system_program = next_account_info(accounts_iter)?; - - if vault_multisig_account.key != &vault.multisig_account { - msg!("Error: Invalid vault multisig account"); - return Err(FarmError::IncorrectAccountAddress.into()); - } - - if account::is_empty(vault_multisig_account)? { - msg!("Init multisig account"); - let seeds: &[&[u8]] = &[b"multisig", vault.name.as_bytes()]; - let _bump = pda::init_system_account( - signer_account, - vault_multisig_account, - &vault.vault_program_id, - &vault.vault_program_id, - seeds, - Multisig::LEN, - )?; - } else { - msg!("Update multisig account"); - } - multisig::set_signers( - vault_multisig_account, - accounts_iter.as_slice(), - min_signatures, - )?; - - Ok(()) - } -} diff --git a/farms/vaults/src/strategies/rdm_stake_lp_compound/shutdown.rs b/farms/vaults/src/strategies/rdm_stake_lp_compound/shutdown.rs deleted file mode 100644 index f5498bd8b39..00000000000 --- a/farms/vaults/src/strategies/rdm_stake_lp_compound/shutdown.rs +++ /dev/null @@ -1,22 +0,0 @@ -//! Vault Shutdown instruction handler - -use { - crate::{traits::Shutdown, vault_info::VaultInfo}, - solana_farm_sdk::{instruction::vault::VaultInstruction, vault::Vault}, - solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, msg}, -}; - -impl Shutdown for VaultInstruction { - fn shutdown(_vault: &Vault, accounts: &[AccountInfo]) -> ProgramResult { - if let [_admin_account, _vault_metadata, vault_info_account, _multisig_account] = accounts { - // Don't do anything special on shutdown for this Vault, just disable deposits and withdrawals - let mut vault_info = VaultInfo::new(vault_info_account); - msg!("disable_deposit"); - vault_info.disable_deposits()?; - msg!("disable_withdrawal"); - vault_info.disable_withdrawals()?; - //pda::close_account(admin_account, vault_info_account) - } - Ok(()) - } -} diff --git a/farms/vaults/src/strategies/rdm_stake_lp_compound/unlock_liquidity.rs b/farms/vaults/src/strategies/rdm_stake_lp_compound/unlock_liquidity.rs deleted file mode 100644 index be6bcb3b5b0..00000000000 --- a/farms/vaults/src/strategies/rdm_stake_lp_compound/unlock_liquidity.rs +++ /dev/null @@ -1,206 +0,0 @@ -//! Unlock Liquidity in the Vault instruction handler - -use { - crate::{ - strategies::common, traits::UnlockLiquidity, user_info::UserInfo, vault_info::VaultInfo, - }, - solana_farm_sdk::{ - id::zero, - instruction::vault::VaultInstruction, - math, - program::{account, protocol::raydium}, - vault::Vault, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - pubkey::Pubkey, - }, -}; - -impl UnlockLiquidity for VaultInstruction { - fn unlock_liquidity(vault: &Vault, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - _vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - vault_token_mint, - user_info_account, - user_vt_token_account, - token_a_reward_custody, - token_b_reward_custody, - lp_token_custody, - farm_program, - vault_stake_info, - farm_id, - farm_authority, - farm_lp_token_account, - farm_first_reward_token_account, - farm_second_reward_token_account, - clock_program - ] = accounts - { - // validate accounts - if vault_authority.key != &vault.vault_authority { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - if !user_account.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - if !account::check_token_account_owner(user_vt_token_account, user_account.key)? { - msg!("Error: Invalid VT token account owner"); - return Err(ProgramError::IllegalOwner); - } - common::check_custody_accounts( - vault, - lp_token_custody, - vault_authority, - vault_authority, - token_a_reward_custody, - token_b_reward_custody, - vault_stake_info, - None, - Some(farm_id.key), - false, - )?; - if !UserInfo::validate_account(vault, user_info_account, user_account.key) { - msg!("Error: Invalid user info account"); - return Err(ProgramError::Custom(140)); - } - - let mut vault_info = VaultInfo::new(vault_info_account); - if !vault_info.is_withdrawal_allowed()? { - msg!("Error: Withdrawals are not allowed for this Vault"); - return Err(ProgramError::Custom(230)); - } - - // calculate amounts to unstake - let vt_remove_amount = if amount > 0 { - amount - } else { - account::get_token_balance(user_vt_token_account)? - }; - let vt_supply_amount = account::get_token_supply(vault_token_mint)?; - let stake_balance = raydium::get_stake_account_balance(vault_stake_info)?; - - msg!( - "Read balances. vt_remove_amount: {}, vt_supply_amount: {}, stake_balance: {}", - vt_remove_amount, - vt_supply_amount, - stake_balance - ); - if vt_remove_amount == 0 || vt_supply_amount == 0 || stake_balance == 0 { - msg!("Error: Zero balance"); - return Err(ProgramError::InsufficientFunds); - } - let lp_remove_amount = math::checked_as_u64(math::checked_div( - math::checked_mul(stake_balance as u128, vt_remove_amount as u128)?, - vt_supply_amount as u128, - )?)?; - - // unstake - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - - let dual_rewards = *farm_second_reward_token_account.key != zero::id(); - let initial_token_a_reward_balance = - account::get_token_balance(token_a_reward_custody)?; - let initial_token_b_reward_balance = if dual_rewards { - account::get_token_balance(token_b_reward_custody)? - } else { - 0 - }; - let initial_lp_tokens_balance = account::get_token_balance(lp_token_custody)?; - - msg!( - "Unstake user's lp tokens. amount: {}, lp_remove_amount: {}", - amount, - lp_remove_amount - ); - raydium::unstake_with_seeds( - &[ - vault_authority.clone(), - vault_stake_info.clone(), - lp_token_custody.clone(), - token_a_reward_custody.clone(), - token_b_reward_custody.clone(), - farm_program.clone(), - farm_lp_token_account.clone(), - farm_first_reward_token_account.clone(), - farm_second_reward_token_account.clone(), - clock_program.clone(), - spl_token_program.clone(), - farm_id.clone(), - farm_authority.clone(), - ], - seeds, - lp_remove_amount, - )?; - let _ = account::check_tokens_received( - lp_token_custody, - initial_lp_tokens_balance, - lp_remove_amount, - )?; - - // update user stats - msg!("Update user stats"); - let mut user_info = UserInfo::new(user_info_account); - user_info.add_lp_tokens_debt(lp_remove_amount)?; - - // update Vault stats - let token_a_rewards = account::get_balance_increase( - token_a_reward_custody, - initial_token_a_reward_balance, - )?; - let token_b_rewards = if dual_rewards { - account::get_balance_increase( - token_b_reward_custody, - initial_token_b_reward_balance, - )? - } else { - 0 - }; - msg!( - "Update Vault stats. token_a_rewards: {}, token_b_rewards: {}", - token_a_rewards, - token_b_rewards - ); - vault_info.add_rewards(token_a_rewards, token_b_rewards)?; - - // burn vault tokens - msg!( - "Burn Vault tokens from the user. vt_remove_amount: {}", - vt_remove_amount - ); - let key = Pubkey::create_program_address( - &[ - b"vault_token_mint", - vault.name.as_bytes(), - &[vault.vault_token_bump], - ], - &vault.vault_program_id, - )?; - if vault_token_mint.key != &key { - msg!("Error: Invalid Vault token mint"); - return Err(ProgramError::InvalidSeeds); - } - account::burn_tokens( - user_vt_token_account, - vault_token_mint, - user_account, - vt_remove_amount, - )?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } - } -} diff --git a/farms/vaults/src/strategies/rdm_stake_lp_compound/user_init.rs b/farms/vaults/src/strategies/rdm_stake_lp_compound/user_init.rs deleted file mode 100644 index ad81b179dff..00000000000 --- a/farms/vaults/src/strategies/rdm_stake_lp_compound/user_init.rs +++ /dev/null @@ -1,55 +0,0 @@ -//! Vault User Init instruction handler - -use { - crate::{traits::UserInit, user_info::UserInfo}, - solana_farm_sdk::{ - instruction::vault::VaultInstruction, - program::{account, pda}, - vault::Vault, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl UserInit for VaultInstruction { - fn user_init(vault: &Vault, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - funding_account, - _vault_metadata, - _vault_info_account, - user_account, - user_info_account, - _system_program - ] = accounts - { - if account::is_empty(user_info_account)? { - msg!("Create user info account"); - let seeds: &[&[u8]] = &[ - b"user_info_account", - user_account.key.as_ref(), - vault.name.as_bytes(), - ]; - let bump = pda::init_system_account( - funding_account, - user_info_account, - &vault.vault_program_id, - &vault.vault_program_id, - seeds, - UserInfo::LEN, - )?; - let mut user_info = UserInfo::new(user_info_account); - user_info.init(&vault.name, bump)?; - } else if !UserInfo::validate_account(vault, user_info_account, user_account.key) { - msg!("Error: User info account already initialized but not valid"); - return Err(ProgramError::AccountAlreadyInitialized); - } - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } - } -} diff --git a/farms/vaults/src/strategies/rdm_stake_lp_compound/withdraw_fees.rs b/farms/vaults/src/strategies/rdm_stake_lp_compound/withdraw_fees.rs deleted file mode 100644 index 59b8c60b83a..00000000000 --- a/farms/vaults/src/strategies/rdm_stake_lp_compound/withdraw_fees.rs +++ /dev/null @@ -1,64 +0,0 @@ -//! Vault WithdrawFees instruction handler - -use { - crate::traits::WithdrawFees, - solana_farm_sdk::{ - instruction::vault::VaultInstruction, program::account, program::pda, vault::Vault, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl WithdrawFees for VaultInstruction { - fn withdraw_fees(vault: &Vault, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - _vault_metadata, - _vault_info_account, - _multisig_account, - vault_authority, - _spl_token_program, - fees_account, - destination_account - ] = accounts - { - // validate accounts - if vault_authority.key != &vault.vault_authority { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - if Some(*fees_account.key) != vault.fees_account_a - && Some(*fees_account.key) != vault.fees_account_b - { - msg!("Error: Invalid fee accounts"); - return Err(ProgramError::InvalidArgument); - } - - let withdraw_amount = if amount > 0 { - amount - } else { - account::get_token_balance(fees_account)? - }; - - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - pda::transfer_tokens_with_seeds( - fees_account, - destination_account, - vault_authority, - seeds, - withdraw_amount, - )?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } - } -} diff --git a/farms/vaults/src/strategies/sbr_stake_lp_compound/add_liquidity.rs b/farms/vaults/src/strategies/sbr_stake_lp_compound/add_liquidity.rs deleted file mode 100644 index c2fff4afe42..00000000000 --- a/farms/vaults/src/strategies/sbr_stake_lp_compound/add_liquidity.rs +++ /dev/null @@ -1,154 +0,0 @@ -//! Add Liquidity to the Vault instruction handler - -use { - crate::{traits::AddLiquidity, user_info::UserInfo, vault_info::VaultInfo}, - solana_farm_sdk::{ - instruction::vault::VaultInstruction, - program::{account, protocol::saber}, - vault::{Vault, VaultStrategy}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl AddLiquidity for VaultInstruction { - fn add_liquidity( - vault: &Vault, - accounts: &[AccountInfo], - max_token_a_amount: u64, - max_token_b_amount: u64, - ) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - _vault_metadata, - vault_info_account, - spl_token_program, - user_info_account, - user_token_a_account, - user_token_b_account, - user_lp_token_account, - lp_token_custody, - pool_program_id, - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - clock_program, - swap_account, - swap_authority - ] = accounts - { - // validate accounts - if !user_account.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - if !account::check_token_account_owner(user_lp_token_account, user_account.key)? { - msg!("Error: Invalid token account owner"); - return Err(ProgramError::IllegalOwner); - } - if let VaultStrategy::StakeLpCompoundRewards { - pool_id: pool_id_key, - lp_token_custody: lp_token_custody_key, - .. - } = vault.strategy - { - if &pool_id_key != swap_account.key { - msg!("Error: Invalid pool id"); - return Err(ProgramError::InvalidArgument); - } - if &lp_token_custody_key != lp_token_custody.key { - msg!("Error: Invalid custody accounts"); - return Err(ProgramError::InvalidArgument); - } - } else { - msg!("Error: Vault strategy mismatch"); - return Err(ProgramError::InvalidArgument); - } - - if !UserInfo::validate_account(vault, user_info_account, user_account.key) { - msg!("Error: Invalid user info account"); - return Err(ProgramError::Custom(140)); - } - - let mut vault_info = VaultInfo::new(vault_info_account); - if !vault_info.is_deposit_allowed()? { - msg!("Error: Deposits are not allowed for this Vault"); - return Err(ProgramError::Custom(220)); - } - - // read user balances - let initial_token_a_user_balance = account::get_token_balance(user_token_a_account)?; - let initial_token_b_user_balance = account::get_token_balance(user_token_b_account)?; - let initial_lp_user_balance = account::get_token_balance(user_lp_token_account)?; - - // Deposit tokens into the pool - msg!("Deposit tokens into the pool. max_token_a_amount: {}, max_token_b_amount: {}", max_token_a_amount, max_token_b_amount); - if max_token_a_amount == 0 && max_token_b_amount == 0 { - msg!("Error: Zero deposit amount"); - return Err(ProgramError::InsufficientFunds); - } - saber::add_liquidity( - &[ - user_account.clone(), - user_token_a_account.clone(), - user_token_b_account.clone(), - user_lp_token_account.clone(), - pool_program_id.clone(), - pool_token_a_account.clone(), - pool_token_b_account.clone(), - lp_token_mint.clone(), - spl_token_program.clone(), - clock_program.clone(), - swap_account.clone(), - swap_authority.clone(), - ], - max_token_a_amount, - max_token_b_amount, - )?; - - // check amounts spent and received - let tokens_a_spent = account::check_tokens_spent( - user_token_a_account, - initial_token_a_user_balance, - max_token_a_amount, - )?; - let tokens_b_spent = account::check_tokens_spent( - user_token_b_account, - initial_token_b_user_balance, - max_token_b_amount, - )?; - let lp_tokens_received = - account::check_tokens_received(user_lp_token_account, initial_lp_user_balance, 1)?; - - // transfer LP tokens to the custody - msg!( - "Transfer LP tokens from user. tokens_a_spent: {}, tokens_b_spent: {}, lp_tokens_received: {}", - tokens_a_spent, - tokens_b_spent, - lp_tokens_received - ); - account::transfer_tokens( - user_lp_token_account, - lp_token_custody, - user_account, - lp_tokens_received, - )?; - - // update user stats - msg!("Update user stats"); - let mut user_info = UserInfo::new(user_info_account); - user_info.add_liquidity(tokens_a_spent, tokens_b_spent)?; - user_info.add_lp_tokens_debt(lp_tokens_received)?; - - // update Vault stats - msg!("Update Vault stats"); - vault_info.add_liquidity(tokens_a_spent, tokens_b_spent)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } - } -} diff --git a/farms/vaults/src/strategies/sbr_stake_lp_compound/crank.rs b/farms/vaults/src/strategies/sbr_stake_lp_compound/crank.rs deleted file mode 100644 index 21cfb8f634d..00000000000 --- a/farms/vaults/src/strategies/sbr_stake_lp_compound/crank.rs +++ /dev/null @@ -1,30 +0,0 @@ -//! Vault Crank instruction handler - -use { - crate::{ - strategies::sbr_stake_lp_compound::{ - crank1::crank1, crank2::crank2, crank3::crank3, crank4::crank4, crank5::crank5, - }, - traits::Crank, - }, - solana_farm_sdk::{instruction::vault::VaultInstruction, vault::Vault}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl Crank for VaultInstruction { - fn crank(vault: &Vault, accounts: &[AccountInfo], step: u64) -> ProgramResult { - match step { - 1 => crank1(vault, accounts), - 2 => crank2(vault, accounts), - 3 => crank3(vault, accounts), - 4 => crank4(vault, accounts), - 5 => crank5(vault, accounts), - _ => { - msg!("Error: Invalid Crank step"); - Err(ProgramError::InvalidArgument) - } - } - } -} diff --git a/farms/vaults/src/strategies/sbr_stake_lp_compound/crank1.rs b/farms/vaults/src/strategies/sbr_stake_lp_compound/crank1.rs deleted file mode 100644 index be9673d6cc8..00000000000 --- a/farms/vaults/src/strategies/sbr_stake_lp_compound/crank1.rs +++ /dev/null @@ -1,115 +0,0 @@ -//! Crank step 1 instruction handler - -use { - crate::{strategies::common, vault_info::VaultInfo}, - solana_farm_sdk::{ - program::{account, protocol::saber}, - vault::{Vault, VaultStrategy}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn crank1(vault: &Vault, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _funding_account, - _vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - iou_token_reward_custody, - farm_program, - vault_stake_info, - mint_wrapper, - mint_wrapper_program, - minter, - iou_token_mint, - iou_fees_account, - quarry, - rewarder, - zero_id - ] = accounts - { - // validate accounts - if vault_authority.key != &vault.vault_authority { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - if let VaultStrategy::StakeLpCompoundRewards { - farm_id: farm_id_key, - token_b_reward_custody: token_b_reward_custody_key, - vault_stake_info: vault_stake_info_key, - .. - } = vault.strategy - { - if &farm_id_key != quarry.key { - msg!("Error: Invalid farm id"); - return Err(ProgramError::InvalidArgument); - } - if &vault_stake_info_key != vault_stake_info.key { - msg!("Error: Invalid Vault Stake Info account"); - return Err(ProgramError::InvalidArgument); - } - if token_b_reward_custody_key != Some(*iou_token_reward_custody.key) { - msg!("Error: Invalid custody accounts"); - return Err(ProgramError::InvalidArgument); - } - } else { - msg!("Error: Vault strategy mismatch"); - return Err(ProgramError::InvalidArgument); - } - - let mut vault_info = VaultInfo::new(vault_info_account); - common::check_min_crank_interval(&vault_info)?; - - // harvest - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - - let initial_iou_token_reward_balance = - account::get_token_balance(iou_token_reward_custody)?; - - msg!("Claim rewards"); - saber::claim_rewards_with_seeds( - &[ - vault_authority.clone(), - iou_token_reward_custody.clone(), - farm_program.clone(), - spl_token_program.clone(), - zero_id.clone(), - vault_stake_info.clone(), - rewarder.clone(), - minter.clone(), - mint_wrapper.clone(), - mint_wrapper_program.clone(), - iou_token_mint.clone(), - iou_fees_account.clone(), - quarry.clone(), - ], - seeds, - )?; - // calculate rewards - let iou_token_rewards = account::get_balance_increase( - iou_token_reward_custody, - initial_iou_token_reward_balance, - )?; - - msg!("Rewards received. iou_token_rewards: {}", iou_token_rewards); - - // update Vault stats - msg!("Update Vault stats",); - vault_info.add_rewards(0, iou_token_rewards)?; - vault_info.update_crank_time()?; - vault_info.set_crank_step(1)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/vaults/src/strategies/sbr_stake_lp_compound/crank2.rs b/farms/vaults/src/strategies/sbr_stake_lp_compound/crank2.rs deleted file mode 100644 index 5f021c1ecf5..00000000000 --- a/farms/vaults/src/strategies/sbr_stake_lp_compound/crank2.rs +++ /dev/null @@ -1,139 +0,0 @@ -//! Crank step 2 instruction handler - -use { - crate::{strategies::common, vault_info::VaultInfo}, - solana_farm_sdk::{ - id::zero, - math, - program::{account, pda, protocol::saber}, - vault::{Vault, VaultStrategy}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn crank2(vault: &Vault, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _funding_account, - _vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - sbr_token_reward_custody, - iou_token_reward_custody, - fees_account_sbr, - redeemer, - redeemer_program, - sbr_token_mint, - iou_token_mint, - sbr_vault, - mint_proxy_program, - mint_proxy_authority, - mint_proxy_state, - minter_info - ] = accounts - { - // validate accounts - if vault_authority.key != &vault.vault_authority { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - if let VaultStrategy::StakeLpCompoundRewards { - token_a_reward_custody: sbr_token_reward_custody_key, - token_b_reward_custody: iou_token_reward_custody_key, - .. - } = vault.strategy - { - if &sbr_token_reward_custody_key != sbr_token_reward_custody.key - || &iou_token_reward_custody_key.or(Some(zero::id())).unwrap() - != iou_token_reward_custody.key - { - msg!("Error: Invalid custody accounts"); - return Err(ProgramError::InvalidArgument); - } - } else { - msg!("Error: Vault strategy mismatch"); - return Err(ProgramError::InvalidArgument); - } - - if Some(*fees_account_sbr.key) != vault.fees_account_a { - msg!("Error: Invalid fee account"); - return Err(ProgramError::InvalidArgument); - } - - let mut vault_info = VaultInfo::new(vault_info_account); - common::check_min_crank_interval(&vault_info)?; - - // redeem rewards - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - - let initial_sbr_tokens_balance = account::get_token_balance(sbr_token_reward_custody)?; - let iou_tokens_balance = account::get_token_balance(iou_token_reward_custody)?; - - msg!("Redeem rewards: {}", iou_tokens_balance); - if iou_tokens_balance < 10 { - msg!("Nothing to do: Not enough tokens to redeem"); - return Ok(()); - } - saber::redeem_rewards_with_seeds( - &[ - vault_authority.clone(), - iou_token_reward_custody.clone(), - sbr_token_reward_custody.clone(), - spl_token_program.clone(), - redeemer.clone(), - redeemer_program.clone(), - sbr_token_mint.clone(), - iou_token_mint.clone(), - sbr_vault.clone(), - mint_proxy_program.clone(), - mint_proxy_authority.clone(), - mint_proxy_state.clone(), - minter_info.clone(), - ], - seeds, - )?; - let _ = account::check_tokens_received( - sbr_token_reward_custody, - initial_sbr_tokens_balance, - iou_tokens_balance, - )?; - - // take fees - let fee = vault_info.get_fee()?; - if fee < 0.0 || fee > 1.0 { - msg!("Error: Invalid fee. fee: {}", fee); - return Err(ProgramError::Custom(260)); - } - let mut sbr_fees = math::checked_as_u64(iou_tokens_balance as f64 * fee)?; - if sbr_fees == 0 && iou_tokens_balance > 0 { - sbr_fees = 1; - } - - msg!("Apply fees. fee: {}, sbr_fees: {}", fee, sbr_fees); - pda::transfer_tokens_with_seeds( - sbr_token_reward_custody, - fees_account_sbr, - vault_authority, - seeds, - sbr_fees, - )?; - - // update Vault stats - msg!("Update Vault stats",); - vault_info.add_rewards(iou_tokens_balance, 0)?; - vault_info.update_crank_time()?; - vault_info.set_crank_step(2)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/vaults/src/strategies/sbr_stake_lp_compound/crank3.rs b/farms/vaults/src/strategies/sbr_stake_lp_compound/crank3.rs deleted file mode 100644 index 5680178e492..00000000000 --- a/farms/vaults/src/strategies/sbr_stake_lp_compound/crank3.rs +++ /dev/null @@ -1,178 +0,0 @@ -//! Crank step 3 instruction handler - -use { - crate::{strategies::common, vault_info::VaultInfo}, - solana_farm_sdk::{ - id::zero, - program, - program::{ - account, - protocol::{raydium, saber}, - }, - vault::{Vault, VaultStrategy}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn crank3(vault: &Vault, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _funding_account, - _vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - sbr_token_custody, - usdc_token_custody, - wrapped_token_custody, - usdc_token_mint, - wrapped_token_mint, - wrapped_token_vault, - decimal_wrapper, - decimal_wrapper_program, - pool_program_id, - pool_coin_token_account, - pool_pc_token_account, - amm_id, - amm_authority, - amm_open_orders, - amm_target, - serum_market, - serum_program_id, - serum_coin_vault_account, - serum_pc_vault_account, - serum_vault_signer, - serum_bids, - serum_asks, - serum_event_queue, - sysvar_account - ] = accounts - { - // validate accounts - if vault_authority.key != &vault.vault_authority { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - if let VaultStrategy::StakeLpCompoundRewards { - token_a_custody: usdc_token_custody_key, - token_b_custody: wrapped_token_custody_key, - token_a_reward_custody: sbr_token_custody_key, - .. - } = vault.strategy - { - if amm_id.key != &saber::saber_to_usdc_amm::id(){ - msg!("Error: Invalid pool id"); - return Err(ProgramError::InvalidArgument); - } - if &usdc_token_custody_key != usdc_token_custody.key - || &wrapped_token_custody_key.or(Some(zero::id())).unwrap() - != wrapped_token_custody.key - || &sbr_token_custody_key != sbr_token_custody.key - { - msg!("Error: Invalid custody accounts"); - return Err(ProgramError::InvalidArgument); - } - } else { - msg!("Error: Vault strategy mismatch"); - return Err(ProgramError::InvalidArgument); - } - - if !program::is_last_instruction(sysvar_account)? { - msg!("Error: Crank3 must be the last instruction in the transaction"); - return Err(ProgramError::InvalidArgument); - } - - let mut vault_info = VaultInfo::new(vault_info_account); - common::check_min_crank_interval(&vault_info)?; - vault_info.update_crank_time()?; - vault_info.set_crank_step(3)?; - - // read balances - let sbr_token_balance = account::get_token_balance(sbr_token_custody)?; - let usdc_token_balance = account::get_token_balance(usdc_token_custody)?; - msg!("SBR rewards balance: {}", sbr_token_balance); - if sbr_token_balance < 10 { - msg!("Nothing to do: Not enough SBR tokens to swap"); - return Ok(()); - } - - // move rewards to token custodies - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - - msg!("Swap SBR to USDC"); - raydium::swap_with_seeds( - &[ - vault_authority.clone(), - sbr_token_custody.clone(), - usdc_token_custody.clone(), - pool_program_id.clone(), - pool_coin_token_account.clone(), - pool_pc_token_account.clone(), - spl_token_program.clone(), - amm_id.clone(), - amm_authority.clone(), - amm_open_orders.clone(), - amm_target.clone(), - serum_market.clone(), - serum_program_id.clone(), - serum_bids.clone(), - serum_asks.clone(), - serum_event_queue.clone(), - serum_coin_vault_account.clone(), - serum_pc_vault_account.clone(), - serum_vault_signer.clone(), - ], - seeds, - sbr_token_balance, - 1, - )?; - let _ = - account::check_tokens_spent(sbr_token_custody, sbr_token_balance, sbr_token_balance)?; - let usdc_tokens_received = - account::check_tokens_received(usdc_token_custody, usdc_token_balance, 1)?; - - msg!("USDC tokens received: {}", usdc_tokens_received); - - if wrapped_token_mint.key != &zero::id() { - msg!("Wrap USDC tokens"); - let initial_usdc_token_balance = account::get_token_balance(usdc_token_custody)?; - let initial_wrapped_token_balance = account::get_token_balance(wrapped_token_custody)?; - - let usdc_decimals = account::get_token_decimals(&usdc_token_mint)?; - let wrapped_decimals = account::get_token_decimals(&wrapped_token_mint)?; - - saber::wrap_token_with_seeds( - decimal_wrapper, - wrapped_token_mint, - wrapped_token_vault, - vault_authority, - usdc_token_custody, - wrapped_token_custody, - decimal_wrapper_program.key, - seeds, - initial_usdc_token_balance, - )?; - - account::check_tokens_received( - wrapped_token_custody, - initial_wrapped_token_balance, - account::to_amount_with_new_decimals( - initial_usdc_token_balance, - usdc_decimals, - wrapped_decimals, - )?, - )?; - } - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/vaults/src/strategies/sbr_stake_lp_compound/crank4.rs b/farms/vaults/src/strategies/sbr_stake_lp_compound/crank4.rs deleted file mode 100644 index 6aab06e554e..00000000000 --- a/farms/vaults/src/strategies/sbr_stake_lp_compound/crank4.rs +++ /dev/null @@ -1,136 +0,0 @@ -//! Crank step 4 instruction handler - -use { - crate::{strategies::common, vault_info::VaultInfo}, - solana_farm_sdk::{ - program::{account, protocol::saber}, - vault::{Vault, VaultStrategy}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn crank4(vault: &Vault, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _funding_account, - _vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - token_a_custody, - token_b_custody, - lp_token_custody, - pool_program_id, - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - clock_program, - swap_account, - swap_authority - ] = accounts - { - // validate accounts - if vault_authority.key != &vault.vault_authority { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - if let VaultStrategy::StakeLpCompoundRewards { - pool_id: pool_id_key, - token_a_custody: token_a_custody_key, - token_b_custody: token_b_custody_key, - lp_token_custody: lp_token_custody_key, - .. - } = vault.strategy - { - if &pool_id_key != swap_account.key { - msg!("Error: Invalid pool id"); - return Err(ProgramError::InvalidArgument); - } - if vault.fees_account_b.is_none() - || (token_a_custody.key != &token_a_custody_key - && (token_b_custody_key.is_none() - || token_a_custody.key != &token_b_custody_key.unwrap()) - && token_a_custody.key != &vault.fees_account_b.unwrap()) - || (token_b_custody.key != &token_a_custody_key - && (token_b_custody_key.is_none() - || token_b_custody.key != &token_b_custody_key.unwrap()) - && token_b_custody.key != &vault.fees_account_b.unwrap()) - || &lp_token_custody_key != lp_token_custody.key - { - msg!("Error: Invalid custody accounts"); - return Err(ProgramError::InvalidArgument); - } - } else { - msg!("Error: Vault strategy mismatch"); - return Err(ProgramError::InvalidArgument); - } - - let mut vault_info = VaultInfo::new(vault_info_account); - common::check_min_crank_interval(&vault_info)?; - - // read balances - let token_a_balance = account::get_token_balance(token_a_custody)?; - let token_b_balance = account::get_token_balance(token_b_custody)?; - let lp_token_balance = account::get_token_balance(lp_token_custody)?; - msg!( - "Read balances. token_a_balance: {}, token_b_balance: {}", - token_a_balance, - token_b_balance - ); - if token_a_balance < 10 && token_b_balance < 10 { - msg!("Nothing to do: Not enough tokens to deposit"); - return Ok(()); - } - - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - - msg!("Deposit tokens into the pool"); - saber::add_liquidity_with_seeds( - &[ - vault_authority.clone(), - token_a_custody.clone(), - token_b_custody.clone(), - lp_token_custody.clone(), - pool_program_id.clone(), - pool_token_a_account.clone(), - pool_token_b_account.clone(), - lp_token_mint.clone(), - spl_token_program.clone(), - clock_program.clone(), - swap_account.clone(), - swap_authority.clone(), - ], - seeds, - token_a_balance, - token_b_balance, - )?; - - // check amounts spent and received - let tokens_a_spent = - account::check_tokens_spent(token_a_custody, token_a_balance, token_a_balance)?; - let tokens_b_spent = - account::check_tokens_spent(token_b_custody, token_b_balance, token_b_balance)?; - let lp_tokens_received = - account::check_tokens_received(lp_token_custody, lp_token_balance, 1)?; - - // update Vault stats - msg!( - "Update Vault stats. tokens_a_spent {}, tokens_b_spent {}, lp_tokens_received {}", - tokens_a_spent, - tokens_b_spent, - lp_tokens_received - ); - vault_info.add_liquidity(tokens_a_spent, tokens_b_spent)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/vaults/src/strategies/sbr_stake_lp_compound/crank5.rs b/farms/vaults/src/strategies/sbr_stake_lp_compound/crank5.rs deleted file mode 100644 index ea363e48e7d..00000000000 --- a/farms/vaults/src/strategies/sbr_stake_lp_compound/crank5.rs +++ /dev/null @@ -1,99 +0,0 @@ -//! Crank step 5 instruction handler - -use { - crate::{strategies::common, vault_info::VaultInfo}, - solana_farm_sdk::{ - program::{account, protocol::saber}, - vault::{Vault, VaultStrategy}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -pub fn crank5(vault: &Vault, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _funding_account, - _vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - lp_token_custody, - farm_program, - vault_stake_info, - vault_miner_account, - quarry, - rewarder - ] = accounts - { - // validate accounts - if vault_authority.key != &vault.vault_authority || - !account::check_token_account_owner(vault_miner_account, vault_stake_info.key)? - { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - if let VaultStrategy::StakeLpCompoundRewards { - farm_id: farm_id_key, - lp_token_custody: lp_token_custody_key, - vault_stake_info: vault_stake_info_key, - .. - } = vault.strategy - { - if &farm_id_key != quarry.key { - msg!("Error: Invalid farm id"); - return Err(ProgramError::InvalidArgument); - } - if &vault_stake_info_key != vault_stake_info.key { - msg!("Error: Invalid Vault Stake Info account"); - return Err(ProgramError::InvalidArgument); - } - if &lp_token_custody_key != lp_token_custody.key { - msg!("Error: Invalid custody accounts"); - return Err(ProgramError::InvalidArgument); - } - } else { - msg!("Error: Vault strategy mismatch"); - return Err(ProgramError::InvalidArgument); - } - - let vault_info = VaultInfo::new(vault_info_account); - common::check_min_crank_interval(&vault_info)?; - - // read balances - let lp_token_balance = account::get_token_balance(lp_token_custody)?; - msg!("Read balances. lp_token_balance: {}", lp_token_balance,); - if lp_token_balance == 0 { - msg!("Nothing to do: Not enough LP tokens to stake"); - return Ok(()); - } - - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - - msg!("Stake LP tokens"); - saber::stake_with_seeds( - &[ - vault_authority.clone(), - lp_token_custody.clone(), - farm_program.clone(), - spl_token_program.clone(), - vault_stake_info.clone(), - vault_miner_account.clone(), - quarry.clone(), - rewarder.clone(), - ], - seeds, - lp_token_balance, - )?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } -} diff --git a/farms/vaults/src/strategies/sbr_stake_lp_compound/features.rs b/farms/vaults/src/strategies/sbr_stake_lp_compound/features.rs deleted file mode 100644 index e743f654685..00000000000 --- a/farms/vaults/src/strategies/sbr_stake_lp_compound/features.rs +++ /dev/null @@ -1,85 +0,0 @@ -//! Feature toggling instructions handlers - -use { - crate::{traits::Features, vault_info::VaultInfo}, - solana_farm_sdk::{instruction::vault::VaultInstruction, vault::Vault}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl Features for VaultInstruction { - fn set_min_crank_interval( - _vault: &Vault, - vault_info: &mut VaultInfo, - _accounts: &[AccountInfo], - min_crank_interval_sec: u64, - ) -> ProgramResult { - msg!("set_min_crank_interval: {}", min_crank_interval_sec); - vault_info.set_min_crank_interval(min_crank_interval_sec) - } - - fn set_fee( - _vault: &Vault, - vault_info: &mut VaultInfo, - _accounts: &[AccountInfo], - fee: f64, - ) -> ProgramResult { - msg!("set_fee: {}", fee); - if fee < 0.0 || fee > 1.0 { - msg!("Error: Invalid new value for fee"); - return Err(ProgramError::InvalidArgument); - } - vault_info.set_fee(fee) - } - - fn set_external_fee( - _vault: &Vault, - vault_info: &mut VaultInfo, - _accounts: &[AccountInfo], - external_fee: f64, - ) -> ProgramResult { - msg!("external_fee: {}", external_fee); - if external_fee < 0.0 || external_fee > 1.0 { - msg!("Error: Invalid new value for external_fee"); - return Err(ProgramError::InvalidArgument); - } - vault_info.set_external_fee(external_fee) - } - - fn enable_deposits( - _vault: &Vault, - vault_info: &mut VaultInfo, - _accounts: &[AccountInfo], - ) -> ProgramResult { - msg!("enable_deposits"); - vault_info.enable_deposits() - } - - fn disable_deposits( - _vault: &Vault, - vault_info: &mut VaultInfo, - _accounts: &[AccountInfo], - ) -> ProgramResult { - msg!("disable_deposits"); - vault_info.disable_deposits() - } - - fn enable_withdrawals( - _vault: &Vault, - vault_info: &mut VaultInfo, - _accounts: &[AccountInfo], - ) -> ProgramResult { - msg!("enable_withdrawals"); - vault_info.enable_withdrawals() - } - - fn disable_withdrawals( - _vault: &Vault, - vault_info: &mut VaultInfo, - _accounts: &[AccountInfo], - ) -> ProgramResult { - msg!("disable_withdrawals"); - vault_info.disable_withdrawals() - } -} diff --git a/farms/vaults/src/strategies/sbr_stake_lp_compound/init.rs b/farms/vaults/src/strategies/sbr_stake_lp_compound/init.rs deleted file mode 100644 index 36d941c4acf..00000000000 --- a/farms/vaults/src/strategies/sbr_stake_lp_compound/init.rs +++ /dev/null @@ -1,228 +0,0 @@ -//! Vault Init instruction handler - -use { - crate::{traits::Init, vault_info::VaultInfo}, - solana_farm_sdk::{ - id::zero, - instruction::vault::VaultInstruction, - program::{account, pda, protocol::saber}, - token::Token, - traits::Packed, - vault::Vault, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl Init for VaultInstruction { - fn init(vault: &Vault, accounts: &[AccountInfo], step: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - admin_account, - _vault_metadata, - vault_info_account, - _multisig_account, - vault_authority, - vault_program, - _system_program, - _spl_token_program, - _associated_token_program, - rent_program, - farm_program, - vault_token_mint, - vault_token_ref, - vault_stake_info, - vault_miner_account, - fees_account_a, - fees_account_b, - usdc_token_custody, - wrapped_token_custody, - lp_token_custody, - usdc_token_mint, - non_usdc_token_mint, - wrapped_token_mint, - lp_token_mint, - sbr_token_reward_custody, - iou_token_reward_custody, - sbr_token_mint, - iou_token_mint, - quarry, - rewarder - ] = accounts - { - // validate accounts - if vault_authority.key != &vault.vault_authority - || vault_token_ref.key != &vault.vault_token_ref - || vault_program.key != &vault.vault_program_id - { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - - if step <= 1 { - // init vault authority account - msg!("Init vault authority"); - pda::init_system_account( - admin_account, - vault_authority, - &vault.vault_program_id, - &vault.vault_program_id, - &[b"vault_authority", vault.name.as_bytes()], - 0, - )?; - - // init vault info account - msg!("Init vault info"); - pda::init_system_account( - admin_account, - vault_info_account, - &vault.vault_program_id, - &vault.vault_program_id, - &[b"info_account", vault.name.as_bytes()], - VaultInfo::LEN, - )?; - let mut vault_info = VaultInfo::new(vault_info_account); - vault_info.init(&vault.name)?; - - // init vault token mint - msg!("Init vault token mint"); - let vault_token = Token::unpack(&vault_token_ref.try_borrow_data()?)?; - if vault_token_mint.key != &vault_token.mint { - msg!("Error: Invalid Vault token mint"); - return Err(ProgramError::InvalidArgument); - } - pda::init_mint( - admin_account, - vault_token_mint, - vault_authority, - rent_program, - &vault.vault_program_id, - &[b"vault_token_mint", vault.name.as_bytes()], - vault_token.decimals, - )?; - - // init stake info - msg!("Init vault miner"); - pda::init_associated_token_account( - admin_account, - vault_stake_info, - vault_miner_account, - lp_token_mint, - rent_program, - )?; - - if account::is_empty(vault_stake_info)? { - msg!("Init stake info"); - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - saber::user_init_with_seeds( - &[ - vault_authority.clone(), - admin_account.clone(), - farm_program.clone(), - lp_token_mint.clone(), - vault_stake_info.clone(), - vault_miner_account.clone(), - quarry.clone(), - rewarder.clone(), - ], - seeds, - )?; - } - } - - if step == 0 || step == 2 { - // init token accounts - msg!("Init fees account a"); - pda::init_token_account( - admin_account, - fees_account_a, - sbr_token_mint, - vault_authority, - rent_program, - &vault.vault_program_id, - &[b"fees_account_a", vault.name.as_bytes()], - )?; - - msg!("Init fees account b"); - pda::init_token_account( - admin_account, - fees_account_b, - non_usdc_token_mint, - vault_authority, - rent_program, - &vault.vault_program_id, - &[b"fees_account_b", vault.name.as_bytes()], - )?; - - msg!("Init lp token custody account"); - pda::init_token_account( - admin_account, - lp_token_custody, - lp_token_mint, - vault_authority, - rent_program, - &vault.vault_program_id, - &[b"lp_token_custody", vault.name.as_bytes()], - )?; - - msg!("Init USDC token custody account"); - pda::init_token_account( - admin_account, - usdc_token_custody, - usdc_token_mint, - vault_authority, - rent_program, - &vault.vault_program_id, - &[b"token_a_custody", vault.name.as_bytes()], - )?; - - if wrapped_token_custody.key != &zero::id() { - msg!("Init wrapped USDC token custody account"); - pda::init_token_account( - admin_account, - wrapped_token_custody, - wrapped_token_mint, - vault_authority, - rent_program, - &vault.vault_program_id, - &[b"token_b_custody", vault.name.as_bytes()], - )?; - } - - msg!("Init SBR token reward custody account"); - pda::init_token_account( - admin_account, - sbr_token_reward_custody, - sbr_token_mint, - vault_authority, - rent_program, - &vault.vault_program_id, - &[b"token_a_reward_custody", vault.name.as_bytes()], - )?; - - if *iou_token_reward_custody.key != zero::id() { - msg!("Init IOU token reward custody account"); - pda::init_token_account( - admin_account, - iou_token_reward_custody, - iou_token_mint, - vault_authority, - rent_program, - &vault.vault_program_id, - &[b"token_b_reward_custody", vault.name.as_bytes()], - )?; - } - } - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } - } -} diff --git a/farms/vaults/src/strategies/sbr_stake_lp_compound/lock_liquidity.rs b/farms/vaults/src/strategies/sbr_stake_lp_compound/lock_liquidity.rs deleted file mode 100644 index 40bb83e90ee..00000000000 --- a/farms/vaults/src/strategies/sbr_stake_lp_compound/lock_liquidity.rs +++ /dev/null @@ -1,176 +0,0 @@ -//! Lock Liquidity in the Vault instruction handler - -use { - crate::{traits::LockLiquidity, user_info::UserInfo, vault_info::VaultInfo}, - solana_farm_sdk::{ - instruction::vault::VaultInstruction, - math, - program::{account, pda, protocol::saber}, - vault::{Vault, VaultStrategy}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl LockLiquidity for VaultInstruction { - fn lock_liquidity(vault: &Vault, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - _vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - vault_token_mint, - user_info_account, - user_vt_token_account, - lp_token_custody, - farm_program, - vault_stake_info, - vault_miner_account, - quarry, - rewarder - ] = accounts - { - // validate accounts - if vault_authority.key != &vault.vault_authority - || !account::check_token_account_owner(vault_miner_account, vault_stake_info.key)? - { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - if !user_account.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - if !account::check_token_account_owner(user_vt_token_account, user_account.key)? { - msg!("Error: Invalid VT token account owner"); - return Err(ProgramError::IllegalOwner); - } - - if let VaultStrategy::StakeLpCompoundRewards { - farm_id: farm_id_key, - lp_token_custody: lp_token_custody_key, - vault_stake_info: vault_stake_info_key, - .. - } = vault.strategy - { - if &farm_id_key != quarry.key { - msg!("Error: Invalid farm id"); - return Err(ProgramError::InvalidArgument); - } - if &vault_stake_info_key != vault_stake_info.key { - msg!("Error: Invalid Vault Stake Info account"); - return Err(ProgramError::InvalidArgument); - } - if &lp_token_custody_key != lp_token_custody.key { - msg!("Error: Invalid custody accounts"); - return Err(ProgramError::InvalidArgument); - } - } else { - msg!("Error: Vault strategy mismatch"); - return Err(ProgramError::InvalidArgument); - } - - if !UserInfo::validate_account(vault, user_info_account, user_account.key) { - msg!("Error: Invalid user info account"); - return Err(ProgramError::Custom(140)); - } - - let vault_info = VaultInfo::new(vault_info_account); - if !vault_info.is_deposit_allowed()? { - msg!("Error: Deposits are not allowed for this Vault"); - return Err(ProgramError::Custom(220)); - } - - // check lp balance - let mut user_info = UserInfo::new(user_info_account); - let lp_tokens_debt = user_info.get_lp_tokens_debt()?; - msg!("Read balances. lp_tokens_debt: {}", lp_tokens_debt); - - let lp_stake_amount = if amount > 0 { - if lp_tokens_debt < amount { - msg!("Error: Insufficient funds"); - return Err(ProgramError::InsufficientFunds); - } - amount - } else { - lp_tokens_debt - }; - if lp_stake_amount == 0 { - msg!("Error: Zero balance. Forgot to deposit funds?"); - return Err(ProgramError::InsufficientFunds); - } - - let initial_lp_custody_balance = account::get_token_balance(lp_token_custody)?; - - // Stake LP tokens - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - - msg!("Stake LP tokens. lp_stake_amount: {}", lp_stake_amount); - let stake_balance = saber::get_stake_account_balance(vault_stake_info)?; - - saber::stake_with_seeds( - &[ - vault_authority.clone(), - lp_token_custody.clone(), - farm_program.clone(), - spl_token_program.clone(), - vault_stake_info.clone(), - vault_miner_account.clone(), - quarry.clone(), - rewarder.clone(), - ], - seeds, - lp_stake_amount, - )?; - let _ = account::check_tokens_spent( - lp_token_custody, - initial_lp_custody_balance, - lp_stake_amount, - )?; - - // update user stats - msg!("Update user stats"); - user_info.remove_lp_tokens_debt(lp_stake_amount)?; - - // compute Vault tokens to mint - let vt_supply_amount = account::get_token_supply(vault_token_mint)?; - let vt_to_mint = if vt_supply_amount == 0 || stake_balance == 0 { - lp_stake_amount - } else { - math::checked_as_u64(math::checked_div( - math::checked_mul(lp_stake_amount as u128, vt_supply_amount as u128)?, - stake_balance as u128 - )?)? - }; - - // mint vault tokens to user - msg!( - "Mint Vault tokens to the user. vt_to_mint: {}, vt_supply_amount: {}, stake_balance: {}", - vt_to_mint, vt_supply_amount, - stake_balance - ); - if vt_to_mint == 0 { - msg!("Error: Add liquidity instruction didn't result in Vault tokens mint"); - return Err(ProgramError::Custom(170)); - } - pda::mint_to_with_seeds( - user_vt_token_account, - vault_token_mint, - vault_authority, - seeds, - vt_to_mint, - )?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } - } -} diff --git a/farms/vaults/src/strategies/sbr_stake_lp_compound/mod.rs b/farms/vaults/src/strategies/sbr_stake_lp_compound/mod.rs deleted file mode 100644 index 760eed89b81..00000000000 --- a/farms/vaults/src/strategies/sbr_stake_lp_compound/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -pub mod add_liquidity; -pub mod crank; -mod crank1; -mod crank2; -mod crank3; -mod crank4; -mod crank5; -pub mod features; -pub mod init; -pub mod lock_liquidity; -pub mod params; -pub mod remove_liquidity; -pub mod remove_multisig; -pub mod set_admin_signers; -pub mod shutdown; -pub mod unlock_liquidity; -pub mod user_init; -pub mod withdraw_fees; diff --git a/farms/vaults/src/strategies/sbr_stake_lp_compound/params.rs b/farms/vaults/src/strategies/sbr_stake_lp_compound/params.rs deleted file mode 100644 index 11e744b5763..00000000000 --- a/farms/vaults/src/strategies/sbr_stake_lp_compound/params.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! Vault related parameters and accounts - -use crate::{traits::VaultParams, vault_info::VaultInfo}; - -impl VaultParams for VaultInfo<'_, '_> { - fn default_min_crank_interval() -> u64 { - 60 - } - - fn default_fee() -> f64 { - 0.003 - } - - fn default_external_fee() -> f64 { - 0.0025 - } -} diff --git a/farms/vaults/src/strategies/sbr_stake_lp_compound/remove_liquidity.rs b/farms/vaults/src/strategies/sbr_stake_lp_compound/remove_liquidity.rs deleted file mode 100644 index 9978c0736a5..00000000000 --- a/farms/vaults/src/strategies/sbr_stake_lp_compound/remove_liquidity.rs +++ /dev/null @@ -1,251 +0,0 @@ -//! Remove Liquidity from the Vault instruction handler - -use { - crate::{traits::RemoveLiquidity, user_info::UserInfo, vault_info::VaultInfo}, - solana_farm_sdk::{ - instruction::vault::VaultInstruction, - math, - program::{account, protocol::saber}, - vault::{Vault, VaultStrategy}, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - pubkey::Pubkey, - }, -}; - -impl RemoveLiquidity for VaultInstruction { - fn remove_liquidity(vault: &Vault, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - user_account, - _vault_metadata, - vault_info_account, - vault_authority, - spl_token_program, - vault_token_mint, - user_info_account, - user_token_a_account, - user_token_b_account, - user_vt_token_account, - lp_token_custody, - pool_program_id, - pool_token_a_account, - pool_token_b_account, - lp_token_mint, - swap_account, - swap_authority, - fees_account_a, - fees_account_b, - farm_program, - vault_stake_info, - vault_miner_account, - quarry, - rewarder - ] = accounts - { - // validate accounts - if vault_authority.key != &vault.vault_authority - || !account::check_token_account_owner(vault_miner_account, vault_stake_info.key)? - { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - if !user_account.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - if !account::check_token_account_owner(user_token_a_account, user_account.key)? - || !account::check_token_account_owner(user_token_b_account, user_account.key)? - || !account::check_token_account_owner(user_vt_token_account, user_account.key)? - { - msg!("Error: Invalid token account owner"); - return Err(ProgramError::IllegalOwner); - } - if let VaultStrategy::StakeLpCompoundRewards { - pool_id: pool_id_key, - farm_id: farm_id_key, - lp_token_custody: lp_token_custody_key, - vault_stake_info: vault_stake_info_key, - .. - } = vault.strategy - { - if &pool_id_key != swap_account.key { - msg!("Error: Invalid pool id"); - return Err(ProgramError::InvalidArgument); - } - if &farm_id_key != quarry.key { - msg!("Error: Invalid farm id"); - return Err(ProgramError::InvalidArgument); - } - if &vault_stake_info_key != vault_stake_info.key { - msg!("Error: Invalid Vault Stake Info account"); - return Err(ProgramError::InvalidArgument); - } - if &lp_token_custody_key != lp_token_custody.key { - msg!("Error: Invalid custody accounts"); - return Err(ProgramError::InvalidArgument); - } - } else { - msg!("Error: Vault strategy mismatch"); - return Err(ProgramError::InvalidArgument); - } - if !UserInfo::validate_account(vault, user_info_account, user_account.key) { - msg!("Error: Invalid user info account"); - return Err(ProgramError::Custom(140)); - } - - let mut vault_info = VaultInfo::new(vault_info_account); - if !vault_info.is_withdrawal_allowed()? { - msg!("Error: Withdrawals are not allowed for this Vault"); - return Err(ProgramError::Custom(230)); - } - - // calculate amounts to unstake - let vt_remove_amount = if amount > 0 { - amount - } else { - account::get_token_balance(user_vt_token_account)? - }; - let vt_supply_amount = account::get_token_supply(vault_token_mint)?; - let stake_balance = saber::get_stake_account_balance(vault_stake_info)?; - - msg!( - "Read balances. vt_remove_amount: {}, vt_supply_amount: {}, stake_balance: {}", - vt_remove_amount, - vt_supply_amount, - stake_balance - ); - if vt_remove_amount == 0 || vt_supply_amount == 0 || stake_balance == 0 { - msg!("Error: Zero balance"); - return Err(ProgramError::InsufficientFunds); - } - let lp_remove_amount = math::checked_as_u64(math::checked_div( - math::checked_mul(stake_balance as u128, vt_remove_amount as u128)?, - vt_supply_amount as u128, - )?)?; - - // unstake - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - - let initial_lp_tokens_balance = account::get_token_balance(lp_token_custody)?; - - msg!( - "Unstake user's lp tokens. amount: {}, lp_remove_amount: {}", - amount, - lp_remove_amount - ); - saber::unstake_with_seeds( - &[ - vault_authority.clone(), - lp_token_custody.clone(), - farm_program.clone(), - spl_token_program.clone(), - vault_stake_info.clone(), - vault_miner_account.clone(), - quarry.clone(), - rewarder.clone(), - ], - seeds, - lp_remove_amount, - )?; - let _ = account::check_tokens_received( - lp_token_custody, - initial_lp_tokens_balance, - lp_remove_amount, - )?; - - // burn vault tokens - msg!( - "Burn Vault tokens from the user. vt_remove_amount: {}", - vt_remove_amount - ); - let key = Pubkey::create_program_address( - &[ - b"vault_token_mint", - vault.name.as_bytes(), - &[vault.vault_token_bump], - ], - &vault.vault_program_id, - )?; - if vault_token_mint.key != &key { - msg!("Error: Invalid Vault token mint"); - return Err(ProgramError::InvalidSeeds); - } - account::burn_tokens( - user_vt_token_account, - vault_token_mint, - user_account, - vt_remove_amount, - )?; - - // remove liquidity from the pool - let initial_token_a_user_balance = account::get_token_balance(user_token_a_account)?; - let initial_token_b_user_balance = account::get_token_balance(user_token_b_account)?; - - msg!( - "Remove liquidity from the pool. lp_remove_amount: {}", - lp_remove_amount - ); - saber::remove_liquidity_with_seeds( - &[ - vault_authority.clone(), - user_token_a_account.clone(), - user_token_b_account.clone(), - lp_token_custody.clone(), - pool_program_id.clone(), - pool_token_a_account.clone(), - pool_token_b_account.clone(), - lp_token_mint.clone(), - spl_token_program.clone(), - swap_account.clone(), - swap_authority.clone(), - fees_account_a.clone(), - fees_account_b.clone(), - ], - seeds, - lp_remove_amount, - )?; - - // check tokens received - let tokens_a_received = - account::get_balance_increase(user_token_a_account, initial_token_a_user_balance)?; - let tokens_b_received = - account::get_balance_increase(user_token_b_account, initial_token_b_user_balance)?; - if tokens_a_received == 0 && tokens_b_received == 0 { - msg!("Error: Remove liquidity instruction didn't result in any of the tokens received"); - return Err(ProgramError::Custom(190)); - } - if initial_lp_tokens_balance != account::get_token_balance(lp_token_custody)? { - msg!( - "Error: Remove liquidity instruction didn't result in expected amount of LP tokens spent" - ); - return Err(ProgramError::Custom(165)); - } - - // send tokens to the user - msg!( - "Update stats. tokens_a_received: {}, tokens_b_received: {}", - tokens_a_received, - tokens_b_received - ); - - // update user stats - msg!("Update user stats"); - let mut user_info = UserInfo::new(user_info_account); - user_info.remove_liquidity(tokens_a_received, tokens_b_received)?; - - // update vault stats - msg!("Update Vault stats"); - vault_info.remove_liquidity(tokens_a_received, tokens_b_received)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } - } -} diff --git a/farms/vaults/src/strategies/sbr_stake_lp_compound/remove_multisig.rs b/farms/vaults/src/strategies/sbr_stake_lp_compound/remove_multisig.rs deleted file mode 100644 index 8bd3ca63446..00000000000 --- a/farms/vaults/src/strategies/sbr_stake_lp_compound/remove_multisig.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! Vault RemoveMultisig instruction handler - -use { - crate::traits::RemoveMultisig, - solana_farm_sdk::{instruction::vault::VaultInstruction, program::account, vault::Vault}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl RemoveMultisig for VaultInstruction { - fn remove_multisig(vault: &Vault, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - admin_account, - _vault_metadata, - _vault_info_account, - _active_multisig_account, - vault_multisig_account - ] = accounts - { - msg!("Close multisig account"); - account::close_system_account(admin_account, vault_multisig_account, &vault.vault_program_id)?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } - } -} diff --git a/farms/vaults/src/strategies/sbr_stake_lp_compound/set_admin_signers.rs b/farms/vaults/src/strategies/sbr_stake_lp_compound/set_admin_signers.rs deleted file mode 100644 index dbbae0dab56..00000000000 --- a/farms/vaults/src/strategies/sbr_stake_lp_compound/set_admin_signers.rs +++ /dev/null @@ -1,60 +0,0 @@ -//! Vault SetAdminSigners instruction handler - -use { - crate::traits::SetAdminSigners, - solana_farm_sdk::{ - error::FarmError, - instruction::vault::VaultInstruction, - program::{account, multisig, multisig::Multisig, pda}, - vault::Vault, - }, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - }, -}; - -impl SetAdminSigners for VaultInstruction { - fn set_admin_signers( - vault: &Vault, - accounts: &[AccountInfo], - min_signatures: u8, - ) -> ProgramResult { - let accounts_iter = &mut accounts.iter(); - - let signer_account = next_account_info(accounts_iter)?; - let _vault_metadata = next_account_info(accounts_iter)?; - let _vault_info_account = next_account_info(accounts_iter)?; - let _active_multisig_account = next_account_info(accounts_iter)?; - let vault_multisig_account = next_account_info(accounts_iter)?; - let _system_program = next_account_info(accounts_iter)?; - - if vault_multisig_account.key != &vault.multisig_account { - msg!("Error: Invalid vault multisig account"); - return Err(FarmError::IncorrectAccountAddress.into()); - } - - if account::is_empty(vault_multisig_account)? { - msg!("Init multisig account"); - let seeds: &[&[u8]] = &[b"multisig", vault.name.as_bytes()]; - let _bump = pda::init_system_account( - signer_account, - vault_multisig_account, - &vault.vault_program_id, - &vault.vault_program_id, - seeds, - Multisig::LEN, - )?; - } else { - msg!("Update multisig account"); - } - multisig::set_signers( - vault_multisig_account, - accounts_iter.as_slice(), - min_signatures, - )?; - - Ok(()) - } -} diff --git a/farms/vaults/src/strategies/sbr_stake_lp_compound/shutdown.rs b/farms/vaults/src/strategies/sbr_stake_lp_compound/shutdown.rs deleted file mode 100644 index f5498bd8b39..00000000000 --- a/farms/vaults/src/strategies/sbr_stake_lp_compound/shutdown.rs +++ /dev/null @@ -1,22 +0,0 @@ -//! Vault Shutdown instruction handler - -use { - crate::{traits::Shutdown, vault_info::VaultInfo}, - solana_farm_sdk::{instruction::vault::VaultInstruction, vault::Vault}, - solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, msg}, -}; - -impl Shutdown for VaultInstruction { - fn shutdown(_vault: &Vault, accounts: &[AccountInfo]) -> ProgramResult { - if let [_admin_account, _vault_metadata, vault_info_account, _multisig_account] = accounts { - // Don't do anything special on shutdown for this Vault, just disable deposits and withdrawals - let mut vault_info = VaultInfo::new(vault_info_account); - msg!("disable_deposit"); - vault_info.disable_deposits()?; - msg!("disable_withdrawal"); - vault_info.disable_withdrawals()?; - //pda::close_account(admin_account, vault_info_account) - } - Ok(()) - } -} diff --git a/farms/vaults/src/strategies/sbr_stake_lp_compound/unlock_liquidity.rs b/farms/vaults/src/strategies/sbr_stake_lp_compound/unlock_liquidity.rs deleted file mode 100644 index 89b74c5d40a..00000000000 --- a/farms/vaults/src/strategies/sbr_stake_lp_compound/unlock_liquidity.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! Unlock Liquidity in the Vault instruction handler - -use { - crate::traits::UnlockLiquidity, - solana_farm_sdk::{instruction::vault::VaultInstruction, vault::Vault}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl UnlockLiquidity for VaultInstruction { - fn unlock_liquidity(_vault: &Vault, _accounts: &[AccountInfo], _amount: u64) -> ProgramResult { - msg!("Error: Liquidity Unlock is not required for this Vault"); - Err(ProgramError::InvalidArgument) - } -} diff --git a/farms/vaults/src/strategies/sbr_stake_lp_compound/user_init.rs b/farms/vaults/src/strategies/sbr_stake_lp_compound/user_init.rs deleted file mode 100644 index cdd783e92ee..00000000000 --- a/farms/vaults/src/strategies/sbr_stake_lp_compound/user_init.rs +++ /dev/null @@ -1,55 +0,0 @@ -//! Vault User Init instruction handler - -use { - crate::{traits::UserInit, user_info::UserInfo}, - solana_farm_sdk::{ - instruction::vault::VaultInstruction, - program::{account, pda}, - vault::Vault, - }, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl UserInit for VaultInstruction { - fn user_init(vault: &Vault, accounts: &[AccountInfo]) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - funding_account, - _vault_metadata, - _vault_info_account, - user_account, - user_info_account, - _system_program - ] = accounts - { - if account::is_empty(user_info_account)? { - msg!("Create user info account"); - let seeds: &[&[u8]] = &[ - b"user_info_account", - &user_account.key.as_ref(), - vault.name.as_bytes(), - ]; - let bump = pda::init_system_account( - funding_account, - user_info_account, - &vault.vault_program_id, - &vault.vault_program_id, - seeds, - UserInfo::LEN, - )?; - let mut user_info = UserInfo::new(user_info_account); - user_info.init(&vault.name, bump)?; - } else if !UserInfo::validate_account(vault, user_info_account, user_account.key) { - msg!("Error: User info account already initialized but not valid"); - return Err(ProgramError::AccountAlreadyInitialized); - } - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } - } -} diff --git a/farms/vaults/src/strategies/sbr_stake_lp_compound/withdraw_fees.rs b/farms/vaults/src/strategies/sbr_stake_lp_compound/withdraw_fees.rs deleted file mode 100644 index dc475ce3c02..00000000000 --- a/farms/vaults/src/strategies/sbr_stake_lp_compound/withdraw_fees.rs +++ /dev/null @@ -1,56 +0,0 @@ -//! Vault WithdrawFees instruction handler - -use { - crate::traits::WithdrawFees, - solana_farm_sdk::{instruction::vault::VaultInstruction, program::pda, vault::Vault}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - }, -}; - -impl WithdrawFees for VaultInstruction { - fn withdraw_fees(vault: &Vault, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - #[allow(clippy::deprecated_cfg_attr)] - #[cfg_attr(rustfmt, rustfmt_skip)] - if let [ - _admin_account, - _vault_metadata, - _vault_info_account, - _multisig_account, - vault_authority, - _spl_token_program, - fees_account, - destination_account - ] = accounts - { - // validate accounts - if vault_authority.key != &vault.vault_authority { - msg!("Error: Invalid Vault accounts"); - return Err(ProgramError::InvalidArgument); - } - if Some(*fees_account.key) != vault.fees_account_a - && Some(*fees_account.key) != vault.fees_account_b - { - msg!("Error: Invalid fee accounts"); - return Err(ProgramError::InvalidArgument); - } - - let seeds: &[&[&[u8]]] = &[&[ - b"vault_authority", - vault.name.as_bytes(), - &[vault.authority_bump], - ]]; - pda::transfer_tokens_with_seeds( - fees_account, - destination_account, - vault_authority, - seeds, - amount, - )?; - - Ok(()) - } else { - Err(ProgramError::NotEnoughAccountKeys) - } - } -} diff --git a/farms/vaults/src/traits.rs b/farms/vaults/src/traits.rs deleted file mode 100644 index dbdcdc5318c..00000000000 --- a/farms/vaults/src/traits.rs +++ /dev/null @@ -1,113 +0,0 @@ -//! Vaults traits and common features. - -use { - crate::vault_info::VaultInfo, - solana_farm_sdk::vault::Vault, - solana_program::{account_info::AccountInfo, entrypoint::ProgramResult}, -}; - -pub trait VaultParams { - fn default_min_crank_interval() -> u64; - fn default_fee() -> f64; - fn default_external_fee() -> f64; -} - -pub trait UserInit { - fn user_init(vault: &Vault, accounts: &[AccountInfo]) -> ProgramResult; -} - -pub trait AddLiquidity { - fn add_liquidity( - vault: &Vault, - accounts: &[AccountInfo], - max_token_a_amount: u64, - max_token_b_amount: u64, - ) -> ProgramResult; -} - -pub trait LockLiquidity { - fn lock_liquidity(vault: &Vault, accounts: &[AccountInfo], amount: u64) -> ProgramResult; -} - -pub trait UnlockLiquidity { - fn unlock_liquidity(vault: &Vault, accounts: &[AccountInfo], amount: u64) -> ProgramResult; -} - -pub trait RemoveLiquidity { - fn remove_liquidity(vault: &Vault, accounts: &[AccountInfo], amount: u64) -> ProgramResult; -} - -pub trait Features { - fn set_min_crank_interval( - vault: &Vault, - vault_info: &mut VaultInfo, - accounts: &[AccountInfo], - min_crank_interval_sec: u64, - ) -> ProgramResult; - - fn set_fee( - vault: &Vault, - vault_info: &mut VaultInfo, - accounts: &[AccountInfo], - fee: f64, - ) -> ProgramResult; - - fn set_external_fee( - vault: &Vault, - vault_info: &mut VaultInfo, - accounts: &[AccountInfo], - external_fee: f64, - ) -> ProgramResult; - - fn enable_deposits( - vault: &Vault, - vault_info: &mut VaultInfo, - accounts: &[AccountInfo], - ) -> ProgramResult; - - fn disable_deposits( - vault: &Vault, - vault_info: &mut VaultInfo, - accounts: &[AccountInfo], - ) -> ProgramResult; - - fn enable_withdrawals( - vault: &Vault, - vault_info: &mut VaultInfo, - accounts: &[AccountInfo], - ) -> ProgramResult; - - fn disable_withdrawals( - vault: &Vault, - vault_info: &mut VaultInfo, - accounts: &[AccountInfo], - ) -> ProgramResult; -} - -pub trait Crank { - fn crank(vault: &Vault, accounts: &[AccountInfo], step: u64) -> ProgramResult; -} - -pub trait Init { - fn init(vault: &Vault, accounts: &[AccountInfo], step: u64) -> ProgramResult; -} - -pub trait Shutdown { - fn shutdown(vault: &Vault, accounts: &[AccountInfo]) -> ProgramResult; -} - -pub trait WithdrawFees { - fn withdraw_fees(vault: &Vault, accounts: &[AccountInfo], amount: u64) -> ProgramResult; -} - -pub trait SetAdminSigners { - fn set_admin_signers( - vault: &Vault, - accounts: &[AccountInfo], - min_signatures: u8, - ) -> ProgramResult; -} - -pub trait RemoveMultisig { - fn remove_multisig(vault: &Vault, accounts: &[AccountInfo]) -> ProgramResult; -} diff --git a/farms/vaults/src/user_info.rs b/farms/vaults/src/user_info.rs deleted file mode 100644 index 419f56767fd..00000000000 --- a/farms/vaults/src/user_info.rs +++ /dev/null @@ -1,348 +0,0 @@ -//! User info account management. - -use { - solana_farm_sdk::{ - math::checked_add, - program::clock, - refdb, - refdb::{RefDB, Reference, ReferenceType, StorageType}, - string::{str_to_as64, ArrayString64}, - vault::Vault, - }, - solana_program::{ - account_info::AccountInfo, clock::UnixTimestamp, entrypoint::ProgramResult, - program_error::ProgramError, pubkey::Pubkey, - }, - std::cell::RefMut, -}; - -pub struct UserInfo<'a, 'b> { - pub key: &'a Pubkey, - pub data: RefMut<'a, &'b mut [u8]>, -} - -impl<'a, 'b> UserInfo<'a, 'b> { - pub const LEN: usize = StorageType::get_storage_size_for_records(ReferenceType::U64, 8); - pub const LAST_DEPOSIT_INDEX: usize = 0; - pub const LAST_WITHDRAWAL_INDEX: usize = 1; - pub const TOKEN_A_ADDED_INDEX: usize = 2; - pub const TOKEN_A_REMOVED_INDEX: usize = 3; - pub const TOKEN_B_ADDED_INDEX: usize = 4; - pub const TOKEN_B_REMOVED_INDEX: usize = 5; - pub const LP_TOKENS_DEBT_INDEX: usize = 6; - pub const USER_BUMP_INDEX: usize = 7; - - pub fn new(account: &'a AccountInfo<'b>) -> Self { - Self { - key: account.key, - data: account.data.borrow_mut(), - } - } - - pub fn init(&mut self, refdb_name: &ArrayString64, user_bump: u8) -> ProgramResult { - RefDB::init(&mut self.data, refdb_name, ReferenceType::U64)?; - - self.init_refdb_field( - UserInfo::LAST_DEPOSIT_INDEX, - "LastDeposit", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - UserInfo::LAST_WITHDRAWAL_INDEX, - "LastWithdrawal", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - UserInfo::TOKEN_A_ADDED_INDEX, - "TokenAAdded", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - UserInfo::TOKEN_A_REMOVED_INDEX, - "TokenARemoved", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - UserInfo::TOKEN_B_ADDED_INDEX, - "TokenBAdded", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - UserInfo::TOKEN_B_REMOVED_INDEX, - "TokenBRemoved", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - UserInfo::LP_TOKENS_DEBT_INDEX, - "LpTokensDebt", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - UserInfo::USER_BUMP_INDEX, - "UserBump", - Reference::U64 { - data: user_bump as u64, - }, - ) - } - - pub fn update_deposit_time(&mut self) -> ProgramResult { - RefDB::update_at( - &mut self.data, - UserInfo::LAST_DEPOSIT_INDEX, - &Reference::U64 { - data: clock::get_time_as_u64()?, - }, - ) - .map(|_| ()) - } - - pub fn update_withdrawal_time(&mut self) -> ProgramResult { - RefDB::update_at( - &mut self.data, - UserInfo::LAST_WITHDRAWAL_INDEX, - &Reference::U64 { - data: clock::get_time_as_u64()?, - }, - ) - .map(|_| ()) - } - - pub fn add_liquidity(&mut self, token_a_added: u64, token_b_added: u64) -> ProgramResult { - if token_a_added > 0 { - let mut token_a_balance = token_a_added; - if let Some(token_a_rec) = RefDB::read_at(&self.data, UserInfo::TOKEN_A_ADDED_INDEX)? { - if let Reference::U64 { data } = token_a_rec.reference { - token_a_balance = token_a_balance.wrapping_add(data); - } - } - RefDB::update_at( - &mut self.data, - UserInfo::TOKEN_A_ADDED_INDEX, - &Reference::U64 { - data: token_a_balance, - }, - )?; - } - if token_b_added > 0 { - let mut token_b_balance = token_b_added; - if let Some(token_b_rec) = RefDB::read_at(&self.data, UserInfo::TOKEN_B_ADDED_INDEX)? { - if let Reference::U64 { data } = token_b_rec.reference { - token_b_balance = token_b_balance.wrapping_add(data); - } - } - RefDB::update_at( - &mut self.data, - UserInfo::TOKEN_B_ADDED_INDEX, - &Reference::U64 { - data: token_b_balance, - }, - )?; - } - if token_a_added > 0 || token_b_added > 0 { - self.update_deposit_time()?; - } - Ok(()) - } - - pub fn remove_liquidity( - &mut self, - token_a_removed: u64, - token_b_removed: u64, - ) -> ProgramResult { - if token_a_removed > 0 { - let mut token_a_balance = token_a_removed; - if let Some(token_a_rec) = RefDB::read_at(&self.data, UserInfo::TOKEN_A_REMOVED_INDEX)? - { - if let Reference::U64 { data } = token_a_rec.reference { - token_a_balance = token_a_balance.wrapping_add(data); - } - } - RefDB::update_at( - &mut self.data, - UserInfo::TOKEN_A_REMOVED_INDEX, - &Reference::U64 { - data: token_a_balance, - }, - )?; - } - if token_b_removed > 0 { - let mut token_b_balance = token_b_removed; - if let Some(token_b_rec) = RefDB::read_at(&self.data, UserInfo::TOKEN_B_REMOVED_INDEX)? - { - if let Reference::U64 { data } = token_b_rec.reference { - token_b_balance = token_b_balance.wrapping_add(data); - } - } - RefDB::update_at( - &mut self.data, - UserInfo::TOKEN_B_REMOVED_INDEX, - &Reference::U64 { - data: token_b_balance, - }, - )?; - } - if token_a_removed > 0 || token_b_removed > 0 { - self.update_withdrawal_time()?; - } - Ok(()) - } - - pub fn add_lp_tokens_debt(&mut self, token_added: u64) -> ProgramResult { - let mut token_debt_total = token_added; - if let Some(token_debt_rec) = RefDB::read_at(&self.data, UserInfo::LP_TOKENS_DEBT_INDEX)? { - if let Reference::U64 { data } = token_debt_rec.reference { - token_debt_total = checked_add(token_debt_total, data)?; - } - } - RefDB::update_at( - &mut self.data, - UserInfo::LP_TOKENS_DEBT_INDEX, - &Reference::U64 { - data: token_debt_total, - }, - )?; - Ok(()) - } - - pub fn remove_lp_tokens_debt(&mut self, token_removed: u64) -> ProgramResult { - let mut token_debt_total = 0; - if let Some(token_debt_rec) = RefDB::read_at(&self.data, UserInfo::LP_TOKENS_DEBT_INDEX)? { - if let Reference::U64 { data } = token_debt_rec.reference { - token_debt_total = data; - } - } - token_debt_total = if let Some(res) = token_debt_total.checked_sub(token_removed) { - res - } else { - 0 - }; - RefDB::update_at( - &mut self.data, - UserInfo::LP_TOKENS_DEBT_INDEX, - &Reference::U64 { - data: token_debt_total, - }, - )?; - Ok(()) - } - - pub fn get_lp_tokens_debt(&self) -> Result { - if let Some(token_debt_rec) = RefDB::read_at(&self.data, UserInfo::LP_TOKENS_DEBT_INDEX)? { - if let Reference::U64 { data } = token_debt_rec.reference { - return Ok(data); - } - } - Err(ProgramError::UninitializedAccount) - } - - pub fn get_deposit_time(&self) -> Result { - if let Some(deposit_rec) = RefDB::read_at(&self.data, UserInfo::LAST_DEPOSIT_INDEX)? { - if let Reference::U64 { data } = deposit_rec.reference { - return Ok(data as UnixTimestamp); - } - } - Err(ProgramError::UninitializedAccount) - } - - pub fn get_withdrawal_time(&self) -> Result { - if let Some(deposit_rec) = RefDB::read_at(&self.data, UserInfo::LAST_WITHDRAWAL_INDEX)? { - if let Reference::U64 { data } = deposit_rec.reference { - return Ok(data as UnixTimestamp); - } - } - Err(ProgramError::UninitializedAccount) - } - - pub fn get_token_a_added(&self) -> Result { - if let Some(deposit_rec) = RefDB::read_at(&self.data, UserInfo::TOKEN_A_ADDED_INDEX)? { - if let Reference::U64 { data } = deposit_rec.reference { - return Ok(data); - } - } - Err(ProgramError::UninitializedAccount) - } - - pub fn get_token_b_added(&self) -> Result { - if let Some(deposit_rec) = RefDB::read_at(&self.data, UserInfo::TOKEN_B_ADDED_INDEX)? { - if let Reference::U64 { data } = deposit_rec.reference { - return Ok(data); - } - } - Err(ProgramError::UninitializedAccount) - } - - pub fn get_token_a_removed(&self) -> Result { - if let Some(deposit_rec) = RefDB::read_at(&self.data, UserInfo::TOKEN_A_REMOVED_INDEX)? { - if let Reference::U64 { data } = deposit_rec.reference { - return Ok(data); - } - } - Err(ProgramError::UninitializedAccount) - } - - pub fn get_token_b_removed(&self) -> Result { - if let Some(deposit_rec) = RefDB::read_at(&self.data, UserInfo::TOKEN_B_REMOVED_INDEX)? { - if let Reference::U64 { data } = deposit_rec.reference { - return Ok(data); - } - } - Err(ProgramError::UninitializedAccount) - } - - pub fn get_user_bump(&self) -> Result { - if let Some(user_bump_rec) = RefDB::read_at(&self.data, UserInfo::USER_BUMP_INDEX)? { - if let Reference::U64 { data } = user_bump_rec.reference { - return Ok(data as u8); - } - } - Err(ProgramError::UninitializedAccount) - } - - pub fn validate_account( - vault: &Vault, - user_info_account: &'a AccountInfo<'b>, - user_account: &Pubkey, - ) -> bool { - if let Ok(refdb) = user_info_account.try_borrow_data() { - if let Ok(Some(user_bump_rec)) = RefDB::read_at(&refdb, UserInfo::USER_BUMP_INDEX) { - if let Reference::U64 { data } = user_bump_rec.reference { - if let Ok(key) = Pubkey::create_program_address( - &[ - b"user_info_account", - user_account.as_ref(), - vault.name.as_bytes(), - &[data as u8], - ], - &vault.vault_program_id, - ) { - if user_info_account.key == &key { - return true; - } - } - } - } - } - false - } - - // private helpers - fn init_refdb_field( - &mut self, - index: usize, - field_name: &str, - reference: Reference, - ) -> ProgramResult { - RefDB::write( - &mut self.data, - &refdb::Record { - index: Some(index as u32), - counter: 0, - tag: 0, - name: str_to_as64(field_name)?, - reference, - }, - ) - .map(|_| ()) - } -} diff --git a/farms/vaults/src/vault_info.rs b/farms/vaults/src/vault_info.rs deleted file mode 100644 index 695e9b1c54e..00000000000 --- a/farms/vaults/src/vault_info.rs +++ /dev/null @@ -1,468 +0,0 @@ -//! Vault info account management. - -use { - crate::traits::VaultParams, - solana_farm_sdk::{ - program::clock, - refdb, - refdb::{RefDB, Reference, ReferenceType, StorageType}, - string::{str_to_as64, ArrayString64}, - }, - solana_program::{ - account_info::AccountInfo, clock::UnixTimestamp, entrypoint::ProgramResult, - program_error::ProgramError, pubkey::Pubkey, - }, - std::cell::RefMut, -}; - -pub struct VaultInfo<'a, 'b> { - pub key: &'a Pubkey, - pub data: RefMut<'a, &'b mut [u8]>, -} - -impl<'a, 'b> VaultInfo<'a, 'b> { - pub const LEN: usize = StorageType::get_storage_size_for_records(ReferenceType::U64, 13); - pub const CRANK_TIME_INDEX: usize = 0; - pub const CRANK_STEP_INDEX: usize = 1; - pub const TOKEN_A_ADDED_INDEX: usize = 2; - pub const TOKEN_A_REMOVED_INDEX: usize = 3; - pub const TOKEN_B_ADDED_INDEX: usize = 4; - pub const TOKEN_B_REMOVED_INDEX: usize = 5; - pub const TOKEN_A_REWARDS_INDEX: usize = 6; - pub const TOKEN_B_REWARDS_INDEX: usize = 7; - pub const DEPOSITS_ALLOWED_INDEX: usize = 8; - pub const WITHDRAWALS_ALLOWED_INDEX: usize = 9; - pub const MIN_CRANK_INTERVAL_INDEX: usize = 10; - pub const FEE_INDEX: usize = 11; - pub const EXTERNAL_FEE_INDEX: usize = 12; - - pub fn new(account: &'a AccountInfo<'b>) -> Self { - Self { - key: account.key, - data: account.data.borrow_mut(), - } - } - - pub fn init(&mut self, refdb_name: &ArrayString64) -> ProgramResult { - if RefDB::is_initialized(&self.data) { - return Ok(()); - } - RefDB::init(&mut self.data, refdb_name, ReferenceType::U64)?; - - self.init_refdb_field( - VaultInfo::CRANK_TIME_INDEX, - "CrankTime", - Reference::U64 { - data: clock::get_time_as_u64()?, - }, - )?; - self.init_refdb_field( - VaultInfo::CRANK_STEP_INDEX, - "CrankStep", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - VaultInfo::TOKEN_A_ADDED_INDEX, - "TokenAAdded", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - VaultInfo::TOKEN_A_REMOVED_INDEX, - "TokenARemoved", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - VaultInfo::TOKEN_B_ADDED_INDEX, - "TokenBAdded", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - VaultInfo::TOKEN_B_REMOVED_INDEX, - "TokenBRemoved", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - VaultInfo::TOKEN_A_REWARDS_INDEX, - "TokenARewards", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - VaultInfo::TOKEN_B_REWARDS_INDEX, - "TokenBRewards", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - VaultInfo::DEPOSITS_ALLOWED_INDEX, - "DepositAllowed", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - VaultInfo::WITHDRAWALS_ALLOWED_INDEX, - "WithdrawalAllowed", - Reference::U64 { data: 0 }, - )?; - self.init_refdb_field( - VaultInfo::MIN_CRANK_INTERVAL_INDEX, - "MinCrankInterval", - Reference::U64 { - data: VaultInfo::default_min_crank_interval(), - }, - )?; - self.init_refdb_field( - VaultInfo::FEE_INDEX, - "Fee", - Reference::U64 { - data: VaultInfo::default_fee().to_bits(), - }, - )?; - self.init_refdb_field( - VaultInfo::EXTERNAL_FEE_INDEX, - "ExternalFee", - Reference::U64 { - data: VaultInfo::default_external_fee().to_bits(), - }, - ) - } - - pub fn update_crank_time(&mut self) -> ProgramResult { - RefDB::update_at( - &mut self.data, - VaultInfo::CRANK_TIME_INDEX, - &Reference::U64 { - data: clock::get_time_as_u64()?, - }, - ) - .map(|_| ()) - } - - pub fn set_crank_step(&mut self, step: u64) -> ProgramResult { - RefDB::update_at( - &mut self.data, - VaultInfo::CRANK_STEP_INDEX, - &Reference::U64 { data: step }, - ) - .map(|_| ()) - } - - pub fn set_min_crank_interval(&mut self, min_crank_interval_sec: u64) -> ProgramResult { - RefDB::update_at( - &mut self.data, - VaultInfo::MIN_CRANK_INTERVAL_INDEX, - &Reference::U64 { - data: min_crank_interval_sec, - }, - ) - .map(|_| ()) - } - - pub fn set_fee(&mut self, fee: f64) -> ProgramResult { - if !(0.0..=1.0).contains(&fee) { - return Err(ProgramError::InvalidArgument); - } - RefDB::update_at( - &mut self.data, - VaultInfo::FEE_INDEX, - &Reference::U64 { - data: fee.to_bits(), - }, - ) - .map(|_| ()) - } - - pub fn set_external_fee(&mut self, external_fee: f64) -> ProgramResult { - if !(0.0..=1.0).contains(&external_fee) { - return Err(ProgramError::InvalidArgument); - } - RefDB::update_at( - &mut self.data, - VaultInfo::EXTERNAL_FEE_INDEX, - &Reference::U64 { - data: external_fee.to_bits(), - }, - ) - .map(|_| ()) - } - - pub fn enable_deposits(&mut self) -> ProgramResult { - RefDB::update_at( - &mut self.data, - VaultInfo::DEPOSITS_ALLOWED_INDEX, - &Reference::U64 { data: 1 }, - ) - .map(|_| ()) - } - - pub fn disable_deposits(&mut self) -> ProgramResult { - RefDB::update_at( - &mut self.data, - VaultInfo::DEPOSITS_ALLOWED_INDEX, - &Reference::U64 { data: 0 }, - ) - .map(|_| ()) - } - - pub fn enable_withdrawals(&mut self) -> ProgramResult { - RefDB::update_at( - &mut self.data, - VaultInfo::WITHDRAWALS_ALLOWED_INDEX, - &Reference::U64 { data: 1 }, - ) - .map(|_| ()) - } - - pub fn disable_withdrawals(&mut self) -> ProgramResult { - RefDB::update_at( - &mut self.data, - VaultInfo::WITHDRAWALS_ALLOWED_INDEX, - &Reference::U64 { data: 0 }, - ) - .map(|_| ()) - } - - pub fn add_liquidity(&mut self, token_a_added: u64, token_b_added: u64) -> ProgramResult { - if token_a_added > 0 { - let mut token_a_balance = token_a_added; - if let Some(token_a_rec) = RefDB::read_at(&self.data, VaultInfo::TOKEN_A_ADDED_INDEX)? { - if let Reference::U64 { data } = token_a_rec.reference { - token_a_balance = token_a_balance.wrapping_add(data); - } - } - RefDB::update_at( - &mut self.data, - VaultInfo::TOKEN_A_ADDED_INDEX, - &Reference::U64 { - data: token_a_balance, - }, - )?; - } - if token_b_added > 0 { - let mut token_b_balance = token_b_added; - if let Some(token_b_rec) = RefDB::read_at(&self.data, VaultInfo::TOKEN_B_ADDED_INDEX)? { - if let Reference::U64 { data } = token_b_rec.reference { - token_b_balance = token_b_balance.wrapping_add(data); - } - } - RefDB::update_at( - &mut self.data, - VaultInfo::TOKEN_B_ADDED_INDEX, - &Reference::U64 { - data: token_b_balance, - }, - )?; - } - Ok(()) - } - - pub fn remove_liquidity( - &mut self, - token_a_removed: u64, - token_b_removed: u64, - ) -> ProgramResult { - if token_a_removed > 0 { - let mut token_a_balance = token_a_removed; - if let Some(token_a_rec) = RefDB::read_at(&self.data, VaultInfo::TOKEN_A_REMOVED_INDEX)? - { - if let Reference::U64 { data } = token_a_rec.reference { - token_a_balance = token_a_balance.wrapping_add(data); - } - } - RefDB::update_at( - &mut self.data, - VaultInfo::TOKEN_A_REMOVED_INDEX, - &Reference::U64 { - data: token_a_balance, - }, - )?; - } - if token_b_removed > 0 { - let mut token_b_balance = token_b_removed; - if let Some(token_b_rec) = RefDB::read_at(&self.data, VaultInfo::TOKEN_B_REMOVED_INDEX)? - { - if let Reference::U64 { data } = token_b_rec.reference { - token_b_balance = token_b_balance.wrapping_add(data); - } - } - RefDB::update_at( - &mut self.data, - VaultInfo::TOKEN_B_REMOVED_INDEX, - &Reference::U64 { - data: token_b_balance, - }, - )?; - } - Ok(()) - } - - pub fn add_rewards(&mut self, token_a_rewards: u64, token_b_rewards: u64) -> ProgramResult { - if token_a_rewards > 0 { - let mut token_a_total = token_a_rewards; - if let Some(token_a_rec) = RefDB::read_at(&self.data, VaultInfo::TOKEN_A_REWARDS_INDEX)? - { - if let Reference::U64 { data } = token_a_rec.reference { - token_a_total = token_a_total.wrapping_add(data); - } - } - RefDB::update_at( - &mut self.data, - VaultInfo::TOKEN_A_REWARDS_INDEX, - &Reference::U64 { - data: token_a_total, - }, - )?; - } - if token_b_rewards > 0 { - let mut token_b_total = token_b_rewards; - if let Some(token_b_rec) = RefDB::read_at(&self.data, VaultInfo::TOKEN_B_REWARDS_INDEX)? - { - if let Reference::U64 { data } = token_b_rec.reference { - token_b_total = token_b_total.wrapping_add(data); - } - } - RefDB::update_at( - &mut self.data, - VaultInfo::TOKEN_B_REWARDS_INDEX, - &Reference::U64 { - data: token_b_total, - }, - )?; - } - Ok(()) - } - - pub fn get_crank_time(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, VaultInfo::CRANK_TIME_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(data as UnixTimestamp); - } - } - Err(ProgramError::InvalidAccountData) - } - - pub fn get_crank_step(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, VaultInfo::CRANK_STEP_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(data); - } - } - Err(ProgramError::InvalidAccountData) - } - - pub fn get_min_crank_interval(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, VaultInfo::MIN_CRANK_INTERVAL_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(data as i64); - } - } - Err(ProgramError::InvalidAccountData) - } - - pub fn get_fee(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, VaultInfo::FEE_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(f64::from_bits(data)); - } - } - Err(ProgramError::InvalidAccountData) - } - - pub fn get_external_fee(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, VaultInfo::EXTERNAL_FEE_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(f64::from_bits(data)); - } - } - Err(ProgramError::InvalidAccountData) - } - - pub fn is_deposit_allowed(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, VaultInfo::DEPOSITS_ALLOWED_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(data > 0); - } - } - Err(ProgramError::InvalidAccountData) - } - - pub fn is_withdrawal_allowed(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, VaultInfo::WITHDRAWALS_ALLOWED_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(data > 0); - } - } - Err(ProgramError::InvalidAccountData) - } - - pub fn get_token_a_added(&self) -> Result { - if let Some(deposit_rec) = RefDB::read_at(&self.data, VaultInfo::TOKEN_A_ADDED_INDEX)? { - if let Reference::U64 { data } = deposit_rec.reference { - return Ok(data); - } - } - Err(ProgramError::InvalidAccountData) - } - - pub fn get_token_b_added(&self) -> Result { - if let Some(deposit_rec) = RefDB::read_at(&self.data, VaultInfo::TOKEN_B_ADDED_INDEX)? { - if let Reference::U64 { data } = deposit_rec.reference { - return Ok(data); - } - } - Err(ProgramError::InvalidAccountData) - } - - pub fn get_token_a_removed(&self) -> Result { - if let Some(deposit_rec) = RefDB::read_at(&self.data, VaultInfo::TOKEN_A_REMOVED_INDEX)? { - if let Reference::U64 { data } = deposit_rec.reference { - return Ok(data); - } - } - Err(ProgramError::InvalidAccountData) - } - - pub fn get_token_b_removed(&self) -> Result { - if let Some(deposit_rec) = RefDB::read_at(&self.data, VaultInfo::TOKEN_B_REMOVED_INDEX)? { - if let Reference::U64 { data } = deposit_rec.reference { - return Ok(data); - } - } - Err(ProgramError::InvalidAccountData) - } - - pub fn get_token_a_rewards(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, VaultInfo::TOKEN_A_REWARDS_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(data); - } - } - Err(ProgramError::InvalidAccountData) - } - - pub fn get_token_b_rewards(&self) -> Result { - if let Some(rec) = RefDB::read_at(&self.data, VaultInfo::TOKEN_B_REWARDS_INDEX)? { - if let Reference::U64 { data } = rec.reference { - return Ok(data); - } - } - Err(ProgramError::InvalidAccountData) - } - - // private helpers - fn init_refdb_field( - &mut self, - index: usize, - field_name: &str, - reference: Reference, - ) -> ProgramResult { - RefDB::write( - &mut self.data, - &refdb::Record { - index: Some(index as u32), - counter: 0, - tag: 0, - name: str_to_as64(field_name)?, - reference, - }, - ) - .map(|_| ()) - } -} diff --git a/feature-proposal/README.md b/feature-proposal/README.md new file mode 100644 index 00000000000..b5637f9a4a5 --- /dev/null +++ b/feature-proposal/README.md @@ -0,0 +1,2 @@ +NOTE: The feature-proposal program and clients are now maintained at +[solana-program/feature-proposal](https://github.com/solana-program/feature-proposal). diff --git a/feature-proposal/cli/Cargo.toml b/feature-proposal/cli/Cargo.toml deleted file mode 100644 index 03a7037b042..00000000000 --- a/feature-proposal/cli/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "spl-feature-proposal-cli" -version = "1.2.0" -description = "SPL Feature Proposal Command-line Utility" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana-program-library" -license = "Apache-2.0" -edition = "2018" - -[dependencies] -chrono = "0.4.19" -clap = "2.33.3" -solana-clap-utils = "1.10.33" -solana-cli-config = "1.10.33" -solana-client = "1.10.33" -solana-logger = "1.10.33" -solana-sdk = "1.10.33" -spl-feature-proposal = { version = "1.0", path = "../program", features = ["no-entrypoint"] } - -[[bin]] -name = "spl-feature-proposal" -path = "src/main.rs" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] diff --git a/feature-proposal/cli/src/main.rs b/feature-proposal/cli/src/main.rs deleted file mode 100644 index 26024e71a0f..00000000000 --- a/feature-proposal/cli/src/main.rs +++ /dev/null @@ -1,487 +0,0 @@ -use { - chrono::{DateTime, NaiveDateTime, SecondsFormat, Utc}, - clap::{ - crate_description, crate_name, crate_version, value_t_or_exit, App, AppSettings, Arg, - SubCommand, - }, - solana_clap_utils::{ - input_parsers::{keypair_of, pubkey_of}, - input_validators::{is_keypair, is_url, is_valid_percentage, is_valid_pubkey}, - }, - solana_client::rpc_client::RpcClient, - solana_sdk::{ - clock::UnixTimestamp, - commitment_config::CommitmentConfig, - program_pack::Pack, - pubkey::Pubkey, - signature::{read_keypair_file, Keypair, Signer}, - transaction::Transaction, - }, - spl_feature_proposal::state::{AcceptanceCriteria, FeatureProposal}, - std::{ - collections::HashMap, - fs::File, - io::Write, - time::{Duration, SystemTime, UNIX_EPOCH}, - }, -}; - -struct Config { - keypair: Keypair, - json_rpc_url: String, - verbose: bool, -} - -fn main() -> Result<(), Box> { - let app_matches = App::new(crate_name!()) - .about(crate_description!()) - .version(crate_version!()) - .setting(AppSettings::SubcommandRequiredElseHelp) - .arg({ - let arg = Arg::with_name("config_file") - .short("C") - .long("config") - .value_name("PATH") - .takes_value(true) - .global(true) - .help("Configuration file to use"); - if let Some(ref config_file) = *solana_cli_config::CONFIG_FILE { - arg.default_value(config_file) - } else { - arg - } - }) - .arg( - Arg::with_name("keypair") - .long("keypair") - .value_name("KEYPAIR") - .validator(is_keypair) - .takes_value(true) - .global(true) - .help("Filepath or URL to a keypair [default: client keypair]"), - ) - .arg( - Arg::with_name("verbose") - .long("verbose") - .short("v") - .takes_value(false) - .global(true) - .help("Show additional information"), - ) - .arg( - Arg::with_name("json_rpc_url") - .long("url") - .value_name("URL") - .takes_value(true) - .global(true) - .validator(is_url) - .help("JSON RPC URL for the cluster [default: value from configuration file]"), - ) - .subcommand( - SubCommand::with_name("address") - .about("Display address information for the feature proposal") - .arg( - Arg::with_name("feature_proposal") - .value_name("FEATURE_PROPOSAL_ADDRESS") - .validator(is_valid_pubkey) - .index(1) - .required(true) - .help("The address of the feature proposal"), - ), - ) - .subcommand( - SubCommand::with_name("propose") - .about("Initiate a feature proposal") - .arg( - Arg::with_name("feature_proposal") - .value_name("FEATURE_PROPOSAL_KEYPAIR") - .validator(is_keypair) - .index(1) - .required(true) - .help("The keypair of the feature proposal"), - ) - .arg( - Arg::with_name("percent_stake_required") - .long("percent-stake-required") - .value_name("PERCENTAGE") - .validator(is_valid_percentage) - .required(true) - .default_value("67") - .help("Percentage of the active stake required for the proposal to pass"), - ) - .arg( - Arg::with_name("distribution_file") - .long("distribution-file") - .value_name("FILENAME") - .required(true) - .default_value("feature-proposal.csv") - .help("Allocations CSV file for use with solana-tokens"), - ) - .arg( - Arg::with_name("confirm") - .long("confirm") - .help("Confirm that the feature proposal should actually be initiated"), - ), - ) - .subcommand( - SubCommand::with_name("tally") - .about("Tally the current results for a proposed feature") - .arg( - Arg::with_name("feature_proposal") - .value_name("FEATURE_PROPOSAL_ADDRESS") - .validator(is_valid_pubkey) - .index(1) - .required(true) - .help("The address of the feature proposal"), - ), - ) - .get_matches(); - - let (sub_command, sub_matches) = app_matches.subcommand(); - let matches = sub_matches.unwrap(); - - let config = { - let cli_config = if let Some(config_file) = matches.value_of("config_file") { - solana_cli_config::Config::load(config_file).unwrap_or_default() - } else { - solana_cli_config::Config::default() - }; - - Config { - json_rpc_url: matches - .value_of("json_rpc_url") - .unwrap_or(&cli_config.json_rpc_url) - .to_string(), - keypair: read_keypair_file( - matches - .value_of("keypair") - .unwrap_or(&cli_config.keypair_path), - )?, - verbose: matches.is_present("verbose"), - } - }; - solana_logger::setup_with_default("solana=info"); - let rpc_client = - RpcClient::new_with_commitment(config.json_rpc_url.clone(), CommitmentConfig::confirmed()); - - match (sub_command, sub_matches) { - ("address", Some(arg_matches)) => { - let feature_proposal_address = pubkey_of(arg_matches, "feature_proposal").unwrap(); - - println!( - "Feature Id: {}", - spl_feature_proposal::get_feature_id_address(&feature_proposal_address) - ); - println!( - "Token Mint Address: {}", - spl_feature_proposal::get_mint_address(&feature_proposal_address) - ); - println!( - "Acceptance Token Address: {}", - spl_feature_proposal::get_acceptance_token_address(&feature_proposal_address) - ); - - Ok(()) - } - ("propose", Some(arg_matches)) => { - let feature_proposal_keypair = keypair_of(arg_matches, "feature_proposal").unwrap(); - let distribution_file = value_t_or_exit!(arg_matches, "distribution_file", String); - let percent_stake_required = - value_t_or_exit!(arg_matches, "percent_stake_required", u8); - - // Hard code deadline for now... - let fortnight = Duration::from_secs(60 * 60 * 24 * 14); - let deadline = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .checked_add(fortnight) - .unwrap() - .as_secs() as UnixTimestamp; - - process_propose( - &rpc_client, - &config, - &feature_proposal_keypair, - distribution_file, - percent_stake_required, - deadline, - arg_matches.is_present("confirm"), - ) - } - ("tally", Some(arg_matches)) => { - if config.verbose { - println!("JSON RPC URL: {}", config.json_rpc_url); - } - - let feature_proposal_address = pubkey_of(arg_matches, "feature_proposal").unwrap(); - process_tally(&rpc_client, &config, &feature_proposal_address) - } - _ => unreachable!(), - } -} - -fn get_feature_proposal( - rpc_client: &RpcClient, - feature_proposal_address: &Pubkey, -) -> Result { - let account = rpc_client - .get_multiple_accounts(&[*feature_proposal_address]) - .map_err(|err| err.to_string())? - .into_iter() - .next() - .unwrap(); - - match account { - None => Err(format!( - "Feature proposal {} does not exist", - feature_proposal_address - )), - Some(account) => FeatureProposal::unpack_from_slice(&account.data).map_err(|err| { - format!( - "Failed to deserialize feature proposal {}: {}", - feature_proposal_address, err - ) - }), - } -} - -fn unix_timestamp_to_string(unix_timestamp: UnixTimestamp) -> String { - format!( - "{} (UnixTimestamp: {})", - match NaiveDateTime::from_timestamp_opt(unix_timestamp, 0) { - Some(ndt) => - DateTime::::from_utc(ndt, Utc).to_rfc3339_opts(SecondsFormat::Secs, true), - None => "unknown".to_string(), - }, - unix_timestamp, - ) -} - -fn process_propose( - rpc_client: &RpcClient, - config: &Config, - feature_proposal_keypair: &Keypair, - distribution_file: String, - percent_stake_required: u8, - deadline: UnixTimestamp, - confirm: bool, -) -> Result<(), Box> { - let distributor_token_address = - spl_feature_proposal::get_distributor_token_address(&feature_proposal_keypair.pubkey()); - let feature_id_address = - spl_feature_proposal::get_feature_id_address(&feature_proposal_keypair.pubkey()); - let acceptance_token_address = - spl_feature_proposal::get_acceptance_token_address(&feature_proposal_keypair.pubkey()); - let mint_address = spl_feature_proposal::get_mint_address(&feature_proposal_keypair.pubkey()); - - println!("Feature Id: {}", feature_id_address); - println!("Token Mint Address: {}", mint_address); - println!("Distributor Token Address: {}", distributor_token_address); - println!("Acceptance Token Address: {}", acceptance_token_address); - - let vote_accounts = rpc_client.get_vote_accounts()?; - let mut distribution = HashMap::new(); - for (pubkey, activated_stake) in vote_accounts - .current - .into_iter() - .chain(vote_accounts.delinquent) - .map(|vote_account| (vote_account.node_pubkey, vote_account.activated_stake)) - { - distribution - .entry(pubkey) - .and_modify(|e| *e += activated_stake) - .or_insert(activated_stake); - } - - let tokens_to_mint: u64 = distribution.iter().map(|x| x.1).sum(); - let tokens_required = tokens_to_mint * percent_stake_required as u64 / 100; - - println!("Number of validators: {}", distribution.len()); - println!( - "Tokens to be minted: {}", - spl_feature_proposal::amount_to_ui_amount(tokens_to_mint) - ); - println!( - "Tokens required for acceptance: {} ({}%)", - spl_feature_proposal::amount_to_ui_amount(tokens_required), - percent_stake_required - ); - - println!("Token distribution file: {}", distribution_file); - { - let mut file = File::create(&distribution_file)?; - file.write_all(b"recipient,amount\n")?; - for (node_address, activated_stake) in distribution.iter() { - file.write_all(format!("{},{}\n", node_address, activated_stake).as_bytes())?; - } - } - - let mut transaction = Transaction::new_with_payer( - &[spl_feature_proposal::instruction::propose( - &config.keypair.pubkey(), - &feature_proposal_keypair.pubkey(), - tokens_to_mint, - AcceptanceCriteria { - tokens_required, - deadline, - }, - )], - Some(&config.keypair.pubkey()), - ); - let blockhash = rpc_client.get_latest_blockhash()?; - transaction.try_sign(&[&config.keypair, feature_proposal_keypair], blockhash)?; - - println!("JSON RPC URL: {}", config.json_rpc_url); - - println!(); - println!("Distribute the proposal tokens to all validators by running:"); - println!( - " $ solana-tokens distribute-spl-tokens \ - --from {} \ - --input-csv {} \ - --db-path db.{} \ - --fee-payer ~/.config/solana/id.json \ - --owner ", - distributor_token_address, - distribution_file, - &feature_proposal_keypair.pubkey().to_string()[..8] - ); - println!( - " $ solana-tokens spl-token-balances \ - --mint {} --input-csv {}", - mint_address, distribution_file - ); - println!(); - - println!( - "Once the distribution is complete, request validators vote for \ - the proposal by first looking up their token account address:" - ); - println!( - " $ spl-token --owner ~/validator-keypair.json accounts {}", - mint_address - ); - println!("and then submit their vote by running:"); - println!( - " $ spl-token --owner ~/validator-keypair.json transfer ALL {}", - acceptance_token_address - ); - println!(); - println!("Periodically the votes must be tallied by running:"); - println!( - " $ spl-feature-proposal tally {}", - feature_proposal_keypair.pubkey() - ); - println!("Tallying is permissionless and may be run by anybody."); - println!("Once this feature proposal is accepted, the {} feature will be activated at the next epoch.", feature_id_address); - - println!(); - println!( - "Proposal will expire at {}", - unix_timestamp_to_string(deadline) - ); - println!(); - if !confirm { - println!("Add --confirm flag to initiate the feature proposal"); - return Ok(()); - } - rpc_client.send_and_confirm_transaction_with_spinner(&transaction)?; - - println!(); - println!("Feature proposal created!"); - Ok(()) -} - -fn process_tally( - rpc_client: &RpcClient, - config: &Config, - feature_proposal_address: &Pubkey, -) -> Result<(), Box> { - let feature_proposal = get_feature_proposal(rpc_client, feature_proposal_address)?; - - let feature_id_address = spl_feature_proposal::get_feature_id_address(feature_proposal_address); - let acceptance_token_address = - spl_feature_proposal::get_acceptance_token_address(feature_proposal_address); - - println!("Feature Id: {}", feature_id_address); - println!("Acceptance Token Address: {}", acceptance_token_address); - - match feature_proposal { - FeatureProposal::Uninitialized => { - return Err("Feature proposal is uninitialized".into()); - } - FeatureProposal::Pending(acceptance_criteria) => { - let acceptance_token_address = - spl_feature_proposal::get_acceptance_token_address(feature_proposal_address); - let acceptance_token_balance = rpc_client - .get_token_account_balance(&acceptance_token_address)? - .amount - .parse::() - .unwrap_or(0); - - println!(); - println!( - "{} tokens required to accept the proposal", - spl_feature_proposal::amount_to_ui_amount(acceptance_criteria.tokens_required) - ); - println!( - "{} tokens have been received", - spl_feature_proposal::amount_to_ui_amount(acceptance_token_balance) - ); - println!( - "Proposal will expire at {}", - unix_timestamp_to_string(acceptance_criteria.deadline) - ); - println!(); - - // Don't bother issuing a transaction if it's clear the Tally won't succeed - if acceptance_token_balance < acceptance_criteria.tokens_required - && (SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs() as UnixTimestamp) - < acceptance_criteria.deadline - { - println!("Feature proposal pending"); - return Ok(()); - } - } - FeatureProposal::Accepted { .. } => { - println!("Feature proposal accepted"); - return Ok(()); - } - FeatureProposal::Expired => { - println!("Feature proposal expired"); - return Ok(()); - } - } - - let mut transaction = Transaction::new_with_payer( - &[spl_feature_proposal::instruction::tally( - feature_proposal_address, - )], - Some(&config.keypair.pubkey()), - ); - let blockhash = rpc_client.get_latest_blockhash()?; - transaction.try_sign(&[&config.keypair], blockhash)?; - - rpc_client.send_and_confirm_transaction_with_spinner(&transaction)?; - - // Check the status of the proposal after the tally completes - let feature_proposal = get_feature_proposal(rpc_client, feature_proposal_address)?; - match feature_proposal { - FeatureProposal::Uninitialized => Err("Feature proposal is uninitialized".into()), - FeatureProposal::Pending { .. } => { - println!("Feature proposal pending"); - Ok(()) - } - FeatureProposal::Accepted { .. } => { - println!("Feature proposal accepted"); - Ok(()) - } - FeatureProposal::Expired => { - println!("Feature proposal expired"); - Ok(()) - } - } -} diff --git a/feature-proposal/program/Cargo.toml b/feature-proposal/program/Cargo.toml deleted file mode 100644 index b99b023d37f..00000000000 --- a/feature-proposal/program/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "spl-feature-proposal" -version = "1.0.0" -description = "Solana Program Library Feature Proposal Program" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana-program-library" -license = "Apache-2.0" -edition = "2018" - -[features] -no-entrypoint = [] -test-bpf = [] - -[dependencies] -borsh = "0.9" -borsh-derive = "0.9.0" -solana-program = "1.10.33" -spl-token = { version = "3.3", path = "../../token/program", features = ["no-entrypoint"] } - -[dev-dependencies] -solana-program-test = "1.10.33" -solana-sdk = "1.10.33" - -[lib] -crate-type = ["cdylib", "lib"] - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] diff --git a/feature-proposal/program/Xargo.toml b/feature-proposal/program/Xargo.toml deleted file mode 100644 index 1744f098ae1..00000000000 --- a/feature-proposal/program/Xargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.bpfel-unknown-unknown.dependencies.std] -features = [] \ No newline at end of file diff --git a/feature-proposal/program/program-id.md b/feature-proposal/program/program-id.md deleted file mode 100644 index f1475c155c4..00000000000 --- a/feature-proposal/program/program-id.md +++ /dev/null @@ -1 +0,0 @@ -Feat1YXHhH6t1juaWF74WLcfv4XoNocjXA6sPWHNgAse diff --git a/feature-proposal/program/run-tests.sh b/feature-proposal/program/run-tests.sh deleted file mode 100755 index 802b1ee53c2..00000000000 --- a/feature-proposal/program/run-tests.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - -set -ex -cd "$(dirname "$0")" -cargo fmt -- --check -cargo clippy -cargo build -cargo build-bpf - -if [[ $1 = -v ]]; then - export RUST_LOG=solana=debug -fi - -cargo test -cargo test-bpf diff --git a/feature-proposal/program/src/entrypoint.rs b/feature-proposal/program/src/entrypoint.rs deleted file mode 100644 index e2382fbe4e8..00000000000 --- a/feature-proposal/program/src/entrypoint.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! Program entrypoint - -#![cfg(all(target_os = "solana", not(feature = "no-entrypoint")))] - -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, pubkey::Pubkey, -}; - -entrypoint!(process_instruction); -fn process_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - instruction_data: &[u8], -) -> ProgramResult { - crate::processor::process_instruction(program_id, accounts, instruction_data) -} diff --git a/feature-proposal/program/src/instruction.rs b/feature-proposal/program/src/instruction.rs deleted file mode 100644 index bb3c6e61f16..00000000000 --- a/feature-proposal/program/src/instruction.rs +++ /dev/null @@ -1,218 +0,0 @@ -//! Program instructions - -use crate::{state::AcceptanceCriteria, *}; -use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; -use solana_program::{ - instruction::{AccountMeta, Instruction}, - msg, - program_error::ProgramError, - program_pack::{Pack, Sealed}, - pubkey::Pubkey, - sysvar, -}; - -/// Instructions supported by the Feature Proposal program -#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema, PartialEq)] -pub enum FeatureProposalInstruction { - /// Propose a new feature. - /// - /// This instruction will create a variety of accounts to support the feature proposal, all - /// funded by account 0: - /// * A new token mint with a supply of `tokens_to_mint`, owned by the program and never - /// modified again - /// * A new "distributor" token account that holds the total supply, owned by account 0. - /// * A new "acceptance" token account that holds 0 tokens, owned by the program. Tokens - /// transfers to this address are irrevocable and permanent. - /// * A new feature id account that has been funded and allocated (as described in - /// `solana_program::feature`) - /// - /// On successful execution of the instruction, the feature proposer is expected to distribute - /// the tokens in the distributor token account out to all participating parties. - /// - /// Based on the provided acceptance criteria, if `AcceptanceCriteria::tokens_required` - /// tokens are transferred into the acceptance token account before - /// `AcceptanceCriteria::deadline` then the proposal is eligible to be accepted. - /// - /// The `FeatureProposalInstruction::Tally` instruction must be executed, by any party, to - /// complete the feature acceptance process. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writeable,signer]` Funding account (must be a system account) - /// 1. `[writeable,signer]` Unallocated feature proposal account to create - /// 2. `[writeable]` Token mint address from `get_mint_address` - /// 3. `[writeable]` Distributor token account address from `get_distributor_token_address` - /// 4. `[writeable]` Acceptance token account address from `get_acceptance_token_address` - /// 5. `[writeable]` Feature id account address from `get_feature_id_address` - /// 6. `[]` System program - /// 7. `[]` SPL Token program - /// 8. `[]` Rent sysvar - /// - Propose { - /// Total number of tokens to mint for this proposal - #[allow(dead_code)] // not dead code.. - tokens_to_mint: u64, - - /// Criteria for how this proposal may be activated - #[allow(dead_code)] // not dead code.. - acceptance_criteria: AcceptanceCriteria, - }, - - /// `Tally` is a permission-less instruction to check the acceptance criteria for the feature - /// proposal, which may result in: - /// * No action - /// * Feature proposal acceptance - /// * Feature proposal expiration - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writeable]` Feature proposal account - /// 1. `[]` Acceptance token account address from `get_acceptance_token_address` - /// 2. `[writeable]` Derived feature id account address from `get_feature_id_address` - /// 3. `[]` System program - /// 4. `[]` Clock sysvar - Tally, -} - -impl Sealed for FeatureProposalInstruction {} -impl Pack for FeatureProposalInstruction { - const LEN: usize = 25; // see `test_get_packed_len()` for justification of "18" - - fn pack_into_slice(&self, dst: &mut [u8]) { - let data = self.pack_into_vec(); - dst[..data.len()].copy_from_slice(&data); - } - - fn unpack_from_slice(src: &[u8]) -> Result { - let mut mut_src: &[u8] = src; - Self::deserialize(&mut mut_src).map_err(|err| { - msg!( - "Error: failed to deserialize feature proposal instruction: {}", - err - ); - ProgramError::InvalidInstructionData - }) - } -} - -impl FeatureProposalInstruction { - fn pack_into_vec(&self) -> Vec { - self.try_to_vec().expect("try_to_vec") - } -} - -/// Create a `FeatureProposalInstruction::Propose` instruction -pub fn propose( - funding_address: &Pubkey, - feature_proposal_address: &Pubkey, - tokens_to_mint: u64, - acceptance_criteria: AcceptanceCriteria, -) -> Instruction { - let mint_address = get_mint_address(feature_proposal_address); - let distributor_token_address = get_distributor_token_address(feature_proposal_address); - let acceptance_token_address = get_acceptance_token_address(feature_proposal_address); - let feature_id_address = get_feature_id_address(feature_proposal_address); - - Instruction { - program_id: id(), - accounts: vec![ - AccountMeta::new(*funding_address, true), - AccountMeta::new(*feature_proposal_address, true), - AccountMeta::new(mint_address, false), - AccountMeta::new(distributor_token_address, false), - AccountMeta::new(acceptance_token_address, false), - AccountMeta::new(feature_id_address, false), - AccountMeta::new_readonly(solana_program::system_program::id(), false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - ], - data: FeatureProposalInstruction::Propose { - tokens_to_mint, - acceptance_criteria, - } - .pack_into_vec(), - } -} - -/// Create a `FeatureProposalInstruction::Tally` instruction -pub fn tally(feature_proposal_address: &Pubkey) -> Instruction { - let acceptance_token_address = get_acceptance_token_address(feature_proposal_address); - let feature_id_address = get_feature_id_address(feature_proposal_address); - - Instruction { - program_id: id(), - accounts: vec![ - AccountMeta::new(*feature_proposal_address, false), - AccountMeta::new_readonly(acceptance_token_address, false), - AccountMeta::new(feature_id_address, false), - AccountMeta::new_readonly(solana_program::system_program::id(), false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - ], - data: FeatureProposalInstruction::Tally.pack_into_vec(), - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_get_packed_len() { - assert_eq!( - FeatureProposalInstruction::get_packed_len(), - solana_program::borsh::get_packed_len::() - ) - } - - #[test] - fn test_serialize_bytes() { - assert_eq!( - FeatureProposalInstruction::Tally.try_to_vec().unwrap(), - vec![1] - ); - - assert_eq!( - FeatureProposalInstruction::Propose { - tokens_to_mint: 42, - acceptance_criteria: AcceptanceCriteria { - tokens_required: 0xdeadbeefdeadbeef, - deadline: -1, - } - } - .try_to_vec() - .unwrap(), - vec![ - 0, 42, 0, 0, 0, 0, 0, 0, 0, 239, 190, 173, 222, 239, 190, 173, 222, 255, 255, 255, - 255, 255, 255, 255, 255 - ] - ); - } - - #[test] - fn test_serialize_large_slice() { - let mut dst = vec![0xff; 4]; - FeatureProposalInstruction::Tally.pack_into_slice(&mut dst); - - // Extra bytes (0xff) ignored - assert_eq!(dst, vec![1, 0xff, 0xff, 0xff]); - } - - #[test] - fn state_deserialize_invalid() { - assert_eq!( - FeatureProposalInstruction::unpack_from_slice(&[1]), - Ok(FeatureProposalInstruction::Tally), - ); - - // Extra bytes (0xff) ignored... - assert_eq!( - FeatureProposalInstruction::unpack_from_slice(&[1, 0xff, 0xff, 0xff]), - Ok(FeatureProposalInstruction::Tally), - ); - - assert_eq!( - FeatureProposalInstruction::unpack_from_slice(&[2]), - Err(ProgramError::InvalidInstructionData), - ); - } -} diff --git a/feature-proposal/program/src/lib.rs b/feature-proposal/program/src/lib.rs deleted file mode 100644 index fd1d4115a04..00000000000 --- a/feature-proposal/program/src/lib.rs +++ /dev/null @@ -1,76 +0,0 @@ -//! Feature Proposal program -#![deny(missing_docs)] -#![forbid(unsafe_code)] - -mod entrypoint; -pub mod instruction; -pub mod processor; -pub mod state; - -// Export current SDK types for downstream users building with a different SDK version -pub use solana_program; -use solana_program::{program_pack::Pack, pubkey::Pubkey}; - -solana_program::declare_id!("Feat1YXHhH6t1juaWF74WLcfv4XoNocjXA6sPWHNgAse"); - -pub(crate) fn get_mint_address_with_seed(feature_proposal_address: &Pubkey) -> (Pubkey, u8) { - Pubkey::find_program_address(&[&feature_proposal_address.to_bytes(), br"mint"], &id()) -} - -pub(crate) fn get_distributor_token_address_with_seed( - feature_proposal_address: &Pubkey, -) -> (Pubkey, u8) { - Pubkey::find_program_address( - &[&feature_proposal_address.to_bytes(), br"distributor"], - &id(), - ) -} - -pub(crate) fn get_acceptance_token_address_with_seed( - feature_proposal_address: &Pubkey, -) -> (Pubkey, u8) { - Pubkey::find_program_address( - &[&feature_proposal_address.to_bytes(), br"acceptance"], - &id(), - ) -} - -pub(crate) fn get_feature_id_address_with_seed(feature_proposal_address: &Pubkey) -> (Pubkey, u8) { - Pubkey::find_program_address( - &[&feature_proposal_address.to_bytes(), br"feature-id"], - &id(), - ) -} - -/// Derive the SPL Token mint address associated with a feature proposal -pub fn get_mint_address(feature_proposal_address: &Pubkey) -> Pubkey { - get_mint_address_with_seed(feature_proposal_address).0 -} - -/// Derive the SPL Token token address associated with a feature proposal that receives the initial -/// minted tokens -pub fn get_distributor_token_address(feature_proposal_address: &Pubkey) -> Pubkey { - get_distributor_token_address_with_seed(feature_proposal_address).0 -} - -/// Derive the SPL Token token address associated with a feature proposal that users send their -/// tokens to accept the proposal -pub fn get_acceptance_token_address(feature_proposal_address: &Pubkey) -> Pubkey { - get_acceptance_token_address_with_seed(feature_proposal_address).0 -} - -/// Derive the feature id address associated with the feature proposal -pub fn get_feature_id_address(feature_proposal_address: &Pubkey) -> Pubkey { - get_feature_id_address_with_seed(feature_proposal_address).0 -} - -/// Convert the UI representation of a token amount (using the decimals field defined in its mint) -/// to the raw amount -pub fn ui_amount_to_amount(ui_amount: f64) -> u64 { - (ui_amount * 10_usize.pow(spl_token::native_mint::DECIMALS as u32) as f64) as u64 -} - -/// Convert a raw amount to its UI representation (using the decimals field defined in its mint) -pub fn amount_to_ui_amount(amount: u64) -> f64 { - amount as f64 / 10_usize.pow(spl_token::native_mint::DECIMALS as u32) as f64 -} diff --git a/feature-proposal/program/src/processor.rs b/feature-proposal/program/src/processor.rs deleted file mode 100644 index ec188953e54..00000000000 --- a/feature-proposal/program/src/processor.rs +++ /dev/null @@ -1,369 +0,0 @@ -//! Program state processor - -use crate::{instruction::*, state::*, *}; -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - clock::Clock, - entrypoint::ProgramResult, - feature::{self, Feature}, - msg, - program::{invoke, invoke_signed}, - program_error::ProgramError, - pubkey::Pubkey, - rent::Rent, - system_instruction, - sysvar::Sysvar, -}; - -/// Instruction processor -pub fn process_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - input: &[u8], -) -> ProgramResult { - let instruction = FeatureProposalInstruction::unpack_from_slice(input)?; - let account_info_iter = &mut accounts.iter(); - - match instruction { - FeatureProposalInstruction::Propose { - tokens_to_mint, - acceptance_criteria, - } => { - msg!("FeatureProposalInstruction::Propose"); - - let funder_info = next_account_info(account_info_iter)?; - let feature_proposal_info = next_account_info(account_info_iter)?; - let mint_info = next_account_info(account_info_iter)?; - let distributor_token_info = next_account_info(account_info_iter)?; - let acceptance_token_info = next_account_info(account_info_iter)?; - let feature_id_info = next_account_info(account_info_iter)?; - let system_program_info = next_account_info(account_info_iter)?; - let spl_token_program_info = next_account_info(account_info_iter)?; - let rent_sysvar_info = next_account_info(account_info_iter)?; - let rent = &Rent::from_account_info(rent_sysvar_info)?; - - let (mint_address, mint_bump_seed) = - get_mint_address_with_seed(feature_proposal_info.key); - if mint_address != *mint_info.key { - msg!("Error: mint address derivation mismatch"); - return Err(ProgramError::InvalidArgument); - } - - let (distributor_token_address, distributor_token_bump_seed) = - get_distributor_token_address_with_seed(feature_proposal_info.key); - if distributor_token_address != *distributor_token_info.key { - msg!("Error: distributor token address derivation mismatch"); - return Err(ProgramError::InvalidArgument); - } - - let (acceptance_token_address, acceptance_token_bump_seed) = - get_acceptance_token_address_with_seed(feature_proposal_info.key); - if acceptance_token_address != *acceptance_token_info.key { - msg!("Error: acceptance token address derivation mismatch"); - return Err(ProgramError::InvalidArgument); - } - - let (feature_id_address, feature_id_bump_seed) = - get_feature_id_address_with_seed(feature_proposal_info.key); - if feature_id_address != *feature_id_info.key { - msg!("Error: feature-id address derivation mismatch"); - return Err(ProgramError::InvalidArgument); - } - - let mint_signer_seeds: &[&[_]] = &[ - &feature_proposal_info.key.to_bytes(), - br"mint", - &[mint_bump_seed], - ]; - - let distributor_token_signer_seeds: &[&[_]] = &[ - &feature_proposal_info.key.to_bytes(), - br"distributor", - &[distributor_token_bump_seed], - ]; - - let acceptance_token_signer_seeds: &[&[_]] = &[ - &feature_proposal_info.key.to_bytes(), - br"acceptance", - &[acceptance_token_bump_seed], - ]; - - let feature_id_signer_seeds: &[&[_]] = &[ - &feature_proposal_info.key.to_bytes(), - br"feature-id", - &[feature_id_bump_seed], - ]; - - msg!("Creating feature proposal account"); - invoke( - &system_instruction::create_account( - funder_info.key, - feature_proposal_info.key, - 1.max(rent.minimum_balance(FeatureProposal::get_packed_len())), - FeatureProposal::get_packed_len() as u64, - program_id, - ), - &[ - funder_info.clone(), - feature_proposal_info.clone(), - system_program_info.clone(), - ], - )?; - FeatureProposal::Pending(acceptance_criteria) - .pack_into_slice(&mut feature_proposal_info.data.borrow_mut()); - - msg!("Creating mint"); - invoke_signed( - &system_instruction::create_account( - funder_info.key, - mint_info.key, - 1.max(rent.minimum_balance(spl_token::state::Mint::get_packed_len())), - spl_token::state::Mint::get_packed_len() as u64, - &spl_token::id(), - ), - &[ - funder_info.clone(), - mint_info.clone(), - system_program_info.clone(), - ], - &[mint_signer_seeds], - )?; - - msg!("Initializing mint"); - invoke( - &spl_token::instruction::initialize_mint( - &spl_token::id(), - mint_info.key, - mint_info.key, - None, - spl_token::native_mint::DECIMALS, - )?, - &[ - mint_info.clone(), - spl_token_program_info.clone(), - rent_sysvar_info.clone(), - ], - )?; - - msg!("Creating distributor token account"); - invoke_signed( - &system_instruction::create_account( - funder_info.key, - distributor_token_info.key, - 1.max(rent.minimum_balance(spl_token::state::Account::get_packed_len())), - spl_token::state::Account::get_packed_len() as u64, - &spl_token::id(), - ), - &[ - funder_info.clone(), - distributor_token_info.clone(), - system_program_info.clone(), - ], - &[distributor_token_signer_seeds], - )?; - - msg!("Initializing distributor token account"); - invoke( - &spl_token::instruction::initialize_account( - &spl_token::id(), - distributor_token_info.key, - mint_info.key, - feature_proposal_info.key, - )?, - &[ - distributor_token_info.clone(), - spl_token_program_info.clone(), - rent_sysvar_info.clone(), - feature_proposal_info.clone(), - mint_info.clone(), - ], - )?; - - msg!("Creating acceptance token account"); - invoke_signed( - &system_instruction::create_account( - funder_info.key, - acceptance_token_info.key, - 1.max(rent.minimum_balance(spl_token::state::Account::get_packed_len())), - spl_token::state::Account::get_packed_len() as u64, - &spl_token::id(), - ), - &[ - funder_info.clone(), - acceptance_token_info.clone(), - system_program_info.clone(), - ], - &[acceptance_token_signer_seeds], - )?; - - msg!("Initializing acceptance token account"); - invoke( - &spl_token::instruction::initialize_account( - &spl_token::id(), - acceptance_token_info.key, - mint_info.key, - feature_proposal_info.key, - )?, - &[ - acceptance_token_info.clone(), - spl_token_program_info.clone(), - rent_sysvar_info.clone(), - feature_proposal_info.clone(), - mint_info.clone(), - ], - )?; - invoke( - &spl_token::instruction::set_authority( - &spl_token::id(), - acceptance_token_info.key, - Some(feature_proposal_info.key), - spl_token::instruction::AuthorityType::CloseAccount, - feature_proposal_info.key, - &[], - )?, - &[ - spl_token_program_info.clone(), - acceptance_token_info.clone(), - feature_proposal_info.clone(), - ], - )?; - invoke( - &spl_token::instruction::set_authority( - &spl_token::id(), - acceptance_token_info.key, - Some(program_id), - spl_token::instruction::AuthorityType::AccountOwner, - feature_proposal_info.key, - &[], - )?, - &[ - spl_token_program_info.clone(), - acceptance_token_info.clone(), - feature_proposal_info.clone(), - ], - )?; - - // Mint `tokens_to_mint` tokens into `distributor_token_account` owned by - // `feature_proposal` - msg!("Minting {} tokens", tokens_to_mint); - invoke_signed( - &spl_token::instruction::mint_to( - &spl_token::id(), - mint_info.key, - distributor_token_info.key, - mint_info.key, - &[], - tokens_to_mint, - )?, - &[ - mint_info.clone(), - distributor_token_info.clone(), - spl_token_program_info.clone(), - ], - &[mint_signer_seeds], - )?; - - // Fully fund the feature id account so the `Tally` instruction will not require any - // lamports from the caller - msg!("Funding feature id account"); - invoke( - &system_instruction::transfer( - funder_info.key, - feature_id_info.key, - 1.max(rent.minimum_balance(Feature::size_of())), - ), - &[ - funder_info.clone(), - feature_id_info.clone(), - system_program_info.clone(), - ], - )?; - - msg!("Allocating feature id account"); - invoke_signed( - &system_instruction::allocate(feature_id_info.key, Feature::size_of() as u64), - &[feature_id_info.clone(), system_program_info.clone()], - &[feature_id_signer_seeds], - )?; - } - - FeatureProposalInstruction::Tally => { - msg!("FeatureProposalInstruction::Tally"); - - let feature_proposal_info = next_account_info(account_info_iter)?; - let feature_proposal_state = - FeatureProposal::unpack_from_slice(&feature_proposal_info.data.borrow())?; - - match feature_proposal_state { - FeatureProposal::Pending(acceptance_criteria) => { - let acceptance_token_info = next_account_info(account_info_iter)?; - let feature_id_info = next_account_info(account_info_iter)?; - let system_program_info = next_account_info(account_info_iter)?; - let clock_sysvar_info = next_account_info(account_info_iter)?; - let clock = &Clock::from_account_info(clock_sysvar_info)?; - - // Re-derive the acceptance token and feature id program addresses to confirm - // the caller provided the correct addresses - let acceptance_token_address = - get_acceptance_token_address(feature_proposal_info.key); - if acceptance_token_address != *acceptance_token_info.key { - msg!("Error: acceptance token address derivation mismatch"); - return Err(ProgramError::InvalidArgument); - } - - let (feature_id_address, feature_id_bump_seed) = - get_feature_id_address_with_seed(feature_proposal_info.key); - if feature_id_address != *feature_id_info.key { - msg!("Error: feature-id address derivation mismatch"); - return Err(ProgramError::InvalidArgument); - } - - let feature_id_signer_seeds: &[&[_]] = &[ - &feature_proposal_info.key.to_bytes(), - br"feature-id", - &[feature_id_bump_seed], - ]; - - if clock.unix_timestamp >= acceptance_criteria.deadline { - msg!("Feature proposal expired"); - FeatureProposal::Expired - .pack_into_slice(&mut feature_proposal_info.data.borrow_mut()); - return Ok(()); - } - - msg!("Unpacking acceptance token account"); - let acceptance_token = - spl_token::state::Account::unpack(&acceptance_token_info.data.borrow())?; - - msg!( - "Feature proposal has received {} tokens, and {} tokens required for acceptance", - acceptance_token.amount, acceptance_criteria.tokens_required - ); - if acceptance_token.amount < acceptance_criteria.tokens_required { - msg!("Activation threshold has not been reached"); - return Ok(()); - } - - msg!("Assigning feature id account"); - invoke_signed( - &system_instruction::assign(feature_id_info.key, &feature::id()), - &[feature_id_info.clone(), system_program_info.clone()], - &[feature_id_signer_seeds], - )?; - - msg!("Feature proposal accepted"); - FeatureProposal::Accepted { - tokens_upon_acceptance: acceptance_token.amount, - } - .pack_into_slice(&mut feature_proposal_info.data.borrow_mut()); - } - _ => { - msg!("Error: feature proposal account not in the pending state"); - return Err(ProgramError::InvalidAccountData); - } - } - } - } - - Ok(()) -} diff --git a/feature-proposal/program/src/state.rs b/feature-proposal/program/src/state.rs deleted file mode 100644 index f1c1cd259ee..00000000000 --- a/feature-proposal/program/src/state.rs +++ /dev/null @@ -1,113 +0,0 @@ -//! Program state -use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; -use solana_program::{ - clock::UnixTimestamp, - msg, - program_error::ProgramError, - program_pack::{Pack, Sealed}, -}; - -/// Criteria for accepting a feature proposal -#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema, PartialEq)] -pub struct AcceptanceCriteria { - /// The balance of the feature proposal's token account must be greater than this amount, and - /// tallied before the deadline for the feature to be accepted. - pub tokens_required: u64, - - /// If the required tokens are not tallied by this deadline then the proposal will expire. - pub deadline: UnixTimestamp, -} - -/// Contents of a Feature Proposal account -#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema, PartialEq)] -pub enum FeatureProposal { - /// Default account state after creating it - Uninitialized, - /// Feature proposal is now pending - Pending(AcceptanceCriteria), - /// Feature proposal was accepted and the feature is now active - Accepted { - /// The balance of the feature proposal's token account at the time of activation. - #[allow(dead_code)] // not dead code.. - tokens_upon_acceptance: u64, - }, - /// Feature proposal was not accepted before the deadline - Expired, -} -impl Sealed for FeatureProposal {} - -impl Pack for FeatureProposal { - const LEN: usize = 17; // see `test_get_packed_len()` for justification of "18" - - fn pack_into_slice(&self, dst: &mut [u8]) { - let data = self.try_to_vec().unwrap(); - dst[..data.len()].copy_from_slice(&data); - } - - fn unpack_from_slice(src: &[u8]) -> Result { - let mut mut_src: &[u8] = src; - Self::deserialize(&mut mut_src).map_err(|err| { - msg!( - "Error: failed to deserialize feature proposal account: {}", - err - ); - ProgramError::InvalidAccountData - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_get_packed_len() { - assert_eq!( - FeatureProposal::get_packed_len(), - solana_program::borsh::get_packed_len::() - ); - } - - #[test] - fn test_serialize_bytes() { - assert_eq!(FeatureProposal::Expired.try_to_vec().unwrap(), vec![3]); - - assert_eq!( - FeatureProposal::Pending(AcceptanceCriteria { - tokens_required: 0xdeadbeefdeadbeef, - deadline: -1, - }) - .try_to_vec() - .unwrap(), - vec![1, 239, 190, 173, 222, 239, 190, 173, 222, 255, 255, 255, 255, 255, 255, 255, 255], - ); - } - - #[test] - fn test_serialize_large_slice() { - let mut dst = vec![0xff; 4]; - FeatureProposal::Expired.pack_into_slice(&mut dst); - - // Extra bytes (0xff) ignored - assert_eq!(dst, vec![3, 0xff, 0xff, 0xff]); - } - - #[test] - fn state_deserialize_invalid() { - assert_eq!( - FeatureProposal::unpack_from_slice(&[3]), - Ok(FeatureProposal::Expired), - ); - - // Extra bytes (0xff) ignored... - assert_eq!( - FeatureProposal::unpack_from_slice(&[3, 0xff, 0xff, 0xff]), - Ok(FeatureProposal::Expired), - ); - - assert_eq!( - FeatureProposal::unpack_from_slice(&[4]), - Err(ProgramError::InvalidAccountData), - ); - } -} diff --git a/feature-proposal/program/tests/functional.rs b/feature-proposal/program/tests/functional.rs deleted file mode 100644 index 7fd6cd37ea7..00000000000 --- a/feature-proposal/program/tests/functional.rs +++ /dev/null @@ -1,205 +0,0 @@ -// Mark this test as BPF-only due to current `ProgramTest` limitations when CPIing into the system program -#![cfg(feature = "test-bpf")] - -use { - solana_program::{ - feature::{self, Feature}, - program_option::COption, - system_program, - }, - solana_program_test::*, - solana_sdk::{ - signature::{Keypair, Signer}, - transaction::Transaction, - }, - spl_feature_proposal::{instruction::*, state::*, *}, -}; - -fn program_test() -> ProgramTest { - ProgramTest::new( - "spl_feature_proposal", - id(), - processor!(processor::process_instruction), - ) -} - -#[tokio::test] -async fn test_basic() { - let feature_proposal = Keypair::new(); - - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - - let feature_id_address = get_feature_id_address(&feature_proposal.pubkey()); - let mint_address = get_mint_address(&feature_proposal.pubkey()); - let distributor_token_address = get_distributor_token_address(&feature_proposal.pubkey()); - let acceptance_token_address = get_acceptance_token_address(&feature_proposal.pubkey()); - - // Create a new feature proposal - let mut transaction = Transaction::new_with_payer( - &[propose( - &payer.pubkey(), - &feature_proposal.pubkey(), - 42, - AcceptanceCriteria { - tokens_required: 42, - deadline: i64::MAX, - }, - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &feature_proposal], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - // Confirm feature id account is now funded and allocated, but not assigned - let feature_id_account = banks_client - .get_account(feature_id_address) - .await - .expect("success") - .expect("some account"); - assert_eq!(feature_id_account.owner, system_program::id()); - assert_eq!(feature_id_account.data.len(), Feature::size_of()); - - // Confirm mint account state - let mint = banks_client - .get_packed_account_data::(mint_address) - .await - .unwrap(); - assert_eq!(mint.supply, 42); - assert_eq!(mint.decimals, 9); - assert!(mint.freeze_authority.is_none()); - assert_eq!(mint.mint_authority, COption::Some(mint_address)); - - // Confirm distributor token account state - let distributor_token = banks_client - .get_packed_account_data::(distributor_token_address) - .await - .unwrap(); - assert_eq!(distributor_token.amount, 42); - assert_eq!(distributor_token.mint, mint_address); - assert_eq!(distributor_token.owner, feature_proposal.pubkey()); - assert!(distributor_token.close_authority.is_none()); - - // Confirm acceptance token account state - let acceptance_token = banks_client - .get_packed_account_data::(acceptance_token_address) - .await - .unwrap(); - assert_eq!(acceptance_token.amount, 0); - assert_eq!(acceptance_token.mint, mint_address); - assert_eq!(acceptance_token.owner, id()); - assert_eq!( - acceptance_token.close_authority, - COption::Some(feature_proposal.pubkey()) - ); - - // Tally #1: Does nothing because the acceptance criteria has not been met - let mut transaction = - Transaction::new_with_payer(&[tally(&feature_proposal.pubkey())], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - // Confirm feature id account is not yet assigned - let feature_id_account = banks_client - .get_account(feature_id_address) - .await - .expect("success") - .expect("some account"); - assert_eq!(feature_id_account.owner, system_program::id()); - - assert!(matches!( - banks_client - .get_packed_account_data::(feature_proposal.pubkey()) - .await, - Ok(FeatureProposal::Pending(_)) - )); - - // Transfer tokens to the acceptance account - let mut transaction = Transaction::new_with_payer( - &[spl_token::instruction::transfer( - &spl_token::id(), - &distributor_token_address, - &acceptance_token_address, - &feature_proposal.pubkey(), - &[], - 42, - ) - .unwrap()], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &feature_proposal], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - // Fetch a new blockhash to avoid the second Tally transaction having the same signature as the - // first Tally transaction - let recent_blockhash = banks_client - .get_new_latest_blockhash(&recent_blockhash) - .await - .unwrap(); - - // Tally #2: the acceptance criteria is now met - let mut transaction = - Transaction::new_with_payer(&[tally(&feature_proposal.pubkey())], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - // Confirm feature id account is now assigned - let feature_id_account = banks_client - .get_account(feature_id_address) - .await - .expect("success") - .expect("some account"); - assert_eq!(feature_id_account.owner, feature::id()); - - // Confirm feature proposal account state - assert!(matches!( - banks_client - .get_packed_account_data::(feature_proposal.pubkey()) - .await, - Ok(FeatureProposal::Accepted { - tokens_upon_acceptance: 42 - }) - )); -} - -#[tokio::test] -async fn test_expired() { - let feature_proposal = Keypair::new(); - - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - - // Create a new feature proposal - let mut transaction = Transaction::new_with_payer( - &[propose( - &payer.pubkey(), - &feature_proposal.pubkey(), - 42, - AcceptanceCriteria { - tokens_required: 42, - deadline: 0, // <=== Already expired - }, - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &feature_proposal], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - assert!(matches!( - banks_client - .get_packed_account_data::(feature_proposal.pubkey()) - .await, - Ok(FeatureProposal::Pending(_)) - )); - - // Tally will cause the proposal to expire - let mut transaction = - Transaction::new_with_payer(&[tally(&feature_proposal.pubkey())], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - assert!(matches!( - banks_client - .get_packed_account_data::(feature_proposal.pubkey()) - .await, - Ok(FeatureProposal::Expired) - )); -} diff --git a/governance/CHANGELOG.md b/governance/CHANGELOG.md index 50ea59516cf..f68e2cba341 100644 --- a/governance/CHANGELOG.md +++ b/governance/CHANGELOG.md @@ -1,9 +1,29 @@ # SPL Governance Changelog -## v3.0.0 - development - -- Support separate vote threshold for `Council` -- `Council` Veto vote +## v4.0.0 - WIP + +- Mandatory signatories + +## v3.1.1 - 25 Apr 2022 + +- Weighted multi choice voting +- Revoking own membership + +## v3.1.0 - 13 Dec 2022 + +- Council governance plugins +- Non transferable and revokable membership +- Veto vote +- Council wallet rules + - approval quorum + - vote tipping + - veto threshold +- Explicitly disabled options + - community/council vote + - community/council proposals +- Absolute max supply +- Proposal cool off time +- Proposal deposit ## v2.2.4 - 24 Mar 2022 diff --git a/governance/NOTES.md b/governance/NOTES.md new file mode 100644 index 00000000000..bca43a84a8f --- /dev/null +++ b/governance/NOTES.md @@ -0,0 +1,27 @@ +# Developers Notes + +## On pub enum GovernanceAccountType + +### Asset-specific governances are deprecated + +The asset specific governances `ProgramGovernance, MintGovernance and TokenGovernance` are legacy and come from the time when they were top level primitives (Realms didn’t exist) and hence we wanted stronger guarantees to create governances for the relevant assets. They are deprecated now. + +The recommendation is to use the generic governance account (`governanceV2`) to manage all kinds of assets. + +### DAO Wallet + +Every Governance account (which holds the governance rules) has an associated native SOL treasury (we call it DAO wallet). The relationship is always 1:1. Since the Governance account is a PDA with data it can’t be used as transaction payer and to store SOL in general. **To control programs, the recommended way is to always use the associated SOL address (DAO wallet) for authority over assets** + +A DAO wallet is 1) PDA with no data, 2) derived from its governance account and 3) owned by System program. This way it behaves like any other wallet. + +If the intention is to manage a program, you should use the DAO wallet as the admin auth in your program + +*Note: as of 2022-09-17 the UI is not up-to-date and it is still allowing users to create the deprecated asset specific governances.* + +### Signing transactions: Use the DAO Wallet + +Right now both PDAs (DAO Wallet and governance account) can sign Txs. However some protocols assume the signer is also a payer or beneficiary and then only the DAO wallet can be used. For that reason it’s always better to use the DAO wallet as the authority because it behaves like any other wallet and works for all scenarios. The objective is to standardize on DAO Wallet as signer to eliminate confusion. + +### Wallet assets + +We have the concept of wallet assets. An asset can be anything a DAO wallet can own (have authority over). This way you could define your programs as assets and show them in the wallet with your contextual actions. diff --git a/governance/README.md b/governance/README.md index 5f927ac6295..aa5be9df83b 100644 --- a/governance/README.md +++ b/governance/README.md @@ -1,7 +1,9 @@ +> This repo still exists in archived form, but the maintained version has now relocated to: https://github.com/Mythic-Project/solana-program-library/tree/master/governance + # SPL Governance SPL Governance is a program the chief purpose of which is to provide core building blocks and primitives to create -Decentralized Autonomous Organizations (DAOs) on Solana blockchain. +Decentralized Autonomous Organizations (DAOs) on the Solana blockchain. The program is DAO type and asset type agnostic and can be used to build any type of DAOs which can own and manage any type of assets. @@ -56,7 +58,7 @@ There are two UIs available which showcase the programs capabilities: It's a good starting point for developers to learn about the program and interact with it -- [Governance UI](https://github.com/solana-labs/governance-ui) project build together +- [Governance UI](https://github.com/solana-labs/governance-ui) project built together with the [MNGO](https://mango.markets/) team: [governance-ui](https://realms.today) This is advanced, user friendly and tasks oriented UI used by most of the existing DAOs on Solana @@ -73,7 +75,7 @@ Discord server: [spl-governance-discord](https://discord.gg/VsPbrK2hJk) ## Program Accounts -The diagram belows shows an illustrative configuration of the program accounts when used to control upgrades +The diagram below shows an illustrative configuration of the program accounts when used to control upgrades of multiple programs through proposals ![Accounts diagram](./resources/governance-accounts.jpg) @@ -154,7 +156,7 @@ during the voting period but still reaches the required Yes vote threshold it ca using FinalizeVote instruction. Once all Proposal transactions are executed the Proposal enters Completed state. -In the Executing state an instruction can be run by any one at any time after the `instruction_hold_up_time` period has +In the Executing state an instruction can be run by any one at any time after the `hold_up_time` period has transpired. ### ProposalTransaction @@ -197,3 +199,8 @@ the DAO until the token is distributed. ### Proposal Workflow ![Proposal Workflow](./resources/governance-workflow.jpg) + +## Audit + +The repository [README](https://github.com/solana-labs/solana-program-library#audits) +contains information about program audits. diff --git a/governance/addin-api/Cargo.toml b/governance/addin-api/Cargo.toml index a4118e5d4e7..e2b0b318a72 100644 --- a/governance/addin-api/Cargo.toml +++ b/governance/addin-api/Cargo.toml @@ -1,14 +1,13 @@ [package] name = "spl-governance-addin-api" -version = "0.1.2" +version = "0.1.4" description = "Solana Program Library Governance Addin Api" -authors = ["Solana Maintainers "] +authors = ["Solana Labs Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" license = "Apache-2.0" -edition = "2018" +edition = "2021" [dependencies] -borsh = "0.9.1" -spl-governance-tools= { version = "0.1.2", path ="../tools"} -solana-program = "1.10.33" - +borsh = "1.5.3" +spl-governance-tools = { version = "0.1.4", path = "../tools" } +solana-program = "2.1.0" diff --git a/governance/addin-api/src/max_voter_weight.rs b/governance/addin-api/src/max_voter_weight.rs index 6d34a0b7328..24c992460de 100644 --- a/governance/addin-api/src/max_voter_weight.rs +++ b/governance/addin-api/src/max_voter_weight.rs @@ -1,35 +1,44 @@ //! MaxVoterWeight Addin interface -use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; -use solana_program::{clock::Slot, program_pack::IsInitialized, pubkey::Pubkey}; -use spl_governance_tools::account::AccountMaxSize; +use { + borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, + solana_program::{clock::Slot, program_pack::IsInitialized, pubkey::Pubkey}, + spl_governance_tools::account::AccountMaxSize, +}; /// MaxVoterWeightRecord account -/// The account is used as an api interface to provide max voting power to the governance program from external addin contracts -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +/// The account is used as an api interface to provide max voting power to the +/// governance program from external addin contracts +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct MaxVoterWeightRecord { - /// VoterWeightRecord discriminator sha256("account:MaxVoterWeightRecord")[..8] - /// Note: The discriminator size must match the addin implementing program discriminator size - /// to ensure it's stored in the private space of the account data and it's unique + /// VoterWeightRecord discriminator + /// sha256("account:MaxVoterWeightRecord")[..8] + /// Note: The discriminator size must match the addin implementing program + /// discriminator size to ensure it's stored in the private space of the + /// account data and it's unique pub account_discriminator: [u8; 8], /// The Realm the MaxVoterWeightRecord belongs to pub realm: Pubkey, /// Governing Token Mint the MaxVoterWeightRecord is associated with - /// Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only + /// Note: The addin can take deposits of any tokens and is not restricted to + /// the community or council tokens only // The mint here is to link the record to either community or council mint of the realm pub governing_token_mint: Pubkey, /// Max voter weight - /// The max voter weight provided by the addin for the given realm and governing_token_mint + /// The max voter weight provided by the addin for the given realm and + /// governing_token_mint pub max_voter_weight: u64, /// The slot when the max voting weight expires /// It should be set to None if the weight never expires - /// If the max vote weight decays with time, for example for time locked based weights, then the expiry must be set - /// As a pattern Revise instruction to update the max weight should be invoked before governance instruction within the same transaction - /// and the expiry set to the current slot to provide up to date weight + /// If the max vote weight decays with time, for example for time locked + /// based weights, then the expiry must be set. As a pattern Revise + /// instruction to update the max weight should be invoked before governance + /// instruction within the same transaction and the expiry set to the + /// current slot to provide up to date weight pub max_voter_weight_expiry: Option, /// Reserved space for future versions diff --git a/governance/addin-api/src/voter_weight.rs b/governance/addin-api/src/voter_weight.rs index c5b2549e5be..61ad330bc1c 100644 --- a/governance/addin-api/src/voter_weight.rs +++ b/governance/addin-api/src/voter_weight.rs @@ -1,11 +1,13 @@ //! VoterWeight Addin interface -use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; -use solana_program::{clock::Slot, program_pack::IsInitialized, pubkey::Pubkey}; -use spl_governance_tools::account::AccountMaxSize; +use { + borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, + solana_program::{clock::Slot, program_pack::IsInitialized, pubkey::Pubkey}, + spl_governance_tools::account::AccountMaxSize, +}; /// The governance action VoterWeight is evaluated for -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum VoterWeightAction { /// Cast vote for a proposal. Target: Proposal CastVote, @@ -25,46 +27,57 @@ pub enum VoterWeightAction { } /// VoterWeightRecord account -/// The account is used as an api interface to provide voting power to the governance program from external addin contracts -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +/// The account is used as an api interface to provide voting power to the +/// governance program from external addin contracts +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct VoterWeightRecord { /// VoterWeightRecord discriminator sha256("account:VoterWeightRecord")[..8] - /// Note: The discriminator size must match the addin implementing program discriminator size - /// to ensure it's stored in the private space of the account data and it's unique + /// Note: The discriminator size must match the addin implementing program + /// discriminator size to ensure it's stored in the private space of the + /// account data and it's unique pub account_discriminator: [u8; 8], /// The Realm the VoterWeightRecord belongs to pub realm: Pubkey, /// Governing Token Mint the VoterWeightRecord is associated with - /// Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only + /// Note: The addin can take deposits of any tokens and is not restricted to + /// the community or council tokens only // The mint here is to link the record to either community or council mint of the realm pub governing_token_mint: Pubkey, /// The owner of the governing token and voter - /// This is the actual owner (voter) and corresponds to TokenOwnerRecord.governing_token_owner + /// This is the actual owner (voter) and corresponds to + /// TokenOwnerRecord.governing_token_owner pub governing_token_owner: Pubkey, /// Voter's weight - /// The weight of the voter provided by the addin for the given realm, governing_token_mint and governing_token_owner (voter) + /// The weight of the voter provided by the addin for the given realm, + /// governing_token_mint and governing_token_owner (voter) pub voter_weight: u64, /// The slot when the voting weight expires /// It should be set to None if the weight never expires - /// If the voter weight decays with time, for example for time locked based weights, then the expiry must be set - /// As a common pattern Revise instruction to update the weight should be invoked before governance instruction within the same transaction - /// and the expiry set to the current slot to provide up to date weight + /// If the voter weight decays with time, for example for time locked based + /// weights, then the expiry must be set. As a common pattern Revise + /// instruction to update the weight should be invoked before governance + /// instruction within the same transaction and the expiry set to the + /// current slot to provide up to date weight pub voter_weight_expiry: Option, /// The governance action the voter's weight pertains to - /// It allows to provided voter's weight specific to the particular action the weight is evaluated for - /// When the action is provided then the governance program asserts the executing action is the same as specified by the addin + /// It allows to provided voter's weight specific to the particular action + /// the weight is evaluated for. When the action is provided then the + /// governance program asserts the executing action is the same as specified + /// by the addin pub weight_action: Option, /// The target the voter's weight action pertains to - /// It allows to provided voter's weight specific to the target the weight is evaluated for - /// For example when addin supplies weight to vote on a particular proposal then it must specify the proposal as the action target - /// When the target is provided then the governance program asserts the target is the same as specified by the addin + /// It allows to provided voter's weight specific to the target the weight + /// is evaluated for. For example when addin supplies weight to vote on a + /// particular proposal then it must specify the proposal as the action + /// target. When the target is provided then the governance program + /// asserts the target is the same as specified by the addin pub weight_action_target: Option, /// Reserved space for future versions diff --git a/governance/addin-mock/program/Cargo.toml b/governance/addin-mock/program/Cargo.toml index eed3d8c0055..575cd75f2c8 100644 --- a/governance/addin-mock/program/Cargo.toml +++ b/governance/addin-mock/program/Cargo.toml @@ -1,39 +1,43 @@ [package] name = "spl-governance-addin-mock" -version = "0.1.2" +version = "0.1.4" description = "Solana Program Library Governance Voter Weight Addin Program" -authors = ["Solana Maintainers "] +authors = ["Solana Labs Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" license = "Apache-2.0" -edition = "2018" +edition = "2021" [features] no-entrypoint = [] -test-bpf = [] +test-sbf = [] [dependencies] -arrayref = "0.3.6" +arrayref = "0.3.9" bincode = "1.3.2" -borsh = "0.9.1" -num-derive = "0.3" +borsh = "1.5.3" +num-derive = "0.4" num-traits = "0.2" -serde = "1.0.127" +serde = "1.0.217" serde_derive = "1.0.103" -solana-program = "1.10.33" -spl-token = { version = "3.3", path = "../../../token/program", features = [ "no-entrypoint" ] } -spl-governance-addin-api= { version = "0.1.2", path ="../../addin-api"} -spl-governance-tools= { version = "0.1.2", path ="../../tools"} -thiserror = "1.0" +solana-program = "2.1.0" +spl-token = { version = "7.0", features = [ + "no-entrypoint", +] } +spl-governance-addin-api = { version = "0.1.4", path = "../../addin-api" } +spl-governance-tools = { version = "0.1.4", path = "../../tools" } +thiserror = "2.0" [dev-dependencies] assert_matches = "1.5.0" -base64 = "0.13" -proptest = "1.0" -solana-program-test = "1.10.33" -solana-sdk = "1.10.33" -spl-governance-test-sdk = { version = "0.1.2", path ="../../test-sdk"} +proptest = "1.6" +solana-program-test = "2.1.0" +solana-sdk = "2.1.0" +spl-governance-test-sdk = { version = "0.1.4", path = "../../test-sdk" } [lib] crate-type = ["cdylib", "lib"] + +[lints] +workspace = true diff --git a/governance/addin-mock/program/src/entrypoint.rs b/governance/addin-mock/program/src/entrypoint.rs index af9e723dfd1..692954a81c9 100644 --- a/governance/addin-mock/program/src/entrypoint.rs +++ b/governance/addin-mock/program/src/entrypoint.rs @@ -1,13 +1,15 @@ //! Program entrypoint #![cfg(all(target_os = "solana", not(feature = "no-entrypoint")))] -use crate::{error::VoterWeightAddinError, processor}; -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, - program_error::PrintProgramError, pubkey::Pubkey, +use { + crate::{error::VoterWeightAddinError, processor}, + solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, program_error::PrintProgramError, + pubkey::Pubkey, + }, }; -entrypoint!(process_instruction); +solana_program::entrypoint!(process_instruction); fn process_instruction( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/governance/addin-mock/program/src/error.rs b/governance/addin-mock/program/src/error.rs index 0d17cf04aeb..0ce4bfd8643 100644 --- a/governance/addin-mock/program/src/error.rs +++ b/governance/addin-mock/program/src/error.rs @@ -1,12 +1,14 @@ //! Error types -use num_derive::FromPrimitive; -use solana_program::{ - decode_error::DecodeError, - msg, - program_error::{PrintProgramError, ProgramError}, +use { + num_derive::FromPrimitive, + solana_program::{ + decode_error::DecodeError, + msg, + program_error::{PrintProgramError, ProgramError}, + }, + thiserror::Error, }; -use thiserror::Error; /// Errors that may be returned by the VoterWeightAddin program #[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] diff --git a/governance/addin-mock/program/src/instruction.rs b/governance/addin-mock/program/src/instruction.rs index fe4d78d2213..65bc2d331fc 100644 --- a/governance/addin-mock/program/src/instruction.rs +++ b/governance/addin-mock/program/src/instruction.rs @@ -1,17 +1,20 @@ //! Program instructions -use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; -use solana_program::{ - clock::Slot, - instruction::{AccountMeta, Instruction}, - pubkey::Pubkey, - system_program, +use { + borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, + solana_program::{ + clock::Slot, + instruction::{AccountMeta, Instruction}, + pubkey::Pubkey, + system_program, + }, + spl_governance_addin_api::voter_weight::VoterWeightAction, }; -use spl_governance_addin_api::voter_weight::VoterWeightAction; /// Instructions supported by the VoterWeight addin program -/// This program is a mock program used by spl-governance for testing and not real addin -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +/// This program is a mock program used by spl-governance for testing and not +/// real addin +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] #[allow(clippy::large_enum_variant)] pub enum VoterWeightAddinInstruction { /// Sets up VoterWeightRecord owned by the program @@ -93,7 +96,7 @@ pub fn setup_voter_weight_record( Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), } } @@ -126,6 +129,6 @@ pub fn setup_max_voter_weight_record( Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), } } diff --git a/governance/addin-mock/program/src/lib.rs b/governance/addin-mock/program/src/lib.rs index 53b71f4a339..45f09c7507d 100644 --- a/governance/addin-mock/program/src/lib.rs +++ b/governance/addin-mock/program/src/lib.rs @@ -8,5 +8,6 @@ pub mod processor; //pub mod state; // pub mod tools; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version pub use solana_program; diff --git a/governance/addin-mock/program/src/processor.rs b/governance/addin-mock/program/src/processor.rs index f3c59d4e5ab..78856294e8c 100644 --- a/governance/addin-mock/program/src/processor.rs +++ b/governance/addin-mock/program/src/processor.rs @@ -1,22 +1,22 @@ //! Program processor -use borsh::BorshDeserialize; - -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - clock::Slot, - entrypoint::ProgramResult, - msg, - program_error::ProgramError, - pubkey::Pubkey, -}; -use spl_governance_addin_api::{ - max_voter_weight::MaxVoterWeightRecord, - voter_weight::{VoterWeightAction, VoterWeightRecord}, +use { + crate::instruction::VoterWeightAddinInstruction, + borsh::BorshDeserialize, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + clock::Slot, + entrypoint::ProgramResult, + msg, + program_error::ProgramError, + pubkey::Pubkey, + }, + spl_governance_addin_api::{ + max_voter_weight::MaxVoterWeightRecord, + voter_weight::{VoterWeightAction, VoterWeightRecord}, + }, + spl_governance_tools::account::create_and_serialize_account, }; -use spl_governance_tools::account::create_and_serialize_account; - -use crate::instruction::VoterWeightAddinInstruction; /// Processes an instruction pub fn process_instruction( diff --git a/governance/chat/program/Cargo.toml b/governance/chat/program/Cargo.toml index 9ef94fe17fd..a6315129bf8 100644 --- a/governance/chat/program/Cargo.toml +++ b/governance/chat/program/Cargo.toml @@ -1,41 +1,47 @@ [package] name = "spl-governance-chat" -version = "0.2.6" +version = "0.2.9" description = "Solana Program Library Governance Chat Program" -authors = ["Solana Maintainers "] +authors = ["Solana Labs Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" license = "Apache-2.0" -edition = "2018" +edition = "2021" [features] no-entrypoint = [] -test-bpf = [] +test-sbf = [] [dependencies] -arrayref = "0.3.6" +arrayref = "0.3.9" bincode = "1.3.2" -borsh = "0.9.1" -num-derive = "0.3" +borsh = "1.5.3" +num-derive = "0.4" num-traits = "0.2" -serde = "1.0.127" +serde = "1.0.217" serde_derive = "1.0.103" -solana-program = "1.10.33" -spl-token = { version = "3.3", path = "../../../token/program", features = [ "no-entrypoint" ] } -spl-governance= { version = "3.0.0", path ="../../program", features = [ "no-entrypoint" ]} -spl-governance-tools= { version = "0.1.2", path ="../../tools"} -spl-governance-addin-api= { version = "0.1.2", path ="../../addin-api"} -thiserror = "1.0" +solana-program = "2.1.0" +spl-token = { version = "7.0", features = [ + "no-entrypoint", +] } +spl-governance = { version = "4.0.0", path = "../../program", features = [ + "no-entrypoint", +] } +spl-governance-tools = { version = "0.1.4", path = "../../tools" } +spl-governance-addin-api = { version = "0.1.4", path = "../../addin-api" } +thiserror = "2.0" [dev-dependencies] assert_matches = "1.5.0" -base64 = "0.13" -proptest = "1.0" -solana-program-test = "1.10.33" -solana-sdk = "1.10.33" -spl-governance-test-sdk = { version = "0.1.2", path ="../../test-sdk"} -spl-governance-addin-mock = { version = "0.1.2", path ="../../addin-mock/program"} +proptest = "1.6" +solana-program-test = "2.1.0" +solana-sdk = "2.1.0" +spl-governance-test-sdk = { version = "0.1.4", path = "../../test-sdk" } +spl-governance-addin-mock = { version = "0.1.4", path = "../../addin-mock/program" } [lib] crate-type = ["cdylib", "lib"] + +[lints] +workspace = true diff --git a/governance/chat/program/src/entrypoint.rs b/governance/chat/program/src/entrypoint.rs index 92e0859237e..c7f4fa52a48 100644 --- a/governance/chat/program/src/entrypoint.rs +++ b/governance/chat/program/src/entrypoint.rs @@ -1,13 +1,15 @@ //! Program entrypoint #![cfg(all(target_os = "solana", not(feature = "no-entrypoint")))] -use crate::{error::GovernanceChatError, processor}; -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, - program_error::PrintProgramError, pubkey::Pubkey, +use { + crate::{error::GovernanceChatError, processor}, + solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, program_error::PrintProgramError, + pubkey::Pubkey, + }, }; -entrypoint!(process_instruction); +solana_program::entrypoint!(process_instruction); fn process_instruction( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/governance/chat/program/src/error.rs b/governance/chat/program/src/error.rs index 74e8dc10feb..8ce588df8fb 100644 --- a/governance/chat/program/src/error.rs +++ b/governance/chat/program/src/error.rs @@ -1,12 +1,14 @@ //! Error types -use num_derive::FromPrimitive; -use solana_program::{ - decode_error::DecodeError, - msg, - program_error::{PrintProgramError, ProgramError}, +use { + num_derive::FromPrimitive, + solana_program::{ + decode_error::DecodeError, + msg, + program_error::{PrintProgramError, ProgramError}, + }, + thiserror::Error, }; -use thiserror::Error; /// Errors that may be returned by the GovernanceChat program #[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] diff --git a/governance/chat/program/src/instruction.rs b/governance/chat/program/src/instruction.rs index 0c798f36b96..9dda2c36f20 100644 --- a/governance/chat/program/src/instruction.rs +++ b/governance/chat/program/src/instruction.rs @@ -1,31 +1,32 @@ //! Program instructions -use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; -use solana_program::{ - instruction::{AccountMeta, Instruction}, - pubkey::Pubkey, - system_program, +use { + crate::state::MessageBody, + borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, + solana_program::{ + instruction::{AccountMeta, Instruction}, + pubkey::Pubkey, + system_program, + }, + spl_governance::instruction::with_realm_config_accounts, }; -use spl_governance::instruction::with_realm_config_accounts; - -use crate::state::MessageBody; /// Instructions supported by the GovernanceChat program -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] #[allow(clippy::large_enum_variant)] pub enum GovernanceChatInstruction { /// Posts a message with a comment for a Proposal /// /// 0. `[]` Governance program id /// 1. `[]` Realm account of the Proposal - /// 2. `[]` Governance account the Proposal is for - /// 3. `[]` Proposal account + /// 2. `[]` Governance account the Proposal is for + /// 3. `[]` Proposal account /// 4. `[]` TokenOwnerRecord account for the message author /// 5. `[signer]` Governance Authority (TokenOwner or Governance Delegate) /// 6. `[writable, signer]` ChatMessage account - /// 7. `[signer]` Payer - /// 8. `[]` System program - /// 9. `[]` ReplyTo Message account (optional) + /// 7. `[signer]` Payer + /// 8. `[]` System program + /// 9. `[]` ReplyTo Message account (optional) /// 10. `[]` Optional Voter Weight Record PostMessage { #[allow(dead_code)] @@ -89,6 +90,6 @@ pub fn post_message( Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), } } diff --git a/governance/chat/program/src/lib.rs b/governance/chat/program/src/lib.rs index 3e314df865f..d361d608183 100644 --- a/governance/chat/program/src/lib.rs +++ b/governance/chat/program/src/lib.rs @@ -1,3 +1,4 @@ +#![allow(clippy::arithmetic_side_effects)] #![deny(missing_docs)] //! Governance Chat program @@ -7,5 +8,6 @@ pub mod instruction; pub mod processor; pub mod state; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version pub use solana_program; diff --git a/governance/chat/program/src/processor.rs b/governance/chat/program/src/processor.rs index 5ece332e3e4..df4f1b2eb38 100644 --- a/governance/chat/program/src/processor.rs +++ b/governance/chat/program/src/processor.rs @@ -1,27 +1,31 @@ //! Program processor -use crate::{ - error::GovernanceChatError, - instruction::GovernanceChatInstruction, - state::{assert_is_valid_chat_message, ChatMessage, GovernanceChatAccountType, MessageBody}, +use { + crate::{ + error::GovernanceChatError, + instruction::GovernanceChatInstruction, + state::{ + assert_is_valid_chat_message, ChatMessage, GovernanceChatAccountType, MessageBody, + }, + }, + borsh::BorshDeserialize, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + clock::Clock, + entrypoint::ProgramResult, + msg, + program_error::ProgramError, + pubkey::Pubkey, + sysvar::Sysvar, + }, + spl_governance::state::{ + governance::get_governance_data_for_realm, proposal::get_proposal_data_for_governance, + realm::get_realm_data, realm_config::get_realm_config_data_for_realm, + token_owner_record::get_token_owner_record_data_for_realm, + }, + spl_governance_addin_api::voter_weight::VoterWeightAction, + spl_governance_tools::account::create_and_serialize_account, }; -use borsh::BorshDeserialize; - -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - clock::Clock, - entrypoint::ProgramResult, - msg, - program_error::ProgramError, - pubkey::Pubkey, - sysvar::Sysvar, -}; -use spl_governance::state::{ - governance::get_governance_data_for_realm, proposal::get_proposal_data_for_governance, - realm::get_realm_data, token_owner_record::get_token_owner_record_data_for_realm, -}; -use spl_governance_addin_api::voter_weight::VoterWeightAction; -use spl_governance_tools::account::create_and_serialize_account; /// Processes an instruction pub fn process_instruction( @@ -85,28 +89,31 @@ pub fn process_post_message( token_owner_record_data.assert_token_owner_or_delegate_is_signer(governance_authority_info)?; - // deserialize proposal to assert it belongs to the given governance and hence belongs to the same realm as the token owner + // deserialize proposal to assert it belongs to the given governance and hence + // belongs to the same realm as the token owner let _proposal_data = get_proposal_data_for_governance( governance_program_id, proposal_info, governance_info.key, )?; - let realm_config_info = next_account_info(account_info_iter)?; //10 + let realm_config_info = next_account_info(account_info_iter)?; // 10 + + let realm_config_data = + get_realm_config_data_for_realm(governance_program_id, realm_config_info, realm_info.key)?; let voter_weight = token_owner_record_data.resolve_voter_weight( - governance_program_id, - realm_config_info, - account_info_iter, // 11 - realm_info.key, + account_info_iter, // voter_weight_record *11 &realm_data, + &realm_config_data, VoterWeightAction::CommentProposal, proposal_info.key, )?; // The owner needs to have at least voter weight of 1 to comment on proposals - // Note: It can be either community or council token and is irrelevant to the proposal's governing token - // Note: 1 is currently hardcoded but if different level is required then it should be added to realm config + // Note: It can be either community or council token and is irrelevant to the + // proposal's governing token Note: 1 is currently hardcoded but if + // different level is required then it should be added to realm config if voter_weight < 1 { return Err(GovernanceChatError::NotEnoughTokensToCommentProposal.into()); } diff --git a/governance/chat/program/src/state.rs b/governance/chat/program/src/state.rs index 9379271b246..10db01c95a8 100644 --- a/governance/chat/program/src/state.rs +++ b/governance/chat/program/src/state.rs @@ -1,14 +1,16 @@ //! Program state -use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; -use solana_program::{ - account_info::AccountInfo, clock::UnixTimestamp, program_error::ProgramError, pubkey::Pubkey, +use { + borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, + solana_program::{ + account_info::AccountInfo, clock::UnixTimestamp, program_error::ProgramError, + pubkey::Pubkey, + }, + spl_governance_tools::account::{assert_is_valid_account_of_type, AccountMaxSize}, }; -use spl_governance_tools::account::{assert_is_valid_account_of_type, AccountMaxSize}; - /// Defines all GovernanceChat accounts types -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum GovernanceChatAccountType { /// Default uninitialized account state Uninitialized, @@ -18,18 +20,19 @@ pub enum GovernanceChatAccountType { } /// Chat message body -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum MessageBody { /// Text message encoded as utf-8 string Text(String), /// Emoticon encoded using utf-8 characters - /// In the UI reactions are displayed together under the parent message (as opposed to hierarchical replies) + /// In the UI reactions are displayed together under the parent message (as + /// opposed to hierarchical replies) Reaction(String), } /// Chat message -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct ChatMessage { /// Account type pub account_type: GovernanceChatAccountType, @@ -61,7 +64,8 @@ impl AccountMaxSize for ChatMessage { } } -/// Checks whether Chat account exists, is initialized and owned by governance-chat program +/// Checks whether Chat account exists, is initialized and owned by +/// governance-chat program pub fn assert_is_valid_chat_message( program_id: &Pubkey, chat_message_info: &AccountInfo, @@ -88,7 +92,7 @@ mod test { reply_to: Some(Pubkey::new_unique()), body: MessageBody::Text("message".to_string()), }; - let size = message.try_to_vec().unwrap().len(); + let size = borsh::to_vec(&message).unwrap().len(); assert_eq!(message.get_max_size(), Some(size)); } diff --git a/governance/chat/program/tests/process_post_message.rs b/governance/chat/program/tests/process_post_message.rs index fa0945a23ea..2bf57fa986b 100644 --- a/governance/chat/program/tests/process_post_message.rs +++ b/governance/chat/program/tests/process_post_message.rs @@ -1,10 +1,10 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] -use program_test::GovernanceChatProgramTest; -use solana_program_test::tokio; -use solana_sdk::signature::Keypair; -use spl_governance::error::GovernanceError; -use spl_governance_chat::error::GovernanceChatError; +use { + program_test::GovernanceChatProgramTest, solana_program_test::tokio, + solana_sdk::signature::Keypair, spl_governance::error::GovernanceError, + spl_governance_chat::error::GovernanceChatError, +}; mod program_test; diff --git a/governance/chat/program/tests/program_test/cookies.rs b/governance/chat/program/tests/program_test/cookies.rs index deac7b87743..b46dffe16f4 100644 --- a/governance/chat/program/tests/program_test/cookies.rs +++ b/governance/chat/program/tests/program_test/cookies.rs @@ -1,6 +1,7 @@ -use solana_program::pubkey::Pubkey; -use solana_sdk::signature::Keypair; -use spl_governance_chat::state::ChatMessage; +use { + solana_program::pubkey::Pubkey, solana_sdk::signature::Keypair, + spl_governance_chat::state::ChatMessage, +}; #[derive(Debug)] pub struct ChatMessageCookie { diff --git a/governance/chat/program/tests/program_test/mod.rs b/governance/chat/program/tests/program_test/mod.rs index 29b7039ee93..1a9d532846a 100644 --- a/governance/chat/program/tests/program_test/mod.rs +++ b/governance/chat/program/tests/program_test/mod.rs @@ -1,33 +1,34 @@ -use std::str::FromStr; - -use solana_program::{program_error::ProgramError, pubkey::Pubkey}; -use solana_program_test::{processor, ProgramTest}; - -use solana_sdk::{signature::Keypair, signer::Signer}; -use spl_governance::{ - instruction::{ - create_governance, create_proposal, create_realm, create_token_owner_record, - deposit_governing_tokens, +use { + self::cookies::TokenOwnerRecordCookie, + crate::program_test::cookies::{ChatMessageCookie, ProposalCookie}, + solana_program::{program_error::ProgramError, pubkey::Pubkey}, + solana_program_test::{processor, ProgramTest}, + solana_sdk::{signature::Keypair, signer::Signer}, + spl_governance::{ + instruction::{ + create_governance, create_proposal, create_realm, create_token_owner_record, + deposit_governing_tokens, + }, + state::{ + enums::{MintMaxVoterWeightSource, VoteThreshold}, + governance::{ + get_governance_address, GovernanceConfig, DEFAULT_DEPOSIT_EXEMPT_PROPOSAL_COUNT, + }, + proposal::{get_proposal_address, VoteType}, + realm::{get_realm_address, GoverningTokenConfigAccountArgs}, + realm_config::GoverningTokenType, + token_owner_record::get_token_owner_record_address, + }, }, - state::{ - enums::{MintMaxVoteWeightSource, VoteThreshold}, - governance::{get_governance_address, GovernanceConfig}, - proposal::{get_proposal_address, VoteType}, - realm::get_realm_address, - token_owner_record::get_token_owner_record_address, + spl_governance_addin_mock::instruction::setup_voter_weight_record, + spl_governance_chat::{ + instruction::post_message, + processor::process_instruction, + state::{ChatMessage, GovernanceChatAccountType, MessageBody}, }, + spl_governance_test_sdk::{addins::ensure_addin_mock_is_built, ProgramTestBench}, + std::str::FromStr, }; -use spl_governance_addin_mock::instruction::setup_voter_weight_record; -use spl_governance_chat::{ - instruction::post_message, - processor::process_instruction, - state::{ChatMessage, GovernanceChatAccountType, MessageBody}, -}; -use spl_governance_test_sdk::{addins::ensure_addin_mock_is_built, ProgramTestBench}; - -use crate::program_test::cookies::{ChatMessageCookie, ProposalCookie}; - -use self::cookies::TokenOwnerRecordCookie; pub mod cookies; @@ -108,17 +109,23 @@ impl GovernanceChatProgramTest { let realm_authority = Keypair::new(); + let community_token_config_args = GoverningTokenConfigAccountArgs { + voter_weight_addin: self.voter_weight_addin_id, + max_voter_weight_addin: None, + token_type: GoverningTokenType::default(), + }; + let create_realm_ix = create_realm( &self.governance_program_id, &realm_authority.pubkey(), &governing_token_mint_keypair.pubkey(), &self.bench.payer.pubkey(), None, - self.voter_weight_addin_id, + Some(community_token_config_args), None, name.clone(), 1, - MintMaxVoteWeightSource::FULL_SUPPLY_FRACTION, + MintMaxVoterWeightSource::FULL_SUPPLY_FRACTION, ); self.bench @@ -176,17 +183,21 @@ impl GovernanceChatProgramTest { } // Create Governance - let governed_account_address = Pubkey::new_unique(); + let governance_seed = Pubkey::new_unique(); let governance_config = GovernanceConfig { - min_community_weight_to_create_proposal: 5, - min_council_weight_to_create_proposal: 2, - min_transaction_hold_up_time: 10, - max_voting_time: 10, community_vote_threshold: VoteThreshold::YesVotePercentage(60), - vote_tipping: spl_governance::state::enums::VoteTipping::Strict, + min_community_weight_to_create_proposal: 5, + transactions_hold_up_time: 10, + voting_base_time: 10, + community_vote_tipping: spl_governance::state::enums::VoteTipping::Strict, council_vote_threshold: VoteThreshold::YesVotePercentage(10), council_veto_vote_threshold: VoteThreshold::YesVotePercentage(50), + min_council_weight_to_create_proposal: 2, + council_vote_tipping: spl_governance::state::enums::VoteTipping::Strict, + community_veto_vote_threshold: VoteThreshold::YesVotePercentage(55), + voting_cool_off_time: 1, + deposit_exempt_proposal_count: DEFAULT_DEPOSIT_EXEMPT_PROPOSAL_COUNT, }; let token_owner_record_address = get_token_owner_record_address( @@ -224,7 +235,7 @@ impl GovernanceChatProgramTest { let create_governance_ix = create_governance( &self.governance_program_id, &realm_address, - Some(&governed_account_address), + &governance_seed, &token_owner_record_address, &self.bench.payer.pubkey(), &token_owner.pubkey(), @@ -242,14 +253,15 @@ impl GovernanceChatProgramTest { let governance_address = get_governance_address( &self.governance_program_id, &realm_address, - &governed_account_address, + &governance_seed, ); let proposal_name = "Proposal #1".to_string(); let description_link = "Proposal Description".to_string(); let options = vec!["Yes".to_string()]; - let proposal_index: u32 = 0; + let use_deny_option = true; + let proposal_seed = Pubkey::new_unique(); let create_proposal_ix = create_proposal( &self.governance_program_id, @@ -265,7 +277,7 @@ impl GovernanceChatProgramTest { VoteType::SingleChoice, options, use_deny_option, - proposal_index, + &proposal_seed, ); self.bench @@ -277,7 +289,7 @@ impl GovernanceChatProgramTest { &self.governance_program_id, &governance_address, &governing_token_mint_keypair.pubkey(), - &proposal_index.to_le_bytes(), + &proposal_seed, ); ProposalCookie { @@ -287,7 +299,7 @@ impl GovernanceChatProgramTest { token_owner_record_address, token_owner, governing_token_mint: governing_token_mint_keypair.pubkey(), - governing_token_mint_authority: governing_token_mint_authority, + governing_token_mint_authority, voter_weight_record, } } diff --git a/governance/program/Cargo.toml b/governance/program/Cargo.toml index 1bf5f482dd1..fd553380c3d 100644 --- a/governance/program/Cargo.toml +++ b/governance/program/Cargo.toml @@ -1,39 +1,44 @@ [package] name = "spl-governance" -version = "3.0.0" +version = "4.0.0" description = "Solana Program Library Governance Program" -authors = ["Solana Maintainers "] +authors = ["Solana Labs Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" license = "Apache-2.0" -edition = "2018" +edition = "2021" [features] no-entrypoint = [] -test-bpf = [] +test-sbf = [] [dependencies] -arrayref = "0.3.6" +arrayref = "0.3.9" bincode = "1.3.2" -borsh = "0.9.1" -num-derive = "0.3" +borsh = "1.5.3" +num-derive = "0.4" num-traits = "0.2" -serde = "1.0.130" +serde = "1.0.217" serde_derive = "1.0.103" -solana-program = "1.10.33" -spl-token = { version = "3.3", path = "../../token/program", features = [ "no-entrypoint" ] } -spl-governance-tools= { version = "0.1.2", path ="../tools"} -spl-governance-addin-api= { version = "0.1.2", path ="../addin-api"} -thiserror = "1.0" +solana-program = "2.1.0" +spl-token = { version = "7.0", features = [ + "no-entrypoint", +] } +spl-governance-tools = { version = "0.1.4", path = "../tools" } +spl-governance-addin-api = { version = "0.1.4", path = "../addin-api" } +thiserror = "2.0" [dev-dependencies] assert_matches = "1.5.0" -base64 = "0.13" -proptest = "1.0" -solana-program-test = "1.10.33" -solana-sdk = "1.10.33" -spl-governance-test-sdk = { version = "0.1.2", path ="../test-sdk"} -spl-governance-addin-mock = { version = "0.1.2", path ="../addin-mock/program"} +base64 = "0.22" +proptest = "1.6" +solana-program-test = "2.1.0" +solana-sdk = "2.1.0" +spl-governance-test-sdk = { version = "0.1.4", path = "../test-sdk" } +spl-governance-addin-mock = { version = "0.1.4", path = "../addin-mock/program" } [lib] crate-type = ["cdylib", "lib"] + +[lints] +workspace = true diff --git a/governance/program/src/addins/max_voter_weight.rs b/governance/program/src/addins/max_voter_weight.rs index 20ad52a6961..7840c60f6bd 100644 --- a/governance/program/src/addins/max_voter_weight.rs +++ b/governance/program/src/addins/max_voter_weight.rs @@ -1,13 +1,14 @@ //! MaxVoterWeight Addin interface -use solana_program::{ - account_info::AccountInfo, clock::Clock, program_error::ProgramError, pubkey::Pubkey, - sysvar::Sysvar, +use { + crate::error::GovernanceError, + solana_program::{ + account_info::AccountInfo, clock::Clock, program_error::ProgramError, pubkey::Pubkey, + sysvar::Sysvar, + }, + spl_governance_addin_api::max_voter_weight::MaxVoterWeightRecord, + spl_governance_tools::account::get_account_data, }; -use spl_governance_addin_api::max_voter_weight::MaxVoterWeightRecord; -use spl_governance_tools::account::get_account_data; - -use crate::error::GovernanceError; /// Asserts MaxVoterWeightRecord hasn't expired pub fn assert_is_valid_max_voter_weight( @@ -33,7 +34,8 @@ pub fn get_max_voter_weight_record_data( get_account_data::(program_id, max_voter_weight_record_info) } -/// Deserializes MaxVoterWeightRecord account, checks owner program and asserts it's for the given realm and governing_token_mint +/// Deserializes MaxVoterWeightRecord account, checks owner program and asserts +/// it's for the given realm and governing_token_mint pub fn get_max_voter_weight_record_data_for_realm_and_governing_token_mint( program_id: &Pubkey, max_voter_weight_record_info: &AccountInfo, diff --git a/governance/program/src/addins/voter_weight.rs b/governance/program/src/addins/voter_weight.rs index fddc931735a..91608f74c82 100644 --- a/governance/program/src/addins/voter_weight.rs +++ b/governance/program/src/addins/voter_weight.rs @@ -1,15 +1,17 @@ //! VoterWeight Addin interface -use solana_program::{ - account_info::AccountInfo, clock::Clock, program_error::ProgramError, pubkey::Pubkey, - sysvar::Sysvar, +use { + crate::{error::GovernanceError, state::token_owner_record::TokenOwnerRecordV2}, + solana_program::{ + account_info::AccountInfo, clock::Clock, program_error::ProgramError, pubkey::Pubkey, + sysvar::Sysvar, + }, + spl_governance_addin_api::voter_weight::{VoterWeightAction, VoterWeightRecord}, + spl_governance_tools::account::get_account_data, }; -use spl_governance_addin_api::voter_weight::{VoterWeightAction, VoterWeightRecord}; -use spl_governance_tools::account::get_account_data; -use crate::{error::GovernanceError, state::token_owner_record::TokenOwnerRecordV2}; - -/// Asserts the VoterWeightRecord hasn't expired and matches the given action and target if specified +/// Asserts the VoterWeightRecord hasn't expired and matches the given action +/// and target if specified pub fn assert_is_valid_voter_weight( voter_weight_record: &VoterWeightRecord, weight_action: VoterWeightAction, @@ -49,7 +51,9 @@ pub fn get_voter_weight_record_data( get_account_data::(program_id, voter_weight_record_info) } -/// Deserializes VoterWeightRecord account, checks owner program and asserts it's for the same realm, mint and token owner as the provided TokenOwnerRecord +/// Deserializes VoterWeightRecord account, checks owner program and asserts +/// it's for the same realm, mint and token owner as the provided +/// TokenOwnerRecord pub fn get_voter_weight_record_data_for_token_owner_record( program_id: &Pubkey, voter_weight_record_info: &AccountInfo, diff --git a/governance/program/src/entrypoint.rs b/governance/program/src/entrypoint.rs index 26c75d468a8..ce0d8210a87 100644 --- a/governance/program/src/entrypoint.rs +++ b/governance/program/src/entrypoint.rs @@ -1,13 +1,15 @@ //! Program entrypoint definitions #![cfg(all(target_os = "solana", not(feature = "no-entrypoint")))] -use crate::{error::GovernanceError, processor}; -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, - program_error::PrintProgramError, pubkey::Pubkey, +use { + crate::{error::GovernanceError, processor}, + solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, program_error::PrintProgramError, + pubkey::Pubkey, + }, }; -entrypoint!(process_instruction); +solana_program::entrypoint!(process_instruction); fn process_instruction( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/governance/program/src/error.rs b/governance/program/src/error.rs index 3bbf79b1743..9ddcc834bd3 100644 --- a/governance/program/src/error.rs +++ b/governance/program/src/error.rs @@ -1,19 +1,23 @@ //! Error types -use num_derive::FromPrimitive; -use solana_program::{ - decode_error::DecodeError, - msg, - program_error::{PrintProgramError, ProgramError}, +use { + num_derive::FromPrimitive, + solana_program::{ + decode_error::DecodeError, + msg, + program_error::{PrintProgramError, ProgramError}, + }, + thiserror::Error, }; -use thiserror::Error; /// Errors that may be returned by the Governance program +// Start Governance custom errors from 500 to avoid conflicts with programs +// invoked via CPI #[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] pub enum GovernanceError { /// Invalid instruction passed to program #[error("Invalid instruction passed to program")] - InvalidInstruction = 500, // Start Governance custom errors from 500 to avoid conflicts with programs invoked via CPI + InvalidInstruction = 500, /// Realm with the given name and governing mints already exists #[error("Realm with the given name and governing mints already exists")] @@ -83,7 +87,8 @@ pub enum GovernanceError { #[error("Invalid Governance config: Vote threshold percentage out of range")] InvalidVoteThresholdPercentage, // 517 - /// Proposal for the given Governance, Governing Token Mint and index already exists + /// Proposal for the given Governance, Governing Token Mint and index + /// already exists #[error("Proposal for the given Governance, Governing Token Mint and index already exists")] ProposalAlreadyExists, // 518 @@ -123,9 +128,9 @@ pub enum GovernanceError { #[error("Invalid Transaction index")] InvalidTransactionIndex, // 527 - /// Transaction hold up time is below the min specified by Governance - #[error("Transaction hold up time is below the min specified by Governance")] - TransactionHoldUpTimeBelowRequiredMin, // 528 + /// Legacy TransactionHoldUpTimeBelowRequiredMin + #[error("Legacy3")] + Legacy3, // 528 /// Transaction at the given index for the Proposal already exists #[error("Transaction at the given index for the Proposal already exists")] @@ -137,31 +142,31 @@ pub enum GovernanceError { /// Invalid State: Can't vote #[error("Invalid State: Can't vote")] - InvalidStateCannotVote, + InvalidStateCannotVote, // 531 /// Invalid State: Can't finalize vote #[error("Invalid State: Can't finalize vote")] - InvalidStateCannotFinalize, + InvalidStateCannotFinalize, // 532 /// Invalid State: Can't cancel Proposal #[error("Invalid State: Can't cancel Proposal")] - InvalidStateCannotCancelProposal, + InvalidStateCannotCancelProposal, // 533 /// Vote already relinquished #[error("Vote already relinquished")] - VoteAlreadyRelinquished, + VoteAlreadyRelinquished, // 534 /// Can't finalize vote. Voting still in progress #[error("Can't finalize vote. Voting still in progress")] - CannotFinalizeVotingInProgress, + CannotFinalizeVotingInProgress, // 535 /// Proposal voting time expired #[error("Proposal voting time expired")] - ProposalVotingTimeExpired, + ProposalVotingTimeExpired, // 536 /// Invalid Signatory Mint #[error("Invalid Signatory Mint")] - InvalidSignatoryMint, + InvalidSignatoryMint, // 537 /// Proposal does not belong to the given Governance #[error("Proposal does not belong to the given Governance")] @@ -227,7 +232,8 @@ pub enum GovernanceError { #[error("Invalid ProgramData account Data")] InvalidProgramDataAccountData, // 552 - /// Provided upgrade authority doesn't match current program upgrade authority + /// Provided upgrade authority doesn't match current program upgrade + /// authority #[error("Provided upgrade authority doesn't match current program upgrade authority")] InvalidUpgradeAuthority, // 553 @@ -255,29 +261,29 @@ pub enum GovernanceError { #[error("Given VoteWeightSource is not supported")] VoteWeightSourceNotSupported, // 559 - /// GoverningTokenMint not allowed to vote - #[error("GoverningTokenMint not allowed to vote")] - GoverningTokenMintNotAllowedToVote, // 560 + /// Legacy1 + #[error("Legacy1")] + Legacy1, // 560 /// Governance PDA must sign #[error("Governance PDA must sign")] - GovernancePdaMustSign, + GovernancePdaMustSign, // 561 - /// Transaction already flagged with error - #[error("Transaction already flagged with error")] - TransactionAlreadyFlaggedWithError, + /// Previously TransactionAlreadyFlaggedWithError + #[error("Legacy2")] + Legacy2, // 562 /// Invalid Realm for Governance #[error("Invalid Realm for Governance")] - InvalidRealmForGovernance, + InvalidRealmForGovernance, // 563 /// Invalid Authority for Realm #[error("Invalid Authority for Realm")] - InvalidAuthorityForRealm, + InvalidAuthorityForRealm, // 564 /// Realm has no authority #[error("Realm has no authority")] - RealmHasNoAuthority, + RealmHasNoAuthority, // 565 /// Realm authority must sign #[error("Realm authority must sign")] @@ -285,127 +291,263 @@ pub enum GovernanceError { /// Invalid governing token holding account #[error("Invalid governing token holding account")] - InvalidGoverningTokenHoldingAccount, + InvalidGoverningTokenHoldingAccount, // 567 /// Realm council mint change is not supported #[error("Realm council mint change is not supported")] - RealmCouncilMintChangeIsNotSupported, + RealmCouncilMintChangeIsNotSupported, // 568 - /// Not supported mint max vote weight sourcef - #[error("Not supported mint max vote weight source")] - MintMaxVoteWeightSourceNotSupported, + /// Invalid max voter weight absolute value + #[error("Invalid max voter weight absolute value")] + InvalidMaxVoterWeightAbsoluteValue, // 569 - /// Invalid max vote weight supply fraction - #[error("Invalid max vote weight supply fraction")] - InvalidMaxVoteWeightSupplyFraction, + /// Invalid max voter weight supply fraction + #[error("Invalid max voter weight supply fraction")] + InvalidMaxVoterWeightSupplyFraction, // 570 /// Owner doesn't have enough governing tokens to create Governance #[error("Owner doesn't have enough governing tokens to create Governance")] - NotEnoughTokensToCreateGovernance, + NotEnoughTokensToCreateGovernance, // 571 /// Too many outstanding proposals #[error("Too many outstanding proposals")] - TooManyOutstandingProposals, + TooManyOutstandingProposals, // 572 /// All proposals must be finalized to withdraw governing tokens #[error("All proposals must be finalized to withdraw governing tokens")] - AllProposalsMustBeFinalisedToWithdrawGoverningTokens, + AllProposalsMustBeFinalisedToWithdrawGoverningTokens, // 573 /// Invalid VoterWeightRecord for Realm #[error("Invalid VoterWeightRecord for Realm")] - InvalidVoterWeightRecordForRealm, + InvalidVoterWeightRecordForRealm, // 574 /// Invalid VoterWeightRecord for GoverningTokenMint #[error("Invalid VoterWeightRecord for GoverningTokenMint")] - InvalidVoterWeightRecordForGoverningTokenMint, + InvalidVoterWeightRecordForGoverningTokenMint, // 575 /// Invalid VoterWeightRecord for TokenOwner #[error("Invalid VoterWeightRecord for TokenOwner")] - InvalidVoterWeightRecordForTokenOwner, + InvalidVoterWeightRecordForTokenOwner, // 576 /// VoterWeightRecord expired #[error("VoterWeightRecord expired")] - VoterWeightRecordExpired, + VoterWeightRecordExpired, // 577 /// Invalid RealmConfig for Realm #[error("Invalid RealmConfig for Realm")] - InvalidRealmConfigForRealm, + InvalidRealmConfigForRealm, // 578 /// TokenOwnerRecord already exists #[error("TokenOwnerRecord already exists")] - TokenOwnerRecordAlreadyExists, + TokenOwnerRecordAlreadyExists, // 579 /// Governing token deposits not allowed #[error("Governing token deposits not allowed")] - GoverningTokenDepositsNotAllowed, + GoverningTokenDepositsNotAllowed, // 580 /// Invalid vote choice weight percentage #[error("Invalid vote choice weight percentage")] - InvalidVoteChoiceWeightPercentage, + InvalidVoteChoiceWeightPercentage, // 581 /// Vote type not supported #[error("Vote type not supported")] - VoteTypeNotSupported, + VoteTypeNotSupported, // 582 /// InvalidProposalOptions #[error("Invalid proposal options")] - InvalidProposalOptions, + InvalidProposalOptions, // 583 - /// Proposal is not not executable - #[error("Proposal is not not executable")] - ProposalIsNotExecutable, + /// Proposal is not executable + #[error("Proposal is not executable")] + ProposalIsNotExecutable, // 584 - /// Invalid vote - #[error("Invalid vote")] - InvalidVote, + /// Deny vote is not allowed + #[error("Deny vote is not allowed")] + DenyVoteIsNotAllowed, // 585 /// Cannot execute defeated option #[error("Cannot execute defeated option")] - CannotExecuteDefeatedOption, + CannotExecuteDefeatedOption, // 586 /// VoterWeightRecord invalid action #[error("VoterWeightRecord invalid action")] - VoterWeightRecordInvalidAction, + VoterWeightRecordInvalidAction, // 587 /// VoterWeightRecord invalid action target #[error("VoterWeightRecord invalid action target")] - VoterWeightRecordInvalidActionTarget, + VoterWeightRecordInvalidActionTarget, // 588 /// Invalid MaxVoterWeightRecord for Realm #[error("Invalid MaxVoterWeightRecord for Realm")] - InvalidMaxVoterWeightRecordForRealm, + InvalidMaxVoterWeightRecordForRealm, // 589 /// Invalid MaxVoterWeightRecord for GoverningTokenMint #[error("Invalid MaxVoterWeightRecord for GoverningTokenMint")] - InvalidMaxVoterWeightRecordForGoverningTokenMint, + InvalidMaxVoterWeightRecordForGoverningTokenMint, // 590 /// MaxVoterWeightRecord expired #[error("MaxVoterWeightRecord expired")] - MaxVoterWeightRecordExpired, + MaxVoterWeightRecordExpired, // 591 /// Not supported VoteType #[error("Not supported VoteType")] - NotSupportedVoteType, + NotSupportedVoteType, // 592 /// RealmConfig change not allowed #[error("RealmConfig change not allowed")] - RealmConfigChangeNotAllowed, + RealmConfigChangeNotAllowed, // 593 /// GovernanceConfig change not allowed #[error("GovernanceConfig change not allowed")] - GovernanceConfigChangeNotAllowed, + GovernanceConfigChangeNotAllowed, // 594 /// At least one VoteThreshold is required #[error("At least one VoteThreshold is required")] - AtLeastOneVoteThresholdRequired, + AtLeastOneVoteThresholdRequired, // 595 /// Reserved buffer must be empty #[error("Reserved buffer must be empty")] - ReservedBufferMustBeEmpty, + ReservedBufferMustBeEmpty, // 596 /// Cannot Relinquish in Finalizing state #[error("Cannot Relinquish in Finalizing state")] - CannotRelinquishInFinalizingState, + CannotRelinquishInFinalizingState, // 597 + + /// Invalid RealmConfig account address + #[error("Invalid RealmConfig account address")] + InvalidRealmConfigAddress, // 598 + + /// Cannot deposit dormant tokens + #[error("Cannot deposit dormant tokens")] + CannotDepositDormantTokens, // 599 + + /// Cannot withdraw membership tokens + #[error("Cannot withdraw membership tokens")] + CannotWithdrawMembershipTokens, // 600 + + /// Cannot revoke GoverningTokens + #[error("Cannot revoke GoverningTokens")] + CannotRevokeGoverningTokens, // 601 + + /// Invalid Revoke amount + #[error("Invalid Revoke amount")] + InvalidRevokeAmount, // 602 + + /// Invalid GoverningToken source + #[error("Invalid GoverningToken source")] + InvalidGoverningTokenSource, // 603 + + /// Cannot change community TokenType to Membership + #[error("Cannot change community TokenType to Membership")] + CannotChangeCommunityTokenTypeToMembership, // 604 + + /// Voter weight threshold disabled + #[error("Voter weight threshold disabled")] + VoterWeightThresholdDisabled, // 605 + + /// Vote not allowed in cool off time + #[error("Vote not allowed in cool off time")] + VoteNotAllowedInCoolOffTime, // 606 + + /// Cannot refund ProposalDeposit + #[error("Cannot refund ProposalDeposit")] + CannotRefundProposalDeposit, // 607 + + ///Invalid Proposal for ProposalDeposit + #[error("Invalid Proposal for ProposalDeposit")] + InvalidProposalForProposalDeposit, // 608 + + /// Invalid deposit_exempt_proposal_count + #[error("Invalid deposit_exempt_proposal_count")] + InvalidDepositExemptProposalCount, // 609 + + /// GoverningTokenMint not allowed to vote + #[error("GoverningTokenMint not allowed to vote")] + GoverningTokenMintNotAllowedToVote, // 610 + + ///Invalid deposit Payer for ProposalDeposit + #[error("Invalid deposit Payer for ProposalDeposit")] + InvalidDepositPayerForProposalDeposit, // 611 + + /// Invalid State: Proposal is not in final state + #[error("Invalid State: Proposal is not in final state")] + InvalidStateNotFinal, // 612 + + ///Invalid state for proposal state transition to Completed + #[error("Invalid state for proposal state transition to Completed")] + InvalidStateToCompleteProposal, // 613 + + /// Invalid number of vote choices + #[error("Invalid number of vote choices")] + InvalidNumberOfVoteChoices, // 614 + + /// Ranked vote is not supported + #[error("Ranked vote is not supported")] + RankedVoteIsNotSupported, // 615 + + /// Choice weight must be 100% + #[error("Choice weight must be 100%")] + ChoiceWeightMustBe100Percent, // 616 + + /// Single choice only is allowed + #[error("Single choice only is allowed")] + SingleChoiceOnlyIsAllowed, // 617 + + /// At least single choice is required + #[error("At least single choice is required")] + AtLeastSingleChoiceIsRequired, // 618 + + /// Total vote weight must be 100% + #[error("Total vote weight must be 100%")] + TotalVoteWeightMustBe100Percent, // 619 + + /// Invalid multi choice proposal parameters + #[error("Invalid multi choice proposal parameters")] + InvalidMultiChoiceProposalParameters, // 620 + + /// Invalid Governance for RequiredSignatory + #[error("Invalid Governance for RequiredSignatory")] + InvalidGovernanceForRequiredSignatory, // 621 + + /// SignatoryRecord already exists + #[error("Signatory Record has already been created")] + SignatoryRecordAlreadyExists, // 622 + + /// Instruction has been removed + #[error("Instruction has been removed")] + InstructionDeprecated, // 623 + + /// Proposal is missing signatories required by its governance + #[error("Proposal is missing required signatories")] + MissingRequiredSignatories, // 624 + + /// TokenOwnerRecordLock authority must sign + #[error("TokenOwnerRecordLock authority must sign")] + TokenOwnerRecordLockAuthorityMustSign, // 625 + + /// TokenOwnerRecordLock is expired + #[error("TokenOwnerRecordLock is expired ")] + ExpiredTokenOwnerRecordLock, // 626 + + /// TokenOwnerRecord locked + #[error("TokenOwnerRecord locked")] + TokenOwnerRecordLocked, // 627 + + /// Invalid TokenOwnerRecordLockAuthority + #[error("Invalid TokenOwnerRecordLockAuthority")] + InvalidTokenOwnerRecordLockAuthority, // 628 + + /// TokenOwnerRecordLock authority already exists + #[error("TokenOwnerRecordLock authority already exists")] + TokenOwnerRecordLockAuthorityAlreadyExists, // 629 + + /// TokenOwnerRecordLock not found + #[error("TokenOwnerRecordLock not found")] + TokenOwnerRecordLockNotFound, // 630 + + /// TokenOwnerRecordLockAuthority not found + #[error("TokenOwnerRecordLockAuthority not found")] + TokenOwnerRecordLockAuthorityNotFound, // 631 } impl PrintProgramError for GovernanceError { diff --git a/governance/program/src/instruction.rs b/governance/program/src/instruction.rs index 72bd717e542..a344f0099dc 100644 --- a/governance/program/src/instruction.rs +++ b/governance/program/src/instruction.rs @@ -1,102 +1,131 @@ //! Program instructions -use crate::{ - state::{ - enums::MintMaxVoteWeightSource, - governance::{ - get_governance_address, get_mint_governance_address, get_program_governance_address, - get_token_governance_address, GovernanceConfig, - }, +use { + crate::state::{ + enums::MintMaxVoterWeightSource, + governance::{get_governance_address, GovernanceConfig}, native_treasury::get_native_treasury_address, program_metadata::get_program_metadata_address, proposal::{get_proposal_address, VoteType}, + proposal_deposit::get_proposal_deposit_address, proposal_transaction::{get_proposal_transaction_address, InstructionData}, - realm::SetRealmAuthorityAction, - realm::{get_governing_token_holding_address, get_realm_address, RealmConfigArgs}, + realm::{ + get_governing_token_holding_address, get_realm_address, + GoverningTokenConfigAccountArgs, GoverningTokenConfigArgs, RealmConfigArgs, + SetRealmAuthorityAction, SetRealmConfigItemArgs, + }, realm_config::get_realm_config_address, + required_signatory::get_required_signatory_address, signatory_record::get_signatory_record_address, token_owner_record::get_token_owner_record_address, vote_record::{get_vote_record_address, Vote}, }, - tools::bpf_loader_upgradeable::get_program_data_address, -}; -use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; -use solana_program::{ - bpf_loader_upgradeable, - instruction::{AccountMeta, Instruction}, - pubkey::Pubkey, - system_program, sysvar, + borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, + solana_program::{ + clock::UnixTimestamp, + instruction::{AccountMeta, Instruction}, + pubkey::Pubkey, + system_program, sysvar, + }, }; /// Instructions supported by the Governance program -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] #[allow(clippy::large_enum_variant)] pub enum GovernanceInstruction { - /// Creates Governance Realm account which aggregates governances for given Community Mint and optional Council Mint + /// Creates Governance Realm account which aggregates governances for given + /// Community Mint and optional Council Mint /// - /// 0. `[writable]` Governance Realm account. PDA seeds:['governance',name] + /// 0. `[writable]` Governance Realm account. + /// * PDA seeds:['governance',name] /// 1. `[]` Realm authority /// 2. `[]` Community Token Mint - /// 3. `[writable]` Community Token Holding account. PDA seeds: ['governance',realm,community_mint] + /// 3. `[writable]` Community Token Holding account. + /// * PDA seeds: ['governance',realm,community_mint] /// The account will be created with the Realm PDA as its owner /// 4. `[signer]` Payer /// 5. `[]` System /// 6. `[]` SPL Token /// 7. `[]` Sysvar Rent - /// 8. `[]` Council Token Mint - optional - /// 9. `[writable]` Council Token Holding account - optional unless council is used. PDA seeds: ['governance',realm,council_mint] + /// 9. `[writable]` Council Token Holding account - optional unless council + /// is used. + /// * PDA seeds: ['governance',realm,council_mint] /// The account will be created with the Realm PDA as its owner - - /// 10. `[]` Optional Community Voter Weight Addin Program Id - /// 11. `[]` Optional Max Community Voter Weight Addin Program Id - /// 12. `[writable]` Optional RealmConfig account. PDA seeds: ['realm-config', realm] + /// 10. `[writable]` RealmConfig account. + /// * PDA seeds: ['realm-config', realm] + /// 11. `[]` Optional Community Voter Weight Addin Program Id + /// 12. `[]` Optional Max Community Voter Weight Addin Program Id + /// 13. `[]` Optional Council Voter Weight Addin Program Id + /// 14. `[]` Optional Max Council Voter Weight Addin Program Id CreateRealm { #[allow(dead_code)] /// UTF-8 encoded Governance Realm name name: String, #[allow(dead_code)] - /// Realm config args + /// Realm config args config_args: RealmConfigArgs, }, - /// Deposits governing tokens (Community or Council) to Governance Realm and establishes your voter weight to be used for voting within the Realm - /// Note: If subsequent (top up) deposit is made and there are active votes for the Voter then the vote weights won't be updated automatically - /// It can be done by relinquishing votes on active Proposals and voting again with the new weight + /// Deposits governing tokens (Community or Council) to Governance Realm and + /// establishes your voter weight to be used for voting within the Realm + /// Note: If subsequent (top up) deposit is made and there are active votes + /// for the Voter then the vote weights won't be updated automatically + /// It can be done by relinquishing votes on active Proposals and voting + /// again with the new weight /// - /// 0. `[]` Governance Realm account - /// 1. `[writable]` Governing Token Holding account. PDA seeds: ['governance',realm, governing_token_mint] - /// 2. `[writable]` Governing Token Source account. All tokens from the account will be transferred to the Holding account + /// 0. `[]` Realm account + /// 1. `[writable]` Governing Token Holding account. + /// * PDA seeds: ['governance',realm, governing_token_mint] + /// 2. `[writable]` Governing Token Source account. It can be either + /// spl-token TokenAccount or MintAccount Tokens will be transferred or + /// minted to the Holding account /// 3. `[signer]` Governing Token Owner account - /// 4. `[signer]` Governing Token Transfer authority - /// 5. `[writable]` Token Owner Record account. PDA seeds: ['governance',realm, governing_token_mint, governing_token_owner] + /// 4. `[signer]` Governing Token Source account authority It should be + /// owner for TokenAccount and mint_authority for MintAccount + /// 5. `[writable]` TokenOwnerRecord account. + /// * PDA seeds: ['governance',realm, governing_token_mint, + /// governing_token_owner] /// 6. `[signer]` Payer /// 7. `[]` System - /// 8. `[]` SPL Token - /// 9. `[]` Sysvar Rent + /// 8. `[]` SPL Token program + /// 9. `[]` RealmConfig account. + /// * PDA seeds: ['realm-config', realm] DepositGoverningTokens { /// The amount to deposit into the realm #[allow(dead_code)] amount: u64, }, - /// Withdraws governing tokens (Community or Council) from Governance Realm and downgrades your voter weight within the Realm - /// Note: It's only possible to withdraw tokens if the Voter doesn't have any outstanding active votes - /// If there are any outstanding votes then they must be relinquished before tokens could be withdrawn + /// Withdraws governing tokens (Community or Council) from Governance Realm + /// and downgrades your voter weight within the Realm. + /// Note: It's only possible to withdraw tokens if the Voter doesn't have + /// any outstanding active votes. + /// If there are any outstanding votes then they must be relinquished + /// before tokens could be withdrawn /// - /// 0. `[]` Governance Realm account - /// 1. `[writable]` Governing Token Holding account. PDA seeds: ['governance',realm, governing_token_mint] - /// 2. `[writable]` Governing Token Destination account. All tokens will be transferred to this account + /// 0. `[]` Realm account + /// 1. `[writable]` Governing Token Holding account. + /// * PDA seeds: ['governance',realm, governing_token_mint] + /// 2. `[writable]` Governing Token Destination account. All tokens will be + /// transferred to this account /// 3. `[signer]` Governing Token Owner account - /// 4. `[writable]` Token Owner Record account. PDA seeds: ['governance',realm, governing_token_mint, governing_token_owner] - /// 5. `[]` SPL Token + /// 4. `[writable]` TokenOwnerRecord account. + /// * PDA seeds: ['governance',realm, governing_token_mint, + /// governing_token_owner] + /// 5. `[]` SPL Token program + /// 6. `[]` RealmConfig account. + /// * PDA seeds: ['realm-config', realm] WithdrawGoverningTokens {}, - /// Sets Governance Delegate for the given Realm and Governing Token Mint (Community or Council) - /// The Delegate would have voting rights and could vote on behalf of the Governing Token Owner - /// The Delegate would also be able to create Proposals on behalf of the Governing Token Owner - /// Note: This doesn't take voting rights from the Token Owner who still can vote and change governance_delegate + /// Sets Governance Delegate for the given Realm and Governing Token Mint + /// (Community or Council). The Delegate would have voting rights and + /// could vote on behalf of the Governing Token Owner. The Delegate would + /// also be able to create Proposals on behalf of the Governing Token + /// Owner. + /// Note: This doesn't take voting rights from the Token Owner who still can + /// vote and change governance_delegate /// /// 0. `[signer]` Current Governance Delegate or Governing Token owner /// 1. `[writable]` Token Owner Record @@ -106,64 +135,55 @@ pub enum GovernanceInstruction { new_governance_delegate: Option, }, - /// Creates Governance account which can be used to govern any arbitrary Solana account or asset + /// Creates Governance account which can be used to govern any arbitrary + /// Solana account or asset /// /// 0. `[]` Realm account the created Governance belongs to - /// 1. `[writable]` Account Governance account. PDA seeds: ['account-governance', realm, governed_account] - /// 2. `[]` Account governed by this Governance - /// Note: The account doesn't have to exist and can be only used as a unique identifier for the Governance account - /// 3. `[]` Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority) + /// 1. `[writable]` Governance account + /// * PDA seeds: ['account-governance', realm, governance_seed] + /// 2. `[]` Governance account PDA seed + /// 3. `[]` Governing TokenOwnerRecord account (Used only if not signed by + /// RealmAuthority) /// 4. `[signer]` Payer /// 5. `[]` System program - /// 6. `[]` Sysvar Rent - /// 7. `[signer]` Governance authority - /// 8. `[]` Realm Config - /// 9. `[]` Optional Voter Weight Record + /// 6. `[signer]` Governance authority + /// 7. `[]` RealmConfig account. + /// * PDA seeds: ['realm-config', realm] + /// 8. `[]` Optional Voter Weight Record CreateGovernance { /// Governance config #[allow(dead_code)] config: GovernanceConfig, }, - /// Creates Program Governance account which governs an upgradable program - /// - /// 0. `[]` Realm account the created Governance belongs to - /// 1. `[writable]` Program Governance account. PDA seeds: ['program-governance', realm, governed_program] - /// 2. `[]` Program governed by this Governance account - /// 3. `[writable]` Program Data account of the Program governed by this Governance account - /// 4. `[signer]` Current Upgrade Authority account of the Program governed by this Governance account - /// 5. `[]` Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority) - /// 6. `[signer]` Payer - /// 7. `[]` bpf_upgradeable_loader program - /// 8. `[]` System program - /// 9. `[]` Sysvar Rent - /// 10. `[signer]` Governance authority - /// 11. `[]` Realm Config - /// 12. `[]` Optional Voter Weight Record - CreateProgramGovernance { - /// Governance config - #[allow(dead_code)] - config: GovernanceConfig, - - #[allow(dead_code)] - /// Indicates whether Program's upgrade_authority should be transferred to the Governance PDA - /// If it's set to false then it can be done at a later time - /// However the instruction would validate the current upgrade_authority signed the transaction nonetheless - transfer_upgrade_authority: bool, - }, + /// Legacy CreateProgramGovernance instruction + /// Exists for backwards-compatibility + Legacy4, - /// Creates Proposal account for Transactions which will be executed at some point in the future + /// Creates Proposal account for Transactions which will be executed at some + /// point in the future /// /// 0. `[]` Realm account the created Proposal belongs to - /// 1. `[writable]` Proposal account. PDA seeds ['governance',governance, governing_token_mint, proposal_index] + /// 1. `[writable]` Proposal account. + /// * PDA seeds ['governance',governance, governing_token_mint, + /// proposal_seed] /// 2. `[writable]` Governance account /// 3. `[writable]` TokenOwnerRecord account of the Proposal owner /// 4. `[]` Governing Token Mint the Proposal is created for - /// 5. `[signer]` Governance Authority (Token Owner or Governance Delegate) + /// 5. `[signer]` Governance Authority (Token Owner or Governance + /// Delegate) /// 6. `[signer]` Payer /// 7. `[]` System program - /// 8. `[]` Realm Config + /// 8. `[]` RealmConfig account. + /// * PDA seeds: ['realm-config', realm] /// 9. `[]` Optional Voter Weight Record + /// 10.`[writable]` Optional ProposalDeposit account. + /// * PDA seeds: ['proposal-deposit', proposal, deposit payer] + /// Proposal deposit is required when there are more active proposals + /// than the configured deposit exempt amount. + /// The deposit is paid by the Payer of the transaction and can be + /// reclaimed using RefundProposalDeposit once the Proposal is no + /// longer active. CreateProposal { #[allow(dead_code)] /// UTF-8 encoded name of the proposal @@ -184,47 +204,51 @@ pub enum GovernanceInstruction { #[allow(dead_code)] /// Indicates whether the proposal has the deny option /// A proposal without the rejecting option is a non binding survey - /// Only proposals with the rejecting option can have executable transactions + /// Only proposals with the rejecting option can have executable + /// transactions use_deny_option: bool, + + #[allow(dead_code)] + /// Unique seed for the Proposal PDA + proposal_seed: Pubkey, }, - /// Adds a signatory to the Proposal which means this Proposal can't leave Draft state until yet another Signatory signs + /// Adds a signatory to the Proposal which means this Proposal can't leave + /// Draft state until yet another Signatory signs /// - /// 0. `[writable]` Proposal account - /// 1. `[]` TokenOwnerRecord account of the Proposal owner - /// 2. `[signer]` Governance Authority (Token Owner or Governance Delegate) - /// 3. `[writable]` Signatory Record Account - /// 4. `[signer]` Payer - /// 5. `[]` System program - /// 6. `[]` Rent sysvar + /// 0. `[]` Governance account + /// 1. `[writable]` Proposal account associated with the governance + /// 2. `[writable]` Signatory Record Account + /// 3. `[signer]` Payer + /// 4. `[]` System program + /// Either: + /// - 5. `[]` TokenOwnerRecord account of the Proposal owner + /// 6. `[signer]` Governance Authority (Token Owner or Governance + /// Delegate) + /// + /// - 5. `[]` RequiredSignatory account associated with the governance. AddSignatory { #[allow(dead_code)] /// Signatory to add to the Proposal signatory: Pubkey, }, - /// Removes a Signatory from the Proposal - /// - /// 0. `[writable]` Proposal account - /// 1. `[]` TokenOwnerRecord account of the Proposal owner - /// 2. `[signer]` Governance Authority (Token Owner or Governance Delegate) - /// 3. `[writable]` Signatory Record Account - /// 4. `[writable]` Beneficiary Account which would receive lamports from the disposed Signatory Record Account - RemoveSignatory { - #[allow(dead_code)] - /// Signatory to remove from the Proposal - signatory: Pubkey, - }, + /// Formerly RemoveSignatory. Exists for backwards-compatibility. + Legacy1, - /// Inserts Transaction with a set of instructions for the Proposal at the given index position - /// New Transaction must be inserted at the end of the range indicated by Proposal transactions_next_index - /// If a Transaction replaces an existing Transaction at a given index then the old one must be removed using RemoveTransaction first + /// Inserts Transaction with a set of instructions for the Proposal at the + /// given index position New Transaction must be inserted at the end of + /// the range indicated by Proposal transactions_next_index + /// If a Transaction replaces an existing Transaction at a given index then + /// the old one must be removed using RemoveTransaction first /// 0. `[]` Governance account /// 1. `[writable]` Proposal account /// 2. `[]` TokenOwnerRecord account of the Proposal owner - /// 3. `[signer]` Governance Authority (Token Owner or Governance Delegate) - /// 4. `[writable]` ProposalTransaction, account. PDA seeds: ['governance', proposal, option_index, index] + /// 3. `[signer]` Governance Authority (Token Owner or Governance + /// Delegate) + /// 4. `[writable]` ProposalTransaction, account. + /// * PDA seeds: ['governance', proposal, option_index, index] /// 5. `[signer]` Payer /// 6. `[]` System program /// 7. `[]` Rent sysvar @@ -236,8 +260,8 @@ pub enum GovernanceInstruction { /// Transaction index to be inserted at. index: u16, #[allow(dead_code)] - /// Waiting time (in seconds) between vote period ending and this being eligible for execution - hold_up_time: u32, + /// Legacy hold_up_time + legacy: u32, #[allow(dead_code)] /// Instructions Data @@ -248,54 +272,69 @@ pub enum GovernanceInstruction { /// /// 0. `[writable]` Proposal account /// 1. `[]` TokenOwnerRecord account of the Proposal owner - /// 2. `[signer]` Governance Authority (Token Owner or Governance Delegate) + /// 2. `[signer]` Governance Authority (Token Owner or Governance + /// Delegate) /// 3. `[writable]` ProposalTransaction, account - /// 4. `[writable]` Beneficiary Account which would receive lamports from the disposed ProposalTransaction account + /// 4. `[writable]` Beneficiary Account which would receive lamports from + /// the disposed ProposalTransaction account RemoveTransaction, /// Cancels Proposal by changing its state to Canceled /// - /// 0. `[writable]` Realm account + /// 0. `[]` Realm account /// 1. `[writable]` Governance account /// 2. `[writable]` Proposal account /// 3. `[writable]` TokenOwnerRecord account of the Proposal owner - /// 4. `[signer]` Governance Authority (Token Owner or Governance Delegate) + /// 4. `[signer]` Governance Authority (Token Owner or Governance + /// Delegate) CancelProposal, /// Signs off Proposal indicating the Signatory approves the Proposal /// When the last Signatory signs off the Proposal it enters Voting state - /// Note: Adding signatories to a Proposal is a quality and not a security gate and - /// it's entirely at the discretion of the Proposal owner - /// If Proposal owner doesn't designate any signatories then can sign off the Proposal themself + /// Note: Adding signatories to a Proposal is a quality and not a security + /// gate and it's entirely at the discretion of the Proposal owner + /// If Proposal owner doesn't designate any signatories then can sign off + /// the Proposal themself /// - /// 0. `[writable]` Realm account - /// 1. `[writable]` Governance account + /// 0. `[]` Realm account + /// 1. `[]` Governance account /// 2. `[writable]` Proposal account - /// 3. `[signer]` Signatory account signing off the Proposal - /// Or Proposal owner if the owner hasn't appointed any signatories - /// 4. `[]` TokenOwnerRecord for the Proposal owner, required when the owner signs off the Proposal - /// Or `[writable]` SignatoryRecord account, required when non owner sings off the Proposal + /// 3. `[signer]` Signatory account signing off the Proposal Or Proposal + /// owner if the owner hasn't appointed any signatories + /// 4. `[]` TokenOwnerRecord for the Proposal owner, required when the + /// owner signs off the Proposal Or `[writable]` SignatoryRecord + /// account, required when non owner sings off the Proposal SignOffProposal, - /// Uses your voter weight (deposited Community or Council tokens) to cast a vote on a Proposal - /// By doing so you indicate you approve or disapprove of running the Proposal set of transactions - /// If you tip the consensus then the transactions can begin to be run after their hold up time + /// Uses your voter weight (deposited Community or Council tokens) to cast + /// a vote on a Proposal By doing so you indicate you approve or + /// disapprove of running the Proposal set of transactions If you tip + /// the consensus then the transactions can begin to be run after their hold + /// up time /// - /// 0. `[writable]` Realm account + /// 0. `[]` Realm account /// 1. `[writable]` Governance account /// 2. `[writable]` Proposal account /// 3. `[writable]` TokenOwnerRecord of the Proposal owner - /// 4. `[writable]` TokenOwnerRecord of the voter. PDA seeds: ['governance',realm, vote_governing_token_mint, governing_token_owner] - /// 5. `[signer]` Governance Authority (Token Owner or Governance Delegate) - /// 6. `[writable]` Proposal VoteRecord account. PDA seeds: ['governance',proposal,token_owner_record] - /// 7. `[]` The Governing Token Mint which is used to cast the vote (vote_governing_token_mint) - /// The voting token mint is the governing_token_mint of the Proposal for Approve, Deny and Abstain votes - /// For Veto vote the voting token mint is the mint of the opposite voting population - /// Council mint to veto Community proposals and Community mint to veto Council proposals - /// Note: In the current version only Council veto is supported + /// 4. `[writable]` TokenOwnerRecord of the voter. + /// * PDA seeds: ['governance',realm, vote_governing_token_mint, + /// governing_token_owner] + /// 5. `[signer]` Governance Authority (Token Owner or Governance + /// Delegate) + /// 6. `[writable]` Proposal VoteRecord account. + /// * PDA seeds: ['governance',proposal,token_owner_record] + /// 7. `[]` The Governing Token Mint which is used to cast the vote + /// (vote_governing_token_mint). + /// The voting token mint is the governing_token_mint of the Proposal + /// for Approve, Deny and Abstain votes. + /// For Veto vote the voting token mint is the mint of the opposite + /// voting population Council mint to veto Community proposals and + /// Community mint to veto Council proposals. + /// Note: In the current version only Council veto is supported /// 8. `[signer]` Payer /// 9. `[]` System program - /// 10. `[]` Realm Config + /// 10. `[]` RealmConfig account. + /// * PDA seeds: ['realm-config', realm] /// 11. `[]` Optional Voter Weight Record /// 12. `[]` Optional Max Voter Weight Record CastVote { @@ -304,38 +343,49 @@ pub enum GovernanceInstruction { vote: Vote, }, - /// Finalizes vote in case the Vote was not automatically tipped within max_voting_time period + /// Finalizes vote in case the Vote was not automatically tipped within + /// max_voting_time period /// - /// 0. `[writable]` Realm account + /// 0. `[]` Realm account /// 1. `[writable]` Governance account /// 2. `[writable]` Proposal account - /// 3. `[writable]` TokenOwnerRecord of the Proposal owner + /// 3. `[writable]` TokenOwnerRecord of the Proposal owner /// 4. `[]` Governing Token Mint - /// 5. `[]` Realm Config + /// 5. `[]` RealmConfig account. + /// * PDA seeds: ['realm-config', realm] /// 6. `[]` Optional Max Voter Weight Record FinalizeVote {}, - /// Relinquish Vote removes voter weight from a Proposal and removes it from voter's active votes - /// If the Proposal is still being voted on then the voter's weight won't count towards the vote outcome - /// If the Proposal is already in decided state then the instruction has no impact on the Proposal - /// and only allows voters to prune their outstanding votes in case they wanted to withdraw Governing tokens from the Realm + /// Relinquish Vote removes voter weight from a Proposal and removes it + /// from voter's active votes. If the Proposal is still being voted on + /// then the voter's weight won't count towards the vote outcome. If the + /// Proposal is already in decided state then the instruction has no impact + /// on the Proposal and only allows voters to prune their outstanding + /// votes in case they wanted to withdraw Governing tokens from the Realm /// /// 0. `[]` Realm account /// 1. `[]` Governance account /// 2. `[writable]` Proposal account - /// 3. `[writable]` TokenOwnerRecord account. PDA seeds: ['governance',realm, vote_governing_token_mint, governing_token_owner] - /// 4. `[writable]` Proposal VoteRecord account. PDA seeds: ['governance',proposal, token_owner_record] - /// 5. `[]` The Governing Token Mint which was used to cast the vote (vote_governing_token_mint) - /// 6. `[signer]` Optional Governance Authority (Token Owner or Governance Delegate) - /// It's required only when Proposal is still being voted on - /// 7. `[writable]` Optional Beneficiary account which would receive lamports when VoteRecord Account is disposed - /// It's required only when Proposal is still being voted on + /// 3. `[writable]` TokenOwnerRecord account. + /// * PDA seeds: ['governance',realm, vote_governing_token_mint, + /// governing_token_owner] + /// 4. `[writable]` Proposal VoteRecord account. + /// * PDA seeds: ['governance',proposal, token_owner_record] + /// 5. `[]` The Governing Token Mint which was used to cast the vote + /// (vote_governing_token_mint) + /// 6. `[signer]` Optional Governance Authority (Token Owner or Governance + /// Delegate) It's required only when Proposal is still being voted on + /// 7. `[writable]` Optional Beneficiary account which would receive + /// lamports when VoteRecord Account is disposed It's required only + /// when Proposal is still being voted on RelinquishVote, /// Executes a Transaction in the Proposal - /// Anybody can execute transaction once Proposal has been voted Yes and transaction_hold_up time has passed - /// The actual transaction being executed will be signed by Governance PDA the Proposal belongs to - /// For example to execute Program upgrade the ProgramGovernance PDA would be used as the singer + /// Anybody can execute transaction once Proposal has been voted Yes and + /// transaction_hold_up time has passed The actual transaction being + /// executed will be signed by Governance PDA the Proposal belongs to + /// For example to execute Program upgrade the ProgramGovernance PDA would + /// be used as the signer /// /// 0. `[]` Governance account /// 1. `[writable]` Proposal account @@ -343,61 +393,17 @@ pub enum GovernanceInstruction { /// 3+ Any extra accounts that are part of the transaction, in order ExecuteTransaction, - /// Creates Mint Governance account which governs a mint - /// - /// 0. `[]` Realm account the created Governance belongs to - /// 1. `[writable]` Mint Governance account. PDA seeds: ['mint-governance', realm, governed_mint] - /// 2. `[writable]` Mint governed by this Governance account - /// 3. `[signer]` Current Mint authority (MintTokens and optionally FreezeAccount) - /// 4. `[]` Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority) - /// 5. `[signer]` Payer - /// 6. `[]` SPL Token program - /// 7. `[]` System program - /// 8. `[]` Sysvar Rent - /// 8. `[signer]` Governance authority - /// 9. `[]` Realm Config - /// 10. `[]` Optional Voter Weight Record - CreateMintGovernance { - #[allow(dead_code)] - /// Governance config - config: GovernanceConfig, + /// Legacy CreateMintGovernance instruction + /// Exists for backwards-compatibility + Legacy2, - #[allow(dead_code)] - /// Indicates whether Mint's authorities (MintTokens, FreezeAccount) should be transferred to the Governance PDA - /// If it's set to false then it can be done at a later time - /// However the instruction would validate the current mint authority signed the transaction nonetheless - transfer_mint_authorities: bool, - }, - - /// Creates Token Governance account which governs a token account - /// - /// 0. `[]` Realm account the created Governance belongs to - /// 1. `[writable]` Token Governance account. PDA seeds: ['token-governance', realm, governed_token] - /// 2. `[writable]` Token account governed by this Governance account - /// 3. `[signer]` Current token account authority (AccountOwner and optionally CloseAccount) - /// 4. `[]` Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority) - /// 5. `[signer]` Payer - /// 6. `[]` SPL Token program - /// 7. `[]` System program - /// 8. `[]` Sysvar Rent - /// 9. `[signer]` Governance authority - /// 10. `[]` Realm Config - /// 11. `[]` Optional Voter Weight Record - CreateTokenGovernance { - #[allow(dead_code)] - /// Governance config - config: GovernanceConfig, - - #[allow(dead_code)] - /// Indicates whether the token account authorities (AccountOwner and optionally CloseAccount) should be transferred to the Governance PDA - /// If it's set to false then it can be done at a later time - /// However the instruction would validate the current token owner signed the transaction nonetheless - transfer_account_authorities: bool, - }, + /// Legacy CreateTokenGovernance instruction + /// Exists for backwards-compatibility + Legacy3, /// Sets GovernanceConfig for a Governance /// - /// 0. `[]` Realm account the Governance account belongs to + /// 0. `[]` Realm account the Governance account belongs to /// 1. `[writable, signer]` The Governance account the config is for SetGovernanceConfig { #[allow(dead_code)] @@ -405,22 +411,16 @@ pub enum GovernanceInstruction { config: GovernanceConfig, }, - /// Flags a transaction and its parent Proposal with error status - /// It can be used by Proposal owner in case the transaction is permanently broken and can't be executed - /// Note: This instruction is a workaround because currently it's not possible to catch errors from CPI calls - /// and the Governance program has no way to know when instruction failed and flag it automatically - /// - /// 0. `[writable]` Proposal account - /// 1. `[]` TokenOwnerRecord account of the Proposal owner - /// 2. `[signer]` Governance Authority (Token Owner or Governance Delegate) - /// 3. `[writable]` ProposalTransaction account to flag - FlagTransactionError, + /// Legacy FlagTransactionError instruction + /// Exists for backwards-compatibility + Legacy5, /// Sets new Realm authority /// /// 0. `[writable]` Realm account - /// 1. `[signer]` Current Realm authority - /// 2. `[]` New realm authority. Must be one of the realm governances when set + /// 1. `[signer]` Current Realm authority + /// 2. `[]` New realm authority. Must be one of the realm governances when + /// set SetRealmAuthority { #[allow(dead_code)] /// Set action ( SetUnchecked, SetChecked, Remove) @@ -429,19 +429,27 @@ pub enum GovernanceInstruction { /// Sets realm config /// 0. `[writable]` Realm account - /// 1. `[signer]` Realm authority + /// 1. `[signer]` Realm authority /// 2. `[]` Council Token Mint - optional - /// Note: In the current version it's only possible to remove council mint (set it to None) - /// After setting council to None it won't be possible to withdraw the tokens from the Realm any longer - /// If that's required then it must be done before executing this instruction - /// 3. `[writable]` Council Token Holding account - optional unless council is used. PDA seeds: ['governance',realm,council_mint] - /// The account will be created with the Realm PDA as its owner + /// Note: In the current version it's only possible to remove council + /// mint (set it to None). + /// After setting council to None it won't be possible to withdraw the + /// tokens from the Realm any longer. + /// If that's required then it must be done before executing this + /// instruction. + /// 3. `[writable]` Council Token Holding account - optional unless + /// council is used. + /// * PDA seeds: ['governance',realm,council_mint] The account will be + /// created with the Realm PDA as its owner /// 4. `[]` System - /// 5. `[writable]` RealmConfig account. PDA seeds: ['realm-config', realm] - - /// 6. `[]` Optional Community Voter Weight Addin Program Id - /// 7. `[]` Optional Max Community Voter Weight Addin Program Id - /// 8. `[signer]` Optional Payer + /// 5. `[writable]` RealmConfig account. + /// * PDA seeds: ['realm-config', realm] + /// 6. `[]` Optional Community Voter Weight Addin Program Id + /// 7. `[]` Optional Max Community Voter Weight Addin Program Id + /// 8. `[]` Optional Council Voter Weight Addin Program Id + /// 9. `[]` Optional Max Council Voter Weight Addin Program Id + /// 10. `[signer]` Optional Payer. Required if RealmConfig doesn't exist + /// and needs to be created SetRealmConfig { #[allow(dead_code)] /// Realm config args @@ -449,32 +457,166 @@ pub enum GovernanceInstruction { }, /// Creates TokenOwnerRecord with 0 deposit amount - /// It's used to register TokenOwner when voter weight addin is used and the Governance program doesn't take deposits + /// It's used to register TokenOwner when voter weight addin is used and the + /// Governance program doesn't take deposits /// /// 0. `[]` Realm account /// 1. `[]` Governing Token Owner account - /// 2. `[writable]` TokenOwnerRecord account. PDA seeds: ['governance',realm, governing_token_mint, governing_token_owner] - /// 3. `[]` Governing Token Mint + /// 2. `[writable]` TokenOwnerRecord account. + /// * PDA seeds: ['governance',realm, governing_token_mint, + /// governing_token_owner] + /// 3. `[]` Governing Token Mint /// 4. `[signer]` Payer /// 5. `[]` System CreateTokenOwnerRecord {}, /// Updates ProgramMetadata account - /// The instruction dumps information implied by the program's code into a persistent account + /// The instruction dumps information implied by the program's code into a + /// persistent account /// - /// 0. `[writable]` ProgramMetadata account. PDA seeds: ['metadata'] + /// 0. `[writable]` ProgramMetadata account. + /// * PDA seeds: ['metadata'] /// 1. `[signer]` Payer /// 2. `[]` System UpdateProgramMetadata {}, /// Creates native SOL treasury account for a Governance account - /// The account has no data and can be used as a payer for instructions signed by Governance PDAs or as a native SOL treasury + /// The account has no data and can be used as a payer for instructions + /// signed by Governance PDAs or as a native SOL treasury /// /// 0. `[]` Governance account the treasury account is for - /// 1. `[writable]` NativeTreasury account. PDA seeds: ['treasury', governance] + /// 1. `[writable]` NativeTreasury account. + /// * PDA seeds: ['native-treasury', governance] /// 2. `[signer]` Payer /// 3. `[]` System CreateNativeTreasury, + + /// Revokes (burns) membership governing tokens for the given + /// TokenOwnerRecord and hence takes away governance power from the + /// TokenOwner. Note: If there are active votes for the TokenOwner then + /// the vote weights won't be updated automatically + /// + /// 0. `[]` Realm account + /// 1. `[writable]` Governing Token Holding account. + /// * PDA seeds: ['governance',realm, governing_token_mint] + /// 2. `[writable]` TokenOwnerRecord account. + /// * PDA seeds: ['governance',realm, governing_token_mint, + /// governing_token_owner] + /// 3. `[writable]` GoverningTokenMint + /// 4. `[signer]` Revoke authority which can be either of: + /// 1) GoverningTokenMint mint_authority to forcefully revoke + /// the membership tokens + /// 2) GoverningTokenOwner who voluntarily revokes their own + /// membership + /// 5. `[]` RealmConfig account. + /// * PDA seeds: ['realm-config', realm] + /// 6. `[]` SPL Token program + RevokeGoverningTokens { + /// The amount to revoke + #[allow(dead_code)] + amount: u64, + }, + + /// Refunds ProposalDeposit once the given proposal is no longer active + /// (Draft, SigningOff, Voting) Once the condition is met the + /// instruction is permissionless and returns the deposit amount to the + /// deposit payer + /// + /// 0. `[]` Proposal account + /// 1. `[writable]` ProposalDeposit account. + /// * PDA seeds: ['proposal-deposit', proposal, deposit payer] + /// 2. `[writable]` Proposal deposit payer (beneficiary) account + RefundProposalDeposit {}, + + /// Transitions an off-chain or manually executable Proposal from Succeeded + /// into Completed state + /// + /// Upon a successful vote on an off-chain or manually executable proposal + /// it remains in Succeeded state Once the external actions are executed + /// the Proposal owner can use the instruction to manually transition it to + /// Completed state + /// + /// + /// 0. `[writable]` Proposal account + /// 1. `[]` TokenOwnerRecord account of the Proposal owner + /// 2. `[signer]` CompleteProposal authority (Token Owner or Delegate) + CompleteProposal {}, + + /// Adds a required signatory to the Governance, which will be applied to + /// all proposals created with it + /// + /// 0. `[writable, signer]` The Governance account the config is for + /// 1. `[writable]` RequiredSignatory Account + /// 2. `[signer]` Payer + /// 3. `[]` System program + AddRequiredSignatory { + #[allow(dead_code)] + /// Required signatory to add to the Governance + signatory: Pubkey, + }, + + /// Removes a required signatory from the Governance + /// + /// 0. `[writable, signer]` The Governance account the config is for + /// 1. `[writable]` RequiredSignatory Account + /// 2. `[writable]` Beneficiary Account which would receive lamports from + /// the disposed RequiredSignatory Account + RemoveRequiredSignatory, + + /// Sets TokenOwnerRecord lock for the given authority and lock id + /// + /// 0. `[]` Realm + /// 1. `[]` RealmConfig + /// 2. `[writable]` TokenOwnerRecord the lock is set for + /// 3. `[signer]` Lock authority issuing the lock + /// 4. `[signer]` Payer + /// 5. `[]` System + SetTokenOwnerRecordLock { + /// Custom lock id which can be used by the authority to issue + /// different locks + #[allow(dead_code)] + lock_id: u8, + + /// The timestamp when the lock expires or None if it never expires + #[allow(dead_code)] + expiry: Option, + }, + + /// Removes all expired TokenOwnerRecord locks and if specified + /// the locks identified by the given lock ids and authority + /// + /// + /// 0. `[]` Realm + /// 1. `[]` RealmConfig + /// 2. `[writable]` TokenOwnerRecord the locks are removed from + /// 3. `[signer]` Optional lock authority which issued the locks specified + /// by lock_ids. If the authority is configured in RealmConfig then it + /// must sign the transaction. If the authority is no longer configured + /// then the locks are removed without the authority signature + RelinquishTokenOwnerRecordLocks { + /// Custom lock ids identifying the lock to remove + /// If the lock_id is None then only expired locks are removed + #[allow(dead_code)] + lock_ids: Option>, + }, + + /// Sets Realm config item + /// Note: + /// This instruction is used to set a single RealmConfig item at a time + /// In the current version it only supports TokenOwnerRecordLockAuthority + /// however eventually all Realm configuration items should be set using + /// this instruction and SetRealmConfig instruction should be deprecated + /// + /// 0. `[writable]` Realm account + /// 1. `[writable]` RealmConfig account + /// 2. `[signer]` Realm authority + /// 3. `[signer]` Payer + /// 4. `[]` System + SetRealmConfigItem { + #[allow(dead_code)] + /// Config args + args: SetRealmConfigItemArgs, + }, } /// Creates CreateRealm instruction @@ -486,12 +628,13 @@ pub fn create_realm( community_token_mint: &Pubkey, payer: &Pubkey, council_token_mint: Option, - community_voter_weight_addin: Option, - max_community_voter_weight_addin: Option, + // Accounts Args + community_token_config_args: Option, + council_token_config_args: Option, // Args name: String, min_community_weight_to_create_governance: u64, - community_mint_max_vote_weight_source: MintMaxVoteWeightSource, + community_mint_max_voter_weight_source: MintMaxVoterWeightSource, ) -> Instruction { let realm_address = get_realm_address(program_id, &name); let community_token_holding_address = @@ -519,40 +662,22 @@ pub fn create_realm( false }; - let use_community_voter_weight_addin = - if let Some(community_voter_weight_addin) = community_voter_weight_addin { - accounts.push(AccountMeta::new_readonly( - community_voter_weight_addin, - false, - )); - true - } else { - false - }; + let realm_config_address = get_realm_config_address(program_id, &realm_address); + accounts.push(AccountMeta::new(realm_config_address, false)); - let use_max_community_voter_weight_addin = - if let Some(max_community_voter_weight_addin) = max_community_voter_weight_addin { - accounts.push(AccountMeta::new_readonly( - max_community_voter_weight_addin, - false, - )); - true - } else { - false - }; + let community_token_config_args = + with_governing_token_config_args(&mut accounts, community_token_config_args); - if use_community_voter_weight_addin || use_max_community_voter_weight_addin { - let realm_config_address = get_realm_config_address(program_id, &realm_address); - accounts.push(AccountMeta::new(realm_config_address, false)); - } + let council_token_config_args = + with_governing_token_config_args(&mut accounts, council_token_config_args); let instruction = GovernanceInstruction::CreateRealm { config_args: RealmConfigArgs { use_council_mint, min_community_weight_to_create_governance, - community_mint_max_vote_weight_source, - use_community_voter_weight_addin, - use_max_community_voter_weight_addin, + community_mint_max_voter_weight_source, + community_token_config_args, + council_token_config_args, }, name, }; @@ -560,7 +685,7 @@ pub fn create_realm( Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), } } @@ -572,7 +697,7 @@ pub fn deposit_governing_tokens( realm: &Pubkey, governing_token_source: &Pubkey, governing_token_owner: &Pubkey, - governing_token_transfer_authority: &Pubkey, + governing_token_source_authority: &Pubkey, payer: &Pubkey, // Args amount: u64, @@ -588,16 +713,19 @@ pub fn deposit_governing_tokens( let governing_token_holding_address = get_governing_token_holding_address(program_id, realm, governing_token_mint); + let realm_config_address = get_realm_config_address(program_id, realm); + let accounts = vec![ AccountMeta::new_readonly(*realm, false), AccountMeta::new(governing_token_holding_address, false), AccountMeta::new(*governing_token_source, false), AccountMeta::new_readonly(*governing_token_owner, true), - AccountMeta::new_readonly(*governing_token_transfer_authority, true), + AccountMeta::new_readonly(*governing_token_source_authority, true), AccountMeta::new(token_owner_record_address, false), AccountMeta::new(*payer, true), AccountMeta::new_readonly(system_program::id(), false), AccountMeta::new_readonly(spl_token::id(), false), + AccountMeta::new_readonly(realm_config_address, false), ]; let instruction = GovernanceInstruction::DepositGoverningTokens { amount }; @@ -605,7 +733,7 @@ pub fn deposit_governing_tokens( Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), } } @@ -629,6 +757,8 @@ pub fn withdraw_governing_tokens( let governing_token_holding_address = get_governing_token_holding_address(program_id, realm, governing_token_mint); + let realm_config_address = get_realm_config_address(program_id, realm); + let accounts = vec![ AccountMeta::new_readonly(*realm, false), AccountMeta::new(governing_token_holding_address, false), @@ -636,6 +766,7 @@ pub fn withdraw_governing_tokens( AccountMeta::new_readonly(*governing_token_owner, true), AccountMeta::new(token_owner_record_address, false), AccountMeta::new_readonly(spl_token::id(), false), + AccountMeta::new_readonly(realm_config_address, false), ]; let instruction = GovernanceInstruction::WithdrawGoverningTokens {}; @@ -643,7 +774,7 @@ pub fn withdraw_governing_tokens( Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), } } @@ -677,7 +808,7 @@ pub fn set_governance_delegate( Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), } } @@ -687,7 +818,7 @@ pub fn create_governance( program_id: &Pubkey, // Accounts realm: &Pubkey, - governed_account: Option<&Pubkey>, + governance_seed: &Pubkey, token_owner_record: &Pubkey, payer: &Pubkey, create_authority: &Pubkey, @@ -695,19 +826,12 @@ pub fn create_governance( // Args config: GovernanceConfig, ) -> Instruction { - let governed_account_address = if let Some(governed_account) = governed_account { - *governed_account - } else { - // If the governed account is not provided then generate a unique identifier for the Governance account - Pubkey::new_unique() - }; - - let governance_address = get_governance_address(program_id, realm, &governed_account_address); + let governance_address = get_governance_address(program_id, realm, governance_seed); let mut accounts = vec![ AccountMeta::new_readonly(*realm, false), AccountMeta::new(governance_address, false), - AccountMeta::new_readonly(governed_account_address, false), + AccountMeta::new_readonly(*governance_seed, false), AccountMeta::new_readonly(*token_owner_record, false), AccountMeta::new(*payer, true), AccountMeta::new_readonly(system_program::id(), false), @@ -721,142 +845,7 @@ pub fn create_governance( Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), - } -} - -/// Creates CreateProgramGovernance instruction -#[allow(clippy::too_many_arguments)] -pub fn create_program_governance( - program_id: &Pubkey, - // Accounts - realm: &Pubkey, - governed_program: &Pubkey, - governed_program_upgrade_authority: &Pubkey, - token_owner_record: &Pubkey, - payer: &Pubkey, - create_authority: &Pubkey, - voter_weight_record: Option, - // Args - config: GovernanceConfig, - transfer_upgrade_authority: bool, -) -> Instruction { - let program_governance_address = - get_program_governance_address(program_id, realm, governed_program); - let governed_program_data_address = get_program_data_address(governed_program); - - let mut accounts = vec![ - AccountMeta::new_readonly(*realm, false), - AccountMeta::new(program_governance_address, false), - AccountMeta::new_readonly(*governed_program, false), - AccountMeta::new(governed_program_data_address, false), - AccountMeta::new_readonly(*governed_program_upgrade_authority, true), - AccountMeta::new_readonly(*token_owner_record, false), - AccountMeta::new(*payer, true), - AccountMeta::new_readonly(bpf_loader_upgradeable::id(), false), - AccountMeta::new_readonly(system_program::id(), false), - AccountMeta::new_readonly(*create_authority, true), - ]; - - with_realm_config_accounts(program_id, &mut accounts, realm, voter_weight_record, None); - - let instruction = GovernanceInstruction::CreateProgramGovernance { - config, - transfer_upgrade_authority, - }; - - Instruction { - program_id: *program_id, - accounts, - data: instruction.try_to_vec().unwrap(), - } -} - -/// Creates CreateMintGovernance -#[allow(clippy::too_many_arguments)] -pub fn create_mint_governance( - program_id: &Pubkey, - // Accounts - realm: &Pubkey, - governed_mint: &Pubkey, - governed_mint_authority: &Pubkey, - token_owner_record: &Pubkey, - payer: &Pubkey, - create_authority: &Pubkey, - voter_weight_record: Option, - // Args - config: GovernanceConfig, - transfer_mint_authorities: bool, -) -> Instruction { - let mint_governance_address = get_mint_governance_address(program_id, realm, governed_mint); - - let mut accounts = vec![ - AccountMeta::new_readonly(*realm, false), - AccountMeta::new(mint_governance_address, false), - AccountMeta::new(*governed_mint, false), - AccountMeta::new_readonly(*governed_mint_authority, true), - AccountMeta::new_readonly(*token_owner_record, false), - AccountMeta::new(*payer, true), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new_readonly(system_program::id(), false), - AccountMeta::new_readonly(*create_authority, true), - ]; - - with_realm_config_accounts(program_id, &mut accounts, realm, voter_weight_record, None); - - let instruction = GovernanceInstruction::CreateMintGovernance { - config, - transfer_mint_authorities, - }; - - Instruction { - program_id: *program_id, - accounts, - data: instruction.try_to_vec().unwrap(), - } -} - -/// Creates CreateTokenGovernance instruction -#[allow(clippy::too_many_arguments)] -pub fn create_token_governance( - program_id: &Pubkey, - // Accounts - realm: &Pubkey, - governed_token: &Pubkey, - governed_token_owner: &Pubkey, - token_owner_record: &Pubkey, - payer: &Pubkey, - create_authority: &Pubkey, - voter_weight_record: Option, - // Args - config: GovernanceConfig, - transfer_account_authorities: bool, -) -> Instruction { - let token_governance_address = get_token_governance_address(program_id, realm, governed_token); - - let mut accounts = vec![ - AccountMeta::new_readonly(*realm, false), - AccountMeta::new(token_governance_address, false), - AccountMeta::new(*governed_token, false), - AccountMeta::new_readonly(*governed_token_owner, true), - AccountMeta::new_readonly(*token_owner_record, false), - AccountMeta::new(*payer, true), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new_readonly(system_program::id(), false), - AccountMeta::new_readonly(*create_authority, true), - ]; - - with_realm_config_accounts(program_id, &mut accounts, realm, voter_weight_record, None); - - let instruction = GovernanceInstruction::CreateTokenGovernance { - config, - transfer_account_authorities, - }; - - Instruction { - program_id: *program_id, - accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), } } @@ -878,14 +867,10 @@ pub fn create_proposal( vote_type: VoteType, options: Vec, use_deny_option: bool, - proposal_index: u32, + proposal_seed: &Pubkey, ) -> Instruction { - let proposal_address = get_proposal_address( - program_id, - governance, - governing_token_mint, - &proposal_index.to_le_bytes(), - ); + let proposal_address = + get_proposal_address(program_id, governance, governing_token_mint, proposal_seed); let mut accounts = vec![ AccountMeta::new_readonly(*realm, false), @@ -900,18 +885,26 @@ pub fn create_proposal( with_realm_config_accounts(program_id, &mut accounts, realm, voter_weight_record, None); + // Deposit is only required when there are more active proposal then the + // configured exempt amount Note: We always pass the account because the + // actual value is not known here without passing Governance account data + let proposal_deposit_address = + get_proposal_deposit_address(program_id, &proposal_address, payer); + accounts.push(AccountMeta::new(proposal_deposit_address, false)); + let instruction = GovernanceInstruction::CreateProposal { name, description_link, vote_type, options, use_deny_option, + proposal_seed: *proposal_seed, }; Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), } } @@ -919,24 +912,39 @@ pub fn create_proposal( pub fn add_signatory( program_id: &Pubkey, // Accounts + governance: &Pubkey, proposal: &Pubkey, - token_owner_record: &Pubkey, - governance_authority: &Pubkey, + add_signatory_authority: &AddSignatoryAuthority, payer: &Pubkey, // Args signatory: &Pubkey, ) -> Instruction { let signatory_record_address = get_signatory_record_address(program_id, proposal, signatory); - let accounts = vec![ + let mut accounts = vec![ + AccountMeta::new_readonly(*governance, false), AccountMeta::new(*proposal, false), - AccountMeta::new_readonly(*token_owner_record, false), - AccountMeta::new_readonly(*governance_authority, true), AccountMeta::new(signatory_record_address, false), AccountMeta::new(*payer, true), AccountMeta::new_readonly(system_program::id(), false), ]; + match add_signatory_authority { + AddSignatoryAuthority::ProposalOwner { + governance_authority, + token_owner_record, + } => { + accounts.push(AccountMeta::new_readonly(*token_owner_record, false)); + accounts.push(AccountMeta::new_readonly(*governance_authority, true)); + } + AddSignatoryAuthority::None => { + accounts.push(AccountMeta::new_readonly( + get_required_signatory_address(program_id, governance, signatory), + false, + )); + } + }; + let instruction = GovernanceInstruction::AddSignatory { signatory: *signatory, }; @@ -944,39 +952,24 @@ pub fn add_signatory( Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), } } -/// Creates RemoveSignatory instruction -pub fn remove_signatory( - program_id: &Pubkey, - // Accounts - proposal: &Pubkey, - token_owner_record: &Pubkey, - governance_authority: &Pubkey, - signatory: &Pubkey, - beneficiary: &Pubkey, -) -> Instruction { - let signatory_record_address = get_signatory_record_address(program_id, proposal, signatory); - - let accounts = vec![ - AccountMeta::new(*proposal, false), - AccountMeta::new_readonly(*token_owner_record, false), - AccountMeta::new_readonly(*governance_authority, true), - AccountMeta::new(signatory_record_address, false), - AccountMeta::new(*beneficiary, false), - ]; - - let instruction = GovernanceInstruction::RemoveSignatory { - signatory: *signatory, - }; - - Instruction { - program_id: *program_id, - accounts, - data: instruction.try_to_vec().unwrap(), - } +#[derive(Debug, Copy, Clone)] +/// Enum to specify the authority by which the instruction should add a +/// signatory +pub enum AddSignatoryAuthority { + /// Proposal owners can add optional signatories to a proposal + ProposalOwner { + /// Token owner or its delegate + governance_authority: Pubkey, + /// Token owner record of the Proposal owner + token_owner_record: Pubkey, + }, + /// Anyone can add signatories that are required by the governance to a + /// proposal + None, } /// Creates SignOffProposal instruction @@ -990,8 +983,8 @@ pub fn sign_off_proposal( proposal_owner_record: Option<&Pubkey>, ) -> Instruction { let mut accounts = vec![ - AccountMeta::new(*realm, false), - AccountMeta::new(*governance, false), + AccountMeta::new_readonly(*realm, false), + AccountMeta::new_readonly(*governance, false), AccountMeta::new(*proposal, false), AccountMeta::new_readonly(*signatory, true), ]; @@ -1009,7 +1002,7 @@ pub fn sign_off_proposal( Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), } } @@ -1035,7 +1028,7 @@ pub fn cast_vote( get_vote_record_address(program_id, proposal, voter_token_owner_record); let mut accounts = vec![ - AccountMeta::new(*realm, false), + AccountMeta::new_readonly(*realm, false), AccountMeta::new(*governance, false), AccountMeta::new(*proposal, false), AccountMeta::new(*proposal_owner_record, false), @@ -1060,7 +1053,7 @@ pub fn cast_vote( Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), } } @@ -1076,7 +1069,7 @@ pub fn finalize_vote( max_voter_weight_record: Option, ) -> Instruction { let mut accounts = vec![ - AccountMeta::new(*realm, false), + AccountMeta::new_readonly(*realm, false), AccountMeta::new(*governance, false), AccountMeta::new(*proposal, false), AccountMeta::new(*proposal_owner_record, false), @@ -1096,7 +1089,7 @@ pub fn finalize_vote( Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), } } @@ -1134,7 +1127,7 @@ pub fn relinquish_vote( Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), } } @@ -1149,7 +1142,7 @@ pub fn cancel_proposal( governance_authority: &Pubkey, ) -> Instruction { let accounts = vec![ - AccountMeta::new(*realm, false), + AccountMeta::new_readonly(*realm, false), AccountMeta::new(*governance, false), AccountMeta::new(*proposal, false), AccountMeta::new(*proposal_owner_record, false), @@ -1161,7 +1154,7 @@ pub fn cancel_proposal( Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), } } @@ -1178,7 +1171,6 @@ pub fn insert_transaction( // Args option_index: u8, index: u16, - hold_up_time: u32, instructions: Vec, ) -> Instruction { let proposal_transaction_address = get_proposal_transaction_address( @@ -1202,14 +1194,14 @@ pub fn insert_transaction( let instruction = GovernanceInstruction::InsertTransaction { option_index, index, - hold_up_time, + legacy: 0, instructions, }; Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), } } @@ -1236,7 +1228,7 @@ pub fn remove_transaction( Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), } } @@ -1264,7 +1256,7 @@ pub fn execute_transaction( Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), } } @@ -1283,32 +1275,7 @@ pub fn set_governance_config( Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), - } -} - -/// Creates FlagTransactionError instruction -pub fn flag_transaction_error( - program_id: &Pubkey, - // Accounts - proposal: &Pubkey, - token_owner_record: &Pubkey, - governance_authority: &Pubkey, - proposal_transaction: &Pubkey, -) -> Instruction { - let accounts = vec![ - AccountMeta::new(*proposal, false), - AccountMeta::new_readonly(*token_owner_record, false), - AccountMeta::new_readonly(*governance_authority, true), - AccountMeta::new(*proposal_transaction, false), - ]; - - let instruction = GovernanceInstruction::FlagTransactionError {}; - - Instruction { - program_id: *program_id, - accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), } } @@ -1342,7 +1309,7 @@ pub fn set_realm_authority( Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), } } @@ -1355,11 +1322,12 @@ pub fn set_realm_config( realm_authority: &Pubkey, council_token_mint: Option, payer: &Pubkey, - community_voter_weight_addin: Option, - max_community_voter_weight_addin: Option, + // Accounts Args + community_token_config_args: Option, + council_token_config_args: Option, // Args min_community_weight_to_create_governance: u64, - community_mint_max_vote_weight_source: MintMaxVoteWeightSource, + community_mint_max_voter_weight_source: MintMaxVoterWeightSource, ) -> Instruction { let mut accounts = vec![ AccountMeta::new(*realm, false), @@ -1379,51 +1347,34 @@ pub fn set_realm_config( accounts.push(AccountMeta::new_readonly(system_program::id(), false)); - // Always pass realm_config_address because it's needed when use_community_voter_weight_addin is set to true - // but also when it's set to false and the addin is being removed from the realm + // Always pass realm_config_address because it's needed when + // use_community_voter_weight_addin is set to true but also when it's set to + // false and the addin is being removed from the realm let realm_config_address = get_realm_config_address(program_id, realm); accounts.push(AccountMeta::new(realm_config_address, false)); - let use_community_voter_weight_addin = - if let Some(community_voter_weight_addin) = community_voter_weight_addin { - accounts.push(AccountMeta::new_readonly( - community_voter_weight_addin, - false, - )); - true - } else { - false - }; + let community_token_config_args = + with_governing_token_config_args(&mut accounts, community_token_config_args); - let use_max_community_voter_weight_addin = - if let Some(max_community_voter_weight_addin) = max_community_voter_weight_addin { - accounts.push(AccountMeta::new_readonly( - max_community_voter_weight_addin, - false, - )); - true - } else { - false - }; + let council_token_config_args = + with_governing_token_config_args(&mut accounts, council_token_config_args); - if use_community_voter_weight_addin || use_max_community_voter_weight_addin { - accounts.push(AccountMeta::new(*payer, true)); - } + accounts.push(AccountMeta::new(*payer, true)); let instruction = GovernanceInstruction::SetRealmConfig { config_args: RealmConfigArgs { use_council_mint, min_community_weight_to_create_governance, - community_mint_max_vote_weight_source, - use_community_voter_weight_addin, - use_max_community_voter_weight_addin, + community_mint_max_voter_weight_source, + community_token_config_args, + council_token_config_args, }, }; Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), } } @@ -1485,7 +1436,7 @@ pub fn create_token_owner_record( Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), } } @@ -1508,7 +1459,7 @@ pub fn upgrade_program_metadata( Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), } } @@ -1533,6 +1484,283 @@ pub fn create_native_treasury( Instruction { program_id: *program_id, accounts, - data: instruction.try_to_vec().unwrap(), + data: borsh::to_vec(&instruction).unwrap(), + } +} + +/// Creates RevokeGoverningTokens instruction +#[allow(clippy::too_many_arguments)] +pub fn revoke_governing_tokens( + program_id: &Pubkey, + // Accounts + realm: &Pubkey, + governing_token_owner: &Pubkey, + governing_token_mint: &Pubkey, + revoke_authority: &Pubkey, + // Args + amount: u64, +) -> Instruction { + let token_owner_record_address = get_token_owner_record_address( + program_id, + realm, + governing_token_mint, + governing_token_owner, + ); + + let governing_token_holding_address = + get_governing_token_holding_address(program_id, realm, governing_token_mint); + + let realm_config_address = get_realm_config_address(program_id, realm); + + let accounts = vec![ + AccountMeta::new_readonly(*realm, false), + AccountMeta::new(governing_token_holding_address, false), + AccountMeta::new(token_owner_record_address, false), + AccountMeta::new(*governing_token_mint, false), + AccountMeta::new_readonly(*revoke_authority, true), + AccountMeta::new_readonly(realm_config_address, false), + AccountMeta::new_readonly(spl_token::id(), false), + ]; + + let instruction = GovernanceInstruction::RevokeGoverningTokens { amount }; + + Instruction { + program_id: *program_id, + accounts, + data: borsh::to_vec(&instruction).unwrap(), + } +} + +/// Creates AddRequiredSignatory instruction +pub fn add_required_signatory( + program_id: &Pubkey, + // Accounts + governance: &Pubkey, + payer: &Pubkey, + // Args + signatory: &Pubkey, +) -> Instruction { + let required_signatory_address = + get_required_signatory_address(program_id, governance, signatory); + + let accounts = vec![ + AccountMeta::new(*governance, true), + AccountMeta::new(required_signatory_address, false), + AccountMeta::new(*payer, true), + AccountMeta::new_readonly(system_program::id(), false), + ]; + + let instruction = GovernanceInstruction::AddRequiredSignatory { + signatory: *signatory, + }; + + Instruction { + program_id: *program_id, + accounts, + data: borsh::to_vec(&instruction).unwrap(), + } +} + +/// Creates RemoveRequiredSignatory instruction +pub fn remove_required_signatory( + program_id: &Pubkey, + // Accounts + governance: &Pubkey, + signatory: &Pubkey, + beneficiary: &Pubkey, +) -> Instruction { + let required_signatory_address = + get_required_signatory_address(program_id, governance, signatory); + + let accounts = vec![ + AccountMeta::new(*governance, true), + AccountMeta::new(required_signatory_address, false), + AccountMeta::new(*beneficiary, false), + ]; + + let instruction = GovernanceInstruction::RemoveRequiredSignatory; + + Instruction { + program_id: *program_id, + accounts, + data: borsh::to_vec(&instruction).unwrap(), + } +} + +/// Adds accounts specified by GoverningTokenConfigAccountArgs +/// and returns GoverningTokenConfigArgs +pub fn with_governing_token_config_args( + accounts: &mut Vec, + governing_token_config_args: Option, +) -> GoverningTokenConfigArgs { + let governing_token_config_args = governing_token_config_args.unwrap_or_default(); + + let use_voter_weight_addin = + if let Some(voter_weight_addin) = governing_token_config_args.voter_weight_addin { + accounts.push(AccountMeta::new_readonly(voter_weight_addin, false)); + true + } else { + false + }; + + let use_max_voter_weight_addin = + if let Some(max_voter_weight_addin) = governing_token_config_args.max_voter_weight_addin { + accounts.push(AccountMeta::new_readonly(max_voter_weight_addin, false)); + true + } else { + false + }; + + GoverningTokenConfigArgs { + use_voter_weight_addin, + use_max_voter_weight_addin, + token_type: governing_token_config_args.token_type, + } +} + +/// Creates RefundProposalDeposit instruction +#[allow(clippy::too_many_arguments)] +pub fn refund_proposal_deposit( + program_id: &Pubkey, + // Accounts + proposal: &Pubkey, + proposal_deposit_payer: &Pubkey, + // Args +) -> Instruction { + let proposal_deposit_address = + get_proposal_deposit_address(program_id, proposal, proposal_deposit_payer); + + let accounts = vec![ + AccountMeta::new_readonly(*proposal, false), + AccountMeta::new(proposal_deposit_address, false), + AccountMeta::new(*proposal_deposit_payer, false), + ]; + + let instruction = GovernanceInstruction::RefundProposalDeposit {}; + + Instruction { + program_id: *program_id, + accounts, + data: borsh::to_vec(&instruction).unwrap(), + } +} + +/// Creates CompleteProposal instruction to move proposal from Succeeded to +/// Completed +pub fn complete_proposal( + program_id: &Pubkey, + // Accounts + proposal: &Pubkey, + token_owner_record: &Pubkey, + complete_proposal_authority: &Pubkey, +) -> Instruction { + let accounts = vec![ + AccountMeta::new(*proposal, false), + AccountMeta::new_readonly(*token_owner_record, false), + AccountMeta::new_readonly(*complete_proposal_authority, true), + ]; + + let instruction = GovernanceInstruction::CompleteProposal {}; + + Instruction { + program_id: *program_id, + accounts, + data: borsh::to_vec(&instruction).unwrap(), + } +} + +/// Creates SetTokenOwnerRecordLock instruction to issue TokenOwnerRecord lock +pub fn set_token_owner_record_lock( + program_id: &Pubkey, + // Accounts + realm: &Pubkey, + token_owner_record: &Pubkey, + token_owner_record_lock_authority: &Pubkey, + payer: &Pubkey, + // Args + lock_id: u8, + expiry: Option, +) -> Instruction { + let realm_config_address = get_realm_config_address(program_id, realm); + + let accounts = vec![ + AccountMeta::new_readonly(*realm, false), + AccountMeta::new_readonly(realm_config_address, false), + AccountMeta::new(*token_owner_record, false), + AccountMeta::new_readonly(*token_owner_record_lock_authority, true), + AccountMeta::new(*payer, true), + AccountMeta::new_readonly(system_program::id(), false), + ]; + + let instruction = GovernanceInstruction::SetTokenOwnerRecordLock { lock_id, expiry }; + + Instruction { + program_id: *program_id, + accounts, + data: borsh::to_vec(&instruction).unwrap(), + } +} + +/// Creates RelinquishTokenOwnerRecordLocks instruction to remove +/// TokenOwnerRecord locks +pub fn relinquish_token_owner_record_locks( + program_id: &Pubkey, + // Accounts + realm: &Pubkey, + token_owner_record: &Pubkey, + token_owner_record_lock_authority: Option, + // Args + lock_ids: Option>, +) -> Instruction { + let realm_config_address = get_realm_config_address(program_id, realm); + + let mut accounts = vec![ + AccountMeta::new_readonly(*realm, false), + AccountMeta::new_readonly(realm_config_address, false), + AccountMeta::new(*token_owner_record, false), + ]; + + if let Some(token_owner_record_lock_authority) = token_owner_record_lock_authority { + accounts.push(AccountMeta::new_readonly( + token_owner_record_lock_authority, + true, + )); + } + + let instruction = GovernanceInstruction::RelinquishTokenOwnerRecordLocks { lock_ids }; + + Instruction { + program_id: *program_id, + accounts, + data: borsh::to_vec(&instruction).unwrap(), + } +} + +/// Creates SetRealmConfigItem instruction to set realm config +pub fn set_realm_config_item( + program_id: &Pubkey, + // Accounts + realm: &Pubkey, + realm_authority: &Pubkey, + payer: &Pubkey, + // Args + args: SetRealmConfigItemArgs, +) -> Instruction { + let realm_config_address = get_realm_config_address(program_id, realm); + + let accounts = vec![ + AccountMeta::new(*realm, false), + AccountMeta::new(realm_config_address, false), + AccountMeta::new_readonly(*realm_authority, true), + AccountMeta::new(*payer, true), + AccountMeta::new_readonly(system_program::id(), false), + ]; + + let instruction = GovernanceInstruction::SetRealmConfigItem { args }; + + Instruction { + program_id: *program_id, + accounts, + data: borsh::to_vec(&instruction).unwrap(), } } diff --git a/governance/program/src/lib.rs b/governance/program/src/lib.rs index 6a7eb0319a5..91c6ee6bef6 100644 --- a/governance/program/src/lib.rs +++ b/governance/program/src/lib.rs @@ -1,3 +1,5 @@ +#![allow(clippy::arithmetic_side_effects)] +#![allow(clippy::doc_lazy_continuation)] #![deny(missing_docs)] //! A Governance program for the Solana blockchain. @@ -9,10 +11,12 @@ pub mod processor; pub mod state; pub mod tools; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version pub use solana_program; /// Seed prefix for Governance PDAs -/// Note: This prefix is used for the initial set of PDAs and shouldn't be used for any new accounts -/// All new PDAs should use a unique prefix to guarantee uniqueness for each account +/// Note: This prefix is used for the initial set of PDAs and shouldn't be used +/// for any new accounts All new PDAs should use a unique prefix to guarantee +/// uniqueness for each account pub const PROGRAM_AUTHORITY_SEED: &[u8] = b"governance"; diff --git a/governance/program/src/processor/mod.rs b/governance/program/src/processor/mod.rs index e8011875a10..a946563c48c 100644 --- a/governance/program/src/processor/mod.rs +++ b/governance/program/src/processor/mod.rs @@ -1,64 +1,73 @@ //! Program processor +mod process_add_required_signatory; mod process_add_signatory; mod process_cancel_proposal; mod process_cast_vote; +mod process_complete_proposal; mod process_create_governance; -mod process_create_mint_governance; mod process_create_native_treasury; -mod process_create_program_governance; + mod process_create_proposal; mod process_create_realm; -mod process_create_token_governance; + mod process_create_token_owner_record; mod process_deposit_governing_tokens; mod process_execute_transaction; mod process_finalize_vote; -mod process_flag_transaction_error; + mod process_insert_transaction; +mod process_refund_proposal_deposit; +mod process_relinquish_token_owner_record_locks; mod process_relinquish_vote; -mod process_remove_signatory; +mod process_remove_required_signatory; mod process_remove_transaction; +mod process_revoke_governing_tokens; mod process_set_governance_config; mod process_set_governance_delegate; mod process_set_realm_authority; mod process_set_realm_config; +mod process_set_realm_config_item; +mod process_set_token_owner_record_lock; mod process_sign_off_proposal; mod process_update_program_metadata; mod process_withdraw_governing_tokens; -use crate::instruction::GovernanceInstruction; - -use process_add_signatory::*; -use process_cancel_proposal::*; -use process_cast_vote::*; -use process_create_governance::*; -use process_create_mint_governance::*; -use process_create_native_treasury::*; -use process_create_program_governance::*; -use process_create_proposal::*; -use process_create_realm::*; -use process_create_token_governance::*; -use process_create_token_owner_record::*; -use process_deposit_governing_tokens::*; -use process_execute_transaction::*; -use process_finalize_vote::*; -use process_flag_transaction_error::*; -use process_insert_transaction::*; -use process_relinquish_vote::*; -use process_remove_signatory::*; -use process_remove_transaction::*; -use process_set_governance_config::*; -use process_set_governance_delegate::*; -use process_set_realm_authority::*; -use process_set_realm_config::*; -use process_sign_off_proposal::*; -use process_update_program_metadata::*; -use process_withdraw_governing_tokens::*; - -use solana_program::{ - account_info::AccountInfo, borsh::try_from_slice_unchecked, entrypoint::ProgramResult, msg, - program_error::ProgramError, pubkey::Pubkey, +use { + crate::{error::GovernanceError, instruction::GovernanceInstruction}, + process_add_required_signatory::*, + process_add_signatory::*, + process_cancel_proposal::*, + process_cast_vote::*, + process_complete_proposal::*, + process_create_governance::*, + process_create_native_treasury::*, + process_create_proposal::*, + process_create_realm::*, + process_create_token_owner_record::*, + process_deposit_governing_tokens::*, + process_execute_transaction::*, + process_finalize_vote::*, + process_insert_transaction::*, + process_refund_proposal_deposit::*, + process_relinquish_token_owner_record_locks::*, + process_relinquish_vote::*, + process_remove_required_signatory::*, + process_remove_transaction::*, + process_revoke_governing_tokens::*, + process_set_governance_config::*, + process_set_governance_delegate::*, + process_set_realm_authority::*, + process_set_realm_config::*, + process_set_realm_config_item::*, + process_set_token_owner_record_lock::*, + process_sign_off_proposal::*, + process_update_program_metadata::*, + process_withdraw_governing_tokens::*, + solana_program::{ + account_info::AccountInfo, borsh1::try_from_slice_unchecked, entrypoint::ProgramResult, + msg, program_error::ProgramError, pubkey::Pubkey, + }, }; /// Processes an instruction @@ -68,23 +77,23 @@ pub fn process_instruction( input: &[u8], ) -> ProgramResult { msg!("VERSION:{:?}", env!("CARGO_PKG_VERSION")); - // Use try_from_slice_unchecked to support forward compatibility of newer UI with older program + // Use try_from_slice_unchecked to support forward compatibility of newer UI + // with older program let instruction: GovernanceInstruction = try_from_slice_unchecked(input).map_err(|_| ProgramError::InvalidInstructionData)?; if let GovernanceInstruction::InsertTransaction { option_index, index, - hold_up_time, + legacy: _, instructions: _, } = instruction { // Do not dump instruction data into logs msg!( - "GOVERNANCE-INSTRUCTION: InsertInstruction {{option_index: {:?}, index: {:?}, hold_up_time: {:?} }}", + "GOVERNANCE-INSTRUCTION: InsertInstruction {{option_index: {:?}, index: {:?}}}", option_index, index, - hold_up_time ); } else { msg!("GOVERNANCE-INSTRUCTION: {:?}", instruction); @@ -107,33 +116,6 @@ pub fn process_instruction( new_governance_delegate, } => process_set_governance_delegate(program_id, accounts, &new_governance_delegate), - GovernanceInstruction::CreateProgramGovernance { - config, - transfer_upgrade_authority, - } => process_create_program_governance( - program_id, - accounts, - config, - transfer_upgrade_authority, - ), - - GovernanceInstruction::CreateMintGovernance { - config, - transfer_mint_authorities, - } => { - process_create_mint_governance(program_id, accounts, config, transfer_mint_authorities) - } - - GovernanceInstruction::CreateTokenGovernance { - config, - transfer_account_authorities, - } => process_create_token_governance( - program_id, - accounts, - config, - transfer_account_authorities, - ), - GovernanceInstruction::CreateGovernance { config } => { process_create_governance(program_id, accounts, config) } @@ -144,6 +126,7 @@ pub fn process_instruction( vote_type: proposal_type, options, use_deny_option, + proposal_seed, } => process_create_proposal( program_id, accounts, @@ -152,12 +135,17 @@ pub fn process_instruction( proposal_type, options, use_deny_option, + proposal_seed, ), GovernanceInstruction::AddSignatory { signatory } => { process_add_signatory(program_id, accounts, signatory) } - GovernanceInstruction::RemoveSignatory { signatory } => { - process_remove_signatory(program_id, accounts, signatory) + GovernanceInstruction::Legacy1 + | GovernanceInstruction::Legacy2 + | GovernanceInstruction::Legacy3 + | GovernanceInstruction::Legacy4 + | GovernanceInstruction::Legacy5 => { + Err(GovernanceError::InstructionDeprecated.into()) // No-op } GovernanceInstruction::SignOffProposal {} => { process_sign_off_proposal(program_id, accounts) @@ -173,16 +161,9 @@ pub fn process_instruction( GovernanceInstruction::InsertTransaction { option_index, index, - hold_up_time, - instructions, - } => process_insert_transaction( - program_id, - accounts, - option_index, - index, - hold_up_time, + legacy: _, instructions, - ), + } => process_insert_transaction(program_id, accounts, option_index, index, instructions), GovernanceInstruction::RemoveTransaction {} => { process_remove_transaction(program_id, accounts) @@ -195,9 +176,6 @@ pub fn process_instruction( process_set_governance_config(program_id, accounts, config) } - GovernanceInstruction::FlagTransactionError {} => { - process_flag_transaction_error(program_id, accounts) - } GovernanceInstruction::SetRealmAuthority { action } => { process_set_realm_authority(program_id, accounts, action) } @@ -213,5 +191,36 @@ pub fn process_instruction( GovernanceInstruction::CreateNativeTreasury {} => { process_create_native_treasury(program_id, accounts) } + + GovernanceInstruction::RevokeGoverningTokens { amount } => { + process_revoke_governing_tokens(program_id, accounts, amount) + } + + GovernanceInstruction::RefundProposalDeposit {} => { + process_refund_proposal_deposit(program_id, accounts) + } + + GovernanceInstruction::CompleteProposal {} => { + process_complete_proposal(program_id, accounts) + } + + GovernanceInstruction::AddRequiredSignatory { signatory } => { + process_add_required_signatory(program_id, accounts, signatory) + } + GovernanceInstruction::RemoveRequiredSignatory => { + process_remove_required_signatory(program_id, accounts) + } + + GovernanceInstruction::SetTokenOwnerRecordLock { lock_id, expiry } => { + process_set_token_owner_record_lock(program_id, accounts, lock_id, expiry) + } + + GovernanceInstruction::RelinquishTokenOwnerRecordLocks { lock_ids } => { + process_relinquish_token_owner_record_locks(program_id, accounts, lock_ids) + } + + GovernanceInstruction::SetRealmConfigItem { args } => { + process_set_realm_config_item(program_id, accounts, args) + } } } diff --git a/governance/program/src/processor/process_add_required_signatory.rs b/governance/program/src/processor/process_add_required_signatory.rs new file mode 100644 index 00000000000..a3245799364 --- /dev/null +++ b/governance/program/src/processor/process_add_required_signatory.rs @@ -0,0 +1,70 @@ +//! Program state processor + +use { + crate::{ + error::GovernanceError, + state::{ + enums::GovernanceAccountType, + governance::get_governance_data, + required_signatory::{get_required_signatory_address_seeds, RequiredSignatory}, + }, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + pubkey::Pubkey, + rent::Rent, + sysvar::Sysvar, + }, + spl_governance_tools::account::create_and_serialize_account_signed, +}; + +/// Processes AddRequiredSignatory instruction +pub fn process_add_required_signatory( + program_id: &Pubkey, + accounts: &[AccountInfo], + signatory: Pubkey, +) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + + let governance_info = next_account_info(account_info_iter)?; // 0 + + let required_signatory_info = next_account_info(account_info_iter)?; // 1 + + let payer_info = next_account_info(account_info_iter)?; // 2 + let system_info = next_account_info(account_info_iter)?; // 3 + + let rent = Rent::get()?; + + // Only governance PDA via a proposal can authorize change to its own config + if !governance_info.is_signer { + return Err(GovernanceError::GovernancePdaMustSign.into()); + }; + + let mut governance_data = get_governance_data(program_id, governance_info)?; + governance_data.required_signatories_count = governance_data + .required_signatories_count + .checked_add(1) + .unwrap(); + governance_data.serialize(&mut governance_info.data.borrow_mut()[..])?; + + let signatory_record_data = RequiredSignatory { + signatory, + account_type: GovernanceAccountType::RequiredSignatory, + governance: *governance_info.key, + account_version: 0, + }; + + create_and_serialize_account_signed::( + payer_info, + required_signatory_info, + &signatory_record_data, + &get_required_signatory_address_seeds(governance_info.key, &signatory), + program_id, + system_info, + &rent, + 0, + )?; + + Ok(()) +} diff --git a/governance/program/src/processor/process_add_signatory.rs b/governance/program/src/processor/process_add_signatory.rs index e441821e7a0..82ae9ca7c32 100644 --- a/governance/program/src/processor/process_add_signatory.rs +++ b/governance/program/src/processor/process_add_signatory.rs @@ -1,19 +1,25 @@ //! Program state processor -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - pubkey::Pubkey, - rent::Rent, - sysvar::Sysvar, -}; -use spl_governance_tools::account::create_and_serialize_account_signed; - -use crate::state::{ - enums::GovernanceAccountType, - proposal::get_proposal_data, - signatory_record::{get_signatory_record_address_seeds, SignatoryRecordV2}, - token_owner_record::get_token_owner_record_data_for_proposal_owner, +use { + crate::{ + error::GovernanceError, + state::{ + enums::GovernanceAccountType, + governance::get_governance_data, + proposal::get_proposal_data_for_governance, + required_signatory::get_required_signatory_data_for_governance, + signatory_record::{get_signatory_record_address_seeds, SignatoryRecordV2}, + token_owner_record::get_token_owner_record_data_for_proposal_owner, + }, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + pubkey::Pubkey, + rent::Rent, + sysvar::Sysvar, + }, + spl_governance_tools::account::create_and_serialize_account_signed, }; /// Processes AddSignatory instruction @@ -24,27 +30,51 @@ pub fn process_add_signatory( ) -> ProgramResult { let account_info_iter = &mut accounts.iter(); - let proposal_info = next_account_info(account_info_iter)?; // 0 - let token_owner_record_info = next_account_info(account_info_iter)?; // 1 - let governance_authority_info = next_account_info(account_info_iter)?; // 2 - - let signatory_record_info = next_account_info(account_info_iter)?; // 3 + let governance_info = next_account_info(account_info_iter)?; // 0 + let proposal_info = next_account_info(account_info_iter)?; // 1 + let signatory_record_info = next_account_info(account_info_iter)?; // 2 - let payer_info = next_account_info(account_info_iter)?; // 4 - let system_info = next_account_info(account_info_iter)?; // 5 + let payer_info = next_account_info(account_info_iter)?; // 3 + let system_info = next_account_info(account_info_iter)?; // 4 - let rent = Rent::get()?; + let governance_data = get_governance_data(program_id, governance_info)?; - let mut proposal_data = get_proposal_data(program_id, proposal_info)?; + let mut proposal_data = + get_proposal_data_for_governance(program_id, proposal_info, governance_info.key)?; proposal_data.assert_can_edit_signatories()?; - let token_owner_record_data = get_token_owner_record_data_for_proposal_owner( - program_id, - token_owner_record_info, - &proposal_data.token_owner_record, - )?; + if !signatory_record_info.data_is_empty() { + return Err(GovernanceError::SignatoryRecordAlreadyExists.into()); + } - token_owner_record_data.assert_token_owner_or_delegate_is_signer(governance_authority_info)?; + // All required signatories must be added before additional signatories can be + // added + if proposal_data.signatories_count < governance_data.required_signatories_count { + let required_signatory_info = next_account_info(account_info_iter)?; // 5 + let required_signatory_data = get_required_signatory_data_for_governance( + program_id, + required_signatory_info, + governance_info.key, + )?; + + if required_signatory_data.signatory != signatory { + return Err(GovernanceError::InvalidSignatoryAddress.into()); + } + } else { + let token_owner_record_info = next_account_info(account_info_iter)?; // 5 + let governance_authority_info = next_account_info(account_info_iter)?; // 6 + + let token_owner_record_data = get_token_owner_record_data_for_proposal_owner( + program_id, + token_owner_record_info, + &proposal_data.token_owner_record, + )?; + + token_owner_record_data + .assert_token_owner_or_delegate_is_signer(governance_authority_info)?; + } + + let rent = Rent::get()?; let signatory_record_data = SignatoryRecordV2 { account_type: GovernanceAccountType::SignatoryRecordV2, @@ -62,10 +92,11 @@ pub fn process_add_signatory( program_id, system_info, &rent, + 0, )?; proposal_data.signatories_count = proposal_data.signatories_count.checked_add(1).unwrap(); - proposal_data.serialize(&mut *proposal_info.data.borrow_mut())?; + proposal_data.serialize(&mut proposal_info.data.borrow_mut()[..])?; Ok(()) } diff --git a/governance/program/src/processor/process_cancel_proposal.rs b/governance/program/src/processor/process_cancel_proposal.rs index 046cfc274b5..bdb73a65ce9 100644 --- a/governance/program/src/processor/process_cancel_proposal.rs +++ b/governance/program/src/processor/process_cancel_proposal.rs @@ -1,17 +1,18 @@ //! Program state processor -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - clock::Clock, - entrypoint::ProgramResult, - pubkey::Pubkey, - sysvar::Sysvar, -}; - -use crate::state::{ - enums::ProposalState, governance::get_governance_data_for_realm, - proposal::get_proposal_data_for_governance, realm::get_realm_data, - token_owner_record::get_token_owner_record_data_for_proposal_owner, +use { + crate::state::{ + enums::ProposalState, governance::get_governance_data_for_realm, + proposal::get_proposal_data_for_governance, realm::assert_is_valid_realm, + token_owner_record::get_token_owner_record_data_for_proposal_owner, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + clock::Clock, + entrypoint::ProgramResult, + pubkey::Pubkey, + sysvar::Sysvar, + }, }; /// Processes CancelProposal instruction @@ -26,7 +27,7 @@ pub fn process_cancel_proposal(program_id: &Pubkey, accounts: &[AccountInfo]) -> let clock = Clock::get()?; - let mut realm_data = get_realm_data(program_id, realm_info)?; + assert_is_valid_realm(program_id, realm_info)?; let mut governance_data = get_governance_data_for_realm(program_id, governance_info, realm_info.key)?; @@ -45,23 +46,16 @@ pub fn process_cancel_proposal(program_id: &Pubkey, accounts: &[AccountInfo]) -> .assert_token_owner_or_delegate_is_signer(governance_authority_info)?; proposal_owner_record_data.decrease_outstanding_proposal_count(); - proposal_owner_record_data.serialize(&mut *proposal_owner_record_info.data.borrow_mut())?; - - if proposal_data.state == ProposalState::Voting { - // Update Realm voting_proposal_count - realm_data.voting_proposal_count = realm_data.voting_proposal_count.saturating_sub(1); - realm_data.serialize(&mut *realm_info.data.borrow_mut())?; - - // Update Governance voting_proposal_count - governance_data.voting_proposal_count = - governance_data.voting_proposal_count.saturating_sub(1); - governance_data.serialize(&mut *governance_info.data.borrow_mut())?; - } + proposal_owner_record_data.serialize(&mut proposal_owner_record_info.data.borrow_mut()[..])?; proposal_data.state = ProposalState::Cancelled; proposal_data.closed_at = Some(clock.unix_timestamp); - proposal_data.serialize(&mut *proposal_info.data.borrow_mut())?; + proposal_data.serialize(&mut proposal_info.data.borrow_mut()[..])?; + + // Update Governance active_proposal_count + governance_data.active_proposal_count = governance_data.active_proposal_count.saturating_sub(1); + governance_data.serialize(&mut governance_info.data.borrow_mut()[..])?; Ok(()) } diff --git a/governance/program/src/processor/process_cast_vote.rs b/governance/program/src/processor/process_cast_vote.rs index aec2e1e8a93..e331d87e7fb 100644 --- a/governance/program/src/processor/process_cast_vote.rs +++ b/governance/program/src/processor/process_cast_vote.rs @@ -1,29 +1,31 @@ //! Program state processor -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - clock::Clock, - entrypoint::ProgramResult, - pubkey::Pubkey, - rent::Rent, - sysvar::Sysvar, -}; -use spl_governance_addin_api::voter_weight::VoterWeightAction; -use spl_governance_tools::account::create_and_serialize_account_signed; - -use crate::{ - error::GovernanceError, - state::{ - enums::GovernanceAccountType, - governance::get_governance_data_for_realm, - proposal::get_proposal_data_for_governance_and_governing_mint, - realm::get_realm_data_for_governing_token_mint, - token_owner_record::{ - get_token_owner_record_data_for_proposal_owner, - get_token_owner_record_data_for_realm_and_governing_mint, +use { + crate::{ + error::GovernanceError, + state::{ + enums::GovernanceAccountType, + governance::get_governance_data_for_realm, + proposal::get_proposal_data_for_governance_and_governing_mint, + realm::get_realm_data_for_governing_token_mint, + realm_config::get_realm_config_data_for_realm, + token_owner_record::{ + get_token_owner_record_data_for_proposal_owner, + get_token_owner_record_data_for_realm_and_governing_mint, + }, + vote_record::{get_vote_kind, get_vote_record_address_seeds, Vote, VoteRecordV2}, }, - vote_record::{get_vote_kind, get_vote_record_address_seeds, Vote, VoteRecordV2}, }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + clock::Clock, + entrypoint::ProgramResult, + pubkey::Pubkey, + rent::Rent, + sysvar::Sysvar, + }, + spl_governance_addin_api::voter_weight::VoterWeightAction, + spl_governance_tools::account::create_and_serialize_account_signed, }; /// Processes CastVote instruction @@ -56,7 +58,7 @@ pub fn process_cast_vote( return Err(GovernanceError::VoteAlreadyExists.into()); } - let mut realm_data = get_realm_data_for_governing_token_mint( + let realm_data = get_realm_data_for_governing_token_mint( program_id, realm_info, vote_governing_token_mint_info.key, @@ -67,9 +69,10 @@ pub fn process_cast_vote( let vote_kind = get_vote_kind(&vote); - // Get the governing_token_mint which the Proposal should be configured with as the voting population for the given vote - // For Approve, Deny and Abstain votes it's the same as vote_governing_token_mint - // For Veto it's the governing token mint of the opposite voting population + // Get the governing_token_mint which the Proposal should be configured with as + // the voting population for the given vote For Approve, Deny and Abstain + // votes it's the same as vote_governing_token_mint For Veto it's the + // governing token mint of the opposite voting population let proposal_governing_token_mint = realm_data.get_proposal_governing_token_mint_for_vote( vote_governing_token_mint_info.key, &vote_kind, @@ -81,7 +84,7 @@ pub fn process_cast_vote( governance_info.key, &proposal_governing_token_mint, )?; - proposal_data.assert_can_cast_vote(&governance_data.config, clock.unix_timestamp)?; + proposal_data.assert_can_cast_vote(&governance_data.config, &vote, clock.unix_timestamp)?; let mut voter_token_owner_record_data = get_token_owner_record_data_for_realm_and_governing_mint( @@ -99,22 +102,14 @@ pub fn process_cast_vote( .checked_add(1) .unwrap(); - voter_token_owner_record_data.total_votes_count = voter_token_owner_record_data - .total_votes_count - .checked_add(1) - .unwrap(); - - // Note: When both voter_weight and max_voter_weight addins are used the realm_config will be deserialized twice in resolve_voter_weight() and resolve_max_voter_weight() - // It can't be deserialized eagerly because some realms won't have the config if they don't use any of the advanced options - // This extra deserialisation should be acceptable to keep things simple and encapsulated. - let realm_config_info = next_account_info(account_info_iter)?; //9 + let realm_config_info = next_account_info(account_info_iter)?; // 9 + let realm_config_data = + get_realm_config_data_for_realm(program_id, realm_config_info, realm_info.key)?; let voter_weight = voter_token_owner_record_data.resolve_voter_weight( - program_id, - realm_config_info, - account_info_iter, // voter_weight_record 10 - realm_info.key, + account_info_iter, // voter_weight_record *10 &realm_data, + &realm_config_data, VoterWeightAction::CastVote, proposal_info.key, )?; @@ -152,12 +147,11 @@ pub fn process_cast_vote( } let max_voter_weight = proposal_data.resolve_max_voter_weight( - program_id, - realm_config_info, - vote_governing_token_mint_info, account_info_iter, // max_voter_weight_record 11 realm_info.key, &realm_data, + &realm_config_data, + vote_governing_token_mint_info, &vote_kind, )?; @@ -169,7 +163,7 @@ pub fn process_cast_vote( if proposal_data.try_tip_vote( max_voter_weight, - &governance_data.config.vote_tipping, + governance_data.get_vote_tipping(&realm_data, vote_governing_token_mint_info.key)?, clock.unix_timestamp, &vote_threshold, &vote_kind, @@ -181,31 +175,28 @@ pub fn process_cast_vote( &proposal_data.token_owner_record, )?; - // If the voter is also the proposal owner then update the voter record which is serialized for the voter later on + // If the voter is also the proposal owner then update the voter record which is + // serialized for the voter later on if proposal_owner_record_info.key == voter_token_owner_record_info.key { voter_token_owner_record_data.decrease_outstanding_proposal_count(); } else { proposal_owner_record_data.decrease_outstanding_proposal_count(); proposal_owner_record_data - .serialize(&mut *proposal_owner_record_info.data.borrow_mut())?; + .serialize(&mut proposal_owner_record_info.data.borrow_mut()[..])?; }; - // Update Realm voting_proposal_count - realm_data.voting_proposal_count = realm_data.voting_proposal_count.saturating_sub(1); - realm_data.serialize(&mut *realm_info.data.borrow_mut())?; - - // Update Governance voting_proposal_count - governance_data.voting_proposal_count = - governance_data.voting_proposal_count.saturating_sub(1); - governance_data.serialize(&mut *governance_info.data.borrow_mut())?; + // If the proposal is tipped decrease Governance active_proposal_count + governance_data.active_proposal_count = + governance_data.active_proposal_count.saturating_sub(1); + governance_data.serialize(&mut governance_info.data.borrow_mut()[..])?; } let governing_token_owner = voter_token_owner_record_data.governing_token_owner; voter_token_owner_record_data - .serialize(&mut *voter_token_owner_record_info.data.borrow_mut())?; + .serialize(&mut voter_token_owner_record_info.data.borrow_mut()[..])?; - proposal_data.serialize(&mut *proposal_info.data.borrow_mut())?; + proposal_data.serialize(&mut proposal_info.data.borrow_mut()[..])?; // Create and serialize VoteRecord let vote_record_data = VoteRecordV2 { @@ -226,6 +217,7 @@ pub fn process_cast_vote( program_id, system_info, &rent, + 0, )?; Ok(()) diff --git a/governance/program/src/processor/process_complete_proposal.rs b/governance/program/src/processor/process_complete_proposal.rs new file mode 100644 index 00000000000..6d2c017cda5 --- /dev/null +++ b/governance/program/src/processor/process_complete_proposal.rs @@ -0,0 +1,42 @@ +//! Program state processor + +use { + crate::state::{ + enums::ProposalState, proposal::get_proposal_data, + token_owner_record::get_token_owner_record_data_for_proposal_owner, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + clock::Clock, + entrypoint::ProgramResult, + pubkey::Pubkey, + sysvar::Sysvar, + }, +}; + +/// Processes CompleteProposal instruction +pub fn process_complete_proposal(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + + let proposal_info = next_account_info(account_info_iter)?; // 0 + let token_owner_record_info = next_account_info(account_info_iter)?; // 1 + let complete_proposal_authority_info = next_account_info(account_info_iter)?; // 2 + + let mut proposal_data = get_proposal_data(program_id, proposal_info)?; + proposal_data.assert_can_complete()?; + + let token_owner_record_data = get_token_owner_record_data_for_proposal_owner( + program_id, + token_owner_record_info, + &proposal_data.token_owner_record, + )?; + token_owner_record_data + .assert_token_owner_or_delegate_is_signer(complete_proposal_authority_info)?; + + let clock = Clock::get()?; + proposal_data.closed_at = Some(clock.unix_timestamp); + proposal_data.state = ProposalState::Completed; + + proposal_data.serialize(&mut proposal_info.data.borrow_mut()[..])?; + Ok(()) +} diff --git a/governance/program/src/processor/process_create_governance.rs b/governance/program/src/processor/process_create_governance.rs index 49d39032730..db630004d83 100644 --- a/governance/program/src/processor/process_create_governance.rs +++ b/governance/program/src/processor/process_create_governance.rs @@ -1,23 +1,27 @@ //! Program state processor -use crate::state::{ - enums::GovernanceAccountType, - governance::{ - assert_valid_create_governance_args, get_governance_address_seeds, GovernanceConfig, - GovernanceV2, +use { + crate::{ + state::{ + enums::GovernanceAccountType, + governance::{ + assert_valid_create_governance_args, get_governance_address_seeds, + GovernanceConfig, GovernanceV2, + }, + realm::get_realm_data, + }, + tools::structs::Reserved119, }, - realm::get_realm_data, -}; -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - pubkey::Pubkey, - rent::Rent, - sysvar::Sysvar, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + pubkey::Pubkey, + rent::Rent, + sysvar::Sysvar, + }, + spl_governance_tools::account::create_and_serialize_account_signed, }; -use spl_governance_tools::account::create_and_serialize_account_signed; - /// Processes CreateGovernance instruction pub fn process_create_governance( program_id: &Pubkey, @@ -28,7 +32,7 @@ pub fn process_create_governance( let realm_info = next_account_info(account_info_iter)?; // 0 let governance_info = next_account_info(account_info_iter)?; // 1 - let governed_account_info = next_account_info(account_info_iter)?; // 2 + let governance_seed_info = next_account_info(account_info_iter)?; // 2 let token_owner_record_info = next_account_info(account_info_iter)?; // 3 @@ -54,22 +58,23 @@ pub fn process_create_governance( let governance_data = GovernanceV2 { account_type: GovernanceAccountType::GovernanceV2, realm: *realm_info.key, - governed_account: *governed_account_info.key, + governance_seed: *governance_seed_info.key, config, - proposals_count: 0, - reserved: [0; 6], - voting_proposal_count: 0, - reserved_v2: [0; 128], + reserved1: 0, + reserved_v2: Reserved119::default(), + required_signatories_count: 0, + active_proposal_count: 0, }; create_and_serialize_account_signed::( payer_info, governance_info, &governance_data, - &get_governance_address_seeds(realm_info.key, governed_account_info.key), + &get_governance_address_seeds(realm_info.key, governance_seed_info.key), program_id, system_info, &rent, + 0, )?; Ok(()) diff --git a/governance/program/src/processor/process_create_mint_governance.rs b/governance/program/src/processor/process_create_mint_governance.rs deleted file mode 100644 index 37ba7eb4329..00000000000 --- a/governance/program/src/processor/process_create_mint_governance.rs +++ /dev/null @@ -1,117 +0,0 @@ -//! Program state processor - -use crate::{ - state::{ - enums::GovernanceAccountType, - governance::{ - assert_valid_create_governance_args, get_mint_governance_address_seeds, - GovernanceConfig, GovernanceV2, - }, - realm::get_realm_data, - }, - tools::spl_token::{ - assert_spl_token_mint_authority_is_signer, set_spl_token_account_authority, - }, -}; -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - program_pack::Pack, - pubkey::Pubkey, - rent::Rent, - sysvar::Sysvar, -}; - -use spl_governance_tools::account::create_and_serialize_account_signed; -use spl_token::{instruction::AuthorityType, state::Mint}; - -/// Processes CreateMintGovernance instruction -pub fn process_create_mint_governance( - program_id: &Pubkey, - accounts: &[AccountInfo], - config: GovernanceConfig, - transfer_mint_authorities: bool, -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - - let realm_info = next_account_info(account_info_iter)?; // 0 - let mint_governance_info = next_account_info(account_info_iter)?; // 1 - - let governed_mint_info = next_account_info(account_info_iter)?; // 2 - let governed_mint_authority_info = next_account_info(account_info_iter)?; // 3 - - let token_owner_record_info = next_account_info(account_info_iter)?; // 4 - - let payer_info = next_account_info(account_info_iter)?; // 5 - let spl_token_info = next_account_info(account_info_iter)?; // 6 - - let system_info = next_account_info(account_info_iter)?; // 7 - - let rent = Rent::get()?; - - let create_authority_info = next_account_info(account_info_iter)?; // 8 - - assert_valid_create_governance_args(program_id, &config, realm_info)?; - - let realm_data = get_realm_data(program_id, realm_info)?; - - realm_data.assert_create_authority_can_create_governance( - program_id, - realm_info.key, - token_owner_record_info, - create_authority_info, - account_info_iter, // realm_config_info 9, voter_weight_record_info 10 - )?; - - let mint_governance_data = GovernanceV2 { - account_type: GovernanceAccountType::MintGovernanceV2, - realm: *realm_info.key, - governed_account: *governed_mint_info.key, - config, - proposals_count: 0, - reserved: [0; 6], - voting_proposal_count: 0, - reserved_v2: [0; 128], - }; - - create_and_serialize_account_signed::( - payer_info, - mint_governance_info, - &mint_governance_data, - &get_mint_governance_address_seeds(realm_info.key, governed_mint_info.key), - program_id, - system_info, - &rent, - )?; - - if transfer_mint_authorities { - set_spl_token_account_authority( - governed_mint_info, - governed_mint_authority_info, - mint_governance_info.key, - AuthorityType::MintTokens, - spl_token_info, - )?; - - // If the mint has freeze_authority then transfer it as well - let mint_data = Mint::unpack(&governed_mint_info.data.borrow())?; - // Note: The code assumes mint_authority==freeze_authority - // If this is not the case then the caller should set freeze_authority accordingly before making the transfer - if mint_data.freeze_authority.is_some() { - set_spl_token_account_authority( - governed_mint_info, - governed_mint_authority_info, - mint_governance_info.key, - AuthorityType::FreezeAccount, - spl_token_info, - )?; - } - } else { - assert_spl_token_mint_authority_is_signer( - governed_mint_info, - governed_mint_authority_info, - )?; - } - - Ok(()) -} diff --git a/governance/program/src/processor/process_create_native_treasury.rs b/governance/program/src/processor/process_create_native_treasury.rs index 46cdc45cc72..3723f0ebabb 100644 --- a/governance/program/src/processor/process_create_native_treasury.rs +++ b/governance/program/src/processor/process_create_native_treasury.rs @@ -1,18 +1,19 @@ //! Program state processor -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - pubkey::Pubkey, - rent::Rent, - system_program, - sysvar::Sysvar, -}; -use spl_governance_tools::account::create_and_serialize_account_with_owner_signed; - -use crate::state::{ - governance::assert_is_valid_governance, - native_treasury::{get_native_treasury_address_seeds, NativeTreasury}, +use { + crate::state::{ + governance::assert_is_valid_governance, + native_treasury::{get_native_treasury_address_seeds, NativeTreasury}, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + pubkey::Pubkey, + rent::Rent, + system_program, + sysvar::Sysvar, + }, + spl_governance_tools::account::create_and_serialize_account_with_owner_signed, }; /// Processes CreateNativeTreasury instruction @@ -42,6 +43,7 @@ pub fn process_create_native_treasury( &system_program::id(), // System program as the PDA owner system_info, &rent, + 0, )?; Ok(()) diff --git a/governance/program/src/processor/process_create_program_governance.rs b/governance/program/src/processor/process_create_program_governance.rs deleted file mode 100644 index 26554931ecc..00000000000 --- a/governance/program/src/processor/process_create_program_governance.rs +++ /dev/null @@ -1,104 +0,0 @@ -//! Program state processor - -use crate::{ - state::governance::GovernanceV2, - state::{ - enums::GovernanceAccountType, - governance::{ - assert_valid_create_governance_args, get_program_governance_address_seeds, - GovernanceConfig, - }, - realm::get_realm_data, - }, - tools::bpf_loader_upgradeable::{ - assert_program_upgrade_authority_is_signer, set_program_upgrade_authority, - }, -}; -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - pubkey::Pubkey, - rent::Rent, - sysvar::Sysvar, -}; - -use spl_governance_tools::account::create_and_serialize_account_signed; - -/// Processes CreateProgramGovernance instruction -pub fn process_create_program_governance( - program_id: &Pubkey, - accounts: &[AccountInfo], - config: GovernanceConfig, - transfer_upgrade_authority: bool, -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - - let realm_info = next_account_info(account_info_iter)?; // 0 - let program_governance_info = next_account_info(account_info_iter)?; // 1 - - let governed_program_info = next_account_info(account_info_iter)?; // 2 - let governed_program_data_info = next_account_info(account_info_iter)?; // 3 - let governed_program_upgrade_authority_info = next_account_info(account_info_iter)?; // 4 - - let token_owner_record_info = next_account_info(account_info_iter)?; // 5 - - let payer_info = next_account_info(account_info_iter)?; // 6 - let bpf_upgrade_loader_info = next_account_info(account_info_iter)?; // 7 - - let system_info = next_account_info(account_info_iter)?; // 8 - - let rent = Rent::get()?; - - let create_authority_info = next_account_info(account_info_iter)?; // 9 - - assert_valid_create_governance_args(program_id, &config, realm_info)?; - - let realm_data = get_realm_data(program_id, realm_info)?; - - realm_data.assert_create_authority_can_create_governance( - program_id, - realm_info.key, - token_owner_record_info, - create_authority_info, - account_info_iter, // realm_config_info 10, voter_weight_record_info 11 - )?; - - let program_governance_data = GovernanceV2 { - account_type: GovernanceAccountType::ProgramGovernanceV2, - realm: *realm_info.key, - governed_account: *governed_program_info.key, - config, - proposals_count: 0, - reserved: [0; 6], - voting_proposal_count: 0, - reserved_v2: [0; 128], - }; - - create_and_serialize_account_signed::( - payer_info, - program_governance_info, - &program_governance_data, - &get_program_governance_address_seeds(realm_info.key, governed_program_info.key), - program_id, - system_info, - &rent, - )?; - - if transfer_upgrade_authority { - set_program_upgrade_authority( - governed_program_info.key, - governed_program_data_info, - governed_program_upgrade_authority_info, - program_governance_info, - bpf_upgrade_loader_info, - )?; - } else { - assert_program_upgrade_authority_is_signer( - governed_program_info.key, - governed_program_data_info, - governed_program_upgrade_authority_info, - )?; - } - - Ok(()) -} diff --git a/governance/program/src/processor/process_create_proposal.rs b/governance/program/src/processor/process_create_proposal.rs index f135fba0c67..9f2f320aee0 100644 --- a/governance/program/src/processor/process_create_proposal.rs +++ b/governance/program/src/processor/process_create_proposal.rs @@ -1,32 +1,36 @@ //! Program state processor -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - clock::Clock, - entrypoint::ProgramResult, - pubkey::Pubkey, - rent::Rent, - sysvar::Sysvar, -}; -use spl_governance_addin_api::voter_weight::VoterWeightAction; -use spl_governance_tools::account::create_and_serialize_account_signed; - -use crate::{ - error::GovernanceError, - state::{ - enums::{GovernanceAccountType, InstructionExecutionFlags, ProposalState}, - governance::get_governance_data_for_realm, - proposal::{ - assert_valid_proposal_options, get_proposal_address_seeds, OptionVoteResult, - ProposalOption, ProposalV2, VoteType, +use { + crate::{ + error::GovernanceError, + state::{ + enums::{GovernanceAccountType, InstructionExecutionFlags, ProposalState}, + governance::get_governance_data_for_realm, + proposal::{ + assert_valid_proposal_options, get_proposal_address_seeds, OptionVoteResult, + ProposalOption, ProposalV2, VoteType, + }, + proposal_deposit::{get_proposal_deposit_address_seeds, ProposalDeposit}, + realm::get_realm_data_for_governing_token_mint, + realm_config::get_realm_config_data_for_realm, + token_owner_record::get_token_owner_record_data_for_realm, + vote_record::VoteKind, }, - realm::get_realm_data_for_governing_token_mint, - token_owner_record::get_token_owner_record_data_for_realm, - vote_record::VoteKind, }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + clock::Clock, + entrypoint::ProgramResult, + pubkey::Pubkey, + rent::Rent, + sysvar::Sysvar, + }, + spl_governance_addin_api::voter_weight::VoterWeightAction, + spl_governance_tools::account::create_and_serialize_account_signed, }; /// Processes CreateProposal instruction +#[allow(clippy::too_many_arguments)] pub fn process_create_proposal( program_id: &Pubkey, accounts: &[AccountInfo], @@ -35,6 +39,7 @@ pub fn process_create_proposal( vote_type: VoteType, options: Vec, use_deny_option: bool, + proposal_seed: Pubkey, ) -> ProgramResult { let account_info_iter = &mut accounts.iter(); @@ -77,23 +82,25 @@ pub fn process_create_proposal( realm_info.key, )?; - // Proposal owner (TokenOwner) or its governance_delegate must sign this transaction + // Proposal owner (TokenOwner) or its governance_delegate must sign this + // transaction proposal_owner_record_data .assert_token_owner_or_delegate_is_signer(governance_authority_info)?; - let realm_config_info = next_account_info(account_info_iter)?; // 10 + let realm_config_info = next_account_info(account_info_iter)?; // 8 + let realm_config_data = + get_realm_config_data_for_realm(program_id, realm_config_info, realm_info.key)?; let voter_weight = proposal_owner_record_data.resolve_voter_weight( - program_id, - realm_config_info, - account_info_iter, - realm_info.key, + account_info_iter, // voter_weight_record *9 &realm_data, + &realm_config_data, VoterWeightAction::CreateProposal, governance_info.key, )?; - // Ensure proposal owner (TokenOwner) has enough tokens to create proposal and no outstanding proposals + // Ensure proposal owner (TokenOwner) has enough tokens to create proposal and + // no outstanding proposals proposal_owner_record_data.assert_can_create_proposal( &realm_data, &governance_data.config, @@ -104,7 +111,7 @@ pub fn process_create_proposal( .outstanding_proposal_count .checked_add(1) .unwrap(); - proposal_owner_record_data.serialize(&mut *proposal_owner_record_info.data.borrow_mut())?; + proposal_owner_record_data.serialize(&mut proposal_owner_record_info.data.borrow_mut()[..])?; assert_valid_proposal_options(&options, &vote_type)?; @@ -168,15 +175,44 @@ pub fn process_create_proposal( &get_proposal_address_seeds( governance_info.key, governing_token_mint_info.key, - &governance_data.proposals_count.to_le_bytes(), + &proposal_seed, ), program_id, system_info, &rent, + 0, )?; - governance_data.proposals_count = governance_data.proposals_count.checked_add(1).unwrap(); - governance_data.serialize(&mut *governance_info.data.borrow_mut())?; + governance_data.active_proposal_count = governance_data + .active_proposal_count + .checked_add(1) + .unwrap(); + + // Take Proposal deposit if needed + let proposal_deposit_amount = governance_data.get_proposal_deposit_amount(); + if proposal_deposit_amount > 0 { + let proposal_deposit_info = next_account_info(account_info_iter)?; // *10 + let proposal_deposit_data = ProposalDeposit { + account_type: GovernanceAccountType::ProposalDeposit, + proposal: *proposal_info.key, + deposit_payer: *payer_info.key, + reserved: [0; 64], + }; + + create_and_serialize_account_signed::( + payer_info, + proposal_deposit_info, + &proposal_deposit_data, + &get_proposal_deposit_address_seeds(proposal_info.key, payer_info.key), + program_id, + system_info, + &rent, + proposal_deposit_amount, + )?; + } + + // Serialize the governance account update to GovernanceV2 if needed + governance_data.serialize_as_governance_v2(governance_info, payer_info, system_info, &rent)?; Ok(()) } diff --git a/governance/program/src/processor/process_create_realm.rs b/governance/program/src/processor/process_create_realm.rs index 03d212b9cf7..33773ae6c45 100644 --- a/governance/program/src/processor/process_create_realm.rs +++ b/governance/program/src/processor/process_create_realm.rs @@ -1,25 +1,28 @@ //! Program state processor -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - pubkey::Pubkey, - rent::Rent, - sysvar::Sysvar, -}; -use spl_governance_tools::account::create_and_serialize_account_signed; - -use crate::{ - error::GovernanceError, - state::{ - enums::GovernanceAccountType, - realm::{ - assert_valid_realm_config_args, get_governing_token_holding_address_seeds, - get_realm_address_seeds, RealmConfig, RealmConfigArgs, RealmV2, +use { + crate::{ + error::GovernanceError, + state::{ + enums::GovernanceAccountType, + realm::{ + assert_valid_realm_config_args, get_governing_token_holding_address_seeds, + get_realm_address_seeds, RealmConfig, RealmConfigArgs, RealmV2, + }, + realm_config::{ + get_realm_config_address_seeds, resolve_governing_token_config, RealmConfigAccount, + }, }, - realm_config::{get_realm_config_address_seeds, RealmConfigAccount}, + tools::{spl_token::create_spl_token_account_signed, structs::Reserved110}, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + pubkey::Pubkey, + rent::Rent, + sysvar::Sysvar, }, - tools::spl_token::create_spl_token_account_signed, + spl_governance_tools::account::create_and_serialize_account_signed, }; /// Processes CreateRealm instruction @@ -27,7 +30,7 @@ pub fn process_create_realm( program_id: &Pubkey, accounts: &[AccountInfo], name: String, - config_args: RealmConfigArgs, + realm_config_args: RealmConfigArgs, ) -> ProgramResult { let account_info_iter = &mut accounts.iter(); @@ -46,8 +49,9 @@ pub fn process_create_realm( return Err(GovernanceError::RealmAlreadyExists.into()); } - assert_valid_realm_config_args(&config_args)?; + assert_valid_realm_config_args(&realm_config_args)?; + // Create Community token holding account create_spl_token_account_signed( payer_info, governance_token_holding_info, @@ -61,7 +65,8 @@ pub fn process_create_realm( rent, )?; - let council_token_mint_address = if config_args.use_council_mint { + // Create Council token holding account + let council_token_mint_address = if realm_config_args.use_council_mint { let council_token_mint_info = next_account_info(account_info_iter)?; // 8 let council_token_holding_info = next_account_info(account_info_iter)?; // 9 @@ -83,48 +88,43 @@ pub fn process_create_realm( None }; - // Setup config for addins + // Create and serialize RealmConfig + let realm_config_info = next_account_info(account_info_iter)?; // 10 - let community_voter_weight_addin = if config_args.use_community_voter_weight_addin { - let community_voter_weight_addin_info = next_account_info(account_info_iter)?; // 10 - Some(*community_voter_weight_addin_info.key) - } else { - None - }; + // 11, 12 + let community_token_config = resolve_governing_token_config( + account_info_iter, + &realm_config_args.community_token_config_args, + None, + )?; - let max_community_voter_weight_addin = if config_args.use_max_community_voter_weight_addin { - let max_community_voter_weight_addin_info = next_account_info(account_info_iter)?; // 11 - Some(*max_community_voter_weight_addin_info.key) - } else { - None + // 13, 14 + let council_token_config = resolve_governing_token_config( + account_info_iter, + &realm_config_args.council_token_config_args, + None, + )?; + + let realm_config_data = RealmConfigAccount { + account_type: GovernanceAccountType::RealmConfig, + realm: *realm_info.key, + community_token_config, + council_token_config, + reserved: Reserved110::default(), }; - if config_args.use_community_voter_weight_addin - || config_args.use_max_community_voter_weight_addin - { - let realm_config_info = next_account_info(account_info_iter)?; // 12 - - let realm_config_data = RealmConfigAccount { - account_type: GovernanceAccountType::RealmConfig, - realm: *realm_info.key, - community_voter_weight_addin, - max_community_voter_weight_addin, - council_voter_weight_addin: None, - council_max_vote_weight_addin: None, - reserved: [0; 128], - }; - - create_and_serialize_account_signed::( - payer_info, - realm_config_info, - &realm_config_data, - &get_realm_config_address_seeds(realm_info.key), - program_id, - system_info, - rent, - )?; - } + create_and_serialize_account_signed::( + payer_info, + realm_config_info, + &realm_config_data, + &get_realm_config_address_seeds(realm_info.key), + program_id, + system_info, + rent, + 0, + )?; + // Create and serialize Realm let realm_data = RealmV2 { account_type: GovernanceAccountType::RealmV2, community_mint: *governance_token_mint_info.key, @@ -135,14 +135,14 @@ pub fn process_create_realm( config: RealmConfig { council_mint: council_token_mint_address, reserved: [0; 6], - community_mint_max_vote_weight_source: config_args - .community_mint_max_vote_weight_source, - min_community_weight_to_create_governance: config_args + community_mint_max_voter_weight_source: realm_config_args + .community_mint_max_voter_weight_source, + min_community_weight_to_create_governance: realm_config_args .min_community_weight_to_create_governance, - use_community_voter_weight_addin: config_args.use_community_voter_weight_addin, - use_max_community_voter_weight_addin: config_args.use_max_community_voter_weight_addin, + legacy1: 0, + legacy2: 0, }, - voting_proposal_count: 0, + legacy1: 0, reserved_v2: [0; 128], }; @@ -154,6 +154,7 @@ pub fn process_create_realm( program_id, system_info, rent, + 0, )?; Ok(()) diff --git a/governance/program/src/processor/process_create_token_governance.rs b/governance/program/src/processor/process_create_token_governance.rs deleted file mode 100644 index 370ee5c8b1c..00000000000 --- a/governance/program/src/processor/process_create_token_governance.rs +++ /dev/null @@ -1,112 +0,0 @@ -//! Program state processor - -use crate::{ - state::{ - enums::GovernanceAccountType, - governance::{ - assert_valid_create_governance_args, get_token_governance_address_seeds, - GovernanceConfig, GovernanceV2, - }, - realm::get_realm_data, - }, - tools::spl_token::{assert_spl_token_owner_is_signer, set_spl_token_account_authority}, -}; -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - program_pack::Pack, - pubkey::Pubkey, - rent::Rent, - sysvar::Sysvar, -}; - -use spl_governance_tools::account::create_and_serialize_account_signed; -use spl_token::{instruction::AuthorityType, state::Account}; - -/// Processes CreateTokenGovernance instruction -pub fn process_create_token_governance( - program_id: &Pubkey, - accounts: &[AccountInfo], - config: GovernanceConfig, - transfer_account_authorities: bool, -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - - let realm_info = next_account_info(account_info_iter)?; // 0 - let token_governance_info = next_account_info(account_info_iter)?; // 1 - - let governed_token_info = next_account_info(account_info_iter)?; // 2 - let governed_token_owner_info = next_account_info(account_info_iter)?; // 3 - - let token_owner_record_info = next_account_info(account_info_iter)?; // 4 - - let payer_info = next_account_info(account_info_iter)?; // 5 - let spl_token_info = next_account_info(account_info_iter)?; // 6 - - let system_info = next_account_info(account_info_iter)?; // 7 - - let rent = Rent::get()?; - - let create_authority_info = next_account_info(account_info_iter)?; // 8 - - assert_valid_create_governance_args(program_id, &config, realm_info)?; - - let realm_data = get_realm_data(program_id, realm_info)?; - - realm_data.assert_create_authority_can_create_governance( - program_id, - realm_info.key, - token_owner_record_info, - create_authority_info, - account_info_iter, // realm_config_info 9, voter_weight_record_info 10 - )?; - - let token_governance_data = GovernanceV2 { - account_type: GovernanceAccountType::TokenGovernanceV2, - realm: *realm_info.key, - governed_account: *governed_token_info.key, - config, - proposals_count: 0, - reserved: [0; 6], - voting_proposal_count: 0, - reserved_v2: [0; 128], - }; - - create_and_serialize_account_signed::( - payer_info, - token_governance_info, - &token_governance_data, - &get_token_governance_address_seeds(realm_info.key, governed_token_info.key), - program_id, - system_info, - &rent, - )?; - - if transfer_account_authorities { - set_spl_token_account_authority( - governed_token_info, - governed_token_owner_info, - token_governance_info.key, - AuthorityType::AccountOwner, - spl_token_info, - )?; - - // If the token account has close_authority then transfer it as well - let token_account_data = Account::unpack(&governed_token_info.data.borrow())?; - // Note: The code assumes owner==close_authority - // If this is not the case then the caller should set close_authority accordingly before making the transfer - if token_account_data.close_authority.is_some() { - set_spl_token_account_authority( - governed_token_info, - governed_token_owner_info, - token_governance_info.key, - AuthorityType::CloseAccount, - spl_token_info, - )?; - } - } else { - assert_spl_token_owner_is_signer(governed_token_info, governed_token_owner_info)?; - } - - Ok(()) -} diff --git a/governance/program/src/processor/process_create_token_owner_record.rs b/governance/program/src/processor/process_create_token_owner_record.rs index 4b7b7531920..3044f2374cd 100644 --- a/governance/program/src/processor/process_create_token_owner_record.rs +++ b/governance/program/src/processor/process_create_token_owner_record.rs @@ -1,21 +1,25 @@ //! Program state processor -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - pubkey::Pubkey, - rent::Rent, - sysvar::Sysvar, -}; -use spl_governance_tools::account::create_and_serialize_account_signed; - -use crate::{ - error::GovernanceError, - state::{ - enums::GovernanceAccountType, - realm::get_realm_data, - token_owner_record::{get_token_owner_record_address_seeds, TokenOwnerRecordV2}, +use { + crate::{ + error::GovernanceError, + state::{ + enums::GovernanceAccountType, + realm::get_realm_data, + token_owner_record::{ + get_token_owner_record_address_seeds, TokenOwnerRecordV2, + TOKEN_OWNER_RECORD_LAYOUT_VERSION, + }, + }, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + pubkey::Pubkey, + rent::Rent, + sysvar::Sysvar, }, + spl_governance_tools::account::create_and_serialize_account_signed, }; /// Processes CreateTokenOwnerRecord instruction @@ -48,10 +52,11 @@ pub fn process_create_token_owner_record( governing_token_mint: *governing_token_mint_info.key, governance_delegate: None, unrelinquished_votes_count: 0, - total_votes_count: 0, outstanding_proposal_count: 0, - reserved: [0; 7], - reserved_v2: [0; 128], + version: TOKEN_OWNER_RECORD_LAYOUT_VERSION, + reserved: [0; 6], + reserved_v2: [0; 124], + locks: vec![], }; create_and_serialize_account_signed( @@ -66,5 +71,6 @@ pub fn process_create_token_owner_record( program_id, system_info, &rent, + 0, ) } diff --git a/governance/program/src/processor/process_deposit_governing_tokens.rs b/governance/program/src/processor/process_deposit_governing_tokens.rs index 4d428f07ec3..a7254edde06 100644 --- a/governance/program/src/processor/process_deposit_governing_tokens.rs +++ b/governance/program/src/processor/process_deposit_governing_tokens.rs @@ -1,25 +1,30 @@ //! Program state processor -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - pubkey::Pubkey, - rent::Rent, - sysvar::Sysvar, -}; -use spl_governance_tools::account::create_and_serialize_account_signed; - -use crate::{ - error::GovernanceError, - state::{ - enums::GovernanceAccountType, - realm::get_realm_data, - token_owner_record::{ - get_token_owner_record_address_seeds, get_token_owner_record_data_for_seeds, - TokenOwnerRecordV2, +use { + crate::{ + error::GovernanceError, + state::{ + enums::GovernanceAccountType, + realm::get_realm_data, + realm_config::get_realm_config_data_for_realm, + token_owner_record::{ + get_token_owner_record_address_seeds, get_token_owner_record_data_for_seeds, + TokenOwnerRecordV2, TOKEN_OWNER_RECORD_LAYOUT_VERSION, + }, + }, + tools::spl_token::{ + get_spl_token_mint, is_spl_token_account, is_spl_token_mint, mint_spl_tokens_to, + transfer_spl_tokens, }, }, - tools::spl_token::{get_spl_token_mint, get_spl_token_owner, transfer_spl_tokens}, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + pubkey::Pubkey, + rent::Rent, + sysvar::Sysvar, + }, + spl_governance_tools::account::create_and_serialize_account_signed, }; /// Processes DepositGoverningTokens instruction @@ -34,11 +39,12 @@ pub fn process_deposit_governing_tokens( let governing_token_holding_info = next_account_info(account_info_iter)?; // 1 let governing_token_source_info = next_account_info(account_info_iter)?; // 2 let governing_token_owner_info = next_account_info(account_info_iter)?; // 3 - let governing_token_transfer_authority_info = next_account_info(account_info_iter)?; // 4 + let governing_token_source_authority_info = next_account_info(account_info_iter)?; // 4 let token_owner_record_info = next_account_info(account_info_iter)?; // 5 let payer_info = next_account_info(account_info_iter)?; // 6 let system_info = next_account_info(account_info_iter)?; // 7 let spl_token_info = next_account_info(account_info_iter)?; // 8 + let realm_config_info = next_account_info(account_info_iter)?; // 9 let rent = Rent::get()?; @@ -52,13 +58,32 @@ pub fn process_deposit_governing_tokens( governing_token_holding_info.key, )?; - transfer_spl_tokens( - governing_token_source_info, - governing_token_holding_info, - governing_token_transfer_authority_info, - amount, - spl_token_info, - )?; + let realm_config_data = + get_realm_config_data_for_realm(program_id, realm_config_info, realm_info.key)?; + + realm_config_data.assert_can_deposit_governing_token(&realm_data, &governing_token_mint)?; + + if is_spl_token_account(governing_token_source_info) { + // If the source is spl-token token account then transfer tokens from it + transfer_spl_tokens( + governing_token_source_info, + governing_token_holding_info, + governing_token_source_authority_info, + amount, + spl_token_info, + )?; + } else if is_spl_token_mint(governing_token_source_info) { + // If it's a mint then mint the tokens + mint_spl_tokens_to( + governing_token_source_info, + governing_token_holding_info, + governing_token_source_authority_info, + amount, + spl_token_info, + )?; + } else { + return Err(GovernanceError::InvalidGoverningTokenSource.into()); + } let token_owner_record_address_seeds = get_token_owner_record_address_seeds( realm_info.key, @@ -67,12 +92,9 @@ pub fn process_deposit_governing_tokens( ); if token_owner_record_info.data_is_empty() { - // Deposited tokens can only be withdrawn by the owner so let's make sure the owner signed the transaction - let governing_token_owner = get_spl_token_owner(governing_token_source_info)?; - - if !(governing_token_owner == *governing_token_owner_info.key - && governing_token_owner_info.is_signer) - { + // Deposited tokens can only be withdrawn by the owner so let's make sure the + // owner signed the transaction + if !governing_token_owner_info.is_signer { return Err(GovernanceError::GoverningTokenOwnerMustSign.into()); } @@ -84,10 +106,11 @@ pub fn process_deposit_governing_tokens( governing_token_mint, governance_delegate: None, unrelinquished_votes_count: 0, - total_votes_count: 0, outstanding_proposal_count: 0, - reserved: [0; 7], - reserved_v2: [0; 128], + version: TOKEN_OWNER_RECORD_LAYOUT_VERSION, + reserved: [0; 6], + reserved_v2: [0; 124], + locks: vec![], }; create_and_serialize_account_signed( @@ -98,6 +121,7 @@ pub fn process_deposit_governing_tokens( program_id, system_info, &rent, + 0, )?; } else { let mut token_owner_record_data = get_token_owner_record_data_for_seeds( @@ -111,7 +135,7 @@ pub fn process_deposit_governing_tokens( .checked_add(amount) .unwrap(); - token_owner_record_data.serialize(&mut *token_owner_record_info.data.borrow_mut())?; + token_owner_record_data.serialize(&mut token_owner_record_info.data.borrow_mut()[..])?; } Ok(()) diff --git a/governance/program/src/processor/process_execute_transaction.rs b/governance/program/src/processor/process_execute_transaction.rs index 7d5228d71f0..a4b8c4333c9 100644 --- a/governance/program/src/processor/process_execute_transaction.rs +++ b/governance/program/src/processor/process_execute_transaction.rs @@ -1,21 +1,22 @@ //! Program state processor -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - clock::Clock, - entrypoint::ProgramResult, - instruction::Instruction, - program::invoke_signed, - pubkey::Pubkey, - sysvar::Sysvar, -}; - -use crate::state::{ - enums::{ProposalState, TransactionExecutionStatus}, - governance::get_governance_data, - native_treasury::get_native_treasury_address_seeds, - proposal::{get_proposal_data_for_governance, OptionVoteResult}, - proposal_transaction::get_proposal_transaction_data_for_proposal, +use { + crate::state::{ + enums::{ProposalState, TransactionExecutionStatus}, + governance::get_governance_data, + native_treasury::get_native_treasury_address_seeds, + proposal::{get_proposal_data_for_governance, OptionVoteResult}, + proposal_transaction::get_proposal_transaction_data_for_proposal, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + clock::Clock, + entrypoint::ProgramResult, + instruction::Instruction, + program::invoke_signed, + pubkey::Pubkey, + sysvar::Sysvar, + }, }; /// Processes ExecuteTransaction instruction @@ -39,8 +40,11 @@ pub fn process_execute_transaction(program_id: &Pubkey, accounts: &[AccountInfo] proposal_info.key, )?; - proposal_data - .assert_can_execute_transaction(&proposal_transaction_data, clock.unix_timestamp)?; + proposal_data.assert_can_execute_transaction( + &proposal_transaction_data, + &governance_data.config, + clock.unix_timestamp, + )?; // Execute instruction with Governance PDA as signer let instructions = proposal_transaction_data @@ -48,10 +52,12 @@ pub fn process_execute_transaction(program_id: &Pubkey, accounts: &[AccountInfo] .iter() .map(Instruction::from); - // In the current implementation accounts for all instructions are passed to each instruction invocation - // This is an overhead but shouldn't be a showstopper because if we can invoke the parent instruction with that many accounts - // then we should also be able to invoke all the nested ones - // TODO: Optimize the invocation to split the provided accounts for each individual instruction + // In the current implementation accounts for all instructions are passed to + // each instruction invocation. This is an overhead but shouldn't be a + // showstopper because if we can invoke the parent instruction with that many + // accounts then we should also be able to invoke all the nested ones + // TODO: Optimize the invocation to split the provided accounts for each + // individual instruction let instruction_account_infos = account_info_iter.as_slice(); let mut signers_seeds: Vec<&[&[u8]]> = vec![]; @@ -64,7 +70,8 @@ pub fn process_execute_transaction(program_id: &Pubkey, accounts: &[AccountInfo] signers_seeds.push(&governance_seeds[..]); - // Sign the transaction using the governance treasury PDA if required by the instruction + // Sign the transaction using the governance treasury PDA if required by the + // instruction let mut treasury_seeds = get_native_treasury_address_seeds(governance_info.key).to_vec(); let (treasury_address, treasury_bump_seed) = Pubkey::find_program_address(&treasury_seeds, program_id); @@ -88,11 +95,13 @@ pub fn process_execute_transaction(program_id: &Pubkey, accounts: &[AccountInfo] proposal_data.state = ProposalState::Executing; } - let mut option = &mut proposal_data.options[proposal_transaction_data.option_index as usize]; + let option = &mut proposal_data.options[proposal_transaction_data.option_index as usize]; option.transactions_executed_count = option.transactions_executed_count.checked_add(1).unwrap(); - // Checking for Executing and ExecutingWithErrors states because instruction can still be executed after being flagged with error - // The check for instructions_executed_count ensures Proposal can't be transitioned to Completed state from ExecutingWithErrors + // Checking for Executing and ExecutingWithErrors states because instruction can + // still be executed after being flagged with error The check for + // instructions_executed_count ensures Proposal can't be transitioned to + // Completed state from ExecutingWithErrors if (proposal_data.state == ProposalState::Executing || proposal_data.state == ProposalState::ExecutingWithErrors) && proposal_data @@ -105,11 +114,11 @@ pub fn process_execute_transaction(program_id: &Pubkey, accounts: &[AccountInfo] proposal_data.state = ProposalState::Completed; } - proposal_data.serialize(&mut *proposal_info.data.borrow_mut())?; + proposal_data.serialize(&mut proposal_info.data.borrow_mut()[..])?; proposal_transaction_data.executed_at = Some(clock.unix_timestamp); proposal_transaction_data.execution_status = TransactionExecutionStatus::Success; - proposal_transaction_data.serialize(&mut *proposal_transaction_info.data.borrow_mut())?; + proposal_transaction_data.serialize(&mut proposal_transaction_info.data.borrow_mut()[..])?; Ok(()) } diff --git a/governance/program/src/processor/process_finalize_vote.rs b/governance/program/src/processor/process_finalize_vote.rs index 0075654c98c..23f59df939b 100644 --- a/governance/program/src/processor/process_finalize_vote.rs +++ b/governance/program/src/processor/process_finalize_vote.rs @@ -1,18 +1,20 @@ //! Program state processor -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - clock::Clock, - entrypoint::ProgramResult, - pubkey::Pubkey, - sysvar::Sysvar, -}; - -use crate::state::{ - governance::get_governance_data_for_realm, - proposal::get_proposal_data_for_governance_and_governing_mint, - realm::get_realm_data_for_governing_token_mint, - token_owner_record::get_token_owner_record_data_for_proposal_owner, vote_record::VoteKind, +use { + crate::state::{ + governance::get_governance_data_for_realm, + proposal::get_proposal_data_for_governance_and_governing_mint, + realm::get_realm_data_for_governing_token_mint, + realm_config::get_realm_config_data_for_realm, + token_owner_record::get_token_owner_record_data_for_proposal_owner, vote_record::VoteKind, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + clock::Clock, + entrypoint::ProgramResult, + pubkey::Pubkey, + sysvar::Sysvar, + }, }; /// Processes FinalizeVote instruction @@ -28,7 +30,7 @@ pub fn process_finalize_vote(program_id: &Pubkey, accounts: &[AccountInfo]) -> P let clock = Clock::get()?; - let mut realm_data = get_realm_data_for_governing_token_mint( + let realm_data = get_realm_data_for_governing_token_mint( program_id, realm_info, governing_token_mint_info.key, @@ -43,15 +45,16 @@ pub fn process_finalize_vote(program_id: &Pubkey, accounts: &[AccountInfo]) -> P governing_token_mint_info.key, )?; - let realm_config_info = next_account_info(account_info_iter)?; // 5 + let realm_config_info = next_account_info(account_info_iter)?; //5 + let realm_config_data = + get_realm_config_data_for_realm(program_id, realm_config_info, realm_info.key)?; let max_voter_weight = proposal_data.resolve_max_voter_weight( - program_id, - realm_config_info, - governing_token_mint_info, account_info_iter, // *6 realm_info.key, &realm_data, + &realm_config_data, + governing_token_mint_info, &VoteKind::Electorate, )?; @@ -75,17 +78,13 @@ pub fn process_finalize_vote(program_id: &Pubkey, accounts: &[AccountInfo]) -> P )?; proposal_owner_record_data.decrease_outstanding_proposal_count(); - proposal_owner_record_data.serialize(&mut *proposal_owner_record_info.data.borrow_mut())?; - - proposal_data.serialize(&mut *proposal_info.data.borrow_mut())?; + proposal_owner_record_data.serialize(&mut proposal_owner_record_info.data.borrow_mut()[..])?; - // Update Realm voting_proposal_count - realm_data.voting_proposal_count = realm_data.voting_proposal_count.saturating_sub(1); - realm_data.serialize(&mut *realm_info.data.borrow_mut())?; + proposal_data.serialize(&mut proposal_info.data.borrow_mut()[..])?; - // Update Governance voting_proposal_count - governance_data.voting_proposal_count = governance_data.voting_proposal_count.saturating_sub(1); - governance_data.serialize(&mut *governance_info.data.borrow_mut())?; + // Update Governance active_proposal_count + governance_data.active_proposal_count = governance_data.active_proposal_count.saturating_sub(1); + governance_data.serialize(&mut governance_info.data.borrow_mut()[..])?; Ok(()) } diff --git a/governance/program/src/processor/process_flag_transaction_error.rs b/governance/program/src/processor/process_flag_transaction_error.rs deleted file mode 100644 index 37719985304..00000000000 --- a/governance/program/src/processor/process_flag_transaction_error.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! Program state processor - -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - clock::Clock, - entrypoint::ProgramResult, - pubkey::Pubkey, - sysvar::Sysvar, -}; - -use crate::state::{ - enums::{ProposalState, TransactionExecutionStatus}, - proposal::get_proposal_data, - proposal_transaction::get_proposal_transaction_data_for_proposal, - token_owner_record::get_token_owner_record_data_for_proposal_owner, -}; - -/// Processes FlagTransactionError instruction -pub fn process_flag_transaction_error( - program_id: &Pubkey, - accounts: &[AccountInfo], -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - - let proposal_info = next_account_info(account_info_iter)?; // 0 - let token_owner_record_info = next_account_info(account_info_iter)?; // 1 - let governance_authority_info = next_account_info(account_info_iter)?; // 2 - - let proposal_transaction_info = next_account_info(account_info_iter)?; // 3 - - let clock = Clock::get()?; - - let mut proposal_data = get_proposal_data(program_id, proposal_info)?; - - let mut proposal_transaction_data = get_proposal_transaction_data_for_proposal( - program_id, - proposal_transaction_info, - proposal_info.key, - )?; - - proposal_data - .assert_can_flag_transaction_error(&proposal_transaction_data, clock.unix_timestamp)?; - - let token_owner_record_data = get_token_owner_record_data_for_proposal_owner( - program_id, - token_owner_record_info, - &proposal_data.token_owner_record, - )?; - - token_owner_record_data.assert_token_owner_or_delegate_is_signer(governance_authority_info)?; - - // If this is the first instruction to be executed then set executing_at timestamp - // It indicates when we started executing instructions for the Proposal and the fact we only flag it as error is irrelevant here - if proposal_data.state == ProposalState::Succeeded { - proposal_data.executing_at = Some(clock.unix_timestamp); - } - - proposal_data.state = ProposalState::ExecutingWithErrors; - proposal_data.serialize(&mut *proposal_info.data.borrow_mut())?; - - proposal_transaction_data.execution_status = TransactionExecutionStatus::Error; - proposal_transaction_data.serialize(&mut *proposal_transaction_info.data.borrow_mut())?; - - Ok(()) -} diff --git a/governance/program/src/processor/process_insert_transaction.rs b/governance/program/src/processor/process_insert_transaction.rs index 972dace0eaa..c0e716cb3c4 100644 --- a/governance/program/src/processor/process_insert_transaction.rs +++ b/governance/program/src/processor/process_insert_transaction.rs @@ -1,27 +1,27 @@ //! Program state processor -use std::cmp::Ordering; - -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - pubkey::Pubkey, - rent::Rent, - sysvar::Sysvar, -}; -use spl_governance_tools::account::create_and_serialize_account_signed; - -use crate::{ - error::GovernanceError, - state::{ - enums::{GovernanceAccountType, TransactionExecutionStatus}, - governance::get_governance_data, - proposal::get_proposal_data_for_governance, - proposal_transaction::{ - get_proposal_transaction_address_seeds, InstructionData, ProposalTransactionV2, +use { + crate::{ + error::GovernanceError, + state::{ + enums::{GovernanceAccountType, TransactionExecutionStatus}, + governance::get_governance_data, + proposal::get_proposal_data_for_governance, + proposal_transaction::{ + get_proposal_transaction_address_seeds, InstructionData, ProposalTransactionV2, + }, + token_owner_record::get_token_owner_record_data_for_proposal_owner, }, - token_owner_record::get_token_owner_record_data_for_proposal_owner, }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + pubkey::Pubkey, + rent::Rent, + sysvar::Sysvar, + }, + spl_governance_tools::account::create_and_serialize_account_signed, + std::cmp::Ordering, }; /// Processes InsertTransaction instruction @@ -30,7 +30,6 @@ pub fn process_insert_transaction( accounts: &[AccountInfo], option_index: u8, instruction_index: u16, - hold_up_time: u32, instructions: Vec, ) -> ProgramResult { let account_info_iter = &mut accounts.iter(); @@ -52,11 +51,9 @@ pub fn process_insert_transaction( return Err(GovernanceError::TransactionAlreadyExists.into()); } - let governance_data = get_governance_data(program_id, governance_info)?; - - if hold_up_time < governance_data.config.min_transaction_hold_up_time { - return Err(GovernanceError::TransactionHoldUpTimeBelowRequiredMin.into()); - } + // Governance account is no longer used and it's deserialized only to validate + // the provided account + let _governance_data = get_governance_data(program_id, governance_info)?; let mut proposal_data = get_proposal_data_for_governance(program_id, proposal_info, governance_info.key)?; @@ -75,7 +72,8 @@ pub fn process_insert_transaction( match instruction_index.cmp(&option.transactions_next_index) { Ordering::Greater => return Err(GovernanceError::InvalidTransactionIndex.into()), // If the index is the same as instructions_next_index then we are adding a new instruction - // If the index is below instructions_next_index then we are inserting into an existing empty space + // If the index is below instructions_next_index then we are inserting into an existing + // empty space Ordering::Equal => { option.transactions_next_index = option.transactions_next_index.checked_add(1).unwrap(); } @@ -83,13 +81,13 @@ pub fn process_insert_transaction( } option.transactions_count = option.transactions_count.checked_add(1).unwrap(); - proposal_data.serialize(&mut *proposal_info.data.borrow_mut())?; + proposal_data.serialize(&mut proposal_info.data.borrow_mut()[..])?; let proposal_transaction_data = ProposalTransactionV2 { account_type: GovernanceAccountType::ProposalTransactionV2, option_index, transaction_index: instruction_index, - hold_up_time, + legacy: 0, instructions, executed_at: None, execution_status: TransactionExecutionStatus::None, @@ -109,6 +107,7 @@ pub fn process_insert_transaction( program_id, system_info, rent, + 0, )?; Ok(()) diff --git a/governance/program/src/processor/process_refund_proposal_deposit.rs b/governance/program/src/processor/process_refund_proposal_deposit.rs new file mode 100644 index 00000000000..552554f2d46 --- /dev/null +++ b/governance/program/src/processor/process_refund_proposal_deposit.rs @@ -0,0 +1,44 @@ +//! Program state processor + +use { + crate::state::{ + proposal::get_proposal_data, + proposal_deposit::get_proposal_deposit_data_for_proposal_and_deposit_payer, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + pubkey::Pubkey, + }, + spl_governance_tools::account::dispose_account, +}; + +/// Processes RefundProposalDeposit instruction +pub fn process_refund_proposal_deposit( + program_id: &Pubkey, + accounts: &[AccountInfo], +) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + + let proposal_info = next_account_info(account_info_iter)?; // 0 + + let proposal_deposit_info = next_account_info(account_info_iter)?; // 1 + let proposal_deposit_payer_info = next_account_info(account_info_iter)?; // 2 + + let proposal_data = get_proposal_data(program_id, proposal_info)?; + + proposal_data.assert_can_refund_proposal_deposit()?; + + // Assert we are disposing a deposit which belongs to the Proposal and the + // deposit payer + let _proposal_deposit_data = get_proposal_deposit_data_for_proposal_and_deposit_payer( + program_id, + proposal_deposit_info, + proposal_info.key, + proposal_deposit_payer_info.key, + )?; + + dispose_account(proposal_deposit_info, proposal_deposit_payer_info)?; + + Ok(()) +} diff --git a/governance/program/src/processor/process_relinquish_token_owner_record_locks.rs b/governance/program/src/processor/process_relinquish_token_owner_record_locks.rs new file mode 100644 index 00000000000..c3490646232 --- /dev/null +++ b/governance/program/src/processor/process_relinquish_token_owner_record_locks.rs @@ -0,0 +1,70 @@ +//! Program state processor + +use { + crate::{ + error::GovernanceError, + state::{ + realm::get_realm_data, realm_config::get_realm_config_data_for_realm, + token_owner_record::get_token_owner_record_data_for_realm, + }, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + clock::Clock, + entrypoint::ProgramResult, + pubkey::Pubkey, + sysvar::Sysvar, + }, +}; + +/// Processes RelinquishTokenOwnerRecordLocks instruction +pub fn process_relinquish_token_owner_record_locks( + program_id: &Pubkey, + accounts: &[AccountInfo], + lock_ids: Option>, +) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + + let realm_info = next_account_info(account_info_iter)?; // 0 + let realm_config_info = next_account_info(account_info_iter)?; // 1 + let token_owner_record_info = next_account_info(account_info_iter)?; // 2 + + let realm_data = get_realm_data(program_id, realm_info)?; + let realm_config_data = + get_realm_config_data_for_realm(program_id, realm_config_info, realm_info.key)?; + + let mut token_owner_record_data = get_token_owner_record_data_for_realm( + program_id, + token_owner_record_info, + &realm_config_data.realm, + )?; + + if let Some(lock_ids) = lock_ids { + let token_owner_record_lock_authority_info = next_account_info(account_info_iter)?; // 3 + + if realm_config_data + .get_token_config(&realm_data, &token_owner_record_data.governing_token_mint)? + .lock_authorities + .contains(token_owner_record_lock_authority_info.key) + { + // If the authority is a configured lock authority it must sign the transaction + if !token_owner_record_lock_authority_info.is_signer { + return Err(GovernanceError::TokenOwnerRecordLockAuthorityMustSign.into()); + } + } + + // Remove the locks + for lock_id in lock_ids { + token_owner_record_data + .remove_lock(lock_id, token_owner_record_lock_authority_info.key)?; + } + } + + // Trim expired locks + let clock = Clock::get()?; + token_owner_record_data.remove_expired_locks(clock.unix_timestamp); + + token_owner_record_data.serialize(&mut token_owner_record_info.data.borrow_mut()[..])?; + + Ok(()) +} diff --git a/governance/program/src/processor/process_relinquish_vote.rs b/governance/program/src/processor/process_relinquish_vote.rs index a02641ce6ba..4224832c5dd 100644 --- a/governance/program/src/processor/process_relinquish_vote.rs +++ b/governance/program/src/processor/process_relinquish_vote.rs @@ -1,24 +1,25 @@ //! Program state processor -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - clock::Clock, - entrypoint::ProgramResult, - pubkey::Pubkey, - sysvar::Sysvar, -}; -use spl_governance_tools::account::dispose_account; - -use crate::{ - error::GovernanceError, - state::{ - enums::ProposalState, - governance::get_governance_data_for_realm, - proposal::get_proposal_data_for_governance, - realm::get_realm_data_for_governing_token_mint, - token_owner_record::get_token_owner_record_data_for_realm_and_governing_mint, - vote_record::{get_vote_record_data_for_proposal_and_token_owner_record, Vote}, +use { + crate::{ + error::GovernanceError, + state::{ + enums::ProposalState, + governance::get_governance_data_for_realm, + proposal::get_proposal_data_for_governance, + realm::get_realm_data_for_governing_token_mint, + token_owner_record::get_token_owner_record_data_for_realm_and_governing_mint, + vote_record::{get_vote_record_data_for_proposal_and_token_owner_record, Vote}, + }, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + clock::Clock, + entrypoint::ProgramResult, + pubkey::Pubkey, + sysvar::Sysvar, }, + spl_governance_tools::account::dispose_account, }; /// Processes RelinquishVote instruction @@ -64,17 +65,21 @@ pub fn process_relinquish_vote(program_id: &Pubkey, accounts: &[AccountInfo]) -> let clock = Clock::get()?; - // If the Proposal is still being voted on then the token owner vote will be withdrawn and it won't count towards the vote outcome - // Note: If there is no tipping point the proposal can be still in Voting state but already past the configured max_voting_time - // It means it awaits manual finalization (FinalizeVote) and it should no longer be possible to withdraw the vote + // If the Proposal is still being voted on then the token owner vote will be + // withdrawn and it won't count towards the vote outcome Note: If there is + // no tipping point the proposal can be still in Voting state but already past + // the configured max voting time (base + cool off voting time) + // It means it awaits manual finalization (FinalizeVote) and it should no + // longer be possible to withdraw the vote if proposal_data.state == ProposalState::Voting - && !proposal_data.has_vote_time_ended(&governance_data.config, clock.unix_timestamp) + && !proposal_data.has_voting_max_time_ended(&governance_data.config, clock.unix_timestamp) { let governance_authority_info = next_account_info(account_info_iter)?; // 5 let beneficiary_info = next_account_info(account_info_iter)?; // 6 - // Note: It's only required to sign by governing_authority if relinquishing the vote results in vote change - // If the Proposal is already decided then anybody can prune active votes for token owner + // Note: It's only required to sign by governing_authority if relinquishing the + // vote results in vote change If the Proposal is already decided then + // anybody can prune active votes for token owner token_owner_record_data .assert_token_owner_or_delegate_is_signer(governance_authority_info)?; @@ -107,33 +112,30 @@ pub fn process_relinquish_vote(program_id: &Pubkey, accounts: &[AccountInfo]) -> } } - proposal_data.serialize(&mut *proposal_info.data.borrow_mut())?; - - dispose_account(vote_record_info, beneficiary_info); + proposal_data.serialize(&mut proposal_info.data.borrow_mut()[..])?; - token_owner_record_data.total_votes_count = token_owner_record_data - .total_votes_count - .checked_sub(1) - .unwrap(); + dispose_account(vote_record_info, beneficiary_info)?; } else { - // After Proposal voting time ends and it's not tipped then it enters implicit (time based) Finalizing state - // and releasing tokens in this state should be disallowed - // In other words releasing tokens is only possible once Proposal is manually finalized using FinalizeVote + // After Proposal voting time ends and it's not tipped then it enters implicit + // (time based) Finalizing state and releasing tokens in this state + // should be disallowed In other words releasing tokens is only possible + // once Proposal is manually finalized using FinalizeVote if proposal_data.state == ProposalState::Voting { return Err(GovernanceError::CannotRelinquishInFinalizingState.into()); } vote_record_data.is_relinquished = true; - vote_record_data.serialize(&mut *vote_record_info.data.borrow_mut())?; + vote_record_data.serialize(&mut vote_record_info.data.borrow_mut()[..])?; } - // If the Proposal has been already voted on then we only have to decrease unrelinquished_votes_count + // If the Proposal has been already voted on then we only have to decrease + // unrelinquished_votes_count token_owner_record_data.unrelinquished_votes_count = token_owner_record_data .unrelinquished_votes_count .checked_sub(1) .unwrap(); - token_owner_record_data.serialize(&mut *token_owner_record_info.data.borrow_mut())?; + token_owner_record_data.serialize(&mut token_owner_record_info.data.borrow_mut()[..])?; Ok(()) } diff --git a/governance/program/src/processor/process_remove_required_signatory.rs b/governance/program/src/processor/process_remove_required_signatory.rs new file mode 100644 index 00000000000..c4ec93b8f19 --- /dev/null +++ b/governance/program/src/processor/process_remove_required_signatory.rs @@ -0,0 +1,48 @@ +use { + crate::{ + error::GovernanceError, + state::{ + governance::get_governance_data, + required_signatory::get_required_signatory_data_for_governance, + }, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + pubkey::Pubkey, + }, + spl_governance_tools::account::dispose_account, +}; + +pub fn process_remove_required_signatory( + program_id: &Pubkey, + accounts: &[AccountInfo], +) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + + let governance_info = next_account_info(account_info_iter)?; // 0 + let required_signatory_info = next_account_info(account_info_iter)?; // 1 + let beneficiary_info = next_account_info(account_info_iter)?; // 2 + + if !governance_info.is_signer { + return Err(GovernanceError::GovernancePdaMustSign.into()); + }; + + let mut governance_data = get_governance_data(program_id, governance_info)?; + + get_required_signatory_data_for_governance( + program_id, + required_signatory_info, + governance_info.key, + )?; + + governance_data.required_signatories_count = governance_data + .required_signatories_count + .checked_sub(1) + .unwrap(); + governance_data.serialize(&mut governance_info.data.borrow_mut()[..])?; + + dispose_account(required_signatory_info, beneficiary_info)?; + + Ok(()) +} diff --git a/governance/program/src/processor/process_remove_signatory.rs b/governance/program/src/processor/process_remove_signatory.rs deleted file mode 100644 index 07ffe9d3aa2..00000000000 --- a/governance/program/src/processor/process_remove_signatory.rs +++ /dev/null @@ -1,56 +0,0 @@ -//! Program state processor - -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - pubkey::Pubkey, -}; -use spl_governance_tools::account::dispose_account; - -use crate::state::{ - proposal::get_proposal_data, signatory_record::get_signatory_record_data_for_seeds, - token_owner_record::get_token_owner_record_data_for_proposal_owner, -}; - -/// Processes RemoveSignatory instruction -pub fn process_remove_signatory( - program_id: &Pubkey, - accounts: &[AccountInfo], - signatory: Pubkey, -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - - let proposal_info = next_account_info(account_info_iter)?; // 0 - let token_owner_record_info = next_account_info(account_info_iter)?; // 1 - let governance_authority_info = next_account_info(account_info_iter)?; // 2 - - let signatory_record_info = next_account_info(account_info_iter)?; // 3 - let beneficiary_info = next_account_info(account_info_iter)?; // 4 - - let mut proposal_data = get_proposal_data(program_id, proposal_info)?; - proposal_data.assert_can_edit_signatories()?; - - let token_owner_record_data = get_token_owner_record_data_for_proposal_owner( - program_id, - token_owner_record_info, - &proposal_data.token_owner_record, - )?; - - token_owner_record_data.assert_token_owner_or_delegate_is_signer(governance_authority_info)?; - - let signatory_record_data = get_signatory_record_data_for_seeds( - program_id, - signatory_record_info, - proposal_info.key, - &signatory, - )?; - signatory_record_data.assert_can_remove_signatory()?; - - proposal_data.signatories_count = proposal_data.signatories_count.checked_sub(1).unwrap(); - - proposal_data.serialize(&mut *proposal_info.data.borrow_mut())?; - - dispose_account(signatory_record_info, beneficiary_info); - - Ok(()) -} diff --git a/governance/program/src/processor/process_remove_transaction.rs b/governance/program/src/processor/process_remove_transaction.rs index e833fd01948..1717ade2629 100644 --- a/governance/program/src/processor/process_remove_transaction.rs +++ b/governance/program/src/processor/process_remove_transaction.rs @@ -1,15 +1,17 @@ //! Program state processor -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - pubkey::Pubkey, -}; -use spl_governance_tools::account::dispose_account; - -use crate::state::{ - proposal::get_proposal_data, proposal_transaction::get_proposal_transaction_data_for_proposal, - token_owner_record::get_token_owner_record_data_for_proposal_owner, +use { + crate::state::{ + proposal::get_proposal_data, + proposal_transaction::get_proposal_transaction_data_for_proposal, + token_owner_record::get_token_owner_record_data_for_proposal_owner, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + pubkey::Pubkey, + }, + spl_governance_tools::account::dispose_account, }; /// Processes RemoveTransaction instruction @@ -40,12 +42,12 @@ pub fn process_remove_transaction(program_id: &Pubkey, accounts: &[AccountInfo]) proposal_info.key, )?; - dispose_account(proposal_transaction_info, beneficiary_info); + dispose_account(proposal_transaction_info, beneficiary_info)?; - let mut option = &mut proposal_data.options[proposal_transaction_data.option_index as usize]; + let option = &mut proposal_data.options[proposal_transaction_data.option_index as usize]; option.transactions_count = option.transactions_count.checked_sub(1).unwrap(); - proposal_data.serialize(&mut *proposal_info.data.borrow_mut())?; + proposal_data.serialize(&mut proposal_info.data.borrow_mut()[..])?; Ok(()) } diff --git a/governance/program/src/processor/process_revoke_governing_tokens.rs b/governance/program/src/processor/process_revoke_governing_tokens.rs new file mode 100644 index 00000000000..b5040f31634 --- /dev/null +++ b/governance/program/src/processor/process_revoke_governing_tokens.rs @@ -0,0 +1,94 @@ +//! Program state processor + +use { + crate::{ + error::GovernanceError, + state::{ + realm::{get_realm_address_seeds, get_realm_data}, + realm_config::get_realm_config_data_for_realm, + token_owner_record::get_token_owner_record_data_for_realm_and_governing_mint, + }, + tools::spl_token::{assert_spl_token_mint_authority_is_signer, burn_spl_tokens_signed}, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + pubkey::Pubkey, + }, +}; + +/// Processes RevokeGoverningTokens instruction +pub fn process_revoke_governing_tokens( + program_id: &Pubkey, + accounts: &[AccountInfo], + amount: u64, +) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + + let realm_info = next_account_info(account_info_iter)?; // 0 + + let governing_token_holding_info = next_account_info(account_info_iter)?; // 1 + let token_owner_record_info = next_account_info(account_info_iter)?; // 2 + + let governing_token_mint_info = next_account_info(account_info_iter)?; // 3 + let revoke_authority_info = next_account_info(account_info_iter)?; // 4 + + let realm_config_info = next_account_info(account_info_iter)?; // 5 + let spl_token_info = next_account_info(account_info_iter)?; // 6 + + let realm_data = get_realm_data(program_id, realm_info)?; + + realm_data.assert_is_valid_governing_token_mint_and_holding( + program_id, + realm_info.key, + governing_token_mint_info.key, + governing_token_holding_info.key, + )?; + + let realm_config_data = + get_realm_config_data_for_realm(program_id, realm_config_info, realm_info.key)?; + + realm_config_data + .assert_can_revoke_governing_token(&realm_data, governing_token_mint_info.key)?; + + let mut token_owner_record_data = get_token_owner_record_data_for_realm_and_governing_mint( + program_id, + token_owner_record_info, + realm_info.key, + governing_token_mint_info.key, + )?; + + // If the governing token owner voluntarily revokes their own membership then + // the owner must sign the transaction + if *revoke_authority_info.key == token_owner_record_data.governing_token_owner { + if !revoke_authority_info.is_signer { + return Err(GovernanceError::GoverningTokenOwnerMustSign.into()); + } + } else { + // If its a forceful membership revocation then the governing_token_mint + // authority must sign the transaction + assert_spl_token_mint_authority_is_signer( + governing_token_mint_info, + revoke_authority_info, + )?; + } + + token_owner_record_data.governing_token_deposit_amount = token_owner_record_data + .governing_token_deposit_amount + .checked_sub(amount) + .ok_or(GovernanceError::InvalidRevokeAmount)?; + + token_owner_record_data.serialize(&mut token_owner_record_info.data.borrow_mut()[..])?; + + burn_spl_tokens_signed( + governing_token_holding_info, + governing_token_mint_info, + realm_info, + &get_realm_address_seeds(&realm_data.name), + program_id, + amount, + spl_token_info, + )?; + + Ok(()) +} diff --git a/governance/program/src/processor/process_set_governance_config.rs b/governance/program/src/processor/process_set_governance_config.rs index 02cc8458270..ae7d3691532 100644 --- a/governance/program/src/processor/process_set_governance_config.rs +++ b/governance/program/src/processor/process_set_governance_config.rs @@ -1,14 +1,17 @@ //! Program state processor -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - pubkey::Pubkey, -}; - -use crate::{ - error::GovernanceError, - state::governance::{assert_is_valid_governance_config, get_governance_data, GovernanceConfig}, +use { + crate::{ + error::GovernanceError, + state::governance::{ + assert_is_valid_governance_config, get_governance_data, GovernanceConfig, + }, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + pubkey::Pubkey, + }, }; /// Processes SetGovernanceConfig instruction @@ -30,19 +33,14 @@ pub fn process_set_governance_config( let mut governance_data = get_governance_data(program_id, governance_info)?; - // Until we have Veto implemented it's better to allow config change as the defence of last resort against governance attacks - // Note: Config change leaves voting proposals in unpredictable state and it's DAOs responsibility - // to ensure the changes are made when there are no proposals in voting state - // For example changing approval quorum could accidentally make proposals to succeed which would otherwise be defeated - // The check wouldn't have any effect when upgrading from V1 to V2 because it was not tracked in V1 - - // if governance_data.voting_proposal_count > 0 { - // return Err(GovernanceError::GovernanceConfigChangeNotAllowed.into()); - // } + // Note: Config change leaves voting proposals in unpredictable state and it's + // DAOs responsibility to ensure the changes are made when there are no + // proposals in voting state For example changing approval quorum could + // accidentally make proposals to succeed which would otherwise be defeated governance_data.config = config; - governance_data.serialize(&mut *governance_info.data.borrow_mut())?; + governance_data.serialize(&mut governance_info.data.borrow_mut()[..])?; Ok(()) } diff --git a/governance/program/src/processor/process_set_governance_delegate.rs b/governance/program/src/processor/process_set_governance_delegate.rs index 321d9590e09..9d08c35ef99 100644 --- a/governance/program/src/processor/process_set_governance_delegate.rs +++ b/governance/program/src/processor/process_set_governance_delegate.rs @@ -1,13 +1,14 @@ //! Program state processor -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - pubkey::Pubkey, +use { + crate::state::token_owner_record::get_token_owner_record_data, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + pubkey::Pubkey, + }, }; -use crate::state::token_owner_record::get_token_owner_record_data; - /// Processes SetGovernanceDelegate instruction pub fn process_set_governance_delegate( program_id: &Pubkey, @@ -25,7 +26,7 @@ pub fn process_set_governance_delegate( token_owner_record_data.assert_token_owner_or_delegate_is_signer(governance_authority_info)?; token_owner_record_data.governance_delegate = *new_governance_delegate; - token_owner_record_data.serialize(&mut *token_owner_record_info.data.borrow_mut())?; + token_owner_record_data.serialize(&mut token_owner_record_info.data.borrow_mut()[..])?; Ok(()) } diff --git a/governance/program/src/processor/process_set_realm_authority.rs b/governance/program/src/processor/process_set_realm_authority.rs index 1d2e83af676..fc5078041d4 100644 --- a/governance/program/src/processor/process_set_realm_authority.rs +++ b/governance/program/src/processor/process_set_realm_authority.rs @@ -1,16 +1,17 @@ //! Program state processor -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - pubkey::Pubkey, -}; - -use crate::{ - error::GovernanceError, - state::{ - governance::assert_governance_for_realm, - realm::{get_realm_data_for_authority, SetRealmAuthorityAction}, +use { + crate::{ + error::GovernanceError, + state::{ + governance::assert_governance_for_realm, + realm::{get_realm_data_for_authority, SetRealmAuthorityAction}, + }, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + pubkey::Pubkey, }, }; @@ -48,7 +49,7 @@ pub fn process_set_realm_authority( realm_data.authority = new_realm_authority; - realm_data.serialize(&mut *realm_info.data.borrow_mut())?; + realm_data.serialize(&mut realm_info.data.borrow_mut()[..])?; Ok(()) } diff --git a/governance/program/src/processor/process_set_realm_config.rs b/governance/program/src/processor/process_set_realm_config.rs index 3706f8e034d..b088b839e88 100644 --- a/governance/program/src/processor/process_set_realm_config.rs +++ b/governance/program/src/processor/process_set_realm_config.rs @@ -1,24 +1,22 @@ //! Program state processor -use borsh::BorshSerialize; -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - pubkey::Pubkey, - rent::Rent, - sysvar::Sysvar, -}; -use spl_governance_tools::account::create_and_serialize_account_signed; - -use crate::{ - error::GovernanceError, - state::{ - enums::GovernanceAccountType, - realm::{assert_valid_realm_config_args, get_realm_data_for_authority, RealmConfigArgs}, - realm_config::{ - get_realm_config_address_seeds, get_realm_config_data_for_realm, RealmConfigAccount, +use { + crate::{ + error::GovernanceError, + state::{ + realm::{ + assert_valid_realm_config_args, get_realm_data_for_authority, RealmConfigArgs, + }, + realm_config::{get_realm_config_data_for_realm, resolve_governing_token_config}, }, }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + pubkey::Pubkey, + rent::Rent, + sysvar::Sysvar, + }, }; /// Processes SetRealmConfig instruction @@ -39,15 +37,11 @@ pub fn process_set_realm_config( return Err(GovernanceError::RealmAuthorityMustSign.into()); } - // Until we have Veto implemented it's better to allow config change as the defence of last resort against governance attacks - // Note: Config change leaves voting proposals in unpredictable state and it's DAOs responsibility - // to ensure the changes are made when there are no proposals in voting state - // For example changing voter-weight or max-voter-weight addin could accidentally make proposals to succeed which would otherwise be defeated - // The check wouldn't have any effect when upgrading from V1 to V2 because it was not tracked in V1 - - // if realm_data.voting_proposal_count > 0 { - // return Err(GovernanceError::RealmConfigChangeNotAllowed.into()); - // } + // Note: Config change leaves voting proposals in unpredictable state and it's + // DAOs responsibility to ensure the changes are made when there are no + // proposals in voting state For example changing voter-weight or + // max-voter-weight addin could accidentally make proposals to succeed which + // would otherwise be defeated assert_valid_realm_config_args(&realm_config_args)?; @@ -56,9 +50,10 @@ pub fn process_set_realm_config( let council_token_mint_info = next_account_info(account_info_iter)?; // 2 let _council_token_holding_info = next_account_info(account_info_iter)?; // 3 - // Council mint can only be at present set to None (removed) and changing it to other mint is not supported - // It might be implemented in future versions but it needs careful planning - // It can potentially open a can of warms like what happens with existing deposits or pending proposals + // Council mint can only be at present set to None (removed) and changing it to + // other mint is not supported It might be implemented in future + // versions but it needs careful planning It can potentially open a can + // of warms like what happens with existing deposits or pending proposals if let Some(council_token_mint) = realm_data.config.council_mint { // Council mint can't be changed to different one if council_token_mint != *council_token_mint_info.key { @@ -70,94 +65,60 @@ pub fn process_set_realm_config( } } else { // Remove council mint from realm - // Note: In the current implementation this also makes it impossible to withdraw council tokens + // Note: In the current implementation this also makes it impossible to withdraw + // council tokens realm_data.config.council_mint = None; } let system_info = next_account_info(account_info_iter)?; // 4 + let realm_config_info = next_account_info(account_info_iter)?; // 5 + let mut realm_config_data = + get_realm_config_data_for_realm(program_id, realm_config_info, realm_info.key)?; - // Setup config for addins + realm_config_data.assert_can_change_config(&realm_config_args)?; - let community_voter_weight_addin = if realm_config_args.use_community_voter_weight_addin { - let community_voter_weight_addin_info = next_account_info(account_info_iter)?; // 6 - Some(*community_voter_weight_addin_info.key) - } else { - None - }; + // Setup configs for tokens (plugins and token types) - let max_community_voter_weight_addin = if realm_config_args.use_max_community_voter_weight_addin - { - let max_community_voter_weight_addin_info = next_account_info(account_info_iter)?; // 7 - Some(*max_community_voter_weight_addin_info.key) - } else { - None - }; - - // If any of the addins is needed then update or create (if doesn't exist yet) RealmConfigAccount - let update_realm_config = if realm_config_args.use_community_voter_weight_addin - || realm_config_args.use_max_community_voter_weight_addin - { - // We need the payer to pay for the new account if it's created - let payer_info = next_account_info(account_info_iter)?; // 8 - - // If RealmConfigAccount doesn't exist yet then create it - if realm_config_info.data_is_empty() { - let realm_config_data = RealmConfigAccount { - account_type: GovernanceAccountType::RealmConfig, - realm: *realm_info.key, - community_voter_weight_addin, - max_community_voter_weight_addin, - council_voter_weight_addin: None, - council_max_vote_weight_addin: None, - reserved: [0; 128], - }; - - let rent = Rent::get()?; - - create_and_serialize_account_signed::( - payer_info, - realm_config_info, - &realm_config_data, - &get_realm_config_address_seeds(realm_info.key), - program_id, - system_info, - &rent, - )?; - false // RealmConfigAccount didn't exist and was created - } else { - true // RealmConfigAccount existed before and needs to be updated - } - } else { - // True: If RealmConfigAccount existed before we have to update it to remove the addins which are not used any longer - // False: We don't want to setup the addins and RealmConfigAccount didn't exist before - realm_data.config.use_community_voter_weight_addin - || realm_data.config.use_max_community_voter_weight_addin - }; + // 6, 7 + let community_token_config = resolve_governing_token_config( + account_info_iter, + &realm_config_args.community_token_config_args, + Some(realm_config_data.community_token_config.clone()), + )?; - if update_realm_config { - let mut realm_config_data = - get_realm_config_data_for_realm(program_id, realm_config_info, realm_info.key)?; + // 8, 9 + let council_token_config = resolve_governing_token_config( + account_info_iter, + &realm_config_args.council_token_config_args, + Some(realm_config_data.council_token_config.clone()), + )?; - realm_config_data.community_voter_weight_addin = community_voter_weight_addin; - realm_config_data.max_community_voter_weight_addin = max_community_voter_weight_addin; + realm_config_data.community_token_config = community_token_config; + realm_config_data.council_token_config = council_token_config; - realm_config_data.serialize(&mut *realm_config_info.data.borrow_mut())?; - } + let payer_info = next_account_info(account_info_iter)?; // 10 + let rent = Rent::get()?; + + realm_config_data.serialize( + program_id, + realm_config_info, + payer_info, + system_info, + &rent, + )?; - realm_data.config.community_mint_max_vote_weight_source = - realm_config_args.community_mint_max_vote_weight_source; + // Update RealmConfig (Realm.config field) + realm_data.config.community_mint_max_voter_weight_source = + realm_config_args.community_mint_max_voter_weight_source; realm_data.config.min_community_weight_to_create_governance = realm_config_args.min_community_weight_to_create_governance; - realm_data.config.use_community_voter_weight_addin = - realm_config_args.use_community_voter_weight_addin; - - realm_data.config.use_max_community_voter_weight_addin = - realm_config_args.use_max_community_voter_weight_addin; + realm_data.config.legacy1 = 0; + realm_data.config.legacy2 = 0; - realm_data.serialize(&mut *realm_info.data.borrow_mut())?; + realm_data.serialize(&mut realm_info.data.borrow_mut()[..])?; Ok(()) } diff --git a/governance/program/src/processor/process_set_realm_config_item.rs b/governance/program/src/processor/process_set_realm_config_item.rs new file mode 100644 index 00000000000..c2438bf9f71 --- /dev/null +++ b/governance/program/src/processor/process_set_realm_config_item.rs @@ -0,0 +1,90 @@ +//! Program state processor + +use { + crate::{ + error::GovernanceError, + state::{ + realm::{get_realm_data_for_authority, SetRealmConfigItemArgs}, + realm_config::get_realm_config_data_for_realm, + }, + tools::structs::SetConfigItemActionType, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + pubkey::Pubkey, + rent::Rent, + sysvar::Sysvar, + }, +}; + +/// Processes SetRealmConfigItem instruction +pub fn process_set_realm_config_item( + program_id: &Pubkey, + accounts: &[AccountInfo], + args: SetRealmConfigItemArgs, +) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + + let realm_info = next_account_info(account_info_iter)?; // 0 + let realm_config_info = next_account_info(account_info_iter)?; // 1 + let realm_authority_info = next_account_info(account_info_iter)?; // 2 + let payer_info = next_account_info(account_info_iter)?; // 3 + let system_info = next_account_info(account_info_iter)?; // 4 + + let rent = Rent::get()?; + + let realm_data = + get_realm_data_for_authority(program_id, realm_info, realm_authority_info.key)?; + + if !realm_authority_info.is_signer { + return Err(GovernanceError::RealmAuthorityMustSign.into()); + } + + let mut realm_config_data = + get_realm_config_data_for_realm(program_id, realm_config_info, realm_info.key)?; + + match args { + SetRealmConfigItemArgs::TokenOwnerRecordLockAuthority { + action, + governing_token_mint, + authority, + } => { + let token_config = + realm_config_data.get_token_config_mut(&realm_data, &governing_token_mint)?; + + match action { + SetConfigItemActionType::Add => { + if token_config.lock_authorities.contains(&authority) { + return Err( + GovernanceError::TokenOwnerRecordLockAuthorityAlreadyExists.into() + ); + } + + token_config.lock_authorities.push(authority); + } + SetConfigItemActionType::Remove => { + if let Some(lock_authority_index) = token_config + .lock_authorities + .iter() + .position(|lock_authority| lock_authority == &authority) + { + token_config.lock_authorities.remove(lock_authority_index); + } else { + return Err(GovernanceError::TokenOwnerRecordLockAuthorityNotFound.into()); + } + } + } + } + } + + realm_config_data.serialize( + program_id, + realm_config_info, + payer_info, + system_info, + &rent, + )?; + + Ok(()) +} diff --git a/governance/program/src/processor/process_set_token_owner_record_lock.rs b/governance/program/src/processor/process_set_token_owner_record_lock.rs new file mode 100644 index 00000000000..482ba2f155a --- /dev/null +++ b/governance/program/src/processor/process_set_token_owner_record_lock.rs @@ -0,0 +1,88 @@ +//! Program state processor + +use { + crate::{ + error::GovernanceError, + state::{ + realm::get_realm_data, + realm_config::get_realm_config_data_for_realm, + token_owner_record::{get_token_owner_record_data_for_realm, TokenOwnerRecordLock}, + }, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + clock::{Clock, UnixTimestamp}, + entrypoint::ProgramResult, + pubkey::Pubkey, + rent::Rent, + sysvar::Sysvar, + }, +}; + +/// Processes SetTokenOwnerRecordLock instruction +pub fn process_set_token_owner_record_lock( + program_id: &Pubkey, + accounts: &[AccountInfo], + lock_id: u8, + expiry: Option, +) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + + let realm_info = next_account_info(account_info_iter)?; // 0 + let realm_config_info = next_account_info(account_info_iter)?; // 1 + let token_owner_record_info = next_account_info(account_info_iter)?; // 2 + let token_owner_record_lock_authority_info = next_account_info(account_info_iter)?; // 3 + let payer_info = next_account_info(account_info_iter)?; // 4 + let system_info = next_account_info(account_info_iter)?; // 5 + + let rent = Rent::get()?; + let clock = Clock::get()?; + + if !token_owner_record_lock_authority_info.is_signer { + return Err(GovernanceError::TokenOwnerRecordLockAuthorityMustSign.into()); + } + + let token_owner_record_lock = TokenOwnerRecordLock { + lock_id, + authority: *token_owner_record_lock_authority_info.key, + expiry, + }; + + // Reject the lock if already expired + if token_owner_record_lock.is_expired(clock.unix_timestamp) { + return Err(GovernanceError::ExpiredTokenOwnerRecordLock.into()); + } + + let realm_data = get_realm_data(program_id, realm_info)?; + let realm_config_data = + get_realm_config_data_for_realm(program_id, realm_config_info, realm_info.key)?; + + let mut token_owner_record_data = get_token_owner_record_data_for_realm( + program_id, + token_owner_record_info, + &realm_config_data.realm, + )?; + + if !realm_config_data + .get_token_config(&realm_data, &token_owner_record_data.governing_token_mint)? + .lock_authorities + .contains(token_owner_record_lock_authority_info.key) + { + return Err(GovernanceError::InvalidTokenOwnerRecordLockAuthority.into()); + } + + // Trim expired locks + token_owner_record_data.remove_expired_locks(clock.unix_timestamp); + + // Add or update the lock for the given authority and lock id + token_owner_record_data.upsert_lock(token_owner_record_lock); + + token_owner_record_data.serialize_with_resize( + token_owner_record_info, + payer_info, + system_info, + &rent, + )?; + + Ok(()) +} diff --git a/governance/program/src/processor/process_sign_off_proposal.rs b/governance/program/src/processor/process_sign_off_proposal.rs index bf15e2e8243..5c50f1a3e81 100644 --- a/governance/program/src/processor/process_sign_off_proposal.rs +++ b/governance/program/src/processor/process_sign_off_proposal.rs @@ -1,18 +1,22 @@ //! Program state processor -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - clock::Clock, - entrypoint::ProgramResult, - pubkey::Pubkey, - sysvar::Sysvar, -}; - -use crate::state::{ - enums::ProposalState, governance::get_governance_data_for_realm, - proposal::get_proposal_data_for_governance, realm::get_realm_data, - signatory_record::get_signatory_record_data_for_seeds, - token_owner_record::get_token_owner_record_data_for_proposal_owner, +use { + crate::{ + error::GovernanceError, + state::{ + enums::ProposalState, governance::get_governance_data_for_realm, + proposal::get_proposal_data_for_governance, realm::assert_is_valid_realm, + signatory_record::get_signatory_record_data_for_seeds, + token_owner_record::get_token_owner_record_data_for_proposal_owner, + }, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + clock::Clock, + entrypoint::ProgramResult, + pubkey::Pubkey, + sysvar::Sysvar, + }, }; /// Processes SignOffProposal instruction @@ -27,9 +31,9 @@ pub fn process_sign_off_proposal(program_id: &Pubkey, accounts: &[AccountInfo]) let clock = Clock::get()?; - let mut realm_data = get_realm_data(program_id, realm_info)?; + assert_is_valid_realm(program_id, realm_info)?; - let mut governance_data = + let governance_data = get_governance_data_for_realm(program_id, governance_info, realm_info.key)?; let mut proposal_data = @@ -37,7 +41,14 @@ pub fn process_sign_off_proposal(program_id: &Pubkey, accounts: &[AccountInfo]) proposal_data.assert_can_sign_off()?; - // If the owner of the proposal hasn't appointed any signatories then can sign off the proposal themself + if governance_data.required_signatories_count > 0 + && proposal_data.signatories_count < governance_data.required_signatories_count + { + return Err(GovernanceError::MissingRequiredSignatories.into()); + } + + // If the owner of the proposal hasn't appointed any signatories then can sign + // off the proposal themself if proposal_data.signatories_count == 0 { let proposal_owner_record_info = next_account_info(account_info_iter)?; // 4 @@ -47,7 +58,8 @@ pub fn process_sign_off_proposal(program_id: &Pubkey, accounts: &[AccountInfo]) &proposal_data.token_owner_record, )?; - // Proposal owner (TokenOwner) or its governance_delegate must be the signatory and sign this transaction + // Proposal owner (TokenOwner) or its governance_delegate must be the signatory + // and sign this transaction proposal_owner_record_data.assert_token_owner_or_delegate_is_signer(signatory_info)?; proposal_data.signing_off_at = Some(clock.unix_timestamp); @@ -64,7 +76,7 @@ pub fn process_sign_off_proposal(program_id: &Pubkey, accounts: &[AccountInfo]) signatory_record_data.assert_can_sign_off(signatory_info)?; signatory_record_data.signed_off = true; - signatory_record_data.serialize(&mut *signatory_record_info.data.borrow_mut())?; + signatory_record_data.serialize(&mut signatory_record_info.data.borrow_mut()[..])?; if proposal_data.signatories_signed_off_count == 0 { proposal_data.signing_off_at = Some(clock.unix_timestamp); @@ -84,16 +96,7 @@ pub fn process_sign_off_proposal(program_id: &Pubkey, accounts: &[AccountInfo]) proposal_data.state = ProposalState::Voting; } - proposal_data.serialize(&mut *proposal_info.data.borrow_mut())?; - - realm_data.voting_proposal_count = realm_data.voting_proposal_count.checked_add(1).unwrap(); - realm_data.serialize(&mut *realm_info.data.borrow_mut())?; - - governance_data.voting_proposal_count = governance_data - .voting_proposal_count - .checked_add(1) - .unwrap(); - governance_data.serialize(&mut *governance_info.data.borrow_mut())?; + proposal_data.serialize(&mut proposal_info.data.borrow_mut()[..])?; Ok(()) } diff --git a/governance/program/src/processor/process_update_program_metadata.rs b/governance/program/src/processor/process_update_program_metadata.rs index 5a394c9920e..adfbe2812ab 100644 --- a/governance/program/src/processor/process_update_program_metadata.rs +++ b/governance/program/src/processor/process_update_program_metadata.rs @@ -1,20 +1,22 @@ //! Program state processor -use borsh::BorshSerialize; -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - clock::Clock, - entrypoint::ProgramResult, - msg, - pubkey::Pubkey, - rent::Rent, - sysvar::Sysvar, -}; -use spl_governance_tools::account::create_and_serialize_account_signed; - -use crate::state::{ - enums::GovernanceAccountType, - program_metadata::{get_program_metadata_data, get_program_metadata_seeds, ProgramMetadata}, +use { + crate::state::{ + enums::GovernanceAccountType, + program_metadata::{ + get_program_metadata_data, get_program_metadata_seeds, ProgramMetadata, + }, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + clock::Clock, + entrypoint::ProgramResult, + msg, + pubkey::Pubkey, + rent::Rent, + sysvar::Sysvar, + }, + spl_governance_tools::account::create_and_serialize_account_signed, }; /// Processes UpdateProgramMetadata instruction @@ -33,7 +35,8 @@ pub fn process_update_program_metadata( const VERSION: &str = env!("CARGO_PKG_VERSION"); - // Put the metadata info into the logs to make it possible to extract it using Tx simulation + // Put the metadata info into the logs to make it possible to extract it using + // Tx simulation msg!("PROGRAM-VERSION:{:?}", VERSION); if program_metadata_info.data_is_empty() { @@ -52,6 +55,7 @@ pub fn process_update_program_metadata( program_id, system_info, &rent, + 0, )?; } else { let mut program_metadata_data = @@ -60,7 +64,10 @@ pub fn process_update_program_metadata( program_metadata_data.version = VERSION.to_string(); program_metadata_data.updated_at = updated_at; - program_metadata_data.serialize(&mut *program_metadata_info.data.borrow_mut())?; + borsh::to_writer( + &mut program_metadata_info.data.borrow_mut()[..], + &program_metadata_data, + )?; } Ok(()) diff --git a/governance/program/src/processor/process_withdraw_governing_tokens.rs b/governance/program/src/processor/process_withdraw_governing_tokens.rs index fca2d7926ed..1aa8be2180e 100644 --- a/governance/program/src/processor/process_withdraw_governing_tokens.rs +++ b/governance/program/src/processor/process_withdraw_governing_tokens.rs @@ -1,20 +1,24 @@ //! Program state processor -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - pubkey::Pubkey, -}; - -use crate::{ - error::GovernanceError, - state::{ - realm::{get_realm_address_seeds, get_realm_data}, - token_owner_record::{ - get_token_owner_record_address_seeds, get_token_owner_record_data_for_seeds, +use { + crate::{ + error::GovernanceError, + state::{ + realm::{get_realm_address_seeds, get_realm_data}, + realm_config::get_realm_config_data_for_realm, + token_owner_record::{ + get_token_owner_record_address_seeds, get_token_owner_record_data_for_seeds, + }, }, + tools::spl_token::{get_spl_token_mint, transfer_spl_tokens_signed}, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + clock::Clock, + entrypoint::ProgramResult, + pubkey::Pubkey, + sysvar::Sysvar, }, - tools::spl_token::{get_spl_token_mint, transfer_spl_tokens_signed}, }; /// Processes WithdrawGoverningTokens instruction @@ -30,6 +34,8 @@ pub fn process_withdraw_governing_tokens( let governing_token_owner_info = next_account_info(account_info_iter)?; // 3 let token_owner_record_info = next_account_info(account_info_iter)?; // 4 let spl_token_info = next_account_info(account_info_iter)?; // 5 + let realm_config_info = next_account_info(account_info_iter)?; // 6 + let clock = Clock::get()?; if !governing_token_owner_info.is_signer { return Err(GovernanceError::GoverningTokenOwnerMustSign.into()); @@ -45,6 +51,11 @@ pub fn process_withdraw_governing_tokens( governing_token_holding_info.key, )?; + let realm_config_data = + get_realm_config_data_for_realm(program_id, realm_config_info, realm_info.key)?; + + realm_config_data.assert_can_withdraw_governing_token(&realm_data, &governing_token_mint)?; + let token_owner_record_address_seeds = get_token_owner_record_address_seeds( realm_info.key, &governing_token_mint, @@ -57,7 +68,7 @@ pub fn process_withdraw_governing_tokens( &token_owner_record_address_seeds, )?; - token_owner_record_data.assert_can_withdraw_governing_tokens()?; + token_owner_record_data.assert_can_withdraw_governing_tokens(clock.unix_timestamp)?; transfer_spl_tokens_signed( governing_token_holding_info, @@ -70,7 +81,7 @@ pub fn process_withdraw_governing_tokens( )?; token_owner_record_data.governing_token_deposit_amount = 0; - token_owner_record_data.serialize(&mut *token_owner_record_info.data.borrow_mut())?; + token_owner_record_data.serialize(&mut token_owner_record_info.data.borrow_mut()[..])?; Ok(()) } diff --git a/governance/program/src/state/enums.rs b/governance/program/src/state/enums.rs index e0811a1627b..f7b74b3ab69 100644 --- a/governance/program/src/state/enums.rs +++ b/governance/program/src/state/enums.rs @@ -3,12 +3,14 @@ use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; /// Defines all Governance accounts types -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, Default, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum GovernanceAccountType { /// Default uninitialized account state + #[default] Uninitialized, - /// Top level aggregation for governances with Community Token (and optional Council Token) + /// Top level aggregation for governances with Community Token (and optional + /// Council Token) RealmV1, /// Token Owner Record for given governing token owner within a Realm @@ -17,50 +19,57 @@ pub enum GovernanceAccountType { /// Governance account GovernanceV1, - /// Program Governance account + /// Legacy ProgramGovernanceV1 account ProgramGovernanceV1, - /// Proposal account for Governance account. A single Governance account can have multiple Proposal accounts + /// Proposal account for Governance account. A single Governance account can + /// have multiple Proposal accounts ProposalV1, /// Proposal Signatory account SignatoryRecordV1, - /// Vote record account for a given Proposal. Proposal can have 0..n voting records + /// Vote record account for a given Proposal. Proposal can have 0..n voting + /// records VoteRecordV1, - /// ProposalInstruction account which holds an instruction to execute for Proposal + /// ProposalInstruction account which holds an instruction to execute for + /// Proposal ProposalInstructionV1, - /// Mint Governance account + /// Legacy MintGovernanceV1 account MintGovernanceV1, - /// Token Governance account + /// Legacy TokenGovernanceV1 account TokenGovernanceV1, /// Realm config account (introduced in V2) RealmConfig, - /// Vote record account for a given Proposal. Proposal can have 0..n voting records - /// V2 adds support for multi option votes + /// Vote record account for a given Proposal. Proposal can have 0..n voting + /// records V2 adds support for multi option votes VoteRecordV2, - /// ProposalTransaction account which holds instructions to execute for Proposal within a single Transaction - /// V2 replaces ProposalInstruction and adds index for proposal option and multiple instructions + /// ProposalTransaction account which holds instructions to execute for + /// Proposal within a single Transaction V2 replaces ProposalInstruction + /// and adds index for proposal option and multiple instructions ProposalTransactionV2, - /// Proposal account for Governance account. A single Governance account can have multiple Proposal accounts - /// V2 adds support for multiple vote options + /// Proposal account for Governance account. A single Governance account can + /// have multiple Proposal accounts V2 adds support for multiple vote + /// options ProposalV2, /// Program metadata account (introduced in V2) - /// It stores information about the particular SPL-Governance program instance + /// It stores information about the particular SPL-Governance program + /// instance ProgramMetadata, - /// Top level aggregation for governances with Community Token (and optional Council Token) - /// V2 adds the following fields: - /// 1) use_community_voter_weight_addin and use_max_community_voter_weight_addin to RealmConfig - /// 2) voting_proposal_count + /// Top level aggregation for governances with Community Token (and optional + /// Council Token) V2 adds the following fields: + /// 1) use_community_voter_weight_addin and + /// use_max_community_voter_weight_addin to RealmConfig + /// 2) voting_proposal_count / replaced with legacy1 in V3 /// 3) extra reserved space reserved_v2 RealmV2, @@ -72,37 +81,39 @@ pub enum GovernanceAccountType { /// V2 adds extra reserved space reserved_v2 GovernanceV2, - /// Program Governance account + /// Legacy ProgramGovernanceV2 account deprecated in V4 /// V2 adds extra reserved space reserved_v2 ProgramGovernanceV2, - /// Mint Governance account + /// Legacy MintGovernanceV2 account deprecated in V4 /// V2 adds extra reserved space reserved_v2 MintGovernanceV2, - /// Token Governance account + /// Legacy TokenGovernanceV2 account deprecated in V4 /// V2 adds extra reserved space reserved_v2 TokenGovernanceV2, /// Proposal Signatory account /// V2 adds extra reserved space reserved_v2 SignatoryRecordV2, -} -impl Default for GovernanceAccountType { - fn default() -> Self { - GovernanceAccountType::Uninitialized - } + /// Proposal deposit account + ProposalDeposit, + + /// Required signatory account + RequiredSignatory, } /// What state a Proposal is in -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, Default, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum ProposalState { /// Draft - Proposal enters Draft state when it's created + #[default] Draft, /// SigningOff - The Proposal is being signed off by Signatories - /// Proposal enters the state when first Signatory Sings and leaves it when last Signatory signs + /// Proposal enters the state when first Signatory Sings and leaves it when + /// last Signatory signs SigningOff, /// Taking votes @@ -112,7 +123,8 @@ pub enum ProposalState { Succeeded, /// Voting on Proposal succeeded and now instructions are being executed - /// Proposal enter this state when first instruction is executed and leaves when the last instruction is executed + /// Proposal enter this state when first instruction is executed and leaves + /// when the last instruction is executed Executing, /// Completed @@ -125,43 +137,43 @@ pub enum ProposalState { Defeated, /// Same as Executing but indicates some instructions failed to execute - /// Proposal can't be transitioned from ExecutingWithErrors to Completed state + /// Proposal can't be transitioned from ExecutingWithErrors to Completed + /// state ExecutingWithErrors, /// The Proposal was vetoed Vetoed, } -impl Default for ProposalState { - fn default() -> Self { - ProposalState::Draft - } -} - /// The type of the vote threshold used to resolve a vote on a Proposal /// -/// Note: In the current version only YesVotePercentage and Disabled thresholds are supported -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +/// Note: In the current version only YesVotePercentage and Disabled thresholds +/// are supported +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum VoteThreshold { - /// Voting threshold of Yes votes in % required to tip the vote (Approval Quorum) - /// It's the percentage of tokens out of the entire pool of governance tokens eligible to vote - /// Note: If the threshold is below or equal to 50% then an even split of votes ex: 50:50 or 40:40 is always resolved as Defeated - /// In other words a '+1 vote' tie breaker is always required to have a successful vote + /// Voting threshold of Yes votes in % required to tip the vote (Approval + /// Quorum) It's the percentage of tokens out of the entire pool of + /// governance tokens eligible to vote Note: If the threshold is below + /// or equal to 50% then an even split of votes ex: 50:50 or 40:40 is always + /// resolved as Defeated In other words a '+1 vote' tie breaker is + /// always required to have a successful vote YesVotePercentage(u8), - /// The minimum number of votes in % out of the entire pool of governance tokens eligible to vote - /// which must be cast for the vote to be valid - /// Once the quorum is achieved a simple majority (50%+1) of Yes votes is required for the vote to succeed - /// Note: Quorum is not implemented in the current version + /// The minimum number of votes in % out of the entire pool of governance + /// tokens eligible to vote which must be cast for the vote to be valid + /// Once the quorum is achieved a simple majority (50%+1) of Yes votes is + /// required for the vote to succeed Note: Quorum is not implemented in + /// the current version QuorumPercentage(u8), - /// Disabled vote threshold indicates the given voting population (community or council) is not allowed to vote - /// on proposals for the given Governance + /// Disabled vote threshold indicates the given voting population (community + /// or council) is not allowed to vote on proposals for the given + /// Governance Disabled, // // Absolute vote threshold expressed in the voting mint units - // It can be implemented once Solana runtime supports accounts resizing to accommodate u64 size extension - // Alternatively we could use the reserved space if it becomes a priority + // It can be implemented once Solana runtime supports accounts resizing to accommodate u64 + // size extension Alternatively we could use the reserved space if it becomes a priority // Absolute(u64) // // Vote threshold which is always accepted @@ -173,10 +185,11 @@ pub enum VoteThreshold { /// The type of vote tipping to use on a Proposal. /// /// Vote tipping means that under some conditions voting will complete early. -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum VoteTipping { - /// Tip when there is no way for another option to win and the vote threshold - /// has been reached. This ignores voters withdrawing their votes. + /// Tip when there is no way for another option to win and the vote + /// threshold has been reached. This ignores voters withdrawing their + /// votes. /// /// Currently only supported for the "yes" option in single choice votes. Strict, @@ -192,7 +205,7 @@ pub enum VoteTipping { } /// The status of instruction execution -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum TransactionExecutionStatus { /// Transaction was not executed yet None, @@ -201,45 +214,52 @@ pub enum TransactionExecutionStatus { Success, /// Transaction execution failed + /// Note: The field is not used any longer Error, } -/// Transaction execution flags defining how instructions are executed for a Proposal -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +/// Transaction execution flags defining how instructions are executed for a +/// Proposal +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum InstructionExecutionFlags { /// No execution flags are specified - /// Instructions can be executed individually, in any order, as soon as they hold_up time expires + /// Instructions can be executed individually, in any order, as soon as they + /// hold_up time expires None, /// Instructions are executed in a specific order /// Note: Ordered execution is not supported in the current version - /// The implementation requires another account type to track deleted instructions + /// The implementation requires another account type to track deleted + /// instructions Ordered, /// Multiple instructions can be executed as a single transaction /// Note: Transactions are not supported in the current version - /// The implementation requires another account type to group instructions within a transaction + /// The implementation requires another account type to group instructions + /// within a transaction UseTransaction, } /// The source of max vote weight used for voting -/// Values below 100% mint supply can be used when the governing token is fully minted but not distributed yet -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] -pub enum MintMaxVoteWeightSource { - /// Fraction (10^10 precision) of the governing mint supply is used as max vote weight - /// The default is 100% (10^10) to use all available mint supply for voting +/// Values below 100% mint supply can be used when the governing token is fully +/// minted but not distributed yet +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] +pub enum MintMaxVoterWeightSource { + /// Fraction (10^10 precision) of the governing mint supply is used as max + /// vote weight The default is 100% (10^10) to use all available mint + /// supply for voting SupplyFraction(u64), - /// Absolute value, irrelevant of the actual mint supply, is used as max vote weight - /// Note: this option is not implemented in the current version + /// Absolute value, irrelevant of the actual mint supply, is used as max + /// voter weight Absolute(u64), } -impl MintMaxVoteWeightSource { +impl MintMaxVoterWeightSource { /// Base for mint supply fraction calculation pub const SUPPLY_FRACTION_BASE: u64 = 10_000_000_000; /// 100% of mint supply - pub const FULL_SUPPLY_FRACTION: MintMaxVoteWeightSource = - MintMaxVoteWeightSource::SupplyFraction(MintMaxVoteWeightSource::SUPPLY_FRACTION_BASE); + pub const FULL_SUPPLY_FRACTION: MintMaxVoterWeightSource = + MintMaxVoterWeightSource::SupplyFraction(MintMaxVoterWeightSource::SUPPLY_FRACTION_BASE); } diff --git a/governance/program/src/state/governance.rs b/governance/program/src/state/governance.rs index 6a7af6be174..f415c6187d8 100644 --- a/governance/program/src/state/governance.rs +++ b/governance/program/src/state/governance.rs @@ -1,98 +1,136 @@ //! Governance Account -use borsh::maybestd::io::Write; - -use crate::{ - error::GovernanceError, - state::{ - enums::{GovernanceAccountType, VoteThreshold, VoteTipping}, - legacy::{is_governance_v1_account_type, GovernanceV1}, - realm::{assert_is_valid_realm, RealmV2}, - vote_record::VoteKind, +use { + crate::{ + error::GovernanceError, + state::{ + enums::{GovernanceAccountType, VoteThreshold, VoteTipping}, + legacy::{is_governance_v1_account_type, GovernanceV1}, + realm::{assert_is_valid_realm, RealmV2}, + vote_record::VoteKind, + }, + tools::structs::Reserved119, + }, + borsh::{io::Write, BorshDeserialize, BorshSchema, BorshSerialize}, + solana_program::{ + account_info::AccountInfo, program_error::ProgramError, program_pack::IsInitialized, + pubkey::Pubkey, rent::Rent, + }, + spl_governance_tools::{ + account::{ + assert_is_valid_account_of_types, extend_account_size, get_account_data, + get_account_type, AccountMaxSize, + }, + error::GovernanceToolsError, }, -}; -use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; -use solana_program::{ - account_info::AccountInfo, borsh::try_from_slice_unchecked, program_error::ProgramError, - program_pack::IsInitialized, pubkey::Pubkey, -}; -use spl_governance_tools::{ - account::{assert_is_valid_account_of_types, get_account_data, AccountMaxSize}, - error::GovernanceToolsError, }; /// Governance config -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct GovernanceConfig { /// The type of the vote threshold used for community vote - /// Note: In the current version only YesVotePercentage and Disabled thresholds are supported + /// Note: In the current version only YesVotePercentage and Disabled + /// thresholds are supported pub community_vote_threshold: VoteThreshold, - /// Minimum community weight a governance token owner must possess to be able to create a proposal + /// Minimum community weight a governance token owner must possess to be + /// able to create a proposal pub min_community_weight_to_create_proposal: u64, - /// Minimum waiting time in seconds for a transaction to be executed after proposal is voted on - pub min_transaction_hold_up_time: u32, + /// The wait time in seconds before transactions can be executed after + /// proposal is successfully voted on + pub transactions_hold_up_time: u32, - /// Time limit in seconds for proposal to be open for voting - pub max_voting_time: u32, + /// The base voting time in seconds for proposal to be open for voting + /// Voting is unrestricted during the base voting time and any vote types + /// can be cast The base voting time can be extend by optional cool off + /// time when only negative votes (Veto and Deny) are allowed + pub voting_base_time: u32, - /// Conditions under which a vote will complete early - pub vote_tipping: VoteTipping, + /// Conditions under which a Community vote will complete early + pub community_vote_tipping: VoteTipping, /// The type of the vote threshold used for council vote - /// Note: In the current version only YesVotePercentage and Disabled thresholds are supported + /// Note: In the current version only YesVotePercentage and Disabled + /// thresholds are supported pub council_vote_threshold: VoteThreshold, /// The threshold for Council Veto votes pub council_veto_vote_threshold: VoteThreshold, - /// Minimum council weight a governance token owner must possess to be able to create a proposal + /// Minimum council weight a governance token owner must possess to be able + /// to create a proposal pub min_council_weight_to_create_proposal: u64, - // - // The threshold for Community Veto votes - // Note: Community Veto vote is not supported in the current version - // In order to use this threshold the space from GovernanceV2.reserved must be taken to expand GovernanceConfig size - // pub community_veto_vote_threshold: VoteThreshold, + + /// Conditions under which a Council vote will complete early + pub council_vote_tipping: VoteTipping, + + /// The threshold for Community Veto votes + pub community_veto_vote_threshold: VoteThreshold, + + /// Voting cool of time + pub voting_cool_off_time: u32, + + /// The number of active proposals exempt from the Proposal security deposit + pub deposit_exempt_proposal_count: u8, } +/// The default number of active proposals exempt from security deposit +pub const DEFAULT_DEPOSIT_EXEMPT_PROPOSAL_COUNT: u8 = 10; + +/// Security deposit is paid when a Proposal is created and can be refunded +/// after voting ends or the Proposals is cancelled +pub const SECURITY_DEPOSIT_BASE_LAMPORTS: u64 = 100_000_000; // 0.1 SOL + /// Governance Account -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct GovernanceV2 { - /// Account type. It can be Uninitialized, Governance, ProgramGovernance, TokenGovernance or MintGovernance + /// Account type. It can be Uninitialized, Governance, ProgramGovernance, + /// TokenGovernance or MintGovernance pub account_type: GovernanceAccountType, /// Governance Realm pub realm: Pubkey, - /// Account governed by this Governance and/or PDA identity seed - /// It can be Program account, Mint account, Token account or any other account - /// - /// Note: The account doesn't have to exist. In that case the field is only a PDA seed + /// The seed used to create Governance account PDA /// - /// Note: Setting governed_account doesn't give any authority over the governed account - /// The relevant authorities for specific account types must still be transferred to the Governance PDA - /// Ex: mint_authority/freeze_authority for a Mint account - /// or upgrade_authority for a Program account should be transferred to the Governance PDA - pub governed_account: Pubkey, + /// Note: For the legacy asset specific Governance accounts + /// the seed by convention is: + /// MintGovernance -> mint address + /// TokenAccountGovernance -> token account address + /// ProgramGovernance -> program address + pub governance_seed: Pubkey, - /// Running count of proposals - pub proposals_count: u32, + /// Reserved space for future versions + pub reserved1: u32, /// Governance config pub config: GovernanceConfig, - /// Reserved space for future versions - pub reserved: [u8; 6], + /// Reserved space for versions v2 and onwards + /// Note 1: V1 accounts must be resized before using this space + /// Note 2: The reserved space should be used from the end to also allow the + /// config to grow if needed + pub reserved_v2: Reserved119, - /// The number of proposals in voting state in the Governance - pub voting_proposal_count: u16, + /// The number of required signatories for proposals in the Governance + pub required_signatories_count: u8, - /// Reserved space for versions v2 and onwards - /// Note: This space won't be available to v1 accounts until runtime supports resizing - pub reserved_v2: [u8; 128], + /// The number of active proposals where active means Draft, SigningOff or + /// Voting state + /// + /// Note: The counter was introduced in program V3 and didn't exist in + /// program V1 & V2 If the program is upgraded from program V1 or V2 + /// while there are any outstanding active proposals the counter won't + /// be accurate until all proposals are transitioned to an inactive final + /// state and the counter reset + pub active_proposal_count: u64, } -impl AccountMaxSize for GovernanceV2 {} +impl AccountMaxSize for GovernanceV2 { + fn get_max_size(&self) -> Option { + Some(236) + } +} /// Checks if the given account type is one of the Governance V2 account types pub fn is_governance_v2_account_type(account_type: &GovernanceAccountType) -> bool { @@ -119,11 +157,50 @@ pub fn is_governance_v2_account_type(account_type: &GovernanceAccountType) -> bo | GovernanceAccountType::ProposalTransactionV2 | GovernanceAccountType::VoteRecordV1 | GovernanceAccountType::VoteRecordV2 - | GovernanceAccountType::ProgramMetadata => false, + | GovernanceAccountType::ProgramMetadata + | GovernanceAccountType::ProposalDeposit + | GovernanceAccountType::RequiredSignatory => false, } } -/// Checks if the given account type is on of the Governance account types of any version +/// Returns GovernanceV2 type for given GovernanceV1 type or None if the given +/// account type is not GovernanceV1 +pub fn try_get_governance_v2_type_for_v1( + account_type: &GovernanceAccountType, +) -> Option { + match account_type { + GovernanceAccountType::GovernanceV1 => Some(GovernanceAccountType::GovernanceV2), + GovernanceAccountType::ProgramGovernanceV1 => { + Some(GovernanceAccountType::ProgramGovernanceV2) + } + GovernanceAccountType::MintGovernanceV1 => Some(GovernanceAccountType::MintGovernanceV2), + GovernanceAccountType::TokenGovernanceV1 => Some(GovernanceAccountType::TokenGovernanceV2), + GovernanceAccountType::Uninitialized + | GovernanceAccountType::RealmV1 + | GovernanceAccountType::RealmV2 + | GovernanceAccountType::RealmConfig + | GovernanceAccountType::TokenOwnerRecordV1 + | GovernanceAccountType::TokenOwnerRecordV2 + | GovernanceAccountType::GovernanceV2 + | GovernanceAccountType::ProgramGovernanceV2 + | GovernanceAccountType::MintGovernanceV2 + | GovernanceAccountType::TokenGovernanceV2 + | GovernanceAccountType::ProposalV1 + | GovernanceAccountType::ProposalV2 + | GovernanceAccountType::SignatoryRecordV1 + | GovernanceAccountType::SignatoryRecordV2 + | GovernanceAccountType::ProposalInstructionV1 + | GovernanceAccountType::ProposalTransactionV2 + | GovernanceAccountType::VoteRecordV1 + | GovernanceAccountType::VoteRecordV2 + | GovernanceAccountType::ProgramMetadata + | GovernanceAccountType::ProposalDeposit + | GovernanceAccountType::RequiredSignatory => None, + } +} + +/// Checks if the given account type is on of the Governance account types of +/// any version pub fn is_governance_account_type(account_type: &GovernanceAccountType) -> bool { is_governance_v1_account_type(account_type) || is_governance_v2_account_type(account_type) } @@ -139,17 +216,17 @@ impl GovernanceV2 { pub fn get_governance_address_seeds(&self) -> Result<[&[u8]; 3], ProgramError> { let seeds = match self.account_type { GovernanceAccountType::GovernanceV1 | GovernanceAccountType::GovernanceV2 => { - get_governance_address_seeds(&self.realm, &self.governed_account) + get_governance_address_seeds(&self.realm, &self.governance_seed) } GovernanceAccountType::ProgramGovernanceV1 | GovernanceAccountType::ProgramGovernanceV2 => { - get_program_governance_address_seeds(&self.realm, &self.governed_account) + get_program_governance_address_seeds(&self.realm, &self.governance_seed) } GovernanceAccountType::MintGovernanceV1 | GovernanceAccountType::MintGovernanceV2 => { - get_mint_governance_address_seeds(&self.realm, &self.governed_account) + get_mint_governance_address_seeds(&self.realm, &self.governance_seed) } GovernanceAccountType::TokenGovernanceV1 | GovernanceAccountType::TokenGovernanceV2 => { - get_token_governance_address_seeds(&self.realm, &self.governed_account) + get_token_governance_address_seeds(&self.realm, &self.governance_seed) } GovernanceAccountType::Uninitialized | GovernanceAccountType::RealmV1 @@ -163,9 +240,11 @@ impl GovernanceV2 { | GovernanceAccountType::ProposalTransactionV2 | GovernanceAccountType::ProposalV2 | GovernanceAccountType::ProgramMetadata + | GovernanceAccountType::ProposalDeposit | GovernanceAccountType::RealmV2 | GovernanceAccountType::TokenOwnerRecordV2 - | GovernanceAccountType::SignatoryRecordV2 => { + | GovernanceAccountType::SignatoryRecordV2 + | GovernanceAccountType::RequiredSignatory => { return Err(GovernanceToolsError::InvalidAccountType.into()) } }; @@ -174,48 +253,86 @@ impl GovernanceV2 { } /// Serializes account into the target buffer - pub fn serialize(self, writer: &mut W) -> Result<(), ProgramError> { + pub fn serialize(self, writer: W) -> Result<(), ProgramError> { if is_governance_v2_account_type(&self.account_type) { - BorshSerialize::serialize(&self, writer)? + borsh::to_writer(writer, &self)? } else if is_governance_v1_account_type(&self.account_type) { - // V1 account can't be resized and we have to translate it back to the original format + // V1 account can't be resized and we have to translate it back to the original + // format - // If reserved_v2 is used it must be individually asses for v1 backward compatibility impact - if self.reserved_v2 != [0; 128] { + // If reserved_v2 is used it must be individually assessed for GovernanceV1 + // account backward compatibility impact + if self.reserved_v2 != Reserved119::default() { panic!("Extended data not supported by GovernanceV1") } + // Note: active_proposal_count is not preserved on GovernanceV1 account until + // it's migrated to GovernanceV2 during Proposal creation + let governance_data_v1 = GovernanceV1 { account_type: self.account_type, realm: self.realm, - governed_account: self.governed_account, - proposals_count: self.proposals_count, + governance_seed: self.governance_seed, + proposals_count: 0, config: self.config, - reserved: self.reserved, - voting_proposal_count: self.voting_proposal_count, }; - BorshSerialize::serialize(&governance_data_v1, writer)?; + borsh::to_writer(writer, &governance_data_v1)? } Ok(()) } - /// Asserts the provided voting population represented by the given governing_token_mint - /// can cast the given vote type on proposals for the Governance + /// Serializes Governance accounts as GovernanceV2 + /// If the account is GovernanceV1 then it changes its type to GovernanceV2 + /// and resizes account data Note: It supports all the specialized + /// Governance account types (Governance, ProgramGovernance, MintGovernance + /// and TokenGovernance) + pub fn serialize_as_governance_v2<'a>( + mut self, + governance_info: &AccountInfo<'a>, + payer_info: &AccountInfo<'a>, + system_info: &AccountInfo<'a>, + rent: &Rent, + ) -> Result<(), ProgramError> { + // If the Governance account is GovernanceV1 reallocate its size and change type + // to GovernanceV2 + if let Some(governance_v2_type) = try_get_governance_v2_type_for_v1(&self.account_type) { + // Change type to GovernanceV2 + // Note: Only type change is required because the account data was translated to + // GovernanceV2 during deserialisation + self.account_type = governance_v2_type; + + extend_account_size( + governance_info, + payer_info, + self.get_max_size().unwrap(), + rent, + system_info, + )?; + } + + self.serialize(&mut governance_info.data.borrow_mut()[..]) + } + + /// Asserts the provided voting population represented by the given + /// governing_token_mint can cast the given vote type on proposals for + /// the Governance pub fn assert_governing_token_mint_can_vote( &self, realm_data: &RealmV2, vote_governing_token_mint: &Pubkey, vote_kind: &VoteKind, ) -> Result<(), ProgramError> { - // resolve_vote_threshold() asserts the vote threshold exists for the given governing_token_mint and is not disabled + // resolve_vote_threshold() asserts the vote threshold exists for the given + // governing_token_mint and is not disabled let _ = self.resolve_vote_threshold(realm_data, vote_governing_token_mint, vote_kind)?; Ok(()) } - /// Resolves VoteThreshold for the given realm, governing token and Vote kind + /// Resolves VoteThreshold for the given realm, governing token and Vote + /// kind pub fn resolve_vote_threshold( &self, realm_data: &RealmV2, @@ -225,10 +342,7 @@ impl GovernanceV2 { let vote_threshold = if realm_data.community_mint == *vote_governing_token_mint { match vote_kind { VoteKind::Electorate => &self.config.community_vote_threshold, - VoteKind::Veto => { - // Community Veto vote is not supported in current version - return Err(GovernanceError::GoverningTokenMintNotAllowedToVote.into()); - } + VoteKind::Veto => &self.config.community_veto_vote_threshold, } } else if realm_data.config.council_mint == Some(*vote_governing_token_mint) { match vote_kind { @@ -245,6 +359,45 @@ impl GovernanceV2 { Ok(vote_threshold.clone()) } + + /// Returns VoteTipping for the given governing_token_mint + pub fn get_vote_tipping( + &self, + realm_data: &RealmV2, + governing_token_mint: &Pubkey, + ) -> Result<&VoteTipping, ProgramError> { + let vote_tipping = if *governing_token_mint == realm_data.community_mint { + &self.config.community_vote_tipping + } else if Some(*governing_token_mint) == realm_data.config.council_mint { + &self.config.council_vote_tipping + } else { + return Err(GovernanceError::InvalidGoverningTokenMint.into()); + }; + + Ok(vote_tipping) + } + + /// Returns the required deposit amount for creating Nth Proposal based on + /// the number of active proposals where N equals to + /// active_proposal_count - deposit_exempt_proposal_count The deposit is + /// not paid unless there are more active Proposal than the exempt amount + /// + /// Note: The exact deposit paid for Nth Proposal is + /// N*SECURITY_DEPOSIT_BASE_LAMPORTS + min_rent_for(ProposalDeposit) + /// + /// Note: Although the deposit amount paid for Nth proposal is linear the + /// total deposit amount required to create N proposals is sum of arithmetic + /// series Dn = N*r + d*N*(N+1)/2 + // where: + // Dn - The total deposit amount required to create N proposals + // N = active_proposal_count - deposit_exempt_proposal_count + // d = SECURITY_DEPOSIT_BASE_LAMPORTS + // r = min rent amount for ProposalDeposit + pub fn get_proposal_deposit_amount(&self) -> u64 { + self.active_proposal_count + .saturating_sub(self.config.deposit_exempt_proposal_count as u64) + .saturating_mul(SECURITY_DEPOSIT_BASE_LAMPORTS) + } } /// Deserializes Governance account and checks owner program @@ -252,12 +405,7 @@ pub fn get_governance_data( program_id: &Pubkey, governance_info: &AccountInfo, ) -> Result { - if governance_info.data_is_empty() { - return Err(GovernanceToolsError::AccountDoesNotExist.into()); - } - - let account_type: GovernanceAccountType = - try_from_slice_unchecked(&governance_info.data.borrow())?; + let account_type: GovernanceAccountType = get_account_type(program_id, governance_info)?; // If the account is V1 version then translate to V2 let mut governance_data = if is_governance_v1_account_type(&account_type) { @@ -266,40 +414,67 @@ pub fn get_governance_data( GovernanceV2 { account_type, realm: governance_data_v1.realm, - governed_account: governance_data_v1.governed_account, - proposals_count: governance_data_v1.proposals_count, + governance_seed: governance_data_v1.governance_seed, + reserved1: 0, config: governance_data_v1.config, - reserved: governance_data_v1.reserved, - voting_proposal_count: governance_data_v1.voting_proposal_count, - - // Add the extra reserved_v2 padding - reserved_v2: [0; 128], + reserved_v2: Reserved119::default(), + required_signatories_count: 0, + // GovernanceV1 layout doesn't support active_proposal_count + // For any legacy GovernanceV1 account it's not preserved until the account layout is + // migrated to GovernanceV2 in CreateProposal + active_proposal_count: 0, } } else { get_account_data::(program_id, governance_info)? }; - // In previous versions of spl-gov (< 3) we had config.proposal_cool_off_time:u32 which was unused and always 0 - // In version 3.0.0 proposal_cool_off_time was replaced with council_vote_threshold:VoteThreshold and council_veto_vote_threshold:VoteThreshold + // In previous versions of spl-gov (< 3) we had + // config.proposal_cool_off_time:u32 which was unused and always 0 + // In version 3.0.0 proposal_cool_off_time was replaced with + // council_vote_threshold:VoteThreshold and + // council_veto_vote_threshold:VoteThreshold If we read a legacy account + // then council_vote_threshold == VoteThreshold::YesVotePercentage(0) // - // If we read a legacy account then council_vote_threshold == VoteThreshold::YesVotePercentage(0) - // and we coerce it to be equal to community_vote_threshold which was used for both council and community thresholds before + // Note: assert_is_valid_governance_config() prevents setting + // council_vote_threshold to VoteThreshold::YesVotePercentage(0) which gives + // as guarantee that it is a legacy account layout set with + // proposal_cool_off_time = 0 // - // Note: assert_is_valid_governance_config() prevents setting council_vote_threshold to VoteThreshold::YesVotePercentage(0) - // which gives as guarantee that it is a legacy account layout set with proposal_cool_off_time = 0 + // Note: All the settings below are one time config migration from program V1 & + // V2 account data to V3 if governance_data.config.council_vote_threshold == VoteThreshold::YesVotePercentage(0) { + // Set council_vote_threshold to community_vote_threshold which was used for + // both council and community thresholds before governance_data.config.council_vote_threshold = governance_data.config.community_vote_threshold.clone(); - // The assumption here is that council should have Veto vote enabled by default and equal to council_vote_threshold + // The assumption here is that council should have Veto vote enabled by default + // and equal to council_vote_threshold governance_data.config.council_veto_vote_threshold = governance_data.config.council_vote_threshold.clone(); + + // For legacy accounts default Council VoteTipping to the Community + governance_data.config.council_vote_tipping = + governance_data.config.community_vote_tipping.clone(); + + // For legacy accounts set the community Veto threshold to Disabled + governance_data.config.community_veto_vote_threshold = VoteThreshold::Disabled; + + // Reset voting_cool_off_time and deposit_exempt_proposal_count previously used + // for voting_proposal_count + governance_data.config.voting_cool_off_time = 0; + governance_data.config.deposit_exempt_proposal_count = + DEFAULT_DEPOSIT_EXEMPT_PROPOSAL_COUNT; + + // Reset reserved space previously used for proposal_count + governance_data.reserved1 = 0; } Ok(governance_data) } -/// Deserializes Governance account, checks owner program and asserts governance belongs to the given ream +/// Deserializes Governance account, checks owner program and asserts governance +/// belongs to the given ream pub fn get_governance_data_for_realm( program_id: &Pubkey, governance_info: &AccountInfo, @@ -314,7 +489,8 @@ pub fn get_governance_data_for_realm( Ok(governance_data) } -/// Checks the given account is a governance account and belongs to the given realm +/// Checks the given account is a governance account and belongs to the given +/// realm pub fn assert_governance_for_realm( program_id: &Pubkey, governance_info: &AccountInfo, @@ -324,13 +500,14 @@ pub fn assert_governance_for_realm( Ok(()) } -/// Returns ProgramGovernance PDA seeds +/// Returns legacy ProgramGovernance PDA seeds pub fn get_program_governance_address_seeds<'a>( realm: &'a Pubkey, governed_program: &'a Pubkey, ) -> [&'a [u8]; 3] { // 'program-governance' prefix ensures uniqueness of the PDA - // Note: Only the current program upgrade authority can create an account with this PDA using CreateProgramGovernance instruction + // Note: Only the current program upgrade authority can create an account with + // this PDA using CreateProgramGovernance instruction [ b"program-governance", realm.as_ref(), @@ -338,7 +515,7 @@ pub fn get_program_governance_address_seeds<'a>( ] } -/// Returns ProgramGovernance PDA address +/// Returns legacy ProgramGovernance PDA address pub fn get_program_governance_address<'a>( program_id: &Pubkey, realm: &'a Pubkey, @@ -351,17 +528,18 @@ pub fn get_program_governance_address<'a>( .0 } -/// Returns MintGovernance PDA seeds +/// Returns legacy MintGovernance PDA seeds pub fn get_mint_governance_address_seeds<'a>( realm: &'a Pubkey, governed_mint: &'a Pubkey, ) -> [&'a [u8]; 3] { // 'mint-governance' prefix ensures uniqueness of the PDA - // Note: Only the current mint authority can create an account with this PDA using CreateMintGovernance instruction + // Note: Only the current mint authority can create an account with this PDA + // using CreateMintGovernance instruction [b"mint-governance", realm.as_ref(), governed_mint.as_ref()] } -/// Returns MintGovernance PDA address +/// Returns legacy MintGovernance PDA address pub fn get_mint_governance_address<'a>( program_id: &Pubkey, realm: &'a Pubkey, @@ -374,24 +552,29 @@ pub fn get_mint_governance_address<'a>( .0 } -/// Returns TokenGovernance PDA seeds +/// Returns legacy TokenGovernance PDA seeds pub fn get_token_governance_address_seeds<'a>( realm: &'a Pubkey, - governed_token: &'a Pubkey, + governed_token_account: &'a Pubkey, ) -> [&'a [u8]; 3] { // 'token-governance' prefix ensures uniqueness of the PDA - // Note: Only the current token account owner can create an account with this PDA using CreateTokenGovernance instruction - [b"token-governance", realm.as_ref(), governed_token.as_ref()] + // Note: Only the current token account owner can create an account with this + // PDA using CreateTokenGovernance instruction + [ + b"token-governance", + realm.as_ref(), + governed_token_account.as_ref(), + ] } -/// Returns TokenGovernance PDA address +/// Returns legacy TokenGovernance PDA address pub fn get_token_governance_address<'a>( program_id: &Pubkey, realm: &'a Pubkey, - governed_token: &'a Pubkey, + governed_token_account: &'a Pubkey, ) -> Pubkey { Pubkey::find_program_address( - &get_token_governance_address_seeds(realm, governed_token), + &get_token_governance_address_seeds(realm, governed_token_account), program_id, ) .0 @@ -400,12 +583,12 @@ pub fn get_token_governance_address<'a>( /// Returns Governance PDA seeds pub fn get_governance_address_seeds<'a>( realm: &'a Pubkey, - governed_account: &'a Pubkey, + governance_seed: &'a Pubkey, ) -> [&'a [u8]; 3] { [ b"account-governance", realm.as_ref(), - governed_account.as_ref(), + governance_seed.as_ref(), ] } @@ -413,16 +596,17 @@ pub fn get_governance_address_seeds<'a>( pub fn get_governance_address<'a>( program_id: &Pubkey, realm: &'a Pubkey, - governed_account: &'a Pubkey, + governance_seed: &'a Pubkey, ) -> Pubkey { Pubkey::find_program_address( - &get_governance_address_seeds(realm, governed_account), + &get_governance_address_seeds(realm, governance_seed), program_id, ) .0 } -/// Checks whether the Governance account exists, is initialized and owned by the Governance program +/// Checks whether the Governance account exists, is initialized and owned by +/// the Governance program pub fn assert_is_valid_governance( program_id: &Pubkey, governance_info: &AccountInfo, @@ -448,17 +632,25 @@ pub fn assert_is_valid_governance_config( governance_config: &GovernanceConfig, ) -> Result<(), ProgramError> { assert_is_valid_vote_threshold(&governance_config.community_vote_threshold)?; + assert_is_valid_vote_threshold(&governance_config.community_veto_vote_threshold)?; + assert_is_valid_vote_threshold(&governance_config.council_vote_threshold)?; assert_is_valid_vote_threshold(&governance_config.council_veto_vote_threshold)?; - // Setting both thresholds to Disabled is not allowed, however we might reconsider it as - // a way to disable Governance permanently + // Setting both thresholds to Disabled is not allowed, however we might + // reconsider it as a way to disable Governance permanently if governance_config.community_vote_threshold == VoteThreshold::Disabled && governance_config.council_vote_threshold == VoteThreshold::Disabled { return Err(GovernanceError::AtLeastOneVoteThresholdRequired.into()); } + // Make u8::MAX invalid value in case we would like to use the magic number as + // Disabled value in the future + if governance_config.deposit_exempt_proposal_count == u8::MAX { + return Err(GovernanceError::InvalidDepositExemptProposalCount.into()); + } + Ok(()) } @@ -481,9 +673,71 @@ pub fn assert_is_valid_vote_threshold(vote_threshold: &VoteThreshold) -> Result< #[cfg(test)] mod test { - use solana_program::clock::Epoch; + use {super::*, solana_program::clock::Epoch}; + + fn create_test_governance_config() -> GovernanceConfig { + GovernanceConfig { + community_vote_threshold: VoteThreshold::YesVotePercentage(60), + min_community_weight_to_create_proposal: 5, + transactions_hold_up_time: 10, + voting_base_time: 5, + community_vote_tipping: VoteTipping::Strict, + council_vote_threshold: VoteThreshold::YesVotePercentage(60), + council_veto_vote_threshold: VoteThreshold::YesVotePercentage(50), + min_council_weight_to_create_proposal: 1, + council_vote_tipping: VoteTipping::Strict, + community_veto_vote_threshold: VoteThreshold::YesVotePercentage(40), + voting_cool_off_time: 2, + deposit_exempt_proposal_count: 0, + } + } + + fn create_test_governance() -> GovernanceV2 { + GovernanceV2 { + account_type: GovernanceAccountType::GovernanceV2, + realm: Pubkey::new_unique(), + governance_seed: Pubkey::new_unique(), + reserved1: 0, + config: create_test_governance_config(), + reserved_v2: Reserved119::default(), + active_proposal_count: 10, + required_signatories_count: 0, + } + } - use super::*; + fn create_test_v1_governance() -> GovernanceV1 { + GovernanceV1 { + account_type: GovernanceAccountType::GovernanceV1, + realm: Pubkey::new_unique(), + governance_seed: Pubkey::new_unique(), + proposals_count: 10, + config: create_test_governance_config(), + } + } + + #[test] + fn test_max_governance_size() { + // Arrange + let governance_data = create_test_governance(); + + // Act + let size = borsh::to_vec(&governance_data).unwrap().len(); + + // Assert + assert_eq!(governance_data.get_max_size(), Some(size)); + } + + #[test] + fn test_v1_governance_size() { + // Arrange + let governance = create_test_v1_governance(); + + // Act + let size = borsh::to_vec(&governance).unwrap().len(); + + // Assert + assert_eq!(108, size); + } #[test] fn test_deserialize_legacy_governance_account_without_council_vote_thresholds() { @@ -535,21 +789,24 @@ mod test { governance.config.council_vote_threshold, governance.config.council_veto_vote_threshold ); + + assert_eq!( + governance.config.council_vote_tipping, + governance.config.community_vote_tipping + ); + + assert_eq!( + governance.config.deposit_exempt_proposal_count, + DEFAULT_DEPOSIT_EXEMPT_PROPOSAL_COUNT + ); + assert_eq!(governance.config.voting_cool_off_time, 0); } #[test] fn test_assert_config_invalid_with_council_zero_yes_vote_threshold() { // Arrange - let governance_config = GovernanceConfig { - community_vote_threshold: VoteThreshold::YesVotePercentage(1), - min_community_weight_to_create_proposal: 1, - min_transaction_hold_up_time: 1, - max_voting_time: 1, - vote_tipping: VoteTipping::Strict, - council_vote_threshold: VoteThreshold::YesVotePercentage(0), - council_veto_vote_threshold: VoteThreshold::YesVotePercentage(1), - min_council_weight_to_create_proposal: 1, - }; + let mut governance_config = create_test_governance_config(); + governance_config.council_vote_threshold = VoteThreshold::YesVotePercentage(0); // Act let err = assert_is_valid_governance_config(&governance_config) @@ -560,19 +817,81 @@ mod test { assert_eq!(err, GovernanceError::InvalidVoteThresholdPercentage.into()); } + #[test] + fn test_migrate_governance_config_from_legacy_data_to_program_v3() { + // Arrange + let mut governance_legacy_data = create_test_governance(); + + governance_legacy_data.config.community_vote_threshold = + VoteThreshold::YesVotePercentage(60); + + // council_vote_threshold == YesVotePercentage(0) indicates legacy account from + // V1 & V2 program versions + governance_legacy_data.config.council_vote_threshold = VoteThreshold::YesVotePercentage(0); + + governance_legacy_data.config.council_veto_vote_threshold = + VoteThreshold::YesVotePercentage(0); + governance_legacy_data.config.council_vote_tipping = VoteTipping::Disabled; + governance_legacy_data.config.community_veto_vote_threshold = + VoteThreshold::YesVotePercentage(0); + governance_legacy_data.config.voting_cool_off_time = 1; + governance_legacy_data.config.voting_base_time = 36000; + + let mut legacy_data = vec![]; + governance_legacy_data.serialize(&mut legacy_data).unwrap(); + + let program_id = Pubkey::new_unique(); + + let info_key = Pubkey::new_unique(); + let mut lamports = 10u64; + + let legacy_account_info = AccountInfo::new( + &info_key, + false, + false, + &mut lamports, + &mut legacy_data[..], + &program_id, + false, + Epoch::default(), + ); + // Act + let governance_program_v3 = get_governance_data(&program_id, &legacy_account_info).unwrap(); + + // Assert + assert_eq!( + governance_program_v3.config.council_vote_threshold, + VoteThreshold::YesVotePercentage(60) + ); + + assert_eq!( + governance_program_v3.config.council_veto_vote_threshold, + VoteThreshold::YesVotePercentage(60) + ); + + assert_eq!( + governance_program_v3.config.community_veto_vote_threshold, + VoteThreshold::Disabled + ); + + assert_eq!( + governance_program_v3.config.council_vote_tipping, + VoteTipping::Strict + ); + + assert_eq!(governance_program_v3.config.voting_cool_off_time, 0); + + assert_eq!( + governance_program_v3.config.deposit_exempt_proposal_count, + DEFAULT_DEPOSIT_EXEMPT_PROPOSAL_COUNT + ); + } + #[test] fn test_assert_config_invalid_with_community_zero_yes_vote_threshold() { // Arrange - let governance_config = GovernanceConfig { - community_vote_threshold: VoteThreshold::YesVotePercentage(0), - min_community_weight_to_create_proposal: 1, - min_transaction_hold_up_time: 1, - max_voting_time: 1, - vote_tipping: VoteTipping::Strict, - council_vote_threshold: VoteThreshold::YesVotePercentage(1), - council_veto_vote_threshold: VoteThreshold::YesVotePercentage(1), - min_council_weight_to_create_proposal: 1, - }; + let mut governance_config = create_test_governance_config(); + governance_config.community_vote_threshold = VoteThreshold::YesVotePercentage(0); // Act let err = assert_is_valid_governance_config(&governance_config) @@ -586,16 +905,9 @@ mod test { #[test] fn test_assert_config_invalid_with_all_vote_thresholds_disabled() { // Arrange - let governance_config = GovernanceConfig { - community_vote_threshold: VoteThreshold::Disabled, - min_community_weight_to_create_proposal: 1, - min_transaction_hold_up_time: 1, - max_voting_time: 1, - vote_tipping: VoteTipping::Strict, - council_vote_threshold: VoteThreshold::Disabled, - council_veto_vote_threshold: VoteThreshold::YesVotePercentage(1), - min_council_weight_to_create_proposal: 1, - }; + let mut governance_config = create_test_governance_config(); + governance_config.community_vote_threshold = VoteThreshold::Disabled; + governance_config.council_vote_threshold = VoteThreshold::Disabled; // Act let err = assert_is_valid_governance_config(&governance_config) @@ -609,16 +921,8 @@ mod test { #[test] fn test_assert_config_invalid_with_council_zero_yes_veto_vote_threshold() { // Arrange - let governance_config = GovernanceConfig { - community_vote_threshold: VoteThreshold::YesVotePercentage(1), - min_community_weight_to_create_proposal: 1, - min_transaction_hold_up_time: 1, - max_voting_time: 1, - vote_tipping: VoteTipping::Strict, - council_vote_threshold: VoteThreshold::YesVotePercentage(1), - council_veto_vote_threshold: VoteThreshold::YesVotePercentage(0), - min_council_weight_to_create_proposal: 1, - }; + let mut governance_config = create_test_governance_config(); + governance_config.council_veto_vote_threshold = VoteThreshold::YesVotePercentage(0); // Act let err = assert_is_valid_governance_config(&governance_config) @@ -628,4 +932,82 @@ mod test { // Assert assert_eq!(err, GovernanceError::InvalidVoteThresholdPercentage.into()); } + + #[test] + fn test_assert_config_invalid_with_community_zero_yes_veto_vote_threshold() { + // Arrange + let mut governance_config = create_test_governance_config(); + governance_config.community_veto_vote_threshold = VoteThreshold::YesVotePercentage(0); + + // Act + let err = assert_is_valid_governance_config(&governance_config) + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::InvalidVoteThresholdPercentage.into()); + } + + #[test] + fn test_get_proposal_deposit_amount_for_exempt_proposal() { + // Arrange + let mut governance_data = create_test_governance(); + + governance_data.active_proposal_count = 10; + governance_data.config.deposit_exempt_proposal_count = 10; + + // Act + let deposit_amount = governance_data.get_proposal_deposit_amount(); + + // Assert + assert_eq!(deposit_amount, 0); + } + + #[test] + fn test_get_proposal_deposit_amount_for_non_exempt_proposal() { + // Arrange + let mut governance_data = create_test_governance(); + + governance_data.active_proposal_count = 100; + governance_data.config.deposit_exempt_proposal_count = 10; + + // Act + let deposit_amount = governance_data.get_proposal_deposit_amount(); + + // Assert + assert_eq!(deposit_amount, SECURITY_DEPOSIT_BASE_LAMPORTS * 90); + } + + #[test] + fn test_get_proposal_deposit_amount_without_exempt_proposal() { + // Arrange + let mut governance_data = create_test_governance(); + + governance_data.active_proposal_count = 10; + governance_data.config.deposit_exempt_proposal_count = 0; + + // Act + let deposit_amount = governance_data.get_proposal_deposit_amount(); + + // Assert + assert_eq!(deposit_amount, SECURITY_DEPOSIT_BASE_LAMPORTS * 10); + } + + #[test] + fn test_assert_config_invalid_with_max_deposit_exempt_proposal_count() { + // Arrange + let mut governance_config = create_test_governance_config(); + governance_config.deposit_exempt_proposal_count = u8::MAX; + + // Act + let err = assert_is_valid_governance_config(&governance_config) + .err() + .unwrap(); + + // Assert + assert_eq!( + err, + GovernanceError::InvalidDepositExemptProposalCount.into() + ); + } } diff --git a/governance/program/src/state/legacy.rs b/governance/program/src/state/legacy.rs index 39fcd71d67b..5dff691c3f6 100644 --- a/governance/program/src/state/legacy.rs +++ b/governance/program/src/state/legacy.rs @@ -1,24 +1,26 @@ //! Legacy Accounts -use crate::state::{ - enums::{ - GovernanceAccountType, InstructionExecutionFlags, ProposalState, - TransactionExecutionStatus, VoteThreshold, +use { + crate::state::{ + enums::{ + GovernanceAccountType, InstructionExecutionFlags, ProposalState, + TransactionExecutionStatus, VoteThreshold, + }, + governance::GovernanceConfig, + proposal_transaction::InstructionData, + realm::RealmConfig, + }, + borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, + solana_program::{ + clock::{Slot, UnixTimestamp}, + program_pack::IsInitialized, + pubkey::Pubkey, }, - governance::GovernanceConfig, - proposal_transaction::InstructionData, - realm::RealmConfig, -}; -use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; -use solana_program::{ - clock::{Slot, UnixTimestamp}, - program_pack::IsInitialized, - pubkey::Pubkey, }; /// Governance Realm Account /// Account PDA seeds" ['governance', name] -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct RealmV1 { /// Governance account type pub account_type: GovernanceAccountType, @@ -37,8 +39,9 @@ pub struct RealmV1 { /// and we have preserve it for V1 serialization roundtrip pub voting_proposal_count: u16, - /// Realm authority. The authority must sign transactions which update the realm config - /// The authority should be transferred to Realm Governance to make the Realm self governed through proposals + /// Realm authority. The authority must sign transactions which update the + /// realm config The authority should be transferred to Realm Governance + /// to make the Realm self governed through proposals pub authority: Option, /// Governance Realm name @@ -53,7 +56,7 @@ impl IsInitialized for RealmV1 { /// Governance Token Owner Record /// Account PDA seeds: ['governance', realm, token_mint, token_owner ] -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct TokenOwnerRecordV1 { /// Governance account type pub account_type: GovernanceAccountType, @@ -64,8 +67,8 @@ pub struct TokenOwnerRecordV1 { /// Governing Token Mint the TokenOwnerRecord holds deposit for pub governing_token_mint: Pubkey, - /// The owner (either single or multisig) of the deposited governing SPL Tokens - /// This is who can authorize a withdrawal of the tokens + /// The owner (either single or multisig) of the deposited governing SPL + /// Tokens This is who can authorize a withdrawal of the tokens pub governing_token_owner: Pubkey, /// The amount of governing tokens deposited into the Realm @@ -73,24 +76,26 @@ pub struct TokenOwnerRecordV1 { pub governing_token_deposit_amount: u64, /// The number of votes cast by TokenOwner but not relinquished yet - /// Every time a vote is cast this number is increased and it's always decreased when relinquishing a vote regardless of the vote state - pub unrelinquished_votes_count: u32, - - /// The total number of votes cast by the TokenOwner - /// If TokenOwner withdraws vote while voting is still in progress total_votes_count is decreased and the vote doesn't count towards the total - pub total_votes_count: u32, + /// Every time a vote is cast this number is increased and it's always + /// decreased when relinquishing a vote regardless of the vote state + pub unrelinquished_votes_count: u64, /// The number of outstanding proposals the TokenOwner currently owns /// The count is increased when TokenOwner creates a proposal - /// and decreased once it's either voted on (Succeeded or Defeated) or Cancelled - /// By default it's restricted to 1 outstanding Proposal per token owner + /// and decreased once it's either voted on (Succeeded or Defeated) or + /// Cancelled By default it's restricted to 10 outstanding Proposal per + /// token owner pub outstanding_proposal_count: u8, + /// Version introduced in program V3 + pub version: u8, + /// Reserved space for future versions - pub reserved: [u8; 7], + pub reserved: [u8; 6], - /// A single account that is allowed to operate governance with the deposited governing tokens - /// It can be delegated to by the governing_token_owner or current governance_delegate + /// A single account that is allowed to operate governance with the + /// deposited governing tokens It can be delegated to by the + /// governing_token_owner or current governance_delegate pub governance_delegate: Option, } @@ -101,38 +106,29 @@ impl IsInitialized for TokenOwnerRecordV1 { } /// Governance Account -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct GovernanceV1 { - /// Account type. It can be Uninitialized, Governance, ProgramGovernance, TokenGovernance or MintGovernance + /// Account type. It can be Uninitialized, Governance, ProgramGovernance, + /// TokenGovernance or MintGovernance pub account_type: GovernanceAccountType, /// Governance Realm pub realm: Pubkey, - /// Account governed by this Governance and/or PDA identity seed - /// It can be Program account, Mint account, Token account or any other account - /// - /// Note: The account doesn't have to exist. In that case the field is only a PDA seed + /// The seed used to create Governance account PDA /// - /// Note: Setting governed_account doesn't give any authority over the governed account - /// The relevant authorities for specific account types must still be transferred to the Governance PDA - /// Ex: mint_authority/freeze_authority for a Mint account - /// or upgrade_authority for a Program account should be transferred to the Governance PDA - pub governed_account: Pubkey, + /// Note: For the legacy asset specific Governance accounts + /// the seed by convention is: + /// MintGovernance -> mint address + /// TokenAccountGovernance -> token account address + /// ProgramGovernance -> program address + pub governance_seed: Pubkey, /// Running count of proposals pub proposals_count: u32, /// Governance config pub config: GovernanceConfig, - - /// Reserved space for future versions - pub reserved: [u8; 6], - - /// The number of proposals in voting state in the Governance - /// Note: This is field introduced in V2 but it took space from reserved - /// and we have preserve it for V1 serialization roundtrip - pub voting_proposal_count: u16, } /// Checks if the given account type is one of the Governance V1 account types @@ -160,7 +156,9 @@ pub fn is_governance_v1_account_type(account_type: &GovernanceAccountType) -> bo | GovernanceAccountType::ProposalTransactionV2 | GovernanceAccountType::VoteRecordV1 | GovernanceAccountType::VoteRecordV2 - | GovernanceAccountType::ProgramMetadata => false, + | GovernanceAccountType::ProgramMetadata + | GovernanceAccountType::ProposalDeposit + | GovernanceAccountType::RequiredSignatory => false, } } @@ -171,7 +169,7 @@ impl IsInitialized for GovernanceV1 { } /// Governance Proposal -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct ProposalV1 { /// Governance account type pub account_type: GovernanceAccountType, @@ -180,13 +178,15 @@ pub struct ProposalV1 { pub governance: Pubkey, /// Indicates which Governing Token is used to vote on the Proposal - /// Whether the general Community token owners or the Council tokens owners vote on this Proposal + /// Whether the general Community token owners or the Council tokens owners + /// vote on this Proposal pub governing_token_mint: Pubkey, /// Current proposal state pub state: ProposalState, - /// The TokenOwnerRecord representing the user who created and owns this Proposal + /// The TokenOwnerRecord representing the user who created and owns this + /// Proposal pub token_owner_record: Pubkey, /// The number of signatories assigned to the Proposal @@ -207,7 +207,7 @@ pub struct ProposalV1 { /// The number of instructions included in the proposal pub instructions_count: u16, - /// The index of the the next instruction to be added + /// The index of the next instruction to be added pub instructions_next_index: u16, /// When the Proposal was created and entered Draft state @@ -220,7 +220,8 @@ pub struct ProposalV1 { pub voting_at: Option, /// When the Proposal began voting as Slot - /// Note: The slot is not currently used but the exact slot is going to be required to support snapshot based vote weights + /// Note: The slot is not currently used but the exact slot is going to be + /// required to support snapshot based vote weights pub voting_at_slot: Option, /// When the Proposal ended voting and entered either Succeeded or Defeated @@ -229,21 +230,24 @@ pub struct ProposalV1 { /// When the Proposal entered Executing state pub executing_at: Option, - /// When the Proposal entered final state Completed or Cancelled and was closed + /// When the Proposal entered final state Completed or Cancelled and was + /// closed pub closed_at: Option, /// Instruction execution flag for ordered and transactional instructions /// Note: This field is not used in the current version pub execution_flags: InstructionExecutionFlags, - /// The max vote weight for the Governing Token mint at the time Proposal was decided - /// It's used to show correct vote results for historical proposals in cases when the mint supply or max weight source changed + /// The max vote weight for the Governing Token mint at the time Proposal + /// was decided It's used to show correct vote results for historical + /// proposals in cases when the mint supply or max weight source changed /// after vote was completed. pub max_vote_weight: Option, /// The vote threshold percentage at the time Proposal was decided - /// It's used to show correct vote results for historical proposals in cases when the threshold - /// was changed for governance config after vote was completed. + /// It's used to show correct vote results for historical proposals in cases + /// when the threshold was changed for governance config after vote was + /// completed. pub vote_threshold: Option, /// Proposal name @@ -260,7 +264,7 @@ impl IsInitialized for ProposalV1 { } /// Account PDA seeds: ['governance', proposal, signatory] -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct SignatoryRecordV1 { /// Governance account type pub account_type: GovernanceAccountType, @@ -282,7 +286,7 @@ impl IsInitialized for SignatoryRecordV1 { } /// Proposal instruction V1 -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct ProposalInstructionV1 { /// Governance Account type pub account_type: GovernanceAccountType, @@ -293,12 +297,13 @@ pub struct ProposalInstructionV1 { /// Unique instruction index within it's parent Proposal pub instruction_index: u16, - /// Minimum waiting time in seconds for the instruction to be executed once proposal is voted on - pub hold_up_time: u32, + /// Previously hold_up_time in versions < V4 + pub legacy: u32, /// Instruction to execute /// The instruction will be signed by Governance PDA the Proposal belongs to - // For example for ProgramGovernance the instruction to upgrade program will be signed by ProgramGovernance PDA + // For example for ProgramGovernance the instruction to upgrade program will be signed by + // ProgramGovernance PDA pub instruction: InstructionData, /// Executed at flag @@ -315,7 +320,7 @@ impl IsInitialized for ProposalInstructionV1 { } /// Vote with number of votes -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum VoteWeightV1 { /// Yes vote Yes(u64), @@ -325,7 +330,7 @@ pub enum VoteWeightV1 { } /// Proposal VoteRecord -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct VoteRecordV1 { /// Governance account type pub account_type: GovernanceAccountType, @@ -334,7 +339,8 @@ pub struct VoteRecordV1 { pub proposal: Pubkey, /// The user who casted this vote - /// This is the Governing Token Owner who deposited governing tokens into the Realm + /// This is the Governing Token Owner who deposited governing tokens into + /// the Realm pub governing_token_owner: Pubkey, /// Indicates whether the vote was relinquished by voter diff --git a/governance/program/src/state/mod.rs b/governance/program/src/state/mod.rs index b64fec9e516..aa9ebf56be4 100644 --- a/governance/program/src/state/mod.rs +++ b/governance/program/src/state/mod.rs @@ -6,9 +6,11 @@ pub mod legacy; pub mod native_treasury; pub mod program_metadata; pub mod proposal; +pub mod proposal_deposit; pub mod proposal_transaction; pub mod realm; pub mod realm_config; +pub mod required_signatory; pub mod signatory_record; pub mod token_owner_record; pub mod vote_record; diff --git a/governance/program/src/state/native_treasury.rs b/governance/program/src/state/native_treasury.rs index ec313d76987..45be0e79bc4 100644 --- a/governance/program/src/state/native_treasury.rs +++ b/governance/program/src/state/native_treasury.rs @@ -1,12 +1,15 @@ //! Native treasury account -use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; -use solana_program::pubkey::Pubkey; -use spl_governance_tools::account::AccountMaxSize; +use { + borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, + solana_program::pubkey::Pubkey, + spl_governance_tools::account::AccountMaxSize, +}; /// Treasury account -/// The account has no data and can be used as a payer for instruction signed by Governance PDAs or as a native SOL treasury -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +/// The account has no data and can be used as a payer for instruction signed by +/// Governance PDAs or as a native SOL treasury +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct NativeTreasury {} impl AccountMaxSize for NativeTreasury { diff --git a/governance/program/src/state/program_metadata.rs b/governance/program/src/state/program_metadata.rs index 1c2fbf0ecd4..7c0f7f51423 100644 --- a/governance/program/src/state/program_metadata.rs +++ b/governance/program/src/state/program_metadata.rs @@ -1,16 +1,18 @@ //! ProgramMetadata Account -use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; -use solana_program::{ - account_info::AccountInfo, clock::Slot, program_error::ProgramError, - program_pack::IsInitialized, pubkey::Pubkey, +use { + crate::state::enums::GovernanceAccountType, + borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, + solana_program::{ + account_info::AccountInfo, clock::Slot, program_error::ProgramError, + program_pack::IsInitialized, pubkey::Pubkey, + }, + spl_governance_tools::account::{get_account_data, AccountMaxSize}, }; -use spl_governance_tools::account::{get_account_data, AccountMaxSize}; -use crate::state::enums::GovernanceAccountType; - -/// Program metadata account. It stores information about the particular SPL-Governance program instance -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +/// Program metadata account. It stores information about the particular +/// SPL-Governance program instance +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct ProgramMetadata { /// Governance account type pub account_type: GovernanceAccountType, @@ -70,7 +72,7 @@ mod test { version: "111.122.155".to_string(), }; - let size = program_metadata_data.try_to_vec().unwrap().len(); + let size = borsh::to_vec(&program_metadata_data).unwrap().len(); assert_eq!(program_metadata_data.get_max_size(), Some(size)); } diff --git a/governance/program/src/state/proposal.rs b/governance/program/src/state/proposal.rs index 6a72ec149fd..7f8090a3e44 100644 --- a/governance/program/src/state/proposal.rs +++ b/governance/program/src/state/proposal.rs @@ -1,45 +1,41 @@ //! Proposal Account -use borsh::maybestd::io::Write; -use solana_program::account_info::next_account_info; -use std::cmp::Ordering; -use std::slice::Iter; - -use solana_program::borsh::try_from_slice_unchecked; -use solana_program::clock::{Slot, UnixTimestamp}; - -use solana_program::{ - account_info::AccountInfo, program_error::ProgramError, program_pack::IsInitialized, - pubkey::Pubkey, -}; -use spl_governance_tools::account::{get_account_data, AccountMaxSize}; - -use crate::addins::max_voter_weight::{ - assert_is_valid_max_voter_weight, - get_max_voter_weight_record_data_for_realm_and_governing_token_mint, -}; -use crate::state::legacy::ProposalV1; -use crate::tools::spl_token::get_spl_token_mint_supply; -use crate::{ - error::GovernanceError, - state::{ - enums::{ - GovernanceAccountType, InstructionExecutionFlags, MintMaxVoteWeightSource, - ProposalState, TransactionExecutionStatus, VoteThreshold, VoteTipping, +use { + crate::{ + addins::max_voter_weight::{ + assert_is_valid_max_voter_weight, + get_max_voter_weight_record_data_for_realm_and_governing_token_mint, + }, + error::GovernanceError, + state::{ + enums::{ + GovernanceAccountType, InstructionExecutionFlags, MintMaxVoterWeightSource, + ProposalState, VoteThreshold, VoteTipping, + }, + governance::GovernanceConfig, + legacy::ProposalV1, + proposal_transaction::ProposalTransactionV2, + realm::RealmV2, + realm_config::RealmConfigAccount, + vote_record::{Vote, VoteKind}, }, - governance::GovernanceConfig, - proposal_transaction::ProposalTransactionV2, - realm::RealmV2, - realm_config::get_realm_config_data_for_realm, - vote_record::Vote, - vote_record::VoteKind, + tools::spl_token::get_spl_token_mint_supply, + PROGRAM_AUTHORITY_SEED, }, - PROGRAM_AUTHORITY_SEED, + borsh::{io::Write, BorshDeserialize, BorshSchema, BorshSerialize}, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + clock::{Slot, UnixTimestamp}, + program_error::ProgramError, + program_pack::IsInitialized, + pubkey::Pubkey, + }, + spl_governance_tools::account::{get_account_data, get_account_type, AccountMaxSize}, + std::{cmp::Ordering, slice::Iter}, }; -use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; /// Proposal option vote result -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum OptionVoteResult { /// Vote on the option is not resolved yet None, @@ -52,7 +48,7 @@ pub enum OptionVoteResult { } /// Proposal Option -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct ProposalOption { /// Option label pub label: String, @@ -69,17 +65,19 @@ pub struct ProposalOption { /// The number of transactions included in the option pub transactions_count: u16, - /// The index of the the next transaction to be added + /// The index of the next transaction to be added pub transactions_next_index: u16, } /// Proposal vote type -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum VoteType { /// Single choice vote with mutually exclusive choices /// In the SingeChoice mode there can ever be a single winner - /// If multiple options score the same highest vote then the Proposal is not resolved and considered as Failed - /// Note: Yes/No vote is a single choice (Yes) vote with the deny option (No) + /// If multiple options score the same highest vote then the Proposal is + /// not resolved and considered as Failed. + /// Note: Yes/No vote is a single choice (Yes) vote with the deny + /// option (No) SingleChoice, /// Multiple options can be selected with up to max_voter_options per voter @@ -87,23 +85,53 @@ pub enum VoteType { /// Ex. voters are given 5 options, can choose up to 3 (max_voter_options) /// and only 1 (max_winning_options) option can win and be executed MultiChoice { + /// Type of MultiChoice + #[allow(dead_code)] + choice_type: MultiChoiceType, + + /// The min number of options a voter must choose + /// + /// Note: In the current version the limit is not supported and not + /// enforced and must always be set to 1 + #[allow(dead_code)] + min_voter_options: u8, + /// The max number of options a voter can choose - /// By default it equals to the number of available options - /// Note: In the current version the limit is not supported and not enforced yet + /// + /// Note: In the current version the limit is not supported and not + /// enforced and must always be set to the number of available + /// options #[allow(dead_code)] max_voter_options: u8, /// The max number of wining options - /// For executable proposals it limits how many options can be executed for a Proposal - /// By default it equals to the number of available options - /// Note: In the current version the limit is not supported and not enforced yet + /// For executable proposals it limits how many options can be executed + /// for a Proposal + /// + /// Note: In the current version the limit is not supported and not + /// enforced and must always be set to the number of available + /// options #[allow(dead_code)] max_winning_options: u8, }, } +/// Type of MultiChoice. +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] +pub enum MultiChoiceType { + /// Multiple options can be approved with full weight allocated to each + /// approved option + FullWeight, + + /// Multiple options can be approved with weight allocated proportionally + /// to the percentage of the total weight. + /// The full weight has to be voted among the approved options, i.e., + /// 100% of the weight has to be allocated + Weighted, +} + /// Governance Proposal -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct ProposalV2 { /// Governance account type pub account_type: GovernanceAccountType, @@ -112,14 +140,16 @@ pub struct ProposalV2 { pub governance: Pubkey, /// Indicates which Governing Token is used to vote on the Proposal - /// Whether the general Community token owners or the Council tokens owners vote on this Proposal + /// Whether the general Community token owners or the Council tokens owners + /// vote on this Proposal pub governing_token_mint: Pubkey, /// Current proposal state pub state: ProposalState, // TODO: add state_at timestamp to have single field to filter recent proposals in the UI - /// The TokenOwnerRecord representing the user who created and owns this Proposal + /// The TokenOwnerRecord representing the user who created and owns this + /// Proposal pub token_owner_record: Pubkey, /// The number of signatories assigned to the Proposal @@ -136,8 +166,13 @@ pub struct ProposalV2 { /// The total weight of the Proposal rejection votes /// If the proposal has no deny option then the weight is None - /// Only proposals with the deny option can have executable instructions attached to them - /// Without the deny option a proposal is only non executable survey + /// + /// Only proposals with the deny option can have executable instructions + /// attached to them Without the deny option a proposal is only non + /// executable survey + /// + /// The deny options is also used for off-chain and/or manually executable + /// proposal to make them binding as opposed to survey only proposals pub deny_vote_weight: Option, /// Reserved space for future versions @@ -148,8 +183,9 @@ pub struct ProposalV2 { /// Note: Abstain is not supported in the current version pub abstain_vote_weight: Option, - /// Optional start time if the Proposal should not enter voting state immediately after being signed off - /// Note: start_at is not supported in the current version + /// Optional start time if the Proposal should not enter voting state + /// immediately after being signed off Note: start_at is not supported + /// in the current version pub start_voting_at: Option, /// When the Proposal was created and entered Draft state @@ -162,7 +198,8 @@ pub struct ProposalV2 { pub voting_at: Option, /// When the Proposal began voting as Slot - /// Note: The slot is not currently used but the exact slot is going to be required to support snapshot based vote weights + /// Note: The slot is not currently used but the exact slot is going to be + /// required to support snapshot based vote weights pub voting_at_slot: Option, /// When the Proposal ended voting and entered either Succeeded or Defeated @@ -171,26 +208,32 @@ pub struct ProposalV2 { /// When the Proposal entered Executing state pub executing_at: Option, - /// When the Proposal entered final state Completed or Cancelled and was closed + /// When the Proposal entered final state Completed or Cancelled and was + /// closed pub closed_at: Option, /// Instruction execution flag for ordered and transactional instructions /// Note: This field is not used in the current version pub execution_flags: InstructionExecutionFlags, - /// The max vote weight for the Governing Token mint at the time Proposal was decided - /// It's used to show correct vote results for historical proposals in cases when the mint supply or max weight source changed - /// after vote was completed. + /// The max vote weight for the Governing Token mint at the time Proposal + /// was decided. + /// It's used to show correct vote results for historical proposals in + /// cases when the mint supply or max weight source changed after vote was + /// completed. pub max_vote_weight: Option, - /// Max voting time for the proposal if different from parent Governance (only higher value possible) + /// Max voting time for the proposal if different from parent Governance + /// (only higher value possible). /// Note: This field is not used in the current version pub max_voting_time: Option, /// The vote threshold at the time Proposal was decided - /// It's used to show correct vote results for historical proposals in cases when the threshold - /// was changed for governance config after vote was completed. - /// TODO: Use this field to override the threshold from parent Governance (only higher value possible) + /// It's used to show correct vote results for historical proposals in cases + /// when the threshold was changed for governance config after vote was + /// completed. + /// TODO: Use this field to override the threshold from parent Governance + /// (only higher value possible) pub vote_threshold: Option, /// Reserved space for future versions @@ -209,7 +252,7 @@ pub struct ProposalV2 { impl AccountMaxSize for ProposalV2 { fn get_max_size(&self) -> Option { let options_size: usize = self.options.iter().map(|o| o.label.len() + 19).sum(); - Some(self.name.len() + self.description_link.len() + options_size + 295) + Some(self.name.len() + self.description_link.len() + options_size + 297) } } @@ -220,13 +263,14 @@ impl IsInitialized for ProposalV2 { } impl ProposalV2 { - /// Checks if Signatories can be edited (added or removed) for the Proposal in the given state + /// Checks if Signatories can be edited (added or removed) for the Proposal + /// in the given state pub fn assert_can_edit_signatories(&self) -> Result<(), ProgramError> { self.assert_is_draft_state() .map_err(|_| GovernanceError::InvalidStateCannotEditSignatories.into()) } - /// Checks if Proposal can be singed off + /// Checks if Proposal can be signed off pub fn assert_can_sign_off(&self) -> Result<(), ProgramError> { match self.state { ProposalState::Draft | ProposalState::SigningOff => Ok(()), @@ -259,39 +303,106 @@ impl ProposalV2 { Ok(()) } + /// Checks the Proposal was finalized (no more state transition will happen) + pub fn assert_is_final_state(&self) -> Result<(), ProgramError> { + match self.state { + ProposalState::Completed + | ProposalState::Cancelled + | ProposalState::Defeated + | ProposalState::Vetoed => Ok(()), + ProposalState::Executing + | ProposalState::ExecutingWithErrors + | ProposalState::SigningOff + | ProposalState::Voting + | ProposalState::Draft + | ProposalState::Succeeded => Err(GovernanceError::InvalidStateNotFinal.into()), + } + } + /// Checks if Proposal can be voted on pub fn assert_can_cast_vote( &self, config: &GovernanceConfig, + vote: &Vote, current_unix_timestamp: UnixTimestamp, ) -> Result<(), ProgramError> { self.assert_is_voting_state() .map_err(|_| GovernanceError::InvalidStateCannotVote)?; - // Check if we are still within the configured max_voting_time period - if self.has_vote_time_ended(config, current_unix_timestamp) { + // Check if we are still within the configured max voting time period + if self.has_voting_max_time_ended(config, current_unix_timestamp) { return Err(GovernanceError::ProposalVotingTimeExpired.into()); } - Ok(()) + match vote { + Vote::Approve(_) | Vote::Abstain => { + // Once the base voting time passes and we are in the voting cool off time + // approving votes are no longer accepted Abstain is considered + // as positive vote because when attendance quorum is used it can tip the scales + if self.has_voting_base_time_ended(config, current_unix_timestamp) { + Err(GovernanceError::VoteNotAllowedInCoolOffTime.into()) + } else { + Ok(()) + } + } + // Within voting cool off time only counter votes are allowed + Vote::Deny | Vote::Veto => Ok(()), + } + } + + /// Checks if proposal has concluded so that security deposit is no longer + /// needed + pub fn assert_can_refund_proposal_deposit(&self) -> Result<(), ProgramError> { + match self.state { + ProposalState::Succeeded + | ProposalState::Executing + | ProposalState::Completed + | ProposalState::Cancelled + | ProposalState::Defeated + | ProposalState::ExecutingWithErrors + | ProposalState::Vetoed => Ok(()), + ProposalState::Draft | ProposalState::SigningOff | ProposalState::Voting => { + Err(GovernanceError::CannotRefundProposalDeposit.into()) + } + } } - /// Vote end time determined by the configured max_voting_time period - pub fn vote_end_time(&self, config: &GovernanceConfig) -> UnixTimestamp { + /// Expected base vote end time determined by the configured + /// base_voting_time and actual voting start time + pub fn voting_base_time_end(&self, config: &GovernanceConfig) -> UnixTimestamp { self.voting_at .unwrap() - .checked_add(config.max_voting_time as i64) + .checked_add(config.voting_base_time as i64) + .unwrap() + } + + /// Checks whether the base voting time has ended for the proposal + pub fn has_voting_base_time_ended( + &self, + config: &GovernanceConfig, + current_unix_timestamp: UnixTimestamp, + ) -> bool { + // Check if we passed the configured base vote end time + self.voting_base_time_end(config) < current_unix_timestamp + } + + /// Expected max vote end time determined by the configured + /// base_voting_time, optional voting_cool_off_time and actual voting start + /// time + pub fn voting_max_time_end(&self, config: &GovernanceConfig) -> UnixTimestamp { + self.voting_base_time_end(config) + .checked_add(config.voting_cool_off_time as i64) .unwrap() } - /// Checks whether the voting time has ended for the proposal - pub fn has_vote_time_ended( + /// Checks whether the max voting time has ended for the proposal + pub fn has_voting_max_time_ended( &self, config: &GovernanceConfig, current_unix_timestamp: UnixTimestamp, ) -> bool { - // Check if we passed vote_end_time - self.vote_end_time(config) < current_unix_timestamp + // Check if we passed the max vote end time + self.voting_max_time_end(config) < current_unix_timestamp } /// Checks if Proposal can be finalized @@ -303,16 +414,18 @@ impl ProposalV2 { self.assert_is_voting_state() .map_err(|_| GovernanceError::InvalidStateCannotFinalize)?; - // We can only finalize the vote after the configured max_voting_time has expired and vote time ended - if !self.has_vote_time_ended(config, current_unix_timestamp) { + // We can only finalize the vote after the configured max_voting_time has + // expired and vote time ended + if !self.has_voting_max_time_ended(config, current_unix_timestamp) { return Err(GovernanceError::CannotFinalizeVotingInProgress.into()); } Ok(()) } - /// Finalizes vote by moving it to final state Succeeded or Defeated if max_voting_time has passed - /// If Proposal is still within max_voting_time period then error is returned + /// Finalizes vote by moving it to final state Succeeded or Defeated if + /// max_voting_time has passed If Proposal is still within + /// max_voting_time period then error is returned pub fn finalize_vote( &mut self, max_voter_weight: u64, @@ -323,7 +436,7 @@ impl ProposalV2 { self.assert_can_finalize_vote(config, current_unix_timestamp)?; self.state = self.resolve_final_vote_state(max_voter_weight, vote_threshold)?; - self.voting_completed_at = Some(self.vote_end_time(config)); + self.voting_completed_at = Some(self.voting_max_time_end(config)); // Capture vote params to correctly display historical results self.max_vote_weight = Some(max_voter_weight); @@ -343,16 +456,19 @@ impl ProposalV2 { let min_vote_threshold_weight = get_min_vote_threshold_weight(vote_threshold, max_vote_weight).unwrap(); - // If the proposal has a reject option then any other option must beat it regardless of the configured min_vote_threshold_weight + // If the proposal has a reject option then any other option must beat it + // regardless of the configured min_vote_threshold_weight let deny_vote_weight = self.deny_vote_weight.unwrap_or(0); let mut best_succeeded_option_weight = 0; let mut best_succeeded_option_count = 0u16; for option in self.options.iter_mut() { - // Any positive vote (Yes) must be equal or above the required min_vote_threshold_weight and higher than the reject option vote (No) - // The same number of positive (Yes) and rejecting (No) votes is a tie and resolved as Defeated - // In other words +1 vote as a tie breaker is required to succeed for the positive option vote + // Any positive vote (Yes) must be equal or above the required + // min_vote_threshold_weight and higher than the reject option vote (No) + // The same number of positive (Yes) and rejecting (No) votes is a tie and + // resolved as Defeated In other words +1 vote as a tie breaker is + // required to succeed for the positive option vote if option.vote_weight >= min_vote_threshold_weight && option.vote_weight > deny_vote_weight { @@ -375,20 +491,23 @@ impl ProposalV2 { } let mut final_state = if best_succeeded_option_count == 0 { - // If none of the individual options succeeded then the proposal as a whole is defeated + // If none of the individual options succeeded then the proposal as a whole is + // defeated ProposalState::Defeated } else { - match self.vote_type { + match &self.vote_type { VoteType::SingleChoice => { let proposal_state = if best_succeeded_option_count > 1 { - // If there is more than one winning option then the single choice proposal is considered as defeated + // If there is more than one winning option then the single choice proposal + // is considered as defeated best_succeeded_option_weight = u64::MAX; // no winning option ProposalState::Defeated } else { ProposalState::Succeeded }; - // Coerce options vote results based on the winning score (best_succeeded_vote_weight) + // Coerce options vote results based on the winning score + // (best_succeeded_vote_weight) for option in self.options.iter_mut() { option.vote_result = if option.vote_weight == best_succeeded_option_weight { OptionVoteResult::Succeeded @@ -400,17 +519,28 @@ impl ProposalV2 { proposal_state } VoteType::MultiChoice { - max_voter_options: _n, - max_winning_options: _m, + choice_type: _, + max_voter_options: _, + max_winning_options: _, + min_voter_options: _, } => { - // If any option succeeded for multi choice then the proposal as a whole succeeded as well + // If any option succeeded for multi choice then the proposal as a whole + // succeeded as well ProposalState::Succeeded } } }; - // None executable proposal is just a survey and is considered Completed once the vote ends and no more actions are available - // There is no overall Success or Failure status for the Proposal however individual options still have their own status + // None executable proposal is just a survey and is considered Completed once + // the vote ends and no more actions are available There is no overall + // Success or Failure status for the Proposal however individual options still + // have their own status + // + // Note: An off-chain/manually executable Proposal has no instructions but it + // still must have the deny vote enabled to be binding In such a case, + // if successful, the Proposal vote ends in Succeeded state and it must be + // manually transitioned to Completed state by the Proposal owner once + // the external actions are executed if self.deny_vote_weight.is_none() { final_state = ProposalState::Completed; } @@ -431,26 +561,25 @@ impl ProposalV2 { return Ok(governing_token_mint_supply); } - match realm_data.config.community_mint_max_vote_weight_source { - MintMaxVoteWeightSource::SupplyFraction(fraction) => { - if fraction == MintMaxVoteWeightSource::SUPPLY_FRACTION_BASE { + let max_voter_weight = match realm_data.config.community_mint_max_voter_weight_source { + MintMaxVoterWeightSource::SupplyFraction(fraction) => { + if fraction == MintMaxVoterWeightSource::SUPPLY_FRACTION_BASE { return Ok(governing_token_mint_supply); } - let max_voter_weight = (governing_token_mint_supply as u128) + (governing_token_mint_supply as u128) .checked_mul(fraction as u128) .unwrap() - .checked_div(MintMaxVoteWeightSource::SUPPLY_FRACTION_BASE as u128) - .unwrap() as u64; - - // When the fraction is used it's possible we can go over the calculated max_vote_weight - // and we have to adjust it in case more votes have been cast - Ok(self.coerce_max_voter_weight(max_voter_weight, vote_kind)) - } - MintMaxVoteWeightSource::Absolute(_) => { - Err(GovernanceError::VoteWeightSourceNotSupported.into()) + .checked_div(MintMaxVoterWeightSource::SUPPLY_FRACTION_BASE as u128) + .unwrap() as u64 } - } + MintMaxVoterWeightSource::Absolute(value) => value, + }; + + // When the fraction or absolute value is used it's possible we can go over the + // calculated max_vote_weight and we have to adjust it in case more + // votes have been cast + Ok(self.coerce_max_voter_weight(max_voter_weight, vote_kind)) } /// Adjusts max voter weight to ensure it's not lower than total cast votes @@ -472,30 +601,30 @@ impl ProposalV2 { max_voter_weight.max(total_vote_weight) } - /// Resolves max voter weight + /// Resolves max voter weight using either 1) voting governing_token_mint + /// supply or 2) max voter weight if configured for the token mint #[allow(clippy::too_many_arguments)] pub fn resolve_max_voter_weight( &mut self, - program_id: &Pubkey, - realm_config_info: &AccountInfo, - vote_governing_token_mint_info: &AccountInfo, account_info_iter: &mut Iter, realm: &Pubkey, realm_data: &RealmV2, + realm_config_data: &RealmConfigAccount, + vote_governing_token_mint_info: &AccountInfo, vote_kind: &VoteKind, ) -> Result { - // if the realm uses addin for max community voter weight then use the externally provided max weight - if realm_data.config.use_max_community_voter_weight_addin - && realm_data.community_mint == *vote_governing_token_mint_info.key + // if the Realm is configured to use max voter weight for the given voting + // governing_token_mint then use the externally provided max_voter_weight + // instead of the supply based max + if let Some(max_voter_weight_addin) = realm_config_data + .get_token_config(realm_data, vote_governing_token_mint_info.key)? + .max_voter_weight_addin { - let realm_config_data = - get_realm_config_data_for_realm(program_id, realm_config_info, realm)?; - let max_voter_weight_record_info = next_account_info(account_info_iter)?; let max_voter_weight_record_data = get_max_voter_weight_record_data_for_realm_and_governing_token_mint( - &realm_config_data.max_community_voter_weight_addin.unwrap(), + &max_voter_weight_addin, max_voter_weight_record_info, realm, vote_governing_token_mint_info.key, @@ -503,8 +632,9 @@ impl ProposalV2 { assert_is_valid_max_voter_weight(&max_voter_weight_record_data)?; - // When the max voter weight addin is used it's possible it can be inaccurate and we can have more votes then the max provided by the addin - // and we have to adjust it to whatever result is higher + // When the max voter weight addin is used it's possible it can be inaccurate + // and we can have more votes then the max provided by the addin and + // we have to adjust it to whatever result is higher return Ok(self.coerce_max_voter_weight( max_voter_weight_record_data.max_voter_weight, vote_kind, @@ -524,8 +654,9 @@ impl ProposalV2 { Ok(max_voter_weight) } - /// Checks if vote can be tipped and automatically transitioned to Succeeded or Defeated state - /// If the conditions are met the state is updated accordingly + /// Checks if vote can be tipped and automatically transitioned to Succeeded + /// or Defeated state If the conditions are met the state is updated + /// accordingly pub fn try_tip_vote( &mut self, max_voter_weight: u64, @@ -554,7 +685,8 @@ impl ProposalV2 { } } - /// Checks if vote can be tipped and automatically transitioned to Succeeded, Defeated or Vetoed state + /// Checks if vote can be tipped and automatically transitioned to + /// Succeeded, Defeated or Vetoed state. /// If yes then Some(ProposalState) is returned and None otherwise pub fn try_get_tipped_vote_state( &mut self, @@ -576,7 +708,8 @@ impl ProposalV2 { } } - /// Checks if Electorate vote can be tipped and automatically transitioned to Succeeded or Defeated state + /// Checks if Electorate vote can be tipped and automatically transitioned + /// to Succeeded or Defeated state. /// If yes then Some(ProposalState) is returned and None otherwise fn try_get_tipped_electorate_vote_state( &mut self, @@ -584,32 +717,25 @@ impl ProposalV2 { vote_tipping: &VoteTipping, min_vote_threshold_weight: u64, ) -> Option { - // Vote tipping is currently supported for SingleChoice votes with single Yes and No (rejection) options only - // Note: Tipping for multiple options (single choice and multiple choices) should be possible but it requires a great deal of considerations - // and I decided to fight it another day + // Vote tipping is currently supported for SingleChoice votes with + // single Yes and No (rejection) options only. + // Note: Tipping for multiple options (single choice and multiple + // choices) should be possible but it requires a great deal of + // considerations and I decided to fight it another day if self.vote_type != VoteType::SingleChoice - // Tipping should not be allowed for opinion only proposals (surveys without rejection) to allow everybody's voice to be heard + // Tipping should not be allowed for opinion only proposals (surveys + // without rejection) to allow everybody's voice to be heard || self.deny_vote_weight.is_none() || self.options.len() != 1 { return None; }; - let mut yes_option = &mut self.options[0]; + let yes_option = &mut self.options[0]; let yes_vote_weight = yes_option.vote_weight; let deny_vote_weight = self.deny_vote_weight.unwrap(); - if yes_vote_weight == max_voter_weight { - yes_option.vote_result = OptionVoteResult::Succeeded; - return Some(ProposalState::Succeeded); - } - - if deny_vote_weight == max_voter_weight { - yes_option.vote_result = OptionVoteResult::Defeated; - return Some(ProposalState::Defeated); - } - match vote_tipping { VoteTipping::Disabled => {} VoteTipping::Strict => { @@ -652,9 +778,11 @@ impl ProposalV2 { min_vote_threshold_weight: u64, ) -> Option { // Veto vote tips as soon as the required threshold is reached - // It's irrespectively of vote_tipping config because the outcome of the Proposal can't change any longer after being vetoed + // It's irrespectively of vote_tipping config because the outcome of the + // Proposal can't change any longer after being vetoed if self.veto_vote_weight >= min_vote_threshold_weight { - // Note: Since we don't tip multi option votes all options vote_result would remain as None + // Note: Since we don't tip multi option votes all options vote_result would + // remain as None Some(ProposalState::Vetoed) } else { None @@ -670,9 +798,10 @@ impl ProposalV2 { match self.state { ProposalState::Draft | ProposalState::SigningOff => Ok(()), ProposalState::Voting => { - // Note: If there is no tipping point the proposal can be still in Voting state but already past the configured max_voting_time - // In that case we treat the proposal as finalized and it's no longer allowed to be canceled - if self.has_vote_time_ended(config, current_unix_timestamp) { + // Note: If there is no tipping point the proposal can be still in Voting state + // but already past the configured max_voting_time In that case + // we treat the proposal as finalized and it's no longer allowed to be canceled + if self.has_voting_max_time_ended(config, current_unix_timestamp) { return Err(GovernanceError::ProposalVotingTimeExpired.into()); } Ok(()) @@ -689,14 +818,16 @@ impl ProposalV2 { } } - /// Checks if Instructions can be edited (inserted or removed) for the Proposal in the given state - /// It also asserts whether the Proposal is executable (has the reject option) + /// Checks if Instructions can be edited (inserted or removed) for the + /// Proposal in the given state It also asserts whether the Proposal is + /// executable (has the reject option) pub fn assert_can_edit_instructions(&self) -> Result<(), ProgramError> { if self.assert_is_draft_state().is_err() { return Err(GovernanceError::InvalidStateCannotEditTransactions.into()); } - // For security purposes only proposals with the reject option can have executable instructions + // For security purposes only proposals with the reject option can have + // executable instructions if self.deny_vote_weight.is_none() { return Err(GovernanceError::ProposalIsNotExecutable.into()); } @@ -704,10 +835,12 @@ impl ProposalV2 { Ok(()) } - /// Checks if Instructions can be executed for the Proposal in the given state + /// Checks if Instructions can be executed for the Proposal in the given + /// state pub fn assert_can_execute_transaction( &self, proposal_transaction_data: &ProposalTransactionV2, + governance_config: &GovernanceConfig, current_unix_timestamp: UnixTimestamp, ) -> Result<(), ProgramError> { match self.state { @@ -734,7 +867,7 @@ impl ProposalV2 { if self .voting_completed_at .unwrap() - .checked_add(proposal_transaction_data.hold_up_time as i64) + .checked_add(governance_config.transactions_hold_up_time as i64) .unwrap() >= current_unix_timestamp { @@ -748,17 +881,17 @@ impl ProposalV2 { Ok(()) } - /// Checks if the instruction can be flagged with error for the Proposal in the given state - pub fn assert_can_flag_transaction_error( - &self, - proposal_transaction_data: &ProposalTransactionV2, - current_unix_timestamp: UnixTimestamp, - ) -> Result<(), ProgramError> { - // Instruction can be flagged for error only when it's eligible for execution - self.assert_can_execute_transaction(proposal_transaction_data, current_unix_timestamp)?; + /// Checks if Proposal with off-chain/manual actions can be transitioned to + /// Completed + pub fn assert_can_complete(&self) -> Result<(), ProgramError> { + // Proposal vote must be successful + if self.state != ProposalState::Succeeded { + return Err(GovernanceError::InvalidStateToCompleteProposal.into()); + } - if proposal_transaction_data.execution_status == TransactionExecutionStatus::Error { - return Err(GovernanceError::TransactionAlreadyFlaggedWithError.into()); + // There must be no on-chain executable actions + if self.options.iter().any(|o| o.transactions_count != 0) { + return Err(GovernanceError::InvalidStateToCompleteProposal.into()); } Ok(()) @@ -769,42 +902,79 @@ impl ProposalV2 { match vote { Vote::Approve(choices) => { if self.options.len() != choices.len() { - return Err(GovernanceError::InvalidVote.into()); + return Err(GovernanceError::InvalidNumberOfVoteChoices.into()); } let mut choice_count = 0u16; + let mut total_choice_weight_percentage = 0u8; for choice in choices { if choice.rank > 0 { - return Err(GovernanceError::InvalidVote.into()); + return Err(GovernanceError::RankedVoteIsNotSupported.into()); } - if choice.weight_percentage == 100 { + if choice.weight_percentage > 0 { choice_count = choice_count.checked_add(1).unwrap(); - } else if choice.weight_percentage != 0 { - return Err(GovernanceError::InvalidVote.into()); + + match self.vote_type { + VoteType::MultiChoice { + choice_type: MultiChoiceType::Weighted, + min_voter_options: _, + max_voter_options: _, + max_winning_options: _, + } => { + // Calculate the total percentage for all choices for weighted + // choice vote. The total must add up + // to exactly 100% + total_choice_weight_percentage = total_choice_weight_percentage + .checked_add(choice.weight_percentage) + .ok_or(GovernanceError::TotalVoteWeightMustBe100Percent)?; + } + _ => { + if choice.weight_percentage != 100 { + return Err( + GovernanceError::ChoiceWeightMustBe100Percent.into() + ); + } + } + } } } match self.vote_type { VoteType::SingleChoice => { if choice_count != 1 { - return Err(GovernanceError::InvalidVote.into()); + return Err(GovernanceError::SingleChoiceOnlyIsAllowed.into()); + } + } + VoteType::MultiChoice { + choice_type: MultiChoiceType::FullWeight, + min_voter_options: _, + max_voter_options: _, + max_winning_options: _, + } => { + if choice_count == 0 { + return Err(GovernanceError::AtLeastSingleChoiceIsRequired.into()); } } VoteType::MultiChoice { - max_voter_options: _n, - max_winning_options: _m, + choice_type: MultiChoiceType::Weighted, + min_voter_options: _, + max_voter_options: _, + max_winning_options: _, } => { if choice_count == 0 { - return Err(GovernanceError::InvalidVote.into()); + return Err(GovernanceError::AtLeastSingleChoiceIsRequired.into()); + } + if total_choice_weight_percentage != 100 { + return Err(GovernanceError::TotalVoteWeightMustBe100Percent.into()); } } } } Vote::Deny => { if self.deny_vote_weight.is_none() { - return Err(GovernanceError::InvalidVote.into()); + return Err(GovernanceError::DenyVoteIsNotAllowed.into()); } } Vote::Abstain => { @@ -817,11 +987,12 @@ impl ProposalV2 { } /// Serializes account into the target buffer - pub fn serialize(self, writer: &mut W) -> Result<(), ProgramError> { + pub fn serialize(self, writer: W) -> Result<(), ProgramError> { if self.account_type == GovernanceAccountType::ProposalV2 { - BorshSerialize::serialize(&self, writer)? + borsh::to_writer(writer, &self)? } else if self.account_type == GovernanceAccountType::ProposalV1 { - // V1 account can't be resized and we have to translate it back to the original format + // V1 account can't be resized and we have to translate it back to the original + // format if self.abstain_vote_weight.is_some() { panic!("ProposalV1 doesn't support Abstain vote") @@ -870,7 +1041,7 @@ impl ProposalV2 { description_link: self.description_link, }; - BorshSerialize::serialize(&proposal_data_v1, writer)?; + borsh::to_writer(writer, &proposal_data_v1)? } Ok(()) @@ -910,8 +1081,7 @@ pub fn get_proposal_data( program_id: &Pubkey, proposal_info: &AccountInfo, ) -> Result { - let account_type: GovernanceAccountType = - try_from_slice_unchecked(&proposal_info.data.borrow())?; + let account_type: GovernanceAccountType = get_account_type(program_id, proposal_info)?; // If the account is V1 version then translate to V2 if account_type == GovernanceAccountType::ProposalV1 { @@ -971,7 +1141,8 @@ pub fn get_proposal_data( get_account_data::(program_id, proposal_info) } -/// Deserializes Proposal and validates it belongs to the given Governance and governing_token_mint +/// Deserializes Proposal and validates it belongs to the given Governance and +/// governing_token_mint pub fn get_proposal_data_for_governance_and_governing_mint( program_id: &Pubkey, proposal_info: &AccountInfo, @@ -1006,13 +1177,13 @@ pub fn get_proposal_data_for_governance( pub fn get_proposal_address_seeds<'a>( governance: &'a Pubkey, governing_token_mint: &'a Pubkey, - proposal_index_le_bytes: &'a [u8], + proposal_seed: &'a Pubkey, ) -> [&'a [u8]; 4] { [ PROGRAM_AUTHORITY_SEED, governance.as_ref(), governing_token_mint.as_ref(), - proposal_index_le_bytes, + proposal_seed.as_ref(), ] } @@ -1021,10 +1192,10 @@ pub fn get_proposal_address<'a>( program_id: &Pubkey, governance: &'a Pubkey, governing_token_mint: &'a Pubkey, - proposal_index_le_bytes: &'a [u8], + proposal_seed: &'a Pubkey, ) -> Pubkey { Pubkey::find_program_address( - &get_proposal_address_seeds(governance, governing_token_mint, proposal_index_le_bytes), + &get_proposal_address_seeds(governance, governing_token_mint, proposal_seed), program_id, ) .0 @@ -1040,15 +1211,18 @@ pub fn assert_valid_proposal_options( } if let VoteType::MultiChoice { + choice_type: _, + min_voter_options, max_voter_options, max_winning_options, - } = *vote_type + } = vote_type { if options.len() == 1 - || max_voter_options as usize != options.len() - || max_winning_options as usize != options.len() + || *max_voter_options as usize != options.len() + || *max_winning_options as usize != options.len() + || *min_voter_options != 1 { - return Err(GovernanceError::InvalidProposalOptions.into()); + return Err(GovernanceError::InvalidMultiChoiceProposalParameters.into()); } } @@ -1064,18 +1238,18 @@ pub fn assert_valid_proposal_options( #[cfg(test)] mod test { - use super::*; - use solana_program::clock::Epoch; - - use crate::state::{ - enums::{MintMaxVoteWeightSource, VoteThreshold}, - legacy::ProposalV1, - realm::RealmConfig, - vote_record::VoteChoice, + use { + super::*, + crate::state::{ + enums::{MintMaxVoterWeightSource, VoteThreshold}, + legacy::ProposalV1, + realm::RealmConfig, + vote_record::VoteChoice, + }, + proptest::prelude::*, + solana_program::clock::Epoch, }; - use proptest::prelude::*; - fn create_test_proposal() -> ProposalV2 { ProposalV2 { account_type: GovernanceAccountType::TokenOwnerRecordV2, @@ -1166,28 +1340,32 @@ mod test { config: RealmConfig { council_mint: Some(Pubkey::new_unique()), reserved: [0; 6], - use_community_voter_weight_addin: false, - use_max_community_voter_weight_addin: false, + legacy1: 0, + legacy2: 0, - community_mint_max_vote_weight_source: - MintMaxVoteWeightSource::FULL_SUPPLY_FRACTION, + community_mint_max_voter_weight_source: + MintMaxVoterWeightSource::FULL_SUPPLY_FRACTION, min_community_weight_to_create_governance: 10, }, - voting_proposal_count: 0, + legacy1: 0, reserved_v2: [0; 128], } } fn create_test_governance_config() -> GovernanceConfig { GovernanceConfig { - min_community_weight_to_create_proposal: 5, - min_council_weight_to_create_proposal: 1, - min_transaction_hold_up_time: 10, - max_voting_time: 5, community_vote_threshold: VoteThreshold::YesVotePercentage(60), - vote_tipping: VoteTipping::Strict, + min_community_weight_to_create_proposal: 5, + transactions_hold_up_time: 10, + voting_base_time: 5, + community_vote_tipping: VoteTipping::Strict, council_vote_threshold: VoteThreshold::YesVotePercentage(60), council_veto_vote_threshold: VoteThreshold::YesVotePercentage(50), + min_council_weight_to_create_proposal: 1, + council_vote_tipping: VoteTipping::Strict, + community_veto_vote_threshold: VoteThreshold::YesVotePercentage(40), + voting_cool_off_time: 0, + deposit_exempt_proposal_count: 0, } } @@ -1195,11 +1373,13 @@ mod test { fn test_max_size() { let mut proposal = create_test_proposal(); proposal.vote_type = VoteType::MultiChoice { + choice_type: MultiChoiceType::FullWeight, + min_voter_options: 1, max_voter_options: 1, max_winning_options: 1, }; - let size = proposal.try_to_vec().unwrap().len(); + let size = borsh::to_vec(&proposal).unwrap().len(); assert_eq!(proposal.get_max_size(), Some(size)); } @@ -1208,11 +1388,13 @@ mod test { fn test_multi_option_proposal_max_size() { let mut proposal = create_test_multi_option_proposal(); proposal.vote_type = VoteType::MultiChoice { + choice_type: MultiChoiceType::FullWeight, + min_voter_options: 1, max_voter_options: 3, max_winning_options: 3, }; - let size = proposal.try_to_vec().unwrap().len(); + let size = borsh::to_vec(&proposal).unwrap().len(); assert_eq!(proposal.get_max_size(), Some(size)); } @@ -1222,7 +1404,7 @@ mod test { governing_token_supply in Just(governing_token_supply), vote_count in 0..=governing_token_supply, ) -> (u64, u64) { - (vote_count as u64, governing_token_supply as u64) + (vote_count, governing_token_supply) } } @@ -1662,7 +1844,7 @@ mod test { // Assert assert_eq!(proposal.state,test_case.expected_finalized_state,"CASE: {:?}",test_case); assert_eq!( - Some(proposal.vote_end_time(&governance_config)), + Some(proposal.voting_max_time_end(&governance_config)), proposal.voting_completed_at ); @@ -1690,7 +1872,7 @@ mod test { no_votes_count in 0..=governing_token_supply, ) -> (u64, u64, u64, u8) { - (yes_votes_count as u64, no_votes_count as u64, governing_token_supply as u64,yes_vote_threshold as u8) + (yes_votes_count, no_votes_count, governing_token_supply, yes_vote_threshold as u8) } } @@ -1722,11 +1904,9 @@ mod test { let vote_tipping = VoteTipping::Strict; let max_voter_weight = proposal.get_max_voter_weight_from_mint_supply(&realm,&governing_token_mint,governing_token_supply,&vote_kind).unwrap(); - let vote_threshold = yes_vote_threshold_percentage.clone(); - // Act - proposal.try_tip_vote(max_voter_weight, &vote_tipping, current_timestamp,&vote_threshold,&vote_kind).unwrap(); + proposal.try_tip_vote(max_voter_weight, &vote_tipping, current_timestamp,&yes_vote_threshold_percentage,&vote_kind).unwrap(); // Assert let yes_vote_threshold_count = get_min_vote_threshold_weight(&yes_vote_threshold_percentage,governing_token_supply).unwrap(); @@ -1771,10 +1951,9 @@ mod test { let vote_kind = VoteKind::Electorate; let max_voter_weight = proposal.get_max_voter_weight_from_mint_supply(&realm,&governing_token_mint,governing_token_supply,&vote_kind).unwrap(); - let vote_threshold = yes_vote_threshold_percentage.clone(); // Act - proposal.finalize_vote(max_voter_weight, &governance_config,current_timestamp,&vote_threshold).unwrap(); + proposal.finalize_vote(max_voter_weight, &governance_config,current_timestamp, &yes_vote_threshold_percentage).unwrap(); // Assert let no_vote_weight = proposal.deny_vote_weight.unwrap(); @@ -1810,9 +1989,9 @@ mod test { let vote_tipping = VoteTipping::Strict; // reduce max vote weight to 100 - realm.config.community_mint_max_vote_weight_source = - MintMaxVoteWeightSource::SupplyFraction( - MintMaxVoteWeightSource::SUPPLY_FRACTION_BASE / 2, + realm.config.community_mint_max_voter_weight_source = + MintMaxVoterWeightSource::SupplyFraction( + MintMaxVoterWeightSource::SUPPLY_FRACTION_BASE / 2, ); let max_voter_weight = proposal @@ -1843,6 +2022,57 @@ mod test { assert_eq!(proposal.max_vote_weight, Some(100)); } + #[test] + fn test_try_tip_vote_with_reduced_absolute_community_mint_max_vote_weight() { + // Arrange + let mut proposal = create_test_proposal(); + + proposal.options[0].vote_weight = 60; + proposal.deny_vote_weight = Some(10); + + proposal.state = ProposalState::Voting; + + let current_timestamp = 15_i64; + + let community_token_supply = 200; + + let mut realm = create_test_realm(); + let governing_token_mint = proposal.governing_token_mint; + let vote_kind = VoteKind::Electorate; + let vote_tipping = VoteTipping::Strict; + + // set max vote weight to 100 + realm.config.community_mint_max_voter_weight_source = + MintMaxVoterWeightSource::Absolute(community_token_supply / 2); + + let max_voter_weight = proposal + .get_max_voter_weight_from_mint_supply( + &realm, + &governing_token_mint, + community_token_supply, + &vote_kind, + ) + .unwrap(); + + let vote_threshold = &VoteThreshold::YesVotePercentage(60); + let vote_kind = VoteKind::Electorate; + + // Act + proposal + .try_tip_vote( + max_voter_weight, + &vote_tipping, + current_timestamp, + vote_threshold, + &vote_kind, + ) + .unwrap(); + + // Assert + assert_eq!(proposal.state, ProposalState::Succeeded); + assert_eq!(proposal.max_vote_weight, Some(100)); + } + #[test] fn test_try_tip_vote_with_reduced_community_mint_max_vote_weight_and_vote_overflow() { // Arrange @@ -1863,9 +2093,9 @@ mod test { let vote_tipping = VoteTipping::Strict; // reduce max vote weight to 100 - realm.config.community_mint_max_vote_weight_source = - MintMaxVoteWeightSource::SupplyFraction( - MintMaxVoteWeightSource::SUPPLY_FRACTION_BASE / 2, + realm.config.community_mint_max_voter_weight_source = + MintMaxVoterWeightSource::SupplyFraction( + MintMaxVoterWeightSource::SUPPLY_FRACTION_BASE / 2, ); // vote above reduced supply @@ -1899,6 +2129,61 @@ mod test { assert_eq!(proposal.max_vote_weight, Some(130)); } + #[test] + fn test_try_tip_vote_with_reduced_absolute_mint_max_vote_weight_and_vote_overflow() { + // Arrange + let mut proposal = create_test_proposal(); + + // no vote weight + proposal.deny_vote_weight = Some(10); + + proposal.state = ProposalState::Voting; + + let current_timestamp = 15_i64; + + let community_token_supply = 200; + + let mut realm = create_test_realm(); + let governing_token_mint = proposal.governing_token_mint; + let vote_kind = VoteKind::Electorate; + let vote_tipping = VoteTipping::Strict; + + // reduce max vote weight to 100 + realm.config.community_mint_max_voter_weight_source = + MintMaxVoterWeightSource::Absolute(community_token_supply / 2); + + // vote above reduced supply + // Yes vote weight + proposal.options[0].vote_weight = 120; + + let max_voter_weight = proposal + .get_max_voter_weight_from_mint_supply( + &realm, + &governing_token_mint, + community_token_supply, + &vote_kind, + ) + .unwrap(); + + let vote_threshold = VoteThreshold::YesVotePercentage(60); + + // Act + proposal + .try_tip_vote( + max_voter_weight, + &vote_tipping, + current_timestamp, + &vote_threshold, + &vote_kind, + ) + .unwrap(); + + // Assert + assert_eq!(proposal.state, ProposalState::Succeeded); + assert_eq!(proposal.max_vote_weight, Some(130)); // Deny Vote 10 + + // Approve Vote 120 + } + #[test] fn test_try_tip_vote_for_council_vote_with_reduced_community_mint_max_vote_weight() { // Arrange @@ -1918,9 +2203,9 @@ mod test { let vote_kind = VoteKind::Electorate; let vote_tipping = VoteTipping::Strict; - realm.config.community_mint_max_vote_weight_source = - MintMaxVoteWeightSource::SupplyFraction( - MintMaxVoteWeightSource::SUPPLY_FRACTION_BASE / 2, + realm.config.community_mint_max_voter_weight_source = + MintMaxVoterWeightSource::SupplyFraction( + MintMaxVoterWeightSource::SUPPLY_FRACTION_BASE / 2, ); realm.config.council_mint = Some(proposal.governing_token_mint); @@ -1970,9 +2255,9 @@ mod test { let vote_kind = VoteKind::Electorate; // reduce max vote weight to 100 - realm.config.community_mint_max_vote_weight_source = - MintMaxVoteWeightSource::SupplyFraction( - MintMaxVoteWeightSource::SUPPLY_FRACTION_BASE / 2, + realm.config.community_mint_max_voter_weight_source = + MintMaxVoterWeightSource::SupplyFraction( + MintMaxVoterWeightSource::SUPPLY_FRACTION_BASE / 2, ); let max_voter_weight = proposal @@ -2021,9 +2306,9 @@ mod test { let vote_kind = VoteKind::Electorate; // reduce max vote weight to 100 - realm.config.community_mint_max_vote_weight_source = - MintMaxVoteWeightSource::SupplyFraction( - MintMaxVoteWeightSource::SUPPLY_FRACTION_BASE / 2, + realm.config.community_mint_max_voter_weight_source = + MintMaxVoterWeightSource::SupplyFraction( + MintMaxVoterWeightSource::SUPPLY_FRACTION_BASE / 2, ); // vote above reduced supply @@ -2063,7 +2348,7 @@ mod test { let governance_config = create_test_governance_config(); let current_timestamp = - proposal.voting_at.unwrap() + governance_config.max_voting_time as i64; + proposal.voting_at.unwrap() + governance_config.voting_base_time as i64; let realm = create_test_realm(); let governing_token_mint = proposal.governing_token_mint; @@ -2098,7 +2383,7 @@ mod test { let governance_config = create_test_governance_config(); let current_timestamp = - proposal.voting_at.unwrap() + governance_config.max_voting_time as i64 + 1; + proposal.voting_at.unwrap() + governance_config.voting_base_time as i64 + 1; let realm = create_test_realm(); let governing_token_mint = proposal.governing_token_mint; @@ -2130,11 +2415,13 @@ mod test { let governance_config = create_test_governance_config(); let current_timestamp = - proposal.voting_at.unwrap() + governance_config.max_voting_time as i64 + 1; + proposal.voting_at.unwrap() + governance_config.voting_base_time as i64 + 1; + + let vote = Vote::Approve(vec![]); // Act let err = proposal - .assert_can_cast_vote(&governance_config, current_timestamp) + .assert_can_cast_vote(&governance_config, &vote, current_timestamp) .err() .unwrap(); @@ -2150,10 +2437,99 @@ mod test { let governance_config = create_test_governance_config(); let current_timestamp = - proposal.voting_at.unwrap() + governance_config.max_voting_time as i64; + proposal.voting_at.unwrap() + governance_config.voting_base_time as i64; + + let vote = Vote::Approve(vec![]); + + // Act + let result = proposal.assert_can_cast_vote(&governance_config, &vote, current_timestamp); + + // Assert + assert_eq!(result, Ok(())); + } + + #[test] + pub fn test_assert_can_vote_approve_before_voting_cool_off_time() { + // Arrange + let mut proposal = create_test_proposal(); + proposal.state = ProposalState::Voting; + + let mut governance_config = create_test_governance_config(); + governance_config.voting_cool_off_time = 2; + + let current_timestamp = + proposal.voting_at.unwrap() + governance_config.voting_base_time as i64 - 1; + + let vote = Vote::Approve(vec![]); + + // Act + let result = proposal.assert_can_cast_vote(&governance_config, &vote, current_timestamp); + + // Assert + assert_eq!(result, Ok(())); + } + + #[test] + pub fn test_assert_cannot_vote_approve_within_voting_cool_off_time() { + // Arrange + let mut proposal = create_test_proposal(); + proposal.state = ProposalState::Voting; + + let mut governance_config = create_test_governance_config(); + governance_config.voting_cool_off_time = 2; + + let current_timestamp = + proposal.voting_at.unwrap() + governance_config.voting_base_time as i64 + 1; + + let vote = Vote::Approve(vec![]); + + // Act + let err = proposal + .assert_can_cast_vote(&governance_config, &vote, current_timestamp) + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::VoteNotAllowedInCoolOffTime.into()); + } + + #[test] + pub fn test_assert_can_vote_veto_within_voting_cool_off_time() { + // Arrange + let mut proposal = create_test_proposal(); + proposal.state = ProposalState::Voting; + + let mut governance_config = create_test_governance_config(); + governance_config.voting_cool_off_time = 2; + + let current_timestamp = + proposal.voting_at.unwrap() + governance_config.voting_base_time as i64 + 1; + + let vote = Vote::Veto; + + // Act + let result = proposal.assert_can_cast_vote(&governance_config, &vote, current_timestamp); + + // Assert + assert_eq!(result, Ok(())); + } + + #[test] + pub fn test_assert_can_vote_deny_within_voting_cool_off_time() { + // Arrange + let mut proposal = create_test_proposal(); + proposal.state = ProposalState::Voting; + + let mut governance_config = create_test_governance_config(); + governance_config.voting_cool_off_time = 1; + + let current_timestamp = + proposal.voting_at.unwrap() + governance_config.voting_base_time as i64 + 1; + + let vote = Vote::Deny; // Act - let result = proposal.assert_can_cast_vote(&governance_config, current_timestamp); + let result = proposal.assert_can_cast_vote(&governance_config, &vote, current_timestamp); // Assert assert_eq!(result, Ok(())); @@ -2172,7 +2548,7 @@ mod test { let result = proposal.assert_valid_vote(&vote); // Assert - assert_eq!(result, Err(GovernanceError::InvalidVote.into())); + assert_eq!(result, Err(GovernanceError::DenyVoteIsNotAllowed.into())); } #[test] @@ -2200,7 +2576,10 @@ mod test { let result = proposal.assert_valid_vote(&vote); // Assert - assert_eq!(result, Err(GovernanceError::InvalidVote.into())); + assert_eq!( + result, + Err(GovernanceError::InvalidNumberOfVoteChoices.into()) + ); } #[test] @@ -2222,7 +2601,10 @@ mod test { let result = proposal.assert_valid_vote(&vote); // Assert - assert_eq!(result, Err(GovernanceError::InvalidVote.into())); + assert_eq!( + result, + Err(GovernanceError::SingleChoiceOnlyIsAllowed.into()) + ); } #[test] @@ -2253,22 +2635,64 @@ mod test { let result = proposal.assert_valid_vote(&vote); // Assert - assert_eq!(result, Err(GovernanceError::InvalidVote.into())); + assert_eq!( + result, + Err(GovernanceError::SingleChoiceOnlyIsAllowed.into()) + ); } #[test] - pub fn test_assert_valid_vote_with_no_choices_for_multi_choice_error() { + pub fn test_assert_valid_multi_choice_full_weight_vote() { // Arrange let mut proposal = create_test_multi_option_proposal(); proposal.vote_type = VoteType::MultiChoice { - max_voter_options: 3, - max_winning_options: 3, + choice_type: MultiChoiceType::FullWeight, + min_voter_options: 1, + max_voter_options: 4, + max_winning_options: 4, }; - let choices = vec![ VoteChoice { rank: 0, - weight_percentage: 0, + weight_percentage: 100, + }, + VoteChoice { + rank: 0, + weight_percentage: 100, + }, + VoteChoice { + rank: 0, + weight_percentage: 100, + }, + ]; + + let vote = Vote::Approve(choices.clone()); + + // Ensure + assert_eq!(proposal.options.len(), choices.len()); + + // Act + let result = proposal.assert_valid_vote(&vote); + + // Assert + assert_eq!(result, Ok(())); + } + + #[test] + pub fn test_assert_valid_vote_with_no_choices_for_multi_choice_error() { + // Arrange + let mut proposal = create_test_multi_option_proposal(); + proposal.vote_type = VoteType::MultiChoice { + choice_type: MultiChoiceType::FullWeight, + min_voter_options: 1, + max_voter_options: 3, + max_winning_options: 3, + }; + + let choices = vec![ + VoteChoice { + rank: 0, + weight_percentage: 0, }, VoteChoice { rank: 0, @@ -2289,7 +2713,51 @@ mod test { let result = proposal.assert_valid_vote(&vote); // Assert - assert_eq!(result, Err(GovernanceError::InvalidVote.into())); + assert_eq!( + result, + Err(GovernanceError::AtLeastSingleChoiceIsRequired.into()) + ); + } + + #[test] + pub fn test_assert_valid_vote_with_choice_weight_not_100_percent_error() { + // Arrange + let mut proposal = create_test_multi_option_proposal(); + proposal.vote_type = VoteType::MultiChoice { + choice_type: MultiChoiceType::FullWeight, + min_voter_options: 1, + max_voter_options: 3, + max_winning_options: 3, + }; + + let choices = vec![ + VoteChoice { + rank: 0, + weight_percentage: 50, + }, + VoteChoice { + rank: 0, + weight_percentage: 50, + }, + VoteChoice { + rank: 0, + weight_percentage: 0, + }, + ]; + + let vote = Vote::Approve(choices.clone()); + + // Ensure + assert_eq!(proposal.options.len(), choices.len()); + + // Act + let result = proposal.assert_valid_vote(&vote); + + // Assert + assert_eq!( + result, + Err(GovernanceError::ChoiceWeightMustBe100Percent.into()) + ); } #[test] @@ -2297,6 +2765,8 @@ mod test { ) { // Arrange let vote_type = VoteType::MultiChoice { + choice_type: MultiChoiceType::FullWeight, + min_voter_options: 1, max_voter_options: 3, max_winning_options: 3, }; @@ -2307,13 +2777,18 @@ mod test { let result = assert_valid_proposal_options(&options, &vote_type); // Assert - assert_eq!(result, Err(GovernanceError::InvalidProposalOptions.into())); + assert_eq!( + result, + Err(GovernanceError::InvalidMultiChoiceProposalParameters.into()) + ); } #[test] pub fn test_assert_valid_proposal_options_with_no_options_for_multi_choice_vote_error() { // Arrange let vote_type = VoteType::MultiChoice { + choice_type: MultiChoiceType::FullWeight, + min_voter_options: 1, max_voter_options: 3, max_winning_options: 3, }; @@ -2345,6 +2820,8 @@ mod test { pub fn test_assert_valid_proposal_options_for_multi_choice_vote() { // Arrange let vote_type = VoteType::MultiChoice { + choice_type: MultiChoiceType::FullWeight, + min_voter_options: 1, max_voter_options: 3, max_winning_options: 3, }; @@ -2366,6 +2843,8 @@ mod test { pub fn test_assert_valid_proposal_options_for_multi_choice_vote_with_empty_option_error() { // Arrange let vote_type = VoteType::MultiChoice { + choice_type: MultiChoiceType::FullWeight, + min_voter_options: 1, max_voter_options: 3, max_winning_options: 3, }; @@ -2383,6 +2862,326 @@ mod test { assert_eq!(result, Err(GovernanceError::InvalidProposalOptions.into())); } + #[test] + pub fn test_assert_valid_vote_for_multi_weighted_choice() { + // Multi weighted choice may be weighted but sum of choices has to be 100% + // Arrange + let mut proposal = create_test_multi_option_proposal(); + proposal.vote_type = VoteType::MultiChoice { + choice_type: MultiChoiceType::Weighted, + min_voter_options: 1, + max_voter_options: 3, + max_winning_options: 3, + }; + + let choices = vec![ + VoteChoice { + rank: 0, + weight_percentage: 42, + }, + VoteChoice { + rank: 0, + weight_percentage: 42, + }, + VoteChoice { + rank: 0, + weight_percentage: 16, + }, + ]; + let vote = Vote::Approve(choices.clone()); + + // Ensure + assert_eq!(proposal.options.len(), choices.len()); + + // Act + let result = proposal.assert_valid_vote(&vote); + + // Assert + assert_eq!(result, Ok(())); + } + + #[test] + pub fn test_assert_valid_full_vote_for_multi_weighted_choice() { + // Multi weighted choice may be weighted to 100% and 0% rest + // Arrange + let mut proposal = create_test_multi_option_proposal(); + proposal.vote_type = VoteType::MultiChoice { + choice_type: MultiChoiceType::Weighted, + min_voter_options: 1, + max_voter_options: 3, + max_winning_options: 3, + }; + + let choices = vec![ + VoteChoice { + rank: 0, + weight_percentage: 0, + }, + VoteChoice { + rank: 0, + weight_percentage: 100, + }, + VoteChoice { + rank: 0, + weight_percentage: 0, + }, + ]; + let vote = Vote::Approve(choices.clone()); + + // Ensure + assert_eq!(proposal.options.len(), choices.len()); + + // Act + let result = proposal.assert_valid_vote(&vote); + + // Assert + assert_eq!(result, Ok(())); + } + + #[test] + pub fn test_assert_valid_vote_with_total_vote_weight_above_100_percent_for_multi_weighted_choice_error( + ) { + // Arrange + let mut proposal = create_test_multi_option_proposal(); + proposal.vote_type = VoteType::MultiChoice { + choice_type: MultiChoiceType::Weighted, + min_voter_options: 1, + max_voter_options: 2, + max_winning_options: 2, + }; + + let choices = vec![ + VoteChoice { + rank: 0, + weight_percentage: 34, + }, + VoteChoice { + rank: 0, + weight_percentage: 34, + }, + VoteChoice { + rank: 0, + weight_percentage: 34, + }, + ]; + let vote = Vote::Approve(choices.clone()); + + // Ensure + assert_eq!(proposal.options.len(), choices.len()); + + // Act + let result = proposal.assert_valid_vote(&vote); + + // Assert + assert_eq!( + result, + Err(GovernanceError::TotalVoteWeightMustBe100Percent.into()) + ); + } + + #[test] + pub fn test_assert_valid_vote_with_over_percentage_for_multi_weighted_choice_error() { + // Multi weighted choice does not permit vote with sum weight over 100% + // Arrange + let mut proposal = create_test_multi_option_proposal(); + proposal.vote_type = VoteType::MultiChoice { + choice_type: MultiChoiceType::Weighted, + min_voter_options: 1, + max_voter_options: 3, + max_winning_options: 3, + }; + + let choices = vec![ + VoteChoice { + rank: 0, + weight_percentage: 34, + }, + VoteChoice { + rank: 0, + weight_percentage: 34, + }, + VoteChoice { + rank: 0, + weight_percentage: 34, + }, + ]; + let vote = Vote::Approve(choices.clone()); + + // Ensure + assert_eq!(proposal.options.len(), choices.len()); + + // Act + let result = proposal.assert_valid_vote(&vote); + + // Assert + assert_eq!( + result, + Err(GovernanceError::TotalVoteWeightMustBe100Percent.into()) + ); + } + + #[test] + pub fn test_assert_valid_vote_with_overflow_weight_for_multi_weighted_choice_error() { + // Multi weighted choice does not permit vote with sum weight over 100% + // Arrange + let mut proposal = create_test_multi_option_proposal(); + proposal.vote_type = VoteType::MultiChoice { + choice_type: MultiChoiceType::Weighted, + min_voter_options: 1, + max_voter_options: 3, + max_winning_options: 3, + }; + + let choices = vec![ + VoteChoice { + rank: 0, + weight_percentage: 100, + }, + VoteChoice { + rank: 0, + weight_percentage: 100, + }, + VoteChoice { + rank: 0, + weight_percentage: 100, + }, + ]; + let vote = Vote::Approve(choices.clone()); + + // Ensure + assert_eq!(proposal.options.len(), choices.len()); + + // Act + let result = proposal.assert_valid_vote(&vote); + + // Assert + assert_eq!( + result, + Err(GovernanceError::TotalVoteWeightMustBe100Percent.into()) + ); + } + + #[test] + pub fn test_assert_valid_proposal_options_with_invalid_choice_number_for_multi_weighted_choice_vote_error( + ) { + // Arrange + let vote_type = VoteType::MultiChoice { + choice_type: MultiChoiceType::Weighted, + min_voter_options: 1, + max_voter_options: 3, + max_winning_options: 3, + }; + + let options = vec!["option 1".to_string(), "option 2".to_string()]; + + // Act + let result = assert_valid_proposal_options(&options, &vote_type); + + // Assert + assert_eq!( + result, + Err(GovernanceError::InvalidMultiChoiceProposalParameters.into()) + ); + } + + #[test] + pub fn test_assert_valid_proposal_options_with_no_options_for_multi_weighted_choice_vote_error() + { + // Arrange + let vote_type = VoteType::MultiChoice { + choice_type: MultiChoiceType::Weighted, + min_voter_options: 1, + max_voter_options: 3, + max_winning_options: 3, + }; + + let options = vec![]; + + // Act + let result = assert_valid_proposal_options(&options, &vote_type); + + // Assert + assert_eq!(result, Err(GovernanceError::InvalidProposalOptions.into())); + } + + #[test] + pub fn test_assert_valid_proposal_options_for_multi_weighted_choice_vote() { + // Arrange + let vote_type = VoteType::MultiChoice { + choice_type: MultiChoiceType::Weighted, + min_voter_options: 1, + max_voter_options: 3, + max_winning_options: 3, + }; + + let options = vec![ + "option 1".to_string(), + "option 2".to_string(), + "option 3".to_string(), + ]; + + // Act + let result = assert_valid_proposal_options(&options, &vote_type); + + // Assert + assert_eq!(result, Ok(())); + } + + #[test] + pub fn test_assert_valid_proposal_options_for_multi_weighted_choice_vote_with_empty_option_error( + ) { + // Arrange + let vote_type = VoteType::MultiChoice { + choice_type: MultiChoiceType::Weighted, + min_voter_options: 1, + max_voter_options: 3, + max_winning_options: 3, + }; + + let options = vec![ + "".to_string(), + "option 2".to_string(), + "option 3".to_string(), + ]; + + // Act + let result = assert_valid_proposal_options(&options, &vote_type); + + // Assert + assert_eq!(result, Err(GovernanceError::InvalidProposalOptions.into())); + } + + #[test] + pub fn test_assert_more_than_ten_proposal_options_for_multi_weighted_choice_error() { + // Arrange + let vote_type = VoteType::MultiChoice { + choice_type: MultiChoiceType::Weighted, + min_voter_options: 1, + max_voter_options: 3, + max_winning_options: 3, + }; + + let options = vec![ + "option 1".to_string(), + "option 2".to_string(), + "option 3".to_string(), + "option 4".to_string(), + "option 5".to_string(), + "option 6".to_string(), + "option 7".to_string(), + "option 8".to_string(), + "option 9".to_string(), + "option 10".to_string(), + "option 11".to_string(), + ]; + + // Act + let result = assert_valid_proposal_options(&options, &vote_type); + + // Assert + assert_eq!(result, Err(GovernanceError::InvalidProposalOptions.into())); + } + #[test] fn test_proposal_v1_to_v2_serialisation_roundtrip() { // Arrange @@ -2438,7 +3237,7 @@ mod test { let proposal_v2 = get_proposal_data(&program_id, &account_info).unwrap(); proposal_v2 - .serialize(&mut &mut **account_info.data.borrow_mut()) + .serialize(&mut account_info.data.borrow_mut()[..]) .unwrap(); // Assert diff --git a/governance/program/src/state/proposal_deposit.rs b/governance/program/src/state/proposal_deposit.rs new file mode 100644 index 00000000000..fa9c43bfed0 --- /dev/null +++ b/governance/program/src/state/proposal_deposit.rs @@ -0,0 +1,119 @@ +//! Proposal deposit account + +use { + crate::{error::GovernanceError, state::enums::GovernanceAccountType}, + borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, + solana_program::{ + account_info::AccountInfo, program_error::ProgramError, program_pack::IsInitialized, + pubkey::Pubkey, + }, + spl_governance_tools::account::{get_account_data, AccountMaxSize}, +}; + +/// Proposal deposit account +/// The account is used to limit spam of proposals +#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +pub struct ProposalDeposit { + /// Governance account type + pub account_type: GovernanceAccountType, + + /// The Proposal the deposit belongs to + pub proposal: Pubkey, + + /// The account which paid for the deposit + pub deposit_payer: Pubkey, + + /// Reserved + pub reserved: [u8; 64], +} + +impl AccountMaxSize for ProposalDeposit { + fn get_max_size(&self) -> Option { + Some(1 + 32 + 32 + 64) + } +} + +impl IsInitialized for ProposalDeposit { + fn is_initialized(&self) -> bool { + self.account_type == GovernanceAccountType::ProposalDeposit + } +} + +/// Returns ProposalDeposit PDA seeds +pub fn get_proposal_deposit_address_seeds<'a>( + proposal: &'a Pubkey, + proposal_deposit_payer: &'a Pubkey, +) -> [&'a [u8]; 3] { + [ + b"proposal-deposit", + proposal.as_ref(), + proposal_deposit_payer.as_ref(), + ] +} + +/// Returns ProposalDeposit PDA address +pub fn get_proposal_deposit_address( + program_id: &Pubkey, + proposal: &Pubkey, + proposal_deposit_payer: &Pubkey, +) -> Pubkey { + Pubkey::find_program_address( + &get_proposal_deposit_address_seeds(proposal, proposal_deposit_payer), + program_id, + ) + .0 +} + +/// Deserializes ProposalDeposit account and checks owner program and account +/// type +pub fn get_proposal_deposit_data( + program_id: &Pubkey, + proposal_deposit_info: &AccountInfo, +) -> Result { + get_account_data::(program_id, proposal_deposit_info) +} + +/// Deserializes ProposalDeposit account +/// 1) Checks owner program and account type +/// 2) Asserts it belongs to the given Proposal and deposit Payer +pub fn get_proposal_deposit_data_for_proposal_and_deposit_payer( + program_id: &Pubkey, + proposal_deposit_info: &AccountInfo, + proposal: &Pubkey, + proposal_deposit_payer: &Pubkey, +) -> Result { + let proposal_deposit_data = get_proposal_deposit_data(program_id, proposal_deposit_info)?; + + if proposal_deposit_data.proposal != *proposal { + return Err(GovernanceError::InvalidProposalForProposalDeposit.into()); + } + + if proposal_deposit_data.deposit_payer != *proposal_deposit_payer { + return Err(GovernanceError::InvalidDepositPayerForProposalDeposit.into()); + } + + Ok(proposal_deposit_data) +} + +#[cfg(test)] +mod test { + + use super::*; + + #[test] + fn test_max_size() { + // Arrange + let proposal_deposit_data = ProposalDeposit { + account_type: GovernanceAccountType::ProposalDeposit, + proposal: Pubkey::new_unique(), + deposit_payer: Pubkey::new_unique(), + reserved: [0; 64], + }; + + // Act + let size = borsh::to_vec(&proposal_deposit_data).unwrap().len(); + + // Assert + assert_eq!(proposal_deposit_data.get_max_size(), Some(size)); + } +} diff --git a/governance/program/src/state/proposal_transaction.rs b/governance/program/src/state/proposal_transaction.rs index dcba1f6ccb5..e95ba74e7ba 100644 --- a/governance/program/src/state/proposal_transaction.rs +++ b/governance/program/src/state/proposal_transaction.rs @@ -1,31 +1,30 @@ //! ProposalTransaction Account -use core::panic; - -use borsh::maybestd::io::Write; - -use crate::{ - error::GovernanceError, - state::{ - enums::{GovernanceAccountType, TransactionExecutionStatus}, - legacy::ProposalInstructionV1, +use { + crate::{ + error::GovernanceError, + state::{ + enums::{GovernanceAccountType, TransactionExecutionStatus}, + legacy::ProposalInstructionV1, + }, + PROGRAM_AUTHORITY_SEED, }, - PROGRAM_AUTHORITY_SEED, -}; -use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; -use solana_program::{ - account_info::AccountInfo, - borsh::try_from_slice_unchecked, - clock::UnixTimestamp, - instruction::{AccountMeta, Instruction}, - program_error::ProgramError, - program_pack::IsInitialized, - pubkey::Pubkey, + borsh::{io::Write, BorshDeserialize, BorshSchema, BorshSerialize}, + core::panic, + solana_program::{ + account_info::AccountInfo, + clock::UnixTimestamp, + instruction::{AccountMeta, Instruction}, + program_error::ProgramError, + program_pack::IsInitialized, + pubkey::Pubkey, + }, + spl_governance_tools::account::{get_account_data, get_account_type, AccountMaxSize}, }; -use spl_governance_tools::account::{get_account_data, AccountMaxSize}; -/// InstructionData wrapper. It can be removed once Borsh serialization for Instruction is supported in the SDK -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +/// InstructionData wrapper. It can be removed once Borsh serialization for +/// Instruction is supported in the SDK +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct InstructionData { /// Pubkey of the instruction processor that executes this instruction pub program_id: Pubkey, @@ -36,11 +35,12 @@ pub struct InstructionData { } /// Account metadata used to define Instructions -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct AccountMetaData { /// An account's public key pub pubkey: Pubkey, - /// True if an Instruction requires a Transaction signature matching `pubkey`. + /// True if an Instruction requires a Transaction signature matching + /// `pubkey`. pub is_signer: bool, /// True if the `pubkey` can be loaded as a read-write account. pub is_writable: bool, @@ -83,7 +83,7 @@ impl From<&InstructionData> for Instruction { } /// Account for an instruction to be executed for Proposal -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct ProposalTransactionV2 { /// Governance Account type pub account_type: GovernanceAccountType, @@ -97,13 +97,14 @@ pub struct ProposalTransactionV2 { /// Unique transaction index within it's parent Proposal pub transaction_index: u16, - /// Minimum waiting time in seconds for the instruction to be executed once proposal is voted on - pub hold_up_time: u32, + /// Previously hold_up_time in versions < V4 + pub legacy: u32, /// Instructions to execute - /// The instructions will be signed by Governance PDA the Proposal belongs to - // For example for ProgramGovernance the instruction to upgrade program will be signed by ProgramGovernance PDA - // All instructions will be executed within a single transaction + /// The instructions will be signed by Governance PDA the Proposal belongs + /// to + // For example for ProgramGovernance the instruction to upgrade program will be signed by + // ProgramGovernance PDA All instructions will be executed within a single transaction pub instructions: Vec, /// Executed at flag @@ -113,7 +114,7 @@ pub struct ProposalTransactionV2 { pub execution_status: TransactionExecutionStatus, /// Reserved space for versions v2 and onwards - /// Note: This space won't be available to v1 accounts until runtime supports resizing + /// Note: V1 accounts must be resized before using this space pub reserved_v2: [u8; 8], } @@ -137,17 +138,19 @@ impl IsInitialized for ProposalTransactionV2 { impl ProposalTransactionV2 { /// Serializes account into the target buffer - pub fn serialize(self, writer: &mut W) -> Result<(), ProgramError> { + pub fn serialize(self, writer: W) -> Result<(), ProgramError> { if self.account_type == GovernanceAccountType::ProposalTransactionV2 { - BorshSerialize::serialize(&self, writer)? + borsh::to_writer(writer, &self)? } else if self.account_type == GovernanceAccountType::ProposalInstructionV1 { if self.instructions.len() != 1 { panic!("Multiple instructions are not supported by ProposalInstructionV1") }; - // V1 account can't be resized and we have to translate it back to the original format + // V1 account can't be resized and we have to translate it back to the original + // format - // If reserved_v2 is used it must be individually asses for v1 backward compatibility impact + // If reserved_v2 is used it must be individually asses for v1 backward + // compatibility impact if self.reserved_v2 != [0; 8] { panic!("Extended data not supported by ProposalInstructionV1") } @@ -156,13 +159,13 @@ impl ProposalTransactionV2 { account_type: self.account_type, proposal: self.proposal, instruction_index: self.transaction_index, - hold_up_time: self.hold_up_time, + legacy: self.legacy, instruction: self.instructions[0].clone(), executed_at: self.executed_at, execution_status: self.execution_status, }; - BorshSerialize::serialize(&proposal_transaction_data_v1, writer)?; + borsh::to_writer(writer, &proposal_transaction_data_v1)? } Ok(()) @@ -207,7 +210,7 @@ pub fn get_proposal_transaction_data( proposal_transaction_info: &AccountInfo, ) -> Result { let account_type: GovernanceAccountType = - try_from_slice_unchecked(&proposal_transaction_info.data.borrow())?; + get_account_type(program_id, proposal_transaction_info)?; // If the account is V1 version then translate to V2 if account_type == GovernanceAccountType::ProposalInstructionV1 { @@ -219,7 +222,7 @@ pub fn get_proposal_transaction_data( proposal: proposal_transaction_data_v1.proposal, option_index: 0, // V1 has a single implied option at index 0 transaction_index: proposal_transaction_data_v1.instruction_index, - hold_up_time: proposal_transaction_data_v1.hold_up_time, + legacy: proposal_transaction_data_v1.legacy, instructions: vec![proposal_transaction_data_v1.instruction], executed_at: proposal_transaction_data_v1.executed_at, execution_status: proposal_transaction_data_v1.execution_status, @@ -230,7 +233,8 @@ pub fn get_proposal_transaction_data( get_account_data::(program_id, proposal_transaction_info) } -/// Deserializes and returns ProposalTransaction account and checks it belongs to the given Proposal +/// Deserializes and returns ProposalTransaction account and checks it belongs +/// to the given Proposal pub fn get_proposal_transaction_data_for_proposal( program_id: &Pubkey, proposal_transaction_info: &AccountInfo, @@ -249,11 +253,12 @@ pub fn get_proposal_transaction_data_for_proposal( #[cfg(test)] mod test { - use std::str::FromStr; - - use solana_program::{bpf_loader_upgradeable, clock::Epoch}; - - use super::*; + use { + super::*, + base64::{engine::general_purpose, Engine as _}, + solana_program::{bpf_loader_upgradeable, clock::Epoch}, + std::str::FromStr, + }; fn create_test_account_meta_data() -> AccountMetaData { AccountMetaData { @@ -281,7 +286,7 @@ mod test { proposal: Pubkey::new_unique(), option_index: 0, transaction_index: 1, - hold_up_time: 10, + legacy: 0, instructions: create_test_instruction_data(), executed_at: Some(100), execution_status: TransactionExecutionStatus::Success, @@ -292,7 +297,7 @@ mod test { #[test] fn test_account_meta_data_size() { let account_meta_data = create_test_account_meta_data(); - let size = account_meta_data.try_to_vec().unwrap().len(); + let size = borsh::to_vec(&account_meta_data).unwrap().len(); assert_eq!(34, size); } @@ -301,7 +306,7 @@ mod test { fn test_proposal_transaction_max_size() { // Arrange let proposal_transaction = create_test_proposal_transaction(); - let size = proposal_transaction.try_to_vec().unwrap().len(); + let size = borsh::to_vec(&proposal_transaction).unwrap().len(); // Act, Assert assert_eq!(proposal_transaction.get_max_size(), Some(size)); @@ -314,7 +319,7 @@ mod test { proposal_transaction.instructions[0].data = vec![]; proposal_transaction.instructions[0].accounts = vec![]; - let size = proposal_transaction.try_to_vec().unwrap().len(); + let size = borsh::to_vec(&proposal_transaction).unwrap().len(); // Act, Assert assert_eq!(proposal_transaction.get_max_size(), Some(size)); @@ -342,7 +347,7 @@ mod test { instruction_data.serialize(&mut instruction_bytes).unwrap(); // base64 encoded message is accepted as the input in the UI - let base64 = base64::encode(instruction_bytes.clone()); + let encoded = general_purpose::STANDARD_NO_PAD.encode(&instruction_bytes); // Assert let instruction = @@ -350,7 +355,7 @@ mod test { assert_eq!(upgrade_instruction, instruction); - assert_eq!(base64,"Aqj2kU6IobDiEBU+92OuKwDCuT0WwSTSwFN6EASAAAAHAAAAchkHXTU9jF+rKpILT6dzsVyNI9NsQy9cab+GGvdwNn0AAfh2HVruy2YibpgcQUmJf5att5YdPXSv1k2pRAKAfpSWAAFDVQuXWos2urmegSPblI813GlTm7CJ/8rv+9yzNE3yfwAB3Gw+apCyfrRNqJ6f1160Htkx+uYZT6FIILQ3WzNA4KwAAQan1RcZLFxRIYzJTD1K8X9Y2u4Im6H9ROPb2YoAAAAAAAAGp9UXGMd0yShWY5hpHV62i164o5tLbVxzVVshAAAAAAAA3Gw+apCyfrRNqJ6f1160Htkx+uYZT6FIILQ3WzNA4KwBAAQAAAADAAAA"); + assert_eq!(encoded,"Aqj2kU6IobDiEBU+92OuKwDCuT0WwSTSwFN6EASAAAAHAAAAchkHXTU9jF+rKpILT6dzsVyNI9NsQy9cab+GGvdwNn0AAfh2HVruy2YibpgcQUmJf5att5YdPXSv1k2pRAKAfpSWAAFDVQuXWos2urmegSPblI813GlTm7CJ/8rv+9yzNE3yfwAB3Gw+apCyfrRNqJ6f1160Htkx+uYZT6FIILQ3WzNA4KwAAQan1RcZLFxRIYzJTD1K8X9Y2u4Im6H9ROPb2YoAAAAAAAAGp9UXGMd0yShWY5hpHV62i164o5tLbVxzVVshAAAAAAAA3Gw+apCyfrRNqJ6f1160Htkx+uYZT6FIILQ3WzNA4KwBAAQAAAADAAAA"); } #[test] @@ -361,7 +366,7 @@ mod test { account_type: GovernanceAccountType::ProposalInstructionV1, proposal: Pubkey::new_unique(), instruction_index: 1, - hold_up_time: 120, + legacy: 0, instruction: create_test_instruction_data()[0].clone(), executed_at: Some(155), execution_status: TransactionExecutionStatus::Success, @@ -394,7 +399,7 @@ mod test { get_proposal_transaction_data(&program_id, &account_info).unwrap(); proposal_transaction_v2 - .serialize(&mut &mut **account_info.data.borrow_mut()) + .serialize(&mut account_info.data.borrow_mut()[..]) .unwrap(); // Assert diff --git a/governance/program/src/state/realm.rs b/governance/program/src/state/realm.rs index ff498d5dd50..70d08aa7959 100644 --- a/governance/program/src/state/realm.rs +++ b/governance/program/src/state/realm.rs @@ -1,34 +1,54 @@ //! Realm Account -use borsh::maybestd::io::Write; -use std::slice::Iter; - -use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - borsh::try_from_slice_unchecked, - program_error::ProgramError, - program_pack::IsInitialized, - pubkey::Pubkey, -}; -use spl_governance_addin_api::voter_weight::VoterWeightAction; -use spl_governance_tools::account::{ - assert_is_valid_account_of_types, get_account_data, AccountMaxSize, +use { + crate::{ + error::GovernanceError, + state::{ + enums::{GovernanceAccountType, MintMaxVoterWeightSource}, + legacy::RealmV1, + realm_config::{get_realm_config_data_for_realm, GoverningTokenType}, + token_owner_record::get_token_owner_record_data_for_realm, + vote_record::VoteKind, + }, + tools::structs::SetConfigItemActionType, + PROGRAM_AUTHORITY_SEED, + }, + borsh::{io::Write, BorshDeserialize, BorshSchema, BorshSerialize}, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + program_error::ProgramError, + program_pack::IsInitialized, + pubkey::Pubkey, + }, + spl_governance_addin_api::voter_weight::VoterWeightAction, + spl_governance_tools::account::{ + assert_is_valid_account_of_types, get_account_data, get_account_type, AccountMaxSize, + }, + std::slice::Iter, }; -use crate::{ - error::GovernanceError, - state::{ - enums::{GovernanceAccountType, MintMaxVoteWeightSource}, - legacy::RealmV1, - token_owner_record::get_token_owner_record_data_for_realm, - vote_record::VoteKind, +/// SetRealmConfigItem instruction arguments to set a single Realm config item +/// Note: In the current version only TokenOwnerRecordLockAuthority is supported +/// Eventually all Realm config items should be supported for single config item +/// change +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] +pub enum SetRealmConfigItemArgs { + /// Set TokenOwnerRecord lock authority + TokenOwnerRecordLockAuthority { + /// Action indicating whether to add or remove the lock authority + #[allow(dead_code)] + action: SetConfigItemActionType, + /// Mint of the governing token the lock authority is for + #[allow(dead_code)] + governing_token_mint: Pubkey, + /// Authority to change + #[allow(dead_code)] + authority: Pubkey, }, - PROGRAM_AUTHORITY_SEED, -}; +} /// Realm Config instruction args -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct RealmConfigArgs { /// Indicates whether council_mint should be used /// If yes then council_mint account must also be passed to the instruction @@ -38,27 +58,61 @@ pub struct RealmConfigArgs { pub min_community_weight_to_create_governance: u64, /// The source used for community mint max vote weight source - pub community_mint_max_vote_weight_source: MintMaxVoteWeightSource, + pub community_mint_max_voter_weight_source: MintMaxVoterWeightSource, + + /// Community token config args + pub community_token_config_args: GoverningTokenConfigArgs, + + /// Council token config args + pub council_token_config_args: GoverningTokenConfigArgs, +} + +/// Realm Config instruction args +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema, Default)] +pub struct GoverningTokenConfigArgs { + /// Indicates whether an external addin program should be used to provide + /// voters weights If yes then the voters weight program account must be + /// passed to the instruction + pub use_voter_weight_addin: bool, + + /// Indicates whether an external addin program should be used to provide + /// max voters weight for the token If yes then the max voter weight + /// program account must be passed to the instruction + pub use_max_voter_weight_addin: bool, + + /// Governing token type defines how the token is used for governance + pub token_type: GoverningTokenType, +} + +/// Realm Config instruction args with account parameters +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema, Default)] +pub struct GoverningTokenConfigAccountArgs { + /// Specifies an external plugin program which should be used to provide + /// voters weights for the given governing token + pub voter_weight_addin: Option, - /// Indicates whether an external addin program should be used to provide community voters weights - /// If yes then the voters weight program account must be passed to the instruction - pub use_community_voter_weight_addin: bool, + /// Specifies an external an external plugin program should be used to + /// provide max voters weight for the given governing token + pub max_voter_weight_addin: Option, - /// Indicates whether an external addin program should be used to provide max voters weight for the community mint - /// If yes then the max voter weight program account must be passed to the instruction - pub use_max_community_voter_weight_addin: bool, + /// Governing token type defines how the token is used for governance power + pub token_type: GoverningTokenType, } /// SetRealmAuthority instruction action -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum SetRealmAuthorityAction { /// Sets realm authority without any checks - /// Uncheck option allows to set the realm authority to non governance accounts + /// Uncheck option allows to set the realm authority to non governance + /// accounts SetUnchecked, - /// Sets realm authority and checks the new new authority is one of the realm's governances - // Note: This is not a security feature because governance creation is only gated with min_community_weight_to_create_governance - // The check is done to prevent scenarios where the authority could be accidentally set to a wrong or none existing account + /// Sets realm authority and checks the new new authority is one of the + /// realm's governances + // Note: This is not a security feature because governance creation is only + // gated with min_community_weight_to_create_governance. + // The check is done to prevent scenarios where the authority could be + // accidentally set to a wrong or none existing account. SetChecked, /// Removes realm authority @@ -66,13 +120,19 @@ pub enum SetRealmAuthorityAction { } /// Realm Config defining Realm parameters. -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct RealmConfig { - /// Indicates whether an external addin program should be used to provide voters weights for the community mint - pub use_community_voter_weight_addin: bool, - - /// Indicates whether an external addin program should be used to provide max voter weight for the community mint - pub use_max_community_voter_weight_addin: bool, + /// Legacy field introduced and used in V2 as + /// use_community_voter_weight_addin: bool If the field is going to be + /// reused in future version it must be taken under consideration + /// that for some Realms it might be already set to 1 + pub legacy1: u8, + + /// Legacy field introduced and used in V2 as + /// use_max_community_voter_weight_addin: bool If the field is going to + /// be reused in future version it must be taken under consideration + /// that for some Realms it might be already set to 1 + pub legacy2: u8, /// Reserved space for future versions pub reserved: [u8; 6], @@ -81,7 +141,7 @@ pub struct RealmConfig { pub min_community_weight_to_create_governance: u64, /// The source used for community mint max vote weight source - pub community_mint_max_vote_weight_source: MintMaxVoteWeightSource, + pub community_mint_max_voter_weight_source: MintMaxVoterWeightSource, /// Optional council mint pub council_mint: Option, @@ -89,7 +149,7 @@ pub struct RealmConfig { /// Governance Realm Account /// Account PDA seeds" ['governance', name] -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct RealmV2 { /// Governance account type pub account_type: GovernanceAccountType, @@ -103,18 +163,22 @@ pub struct RealmV2 { /// Reserved space for future versions pub reserved: [u8; 6], - /// The number of proposals in voting state in the Realm - pub voting_proposal_count: u16, + /// Legacy field not used since program V3 any longer + /// Note: If the field is going to be reused in future version it must be + /// taken under consideration that for some Realms it might be already + /// set to none zero because it was used as voting_proposal_count before + pub legacy1: u16, - /// Realm authority. The authority must sign transactions which update the realm config - /// The authority should be transferred to Realm Governance to make the Realm self governed through proposals + /// Realm authority. The authority must sign transactions which update the + /// realm config The authority should be transferred to Realm Governance + /// to make the Realm self governed through proposals pub authority: Option, /// Governance Realm name pub name: String, /// Reserved space for versions v2 and onwards - /// Note: This space won't be available to v1 accounts until runtime supports resizing + /// Note: V1 accounts must be resized before using this space pub reserved_v2: [u8; 128], } @@ -130,7 +194,8 @@ impl IsInitialized for RealmV2 { } } -/// Checks if the given account type is on of the Realm account types of any version +/// Checks if the given account type is on of the Realm account types of any +/// version pub fn is_realm_account_type(account_type: &GovernanceAccountType) -> bool { match account_type { GovernanceAccountType::RealmV1 | GovernanceAccountType::RealmV2 => true, @@ -154,7 +219,9 @@ pub fn is_realm_account_type(account_type: &GovernanceAccountType) -> bool { | GovernanceAccountType::ProposalTransactionV2 | GovernanceAccountType::VoteRecordV1 | GovernanceAccountType::VoteRecordV2 - | GovernanceAccountType::ProgramMetadata => false, + | GovernanceAccountType::ProgramMetadata + | GovernanceAccountType::ProposalDeposit + | GovernanceAccountType::RequiredSignatory => false, } } @@ -175,12 +242,16 @@ impl RealmV2 { Err(GovernanceError::InvalidGoverningTokenMint.into()) } - /// Returns the governing token mint which is used to vote on a proposal given the provided Vote kind and vote_governing_token_mint + /// Returns the governing token mint which is used to vote on a proposal + /// given the provided Vote kind and vote_governing_token_mint /// - /// Veto vote is cast on a proposal configured for the opposite voting population defined using governing_token_mint - /// Council can veto Community vote and Community can veto Council assuming the veto for the voting population is enabled + /// Veto vote is cast on a proposal configured for the opposite voting + /// population defined using governing_token_mint Council can veto + /// Community vote and Community can veto Council assuming the veto for the + /// voting population is enabled /// - /// For all votes other than Veto (Electorate votes) the vote_governing_token_mint is the same as Proposal governing_token_mint + /// For all votes other than Veto (Electorate votes) the + /// vote_governing_token_mint is the same as Proposal governing_token_mint pub fn get_proposal_governing_token_mint_for_vote( &self, vote_governing_token_mint: &Pubkey, @@ -189,14 +260,14 @@ impl RealmV2 { match vote_kind { VoteKind::Electorate => Ok(*vote_governing_token_mint), VoteKind::Veto => { - // When Community veto Council proposal then return council_token_mint as the Proposal governing_token_mint + // When Community veto Council proposal then return council_token_mint as the + // Proposal governing_token_mint if self.community_mint == *vote_governing_token_mint { - // Community Veto is not supported in the current version - return Err(GovernanceError::GoverningTokenMintNotAllowedToVote.into()); - //return Ok(self.config.council_mint.unwrap()); + return Ok(self.config.council_mint.unwrap()); } - // When Council veto Community proposal then return community_token_mint as the Proposal governing_token_mint + // When Council veto Community proposal then return community_token_mint as the + // Proposal governing_token_mint if self.config.council_mint == Some(*vote_governing_token_mint) { return Ok(self.community_mint); } @@ -206,7 +277,8 @@ impl RealmV2 { } } - /// Asserts the given governing token mint and holding accounts are valid for the realm + /// Asserts the given governing token mint and holding accounts are valid + /// for the realm pub fn assert_is_valid_governing_token_mint_and_holding( &self, program_id: &Pubkey, @@ -235,7 +307,8 @@ impl RealmV2 { create_authority_info: &AccountInfo, account_info_iter: &mut Iter, ) -> Result<(), ProgramError> { - // Check if create_authority_info is realm_authority and if yes then it must signed the transaction + // Check if create_authority_info is realm_authority and if yes then it must + // signed the transaction if self.authority == Some(*create_authority_info.key) { return if !create_authority_info.is_signer { Err(GovernanceError::RealmAuthorityMustSign.into()) @@ -244,20 +317,21 @@ impl RealmV2 { }; } - // If realm_authority hasn't signed then check if TokenOwner or Delegate signed and can crate governance + // If realm_authority hasn't signed then check if TokenOwner or Delegate signed + // and can crate governance let token_owner_record_data = get_token_owner_record_data_for_realm(program_id, token_owner_record_info, realm)?; token_owner_record_data.assert_token_owner_or_delegate_is_signer(create_authority_info)?; let realm_config_info = next_account_info(account_info_iter)?; + let realm_config_data = + get_realm_config_data_for_realm(program_id, realm_config_info, realm)?; let voter_weight = token_owner_record_data.resolve_voter_weight( - program_id, - realm_config_info, account_info_iter, - realm, self, + &realm_config_data, VoterWeightAction::CreateGovernance, realm, )?; @@ -268,13 +342,15 @@ impl RealmV2 { } /// Serializes account into the target buffer - pub fn serialize(self, writer: &mut W) -> Result<(), ProgramError> { + pub fn serialize(self, writer: W) -> Result<(), ProgramError> { if self.account_type == GovernanceAccountType::RealmV2 { - BorshSerialize::serialize(&self, writer)? + borsh::to_writer(writer, &self)? } else if self.account_type == GovernanceAccountType::RealmV1 { - // V1 account can't be resized and we have to translate it back to the original format + // V1 account can't be resized and we have to translate it back to the original + // format - // If reserved_v2 is used it must be individually asses for v1 backward compatibility impact + // If reserved_v2 is used it must be individually asses for v1 backward + // compatibility impact if self.reserved_v2 != [0; 128] { panic!("Extended data not supported by RealmV1") } @@ -284,19 +360,20 @@ impl RealmV2 { community_mint: self.community_mint, config: self.config, reserved: self.reserved, - voting_proposal_count: self.voting_proposal_count, + voting_proposal_count: 0, authority: self.authority, name: self.name, }; - BorshSerialize::serialize(&realm_data_v1, writer)?; + borsh::to_writer(writer, &realm_data_v1)? } Ok(()) } } -/// Checks whether the Realm account exists, is initialized and owned by Governance program +/// Checks whether the Realm account exists, is initialized and owned by +/// Governance program pub fn assert_is_valid_realm( program_id: &Pubkey, realm_info: &AccountInfo, @@ -309,7 +386,7 @@ pub fn get_realm_data( program_id: &Pubkey, realm_info: &AccountInfo, ) -> Result { - let account_type: GovernanceAccountType = try_from_slice_unchecked(&realm_info.data.borrow())?; + let account_type: GovernanceAccountType = get_account_type(program_id, realm_info)?; // If the account is V1 version then translate to V2 if account_type == GovernanceAccountType::RealmV1 { @@ -320,7 +397,7 @@ pub fn get_realm_data( community_mint: realm_data_v1.community_mint, config: realm_data_v1.config, reserved: realm_data_v1.reserved, - voting_proposal_count: realm_data_v1.voting_proposal_count, + legacy1: 0, authority: realm_data_v1.authority, name: realm_data_v1.name, // Add the extra reserved_v2 padding @@ -350,7 +427,8 @@ pub fn get_realm_data_for_authority( Ok(realm_data) } -/// Deserializes Ream account and asserts the given governing_token_mint is either Community or Council mint of the Realm +/// Deserializes Ream account and asserts the given governing_token_mint is +/// either Community or Council mint of the Realm pub fn get_realm_data_for_governing_token_mint( program_id: &Pubkey, realm_info: &AccountInfo, @@ -399,15 +477,19 @@ pub fn get_governing_token_holding_address( } /// Asserts given realm config args are correct -pub fn assert_valid_realm_config_args(config_args: &RealmConfigArgs) -> Result<(), ProgramError> { - match config_args.community_mint_max_vote_weight_source { - MintMaxVoteWeightSource::SupplyFraction(fraction) => { - if !(1..=MintMaxVoteWeightSource::SUPPLY_FRACTION_BASE).contains(&fraction) { - return Err(GovernanceError::InvalidMaxVoteWeightSupplyFraction.into()); +pub fn assert_valid_realm_config_args( + realm_config_args: &RealmConfigArgs, +) -> Result<(), ProgramError> { + match realm_config_args.community_mint_max_voter_weight_source { + MintMaxVoterWeightSource::SupplyFraction(fraction) => { + if !(1..=MintMaxVoterWeightSource::SUPPLY_FRACTION_BASE).contains(&fraction) { + return Err(GovernanceError::InvalidMaxVoterWeightSupplyFraction.into()); } } - MintMaxVoteWeightSource::Absolute(_) => { - return Err(GovernanceError::MintMaxVoteWeightSourceNotSupported.into()) + MintMaxVoterWeightSource::Absolute(value) => { + if value == 0 { + return Err(GovernanceError::InvalidMaxVoterWeightAbsoluteValue.into()); + } } } @@ -417,10 +499,10 @@ pub fn assert_valid_realm_config_args(config_args: &RealmConfigArgs) -> Result<( #[cfg(test)] mod test { - use crate::instruction::GovernanceInstruction; - use solana_program::borsh::try_from_slice_unchecked; - - use super::*; + use { + super::*, crate::instruction::GovernanceInstruction, + solana_program::borsh1::try_from_slice_unchecked, + }; #[test] fn test_max_size() { @@ -433,51 +515,55 @@ mod test { name: "test-realm".to_string(), config: RealmConfig { council_mint: Some(Pubkey::new_unique()), - use_community_voter_weight_addin: false, - use_max_community_voter_weight_addin: false, + legacy1: 0, + legacy2: 0, reserved: [0; 6], - community_mint_max_vote_weight_source: MintMaxVoteWeightSource::Absolute(100), + community_mint_max_voter_weight_source: MintMaxVoterWeightSource::Absolute(100), min_community_weight_to_create_governance: 10, }, - voting_proposal_count: 0, + legacy1: 0, reserved_v2: [0; 128], }; - let size = realm.try_to_vec().unwrap().len(); + let size = borsh::to_vec(&realm).unwrap().len(); assert_eq!(realm.get_max_size(), Some(size)); } /// Realm Config instruction args - #[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] + #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct RealmConfigArgsV1 { /// Indicates whether council_mint should be used - /// If yes then council_mint account must also be passed to the instruction + /// If yes then council_mint account must also be passed to the + /// instruction pub use_council_mint: bool, /// Min number of community tokens required to create a governance pub min_community_weight_to_create_governance: u64, /// The source used for community mint max vote weight source - pub community_mint_max_vote_weight_source: MintMaxVoteWeightSource, + pub community_mint_max_voter_weight_source: MintMaxVoterWeightSource, } /// Instructions supported by the Governance program - #[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] + #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum GovernanceInstructionV1 { - /// Creates Governance Realm account which aggregates governances for given Community Mint and optional Council Mint + /// Creates Governance Realm account which aggregates governances for + /// given Community Mint and optional Council Mint CreateRealm { #[allow(dead_code)] /// UTF-8 encoded Governance Realm name name: String, #[allow(dead_code)] - /// Realm config args + /// Realm config args config_args: RealmConfigArgsV1, }, - /// Deposits governing tokens (Community or Council) to Governance Realm and establishes your voter weight to be used for voting within the Realm + /// Deposits governing tokens (Community or Council) to Governance Realm + /// and establishes your voter weight to be used for voting within the + /// Realm DepositGoverningTokens { /// The amount to deposit into the realm #[allow(dead_code)] @@ -493,10 +579,10 @@ mod test { config_args: RealmConfigArgs { use_council_mint: true, min_community_weight_to_create_governance: 100, - community_mint_max_vote_weight_source: - MintMaxVoteWeightSource::FULL_SUPPLY_FRACTION, - use_community_voter_weight_addin: false, - use_max_community_voter_weight_addin: false, + community_mint_max_voter_weight_source: + MintMaxVoterWeightSource::FULL_SUPPLY_FRACTION, + community_token_config_args: GoverningTokenConfigArgs::default(), + council_token_config_args: GoverningTokenConfigArgs::default(), }, }; @@ -513,8 +599,8 @@ mod test { if let GovernanceInstructionV1::CreateRealm { name, config_args } = create_realm_ix_v1 { assert_eq!("test-realm", name); assert_eq!( - MintMaxVoteWeightSource::FULL_SUPPLY_FRACTION, - config_args.community_mint_max_vote_weight_source + MintMaxVoterWeightSource::FULL_SUPPLY_FRACTION, + config_args.community_mint_max_voter_weight_source ); } else { panic!("Can't deserialize v1 CreateRealm instruction from v2"); diff --git a/governance/program/src/state/realm_config.rs b/governance/program/src/state/realm_config.rs index 3b6bec58e47..564316c83ee 100644 --- a/governance/program/src/state/realm_config.rs +++ b/governance/program/src/state/realm_config.rs @@ -1,18 +1,100 @@ //! RealmConfig account - -use solana_program::{ - account_info::AccountInfo, program_error::ProgramError, program_pack::IsInitialized, - pubkey::Pubkey, +use { + crate::{ + error::GovernanceError, + state::{ + enums::GovernanceAccountType, + realm::{GoverningTokenConfigArgs, RealmConfigArgs, RealmV2}, + }, + tools::structs::Reserved110, + }, + borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + program_error::ProgramError, + program_pack::IsInitialized, + pubkey::Pubkey, + rent::Rent, + }, + spl_governance_tools::account::{ + create_and_serialize_account_signed, extend_account_size, get_account_data, AccountMaxSize, + }, + std::slice::Iter, }; -use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; -use spl_governance_tools::account::{get_account_data, AccountMaxSize}; +/// The type of the governing token defines: +/// 1) Who retains the authority over deposited tokens +/// 2) Which token instructions Deposit, Withdraw and Revoke (burn) are allowed +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] +pub enum GoverningTokenType { + /// Liquid token is a token which is fully liquid and the token owner + /// retains full authority over it. + /// Deposit - Yes + /// Withdraw - Yes + /// Revoke - No, Realm authority cannot revoke liquid tokens + Liquid, + + /// Membership token is a token controlled by Realm authority + /// Deposit - Yes, membership tokens can be deposited to gain governance + /// power. + /// The membership tokens are conventionally minted into the holding + /// account to keep them out of members possession. + /// Withdraw - No, after membership tokens are deposited they are no longer + /// transferable and can't be withdrawn. + /// Revoke - Yes, Realm authority can Revoke (burn) membership tokens. + Membership, + + /// Dormant token is a token which is only a placeholder and its deposits + /// are not accepted and not used for governance power within the Realm + /// + /// The Dormant token type is used when only a single voting population is + /// operational. For example a Multisig starter DAO uses Council only + /// and sets Community as Dormant to indicate its not utilized for any + /// governance power. Once the starter DAO decides to decentralise then + /// it can change the Community token to Liquid + /// + /// Note: When an external voter weight plugin which takes deposits of the + /// token is used then the type should be set to Dormant to make the + /// intention explicit + /// + /// Deposit - No, dormant tokens can't be deposited into the Realm + /// Withdraw - Yes, tokens can still be withdrawn from Realm to support + /// scenario where the config is changed while some tokens are still + /// deposited. + /// Revoke - No, Realm authority cannot revoke dormant tokens + Dormant, +} + +#[allow(clippy::derivable_impls)] +impl Default for GoverningTokenType { + fn default() -> Self { + GoverningTokenType::Liquid + } +} + +/// GoverningTokenConfig specifies configuration for Realm governing token +/// (Community or Council) +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema, Default)] +pub struct GoverningTokenConfig { + /// Plugin providing voter weights for the governing token + pub voter_weight_addin: Option, -use crate::{error::GovernanceError, state::enums::GovernanceAccountType}; + /// Plugin providing max voter weight for the governing token + pub max_voter_weight_addin: Option, + + /// Governing token type + pub token_type: GoverningTokenType, + + /// Reserved space for future versions + pub reserved: [u8; 4], + + /// Lock authorities for TokenOwnerRecords + pub lock_authorities: Vec, +} /// RealmConfig account /// The account is an optional extension to RealmConfig stored on Realm account -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct RealmConfigAccount { /// Governance account type pub account_type: GovernanceAccountType, @@ -20,28 +102,25 @@ pub struct RealmConfigAccount { /// The realm the config belong to pub realm: Pubkey, - /// Addin providing voter weights for community token - pub community_voter_weight_addin: Option, + /// Community token config + pub community_token_config: GoverningTokenConfig, - /// Addin providing max vote weight for community token - /// Note: This field is not implemented in the current version - pub max_community_voter_weight_addin: Option, - - /// Addin providing voter weights for council token - /// Note: This field is not implemented in the current version - pub council_voter_weight_addin: Option, - - /// Addin providing max vote weight for council token - /// Note: This field is not implemented in the current version - pub council_max_vote_weight_addin: Option, + /// Council token config + pub council_token_config: GoverningTokenConfig, /// Reserved - pub reserved: [u8; 128], + pub reserved: Reserved110, } impl AccountMaxSize for RealmConfigAccount { fn get_max_size(&self) -> Option { - Some(1 + 32 + 33 * 4 + 128) + Some( + 1 + 32 + + 75 * 2 + + 110 + + self.community_token_config.lock_authorities.len() * 32 + + self.council_token_config.lock_authorities.len() * 32, + ) } } @@ -51,6 +130,162 @@ impl IsInitialized for RealmConfigAccount { } } +impl RealmConfigAccount { + /// Returns GoverningTokenConfig for the given governing_token_mint + pub fn get_token_config( + &self, + realm_data: &RealmV2, + governing_token_mint: &Pubkey, + ) -> Result<&GoverningTokenConfig, ProgramError> { + let token_config = if *governing_token_mint == realm_data.community_mint { + &self.community_token_config + } else if Some(*governing_token_mint) == realm_data.config.council_mint { + &self.council_token_config + } else { + return Err(GovernanceError::InvalidGoverningTokenMint.into()); + }; + + Ok(token_config) + } + + /// Returns mutable GoverningTokenConfig for the given governing_token_mint + pub fn get_token_config_mut( + &mut self, + realm_data: &RealmV2, + governing_token_mint: &Pubkey, + ) -> Result<&mut GoverningTokenConfig, ProgramError> { + let token_config = if *governing_token_mint == realm_data.community_mint { + &mut self.community_token_config + } else if Some(*governing_token_mint) == realm_data.config.council_mint { + &mut self.council_token_config + } else { + return Err(GovernanceError::InvalidGoverningTokenMint.into()); + }; + + Ok(token_config) + } + + /// Asserts the given governing token can be revoked + pub fn assert_can_revoke_governing_token( + &self, + realm_data: &RealmV2, + governing_token_mint: &Pubkey, + ) -> Result<(), ProgramError> { + let governing_token_type = &self + .get_token_config(realm_data, governing_token_mint)? + .token_type; + + match governing_token_type { + GoverningTokenType::Membership => Ok(()), + GoverningTokenType::Liquid | GoverningTokenType::Dormant => { + Err(GovernanceError::CannotRevokeGoverningTokens.into()) + } + } + } + + /// Asserts the given governing token can be deposited + pub fn assert_can_deposit_governing_token( + &self, + realm_data: &RealmV2, + governing_token_mint: &Pubkey, + ) -> Result<(), ProgramError> { + let governing_token_type = &self + .get_token_config(realm_data, governing_token_mint)? + .token_type; + + match governing_token_type { + GoverningTokenType::Membership | GoverningTokenType::Liquid => Ok(()), + // Note: Preventing deposits of the Dormant type tokens is not a direct security concern + // It only makes the intention of not using deposited tokens as governance power + // stronger + GoverningTokenType::Dormant => Err(GovernanceError::CannotDepositDormantTokens.into()), + } + } + + /// Asserts the given governing token can be withdrawn + pub fn assert_can_withdraw_governing_token( + &self, + realm_data: &RealmV2, + governing_token_mint: &Pubkey, + ) -> Result<(), ProgramError> { + let governing_token_type = &self + .get_token_config(realm_data, governing_token_mint)? + .token_type; + + match governing_token_type { + GoverningTokenType::Dormant | GoverningTokenType::Liquid => Ok(()), + GoverningTokenType::Membership => { + Err(GovernanceError::CannotWithdrawMembershipTokens.into()) + } + } + } + + /// Asserts the given RealmConfigArgs represent a valid Realm configuration + /// change + pub fn assert_can_change_config( + &self, + realm_config_args: &RealmConfigArgs, + ) -> Result<(), ProgramError> { + // Existing community token type can't be changed to Membership because it would + // give the Realm authority the right to burn members tokens which should not be + // the case because the tokens belong to the members On the other had + // for the Council token it's acceptable and in fact desired change because + // council tokens denote membership which should be controlled by the + // Realm + if self.community_token_config.token_type != GoverningTokenType::Membership + && realm_config_args.community_token_config_args.token_type + == GoverningTokenType::Membership + { + return Err(GovernanceError::CannotChangeCommunityTokenTypeToMembership.into()); + } + + Ok(()) + } + + /// Serializes RealmConfigAccount and resizes it if required + /// If the account doesn't exist then it's created + pub fn serialize<'a>( + self, + program_id: &Pubkey, + realm_config_info: &AccountInfo<'a>, + payer_info: &AccountInfo<'a>, + system_info: &AccountInfo<'a>, + rent: &Rent, + ) -> Result<(), ProgramError> { + // Update or create RealmConfigAccount + if realm_config_info.data_is_empty() { + // For older Realm accounts (pre program V3) RealmConfigAccount might not exist + // yet and we have to create it + + create_and_serialize_account_signed::( + payer_info, + realm_config_info, + &self, + &get_realm_config_address_seeds(&self.realm), + program_id, + system_info, + rent, + 0, + )?; + } else { + let realm_config_max_size = self.get_max_size().unwrap(); + if realm_config_info.data_len() < realm_config_max_size { + extend_account_size( + realm_config_info, + payer_info, + realm_config_max_size, + rent, + system_info, + )?; + } + + borsh::to_writer(&mut realm_config_info.data.borrow_mut()[..], &self)?; + }; + + Ok(()) + } +} + /// Deserializes RealmConfig account and checks owner program pub fn get_realm_config_data( program_id: &Pubkey, @@ -59,17 +294,42 @@ pub fn get_realm_config_data( get_account_data::(program_id, realm_config_info) } -/// Deserializes RealmConfig account and checks the owner program and the Realm it belongs to +/// If the account exists then deserializes it into RealmConfigAccount struct +/// and checks the owner program and the Realm it belongs to If the account +/// doesn't exist then it checks its address is derived from the given owner +/// program and Realm and returns default RealmConfigAccount pub fn get_realm_config_data_for_realm( program_id: &Pubkey, realm_config_info: &AccountInfo, realm: &Pubkey, ) -> Result { - let realm_config_data = get_realm_config_data(program_id, realm_config_info)?; + let realm_config_data = if realm_config_info.data_is_empty() { + // If RealmConfigAccount doesn't exist yet then validate its PDA + // PDA validation is required because RealmConfigAccount might not exist for + // legacy Realms and then its absence is used as default + // RealmConfigAccount value with no plugins and Liquid governance tokens + let realm_config_address = get_realm_config_address(program_id, realm); - if realm_config_data.realm != *realm { - return Err(GovernanceError::InvalidRealmConfigForRealm.into()); - } + if realm_config_address != *realm_config_info.key { + return Err(GovernanceError::InvalidRealmConfigAddress.into()); + } + + RealmConfigAccount { + account_type: GovernanceAccountType::RealmConfig, + realm: *realm, + community_token_config: GoverningTokenConfig::default(), + council_token_config: GoverningTokenConfig::default(), + reserved: Reserved110::default(), + } + } else { + let realm_config_data = get_realm_config_data(program_id, realm_config_info)?; + + if realm_config_data.realm != *realm { + return Err(GovernanceError::InvalidRealmConfigForRealm.into()); + } + + realm_config_data + }; Ok(realm_config_data) } @@ -83,25 +343,100 @@ pub fn get_realm_config_address_seeds(realm: &Pubkey) -> [&[u8]; 2] { pub fn get_realm_config_address(program_id: &Pubkey, realm: &Pubkey) -> Pubkey { Pubkey::find_program_address(&get_realm_config_address_seeds(realm), program_id).0 } +/// Resolves GoverningTokenConfig from GoverningTokenConfigArgs and instruction +/// accounts +pub fn resolve_governing_token_config( + account_info_iter: &mut Iter, + governing_token_config_args: &GoverningTokenConfigArgs, + existing_governing_token_config: Option, +) -> Result { + let voter_weight_addin = if governing_token_config_args.use_voter_weight_addin { + let voter_weight_addin_info = next_account_info(account_info_iter)?; + Some(*voter_weight_addin_info.key) + } else { + None + }; + + let max_voter_weight_addin = if governing_token_config_args.use_max_voter_weight_addin { + let max_voter_weight_addin_info = next_account_info(account_info_iter)?; + Some(*max_voter_weight_addin_info.key) + } else { + None + }; + + let lock_authorities = + if let Some(existing_governing_token_config) = existing_governing_token_config { + existing_governing_token_config.lock_authorities + } else { + vec![] + }; + + Ok(GoverningTokenConfig { + voter_weight_addin, + max_voter_weight_addin, + token_type: governing_token_config_args.token_type.clone(), + reserved: [0; 4], + lock_authorities, + }) +} #[cfg(test)] mod test { - use super::*; - use crate::state::{enums::GovernanceAccountType, realm_config::RealmConfigAccount}; + use { + super::*, + crate::state::{enums::GovernanceAccountType, realm_config::RealmConfigAccount}, + }; #[test] fn test_max_size() { let realm_config = RealmConfigAccount { account_type: GovernanceAccountType::RealmV2, realm: Pubkey::new_unique(), - community_voter_weight_addin: Some(Pubkey::new_unique()), - max_community_voter_weight_addin: Some(Pubkey::new_unique()), - council_voter_weight_addin: Some(Pubkey::new_unique()), - council_max_vote_weight_addin: Some(Pubkey::new_unique()), - reserved: [0; 128], + community_token_config: GoverningTokenConfig { + voter_weight_addin: Some(Pubkey::new_unique()), + max_voter_weight_addin: Some(Pubkey::new_unique()), + token_type: GoverningTokenType::Liquid, + reserved: [0; 4], + lock_authorities: vec![], + }, + council_token_config: GoverningTokenConfig { + voter_weight_addin: Some(Pubkey::new_unique()), + max_voter_weight_addin: Some(Pubkey::new_unique()), + token_type: GoverningTokenType::Liquid, + reserved: [0; 4], + lock_authorities: vec![], + }, + reserved: Reserved110::default(), + }; + + let size = borsh::to_vec(&realm_config).unwrap().len(); + + assert_eq!(realm_config.get_max_size(), Some(size)); + } + + #[test] + fn test_max_size_with_lock_authorities() { + let realm_config = RealmConfigAccount { + account_type: GovernanceAccountType::RealmV2, + realm: Pubkey::new_unique(), + community_token_config: GoverningTokenConfig { + voter_weight_addin: Some(Pubkey::new_unique()), + max_voter_weight_addin: Some(Pubkey::new_unique()), + token_type: GoverningTokenType::Liquid, + reserved: [0; 4], + lock_authorities: vec![Pubkey::new_unique()], + }, + council_token_config: GoverningTokenConfig { + voter_weight_addin: Some(Pubkey::new_unique()), + max_voter_weight_addin: Some(Pubkey::new_unique()), + token_type: GoverningTokenType::Liquid, + reserved: [0; 4], + lock_authorities: vec![Pubkey::new_unique(), Pubkey::new_unique()], + }, + reserved: Reserved110::default(), }; - let size = realm_config.try_to_vec().unwrap().len(); + let size = borsh::to_vec(&realm_config).unwrap().len(); assert_eq!(realm_config.get_max_size(), Some(size)); } diff --git a/governance/program/src/state/required_signatory.rs b/governance/program/src/state/required_signatory.rs new file mode 100644 index 00000000000..9447b693818 --- /dev/null +++ b/governance/program/src/state/required_signatory.rs @@ -0,0 +1,76 @@ +//! RequiredSignatory account +use { + crate::{error::GovernanceError, state::enums::GovernanceAccountType}, + borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, + solana_program::{ + account_info::AccountInfo, program_error::ProgramError, program_pack::IsInitialized, + pubkey::Pubkey, + }, + spl_governance_tools::account::{get_account_data, AccountMaxSize}, +}; + +/// Required signatory +#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +pub struct RequiredSignatory { + /// Account type + pub account_type: GovernanceAccountType, + + /// Account version + pub account_version: u8, + + /// Governance this required signatory belongs to + pub governance: Pubkey, + + /// Address of required signatory + pub signatory: Pubkey, +} + +impl AccountMaxSize for RequiredSignatory {} + +impl IsInitialized for RequiredSignatory { + fn is_initialized(&self) -> bool { + self.account_type == GovernanceAccountType::RequiredSignatory + } +} + +/// Deserializes RequiredSignatory account, checks the owner program, and +/// asserts that required signatory belongs to the given governance +pub fn get_required_signatory_data_for_governance( + program_id: &Pubkey, + required_signatory_info: &AccountInfo, + governance: &Pubkey, +) -> Result { + let required_signatory_data = + get_account_data::(program_id, required_signatory_info)?; + + if required_signatory_data.governance != *governance { + return Err(GovernanceError::InvalidGovernanceForRequiredSignatory.into()); + } + + Ok(required_signatory_data) +} + +/// Returns RequiredSignatory PDA seeds +pub fn get_required_signatory_address_seeds<'a>( + governance: &'a Pubkey, + signatory: &'a Pubkey, +) -> [&'a [u8]; 3] { + [ + b"required-signatory".as_ref(), + governance.as_ref(), + signatory.as_ref(), + ] +} + +/// Returns RequiredSignatory PDA address +pub fn get_required_signatory_address<'a>( + program_id: &Pubkey, + governance: &'a Pubkey, + signatory: &'a Pubkey, +) -> Pubkey { + Pubkey::find_program_address( + &get_required_signatory_address_seeds(governance, signatory), + program_id, + ) + .0 +} diff --git a/governance/program/src/state/signatory_record.rs b/governance/program/src/state/signatory_record.rs index b97b200a358..c20a8abd4a1 100644 --- a/governance/program/src/state/signatory_record.rs +++ b/governance/program/src/state/signatory_record.rs @@ -1,21 +1,21 @@ //! Signatory Record -use borsh::maybestd::io::Write; - -use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; -use solana_program::borsh::try_from_slice_unchecked; -use solana_program::{ - account_info::AccountInfo, program_error::ProgramError, program_pack::IsInitialized, - pubkey::Pubkey, +use { + crate::{ + error::GovernanceError, + state::{enums::GovernanceAccountType, legacy::SignatoryRecordV1}, + PROGRAM_AUTHORITY_SEED, + }, + borsh::{io::Write, BorshDeserialize, BorshSchema, BorshSerialize}, + solana_program::{ + account_info::AccountInfo, program_error::ProgramError, program_pack::IsInitialized, + pubkey::Pubkey, + }, + spl_governance_tools::account::{get_account_data, get_account_type, AccountMaxSize}, }; -use spl_governance_tools::account::{get_account_data, AccountMaxSize}; - -use crate::{error::GovernanceError, PROGRAM_AUTHORITY_SEED}; - -use crate::state::{enums::GovernanceAccountType, legacy::SignatoryRecordV1}; /// Account PDA seeds: ['governance', proposal, signatory] -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct SignatoryRecordV2 { /// Governance account type pub account_type: GovernanceAccountType, @@ -30,7 +30,7 @@ pub struct SignatoryRecordV2 { pub signed_off: bool, /// Reserved space for versions v2 and onwards - /// Note: This space won't be available to v1 accounts until runtime supports resizing + /// Note: V1 accounts must be resized before using this space pub reserved_v2: [u8; 8], } @@ -66,13 +66,15 @@ impl SignatoryRecordV2 { } /// Serializes account into the target buffer - pub fn serialize(self, writer: &mut W) -> Result<(), ProgramError> { + pub fn serialize(self, writer: W) -> Result<(), ProgramError> { if self.account_type == GovernanceAccountType::SignatoryRecordV2 { - BorshSerialize::serialize(&self, writer)? + borsh::to_writer(writer, &self)? } else if self.account_type == GovernanceAccountType::SignatoryRecordV1 { - // V1 account can't be resized and we have to translate it back to the original format + // V1 account can't be resized and we have to translate it back to the original + // format - // If reserved_v2 is used it must be individually asses for v1 backward compatibility impact + // If reserved_v2 is used it must be individually asses for v1 backward + // compatibility impact if self.reserved_v2 != [0; 8] { panic!("Extended data not supported by SignatoryRecordV1") } @@ -84,7 +86,7 @@ impl SignatoryRecordV2 { signed_off: self.signed_off, }; - BorshSerialize::serialize(&signatory_record_data_v1, writer)?; + borsh::to_writer(writer, &signatory_record_data_v1)? } Ok(()) @@ -121,8 +123,7 @@ pub fn get_signatory_record_data( program_id: &Pubkey, signatory_record_info: &AccountInfo, ) -> Result { - let account_type: GovernanceAccountType = - try_from_slice_unchecked(&signatory_record_info.data.borrow())?; + let account_type: GovernanceAccountType = get_account_type(program_id, signatory_record_info)?; // If the account is V1 version then translate to V2 if account_type == GovernanceAccountType::SignatoryRecordV1 { diff --git a/governance/program/src/state/token_owner_record.rs b/governance/program/src/state/token_owner_record.rs index 1cd43af3e66..ee93e3ecaf0 100644 --- a/governance/program/src/state/token_owner_record.rs +++ b/governance/program/src/state/token_owner_record.rs @@ -1,34 +1,59 @@ //! Token Owner Record Account -use borsh::maybestd::io::Write; -use std::slice::Iter; - -use crate::{ - addins::voter_weight::{ - assert_is_valid_voter_weight, get_voter_weight_record_data_for_token_owner_record, +use { + crate::{ + addins::voter_weight::{ + assert_is_valid_voter_weight, get_voter_weight_record_data_for_token_owner_record, + }, + error::GovernanceError, + state::{ + enums::GovernanceAccountType, governance::GovernanceConfig, legacy::TokenOwnerRecordV1, + realm::RealmV2, realm_config::RealmConfigAccount, + }, + PROGRAM_AUTHORITY_SEED, }, - error::GovernanceError, - state::{ - enums::GovernanceAccountType, governance::GovernanceConfig, legacy::TokenOwnerRecordV1, - realm::RealmV2, realm_config::get_realm_config_data_for_realm, + borsh::{io::Write, BorshDeserialize, BorshSchema, BorshSerialize}, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + clock::UnixTimestamp, + program_error::ProgramError, + program_pack::IsInitialized, + pubkey::Pubkey, + rent::Rent, }, - PROGRAM_AUTHORITY_SEED, + spl_governance_addin_api::voter_weight::VoterWeightAction, + spl_governance_tools::account::{ + extend_account_size, get_account_data, get_account_type, AccountMaxSize, + }, + std::slice::Iter, }; -use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - borsh::try_from_slice_unchecked, - program_error::ProgramError, - program_pack::IsInitialized, - pubkey::Pubkey, -}; -use spl_governance_addin_api::voter_weight::VoterWeightAction; -use spl_governance_tools::account::{get_account_data, AccountMaxSize}; +/// A lock of TokenOwnerRecord which can be issued by external authorities to +/// prevent token withdrawals +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] +pub struct TokenOwnerRecordLock { + /// Custom lock id which can be used by the authority to issue + /// different locks + pub lock_id: u8, + + /// The authority issuing the lock + pub authority: Pubkey, + + /// The timestamp when the lock expires or None if it never expires + pub expiry: Option, +} + +impl TokenOwnerRecordLock { + /// Checks whether the lock is expired + pub fn is_expired(&self, current_unix_timestamp: UnixTimestamp) -> bool { + // If the expiry is None then the lock never expires + self.expiry.is_some() && Some(current_unix_timestamp) > self.expiry + } +} /// Governance Token Owner Record /// Account PDA seeds: ['governance', realm, token_mint, token_owner ] -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct TokenOwnerRecordV2 { /// Governance account type pub account_type: GovernanceAccountType, @@ -39,8 +64,8 @@ pub struct TokenOwnerRecordV2 { /// Governing Token Mint the TokenOwnerRecord holds deposit for pub governing_token_mint: Pubkey, - /// The owner (either single or multisig) of the deposited governing SPL Tokens - /// This is who can authorize a withdrawal of the tokens + /// The owner (either single or multisig) of the deposited governing SPL + /// Tokens This is who can authorize a withdrawal of the tokens pub governing_token_owner: Pubkey, /// The amount of governing tokens deposited into the Realm @@ -48,34 +73,74 @@ pub struct TokenOwnerRecordV2 { pub governing_token_deposit_amount: u64, /// The number of votes cast by TokenOwner but not relinquished yet - /// Every time a vote is cast this number is increased and it's always decreased when relinquishing a vote regardless of the vote state - pub unrelinquished_votes_count: u32, - - /// The total number of votes cast by the TokenOwner - /// If TokenOwner withdraws vote while voting is still in progress total_votes_count is decreased and the vote doesn't count towards the total - pub total_votes_count: u32, + /// Every time a vote is cast this number is increased and it's always + /// decreased when relinquishing a vote regardless of the vote state + pub unrelinquished_votes_count: u64, /// The number of outstanding proposals the TokenOwner currently owns /// The count is increased when TokenOwner creates a proposal - /// and decreased once it's either voted on (Succeeded or Defeated) or Cancelled - /// By default it's restricted to 1 outstanding Proposal per token owner + /// and decreased once it's either voted on (Succeeded or Defeated) or + /// Cancelled By default it's restricted to 1 outstanding Proposal per + /// token owner pub outstanding_proposal_count: u8, + /// Version of the account layout + /// Note: In future versions (>program V3) we should introduce + /// GovernanceAccountType::TokenOwnerRecord(version:u8) as a way to version + /// this account (and all other accounts too) It can't be done in + /// program V3 because it would require to fetch another + /// GovernanceAccountType by the UI and the RPC is already overloaded with + /// all the existing types The new account type and versioning scheme + /// can be introduced once we migrate UI to use indexer to fetch all the + /// accounts Once the new versioning scheme is introduced this field can + /// be migrated and removed + /// + /// The other issues which need to be addressed before we can cleanup the + /// account versioning code: + /// 1) Remove the specific governance accounts (ProgramGovernance, + /// TokenGovernance, MintGovernance) The only reason they exist is the UI + /// which can't handle the generic use case for those assets + /// 2) For account layout breaking changes all plugins would have to be + /// upgraded + /// 3) For account layout changes the Holaplex indexer would have to be + /// upgraded + /// 4) We should migrate the UI to use the indexer for fetching data and + /// stop using getProgramAccounts + /// 5) The UI would have to be upgraded to support account migration to the + /// latest version + /// 6) The client sdk is already messy because of the different + /// program/account versions and it should be cleaned up before we add + /// even more versions. + pub version: u8, + /// Reserved space for future versions - pub reserved: [u8; 7], + pub reserved: [u8; 6], - /// A single account that is allowed to operate governance with the deposited governing tokens - /// It can be delegated to by the governing_token_owner or current governance_delegate + /// A single account that is allowed to operate governance with the + /// deposited governing tokens It can be delegated to by the + /// governing_token_owner or current governance_delegate pub governance_delegate: Option, /// Reserved space for versions v2 and onwards - /// Note: This space won't be available to v1 accounts until runtime supports resizing - pub reserved_v2: [u8; 128], + /// Note: V1 accounts must be resized before using this space + pub reserved_v2: [u8; 124], + + /// A list of locks which can be issued by external authorities + /// to prevent token withdrawals + pub locks: Vec, } +/// The current version of TokenOwnerRecord account layout +/// Note: It's the version of the account layout and not the version of the +/// program or the account type +/// +/// program V1,V2 -> account layout version 0 +/// program V3 -> account layout version 1 +pub const TOKEN_OWNER_RECORD_LAYOUT_VERSION: u8 = 1; + impl AccountMaxSize for TokenOwnerRecordV2 { fn get_max_size(&self) -> Option { - Some(282) + Some(282 + self.locks.len() * 42) } } @@ -106,7 +171,8 @@ impl TokenOwnerRecordV2 { Err(GovernanceError::GoverningTokenOwnerOrDelegateMustSign.into()) } - /// Asserts TokenOwner has enough tokens to be allowed to create proposal and doesn't have any outstanding proposals + /// Asserts TokenOwner has enough tokens to be allowed to create proposal + /// and doesn't have any outstanding proposals pub fn assert_can_create_proposal( &self, realm_data: &RealmV2, @@ -122,12 +188,19 @@ impl TokenOwnerRecordV2 { return Err(GovernanceError::InvalidGoverningTokenMint.into()); }; + // If the weight threshold is set to u64::MAX then it indicates explicitly + // Disabled value which should prevent any possibility of using it + if min_weight_to_create_proposal == u64::MAX { + return Err(GovernanceError::VoterWeightThresholdDisabled.into()); + } + if voter_weight < min_weight_to_create_proposal { return Err(GovernanceError::NotEnoughTokensToCreateProposal.into()); } // The number of outstanding proposals is currently restricted to 10 - // If there is a need to change it in the future then it should be added to realm or governance config + // If there is a need to change it in the future then it should be added to + // realm or governance config if self.outstanding_proposal_count >= 10 { return Err(GovernanceError::TooManyOutstandingProposals.into()); } @@ -151,6 +224,12 @@ impl TokenOwnerRecordV2 { return Err(GovernanceError::InvalidGoverningTokenMint.into()); }; + // If the weight threshold is set to u64::MAX then it indicates explicitly + // Disabled value which should prevent any possibility of using it + if min_weight_to_create_governance == u64::MAX { + return Err(GovernanceError::VoterWeightThresholdDisabled.into()); + } + if voter_weight < min_weight_to_create_governance { return Err(GovernanceError::NotEnoughTokensToCreateGovernance.into()); } @@ -159,7 +238,10 @@ impl TokenOwnerRecordV2 { } /// Asserts TokenOwner can withdraw tokens from Realm - pub fn assert_can_withdraw_governing_tokens(&self) -> Result<(), ProgramError> { + pub fn assert_can_withdraw_governing_tokens( + &self, + current_unix_timestamp: UnixTimestamp, + ) -> Result<(), ProgramError> { if self.unrelinquished_votes_count > 0 { return Err( GovernanceError::AllVotesMustBeRelinquishedToWithdrawGoverningTokens.into(), @@ -172,42 +254,50 @@ impl TokenOwnerRecordV2 { ); } + if self + .locks + .iter() + .any(|lock| !lock.is_expired(current_unix_timestamp)) + { + return Err(GovernanceError::TokenOwnerRecordLocked.into()); + } + Ok(()) } /// Decreases outstanding_proposal_count pub fn decrease_outstanding_proposal_count(&mut self) { // Previous versions didn't use the count and it can be already 0 - // TODO: Remove this check once all outstanding proposals on mainnet are resolved + // TODO: Remove this check once all outstanding proposals on mainnet are + // resolved if self.outstanding_proposal_count != 0 { self.outstanding_proposal_count = self.outstanding_proposal_count.checked_sub(1).unwrap(); } } - /// Resolves voter's weight using either the amount deposited into the realm or weight provided by voter weight addin (if configured) + /// Resolves voter's weight using either the amount deposited into the realm + /// or weight provided by voter weight addin (if configured) #[allow(clippy::too_many_arguments)] pub fn resolve_voter_weight( &self, - program_id: &Pubkey, - realm_config_info: &AccountInfo, account_info_iter: &mut Iter, - realm: &Pubkey, realm_data: &RealmV2, + realm_config_data: &RealmConfigAccount, weight_action: VoterWeightAction, weight_action_target: &Pubkey, ) -> Result { - // if the realm uses addin for community voter weight then use the externally provided weight - if realm_data.config.use_community_voter_weight_addin - && realm_data.community_mint == self.governing_token_mint + // if the Realm is configured to use voter weight plugin for our + // governing_token_mint then use the externally provided voter_weight + // instead of governing_token_deposit_amount + if let Some(voter_weight_addin) = realm_config_data + .get_token_config(realm_data, &self.governing_token_mint)? + .voter_weight_addin { let voter_weight_record_info = next_account_info(account_info_iter)?; - let realm_config_data = - get_realm_config_data_for_realm(program_id, realm_config_info, realm)?; - let voter_weight_record_data = get_voter_weight_record_data_for_token_owner_record( - &realm_config_data.community_voter_weight_addin.unwrap(), + &voter_weight_addin, voter_weight_record_info, self, )?; @@ -224,15 +314,83 @@ impl TokenOwnerRecordV2 { } } + /// Removes expired locks + pub fn remove_expired_locks(&mut self, current_unix_timestamp: UnixTimestamp) { + self.locks + .retain(|lock| !lock.is_expired(current_unix_timestamp)); + } + + /// Removes a lock by its id and authority + pub fn remove_lock( + &mut self, + lock_id: u8, + lock_authority: &Pubkey, + ) -> Result<(), ProgramError> { + if let Some(lock_index) = self + .locks + .iter() + .position(|lock| lock.lock_id == lock_id && lock.authority == *lock_authority) + { + self.locks.remove(lock_index); + Ok(()) + } else { + Err(GovernanceError::TokenOwnerRecordLockNotFound.into()) + } + } + + /// Upserts (updates or inserts) a lock by its id and authority + pub fn upsert_lock(&mut self, lock: TokenOwnerRecordLock) { + if let Some(lock_index) = self.locks.iter().position(|existing_lock| { + existing_lock.lock_id == lock.lock_id && existing_lock.authority == lock.authority + }) { + self.locks[lock_index] = lock; + } else { + self.locks.push(lock); + } + } + + /// Serializes TokenOwnerRecord and resizes it if required + /// If the account is TokenOwnerRecordV1 and needs to be resized + /// then its type is changed to TokenOwnerRecordV2 to preserve the extra + /// data + pub fn serialize_with_resize<'a>( + mut self, + token_owner_record_info: &AccountInfo<'a>, + payer_info: &AccountInfo<'a>, + system_info: &AccountInfo<'a>, + rent: &Rent, + ) -> Result<(), ProgramError> { + let token_owner_record_data_max_size = self.get_max_size().unwrap(); + if token_owner_record_info.data_len() < token_owner_record_data_max_size { + extend_account_size( + token_owner_record_info, + payer_info, + token_owner_record_data_max_size, + rent, + system_info, + )?; + + // When the account is resized we have to change the type to V2 to preserve + // the extra data + if self.account_type == GovernanceAccountType::TokenOwnerRecordV1 { + self.account_type = GovernanceAccountType::TokenOwnerRecordV2; + } + } + + self.serialize(&mut token_owner_record_info.data.borrow_mut()[..]) + } + /// Serializes account into the target buffer - pub fn serialize(self, writer: &mut W) -> Result<(), ProgramError> { + pub fn serialize(self, writer: W) -> Result<(), ProgramError> { if self.account_type == GovernanceAccountType::TokenOwnerRecordV2 { - BorshSerialize::serialize(&self, writer)? + borsh::to_writer(writer, &self)? } else if self.account_type == GovernanceAccountType::TokenOwnerRecordV1 { - // V1 account can't be resized and we have to translate it back to the original format + // V1 account can't be resized and we have to translate it back to the original + // format - // If reserved_v2 is used it must be individually asses for v1 backward compatibility impact - if self.reserved_v2 != [0; 128] { + // If reserved_v2 is used it must be individually asses for v1 backward + // compatibility impact + if self.reserved_v2 != [0; 124] { panic!("Extended data not supported by TokenOwnerRecordV1") } @@ -243,13 +401,13 @@ impl TokenOwnerRecordV2 { governing_token_owner: self.governing_token_owner, governing_token_deposit_amount: self.governing_token_deposit_amount, unrelinquished_votes_count: self.unrelinquished_votes_count, - total_votes_count: self.total_votes_count, outstanding_proposal_count: self.outstanding_proposal_count, + version: self.version, reserved: self.reserved, governance_delegate: self.governance_delegate, }; - BorshSerialize::serialize(&token_owner_record_data_v1, writer)?; + borsh::to_writer(writer, &token_owner_record_data_v1)? } Ok(()) @@ -290,36 +448,52 @@ pub fn get_token_owner_record_data( token_owner_record_info: &AccountInfo, ) -> Result { let account_type: GovernanceAccountType = - try_from_slice_unchecked(&token_owner_record_info.data.borrow())?; + get_account_type(program_id, token_owner_record_info)?; // If the account is V1 version then translate to V2 - if account_type == GovernanceAccountType::TokenOwnerRecordV1 { + let mut token_owner_record_data = if account_type == GovernanceAccountType::TokenOwnerRecordV1 { let token_owner_record_data_v1 = get_account_data::(program_id, token_owner_record_info)?; - return Ok(TokenOwnerRecordV2 { + TokenOwnerRecordV2 { account_type, - realm: token_owner_record_data_v1.realm, governing_token_mint: token_owner_record_data_v1.governing_token_mint, governing_token_owner: token_owner_record_data_v1.governing_token_owner, governing_token_deposit_amount: token_owner_record_data_v1 .governing_token_deposit_amount, unrelinquished_votes_count: token_owner_record_data_v1.unrelinquished_votes_count, - total_votes_count: token_owner_record_data_v1.total_votes_count, outstanding_proposal_count: token_owner_record_data_v1.outstanding_proposal_count, + version: token_owner_record_data_v1.version, reserved: token_owner_record_data_v1.reserved, governance_delegate: token_owner_record_data_v1.governance_delegate, // Add the extra reserved_v2 padding - reserved_v2: [0; 128], - }); + reserved_v2: [0; 124], + locks: vec![], + } + } else { + get_account_data::(program_id, token_owner_record_info)? + }; + + // If the deserialized account uses the old account layout indicated by the + // version value then migrate the data to version 1 + if token_owner_record_data.version < 1 { + token_owner_record_data.version = 1; + + // In previous versions unrelinquished_votes_count was u32 followed by + // total_votes_count:u32 In program V3 unrelinquished_votes_count was + // changed to u64 by extending it into the space previously used by + // total_votes_count:u32 Since total_votes_count could have some value + // we have to zero the upper 4 bytes of unrelinquished_votes_count + token_owner_record_data.unrelinquished_votes_count &= u32::MAX as u64; } - get_account_data::(program_id, token_owner_record_info) + Ok(token_owner_record_data) } -/// Deserializes TokenOwnerRecord account and checks its PDA against the provided seeds +/// Deserializes TokenOwnerRecord account and checks its PDA against the +/// provided seeds pub fn get_token_owner_record_data_for_seeds( program_id: &Pubkey, token_owner_record_info: &AccountInfo, @@ -335,7 +509,8 @@ pub fn get_token_owner_record_data_for_seeds( get_token_owner_record_data(program_id, token_owner_record_info) } -/// Deserializes TokenOwnerRecord account and asserts it belongs to the given realm +/// Deserializes TokenOwnerRecord account and asserts it belongs to the given +/// realm pub fn get_token_owner_record_data_for_realm( program_id: &Pubkey, token_owner_record_info: &AccountInfo, @@ -350,7 +525,8 @@ pub fn get_token_owner_record_data_for_realm( Ok(token_owner_record_data) } -/// Deserializes TokenOwnerRecord account and asserts it belongs to the given realm and is for the given governing mint +/// Deserializes TokenOwnerRecord account and asserts it belongs to the given +/// realm and is for the given governing mint pub fn get_token_owner_record_data_for_realm_and_governing_mint( program_id: &Pubkey, token_owner_record_info: &AccountInfo, @@ -367,7 +543,8 @@ pub fn get_token_owner_record_data_for_realm_and_governing_mint( Ok(token_owner_record_data) } -/// Deserializes TokenOwnerRecord account and checks its address is the give proposal_owner +/// Deserializes TokenOwnerRecord account and checks its address is the give +/// proposal_owner pub fn get_token_owner_record_data_for_proposal_owner( program_id: &Pubkey, token_owner_record_info: &AccountInfo, @@ -382,28 +559,161 @@ pub fn get_token_owner_record_data_for_proposal_owner( #[cfg(test)] mod test { - use solana_program::borsh::get_packed_len; + use {super::*, solana_program::stake_history::Epoch}; - use super::*; + fn create_test_token_owner_record() -> TokenOwnerRecordV2 { + TokenOwnerRecordV2 { + account_type: GovernanceAccountType::TokenOwnerRecordV2, + realm: Pubkey::new_unique(), + governing_token_mint: Pubkey::new_unique(), + governing_token_owner: Pubkey::new_unique(), + governing_token_deposit_amount: 10, + governance_delegate: Some(Pubkey::new_unique()), + unrelinquished_votes_count: 1, + outstanding_proposal_count: 1, + version: 1, + reserved: [0; 6], + reserved_v2: [0; 124], + locks: vec![], + } + } + + fn create_test_program_v1_token_owner_record() -> TokenOwnerRecordV1 { + TokenOwnerRecordV1 { + account_type: GovernanceAccountType::TokenOwnerRecordV1, + realm: Pubkey::new_unique(), + governing_token_mint: Pubkey::new_unique(), + governing_token_owner: Pubkey::new_unique(), + governing_token_deposit_amount: 10, + governance_delegate: Some(Pubkey::new_unique()), + unrelinquished_votes_count: 1, + outstanding_proposal_count: 1, + version: 0, + reserved: [0; 6], + } + } #[test] fn test_max_size() { - let token_owner_record = TokenOwnerRecordV2 { + // Arrange + let token_owner_record = create_test_token_owner_record(); + + // Act + let size = borsh::to_vec(&token_owner_record).unwrap().len(); + + // Assert + assert_eq!(token_owner_record.get_max_size(), Some(size)); + } + + #[test] + fn test_max_size_with_locks() { + // Arrange + let mut token_owner_record = create_test_token_owner_record(); + token_owner_record.locks.push(TokenOwnerRecordLock { + lock_id: 1, + authority: Pubkey::new_unique(), + expiry: Some(10), + }); + token_owner_record.locks.push(TokenOwnerRecordLock { + lock_id: 1, + authority: Pubkey::new_unique(), + expiry: Some(10), + }); + + // Act + let size = borsh::to_vec(&token_owner_record).unwrap().len(); + + // Assert + assert_eq!(token_owner_record.get_max_size(), Some(size)); + } + + #[test] + fn test_program_v1_token_owner_record_size() { + // Arrange + let governance = create_test_program_v1_token_owner_record(); + + // Act + let size = borsh::to_vec(&governance).unwrap().len(); + + // Assert + assert_eq!(154, size); + } + + /// Legacy TokenOwnerRecord for program V1 and V2 accounts with + /// outstanding_proposal_count and without version + #[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] + pub struct LegacyTokenOwnerRecord { + pub account_type: GovernanceAccountType, + + pub realm: Pubkey, + + pub governing_token_mint: Pubkey, + + pub governing_token_owner: Pubkey, + + pub governing_token_deposit_amount: u64, + + /// Legacy u32 field. Changed to u64 in program V3 + pub unrelinquished_votes_count: u32, + + /// Legacy field. Removed in program V3 + pub total_votes_count: u32, + + pub outstanding_proposal_count: u8, + + pub reserved: [u8; 7], + + pub governance_delegate: Option, + + pub reserved_v2: [u8; 128], + } + + #[test] + fn test_migrate_token_owner_record_from_legacy_data_to_program_v3() { + // Arrange + let legacy_token_owner_record = LegacyTokenOwnerRecord { account_type: GovernanceAccountType::TokenOwnerRecordV2, realm: Pubkey::new_unique(), governing_token_mint: Pubkey::new_unique(), governing_token_owner: Pubkey::new_unique(), governing_token_deposit_amount: 10, - governance_delegate: Some(Pubkey::new_unique()), - unrelinquished_votes_count: 1, - total_votes_count: 1, + unrelinquished_votes_count: 10, + // Set total_votes_count which should be trimmed in program V3 version + total_votes_count: 100, outstanding_proposal_count: 1, reserved: [0; 7], + governance_delegate: Some(Pubkey::new_unique()), reserved_v2: [0; 128], }; - let size = get_packed_len::(); - - assert_eq!(token_owner_record.get_max_size(), Some(size)); + let mut legacy_data = vec![]; + borsh::to_writer(&mut legacy_data, &legacy_token_owner_record).unwrap(); + + let program_id = Pubkey::new_unique(); + + let info_key = Pubkey::new_unique(); + let mut lamports = 10u64; + + let legacy_account_info = AccountInfo::new( + &info_key, + false, + false, + &mut lamports, + &mut legacy_data[..], + &program_id, + false, + Epoch::default(), + ); + + // Act + let token_owner_record_program_v3 = + get_token_owner_record_data(&program_id, &legacy_account_info).unwrap(); + + // Assert + assert_eq!(token_owner_record_program_v3.unrelinquished_votes_count, 10); + assert_eq!( + token_owner_record_program_v3.version, + TOKEN_OWNER_RECORD_LAYOUT_VERSION + ); } } diff --git a/governance/program/src/state/vote_record.rs b/governance/program/src/state/vote_record.rs index c9e8b99a2a4..8606ba02075 100644 --- a/governance/program/src/state/vote_record.rs +++ b/governance/program/src/state/vote_record.rs @@ -1,34 +1,34 @@ //! Proposal Vote Record Account -use borsh::maybestd::io::Write; - -use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; -use solana_program::account_info::AccountInfo; -use solana_program::borsh::try_from_slice_unchecked; - -use solana_program::program_error::ProgramError; -use solana_program::{program_pack::IsInitialized, pubkey::Pubkey}; -use spl_governance_tools::account::{get_account_data, AccountMaxSize}; - -use crate::error::GovernanceError; - -use crate::PROGRAM_AUTHORITY_SEED; - -use crate::state::{ - enums::GovernanceAccountType, - legacy::{VoteRecordV1, VoteWeightV1}, - proposal::ProposalV2, - realm::RealmV2, - token_owner_record::TokenOwnerRecordV2, +use { + crate::{ + error::GovernanceError, + state::{ + enums::GovernanceAccountType, + legacy::{VoteRecordV1, VoteWeightV1}, + proposal::ProposalV2, + realm::RealmV2, + token_owner_record::TokenOwnerRecordV2, + }, + PROGRAM_AUTHORITY_SEED, + }, + borsh::{io::Write, BorshDeserialize, BorshSchema, BorshSerialize}, + solana_program::{ + account_info::AccountInfo, program_error::ProgramError, program_pack::IsInitialized, + pubkey::Pubkey, + }, + spl_governance_tools::account::{get_account_data, get_account_type, AccountMaxSize}, }; /// Voter choice for a proposal option -/// In the current version only 1) Single choice and 2) Multiple choices proposals are supported -/// In the future versions we can add support for 1) Quadratic voting, 2) Ranked choice voting and 3) Weighted voting -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +/// In the current version only 1) Single choice, 2) Multiple choices proposals +/// and 3) Weighted voting are supported. +/// In the future versions we can add support for 1) Quadratic voting and +/// 2) Ranked choice voting +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct VoteChoice { /// The rank given to the choice by voter - /// Note: The filed is not used in the current version + /// Note: The field is not used in the current version pub rank: u8, /// The voter's weight percentage given by the voter to the choice @@ -39,15 +39,22 @@ impl VoteChoice { /// Returns the choice weight given the voter's weight pub fn get_choice_weight(&self, voter_weight: u64) -> Result { Ok(match self.weight_percentage { + // Avoid any rounding errors for full weight 100 => voter_weight, - 0 => 0, + // Note: The total weight for all choices might not equal voter_weight due to rounding + // errors + 0..=99 => (voter_weight as u128) + .checked_mul(self.weight_percentage as u128) + .unwrap() + .checked_div(100) + .unwrap() as u64, _ => return Err(GovernanceError::InvalidVoteChoiceWeightPercentage.into()), }) } } /// User's vote -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum Vote { /// Vote approving choices Approve(Vec), @@ -64,13 +71,15 @@ pub enum Vote { } /// VoteKind defines the type of the vote being cast -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub enum VoteKind { - /// Electorate vote is cast by the voting population identified by governing_token_mint - /// Approve, Deny and Abstain votes are Electorate votes + /// Electorate vote is cast by the voting population identified by + /// governing_token_mint Approve, Deny and Abstain votes are Electorate + /// votes Electorate, - /// Vote cast by the opposite voting population to the Electorate identified by governing_token_mint + /// Vote cast by the opposite voting population to the Electorate identified + /// by governing_token_mint Veto, } @@ -83,7 +92,7 @@ pub fn get_vote_kind(vote: &Vote) -> VoteKind { } /// Proposal VoteRecord -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] pub struct VoteRecordV2 { /// Governance account type pub account_type: GovernanceAccountType, @@ -92,7 +101,8 @@ pub struct VoteRecordV2 { pub proposal: Pubkey, /// The user who casted this vote - /// This is the Governing Token Owner who deposited governing tokens into the Realm + /// This is the Governing Token Owner who deposited governing tokens into + /// the Realm pub governing_token_owner: Pubkey, /// Indicates whether the vote was relinquished by voter @@ -105,7 +115,7 @@ pub struct VoteRecordV2 { pub vote: Vote, /// Reserved space for versions v2 and onwards - /// Note: This space won't be available to v1 accounts until runtime supports resizing + /// Note: V1 accounts must be resized before using this space pub reserved_v2: [u8; 8], } @@ -127,13 +137,15 @@ impl VoteRecordV2 { } /// Serializes account into the target buffer - pub fn serialize(self, writer: &mut W) -> Result<(), ProgramError> { + pub fn serialize(self, writer: W) -> Result<(), ProgramError> { if self.account_type == GovernanceAccountType::VoteRecordV2 { - BorshSerialize::serialize(&self, writer)? + borsh::to_writer(writer, &self)? } else if self.account_type == GovernanceAccountType::VoteRecordV1 { - // V1 account can't be resized and we have to translate it back to the original format + // V1 account can't be resized and we have to translate it back to the original + // format - // If reserved_v2 is used it must be individually asses for v1 backward compatibility impact + // If reserved_v2 is used it must be individually asses for v1 backward + // compatibility impact if self.reserved_v2 != [0; 8] { panic!("Extended data not supported by VoteRecordV1") } @@ -154,7 +166,7 @@ impl VoteRecordV2 { vote_weight, }; - BorshSerialize::serialize(&vote_record_data_v1, writer)?; + borsh::to_writer(writer, &vote_record_data_v1)? } Ok(()) @@ -166,8 +178,7 @@ pub fn get_vote_record_data( program_id: &Pubkey, vote_record_info: &AccountInfo, ) -> Result { - let account_type: GovernanceAccountType = - try_from_slice_unchecked(&vote_record_info.data.borrow())?; + let account_type: GovernanceAccountType = get_account_type(program_id, vote_record_info)?; // If the account is V1 version then translate to V2 if account_type == GovernanceAccountType::VoteRecordV1 { @@ -198,7 +209,8 @@ pub fn get_vote_record_data( get_account_data::(program_id, vote_record_info) } -/// Deserializes VoteRecord and checks it belongs to the provided Proposal and TokenOwnerRecord +/// Deserializes VoteRecord and checks it belongs to the provided Proposal and +/// TokenOwnerRecord pub fn get_vote_record_data_for_proposal_and_token_owner_record( program_id: &Pubkey, vote_record_info: &AccountInfo, @@ -217,9 +229,11 @@ pub fn get_vote_record_data_for_proposal_and_token_owner_record( return Err(GovernanceError::InvalidGoverningTokenOwnerForVoteRecord.into()); } - // Assert governing_token_mint between Proposal and TokenOwnerRecord match for the deserialized VoteRecord - // For Approve, Deny and Abstain votes Proposal.governing_token_mint must equal TokenOwnerRecord.governing_token_mint - // For Veto vote it must be the governing_token_mint of the opposite voting population + // Assert governing_token_mint between Proposal and TokenOwnerRecord match for + // the deserialized VoteRecord For Approve, Deny and Abstain votes + // Proposal.governing_token_mint must equal + // TokenOwnerRecord.governing_token_mint For Veto vote it must be the + // governing_token_mint of the opposite voting population let proposal_governing_token_mint = realm_data.get_proposal_governing_token_mint_for_vote( &token_owner_record_data.governing_token_mint, &get_vote_kind(&vote_record_data.vote), @@ -260,10 +274,7 @@ pub fn get_vote_record_address<'a>( #[cfg(test)] mod test { - use borsh::BorshSerialize; - use solana_program::clock::Epoch; - - use super::*; + use {super::*, solana_program::clock::Epoch}; #[test] fn test_vote_record_v1_to_v2_serialisation_roundtrip() { @@ -278,7 +289,7 @@ mod test { }; let mut account_data = vec![]; - vote_record_v1_source.serialize(&mut account_data).unwrap(); + borsh::to_writer(&mut account_data, &vote_record_v1_source).unwrap(); let program_id = Pubkey::new_unique(); @@ -299,9 +310,8 @@ mod test { // Act let vote_record_v2 = get_vote_record_data(&program_id, &account_info).unwrap(); - vote_record_v2 - .serialize(&mut &mut **account_info.data.borrow_mut()) + .serialize(&mut account_info.data.borrow_mut()[..]) .unwrap(); // Assert @@ -311,4 +321,85 @@ mod test { assert_eq!(vote_record_v1_source, vote_record_v1_target) } + + #[test] + fn test_get_choice_weight_with_invalid_weight_percentage_error() { + // Arrange + let vote_choice = VoteChoice { + rank: 0, + weight_percentage: 127, + }; + + // Act + let result = vote_choice.get_choice_weight(100); + + // Assert + assert_eq!( + Err(GovernanceError::InvalidVoteChoiceWeightPercentage.into()), + result + ); + } + + #[test] + fn test_get_choice_weight() { + // Arrange + let vote_choice = VoteChoice { + rank: 0, + weight_percentage: 100, + }; + + // Act + let result = vote_choice.get_choice_weight(100); + + // Assert + assert_eq!(Ok(100_u64), result); + + // Arrange + let vote_choice = VoteChoice { + rank: 0, + weight_percentage: 0, + }; + + // Act + let result = vote_choice.get_choice_weight(100); + + // Assert + assert_eq!(Ok(0_u64), result); + + // Arrange + let vote_choice = VoteChoice { + rank: 0, + weight_percentage: 33, + }; + + // Act + let result = vote_choice.get_choice_weight(100); + + // Assert + assert_eq!(Ok(33_u64), result); + + // Arrange + let vote_choice = VoteChoice { + rank: 0, + weight_percentage: 34, + }; + + // Act + let result = vote_choice.get_choice_weight(100); + + // Assert + assert_eq!(Ok(34_u64), result); + + // Arrange + let vote_choice = VoteChoice { + rank: 0, + weight_percentage: 50, + }; + + // Act + let result = vote_choice.get_choice_weight(u64::MAX); + + // Assert + assert_eq!(Ok(u64::MAX / 2), result); + } } diff --git a/governance/program/src/tools/bpf_loader_upgradeable.rs b/governance/program/src/tools/bpf_loader_upgradeable.rs index bffde9afdbf..9fdf8390de1 100644 --- a/governance/program/src/tools/bpf_loader_upgradeable.rs +++ b/governance/program/src/tools/bpf_loader_upgradeable.rs @@ -1,17 +1,17 @@ //! General purpose bpf_loader_upgradeable utility functions -use solana_program::{ - account_info::AccountInfo, - bpf_loader_upgradeable::{self, UpgradeableLoaderState}, - program::invoke, - program_error::ProgramError, - pubkey::Pubkey, +use { + crate::error::GovernanceError, + bincode::deserialize, + solana_program::{ + account_info::AccountInfo, + bpf_loader_upgradeable::{self, UpgradeableLoaderState}, + program::invoke, + program_error::ProgramError, + pubkey::Pubkey, + }, }; -use bincode::deserialize; - -use crate::error::GovernanceError; - /// Returns ProgramData account address for the given Program pub fn get_program_data_address(program: &Pubkey) -> Pubkey { Pubkey::find_program_address(&[program.as_ref()], &bpf_loader_upgradeable::id()).0 @@ -57,7 +57,8 @@ pub fn set_program_upgrade_authority<'a>( ) } -/// Asserts the program is upgradable and its upgrade authority is a signer of the transaction +/// Asserts the program is upgradable and its upgrade authority is a signer of +/// the transaction pub fn assert_program_upgrade_authority_is_signer( program_address: &Pubkey, program_data_info: &AccountInfo, diff --git a/governance/program/src/tools/mod.rs b/governance/program/src/tools/mod.rs index 92d42769369..c434f5bbbce 100644 --- a/governance/program/src/tools/mod.rs +++ b/governance/program/src/tools/mod.rs @@ -5,3 +5,5 @@ pub mod spl_token; pub mod bpf_loader_upgradeable; pub mod pack; + +pub mod structs; diff --git a/governance/program/src/tools/pack.rs b/governance/program/src/tools/pack.rs index a503649fd12..809d3b296ee 100644 --- a/governance/program/src/tools/pack.rs +++ b/governance/program/src/tools/pack.rs @@ -1,7 +1,9 @@ //! General purpose packing utility functions -use arrayref::array_refs; -use solana_program::{program_error::ProgramError, program_option::COption, pubkey::Pubkey}; +use { + arrayref::array_refs, + solana_program::{program_error::ProgramError, program_option::COption, pubkey::Pubkey}, +}; /// Unpacks COption from a slice pub fn unpack_coption_pubkey(src: &[u8; 36]) -> Result, ProgramError> { diff --git a/governance/program/src/tools/spl_token.rs b/governance/program/src/tools/spl_token.rs index aad3db5840b..a5f19ce0ee2 100644 --- a/governance/program/src/tools/spl_token.rs +++ b/governance/program/src/tools/spl_token.rs @@ -1,26 +1,28 @@ //! General purpose SPL token utility functions -use arrayref::array_ref; -use solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - msg, - program::{invoke, invoke_signed}, - program_error::ProgramError, - program_option::COption, - program_pack::Pack, - pubkey::Pubkey, - rent::Rent, - system_instruction, +use { + crate::{error::GovernanceError, tools::pack::unpack_coption_pubkey}, + arrayref::array_ref, + solana_program::{ + account_info::AccountInfo, + entrypoint::ProgramResult, + msg, + program::{invoke, invoke_signed}, + program_error::ProgramError, + program_option::COption, + program_pack::Pack, + pubkey::Pubkey, + rent::Rent, + system_instruction, + }, + spl_token::{ + instruction::{set_authority, AuthorityType}, + state::{Account, Mint}, + }, }; -use spl_token::{ - instruction::{set_authority, AuthorityType}, - state::{Account, Mint}, -}; - -use crate::{error::GovernanceError, tools::pack::unpack_coption_pubkey}; -/// Creates and initializes SPL token account with PDA using the provided PDA seeds +/// Creates and initializes SPL token account with PDA using the provided PDA +/// seeds #[allow(clippy::too_many_arguments)] pub fn create_spl_token_account_signed<'a>( payer_info: &AccountInfo<'a>, @@ -121,7 +123,39 @@ pub fn transfer_spl_tokens<'a>( Ok(()) } -/// Transfers SPL Tokens from a token account owned by the provided PDA authority with seeds +/// Mint SPL Tokens +pub fn mint_spl_tokens_to<'a>( + mint_info: &AccountInfo<'a>, + destination_info: &AccountInfo<'a>, + mint_authority_info: &AccountInfo<'a>, + amount: u64, + spl_token_info: &AccountInfo<'a>, +) -> ProgramResult { + let mint_to_ix = spl_token::instruction::mint_to( + &spl_token::id(), + mint_info.key, + destination_info.key, + mint_authority_info.key, + &[], + amount, + ) + .unwrap(); + + invoke( + &mint_to_ix, + &[ + spl_token_info.clone(), + mint_authority_info.clone(), + mint_info.clone(), + destination_info.clone(), + ], + )?; + + Ok(()) +} + +/// Transfers SPL Tokens from a token account owned by the provided PDA +/// authority with seeds pub fn transfer_spl_tokens_signed<'a>( source_info: &AccountInfo<'a>, destination_info: &AccountInfo<'a>, @@ -170,7 +204,58 @@ pub fn transfer_spl_tokens_signed<'a>( Ok(()) } -/// Asserts the given account_info represents a valid SPL Token account which is initialized and belongs to spl_token program +/// Burns SPL Tokens from a token account owned by the provided PDA authority +/// with seeds +pub fn burn_spl_tokens_signed<'a>( + token_account_info: &AccountInfo<'a>, + token_mint_info: &AccountInfo<'a>, + authority_info: &AccountInfo<'a>, + authority_seeds: &[&[u8]], + program_id: &Pubkey, + amount: u64, + spl_token_info: &AccountInfo<'a>, +) -> ProgramResult { + let (authority_address, bump_seed) = Pubkey::find_program_address(authority_seeds, program_id); + + if authority_address != *authority_info.key { + msg!( + "Burn SPL Token with Authority PDA: {:?} was requested while PDA: {:?} was expected", + authority_info.key, + authority_address + ); + return Err(ProgramError::InvalidSeeds); + } + + let burn_ix = spl_token::instruction::burn( + &spl_token::id(), + token_account_info.key, + token_mint_info.key, + authority_info.key, + &[], + amount, + ) + .unwrap(); + + let mut signers_seeds = authority_seeds.to_vec(); + let bump = &[bump_seed]; + signers_seeds.push(bump); + + invoke_signed( + &burn_ix, + &[ + spl_token_info.clone(), + token_account_info.clone(), + token_mint_info.clone(), + authority_info.clone(), + ], + &[&signers_seeds[..]], + )?; + + Ok(()) +} + +/// Asserts the given account_info represents a valid SPL Token account which is +/// initialized and belongs to spl_token program pub fn assert_is_valid_spl_token_account(account_info: &AccountInfo) -> Result<(), ProgramError> { if account_info.data_is_empty() { return Err(GovernanceError::SplTokenAccountDoesNotExist.into()); @@ -184,7 +269,13 @@ pub fn assert_is_valid_spl_token_account(account_info: &AccountInfo) -> Result<( return Err(GovernanceError::SplTokenInvalidTokenAccountData.into()); } - // TokeAccount layout: mint(32), owner(32), amount(8), delegate(36), state(1), ... + // TokenAccount layout: + // mint(32) + // owner(32) + // amount(8) + // delegate(36) + // state(1) + // ... let data = account_info.try_borrow_data()?; let state = array_ref![data, 108, 1]; @@ -195,7 +286,13 @@ pub fn assert_is_valid_spl_token_account(account_info: &AccountInfo) -> Result<( Ok(()) } -/// Asserts the given mint_info represents a valid SPL Token Mint account which is initialized and belongs to spl_token program +/// Checks if the given account_info is spl-token token account +pub fn is_spl_token_account(account_info: &AccountInfo) -> bool { + assert_is_valid_spl_token_account(account_info).is_ok() +} + +/// Asserts the given mint_info represents a valid SPL Token Mint account which +/// is initialized and belongs to spl_token program pub fn assert_is_valid_spl_token_mint(mint_info: &AccountInfo) -> Result<(), ProgramError> { if mint_info.data_is_empty() { return Err(GovernanceError::SplTokenMintDoesNotExist.into()); @@ -210,7 +307,7 @@ pub fn assert_is_valid_spl_token_mint(mint_info: &AccountInfo) -> Result<(), Pro } // In token program [36, 8, 1, is_initialized(1), 36] is the layout - let data = mint_info.try_borrow_data().unwrap(); + let data = mint_info.try_borrow_data()?; let is_initialized = array_ref![data, 45, 1]; if is_initialized == &[0] { @@ -220,6 +317,11 @@ pub fn assert_is_valid_spl_token_mint(mint_info: &AccountInfo) -> Result<(), Pro Ok(()) } +/// Checks if the given account_info is be spl-token mint account +pub fn is_spl_token_mint(mint_info: &AccountInfo) -> bool { + assert_is_valid_spl_token_mint(mint_info).is_ok() +} + /// Computationally cheap method to get mint from a token account /// It reads mint without deserializing full account data pub fn get_spl_token_mint(token_account_info: &AccountInfo) -> Result { @@ -242,7 +344,8 @@ pub fn get_spl_token_owner(token_account_info: &AccountInfo) -> Result Result { assert_is_valid_spl_token_mint(mint_info)?; // In token program, 36, 8, 1, 1 is the layout, where the first 8 is supply u64. @@ -253,7 +356,8 @@ pub fn get_spl_token_mint_supply(mint_info: &AccountInfo) -> Result Result, ProgramError> { @@ -265,7 +369,8 @@ pub fn get_spl_token_mint_authority( unpack_coption_pubkey(bytes) } -/// Asserts current mint authority matches the given authority and it's signer of the transaction +/// Asserts current mint authority matches the given authority and it's signer +/// of the transaction pub fn assert_spl_token_mint_authority_is_signer( mint_info: &AccountInfo, mint_authority_info: &AccountInfo, @@ -287,7 +392,8 @@ pub fn assert_spl_token_mint_authority_is_signer( Ok(()) } -/// Asserts current token owner matches the given owner and it's signer of the transaction +/// Asserts current token owner matches the given owner and it's signer of the +/// transaction pub fn assert_spl_token_owner_is_signer( token_info: &AccountInfo, token_owner_info: &AccountInfo, diff --git a/governance/program/src/tools/structs.rs b/governance/program/src/tools/structs.rs new file mode 100644 index 00000000000..0a880c92797 --- /dev/null +++ b/governance/program/src/tools/structs.rs @@ -0,0 +1,55 @@ +//! General purpose structs utilities + +use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; + +/// Reserved 110 bytes +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] +pub struct Reserved110 { + /// Reserved 64 bytes + pub reserved64: [u8; 64], + /// Reserved 32 bytes + pub reserved32: [u8; 32], + /// Reserved 4 bytes + pub reserved14: [u8; 14], +} + +impl Default for Reserved110 { + fn default() -> Self { + Self { + reserved64: [0; 64], + reserved32: [0; 32], + reserved14: [0; 14], + } + } +} + +/// Reserved 119 bytes +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] +pub struct Reserved119 { + /// Reserved 64 bytes + pub reserved64: [u8; 64], + /// Reserved 32 bytes + pub reserved32: [u8; 32], + /// Reserved 19 bytes + pub reserved23: [u8; 23], +} + +impl Default for Reserved119 { + fn default() -> Self { + Self { + reserved64: [0; 64], + reserved32: [0; 32], + reserved23: [0; 23], + } + } +} + +/// Enum describing the action type for setting a config item +#[derive(Clone, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, BorshSchema)] +pub enum SetConfigItemActionType { + /// Add config item + Add, + + /// Remove config item + Remove, +} diff --git a/governance/program/tests/migrate_legacy_accounts.rs b/governance/program/tests/migrate_legacy_accounts.rs new file mode 100644 index 00000000000..87efec45e2f --- /dev/null +++ b/governance/program/tests/migrate_legacy_accounts.rs @@ -0,0 +1,82 @@ +#![cfg(feature = "test-sbf")] + +use solana_program_test::*; + +mod program_test; + +use { + program_test::{legacy::*, *}, + spl_governance::state::{ + enums::{VoteThreshold, VoteTipping}, + governance::DEFAULT_DEPOSIT_EXEMPT_PROPOSAL_COUNT, + }, +}; + +#[tokio::test] +async fn test_create_proposal_and_migrate_governance_v1_to_v2() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + // Override Governance account with LegacyV1 version + let mut governance_v1: LegacyGovernanceV1 = governance_cookie.account.clone().into(); + governance_v1.config.vote_threshold_percentage = VoteThresholdPercentage::YesVote(55); + + governance_test.set_account(&governance_cookie.address, &governance_v1); + + // Act + governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + // Assert + let governance_account = governance_test + .get_governance_account(&governance_cookie.address) + .await; + + assert_eq!(1, governance_account.active_proposal_count); + + assert_eq!( + VoteThreshold::YesVotePercentage(55), + governance_account.config.council_vote_threshold + ); + + assert_eq!( + VoteThreshold::YesVotePercentage(55), + governance_account.config.council_veto_vote_threshold + ); + + assert_eq!( + VoteThreshold::Disabled, + governance_account.config.community_veto_vote_threshold + ); + + assert_eq!( + DEFAULT_DEPOSIT_EXEMPT_PROPOSAL_COUNT, + governance_account.config.deposit_exempt_proposal_count + ); + + assert_eq!(0, governance_account.reserved1); + + assert_eq!( + VoteTipping::Strict, + governance_account.config.council_vote_tipping + ); + + assert_eq!( + VoteTipping::Strict, + governance_account.config.community_vote_tipping + ); +} diff --git a/governance/program/tests/process_add_required_signatory.rs b/governance/program/tests/process_add_required_signatory.rs new file mode 100644 index 00000000000..689387b6122 --- /dev/null +++ b/governance/program/tests/process_add_required_signatory.rs @@ -0,0 +1,188 @@ +#![cfg(feature = "test-sbf")] + +mod program_test; + +use { + num_traits::cast::ToPrimitive, + program_test::*, + solana_program::{ + program_error::ProgramError, pubkey::Pubkey, system_instruction::SystemError, + }, + solana_program_test::tokio, + solana_sdk::signature::Signer, + spl_governance::{error::GovernanceError, instruction::add_required_signatory}, +}; + +#[tokio::test] +async fn test_add_required_signatory() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let signatory = Pubkey::new_unique(); + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + let mut proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + let proposal_transaction_cookie = governance_test + .with_add_required_signatory_transaction( + &mut proposal_cookie, + &token_owner_record_cookie, + &governance_cookie, + &signatory, + ) + .await + .unwrap(); + + governance_test + .sign_off_proposal_by_owner(&proposal_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + // Advance timestamp past hold_up_time + governance_test + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) + .await; + + // Act + governance_test + .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie) + .await + .unwrap(); + + // Assert + let governance_account = governance_test + .get_governance_account(&governance_cookie.address) + .await; + + assert_eq!(1, governance_account.required_signatories_count); +} + +#[tokio::test] +pub async fn add_same_required_signatory_to_governance_twice_err() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let (token_owner_record_cookie, mut governance_cookie, realm_cookie, signatory) = + governance_test + .with_governance_with_required_signatory() + .await; + + let mut proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + let proposal_transaction_cookie = governance_test + .with_add_required_signatory_transaction( + &mut proposal_cookie, + &token_owner_record_cookie, + &governance_cookie, + &signatory.pubkey(), + ) + .await + .unwrap(); + + governance_test + .with_signatory_record_for_required_signatory( + &proposal_cookie, + &governance_cookie, + &signatory.pubkey(), + ) + .await + .unwrap(); + + governance_test + .do_required_signoff( + &realm_cookie, + &governance_cookie, + &proposal_cookie, + &signatory, + ) + .await + .unwrap(); + + governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + governance_test + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) + .await; + + // Act + let err = governance_test + .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie) + .await + .err() + .unwrap(); + + // Assert + assert_eq!( + err, + ProgramError::Custom(SystemError::AccountAlreadyInUse.to_u32().unwrap()) + ); +} + +#[tokio::test] +pub async fn add_required_signatory_to_governance_without_governance_signer_err() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let signatory = Pubkey::new_unique(); + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + let mut gwr_ix = add_required_signatory( + &governance_test.program_id, + &governance_cookie.address, + &governance_test.bench.payer.pubkey(), + &signatory, + ); + + gwr_ix.accounts[0].is_signer = false; + + // Act + let err = governance_test + .bench + .process_transaction(&[gwr_ix], Some(&[])) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::GovernancePdaMustSign.into()); +} diff --git a/governance/program/tests/process_add_signatory.rs b/governance/program/tests/process_add_signatory.rs index 0bdcfd18e03..bec2e6076cb 100644 --- a/governance/program/tests/process_add_signatory.rs +++ b/governance/program/tests/process_add_signatory.rs @@ -1,12 +1,17 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] mod program_test; -use solana_program_test::tokio; - -use program_test::*; - -use spl_governance::error::GovernanceError; +use { + program_test::*, + solana_program::program_error::ProgramError, + solana_program_test::tokio, + solana_sdk::{pubkey::Pubkey, signature::Signer}, + spl_governance::{ + error::GovernanceError, + instruction::{add_signatory, AddSignatoryAuthority, GovernanceInstruction}, + }, +}; #[tokio::test] async fn test_add_signatory() { @@ -14,7 +19,6 @@ async fn test_add_signatory() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -22,11 +26,7 @@ async fn test_add_signatory() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -37,7 +37,11 @@ async fn test_add_signatory() { // Act let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) .await .unwrap(); @@ -61,7 +65,6 @@ async fn test_add_signatory_with_owner_or_delegate_must_sign_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let mut token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -69,11 +72,7 @@ async fn test_add_signatory_with_owner_or_delegate_must_sign_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -91,7 +90,11 @@ async fn test_add_signatory_with_owner_or_delegate_must_sign_error() { // Act let err = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) .await .err() .unwrap(); @@ -109,7 +112,6 @@ async fn test_add_signatory_with_invalid_proposal_owner_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let mut token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -117,11 +119,7 @@ async fn test_add_signatory_with_invalid_proposal_owner_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -139,7 +137,11 @@ async fn test_add_signatory_with_invalid_proposal_owner_error() { // Act let err = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) .await .err() .unwrap(); @@ -147,3 +149,303 @@ async fn test_add_signatory_with_invalid_proposal_owner_error() { // Assert assert_eq!(err, GovernanceError::InvalidProposalOwnerAccount.into()); } + +#[tokio::test] +async fn test_add_signatory_for_required_signatory() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let signatory = Pubkey::new_unique(); + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + let mut proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + let signatory_record_cookie = governance_test + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) + .await + .unwrap(); + + let proposal_transaction_cookie = governance_test + .with_add_required_signatory_transaction( + &mut proposal_cookie, + &token_owner_record_cookie, + &governance_cookie, + &signatory, + ) + .await + .unwrap(); + + governance_test + .sign_off_proposal(&proposal_cookie, &signatory_record_cookie) + .await + .unwrap(); + + governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + // Advance timestamp past hold_up_time + governance_test + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) + .await; + + governance_test + .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie) + .await + .unwrap(); + + let new_proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + // Act + let new_signatory_record_cookie = governance_test + .with_signatory_record_for_required_signatory( + &new_proposal_cookie, + &governance_cookie, + &signatory, + ) + .await + .unwrap(); + + // Assert + let signatory_account = governance_test + .get_signatory_record_account(&new_signatory_record_cookie.address) + .await; + + assert_eq!(signatory_account.signatory, signatory); + assert_eq!(signatory_account.proposal, new_proposal_cookie.address); + assert!(!signatory_account.signed_off); + + let new_proposal_account = governance_test + .get_proposal_account(&new_proposal_cookie.address) + .await; + + assert_eq!(new_proposal_account.signatories_count, 1); +} + +#[tokio::test] +async fn test_add_signatory_for_required_signatory_multiple_times_err() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let signatory = Pubkey::new_unique(); + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + let mut proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + let signatory_record_cookie = governance_test + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) + .await + .unwrap(); + + let proposal_transaction_cookie = governance_test + .with_add_required_signatory_transaction( + &mut proposal_cookie, + &token_owner_record_cookie, + &governance_cookie, + &signatory, + ) + .await + .unwrap(); + + governance_test + .sign_off_proposal(&proposal_cookie, &signatory_record_cookie) + .await + .unwrap(); + + governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + // Advance timestamp past hold_up_time + governance_test + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) + .await; + + governance_test + .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie) + .await + .unwrap(); + + let new_proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + governance_test + .with_signatory_record_for_required_signatory( + &new_proposal_cookie, + &governance_cookie, + &signatory, + ) + .await + .unwrap(); + governance_test.advance_clock().await; + + // Act + let err = governance_test + .with_signatory_record_for_required_signatory( + &new_proposal_cookie, + &governance_cookie, + &signatory, + ) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::SignatoryRecordAlreadyExists.into()); +} + +#[tokio::test] +pub async fn test_add_optional_signatory_before_all_required_signatories_err() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let (token_owner_record_cookie, mut governance_cookie, _, _) = governance_test + .with_governance_with_required_signatory() + .await; + + let proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + // Act + let err = governance_test + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, ProgramError::UninitializedAccount); +} + +#[tokio::test] +pub async fn test_add_optional_signatory_to_proposal_with_required_signatories() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let (token_owner_record_cookie, mut governance_cookie, _, signatory) = governance_test + .with_governance_with_required_signatory() + .await; + + let proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + governance_test + .with_signatory_record_for_required_signatory( + &proposal_cookie, + &governance_cookie, + &signatory.pubkey(), + ) + .await + .unwrap(); + + // Act + governance_test + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) + .await + .unwrap(); + + // Assert + let proposal_account = governance_test + .get_proposal_account(&proposal_cookie.address) + .await; + assert_eq!(proposal_account.signatories_count, 2); +} + +#[tokio::test] +pub async fn test_add_non_matching_required_signatory_to_proposal_err() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let (token_owner_record_cookie, mut governance_cookie, _, signatory) = governance_test + .with_governance_with_required_signatory() + .await; + + let proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + let mut create_signatory_record_ix = add_signatory( + &governance_test.program_id, + &governance_cookie.address, + &proposal_cookie.address, + &AddSignatoryAuthority::None, + &governance_test.bench.payer.pubkey(), + &signatory.pubkey(), + ); + + create_signatory_record_ix.data = borsh::to_vec(&GovernanceInstruction::AddSignatory { + signatory: Pubkey::new_unique(), + }) + .unwrap(); + + // Act + let err = governance_test + .bench + .process_transaction(&[create_signatory_record_ix], Some(&[])) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::InvalidSignatoryAddress.into()); +} diff --git a/governance/program/tests/process_cancel_proposal.rs b/governance/program/tests/process_cancel_proposal.rs index 382efc89584..c7b61f8bd13 100644 --- a/governance/program/tests/process_cancel_proposal.rs +++ b/governance/program/tests/process_cancel_proposal.rs @@ -1,11 +1,12 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] mod program_test; -use solana_program_test::tokio; - -use program_test::*; -use spl_governance::{error::GovernanceError, state::enums::ProposalState}; +use { + program_test::*, + solana_program_test::tokio, + spl_governance::{error::GovernanceError, state::enums::ProposalState}, +}; #[tokio::test] async fn test_cancel_proposal() { @@ -13,7 +14,6 @@ async fn test_cancel_proposal() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -21,11 +21,7 @@ async fn test_cancel_proposal() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -56,17 +52,11 @@ async fn test_cancel_proposal() { assert_eq!(0, token_owner_record_account.outstanding_proposal_count); - let realm_account = governance_test - .get_realm_account(&realm_cookie.address) - .await; - - assert_eq!(0, realm_account.voting_proposal_count); - let governance_account = governance_test .get_governance_account(&governance_cookie.address) .await; - assert_eq!(0, governance_account.voting_proposal_count); + assert_eq!(0, governance_account.active_proposal_count); } #[tokio::test] @@ -75,7 +65,6 @@ async fn test_cancel_proposal_with_already_completed_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -83,11 +72,7 @@ async fn test_cancel_proposal_with_already_completed_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -122,7 +107,6 @@ async fn test_cancel_proposal_with_owner_or_delegate_must_sign_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let mut token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -130,11 +114,7 @@ async fn test_cancel_proposal_with_owner_or_delegate_must_sign_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -158,7 +138,6 @@ async fn test_cancel_proposal_with_owner_or_delegate_must_sign_error() { .unwrap(); // Assert - assert_eq!( err, GovernanceError::GoverningTokenOwnerOrDelegateMustSign.into() @@ -171,7 +150,6 @@ async fn test_cancel_proposal_with_vote_time_expired_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -179,10 +157,58 @@ async fn test_cancel_proposal_with_vote_time_expired_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + let clock = governance_test.bench.get_clock().await; + + let proposal_cookie = governance_test + .with_signed_off_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + // Advance timestamp past max_voting_time + governance_test + .advance_clock_past_timestamp( + governance_cookie.account.config.voting_base_time as i64 + clock.unix_timestamp, + ) + .await; + + // Act + + let err = governance_test + .cancel_proposal(&proposal_cookie, &token_owner_record_cookie) + .await + .err() + .unwrap(); + + // Assert + + assert_eq!(err, GovernanceError::ProposalVotingTimeExpired.into()); +} + +#[tokio::test] +async fn test_cancel_proposal_after_voting_cool_off_with_vote_time_expired_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Set none default voting cool off time + let mut governance_config = governance_test.get_default_governance_config(); + governance_config.voting_cool_off_time = 10; + + let mut governance_cookie = governance_test + .with_governance_using_config( &realm_cookie, - &governed_account_cookie, &token_owner_record_cookie, + &governance_config, ) .await .unwrap(); @@ -197,7 +223,9 @@ async fn test_cancel_proposal_with_vote_time_expired_error() { // Advance timestamp past max_voting_time governance_test .advance_clock_past_timestamp( - governance_cookie.account.config.max_voting_time as i64 + clock.unix_timestamp, + (governance_cookie.account.config.voting_base_time + + governance_cookie.account.config.voting_cool_off_time) as i64 + + clock.unix_timestamp, ) .await; @@ -220,7 +248,6 @@ async fn test_cancel_proposal_in_voting_state() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -228,11 +255,7 @@ async fn test_cancel_proposal_in_voting_state() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -258,15 +281,9 @@ async fn test_cancel_proposal_in_voting_state() { assert_eq!(ProposalState::Cancelled, proposal_account.state); - let realm_account = governance_test - .get_realm_account(&realm_cookie.address) - .await; - - assert_eq!(0, realm_account.voting_proposal_count); - let governance_account = governance_test .get_governance_account(&governance_cookie.address) .await; - assert_eq!(0, governance_account.voting_proposal_count); + assert_eq!(0, governance_account.active_proposal_count); } diff --git a/governance/program/tests/process_cast_vote.rs b/governance/program/tests/process_cast_vote.rs index 5050f231d11..7d5b5b22757 100644 --- a/governance/program/tests/process_cast_vote.rs +++ b/governance/program/tests/process_cast_vote.rs @@ -1,14 +1,19 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] mod program_test; -use solana_program::pubkey::Pubkey; -use solana_program_test::tokio; - -use program_test::*; -use spl_governance::{ - error::GovernanceError, - state::enums::{ProposalState, VoteThreshold, VoteTipping}, +use { + crate::program_test::args::RealmSetupArgs, + program_test::*, + solana_program::pubkey::Pubkey, + solana_program_test::tokio, + spl_governance::{ + error::GovernanceError, + state::{ + enums::{MintMaxVoterWeightSource, ProposalState, VoteThreshold, VoteTipping}, + vote_record::Vote, + }, + }, }; #[tokio::test] @@ -17,7 +22,6 @@ async fn test_cast_vote() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -25,11 +29,7 @@ async fn test_cast_vote() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -81,19 +81,12 @@ async fn test_cast_vote() { .await; assert_eq!(1, token_owner_record.unrelinquished_votes_count); - assert_eq!(1, token_owner_record.total_votes_count); - - let realm_account = governance_test - .get_realm_account(&realm_cookie.address) - .await; - - assert_eq!(0, realm_account.voting_proposal_count); let governance_account = governance_test .get_governance_account(&governance_cookie.address) .await; - assert_eq!(0, governance_account.voting_proposal_count); + assert_eq!(0, governance_account.active_proposal_count); } #[tokio::test] @@ -102,7 +95,6 @@ async fn test_cast_vote_with_invalid_governance_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -110,11 +102,7 @@ async fn test_cast_vote_with_invalid_governance_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -123,15 +111,9 @@ async fn test_cast_vote_with_invalid_governance_error() { .await .unwrap(); - // Setup Governance for a different account - let governed_account_cookie2 = governance_test.with_governed_account().await; - + // Setup another Governance let governance_cookie2 = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie2, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -153,7 +135,6 @@ async fn test_cast_vote_with_invalid_mint_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let mut token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -161,11 +142,7 @@ async fn test_cast_vote_with_invalid_mint_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -194,7 +171,6 @@ async fn test_cast_vote_with_invalid_token_owner_record_mint_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let mut token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -202,11 +178,7 @@ async fn test_cast_vote_with_invalid_token_owner_record_mint_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -242,7 +214,6 @@ async fn test_cast_vote_with_invalid_token_owner_record_from_different_realm_err let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let mut token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -250,11 +221,7 @@ async fn test_cast_vote_with_invalid_token_owner_record_from_different_realm_err .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -289,7 +256,6 @@ async fn test_cast_vote_with_governance_authority_must_sign_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let mut token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -297,11 +263,7 @@ async fn test_cast_vote_with_governance_authority_must_sign_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -337,7 +299,6 @@ async fn test_cast_vote_with_strict_vote_tipped_to_succeeded() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie1 = governance_test .with_community_token_deposit(&realm_cookie) @@ -345,11 +306,7 @@ async fn test_cast_vote_with_strict_vote_tipped_to_succeeded() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie1, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie1) .await .unwrap(); @@ -427,18 +384,6 @@ async fn test_cast_vote_with_strict_vote_tipped_to_succeeded() { .await; assert_eq!(0, proposal_owner_record.outstanding_proposal_count); - - let realm_account = governance_test - .get_realm_account(&realm_cookie.address) - .await; - - assert_eq!(0, realm_account.voting_proposal_count); - - let governance_account = governance_test - .get_governance_account(&governance_cookie.address) - .await; - - assert_eq!(0, governance_account.voting_proposal_count); } #[tokio::test] @@ -447,7 +392,6 @@ async fn test_cast_vote_with_strict_vote_tipped_to_defeated() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; // 100 votes let token_owner_record_cookie1 = governance_test @@ -456,11 +400,7 @@ async fn test_cast_vote_with_strict_vote_tipped_to_defeated() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie1, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie1) .await .unwrap(); @@ -545,11 +485,10 @@ async fn test_cast_vote_with_early_vote_tipped_to_succeeded() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let mut governance_config = governance_test.get_default_governance_config(); - governance_config.vote_tipping = VoteTipping::Early; + governance_config.community_vote_tipping = VoteTipping::Early; governance_config.community_vote_threshold = VoteThreshold::YesVotePercentage(15); let token_owner_record_cookie1 = governance_test @@ -560,7 +499,6 @@ async fn test_cast_vote_with_early_vote_tipped_to_succeeded() { let mut governance_cookie = governance_test .with_governance_using_config( &realm_cookie, - &governed_account_cookie, &token_owner_record_cookie1, &governance_config, ) @@ -701,6 +639,12 @@ async fn test_cast_vote_with_early_vote_tipped_to_succeeded() { .get_token_owner_record_account(&proposal_cookie.account.token_owner_record) .await; assert_eq!(0, proposal_owner_record.outstanding_proposal_count); + + let governance_account = governance_test + .get_governance_account(&governance_cookie.address) + .await; + + assert_eq!(0, governance_account.active_proposal_count); } #[tokio::test] @@ -709,11 +653,10 @@ async fn test_cast_vote_with_early_vote_tipped_to_defeated() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let mut governance_config = governance_test.get_default_governance_config(); - governance_config.vote_tipping = VoteTipping::Early; + governance_config.community_vote_tipping = VoteTipping::Early; governance_config.community_vote_threshold = VoteThreshold::YesVotePercentage(40); // 100 votes @@ -725,7 +668,6 @@ async fn test_cast_vote_with_early_vote_tipped_to_defeated() { let mut _governance_cookie = governance_test .with_governance_using_config( &realm_cookie, - &governed_account_cookie, &token_owner_record_cookie1, &governance_config, ) @@ -813,7 +755,6 @@ async fn test_cast_vote_with_threshold_below_50_and_vote_not_tipped() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let mut governance_config = governance_test.get_default_governance_config(); @@ -827,7 +768,6 @@ async fn test_cast_vote_with_threshold_below_50_and_vote_not_tipped() { let mut governance_cookie = governance_test .with_governance_using_config( &realm_cookie, - &governed_account_cookie, &token_owner_record_cookie, &governance_config, ) @@ -864,17 +804,11 @@ async fn test_cast_vote_with_threshold_below_50_and_vote_not_tipped() { assert_eq!(1, proposal_owner_record.outstanding_proposal_count); - let realm_account = governance_test - .get_realm_account(&realm_cookie.address) - .await; - - assert_eq!(1, realm_account.voting_proposal_count); - let governance_account = governance_test .get_governance_account(&governance_cookie.address) .await; - assert_eq!(1, governance_account.voting_proposal_count); + assert_eq!(1, governance_account.active_proposal_count); } #[tokio::test] @@ -883,11 +817,10 @@ async fn test_cast_vote_with_disabled_tipping_yes_votes() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let mut governance_config = governance_test.get_default_governance_config(); - governance_config.vote_tipping = VoteTipping::Disabled; + governance_config.community_vote_tipping = VoteTipping::Disabled; governance_config.community_vote_threshold = VoteThreshold::YesVotePercentage(10); let token_owner_record_cookie1 = governance_test @@ -898,7 +831,6 @@ async fn test_cast_vote_with_disabled_tipping_yes_votes() { let mut _governance_cookie = governance_test .with_governance_using_config( &realm_cookie, - &governed_account_cookie, &token_owner_record_cookie1, &governance_config, ) @@ -954,11 +886,10 @@ async fn test_cast_vote_with_disabled_tipping_no_votes() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let mut governance_config = governance_test.get_default_governance_config(); - governance_config.vote_tipping = VoteTipping::Disabled; + governance_config.community_vote_tipping = VoteTipping::Disabled; governance_config.community_vote_threshold = VoteThreshold::YesVotePercentage(10); let token_owner_record_cookie1 = governance_test @@ -969,7 +900,6 @@ async fn test_cast_vote_with_disabled_tipping_no_votes() { let mut _governance_cookie = governance_test .with_governance_using_config( &realm_cookie, - &governed_account_cookie, &token_owner_record_cookie1, &governance_config, ) @@ -1004,7 +934,6 @@ async fn test_cast_vote_with_voting_time_expired_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -1012,11 +941,7 @@ async fn test_cast_vote_with_voting_time_expired_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -1030,7 +955,7 @@ async fn test_cast_vote_with_voting_time_expired_error() { .await; let vote_expired_at = proposal_account.voting_at.unwrap() - + governance_cookie.account.config.max_voting_time as i64; + + governance_cookie.account.config.voting_base_time as i64; governance_test .advance_clock_past_timestamp(vote_expired_at) @@ -1055,7 +980,6 @@ async fn test_cast_vote_with_cast_twice_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -1063,11 +987,7 @@ async fn test_cast_vote_with_cast_twice_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -1104,7 +1024,6 @@ async fn test_cast_vote_with_invalid_proposal_owner_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -1112,11 +1031,7 @@ async fn test_cast_vote_with_invalid_proposal_owner_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -1144,7 +1059,6 @@ async fn test_cast_tipping_vote_with_invalid_proposal_owner_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -1152,11 +1066,7 @@ async fn test_cast_tipping_vote_with_invalid_proposal_owner_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -1199,7 +1109,6 @@ async fn test_cast_council_vote() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_council_token_deposit(&realm_cookie) @@ -1212,7 +1121,6 @@ async fn test_cast_council_vote() { let mut governance_cookie = governance_test .with_governance_using_config( &realm_cookie, - &governed_account_cookie, &token_owner_record_cookie, &governance_config, ) @@ -1243,3 +1151,359 @@ async fn test_cast_council_vote() { proposal_account.vote_threshold ); } + +#[tokio::test] +async fn test_cast_vote_with_invalid_realm_config_account_address_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_signed_off_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + // Try bypass config check by using none existing config account + let realm_config_address = Pubkey::new_unique(); + + // Act + let err = governance_test + .with_cast_vote_using_instruction( + &proposal_cookie, + &token_owner_record_cookie, + Vote::Deny, + |i| { + i.accounts[10].pubkey = realm_config_address; // realm_config_address + }, + None, + ) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::InvalidRealmConfigAddress.into()); +} + +#[tokio::test] +async fn test_cast_early_council_vote_with_disabled_community_vote_tipping() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_council_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_config = governance_test.get_default_governance_config(); + + governance_config.community_vote_tipping = VoteTipping::Disabled; + governance_config.council_vote_tipping = VoteTipping::Early; + + let mut governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie, + &governance_config, + ) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_signed_off_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + governance_test + .mint_community_tokens(&realm_cookie, 20) + .await; + + // Act + governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + // Assert + + let proposal_account = governance_test + .get_proposal_account(&proposal_cookie.address) + .await; + + assert_eq!(proposal_account.state, ProposalState::Succeeded); +} + +#[tokio::test] +async fn test_cast_community_vote_with_early_council_and_disabled_community_vote_tipping() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_config = governance_test.get_default_governance_config(); + + governance_config.community_vote_tipping = VoteTipping::Disabled; + governance_config.council_vote_tipping = VoteTipping::Early; + + let mut governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie, + &governance_config, + ) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_signed_off_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + governance_test + .mint_community_tokens(&realm_cookie, 20) + .await; + + // Act + governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + // Assert + + let proposal_account = governance_test + .get_proposal_account(&proposal_cookie.address) + .await; + + assert_eq!(proposal_account.state, ProposalState::Voting); +} + +#[tokio::test] +async fn test_cast_vote_with_disabled_tipping_and_max_yes_votes() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let mut governance_config = governance_test.get_default_governance_config(); + + governance_config.community_vote_tipping = VoteTipping::Disabled; + governance_config.community_vote_threshold = VoteThreshold::YesVotePercentage(10); + + let token_owner_record_cookie1 = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut _governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie1, + &governance_config, + ) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_signed_off_proposal(&token_owner_record_cookie1, &mut _governance_cookie) + .await + .unwrap(); + + // Act + governance_test + .with_cast_yes_no_vote( + &proposal_cookie, + &token_owner_record_cookie1, + YesNoVote::Yes, + ) + .await + .unwrap(); + + // Assert + + let proposal_account = governance_test + .get_proposal_account(&proposal_cookie.address) + .await; + assert_eq!(ProposalState::Voting, proposal_account.state); +} + +#[tokio::test] +async fn test_cast_vote_with_disabled_tipping_and_max_no_votes() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let mut governance_config = governance_test.get_default_governance_config(); + + governance_config.community_vote_tipping = VoteTipping::Disabled; + governance_config.community_vote_threshold = VoteThreshold::YesVotePercentage(10); + + let token_owner_record_cookie1 = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut _governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie1, + &governance_config, + ) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_signed_off_proposal(&token_owner_record_cookie1, &mut _governance_cookie) + .await + .unwrap(); + + // Act + governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie1, YesNoVote::No) + .await + .unwrap(); + + // Assert + + let proposal_account = governance_test + .get_proposal_account(&proposal_cookie.address) + .await; + assert_eq!(ProposalState::Voting, proposal_account.state); +} + +#[tokio::test] +async fn test_cast_vote_with_strict_tipping_and_inflated_max_vote_weight() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + // Reduce max voter weight to 50% for the cast vote to be above max_voter_weight + let realm_config_args = RealmSetupArgs { + community_mint_max_voter_weight_source: MintMaxVoterWeightSource::SupplyFraction( + MintMaxVoterWeightSource::SUPPLY_FRACTION_BASE / 2, + ), + ..Default::default() + }; + + let realm_cookie = governance_test + .with_realm_using_args(&realm_config_args) + .await; + + let governance_config = governance_test.get_default_governance_config(); + + // Mint and deposit 100 tokens to Member + let token_owner_record_cookie1 = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Mint 20 community tokens to increase total supply to 120 + // It gives us max_voter_weight==60 which is below the cast vote weight of 100 + governance_test + .mint_community_tokens(&realm_cookie, 20) + .await; + + let mut _governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie1, + &governance_config, + ) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_signed_off_proposal(&token_owner_record_cookie1, &mut _governance_cookie) + .await + .unwrap(); + + // Act + governance_test + .with_cast_yes_no_vote( + &proposal_cookie, + &token_owner_record_cookie1, + YesNoVote::Yes, + ) + .await + .unwrap(); + + // Assert + + let proposal_account = governance_test + .get_proposal_account(&proposal_cookie.address) + .await; + + assert_eq!(ProposalState::Succeeded, proposal_account.state); + // max_vote_weight should be coerced from 60 to 100 + assert_eq!(proposal_account.max_vote_weight, Some(100)) +} + +#[tokio::test] +async fn test_cast_approve_vote_with_cannot_vote_in_cool_off_time_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Set none default voting cool off time + let mut governance_config = governance_test.get_default_governance_config(); + governance_config.voting_cool_off_time = 50; + + let mut governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie, + &governance_config, + ) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_signed_off_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + // Advance timestamp into voting_cool_off_time + let clock = governance_test.bench.get_clock().await; + + governance_test + .advance_clock_past_timestamp( + clock.unix_timestamp + governance_cookie.account.config.voting_base_time as i64, + ) + .await; + + // Act + + let err = governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .err() + .unwrap(); + + // Assert + + assert_eq!(err, GovernanceError::VoteNotAllowedInCoolOffTime.into()); +} diff --git a/governance/program/tests/process_complete_proposal.rs b/governance/program/tests/process_complete_proposal.rs new file mode 100644 index 00000000000..ca0849fafc4 --- /dev/null +++ b/governance/program/tests/process_complete_proposal.rs @@ -0,0 +1,217 @@ +#![cfg(feature = "test-sbf")] + +mod program_test; + +use { + program_test::*, + solana_program_test::tokio, + spl_governance::{error::GovernanceError, state::enums::ProposalState}, +}; + +#[tokio::test] +async fn test_complete_proposal() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_signed_off_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + let clock = governance_test.bench.get_clock().await; + + // Ensure + let proposal_account = governance_test + .get_proposal_account(&proposal_cookie.address) + .await; + assert_eq!(ProposalState::Succeeded, proposal_account.state); + + // Act + governance_test + .complete_proposal(&proposal_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + // Assert + let proposal_account = governance_test + .get_proposal_account(&proposal_cookie.address) + .await; + + assert_eq!(ProposalState::Completed, proposal_account.state); + assert_eq!(Some(clock.unix_timestamp), proposal_account.closed_at); +} + +#[tokio::test] +async fn test_complete_proposal_with_wrong_state_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + // Ensure + let proposal = governance_test + .get_proposal_account(&proposal_cookie.address) + .await; + assert_eq!(ProposalState::Draft, proposal.state); + + // Act + let err = governance_test + .complete_proposal(&proposal_cookie, &token_owner_record_cookie) + .await + .err() + .unwrap(); + + assert_eq!(err, GovernanceError::InvalidStateToCompleteProposal.into()); +} + +#[tokio::test] +async fn test_complete_proposal_with_completed_state_transaction_exists_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + let governed_token_account_cookie = governance_test + .with_governed_token_account(&governance_cookie) + .await; + + let mut proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + let signatory_record_cookie = governance_test + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) + .await + .unwrap(); + + let proposal_transaction_cookie = governance_test + .with_transfer_tokens_transaction( + &governed_token_account_cookie, + &mut proposal_cookie, + &token_owner_record_cookie, + None, + ) + .await + .unwrap(); + + governance_test + .sign_off_proposal(&proposal_cookie, &signatory_record_cookie) + .await + .unwrap(); + + governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + // transaction exists while not advancing the time + + let proposal = governance_test + .get_proposal_account(&proposal_cookie.address) + .await; + assert_eq!(ProposalState::Succeeded, proposal.state); + assert!(!proposal_transaction_cookie.account.instructions.is_empty()); + + // Act + let err = governance_test + .complete_proposal(&proposal_cookie, &token_owner_record_cookie) + .await + .err() + .unwrap(); + + assert_eq!(err, GovernanceError::InvalidStateToCompleteProposal.into()); +} + +#[tokio::test] +async fn test_complete_proposal_with_owner_or_delegate_must_sign_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let mut token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_signed_off_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + // Try to maliciously sign using different owner signature + let token_owner_record_cookie2 = governance_test + .with_council_token_deposit(&realm_cookie) + .await + .unwrap(); + token_owner_record_cookie.token_owner = token_owner_record_cookie2.token_owner; + + // Act + let err = governance_test + .complete_proposal(&proposal_cookie, &token_owner_record_cookie) + .await + .err() + .unwrap(); + + assert_eq!( + err, + GovernanceError::GoverningTokenOwnerOrDelegateMustSign.into() + ); +} diff --git a/governance/program/tests/process_create_governance.rs b/governance/program/tests/process_create_governance.rs index 490f90a7703..ac0562b91a1 100644 --- a/governance/program/tests/process_create_governance.rs +++ b/governance/program/tests/process_create_governance.rs @@ -1,12 +1,14 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] mod program_test; -use solana_program_test::*; - -use program_test::*; -use solana_sdk::signature::Keypair; -use spl_governance::{error::GovernanceError, state::enums::VoteThreshold}; -use spl_governance_tools::error::GovernanceToolsError; +use { + crate::program_test::args::RealmSetupArgs, + program_test::*, + solana_program_test::*, + solana_sdk::signature::Keypair, + spl_governance::{error::GovernanceError, state::enums::VoteThreshold}, + spl_governance_tools::error::GovernanceToolsError, +}; #[tokio::test] async fn test_create_governance() { @@ -14,7 +16,6 @@ async fn test_create_governance() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -23,11 +24,7 @@ async fn test_create_governance() { // Act let governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -45,7 +42,6 @@ async fn test_create_governance_with_invalid_realm_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let mut realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -53,11 +49,7 @@ async fn test_create_governance_with_invalid_realm_error() { .unwrap(); let governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -65,11 +57,7 @@ async fn test_create_governance_with_invalid_realm_error() { // Act let err = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .err() .unwrap(); @@ -85,7 +73,6 @@ async fn test_create_governance_with_invalid_config_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -98,12 +85,7 @@ async fn test_create_governance_with_invalid_config_error() { // Act let err = governance_test - .with_governance_using_config( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - &config, - ) + .with_governance_using_config(&realm_cookie, &token_owner_record_cookie, &config) .await .err() .unwrap(); @@ -118,12 +100,7 @@ async fn test_create_governance_with_invalid_config_error() { // Act let err = governance_test - .with_governance_using_config( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - &config, - ) + .with_governance_using_config(&realm_cookie, &token_owner_record_cookie, &config) .await .err() .unwrap(); @@ -139,7 +116,6 @@ async fn test_create_governance_with_not_enough_community_tokens_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; // Set token deposit amount below the required threshold let token_amount = 4; @@ -151,11 +127,7 @@ async fn test_create_governance_with_not_enough_community_tokens_error() { // Act let err = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .err() .unwrap(); @@ -173,7 +145,6 @@ async fn test_create_governance_with_not_enough_council_tokens_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; // Set token deposit amount below the required threshold let token_amount: u64 = 0; @@ -185,11 +156,7 @@ async fn test_create_governance_with_not_enough_council_tokens_error() { // Act let err = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .err() .unwrap(); @@ -207,22 +174,13 @@ async fn test_create_governance_using_realm_authority() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let config = governance_test.get_default_governance_config(); let realm_authority = realm_cookie.realm_authority.as_ref().unwrap(); // Act let governance_cookie = governance_test - .with_governance_impl( - &realm_cookie, - &governed_account_cookie, - None, - &realm_authority, - None, - &config, - None, - ) + .with_governance_impl(&realm_cookie, None, realm_authority, None, &config, None) .await .unwrap(); @@ -240,7 +198,6 @@ async fn test_create_governance_using_realm_authority_with_authority_must_sign_e let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let config = governance_test.get_default_governance_config(); let realm_authority = realm_cookie.realm_authority.as_ref().unwrap(); @@ -249,9 +206,8 @@ async fn test_create_governance_using_realm_authority_with_authority_must_sign_e let err = governance_test .with_governance_impl( &realm_cookie, - &governed_account_cookie, None, - &realm_authority, + realm_authority, None, &config, Some(&[]), @@ -270,7 +226,6 @@ async fn test_create_governance_using_realm_authority_with_wrong_authority_sign_ let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -284,7 +239,6 @@ async fn test_create_governance_using_realm_authority_with_wrong_authority_sign_ let err = governance_test .with_governance_impl( &realm_cookie, - &governed_account_cookie, Some(&token_owner_record_cookie.address), &authority, None, @@ -301,3 +255,36 @@ async fn test_create_governance_using_realm_authority_with_wrong_authority_sign_ GovernanceError::GoverningTokenOwnerOrDelegateMustSign.into() ); } + +#[tokio::test] +async fn test_create_governance_with_community_disabled_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_config_args = RealmSetupArgs { + min_community_weight_to_create_governance: u64::MAX, + ..Default::default() + }; + + let realm_cookie = governance_test + .with_realm_using_args(&realm_config_args) + .await; + + // Set token deposit amount to max + let token_amount = u64::MAX; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit_amount(&realm_cookie, token_amount) + .await + .unwrap(); + + // Act + let err = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::VoterWeightThresholdDisabled.into()); +} diff --git a/governance/program/tests/process_create_mint_governance.rs b/governance/program/tests/process_create_mint_governance.rs deleted file mode 100644 index fd52181abca..00000000000 --- a/governance/program/tests/process_create_mint_governance.rs +++ /dev/null @@ -1,273 +0,0 @@ -#![cfg(feature = "test-bpf")] -mod program_test; - -use solana_program_test::*; - -use program_test::*; -use solana_sdk::{signature::Keypair, signer::Signer}; -use spl_governance::error::GovernanceError; -use spl_governance_tools::error::GovernanceToolsError; -use spl_token::error::TokenError; - -#[tokio::test] -async fn test_create_mint_governance() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let governed_mint_cookie = governance_test.with_governed_mint().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - // Act - let mint_governance_cookie = governance_test - .with_mint_governance( - &realm_cookie, - &governed_mint_cookie, - &token_owner_record_cookie, - ) - .await - .unwrap(); - - // // Assert - let mint_governance_account = governance_test - .get_governance_account(&mint_governance_cookie.address) - .await; - - assert_eq!(mint_governance_cookie.account, mint_governance_account); - - let mint_account = governance_test - .get_mint_account(&governed_mint_cookie.address) - .await; - - assert_eq!( - mint_governance_cookie.address, - mint_account.mint_authority.unwrap() - ); -} - -#[tokio::test] -async fn test_create_mint_governance_without_transferring_mint_authority() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let mut governed_mint_cookie = governance_test.with_governed_mint().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - governed_mint_cookie.transfer_mint_authority = false; - // Act - let mint_governance_cookie = governance_test - .with_mint_governance( - &realm_cookie, - &governed_mint_cookie, - &token_owner_record_cookie, - ) - .await - .unwrap(); - - // // Assert - let mint_governance_account = governance_test - .get_governance_account(&mint_governance_cookie.address) - .await; - - assert_eq!(mint_governance_cookie.account, mint_governance_account); - - let mint_account = governance_test - .get_mint_account(&governed_mint_cookie.address) - .await; - - assert_eq!( - governed_mint_cookie.mint_authority.pubkey(), - mint_account.mint_authority.unwrap() - ); -} - -#[tokio::test] -async fn test_create_mint_governance_without_transferring_mint_authority_with_invalid_authority_error( -) { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let mut governed_mint_cookie = governance_test.with_governed_mint().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - governed_mint_cookie.transfer_mint_authority = false; - governed_mint_cookie.mint_authority = Keypair::new(); - - // Act - let err = governance_test - .with_mint_governance( - &realm_cookie, - &governed_mint_cookie, - &token_owner_record_cookie, - ) - .await - .err() - .unwrap(); - - // Assert - assert_eq!(err, GovernanceError::InvalidMintAuthority.into()); -} - -#[tokio::test] -async fn test_create_mint_governance_without_transferring_mint_authority_with_authority_not_signed_error( -) { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let mut governed_mint_cookie = governance_test.with_governed_mint().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - governed_mint_cookie.transfer_mint_authority = false; - - // Act - let err = governance_test - .with_mint_governance_using_instruction( - &realm_cookie, - &governed_mint_cookie, - &token_owner_record_cookie, - |i| { - i.accounts[3].is_signer = false; // governed_mint_authority - }, - Some(&[&token_owner_record_cookie.token_owner]), - ) - .await - .err() - .unwrap(); - - // Assert - assert_eq!(err, GovernanceError::MintAuthorityMustSign.into()); -} - -#[tokio::test] -async fn test_create_mint_governance_with_invalid_mint_authority_error() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let mut governed_mint_cookie = governance_test.with_governed_mint().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - governed_mint_cookie.mint_authority = Keypair::new(); - - // Act - let err = governance_test - .with_mint_governance( - &realm_cookie, - &governed_mint_cookie, - &token_owner_record_cookie, - ) - .await - .err() - .unwrap(); - - // Assert - assert_eq!(err, TokenError::OwnerMismatch.into()); -} - -#[tokio::test] -async fn test_create_mint_governance_with_invalid_realm_error() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let mut realm_cookie = governance_test.with_realm().await; - let governed_mint_cookie = governance_test.with_governed_mint().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - let mint_governance_cookie = governance_test - .with_mint_governance( - &realm_cookie, - &governed_mint_cookie, - &token_owner_record_cookie, - ) - .await - .unwrap(); - - // try to use Governance account other than Realm as realm - realm_cookie.address = mint_governance_cookie.address; - - // Act - let err = governance_test - .with_mint_governance( - &realm_cookie, - &governed_mint_cookie, - &token_owner_record_cookie, - ) - .await - .err() - .unwrap(); - - // Assert - assert_eq!(err, GovernanceToolsError::InvalidAccountType.into()); -} - -#[tokio::test] -async fn test_create_mint_governance_with_freeze_authority_transfer() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let governed_mint_cookie = governance_test.with_freezable_governed_mint().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - // Act - let mint_governance_cookie = governance_test - .with_mint_governance( - &realm_cookie, - &governed_mint_cookie, - &token_owner_record_cookie, - ) - .await - .unwrap(); - - // // Assert - let mint_governance_account = governance_test - .get_governance_account(&mint_governance_cookie.address) - .await; - - assert_eq!(mint_governance_cookie.account, mint_governance_account); - - let mint_account = governance_test - .get_mint_account(&governed_mint_cookie.address) - .await; - - assert_eq!( - mint_governance_cookie.address, - mint_account.mint_authority.unwrap() - ); - - assert_eq!( - mint_governance_cookie.address, - mint_account.freeze_authority.unwrap() - ); -} diff --git a/governance/program/tests/process_create_native_treasury.rs b/governance/program/tests/process_create_native_treasury.rs index e44f0527e6e..7a6f37f0844 100644 --- a/governance/program/tests/process_create_native_treasury.rs +++ b/governance/program/tests/process_create_native_treasury.rs @@ -1,4 +1,4 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] use solana_program_test::*; @@ -12,7 +12,6 @@ async fn test_create_native_treasury() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -20,11 +19,7 @@ async fn test_create_native_treasury() { .unwrap(); let governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -48,7 +43,6 @@ async fn test_execute_transfer_from_native_treasury() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -56,11 +50,7 @@ async fn test_execute_transfer_from_native_treasury() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -74,7 +64,11 @@ async fn test_execute_transfer_from_native_treasury() { .unwrap(); let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) .await .unwrap(); @@ -104,7 +98,9 @@ async fn test_execute_transfer_from_native_treasury() { // Advance timestamp past hold_up_time governance_test - .advance_clock_by_min_timespan(proposal_transaction_cookie.account.hold_up_time as u64) + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) .await; // Act diff --git a/governance/program/tests/process_create_program_governance.rs b/governance/program/tests/process_create_program_governance.rs deleted file mode 100644 index e8dd1414bee..00000000000 --- a/governance/program/tests/process_create_program_governance.rs +++ /dev/null @@ -1,237 +0,0 @@ -#![cfg(feature = "test-bpf")] -mod program_test; - -use solana_program_test::*; - -use program_test::*; -use solana_sdk::signature::{Keypair, Signer}; -use spl_governance::{ - error::GovernanceError, tools::bpf_loader_upgradeable::get_program_upgrade_authority, -}; -use spl_governance_test_sdk::tools::ProgramInstructionError; -use spl_governance_tools::error::GovernanceToolsError; - -#[tokio::test] -async fn test_create_program_governance() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let governed_program_cookie = governance_test.with_governed_program().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - // Act - let program_governance_cookie = governance_test - .with_program_governance( - &realm_cookie, - &governed_program_cookie, - &token_owner_record_cookie, - ) - .await - .unwrap(); - - // Assert - let program_governance_account = governance_test - .get_governance_account(&program_governance_cookie.address) - .await; - - assert_eq!( - program_governance_cookie.account, - program_governance_account - ); - - let program_data = governance_test - .get_upgradable_loader_account(&governed_program_cookie.data_address) - .await; - - let upgrade_authority = get_program_upgrade_authority(&program_data).unwrap(); - - assert_eq!(Some(program_governance_cookie.address), upgrade_authority); -} - -#[tokio::test] -async fn test_create_program_governance_without_transferring_upgrade_authority() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let mut governed_program_cookie = governance_test.with_governed_program().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - governed_program_cookie.transfer_upgrade_authority = false; - - // Act - let program_governance_cookie = governance_test - .with_program_governance( - &realm_cookie, - &governed_program_cookie, - &token_owner_record_cookie, - ) - .await - .unwrap(); - - // Assert - let program_governance_account = governance_test - .get_governance_account(&program_governance_cookie.address) - .await; - - assert_eq!( - program_governance_cookie.account, - program_governance_account - ); - - let program_data = governance_test - .get_upgradable_loader_account(&governed_program_cookie.data_address) - .await; - - let upgrade_authority = get_program_upgrade_authority(&program_data).unwrap(); - - assert_eq!( - Some(governed_program_cookie.upgrade_authority.pubkey()), - upgrade_authority - ); -} - -#[tokio::test] -async fn test_create_program_governance_without_transferring_upgrade_authority_with_invalid_authority_error( -) { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let mut governed_program_cookie = governance_test.with_governed_program().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - governed_program_cookie.transfer_upgrade_authority = false; - governed_program_cookie.upgrade_authority = Keypair::new(); - - // Act - let err = governance_test - .with_program_governance( - &realm_cookie, - &governed_program_cookie, - &token_owner_record_cookie, - ) - .await - .err() - .unwrap(); - - // Assert - assert_eq!(err, GovernanceError::InvalidUpgradeAuthority.into()); -} - -#[tokio::test] -async fn test_create_program_governance_without_transferring_upgrade_authority_with_authority_not_signed_error( -) { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let mut governed_program_cookie = governance_test.with_governed_program().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - governed_program_cookie.transfer_upgrade_authority = false; - - // Act - let err = governance_test - .with_program_governance_using_instruction( - &realm_cookie, - &governed_program_cookie, - &token_owner_record_cookie, - |i| { - i.accounts[4].is_signer = false; // governed_program_upgrade_authority - }, - Some(&[&token_owner_record_cookie.token_owner]), - ) - .await - .err() - .unwrap(); - - // Assert - assert_eq!(err, GovernanceError::UpgradeAuthorityMustSign.into()); -} - -#[tokio::test] -async fn test_create_program_governance_with_incorrect_upgrade_authority_error() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let mut governed_program_cookie = governance_test.with_governed_program().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - governed_program_cookie.upgrade_authority = Keypair::new(); - - // Act - let err = governance_test - .with_program_governance( - &realm_cookie, - &governed_program_cookie, - &token_owner_record_cookie, - ) - .await - .err() - .unwrap(); - - // Assert - assert_eq!(err, ProgramInstructionError::IncorrectAuthority.into()); -} - -#[tokio::test] -async fn test_create_program_governance_with_invalid_realm_error() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let mut realm_cookie = governance_test.with_realm().await; - let governed_program_cookie = governance_test.with_governed_program().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - let program_governance_cookie = governance_test - .with_program_governance( - &realm_cookie, - &governed_program_cookie, - &token_owner_record_cookie, - ) - .await - .unwrap(); - - realm_cookie.address = program_governance_cookie.address; - - // Act - let err = governance_test - .with_program_governance( - &realm_cookie, - &governed_program_cookie, - &token_owner_record_cookie, - ) - .await - .err() - .unwrap(); - - // Assert - assert_eq!(err, GovernanceToolsError::InvalidAccountType.into()); -} diff --git a/governance/program/tests/process_create_proposal.rs b/governance/program/tests/process_create_proposal.rs index 4dd29b56eee..1d8e241c2ae 100644 --- a/governance/program/tests/process_create_proposal.rs +++ b/governance/program/tests/process_create_proposal.rs @@ -1,13 +1,21 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] -use solana_program::{instruction::AccountMeta, pubkey::Pubkey}; -use solana_program_test::*; +use { + solana_program::{instruction::AccountMeta, pubkey::Pubkey}, + solana_program_test::*, +}; mod program_test; -use program_test::*; -use solana_sdk::signature::Keypair; -use spl_governance::{error::GovernanceError, state::enums::VoteThreshold}; +use { + program_test::*, + solana_sdk::signature::Keypair, + spl_governance::{ + error::GovernanceError, + state::{enums::VoteThreshold, governance::SECURITY_DEPOSIT_BASE_LAMPORTS}, + }, + spl_governance_tools::account::AccountMaxSize, +}; #[tokio::test] async fn test_create_community_proposal() { @@ -15,7 +23,6 @@ async fn test_create_community_proposal() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -23,11 +30,7 @@ async fn test_create_community_proposal() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -44,17 +47,17 @@ async fn test_create_community_proposal() { assert_eq!(proposal_cookie.account, proposal_account); - let governance_account = governance_test - .get_governance_account(&governance_cookie.address) - .await; - - assert_eq!(1, governance_account.proposals_count); - let token_owner_record_account = governance_test .get_token_owner_record_account(&token_owner_record_cookie.address) .await; assert_eq!(1, token_owner_record_account.outstanding_proposal_count); + + let governance_account = governance_test + .get_governance_account(&governance_cookie.address) + .await; + + assert_eq!(1, governance_account.active_proposal_count); } #[tokio::test] @@ -63,7 +66,6 @@ async fn test_create_multiple_proposals() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let community_token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -71,11 +73,7 @@ async fn test_create_multiple_proposals() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &community_token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &community_token_owner_record_cookie) .await .unwrap(); @@ -110,12 +108,6 @@ async fn test_create_multiple_proposals() { .await; assert_eq!(council_proposal_cookie.account, council_proposal_account); - - let governance_account = governance_test - .get_governance_account(&governance_cookie.address) - .await; - - assert_eq!(2, governance_account.proposals_count); } #[tokio::test] @@ -124,7 +116,6 @@ async fn test_create_proposal_with_not_authorized_governance_authority_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let mut token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -132,11 +123,7 @@ async fn test_create_proposal_with_not_authorized_governance_authority_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -162,7 +149,6 @@ async fn test_create_proposal_with_governance_delegate_signer() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let mut token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -170,11 +156,7 @@ async fn test_create_proposal_with_governance_delegate_signer() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -205,7 +187,6 @@ async fn test_create_proposal_with_not_enough_community_tokens_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie1 = governance_test .with_community_token_deposit(&realm_cookie) @@ -213,11 +194,7 @@ async fn test_create_proposal_with_not_enough_community_tokens_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie1, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie1) .await .unwrap(); @@ -246,7 +223,6 @@ async fn test_create_proposal_with_not_enough_council_tokens_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; // Set token deposit amount below the required threshold let token_amount = 1; @@ -257,11 +233,7 @@ async fn test_create_proposal_with_not_enough_council_tokens_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -282,7 +254,6 @@ async fn test_create_proposal_with_owner_or_delegate_must_sign_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -290,11 +261,7 @@ async fn test_create_proposal_with_owner_or_delegate_must_sign_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -327,7 +294,6 @@ async fn test_create_proposal_with_invalid_governing_token_mint_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let mut token_owner_record_cookie = governance_test .with_council_token_deposit(&realm_cookie) @@ -335,11 +301,7 @@ async fn test_create_proposal_with_invalid_governing_token_mint_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -363,7 +325,6 @@ async fn test_create_community_proposal_using_council_tokens() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let mut community_token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -371,11 +332,7 @@ async fn test_create_community_proposal_using_council_tokens() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &community_token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &community_token_owner_record_cookie) .await .unwrap(); @@ -416,7 +373,6 @@ async fn test_create_council_proposal_using_community_tokens() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let mut council_token_owner_record_cookie = governance_test .with_council_token_deposit(&realm_cookie) @@ -424,11 +380,7 @@ async fn test_create_council_proposal_using_community_tokens() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &council_token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &council_token_owner_record_cookie) .await .unwrap(); @@ -469,7 +421,6 @@ async fn test_create_proposal_with_disabled_council_vote_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_council_token_deposit(&realm_cookie) @@ -482,7 +433,6 @@ async fn test_create_proposal_with_disabled_council_vote_error() { let mut governance_cookie = governance_test .with_governance_using_config( &realm_cookie, - &governed_account_cookie, &token_owner_record_cookie, &governance_config, ) @@ -509,7 +459,6 @@ async fn test_create_proposal_with_disabled_community_vote_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -522,7 +471,6 @@ async fn test_create_proposal_with_disabled_community_vote_error() { let mut governance_cookie = governance_test .with_governance_using_config( &realm_cookie, - &governed_account_cookie, &token_owner_record_cookie, &governance_config, ) @@ -542,3 +490,229 @@ async fn test_create_proposal_with_disabled_community_vote_error() { GovernanceError::GoverningTokenMintNotAllowedToVote.into() ); } + +#[tokio::test] +async fn test_create_proposal_with_invalid_realm_config_account_address_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + // Try bypass config check by using none existing config account + let realm_config_address = Pubkey::new_unique(); + + // Act + let err = governance_test + .with_proposal_using_instruction(&token_owner_record_cookie, &mut governance_cookie, |i| { + i.accounts[8].pubkey = realm_config_address; + }) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::InvalidRealmConfigAddress.into()); +} + +#[tokio::test] +async fn test_create_proposal_with_community_disabled_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + // Set token deposit amount to max + let token_amount = u64::MAX; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit_amount(&realm_cookie, token_amount) + .await + .unwrap(); + + let mut governance_config = governance_test.get_default_governance_config(); + governance_config.min_community_weight_to_create_proposal = u64::MAX; + + let mut governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie, + &governance_config, + ) + .await + .unwrap(); + + // Act + let err = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::VoterWeightThresholdDisabled.into()); +} + +#[tokio::test] +async fn test_create_proposal_with_security_deposit() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_config = governance_test.get_default_governance_config(); + // Deposit is taken for every Proposal + governance_config.deposit_exempt_proposal_count = 0; + + let mut governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie, + &governance_config, + ) + .await + .unwrap(); + + // Act + let proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + // Assert + + let proposal_deposit_account = governance_test + .get_proposal_deposit_account(&proposal_cookie.proposal_deposit.address) + .await; + + assert_eq!( + proposal_cookie.proposal_deposit.account, + proposal_deposit_account + ); + + let proposal_deposit_account_info = governance_test + .bench + .get_account(&proposal_cookie.proposal_deposit.address) + .await + .unwrap(); + + let expected_lamports = governance_test + .bench + .rent + .minimum_balance(proposal_deposit_account.get_max_size().unwrap()) + + SECURITY_DEPOSIT_BASE_LAMPORTS; + + assert_eq!(expected_lamports, proposal_deposit_account_info.lamports); +} + +#[tokio::test] +async fn test_create_multiple_proposals_with_security_deposits() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_config = governance_test.get_default_governance_config(); + // Make the fist Proposal deposit free and take the deposit for Proposal 2 & 3 + governance_config.deposit_exempt_proposal_count = 1; + + let mut governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie, + &governance_config, + ) + .await + .unwrap(); + + // Act + let proposal_cookie1 = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + let proposal_cookie2 = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + let proposal_cookie3 = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + // Assert + let proposal_deposit_account_info1 = governance_test + .bench + .get_account(&proposal_cookie1.proposal_deposit.address) + .await; + + assert_eq!(None, proposal_deposit_account_info1); + + // Proposal 2 + let proposal_deposit_account2 = governance_test + .get_proposal_deposit_account(&proposal_cookie2.proposal_deposit.address) + .await; + + assert_eq!( + proposal_cookie2.proposal_deposit.account, + proposal_deposit_account2 + ); + + let proposal_deposit_account_info2 = governance_test + .bench + .get_account(&proposal_cookie2.proposal_deposit.address) + .await + .unwrap(); + + let expected_lamports = governance_test + .bench + .rent + .minimum_balance(proposal_deposit_account2.get_max_size().unwrap()) + + SECURITY_DEPOSIT_BASE_LAMPORTS; + + assert_eq!(expected_lamports, proposal_deposit_account_info2.lamports); + + // Proposal 3 + let proposal_deposit_account3 = governance_test + .get_proposal_deposit_account(&proposal_cookie3.proposal_deposit.address) + .await; + + assert_eq!( + proposal_cookie3.proposal_deposit.account, + proposal_deposit_account3 + ); + + let proposal_deposit_account_info3 = governance_test + .bench + .get_account(&proposal_cookie3.proposal_deposit.address) + .await + .unwrap(); + + let expected_lamports = governance_test + .bench + .rent + .minimum_balance(proposal_deposit_account3.get_max_size().unwrap()) + + 2 * SECURITY_DEPOSIT_BASE_LAMPORTS; + + assert_eq!(expected_lamports, proposal_deposit_account_info3.lamports); +} diff --git a/governance/program/tests/process_create_realm.rs b/governance/program/tests/process_create_realm.rs index 48e2e8404da..d380bcbcb0b 100644 --- a/governance/program/tests/process_create_realm.rs +++ b/governance/program/tests/process_create_realm.rs @@ -1,17 +1,15 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] use solana_program_test::*; mod program_test; -use program_test::*; -use spl_governance::state::{ - enums::MintMaxVoteWeightSource, - realm::{get_realm_address, RealmConfigArgs}, +use { + crate::program_test::args::RealmSetupArgs, + program_test::*, + spl_governance::state::{enums::MintMaxVoterWeightSource, realm::get_realm_address}, }; -use self::args::SetRealmConfigArgs; - #[tokio::test] async fn test_create_realm() { // Arrange @@ -33,23 +31,39 @@ async fn test_create_realm_with_non_default_config() { // Arrange let mut governance_test = GovernanceProgramTest::start_new().await; - let realm_config_args = RealmConfigArgs { + let realm_setup_args = RealmSetupArgs { use_council_mint: false, - community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(1), - min_community_weight_to_create_governance: 10, - use_community_voter_weight_addin: false, - use_max_community_voter_weight_addin: false, + community_mint_max_voter_weight_source: MintMaxVoterWeightSource::SupplyFraction(1), + min_community_weight_to_create_governance: 1, + ..Default::default() }; - let set_realm_config_args = SetRealmConfigArgs { - realm_config_args, - community_voter_weight_addin: None, - max_community_voter_weight_addin: None, + // Act + let realm_cookie = governance_test + .with_realm_using_args(&realm_setup_args) + .await; + + // Assert + let realm_account = governance_test + .get_realm_account(&realm_cookie.address) + .await; + + assert_eq!(realm_cookie.account, realm_account); +} + +#[tokio::test] +async fn test_create_realm_with_max_voter_weight_absolute_value() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_setup_args = RealmSetupArgs { + community_mint_max_voter_weight_source: MintMaxVoterWeightSource::Absolute(1), + ..Default::default() }; // Act let realm_cookie = governance_test - .with_realm_using_config_args(&set_realm_config_args) + .with_realm_using_args(&realm_setup_args) .await; // Assert @@ -58,6 +72,13 @@ async fn test_create_realm_with_non_default_config() { .await; assert_eq!(realm_cookie.account, realm_account); + assert_eq!( + realm_cookie + .account + .config + .community_mint_max_voter_weight_source, + MintMaxVoterWeightSource::Absolute(1) + ); } #[tokio::test] diff --git a/governance/program/tests/process_create_token_governance.rs b/governance/program/tests/process_create_token_governance.rs deleted file mode 100644 index 55486a85e0d..00000000000 --- a/governance/program/tests/process_create_token_governance.rs +++ /dev/null @@ -1,278 +0,0 @@ -#![cfg(feature = "test-bpf")] -mod program_test; - -use solana_program_test::*; - -use program_test::*; -use solana_sdk::{signature::Keypair, signer::Signer}; -use spl_governance::error::GovernanceError; -use spl_governance_tools::error::GovernanceToolsError; - -use spl_token::{error::TokenError, instruction::AuthorityType}; - -#[tokio::test] -async fn test_create_token_governance() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let governed_token_cookie = governance_test.with_governed_token().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - // Act - let token_governance_cookie = governance_test - .with_token_governance( - &realm_cookie, - &governed_token_cookie, - &token_owner_record_cookie, - ) - .await - .unwrap(); - - // Assert - let token_governance_account = governance_test - .get_governance_account(&token_governance_cookie.address) - .await; - - assert_eq!(token_governance_cookie.account, token_governance_account); - - let token_account = governance_test - .get_token_account(&governed_token_cookie.address) - .await; - - assert_eq!(token_governance_cookie.address, token_account.owner); -} - -#[tokio::test] -async fn test_create_token_governance_without_transferring_token_owner() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let mut governed_token_cookie = governance_test.with_governed_token().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - governed_token_cookie.transfer_token_owner = false; - - // Act - let token_governance_cookie = governance_test - .with_token_governance( - &realm_cookie, - &governed_token_cookie, - &token_owner_record_cookie, - ) - .await - .unwrap(); - - // Assert - let token_governance_account = governance_test - .get_governance_account(&token_governance_cookie.address) - .await; - - assert_eq!(token_governance_cookie.account, token_governance_account); - - let token_account = governance_test - .get_token_account(&governed_token_cookie.address) - .await; - - assert_eq!( - governed_token_cookie.token_owner.pubkey(), - token_account.owner - ); -} - -#[tokio::test] -async fn test_create_token_governance_without_transferring_token_owner_with_invalid_token_owner_error( -) { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let mut governed_token_cookie = governance_test.with_governed_token().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - governed_token_cookie.transfer_token_owner = false; - governed_token_cookie.token_owner = Keypair::new(); - - // Act - let err = governance_test - .with_token_governance( - &realm_cookie, - &governed_token_cookie, - &token_owner_record_cookie, - ) - .await - .err() - .unwrap(); - - // Assert - assert_eq!(err, GovernanceError::InvalidTokenOwner.into()); -} - -#[tokio::test] -async fn test_create_token_governance_without_transferring_token_owner_with_owner_not_signed_error() -{ - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let mut governed_token_cookie = governance_test.with_governed_token().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - governed_token_cookie.transfer_token_owner = false; - - // Act - let err = governance_test - .with_token_governance_using_instruction( - &realm_cookie, - &governed_token_cookie, - &token_owner_record_cookie, - |i| { - i.accounts[3].is_signer = false; // governed_token_owner - }, - Some(&[&token_owner_record_cookie.token_owner]), - ) - .await - .err() - .unwrap(); - - // Assert - assert_eq!(err, GovernanceError::TokenOwnerMustSign.into()); -} - -#[tokio::test] -async fn test_create_token_governance_with_invalid_token_owner_error() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let mut governed_token_cookie = governance_test.with_governed_token().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - governed_token_cookie.token_owner = Keypair::new(); - - // Act - let err = governance_test - .with_token_governance( - &realm_cookie, - &governed_token_cookie, - &token_owner_record_cookie, - ) - .await - .err() - .unwrap(); - - // Assert - assert_eq!(err, TokenError::OwnerMismatch.into()); -} - -#[tokio::test] -async fn test_create_token_governance_with_invalid_realm_error() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let mut realm_cookie = governance_test.with_realm().await; - let governed_token_cookie = governance_test.with_governed_token().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - let token_governance_cookie = governance_test - .with_token_governance( - &realm_cookie, - &governed_token_cookie, - &token_owner_record_cookie, - ) - .await - .unwrap(); - - // try to use Governance account other than Realm as realm - realm_cookie.address = token_governance_cookie.address; - - // Act - let err = governance_test - .with_token_governance( - &realm_cookie, - &governed_token_cookie, - &token_owner_record_cookie, - ) - .await - .err() - .unwrap(); - - // Assert - assert_eq!(err, GovernanceToolsError::InvalidAccountType.into()); -} - -#[tokio::test] -async fn test_create_token_governance_with_close_authority_transfer() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let governed_token_cookie = governance_test.with_governed_token().await; - - governance_test - .bench - .set_spl_token_account_authority( - &governed_token_cookie.address, - &governed_token_cookie.token_owner, - Some(&governed_token_cookie.token_owner.pubkey()), - AuthorityType::CloseAccount, - ) - .await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - // Act - let token_governance_cookie = governance_test - .with_token_governance( - &realm_cookie, - &governed_token_cookie, - &token_owner_record_cookie, - ) - .await - .unwrap(); - - // Assert - let token_governance_account = governance_test - .get_governance_account(&token_governance_cookie.address) - .await; - - assert_eq!(token_governance_cookie.account, token_governance_account); - - let token_account = governance_test - .get_token_account(&governed_token_cookie.address) - .await; - - assert_eq!(token_governance_cookie.address, token_account.owner); - assert_eq!( - token_governance_cookie.address, - token_account.close_authority.unwrap() - ); -} diff --git a/governance/program/tests/process_create_token_owner_record.rs b/governance/program/tests/process_create_token_owner_record.rs index 2b81bd6d81c..99b47f74c7e 100644 --- a/governance/program/tests/process_create_token_owner_record.rs +++ b/governance/program/tests/process_create_token_owner_record.rs @@ -1,10 +1,12 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] use solana_program_test::*; mod program_test; -use program_test::*; +use { + program_test::*, spl_governance::state::token_owner_record::TOKEN_OWNER_RECORD_LAYOUT_VERSION, +}; #[tokio::test] async fn test_create_token_owner_record() { @@ -24,6 +26,12 @@ async fn test_create_token_owner_record() { assert_eq!(0, token_owner_record_account.governing_token_deposit_amount); + assert_eq!( + TOKEN_OWNER_RECORD_LAYOUT_VERSION, + token_owner_record_account.version + ); + assert_eq!(0, token_owner_record_account.unrelinquished_votes_count); + assert_eq!( token_owner_record_cookie.account, token_owner_record_account diff --git a/governance/program/tests/process_deposit_governing_tokens.rs b/governance/program/tests/process_deposit_governing_tokens.rs index b5163ac5df3..bd921685a42 100644 --- a/governance/program/tests/process_deposit_governing_tokens.rs +++ b/governance/program/tests/process_deposit_governing_tokens.rs @@ -1,13 +1,21 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] -use solana_program::instruction::AccountMeta; -use solana_program_test::*; +use {solana_program::instruction::AccountMeta, solana_program_test::*}; mod program_test; -use program_test::*; -use solana_sdk::signature::{Keypair, Signer}; -use spl_governance::{error::GovernanceError, instruction::deposit_governing_tokens}; +use { + crate::program_test::args::*, + program_test::*, + solana_sdk::signature::{Keypair, Signer}, + spl_governance::{ + error::GovernanceError, + instruction::deposit_governing_tokens, + state::{ + realm_config::GoverningTokenType, token_owner_record::TOKEN_OWNER_RECORD_LAYOUT_VERSION, + }, + }, +}; #[tokio::test] async fn test_deposit_initial_community_tokens() { @@ -29,6 +37,12 @@ async fn test_deposit_initial_community_tokens() { assert_eq!(token_owner_record_cookie.account, token_owner_record); + assert_eq!( + TOKEN_OWNER_RECORD_LAYOUT_VERSION, + token_owner_record.version + ); + assert_eq!(0, token_owner_record.unrelinquished_votes_count); + let source_account = governance_test .get_token_account(&token_owner_record_cookie.token_source) .await; @@ -235,55 +249,6 @@ async fn test_deposit_initial_community_tokens_with_owner_must_sign_error() { // Assert assert_eq!(error, GovernanceError::GoverningTokenOwnerMustSign.into()); } -#[tokio::test] -async fn test_deposit_initial_community_tokens_with_invalid_owner_error() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - let realm_cookie = governance_test.with_realm().await; - - let token_owner = Keypair::new(); - let transfer_authority = Keypair::new(); - let token_source = Keypair::new(); - - let invalid_owner = Keypair::new(); - - let amount = 10; - - governance_test - .bench - .create_token_account_with_transfer_authority( - &token_source, - &realm_cookie.account.community_mint, - &realm_cookie.community_mint_authority, - amount, - &token_owner, - &transfer_authority.pubkey(), - ) - .await; - - let deposit_ix = deposit_governing_tokens( - &governance_test.program_id, - &realm_cookie.address, - &token_source.pubkey(), - &invalid_owner.pubkey(), - &transfer_authority.pubkey(), - &governance_test.bench.context.payer.pubkey(), - amount, - &realm_cookie.account.community_mint, - ); - - // // Act - - let error = governance_test - .bench - .process_transaction(&[deposit_ix], Some(&[&transfer_authority, &invalid_owner])) - .await - .err() - .unwrap(); - - // Assert - assert_eq!(error, GovernanceError::GoverningTokenOwnerMustSign.into()); -} #[tokio::test] async fn test_deposit_community_tokens_with_malicious_holding_account_error() { @@ -340,3 +305,62 @@ async fn test_deposit_community_tokens_with_malicious_holding_account_error() { GovernanceError::InvalidGoverningTokenHoldingAccount.into() ); } + +#[tokio::test] +async fn test_deposit_community_tokens_using_mint() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + let realm_cookie = governance_test.with_realm().await; + + // Act + let token_owner_record_cookie = governance_test + .with_initial_governing_token_deposit_using_mint( + &realm_cookie.address, + &realm_cookie.account.community_mint, + &realm_cookie.community_mint_authority, + 10, + None, + ) + .await + .unwrap(); + + // Assert + + let token_owner_record = governance_test + .get_token_owner_record_account(&token_owner_record_cookie.address) + .await; + + assert_eq!(token_owner_record_cookie.account, token_owner_record); + + let holding_account = governance_test + .get_token_account(&realm_cookie.community_token_holding_account) + .await; + + assert_eq!( + token_owner_record.governing_token_deposit_amount, + holding_account.amount + ); +} + +#[tokio::test] +async fn test_deposit_comunity_tokens_with_cannot_deposit_dormant_tokens_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let mut realm_config_args = RealmSetupArgs::default(); + realm_config_args.council_token_config_args.token_type = GoverningTokenType::Dormant; + + let realm_cookie = governance_test + .with_realm_using_args(&realm_config_args) + .await; + + // Act + let err = governance_test + .with_council_token_deposit(&realm_cookie) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::CannotDepositDormantTokens.into()); +} diff --git a/governance/program/tests/process_execute_transaction.rs b/governance/program/tests/process_execute_transaction.rs index cd7c2e05f31..df5930899fd 100644 --- a/governance/program/tests/process_execute_transaction.rs +++ b/governance/program/tests/process_execute_transaction.rs @@ -1,18 +1,19 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] mod program_test; -use solana_program::{ - instruction::{AccountMeta, Instruction}, - program_error::ProgramError, - sysvar::clock, -}; -use solana_program_test::tokio; - -use program_test::*; -use spl_governance::{ - error::GovernanceError, - state::enums::{ProposalState, TransactionExecutionStatus}, +use { + program_test::*, + solana_program::{ + instruction::{AccountMeta, Instruction}, + program_error::ProgramError, + sysvar::clock, + }, + solana_program_test::tokio, + spl_governance::{ + error::GovernanceError, + state::enums::{ProposalState, TransactionExecutionStatus}, + }, }; #[tokio::test] @@ -21,29 +22,30 @@ async fn test_execute_mint_transaction() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_mint_cookie = governance_test.with_governed_mint().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) .await .unwrap(); - let mut mint_governance_cookie = governance_test - .with_mint_governance( - &realm_cookie, - &governed_mint_cookie, - &token_owner_record_cookie, - ) + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); + let governed_mint_cookie = governance_test.with_governed_mint(&governance_cookie).await; + let mut proposal_cookie = governance_test - .with_proposal(&token_owner_record_cookie, &mut mint_governance_cookie) + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) .await .unwrap(); let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) .await .unwrap(); @@ -54,7 +56,6 @@ async fn test_execute_mint_transaction() { &token_owner_record_cookie, 0, None, - None, ) .await .unwrap(); @@ -71,7 +72,9 @@ async fn test_execute_mint_transaction() { // Advance timestamp past hold_up_time governance_test - .advance_clock_by_min_timespan(proposal_transaction_cookie.account.hold_up_time as u64) + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) .await; let clock = governance_test.bench.get_clock().await; @@ -122,35 +125,38 @@ async fn test_execute_transfer_transaction() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_token_cookie = governance_test.with_governed_token().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) .await .unwrap(); - let mut token_governance_cookie = governance_test - .with_token_governance( - &realm_cookie, - &governed_token_cookie, - &token_owner_record_cookie, - ) + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); + let governed_token_account_cookie = governance_test + .with_governed_token_account(&governance_cookie) + .await; + let mut proposal_cookie = governance_test - .with_proposal(&token_owner_record_cookie, &mut token_governance_cookie) + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) .await .unwrap(); let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) .await .unwrap(); let proposal_transaction_cookie = governance_test .with_transfer_tokens_transaction( - &governed_token_cookie, + &governed_token_account_cookie, &mut proposal_cookie, &token_owner_record_cookie, None, @@ -170,7 +176,9 @@ async fn test_execute_transfer_transaction() { // Advance timestamp past hold_up_time governance_test - .advance_clock_by_min_timespan(proposal_transaction_cookie.account.hold_up_time as u64) + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) .await; let clock = governance_test.bench.get_clock().await; @@ -215,41 +223,48 @@ async fn test_execute_transfer_transaction() { assert_eq!(15, instruction_token_account.amount); } +// Ignored until program-test manages fork graphs correctly, see +// https://github.com/solana-labs/solana/pull/34407 for the failing downstream +// test #[tokio::test] +#[ignore] async fn test_execute_upgrade_program_transaction() { // Arrange let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_program_cookie = governance_test.with_governed_program().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) .await .unwrap(); - let mut program_governance_cookie = governance_test - .with_program_governance( - &realm_cookie, - &governed_program_cookie, - &token_owner_record_cookie, - ) + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); + let governed_program_cookie = governance_test + .with_governed_program(&governance_cookie) + .await; + let mut proposal_cookie = governance_test - .with_proposal(&token_owner_record_cookie, &mut program_governance_cookie) + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) .await .unwrap(); let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) .await .unwrap(); let proposal_transaction_cookie = governance_test .with_upgrade_program_transaction( - &program_governance_cookie, + &governance_cookie, &mut proposal_cookie, &token_owner_record_cookie, ) @@ -268,7 +283,9 @@ async fn test_execute_upgrade_program_transaction() { // Advance timestamp past hold_up_time governance_test - .advance_clock_by_min_timespan(proposal_transaction_cookie.account.hold_up_time as u64) + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) .await; // Ensure we can invoke the governed program before upgrade @@ -347,34 +364,39 @@ async fn test_execute_proposal_transaction_with_invalid_state_errors() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_mint_cookie = governance_test.with_governed_mint().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) .await .unwrap(); - let mut mint_governance_cookie = governance_test - .with_mint_governance( - &realm_cookie, - &governed_mint_cookie, - &token_owner_record_cookie, - ) + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); + let governed_mint_cookie = governance_test.with_governed_mint(&governance_cookie).await; + let mut proposal_cookie = governance_test - .with_proposal(&token_owner_record_cookie, &mut mint_governance_cookie) + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) .await .unwrap(); let signatory_record_cookie1 = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) .await .unwrap(); let signatory_record_cookie2 = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) .await .unwrap(); @@ -385,7 +407,6 @@ async fn test_execute_proposal_transaction_with_invalid_state_errors() { &token_owner_record_cookie, 0, None, - None, ) .await .unwrap(); @@ -471,7 +492,9 @@ async fn test_execute_proposal_transaction_with_invalid_state_errors() { // Arrange // Advance timestamp past hold_up_time governance_test - .advance_clock_by_min_timespan(proposal_transaction_cookie.account.hold_up_time as u64) + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) .await; // Act @@ -512,29 +535,30 @@ async fn test_execute_proposal_transaction_for_other_proposal_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_mint_cookie = governance_test.with_governed_mint().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) .await .unwrap(); - let mut mint_governance_cookie = governance_test - .with_mint_governance( - &realm_cookie, - &governed_mint_cookie, - &token_owner_record_cookie, - ) + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); + let governed_mint_cookie = governance_test.with_governed_mint(&governance_cookie).await; + let mut proposal_cookie = governance_test - .with_proposal(&token_owner_record_cookie, &mut mint_governance_cookie) + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) .await .unwrap(); let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) .await .unwrap(); @@ -545,7 +569,6 @@ async fn test_execute_proposal_transaction_for_other_proposal_error() { &token_owner_record_cookie, 0, None, - None, ) .await .unwrap(); @@ -563,7 +586,9 @@ async fn test_execute_proposal_transaction_for_other_proposal_error() { // Advance clock past hold_up_time governance_test - .advance_clock_by_min_timespan(proposal_transaction_cookie.account.hold_up_time as u64) + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) .await; let token_owner_record_cookie2 = governance_test @@ -572,7 +597,7 @@ async fn test_execute_proposal_transaction_for_other_proposal_error() { .unwrap(); let proposal_cookie2 = governance_test - .with_proposal(&token_owner_record_cookie2, &mut mint_governance_cookie) + .with_proposal(&token_owner_record_cookie2, &mut governance_cookie) .await .unwrap(); @@ -598,29 +623,30 @@ async fn test_execute_mint_transaction_twice_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_mint_cookie = governance_test.with_governed_mint().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) .await .unwrap(); - let mut mint_governance_cookie = governance_test - .with_mint_governance( - &realm_cookie, - &governed_mint_cookie, - &token_owner_record_cookie, - ) + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); + let governed_mint_cookie = governance_test.with_governed_mint(&governance_cookie).await; + let mut proposal_cookie = governance_test - .with_proposal(&token_owner_record_cookie, &mut mint_governance_cookie) + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) .await .unwrap(); let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) .await .unwrap(); @@ -631,7 +657,6 @@ async fn test_execute_mint_transaction_twice_error() { &token_owner_record_cookie, 0, None, - None, ) .await .unwrap(); @@ -654,7 +679,9 @@ async fn test_execute_mint_transaction_twice_error() { // Advance clock past hold_up_time governance_test - .advance_clock_by_min_timespan(proposal_transaction_cookie.account.hold_up_time as u64) + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) .await; governance_test @@ -682,7 +709,6 @@ async fn test_execute_transaction_with_create_proposal_and_execute_in_single_slo let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_mint_cookie = governance_test.with_governed_mint().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -690,25 +716,30 @@ async fn test_execute_transaction_with_create_proposal_and_execute_in_single_slo .unwrap(); let mut governance_config = governance_test.get_default_governance_config(); - governance_config.min_transaction_hold_up_time = 0; + governance_config.transactions_hold_up_time = 0; - let mut mint_governance_cookie = governance_test - .with_mint_governance_using_config( + let mut governance_cookie = governance_test + .with_governance_using_config( &realm_cookie, - &governed_mint_cookie, &token_owner_record_cookie, &governance_config, ) .await .unwrap(); + let governed_mint_cookie = governance_test.with_governed_mint(&governance_cookie).await; + let mut proposal_cookie = governance_test - .with_proposal(&token_owner_record_cookie, &mut mint_governance_cookie) + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) .await .unwrap(); let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) .await .unwrap(); @@ -719,7 +750,6 @@ async fn test_execute_transaction_with_create_proposal_and_execute_in_single_slo &token_owner_record_cookie, 0, None, - Some(0), ) .await .unwrap(); diff --git a/governance/program/tests/process_finalize_vote.rs b/governance/program/tests/process_finalize_vote.rs index 6a56dcce57c..c7ea681f6cb 100644 --- a/governance/program/tests/process_finalize_vote.rs +++ b/governance/program/tests/process_finalize_vote.rs @@ -1,13 +1,14 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] mod program_test; -use solana_program_test::tokio; - -use program_test::*; -use spl_governance::{ - error::GovernanceError, - state::enums::{ProposalState, VoteThreshold}, +use { + program_test::*, + solana_program_test::tokio, + spl_governance::{ + error::GovernanceError, + state::enums::{ProposalState, VoteThreshold}, + }, }; #[tokio::test] @@ -16,7 +17,6 @@ async fn test_finalize_vote_to_succeeded() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let mut governance_config = governance_test.get_default_governance_config(); @@ -30,7 +30,6 @@ async fn test_finalize_vote_to_succeeded() { let mut governance_cookie = governance_test .with_governance_using_config( &realm_cookie, - &governed_account_cookie, &token_owner_record_cookie, &governance_config, ) @@ -62,7 +61,7 @@ async fn test_finalize_vote_to_succeeded() { // Advance timestamp past max_voting_time governance_test .advance_clock_past_timestamp( - governance_cookie.account.config.max_voting_time as i64 + governance_cookie.account.config.voting_base_time as i64 + proposal_account.voting_at.unwrap(), ) .await; @@ -82,7 +81,7 @@ async fn test_finalize_vote_to_succeeded() { assert_eq!(proposal_account.state, ProposalState::Succeeded); assert_eq!( - Some(proposal_account.vote_end_time(&governance_cookie.account.config)), + Some(proposal_account.voting_max_time_end(&governance_cookie.account.config)), proposal_account.voting_completed_at ); @@ -99,17 +98,11 @@ async fn test_finalize_vote_to_succeeded() { assert_eq!(0, proposal_owner_record.outstanding_proposal_count); - let realm_account = governance_test - .get_realm_account(&realm_cookie.address) - .await; - - assert_eq!(0, realm_account.voting_proposal_count); - let governance_account = governance_test .get_governance_account(&governance_cookie.address) .await; - assert_eq!(0, governance_account.voting_proposal_count); + assert_eq!(0, governance_account.active_proposal_count); } #[tokio::test] @@ -118,7 +111,6 @@ async fn test_finalize_vote_to_defeated() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -126,11 +118,7 @@ async fn test_finalize_vote_to_defeated() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -159,7 +147,7 @@ async fn test_finalize_vote_to_defeated() { // Advance clock past max_voting_time governance_test .advance_clock_past_timestamp( - governance_cookie.account.config.max_voting_time as i64 + governance_cookie.account.config.voting_base_time as i64 + proposal_account.voting_at.unwrap(), ) .await; @@ -186,7 +174,6 @@ async fn test_finalize_vote_with_invalid_mint_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -194,11 +181,7 @@ async fn test_finalize_vote_with_invalid_mint_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -246,7 +229,6 @@ async fn test_finalize_vote_with_invalid_governance_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -254,11 +236,7 @@ async fn test_finalize_vote_with_invalid_governance_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -284,15 +262,10 @@ async fn test_finalize_vote_with_invalid_governance_error() { assert_eq!(ProposalState::Voting, proposal_account.state); - // Setup Governance for a different account - let governed_account_cookie2 = governance_test.with_governed_account().await; + // Setup another Governance let governance_cookie2 = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie2, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -317,7 +290,6 @@ async fn test_finalize_council_vote() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let mut governance_config = governance_test.get_default_governance_config(); governance_config.council_vote_threshold = VoteThreshold::YesVotePercentage(40); @@ -332,7 +304,6 @@ async fn test_finalize_council_vote() { let mut governance_cookie = governance_test .with_governance_using_config( &realm_cookie, - &governed_account_cookie, &token_owner_record_cookie, &governance_config, ) @@ -349,7 +320,8 @@ async fn test_finalize_council_vote() { .await .unwrap(); - // Cast vote with 47% weight, above 40% quorum but below 50%+1 to tip automatically + // Cast vote with 47% weight, above 40% quorum but below 50%+1 to tip + // automatically governance_test .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) .await @@ -365,7 +337,7 @@ async fn test_finalize_council_vote() { // Advance timestamp past max_voting_time governance_test .advance_clock_past_timestamp( - governance_cookie.account.config.max_voting_time as i64 + governance_cookie.account.config.voting_base_time as i64 + proposal_account.voting_at.unwrap(), ) .await; @@ -385,7 +357,7 @@ async fn test_finalize_council_vote() { assert_eq!(proposal_account.state, ProposalState::Succeeded); assert_eq!( - Some(proposal_account.vote_end_time(&governance_cookie.account.config)), + Some(proposal_account.voting_max_time_end(&governance_cookie.account.config)), proposal_account.voting_completed_at ); @@ -396,3 +368,112 @@ async fn test_finalize_council_vote() { proposal_account.vote_threshold ); } + +#[tokio::test] +async fn test_finalize_vote_with_cannot_finalize_during_voting_time_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + // Total 210 tokens + governance_test + .mint_community_tokens(&realm_cookie, 110) + .await; + + let proposal_cookie = governance_test + .with_signed_off_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + governance_test.advance_clock().await; + + // Act + + let err = governance_test + .finalize_vote(&realm_cookie, &proposal_cookie, None) + .await + .err() + .unwrap(); + + // Assert + + assert_eq!(err, GovernanceError::CannotFinalizeVotingInProgress.into()); +} + +#[tokio::test] +async fn test_finalize_vote_with_cannot_finalize_during_cool_off_time_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Set none default voting cool off time + let mut governance_config = governance_test.get_default_governance_config(); + governance_config.voting_cool_off_time = 50; + + let mut governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie, + &governance_config, + ) + .await + .unwrap(); + + // Total 210 tokens + governance_test + .mint_community_tokens(&realm_cookie, 110) + .await; + + let proposal_cookie = governance_test + .with_signed_off_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + // Advance timestamp into voting_cool_off_time + let clock = governance_test.bench.get_clock().await; + + governance_test + .advance_clock_past_timestamp( + clock.unix_timestamp + governance_cookie.account.config.voting_base_time as i64, + ) + .await; + + // Act + + let err = governance_test + .finalize_vote(&realm_cookie, &proposal_cookie, None) + .await + .err() + .unwrap(); + + // Assert + + assert_eq!(err, GovernanceError::CannotFinalizeVotingInProgress.into()); +} diff --git a/governance/program/tests/process_flag_transaction_error.rs b/governance/program/tests/process_flag_transaction_error.rs deleted file mode 100644 index 0022cde4221..00000000000 --- a/governance/program/tests/process_flag_transaction_error.rs +++ /dev/null @@ -1,447 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod program_test; - -use solana_program_test::tokio; - -use program_test::*; -use spl_governance::{ - error::GovernanceError, - state::enums::{ProposalState, TransactionExecutionStatus}, -}; - -#[tokio::test] -async fn test_execute_flag_transaction_error() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) - .await - .unwrap(); - - let mut proposal_cookie = governance_test - .with_proposal(&token_owner_record_cookie, &mut governance_cookie) - .await - .unwrap(); - - let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) - .await - .unwrap(); - - let proposal_transaction_cookie = governance_test - .with_nop_transaction(&mut proposal_cookie, &token_owner_record_cookie, 0, None) - .await - .unwrap(); - - governance_test - .sign_off_proposal(&proposal_cookie, &signatory_record_cookie) - .await - .unwrap(); - - governance_test - .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) - .await - .unwrap(); - - // Advance timestamp past hold_up_time - governance_test - .advance_clock_by_min_timespan(proposal_transaction_cookie.account.hold_up_time as u64) - .await; - - let clock = governance_test.bench.get_clock().await; - - // Act - governance_test - .flag_transaction_error( - &proposal_cookie, - &token_owner_record_cookie, - &proposal_transaction_cookie, - ) - .await - .unwrap(); - - // Assert - - let proposal_account = governance_test - .get_proposal_account(&proposal_cookie.address) - .await; - - let yes_option = proposal_account.options.first().unwrap(); - - assert_eq!(0, yes_option.transactions_executed_count); - assert_eq!(ProposalState::ExecutingWithErrors, proposal_account.state); - assert_eq!(None, proposal_account.closed_at); - assert_eq!(Some(clock.unix_timestamp), proposal_account.executing_at); - - let proposal_transaction_account = governance_test - .get_proposal_transaction_account(&proposal_transaction_cookie.address) - .await; - - assert_eq!(None, proposal_transaction_account.executed_at); - - assert_eq!( - TransactionExecutionStatus::Error, - proposal_transaction_account.execution_status - ); -} - -#[tokio::test] -async fn test_execute_proposal_transaction_after_flagged_with_error() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let governed_mint_cookie = governance_test.with_governed_mint().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - let mut mint_governance_cookie = governance_test - .with_mint_governance( - &realm_cookie, - &governed_mint_cookie, - &token_owner_record_cookie, - ) - .await - .unwrap(); - - let mut proposal_cookie = governance_test - .with_proposal(&token_owner_record_cookie, &mut mint_governance_cookie) - .await - .unwrap(); - - let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) - .await - .unwrap(); - - let proposal_transaction_cookie = governance_test - .with_mint_tokens_transaction( - &governed_mint_cookie, - &mut proposal_cookie, - &token_owner_record_cookie, - 0, - None, - None, - ) - .await - .unwrap(); - - governance_test - .sign_off_proposal(&proposal_cookie, &signatory_record_cookie) - .await - .unwrap(); - - governance_test - .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) - .await - .unwrap(); - - // Advance timestamp past hold_up_time - governance_test - .advance_clock_by_min_timespan(proposal_transaction_cookie.account.hold_up_time as u64) - .await; - - governance_test - .flag_transaction_error( - &proposal_cookie, - &token_owner_record_cookie, - &proposal_transaction_cookie, - ) - .await - .unwrap(); - - // Act - governance_test - .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie) - .await - .unwrap(); - - // Assert - - let proposal_account = governance_test - .get_proposal_account(&proposal_cookie.address) - .await; - - assert_eq!(ProposalState::Completed, proposal_account.state); - - let proposal_transaction_account = governance_test - .get_proposal_transaction_account(&proposal_transaction_cookie.address) - .await; - - assert_eq!( - TransactionExecutionStatus::Success, - proposal_transaction_account.execution_status - ); -} - -#[tokio::test] -async fn test_execute_second_transaction_after_first_transaction_flagged_with_error() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let governed_mint_cookie = governance_test.with_governed_mint().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - let mut mint_governance_cookie = governance_test - .with_mint_governance( - &realm_cookie, - &governed_mint_cookie, - &token_owner_record_cookie, - ) - .await - .unwrap(); - - let mut proposal_cookie = governance_test - .with_proposal(&token_owner_record_cookie, &mut mint_governance_cookie) - .await - .unwrap(); - - let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) - .await - .unwrap(); - - let proposal_transaction_cookie1 = governance_test - .with_nop_transaction(&mut proposal_cookie, &token_owner_record_cookie, 0, None) - .await - .unwrap(); - - let proposal_transaction_cookie2 = governance_test - .with_mint_tokens_transaction( - &governed_mint_cookie, - &mut proposal_cookie, - &token_owner_record_cookie, - 0, - None, - None, - ) - .await - .unwrap(); - - governance_test - .sign_off_proposal(&proposal_cookie, &signatory_record_cookie) - .await - .unwrap(); - - governance_test - .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) - .await - .unwrap(); - - // Advance timestamp past hold_up_time - governance_test - .advance_clock_by_min_timespan(proposal_transaction_cookie2.account.hold_up_time as u64) - .await; - - governance_test - .flag_transaction_error( - &proposal_cookie, - &token_owner_record_cookie, - &proposal_transaction_cookie1, - ) - .await - .unwrap(); - - // Act - governance_test - .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie2) - .await - .unwrap(); - - // Assert - - let proposal_account = governance_test - .get_proposal_account(&proposal_cookie.address) - .await; - - assert_eq!(ProposalState::ExecutingWithErrors, proposal_account.state); -} - -#[tokio::test] -async fn test_flag_transaction_error_with_proposal_transaction_already_executed_error() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let governed_mint_cookie = governance_test.with_governed_mint().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - let mut mint_governance_cookie = governance_test - .with_mint_governance( - &realm_cookie, - &governed_mint_cookie, - &token_owner_record_cookie, - ) - .await - .unwrap(); - - let mut proposal_cookie = governance_test - .with_proposal(&token_owner_record_cookie, &mut mint_governance_cookie) - .await - .unwrap(); - - let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) - .await - .unwrap(); - - let proposal_transaction_cookie = governance_test - .with_mint_tokens_transaction( - &governed_mint_cookie, - &mut proposal_cookie, - &token_owner_record_cookie, - 0, - None, - None, - ) - .await - .unwrap(); - - // Add another transaction to prevent Proposal from transitioning to Competed state - governance_test - .with_nop_transaction(&mut proposal_cookie, &token_owner_record_cookie, 0, None) - .await - .unwrap(); - - governance_test - .sign_off_proposal(&proposal_cookie, &signatory_record_cookie) - .await - .unwrap(); - - governance_test - .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) - .await - .unwrap(); - - // Advance timestamp past hold_up_time - governance_test - .advance_clock_by_min_timespan(proposal_transaction_cookie.account.hold_up_time as u64) - .await; - - governance_test - .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie) - .await - .unwrap(); - - // Act - - let err = governance_test - .flag_transaction_error( - &proposal_cookie, - &token_owner_record_cookie, - &proposal_transaction_cookie, - ) - .await - .err() - .unwrap(); - - // Assert - - assert_eq!(err, GovernanceError::TransactionAlreadyExecuted.into()); -} - -#[tokio::test] -async fn test_flag_transaction_error_with_owner_or_delegate_must_sign_error() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; - - let mut token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) - .await - .unwrap(); - - let mut proposal_cookie = governance_test - .with_proposal(&token_owner_record_cookie, &mut governance_cookie) - .await - .unwrap(); - - let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) - .await - .unwrap(); - - let proposal_transaction_cookie = governance_test - .with_nop_transaction(&mut proposal_cookie, &token_owner_record_cookie, 0, None) - .await - .unwrap(); - - governance_test - .sign_off_proposal(&proposal_cookie, &signatory_record_cookie) - .await - .unwrap(); - - governance_test - .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) - .await - .unwrap(); - - // Advance timestamp past hold_up_time - governance_test - .advance_clock_by_min_timespan(proposal_transaction_cookie.account.hold_up_time as u64) - .await; - - let token_owner_record_cookie2 = governance_test - .with_council_token_deposit(&realm_cookie) - .await - .unwrap(); - - // Try to maliciously sign using different owner signature - token_owner_record_cookie.token_owner = token_owner_record_cookie2.token_owner; - - // Act - - let err = governance_test - .flag_transaction_error( - &proposal_cookie, - &token_owner_record_cookie, - &proposal_transaction_cookie, - ) - .await - .err() - .unwrap(); - - // Assert - - assert_eq!( - err, - GovernanceError::GoverningTokenOwnerOrDelegateMustSign.into() - ); -} diff --git a/governance/program/tests/process_insert_transaction.rs b/governance/program/tests/process_insert_transaction.rs index 5bad103bee5..929839f1407 100644 --- a/governance/program/tests/process_insert_transaction.rs +++ b/governance/program/tests/process_insert_transaction.rs @@ -1,11 +1,8 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] mod program_test; -use solana_program_test::tokio; - -use program_test::*; -use spl_governance::error::GovernanceError; +use {program_test::*, solana_program_test::tokio, spl_governance::error::GovernanceError}; #[tokio::test] async fn test_insert_transaction() { @@ -13,7 +10,6 @@ async fn test_insert_transaction() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -21,11 +17,7 @@ async fn test_insert_transaction() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -68,7 +60,6 @@ async fn test_insert_multiple_transactions() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -76,11 +67,7 @@ async fn test_insert_multiple_transactions() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -119,7 +106,6 @@ async fn test_insert_transaction_with_invalid_index_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -127,11 +113,7 @@ async fn test_insert_transaction_with_invalid_index_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -157,7 +139,6 @@ async fn test_insert_transaction_with_proposal_transaction_already_exists_error( let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -165,11 +146,7 @@ async fn test_insert_transaction_with_proposal_transaction_already_exists_error( .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -196,58 +173,12 @@ async fn test_insert_transaction_with_proposal_transaction_already_exists_error( assert_eq!(err, GovernanceError::TransactionAlreadyExists.into()); } -#[tokio::test] -async fn test_insert_transaction_with_invalid_hold_up_time_error() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; - - let mut config = governance_test.get_default_governance_config(); - - config.min_transaction_hold_up_time = 100; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - let mut governance_cookie = governance_test - .with_governance_using_config( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - &config, - ) - .await - .unwrap(); - - let mut proposal_cookie = governance_test - .with_proposal(&token_owner_record_cookie, &mut governance_cookie) - .await - .unwrap(); - - // Act - let err = governance_test - .with_nop_transaction(&mut proposal_cookie, &token_owner_record_cookie, 0, None) - .await - .err() - .unwrap(); - - // Assert - assert_eq!( - err, - GovernanceError::TransactionHoldUpTimeBelowRequiredMin.into() - ); -} #[tokio::test] async fn test_insert_transaction_with_not_editable_proposal_error() { // Arrange let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -255,11 +186,7 @@ async fn test_insert_transaction_with_not_editable_proposal_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -288,7 +215,6 @@ async fn test_insert_transaction_with_owner_or_delegate_must_sign_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let mut token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -296,11 +222,7 @@ async fn test_insert_transaction_with_owner_or_delegate_must_sign_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -336,7 +258,6 @@ async fn test_insert_transaction_with_invalid_governance_for_proposal_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -344,11 +265,7 @@ async fn test_insert_transaction_with_invalid_governance_for_proposal_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -357,15 +274,11 @@ async fn test_insert_transaction_with_invalid_governance_for_proposal_error() { .await .unwrap(); - // Try to maliciously use a different governance account to use with the proposal - let governed_account_cookie2 = governance_test.with_governed_account().await; + // Try to maliciously use a different governance account to use with the + // proposal let governance_cookie2 = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie2, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); diff --git a/governance/program/tests/process_refund_proposal_deposit.rs b/governance/program/tests/process_refund_proposal_deposit.rs new file mode 100644 index 00000000000..2eec08b950a --- /dev/null +++ b/governance/program/tests/process_refund_proposal_deposit.rs @@ -0,0 +1,313 @@ +#![cfg(feature = "test-sbf")] + +use {solana_program::program_error::ProgramError, solana_program_test::*}; + +mod program_test; + +use {program_test::*, spl_governance::error::GovernanceError}; + +#[tokio::test] +async fn test_refund_proposal_deposit() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_config = governance_test.get_default_governance_config(); + governance_config.deposit_exempt_proposal_count = 0; + + let mut governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie, + &governance_config, + ) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + governance_test + .cancel_proposal(&proposal_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + // Act + governance_test + .refund_proposal_deposit(&proposal_cookie) + .await + .unwrap(); + + // Assert + + let proposal_deposit_account_info = governance_test + .bench + .get_account(&proposal_cookie.proposal_deposit.address) + .await; + + assert_eq!(None, proposal_deposit_account_info); +} + +#[tokio::test] +async fn test_refund_proposal_deposit_with_cannot_refund_draft_proposal_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_config = governance_test.get_default_governance_config(); + governance_config.deposit_exempt_proposal_count = 0; + + let mut governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie, + &governance_config, + ) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + // Act + let err = governance_test + .refund_proposal_deposit(&proposal_cookie) + .await + .err() + .unwrap(); + + // Assert + + assert_eq!(err, GovernanceError::CannotRefundProposalDeposit.into()); +} + +#[tokio::test] +async fn test_refund_proposal_deposit_with_cannot_refund_voting_proposal_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_config = governance_test.get_default_governance_config(); + governance_config.deposit_exempt_proposal_count = 0; + + let mut governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie, + &governance_config, + ) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_signed_off_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + // Act + let err = governance_test + .refund_proposal_deposit(&proposal_cookie) + .await + .err() + .unwrap(); + + // Assert + + assert_eq!(err, GovernanceError::CannotRefundProposalDeposit.into()); +} + +#[tokio::test] +async fn test_refund_proposal_deposit_with_invalid_proposal_deposit_payer_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_config = governance_test.get_default_governance_config(); + governance_config.deposit_exempt_proposal_count = 0; + + let mut governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie, + &governance_config, + ) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + governance_test + .cancel_proposal(&proposal_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + // Try to refund the deposit to account which is different than Proposal deposit + // payer + let deposit_payer2 = governance_test.bench.with_wallet().await; + + // Act + let err = governance_test + .refund_proposal_deposit_using_instruction( + &proposal_cookie, + |i| { + i.accounts[2].pubkey = deposit_payer2.address; // proposal_deposit_payer + }, + None, + ) + .await + .err() + .unwrap(); + + // Assert + + assert_eq!( + err, + GovernanceError::InvalidDepositPayerForProposalDeposit.into() + ); +} + +#[tokio::test] +async fn test_refund_proposal_deposit_with_invalid_proposal_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_config = governance_test.get_default_governance_config(); + governance_config.deposit_exempt_proposal_count = 0; + + let mut governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie, + &governance_config, + ) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + governance_test + .cancel_proposal(&proposal_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + // Try to refund deposit from a different proposal + let proposal_cookie2 = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + // Act + let err = governance_test + .refund_proposal_deposit_using_instruction( + &proposal_cookie, + |i| { + i.accounts[1].pubkey = proposal_cookie2.proposal_deposit.address; + // proposal_deposit + }, + None, + ) + .await + .err() + .unwrap(); + + // Assert + + assert_eq!( + err, + GovernanceError::InvalidProposalForProposalDeposit.into() + ); +} + +#[tokio::test] +async fn test_refund_proposal_deposit_with_invalid_proposal_deposit_account_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_config = governance_test.get_default_governance_config(); + governance_config.deposit_exempt_proposal_count = 0; + + let mut governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie, + &governance_config, + ) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + governance_test + .cancel_proposal(&proposal_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + // Act + let err = governance_test + .refund_proposal_deposit_using_instruction( + &proposal_cookie, + |i| { + // Try to drain the Proposal account + i.accounts[1].pubkey = proposal_cookie.address; + }, + None, + ) + .await + .err() + .unwrap(); + + // Assert + + assert_eq!(err, ProgramError::UninitializedAccount); +} diff --git a/governance/program/tests/process_relinquish_token_owner_record_locks.rs b/governance/program/tests/process_relinquish_token_owner_record_locks.rs new file mode 100644 index 00000000000..bf46db1e053 --- /dev/null +++ b/governance/program/tests/process_relinquish_token_owner_record_locks.rs @@ -0,0 +1,527 @@ +#![cfg(feature = "test-sbf")] + +mod program_test; + +use { + program_test::*, + solana_program_test::tokio, + solana_sdk::{program_error::ProgramError, signature::Keypair, signer::Signer}, + spl_governance::{ + error::GovernanceError, state::realm::SetRealmConfigItemArgs, + tools::structs::SetConfigItemActionType, + }, +}; + +#[tokio::test] +async fn test_relinquish_token_owner_record_lock() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_cookie = governance_test + .with_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + ) + .await + .unwrap(); + + // Act + governance_test + .relinquish_token_owner_record_locks( + &token_owner_record_cookie, + Some(&token_owner_record_lock_authority_cookie.authority), + Some(vec![token_owner_record_lock_cookie.lock_id]), + ) + .await + .unwrap(); + + // Assert + let token_owner_record_account = governance_test + .get_token_owner_record_account(&token_owner_record_cookie.address) + .await; + + assert_eq!(0, token_owner_record_account.locks.len()); +} + +#[tokio::test] +async fn test_relinquish_token_owner_record_locks_with_invalid_authority_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_cookie = governance_test + .with_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + ) + .await + .unwrap(); + + let token_owner_record_lock_authority = Keypair::new(); + + // Act + let err = governance_test + .relinquish_token_owner_record_locks( + &token_owner_record_cookie, + Some(&token_owner_record_lock_authority), + Some(vec![token_owner_record_lock_cookie.lock_id]), + ) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::TokenOwnerRecordLockNotFound.into()); +} + +#[tokio::test] +async fn test_relinquish_token_owner_record_locks_with_missing_authority_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_cookie = governance_test + .with_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + ) + .await + .unwrap(); + + // Act + let err = governance_test + .relinquish_token_owner_record_locks( + &token_owner_record_cookie, + None, + Some(vec![token_owner_record_lock_cookie.lock_id]), + ) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, ProgramError::NotEnoughAccountKeys); +} + +#[tokio::test] +async fn test_relinquish_token_owner_record_locks_with_invalid_lock_id_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + governance_test + .with_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + ) + .await + .unwrap(); + + // Act + let err = governance_test + .relinquish_token_owner_record_locks( + &token_owner_record_cookie, + Some(&token_owner_record_lock_authority_cookie.authority), + Some(vec![0]), + ) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::TokenOwnerRecordLockNotFound.into()); +} + +#[tokio::test] +async fn test_relinquish_token_owner_record_locks_with_authority_must_sign_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_cookie = governance_test + .with_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + ) + .await + .unwrap(); + + // Act + let err = governance_test + .relinquish_token_owner_record_locks_using_ix( + &token_owner_record_cookie, + Some(&token_owner_record_lock_authority_cookie.authority), + Some(vec![token_owner_record_lock_cookie.lock_id]), + |i| i.accounts[3].is_signer = false, + Some(&[]), + ) + .await + .err() + .unwrap(); + + // Assert + assert_eq!( + err, + GovernanceError::TokenOwnerRecordLockAuthorityMustSign.into() + ); +} + +#[tokio::test] +async fn test_relinquish_token_owner_record_locks_after_authority_revoked() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_cookie = governance_test + .with_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + ) + .await + .unwrap(); + + // Revoke authority + let args = SetRealmConfigItemArgs::TokenOwnerRecordLockAuthority { + action: SetConfigItemActionType::Remove, + governing_token_mint: realm_cookie.account.community_mint, + authority: token_owner_record_lock_authority_cookie.authority.pubkey(), + }; + + governance_test + .set_realm_config_item(&realm_cookie, args) + .await + .unwrap(); + + // Act + governance_test + .relinquish_token_owner_record_locks( + &token_owner_record_cookie, + Some(&token_owner_record_lock_authority_cookie.authority), + Some(vec![token_owner_record_lock_cookie.lock_id]), + ) + .await + .unwrap(); + + // Assert + let token_owner_record_account = governance_test + .get_token_owner_record_account(&token_owner_record_cookie.address) + .await; + + assert_eq!(0, token_owner_record_account.locks.len()); +} + +#[tokio::test] +async fn test_relinquish_token_owner_record_locks_after_authority_revoked_and_without_signature() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_cookie = governance_test + .with_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + ) + .await + .unwrap(); + + // Revoke authority + let args = SetRealmConfigItemArgs::TokenOwnerRecordLockAuthority { + action: SetConfigItemActionType::Remove, + governing_token_mint: realm_cookie.account.community_mint, + authority: token_owner_record_lock_authority_cookie.authority.pubkey(), + }; + + governance_test + .set_realm_config_item(&realm_cookie, args) + .await + .unwrap(); + + // Act + governance_test + .relinquish_token_owner_record_locks_using_ix( + &token_owner_record_cookie, + Some(&token_owner_record_lock_authority_cookie.authority), + Some(vec![token_owner_record_lock_cookie.lock_id]), + |i| i.accounts[3].is_signer = false, // Remove authority signature + Some(&[]), + ) + .await + .unwrap(); + + // Assert + let token_owner_record_account = governance_test + .get_token_owner_record_account(&token_owner_record_cookie.address) + .await; + + assert_eq!(0, token_owner_record_account.locks.len()); +} + +#[tokio::test] +async fn test_relinquish_expired_token_owner_record_lock() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + // Set none expiring lock + + let lock_id = 100; + + governance_test + .set_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + lock_id, + None, + ) + .await + .unwrap(); + + // Set another lock + let token_owner_record_lock_authority_cookie2 = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_cookie2 = governance_test + .with_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie2, + ) + .await + .unwrap(); + + // And expire it + governance_test + .advance_clock_past_timestamp(token_owner_record_lock_cookie2.expiry.unwrap()) + .await; + + // Act + governance_test + .relinquish_token_owner_record_locks( + &token_owner_record_cookie, + Some(&token_owner_record_lock_authority_cookie2.authority), + Some(vec![token_owner_record_lock_cookie2.lock_id]), + ) + .await + .unwrap(); + + // Assert + let token_owner_record_account = governance_test + .get_token_owner_record_account(&token_owner_record_cookie.address) + .await; + + assert_eq!(1, token_owner_record_account.locks.len()); + assert_eq!(lock_id, token_owner_record_account.locks[0].lock_id); +} + +#[tokio::test] +async fn test_relinquish_token_owner_record_locks_for_expired_locks_only() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + // Set none expiring lock + + let lock_id = 100; + + governance_test + .set_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + lock_id, + None, + ) + .await + .unwrap(); + + // Set another lock + let token_owner_record_lock_authority_cookie2 = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_cookie2 = governance_test + .with_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie2, + ) + .await + .unwrap(); + + // And expire it + governance_test + .advance_clock_past_timestamp(token_owner_record_lock_cookie2.expiry.unwrap()) + .await; + + // Act + governance_test + .relinquish_token_owner_record_locks(&token_owner_record_cookie, None, None) + .await + .unwrap(); + + // Assert + let token_owner_record_account = governance_test + .get_token_owner_record_account(&token_owner_record_cookie.address) + .await; + + assert_eq!(1, token_owner_record_account.locks.len()); + assert_eq!(lock_id, token_owner_record_account.locks[0].lock_id); +} + +#[tokio::test] +async fn test_relinquish_multiple_token_owner_record_locks() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let lock_type1 = 1; + + governance_test + .set_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + lock_type1, + None, + ) + .await + .unwrap(); + + let lock_type2 = 2; + governance_test + .set_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + lock_type2, + None, + ) + .await + .unwrap(); + + // Act + governance_test + .relinquish_token_owner_record_locks( + &token_owner_record_cookie, + Some(&token_owner_record_lock_authority_cookie.authority), + Some(vec![lock_type1, lock_type2]), + ) + .await + .unwrap(); + + // Assert + let token_owner_record_account = governance_test + .get_token_owner_record_account(&token_owner_record_cookie.address) + .await; + + assert_eq!(0, token_owner_record_account.locks.len()); +} diff --git a/governance/program/tests/process_relinquish_vote.rs b/governance/program/tests/process_relinquish_vote.rs index 34f3a556036..c3ea41e4d6c 100644 --- a/governance/program/tests/process_relinquish_vote.rs +++ b/governance/program/tests/process_relinquish_vote.rs @@ -1,12 +1,21 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] mod program_test; -use solana_program::{instruction::AccountMeta, pubkey::Pubkey}; -use solana_program_test::tokio; - -use program_test::*; -use spl_governance::{error::GovernanceError, state::enums::ProposalState}; +use { + program_test::*, + solana_program::{instruction::AccountMeta, pubkey::Pubkey}, + solana_program_test::tokio, + solana_sdk::signer::Signer, + spl_governance::{ + error::GovernanceError, + instruction::{cast_vote, relinquish_vote}, + state::{ + enums::{ProposalState, VoteTipping}, + vote_record::{Vote, VoteChoice}, + }, + }, +}; #[tokio::test] async fn test_relinquish_voted_proposal() { @@ -14,7 +23,6 @@ async fn test_relinquish_voted_proposal() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -22,11 +30,7 @@ async fn test_relinquish_voted_proposal() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -60,7 +64,6 @@ async fn test_relinquish_voted_proposal() { .await; assert_eq!(0, token_owner_record.unrelinquished_votes_count); - assert_eq!(1, token_owner_record.total_votes_count); let vote_record_account = governance_test .get_vote_record_account(&vote_record_cookie.address) @@ -76,7 +79,6 @@ async fn test_relinquish_active_yes_vote() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -84,11 +86,7 @@ async fn test_relinquish_active_yes_vote() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -128,7 +126,6 @@ async fn test_relinquish_active_yes_vote() { .await; assert_eq!(0, token_owner_record.unrelinquished_votes_count); - assert_eq!(0, token_owner_record.total_votes_count); let vote_record_account = governance_test .bench @@ -144,7 +141,6 @@ async fn test_relinquish_active_no_vote() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -152,11 +148,7 @@ async fn test_relinquish_active_no_vote() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -196,7 +188,6 @@ async fn test_relinquish_active_no_vote() { .await; assert_eq!(0, token_owner_record.unrelinquished_votes_count); - assert_eq!(0, token_owner_record.total_votes_count); let vote_record_account = governance_test .bench @@ -212,7 +203,6 @@ async fn test_relinquish_vote_with_invalid_mint_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let mut token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -220,11 +210,7 @@ async fn test_relinquish_vote_with_invalid_mint_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -259,7 +245,6 @@ async fn test_relinquish_vote_with_governance_authority_must_sign_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let mut token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -267,11 +252,7 @@ async fn test_relinquish_vote_with_governance_authority_must_sign_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -320,7 +301,6 @@ async fn test_relinquish_vote_with_invalid_vote_record_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -328,11 +308,7 @@ async fn test_relinquish_vote_with_invalid_vote_record_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -390,7 +366,6 @@ async fn test_relinquish_vote_with_already_relinquished_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -398,11 +373,7 @@ async fn test_relinquish_vote_with_already_relinquished_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -426,7 +397,7 @@ async fn test_relinquish_vote_with_already_relinquished_error() { .get_vote_record_account(&vote_record_cookie.address) .await; - assert_eq!(true, vote_record_account.is_relinquished); + assert!(vote_record_account.is_relinquished); governance_test .mint_community_tokens(&realm_cookie, 10) @@ -452,7 +423,6 @@ async fn test_relinquish_proposal_with_cannot_relinquish_in_finalizing_state_err let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; // Deposit 100 tokens let token_owner_record_cookie = governance_test @@ -466,11 +436,7 @@ async fn test_relinquish_proposal_with_cannot_relinquish_in_finalizing_state_err .await; let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -489,7 +455,7 @@ async fn test_relinquish_proposal_with_cannot_relinquish_in_finalizing_state_err // Advance timestamp past max_voting_time governance_test .advance_clock_past_timestamp( - governance_cookie.account.config.max_voting_time as i64 + clock.unix_timestamp, + governance_cookie.account.config.voting_base_time as i64 + clock.unix_timestamp, ) .await; @@ -507,3 +473,155 @@ async fn test_relinquish_proposal_with_cannot_relinquish_in_finalizing_state_err GovernanceError::CannotRelinquishInFinalizingState.into() ); } + +#[tokio::test] +async fn test_relinquish_and_cast_vote_in_single_transaction() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_config = governance_test.get_default_governance_config(); + governance_config.community_vote_tipping = VoteTipping::Disabled; + + let mut governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie, + &governance_config, + ) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_signed_off_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + let vote_record_cookie = governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + let relinquish_vote_ix = relinquish_vote( + &governance_test.program_id, + &token_owner_record_cookie.account.realm, + &proposal_cookie.account.governance, + &proposal_cookie.address, + &token_owner_record_cookie.address, + &token_owner_record_cookie.account.governing_token_mint, + Some(token_owner_record_cookie.token_owner.pubkey()), + Some(governance_test.bench.payer.pubkey()), + ); + + let cast_vote_ix = cast_vote( + &governance_test.program_id, + &token_owner_record_cookie.account.realm, + &proposal_cookie.account.governance, + &proposal_cookie.address, + &proposal_cookie.account.token_owner_record, + &token_owner_record_cookie.address, + &token_owner_record_cookie.token_owner.pubkey(), + &token_owner_record_cookie.account.governing_token_mint, + &governance_test.bench.payer.pubkey(), + None, + None, + Vote::Approve(vec![VoteChoice { + rank: 0, + weight_percentage: 100, + }]), + ); + + // Act + governance_test + .bench + .process_transaction( + &[relinquish_vote_ix, cast_vote_ix], + Some(&[&token_owner_record_cookie.token_owner]), + ) + .await + .unwrap(); + + // Assert + let vote_record_account = governance_test + .get_vote_record_account(&vote_record_cookie.address) + .await; + + assert_eq!(vote_record_cookie.account, vote_record_account); +} + +#[tokio::test] +async fn test_change_yes_vote_to_no_within_cool_off_time() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Set none default voting cool off time + let mut governance_config = governance_test.get_default_governance_config(); + governance_config.voting_cool_off_time = 50; + + let mut governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie, + &governance_config, + ) + .await + .unwrap(); + + // Total 300 tokens + governance_test + .mint_community_tokens(&realm_cookie, 200) + .await; + + let proposal_cookie = governance_test + .with_signed_off_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + // Advance timestamp into voting_cool_off_time + let clock = governance_test.bench.get_clock().await; + + governance_test + .advance_clock_past_timestamp( + clock.unix_timestamp + governance_cookie.account.config.voting_base_time as i64, + ) + .await; + + // Act + governance_test + .relinquish_vote(&proposal_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::No) + .await + .unwrap(); + + // Assert + + let proposal_account = governance_test + .get_proposal_account(&proposal_cookie.address) + .await; + + assert_eq!(0, proposal_account.options[0].vote_weight); + assert_eq!(100, proposal_account.deny_vote_weight.unwrap()); + assert_eq!(ProposalState::Voting, proposal_account.state); +} diff --git a/governance/program/tests/process_remove_required_signatory.rs b/governance/program/tests/process_remove_required_signatory.rs new file mode 100644 index 00000000000..c810543ac65 --- /dev/null +++ b/governance/program/tests/process_remove_required_signatory.rs @@ -0,0 +1,205 @@ +#![cfg(feature = "test-sbf")] + +mod program_test; + +use { + program_test::*, + solana_program::pubkey::Pubkey, + solana_program_test::tokio, + solana_sdk::signature::Signer, + spl_governance::{error::GovernanceError, instruction::remove_required_signatory}, + spl_governance_tools::error::GovernanceToolsError, +}; + +#[tokio::test] +async fn test_remove_required_signatory() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let (token_owner_record_cookie, mut governance_cookie, realm_cookie, signatory) = + governance_test + .with_governance_with_required_signatory() + .await; + + let mut proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + let beneficiary = Pubkey::new_unique(); + + let proposal_transaction_cookie = governance_test + .with_remove_required_signatory_transaction( + &mut proposal_cookie, + &token_owner_record_cookie, + &governance_cookie, + &signatory.pubkey(), + &beneficiary, + ) + .await + .unwrap(); + + governance_test + .with_signatory_record_for_required_signatory( + &proposal_cookie, + &governance_cookie, + &signatory.pubkey(), + ) + .await + .unwrap(); + + governance_test + .do_required_signoff( + &realm_cookie, + &governance_cookie, + &proposal_cookie, + &signatory, + ) + .await + .unwrap(); + + governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + // Advance timestamp past hold_up_time + governance_test + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) + .await; + + // Act + governance_test + .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie) + .await + .unwrap(); + + // Assert + let after_proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + let proposal_account = governance_test + .get_proposal_account(&after_proposal_cookie.address) + .await; + + assert_eq!(0, proposal_account.signatories_count); + + let governance_account = governance_test + .get_governance_account(&governance_cookie.address) + .await; + + assert_eq!(0, governance_account.required_signatories_count); +} + +#[tokio::test] +async fn test_remove_non_existing_required_signatory_err() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let (token_owner_record_cookie, mut governance_cookie, realm_cookie, signatory) = + governance_test + .with_governance_with_required_signatory() + .await; + + let mut proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + let beneficiary = Pubkey::new_unique(); + + let proposal_transaction_cookie = governance_test + .with_remove_required_signatory_transaction( + &mut proposal_cookie, + &token_owner_record_cookie, + &governance_cookie, + &Pubkey::new_unique(), + &beneficiary, + ) + .await + .unwrap(); + + governance_test + .with_signatory_record_for_required_signatory( + &proposal_cookie, + &governance_cookie, + &signatory.pubkey(), + ) + .await + .unwrap(); + + governance_test + .do_required_signoff( + &realm_cookie, + &governance_cookie, + &proposal_cookie, + &signatory, + ) + .await + .unwrap(); + + governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + // Advance timestamp past hold_up_time + governance_test + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) + .await; + + // Act + let err = governance_test + .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceToolsError::AccountDoesNotExist.into()); +} + +#[tokio::test] +pub async fn remove_required_signatory_from_governance_without_governance_signer_err() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let signatory = Pubkey::new_unique(); + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + let mut gwr_ix = remove_required_signatory( + &governance_test.program_id, + &governance_cookie.address, + &signatory, + &governance_test.bench.payer.pubkey(), + ); + + gwr_ix.accounts[0].is_signer = false; + + // Act + let err = governance_test + .bench + .process_transaction(&[gwr_ix], Some(&[])) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::GovernancePdaMustSign.into()); +} diff --git a/governance/program/tests/process_remove_signatory.rs b/governance/program/tests/process_remove_signatory.rs deleted file mode 100644 index deecefe3a4f..00000000000 --- a/governance/program/tests/process_remove_signatory.rs +++ /dev/null @@ -1,293 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod program_test; - -use solana_program_test::tokio; - -use program_test::*; - -use spl_governance::{error::GovernanceError, state::enums::ProposalState}; - -#[tokio::test] -async fn test_remove_signatory() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) - .await - .unwrap(); - - let proposal_cookie = governance_test - .with_proposal(&token_owner_record_cookie, &mut governance_cookie) - .await - .unwrap(); - - let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) - .await - .unwrap(); - - // Act - governance_test - .remove_signatory( - &proposal_cookie, - &token_owner_record_cookie, - &signatory_record_cookie, - ) - .await - .unwrap(); - - // Assert - let proposal_account = governance_test - .get_proposal_account(&proposal_cookie.address) - .await; - - assert_eq!(0, proposal_account.signatories_count); - assert_eq!(ProposalState::Draft, proposal_account.state); - - let signatory_account = governance_test - .bench - .get_account(&signatory_record_cookie.address) - .await; - - assert_eq!(None, signatory_account); -} - -#[tokio::test] -async fn test_remove_signatory_with_owner_or_delegate_must_sign_error() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; - - let mut token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) - .await - .unwrap(); - - let proposal_cookie = governance_test - .with_proposal(&token_owner_record_cookie, &mut governance_cookie) - .await - .unwrap(); - - let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) - .await - .unwrap(); - - let other_token_owner_record_cookie = governance_test - .with_council_token_deposit(&realm_cookie) - .await - .unwrap(); - - token_owner_record_cookie.token_owner = other_token_owner_record_cookie.token_owner; - - // Act - let err = governance_test - .remove_signatory( - &proposal_cookie, - &token_owner_record_cookie, - &signatory_record_cookie, - ) - .await - .err() - .unwrap(); - - // Assert - assert_eq!( - err, - GovernanceError::GoverningTokenOwnerOrDelegateMustSign.into() - ); -} - -#[tokio::test] -async fn test_remove_signatory_with_invalid_proposal_owner_error() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; - - let mut token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) - .await - .unwrap(); - - let proposal_cookie = governance_test - .with_proposal(&token_owner_record_cookie, &mut governance_cookie) - .await - .unwrap(); - - let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) - .await - .unwrap(); - - let other_token_owner_record_cookie = governance_test - .with_council_token_deposit(&realm_cookie) - .await - .unwrap(); - - token_owner_record_cookie.address = other_token_owner_record_cookie.address; - - // Act - let err = governance_test - .remove_signatory( - &proposal_cookie, - &token_owner_record_cookie, - &signatory_record_cookie, - ) - .await - .err() - .unwrap(); - - // Assert - assert_eq!(err, GovernanceError::InvalidProposalOwnerAccount.into()); -} - -#[tokio::test] -async fn test_remove_signatory_with_not_editable_error() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) - .await - .unwrap(); - - let proposal_cookie = governance_test - .with_proposal(&token_owner_record_cookie, &mut governance_cookie) - .await - .unwrap(); - - let signatory_record_cookie1 = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) - .await - .unwrap(); - - let signatory_record_cookie2 = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) - .await - .unwrap(); - - governance_test - .sign_off_proposal(&proposal_cookie, &signatory_record_cookie1) - .await - .unwrap(); - - // Act - let err = governance_test - .remove_signatory( - &proposal_cookie, - &token_owner_record_cookie, - &signatory_record_cookie2, - ) - .await - .err() - .unwrap(); - - // Assert - assert_eq!( - err, - GovernanceError::InvalidStateCannotEditSignatories.into() - ); -} - -#[tokio::test] -async fn test_remove_signatory_with_already_signed_error() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_new().await; - - let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; - - let token_owner_record_cookie = governance_test - .with_community_token_deposit(&realm_cookie) - .await - .unwrap(); - - let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) - .await - .unwrap(); - - let proposal_cookie = governance_test - .with_proposal(&token_owner_record_cookie, &mut governance_cookie) - .await - .unwrap(); - - let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) - .await - .unwrap(); - - governance_test - .sign_off_proposal(&proposal_cookie, &signatory_record_cookie) - .await - .unwrap(); - - // Act - let err = governance_test - .remove_signatory( - &proposal_cookie, - &token_owner_record_cookie, - &signatory_record_cookie, - ) - .await - .err() - .unwrap(); - - // Assert - assert_eq!( - err, - GovernanceError::InvalidStateCannotEditSignatories.into() - ); -} diff --git a/governance/program/tests/process_remove_transaction.rs b/governance/program/tests/process_remove_transaction.rs index 34363d42b19..6908b616ebf 100644 --- a/governance/program/tests/process_remove_transaction.rs +++ b/governance/program/tests/process_remove_transaction.rs @@ -1,11 +1,8 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] mod program_test; -use solana_program_test::tokio; - -use program_test::*; -use spl_governance::error::GovernanceError; +use {program_test::*, solana_program_test::tokio, spl_governance::error::GovernanceError}; #[tokio::test] async fn test_remove_transaction() { @@ -13,7 +10,6 @@ async fn test_remove_transaction() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -21,11 +17,7 @@ async fn test_remove_transaction() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -43,7 +35,7 @@ async fn test_remove_transaction() { governance_test .remove_transaction( - &mut proposal_cookie, + &proposal_cookie, &token_owner_record_cookie, &proposal_transaction_cookie, ) @@ -76,7 +68,6 @@ async fn test_replace_transaction() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -84,11 +75,7 @@ async fn test_replace_transaction() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -111,7 +98,7 @@ async fn test_replace_transaction() { governance_test .remove_transaction( - &mut proposal_cookie, + &proposal_cookie, &token_owner_record_cookie, &proposal_transaction_cookie, ) @@ -149,7 +136,6 @@ async fn test_remove_front_transaction() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -157,11 +143,7 @@ async fn test_remove_front_transaction() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -184,7 +166,7 @@ async fn test_remove_front_transaction() { governance_test .remove_transaction( - &mut proposal_cookie, + &proposal_cookie, &token_owner_record_cookie, &proposal_transaction_cookie, ) @@ -215,7 +197,6 @@ async fn test_remove_transaction_with_owner_or_delegate_must_sign_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let mut token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -223,11 +204,7 @@ async fn test_remove_transaction_with_owner_or_delegate_must_sign_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -251,7 +228,7 @@ async fn test_remove_transaction_with_owner_or_delegate_must_sign_error() { // Act let err = governance_test .remove_transaction( - &mut proposal_cookie, + &proposal_cookie, &token_owner_record_cookie, &proposal_transaction_cookie, ) @@ -272,7 +249,6 @@ async fn test_remove_transaction_with_proposal_not_editable_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -280,11 +256,7 @@ async fn test_remove_transaction_with_proposal_not_editable_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -306,7 +278,7 @@ async fn test_remove_transaction_with_proposal_not_editable_error() { // Act let err = governance_test .remove_transaction( - &mut proposal_cookie, + &proposal_cookie, &token_owner_record_cookie, &proposal_transaction_cookie, ) @@ -327,7 +299,6 @@ async fn test_remove_transaction_with_proposal_transaction_from_other_proposal_e let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -335,11 +306,7 @@ async fn test_remove_transaction_with_proposal_transaction_from_other_proposal_e .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -371,7 +338,7 @@ async fn test_remove_transaction_with_proposal_transaction_from_other_proposal_e // Act let err = governance_test .remove_transaction( - &mut proposal_cookie, + &proposal_cookie, &token_owner_record_cookie, &proposal_transaction_cookie2, ) diff --git a/governance/program/tests/process_revoke_governing_tokens.rs b/governance/program/tests/process_revoke_governing_tokens.rs new file mode 100644 index 00000000000..5a038c85f82 --- /dev/null +++ b/governance/program/tests/process_revoke_governing_tokens.rs @@ -0,0 +1,650 @@ +#![cfg(feature = "test-sbf")] + +use {solana_program::pubkey::Pubkey, solana_program_test::*}; + +mod program_test; + +use { + crate::program_test::args::RealmSetupArgs, + program_test::*, + solana_sdk::signature::{Keypair, Signer}, + spl_governance::{ + error::GovernanceError, + state::{realm::get_governing_token_holding_address, realm_config::GoverningTokenType}, + }, + spl_governance_test_sdk::tools::{clone_keypair, NopOverride}, +}; + +#[tokio::test] +async fn test_revoke_community_tokens() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let mut realm_config_args = RealmSetupArgs::default(); + realm_config_args.community_token_config_args.token_type = GoverningTokenType::Membership; + + let realm_cookie = governance_test + .with_realm_using_args(&realm_config_args) + .await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Act + governance_test + .revoke_community_tokens(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + // Assert + + let token_owner_record = governance_test + .get_token_owner_record_account(&token_owner_record_cookie.address) + .await; + + assert_eq!(token_owner_record.governing_token_deposit_amount, 0); + + let holding_account = governance_test + .get_token_account(&realm_cookie.community_token_holding_account) + .await; + + assert_eq!(holding_account.amount, 0); +} + +#[tokio::test] +async fn test_revoke_council_tokens() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let mut realm_config_args = RealmSetupArgs::default(); + realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership; + + let realm_cookie = governance_test + .with_realm_using_args(&realm_config_args) + .await; + + let token_owner_record_cookie = governance_test + .with_council_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Act + governance_test + .revoke_council_tokens(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + // Assert + + let token_owner_record = governance_test + .get_token_owner_record_account(&token_owner_record_cookie.address) + .await; + + assert_eq!(token_owner_record.governing_token_deposit_amount, 0); + + let holding_account = governance_test + .get_token_account(&realm_cookie.council_token_holding_account.unwrap()) + .await; + + assert_eq!(holding_account.amount, 0); +} + +#[tokio::test] +async fn test_revoke_own_council_tokens() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let mut realm_config_args = RealmSetupArgs::default(); + realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership; + + let realm_cookie = governance_test + .with_realm_using_args(&realm_config_args) + .await; + + let token_owner_record_cookie = governance_test + .with_council_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Act + governance_test + .revoke_governing_tokens_using_instruction( + &realm_cookie, + &token_owner_record_cookie, + &realm_cookie.account.config.council_mint.unwrap(), + &token_owner_record_cookie.token_owner, + token_owner_record_cookie + .account + .governing_token_deposit_amount, + NopOverride, + None, + ) + .await + .unwrap(); + + // Assert + + let token_owner_record = governance_test + .get_token_owner_record_account(&token_owner_record_cookie.address) + .await; + + assert_eq!(token_owner_record.governing_token_deposit_amount, 0); +} + +#[tokio::test] +async fn test_revoke_own_council_tokens_with_owner_must_sign_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let mut realm_config_args = RealmSetupArgs::default(); + realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership; + + let realm_cookie = governance_test + .with_realm_using_args(&realm_config_args) + .await; + + let token_owner_record_cookie = governance_test + .with_council_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Act + let err = governance_test + .revoke_governing_tokens_using_instruction( + &realm_cookie, + &token_owner_record_cookie, + &realm_cookie.account.config.council_mint.unwrap(), + &token_owner_record_cookie.token_owner, + token_owner_record_cookie + .account + .governing_token_deposit_amount, + |i| i.accounts[4].is_signer = false, // revoke_authority + Some(&[]), + ) + .await + .err() + .unwrap(); + + // Assert + + assert_eq!(err, GovernanceError::GoverningTokenOwnerMustSign.into()); +} + +#[tokio::test] +async fn test_revoke_community_tokens_with_cannot_revoke_liquid_token_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Act + let err = governance_test + .revoke_community_tokens(&realm_cookie, &token_owner_record_cookie) + .await + .err() + .unwrap(); + + // Assert + + assert_eq!(err, GovernanceError::CannotRevokeGoverningTokens.into()); +} + +#[tokio::test] +async fn test_revoke_community_tokens_with_cannot_revoke_dormant_token_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let mut realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut realm_config_args = RealmSetupArgs::default(); + realm_config_args.community_token_config_args.token_type = GoverningTokenType::Dormant; + + governance_test + .set_realm_config(&mut realm_cookie, &realm_config_args) + .await + .unwrap(); + + // Act + let err = governance_test + .revoke_community_tokens(&realm_cookie, &token_owner_record_cookie) + .await + .err() + .unwrap(); + + // Assert + + assert_eq!(err, GovernanceError::CannotRevokeGoverningTokens.into()); +} + +#[tokio::test] +async fn test_revoke_council_tokens_with_mint_authority_must_sign_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let mut realm_config_args = RealmSetupArgs::default(); + realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership; + + let realm_cookie = governance_test + .with_realm_using_args(&realm_config_args) + .await; + + let token_owner_record_cookie = governance_test + .with_council_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Act + let err = governance_test + .revoke_governing_tokens_using_instruction( + &realm_cookie, + &token_owner_record_cookie, + &realm_cookie.account.config.council_mint.unwrap(), + realm_cookie.council_mint_authority.as_ref().unwrap(), + 1, + |i| i.accounts[4].is_signer = false, // mint_authority + Some(&[]), + ) + .await + .err() + .unwrap(); + + // Assert + + assert_eq!(err, GovernanceError::MintAuthorityMustSign.into()); +} + +#[tokio::test] +async fn test_revoke_council_tokens_with_invalid_revoke_authority_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let mut realm_config_args = RealmSetupArgs::default(); + realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership; + + let realm_cookie = governance_test + .with_realm_using_args(&realm_config_args) + .await; + + let token_owner_record_cookie = governance_test + .with_council_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Act + let err = governance_test + .revoke_governing_tokens_using_instruction( + &realm_cookie, + &token_owner_record_cookie, + &realm_cookie.account.config.council_mint.unwrap(), + &Keypair::new(), // Try to use fake authority + 1, + NopOverride, + None, + ) + .await + .err() + .unwrap(); + + // Assert + + assert_eq!(err, GovernanceError::InvalidMintAuthority.into()); +} + +#[tokio::test] +async fn test_revoke_council_tokens_with_invalid_token_holding_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let mut realm_config_args = RealmSetupArgs::default(); + realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership; + + let realm_cookie = governance_test + .with_realm_using_args(&realm_config_args) + .await; + + let token_owner_record_cookie = governance_test + .with_council_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Try to revoke from the community holding account + let governing_token_holding_address = get_governing_token_holding_address( + &governance_test.program_id, + &realm_cookie.address, + &realm_cookie.account.community_mint, + ); + + // Act + let err = governance_test + .revoke_governing_tokens_using_instruction( + &realm_cookie, + &token_owner_record_cookie, + &realm_cookie.account.config.council_mint.unwrap(), + realm_cookie.council_mint_authority.as_ref().unwrap(), + 1, + |i| i.accounts[1].pubkey = governing_token_holding_address, // governing_token_holding_address + None, + ) + .await + .err() + .unwrap(); + + // Assert + + assert_eq!( + err, + GovernanceError::InvalidGoverningTokenHoldingAccount.into() + ); +} + +#[tokio::test] +async fn test_revoke_council_tokens_with_other_realm_config_account_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let mut realm_config_args = RealmSetupArgs::default(); + realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership; + + let realm_cookie = governance_test + .with_realm_using_args(&realm_config_args) + .await; + + let token_owner_record_cookie = governance_test + .with_council_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Try use other Realm config + let realm_cookie2 = governance_test.with_realm().await; + + // Act + let err = governance_test + .revoke_governing_tokens_using_instruction( + &realm_cookie, + &token_owner_record_cookie, + &realm_cookie.account.config.council_mint.unwrap(), + realm_cookie.council_mint_authority.as_ref().unwrap(), + 1, + |i| i.accounts[5].pubkey = realm_cookie2.realm_config.address, //realm_config_address + None, + ) + .await + .err() + .unwrap(); + + // Assert + + assert_eq!(err, GovernanceError::InvalidRealmConfigForRealm.into()); +} + +#[tokio::test] +async fn test_revoke_council_tokens_with_invalid_realm_config_account_address_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let mut realm_config_args = RealmSetupArgs::default(); + realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership; + + let realm_cookie = governance_test + .with_realm_using_args(&realm_config_args) + .await; + + let token_owner_record_cookie = governance_test + .with_council_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Try bypass config check by using none existing config account + let realm_config_address = Pubkey::new_unique(); + + // Act + let err = governance_test + .revoke_governing_tokens_using_instruction( + &realm_cookie, + &token_owner_record_cookie, + &realm_cookie.account.config.council_mint.unwrap(), + realm_cookie.council_mint_authority.as_ref().unwrap(), + 1, + |i| i.accounts[5].pubkey = realm_config_address, // realm_config_address + None, + ) + .await + .err() + .unwrap(); + + // Assert + + assert_eq!(err, GovernanceError::InvalidRealmConfigAddress.into()); +} + +#[tokio::test] +async fn test_revoke_council_tokens_with_token_owner_record_for_different_mint_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let mut realm_config_args = RealmSetupArgs::default(); + realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership; + + let realm_cookie = governance_test + .with_realm_using_args(&realm_config_args) + .await; + + let token_owner_record_cookie = governance_test + .with_council_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Try to revoke from the community token owner record + let token_owner_record_cookie2 = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Act + let err = governance_test + .revoke_governing_tokens_using_instruction( + &realm_cookie, + &token_owner_record_cookie, + &realm_cookie.account.config.council_mint.unwrap(), + realm_cookie.council_mint_authority.as_ref().unwrap(), + 1, + |i| i.accounts[2].pubkey = token_owner_record_cookie2.address, // token_owner_record_address + None, + ) + .await + .err() + .unwrap(); + + // Assert + + assert_eq!( + err, + GovernanceError::InvalidGoverningMintForTokenOwnerRecord.into() + ); +} + +#[tokio::test] +async fn test_revoke_council_tokens_with_too_large_amount_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let mut realm_config_args = RealmSetupArgs::default(); + realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership; + + let realm_cookie = governance_test + .with_realm_using_args(&realm_config_args) + .await; + + let token_owner_record_cookie = governance_test + .with_council_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Act + let err = governance_test + .revoke_governing_tokens_using_instruction( + &realm_cookie, + &token_owner_record_cookie, + &realm_cookie.account.config.council_mint.unwrap(), + realm_cookie.council_mint_authority.as_ref().unwrap(), + 200, + NopOverride, + None, + ) + .await + .err() + .unwrap(); + + // Assert + + assert_eq!(err, GovernanceError::InvalidRevokeAmount.into()); +} + +#[tokio::test] +async fn test_revoke_council_tokens_with_partial_revoke_amount() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let mut realm_config_args = RealmSetupArgs::default(); + realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership; + + let realm_cookie = governance_test + .with_realm_using_args(&realm_config_args) + .await; + + let token_owner_record_cookie = governance_test + .with_council_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Act + governance_test + .revoke_governing_tokens_using_instruction( + &realm_cookie, + &token_owner_record_cookie, + &realm_cookie.account.config.council_mint.unwrap(), + realm_cookie.council_mint_authority.as_ref().unwrap(), + 5, + NopOverride, + None, + ) + .await + .unwrap(); + + // Assert + + let token_owner_record = governance_test + .get_token_owner_record_account(&token_owner_record_cookie.address) + .await; + + assert_eq!(token_owner_record.governing_token_deposit_amount, 95); +} + +#[tokio::test] +async fn test_revoke_council_tokens_with_community_mint_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let mut realm_config_args = RealmSetupArgs::default(); + realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership; + + let realm_cookie = governance_test + .with_realm_using_args(&realm_config_args) + .await; + + let token_owner_record_cookie = governance_test + .with_council_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Try to use mint and authority for Community to revoke Council token + let governing_token_mint = realm_cookie.account.community_mint; + let governing_token_mint_authority = clone_keypair(&realm_cookie.community_mint_authority); + let governing_token_holding_address = get_governing_token_holding_address( + &governance_test.program_id, + &realm_cookie.address, + &governing_token_mint, + ); + + // Act + let err = governance_test + .revoke_governing_tokens_using_instruction( + &realm_cookie, + &token_owner_record_cookie, + &realm_cookie.account.config.council_mint.unwrap(), + realm_cookie.council_mint_authority.as_ref().unwrap(), + 1, + |i| { + i.accounts[1].pubkey = governing_token_holding_address; + i.accounts[3].pubkey = governing_token_mint; + i.accounts[4].pubkey = governing_token_mint_authority.pubkey(); + }, // mint_authority + Some(&[&governing_token_mint_authority]), + ) + .await + .err() + .unwrap(); + + // Assert + + assert_eq!(err, GovernanceError::CannotRevokeGoverningTokens.into()); +} + +#[tokio::test] +async fn test_revoke_council_tokens_with_not_matching_mint_and_authority_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let mut realm_config_args = RealmSetupArgs::default(); + realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership; + + let realm_cookie = governance_test + .with_realm_using_args(&realm_config_args) + .await; + + let token_owner_record_cookie = governance_test + .with_council_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Try to use a valid mint and authority not matching the Council mint + let governing_token_mint = realm_cookie.account.community_mint; + let governing_token_mint_authority = clone_keypair(&realm_cookie.community_mint_authority); + + // Act + let err = governance_test + .revoke_governing_tokens_using_instruction( + &realm_cookie, + &token_owner_record_cookie, + &realm_cookie.account.config.council_mint.unwrap(), + realm_cookie.council_mint_authority.as_ref().unwrap(), + 1, + |i| { + i.accounts[3].pubkey = governing_token_mint; + i.accounts[4].pubkey = governing_token_mint_authority.pubkey(); + }, // mint_authority + Some(&[&governing_token_mint_authority]), + ) + .await + .err() + .unwrap(); + + // Assert + + assert_eq!( + err, + GovernanceError::InvalidGoverningTokenHoldingAccount.into() + ); +} diff --git a/governance/program/tests/process_set_governance_config.rs b/governance/program/tests/process_set_governance_config.rs index 8d2c5d24f91..5a3f829c9f0 100644 --- a/governance/program/tests/process_set_governance_config.rs +++ b/governance/program/tests/process_set_governance_config.rs @@ -1,16 +1,17 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] mod program_test; -use program_test::*; -use solana_program_test::tokio; -use solana_sdk::{signature::Keypair, signer::Signer}; -use spl_governance::{ - error::GovernanceError, instruction::set_governance_config, state::enums::VoteThreshold, +use { + program_test::*, + solana_program_test::tokio, + solana_sdk::{signature::Keypair, signer::Signer}, + spl_governance::{ + error::GovernanceError, instruction::set_governance_config, state::enums::VoteThreshold, + }, + spl_governance_test_sdk::tools::ProgramInstructionError, + spl_governance_tools::error::GovernanceToolsError, }; -use spl_governance_test_sdk::tools::ProgramInstructionError; - -use spl_governance_tools::error::GovernanceToolsError; #[tokio::test] async fn test_set_governance_config() { @@ -18,7 +19,6 @@ async fn test_set_governance_config() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -26,11 +26,7 @@ async fn test_set_governance_config() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -40,7 +36,11 @@ async fn test_set_governance_config() { .unwrap(); let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) .await .unwrap(); @@ -70,7 +70,9 @@ async fn test_set_governance_config() { // Advance timestamp past hold_up_time governance_test - .advance_clock_by_min_timespan(proposal_transaction_cookie.account.hold_up_time as u64) + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) .await; // Act @@ -132,7 +134,8 @@ async fn test_set_governance_config_with_fake_governance_signer_error() { new_governance_config.clone(), ); - // Set Governance signer to fake account we have authority over and can use to sign the transaction + // Set Governance signer to fake account we have authority over and can use to + // sign the transaction let governance_signer = Keypair::new(); set_governance_config_ix.accounts[0].pubkey = governance_signer.pubkey(); @@ -154,7 +157,6 @@ async fn test_set_governance_config_with_invalid_governance_authority_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -162,11 +164,7 @@ async fn test_set_governance_config_with_invalid_governance_authority_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -176,19 +174,19 @@ async fn test_set_governance_config_with_invalid_governance_authority_error() { .unwrap(); let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) .await .unwrap(); - // Try to maliciously use a different governance account to change the given governance config - let governed_account_cookie2 = governance_test.with_governed_account().await; + // Try to maliciously use a different governance account to change the given + // governance config let governance_cookie2 = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie2, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -207,7 +205,6 @@ async fn test_set_governance_config_with_invalid_governance_authority_error() { 0, None, &mut set_governance_config_ix, - None, ) .await .unwrap(); @@ -224,7 +221,9 @@ async fn test_set_governance_config_with_invalid_governance_authority_error() { // Advance timestamp past hold_up_time governance_test - .advance_clock_by_min_timespan(proposal_transaction_cookie.account.hold_up_time as u64) + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) .await; // Act diff --git a/governance/program/tests/process_set_governance_delegate.rs b/governance/program/tests/process_set_governance_delegate.rs index fa5452584d6..1c468eb2d24 100644 --- a/governance/program/tests/process_set_governance_delegate.rs +++ b/governance/program/tests/process_set_governance_delegate.rs @@ -1,13 +1,14 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] -use solana_program::instruction::AccountMeta; -use solana_program_test::*; +use {solana_program::instruction::AccountMeta, solana_program_test::*}; mod program_test; -use program_test::*; -use solana_sdk::signature::{Keypair, Signer}; -use spl_governance::{error::GovernanceError, instruction::set_governance_delegate}; +use { + program_test::*, + solana_sdk::signature::{Keypair, Signer}, + spl_governance::{error::GovernanceError, instruction::set_governance_delegate}, +}; #[tokio::test] async fn test_set_community_governance_delegate() { diff --git a/governance/program/tests/process_set_realm_authority.rs b/governance/program/tests/process_set_realm_authority.rs index d6ed16e8039..cdbd639b217 100644 --- a/governance/program/tests/process_set_realm_authority.rs +++ b/governance/program/tests/process_set_realm_authority.rs @@ -1,13 +1,13 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] -use solana_program::pubkey::Pubkey; -use solana_program_test::*; +use {solana_program::pubkey::Pubkey, solana_program_test::*}; mod program_test; -use program_test::*; -use spl_governance::error::GovernanceError; -use spl_governance_tools::error::GovernanceToolsError; +use { + program_test::*, spl_governance::error::GovernanceError, + spl_governance_tools::error::GovernanceToolsError, +}; #[tokio::test] async fn test_set_realm_authority() { @@ -16,19 +16,13 @@ async fn test_set_realm_authority() { let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; - let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) .await .unwrap(); let governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -197,19 +191,13 @@ async fn test_set_realm_authority_with_governance_from_other_realm_error() { // Setup other realm let realm_cookie2 = governance_test.with_realm().await; - let governed_account_cookie2 = governance_test.with_governed_account().await; - let token_owner_record_cookie2 = governance_test .with_community_token_deposit(&realm_cookie2) .await .unwrap(); let governance_cookie2 = governance_test - .with_governance( - &realm_cookie2, - &governed_account_cookie2, - &token_owner_record_cookie2, - ) + .with_governance(&realm_cookie2, &token_owner_record_cookie2) .await .unwrap(); diff --git a/governance/program/tests/process_set_realm_config.rs b/governance/program/tests/process_set_realm_config.rs index 0b675158abc..47af3cc4d33 100644 --- a/governance/program/tests/process_set_realm_config.rs +++ b/governance/program/tests/process_set_realm_config.rs @@ -1,18 +1,18 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] -use solana_program::pubkey::Pubkey; -use solana_program_test::*; +use {solana_program::pubkey::Pubkey, solana_program_test::*, solana_sdk::signer::Signer}; mod program_test; -use program_test::*; -use spl_governance::{ - error::GovernanceError, - state::{enums::MintMaxVoteWeightSource, realm::RealmConfigArgs}, +use { + crate::program_test::args::RealmSetupArgs, + program_test::*, + spl_governance::{ + error::GovernanceError, + state::{realm::GoverningTokenConfigAccountArgs, realm_config::GoverningTokenType}, + }, }; -use self::args::SetRealmConfigArgs; - #[tokio::test] async fn test_set_realm_config() { // Arrange @@ -20,25 +20,12 @@ async fn test_set_realm_config() { let mut realm_cookie = governance_test.with_realm().await; - let realm_config_args = RealmConfigArgs { - use_council_mint: true, - - community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(100), - min_community_weight_to_create_governance: 10, - use_community_voter_weight_addin: false, - use_max_community_voter_weight_addin: false, - }; - - let set_realm_config_args = SetRealmConfigArgs { - realm_config_args, - community_voter_weight_addin: None, - max_community_voter_weight_addin: None, - }; + let realm_setup_args = RealmSetupArgs::default(); // Act governance_test - .set_realm_config(&mut realm_cookie, &set_realm_config_args) + .set_realm_config(&mut realm_cookie, &realm_setup_args) .await .unwrap(); @@ -57,27 +44,14 @@ async fn test_set_realm_config_with_authority_must_sign_error() { let mut realm_cookie = governance_test.with_realm().await; - let realm_config_args = RealmConfigArgs { - use_council_mint: true, - - community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(100), - min_community_weight_to_create_governance: 10, - use_community_voter_weight_addin: false, - use_max_community_voter_weight_addin: false, - }; - - let set_realm_config_args = SetRealmConfigArgs { - realm_config_args, - community_voter_weight_addin: None, - max_community_voter_weight_addin: None, - }; + let realm_setup_args = RealmSetupArgs::default(); // Act let err = governance_test .set_realm_config_using_instruction( &mut realm_cookie, - &set_realm_config_args, + &realm_setup_args, |i| i.accounts[1].is_signer = false, Some(&[]), ) @@ -96,20 +70,7 @@ async fn test_set_realm_config_with_no_authority_error() { let mut realm_cookie = governance_test.with_realm().await; - let realm_config_args = RealmConfigArgs { - use_council_mint: true, - - community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(100), - min_community_weight_to_create_governance: 10, - use_community_voter_weight_addin: false, - use_max_community_voter_weight_addin: false, - }; - - let set_realm_config_args = SetRealmConfigArgs { - realm_config_args, - community_voter_weight_addin: None, - max_community_voter_weight_addin: None, - }; + let realm_setup_args = RealmSetupArgs::default(); governance_test .set_realm_authority(&realm_cookie, None) @@ -121,7 +82,7 @@ async fn test_set_realm_config_with_no_authority_error() { let err = governance_test .set_realm_config_using_instruction( &mut realm_cookie, - &set_realm_config_args, + &realm_setup_args, |i| i.accounts[1].is_signer = false, Some(&[]), ) @@ -140,20 +101,7 @@ async fn test_set_realm_config_with_invalid_authority_error() { let mut realm_cookie = governance_test.with_realm().await; - let realm_config_args = RealmConfigArgs { - use_council_mint: true, - - community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(100), - min_community_weight_to_create_governance: 10, - use_community_voter_weight_addin: false, - use_max_community_voter_weight_addin: false, - }; - - let set_realm_config_args = SetRealmConfigArgs { - realm_config_args, - community_voter_weight_addin: None, - max_community_voter_weight_addin: None, - }; + let realm_setup_args = RealmSetupArgs::default(); let realm_cookie2 = governance_test.with_realm().await; @@ -163,7 +111,7 @@ async fn test_set_realm_config_with_invalid_authority_error() { // Act let err = governance_test - .set_realm_config(&mut realm_cookie, &set_realm_config_args) + .set_realm_config(&mut realm_cookie, &realm_setup_args) .await .err() .unwrap(); @@ -179,24 +127,14 @@ async fn test_set_realm_config_with_remove_council() { let mut realm_cookie = governance_test.with_realm().await; - let realm_config_args = RealmConfigArgs { + let realm_setup_args = RealmSetupArgs { use_council_mint: false, - - community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(100), - min_community_weight_to_create_governance: 10, - use_community_voter_weight_addin: false, - use_max_community_voter_weight_addin: false, - }; - - let set_realm_config_args = SetRealmConfigArgs { - realm_config_args, - community_voter_weight_addin: None, - max_community_voter_weight_addin: None, + ..Default::default() }; // Act governance_test - .set_realm_config(&mut realm_cookie, &set_realm_config_args) + .set_realm_config(&mut realm_cookie, &realm_setup_args) .await .unwrap(); @@ -216,27 +154,14 @@ async fn test_set_realm_config_with_council_change_error() { let mut realm_cookie = governance_test.with_realm().await; - let realm_config_args = RealmConfigArgs { - use_council_mint: true, - - community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(100), - min_community_weight_to_create_governance: 10, - use_community_voter_weight_addin: false, - use_max_community_voter_weight_addin: false, - }; - - let set_realm_config_args = SetRealmConfigArgs { - realm_config_args, - community_voter_weight_addin: None, - max_community_voter_weight_addin: None, - }; + let realm_setup_args = RealmSetupArgs::default(); // Try to replace council mint realm_cookie.account.config.council_mint = serde::__private::Some(Pubkey::new_unique()); // Act let err = governance_test - .set_realm_config(&mut realm_cookie, &set_realm_config_args) + .set_realm_config(&mut realm_cookie, &realm_setup_args) .await .err() .unwrap(); @@ -255,33 +180,23 @@ async fn test_set_realm_config_with_council_restore_error() { let mut realm_cookie = governance_test.with_realm().await; - let realm_config_args = RealmConfigArgs { + let mut realm_setup_args = RealmSetupArgs { use_council_mint: false, - - community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(100), - min_community_weight_to_create_governance: 10, - use_community_voter_weight_addin: false, - use_max_community_voter_weight_addin: false, - }; - - let mut set_realm_config_args = SetRealmConfigArgs { - realm_config_args, - community_voter_weight_addin: None, - max_community_voter_weight_addin: None, + ..Default::default() }; governance_test - .set_realm_config(&mut realm_cookie, &set_realm_config_args) + .set_realm_config(&mut realm_cookie, &realm_setup_args) .await .unwrap(); // Try to restore council mint after removing it - set_realm_config_args.realm_config_args.use_council_mint = true; + realm_setup_args.use_council_mint = true; realm_cookie.account.config.council_mint = serde::__private::Some(Pubkey::new_unique()); // Act let err = governance_test - .set_realm_config(&mut realm_cookie, &set_realm_config_args) + .set_realm_config(&mut realm_cookie, &realm_setup_args) .await .err() .unwrap(); @@ -292,3 +207,208 @@ async fn test_set_realm_config_with_council_restore_error() { GovernanceError::RealmCouncilMintChangeIsNotSupported.into() ); } + +#[tokio::test] +async fn test_set_realm_config_with_liquid_community_token_cannot_be_changed_to_memebership_error() +{ + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let mut realm_cookie = governance_test.with_realm().await; + + let mut realm_setup_args = RealmSetupArgs::default(); + + // Try to change Community token type to Membership + realm_setup_args.community_token_config_args.token_type = GoverningTokenType::Membership; + + // Act + let err = governance_test + .set_realm_config(&mut realm_cookie, &realm_setup_args) + .await + .err() + .unwrap(); + + // Assert + assert_eq!( + err, + GovernanceError::CannotChangeCommunityTokenTypeToMembership.into() + ); +} + +#[tokio::test] +async fn test_set_realm_config_for_community_token_config() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let mut realm_cookie = governance_test.with_realm().await; + + // Change Community token type to Dormant and set plugins + let realm_setup_args = RealmSetupArgs { + community_token_config_args: GoverningTokenConfigAccountArgs { + voter_weight_addin: Some(Pubkey::new_unique()), + max_voter_weight_addin: Some(Pubkey::new_unique()), + token_type: GoverningTokenType::Dormant, + }, + ..Default::default() + }; + + // Act + + governance_test + .set_realm_config(&mut realm_cookie, &realm_setup_args) + .await + .unwrap(); + + // Assert + + let realm_config_account = governance_test + .get_realm_config_account(&realm_cookie.realm_config.address) + .await; + + assert_eq!( + realm_config_account.community_token_config.token_type, + GoverningTokenType::Dormant + ); + + assert_eq!( + realm_config_account + .community_token_config + .voter_weight_addin, + realm_setup_args + .community_token_config_args + .voter_weight_addin + ); + + assert_eq!( + realm_config_account + .community_token_config + .max_voter_weight_addin, + realm_setup_args + .community_token_config_args + .max_voter_weight_addin + ); +} + +#[tokio::test] +async fn test_set_realm_config_for_council_token_config() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let mut realm_cookie = governance_test.with_realm().await; + + // Change Council token type to Membership and set plugins + let realm_setup_args = RealmSetupArgs { + council_token_config_args: GoverningTokenConfigAccountArgs { + voter_weight_addin: Some(Pubkey::new_unique()), + max_voter_weight_addin: Some(Pubkey::new_unique()), + token_type: GoverningTokenType::Membership, + }, + ..Default::default() + }; + + // Act + + governance_test + .set_realm_config(&mut realm_cookie, &realm_setup_args) + .await + .unwrap(); + + // Assert + + let realm_config_account = governance_test + .get_realm_config_account(&realm_cookie.realm_config.address) + .await; + + assert_eq!( + realm_config_account.council_token_config.token_type, + GoverningTokenType::Membership + ); + + assert_eq!( + realm_config_account.council_token_config.voter_weight_addin, + realm_setup_args + .council_token_config_args + .voter_weight_addin + ); + + assert_eq!( + realm_config_account + .council_token_config + .max_voter_weight_addin, + realm_setup_args + .council_token_config_args + .max_voter_weight_addin + ); +} + +#[tokio::test] +async fn test_set_realm_config_without_existing_realm_config() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let mut realm_cookie = governance_test.with_realm().await; + + let realm_setup_args = RealmSetupArgs::default(); + + governance_test.remove_realm_config_account(&realm_cookie.realm_config.address); + + // Act + + governance_test + .set_realm_config(&mut realm_cookie, &realm_setup_args) + .await + .unwrap(); + + // Assert + let realm_account = governance_test + .get_realm_account(&realm_cookie.address) + .await; + + assert_eq!(realm_cookie.account, realm_account); +} + +#[tokio::test] +async fn test_set_realm_config_with_token_owner_record_lock_authorities() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let mut realm_cookie = governance_test.with_realm().await; + + let community_token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let council_token_owner_record_lock_authority_cookie = governance_test + .with_council_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let realm_setup_args = RealmSetupArgs::default(); + + // Act + + governance_test + .set_realm_config(&mut realm_cookie, &realm_setup_args) + .await + .unwrap(); + + // Assert + let realm_config_account = governance_test + .get_realm_config_account(&realm_cookie.realm_config.address) + .await; + + assert_eq!( + vec![community_token_owner_record_lock_authority_cookie + .authority + .pubkey()], + realm_config_account.community_token_config.lock_authorities + ); + + assert_eq!( + vec![council_token_owner_record_lock_authority_cookie + .authority + .pubkey()], + realm_config_account.council_token_config.lock_authorities + ); +} diff --git a/governance/program/tests/process_set_realm_config_item.rs b/governance/program/tests/process_set_realm_config_item.rs new file mode 100644 index 00000000000..fc4e6753ef8 --- /dev/null +++ b/governance/program/tests/process_set_realm_config_item.rs @@ -0,0 +1,386 @@ +#![cfg(feature = "test-sbf")] + +mod program_test; + +use { + program_test::*, + solana_program::pubkey::Pubkey, + solana_program_test::tokio, + solana_sdk::{signature::Keypair, signer::Signer}, + spl_governance::{ + error::GovernanceError, + state::{ + enums::GovernanceAccountType, + realm::SetRealmConfigItemArgs, + realm_config::{GoverningTokenConfig, RealmConfigAccount}, + }, + tools::structs::{Reserved110, SetConfigItemActionType}, + }, + spl_governance_tools::account::AccountMaxSize, +}; + +#[tokio::test] +async fn test_add_community_token_owner_record_lock_authority() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + // Act + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + // Assert + let realm_config_account = governance_test + .get_realm_config_account(&realm_cookie.realm_config.address) + .await; + + assert_eq!( + 1, + realm_config_account + .community_token_config + .lock_authorities + .len() + ); + + assert_eq!( + &token_owner_record_lock_authority_cookie.authority.pubkey(), + realm_config_account + .community_token_config + .lock_authorities + .first() + .unwrap() + ); +} + +#[tokio::test] +async fn test_remove_community_token_owner_record_lock_authority() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + // Act + + let args = SetRealmConfigItemArgs::TokenOwnerRecordLockAuthority { + action: SetConfigItemActionType::Remove, + governing_token_mint: realm_cookie.account.community_mint, + authority: token_owner_record_lock_authority_cookie.authority.pubkey(), + }; + + governance_test + .set_realm_config_item(&realm_cookie, args) + .await + .unwrap(); + + // Assert + let realm_config_account = governance_test + .get_realm_config_account(&realm_cookie.realm_config.address) + .await; + + assert_eq!( + 0, + realm_config_account + .community_token_config + .lock_authorities + .len() + ); +} + +#[tokio::test] +async fn test_add_council_token_owner_record_lock_authority() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + // Act + let token_owner_record_lock_authority_cookie = governance_test + .with_council_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + // Assert + let realm_config_account = governance_test + .get_realm_config_account(&realm_cookie.realm_config.address) + .await; + + assert_eq!( + 1, + realm_config_account + .council_token_config + .lock_authorities + .len() + ); + + assert_eq!( + &token_owner_record_lock_authority_cookie.authority.pubkey(), + realm_config_account + .council_token_config + .lock_authorities + .first() + .unwrap() + ); +} + +#[tokio::test] +async fn test_set_realm_config_item_with_realm_authority_must_sign_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let args = SetRealmConfigItemArgs::TokenOwnerRecordLockAuthority { + action: SetConfigItemActionType::Add, + governing_token_mint: realm_cookie.account.community_mint, + authority: Keypair::new().pubkey(), + }; + + // Act + let err = governance_test + .set_realm_config_item_using_ix( + &realm_cookie, + args, + |i| i.accounts[2].is_signer = false, + Some(&[]), + ) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::RealmAuthorityMustSign.into()); +} + +#[tokio::test] +async fn test_set_realm_config_item_with_invalid_realm_authority_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let args = SetRealmConfigItemArgs::TokenOwnerRecordLockAuthority { + action: SetConfigItemActionType::Add, + governing_token_mint: realm_cookie.account.community_mint, + authority: Keypair::new().pubkey(), + }; + + let realm_authority = Keypair::new(); + + // Act + let err = governance_test + .set_realm_config_item_using_ix( + &realm_cookie, + args, + |i| i.accounts[2].pubkey = realm_authority.pubkey(), + Some(&[&realm_authority]), + ) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::InvalidAuthorityForRealm.into()); +} + +#[tokio::test] +async fn test_set_realm_config_item_with_invalid_realm_config_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let args = SetRealmConfigItemArgs::TokenOwnerRecordLockAuthority { + action: SetConfigItemActionType::Add, + governing_token_mint: realm_cookie.account.community_mint, + authority: Keypair::new().pubkey(), + }; + + let realm_cookie2 = governance_test.with_realm().await; + + // Act + let err = governance_test + .set_realm_config_item_using_ix( + &realm_cookie, + args, + |i| i.accounts[1].pubkey = realm_cookie2.realm_config.address, + None, + ) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::InvalidRealmConfigForRealm.into()); +} + +#[tokio::test] +async fn test_add_token_owner_record_lock_authority_with_invalid_governing_token_mint() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let args = SetRealmConfigItemArgs::TokenOwnerRecordLockAuthority { + action: SetConfigItemActionType::Add, + governing_token_mint: Pubkey::new_unique(), // Use invalid mint + authority: Keypair::new().pubkey(), + }; + + // Act + let err = governance_test + .set_realm_config_item(&realm_cookie, args) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::InvalidGoverningTokenMint.into()); +} + +#[tokio::test] +async fn test_add_token_owner_record_lock_authority_with_authority_already_exists_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let args = SetRealmConfigItemArgs::TokenOwnerRecordLockAuthority { + action: SetConfigItemActionType::Add, + governing_token_mint: realm_cookie.account.config.council_mint.unwrap(), + // Set the same authority + authority: Pubkey::new_unique(), + }; + + governance_test + .set_realm_config_item(&realm_cookie, args.clone()) + .await + .unwrap(); + + // Advance the clock to accept the same transaction + governance_test.advance_clock().await; + + // Act + let err = governance_test + .set_realm_config_item(&realm_cookie, args) + .await + .err() + .unwrap(); + + // Assert + assert_eq!( + err, + GovernanceError::TokenOwnerRecordLockAuthorityAlreadyExists.into() + ); +} + +#[tokio::test] +async fn test_set_realm_config_item_without_existing_realm_config() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + governance_test.remove_realm_config_account(&realm_cookie.realm_config.address); + + // Act + governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + // Assert + let realm_config_account = governance_test + .get_realm_config_account(&realm_cookie.realm_config.address) + .await; + + assert_eq!( + 1, + realm_config_account + .community_token_config + .lock_authorities + .len() + ); +} + +#[tokio::test] +async fn test_set_realm_config_item_with_extended_account_size() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + // Act + governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + // Assert + let realm_config_account = governance_test + .bench + .get_account(&realm_cookie.realm_config.address) + .await + .unwrap(); + + // RealmConfig without any lock authorities + let realm_config = RealmConfigAccount { + account_type: GovernanceAccountType::RealmConfig, + realm: realm_cookie.address, + community_token_config: GoverningTokenConfig::default(), + council_token_config: GoverningTokenConfig::default(), + reserved: Reserved110::default(), + }; + + assert_eq!( + realm_config.get_max_size().unwrap() + 32, + realm_config_account.data.len() + ); +} + +#[tokio::test] +async fn test_remove_token_owner_record_lock_authority_with_authority_not_found_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let args = SetRealmConfigItemArgs::TokenOwnerRecordLockAuthority { + action: SetConfigItemActionType::Remove, + governing_token_mint: realm_cookie.account.community_mint, + authority: token_owner_record_lock_authority_cookie.authority.pubkey(), + }; + + governance_test + .set_realm_config_item(&realm_cookie, args.clone()) + .await + .unwrap(); + + // Advance the clock to accept the same transaction + governance_test.advance_clock().await; + + // Act + let err = governance_test + .set_realm_config_item(&realm_cookie, args) + .await + .err() + .unwrap(); + + // Assert + assert_eq!( + err, + GovernanceError::TokenOwnerRecordLockAuthorityNotFound.into() + ); +} diff --git a/governance/program/tests/process_set_token_owner_record_lock.rs b/governance/program/tests/process_set_token_owner_record_lock.rs new file mode 100644 index 00000000000..3fe63c621c2 --- /dev/null +++ b/governance/program/tests/process_set_token_owner_record_lock.rs @@ -0,0 +1,706 @@ +#![cfg(feature = "test-sbf")] + +mod program_test; + +use { + program_test::*, + solana_program_test::tokio, + solana_sdk::{signature::Keypair, signer::Signer}, + spl_governance::{ + error::GovernanceError, + state::{enums::GovernanceAccountType, legacy::TokenOwnerRecordV1}, + }, + spl_governance_tools::account::AccountMaxSize, +}; + +#[tokio::test] +async fn test_set_token_owner_record_lock() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + // Act + let token_owner_record_lock_cookie = governance_test + .with_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + ) + .await + .unwrap(); + + // Assert + let token_owner_record_account = governance_test + .get_token_owner_record_account(&token_owner_record_cookie.address) + .await; + + assert_eq!(1, token_owner_record_account.locks.len()); + assert_eq!( + token_owner_record_lock_cookie.authority, + token_owner_record_account.locks[0].authority + ); + assert_eq!( + token_owner_record_lock_cookie.lock_id, + token_owner_record_account.locks[0].lock_id + ); + assert_eq!( + token_owner_record_lock_cookie.expiry, + token_owner_record_account.locks[0].expiry + ); +} + +#[tokio::test] +async fn test_override_existing_token_owner_record_lock() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_cookie = governance_test + .with_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + ) + .await + .unwrap(); + + let expiry = None; + let lock_id = token_owner_record_lock_cookie.lock_id; + + // Act + + governance_test + .set_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + lock_id, + expiry, + ) + .await + .unwrap(); + + // Assert + let token_owner_record_account = governance_test + .get_token_owner_record_account(&token_owner_record_cookie.address) + .await; + + assert_eq!(1, token_owner_record_account.locks.len()); + assert_eq!( + token_owner_record_lock_authority_cookie.authority.pubkey(), + token_owner_record_account.locks[0].authority + ); + assert_eq!(lock_id, token_owner_record_account.locks[0].lock_id); + assert_eq!(expiry, token_owner_record_account.locks[0].expiry); +} + +#[tokio::test] +async fn test_set_token_owner_record_lock_and_trim_expired_lock() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_cookie = governance_test + .with_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + ) + .await + .unwrap(); + + governance_test + .advance_clock_past_timestamp(token_owner_record_lock_cookie.expiry.unwrap()) + .await; + + let expiry = None; + let lock_id = 101; + + // Act + + governance_test + .set_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + lock_id, + expiry, + ) + .await + .unwrap(); + + // Assert + let token_owner_record_account = governance_test + .get_token_owner_record_account(&token_owner_record_cookie.address) + .await; + + assert_eq!(1, token_owner_record_account.locks.len()); + assert_eq!( + token_owner_record_lock_authority_cookie.authority.pubkey(), + token_owner_record_account.locks[0].authority + ); + assert_eq!(lock_id, token_owner_record_account.locks[0].lock_id); + assert_eq!(expiry, token_owner_record_account.locks[0].expiry); +} + +#[tokio::test] +async fn test_set_multiple_token_owner_record_locks() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie1 = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie2 = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + // Act + let token_owner_record_lock_cookie1 = governance_test + .with_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie1, + ) + .await + .unwrap(); + + let token_owner_record_lock_cookie2 = governance_test + .with_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie2, + ) + .await + .unwrap(); + + // Assert + let token_owner_record_account = governance_test + .get_token_owner_record_account(&token_owner_record_cookie.address) + .await; + + assert_eq!(2, token_owner_record_account.locks.len()); + assert_eq!( + token_owner_record_lock_cookie1.authority, + token_owner_record_account.locks[0].authority + ); + assert_eq!( + token_owner_record_lock_cookie2.authority, + token_owner_record_account.locks[1].authority + ); +} + +#[tokio::test] +async fn test_set_token_owner_record_lock_with_lock_authority_must_sign_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let expiry = None; + let lock_id = 101; + + // Act + let err = governance_test + .set_token_owner_record_lock_using_ix( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + lock_id, + expiry, + |i| i.accounts[3].is_signer = false, + Some(&[]), + ) + .await + .err() + .unwrap(); + + // Assert + assert_eq!( + err, + GovernanceError::TokenOwnerRecordLockAuthorityMustSign.into() + ); +} + +#[tokio::test] +async fn test_set_token_owner_record_lock_with_invalid_lock_authority_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let expiry = None; + let lock_id = 101; + let lock_authority = Keypair::new(); + + // Act + let err = governance_test + .set_token_owner_record_lock_using_ix( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + lock_id, + expiry, + |i| i.accounts[3].pubkey = lock_authority.pubkey(), + Some(&[&lock_authority]), + ) + .await + .err() + .unwrap(); + + // Assert + assert_eq!( + err, + GovernanceError::InvalidTokenOwnerRecordLockAuthority.into() + ); +} + +#[tokio::test] +async fn test_set_token_owner_record_lock_with_invalid_realm_config_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + let realm_cookie2 = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let expiry = None; + let lock_id = 101; + + // Act + let err = governance_test + .set_token_owner_record_lock_using_ix( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + lock_id, + expiry, + |i| i.accounts[1].pubkey = realm_cookie2.realm_config.address, + None, + ) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::InvalidRealmConfigForRealm.into()); +} + +#[tokio::test] +async fn test_set_token_owner_record_lock_with_invalid_token_owner_record_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + let realm_cookie2 = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_cookie2 = governance_test + .with_community_token_deposit(&realm_cookie2) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let expiry = None; + let lock_id = 101; + + // Act + let err = governance_test + .set_token_owner_record_lock_using_ix( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + lock_id, + expiry, + |i| i.accounts[2].pubkey = token_owner_record_cookie2.address, + None, + ) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::InvalidRealmForTokenOwnerRecord.into()); +} + +#[tokio::test] +async fn test_set_community_token_owner_record_lock_with_council_authority_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let council_token_owner_record_lock_authority_cookie = governance_test + .with_council_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + // Act + let err = governance_test + .with_token_owner_record_lock( + &token_owner_record_cookie, + &council_token_owner_record_lock_authority_cookie, + ) + .await + .err() + .unwrap(); + + // Assert + assert_eq!( + err, + GovernanceError::InvalidTokenOwnerRecordLockAuthority.into() + ); +} + +#[tokio::test] +async fn test_set_community_token_owner_record_lock_with_expired_lock_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let expiry = Some(0); + let lock_id = 101; + + // Act + let err = governance_test + .set_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + lock_id, + expiry, + ) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::ExpiredTokenOwnerRecordLock.into()); +} + +#[tokio::test] +async fn test_set_token_owner_record_lock_with_extended_account_size() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let mut token_owner_record_account = governance_test + .bench + .get_account(&token_owner_record_cookie.address) + .await + .unwrap(); + + let token_owner_record_account_size = token_owner_record_account.data.len(); + + // Act + governance_test + .with_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + ) + .await + .unwrap(); + + // Assert + token_owner_record_account = governance_test + .bench + .get_account(&token_owner_record_cookie.address) + .await + .unwrap(); + + assert_eq!( + token_owner_record_account_size + 42, + token_owner_record_account.data.len() + ); +} + +#[tokio::test] +async fn test_set_token_owner_record_lock_for_v1_account() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_data_v1 = TokenOwnerRecordV1 { + account_type: GovernanceAccountType::TokenOwnerRecordV1, + realm: token_owner_record_cookie.account.realm, + governing_token_mint: token_owner_record_cookie.account.governing_token_mint, + governing_token_owner: token_owner_record_cookie.account.governing_token_owner, + governing_token_deposit_amount: token_owner_record_cookie + .account + .governing_token_deposit_amount, + governance_delegate: token_owner_record_cookie.account.governance_delegate, + unrelinquished_votes_count: token_owner_record_cookie.account.unrelinquished_votes_count, + outstanding_proposal_count: token_owner_record_cookie.account.outstanding_proposal_count, + version: 0, + reserved: [0; 6], + }; + + governance_test.bench.set_borsh_account( + &governance_test.program_id, + &token_owner_record_cookie.address, + &token_owner_record_data_v1, + ); + + // Act + governance_test + .with_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + ) + .await + .unwrap(); + + // Assert + let token_owner_record_data = governance_test + .get_token_owner_record_account(&token_owner_record_cookie.address) + .await; + + assert_eq!( + GovernanceAccountType::TokenOwnerRecordV2, + token_owner_record_data.account_type + ); + + let token_owner_record_account = governance_test + .bench + .get_account(&token_owner_record_cookie.address) + .await + .unwrap(); + + assert_eq!( + token_owner_record_data.get_max_size().unwrap(), + token_owner_record_account.data.len() + ); +} + +#[tokio::test] +async fn test_set_token_owner_record_lock_with_non_expiring_and_expiring_locks() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let lock_id1 = 0; + let expiry1 = None; + + let lock_id2 = 1; + let clock = governance_test.bench.get_clock().await; + let expiry2 = Some(clock.unix_timestamp + 1); + + // Act + + governance_test + .set_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + lock_id1, + expiry1, + ) + .await + .unwrap(); + + governance_test + .set_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + lock_id2, + expiry2, + ) + .await + .unwrap(); + + // Assert + let token_owner_record_account = governance_test + .get_token_owner_record_account(&token_owner_record_cookie.address) + .await; + + assert_eq!(None, token_owner_record_account.locks[0].expiry); + assert_eq!(expiry2, token_owner_record_account.locks[1].expiry); +} + +#[tokio::test] +async fn test_set_token_owner_record_lock_with_multiple_non_expiring_locks() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + let lock_id1 = 0; + let expiry1 = None; + + let lock_id2 = 1; + let expiry2 = None; + + governance_test + .set_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + lock_id1, + expiry1, + ) + .await + .unwrap(); + + governance_test + .set_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + lock_id2, + expiry2, + ) + .await + .unwrap(); + + let clock = governance_test.bench.get_clock().await; + let new_expiry1 = Some(clock.unix_timestamp + 1); + + // Act + + governance_test + .set_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + lock_id1, + new_expiry1, + ) + .await + .unwrap(); + + // Assert + let token_owner_record_account = governance_test + .get_token_owner_record_account(&token_owner_record_cookie.address) + .await; + + assert_eq!(new_expiry1, token_owner_record_account.locks[0].expiry); + assert_eq!(None, token_owner_record_account.locks[1].expiry); +} diff --git a/governance/program/tests/process_sign_off_proposal.rs b/governance/program/tests/process_sign_off_proposal.rs index e7b53e8af53..ded1604aba6 100644 --- a/governance/program/tests/process_sign_off_proposal.rs +++ b/governance/program/tests/process_sign_off_proposal.rs @@ -1,11 +1,15 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] mod program_test; -use solana_program_test::tokio; - -use program_test::*; -use spl_governance::{error::GovernanceError, state::enums::ProposalState}; +use { + program_test::*, + solana_program::pubkey::Pubkey, + solana_program_test::tokio, + solana_sdk::signature::{Keypair, Signer}, + spl_governance::{error::GovernanceError, state::enums::ProposalState}, + spl_governance_tools::error::GovernanceToolsError, +}; #[tokio::test] async fn test_sign_off_proposal() { @@ -13,7 +17,6 @@ async fn test_sign_off_proposal() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -21,11 +24,7 @@ async fn test_sign_off_proposal() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -35,7 +34,11 @@ async fn test_sign_off_proposal() { .unwrap(); let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) .await .unwrap(); @@ -63,19 +66,7 @@ async fn test_sign_off_proposal() { .get_signatory_record_account(&signatory_record_cookie.address) .await; - assert_eq!(true, signatory_record_account.signed_off); - - let realm_account = governance_test - .get_realm_account(&realm_cookie.address) - .await; - - assert_eq!(1, realm_account.voting_proposal_count); - - let governance_account = governance_test - .get_governance_account(&governance_cookie.address) - .await; - - assert_eq!(1, governance_account.voting_proposal_count); + assert!(signatory_record_account.signed_off); } #[tokio::test] @@ -84,7 +75,6 @@ async fn test_sign_off_proposal_with_signatory_must_sign_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -92,11 +82,7 @@ async fn test_sign_off_proposal_with_signatory_must_sign_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -106,7 +92,11 @@ async fn test_sign_off_proposal_with_signatory_must_sign_error() { .unwrap(); let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) .await .unwrap(); @@ -132,7 +122,6 @@ async fn test_sign_off_proposal_by_owner() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -140,11 +129,7 @@ async fn test_sign_off_proposal_by_owner() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -180,7 +165,6 @@ async fn test_sign_off_proposal_by_owner_with_owner_must_sign_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -188,11 +172,7 @@ async fn test_sign_off_proposal_by_owner_with_owner_must_sign_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -227,7 +207,6 @@ async fn test_sign_off_proposal_by_owner_with_other_proposal_owner_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -235,11 +214,7 @@ async fn test_sign_off_proposal_by_owner_with_other_proposal_owner_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -271,7 +246,6 @@ async fn test_sign_off_proposal_by_owner_with_existing_signatories_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -279,11 +253,7 @@ async fn test_sign_off_proposal_by_owner_with_existing_signatories_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -293,7 +263,11 @@ async fn test_sign_off_proposal_by_owner_with_existing_signatories_error() { .unwrap(); governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) .await .unwrap(); @@ -309,3 +283,637 @@ async fn test_sign_off_proposal_by_owner_with_existing_signatories_error() { assert_eq!(err, GovernanceError::InvalidSignatoryAddress.into()); } + +#[tokio::test] +async fn test_sign_off_proposal_with_non_existing_governance_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + let mut proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + let signatory_record_cookie = governance_test + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) + .await + .unwrap(); + + // Override Governance with non existing account + proposal_cookie.account.governance = Pubkey::new_unique(); + + // Act + let err = governance_test + .sign_off_proposal(&proposal_cookie, &signatory_record_cookie) + .await + .err() + .unwrap(); + + // Assert + + assert_eq!(err, GovernanceToolsError::AccountDoesNotExist.into()); +} + +#[tokio::test] +async fn test_sign_off_proposal_with_non_existing_realm_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + let mut proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + let signatory_record_cookie = governance_test + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) + .await + .unwrap(); + + // Override Realm with non existing account + proposal_cookie.realm = Pubkey::new_unique(); + + // Act + let err = governance_test + .sign_off_proposal(&proposal_cookie, &signatory_record_cookie) + .await + .err() + .unwrap(); + + // Assert + + assert_eq!(err, GovernanceToolsError::AccountDoesNotExist.into()); +} + +#[tokio::test] +async fn test_sign_off_proposal_with_required_signatory() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let signatory = Keypair::new(); + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + let mut proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + let signatory_record_cookie = governance_test + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) + .await + .unwrap(); + + let proposal_transaction_cookie = governance_test + .with_add_required_signatory_transaction( + &mut proposal_cookie, + &token_owner_record_cookie, + &governance_cookie, + &signatory.pubkey(), + ) + .await + .unwrap(); + + governance_test + .sign_off_proposal(&proposal_cookie, &signatory_record_cookie) + .await + .unwrap(); + + governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + governance_test + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) + .await; + + governance_test + .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie) + .await + .unwrap(); + + let new_proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + governance_test + .with_signatory_record_for_required_signatory( + &new_proposal_cookie, + &governance_cookie, + &signatory.pubkey(), + ) + .await + .unwrap(); + + // Act + governance_test + .do_required_signoff( + &realm_cookie, + &governance_cookie, + &new_proposal_cookie, + &signatory, + ) + .await + .unwrap(); + + // Assert + let proposal_account = governance_test + .get_proposal_account(&new_proposal_cookie.address) + .await; + + assert_eq!(1, proposal_account.signatories_signed_off_count); + assert_eq!(ProposalState::Voting, proposal_account.state); +} + +#[tokio::test] +async fn test_partial_sign_off_proposal_with_two_governance_signatories() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let signatory_1 = Keypair::new(); + let signatory_2 = Keypair::new(); + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + let mut proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + let signatory_record_cookie = governance_test + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) + .await + .unwrap(); + + let proposal_transaction_cookie_1 = governance_test + .with_add_required_signatory_transaction( + &mut proposal_cookie, + &token_owner_record_cookie, + &governance_cookie, + &signatory_1.pubkey(), + ) + .await + .unwrap(); + + let proposal_transaction_cookie_2 = governance_test + .with_add_required_signatory_transaction( + &mut proposal_cookie, + &token_owner_record_cookie, + &governance_cookie, + &signatory_2.pubkey(), + ) + .await + .unwrap(); + + governance_test + .sign_off_proposal(&proposal_cookie, &signatory_record_cookie) + .await + .unwrap(); + + governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + governance_test + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) + .await; + + governance_test + .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie_1) + .await + .unwrap(); + + governance_test + .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie_2) + .await + .unwrap(); + + // End setup proposal + + let new_proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + governance_test + .with_signatory_record_for_required_signatory( + &new_proposal_cookie, + &governance_cookie, + &signatory_1.pubkey(), + ) + .await + .unwrap(); + + governance_test + .with_signatory_record_for_required_signatory( + &new_proposal_cookie, + &governance_cookie, + &signatory_2.pubkey(), + ) + .await + .unwrap(); + + // Act + governance_test + .do_required_signoff( + &realm_cookie, + &governance_cookie, + &new_proposal_cookie, + &signatory_1, + ) + .await + .unwrap(); + + // Assert + let proposal_account = governance_test + .get_proposal_account(&new_proposal_cookie.address) + .await; + + assert_eq!(1, proposal_account.signatories_signed_off_count); + assert_eq!(ProposalState::SigningOff, proposal_account.state); +} + +#[tokio::test] +async fn test_repeat_sign_off_proposal_err() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let signatory_1 = Keypair::new(); + let signatory_2 = Keypair::new(); + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + // Proposal to create required signatory 1 + let mut proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + let signatory_record_cookie = governance_test + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) + .await + .unwrap(); + + let proposal_transaction_cookie = governance_test + .with_add_required_signatory_transaction( + &mut proposal_cookie, + &token_owner_record_cookie, + &governance_cookie, + &signatory_1.pubkey(), + ) + .await + .unwrap(); + + governance_test + .sign_off_proposal(&proposal_cookie, &signatory_record_cookie) + .await + .unwrap(); + + governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + governance_test + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) + .await; + + governance_test + .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie) + .await + .unwrap(); + + // Proposal to create required signatory 2 + let mut proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + let proposal_transaction_cookie = governance_test + .with_add_required_signatory_transaction( + &mut proposal_cookie, + &token_owner_record_cookie, + &governance_cookie, + &signatory_2.pubkey(), + ) + .await + .unwrap(); + + governance_test + .with_signatory_record_for_required_signatory( + &proposal_cookie, + &governance_cookie, + &signatory_1.pubkey(), + ) + .await + .unwrap(); + + governance_test + .do_required_signoff( + &realm_cookie, + &governance_cookie, + &proposal_cookie, + &signatory_1, + ) + .await + .unwrap(); + + governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + governance_test + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) + .await; + + governance_test + .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie) + .await + .unwrap(); + + // End setup proposals + + let new_proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + governance_test + .with_signatory_record_for_required_signatory( + &new_proposal_cookie, + &governance_cookie, + &signatory_1.pubkey(), + ) + .await + .unwrap(); + + governance_test + .with_signatory_record_for_required_signatory( + &new_proposal_cookie, + &governance_cookie, + &signatory_2.pubkey(), + ) + .await + .unwrap(); + + // Sign off 1 + governance_test + .do_required_signoff( + &realm_cookie, + &governance_cookie, + &new_proposal_cookie, + &signatory_1, + ) + .await + .unwrap(); + governance_test.advance_clock().await; + + // Act + let err = governance_test + .do_required_signoff( + &realm_cookie, + &governance_cookie, + &new_proposal_cookie, + &signatory_1, + ) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::SignatoryAlreadySignedOff.into()); +} + +#[tokio::test] +async fn test_sign_off_without_all_required_signatories_err() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let signatory_1 = Keypair::new(); + let signatory_2 = Keypair::new(); + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + // Proposal to create required signatory 1 + let mut proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + let signatory_record_cookie = governance_test + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) + .await + .unwrap(); + + let proposal_transaction_cookie = governance_test + .with_add_required_signatory_transaction( + &mut proposal_cookie, + &token_owner_record_cookie, + &governance_cookie, + &signatory_1.pubkey(), + ) + .await + .unwrap(); + + governance_test + .sign_off_proposal(&proposal_cookie, &signatory_record_cookie) + .await + .unwrap(); + + governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + governance_test + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) + .await; + + governance_test + .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie) + .await + .unwrap(); + + // Proposal to create required signatory 2 + let mut proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + let proposal_transaction_cookie = governance_test + .with_add_required_signatory_transaction( + &mut proposal_cookie, + &token_owner_record_cookie, + &governance_cookie, + &signatory_2.pubkey(), + ) + .await + .unwrap(); + + governance_test + .with_signatory_record_for_required_signatory( + &proposal_cookie, + &governance_cookie, + &signatory_1.pubkey(), + ) + .await + .unwrap(); + + governance_test + .do_required_signoff( + &realm_cookie, + &governance_cookie, + &proposal_cookie, + &signatory_1, + ) + .await + .unwrap(); + + governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + governance_test + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) + .await; + + governance_test + .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie) + .await + .unwrap(); + + // End setup proposals + + let new_proposal_cookie = governance_test + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + governance_test + .with_signatory_record_for_required_signatory( + &new_proposal_cookie, + &governance_cookie, + &signatory_1.pubkey(), + ) + .await + .unwrap(); + + // Act + let err = governance_test + .do_required_signoff( + &realm_cookie, + &governance_cookie, + &new_proposal_cookie, + &signatory_1, + ) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::MissingRequiredSignatories.into()); +} diff --git a/governance/program/tests/process_update_program_metadata.rs b/governance/program/tests/process_update_program_metadata.rs index a9e4a13f9f9..8e7a205be9a 100644 --- a/governance/program/tests/process_update_program_metadata.rs +++ b/governance/program/tests/process_update_program_metadata.rs @@ -1,4 +1,4 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] use solana_program_test::*; diff --git a/governance/program/tests/process_withdraw_governing_tokens.rs b/governance/program/tests/process_withdraw_governing_tokens.rs index 7702a60bb0f..7f797770dc7 100644 --- a/governance/program/tests/process_withdraw_governing_tokens.rs +++ b/governance/program/tests/process_withdraw_governing_tokens.rs @@ -1,16 +1,23 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] -use solana_program::{instruction::AccountMeta, pubkey::Pubkey}; -use solana_program_test::*; +use { + solana_program::{instruction::AccountMeta, pubkey::Pubkey}, + solana_program_test::*, +}; mod program_test; -use program_test::*; -use solana_sdk::signature::Signer; - -use spl_governance::{ - error::GovernanceError, instruction::withdraw_governing_tokens, - state::token_owner_record::get_token_owner_record_address, +use { + crate::program_test::args::RealmSetupArgs, + program_test::*, + solana_sdk::signature::Signer, + spl_governance::{ + error::GovernanceError, + instruction::withdraw_governing_tokens, + state::{ + realm_config::GoverningTokenType, token_owner_record::get_token_owner_record_address, + }, + }, }; #[tokio::test] @@ -185,7 +192,6 @@ async fn test_withdraw_governing_tokens_with_unrelinquished_votes_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -193,11 +199,7 @@ async fn test_withdraw_governing_tokens_with_unrelinquished_votes_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -231,7 +233,6 @@ async fn test_withdraw_governing_tokens_after_relinquishing_vote() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -239,11 +240,7 @@ async fn test_withdraw_governing_tokens_after_relinquishing_vote() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -337,7 +334,6 @@ async fn test_withdraw_governing_tokens_with_outstanding_proposals_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -345,11 +341,7 @@ async fn test_withdraw_governing_tokens_with_outstanding_proposals_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -378,7 +370,6 @@ async fn test_withdraw_governing_tokens_after_proposal_cancelled() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -386,11 +377,7 @@ async fn test_withdraw_governing_tokens_after_proposal_cancelled() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -420,3 +407,101 @@ async fn test_withdraw_governing_tokens_after_proposal_cancelled() { source_account.amount ); } + +#[tokio::test] +async fn test_withdraw_council_tokens_with_cannot_withdraw_membership_tokens_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let mut realm_config_args = RealmSetupArgs::default(); + realm_config_args.council_token_config_args.token_type = GoverningTokenType::Membership; + + let realm_cookie = governance_test + .with_realm_using_args(&realm_config_args) + .await; + + let token_owner_record_cookie = governance_test + .with_council_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Act + let err = governance_test + .withdraw_council_tokens(&realm_cookie, &token_owner_record_cookie) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::CannotWithdrawMembershipTokens.into()); +} + +#[tokio::test] +async fn test_withdraw_dormant_community_tokens() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let mut realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut realm_setup_args = RealmSetupArgs::default(); + realm_setup_args.community_token_config_args.token_type = GoverningTokenType::Dormant; + + governance_test + .set_realm_config(&mut realm_cookie, &realm_setup_args) + .await + .unwrap(); + + // Act + governance_test + .withdraw_community_tokens(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + // Assert + let token_owner_record = governance_test + .get_token_owner_record_account(&token_owner_record_cookie.address) + .await; + + assert_eq!(0, token_owner_record.governing_token_deposit_amount); +} + +#[tokio::test] +async fn test_withdraw_governing_tokens_with_token_owner_record_lock_error() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let token_owner_record_lock_authority_cookie = governance_test + .with_community_token_owner_record_lock_authority(&realm_cookie) + .await + .unwrap(); + + governance_test + .with_token_owner_record_lock( + &token_owner_record_cookie, + &token_owner_record_lock_authority_cookie, + ) + .await + .unwrap(); + + // Act + let err = governance_test + .withdraw_community_tokens(&realm_cookie, &token_owner_record_cookie) + .await + .err() + .unwrap(); + + // Assert + assert_eq!(err, GovernanceError::TokenOwnerRecordLocked.into()); +} diff --git a/governance/program/tests/program_test/args.rs b/governance/program/tests/program_test/args.rs index 75dd8c58693..3e0b5509879 100644 --- a/governance/program/tests/program_test/args.rs +++ b/governance/program/tests/program_test/args.rs @@ -1,28 +1,70 @@ -use solana_program::pubkey::Pubkey; -use spl_governance::state::{enums::MintMaxVoteWeightSource, realm::RealmConfigArgs}; +use spl_governance::state::{ + enums::MintMaxVoterWeightSource, realm::GoverningTokenConfigAccountArgs, +}; #[derive(Clone, Debug, PartialEq)] -pub struct SetRealmConfigArgs { - pub realm_config_args: RealmConfigArgs, - pub community_voter_weight_addin: Option, - pub max_community_voter_weight_addin: Option, +pub struct RealmSetupArgs { + pub use_council_mint: bool, + pub min_community_weight_to_create_governance: u64, + pub community_mint_max_voter_weight_source: MintMaxVoterWeightSource, + pub community_token_config_args: GoverningTokenConfigAccountArgs, + pub council_token_config_args: GoverningTokenConfigAccountArgs, } -impl Default for SetRealmConfigArgs { +impl Default for RealmSetupArgs { fn default() -> Self { - let realm_config_args = RealmConfigArgs { + Self { use_council_mint: true, - - community_mint_max_vote_weight_source: MintMaxVoteWeightSource::SupplyFraction(100), + community_token_config_args: GoverningTokenConfigAccountArgs::default(), + council_token_config_args: GoverningTokenConfigAccountArgs::default(), min_community_weight_to_create_governance: 10, - use_community_voter_weight_addin: false, - use_max_community_voter_weight_addin: false, - }; - - Self { - realm_config_args, - community_voter_weight_addin: None, - max_community_voter_weight_addin: None, + community_mint_max_voter_weight_source: MintMaxVoterWeightSource::FULL_SUPPLY_FRACTION, } } } + +#[derive(Clone, Debug, PartialEq)] +pub struct PluginSetupArgs { + pub use_community_voter_weight_addin: bool, + pub use_max_community_voter_weight_addin: bool, + pub use_council_voter_weight_addin: bool, + pub use_max_council_voter_weight_addin: bool, +} + +impl PluginSetupArgs { + #[allow(dead_code)] + pub const COMMUNITY_VOTER_WEIGHT: PluginSetupArgs = PluginSetupArgs { + use_community_voter_weight_addin: true, + use_max_community_voter_weight_addin: false, + use_council_voter_weight_addin: false, + use_max_council_voter_weight_addin: false, + }; + #[allow(dead_code)] + pub const COMMUNITY_MAX_VOTER_WEIGHT: PluginSetupArgs = PluginSetupArgs { + use_community_voter_weight_addin: false, + use_max_community_voter_weight_addin: true, + use_council_voter_weight_addin: false, + use_max_council_voter_weight_addin: false, + }; + #[allow(dead_code)] + pub const COUNCIL_VOTER_WEIGHT: PluginSetupArgs = PluginSetupArgs { + use_community_voter_weight_addin: false, + use_max_community_voter_weight_addin: false, + use_council_voter_weight_addin: true, + use_max_council_voter_weight_addin: false, + }; + #[allow(dead_code)] + pub const COUNCIL_MAX_VOTER_WEIGHT: PluginSetupArgs = PluginSetupArgs { + use_community_voter_weight_addin: false, + use_max_community_voter_weight_addin: false, + use_council_voter_weight_addin: false, + use_max_council_voter_weight_addin: true, + }; + #[allow(dead_code)] + pub const ALL: PluginSetupArgs = PluginSetupArgs { + use_community_voter_weight_addin: true, + use_max_community_voter_weight_addin: true, + use_council_voter_weight_addin: true, + use_max_council_voter_weight_addin: true, + }; +} diff --git a/governance/program/tests/program_test/cookies.rs b/governance/program/tests/program_test/cookies.rs index 5f3436fa31c..4965acbc830 100644 --- a/governance/program/tests/program_test/cookies.rs +++ b/governance/program/tests/program_test/cookies.rs @@ -1,17 +1,20 @@ -use solana_program::{instruction::Instruction, pubkey::Pubkey}; -use solana_sdk::signature::Keypair; -use spl_governance::state::{ - governance::GovernanceV2, native_treasury::NativeTreasury, program_metadata::ProgramMetadata, - proposal::ProposalV2, proposal_transaction::ProposalTransactionV2, realm::RealmV2, - realm_config::RealmConfigAccount, signatory_record::SignatoryRecordV2, - token_owner_record::TokenOwnerRecordV2, vote_record::VoteRecordV2, +#![allow(dead_code)] +use { + solana_program::{clock::UnixTimestamp, instruction::Instruction, pubkey::Pubkey}, + solana_sdk::signature::Keypair, + spl_governance::state::{ + governance::GovernanceV2, native_treasury::NativeTreasury, + program_metadata::ProgramMetadata, proposal::ProposalV2, proposal_deposit::ProposalDeposit, + proposal_transaction::ProposalTransactionV2, realm::RealmV2, + realm_config::RealmConfigAccount, signatory_record::SignatoryRecordV2, + token_owner_record::TokenOwnerRecordV2, vote_record::VoteRecordV2, + }, + spl_governance_addin_api::{ + max_voter_weight::MaxVoterWeightRecord, voter_weight::VoterWeightRecord, + }, + spl_governance_test_sdk::tools::clone_keypair, }; -use spl_governance_addin_api::{ - max_voter_weight::MaxVoterWeightRecord, voter_weight::VoterWeightRecord, -}; -use spl_governance_test_sdk::tools::clone_keypair; - pub trait AccountCookie { fn get_address(&self) -> Pubkey; } @@ -32,7 +35,7 @@ pub struct RealmCookie { pub realm_authority: Option, - pub realm_config: Option, + pub realm_config: RealmConfigCookie, } #[derive(Debug)] @@ -70,7 +73,6 @@ impl TokenOwnerRecordCookie { .unwrap_or(&self.token_owner) } - #[allow(dead_code)] pub fn clone_governance_delegate(&self) -> Keypair { clone_keypair(&self.governance_delegate) } @@ -93,8 +95,7 @@ impl AccountCookie for GovernedProgramCookie { #[derive(Debug)] pub struct GovernedMintCookie { pub address: Pubkey, - pub mint_authority: Keypair, - pub transfer_mint_authority: bool, + pub mint_authority: Pubkey, } impl AccountCookie for GovernedMintCookie { @@ -104,25 +105,13 @@ impl AccountCookie for GovernedMintCookie { } #[derive(Debug)] -pub struct GovernedTokenCookie { +pub struct GovernedTokenAccountCookie { pub address: Pubkey, - pub token_owner: Keypair, - pub transfer_token_owner: bool, + pub token_account_owner: Pubkey, pub token_mint: Pubkey, } -impl AccountCookie for GovernedTokenCookie { - fn get_address(&self) -> Pubkey { - self.address - } -} - -#[derive(Debug)] -pub struct GovernedAccountCookie { - pub address: Pubkey, -} - -impl AccountCookie for GovernedAccountCookie { +impl AccountCookie for GovernedTokenAccountCookie { fn get_address(&self) -> Pubkey { self.address } @@ -142,13 +131,21 @@ pub struct ProposalCookie { pub realm: Pubkey, pub proposal_owner: Pubkey, + + pub proposal_deposit: ProposalDepositCookie, +} + +#[derive(Debug)] +pub struct ProposalDepositCookie { + pub address: Pubkey, + pub account: ProposalDeposit, } #[derive(Debug)] pub struct SignatoryRecordCookie { pub address: Pubkey, pub account: SignatoryRecordV2, - pub signatory: Keypair, + pub signatory: Option, } #[derive(Debug)] @@ -187,3 +184,15 @@ pub struct NativeTreasuryCookie { pub address: Pubkey, pub account: NativeTreasury, } + +#[derive(Debug)] +pub struct TokenOwnerRecordLockCookie { + pub authority: Pubkey, + pub lock_id: u8, + pub expiry: Option, +} + +#[derive(Debug)] +pub struct TokenOwnerRecordLockAuthorityCookie { + pub authority: Keypair, +} diff --git a/governance/program/tests/program_test/legacy.rs b/governance/program/tests/program_test/legacy.rs new file mode 100644 index 00000000000..39748ad1404 --- /dev/null +++ b/governance/program/tests/program_test/legacy.rs @@ -0,0 +1,134 @@ +use { + borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, + solana_program::pubkey::Pubkey, + spl_governance::state::{enums::GovernanceAccountType, governance::GovernanceV2}, +}; + +/// Legacy Governance account as of spl-gov V1 +#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +pub struct LegacyGovernanceV1 { + /// Account type. + pub account_type: GovernanceAccountType, + + /// Governance Realm + pub realm: Pubkey, + + /// Governance seed + pub governance_seed: Pubkey, + + /// Running count of proposals + pub proposals_count: u32, + + /// Governance config + pub config: LegacyGovernanceConfigV1, + + /// Reserved space for future versions + pub reserved: [u8; 8], +} + +/// Legacy GovernanceConfig as of spl-gov V1 +#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +pub struct LegacyGovernanceConfigV1 { + /// The type of the vote threshold used for voting + pub vote_threshold_percentage: VoteThresholdPercentage, + + /// Minimum number of community tokens a governance token owner must possess + /// to be able to create a proposal + pub min_community_tokens_to_create_proposal: u64, + + /// The wait time in seconds before transactions can be executed after + /// proposal is successfully voted on + pub transactions_hold_up_time: u32, + + /// Time limit in seconds for proposal to be open for voting + pub max_voting_time: u32, + + /// The source of vote weight for voters + /// Note: In the current version only token deposits are accepted as vote + /// weight + pub vote_weight_source: VoteWeightSource, + + /// The time period in seconds within which a Proposal can be still + /// cancelled after being voted on Once cool off time expires Proposal + /// can't be cancelled any longer and becomes a law Note: This field is + /// not implemented in the current version + pub proposal_cool_off_time: u32, + + /// Minimum number of council tokens a governance token owner must possess + /// to be able to create a proposal + pub min_council_tokens_to_create_proposal: u64, +} + +/// Legacy VoteWeightSource as of spl-gov V1 +#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +pub enum VoteWeightSource { + /// Governing token deposits into the Realm are used as voter weights + Deposit, + /// Governing token account snapshots as of the time a proposal entered + /// voting state are used as voter weights Note: Snapshot source is not + /// supported in the current version Support for account snapshots are + /// required in solana and/or arweave as a prerequisite + Snapshot, +} + +/// Legacy VoteThresholdPercentage as of spl-gov V1 +#[repr(C)] +#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +pub enum VoteThresholdPercentage { + /// Voting threshold of Yes votes in % required to tip the vote + /// It's the percentage of tokens out of the entire pool of governance + /// tokens eligible to vote Note: If the threshold is below or equal to + /// 50% then an even split of votes ex: 50:50 or 40:40 is always resolved as + /// Defeated In other words a '+1 vote' tie breaker is always required + /// to have a successful vote + YesVote(u8), + + /// The minimum number of votes in % out of the entire pool of governance + /// tokens eligible to vote which must be cast for the vote to be valid + /// Once the quorum is achieved a simple majority (50%+1) of Yes votes is + /// required for the vote to succeed Note: Quorum is not implemented in + /// the current version + Quorum(u8), +} + +impl From for LegacyGovernanceV1 { + fn from(governance_v2: GovernanceV2) -> Self { + let account_type = match governance_v2.account_type { + GovernanceAccountType::GovernanceV2 => GovernanceAccountType::GovernanceV1, + GovernanceAccountType::ProgramGovernanceV2 => { + GovernanceAccountType::ProgramGovernanceV1 + } + GovernanceAccountType::MintGovernanceV2 => GovernanceAccountType::MintGovernanceV1, + GovernanceAccountType::TokenGovernanceV2 => GovernanceAccountType::TokenGovernanceV1, + _ => panic!("Invalid Governance account type"), + }; + + let yes_vote_threshold = match governance_v2.config.community_vote_threshold { + spl_governance::state::enums::VoteThreshold::YesVotePercentage(yes_vote_percentage) => { + yes_vote_percentage + } + _ => panic!("Invalid vote threshold"), + }; + + LegacyGovernanceV1 { + account_type, + realm: governance_v2.realm, + governance_seed: governance_v2.governance_seed, + proposals_count: 0, + config: LegacyGovernanceConfigV1 { + vote_threshold_percentage: VoteThresholdPercentage::YesVote(yes_vote_threshold), + min_community_tokens_to_create_proposal: governance_v2 + .config + .min_community_weight_to_create_proposal, + transactions_hold_up_time: governance_v2.config.transactions_hold_up_time, + max_voting_time: governance_v2.config.voting_base_time, + vote_weight_source: VoteWeightSource::Deposit, + proposal_cool_off_time: 0, + min_council_tokens_to_create_proposal: governance_v2 + .config + .min_council_weight_to_create_proposal, + }, + reserved: [0; 8], + } + } +} diff --git a/governance/program/tests/program_test/mod.rs b/governance/program/tests/program_test/mod.rs index 2cc270f2d47..0d2b9b21ce4 100644 --- a/governance/program/tests/program_test/mod.rs +++ b/governance/program/tests/program_test/mod.rs @@ -1,85 +1,102 @@ -use std::str::FromStr; - -use solana_program::{ - bpf_loader_upgradeable::{self, UpgradeableLoaderState}, - clock::{Slot, UnixTimestamp}, - instruction::{AccountMeta, Instruction}, - program_error::ProgramError, - program_pack::{IsInitialized, Pack}, - pubkey::Pubkey, - system_instruction, -}; - -use solana_program_test::*; - -use solana_sdk::signature::{Keypair, Signer}; - -use spl_governance::{ - instruction::{ - add_signatory, cancel_proposal, cast_vote, create_governance, create_mint_governance, - create_native_treasury, create_program_governance, create_proposal, create_realm, - create_token_governance, create_token_owner_record, deposit_governing_tokens, - execute_transaction, finalize_vote, flag_transaction_error, insert_transaction, - relinquish_vote, remove_signatory, remove_transaction, set_governance_config, - set_governance_delegate, set_realm_authority, set_realm_config, sign_off_proposal, - upgrade_program_metadata, withdraw_governing_tokens, +#![allow(clippy::arithmetic_side_effects)] + +use { + self::cookies::TokenOwnerRecordLockAuthorityCookie, + borsh::BorshSerialize, + solana_program::{ + bpf_loader_upgradeable::{self, UpgradeableLoaderState}, + clock::{Slot, UnixTimestamp}, + instruction::{AccountMeta, Instruction}, + program_error::ProgramError, + program_pack::{IsInitialized, Pack}, + pubkey::Pubkey, + system_instruction, }, - processor::process_instruction, - state::{ - enums::{ - GovernanceAccountType, InstructionExecutionFlags, MintMaxVoteWeightSource, - ProposalState, TransactionExecutionStatus, VoteThreshold, + solana_program_test::*, + solana_sdk::signature::{Keypair, Signer}, + spl_governance::{ + instruction::{ + add_required_signatory, add_signatory, cancel_proposal, cast_vote, complete_proposal, + create_governance, create_native_treasury, create_proposal, create_realm, + create_token_owner_record, deposit_governing_tokens, execute_transaction, + finalize_vote, insert_transaction, refund_proposal_deposit, + relinquish_token_owner_record_locks, relinquish_vote, remove_required_signatory, + remove_transaction, revoke_governing_tokens, set_governance_config, + set_governance_delegate, set_realm_authority, set_realm_config, set_realm_config_item, + set_token_owner_record_lock, sign_off_proposal, upgrade_program_metadata, + withdraw_governing_tokens, AddSignatoryAuthority, }, - governance::{ - get_governance_address, get_mint_governance_address, get_program_governance_address, - get_token_governance_address, GovernanceConfig, GovernanceV2, - }, - native_treasury::{get_native_treasury_address, NativeTreasury}, - program_metadata::{get_program_metadata_address, ProgramMetadata}, - proposal::{get_proposal_address, OptionVoteResult, ProposalOption, ProposalV2, VoteType}, - proposal_transaction::{ - get_proposal_transaction_address, InstructionData, ProposalTransactionV2, + processor::process_instruction, + state::{ + enums::{ + GovernanceAccountType, InstructionExecutionFlags, MintMaxVoterWeightSource, + ProposalState, TransactionExecutionStatus, VoteThreshold, + }, + governance::{ + get_governance_address, GovernanceConfig, GovernanceV2, + DEFAULT_DEPOSIT_EXEMPT_PROPOSAL_COUNT, + }, + native_treasury::{get_native_treasury_address, NativeTreasury}, + program_metadata::{get_program_metadata_address, ProgramMetadata}, + proposal::{ + get_proposal_address, OptionVoteResult, ProposalOption, ProposalV2, VoteType, + }, + proposal_deposit::{get_proposal_deposit_address, ProposalDeposit}, + proposal_transaction::{ + get_proposal_transaction_address, InstructionData, ProposalTransactionV2, + }, + realm::{ + get_governing_token_holding_address, get_realm_address, + GoverningTokenConfigAccountArgs, RealmConfig, RealmV2, SetRealmAuthorityAction, + SetRealmConfigItemArgs, + }, + realm_config::{get_realm_config_address, GoverningTokenConfig, RealmConfigAccount}, + required_signatory::RequiredSignatory, + signatory_record::{get_signatory_record_address, SignatoryRecordV2}, + token_owner_record::{ + get_token_owner_record_address, TokenOwnerRecordV2, + TOKEN_OWNER_RECORD_LAYOUT_VERSION, + }, + vote_record::{get_vote_record_address, Vote, VoteChoice, VoteRecordV2}, }, - realm::{ - get_governing_token_holding_address, get_realm_address, RealmConfig, RealmConfigArgs, - RealmV2, SetRealmAuthorityAction, + tools::{ + bpf_loader_upgradeable::get_program_data_address, + structs::{Reserved110, Reserved119, SetConfigItemActionType}, }, - realm_config::{get_realm_config_address, RealmConfigAccount}, - signatory_record::{get_signatory_record_address, SignatoryRecordV2}, - token_owner_record::{get_token_owner_record_address, TokenOwnerRecordV2}, - vote_record::{get_vote_record_address, Vote, VoteChoice, VoteRecordV2}, }, - tools::bpf_loader_upgradeable::get_program_data_address, -}; -use spl_governance_addin_api::{ - max_voter_weight::MaxVoterWeightRecord, - voter_weight::{VoterWeightAction, VoterWeightRecord}, -}; -use spl_governance_addin_mock::instruction::{ - setup_max_voter_weight_record, setup_voter_weight_record, + spl_governance_addin_api::{ + max_voter_weight::MaxVoterWeightRecord, + voter_weight::{VoterWeightAction, VoterWeightRecord}, + }, + spl_governance_addin_mock::instruction::{ + setup_max_voter_weight_record, setup_voter_weight_record, + }, + std::str::FromStr, }; pub mod args; pub mod cookies; - -use crate::program_test::cookies::{ - RealmConfigCookie, SignatoryRecordCookie, VoterWeightRecordCookie, -}; - -use spl_governance_test_sdk::{ - addins::ensure_addin_mock_is_built, - cookies::WalletCookie, - tools::{clone_keypair, NopOverride}, - ProgramTestBench, -}; - -use self::{ - args::SetRealmConfigArgs, - cookies::{ - GovernanceCookie, GovernedAccountCookie, GovernedMintCookie, GovernedProgramCookie, - GovernedTokenCookie, MaxVoterWeightRecordCookie, NativeTreasuryCookie, - ProgramMetadataCookie, ProposalCookie, ProposalTransactionCookie, RealmCookie, - TokenOwnerRecordCookie, VoteRecordCookie, +pub mod legacy; + +use { + crate::{ + args::{PluginSetupArgs, RealmSetupArgs}, + cookies::{ + GovernanceCookie, GovernedMintCookie, GovernedProgramCookie, + GovernedTokenAccountCookie, MaxVoterWeightRecordCookie, NativeTreasuryCookie, + ProgramMetadataCookie, ProposalCookie, ProposalDepositCookie, + ProposalTransactionCookie, RealmCookie, TokenOwnerRecordCookie, + TokenOwnerRecordLockCookie, VoteRecordCookie, + }, + program_test::cookies::{ + RealmConfigCookie, SignatoryRecordCookie, VoterWeightRecordCookie, + }, + }, + spl_governance_test_sdk::{ + addins::ensure_addin_mock_is_built, + cookies::WalletCookie, + tools::{clone_keypair, NopOverride}, + ProgramTestBench, }, }; @@ -127,10 +144,13 @@ impl GovernanceProgramTest { use_voter_weight_addin: bool, use_max_voter_weight_addin: bool, ) -> Self { - // We only ensure the addin mock program is built but it doesn't detect changes - // If the addin is changed then it needs to be manually rebuilt - // Note: The crate of the mock is built when spl-governance is built but we also need spl_governance_addin_mock.so - // And we can't use build.rs script because cargo build-bpf hangs when executed from the script + // We only ensure the addin mock program is built but it doesn't detect + // changes. + // If the addin is changed then it needs to be manually rebuilt. + // Note: The crate of the mock is built when spl-governance is built + // but we also need spl_governance_addin_mock.so. + // And we can't use build.rs script because cargo build-sbf hangs when + // executed from the script. ensure_addin_mock_is_built(); Self::start_impl(use_voter_weight_addin, use_max_voter_weight_addin).await @@ -179,46 +199,49 @@ impl GovernanceProgramTest { } #[allow(dead_code)] - pub fn get_default_set_realm_config_args(&mut self) -> SetRealmConfigArgs { - let realm_config_args = RealmConfigArgs { - use_council_mint: true, - community_mint_max_vote_weight_source: MintMaxVoteWeightSource::FULL_SUPPLY_FRACTION, - min_community_weight_to_create_governance: 10, - use_community_voter_weight_addin: self.voter_weight_addin_id.is_some(), - use_max_community_voter_weight_addin: self.max_voter_weight_addin_id.is_some(), - }; + pub async fn with_realm(&mut self) -> RealmCookie { + let realm_setup_args = RealmSetupArgs::default(); + self.with_realm_using_args(&realm_setup_args).await + } - let community_voter_weight_addin = if realm_config_args.use_community_voter_weight_addin { - self.voter_weight_addin_id - } else { - None - }; + #[allow(dead_code)] + pub async fn with_realm_using_addins( + &mut self, + plugin_setup_args: PluginSetupArgs, + ) -> RealmCookie { + let mut realm_setup_args = RealmSetupArgs::default(); - let max_community_voter_weight_addin = - if realm_config_args.use_max_community_voter_weight_addin { - self.max_voter_weight_addin_id - } else { - None - }; + if plugin_setup_args.use_community_voter_weight_addin { + realm_setup_args + .community_token_config_args + .voter_weight_addin = self.voter_weight_addin_id; + } - SetRealmConfigArgs { - realm_config_args, - community_voter_weight_addin, - max_community_voter_weight_addin, + if plugin_setup_args.use_max_community_voter_weight_addin { + realm_setup_args + .community_token_config_args + .max_voter_weight_addin = self.max_voter_weight_addin_id; } - } - #[allow(dead_code)] - pub async fn with_realm(&mut self) -> RealmCookie { - let set_realm_config_args = self.get_default_set_realm_config_args(); - self.with_realm_using_config_args(&set_realm_config_args) - .await + if plugin_setup_args.use_council_voter_weight_addin { + realm_setup_args + .council_token_config_args + .voter_weight_addin = self.voter_weight_addin_id; + } + + if plugin_setup_args.use_max_council_voter_weight_addin { + realm_setup_args + .council_token_config_args + .max_voter_weight_addin = self.max_voter_weight_addin_id; + } + + self.with_realm_using_args(&realm_setup_args).await } #[allow(dead_code)] - pub async fn with_realm_using_config_args( + pub async fn with_realm_using_args( &mut self, - set_realm_config_args: &SetRealmConfigArgs, + realm_setup_args: &RealmSetupArgs, ) -> RealmCookie { let name = format!("Realm #{}", self.next_realm_id).to_string(); self.next_realm_id += 1; @@ -246,7 +269,7 @@ impl GovernanceProgramTest { council_token_mint_pubkey, council_token_holding_address, council_token_mint_authority, - ) = if set_realm_config_args.realm_config_args.use_council_mint { + ) = if realm_setup_args.use_council_mint { let council_token_mint_keypair = Keypair::new(); let council_token_mint_authority = Keypair::new(); @@ -275,21 +298,44 @@ impl GovernanceProgramTest { let realm_authority = Keypair::new(); + let community_token_args = GoverningTokenConfigAccountArgs { + voter_weight_addin: realm_setup_args + .community_token_config_args + .voter_weight_addin, + max_voter_weight_addin: realm_setup_args + .community_token_config_args + .max_voter_weight_addin, + token_type: realm_setup_args + .community_token_config_args + .token_type + .clone(), + }; + + let council_token_args = GoverningTokenConfigAccountArgs { + voter_weight_addin: realm_setup_args + .council_token_config_args + .voter_weight_addin, + max_voter_weight_addin: realm_setup_args + .council_token_config_args + .max_voter_weight_addin, + token_type: realm_setup_args + .council_token_config_args + .token_type + .clone(), + }; + let create_realm_ix = create_realm( &self.program_id, &realm_authority.pubkey(), &community_token_mint_keypair.pubkey(), &self.bench.payer.pubkey(), council_token_mint_pubkey, - set_realm_config_args.community_voter_weight_addin, - set_realm_config_args.max_community_voter_weight_addin, + Some(community_token_args), + Some(council_token_args), name.clone(), - set_realm_config_args - .realm_config_args - .min_community_weight_to_create_governance, - set_realm_config_args - .realm_config_args - .community_mint_max_vote_weight_source + realm_setup_args.min_community_weight_to_create_governance, + realm_setup_args + .community_mint_max_voter_weight_source .clone(), ); @@ -309,41 +355,53 @@ impl GovernanceProgramTest { council_mint: council_token_mint_pubkey, reserved: [0; 6], - min_community_weight_to_create_governance: set_realm_config_args - .realm_config_args + min_community_weight_to_create_governance: realm_setup_args .min_community_weight_to_create_governance, - community_mint_max_vote_weight_source: set_realm_config_args - .realm_config_args - .community_mint_max_vote_weight_source + community_mint_max_voter_weight_source: realm_setup_args + .community_mint_max_voter_weight_source .clone(), - use_community_voter_weight_addin: false, - use_max_community_voter_weight_addin: false, + legacy1: 0, + legacy2: 0, }, - voting_proposal_count: 0, + legacy1: 0, reserved_v2: [0; 128], }; - let realm_config_cookie = if set_realm_config_args.community_voter_weight_addin.is_some() - || set_realm_config_args - .max_community_voter_weight_addin - .is_some() - { - Some(RealmConfigCookie { - address: get_realm_config_address(&self.program_id, &realm_address), - account: RealmConfigAccount { - account_type: GovernanceAccountType::RealmConfig, - realm: realm_address, - community_voter_weight_addin: set_realm_config_args - .community_voter_weight_addin, - max_community_voter_weight_addin: set_realm_config_args - .max_community_voter_weight_addin, - council_voter_weight_addin: None, - council_max_vote_weight_addin: None, - reserved: [0; 128], + let realm_config_cookie = RealmConfigCookie { + address: get_realm_config_address(&self.program_id, &realm_address), + account: RealmConfigAccount { + account_type: GovernanceAccountType::RealmConfig, + realm: realm_address, + reserved: Reserved110::default(), + community_token_config: GoverningTokenConfig { + voter_weight_addin: realm_setup_args + .community_token_config_args + .voter_weight_addin, + max_voter_weight_addin: realm_setup_args + .community_token_config_args + .max_voter_weight_addin, + token_type: realm_setup_args + .community_token_config_args + .token_type + .clone(), + reserved: [0; 4], + lock_authorities: vec![], }, - }) - } else { - None + council_token_config: GoverningTokenConfig { + voter_weight_addin: realm_setup_args + .council_token_config_args + .voter_weight_addin, + max_voter_weight_addin: realm_setup_args + .council_token_config_args + .max_voter_weight_addin, + token_type: realm_setup_args + .council_token_config_args + .token_type + .clone(), + reserved: [0; 4], + lock_authorities: vec![], + }, + }, }; RealmCookie { @@ -370,7 +428,7 @@ impl GovernanceProgramTest { let realm_authority = Keypair::new(); - let community_mint_max_vote_weight_source = MintMaxVoteWeightSource::FULL_SUPPLY_FRACTION; + let community_mint_max_voter_weight_source = MintMaxVoterWeightSource::FULL_SUPPLY_FRACTION; let min_community_weight_to_create_governance = 10; let create_realm_ix = create_realm( @@ -383,7 +441,7 @@ impl GovernanceProgramTest { None, name.clone(), min_community_weight_to_create_governance, - community_mint_max_vote_weight_source, + community_mint_max_voter_weight_source, ); self.bench @@ -402,13 +460,13 @@ impl GovernanceProgramTest { council_mint: Some(council_mint), reserved: [0; 6], - community_mint_max_vote_weight_source: - MintMaxVoteWeightSource::FULL_SUPPLY_FRACTION, + community_mint_max_voter_weight_source: + MintMaxVoterWeightSource::FULL_SUPPLY_FRACTION, min_community_weight_to_create_governance, - use_community_voter_weight_addin: false, - use_max_community_voter_weight_addin: false, + legacy1: 0, + legacy2: 0, }, - voting_proposal_count: 0, + legacy1: 0, reserved_v2: [0; 128], }; @@ -421,6 +479,17 @@ impl GovernanceProgramTest { let council_token_holding_address = get_governing_token_holding_address(&self.program_id, &realm_address, &council_mint); + let realm_config_cookie = RealmConfigCookie { + address: get_realm_config_address(&self.program_id, &realm_address), + account: RealmConfigAccount { + account_type: GovernanceAccountType::RealmConfig, + realm: realm_address, + council_token_config: GoverningTokenConfig::default(), + reserved: Reserved110::default(), + community_token_config: GoverningTokenConfig::default(), + }, + }; + RealmCookie { address: realm_address, account, @@ -433,11 +502,12 @@ impl GovernanceProgramTest { realm_cookie.council_mint_authority.as_ref().unwrap(), )), realm_authority: Some(realm_authority), - realm_config: None, + realm_config: realm_config_cookie, } } - // Creates TokenOwner which owns 100 community tokens and deposits them into the given Realm + // Creates TokenOwner which owns 100 community tokens and deposits them into the + // given Realm #[allow(dead_code)] pub async fn with_community_token_deposit( &mut self, @@ -457,6 +527,28 @@ impl GovernanceProgramTest { pub async fn with_community_token_owner_record( &mut self, realm_cookie: &RealmCookie, + ) -> TokenOwnerRecordCookie { + self.with_token_owner_record(realm_cookie, &realm_cookie.account.community_mint) + .await + } + + #[allow(dead_code)] + pub async fn with_council_token_owner_record( + &mut self, + realm_cookie: &RealmCookie, + ) -> TokenOwnerRecordCookie { + self.with_token_owner_record( + realm_cookie, + &realm_cookie.account.config.council_mint.unwrap(), + ) + .await + } + + #[allow(dead_code)] + pub async fn with_token_owner_record( + &mut self, + realm_cookie: &RealmCookie, + governing_token_mint: &Pubkey, ) -> TokenOwnerRecordCookie { let token_owner = Keypair::new(); @@ -464,7 +556,7 @@ impl GovernanceProgramTest { &self.program_id, &realm_cookie.address, &token_owner.pubkey(), - &realm_cookie.account.community_mint, + governing_token_mint, &self.bench.payer.pubkey(), ); @@ -476,21 +568,22 @@ impl GovernanceProgramTest { let account = TokenOwnerRecordV2 { account_type: GovernanceAccountType::TokenOwnerRecordV2, realm: realm_cookie.address, - governing_token_mint: realm_cookie.account.community_mint, + governing_token_mint: *governing_token_mint, governing_token_owner: token_owner.pubkey(), governing_token_deposit_amount: 0, governance_delegate: None, unrelinquished_votes_count: 0, - total_votes_count: 0, outstanding_proposal_count: 0, - reserved: [0; 7], - reserved_v2: [0; 128], + version: TOKEN_OWNER_RECORD_LAYOUT_VERSION, + reserved: [0; 6], + reserved_v2: [0; 124], + locks: vec![], }; let token_owner_record_address = get_token_owner_record_address( &self.program_id, &realm_cookie.address, - &realm_cookie.account.community_mint, + governing_token_mint, &token_owner.pubkey(), ); @@ -625,7 +718,7 @@ impl GovernanceProgramTest { self.with_initial_governing_token_deposit( &realm_cookie.address, &realm_cookie.account.config.council_mint.unwrap(), - &realm_cookie.council_mint_authority.as_ref().unwrap(), + realm_cookie.council_mint_authority.as_ref().unwrap(), amount, None, ) @@ -673,7 +766,7 @@ impl GovernanceProgramTest { amount: u64, token_owner: Option, ) -> Result { - let token_owner = token_owner.unwrap_or(Keypair::new()); + let token_owner = token_owner.unwrap_or_else(Keypair::new); let token_source = Keypair::new(); let transfer_authority = Keypair::new(); @@ -719,10 +812,79 @@ impl GovernanceProgramTest { governing_token_deposit_amount: amount, governance_delegate: None, unrelinquished_votes_count: 0, - total_votes_count: 0, outstanding_proposal_count: 0, - reserved: [0; 7], - reserved_v2: [0; 128], + version: TOKEN_OWNER_RECORD_LAYOUT_VERSION, + reserved: [0; 6], + reserved_v2: [0; 124], + locks: vec![], + }; + + let governance_delegate = Keypair::from_base58_string(&token_owner.to_base58_string()); + + Ok(TokenOwnerRecordCookie { + address: token_owner_record_address, + account, + + token_source_amount: amount, + token_source: token_source.pubkey(), + token_owner, + governance_authority: None, + governance_delegate, + voter_weight_record: None, + max_voter_weight_record: None, + }) + } + + #[allow(dead_code)] + pub async fn with_initial_governing_token_deposit_using_mint( + &mut self, + realm_address: &Pubkey, + governing_mint: &Pubkey, + governing_mint_authority: &Keypair, + amount: u64, + token_owner: Option, + ) -> Result { + let token_owner = token_owner.unwrap_or_else(Keypair::new); + let token_source = Keypair::new(); + + let deposit_governing_tokens_ix = deposit_governing_tokens( + &self.program_id, + realm_address, + governing_mint, + &token_owner.pubkey(), + &governing_mint_authority.pubkey(), + &self.bench.payer.pubkey(), + amount, + governing_mint, + ); + + self.bench + .process_transaction( + &[deposit_governing_tokens_ix], + Some(&[&token_owner, governing_mint_authority]), + ) + .await?; + + let token_owner_record_address = get_token_owner_record_address( + &self.program_id, + realm_address, + governing_mint, + &token_owner.pubkey(), + ); + + let account = TokenOwnerRecordV2 { + account_type: GovernanceAccountType::TokenOwnerRecordV2, + realm: *realm_address, + governing_token_mint: *governing_mint, + governing_token_owner: token_owner.pubkey(), + governing_token_deposit_amount: amount, + governance_delegate: None, + unrelinquished_votes_count: 0, + outstanding_proposal_count: 0, + version: TOKEN_OWNER_RECORD_LAYOUT_VERSION, + reserved: [0; 6], + reserved_v2: [0; 124], + locks: vec![], }; let governance_delegate = Keypair::from_base58_string(&token_owner.to_base58_string()); @@ -974,63 +1136,37 @@ impl GovernanceProgramTest { pub async fn set_realm_config( &mut self, realm_cookie: &mut RealmCookie, - set_realm_config_args: &SetRealmConfigArgs, + realm_setup_args: &RealmSetupArgs, ) -> Result<(), ProgramError> { - self.set_realm_config_using_instruction( - realm_cookie, - set_realm_config_args, - NopOverride, - None, - ) - .await + self.set_realm_config_using_instruction(realm_cookie, realm_setup_args, NopOverride, None) + .await } #[allow(dead_code)] pub async fn set_realm_config_using_instruction( &mut self, realm_cookie: &mut RealmCookie, - set_realm_config_args: &SetRealmConfigArgs, + realm_setup_args: &RealmSetupArgs, instruction_override: F, signers_override: Option<&[&Keypair]>, ) -> Result<(), ProgramError> { - let council_token_mint = if set_realm_config_args.realm_config_args.use_council_mint { + let council_token_mint = if realm_setup_args.use_council_mint { realm_cookie.account.config.council_mint } else { None }; - let community_voter_weight_addin = if set_realm_config_args - .realm_config_args - .use_community_voter_weight_addin - { - set_realm_config_args.community_voter_weight_addin - } else { - None - }; - - let max_community_voter_weight_addin = if set_realm_config_args - .realm_config_args - .use_max_community_voter_weight_addin - { - set_realm_config_args.max_community_voter_weight_addin - } else { - None - }; - let mut set_realm_config_ix = set_realm_config( &self.program_id, &realm_cookie.address, &realm_cookie.realm_authority.as_ref().unwrap().pubkey(), council_token_mint, &self.bench.payer.pubkey(), - community_voter_weight_addin, - max_community_voter_weight_addin, - set_realm_config_args - .realm_config_args - .min_community_weight_to_create_governance, - set_realm_config_args - .realm_config_args - .community_mint_max_vote_weight_source + Some(realm_setup_args.community_token_config_args.clone()), + Some(realm_setup_args.council_token_config_args.clone()), + realm_setup_args.min_community_weight_to_create_governance, + realm_setup_args + .community_mint_max_voter_weight_source .clone(), ); @@ -1043,32 +1179,46 @@ impl GovernanceProgramTest { realm_cookie .account .config - .community_mint_max_vote_weight_source = set_realm_config_args - .realm_config_args - .community_mint_max_vote_weight_source + .community_mint_max_voter_weight_source = realm_setup_args + .community_mint_max_voter_weight_source .clone(); - if set_realm_config_args - .realm_config_args - .use_community_voter_weight_addin - || set_realm_config_args - .realm_config_args - .use_max_community_voter_weight_addin - { - realm_cookie.realm_config = Some(RealmConfigCookie { - address: get_realm_config_address(&self.program_id, &realm_cookie.address), - account: RealmConfigAccount { - account_type: GovernanceAccountType::RealmConfig, - realm: realm_cookie.address, - community_voter_weight_addin, - max_community_voter_weight_addin, - council_voter_weight_addin: None, - council_max_vote_weight_addin: None, - reserved: [0; 128], + realm_cookie.realm_config = RealmConfigCookie { + address: get_realm_config_address(&self.program_id, &realm_cookie.address), + account: RealmConfigAccount { + account_type: GovernanceAccountType::RealmConfig, + realm: realm_cookie.address, + reserved: Reserved110::default(), + community_token_config: GoverningTokenConfig { + voter_weight_addin: realm_setup_args + .community_token_config_args + .voter_weight_addin, + max_voter_weight_addin: realm_setup_args + .community_token_config_args + .max_voter_weight_addin, + token_type: realm_setup_args + .community_token_config_args + .token_type + .clone(), + reserved: [0; 4], + lock_authorities: vec![], }, - }) - } - + council_token_config: GoverningTokenConfig { + voter_weight_addin: realm_setup_args + .council_token_config_args + .voter_weight_addin, + max_voter_weight_addin: realm_setup_args + .council_token_config_args + .max_voter_weight_addin, + token_type: realm_setup_args + .council_token_config_args + .token_type + .clone(), + reserved: [0; 4], + lock_authorities: vec![], + }, + }, + }; self.bench .process_transaction(&[set_realm_config_ix], Some(signers)) .await @@ -1130,48 +1280,98 @@ impl GovernanceProgramTest { } #[allow(dead_code)] - pub async fn with_governed_account(&mut self) -> GovernedAccountCookie { - GovernedAccountCookie { - address: Pubkey::new_unique(), - } + pub async fn revoke_community_tokens( + &mut self, + realm_cookie: &RealmCookie, + token_owner_record_cookie: &TokenOwnerRecordCookie, + ) -> Result<(), ProgramError> { + self.revoke_governing_tokens_using_instruction( + realm_cookie, + token_owner_record_cookie, + &realm_cookie.account.community_mint, + &realm_cookie.community_mint_authority, + token_owner_record_cookie + .account + .governing_token_deposit_amount, + NopOverride, + None, + ) + .await } #[allow(dead_code)] - pub async fn with_governed_mint(&mut self) -> GovernedMintCookie { - let mint_authority = Keypair::new(); - - self.with_governed_mint_impl(&mint_authority, None).await + pub async fn revoke_council_tokens( + &mut self, + realm_cookie: &RealmCookie, + token_owner_record_cookie: &TokenOwnerRecordCookie, + ) -> Result<(), ProgramError> { + self.revoke_governing_tokens_using_instruction( + realm_cookie, + token_owner_record_cookie, + &realm_cookie.account.config.council_mint.unwrap(), + realm_cookie.council_mint_authority.as_ref().unwrap(), + token_owner_record_cookie + .account + .governing_token_deposit_amount, + NopOverride, + None, + ) + .await } #[allow(dead_code)] - pub async fn with_freezable_governed_mint(&mut self) -> GovernedMintCookie { - let mint_authority = Keypair::new(); + #[allow(clippy::too_many_arguments)] + pub async fn revoke_governing_tokens_using_instruction( + &mut self, + realm_cookie: &RealmCookie, + token_owner_record_cookie: &TokenOwnerRecordCookie, + governing_token_mint: &Pubkey, + revoke_authority: &Keypair, + amount: u64, + instruction_override: F, + signers_override: Option<&[&Keypair]>, + ) -> Result<(), ProgramError> { + let mut revoke_governing_tokens_ix = revoke_governing_tokens( + &self.program_id, + &realm_cookie.address, + &token_owner_record_cookie.account.governing_token_owner, + governing_token_mint, + &revoke_authority.pubkey(), + amount, + ); + + instruction_override(&mut revoke_governing_tokens_ix); + + let default_signers = &[revoke_authority]; + let signers = signers_override.unwrap_or(default_signers); - self.with_governed_mint_impl(&mint_authority, Some(&mint_authority.pubkey())) + self.bench + .process_transaction(&[revoke_governing_tokens_ix], Some(signers)) .await } #[allow(dead_code)] - pub async fn with_governed_mint_impl( + pub async fn with_governed_mint( &mut self, - mint_authority: &Keypair, - freeze_authority: Option<&Pubkey>, + governance_cookie: &GovernanceCookie, ) -> GovernedMintCookie { let mint_keypair = Keypair::new(); self.bench - .create_mint(&mint_keypair, &mint_authority.pubkey(), freeze_authority) + .create_mint(&mint_keypair, &governance_cookie.address, None) .await; GovernedMintCookie { address: mint_keypair.pubkey(), - mint_authority: clone_keypair(mint_authority), - transfer_mint_authority: true, + mint_authority: governance_cookie.address, } } #[allow(dead_code)] - pub async fn with_governed_token(&mut self) -> GovernedTokenCookie { + pub async fn with_governed_token_account( + &mut self, + governance_cookie: &GovernanceCookie, + ) -> GovernedTokenAccountCookie { let mint_keypair = Keypair::new(); let mint_authority = Keypair::new(); @@ -1179,14 +1379,14 @@ impl GovernanceProgramTest { .create_mint(&mint_keypair, &mint_authority.pubkey(), None) .await; - let token_keypair = Keypair::new(); - let token_owner = Keypair::new(); + let token_account_keypair = Keypair::new(); + let token_account_owner = governance_cookie.address; self.bench .create_empty_token_account( - &token_keypair, + &token_account_keypair, &mint_keypair.pubkey(), - &token_owner.pubkey(), + &token_account_owner, ) .await; @@ -1194,29 +1394,32 @@ impl GovernanceProgramTest { .mint_tokens( &mint_keypair.pubkey(), &mint_authority, - &token_keypair.pubkey(), + &token_account_keypair.pubkey(), 100, ) .await; - GovernedTokenCookie { - address: token_keypair.pubkey(), - token_owner, - transfer_token_owner: true, + GovernedTokenAccountCookie { + address: token_account_keypair.pubkey(), + token_account_owner, token_mint: mint_keypair.pubkey(), } } pub fn get_default_governance_config(&mut self) -> GovernanceConfig { GovernanceConfig { - min_community_weight_to_create_proposal: 5, - min_council_weight_to_create_proposal: 2, - min_transaction_hold_up_time: 10, - max_voting_time: 10, community_vote_threshold: VoteThreshold::YesVotePercentage(60), - vote_tipping: spl_governance::state::enums::VoteTipping::Strict, + min_community_weight_to_create_proposal: 5, + transactions_hold_up_time: 10, + voting_base_time: 10, + community_vote_tipping: spl_governance::state::enums::VoteTipping::Strict, council_vote_threshold: VoteThreshold::YesVotePercentage(80), council_veto_vote_threshold: VoteThreshold::YesVotePercentage(55), + min_council_weight_to_create_proposal: 2, + council_vote_tipping: spl_governance::state::enums::VoteTipping::Strict, + community_veto_vote_threshold: VoteThreshold::YesVotePercentage(80), + voting_cool_off_time: 0, + deposit_exempt_proposal_count: DEFAULT_DEPOSIT_EXEMPT_PROPOSAL_COUNT, } } @@ -1224,37 +1427,27 @@ impl GovernanceProgramTest { pub async fn with_governance( &mut self, realm_cookie: &RealmCookie, - governed_account_cookie: &GovernedAccountCookie, token_owner_record_cookie: &TokenOwnerRecordCookie, ) -> Result { let config = self.get_default_governance_config(); - self.with_governance_using_config( - realm_cookie, - governed_account_cookie, - token_owner_record_cookie, - &config, - ) - .await + self.with_governance_using_config(realm_cookie, token_owner_record_cookie, &config) + .await } #[allow(dead_code)] pub async fn with_governance_using_config( &mut self, realm_cookie: &RealmCookie, - governed_account_cookie: &GovernedAccountCookie, token_owner_record_cookie: &TokenOwnerRecordCookie, governance_config: &GovernanceConfig, ) -> Result { - let voter_weight_record = - if let Some(voter_weight_record) = &token_owner_record_cookie.voter_weight_record { - Some(voter_weight_record.address) - } else { - None - }; + let voter_weight_record = token_owner_record_cookie + .voter_weight_record + .as_ref() + .map(|voter_weight_record| voter_weight_record.address); self.with_governance_impl( realm_cookie, - governed_account_cookie, Some(&token_owner_record_cookie.address), &token_owner_record_cookie.token_owner, voter_weight_record, @@ -1265,20 +1458,22 @@ impl GovernanceProgramTest { } #[allow(dead_code)] + #[allow(clippy::too_many_arguments)] pub async fn with_governance_impl( &mut self, realm_cookie: &RealmCookie, - governed_account_cookie: &GovernedAccountCookie, token_owner_record: Option<&Pubkey>, create_authority: &Keypair, voter_weight_record: Option, governance_config: &GovernanceConfig, signers_override: Option<&[&Keypair]>, ) -> Result { + let governance_seed = Pubkey::new_unique(); + let mut create_governance_ix = create_governance( &self.program_id, &realm_cookie.address, - Some(&governed_account_cookie.address), + &governance_seed, token_owner_record.unwrap_or(&Pubkey::new_unique()), &self.bench.payer.pubkey(), &create_authority.pubkey(), @@ -1289,18 +1484,18 @@ impl GovernanceProgramTest { let account = GovernanceV2 { account_type: GovernanceAccountType::GovernanceV2, realm: realm_cookie.address, - governed_account: governed_account_cookie.address, + governance_seed, config: governance_config.clone(), - proposals_count: 0, - reserved: [0; 6], - voting_proposal_count: 0, - reserved_v2: [0; 128], + reserved1: 0, + reserved_v2: Reserved119::default(), + required_signatories_count: 0, + active_proposal_count: 0, }; let default_signers = &[create_authority]; let signers = signers_override.unwrap_or(default_signers); - if signers.len() == 0 { + if signers.is_empty() { create_governance_ix.accounts[6].is_signer = false; } @@ -1308,11 +1503,8 @@ impl GovernanceProgramTest { .process_transaction(&[create_governance_ix], Some(signers)) .await?; - let governance_address = get_governance_address( - &self.program_id, - &realm_cookie.address, - &governed_account_cookie.address, - ); + let governance_address = + get_governance_address(&self.program_id, &realm_cookie.address, &governance_seed); Ok(GovernanceCookie { address: governance_address, @@ -1322,7 +1514,10 @@ impl GovernanceProgramTest { } #[allow(dead_code)] - pub async fn with_governed_program(&mut self) -> GovernedProgramCookie { + pub async fn with_governed_program( + &mut self, + governance_cookie: &GovernanceCookie, + ) -> GovernedProgramCookie { let program_keypair = Keypair::new(); let program_buffer_keypair = Keypair::new(); let program_upgrade_authority_keypair = Keypair::new(); @@ -1333,12 +1528,14 @@ impl GovernanceProgramTest { let path_buf = find_file("solana_bpf_rust_upgradeable.so").unwrap(); let program_data = read_file(path_buf); - let program_buffer_rent = self - .bench - .rent - .minimum_balance(UpgradeableLoaderState::programdata_len(program_data.len()).unwrap()); + let program_buffer_rent = + self.bench + .rent + .minimum_balance(UpgradeableLoaderState::size_of_programdata( + program_data.len(), + )); - let mut instructions = bpf_loader_upgradeable::create_buffer( + let instructions = bpf_loader_upgradeable::create_buffer( &self.bench.payer.pubkey(), &program_buffer_keypair.pubkey(), &program_upgrade_authority_keypair.pubkey(), @@ -1347,21 +1544,29 @@ impl GovernanceProgramTest { ) .unwrap(); - let chunk_size = 800; + self.bench + .process_transaction(&instructions, Some(&[&program_buffer_keypair])) + .await + .unwrap(); - for (chunk, i) in program_data.chunks(chunk_size).zip(0..) { - instructions.push(bpf_loader_upgradeable::write( + const CHUNK_SIZE: usize = 800; + for (i, chunk) in program_data.chunks(CHUNK_SIZE).enumerate() { + let instruction = bpf_loader_upgradeable::write( &program_buffer_keypair.pubkey(), &program_upgrade_authority_keypair.pubkey(), - (i * chunk_size) as u32, + (i * CHUNK_SIZE) as u32, chunk.to_vec(), - )); + ); + self.bench + .process_transaction(&[instruction], Some(&[&program_upgrade_authority_keypair])) + .await + .unwrap(); } let program_account_rent = self .bench .rent - .minimum_balance(UpgradeableLoaderState::program_len().unwrap()); + .minimum_balance(UpgradeableLoaderState::size_of_program()); let deploy_ixs = bpf_loader_upgradeable::deploy_with_max_program_len( &self.bench.payer.pubkey(), @@ -1373,318 +1578,34 @@ impl GovernanceProgramTest { ) .unwrap(); - instructions.extend_from_slice(&deploy_ixs); - self.bench .process_transaction( - &instructions[..], - Some(&[ - &program_upgrade_authority_keypair, - &program_keypair, - &program_buffer_keypair, - ]), + &deploy_ixs, + Some(&[&program_upgrade_authority_keypair, &program_keypair]), ) .await .unwrap(); - GovernedProgramCookie { - address: program_keypair.pubkey(), - upgrade_authority: program_upgrade_authority_keypair, - data_address: program_data_address, - transfer_upgrade_authority: true, - } - } - - #[allow(dead_code)] - pub async fn with_program_governance( - &mut self, - realm_cookie: &RealmCookie, - governed_program_cookie: &GovernedProgramCookie, - token_owner_record_cookie: &TokenOwnerRecordCookie, - ) -> Result { - self.with_program_governance_using_instruction( - realm_cookie, - governed_program_cookie, - token_owner_record_cookie, - NopOverride, - None, - ) - .await - } - - #[allow(dead_code)] - pub async fn with_program_governance_using_instruction( - &mut self, - realm_cookie: &RealmCookie, - governed_program_cookie: &GovernedProgramCookie, - token_owner_record_cookie: &TokenOwnerRecordCookie, - instruction_override: F, - signers_override: Option<&[&Keypair]>, - ) -> Result { - let config = self.get_default_governance_config(); - - let voter_weight_record = - if let Some(voter_weight_record) = &token_owner_record_cookie.voter_weight_record { - Some(voter_weight_record.address) - } else { - None - }; - - let mut create_program_governance_ix = create_program_governance( - &self.program_id, - &realm_cookie.address, - &governed_program_cookie.address, - &governed_program_cookie.upgrade_authority.pubkey(), - &token_owner_record_cookie.address, - &self.bench.payer.pubkey(), - &token_owner_record_cookie.token_owner.pubkey(), - voter_weight_record, - config.clone(), - governed_program_cookie.transfer_upgrade_authority, - ); - - instruction_override(&mut create_program_governance_ix); - - let default_signers = &[ - &governed_program_cookie.upgrade_authority, - &token_owner_record_cookie.token_owner, - ]; - let signers = signers_override.unwrap_or(default_signers); - - self.bench - .process_transaction(&[create_program_governance_ix], Some(signers)) - .await?; - - let account = GovernanceV2 { - account_type: GovernanceAccountType::ProgramGovernanceV2, - realm: realm_cookie.address, - governed_account: governed_program_cookie.address, - config, - proposals_count: 0, - reserved: [0; 6], - voting_proposal_count: 0, - reserved_v2: [0; 128], - }; - - let program_governance_address = get_program_governance_address( - &self.program_id, - &realm_cookie.address, - &governed_program_cookie.address, - ); - - Ok(GovernanceCookie { - address: program_governance_address, - account, - next_proposal_index: 0, - }) - } - - #[allow(dead_code)] - pub async fn with_mint_governance( - &mut self, - realm_cookie: &RealmCookie, - governed_mint_cookie: &GovernedMintCookie, - token_owner_record_cookie: &TokenOwnerRecordCookie, - ) -> Result { - self.with_mint_governance_using_instruction( - realm_cookie, - governed_mint_cookie, - token_owner_record_cookie, - NopOverride, - None, - ) - .await - } - - #[allow(dead_code)] - pub async fn with_mint_governance_using_config( - &mut self, - realm_cookie: &RealmCookie, - governed_mint_cookie: &GovernedMintCookie, - token_owner_record_cookie: &TokenOwnerRecordCookie, - governance_config: &GovernanceConfig, - ) -> Result { - self.with_mint_governance_using_config_and_instruction( - realm_cookie, - governed_mint_cookie, - token_owner_record_cookie, - governance_config, - NopOverride, - None, - ) - .await - } - - #[allow(dead_code)] - pub async fn with_mint_governance_using_instruction( - &mut self, - realm_cookie: &RealmCookie, - governed_mint_cookie: &GovernedMintCookie, - token_owner_record_cookie: &TokenOwnerRecordCookie, - instruction_override: F, - signers_override: Option<&[&Keypair]>, - ) -> Result { - let governance_config = self.get_default_governance_config(); - - self.with_mint_governance_using_config_and_instruction( - realm_cookie, - governed_mint_cookie, - token_owner_record_cookie, - &governance_config, - instruction_override, - signers_override, - ) - .await - } - - #[allow(dead_code)] - pub async fn with_mint_governance_using_config_and_instruction( - &mut self, - realm_cookie: &RealmCookie, - governed_mint_cookie: &GovernedMintCookie, - token_owner_record_cookie: &TokenOwnerRecordCookie, - governance_config: &GovernanceConfig, - instruction_override: F, - signers_override: Option<&[&Keypair]>, - ) -> Result { - let voter_weight_record = - if let Some(voter_weight_record) = &token_owner_record_cookie.voter_weight_record { - Some(voter_weight_record.address) - } else { - None - }; - - let mut create_mint_governance_ix = create_mint_governance( - &self.program_id, - &realm_cookie.address, - &governed_mint_cookie.address, - &governed_mint_cookie.mint_authority.pubkey(), - &token_owner_record_cookie.address, - &self.bench.payer.pubkey(), - &token_owner_record_cookie.token_owner.pubkey(), - voter_weight_record, - governance_config.clone(), - governed_mint_cookie.transfer_mint_authority, - ); - - instruction_override(&mut create_mint_governance_ix); - - let default_signers = &[ - &governed_mint_cookie.mint_authority, - &token_owner_record_cookie.token_owner, - ]; - let signers = signers_override.unwrap_or(default_signers); - - self.bench - .process_transaction(&[create_mint_governance_ix], Some(signers)) - .await?; - - let account = GovernanceV2 { - account_type: GovernanceAccountType::MintGovernanceV2, - realm: realm_cookie.address, - governed_account: governed_mint_cookie.address, - config: governance_config.clone(), - proposals_count: 0, - reserved: [0; 6], - voting_proposal_count: 0, - reserved_v2: [0; 128], - }; - - let mint_governance_address = get_mint_governance_address( - &self.program_id, - &realm_cookie.address, - &governed_mint_cookie.address, - ); - - Ok(GovernanceCookie { - address: mint_governance_address, - account, - next_proposal_index: 0, - }) - } - - #[allow(dead_code)] - pub async fn with_token_governance( - &mut self, - realm_cookie: &RealmCookie, - governed_token_cookie: &GovernedTokenCookie, - token_owner_record_cookie: &TokenOwnerRecordCookie, - ) -> Result { - self.with_token_governance_using_instruction( - realm_cookie, - governed_token_cookie, - &token_owner_record_cookie, - NopOverride, - None, - ) - .await - } - - #[allow(dead_code)] - pub async fn with_token_governance_using_instruction( - &mut self, - realm_cookie: &RealmCookie, - governed_token_cookie: &GovernedTokenCookie, - token_owner_record_cookie: &TokenOwnerRecordCookie, - instruction_override: F, - signers_override: Option<&[&Keypair]>, - ) -> Result { - let config = self.get_default_governance_config(); - - let voter_weight_record = - if let Some(voter_weight_record) = &token_owner_record_cookie.voter_weight_record { - Some(voter_weight_record.address) - } else { - None - }; - - let mut create_token_governance_ix = create_token_governance( - &self.program_id, - &realm_cookie.address, - &governed_token_cookie.address, - &governed_token_cookie.token_owner.pubkey(), - &token_owner_record_cookie.address, - &self.bench.payer.pubkey(), - &token_owner_record_cookie.token_owner.pubkey(), - voter_weight_record, - config.clone(), - governed_token_cookie.transfer_token_owner, + let set_upgrade_authority_ix = bpf_loader_upgradeable::set_upgrade_authority( + &program_keypair.pubkey(), + &program_upgrade_authority_keypair.pubkey(), + Some(&governance_cookie.address), ); - instruction_override(&mut create_token_governance_ix); - - let default_signers = &[ - &governed_token_cookie.token_owner, - &token_owner_record_cookie.token_owner, - ]; - let signers = signers_override.unwrap_or(default_signers); - self.bench - .process_transaction(&[create_token_governance_ix], Some(signers)) - .await?; - - let account = GovernanceV2 { - account_type: GovernanceAccountType::TokenGovernanceV2, - realm: realm_cookie.address, - governed_account: governed_token_cookie.address, - config, - proposals_count: 0, - reserved: [0; 6], - voting_proposal_count: 0, - reserved_v2: [0; 128], - }; - - let token_governance_address = get_token_governance_address( - &self.program_id, - &realm_cookie.address, - &governed_token_cookie.address, - ); + .process_transaction( + &[set_upgrade_authority_ix], + Some(&[&program_upgrade_authority_keypair]), + ) + .await + .unwrap(); - Ok(GovernanceCookie { - address: token_governance_address, - account, - next_proposal_index: 0, - }) + GovernedProgramCookie { + address: program_keypair.pubkey(), + upgrade_authority: program_upgrade_authority_keypair, + data_address: program_data_address, + transfer_upgrade_authority: true, + } } #[allow(dead_code)] @@ -1732,7 +1653,11 @@ impl GovernanceProgramTest { .await?; let signatory_record_cookie = self - .with_signatory(&proposal_cookie, token_owner_record_cookie) + .with_signatory( + &proposal_cookie, + governance_cookie, + token_owner_record_cookie, + ) .await?; self.sign_off_proposal(&proposal_cookie, &signatory_record_cookie) @@ -1780,12 +1705,12 @@ impl GovernanceProgramTest { let governance_authority = token_owner_record_cookie.get_governance_authority(); - let voter_weight_record = - if let Some(voter_weight_record) = &token_owner_record_cookie.voter_weight_record { - Some(voter_weight_record.address) - } else { - None - }; + let voter_weight_record = token_owner_record_cookie + .voter_weight_record + .as_ref() + .map(|voter_weight_record| voter_weight_record.address); + + let proposal_seed = Pubkey::new_unique(); let mut create_proposal_transaction = create_proposal( &self.program_id, @@ -1801,7 +1726,7 @@ impl GovernanceProgramTest { vote_type.clone(), options.clone(), use_deny_option, - proposal_index, + &proposal_seed, ); instruction_override(&mut create_proposal_transaction); @@ -1851,7 +1776,7 @@ impl GovernanceProgramTest { token_owner_record: token_owner_record_cookie.address, signatories_signed_off_count: 0, - vote_type: vote_type, + vote_type, options: proposal_options, deny_vote_weight, @@ -1864,6 +1789,7 @@ impl GovernanceProgramTest { vote_threshold: None, reserved: [0; 64], + reserved1: 0, }; @@ -1871,14 +1797,32 @@ impl GovernanceProgramTest { &self.program_id, &governance_cookie.address, &token_owner_record_cookie.account.governing_token_mint, - &proposal_index.to_le_bytes(), + &proposal_seed, ); + // Setup Proposal deposit + let proposal_deposit_payer = self.bench.payer.pubkey(); + + let proposal_deposit_cookie = ProposalDepositCookie { + address: get_proposal_deposit_address( + &self.program_id, + &proposal_address, + &proposal_deposit_payer, + ), + account: ProposalDeposit { + account_type: GovernanceAccountType::ProposalDeposit, + proposal: proposal_address, + deposit_payer: proposal_deposit_payer, + reserved: [0; 64], + }, + }; + Ok(ProposalCookie { address: proposal_address, account, proposal_owner: governance_authority.pubkey(), realm: governance_cookie.account.realm, + proposal_deposit: proposal_deposit_cookie, }) } @@ -1886,15 +1830,19 @@ impl GovernanceProgramTest { pub async fn with_signatory( &mut self, proposal_cookie: &ProposalCookie, + governance_cookie: &GovernanceCookie, token_owner_record_cookie: &TokenOwnerRecordCookie, ) -> Result { let signatory = Keypair::new(); let add_signatory_ix = add_signatory( &self.program_id, + &governance_cookie.address, &proposal_cookie.address, - &token_owner_record_cookie.address, - &token_owner_record_cookie.token_owner.pubkey(), + &AddSignatoryAuthority::ProposalOwner { + token_owner_record: token_owner_record_cookie.address, + governance_authority: token_owner_record_cookie.token_owner.pubkey(), + }, &self.bench.payer.pubkey(), &signatory.pubkey(), ); @@ -1923,37 +1871,12 @@ impl GovernanceProgramTest { let signatory_record_cookie = SignatoryRecordCookie { address: signatory_record_address, account: signatory_record_data, - signatory, + signatory: Some(signatory), }; Ok(signatory_record_cookie) } - #[allow(dead_code)] - pub async fn remove_signatory( - &mut self, - proposal_cookie: &ProposalCookie, - token_owner_record_cookie: &TokenOwnerRecordCookie, - signatory_record_cookie: &SignatoryRecordCookie, - ) -> Result<(), ProgramError> { - let remove_signatory_ix = remove_signatory( - &self.program_id, - &proposal_cookie.address, - &token_owner_record_cookie.address, - &token_owner_record_cookie.token_owner.pubkey(), - &signatory_record_cookie.account.signatory, - &token_owner_record_cookie.token_owner.pubkey(), - ); - - self.bench - .process_transaction( - &[remove_signatory_ix], - Some(&[&token_owner_record_cookie.token_owner]), - ) - .await?; - - Ok(()) - } #[allow(dead_code)] pub async fn sign_off_proposal_by_owner( &mut self, @@ -2026,13 +1949,13 @@ impl GovernanceProgramTest { &proposal_cookie.realm, &proposal_cookie.account.governance, &proposal_cookie.address, - &signatory_record_cookie.signatory.pubkey(), + &signatory_record_cookie.signatory.as_ref().unwrap().pubkey(), None, ); instruction_override(&mut sign_off_proposal_ix); - let default_signers = &[&signatory_record_cookie.signatory]; + let default_signers = &[signatory_record_cookie.signatory.as_ref().unwrap()]; let signers = signers_override.unwrap_or(default_signers); self.bench @@ -2043,13 +1966,44 @@ impl GovernanceProgramTest { } #[allow(dead_code)] - pub async fn finalize_vote( + pub async fn refund_proposal_deposit( &mut self, - realm_cookie: &RealmCookie, proposal_cookie: &ProposalCookie, - max_voter_weight_record_cookie: Option, ) -> Result<(), ProgramError> { - let max_voter_weight_record = max_voter_weight_record_cookie.map(|rc| rc.address); + self.refund_proposal_deposit_using_instruction(proposal_cookie, NopOverride, None) + .await + } + + #[allow(dead_code)] + pub async fn refund_proposal_deposit_using_instruction( + &mut self, + proposal_cookie: &ProposalCookie, + instruction_override: F, + signers_override: Option<&[&Keypair]>, + ) -> Result<(), ProgramError> { + let mut refund_proposal_deposit_ix = refund_proposal_deposit( + &self.program_id, + &proposal_cookie.address, + &proposal_cookie.proposal_deposit.account.deposit_payer, + ); + + instruction_override(&mut refund_proposal_deposit_ix); + + self.bench + .process_transaction(&[refund_proposal_deposit_ix], signers_override) + .await?; + + Ok(()) + } + + #[allow(dead_code)] + pub async fn finalize_vote( + &mut self, + realm_cookie: &RealmCookie, + proposal_cookie: &ProposalCookie, + max_voter_weight_record_cookie: Option, + ) -> Result<(), ProgramError> { + let max_voter_weight_record = max_voter_weight_record_cookie.map(|rc| rc.address); let finalize_vote_ix = finalize_vote( &self.program_id, @@ -2155,7 +2109,6 @@ impl GovernanceProgramTest { self.with_cast_vote(proposal_cookie, token_owner_record_cookie, vote) .await } - #[allow(dead_code)] pub async fn with_cast_vote( &mut self, @@ -2163,22 +2116,36 @@ impl GovernanceProgramTest { token_owner_record_cookie: &TokenOwnerRecordCookie, vote: Vote, ) -> Result { - let voter_weight_record = - if let Some(voter_weight_record) = &token_owner_record_cookie.voter_weight_record { - Some(voter_weight_record.address) - } else { - None - }; + self.with_cast_vote_using_instruction( + proposal_cookie, + token_owner_record_cookie, + vote, + NopOverride, + None, + ) + .await + } - let max_voter_weight_record = if let Some(max_voter_weight_record) = - &token_owner_record_cookie.max_voter_weight_record - { - Some(max_voter_weight_record.address) - } else { - None - }; + #[allow(dead_code)] + pub async fn with_cast_vote_using_instruction( + &mut self, + proposal_cookie: &ProposalCookie, + token_owner_record_cookie: &TokenOwnerRecordCookie, + vote: Vote, + instruction_override: F, + signers_override: Option<&[&Keypair]>, + ) -> Result { + let voter_weight_record = token_owner_record_cookie + .voter_weight_record + .as_ref() + .map(|voter_weight_record| voter_weight_record.address); + + let max_voter_weight_record = token_owner_record_cookie + .max_voter_weight_record + .as_ref() + .map(|max_voter_weight_record| max_voter_weight_record.address); - let cast_vote_ix = cast_vote( + let mut cast_vote_ix = cast_vote( &self.program_id, &token_owner_record_cookie.account.realm, &proposal_cookie.account.governance, @@ -2193,11 +2160,13 @@ impl GovernanceProgramTest { vote.clone(), ); + instruction_override(&mut cast_vote_ix); + + let default_signers = &[&token_owner_record_cookie.token_owner]; + let signers = signers_override.unwrap_or(default_signers); + self.bench - .process_transaction( - &[cast_vote_ix], - Some(&[&token_owner_record_cookie.token_owner]), - ) + .process_transaction(&[cast_vote_ix], Some(signers)) .await?; let vote_amount = token_owner_record_cookie @@ -2245,7 +2214,6 @@ impl GovernanceProgramTest { 0, None, &mut set_governance_config_ix, - None, ) .await } @@ -2258,7 +2226,6 @@ impl GovernanceProgramTest { token_owner_record_cookie: &TokenOwnerRecordCookie, option_index: u8, index: Option, - hold_up_time: Option, ) -> Result { let token_account_keypair = Keypair::new(); self.bench @@ -2285,7 +2252,6 @@ impl GovernanceProgramTest { option_index, index, &mut instruction, - hold_up_time, ) .await } @@ -2293,7 +2259,7 @@ impl GovernanceProgramTest { #[allow(dead_code)] pub async fn with_transfer_tokens_transaction( &mut self, - governed_token_cookie: &GovernedTokenCookie, + governed_token_account_cookie: &GovernedTokenAccountCookie, proposal_cookie: &mut ProposalCookie, token_owner_record_cookie: &TokenOwnerRecordCookie, index: Option, @@ -2302,14 +2268,14 @@ impl GovernanceProgramTest { self.bench .create_empty_token_account( &token_account_keypair, - &governed_token_cookie.token_mint, + &governed_token_account_cookie.token_mint, &self.bench.payer.pubkey(), ) .await; let mut instruction = spl_token::instruction::transfer( &spl_token::id(), - &governed_token_cookie.address, + &governed_token_account_cookie.address, &token_account_keypair.pubkey(), &proposal_cookie.account.governance, &[], @@ -2323,7 +2289,6 @@ impl GovernanceProgramTest { 0, index, &mut instruction, - None, ) .await } @@ -2349,7 +2314,6 @@ impl GovernanceProgramTest { 0, None, &mut transfer_ix, - None, ) .await } @@ -2368,12 +2332,14 @@ impl GovernanceProgramTest { let path_buf = find_file("solana_bpf_rust_upgraded.so").unwrap(); let program_data = read_file(path_buf); - let program_buffer_rent = self - .bench - .rent - .minimum_balance(UpgradeableLoaderState::programdata_len(program_data.len()).unwrap()); + let program_buffer_rent = + self.bench + .rent + .minimum_balance(UpgradeableLoaderState::size_of_programdata( + program_data.len(), + )); - let mut instructions = bpf_loader_upgradeable::create_buffer( + let instructions = bpf_loader_upgradeable::create_buffer( &self.bench.payer.pubkey(), &program_buffer_keypair.pubkey(), &buffer_authority_keypair.pubkey(), @@ -2382,33 +2348,38 @@ impl GovernanceProgramTest { ) .unwrap(); - let chunk_size = 800; + self.bench + .process_transaction(&instructions, Some(&[&program_buffer_keypair])) + .await + .unwrap(); - for (chunk, i) in program_data.chunks(chunk_size).zip(0..) { - instructions.push(bpf_loader_upgradeable::write( + const CHUNK_SIZE: usize = 800; + for (i, chunk) in program_data.chunks(CHUNK_SIZE).enumerate() { + let instruction = bpf_loader_upgradeable::write( &program_buffer_keypair.pubkey(), &buffer_authority_keypair.pubkey(), - (i * chunk_size) as u32, + (i * CHUNK_SIZE) as u32, chunk.to_vec(), - )); + ); + self.bench + .process_transaction(&[instruction], Some(&[&buffer_authority_keypair])) + .await + .unwrap(); } - instructions.push(bpf_loader_upgradeable::set_buffer_authority( + let set_authority_ixs = bpf_loader_upgradeable::set_buffer_authority( &program_buffer_keypair.pubkey(), &buffer_authority_keypair.pubkey(), &governance_cookie.address, - )); + ); self.bench - .process_transaction( - &instructions[..], - Some(&[&program_buffer_keypair, &buffer_authority_keypair]), - ) + .process_transaction(&[set_authority_ixs], Some(&[&buffer_authority_keypair])) .await .unwrap(); let mut upgrade_ix = bpf_loader_upgradeable::upgrade( - &governance_cookie.account.governed_account, + &governance_cookie.account.governance_seed, &program_buffer_keypair.pubkey(), &governance_cookie.address, &governance_cookie.address, @@ -2420,7 +2391,6 @@ impl GovernanceProgramTest { 0, None, &mut upgrade_ix, - None, ) .await } @@ -2434,7 +2404,8 @@ impl GovernanceProgramTest { index: Option, ) -> Result { // Create NOP instruction as a placeholder - // Note: The actual instruction is irrelevant because we do not execute it in tests + // Note: The actual instruction is irrelevant because we do not execute it in + // tests let mut instruction = Instruction { program_id: Pubkey::new_unique(), accounts: vec![], @@ -2447,7 +2418,6 @@ impl GovernanceProgramTest { option_index, index, &mut instruction, - None, ) .await } @@ -2460,12 +2430,9 @@ impl GovernanceProgramTest { option_index: u8, index: Option, instruction: &mut Instruction, - hold_up_time: Option, ) -> Result { - let hold_up_time = hold_up_time.unwrap_or(15); - let instruction_data: InstructionData = instruction.clone().into(); - let mut yes_option = &mut proposal_cookie.account.options[0]; + let yes_option = &mut proposal_cookie.account.options[0]; let transaction_index = index.unwrap_or(yes_option.transactions_next_index); @@ -2480,7 +2447,6 @@ impl GovernanceProgramTest { &self.bench.payer.pubkey(), option_index, transaction_index, - hold_up_time, vec![instruction_data.clone()], ); @@ -2502,7 +2468,7 @@ impl GovernanceProgramTest { account_type: GovernanceAccountType::ProposalTransactionV2, option_index, transaction_index, - hold_up_time, + legacy: 0, instructions: vec![instruction_data], executed_at: None, execution_status: TransactionExecutionStatus::None, @@ -2515,7 +2481,9 @@ impl GovernanceProgramTest { .iter() .map(|a| AccountMeta { pubkey: a.pubkey, - is_signer: false, // Remove signer since the Governance account PDA will be signing the instruction for us + // Remove signer since the Governance account PDA will be + // signing the instruction for us + is_signer: false, is_writable: a.is_writable, }) .collect(); @@ -2530,10 +2498,191 @@ impl GovernanceProgramTest { } #[allow(dead_code)] - pub async fn remove_transaction( + pub async fn with_add_required_signatory_transaction( + &mut self, + proposal_cookie: &mut ProposalCookie, + token_owner_record_cookie: &TokenOwnerRecordCookie, + governance: &GovernanceCookie, + signatory: &Pubkey, + ) -> Result { + let mut gwr_ix = add_required_signatory( + &self.program_id, + &governance.address, + &self.bench.payer.pubkey(), + signatory, + ); + + self.with_proposal_transaction( + proposal_cookie, + token_owner_record_cookie, + 0, + None, + &mut gwr_ix, + ) + .await + } + + #[allow(dead_code)] + pub async fn with_remove_required_signatory_transaction( &mut self, proposal_cookie: &mut ProposalCookie, token_owner_record_cookie: &TokenOwnerRecordCookie, + governance: &GovernanceCookie, + signatory: &Pubkey, + beneficiary: &Pubkey, + ) -> Result { + let mut ix = remove_required_signatory( + &self.program_id, + &governance.address, + signatory, + beneficiary, + ); + + self.with_proposal_transaction(proposal_cookie, token_owner_record_cookie, 0, None, &mut ix) + .await + } + + #[allow(dead_code)] + pub async fn do_required_signoff( + &mut self, + realm_cookie: &RealmCookie, + governance_cookie: &GovernanceCookie, + proposal_cookie: &ProposalCookie, + signatory: &Keypair, + ) -> Result<(), ProgramError> { + let ix = sign_off_proposal( + &self.program_id, + &realm_cookie.address, + &governance_cookie.address, + &proposal_cookie.address, + &signatory.pubkey(), + None, + ); + + self.bench + .process_transaction(&[ix], Some(&[signatory])) + .await?; + + Ok(()) + } + + #[allow(dead_code)] + pub async fn with_signatory_record_for_required_signatory( + &mut self, + proposal_cookie: &ProposalCookie, + governance: &GovernanceCookie, + signatory: &Pubkey, + ) -> Result { + let create_signatory_record_ix = add_signatory( + &self.program_id, + &governance.address, + &proposal_cookie.address, + &AddSignatoryAuthority::None, + &self.bench.payer.pubkey(), + signatory, + ); + + self.bench + .process_transaction(&[create_signatory_record_ix], Some(&[])) + .await?; + + let signatory_record_address = + get_signatory_record_address(&self.program_id, &proposal_cookie.address, signatory); + + let signatory_record_data = SignatoryRecordV2 { + account_type: GovernanceAccountType::SignatoryRecordV2, + proposal: proposal_cookie.address, + signatory: *signatory, + signed_off: false, + reserved_v2: [0; 8], + }; + + let signatory_record_cookie = SignatoryRecordCookie { + address: signatory_record_address, + account: signatory_record_data, + signatory: None, + }; + + Ok(signatory_record_cookie) + } + + #[allow(dead_code)] + pub async fn with_governance_with_required_signatory( + &mut self, + ) -> ( + TokenOwnerRecordCookie, + GovernanceCookie, + RealmCookie, + Keypair, + ) { + let realm_cookie = self.with_realm().await; + + let signatory = Keypair::new(); + + let token_owner_record_cookie = self + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_cookie = self + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + let mut proposal_cookie = self + .with_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + let signatory_record_cookie = self + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) + .await + .unwrap(); + + let proposal_transaction_cookie = self + .with_add_required_signatory_transaction( + &mut proposal_cookie, + &token_owner_record_cookie, + &governance_cookie, + &signatory.pubkey(), + ) + .await + .unwrap(); + + self.sign_off_proposal(&proposal_cookie, &signatory_record_cookie) + .await + .unwrap(); + + self.with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + self.advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) + .await; + + self.execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie) + .await + .unwrap(); + + ( + token_owner_record_cookie, + governance_cookie, + realm_cookie, + signatory, + ) + } + + #[allow(dead_code)] + pub async fn remove_transaction( + &mut self, + proposal_cookie: &ProposalCookie, + token_owner_record_cookie: &TokenOwnerRecordCookie, proposal_transaction_cookie: &ProposalTransactionCookie, ) -> Result<(), ProgramError> { let remove_transaction_ix = remove_transaction( @@ -2575,28 +2724,6 @@ impl GovernanceProgramTest { .await } - #[allow(dead_code)] - pub async fn flag_transaction_error( - &mut self, - proposal_cookie: &ProposalCookie, - token_owner_record_cookie: &TokenOwnerRecordCookie, - proposal_transaction_cookie: &ProposalTransactionCookie, - ) -> Result<(), ProgramError> { - let governance_authority = token_owner_record_cookie.get_governance_authority(); - - let flag_transaction_error_ix = flag_transaction_error( - &self.program_id, - &proposal_cookie.address, - &proposal_cookie.account.token_owner_record, - &governance_authority.pubkey(), - &proposal_transaction_cookie.address, - ); - - self.bench - .process_transaction(&[flag_transaction_error_ix], Some(&[&governance_authority])) - .await - } - #[allow(dead_code)] pub async fn get_token_owner_record_account(&mut self, address: &Pubkey) -> TokenOwnerRecordV2 { self.bench @@ -2618,13 +2745,20 @@ impl GovernanceProgramTest { .await } + #[allow(dead_code)] + pub async fn get_proposal_deposit_account(&mut self, address: &Pubkey) -> ProposalDeposit { + self.bench + .get_borsh_account::(address) + .await + } + #[allow(dead_code)] pub async fn get_realm_account(&mut self, realm_address: &Pubkey) -> RealmV2 { self.bench.get_borsh_account::(realm_address).await } #[allow(dead_code)] - pub async fn get_realm_config_data( + pub async fn get_realm_config_account( &mut self, realm_config_address: &Pubkey, ) -> RealmConfigAccount { @@ -2633,6 +2767,11 @@ impl GovernanceProgramTest { .await } + #[allow(dead_code)] + pub fn remove_realm_config_account(&mut self, realm_config_address: &Pubkey) { + self.bench.remove_account(realm_config_address); + } + #[allow(dead_code)] pub async fn get_governance_account(&mut self, governance_address: &Pubkey) -> GovernanceV2 { self.bench @@ -2664,6 +2803,16 @@ impl GovernanceProgramTest { .await } + #[allow(dead_code)] + pub async fn get_required_signatory_account( + &mut self, + required_signatory_address: &Pubkey, + ) -> RequiredSignatory { + self.bench + .get_borsh_account::(required_signatory_address) + .await + } + #[allow(dead_code)] pub async fn get_signatory_record_account( &mut self, @@ -2684,12 +2833,18 @@ impl GovernanceProgramTest { .unwrap() } + #[allow(dead_code)] + pub fn set_account(&mut self, address: &Pubkey, account: &T) { + self.bench + .set_borsh_account(&self.program_id, address, account); + } + #[allow(dead_code)] pub async fn advance_clock_past_voting_time(&mut self, governance_cookie: &GovernanceCookie) { let clock = self.bench.get_clock().await; self.advance_clock_past_timestamp( - clock.unix_timestamp + governance_cookie.account.config.max_voting_time as i64, + clock.unix_timestamp + governance_cookie.account.config.voting_base_time as i64, ) .await; } @@ -2700,7 +2855,8 @@ impl GovernanceProgramTest { let mut n = 1; while clock.unix_timestamp <= unix_timestamp { - // Since the exact time is not deterministic keep wrapping by arbitrary 400 slots until we pass the requested timestamp + // Since the exact time is not deterministic keep wrapping by arbitrary 400 + // slots until we pass the requested timestamp self.bench .context .warp_to_slot(clock.slot + n * 400) @@ -2856,4 +3012,233 @@ impl GovernanceProgramTest { Ok(max_voter_weight_record_cookie) } + + #[allow(dead_code)] + pub async fn complete_proposal( + &mut self, + proposal_cookie: &ProposalCookie, + token_owner_record_cookie: &TokenOwnerRecordCookie, + ) -> Result<(), ProgramError> { + let complete_proposal_authority = token_owner_record_cookie.get_governance_authority(); + + let complete_proposal_ix = complete_proposal( + &self.program_id, + &proposal_cookie.address, + &proposal_cookie.account.token_owner_record, + &complete_proposal_authority.pubkey(), + ); + + self.bench + .process_transaction( + &[complete_proposal_ix], + Some(&[complete_proposal_authority]), + ) + .await?; + + Ok(()) + } + + #[allow(dead_code)] + pub async fn with_token_owner_record_lock( + &mut self, + token_owner_record_cookie: &TokenOwnerRecordCookie, + token_owner_record_lock_authority_cookie: &TokenOwnerRecordLockAuthorityCookie, + ) -> Result { + let lock_id = 5; + let clock = self.bench.get_clock().await; + let expiry: Option = Some(clock.unix_timestamp + 1); + + self.set_token_owner_record_lock( + token_owner_record_cookie, + token_owner_record_lock_authority_cookie, + lock_id, + expiry, + ) + .await?; + + Ok(TokenOwnerRecordLockCookie { + authority: token_owner_record_lock_authority_cookie.authority.pubkey(), + lock_id, + expiry, + }) + } + + #[allow(dead_code)] + pub async fn set_token_owner_record_lock( + &mut self, + token_owner_record_cookie: &TokenOwnerRecordCookie, + token_owner_record_lock_authority_cookie: &TokenOwnerRecordLockAuthorityCookie, + lock_id: u8, + expiry: Option, + ) -> Result<(), ProgramError> { + self.set_token_owner_record_lock_using_ix( + token_owner_record_cookie, + token_owner_record_lock_authority_cookie, + lock_id, + expiry, + NopOverride, + None, + ) + .await + } + + #[allow(dead_code)] + pub async fn set_token_owner_record_lock_using_ix( + &mut self, + token_owner_record_cookie: &TokenOwnerRecordCookie, + token_owner_record_lock_authority_cookie: &TokenOwnerRecordLockAuthorityCookie, + lock_id: u8, + expiry: Option, + instruction_override: F, + signers_override: Option<&[&Keypair]>, + ) -> Result<(), ProgramError> { + let mut set_token_owner_record_lock_ix = set_token_owner_record_lock( + &self.program_id, + &token_owner_record_cookie.account.realm, + &token_owner_record_cookie.address, + &token_owner_record_lock_authority_cookie.authority.pubkey(), + &self.bench.payer.pubkey(), + lock_id, + expiry, + ); + + instruction_override(&mut set_token_owner_record_lock_ix); + + let default_signers = &[&token_owner_record_lock_authority_cookie.authority]; + let signers = signers_override.unwrap_or(default_signers); + + self.bench + .process_transaction(&[set_token_owner_record_lock_ix], Some(signers)) + .await + } + + #[allow(dead_code)] + pub async fn relinquish_token_owner_record_locks( + &mut self, + token_owner_record_cookie: &TokenOwnerRecordCookie, + token_owner_record_lock_authority: Option<&Keypair>, + lock_ids: Option>, + ) -> Result<(), ProgramError> { + self.relinquish_token_owner_record_locks_using_ix( + token_owner_record_cookie, + token_owner_record_lock_authority, + lock_ids, + NopOverride, + None, + ) + .await + } + + #[allow(dead_code)] + pub async fn relinquish_token_owner_record_locks_using_ix( + &mut self, + token_owner_record_cookie: &TokenOwnerRecordCookie, + token_owner_record_lock_authority: Option<&Keypair>, + lock_ids: Option>, + instruction_override: F, + signers_override: Option<&[&Keypair]>, + ) -> Result<(), ProgramError> { + let token_owner_record_lock_authority_pubkey = + token_owner_record_lock_authority.map(|kp| kp.pubkey()); + + let mut remove_token_owner_record_lock_ix = relinquish_token_owner_record_locks( + &self.program_id, + &token_owner_record_cookie.account.realm, + &token_owner_record_cookie.address, + token_owner_record_lock_authority_pubkey, + lock_ids, + ); + + instruction_override(&mut remove_token_owner_record_lock_ix); + + let default_signers = + if let Some(token_owner_record_lock_authority) = token_owner_record_lock_authority { + vec![token_owner_record_lock_authority] + } else { + vec![] + }; + let signers = signers_override.unwrap_or(&default_signers); + + self.bench + .process_transaction(&[remove_token_owner_record_lock_ix], Some(signers)) + .await + } + + #[allow(dead_code)] + pub async fn set_realm_config_item( + &mut self, + realm_cookie: &RealmCookie, + args: SetRealmConfigItemArgs, + ) -> Result<(), ProgramError> { + self.set_realm_config_item_using_ix(realm_cookie, args, NopOverride, None) + .await + } + + #[allow(dead_code)] + pub async fn set_realm_config_item_using_ix( + &mut self, + realm_cookie: &RealmCookie, + args: SetRealmConfigItemArgs, + instruction_override: F, + signers_override: Option<&[&Keypair]>, + ) -> Result<(), ProgramError> { + let mut set_realm_config_item_ix = set_realm_config_item( + &self.program_id, + &realm_cookie.address, + &realm_cookie.account.authority.unwrap(), + &self.bench.payer.pubkey(), + args, + ); + + instruction_override(&mut set_realm_config_item_ix); + + let default_signers = &[realm_cookie.realm_authority.as_ref().unwrap()]; + let signers = signers_override.unwrap_or(default_signers); + + self.bench + .process_transaction(&[set_realm_config_item_ix], Some(signers)) + .await + } + + #[allow(dead_code)] + pub async fn with_community_token_owner_record_lock_authority( + &mut self, + realm_cookie: &RealmCookie, + ) -> Result { + let token_owner_record_lock_authority = Keypair::new(); + let args = SetRealmConfigItemArgs::TokenOwnerRecordLockAuthority { + action: SetConfigItemActionType::Add, + governing_token_mint: realm_cookie.account.community_mint, + authority: token_owner_record_lock_authority.pubkey(), + }; + + self.set_realm_config_item(realm_cookie, args) + .await + .unwrap(); + + Ok(TokenOwnerRecordLockAuthorityCookie { + authority: token_owner_record_lock_authority, + }) + } + + #[allow(dead_code)] + pub async fn with_council_token_owner_record_lock_authority( + &mut self, + realm_cookie: &RealmCookie, + ) -> Result { + let token_owner_record_lock_authority = Keypair::new(); + let args = SetRealmConfigItemArgs::TokenOwnerRecordLockAuthority { + action: SetConfigItemActionType::Add, + governing_token_mint: realm_cookie.account.config.council_mint.unwrap(), + authority: token_owner_record_lock_authority.pubkey(), + }; + + self.set_realm_config_item(realm_cookie, args) + .await + .unwrap(); + + Ok(TokenOwnerRecordLockAuthorityCookie { + authority: token_owner_record_lock_authority, + }) + } } diff --git a/governance/program/tests/setup_realm_with_all_addins.rs b/governance/program/tests/setup_realm_with_all_addins.rs index ba0f18981f5..6502fcfd44c 100644 --- a/governance/program/tests/setup_realm_with_all_addins.rs +++ b/governance/program/tests/setup_realm_with_all_addins.rs @@ -1,42 +1,49 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] -use solana_program::pubkey::Pubkey; -use solana_program_test::*; +use {solana_program::pubkey::Pubkey, solana_program_test::*}; mod program_test; -use program_test::*; +use {crate::program_test::args::RealmSetupArgs, program_test::*}; #[tokio::test] async fn test_create_realm_with_all_addins() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_all_addins().await; - // Act - - let realm_cookie = governance_test.with_realm().await; + let mut realm_setup_args = RealmSetupArgs::default(); - // Assert + realm_setup_args + .community_token_config_args + .voter_weight_addin = governance_test.voter_weight_addin_id; - let realm_account_data = governance_test - .get_realm_account(&realm_cookie.address) - .await; + realm_setup_args + .community_token_config_args + .max_voter_weight_addin = governance_test.max_voter_weight_addin_id; - assert!(realm_account_data.config.use_community_voter_weight_addin); + // Act - assert!( - realm_account_data - .config - .use_max_community_voter_weight_addin - ); + let realm_cookie = governance_test + .with_realm_using_args(&realm_setup_args) + .await; - let realm_config_cookie = realm_cookie.realm_config.unwrap(); + // Assert let realm_config_data = governance_test - .get_realm_config_data(&realm_config_cookie.address) + .get_realm_config_account(&realm_cookie.realm_config.address) .await; - assert_eq!(realm_config_cookie.account, realm_config_data); + assert_eq!(realm_cookie.realm_config.account, realm_config_data); + + assert!(realm_config_data + .community_token_config + .voter_weight_addin + .is_some()); + + assert!(realm_config_data + .community_token_config + .max_voter_weight_addin + .is_some()); } #[tokio::test] @@ -44,56 +51,44 @@ async fn test_set_all_addins_for_realm_without_addins() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_all_addins().await; - let mut set_realm_config_args = governance_test.get_default_set_realm_config_args(); - - set_realm_config_args - .realm_config_args - .use_max_community_voter_weight_addin = false; - - set_realm_config_args - .realm_config_args - .use_community_voter_weight_addin = false; + let mut realm_setup_args = RealmSetupArgs::default(); let mut realm_cookie = governance_test - .with_realm_using_config_args(&set_realm_config_args) + .with_realm_using_args(&realm_setup_args) .await; - set_realm_config_args - .realm_config_args - .use_community_voter_weight_addin = true; + realm_setup_args + .community_token_config_args + .voter_weight_addin = governance_test.voter_weight_addin_id; - set_realm_config_args - .realm_config_args - .use_max_community_voter_weight_addin = true; + realm_setup_args + .community_token_config_args + .max_voter_weight_addin = governance_test.max_voter_weight_addin_id; // Act governance_test - .set_realm_config(&mut realm_cookie, &set_realm_config_args) + .set_realm_config(&mut realm_cookie, &realm_setup_args) .await .unwrap(); // Assert - let realm_account_data = governance_test - .get_realm_account(&realm_cookie.address) + let realm_config_data = governance_test + .get_realm_config_account(&realm_cookie.realm_config.address) .await; - assert!( - realm_account_data - .config - .use_max_community_voter_weight_addin - ); - - assert!(realm_account_data.config.use_community_voter_weight_addin); + assert_eq!(realm_cookie.realm_config.account, realm_config_data); - let realm_config_cookie = realm_cookie.realm_config.unwrap(); - - let realm_config_data = governance_test - .get_realm_config_data(&realm_config_cookie.address) - .await; + assert!(realm_config_data + .community_token_config + .voter_weight_addin + .is_some()); - assert_eq!(realm_config_cookie.account, realm_config_data); + assert!(realm_config_data + .community_token_config + .max_voter_weight_addin + .is_some()); } #[tokio::test] @@ -101,58 +96,47 @@ async fn test_set_all_addin_for_realm_without_council_and_addins() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_all_addins().await; - let mut set_realm_config_args = governance_test.get_default_set_realm_config_args(); - - set_realm_config_args - .realm_config_args - .use_community_voter_weight_addin = false; - - set_realm_config_args - .realm_config_args - .use_max_community_voter_weight_addin = false; - - set_realm_config_args.realm_config_args.use_council_mint = false; + let mut realm_setup_args = RealmSetupArgs { + use_council_mint: false, + ..Default::default() + }; let mut realm_cookie = governance_test - .with_realm_using_config_args(&set_realm_config_args) + .with_realm_using_args(&realm_setup_args) .await; - set_realm_config_args - .realm_config_args - .use_max_community_voter_weight_addin = true; + realm_setup_args + .community_token_config_args + .voter_weight_addin = governance_test.voter_weight_addin_id; - set_realm_config_args - .realm_config_args - .use_community_voter_weight_addin = true; + realm_setup_args + .community_token_config_args + .max_voter_weight_addin = governance_test.max_voter_weight_addin_id; // Act governance_test - .set_realm_config(&mut realm_cookie, &set_realm_config_args) + .set_realm_config(&mut realm_cookie, &realm_setup_args) .await .unwrap(); // Assert - let realm_account_data = governance_test - .get_realm_account(&realm_cookie.address) + let realm_config_data = governance_test + .get_realm_config_account(&realm_cookie.realm_config.address) .await; - assert!( - realm_account_data - .config - .use_max_community_voter_weight_addin - ); + assert_eq!(realm_cookie.realm_config.account, realm_config_data); - assert!(realm_account_data.config.use_community_voter_weight_addin); + assert!(realm_config_data + .community_token_config + .voter_weight_addin + .is_some()); - let realm_config_cookie = realm_cookie.realm_config.unwrap(); - - let realm_config_data = governance_test - .get_realm_config_data(&realm_config_cookie.address) - .await; - - assert_eq!(realm_config_cookie.account, realm_config_data); + assert!(realm_config_data + .community_token_config + .max_voter_weight_addin + .is_some()); } #[tokio::test] @@ -162,60 +146,61 @@ async fn test_set_all_realm_addins_for_realm_with_all_addins() { let mut realm_cookie = governance_test.with_realm().await; - let mut set_realm_config_args = governance_test.get_default_set_realm_config_args(); + let mut realm_setup_args = RealmSetupArgs::default(); - set_realm_config_args - .realm_config_args - .use_max_community_voter_weight_addin = true; + realm_setup_args + .community_token_config_args + .voter_weight_addin = governance_test.voter_weight_addin_id; - set_realm_config_args - .realm_config_args - .use_community_voter_weight_addin = true; + realm_setup_args + .community_token_config_args + .max_voter_weight_addin = governance_test.max_voter_weight_addin_id; let max_community_voter_weight_addin_address = Pubkey::new_unique(); - set_realm_config_args.max_community_voter_weight_addin = - Some(max_community_voter_weight_addin_address); + realm_setup_args + .community_token_config_args + .max_voter_weight_addin = Some(max_community_voter_weight_addin_address); let community_voter_weight_addin_address = Pubkey::new_unique(); - set_realm_config_args.community_voter_weight_addin = Some(community_voter_weight_addin_address); + realm_setup_args + .community_token_config_args + .voter_weight_addin = Some(community_voter_weight_addin_address); // Act governance_test - .set_realm_config(&mut realm_cookie, &set_realm_config_args) + .set_realm_config(&mut realm_cookie, &realm_setup_args) .await .unwrap(); // Assert - let realm_account_data = governance_test - .get_realm_account(&realm_cookie.address) - .await; - - assert!( - realm_account_data - .config - .use_max_community_voter_weight_addin - ); - - assert!(realm_account_data.config.use_community_voter_weight_addin); - - let realm_config_cookie = realm_cookie.realm_config.unwrap(); - let realm_config_data = governance_test - .get_realm_config_data(&realm_config_cookie.address) + .get_realm_config_account(&realm_cookie.realm_config.address) .await; - assert_eq!(realm_config_cookie.account, realm_config_data); + assert_eq!(realm_cookie.realm_config.account, realm_config_data); assert_eq!( - realm_config_data.max_community_voter_weight_addin, + realm_config_data + .community_token_config + .max_voter_weight_addin, Some(max_community_voter_weight_addin_address) ); assert_eq!( - realm_config_data.community_voter_weight_addin, + realm_config_data.community_token_config.voter_weight_addin, Some(community_voter_weight_addin_address) ); + + assert!(realm_config_data + .community_token_config + .voter_weight_addin + .is_some()); + + assert!(realm_config_data + .community_token_config + .max_voter_weight_addin + .is_some()); } #[tokio::test] @@ -223,48 +208,42 @@ async fn test_set_realm_config_without_addins_for_realm_without_addins() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_all_addins().await; - let mut set_realm_config_args = governance_test.get_default_set_realm_config_args(); - - set_realm_config_args - .realm_config_args - .use_max_community_voter_weight_addin = false; - - set_realm_config_args - .realm_config_args - .use_community_voter_weight_addin = false; + let mut realm_setup_args = RealmSetupArgs::default(); let mut realm_cookie = governance_test - .with_realm_using_config_args(&set_realm_config_args) + .with_realm_using_args(&realm_setup_args) .await; - set_realm_config_args - .realm_config_args - .use_max_community_voter_weight_addin = false; + realm_setup_args + .community_token_config_args + .max_voter_weight_addin = None; - set_realm_config_args - .realm_config_args - .use_community_voter_weight_addin = false; + realm_setup_args + .community_token_config_args + .voter_weight_addin = None; // Act governance_test - .set_realm_config(&mut realm_cookie, &set_realm_config_args) + .set_realm_config(&mut realm_cookie, &realm_setup_args) .await .unwrap(); // Assert - let realm_account_data = governance_test - .get_realm_account(&realm_cookie.address) + let realm_config_data = governance_test + .get_realm_config_account(&realm_cookie.realm_config.address) .await; - assert!( - !realm_account_data - .config - .use_max_community_voter_weight_addin - ); + assert!(realm_config_data + .community_token_config + .voter_weight_addin + .is_none()); - assert!(!realm_account_data.config.use_community_voter_weight_addin); + assert!(realm_config_data + .community_token_config + .max_voter_weight_addin + .is_none()); } #[tokio::test] @@ -273,35 +252,28 @@ async fn test_set_realm_config_without_any_addins_for_realm_with_existing_addins let mut governance_test = GovernanceProgramTest::start_with_all_addins().await; let mut realm_cookie = governance_test.with_realm().await; - let mut set_realm_config_args = governance_test.get_default_set_realm_config_args(); - - set_realm_config_args - .realm_config_args - .use_max_community_voter_weight_addin = false; - - set_realm_config_args - .realm_config_args - .use_community_voter_weight_addin = false; + let realm_setup_args = RealmSetupArgs::default(); // Act governance_test - .set_realm_config(&mut realm_cookie, &set_realm_config_args) + .set_realm_config(&mut realm_cookie, &realm_setup_args) .await .unwrap(); // Assert - let realm_account_data = governance_test - .get_realm_account(&realm_cookie.address) - .await; - - assert!(!realm_account_data.config.use_community_voter_weight_addin); - let realm_config_data = governance_test - .get_realm_config_data(&realm_cookie.realm_config.unwrap().address) + .get_realm_config_account(&realm_cookie.realm_config.address) .await; - assert!(realm_config_data.max_community_voter_weight_addin.is_none()); - assert!(realm_config_data.community_voter_weight_addin.is_none()); + assert!(realm_config_data + .community_token_config + .max_voter_weight_addin + .is_none()); + + assert!(realm_config_data + .community_token_config + .voter_weight_addin + .is_none()); } diff --git a/governance/program/tests/setup_realm_with_max_voter_weight_addin.rs b/governance/program/tests/setup_realm_with_max_voter_weight_addin.rs index 2423ddf2312..0b31c2ca5fc 100644 --- a/governance/program/tests/setup_realm_with_max_voter_weight_addin.rs +++ b/governance/program/tests/setup_realm_with_max_voter_weight_addin.rs @@ -1,40 +1,40 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] -use solana_program::pubkey::Pubkey; -use solana_program_test::*; +use {solana_program::pubkey::Pubkey, solana_program_test::*}; mod program_test; -use program_test::*; +use {crate::program_test::args::RealmSetupArgs, program_test::*}; #[tokio::test] async fn test_create_realm_with_max_voter_weight_addin() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await; - // Act + let mut realm_setup_args = RealmSetupArgs::default(); - let realm_cookie = governance_test.with_realm().await; + realm_setup_args + .community_token_config_args + .max_voter_weight_addin = governance_test.max_voter_weight_addin_id; - // Assert + // Act - let realm_account_data = governance_test - .get_realm_account(&realm_cookie.address) + let realm_cookie = governance_test + .with_realm_using_args(&realm_setup_args) .await; - assert!( - realm_account_data - .config - .use_max_community_voter_weight_addin - ); - - let realm_config_cookie = realm_cookie.realm_config.unwrap(); + // Assert let realm_config_data = governance_test - .get_realm_config_data(&realm_config_cookie.address) + .get_realm_config_account(&realm_cookie.realm_config.address) .await; - assert_eq!(realm_config_cookie.account, realm_config_data); + assert_eq!(realm_cookie.realm_config.account, realm_config_data); + + assert!(realm_config_data + .community_token_config + .max_voter_weight_addin + .is_some()); } #[tokio::test] @@ -42,50 +42,35 @@ async fn test_set_realm_max_voter_weight_addin_for_realm_without_addins() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await; - let mut set_realm_config_args = governance_test.get_default_set_realm_config_args(); - - set_realm_config_args - .realm_config_args - .use_max_community_voter_weight_addin = false; - - set_realm_config_args - .realm_config_args - .use_community_voter_weight_addin = false; + let mut realm_setup_args = RealmSetupArgs::default(); let mut realm_cookie = governance_test - .with_realm_using_config_args(&set_realm_config_args) + .with_realm_using_args(&realm_setup_args) .await; - set_realm_config_args - .realm_config_args - .use_max_community_voter_weight_addin = true; + realm_setup_args + .community_token_config_args + .max_voter_weight_addin = governance_test.max_voter_weight_addin_id; // Act governance_test - .set_realm_config(&mut realm_cookie, &set_realm_config_args) + .set_realm_config(&mut realm_cookie, &realm_setup_args) .await .unwrap(); // Assert - let realm_account_data = governance_test - .get_realm_account(&realm_cookie.address) - .await; - - assert!( - realm_account_data - .config - .use_max_community_voter_weight_addin - ); - - let realm_config_cookie = realm_cookie.realm_config.unwrap(); - let realm_config_data = governance_test - .get_realm_config_data(&realm_config_cookie.address) + .get_realm_config_account(&realm_cookie.realm_config.address) .await; - assert_eq!(realm_config_cookie.account, realm_config_data); + assert_eq!(realm_cookie.realm_config.account, realm_config_data); + + assert!(realm_config_data + .community_token_config + .max_voter_weight_addin + .is_some()); } #[tokio::test] @@ -93,52 +78,38 @@ async fn test_set_realm_max_voter_weight_addin_for_realm_without_council_and_add // Arrange let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await; - let mut set_realm_config_args = governance_test.get_default_set_realm_config_args(); - - set_realm_config_args - .realm_config_args - .use_community_voter_weight_addin = false; - - set_realm_config_args - .realm_config_args - .use_max_community_voter_weight_addin = false; - - set_realm_config_args.realm_config_args.use_council_mint = false; + let mut realm_setup_args = RealmSetupArgs { + use_council_mint: false, + ..Default::default() + }; let mut realm_cookie = governance_test - .with_realm_using_config_args(&set_realm_config_args) + .with_realm_using_args(&realm_setup_args) .await; - set_realm_config_args - .realm_config_args - .use_max_community_voter_weight_addin = true; + realm_setup_args + .community_token_config_args + .max_voter_weight_addin = governance_test.max_voter_weight_addin_id; // Act governance_test - .set_realm_config(&mut realm_cookie, &set_realm_config_args) + .set_realm_config(&mut realm_cookie, &realm_setup_args) .await .unwrap(); // Assert - let realm_account_data = governance_test - .get_realm_account(&realm_cookie.address) - .await; - - assert!( - realm_account_data - .config - .use_max_community_voter_weight_addin - ); - - let realm_config_cookie = realm_cookie.realm_config.unwrap(); - let realm_config_data = governance_test - .get_realm_config_data(&realm_config_cookie.address) + .get_realm_config_account(&realm_cookie.realm_config.address) .await; - assert_eq!(realm_config_cookie.account, realm_config_data); + assert_eq!(realm_cookie.realm_config.account, realm_config_data); + + assert!(realm_config_data + .community_token_config + .max_voter_weight_addin + .is_some()); } #[tokio::test] @@ -148,46 +119,42 @@ async fn test_set_realm_max_voter_weight_addin_for_realm_with_existing_voter_wei let mut realm_cookie = governance_test.with_realm().await; - let mut set_realm_config_args = governance_test.get_default_set_realm_config_args(); + let mut realm_setup_args = RealmSetupArgs::default(); - set_realm_config_args - .realm_config_args - .use_max_community_voter_weight_addin = true; + realm_setup_args + .community_token_config_args + .max_voter_weight_addin = governance_test.max_voter_weight_addin_id; let max_community_voter_weight_addin_address = Pubkey::new_unique(); - set_realm_config_args.max_community_voter_weight_addin = - Some(max_community_voter_weight_addin_address); + realm_setup_args + .community_token_config_args + .max_voter_weight_addin = Some(max_community_voter_weight_addin_address); // Act governance_test - .set_realm_config(&mut realm_cookie, &set_realm_config_args) + .set_realm_config(&mut realm_cookie, &realm_setup_args) .await .unwrap(); // Assert - let realm_account_data = governance_test - .get_realm_account(&realm_cookie.address) - .await; - - assert!( - realm_account_data - .config - .use_max_community_voter_weight_addin - ); - - let realm_config_cookie = realm_cookie.realm_config.unwrap(); - let realm_config_data = governance_test - .get_realm_config_data(&realm_config_cookie.address) + .get_realm_config_account(&realm_cookie.realm_config.address) .await; - assert_eq!(realm_config_cookie.account, realm_config_data); + assert_eq!(realm_cookie.realm_config.account, realm_config_data); assert_eq!( - realm_config_data.max_community_voter_weight_addin, + realm_config_data + .community_token_config + .max_voter_weight_addin, Some(max_community_voter_weight_addin_address) ); + + assert!(realm_config_data + .community_token_config + .max_voter_weight_addin + .is_some()); } #[tokio::test] @@ -195,38 +162,33 @@ async fn test_set_realm_config_with_no_max_voter_weight_addin_for_realm_without_ // Arrange let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await; - let mut set_realm_config_args = governance_test.get_default_set_realm_config_args(); - - set_realm_config_args - .realm_config_args - .use_max_community_voter_weight_addin = false; + let mut realm_setup_args = RealmSetupArgs::default(); let mut realm_cookie = governance_test - .with_realm_using_config_args(&set_realm_config_args) + .with_realm_using_args(&realm_setup_args) .await; - set_realm_config_args - .realm_config_args - .use_max_community_voter_weight_addin = false; + realm_setup_args + .community_token_config_args + .max_voter_weight_addin = None; // Act governance_test - .set_realm_config(&mut realm_cookie, &set_realm_config_args) + .set_realm_config(&mut realm_cookie, &realm_setup_args) .await .unwrap(); // Assert - let realm_account_data = governance_test - .get_realm_account(&realm_cookie.address) + let realm_config_data = governance_test + .get_realm_config_account(&realm_cookie.realm_config.address) .await; - assert!( - !realm_account_data - .config - .use_max_community_voter_weight_addin - ); + assert!(realm_config_data + .community_token_config + .max_voter_weight_addin + .is_none()); } #[tokio::test] @@ -235,30 +197,28 @@ async fn test_set_realm_config_with_no_max_voter_weight_addin_for_realm_with_exi let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await; let mut realm_cookie = governance_test.with_realm().await; - let mut set_realm_config_args = governance_test.get_default_set_realm_config_args(); - - set_realm_config_args - .realm_config_args - .use_max_community_voter_weight_addin = false; + let realm_setup_args = RealmSetupArgs::default(); // Act governance_test - .set_realm_config(&mut realm_cookie, &set_realm_config_args) + .set_realm_config(&mut realm_cookie, &realm_setup_args) .await .unwrap(); // Assert - let realm_account_data = governance_test - .get_realm_account(&realm_cookie.address) - .await; - - assert!(!realm_account_data.config.use_community_voter_weight_addin); - let realm_config_data = governance_test - .get_realm_config_data(&realm_cookie.realm_config.unwrap().address) + .get_realm_config_account(&realm_cookie.realm_config.address) .await; - assert!(realm_config_data.max_community_voter_weight_addin.is_none()); + assert!(realm_config_data + .community_token_config + .max_voter_weight_addin + .is_none()); + + assert!(realm_config_data + .community_token_config + .voter_weight_addin + .is_none()); } diff --git a/governance/program/tests/setup_realm_with_voter_weight_addin.rs b/governance/program/tests/setup_realm_with_voter_weight_addin.rs index 7ca44961fbf..00d0ca56733 100644 --- a/governance/program/tests/setup_realm_with_voter_weight_addin.rs +++ b/governance/program/tests/setup_realm_with_voter_weight_addin.rs @@ -1,36 +1,40 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] -use solana_program::pubkey::Pubkey; -use solana_program_test::*; +use {solana_program::pubkey::Pubkey, solana_program_test::*}; mod program_test; -use program_test::*; +use {crate::program_test::args::RealmSetupArgs, program_test::*}; #[tokio::test] async fn test_create_realm_with_voter_weight_addin() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await; - // Act + let mut realm_setup_args = RealmSetupArgs::default(); - let realm_cookie = governance_test.with_realm().await; + realm_setup_args + .community_token_config_args + .voter_weight_addin = governance_test.voter_weight_addin_id; - // Assert + // Act - let realm_account_data = governance_test - .get_realm_account(&realm_cookie.address) + let realm_cookie = governance_test + .with_realm_using_args(&realm_setup_args) .await; - assert!(realm_account_data.config.use_community_voter_weight_addin); - - let realm_config_cookie = realm_cookie.realm_config.unwrap(); + // Assert let realm_config_data = governance_test - .get_realm_config_data(&realm_config_cookie.address) + .get_realm_config_account(&realm_cookie.realm_config.address) .await; - assert_eq!(realm_config_cookie.account, realm_config_data); + assert_eq!(realm_cookie.realm_config.account, realm_config_data); + + assert!(realm_config_data + .community_token_config + .voter_weight_addin + .is_some()); } #[tokio::test] @@ -38,41 +42,38 @@ async fn test_set_realm_voter_weight_addin_for_realm_without_addins() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await; - let mut set_realm_config_args = governance_test.get_default_set_realm_config_args(); - set_realm_config_args - .realm_config_args - .use_community_voter_weight_addin = false; + let mut realm_setup_args = RealmSetupArgs::default(); + realm_setup_args + .community_token_config_args + .voter_weight_addin = None; let mut realm_cookie = governance_test - .with_realm_using_config_args(&set_realm_config_args) + .with_realm_using_args(&realm_setup_args) .await; - set_realm_config_args - .realm_config_args - .use_community_voter_weight_addin = true; + realm_setup_args + .community_token_config_args + .voter_weight_addin = governance_test.voter_weight_addin_id; // Act governance_test - .set_realm_config(&mut realm_cookie, &set_realm_config_args) + .set_realm_config(&mut realm_cookie, &realm_setup_args) .await .unwrap(); // Assert - let realm_account_data = governance_test - .get_realm_account(&realm_cookie.address) - .await; - - assert!(realm_account_data.config.use_community_voter_weight_addin); - - let realm_config_cookie = realm_cookie.realm_config.unwrap(); - let realm_config_data = governance_test - .get_realm_config_data(&realm_config_cookie.address) + .get_realm_config_account(&realm_cookie.realm_config.address) .await; - assert_eq!(realm_config_cookie.account, realm_config_data); + assert_eq!(realm_cookie.realm_config.account, realm_config_data); + + assert!(realm_config_data + .community_token_config + .voter_weight_addin + .is_some()); } #[tokio::test] @@ -80,42 +81,38 @@ async fn test_set_realm_voter_weight_addin_for_realm_without_council_and_addins( // Arrange let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await; - let mut set_realm_config_args = governance_test.get_default_set_realm_config_args(); - set_realm_config_args - .realm_config_args - .use_community_voter_weight_addin = false; - set_realm_config_args.realm_config_args.use_council_mint = false; + let mut realm_setup_args = RealmSetupArgs { + use_council_mint: false, + ..Default::default() + }; let mut realm_cookie = governance_test - .with_realm_using_config_args(&set_realm_config_args) + .with_realm_using_args(&realm_setup_args) .await; - set_realm_config_args - .realm_config_args - .use_community_voter_weight_addin = true; + realm_setup_args + .community_token_config_args + .voter_weight_addin = governance_test.voter_weight_addin_id; // Act governance_test - .set_realm_config(&mut realm_cookie, &set_realm_config_args) + .set_realm_config(&mut realm_cookie, &realm_setup_args) .await .unwrap(); // Assert - let realm_account_data = governance_test - .get_realm_account(&realm_cookie.address) - .await; - - assert!(realm_account_data.config.use_community_voter_weight_addin); - - let realm_config_cookie = realm_cookie.realm_config.unwrap(); - let realm_config_data = governance_test - .get_realm_config_data(&realm_config_cookie.address) + .get_realm_config_account(&realm_cookie.realm_config.address) .await; - assert_eq!(realm_config_cookie.account, realm_config_data); + assert_eq!(realm_cookie.realm_config.account, realm_config_data); + + assert!(realm_config_data + .community_token_config + .voter_weight_addin + .is_some()); } #[tokio::test] @@ -123,43 +120,44 @@ async fn test_set_realm_voter_weight_addin_for_realm_with_existing_voter_weight_ // Arrange let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await; - let mut realm_cookie = governance_test.with_realm().await; + let mut realm_setup_args = RealmSetupArgs::default(); - let mut set_realm_config_args = governance_test.get_default_set_realm_config_args(); + realm_setup_args + .community_token_config_args + .voter_weight_addin = governance_test.voter_weight_addin_id; - set_realm_config_args - .realm_config_args - .use_community_voter_weight_addin = true; + let mut realm_cookie = governance_test + .with_realm_using_args(&realm_setup_args) + .await; let community_voter_weight_addin_address = Pubkey::new_unique(); - set_realm_config_args.community_voter_weight_addin = Some(community_voter_weight_addin_address); + realm_setup_args + .community_token_config_args + .voter_weight_addin = Some(community_voter_weight_addin_address); // Act governance_test - .set_realm_config(&mut realm_cookie, &set_realm_config_args) + .set_realm_config(&mut realm_cookie, &realm_setup_args) .await .unwrap(); // Assert - let realm_account_data = governance_test - .get_realm_account(&realm_cookie.address) - .await; - - assert!(realm_account_data.config.use_community_voter_weight_addin); - - let realm_config_cookie = realm_cookie.realm_config.unwrap(); - let realm_config_data = governance_test - .get_realm_config_data(&realm_config_cookie.address) + .get_realm_config_account(&realm_cookie.realm_config.address) .await; - assert_eq!(realm_config_cookie.account, realm_config_data); + assert_eq!(realm_cookie.realm_config.account, realm_config_data); assert_eq!( - realm_config_data.community_voter_weight_addin, + realm_config_data.community_token_config.voter_weight_addin, Some(community_voter_weight_addin_address) ); + + assert!(realm_config_data + .community_token_config + .voter_weight_addin + .is_some()); } #[tokio::test] @@ -167,33 +165,37 @@ async fn test_set_realm_config_with_no_voter_weight_addin_for_realm_without_addi // Arrange let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await; - let mut realm_config_args = governance_test.get_default_set_realm_config_args(); - realm_config_args - .realm_config_args - .use_community_voter_weight_addin = false; + let mut realm_setup_args = RealmSetupArgs::default(); + + realm_setup_args + .community_token_config_args + .voter_weight_addin = None; let mut realm_cookie = governance_test - .with_realm_using_config_args(&realm_config_args) + .with_realm_using_args(&realm_setup_args) .await; - realm_config_args - .realm_config_args - .use_community_voter_weight_addin = false; + realm_setup_args + .community_token_config_args + .voter_weight_addin = None; // Act governance_test - .set_realm_config(&mut realm_cookie, &realm_config_args) + .set_realm_config(&mut realm_cookie, &realm_setup_args) .await .unwrap(); // Assert - let realm_account_data = governance_test - .get_realm_account(&realm_cookie.address) + let realm_config_data = governance_test + .get_realm_config_account(&realm_cookie.realm_config.address) .await; - assert!(!realm_account_data.config.use_community_voter_weight_addin); + assert!(realm_config_data + .community_token_config + .voter_weight_addin + .is_none()); } #[tokio::test] @@ -202,29 +204,23 @@ async fn test_set_realm_config_with_no_voter_weight_addin_for_realm_with_existin let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await; let mut realm_cookie = governance_test.with_realm().await; - let mut realm_config_args = governance_test.get_default_set_realm_config_args(); - realm_config_args - .realm_config_args - .use_community_voter_weight_addin = false; + let realm_setup_args = RealmSetupArgs::default(); // Act governance_test - .set_realm_config(&mut realm_cookie, &realm_config_args) + .set_realm_config(&mut realm_cookie, &realm_setup_args) .await .unwrap(); // Assert - let realm_account_data = governance_test - .get_realm_account(&realm_cookie.address) - .await; - - assert!(!realm_account_data.config.use_community_voter_weight_addin); - let realm_config_data = governance_test - .get_realm_config_data(&realm_cookie.realm_config.unwrap().address) + .get_realm_config_account(&realm_cookie.realm_config.address) .await; - assert!(realm_config_data.community_voter_weight_addin.is_none()); + assert!(realm_config_data + .community_token_config + .voter_weight_addin + .is_none()); } diff --git a/governance/program/tests/use_proposals_with_multiple_options.rs b/governance/program/tests/use_proposals_with_multiple_options.rs index b8120956a2f..2a9af2a9f5e 100644 --- a/governance/program/tests/use_proposals_with_multiple_options.rs +++ b/governance/program/tests/use_proposals_with_multiple_options.rs @@ -1,16 +1,18 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] use solana_program_test::*; mod program_test; -use program_test::*; -use spl_governance::{ - error::GovernanceError, - state::{ - enums::{ProposalState, VoteThreshold}, - proposal::{OptionVoteResult, VoteType}, - vote_record::{Vote, VoteChoice}, +use { + program_test::*, + spl_governance::{ + error::GovernanceError, + state::{ + enums::{ProposalState, VoteThreshold}, + proposal::{MultiChoiceType, OptionVoteResult, VoteType}, + vote_record::{Vote, VoteChoice}, + }, }, }; @@ -20,7 +22,6 @@ async fn test_create_proposal_with_single_choice_options_and_deny_option() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -28,11 +29,7 @@ async fn test_create_proposal_with_single_choice_options_and_deny_option() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -66,7 +63,6 @@ async fn test_create_proposal_with_multiple_choice_options_and_without_deny_opti let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -74,11 +70,7 @@ async fn test_create_proposal_with_multiple_choice_options_and_without_deny_opti .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -92,6 +84,8 @@ async fn test_create_proposal_with_multiple_choice_options_and_without_deny_opti options, false, VoteType::MultiChoice { + choice_type: MultiChoiceType::FullWeight, + min_voter_options: 1, max_winning_options: 2, max_voter_options: 2, }, @@ -106,11 +100,13 @@ async fn test_create_proposal_with_multiple_choice_options_and_without_deny_opti assert_eq!( proposal_account.vote_type, VoteType::MultiChoice { + choice_type: MultiChoiceType::FullWeight, + min_voter_options: 1, max_winning_options: 2, max_voter_options: 2, } ); - assert!(!proposal_account.deny_vote_weight.is_some()); + assert!(proposal_account.deny_vote_weight.is_none()); assert_eq!(proposal_cookie.account, proposal_account); } @@ -121,7 +117,6 @@ async fn test_insert_transaction_with_proposal_not_executable_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -129,11 +124,7 @@ async fn test_insert_transaction_with_proposal_not_executable_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -165,7 +156,6 @@ async fn test_insert_transactions_for_multiple_options() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -173,11 +163,7 @@ async fn test_insert_transactions_for_multiple_options() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -239,7 +225,6 @@ async fn test_vote_on_none_executable_single_choice_proposal_with_multiple_optio let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -247,11 +232,7 @@ async fn test_vote_on_none_executable_single_choice_proposal_with_multiple_optio .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -267,7 +248,11 @@ async fn test_vote_on_none_executable_single_choice_proposal_with_multiple_optio .unwrap(); let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) .await .unwrap(); @@ -295,10 +280,10 @@ async fn test_vote_on_none_executable_single_choice_proposal_with_multiple_optio .await .unwrap(); - // Advance timestamp past max_voting_time + // Advance timestamp past voting_base_time governance_test .advance_clock_past_timestamp( - governance_cookie.account.config.max_voting_time as i64 + clock.unix_timestamp, + governance_cookie.account.config.voting_base_time as i64 + clock.unix_timestamp, ) .await; @@ -333,7 +318,6 @@ async fn test_vote_on_none_executable_multi_choice_proposal_with_multiple_option let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -341,11 +325,7 @@ async fn test_vote_on_none_executable_multi_choice_proposal_with_multiple_option .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -360,6 +340,8 @@ async fn test_vote_on_none_executable_multi_choice_proposal_with_multiple_option ], false, VoteType::MultiChoice { + choice_type: MultiChoiceType::FullWeight, + min_voter_options: 1, max_winning_options: 3, max_voter_options: 3, }, @@ -368,7 +350,11 @@ async fn test_vote_on_none_executable_multi_choice_proposal_with_multiple_option .unwrap(); let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie) + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie, + ) .await .unwrap(); @@ -400,10 +386,10 @@ async fn test_vote_on_none_executable_multi_choice_proposal_with_multiple_option .await .unwrap(); - // Advance timestamp past max_voting_time + // Advance timestamp past voting_base_time governance_test .advance_clock_past_timestamp( - governance_cookie.account.config.max_voting_time as i64 + clock.unix_timestamp, + governance_cookie.account.config.voting_base_time as i64 + clock.unix_timestamp, ) .await; @@ -443,7 +429,6 @@ async fn test_vote_on_executable_proposal_with_multiple_options_and_partial_succ let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; // 100 tokens let token_owner_record_cookie1 = governance_test @@ -470,7 +455,6 @@ async fn test_vote_on_executable_proposal_with_multiple_options_and_partial_succ let mut governance_cookie = governance_test .with_governance_using_config( &realm_cookie, - &governed_account_cookie, &token_owner_record_cookie1, &governance_config, ) @@ -488,6 +472,8 @@ async fn test_vote_on_executable_proposal_with_multiple_options_and_partial_succ ], true, VoteType::MultiChoice { + choice_type: MultiChoiceType::FullWeight, + min_voter_options: 1, max_winning_options: 3, max_voter_options: 3, }, @@ -496,7 +482,11 @@ async fn test_vote_on_executable_proposal_with_multiple_options_and_partial_succ .unwrap(); let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie1) + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie1, + ) .await .unwrap(); @@ -560,10 +550,10 @@ async fn test_vote_on_executable_proposal_with_multiple_options_and_partial_succ .await .unwrap(); - // Advance timestamp past max_voting_time + // Advance timestamp past voting_base_time governance_test .advance_clock_past_timestamp( - governance_cookie.account.config.max_voting_time as i64 + clock.unix_timestamp, + governance_cookie.account.config.voting_base_time as i64 + clock.unix_timestamp, ) .await; @@ -604,7 +594,6 @@ async fn test_execute_proposal_with_multiple_options_and_partial_success() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_mint_cookie = governance_test.with_governed_mint().await; // 100 tokens let token_owner_record_cookie1 = governance_test @@ -629,15 +618,16 @@ async fn test_execute_proposal_with_multiple_options_and_partial_success() { governance_config.community_vote_threshold = VoteThreshold::YesVotePercentage(30); let mut governance_cookie = governance_test - .with_mint_governance_using_config( + .with_governance_using_config( &realm_cookie, - &governed_mint_cookie, &token_owner_record_cookie1, &governance_config, ) .await .unwrap(); + let governed_mint_cookie = governance_test.with_governed_mint(&governance_cookie).await; + let mut proposal_cookie = governance_test .with_multi_option_proposal( &token_owner_record_cookie1, @@ -649,6 +639,8 @@ async fn test_execute_proposal_with_multiple_options_and_partial_success() { ], true, VoteType::MultiChoice { + choice_type: MultiChoiceType::FullWeight, + min_voter_options: 1, max_winning_options: 3, max_voter_options: 3, }, @@ -663,7 +655,6 @@ async fn test_execute_proposal_with_multiple_options_and_partial_success() { &token_owner_record_cookie1, 0, Some(0), - None, ) .await .unwrap(); @@ -675,7 +666,6 @@ async fn test_execute_proposal_with_multiple_options_and_partial_success() { &token_owner_record_cookie1, 1, Some(0), - None, ) .await .unwrap(); @@ -687,13 +677,16 @@ async fn test_execute_proposal_with_multiple_options_and_partial_success() { &token_owner_record_cookie1, 2, Some(0), - None, ) .await .unwrap(); let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie1) + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie1, + ) .await .unwrap(); @@ -753,9 +746,9 @@ async fn test_execute_proposal_with_multiple_options_and_partial_success() { .await .unwrap(); - // Advance timestamp past max_voting_time + // Advance timestamp past voting_base_time governance_test - .advance_clock_by_min_timespan(governance_cookie.account.config.max_voting_time as u64) + .advance_clock_by_min_timespan(governance_cookie.account.config.voting_base_time as u64) .await; governance_test @@ -765,7 +758,9 @@ async fn test_execute_proposal_with_multiple_options_and_partial_success() { // Advance timestamp past hold_up_time governance_test - .advance_clock_by_min_timespan(proposal_transaction_cookie1.account.hold_up_time as u64) + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) .await; let mut proposal_account = governance_test @@ -817,7 +812,6 @@ async fn test_try_execute_proposal_with_multiple_options_and_full_deny() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_mint_cookie = governance_test.with_governed_mint().await; // 100 tokens let token_owner_record_cookie1 = governance_test @@ -836,15 +830,16 @@ async fn test_try_execute_proposal_with_multiple_options_and_full_deny() { governance_config.community_vote_threshold = VoteThreshold::YesVotePercentage(30); let mut governance_cookie = governance_test - .with_mint_governance_using_config( + .with_governance_using_config( &realm_cookie, - &governed_mint_cookie, &token_owner_record_cookie1, &governance_config, ) .await .unwrap(); + let governed_mint_cookie = governance_test.with_governed_mint(&governance_cookie).await; + let mut proposal_cookie = governance_test .with_multi_option_proposal( &token_owner_record_cookie1, @@ -856,6 +851,8 @@ async fn test_try_execute_proposal_with_multiple_options_and_full_deny() { ], true, VoteType::MultiChoice { + choice_type: MultiChoiceType::FullWeight, + min_voter_options: 1, max_winning_options: 3, max_voter_options: 3, }, @@ -870,7 +867,6 @@ async fn test_try_execute_proposal_with_multiple_options_and_full_deny() { &token_owner_record_cookie1, 0, Some(0), - None, ) .await .unwrap(); @@ -882,7 +878,6 @@ async fn test_try_execute_proposal_with_multiple_options_and_full_deny() { &token_owner_record_cookie1, 1, Some(0), - None, ) .await .unwrap(); @@ -894,13 +889,16 @@ async fn test_try_execute_proposal_with_multiple_options_and_full_deny() { &token_owner_record_cookie1, 2, Some(0), - None, ) .await .unwrap(); let signatory_record_cookie = governance_test - .with_signatory(&proposal_cookie, &token_owner_record_cookie1) + .with_signatory( + &proposal_cookie, + &governance_cookie, + &token_owner_record_cookie1, + ) .await .unwrap(); @@ -919,9 +917,9 @@ async fn test_try_execute_proposal_with_multiple_options_and_full_deny() { .await .unwrap(); - // Advance timestamp past max_voting_time + // Advance timestamp past voting_base_time governance_test - .advance_clock_by_min_timespan(governance_cookie.account.config.max_voting_time as u64) + .advance_clock_by_min_timespan(governance_cookie.account.config.voting_base_time as u64) .await; governance_test @@ -931,7 +929,9 @@ async fn test_try_execute_proposal_with_multiple_options_and_full_deny() { // Advance timestamp past hold_up_time governance_test - .advance_clock_by_min_timespan(proposal_transaction_cookie1.account.hold_up_time as u64) + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) .await; let proposal_account = governance_test @@ -989,7 +989,6 @@ async fn test_create_proposal_with_10_options_and_cast_vote() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) @@ -997,18 +996,13 @@ async fn test_create_proposal_with_10_options_and_cast_vote() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); let options_count = 10; let options: Vec = (0..options_count) - .into_iter() .map(|n| format!("option {:?}", n)) .collect(); @@ -1021,6 +1015,8 @@ async fn test_create_proposal_with_10_options_and_cast_vote() { options, false, VoteType::MultiChoice { + choice_type: MultiChoiceType::FullWeight, + min_voter_options: 1, max_winning_options: options_len, max_voter_options: options_len, }, @@ -1035,7 +1031,6 @@ async fn test_create_proposal_with_10_options_and_cast_vote() { let vote = Vote::Approve( (0..options_count) - .into_iter() .map(|_| VoteChoice { rank: 0, weight_percentage: 100, @@ -1053,7 +1048,7 @@ async fn test_create_proposal_with_10_options_and_cast_vote() { governance_test .advance_clock_past_timestamp( - governance_cookie.account.config.max_voting_time as i64 + clock.unix_timestamp, + governance_cookie.account.config.voting_base_time as i64 + clock.unix_timestamp, ) .await; @@ -1071,11 +1066,678 @@ async fn test_create_proposal_with_10_options_and_cast_vote() { assert_eq!( proposal_account.vote_type, VoteType::MultiChoice { + choice_type: MultiChoiceType::FullWeight, + min_voter_options: 1, max_winning_options: options_len, max_voter_options: options_len, } ); - assert!(!proposal_account.deny_vote_weight.is_some()); + assert!(proposal_account.deny_vote_weight.is_none()); + + assert_eq!(ProposalState::Completed, proposal_account.state); +} + +#[tokio::test] +async fn test_vote_multi_weighted_choice_proposal_non_executable() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_config = governance_test.get_default_governance_config(); + governance_config.community_vote_threshold = VoteThreshold::YesVotePercentage(30); + + let mut governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie, + &governance_config, + ) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_multi_option_proposal( + &token_owner_record_cookie, + &mut governance_cookie, + vec![ + "option 1".to_string(), + "option 2".to_string(), + "option 3".to_string(), + "option 4".to_string(), + ], + false, + VoteType::MultiChoice { + choice_type: MultiChoiceType::Weighted, + min_voter_options: 1, + max_winning_options: 4, + max_voter_options: 4, + }, + ) + .await + .unwrap(); + + let clock = governance_test.bench.get_clock().await; + + governance_test + .sign_off_proposal_by_owner(&proposal_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + let vote = Vote::Approve(vec![ + VoteChoice { + rank: 0, + weight_percentage: 30, + }, + VoteChoice { + rank: 0, + weight_percentage: 29, + }, + VoteChoice { + rank: 0, + weight_percentage: 41, + }, + VoteChoice { + rank: 0, + weight_percentage: 0, + }, + ]); + + // Act + governance_test + .with_cast_vote(&proposal_cookie, &token_owner_record_cookie, vote) + .await + .unwrap(); + + governance_test + .advance_clock_past_timestamp( + governance_cookie.account.config.voting_base_time as i64 + clock.unix_timestamp, + ) + .await; + + governance_test + .finalize_vote(&realm_cookie, &proposal_cookie, None) + .await + .unwrap(); + + // Assert + let proposal_account = governance_test + .get_proposal_account(&proposal_cookie.address) + .await; + + assert_eq!( + OptionVoteResult::Succeeded, + proposal_account.options[0].vote_result + ); + assert_eq!( + OptionVoteResult::Defeated, + proposal_account.options[1].vote_result + ); + assert_eq!( + OptionVoteResult::Succeeded, + proposal_account.options[2].vote_result + ); + assert_eq!( + OptionVoteResult::Defeated, + proposal_account.options[3].vote_result + ); + assert_eq!( + (token_owner_record_cookie.token_source_amount as f32 * 0.3) as u64, + proposal_account.options[0].vote_weight + ); + assert_eq!( + (token_owner_record_cookie.token_source_amount as f32 * 0.29) as u64, + proposal_account.options[1].vote_weight + ); + assert_eq!( + (token_owner_record_cookie.token_source_amount as f32 * 0.41) as u64, + proposal_account.options[2].vote_weight + ); + assert_eq!(0_u64, proposal_account.options[3].vote_weight); + // None executable proposal transitions to Completed when vote is finalized assert_eq!(ProposalState::Completed, proposal_account.state); } + +#[tokio::test] +async fn test_vote_multi_weighted_choice_proposal_with_partial_success() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + // 100 tokens each, sum 300 tokens + let token_owner_record_cookie1 = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + let token_owner_record_cookie2 = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + let token_owner_record_cookie3 = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + // 60 tokes approval quorum as 20% of 300 is 60 + let mut governance_config = governance_test.get_default_governance_config(); + governance_config.community_vote_threshold = VoteThreshold::YesVotePercentage(20); + + let mut governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie1, + &governance_config, + ) + .await + .unwrap(); + + let governed_mint_cookie = governance_test.with_governed_mint(&governance_cookie).await; + + let mut proposal_cookie = governance_test + .with_multi_option_proposal( + &token_owner_record_cookie1, + &mut governance_cookie, + vec![ + "option 1".to_string(), + "option 2".to_string(), + "option 3".to_string(), + "option 4".to_string(), + ], + true, + VoteType::MultiChoice { + choice_type: MultiChoiceType::Weighted, + min_voter_options: 1, + max_winning_options: 4, + max_voter_options: 4, + }, + ) + .await + .unwrap(); + + let proposal_transaction_cookie1 = governance_test + .with_mint_tokens_transaction( + &governed_mint_cookie, + &mut proposal_cookie, + &token_owner_record_cookie1, + 0, + Some(0), + ) + .await + .unwrap(); + let proposal_transaction_cookie2 = governance_test + .with_mint_tokens_transaction( + &governed_mint_cookie, + &mut proposal_cookie, + &token_owner_record_cookie1, + 1, + Some(0), + ) + .await + .unwrap(); + let proposal_transaction_cookie3 = governance_test + .with_mint_tokens_transaction( + &governed_mint_cookie, + &mut proposal_cookie, + &token_owner_record_cookie1, + 2, + Some(0), + ) + .await + .unwrap(); + let proposal_transaction_cookie4 = governance_test + .with_mint_tokens_transaction( + &governed_mint_cookie, + &mut proposal_cookie, + &token_owner_record_cookie1, + 3, + Some(0), + ) + .await + .unwrap(); + + governance_test + .sign_off_proposal_by_owner(&proposal_cookie, &token_owner_record_cookie1) + .await + .unwrap(); + + // vote1: + // deny: 100 + // vote2 + vote3: + // choice 1: 0 -> Defeated + // choice 2: 91 -> Defeated (91 is over 60, 20% from 300, but deny overrules) + // choice 3: 101 -> Success + // choice 4: 8 -> Defeated (below of 60) + + let vote1 = Vote::Approve(vec![ + VoteChoice { + rank: 0, + weight_percentage: 0, + }, + VoteChoice { + rank: 0, + weight_percentage: 30, + }, + VoteChoice { + rank: 0, + weight_percentage: 70, + }, + VoteChoice { + rank: 0, + weight_percentage: 0, + }, + ]); + governance_test + .with_cast_vote(&proposal_cookie, &token_owner_record_cookie1, vote1) + .await + .expect("Voting the vote 1 of owner 1 should succeed"); + + let vote2 = Vote::Approve(vec![ + VoteChoice { + rank: 0, + weight_percentage: 0, + }, + VoteChoice { + rank: 0, + weight_percentage: 61, + }, + VoteChoice { + rank: 0, + weight_percentage: 31, + }, + VoteChoice { + rank: 0, + weight_percentage: 8, + }, + ]); + governance_test + .with_cast_vote(&proposal_cookie, &token_owner_record_cookie2, vote2) + .await + .expect("Voting the vote 1 of owner 1 should succeed"); + + governance_test + .with_cast_vote(&proposal_cookie, &token_owner_record_cookie3, Vote::Deny) + .await + .expect("Casting deny vote of owner 3 should succeed"); + + let clock = governance_test.bench.get_clock().await; + governance_test + .advance_clock_past_timestamp( + governance_cookie.account.config.voting_base_time as i64 + clock.unix_timestamp, + ) + .await; + governance_test + .finalize_vote(&realm_cookie, &proposal_cookie, None) + .await + .unwrap(); + // Advance timestamp past hold_up_time + governance_test + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) + .await; + + let mut proposal_account = governance_test + .get_proposal_account(&proposal_cookie.address) + .await; + + assert_eq!(ProposalState::Succeeded, proposal_account.state); + + // Act + let transaction1_err = governance_test + .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie1) + .await + .expect_err("Choice 1 should fail to execute, it hasn't got enough votes"); + let transaction2_err = governance_test + .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie2) + .await + .expect_err("Choice 2 should fail to execute, it hasn't got enough votes"); + governance_test + .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie3) + .await + .expect("Choice 3 should be executed as it won the poll"); + let transaction4_err = governance_test + .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie4) + .await + .expect_err("Choice 4 should be executed as the winner has been executed already"); + + // Assert + proposal_account = governance_test + .get_proposal_account(&proposal_cookie.address) + .await; + + assert_eq!(ProposalState::Completed, proposal_account.state); + + assert_eq!( + transaction1_err, + GovernanceError::CannotExecuteDefeatedOption.into() + ); + assert_eq!( + transaction2_err, + GovernanceError::CannotExecuteDefeatedOption.into() + ); + assert_eq!( + transaction4_err, + GovernanceError::InvalidStateCannotExecuteTransaction.into() + ); +} + +#[tokio::test] +async fn test_vote_multi_weighted_choice_proposal_with_multi_success() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + // 100 tokens each, sum 300 tokens + let token_owner_record_cookie1 = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + let token_owner_record_cookie2 = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + // 60 tokes approval quorum as 30% of 200 is 60 + let mut governance_config = governance_test.get_default_governance_config(); + governance_config.community_vote_threshold = VoteThreshold::YesVotePercentage(30); + + let mut governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie1, + &governance_config, + ) + .await + .unwrap(); + + let governed_mint_cookie = governance_test.with_governed_mint(&governance_cookie).await; + + let mut proposal_cookie = governance_test + .with_multi_option_proposal( + &token_owner_record_cookie1, + &mut governance_cookie, + vec![ + "option 1".to_string(), + "option 2".to_string(), + "option 3".to_string(), + ], + true, + VoteType::MultiChoice { + choice_type: MultiChoiceType::Weighted, + min_voter_options: 1, + max_winning_options: 3, + max_voter_options: 3, + }, + ) + .await + .unwrap(); + + let proposal_transaction_cookie1 = governance_test + .with_mint_tokens_transaction( + &governed_mint_cookie, + &mut proposal_cookie, + &token_owner_record_cookie1, + 0, + Some(0), + ) + .await + .unwrap(); + let proposal_transaction_cookie2 = governance_test + .with_mint_tokens_transaction( + &governed_mint_cookie, + &mut proposal_cookie, + &token_owner_record_cookie1, + 1, + Some(0), + ) + .await + .unwrap(); + let proposal_transaction_cookie3 = governance_test + .with_mint_tokens_transaction( + &governed_mint_cookie, + &mut proposal_cookie, + &token_owner_record_cookie1, + 2, + Some(0), + ) + .await + .unwrap(); + + governance_test + .sign_off_proposal_by_owner(&proposal_cookie, &token_owner_record_cookie1) + .await + .unwrap(); + + // vote1 + vote2: + // choice 1: 28 -> Defeated (below 60) + // choice 2: 105 -> Success + // choice 3: 61 -> Success + + let vote1 = Vote::Approve(vec![ + VoteChoice { + rank: 0, + weight_percentage: 14, + }, + VoteChoice { + rank: 0, + weight_percentage: 55, + }, + VoteChoice { + rank: 0, + weight_percentage: 31, + }, + ]); + governance_test + .with_cast_vote(&proposal_cookie, &token_owner_record_cookie1, vote1) + .await + .expect("Voting the vote 1 of owner 1 should succeed"); + + let vote2 = Vote::Approve(vec![ + VoteChoice { + rank: 0, + weight_percentage: 20, + }, + VoteChoice { + rank: 0, + weight_percentage: 50, + }, + VoteChoice { + rank: 0, + weight_percentage: 30, + }, + ]); + governance_test + .with_cast_vote(&proposal_cookie, &token_owner_record_cookie2, vote2) + .await + .expect("Voting the vote 1 of owner 1 should succeed"); + + // Advance timestamp past voting_base_time + let clock = governance_test.bench.get_clock().await; + governance_test + .advance_clock_past_timestamp( + governance_cookie.account.config.voting_base_time as i64 + clock.unix_timestamp, + ) + .await; + governance_test + .finalize_vote(&realm_cookie, &proposal_cookie, None) + .await + .unwrap(); + // Advance timestamp past hold_up_time + governance_test + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) + .await; + + let mut proposal_account = governance_test + .get_proposal_account(&proposal_cookie.address) + .await; + + assert_eq!(ProposalState::Succeeded, proposal_account.state); + + // Act + let transaction1_err = governance_test + .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie1) + .await + .expect_err("Choice 1 should fail to execute, it hasn't got enough votes"); + governance_test + .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie2) + .await + .expect("Choice 2 should be executed as it passed the poll"); + governance_test + .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie3) + .await + .expect("Choice 3 should be executed as it passed the poll"); + + // Assert + proposal_account = governance_test + .get_proposal_account(&proposal_cookie.address) + .await; + + assert_eq!(ProposalState::Completed, proposal_account.state); + + assert_eq!( + transaction1_err, + GovernanceError::CannotExecuteDefeatedOption.into() + ); +} + +#[tokio::test] +async fn test_vote_multi_weighted_choice_proposal_executable_with_full_deny() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + // 100 tokens + let token_owner_record_cookie1 = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + // 100 tokens + let token_owner_record_cookie2 = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let mut governance_config = governance_test.get_default_governance_config(); + governance_config.community_vote_threshold = VoteThreshold::YesVotePercentage(3); + + let mut governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie1, + &governance_config, + ) + .await + .unwrap(); + + let governed_mint_cookie = governance_test.with_governed_mint(&governance_cookie).await; + + let mut proposal_cookie = governance_test + .with_multi_option_proposal( + &token_owner_record_cookie1, + &mut governance_cookie, + vec!["option 1".to_string(), "option 2".to_string()], + true, + VoteType::MultiChoice { + choice_type: MultiChoiceType::Weighted, + min_voter_options: 1, + max_winning_options: 2, + max_voter_options: 2, + }, + ) + .await + .unwrap(); + + let proposal_transaction_cookie1 = governance_test + .with_mint_tokens_transaction( + &governed_mint_cookie, + &mut proposal_cookie, + &token_owner_record_cookie1, + 0, + Some(0), + ) + .await + .unwrap(); + + let proposal_transaction_cookie2 = governance_test + .with_mint_tokens_transaction( + &governed_mint_cookie, + &mut proposal_cookie, + &token_owner_record_cookie1, + 1, + Some(0), + ) + .await + .unwrap(); + + governance_test + .sign_off_proposal_by_owner(&proposal_cookie, &token_owner_record_cookie1) + .await + .unwrap(); + + governance_test + .with_cast_vote(&proposal_cookie, &token_owner_record_cookie1, Vote::Deny) + .await + .expect("Casting deny vote for owner 1 should succeed"); + governance_test + .with_cast_vote(&proposal_cookie, &token_owner_record_cookie2, Vote::Deny) + .await + .expect("Casting deny vote for owner 1 should succeed"); + + // Advance timestamp past voting_base_time + let clock = governance_test.bench.get_clock().await; + governance_test + .advance_clock_past_timestamp( + governance_cookie.account.config.voting_base_time as i64 + clock.unix_timestamp, + ) + .await; + + governance_test + .finalize_vote(&realm_cookie, &proposal_cookie, None) + .await + .unwrap(); + + // Advance timestamp past hold_up_time + governance_test + .advance_clock_by_min_timespan( + governance_cookie.account.config.transactions_hold_up_time as u64, + ) + .await; + + let proposal_account = governance_test + .get_proposal_account(&proposal_cookie.address) + .await; + + assert_eq!(ProposalState::Defeated, proposal_account.state); + + // Act + let transaction1_err = governance_test + .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie1) + .await + .expect_err("The proposal was denied, error on choice 1 execution expected"); + let transaction2_err = governance_test + .execute_proposal_transaction(&proposal_cookie, &proposal_transaction_cookie2) + .await + .expect_err("The proposal was denied, error on choice 2 execution expected"); + + // Assert + assert_eq!( + transaction1_err, + GovernanceError::InvalidStateCannotExecuteTransaction.into() + ); + assert_eq!( + transaction2_err, + GovernanceError::InvalidStateCannotExecuteTransaction.into() + ); +} diff --git a/governance/program/tests/use_realm_with_all_addins.rs b/governance/program/tests/use_realm_with_all_addins.rs index ab566a230f6..ac2e0858832 100644 --- a/governance/program/tests/use_realm_with_all_addins.rs +++ b/governance/program/tests/use_realm_with_all_addins.rs @@ -1,18 +1,22 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] use solana_program_test::*; mod program_test; -use program_test::*; -use spl_governance::state::enums::ProposalState; +use { + program_test::{args::*, *}, + spl_governance::state::enums::ProposalState, +}; #[tokio::test] -async fn test_cast_vote_with_all_addin() { +async fn test_cast_community_vote_with_all_addin() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_all_addins().await; - let realm_cookie = governance_test.with_realm().await; + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::ALL) + .await; let mut token_owner_record_cookie = governance_test .with_community_token_owner_record(&realm_cookie) @@ -30,14 +34,64 @@ async fn test_cast_vote_with_all_addin() { .await .unwrap(); - let governed_account_cookie = governance_test.with_governed_account().await; + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_signed_off_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + // Act + + let vote_record_cookie = governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + // Assert + let vote_record_account = governance_test + .get_vote_record_account(&vote_record_cookie.address) + .await; + + assert_eq!(120, vote_record_account.voter_weight); + + let proposal_account = governance_test + .get_proposal_account(&proposal_cookie.address) + .await; + + assert_eq!(proposal_account.state, ProposalState::Voting) +} + +#[tokio::test] +async fn test_cast_council_vote_with_all_addin() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_with_all_addins().await; + + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::ALL) + .await; + + let mut token_owner_record_cookie = governance_test + .with_council_token_owner_record(&realm_cookie) + .await; + + // voter weight 120 + governance_test + .with_voter_weight_addin_record(&mut token_owner_record_cookie) + .await + .unwrap(); + + // max voter weight 250 + governance_test + .with_max_voter_weight_addin_record_impl(&mut token_owner_record_cookie, 250, None) + .await + .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -72,7 +126,9 @@ async fn test_tip_vote_with_all_addin() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_all_addins().await; - let realm_cookie = governance_test.with_realm().await; + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::ALL) + .await; let mut token_owner_record_cookie = governance_test .with_community_token_owner_record(&realm_cookie) @@ -90,14 +146,8 @@ async fn test_tip_vote_with_all_addin() { .await .unwrap(); - let governed_account_cookie = governance_test.with_governed_account().await; - let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -132,7 +182,9 @@ async fn test_finalize_vote_with_all_addin() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_all_addins().await; - let realm_cookie = governance_test.with_realm().await; + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::ALL) + .await; let mut token_owner_record_cookie = governance_test .with_community_token_owner_record(&realm_cookie) @@ -150,14 +202,8 @@ async fn test_finalize_vote_with_all_addin() { .await .unwrap(); - let governed_account_cookie = governance_test.with_governed_account().await; - let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); diff --git a/governance/program/tests/use_realm_with_max_voter_weight_addin.rs b/governance/program/tests/use_realm_with_max_voter_weight_addin.rs index 75df30e8743..511952844e2 100644 --- a/governance/program/tests/use_realm_with_max_voter_weight_addin.rs +++ b/governance/program/tests/use_realm_with_max_voter_weight_addin.rs @@ -1,19 +1,22 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] use solana_program_test::*; mod program_test; -use program_test::*; -use spl_governance::{error::GovernanceError, state::enums::ProposalState}; +use { + program_test::{args::*, *}, + spl_governance::{error::GovernanceError, state::enums::ProposalState}, +}; #[tokio::test] -async fn test_cast_vote_with_max_voter_weight_addin() { +async fn test_cast_vote_with_community_max_voter_weight_addin() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await; - let governed_account_cookie = governance_test.with_governed_account().await; - let realm_cookie = governance_test.with_realm().await; + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::COMMUNITY_MAX_VOTER_WEIGHT) + .await; // TokenOwnerRecord with voting power of 100 let mut token_owner_record_cookie = governance_test @@ -28,11 +31,53 @@ async fn test_cast_vote_with_max_voter_weight_addin() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_signed_off_proposal(&token_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + // Act + governance_test + .with_cast_yes_no_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes) + .await + .unwrap(); + + // Assert + + let proposal_account = governance_test + .get_proposal_account(&proposal_cookie.address) + .await; + + assert_eq!(proposal_account.state, ProposalState::Voting) +} + +#[tokio::test] +async fn test_cast_vote_with_council_max_voter_weight_addin() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await; + + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::COUNCIL_MAX_VOTER_WEIGHT) + .await; + + // TokenOwnerRecord with voting power of 100 + let mut token_owner_record_cookie = governance_test + .with_council_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Bump MaxVoterWeight to 200 + governance_test + .with_max_voter_weight_addin_record(&mut token_owner_record_cookie) + .await + .unwrap(); + + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -60,9 +105,10 @@ async fn test_cast_vote_with_max_voter_weight_addin() { async fn test_tip_vote_with_max_voter_weight_addin() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await; - let governed_account_cookie = governance_test.with_governed_account().await; - let realm_cookie = governance_test.with_realm().await; + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::COMMUNITY_MAX_VOTER_WEIGHT) + .await; // TokenOwnerRecord with voting power of 180 let mut token_owner_record_cookie = governance_test @@ -77,11 +123,7 @@ async fn test_tip_vote_with_max_voter_weight_addin() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -110,9 +152,10 @@ async fn test_tip_vote_with_max_voter_weight_addin() { async fn test_tip_vote_with_max_voter_weight_addin_and_max_below_total_cast_votes() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await; - let governed_account_cookie = governance_test.with_governed_account().await; - let realm_cookie = governance_test.with_realm().await; + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::COMMUNITY_MAX_VOTER_WEIGHT) + .await; // TokenOwnerRecord with voting power of 100 let mut token_owner_record_cookie = governance_test @@ -127,11 +170,7 @@ async fn test_tip_vote_with_max_voter_weight_addin_and_max_below_total_cast_vote .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -153,16 +192,18 @@ async fn test_tip_vote_with_max_voter_weight_addin_and_max_below_total_cast_vote .await; assert_eq!(proposal_account.state, ProposalState::Succeeded); - assert_eq!(proposal_account.max_vote_weight, Some(100)); // Adjusted max based on cast votes + // Adjusted max based on cast votes + assert_eq!(proposal_account.max_vote_weight, Some(100)); } #[tokio::test] async fn test_finalize_vote_with_max_voter_weight_addin() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await; - let governed_account_cookie = governance_test.with_governed_account().await; - let realm_cookie = governance_test.with_realm().await; + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::COMMUNITY_MAX_VOTER_WEIGHT) + .await; // TokenOwnerRecord with voting power of 100 let mut token_owner_record_cookie = governance_test @@ -177,11 +218,7 @@ async fn test_finalize_vote_with_max_voter_weight_addin() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -231,9 +268,10 @@ async fn test_finalize_vote_with_max_voter_weight_addin() { async fn test_finalize_vote_with_max_voter_weight_addin_and_max_below_total_cast_votes() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await; - let governed_account_cookie = governance_test.with_governed_account().await; - let realm_cookie = governance_test.with_realm().await; + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::COMMUNITY_MAX_VOTER_WEIGHT) + .await; // TokenOwnerRecord with voting power of 100 let mut token_owner_record_cookie = governance_test @@ -248,11 +286,7 @@ async fn test_finalize_vote_with_max_voter_weight_addin_and_max_below_total_cast .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -295,16 +329,18 @@ async fn test_finalize_vote_with_max_voter_weight_addin_and_max_below_total_cast .await; assert_eq!(proposal_account.state, ProposalState::Succeeded); - assert_eq!(proposal_account.max_vote_weight, Some(100)); // Adjusted max based on cast votes + // Adjusted max based on cast votes + assert_eq!(proposal_account.max_vote_weight, Some(100)); } #[tokio::test] async fn test_cast_vote_with_max_voter_weight_addin_and_expired_record_error() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await; - let governed_account_cookie = governance_test.with_governed_account().await; - let realm_cookie = governance_test.with_realm().await; + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::COMMUNITY_MAX_VOTER_WEIGHT) + .await; // TokenOwnerRecord with voting power of 100 let mut token_owner_record_cookie = governance_test @@ -319,11 +355,7 @@ async fn test_cast_vote_with_max_voter_weight_addin_and_expired_record_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); diff --git a/governance/program/tests/use_realm_with_voter_weight_addin.rs b/governance/program/tests/use_realm_with_voter_weight_addin.rs index 08ba5c423e2..dd66b868aca 100644 --- a/governance/program/tests/use_realm_with_voter_weight_addin.rs +++ b/governance/program/tests/use_realm_with_voter_weight_addin.rs @@ -1,24 +1,26 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] -use solana_program::pubkey::Pubkey; -use solana_program_test::*; +use {solana_program::pubkey::Pubkey, solana_program_test::*}; mod program_test; -use program_test::*; -use spl_governance::{ - error::GovernanceError, - state::vote_record::{Vote, VoteChoice}, +use { + program_test::{args::*, *}, + spl_governance::{ + error::GovernanceError, + state::vote_record::{Vote, VoteChoice}, + }, + spl_governance_addin_api::voter_weight::VoterWeightAction, }; -use spl_governance_addin_api::voter_weight::VoterWeightAction; #[tokio::test] -async fn test_create_governance_with_voter_weight_addin() { +async fn test_create_governance_with_community_voter_weight_addin() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await; - let governed_account_cookie = governance_test.with_governed_account().await; - let realm_cookie = governance_test.with_realm().await; + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT) + .await; let mut token_owner_record_cookie = governance_test .with_community_token_owner_record(&realm_cookie) @@ -31,11 +33,39 @@ async fn test_create_governance_with_voter_weight_addin() { // Act let governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + // // Assert + let governance_account = governance_test + .get_governance_account(&governance_cookie.address) + .await; + + assert_eq!(governance_cookie.account, governance_account); +} + +#[tokio::test] +async fn test_create_governance_with_council_voter_weight_addin() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await; + + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::COUNCIL_VOTER_WEIGHT) + .await; + + let mut token_owner_record_cookie = governance_test + .with_council_token_owner_record(&realm_cookie) + .await; + + governance_test + .with_voter_weight_addin_record(&mut token_owner_record_cookie) + .await + .unwrap(); + + // Act + let governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -51,9 +81,10 @@ async fn test_create_governance_with_voter_weight_addin() { async fn test_create_proposal_with_voter_weight_addin() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await; - let governed_account_cookie = governance_test.with_governed_account().await; - let realm_cookie = governance_test.with_realm().await; + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT) + .await; let mut token_owner_record_cookie = governance_test .with_community_token_owner_record(&realm_cookie) @@ -65,11 +96,7 @@ async fn test_create_proposal_with_voter_weight_addin() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -91,9 +118,10 @@ async fn test_create_proposal_with_voter_weight_addin() { async fn test_cast_vote_with_voter_weight_addin() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await; - let governed_account_cookie = governance_test.with_governed_account().await; - let realm_cookie = governance_test.with_realm().await; + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT) + .await; let mut token_owner_record_cookie = governance_test .with_community_token_owner_record(&realm_cookie) @@ -105,11 +133,7 @@ async fn test_cast_vote_with_voter_weight_addin() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -150,9 +174,10 @@ async fn test_cast_vote_with_voter_weight_addin() { async fn test_create_token_governance_with_voter_weight_addin() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await; - let governed_token_cookie = governance_test.with_governed_token().await; - let realm_cookie = governance_test.with_realm().await; + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT) + .await; let mut token_owner_record_cookie = governance_test .with_community_token_owner_record(&realm_cookie) @@ -164,66 +189,28 @@ async fn test_create_token_governance_with_voter_weight_addin() { .unwrap(); // Act - let token_governance_cookie = governance_test - .with_token_governance( - &realm_cookie, - &governed_token_cookie, - &token_owner_record_cookie, - ) + let governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); // // Assert let token_governance_account = governance_test - .get_governance_account(&token_governance_cookie.address) + .get_governance_account(&governance_cookie.address) .await; - assert_eq!(token_governance_cookie.account, token_governance_account); + assert_eq!(governance_cookie.account, token_governance_account); } #[tokio::test] -async fn test_create_mint_governance_with_voter_weight_addin() { +async fn test_create_governance_with_voter_weight_addin() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await; - let governed_mint_cookie = governance_test.with_governed_mint().await; - - let realm_cookie = governance_test.with_realm().await; - let mut token_owner_record_cookie = governance_test - .with_community_token_owner_record(&realm_cookie) + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT) .await; - governance_test - .with_voter_weight_addin_record(&mut token_owner_record_cookie) - .await - .unwrap(); - - // Act - let mint_governance_cookie = governance_test - .with_mint_governance( - &realm_cookie, - &governed_mint_cookie, - &token_owner_record_cookie, - ) - .await - .unwrap(); - - // // Assert - let mint_governance_account = governance_test - .get_governance_account(&mint_governance_cookie.address) - .await; - - assert_eq!(mint_governance_cookie.account, mint_governance_account); -} - -#[tokio::test] -async fn test_create_program_governance_with_voter_weight_addin() { - // Arrange - let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await; - let governed_program_cookie = governance_test.with_governed_program().await; - - let realm_cookie = governance_test.with_realm().await; - let mut token_owner_record_cookie = governance_test .with_community_token_owner_record(&realm_cookie) .await; @@ -234,33 +221,27 @@ async fn test_create_program_governance_with_voter_weight_addin() { .unwrap(); // Act - let program_governance_cookie = governance_test - .with_program_governance( - &realm_cookie, - &governed_program_cookie, - &token_owner_record_cookie, - ) + let governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); - // Assert - let program_governance_account = governance_test - .get_governance_account(&program_governance_cookie.address) + // // Assert + let governance_account = governance_test + .get_governance_account(&governance_cookie.address) .await; - assert_eq!( - program_governance_cookie.account, - program_governance_account - ); + assert_eq!(governance_cookie.account, governance_account); } #[tokio::test] async fn test_create_governance_with_voter_weight_action_error() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await; - let governed_account_cookie = governance_test.with_governed_account().await; - let realm_cookie = governance_test.with_realm().await; + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT) + .await; let mut token_owner_record_cookie = governance_test .with_community_token_owner_record(&realm_cookie) @@ -279,11 +260,7 @@ async fn test_create_governance_with_voter_weight_action_error() { // Act let err = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .err() .unwrap(); @@ -296,9 +273,10 @@ async fn test_create_governance_with_voter_weight_action_error() { async fn test_create_governance_with_voter_weight_expiry_error() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await; - let governed_account_cookie = governance_test.with_governed_account().await; - let realm_cookie = governance_test.with_realm().await; + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT) + .await; let mut token_owner_record_cookie = governance_test .with_community_token_owner_record(&realm_cookie) @@ -319,11 +297,7 @@ async fn test_create_governance_with_voter_weight_expiry_error() { // Act let err = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .err() .unwrap(); @@ -336,9 +310,10 @@ async fn test_create_governance_with_voter_weight_expiry_error() { async fn test_cast_vote_with_voter_weight_action_error() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await; - let governed_account_cookie = governance_test.with_governed_account().await; - let realm_cookie = governance_test.with_realm().await; + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT) + .await; let mut token_owner_record_cookie = governance_test .with_community_token_owner_record(&realm_cookie) @@ -350,11 +325,7 @@ async fn test_cast_vote_with_voter_weight_action_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -392,9 +363,10 @@ async fn test_cast_vote_with_voter_weight_action_error() { async fn test_create_governance_with_voter_weight_action_target_error() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await; - let governed_account_cookie = governance_test.with_governed_account().await; - let realm_cookie = governance_test.with_realm().await; + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT) + .await; let mut token_owner_record_cookie = governance_test .with_community_token_owner_record(&realm_cookie) @@ -415,11 +387,7 @@ async fn test_create_governance_with_voter_weight_action_target_error() { // Act let err = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .err() .unwrap(); @@ -435,9 +403,10 @@ async fn test_create_governance_with_voter_weight_action_target_error() { async fn test_create_proposal_with_voter_weight_action_error() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await; - let governed_account_cookie = governance_test.with_governed_account().await; - let realm_cookie = governance_test.with_realm().await; + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT) + .await; let mut token_owner_record_cookie = governance_test .with_community_token_owner_record(&realm_cookie) @@ -455,11 +424,7 @@ async fn test_create_proposal_with_voter_weight_action_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -479,9 +444,10 @@ async fn test_create_proposal_with_voter_weight_action_error() { async fn test_create_governance_with_voter_weight_record() { // Arrange let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await; - let governed_account_cookie = governance_test.with_governed_account().await; - let realm_cookie = governance_test.with_realm().await; + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT) + .await; let mut token_owner_record_cookie = governance_test .with_community_token_owner_record(&realm_cookie) @@ -503,11 +469,7 @@ async fn test_create_governance_with_voter_weight_record() { // Act let governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); diff --git a/governance/program/tests/use_veto_vote.rs b/governance/program/tests/use_veto_vote.rs index 2b80a3ffb7b..8c40f221ff5 100644 --- a/governance/program/tests/use_veto_vote.rs +++ b/governance/program/tests/use_veto_vote.rs @@ -1,29 +1,27 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] mod program_test; - -use solana_program::instruction::AccountMeta; -use solana_program_test::tokio; - -use program_test::*; -use spl_governance::{ - error::GovernanceError, - state::{ - enums::{ProposalState, VoteThreshold}, - vote_record::Vote, +use { + crate::program_test::args::{PluginSetupArgs, RealmSetupArgs}, + program_test::*, + solana_program::instruction::AccountMeta, + solana_program_test::tokio, + spl_governance::{ + error::GovernanceError, + state::{ + enums::{ProposalState, VoteThreshold}, + vote_record::Vote, + }, }, + spl_governance_test_sdk::tools::clone_keypair, }; -use spl_governance_test_sdk::tools::clone_keypair; - -use self::args::SetRealmConfigArgs; #[tokio::test] -async fn test_cast_veto_vote() { +async fn test_cast_council_veto_vote() { // Arrange let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_council_token_deposit(&realm_cookie) @@ -34,11 +32,7 @@ async fn test_cast_veto_vote() { governance_test.mint_council_tokens(&realm_cookie, 20).await; let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -95,39 +89,98 @@ async fn test_cast_veto_vote() { .await; assert_eq!(1, token_owner_record.unrelinquished_votes_count); - assert_eq!(1, token_owner_record.total_votes_count); +} + +#[tokio::test] +async fn test_cast_community_veto_vote() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Mint extra community tokens for total supply of 120 + governance_test + .mint_community_tokens(&realm_cookie, 20) + .await; + + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + let proposal_owner_record_cookie = governance_test + .with_council_token_deposit(&realm_cookie) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_signed_off_proposal(&proposal_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); - let realm_account = governance_test - .get_realm_account(&realm_cookie.address) + // Act + let vote_record_cookie = governance_test + .with_cast_vote(&proposal_cookie, &token_owner_record_cookie, Vote::Veto) + .await + .unwrap(); + + // Assert + let vote_record_account = governance_test + .get_vote_record_account(&vote_record_cookie.address) .await; - assert_eq!(0, realm_account.voting_proposal_count); + assert_eq!(vote_record_cookie.account, vote_record_account); - let governance_account = governance_test - .get_governance_account(&governance_cookie.address) + let proposal_account = governance_test + .get_proposal_account(&proposal_cookie.address) .await; - assert_eq!(0, governance_account.voting_proposal_count); + assert_eq!( + token_owner_record_cookie + .account + .governing_token_deposit_amount, + proposal_account.veto_vote_weight + ); + + assert_eq!(proposal_account.state, ProposalState::Vetoed); + + assert_eq!(Some(120), proposal_account.max_vote_weight); + assert_eq!( + Some( + governance_cookie + .account + .config + .community_veto_vote_threshold + ), + proposal_account.vote_threshold + ); } #[tokio::test] -async fn test_cast_veto_vote_with_community_not_allowed_to_vote_error() { +async fn test_cast_community_veto_vote_with_community_veto_disabled_error() { // Arrange let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_community_token_deposit(&realm_cookie) .await .unwrap(); + let mut governance_config = governance_test.get_default_governance_config(); + governance_config.community_veto_vote_threshold = VoteThreshold::Disabled; + let mut governance_cookie = governance_test - .with_governance( + .with_governance_using_config( &realm_cookie, - &governed_account_cookie, &token_owner_record_cookie, + &governance_config, ) .await .unwrap(); @@ -162,7 +215,6 @@ async fn test_cast_veto_vote_with_invalid_voting_mint_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_council_token_deposit(&realm_cookie) @@ -170,11 +222,7 @@ async fn test_cast_veto_vote_with_invalid_voting_mint_error() { .unwrap(); let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -207,7 +255,6 @@ async fn test_cast_veto_vote_with_council_veto_vote_disabled_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_council_token_deposit(&realm_cookie) @@ -220,7 +267,6 @@ async fn test_cast_veto_vote_with_council_veto_vote_disabled_error() { let mut governance_cookie = governance_test .with_governance_using_config( &realm_cookie, - &governed_account_cookie, &token_owner_record_cookie, &governance_config, ) @@ -257,7 +303,6 @@ async fn test_cast_veto_vote_without_tipping() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_council_token_deposit(&realm_cookie) @@ -270,11 +315,7 @@ async fn test_cast_veto_vote_without_tipping() { .await; let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -321,7 +362,6 @@ async fn test_cast_multiple_veto_votes_for_partially_approved_proposal() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_council_token_deposit(&realm_cookie) @@ -333,15 +373,12 @@ async fn test_cast_multiple_veto_votes_for_partially_approved_proposal() { .await .unwrap(); - // Mint extra council tokens for total supply of 210 to prevent single vote tipping + // Mint extra council tokens for total supply of 210 to prevent single vote + // tipping governance_test.mint_council_tokens(&realm_cookie, 10).await; let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -350,7 +387,8 @@ async fn test_cast_multiple_veto_votes_for_partially_approved_proposal() { .await .unwrap(); - // Mint extra council tokens for total supply of 200 to prevent single vote tipping + // Mint extra council tokens for total supply of 200 to prevent single vote + // tipping governance_test .mint_community_tokens(&realm_cookie, 100) .await; @@ -400,7 +438,6 @@ async fn test_cast_veto_vote_with_no_council_error() { let mut governance_test = GovernanceProgramTest::start_new().await; let mut realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_council_token_deposit(&realm_cookie) @@ -413,7 +450,6 @@ async fn test_cast_veto_vote_with_no_council_error() { let mut governance_cookie = governance_test .with_governance_using_config( &realm_cookie, - &governed_account_cookie, &token_owner_record_cookie, &governance_config, ) @@ -431,11 +467,13 @@ async fn test_cast_veto_vote_with_no_council_error() { .unwrap(); // Remove Council - let mut set_realm_config_args = SetRealmConfigArgs::default(); - set_realm_config_args.realm_config_args.use_council_mint = false; + let realm_setup_args = RealmSetupArgs { + use_council_mint: false, + ..Default::default() + }; governance_test - .set_realm_config(&mut realm_cookie, &set_realm_config_args) + .set_realm_config(&mut realm_cookie, &realm_setup_args) .await .unwrap(); @@ -456,7 +494,6 @@ async fn test_relinquish_veto_vote() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_council_token_deposit(&realm_cookie) @@ -469,11 +506,7 @@ async fn test_relinquish_veto_vote() { .await; let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -514,7 +547,6 @@ async fn test_relinquish_veto_vote_with_vote_record_for_different_voting_mint_er let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let council_token_owner_record_cookie = governance_test .with_council_token_deposit(&realm_cookie) @@ -527,11 +559,7 @@ async fn test_relinquish_veto_vote_with_vote_record_for_different_voting_mint_er .await; let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &council_token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &council_token_owner_record_cookie) .await .unwrap(); @@ -554,7 +582,8 @@ async fn test_relinquish_veto_vote_with_vote_record_for_different_voting_mint_er .await .unwrap(); - // Create Community TokenOwnerRecord for council_token_owner and Cast Community vote + // Create Community TokenOwnerRecord for council_token_owner and Cast Community + // vote let community_token_owner_record_cookie = governance_test .with_community_token_deposit_by_owner( &realm_cookie, @@ -585,7 +614,8 @@ async fn test_relinquish_veto_vote_with_vote_record_for_different_voting_mint_er &proposal_cookie, &council_token_owner_record_cookie, |i| { - // Try to use a vote_record from community Yes vote to relinquish council Veto vote + // Try to use a vote_record from community Yes vote to relinquish council Veto + // vote i.accounts[4] = AccountMeta::new(community_vote_record_cookie.address, false) }, ) @@ -604,7 +634,6 @@ async fn test_cast_veto_vote_with_council_only_allowed_to_veto() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_council_token_deposit(&realm_cookie) @@ -618,7 +647,6 @@ async fn test_cast_veto_vote_with_council_only_allowed_to_veto() { let mut governance_cookie = governance_test .with_governance_using_config( &realm_cookie, - &governed_account_cookie, &token_owner_record_cookie, &governance_config, ) @@ -655,24 +683,20 @@ async fn test_cast_yes_and_veto_votes_with_yes_as_winning_vote() { let mut governance_test = GovernanceProgramTest::start_new().await; let realm_cookie = governance_test.with_realm().await; - let governed_account_cookie = governance_test.with_governed_account().await; let token_owner_record_cookie = governance_test .with_council_token_deposit(&realm_cookie) .await .unwrap(); - // Mint extra council tokens for total supply of 210 to prevent single vote tipping + // Mint extra council tokens for total supply of 210 to prevent single vote + // tipping governance_test .mint_council_tokens(&realm_cookie, 110) .await; let mut governance_cookie = governance_test - .with_governance( - &realm_cookie, - &governed_account_cookie, - &token_owner_record_cookie, - ) + .with_governance(&realm_cookie, &token_owner_record_cookie) .await .unwrap(); @@ -715,5 +739,227 @@ async fn test_cast_yes_and_veto_votes_with_yes_as_winning_vote() { assert_eq!(proposal_account.state, ProposalState::Succeeded); } -// TODO: Once Veto for Community or plugin support for Council is implemented write Veto tests with plugin -// The tests should cover scenarios where Veto voter_weight and/or max_voter_weight is resolved using the plugins +#[tokio::test] +async fn test_veto_vote_with_community_voter_weight_addin() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_with_voter_weight_addin().await; + + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::COMMUNITY_VOTER_WEIGHT) + .await; + + let mut token_owner_record_cookie = governance_test + .with_community_token_owner_record(&realm_cookie) + .await; + + governance_test + .with_voter_weight_addin_record(&mut token_owner_record_cookie) + .await + .unwrap(); + + let mut governance_cookie = governance_test + .with_governance(&realm_cookie, &token_owner_record_cookie) + .await + .unwrap(); + + // Create Proposal for Council vote + let proposal_owner_record_cookie = governance_test + .with_council_token_deposit(&realm_cookie) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_signed_off_proposal(&proposal_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + // Act + governance_test + .with_cast_vote(&proposal_cookie, &token_owner_record_cookie, Vote::Veto) + .await + .unwrap(); + + // Assert + let proposal_account = governance_test + .get_proposal_account(&proposal_cookie.address) + .await; + + assert_eq!(proposal_account.state, ProposalState::Vetoed); +} + +#[tokio::test] +async fn test_veto_vote_with_community_max_voter_weight_addin() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await; + + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::COMMUNITY_MAX_VOTER_WEIGHT) + .await; + + // TokenOwnerRecord with voting power of 100 + let mut token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Bump MaxVoterWeight to 200 + governance_test + .with_max_voter_weight_addin_record(&mut token_owner_record_cookie) + .await + .unwrap(); + + let mut governance_config = governance_test.get_default_governance_config(); + governance_config.community_veto_vote_threshold = VoteThreshold::YesVotePercentage(50); // 50% Veto + + let mut governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie, + &governance_config, + ) + .await + .unwrap(); + + // Create Proposal for Council vote + let proposal_owner_record_cookie = governance_test + .with_council_token_deposit(&realm_cookie) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_signed_off_proposal(&proposal_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + // Act + governance_test + .with_cast_vote(&proposal_cookie, &token_owner_record_cookie, Vote::Veto) + .await + .unwrap(); + + // Assert + let proposal_account = governance_test + .get_proposal_account(&proposal_cookie.address) + .await; + + assert_eq!(proposal_account.state, ProposalState::Vetoed); +} + +#[tokio::test] +async fn test_veto_vote_with_community_max_voter_weight_addin_and_veto_not_tipped() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_with_max_voter_weight_addin().await; + + let realm_cookie = governance_test + .with_realm_using_addins(PluginSetupArgs::COMMUNITY_MAX_VOTER_WEIGHT) + .await; + + // TokenOwnerRecord with voting power of 100 + let mut token_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Bump MaxVoterWeight to 200 + governance_test + .with_max_voter_weight_addin_record(&mut token_owner_record_cookie) + .await + .unwrap(); + + let mut governance_config = governance_test.get_default_governance_config(); + governance_config.community_veto_vote_threshold = VoteThreshold::YesVotePercentage(51); // 51% Veto + + let mut governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie, + &governance_config, + ) + .await + .unwrap(); + + // Create Proposal for Council vote + let proposal_owner_record_cookie = governance_test + .with_council_token_deposit(&realm_cookie) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_signed_off_proposal(&proposal_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + // Act + governance_test + .with_cast_vote(&proposal_cookie, &token_owner_record_cookie, Vote::Veto) + .await + .unwrap(); + + // Assert + let proposal_account = governance_test + .get_proposal_account(&proposal_cookie.address) + .await; + + assert_eq!(proposal_account.state, ProposalState::Voting); +} + +#[tokio::test] +async fn test_cast_council_veto_vote_within_cool_off_time() { + // Arrange + let mut governance_test = GovernanceProgramTest::start_new().await; + + let realm_cookie = governance_test.with_realm().await; + + let token_owner_record_cookie = governance_test + .with_council_token_deposit(&realm_cookie) + .await + .unwrap(); + + // Mint extra council tokens for total supply of 120 + governance_test.mint_council_tokens(&realm_cookie, 20).await; + + // Set none default voting cool off time + let mut governance_config = governance_test.get_default_governance_config(); + governance_config.voting_cool_off_time = 50; + + let mut governance_cookie = governance_test + .with_governance_using_config( + &realm_cookie, + &token_owner_record_cookie, + &governance_config, + ) + .await + .unwrap(); + + let proposal_owner_record_cookie = governance_test + .with_community_token_deposit(&realm_cookie) + .await + .unwrap(); + + let proposal_cookie = governance_test + .with_signed_off_proposal(&proposal_owner_record_cookie, &mut governance_cookie) + .await + .unwrap(); + + // Advance timestamp into voting_cool_off_time + let clock = governance_test.bench.get_clock().await; + + governance_test + .advance_clock_past_timestamp( + clock.unix_timestamp + governance_cookie.account.config.voting_base_time as i64, + ) + .await; + + // Act + governance_test + .with_cast_vote(&proposal_cookie, &token_owner_record_cookie, Vote::Veto) + .await + .unwrap(); + + // Assert + let proposal_account = governance_test + .get_proposal_account(&proposal_cookie.address) + .await; + + assert_eq!(proposal_account.state, ProposalState::Vetoed); +} diff --git a/governance/test-sdk/Cargo.toml b/governance/test-sdk/Cargo.toml index 14c6292e702..dd27a6fcf46 100644 --- a/governance/test-sdk/Cargo.toml +++ b/governance/test-sdk/Cargo.toml @@ -1,25 +1,25 @@ [package] name = "spl-governance-test-sdk" -version = "0.1.2" +version = "0.1.4" description = "Solana Program Library Governance Program Test SDK" -authors = ["Solana Maintainers "] +authors = ["Solana Labs Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" license = "Apache-2.0" -edition = "2018" +edition = "2021" [dependencies] -arrayref = "0.3.6" +arrayref = "0.3.9" bincode = "1.3.2" -borsh = "0.9.1" -lazy_static = "1.4.0" -num-derive = "0.3" +borsh = "1.5.3" +lazy_static = "1.5.0" +num-derive = "0.4" num-traits = "0.2" -serde = "1.0.127" +serde = "1.0.217" serde_derive = "1.0.103" -solana-program = "1.10.33" -solana-program-test = "1.10.33" -solana-sdk = "1.10.33" -spl-token = { version = "3.3", path = "../../token/program", features = [ "no-entrypoint" ] } -thiserror = "1.0" - - +solana-program = "2.1.0" +solana-program-test = "2.1.0" +solana-sdk = "2.1.0" +spl-token = { version = "7.0", features = [ + "no-entrypoint", +] } +thiserror = "2.0" diff --git a/governance/test-sdk/src/addins.rs b/governance/test-sdk/src/addins.rs index 88a41a1c7d9..101f1b3a95c 100644 --- a/governance/test-sdk/src/addins.rs +++ b/governance/test-sdk/src/addins.rs @@ -1,7 +1,8 @@ -use lazy_static::lazy_static; - -use solana_program_test::find_file; -use std::{process::Command, sync::Mutex}; +use { + lazy_static::lazy_static, + solana_program_test::find_file, + std::{process::Command, sync::Mutex}, +}; lazy_static! { pub static ref VOTER_WEIGHT_ADDIN_BUILD_GUARD: Mutex:: = Mutex::new(0); @@ -12,8 +13,8 @@ pub fn ensure_addin_mock_is_built() { let _guard = VOTER_WEIGHT_ADDIN_BUILD_GUARD.lock().unwrap(); if find_file("spl_governance_addin_mock.so").is_none() { assert!(Command::new("cargo") - .args(&[ - "build-bpf", + .args([ + "build-sbf", "--manifest-path", "../addin-mock/program/Cargo.toml", ]) diff --git a/governance/test-sdk/src/cookies.rs b/governance/test-sdk/src/cookies.rs index 2f47c625b63..cd9e1bcd803 100644 --- a/governance/test-sdk/src/cookies.rs +++ b/governance/test-sdk/src/cookies.rs @@ -1,5 +1,4 @@ -use solana_program::pubkey::Pubkey; -use solana_sdk::account::Account; +use {solana_program::pubkey::Pubkey, solana_sdk::account::Account}; #[derive(Debug)] pub struct TokenAccountCookie { diff --git a/governance/test-sdk/src/lib.rs b/governance/test-sdk/src/lib.rs index 687a5dd4fab..8086306c24a 100644 --- a/governance/test-sdk/src/lib.rs +++ b/governance/test-sdk/src/lib.rs @@ -1,27 +1,32 @@ -use std::borrow::Borrow; - -use borsh::BorshDeserialize; -use cookies::{TokenAccountCookie, WalletCookie}; -use solana_program::{ - borsh::try_from_slice_unchecked, clock::Clock, instruction::Instruction, - program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, rent::Rent, - system_instruction, system_program, sysvar, +#![allow(clippy::arithmetic_side_effects)] +use { + crate::tools::map_transaction_error, + bincode::deserialize, + borsh::{BorshDeserialize, BorshSerialize}, + cookies::{TokenAccountCookie, WalletCookie}, + solana_program::{ + borsh1::try_from_slice_unchecked, clock::Clock, instruction::Instruction, + program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, rent::Rent, + stake_history::Epoch, system_instruction, system_program, sysvar, + }, + solana_program_test::{ProgramTest, ProgramTestContext}, + solana_sdk::{ + account::{Account, AccountSharedData, WritableAccount}, + signature::Keypair, + signer::Signer, + transaction::Transaction, + }, + spl_token::instruction::{set_authority, AuthorityType}, + std::borrow::Borrow, + tools::clone_keypair, }; -use solana_program_test::{ProgramTest, ProgramTestContext}; -use solana_sdk::{account::Account, signature::Keypair, signer::Signer, transaction::Transaction}; - -use bincode::deserialize; - -use spl_token::instruction::{set_authority, AuthorityType}; -use tools::clone_keypair; - -use crate::tools::map_transaction_error; pub mod addins; pub mod cookies; pub mod tools; -/// Program's test bench which captures test context, rent and payer and common utility functions +/// Program's test bench which captures test context, rent and payer and common +/// utility functions pub struct ProgramTestBench { pub context: ProgramTestContext, pub rent: Rent, @@ -33,7 +38,7 @@ impl ProgramTestBench { /// Create new bench given a ProgramTest instance populated with all of the /// desired programs. pub async fn start_new(program_test: ProgramTest) -> Self { - let mut context = program_test.start_with_context().await; + let context = program_test.start_with_context().await; let rent = context.banks_client.get_rent().await.unwrap(); let payer = clone_keypair(&context.payer); @@ -74,7 +79,6 @@ impl ProgramTestBench { transaction.sign(&all_signers, recent_blockhash); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 self.context .banks_client .process_transaction(transaction) @@ -344,6 +348,37 @@ impl ProgramTestBench { .unwrap_or_else(|| panic!("GET-TEST-ACCOUNT-ERROR: Account {} not found", address)) } + /// Overrides or creates Borsh serialized account with arbitrary account + /// data subverting normal runtime checks + pub fn set_borsh_account( + &mut self, + program_id: &Pubkey, + address: &Pubkey, + account: &T, + ) { + let mut account_data = vec![]; + borsh::to_writer(&mut account_data, &account).unwrap(); + + let data = AccountSharedData::create( + self.rent.minimum_balance(account_data.len()), + account_data, + *program_id, + false, + Epoch::default(), + ); + + self.context.set_account(address, &data); + } + + /// Removes an account by setting its data to empty and owner to system + /// subverting normal runtime checks + pub fn remove_account(&mut self, address: &Pubkey) { + let data = + AccountSharedData::create(0, vec![], system_program::id(), false, Epoch::default()); + + self.context.set_account(address, &data); + } + #[allow(dead_code)] pub async fn get_account(&mut self, address: &Pubkey) -> Option { self.context diff --git a/governance/test-sdk/src/tools.rs b/governance/test-sdk/src/tools.rs index b1b6538431e..c929467e689 100644 --- a/governance/test-sdk/src/tools.rs +++ b/governance/test-sdk/src/tools.rs @@ -1,7 +1,8 @@ -use std::convert::TryFrom; - -use solana_program::{instruction::InstructionError, program_error::ProgramError}; -use solana_sdk::{signature::Keypair, transaction::TransactionError, transport::TransportError}; +use { + solana_program::{instruction::InstructionError, program_error::ProgramError}, + solana_sdk::{signature::Keypair, transaction::TransactionError, transport::TransportError}, + std::convert::TryFrom, +}; /// TODO: Add to Solana SDK /// Instruction errors not mapped in the sdk @@ -28,16 +29,25 @@ pub fn map_transaction_error(transport_error: TransportError) -> ProgramError { TransportError::TransactionError(TransactionError::InstructionError( _, instruction_error, - )) => ProgramError::try_from(instruction_error).unwrap_or_else(|ie| match ie { + )) => match instruction_error { + // In solana-sdk v1.19.0, there is a ProgramError for + // InstructionError::IncorrectAuthority. This results in the error mapping + // returning two different values: one for sdk < v1.19 and another for sdk >= v1.19.0. + // To avoid this situation, handle InstructionError::IncorrectAuthority earlier. + // Can be removed when Solana v1.19.0 becomes a stable channel (also need to update the + // test assert for + // `test_create_program_governance_with_incorrect_upgrade_authority_error`) InstructionError::IncorrectAuthority => { ProgramInstructionError::IncorrectAuthority.into() } - InstructionError::PrivilegeEscalation => { - ProgramInstructionError::PrivilegeEscalation.into() - } - _ => panic!("TEST-INSTRUCTION-ERROR {:?}", ie), - }), - + _ => ProgramError::try_from(instruction_error).unwrap_or_else(|ie| match ie { + InstructionError::IncorrectAuthority => unreachable!(), + InstructionError::PrivilegeEscalation => { + ProgramInstructionError::PrivilegeEscalation.into() + } + _ => panic!("TEST-INSTRUCTION-ERROR {:?}", ie), + }), + }, _ => panic!("TEST-TRANSPORT-ERROR: {:?}", transport_error), } } diff --git a/governance/tools/Cargo.toml b/governance/tools/Cargo.toml index 1a77a548598..766bab14b7c 100644 --- a/governance/tools/Cargo.toml +++ b/governance/tools/Cargo.toml @@ -1,20 +1,22 @@ [package] name = "spl-governance-tools" -version = "0.1.2" +version = "0.1.4" description = "Solana Program Library Governance Tools" -authors = ["Solana Maintainers "] +authors = ["Solana Labs Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" license = "Apache-2.0" -edition = "2018" +edition = "2021" [dependencies] -arrayref = "0.3.6" +arrayref = "0.3.9" bincode = "1.3.2" -borsh = "0.9.1" -num-derive = "0.3" +borsh = "1.5.3" +num-derive = "0.4" num-traits = "0.2" -serde = "1.0.127" +serde = "1.0.217" serde_derive = "1.0.103" -solana-program = "1.10.33" -spl-token = { version = "3.3", path = "../../token/program", features = [ "no-entrypoint" ] } -thiserror = "1.0" +solana-program = "2.1.0" +spl-token = { version = "7.0", features = [ + "no-entrypoint", +] } +thiserror = "2.0" diff --git a/governance/tools/src/account.rs b/governance/tools/src/account.rs index 1be7d4c0edb..b3183b00c03 100644 --- a/governance/tools/src/account.rs +++ b/governance/tools/src/account.rs @@ -1,32 +1,34 @@ //! General purpose account utility functions -use borsh::{BorshDeserialize, BorshSerialize}; -use solana_program::{ - account_info::AccountInfo, - borsh::try_from_slice_unchecked, - msg, - program::invoke, - program::invoke_signed, - program_error::ProgramError, - program_pack::IsInitialized, - pubkey::Pubkey, - rent::Rent, - system_instruction::{self, create_account}, - system_program, - sysvar::Sysvar, +use { + crate::error::GovernanceToolsError, + borsh::{BorshDeserialize, BorshSerialize}, + solana_program::{ + account_info::AccountInfo, + borsh1::try_from_slice_unchecked, + msg, + program::{invoke, invoke_signed}, + program_error::ProgramError, + program_pack::IsInitialized, + pubkey::Pubkey, + rent::Rent, + system_instruction::{self, create_account}, + system_program, + sysvar::Sysvar, + }, }; -use crate::error::GovernanceToolsError; - /// Trait for accounts to return their max size pub trait AccountMaxSize { - /// Returns max account size or None if max size is not known and actual instance size should be used + /// Returns max account size or None if max size is not known and actual + /// instance size should be used fn get_max_size(&self) -> Option { None } } -/// Creates a new account and serializes data into it using AccountMaxSize to determine the account's size +/// Creates a new account and serializes data into it using AccountMaxSize to +/// determine the account's size pub fn create_and_serialize_account<'a, T: BorshSerialize + AccountMaxSize>( payer_info: &AccountInfo<'a>, account_info: &AccountInfo<'a>, @@ -42,7 +44,7 @@ pub fn create_and_serialize_account<'a, T: BorshSerialize + AccountMaxSize>( let (serialized_data, account_size) = if let Some(max_size) = account_data.get_max_size() { (None, max_size) } else { - let serialized_data = account_data.try_to_vec()?; + let serialized_data = borsh::to_vec(account_data)?; let account_size = serialized_data.len(); (Some(serialized_data), account_size) }; @@ -72,15 +74,17 @@ pub fn create_and_serialize_account<'a, T: BorshSerialize + AccountMaxSize>( .borrow_mut() .copy_from_slice(&serialized_data); } else { - account_data.serialize(&mut *account_info.data.borrow_mut())?; + borsh::to_writer(&mut account_info.data.borrow_mut()[..], account_data)?; } Ok(()) } -/// Creates a new account and serializes data into it using the provided seeds to invoke signed CPI call -/// The owner of the account is set to the PDA program -/// Note: This functions also checks the provided account PDA matches the supplied seeds +/// Creates a new account and serializes data into it using the provided seeds +/// to invoke signed CPI call The owner of the account is set to the PDA program +/// Note: This functions also checks the provided account PDA matches the +/// supplied seeds +#[allow(clippy::too_many_arguments)] pub fn create_and_serialize_account_signed<'a, T: BorshSerialize + AccountMaxSize>( payer_info: &AccountInfo<'a>, account_info: &AccountInfo<'a>, @@ -89,6 +93,7 @@ pub fn create_and_serialize_account_signed<'a, T: BorshSerialize + AccountMaxSiz program_id: &Pubkey, system_info: &AccountInfo<'a>, rent: &Rent, + extra_lamports: u64, // Extra lamports added on top of the rent exempt amount ) -> Result<(), ProgramError> { create_and_serialize_account_with_owner_signed( payer_info, @@ -99,11 +104,13 @@ pub fn create_and_serialize_account_signed<'a, T: BorshSerialize + AccountMaxSiz program_id, // By default use PDA program_id as the owner of the account system_info, rent, + extra_lamports, ) } -/// Creates a new account and serializes data into it using the provided seeds to invoke signed CPI call -/// Note: This functions also checks the provided account PDA matches the supplied seeds +/// Creates a new account and serializes data into it using the provided seeds +/// to invoke signed CPI call Note: This functions also checks the provided +/// account PDA matches the supplied seeds #[allow(clippy::too_many_arguments)] pub fn create_and_serialize_account_with_owner_signed<'a, T: BorshSerialize + AccountMaxSize>( payer_info: &AccountInfo<'a>, @@ -114,6 +121,7 @@ pub fn create_and_serialize_account_with_owner_signed<'a, T: BorshSerialize + Ac owner_program_id: &Pubkey, system_info: &AccountInfo<'a>, rent: &Rent, + extra_lamports: u64, // Extra lamports added on top of the rent exempt amount ) -> Result<(), ProgramError> { // Get PDA and assert it's the same as the requested account address let (account_address, bump_seed) = @@ -131,7 +139,7 @@ pub fn create_and_serialize_account_with_owner_signed<'a, T: BorshSerialize + Ac let (serialized_data, account_size) = if let Some(max_size) = account_data.get_max_size() { (None, max_size) } else { - let serialized_data = account_data.try_to_vec()?; + let serialized_data = borsh::to_vec(&account_data)?; let account_size = serialized_data.len(); (Some(serialized_data), account_size) }; @@ -140,12 +148,15 @@ pub fn create_and_serialize_account_with_owner_signed<'a, T: BorshSerialize + Ac let bump = &[bump_seed]; signers_seeds.push(bump); - let rent_exempt_lamports = rent.minimum_balance(account_size).max(1); + let rent_exempt_lamports = rent.minimum_balance(account_size); + let total_lamports = rent_exempt_lamports.checked_add(extra_lamports).unwrap(); - // If the account has some lamports already it can't be created using create_account instruction - // Anybody can send lamports to a PDA and by doing so create the account and perform DoS attack by blocking create_account + // If the account has some lamports already it can't be created using + // create_account instruction. + // Anybody can send lamports to a PDA and by doing so create the account + // and perform DoS attack by blocking create_account if account_info.lamports() > 0 { - let top_up_lamports = rent_exempt_lamports.saturating_sub(account_info.lamports()); + let top_up_lamports = total_lamports.saturating_sub(account_info.lamports()); if top_up_lamports > 0 { invoke( @@ -174,7 +185,7 @@ pub fn create_and_serialize_account_with_owner_signed<'a, T: BorshSerialize + Ac let create_account_instruction = create_account( payer_info.key, account_info.key, - rent_exempt_lamports, + total_lamports, account_size as u64, owner_program_id, ); @@ -196,13 +207,14 @@ pub fn create_and_serialize_account_with_owner_signed<'a, T: BorshSerialize + Ac .borrow_mut() .copy_from_slice(&serialized_data); } else if account_size > 0 { - account_data.serialize(&mut *account_info.data.borrow_mut())?; + borsh::to_writer(&mut account_info.data.borrow_mut()[..], account_data)?; } Ok(()) } -/// Deserializes account and checks it's initialized and owned by the specified program +/// Deserializes account and checks it's initialized and owned by the specified +/// program pub fn get_account_data( owner_program_id: &Pubkey, account_info: &AccountInfo, @@ -222,8 +234,28 @@ pub fn get_account_data( } } -/// Asserts the given account is not empty, owned by the given program and of the expected type -/// Note: The function assumes the account type T is stored as the first element in the account data +/// Deserializes account type and checks if the given account_info is owned by +/// owner_program_id +pub fn get_account_type( + owner_program_id: &Pubkey, + account_info: &AccountInfo, +) -> Result { + if account_info.data_is_empty() { + return Err(GovernanceToolsError::AccountDoesNotExist.into()); + } + + if account_info.owner != owner_program_id { + return Err(GovernanceToolsError::InvalidAccountOwner.into()); + } + + let account_type: T = try_from_slice_unchecked(&account_info.data.borrow())?; + + Ok(account_type) +} + +/// Asserts the given account is not empty, owned by the given program and of +/// the expected type Note: The function assumes the account type T is stored as +/// the first element in the account data pub fn assert_is_valid_account_of_type( owner_program_id: &Pubkey, account_info: &AccountInfo, @@ -232,20 +264,21 @@ pub fn assert_is_valid_account_of_type( assert_is_valid_account_of_types(owner_program_id, account_info, |at: &T| *at == account_type) } -/// Asserts the given account is not empty, owned by the given program and one of the types asserted via the provided predicate function -/// Note: The function assumes the account type T is stored as the first element in the account data +/// Asserts the given account is not empty, owned by the given program and one +/// of the types asserted via the provided predicate function Note: The function +/// assumes the account type T is stored as the first element in the account +/// data pub fn assert_is_valid_account_of_types bool>( owner_program_id: &Pubkey, account_info: &AccountInfo, is_account_type: F, ) -> Result<(), ProgramError> { - if account_info.owner != owner_program_id { - return Err(GovernanceToolsError::InvalidAccountOwner.into()); - } - if account_info.data_is_empty() { return Err(GovernanceToolsError::AccountDoesNotExist.into()); } + if account_info.owner != owner_program_id { + return Err(GovernanceToolsError::InvalidAccountOwner.into()); + } let account_type: T = try_from_slice_unchecked(&account_info.data.borrow())?; @@ -256,9 +289,14 @@ pub fn assert_is_valid_account_of_types Result<(), ProgramError> { let account_lamports = account_info.lamports(); **account_info.lamports.borrow_mut() = 0; @@ -267,7 +305,35 @@ pub fn dispose_account(account_info: &AccountInfo, beneficiary_info: &AccountInf .checked_add(account_lamports) .unwrap(); - let mut account_data = account_info.data.borrow_mut(); + account_info.assign(&system_program::id()); + account_info.realloc(0, false) +} + +/// Extends account size to the new account size +pub fn extend_account_size<'a>( + account_info: &AccountInfo<'a>, + payer_info: &AccountInfo<'a>, + new_account_size: usize, + rent: &Rent, + system_info: &AccountInfo<'a>, +) -> Result<(), ProgramError> { + if new_account_size <= account_info.data_len() { + return Err(GovernanceToolsError::InvalidNewAccountSize.into()); + } + + let rent_exempt_lamports = rent.minimum_balance(new_account_size); + let top_up_lamports = rent_exempt_lamports.saturating_sub(account_info.lamports()); + + if top_up_lamports > 0 { + invoke( + &system_instruction::transfer(payer_info.key, account_info.key, top_up_lamports), + &[ + payer_info.clone(), + account_info.clone(), + system_info.clone(), + ], + )?; + } - account_data.fill(0); + account_info.realloc(new_account_size, false) } diff --git a/governance/tools/src/error.rs b/governance/tools/src/error.rs index 859882d0704..feb84ec9bbf 100644 --- a/governance/tools/src/error.rs +++ b/governance/tools/src/error.rs @@ -1,12 +1,14 @@ //! Error types -use num_derive::FromPrimitive; -use solana_program::{ - decode_error::DecodeError, - msg, - program_error::{PrintProgramError, ProgramError}, +use { + num_derive::FromPrimitive, + solana_program::{ + decode_error::DecodeError, + msg, + program_error::{PrintProgramError, ProgramError}, + }, + thiserror::Error, }; -use thiserror::Error; /// Errors that may be returned by the GovernanceTools #[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] @@ -21,11 +23,15 @@ pub enum GovernanceToolsError { /// Invalid account owner #[error("Invalid account owner")] - InvalidAccountOwner, + InvalidAccountOwner, // 1102 - /// Invalid Account type - #[error("Invalid Account type")] + /// Invalid account type + #[error("Invalid account type")] InvalidAccountType, + + /// Invalid new account size + #[error("Invalid new account size")] + InvalidNewAccountSize, } impl PrintProgramError for GovernanceToolsError { diff --git a/instruction-padding/README.md b/instruction-padding/README.md new file mode 100644 index 00000000000..fd71f7e7125 --- /dev/null +++ b/instruction-padding/README.md @@ -0,0 +1,2 @@ +NOTE: The instruction-padding program and clients are now maintained at +[solana-program/instruction-padding](https://github.com/solana-program/instruction-padding). diff --git a/libraries/README.md b/libraries/README.md new file mode 100644 index 00000000000..7f619ec7993 --- /dev/null +++ b/libraries/README.md @@ -0,0 +1,13 @@ +NOTE: The actively maintained libraries now live at +[solana-program/libraries](https://github.com/solana-program/libraries). + +The other repo includes: + +* discriminator +* pod +* program-error +* tlv-account-resolution +* type-length-value +* type-length-value-derive-test + +Unmaintained libraries still live here and can still be forked. diff --git a/libraries/concurrent-merkle-tree/Cargo.toml b/libraries/concurrent-merkle-tree/Cargo.toml new file mode 100644 index 00000000000..a94f5e5323b --- /dev/null +++ b/libraries/concurrent-merkle-tree/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "spl-concurrent-merkle-tree" +version = "0.4.0" +description = "Solana Program Library Concurrent Merkle Tree" +authors = ["Solana Labs Maintainers "] +repository = "https://github.com/solana-labs/solana-program-library" +license = "Apache-2.0" +edition = "2021" + +[features] +log = [] +sol-log = ["log"] + +[dependencies] +solana-program = ">=1.18.11,<=2" +bytemuck = "1.21" +thiserror = "2.0.9" + +[dev-dependencies] +rand_distr = "0.4.3" +rand = "0.8" +spl-merkle-tree-reference = { version = "0.1.0", path = "../merkle-tree-reference" } +tokio = { version = "1.42", features = ["full"] } + +[lib] +crate-type = ["cdylib", "lib"] + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] diff --git a/libraries/concurrent-merkle-tree/src/changelog.rs b/libraries/concurrent-merkle-tree/src/changelog.rs new file mode 100644 index 00000000000..e86311ad0de --- /dev/null +++ b/libraries/concurrent-merkle-tree/src/changelog.rs @@ -0,0 +1,80 @@ +use crate::{ + hash::hash_to_parent, + node::{Node, EMPTY}, +}; + +/// Stores the path of nodes changed in a tree by a Merkle tree operation +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[repr(C)] +pub struct ChangeLog { + /// Historical root value before Path was applied + pub root: Node, + /// Nodes of off-chain merkle tree + pub path: [Node; MAX_DEPTH], + /// Bitmap of node parity (used when hashing) + pub index: u32, + pub _padding: u32, +} + +impl Default for ChangeLog { + fn default() -> Self { + Self { + root: EMPTY, + path: [EMPTY; MAX_DEPTH], + index: 0, + _padding: 0, + } + } +} + +impl ChangeLog { + pub fn new(root: Node, path: [Node; MAX_DEPTH], index: u32) -> Self { + Self { + root, + path, + index, + _padding: 0, + } + } + + /// Returns the leaf value modified when the change log was recorded + pub fn get_leaf(&self) -> Node { + self.path[0] + } + + /// Sets all change log values from a leaf and valid proof + pub fn replace_and_recompute_path( + &mut self, + index: u32, + mut node: Node, + proof: &[Node], + ) -> Node { + self.index = index; + for (i, sibling) in proof.iter().enumerate() { + self.path[i] = node; + hash_to_parent(&mut node, sibling, self.index >> i & 1 == 0); + } + self.root = node; + node + } + + /// Fast forwards the given proof and corresponding leaf by applying an + /// update from the current change log + pub fn update_proof_or_leaf( + &self, + leaf_index: u32, + proof: &mut [Node; MAX_DEPTH], + leaf: &mut Node, + ) { + let padding: usize = 32 - MAX_DEPTH; + if leaf_index != self.index { + // This bit math is used to identify which node in the proof + // we need to swap for a corresponding node in a saved change log + let common_path_len = ((leaf_index ^ self.index) << padding).leading_zeros() as usize; + let critbit_index = (MAX_DEPTH - 1) - common_path_len; + proof[critbit_index] = self.path[critbit_index]; + } else { + *leaf = self.get_leaf(); + } + } +} diff --git a/libraries/concurrent-merkle-tree/src/concurrent_merkle_tree.rs b/libraries/concurrent-merkle-tree/src/concurrent_merkle_tree.rs new file mode 100644 index 00000000000..c0dc495dc6a --- /dev/null +++ b/libraries/concurrent-merkle-tree/src/concurrent_merkle_tree.rs @@ -0,0 +1,587 @@ +use { + crate::{ + changelog::ChangeLog, + error::ConcurrentMerkleTreeError, + hash::{fill_in_proof, hash_to_parent, recompute}, + node::{empty_node, empty_node_cached, Node, EMPTY}, + path::Path, + }, + bytemuck::{Pod, Zeroable}, + log_compute, solana_logging, +}; + +/// Enforce constraints on max depth and buffer size +#[inline(always)] +fn check_bounds(max_depth: usize, max_buffer_size: usize) { + // We cannot allow a tree depth greater than 30 because of the bit math + // required to update `ChangeLog`s + assert!(max_depth < 31); + // This will return true if MAX_BUFFER_SIZE is a power of 2 or if it is 0 + assert!(max_buffer_size & (max_buffer_size - 1) == 0); +} + +fn check_leaf_index(leaf_index: u32, max_depth: usize) -> Result<(), ConcurrentMerkleTreeError> { + if leaf_index >= (1 << max_depth) { + return Err(ConcurrentMerkleTreeError::LeafIndexOutOfBounds); + } + Ok(()) +} + +/// Conurrent Merkle Tree is a Merkle Tree that allows +/// multiple tree operations targeted for the same tree root to succeed. +/// +/// In a normal merkle tree, only the first tree operation will succeed because +/// the following operations will have proofs for the unmodified tree state. +/// ConcurrentMerkleTree avoids this by storing a buffer of modified nodes +/// (`change_logs`) which allows it to implement fast-forwarding of concurrent +/// merkle tree operations. +/// +/// As long as the concurrent merkle tree operations +/// have proofs that are valid for a previous state of the tree that can be +/// found in the stored buffer, that tree operation's proof can be +/// fast-forwarded and the tree operation can be applied. +/// +/// There are two primitive operations for Concurrent Merkle Trees: +/// [set_leaf](ConcurrentMerkleTree:set_leaf) and +/// [append](ConcurrentMerkleTree::append). Setting a leaf value requires +/// passing a proof to perform that tree operation, but appending does not +/// require a proof. +/// +/// An additional key property of ConcurrentMerkleTree is support for +/// [append](ConcurrentMerkleTree::append) operations, which do not require any +/// proofs to be passed. This is accomplished by keeping track of the +/// proof to the rightmost leaf in the tree (`rightmost_proof`). +/// +/// The `ConcurrentMerkleTree` is a generic struct that may be interacted with +/// using macros. Those macros may wrap up the construction and both mutable and +/// immutable calls to the `ConcurrentMerkleTree` struct. If the macro contains +/// a big match statement over different sizes of a tree and buffer, it might +/// create a huge stack footprint. This in turn might lead to a stack overflow +/// given the max stack offset of just 4kb. In order to minimize the stack frame +/// size, the arguments for the `ConcurrentMerkleTree` methods that contain the +/// proofs are passed as references to structs. +#[repr(C)] +#[derive(Copy, Clone)] +pub struct ConcurrentMerkleTree { + pub sequence_number: u64, + /// Index of most recent root & changes + pub active_index: u64, + /// Number of active changes we are tracking + pub buffer_size: u64, + /// Proof for respective root + pub change_logs: [ChangeLog; MAX_BUFFER_SIZE], + pub rightmost_proof: Path, +} + +unsafe impl Zeroable + for ConcurrentMerkleTree +{ +} +unsafe impl Pod + for ConcurrentMerkleTree +{ +} + +impl Default + for ConcurrentMerkleTree +{ + fn default() -> Self { + Self { + sequence_number: 0, + active_index: 0, + buffer_size: 0, + change_logs: [ChangeLog::::default(); MAX_BUFFER_SIZE], + rightmost_proof: Path::::default(), + } + } +} + +/// Arguments structure for initializing a tree with a root. +pub struct InitializeWithRootArgs { + pub root: Node, + pub rightmost_leaf: Node, + pub proof_vec: Vec, + pub index: u32, +} + +/// Arguments structure for setting a leaf in the tree. +pub struct SetLeafArgs { + pub current_root: Node, + pub previous_leaf: Node, + pub new_leaf: Node, + pub proof_vec: Vec, + pub index: u32, +} + +/// Arguments structure for filling an empty leaf or appending a new leaf to the +/// tree. +pub struct FillEmptyOrAppendArgs { + pub current_root: Node, + pub leaf: Node, + pub proof_vec: Vec, + pub index: u32, +} + +/// Arguments structure for proving a leaf in the tree. +pub struct ProveLeafArgs { + pub current_root: Node, + pub leaf: Node, + pub proof_vec: Vec, + pub index: u32, +} + +impl + ConcurrentMerkleTree +{ + pub fn new() -> Self { + Self::default() + } + + pub fn is_initialized(&self) -> bool { + !(self.buffer_size == 0 && self.sequence_number == 0 && self.active_index == 0) + } + + /// This is the trustless initialization method that should be used in most + /// cases. + pub fn initialize(&mut self) -> Result { + check_bounds(MAX_DEPTH, MAX_BUFFER_SIZE); + if self.is_initialized() { + return Err(ConcurrentMerkleTreeError::TreeAlreadyInitialized); + } + let mut rightmost_proof = Path::default(); + let empty_node_cache = [Node::default(); MAX_DEPTH]; + for (i, node) in rightmost_proof.proof.iter_mut().enumerate() { + *node = empty_node_cached::(i as u32, &empty_node_cache); + } + let mut path = [Node::default(); MAX_DEPTH]; + for (i, node) in path.iter_mut().enumerate() { + *node = empty_node_cached::(i as u32, &empty_node_cache); + } + self.change_logs[0].root = empty_node(MAX_DEPTH as u32); + self.change_logs[0].path = path; + self.sequence_number = 0; + self.active_index = 0; + self.buffer_size = 1; + self.rightmost_proof = rightmost_proof; + Ok(self.change_logs[0].root) + } + + /// This is a trustful initialization method that assumes the root contains + /// the expected leaves. + /// + /// At the time of this crate's publishing, there is no supported way to + /// efficiently verify a pre-initialized root on-chain. Using this + /// method before having a method for on-chain verification will prevent + /// other applications from indexing the leaf data stored in this tree. + pub fn initialize_with_root( + &mut self, + args: &InitializeWithRootArgs, + ) -> Result { + check_bounds(MAX_DEPTH, MAX_BUFFER_SIZE); + check_leaf_index(args.index, MAX_DEPTH)?; + + if self.is_initialized() { + return Err(ConcurrentMerkleTreeError::TreeAlreadyInitialized); + } + let mut proof: [Node; MAX_DEPTH] = [Node::default(); MAX_DEPTH]; + proof.copy_from_slice(&args.proof_vec); + let rightmost_proof = Path { + proof, + index: args.index + 1, + leaf: args.rightmost_leaf, + _padding: 0, + }; + self.change_logs[0].root = args.root; + self.sequence_number = 1; + self.active_index = 0; + self.buffer_size = 1; + self.rightmost_proof = rightmost_proof; + if args.root != recompute(args.rightmost_leaf, &proof, args.index) { + solana_logging!("Proof failed to verify"); + return Err(ConcurrentMerkleTreeError::InvalidProof); + } + Ok(args.root) + } + + /// Errors if one of the leaves of the current merkle tree is non-EMPTY + pub fn prove_tree_is_empty(&self) -> Result<(), ConcurrentMerkleTreeError> { + if !self.is_initialized() { + return Err(ConcurrentMerkleTreeError::TreeNotInitialized); + } + let empty_node_cache = [EMPTY; MAX_DEPTH]; + if self.get_root() != empty_node_cached::(MAX_DEPTH as u32, &empty_node_cache) { + return Err(ConcurrentMerkleTreeError::TreeNonEmpty); + } + Ok(()) + } + + /// Returns the current root of the merkle tree + pub fn get_root(&self) -> [u8; 32] { + self.get_change_log().root + } + + /// Returns the most recent changelog + pub fn get_change_log(&self) -> Box> { + if !self.is_initialized() { + solana_logging!("Tree is not initialized, returning default change log"); + return Box::>::default(); + } + Box::new(self.change_logs[self.active_index as usize]) + } + + /// This method will fail if the leaf cannot be proven + /// to exist in the current tree root. + /// + /// This method will attempts to prove the leaf first + /// using the proof nodes provided. However if this fails, + /// then a proof will be constructed by inferring a proof + /// from the changelog buffer. + /// + /// Note: this is *not* the same as verifying that a (proof, leaf) + /// combination is valid for the given root. That functionality + /// is provided by `check_valid_proof`. + pub fn prove_leaf(&self, args: &ProveLeafArgs) -> Result<(), ConcurrentMerkleTreeError> { + check_bounds(MAX_DEPTH, MAX_BUFFER_SIZE); + check_leaf_index(args.index, MAX_DEPTH)?; + if !self.is_initialized() { + return Err(ConcurrentMerkleTreeError::TreeNotInitialized); + } + + if args.index > self.rightmost_proof.index { + solana_logging!( + "Received an index larger than the rightmost index {} > {}", + args.index, + self.rightmost_proof.index + ); + Err(ConcurrentMerkleTreeError::LeafIndexOutOfBounds) + } else { + let mut proof: [Node; MAX_DEPTH] = [Node::default(); MAX_DEPTH]; + fill_in_proof::(&args.proof_vec, &mut proof); + let valid_root = + self.check_valid_leaf(args.current_root, args.leaf, &mut proof, args.index, true)?; + if !valid_root { + solana_logging!("Proof failed to verify"); + return Err(ConcurrentMerkleTreeError::InvalidProof); + } + Ok(()) + } + } + + /// Only used to initialize right most path for a completely empty tree. + #[inline(always)] + fn initialize_tree_from_append( + &mut self, + leaf: Node, + mut proof: [Node; MAX_DEPTH], + ) -> Result { + let old_root = recompute(EMPTY, &proof, 0); + if old_root == empty_node(MAX_DEPTH as u32) { + self.try_apply_proof(old_root, EMPTY, leaf, &mut proof, 0, false) + } else { + Err(ConcurrentMerkleTreeError::TreeAlreadyInitialized) + } + } + + /// Appending a non-empty Node will always succeed . + pub fn append(&mut self, mut node: Node) -> Result { + check_bounds(MAX_DEPTH, MAX_BUFFER_SIZE); + if !self.is_initialized() { + return Err(ConcurrentMerkleTreeError::TreeNotInitialized); + } + if node == EMPTY { + return Err(ConcurrentMerkleTreeError::CannotAppendEmptyNode); + } + if self.rightmost_proof.index >= 1 << MAX_DEPTH { + return Err(ConcurrentMerkleTreeError::TreeFull); + } + if self.rightmost_proof.index == 0 { + return self.initialize_tree_from_append(node, self.rightmost_proof.proof); + } + let leaf = node; + let intersection = self.rightmost_proof.index.trailing_zeros() as usize; + let mut change_list = [EMPTY; MAX_DEPTH]; + let mut intersection_node = self.rightmost_proof.leaf; + let empty_node_cache = [Node::default(); MAX_DEPTH]; + + for (i, cl_item) in change_list.iter_mut().enumerate().take(MAX_DEPTH) { + *cl_item = node; + match i { + i if i < intersection => { + // Compute proof to the appended node from empty nodes + let sibling = empty_node_cached::(i as u32, &empty_node_cache); + hash_to_parent( + &mut intersection_node, + &self.rightmost_proof.proof[i], + ((self.rightmost_proof.index - 1) >> i) & 1 == 0, + ); + hash_to_parent(&mut node, &sibling, true); + self.rightmost_proof.proof[i] = sibling; + } + i if i == intersection => { + // Compute the where the new node intersects the main tree + hash_to_parent(&mut node, &intersection_node, false); + self.rightmost_proof.proof[intersection] = intersection_node; + } + _ => { + // Update the change list path up to the root + hash_to_parent( + &mut node, + &self.rightmost_proof.proof[i], + ((self.rightmost_proof.index - 1) >> i) & 1 == 0, + ); + } + } + } + + self.update_internal_counters(); + self.change_logs[self.active_index as usize] = + ChangeLog::::new(node, change_list, self.rightmost_proof.index); + self.rightmost_proof.index += 1; + self.rightmost_proof.leaf = leaf; + Ok(node) + } + + /// Convenience function for `set_leaf` + /// + /// This method will `set_leaf` if the leaf at `index` is an empty node, + /// otherwise it will `append` the new leaf. + pub fn fill_empty_or_append( + &mut self, + args: &FillEmptyOrAppendArgs, + ) -> Result { + check_bounds(MAX_DEPTH, MAX_BUFFER_SIZE); + check_leaf_index(args.index, MAX_DEPTH)?; + if !self.is_initialized() { + return Err(ConcurrentMerkleTreeError::TreeNotInitialized); + } + + let mut proof: [Node; MAX_DEPTH] = [Node::default(); MAX_DEPTH]; + fill_in_proof::(&args.proof_vec, &mut proof); + + log_compute!(); + match self.try_apply_proof( + args.current_root, + EMPTY, + args.leaf, + &mut proof, + args.index, + false, + ) { + Ok(new_root) => Ok(new_root), + Err(error) => match error { + ConcurrentMerkleTreeError::LeafContentsModified => self.append(args.leaf), + _ => Err(error), + }, + } + } + + /// This method will update the leaf at `index`. + /// + /// However if the proof cannot be verified, this method will fail. + pub fn set_leaf(&mut self, args: &SetLeafArgs) -> Result { + check_bounds(MAX_DEPTH, MAX_BUFFER_SIZE); + check_leaf_index(args.index, MAX_DEPTH)?; + if !self.is_initialized() { + return Err(ConcurrentMerkleTreeError::TreeNotInitialized); + } + + if args.index > self.rightmost_proof.index { + Err(ConcurrentMerkleTreeError::LeafIndexOutOfBounds) + } else { + let mut proof: [Node; MAX_DEPTH] = [Node::default(); MAX_DEPTH]; + fill_in_proof::(&args.proof_vec, &mut proof); + + log_compute!(); + self.try_apply_proof( + args.current_root, + args.previous_leaf, + args.new_leaf, + &mut proof, + args.index, + true, + ) + } + } + + /// Returns the Current Seq of the tree, the seq is the monotonic counter of + /// the tree operations that is incremented every time a mutable + /// operation is performed on the tree. + pub fn get_seq(&self) -> u64 { + self.sequence_number + } + + /// Modifies the `proof` for leaf at `leaf_index` + /// in place by fast-forwarding the given `proof` through the + /// `changelog`s, starting at index `changelog_buffer_index` + /// Returns false if the leaf was updated in the change log + #[inline(always)] + fn fast_forward_proof( + &self, + leaf: &mut Node, + proof: &mut [Node; MAX_DEPTH], + leaf_index: u32, + mut changelog_buffer_index: u64, + use_full_buffer: bool, + ) -> bool { + solana_logging!( + "Fast-forwarding proof, starting index {}", + changelog_buffer_index + ); + let mask: usize = MAX_BUFFER_SIZE - 1; + + let mut updated_leaf = *leaf; + log_compute!(); + // Modifies proof by iterating through the change log + loop { + // If use_full_buffer is false, this loop will terminate if the initial value of + // changelog_buffer_index is the active index + if !use_full_buffer && changelog_buffer_index == self.active_index { + break; + } + changelog_buffer_index = (changelog_buffer_index + 1) & mask as u64; + self.change_logs[changelog_buffer_index as usize].update_proof_or_leaf( + leaf_index, + proof, + &mut updated_leaf, + ); + // If use_full_buffer is true, this loop will do 1 full pass of the change logs + if use_full_buffer && changelog_buffer_index == self.active_index { + break; + } + } + log_compute!(); + let proof_leaf_unchanged = updated_leaf == *leaf; + *leaf = updated_leaf; + proof_leaf_unchanged + } + + #[inline(always)] + fn find_root_in_changelog(&self, current_root: Node) -> Option { + let mask: usize = MAX_BUFFER_SIZE - 1; + for i in 0..self.buffer_size { + let j = self.active_index.wrapping_sub(i) & mask as u64; + if self.change_logs[j as usize].root == current_root { + return Some(j); + } + } + None + } + + #[inline(always)] + fn check_valid_leaf( + &self, + current_root: Node, + leaf: Node, + proof: &mut [Node; MAX_DEPTH], + leaf_index: u32, + allow_inferred_proof: bool, + ) -> Result { + let mask: usize = MAX_BUFFER_SIZE - 1; + let (changelog_index, use_full_buffer) = match self.find_root_in_changelog(current_root) { + Some(matching_changelog_index) => (matching_changelog_index, false), + None => { + if allow_inferred_proof { + solana_logging!("Failed to find root in change log -> replaying full buffer"); + ( + self.active_index.wrapping_sub(self.buffer_size - 1) & mask as u64, + true, + ) + } else { + return Err(ConcurrentMerkleTreeError::RootNotFound); + } + } + }; + let mut updatable_leaf_node = leaf; + let proof_leaf_unchanged = self.fast_forward_proof( + &mut updatable_leaf_node, + proof, + leaf_index, + changelog_index, + use_full_buffer, + ); + if !proof_leaf_unchanged { + return Err(ConcurrentMerkleTreeError::LeafContentsModified); + } + Ok(self.check_valid_proof(updatable_leaf_node, proof, leaf_index)) + } + + /// Checks that the proof provided is valid for the current root. + pub fn check_valid_proof( + &self, + leaf: Node, + proof: &[Node; MAX_DEPTH], + leaf_index: u32, + ) -> bool { + if !self.is_initialized() { + solana_logging!("Tree is not initialized, returning false"); + return false; + } + if check_leaf_index(leaf_index, MAX_DEPTH).is_err() { + solana_logging!("Leaf index out of bounds for max_depth"); + return false; + } + recompute(leaf, proof, leaf_index) == self.get_root() + } + + /// Note: Enabling `allow_inferred_proof` will fast forward the given proof + /// from the beginning of the buffer in the case that the supplied root is + /// not in the buffer. + #[inline(always)] + fn try_apply_proof( + &mut self, + current_root: Node, + leaf: Node, + new_leaf: Node, + proof: &mut [Node; MAX_DEPTH], + leaf_index: u32, + allow_inferred_proof: bool, + ) -> Result { + solana_logging!("Active Index: {}", self.active_index); + solana_logging!("Rightmost Index: {}", self.rightmost_proof.index); + solana_logging!("Buffer Size: {}", self.buffer_size); + solana_logging!("Leaf Index: {}", leaf_index); + let valid_root = + self.check_valid_leaf(current_root, leaf, proof, leaf_index, allow_inferred_proof)?; + if !valid_root { + return Err(ConcurrentMerkleTreeError::InvalidProof); + } + self.update_internal_counters(); + Ok(self.update_buffers_from_proof(new_leaf, proof, leaf_index)) + } + + /// Implements circular addition for changelog buffer index + fn update_internal_counters(&mut self) { + let mask: usize = MAX_BUFFER_SIZE - 1; + self.active_index += 1; + self.active_index &= mask as u64; + if self.buffer_size < MAX_BUFFER_SIZE as u64 { + self.buffer_size += 1; + } + self.sequence_number = self.sequence_number.saturating_add(1); + } + + /// Creates a new root from a proof that is valid for the root at + /// `self.active_index` + fn update_buffers_from_proof(&mut self, start: Node, proof: &[Node], index: u32) -> Node { + let change_log = &mut self.change_logs[self.active_index as usize]; + // Also updates change_log's current root + let root = change_log.replace_and_recompute_path(index, start, proof); + // Update rightmost path if possible + if self.rightmost_proof.index < (1 << MAX_DEPTH) { + if index < self.rightmost_proof.index { + change_log.update_proof_or_leaf( + self.rightmost_proof.index - 1, + &mut self.rightmost_proof.proof, + &mut self.rightmost_proof.leaf, + ); + } else { + assert!(index == self.rightmost_proof.index); + solana_logging!("Appending rightmost leaf"); + self.rightmost_proof.proof.copy_from_slice(proof); + self.rightmost_proof.index = index + 1; + self.rightmost_proof.leaf = change_log.get_leaf(); + } + } + root + } +} diff --git a/libraries/concurrent-merkle-tree/src/error.rs b/libraries/concurrent-merkle-tree/src/error.rs new file mode 100644 index 00000000000..16083211909 --- /dev/null +++ b/libraries/concurrent-merkle-tree/src/error.rs @@ -0,0 +1,42 @@ +use thiserror::Error; + +/// Concurrent merkle tree operation errors +#[derive(Error, Debug, PartialEq, Eq)] +pub enum ConcurrentMerkleTreeError { + /// Received an index larger than the rightmost index + #[error("Received an index larger than the rightmost index, or greater than (1 << max_depth)")] + LeafIndexOutOfBounds, + + /// Invalid root recomputed from proof + #[error("Invalid root recomputed from proof")] + InvalidProof, + + /// Node to append cannot be empty + #[error("Cannot append an empty node")] + CannotAppendEmptyNode, + + /// The tree is at capacity + #[error("Tree is full, cannot append")] + TreeFull, + + /// This tree has already been initialized + #[error("Tree already initialized")] + TreeAlreadyInitialized, + + /// This tree has not yet been initialized + #[error("Tree needs to be initialized before using")] + TreeNotInitialized, + + /// Root passed as argument cannot be found in stored changelog buffer + #[error("Root not found in changelog buffer")] + RootNotFound, + + /// The tree's current leaf value does not match the supplied proof's leaf + /// value + #[error("This tree's current leaf value does not match the supplied proof's leaf value")] + LeafContentsModified, + + /// Tree has at least 1 non-EMPTY leaf + #[error("Tree is not empty")] + TreeNonEmpty, +} diff --git a/libraries/concurrent-merkle-tree/src/hash.rs b/libraries/concurrent-merkle-tree/src/hash.rs new file mode 100644 index 00000000000..10278c3a662 --- /dev/null +++ b/libraries/concurrent-merkle-tree/src/hash.rs @@ -0,0 +1,46 @@ +use { + crate::node::{empty_node, Node}, + solana_program::keccak::hashv, +}; + +/// Recomputes root of the Merkle tree from Node & proof +pub fn recompute(leaf: Node, proof: &[Node], index: u32) -> Node { + let mut current_node = leaf; + for (depth, sibling) in proof.iter().enumerate() { + hash_to_parent(&mut current_node, sibling, index >> depth & 1 == 0); + } + current_node +} + +/// Computes the parent node of `node` and `sibling` and copies the result into +/// `node` +#[inline(always)] +pub fn hash_to_parent(node: &mut Node, sibling: &Node, is_left: bool) { + let parent = if is_left { + hashv(&[node, sibling]) + } else { + hashv(&[sibling, node]) + }; + node.copy_from_slice(parent.as_ref()) +} + +/// Fills in proof to the height of the concurrent merkle tree. +/// Missing nodes are inferred as empty node hashes. +pub fn fill_in_proof( + proof_vec: &[Node], + full_proof: &mut [Node; MAX_DEPTH], +) { + solana_logging!("Attempting to fill in proof"); + if !proof_vec.is_empty() { + full_proof[..proof_vec.len()].copy_from_slice(proof_vec); + } + + for (i, item) in full_proof + .iter_mut() + .enumerate() + .take(MAX_DEPTH) + .skip(proof_vec.len()) + { + *item = empty_node(i as u32); + } +} diff --git a/libraries/concurrent-merkle-tree/src/lib.rs b/libraries/concurrent-merkle-tree/src/lib.rs new file mode 100644 index 00000000000..fecd503d5d6 --- /dev/null +++ b/libraries/concurrent-merkle-tree/src/lib.rs @@ -0,0 +1,25 @@ +#![allow(clippy::arithmetic_side_effects)] +//! # Concurrent Merkle Tree +//! +//! This crate is a Solana-optimized implementation of the +//! concurrent merkle tree data structure introduced in [this +//! whitepaper](https://drive.google.com/file/d/1BOpa5OFmara50fTvL0VIVYjtg-qzHCVc/view) +//! +//! The core implementation of CMT can be found in [concurrent_merkle_tree] + +/// Private macros to enable logging in the Solana runtime +#[macro_use] +mod log; +/// Changelog implementation to keep track of information necessary to fast +/// forward proofs +pub mod changelog; +/// Core implementation of the concurrent merkle tree structure +pub mod concurrent_merkle_tree; +/// Descriptive errors +pub mod error; +/// Hashing utils to support merkle tree operations +pub mod hash; +/// Node implementation and utils +pub mod node; +/// Path implementation +pub mod path; diff --git a/libraries/concurrent-merkle-tree/src/log.rs b/libraries/concurrent-merkle-tree/src/log.rs new file mode 100644 index 00000000000..a6cbaba2b52 --- /dev/null +++ b/libraries/concurrent-merkle-tree/src/log.rs @@ -0,0 +1,17 @@ +macro_rules! solana_logging { + ($message:literal, $($arg:tt)*) => { + #[cfg(feature = "log")] + ::solana_program::msg!($message, $($arg)*); + }; + ($message:literal) => { + #[cfg(feature = "log")] + ::solana_program::msg!($message); + }; +} + +macro_rules! log_compute { + () => { + #[cfg(all(feature = "sol-log", feature = "log"))] + ::solana_program::log::sol_log_compute_units(); + }; +} diff --git a/libraries/concurrent-merkle-tree/src/node.rs b/libraries/concurrent-merkle-tree/src/node.rs new file mode 100644 index 00000000000..e04613a4f6b --- /dev/null +++ b/libraries/concurrent-merkle-tree/src/node.rs @@ -0,0 +1,45 @@ +use solana_program::keccak::hashv; + +/// Abstract type for 32 byte leaf data +pub type Node = [u8; 32]; + +/// An empty node is a 32 byte array of zeroes +pub const EMPTY: Node = [0_u8; 32]; + +/// Calculates the hash of empty nodes up to level i +pub fn empty_node(level: u32) -> Node { + empty_node_cached::<0>(level, &[]) +} + +/// Calculates the hash of empty nodes up to level i using an existing cache +pub fn empty_node_cached(level: u32, cache: &[Node; N]) -> Node { + let mut data = EMPTY; + if level != 0 { + let target = (level - 1) as usize; + let lower_empty = if target < cache.len() && cache[target] != EMPTY { + cache[target] + } else { + empty_node(target as u32) + }; + let hash = hashv(&[lower_empty.as_ref(), lower_empty.as_ref()]); + data.copy_from_slice(hash.as_ref()); + } + data +} + +/// Calculates and caches the hash of empty nodes up to level i +pub fn empty_node_cached_mut(level: u32, cache: &mut [Node; N]) -> Node { + let mut data = EMPTY; + if level != 0 { + let target = (level - 1) as usize; + let lower_empty = if target < cache.len() && cache[target] != EMPTY { + cache[target] + } else { + empty_node(target as u32) + }; + let hash = hashv(&[lower_empty.as_ref(), lower_empty.as_ref()]); + data.copy_from_slice(hash.as_ref()); + } + cache[level as usize] = data; + data +} diff --git a/libraries/concurrent-merkle-tree/src/path.rs b/libraries/concurrent-merkle-tree/src/path.rs new file mode 100644 index 00000000000..03614177311 --- /dev/null +++ b/libraries/concurrent-merkle-tree/src/path.rs @@ -0,0 +1,22 @@ +use crate::node::Node; + +/// Represents a proof to perform a Merkle tree operation on the leaf at `index` +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[repr(C)] +pub struct Path { + pub proof: [Node; MAX_DEPTH], + pub leaf: Node, + pub index: u32, + pub _padding: u32, +} + +impl Default for Path { + fn default() -> Self { + Self { + proof: [Node::default(); MAX_DEPTH], + leaf: Node::default(), + index: 0, + _padding: 0, + } + } +} diff --git a/libraries/concurrent-merkle-tree/tests/tests.rs b/libraries/concurrent-merkle-tree/tests/tests.rs new file mode 100644 index 00000000000..240770d61cf --- /dev/null +++ b/libraries/concurrent-merkle-tree/tests/tests.rs @@ -0,0 +1,576 @@ +#![allow(clippy::arithmetic_side_effects)] +use { + rand::{self, thread_rng, Rng}, + spl_concurrent_merkle_tree::{ + concurrent_merkle_tree::{ + ConcurrentMerkleTree, FillEmptyOrAppendArgs, InitializeWithRootArgs, ProveLeafArgs, + SetLeafArgs, + }, + error::ConcurrentMerkleTreeError, + node::{Node, EMPTY}, + }, + spl_merkle_tree_reference::MerkleTree, +}; + +const DEPTH: usize = 10; +const BUFFER_SIZE: usize = 64; + +fn setup() -> (ConcurrentMerkleTree, MerkleTree) { + // On-chain CMT + let cmt = ConcurrentMerkleTree::::new(); + // Init off-chain Merkle tree with corresponding # of leaves + let leaves = vec![EMPTY; 1 << DEPTH]; + // Off-chain merkle tree + let reference_tree = MerkleTree::new(leaves.as_slice()); + + (cmt, reference_tree) +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_initialize() { + let (mut cmt, off_chain_tree) = setup(); + cmt.initialize().unwrap(); + + assert_eq!( + cmt.get_change_log().root, + off_chain_tree.get_root(), + "Init failed to set root properly" + ); + + // Check that reinitialization fails + if let Err(ConcurrentMerkleTreeError::TreeAlreadyInitialized) = cmt.initialize() { + println!("Reinitialization successfully prevented"); + } else { + panic!("Tree should not be able to be reinitialized"); + } +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_bypass_initialize() { + let (mut cmt, off_chain_tree) = setup(); + let mut rng = thread_rng(); + let leaf = rng.gen::<[u8; 32]>(); + + assert_eq!( + ConcurrentMerkleTreeError::TreeNotInitialized, + cmt.append(leaf).unwrap_err(), + "Expected TreeNotInitialized error when appending to uninitialized tree" + ); + + assert_eq!( + ConcurrentMerkleTreeError::TreeNotInitialized, + cmt.set_leaf(&SetLeafArgs { + current_root: off_chain_tree.get_root(), + previous_leaf: [0; 32], + new_leaf: leaf, + proof_vec: off_chain_tree.get_proof_of_leaf(0), + index: 0 + },) + .unwrap_err(), + "Expected TreeNotInitialized error when setting a leaf on an uninitialized tree" + ); + + assert_eq!( + ConcurrentMerkleTreeError::TreeNotInitialized, + cmt.prove_leaf(&ProveLeafArgs { + current_root: off_chain_tree.get_root(), + leaf, + proof_vec: off_chain_tree.get_proof_of_leaf(0), + index: 0 + }) + .unwrap_err(), + "Expected TreeNotInitialized error when proving a leaf exists on an uninitialized tree" + ); + + assert_eq!( + ConcurrentMerkleTreeError::TreeNotInitialized, + cmt.fill_empty_or_append( + &FillEmptyOrAppendArgs { current_root: off_chain_tree.get_root(), leaf, proof_vec: off_chain_tree.get_proof_of_leaf(0), index: 0 } + ) + .unwrap_err(), + "Expected TreeNotInitialized error when filling an empty leaf or appending to uninitialized tree" + ); +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_append() { + let (mut cmt, mut off_chain_tree) = setup(); + let mut rng = thread_rng(); + cmt.initialize().unwrap(); + + for i in 0..(1 << DEPTH) { + let leaf = rng.gen::<[u8; 32]>(); + cmt.append(leaf).unwrap(); + off_chain_tree.add_leaf(leaf, i); + assert_eq!( + cmt.get_change_log().root, + off_chain_tree.get_root(), + "On chain tree failed to update properly on an append", + ); + } + + assert_eq!( + cmt.buffer_size, BUFFER_SIZE as u64, + "CMT buffer size is wrong" + ); +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_prove_leaf() { + let (mut cmt, mut off_chain_tree) = setup(); + let mut rng = thread_rng(); + cmt.initialize().unwrap(); + + for i in 0..(1 << DEPTH) { + let leaf = rng.gen::<[u8; 32]>(); + cmt.append(leaf).unwrap(); + off_chain_tree.add_leaf(leaf, i); + } + + // Test that all leaves can be verified + for leaf_index in 0..(1 << DEPTH) { + cmt.prove_leaf(&ProveLeafArgs { + current_root: off_chain_tree.get_root(), + leaf: off_chain_tree.get_leaf(leaf_index), + proof_vec: off_chain_tree.get_proof_of_leaf(leaf_index), + index: leaf_index as u32, + }) + .unwrap(); + } + + // Test that old proofs can be verified + // Up to BUFFER_SIZE old + let num_leaves_to_try = 10; + for _ in 0..num_leaves_to_try { + let leaf_idx = rng.gen_range(0..1 << DEPTH); + let _last_leaf_idx = off_chain_tree.leaf_nodes.len() - 1; + let root = off_chain_tree.get_root(); + let leaf = off_chain_tree.get_leaf(leaf_idx); + let old_proof = off_chain_tree.get_proof_of_leaf(leaf_idx); + + // While executing random replaces, check + for _ in 0..(BUFFER_SIZE - 1) { + let new_leaf = rng.gen::(); + let mut random_leaf_idx = rng.gen_range(0..1 << DEPTH); + while random_leaf_idx == leaf_idx { + random_leaf_idx = rng.gen_range(0..1 << DEPTH); + } + + cmt.set_leaf(&SetLeafArgs { + current_root: off_chain_tree.get_root(), + previous_leaf: off_chain_tree.get_leaf(random_leaf_idx), + new_leaf, + proof_vec: off_chain_tree.get_proof_of_leaf(random_leaf_idx), + index: random_leaf_idx as u32, + }) + .unwrap(); + off_chain_tree.add_leaf(new_leaf, random_leaf_idx); + + // Assert that we can still prove existence of our mostly unused leaf + cmt.prove_leaf(&ProveLeafArgs { + current_root: root, + leaf, + proof_vec: old_proof.clone(), + index: leaf_idx as u32, + }) + .unwrap(); + } + } +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_initialize_with_root() { + let (mut cmt, mut tree) = setup(); + let mut rng = thread_rng(); + + for i in 0..(1 << DEPTH) { + tree.add_leaf(rng.gen::<[u8; 32]>(), i); + } + + let last_leaf_idx = tree.leaf_nodes.len() - 1; + cmt.initialize_with_root(&InitializeWithRootArgs { + root: tree.get_root(), + rightmost_leaf: tree.get_leaf(last_leaf_idx), + proof_vec: tree.get_proof_of_leaf(last_leaf_idx), + index: last_leaf_idx as u32, + }) + .unwrap(); + + assert_eq!( + cmt.get_change_log().root, + tree.get_root(), + "Init failed to set root properly" + ); + + // Check that reinitialization fails + if let Err(ConcurrentMerkleTreeError::TreeAlreadyInitialized) = + cmt.initialize_with_root(&InitializeWithRootArgs { + root: tree.get_root(), + rightmost_leaf: tree.get_leaf(last_leaf_idx), + proof_vec: tree.get_proof_of_leaf(last_leaf_idx), + index: last_leaf_idx as u32, + }) + { + println!("Reinitialization with root successfully prevented"); + } else { + panic!("Tree should not be able to be reinitialized"); + } +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_leaf_contents_modified() { + let (mut cmt, mut tree) = setup(); + let mut rng = thread_rng(); + cmt.initialize().unwrap(); + + // Create tree with a single leaf + let leaf = rng.gen::<[u8; 32]>(); + tree.add_leaf(leaf, 0); + cmt.append(leaf).unwrap(); + + // Save a proof of this leaf + let root = tree.get_root(); + let proof = tree.get_proof_of_leaf(0); + + // Update leaf to be something else + let new_leaf_0 = rng.gen::<[u8; 32]>(); + tree.add_leaf(leaf, 0); + cmt.set_leaf(&SetLeafArgs { + current_root: root, + previous_leaf: leaf, + new_leaf: new_leaf_0, + proof_vec: proof.clone(), + index: 0_u32, + }) + .unwrap(); + + // Should fail to replace same leaf using outdated info + let new_leaf_1 = rng.gen::<[u8; 32]>(); + tree.add_leaf(leaf, 0); + match cmt.set_leaf(&SetLeafArgs { + current_root: root, + previous_leaf: leaf, + new_leaf: new_leaf_1, + proof_vec: proof, + index: 0u32, + }) { + Ok(_) => { + panic!("CMT should fail when replacing leafs with outdated leaf proofs") + } + Err(e) => match e { + ConcurrentMerkleTreeError::LeafContentsModified => {} + _ => { + panic!("Wrong error was thrown: {:?}", e); + } + }, + } +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_replaces() { + let (mut cmt, mut tree) = setup(); + let mut rng = thread_rng(); + cmt.initialize().unwrap(); + + // Fill both trees with random nodes + for i in 0..(1 << DEPTH) { + let leaf = rng.gen::<[u8; 32]>(); + tree.add_leaf(leaf, i); + cmt.append(leaf).unwrap(); + } + assert_eq!(cmt.get_change_log().root, tree.get_root()); + + // Replace leaves in order + for i in 0..(1 << DEPTH) { + let leaf = rng.gen::<[u8; 32]>(); + cmt.set_leaf(&SetLeafArgs { + current_root: tree.get_root(), + previous_leaf: tree.get_leaf(i), + new_leaf: leaf, + proof_vec: tree.get_proof_of_leaf(i), + index: i as u32, + }) + .unwrap(); + tree.add_leaf(leaf, i); + assert_eq!(cmt.get_change_log().root, tree.get_root()); + } + + // Replaces leaves in a random order by x capacity + let test_capacity: usize = 1 << (DEPTH - 1); + for _ in 0..(test_capacity) { + let index = rng.gen_range(0..test_capacity) % (1 << DEPTH); + let leaf = rng.gen::<[u8; 32]>(); + cmt.set_leaf(&SetLeafArgs { + current_root: tree.get_root(), + previous_leaf: tree.get_leaf(index), + new_leaf: leaf, + proof_vec: tree.get_proof_of_leaf(index), + index: index as u32, + }) + .unwrap(); + tree.add_leaf(leaf, index); + assert_eq!(cmt.get_change_log().root, tree.get_root()); + } +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_default_node_is_empty() { + assert_eq!( + Node::default(), + EMPTY, + "Expected default() to be the empty node" + ); +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_mixed() { + let (mut cmt, mut tree) = setup(); + let mut rng = thread_rng(); + cmt.initialize().unwrap(); + + // Fill both trees with random nodes + let mut tree_size = 10; + for i in 0..tree_size { + let leaf = rng.gen::<[u8; 32]>(); + tree.add_leaf(leaf, i); + cmt.append(leaf).unwrap(); + } + assert_eq!(cmt.get_change_log().root, tree.get_root()); + + // Replaces leaves in a random order by 4x capacity + let mut last_rmp = cmt.rightmost_proof; + + let tree_capacity: usize = 1 << DEPTH; + while tree_size < tree_capacity { + let leaf = rng.gen::<[u8; 32]>(); + let random_num: u32 = rng.gen_range(0..10); + if random_num < 5 { + println!("{} append", tree_size); + cmt.append(leaf).unwrap(); + tree.add_leaf(leaf, tree_size); + tree_size += 1; + } else { + let index = rng.gen_range(0..tree_size) % (tree_size); + println!("{} replace {}", tree_size, index); + cmt.set_leaf(&SetLeafArgs { + current_root: tree.get_root(), + previous_leaf: tree.get_leaf(index), + new_leaf: leaf, + proof_vec: tree.get_proof_of_leaf(index), + index: index as u32, + }) + .unwrap(); + tree.add_leaf(leaf, index); + } + if cmt.get_change_log().root != tree.get_root() { + let last_active_index: usize = + (cmt.active_index as usize + BUFFER_SIZE - 1) % BUFFER_SIZE; + println!("{:?}", &last_rmp); + println!("{:?}", &cmt.change_logs[last_active_index]); + println!("{:?}", &cmt.get_change_log()) + } + last_rmp = cmt.rightmost_proof; + assert_eq!(cmt.get_change_log().root, tree.get_root()); + } +} + +#[tokio::test(flavor = "multi_thread")] +/// Append after replacing the last leaf +async fn test_append_bug_repro_1() { + let (mut cmt, mut tree) = setup(); + let mut rng = thread_rng(); + cmt.initialize().unwrap(); + + // Fill both trees with random nodes + let tree_size = 10; + for i in 0..tree_size { + let leaf = rng.gen::<[u8; 32]>(); + tree.add_leaf(leaf, i); + cmt.append(leaf).unwrap(); + } + assert_eq!(cmt.get_change_log().root, tree.get_root()); + + // Replace the rightmost leaf + let leaf_0 = rng.gen::<[u8; 32]>(); + let index = 9; + cmt.set_leaf(&SetLeafArgs { + current_root: tree.get_root(), + previous_leaf: tree.get_leaf(index), + new_leaf: leaf_0, + proof_vec: tree.get_proof_of_leaf(index), + index: index as u32, + }) + .unwrap(); + tree.add_leaf(leaf_0, index); + + let last_rmp = cmt.rightmost_proof; + + // Append + let leaf_1 = rng.gen::<[u8; 32]>(); + cmt.append(leaf_1).unwrap(); + tree.add_leaf(leaf_1, tree_size); + + // Now compare something + if cmt.get_change_log().root != tree.get_root() { + let _last_active_index: usize = (cmt.active_index as usize + BUFFER_SIZE - 1) % BUFFER_SIZE; + println!("{:?}", &last_rmp); + } + assert_eq!(cmt.get_change_log().root, tree.get_root()); +} + +#[tokio::test(flavor = "multi_thread")] +/// Append after also appending via a replace +async fn test_append_bug_repro_2() { + let (mut cmt, mut tree) = setup(); + let mut rng = thread_rng(); + cmt.initialize().unwrap(); + + // Fill both trees with random nodes + let mut tree_size = 10; + for i in 0..tree_size { + let leaf = rng.gen::<[u8; 32]>(); + tree.add_leaf(leaf, i); + cmt.append(leaf).unwrap(); + } + assert_eq!(cmt.get_change_log().root, tree.get_root()); + + // Replace the rightmost leaf + let mut leaf = rng.gen::<[u8; 32]>(); + let index = 10; + cmt.set_leaf(&SetLeafArgs { + current_root: tree.get_root(), + previous_leaf: tree.get_leaf(index), + new_leaf: leaf, + proof_vec: tree.get_proof_of_leaf(index), + index: index as u32, + }) + .unwrap(); + tree.add_leaf(leaf, index); + tree_size += 1; + + let last_rmp = cmt.rightmost_proof; + + // Append + leaf = rng.gen::<[u8; 32]>(); + cmt.append(leaf).unwrap(); + tree.add_leaf(leaf, tree_size); + + // Now compare something + if cmt.get_change_log().root != tree.get_root() { + let _last_active_index: usize = (cmt.active_index as usize + BUFFER_SIZE - 1) % BUFFER_SIZE; + println!("{:?}", &last_rmp); + } + assert_eq!(cmt.get_change_log().root, tree.get_root()); +} + +#[tokio::test(flavor = "multi_thread")] +/// Test that empty trees are checked properly by adding & removing leaves one +/// by one +async fn test_prove_tree_empty_incremental() { + let (mut cmt, mut tree) = setup(); + let mut rng = thread_rng(); + cmt.initialize().unwrap(); + + cmt.prove_tree_is_empty().unwrap(); + + // Append a random leaf & remove it, and make sure that the tree is empty at the + // end + let tree_size = 64; + for i in 0..tree_size { + let leaf = rng.gen::<[u8; 32]>(); + cmt.append(leaf).unwrap(); + tree.add_leaf(leaf, i); + + match cmt.prove_tree_is_empty() { + Ok(_) => { + panic!("Tree has a leaf in it -- should not be possible to prove empty!") + } + Err(e) => match e { + ConcurrentMerkleTreeError::TreeNonEmpty => {} + _ => { + panic!("Wrong error thrown. Expected TreeNonEmpty erro") + } + }, + } + + cmt.set_leaf(&SetLeafArgs { + current_root: tree.get_root(), + previous_leaf: tree.get_leaf(i), + new_leaf: EMPTY, + proof_vec: tree.get_proof_of_leaf(i), + index: i as u32, + }) + .unwrap(); + tree.add_leaf(EMPTY, i); + + cmt.prove_tree_is_empty().unwrap(); + } +} + +#[tokio::test(flavor = "multi_thread")] +/// Test that empty trees are checked properly by adding & removing leaves in a +/// batch +async fn test_prove_tree_empty_batched() { + let (mut cmt, mut tree) = setup(); + let mut rng = thread_rng(); + cmt.initialize().unwrap(); + + // Sanity check + cmt.prove_tree_is_empty().unwrap(); + + // Add random leaves to the tree + let tree_size = 64; + for i in 0..tree_size { + let leaf = rng.gen::<[u8; 32]>(); + cmt.append(leaf).unwrap(); + tree.add_leaf(leaf, i); + + match cmt.prove_tree_is_empty() { + Ok(_) => { + panic!("Tree has a leaf in it -- should not be possible to prove empty!") + } + Err(e) => match e { + ConcurrentMerkleTreeError::TreeNonEmpty => {} + _ => { + panic!("Wrong error thrown. Expected TreeNonEmpty erro") + } + }, + } + } + // Remove random leaves + for i in 0..tree_size - 1 { + cmt.set_leaf(&SetLeafArgs { + current_root: tree.get_root(), + previous_leaf: tree.get_leaf(i), + new_leaf: EMPTY, + proof_vec: tree.get_proof_of_leaf(i), + index: i as u32, + }) + .unwrap(); + tree.add_leaf(EMPTY, i); + + match cmt.prove_tree_is_empty() { + Ok(_) => { + panic!("Tree has a leaf in it -- should not be possible to prove empty!") + } + Err(e) => match e { + ConcurrentMerkleTreeError::TreeNonEmpty => {} + _ => { + panic!("Wrong error thrown. Expected TreeNonEmpty erro") + } + }, + } + } + cmt.set_leaf(&SetLeafArgs { + current_root: tree.get_root(), + previous_leaf: tree.get_leaf(tree_size - 1), + new_leaf: EMPTY, + proof_vec: tree.get_proof_of_leaf(tree_size - 1), + index: (tree_size - 1) as u32, + }) + .unwrap(); + tree.add_leaf(EMPTY, tree_size - 1); + + // Check that the last leaf was successfully removed + cmt.prove_tree_is_empty().unwrap(); +} diff --git a/libraries/math-example/Cargo.toml b/libraries/math-example/Cargo.toml new file mode 100644 index 00000000000..fe6e995544d --- /dev/null +++ b/libraries/math-example/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "spl-math-example" +version = "0.1.0" +description = "Solana Program Library Math Example" +authors = ["Solana Labs Maintainers "] +repository = "https://github.com/solana-labs/solana-program-library" +license = "Apache-2.0" +edition = "2021" + +[features] +no-entrypoint = [] +test-sbf = [] + +[dependencies] +borsh = "1.5.3" +num-derive = "0.4" +num-traits = "0.2" +solana-program = "2.1.0" +spl-math = { path = "../math", version = "0.3.0" } +thiserror = "2.0" + +[dev-dependencies] +solana-program-test = "2.1.0" +solana-sdk = "2.1.0" + +[lib] +crate-type = ["cdylib", "lib"] + + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] diff --git a/libraries/math-example/README.md b/libraries/math-example/README.md new file mode 100644 index 00000000000..2035ce0c8f0 --- /dev/null +++ b/libraries/math-example/README.md @@ -0,0 +1,8 @@ +# Math + +Program wrapper around the spl-math-utils crate. The program exists for testing purposes. + +## Audit + +The repository [README](https://github.com/solana-labs/solana-program-library#audits) +contains information about program audits. diff --git a/associated-token-account/program/Xargo.toml b/libraries/math-example/Xargo.toml similarity index 100% rename from associated-token-account/program/Xargo.toml rename to libraries/math-example/Xargo.toml diff --git a/libraries/math-example/src/entrypoint.rs b/libraries/math-example/src/entrypoint.rs new file mode 100644 index 00000000000..8876e45b78b --- /dev/null +++ b/libraries/math-example/src/entrypoint.rs @@ -0,0 +1,14 @@ +//! Program entrypoint + +#![cfg(not(feature = "no-entrypoint"))] + +use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey}; + +solana_program::entrypoint!(process_instruction); +fn process_instruction( + program_id: &Pubkey, + accounts: &[AccountInfo], + instruction_data: &[u8], +) -> ProgramResult { + crate::processor::process_instruction(program_id, accounts, instruction_data) +} diff --git a/libraries/math-example/src/error.rs b/libraries/math-example/src/error.rs new file mode 100644 index 00000000000..301bf7740c2 --- /dev/null +++ b/libraries/math-example/src/error.rs @@ -0,0 +1,42 @@ +//! Error types + +use { + num_derive::FromPrimitive, + solana_program::{decode_error::DecodeError, program_error::ProgramError}, + thiserror::Error, +}; + +/// Errors that may be returned by the Math program. +#[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] +pub enum MathError { + /// Calculation overflowed the destination number + #[error("Calculation overflowed the destination number")] + Overflow, + /// Calculation underflowed the destination number + #[error("Calculation underflowed the destination number")] + Underflow, +} +impl From for ProgramError { + fn from(e: MathError) -> Self { + ProgramError::Custom(e as u32) + } +} +impl DecodeError for MathError { + fn type_of() -> &'static str { + "Math Error" + } +} + +#[cfg(test)] +mod tests { + use {super::*, solana_program::program_error::ProgramError}; + + #[test] + fn test_math_error_from() { + let program_error = ProgramError::from(MathError::Overflow); + assert_eq!(program_error, ProgramError::Custom(0)); + + let program_error = ProgramError::from(MathError::Underflow); + assert_eq!(program_error, ProgramError::Custom(1)); + } +} diff --git a/libraries/math-example/src/instruction.rs b/libraries/math-example/src/instruction.rs new file mode 100644 index 00000000000..c9e3b40c4ce --- /dev/null +++ b/libraries/math-example/src/instruction.rs @@ -0,0 +1,460 @@ +//! Program instructions, used for end-to-end testing and instruction counts + +use { + crate::id, + borsh::{BorshDeserialize, BorshSerialize}, + solana_program::instruction::Instruction, +}; + +/// Instructions supported by the math program, used for testing instruction +/// counts +#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, PartialEq)] +pub enum MathInstruction { + /// Calculate the square root of the given u64 with decimals + /// + /// No accounts required for this instruction + PreciseSquareRoot { + /// Number underneath the square root sign, whose square root will be + /// calculated + radicand: u64, + }, + /// Calculate the integer square root of the given u64 + /// + /// No accounts required for this instruction + SquareRootU64 { + /// Number underneath the square root sign, whose square root will be + /// calculated + radicand: u64, + }, + /// Calculate the integer square root of the given u128 + /// + /// No accounts required for this instruction + SquareRootU128 { + /// Number underneath the square root sign, whose square root will be + /// calculated + radicand: u128, + }, + /// Multiply two u64 values + /// + /// No accounts required for this instruction + U64Multiply { + /// The multiplicand + multiplicand: u64, + /// The multipier + multiplier: u64, + }, + /// Divide two u64 values + /// + /// No accounts required for this instruction + U64Divide { + /// The dividend + dividend: u64, + /// The divisor + divisor: u64, + }, + /// Multiply two float values + /// + /// No accounts required for this instruction + F32Multiply { + /// The multiplicand + multiplicand: f32, + /// The multipier + multiplier: f32, + }, + /// Divide two float values + /// + /// No accounts required for this instruction + F32Divide { + /// The dividend + dividend: f32, + /// The divisor + divisor: f32, + }, + + /// Exponentiate a float base by a power + /// + /// No accounts required for this instruction + F32Exponentiate { + /// The base + base: f32, + /// The exponent + exponent: f32, + }, + + /// Natural Log of a float + /// + /// No accounts required for this instruction + F32NaturalLog { + /// The argument + argument: f32, + }, + + /// The Normal CDF of a float + /// + /// No accounts required for this instruction + F32NormalCDF { + /// The argument + argument: f32, + }, + + /// Pow two float values + /// + /// No accounts required for this instruction + F64Pow { + /// The base + base: f64, + /// The exponent + exponent: f64, + }, + + /// Multiply two u128 values + /// + /// No accounts required for this instruction + U128Multiply { + /// The multiplicand + multiplicand: u128, + /// The multipier + multiplier: u128, + }, + /// Divide two u128 values + /// + /// No accounts required for this instruction + U128Divide { + /// The dividend + dividend: u128, + /// The divisor + divisor: u128, + }, + /// Multiply two f64 values + /// + /// No accounts required for this instruction + F64Multiply { + /// The multiplicand + multiplicand: f64, + /// The multipier + multiplier: f64, + }, + /// Divide two f64 values + /// + /// No accounts required for this instruction + F64Divide { + /// The dividend + dividend: f64, + /// The divisor + divisor: f64, + }, + + /// Don't do anything for comparison + /// + /// No accounts required for this instruction + Noop, +} + +/// Create PreciseSquareRoot instruction +pub fn precise_sqrt(radicand: u64) -> Instruction { + Instruction { + program_id: id(), + accounts: vec![], + data: borsh::to_vec(&MathInstruction::PreciseSquareRoot { radicand }).unwrap(), + } +} + +/// Create U64 SquareRoot instruction +pub fn sqrt_u64(radicand: u64) -> Instruction { + Instruction { + program_id: id(), + accounts: vec![], + data: borsh::to_vec(&MathInstruction::SquareRootU64 { radicand }).unwrap(), + } +} + +/// Create U128 SquareRoot instruction +pub fn sqrt_u128(radicand: u128) -> Instruction { + Instruction { + program_id: id(), + accounts: vec![], + data: borsh::to_vec(&MathInstruction::SquareRootU128 { radicand }).unwrap(), + } +} + +/// Create U64 Multiplication instruction +pub fn u64_multiply(multiplicand: u64, multiplier: u64) -> Instruction { + Instruction { + program_id: id(), + accounts: vec![], + data: borsh::to_vec(&MathInstruction::U64Multiply { + multiplicand, + multiplier, + }) + .unwrap(), + } +} + +/// Create U64 Division instruction +pub fn u64_divide(dividend: u64, divisor: u64) -> Instruction { + Instruction { + program_id: id(), + accounts: vec![], + data: borsh::to_vec(&MathInstruction::U64Divide { dividend, divisor }).unwrap(), + } +} + +/// Create F32 Multiplication instruction +pub fn f32_multiply(multiplicand: f32, multiplier: f32) -> Instruction { + Instruction { + program_id: id(), + accounts: vec![], + data: borsh::to_vec(&MathInstruction::F32Multiply { + multiplicand, + multiplier, + }) + .unwrap(), + } +} + +/// Create F32 Division instruction +pub fn f32_divide(dividend: f32, divisor: f32) -> Instruction { + Instruction { + program_id: id(), + accounts: vec![], + data: borsh::to_vec(&MathInstruction::F32Divide { dividend, divisor }).unwrap(), + } +} + +/// Create F32 Exponentiate instruction +pub fn f32_exponentiate(base: f32, exponent: f32) -> Instruction { + Instruction { + program_id: id(), + accounts: vec![], + data: borsh::to_vec(&MathInstruction::F32Exponentiate { base, exponent }).unwrap(), + } +} + +/// Create F32 Natural Log instruction +pub fn f32_natural_log(argument: f32) -> Instruction { + Instruction { + program_id: id(), + accounts: vec![], + data: borsh::to_vec(&MathInstruction::F32NaturalLog { argument }).unwrap(), + } +} + +/// Create F32 Normal CDF instruction +pub fn f32_normal_cdf(argument: f32) -> Instruction { + Instruction { + program_id: id(), + accounts: vec![], + data: borsh::to_vec(&MathInstruction::F32NormalCDF { argument }).unwrap(), + } +} + +/// Create F64Pow instruction +pub fn f64_pow(base: f64, exponent: f64) -> Instruction { + Instruction { + program_id: id(), + accounts: vec![], + data: borsh::to_vec(&MathInstruction::F64Pow { base, exponent }).unwrap(), + } +} + +/// Create U128 Multiplication instruction +pub fn u128_multiply(multiplicand: u128, multiplier: u128) -> Instruction { + Instruction { + program_id: id(), + accounts: vec![], + data: borsh::to_vec(&MathInstruction::U128Multiply { + multiplicand, + multiplier, + }) + .unwrap(), + } +} + +/// Create U128 Division instruction +pub fn u128_divide(dividend: u128, divisor: u128) -> Instruction { + Instruction { + program_id: id(), + accounts: vec![], + data: borsh::to_vec(&MathInstruction::U128Divide { dividend, divisor }).unwrap(), + } +} + +/// Create F64 Multiplication instruction +pub fn f64_multiply(multiplicand: f64, multiplier: f64) -> Instruction { + Instruction { + program_id: id(), + accounts: vec![], + data: borsh::to_vec(&MathInstruction::F64Multiply { + multiplicand, + multiplier, + }) + .unwrap(), + } +} + +/// Create F64 Division instruction +pub fn f64_divide(dividend: f64, divisor: f64) -> Instruction { + Instruction { + program_id: id(), + accounts: vec![], + data: borsh::to_vec(&MathInstruction::F64Divide { dividend, divisor }).unwrap(), + } +} + +/// Create Noop instruction +pub fn noop() -> Instruction { + Instruction { + program_id: id(), + accounts: vec![], + data: borsh::to_vec(&MathInstruction::Noop).unwrap(), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_precise_sqrt() { + let instruction = precise_sqrt(u64::MAX); + assert_eq!(0, instruction.accounts.len()); + assert_eq!( + instruction.data, + borsh::to_vec(&MathInstruction::PreciseSquareRoot { radicand: u64::MAX }).unwrap() + ); + assert_eq!(instruction.program_id, crate::id()); + } + + #[test] + fn test_sqrt_u64() { + let instruction = sqrt_u64(u64::MAX); + assert_eq!(0, instruction.accounts.len()); + assert_eq!( + instruction.data, + borsh::to_vec(&MathInstruction::SquareRootU64 { radicand: u64::MAX }).unwrap() + ); + assert_eq!(instruction.program_id, crate::id()); + } + + #[test] + fn test_sqrt_u128() { + let instruction = sqrt_u128(u128::MAX); + assert_eq!(0, instruction.accounts.len()); + assert_eq!( + instruction.data, + borsh::to_vec(&MathInstruction::SquareRootU128 { + radicand: u128::MAX + }) + .unwrap() + ); + assert_eq!(instruction.program_id, crate::id()); + } + + #[test] + fn test_u64_multiply() { + let instruction = u64_multiply(u64::MAX, u64::MAX); + assert_eq!(0, instruction.accounts.len()); + assert_eq!( + instruction.data, + borsh::to_vec(&MathInstruction::U64Multiply { + multiplicand: u64::MAX, + multiplier: u64::MAX + }) + .unwrap() + ); + assert_eq!(instruction.program_id, crate::id()); + } + + #[test] + fn test_u64_divide() { + let instruction = u64_divide(u64::MAX, u64::MAX); + assert_eq!(0, instruction.accounts.len()); + assert_eq!( + instruction.data, + borsh::to_vec(&MathInstruction::U64Divide { + dividend: u64::MAX, + divisor: u64::MAX + }) + .unwrap() + ); + assert_eq!(instruction.program_id, crate::id()); + } + + #[test] + fn test_f32_multiply() { + let instruction = f32_multiply(f32::MAX, f32::MAX); + assert_eq!(0, instruction.accounts.len()); + assert_eq!( + instruction.data, + borsh::to_vec(&MathInstruction::F32Multiply { + multiplicand: f32::MAX, + multiplier: f32::MAX + }) + .unwrap() + ); + assert_eq!(instruction.program_id, crate::id()); + } + + #[test] + fn test_f32_divide() { + let instruction = f32_divide(f32::MAX, f32::MAX); + assert_eq!(0, instruction.accounts.len()); + assert_eq!( + instruction.data, + borsh::to_vec(&MathInstruction::F32Divide { + dividend: f32::MAX, + divisor: f32::MAX + }) + .unwrap() + ); + assert_eq!(instruction.program_id, crate::id()); + } + + #[test] + fn test_f32_exponentiate() { + let instruction = f32_exponentiate(f32::MAX, f32::MAX); + assert_eq!(0, instruction.accounts.len()); + assert_eq!( + instruction.data, + borsh::to_vec(&MathInstruction::F32Exponentiate { + base: f32::MAX, + exponent: f32::MAX + }) + .unwrap() + ); + assert_eq!(instruction.program_id, crate::id()) + } + + #[test] + fn test_f32_natural_log() { + let instruction = f32_natural_log(f32::MAX); + assert_eq!(0, instruction.accounts.len()); + assert_eq!( + instruction.data, + borsh::to_vec(&MathInstruction::F32NaturalLog { argument: f32::MAX }).unwrap() + ); + assert_eq!(instruction.program_id, crate::id()) + } + + #[test] + fn test_f32_normal_cdf() { + let instruction = f32_normal_cdf(f32::MAX); + assert_eq!(0, instruction.accounts.len()); + assert_eq!( + instruction.data, + borsh::to_vec(&MathInstruction::F32NormalCDF { argument: f32::MAX }).unwrap() + ); + assert_eq!(instruction.program_id, crate::id()) + } + + #[test] + fn test_noop() { + let instruction = noop(); + assert_eq!(0, instruction.accounts.len()); + assert_eq!( + instruction.data, + borsh::to_vec(&MathInstruction::Noop).unwrap() + ); + assert_eq!(instruction.program_id, crate::id()); + } +} diff --git a/libraries/math-example/src/lib.rs b/libraries/math-example/src/lib.rs new file mode 100644 index 00000000000..e0162970628 --- /dev/null +++ b/libraries/math-example/src/lib.rs @@ -0,0 +1,13 @@ +//! Math operations using unsigned integers + +#![deny(missing_docs)] +#![forbid(unsafe_code)] + +mod entrypoint; +pub mod error; +pub mod instruction; +pub mod processor; + +pub use spl_math::{approximations, checked_ceil_div, precise_number, uint}; + +solana_program::declare_id!("Math111111111111111111111111111111111111111"); diff --git a/libraries/math-example/src/processor.rs b/libraries/math-example/src/processor.rs new file mode 100644 index 00000000000..dfc2bb176b6 --- /dev/null +++ b/libraries/math-example/src/processor.rs @@ -0,0 +1,314 @@ +#![allow(clippy::arithmetic_side_effects)] +//! Program state processor + +use { + crate::{ + approximations::{f32_normal_cdf, sqrt}, + instruction::MathInstruction, + precise_number::PreciseNumber, + }, + borsh::BorshDeserialize, + solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, log::sol_log_compute_units, msg, + pubkey::Pubkey, + }, +}; + +/// u64_multiply +#[inline(never)] +fn u64_multiply(multiplicand: u64, multiplier: u64) -> u64 { + multiplicand * multiplier +} + +/// u64_divide +#[inline(never)] +fn u64_divide(dividend: u64, divisor: u64) -> u64 { + dividend / divisor +} + +/// f32_multiply +#[inline(never)] +fn f32_multiply(multiplicand: f32, multiplier: f32) -> f32 { + multiplicand * multiplier +} + +/// f32_divide +#[inline(never)] +fn f32_divide(dividend: f32, divisor: f32) -> f32 { + dividend / divisor +} + +/// f32_exponentiate +#[inline(never)] +fn f32_exponentiate(base: f32, exponent: f32) -> f32 { + base.powf(exponent) +} + +/// f32_natural_log +#[inline(never)] +fn f32_natural_log(argument: f32) -> f32 { + argument.ln() +} + +/// u128_multiply +#[inline(never)] +fn u128_multiply(multiplicand: u128, multiplier: u128) -> u128 { + multiplicand * multiplier +} + +/// u128_divide +#[inline(never)] +fn u128_divide(dividend: u128, divisor: u128) -> u128 { + dividend / divisor +} + +/// f64_multiply +#[inline(never)] +fn f64_multiply(multiplicand: f64, multiplier: f64) -> f64 { + multiplicand * multiplier +} + +/// f64_divide +#[inline(never)] +fn f64_divide(dividend: f64, divisor: f64) -> f64 { + dividend / divisor +} + +/// Instruction processor +pub fn process_instruction( + _program_id: &Pubkey, + _accounts: &[AccountInfo], + input: &[u8], +) -> ProgramResult { + let instruction = MathInstruction::try_from_slice(input).unwrap(); + match instruction { + MathInstruction::PreciseSquareRoot { radicand } => { + msg!("Calculating square root using PreciseNumber"); + let radicand = PreciseNumber::new(radicand as u128).unwrap(); + sol_log_compute_units(); + let result = radicand.sqrt().unwrap().to_imprecise().unwrap() as u64; + sol_log_compute_units(); + msg!("{}", result); + Ok(()) + } + MathInstruction::SquareRootU64 { radicand } => { + msg!("Calculating u64 square root"); + sol_log_compute_units(); + let result = sqrt(radicand).unwrap(); + sol_log_compute_units(); + msg!("{}", result); + Ok(()) + } + MathInstruction::SquareRootU128 { radicand } => { + msg!("Calculating u128 square root"); + sol_log_compute_units(); + let result = sqrt(radicand).unwrap(); + sol_log_compute_units(); + msg!("{}", result); + Ok(()) + } + MathInstruction::U64Multiply { + multiplicand, + multiplier, + } => { + msg!("Calculating U64 Multiply"); + sol_log_compute_units(); + let result = u64_multiply(multiplicand, multiplier); + sol_log_compute_units(); + msg!("{}", result); + Ok(()) + } + MathInstruction::U64Divide { dividend, divisor } => { + msg!("Calculating U64 Divide"); + sol_log_compute_units(); + let result = u64_divide(dividend, divisor); + sol_log_compute_units(); + msg!("{}", result); + Ok(()) + } + MathInstruction::F32Multiply { + multiplicand, + multiplier, + } => { + msg!("Calculating f32 Multiply"); + sol_log_compute_units(); + let result = f32_multiply(multiplicand, multiplier); + sol_log_compute_units(); + msg!("{}", result as u64); + Ok(()) + } + MathInstruction::F32Divide { dividend, divisor } => { + msg!("Calculating f32 Divide"); + sol_log_compute_units(); + let result = f32_divide(dividend, divisor); + sol_log_compute_units(); + msg!("{}", result as u64); + Ok(()) + } + MathInstruction::F32Exponentiate { base, exponent } => { + msg!("Calculating f32 Exponent"); + sol_log_compute_units(); + let result = f32_exponentiate(base, exponent); + sol_log_compute_units(); + msg!("{}", result as u64); + Ok(()) + } + MathInstruction::F32NaturalLog { argument } => { + msg!("Calculating f32 Natural Log"); + sol_log_compute_units(); + let result = f32_natural_log(argument); + sol_log_compute_units(); + msg!("{}", result as u64); + Ok(()) + } + MathInstruction::F32NormalCDF { argument } => { + msg!("Calculating f32 Normal CDF"); + sol_log_compute_units(); + let result = f32_normal_cdf(argument); + sol_log_compute_units(); + msg!("{}", result as u64); + Ok(()) + } + MathInstruction::F64Pow { base, exponent } => { + msg!("Calculating f64 Pow"); + sol_log_compute_units(); + let result = base.powi(exponent as i32); + sol_log_compute_units(); + msg!("{}", result as u64); + sol_log_compute_units(); + let result = base.powf(exponent); + sol_log_compute_units(); + msg!("{}", result as u64); + Ok(()) + } + MathInstruction::U128Multiply { + multiplicand, + multiplier, + } => { + msg!("Calculating u128 Multiply"); + sol_log_compute_units(); + let result = u128_multiply(multiplicand, multiplier); + sol_log_compute_units(); + msg!("{}", result); + Ok(()) + } + MathInstruction::U128Divide { dividend, divisor } => { + msg!("Calculating u128 Divide"); + sol_log_compute_units(); + let result = u128_divide(dividend, divisor); + sol_log_compute_units(); + msg!("{}", result); + Ok(()) + } + MathInstruction::F64Multiply { + multiplicand, + multiplier, + } => { + msg!("Calculating f64 Multiply"); + sol_log_compute_units(); + let result = f64_multiply(multiplicand, multiplier); + sol_log_compute_units(); + msg!("{}", result as u64); + Ok(()) + } + MathInstruction::F64Divide { dividend, divisor } => { + msg!("Calculating f64 Divide"); + sol_log_compute_units(); + let result = f64_divide(dividend, divisor); + sol_log_compute_units(); + msg!("{}", result as u64); + Ok(()) + } + MathInstruction::Noop => { + msg!("Do nothing"); + msg!("{}", 0_u64); + Ok(()) + } + } +} + +#[cfg(test)] +mod tests { + use {super::*, crate::instruction::MathInstruction}; + + #[test] + fn test_u64_multiply() { + assert_eq!(2 * 2, u64_multiply(2, 2)); + assert_eq!(4 * 3, u64_multiply(4, 3)); + } + + #[test] + fn test_u64_divide() { + assert_eq!(1, u64_divide(2, 2)); + assert_eq!(2, u64_divide(2, 1)); + } + + #[test] + fn test_f32_multiply() { + assert_eq!(2.0 * 2.0, f32_multiply(2.0, 2.0)); + assert_eq!(4.0 * 3.0, f32_multiply(4.0, 3.0)); + } + + #[test] + fn test_f32_divide() { + assert_eq!(1.0, f32_divide(2.0, 2.0)); + assert_eq!(2.0, f32_divide(2.0, 1.0)); + } + + #[test] + fn test_f32_exponentiate() { + assert_eq!(16.0, f32_exponentiate(4.0, 2.0)); + assert_eq!(4.0, f32_exponentiate(16.0, 0.5)) + } + + #[test] + fn test_f32_natural_log() { + let one = 1.0f32; + // e^1 + let e = one.exp(); + + // ln(e) - 1 == 0 + let abs_difference = (f32_natural_log(e) - 1.0).abs(); + + assert!(abs_difference <= f32::EPSILON); + } + + #[test] + fn test_process_instruction() { + let program_id = Pubkey::new_unique(); + for math_instruction in &[ + MathInstruction::PreciseSquareRoot { radicand: u64::MAX }, + MathInstruction::SquareRootU64 { radicand: u64::MAX }, + MathInstruction::SquareRootU128 { + radicand: u128::MAX, + }, + MathInstruction::U64Multiply { + multiplicand: 3, + multiplier: 4, + }, + MathInstruction::U64Divide { + dividend: 2, + divisor: 2, + }, + MathInstruction::F32Multiply { + multiplicand: 3.0, + multiplier: 4.0, + }, + MathInstruction::F32Divide { + dividend: 2.0, + divisor: 2.0, + }, + MathInstruction::F32Exponentiate { + base: 4.0, + exponent: 2.0, + }, + MathInstruction::F32NaturalLog { + argument: std::f32::consts::E, + }, + MathInstruction::Noop, + ] { + let input = borsh::to_vec(math_instruction).unwrap(); + process_instruction(&program_id, &[], &input).unwrap(); + } + } +} diff --git a/libraries/math-example/tests/instruction_count.rs b/libraries/math-example/tests/instruction_count.rs new file mode 100644 index 00000000000..a7dbd26aad2 --- /dev/null +++ b/libraries/math-example/tests/instruction_count.rs @@ -0,0 +1,293 @@ +// Mark this test as BPF-only due to current `ProgramTest` limitations when +// CPIing into the system program +#![cfg(feature = "test-sbf")] + +use { + solana_program_test::*, + solana_sdk::{signature::Signer, transaction::Transaction}, + spl_math_example::{id, instruction, processor::process_instruction}, +}; + +#[tokio::test] +async fn test_precise_sqrt_u64_max() { + let mut pc = ProgramTest::new("spl_math_example", id(), processor!(process_instruction)); + + // This is way too big! It's possible to dial down the numbers to get to + // something reasonable, but the better option is to do everything in u64 + pc.set_compute_max_units(350_000); + + let (banks_client, payer, recent_blockhash) = pc.start().await; + + let mut transaction = Transaction::new_with_payer( + &[instruction::precise_sqrt(u64::MAX)], + Some(&payer.pubkey()), + ); + transaction.sign(&[&payer], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn test_precise_sqrt_u32_max() { + let mut pc = ProgramTest::new("spl_math_example", id(), processor!(process_instruction)); + + pc.set_compute_max_units(170_000); + + let (banks_client, payer, recent_blockhash) = pc.start().await; + + let mut transaction = Transaction::new_with_payer( + &[instruction::precise_sqrt(u32::MAX as u64)], + Some(&payer.pubkey()), + ); + transaction.sign(&[&payer], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn test_sqrt_u64() { + let mut pc = ProgramTest::new("spl_math_example", id(), processor!(process_instruction)); + + // Dial down the BPF compute budget to detect if the operation gets bloated in + // the future + pc.set_compute_max_units(2_500); + + let (banks_client, payer, recent_blockhash) = pc.start().await; + + let mut transaction = + Transaction::new_with_payer(&[instruction::sqrt_u64(u64::MAX)], Some(&payer.pubkey())); + transaction.sign(&[&payer], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn test_sqrt_u128() { + let mut pc = ProgramTest::new("spl_math_example", id(), processor!(process_instruction)); + + // Dial down the BPF compute budget to detect if the operation gets bloated in + // the future + pc.set_compute_max_units(4_100); + + let (banks_client, payer, recent_blockhash) = pc.start().await; + + let mut transaction = Transaction::new_with_payer( + &[instruction::sqrt_u128(u64::MAX as u128)], + Some(&payer.pubkey()), + ); + transaction.sign(&[&payer], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn test_sqrt_u128_max() { + let mut pc = ProgramTest::new("spl_math_example", id(), processor!(process_instruction)); + + pc.set_compute_max_units(7_000); + + let (banks_client, payer, recent_blockhash) = pc.start().await; + + let mut transaction = + Transaction::new_with_payer(&[instruction::sqrt_u128(u128::MAX)], Some(&payer.pubkey())); + transaction.sign(&[&payer], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn test_u64_multiply() { + let mut pc = ProgramTest::new("spl_math_example", id(), processor!(process_instruction)); + + pc.set_compute_max_units(1350); + + let (banks_client, payer, recent_blockhash) = pc.start().await; + + let mut transaction = + Transaction::new_with_payer(&[instruction::u64_multiply(42, 84)], Some(&payer.pubkey())); + transaction.sign(&[&payer], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn test_u64_divide() { + let mut pc = ProgramTest::new("spl_math_example", id(), processor!(process_instruction)); + + pc.set_compute_max_units(1650); + + let (banks_client, payer, recent_blockhash) = pc.start().await; + + let mut transaction = + Transaction::new_with_payer(&[instruction::u64_divide(3, 1)], Some(&payer.pubkey())); + transaction.sign(&[&payer], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn test_f32_multiply() { + let mut pc = ProgramTest::new("spl_math_example", id(), processor!(process_instruction)); + + pc.set_compute_max_units(1600); + + let (banks_client, payer, recent_blockhash) = pc.start().await; + + let mut transaction = Transaction::new_with_payer( + &[instruction::f32_multiply(1.5_f32, 2.0_f32)], + Some(&payer.pubkey()), + ); + transaction.sign(&[&payer], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn test_f32_divide() { + let mut pc = ProgramTest::new("spl_math_example", id(), processor!(process_instruction)); + + pc.set_compute_max_units(1650); + + let (banks_client, payer, recent_blockhash) = pc.start().await; + + let mut transaction = Transaction::new_with_payer( + &[instruction::f32_divide(3_f32, 1.5_f32)], + Some(&payer.pubkey()), + ); + transaction.sign(&[&payer], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn test_f32_exponentiate() { + let mut pc = ProgramTest::new("spl_math_example", id(), processor!(process_instruction)); + + pc.set_compute_max_units(1400); + + let (banks_client, payer, recent_blockhash) = pc.start().await; + + let mut transaction = Transaction::new_with_payer( + &[instruction::f32_exponentiate(4_f32, 2_f32)], + Some(&payer.pubkey()), + ); + transaction.sign(&[&payer], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn test_f32_natural_log() { + let mut pc = ProgramTest::new("spl_math_example", id(), processor!(process_instruction)); + + pc.set_compute_max_units(3500); + + let (banks_client, payer, recent_blockhash) = pc.start().await; + + let mut transaction = Transaction::new_with_payer( + &[instruction::f32_natural_log(1_f32.exp())], + Some(&payer.pubkey()), + ); + transaction.sign(&[&payer], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn test_f32_normal_cdf() { + let mut pc = ProgramTest::new("spl_math_example", id(), processor!(process_instruction)); + + // Dial down the BPF compute budget to detect if the operation gets bloated in + // the future + pc.set_compute_max_units(3_100); + + let (banks_client, payer, recent_blockhash) = pc.start().await; + + let mut transaction = + Transaction::new_with_payer(&[instruction::f32_normal_cdf(0_f32)], Some(&payer.pubkey())); + transaction.sign(&[&payer], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn test_f64_pow() { + let mut pc = ProgramTest::new("spl_math_example", id(), processor!(process_instruction)); + + pc.set_compute_max_units(30_000); + + let (banks_client, payer, recent_blockhash) = pc.start().await; + + let mut transaction = Transaction::new_with_payer( + &[instruction::f64_pow(50_f64, 10.5_f64)], + Some(&payer.pubkey()), + ); + transaction.sign(&[&payer], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn test_u128_multiply() { + let mut pc = ProgramTest::new("spl_math_example", id(), processor!(process_instruction)); + + pc.set_compute_max_units(10000); + + let (banks_client, payer, recent_blockhash) = pc.start().await; + + let mut transaction = Transaction::new_with_payer( + &[instruction::u128_multiply(u64::MAX.into(), u64::MAX.into())], + Some(&payer.pubkey()), + ); + transaction.sign(&[&payer], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn test_u128_divide() { + let mut pc = ProgramTest::new("spl_math_example", id(), processor!(process_instruction)); + + pc.set_compute_max_units(10000); + + let (banks_client, payer, recent_blockhash) = pc.start().await; + + let mut transaction = Transaction::new_with_payer( + &[instruction::u128_divide(u128::MAX, u128::MAX / 69)], + Some(&payer.pubkey()), + ); + transaction.sign(&[&payer], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn test_f64_multiply() { + let mut pc = ProgramTest::new("spl_math_example", id(), processor!(process_instruction)); + + pc.set_compute_max_units(10000); + + let (banks_client, payer, recent_blockhash) = pc.start().await; + + let mut transaction = Transaction::new_with_payer( + &[instruction::f64_multiply(f64::powf(2., 42.), 1e-4)], + Some(&payer.pubkey()), + ); + transaction.sign(&[&payer], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn test_f64_divide() { + let mut pc = ProgramTest::new("spl_math_example", id(), processor!(process_instruction)); + + pc.set_compute_max_units(10000); + + let (banks_client, payer, recent_blockhash) = pc.start().await; + + let mut transaction = Transaction::new_with_payer( + &[instruction::f64_divide(f64::powf(2., 42.), 420420.6969)], + Some(&payer.pubkey()), + ); + transaction.sign(&[&payer], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn test_noop() { + let mut pc = ProgramTest::new("spl_math_example", id(), processor!(process_instruction)); + + pc.set_compute_max_units(1200); + + let (banks_client, payer, recent_blockhash) = pc.start().await; + + let mut transaction = + Transaction::new_with_payer(&[instruction::noop()], Some(&payer.pubkey())); + transaction.sign(&[&payer], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); +} diff --git a/libraries/math/Cargo.toml b/libraries/math/Cargo.toml index 2b9d61a3c72..5cc3ee973e2 100644 --- a/libraries/math/Cargo.toml +++ b/libraries/math/Cargo.toml @@ -1,34 +1,19 @@ [package] name = "spl-math" -version = "0.1.0" +version = "0.3.0" description = "Solana Program Library Math" -authors = ["Solana Maintainers "] +authors = ["Solana Labs Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" license = "Apache-2.0" -edition = "2018" - -[features] -no-entrypoint = [] -test-bpf = [] +edition = "2021" [dependencies] -borsh = "0.9" -borsh-derive = "0.9.0" -num-derive = "0.3" num-traits = "0.2" -solana-program = "1.10.33" -thiserror = "1.0" -uint = "0.9" +uint = "0.10" [dev-dependencies] -proptest = "1.0.0" -solana-program-test = "1.10.33" -solana-sdk = "1.10.33" -libm = "0.2.2" - -[lib] -crate-type = ["cdylib", "lib"] - +proptest = "1.6.0" +libm = "0.2.11" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/libraries/math/README.md b/libraries/math/README.md new file mode 100644 index 00000000000..17e2fa99371 --- /dev/null +++ b/libraries/math/README.md @@ -0,0 +1,8 @@ +# Math + +Library with utilities for on-chain math. + +## Audit + +The repository [README](https://github.com/solana-labs/solana-program-library#audits) +contains information about program audits. diff --git a/libraries/math/Xargo.toml b/libraries/math/Xargo.toml deleted file mode 100644 index 1744f098ae1..00000000000 --- a/libraries/math/Xargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.bpfel-unknown-unknown.dependencies.std] -features = [] \ No newline at end of file diff --git a/libraries/math/src/approximations.rs b/libraries/math/src/approximations.rs index f28a6d99030..6a784d20bf2 100644 --- a/libraries/math/src/approximations.rs +++ b/libraries/math/src/approximations.rs @@ -1,3 +1,4 @@ +#![allow(clippy::arithmetic_side_effects)] //! Approximation calculations use { @@ -79,8 +80,8 @@ mod tests { let root = sqrt(radicand).unwrap(); let lower_bound = root.saturating_sub(1).checked_pow(2).unwrap(); let upper_bound = root.checked_add(1).unwrap().checked_pow(2).unwrap(); - assert!(radicand as u128 <= upper_bound); - assert!(radicand as u128 >= lower_bound); + assert!(radicand <= upper_bound); + assert!(radicand >= lower_bound); } #[test] @@ -109,7 +110,7 @@ mod tests { fn test_normal_cdf_f32_min_max() { let test_arguments: [f32; 2] = [f32::MIN, f32::MAX]; for i in test_arguments.iter() { - check_normal_cdf_f32(*i as f32) + check_normal_cdf_f32(*i) } } diff --git a/libraries/math/src/checked_ceil_div.rs b/libraries/math/src/checked_ceil_div.rs index 288463e4868..91b53ba8095 100644 --- a/libraries/math/src/checked_ceil_div.rs +++ b/libraries/math/src/checked_ceil_div.rs @@ -11,10 +11,10 @@ use crate::uint::U256; /// calculation. /// /// For example, 400 / 32 = 12, with a remainder cutting off 0.5 of amount. -/// If we simply ceiling the quotient to 13, then we're saying 400 / 32 = 13, which -/// also cuts off value. To improve this result, we calculate the other way -/// around and again check for a remainder: 400 / 13 = 30, with a remainder of -/// 0.77, and we ceiling that value again. This gives us a final calculation +/// If we simply ceiling the quotient to 13, then we're saying 400 / 32 = 13, +/// which also cuts off value. To improve this result, we calculate the other +/// way around and again check for a remainder: 400 / 13 = 30, with a remainder +/// of 0.77, and we ceiling that value again. This gives us a final calculation /// of 400 / 31 = 13, which provides a ceiling calculation without cutting off /// more value than needed. /// diff --git a/libraries/math/src/entrypoint.rs b/libraries/math/src/entrypoint.rs deleted file mode 100644 index 82641a41587..00000000000 --- a/libraries/math/src/entrypoint.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! Program entrypoint - -#![cfg(not(feature = "no-entrypoint"))] - -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, pubkey::Pubkey, -}; - -entrypoint!(process_instruction); -fn process_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - instruction_data: &[u8], -) -> ProgramResult { - crate::processor::process_instruction(program_id, accounts, instruction_data) -} diff --git a/libraries/math/src/error.rs b/libraries/math/src/error.rs deleted file mode 100644 index 5667e519056..00000000000 --- a/libraries/math/src/error.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! Error types - -use { - num_derive::FromPrimitive, - solana_program::{decode_error::DecodeError, program_error::ProgramError}, - thiserror::Error, -}; - -/// Errors that may be returned by the Math program. -#[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] -pub enum MathError { - /// Calculation overflowed the destination number - #[error("Calculation overflowed the destination number")] - Overflow, - /// Calculation underflowed the destination number - #[error("Calculation underflowed the destination number")] - Underflow, -} -impl From for ProgramError { - fn from(e: MathError) -> Self { - ProgramError::Custom(e as u32) - } -} -impl DecodeError for MathError { - fn type_of() -> &'static str { - "Math Error" - } -} - -#[cfg(test)] -mod tests { - use super::*; - use solana_program::program_error::ProgramError; - - #[test] - fn test_math_error_from() { - let program_error = ProgramError::from(MathError::Overflow); - assert_eq!(program_error, ProgramError::Custom(0)); - - let program_error = ProgramError::from(MathError::Underflow); - assert_eq!(program_error, ProgramError::Custom(1)); - } -} diff --git a/libraries/math/src/instruction.rs b/libraries/math/src/instruction.rs deleted file mode 100644 index adb768a4498..00000000000 --- a/libraries/math/src/instruction.rs +++ /dev/null @@ -1,392 +0,0 @@ -//! Program instructions, used for end-to-end testing and instruction counts - -use { - crate::id, - borsh::{BorshDeserialize, BorshSerialize}, - solana_program::instruction::Instruction, -}; - -/// Instructions supported by the math program, used for testing instruction -/// counts -#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, PartialEq)] -pub enum MathInstruction { - /// Calculate the square root of the given u64 with decimals - /// - /// No accounts required for this instruction - PreciseSquareRoot { - /// Number underneath the square root sign, whose square root will be - /// calculated - radicand: u64, - }, - /// Calculate the integer square root of the given u64 - /// - /// No accounts required for this instruction - SquareRootU64 { - /// Number underneath the square root sign, whose square root will be - /// calculated - radicand: u64, - }, - /// Calculate the integer square root of the given u128 - /// - /// No accounts required for this instruction - SquareRootU128 { - /// Number underneath the square root sign, whose square root will be - /// calculated - radicand: u128, - }, - /// Multiply two u64 values - /// - /// No accounts required for this instruction - U64Multiply { - /// The multiplicand - multiplicand: u64, - /// The multipier - multiplier: u64, - }, - /// Divide two u64 values - /// - /// No accounts required for this instruction - U64Divide { - /// The dividend - dividend: u64, - /// The divisor - divisor: u64, - }, - /// Multiply two float values - /// - /// No accounts required for this instruction - F32Multiply { - /// The multiplicand - multiplicand: f32, - /// The multipier - multiplier: f32, - }, - /// Divide two float values - /// - /// No accounts required for this instruction - F32Divide { - /// The dividend - dividend: f32, - /// The divisor - divisor: f32, - }, - - /// Exponentiate a float base by a power - /// - /// No accounts required for this instruction - F32Exponentiate { - /// The base - base: f32, - /// The exponent - exponent: f32, - }, - - /// Natural Log of a float - /// - /// No accounts required for this instruction - F32NaturalLog { - /// The argument - argument: f32, - }, - - /// The Normal CDF of a float - /// - /// No accounts required for this instruction - F32NormalCDF { - /// The argument - argument: f32, - }, - - /// Don't do anything for comparison - /// - /// No accounts required for this instruction - Noop, -} - -/// Create PreciseSquareRoot instruction -pub fn precise_sqrt(radicand: u64) -> Instruction { - Instruction { - program_id: id(), - accounts: vec![], - data: MathInstruction::PreciseSquareRoot { radicand } - .try_to_vec() - .unwrap(), - } -} - -/// Create U64 SquareRoot instruction -pub fn sqrt_u64(radicand: u64) -> Instruction { - Instruction { - program_id: id(), - accounts: vec![], - data: MathInstruction::SquareRootU64 { radicand } - .try_to_vec() - .unwrap(), - } -} - -/// Create U128 SquareRoot instruction -pub fn sqrt_u128(radicand: u128) -> Instruction { - Instruction { - program_id: id(), - accounts: vec![], - data: MathInstruction::SquareRootU128 { radicand } - .try_to_vec() - .unwrap(), - } -} - -/// Create U64 Multiplication instruction -pub fn u64_multiply(multiplicand: u64, multiplier: u64) -> Instruction { - Instruction { - program_id: id(), - accounts: vec![], - data: MathInstruction::U64Multiply { - multiplicand, - multiplier, - } - .try_to_vec() - .unwrap(), - } -} - -/// Create U64 Division instruction -pub fn u64_divide(dividend: u64, divisor: u64) -> Instruction { - Instruction { - program_id: id(), - accounts: vec![], - data: MathInstruction::U64Divide { dividend, divisor } - .try_to_vec() - .unwrap(), - } -} - -/// Create F32 Multiplication instruction -pub fn f32_multiply(multiplicand: f32, multiplier: f32) -> Instruction { - Instruction { - program_id: id(), - accounts: vec![], - data: MathInstruction::F32Multiply { - multiplicand, - multiplier, - } - .try_to_vec() - .unwrap(), - } -} - -/// Create F32 Division instruction -pub fn f32_divide(dividend: f32, divisor: f32) -> Instruction { - Instruction { - program_id: id(), - accounts: vec![], - data: MathInstruction::F32Divide { dividend, divisor } - .try_to_vec() - .unwrap(), - } -} - -/// Create F32 Exponentiate instruction -pub fn f32_exponentiate(base: f32, exponent: f32) -> Instruction { - Instruction { - program_id: id(), - accounts: vec![], - data: MathInstruction::F32Exponentiate { base, exponent } - .try_to_vec() - .unwrap(), - } -} - -/// Create F32 Natural Log instruction -pub fn f32_natural_log(argument: f32) -> Instruction { - Instruction { - program_id: id(), - accounts: vec![], - data: MathInstruction::F32NaturalLog { argument } - .try_to_vec() - .unwrap(), - } -} - -/// Create F32 Normal CDF instruction -pub fn f32_normal_cdf(argument: f32) -> Instruction { - Instruction { - program_id: id(), - accounts: vec![], - data: MathInstruction::F32NormalCDF { argument } - .try_to_vec() - .unwrap(), - } -} - -/// Create Noop instruction -pub fn noop() -> Instruction { - Instruction { - program_id: id(), - accounts: vec![], - data: MathInstruction::Noop.try_to_vec().unwrap(), - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_precise_sqrt() { - let instruction = precise_sqrt(u64::MAX); - assert_eq!(0, instruction.accounts.len()); - assert_eq!( - instruction.data, - MathInstruction::PreciseSquareRoot { radicand: u64::MAX } - .try_to_vec() - .unwrap() - ); - assert_eq!(instruction.program_id, crate::id()); - } - - #[test] - fn test_sqrt_u64() { - let instruction = sqrt_u64(u64::MAX); - assert_eq!(0, instruction.accounts.len()); - assert_eq!( - instruction.data, - MathInstruction::SquareRootU64 { radicand: u64::MAX } - .try_to_vec() - .unwrap() - ); - assert_eq!(instruction.program_id, crate::id()); - } - - #[test] - fn test_sqrt_u128() { - let instruction = sqrt_u128(u128::MAX); - assert_eq!(0, instruction.accounts.len()); - assert_eq!( - instruction.data, - MathInstruction::SquareRootU128 { - radicand: u128::MAX - } - .try_to_vec() - .unwrap() - ); - assert_eq!(instruction.program_id, crate::id()); - } - - #[test] - fn test_u64_multiply() { - let instruction = u64_multiply(u64::MAX, u64::MAX); - assert_eq!(0, instruction.accounts.len()); - assert_eq!( - instruction.data, - MathInstruction::U64Multiply { - multiplicand: u64::MAX, - multiplier: u64::MAX - } - .try_to_vec() - .unwrap() - ); - assert_eq!(instruction.program_id, crate::id()); - } - - #[test] - fn test_u64_divide() { - let instruction = u64_divide(u64::MAX, u64::MAX); - assert_eq!(0, instruction.accounts.len()); - assert_eq!( - instruction.data, - MathInstruction::U64Divide { - dividend: u64::MAX, - divisor: u64::MAX - } - .try_to_vec() - .unwrap() - ); - assert_eq!(instruction.program_id, crate::id()); - } - - #[test] - fn test_f32_multiply() { - let instruction = f32_multiply(f32::MAX, f32::MAX); - assert_eq!(0, instruction.accounts.len()); - assert_eq!( - instruction.data, - MathInstruction::F32Multiply { - multiplicand: f32::MAX, - multiplier: f32::MAX - } - .try_to_vec() - .unwrap() - ); - assert_eq!(instruction.program_id, crate::id()); - } - - #[test] - fn test_f32_divide() { - let instruction = f32_divide(f32::MAX, f32::MAX); - assert_eq!(0, instruction.accounts.len()); - assert_eq!( - instruction.data, - MathInstruction::F32Divide { - dividend: f32::MAX, - divisor: f32::MAX - } - .try_to_vec() - .unwrap() - ); - assert_eq!(instruction.program_id, crate::id()); - } - - #[test] - fn test_f32_exponentiate() { - let instruction = f32_exponentiate(f32::MAX, f32::MAX); - assert_eq!(0, instruction.accounts.len()); - assert_eq!( - instruction.data, - MathInstruction::F32Exponentiate { - base: f32::MAX, - exponent: f32::MAX - } - .try_to_vec() - .unwrap() - ); - assert_eq!(instruction.program_id, crate::id()) - } - - #[test] - fn test_f32_natural_log() { - let instruction = f32_natural_log(f32::MAX); - assert_eq!(0, instruction.accounts.len()); - assert_eq!( - instruction.data, - MathInstruction::F32NaturalLog { argument: f32::MAX } - .try_to_vec() - .unwrap() - ); - assert_eq!(instruction.program_id, crate::id()) - } - - #[test] - fn test_f32_normal_cdf() { - let instruction = f32_normal_cdf(f32::MAX); - assert_eq!(0, instruction.accounts.len()); - assert_eq!( - instruction.data, - MathInstruction::F32NormalCDF { argument: f32::MAX } - .try_to_vec() - .unwrap() - ); - assert_eq!(instruction.program_id, crate::id()) - } - - #[test] - fn test_noop() { - let instruction = noop(); - assert_eq!(0, instruction.accounts.len()); - assert_eq!( - instruction.data, - MathInstruction::Noop.try_to_vec().unwrap() - ); - assert_eq!(instruction.program_id, crate::id()); - } -} diff --git a/libraries/math/src/lib.rs b/libraries/math/src/lib.rs index 3e9c5ba83b4..54c5a430917 100644 --- a/libraries/math/src/lib.rs +++ b/libraries/math/src/lib.rs @@ -1,15 +1,6 @@ -//! Math operations using unsigned integers - -#![deny(missing_docs)] -#![forbid(unsafe_code)] +//! Math utilities. pub mod approximations; pub mod checked_ceil_div; -mod entrypoint; -pub mod error; -pub mod instruction; pub mod precise_number; -pub mod processor; pub mod uint; - -solana_program::declare_id!("Math111111111111111111111111111111111111111"); diff --git a/libraries/math/src/precise_number.rs b/libraries/math/src/precise_number.rs index 12d86c675a1..23d66af0e71 100644 --- a/libraries/math/src/precise_number.rs +++ b/libraries/math/src/precise_number.rs @@ -1,3 +1,4 @@ +#![allow(clippy::arithmetic_side_effects)] //! Defines PreciseNumber, a U256 wrapper with float-like operations use crate::uint::U256; @@ -8,7 +9,8 @@ type InnerUint = U256; /// The representation of the number one as a precise number as 10^12 pub const ONE: u128 = 1_000_000_000_000; -/// Struct encapsulating a fixed-point number that allows for decimal calculations +/// Struct encapsulating a fixed-point number that allows for decimal +/// calculations #[derive(Clone, Debug, PartialEq)] pub struct PreciseNumber { /// Wrapper over the inner value, which is multiplied by ONE @@ -27,7 +29,7 @@ fn zero() -> InnerUint { impl PreciseNumber { /// Correction to apply to avoid truncation errors on division. Since - /// integer operations will always floor the result, we artifically bump it + /// integer operations will always floor the result, we artificially bump it /// up by one half to get the expect result. fn rounding_correction() -> InnerUint { InnerUint::from(ONE / 2) @@ -35,7 +37,7 @@ impl PreciseNumber { /// Desired precision for the correction factor applied during each /// iteration of checked_pow_approximation. Once the correction factor is - /// smaller than this number, or we reach the maxmium number of iterations, + /// smaller than this number, or we reach the maximum number of iterations, /// the calculation ends. fn precision() -> InnerUint { InnerUint::from(100) @@ -60,7 +62,7 @@ impl PreciseNumber { /// Maximum base allowed when calculating exponents in checked_pow_fraction /// and checked_pow_approximation. The calculation use a Taylor Series - /// approxmation around 1, which converges for bases between 0 and 2. See + /// approximation around 1, which converges for bases between 0 and 2. See /// https://en.wikipedia.org/wiki/Binomial_series#Conditions_for_convergence /// for more information. fn max_pow_base() -> InnerUint { @@ -178,7 +180,8 @@ impl PreciseNumber { Some(Self { value }) } - /// Performs a subtraction, returning the result and whether the result is negative + /// Performs a subtraction, returning the result and whether the result is + /// negative pub fn unsigned_sub(&self, rhs: &Self) -> (Self, bool) { match self.value.checked_sub(rhs.value) { None => { @@ -343,11 +346,12 @@ impl PreciseNumber { /// Based on testing around the limits, this base is the smallest value that /// provides an epsilon of 11 digits fn maximum_sqrt_base() -> Self { - Self::new(std::u128::MAX).unwrap() + Self::new(u128::MAX).unwrap() } /// Approximate the square root using Newton's method. Based on testing, - /// this provides a precision of 11 digits for inputs between 0 and u128::MAX + /// this provides a precision of 11 digits for inputs between 0 and + /// u128::MAX pub fn sqrt(&self) -> Option { if self.less_than(&Self::minimum_sqrt_base()) || self.greater_than(&Self::maximum_sqrt_base()) @@ -365,8 +369,7 @@ impl PreciseNumber { #[cfg(test)] mod tests { - use super::*; - use proptest::prelude::*; + use {super::*, proptest::prelude::*}; fn check_pow_approximation(base: InnerUint, exponent: InnerUint, expected: InnerUint) { let precision = InnerUint::from(5_000_000); // correct to at least 3 decimal places diff --git a/libraries/math/src/processor.rs b/libraries/math/src/processor.rs deleted file mode 100644 index 48b021c5f10..00000000000 --- a/libraries/math/src/processor.rs +++ /dev/null @@ -1,241 +0,0 @@ -//! Program state processor - -use { - crate::{ - approximations::{f32_normal_cdf, sqrt}, - instruction::MathInstruction, - precise_number::PreciseNumber, - }, - borsh::BorshDeserialize, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, log::sol_log_compute_units, msg, - pubkey::Pubkey, - }, -}; - -/// u64_multiply -#[inline(never)] -fn u64_multiply(multiplicand: u64, multiplier: u64) -> u64 { - multiplicand * multiplier -} - -/// u64_divide -#[inline(never)] -fn u64_divide(dividend: u64, divisor: u64) -> u64 { - dividend / divisor -} - -/// f32_multiply -#[inline(never)] -fn f32_multiply(multiplicand: f32, multiplier: f32) -> f32 { - multiplicand * multiplier -} - -/// f32_divide -#[inline(never)] -fn f32_divide(dividend: f32, divisor: f32) -> f32 { - dividend / divisor -} - -/// f32_exponentiate -#[inline(never)] -fn f32_exponentiate(base: f32, exponent: f32) -> f32 { - base.powf(exponent) -} - -/// f32_natural_log -#[inline(never)] -fn f32_natural_log(argument: f32) -> f32 { - argument.ln() -} - -/// Instruction processor -pub fn process_instruction( - _program_id: &Pubkey, - _accounts: &[AccountInfo], - input: &[u8], -) -> ProgramResult { - let instruction = MathInstruction::try_from_slice(input).unwrap(); - match instruction { - MathInstruction::PreciseSquareRoot { radicand } => { - msg!("Calculating square root using PreciseNumber"); - let radicand = PreciseNumber::new(radicand as u128).unwrap(); - sol_log_compute_units(); - let result = radicand.sqrt().unwrap().to_imprecise().unwrap() as u64; - sol_log_compute_units(); - msg!("{}", result); - Ok(()) - } - MathInstruction::SquareRootU64 { radicand } => { - msg!("Calculating u64 square root"); - sol_log_compute_units(); - let result = sqrt(radicand).unwrap(); - sol_log_compute_units(); - msg!("{}", result); - Ok(()) - } - MathInstruction::SquareRootU128 { radicand } => { - msg!("Calculating u128 square root"); - sol_log_compute_units(); - let result = sqrt(radicand).unwrap(); - sol_log_compute_units(); - msg!("{}", result); - Ok(()) - } - MathInstruction::U64Multiply { - multiplicand, - multiplier, - } => { - msg!("Calculating U64 Multiply"); - sol_log_compute_units(); - let result = u64_multiply(multiplicand, multiplier); - sol_log_compute_units(); - msg!("{}", result); - Ok(()) - } - MathInstruction::U64Divide { dividend, divisor } => { - msg!("Calculating U64 Divide"); - sol_log_compute_units(); - let result = u64_divide(dividend, divisor); - sol_log_compute_units(); - msg!("{}", result); - Ok(()) - } - MathInstruction::F32Multiply { - multiplicand, - multiplier, - } => { - msg!("Calculating f32 Multiply"); - sol_log_compute_units(); - let result = f32_multiply(multiplicand, multiplier); - sol_log_compute_units(); - msg!("{}", result as u64); - Ok(()) - } - MathInstruction::F32Divide { dividend, divisor } => { - msg!("Calculating f32 Divide"); - sol_log_compute_units(); - let result = f32_divide(dividend, divisor); - sol_log_compute_units(); - msg!("{}", result as u64); - Ok(()) - } - MathInstruction::F32Exponentiate { base, exponent } => { - msg!("Calculating f32 Exponent"); - sol_log_compute_units(); - let result = f32_exponentiate(base, exponent); - sol_log_compute_units(); - msg!("{}", result as u64); - Ok(()) - } - MathInstruction::F32NaturalLog { argument } => { - msg!("Calculating f32 Natural Log"); - sol_log_compute_units(); - let result = f32_natural_log(argument); - sol_log_compute_units(); - msg!("{}", result as u64); - Ok(()) - } - MathInstruction::F32NormalCDF { argument } => { - msg!("Calculating f32 Normal CDF"); - sol_log_compute_units(); - let result = f32_normal_cdf(argument); - sol_log_compute_units(); - msg!("{}", result as u64); - Ok(()) - } - MathInstruction::Noop => { - msg!("Do nothing"); - msg!("{}", 0_u64); - Ok(()) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::instruction::MathInstruction; - use borsh::BorshSerialize; - - #[test] - fn test_u64_multiply() { - assert_eq!(2 * 2, u64_multiply(2, 2)); - assert_eq!(4 * 3, u64_multiply(4, 3)); - } - - #[test] - fn test_u64_divide() { - assert_eq!(1, u64_divide(2, 2)); - assert_eq!(2, u64_divide(2, 1)); - } - - #[test] - fn test_f32_multiply() { - assert_eq!(2.0 * 2.0, f32_multiply(2.0, 2.0)); - assert_eq!(4.0 * 3.0, f32_multiply(4.0, 3.0)); - } - - #[test] - fn test_f32_divide() { - assert_eq!(1.0, f32_divide(2.0, 2.0)); - assert_eq!(2.0, f32_divide(2.0, 1.0)); - } - - #[test] - fn test_f32_exponentiate() { - assert_eq!(16.0, f32_exponentiate(4.0, 2.0)); - assert_eq!(4.0, f32_exponentiate(16.0, 0.5)) - } - - #[test] - fn test_f32_natural_log() { - let one = 1.0f32; - // e^1 - let e = one.exp(); - - // ln(e) - 1 == 0 - let abs_difference = (f32_natural_log(e) - 1.0).abs(); - - assert!(abs_difference <= f32::EPSILON); - } - - #[test] - fn test_process_instruction() { - let program_id = Pubkey::new_unique(); - for math_instruction in &[ - MathInstruction::PreciseSquareRoot { radicand: u64::MAX }, - MathInstruction::SquareRootU64 { radicand: u64::MAX }, - MathInstruction::SquareRootU128 { - radicand: u128::MAX, - }, - MathInstruction::U64Multiply { - multiplicand: 3, - multiplier: 4, - }, - MathInstruction::U64Divide { - dividend: 2, - divisor: 2, - }, - MathInstruction::F32Multiply { - multiplicand: 3.0, - multiplier: 4.0, - }, - MathInstruction::F32Divide { - dividend: 2.0, - divisor: 2.0, - }, - MathInstruction::F32Exponentiate { - base: 4.0, - exponent: 2.0, - }, - MathInstruction::F32NaturalLog { - argument: std::f32::consts::E, - }, - MathInstruction::Noop, - ] { - let input = math_instruction.try_to_vec().unwrap(); - process_instruction(&program_id, &[], &input).unwrap(); - } - } -} diff --git a/libraries/math/src/uint.rs b/libraries/math/src/uint.rs index 5376e85292b..43f952fc3b8 100644 --- a/libraries/math/src/uint.rs +++ b/libraries/math/src/uint.rs @@ -1,9 +1,11 @@ +#![allow(clippy::arithmetic_side_effects)] //! Large uint types // required for clippy #![allow(clippy::assign_op_pattern)] #![allow(clippy::ptr_offset_with_cast)] #![allow(clippy::manual_range_contains)] +#![allow(missing_docs)] use uint::construct_uint; diff --git a/libraries/math/tests/instruction_count.rs b/libraries/math/tests/instruction_count.rs deleted file mode 100644 index f5a1370d17b..00000000000 --- a/libraries/math/tests/instruction_count.rs +++ /dev/null @@ -1,209 +0,0 @@ -// Mark this test as BPF-only due to current `ProgramTest` limitations when CPIing into the system program -#![cfg(feature = "test-bpf")] - -use { - solana_program_test::*, - solana_sdk::{signature::Signer, transaction::Transaction}, - spl_math::{id, instruction, processor::process_instruction}, -}; - -#[tokio::test] -async fn test_precise_sqrt_u64_max() { - let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction)); - - // This is way too big! It's possible to dial down the numbers to get to - // something reasonable, but the better option is to do everything in u64 - pc.set_compute_max_units(350_000); - - let (mut banks_client, payer, recent_blockhash) = pc.start().await; - - let mut transaction = Transaction::new_with_payer( - &[instruction::precise_sqrt(u64::MAX)], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); -} - -#[tokio::test] -async fn test_precise_sqrt_u32_max() { - let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction)); - - pc.set_compute_max_units(170_000); - - let (mut banks_client, payer, recent_blockhash) = pc.start().await; - - let mut transaction = Transaction::new_with_payer( - &[instruction::precise_sqrt(u32::MAX as u64)], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); -} - -#[tokio::test] -async fn test_sqrt_u64() { - let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction)); - - // Dial down the BPF compute budget to detect if the operation gets bloated in the future - pc.set_compute_max_units(2_500); - - let (mut banks_client, payer, recent_blockhash) = pc.start().await; - - let mut transaction = - Transaction::new_with_payer(&[instruction::sqrt_u64(u64::MAX)], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); -} - -#[tokio::test] -async fn test_sqrt_u128() { - let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction)); - - // Dial down the BPF compute budget to detect if the operation gets bloated in the future - pc.set_compute_max_units(4_100); - - let (mut banks_client, payer, recent_blockhash) = pc.start().await; - - let mut transaction = Transaction::new_with_payer( - &[instruction::sqrt_u128(u64::MAX as u128)], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); -} - -#[tokio::test] -async fn test_sqrt_u128_max() { - let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction)); - - pc.set_compute_max_units(7_000); - - let (mut banks_client, payer, recent_blockhash) = pc.start().await; - - let mut transaction = - Transaction::new_with_payer(&[instruction::sqrt_u128(u128::MAX)], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); -} - -#[tokio::test] -async fn test_u64_multiply() { - let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction)); - - pc.set_compute_max_units(1350); - - let (mut banks_client, payer, recent_blockhash) = pc.start().await; - - let mut transaction = - Transaction::new_with_payer(&[instruction::u64_multiply(42, 84)], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); -} - -#[tokio::test] -async fn test_u64_divide() { - let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction)); - - pc.set_compute_max_units(1650); - - let (mut banks_client, payer, recent_blockhash) = pc.start().await; - - let mut transaction = - Transaction::new_with_payer(&[instruction::u64_divide(3, 1)], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); -} - -#[tokio::test] -async fn test_f32_multiply() { - let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction)); - - pc.set_compute_max_units(1600); - - let (mut banks_client, payer, recent_blockhash) = pc.start().await; - - let mut transaction = Transaction::new_with_payer( - &[instruction::f32_multiply(1.5_f32, 2.0_f32)], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); -} - -#[tokio::test] -async fn test_f32_divide() { - let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction)); - - pc.set_compute_max_units(1650); - - let (mut banks_client, payer, recent_blockhash) = pc.start().await; - - let mut transaction = Transaction::new_with_payer( - &[instruction::f32_divide(3_f32, 1.5_f32)], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); -} - -#[tokio::test] -async fn test_f32_exponentiate() { - let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction)); - - pc.set_compute_max_units(1400); - - let (mut banks_client, payer, recent_blockhash) = pc.start().await; - - let mut transaction = Transaction::new_with_payer( - &[instruction::f32_exponentiate(4_f32, 2_f32)], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); -} - -#[tokio::test] -async fn test_f32_natural_log() { - let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction)); - - pc.set_compute_max_units(3500); - - let (mut banks_client, payer, recent_blockhash) = pc.start().await; - - let mut transaction = Transaction::new_with_payer( - &[instruction::f32_natural_log(1_f32.exp())], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); -} - -#[tokio::test] -async fn test_f32_normal_cdf() { - let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction)); - - // Dial down the BPF compute budget to detect if the operation gets bloated in the future - pc.set_compute_max_units(3_100); - - let (mut banks_client, payer, recent_blockhash) = pc.start().await; - - let mut transaction = - Transaction::new_with_payer(&[instruction::f32_normal_cdf(0_f32)], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); -} - -#[tokio::test] -async fn test_noop() { - let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction)); - - pc.set_compute_max_units(1200); - - let (mut banks_client, payer, recent_blockhash) = pc.start().await; - - let mut transaction = - Transaction::new_with_payer(&[instruction::noop()], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); -} diff --git a/libraries/merkle-tree-reference/Cargo.toml b/libraries/merkle-tree-reference/Cargo.toml new file mode 100644 index 00000000000..cf5a7fc0ce5 --- /dev/null +++ b/libraries/merkle-tree-reference/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "spl-merkle-tree-reference" +version = "0.1.0" +description = "Reference implementation of a merkle tree" +authors = ["Solana Labs Maintainers "] +repository = "https://github.com/solana-labs/solana-program-library" +license = "Apache-2.0" +edition = "2021" + +[dependencies] +solana-program = ">=1.18.11,<=2" +thiserror = "2.0.9" + +[lib] +crate-type = ["cdylib", "lib"] + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] diff --git a/libraries/merkle-tree-reference/src/lib.rs b/libraries/merkle-tree-reference/src/lib.rs new file mode 100644 index 00000000000..c6fb4adf502 --- /dev/null +++ b/libraries/merkle-tree-reference/src/lib.rs @@ -0,0 +1,216 @@ +#![allow(clippy::arithmetic_side_effects)] +use { + solana_program::keccak::hashv, + std::{cell::RefCell, collections::VecDeque, iter::FromIterator, rc::Rc}, +}; + +pub type Node = [u8; 32]; +pub const EMPTY: Node = [0; 32]; + +/// Max number of concurrent changes to tree supported before having to +/// regenerate proofs +pub const MAX_SIZE: usize = 64; + +/// Max depth of the Merkle tree +pub const MAX_DEPTH: usize = 14; + +/// Used for node parity when hashing +pub const MASK: usize = MAX_SIZE - 1; + +/// Recomputes root of the Merkle tree from Node & proof +pub fn recompute(mut leaf: Node, proof: &[Node], index: u32) -> Node { + for (i, s) in proof.iter().enumerate() { + if index >> i & 1 == 0 { + let res = hashv(&[&leaf, s.as_ref()]); + leaf.copy_from_slice(res.as_ref()); + } else { + let res = hashv(&[s.as_ref(), &leaf]); + leaf.copy_from_slice(res.as_ref()); + } + } + leaf +} + +// Off-chain implementation to keep track of nodes +pub struct MerkleTree { + pub leaf_nodes: Vec>>, + pub root: Node, +} + +impl MerkleTree { + /// Calculates updated root from the passed leaves + pub fn new(leaves: &[Node]) -> Self { + let mut leaf_nodes = vec![]; + for (i, node) in leaves.iter().enumerate() { + let mut tree_node = TreeNode::new_empty(0, i as u128); + tree_node.node = *node; + leaf_nodes.push(Rc::new(RefCell::new(tree_node))); + } + let root = MerkleTree::build_root(leaf_nodes.as_slice()); + Self { leaf_nodes, root } + } + + /// Builds root from stack of leaves + pub fn build_root(leaves: &[Rc>]) -> Node { + let mut tree = VecDeque::from_iter(leaves.iter().map(Rc::clone)); + let mut seq_num = leaves.len() as u128; + while tree.len() > 1 { + let left = tree.pop_front().unwrap(); + let level = left.borrow().level; + let right = if level != tree[0].borrow().level { + let node = Rc::new(RefCell::new(TreeNode::new_empty(level, seq_num))); + seq_num += 1; + node + } else { + tree.pop_front().unwrap() + }; + let mut hashed_parent = EMPTY; + + hashed_parent + .copy_from_slice(hashv(&[&left.borrow().node, &right.borrow().node]).as_ref()); + let parent = Rc::new(RefCell::new(TreeNode::new( + hashed_parent, + left.clone(), + right.clone(), + level + 1, + seq_num, + ))); + left.borrow_mut().assign_parent(parent.clone()); + right.borrow_mut().assign_parent(parent.clone()); + tree.push_back(parent); + seq_num += 1; + } + + let root = tree[0].borrow().node; + root + } + + /// Traverses TreeNodes upwards to root from a Leaf TreeNode + /// hashing along the way + pub fn get_proof_of_leaf(&self, idx: usize) -> Vec { + let mut proof = vec![]; + let mut node = self.leaf_nodes[idx].clone(); + loop { + let ref_node = node.clone(); + if ref_node.borrow().parent.is_none() { + break; + } + let parent = ref_node.borrow().parent.as_ref().unwrap().clone(); + if parent.borrow().left.as_ref().unwrap().borrow().id == ref_node.borrow().id { + proof.push(parent.borrow().right.as_ref().unwrap().borrow().node); + } else { + proof.push(parent.borrow().left.as_ref().unwrap().borrow().node); + } + node = parent; + } + proof + } + + /// Updates root from an updated leaf node set at index: `idx` + fn update_root_from_leaf(&mut self, leaf_idx: usize) { + let mut node = self.leaf_nodes[leaf_idx].clone(); + loop { + let ref_node = node.clone(); + if ref_node.borrow().parent.is_none() { + self.root = ref_node.borrow().node; + break; + } + let parent = ref_node.borrow().parent.as_ref().unwrap().clone(); + let hash = if parent.borrow().left.as_ref().unwrap().borrow().id == ref_node.borrow().id + { + hashv(&[ + &ref_node.borrow().node, + &parent.borrow().right.as_ref().unwrap().borrow().node, + ]) + } else { + hashv(&[ + &parent.borrow().left.as_ref().unwrap().borrow().node, + &ref_node.borrow().node, + ]) + }; + node = parent; + node.borrow_mut().node.copy_from_slice(hash.as_ref()); + } + } + + pub fn get_node(&self, idx: usize) -> Node { + self.leaf_nodes[idx].borrow().node + } + + pub fn get_root(&self) -> Node { + self.root + } + + pub fn add_leaf(&mut self, leaf: Node, leaf_idx: usize) { + self.leaf_nodes[leaf_idx].borrow_mut().node = leaf; + self.update_root_from_leaf(leaf_idx) + } + + pub fn remove_leaf(&mut self, leaf_idx: usize) { + self.leaf_nodes[leaf_idx].borrow_mut().node = EMPTY; + self.update_root_from_leaf(leaf_idx) + } + + pub fn get_leaf(&self, leaf_idx: usize) -> Node { + self.leaf_nodes[leaf_idx].borrow().node + } +} + +#[derive(Clone)] +pub struct TreeNode { + pub node: Node, + left: Option>>, + right: Option>>, + parent: Option>>, + level: u32, + /// ID needed to figure out whether we came from left or right child node + /// when hashing path upwards + id: u128, +} + +impl TreeNode { + pub fn new( + node: Node, + left: Rc>, + right: Rc>, + level: u32, + id: u128, + ) -> Self { + Self { + node, + left: Some(left), + right: Some(right), + parent: None, + level, + id, + } + } + + pub fn new_empty(level: u32, id: u128) -> Self { + Self { + node: empty_node(level), + left: None, + right: None, + parent: None, + level, + id, + } + } + + /// Allows to propagate parent assignment + pub fn assign_parent(&mut self, parent: Rc>) { + self.parent = Some(parent); + } +} + +/// Calculates hash of empty nodes up to level i +/// TODO: cache this +pub fn empty_node(level: u32) -> Node { + let mut data = EMPTY; + if level != 0 { + let lower_empty = empty_node(level - 1); + let hash = hashv(&[&lower_empty, &lower_empty]); + data.copy_from_slice(hash.as_ref()); + } + data +} diff --git a/managed-token/README.md b/managed-token/README.md new file mode 100644 index 00000000000..95528a5a081 --- /dev/null +++ b/managed-token/README.md @@ -0,0 +1,10 @@ +# Managed Token + +On-chain program for "managed tokens", SPL tokens that are perpetually frozen, +and must be used through this program, which will thaw the account, perform an +instruction, and re-freeze the account. + +## Audit + +The repository [README](https://github.com/solana-labs/solana-program-library#audits) +contains information about program audits. diff --git a/managed-token/program/Cargo.toml b/managed-token/program/Cargo.toml new file mode 100644 index 00000000000..e7ce24bfad2 --- /dev/null +++ b/managed-token/program/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "spl-managed-token" +version = "0.1.0" +description = "Solana Program Library Token Swap" +authors = ["Solana Labs Maintainers "] +repository = "https://github.com/solana-labs/solana-program-library" +license = "Apache-2.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +crate-type = ["cdylib", "lib"] +name = "spl_managed_token" + +[features] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +cpi = ["no-entrypoint"] +default = [] +test = [] + +[dependencies] +borsh = "1.5.3" +shank = "^0.4.2" +solana-program = "2.1.0" +spl-associated-token-account = { version = "6.0.0", features = [ + "no-entrypoint", +] } +spl-associated-token-account-client = { version = "2.0.0" } +spl-token = { version = "7.0", features = [ + "no-entrypoint", +] } +thiserror = "^2.0.9" + +[dev-dependencies] +solana-program-test = "2.1.0" +solana-sdk = "2.1.0" diff --git a/managed-token/program/build.sh b/managed-token/program/build.sh new file mode 100755 index 00000000000..85b31534dfc --- /dev/null +++ b/managed-token/program/build.sh @@ -0,0 +1,6 @@ +cargo build-bpf +cd ../sdk +yarn +yarn solita +cd - + diff --git a/managed-token/program/src/accounts.rs b/managed-token/program/src/accounts.rs new file mode 100644 index 00000000000..94f980aa6ef --- /dev/null +++ b/managed-token/program/src/accounts.rs @@ -0,0 +1,498 @@ +use { + crate::assert_with_msg, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + program_error::ProgramError, + system_program, + }, +}; + +pub struct InitializeMint<'a, 'info> { + pub mint: &'a AccountInfo<'info>, + pub payer: &'a AccountInfo<'info>, + pub upstream_authority: &'a AccountInfo<'info>, + pub system_program: &'a AccountInfo<'info>, + pub token_program: &'a AccountInfo<'info>, +} + +impl<'a, 'info> InitializeMint<'a, 'info> { + pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result { + let account_iter = &mut accounts.iter(); + let ctx = Self { + mint: next_account_info(account_iter)?, + payer: next_account_info(account_iter)?, + upstream_authority: next_account_info(account_iter)?, + system_program: next_account_info(account_iter)?, + token_program: next_account_info(account_iter)?, + }; + assert_with_msg( + ctx.mint.data_is_empty(), + ProgramError::InvalidAccountData, + "Mint account must be uninitialized", + )?; + assert_with_msg( + ctx.mint.owner == &system_program::id(), + ProgramError::IllegalOwner, + "Mint account must be owned by the System Program when uninitialized", + )?; + assert_with_msg( + ctx.token_program.key == &spl_token::id(), + ProgramError::InvalidInstructionData, + "Invalid key supplied for Token Program", + )?; + assert_with_msg( + ctx.system_program.key == &system_program::id(), + ProgramError::InvalidInstructionData, + "Invalid key supplied for System Program", + )?; + assert_with_msg( + ctx.mint.is_writable, + ProgramError::InvalidInstructionData, + "Mint account must be writable", + )?; + assert_with_msg( + ctx.payer.is_writable, + ProgramError::InvalidInstructionData, + "Payer account must be writable (lamport balance will change)", + )?; + assert_with_msg( + ctx.payer.is_signer, + ProgramError::MissingRequiredSignature, + "Payer must sign for initialization", + )?; + Ok(ctx) + } +} + +pub struct InitializeAccount<'a, 'info> { + pub token_account: &'a AccountInfo<'info>, + pub owner: &'a AccountInfo<'info>, + pub payer: &'a AccountInfo<'info>, + pub upstream_authority: &'a AccountInfo<'info>, + pub freeze_authority: &'a AccountInfo<'info>, + pub mint: &'a AccountInfo<'info>, + pub system_program: &'a AccountInfo<'info>, + pub associated_token_program: &'a AccountInfo<'info>, + pub token_program: &'a AccountInfo<'info>, +} + +impl<'a, 'info> InitializeAccount<'a, 'info> { + pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result { + let account_iter = &mut accounts.iter(); + let ctx = Self { + token_account: next_account_info(account_iter)?, + owner: next_account_info(account_iter)?, + payer: next_account_info(account_iter)?, + upstream_authority: next_account_info(account_iter)?, + freeze_authority: next_account_info(account_iter)?, + mint: next_account_info(account_iter)?, + system_program: next_account_info(account_iter)?, + associated_token_program: next_account_info(account_iter)?, + token_program: next_account_info(account_iter)?, + }; + assert_with_msg( + ctx.token_account.data_is_empty(), + ProgramError::InvalidAccountData, + "Token account must be uninitialized", + )?; + assert_with_msg( + ctx.token_account.owner == &system_program::id(), + ProgramError::IllegalOwner, + "Token account must be owned by System Program when uninitialized", + )?; + assert_with_msg( + ctx.mint.owner == ctx.token_program.key, + ProgramError::IllegalOwner, + "Mint account must be owned by the Token Program", + )?; + assert_with_msg( + ctx.token_program.key == &spl_token::id(), + ProgramError::InvalidInstructionData, + "Invalid key supplied for Token Program", + )?; + assert_with_msg( + ctx.system_program.key == &system_program::id(), + ProgramError::InvalidInstructionData, + "Invalid key supplied for System Program", + )?; + assert_with_msg( + ctx.associated_token_program.key == &spl_associated_token_account_client::program::id(), + ProgramError::InvalidInstructionData, + "Invalid key supplied for Associataed Token Program", + )?; + assert_with_msg( + ctx.token_account.is_writable, + ProgramError::InvalidInstructionData, + "Token account must be writable", + )?; + assert_with_msg( + ctx.payer.is_writable, + ProgramError::InvalidInstructionData, + "Payer account must be writable (lamport balance will change)", + )?; + assert_with_msg( + ctx.payer.is_signer, + ProgramError::MissingRequiredSignature, + "Payer must sign for initialization", + )?; + assert_with_msg( + ctx.upstream_authority.is_signer, + ProgramError::MissingRequiredSignature, + "Freeze authority must sign for initialization", + )?; + Ok(ctx) + } +} + +pub struct Mint<'a, 'info> { + pub mint: &'a AccountInfo<'info>, + pub token_account: &'a AccountInfo<'info>, + pub upstream_authority: &'a AccountInfo<'info>, + pub freeze_and_mint_authority: &'a AccountInfo<'info>, + pub token_program: &'a AccountInfo<'info>, +} + +impl<'a, 'info> Mint<'a, 'info> { + pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result { + let account_iter = &mut accounts.iter(); + let ctx = Self { + mint: next_account_info(account_iter)?, + token_account: next_account_info(account_iter)?, + upstream_authority: next_account_info(account_iter)?, + freeze_and_mint_authority: next_account_info(account_iter)?, + token_program: next_account_info(account_iter)?, + }; + assert_with_msg( + ctx.mint.owner == ctx.token_program.key, + ProgramError::IllegalOwner, + "Mint account must be owned by the Token Program", + )?; + assert_with_msg( + ctx.token_account.owner == ctx.token_program.key, + ProgramError::IllegalOwner, + "Token account must be owned by the Token Program", + )?; + assert_with_msg( + ctx.token_program.key == &spl_token::id(), + ProgramError::InvalidInstructionData, + "Invalid key supplied for Token Program", + )?; + assert_with_msg( + ctx.mint.is_writable, + ProgramError::InvalidInstructionData, + "Mint must be writable", + )?; + assert_with_msg( + ctx.token_account.is_writable, + ProgramError::InvalidInstructionData, + "Token Account must be writable", + )?; + assert_with_msg( + ctx.upstream_authority.is_signer, + ProgramError::MissingRequiredSignature, + "Freeze authority must sign for modification", + )?; + Ok(ctx) + } +} + +pub struct Burn<'a, 'info> { + pub mint: &'a AccountInfo<'info>, + pub token_account: &'a AccountInfo<'info>, + pub owner: &'a AccountInfo<'info>, + pub upstream_authority: &'a AccountInfo<'info>, + pub freeze_authority: &'a AccountInfo<'info>, + pub token_program: &'a AccountInfo<'info>, +} + +impl<'a, 'info> Burn<'a, 'info> { + pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result { + let account_iter = &mut accounts.iter(); + let ctx = Self { + mint: next_account_info(account_iter)?, + token_account: next_account_info(account_iter)?, + owner: next_account_info(account_iter)?, + upstream_authority: next_account_info(account_iter)?, + freeze_authority: next_account_info(account_iter)?, + token_program: next_account_info(account_iter)?, + }; + assert_with_msg( + ctx.mint.owner == ctx.token_program.key, + ProgramError::IllegalOwner, + "Mint account must be owned by the Token Program", + )?; + assert_with_msg( + ctx.token_account.owner == ctx.token_program.key, + ProgramError::IllegalOwner, + "Token account must be owned by the Token Program", + )?; + assert_with_msg( + ctx.token_program.key == &spl_token::id(), + ProgramError::InvalidInstructionData, + "Invalid key supplied for Token Program", + )?; + assert_with_msg( + ctx.mint.is_writable, + ProgramError::InvalidInstructionData, + "Mint must be writable", + )?; + assert_with_msg( + ctx.token_account.is_writable, + ProgramError::InvalidInstructionData, + "Token Account must be writable", + )?; + assert_with_msg( + ctx.upstream_authority.is_signer, + ProgramError::MissingRequiredSignature, + "Freeze authority must sign for modification", + )?; + assert_with_msg( + ctx.owner.is_signer, + ProgramError::MissingRequiredSignature, + "Owner must sign for modification", + )?; + Ok(ctx) + } +} + +pub struct Transfer<'a, 'info> { + pub src_account: &'a AccountInfo<'info>, + pub dst_account: &'a AccountInfo<'info>, + pub mint: &'a AccountInfo<'info>, + pub owner: &'a AccountInfo<'info>, + pub upstream_authority: &'a AccountInfo<'info>, + pub freeze_authority: &'a AccountInfo<'info>, + pub token_program: &'a AccountInfo<'info>, +} + +impl<'a, 'info> Transfer<'a, 'info> { + pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result { + let account_iter = &mut accounts.iter(); + let ctx = Self { + src_account: next_account_info(account_iter)?, + dst_account: next_account_info(account_iter)?, + mint: next_account_info(account_iter)?, + owner: next_account_info(account_iter)?, + upstream_authority: next_account_info(account_iter)?, + freeze_authority: next_account_info(account_iter)?, + token_program: next_account_info(account_iter)?, + }; + assert_with_msg( + ctx.mint.owner == &spl_token::id(), + ProgramError::IllegalOwner, + "Mint account must be owned by the Token Program", + )?; + assert_with_msg( + ctx.src_account.owner == &spl_token::id(), + ProgramError::IllegalOwner, + "Source token account must be owned by the Token Program", + )?; + assert_with_msg( + ctx.dst_account.owner == &spl_token::id(), + ProgramError::IllegalOwner, + "Destination token account must be owned by the Token Program", + )?; + assert_with_msg( + ctx.token_program.key == &spl_token::id(), + ProgramError::InvalidInstructionData, + "Invalid key supplied for Token Program", + )?; + assert_with_msg( + ctx.src_account.is_writable, + ProgramError::InvalidInstructionData, + "Source token account must be writable", + )?; + assert_with_msg( + ctx.dst_account.is_writable, + ProgramError::InvalidInstructionData, + "Destination token account must be writable", + )?; + assert_with_msg( + ctx.owner.is_signer, + ProgramError::MissingRequiredSignature, + "Owner must sign for modification", + )?; + assert_with_msg( + ctx.upstream_authority.is_signer, + ProgramError::MissingRequiredSignature, + "Freeze authority must sign for modification", + )?; + Ok(ctx) + } +} + +pub struct Close<'a, 'info> { + pub token_account: &'a AccountInfo<'info>, + pub dst_account: &'a AccountInfo<'info>, + pub mint: &'a AccountInfo<'info>, + pub owner: &'a AccountInfo<'info>, + pub upstream_authority: &'a AccountInfo<'info>, + pub freeze_authority: &'a AccountInfo<'info>, + pub token_program: &'a AccountInfo<'info>, +} + +impl<'a, 'info> Close<'a, 'info> { + pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result { + let account_iter = &mut accounts.iter(); + let ctx = Self { + token_account: next_account_info(account_iter)?, + dst_account: next_account_info(account_iter)?, + mint: next_account_info(account_iter)?, + owner: next_account_info(account_iter)?, + upstream_authority: next_account_info(account_iter)?, + freeze_authority: next_account_info(account_iter)?, + token_program: next_account_info(account_iter)?, + }; + assert_with_msg( + ctx.mint.owner == ctx.token_program.key, + ProgramError::IllegalOwner, + "Mint account must be owned by the Token Program", + )?; + assert_with_msg( + ctx.token_account.owner == ctx.token_program.key, + ProgramError::IllegalOwner, + "Token account must be owned by the Token Program", + )?; + assert_with_msg( + ctx.dst_account.owner == &system_program::id(), + ProgramError::IllegalOwner, + "Destination account must be owned by the System Program", + )?; + assert_with_msg( + ctx.token_program.key == &spl_token::id(), + ProgramError::InvalidInstructionData, + "Invalid key supplied for Token Program", + )?; + assert_with_msg( + ctx.token_account.is_writable, + ProgramError::InvalidInstructionData, + "Token Account must be writable", + )?; + assert_with_msg( + ctx.dst_account.is_writable, + ProgramError::InvalidInstructionData, + "Destination account must be writable", + )?; + assert_with_msg( + ctx.owner.is_signer, + ProgramError::MissingRequiredSignature, + "Owner must sign for close", + )?; + assert_with_msg( + ctx.upstream_authority.is_signer, + ProgramError::MissingRequiredSignature, + "Freeze authority must sign for close", + )?; + Ok(ctx) + } +} + +pub struct Approve<'a, 'info> { + pub mint: &'a AccountInfo<'info>, + pub token_account: &'a AccountInfo<'info>, + pub owner: &'a AccountInfo<'info>, + pub upstream_authority: &'a AccountInfo<'info>, + pub delegate: &'a AccountInfo<'info>, + pub freeze_authority: &'a AccountInfo<'info>, + pub token_program: &'a AccountInfo<'info>, +} + +impl<'a, 'info> Approve<'a, 'info> { + pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result { + let account_iter = &mut accounts.iter(); + let ctx = Self { + mint: next_account_info(account_iter)?, + token_account: next_account_info(account_iter)?, + owner: next_account_info(account_iter)?, + upstream_authority: next_account_info(account_iter)?, + delegate: next_account_info(account_iter)?, + freeze_authority: next_account_info(account_iter)?, + token_program: next_account_info(account_iter)?, + }; + assert_with_msg( + ctx.mint.owner == &spl_token::id(), + ProgramError::IllegalOwner, + "Mint account must be owned by the Token Program", + )?; + assert_with_msg( + ctx.token_account.owner == ctx.token_program.key, + ProgramError::IllegalOwner, + "Token account must be owned by the Token Program", + )?; + assert_with_msg( + ctx.token_account.is_writable, + ProgramError::InvalidInstructionData, + "Token Account must be writable", + )?; + assert_with_msg( + ctx.token_program.key == &spl_token::id(), + ProgramError::InvalidInstructionData, + "Invalid key supplied for Token Program", + )?; + assert_with_msg( + ctx.upstream_authority.is_signer, + ProgramError::MissingRequiredSignature, + "Freeze authority must sign for modification", + )?; + assert_with_msg( + ctx.owner.is_signer, + ProgramError::MissingRequiredSignature, + "Owner must sign for modification", + )?; + Ok(ctx) + } +} + +pub struct Revoke<'a, 'info> { + pub mint: &'a AccountInfo<'info>, + pub token_account: &'a AccountInfo<'info>, + pub owner: &'a AccountInfo<'info>, + pub upstream_authority: &'a AccountInfo<'info>, + pub freeze_authority: &'a AccountInfo<'info>, + pub token_program: &'a AccountInfo<'info>, +} + +impl<'a, 'info> Revoke<'a, 'info> { + pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result { + let account_iter = &mut accounts.iter(); + let ctx = Self { + mint: next_account_info(account_iter)?, + token_account: next_account_info(account_iter)?, + owner: next_account_info(account_iter)?, + upstream_authority: next_account_info(account_iter)?, + freeze_authority: next_account_info(account_iter)?, + token_program: next_account_info(account_iter)?, + }; + assert_with_msg( + ctx.mint.owner == &spl_token::id(), + ProgramError::IllegalOwner, + "Mint account must be owned by the Token Program", + )?; + assert_with_msg( + ctx.token_account.owner == ctx.token_program.key, + ProgramError::IllegalOwner, + "Token account must be owned by the Token Program", + )?; + assert_with_msg( + ctx.token_account.is_writable, + ProgramError::InvalidInstructionData, + "Token Account must be writable", + )?; + assert_with_msg( + ctx.token_program.key == &spl_token::id(), + ProgramError::InvalidInstructionData, + "Invalid key supplied for Token Program", + )?; + assert_with_msg( + ctx.upstream_authority.is_signer, + ProgramError::MissingRequiredSignature, + "Freeze authority must sign for modification", + )?; + assert_with_msg( + ctx.owner.is_signer, + ProgramError::MissingRequiredSignature, + "Owner must sign for modification", + )?; + Ok(ctx) + } +} diff --git a/managed-token/program/src/instruction.rs b/managed-token/program/src/instruction.rs new file mode 100644 index 00000000000..bf22c82c817 --- /dev/null +++ b/managed-token/program/src/instruction.rs @@ -0,0 +1,296 @@ +use { + crate::get_authority, + borsh::{BorshDeserialize, BorshSerialize}, + shank::ShankInstruction, + solana_program::{ + instruction::{AccountMeta, Instruction}, + program_error::ProgramError, + pubkey::Pubkey, + system_program, + }, + spl_associated_token_account_client::address::get_associated_token_address, +}; + +#[derive(Debug, Clone, ShankInstruction, BorshSerialize, BorshDeserialize)] +#[rustfmt::skip] +pub enum ManagedTokenInstruction { + + #[account(0, writable, signer, name = "mint")] + #[account(1, writable, signer, name = "payer")] + #[account(2, name = "upstream_authority")] + #[account(3, name = "system_program", desc = "System program")] + #[account(4, name = "token_program", desc = "Token program")] + InitializeMint { + decimals: u8, + }, + + #[account(0, writable, name = "account")] + #[account(1, name = "owner")] + #[account(2, writable, signer, name = "payer")] + #[account(3, signer, name = "upstream_authority")] + #[account(4, name = "freeze_authority")] + #[account(5, name = "mint")] + #[account(6, name = "system_program", desc = "System program")] + #[account( + 7, + name = "associated_token_program", + desc = "Associated Token program" + )] + #[account(8, name = "token_program", desc = "Token program")] + InitializeAccount, + + #[account(0, writable, name = "src_account")] + #[account(1, writable, name = "dst_account")] + #[account(2, name = "mint")] + #[account(3, signer, name = "owner")] + #[account(4, signer, name = "upstream_authority")] + #[account(5, name = "freeze_authority")] + #[account(6, name = "token_program", desc = "Token program")] + Transfer { amount: u64 }, + + #[account(0, writable, name = "mint")] + #[account(1, writable, name = "account")] + #[account(2, signer, name = "upstream_authority")] + #[account(3, name = "freeze_authority")] + #[account(4, name = "token_program", desc = "Token program")] + MintTo { amount: u64 }, + + #[account(0, writable, name = "mint")] + #[account(1, writable, name = "account")] + #[account(2, signer, name = "owner")] + #[account(3, signer, name = "upstream_authority")] + #[account(4, name = "freeze_authority")] + #[account(5, name = "token_program", desc = "Token program")] + Burn { amount: u64 }, + + #[account(0, writable, name = "account")] + #[account(1, writable, name = "destination")] + #[account(2, name = "mint")] + #[account(3, signer, name = "owner")] + #[account(4, signer, name = "upstream_authority")] + #[account(5, name = "freeze_authority")] + #[account(6, name = "token_program", desc = "Token program")] + CloseAccount, + + #[account(0, name = "mint")] + #[account(1, writable, name = "account")] + #[account(2, signer, name = "owner")] + #[account(3, signer, name = "upstream_authority")] + #[account(4, name = "delegate")] + #[account(5, name = "freeze_authority")] + #[account(6, name = "token_program", desc = "Token program")] + Approve { amount: u64 }, + + #[account(0, name = "mint")] + #[account(1, writable, name = "account")] + #[account(2, signer, name = "owner")] + #[account(3, signer, name = "upstream_authority")] + #[account(4, name = "freeze_authority")] + #[account(5, name = "token_program", desc = "Token program")] + Revoke, +} + +pub fn create_initialize_mint_instruction( + mint: &Pubkey, + payer: &Pubkey, + upstream_authority: &Pubkey, + decimals: u8, +) -> Result { + Ok(Instruction { + program_id: crate::id(), + accounts: vec![ + AccountMeta::new(*mint, true), + AccountMeta::new(*payer, true), + AccountMeta::new_readonly(*upstream_authority, false), + AccountMeta::new_readonly(system_program::id(), false), + AccountMeta::new_readonly(spl_token::id(), false), + ], + data: borsh::to_vec(&ManagedTokenInstruction::InitializeMint { decimals })?, + }) +} + +pub fn create_initialize_account_instruction( + mint: &Pubkey, + owner: &Pubkey, + payer: &Pubkey, + upstream_authority: &Pubkey, +) -> Result { + let account = get_associated_token_address(owner, mint); + let (freeze_authority, _) = get_authority(upstream_authority); + Ok(Instruction { + program_id: crate::id(), + accounts: vec![ + AccountMeta::new(account, false), + AccountMeta::new_readonly(*owner, false), + AccountMeta::new(*payer, true), + AccountMeta::new_readonly(*upstream_authority, true), + AccountMeta::new_readonly(freeze_authority, false), + AccountMeta::new_readonly(*mint, false), + AccountMeta::new_readonly(system_program::id(), false), + AccountMeta::new_readonly(spl_associated_token_account_client::program::id(), false), + AccountMeta::new_readonly(spl_token::id(), false), + ], + data: borsh::to_vec(&ManagedTokenInstruction::InitializeAccount)?, + }) +} + +pub fn create_mint_to_instruction( + mint: &Pubkey, + owner: &Pubkey, + upstream_authority: &Pubkey, + amount: u64, +) -> Result { + let account = get_associated_token_address(owner, mint); + let (authority, _) = get_authority(upstream_authority); + Ok(Instruction { + program_id: crate::id(), + accounts: vec![ + AccountMeta::new(*mint, false), + AccountMeta::new(account, false), + AccountMeta::new_readonly(*upstream_authority, true), + AccountMeta::new_readonly(authority, false), + AccountMeta::new_readonly(spl_token::id(), false), + ], + data: borsh::to_vec(&ManagedTokenInstruction::MintTo { amount })?, + }) +} + +pub fn create_transfer_instruction( + src: &Pubkey, + dst: &Pubkey, + mint: &Pubkey, + upstream_authority: &Pubkey, + amount: u64, +) -> Result { + let src_account = get_associated_token_address(src, mint); + let dst_account = get_associated_token_address(dst, mint); + let (freeze_authority, _) = get_authority(upstream_authority); + Ok(Instruction { + program_id: crate::id(), + accounts: vec![ + AccountMeta::new(src_account, false), + AccountMeta::new(dst_account, false), + AccountMeta::new_readonly(*mint, false), + AccountMeta::new_readonly(*src, true), + AccountMeta::new_readonly(*upstream_authority, true), + AccountMeta::new_readonly(freeze_authority, false), + AccountMeta::new_readonly(spl_token::id(), false), + ], + data: borsh::to_vec(&ManagedTokenInstruction::Transfer { amount })?, + }) +} + +pub fn create_transfer_with_delegate_instruction( + src: &Pubkey, + dst: &Pubkey, + delegate: &Pubkey, + mint: &Pubkey, + upstream_authority: &Pubkey, + amount: u64, +) -> Result { + let src_account = get_associated_token_address(src, mint); + let dst_account = get_associated_token_address(dst, mint); + let (freeze_authority, _) = get_authority(upstream_authority); + Ok(Instruction { + program_id: crate::id(), + accounts: vec![ + AccountMeta::new(src_account, false), + AccountMeta::new(dst_account, false), + AccountMeta::new_readonly(*mint, false), + AccountMeta::new_readonly(*delegate, true), + AccountMeta::new_readonly(*upstream_authority, true), + AccountMeta::new_readonly(freeze_authority, false), + AccountMeta::new_readonly(spl_token::id(), false), + ], + data: borsh::to_vec(&ManagedTokenInstruction::Transfer { amount })?, + }) +} + +pub fn create_burn_instruction( + mint: &Pubkey, + owner: &Pubkey, + upstream_authority: &Pubkey, + amount: u64, +) -> Result { + let account = get_associated_token_address(owner, mint); + let (freeze_authority, _) = get_authority(upstream_authority); + Ok(Instruction { + program_id: crate::id(), + accounts: vec![ + AccountMeta::new(*mint, false), + AccountMeta::new(account, false), + AccountMeta::new_readonly(*owner, true), + AccountMeta::new_readonly(*upstream_authority, true), + AccountMeta::new_readonly(freeze_authority, false), + AccountMeta::new_readonly(spl_token::id(), false), + ], + data: borsh::to_vec(&ManagedTokenInstruction::Burn { amount })?, + }) +} + +pub fn create_close_account_instruction( + mint: &Pubkey, + owner: &Pubkey, + upstream_authority: &Pubkey, +) -> Result { + let account = get_associated_token_address(owner, mint); + let (freeze_authority, _) = get_authority(upstream_authority); + Ok(Instruction { + program_id: crate::id(), + accounts: vec![ + AccountMeta::new(account, false), + AccountMeta::new(*owner, false), + AccountMeta::new_readonly(*mint, false), + AccountMeta::new_readonly(*owner, true), + AccountMeta::new_readonly(*upstream_authority, true), + AccountMeta::new_readonly(freeze_authority, false), + AccountMeta::new_readonly(spl_token::id(), false), + ], + data: borsh::to_vec(&ManagedTokenInstruction::CloseAccount)?, + }) +} + +pub fn create_approve_instruction( + mint: &Pubkey, + owner: &Pubkey, + delegate: &Pubkey, + upstream_authority: &Pubkey, + amount: u64, +) -> Result { + let (freeze_authority, _) = get_authority(upstream_authority); + let account = get_associated_token_address(owner, mint); + Ok(Instruction { + program_id: crate::id(), + accounts: vec![ + AccountMeta::new_readonly(*mint, false), + AccountMeta::new(account, false), + AccountMeta::new_readonly(*owner, true), + AccountMeta::new_readonly(*upstream_authority, true), + AccountMeta::new_readonly(*delegate, false), + AccountMeta::new_readonly(freeze_authority, false), + AccountMeta::new_readonly(spl_token::id(), false), + ], + data: borsh::to_vec(&ManagedTokenInstruction::Approve { amount })?, + }) +} + +pub fn create_revoke_instruction( + mint: &Pubkey, + owner: &Pubkey, + upstream_authority: &Pubkey, +) -> Result { + let (freeze_authority, _) = get_authority(upstream_authority); + let account = get_associated_token_address(owner, mint); + Ok(Instruction { + program_id: crate::id(), + accounts: vec![ + AccountMeta::new_readonly(*mint, false), + AccountMeta::new(account, false), + AccountMeta::new_readonly(*owner, true), + AccountMeta::new_readonly(*upstream_authority, true), + AccountMeta::new_readonly(freeze_authority, false), + AccountMeta::new_readonly(spl_token::id(), false), + ], + data: borsh::to_vec(&ManagedTokenInstruction::Revoke)?, + }) +} diff --git a/managed-token/program/src/lib.rs b/managed-token/program/src/lib.rs new file mode 100644 index 00000000000..389694ec363 --- /dev/null +++ b/managed-token/program/src/lib.rs @@ -0,0 +1,265 @@ +solana_program::declare_id!("mTok58Lg4YfcmwqyrDHpf7ogp599WRhzb6PxjaBqAxS"); + +use { + borsh::BorshDeserialize, + solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, msg, program::invoke, + program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, rent::Rent, + system_instruction, sysvar::Sysvar, + }, + spl_associated_token_account::instruction::create_associated_token_account, +}; + +#[track_caller] +#[inline(always)] +pub fn assert_with_msg(v: bool, err: impl Into, msg: &str) -> ProgramResult { + if v { + Ok(()) + } else { + let caller = std::panic::Location::caller(); + msg!("{}. \n{}", msg, caller); + Err(err.into()) + } +} + +pub mod accounts; +pub mod instruction; +pub mod token; +use { + accounts::{Approve, Burn, Close, InitializeAccount, InitializeMint, Mint, Revoke, Transfer}, + instruction::ManagedTokenInstruction, + token::{approve, burn, close, freeze, initialize_mint, mint_to, revoke, thaw, transfer}, +}; + +#[cfg(not(feature = "no-entrypoint"))] +solana_program::entrypoint!(process_instruction); + +#[inline] +fn get_authority_seeds_checked( + upstream_authority: &Pubkey, + expected_key: &Pubkey, +) -> Result>, ProgramError> { + let (key, seeds) = get_authority(upstream_authority); + assert_with_msg( + expected_key == &key, + ProgramError::InvalidInstructionData, + "Invalid authority", + )?; + Ok(seeds) +} + +#[inline] +fn get_authority(upstream_authority: &Pubkey) -> (Pubkey, Vec>) { + let mut seeds = vec![upstream_authority.as_ref().to_vec()]; + let (key, bump) = Pubkey::find_program_address( + &seeds.iter().map(|s| s.as_slice()).collect::>(), + &crate::id(), + ); + seeds.push(vec![bump]); + (key, seeds) +} + +pub fn process_instruction( + _program_id: &Pubkey, + accounts: &[AccountInfo], + instruction_data: &[u8], +) -> ProgramResult { + let instruction = ManagedTokenInstruction::try_from_slice(instruction_data)?; + match instruction { + ManagedTokenInstruction::InitializeMint { decimals } => { + msg!("ManagedTokenInstruction::InitializeMint"); + process_initialize_mint(accounts, decimals) + } + ManagedTokenInstruction::InitializeAccount => { + msg!("ManagedTokenInstruction::InitializeAccount"); + process_initialize_account(accounts) + } + ManagedTokenInstruction::Transfer { amount } => { + msg!("ManagedTokenInstruction::Transfer"); + process_transfer(accounts, amount) + } + ManagedTokenInstruction::MintTo { amount } => { + msg!("ManagedTokenInstruction::MintTo"); + process_mint_to(accounts, amount) + } + ManagedTokenInstruction::Burn { amount } => { + msg!("ManagedTokenInstruction::Burn"); + process_burn(accounts, amount) + } + ManagedTokenInstruction::CloseAccount => { + msg!("ManagedTokenInstruction::CloseAccount"); + process_close(accounts) + } + ManagedTokenInstruction::Approve { amount } => { + msg!("ManagedTokenInstruction::Approve"); + process_approve(accounts, amount) + } + ManagedTokenInstruction::Revoke => { + msg!("ManagedTokenInstruction::Revoke"); + process_revoke(accounts) + } + } +} + +pub fn process_initialize_mint(accounts: &[AccountInfo], decimals: u8) -> ProgramResult { + let InitializeMint { + mint, + payer, + upstream_authority, + system_program, + token_program, + } = InitializeMint::load(accounts)?; + let space = spl_token::state::Mint::LEN; + invoke( + &system_instruction::create_account( + payer.key, + mint.key, + Rent::get()?.minimum_balance(space), + space as u64, + token_program.key, + ), + &[payer.clone(), mint.clone(), system_program.clone()], + )?; + let (authority, _) = get_authority(upstream_authority.key); + initialize_mint(&authority, &authority, mint, token_program, decimals) +} + +pub fn process_initialize_account(accounts: &[AccountInfo]) -> ProgramResult { + let InitializeAccount { + token_account, + owner, + payer, + upstream_authority, + freeze_authority, + mint, + system_program, + associated_token_program, + token_program, + } = InitializeAccount::load(accounts)?; + invoke( + &create_associated_token_account(payer.key, owner.key, mint.key, token_program.key), + &[ + associated_token_program.clone(), + payer.clone(), + owner.clone(), + token_account.clone(), + mint.clone(), + system_program.clone(), + token_program.clone(), + ], + )?; + let seeds = get_authority_seeds_checked(upstream_authority.key, freeze_authority.key)?; + freeze(freeze_authority, mint, token_account, token_program, &seeds) +} + +pub fn process_transfer(accounts: &[AccountInfo], amount: u64) -> ProgramResult { + let Transfer { + src_account, + dst_account, + mint, + owner, + upstream_authority, + freeze_authority, + token_program, + } = Transfer::load(accounts)?; + let seeds = get_authority_seeds_checked(upstream_authority.key, freeze_authority.key)?; + thaw(freeze_authority, mint, src_account, token_program, &seeds)?; + thaw(freeze_authority, mint, dst_account, token_program, &seeds)?; + transfer(src_account, dst_account, owner, token_program, amount)?; + freeze(freeze_authority, mint, dst_account, token_program, &seeds)?; + freeze(freeze_authority, mint, src_account, token_program, &seeds) +} + +pub fn process_mint_to(accounts: &[AccountInfo], amount: u64) -> ProgramResult { + let Mint { + mint, + token_account, + upstream_authority, + freeze_and_mint_authority: authority, + token_program, + } = Mint::load(accounts)?; + let authority_seeds = get_authority_seeds_checked(upstream_authority.key, authority.key)?; + thaw( + authority, + mint, + token_account, + token_program, + &authority_seeds, + )?; + mint_to( + mint, + token_account, + authority, + token_program, + amount, + &authority_seeds, + )?; + freeze( + authority, + mint, + token_account, + token_program, + &authority_seeds, + ) +} + +pub fn process_burn(accounts: &[AccountInfo], amount: u64) -> ProgramResult { + let Burn { + mint, + token_account, + owner, + upstream_authority, + freeze_authority, + token_program, + } = Burn::load(accounts)?; + let seeds = get_authority_seeds_checked(upstream_authority.key, freeze_authority.key)?; + thaw(freeze_authority, mint, token_account, token_program, &seeds)?; + burn(mint, token_account, owner, token_program, amount)?; + freeze(freeze_authority, mint, token_account, token_program, &seeds) +} + +pub fn process_close(accounts: &[AccountInfo]) -> ProgramResult { + let Close { + token_account, + dst_account, + mint, + owner, + upstream_authority, + freeze_authority, + token_program, + } = Close::load(accounts)?; + let seeds = get_authority_seeds_checked(upstream_authority.key, freeze_authority.key)?; + thaw(freeze_authority, mint, token_account, token_program, &seeds)?; + close(token_account, dst_account, owner, token_program) +} + +pub fn process_approve(accounts: &[AccountInfo], amount: u64) -> ProgramResult { + let Approve { + mint, + token_account, + owner, + upstream_authority, + delegate, + freeze_authority, + token_program, + } = Approve::load(accounts)?; + let seeds = get_authority_seeds_checked(upstream_authority.key, freeze_authority.key)?; + thaw(freeze_authority, mint, token_account, token_program, &seeds)?; + approve(token_account, owner, delegate, token_program, amount)?; + freeze(freeze_authority, mint, token_account, token_program, &seeds) +} + +pub fn process_revoke(accounts: &[AccountInfo]) -> ProgramResult { + let Revoke { + mint, + token_account, + owner, + upstream_authority, + freeze_authority, + token_program, + } = Revoke::load(accounts)?; + let seeds = get_authority_seeds_checked(upstream_authority.key, freeze_authority.key)?; + thaw(freeze_authority, mint, token_account, token_program, &seeds)?; + revoke(token_account, owner, token_program)?; + freeze(freeze_authority, mint, token_account, token_program, &seeds) +} diff --git a/managed-token/program/src/token.rs b/managed-token/program/src/token.rs new file mode 100644 index 00000000000..314806dbbf6 --- /dev/null +++ b/managed-token/program/src/token.rs @@ -0,0 +1,211 @@ +use solana_program::{ + account_info::AccountInfo, + entrypoint::ProgramResult, + program::{invoke, invoke_signed}, + pubkey::Pubkey, +}; + +pub(crate) fn initialize_mint<'a, 'b>( + freeze_authority: &Pubkey, + mint_authority: &Pubkey, + mint: &'a AccountInfo<'b>, + token_program: &'a AccountInfo<'b>, + decimals: u8, +) -> ProgramResult { + invoke( + &spl_token::instruction::initialize_mint2( + token_program.key, + mint.key, + mint_authority, + Some(freeze_authority), + decimals, + )?, + &[token_program.clone(), mint.clone()], + ) +} + +pub(crate) fn thaw<'a, 'b>( + freeze_authority: &'a AccountInfo<'b>, + mint: &'a AccountInfo<'b>, + target: &'a AccountInfo<'b>, + token_program: &'a AccountInfo<'b>, + seeds: &[Vec], +) -> ProgramResult { + invoke_signed( + &spl_token::instruction::thaw_account( + token_program.key, + target.key, + mint.key, + freeze_authority.key, + &[], + )?, + &[ + token_program.clone(), + mint.clone(), + freeze_authority.clone(), + target.clone(), + ], + &[&seeds.iter().map(|s| s.as_slice()).collect::>()], + ) +} + +pub(crate) fn freeze<'a, 'b>( + freeze_authority: &'a AccountInfo<'b>, + mint: &'a AccountInfo<'b>, + target: &'a AccountInfo<'b>, + token_program: &'a AccountInfo<'b>, + seeds: &[Vec], +) -> ProgramResult { + invoke_signed( + &spl_token::instruction::freeze_account( + token_program.key, + target.key, + mint.key, + freeze_authority.key, + &[], + )?, + &[ + token_program.clone(), + mint.clone(), + freeze_authority.clone(), + target.clone(), + ], + &[&seeds.iter().map(|s| s.as_slice()).collect::>()], + ) +} + +pub(crate) fn transfer<'a, 'b>( + src: &'a AccountInfo<'b>, + dst: &'a AccountInfo<'b>, + owner: &'a AccountInfo<'b>, + token_program: &'a AccountInfo<'b>, + amount: u64, +) -> ProgramResult { + invoke( + &spl_token::instruction::transfer( + token_program.key, + src.key, + dst.key, + owner.key, + &[], + amount, + )?, + &[ + token_program.clone(), + src.clone(), + dst.clone(), + owner.clone(), + ], + ) +} + +pub(crate) fn mint_to<'a, 'b>( + mint: &'a AccountInfo<'b>, + account: &'a AccountInfo<'b>, + owner: &'a AccountInfo<'b>, + token_program: &'a AccountInfo<'b>, + amount: u64, + seeds: &[Vec], +) -> ProgramResult { + invoke_signed( + &spl_token::instruction::mint_to( + token_program.key, + mint.key, + account.key, + owner.key, + &[], + amount, + )?, + &[ + token_program.clone(), + mint.clone(), + account.clone(), + owner.clone(), + ], + &[&seeds.iter().map(|s| s.as_slice()).collect::>()], + ) +} + +pub(crate) fn burn<'a, 'b>( + mint: &'a AccountInfo<'b>, + account: &'a AccountInfo<'b>, + owner: &'a AccountInfo<'b>, + token_program: &'a AccountInfo<'b>, + amount: u64, +) -> ProgramResult { + invoke( + &spl_token::instruction::burn( + token_program.key, + account.key, + mint.key, + owner.key, + &[], + amount, + )?, + &[ + token_program.clone(), + mint.clone(), + account.clone(), + owner.clone(), + ], + ) +} + +pub(crate) fn approve<'a, 'b>( + account: &'a AccountInfo<'b>, + owner: &'a AccountInfo<'b>, + delegate: &'a AccountInfo<'b>, + token_program: &'a AccountInfo<'b>, + amount: u64, +) -> ProgramResult { + invoke( + &spl_token::instruction::approve( + token_program.key, + account.key, + delegate.key, + owner.key, + &[], + amount, + )?, + &[ + token_program.clone(), + account.clone(), + delegate.clone(), + owner.clone(), + ], + ) +} + +pub(crate) fn revoke<'a, 'b>( + account: &'a AccountInfo<'b>, + owner: &'a AccountInfo<'b>, + token_program: &'a AccountInfo<'b>, +) -> ProgramResult { + invoke( + &spl_token::instruction::revoke(token_program.key, account.key, owner.key, &[])?, + &[token_program.clone(), account.clone(), owner.clone()], + ) +} + +pub(crate) fn close<'a, 'b>( + account: &'a AccountInfo<'b>, + destination: &'a AccountInfo<'b>, + owner: &'a AccountInfo<'b>, + token_program: &'a AccountInfo<'b>, +) -> ProgramResult { + invoke( + &spl_token::instruction::close_account( + token_program.key, + account.key, + destination.key, + owner.key, + &[], + )?, + &[ + token_program.clone(), + destination.clone(), + account.clone(), + owner.clone(), + ], + ) +} diff --git a/managed-token/program/tests/test.rs b/managed-token/program/tests/test.rs new file mode 100644 index 00000000000..3d7600d0237 --- /dev/null +++ b/managed-token/program/tests/test.rs @@ -0,0 +1,312 @@ +use { + solana_program::program_option::COption, + solana_program_test::*, + solana_sdk::{ + commitment_config::CommitmentLevel, + instruction::Instruction, + native_token::LAMPORTS_PER_SOL, + pubkey::Pubkey, + signature::{Keypair, Signature, Signer}, + system_instruction, + transaction::Transaction, + }, + spl_associated_token_account::instruction::create_associated_token_account, + spl_associated_token_account_client::address::get_associated_token_address, + spl_managed_token::instruction::*, + spl_token::state::Account as TokenAccount, +}; + +pub fn sol(amount: f64) -> u64 { + (amount * LAMPORTS_PER_SOL as f64) as u64 +} + +async fn process_transaction( + client: &mut BanksClient, + instructions: Vec, + signers: Vec<&Keypair>, +) -> Result { + let mut tx = Transaction::new_with_payer(&instructions, Some(&signers[0].pubkey())); + tx.partial_sign(&signers, client.get_latest_blockhash().await?); + let sig = tx.signatures[0]; + client + .process_transaction_with_commitment(tx, CommitmentLevel::Confirmed) + .await?; + Ok(sig) +} + +async fn transfer( + context: &mut BanksClient, + payer: &Keypair, + receiver: &Pubkey, + amount: u64, +) -> Result { + let ixs = vec![system_instruction::transfer( + &payer.pubkey(), + receiver, + amount, + )]; + process_transaction(context, ixs, vec![payer]).await +} + +fn spl_managed_token_test() -> ProgramTest { + ProgramTest::new( + "spl_managed_token", + spl_managed_token::id(), + processor!(spl_managed_token::process_instruction), + ) +} + +#[tokio::test] +async fn test_spl_managed_token_basic() { + let mut context = spl_managed_token_test().start_with_context().await; + let lwc = &mut context.banks_client; + let authority = Keypair::new(); + transfer(lwc, &context.payer, &authority.pubkey(), sol(10.0)) + .await + .unwrap(); + let mint = Keypair::new(); + let mint_key = mint.pubkey(); + let create_ix = + create_initialize_mint_instruction(&mint_key, &authority.pubkey(), &authority.pubkey(), 0) + .unwrap(); + process_transaction(lwc, vec![create_ix], vec![&authority, &mint]) + .await + .unwrap(); + + let alice = Keypair::new(); + let alice_key = alice.pubkey(); + let bob = Keypair::new(); + let bob_key = bob.pubkey(); + let eve = Keypair::new(); + let eve_key = eve.pubkey(); + + for k in [&alice_key, &bob_key] { + transfer(lwc, &context.payer, k, sol(1.0)).await.unwrap(); + let create_ata = create_initialize_account_instruction( + &mint_key, + k, + &authority.pubkey(), + &authority.pubkey(), + ) + .unwrap(); + let mint_to_ix = + create_mint_to_instruction(&mint_key, k, &authority.pubkey(), 1000).unwrap(); + process_transaction(lwc, vec![create_ata, mint_to_ix], vec![&authority]) + .await + .unwrap(); + } + + let create_eve = + create_associated_token_account(&authority.pubkey(), &eve_key, &mint_key, &spl_token::id()); + process_transaction(lwc, vec![create_eve], vec![&authority]) + .await + .unwrap(); + + // Try transfer the normal way + let failed_transfer_ix = spl_token::instruction::transfer( + &spl_token::id(), + &get_associated_token_address(&alice_key, &mint_key), + &get_associated_token_address(&bob_key, &mint_key), + &alice_key, + &[], + 100, + ) + .unwrap(); + + assert!( + process_transaction(lwc, vec![failed_transfer_ix], vec![&alice]) + .await + .is_err() + ); + + let eve_ix = + create_transfer_instruction(&alice_key, &eve_key, &mint_key, &authority.pubkey(), 100) + .unwrap(); + + assert!( + process_transaction(lwc, vec![eve_ix], vec![&alice, &authority]) + .await + .is_err() + ); + + let successful_transfer_ix = + create_transfer_instruction(&alice_key, &bob_key, &mint_key, &authority.pubkey(), 100) + .unwrap(); + let burn_ix = create_burn_instruction(&mint_key, &alice_key, &authority.pubkey(), 900).unwrap(); + + process_transaction( + lwc, + vec![successful_transfer_ix, burn_ix], + vec![&alice, &authority], + ) + .await + .unwrap(); +} + +#[tokio::test] +async fn test_spl_managed_token_with_approve_and_revoke() { + let mut context = spl_managed_token_test().start_with_context().await; + let lwc = &mut context.banks_client; + let authority = Keypair::new(); + transfer(lwc, &context.payer, &authority.pubkey(), sol(10.0)) + .await + .unwrap(); + let mint = Keypair::new(); + let mint_key = mint.pubkey(); + let create_ix = + create_initialize_mint_instruction(&mint_key, &authority.pubkey(), &authority.pubkey(), 0) + .unwrap(); + process_transaction(lwc, vec![create_ix], vec![&authority, &mint]) + .await + .unwrap(); + + let alice = Keypair::new(); + let alice_key = alice.pubkey(); + let bob = Keypair::new(); + let bob_key = bob.pubkey(); + + transfer(lwc, &context.payer, &alice_key, sol(1.0)) + .await + .unwrap(); + transfer(lwc, &context.payer, &bob_key, sol(1.0)) + .await + .unwrap(); + + let create_alice_ata_ix = create_initialize_account_instruction( + &mint_key, + &alice_key, + &authority.pubkey(), + &authority.pubkey(), + ) + .unwrap(); + let mint_to_ix = + create_mint_to_instruction(&mint_key, &alice_key, &authority.pubkey(), 1).unwrap(); + let delegate_ix = + create_approve_instruction(&mint_key, &alice_key, &bob_key, &authority.pubkey(), 1) + .unwrap(); + process_transaction( + lwc, + vec![create_alice_ata_ix, mint_to_ix, delegate_ix], + vec![&alice, &authority], + ) + .await + .unwrap(); + + assert!(lwc + .get_packed_account_data::(get_associated_token_address( + &alice_key, &mint_key + )) + .await + .unwrap() + .delegate + .eq(&COption::Some(bob_key))); + + let revoke_ix = create_revoke_instruction(&mint_key, &alice_key, &authority.pubkey()).unwrap(); + process_transaction(lwc, vec![revoke_ix], vec![&alice, &authority]) + .await + .unwrap(); + + assert!(lwc + .get_packed_account_data::(get_associated_token_address( + &alice_key, &mint_key + )) + .await + .unwrap() + .delegate + .is_none()); +} + +#[tokio::test] +async fn test_spl_managed_token_with_delegate_transfer() { + let mut context = spl_managed_token_test().start_with_context().await; + let lwc = &mut context.banks_client; + let authority = Keypair::new(); + transfer(lwc, &context.payer, &authority.pubkey(), sol(10.0)) + .await + .unwrap(); + let mint = Keypair::new(); + let mint_key = mint.pubkey(); + let create_ix = + create_initialize_mint_instruction(&mint_key, &authority.pubkey(), &authority.pubkey(), 0) + .unwrap(); + process_transaction(lwc, vec![create_ix], vec![&authority, &mint]) + .await + .unwrap(); + + let alice = Keypair::new(); + let alice_key = alice.pubkey(); + let bob = Keypair::new(); + let bob_key = bob.pubkey(); + let eve = Keypair::new(); + let eve_key = eve.pubkey(); + + transfer(lwc, &context.payer, &alice_key, sol(1.0)) + .await + .unwrap(); + transfer(lwc, &context.payer, &bob_key, sol(1.0)) + .await + .unwrap(); + + let create_alice_ata_ix = create_initialize_account_instruction( + &mint_key, + &alice_key, + &authority.pubkey(), + &authority.pubkey(), + ) + .unwrap(); + let mint_to_ix = + create_mint_to_instruction(&mint_key, &alice_key, &authority.pubkey(), 1).unwrap(); + let delegate_ix = + create_approve_instruction(&mint_key, &alice_key, &bob_key, &authority.pubkey(), 1) + .unwrap(); + process_transaction( + lwc, + vec![create_alice_ata_ix, mint_to_ix, delegate_ix], + vec![&alice, &authority], + ) + .await + .unwrap(); + + assert!(lwc + .get_packed_account_data::(get_associated_token_address( + &alice_key, &mint_key + )) + .await + .unwrap() + .delegate + .eq(&COption::Some(bob_key))); + + let create_eve_ata_ix = create_initialize_account_instruction( + &mint_key, + &eve_key, + &authority.pubkey(), + &authority.pubkey(), + ) + .unwrap(); + let successful_transfer_ix = create_transfer_with_delegate_instruction( + &alice_key, + &eve_key, + &bob_key, + &mint_key, + &authority.pubkey(), + 1, + ) + .unwrap(); + process_transaction( + lwc, + vec![create_eve_ata_ix, successful_transfer_ix], + vec![&bob, &authority], + ) + .await + .unwrap(); + + assert!( + lwc.get_packed_account_data::(get_associated_token_address( + &eve_key, &mint_key + )) + .await + .unwrap() + .amount + == 1 + ); +} diff --git a/managed-token/sdk/.solitarc.js b/managed-token/sdk/.solitarc.js new file mode 100644 index 00000000000..c759620a057 --- /dev/null +++ b/managed-token/sdk/.solitarc.js @@ -0,0 +1,14 @@ +const path = require('path'); +const programDir = path.join(__dirname, '..', 'program'); +const idlDir = path.join(__dirname, 'idl'); +const sdkDir = path.join(__dirname, 'src', 'generated'); +const binaryInstallDir = path.join(__dirname, '..', '..', 'target', 'solita'); + +module.exports = { + idlGenerator: 'shank', + programName: 'spl_managed_token', + idlDir, + sdkDir, + binaryInstallDir, + programDir, +}; diff --git a/managed-token/sdk/idl/spl_managed_token.json b/managed-token/sdk/idl/spl_managed_token.json new file mode 100644 index 00000000000..cbb7f158ed6 --- /dev/null +++ b/managed-token/sdk/idl/spl_managed_token.json @@ -0,0 +1,408 @@ +{ + "version": "0.1.0", + "name": "spl_managed_token", + "instructions": [ + { + "name": "InitializeMint", + "accounts": [ + { + "name": "mint", + "isMut": true, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "upstreamAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "System program" + ] + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "Token program" + ] + } + ], + "args": [ + { + "name": "decimals", + "type": "u8" + } + ], + "discriminant": { + "type": "u8", + "value": 0 + } + }, + { + "name": "InitializeAccount", + "accounts": [ + { + "name": "account", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": false + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "upstreamAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "freezeAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "System program" + ] + }, + { + "name": "associatedTokenProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "Associated Token program" + ] + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "Token program" + ] + } + ], + "args": [], + "discriminant": { + "type": "u8", + "value": 1 + } + }, + { + "name": "Transfer", + "accounts": [ + { + "name": "srcAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "dstAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "upstreamAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "freezeAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "Token program" + ] + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ], + "discriminant": { + "type": "u8", + "value": 2 + } + }, + { + "name": "MintTo", + "accounts": [ + { + "name": "mint", + "isMut": true, + "isSigner": false + }, + { + "name": "account", + "isMut": true, + "isSigner": false + }, + { + "name": "upstreamAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "freezeAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "Token program" + ] + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ], + "discriminant": { + "type": "u8", + "value": 3 + } + }, + { + "name": "Burn", + "accounts": [ + { + "name": "mint", + "isMut": true, + "isSigner": false + }, + { + "name": "account", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "upstreamAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "freezeAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "Token program" + ] + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ], + "discriminant": { + "type": "u8", + "value": 4 + } + }, + { + "name": "CloseAccount", + "accounts": [ + { + "name": "account", + "isMut": true, + "isSigner": false + }, + { + "name": "destination", + "isMut": true, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "upstreamAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "freezeAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "Token program" + ] + } + ], + "args": [], + "discriminant": { + "type": "u8", + "value": 5 + } + }, + { + "name": "Approve", + "accounts": [ + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "account", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "upstreamAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "delegate", + "isMut": false, + "isSigner": false + }, + { + "name": "freezeAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "Token program" + ] + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ], + "discriminant": { + "type": "u8", + "value": 6 + } + }, + { + "name": "Revoke", + "accounts": [ + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "account", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "upstreamAuthority", + "isMut": false, + "isSigner": true + }, + { + "name": "freezeAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "Token program" + ] + } + ], + "args": [], + "discriminant": { + "type": "u8", + "value": 7 + } + } + ], + "metadata": { + "origin": "shank", + "address": "mTok58Lg4YfcmwqyrDHpf7ogp599WRhzb6PxjaBqAxS" + } +} \ No newline at end of file diff --git a/managed-token/sdk/package.json b/managed-token/sdk/package.json new file mode 100644 index 00000000000..1a541cdc10f --- /dev/null +++ b/managed-token/sdk/package.json @@ -0,0 +1,12 @@ +{ + "name": "managed-token", + "version": "1.0.0", + "description": "SDK for managed-token", + "main": "index.ts", + "license": "MIT", + "dependencies": { + "@metaplex-foundation/rustbin": "^0.3.1", + "@metaplex-foundation/solita": "^0.12.2", + "@solana/spl-token": "0.1.8" + } +} diff --git a/managed-token/sdk/src/generated/index.ts b/managed-token/sdk/src/generated/index.ts new file mode 100644 index 00000000000..c0c25839c00 --- /dev/null +++ b/managed-token/sdk/src/generated/index.ts @@ -0,0 +1,18 @@ +import { PublicKey } from '@solana/web3.js' +export * from './instructions' + +/** + * Program address + * + * @category constants + * @category generated + */ +export const PROGRAM_ADDRESS = 'mTok58Lg4YfcmwqyrDHpf7ogp599WRhzb6PxjaBqAxS' + +/** + * Program public key + * + * @category constants + * @category generated + */ +export const PROGRAM_ID = new PublicKey(PROGRAM_ADDRESS) diff --git a/managed-token/sdk/src/generated/instructions/Approve.ts b/managed-token/sdk/src/generated/instructions/Approve.ts new file mode 100644 index 00000000000..cde5484ab39 --- /dev/null +++ b/managed-token/sdk/src/generated/instructions/Approve.ts @@ -0,0 +1,124 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as splToken from '@solana/spl-token' +import * as beet from '@metaplex-foundation/beet' +import * as web3 from '@solana/web3.js' + +/** + * @category Instructions + * @category Approve + * @category generated + */ +export type ApproveInstructionArgs = { + instructionArgs: beet.bignum +} +/** + * @category Instructions + * @category Approve + * @category generated + */ +export const ApproveStruct = new beet.BeetArgsStruct< + ApproveInstructionArgs & { + instructionDiscriminator: number + } +>( + [ + ['instructionDiscriminator', beet.u8], + ['instructionArgs', beet.u64], + ], + 'ApproveInstructionArgs' +) +/** + * Accounts required by the _Approve_ instruction + * + * @property [] mint + * @property [_writable_] account + * @property [**signer**] owner + * @property [**signer**] upstreamAuthority + * @property [] delegate + * @property [] freezeAuthority + * @category Instructions + * @category Approve + * @category generated + */ +export type ApproveInstructionAccounts = { + mint: web3.PublicKey + account: web3.PublicKey + owner: web3.PublicKey + upstreamAuthority: web3.PublicKey + delegate: web3.PublicKey + freezeAuthority: web3.PublicKey + tokenProgram?: web3.PublicKey +} + +export const approveInstructionDiscriminator = 6 + +/** + * Creates a _Approve_ instruction. + * + * @param accounts that will be accessed while the instruction is processed + * @param args to provide as instruction data to the program + * + * @category Instructions + * @category Approve + * @category generated + */ +export function createApproveInstruction( + accounts: ApproveInstructionAccounts, + args: ApproveInstructionArgs, + programId = new web3.PublicKey('mTok58Lg4YfcmwqyrDHpf7ogp599WRhzb6PxjaBqAxS') +) { + const [data] = ApproveStruct.serialize({ + instructionDiscriminator: approveInstructionDiscriminator, + ...args, + }) + const keys: web3.AccountMeta[] = [ + { + pubkey: accounts.mint, + isWritable: false, + isSigner: false, + }, + { + pubkey: accounts.account, + isWritable: true, + isSigner: false, + }, + { + pubkey: accounts.owner, + isWritable: false, + isSigner: true, + }, + { + pubkey: accounts.upstreamAuthority, + isWritable: false, + isSigner: true, + }, + { + pubkey: accounts.delegate, + isWritable: false, + isSigner: false, + }, + { + pubkey: accounts.freezeAuthority, + isWritable: false, + isSigner: false, + }, + { + pubkey: accounts.tokenProgram ?? splToken.TOKEN_PROGRAM_ID, + isWritable: false, + isSigner: false, + }, + ] + + const ix = new web3.TransactionInstruction({ + programId, + keys, + data, + }) + return ix +} diff --git a/managed-token/sdk/src/generated/instructions/Burn.ts b/managed-token/sdk/src/generated/instructions/Burn.ts new file mode 100644 index 00000000000..192fe252540 --- /dev/null +++ b/managed-token/sdk/src/generated/instructions/Burn.ts @@ -0,0 +1,117 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as splToken from '@solana/spl-token' +import * as beet from '@metaplex-foundation/beet' +import * as web3 from '@solana/web3.js' + +/** + * @category Instructions + * @category Burn + * @category generated + */ +export type BurnInstructionArgs = { + instructionArgs: beet.bignum +} +/** + * @category Instructions + * @category Burn + * @category generated + */ +export const BurnStruct = new beet.BeetArgsStruct< + BurnInstructionArgs & { + instructionDiscriminator: number + } +>( + [ + ['instructionDiscriminator', beet.u8], + ['instructionArgs', beet.u64], + ], + 'BurnInstructionArgs' +) +/** + * Accounts required by the _Burn_ instruction + * + * @property [_writable_] mint + * @property [_writable_] account + * @property [**signer**] owner + * @property [**signer**] upstreamAuthority + * @property [] freezeAuthority + * @category Instructions + * @category Burn + * @category generated + */ +export type BurnInstructionAccounts = { + mint: web3.PublicKey + account: web3.PublicKey + owner: web3.PublicKey + upstreamAuthority: web3.PublicKey + freezeAuthority: web3.PublicKey + tokenProgram?: web3.PublicKey +} + +export const burnInstructionDiscriminator = 4 + +/** + * Creates a _Burn_ instruction. + * + * @param accounts that will be accessed while the instruction is processed + * @param args to provide as instruction data to the program + * + * @category Instructions + * @category Burn + * @category generated + */ +export function createBurnInstruction( + accounts: BurnInstructionAccounts, + args: BurnInstructionArgs, + programId = new web3.PublicKey('mTok58Lg4YfcmwqyrDHpf7ogp599WRhzb6PxjaBqAxS') +) { + const [data] = BurnStruct.serialize({ + instructionDiscriminator: burnInstructionDiscriminator, + ...args, + }) + const keys: web3.AccountMeta[] = [ + { + pubkey: accounts.mint, + isWritable: true, + isSigner: false, + }, + { + pubkey: accounts.account, + isWritable: true, + isSigner: false, + }, + { + pubkey: accounts.owner, + isWritable: false, + isSigner: true, + }, + { + pubkey: accounts.upstreamAuthority, + isWritable: false, + isSigner: true, + }, + { + pubkey: accounts.freezeAuthority, + isWritable: false, + isSigner: false, + }, + { + pubkey: accounts.tokenProgram ?? splToken.TOKEN_PROGRAM_ID, + isWritable: false, + isSigner: false, + }, + ] + + const ix = new web3.TransactionInstruction({ + programId, + keys, + data, + }) + return ix +} diff --git a/managed-token/sdk/src/generated/instructions/CloseAccount.ts b/managed-token/sdk/src/generated/instructions/CloseAccount.ts new file mode 100644 index 00000000000..8f3e5681944 --- /dev/null +++ b/managed-token/sdk/src/generated/instructions/CloseAccount.ts @@ -0,0 +1,104 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as splToken from '@solana/spl-token' +import * as beet from '@metaplex-foundation/beet' +import * as web3 from '@solana/web3.js' + +/** + * @category Instructions + * @category CloseAccount + * @category generated + */ +export const CloseAccountStruct = new beet.BeetArgsStruct<{ + instructionDiscriminator: number +}>([['instructionDiscriminator', beet.u8]], 'CloseAccountInstructionArgs') +/** + * Accounts required by the _CloseAccount_ instruction + * + * @property [_writable_] account + * @property [_writable_] destination + * @property [] mint + * @property [**signer**] owner + * @property [**signer**] upstreamAuthority + * @property [] freezeAuthority + * @category Instructions + * @category CloseAccount + * @category generated + */ +export type CloseAccountInstructionAccounts = { + account: web3.PublicKey + destination: web3.PublicKey + mint: web3.PublicKey + owner: web3.PublicKey + upstreamAuthority: web3.PublicKey + freezeAuthority: web3.PublicKey + tokenProgram?: web3.PublicKey +} + +export const closeAccountInstructionDiscriminator = 5 + +/** + * Creates a _CloseAccount_ instruction. + * + * @param accounts that will be accessed while the instruction is processed + * @category Instructions + * @category CloseAccount + * @category generated + */ +export function createCloseAccountInstruction( + accounts: CloseAccountInstructionAccounts, + programId = new web3.PublicKey('mTok58Lg4YfcmwqyrDHpf7ogp599WRhzb6PxjaBqAxS') +) { + const [data] = CloseAccountStruct.serialize({ + instructionDiscriminator: closeAccountInstructionDiscriminator, + }) + const keys: web3.AccountMeta[] = [ + { + pubkey: accounts.account, + isWritable: true, + isSigner: false, + }, + { + pubkey: accounts.destination, + isWritable: true, + isSigner: false, + }, + { + pubkey: accounts.mint, + isWritable: false, + isSigner: false, + }, + { + pubkey: accounts.owner, + isWritable: false, + isSigner: true, + }, + { + pubkey: accounts.upstreamAuthority, + isWritable: false, + isSigner: true, + }, + { + pubkey: accounts.freezeAuthority, + isWritable: false, + isSigner: false, + }, + { + pubkey: accounts.tokenProgram ?? splToken.TOKEN_PROGRAM_ID, + isWritable: false, + isSigner: false, + }, + ] + + const ix = new web3.TransactionInstruction({ + programId, + keys, + data, + }) + return ix +} diff --git a/managed-token/sdk/src/generated/instructions/InitializeAccount.ts b/managed-token/sdk/src/generated/instructions/InitializeAccount.ts new file mode 100644 index 00000000000..726e9ac1586 --- /dev/null +++ b/managed-token/sdk/src/generated/instructions/InitializeAccount.ts @@ -0,0 +1,117 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as splToken from '@solana/spl-token' +import * as beet from '@metaplex-foundation/beet' +import * as web3 from '@solana/web3.js' + +/** + * @category Instructions + * @category InitializeAccount + * @category generated + */ +export const InitializeAccountStruct = new beet.BeetArgsStruct<{ + instructionDiscriminator: number +}>([['instructionDiscriminator', beet.u8]], 'InitializeAccountInstructionArgs') +/** + * Accounts required by the _InitializeAccount_ instruction + * + * @property [_writable_] account + * @property [] owner + * @property [_writable_, **signer**] payer + * @property [**signer**] upstreamAuthority + * @property [] freezeAuthority + * @property [] mint + * @property [] associatedTokenProgram Associated Token program + * @category Instructions + * @category InitializeAccount + * @category generated + */ +export type InitializeAccountInstructionAccounts = { + account: web3.PublicKey + owner: web3.PublicKey + payer: web3.PublicKey + upstreamAuthority: web3.PublicKey + freezeAuthority: web3.PublicKey + mint: web3.PublicKey + systemProgram?: web3.PublicKey + associatedTokenProgram: web3.PublicKey + tokenProgram?: web3.PublicKey +} + +export const initializeAccountInstructionDiscriminator = 1 + +/** + * Creates a _InitializeAccount_ instruction. + * + * @param accounts that will be accessed while the instruction is processed + * @category Instructions + * @category InitializeAccount + * @category generated + */ +export function createInitializeAccountInstruction( + accounts: InitializeAccountInstructionAccounts, + programId = new web3.PublicKey('mTok58Lg4YfcmwqyrDHpf7ogp599WRhzb6PxjaBqAxS') +) { + const [data] = InitializeAccountStruct.serialize({ + instructionDiscriminator: initializeAccountInstructionDiscriminator, + }) + const keys: web3.AccountMeta[] = [ + { + pubkey: accounts.account, + isWritable: true, + isSigner: false, + }, + { + pubkey: accounts.owner, + isWritable: false, + isSigner: false, + }, + { + pubkey: accounts.payer, + isWritable: true, + isSigner: true, + }, + { + pubkey: accounts.upstreamAuthority, + isWritable: false, + isSigner: true, + }, + { + pubkey: accounts.freezeAuthority, + isWritable: false, + isSigner: false, + }, + { + pubkey: accounts.mint, + isWritable: false, + isSigner: false, + }, + { + pubkey: accounts.systemProgram ?? web3.SystemProgram.programId, + isWritable: false, + isSigner: false, + }, + { + pubkey: accounts.associatedTokenProgram, + isWritable: false, + isSigner: false, + }, + { + pubkey: accounts.tokenProgram ?? splToken.TOKEN_PROGRAM_ID, + isWritable: false, + isSigner: false, + }, + ] + + const ix = new web3.TransactionInstruction({ + programId, + keys, + data, + }) + return ix +} diff --git a/managed-token/sdk/src/generated/instructions/InitializeMint.ts b/managed-token/sdk/src/generated/instructions/InitializeMint.ts new file mode 100644 index 00000000000..9bf3627e146 --- /dev/null +++ b/managed-token/sdk/src/generated/instructions/InitializeMint.ts @@ -0,0 +1,109 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as splToken from '@solana/spl-token' +import * as beet from '@metaplex-foundation/beet' +import * as web3 from '@solana/web3.js' + +/** + * @category Instructions + * @category InitializeMint + * @category generated + */ +export type InitializeMintInstructionArgs = { + instructionArgs: number +} +/** + * @category Instructions + * @category InitializeMint + * @category generated + */ +export const InitializeMintStruct = new beet.BeetArgsStruct< + InitializeMintInstructionArgs & { + instructionDiscriminator: number + } +>( + [ + ['instructionDiscriminator', beet.u8], + ['instructionArgs', beet.u8], + ], + 'InitializeMintInstructionArgs' +) +/** + * Accounts required by the _InitializeMint_ instruction + * + * @property [_writable_, **signer**] mint + * @property [_writable_, **signer**] payer + * @property [] upstreamAuthority + * @category Instructions + * @category InitializeMint + * @category generated + */ +export type InitializeMintInstructionAccounts = { + mint: web3.PublicKey + payer: web3.PublicKey + upstreamAuthority: web3.PublicKey + systemProgram?: web3.PublicKey + tokenProgram?: web3.PublicKey +} + +export const initializeMintInstructionDiscriminator = 0 + +/** + * Creates a _InitializeMint_ instruction. + * + * @param accounts that will be accessed while the instruction is processed + * @param args to provide as instruction data to the program + * + * @category Instructions + * @category InitializeMint + * @category generated + */ +export function createInitializeMintInstruction( + accounts: InitializeMintInstructionAccounts, + args: InitializeMintInstructionArgs, + programId = new web3.PublicKey('mTok58Lg4YfcmwqyrDHpf7ogp599WRhzb6PxjaBqAxS') +) { + const [data] = InitializeMintStruct.serialize({ + instructionDiscriminator: initializeMintInstructionDiscriminator, + ...args, + }) + const keys: web3.AccountMeta[] = [ + { + pubkey: accounts.mint, + isWritable: true, + isSigner: true, + }, + { + pubkey: accounts.payer, + isWritable: true, + isSigner: true, + }, + { + pubkey: accounts.upstreamAuthority, + isWritable: false, + isSigner: false, + }, + { + pubkey: accounts.systemProgram ?? web3.SystemProgram.programId, + isWritable: false, + isSigner: false, + }, + { + pubkey: accounts.tokenProgram ?? splToken.TOKEN_PROGRAM_ID, + isWritable: false, + isSigner: false, + }, + ] + + const ix = new web3.TransactionInstruction({ + programId, + keys, + data, + }) + return ix +} diff --git a/managed-token/sdk/src/generated/instructions/MintTo.ts b/managed-token/sdk/src/generated/instructions/MintTo.ts new file mode 100644 index 00000000000..2f6f1ebf122 --- /dev/null +++ b/managed-token/sdk/src/generated/instructions/MintTo.ts @@ -0,0 +1,110 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as splToken from '@solana/spl-token' +import * as beet from '@metaplex-foundation/beet' +import * as web3 from '@solana/web3.js' + +/** + * @category Instructions + * @category MintTo + * @category generated + */ +export type MintToInstructionArgs = { + instructionArgs: beet.bignum +} +/** + * @category Instructions + * @category MintTo + * @category generated + */ +export const MintToStruct = new beet.BeetArgsStruct< + MintToInstructionArgs & { + instructionDiscriminator: number + } +>( + [ + ['instructionDiscriminator', beet.u8], + ['instructionArgs', beet.u64], + ], + 'MintToInstructionArgs' +) +/** + * Accounts required by the _MintTo_ instruction + * + * @property [_writable_] mint + * @property [_writable_] account + * @property [**signer**] upstreamAuthority + * @property [] freezeAuthority + * @category Instructions + * @category MintTo + * @category generated + */ +export type MintToInstructionAccounts = { + mint: web3.PublicKey + account: web3.PublicKey + upstreamAuthority: web3.PublicKey + freezeAuthority: web3.PublicKey + tokenProgram?: web3.PublicKey +} + +export const mintToInstructionDiscriminator = 3 + +/** + * Creates a _MintTo_ instruction. + * + * @param accounts that will be accessed while the instruction is processed + * @param args to provide as instruction data to the program + * + * @category Instructions + * @category MintTo + * @category generated + */ +export function createMintToInstruction( + accounts: MintToInstructionAccounts, + args: MintToInstructionArgs, + programId = new web3.PublicKey('mTok58Lg4YfcmwqyrDHpf7ogp599WRhzb6PxjaBqAxS') +) { + const [data] = MintToStruct.serialize({ + instructionDiscriminator: mintToInstructionDiscriminator, + ...args, + }) + const keys: web3.AccountMeta[] = [ + { + pubkey: accounts.mint, + isWritable: true, + isSigner: false, + }, + { + pubkey: accounts.account, + isWritable: true, + isSigner: false, + }, + { + pubkey: accounts.upstreamAuthority, + isWritable: false, + isSigner: true, + }, + { + pubkey: accounts.freezeAuthority, + isWritable: false, + isSigner: false, + }, + { + pubkey: accounts.tokenProgram ?? splToken.TOKEN_PROGRAM_ID, + isWritable: false, + isSigner: false, + }, + ] + + const ix = new web3.TransactionInstruction({ + programId, + keys, + data, + }) + return ix +} diff --git a/managed-token/sdk/src/generated/instructions/Revoke.ts b/managed-token/sdk/src/generated/instructions/Revoke.ts new file mode 100644 index 00000000000..1adeae9f364 --- /dev/null +++ b/managed-token/sdk/src/generated/instructions/Revoke.ts @@ -0,0 +1,97 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as splToken from '@solana/spl-token' +import * as beet from '@metaplex-foundation/beet' +import * as web3 from '@solana/web3.js' + +/** + * @category Instructions + * @category Revoke + * @category generated + */ +export const RevokeStruct = new beet.BeetArgsStruct<{ + instructionDiscriminator: number +}>([['instructionDiscriminator', beet.u8]], 'RevokeInstructionArgs') +/** + * Accounts required by the _Revoke_ instruction + * + * @property [] mint + * @property [_writable_] account + * @property [**signer**] owner + * @property [**signer**] upstreamAuthority + * @property [] freezeAuthority + * @category Instructions + * @category Revoke + * @category generated + */ +export type RevokeInstructionAccounts = { + mint: web3.PublicKey + account: web3.PublicKey + owner: web3.PublicKey + upstreamAuthority: web3.PublicKey + freezeAuthority: web3.PublicKey + tokenProgram?: web3.PublicKey +} + +export const revokeInstructionDiscriminator = 7 + +/** + * Creates a _Revoke_ instruction. + * + * @param accounts that will be accessed while the instruction is processed + * @category Instructions + * @category Revoke + * @category generated + */ +export function createRevokeInstruction( + accounts: RevokeInstructionAccounts, + programId = new web3.PublicKey('mTok58Lg4YfcmwqyrDHpf7ogp599WRhzb6PxjaBqAxS') +) { + const [data] = RevokeStruct.serialize({ + instructionDiscriminator: revokeInstructionDiscriminator, + }) + const keys: web3.AccountMeta[] = [ + { + pubkey: accounts.mint, + isWritable: false, + isSigner: false, + }, + { + pubkey: accounts.account, + isWritable: true, + isSigner: false, + }, + { + pubkey: accounts.owner, + isWritable: false, + isSigner: true, + }, + { + pubkey: accounts.upstreamAuthority, + isWritable: false, + isSigner: true, + }, + { + pubkey: accounts.freezeAuthority, + isWritable: false, + isSigner: false, + }, + { + pubkey: accounts.tokenProgram ?? splToken.TOKEN_PROGRAM_ID, + isWritable: false, + isSigner: false, + }, + ] + + const ix = new web3.TransactionInstruction({ + programId, + keys, + data, + }) + return ix +} diff --git a/managed-token/sdk/src/generated/instructions/Transfer.ts b/managed-token/sdk/src/generated/instructions/Transfer.ts new file mode 100644 index 00000000000..d1ab32846cf --- /dev/null +++ b/managed-token/sdk/src/generated/instructions/Transfer.ts @@ -0,0 +1,124 @@ +/** + * This code was GENERATED using the solita package. + * Please DO NOT EDIT THIS FILE, instead rerun solita to update it or write a wrapper to add functionality. + * + * See: https://github.com/metaplex-foundation/solita + */ + +import * as splToken from '@solana/spl-token' +import * as beet from '@metaplex-foundation/beet' +import * as web3 from '@solana/web3.js' + +/** + * @category Instructions + * @category Transfer + * @category generated + */ +export type TransferInstructionArgs = { + instructionArgs: beet.bignum +} +/** + * @category Instructions + * @category Transfer + * @category generated + */ +export const TransferStruct = new beet.BeetArgsStruct< + TransferInstructionArgs & { + instructionDiscriminator: number + } +>( + [ + ['instructionDiscriminator', beet.u8], + ['instructionArgs', beet.u64], + ], + 'TransferInstructionArgs' +) +/** + * Accounts required by the _Transfer_ instruction + * + * @property [_writable_] srcAccount + * @property [_writable_] dstAccount + * @property [] mint + * @property [**signer**] owner + * @property [**signer**] upstreamAuthority + * @property [] freezeAuthority + * @category Instructions + * @category Transfer + * @category generated + */ +export type TransferInstructionAccounts = { + srcAccount: web3.PublicKey + dstAccount: web3.PublicKey + mint: web3.PublicKey + owner: web3.PublicKey + upstreamAuthority: web3.PublicKey + freezeAuthority: web3.PublicKey + tokenProgram?: web3.PublicKey +} + +export const transferInstructionDiscriminator = 2 + +/** + * Creates a _Transfer_ instruction. + * + * @param accounts that will be accessed while the instruction is processed + * @param args to provide as instruction data to the program + * + * @category Instructions + * @category Transfer + * @category generated + */ +export function createTransferInstruction( + accounts: TransferInstructionAccounts, + args: TransferInstructionArgs, + programId = new web3.PublicKey('mTok58Lg4YfcmwqyrDHpf7ogp599WRhzb6PxjaBqAxS') +) { + const [data] = TransferStruct.serialize({ + instructionDiscriminator: transferInstructionDiscriminator, + ...args, + }) + const keys: web3.AccountMeta[] = [ + { + pubkey: accounts.srcAccount, + isWritable: true, + isSigner: false, + }, + { + pubkey: accounts.dstAccount, + isWritable: true, + isSigner: false, + }, + { + pubkey: accounts.mint, + isWritable: false, + isSigner: false, + }, + { + pubkey: accounts.owner, + isWritable: false, + isSigner: true, + }, + { + pubkey: accounts.upstreamAuthority, + isWritable: false, + isSigner: true, + }, + { + pubkey: accounts.freezeAuthority, + isWritable: false, + isSigner: false, + }, + { + pubkey: accounts.tokenProgram ?? splToken.TOKEN_PROGRAM_ID, + isWritable: false, + isSigner: false, + }, + ] + + const ix = new web3.TransactionInstruction({ + programId, + keys, + data, + }) + return ix +} diff --git a/managed-token/sdk/src/generated/instructions/index.ts b/managed-token/sdk/src/generated/instructions/index.ts new file mode 100644 index 00000000000..733e6126d6e --- /dev/null +++ b/managed-token/sdk/src/generated/instructions/index.ts @@ -0,0 +1,8 @@ +export * from './Approve' +export * from './Burn' +export * from './CloseAccount' +export * from './InitializeAccount' +export * from './InitializeMint' +export * from './MintTo' +export * from './Revoke' +export * from './Transfer' diff --git a/managed-token/sdk/yarn.lock b/managed-token/sdk/yarn.lock new file mode 100644 index 00000000000..5cb1a78cdf3 --- /dev/null +++ b/managed-token/sdk/yarn.lock @@ -0,0 +1,537 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/runtime@^7.10.5", "@babel/runtime@^7.17.2": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259" + integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/runtime@^7.23.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.4.tgz#de795accd698007a66ba44add6cc86542aff1edd" + integrity sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA== + dependencies: + regenerator-runtime "^0.14.0" + +"@metaplex-foundation/beet-solana@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/beet-solana/-/beet-solana-0.3.1.tgz#4b37cda5c7f32ffd2bdd8b3164edc05c6463ab35" + integrity sha512-tgyEl6dvtLln8XX81JyBvWjIiEcjTkUwZbrM5dIobTmoqMuGewSyk9CClno8qsMsFdB5T3jC91Rjeqmu/6xk2g== + dependencies: + "@metaplex-foundation/beet" ">=0.1.0" + "@solana/web3.js" "^1.56.2" + bs58 "^5.0.0" + debug "^4.3.4" + +"@metaplex-foundation/beet@>=0.1.0": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/beet/-/beet-0.6.1.tgz#6331bdde0648bf2cae6f9e482f8e3552db05d69f" + integrity sha512-OYgnijLFzw0cdUlRKH5POp0unQECPOW9muJ2X3QIVyak5G6I6l/rKo72sICgPLIFKdmsi2jmnkuLY7wp14iXdw== + dependencies: + ansicolors "^0.3.2" + bn.js "^5.2.0" + debug "^4.3.3" + +"@metaplex-foundation/beet@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/beet/-/beet-0.4.0.tgz#eb2a0a6eb084bb25d67dd9bed2f7387ee7e63a55" + integrity sha512-2OAKJnLatCc3mBXNL0QmWVQKAWK2C7XDfepgL0p/9+8oSx4bmRAFHFqptl1A/C0U5O3dxGwKfmKluW161OVGcA== + dependencies: + ansicolors "^0.3.2" + bn.js "^5.2.0" + debug "^4.3.3" + +"@metaplex-foundation/rustbin@^0.3.0", "@metaplex-foundation/rustbin@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/rustbin/-/rustbin-0.3.1.tgz#bbcd61e8699b73c0b062728c6f5e8d52e8145042" + integrity sha512-hWd2JPrnt2/nJzkBpZD3Y6ZfCUlJujv2K7qUfsxdS0jSwLrSrOvYwmNWFw6mc3lbULj6VP4WDyuy9W5/CHU/lQ== + dependencies: + debug "^4.3.3" + semver "^7.3.7" + text-table "^0.2.0" + toml "^3.0.0" + +"@metaplex-foundation/solita@^0.12.2": + version "0.12.2" + resolved "https://registry.yarnpkg.com/@metaplex-foundation/solita/-/solita-0.12.2.tgz#13ef213ac183c986f6d01c5d981c44e59a900834" + integrity sha512-oczMfE43NNHWweSqhXPTkQBUbap/aAiwjDQw8zLKNnd/J8sXr/0+rKcN5yJIEgcHeKRkp90eTqkmt2WepQc8yw== + dependencies: + "@metaplex-foundation/beet" "^0.4.0" + "@metaplex-foundation/beet-solana" "^0.3.0" + "@metaplex-foundation/rustbin" "^0.3.0" + "@solana/web3.js" "^1.36.0" + camelcase "^6.2.1" + debug "^4.3.3" + js-sha256 "^0.9.0" + prettier "^2.5.1" + snake-case "^3.0.4" + spok "^1.4.3" + +"@noble/curves@^1.2.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.4.0.tgz#f05771ef64da724997f69ee1261b2417a49522d6" + integrity sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg== + dependencies: + "@noble/hashes" "1.4.0" + +"@noble/hashes@1.4.0", "@noble/hashes@^1.3.3": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" + integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== + +"@solana/buffer-layout@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz#b996235eaec15b1e0b5092a8ed6028df77fa6c15" + integrity sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA== + dependencies: + buffer "~6.0.3" + +"@solana/spl-token@0.1.8": + version "0.1.8" + resolved "https://registry.yarnpkg.com/@solana/spl-token/-/spl-token-0.1.8.tgz#f06e746341ef8d04165e21fc7f555492a2a0faa6" + integrity sha512-LZmYCKcPQDtJgecvWOgT/cnoIQPWjdH+QVyzPcFvyDUiT0DiRjZaam4aqNUyvchLFhzgunv3d9xOoyE34ofdoQ== + dependencies: + "@babel/runtime" "^7.10.5" + "@solana/web3.js" "^1.21.0" + bn.js "^5.1.0" + buffer "6.0.3" + buffer-layout "^1.2.0" + dotenv "10.0.0" + +"@solana/web3.js@^1.21.0", "@solana/web3.js@^1.36.0", "@solana/web3.js@^1.56.2": + version "1.91.6" + resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.91.6.tgz#c090661c344cbc61e6cdeb0da67d3ea80d5848e1" + integrity sha512-dm20nN6HQvXToo+kM51nxHdtaa2wMSRdeK37p+WIWESfeiVHqV8XbV4XnWupq6ngt5vIckhGFG7ZnTBxUgLzDA== + dependencies: + "@babel/runtime" "^7.23.4" + "@noble/curves" "^1.2.0" + "@noble/hashes" "^1.3.3" + "@solana/buffer-layout" "^4.0.1" + agentkeepalive "^4.5.0" + bigint-buffer "^1.1.5" + bn.js "^5.2.1" + borsh "^0.7.0" + bs58 "^4.0.1" + buffer "6.0.3" + fast-stable-stringify "^1.0.0" + jayson "^4.1.0" + node-fetch "^2.7.0" + rpc-websockets "^7.5.1" + superstruct "^0.14.2" + +"@types/connect@^3.4.33": + version "3.4.35" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" + integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== + dependencies: + "@types/node" "*" + +"@types/node@*": + version "18.7.18" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.18.tgz#633184f55c322e4fb08612307c274ee6d5ed3154" + integrity sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg== + +"@types/node@^12.12.54": + version "12.20.55" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" + integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== + +"@types/ws@^7.4.4": + version "7.4.7" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" + integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== + dependencies: + "@types/node" "*" + +JSONStream@^1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" + integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + +agentkeepalive@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" + integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== + dependencies: + humanize-ms "^1.2.1" + +ansicolors@^0.3.2, ansicolors@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" + integrity sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg== + +base-x@^3.0.2: + version "3.0.9" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" + integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== + dependencies: + safe-buffer "^5.0.1" + +base-x@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-4.0.0.tgz#d0e3b7753450c73f8ad2389b5c018a4af7b2224a" + integrity sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw== + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bigint-buffer@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/bigint-buffer/-/bigint-buffer-1.1.5.tgz#d038f31c8e4534c1f8d0015209bf34b4fa6dd442" + integrity sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA== + dependencies: + bindings "^1.3.0" + +bindings@^1.3.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bn.js@^5.1.0, bn.js@^5.2.0, bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + +borsh@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.7.0.tgz#6e9560d719d86d90dc589bca60ffc8a6c51fec2a" + integrity sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA== + dependencies: + bn.js "^5.2.0" + bs58 "^4.0.0" + text-encoding-utf-8 "^1.0.2" + +bs58@^4.0.0, bs58@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" + integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== + dependencies: + base-x "^3.0.2" + +bs58@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-5.0.0.tgz#865575b4d13c09ea2a84622df6c8cbeb54ffc279" + integrity sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ== + dependencies: + base-x "^4.0.0" + +buffer-layout@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/buffer-layout/-/buffer-layout-1.2.2.tgz#b9814e7c7235783085f9ca4966a0cfff112259d5" + integrity sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA== + +buffer@6.0.3, buffer@~6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + +bufferutil@^4.0.1: + version "4.0.6" + resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.6.tgz#ebd6c67c7922a0e902f053e5d8be5ec850e48433" + integrity sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw== + dependencies: + node-gyp-build "^4.3.0" + +camelcase@^6.2.1: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +commander@^2.20.3: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +debug@^4.3.3, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +delay@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" + integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== + +dot-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" + integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +dotenv@10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" + integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== + +es6-promise@^4.0.3: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ== + dependencies: + es6-promise "^4.0.3" + +eventemitter3@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +eyes@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" + integrity sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ== + +fast-stable-stringify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz#5c5543462b22aeeefd36d05b34e51c78cb86d313" + integrity sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag== + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== + dependencies: + ms "^2.0.0" + +ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +isomorphic-ws@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" + integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== + +jayson@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/jayson/-/jayson-4.1.0.tgz#60dc946a85197317f2b1439d672a8b0a99cea2f9" + integrity sha512-R6JlbyLN53Mjku329XoRT2zJAE6ZgOQ8f91ucYdMCD4nkGCF9kZSrcGXpHIU4jeKj58zUZke2p+cdQchU7Ly7A== + dependencies: + "@types/connect" "^3.4.33" + "@types/node" "^12.12.54" + "@types/ws" "^7.4.4" + 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" + json-stringify-safe "^5.0.1" + uuid "^8.3.2" + ws "^7.4.5" + +js-sha256@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.9.0.tgz#0b89ac166583e91ef9123644bd3c5334ce9d0966" + integrity sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA== + +json-stringify-safe@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== + +jsonparse@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== + +lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@^2.0.0: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" + +node-fetch@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + +node-gyp-build@^4.3.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40" + integrity sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg== + +prettier@^2.5.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" + integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== + +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + +rpc-websockets@^7.5.1: + version "7.10.0" + resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.10.0.tgz#8ffaf6aaab3eb18e603c7549988cf49feeddcd29" + integrity sha512-cemZ6RiDtYZpPiBzYijdOrkQQzmBCmug0E9SdRH2gIUNT15ql4mwCYWIp0VnSZq6Qrw/JkGUygp4PrK1y9KfwQ== + dependencies: + "@babel/runtime" "^7.17.2" + eventemitter3 "^4.0.7" + uuid "^8.3.2" + ws "^8.5.0" + optionalDependencies: + bufferutil "^4.0.1" + utf-8-validate "^5.0.2" + +safe-buffer@^5.0.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +semver@^7.3.7: + version "7.5.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e" + integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ== + dependencies: + lru-cache "^6.0.0" + +snake-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c" + integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + +spok@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/spok/-/spok-1.4.3.tgz#8516234e6bd8caf0e10567bd675e15fd03b5ceb8" + integrity sha512-5wFGctwrk638aDs+44u99kohxFNByUq2wo0uShQ9yqxSmsxqx7zKbMo1Busy4s7stZQXU+PhJ/BlVf2XWFEGIw== + dependencies: + ansicolors "~0.3.2" + +superstruct@^0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.14.2.tgz#0dbcdf3d83676588828f1cf5ed35cda02f59025b" + integrity sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ== + +text-encoding-utf-8@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz#585b62197b0ae437e3c7b5d0af27ac1021e10d13" + integrity sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg== + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +"through@>=2.2.7 <3": + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + +toml@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/toml/-/toml-3.0.0.tgz#342160f1af1904ec9d204d03a5d61222d762c5ee" + integrity sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w== + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +tslib@^2.0.3: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + +utf-8-validate@^5.0.2: + version "5.0.9" + resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.9.tgz#ba16a822fbeedff1a58918f2a6a6b36387493ea3" + integrity sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q== + dependencies: + node-gyp-build "^4.3.0" + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +ws@^7.4.5: + version "7.5.10" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" + integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== + +ws@^8.5.0: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" + integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== diff --git a/memo/README.md b/memo/README.md index 1cff1b99999..71ece75d71f 100644 --- a/memo/README.md +++ b/memo/README.md @@ -1,3 +1,6 @@ +NOTE: The memo program and clients are now maintained at +[solana-program/memo](https://github.com/solana-program/memo). + # Memo Program A simple program that validates a string of UTF-8 encoded characters and logs it @@ -7,3 +10,8 @@ record a string on-chain, stored in the instruction data of a successful transaction, and optionally verify the originator. Full documentation is available at https://spl.solana.com/memo + +## Audit + +The repository [README](https://github.com/solana-labs/solana-program-library#audits) +contains information about program audits. diff --git a/memo/program/Cargo.toml b/memo/program/Cargo.toml deleted file mode 100644 index 6a91bfd12b7..00000000000 --- a/memo/program/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "spl-memo" -version = "3.0.1" -description = "Solana Program Library Memo" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana-program-library" -license = "Apache-2.0" -edition = "2018" - -[features] -no-entrypoint = [] -test-bpf = [] - -[dependencies] -solana-program = "1.10.33" - -[dev-dependencies] -solana-program-test = "1.10.33" -solana-sdk = "1.10.33" - -[lib] -crate-type = ["cdylib", "lib"] - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] diff --git a/memo/program/Xargo.toml b/memo/program/Xargo.toml deleted file mode 100644 index 1744f098ae1..00000000000 --- a/memo/program/Xargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.bpfel-unknown-unknown.dependencies.std] -features = [] \ No newline at end of file diff --git a/memo/program/program-id.md b/memo/program/program-id.md deleted file mode 100644 index 284ff6d8137..00000000000 --- a/memo/program/program-id.md +++ /dev/null @@ -1 +0,0 @@ -MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr diff --git a/memo/program/src/entrypoint.rs b/memo/program/src/entrypoint.rs deleted file mode 100644 index 82641a41587..00000000000 --- a/memo/program/src/entrypoint.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! Program entrypoint - -#![cfg(not(feature = "no-entrypoint"))] - -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, pubkey::Pubkey, -}; - -entrypoint!(process_instruction); -fn process_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - instruction_data: &[u8], -) -> ProgramResult { - crate::processor::process_instruction(program_id, accounts, instruction_data) -} diff --git a/memo/program/src/lib.rs b/memo/program/src/lib.rs deleted file mode 100644 index 53d80dddd54..00000000000 --- a/memo/program/src/lib.rs +++ /dev/null @@ -1,54 +0,0 @@ -#![deny(missing_docs)] - -//! A program that accepts a string of encoded characters and verifies that it parses, -//! while verifying and logging signers. Currently handles UTF-8 characters. - -mod entrypoint; -pub mod processor; - -// Export current sdk types for downstream users building with a different sdk version -pub use solana_program; -use solana_program::{ - instruction::{AccountMeta, Instruction}, - pubkey::Pubkey, -}; - -/// Legacy symbols from Memo v1 -pub mod v1 { - solana_program::declare_id!("Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo"); -} - -solana_program::declare_id!("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"); - -/// Build a memo instruction, possibly signed -/// -/// Accounts expected by this instruction: -/// -/// 0. ..0+N. `[signer]` Expected signers; if zero provided, instruction will be processed as a -/// normal, unsigned spl-memo -/// -pub fn build_memo(memo: &[u8], signer_pubkeys: &[&Pubkey]) -> Instruction { - Instruction { - program_id: id(), - accounts: signer_pubkeys - .iter() - .map(|&pubkey| AccountMeta::new_readonly(*pubkey, true)) - .collect(), - data: memo.to_vec(), - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_build_memo() { - let signer_pubkey = Pubkey::new_unique(); - let memo = "🐆".as_bytes(); - let instruction = build_memo(memo, &[&signer_pubkey]); - assert_eq!(memo, instruction.data); - assert_eq!(instruction.accounts.len(), 1); - assert_eq!(instruction.accounts[0].pubkey, signer_pubkey); - } -} diff --git a/memo/program/src/processor.rs b/memo/program/src/processor.rs deleted file mode 100644 index baf64b82048..00000000000 --- a/memo/program/src/processor.rs +++ /dev/null @@ -1,109 +0,0 @@ -//! Program state processor - -use solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, - pubkey::Pubkey, -}; -use std::str::from_utf8; - -/// Instruction processor -pub fn process_instruction( - _program_id: &Pubkey, - accounts: &[AccountInfo], - input: &[u8], -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mut missing_required_signature = false; - for account_info in account_info_iter { - if let Some(address) = account_info.signer_key() { - msg!("Signed by {:?}", address); - } else { - missing_required_signature = true; - } - } - if missing_required_signature { - return Err(ProgramError::MissingRequiredSignature); - } - - let memo = from_utf8(input).map_err(|err| { - msg!("Invalid UTF-8, from byte {}", err.valid_up_to()); - ProgramError::InvalidInstructionData - })?; - msg!("Memo (len {}): {:?}", memo.len(), memo); - - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - use solana_program::{ - account_info::IntoAccountInfo, program_error::ProgramError, pubkey::Pubkey, - }; - use solana_sdk::account::Account; - - #[test] - fn test_utf8_memo() { - let program_id = Pubkey::new(&[0; 32]); - - let string = b"letters and such"; - assert_eq!(Ok(()), process_instruction(&program_id, &[], string)); - - let emoji = "🐆".as_bytes(); - let bytes = [0xF0, 0x9F, 0x90, 0x86]; - assert_eq!(emoji, bytes); - assert_eq!(Ok(()), process_instruction(&program_id, &[], emoji)); - - let mut bad_utf8 = bytes; - bad_utf8[3] = 0xFF; // Invalid UTF-8 byte - assert_eq!( - Err(ProgramError::InvalidInstructionData), - process_instruction(&program_id, &[], &bad_utf8) - ); - } - - #[test] - fn test_signers() { - let program_id = Pubkey::new(&[0; 32]); - let memo = "🐆".as_bytes(); - - let pubkey0 = Pubkey::new_unique(); - let pubkey1 = Pubkey::new_unique(); - let pubkey2 = Pubkey::new_unique(); - let mut account0 = Account::default(); - let mut account1 = Account::default(); - let mut account2 = Account::default(); - - let signed_account_infos = vec![ - (&pubkey0, true, &mut account0).into_account_info(), - (&pubkey1, true, &mut account1).into_account_info(), - (&pubkey2, true, &mut account2).into_account_info(), - ]; - assert_eq!( - Ok(()), - process_instruction(&program_id, &signed_account_infos, memo) - ); - - assert_eq!(Ok(()), process_instruction(&program_id, &[], memo)); - - let unsigned_account_infos = vec![ - (&pubkey0, false, &mut account0).into_account_info(), - (&pubkey1, false, &mut account1).into_account_info(), - (&pubkey2, false, &mut account2).into_account_info(), - ]; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - process_instruction(&program_id, &unsigned_account_infos, memo) - ); - - let partially_signed_account_infos = vec![ - (&pubkey0, true, &mut account0).into_account_info(), - (&pubkey1, false, &mut account1).into_account_info(), - (&pubkey2, true, &mut account2).into_account_info(), - ]; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - process_instruction(&program_id, &partially_signed_account_infos, memo) - ); - } -} diff --git a/memo/program/tests/functional.rs b/memo/program/tests/functional.rs deleted file mode 100644 index c5ef6d901b2..00000000000 --- a/memo/program/tests/functional.rs +++ /dev/null @@ -1,206 +0,0 @@ -#![cfg(feature = "test-bpf")] - -use solana_program::{ - instruction::{AccountMeta, Instruction, InstructionError}, - pubkey::Pubkey, -}; -use solana_program_test::*; -use solana_sdk::{ - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, -}; -use spl_memo::*; - -fn program_test() -> ProgramTest { - ProgramTest::new("spl_memo", id(), processor!(processor::process_instruction)) -} - -#[tokio::test] -async fn test_memo_signing() { - let memo = "🐆".as_bytes(); - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - - let keypairs = vec![Keypair::new(), Keypair::new(), Keypair::new()]; - let pubkeys: Vec = keypairs.iter().map(|keypair| keypair.pubkey()).collect(); - - // Test complete signing - let signer_key_refs: Vec<&Pubkey> = pubkeys.iter().collect(); - let mut transaction = - Transaction::new_with_payer(&[build_memo(memo, &signer_key_refs)], Some(&payer.pubkey())); - let mut signers = vec![&payer]; - for keypair in keypairs.iter() { - signers.push(keypair); - } - transaction.sign(&signers, recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - // Test unsigned memo - let mut transaction = - Transaction::new_with_payer(&[build_memo(memo, &[])], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - // Demonstrate success on signature provided, regardless of specific memo AccountMeta - let mut transaction = Transaction::new_with_payer( - &[Instruction { - program_id: id(), - accounts: vec![ - AccountMeta::new_readonly(keypairs[0].pubkey(), true), - AccountMeta::new_readonly(keypairs[1].pubkey(), true), - AccountMeta::new_readonly(payer.pubkey(), false), - ], - data: memo.to_vec(), - }], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &keypairs[0], &keypairs[1]], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - // Test missing signer(s) - let mut transaction = Transaction::new_with_payer( - &[Instruction { - program_id: id(), - accounts: vec![ - AccountMeta::new_readonly(keypairs[0].pubkey(), true), - AccountMeta::new_readonly(keypairs[1].pubkey(), false), - AccountMeta::new_readonly(keypairs[2].pubkey(), true), - ], - data: memo.to_vec(), - }], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &keypairs[0], &keypairs[2]], recent_blockhash); - assert_eq!( - banks_client - .process_transaction(transaction) - .await - .unwrap_err() - .unwrap(), - TransactionError::InstructionError(0, InstructionError::MissingRequiredSignature) - ); - - let mut transaction = Transaction::new_with_payer( - &[Instruction { - program_id: id(), - accounts: vec![ - AccountMeta::new_readonly(keypairs[0].pubkey(), false), - AccountMeta::new_readonly(keypairs[1].pubkey(), false), - AccountMeta::new_readonly(keypairs[2].pubkey(), false), - ], - data: memo.to_vec(), - }], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer], recent_blockhash); - assert_eq!( - banks_client - .process_transaction(transaction) - .await - .unwrap_err() - .unwrap(), - TransactionError::InstructionError(0, InstructionError::MissingRequiredSignature) - ); - - // Test invalid utf-8; demonstrate log - let invalid_utf8 = [0xF0, 0x9F, 0x90, 0x86, 0xF0, 0x9F, 0xFF, 0x86]; - let mut transaction = - Transaction::new_with_payer(&[build_memo(&invalid_utf8, &[])], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - assert_eq!( - banks_client - .process_transaction(transaction) - .await - .unwrap_err() - .unwrap(), - TransactionError::InstructionError(0, InstructionError::InvalidInstructionData) - ); -} - -#[tokio::test] -#[ignore] -async fn test_memo_compute_limits() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - - // Test memo length - let mut memo = vec![]; - for _ in 0..1000 { - let mut vec = vec![0x53, 0x4F, 0x4C]; - memo.append(&mut vec); - } - - let mut transaction = - Transaction::new_with_payer(&[build_memo(&memo[..450], &[])], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - let mut transaction = - Transaction::new_with_payer(&[build_memo(&memo[..600], &[])], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - let err = banks_client - .process_transaction(transaction) - .await - .unwrap_err() - .unwrap(); - let failed_to_complete = - TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete); - let computational_budget_exceeded = - TransactionError::InstructionError(0, InstructionError::ComputationalBudgetExceeded); - assert!(err == failed_to_complete || err == computational_budget_exceeded); - - let mut memo = vec![]; - for _ in 0..100 { - let mut vec = vec![0xE2, 0x97, 0x8E]; - memo.append(&mut vec); - } - - let mut transaction = - Transaction::new_with_payer(&[build_memo(&memo[..60], &[])], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - let mut transaction = - Transaction::new_with_payer(&[build_memo(&memo[..63], &[])], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - let err = banks_client - .process_transaction(transaction) - .await - .unwrap_err() - .unwrap(); - assert!(err == failed_to_complete || err == computational_budget_exceeded); - - // Test num signers with 32-byte memo - let memo = Pubkey::new_unique().to_bytes(); - let mut keypairs = vec![]; - for _ in 0..20 { - keypairs.push(Keypair::new()); - } - let pubkeys: Vec = keypairs.iter().map(|keypair| keypair.pubkey()).collect(); - let signer_key_refs: Vec<&Pubkey> = pubkeys.iter().collect(); - - let mut signers = vec![&payer]; - for keypair in keypairs[..12].iter() { - signers.push(keypair); - } - let mut transaction = Transaction::new_with_payer( - &[build_memo(&memo, &signer_key_refs[..12])], - Some(&payer.pubkey()), - ); - transaction.sign(&signers, recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - let mut signers = vec![&payer]; - for keypair in keypairs[..15].iter() { - signers.push(keypair); - } - let mut transaction = Transaction::new_with_payer( - &[build_memo(&memo, &signer_key_refs[..15])], - Some(&payer.pubkey()), - ); - transaction.sign(&signers, recent_blockhash); - let err = banks_client - .process_transaction(transaction) - .await - .unwrap_err() - .unwrap(); - assert!(err == failed_to_complete || err == computational_budget_exceeded); -} diff --git a/memo/ts/.eslintignore b/memo/ts/.eslintignore deleted file mode 100644 index 1521c8b7652..00000000000 --- a/memo/ts/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/memo/ts/.eslintrc.cjs b/memo/ts/.eslintrc.cjs deleted file mode 100644 index 45647ba2202..00000000000 --- a/memo/ts/.eslintrc.cjs +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - root: true, - parser: '@typescript-eslint/parser', - plugins: [ - '@typescript-eslint', - ], - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'prettier', - ], -}; diff --git a/memo/ts/.gitignore b/memo/ts/.gitignore deleted file mode 100644 index 1521c8b7652..00000000000 --- a/memo/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/memo/ts/.prettierrc.yaml b/memo/ts/.prettierrc.yaml deleted file mode 100644 index 59f717fb8ca..00000000000 --- a/memo/ts/.prettierrc.yaml +++ /dev/null @@ -1,6 +0,0 @@ -arrowParens: "avoid" -bracketSpacing: false -semi: true -singleQuote: true -tabWidth: 2 -trailingComma: "all" diff --git a/memo/ts/jest.config.cjs b/memo/ts/jest.config.cjs deleted file mode 100644 index e86e13bab91..00000000000 --- a/memo/ts/jest.config.cjs +++ /dev/null @@ -1,5 +0,0 @@ -/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ -module.exports = { - preset: 'ts-jest', - testEnvironment: 'node', -}; diff --git a/memo/ts/package.json b/memo/ts/package.json deleted file mode 100644 index da8e7c47e34..00000000000 --- a/memo/ts/package.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "name": "@solana/spl-memo", - "version": "0.1.0", - "description": "SPL Memo Program JS API", - "files": [ - "dist", - "src" - ], - "main": "dist/index.js", - "types": "dist/index.d.ts", - "type": "module", - "sideEffects": false, - "scripts": { - "build": "npm run clean && tsc", - "clean": "rimraf ./dist", - "lint": "eslint --max-warnings 0 . && npm run pretty", - "lint:fix": "eslint . --fix && npm run pretty:fix", - "pretty": "prettier --check '{,{src,test}/**/}*.{j,t}s'", - "pretty:fix": "prettier --write '{,{src,test}/**/}*.{j,t}s'", - "test": "npm run test:unit && npm run test:e2e", - "test:unit": "jest test/unit", - "test:e2e": "start-server-and-test 'solana-test-validator -r -q' http://localhost:8899/health 'jest test/e2e'" - }, - "repository": { - "type": "git", - "url": "https://github.com/solana-labs/solana-program-library" - }, - "publishConfig": { - "access": "public" - }, - "author": "Solana Maintainers ", - "license": "MIT", - "devDependencies": { - "@types/chai": "^4.3.1", - "@types/jest": "^28.1.1", - "@types/node": "^17.0.42", - "@types/node-fetch": "^2.6.1", - "@types/prettier": "^2.6.3", - "@typescript-eslint/eslint-plugin": "^5.28.0", - "@typescript-eslint/parser": "^5.28.0", - "chai": "^4.3.6", - "eslint": "^8.17.0", - "eslint-config-prettier": "^8.5.0", - "jest": "^28.1.1", - "prettier": "^2.7.0", - "process": "^0.11.10", - "start-server-and-test": "^1.14.0", - "ts-jest": "^28.0.5", - "ts-node": "^10.8.1", - "typescript": "^4.7.3" - }, - "dependencies": { - "@solana/web3.js": "^1.41.0", - "buffer": "^6.0.3" - } -} diff --git a/memo/ts/src/index.ts b/memo/ts/src/index.ts deleted file mode 100644 index 3b4d945e427..00000000000 --- a/memo/ts/src/index.ts +++ /dev/null @@ -1,43 +0,0 @@ -import {Buffer} from 'buffer'; -import {PublicKey, TransactionInstruction} from '@solana/web3.js'; - -export const MEMO_PROGRAM_ID: PublicKey = new PublicKey( - 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr', -); - -/** - * Creates and returns an instruction which validates a string of UTF-8 - * encoded characters and verifies that any accounts provided are signers of - * the transaction. The program also logs the memo, as well as any verified - * signer addresses, to the transaction log, so that anyone can easily observe - * memos and know they were approved by zero or more addresses by inspecting - * the transaction log from a trusted provider. - * - * Public keys passed in via the signerPubkeys will identify Signers which - * must subsequently sign the Transaction including the returned - * TransactionInstruction in order for the transaction to be valid. - * - * @param memo The UTF-8 encoded memo string to validate - * @param signerPubkeys An array of public keys which must sign the - * Transaction including the returned TransactionInstruction in order - * for the transaction to be valid and the memo verification to - * succeed. null is allowed if there are no signers for the memo - * verification. - **/ -export function createMemoInstruction( - memo: string, - signerPubkeys?: Array, -): TransactionInstruction { - const keys = - signerPubkeys == null - ? [] - : signerPubkeys.map(function (key) { - return {pubkey: key, isSigner: true, isWritable: false}; - }); - - return new TransactionInstruction({ - keys: keys, - programId: MEMO_PROGRAM_ID, - data: Buffer.from(memo, 'utf8'), - }); -} diff --git a/memo/ts/test/e2e/transaction.test.ts b/memo/ts/test/e2e/transaction.test.ts deleted file mode 100644 index e8630d571b5..00000000000 --- a/memo/ts/test/e2e/transaction.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import {createMemoInstruction} from '../../src'; -import { - Connection, - Keypair, - Transaction, - LAMPORTS_PER_SOL, - sendAndConfirmTransaction, -} from '@solana/web3.js'; - -test('transaction: live', async () => { - const url = 'http://localhost:8899'; - const connection = new Connection(url, 'confirmed'); - await connection.getVersion(); - const signer = new Keypair(); // also fee-payer - - const airdropSignature = await connection.requestAirdrop( - signer.publicKey, - LAMPORTS_PER_SOL / 10, - ); - await connection.confirmTransaction(airdropSignature, 'confirmed'); - - const memoTx = new Transaction().add( - createMemoInstruction('this is a test memo', [signer.publicKey]), - ); - await sendAndConfirmTransaction(connection, memoTx, [signer], { - preflightCommitment: 'confirmed', - }); -}); diff --git a/memo/ts/test/unit/index.test.ts b/memo/ts/test/unit/index.test.ts deleted file mode 100644 index 3b2857db723..00000000000 --- a/memo/ts/test/unit/index.test.ts +++ /dev/null @@ -1,41 +0,0 @@ -import {createMemoInstruction, MEMO_PROGRAM_ID} from '../../src'; -import {expect} from 'chai'; -import {Keypair} from '@solana/web3.js'; - -test('instruction: no signers', () => { - const ix = createMemoInstruction('this is a test memo', []); - expect(ix.programId).to.eql(MEMO_PROGRAM_ID); - expect(ix.keys).to.have.length(0); - expect(ix.data).to.have.length(19); - - const ix2 = createMemoInstruction('this is a test'); - expect(ix2.programId).to.eql(MEMO_PROGRAM_ID); - expect(ix2.keys).to.have.length(0); - expect(ix2.data).to.have.length(14); -}); - -test('instruction: one signer', () => { - const signer = new Keypair(); - const ix = createMemoInstruction('this is a test memo', [signer.publicKey]); - expect(ix.programId).to.eql(MEMO_PROGRAM_ID); - expect(ix.keys).to.have.length(1); - expect(ix.data).to.have.length(19); -}); - -test('instruction: many signers', () => { - const signer0 = new Keypair(); - const signer1 = new Keypair(); - const signer2 = new Keypair(); - const signer3 = new Keypair(); - const signer4 = new Keypair(); - const ix = createMemoInstruction('this is a test memo', [ - signer0.publicKey, - signer1.publicKey, - signer2.publicKey, - signer3.publicKey, - signer4.publicKey, - ]); - expect(ix.programId).to.eql(MEMO_PROGRAM_ID); - expect(ix.keys).to.have.length(5); - expect(ix.data).to.have.length(19); -}); diff --git a/memo/ts/tsconfig.json b/memo/ts/tsconfig.json deleted file mode 100644 index 0ce09cf7dfc..00000000000 --- a/memo/ts/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "esnext", - "module": "esnext", - "esModuleInterop": true, - "moduleResolution": "node", - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "strict": true, - "isolatedModules": true, - "noImplicitReturns": true, - }, - "include": ["src/**/*.ts"], - "exclude": ["node_modules"] -} diff --git a/memo/ts/yarn.lock b/memo/ts/yarn.lock deleted file mode 100644 index c5ee1b3151f..00000000000 --- a/memo/ts/yarn.lock +++ /dev/null @@ -1,3556 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@ampproject/remapping@^2.1.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" - integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== - dependencies: - "@jridgewell/gen-mapping" "^0.1.0" - "@jridgewell/trace-mapping" "^0.3.9" - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" - integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== - dependencies: - "@babel/highlight" "^7.16.7" - -"@babel/compat-data@^7.17.10": - version "7.18.5" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.5.tgz#acac0c839e317038c73137fbb6ef71a1d6238471" - integrity sha512-BxhE40PVCBxVEJsSBhB6UWyAuqJRxGsAw8BdHMJ3AKGydcwuWW4kOO3HmqBQAdcq/OP+/DlTVxLvsCzRTnZuGg== - -"@babel/core@^7.11.6", "@babel/core@^7.12.3": - version "7.18.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.5.tgz#c597fa680e58d571c28dda9827669c78cdd7f000" - integrity sha512-MGY8vg3DxMnctw0LdvSEojOsumc70g0t18gNyUdAZqB1Rpd1Bqo/svHGvt+UJ6JcGX+DIekGFDxxIWofBxLCnQ== - dependencies: - "@ampproject/remapping" "^2.1.0" - "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.18.2" - "@babel/helper-compilation-targets" "^7.18.2" - "@babel/helper-module-transforms" "^7.18.0" - "@babel/helpers" "^7.18.2" - "@babel/parser" "^7.18.5" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.18.5" - "@babel/types" "^7.18.4" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.1" - semver "^6.3.0" - -"@babel/generator@^7.18.2", "@babel/generator@^7.7.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.2.tgz#33873d6f89b21efe2da63fe554460f3df1c5880d" - integrity sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw== - dependencies: - "@babel/types" "^7.18.2" - "@jridgewell/gen-mapping" "^0.3.0" - jsesc "^2.5.1" - -"@babel/helper-compilation-targets@^7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.2.tgz#67a85a10cbd5fc7f1457fec2e7f45441dc6c754b" - integrity sha512-s1jnPotJS9uQnzFtiZVBUxe67CuBa679oWFHpxYYnTpRL/1ffhyX44R9uYiXoa/pLXcY9H2moJta0iaanlk/rQ== - dependencies: - "@babel/compat-data" "^7.17.10" - "@babel/helper-validator-option" "^7.16.7" - browserslist "^4.20.2" - semver "^6.3.0" - -"@babel/helper-environment-visitor@^7.16.7", "@babel/helper-environment-visitor@^7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz#8a6d2dedb53f6bf248e31b4baf38739ee4a637bd" - integrity sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ== - -"@babel/helper-function-name@^7.17.9": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz#136fcd54bc1da82fcb47565cf16fd8e444b1ff12" - integrity sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg== - dependencies: - "@babel/template" "^7.16.7" - "@babel/types" "^7.17.0" - -"@babel/helper-hoist-variables@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" - integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-module-imports@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" - integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-module-transforms@^7.18.0": - version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz#baf05dec7a5875fb9235bd34ca18bad4e21221cd" - integrity sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA== - dependencies: - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-simple-access" "^7.17.7" - "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/helper-validator-identifier" "^7.16.7" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.18.0" - "@babel/types" "^7.18.0" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.17.12", "@babel/helper-plugin-utils@^7.8.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz#86c2347da5acbf5583ba0a10aed4c9bf9da9cf96" - integrity sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA== - -"@babel/helper-simple-access@^7.17.7": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.2.tgz#4dc473c2169ac3a1c9f4a51cfcd091d1c36fcff9" - integrity sha512-7LIrjYzndorDY88MycupkpQLKS1AFfsVRm2k/9PtKScSy5tZq0McZTj+DiMRynboZfIqOKvo03pmhTaUgiD6fQ== - dependencies: - "@babel/types" "^7.18.2" - -"@babel/helper-split-export-declaration@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" - integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-validator-identifier@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" - integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== - -"@babel/helper-validator-option@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" - integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== - -"@babel/helpers@^7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.2.tgz#970d74f0deadc3f5a938bfa250738eb4ac889384" - integrity sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg== - dependencies: - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.18.2" - "@babel/types" "^7.18.2" - -"@babel/highlight@^7.16.7": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.17.12.tgz#257de56ee5afbd20451ac0a75686b6b404257351" - integrity sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg== - dependencies: - "@babel/helper-validator-identifier" "^7.16.7" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.18.5": - version "7.18.5" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.5.tgz#337062363436a893a2d22faa60be5bb37091c83c" - integrity sha512-YZWVaglMiplo7v8f1oMQ5ZPQr0vn7HPeZXxXWsxXJRjGVrzUFn9OxFQl1sb5wzfootjA/yChhW84BV+383FSOw== - -"@babel/plugin-syntax-async-generators@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" - integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-bigint@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" - integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-class-properties@^7.8.3": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" - integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - -"@babel/plugin-syntax-import-meta@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" - integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-json-strings@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" - integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" - integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" - integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-numeric-separator@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" - integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-object-rest-spread@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" - integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-catch-binding@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" - integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-chaining@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" - integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-top-level-await@^7.8.3": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" - integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-typescript@^7.7.2": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.17.12.tgz#b54fc3be6de734a56b87508f99d6428b5b605a7b" - integrity sha512-TYY0SXFiO31YXtNg3HtFwNJHjLsAyIIhAhNWkQ5whPPS7HWUFlg9z0Ta4qAQNjQbP1wsSt/oKkmZ/4/WWdMUpw== - dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - -"@babel/runtime@^7.12.5", "@babel/runtime@^7.17.2": - version "7.18.3" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.3.tgz#c7b654b57f6f63cf7f8b418ac9ca04408c4579f4" - integrity sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/template@^7.16.7", "@babel/template@^7.3.3": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" - integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== - dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/parser" "^7.16.7" - "@babel/types" "^7.16.7" - -"@babel/traverse@^7.18.0", "@babel/traverse@^7.18.2", "@babel/traverse@^7.18.5", "@babel/traverse@^7.7.2": - version "7.18.5" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.5.tgz#94a8195ad9642801837988ab77f36e992d9a20cd" - integrity sha512-aKXj1KT66sBj0vVzk6rEeAO6Z9aiiQ68wfDgge3nHhA/my6xMM/7HGQUNumKZaoa2qUPQ5whJG9aAifsxUKfLA== - dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.18.2" - "@babel/helper-environment-visitor" "^7.18.2" - "@babel/helper-function-name" "^7.17.9" - "@babel/helper-hoist-variables" "^7.16.7" - "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/parser" "^7.18.5" - "@babel/types" "^7.18.4" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/types@^7.0.0", "@babel/types@^7.16.7", "@babel/types@^7.17.0", "@babel/types@^7.18.0", "@babel/types@^7.18.2", "@babel/types@^7.18.4", "@babel/types@^7.3.0", "@babel/types@^7.3.3": - version "7.18.4" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.4.tgz#27eae9b9fd18e9dccc3f9d6ad051336f307be354" - integrity sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw== - dependencies: - "@babel/helper-validator-identifier" "^7.16.7" - to-fast-properties "^2.0.0" - -"@bcoe/v8-coverage@^0.2.3": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" - integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== - -"@cspotcode/source-map-support@^0.8.0": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" - integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== - dependencies: - "@jridgewell/trace-mapping" "0.3.9" - -"@eslint/eslintrc@^1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f" - integrity sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw== - dependencies: - ajv "^6.12.4" - debug "^4.3.2" - espree "^9.3.2" - globals "^13.15.0" - ignore "^5.2.0" - import-fresh "^3.2.1" - js-yaml "^4.1.0" - minimatch "^3.1.2" - strip-json-comments "^3.1.1" - -"@ethersproject/bytes@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.6.1.tgz#24f916e411f82a8a60412344bf4a813b917eefe7" - integrity sha512-NwQt7cKn5+ZE4uDn+X5RAXLp46E1chXoaMmrxAyA0rblpxz8t58lVkrHXoRIn0lz1joQElQ8410GqhTqMOwc6g== - dependencies: - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/logger@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.6.0.tgz#d7db1bfcc22fd2e4ab574cba0bb6ad779a9a3e7a" - integrity sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg== - -"@ethersproject/sha2@^5.5.0": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.6.1.tgz#211f14d3f5da5301c8972a8827770b6fd3e51656" - integrity sha512-5K2GyqcW7G4Yo3uenHegbXRPDgARpWUiXc6RiF7b6i/HXUoWlb7uCARh7BAHg7/qT/Q5ydofNwiZcim9qpjB6g== - dependencies: - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - hash.js "1.1.7" - -"@hapi/hoek@^9.0.0": - version "9.3.0" - resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb" - integrity sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ== - -"@hapi/topo@^5.0.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012" - integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== - dependencies: - "@hapi/hoek" "^9.0.0" - -"@humanwhocodes/config-array@^0.9.2": - version "0.9.5" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7" - integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw== - dependencies: - "@humanwhocodes/object-schema" "^1.2.1" - debug "^4.1.1" - minimatch "^3.0.4" - -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== - -"@istanbuljs/load-nyc-config@^1.0.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" - integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== - dependencies: - camelcase "^5.3.1" - find-up "^4.1.0" - get-package-type "^0.1.0" - js-yaml "^3.13.1" - resolve-from "^5.0.0" - -"@istanbuljs/schema@^0.1.2": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" - integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== - -"@jest/console@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-28.1.1.tgz#305f8ca50b6e70413839f54c0e002b60a0f2fd7d" - integrity sha512-0RiUocPVFEm3WRMOStIHbRWllG6iW6E3/gUPnf4lkrVFyXIIDeCe+vlKeYyFOMhB2EPE6FLFCNADSOOQMaqvyA== - dependencies: - "@jest/types" "^28.1.1" - "@types/node" "*" - chalk "^4.0.0" - jest-message-util "^28.1.1" - jest-util "^28.1.1" - slash "^3.0.0" - -"@jest/core@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-28.1.1.tgz#086830bec6267accf9af5ca76f794858e9f9f092" - integrity sha512-3pYsBoZZ42tXMdlcFeCc/0j9kOlK7MYuXs2B1QbvDgMoW1K9NJ4G/VYvIbMb26iqlkTfPHo7SC2JgjDOk/mxXw== - dependencies: - "@jest/console" "^28.1.1" - "@jest/reporters" "^28.1.1" - "@jest/test-result" "^28.1.1" - "@jest/transform" "^28.1.1" - "@jest/types" "^28.1.1" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - ci-info "^3.2.0" - exit "^0.1.2" - graceful-fs "^4.2.9" - jest-changed-files "^28.0.2" - jest-config "^28.1.1" - jest-haste-map "^28.1.1" - jest-message-util "^28.1.1" - jest-regex-util "^28.0.2" - jest-resolve "^28.1.1" - jest-resolve-dependencies "^28.1.1" - jest-runner "^28.1.1" - jest-runtime "^28.1.1" - jest-snapshot "^28.1.1" - jest-util "^28.1.1" - jest-validate "^28.1.1" - jest-watcher "^28.1.1" - micromatch "^4.0.4" - pretty-format "^28.1.1" - rimraf "^3.0.0" - slash "^3.0.0" - strip-ansi "^6.0.0" - -"@jest/environment@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-28.1.1.tgz#c4cbf85283278d768f816ebd1a258ea6f9e39d4f" - integrity sha512-9auVQ2GzQ7nrU+lAr8KyY838YahElTX9HVjbQPPS2XjlxQ+na18G113OoBhyBGBtD6ZnO/SrUy5WR8EzOj1/Uw== - dependencies: - "@jest/fake-timers" "^28.1.1" - "@jest/types" "^28.1.1" - "@types/node" "*" - jest-mock "^28.1.1" - -"@jest/expect-utils@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-28.1.1.tgz#d84c346025b9f6f3886d02c48a6177e2b0360587" - integrity sha512-n/ghlvdhCdMI/hTcnn4qV57kQuV9OTsZzH1TTCVARANKhl6hXJqLKUkwX69ftMGpsbpt96SsDD8n8LD2d9+FRw== - dependencies: - jest-get-type "^28.0.2" - -"@jest/expect@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-28.1.1.tgz#ea4fcc8504b45835029221c0dc357c622a761326" - integrity sha512-/+tQprrFoT6lfkMj4mW/mUIfAmmk/+iQPmg7mLDIFOf2lyf7EBHaS+x3RbeR0VZVMe55IvX7QRoT/2aK3AuUXg== - dependencies: - expect "^28.1.1" - jest-snapshot "^28.1.1" - -"@jest/fake-timers@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-28.1.1.tgz#47ce33296ab9d680c76076d51ddbe65ceb3337f1" - integrity sha512-BY/3+TyLs5+q87rGWrGUY5f8e8uC3LsVHS9Diz8+FV3ARXL4sNnkLlIB8dvDvRrp+LUCGM+DLqlsYubizGUjIA== - dependencies: - "@jest/types" "^28.1.1" - "@sinonjs/fake-timers" "^9.1.1" - "@types/node" "*" - jest-message-util "^28.1.1" - jest-mock "^28.1.1" - jest-util "^28.1.1" - -"@jest/globals@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-28.1.1.tgz#c0a7977f85e26279cc090d9adcdf82b8a34c4061" - integrity sha512-dEgl/6v7ToB4vXItdvcltJBgny0xBE6xy6IYQrPJAJggdEinGxCDMivNv7sFzPcTITGquXD6UJwYxfJ/5ZwDSg== - dependencies: - "@jest/environment" "^28.1.1" - "@jest/expect" "^28.1.1" - "@jest/types" "^28.1.1" - -"@jest/reporters@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-28.1.1.tgz#9389f4bb3cce4d9b586f6195f83c79cd2a1c8662" - integrity sha512-597Zj4D4d88sZrzM4atEGLuO7SdA/YrOv9SRXHXRNC+/FwPCWxZhBAEzhXoiJzfRwn8zes/EjS8Lo6DouGN5Gg== - dependencies: - "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^28.1.1" - "@jest/test-result" "^28.1.1" - "@jest/transform" "^28.1.1" - "@jest/types" "^28.1.1" - "@jridgewell/trace-mapping" "^0.3.7" - "@types/node" "*" - chalk "^4.0.0" - collect-v8-coverage "^1.0.0" - exit "^0.1.2" - glob "^7.1.3" - graceful-fs "^4.2.9" - istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^5.1.0" - istanbul-lib-report "^3.0.0" - istanbul-lib-source-maps "^4.0.0" - istanbul-reports "^3.1.3" - jest-message-util "^28.1.1" - jest-util "^28.1.1" - jest-worker "^28.1.1" - slash "^3.0.0" - string-length "^4.0.1" - strip-ansi "^6.0.0" - terminal-link "^2.0.0" - v8-to-istanbul "^9.0.0" - -"@jest/schemas@^28.0.2": - version "28.0.2" - resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-28.0.2.tgz#08c30df6a8d07eafea0aef9fb222c5e26d72e613" - integrity sha512-YVDJZjd4izeTDkij00vHHAymNXQ6WWsdChFRK86qck6Jpr3DCL5W3Is3vslviRlP+bLuMYRLbdp98amMvqudhA== - dependencies: - "@sinclair/typebox" "^0.23.3" - -"@jest/source-map@^28.0.2": - version "28.0.2" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-28.0.2.tgz#914546f4410b67b1d42c262a1da7e0406b52dc90" - integrity sha512-Y9dxC8ZpN3kImkk0LkK5XCEneYMAXlZ8m5bflmSL5vrwyeUpJfentacCUg6fOb8NOpOO7hz2+l37MV77T6BFPw== - dependencies: - "@jridgewell/trace-mapping" "^0.3.7" - callsites "^3.0.0" - graceful-fs "^4.2.9" - -"@jest/test-result@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-28.1.1.tgz#c6f18d1bbb01aa88925dd687872a75f8414b317a" - integrity sha512-hPmkugBktqL6rRzwWAtp1JtYT4VHwv8OQ+9lE5Gymj6dHzubI/oJHMUpPOt8NrdVWSrz9S7bHjJUmv2ggFoUNQ== - dependencies: - "@jest/console" "^28.1.1" - "@jest/types" "^28.1.1" - "@types/istanbul-lib-coverage" "^2.0.0" - collect-v8-coverage "^1.0.0" - -"@jest/test-sequencer@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-28.1.1.tgz#f594ee2331df75000afe0d1ae3237630ecec732e" - integrity sha512-nuL+dNSVMcWB7OOtgb0EGH5AjO4UBCt68SLP08rwmC+iRhyuJWS9MtZ/MpipxFwKAlHFftbMsydXqWre8B0+XA== - dependencies: - "@jest/test-result" "^28.1.1" - graceful-fs "^4.2.9" - jest-haste-map "^28.1.1" - slash "^3.0.0" - -"@jest/transform@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-28.1.1.tgz#83541f2a3f612077c8501f49cc4e205d4e4a6b27" - integrity sha512-PkfaTUuvjUarl1EDr5ZQcCA++oXkFCP9QFUkG0yVKVmNObjhrqDy0kbMpMebfHWm3CCDHjYNem9eUSH8suVNHQ== - dependencies: - "@babel/core" "^7.11.6" - "@jest/types" "^28.1.1" - "@jridgewell/trace-mapping" "^0.3.7" - babel-plugin-istanbul "^6.1.1" - chalk "^4.0.0" - convert-source-map "^1.4.0" - fast-json-stable-stringify "^2.0.0" - graceful-fs "^4.2.9" - jest-haste-map "^28.1.1" - jest-regex-util "^28.0.2" - jest-util "^28.1.1" - micromatch "^4.0.4" - pirates "^4.0.4" - slash "^3.0.0" - write-file-atomic "^4.0.1" - -"@jest/types@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-28.1.1.tgz#d059bbc80e6da6eda9f081f293299348bd78ee0b" - integrity sha512-vRXVqSg1VhDnB8bWcmvLzmg0Bt9CRKVgHPXqYwvWMX3TvAjeO+nRuK6+VdTKCtWOvYlmkF/HqNAL/z+N3B53Kw== - dependencies: - "@jest/schemas" "^28.0.2" - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^17.0.8" - chalk "^4.0.0" - -"@jridgewell/gen-mapping@^0.1.0": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" - integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== - dependencies: - "@jridgewell/set-array" "^1.0.0" - "@jridgewell/sourcemap-codec" "^1.4.10" - -"@jridgewell/gen-mapping@^0.3.0": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz#cf92a983c83466b8c0ce9124fadeaf09f7c66ea9" - integrity sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg== - dependencies: - "@jridgewell/set-array" "^1.0.0" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" - -"@jridgewell/resolve-uri@^3.0.3": - version "3.0.7" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz#30cd49820a962aff48c8fffc5cd760151fca61fe" - integrity sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA== - -"@jridgewell/set-array@^1.0.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.1.tgz#36a6acc93987adcf0ba50c66908bd0b70de8afea" - integrity sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ== - -"@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.13" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz#b6461fb0c2964356c469e115f504c95ad97ab88c" - integrity sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w== - -"@jridgewell/trace-mapping@0.3.9": - version "0.3.9" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" - integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - -"@jridgewell/trace-mapping@^0.3.7", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.13" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz#dcfe3e95f224c8fe97a87a5235defec999aa92ea" - integrity sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - -"@nodelib/fs.walk@^1.2.3": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - -"@sideway/address@^4.1.3": - version "4.1.4" - resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0" - integrity sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw== - dependencies: - "@hapi/hoek" "^9.0.0" - -"@sideway/formula@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.0.tgz#fe158aee32e6bd5de85044be615bc08478a0a13c" - integrity sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg== - -"@sideway/pinpoint@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" - integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== - -"@sinclair/typebox@^0.23.3": - version "0.23.5" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.23.5.tgz#93f7b9f4e3285a7a9ade7557d9a8d36809cbc47d" - integrity sha512-AFBVi/iT4g20DHoujvMH1aEDn8fGJh4xsRGCP6d8RpLPMqsNPvW01Jcn0QysXTsg++/xj25NmJsGyH9xug/wKg== - -"@sinonjs/commons@^1.7.0": - version "1.8.3" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" - integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== - dependencies: - type-detect "4.0.8" - -"@sinonjs/fake-timers@^9.1.1": - version "9.1.2" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz#4eaab737fab77332ab132d396a3c0d364bd0ea8c" - integrity sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw== - dependencies: - "@sinonjs/commons" "^1.7.0" - -"@solana/buffer-layout@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-4.0.0.tgz#75b1b11adc487234821c81dfae3119b73a5fd734" - integrity sha512-lR0EMP2HC3+Mxwd4YcnZb0smnaDw7Bl2IQWZiTevRH5ZZBZn6VRWn3/92E3qdU4SSImJkA6IDHawOHAnx/qUvQ== - dependencies: - buffer "~6.0.3" - -"@solana/web3.js@^1.41.0": - version "1.44.0" - resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.44.0.tgz#233f7bd268520a0ce852ff7f92ded150c5fad0f5" - integrity sha512-KHf7o8sM5FlxYGHGroD7IJeCCOmjFITdBIXq4cO5xPFQ8O6Y26FWfYqIXqY1dXI29t240g0m1GYPssCp5UVgZg== - dependencies: - "@babel/runtime" "^7.12.5" - "@ethersproject/sha2" "^5.5.0" - "@solana/buffer-layout" "^4.0.0" - bigint-buffer "^1.1.5" - bn.js "^5.0.0" - borsh "^0.7.0" - bs58 "^4.0.1" - buffer "6.0.1" - fast-stable-stringify "^1.0.0" - jayson "^3.4.4" - js-sha3 "^0.8.0" - node-fetch "2" - rpc-websockets "^7.4.2" - secp256k1 "^4.0.2" - superstruct "^0.14.2" - tweetnacl "^1.0.0" - -"@tsconfig/node10@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" - integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== - -"@tsconfig/node12@^1.0.7": - version "1.0.10" - resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.10.tgz#10fecee4a3be17357ce99b370bd81874044d8dbd" - integrity sha512-N+srakvPaYMGkwjNDx3ASx65Zl3QG8dJgVtIB+YMOkucU+zctlv/hdP5250VKdDHSDoW9PFZoCqbqNcAPjCjXA== - -"@tsconfig/node14@^1.0.0": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.2.tgz#b09c08de2eb319ca2acab17a1b8028af110b24b3" - integrity sha512-YwrUA5ysDXHFYfL0Xed9x3sNS4P+aKlCOnnbqUa2E5HdQshHFleCJVrj1PlGTb4GgFUCDyte1v3JWLy2sz8Oqg== - -"@tsconfig/node16@^1.0.2": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" - integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== - -"@types/babel__core@^7.1.14": - version "7.1.19" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.19.tgz#7b497495b7d1b4812bdb9d02804d0576f43ee460" - integrity sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - "@types/babel__generator" "*" - "@types/babel__template" "*" - "@types/babel__traverse" "*" - -"@types/babel__generator@*": - version "7.6.4" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" - integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== - dependencies: - "@babel/types" "^7.0.0" - -"@types/babel__template@*": - version "7.4.1" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" - integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - -"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": - version "7.17.1" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.17.1.tgz#1a0e73e8c28c7e832656db372b779bfd2ef37314" - integrity sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA== - dependencies: - "@babel/types" "^7.3.0" - -"@types/chai@^4.3.1": - version "4.3.1" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.1.tgz#e2c6e73e0bdeb2521d00756d099218e9f5d90a04" - integrity sha512-/zPMqDkzSZ8t3VtxOa4KPq7uzzW978M9Tvh+j7GHKuo6k6GTLxPJ4J5gE5cjfJ26pnXst0N5Hax8Sr0T2Mi9zQ== - -"@types/connect@^3.4.33": - version "3.4.35" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" - integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== - dependencies: - "@types/node" "*" - -"@types/express-serve-static-core@^4.17.9": - version "4.17.29" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.29.tgz#2a1795ea8e9e9c91b4a4bbe475034b20c1ec711c" - integrity sha512-uMd++6dMKS32EOuw1Uli3e3BPgdLIXmezcfHv7N4c1s3gkhikBplORPpMq3fuWkxncZN1reb16d5n8yhQ80x7Q== - dependencies: - "@types/node" "*" - "@types/qs" "*" - "@types/range-parser" "*" - -"@types/graceful-fs@^4.1.3": - version "4.1.5" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" - integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== - dependencies: - "@types/node" "*" - -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" - integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== - -"@types/istanbul-lib-report@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" - integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== - dependencies: - "@types/istanbul-lib-coverage" "*" - -"@types/istanbul-reports@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" - integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== - dependencies: - "@types/istanbul-lib-report" "*" - -"@types/jest@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-28.1.1.tgz#8c9ba63702a11f8c386ee211280e8b68cb093cd1" - integrity sha512-C2p7yqleUKtCkVjlOur9BWVA4HgUQmEj/HWCt5WzZ5mLXrWnyIfl0wGuArc+kBXsy0ZZfLp+7dywB4HtSVYGVA== - dependencies: - jest-matcher-utils "^27.0.0" - pretty-format "^27.0.0" - -"@types/json-schema@^7.0.9": - version "7.0.11" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" - integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== - -"@types/lodash@^4.14.159": - version "4.14.182" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.182.tgz#05301a4d5e62963227eaafe0ce04dd77c54ea5c2" - integrity sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q== - -"@types/node-fetch@^2.6.1": - version "2.6.1" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.1.tgz#8f127c50481db65886800ef496f20bbf15518975" - integrity sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA== - dependencies: - "@types/node" "*" - form-data "^3.0.0" - -"@types/node@*", "@types/node@^17.0.42": - version "17.0.42" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.42.tgz#d7e8f22700efc94d125103075c074396b5f41f9b" - integrity sha512-Q5BPGyGKcvQgAMbsr7qEGN/kIPN6zZecYYABeTDBizOsau+2NMdSVTar9UQw21A2+JyA2KRNDYaYrPB0Rpk2oQ== - -"@types/node@^12.12.54": - version "12.20.55" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" - integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== - -"@types/prettier@^2.1.5", "@types/prettier@^2.6.3": - version "2.6.3" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.6.3.tgz#68ada76827b0010d0db071f739314fa429943d0a" - integrity sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg== - -"@types/qs@*": - version "6.9.7" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" - integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== - -"@types/range-parser@*": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" - integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== - -"@types/stack-utils@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" - integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== - -"@types/ws@^7.4.4": - version "7.4.7" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" - integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== - dependencies: - "@types/node" "*" - -"@types/yargs-parser@*": - version "21.0.0" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" - integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== - -"@types/yargs@^17.0.8": - version "17.0.10" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.10.tgz#591522fce85d8739bca7b8bb90d048e4478d186a" - integrity sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA== - dependencies: - "@types/yargs-parser" "*" - -"@typescript-eslint/eslint-plugin@^5.28.0": - version "5.28.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.28.0.tgz#6204ac33bdd05ab27c7f77960f1023951115d403" - integrity sha512-DXVU6Cg29H2M6EybqSg2A+x8DgO9TCUBRp4QEXQHJceLS7ogVDP0g3Lkg/SZCqcvkAP/RruuQqK0gdlkgmhSUA== - dependencies: - "@typescript-eslint/scope-manager" "5.28.0" - "@typescript-eslint/type-utils" "5.28.0" - "@typescript-eslint/utils" "5.28.0" - debug "^4.3.4" - functional-red-black-tree "^1.0.1" - ignore "^5.2.0" - regexpp "^3.2.0" - semver "^7.3.7" - tsutils "^3.21.0" - -"@typescript-eslint/parser@^5.28.0": - version "5.28.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.28.0.tgz#639b101cad2bfb7ae16e69710ac95c42bd4eae33" - integrity sha512-ekqoNRNK1lAcKhZESN/PdpVsWbP9jtiNqzFWkp/yAUdZvJalw2heCYuqRmM5eUJSIYEkgq5sGOjq+ZqsLMjtRA== - dependencies: - "@typescript-eslint/scope-manager" "5.28.0" - "@typescript-eslint/types" "5.28.0" - "@typescript-eslint/typescript-estree" "5.28.0" - debug "^4.3.4" - -"@typescript-eslint/scope-manager@5.28.0": - version "5.28.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.28.0.tgz#ef9a5c68fecde72fd2ff8a84b9c120324826c1b9" - integrity sha512-LeBLTqF/he1Z+boRhSqnso6YrzcKMTQ8bO/YKEe+6+O/JGof9M0g3IJlIsqfrK/6K03MlFIlycbf1uQR1IjE+w== - dependencies: - "@typescript-eslint/types" "5.28.0" - "@typescript-eslint/visitor-keys" "5.28.0" - -"@typescript-eslint/type-utils@5.28.0": - version "5.28.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.28.0.tgz#53ccc78fdcf0205ef544d843b84104c0e9c7ca8e" - integrity sha512-SyKjKh4CXPglueyC6ceAFytjYWMoPHMswPQae236zqe1YbhvCVQyIawesYywGiu98L9DwrxsBN69vGIVxJ4mQQ== - dependencies: - "@typescript-eslint/utils" "5.28.0" - debug "^4.3.4" - tsutils "^3.21.0" - -"@typescript-eslint/types@5.28.0": - version "5.28.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.28.0.tgz#cffd9bcdce28db6daaa146e48a0be4387a6f4e9d" - integrity sha512-2OOm8ZTOQxqkPbf+DAo8oc16sDlVR5owgJfKheBkxBKg1vAfw2JsSofH9+16VPlN9PWtv8Wzhklkqw3k/zCVxA== - -"@typescript-eslint/typescript-estree@5.28.0": - version "5.28.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.28.0.tgz#3487d158d091ca2772b285e67412ff6d9797d863" - integrity sha512-9GX+GfpV+F4hdTtYc6OV9ZkyYilGXPmQpm6AThInpBmKJEyRSIjORJd1G9+bknb7OTFYL+Vd4FBJAO6T78OVqA== - dependencies: - "@typescript-eslint/types" "5.28.0" - "@typescript-eslint/visitor-keys" "5.28.0" - debug "^4.3.4" - globby "^11.1.0" - is-glob "^4.0.3" - semver "^7.3.7" - tsutils "^3.21.0" - -"@typescript-eslint/utils@5.28.0": - version "5.28.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.28.0.tgz#b27a136eac300a48160b36d2aad0da44a1341b99" - integrity sha512-E60N5L0fjv7iPJV3UGc4EC+A3Lcj4jle9zzR0gW7vXhflO7/J29kwiTGITA2RlrmPokKiZbBy2DgaclCaEUs6g== - dependencies: - "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.28.0" - "@typescript-eslint/types" "5.28.0" - "@typescript-eslint/typescript-estree" "5.28.0" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - -"@typescript-eslint/visitor-keys@5.28.0": - version "5.28.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.28.0.tgz#982bb226b763c48fc1859a60de33fbf939d40a0f" - integrity sha512-BtfP1vCor8cWacovzzPFOoeW4kBQxzmhxGoOpt0v1SFvG+nJ0cWaVdJk7cky1ArTcFHHKNIxyo2LLr3oNkSuXA== - dependencies: - "@typescript-eslint/types" "5.28.0" - eslint-visitor-keys "^3.3.0" - -JSONStream@^1.3.5: - version "1.3.5" - resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" - integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== - dependencies: - jsonparse "^1.2.0" - through ">=2.2.7 <3" - -acorn-jsx@^5.3.2: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -acorn-walk@^8.1.1: - version "8.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" - integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== - -acorn@^8.4.1, acorn@^8.7.1: - version "8.7.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" - integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== - -ajv@^6.10.0, ajv@^6.12.4: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ansi-escapes@^4.2.1: - version "4.3.2" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== - dependencies: - type-fest "^0.21.3" - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -ansi-styles@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" - integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== - -anymatch@^3.0.3: - version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -assertion-error@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" - integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== - -axios@^0.21.1: - version "0.21.4" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" - integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== - dependencies: - follow-redirects "^1.14.0" - -babel-jest@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-28.1.1.tgz#2a3a4ae50964695b2d694ccffe4bec537c5a3586" - integrity sha512-MEt0263viUdAkTq5D7upHPNxvt4n9uLUGa6pPz3WviNBMtOmStb1lIXS3QobnoqM+qnH+vr4EKlvhe8QcmxIYw== - dependencies: - "@jest/transform" "^28.1.1" - "@types/babel__core" "^7.1.14" - babel-plugin-istanbul "^6.1.1" - babel-preset-jest "^28.1.1" - chalk "^4.0.0" - graceful-fs "^4.2.9" - slash "^3.0.0" - -babel-plugin-istanbul@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" - integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@istanbuljs/load-nyc-config" "^1.0.0" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-instrument "^5.0.4" - test-exclude "^6.0.0" - -babel-plugin-jest-hoist@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.1.tgz#5e055cdcc47894f28341f87f5e35aad2df680b11" - integrity sha512-NovGCy5Hn25uMJSAU8FaHqzs13cFoOI4lhIujiepssjCKRsAo3TA734RDWSGxuFTsUJXerYOqQQodlxgmtqbzw== - dependencies: - "@babel/template" "^7.3.3" - "@babel/types" "^7.3.3" - "@types/babel__core" "^7.1.14" - "@types/babel__traverse" "^7.0.6" - -babel-preset-current-node-syntax@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" - integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== - dependencies: - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-bigint" "^7.8.3" - "@babel/plugin-syntax-class-properties" "^7.8.3" - "@babel/plugin-syntax-import-meta" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.8.3" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-top-level-await" "^7.8.3" - -babel-preset-jest@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-28.1.1.tgz#5b6e5e69f963eb2d70f739c607b8f723c0ee75e4" - integrity sha512-FCq9Oud0ReTeWtcneYf/48981aTfXYuB9gbU4rBNNJVBSQ6ssv7E6v/qvbBxtOWwZFXjLZwpg+W3q7J6vhH25g== - dependencies: - babel-plugin-jest-hoist "^28.1.1" - babel-preset-current-node-syntax "^1.0.0" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -base-x@^3.0.2: - version "3.0.9" - resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" - integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== - dependencies: - safe-buffer "^5.0.1" - -base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -bigint-buffer@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/bigint-buffer/-/bigint-buffer-1.1.5.tgz#d038f31c8e4534c1f8d0015209bf34b4fa6dd442" - integrity sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA== - dependencies: - bindings "^1.3.0" - -bindings@^1.3.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - -bluebird@3.7.2: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - -bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - -bn.js@^5.0.0, bn.js@^5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" - integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== - -borsh@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.7.0.tgz#6e9560d719d86d90dc589bca60ffc8a6c51fec2a" - integrity sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA== - dependencies: - bn.js "^5.2.0" - bs58 "^4.0.0" - text-encoding-utf-8 "^1.0.2" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -brorand@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== - -browserslist@^4.20.2: - version "4.20.4" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.4.tgz#98096c9042af689ee1e0271333dbc564b8ce4477" - integrity sha512-ok1d+1WpnU24XYN7oC3QWgTyMhY/avPJ/r9T00xxvUOIparA/gc+UPUMaod3i+G6s+nI2nUb9xZ5k794uIwShw== - dependencies: - caniuse-lite "^1.0.30001349" - electron-to-chromium "^1.4.147" - escalade "^3.1.1" - node-releases "^2.0.5" - picocolors "^1.0.0" - -bs-logger@0.x: - version "0.2.6" - resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" - integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== - dependencies: - fast-json-stable-stringify "2.x" - -bs58@^4.0.0, bs58@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" - integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== - dependencies: - base-x "^3.0.2" - -bser@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" - integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== - dependencies: - node-int64 "^0.4.0" - -buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - -buffer@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.1.tgz#3cbea8c1463e5a0779e30b66d4c88c6ffa182ac2" - integrity sha512-rVAXBwEcEoYtxnHSO5iWyhzV/O1WMtkUYWlfdLS7FjU4PnSJJHEfHXi/uHPI5EwltmOA794gN3bm3/pzuctWjQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - -buffer@^6.0.3, buffer@~6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - -bufferutil@^4.0.1: - version "4.0.6" - resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.6.tgz#ebd6c67c7922a0e902f053e5d8be5ec850e48433" - integrity sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw== - dependencies: - node-gyp-build "^4.3.0" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -camelcase@^6.2.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" - integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== - -caniuse-lite@^1.0.30001349: - version "1.0.30001352" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001352.tgz#cc6f5da3f983979ad1e2cdbae0505dccaa7c6a12" - integrity sha512-GUgH8w6YergqPQDGWhJGt8GDRnY0L/iJVQcU3eJ46GYf52R8tk0Wxp0PymuFVZboJYXGiCqwozAYZNRjVj6IcA== - -chai@^4.3.6: - version "4.3.6" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.6.tgz#ffe4ba2d9fa9d6680cc0b370adae709ec9011e9c" - integrity sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q== - dependencies: - assertion-error "^1.1.0" - check-error "^1.0.2" - deep-eql "^3.0.1" - get-func-name "^2.0.0" - loupe "^2.3.1" - pathval "^1.1.1" - type-detect "^4.0.5" - -chalk@^2.0.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^4.0.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -char-regex@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" - integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== - -check-error@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" - integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA== - -check-more-types@2.24.0: - version "2.24.0" - resolved "https://registry.yarnpkg.com/check-more-types/-/check-more-types-2.24.0.tgz#1420ffb10fd444dcfc79b43891bbfffd32a84600" - integrity sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA== - -ci-info@^3.2.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.1.tgz#58331f6f472a25fe3a50a351ae3052936c2c7f32" - integrity sha512-SXgeMX9VwDe7iFFaEWkA5AstuER9YKqy4EhHqr4DVqkwmD9rpVimkMKWHdjn30Ja45txyjhSn63lVX69eVCckg== - -cjs-module-lexer@^1.0.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" - integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== - -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== - -collect-v8-coverage@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" - integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -combined-stream@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -commander@^2.20.3: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - -convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" - integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== - dependencies: - safe-buffer "~5.1.1" - -create-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== - -cross-spawn@^7.0.2, cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -debug@4.3.2: - version "4.3.2" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" - integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== - dependencies: - ms "2.1.2" - -debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -dedent@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" - integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== - -deep-eql@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" - integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== - dependencies: - type-detect "^4.0.0" - -deep-is@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== - -deepmerge@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" - integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== - -delay@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" - integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== - -detect-newline@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" - integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== - -diff-sequences@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327" - integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ== - -diff-sequences@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-28.1.1.tgz#9989dc731266dc2903457a70e996f3a041913ac6" - integrity sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw== - -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -duplexer@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" - integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== - -electron-to-chromium@^1.4.147: - version "1.4.154" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.154.tgz#d69c60499fc467a6c59591d29183e520afbc78a1" - integrity sha512-GbV9djOkrnj6xmW+YYVVEI3VCQnJ0pnSTu7TW2JyjKd5cakoiSaG5R4RbEtfaD92GsY10DzbU3GYRe+IOA9kqA== - -elliptic@^6.5.4: - version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - -emittery@^0.10.2: - version "0.10.2" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.2.tgz#902eec8aedb8c41938c46e9385e9db7e03182933" - integrity sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -es6-promise@^4.0.3: - version "4.2.8" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" - integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== - -es6-promisify@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" - integrity sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ== - dependencies: - es6-promise "^4.0.3" - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -escape-string-regexp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" - integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== - -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -eslint-config-prettier@^8.5.0: - version "8.5.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz#5a81680ec934beca02c7b1a61cf8ca34b66feab1" - integrity sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q== - -eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-scope@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" - integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== - dependencies: - esrecurse "^4.3.0" - estraverse "^5.2.0" - -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - -eslint-visitor-keys@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" - integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== - -eslint@^8.17.0: - version "8.17.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.17.0.tgz#1cfc4b6b6912f77d24b874ca1506b0fe09328c21" - integrity sha512-gq0m0BTJfci60Fz4nczYxNAlED+sMcihltndR8t9t1evnU/azx53x3t2UHXC/uRjcbvRw/XctpaNygSTcQD+Iw== - dependencies: - "@eslint/eslintrc" "^1.3.0" - "@humanwhocodes/config-array" "^0.9.2" - ajv "^6.10.0" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.3.2" - doctrine "^3.0.0" - escape-string-regexp "^4.0.0" - eslint-scope "^7.1.1" - eslint-utils "^3.0.0" - eslint-visitor-keys "^3.3.0" - espree "^9.3.2" - esquery "^1.4.0" - esutils "^2.0.2" - fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^6.0.1" - globals "^13.15.0" - ignore "^5.2.0" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - js-yaml "^4.1.0" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash.merge "^4.6.2" - minimatch "^3.1.2" - natural-compare "^1.4.0" - optionator "^0.9.1" - regexpp "^3.2.0" - strip-ansi "^6.0.1" - strip-json-comments "^3.1.0" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -espree@^9.3.2: - version "9.3.2" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.2.tgz#f58f77bd334731182801ced3380a8cc859091596" - integrity sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA== - dependencies: - acorn "^8.7.1" - acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.3.0" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -event-stream@=3.3.4: - version "3.3.4" - resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" - integrity sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g== - dependencies: - duplexer "~0.1.1" - from "~0" - map-stream "~0.1.0" - pause-stream "0.0.11" - split "0.3" - stream-combiner "~0.0.4" - through "~2.3.1" - -eventemitter3@^4.0.7: - version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" - integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== - -execa@5.1.1, execa@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - -exit@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== - -expect@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/expect/-/expect-28.1.1.tgz#ca6fff65f6517cf7220c2e805a49c19aea30b420" - integrity sha512-/AANEwGL0tWBwzLNOvO0yUdy2D52jVdNXppOqswC49sxMN2cPWsGCQdzuIf9tj6hHoBQzNvx75JUYuQAckPo3w== - dependencies: - "@jest/expect-utils" "^28.1.1" - jest-get-type "^28.0.2" - jest-matcher-utils "^28.1.1" - jest-message-util "^28.1.1" - jest-util "^28.1.1" - -eyes@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" - integrity sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ== - -fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-glob@^3.2.9: - version "3.2.11" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" - integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - -fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== - -fast-stable-stringify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz#5c5543462b22aeeefd36d05b34e51c78cb86d313" - integrity sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag== - -fastq@^1.6.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" - integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== - dependencies: - reusify "^1.0.4" - -fb-watchman@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" - integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== - dependencies: - bser "2.1.1" - -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== - dependencies: - flat-cache "^3.0.4" - -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -find-up@^4.0.0, find-up@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== - dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" - -flatted@^3.1.0: - version "3.2.5" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" - integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== - -follow-redirects@^1.14.0: - version "1.15.1" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5" - integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA== - -form-data@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" - integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -from@~0: - version "0.1.7" - resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" - integrity sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g== - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== - -fsevents@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -get-func-name@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" - integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== - -get-package-type@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" - integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== - -get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - -glob-parent@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob-parent@^6.0.1: - version "6.0.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" - integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== - dependencies: - is-glob "^4.0.3" - -glob@^7.1.3, glob@^7.1.4: - version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.1.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globals@^13.15.0: - version "13.15.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.15.0.tgz#38113218c907d2f7e98658af246cef8b77e90bac" - integrity sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog== - dependencies: - type-fest "^0.20.2" - -globby@^11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" - -graceful-fs@^4.2.9: - version "4.2.10" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" - integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -html-escaper@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" - integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== - -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - -ieee754@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -ignore@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" - integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== - -import-fresh@^3.0.0, import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -import-local@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" - integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== - dependencies: - pkg-dir "^4.2.0" - resolve-cwd "^3.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@^2.0.3, inherits@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== - -is-core-module@^2.8.1: - version "2.9.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69" - integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== - dependencies: - has "^1.0.3" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-generator-fn@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" - integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== - -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -isomorphic-ws@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" - integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== - -istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" - integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== - -istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz#31d18bdd127f825dd02ea7bfdfd906f8ab840e9f" - integrity sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A== - dependencies: - "@babel/core" "^7.12.3" - "@babel/parser" "^7.14.7" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.2.0" - semver "^6.3.0" - -istanbul-lib-report@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" - integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== - dependencies: - istanbul-lib-coverage "^3.0.0" - make-dir "^3.0.0" - supports-color "^7.1.0" - -istanbul-lib-source-maps@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" - integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== - dependencies: - debug "^4.1.1" - istanbul-lib-coverage "^3.0.0" - source-map "^0.6.1" - -istanbul-reports@^3.1.3: - version "3.1.4" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.4.tgz#1b6f068ecbc6c331040aab5741991273e609e40c" - integrity sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw== - dependencies: - html-escaper "^2.0.0" - istanbul-lib-report "^3.0.0" - -jayson@^3.4.4: - version "3.6.6" - resolved "https://registry.yarnpkg.com/jayson/-/jayson-3.6.6.tgz#189984f624e398f831bd2be8e8c80eb3abf764a1" - integrity sha512-f71uvrAWTtrwoww6MKcl9phQTC+56AopLyEenWvKVAIMz+q0oVGj6tenLZ7Z6UiPBkJtKLj4kt0tACllFQruGQ== - dependencies: - "@types/connect" "^3.4.33" - "@types/express-serve-static-core" "^4.17.9" - "@types/lodash" "^4.14.159" - "@types/node" "^12.12.54" - "@types/ws" "^7.4.4" - JSONStream "^1.3.5" - commander "^2.20.3" - delay "^5.0.0" - es6-promisify "^5.0.0" - eyes "^0.1.8" - isomorphic-ws "^4.0.1" - json-stringify-safe "^5.0.1" - lodash "^4.17.20" - uuid "^8.3.2" - ws "^7.4.5" - -jest-changed-files@^28.0.2: - version "28.0.2" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-28.0.2.tgz#7d7810660a5bd043af9e9cfbe4d58adb05e91531" - integrity sha512-QX9u+5I2s54ZnGoMEjiM2WeBvJR2J7w/8ZUmH2um/WLAuGAYFQcsVXY9+1YL6k0H/AGUdH8pXUAv6erDqEsvIA== - dependencies: - execa "^5.0.0" - throat "^6.0.1" - -jest-circus@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-28.1.1.tgz#3d27da6a974d85a466dc0cdc6ddeb58daaa57bb4" - integrity sha512-75+BBVTsL4+p2w198DQpCeyh1RdaS2lhEG87HkaFX/UG0gJExVq2skG2pT7XZEGBubNj2CytcWSPan4QEPNosw== - dependencies: - "@jest/environment" "^28.1.1" - "@jest/expect" "^28.1.1" - "@jest/test-result" "^28.1.1" - "@jest/types" "^28.1.1" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - dedent "^0.7.0" - is-generator-fn "^2.0.0" - jest-each "^28.1.1" - jest-matcher-utils "^28.1.1" - jest-message-util "^28.1.1" - jest-runtime "^28.1.1" - jest-snapshot "^28.1.1" - jest-util "^28.1.1" - pretty-format "^28.1.1" - slash "^3.0.0" - stack-utils "^2.0.3" - throat "^6.0.1" - -jest-cli@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-28.1.1.tgz#23ddfde8940e1818585ae4a568877b33b0e51cfe" - integrity sha512-+sUfVbJqb1OjBZ0OdBbI6OWfYM1i7bSfzYy6gze1F1w3OKWq8ZTEKkZ8a7ZQPq6G/G1qMh/uKqpdWhgl11NFQQ== - dependencies: - "@jest/core" "^28.1.1" - "@jest/test-result" "^28.1.1" - "@jest/types" "^28.1.1" - chalk "^4.0.0" - exit "^0.1.2" - graceful-fs "^4.2.9" - import-local "^3.0.2" - jest-config "^28.1.1" - jest-util "^28.1.1" - jest-validate "^28.1.1" - prompts "^2.0.1" - yargs "^17.3.1" - -jest-config@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-28.1.1.tgz#e90b97b984f14a6c24a221859e81b258990fce2f" - integrity sha512-tASynMhS+jVV85zKvjfbJ8nUyJS/jUSYZ5KQxLUN2ZCvcQc/OmhQl2j6VEL3ezQkNofxn5pQ3SPYWPHb0unTZA== - dependencies: - "@babel/core" "^7.11.6" - "@jest/test-sequencer" "^28.1.1" - "@jest/types" "^28.1.1" - babel-jest "^28.1.1" - chalk "^4.0.0" - ci-info "^3.2.0" - deepmerge "^4.2.2" - glob "^7.1.3" - graceful-fs "^4.2.9" - jest-circus "^28.1.1" - jest-environment-node "^28.1.1" - jest-get-type "^28.0.2" - jest-regex-util "^28.0.2" - jest-resolve "^28.1.1" - jest-runner "^28.1.1" - jest-util "^28.1.1" - jest-validate "^28.1.1" - micromatch "^4.0.4" - parse-json "^5.2.0" - pretty-format "^28.1.1" - slash "^3.0.0" - strip-json-comments "^3.1.1" - -jest-diff@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.5.1.tgz#a07f5011ac9e6643cf8a95a462b7b1ecf6680def" - integrity sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw== - dependencies: - chalk "^4.0.0" - diff-sequences "^27.5.1" - jest-get-type "^27.5.1" - pretty-format "^27.5.1" - -jest-diff@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-28.1.1.tgz#1a3eedfd81ae79810931c63a1d0f201b9120106c" - integrity sha512-/MUUxeR2fHbqHoMMiffe/Afm+U8U4olFRJ0hiVG2lZatPJcnGxx292ustVu7bULhjV65IYMxRdploAKLbcrsyg== - dependencies: - chalk "^4.0.0" - diff-sequences "^28.1.1" - jest-get-type "^28.0.2" - pretty-format "^28.1.1" - -jest-docblock@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-28.1.1.tgz#6f515c3bf841516d82ecd57a62eed9204c2f42a8" - integrity sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA== - dependencies: - detect-newline "^3.0.0" - -jest-each@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-28.1.1.tgz#ba5238dacf4f31d9fe23ddc2c44c01e7c23885c4" - integrity sha512-A042rqh17ZvEhRceDMi784ppoXR7MWGDEKTXEZXb4svt0eShMZvijGxzKsx+yIjeE8QYmHPrnHiTSQVhN4nqaw== - dependencies: - "@jest/types" "^28.1.1" - chalk "^4.0.0" - jest-get-type "^28.0.2" - jest-util "^28.1.1" - pretty-format "^28.1.1" - -jest-environment-node@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-28.1.1.tgz#1c86c59003a7d319fa06ea3b1bbda6c193715c67" - integrity sha512-2aV/eeY/WNgUUJrrkDJ3cFEigjC5fqT1+fCclrY6paqJ5zVPoM//sHmfgUUp7WLYxIdbPwMiVIzejpN56MxnNA== - dependencies: - "@jest/environment" "^28.1.1" - "@jest/fake-timers" "^28.1.1" - "@jest/types" "^28.1.1" - "@types/node" "*" - jest-mock "^28.1.1" - jest-util "^28.1.1" - -jest-get-type@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1" - integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== - -jest-get-type@^28.0.2: - version "28.0.2" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-28.0.2.tgz#34622e628e4fdcd793d46db8a242227901fcf203" - integrity sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA== - -jest-haste-map@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-28.1.1.tgz#471685f1acd365a9394745bb97c8fc16289adca3" - integrity sha512-ZrRSE2o3Ezh7sb1KmeLEZRZ4mgufbrMwolcFHNRSjKZhpLa8TdooXOOFlSwoUzlbVs1t0l7upVRW2K7RWGHzbQ== - dependencies: - "@jest/types" "^28.1.1" - "@types/graceful-fs" "^4.1.3" - "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.9" - jest-regex-util "^28.0.2" - jest-util "^28.1.1" - jest-worker "^28.1.1" - micromatch "^4.0.4" - walker "^1.0.8" - optionalDependencies: - fsevents "^2.3.2" - -jest-leak-detector@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-28.1.1.tgz#537f37afd610a4b3f4cab15e06baf60484548efb" - integrity sha512-4jvs8V8kLbAaotE+wFR7vfUGf603cwYtFf1/PYEsyX2BAjSzj8hQSVTP6OWzseTl0xL6dyHuKs2JAks7Pfubmw== - dependencies: - jest-get-type "^28.0.2" - pretty-format "^28.1.1" - -jest-matcher-utils@^27.0.0: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab" - integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw== - dependencies: - chalk "^4.0.0" - jest-diff "^27.5.1" - jest-get-type "^27.5.1" - pretty-format "^27.5.1" - -jest-matcher-utils@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-28.1.1.tgz#a7c4653c2b782ec96796eb3088060720f1e29304" - integrity sha512-NPJPRWrbmR2nAJ+1nmnfcKKzSwgfaciCCrYZzVnNoxVoyusYWIjkBMNvu0RHJe7dNj4hH3uZOPZsQA+xAYWqsw== - dependencies: - chalk "^4.0.0" - jest-diff "^28.1.1" - jest-get-type "^28.0.2" - pretty-format "^28.1.1" - -jest-message-util@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-28.1.1.tgz#60aa0b475cfc08c8a9363ed2fb9108514dd9ab89" - integrity sha512-xoDOOT66fLfmTRiqkoLIU7v42mal/SqwDKvfmfiWAdJMSJiU+ozgluO7KbvoAgiwIrrGZsV7viETjc8GNrA/IQ== - dependencies: - "@babel/code-frame" "^7.12.13" - "@jest/types" "^28.1.1" - "@types/stack-utils" "^2.0.0" - chalk "^4.0.0" - graceful-fs "^4.2.9" - micromatch "^4.0.4" - pretty-format "^28.1.1" - slash "^3.0.0" - stack-utils "^2.0.3" - -jest-mock@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-28.1.1.tgz#37903d269427fa1ef5b2447be874e1c62a39a371" - integrity sha512-bDCb0FjfsmKweAvE09dZT59IMkzgN0fYBH6t5S45NoJfd2DHkS3ySG2K+hucortryhO3fVuXdlxWcbtIuV/Skw== - dependencies: - "@jest/types" "^28.1.1" - "@types/node" "*" - -jest-pnp-resolver@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" - integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== - -jest-regex-util@^28.0.2: - version "28.0.2" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-28.0.2.tgz#afdc377a3b25fb6e80825adcf76c854e5bf47ead" - integrity sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw== - -jest-resolve-dependencies@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.1.tgz#3dffaaa56f4b41bc6b61053899d1756401763a27" - integrity sha512-p8Y150xYJth4EXhOuB8FzmS9r8IGLEioiaetgdNGb9VHka4fl0zqWlVe4v7mSkYOuEUg2uB61iE+zySDgrOmgQ== - dependencies: - jest-regex-util "^28.0.2" - jest-snapshot "^28.1.1" - -jest-resolve@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-28.1.1.tgz#bc2eaf384abdcc1aaf3ba7c50d1adf01e59095e5" - integrity sha512-/d1UbyUkf9nvsgdBildLe6LAD4DalgkgZcKd0nZ8XUGPyA/7fsnaQIlKVnDiuUXv/IeZhPEDrRJubVSulxrShA== - dependencies: - chalk "^4.0.0" - graceful-fs "^4.2.9" - jest-haste-map "^28.1.1" - jest-pnp-resolver "^1.2.2" - jest-util "^28.1.1" - jest-validate "^28.1.1" - resolve "^1.20.0" - resolve.exports "^1.1.0" - slash "^3.0.0" - -jest-runner@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-28.1.1.tgz#9ecdb3f27a00059986797aa6b012ba8306aa436c" - integrity sha512-W5oFUiDBgTsCloTAj6q95wEvYDB0pxIhY6bc5F26OucnwBN+K58xGTGbliSMI4ChQal5eANDF+xvELaYkJxTmA== - dependencies: - "@jest/console" "^28.1.1" - "@jest/environment" "^28.1.1" - "@jest/test-result" "^28.1.1" - "@jest/transform" "^28.1.1" - "@jest/types" "^28.1.1" - "@types/node" "*" - chalk "^4.0.0" - emittery "^0.10.2" - graceful-fs "^4.2.9" - jest-docblock "^28.1.1" - jest-environment-node "^28.1.1" - jest-haste-map "^28.1.1" - jest-leak-detector "^28.1.1" - jest-message-util "^28.1.1" - jest-resolve "^28.1.1" - jest-runtime "^28.1.1" - jest-util "^28.1.1" - jest-watcher "^28.1.1" - jest-worker "^28.1.1" - source-map-support "0.5.13" - throat "^6.0.1" - -jest-runtime@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-28.1.1.tgz#569e1dc3c36c6c4c0b29516c1c49b6ad580abdaf" - integrity sha512-J89qEJWW0leOsqyi0D9zHpFEYHwwafFdS9xgvhFHtIdRghbadodI0eA+DrthK/1PebBv3Px8mFSMGKrtaVnleg== - dependencies: - "@jest/environment" "^28.1.1" - "@jest/fake-timers" "^28.1.1" - "@jest/globals" "^28.1.1" - "@jest/source-map" "^28.0.2" - "@jest/test-result" "^28.1.1" - "@jest/transform" "^28.1.1" - "@jest/types" "^28.1.1" - chalk "^4.0.0" - cjs-module-lexer "^1.0.0" - collect-v8-coverage "^1.0.0" - execa "^5.0.0" - glob "^7.1.3" - graceful-fs "^4.2.9" - jest-haste-map "^28.1.1" - jest-message-util "^28.1.1" - jest-mock "^28.1.1" - jest-regex-util "^28.0.2" - jest-resolve "^28.1.1" - jest-snapshot "^28.1.1" - jest-util "^28.1.1" - slash "^3.0.0" - strip-bom "^4.0.0" - -jest-snapshot@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-28.1.1.tgz#ab825c16c8d8b5e883bd57eee6ca8748c42ab848" - integrity sha512-1KjqHJ98adRcbIdMizjF5DipwZFbvxym/kFO4g4fVZCZRxH/dqV8TiBFCa6rqic3p0karsy8RWS1y4E07b7P0A== - dependencies: - "@babel/core" "^7.11.6" - "@babel/generator" "^7.7.2" - "@babel/plugin-syntax-typescript" "^7.7.2" - "@babel/traverse" "^7.7.2" - "@babel/types" "^7.3.3" - "@jest/expect-utils" "^28.1.1" - "@jest/transform" "^28.1.1" - "@jest/types" "^28.1.1" - "@types/babel__traverse" "^7.0.6" - "@types/prettier" "^2.1.5" - babel-preset-current-node-syntax "^1.0.0" - chalk "^4.0.0" - expect "^28.1.1" - graceful-fs "^4.2.9" - jest-diff "^28.1.1" - jest-get-type "^28.0.2" - jest-haste-map "^28.1.1" - jest-matcher-utils "^28.1.1" - jest-message-util "^28.1.1" - jest-util "^28.1.1" - natural-compare "^1.4.0" - pretty-format "^28.1.1" - semver "^7.3.5" - -jest-util@^28.0.0, jest-util@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-28.1.1.tgz#ff39e436a1aca397c0ab998db5a51ae2b7080d05" - integrity sha512-FktOu7ca1DZSyhPAxgxB6hfh2+9zMoJ7aEQA759Z6p45NuO8mWcqujH+UdHlCm/V6JTWwDztM2ITCzU1ijJAfw== - dependencies: - "@jest/types" "^28.1.1" - "@types/node" "*" - chalk "^4.0.0" - ci-info "^3.2.0" - graceful-fs "^4.2.9" - picomatch "^2.2.3" - -jest-validate@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-28.1.1.tgz#59b7b339b3c85b5144bd0c06ad3600f503a4acc8" - integrity sha512-Kpf6gcClqFCIZ4ti5++XemYJWUPCFUW+N2gknn+KgnDf549iLul3cBuKVe1YcWRlaF8tZV8eJCap0eECOEE3Ug== - dependencies: - "@jest/types" "^28.1.1" - camelcase "^6.2.0" - chalk "^4.0.0" - jest-get-type "^28.0.2" - leven "^3.1.0" - pretty-format "^28.1.1" - -jest-watcher@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-28.1.1.tgz#533597fb3bfefd52b5cd115cd916cffd237fb60c" - integrity sha512-RQIpeZ8EIJMxbQrXpJQYIIlubBnB9imEHsxxE41f54ZwcqWLysL/A0ZcdMirf+XsMn3xfphVQVV4EW0/p7i7Ug== - dependencies: - "@jest/test-result" "^28.1.1" - "@jest/types" "^28.1.1" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - emittery "^0.10.2" - jest-util "^28.1.1" - string-length "^4.0.1" - -jest-worker@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-28.1.1.tgz#3480c73247171dfd01eda77200f0063ab6a3bf28" - integrity sha512-Au7slXB08C6h+xbJPp7VIb6U0XX5Kc9uel/WFc6/rcTzGiaVCBRngBExSYuXSLFPULPSYU3cJ3ybS988lNFQhQ== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^8.0.0" - -jest@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest/-/jest-28.1.1.tgz#3c39a3a09791e16e9ef283597d24ab19a0df701e" - integrity sha512-qw9YHBnjt6TCbIDMPMpJZqf9E12rh6869iZaN08/vpOGgHJSAaLLUn6H8W3IAEuy34Ls3rct064mZLETkxJ2XA== - dependencies: - "@jest/core" "^28.1.1" - "@jest/types" "^28.1.1" - import-local "^3.0.2" - jest-cli "^28.1.1" - -joi@^17.4.0: - version "17.6.0" - resolved "https://registry.yarnpkg.com/joi/-/joi-17.6.0.tgz#0bb54f2f006c09a96e75ce687957bd04290054b2" - integrity sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw== - dependencies: - "@hapi/hoek" "^9.0.0" - "@hapi/topo" "^5.0.0" - "@sideway/address" "^4.1.3" - "@sideway/formula" "^3.0.0" - "@sideway/pinpoint" "^2.0.0" - -js-sha3@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" - integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -json-parse-even-better-errors@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" - integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== - -json-stringify-safe@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== - -json5@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" - integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== - -jsonparse@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" - integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== - -kleur@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" - integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== - -lazy-ass@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/lazy-ass/-/lazy-ass-1.6.0.tgz#7999655e8646c17f089fdd187d150d3324d54513" - integrity sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw== - -leven@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" - integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== - -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -lines-and-columns@^1.1.6: - version "1.2.4" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" - integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== - -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" - -lodash.memoize@4.x: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" - integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== - -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - -lodash@^4.17.20, lodash@^4.17.21: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -loupe@^2.3.1: - version "2.3.4" - resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.4.tgz#7e0b9bffc76f148f9be769cb1321d3dcf3cb25f3" - integrity sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ== - dependencies: - get-func-name "^2.0.0" - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -make-dir@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - -make-error@1.x, make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -makeerror@1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" - integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== - dependencies: - tmpl "1.0.5" - -map-stream@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" - integrity sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g== - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - -merge2@^1.3.0, merge2@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== - dependencies: - braces "^3.0.2" - picomatch "^2.3.1" - -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -mime-types@^2.1.12: - version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== - -minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.2.5: - version "1.2.6" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" - integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== - -node-addon-api@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" - integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== - -node-fetch@2: - version "2.6.7" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" - integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== - dependencies: - whatwg-url "^5.0.0" - -node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.4.0.tgz#42e99687ce87ddeaf3a10b99dc06abc11021f3f4" - integrity sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ== - -node-int64@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== - -node-releases@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.5.tgz#280ed5bc3eba0d96ce44897d8aee478bfb3d9666" - integrity sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q== - -normalize-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - -onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== - dependencies: - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - word-wrap "^1.2.3" - -p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -parse-json@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" - integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== - dependencies: - "@babel/code-frame" "^7.0.0" - error-ex "^1.3.1" - json-parse-even-better-errors "^2.3.0" - lines-and-columns "^1.1.6" - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - -path-key@^3.0.0, path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -pathval@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" - integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== - -pause-stream@0.0.11: - version "0.0.11" - resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" - integrity sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A== - dependencies: - through "~2.3" - -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== - -picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -pirates@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" - integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== - -pkg-dir@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== - dependencies: - find-up "^4.0.0" - -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -prettier@^2.7.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.0.tgz#a4fdae07e5596c51c9857ea676cd41a0163879d6" - integrity sha512-nwoX4GMFgxoPC6diHvSwmK/4yU8FFH3V8XWtLQrbj4IBsK2pkYhG4kf/ljF/haaZ/aii+wNJqISrCDPgxGWDVQ== - -pretty-format@^27.0.0, pretty-format@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" - integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== - dependencies: - ansi-regex "^5.0.1" - ansi-styles "^5.0.0" - react-is "^17.0.1" - -pretty-format@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-28.1.1.tgz#f731530394e0f7fcd95aba6b43c50e02d86b95cb" - integrity sha512-wwJbVTGFHeucr5Jw2bQ9P+VYHyLdAqedFLEkdQUVaBF/eiidDwH5OpilINq4mEfhbCjLnirt6HTTDhv1HaTIQw== - dependencies: - "@jest/schemas" "^28.0.2" - ansi-regex "^5.0.1" - ansi-styles "^5.0.0" - react-is "^18.0.0" - -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== - -prompts@^2.0.1: - version "2.4.2" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" - integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== - dependencies: - kleur "^3.0.3" - sisteransi "^1.0.5" - -ps-tree@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.2.0.tgz#5e7425b89508736cdd4f2224d028f7bb3f722ebd" - integrity sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA== - dependencies: - event-stream "=3.3.4" - -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - -react-is@^17.0.1: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" - integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== - -react-is@^18.0.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" - integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== - -regenerator-runtime@^0.13.4: - version "0.13.9" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" - integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== - -regexpp@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== - -resolve-cwd@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" - integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== - dependencies: - resolve-from "^5.0.0" - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve-from@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" - integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== - -resolve.exports@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" - integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== - -resolve@^1.20.0: - version "1.22.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" - integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== - dependencies: - is-core-module "^2.8.1" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rimraf@^3.0.0, rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -rpc-websockets@^7.4.2: - version "7.5.0" - resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.5.0.tgz#bbeb87572e66703ff151e50af1658f98098e2748" - integrity sha512-9tIRi1uZGy7YmDjErf1Ax3wtqdSSLIlnmL5OtOzgd5eqPKbsPpwDP5whUDO2LQay3Xp0CcHlcNSGzacNRluBaQ== - dependencies: - "@babel/runtime" "^7.17.2" - eventemitter3 "^4.0.7" - uuid "^8.3.2" - ws "^8.5.0" - optionalDependencies: - bufferutil "^4.0.1" - utf-8-validate "^5.0.2" - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -rxjs@^7.1.0: - version "7.5.5" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.5.tgz#2ebad89af0f560f460ad5cc4213219e1f7dd4e9f" - integrity sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw== - dependencies: - tslib "^2.1.0" - -safe-buffer@^5.0.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -secp256k1@^4.0.2: - version "4.0.3" - resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.3.tgz#c4559ecd1b8d3c1827ed2d1b94190d69ce267303" - integrity sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA== - dependencies: - elliptic "^6.5.4" - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" - -semver@7.x, semver@^7.3.5, semver@^7.3.7: - version "7.3.7" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" - integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== - dependencies: - lru-cache "^6.0.0" - -semver@^6.0.0, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -signal-exit@^3.0.3, signal-exit@^3.0.7: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - -sisteransi@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" - integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -source-map-support@0.5.13: - version "0.5.13" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" - integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map@^0.6.0, source-map@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -split@0.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" - integrity sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA== - dependencies: - through "2" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== - -stack-utils@^2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" - integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== - dependencies: - escape-string-regexp "^2.0.0" - -start-server-and-test@^1.14.0: - version "1.14.0" - resolved "https://registry.yarnpkg.com/start-server-and-test/-/start-server-and-test-1.14.0.tgz#c57f04f73eac15dd51733b551d775b40837fdde3" - integrity sha512-on5ELuxO2K0t8EmNj9MtVlFqwBMxfWOhu4U7uZD1xccVpFlOQKR93CSe0u98iQzfNxRyaNTb/CdadbNllplTsw== - dependencies: - bluebird "3.7.2" - check-more-types "2.24.0" - debug "4.3.2" - execa "5.1.1" - lazy-ass "1.6.0" - ps-tree "1.2.0" - wait-on "6.0.0" - -stream-combiner@~0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" - integrity sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw== - dependencies: - duplexer "~0.1.1" - -string-length@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" - integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== - dependencies: - char-regex "^1.0.2" - strip-ansi "^6.0.0" - -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-bom@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" - integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== - -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -superstruct@^0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.14.2.tgz#0dbcdf3d83676588828f1cf5ed35cda02f59025b" - integrity sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ== - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.0.0, supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-color@^8.0.0: - version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - -supports-hyperlinks@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" - integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== - dependencies: - has-flag "^4.0.0" - supports-color "^7.0.0" - -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - -terminal-link@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" - integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== - dependencies: - ansi-escapes "^4.2.1" - supports-hyperlinks "^2.0.0" - -test-exclude@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" - integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== - dependencies: - "@istanbuljs/schema" "^0.1.2" - glob "^7.1.4" - minimatch "^3.0.4" - -text-encoding-utf-8@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz#585b62197b0ae437e3c7b5d0af27ac1021e10d13" - integrity sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg== - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== - -throat@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" - integrity sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w== - -through@2, "through@>=2.2.7 <3", through@~2.3, through@~2.3.1: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== - -tmpl@1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" - integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== - -ts-jest@^28.0.5: - version "28.0.5" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-28.0.5.tgz#31776f768fba6dfc8c061d488840ed0c8eeac8b9" - integrity sha512-Sx9FyP9pCY7pUzQpy4FgRZf2bhHY3za576HMKJFs+OnQ9jS96Du5vNsDKkyedQkik+sEabbKAnCliv9BEsHZgQ== - dependencies: - bs-logger "0.x" - fast-json-stable-stringify "2.x" - jest-util "^28.0.0" - json5 "^2.2.1" - lodash.memoize "4.x" - make-error "1.x" - semver "7.x" - yargs-parser "^21.0.1" - -ts-node@^10.8.1: - version "10.8.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.8.1.tgz#ea2bd3459011b52699d7e88daa55a45a1af4f066" - integrity sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g== - dependencies: - "@cspotcode/source-map-support" "^0.8.0" - "@tsconfig/node10" "^1.0.7" - "@tsconfig/node12" "^1.0.7" - "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.2" - acorn "^8.4.1" - acorn-walk "^8.1.1" - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - v8-compile-cache-lib "^3.0.1" - yn "3.1.1" - -tslib@^1.8.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tslib@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" - integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== - -tsutils@^3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - -tweetnacl@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" - integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== - -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - -type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.5: - version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== - -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - -type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - -typescript@^4.7.3: - version "4.7.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.3.tgz#8364b502d5257b540f9de4c40be84c98e23a129d" - integrity sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA== - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -utf-8-validate@^5.0.2: - version "5.0.9" - resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.9.tgz#ba16a822fbeedff1a58918f2a6a6b36387493ea3" - integrity sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q== - dependencies: - node-gyp-build "^4.3.0" - -uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - -v8-compile-cache-lib@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" - integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== - -v8-compile-cache@^2.0.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== - -v8-to-istanbul@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.0.0.tgz#be0dae58719fc53cb97e5c7ac1d7e6d4f5b19511" - integrity sha512-HcvgY/xaRm7isYmyx+lFKA4uQmfUbN0J4M0nNItvzTvH/iQ9kW5j/t4YSR+Ge323/lrgDAWJoF46tzGQHwBHFw== - dependencies: - "@jridgewell/trace-mapping" "^0.3.7" - "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" - -wait-on@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-6.0.0.tgz#7e9bf8e3d7fe2daecbb7a570ac8ca41e9311c7e7" - integrity sha512-tnUJr9p5r+bEYXPUdRseolmz5XqJTTj98JgOsfBn7Oz2dxfE2g3zw1jE+Mo8lopM3j3et/Mq1yW7kKX6qw7RVw== - dependencies: - axios "^0.21.1" - joi "^17.4.0" - lodash "^4.17.21" - minimist "^1.2.5" - rxjs "^7.1.0" - -walker@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" - integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== - dependencies: - makeerror "1.0.12" - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -word-wrap@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - -write-file-atomic@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.1.tgz#9faa33a964c1c85ff6f849b80b42a88c2c537c8f" - integrity sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ== - dependencies: - imurmurhash "^0.1.4" - signal-exit "^3.0.7" - -ws@^7.4.5: - version "7.5.8" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.8.tgz#ac2729881ab9e7cbaf8787fe3469a48c5c7f636a" - integrity sha512-ri1Id1WinAX5Jqn9HejiGb8crfRio0Qgu8+MtL36rlTA6RLsMdWt1Az/19A2Qij6uSHUMphEFaTKa4WG+UNHNw== - -ws@^8.5.0: - version "8.8.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.8.0.tgz#8e71c75e2f6348dbf8d78005107297056cb77769" - integrity sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ== - -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yargs-parser@^21.0.0, yargs-parser@^21.0.1: - version "21.0.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.1.tgz#0267f286c877a4f0f728fceb6f8a3e4cb95c6e35" - integrity sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg== - -yargs@^17.3.1: - version "17.5.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e" - integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.3" - y18n "^5.0.5" - yargs-parser "^21.0.0" - -yn@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== diff --git a/name-service/README.md b/name-service/README.md index bbc36c1735a..b12c637f894 100644 --- a/name-service/README.md +++ b/name-service/README.md @@ -8,4 +8,9 @@ utilize to create and use their own version of a name service of any kind. Full documentation is available at https://spl.solana.com/name-service -JavaScript binding are available in the `./js` directory. \ No newline at end of file +JavaScript binding are available in the `./js` directory. + +## Audit + +The repository [README](https://github.com/solana-labs/solana-program-library#audits) +contains information about program audits. diff --git a/name-service/js/.eslintignore b/name-service/js/.eslintignore new file mode 100644 index 00000000000..6da325effab --- /dev/null +++ b/name-service/js/.eslintignore @@ -0,0 +1,5 @@ +docs +lib +test-ledger + +package-lock.json diff --git a/name-service/js/.eslintrc.json b/name-service/js/.eslintrc.json index b8afff428fd..a6f356a97f9 100644 --- a/name-service/js/.eslintrc.json +++ b/name-service/js/.eslintrc.json @@ -10,8 +10,7 @@ "plugin:eslint-comments/recommended", "plugin:@typescript-eslint/recommended", "plugin:import/typescript", - "prettier", - "prettier/@typescript-eslint" + "prettier" ], "globals": { "BigInt": true, "console": true, "WebAssembly": true }, "rules": { diff --git a/name-service/js/README.md b/name-service/js/README.md index e340ca1b0eb..8a5bb243e8d 100644 --- a/name-service/js/README.md +++ b/name-service/js/README.md @@ -1,6 +1,6 @@ # Name Service JavaScript bindings -[![npm](https://img.shields.io/npm/v/@solana/spl-name-service)](https://unpkg.com/@solana/spl-name-service@latest/) [![GitHub license](https://img.shields.io/badge/license-APACHE-blue.svg)](https://github.com/solana-labs/token-list/blob/b3fa86b3fdd9c817139e38641d46c5a892542a52/LICENSE) +[![npm](https://img.shields.io/npm/v/@solana/spl-name-service)](https://unpkg.com/@solana/spl-name-service@latest/) Full documentation is available at https://spl.solana.com/name-service diff --git a/name-service/js/jest.config.ts b/name-service/js/jest.config.ts new file mode 100644 index 00000000000..e584adb3225 --- /dev/null +++ b/name-service/js/jest.config.ts @@ -0,0 +1,7 @@ +import type { JestConfigWithTsJest } from 'ts-jest'; + +const jestConfig: JestConfigWithTsJest = { + preset: 'ts-jest', +}; + +export default jestConfig; diff --git a/name-service/js/package.json b/name-service/js/package.json index f01292f6df2..430b70d689c 100644 --- a/name-service/js/package.json +++ b/name-service/js/package.json @@ -1,10 +1,12 @@ { "name": "@solana/spl-name-service", - "version": "0.1.4", + "version": "0.2.1", "description": "SPL Name Service JavaScript API", "license": "MIT", - "author": "Solana Maintainers ", + "author": "Solana Labs Maintainers ", "homepage": "https://solana.com/", + "type": "module", + "sideEffects": false, "repository": { "type": "git", "url": "https://github.com/solana-labs/solana-program-library" @@ -15,41 +17,51 @@ "publishConfig": { "access": "public" }, - "main": "dist/index.js", - "types": "dist/index.d.ts", + "files": [ + "lib", + "src", + "LICENSE" + ], + "main": "lib/cjs/index.js", + "module": "lib/esm/index.js", + "types": "lib/types/index.d.ts", + "exports": { + "types": "lib/types/index.d.ts", + "require": "lib/cjs/index.js", + "import": "lib/esm/index.js" + }, "scripts": { - "dev": "tsc && node --trace-warnings dist/transfer.js", - "build": "tsc", + "build": "tsc --build --verbose tsconfig.all.json", + "build:program": "cargo build-sbf --manifest-path=../program/Cargo.toml", "prepublish": "tsc", - "lint": "yarn pretty && eslint --max-warnings 0 'src/*.ts'", - "lint:fix": "yarn pretty:fix && eslint 'src/*.ts' --fix", - "pretty": "prettier --check 'src/*.ts'", - "pretty:fix": "prettier --write 'src/*.ts'", - "doc": "yarn typedoc src/index.ts" - }, - "prettier": { - "singleQuote": true + "lint": "eslint --max-warnings 0 'src/*.ts'", + "lint:fix": "eslint 'src/*.ts' --fix", + "doc": "npm run typedoc src/index.ts", + "test": "npm run test:unit && npm run test:e2e", + "test:unit": "NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest test/unit", + "test:e2e": "NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" start-server-and-test 'solana-test-validator --bpf-program namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX ../../target/deploy/spl_name_service.so --reset --quiet' http://127.0.0.1:8899/health 'jest test/e2e'" }, "devDependencies": { - "@tsconfig/recommended": "^1.0.1", - "@types/node": "^14.14.20", - "@typescript-eslint/eslint-plugin": "^4.0.1", - "@typescript-eslint/parser": "^4.0.1", - "babel-eslint": "^10.1.0", - "eslint": "^7.8.0", - "eslint-config-prettier": "^6.11.0", + "@jest/globals": "^29.7.0", + "@types/bn.js": "^5.1.6", + "@types/jest": "^29.5.14", + "@types/node": "^22.10.5", + "@typescript-eslint/eslint-plugin": "^8.4.0", + "@typescript-eslint/parser": "^8.4.0", + "eslint": "^8.57.0", "eslint-plugin-eslint-comments": "^3.2.0", - "eslint-plugin-functional": "^3.0.2", - "eslint-plugin-import": "^2.22.0", - "prettier": "^2.2.1", - "ts-node": "^9.1.1", - "typedoc": "^0.22.11", - "typescript": "^4.1.3" + "eslint-plugin-functional": "^7.2.1", + "eslint-plugin-import": "^2.31.0", + "jest": "^29.7.0", + "start-server-and-test": "^2.0.9", + "ts-jest": "^29.2.5", + "ts-node": "^10.9.2", + "typedoc": "^0.27.6", + "typescript": "^5.7.2" }, "dependencies": { - "@solana/spl-token": "0.1.4", - "@solana/web3.js": "^1.11.0", + "@solana/web3.js": "^1.95.5", "bn.js": "^5.1.3", - "borsh": "^0.4.0" + "borsh": "^2.0.0" } } diff --git a/name-service/js/src/bindings.ts b/name-service/js/src/bindings.ts index c39331dedec..b2377c51967 100644 --- a/name-service/js/src/bindings.ts +++ b/name-service/js/src/bindings.ts @@ -1,30 +1,19 @@ -import { - Connection, - PublicKey, - SystemProgram, - TransactionInstruction, -} from '@solana/web3.js'; +import { Connection, PublicKey, SystemProgram, TransactionInstruction } from '@solana/web3.js'; import { - createInstruction, - deleteInstruction, - transferInstruction, - updateInstruction, + createInstruction, + deleteInstruction, + reallocInstruction, + transferInstruction, + updateInstruction, } from './instructions'; import { NameRegistryState } from './state'; import { Numberu64 } from './utils'; -import { - getHashedName, - getNameAccountKey, - getNameOwner, - Numberu32, -} from './utils'; +import { getHashedName, getNameAccountKey, getNameOwner, Numberu32 } from './utils'; //////////////////////////////////////////////////////////// -export const NAME_PROGRAM_ID = new PublicKey( - 'namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX' -); +export const NAME_PROGRAM_ID = new PublicKey('namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX'); export const HASH_PREFIX = 'SPL Name Service'; //////////////////////////////////////////////////////////// @@ -42,47 +31,41 @@ export const HASH_PREFIX = 'SPL Name Service'; * @returns */ export async function createNameRegistry( - connection: Connection, - name: string, - space: number, - payerKey: PublicKey, - nameOwner: PublicKey, - lamports?: number, - nameClass?: PublicKey, - parentName?: PublicKey + connection: Connection, + name: string, + space: number, + payerKey: PublicKey, + nameOwner: PublicKey, + lamports?: number, + nameClass?: PublicKey, + parentName?: PublicKey, ): Promise { - const hashed_name = await getHashedName(name); - const nameAccountKey = await getNameAccountKey( - hashed_name, - nameClass, - parentName - ); - - const balance = lamports - ? lamports - : await connection.getMinimumBalanceForRentExemption(space); - - let nameParentOwner: PublicKey | undefined; - if (parentName) { - const parentAccount = await getNameOwner(connection, parentName); - nameParentOwner = parentAccount.owner; - } - - const createNameInstr = createInstruction( - NAME_PROGRAM_ID, - SystemProgram.programId, - nameAccountKey, - nameOwner, - payerKey, - hashed_name, - new Numberu64(balance), - new Numberu32(space), - nameClass, - parentName, - nameParentOwner - ); - - return createNameInstr; + const hashed_name = await getHashedName(name); + const nameAccountKey = await getNameAccountKey(hashed_name, nameClass, parentName); + + const balance = lamports ? lamports : await connection.getMinimumBalanceForRentExemption(space); + + let nameParentOwner: PublicKey | undefined; + if (parentName) { + const parentAccount = await getNameOwner(connection, parentName); + nameParentOwner = parentAccount.owner; + } + + const createNameInstr = createInstruction( + NAME_PROGRAM_ID, + SystemProgram.programId, + nameAccountKey, + nameOwner, + payerKey, + hashed_name, + new Numberu64(balance), + new Numberu32(space), + nameClass, + parentName, + nameParentOwner, + ); + + return createNameInstr; } /** @@ -96,38 +79,33 @@ export async function createNameRegistry( * @param nameParent The parent name of this name, if it exists */ export async function updateNameRegistryData( - connection: Connection, - name: string, - offset: number, - input_data: Buffer, - nameClass?: PublicKey, - nameParent?: PublicKey + connection: Connection, + name: string, + offset: number, + input_data: Buffer, + nameClass?: PublicKey, + nameParent?: PublicKey, ): Promise { - const hashed_name = await getHashedName(name); - const nameAccountKey = await getNameAccountKey( - hashed_name, - nameClass, - nameParent - ); - - let signer: PublicKey; - if (nameClass) { - signer = nameClass; - } else { - signer = (await NameRegistryState.retrieve(connection, nameAccountKey)) - .owner; - } - - const updateInstr = updateInstruction( - NAME_PROGRAM_ID, - nameAccountKey, - new Numberu32(offset), - input_data, - signer, - nameParent - ); - - return updateInstr; + const hashed_name = await getHashedName(name); + const nameAccountKey = await getNameAccountKey(hashed_name, nameClass, nameParent); + + let signer: PublicKey; + if (nameClass) { + signer = nameClass; + } else { + signer = (await NameRegistryState.retrieve(connection, nameAccountKey)).owner; + } + + const updateInstr = updateInstruction( + NAME_PROGRAM_ID, + nameAccountKey, + new Numberu32(offset), + input_data, + signer, + nameParent, + ); + + return updateInstr; } /** @@ -142,38 +120,32 @@ export async function updateNameRegistryData( * @returns */ export async function transferNameOwnership( - connection: Connection, - name: string, - newOwner: PublicKey, - nameClass?: PublicKey, - nameParent?: PublicKey + connection: Connection, + name: string, + newOwner: PublicKey, + nameClass?: PublicKey, + nameParent?: PublicKey, ): Promise { - const hashed_name = await getHashedName(name); - const nameAccountKey = await getNameAccountKey( - hashed_name, - nameClass, - nameParent - ); - - let curentNameOwner: PublicKey; - if (nameClass) { - curentNameOwner = nameClass; - } else { - curentNameOwner = ( - await NameRegistryState.retrieve(connection, nameAccountKey) - ).owner; - } - - const transferInstr = transferInstruction( - NAME_PROGRAM_ID, - nameAccountKey, - newOwner, - curentNameOwner, - nameClass, - nameParent - ); - - return transferInstr; + const hashed_name = await getHashedName(name); + const nameAccountKey = await getNameAccountKey(hashed_name, nameClass, nameParent); + + let curentNameOwner: PublicKey; + if (nameClass) { + curentNameOwner = nameClass; + } else { + curentNameOwner = (await NameRegistryState.retrieve(connection, nameAccountKey)).owner; + } + + const transferInstr = transferInstruction( + NAME_PROGRAM_ID, + nameAccountKey, + newOwner, + curentNameOwner, + nameClass, + nameParent, + ); + + return transferInstr; } /** @@ -187,33 +159,64 @@ export async function transferNameOwnership( * @returns */ export async function deleteNameRegistry( - connection: Connection, - name: string, - refundTargetKey: PublicKey, - nameClass?: PublicKey, - nameParent?: PublicKey + connection: Connection, + name: string, + refundTargetKey: PublicKey, + nameClass?: PublicKey, + nameParent?: PublicKey, +): Promise { + const hashed_name = await getHashedName(name); + const nameAccountKey = await getNameAccountKey(hashed_name, nameClass, nameParent); + + let nameOwner: PublicKey; + if (nameClass) { + nameOwner = nameClass; + } else { + nameOwner = (await NameRegistryState.retrieve(connection, nameAccountKey)).owner; + } + + const changeAuthoritiesInstr = deleteInstruction(NAME_PROGRAM_ID, nameAccountKey, refundTargetKey, nameOwner); + + return changeAuthoritiesInstr; +} + +/** + * Realloc the name account space. + * + * @param connection The solana connection object to the RPC node + * @param name The name of the name account + * @param space The new space to be allocated + * @param payerKey The allocation cost payer if new space is larger than current or the refund destination if smaller + * @param nameClass The class of this name, if it exsists + * @param nameParent The parent name of this name, if it exists + * @returns + */ +export async function reallocNameAccount( + connection: Connection, + name: string, + space: number, + payerKey: PublicKey, + nameClass?: PublicKey, + nameParent?: PublicKey, ): Promise { - const hashed_name = await getHashedName(name); - const nameAccountKey = await getNameAccountKey( - hashed_name, - nameClass, - nameParent - ); - - let nameOwner: PublicKey; - if (nameClass) { - nameOwner = nameClass; - } else { - nameOwner = (await NameRegistryState.retrieve(connection, nameAccountKey)) - .owner; - } - - const changeAuthoritiesInstr = deleteInstruction( - NAME_PROGRAM_ID, - nameAccountKey, - refundTargetKey, - nameOwner - ); - - return changeAuthoritiesInstr; + const hashedName = await getHashedName(name); + const nameAccountKey = await getNameAccountKey(hashedName, nameClass, nameParent); + + let nameOwner: PublicKey; + if (nameClass) { + nameOwner = nameClass; + } else { + nameOwner = (await NameRegistryState.retrieve(connection, nameAccountKey)).owner; + } + + const reallocInstr = reallocInstruction( + NAME_PROGRAM_ID, + SystemProgram.programId, + payerKey, + nameAccountKey, + nameOwner, + new Numberu32(space), + ); + + return reallocInstr; } diff --git a/name-service/js/src/instructions.ts b/name-service/js/src/instructions.ts index e6b4ed74554..e7e709f5bdf 100644 --- a/name-service/js/src/instructions.ts +++ b/name-service/js/src/instructions.ts @@ -3,214 +3,255 @@ import { PublicKey, TransactionInstruction } from '@solana/web3.js'; import { Numberu32, Numberu64 } from './utils'; export function createInstruction( - nameProgramId: PublicKey, - systemProgramId: PublicKey, - nameKey: PublicKey, - nameOwnerKey: PublicKey, - payerKey: PublicKey, - hashed_name: Buffer, - lamports: Numberu64, - space: Numberu32, - nameClassKey?: PublicKey, - nameParent?: PublicKey, - nameParentOwner?: PublicKey + nameProgramId: PublicKey, + systemProgramId: PublicKey, + nameKey: PublicKey, + nameOwnerKey: PublicKey, + payerKey: PublicKey, + hashed_name: Buffer, + lamports: Numberu64, + space: Numberu32, + nameClassKey?: PublicKey, + nameParent?: PublicKey, + nameParentOwner?: PublicKey, ): TransactionInstruction { - const buffers = [ - Buffer.from(Int8Array.from([0])), - new Numberu32(hashed_name.length).toBuffer(), - hashed_name, - lamports.toBuffer(), - space.toBuffer(), - ]; - - const data = Buffer.concat(buffers); - - const keys = [ - { - pubkey: systemProgramId, - isSigner: false, - isWritable: false, - }, - { - pubkey: payerKey, - isSigner: true, - isWritable: true, - }, - { - pubkey: nameKey, - isSigner: false, - isWritable: true, - }, - { - pubkey: nameOwnerKey, - isSigner: false, - isWritable: false, - }, - ]; - - if (nameClassKey) { - keys.push({ - pubkey: nameClassKey, - isSigner: true, - isWritable: false, - }); - } else { - keys.push({ - pubkey: new PublicKey(Buffer.alloc(32)), - isSigner: false, - isWritable: false, - }); - } - if (nameParent) { - keys.push({ - pubkey: nameParent, - isSigner: false, - isWritable: false, - }); - } else { - keys.push({ - pubkey: new PublicKey(Buffer.alloc(32)), - isSigner: false, - isWritable: false, - }); - } - if (nameParentOwner) { - keys.push({ - pubkey: nameParentOwner, - isSigner: true, - isWritable: false, - }); - } + const buffers = [ + Buffer.from(Uint8Array.from([0])), + new Numberu32(hashed_name.length).toBuffer(), + hashed_name, + lamports.toBuffer(), + space.toBuffer(), + ]; + + const data = Buffer.concat(buffers); + + const keys = [ + { + pubkey: systemProgramId, + isSigner: false, + isWritable: false, + }, + { + pubkey: payerKey, + isSigner: true, + isWritable: true, + }, + { + pubkey: nameKey, + isSigner: false, + isWritable: true, + }, + { + pubkey: nameOwnerKey, + isSigner: false, + isWritable: false, + }, + ]; - return new TransactionInstruction({ - keys, - programId: nameProgramId, - data, - }); + if (nameClassKey) { + keys.push({ + pubkey: nameClassKey, + isSigner: true, + isWritable: false, + }); + } else { + keys.push({ + pubkey: new PublicKey(Buffer.alloc(32)), + isSigner: false, + isWritable: false, + }); + } + if (nameParent) { + keys.push({ + pubkey: nameParent, + isSigner: false, + isWritable: false, + }); + } else { + keys.push({ + pubkey: new PublicKey(Buffer.alloc(32)), + isSigner: false, + isWritable: false, + }); + } + if (nameParentOwner) { + keys.push({ + pubkey: nameParentOwner, + isSigner: true, + isWritable: false, + }); + } + + return new TransactionInstruction({ + keys, + programId: nameProgramId, + data, + }); } export function updateInstruction( - nameProgramId: PublicKey, - nameAccountKey: PublicKey, - offset: Numberu32, - input_data: Buffer, - nameUpdateSigner: PublicKey, - parentNameKey: PublicKey | undefined + nameProgramId: PublicKey, + nameAccountKey: PublicKey, + offset: Numberu32, + input_data: Buffer, + nameUpdateSigner: PublicKey, + parentNameKey: PublicKey | undefined, ): TransactionInstruction { - const buffers = [ - Buffer.from(Int8Array.from([1])), - offset.toBuffer(), - new Numberu32(input_data.length).toBuffer(), - input_data, - ]; - - const data = Buffer.concat(buffers); - const keys = [ - { - pubkey: nameAccountKey, - isSigner: false, - isWritable: true, - }, - { - pubkey: nameUpdateSigner, - isSigner: true, - isWritable: false, - }, - ]; - - if (parentNameKey) { - keys.push({ - pubkey: parentNameKey, - isSigner: false, - isWritable: false, - }); - } + const buffers = [ + Buffer.from(Uint8Array.from([1])), + offset.toBuffer(), + new Numberu32(input_data.length).toBuffer(), + input_data, + ]; + + const data = Buffer.concat(buffers); + const keys = [ + { + pubkey: nameAccountKey, + isSigner: false, + isWritable: true, + }, + { + pubkey: nameUpdateSigner, + isSigner: true, + isWritable: false, + }, + ]; - return new TransactionInstruction({ - keys, - programId: nameProgramId, - data, - }); + if (parentNameKey) { + keys.push({ + pubkey: parentNameKey, + isSigner: false, + isWritable: false, + }); + } + + return new TransactionInstruction({ + keys, + programId: nameProgramId, + data, + }); } export function transferInstruction( - nameProgramId: PublicKey, - nameAccountKey: PublicKey, - newOwnerKey: PublicKey, - currentNameOwnerKey: PublicKey, - nameClassKey?: PublicKey, - nameParent?: PublicKey + nameProgramId: PublicKey, + nameAccountKey: PublicKey, + newOwnerKey: PublicKey, + currentNameOwnerKey: PublicKey, + nameClassKey?: PublicKey, + nameParent?: PublicKey, ): TransactionInstruction { - const buffers = [Buffer.from(Int8Array.from([2])), newOwnerKey.toBuffer()]; - - const data = Buffer.concat(buffers); - - const keys = [ - { - pubkey: nameAccountKey, - isSigner: false, - isWritable: true, - }, - { - pubkey: currentNameOwnerKey, - isSigner: true, - isWritable: false, - }, - ]; - - if (nameClassKey) { - keys.push({ - pubkey: nameClassKey, - isSigner: true, - isWritable: false, - }); - } + const buffers = [Buffer.from(Uint8Array.from([2])), newOwnerKey.toBuffer()]; - if (nameParent) { - keys.push({ - pubkey: nameParent, - isSigner: false, - isWritable: false, - }); - } + const data = Buffer.concat(buffers); + + const keys = [ + { + pubkey: nameAccountKey, + isSigner: false, + isWritable: true, + }, + { + pubkey: currentNameOwnerKey, + isSigner: true, + isWritable: false, + }, + ]; + + if (nameClassKey) { + keys.push({ + pubkey: nameClassKey, + isSigner: true, + isWritable: false, + }); + } + + if (nameParent) { + keys.push({ + pubkey: nameParent, + isSigner: false, + isWritable: false, + }); + } - return new TransactionInstruction({ - keys, - programId: nameProgramId, - data, - }); + return new TransactionInstruction({ + keys, + programId: nameProgramId, + data, + }); } export function deleteInstruction( - nameProgramId: PublicKey, - nameAccountKey: PublicKey, - refundTargetKey: PublicKey, - nameOwnerKey: PublicKey + nameProgramId: PublicKey, + nameAccountKey: PublicKey, + refundTargetKey: PublicKey, + nameOwnerKey: PublicKey, +): TransactionInstruction { + const buffers = [Buffer.from(Uint8Array.from([3]))]; + + const data = Buffer.concat(buffers); + const keys = [ + { + pubkey: nameAccountKey, + isSigner: false, + isWritable: true, + }, + { + pubkey: nameOwnerKey, + isSigner: true, + isWritable: false, + }, + { + pubkey: refundTargetKey, + isSigner: false, + isWritable: true, + }, + ]; + + return new TransactionInstruction({ + keys, + programId: nameProgramId, + data, + }); +} + +export function reallocInstruction( + nameProgramId: PublicKey, + systemProgramId: PublicKey, + payerKey: PublicKey, + nameAccountKey: PublicKey, + nameOwnerKey: PublicKey, + space: Numberu32, ): TransactionInstruction { - const buffers = [Buffer.from(Int8Array.from([3]))]; - - const data = Buffer.concat(buffers); - const keys = [ - { - pubkey: nameAccountKey, - isSigner: false, - isWritable: true, - }, - { - pubkey: nameOwnerKey, - isSigner: true, - isWritable: false, - }, - { - pubkey: refundTargetKey, - isSigner: false, - isWritable: true, - }, - ]; - - return new TransactionInstruction({ - keys, - programId: nameProgramId, - data, - }); + const buffers = [Buffer.from(Uint8Array.from([4])), space.toBuffer()]; + + const data = Buffer.concat(buffers); + const keys = [ + { + pubkey: systemProgramId, + isSigner: false, + isWritable: false, + }, + { + pubkey: payerKey, + isSigner: true, + isWritable: true, + }, + { + pubkey: nameAccountKey, + isSigner: false, + isWritable: true, + }, + { + pubkey: nameOwnerKey, + isSigner: true, + isWritable: false, + }, + ]; + + return new TransactionInstruction({ + keys, + programId: nameProgramId, + data, + }); } diff --git a/name-service/js/src/state.ts b/name-service/js/src/state.ts index 5b56bebc4c4..e7b6c306508 100644 --- a/name-service/js/src/state.ts +++ b/name-service/js/src/state.ts @@ -1,56 +1,43 @@ import { Connection, PublicKey } from '@solana/web3.js'; -import { deserializeUnchecked, Schema } from 'borsh'; +import { deserialize, Schema } from 'borsh'; -export class NameRegistryState { - static HEADER_LEN = 96; - parentName: PublicKey; - owner: PublicKey; - class: PublicKey; - data: Buffer | undefined; - - static schema: Schema = new Map([ - [ - NameRegistryState, - { - kind: 'struct', - fields: [ - ['parentName', [32]], - ['owner', [32]], - ['class', [32]], - ], - }, - ], - ]); - constructor(obj: { +type InitArgs = { parentName: Uint8Array; owner: Uint8Array; class: Uint8Array; - }) { - this.parentName = new PublicKey(obj.parentName); - this.owner = new PublicKey(obj.owner); - this.class = new PublicKey(obj.class); - } +}; + +export class NameRegistryState { + static HEADER_LEN = 96; + parentName: PublicKey; + owner: PublicKey; + class: PublicKey; + data: Buffer | undefined; - public static async retrieve( - connection: Connection, - nameAccountKey: PublicKey - ): Promise { - const nameAccount = await connection.getAccountInfo( - nameAccountKey, - 'processed' - ); - if (!nameAccount) { - throw new Error('Invalid name account provided'); + static schema: Schema = { + struct: { + parentName: { array: { type: 'u8', len: 32 } }, + owner: { array: { type: 'u8', len: 32 } }, + class: { array: { type: 'u8', len: 32 } }, + }, + }; + constructor(obj: InitArgs) { + this.parentName = new PublicKey(obj.parentName); + this.owner = new PublicKey(obj.owner); + this.class = new PublicKey(obj.class); } - const res: NameRegistryState = deserializeUnchecked( - this.schema, - NameRegistryState, - nameAccount.data - ); + public static async retrieve(connection: Connection, nameAccountKey: PublicKey): Promise { + const nameAccount = await connection.getAccountInfo(nameAccountKey, 'processed'); + if (!nameAccount) { + throw new Error('Invalid name account provided'); + } + + const deserialized = deserialize(this.schema, nameAccount.data) as InitArgs; + const res = new NameRegistryState(deserialized); - res.data = nameAccount.data?.slice(this.HEADER_LEN); + res.data = nameAccount.data?.slice(this.HEADER_LEN); - return res; - } + return res; + } } diff --git a/name-service/js/src/twitter.ts b/name-service/js/src/twitter.ts index d33b9666f98..05f3a212a23 100644 --- a/name-service/js/src/twitter.ts +++ b/name-service/js/src/twitter.ts @@ -1,441 +1,362 @@ -import { - Connection, - PublicKey, - SystemProgram, - TransactionInstruction, -} from '@solana/web3.js'; -import { deserialize, deserializeUnchecked, Schema, serialize } from 'borsh'; +import { Connection, PublicKey, SystemProgram, TransactionInstruction } from '@solana/web3.js'; +import { deserialize, Schema, serialize } from 'borsh'; import { deleteNameRegistry, NAME_PROGRAM_ID } from './bindings'; -import { - createInstruction, - deleteInstruction, - transferInstruction, - updateInstruction, -} from './instructions'; +import { createInstruction, deleteInstruction, transferInstruction, updateInstruction } from './instructions'; import { NameRegistryState } from './state'; -import { - getFilteredProgramAccounts, - getHashedName, - getNameAccountKey, - Numberu32, - Numberu64, -} from './utils'; +import { getFilteredProgramAccounts, getHashedName, getNameAccountKey, Numberu32, Numberu64 } from './utils'; //////////////////////////////////////////////////// // Global Variables -export const TWITTER_VERIFICATION_AUTHORITY = new PublicKey( - 'FvPH7PrVrLGKPfqaf3xJodFTjZriqrAXXLTVWEorTFBi' -); +export const TWITTER_VERIFICATION_AUTHORITY = new PublicKey('FvPH7PrVrLGKPfqaf3xJodFTjZriqrAXXLTVWEorTFBi'); // The address of the name registry that will be a parent to all twitter handle registries, // it should be owned by the TWITTER_VERIFICATION_AUTHORITY and its name is irrelevant -export const TWITTER_ROOT_PARENT_REGISTRY_KEY = new PublicKey( - '4YcexoW3r78zz16J2aqmukBLRwGq6rAvWzJpkYAXqebv' -); +export const TWITTER_ROOT_PARENT_REGISTRY_KEY = new PublicKey('4YcexoW3r78zz16J2aqmukBLRwGq6rAvWzJpkYAXqebv'); //////////////////////////////////////////////////// // Bindings // Signed by the authority, the payer and the verified pubkey export async function createVerifiedTwitterRegistry( - connection: Connection, - twitterHandle: string, - verifiedPubkey: PublicKey, - space: number, // The space that the user will have to write data into the verified registry - payerKey: PublicKey + connection: Connection, + twitterHandle: string, + verifiedPubkey: PublicKey, + space: number, // The space that the user will have to write data into the verified registry + payerKey: PublicKey, ): Promise { - // Create user facing registry - const hashedTwitterHandle = await getHashedName(twitterHandle); - const twitterHandleRegistryKey = await getNameAccountKey( - hashedTwitterHandle, - undefined, - TWITTER_ROOT_PARENT_REGISTRY_KEY - ); - - let instructions = [ - createInstruction( - NAME_PROGRAM_ID, - SystemProgram.programId, - twitterHandleRegistryKey, - verifiedPubkey, - payerKey, - hashedTwitterHandle, - new Numberu64(await connection.getMinimumBalanceForRentExemption(space)), - new Numberu32(space), - undefined, - TWITTER_ROOT_PARENT_REGISTRY_KEY, - TWITTER_VERIFICATION_AUTHORITY // Twitter authority acts as owner of the parent for all user-facing registries - ), - ]; - - instructions = instructions.concat( - await createReverseTwitterRegistry( - connection, - twitterHandle, - twitterHandleRegistryKey, - verifiedPubkey, - payerKey - ) - ); - - return instructions; + // Create user facing registry + const hashedTwitterHandle = await getHashedName(twitterHandle); + const twitterHandleRegistryKey = await getNameAccountKey( + hashedTwitterHandle, + undefined, + TWITTER_ROOT_PARENT_REGISTRY_KEY, + ); + + let instructions = [ + createInstruction( + NAME_PROGRAM_ID, + SystemProgram.programId, + twitterHandleRegistryKey, + verifiedPubkey, + payerKey, + hashedTwitterHandle, + new Numberu64(await connection.getMinimumBalanceForRentExemption(space)), + new Numberu32(space), + undefined, + TWITTER_ROOT_PARENT_REGISTRY_KEY, + TWITTER_VERIFICATION_AUTHORITY, // Twitter authority acts as owner of the parent for all user-facing registries + ), + ]; + + instructions = instructions.concat( + await createReverseTwitterRegistry( + connection, + twitterHandle, + twitterHandleRegistryKey, + verifiedPubkey, + payerKey, + ), + ); + + return instructions; } // Overwrite the data that is written in the user facing registry // Signed by the verified pubkey export async function changeTwitterRegistryData( - twitterHandle: string, - verifiedPubkey: PublicKey, - offset: number, // The offset at which to write the input data into the NameRegistryData - input_data: Buffer + twitterHandle: string, + verifiedPubkey: PublicKey, + offset: number, // The offset at which to write the input data into the NameRegistryData + input_data: Buffer, ): Promise { - const hashedTwitterHandle = await getHashedName(twitterHandle); - const twitterHandleRegistryKey = await getNameAccountKey( - hashedTwitterHandle, - undefined, - TWITTER_ROOT_PARENT_REGISTRY_KEY - ); - - const instructions = [ - updateInstruction( - NAME_PROGRAM_ID, - twitterHandleRegistryKey, - new Numberu32(offset), - input_data, - verifiedPubkey, - undefined - ), - ]; - - return instructions; + const hashedTwitterHandle = await getHashedName(twitterHandle); + const twitterHandleRegistryKey = await getNameAccountKey( + hashedTwitterHandle, + undefined, + TWITTER_ROOT_PARENT_REGISTRY_KEY, + ); + + const instructions = [ + updateInstruction( + NAME_PROGRAM_ID, + twitterHandleRegistryKey, + new Numberu32(offset), + input_data, + verifiedPubkey, + undefined, + ), + ]; + + return instructions; } // Change the verified pubkey for a given twitter handle // Signed by the Authority, the verified pubkey and the payer export async function changeVerifiedPubkey( - connection: Connection, - twitterHandle: string, - currentVerifiedPubkey: PublicKey, - newVerifiedPubkey: PublicKey, - payerKey: PublicKey + connection: Connection, + twitterHandle: string, + currentVerifiedPubkey: PublicKey, + newVerifiedPubkey: PublicKey, + payerKey: PublicKey, ): Promise { - const hashedTwitterHandle = await getHashedName(twitterHandle); - const twitterHandleRegistryKey = await getNameAccountKey( - hashedTwitterHandle, - undefined, - TWITTER_ROOT_PARENT_REGISTRY_KEY - ); - - // Transfer the user-facing registry ownership - let instructions = [ - transferInstruction( - NAME_PROGRAM_ID, - twitterHandleRegistryKey, - newVerifiedPubkey, - currentVerifiedPubkey, - undefined - ), - ]; - - // Delete the current reverse registry - instructions.push( - await deleteNameRegistry( - connection, - currentVerifiedPubkey.toString(), - payerKey, - TWITTER_VERIFICATION_AUTHORITY, - TWITTER_ROOT_PARENT_REGISTRY_KEY - ) - ); - - // Create the new reverse registry - instructions = instructions.concat( - await createReverseTwitterRegistry( - connection, - twitterHandle, - twitterHandleRegistryKey, - newVerifiedPubkey, - payerKey - ) - ); - - return instructions; + const hashedTwitterHandle = await getHashedName(twitterHandle); + const twitterHandleRegistryKey = await getNameAccountKey( + hashedTwitterHandle, + undefined, + TWITTER_ROOT_PARENT_REGISTRY_KEY, + ); + + // Transfer the user-facing registry ownership + let instructions = [ + transferInstruction( + NAME_PROGRAM_ID, + twitterHandleRegistryKey, + newVerifiedPubkey, + currentVerifiedPubkey, + undefined, + ), + ]; + + // Delete the current reverse registry + instructions.push( + await deleteNameRegistry( + connection, + currentVerifiedPubkey.toString(), + payerKey, + TWITTER_VERIFICATION_AUTHORITY, + TWITTER_ROOT_PARENT_REGISTRY_KEY, + ), + ); + + // Create the new reverse registry + instructions = instructions.concat( + await createReverseTwitterRegistry( + connection, + twitterHandle, + twitterHandleRegistryKey, + newVerifiedPubkey, + payerKey, + ), + ); + + return instructions; } // Delete the verified registry for a given twitter handle // Signed by the verified pubkey export async function deleteTwitterRegistry( - twitterHandle: string, - verifiedPubkey: PublicKey + twitterHandle: string, + verifiedPubkey: PublicKey, ): Promise { - const hashedTwitterHandle = await getHashedName(twitterHandle); - const twitterHandleRegistryKey = await getNameAccountKey( - hashedTwitterHandle, - undefined, - TWITTER_ROOT_PARENT_REGISTRY_KEY - ); - - const hashedVerifiedPubkey = await getHashedName(verifiedPubkey.toString()); - const reverseRegistryKey = await getNameAccountKey( - hashedVerifiedPubkey, - TWITTER_VERIFICATION_AUTHORITY, - TWITTER_ROOT_PARENT_REGISTRY_KEY - ); - - const instructions = [ - // Delete the user facing registry - deleteInstruction( - NAME_PROGRAM_ID, - twitterHandleRegistryKey, - verifiedPubkey, - verifiedPubkey - ), - // Delete the reverse registry - deleteInstruction( - NAME_PROGRAM_ID, - reverseRegistryKey, - verifiedPubkey, - verifiedPubkey - ), - ]; - - return instructions; + const hashedTwitterHandle = await getHashedName(twitterHandle); + const twitterHandleRegistryKey = await getNameAccountKey( + hashedTwitterHandle, + undefined, + TWITTER_ROOT_PARENT_REGISTRY_KEY, + ); + + const hashedVerifiedPubkey = await getHashedName(verifiedPubkey.toString()); + const reverseRegistryKey = await getNameAccountKey( + hashedVerifiedPubkey, + TWITTER_VERIFICATION_AUTHORITY, + TWITTER_ROOT_PARENT_REGISTRY_KEY, + ); + + const instructions = [ + // Delete the user facing registry + deleteInstruction(NAME_PROGRAM_ID, twitterHandleRegistryKey, verifiedPubkey, verifiedPubkey), + // Delete the reverse registry + deleteInstruction(NAME_PROGRAM_ID, reverseRegistryKey, verifiedPubkey, verifiedPubkey), + ]; + + return instructions; } ////////////////////////////////////////// // Getter Functions // Returns the key of the user-facing registry -export async function getTwitterRegistryKey( - twitter_handle: string -): Promise { - const hashedTwitterHandle = await getHashedName(twitter_handle); - return await getNameAccountKey( - hashedTwitterHandle, - undefined, - TWITTER_ROOT_PARENT_REGISTRY_KEY - ); +export async function getTwitterRegistryKey(twitter_handle: string): Promise { + const hashedTwitterHandle = await getHashedName(twitter_handle); + return await getNameAccountKey(hashedTwitterHandle, undefined, TWITTER_ROOT_PARENT_REGISTRY_KEY); } -export async function getTwitterRegistry( - connection: Connection, - twitter_handle: string -): Promise { - const hashedTwitterHandle = await getHashedName(twitter_handle); - const twitterHandleRegistryKey = await getNameAccountKey( - hashedTwitterHandle, - undefined, - TWITTER_ROOT_PARENT_REGISTRY_KEY - ); - const registry = NameRegistryState.retrieve( - connection, - twitterHandleRegistryKey - ); - return registry; +export async function getTwitterRegistry(connection: Connection, twitter_handle: string): Promise { + const hashedTwitterHandle = await getHashedName(twitter_handle); + const twitterHandleRegistryKey = await getNameAccountKey( + hashedTwitterHandle, + undefined, + TWITTER_ROOT_PARENT_REGISTRY_KEY, + ); + const registry = NameRegistryState.retrieve(connection, twitterHandleRegistryKey); + return registry; } export async function getHandleAndRegistryKey( - connection: Connection, - verifiedPubkey: PublicKey + connection: Connection, + verifiedPubkey: PublicKey, ): Promise<[string, PublicKey]> { - const hashedVerifiedPubkey = await getHashedName(verifiedPubkey.toString()); - const reverseRegistryKey = await getNameAccountKey( - hashedVerifiedPubkey, - TWITTER_VERIFICATION_AUTHORITY, - TWITTER_ROOT_PARENT_REGISTRY_KEY - ); - - const reverseRegistryState = await ReverseTwitterRegistryState.retrieve( - connection, - reverseRegistryKey - ); - return [ - reverseRegistryState.twitterHandle, - new PublicKey(reverseRegistryState.twitterRegistryKey), - ]; + const hashedVerifiedPubkey = await getHashedName(verifiedPubkey.toString()); + const reverseRegistryKey = await getNameAccountKey( + hashedVerifiedPubkey, + TWITTER_VERIFICATION_AUTHORITY, + TWITTER_ROOT_PARENT_REGISTRY_KEY, + ); + + const reverseRegistryState = await ReverseTwitterRegistryState.retrieve(connection, reverseRegistryKey); + return [reverseRegistryState.twitterHandle, new PublicKey(reverseRegistryState.twitterRegistryKey)]; } // Uses the RPC node filtering feature, execution speed may vary export async function getTwitterHandleandRegistryKeyViaFilters( - connection: Connection, - verifiedPubkey: PublicKey + connection: Connection, + verifiedPubkey: PublicKey, ): Promise<[string, PublicKey]> { - const filters = [ - { - memcmp: { - offset: 0, - bytes: TWITTER_ROOT_PARENT_REGISTRY_KEY.toBase58(), - }, - }, - { - memcmp: { - offset: 32, - bytes: verifiedPubkey.toBase58(), - }, - }, - { - memcmp: { - offset: 64, - bytes: TWITTER_VERIFICATION_AUTHORITY.toBase58(), - }, - }, - ]; - - const filteredAccounts = await getFilteredProgramAccounts( - connection, - NAME_PROGRAM_ID, - filters - ); - - for (const f of filteredAccounts) { - if (f.accountInfo.data.length > NameRegistryState.HEADER_LEN + 32) { - const data = f.accountInfo.data.slice(NameRegistryState.HEADER_LEN); - const state: ReverseTwitterRegistryState = deserialize( - ReverseTwitterRegistryState.schema, - ReverseTwitterRegistryState, - data - ); - return [state.twitterHandle, new PublicKey(state.twitterRegistryKey)]; + const filters = [ + { + memcmp: { + offset: 0, + bytes: TWITTER_ROOT_PARENT_REGISTRY_KEY.toBase58(), + }, + }, + { + memcmp: { + offset: 32, + bytes: verifiedPubkey.toBase58(), + }, + }, + { + memcmp: { + offset: 64, + bytes: TWITTER_VERIFICATION_AUTHORITY.toBase58(), + }, + }, + ]; + + const filteredAccounts = await getFilteredProgramAccounts(connection, NAME_PROGRAM_ID, filters); + + for (const f of filteredAccounts) { + if (f.accountInfo.data.length > NameRegistryState.HEADER_LEN + 32) { + const data = f.accountInfo.data.slice(NameRegistryState.HEADER_LEN); + const state = deserialize(ReverseTwitterRegistryState.schema, data) as ReverseTwitterRegistryState; + return [state.twitterHandle, new PublicKey(state.twitterRegistryKey)]; + } } - } - throw new Error('Registry not found.'); + throw new Error('Registry not found.'); } // Uses the RPC node filtering feature, execution speed may vary // Does not give you the handle, but is an alternative to getHandlesAndKeysFromVerifiedPubkey + getTwitterRegistry to get the data -export async function getTwitterRegistryData( - connection: Connection, - verifiedPubkey: PublicKey -): Promise { - const filters = [ - { - memcmp: { - offset: 0, - bytes: TWITTER_ROOT_PARENT_REGISTRY_KEY.toBytes(), - }, - }, - { - memcmp: { - offset: 32, - bytes: verifiedPubkey.toBytes(), - }, - }, - { - memcmp: { - offset: 64, - bytes: new PublicKey(Buffer.alloc(32, 0)).toBase58(), - }, - }, - ]; - - const filteredAccounts = await getFilteredProgramAccounts( - connection, - NAME_PROGRAM_ID, - filters - ); - - if (filteredAccounts.length > 1) { - throw new Error('Found more than one registry.'); - } - - return filteredAccounts[0].accountInfo.data.slice( - NameRegistryState.HEADER_LEN - ); +export async function getTwitterRegistryData(connection: Connection, verifiedPubkey: PublicKey): Promise { + const filters = [ + { + memcmp: { + offset: 0, + bytes: TWITTER_ROOT_PARENT_REGISTRY_KEY.toBase58(), + }, + }, + { + memcmp: { + offset: 32, + bytes: verifiedPubkey.toBase58(), + }, + }, + { + memcmp: { + offset: 64, + bytes: new PublicKey(Buffer.alloc(32, 0)).toBase58(), + }, + }, + ]; + + const filteredAccounts = await getFilteredProgramAccounts(connection, NAME_PROGRAM_ID, filters); + + if (filteredAccounts.length > 1) { + throw new Error('Found more than one registry.'); + } + + return filteredAccounts[0].accountInfo.data.slice(NameRegistryState.HEADER_LEN); } ////////////////////////////////////////////// // Utils export class ReverseTwitterRegistryState { - twitterRegistryKey: Uint8Array; - twitterHandle: string; - - static schema: Schema = new Map([ - [ - ReverseTwitterRegistryState, - { - kind: 'struct', - fields: [ - ['twitterRegistryKey', [32]], - ['twitterHandle', 'string'], - ], - }, - ], - ]); - constructor(obj: { twitterRegistryKey: Uint8Array; twitterHandle: string }) { - this.twitterRegistryKey = obj.twitterRegistryKey; - this.twitterHandle = obj.twitterHandle; - } - - public static async retrieve( - connection: Connection, - reverseTwitterAccountKey: PublicKey - ): Promise { - const reverseTwitterAccount = await connection.getAccountInfo( - reverseTwitterAccountKey, - 'processed' - ); - if (!reverseTwitterAccount) { - throw new Error('Invalid reverse Twitter account provided'); + twitterRegistryKey: Uint8Array; + twitterHandle: string; + + static schema: Schema = { + struct: { + twitterRegistryKey: { array: { type: 'u8', len: 32 } }, + twitterHandle: 'string', + }, + }; + constructor(obj: { twitterRegistryKey: Uint8Array; twitterHandle: string }) { + this.twitterRegistryKey = obj.twitterRegistryKey; + this.twitterHandle = obj.twitterHandle; } - const res: ReverseTwitterRegistryState = deserializeUnchecked( - this.schema, - ReverseTwitterRegistryState, - reverseTwitterAccount.data.slice(NameRegistryState.HEADER_LEN) - ); - - return res; - } + public static async retrieve( + connection: Connection, + reverseTwitterAccountKey: PublicKey, + ): Promise { + const reverseTwitterAccount = await connection.getAccountInfo(reverseTwitterAccountKey, 'processed'); + if (!reverseTwitterAccount) { + throw new Error('Invalid reverse Twitter account provided'); + } + + const res = deserialize( + this.schema, + reverseTwitterAccount.data.slice(NameRegistryState.HEADER_LEN), + ) as ReverseTwitterRegistryState; + + return res; + } } export async function createReverseTwitterRegistry( - connection: Connection, - twitterHandle: string, - twitterRegistryKey: PublicKey, - verifiedPubkey: PublicKey, - payerKey: PublicKey + connection: Connection, + twitterHandle: string, + twitterRegistryKey: PublicKey, + verifiedPubkey: PublicKey, + payerKey: PublicKey, ): Promise { - // Create the reverse lookup registry - const hashedVerifiedPubkey = await getHashedName(verifiedPubkey.toString()); - const reverseRegistryKey = await getNameAccountKey( - hashedVerifiedPubkey, - TWITTER_VERIFICATION_AUTHORITY, - TWITTER_ROOT_PARENT_REGISTRY_KEY - ); - const reverseTwitterRegistryStateBuff = serialize( - ReverseTwitterRegistryState.schema, - new ReverseTwitterRegistryState({ - twitterRegistryKey: twitterRegistryKey.toBytes(), - twitterHandle, - }) - ); - return [ - createInstruction( - NAME_PROGRAM_ID, - SystemProgram.programId, - reverseRegistryKey, - verifiedPubkey, - payerKey, - hashedVerifiedPubkey, - new Numberu64( - await connection.getMinimumBalanceForRentExemption( - reverseTwitterRegistryStateBuff.length - ) - ), - new Numberu32(reverseTwitterRegistryStateBuff.length), - TWITTER_VERIFICATION_AUTHORITY, // Twitter authority acts as class for all reverse-lookup registries - TWITTER_ROOT_PARENT_REGISTRY_KEY, // Reverse registries are also children of the root - TWITTER_VERIFICATION_AUTHORITY - ), - updateInstruction( - NAME_PROGRAM_ID, - reverseRegistryKey, - new Numberu32(0), - Buffer.from(reverseTwitterRegistryStateBuff), - TWITTER_VERIFICATION_AUTHORITY, - undefined - ), - ]; + // Create the reverse lookup registry + const hashedVerifiedPubkey = await getHashedName(verifiedPubkey.toString()); + const reverseRegistryKey = await getNameAccountKey( + hashedVerifiedPubkey, + TWITTER_VERIFICATION_AUTHORITY, + TWITTER_ROOT_PARENT_REGISTRY_KEY, + ); + const reverseTwitterRegistryStateBuff = serialize( + ReverseTwitterRegistryState.schema, + new ReverseTwitterRegistryState({ + twitterRegistryKey: twitterRegistryKey.toBytes(), + twitterHandle, + }), + ); + return [ + createInstruction( + NAME_PROGRAM_ID, + SystemProgram.programId, + reverseRegistryKey, + verifiedPubkey, + payerKey, + hashedVerifiedPubkey, + new Numberu64(await connection.getMinimumBalanceForRentExemption(reverseTwitterRegistryStateBuff.length)), + new Numberu32(reverseTwitterRegistryStateBuff.length), + TWITTER_VERIFICATION_AUTHORITY, // Twitter authority acts as class for all reverse-lookup registries + TWITTER_ROOT_PARENT_REGISTRY_KEY, // Reverse registries are also children of the root + TWITTER_VERIFICATION_AUTHORITY, + ), + updateInstruction( + NAME_PROGRAM_ID, + reverseRegistryKey, + new Numberu32(0), + Buffer.from(reverseTwitterRegistryStateBuff), + TWITTER_VERIFICATION_AUTHORITY, + undefined, + ), + ]; } diff --git a/name-service/js/src/utils.ts b/name-service/js/src/utils.ts index 99e7ad179da..29f0779662e 100644 --- a/name-service/js/src/utils.ts +++ b/name-service/js/src/utils.ts @@ -2,12 +2,13 @@ import assert from 'assert'; import { createHash } from 'crypto'; import { - AccountInfo, - Connection, - Keypair, - PublicKey, - Transaction, - TransactionInstruction, + AccountInfo, + Connection, + GetProgramAccountsFilter, + Keypair, + PublicKey, + Transaction, + TransactionInstruction, } from '@solana/web3.js'; import BN from 'bn.js'; @@ -15,143 +16,134 @@ import { HASH_PREFIX, NAME_PROGRAM_ID } from './bindings'; import { NameRegistryState } from './state'; export class Numberu32 extends BN { - /** - * Convert to Buffer representation - */ - toBuffer(): Buffer { - const a = super.toArray().reverse(); - const b = Buffer.from(a); - if (b.length === 4) { - return b; - } - assert(b.length < 4, 'Numberu32 too large'); + /** + * Convert to Buffer representation + */ + toBuffer(): Buffer { + const a = super.toArray().reverse(); + const b = Buffer.from(a); + if (b.length === 4) { + return b; + } + assert(b.length < 4, 'Numberu32 too large'); - const zeroPad = Buffer.alloc(4); - b.copy(zeroPad); - return zeroPad; - } + const zeroPad = Buffer.alloc(4); + b.copy(zeroPad); + return zeroPad; + } - /** - * Construct a Numberu64 from Buffer representation - */ - static fromBuffer(buffer): BN { - assert(buffer.length === 4, `Invalid buffer length: ${buffer.length}`); - return new BN( - [...buffer] - .reverse() - .map((i) => `00${i.toString(16)}`.slice(-2)) - .join(''), - 16 - ); - } + /** + * Construct a Numberu64 from Buffer representation + */ + static fromBuffer(buffer: Buffer): BN { + assert(buffer.length === 4, `Invalid buffer length: ${buffer.length}`); + return new BN( + [...buffer] + .reverse() + .map(i => `00${i.toString(16)}`.slice(-2)) + .join(''), + 16, + ); + } } export class Numberu64 extends BN { - /** - * Convert to Buffer representation - */ - toBuffer(): Buffer { - const a = super.toArray().reverse(); - const b = Buffer.from(a); - if (b.length === 8) { - return b; - } - assert(b.length < 8, 'Numberu64 too large'); + /** + * Convert to Buffer representation + */ + toBuffer(): Buffer { + const a = super.toArray().reverse(); + const b = Buffer.from(a); + if (b.length === 8) { + return b; + } + assert(b.length < 8, 'Numberu64 too large'); - const zeroPad = Buffer.alloc(8); - b.copy(zeroPad); - return zeroPad; - } + const zeroPad = Buffer.alloc(8); + b.copy(zeroPad); + return zeroPad; + } - /** - * Construct a Numberu64 from Buffer representation - */ - static fromBuffer(buffer): BN { - assert(buffer.length === 8, `Invalid buffer length: ${buffer.length}`); - return new BN( - [...buffer] - .reverse() - .map((i) => `00${i.toString(16)}`.slice(-2)) - .join(''), - 16 - ); - } + /** + * Construct a Numberu64 from Buffer representation + */ + static fromBuffer(buffer: Buffer): BN { + assert(buffer.length === 8, `Invalid buffer length: ${buffer.length}`); + return new BN( + [...buffer] + .reverse() + .map(i => `00${i.toString(16)}`.slice(-2)) + .join(''), + 16, + ); + } } export const signAndSendTransactionInstructions = async ( - // sign and send transaction - connection: Connection, - signers: Array, - feePayer: Keypair, - txInstructions: Array + // sign and send transaction + connection: Connection, + signers: Array, + feePayer: Keypair, + txInstructions: Array, ): Promise => { - const tx = new Transaction(); - tx.feePayer = feePayer.publicKey; - signers.push(feePayer); - tx.add(...txInstructions); - return await connection.sendTransaction(tx, signers); + const tx = new Transaction(); + tx.feePayer = feePayer.publicKey; + signers.push(feePayer); + tx.add(...txInstructions); + return await connection.sendTransaction(tx, signers); }; export async function getHashedName(name: string): Promise { - const input = HASH_PREFIX + name; - const buffer = createHash('sha256').update(input, 'utf8').digest(); - return buffer; + const input = HASH_PREFIX + name; + const buffer = createHash('sha256').update(input, 'utf8').digest(); + return buffer; } export async function getNameAccountKey( - hashed_name: Buffer, - nameClass?: PublicKey, - nameParent?: PublicKey + hashed_name: Buffer, + nameClass?: PublicKey, + nameParent?: PublicKey, ): Promise { - const seeds = [hashed_name]; - if (nameClass) { - seeds.push(nameClass.toBuffer()); - } else { - seeds.push(Buffer.alloc(32)); - } - if (nameParent) { - seeds.push(nameParent.toBuffer()); - } else { - seeds.push(Buffer.alloc(32)); - } - const [nameAccountKey] = await PublicKey.findProgramAddress( - seeds, - NAME_PROGRAM_ID - ); - return nameAccountKey; + const seeds = [hashed_name]; + if (nameClass) { + seeds.push(nameClass.toBuffer()); + } else { + seeds.push(Buffer.alloc(32)); + } + if (nameParent) { + seeds.push(nameParent.toBuffer()); + } else { + seeds.push(Buffer.alloc(32)); + } + const [nameAccountKey] = await PublicKey.findProgramAddress(seeds, NAME_PROGRAM_ID); + return nameAccountKey; } -export async function getNameOwner( - connection: Connection, - nameAccountKey: PublicKey -): Promise { - const nameAccount = await connection.getAccountInfo(nameAccountKey); - if (!nameAccount) { - throw new Error('Unable to find the given account.'); - } - return NameRegistryState.retrieve(connection, nameAccountKey); +export async function getNameOwner(connection: Connection, nameAccountKey: PublicKey): Promise { + const nameAccount = await connection.getAccountInfo(nameAccountKey); + if (!nameAccount) { + throw new Error('Unable to find the given account.'); + } + return NameRegistryState.retrieve(connection, nameAccountKey); } -//Taken from Serum export async function getFilteredProgramAccounts( - connection: Connection, - programId: PublicKey, - filters + connection: Connection, + programId: PublicKey, + filters: GetProgramAccountsFilter[], ): Promise<{ publicKey: PublicKey; accountInfo: AccountInfo }[]> { - const resp = await connection.getProgramAccounts(programId, { - commitment: connection.commitment, - filters, - encoding: 'base64', - }); - return resp.map( - ({ pubkey, account: { data, executable, owner, lamports } }) => ({ - publicKey: pubkey, - accountInfo: { - data: data, - executable, - owner: owner, - lamports, - }, - }) - ); + const resp = await connection.getProgramAccounts(programId, { + commitment: connection.commitment, + filters, + encoding: 'base64', + }); + return resp.map(({ pubkey, account: { data, executable, owner, lamports } }) => ({ + publicKey: pubkey, + accountInfo: { + data: data, + executable, + owner: owner, + lamports, + }, + })); } diff --git a/name-service/js/test/e2e/index.test.ts b/name-service/js/test/e2e/index.test.ts new file mode 100644 index 00000000000..3f84ff9b109 --- /dev/null +++ b/name-service/js/test/e2e/index.test.ts @@ -0,0 +1,93 @@ +import { + Connection, + Keypair, + LAMPORTS_PER_SOL, + PublicKey, + sendAndConfirmTransaction, + Transaction, +} from '@solana/web3.js'; +import { beforeAll, beforeEach, describe, expect, test } from '@jest/globals'; + +import { + createNameRegistry, + deleteNameRegistry, + getHashedName, + getNameAccountKey, + NameRegistryState, + reallocNameAccount, + transferNameOwnership, + updateNameRegistryData, +} from '../../src'; + +const url = 'http://127.0.0.1:8899'; +const connection = new Connection(url, 'confirmed'); +const payer = Keypair.generate(); +const owner = Keypair.generate(); +const space = 20; +let nameKey: PublicKey; +let name: string; +beforeAll(async () => { + const airdropSignature = await connection.requestAirdrop(payer.publicKey, LAMPORTS_PER_SOL); + await connection.confirmTransaction({ + signature: airdropSignature, + ...(await connection.getLatestBlockhash()), + }); +}); + +beforeEach(async () => { + name = Math.random().toString() + '.sol'; + nameKey = await getNameKey(name); + const lamports = await connection.getMinimumBalanceForRentExemption(space + NameRegistryState.HEADER_LEN); + const inst = await createNameRegistry(connection, name, space, payer.publicKey, owner.publicKey, lamports); + const tx = new Transaction().add(inst); + await sendAndConfirmTransaction(connection, tx, [payer]); +}); + +test('Create Name Registery', async () => { + const nameAccount = await NameRegistryState.retrieve(connection, nameKey); + nameAccount.owner.equals(owner.publicKey); + expect(nameAccount.data?.length).toEqual(space); +}); +test('Update Name Registery', async () => { + const data = Buffer.from('@Dudl'); + const inst = await updateNameRegistryData(connection, name, 0, data); + const tx = new Transaction().add(inst); + await sendAndConfirmTransaction(connection, tx, [payer, owner]); + const nameAccount = await NameRegistryState.retrieve(connection, nameKey); + nameAccount.data?.equals(data); +}); +test('Transfer Name Ownership', async () => { + const newOwner = Keypair.generate(); + const inst = await transferNameOwnership(connection, name, newOwner.publicKey); + const tx = new Transaction().add(inst); + await sendAndConfirmTransaction(connection, tx, [payer, owner]); + const nameAccount = await NameRegistryState.retrieve(connection, nameKey); + nameAccount.owner.equals(newOwner.publicKey); +}); +test('Realloc Name Account to bigger space', async () => { + const inst = await reallocNameAccount(connection, name, space + 10, payer.publicKey); + const tx = new Transaction().add(inst); + await sendAndConfirmTransaction(connection, tx, [payer, owner]); + const nameAccount = await NameRegistryState.retrieve(connection, nameKey); + expect(nameAccount.data?.length).toEqual(space + 10); +}); +test('Realloc Name Account to smaller space', async () => { + const inst = await reallocNameAccount(connection, name, space - 10, payer.publicKey); + const tx = new Transaction().add(inst); + await sendAndConfirmTransaction(connection, tx, [payer, owner]); + const nameAccount = await NameRegistryState.retrieve(connection, nameKey); + expect(nameAccount.data?.length).toEqual(space - 10); +}); +test('Delete Name Registry', async () => { + const inst = await deleteNameRegistry(connection, name, payer.publicKey); + const tx = new Transaction().add(inst); + await sendAndConfirmTransaction(connection, tx, [payer, owner]); + const nameAccount = await connection.getAccountInfo(nameKey); + expect(nameAccount).toBeNull; +}); + +const getNameKey = async (name: string, nameClass?: PublicKey, parentName?: PublicKey) => { + const hashedName = await getHashedName(name); + const nameAccountKey = await getNameAccountKey(hashedName, nameClass, parentName); + return nameAccountKey; +}; diff --git a/name-service/js/test/unit/index.test.ts b/name-service/js/test/unit/index.test.ts new file mode 100644 index 00000000000..87d3d67de03 --- /dev/null +++ b/name-service/js/test/unit/index.test.ts @@ -0,0 +1,120 @@ +import { Keypair, LAMPORTS_PER_SOL, PublicKey, SystemProgram } from '@solana/web3.js'; + +import { + createInstruction, + deleteInstruction, + reallocInstruction, + transferInstruction, + updateInstruction, +} from '../../src'; +import { Numberu32, Numberu64 } from '../../src/utils'; + +import { describe, expect, test } from '@jest/globals'; + +describe('SplNameService Instructions', () => { + const nameServiceAddress = new PublicKey('namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX'); + const nameAccountKey = Keypair.generate().publicKey; + const nameOwnerKey = Keypair.generate().publicKey; + const payerKey = Keypair.generate().publicKey; + const nameClassKey = Keypair.generate().publicKey; + const nameParent = Keypair.generate().publicKey; + const nameParentOwner = Keypair.generate().publicKey; + const name = Buffer.from('hello'); + + test('createInstruction without class and parent name key', () => { + const instruction = createInstruction( + nameServiceAddress, + SystemProgram.programId, + nameAccountKey, + nameOwnerKey, + payerKey, + name, + new Numberu64(LAMPORTS_PER_SOL), + new Numberu64(10), + ); + + expect(instruction.keys).toHaveLength(6); + instruction.keys[0].pubkey.equals(SystemProgram.programId); + instruction.keys[1].pubkey.equals(payerKey); + instruction.keys[2].pubkey.equals(nameAccountKey); + instruction.keys[3].pubkey.equals(nameOwnerKey); + instruction.keys[4].pubkey.equals(new PublicKey(Buffer.alloc(32))); + instruction.keys[5].pubkey.equals(new PublicKey(Buffer.alloc(32))); + }); + + test('createInstruction with class and parent name key', () => { + const instruction = createInstruction( + nameServiceAddress, + SystemProgram.programId, + nameAccountKey, + nameOwnerKey, + payerKey, + name, + new Numberu64(LAMPORTS_PER_SOL), + new Numberu64(10), + nameClassKey, + nameParent, + nameParentOwner, + ); + + expect(instruction.keys).toHaveLength(7); + instruction.keys[0].pubkey.equals(SystemProgram.programId); + instruction.keys[1].pubkey.equals(payerKey); + instruction.keys[2].pubkey.equals(nameAccountKey); + instruction.keys[3].pubkey.equals(nameOwnerKey); + instruction.keys[4].pubkey.equals(nameClassKey); + instruction.keys[5].pubkey.equals(nameParent); + instruction.keys[6].pubkey.equals(nameParentOwner); + }); + + test('updateInstruction', () => { + const data = Buffer.from('@Dudl'); + const instruction = updateInstruction( + nameServiceAddress, + nameAccountKey, + new Numberu32(0), + data, + nameOwnerKey, + undefined, + ); + + expect(instruction.keys).toHaveLength(2); + instruction.keys[0].pubkey.equals(nameAccountKey); + instruction.keys[1].pubkey.equals(nameOwnerKey); + }); + + test('transferInstruction', () => { + const newOwner = Keypair.generate().publicKey; + const instruction = transferInstruction(nameServiceAddress, nameAccountKey, newOwner, nameOwnerKey); + + expect(instruction.keys).toHaveLength(2); + instruction.keys[0].pubkey.equals(nameAccountKey); + instruction.keys[1].pubkey.equals(nameOwnerKey); + }); + + test('deleteInstruction', () => { + const instruction = deleteInstruction(nameServiceAddress, nameAccountKey, payerKey, nameOwnerKey); + + expect(instruction.keys).toHaveLength(3); + instruction.keys[0].pubkey.equals(nameAccountKey); + instruction.keys[1].pubkey.equals(nameOwnerKey); + instruction.keys[2].pubkey.equals(payerKey); + }); + + test('reallocInstruction', () => { + const instruction = reallocInstruction( + nameServiceAddress, + SystemProgram.programId, + payerKey, + nameAccountKey, + nameOwnerKey, + new Numberu32(30), + ); + + expect(instruction.keys).toHaveLength(4); + instruction.keys[0].pubkey.equals(SystemProgram.programId); + instruction.keys[1].pubkey.equals(payerKey); + instruction.keys[2].pubkey.equals(nameAccountKey); + instruction.keys[3].pubkey.equals(nameOwnerKey); + }); +}); diff --git a/name-service/js/tsconfig.all.json b/name-service/js/tsconfig.all.json new file mode 100644 index 00000000000..917ce153962 --- /dev/null +++ b/name-service/js/tsconfig.all.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.root.json", + "references": [ + { + "path": "./tsconfig.cjs.json" + }, + { + "path": "./tsconfig.esm.json" + } + ] +} diff --git a/name-service/js/tsconfig.base.json b/name-service/js/tsconfig.base.json new file mode 100644 index 00000000000..baeb8a34d98 --- /dev/null +++ b/name-service/js/tsconfig.base.json @@ -0,0 +1,14 @@ +{ + "include": [], + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "Node", + "esModuleInterop": true, + "isolatedModules": true, + "noEmitOnError": true, + "resolveJsonModule": true, + "strict": true, + "stripInternal": true + } +} diff --git a/name-service/js/tsconfig.cjs.json b/name-service/js/tsconfig.cjs.json new file mode 100644 index 00000000000..7e4292fb5e6 --- /dev/null +++ b/name-service/js/tsconfig.cjs.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.base.json", + "include": ["src"], + "compilerOptions": { + "outDir": "lib/cjs", + "target": "ES2016", + "module": "CommonJS", + "sourceMap": true + } +} diff --git a/name-service/js/tsconfig.esm.json b/name-service/js/tsconfig.esm.json new file mode 100644 index 00000000000..a74c93600c5 --- /dev/null +++ b/name-service/js/tsconfig.esm.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.base.json", + "include": ["src"], + "compilerOptions": { + "outDir": "lib/esm", + "declarationDir": "lib/types", + "target": "ES2020", + "module": "ES2020", + "sourceMap": true, + "declaration": true, + "declarationMap": true + } +} diff --git a/name-service/js/tsconfig.json b/name-service/js/tsconfig.json index ebdb8307224..ab064c43dc9 100644 --- a/name-service/js/tsconfig.json +++ b/name-service/js/tsconfig.json @@ -1,32 +1,8 @@ { - "extends": "@tsconfig/recommended/tsconfig.json", - "ts-node": { - "compilerOptions": { - "module": "commonjs", - "baseUrl": "./", - "paths": { - "*" : ["types/*"] - } - } - }, - "compilerOptions": { - "module": "commonjs", - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "target": "es2019", - "outDir": "dist", - "rootDir": "./src", - "declaration": true, - "noImplicitAny": false, - "moduleResolution": "node", - "sourceMap": true, - "baseUrl": ".", - "paths": { - "*": ["node_modules/*", "src/types/*"] - }, - "resolveJsonModule": true - }, - "include": ["src/*"], - "exclude": ["src/**/*.test.ts", "**/node_modules", "dist"] + "extends": "./tsconfig.all.json", + "include": ["src", "test"], + "compilerOptions": { + "noEmit": true, + "skipLibCheck": true } - \ No newline at end of file +} diff --git a/name-service/js/tsconfig.root.json b/name-service/js/tsconfig.root.json new file mode 100644 index 00000000000..fdffcb60b1e --- /dev/null +++ b/name-service/js/tsconfig.root.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.base.json", + "compilerOptions": { + "composite": true + } +} diff --git a/name-service/js/yarn.lock b/name-service/js/yarn.lock deleted file mode 100644 index 32e0391ec84..00000000000 --- a/name-service/js/yarn.lock +++ /dev/null @@ -1,2212 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/code-frame@7.12.11": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" - integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== - dependencies: - "@babel/highlight" "^7.10.4" - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" - integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== - dependencies: - "@babel/highlight" "^7.16.7" - -"@babel/generator@^7.17.9": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.9.tgz#f4af9fd38fa8de143c29fce3f71852406fc1e2fc" - integrity sha512-rAdDousTwxbIxbz5I7GEQ3lUip+xVCXooZNbsydCWs3xA7ZsYOv+CFRdzGxRX78BmQHu9B1Eso59AOZQOJDEdQ== - dependencies: - "@babel/types" "^7.17.0" - jsesc "^2.5.1" - source-map "^0.5.0" - -"@babel/helper-environment-visitor@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" - integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-function-name@^7.17.9": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz#136fcd54bc1da82fcb47565cf16fd8e444b1ff12" - integrity sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg== - dependencies: - "@babel/template" "^7.16.7" - "@babel/types" "^7.17.0" - -"@babel/helper-hoist-variables@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" - integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-split-export-declaration@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" - integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-validator-identifier@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" - integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== - -"@babel/highlight@^7.10.4", "@babel/highlight@^7.16.7": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.17.9.tgz#61b2ee7f32ea0454612def4fccdae0de232b73e3" - integrity sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg== - dependencies: - "@babel/helper-validator-identifier" "^7.16.7" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/parser@^7.16.7", "@babel/parser@^7.17.9", "@babel/parser@^7.7.0": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.9.tgz#9c94189a6062f0291418ca021077983058e171ef" - integrity sha512-vqUSBLP8dQHFPdPi9bc5GK9vRkYHJ49fsZdtoJ8EQ8ibpwk5rPKfvNIwChB0KVXcIjcepEBBd2VHC5r9Gy8ueg== - -"@babel/runtime@^7.10.5", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72" - integrity sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/template@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" - integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== - dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/parser" "^7.16.7" - "@babel/types" "^7.16.7" - -"@babel/traverse@^7.7.0": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.9.tgz#1f9b207435d9ae4a8ed6998b2b82300d83c37a0d" - integrity sha512-PQO8sDIJ8SIwipTPiR71kJQCKQYB5NGImbOviK8K+kg5xkNSYXLBupuX9QhatFowrsvo9Hj8WgArg3W7ijNAQw== - dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.9" - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-function-name" "^7.17.9" - "@babel/helper-hoist-variables" "^7.16.7" - "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/parser" "^7.17.9" - "@babel/types" "^7.17.0" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/types@^7.16.7", "@babel/types@^7.17.0", "@babel/types@^7.7.0": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b" - integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw== - dependencies: - "@babel/helper-validator-identifier" "^7.16.7" - to-fast-properties "^2.0.0" - -"@eslint/eslintrc@^0.4.3": - version "0.4.3" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" - integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== - dependencies: - ajv "^6.12.4" - debug "^4.1.1" - espree "^7.3.0" - globals "^13.9.0" - ignore "^4.0.6" - import-fresh "^3.2.1" - js-yaml "^3.13.1" - minimatch "^3.0.4" - strip-json-comments "^3.1.1" - -"@ethersproject/bytes@^5.6.0": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.6.1.tgz#24f916e411f82a8a60412344bf4a813b917eefe7" - integrity sha512-NwQt7cKn5+ZE4uDn+X5RAXLp46E1chXoaMmrxAyA0rblpxz8t58lVkrHXoRIn0lz1joQElQ8410GqhTqMOwc6g== - dependencies: - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/logger@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.6.0.tgz#d7db1bfcc22fd2e4ab574cba0bb6ad779a9a3e7a" - integrity sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg== - -"@ethersproject/sha2@^5.5.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.6.0.tgz#364c4c11cc753bda36f31f001628706ebadb64d9" - integrity sha512-1tNWCPFLu1n3JM9t4/kytz35DkuF9MxqkGGEHNauEbaARdm2fafnOyw1s0tIQDPKF/7bkP1u3dbrmjpn5CelyA== - dependencies: - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - hash.js "1.1.7" - -"@humanwhocodes/config-array@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" - integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== - dependencies: - "@humanwhocodes/object-schema" "^1.2.0" - debug "^4.1.1" - minimatch "^3.0.4" - -"@humanwhocodes/object-schema@^1.2.0": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== - -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - -"@nodelib/fs.walk@^1.2.3": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - -"@solana/buffer-layout@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-4.0.0.tgz#75b1b11adc487234821c81dfae3119b73a5fd734" - integrity sha512-lR0EMP2HC3+Mxwd4YcnZb0smnaDw7Bl2IQWZiTevRH5ZZBZn6VRWn3/92E3qdU4SSImJkA6IDHawOHAnx/qUvQ== - dependencies: - buffer "~6.0.3" - -"@solana/spl-token@0.1.4": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@solana/spl-token/-/spl-token-0.1.4.tgz#7fc6ba82a7fbb2b0907f7ffc87709488db83ed2a" - integrity sha512-W8uSC4ysWVjbKK7lvsIHFxdMIkOCEoOm9tYY9VVpBlUIp4+K5bpPxHXUlxMiHfkKPWAxab6IGUn71VVLg8uq5Q== - dependencies: - "@babel/runtime" "^7.10.5" - "@solana/web3.js" "^1.9.1" - bn.js "^5.1.0" - buffer "6.0.3" - buffer-layout "^1.2.0" - dotenv "8.2.0" - -"@solana/web3.js@^1.11.0", "@solana/web3.js@^1.9.1": - version "1.39.1" - resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.39.1.tgz#858ecd42ff2a5bcba3a4bb642a50194d77e2a578" - integrity sha512-Q7XnWTAiU7n7GcoINDAAMLO7CJHpm5kPK46HKwJi2x0cusHQ3WFa7QEp6aPzH7tuf7yl/Kw1lYitcwTVOvqARA== - dependencies: - "@babel/runtime" "^7.12.5" - "@ethersproject/sha2" "^5.5.0" - "@solana/buffer-layout" "^4.0.0" - bn.js "^5.0.0" - borsh "^0.7.0" - bs58 "^4.0.1" - buffer "6.0.1" - cross-fetch "^3.1.4" - jayson "^3.4.4" - js-sha3 "^0.8.0" - rpc-websockets "^7.4.2" - secp256k1 "^4.0.2" - superstruct "^0.14.2" - tweetnacl "^1.0.0" - -"@tsconfig/recommended@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@tsconfig/recommended/-/recommended-1.0.1.tgz#7619bad397e06ead1c5182926c944e0ca6177f52" - integrity sha512-2xN+iGTbPBEzGSnVp/Hd64vKJCJWxsi9gfs88x4PPMyEjHJoA3o5BY9r5OLPHIZU2pAQxkSAsJFqn6itClP8mQ== - -"@types/bn.js@^4.11.5": - version "4.11.6" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" - integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== - dependencies: - "@types/node" "*" - -"@types/connect@^3.4.33": - version "3.4.35" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" - integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== - dependencies: - "@types/node" "*" - -"@types/express-serve-static-core@^4.17.9": - version "4.17.28" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz#c47def9f34ec81dc6328d0b1b5303d1ec98d86b8" - integrity sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig== - dependencies: - "@types/node" "*" - "@types/qs" "*" - "@types/range-parser" "*" - -"@types/json-schema@^7.0.7": - version "7.0.11" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" - integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== - -"@types/json5@^0.0.29": - version "0.0.29" - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" - integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= - -"@types/lodash@^4.14.159": - version "4.14.182" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.182.tgz#05301a4d5e62963227eaafe0ce04dd77c54ea5c2" - integrity sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q== - -"@types/node@*": - version "17.0.25" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.25.tgz#527051f3c2f77aa52e5dc74e45a3da5fb2301448" - integrity sha512-wANk6fBrUwdpY4isjWrKTufkrXdu1D2YHCot2fD/DfWxF5sMrVSA+KN7ydckvaTCh0HiqX9IVl0L5/ZoXg5M7w== - -"@types/node@^12.12.54": - version "12.20.48" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.48.tgz#55f70bd432b6515828c0298689776861b90ca4fa" - integrity sha512-4kxzqkrpwYtn6okJUcb2lfUu9ilnb3yhUOH6qX3nug8D2DupZ2drIkff2yJzYcNJVl3begnlcaBJ7tqiTTzjnQ== - -"@types/node@^14.14.20": - version "14.18.13" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.13.tgz#6ad4d9db59e6b3faf98dcfe4ca9d2aec84443277" - integrity sha512-Z6/KzgyWOga3pJNS42A+zayjhPbf2zM3hegRQaOPnLOzEi86VV++6FLDWgR1LGrVCRufP/ph2daa3tEa5br1zA== - -"@types/qs@*": - version "6.9.7" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" - integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== - -"@types/range-parser@*": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" - integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== - -"@types/ws@^7.4.4": - version "7.4.7" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" - integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== - dependencies: - "@types/node" "*" - -"@typescript-eslint/eslint-plugin@^4.0.1": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" - integrity sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg== - dependencies: - "@typescript-eslint/experimental-utils" "4.33.0" - "@typescript-eslint/scope-manager" "4.33.0" - debug "^4.3.1" - functional-red-black-tree "^1.0.1" - ignore "^5.1.8" - regexpp "^3.1.0" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/experimental-utils@4.33.0", "@typescript-eslint/experimental-utils@^4.9.1": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd" - integrity sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q== - dependencies: - "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.33.0" - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/typescript-estree" "4.33.0" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - -"@typescript-eslint/parser@^4.0.1": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899" - integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA== - dependencies: - "@typescript-eslint/scope-manager" "4.33.0" - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/typescript-estree" "4.33.0" - debug "^4.3.1" - -"@typescript-eslint/scope-manager@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3" - integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ== - dependencies: - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/visitor-keys" "4.33.0" - -"@typescript-eslint/types@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" - integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== - -"@typescript-eslint/typescript-estree@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" - integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA== - dependencies: - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/visitor-keys" "4.33.0" - debug "^4.3.1" - globby "^11.0.3" - is-glob "^4.0.1" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/visitor-keys@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" - integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg== - dependencies: - "@typescript-eslint/types" "4.33.0" - eslint-visitor-keys "^2.0.0" - -JSONStream@^1.3.5: - version "1.3.5" - resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" - integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== - dependencies: - jsonparse "^1.2.0" - through ">=2.2.7 <3" - -acorn-jsx@^5.3.1: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -acorn@^7.4.0: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - -ajv@^6.10.0, ajv@^6.12.4: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ajv@^8.0.1: - version "8.11.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" - integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - -ansi-colors@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -array-includes@^3.1.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" - integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - get-intrinsic "^1.1.1" - is-string "^1.0.7" - -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -array.prototype.flat@^1.2.5: - version "1.3.0" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz#0b0c1567bf57b38b56b4c97b8aa72ab45e4adc7b" - integrity sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.2" - es-shim-unscopables "^1.0.0" - -array.prototype.flatmap@^1.2.4: - version "1.3.0" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz#a7e8ed4225f4788a70cd910abcf0791e76a5534f" - integrity sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.2" - es-shim-unscopables "^1.0.0" - -astral-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" - integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== - -babel-eslint@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" - integrity sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.7.0" - "@babel/traverse" "^7.7.0" - "@babel/types" "^7.7.0" - eslint-visitor-keys "^1.0.0" - resolve "^1.12.0" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -base-x@^3.0.2: - version "3.0.9" - resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" - integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== - dependencies: - safe-buffer "^5.0.1" - -base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - -bn.js@^5.0.0, bn.js@^5.1.0, bn.js@^5.1.3, bn.js@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" - integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== - -borsh@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.4.0.tgz#9dd6defe741627f1315eac2a73df61421f6ddb9f" - integrity sha512-aX6qtLya3K0AkT66CmYWCCDr77qsE9arV05OmdFpmat9qu8Pg9J5tBUPDztAW5fNh/d/MyVG/OYziP52Ndzx1g== - dependencies: - "@types/bn.js" "^4.11.5" - bn.js "^5.0.0" - bs58 "^4.0.0" - text-encoding-utf-8 "^1.0.2" - -borsh@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.7.0.tgz#6e9560d719d86d90dc589bca60ffc8a6c51fec2a" - integrity sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA== - dependencies: - bn.js "^5.2.0" - bs58 "^4.0.0" - text-encoding-utf-8 "^1.0.2" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== - dependencies: - balanced-match "^1.0.0" - -braces@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -brorand@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= - -bs58@^4.0.0, bs58@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" - integrity sha1-vhYedsNU9veIrkBx9j806MTwpCo= - dependencies: - base-x "^3.0.2" - -buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - -buffer-layout@^1.2.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/buffer-layout/-/buffer-layout-1.2.2.tgz#b9814e7c7235783085f9ca4966a0cfff112259d5" - integrity sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA== - -buffer@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.1.tgz#3cbea8c1463e5a0779e30b66d4c88c6ffa182ac2" - integrity sha512-rVAXBwEcEoYtxnHSO5iWyhzV/O1WMtkUYWlfdLS7FjU4PnSJJHEfHXi/uHPI5EwltmOA794gN3bm3/pzuctWjQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - -buffer@6.0.3, buffer@~6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - -bufferutil@^4.0.1: - version "4.0.6" - resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.6.tgz#ebd6c67c7922a0e902f053e5d8be5ec850e48433" - integrity sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw== - dependencies: - node-gyp-build "^4.3.0" - -call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -chalk@^2.0.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^4.0.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -circular-json@^0.5.9: - version "0.5.9" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.9.tgz#932763ae88f4f7dead7a0d09c8a51a4743a53b1d" - integrity sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ== - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -commander@^2.20.3: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -create-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== - -cross-fetch@^3.1.4: - version "3.1.5" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" - integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== - dependencies: - node-fetch "2.6.7" - -cross-spawn@^7.0.2: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -debug@^2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@^3.2.7: - version "3.2.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - -debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -deep-is@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== - -deepmerge@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" - integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== - -define-properties@^1.1.3: - version "1.1.4" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" - integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== - dependencies: - has-property-descriptors "^1.0.0" - object-keys "^1.1.1" - -delay@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" - integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== - -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -dotenv@8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" - integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== - -elliptic@^6.5.4: - version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -enquirer@^2.3.5: - version "2.3.6" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" - integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== - dependencies: - ansi-colors "^4.1.1" - -es-abstract@^1.19.1, es-abstract@^1.19.2: - version "1.19.5" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.5.tgz#a2cb01eb87f724e815b278b0dd0d00f36ca9a7f1" - integrity sha512-Aa2G2+Rd3b6kxEUKTF4TaW67czBLyAv3z7VOhYRU50YBx+bbsYZ9xQP4lMNazePuFlybXI0V4MruPos7qUo5fA== - dependencies: - call-bind "^1.0.2" - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - get-intrinsic "^1.1.1" - get-symbol-description "^1.0.0" - has "^1.0.3" - has-symbols "^1.0.3" - internal-slot "^1.0.3" - is-callable "^1.2.4" - is-negative-zero "^2.0.2" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" - is-string "^1.0.7" - is-weakref "^1.0.2" - object-inspect "^1.12.0" - object-keys "^1.1.1" - object.assign "^4.1.2" - string.prototype.trimend "^1.0.4" - string.prototype.trimstart "^1.0.4" - unbox-primitive "^1.0.1" - -es-shim-unscopables@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" - integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== - dependencies: - has "^1.0.3" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -es6-promise@^4.0.3: - version "4.2.8" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" - integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== - -es6-promisify@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" - integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= - dependencies: - es6-promise "^4.0.3" - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -eslint-config-prettier@^6.11.0: - version "6.15.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz#7f93f6cb7d45a92f1537a70ecc06366e1ac6fed9" - integrity sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw== - dependencies: - get-stdin "^6.0.0" - -eslint-import-resolver-node@^0.3.6: - version "0.3.6" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" - integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== - dependencies: - debug "^3.2.7" - resolve "^1.20.0" - -eslint-module-utils@^2.7.3: - version "2.7.3" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee" - integrity sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ== - dependencies: - debug "^3.2.7" - find-up "^2.1.0" - -eslint-plugin-eslint-comments@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz#9e1cd7b4413526abb313933071d7aba05ca12ffa" - integrity sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ== - dependencies: - escape-string-regexp "^1.0.5" - ignore "^5.0.5" - -eslint-plugin-functional@^3.0.2: - version "3.7.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-functional/-/eslint-plugin-functional-3.7.2.tgz#c90325dddfa822fab27419375084d12158f05da1" - integrity sha512-BuWPOeE0nuXYlZjObYOHnYf7G3iG+sysxw84I579MsrH+hy5XdXb2sdabmXQ5z7eFGCg2/DWNbZ/yz5GAgtcUg== - dependencies: - "@typescript-eslint/experimental-utils" "^4.9.1" - array.prototype.flatmap "^1.2.4" - deepmerge "^4.2.2" - escape-string-regexp "^4.0.0" - object.fromentries "^2.0.3" - -eslint-plugin-import@^2.22.0: - version "2.26.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz#f812dc47be4f2b72b478a021605a59fc6fe8b88b" - integrity sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA== - dependencies: - array-includes "^3.1.4" - array.prototype.flat "^1.2.5" - debug "^2.6.9" - doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.6" - eslint-module-utils "^2.7.3" - has "^1.0.3" - is-core-module "^2.8.1" - is-glob "^4.0.3" - minimatch "^3.1.2" - object.values "^1.1.5" - resolve "^1.22.0" - tsconfig-paths "^3.14.1" - -eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - -eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - -eslint@^7.8.0: - version "7.32.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" - integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== - dependencies: - "@babel/code-frame" "7.12.11" - "@eslint/eslintrc" "^0.4.3" - "@humanwhocodes/config-array" "^0.5.0" - ajv "^6.10.0" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.0.1" - doctrine "^3.0.0" - enquirer "^2.3.5" - escape-string-regexp "^4.0.0" - eslint-scope "^5.1.1" - eslint-utils "^2.1.0" - eslint-visitor-keys "^2.0.0" - espree "^7.3.1" - esquery "^1.4.0" - esutils "^2.0.2" - fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.1.2" - globals "^13.6.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - js-yaml "^3.13.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash.merge "^4.6.2" - minimatch "^3.0.4" - natural-compare "^1.4.0" - optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" - strip-json-comments "^3.1.0" - table "^6.0.9" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -espree@^7.3.0, espree@^7.3.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" - integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== - dependencies: - acorn "^7.4.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^1.3.0" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -eventemitter3@^4.0.7: - version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" - integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== - -eyes@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" - integrity sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A= - -fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-glob@^3.2.9: - version "3.2.11" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" - integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -fastq@^1.6.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" - integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== - dependencies: - reusify "^1.0.4" - -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== - dependencies: - flat-cache "^3.0.4" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - dependencies: - locate-path "^2.0.0" - -flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== - dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" - -flatted@^3.1.0: - version "3.2.5" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" - integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" - integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - -get-stdin@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" - integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== - -get-symbol-description@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" - integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" - -glob-parent@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob@^7.1.3: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^8.0.3: - version "8.0.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-8.0.3.tgz#415c6eb2deed9e502c68fa44a272e6da6eeca42e" - integrity sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^5.0.1" - once "^1.3.0" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globals@^13.6.0, globals@^13.9.0: - version "13.13.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.13.0.tgz#ac32261060d8070e2719dd6998406e27d2b5727b" - integrity sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A== - dependencies: - type-fest "^0.20.2" - -globby@^11.0.3: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" - -has-bigints@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" - integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-property-descriptors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" - integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== - dependencies: - get-intrinsic "^1.1.1" - -has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== - -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== - dependencies: - has-symbols "^1.0.2" - -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -ieee754@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -ignore@^5.0.5, ignore@^5.1.8, ignore@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" - integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== - -import-fresh@^3.0.0, import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@^2.0.3, inherits@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -internal-slot@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" - integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== - dependencies: - get-intrinsic "^1.1.0" - has "^1.0.3" - side-channel "^1.0.4" - -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== - dependencies: - has-bigints "^1.0.1" - -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-callable@^1.1.4, is-callable@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" - integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== - -is-core-module@^2.8.1: - version "2.9.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69" - integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== - dependencies: - has "^1.0.3" - -is-date-object@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== - dependencies: - has-tostringtag "^1.0.0" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-negative-zero@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== - -is-number-object@^1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" - integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== - dependencies: - has-tostringtag "^1.0.0" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-shared-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" - integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== - dependencies: - call-bind "^1.0.2" - -is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== - dependencies: - has-tostringtag "^1.0.0" - -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== - dependencies: - has-symbols "^1.0.2" - -is-weakref@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" - integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== - dependencies: - call-bind "^1.0.2" - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -isomorphic-ws@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" - integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== - -jayson@^3.4.4: - version "3.6.6" - resolved "https://registry.yarnpkg.com/jayson/-/jayson-3.6.6.tgz#189984f624e398f831bd2be8e8c80eb3abf764a1" - integrity sha512-f71uvrAWTtrwoww6MKcl9phQTC+56AopLyEenWvKVAIMz+q0oVGj6tenLZ7Z6UiPBkJtKLj4kt0tACllFQruGQ== - dependencies: - "@types/connect" "^3.4.33" - "@types/express-serve-static-core" "^4.17.9" - "@types/lodash" "^4.14.159" - "@types/node" "^12.12.54" - "@types/ws" "^7.4.4" - JSONStream "^1.3.5" - commander "^2.20.3" - delay "^5.0.0" - es6-promisify "^5.0.0" - eyes "^0.1.8" - isomorphic-ws "^4.0.1" - json-stringify-safe "^5.0.1" - lodash "^4.17.20" - uuid "^8.3.2" - ws "^7.4.5" - -js-sha3@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" - integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema-traverse@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" - integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - -json-stringify-safe@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - -json5@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== - dependencies: - minimist "^1.2.0" - -jsonc-parser@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.0.0.tgz#abdd785701c7e7eaca8a9ec8cf070ca51a745a22" - integrity sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA== - -jsonparse@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" - integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= - -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - -lodash.truncate@^4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" - integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= - -lodash@^4.17.20: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -lunr@^2.3.9: - version "2.3.9" - resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1" - integrity sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow== - -make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -marked@^4.0.16: - version "4.0.16" - resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.16.tgz#9ec18fc1a723032eb28666100344d9428cf7a264" - integrity sha512-wahonIQ5Jnyatt2fn8KqF/nIqZM8mh3oRu2+l5EANGMhu6RFjiSG52QNE2eWzFMI94HqYSgN184NurgNG6CztA== - -merge2@^1.3.0, merge2@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== - dependencies: - braces "^3.0.2" - picomatch "^2.3.1" - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= - -minimatch@^3.0.4, minimatch@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^5.0.1, minimatch@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.0.tgz#1717b464f4971b144f6aabe8f2d0b8e4511e09c7" - integrity sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg== - dependencies: - brace-expansion "^2.0.1" - -minimist@^1.2.0, minimist@^1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" - integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -node-addon-api@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" - integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== - -node-fetch@2.6.7: - version "2.6.7" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" - integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== - dependencies: - whatwg-url "^5.0.0" - -node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.4.0.tgz#42e99687ce87ddeaf3a10b99dc06abc11021f3f4" - integrity sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ== - -object-inspect@^1.12.0, object-inspect@^1.9.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" - integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== - -object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object.assign@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" - integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - has-symbols "^1.0.1" - object-keys "^1.1.1" - -object.fromentries@^2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.5.tgz#7b37b205109c21e741e605727fe8b0ad5fa08251" - integrity sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - -object.values@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" - integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== - dependencies: - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - word-wrap "^1.2.3" - -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= - dependencies: - p-limit "^1.1.0" - -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -prettier@^2.2.1: - version "2.6.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.2.tgz#e26d71a18a74c3d0f0597f55f01fb6c06c206032" - integrity sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew== - -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - -regenerator-runtime@^0.13.4: - version "0.13.9" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" - integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== - -regexpp@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== - -require-from-string@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve@^1.12.0, resolve@^1.20.0, resolve@^1.22.0: - version "1.22.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" - integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== - dependencies: - is-core-module "^2.8.1" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -rpc-websockets@^7.4.2: - version "7.4.17" - resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.4.17.tgz#f38845dd96db0442bff9e15fba9df781beb44cc0" - integrity sha512-eolVi/qlXS13viIUH9aqrde902wzSLAai0IjmOZSRefp5I3CSG/vCnD0c0fDSYCWuEyUoRL1BHQA8K1baEUyow== - dependencies: - "@babel/runtime" "^7.11.2" - circular-json "^0.5.9" - eventemitter3 "^4.0.7" - uuid "^8.3.0" - ws "^7.4.5" - optionalDependencies: - bufferutil "^4.0.1" - utf-8-validate "^5.0.2" - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -safe-buffer@^5.0.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -secp256k1@^4.0.2: - version "4.0.3" - resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.3.tgz#c4559ecd1b8d3c1827ed2d1b94190d69ce267303" - integrity sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA== - dependencies: - elliptic "^6.5.4" - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" - -semver@^7.2.1, semver@^7.3.5: - version "7.3.7" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" - integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== - dependencies: - lru-cache "^6.0.0" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -shiki@^0.10.1: - version "0.10.1" - resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.10.1.tgz#6f9a16205a823b56c072d0f1a0bcd0f2646bef14" - integrity sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng== - dependencies: - jsonc-parser "^3.0.0" - vscode-oniguruma "^1.6.1" - vscode-textmate "5.2.0" - -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== - dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -slice-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" - integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - -source-map-support@^0.5.17: - version "0.5.21" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map@^0.5.0: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - -source-map@^0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string.prototype.trimend@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" - integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -string.prototype.trimstart@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" - integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= - -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -superstruct@^0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.14.2.tgz#0dbcdf3d83676588828f1cf5ed35cda02f59025b" - integrity sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ== - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - -table@^6.0.9: - version "6.8.0" - resolved "https://registry.yarnpkg.com/table/-/table-6.8.0.tgz#87e28f14fa4321c3377ba286f07b79b281a3b3ca" - integrity sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA== - dependencies: - ajv "^8.0.1" - lodash.truncate "^4.4.2" - slice-ansi "^4.0.0" - string-width "^4.2.3" - strip-ansi "^6.0.1" - -text-encoding-utf-8@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz#585b62197b0ae437e3c7b5d0af27ac1021e10d13" - integrity sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg== - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -"through@>=2.2.7 <3": - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= - -ts-node@^9.1.1: - version "9.1.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d" - integrity sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg== - dependencies: - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - source-map-support "^0.5.17" - yn "3.1.1" - -tsconfig-paths@^3.14.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" - integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== - dependencies: - "@types/json5" "^0.0.29" - json5 "^1.0.1" - minimist "^1.2.6" - strip-bom "^3.0.0" - -tslib@^1.8.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tsutils@^3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - -tweetnacl@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" - integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== - -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - -typedoc@^0.22.11: - version "0.22.17" - resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.22.17.tgz#bc51cc95f569040112504300831cdac4f8089b7b" - integrity sha512-h6+uXHVVCPDaANzjwzdsj9aePBjZiBTpiMpBBeyh1zcN2odVsDCNajz8zyKnixF93HJeGpl34j/70yoEE5BfNg== - dependencies: - glob "^8.0.3" - lunr "^2.3.9" - marked "^4.0.16" - minimatch "^5.1.0" - shiki "^0.10.1" - -typescript@^4.1.3: - version "4.6.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.3.tgz#eefeafa6afdd31d725584c67a0eaba80f6fc6c6c" - integrity sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw== - -unbox-primitive@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" - integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== - dependencies: - function-bind "^1.1.1" - has-bigints "^1.0.1" - has-symbols "^1.0.2" - which-boxed-primitive "^1.0.2" - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -utf-8-validate@^5.0.2: - version "5.0.9" - resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.9.tgz#ba16a822fbeedff1a58918f2a6a6b36387493ea3" - integrity sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q== - dependencies: - node-gyp-build "^4.3.0" - -uuid@^8.3.0, uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - -v8-compile-cache@^2.0.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== - -vscode-oniguruma@^1.6.1: - version "1.6.2" - resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz#aeb9771a2f1dbfc9083c8a7fdd9cccaa3f386607" - integrity sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA== - -vscode-textmate@5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.2.0.tgz#01f01760a391e8222fe4f33fbccbd1ad71aed74e" - integrity sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ== - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -word-wrap@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -ws@^7.4.5: - version "7.5.7" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.7.tgz#9e0ac77ee50af70d58326ecff7e85eb3fa375e67" - integrity sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yn@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== diff --git a/name-service/program/Cargo.toml b/name-service/program/Cargo.toml index 1abc2e6d759..977b2e99698 100644 --- a/name-service/program/Cargo.toml +++ b/name-service/program/Cargo.toml @@ -1,31 +1,31 @@ [package] name = "spl-name-service" description = "Solana Program Library Name Service" -version = "0.2.0" +version = "0.3.0" repository = "https://github.com/solana-labs/solana-program-library" authors = [ "lcchy ", - "Solana Maintainers " + "Solana Labs Maintainers ", ] license = "Apache-2.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] no-entrypoint = [] -test-bpf = [] +test-sbf = [] [dependencies] -solana-program = "1.10.33" +solana-program = "2.1.0" num-traits = "0.2" -borsh = "0.9.1" -num-derive = "0.3.3" -thiserror = "1.0.29" +borsh = "1.5.3" +num-derive = "0.4.2" +thiserror = "2.0.9" [dev-dependencies] -solana-program-test = "1.10.33" -solana-sdk = "1.10.33" +solana-program-test = "2.1.0" +solana-sdk = "2.1.0" [lib] crate-type = ["cdylib", "lib"] diff --git a/name-service/program/src/entrypoint.rs b/name-service/program/src/entrypoint.rs index 1e70cd1ce17..bd19cbdf4dd 100644 --- a/name-service/program/src/entrypoint.rs +++ b/name-service/program/src/entrypoint.rs @@ -1,14 +1,13 @@ use { - crate::error::NameServiceError, - crate::processor::Processor, + crate::{error::NameServiceError, processor::Processor}, num_traits::FromPrimitive, solana_program::{ - account_info::AccountInfo, decode_error::DecodeError, entrypoint, - entrypoint::ProgramResult, msg, program_error::PrintProgramError, pubkey::Pubkey, + account_info::AccountInfo, decode_error::DecodeError, entrypoint::ProgramResult, msg, + program_error::PrintProgramError, pubkey::Pubkey, }, }; -entrypoint!(process_instruction); +solana_program::entrypoint!(process_instruction); pub fn process_instruction( program_id: &Pubkey, diff --git a/name-service/program/src/instruction.rs b/name-service/program/src/instruction.rs index 2dd7a6faa3d..7f722284b3e 100644 --- a/name-service/program/src/instruction.rs +++ b/name-service/program/src/instruction.rs @@ -13,13 +13,14 @@ use { pub enum NameRegistryInstruction { /// Create an empty name record /// - /// The address of the name record (account #1) is a program-derived address with the following - /// seeds to ensure uniqueness: + /// The address of the name record (account #1) is a program-derived address + /// with the following seeds to ensure uniqueness: /// * SHA256(HASH_PREFIX, `Create::name`) /// * Account class (account #3) /// * Parent name record address (account #4) /// - /// If this is a child record, the parent record's owner must approve by signing (account #5) + /// If this is a child record, the parent record's owner must approve by + /// signing (account #5) /// /// Accounts expected by this instruction: /// 0. `[]` System program @@ -27,18 +28,22 @@ pub enum NameRegistryInstruction { /// 2. `[writeable]` Name record to be created (program-derived address) /// 3. `[]` Account owner (written into `NameRecordHeader::owner`) /// 4. `[signer]` Account class (written into `NameRecordHeader::class`). - /// If `Pubkey::default()` then the `signer` bit is not required - /// 5. `[]` Parent name record (written into `NameRecordHeader::parent_name). `Pubkey::default()` is equivalent to no existing parent. - /// 6. `[signer]` Owner of the parent name record. Optional but needed if parent name different than default. - /// + /// If `Pubkey::default()` then the `signer` bit is not required + /// 5. `[]` Parent name record (written into + /// `NameRecordHeader::parent_name). `Pubkey::default()` is equivalent + /// to no existing parent. + /// 6. `[signer]` Owner of the parent name record. Optional but needed if + /// parent name different than default. Create { - /// SHA256 of the (HASH_PREFIX + Name) of the record to create, hashing is done off-chain + /// SHA256 of the (HASH_PREFIX + Name) of the record to create, hashing + /// is done off-chain hashed_name: Vec, /// Number of lamports to fund the name record with lamports: u64, - /// Number of bytes of memory to allocate in addition to the `NameRecordHeader` + /// Number of bytes of memory to allocate in addition to the + /// `NameRecordHeader` space: u32, }, @@ -81,14 +86,32 @@ pub enum NameRegistryInstruction { /// Delete a name record. /// - /// Any lamports remaining in the name record will be transferred to the refund account (#2) + /// Any lamports remaining in the name record will be transferred to the + /// refund account (#2) /// /// Accounts expected by this instruction: /// 0. `[writeable]` Name record to be deleted /// 1. `[signer]` Account owner /// 2. `[writeable]` Refund account - /// Delete, + + /// Realloc the data of a name record. + /// + /// The space change cannot be more than `MAX_PERMITTED_DATA_LENGTH` greater + /// than current `space`. + /// + /// Accounts expected by this instruction: + /// 0. `[]` System program + /// 1. `[writeable, signer]` Payer account (will be refunded if new + /// `space` is less than current `space`) + /// 2. `[writeable]` Name record to be reallocated + /// 3. `[signer]` Account owner + Realloc { + /// New total number of bytes in addition to the `NameRecordHeader`. + /// There are no checks on the existing data; it will be truncated if + /// the new space is less than the current space. + space: u32, + }, } #[allow(clippy::too_many_arguments)] @@ -102,7 +125,7 @@ pub fn create( name_parent_opt: Option, name_parent_owner_opt: Option, ) -> Result { - let data = instruction_data.try_to_vec().unwrap(); + let data = borsh::to_vec(&instruction_data).unwrap(); let mut accounts = vec![ AccountMeta::new_readonly(system_program::id(), false), AccountMeta::new(payer_key, true), @@ -139,7 +162,7 @@ pub fn update( name_parent: Option, ) -> Result { let instruction_data = NameRegistryInstruction::Update { offset, data }; - let data = instruction_data.try_to_vec().unwrap(); + let data = borsh::to_vec(&instruction_data).unwrap(); let mut accounts = vec![ AccountMeta::new(name_account_key, false), AccountMeta::new_readonly(name_update_signer, true), @@ -164,7 +187,7 @@ pub fn transfer( name_class_opt: Option, ) -> Result { let instruction_data = NameRegistryInstruction::Transfer { new_owner }; - let data = instruction_data.try_to_vec().unwrap(); + let data = borsh::to_vec(&instruction_data).unwrap(); let mut accounts = vec![ AccountMeta::new(name_account_key, false), AccountMeta::new_readonly(name_owner_key, true), @@ -188,7 +211,7 @@ pub fn delete( refund_target: Pubkey, ) -> Result { let instruction_data = NameRegistryInstruction::Delete; - let data = instruction_data.try_to_vec().unwrap(); + let data = borsh::to_vec(&instruction_data).unwrap(); let accounts = vec![ AccountMeta::new(name_account_key, false), AccountMeta::new_readonly(name_owner_key, true), @@ -201,3 +224,26 @@ pub fn delete( data, }) } + +pub fn realloc( + name_service_program_id: Pubkey, + payer_key: Pubkey, + name_account_key: Pubkey, + name_owner_key: Pubkey, + space: u32, +) -> Result { + let instruction_data = NameRegistryInstruction::Realloc { space }; + let data = borsh::to_vec(&instruction_data).unwrap(); + let accounts = vec![ + AccountMeta::new_readonly(system_program::id(), false), + AccountMeta::new(payer_key, true), + AccountMeta::new(name_account_key, false), + AccountMeta::new_readonly(name_owner_key, true), + ]; + + Ok(Instruction { + program_id: name_service_program_id, + accounts, + data, + }) +} diff --git a/name-service/program/src/lib.rs b/name-service/program/src/lib.rs index 2b4e21a25f6..bd7e144698c 100644 --- a/name-service/program/src/lib.rs +++ b/name-service/program/src/lib.rs @@ -5,7 +5,8 @@ pub mod instruction; pub mod processor; pub mod state; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version pub use solana_program; solana_program::declare_id!("namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX"); diff --git a/name-service/program/src/processor.rs b/name-service/program/src/processor.rs index d185dd2a9cf..8331f5d5426 100644 --- a/name-service/program/src/processor.rs +++ b/name-service/program/src/processor.rs @@ -1,8 +1,7 @@ use { crate::{ instruction::NameRegistryInstruction, - state::get_seeds_and_key, - state::{write_data, NameRecordHeader}, + state::{get_seeds_and_key, write_data, NameRecordHeader}, }, borsh::BorshDeserialize, solana_program::{ @@ -13,8 +12,11 @@ use { program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, + rent::Rent, system_instruction, + sysvar::Sysvar, }, + std::cmp::Ordering, }; pub struct Processor {} @@ -82,7 +84,8 @@ impl Processor { if name_account.data.borrow().len() == 0 { // Issue the name registry account // The creation is done in three steps: transfer, allocate and assign, because - // one cannot `system_instruction::create` an account to which lamports have been transfered before. + // one cannot `system_instruction::create` an account to which lamports have + // been transferred before. invoke( &system_instruction::transfer(payer_account.key, &name_account_key, lamports), &[ @@ -95,7 +98,7 @@ impl Processor { invoke_signed( &system_instruction::allocate( &name_account_key, - (NameRecordHeader::LEN + space as usize) as u64, + NameRecordHeader::LEN.saturating_add(space as usize) as u64, ), &[name_account.clone(), system_program.clone()], &[&seeds.chunks(32).collect::>()], @@ -158,7 +161,11 @@ impl Processor { return Err(ProgramError::InvalidArgument); } - write_data(name_account, &data, NameRecordHeader::LEN + offset as usize); + write_data( + name_account, + &data, + NameRecordHeader::LEN.saturating_add(offset as usize), + ); Ok(()) } @@ -229,12 +236,63 @@ impl Processor { // Close the account by transferring the rent sol let source_amount: &mut u64 = &mut name_account.lamports.borrow_mut(); let dest_amount: &mut u64 = &mut refund_target.lamports.borrow_mut(); - *dest_amount += *source_amount; + *dest_amount = dest_amount.saturating_add(*source_amount); *source_amount = 0; Ok(()) } + fn process_realloc(accounts: &[AccountInfo], space: u32) -> ProgramResult { + let accounts_iter = &mut accounts.iter(); + let system_program = next_account_info(accounts_iter)?; + let payer_account = next_account_info(accounts_iter)?; + let name_account = next_account_info(accounts_iter)?; + let name_owner = next_account_info(accounts_iter)?; + + let name_record_header = NameRecordHeader::unpack_from_slice(&name_account.data.borrow())?; + + // Verifications + if !name_owner.is_signer || name_record_header.owner != *name_owner.key { + msg!("The given name owner is incorrect or not a signer."); + return Err(ProgramError::InvalidArgument); + } + + let new_space = NameRecordHeader::LEN.saturating_add(space as usize); + let required_lamports = Rent::get()?.minimum_balance(new_space); + match name_account.lamports().cmp(&required_lamports) { + Ordering::Less => { + // Overflow cannot happen here because we already checked the sizes. + #[allow(clippy::arithmetic_side_effects)] + let lamports_to_add = required_lamports - name_account.lamports(); + invoke( + &system_instruction::transfer( + payer_account.key, + name_account.key, + lamports_to_add, + ), + &[ + payer_account.clone(), + name_account.clone(), + system_program.clone(), + ], + )?; + } + Ordering::Greater => { + // Overflow cannot happen here because we already checked the sizes. + #[allow(clippy::arithmetic_side_effects)] + let lamports_to_remove = name_account.lamports() - required_lamports; + let source_amount: &mut u64 = &mut name_account.lamports.borrow_mut(); + let dest_amount: &mut u64 = &mut payer_account.lamports.borrow_mut(); + *source_amount = source_amount.saturating_sub(lamports_to_remove); + *dest_amount = dest_amount.saturating_add(lamports_to_remove); + } + Ordering::Equal => {} + } + // Max data increase is checked in realloc. No need to check here. + name_account.realloc(new_space, false)?; + Ok(()) + } + pub fn process_instruction( program_id: &Pubkey, accounts: &[AccountInfo], @@ -266,6 +324,10 @@ impl Processor { msg!("Instruction: Delete Name"); Processor::process_delete(accounts)?; } + NameRegistryInstruction::Realloc { space } => { + msg!("Instruction: Realloc Name Record"); + Processor::process_realloc(accounts, space)?; + } } Ok(()) } diff --git a/name-service/program/src/state.rs b/name-service/program/src/state.rs index 899da7472f6..ea584267af1 100644 --- a/name-service/program/src/state.rs +++ b/name-service/program/src/state.rs @@ -9,9 +9,11 @@ use { }, }; -/// The data for a Name Registry account is always prefixed a `NameRecordHeader` structure. +/// The data for a Name Registry account is always prefixed a `NameRecordHeader` +/// structure. /// -/// The layout of the remaining bytes in the account data are determined by the record `class` +/// The layout of the remaining bytes in the account data are determined by the +/// record `class` #[derive(Clone, Debug, BorshSerialize, BorshDeserialize, PartialEq)] pub struct NameRecordHeader { // Names are hierarchical. `parent_name` contains the account address of the parent @@ -21,7 +23,8 @@ pub struct NameRecordHeader { // The owner of this name pub owner: Pubkey, - // The class of data this account represents (DNS record, twitter handle, SPL Token name/symbol, etc) + // The class of data this account represents (DNS record, twitter handle, SPL Token + // name/symbol, etc) // // If `Pubkey::default()` the data is unspecified. pub class: Pubkey, @@ -54,7 +57,7 @@ impl IsInitialized for NameRecordHeader { pub fn write_data(account: &AccountInfo, input: &[u8], offset: usize) { let mut account_data = account.data.borrow_mut(); - account_data[offset..offset + input.len()].copy_from_slice(input); + account_data[offset..offset.saturating_add(input.len())].copy_from_slice(input); } //////////////////////////////////////////////////////////// @@ -69,7 +72,9 @@ pub fn get_seeds_and_key( name_class_opt: Option<&Pubkey>, parent_name_address_opt: Option<&Pubkey>, ) -> (Pubkey, Vec) { - // let hashed_name: Vec = hashv(&[(HASH_PREFIX.to_owned() + name).as_bytes()]).0.to_vec(); + // let hashed_name: Vec = hashv(&[ + // (HASH_PREFIX.to_owned() + name).as_bytes() + // ]).0.to_vec(); let mut seeds_vec: Vec = hashed_name; let name_class = name_class_opt.cloned().unwrap_or_default(); diff --git a/name-service/program/tests/functional.rs b/name-service/program/tests/functional.rs index 1373cf4bb98..c77415d6613 100644 --- a/name-service/program/tests/functional.rs +++ b/name-service/program/tests/functional.rs @@ -1,19 +1,20 @@ -#![cfg(feature = "test-bpf")] -use std::str::FromStr; - -use solana_program::{instruction::Instruction, program_pack::Pack, pubkey::Pubkey}; -use solana_program_test::{processor, tokio, ProgramTest, ProgramTestContext}; - -use solana_program::hash::hashv; -use solana_sdk::{ - signature::{Keypair, Signer}, - transaction::Transaction, - transport::TransportError, -}; -use spl_name_service::{ - entrypoint::process_instruction, - instruction::{create, delete, transfer, update, NameRegistryInstruction}, - state::{get_seeds_and_key, NameRecordHeader, HASH_PREFIX}, +#![cfg(feature = "test-sbf")] +use { + solana_program::{hash::hashv, instruction::Instruction, program_pack::Pack, pubkey::Pubkey}, + solana_program_test::{ + processor, tokio, ProgramTest, ProgramTestBanksClientExt, ProgramTestContext, + }, + solana_sdk::{ + signature::{Keypair, Signer}, + transaction::Transaction, + transport::TransportError, + }, + spl_name_service::{ + instruction::{create, delete, realloc, transfer, update, NameRegistryInstruction}, + processor::Processor, + state::{get_seeds_and_key, NameRecordHeader, HASH_PREFIX}, + }, + std::str::FromStr, }; #[tokio::test] @@ -24,7 +25,7 @@ async fn test_name_service() { let program_test = ProgramTest::new( "spl_name_service", program_id, - processor!(process_instruction), + processor!(Processor::process_instruction), ); let mut ctx = program_test.start_with_context().await; @@ -49,7 +50,7 @@ async fn test_name_service() { program_id, NameRegistryInstruction::Create { hashed_name: hashed_root_name, - lamports: rent.minimum_balance(space + NameRecordHeader::LEN), + lamports: rent.minimum_balance(space.saturating_add(NameRecordHeader::LEN)), space: space as u32, }, root_name_account_key, @@ -65,8 +66,7 @@ async fn test_name_service() { .unwrap(); let name_record_header = NameRecordHeader::unpack_from_slice( - &mut &ctx - .banks_client + &ctx.banks_client .get_account(root_name_account_key) .await .unwrap() @@ -93,7 +93,7 @@ async fn test_name_service() { program_id, NameRegistryInstruction::Create { hashed_name, - lamports: rent.minimum_balance(space + NameRecordHeader::LEN), + lamports: rent.minimum_balance(space.saturating_add(NameRecordHeader::LEN)), space: space as u32, }, name_account_key, @@ -113,8 +113,7 @@ async fn test_name_service() { .unwrap(); let name_record_header = NameRecordHeader::unpack_from_slice( - &mut &ctx - .banks_client + &ctx.banks_client .get_account(name_account_key) .await .unwrap() @@ -140,8 +139,7 @@ async fn test_name_service() { .unwrap(); let name_record_header = NameRecordHeader::unpack_from_slice( - &mut &ctx - .banks_client + &ctx.banks_client .get_account(name_account_key) .await .unwrap() @@ -168,8 +166,7 @@ async fn test_name_service() { .unwrap(); let name_record_header = NameRecordHeader::unpack_from_slice( - &mut &ctx - .banks_client + &ctx.banks_client .get_account(name_account_key) .await .unwrap() @@ -179,6 +176,59 @@ async fn test_name_service() { .unwrap(); println!("Name Record Header: {:?}", name_record_header); + let data = "hello".as_bytes().to_vec(); + let update_instruction = update( + program_id, + space as u32, + data, + name_account_key, + sol_subdomains_class.pubkey(), + Some(name_record_header.parent_name), + ) + .unwrap(); + + sign_send_instruction( + &mut ctx, + update_instruction.clone(), + vec![&sol_subdomains_class], + ) + .await + .unwrap_err(); + + let new_space = space.checked_mul(2).unwrap(); + let payer_key = ctx.payer.pubkey(); + let realloc_instruction = |space| { + realloc( + program_id, + payer_key, + name_account_key, + payer_key, + space as u32, + ) + .unwrap() + }; + + sign_send_instruction(&mut ctx, realloc_instruction(new_space), vec![]) + .await + .unwrap(); + + // update blockhash to prevent losing txn to dedup + ctx.last_blockhash = ctx + .banks_client + .get_new_latest_blockhash(&ctx.last_blockhash) + .await + .unwrap(); + + // resend update ix. Should succeed this time. + sign_send_instruction(&mut ctx, update_instruction, vec![&sol_subdomains_class]) + .await + .unwrap(); + + // realloc to smaller this time + sign_send_instruction(&mut ctx, realloc_instruction(space / 2), vec![]) + .await + .unwrap(); + let delete_instruction = delete( program_id, name_account_key, @@ -203,7 +253,6 @@ pub async fn sign_send_instruction( payer_signers.push(s); } transaction.partial_sign(&payer_signers, ctx.last_blockhash); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 ctx.banks_client .process_transaction(transaction) .await diff --git a/package.json b/package.json new file mode 100644 index 00000000000..8369712d241 --- /dev/null +++ b/package.json @@ -0,0 +1,32 @@ +{ + "private": true, + "workspaces": [ + "account-compression/sdk", + "token-lending/js", + "token-swap/js" + ], + "scripts": { + "build": "turbo run build", + "build:program": "turbo run build:program", + "clean": "turbo run clean", + "lint": "turbo run lint", + "format": "prettier --check .", + "format:fix": "prettier --write .", + "test": "turbo run test" + }, + "devDependencies": { + "@solana/eslint-config-solana": "^4.0.0", + "@solana/prettier-config-solana": "^0.0.5", + "eslint-config-prettier": "^9.1.0", + "eslint-config-turbo": "^2.3.3", + "eslint-plugin-prettier": "^5.2.1", + "prettier": "^3.4.2", + "turbo": "^2.3.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "packageManager": "pnpm@8.14.3", + "prettier": "@solana/prettier-config-solana", + "name": "solana-program-library" +} diff --git a/patch.crates-io.sh b/patch.crates-io.sh index b420b571e00..d7374fc32d0 100755 --- a/patch.crates-io.sh +++ b/patch.crates-io.sh @@ -22,33 +22,148 @@ set -e solana_dir=$(cd "$solana_dir" && pwd) cd "$(dirname "$0")" +project_root=$(pwd) source "$solana_dir"/scripts/read-cargo-variable.sh -solana_ver=$(readCargoVariable version "$solana_dir"/sdk/Cargo.toml) + +# The toolchain file only exists in version >= 1.15 +toolchain_file="$solana_dir"/rust-toolchain.toml +if [[ -f "$toolchain_file" ]]; then + cp "$toolchain_file" . +fi + +# only add exclude rule when solana root is under spl root +if echo "$solana_dir" | grep "^$project_root" > /dev/null; then + echo "Excluding $solana_dir from workspace" + echo + for crate in "${workspace_crates[@]}"; do + if grep -q "exclude.*$solana_dir" "$crate"; then + echo "$crate is already patched" + else + sed -i'' "$crate" -e "/exclude/a \ \ \"$solana_dir\"," + fi + done +fi + +# get version from Cargo.toml first. if it is empty, get it from other places. +solana_ver="$(readCargoVariable version "$solana_dir"/Cargo.toml)" +solana_ver=${solana_ver:-$(readCargoVariable version "$solana_dir"/sdk/Cargo.toml)} crates_map=() crates_map+=("solana-account-decoder account-decoder") +crates_map+=("solana-account-decoder-client-types account-decoder-client-types") crates_map+=("solana-banks-client banks-client") +crates_map+=("solana-banks-interface banks-interface") crates_map+=("solana-banks-server banks-server") -crates_map+=("solana-bpf-loader-program programs/bpf_loader") +crates_map+=("solana-bloom bloom") +crates_map+=("solana-bucket-map bucket_map") +crates_map+=("solana-builtins-default-costs builtins-default-costs") crates_map+=("solana-clap-utils clap-utils") +crates_map+=("solana-clap-v3-utils clap-v3-utils") crates_map+=("solana-cli-config cli-config") crates_map+=("solana-cli-output cli-output") crates_map+=("solana-client client") +crates_map+=("solana-compute-budget compute-budget") +crates_map+=("solana-connection-cache connection-cache") crates_map+=("solana-core core") -crates_map+=("solana-logger logger") -crates_map+=("solana-notifier notifier") -crates_map+=("solana-remote-wallet remote-wallet") -crates_map+=("solana-program sdk/program") +crates_map+=("solana-entry entry") +crates_map+=("solana-faucet faucet") +crates_map+=("solana-fee fee") +crates_map+=("agave-geyser-plugin-interface geyser-plugin-interface") +crates_map+=("solana-geyser-plugin-manager geyser-plugin-manager") +crates_map+=("solana-gossip gossip") +crates_map+=("solana-lattice-hash lattice-hash") +crates_map+=("solana-ledger ledger") +crates_map+=("solana-log-collector log-collector") +crates_map+=("solana-measure measure") +crates_map+=("solana-merkle-tree merkle-tree") +crates_map+=("solana-metrics metrics") +crates_map+=("solana-net-utils net-utils") +crates_map+=("solana-perf perf") +crates_map+=("solana-poh poh") +crates_map+=("solana-program-runtime program-runtime") crates_map+=("solana-program-test program-test") +crates_map+=("solana-address-lookup-table-program programs/address-lookup-table") +crates_map+=("solana-bpf-loader-program programs/bpf_loader") +crates_map+=("solana-compute-budget-program programs/compute-budget") +crates_map+=("solana-config-program programs/config") +crates_map+=("solana-stake-program programs/stake") +crates_map+=("solana-system-program programs/system") +crates_map+=("solana-vote-program programs/vote") +crates_map+=("solana-zk-elgamal-proof-program programs/zk-elgamal-proof") +crates_map+=("solana-zk-token-proof-program programs/zk-token-proof") +crates_map+=("solana-pubsub-client pubsub-client") +crates_map+=("solana-quic-client quic-client") +crates_map+=("solana-rayon-threadlimit rayon-threadlimit") +crates_map+=("solana-remote-wallet remote-wallet") +crates_map+=("solana-rpc rpc") +crates_map+=("solana-rpc-client rpc-client") +crates_map+=("solana-rpc-client-api rpc-client-api") +crates_map+=("solana-rpc-client-nonce-utils rpc-client-nonce-utils") crates_map+=("solana-runtime runtime") +crates_map+=("solana-runtime-transaction runtime-transaction") crates_map+=("solana-sdk sdk") -crates_map+=("solana-stake-program programs/stake") +crates_map+=("solana-sdk-macro sdk/macro") +crates_map+=("solana-program sdk/program") +crates_map+=("solana-send-transaction-service send-transaction-service") +crates_map+=("solana-storage-bigtable storage-bigtable") +crates_map+=("solana-storage-proto storage-proto") +crates_map+=("solana-streamer streamer") +crates_map+=("solana-svm-rent-collector svm-rent-collector") +crates_map+=("solana-svm-transaction svm-transaction") crates_map+=("solana-test-validator test-validator") +crates_map+=("solana-thin-client thin-client") +crates_map+=("solana-tpu-client tpu-client") crates_map+=("solana-transaction-status transaction-status") +crates_map+=("solana-transaction-status-client-types transaction-status-client-types") +crates_map+=("solana-udp-client udp-client") crates_map+=("solana-version version") -crates_map+=("solana-vote-program programs/vote") crates_map+=("solana-zk-token-sdk zk-token-sdk") +crates_map+=("solana-zk-sdk zk-sdk") +crates_map+=("solana-bn254 curves/bn254") +crates_map+=("solana-curve25519 curves/curve25519") +crates_map+=("solana-secp256k1-recover curves/secp256k1-recover") +crates_map+=("solana-account sdk/account") +crates_map+=("solana-account-info sdk/account-info") +crates_map+=("solana-atomic-u64 sdk/atomic-u64") +crates_map+=("solana-bincode sdk/bincode") +crates_map+=("solana-borsh sdk/borsh") +crates_map+=("solana-clock sdk/clock") +crates_map+=("solana-cpi sdk/cpi") +crates_map+=("solana-decode-error sdk/decode-error") +crates_map+=("solana-define-syscall sdk/define-syscall") +crates_map+=("solana-derivation-path sdk/derivation-path") +crates_map+=("solana-epoch-schedule sdk/epoch-schedule") +crates_map+=("solana-feature-set sdk/feature-set") +crates_map+=("solana-fee-calculator sdk/fee-calculator") +crates_map+=("solana-frozen-abi sdk/frozen-abi") +crates_map+=("solana-frozen-abi-macro sdk/frozen-abi/macro") +crates_map+=("solana-hash sdk/hash") +crates_map+=("solana-inflation sdk/inflation") +crates_map+=("solana-instruction sdk/instruction") +crates_map+=("solana-last-restart-slot sdk/last-restart-slot") +crates_map+=("solana-logger sdk/logger") +crates_map+=("solana-msg sdk/msg") +crates_map+=("solana-native-token sdk/native-token") +crates_map+=("solana-packet sdk/packet") +crates_map+=("solana-precompile-error sdk/precompile-error") +crates_map+=("solana-program-entrypoint sdk/program-entrypoint") +crates_map+=("solana-program-error sdk/program-error") +crates_map+=("solana-program-memory sdk/program-memory") +crates_map+=("solana-program-option sdk/program-option") +crates_map+=("solana-program-pack sdk/program-pack") +crates_map+=("solana-pubkey sdk/pubkey") +crates_map+=("solana-rent sdk/rent") +crates_map+=("solana-sanitize sdk/sanitize") +crates_map+=("solana-serde-varint sdk/serde-varint") +crates_map+=("solana-serialize-utils sdk/serialize-utils") +crates_map+=("solana-sha256-hasher sdk/sha256-hasher") +crates_map+=("solana-short-vec sdk/short-vec") +crates_map+=("solana-signature sdk/signature") +crates_map+=("solana-slot-hashes sdk/slot-hashes") +crates_map+=("solana-stable-layout sdk/stable-layout") +crates_map+=("solana-timings sdk/timings") +crates_map+=("solana-transaction-error sdk/transaction-error") patch_crates=() for map_entry in "${crates_map[@]}"; do @@ -62,11 +177,14 @@ done echo "Patching in $solana_ver from $solana_dir" echo for crate in "${workspace_crates[@]}"; do - if grep -q '\[patch.crates-io\]' "$crate"; then + if grep -q "# The following entries are auto-generated by $0" "$crate"; then echo "$crate is already patched" else + if ! grep -q '\[patch.crates-io\]' "$crate"; then + echo "[patch.crates-io]" >> "$crate" + fi cat >> "$crate" <=0.10.0'} + dev: true + + /@ampproject/remapping@2.2.1: + resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + dev: true + + /@babel/code-frame@7.26.2: + resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.25.9 + js-tokens: 4.0.0 + picocolors: 1.0.0 + dev: true + + /@babel/compat-data@7.26.2: + resolution: {integrity: sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/core@7.26.0: + resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.2.1 + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.2 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helpers': 7.26.0 + '@babel/parser': 7.26.2 + '@babel/template': 7.25.9 + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + convert-source-map: 2.0.0 + debug: 4.4.0 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/generator@7.26.2: + resolution: {integrity: sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 3.0.2 + dev: true + + /@babel/helper-compilation-targets@7.25.9: + resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': 7.26.2 + '@babel/helper-validator-option': 7.25.9 + browserslist: 4.24.2 + lru-cache: 5.1.1 + semver: 6.3.1 + dev: true + + /@babel/helper-module-imports@7.25.9: + resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0): + resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + '@babel/traverse': 7.25.9 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-plugin-utils@7.22.5: + resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-string-parser@7.25.9: + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-identifier@7.25.9: + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-option@7.25.9: + resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helpers@7.26.0: + resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.25.9 + '@babel/types': 7.26.0 + dev: true + + /@babel/parser@7.23.0: + resolution: {integrity: sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.26.0 + dev: true + + /@babel/parser@7.26.2: + resolution: {integrity: sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.26.0 + dev: true + + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.26.0): + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.26.0): + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.26.0): + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.0): + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.26.0): + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-jsx@7.22.5(@babel/core@7.26.0): + resolution: {integrity: sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.26.0): + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.26.0): + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.26.0): + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.26.0): + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.26.0): + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.26.0): + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.26.0): + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-typescript@7.22.5(@babel/core@7.26.0): + resolution: {integrity: sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/runtime@7.25.0: + resolution: {integrity: sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.0 + + /@babel/template@7.25.9: + resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 + dev: true + + /@babel/traverse@7.25.9: + resolution: {integrity: sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.2 + '@babel/parser': 7.26.2 + '@babel/template': 7.25.9 + '@babel/types': 7.26.0 + debug: 4.4.0 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/types@7.26.0: + resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + dev: true + + /@bcoe/v8-coverage@0.2.3: + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + dev: true + + /@coral-xyz/anchor@0.29.0: + resolution: {integrity: sha512-eny6QNG0WOwqV0zQ7cs/b1tIuzZGmP7U7EcH+ogt4Gdbl8HDmIYVMh/9aTmYZPaFWjtUaI8qSn73uYEXWfATdA==} + engines: {node: '>=11'} + dependencies: + '@coral-xyz/borsh': 0.29.0(@solana/web3.js@1.95.4) + '@noble/hashes': 1.4.0 + '@solana/web3.js': 1.95.4 + bn.js: 5.2.1 + bs58: 4.0.1 + buffer-layout: 1.2.2 + camelcase: 6.3.0 + cross-fetch: 3.1.8 + crypto-hash: 1.3.0 + eventemitter3: 4.0.7 + pako: 2.1.0 + snake-case: 3.0.4 + superstruct: 0.15.5 + toml: 3.0.0 + transitivePeerDependencies: + - bufferutil + - encoding + - utf-8-validate + dev: true + + /@coral-xyz/borsh@0.29.0(@solana/web3.js@1.95.4): + resolution: {integrity: sha512-s7VFVa3a0oqpkuRloWVPdCK7hMbAMY270geZOGfCnaqexrP5dTIpbEHL33req6IYPPJ0hYa71cdvJ1h6V55/oQ==} + engines: {node: '>=10'} + peerDependencies: + '@solana/web3.js': ^1.68.0 + dependencies: + '@solana/web3.js': 1.95.4 + bn.js: 5.2.1 + buffer-layout: 1.2.2 + dev: true + + /@cspotcode/source-map-support@0.8.1: + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + dev: true + + /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + 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.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/eslint-utils@4.4.0(eslint@9.13.0): + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 9.13.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/regexpp@4.10.0: + resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + 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/config-array@0.18.0: + resolution: {integrity: sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@eslint/object-schema': 2.1.4 + debug: 4.4.0 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@eslint/core@0.7.0: + resolution: {integrity: sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.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 + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@eslint/eslintrc@3.1.0: + resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + ajv: 6.12.6 + debug: 4.4.0 + espree: 10.3.0 + globals: 14.0.0 + ignore: 5.3.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@eslint/js@8.57.0: + resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@eslint/js@9.13.0: + resolution: {integrity: sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true + + /@eslint/object-schema@2.1.4: + resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true + + /@eslint/plugin-kit@0.2.2: + resolution: {integrity: sha512-CXtq5nR4Su+2I47WPOlWud98Y5Lv8Kyxp2ukhgFx/eW6Blm18VXJO5WuQylPugRo8nbluoi6GvvxBLqHcvqUUw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + levn: 0.4.1 + dev: true + + /@gerrit0/mini-shiki@1.24.1: + resolution: {integrity: sha512-PNP/Gjv3VqU7z7DjRgO3F9Ok5frTKqtpV+LJW1RzMcr2zpRk0ulhEWnbcNGXzPC7BZyWMIHrkfQX2GZRfxrn6Q==} + dependencies: + '@shikijs/engine-oniguruma': 1.24.0 + '@shikijs/types': 1.24.0 + '@shikijs/vscode-textmate': 9.3.0 + dev: true + + /@hapi/hoek@9.3.0: + resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} + dev: true + + /@hapi/topo@5.1.0: + resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} + dependencies: + '@hapi/hoek': 9.3.0 + dev: true + + /@humanfs/core@0.19.1: + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + dev: true + + /@humanfs/node@0.16.6: + resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} + engines: {node: '>=18.18.0'} + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.3.1 + dev: true + + /@humanwhocodes/config-array@0.11.14: + resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 2.0.2 + debug: 4.4.0 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@humanwhocodes/module-importer@1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + dev: true + + /@humanwhocodes/object-schema@2.0.2: + resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} + dev: true + + /@humanwhocodes/retry@0.3.1: + resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} + engines: {node: '>=18.18'} + dev: true + + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + dependencies: + 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 + + /@istanbuljs/load-nyc-config@1.1.0: + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.1 + resolve-from: 5.0.0 + dev: true + + /@istanbuljs/schema@0.1.3: + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + dev: true + + /@jest/console@29.7.0: + resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@types/node': 22.10.5 + chalk: 4.1.2 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + dev: true + + /@jest/console@30.0.0-alpha.6: + resolution: {integrity: sha512-08BeAnuabmauj5B+Xa4GNPAotQUGm3PLKSE3rnpnmxniZzR4tXhx8+AA2+HGTri4bbVRY/r3Jl0vJnkhvHTkeQ==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@jest/types': 30.0.0-alpha.6 + '@types/node': 22.10.5 + chalk: 4.1.2 + jest-message-util: 30.0.0-alpha.6 + jest-util: 30.0.0-alpha.6 + slash: 3.0.0 + dev: true + + /@jest/core@29.7.0(ts-node@10.9.2): + resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.10.5 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@22.10.5)(ts-node@10.9.2) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.5 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + dev: true + + /@jest/core@30.0.0-alpha.6: + resolution: {integrity: sha512-Qsvu9/I0hUOpeelp3jlTmg6cg3C+w18v4hxWVGchCRJAChvuxmsomB1Cm+DKB6NiMy2EvUvpwdT8X31lERtemw==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/console': 30.0.0-alpha.6 + '@jest/pattern': 30.0.0-alpha.6 + '@jest/reporters': 30.0.0-alpha.6 + '@jest/test-result': 30.0.0-alpha.6 + '@jest/transform': 30.0.0-alpha.6 + '@jest/types': 30.0.0-alpha.6 + '@types/node': 22.10.5 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 4.0.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 30.0.0-alpha.6 + jest-config: 30.0.0-alpha.6(@types/node@22.10.5) + jest-haste-map: 30.0.0-alpha.6 + jest-message-util: 30.0.0-alpha.6 + jest-regex-util: 30.0.0-alpha.6 + jest-resolve: 30.0.0-alpha.6 + jest-resolve-dependencies: 30.0.0-alpha.6 + jest-runner: 30.0.0-alpha.6 + jest-runtime: 30.0.0-alpha.6 + jest-snapshot: 30.0.0-alpha.6 + jest-util: 30.0.0-alpha.6 + jest-validate: 30.0.0-alpha.6 + jest-watcher: 30.0.0-alpha.6 + micromatch: 4.0.8 + pretty-format: 30.0.0-alpha.6 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - esbuild-register + - supports-color + - ts-node + dev: true + + /@jest/environment@29.7.0: + resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.10.5 + jest-mock: 29.7.0 + dev: true + + /@jest/environment@30.0.0-alpha.6: + resolution: {integrity: sha512-pjNYNkzq761hh8D2grrG77L6nhe2VBCFFM+G1hyqhaJ2MAzhp2Gh+G94uF3px7luSzLh8GYvGJQGYy197EUOGQ==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@jest/fake-timers': 30.0.0-alpha.6 + '@jest/types': 30.0.0-alpha.6 + '@types/node': 22.10.5 + jest-mock: 30.0.0-alpha.6 + dev: true + + /@jest/expect-utils@29.7.0: + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + jest-get-type: 29.6.3 + dev: true + + /@jest/expect-utils@30.0.0-alpha.6: + resolution: {integrity: sha512-QMySMhaCUl0ZQd7Tx5X3fVWY5jtQxZNrTll0OyavdQ70ZTLgk0kU9K+XovcMWO26MK9R5EX7bBgD/j7w9hUM4w==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + jest-get-type: 30.0.0-alpha.6 + dev: true + + /@jest/expect@29.7.0: + resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + expect: 29.7.0 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/expect@30.0.0-alpha.6: + resolution: {integrity: sha512-3O74pygTwUBzUjO958IgNwmp0WrjASbiWdMEfUMePVqtiGoyS4Nxj9hsx4uKsNVivNJSZiiayYoP6dLhWerJXQ==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + expect: 30.0.0-alpha.6 + jest-snapshot: 30.0.0-alpha.6 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/fake-timers@29.7.0: + resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@sinonjs/fake-timers': 10.3.0 + '@types/node': 22.10.5 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + dev: true + + /@jest/fake-timers@30.0.0-alpha.6: + resolution: {integrity: sha512-deka0RmhJgEKPJM6cXPd4TJQ6fLczErdMN7Oxzr16UTDFHxtFd79tduJ8uP92dQyO4zy63N/dlFK6d+FHyWUDw==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@jest/types': 30.0.0-alpha.6 + '@sinonjs/fake-timers': 11.3.1 + '@types/node': 22.10.5 + jest-message-util: 30.0.0-alpha.6 + jest-mock: 30.0.0-alpha.6 + jest-util: 30.0.0-alpha.6 + dev: true + + /@jest/globals@29.7.0: + resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/types': 29.6.3 + jest-mock: 29.7.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/globals@30.0.0-alpha.6: + resolution: {integrity: sha512-+uJMoPUos9RH6+52iNgKJBbx1Hd2QsCZjExi5XpVvTjJ/gE4eJ1X7irUMt+14sH0QkeZ3GnjeTJFopyjOCsu+Q==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@jest/environment': 30.0.0-alpha.6 + '@jest/expect': 30.0.0-alpha.6 + '@jest/types': 30.0.0-alpha.6 + jest-mock: 30.0.0-alpha.6 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/pattern@30.0.0-alpha.6: + resolution: {integrity: sha512-eoV3sjS1M5k3YdrFWezqdndfgepwB86gwyXC0BzV2saZdJ42ySUoEDBGKuwta8A6Zh3w8tVHNFxz1BqiFraHCQ==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@types/node': 22.10.5 + jest-regex-util: 30.0.0-alpha.6 + dev: true + + /@jest/reporters@29.7.0: + resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.20 + '@types/node': 22.10.5 + chalk: 4.1.2 + collect-v8-coverage: 1.0.2 + exit: 0.1.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.1 + istanbul-lib-instrument: 6.0.1 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.6 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + jest-worker: 29.7.0 + slash: 3.0.0 + string-length: 4.0.2 + strip-ansi: 6.0.1 + v8-to-istanbul: 9.1.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/reporters@30.0.0-alpha.6: + resolution: {integrity: sha512-jzW0t2OtEzBYwlG4EMJKG4q5RPaVvLPDm/nBS08hd+XPoLJJ9b5thyo/MoThIqJfdi0lHqFlDQUmlL205CMoSw==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 30.0.0-alpha.6 + '@jest/test-result': 30.0.0-alpha.6 + '@jest/transform': 30.0.0-alpha.6 + '@jest/types': 30.0.0-alpha.6 + '@jridgewell/trace-mapping': 0.3.25 + '@types/node': 22.10.5 + chalk: 4.1.2 + collect-v8-coverage: 1.0.2 + exit: 0.1.2 + glob: 10.4.5 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.1 + istanbul-lib-instrument: 6.0.3 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.1.6 + jest-message-util: 30.0.0-alpha.6 + jest-util: 30.0.0-alpha.6 + jest-worker: 30.0.0-alpha.6 + slash: 3.0.0 + string-length: 4.0.2 + strip-ansi: 6.0.1 + v8-to-istanbul: 9.1.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/schemas@29.6.3: + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@sinclair/typebox': 0.27.8 + dev: true + + /@jest/schemas@30.0.0-alpha.6: + resolution: {integrity: sha512-Ukr3kR/VsBq8+JHU92xArhSJeFQHVHs5T1laPO00GrrNzv3DvoHn3/EVVagGn9CHbLeAyJHXFRHYxq3+520kiA==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@sinclair/typebox': 0.33.17 + dev: true + + /@jest/snapshot-utils@30.0.0-alpha.6: + resolution: {integrity: sha512-iDtIFCyRT8ZyLmz6kYbS8GR/MBXKA6uZPBfdTcnd2y0T987DV3GVlvwkAC+iFTc1w3HgwQe8LTf+y3i+O2ISCw==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@jest/types': 30.0.0-alpha.6 + chalk: 4.1.2 + graceful-fs: 4.2.11 + natural-compare: 1.4.0 + dev: true + + /@jest/source-map@29.6.3: + resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + callsites: 3.1.0 + graceful-fs: 4.2.11 + dev: true + + /@jest/source-map@30.0.0-alpha.6: + resolution: {integrity: sha512-7rSrxehVyzqw5O+F2ds7wLAm9f6QxqYsJU42LNyUpaFlJqtWz3PeQ2Wu3DVoPzGu0C66EhDHKYmeN0mXnRDZmQ==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + callsites: 3.1.0 + graceful-fs: 4.2.11 + dev: true + + /@jest/test-result@29.7.0: + resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/console': 29.7.0 + '@jest/types': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + collect-v8-coverage: 1.0.2 + dev: true + + /@jest/test-result@30.0.0-alpha.6: + resolution: {integrity: sha512-Jlg8lCm7VQ6YvQ0eZx2nQEtej/ng+ulV8cXH7Nj5i33hNZq8EZvWM4gQDWDzRe1X7cVE3Bd42On5f6s2rqqIjw==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@jest/console': 30.0.0-alpha.6 + '@jest/types': 30.0.0-alpha.6 + '@types/istanbul-lib-coverage': 2.0.6 + collect-v8-coverage: 1.0.2 + dev: true + + /@jest/test-sequencer@29.7.0: + resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/test-result': 29.7.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + slash: 3.0.0 + dev: true + + /@jest/test-sequencer@30.0.0-alpha.6: + resolution: {integrity: sha512-5M89jbSQWkBjGlFrRk2wXjRJVxR+uN553sFN0q2TglH0/a4OMSVxRBcCmnIqqDMDizGAlYTxW6BaXxHGHpvrRQ==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@jest/test-result': 30.0.0-alpha.6 + graceful-fs: 4.2.11 + jest-haste-map: 30.0.0-alpha.6 + slash: 3.0.0 + dev: true + + /@jest/transform@29.7.0: + resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/core': 7.26.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.20 + babel-plugin-istanbul: 6.1.1 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + micromatch: 4.0.8 + pirates: 4.0.6 + slash: 3.0.0 + write-file-atomic: 4.0.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/transform@30.0.0-alpha.6: + resolution: {integrity: sha512-4L8BZm38BJASswsqruc4c3F0AExYLvp0xq8067e7fIyg4hfwa4zUA+N2idf+eTTjDWevVVdIBfELzJ8b7nvO4Q==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@babel/core': 7.26.0 + '@jest/types': 30.0.0-alpha.6 + '@jridgewell/trace-mapping': 0.3.25 + babel-plugin-istanbul: 7.0.0 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 30.0.0-alpha.6 + jest-regex-util: 30.0.0-alpha.6 + jest-util: 30.0.0-alpha.6 + micromatch: 4.0.8 + pirates: 4.0.6 + slash: 3.0.0 + write-file-atomic: 5.0.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/types@29.6.3: + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 22.10.5 + '@types/yargs': 17.0.31 + chalk: 4.1.2 + dev: true + + /@jest/types@30.0.0-alpha.6: + resolution: {integrity: sha512-qUjAm8uvIR7oExn/Fp7/bvn58HSZng5itQDM9x0vaxXWxxGH/8MDmqX/h7OUBz9ka+KfYRaTxe4Y6wiM8+nphw==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@jest/pattern': 30.0.0-alpha.6 + '@jest/schemas': 30.0.0-alpha.6 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 22.10.5 + '@types/yargs': 17.0.31 + chalk: 4.1.2 + dev: true + + /@jridgewell/gen-mapping@0.3.5: + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.25 + dev: true + + /@jridgewell/resolve-uri@3.1.1: + resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/set-array@1.2.1: + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: true + + /@jridgewell/trace-mapping@0.3.20: + resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /@jridgewell/trace-mapping@0.3.25: + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /@jridgewell/trace-mapping@0.3.9: + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /@metaplex-foundation/beet-solana@0.3.1: + resolution: {integrity: sha512-tgyEl6dvtLln8XX81JyBvWjIiEcjTkUwZbrM5dIobTmoqMuGewSyk9CClno8qsMsFdB5T3jC91Rjeqmu/6xk2g==} + dependencies: + '@metaplex-foundation/beet': 0.7.2 + '@solana/web3.js': 1.95.5 + bs58: 5.0.0 + debug: 4.3.7(supports-color@8.1.1) + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + dev: true + + /@metaplex-foundation/beet-solana@0.4.1: + resolution: {integrity: sha512-/6o32FNUtwK8tjhotrvU/vorP7umBuRFvBZrC6XCk51aKidBHe5LPVPA5AjGPbV3oftMfRuXPNd9yAGeEqeCDQ==} + dependencies: + '@metaplex-foundation/beet': 0.7.2 + '@solana/web3.js': 1.95.4 + bs58: 5.0.0 + debug: 4.3.7(supports-color@8.1.1) + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + dev: false + + /@metaplex-foundation/beet@0.7.2: + resolution: {integrity: sha512-K+g3WhyFxKPc0xIvcIjNyV1eaTVJTiuaHZpig7Xx0MuYRMoJLLvhLTnUXhFdR5Tu2l2QSyKwfyXDgZlzhULqFg==} + dependencies: + ansicolors: 0.3.2 + assert: 2.1.0 + bn.js: 5.2.1 + debug: 4.3.7(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + + /@metaplex-foundation/rustbin@0.3.5: + resolution: {integrity: sha512-m0wkRBEQB/8krwMwKBvFugufZtYwMXiGHud2cTDAv+aGXK4M90y0Hx67/wpu+AqqoQfdV8VM9YezUOHKD+Z5kA==} + dependencies: + debug: 4.3.7(supports-color@8.1.1) + semver: 7.6.3 + text-table: 0.2.0 + toml: 3.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@metaplex-foundation/solita@0.20.1: + resolution: {integrity: sha512-E2bHGzT6wA/sXWBLgJ50ZQNvukPnQlH6kRU6m6lmatJdEOjNWhR1lLI7ESIk/i4ZiSdHZkc/Q6ile8eIlXOzNQ==} + hasBin: true + dependencies: + '@metaplex-foundation/beet': 0.7.2 + '@metaplex-foundation/beet-solana': 0.3.1 + '@metaplex-foundation/rustbin': 0.3.5 + '@solana/web3.js': 1.95.4 + ansi-colors: 4.1.3 + camelcase: 6.3.0 + debug: 4.3.7(supports-color@8.1.1) + js-sha256: 0.9.0 + prettier: 2.8.8 + snake-case: 3.0.4 + spok: 1.5.5 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + dev: true + + /@noble/curves@1.4.2: + resolution: {integrity: sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==} + dependencies: + '@noble/hashes': 1.4.0 + + /@noble/hashes@1.4.0: + resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} + engines: {node: '>= 16'} + + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: true + + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: true + + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.15.0 + dev: true + + /@pkgjs/parseargs@0.11.0: + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + requiresBuild: true + dev: true + optional: true + + /@pkgr/core@0.1.1: + resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + dev: true + + /@rollup/plugin-commonjs@28.0.2(rollup@4.30.1): + resolution: {integrity: sha512-BEFI2EDqzl+vA1rl97IDRZ61AIwGH093d9nz8+dThxJNH8oSoB7MjWvPCX3dkaK1/RCJ/1v/R1XB15FuSs0fQw==} + engines: {node: '>=16.0.0 || 14 >= 14.17'} + peerDependencies: + rollup: ^2.68.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@rollup/pluginutils': 5.1.0(rollup@4.30.1) + commondir: 1.0.1 + estree-walker: 2.0.2 + fdir: 6.3.0(picomatch@4.0.2) + is-reference: 1.2.1 + magic-string: 0.30.10 + picomatch: 4.0.2 + rollup: 4.30.1 + dev: true + + /@rollup/plugin-node-resolve@16.0.0(rollup@4.30.1): + resolution: {integrity: sha512-0FPvAeVUT/zdWoO0jnb/V5BlBsUSNfkIOtFHzMO4H9MOklrmQFY6FduVHKucNb/aTFxvnGhj4MNj/T1oNdDfNg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.78.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@rollup/pluginutils': 5.1.0(rollup@4.30.1) + '@types/resolve': 1.20.2 + deepmerge: 4.3.1 + is-module: 1.0.0 + resolve: 1.22.8 + rollup: 4.30.1 + dev: true + + /@rollup/plugin-typescript@12.1.2(rollup@4.30.1)(tslib@2.8.1)(typescript@5.7.2): + resolution: {integrity: sha512-cdtSp154H5sv637uMr1a8OTWB0L1SWDSm1rDGiyfcGcvQ6cuTs4MDk2BVEBGysUWago4OJN4EQZqOTl/QY3Jgg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.14.0||^3.0.0||^4.0.0 + tslib: '*' + typescript: '>=3.7.0' + peerDependenciesMeta: + rollup: + optional: true + tslib: + optional: true + dependencies: + '@rollup/pluginutils': 5.1.0(rollup@4.30.1) + resolve: 1.22.8 + rollup: 4.30.1 + tslib: 2.8.1 + typescript: 5.7.2 + dev: true + + /@rollup/pluginutils@5.1.0(rollup@4.30.1): + resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} + 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.6 + estree-walker: 2.0.2 + picomatch: 2.3.1 + rollup: 4.30.1 + dev: true + + /@rollup/rollup-android-arm-eabi@4.30.1: + resolution: {integrity: sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q==} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-android-arm64@4.30.1: + resolution: {integrity: sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w==} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-arm64@4.30.1: + resolution: {integrity: sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-x64@4.30.1: + resolution: {integrity: sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-freebsd-arm64@4.30.1: + resolution: {integrity: sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ==} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-freebsd-x64@4.30.1: + resolution: {integrity: sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw==} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm-gnueabihf@4.30.1: + resolution: {integrity: sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm-musleabihf@4.30.1: + resolution: {integrity: sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-gnu@4.30.1: + resolution: {integrity: sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-musl@4.30.1: + resolution: {integrity: sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-loongarch64-gnu@4.30.1: + resolution: {integrity: sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ==} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-powerpc64le-gnu@4.30.1: + resolution: {integrity: sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw==} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-riscv64-gnu@4.30.1: + resolution: {integrity: sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-s390x-gnu@4.30.1: + resolution: {integrity: sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA==} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-gnu@4.30.1: + resolution: {integrity: sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-musl@4.30.1: + resolution: {integrity: sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-arm64-msvc@4.30.1: + resolution: {integrity: sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-ia32-msvc@4.30.1: + resolution: {integrity: sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-x64-msvc@4.30.1: + resolution: {integrity: sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rtsao/scc@1.1.0: + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + dev: true + + /@shikijs/engine-oniguruma@1.24.0: + resolution: {integrity: sha512-Eua0qNOL73Y82lGA4GF5P+G2+VXX9XnuUxkiUuwcxQPH4wom+tE39kZpBFXfUuwNYxHSkrSxpB1p4kyRW0moSg==} + dependencies: + '@shikijs/types': 1.24.0 + '@shikijs/vscode-textmate': 9.3.0 + dev: true + + /@shikijs/types@1.24.0: + resolution: {integrity: sha512-aptbEuq1Pk88DMlCe+FzXNnBZ17LCiLIGWAeCWhoFDzia5Q5Krx3DgnULLiouSdd6+LUM39XwXGppqYE0Ghtug==} + dependencies: + '@shikijs/vscode-textmate': 9.3.0 + '@types/hast': 3.0.4 + dev: true + + /@shikijs/vscode-textmate@9.3.0: + resolution: {integrity: sha512-jn7/7ky30idSkd/O5yDBfAnVt+JJpepofP/POZ1iMOxK59cOfqIgg/Dj0eFsjOTMw+4ycJN0uhZH/Eb0bs/EUA==} + dev: true + + /@sideway/address@4.1.5: + resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} + dependencies: + '@hapi/hoek': 9.3.0 + dev: true + + /@sideway/formula@3.0.1: + resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} + dev: true + + /@sideway/pinpoint@2.0.0: + resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} + dev: true + + /@sinclair/typebox@0.27.8: + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + dev: true + + /@sinclair/typebox@0.33.17: + resolution: {integrity: sha512-75232GRx3wp3P7NP+yc4nRK3XUAnaQShxTAzapgmQrgs0QvSq0/mOJGoZXRpH15cFCKyys+4laCPbBselqJ5Ag==} + dev: true + + /@sinonjs/commons@3.0.0: + resolution: {integrity: sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==} + dependencies: + type-detect: 4.0.8 + dev: true + + /@sinonjs/commons@3.0.1: + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + dependencies: + type-detect: 4.0.8 + dev: true + + /@sinonjs/fake-timers@10.3.0: + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + dependencies: + '@sinonjs/commons': 3.0.0 + dev: true + + /@sinonjs/fake-timers@11.3.1: + resolution: {integrity: sha512-EVJO7nW5M/F5Tur0Rf2z/QoMo+1Ia963RiMtapiQrEWvY0iBUvADo8Beegwjpnle5BHkyHuoxSTW3jF43H1XRA==} + dependencies: + '@sinonjs/commons': 3.0.1 + dev: true + + /@solana/buffer-layout-utils@0.2.0: + resolution: {integrity: sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g==} + engines: {node: '>= 10'} + dependencies: + '@solana/buffer-layout': 4.0.1 + '@solana/web3.js': 1.95.5 + bigint-buffer: 1.1.5 + bignumber.js: 9.1.2 + transitivePeerDependencies: + - bufferutil + - encoding + - utf-8-validate + + /@solana/buffer-layout@4.0.1: + resolution: {integrity: sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==} + engines: {node: '>=5.10'} + dependencies: + buffer: 6.0.3 + + /@solana/codecs-core@2.0.0-rc.1(typescript@5.7.2): + resolution: {integrity: sha512-bauxqMfSs8EHD0JKESaNmNuNvkvHSuN3bbWAF5RjOfDu2PugxHrvRebmYauvSumZ3cTfQ4HJJX6PG5rN852qyQ==} + peerDependencies: + typescript: '>=5' + dependencies: + '@solana/errors': 2.0.0-rc.1(typescript@5.7.2) + typescript: 5.7.2 + dev: true + + /@solana/codecs-data-structures@2.0.0-rc.1(typescript@5.7.2): + resolution: {integrity: sha512-rinCv0RrAVJ9rE/rmaibWJQxMwC5lSaORSZuwjopSUE6T0nb/MVg6Z1siNCXhh/HFTOg0l8bNvZHgBcN/yvXog==} + peerDependencies: + typescript: '>=5' + dependencies: + '@solana/codecs-core': 2.0.0-rc.1(typescript@5.7.2) + '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.7.2) + '@solana/errors': 2.0.0-rc.1(typescript@5.7.2) + typescript: 5.7.2 + dev: true + + /@solana/codecs-numbers@2.0.0-rc.1(typescript@5.7.2): + resolution: {integrity: sha512-J5i5mOkvukXn8E3Z7sGIPxsThRCgSdgTWJDQeZvucQ9PT6Y3HiVXJ0pcWiOWAoQ3RX8e/f4I3IC+wE6pZiJzDQ==} + peerDependencies: + typescript: '>=5' + dependencies: + '@solana/codecs-core': 2.0.0-rc.1(typescript@5.7.2) + '@solana/errors': 2.0.0-rc.1(typescript@5.7.2) + typescript: 5.7.2 + dev: true + + /@solana/codecs-strings@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2): + resolution: {integrity: sha512-9/wPhw8TbGRTt6mHC4Zz1RqOnuPTqq1Nb4EyuvpZ39GW6O2t2Q7Q0XxiB3+BdoEjwA2XgPw6e2iRfvYgqty44g==} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: '>=5' + dependencies: + '@solana/codecs-core': 2.0.0-rc.1(typescript@5.7.2) + '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.7.2) + '@solana/errors': 2.0.0-rc.1(typescript@5.7.2) + fastestsmallesttextencoderdecoder: 1.0.22 + typescript: 5.7.2 + dev: true + + /@solana/codecs@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2): + resolution: {integrity: sha512-qxoR7VybNJixV51L0G1RD2boZTcxmwUWnKCaJJExQ5qNKwbpSyDdWfFJfM5JhGyKe9DnPVOZB+JHWXnpbZBqrQ==} + peerDependencies: + typescript: '>=5' + dependencies: + '@solana/codecs-core': 2.0.0-rc.1(typescript@5.7.2) + '@solana/codecs-data-structures': 2.0.0-rc.1(typescript@5.7.2) + '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.7.2) + '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) + '@solana/options': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + dev: true + + /@solana/errors@2.0.0-rc.1(typescript@5.7.2): + resolution: {integrity: sha512-ejNvQ2oJ7+bcFAYWj225lyRkHnixuAeb7RQCixm+5mH4n1IA4Qya/9Bmfy5RAAHQzxK43clu3kZmL5eF9VGtYQ==} + hasBin: true + peerDependencies: + typescript: '>=5' + dependencies: + chalk: 5.3.0 + commander: 12.1.0 + typescript: 5.7.2 + dev: true + + /@solana/eslint-config-solana@3.0.6(@typescript-eslint/eslint-plugin@8.12.2)(@typescript-eslint/parser@8.12.2)(eslint-plugin-jest@28.10.0)(eslint-plugin-react-hooks@4.6.2)(eslint-plugin-simple-import-sort@12.1.1)(eslint-plugin-sort-keys-fix@1.1.2)(eslint-plugin-typescript-sort-keys@3.3.0)(eslint@8.57.0)(typescript@5.7.2): + resolution: {integrity: sha512-3u024DkukJCfzUfOgN1EmWzVZLaZtgRLJ52FEdQmIG8NYOzLpaIJFgQvjYXWQlnK6ycIcSn/MesHG6sbKkMtTQ==} + peerDependencies: + '@typescript-eslint/eslint-plugin': ^7.0.0 + '@typescript-eslint/parser': ^7.0.0 + eslint: ^8.45.0 + eslint-plugin-jest: ^27.2.3 + eslint-plugin-react-hooks: ^4.6.0 + eslint-plugin-simple-import-sort: ^12.0.0 + eslint-plugin-sort-keys-fix: ^1.1.2 + eslint-plugin-typescript-sort-keys: ^3.2.0 + typescript: ^5.1.6 + dependencies: + '@typescript-eslint/eslint-plugin': 8.12.2(@typescript-eslint/parser@8.12.2)(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/parser': 8.12.2(eslint@8.57.0)(typescript@5.7.2) + eslint: 8.57.0 + eslint-plugin-jest: 28.10.0(@typescript-eslint/eslint-plugin@8.12.2)(eslint@8.57.0)(jest@29.7.0)(typescript@5.7.2) + eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0) + eslint-plugin-simple-import-sort: 12.1.1(eslint@8.57.0) + eslint-plugin-sort-keys-fix: 1.1.2 + eslint-plugin-typescript-sort-keys: 3.3.0(@typescript-eslint/parser@8.12.2)(eslint@8.57.0)(typescript@5.7.2) + typescript: 5.7.2 + dev: true + + /@solana/eslint-config-solana@4.0.0(@eslint/js@9.13.0)(@types/eslint__js@8.42.3)(eslint-plugin-jest@28.10.0)(eslint-plugin-react-hooks@5.0.0)(eslint-plugin-simple-import-sort@12.1.1)(eslint-plugin-sort-keys-fix@1.1.2)(eslint-plugin-typescript-sort-keys@3.3.0)(eslint@9.13.0)(globals@15.11.0)(jest@30.0.0-alpha.6)(typescript-eslint@8.12.2)(typescript@5.7.2): + resolution: {integrity: sha512-kDhd7uOsby+7Gffenn0EBeE692s2cwPe0/Lv1BsdfeniDM4NxBcfIXLQFB8iCCvdFWrO9b+0SMuGrhRHdgTDQQ==} + peerDependencies: + '@eslint/js': ^9.13.0 + '@types/eslint__js': ^8.42.3 + eslint: ^9.13.0 + eslint-plugin-jest: ^28.8.3 + eslint-plugin-react-hooks: ^5.0.0 + eslint-plugin-simple-import-sort: ^12.1.1 + eslint-plugin-sort-keys-fix: ^1.1.2 + eslint-plugin-typescript-sort-keys: ^3.3.0 + globals: ^15.11.0 + jest: ^30.0.0-alpha.6 + typescript: ^5.6 + typescript-eslint: ^8.11.0 + dependencies: + '@eslint/js': 9.13.0 + '@types/eslint__js': 8.42.3 + eslint: 9.13.0 + eslint-plugin-jest: 28.10.0(eslint@9.13.0)(jest@30.0.0-alpha.6)(typescript@5.7.2) + eslint-plugin-react-hooks: 5.0.0(eslint@9.13.0) + eslint-plugin-simple-import-sort: 12.1.1(eslint@9.13.0) + eslint-plugin-sort-keys-fix: 1.1.2 + eslint-plugin-typescript-sort-keys: 3.3.0(@typescript-eslint/parser@8.12.2)(eslint@9.13.0)(typescript@5.7.2) + globals: 15.11.0 + jest: 30.0.0-alpha.6 + typescript: 5.7.2 + typescript-eslint: 8.12.2(eslint@9.13.0)(typescript@5.7.2) + dev: true + + /@solana/options@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2): + resolution: {integrity: sha512-mLUcR9mZ3qfHlmMnREdIFPf9dpMc/Bl66tLSOOWxw4ml5xMT2ohFn7WGqoKcu/UHkT9CrC6+amEdqCNvUqI7AA==} + peerDependencies: + typescript: '>=5' + dependencies: + '@solana/codecs-core': 2.0.0-rc.1(typescript@5.7.2) + '@solana/codecs-data-structures': 2.0.0-rc.1(typescript@5.7.2) + '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.7.2) + '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) + '@solana/errors': 2.0.0-rc.1(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + dev: true + + /@solana/prettier-config-solana@0.0.5(prettier@3.4.2): + resolution: {integrity: sha512-igtLH1QaX5xzSLlqteexRIg9X1QKA03xKYQc2qY1TrMDDhxKXoRZOStQPWdita2FVJzxTGz/tdMGC1vS0biRcg==} + peerDependencies: + prettier: ^3.2.0 + dependencies: + prettier: 3.4.2 + dev: true + + /@solana/spl-token-group@0.0.7(@solana/web3.js@1.95.5)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2): + resolution: {integrity: sha512-V1N/iX7Cr7H0uazWUT2uk27TMqlqedpXHRqqAbVO2gvmJyT0E0ummMEAVQeXZ05ZhQ/xF39DLSdBp90XebWEug==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.95.3 + dependencies: + '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) + '@solana/web3.js': 1.95.5 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - typescript + dev: true + + /@solana/spl-token-metadata@0.1.6(@solana/web3.js@1.95.5)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2): + resolution: {integrity: sha512-7sMt1rsm/zQOQcUWllQX9mD2O6KhSAtY1hFR2hfFwgqfFWzSY9E9GDvFVNYUI1F0iQKcm6HmePU9QbKRXTEBiA==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.95.3 + dependencies: + '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) + '@solana/web3.js': 1.95.5 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - typescript + dev: true + + /@solana/spl-token@0.4.9(@solana/web3.js@1.95.5)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2): + resolution: {integrity: sha512-g3wbj4F4gq82YQlwqhPB0gHFXfgsC6UmyGMxtSLf/BozT/oKd59465DbnlUK8L8EcimKMavxsVAMoLcEdeCicg==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.95.3 + dependencies: + '@solana/buffer-layout': 4.0.1 + '@solana/buffer-layout-utils': 0.2.0 + '@solana/spl-token-group': 0.0.7(@solana/web3.js@1.95.5)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) + '@solana/spl-token-metadata': 0.1.6(@solana/web3.js@1.95.5)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2) + '@solana/web3.js': 1.95.5 + buffer: 6.0.3 + transitivePeerDependencies: + - bufferutil + - encoding + - fastestsmallesttextencoderdecoder + - typescript + - utf-8-validate + dev: true + + /@solana/web3.js@1.95.4: + resolution: {integrity: sha512-sdewnNEA42ZSMxqkzdwEWi6fDgzwtJHaQa5ndUGEJYtoOnM6X5cvPmjoTUp7/k7bRrVAxfBgDnvQQHD6yhlLYw==} + dependencies: + '@babel/runtime': 7.25.0 + '@noble/curves': 1.4.2 + '@noble/hashes': 1.4.0 + '@solana/buffer-layout': 4.0.1 + agentkeepalive: 4.5.0 + bigint-buffer: 1.1.5 + bn.js: 5.2.1 + borsh: 0.7.0 + bs58: 4.0.1 + buffer: 6.0.3 + fast-stable-stringify: 1.0.0 + jayson: 4.1.1 + node-fetch: 2.7.0 + rpc-websockets: 9.0.2 + superstruct: 2.0.2 + transitivePeerDependencies: + - bufferutil + - encoding + - utf-8-validate + + /@solana/web3.js@1.95.5: + resolution: {integrity: sha512-hU9cBrbg1z6gEjLH9vwIckGBVB78Ijm0iZFNk4ocm5OD82piPwuk3MeQ1rfiKD9YQtr95krrcaopb49EmQJlRg==} + dependencies: + '@babel/runtime': 7.25.0 + '@noble/curves': 1.4.2 + '@noble/hashes': 1.4.0 + '@solana/buffer-layout': 4.0.1 + agentkeepalive: 4.5.0 + bigint-buffer: 1.1.5 + bn.js: 5.2.1 + borsh: 0.7.0 + bs58: 4.0.1 + buffer: 6.0.3 + fast-stable-stringify: 1.0.0 + jayson: 4.1.1 + node-fetch: 2.7.0 + rpc-websockets: 9.0.2 + superstruct: 2.0.2 + transitivePeerDependencies: + - bufferutil + - encoding + - utf-8-validate + + /@swc/helpers@0.5.11: + resolution: {integrity: sha512-YNlnKRWF2sVojTpIyzwou9XoTNbzbzONwRhOoniEioF1AtaitTvVZblaQRrAzChWQ1bLYyYSWzM18y4WwgzJ+A==} + dependencies: + tslib: 2.8.1 + + /@tsconfig/node10@1.0.9: + resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} + dev: true + + /@tsconfig/node12@1.0.11: + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + dev: true + + /@tsconfig/node14@1.0.3: + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + dev: true + + /@tsconfig/node16@1.0.4: + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + dev: true + + /@types/babel__core@7.20.4: + resolution: {integrity: sha512-mLnSC22IC4vcWiuObSRjrLd9XcBTGf59vUSoq2jkQDJ/QQ8PMI9rSuzE+aEV8karUMbskw07bKYoUJCKTUaygg==} + dependencies: + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 + '@types/babel__generator': 7.6.7 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.4 + dev: true + + /@types/babel__generator@7.6.7: + resolution: {integrity: sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==} + dependencies: + '@babel/types': 7.26.0 + dev: true + + /@types/babel__template@7.4.4: + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + dependencies: + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 + dev: true + + /@types/babel__traverse@7.20.4: + resolution: {integrity: sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==} + dependencies: + '@babel/types': 7.26.0 + dev: true + + /@types/bn.js@5.1.6: + resolution: {integrity: sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w==} + dependencies: + '@types/node': 22.10.5 + dev: true + + /@types/chai-as-promised@8.0.1: + resolution: {integrity: sha512-dAlDhLjJlABwAVYObo9TPWYTRg9NaQM5CXeaeJYcYAkvzUf0JRLIiog88ao2Wqy/20WUnhbbUZcgvngEbJ3YXQ==} + dependencies: + '@types/chai': 5.0.1 + dev: true + + /@types/chai@5.0.1: + resolution: {integrity: sha512-5T8ajsg3M/FOncpLYW7sdOcD6yf4+722sze/tc4KQV0P8Z2rAr3SAuHCIkYmYpt8VbcQlnz8SxlOlPQYefe4cA==} + dependencies: + '@types/deep-eql': 4.0.2 + dev: true + + /@types/connect@3.4.38: + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + dependencies: + '@types/node': 22.10.5 + + /@types/deep-eql@4.0.2: + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + dev: true + + /@types/eslint@8.56.7: + resolution: {integrity: sha512-SjDvI/x3zsZnOkYZ3lCt9lOZWZLB2jIlNKz+LBgCtDurK0JZcwucxYHn1w2BJkD34dgX9Tjnak0txtq4WTggEA==} + dependencies: + '@types/estree': 1.0.5 + '@types/json-schema': 7.0.15 + dev: true + + /@types/eslint__js@8.42.3: + resolution: {integrity: sha512-alfG737uhmPdnvkrLdZLcEKJ/B8s9Y4hrZ+YAdzUeoArBlSUERA2E87ROfOaS4jd/C45fzOoZzidLc1IPwLqOw==} + dependencies: + '@types/eslint': 8.56.7 + dev: true + + /@types/estree@1.0.5: + resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + dev: true + + /@types/estree@1.0.6: + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + dev: true + + /@types/graceful-fs@4.1.9: + resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + dependencies: + '@types/node': 22.10.5 + dev: true + + /@types/hast@3.0.4: + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + dependencies: + '@types/unist': 3.0.3 + dev: true + + /@types/istanbul-lib-coverage@2.0.6: + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + dev: true + + /@types/istanbul-lib-report@3.0.3: + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + dev: true + + /@types/istanbul-reports@3.0.4: + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + dependencies: + '@types/istanbul-lib-report': 3.0.3 + dev: true + + /@types/jest@29.5.14: + resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==} + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + dev: true + + /@types/json-schema@7.0.15: + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + dev: true + + /@types/json5@0.0.29: + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + dev: true + + /@types/mocha@10.0.10: + resolution: {integrity: sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==} + dev: true + + /@types/node-fetch@2.6.12: + resolution: {integrity: sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==} + dependencies: + '@types/node': 22.10.5 + form-data: 4.0.0 + dev: true + + /@types/node@12.20.55: + resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} + + /@types/node@22.10.5: + resolution: {integrity: sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==} + dependencies: + undici-types: 6.20.0 + + /@types/resolve@1.20.2: + resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} + dev: true + + /@types/semver@7.5.8: + resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} + dev: true + + /@types/stack-utils@2.0.3: + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + dev: true + + /@types/unist@3.0.3: + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + dev: true + + /@types/uuid@8.3.4: + resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} + + /@types/ws@7.4.7: + resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} + dependencies: + '@types/node': 22.10.5 + + /@types/ws@8.5.10: + resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==} + dependencies: + '@types/node': 22.10.5 + + /@types/yargs-parser@21.0.3: + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + dev: true + + /@types/yargs@17.0.31: + resolution: {integrity: sha512-bocYSx4DI8TmdlvxqGpVNXOgCNR1Jj0gNPhhAY+iz1rgKDAaYrAYdFYnhDV1IFuiuVc9HkOwyDcFxaTElF3/wg==} + dependencies: + '@types/yargs-parser': 21.0.3 + dev: true + + /@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2)(eslint@8.57.0)(typescript@5.7.2): + resolution: {integrity: sha512-gQxbxM8mcxBwaEmWdtLCIGLfixBMHhQjBqR8sVWNTPpcj45WlYL2IObS/DNMLH1DBP0n8qz+aiiLTGfopPEebw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.12.2(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/scope-manager': 8.12.2 + '@typescript-eslint/type-utils': 8.12.2(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/utils': 8.12.2(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/visitor-keys': 8.12.2 + eslint: 8.57.0 + graphemer: 1.4.0 + ignore: 5.3.1 + natural-compare: 1.4.0 + ts-api-utils: 1.3.0(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2)(eslint@9.13.0)(typescript@5.7.2): + resolution: {integrity: sha512-gQxbxM8mcxBwaEmWdtLCIGLfixBMHhQjBqR8sVWNTPpcj45WlYL2IObS/DNMLH1DBP0n8qz+aiiLTGfopPEebw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.12.2(eslint@9.13.0)(typescript@5.7.2) + '@typescript-eslint/scope-manager': 8.12.2 + '@typescript-eslint/type-utils': 8.12.2(eslint@9.13.0)(typescript@5.7.2) + '@typescript-eslint/utils': 8.12.2(eslint@9.13.0)(typescript@5.7.2) + '@typescript-eslint/visitor-keys': 8.12.2 + eslint: 9.13.0 + graphemer: 1.4.0 + ignore: 5.3.1 + natural-compare: 1.4.0 + ts-api-utils: 1.3.0(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/eslint-plugin@8.4.0(@typescript-eslint/parser@8.4.0)(eslint@8.57.0)(typescript@5.7.2): + resolution: {integrity: sha512-rg8LGdv7ri3oAlenMACk9e+AR4wUV0yrrG+XKsGKOK0EVgeEDqurkXMPILG2836fW4ibokTB5v4b6Z9+GYQDEw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.10.0 + '@typescript-eslint/parser': 8.4.0(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/scope-manager': 8.4.0 + '@typescript-eslint/type-utils': 8.4.0(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/utils': 8.4.0(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/visitor-keys': 8.4.0 + eslint: 8.57.0 + graphemer: 1.4.0 + ignore: 5.3.1 + natural-compare: 1.4.0 + ts-api-utils: 1.3.0(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/experimental-utils@5.62.0(eslint@8.57.0)(typescript@5.7.2): + resolution: {integrity: sha512-RTXpeB3eMkpoclG3ZHft6vG/Z30azNHuqY6wKPBHlVMZFuEvrtlEDe8gMqDb+SO+9hjC/pLekeSCryf9vMZlCw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.7.2) + eslint: 8.57.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/experimental-utils@5.62.0(eslint@9.13.0)(typescript@5.7.2): + resolution: {integrity: sha512-RTXpeB3eMkpoclG3ZHft6vG/Z30azNHuqY6wKPBHlVMZFuEvrtlEDe8gMqDb+SO+9hjC/pLekeSCryf9vMZlCw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@typescript-eslint/utils': 5.62.0(eslint@9.13.0)(typescript@5.7.2) + eslint: 9.13.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/parser@8.12.2(eslint@8.57.0)(typescript@5.7.2): + resolution: {integrity: sha512-MrvlXNfGPLH3Z+r7Tk+Z5moZAc0dzdVjTgUgwsdGweH7lydysQsnSww3nAmsq8blFuRD5VRlAr9YdEFw3e6PBw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 8.12.2 + '@typescript-eslint/types': 8.12.2 + '@typescript-eslint/typescript-estree': 8.12.2(typescript@5.7.2) + '@typescript-eslint/visitor-keys': 8.12.2 + debug: 4.3.7(supports-color@8.1.1) + eslint: 8.57.0 + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.7.2): + resolution: {integrity: sha512-MrvlXNfGPLH3Z+r7Tk+Z5moZAc0dzdVjTgUgwsdGweH7lydysQsnSww3nAmsq8blFuRD5VRlAr9YdEFw3e6PBw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 8.12.2 + '@typescript-eslint/types': 8.12.2 + '@typescript-eslint/typescript-estree': 8.12.2(typescript@5.7.2) + '@typescript-eslint/visitor-keys': 8.12.2 + debug: 4.3.7(supports-color@8.1.1) + eslint: 9.13.0 + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@8.4.0(eslint@8.57.0)(typescript@5.7.2): + resolution: {integrity: sha512-NHgWmKSgJk5K9N16GIhQ4jSobBoJwrmURaLErad0qlLjrpP5bECYg+wxVTGlGZmJbU03jj/dfnb6V9bw+5icsA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 8.4.0 + '@typescript-eslint/types': 8.4.0 + '@typescript-eslint/typescript-estree': 8.4.0(typescript@5.7.2) + '@typescript-eslint/visitor-keys': 8.4.0 + debug: 4.3.6 + eslint: 8.57.0 + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@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.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 + dev: true + + /@typescript-eslint/scope-manager@8.12.2: + resolution: {integrity: sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@typescript-eslint/types': 8.12.2 + '@typescript-eslint/visitor-keys': 8.12.2 + dev: true + + /@typescript-eslint/scope-manager@8.4.0: + resolution: {integrity: sha512-n2jFxLeY0JmKfUqy3P70rs6vdoPjHK8P/w+zJcV3fk0b0BwRXC/zxRTEnAsgYT7MwdQDt/ZEbtdzdVC+hcpF0A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@typescript-eslint/types': 8.4.0 + '@typescript-eslint/visitor-keys': 8.4.0 + dev: true + + /@typescript-eslint/type-utils@8.12.2(eslint@8.57.0)(typescript@5.7.2): + resolution: {integrity: sha512-bwuU4TAogPI+1q/IJSKuD4shBLc/d2vGcRT588q+jzayQyjVK2X6v/fbR4InY2U2sgf8MEvVCqEWUzYzgBNcGQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 8.12.2(typescript@5.7.2) + '@typescript-eslint/utils': 8.12.2(eslint@8.57.0)(typescript@5.7.2) + debug: 4.4.0 + ts-api-utils: 1.3.0(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - eslint + - supports-color + dev: true + + /@typescript-eslint/type-utils@8.12.2(eslint@9.13.0)(typescript@5.7.2): + resolution: {integrity: sha512-bwuU4TAogPI+1q/IJSKuD4shBLc/d2vGcRT588q+jzayQyjVK2X6v/fbR4InY2U2sgf8MEvVCqEWUzYzgBNcGQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 8.12.2(typescript@5.7.2) + '@typescript-eslint/utils': 8.12.2(eslint@9.13.0)(typescript@5.7.2) + debug: 4.4.0 + ts-api-utils: 1.3.0(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - eslint + - supports-color + dev: true + + /@typescript-eslint/type-utils@8.4.0(eslint@8.57.0)(typescript@5.7.2): + resolution: {integrity: sha512-pu2PAmNrl9KX6TtirVOrbLPLwDmASpZhK/XU7WvoKoCUkdtq9zF7qQ7gna0GBZFN0hci0vHaSusiL2WpsQk37A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 8.4.0(typescript@5.7.2) + '@typescript-eslint/utils': 8.4.0(eslint@8.57.0)(typescript@5.7.2) + debug: 4.4.0 + ts-api-utils: 1.3.0(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - eslint + - supports-color + dev: true + + /@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/types@8.12.2: + resolution: {integrity: sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true + + /@typescript-eslint/types@8.4.0: + resolution: {integrity: sha512-T1RB3KQdskh9t3v/qv7niK6P8yvn7ja1mS7QK7XfRVL6wtZ8/mFs/FHf4fKvTA0rKnqnYxl/uHFNbnEt0phgbw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true + + /@typescript-eslint/typescript-estree@5.62.0(typescript@5.7.2): + resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 + debug: 4.4.0 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.6.3 + tsutils: 3.21.0(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/typescript-estree@8.12.2(typescript@5.7.2): + resolution: {integrity: sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 8.12.2 + '@typescript-eslint/visitor-keys': 8.12.2 + debug: 4.4.0 + fast-glob: 3.3.2 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.6.3 + ts-api-utils: 1.3.0(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/typescript-estree@8.4.0(typescript@5.7.2): + resolution: {integrity: sha512-kJ2OIP4dQw5gdI4uXsaxUZHRwWAGpREJ9Zq6D5L0BweyOrWsL6Sz0YcAZGWhvKnH7fm1J5YFE1JrQL0c9dd53A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 8.4.0 + '@typescript-eslint/visitor-keys': 8.4.0 + debug: 4.4.0 + fast-glob: 3.3.2 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.6.3 + ts-api-utils: 1.3.0(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/utils@5.62.0(eslint@8.57.0)(typescript@5.7.2): + resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@types/json-schema': 7.0.15 + '@types/semver': 7.5.8 + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.7.2) + eslint: 8.57.0 + eslint-scope: 5.1.1 + semver: 7.6.3 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/utils@5.62.0(eslint@9.13.0)(typescript@5.7.2): + resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@9.13.0) + '@types/json-schema': 7.0.15 + '@types/semver': 7.5.8 + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.7.2) + eslint: 9.13.0 + eslint-scope: 5.1.1 + semver: 7.6.3 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/utils@8.12.2(eslint@8.57.0)(typescript@5.7.2): + resolution: {integrity: sha512-UTTuDIX3fkfAz6iSVa5rTuSfWIYZ6ATtEocQ/umkRSyC9O919lbZ8dcH7mysshrCdrAM03skJOEYaBugxN+M6A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@typescript-eslint/scope-manager': 8.12.2 + '@typescript-eslint/types': 8.12.2 + '@typescript-eslint/typescript-estree': 8.12.2(typescript@5.7.2) + eslint: 8.57.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/utils@8.12.2(eslint@9.13.0)(typescript@5.7.2): + resolution: {integrity: sha512-UTTuDIX3fkfAz6iSVa5rTuSfWIYZ6ATtEocQ/umkRSyC9O919lbZ8dcH7mysshrCdrAM03skJOEYaBugxN+M6A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@9.13.0) + '@typescript-eslint/scope-manager': 8.12.2 + '@typescript-eslint/types': 8.12.2 + '@typescript-eslint/typescript-estree': 8.12.2(typescript@5.7.2) + eslint: 9.13.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/utils@8.4.0(eslint@8.57.0)(typescript@5.7.2): + resolution: {integrity: sha512-swULW8n1IKLjRAgciCkTCafyTHHfwVQFt8DovmaF69sKbOxTSFMmIZaSHjqO9i/RV0wIblaawhzvtva8Nmm7lQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@typescript-eslint/scope-manager': 8.4.0 + '@typescript-eslint/types': 8.4.0 + '@typescript-eslint/typescript-estree': 8.4.0(typescript@5.7.2) + eslint: 8.57.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@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.62.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@typescript-eslint/visitor-keys@8.12.2: + resolution: {integrity: sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@typescript-eslint/types': 8.12.2 + eslint-visitor-keys: 3.4.3 + dev: true + + /@typescript-eslint/visitor-keys@8.4.0: + resolution: {integrity: sha512-zTQD6WLNTre1hj5wp09nBIDiOc2U5r/qmzo7wxPn4ZgAjHql09EofqhF9WF+fZHzL5aCyaIpPcT2hyxl73kr9A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@typescript-eslint/types': 8.4.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@ungap/structured-clone@1.2.0: + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + 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 + + /acorn-jsx@5.3.2(acorn@7.4.1): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 7.4.1 + dev: true + + /acorn-jsx@5.3.2(acorn@8.11.3): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.11.3 + dev: true + + /acorn-jsx@5.3.2(acorn@8.14.0): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.14.0 + dev: true + + /acorn-walk@8.3.4: + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + engines: {node: '>=0.4.0'} + dependencies: + acorn: 8.14.0 + dev: true + + /acorn@7.4.1: + resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /acorn@8.11.3: + resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /agentkeepalive@4.5.0: + resolution: {integrity: sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==} + engines: {node: '>= 8.0.0'} + dependencies: + humanize-ms: 1.2.1 + + /ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + 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'} + dependencies: + type-fest: 0.21.3 + dev: true + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: true + + /ansi-regex@6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + engines: {node: '>=12'} + dev: true + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: true + + /ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + dev: true + + /ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + dev: true + + /ansicolors@0.3.2: + resolution: {integrity: sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==} + + /anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + dev: true + + /arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + dev: true + + /arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + dev: true + + /argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + dependencies: + sprintf-js: 1.0.3 + dev: true + + /argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: true + + /array-buffer-byte-length@1.0.1: + resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + is-array-buffer: 3.0.4 + dev: true + + /array-includes@3.1.8: + resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.4 + is-string: 1.0.7 + dev: true + + /array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + dev: true + + /array.prototype.findlastindex@1.2.5: + resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-shim-unscopables: 1.0.2 + dev: true + + /array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + dev: true + + /array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + dev: true + + /arraybuffer.prototype.slice@1.0.3: + resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.1 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + is-array-buffer: 3.0.4 + is-shared-array-buffer: 1.0.3 + dev: true + + /assert@2.1.0: + resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==} + dependencies: + call-bind: 1.0.7 + is-nan: 1.3.2 + object-is: 1.1.6 + object.assign: 4.1.5 + util: 0.12.5 + + /async@3.2.5: + resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} + dev: true + + /asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + dev: true + + /available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + dependencies: + possible-typed-array-names: 1.0.0 + + /axios@1.7.7(debug@4.4.0): + resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} + dependencies: + follow-redirects: 1.15.9(debug@4.4.0) + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + dev: true + + /babel-jest@29.7.0(@babel/core@7.26.0): + resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.8.0 + dependencies: + '@babel/core': 7.26.0 + '@jest/transform': 29.7.0 + '@types/babel__core': 7.20.4 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 29.6.3(@babel/core@7.26.0) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-jest@30.0.0-alpha.6(@babel/core@7.26.0): + resolution: {integrity: sha512-WOQkqpBz2q8d/AT6D6rZXW5xnKHDmk3kIukaXlzUyoBBIvLh1SEvi2RGS4fboEtS0kNkyL+zf1rSfkt5OCIgmw==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + peerDependencies: + '@babel/core': ^7.11.0 + dependencies: + '@babel/core': 7.26.0 + '@jest/transform': 30.0.0-alpha.6 + '@types/babel__core': 7.20.4 + babel-plugin-istanbul: 7.0.0 + babel-preset-jest: 30.0.0-alpha.6(@babel/core@7.26.0) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-istanbul@6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} + dependencies: + '@babel/helper-plugin-utils': 7.22.5 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 5.2.1 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-istanbul@7.0.0: + resolution: {integrity: sha512-C5OzENSx/A+gt7t4VH1I2XsflxyPUmXRFPKBxt33xncdOmq7oROVM3bZv9Ysjjkv8OJYDMa+tKuKMvqU/H3xdw==} + engines: {node: '>=12'} + dependencies: + '@babel/helper-plugin-utils': 7.22.5 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 6.0.3 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-jest-hoist@29.6.3: + resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/template': 7.25.9 + '@babel/types': 7.26.0 + '@types/babel__core': 7.20.4 + '@types/babel__traverse': 7.20.4 + dev: true + + /babel-plugin-jest-hoist@30.0.0-alpha.6: + resolution: {integrity: sha512-e/aPv0pmnvJqXM5SfCBpyMwZFEZrKW1Mb4unwTkxewk6/0TjwBk6l3B3F9H9OKZ3ErhkH4b+Epd3IIM5E53I2g==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@babel/template': 7.25.9 + '@babel/types': 7.26.0 + '@types/babel__core': 7.20.4 + dev: true + + /babel-preset-current-node-syntax@1.0.1(@babel/core@7.26.0): + resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.26.0 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.26.0) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.26.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.26.0) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.26.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.26.0) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.26.0) + dev: true + + /babel-preset-jest@29.6.3(@babel/core@7.26.0): + resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.26.0 + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.26.0) + dev: true + + /babel-preset-jest@30.0.0-alpha.6(@babel/core@7.26.0): + resolution: {integrity: sha512-Xsis7RI2oT2zlyCIEzMtjDiES0wKoQxTUo5BGzx1q3ZemnDE1/7xTC4/lI4eBLmAtwk/hpZLRYwltvbQEvyRWw==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + peerDependencies: + '@babel/core': ^7.11.0 + dependencies: + '@babel/core': 7.26.0 + babel-plugin-jest-hoist: 30.0.0-alpha.6 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.26.0) + dev: true + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /base-x@3.0.9: + resolution: {integrity: sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==} + dependencies: + safe-buffer: 5.2.1 + + /base-x@4.0.0: + resolution: {integrity: sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==} + + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + /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 + + /bignumber.js@9.1.2: + resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==} + + /binary-extensions@2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} + dev: true + + /bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + dependencies: + file-uri-to-path: 1.0.0 + + /bluebird@3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + dev: true + + /bn.js@5.2.1: + resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} + + /borsh@0.7.0: + resolution: {integrity: sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==} + dependencies: + bn.js: 5.2.1 + bs58: 4.0.1 + text-encoding-utf-8: 1.0.2 + + /borsh@2.0.0: + resolution: {integrity: sha512-kc9+BgR3zz9+cjbwM8ODoUB4fs3X3I5A/HtX7LZKxCLaMrEeDFoBpnhZY//DTS1VZBSs6S5v46RZRbZjRFspEg==} + dev: false + + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true + + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + dev: true + + /braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.1.1 + dev: true + + /browser-stdout@1.3.1: + resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} + dev: true + + /browserslist@4.24.2: + resolution: {integrity: sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001676 + electron-to-chromium: 1.5.50 + node-releases: 2.0.18 + update-browserslist-db: 1.1.1(browserslist@4.24.2) + dev: true + + /bs-logger@0.2.6: + resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} + engines: {node: '>= 6'} + dependencies: + fast-json-stable-stringify: 2.1.0 + dev: true + + /bs58@4.0.1: + resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} + dependencies: + base-x: 3.0.9 + + /bs58@5.0.0: + resolution: {integrity: sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==} + dependencies: + base-x: 4.0.0 + + /bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + dependencies: + node-int64: 0.4.0 + dev: true + + /buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: true + + /buffer-layout@1.2.2: + resolution: {integrity: sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==} + engines: {node: '>=4.5'} + dev: true + + /buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + /bufferutil@4.0.8: + resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==} + engines: {node: '>=6.14.2'} + requiresBuild: true + dependencies: + node-gyp-build: 4.6.1 + + /call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + set-function-length: 1.2.2 + + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + dev: true + + /camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + dev: true + + /camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + dev: true + + /caniuse-lite@1.0.30001676: + resolution: {integrity: sha512-Qz6zwGCiPghQXGJvgQAem79esjitvJ+CxSbSQkW9H/UX5hg8XM88d4lp2W+MEQ81j+Hip58Il+jGVdazk1z9cw==} + dev: true + + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + + /chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: true + + /char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + dev: true + + /check-more-types@2.24.0: + resolution: {integrity: sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==} + engines: {node: '>= 0.8.0'} + dev: true + + /chokidar@3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + dev: true + + /ci-info@4.0.0: + resolution: {integrity: sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==} + engines: {node: '>=8'} + dev: true + + /cjs-module-lexer@1.2.3: + resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} + dev: true + + /cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + + /cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + + /co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + dev: true + + /collect-v8-coverage@1.0.2: + resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + dev: true + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: true + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true + + /combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + dev: true + + /commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + dev: true + + /commander@13.0.0: + resolution: {integrity: sha512-oPYleIY8wmTVzkvQq10AEok6YcTC4sRUBl8F9gVuwchGVUCTbl/vhLTaQqutuuySYOsu8YTgV+OxKc/8Yvx+mQ==} + engines: {node: '>=18'} + dev: true + + /commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + /commander@5.1.0: + resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} + engines: {node: '>= 6'} + dev: true + + /commondir@1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + dev: true + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true + + /convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + dev: true + + /create-jest@29.7.0(@types/node@22.10.5)(ts-node@10.9.2): + resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@22.10.5)(ts-node@10.9.2) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + dev: true + + /create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + dev: true + + /cross-fetch@3.1.8: + resolution: {integrity: sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==} + dependencies: + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + dev: true + + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true + + /crypto-hash@1.3.0: + resolution: {integrity: sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg==} + engines: {node: '>=8'} + dev: true + + /data-view-buffer@1.0.1: + resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + dev: true + + /data-view-byte-length@1.0.1: + resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + dev: true + + /data-view-byte-offset@1.0.0: + resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + dev: true + + /debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + dev: true + + /debug@4.3.6: + resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: true + + /debug@4.3.7(supports-color@8.1.1): + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + supports-color: 8.1.1 + + /debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + dev: true + + /decamelize@4.0.0: + resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} + engines: {node: '>=10'} + dev: true + + /dedent@1.5.1: + resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + dev: true + + /deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + dev: true + + /deepmerge-ts@7.1.3: + resolution: {integrity: sha512-qCSH6I0INPxd9Y1VtAiLpnYvz5O//6rCfJXKk0z66Up9/VOSr+1yS8XSKA5IWRxjocFGlzPyaZYe+jxq7OOLtQ==} + engines: {node: '>=16.0.0'} + dev: true + + /deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + dev: true + + /define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + gopd: 1.0.1 + + /define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + /delay@5.0.0: + resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==} + engines: {node: '>=10'} + + /delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dev: true + + /detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + dev: true + + /diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true + + /diff-sequences@30.0.0-alpha.6: + resolution: {integrity: sha512-DVGt3/yzbneMUTuupsMqyfSXMnU2fE0lVsC9uFsJmRpluvSi7ZhrS0GX5tnMna6Ta788FGfOUx+irI/+cAZ4EA==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dev: true + + /diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + dev: true + + /diff@5.2.0: + resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} + engines: {node: '>=0.3.1'} + dev: true + + /dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: true + + /doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /dot-case@3.0.4: + resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + dev: true + + /dotenv@16.0.3: + resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} + engines: {node: '>=12'} + dev: true + + /duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + dev: true + + /eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true + + /ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} + engines: {node: '>=0.10.0'} + hasBin: true + dependencies: + jake: 10.9.1 + dev: true + + /electron-to-chromium@1.5.50: + resolution: {integrity: sha512-eMVObiUQ2LdgeO1F/ySTXsvqvxb6ZH2zPGaMYsWzRDdOddUa77tdmI0ltg+L16UpbWdhPmuF3wIQYyQq65WfZw==} + dev: true + + /email-addresses@5.0.0: + resolution: {integrity: sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==} + dev: true + + /emittery@0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + dev: true + + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: true + + /emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true + + /entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + dev: true + + /error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + dependencies: + is-arrayish: 0.2.1 + dev: true + + /es-abstract@1.23.3: + resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.1 + arraybuffer.prototype.slice: 1.0.3 + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + data-view-buffer: 1.0.1 + data-view-byte-length: 1.0.1 + data-view-byte-offset: 1.0.0 + es-define-property: 1.0.0 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-set-tostringtag: 2.0.3 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.4 + get-symbol-description: 1.0.2 + globalthis: 1.0.3 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + internal-slot: 1.0.7 + is-array-buffer: 3.0.4 + is-callable: 1.2.7 + is-data-view: 1.0.1 + is-negative-zero: 2.0.3 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.3 + is-string: 1.0.7 + is-typed-array: 1.1.13 + is-weakref: 1.0.2 + object-inspect: 1.13.1 + object-keys: 1.1.1 + object.assign: 4.1.5 + regexp.prototype.flags: 1.5.2 + safe-array-concat: 1.1.2 + safe-regex-test: 1.0.3 + string.prototype.trim: 1.2.9 + string.prototype.trimend: 1.0.8 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.2 + typed-array-byte-length: 1.0.1 + typed-array-byte-offset: 1.0.2 + typed-array-length: 1.0.6 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.15 + dev: true + + /es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.4 + + /es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + /es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + dev: true + + /es-set-tostringtag@2.0.3: + resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.4 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + dev: true + + /es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + dependencies: + hasown: 2.0.2 + dev: true + + /es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} + dependencies: + is-callable: 1.2.7 + is-date-object: 1.0.5 + is-symbol: 1.0.4 + dev: true + + /es6-promise@4.2.8: + resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} + + /es6-promisify@5.0.0: + resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} + dependencies: + es6-promise: 4.2.8 + + /escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + dev: true + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + dev: true + + /escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + dev: true + + /escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: true + + /escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + dev: true + + /eslint-config-prettier@9.1.0(eslint@9.13.0): + resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + dependencies: + eslint: 9.13.0 + dev: true + + /eslint-config-turbo@2.3.3(eslint@8.57.0): + resolution: {integrity: sha512-cM9wSBYowQIrjx2MPCzFE6jTnG4vpTPJKZ/O+Ps3CqrmGK/wtNOsY6WHGMwLtKY/nNbgRahAJH6jGVF6k2coOg==} + peerDependencies: + eslint: '>6.6.0' + dependencies: + eslint: 8.57.0 + eslint-plugin-turbo: 2.3.3(eslint@8.57.0) + dev: true + + /eslint-config-turbo@2.3.3(eslint@9.13.0): + resolution: {integrity: sha512-cM9wSBYowQIrjx2MPCzFE6jTnG4vpTPJKZ/O+Ps3CqrmGK/wtNOsY6WHGMwLtKY/nNbgRahAJH6jGVF6k2coOg==} + peerDependencies: + eslint: '>6.6.0' + dependencies: + eslint: 9.13.0 + eslint-plugin-turbo: 2.3.3(eslint@9.13.0) + dev: true + + /eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + dependencies: + debug: 3.2.7 + is-core-module: 2.15.1 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-module-utils@2.12.0(@typescript-eslint/parser@8.12.2)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): + resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + '@typescript-eslint/parser': 8.12.2(eslint@8.57.0)(typescript@5.7.2) + debug: 3.2.7 + eslint: 8.57.0 + eslint-import-resolver-node: 0.3.9 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-module-utils@2.12.0(@typescript-eslint/parser@8.4.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): + resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + '@typescript-eslint/parser': 8.4.0(eslint@8.57.0)(typescript@5.7.2) + debug: 3.2.7 + eslint: 8.57.0 + eslint-import-resolver-node: 0.3.9 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-eslint-comments@3.2.0(eslint@8.57.0): + resolution: {integrity: sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==} + engines: {node: '>=6.5.0'} + peerDependencies: + eslint: '>=4.19.1' + dependencies: + escape-string-regexp: 1.0.5 + eslint: 8.57.0 + ignore: 5.2.4 + dev: true + + /eslint-plugin-functional@7.2.1(eslint@8.57.0)(typescript@5.7.2): + resolution: {integrity: sha512-cHhUmrOSde6pGuUJ6guuuJQKudbEMpk6DtgHLjStwjbI/NnzWp2jIizaLF1U1zVDJBjJHfJ1HeqYiDyiCF34CQ==} + engines: {node: '>=v18.18.0'} + peerDependencies: + eslint: ^9.0.0 + typescript: '>=4.7.4' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/utils': 8.12.2(eslint@8.57.0)(typescript@5.7.2) + deepmerge-ts: 7.1.3 + escape-string-regexp: 5.0.0 + eslint: 8.57.0 + is-immutable-type: 5.0.0(eslint@8.57.0)(typescript@5.7.2) + ts-api-utils: 2.0.0(typescript@5.7.2) + ts-declaration-location: 1.0.4(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.12.2)(eslint@8.57.0): + resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + dependencies: + '@rtsao/scc': 1.1.0 + '@typescript-eslint/parser': 8.12.2(eslint@8.57.0)(typescript@5.7.2) + array-includes: 3.1.8 + array.prototype.findlastindex: 1.2.5 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 8.57.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.12.2)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) + hasown: 2.0.2 + is-core-module: 2.15.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.0 + semver: 6.3.1 + string.prototype.trimend: 1.0.8 + tsconfig-paths: 3.15.0 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + dev: true + + /eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.4.0)(eslint@8.57.0): + resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + dependencies: + '@rtsao/scc': 1.1.0 + '@typescript-eslint/parser': 8.4.0(eslint@8.57.0)(typescript@5.7.2) + array-includes: 3.1.8 + array.prototype.findlastindex: 1.2.5 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 8.57.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.4.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) + hasown: 2.0.2 + is-core-module: 2.15.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.0 + semver: 6.3.1 + string.prototype.trimend: 1.0.8 + tsconfig-paths: 3.15.0 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + dev: true + + /eslint-plugin-jest@28.10.0(@typescript-eslint/eslint-plugin@8.12.2)(eslint@8.57.0)(jest@29.7.0)(typescript@5.7.2): + resolution: {integrity: sha512-hyMWUxkBH99HpXT3p8hc7REbEZK3D+nk8vHXGgpB+XXsi0gO4PxMSP+pjfUzb67GnV9yawV9a53eUmcde1CCZA==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + peerDependencies: + '@typescript-eslint/eslint-plugin': ^6.0.0 || ^7.0.0 || ^8.0.0 + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 + jest: '*' + peerDependenciesMeta: + '@typescript-eslint/eslint-plugin': + optional: true + jest: + optional: true + dependencies: + '@typescript-eslint/eslint-plugin': 8.12.2(@typescript-eslint/parser@8.12.2)(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/utils': 8.12.2(eslint@8.57.0)(typescript@5.7.2) + eslint: 8.57.0 + jest: 29.7.0(@types/node@22.10.5)(ts-node@10.9.2) + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /eslint-plugin-jest@28.10.0(eslint@9.13.0)(jest@30.0.0-alpha.6)(typescript@5.7.2): + resolution: {integrity: sha512-hyMWUxkBH99HpXT3p8hc7REbEZK3D+nk8vHXGgpB+XXsi0gO4PxMSP+pjfUzb67GnV9yawV9a53eUmcde1CCZA==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + peerDependencies: + '@typescript-eslint/eslint-plugin': ^6.0.0 || ^7.0.0 || ^8.0.0 + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 + jest: '*' + peerDependenciesMeta: + '@typescript-eslint/eslint-plugin': + optional: true + jest: + optional: true + dependencies: + '@typescript-eslint/utils': 8.12.2(eslint@9.13.0)(typescript@5.7.2) + eslint: 9.13.0 + jest: 30.0.0-alpha.6 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /eslint-plugin-mocha@10.5.0(eslint@8.57.0): + resolution: {integrity: sha512-F2ALmQVPT1GoP27O1JTZGrV9Pqg8k79OeIuvw63UxMtQKREZtmkK1NFgkZQ2TW7L2JSSFKHFPTtHu5z8R9QNRw==} + engines: {node: '>=14.0.0'} + peerDependencies: + eslint: '>=7.0.0' + dependencies: + eslint: 8.57.0 + eslint-utils: 3.0.0(eslint@8.57.0) + globals: 13.24.0 + rambda: 7.5.0 + dev: true + + /eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0)(eslint@9.13.0)(prettier@3.4.2): + resolution: {integrity: sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '*' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true + dependencies: + eslint: 9.13.0 + eslint-config-prettier: 9.1.0(eslint@9.13.0) + prettier: 3.4.2 + prettier-linter-helpers: 1.0.0 + synckit: 0.9.1 + dev: true + + /eslint-plugin-react-hooks@4.6.2(eslint@8.57.0): + resolution: {integrity: sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + dependencies: + eslint: 8.57.0 + dev: true + + /eslint-plugin-react-hooks@5.0.0(eslint@9.13.0): + resolution: {integrity: sha512-hIOwI+5hYGpJEc4uPRmz2ulCjAGD/N13Lukkh8cLV0i2IRk/bdZDYjgLVHj+U9Z704kLIdIO6iueGvxNur0sgw==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + dependencies: + eslint: 9.13.0 + dev: true + + /eslint-plugin-require-extensions@0.1.3(eslint@8.57.0): + resolution: {integrity: sha512-T3c1PZ9PIdI3hjV8LdunfYI8gj017UQjzAnCrxuo3wAjneDbTPHdE3oNWInOjMA+z/aBkUtlW5vC0YepYMZIug==} + engines: {node: '>=16'} + peerDependencies: + eslint: '*' + dependencies: + eslint: 8.57.0 + dev: true + + /eslint-plugin-simple-import-sort@12.1.1(eslint@8.57.0): + resolution: {integrity: sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==} + peerDependencies: + eslint: '>=5.0.0' + dependencies: + eslint: 8.57.0 + dev: true + + /eslint-plugin-simple-import-sort@12.1.1(eslint@9.13.0): + resolution: {integrity: sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==} + peerDependencies: + eslint: '>=5.0.0' + dependencies: + eslint: 9.13.0 + dev: true + + /eslint-plugin-sort-keys-fix@1.1.2: + resolution: {integrity: sha512-DNPHFGCA0/hZIsfODbeLZqaGY/+q3vgtshF85r+YWDNCQ2apd9PNs/zL6ttKm0nD1IFwvxyg3YOTI7FHl4unrw==} + engines: {node: '>=0.10.0'} + dependencies: + espree: 6.2.1 + esutils: 2.0.3 + natural-compare: 1.4.0 + requireindex: 1.2.0 + dev: true + + /eslint-plugin-turbo@2.3.3(eslint@8.57.0): + resolution: {integrity: sha512-j8UEA0Z+NNCsjZep9G5u5soDQHcXq/x4amrwulk6eHF1U91H2qAjp5I4jQcvJewmccCJbVp734PkHHTRnosjpg==} + peerDependencies: + eslint: '>6.6.0' + dependencies: + dotenv: 16.0.3 + eslint: 8.57.0 + dev: true + + /eslint-plugin-turbo@2.3.3(eslint@9.13.0): + resolution: {integrity: sha512-j8UEA0Z+NNCsjZep9G5u5soDQHcXq/x4amrwulk6eHF1U91H2qAjp5I4jQcvJewmccCJbVp734PkHHTRnosjpg==} + peerDependencies: + eslint: '>6.6.0' + dependencies: + dotenv: 16.0.3 + eslint: 9.13.0 + dev: true + + /eslint-plugin-typescript-sort-keys@3.3.0(@typescript-eslint/parser@8.12.2)(eslint@8.57.0)(typescript@5.7.2): + resolution: {integrity: sha512-bRW3Rc/VNdrSP9OoY5wgjjaXCOOkZKpzvl/Mk6l8Sg8CMehVIcg9K4y33l+ZcZiknpl0aR6rKusxuCJNGZWmVw==} + engines: {node: '>= 16'} + peerDependencies: + '@typescript-eslint/parser': '>=6' + eslint: ^7 || ^8 + typescript: ^3 || ^4 || ^5 + dependencies: + '@typescript-eslint/experimental-utils': 5.62.0(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/parser': 8.12.2(eslint@8.57.0)(typescript@5.7.2) + eslint: 8.57.0 + json-schema: 0.4.0 + natural-compare-lite: 1.4.0 + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-typescript-sort-keys@3.3.0(@typescript-eslint/parser@8.12.2)(eslint@9.13.0)(typescript@5.7.2): + resolution: {integrity: sha512-bRW3Rc/VNdrSP9OoY5wgjjaXCOOkZKpzvl/Mk6l8Sg8CMehVIcg9K4y33l+ZcZiknpl0aR6rKusxuCJNGZWmVw==} + engines: {node: '>= 16'} + peerDependencies: + '@typescript-eslint/parser': '>=6' + eslint: ^7 || ^8 + typescript: ^3 || ^4 || ^5 + dependencies: + '@typescript-eslint/experimental-utils': 5.62.0(eslint@9.13.0)(typescript@5.7.2) + '@typescript-eslint/parser': 8.12.2(eslint@9.13.0)(typescript@5.7.2) + eslint: 9.13.0 + json-schema: 0.4.0 + natural-compare-lite: 1.4.0 + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + dev: true + + /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-scope@8.2.0: + resolution: {integrity: sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + dev: true + + /eslint-utils@3.0.0(eslint@8.57.0): + resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} + engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} + peerDependencies: + eslint: '>=5' + dependencies: + eslint: 8.57.0 + eslint-visitor-keys: 2.1.0 + dev: true + + /eslint-visitor-keys@1.3.0: + resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} + engines: {node: '>=4'} + 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-visitor-keys@4.2.0: + resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true + + /eslint@8.57.0: + resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/regexpp': 4.12.1 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.0 + '@humanwhocodes/config-array': 0.11.14 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.7(supports-color@8.1.1) + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.24.0 + graphemer: 1.4.0 + ignore: 5.3.1 + 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 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint@9.13.0: + resolution: {integrity: sha512-EYZK6SX6zjFHST/HRytOdA/zE72Cq/bfw45LSyuwrdvcclb/gqV8RRQxywOBEWO2+WDpva6UZa4CcDeJKzUCFA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@9.13.0) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.18.0 + '@eslint/core': 0.7.0 + '@eslint/eslintrc': 3.1.0 + '@eslint/js': 9.13.0 + '@eslint/plugin-kit': 0.2.2 + '@humanfs/node': 0.16.6 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.3.1 + '@types/estree': 1.0.6 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.4.0 + escape-string-regexp: 4.0.0 + eslint-scope: 8.2.0 + eslint-visitor-keys: 4.2.0 + espree: 10.3.0 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.1 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + /espree@10.3.0: + resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) + eslint-visitor-keys: 4.2.0 + dev: true + + /espree@6.2.1: + resolution: {integrity: sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==} + engines: {node: '>=6.0.0'} + dependencies: + acorn: 7.4.1 + acorn-jsx: 5.3.2(acorn@7.4.1) + eslint-visitor-keys: 1.3.0 + dev: true + + /espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.11.3 + acorn-jsx: 5.3.2(acorn@8.11.3) + eslint-visitor-keys: 3.4.3 + dev: true + + /esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + engines: {node: '>=0.10'} + dependencies: + estraverse: 5.3.0 + dev: true + + /esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + dependencies: + estraverse: 5.3.0 + dev: true + + /estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + dev: true + + /estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + dev: true + + /estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + dev: true + + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: true + + /event-stream@3.3.4: + resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==} + dependencies: + duplexer: 0.1.2 + from: 0.1.7 + map-stream: 0.1.0 + pause-stream: 0.0.11 + split: 0.3.3 + stream-combiner: 0.0.4 + through: 2.3.8 + dev: true + + /eventemitter3@4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + dev: true + + /eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + + /execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + dev: true + + /exit@0.1.2: + resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + engines: {node: '>= 0.8.0'} + dev: true + + /expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/expect-utils': 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + dev: true + + /expect@30.0.0-alpha.6: + resolution: {integrity: sha512-WVi2V4iHKw/vHEyye00Q9CSZz7KHDbJkJyteUI8kTih9jiyMl3bIk7wLYFcY9D1Blnadlyb5w5NBuNjQBow99g==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@jest/expect-utils': 30.0.0-alpha.6 + jest-get-type: 30.0.0-alpha.6 + jest-matcher-utils: 30.0.0-alpha.6 + jest-message-util: 30.0.0-alpha.6 + jest-mock: 30.0.0-alpha.6 + jest-util: 30.0.0-alpha.6 + dev: true + + /eyes@0.1.8: + resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==} + engines: {node: '> 0.1.90'} + + /fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: true + + /fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + dev: true + + /fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + dev: true + + /fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + dev: true + + /fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + dev: true + + /fast-stable-stringify@1.0.0: + resolution: {integrity: sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==} + + /fastestsmallesttextencoderdecoder@1.0.22: + resolution: {integrity: sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==} + dev: true + + /fastq@1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + dependencies: + reusify: 1.0.4 + dev: true + + /fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + dependencies: + bser: 2.1.1 + dev: true + + /fdir@6.3.0(picomatch@4.0.2): + resolution: {integrity: sha512-QOnuT+BOtivR77wYvCWHfGt9s4Pz1VIMbD463vegT5MLqNXy8rYFT/lPVEqf/bhYeT6qmqrNHhsX+rWwe3rOCQ==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + dependencies: + picomatch: 4.0.2 + dev: true + + /file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flat-cache: 3.1.1 + dev: true + + /file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + dependencies: + flat-cache: 4.0.1 + dev: true + + /file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + + /filelist@1.0.4: + resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + dependencies: + minimatch: 5.1.6 + dev: true + + /filename-reserved-regex@2.0.0: + resolution: {integrity: sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==} + engines: {node: '>=4'} + dev: true + + /filenamify@4.3.0: + resolution: {integrity: sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==} + engines: {node: '>=8'} + dependencies: + filename-reserved-regex: 2.0.0 + strip-outer: 1.0.1 + trim-repeated: 1.0.0 + dev: true + + /fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: true + + /find-cache-dir@3.3.2: + resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} + engines: {node: '>=8'} + dependencies: + commondir: 1.0.1 + make-dir: 3.1.0 + pkg-dir: 4.2.0 + dev: true + + /find-process@1.4.7: + resolution: {integrity: sha512-/U4CYp1214Xrp3u3Fqr9yNynUrr5Le4y0SsJh2lMDDSbpwYSz3M2SMWQC+wqcx79cN8PQtHQIL8KnuY9M66fdg==} + hasBin: true + dependencies: + chalk: 4.1.2 + commander: 5.1.0 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + dev: true + + /find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + dev: true + + /find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + dev: true + + /flat-cache@3.1.1: + resolution: {integrity: sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==} + engines: {node: '>=12.0.0'} + dependencies: + flatted: 3.2.9 + keyv: 4.5.4 + rimraf: 3.0.2 + dev: true + + /flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + dependencies: + flatted: 3.2.9 + keyv: 4.5.4 + dev: true + + /flat@5.0.2: + resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} + hasBin: true + dev: true + + /flatted@3.2.9: + resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} + dev: true + + /follow-redirects@1.15.9(debug@4.4.0): + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dependencies: + debug: 4.4.0 + dev: true + + /for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + dependencies: + is-callable: 1.2.7 + + /foreground-child@3.1.1: + resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} + engines: {node: '>=14'} + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + dev: true + + /form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: true + + /from@0.1.7: + resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} + dev: true + + /fs-extra@11.1.1: + resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==} + engines: {node: '>=14.14'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: true + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + dev: true + + /fsevents@2.3.3: + 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 + + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + /function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + functions-have-names: 1.2.3 + dev: true + + /functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + dev: true + + /gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + dev: true + + /get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + dev: true + + /get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + + /get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + dev: true + + /get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + dev: true + + /get-symbol-description@1.0.2: + resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + dev: true + + /gh-pages@6.3.0: + resolution: {integrity: sha512-Ot5lU6jK0Eb+sszG8pciXdjMXdBJ5wODvgjR+imihTqsUWF2K6dJ9HST55lgqcs8wWcw6o6wAsUzfcYRhJPXbA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + async: 3.2.5 + commander: 13.0.0 + email-addresses: 5.0.0 + filenamify: 4.3.0 + find-cache-dir: 3.3.2 + fs-extra: 11.1.1 + globby: 11.1.0 + dev: true + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + dependencies: + foreground-child: 3.1.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.0 + 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 + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + 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'} + dependencies: + type-fest: 0.20.2 + dev: true + + /globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + dev: true + + /globals@15.11.0: + resolution: {integrity: sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw==} + engines: {node: '>=18'} + dev: true + + /globalthis@1.0.3: + resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} + engines: {node: '>= 0.4'} + dependencies: + define-properties: 1.2.1 + dev: true + + /globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.2 + ignore: 5.3.1 + merge2: 1.4.1 + slash: 3.0.0 + dev: true + + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.2.4 + + /graceful-fs@4.2.11: + 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 + + /has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + dev: true + + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + /has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + dependencies: + es-define-property: 1.0.0 + + /has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} + engines: {node: '>= 0.4'} + + /has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + + /has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + + /hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + + /he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + dev: true + + /html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + dev: true + + /human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + dev: true + + /humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + dependencies: + ms: 2.1.3 + + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + /ignore@5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + engines: {node: '>= 4'} + dev: true + + /ignore@5.3.1: + resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} + engines: {node: '>= 4'} + dev: true + + /import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + dev: true + + /import-local@3.1.0: + resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} + engines: {node: '>=8'} + hasBin: true + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + dev: true + + /imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + dev: true + + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: true + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + /internal-slot@1.0.7: + resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.0.4 + dev: true + + /is-arguments@1.1.1: + resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + /is-array-buffer@3.0.4: + resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + dev: true + + /is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + dev: true + + /is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + dependencies: + has-bigints: 1.0.2 + dev: true + + /is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.2.0 + dev: true + + /is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + dev: true + + /is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + /is-core-module@2.15.1: + resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} + engines: {node: '>= 0.4'} + dependencies: + hasown: 2.0.2 + dev: true + + /is-data-view@1.0.1: + resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} + engines: {node: '>= 0.4'} + dependencies: + is-typed-array: 1.1.13 + dev: true + + /is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + dev: true + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: true + + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: true + + /is-generator-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + dev: true + + /is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true + + /is-immutable-type@5.0.0(eslint@8.57.0)(typescript@5.7.2): + resolution: {integrity: sha512-mcvHasqbRBWJznuPqqHRKiJgYAz60sZ0mvO3bN70JbkuK7ksfmgc489aKZYxMEjIbRvyOseaTjaRZLRF/xFeRA==} + peerDependencies: + eslint: '*' + typescript: '>=4.7.4' + dependencies: + '@typescript-eslint/type-utils': 8.12.2(eslint@8.57.0)(typescript@5.7.2) + eslint: 8.57.0 + ts-api-utils: 1.3.0(typescript@5.7.2) + ts-declaration-location: 1.0.4(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + dev: true + + /is-module@1.0.0: + resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} + dev: true + + /is-nan@1.3.2: + resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + + /is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + dev: true + + /is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + dev: true + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + 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'} + dev: true + + /is-reference@1.2.1: + resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} + dependencies: + '@types/estree': 1.0.6 + dev: true + + /is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + dev: true + + /is-shared-array-buffer@1.0.3: + resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + dev: true + + /is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + dev: true + + /is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + dev: true + + /is-symbol@1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: true + + /is-typed-array@1.1.13: + resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.15 + + /is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + dev: true + + /is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + dependencies: + call-bind: 1.0.7 + dev: true + + /isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + dev: true + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true + + /isomorphic-ws@4.0.1(ws@7.5.10): + resolution: {integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==} + peerDependencies: + ws: '*' + dependencies: + ws: 7.5.10 + + /istanbul-lib-coverage@3.2.1: + resolution: {integrity: sha512-opCrKqbthmq3SKZ10mFMQG9dk3fTa3quaOLD35kJa5ejwZHd9xAr+kLuziiZz2cG32s4lMZxNdmdcEQnTDP4+g==} + engines: {node: '>=8'} + dev: true + + /istanbul-lib-instrument@5.2.1: + resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} + engines: {node: '>=8'} + dependencies: + '@babel/core': 7.26.0 + '@babel/parser': 7.23.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.1 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-lib-instrument@6.0.1: + resolution: {integrity: sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==} + engines: {node: '>=10'} + dependencies: + '@babel/core': 7.26.0 + '@babel/parser': 7.23.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.1 + semver: 7.6.3 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-lib-instrument@6.0.3: + resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} + engines: {node: '>=10'} + dependencies: + '@babel/core': 7.26.0 + '@babel/parser': 7.26.2 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.1 + semver: 7.6.3 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + dependencies: + istanbul-lib-coverage: 3.2.1 + make-dir: 4.0.0 + supports-color: 7.2.0 + dev: true + + /istanbul-lib-source-maps@4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + dependencies: + debug: 4.4.0 + istanbul-lib-coverage: 3.2.1 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} + engines: {node: '>=10'} + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + debug: 4.4.0 + istanbul-lib-coverage: 3.2.1 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-reports@3.1.6: + resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} + engines: {node: '>=8'} + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + 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 + + /jake@10.9.1: + resolution: {integrity: sha512-61btcOHNnLnsOdtLgA5efqQWjnSi/vow5HbI7HMdKKWqvrKR1bLK3BPlJn9gcSaP2ewuamUSMB5XEy76KUIS2w==} + engines: {node: '>=10'} + hasBin: true + dependencies: + async: 3.2.5 + chalk: 4.1.2 + filelist: 1.0.4 + minimatch: 3.1.2 + dev: true + + /jayson@4.1.1: + resolution: {integrity: sha512-5ZWm4Q/0DHPyeMfAsrwViwUS2DMVsQgWh8bEEIVTkfb3DzHZ2L3G5WUnF+AKmGjjM9r1uAv73SaqC1/U4RL45w==} + 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 + uuid: 8.3.2 + ws: 7.5.10 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + /jest-changed-files@29.7.0: + resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + execa: 5.1.1 + jest-util: 29.7.0 + p-limit: 3.1.0 + dev: true + + /jest-changed-files@30.0.0-alpha.6: + resolution: {integrity: sha512-Fmyt6W27L4fRBl/gReFC4WU+3XIqB7ySHu+a9QxrERapfCb43o7y81TCvTwJHSw5dxGzXLOObVB0tRMDWMafnw==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + execa: 5.1.1 + jest-util: 30.0.0-alpha.6 + p-limit: 3.1.0 + dev: true + + /jest-circus@29.7.0: + resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.10.5 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.5.1 + is-generator-fn: 2.1.0 + jest-each: 29.7.0 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + p-limit: 3.1.0 + pretty-format: 29.7.0 + pure-rand: 6.0.4 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + dev: true + + /jest-circus@30.0.0-alpha.6: + resolution: {integrity: sha512-1C62WeTyWinn6zR61syYKe5yqVbV+ftf21vOgj8AtTxGfMUAlGCpeZ5zh4Kc9Qk7r/PiPiHWZtgZmeT4oe9Dug==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@jest/environment': 30.0.0-alpha.6 + '@jest/expect': 30.0.0-alpha.6 + '@jest/test-result': 30.0.0-alpha.6 + '@jest/types': 30.0.0-alpha.6 + '@types/node': 22.10.5 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.5.1 + is-generator-fn: 2.1.0 + jest-each: 30.0.0-alpha.6 + jest-matcher-utils: 30.0.0-alpha.6 + jest-message-util: 30.0.0-alpha.6 + jest-runtime: 30.0.0-alpha.6 + jest-snapshot: 30.0.0-alpha.6 + jest-util: 30.0.0-alpha.6 + p-limit: 3.1.0 + pretty-format: 30.0.0-alpha.6 + pure-rand: 6.0.4 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + dev: true + + /jest-cli@29.7.0(@types/node@22.10.5)(ts-node@10.9.2): + resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@22.10.5)(ts-node@10.9.2) + exit: 0.1.2 + import-local: 3.1.0 + jest-config: 29.7.0(@types/node@22.10.5)(ts-node@10.9.2) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + dev: true + + /jest-cli@30.0.0-alpha.6: + resolution: {integrity: sha512-3VYzI2KgpMNAsf+LdRAQtAbhH3IDyFnT36U6URXot+2JWwoCGQQ6w4HIfqyOSlH4aejKgTPSfxki2shRPDFtlQ==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/core': 30.0.0-alpha.6 + '@jest/test-result': 30.0.0-alpha.6 + '@jest/types': 30.0.0-alpha.6 + chalk: 4.1.2 + exit: 0.1.2 + import-local: 3.1.0 + jest-config: 30.0.0-alpha.6(@types/node@22.10.5) + jest-util: 30.0.0-alpha.6 + jest-validate: 30.0.0-alpha.6 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - esbuild-register + - supports-color + - ts-node + dev: true + + /jest-config@29.7.0(@types/node@22.10.5)(ts-node@10.9.2): + resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + dependencies: + '@babel/core': 7.26.0 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.10.5 + babel-jest: 29.7.0(@babel/core@7.26.0) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + ts-node: 10.9.2(@types/node@22.10.5)(typescript@5.7.2) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + dev: true + + /jest-config@30.0.0-alpha.6(@types/node@22.10.5): + resolution: {integrity: sha512-Tq9rH1mg9+nlIhh3efGwMSogFVKZ9z7c6P33ZlK74iJlnqqIAKYERZL2nNmNC5+5p8uxlTPSFZfBz9O8NGKotw==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + peerDependencies: + '@types/node': '*' + esbuild-register: '>=3.4.0' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + esbuild-register: + optional: true + ts-node: + optional: true + dependencies: + '@babel/core': 7.26.0 + '@jest/pattern': 30.0.0-alpha.6 + '@jest/test-sequencer': 30.0.0-alpha.6 + '@jest/types': 30.0.0-alpha.6 + '@types/node': 22.10.5 + babel-jest: 30.0.0-alpha.6(@babel/core@7.26.0) + chalk: 4.1.2 + ci-info: 4.0.0 + deepmerge: 4.3.1 + glob: 10.4.5 + graceful-fs: 4.2.11 + jest-circus: 30.0.0-alpha.6 + jest-docblock: 30.0.0-alpha.6 + jest-environment-node: 30.0.0-alpha.6 + jest-get-type: 30.0.0-alpha.6 + jest-regex-util: 30.0.0-alpha.6 + jest-resolve: 30.0.0-alpha.6 + jest-runner: 30.0.0-alpha.6 + jest-util: 30.0.0-alpha.6 + jest-validate: 30.0.0-alpha.6 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 30.0.0-alpha.6 + slash: 3.0.0 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + dev: true + + /jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + chalk: 4.1.2 + diff-sequences: 29.6.3 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + dev: true + + /jest-diff@30.0.0-alpha.6: + resolution: {integrity: sha512-43j1DoYwVKrkbB67a2gC0ijjIY9biF0JSPXv7H6zlOkzNlqYg8hSDzrurLNo6zGKatW4JSBLE79LmXPJPj1m6A==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + chalk: 4.1.2 + diff-sequences: 30.0.0-alpha.6 + jest-get-type: 30.0.0-alpha.6 + pretty-format: 30.0.0-alpha.6 + dev: true + + /jest-docblock@29.7.0: + resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + detect-newline: 3.1.0 + dev: true + + /jest-docblock@30.0.0-alpha.6: + resolution: {integrity: sha512-KXRLgRo7/rF1wqxQupsFCZa6wOp1qrDg4GdSXKfIHODYQb0dpi4rYaYA8xV5l2g9KwYc9/zV7l1tPe9TOr27ew==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + detect-newline: 3.1.0 + dev: true + + /jest-each@29.7.0: + resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + jest-get-type: 29.6.3 + jest-util: 29.7.0 + pretty-format: 29.7.0 + dev: true + + /jest-each@30.0.0-alpha.6: + resolution: {integrity: sha512-snLI2JNYkoBMlZRrNk67XiauUy+uEzRCszKdj+cqHyZ4/MU8fz7gCxbn3g0zmiGUxr0RX0534UxMjc82Sk++tg==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@jest/types': 30.0.0-alpha.6 + chalk: 4.1.2 + jest-get-type: 30.0.0-alpha.6 + jest-util: 30.0.0-alpha.6 + pretty-format: 30.0.0-alpha.6 + dev: true + + /jest-environment-node@29.7.0: + resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.10.5 + jest-mock: 29.7.0 + jest-util: 29.7.0 + dev: true + + /jest-environment-node@30.0.0-alpha.6: + resolution: {integrity: sha512-UN9W3dFzO150Bqj1x+1pq7dMUqw/QhpqhdtmC3B1P6GD9eKEMFGuRw3EButx5SGzrZOqRNlF+tUNC8CoWGW2Og==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@jest/environment': 30.0.0-alpha.6 + '@jest/fake-timers': 30.0.0-alpha.6 + '@jest/types': 30.0.0-alpha.6 + '@types/node': 22.10.5 + jest-mock: 30.0.0-alpha.6 + jest-util: 30.0.0-alpha.6 + dev: true + + /jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true + + /jest-get-type@30.0.0-alpha.6: + resolution: {integrity: sha512-lJEoQdCY4ICN6+T0lJ9BODKuqPOEpCv2NnJsEO1nmsK0fbWZmN/pgOPHVqLfK8i3jZpUmgupJ1w8r36mc8iiBQ==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dev: true + + /jest-haste-map@29.7.0: + resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@types/graceful-fs': 4.1.9 + '@types/node': 22.10.5 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + jest-worker: 29.7.0 + micromatch: 4.0.8 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /jest-haste-map@30.0.0-alpha.6: + resolution: {integrity: sha512-NR/Kw8HyOkuWIdT8ynsp9KnsTDvWnlz8WSOmtQxySTIzOWbZaeJ2FJi9LoDL6+vhKpdlLfUvhgZVtnFJSLCzew==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@jest/types': 30.0.0-alpha.6 + '@types/node': 22.10.5 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 30.0.0-alpha.6 + jest-util: 30.0.0-alpha.6 + jest-worker: 30.0.0-alpha.6 + micromatch: 4.0.8 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /jest-leak-detector@29.7.0: + resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + dev: true + + /jest-leak-detector@30.0.0-alpha.6: + resolution: {integrity: sha512-a6fh/6h6dCDyj+aplGqkajVqzmi+qYHs5X8orMZv+u56++gUezJZJf8GCiQqw2vtxcsWVPUuQXa3kF33tAYzNQ==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + jest-get-type: 30.0.0-alpha.6 + pretty-format: 30.0.0-alpha.6 + dev: true + + /jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + chalk: 4.1.2 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + dev: true + + /jest-matcher-utils@30.0.0-alpha.6: + resolution: {integrity: sha512-jaq7+HznsK54G0qzu96ZwfMEKHmlPiDqg6qG2p/hVQzr6Y/qVMRh8abI9Y1lX6SSXkr+S9mPAkmOsuJNLTLYmQ==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + chalk: 4.1.2 + jest-diff: 30.0.0-alpha.6 + jest-get-type: 30.0.0-alpha.6 + pretty-format: 30.0.0-alpha.6 + dev: true + + /jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/code-frame': 7.26.2 + '@jest/types': 29.6.3 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 + dev: true + + /jest-message-util@30.0.0-alpha.6: + resolution: {integrity: sha512-XAGJqkrBo7m3bFxWqiNqL0PyAWGf1XHR6bTve90MjBKJuIzhJsounGTzBNUw8JoU7Uzcj5Z6ZmEhaE3CDnwjfw==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@babel/code-frame': 7.26.2 + '@jest/types': 30.0.0-alpha.6 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.8 + pretty-format: 30.0.0-alpha.6 + slash: 3.0.0 + stack-utils: 2.0.6 + dev: true + + /jest-mock@29.7.0: + resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@types/node': 22.10.5 + jest-util: 29.7.0 + dev: true + + /jest-mock@30.0.0-alpha.6: + resolution: {integrity: sha512-ezW02IXiKyFYAgDuxfAlONWULitSaB66t411fq2BJxQtgyMGtv59CsnhgbKb0gQp+9vig5MO5ytDCUPalTbarg==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@jest/types': 30.0.0-alpha.6 + '@types/node': 22.10.5 + jest-util: 30.0.0-alpha.6 + dev: true + + /jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + dependencies: + jest-resolve: 29.7.0 + dev: true + + /jest-pnp-resolver@1.2.3(jest-resolve@30.0.0-alpha.6): + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + dependencies: + jest-resolve: 30.0.0-alpha.6 + dev: true + + /jest-regex-util@29.6.3: + resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true + + /jest-regex-util@30.0.0-alpha.6: + resolution: {integrity: sha512-XcsAVaqc69QyMz1/FChyhWSoAMaKcDPhFOuWJz/H51LppsyZRAJPXkPnMopsS+qfut8cggExr9QLcsYaX6hqqA==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dev: true + + /jest-resolve-dependencies@29.7.0: + resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + jest-regex-util: 29.6.3 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-resolve-dependencies@30.0.0-alpha.6: + resolution: {integrity: sha512-G+st0nBR4FNIvVCHq8YNJBiG6t7u0+cxM099lbtOoJNJU+ZTdIxSyzPnnmp/C+YHd1QOlDNlplvL+xe1KHhPUA==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + jest-regex-util: 30.0.0-alpha.6 + jest-snapshot: 30.0.0-alpha.6 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-resolve@29.7.0: + resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) + jest-util: 29.7.0 + jest-validate: 29.7.0 + resolve: 1.22.8 + resolve.exports: 2.0.2 + slash: 3.0.0 + dev: true + + /jest-resolve@30.0.0-alpha.6: + resolution: {integrity: sha512-0EyeId+RFng52qHvuxOzKjZd2uDF/2Hdzpzt54+biGgY/VVAvf8mYE9UV7g6154Ozpq6KLztSqqMCfPgVs4CbA==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-haste-map: 30.0.0-alpha.6 + jest-pnp-resolver: 1.2.3(jest-resolve@30.0.0-alpha.6) + jest-util: 30.0.0-alpha.6 + jest-validate: 30.0.0-alpha.6 + resolve: 1.22.8 + resolve.exports: 2.0.2 + slash: 3.0.0 + dev: true + + /jest-runner@29.7.0: + resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/console': 29.7.0 + '@jest/environment': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.10.5 + chalk: 4.1.2 + emittery: 0.13.1 + graceful-fs: 4.2.11 + jest-docblock: 29.7.0 + jest-environment-node: 29.7.0 + jest-haste-map: 29.7.0 + jest-leak-detector: 29.7.0 + jest-message-util: 29.7.0 + jest-resolve: 29.7.0 + jest-runtime: 29.7.0 + jest-util: 29.7.0 + jest-watcher: 29.7.0 + jest-worker: 29.7.0 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-runner@30.0.0-alpha.6: + resolution: {integrity: sha512-SoADy4YnspMpXLNnRCXNIoinm1N5SMci+iF6Y29Duv3wnWhcL14XjEOcyUKBB+AIL52YwouLeUHkCyCspbBk1Q==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@jest/console': 30.0.0-alpha.6 + '@jest/environment': 30.0.0-alpha.6 + '@jest/test-result': 30.0.0-alpha.6 + '@jest/transform': 30.0.0-alpha.6 + '@jest/types': 30.0.0-alpha.6 + '@types/node': 22.10.5 + chalk: 4.1.2 + emittery: 0.13.1 + graceful-fs: 4.2.11 + jest-docblock: 30.0.0-alpha.6 + jest-environment-node: 30.0.0-alpha.6 + jest-haste-map: 30.0.0-alpha.6 + jest-leak-detector: 30.0.0-alpha.6 + jest-message-util: 30.0.0-alpha.6 + jest-resolve: 30.0.0-alpha.6 + jest-runtime: 30.0.0-alpha.6 + jest-util: 30.0.0-alpha.6 + jest-watcher: 30.0.0-alpha.6 + jest-worker: 30.0.0-alpha.6 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-runtime@29.7.0: + resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/globals': 29.7.0 + '@jest/source-map': 29.6.3 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.10.5 + chalk: 4.1.2 + cjs-module-lexer: 1.2.3 + collect-v8-coverage: 1.0.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-runtime@30.0.0-alpha.6: + resolution: {integrity: sha512-p7w7DSFFzwHyR4HsNXca/p32VpL9MLT1c71+VplFJIEgeRHvyqxrARentlul6uJniwtlqvZrVVf5baCQ5a5GUw==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@jest/environment': 30.0.0-alpha.6 + '@jest/fake-timers': 30.0.0-alpha.6 + '@jest/globals': 30.0.0-alpha.6 + '@jest/source-map': 30.0.0-alpha.6 + '@jest/test-result': 30.0.0-alpha.6 + '@jest/transform': 30.0.0-alpha.6 + '@jest/types': 30.0.0-alpha.6 + '@types/node': 22.10.5 + chalk: 4.1.2 + cjs-module-lexer: 1.2.3 + collect-v8-coverage: 1.0.2 + glob: 10.4.5 + graceful-fs: 4.2.11 + jest-haste-map: 30.0.0-alpha.6 + jest-message-util: 30.0.0-alpha.6 + jest-mock: 30.0.0-alpha.6 + jest-regex-util: 30.0.0-alpha.6 + jest-resolve: 30.0.0-alpha.6 + jest-snapshot: 30.0.0-alpha.6 + jest-util: 30.0.0-alpha.6 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-snapshot@29.7.0: + resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/core': 7.26.0 + '@babel/generator': 7.26.2 + '@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.26.0) + '@babel/plugin-syntax-typescript': 7.22.5(@babel/core@7.26.0) + '@babel/types': 7.26.0 + '@jest/expect-utils': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.26.0) + chalk: 4.1.2 + expect: 29.7.0 + graceful-fs: 4.2.11 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + natural-compare: 1.4.0 + pretty-format: 29.7.0 + semver: 7.6.3 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-snapshot@30.0.0-alpha.6: + resolution: {integrity: sha512-YCBUxSNJ9YGch3tyQdxQkOUitbmXahHL6UhSQeSMERFfX1UMrHyEDHggglocCUg4G3jdU8YzshxOJ/oaR6Ph8w==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@babel/core': 7.26.0 + '@babel/generator': 7.26.2 + '@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.26.0) + '@babel/plugin-syntax-typescript': 7.22.5(@babel/core@7.26.0) + '@babel/types': 7.26.0 + '@jest/expect-utils': 30.0.0-alpha.6 + '@jest/snapshot-utils': 30.0.0-alpha.6 + '@jest/transform': 30.0.0-alpha.6 + '@jest/types': 30.0.0-alpha.6 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.26.0) + chalk: 4.1.2 + expect: 30.0.0-alpha.6 + graceful-fs: 4.2.11 + jest-diff: 30.0.0-alpha.6 + jest-get-type: 30.0.0-alpha.6 + jest-matcher-utils: 30.0.0-alpha.6 + jest-message-util: 30.0.0-alpha.6 + jest-util: 30.0.0-alpha.6 + pretty-format: 30.0.0-alpha.6 + semver: 7.6.3 + synckit: 0.9.1 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@types/node': 22.10.5 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + dev: true + + /jest-util@30.0.0-alpha.6: + resolution: {integrity: sha512-JlimakOVDyoMC8TEG+knoufxUqLG+Btihf1G8o5sHxz54C6oL54Wetfepp+Nhuj/1hSL0sQtkovvjlEycf9i0w==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@jest/types': 30.0.0-alpha.6 + '@types/node': 22.10.5 + chalk: 4.1.2 + ci-info: 4.0.0 + graceful-fs: 4.2.11 + picomatch: 4.0.2 + dev: true + + /jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 + dev: true + + /jest-validate@30.0.0-alpha.6: + resolution: {integrity: sha512-sINLwCenOUeJVzS5p+o1NhwKsY0de5Es0J7bsaSuZJQGRY67W20idceflr+aZ2akrKgvvqU8Tsg6lkFQyq+a6Q==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@jest/types': 30.0.0-alpha.6 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 30.0.0-alpha.6 + leven: 3.1.0 + pretty-format: 30.0.0-alpha.6 + dev: true + + /jest-watcher@29.7.0: + resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.10.5 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.13.1 + jest-util: 29.7.0 + string-length: 4.0.2 + dev: true + + /jest-watcher@30.0.0-alpha.6: + resolution: {integrity: sha512-+zL1y3GSJG8EOxVSc2p0dndis0rNDcwKTs4b1bpNTI0XneeTiZlCpRBNYI+sqBl/eZtJBrQdiBRSYz7kJqg7NQ==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@jest/test-result': 30.0.0-alpha.6 + '@jest/types': 30.0.0-alpha.6 + '@types/node': 22.10.5 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.13.1 + jest-util: 30.0.0-alpha.6 + string-length: 4.0.2 + dev: true + + /jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@types/node': 22.10.5 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + dev: true + + /jest-worker@30.0.0-alpha.6: + resolution: {integrity: sha512-qlzX7zFT/QdUV/LWsJwZBlaIBaJ+E2VH3d1gArGVP+9hUHGpJkEzCSBK7yuZrkt+M/U0Jre5+maPRmkinEF4DA==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@types/node': 22.10.5 + '@ungap/structured-clone': 1.2.0 + jest-util: 30.0.0-alpha.6 + merge-stream: 2.0.0 + supports-color: 8.1.1 + dev: true + + /jest@29.7.0(@types/node@22.10.5)(ts-node@10.9.2): + resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2) + '@jest/types': 29.6.3 + import-local: 3.1.0 + jest-cli: 29.7.0(@types/node@22.10.5)(ts-node@10.9.2) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + dev: true + + /jest@30.0.0-alpha.6: + resolution: {integrity: sha512-9T3nAcIAcEpCX2MdxcjG2IDfG/0tjumnCkVNGh+AKkRXcWF4Er5jLROKvXsgXUJCmr/nMqLF6LG0GrDJ0kjFag==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/core': 30.0.0-alpha.6 + '@jest/types': 30.0.0-alpha.6 + import-local: 3.1.0 + jest-cli: 30.0.0-alpha.6 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - esbuild-register + - supports-color + - ts-node + dev: true + + /joi@17.13.3: + resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} + dependencies: + '@hapi/hoek': 9.3.0 + '@hapi/topo': 5.1.0 + '@sideway/address': 4.1.5 + '@sideway/formula': 3.0.1 + '@sideway/pinpoint': 2.0.0 + dev: true + + /js-sha256@0.9.0: + resolution: {integrity: sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==} + dev: true + + /js-sha3@0.9.3: + resolution: {integrity: sha512-BcJPCQeLg6WjEx3FE591wVAevlli8lxsxm9/FzV4HXkV49TmBH38Yvrpce6fjbADGMKFrBMGTqrVz3qPIZ88Gg==} + dev: false + + /js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: true + + /js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + dev: true + + /js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + dev: true + + /jsesc@3.0.2: + resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} + engines: {node: '>=6'} + hasBin: true + dev: true + + /json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + dev: true + + /json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + dev: true + + /json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + dev: true + + /json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + dev: true + + /json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + dev: true + + /json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + + /json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + dependencies: + minimist: 1.2.8 + dev: true + + /json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + dev: true + + /jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + dependencies: + universalify: 2.0.1 + optionalDependencies: + 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} + + /keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + dependencies: + json-buffer: 3.0.1 + dev: true + + /kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + dev: true + + /lazy-ass@1.6.0: + resolution: {integrity: sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==} + engines: {node: '> 0.8'} + dev: true + + /leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + dev: true + + /levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + dev: true + + /linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + dependencies: + uc.micro: 2.1.0 + dev: true + + /locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + dependencies: + p-locate: 4.1.0 + dev: true + + /locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + dev: true + + /lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + dev: true + + /lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true + + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: true + + /log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + dev: true + + /lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + dependencies: + tslib: 2.8.1 + dev: true + + /lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + dev: true + + /lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + dependencies: + yallist: 3.1.1 + dev: true + + /lunr@2.3.9: + resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} + dev: true + + /magic-string@0.30.10: + resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /make-dir@3.1.0: + resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} + engines: {node: '>=8'} + dependencies: + semver: 6.3.1 + dev: true + + /make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + dependencies: + semver: 7.6.3 + dev: true + + /make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + dev: true + + /makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + dependencies: + tmpl: 1.0.5 + dev: true + + /map-stream@0.1.0: + resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==} + dev: true + + /markdown-it@14.1.0: + resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} + hasBin: true + dependencies: + argparse: 2.0.1 + entities: 4.5.0 + linkify-it: 5.0.0 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 + dev: true + + /mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + dev: true + + /merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + dev: true + + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: true + + /micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + dev: true + + /micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + dev: true + + /mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: true + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: true + + /mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + dev: true + + /minimatch@10.0.1: + resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} + engines: {node: 20 || >=22} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: true + + /minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + dev: true + + /mocha@11.0.1: + resolution: {integrity: sha512-+3GkODfsDG71KSCQhc4IekSW+ItCK/kiez1Z28ksWvYhKXV/syxMlerR/sC7whDp7IyreZ4YxceMLdTs5hQE8A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + dependencies: + ansi-colors: 4.1.3 + browser-stdout: 1.3.1 + chokidar: 3.5.3 + debug: 4.3.7(supports-color@8.1.1) + diff: 5.2.0 + escape-string-regexp: 4.0.0 + find-up: 5.0.0 + glob: 10.4.5 + he: 1.2.0 + js-yaml: 4.1.0 + log-symbols: 4.1.0 + minimatch: 5.1.6 + ms: 2.1.3 + serialize-javascript: 6.0.2 + strip-json-comments: 3.1.1 + supports-color: 8.1.1 + workerpool: 6.5.1 + yargs: 16.2.0 + yargs-parser: 20.2.9 + yargs-unparser: 2.0.0 + dev: true + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: true + + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + /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 + + /no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + dependencies: + lower-case: 2.0.2 + tslib: 2.8.1 + dev: true + + /node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + dependencies: + whatwg-url: 5.0.0 + + /node-gyp-build@4.6.1: + resolution: {integrity: sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==} + hasBin: true + requiresBuild: true + + /node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + dev: true + + /node-releases@2.0.18: + resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} + dev: true + + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + dev: true + + /npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + dependencies: + path-key: 3.1.1 + dev: true + + /object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + dev: true + + /object-is@1.1.6: + resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + + /object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + /object.assign@4.1.5: + resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + has-symbols: 1.0.3 + object-keys: 1.1.1 + + /object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + dev: true + + /object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + dev: true + + /object.values@1.2.0: + resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + dev: true + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + dev: true + + /onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + dependencies: + mimic-fn: 2.1.0 + dev: true + + /optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} + engines: {node: '>= 0.8.0'} + dependencies: + '@aashutoshrathi/word-wrap': 1.2.6 + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + dependencies: + p-try: 2.2.0 + dev: true + + /p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + dependencies: + yocto-queue: 0.1.0 + dev: true + + /p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + dependencies: + p-limit: 2.3.0 + dev: true + + /p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + dependencies: + p-limit: 3.1.0 + dev: true + + /p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + dev: true + + /package-json-from-dist@1.0.0: + resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==} + dev: true + + /pako@2.1.0: + resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} + dev: true + + /parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + dev: true + + /parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + dependencies: + '@babel/code-frame': 7.26.2 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + dev: true + + /path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + dev: true + + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + dev: true + + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + dev: true + + /path-parse@1.0.7: + 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-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: true + + /pause-stream@0.0.11: + resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} + dependencies: + through: 2.3.8 + dev: true + + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true + + /picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + dev: true + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: true + + /picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + dev: true + + /pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + dev: true + + /pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + dependencies: + find-up: 4.1.0 + dev: true + + /possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + + /prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + dev: true + + /prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + dependencies: + fast-diff: 1.3.0 + dev: true + + /prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} + engines: {node: '>=10.13.0'} + hasBin: true + dev: true + + /prettier@3.4.2: + resolution: {integrity: sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==} + engines: {node: '>=14'} + hasBin: true + dev: true + + /pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.2.0 + dev: true + + /pretty-format@30.0.0-alpha.6: + resolution: {integrity: sha512-xkeffkZoqQmRrcNewpOsUCKNOl+CkPqjt3Ld749uz1S7/O7GuPNPv2fZk3v/1U/FE8/B4Zz0llVL80MKON1tOQ==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + dependencies: + '@jest/schemas': 30.0.0-alpha.6 + ansi-styles: 5.2.0 + react-is: 18.2.0 + dev: true + + /prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + dev: true + + /proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + dev: true + + /ps-tree@1.2.0: + resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==} + engines: {node: '>= 0.10'} + hasBin: true + dependencies: + event-stream: 3.3.4 + dev: true + + /punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + dev: true + + /punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + dev: true + + /pure-rand@6.0.4: + resolution: {integrity: sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==} + dev: true + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /rambda@7.5.0: + resolution: {integrity: sha512-y/M9weqWAH4iopRd7EHDEQQvpFPHj1AA3oHozE9tfITHUtTR7Z9PSlIRRG2l1GuW7sefC1cXFfIcF+cgnShdBA==} + dev: true + + /randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + dependencies: + safe-buffer: 5.2.1 + dev: true + + /react-is@18.2.0: + resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + dev: true + + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + dev: true + + /regenerator-runtime@0.14.0: + resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} + + /regexp.prototype.flags@1.5.2: + resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-errors: 1.3.0 + set-function-name: 2.0.1 + dev: true + + /require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + dev: true + + /requireindex@1.2.0: + resolution: {integrity: sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==} + engines: {node: '>=0.10.5'} + dev: true + + /resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + dependencies: + resolve-from: 5.0.0 + dev: true + + /resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: true + + /resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + dev: true + + /resolve.exports@2.0.2: + resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} + engines: {node: '>=10'} + dev: true + + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.15.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true + + /rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + dependencies: + glob: 7.2.3 + dev: true + + /rollup@4.30.1: + resolution: {integrity: sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + dependencies: + '@types/estree': 1.0.6 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.30.1 + '@rollup/rollup-android-arm64': 4.30.1 + '@rollup/rollup-darwin-arm64': 4.30.1 + '@rollup/rollup-darwin-x64': 4.30.1 + '@rollup/rollup-freebsd-arm64': 4.30.1 + '@rollup/rollup-freebsd-x64': 4.30.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.30.1 + '@rollup/rollup-linux-arm-musleabihf': 4.30.1 + '@rollup/rollup-linux-arm64-gnu': 4.30.1 + '@rollup/rollup-linux-arm64-musl': 4.30.1 + '@rollup/rollup-linux-loongarch64-gnu': 4.30.1 + '@rollup/rollup-linux-powerpc64le-gnu': 4.30.1 + '@rollup/rollup-linux-riscv64-gnu': 4.30.1 + '@rollup/rollup-linux-s390x-gnu': 4.30.1 + '@rollup/rollup-linux-x64-gnu': 4.30.1 + '@rollup/rollup-linux-x64-musl': 4.30.1 + '@rollup/rollup-win32-arm64-msvc': 4.30.1 + '@rollup/rollup-win32-ia32-msvc': 4.30.1 + '@rollup/rollup-win32-x64-msvc': 4.30.1 + fsevents: 2.3.3 + dev: true + + /rpc-websockets@9.0.2: + resolution: {integrity: sha512-YzggvfItxMY3Lwuax5rC18inhbjJv9Py7JXRHxTIi94JOLrqBsSsUUc5bbl5W6c11tXhdfpDPK0KzBhoGe8jjw==} + dependencies: + '@swc/helpers': 0.5.11 + '@types/uuid': 8.3.4 + '@types/ws': 8.5.10 + buffer: 6.0.3 + eventemitter3: 5.0.1 + uuid: 8.3.2 + ws: 8.14.2(bufferutil@4.0.8)(utf-8-validate@5.0.10) + optionalDependencies: + bufferutil: 4.0.8 + utf-8-validate: 5.0.10 + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + dependencies: + tslib: 2.8.1 + dev: true + + /safe-array-concat@1.1.2: + resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} + engines: {node: '>=0.4'} + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + isarray: 2.0.5 + dev: true + + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + /safe-regex-test@1.0.3: + resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-regex: 1.1.4 + dev: true + + /semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + dev: true + + /semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + dev: true + + /serialize-javascript@6.0.2: + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + dependencies: + randombytes: 2.1.0 + dev: true + + /set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + + /set-function-name@2.0.1: + resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + dev: true + + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + dev: true + + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + dev: true + + /side-channel@1.0.4: + resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + object-inspect: 1.13.1 + dev: true + + /signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + dev: true + + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + dev: true + + /sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + dev: true + + /slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + dev: true + + /snake-case@3.0.4: + resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + dependencies: + dot-case: 3.0.4 + tslib: 2.8.1 + dev: true + + /source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: true + + /source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + dev: true + + /split@0.3.3: + resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==} + dependencies: + through: 2.3.8 + dev: true + + /spok@1.5.5: + resolution: {integrity: sha512-IrJIXY54sCNFASyHPOY+jEirkiJ26JDqsGiI0Dvhwcnkl0PEWi1PSsrkYql0rzDw8LFVTcA7rdUCAJdE2HE+2Q==} + dependencies: + ansicolors: 0.3.2 + find-process: 1.4.7 + transitivePeerDependencies: + - supports-color + dev: true + + /sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + dev: true + + /stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + dependencies: + escape-string-regexp: 2.0.0 + dev: true + + /start-server-and-test@2.0.9: + resolution: {integrity: sha512-DDceIvc4wdpr+z3Aqkot2QMho8TcUBh5qH0wEHDpEexBTzlheOcmh53d3dExABY4J5C7qS2UbSXqRWLtxpbWIQ==} + engines: {node: '>=16'} + hasBin: true + dependencies: + arg: 5.0.2 + bluebird: 3.7.2 + check-more-types: 2.24.0 + debug: 4.4.0 + execa: 5.1.1 + lazy-ass: 1.6.0 + ps-tree: 1.2.0 + wait-on: 8.0.1(debug@4.4.0) + transitivePeerDependencies: + - supports-color + dev: true + + /stream-combiner@0.0.4: + resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==} + dependencies: + duplexer: 0.1.2 + dev: true + + /string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + dev: true + + /string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + 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.prototype.trim@1.2.9: + resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + dev: true + + /string.prototype.trimend@1.0.8: + resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + dev: true + + /string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + dev: true + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: true + + /strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + dependencies: + ansi-regex: 6.0.1 + dev: true + + /strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + dev: true + + /strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + dev: true + + /strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + dev: true + + /strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + dev: true + + /strip-outer@1.0.1: + resolution: {integrity: sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==} + engines: {node: '>=0.10.0'} + dependencies: + escape-string-regexp: 1.0.5 + dev: true + + /superstruct@0.15.5: + resolution: {integrity: sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ==} + dev: true + + /superstruct@2.0.2: + resolution: {integrity: sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==} + engines: {node: '>=14.0.0'} + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + dependencies: + has-flag: 4.0.0 + + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: true + + /synckit@0.9.1: + resolution: {integrity: sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==} + engines: {node: ^14.18.0 || >=16.0.0} + dependencies: + '@pkgr/core': 0.1.1 + tslib: 2.8.1 + dev: true + + /test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + dev: true + + /text-encoding-utf-8@1.0.2: + resolution: {integrity: sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==} + + /text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + dev: true + + /through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + + /tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + dev: true + + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + dev: true + + /toml@3.0.0: + resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} + dev: true + + /tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + /trim-repeated@1.0.0: + resolution: {integrity: sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==} + engines: {node: '>=0.10.0'} + dependencies: + escape-string-regexp: 1.0.5 + dev: true + + /ts-api-utils@1.3.0(typescript@5.7.2): + resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: 5.7.2 + dev: true + + /ts-api-utils@2.0.0(typescript@5.7.2): + resolution: {integrity: sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + dependencies: + typescript: 5.7.2 + dev: true + + /ts-declaration-location@1.0.4(typescript@5.7.2): + resolution: {integrity: sha512-r4JoxYhKULbZuH81Pjrp9OEG5St7XWk7zXwGkLKhmVcjiBVHTJXV5wK6dEa9JKW5QGSTW6b1lOjxAKp8R1SQhg==} + peerDependencies: + typescript: '>=4.0.0' + dependencies: + minimatch: 10.0.1 + typescript: 5.7.2 + dev: true + + /ts-jest-resolver@2.0.1: + resolution: {integrity: sha512-FolE73BqVZCs8/RbLKxC67iaAtKpBWx7PeLKFW2zJQlOf9j851I7JRxSDenri2NFvVH3QP7v3S8q1AmL24Zb9Q==} + dependencies: + jest-resolve: 29.7.0 + dev: true + + /ts-jest@29.2.5(@babel/core@7.26.0)(jest@29.7.0)(typescript@5.7.2): + resolution: {integrity: sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==} + engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@babel/core': '>=7.0.0-beta.0 <8' + '@jest/transform': ^29.0.0 + '@jest/types': ^29.0.0 + babel-jest: ^29.0.0 + esbuild: '*' + jest: ^29.0.0 + typescript: '>=4.3 <6' + peerDependenciesMeta: + '@babel/core': + optional: true + '@jest/transform': + optional: true + '@jest/types': + optional: true + babel-jest: + optional: true + esbuild: + optional: true + dependencies: + '@babel/core': 7.26.0 + bs-logger: 0.2.6 + ejs: 3.1.10 + fast-json-stable-stringify: 2.1.0 + jest: 29.7.0(@types/node@22.10.5)(ts-node@10.9.2) + jest-util: 29.7.0 + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.6.3 + typescript: 5.7.2 + yargs-parser: 21.1.1 + dev: true + + /ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2): + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.9 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 22.10.5 + acorn: 8.14.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.7.2 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + dev: true + + /tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + dev: true + + /tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + dev: true + + /tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + /tsutils@3.21.0(typescript@5.7.2): + 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: 5.7.2 + dev: true + + /turbo-darwin-64@2.3.3: + resolution: {integrity: sha512-bxX82xe6du/3rPmm4aCC5RdEilIN99VUld4HkFQuw+mvFg6darNBuQxyWSHZTtc25XgYjQrjsV05888w1grpaA==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /turbo-darwin-arm64@2.3.3: + resolution: {integrity: sha512-DYbQwa3NsAuWkCUYVzfOUBbSUBVQzH5HWUFy2Kgi3fGjIWVZOFk86ss+xsWu//rlEAfYwEmopigsPYSmW4X15A==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /turbo-linux-64@2.3.3: + resolution: {integrity: sha512-eHj9OIB0dFaP6BxB88jSuaCLsOQSYWBgmhy2ErCu6D2GG6xW3b6e2UWHl/1Ho9FsTg4uVgo4DB9wGsKa5erjUA==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /turbo-linux-arm64@2.3.3: + resolution: {integrity: sha512-NmDE/NjZoDj1UWBhMtOPmqFLEBKhzGS61KObfrDEbXvU3lekwHeoPvAMfcovzswzch+kN2DrtbNIlz+/rp8OCg==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /turbo-windows-64@2.3.3: + resolution: {integrity: sha512-O2+BS4QqjK3dOERscXqv7N2GXNcqHr9hXumkMxDj/oGx9oCatIwnnwx34UmzodloSnJpgSqjl8iRWiY65SmYoQ==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /turbo-windows-arm64@2.3.3: + resolution: {integrity: sha512-dW4ZK1r6XLPNYLIKjC4o87HxYidtRRcBeo/hZ9Wng2XM/MqqYkAyzJXJGgRMsc0MMEN9z4+ZIfnSNBrA0b08ag==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /turbo@2.3.3: + resolution: {integrity: sha512-DUHWQAcC8BTiUZDRzAYGvpSpGLiaOQPfYXlCieQbwUvmml/LRGIe3raKdrOPOoiX0DYlzxs2nH6BoWJoZrj8hA==} + hasBin: true + optionalDependencies: + turbo-darwin-64: 2.3.3 + turbo-darwin-arm64: 2.3.3 + turbo-linux-64: 2.3.3 + turbo-linux-arm64: 2.3.3 + turbo-windows-64: 2.3.3 + turbo-windows-arm64: 2.3.3 + dev: true + + /type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + dev: true + + /type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + dev: true + + /type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + dev: true + + /type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + dev: true + + /typed-array-buffer@1.0.2: + resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-typed-array: 1.1.13 + dev: true + + /typed-array-byte-length@1.0.1: + resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + dev: true + + /typed-array-byte-offset@1.0.2: + resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + dev: true + + /typed-array-length@1.0.6: + resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + possible-typed-array-names: 1.0.0 + dev: true + + /typedoc@0.27.6(typescript@5.7.2): + resolution: {integrity: sha512-oBFRoh2Px6jFx366db0lLlihcalq/JzyCVp7Vaq1yphL/tbgx2e+bkpkCgJPunaPvPwoTOXSwasfklWHm7GfAw==} + engines: {node: '>= 18'} + hasBin: true + peerDependencies: + typescript: 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x + dependencies: + '@gerrit0/mini-shiki': 1.24.1 + lunr: 2.3.9 + markdown-it: 14.1.0 + minimatch: 9.0.5 + typescript: 5.7.2 + yaml: 2.6.1 + dev: true + + /typescript-collections@1.3.3: + resolution: {integrity: sha512-7sI4e/bZijOzyURng88oOFZCISQPTHozfE2sUu5AviFYk5QV7fYGb6YiDl+vKjF/pICA354JImBImL9XJWUvdQ==} + dev: false + + /typescript-eslint@8.12.2(eslint@9.13.0)(typescript@5.7.2): + resolution: {integrity: sha512-UbuVUWSrHVR03q9CWx+JDHeO6B/Hr9p4U5lRH++5tq/EbFq1faYZe50ZSBePptgfIKLEti0aPQ3hFgnPVcd8ZQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/eslint-plugin': 8.12.2(@typescript-eslint/parser@8.12.2)(eslint@9.13.0)(typescript@5.7.2) + '@typescript-eslint/parser': 8.12.2(eslint@9.13.0)(typescript@5.7.2) + '@typescript-eslint/utils': 8.12.2(eslint@9.13.0)(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - eslint + - supports-color + dev: true + + /typescript@5.7.2: + resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} + engines: {node: '>=14.17'} + hasBin: true + dev: true + + /uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + dev: true + + /unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + dependencies: + call-bind: 1.0.7 + has-bigints: 1.0.2 + has-symbols: 1.0.3 + which-boxed-primitive: 1.0.2 + dev: true + + /undici-types@6.20.0: + resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + + /universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + dev: true + + /update-browserslist-db@1.1.1(browserslist@4.24.2): + resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.24.2 + escalade: 3.2.0 + picocolors: 1.1.1 + dev: true + + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.1 + 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.6.1 + + /util@0.12.5: + resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + dependencies: + inherits: 2.0.4 + is-arguments: 1.1.1 + is-generator-function: 1.0.10 + is-typed-array: 1.1.13 + which-typed-array: 1.1.15 + + /uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + + /v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + dev: true + + /v8-to-istanbul@9.1.3: + resolution: {integrity: sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==} + engines: {node: '>=10.12.0'} + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + '@types/istanbul-lib-coverage': 2.0.6 + convert-source-map: 2.0.0 + dev: true + + /wait-on@8.0.1(debug@4.4.0): + resolution: {integrity: sha512-1wWQOyR2LVVtaqrcIL2+OM+x7bkpmzVROa0Nf6FryXkS+er5Sa1kzFGjzZRqLnHa3n1rACFLeTwUqE1ETL9Mig==} + engines: {node: '>=12.0.0'} + hasBin: true + dependencies: + axios: 1.7.7(debug@4.4.0) + joi: 17.13.3 + lodash: 4.17.21 + minimist: 1.2.8 + rxjs: 7.8.1 + transitivePeerDependencies: + - debug + dev: true + + /walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + dependencies: + makeerror: 1.0.12 + dev: true + + /webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + /whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + /which-boxed-primitive@1.0.2: + resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + dependencies: + is-bigint: 1.0.4 + is-boolean-object: 1.1.2 + is-number-object: 1.0.7 + is-string: 1.0.7 + is-symbol: 1.0.4 + dev: true + + /which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.2 + + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /workerpool@6.5.1: + resolution: {integrity: sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==} + dev: true + + /wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + 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@4.0.2: + resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + imurmurhash: 0.1.4 + signal-exit: 3.0.7 + dev: true + + /write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + imurmurhash: 0.1.4 + signal-exit: 4.1.0 + dev: true + + /ws@7.5.10: + resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + /ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@5.0.10): + resolution: {integrity: sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dependencies: + bufferutil: 4.0.8 + utf-8-validate: 5.0.10 + + /y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + dev: true + + /yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + dev: true + + /yaml@2.6.1: + resolution: {integrity: sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==} + engines: {node: '>= 14'} + hasBin: true + dev: true + + /yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + dev: true + + /yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + dev: true + + /yargs-unparser@2.0.0: + resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} + engines: {node: '>=10'} + dependencies: + camelcase: 6.3.0 + decamelize: 4.0.0 + flat: 5.0.2 + is-plain-obj: 2.1.0 + dev: true + + /yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + dependencies: + cliui: 7.0.4 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + dev: true + + /yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + dev: true + + /yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + dev: true + + /yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + dev: true diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 00000000000..3e3548b6355 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,11 @@ +packages: + - "account-compression/sdk" + - "libraries/type-length-value/js" + - "name-service/js" + - "single-pool/js/packages/*" + - "stake-pool/js" + - "token/js" + - "token-group/js" + - "token-lending/js" + - "token-metadata/js" + - "token-swap/js" diff --git a/record/README.md b/record/README.md new file mode 100644 index 00000000000..8a80596b395 --- /dev/null +++ b/record/README.md @@ -0,0 +1,2 @@ +NOTE: The record program and clients are now maintained at +[solana-program/record](https://github.com/solana-program/record). diff --git a/record/program/Cargo.toml b/record/program/Cargo.toml deleted file mode 100644 index 4a1b882f2db..00000000000 --- a/record/program/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "spl-record" -version = "0.1.0" -description = "Solana Program Library Record Program" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana-program-library" -license = "Apache-2.0" -edition = "2018" - -[features] -no-entrypoint = [] -test-bpf = [] - -[dependencies] -borsh = "0.9.1" -borsh-derive = "0.9.0" -num-derive = "0.3" -num-traits = "0.2" -solana-program = "1.10.33" -thiserror = "1.0" - -[dev-dependencies] -solana-program-test = "1.10.33" -solana-sdk = "1.10.33" - -[lib] -crate-type = ["cdylib", "lib"] - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] diff --git a/record/program/Xargo.toml b/record/program/Xargo.toml deleted file mode 100644 index 1744f098ae1..00000000000 --- a/record/program/Xargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.bpfel-unknown-unknown.dependencies.std] -features = [] \ No newline at end of file diff --git a/record/program/program-id.md b/record/program/program-id.md deleted file mode 100644 index 09f28307584..00000000000 --- a/record/program/program-id.md +++ /dev/null @@ -1 +0,0 @@ -ReciQBw6sQKH9TVVJQDnbnJ5W7FP539tPHjZhRF4E9r diff --git a/record/program/src/entrypoint.rs b/record/program/src/entrypoint.rs deleted file mode 100644 index e2382fbe4e8..00000000000 --- a/record/program/src/entrypoint.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! Program entrypoint - -#![cfg(all(target_os = "solana", not(feature = "no-entrypoint")))] - -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, pubkey::Pubkey, -}; - -entrypoint!(process_instruction); -fn process_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - instruction_data: &[u8], -) -> ProgramResult { - crate::processor::process_instruction(program_id, accounts, instruction_data) -} diff --git a/record/program/src/error.rs b/record/program/src/error.rs deleted file mode 100644 index 537639154b7..00000000000 --- a/record/program/src/error.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! Error types - -use num_derive::FromPrimitive; -use solana_program::{decode_error::DecodeError, program_error::ProgramError}; -use thiserror::Error; - -/// Errors that may be returned by the program. -#[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] -pub enum RecordError { - /// Incorrect authority provided on update or delete - #[error("Incorrect authority provided on update or delete")] - IncorrectAuthority, - - /// Calculation overflow - #[error("Calculation overflow")] - Overflow, -} -impl From for ProgramError { - fn from(e: RecordError) -> Self { - ProgramError::Custom(e as u32) - } -} -impl DecodeError for RecordError { - fn type_of() -> &'static str { - "Record Error" - } -} diff --git a/record/program/src/instruction.rs b/record/program/src/instruction.rs deleted file mode 100644 index bd86bd7183f..00000000000 --- a/record/program/src/instruction.rs +++ /dev/null @@ -1,173 +0,0 @@ -//! Program instructions - -use crate::id; -use borsh::{BorshDeserialize, BorshSerialize}; -use solana_program::{ - instruction::{AccountMeta, Instruction}, - pubkey::Pubkey, -}; - -/// Instructions supported by the program -#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, PartialEq)] -pub enum RecordInstruction { - /// Create a new record - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` Record account, must be uninitialized - /// 1. `[]` Record authority - Initialize, - - /// Write to the provided record account - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` Record account, must be previously initialized - /// 1. `[signer]` Current record authority - Write { - /// Offset to start writing record, expressed as `u64`. - offset: u64, - /// Data to replace the existing record data - data: Vec, - }, - - /// Update the authority of the provided record account - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` Record account, must be previously initialized - /// 1. `[signer]` Current record authority - /// 2. `[]` New record authority - SetAuthority, - - /// Close the provided record account, draining lamports to recipient account - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` Record account, must be previously initialized - /// 1. `[signer]` Record authority - /// 2. `[]` Receiver of account lamports - CloseAccount, -} - -/// Create a `RecordInstruction::Initialize` instruction -pub fn initialize(record_account: &Pubkey, authority: &Pubkey) -> Instruction { - Instruction::new_with_borsh( - id(), - &RecordInstruction::Initialize, - vec![ - AccountMeta::new(*record_account, false), - AccountMeta::new_readonly(*authority, false), - ], - ) -} - -/// Create a `RecordInstruction::Write` instruction -pub fn write(record_account: &Pubkey, signer: &Pubkey, offset: u64, data: Vec) -> Instruction { - Instruction::new_with_borsh( - id(), - &RecordInstruction::Write { offset, data }, - vec![ - AccountMeta::new(*record_account, false), - AccountMeta::new_readonly(*signer, true), - ], - ) -} - -/// Create a `RecordInstruction::SetAuthority` instruction -pub fn set_authority( - record_account: &Pubkey, - signer: &Pubkey, - new_authority: &Pubkey, -) -> Instruction { - Instruction::new_with_borsh( - id(), - &RecordInstruction::SetAuthority, - vec![ - AccountMeta::new(*record_account, false), - AccountMeta::new_readonly(*signer, true), - AccountMeta::new_readonly(*new_authority, false), - ], - ) -} - -/// Create a `RecordInstruction::CloseAccount` instruction -pub fn close_account(record_account: &Pubkey, signer: &Pubkey, receiver: &Pubkey) -> Instruction { - Instruction::new_with_borsh( - id(), - &RecordInstruction::CloseAccount, - vec![ - AccountMeta::new(*record_account, false), - AccountMeta::new_readonly(*signer, true), - AccountMeta::new(*receiver, false), - ], - ) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::state::tests::TEST_DATA; - use solana_program::program_error::ProgramError; - - #[test] - fn serialize_initialize() { - let instruction = RecordInstruction::Initialize; - let expected = vec![0]; - assert_eq!(instruction.try_to_vec().unwrap(), expected); - assert_eq!( - RecordInstruction::try_from_slice(&expected).unwrap(), - instruction - ); - } - - #[test] - fn serialize_write() { - let data = TEST_DATA.try_to_vec().unwrap(); - let offset = 0u64; - let instruction = RecordInstruction::Write { - offset: 0, - data: data.clone(), - }; - let mut expected = vec![1]; - expected.extend_from_slice(&offset.to_le_bytes()); - expected.append(&mut data.try_to_vec().unwrap()); - assert_eq!(instruction.try_to_vec().unwrap(), expected); - assert_eq!( - RecordInstruction::try_from_slice(&expected).unwrap(), - instruction - ); - } - - #[test] - fn serialize_set_authority() { - let instruction = RecordInstruction::SetAuthority; - let expected = vec![2]; - assert_eq!(instruction.try_to_vec().unwrap(), expected); - assert_eq!( - RecordInstruction::try_from_slice(&expected).unwrap(), - instruction - ); - } - - #[test] - fn serialize_close_account() { - let instruction = RecordInstruction::CloseAccount; - let expected = vec![3]; - assert_eq!(instruction.try_to_vec().unwrap(), expected); - assert_eq!( - RecordInstruction::try_from_slice(&expected).unwrap(), - instruction - ); - } - - #[test] - fn deserialize_invalid_instruction() { - let mut expected = vec![12]; - expected.append(&mut TEST_DATA.try_to_vec().unwrap()); - let err: ProgramError = RecordInstruction::try_from_slice(&expected) - .unwrap_err() - .into(); - assert!(matches!(err, ProgramError::BorshIoError(_))); - } -} diff --git a/record/program/src/lib.rs b/record/program/src/lib.rs deleted file mode 100644 index 94db665098b..00000000000 --- a/record/program/src/lib.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! Record program -#![deny(missing_docs)] - -mod entrypoint; -pub mod error; -pub mod instruction; -pub mod processor; -pub mod state; - -// Export current SDK types for downstream users building with a different SDK version -pub use solana_program; - -solana_program::declare_id!("ReciQBw6sQKH9TVVJQDnbnJ5W7FP539tPHjZhRF4E9r"); diff --git a/record/program/src/processor.rs b/record/program/src/processor.rs deleted file mode 100644 index 9985dd89e34..00000000000 --- a/record/program/src/processor.rs +++ /dev/null @@ -1,121 +0,0 @@ -//! Program state processor - -use { - crate::{ - error::RecordError, - instruction::RecordInstruction, - state::{Data, RecordData}, - }, - borsh::{BorshDeserialize, BorshSerialize}, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - program_error::ProgramError, - program_pack::IsInitialized, - pubkey::Pubkey, - }, -}; - -fn check_authority(authority_info: &AccountInfo, expected_authority: &Pubkey) -> ProgramResult { - if expected_authority != authority_info.key { - msg!("Incorrect record authority provided"); - return Err(RecordError::IncorrectAuthority.into()); - } - if !authority_info.is_signer { - msg!("Record authority signature missing"); - return Err(ProgramError::MissingRequiredSignature); - } - Ok(()) -} - -/// Instruction processor -pub fn process_instruction( - _program_id: &Pubkey, - accounts: &[AccountInfo], - input: &[u8], -) -> ProgramResult { - let instruction = RecordInstruction::try_from_slice(input)?; - let account_info_iter = &mut accounts.iter(); - - match instruction { - RecordInstruction::Initialize => { - msg!("RecordInstruction::Initialize"); - - let data_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - - let mut account_data = RecordData::try_from_slice(*data_info.data.borrow())?; - if account_data.is_initialized() { - msg!("Record account already initialized"); - return Err(ProgramError::AccountAlreadyInitialized); - } - - account_data.authority = *authority_info.key; - account_data.version = RecordData::CURRENT_VERSION; - account_data - .serialize(&mut *data_info.data.borrow_mut()) - .map_err(|e| e.into()) - } - - RecordInstruction::Write { offset, data } => { - msg!("RecordInstruction::Write"); - let data_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - let account_data = RecordData::try_from_slice(&data_info.data.borrow())?; - if !account_data.is_initialized() { - msg!("Record account not initialized"); - return Err(ProgramError::UninitializedAccount); - } - check_authority(authority_info, &account_data.authority)?; - let start = RecordData::WRITABLE_START_INDEX + offset as usize; - let end = start + data.len(); - if end > data_info.data.borrow().len() { - Err(ProgramError::AccountDataTooSmall) - } else { - data_info.data.borrow_mut()[start..end].copy_from_slice(&data); - Ok(()) - } - } - - RecordInstruction::SetAuthority => { - msg!("RecordInstruction::SetAuthority"); - let data_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - let new_authority_info = next_account_info(account_info_iter)?; - let mut account_data = RecordData::try_from_slice(&data_info.data.borrow())?; - if !account_data.is_initialized() { - msg!("Record account not initialized"); - return Err(ProgramError::UninitializedAccount); - } - check_authority(authority_info, &account_data.authority)?; - account_data.authority = *new_authority_info.key; - account_data - .serialize(&mut *data_info.data.borrow_mut()) - .map_err(|e| e.into()) - } - - RecordInstruction::CloseAccount => { - msg!("RecordInstruction::CloseAccount"); - let data_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - let destination_info = next_account_info(account_info_iter)?; - let mut account_data = RecordData::try_from_slice(&data_info.data.borrow())?; - if !account_data.is_initialized() { - msg!("Record not initialized"); - return Err(ProgramError::UninitializedAccount); - } - check_authority(authority_info, &account_data.authority)?; - let destination_starting_lamports = destination_info.lamports(); - let data_lamports = data_info.lamports(); - **data_info.lamports.borrow_mut() = 0; - **destination_info.lamports.borrow_mut() = destination_starting_lamports - .checked_add(data_lamports) - .ok_or(RecordError::Overflow)?; - account_data.data = Data::default(); - account_data - .serialize(&mut *data_info.data.borrow_mut()) - .map_err(|e| e.into()) - } - } -} diff --git a/record/program/src/state.rs b/record/program/src/state.rs deleted file mode 100644 index cdf8fde8864..00000000000 --- a/record/program/src/state.rs +++ /dev/null @@ -1,88 +0,0 @@ -//! Program state -use { - borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, - solana_program::{program_pack::IsInitialized, pubkey::Pubkey}, -}; - -/// Struct wrapping data and providing metadata -#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema, PartialEq)] -pub struct RecordData { - /// Struct version, allows for upgrades to the program - pub version: u8, - - /// The account allowed to update the data - pub authority: Pubkey, - - /// The data contained by the account, could be anything serializable - pub data: Data, -} - -/// Struct just for data -#[derive(Clone, Debug, Default, BorshSerialize, BorshDeserialize, BorshSchema, PartialEq)] -pub struct Data { - /// The data contained by the account, could be anything or serializable - pub bytes: [u8; Self::DATA_SIZE], -} - -impl Data { - /// very small data for easy testing - pub const DATA_SIZE: usize = 8; -} - -impl RecordData { - /// Version to fill in on new created accounts - pub const CURRENT_VERSION: u8 = 1; - - /// Start of writable account data, after version and authority - pub const WRITABLE_START_INDEX: usize = 33; -} - -impl IsInitialized for RecordData { - /// Is initialized - fn is_initialized(&self) -> bool { - self.version == Self::CURRENT_VERSION - } -} - -#[cfg(test)] -pub mod tests { - use super::*; - use solana_program::program_error::ProgramError; - - /// Version for tests - pub const TEST_VERSION: u8 = 1; - /// Pubkey for tests - pub const TEST_PUBKEY: Pubkey = Pubkey::new_from_array([100; 32]); - /// Bytes for tests - pub const TEST_BYTES: [u8; Data::DATA_SIZE] = [42; Data::DATA_SIZE]; - /// Data for tests - pub const TEST_DATA: Data = Data { bytes: TEST_BYTES }; - /// RecordData for tests - pub const TEST_RECORD_DATA: RecordData = RecordData { - version: TEST_VERSION, - authority: TEST_PUBKEY, - data: TEST_DATA, - }; - - #[test] - fn serialize_data() { - let mut expected = vec![TEST_VERSION]; - expected.extend_from_slice(&TEST_PUBKEY.to_bytes()); - expected.extend_from_slice(&TEST_DATA.bytes); - assert_eq!(TEST_RECORD_DATA.try_to_vec().unwrap(), expected); - assert_eq!( - RecordData::try_from_slice(&expected).unwrap(), - TEST_RECORD_DATA - ); - } - - #[test] - fn deserialize_invalid_slice() { - let data = [200; Data::DATA_SIZE - 1]; - let mut expected = vec![TEST_VERSION]; - expected.extend_from_slice(&TEST_PUBKEY.to_bytes()); - expected.extend_from_slice(&data); - let err: ProgramError = RecordData::try_from_slice(&expected).unwrap_err().into(); - assert!(matches!(err, ProgramError::BorshIoError(_))); - } -} diff --git a/record/program/tests/functional.rs b/record/program/tests/functional.rs deleted file mode 100644 index 932f0f3b5bf..00000000000 --- a/record/program/tests/functional.rs +++ /dev/null @@ -1,532 +0,0 @@ -#![cfg(feature = "test-bpf")] - -use { - borsh::BorshSerialize, - solana_program::{ - borsh::get_packed_len, - instruction::{AccountMeta, Instruction, InstructionError}, - pubkey::Pubkey, - rent::Rent, - system_instruction, - }, - solana_program_test::*, - solana_sdk::{ - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, - }, - spl_record::{ - error::RecordError, - id, instruction, - processor::process_instruction, - state::{Data, RecordData}, - }, -}; - -fn program_test() -> ProgramTest { - ProgramTest::new("spl_record", id(), processor!(process_instruction)) -} - -async fn initialize_storage_account( - context: &mut ProgramTestContext, - authority: &Keypair, - account: &Keypair, - data: Data, -) { - let transaction = Transaction::new_signed_with_payer( - &[ - system_instruction::create_account( - &context.payer.pubkey(), - &account.pubkey(), - 1.max(Rent::default().minimum_balance(get_packed_len::())), - get_packed_len::() as u64, - &id(), - ), - instruction::initialize(&account.pubkey(), &authority.pubkey()), - instruction::write( - &account.pubkey(), - &authority.pubkey(), - 0, - data.try_to_vec().unwrap(), - ), - ], - Some(&context.payer.pubkey()), - &[&context.payer, account, authority], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); -} - -#[tokio::test] -async fn initialize_success() { - let mut context = program_test().start_with_context().await; - - let authority = Keypair::new(); - let account = Keypair::new(); - let data = Data { - bytes: [111u8; Data::DATA_SIZE], - }; - initialize_storage_account(&mut context, &authority, &account, data.clone()).await; - let account_data = context - .banks_client - .get_account_data_with_borsh::(account.pubkey()) - .await - .unwrap(); - assert_eq!(account_data.data, data); - assert_eq!(account_data.authority, authority.pubkey()); - assert_eq!(account_data.version, RecordData::CURRENT_VERSION); -} - -#[tokio::test] -async fn initialize_with_seed_success() { - let mut context = program_test().start_with_context().await; - - let authority = Keypair::new(); - let seed = "storage"; - let account = Pubkey::create_with_seed(&authority.pubkey(), seed, &id()).unwrap(); - let data = Data { - bytes: [111u8; Data::DATA_SIZE], - }; - let transaction = Transaction::new_signed_with_payer( - &[ - system_instruction::create_account_with_seed( - &context.payer.pubkey(), - &account, - &authority.pubkey(), - seed, - 1.max(Rent::default().minimum_balance(get_packed_len::())), - get_packed_len::() as u64, - &id(), - ), - instruction::initialize(&account, &authority.pubkey()), - instruction::write(&account, &authority.pubkey(), 0, data.try_to_vec().unwrap()), - ], - Some(&context.payer.pubkey()), - &[&context.payer, &authority], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - let account_data = context - .banks_client - .get_account_data_with_borsh::(account) - .await - .unwrap(); - assert_eq!(account_data.data, data); - assert_eq!(account_data.authority, authority.pubkey()); - assert_eq!(account_data.version, RecordData::CURRENT_VERSION); -} - -#[tokio::test] -async fn initialize_twice_fail() { - let mut context = program_test().start_with_context().await; - - let authority = Keypair::new(); - let account = Keypair::new(); - let data = Data { - bytes: [111u8; Data::DATA_SIZE], - }; - initialize_storage_account(&mut context, &authority, &account, data).await; - let transaction = Transaction::new_signed_with_payer( - &[instruction::initialize( - &account.pubkey(), - &authority.pubkey(), - )], - Some(&context.payer.pubkey()), - &[&context.payer], - context.last_blockhash, - ); - assert_eq!( - context - .banks_client - .process_transaction(transaction) - .await - .unwrap_err() - .unwrap(), - TransactionError::InstructionError(0, InstructionError::AccountAlreadyInitialized) - ); -} - -#[tokio::test] -async fn write_success() { - let mut context = program_test().start_with_context().await; - - let authority = Keypair::new(); - let account = Keypair::new(); - let data = Data { - bytes: [222u8; Data::DATA_SIZE], - }; - initialize_storage_account(&mut context, &authority, &account, data).await; - - let new_data = Data { - bytes: [200u8; Data::DATA_SIZE], - }; - let transaction = Transaction::new_signed_with_payer( - &[instruction::write( - &account.pubkey(), - &authority.pubkey(), - 0, - new_data.try_to_vec().unwrap(), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &authority], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let account_data = context - .banks_client - .get_account_data_with_borsh::(account.pubkey()) - .await - .unwrap(); - assert_eq!(account_data.data, new_data); - assert_eq!(account_data.authority, authority.pubkey()); - assert_eq!(account_data.version, RecordData::CURRENT_VERSION); -} - -#[tokio::test] -async fn write_fail_wrong_authority() { - let mut context = program_test().start_with_context().await; - - let authority = Keypair::new(); - let account = Keypair::new(); - let data = Data { - bytes: [222u8; Data::DATA_SIZE], - }; - initialize_storage_account(&mut context, &authority, &account, data).await; - - let new_data = Data { - bytes: [200u8; Data::DATA_SIZE], - }; - let wrong_authority = Keypair::new(); - let transaction = Transaction::new_signed_with_payer( - &[instruction::write( - &account.pubkey(), - &wrong_authority.pubkey(), - 0, - new_data.try_to_vec().unwrap(), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &wrong_authority], - context.last_blockhash, - ); - assert_eq!( - context - .banks_client - .process_transaction(transaction) - .await - .unwrap_err() - .unwrap(), - TransactionError::InstructionError( - 0, - InstructionError::Custom(RecordError::IncorrectAuthority as u32) - ) - ); -} - -#[tokio::test] -async fn write_fail_unsigned() { - let mut context = program_test().start_with_context().await; - - let authority = Keypair::new(); - let account = Keypair::new(); - let data = Data { - bytes: [222u8; Data::DATA_SIZE], - }; - initialize_storage_account(&mut context, &authority, &account, data).await; - - let data = Data { - bytes: [200u8; Data::DATA_SIZE], - } - .try_to_vec() - .unwrap(); - let transaction = Transaction::new_signed_with_payer( - &[Instruction::new_with_borsh( - id(), - &instruction::RecordInstruction::Write { offset: 0, data }, - vec![ - AccountMeta::new(account.pubkey(), false), - AccountMeta::new_readonly(authority.pubkey(), false), - ], - )], - Some(&context.payer.pubkey()), - &[&context.payer], - context.last_blockhash, - ); - assert_eq!( - context - .banks_client - .process_transaction(transaction) - .await - .unwrap_err() - .unwrap(), - TransactionError::InstructionError(0, InstructionError::MissingRequiredSignature) - ); -} - -#[tokio::test] -async fn close_account_success() { - let mut context = program_test().start_with_context().await; - - let authority = Keypair::new(); - let account = Keypair::new(); - let data = Data { - bytes: [222u8; Data::DATA_SIZE], - }; - initialize_storage_account(&mut context, &authority, &account, data).await; - let recipient = Pubkey::new_unique(); - - let transaction = Transaction::new_signed_with_payer( - &[instruction::close_account( - &account.pubkey(), - &authority.pubkey(), - &recipient, - )], - Some(&context.payer.pubkey()), - &[&context.payer, &authority], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let account = context - .banks_client - .get_account(recipient) - .await - .unwrap() - .unwrap(); - assert_eq!( - account.lamports, - 1.max(Rent::default().minimum_balance(get_packed_len::())) - ); -} - -#[tokio::test] -async fn close_account_fail_wrong_authority() { - let mut context = program_test().start_with_context().await; - - let authority = Keypair::new(); - let account = Keypair::new(); - let data = Data { - bytes: [222u8; Data::DATA_SIZE], - }; - initialize_storage_account(&mut context, &authority, &account, data).await; - - let wrong_authority = Keypair::new(); - let transaction = Transaction::new_signed_with_payer( - &[Instruction::new_with_borsh( - id(), - &instruction::RecordInstruction::CloseAccount, - vec![ - AccountMeta::new(account.pubkey(), false), - AccountMeta::new_readonly(wrong_authority.pubkey(), true), - AccountMeta::new(Pubkey::new_unique(), false), - ], - )], - Some(&context.payer.pubkey()), - &[&context.payer, &wrong_authority], - context.last_blockhash, - ); - assert_eq!( - context - .banks_client - .process_transaction(transaction) - .await - .unwrap_err() - .unwrap(), - TransactionError::InstructionError( - 0, - InstructionError::Custom(RecordError::IncorrectAuthority as u32) - ) - ); -} - -#[tokio::test] -async fn close_account_fail_unsigned() { - let mut context = program_test().start_with_context().await; - - let authority = Keypair::new(); - let account = Keypair::new(); - let data = Data { - bytes: [222u8; Data::DATA_SIZE], - }; - initialize_storage_account(&mut context, &authority, &account, data).await; - - let transaction = Transaction::new_signed_with_payer( - &[Instruction::new_with_borsh( - id(), - &instruction::RecordInstruction::CloseAccount, - vec![ - AccountMeta::new(account.pubkey(), false), - AccountMeta::new_readonly(authority.pubkey(), false), - AccountMeta::new(Pubkey::new_unique(), false), - ], - )], - Some(&context.payer.pubkey()), - &[&context.payer], - context.last_blockhash, - ); - assert_eq!( - context - .banks_client - .process_transaction(transaction) - .await - .unwrap_err() - .unwrap(), - TransactionError::InstructionError(0, InstructionError::MissingRequiredSignature) - ); -} - -#[tokio::test] -async fn set_authority_success() { - let mut context = program_test().start_with_context().await; - - let authority = Keypair::new(); - let account = Keypair::new(); - let data = Data { - bytes: [222u8; Data::DATA_SIZE], - }; - initialize_storage_account(&mut context, &authority, &account, data).await; - let new_authority = Keypair::new(); - - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_authority( - &account.pubkey(), - &authority.pubkey(), - &new_authority.pubkey(), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &authority], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let account_data = context - .banks_client - .get_account_data_with_borsh::(account.pubkey()) - .await - .unwrap(); - assert_eq!(account_data.authority, new_authority.pubkey()); - - let new_data = Data { - bytes: [200u8; Data::DATA_SIZE], - }; - let transaction = Transaction::new_signed_with_payer( - &[instruction::write( - &account.pubkey(), - &new_authority.pubkey(), - 0, - new_data.try_to_vec().unwrap(), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &new_authority], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let account_data = context - .banks_client - .get_account_data_with_borsh::(account.pubkey()) - .await - .unwrap(); - assert_eq!(account_data.data, new_data); - assert_eq!(account_data.authority, new_authority.pubkey()); - assert_eq!(account_data.version, RecordData::CURRENT_VERSION); -} - -#[tokio::test] -async fn set_authority_fail_wrong_authority() { - let mut context = program_test().start_with_context().await; - - let authority = Keypair::new(); - let account = Keypair::new(); - let data = Data { - bytes: [222u8; Data::DATA_SIZE], - }; - initialize_storage_account(&mut context, &authority, &account, data).await; - - let wrong_authority = Keypair::new(); - let transaction = Transaction::new_signed_with_payer( - &[Instruction::new_with_borsh( - id(), - &instruction::RecordInstruction::SetAuthority, - vec![ - AccountMeta::new(account.pubkey(), false), - AccountMeta::new_readonly(wrong_authority.pubkey(), true), - AccountMeta::new(Pubkey::new_unique(), false), - ], - )], - Some(&context.payer.pubkey()), - &[&context.payer, &wrong_authority], - context.last_blockhash, - ); - assert_eq!( - context - .banks_client - .process_transaction(transaction) - .await - .unwrap_err() - .unwrap(), - TransactionError::InstructionError( - 0, - InstructionError::Custom(RecordError::IncorrectAuthority as u32) - ) - ); -} - -#[tokio::test] -async fn set_authority_fail_unsigned() { - let mut context = program_test().start_with_context().await; - - let authority = Keypair::new(); - let account = Keypair::new(); - let data = Data { - bytes: [222u8; Data::DATA_SIZE], - }; - initialize_storage_account(&mut context, &authority, &account, data).await; - - let transaction = Transaction::new_signed_with_payer( - &[Instruction::new_with_borsh( - id(), - &instruction::RecordInstruction::SetAuthority, - vec![ - AccountMeta::new(account.pubkey(), false), - AccountMeta::new_readonly(authority.pubkey(), false), - AccountMeta::new(Pubkey::new_unique(), false), - ], - )], - Some(&context.payer.pubkey()), - &[&context.payer], - context.last_blockhash, - ); - assert_eq!( - context - .banks_client - .process_transaction(transaction) - .await - .unwrap_err() - .unwrap(), - TransactionError::InstructionError(0, InstructionError::MissingRequiredSignature) - ); -} diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 00000000000..1de01fa45c4 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "1.81.0" diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 00000000000..1681821bafe --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,5 @@ +comment_width = 80 +edition = "2021" +group_imports = "One" +imports_granularity = "One" +wrap_comments = true diff --git a/shared-memory/README.md b/shared-memory/README.md index f14a38dbd15..67e29a64066 100644 --- a/shared-memory/README.md +++ b/shared-memory/README.md @@ -4,3 +4,8 @@ A shared-memory program on the Solana blockchain, usable for sharing data between programs or within cross-program invocations. Full documentation is available at https://spl.solana.com/shared-memory + +## Audit + +The repository [README](https://github.com/solana-labs/solana-program-library#audits) +contains information about program audits. diff --git a/shared-memory/program/Cargo.toml b/shared-memory/program/Cargo.toml index 99058d53b6c..b02656a05e9 100644 --- a/shared-memory/program/Cargo.toml +++ b/shared-memory/program/Cargo.toml @@ -2,21 +2,21 @@ name = "spl-shared-memory" version = "2.0.6" description = "Solana Program Library Shared-memory" -authors = ["Solana Maintainers "] +authors = ["Solana Labs Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" license = "Apache-2.0" -edition = "2018" +edition = "2021" [features] -test-bpf = [] +test-sbf = [] [dependencies] -arrayref = "0.3.6" -solana-program = "=1.10.33" +arrayref = "0.3.9" +solana-program = "2.1.0" [dev-dependencies] -solana-program-test = "=1.10.33" -solana-sdk = "=1.10.33" +solana-program-test = "2.1.0" +solana-sdk = "2.1.0" [lib] crate-type = ["cdylib", "lib"] diff --git a/shared-memory/program/src/lib.rs b/shared-memory/program/src/lib.rs index ef0ac92c8cc..ab4d075d619 100644 --- a/shared-memory/program/src/lib.rs +++ b/shared-memory/program/src/lib.rs @@ -1,3 +1,4 @@ +#![allow(clippy::arithmetic_side_effects)] #![deny(missing_docs)] //! Shared memory program for the Solana blockchain. // @@ -7,15 +8,19 @@ // implement the typical `process_instruction` entrypoint. extern crate solana_program; -use arrayref::{array_refs, mut_array_refs}; -use solana_program::{ - declare_id, entrypoint::MAX_PERMITTED_DATA_INCREASE, entrypoint::SUCCESS, - program_error::ProgramError, pubkey::Pubkey, -}; -use std::{ - mem::{align_of, size_of}, - ptr::read, - slice::{from_raw_parts, from_raw_parts_mut}, +use { + arrayref::{array_refs, mut_array_refs}, + solana_program::{ + declare_id, + entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS}, + program_error::ProgramError, + pubkey::Pubkey, + }, + std::{ + mem::{align_of, size_of}, + ptr::read, + slice::{from_raw_parts, from_raw_parts_mut}, + }, }; declare_id!("shmem4EWT2sPdVGvTZCzXXRAURL9G5vpPxNwSeKhHUL"); diff --git a/shared-memory/program/tests/shared-memory.rs b/shared-memory/program/tests/shared-memory.rs index f1a06f07666..cbed1e5d467 100644 --- a/shared-memory/program/tests/shared-memory.rs +++ b/shared-memory/program/tests/shared-memory.rs @@ -1,14 +1,16 @@ -// Program test does not support calling a raw program entrypoint, only `process_instruction` -#![cfg(feature = "test-bpf")] +// Program test does not support calling a raw program entrypoint, only +// `process_instruction` +#![cfg(feature = "test-sbf")] -use solana_program_test::*; -use solana_sdk::{ - account::Account, - instruction::InstructionError, - instruction::{AccountMeta, Instruction}, - pubkey::Pubkey, - signature::Signer, - transaction::{Transaction, TransactionError}, +use { + solana_program_test::*, + solana_sdk::{ + account::Account, + instruction::{AccountMeta, Instruction, InstructionError}, + pubkey::Pubkey, + signature::Signer, + transaction::{Transaction, TransactionError}, + }, }; #[tokio::test] @@ -19,7 +21,7 @@ async fn assert_instruction_count() { let shared_key = Pubkey::new_unique(); let mut program_test = ProgramTest::new( - "spl_shared_memory", // Run the BPF version with `cargo test-bpf` + "spl_shared_memory", // Run the BPF version with `cargo test-sbf` program_id, None, ); @@ -33,7 +35,7 @@ async fn assert_instruction_count() { }, ); program_test.set_compute_max_units(480); - let (mut banks_client, payer, recent_blockhash) = program_test.start().await; + let (banks_client, payer, recent_blockhash) = program_test.start().await; // success let content = vec![42; NUM_TO_SHARE]; @@ -59,7 +61,7 @@ async fn test_helloworld() { let shared_key = Pubkey::new_unique(); let mut program_test = ProgramTest::new( - "spl_shared_memory", // Run the BPF version with `cargo test-bpf` + "spl_shared_memory", // Run the BPF version with `cargo test-sbf` program_id, None, ); @@ -72,7 +74,7 @@ async fn test_helloworld() { ..Account::default() }, ); - let (mut banks_client, payer, recent_blockhash) = program_test.start().await; + let (banks_client, payer, recent_blockhash) = program_test.start().await; // success let content = vec![42; NUM_TO_SHARE]; diff --git a/single-pool/README.md b/single-pool/README.md new file mode 100644 index 00000000000..4c2a2cfad01 --- /dev/null +++ b/single-pool/README.md @@ -0,0 +1,2 @@ +NOTE: The single-pool program and clients are now maintained at +[solana-program/single-pool](https://github.com/solana-program/single-pool). diff --git a/slashing/README.md b/slashing/README.md new file mode 100644 index 00000000000..93dcccf439d --- /dev/null +++ b/slashing/README.md @@ -0,0 +1,2 @@ +NOTE: The slashing program and clients are now maintained at +[solana-program/slashing](https://github.com/solana-program/slashing). diff --git a/stake-pool/README.md b/stake-pool/README.md index 179033a262e..7320995c63c 100644 --- a/stake-pool/README.md +++ b/stake-pool/README.md @@ -1,9 +1,2 @@ -# stake-pool program - -Full documentation is available at https://spl.solana.com/stake-pool - -The command-line interface tool is available in the `./cli` directory. - -Javascript bindings are available in the `./js` directory. - -Python bindings are available in the `./py` directory. +NOTE: The stake-pool program and clients are now maintained at +[solana-program/stake-pool](https://github.com/solana-program/stake-pool). diff --git a/stake-pool/cli/Cargo.toml b/stake-pool/cli/Cargo.toml deleted file mode 100644 index b1c3943ae38..00000000000 --- a/stake-pool/cli/Cargo.toml +++ /dev/null @@ -1,34 +0,0 @@ -[package] -authors = ["Solana Maintainers "] -description = "SPL-Stake-Pool Command-line Utility" -edition = "2018" -homepage = "https://spl.solana.com/stake-pool" -license = "Apache-2.0" -name = "spl-stake-pool-cli" -repository = "https://github.com/solana-labs/solana-program-library" -version = "0.6.4" - -[dependencies] -borsh = "0.9" -clap = "2.33.3" -serde = "1.0.130" -serde_derive = "1.0.130" -serde_json = "1.0.68" -solana-account-decoder = "=1.10.33" -solana-clap-utils = "=1.10.33" -solana-cli-config = "=1.10.33" -solana-cli-output = "=1.10.33" -solana-client = "=1.10.33" -solana-logger = "=1.10.33" -solana-program = "=1.10.33" -solana-remote-wallet = "=1.10.33" -solana-sdk = "=1.10.33" -spl-associated-token-account = { version = "=1.0.5", path="../../associated-token-account/program", features = [ "no-entrypoint" ] } -spl-stake-pool = { version = "=0.6.4", path="../program", features = [ "no-entrypoint" ] } -spl-token = { version = "=3.3.1", path="../../token/program", features = [ "no-entrypoint" ] } -bs58 = "0.4.0" -bincode = "1.3.1" - -[[bin]] -name = "spl-stake-pool" -path = "src/main.rs" diff --git a/stake-pool/cli/README.md b/stake-pool/cli/README.md deleted file mode 100644 index b3ed9f3ff84..00000000000 --- a/stake-pool/cli/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# SPL Stake Pool program command-line utility - -A basic command-line for creating and using SPL Stake Pools. See https://spl.solana.com/stake-pool for more details. - -Under `./scripts`, there are helpful Bash scripts for setting up and running a -stake pool. More information at the -[stake pool quick start guide](https://spl.solana.com/stake-pool/quickstart). diff --git a/stake-pool/cli/scripts/add-validators.sh b/stake-pool/cli/scripts/add-validators.sh deleted file mode 100755 index 4bdcbdf1e1e..00000000000 --- a/stake-pool/cli/scripts/add-validators.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - -# Script to add new validators to a stake pool, given the stake pool keyfile and -# a file listing validator vote account pubkeys - -cd "$(dirname "$0")" || exit -stake_pool_keyfile=$1 -validator_list=$2 # File containing validator vote account addresses, each will be added to the stake pool after creation - -add_validator_stakes () { - stake_pool=$1 - validator_list=$2 - while read -r validator - do - $spl_stake_pool add-validator "$stake_pool" "$validator" - done < "$validator_list" -} - -spl_stake_pool=spl-stake-pool -# Uncomment to use a local build -#spl_stake_pool=../../../target/debug/spl-stake-pool - -stake_pool_pubkey=$(solana-keygen pubkey "$stake_pool_keyfile") -echo "Adding validator stake accounts to the pool" -add_validator_stakes "$stake_pool_pubkey" "$validator_list" diff --git a/stake-pool/cli/scripts/deposit.sh b/stake-pool/cli/scripts/deposit.sh deleted file mode 100755 index 9f316f35349..00000000000 --- a/stake-pool/cli/scripts/deposit.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env bash - -# Script to deposit stakes and SOL into a stake pool, given the stake pool keyfile -# and a path to a file containing a list of validator vote accounts - -cd "$(dirname "$0")" || exit -stake_pool_keyfile=$1 -validator_list=$2 -sol_amount=$3 - -create_keypair () { - if test ! -f "$1" - then - solana-keygen new --no-passphrase -s -o "$1" - fi -} - -create_user_stakes () { - validator_list=$1 - sol_amount=$2 - authority=$3 - while read -r validator - do - create_keypair "$keys_dir/stake_$validator".json - solana create-stake-account "$keys_dir/stake_$validator.json" "$sol_amount" --withdraw-authority "$authority" --stake-authority "$authority" - done < "$validator_list" -} - -delegate_user_stakes () { - validator_list=$1 - authority=$2 - while read -r validator - do - solana delegate-stake --force "$keys_dir/stake_$validator.json" "$validator" --stake-authority "$authority" - done < "$validator_list" -} - -deposit_stakes () { - stake_pool_pubkey=$1 - validator_list=$2 - authority=$3 - while read -r validator - do - stake=$(solana-keygen pubkey "$keys_dir/stake_$validator.json") - $spl_stake_pool deposit-stake "$stake_pool_pubkey" "$stake" --withdraw-authority "$authority" - done < "$validator_list" -} - -keys_dir=keys -stake_pool_pubkey=$(solana-keygen pubkey "$stake_pool_keyfile") - -spl_stake_pool=spl-stake-pool -# Uncomment to use a locally build CLI -#spl_stake_pool=../../../target/debug/spl-stake-pool - -echo "Setting up keys directory $keys_dir" -mkdir -p $keys_dir -authority=$keys_dir/authority.json -echo "Setting up authority for deposited stake accounts at $authority" -create_keypair $authority - -echo "Creating user stake accounts to deposit into the pool" -create_user_stakes "$validator_list" "$sol_amount" $authority -echo "Delegating user stakes so that deposit will work" -delegate_user_stakes "$validator_list" $authority - -echo "Waiting for stakes to activate, this may take awhile depending on the network!" -echo "If you are running on localnet with 32 slots per epoch, wait 12 seconds..." -sleep 12 -echo "Depositing stakes into stake pool" -deposit_stakes "$stake_pool_pubkey" "$validator_list" $authority -echo "Depositing SOL into stake pool" -$spl_stake_pool deposit-sol "$stake_pool_pubkey" "$sol_amount" diff --git a/stake-pool/cli/scripts/rebalance.sh b/stake-pool/cli/scripts/rebalance.sh deleted file mode 100755 index 3db44972227..00000000000 --- a/stake-pool/cli/scripts/rebalance.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash - -# Script to add a certain amount of SOL into a stake pool, given the stake pool -# keyfile and a path to a file containing a list of validator vote accounts - -cd "$(dirname "$0")" || exit -stake_pool_keyfile=$1 -validator_list=$2 -sol_amount=$3 - -spl_stake_pool=spl-stake-pool -# Uncomment to use a locally build CLI -#spl_stake_pool=../../../target/debug/spl-stake-pool - -increase_stakes () { - stake_pool_pubkey=$1 - validator_list=$2 - sol_amount=$3 - while read -r validator - do - $spl_stake_pool increase-validator-stake "$stake_pool_pubkey" "$validator" "$sol_amount" - done < "$validator_list" -} - -stake_pool_pubkey=$(solana-keygen pubkey "$stake_pool_keyfile") -echo "Increasing amount delegated to each validator in stake pool" -increase_stakes "$stake_pool_pubkey" "$validator_list" "$sol_amount" diff --git a/stake-pool/cli/scripts/setup-stake-pool.sh b/stake-pool/cli/scripts/setup-stake-pool.sh deleted file mode 100755 index 0aacb09d064..00000000000 --- a/stake-pool/cli/scripts/setup-stake-pool.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env bash - -# Script to setup a stake pool from scratch. Please modify the parameters to -# create a stake pool to your liking! - -cd "$(dirname "$0")" || exit -command_args=() - -################################################### -### MODIFY PARAMETERS BELOW THIS LINE FOR YOUR POOL -################################################### - -# Epoch fee, assessed as a percentage of rewards earned by the pool every epoch, -# represented as `numerator / denominator` -command_args+=( --epoch-fee-numerator 0 ) -command_args+=( --epoch-fee-denominator 0 ) - -# Withdrawal fee for SOL and stake accounts, represented as `numerator / denominator` -command_args+=( --withdrawal-fee-numerator 0 ) -command_args+=( --withdrawal-fee-denominator 0 ) - -# Deposit fee for SOL and stake accounts, represented as `numerator / denominator` -command_args+=( --deposit-fee-numerator 0 ) -command_args+=( --deposit-fee-denominator 0 ) - -command_args+=( --referral-fee 0 ) # Percentage of deposit fee that goes towards the referrer (a number between 0 and 100, inclusive) - -command_args+=( --max-validators 2950 ) # Maximum number of validators in the stake pool, 2950 is the current maximum possible - -# (Optional) Deposit authority, required to sign all deposits into the pool. -# Setting this variable makes the pool "private" or "restricted". -# Uncomment and set to a valid keypair if you want the pool to be restricted. -#command_args+=( --deposit-authority keys/authority.json ) - -################################################### -### MODIFY PARAMETERS ABOVE THIS LINE FOR YOUR POOL -################################################### - -keys_dir=keys -spl_stake_pool=spl-stake-pool -# Uncomment to use a local build -#spl_stake_pool=../../../target/debug/spl-stake-pool - -mkdir -p $keys_dir - -create_keypair () { - if test ! -f "$1" - then - solana-keygen new --no-passphrase -s -o "$1" - fi -} - -echo "Creating pool" -stake_pool_keyfile=$keys_dir/stake-pool.json -validator_list_keyfile=$keys_dir/validator-list.json -mint_keyfile=$keys_dir/mint.json -reserve_keyfile=$keys_dir/reserve.json -create_keypair $stake_pool_keyfile -create_keypair $validator_list_keyfile -create_keypair $mint_keyfile -create_keypair $reserve_keyfile - -set -ex -$spl_stake_pool \ - create-pool \ - "${command_args[@]}" \ - --pool-keypair "$stake_pool_keyfile" \ - --validator-list-keypair "$validator_list_keyfile" \ - --mint-keypair "$mint_keyfile" \ - --reserve-keypair "$reserve_keyfile" diff --git a/stake-pool/cli/scripts/setup-test-validator.sh b/stake-pool/cli/scripts/setup-test-validator.sh deleted file mode 100755 index 5fd803dd50b..00000000000 --- a/stake-pool/cli/scripts/setup-test-validator.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env bash - -# Script to setup a local solana-test-validator with the stake pool program -# given a maximum number of validators and a file path to store the list of -# test validator vote accounts. - -cd "$(dirname "$0")" || exit -max_validators=$1 -validator_file=$2 - -create_keypair () { - if test ! -f "$1" - then - solana-keygen new --no-passphrase -s -o "$1" - fi -} - -setup_test_validator() { - solana-test-validator -c SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy -c EmiU8AQkB2sswTxVB6aCmsAJftoowZGGDXuytm6X65R3 --url devnet --slots-per-epoch 32 --quiet --reset & - pid=$! - solana config set --url http://127.0.0.1:8899 - solana config set --commitment confirmed - echo "waiting for solana-test-validator, pid: $pid" - sleep 5 -} - -create_vote_accounts () { - max_validators=$1 - validator_file=$2 - for number in $(seq 1 "$max_validators") - do - create_keypair "$keys_dir/identity_$number.json" - create_keypair "$keys_dir/vote_$number.json" - create_keypair "$keys_dir/withdrawer_$number.json" - solana create-vote-account "$keys_dir/vote_$number.json" "$keys_dir/identity_$number.json" "$keys_dir/withdrawer_$number.json" --commission 1 - vote_pubkey=$(solana-keygen pubkey "$keys_dir/vote_$number.json") - echo "$vote_pubkey" >> "$validator_file" - done -} - - -echo "Setup keys directory and clear old validator list file if found" -keys_dir=keys -mkdir -p $keys_dir -if test -f "$validator_file" -then - rm "$validator_file" -fi - -echo "Setting up local test validator" -setup_test_validator - -echo "Creating vote accounts, these accounts be added to the stake pool" -create_vote_accounts "$max_validators" "$validator_file" - -echo "Done adding $max_validators validator vote accounts, their pubkeys can be found in $validator_file" diff --git a/stake-pool/cli/scripts/withdraw.sh b/stake-pool/cli/scripts/withdraw.sh deleted file mode 100755 index deeee7a0c5f..00000000000 --- a/stake-pool/cli/scripts/withdraw.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash - -# Script to withdraw stakes and SOL from a stake pool, given the stake pool public key -# and a path to a file containing a list of validator vote accounts - -cd "$(dirname "$0")" || exit -stake_pool_keyfile=$1 -validator_list=$2 -withdraw_sol_amount=$3 - -create_keypair () { - if test ! -f "$1" - then - solana-keygen new --no-passphrase -s -o "$1" - fi -} - -withdraw_stakes () { - stake_pool_pubkey=$1 - validator_list=$2 - pool_amount=$3 - while read -r validator - do - $spl_stake_pool withdraw-stake "$stake_pool_pubkey" "$pool_amount" --vote-account "$validator" - done < "$validator_list" -} - -stake_pool_pubkey=$(solana-keygen pubkey "$stake_pool_keyfile") -keys_dir=keys - -spl_stake_pool=spl-stake-pool -# Uncomment to use a locally build CLI -#spl_stake_pool=../../../target/debug/spl-stake-pool - -echo "Setting up keys directory $keys_dir" -mkdir -p $keys_dir -authority=$keys_dir/authority.json -echo "Setting up authority for withdrawn stake accounts at $authority" -create_keypair $authority - -echo "Withdrawing stakes from stake pool" -withdraw_stakes "$stake_pool_pubkey" "$validator_list" "$withdraw_sol_amount" -echo "Withdrawing SOL from stake pool to authority" -$spl_stake_pool withdraw-sol "$stake_pool_pubkey" $authority "$withdraw_sol_amount" diff --git a/stake-pool/cli/src/client.rs b/stake-pool/cli/src/client.rs deleted file mode 100644 index 005d890896e..00000000000 --- a/stake-pool/cli/src/client.rs +++ /dev/null @@ -1,152 +0,0 @@ -use { - bincode::deserialize, - solana_account_decoder::UiAccountEncoding, - solana_client::{ - client_error::ClientError, - rpc_client::RpcClient, - rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig}, - rpc_filter::{Memcmp, MemcmpEncodedBytes, MemcmpEncoding, RpcFilterType}, - }, - solana_program::{borsh::try_from_slice_unchecked, program_pack::Pack, pubkey::Pubkey, stake}, - spl_stake_pool::{ - find_withdraw_authority_program_address, - state::{StakePool, ValidatorList}, - }, - std::collections::HashSet, -}; - -type Error = Box; - -pub fn get_stake_pool( - rpc_client: &RpcClient, - stake_pool_address: &Pubkey, -) -> Result { - let account_data = rpc_client.get_account_data(stake_pool_address)?; - let stake_pool = try_from_slice_unchecked::(account_data.as_slice()) - .map_err(|err| format!("Invalid stake pool {}: {}", stake_pool_address, err))?; - Ok(stake_pool) -} - -pub fn get_validator_list( - rpc_client: &RpcClient, - validator_list_address: &Pubkey, -) -> Result { - let account_data = rpc_client.get_account_data(validator_list_address)?; - let validator_list = try_from_slice_unchecked::(account_data.as_slice()) - .map_err(|err| format!("Invalid validator list {}: {}", validator_list_address, err))?; - Ok(validator_list) -} - -pub fn get_token_account( - rpc_client: &RpcClient, - token_account_address: &Pubkey, - expected_token_mint: &Pubkey, -) -> Result { - let account_data = rpc_client.get_account_data(token_account_address)?; - let token_account = spl_token::state::Account::unpack_from_slice(account_data.as_slice()) - .map_err(|err| format!("Invalid token account {}: {}", token_account_address, err))?; - - if token_account.mint != *expected_token_mint { - Err(format!( - "Invalid token mint for {}, expected mint is {}", - token_account_address, expected_token_mint - ) - .into()) - } else { - Ok(token_account) - } -} - -pub fn get_token_mint( - rpc_client: &RpcClient, - token_mint_address: &Pubkey, -) -> Result { - let account_data = rpc_client.get_account_data(token_mint_address)?; - let token_mint = spl_token::state::Mint::unpack_from_slice(account_data.as_slice()) - .map_err(|err| format!("Invalid token mint {}: {}", token_mint_address, err))?; - - Ok(token_mint) -} - -pub(crate) fn get_stake_state( - rpc_client: &RpcClient, - stake_address: &Pubkey, -) -> Result { - let account_data = rpc_client.get_account_data(stake_address)?; - let stake_state = deserialize(account_data.as_slice()) - .map_err(|err| format!("Invalid stake account {}: {}", stake_address, err))?; - Ok(stake_state) -} - -pub(crate) fn get_stake_pools( - rpc_client: &RpcClient, -) -> Result, ClientError> { - rpc_client - .get_program_accounts_with_config( - &spl_stake_pool::id(), - RpcProgramAccountsConfig { - filters: Some(vec![RpcFilterType::Memcmp(Memcmp { - offset: 0, // 0 is the account type - bytes: MemcmpEncodedBytes::Base58("2".to_string()), - encoding: None, - })]), - account_config: RpcAccountInfoConfig { - encoding: Some(UiAccountEncoding::Base64), - ..RpcAccountInfoConfig::default() - }, - ..RpcProgramAccountsConfig::default() - }, - ) - .map(|accounts| { - accounts - .into_iter() - .filter_map(|(address, account)| { - let pool_withdraw_authority = - find_withdraw_authority_program_address(&spl_stake_pool::id(), &address).0; - match try_from_slice_unchecked::(account.data.as_slice()) { - Ok(stake_pool) => { - get_validator_list(rpc_client, &stake_pool.validator_list) - .map(|validator_list| { - (address, stake_pool, validator_list, pool_withdraw_authority) - }) - .ok() - } - Err(err) => { - eprintln!("Invalid stake pool data for {}: {}", address, err); - None - } - } - }) - .collect() - }) -} - -pub(crate) fn get_all_stake( - rpc_client: &RpcClient, - authorized_staker: &Pubkey, -) -> Result, ClientError> { - let all_stake_accounts = rpc_client.get_program_accounts_with_config( - &stake::program::id(), - RpcProgramAccountsConfig { - filters: Some(vec![ - // Filter by `Meta::authorized::staker`, which begins at byte offset 12 - RpcFilterType::Memcmp(Memcmp { - offset: 12, - bytes: MemcmpEncodedBytes::Base58(authorized_staker.to_string()), - encoding: Some(MemcmpEncoding::Binary), - }), - ]), - account_config: RpcAccountInfoConfig { - encoding: Some(solana_account_decoder::UiAccountEncoding::Base64), - commitment: Some(rpc_client.commitment()), - ..RpcAccountInfoConfig::default() - }, - ..RpcProgramAccountsConfig::default() - }, - )?; - - Ok(all_stake_accounts - .into_iter() - .map(|(address, _)| address) - .collect()) -} diff --git a/stake-pool/cli/src/main.rs b/stake-pool/cli/src/main.rs deleted file mode 100644 index 299d0aac6c6..00000000000 --- a/stake-pool/cli/src/main.rs +++ /dev/null @@ -1,2956 +0,0 @@ -mod client; -mod output; - -use { - crate::{ - client::*, - output::{CliStakePool, CliStakePoolDetails, CliStakePoolStakeAccountInfo, CliStakePools}, - }, - clap::{ - crate_description, crate_name, crate_version, value_t, value_t_or_exit, App, AppSettings, - Arg, ArgGroup, ArgMatches, SubCommand, - }, - solana_clap_utils::{ - input_parsers::{keypair_of, pubkey_of}, - input_validators::{ - is_amount, is_keypair_or_ask_keyword, is_parsable, is_pubkey, is_url, - is_valid_percentage, is_valid_pubkey, is_valid_signer, - }, - keypair::{signer_from_path_with_config, SignerFromPathConfig}, - }, - solana_cli_output::OutputFormat, - solana_client::rpc_client::RpcClient, - solana_program::{ - borsh::{get_instance_packed_len, get_packed_len}, - instruction::Instruction, - program_pack::Pack, - pubkey::Pubkey, - stake, - }, - solana_remote_wallet::remote_wallet::RemoteWalletManager, - solana_sdk::{ - commitment_config::CommitmentConfig, - hash::Hash, - message::Message, - native_token::{self, Sol}, - signature::{Keypair, Signer}, - signers::Signers, - system_instruction, - transaction::Transaction, - }, - spl_associated_token_account::get_associated_token_address, - spl_stake_pool::state::ValidatorStakeInfo, - spl_stake_pool::{ - self, find_stake_program_address, find_transient_stake_program_address, - find_withdraw_authority_program_address, - instruction::{FundingType, PreferredValidatorType}, - state::{Fee, FeeType, StakePool, ValidatorList}, - MINIMUM_ACTIVE_STAKE, MINIMUM_RESERVE_LAMPORTS, - }, - std::cmp::Ordering, - std::{process::exit, sync::Arc}, -}; -// use instruction::create_associated_token_account once ATA 1.0.5 is released -#[allow(deprecated)] -use spl_associated_token_account::create_associated_token_account; - -pub(crate) struct Config { - rpc_client: RpcClient, - verbose: bool, - output_format: OutputFormat, - manager: Box, - staker: Box, - funding_authority: Option>, - token_owner: Box, - fee_payer: Box, - dry_run: bool, - no_update: bool, -} - -type Error = Box; -type CommandResult = Result<(), Error>; - -const STAKE_STATE_LEN: usize = 200; - -macro_rules! unique_signers { - ($vec:ident) => { - $vec.sort_by_key(|l| l.pubkey()); - $vec.dedup(); - }; -} - -fn check_fee_payer_balance(config: &Config, required_balance: u64) -> Result<(), Error> { - let balance = config.rpc_client.get_balance(&config.fee_payer.pubkey())?; - if balance < required_balance { - Err(format!( - "Fee payer, {}, has insufficient balance: {} required, {} available", - config.fee_payer.pubkey(), - Sol(required_balance), - Sol(balance) - ) - .into()) - } else { - Ok(()) - } -} - -const FEES_REFERENCE: &str = "Consider setting a minimal fee. \ - See https://spl.solana.com/stake-pool/fees for more \ - information about fees and best practices. If you are \ - aware of the possible risks of a stake pool with no fees, \ - you may force pool creation with the --unsafe-fees flag."; - -fn check_stake_pool_fees( - epoch_fee: &Fee, - withdrawal_fee: &Fee, - deposit_fee: &Fee, -) -> Result<(), Error> { - if epoch_fee.numerator == 0 || epoch_fee.denominator == 0 { - return Err(format!("Epoch fee should not be 0. {}", FEES_REFERENCE,).into()); - } - let is_withdrawal_fee_zero = withdrawal_fee.numerator == 0 || withdrawal_fee.denominator == 0; - let is_deposit_fee_zero = deposit_fee.numerator == 0 || deposit_fee.denominator == 0; - if is_withdrawal_fee_zero && is_deposit_fee_zero { - return Err(format!( - "Withdrawal and deposit fee should not both be 0. {}", - FEES_REFERENCE, - ) - .into()); - } - Ok(()) -} - -fn get_signer( - matches: &ArgMatches<'_>, - keypair_name: &str, - keypair_path: &str, - wallet_manager: &mut Option>, - signer_from_path_config: SignerFromPathConfig, -) -> Box { - signer_from_path_with_config( - matches, - matches.value_of(keypair_name).unwrap_or(keypair_path), - keypair_name, - wallet_manager, - &signer_from_path_config, - ) - .unwrap_or_else(|e| { - eprintln!("error: {}", e); - exit(1); - }) -} - -fn get_latest_blockhash(client: &RpcClient) -> Result { - Ok(client - .get_latest_blockhash_with_commitment(CommitmentConfig::confirmed())? - .0) -} - -fn send_transaction_no_wait( - config: &Config, - transaction: Transaction, -) -> solana_client::client_error::Result<()> { - if config.dry_run { - let result = config.rpc_client.simulate_transaction(&transaction)?; - println!("Simulate result: {:?}", result); - } else { - let signature = config.rpc_client.send_transaction(&transaction)?; - println!("Signature: {}", signature); - } - Ok(()) -} - -fn send_transaction( - config: &Config, - transaction: Transaction, -) -> solana_client::client_error::Result<()> { - if config.dry_run { - let result = config.rpc_client.simulate_transaction(&transaction)?; - println!("Simulate result: {:?}", result); - } else { - let signature = config - .rpc_client - .send_and_confirm_transaction_with_spinner(&transaction)?; - println!("Signature: {}", signature); - } - Ok(()) -} - -fn checked_transaction_with_signers( - config: &Config, - instructions: &[Instruction], - signers: &T, -) -> Result { - let recent_blockhash = get_latest_blockhash(&config.rpc_client)?; - let message = Message::new_with_blockhash( - instructions, - Some(&config.fee_payer.pubkey()), - &recent_blockhash, - ); - check_fee_payer_balance(config, config.rpc_client.get_fee_for_message(&message)?)?; - let transaction = Transaction::new(signers, message, recent_blockhash); - Ok(transaction) -} - -fn new_stake_account( - fee_payer: &Pubkey, - instructions: &mut Vec, - lamports: u64, -) -> Keypair { - // Account for tokens not specified, creating one - let stake_receiver_keypair = Keypair::new(); - let stake_receiver_pubkey = stake_receiver_keypair.pubkey(); - println!( - "Creating account to receive stake {}", - stake_receiver_pubkey - ); - - instructions.push( - // Creating new account - system_instruction::create_account( - fee_payer, - &stake_receiver_pubkey, - lamports, - STAKE_STATE_LEN as u64, - &stake::program::id(), - ), - ); - - stake_receiver_keypair -} - -#[allow(clippy::too_many_arguments)] -fn command_create_pool( - config: &Config, - deposit_authority: Option, - epoch_fee: Fee, - withdrawal_fee: Fee, - deposit_fee: Fee, - referral_fee: u8, - max_validators: u32, - stake_pool_keypair: Option, - validator_list_keypair: Option, - mint_keypair: Option, - reserve_keypair: Option, - unsafe_fees: bool, -) -> CommandResult { - if !unsafe_fees { - check_stake_pool_fees(&epoch_fee, &withdrawal_fee, &deposit_fee)?; - } - let reserve_keypair = reserve_keypair.unwrap_or_else(Keypair::new); - println!("Creating reserve stake {}", reserve_keypair.pubkey()); - - let mint_keypair = mint_keypair.unwrap_or_else(Keypair::new); - println!("Creating mint {}", mint_keypair.pubkey()); - - let stake_pool_keypair = stake_pool_keypair.unwrap_or_else(Keypair::new); - - let validator_list_keypair = validator_list_keypair.unwrap_or_else(Keypair::new); - - let reserve_stake_balance = config - .rpc_client - .get_minimum_balance_for_rent_exemption(STAKE_STATE_LEN)? - + MINIMUM_RESERVE_LAMPORTS; - let mint_account_balance = config - .rpc_client - .get_minimum_balance_for_rent_exemption(spl_token::state::Mint::LEN)?; - let pool_fee_account_balance = config - .rpc_client - .get_minimum_balance_for_rent_exemption(spl_token::state::Account::LEN)?; - let stake_pool_account_lamports = config - .rpc_client - .get_minimum_balance_for_rent_exemption(get_packed_len::())?; - let empty_validator_list = ValidatorList::new(max_validators); - let validator_list_size = get_instance_packed_len(&empty_validator_list)?; - let validator_list_balance = config - .rpc_client - .get_minimum_balance_for_rent_exemption(validator_list_size)?; - let mut total_rent_free_balances = reserve_stake_balance - + mint_account_balance - + pool_fee_account_balance - + stake_pool_account_lamports - + validator_list_balance; - - let default_decimals = spl_token::native_mint::DECIMALS; - - // Calculate withdraw authority used for minting pool tokens - let (withdraw_authority, _) = find_withdraw_authority_program_address( - &spl_stake_pool::id(), - &stake_pool_keypair.pubkey(), - ); - - if config.verbose { - println!("Stake pool withdraw authority {}", withdraw_authority); - } - - let mut instructions = vec![ - // Account for the stake pool reserve - system_instruction::create_account( - &config.fee_payer.pubkey(), - &reserve_keypair.pubkey(), - reserve_stake_balance, - STAKE_STATE_LEN as u64, - &stake::program::id(), - ), - stake::instruction::initialize( - &reserve_keypair.pubkey(), - &stake::state::Authorized { - staker: withdraw_authority, - withdrawer: withdraw_authority, - }, - &stake::state::Lockup::default(), - ), - // Account for the stake pool mint - system_instruction::create_account( - &config.fee_payer.pubkey(), - &mint_keypair.pubkey(), - mint_account_balance, - spl_token::state::Mint::LEN as u64, - &spl_token::id(), - ), - // Initialize pool token mint account - spl_token::instruction::initialize_mint( - &spl_token::id(), - &mint_keypair.pubkey(), - &withdraw_authority, - None, - default_decimals, - )?, - ]; - - let pool_fee_account = add_associated_token_account( - config, - &mint_keypair.pubkey(), - &config.manager.pubkey(), - &mut instructions, - &mut total_rent_free_balances, - ); - println!("Creating pool fee collection account {}", pool_fee_account); - - let recent_blockhash = get_latest_blockhash(&config.rpc_client)?; - let setup_message = Message::new_with_blockhash( - &instructions, - Some(&config.fee_payer.pubkey()), - &recent_blockhash, - ); - let initialize_message = Message::new_with_blockhash( - &[ - // Validator stake account list storage - system_instruction::create_account( - &config.fee_payer.pubkey(), - &validator_list_keypair.pubkey(), - validator_list_balance, - validator_list_size as u64, - &spl_stake_pool::id(), - ), - // Account for the stake pool - system_instruction::create_account( - &config.fee_payer.pubkey(), - &stake_pool_keypair.pubkey(), - stake_pool_account_lamports, - get_packed_len::() as u64, - &spl_stake_pool::id(), - ), - // Initialize stake pool - spl_stake_pool::instruction::initialize( - &spl_stake_pool::id(), - &stake_pool_keypair.pubkey(), - &config.manager.pubkey(), - &config.staker.pubkey(), - &withdraw_authority, - &validator_list_keypair.pubkey(), - &reserve_keypair.pubkey(), - &mint_keypair.pubkey(), - &pool_fee_account, - &spl_token::id(), - deposit_authority.as_ref().map(|x| x.pubkey()), - epoch_fee, - withdrawal_fee, - deposit_fee, - referral_fee, - max_validators, - ), - ], - Some(&config.fee_payer.pubkey()), - &recent_blockhash, - ); - check_fee_payer_balance( - config, - total_rent_free_balances - + config.rpc_client.get_fee_for_message(&setup_message)? - + config.rpc_client.get_fee_for_message(&initialize_message)?, - )?; - let mut setup_signers = vec![config.fee_payer.as_ref(), &mint_keypair, &reserve_keypair]; - unique_signers!(setup_signers); - let setup_transaction = Transaction::new(&setup_signers, setup_message, recent_blockhash); - let mut initialize_signers = vec![ - config.fee_payer.as_ref(), - &stake_pool_keypair, - &validator_list_keypair, - config.manager.as_ref(), - ]; - let initialize_transaction = if let Some(deposit_authority) = deposit_authority { - println!( - "Deposits will be restricted to {} only, this can be changed using the set-funding-authority command.", - deposit_authority.pubkey() - ); - let mut initialize_signers = initialize_signers.clone(); - initialize_signers.push(&deposit_authority); - unique_signers!(initialize_signers); - Transaction::new(&initialize_signers, initialize_message, recent_blockhash) - } else { - unique_signers!(initialize_signers); - Transaction::new(&initialize_signers, initialize_message, recent_blockhash) - }; - send_transaction(config, setup_transaction)?; - - println!( - "Creating stake pool {} with validator list {}", - stake_pool_keypair.pubkey(), - validator_list_keypair.pubkey() - ); - send_transaction(config, initialize_transaction)?; - Ok(()) -} - -fn command_vsa_add( - config: &Config, - stake_pool_address: &Pubkey, - vote_account: &Pubkey, -) -> CommandResult { - let (stake_account_address, _) = - find_stake_program_address(&spl_stake_pool::id(), vote_account, stake_pool_address); - println!( - "Adding stake account {}, delegated to {}", - stake_account_address, vote_account - ); - let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?; - let validator_list = get_validator_list(&config.rpc_client, &stake_pool.validator_list)?; - if validator_list.contains(vote_account) { - println!( - "Stake pool already contains validator {}, ignoring", - vote_account - ); - return Ok(()); - } - - if !config.no_update { - command_update(config, stake_pool_address, false, false)?; - } - - let mut signers = vec![config.fee_payer.as_ref(), config.staker.as_ref()]; - unique_signers!(signers); - let transaction = checked_transaction_with_signers( - config, - &[ - spl_stake_pool::instruction::add_validator_to_pool_with_vote( - &spl_stake_pool::id(), - &stake_pool, - stake_pool_address, - &config.fee_payer.pubkey(), - vote_account, - ), - ], - &signers, - )?; - - send_transaction(config, transaction)?; - Ok(()) -} - -fn command_vsa_remove( - config: &Config, - stake_pool_address: &Pubkey, - vote_account: &Pubkey, - new_authority: &Option, - stake_receiver: &Option, -) -> CommandResult { - if !config.no_update { - command_update(config, stake_pool_address, false, false)?; - } - - let (stake_account_address, _) = - find_stake_program_address(&spl_stake_pool::id(), vote_account, stake_pool_address); - println!( - "Removing stake account {}, delegated to {}", - stake_account_address, vote_account - ); - - let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?; - - let mut instructions = vec![]; - let mut stake_keypair = None; - - let stake_receiver = stake_receiver.unwrap_or_else(|| { - let new_stake_keypair = new_stake_account( - &config.fee_payer.pubkey(), - &mut instructions, - /* stake_receiver_account_balance = */ 0, - ); - let stake_pubkey = new_stake_keypair.pubkey(); - stake_keypair = Some(new_stake_keypair); - stake_pubkey - }); - - let staker_pubkey = config.staker.pubkey(); - let new_authority = new_authority.as_ref().unwrap_or(&staker_pubkey); - - let validator_list = get_validator_list(&config.rpc_client, &stake_pool.validator_list)?; - let validator_stake_info = validator_list - .find(vote_account) - .ok_or("Vote account not found in validator list")?; - - let mut signers = vec![config.fee_payer.as_ref(), config.staker.as_ref()]; - if let Some(stake_keypair) = stake_keypair.as_ref() { - signers.push(stake_keypair); - } - instructions.push( - // Create new validator stake account address - spl_stake_pool::instruction::remove_validator_from_pool_with_vote( - &spl_stake_pool::id(), - &stake_pool, - stake_pool_address, - vote_account, - new_authority, - validator_stake_info.transient_seed_suffix_start, - &stake_receiver, - ), - ); - unique_signers!(signers); - let transaction = checked_transaction_with_signers(config, &instructions, &signers)?; - send_transaction(config, transaction)?; - Ok(()) -} - -fn command_increase_validator_stake( - config: &Config, - stake_pool_address: &Pubkey, - vote_account: &Pubkey, - amount: f64, -) -> CommandResult { - let lamports = native_token::sol_to_lamports(amount); - if !config.no_update { - command_update(config, stake_pool_address, false, false)?; - } - - let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?; - let validator_list = get_validator_list(&config.rpc_client, &stake_pool.validator_list)?; - let validator_stake_info = validator_list - .find(vote_account) - .ok_or("Vote account not found in validator list")?; - - let mut signers = vec![config.fee_payer.as_ref(), config.staker.as_ref()]; - unique_signers!(signers); - let transaction = checked_transaction_with_signers( - config, - &[ - spl_stake_pool::instruction::increase_validator_stake_with_vote( - &spl_stake_pool::id(), - &stake_pool, - stake_pool_address, - vote_account, - lamports, - validator_stake_info.transient_seed_suffix_start, - ), - ], - &signers, - )?; - send_transaction(config, transaction)?; - Ok(()) -} - -fn command_decrease_validator_stake( - config: &Config, - stake_pool_address: &Pubkey, - vote_account: &Pubkey, - amount: f64, -) -> CommandResult { - let lamports = native_token::sol_to_lamports(amount); - if !config.no_update { - command_update(config, stake_pool_address, false, false)?; - } - - let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?; - let validator_list = get_validator_list(&config.rpc_client, &stake_pool.validator_list)?; - let validator_stake_info = validator_list - .find(vote_account) - .ok_or("Vote account not found in validator list")?; - - let mut signers = vec![config.fee_payer.as_ref(), config.staker.as_ref()]; - unique_signers!(signers); - let transaction = checked_transaction_with_signers( - config, - &[ - spl_stake_pool::instruction::decrease_validator_stake_with_vote( - &spl_stake_pool::id(), - &stake_pool, - stake_pool_address, - vote_account, - lamports, - validator_stake_info.transient_seed_suffix_start, - ), - ], - &signers, - )?; - send_transaction(config, transaction)?; - Ok(()) -} - -fn command_set_preferred_validator( - config: &Config, - stake_pool_address: &Pubkey, - preferred_type: PreferredValidatorType, - vote_address: Option, -) -> CommandResult { - let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?; - let mut signers = vec![config.fee_payer.as_ref(), config.staker.as_ref()]; - unique_signers!(signers); - let transaction = checked_transaction_with_signers( - config, - &[spl_stake_pool::instruction::set_preferred_validator( - &spl_stake_pool::id(), - stake_pool_address, - &config.staker.pubkey(), - &stake_pool.validator_list, - preferred_type, - vote_address, - )], - &signers, - )?; - send_transaction(config, transaction)?; - Ok(()) -} - -fn add_associated_token_account( - config: &Config, - mint: &Pubkey, - owner: &Pubkey, - instructions: &mut Vec, - rent_free_balances: &mut u64, -) -> Pubkey { - // Account for tokens not specified, creating one - let account = get_associated_token_address(owner, mint); - if get_token_account(&config.rpc_client, &account, mint).is_err() { - println!("Creating associated token account {} to receive stake pool tokens of mint {}, owned by {}", account, mint, owner); - - let min_account_balance = config - .rpc_client - .get_minimum_balance_for_rent_exemption(spl_token::state::Account::LEN) - .unwrap(); - - #[allow(deprecated)] - instructions.push(create_associated_token_account( - &config.fee_payer.pubkey(), - owner, - mint, - )); - - *rent_free_balances += min_account_balance; - } else { - println!("Using existing associated token account {} to receive stake pool tokens of mint {}, owned by {}", account, mint, owner); - } - - account -} - -fn command_deposit_stake( - config: &Config, - stake_pool_address: &Pubkey, - stake: &Pubkey, - withdraw_authority: Box, - pool_token_receiver_account: &Option, - referrer_token_account: &Option, -) -> CommandResult { - if !config.no_update { - command_update(config, stake_pool_address, false, false)?; - } - - let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?; - let stake_state = get_stake_state(&config.rpc_client, stake)?; - - if config.verbose { - println!("Depositing stake account {:?}", stake_state); - } - let vote_account = match stake_state { - stake::state::StakeState::Stake(_, stake) => Ok(stake.delegation.voter_pubkey), - _ => Err("Wrong stake account state, must be delegated to validator"), - }?; - - // Check if this vote account has staking account in the pool - let validator_list = get_validator_list(&config.rpc_client, &stake_pool.validator_list)?; - if !validator_list.contains(&vote_account) { - return Err("Stake account for this validator does not exist in the pool.".into()); - } - - // Calculate validator stake account address linked to the pool - let (validator_stake_account, _) = - find_stake_program_address(&spl_stake_pool::id(), &vote_account, stake_pool_address); - - let validator_stake_state = get_stake_state(&config.rpc_client, &validator_stake_account)?; - println!( - "Depositing stake {} into stake pool account {}", - stake, validator_stake_account - ); - if config.verbose { - println!("{:?}", validator_stake_state); - } - - let mut instructions: Vec = vec![]; - let mut signers = vec![config.fee_payer.as_ref(), withdraw_authority.as_ref()]; - - let mut total_rent_free_balances: u64 = 0; - - // Create token account if not specified - let pool_token_receiver_account = - pool_token_receiver_account.unwrap_or(add_associated_token_account( - config, - &stake_pool.pool_mint, - &config.token_owner.pubkey(), - &mut instructions, - &mut total_rent_free_balances, - )); - - let referrer_token_account = referrer_token_account.unwrap_or(pool_token_receiver_account); - - let pool_withdraw_authority = - find_withdraw_authority_program_address(&spl_stake_pool::id(), stake_pool_address).0; - - let mut deposit_instructions = - if let Some(stake_deposit_authority) = config.funding_authority.as_ref() { - signers.push(stake_deposit_authority.as_ref()); - if stake_deposit_authority.pubkey() != stake_pool.stake_deposit_authority { - let error = format!( - "Invalid deposit authority specified, expected {}, received {}", - stake_pool.stake_deposit_authority, - stake_deposit_authority.pubkey() - ); - return Err(error.into()); - } - - spl_stake_pool::instruction::deposit_stake_with_authority( - &spl_stake_pool::id(), - stake_pool_address, - &stake_pool.validator_list, - &stake_deposit_authority.pubkey(), - &pool_withdraw_authority, - stake, - &withdraw_authority.pubkey(), - &validator_stake_account, - &stake_pool.reserve_stake, - &pool_token_receiver_account, - &stake_pool.manager_fee_account, - &referrer_token_account, - &stake_pool.pool_mint, - &spl_token::id(), - ) - } else { - spl_stake_pool::instruction::deposit_stake( - &spl_stake_pool::id(), - stake_pool_address, - &stake_pool.validator_list, - &pool_withdraw_authority, - stake, - &withdraw_authority.pubkey(), - &validator_stake_account, - &stake_pool.reserve_stake, - &pool_token_receiver_account, - &stake_pool.manager_fee_account, - &referrer_token_account, - &stake_pool.pool_mint, - &spl_token::id(), - ) - }; - - instructions.append(&mut deposit_instructions); - - let recent_blockhash = get_latest_blockhash(&config.rpc_client)?; - let message = Message::new_with_blockhash( - &instructions, - Some(&config.fee_payer.pubkey()), - &recent_blockhash, - ); - check_fee_payer_balance( - config, - total_rent_free_balances + config.rpc_client.get_fee_for_message(&message)?, - )?; - unique_signers!(signers); - let transaction = Transaction::new(&signers, message, recent_blockhash); - send_transaction(config, transaction)?; - Ok(()) -} - -fn command_deposit_all_stake( - config: &Config, - stake_pool_address: &Pubkey, - stake_authority: &Pubkey, - withdraw_authority: Box, - pool_token_receiver_account: &Option, - referrer_token_account: &Option, -) -> CommandResult { - if !config.no_update { - command_update(config, stake_pool_address, false, false)?; - } - - let stake_addresses = get_all_stake(&config.rpc_client, stake_authority)?; - let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?; - - // Create token account if not specified - let mut total_rent_free_balances = 0; - let mut create_token_account_instructions = vec![]; - let pool_token_receiver_account = - pool_token_receiver_account.unwrap_or(add_associated_token_account( - config, - &stake_pool.pool_mint, - &config.token_owner.pubkey(), - &mut create_token_account_instructions, - &mut total_rent_free_balances, - )); - if !create_token_account_instructions.is_empty() { - let recent_blockhash = get_latest_blockhash(&config.rpc_client)?; - let message = Message::new_with_blockhash( - &create_token_account_instructions, - Some(&config.fee_payer.pubkey()), - &recent_blockhash, - ); - check_fee_payer_balance( - config, - total_rent_free_balances + config.rpc_client.get_fee_for_message(&message)?, - )?; - let transaction = Transaction::new(&[config.fee_payer.as_ref()], message, recent_blockhash); - send_transaction(config, transaction)?; - } - - let referrer_token_account = referrer_token_account.unwrap_or(pool_token_receiver_account); - - let pool_withdraw_authority = - find_withdraw_authority_program_address(&spl_stake_pool::id(), stake_pool_address).0; - let validator_list = get_validator_list(&config.rpc_client, &stake_pool.validator_list)?; - let mut signers = if let Some(stake_deposit_authority) = config.funding_authority.as_ref() { - if stake_deposit_authority.pubkey() != stake_pool.stake_deposit_authority { - let error = format!( - "Invalid deposit authority specified, expected {}, received {}", - stake_pool.stake_deposit_authority, - stake_deposit_authority.pubkey() - ); - return Err(error.into()); - } - - vec![ - config.fee_payer.as_ref(), - withdraw_authority.as_ref(), - stake_deposit_authority.as_ref(), - ] - } else { - vec![config.fee_payer.as_ref(), withdraw_authority.as_ref()] - }; - unique_signers!(signers); - - for stake_address in stake_addresses { - let stake_state = get_stake_state(&config.rpc_client, &stake_address)?; - - let vote_account = match stake_state { - stake::state::StakeState::Stake(_, stake) => Ok(stake.delegation.voter_pubkey), - _ => Err("Wrong stake account state, must be delegated to validator"), - }?; - - if !validator_list.contains(&vote_account) { - return Err("Stake account for this validator does not exist in the pool.".into()); - } - - // Calculate validator stake account address linked to the pool - let (validator_stake_account, _) = - find_stake_program_address(&spl_stake_pool::id(), &vote_account, stake_pool_address); - - let validator_stake_state = get_stake_state(&config.rpc_client, &validator_stake_account)?; - println!("Depositing user stake {}: {:?}", stake_address, stake_state); - println!( - "..into pool stake {}: {:?}", - validator_stake_account, validator_stake_state - ); - - let instructions = if let Some(stake_deposit_authority) = config.funding_authority.as_ref() - { - spl_stake_pool::instruction::deposit_stake_with_authority( - &spl_stake_pool::id(), - stake_pool_address, - &stake_pool.validator_list, - &stake_deposit_authority.pubkey(), - &pool_withdraw_authority, - &stake_address, - &withdraw_authority.pubkey(), - &validator_stake_account, - &stake_pool.reserve_stake, - &pool_token_receiver_account, - &stake_pool.manager_fee_account, - &referrer_token_account, - &stake_pool.pool_mint, - &spl_token::id(), - ) - } else { - spl_stake_pool::instruction::deposit_stake( - &spl_stake_pool::id(), - stake_pool_address, - &stake_pool.validator_list, - &pool_withdraw_authority, - &stake_address, - &withdraw_authority.pubkey(), - &validator_stake_account, - &stake_pool.reserve_stake, - &pool_token_receiver_account, - &stake_pool.manager_fee_account, - &referrer_token_account, - &stake_pool.pool_mint, - &spl_token::id(), - ) - }; - - let recent_blockhash = get_latest_blockhash(&config.rpc_client)?; - let message = Message::new_with_blockhash( - &instructions, - Some(&config.fee_payer.pubkey()), - &recent_blockhash, - ); - check_fee_payer_balance(config, config.rpc_client.get_fee_for_message(&message)?)?; - let transaction = Transaction::new(&signers, message, recent_blockhash); - send_transaction(config, transaction)?; - } - Ok(()) -} - -fn command_deposit_sol( - config: &Config, - stake_pool_address: &Pubkey, - from: &Option, - pool_token_receiver_account: &Option, - referrer_token_account: &Option, - amount: f64, -) -> CommandResult { - if !config.no_update { - command_update(config, stake_pool_address, false, false)?; - } - - let amount = native_token::sol_to_lamports(amount); - - // Check withdraw_from balance - let from_pubkey = from - .as_ref() - .map_or_else(|| config.fee_payer.pubkey(), |keypair| keypair.pubkey()); - let from_balance = config.rpc_client.get_balance(&from_pubkey)?; - if from_balance < amount { - return Err(format!( - "Not enough SOL to deposit into pool: {}.\nMaximum deposit amount is {} SOL.", - Sol(amount), - Sol(from_balance) - ) - .into()); - } - - let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?; - - let mut instructions: Vec = vec![]; - - // ephemeral SOL account just to do the transfer - let user_sol_transfer = Keypair::new(); - let mut signers = vec![config.fee_payer.as_ref(), &user_sol_transfer]; - if let Some(keypair) = from.as_ref() { - signers.push(keypair) - } - - let mut total_rent_free_balances: u64 = 0; - - // Create the ephemeral SOL account - instructions.push(system_instruction::transfer( - &from_pubkey, - &user_sol_transfer.pubkey(), - amount, - )); - - // Create token account if not specified - let pool_token_receiver_account = - pool_token_receiver_account.unwrap_or(add_associated_token_account( - config, - &stake_pool.pool_mint, - &config.token_owner.pubkey(), - &mut instructions, - &mut total_rent_free_balances, - )); - - let referrer_token_account = referrer_token_account.unwrap_or(pool_token_receiver_account); - - let pool_withdraw_authority = - find_withdraw_authority_program_address(&spl_stake_pool::id(), stake_pool_address).0; - - let deposit_instruction = if let Some(deposit_authority) = config.funding_authority.as_ref() { - let expected_sol_deposit_authority = stake_pool.sol_deposit_authority.ok_or_else(|| { - "SOL deposit authority specified in arguments but stake pool has none".to_string() - })?; - signers.push(deposit_authority.as_ref()); - if deposit_authority.pubkey() != expected_sol_deposit_authority { - let error = format!( - "Invalid deposit authority specified, expected {}, received {}", - expected_sol_deposit_authority, - deposit_authority.pubkey() - ); - return Err(error.into()); - } - - spl_stake_pool::instruction::deposit_sol_with_authority( - &spl_stake_pool::id(), - stake_pool_address, - &deposit_authority.pubkey(), - &pool_withdraw_authority, - &stake_pool.reserve_stake, - &user_sol_transfer.pubkey(), - &pool_token_receiver_account, - &stake_pool.manager_fee_account, - &referrer_token_account, - &stake_pool.pool_mint, - &spl_token::id(), - amount, - ) - } else { - spl_stake_pool::instruction::deposit_sol( - &spl_stake_pool::id(), - stake_pool_address, - &pool_withdraw_authority, - &stake_pool.reserve_stake, - &user_sol_transfer.pubkey(), - &pool_token_receiver_account, - &stake_pool.manager_fee_account, - &referrer_token_account, - &stake_pool.pool_mint, - &spl_token::id(), - amount, - ) - }; - - instructions.push(deposit_instruction); - - let recent_blockhash = get_latest_blockhash(&config.rpc_client)?; - let message = Message::new_with_blockhash( - &instructions, - Some(&config.fee_payer.pubkey()), - &recent_blockhash, - ); - check_fee_payer_balance( - config, - total_rent_free_balances + config.rpc_client.get_fee_for_message(&message)?, - )?; - unique_signers!(signers); - let transaction = Transaction::new(&signers, message, recent_blockhash); - send_transaction(config, transaction)?; - Ok(()) -} - -fn command_list(config: &Config, stake_pool_address: &Pubkey) -> CommandResult { - let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?; - let reserve_stake_account_address = stake_pool.reserve_stake.to_string(); - let total_lamports = stake_pool.total_lamports; - let last_update_epoch = stake_pool.last_update_epoch; - let validator_list = get_validator_list(&config.rpc_client, &stake_pool.validator_list)?; - let max_number_of_validators = validator_list.header.max_validators; - let current_number_of_validators = validator_list.validators.len(); - let pool_mint = get_token_mint(&config.rpc_client, &stake_pool.pool_mint)?; - let epoch_info = config.rpc_client.get_epoch_info()?; - let pool_withdraw_authority = - find_withdraw_authority_program_address(&spl_stake_pool::id(), stake_pool_address).0; - let reserve_stake = config.rpc_client.get_account(&stake_pool.reserve_stake)?; - let minimum_reserve_stake_balance = config - .rpc_client - .get_minimum_balance_for_rent_exemption(STAKE_STATE_LEN)? - + MINIMUM_RESERVE_LAMPORTS; - let cli_stake_pool_stake_account_infos = validator_list - .validators - .iter() - .map(|validator| { - let (stake_account_address, _) = find_stake_program_address( - &spl_stake_pool::id(), - &validator.vote_account_address, - stake_pool_address, - ); - let (transient_stake_account_address, _) = find_transient_stake_program_address( - &spl_stake_pool::id(), - &validator.vote_account_address, - stake_pool_address, - validator.transient_seed_suffix_start, - ); - let update_required = validator.last_update_epoch != epoch_info.epoch; - CliStakePoolStakeAccountInfo { - vote_account_address: validator.vote_account_address.to_string(), - stake_account_address: stake_account_address.to_string(), - validator_active_stake_lamports: validator.active_stake_lamports, - validator_last_update_epoch: validator.last_update_epoch, - validator_lamports: validator.stake_lamports(), - validator_transient_stake_account_address: transient_stake_account_address - .to_string(), - validator_transient_stake_lamports: validator.transient_stake_lamports, - update_required, - } - }) - .collect(); - let total_pool_tokens = - spl_token::amount_to_ui_amount(stake_pool.pool_token_supply, pool_mint.decimals); - let mut cli_stake_pool = CliStakePool::from(( - *stake_pool_address, - stake_pool, - validator_list, - pool_withdraw_authority, - )); - let update_required = last_update_epoch != epoch_info.epoch; - let cli_stake_pool_details = CliStakePoolDetails { - reserve_stake_account_address, - reserve_stake_lamports: reserve_stake.lamports, - minimum_reserve_stake_balance, - stake_accounts: cli_stake_pool_stake_account_infos, - total_lamports, - total_pool_tokens, - current_number_of_validators: current_number_of_validators as u32, - max_number_of_validators, - update_required, - }; - cli_stake_pool.details = Some(cli_stake_pool_details); - println!("{}", config.output_format.formatted_string(&cli_stake_pool)); - Ok(()) -} - -fn command_update( - config: &Config, - stake_pool_address: &Pubkey, - force: bool, - no_merge: bool, -) -> CommandResult { - if config.no_update { - println!("Update requested, but --no-update flag specified, so doing nothing"); - return Ok(()); - } - let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?; - let epoch_info = config.rpc_client.get_epoch_info()?; - - if stake_pool.last_update_epoch == epoch_info.epoch { - if force { - println!("Update not required, but --force flag specified, so doing it anyway"); - } else { - println!("Update not required"); - return Ok(()); - } - } - - let validator_list = get_validator_list(&config.rpc_client, &stake_pool.validator_list)?; - - let (mut update_list_instructions, final_instructions) = - spl_stake_pool::instruction::update_stake_pool( - &spl_stake_pool::id(), - &stake_pool, - &validator_list, - stake_pool_address, - no_merge, - ); - - let update_list_instructions_len = update_list_instructions.len(); - if update_list_instructions_len > 0 { - let last_instruction = update_list_instructions.split_off(update_list_instructions_len - 1); - // send the first ones without waiting - for instruction in update_list_instructions { - let transaction = checked_transaction_with_signers( - config, - &[instruction], - &[config.fee_payer.as_ref()], - )?; - send_transaction_no_wait(config, transaction)?; - } - - // wait on the last one - let transaction = checked_transaction_with_signers( - config, - &last_instruction, - &[config.fee_payer.as_ref()], - )?; - send_transaction(config, transaction)?; - } - let transaction = checked_transaction_with_signers( - config, - &final_instructions, - &[config.fee_payer.as_ref()], - )?; - send_transaction(config, transaction)?; - - Ok(()) -} - -#[derive(PartialEq, Debug)] -struct WithdrawAccount { - stake_address: Pubkey, - vote_address: Option, - pool_amount: u64, -} - -fn sorted_accounts( - validator_list: &ValidatorList, - stake_pool: &StakePool, - get_info: F, -) -> Vec<(Pubkey, u64, Option)> -where - F: Fn(&ValidatorStakeInfo) -> (Pubkey, u64, Option), -{ - let mut result: Vec<(Pubkey, u64, Option)> = validator_list - .validators - .iter() - .map(get_info) - .collect::>(); - - result.sort_by(|left, right| { - if left.2 == stake_pool.preferred_withdraw_validator_vote_address { - Ordering::Less - } else if right.2 == stake_pool.preferred_withdraw_validator_vote_address { - Ordering::Greater - } else { - right.1.cmp(&left.1) - } - }); - - result -} - -fn prepare_withdraw_accounts( - rpc_client: &RpcClient, - stake_pool: &StakePool, - pool_amount: u64, - stake_pool_address: &Pubkey, - skip_fee: bool, -) -> Result, Error> { - let min_balance = rpc_client - .get_minimum_balance_for_rent_exemption(STAKE_STATE_LEN)? - .saturating_add(MINIMUM_ACTIVE_STAKE); - let pool_mint = get_token_mint(rpc_client, &stake_pool.pool_mint)?; - let validator_list: ValidatorList = get_validator_list(rpc_client, &stake_pool.validator_list)?; - - let mut accounts: Vec<(Pubkey, u64, Option)> = Vec::new(); - - accounts.append(&mut sorted_accounts( - &validator_list, - stake_pool, - |validator| { - let (stake_account_address, _) = find_stake_program_address( - &spl_stake_pool::id(), - &validator.vote_account_address, - stake_pool_address, - ); - - ( - stake_account_address, - validator.active_stake_lamports, - Some(validator.vote_account_address), - ) - }, - )); - - accounts.append(&mut sorted_accounts( - &validator_list, - stake_pool, - |validator| { - let (transient_stake_account_address, _) = find_transient_stake_program_address( - &spl_stake_pool::id(), - &validator.vote_account_address, - stake_pool_address, - validator.transient_seed_suffix_start, - ); - - ( - transient_stake_account_address, - validator - .transient_stake_lamports - .saturating_sub(min_balance), - Some(validator.vote_account_address), - ) - }, - )); - - let reserve_stake = rpc_client.get_account(&stake_pool.reserve_stake)?; - - accounts.push(( - stake_pool.reserve_stake, - reserve_stake.lamports - - rpc_client.get_minimum_balance_for_rent_exemption(STAKE_STATE_LEN)? - - MINIMUM_RESERVE_LAMPORTS, - None, - )); - - // Prepare the list of accounts to withdraw from - let mut withdraw_from: Vec = vec![]; - let mut remaining_amount = pool_amount; - - let fee = stake_pool.stake_withdrawal_fee; - let inverse_fee = Fee { - numerator: fee.denominator - fee.numerator, - denominator: fee.denominator, - }; - - // Go through available accounts and withdraw from largest to smallest - for (stake_address, lamports, vote_address_opt) in accounts { - if lamports <= min_balance { - continue; - } - - let available_for_withdrawal_wo_fee = - stake_pool.calc_pool_tokens_for_deposit(lamports).unwrap(); - - let available_for_withdrawal = if skip_fee { - available_for_withdrawal_wo_fee - } else { - available_for_withdrawal_wo_fee * inverse_fee.denominator / inverse_fee.numerator - }; - - let pool_amount = u64::min(available_for_withdrawal, remaining_amount); - - // Those accounts will be withdrawn completely with `claim` instruction - withdraw_from.push(WithdrawAccount { - stake_address, - vote_address: vote_address_opt, - pool_amount, - }); - remaining_amount -= pool_amount; - - if remaining_amount == 0 { - break; - } - } - - // Not enough stake to withdraw the specified amount - if remaining_amount > 0 { - return Err(format!( - "No stake accounts found in this pool with enough balance to withdraw {} pool tokens.", - spl_token::amount_to_ui_amount(pool_amount, pool_mint.decimals) - ) - .into()); - } - - Ok(withdraw_from) -} - -fn command_withdraw_stake( - config: &Config, - stake_pool_address: &Pubkey, - use_reserve: bool, - vote_account_address: &Option, - stake_receiver_param: &Option, - pool_token_account: &Option, - pool_amount: f64, -) -> CommandResult { - if !config.no_update { - command_update(config, stake_pool_address, false, false)?; - } - - let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?; - let pool_mint = get_token_mint(&config.rpc_client, &stake_pool.pool_mint)?; - let pool_amount = spl_token::ui_amount_to_amount(pool_amount, pool_mint.decimals); - - let pool_withdraw_authority = - find_withdraw_authority_program_address(&spl_stake_pool::id(), stake_pool_address).0; - - let pool_token_account = pool_token_account.unwrap_or(get_associated_token_address( - &config.token_owner.pubkey(), - &stake_pool.pool_mint, - )); - let token_account = get_token_account( - &config.rpc_client, - &pool_token_account, - &stake_pool.pool_mint, - )?; - let stake_account_rent_exemption = config - .rpc_client - .get_minimum_balance_for_rent_exemption(STAKE_STATE_LEN)?; - - // Check withdraw_from balance - if token_account.amount < pool_amount { - return Err(format!( - "Not enough token balance to withdraw {} pool tokens.\nMaximum withdraw amount is {} pool tokens.", - spl_token::amount_to_ui_amount(pool_amount, pool_mint.decimals), - spl_token::amount_to_ui_amount(token_account.amount, pool_mint.decimals) - ) - .into()); - } - - let withdraw_accounts = if use_reserve { - vec![WithdrawAccount { - stake_address: stake_pool.reserve_stake, - vote_address: None, - pool_amount, - }] - } else if let Some(vote_account_address) = vote_account_address { - let (stake_account_address, _) = find_stake_program_address( - &spl_stake_pool::id(), - vote_account_address, - stake_pool_address, - ); - let stake_account = config.rpc_client.get_account(&stake_account_address)?; - - let available_for_withdrawal = stake_pool - .calc_lamports_withdraw_amount( - stake_account - .lamports - .saturating_sub(MINIMUM_ACTIVE_STAKE) - .saturating_sub(stake_account_rent_exemption), - ) - .unwrap(); - - if available_for_withdrawal < pool_amount { - return Err(format!( - "Not enough lamports available for withdrawal from {}, {} asked, {} available", - stake_account_address, pool_amount, available_for_withdrawal - ) - .into()); - } - vec![WithdrawAccount { - stake_address: stake_account_address, - vote_address: Some(*vote_account_address), - pool_amount, - }] - } else { - // Get the list of accounts to withdraw from - prepare_withdraw_accounts( - &config.rpc_client, - &stake_pool, - pool_amount, - stake_pool_address, - stake_pool.manager_fee_account == pool_token_account, - )? - }; - - // Construct transaction to withdraw from withdraw_accounts account list - let mut instructions: Vec = vec![]; - let user_transfer_authority = Keypair::new(); // ephemeral keypair just to do the transfer - let mut signers = vec![ - config.fee_payer.as_ref(), - config.token_owner.as_ref(), - &user_transfer_authority, - ]; - let mut new_stake_keypairs = vec![]; - - instructions.push( - // Approve spending token - spl_token::instruction::approve( - &spl_token::id(), - &pool_token_account, - &user_transfer_authority.pubkey(), - &config.token_owner.pubkey(), - &[], - pool_amount, - )?, - ); - - let mut total_rent_free_balances = 0; - - // Go through prepared accounts and withdraw/claim them - for withdraw_account in withdraw_accounts { - // Convert pool tokens amount to lamports - let sol_withdraw_amount = stake_pool - .calc_lamports_withdraw_amount(withdraw_account.pool_amount) - .unwrap(); - - if let Some(vote_address) = withdraw_account.vote_address { - println!( - "Withdrawing {}, or {} pool tokens, from stake account {}, delegated to {}", - Sol(sol_withdraw_amount), - spl_token::amount_to_ui_amount(withdraw_account.pool_amount, pool_mint.decimals), - withdraw_account.stake_address, - vote_address, - ); - } else { - println!( - "Withdrawing {}, or {} pool tokens, from stake account {}", - Sol(sol_withdraw_amount), - spl_token::amount_to_ui_amount(withdraw_account.pool_amount, pool_mint.decimals), - withdraw_account.stake_address, - ); - } - - // Use separate mutable variable because withdraw might create a new account - let stake_receiver = stake_receiver_param.unwrap_or_else(|| { - let stake_keypair = new_stake_account( - &config.fee_payer.pubkey(), - &mut instructions, - stake_account_rent_exemption, - ); - let stake_pubkey = stake_keypair.pubkey(); - total_rent_free_balances += stake_account_rent_exemption; - new_stake_keypairs.push(stake_keypair); - stake_pubkey - }); - - instructions.push(spl_stake_pool::instruction::withdraw_stake( - &spl_stake_pool::id(), - stake_pool_address, - &stake_pool.validator_list, - &pool_withdraw_authority, - &withdraw_account.stake_address, - &stake_receiver, - &config.staker.pubkey(), - &user_transfer_authority.pubkey(), - &pool_token_account, - &stake_pool.manager_fee_account, - &stake_pool.pool_mint, - &spl_token::id(), - withdraw_account.pool_amount, - )); - } - - let recent_blockhash = get_latest_blockhash(&config.rpc_client)?; - let message = Message::new_with_blockhash( - &instructions, - Some(&config.fee_payer.pubkey()), - &recent_blockhash, - ); - for new_stake_keypair in &new_stake_keypairs { - signers.push(new_stake_keypair); - } - check_fee_payer_balance( - config, - total_rent_free_balances + config.rpc_client.get_fee_for_message(&message)?, - )?; - unique_signers!(signers); - let transaction = Transaction::new(&signers, message, recent_blockhash); - send_transaction(config, transaction)?; - Ok(()) -} - -fn command_withdraw_sol( - config: &Config, - stake_pool_address: &Pubkey, - pool_token_account: &Option, - sol_receiver: &Pubkey, - pool_amount: f64, -) -> CommandResult { - if !config.no_update { - command_update(config, stake_pool_address, false, false)?; - } - - let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?; - let pool_mint = get_token_mint(&config.rpc_client, &stake_pool.pool_mint)?; - let pool_amount = spl_token::ui_amount_to_amount(pool_amount, pool_mint.decimals); - - let pool_token_account = pool_token_account.unwrap_or(get_associated_token_address( - &config.token_owner.pubkey(), - &stake_pool.pool_mint, - )); - let token_account = get_token_account( - &config.rpc_client, - &pool_token_account, - &stake_pool.pool_mint, - )?; - - // Check withdraw_from balance - if token_account.amount < pool_amount { - return Err(format!( - "Not enough token balance to withdraw {} pool tokens.\nMaximum withdraw amount is {} pool tokens.", - spl_token::amount_to_ui_amount(pool_amount, pool_mint.decimals), - spl_token::amount_to_ui_amount(token_account.amount, pool_mint.decimals) - ) - .into()); - } - - // Construct transaction to withdraw from withdraw_accounts account list - let user_transfer_authority = Keypair::new(); // ephemeral keypair just to do the transfer - let mut signers = vec![ - config.fee_payer.as_ref(), - config.token_owner.as_ref(), - &user_transfer_authority, - ]; - - let mut instructions = vec![ - // Approve spending token - spl_token::instruction::approve( - &spl_token::id(), - &pool_token_account, - &user_transfer_authority.pubkey(), - &config.token_owner.pubkey(), - &[], - pool_amount, - )?, - ]; - - let pool_withdraw_authority = - find_withdraw_authority_program_address(&spl_stake_pool::id(), stake_pool_address).0; - - let withdraw_instruction = if let Some(withdraw_authority) = config.funding_authority.as_ref() { - let expected_sol_withdraw_authority = - stake_pool.sol_withdraw_authority.ok_or_else(|| { - "SOL withdraw authority specified in arguments but stake pool has none".to_string() - })?; - signers.push(withdraw_authority.as_ref()); - if withdraw_authority.pubkey() != expected_sol_withdraw_authority { - let error = format!( - "Invalid deposit withdraw specified, expected {}, received {}", - expected_sol_withdraw_authority, - withdraw_authority.pubkey() - ); - return Err(error.into()); - } - - spl_stake_pool::instruction::withdraw_sol_with_authority( - &spl_stake_pool::id(), - stake_pool_address, - &withdraw_authority.pubkey(), - &pool_withdraw_authority, - &user_transfer_authority.pubkey(), - &pool_token_account, - &stake_pool.reserve_stake, - sol_receiver, - &stake_pool.manager_fee_account, - &stake_pool.pool_mint, - &spl_token::id(), - pool_amount, - ) - } else { - spl_stake_pool::instruction::withdraw_sol( - &spl_stake_pool::id(), - stake_pool_address, - &pool_withdraw_authority, - &user_transfer_authority.pubkey(), - &pool_token_account, - &stake_pool.reserve_stake, - sol_receiver, - &stake_pool.manager_fee_account, - &stake_pool.pool_mint, - &spl_token::id(), - pool_amount, - ) - }; - - instructions.push(withdraw_instruction); - - let recent_blockhash = get_latest_blockhash(&config.rpc_client)?; - let message = Message::new_with_blockhash( - &instructions, - Some(&config.fee_payer.pubkey()), - &recent_blockhash, - ); - check_fee_payer_balance(config, config.rpc_client.get_fee_for_message(&message)?)?; - unique_signers!(signers); - let transaction = Transaction::new(&signers, message, recent_blockhash); - send_transaction(config, transaction)?; - Ok(()) -} - -fn command_set_manager( - config: &Config, - stake_pool_address: &Pubkey, - new_manager: &Option, - new_fee_receiver: &Option, -) -> CommandResult { - if !config.no_update { - command_update(config, stake_pool_address, false, false)?; - } - let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?; - - // If new accounts are missing in the arguments use the old ones - let (new_manager_pubkey, mut signers): (Pubkey, Vec<&dyn Signer>) = match new_manager { - None => (stake_pool.manager, vec![]), - Some(value) => (value.pubkey(), vec![value]), - }; - let new_fee_receiver = match new_fee_receiver { - None => stake_pool.manager_fee_account, - Some(value) => { - // Check for fee receiver being a valid token account and have to same mint as the stake pool - let token_account = - get_token_account(&config.rpc_client, value, &stake_pool.pool_mint)?; - if token_account.mint != stake_pool.pool_mint { - return Err("Fee receiver account belongs to a different mint" - .to_string() - .into()); - } - *value - } - }; - - signers.append(&mut vec![ - config.fee_payer.as_ref(), - config.manager.as_ref(), - ]); - unique_signers!(signers); - let transaction = checked_transaction_with_signers( - config, - &[spl_stake_pool::instruction::set_manager( - &spl_stake_pool::id(), - stake_pool_address, - &config.manager.pubkey(), - &new_manager_pubkey, - &new_fee_receiver, - )], - &signers, - )?; - send_transaction(config, transaction)?; - Ok(()) -} - -fn command_set_staker( - config: &Config, - stake_pool_address: &Pubkey, - new_staker: &Pubkey, -) -> CommandResult { - if !config.no_update { - command_update(config, stake_pool_address, false, false)?; - } - let mut signers = vec![config.fee_payer.as_ref(), config.manager.as_ref()]; - unique_signers!(signers); - let transaction = checked_transaction_with_signers( - config, - &[spl_stake_pool::instruction::set_staker( - &spl_stake_pool::id(), - stake_pool_address, - &config.manager.pubkey(), - new_staker, - )], - &signers, - )?; - send_transaction(config, transaction)?; - Ok(()) -} - -fn command_set_funding_authority( - config: &Config, - stake_pool_address: &Pubkey, - new_authority: Option, - funding_type: FundingType, -) -> CommandResult { - if !config.no_update { - command_update(config, stake_pool_address, false, false)?; - } - let mut signers = vec![config.fee_payer.as_ref(), config.manager.as_ref()]; - unique_signers!(signers); - let transaction = checked_transaction_with_signers( - config, - &[spl_stake_pool::instruction::set_funding_authority( - &spl_stake_pool::id(), - stake_pool_address, - &config.manager.pubkey(), - new_authority.as_ref(), - funding_type, - )], - &signers, - )?; - send_transaction(config, transaction)?; - Ok(()) -} - -fn command_set_fee( - config: &Config, - stake_pool_address: &Pubkey, - new_fee: FeeType, -) -> CommandResult { - if !config.no_update { - command_update(config, stake_pool_address, false, false)?; - } - let mut signers = vec![config.fee_payer.as_ref(), config.manager.as_ref()]; - unique_signers!(signers); - let transaction = checked_transaction_with_signers( - config, - &[spl_stake_pool::instruction::set_fee( - &spl_stake_pool::id(), - stake_pool_address, - &config.manager.pubkey(), - new_fee, - )], - &signers, - )?; - send_transaction(config, transaction)?; - Ok(()) -} - -fn command_list_all_pools(config: &Config) -> CommandResult { - let all_pools = get_stake_pools(&config.rpc_client)?; - let cli_stake_pool_vec: Vec = - all_pools.into_iter().map(CliStakePool::from).collect(); - let cli_stake_pools = CliStakePools { - pools: cli_stake_pool_vec, - }; - println!( - "{}", - config.output_format.formatted_string(&cli_stake_pools) - ); - Ok(()) -} - -fn main() { - solana_logger::setup_with_default("solana=info"); - - let matches = App::new(crate_name!()) - .about(crate_description!()) - .version(crate_version!()) - .setting(AppSettings::SubcommandRequiredElseHelp) - .arg({ - let arg = Arg::with_name("config_file") - .short("C") - .long("config") - .value_name("PATH") - .takes_value(true) - .global(true) - .help("Configuration file to use"); - if let Some(ref config_file) = *solana_cli_config::CONFIG_FILE { - arg.default_value(config_file) - } else { - arg - } - }) - .arg( - Arg::with_name("verbose") - .long("verbose") - .short("v") - .takes_value(false) - .global(true) - .help("Show additional information"), - ) - .arg( - Arg::with_name("output_format") - .long("output") - .value_name("FORMAT") - .global(true) - .takes_value(true) - .possible_values(&["json", "json-compact"]) - .help("Return information in specified output format"), - ) - .arg( - Arg::with_name("dry_run") - .long("dry-run") - .takes_value(false) - .global(true) - .help("Simulate transaction instead of executing"), - ) - .arg( - Arg::with_name("no_update") - .long("no-update") - .takes_value(false) - .global(true) - .help("Do not automatically update the stake pool if needed"), - ) - .arg( - Arg::with_name("json_rpc_url") - .long("url") - .value_name("URL") - .takes_value(true) - .validator(is_url) - .help("JSON RPC URL for the cluster. Default from the configuration file."), - ) - .arg( - Arg::with_name("staker") - .long("staker") - .value_name("KEYPAIR") - .validator(is_valid_signer) - .takes_value(true) - .help("Stake pool staker. [default: cli config keypair]"), - ) - .arg( - Arg::with_name("manager") - .long("manager") - .value_name("KEYPAIR") - .validator(is_valid_signer) - .takes_value(true) - .help("Stake pool manager. [default: cli config keypair]"), - ) - .arg( - Arg::with_name("funding_authority") - .long("funding-authority") - .value_name("KEYPAIR") - .validator(is_valid_signer) - .takes_value(true) - .help("Stake pool funding authority for deposits or withdrawals. [default: cli config keypair]"), - ) - .arg( - Arg::with_name("token_owner") - .long("token-owner") - .value_name("KEYPAIR") - .validator(is_valid_signer) - .takes_value(true) - .help("Owner of pool token account [default: cli config keypair]"), - ) - .arg( - Arg::with_name("fee_payer") - .long("fee-payer") - .value_name("KEYPAIR") - .validator(is_valid_signer) - .takes_value(true) - .help("Transaction fee payer account [default: cli config keypair]"), - ) - .subcommand(SubCommand::with_name("create-pool") - .about("Create a new stake pool") - .arg( - Arg::with_name("epoch_fee_numerator") - .long("epoch-fee-numerator") - .short("n") - .validator(is_parsable::) - .value_name("NUMERATOR") - .takes_value(true) - .required(true) - .help("Epoch fee numerator, fee amount is numerator divided by denominator."), - ) - .arg( - Arg::with_name("epoch_fee_denominator") - .long("epoch-fee-denominator") - .short("d") - .validator(is_parsable::) - .value_name("DENOMINATOR") - .takes_value(true) - .required(true) - .help("Epoch fee denominator, fee amount is numerator divided by denominator."), - ) - .arg( - Arg::with_name("withdrawal_fee_numerator") - .long("withdrawal-fee-numerator") - .validator(is_parsable::) - .value_name("NUMERATOR") - .takes_value(true) - .requires("withdrawal_fee_denominator") - .help("Withdrawal fee numerator, fee amount is numerator divided by denominator [default: 0]"), - ).arg( - Arg::with_name("withdrawal_fee_denominator") - .long("withdrawal-fee-denominator") - .validator(is_parsable::) - .value_name("DENOMINATOR") - .takes_value(true) - .requires("withdrawal_fee_numerator") - .help("Withdrawal fee denominator, fee amount is numerator divided by denominator [default: 0]"), - ) - .arg( - Arg::with_name("deposit_fee_numerator") - .long("deposit-fee-numerator") - .validator(is_parsable::) - .value_name("NUMERATOR") - .takes_value(true) - .requires("deposit_fee_denominator") - .help("Deposit fee numerator, fee amount is numerator divided by denominator [default: 0]"), - ).arg( - Arg::with_name("deposit_fee_denominator") - .long("deposit-fee-denominator") - .validator(is_parsable::) - .value_name("DENOMINATOR") - .takes_value(true) - .requires("deposit_fee_numerator") - .help("Deposit fee denominator, fee amount is numerator divided by denominator [default: 0]"), - ) - .arg( - Arg::with_name("referral_fee") - .long("referral-fee") - .validator(is_valid_percentage) - .value_name("FEE_PERCENTAGE") - .takes_value(true) - .help("Referral fee percentage, maximum 100"), - ) - .arg( - Arg::with_name("max_validators") - .long("max-validators") - .short("m") - .validator(is_parsable::) - .value_name("NUMBER") - .takes_value(true) - .required(true) - .help("Max number of validators included in the stake pool"), - ) - .arg( - Arg::with_name("deposit_authority") - .long("deposit-authority") - .short("a") - .validator(is_valid_signer) - .value_name("DEPOSIT_AUTHORITY_KEYPAIR") - .takes_value(true) - .help("Deposit authority required to sign all deposits into the stake pool"), - ) - .arg( - Arg::with_name("pool_keypair") - .long("pool-keypair") - .short("p") - .validator(is_keypair_or_ask_keyword) - .value_name("PATH") - .takes_value(true) - .help("Stake pool keypair [default: new keypair]"), - ) - .arg( - Arg::with_name("validator_list_keypair") - .long("validator-list-keypair") - .validator(is_keypair_or_ask_keyword) - .value_name("PATH") - .takes_value(true) - .help("Validator list keypair [default: new keypair]"), - ) - .arg( - Arg::with_name("mint_keypair") - .long("mint-keypair") - .validator(is_keypair_or_ask_keyword) - .value_name("PATH") - .takes_value(true) - .help("Stake pool mint keypair [default: new keypair]"), - ) - .arg( - Arg::with_name("reserve_keypair") - .long("reserve-keypair") - .validator(is_keypair_or_ask_keyword) - .value_name("PATH") - .takes_value(true) - .help("Stake pool reserve keypair [default: new keypair]"), - ) - .arg( - Arg::with_name("unsafe_fees") - .long("unsafe-fees") - .takes_value(false) - .help("Bypass fee checks, allowing pool to be created with unsafe fees"), - ) - ) - .subcommand(SubCommand::with_name("add-validator") - .about("Add validator account to the stake pool. Must be signed by the pool staker.") - .arg( - Arg::with_name("pool") - .index(1) - .validator(is_pubkey) - .value_name("POOL_ADDRESS") - .takes_value(true) - .required(true) - .help("Stake pool address"), - ) - .arg( - Arg::with_name("vote_account") - .index(2) - .validator(is_pubkey) - .value_name("VOTE_ACCOUNT_ADDRESS") - .takes_value(true) - .required(true) - .help("The validator vote account that the stake is delegated to"), - ) - ) - .subcommand(SubCommand::with_name("remove-validator") - .about("Remove validator account from the stake pool. Must be signed by the pool staker.") - .arg( - Arg::with_name("pool") - .index(1) - .validator(is_pubkey) - .value_name("POOL_ADDRESS") - .takes_value(true) - .required(true) - .help("Stake pool address"), - ) - .arg( - Arg::with_name("vote_account") - .index(2) - .validator(is_pubkey) - .value_name("VOTE_ACCOUNT_ADDRESS") - .takes_value(true) - .required(true) - .help("Vote account for the validator to remove from the pool"), - ) - .arg( - Arg::with_name("new_authority") - .long("new-authority") - .validator(is_pubkey) - .value_name("ADDRESS") - .takes_value(true) - .help("New authority to set as Staker and Withdrawer in the stake account removed from the pool. - Defaults to the client keypair."), - ) - .arg( - Arg::with_name("stake_receiver") - .long("stake-receiver") - .validator(is_pubkey) - .value_name("ADDRESS") - .takes_value(true) - .help("Stake account to receive SOL from the stake pool. Defaults to a new stake account."), - ) - ) - .subcommand(SubCommand::with_name("increase-validator-stake") - .about("Increase stake to a validator, drawing from the stake pool reserve. Must be signed by the pool staker.") - .arg( - Arg::with_name("pool") - .index(1) - .validator(is_pubkey) - .value_name("POOL_ADDRESS") - .takes_value(true) - .required(true) - .help("Stake pool address"), - ) - .arg( - Arg::with_name("vote_account") - .index(2) - .validator(is_pubkey) - .value_name("VOTE_ACCOUNT_ADDRESS") - .takes_value(true) - .required(true) - .help("Vote account for the validator to increase stake to"), - ) - .arg( - Arg::with_name("amount") - .index(3) - .validator(is_amount) - .value_name("AMOUNT") - .takes_value(true) - .help("Amount in SOL to add to the validator stake account. Must be at least the rent-exempt amount for a stake plus 1 SOL for merging."), - ) - ) - .subcommand(SubCommand::with_name("decrease-validator-stake") - .about("Decrease stake to a validator, splitting from the active stake. Must be signed by the pool staker.") - .arg( - Arg::with_name("pool") - .index(1) - .validator(is_pubkey) - .value_name("POOL_ADDRESS") - .takes_value(true) - .required(true) - .help("Stake pool address"), - ) - .arg( - Arg::with_name("vote_account") - .index(2) - .validator(is_pubkey) - .value_name("VOTE_ACCOUNT_ADDRESS") - .takes_value(true) - .required(true) - .help("Vote account for the validator to decrease stake from"), - ) - .arg( - Arg::with_name("amount") - .index(3) - .validator(is_amount) - .value_name("AMOUNT") - .takes_value(true) - .help("Amount in SOL to remove from the validator stake account. Must be at least the rent-exempt amount for a stake."), - ) - ) - .subcommand(SubCommand::with_name("set-preferred-validator") - .about("Set the preferred validator for deposits or withdrawals. Must be signed by the pool staker.") - .arg( - Arg::with_name("pool") - .index(1) - .validator(is_pubkey) - .value_name("POOL_ADDRESS") - .takes_value(true) - .required(true) - .help("Stake pool address"), - ) - .arg( - Arg::with_name("preferred_type") - .index(2) - .value_name("OPERATION") - .possible_values(&["deposit", "withdraw"]) // PreferredValidatorType enum - .takes_value(true) - .required(true) - .help("Operation for which to restrict the validator"), - ) - .arg( - Arg::with_name("vote_account") - .long("vote-account") - .validator(is_pubkey) - .value_name("VOTE_ACCOUNT_ADDRESS") - .takes_value(true) - .help("Vote account for the validator that users must deposit into."), - ) - .arg( - Arg::with_name("unset") - .long("unset") - .takes_value(false) - .help("Unset the preferred validator."), - ) - .group(ArgGroup::with_name("validator") - .arg("vote_account") - .arg("unset") - .required(true) - ) - ) - .subcommand(SubCommand::with_name("deposit-stake") - .about("Deposit active stake account into the stake pool in exchange for pool tokens") - .arg( - Arg::with_name("pool") - .index(1) - .validator(is_pubkey) - .value_name("POOL_ADDRESS") - .takes_value(true) - .required(true) - .help("Stake pool address"), - ) - .arg( - Arg::with_name("stake_account") - .index(2) - .validator(is_pubkey) - .value_name("STAKE_ACCOUNT_ADDRESS") - .takes_value(true) - .required(true) - .help("Stake address to join the pool"), - ) - .arg( - Arg::with_name("withdraw_authority") - .long("withdraw-authority") - .validator(is_valid_signer) - .value_name("KEYPAIR") - .takes_value(true) - .help("Withdraw authority for the stake account to be deposited. [default: cli config keypair]"), - ) - .arg( - Arg::with_name("token_receiver") - .long("token-receiver") - .validator(is_pubkey) - .value_name("ADDRESS") - .takes_value(true) - .help("Account to receive the minted pool tokens. \ - Defaults to the token-owner's associated pool token account. \ - Creates the account if it does not exist."), - ) - .arg( - Arg::with_name("referrer") - .validator(is_pubkey) - .value_name("ADDRESS") - .takes_value(true) - .help("Pool token account to receive the referral fees for deposits. \ - Defaults to the token receiver."), - ) - ) - .subcommand(SubCommand::with_name("deposit-all-stake") - .about("Deposit all active stake accounts into the stake pool in exchange for pool tokens") - .arg( - Arg::with_name("pool") - .index(1) - .validator(is_pubkey) - .value_name("POOL_ADDRESS") - .takes_value(true) - .required(true) - .help("Stake pool address"), - ) - .arg( - Arg::with_name("stake_authority") - .index(2) - .validator(is_pubkey) - .value_name("ADDRESS") - .takes_value(true) - .required(true) - .help("Stake authority address to search for stake accounts"), - ) - .arg( - Arg::with_name("withdraw_authority") - .long("withdraw-authority") - .validator(is_valid_signer) - .value_name("KEYPAIR") - .takes_value(true) - .help("Withdraw authority for the stake account to be deposited. [default: cli config keypair]"), - ) - .arg( - Arg::with_name("token_receiver") - .long("token-receiver") - .validator(is_pubkey) - .value_name("ADDRESS") - .takes_value(true) - .help("Account to receive the minted pool tokens. \ - Defaults to the token-owner's associated pool token account. \ - Creates the account if it does not exist."), - ) - .arg( - Arg::with_name("referrer") - .validator(is_pubkey) - .value_name("ADDRESS") - .takes_value(true) - .help("Pool token account to receive the referral fees for deposits. \ - Defaults to the token receiver."), - ) - ) - .subcommand(SubCommand::with_name("deposit-sol") - .about("Deposit SOL into the stake pool in exchange for pool tokens") - .arg( - Arg::with_name("pool") - .index(1) - .validator(is_pubkey) - .value_name("POOL_ADDRESS") - .takes_value(true) - .required(true) - .help("Stake pool address"), - ).arg( - Arg::with_name("amount") - .index(2) - .validator(is_amount) - .value_name("AMOUNT") - .takes_value(true) - .help("Amount in SOL to deposit into the stake pool reserve account."), - ) - .arg( - Arg::with_name("from") - .long("from") - .validator(is_valid_signer) - .value_name("KEYPAIR") - .takes_value(true) - .help("Source account of funds. [default: cli config keypair]"), - ) - .arg( - Arg::with_name("token_receiver") - .long("token-receiver") - .validator(is_pubkey) - .value_name("POOL_TOKEN_RECEIVER_ADDRESS") - .takes_value(true) - .help("Account to receive the minted pool tokens. \ - Defaults to the token-owner's associated pool token account. \ - Creates the account if it does not exist."), - ) - .arg( - Arg::with_name("referrer") - .long("referrer") - .validator(is_pubkey) - .value_name("REFERRER_TOKEN_ADDRESS") - .takes_value(true) - .help("Account to receive the referral fees for deposits. \ - Defaults to the token receiver."), - ) - ) - .subcommand(SubCommand::with_name("list") - .about("List stake accounts managed by this pool") - .arg( - Arg::with_name("pool") - .index(1) - .validator(is_pubkey) - .value_name("POOL_ADDRESS") - .takes_value(true) - .required(true) - .help("Stake pool address."), - ) - ) - .subcommand(SubCommand::with_name("update") - .about("Updates all balances in the pool after validator stake accounts receive rewards.") - .arg( - Arg::with_name("pool") - .index(1) - .validator(is_pubkey) - .value_name("POOL_ADDRESS") - .takes_value(true) - .required(true) - .help("Stake pool address."), - ) - .arg( - Arg::with_name("force") - .long("force") - .takes_value(false) - .help("Update all balances, even if it has already been performed this epoch."), - ) - .arg( - Arg::with_name("no_merge") - .long("no-merge") - .takes_value(false) - .help("Do not automatically merge transient stakes. Useful if the stake pool is in an expected state, but the balances still need to be updated."), - ) - ) - .subcommand(SubCommand::with_name("withdraw-stake") - .about("Withdraw active stake from the stake pool in exchange for pool tokens") - .arg( - Arg::with_name("pool") - .index(1) - .validator(is_pubkey) - .value_name("POOL_ADDRESS") - .takes_value(true) - .required(true) - .help("Stake pool address."), - ) - .arg( - Arg::with_name("amount") - .index(2) - .validator(is_amount) - .value_name("AMOUNT") - .takes_value(true) - .required(true) - .help("Amount of pool tokens to withdraw for activated stake."), - ) - .arg( - Arg::with_name("pool_account") - .long("pool-account") - .validator(is_pubkey) - .value_name("ADDRESS") - .takes_value(true) - .help("Pool token account to withdraw tokens from. Defaults to the token-owner's associated token account."), - ) - .arg( - Arg::with_name("stake_receiver") - .long("stake-receiver") - .validator(is_pubkey) - .value_name("STAKE_ACCOUNT_ADDRESS") - .takes_value(true) - .requires("withdraw_from") - .help("Stake account from which to receive a stake from the stake pool. Defaults to a new stake account."), - ) - .arg( - Arg::with_name("vote_account") - .long("vote-account") - .validator(is_pubkey) - .value_name("VOTE_ACCOUNT_ADDRESS") - .takes_value(true) - .help("Validator to withdraw from. Defaults to the largest validator stakes in the pool."), - ) - .arg( - Arg::with_name("use_reserve") - .long("use-reserve") - .takes_value(false) - .help("Withdraw from the stake pool's reserve. Only possible if all validator stakes are at the minimum possible amount."), - ) - .group(ArgGroup::with_name("withdraw_from") - .arg("use_reserve") - .arg("vote_account") - ) - ) - .subcommand(SubCommand::with_name("withdraw-sol") - .about("Withdraw SOL from the stake pool's reserve in exchange for pool tokens") - .arg( - Arg::with_name("pool") - .index(1) - .validator(is_pubkey) - .value_name("POOL_ADDRESS") - .takes_value(true) - .required(true) - .help("Stake pool address."), - ) - .arg( - Arg::with_name("sol_receiver") - .index(2) - .validator(is_valid_pubkey) - .value_name("SYSTEM_ACCOUNT_ADDRESS_OR_KEYPAIR") - .takes_value(true) - .required(true) - .help("System account to receive SOL from the stake pool. Defaults to the payer."), - ) - .arg( - Arg::with_name("amount") - .index(3) - .validator(is_amount) - .value_name("AMOUNT") - .takes_value(true) - .required(true) - .help("Amount of pool tokens to withdraw for SOL."), - ) - .arg( - Arg::with_name("pool_account") - .long("pool-account") - .validator(is_pubkey) - .value_name("ADDRESS") - .takes_value(true) - .help("Pool token account to withdraw tokens from. Defaults to the token-owner's associated token account."), - ) - ) - .subcommand(SubCommand::with_name("set-manager") - .about("Change manager or fee receiver account for the stake pool. Must be signed by the current manager.") - .arg( - Arg::with_name("pool") - .index(1) - .validator(is_pubkey) - .value_name("POOL_ADDRESS") - .takes_value(true) - .required(true) - .help("Stake pool address."), - ) - .arg( - Arg::with_name("new_manager") - .long("new-manager") - .validator(is_valid_signer) - .value_name("KEYPAIR") - .takes_value(true) - .help("Keypair for the new stake pool manager."), - ) - .arg( - Arg::with_name("new_fee_receiver") - .long("new-fee-receiver") - .validator(is_pubkey) - .value_name("ADDRESS") - .takes_value(true) - .help("Public key for the new account to set as the stake pool fee receiver."), - ) - .group(ArgGroup::with_name("new_accounts") - .arg("new_manager") - .arg("new_fee_receiver") - .required(true) - .multiple(true) - ) - ) - .subcommand(SubCommand::with_name("set-staker") - .about("Change staker account for the stake pool. Must be signed by the manager or current staker.") - .arg( - Arg::with_name("pool") - .index(1) - .validator(is_pubkey) - .value_name("POOL_ADDRESS") - .takes_value(true) - .required(true) - .help("Stake pool address."), - ) - .arg( - Arg::with_name("new_staker") - .index(2) - .validator(is_pubkey) - .value_name("ADDRESS") - .takes_value(true) - .help("Public key for the new stake pool staker."), - ) - ) - .subcommand(SubCommand::with_name("set-funding-authority") - .about("Change one of the funding authorities for the stake pool. Must be signed by the manager.") - .arg( - Arg::with_name("pool") - .index(1) - .validator(is_pubkey) - .value_name("POOL_ADDRESS") - .takes_value(true) - .required(true) - .help("Stake pool address."), - ) - .arg( - Arg::with_name("funding_type") - .index(2) - .value_name("FUNDING_TYPE") - .possible_values(&["stake-deposit", "sol-deposit", "sol-withdraw"]) // FundingType enum - .takes_value(true) - .required(true) - .help("Funding type to be updated."), - ) - .arg( - Arg::with_name("new_authority") - .index(3) - .validator(is_pubkey) - .value_name("AUTHORITY_ADDRESS") - .takes_value(true) - .help("Public key for the new stake pool funding authority."), - ) - .arg( - Arg::with_name("unset") - .long("unset") - .takes_value(false) - .help("Unset the stake deposit authority. The program will use a program derived address.") - ) - .group(ArgGroup::with_name("validator") - .arg("new_authority") - .arg("unset") - .required(true) - ) - ) - .subcommand(SubCommand::with_name("set-fee") - .about("Change the [epoch/withdraw/stake deposit/sol deposit] fee assessed by the stake pool. Must be signed by the manager.") - .arg( - Arg::with_name("pool") - .index(1) - .validator(is_pubkey) - .value_name("POOL_ADDRESS") - .takes_value(true) - .required(true) - .help("Stake pool address."), - ) - .arg(Arg::with_name("fee_type") - .index(2) - .value_name("FEE_TYPE") - .possible_values(&["epoch", "stake-deposit", "sol-deposit", "stake-withdrawal", "sol-withdrawal"]) // FeeType enum - .takes_value(true) - .required(true) - .help("Fee type to be updated."), - ) - .arg( - Arg::with_name("fee_numerator") - .index(3) - .validator(is_parsable::) - .value_name("NUMERATOR") - .takes_value(true) - .required(true) - .help("Fee numerator, fee amount is numerator divided by denominator."), - ) - .arg( - Arg::with_name("fee_denominator") - .index(4) - .validator(is_parsable::) - .value_name("DENOMINATOR") - .takes_value(true) - .required(true) - .help("Fee denominator, fee amount is numerator divided by denominator."), - ) - ) - .subcommand(SubCommand::with_name("set-referral-fee") - .about("Change the referral fee assessed by the stake pool for stake deposits. Must be signed by the manager.") - .arg( - Arg::with_name("pool") - .index(1) - .validator(is_pubkey) - .value_name("POOL_ADDRESS") - .takes_value(true) - .required(true) - .help("Stake pool address."), - ) - .arg(Arg::with_name("fee_type") - .index(2) - .value_name("FEE_TYPE") - .possible_values(&["stake", "sol"]) // FeeType enum, kind of - .takes_value(true) - .required(true) - .help("Fee type to be updated."), - ) - .arg( - Arg::with_name("fee") - .index(3) - .validator(is_valid_percentage) - .value_name("FEE_PERCENTAGE") - .takes_value(true) - .required(true) - .help("Fee percentage, maximum 100"), - ) - ) - .subcommand(SubCommand::with_name("list-all") - .about("List information about all stake pools") - ) - .get_matches(); - - let mut wallet_manager = None; - let cli_config = if let Some(config_file) = matches.value_of("config_file") { - solana_cli_config::Config::load(config_file).unwrap_or_default() - } else { - solana_cli_config::Config::default() - }; - let config = { - let json_rpc_url = value_t!(matches, "json_rpc_url", String) - .unwrap_or_else(|_| cli_config.json_rpc_url.clone()); - - let staker = get_signer( - &matches, - "staker", - &cli_config.keypair_path, - &mut wallet_manager, - SignerFromPathConfig { - allow_null_signer: false, - }, - ); - - let funding_authority = if matches.is_present("funding_authority") { - Some(get_signer( - &matches, - "funding_authority", - &cli_config.keypair_path, - &mut wallet_manager, - SignerFromPathConfig { - allow_null_signer: false, - }, - )) - } else { - None - }; - let manager = get_signer( - &matches, - "manager", - &cli_config.keypair_path, - &mut wallet_manager, - SignerFromPathConfig { - allow_null_signer: false, - }, - ); - let token_owner = get_signer( - &matches, - "token_owner", - &cli_config.keypair_path, - &mut wallet_manager, - SignerFromPathConfig { - allow_null_signer: false, - }, - ); - let fee_payer = get_signer( - &matches, - "fee_payer", - &cli_config.keypair_path, - &mut wallet_manager, - SignerFromPathConfig { - allow_null_signer: false, - }, - ); - let verbose = matches.is_present("verbose"); - let output_format = matches - .value_of("output_format") - .map(|value| match value { - "json" => OutputFormat::Json, - "json-compact" => OutputFormat::JsonCompact, - _ => unreachable!(), - }) - .unwrap_or(if verbose { - OutputFormat::DisplayVerbose - } else { - OutputFormat::Display - }); - let dry_run = matches.is_present("dry_run"); - let no_update = matches.is_present("no_update"); - - Config { - rpc_client: RpcClient::new_with_commitment(json_rpc_url, CommitmentConfig::confirmed()), - verbose, - output_format, - manager, - staker, - funding_authority, - token_owner, - fee_payer, - dry_run, - no_update, - } - }; - - let _ = match matches.subcommand() { - ("create-pool", Some(arg_matches)) => { - let deposit_authority = keypair_of(arg_matches, "deposit_authority"); - let e_numerator = value_t_or_exit!(arg_matches, "epoch_fee_numerator", u64); - let e_denominator = value_t_or_exit!(arg_matches, "epoch_fee_denominator", u64); - let w_numerator = value_t!(arg_matches, "withdrawal_fee_numerator", u64); - let w_denominator = value_t!(arg_matches, "withdrawal_fee_denominator", u64); - let d_numerator = value_t!(arg_matches, "deposit_fee_numerator", u64); - let d_denominator = value_t!(arg_matches, "deposit_fee_denominator", u64); - let referral_fee = value_t!(arg_matches, "referral_fee", u8); - let max_validators = value_t_or_exit!(arg_matches, "max_validators", u32); - let pool_keypair = keypair_of(arg_matches, "pool_keypair"); - let validator_list_keypair = keypair_of(arg_matches, "validator_list_keypair"); - let mint_keypair = keypair_of(arg_matches, "mint_keypair"); - let reserve_keypair = keypair_of(arg_matches, "reserve_keypair"); - let unsafe_fees = arg_matches.is_present("unsafe_fees"); - command_create_pool( - &config, - deposit_authority, - Fee { - numerator: e_numerator, - denominator: e_denominator, - }, - Fee { - numerator: w_numerator.unwrap_or(0), - denominator: w_denominator.unwrap_or(0), - }, - Fee { - numerator: d_numerator.unwrap_or(0), - denominator: d_denominator.unwrap_or(0), - }, - referral_fee.unwrap_or(0), - max_validators, - pool_keypair, - validator_list_keypair, - mint_keypair, - reserve_keypair, - unsafe_fees, - ) - } - ("add-validator", Some(arg_matches)) => { - let stake_pool_address = pubkey_of(arg_matches, "pool").unwrap(); - let vote_account_address = pubkey_of(arg_matches, "vote_account").unwrap(); - command_vsa_add(&config, &stake_pool_address, &vote_account_address) - } - ("remove-validator", Some(arg_matches)) => { - let stake_pool_address = pubkey_of(arg_matches, "pool").unwrap(); - let vote_account = pubkey_of(arg_matches, "vote_account").unwrap(); - let new_authority = pubkey_of(arg_matches, "new_authority"); - let stake_receiver = pubkey_of(arg_matches, "stake_receiver"); - command_vsa_remove( - &config, - &stake_pool_address, - &vote_account, - &new_authority, - &stake_receiver, - ) - } - ("increase-validator-stake", Some(arg_matches)) => { - let stake_pool_address = pubkey_of(arg_matches, "pool").unwrap(); - let vote_account = pubkey_of(arg_matches, "vote_account").unwrap(); - let amount = value_t_or_exit!(arg_matches, "amount", f64); - command_increase_validator_stake(&config, &stake_pool_address, &vote_account, amount) - } - ("decrease-validator-stake", Some(arg_matches)) => { - let stake_pool_address = pubkey_of(arg_matches, "pool").unwrap(); - let vote_account = pubkey_of(arg_matches, "vote_account").unwrap(); - let amount = value_t_or_exit!(arg_matches, "amount", f64); - command_decrease_validator_stake(&config, &stake_pool_address, &vote_account, amount) - } - ("set-preferred-validator", Some(arg_matches)) => { - let stake_pool_address = pubkey_of(arg_matches, "pool").unwrap(); - let preferred_type = match arg_matches.value_of("preferred_type").unwrap() { - "deposit" => PreferredValidatorType::Deposit, - "withdraw" => PreferredValidatorType::Withdraw, - _ => unreachable!(), - }; - let vote_account = pubkey_of(arg_matches, "vote_account"); - let _unset = arg_matches.is_present("unset"); - // since unset and vote_account can't both be set, if unset is set - // then vote_account will be None, which is valid for the program - command_set_preferred_validator( - &config, - &stake_pool_address, - preferred_type, - vote_account, - ) - } - ("deposit-stake", Some(arg_matches)) => { - let stake_pool_address = pubkey_of(arg_matches, "pool").unwrap(); - let stake_account = pubkey_of(arg_matches, "stake_account").unwrap(); - let token_receiver: Option = pubkey_of(arg_matches, "token_receiver"); - let referrer: Option = pubkey_of(arg_matches, "referrer"); - let withdraw_authority = get_signer( - arg_matches, - "withdraw_authority", - &cli_config.keypair_path, - &mut wallet_manager, - SignerFromPathConfig { - allow_null_signer: false, - }, - ); - command_deposit_stake( - &config, - &stake_pool_address, - &stake_account, - withdraw_authority, - &token_receiver, - &referrer, - ) - } - ("deposit-sol", Some(arg_matches)) => { - let stake_pool_address = pubkey_of(arg_matches, "pool").unwrap(); - let token_receiver: Option = pubkey_of(arg_matches, "token_receiver"); - let referrer: Option = pubkey_of(arg_matches, "referrer"); - let from = keypair_of(arg_matches, "from"); - let amount = value_t_or_exit!(arg_matches, "amount", f64); - command_deposit_sol( - &config, - &stake_pool_address, - &from, - &token_receiver, - &referrer, - amount, - ) - } - ("list", Some(arg_matches)) => { - let stake_pool_address = pubkey_of(arg_matches, "pool").unwrap(); - command_list(&config, &stake_pool_address) - } - ("update", Some(arg_matches)) => { - let stake_pool_address = pubkey_of(arg_matches, "pool").unwrap(); - let no_merge = arg_matches.is_present("no_merge"); - let force = arg_matches.is_present("force"); - command_update(&config, &stake_pool_address, force, no_merge) - } - ("withdraw-stake", Some(arg_matches)) => { - let stake_pool_address = pubkey_of(arg_matches, "pool").unwrap(); - let vote_account = pubkey_of(arg_matches, "vote_account"); - let pool_account = pubkey_of(arg_matches, "pool_account"); - let pool_amount = value_t_or_exit!(arg_matches, "amount", f64); - let stake_receiver = pubkey_of(arg_matches, "stake_receiver"); - let use_reserve = arg_matches.is_present("use_reserve"); - command_withdraw_stake( - &config, - &stake_pool_address, - use_reserve, - &vote_account, - &stake_receiver, - &pool_account, - pool_amount, - ) - } - ("withdraw-sol", Some(arg_matches)) => { - let stake_pool_address = pubkey_of(arg_matches, "pool").unwrap(); - let pool_account = pubkey_of(arg_matches, "pool_account"); - let pool_amount = value_t_or_exit!(arg_matches, "amount", f64); - let sol_receiver = get_signer( - arg_matches, - "sol_receiver", - &cli_config.keypair_path, - &mut wallet_manager, - SignerFromPathConfig { - allow_null_signer: true, - }, - ) - .pubkey(); - command_withdraw_sol( - &config, - &stake_pool_address, - &pool_account, - &sol_receiver, - pool_amount, - ) - } - ("set-manager", Some(arg_matches)) => { - let stake_pool_address = pubkey_of(arg_matches, "pool").unwrap(); - let new_manager: Option = keypair_of(arg_matches, "new_manager"); - let new_fee_receiver: Option = pubkey_of(arg_matches, "new_fee_receiver"); - command_set_manager( - &config, - &stake_pool_address, - &new_manager, - &new_fee_receiver, - ) - } - ("set-staker", Some(arg_matches)) => { - let stake_pool_address = pubkey_of(arg_matches, "pool").unwrap(); - let new_staker = pubkey_of(arg_matches, "new_staker").unwrap(); - command_set_staker(&config, &stake_pool_address, &new_staker) - } - ("set-funding-authority", Some(arg_matches)) => { - let stake_pool_address = pubkey_of(arg_matches, "pool").unwrap(); - let new_authority = pubkey_of(arg_matches, "new_authority"); - let funding_type = match arg_matches.value_of("funding_type").unwrap() { - "sol-deposit" => FundingType::SolDeposit, - "stake-deposit" => FundingType::StakeDeposit, - "sol-withdraw" => FundingType::SolWithdraw, - _ => unreachable!(), - }; - let _unset = arg_matches.is_present("unset"); - command_set_funding_authority(&config, &stake_pool_address, new_authority, funding_type) - } - ("set-fee", Some(arg_matches)) => { - let stake_pool_address = pubkey_of(arg_matches, "pool").unwrap(); - let numerator = value_t_or_exit!(arg_matches, "fee_numerator", u64); - let denominator = value_t_or_exit!(arg_matches, "fee_denominator", u64); - let new_fee = Fee { - denominator, - numerator, - }; - match arg_matches.value_of("fee_type").unwrap() { - "epoch" => command_set_fee(&config, &stake_pool_address, FeeType::Epoch(new_fee)), - "stake-deposit" => { - command_set_fee(&config, &stake_pool_address, FeeType::StakeDeposit(new_fee)) - } - "sol-deposit" => { - command_set_fee(&config, &stake_pool_address, FeeType::SolDeposit(new_fee)) - } - "stake-withdrawal" => command_set_fee( - &config, - &stake_pool_address, - FeeType::StakeWithdrawal(new_fee), - ), - "sol-withdrawal" => command_set_fee( - &config, - &stake_pool_address, - FeeType::SolWithdrawal(new_fee), - ), - _ => unreachable!(), - } - } - ("set-referral-fee", Some(arg_matches)) => { - let stake_pool_address = pubkey_of(arg_matches, "pool").unwrap(); - let fee = value_t_or_exit!(arg_matches, "fee", u8); - assert!( - fee <= 100u8, - "Invalid fee {}%. Fee needs to be in range [0-100]", - fee - ); - let fee_type = match arg_matches.value_of("fee_type").unwrap() { - "sol" => FeeType::SolReferral(fee), - "stake" => FeeType::StakeReferral(fee), - _ => unreachable!(), - }; - command_set_fee(&config, &stake_pool_address, fee_type) - } - ("list-all", _) => command_list_all_pools(&config), - ("deposit-all-stake", Some(arg_matches)) => { - let stake_pool_address = pubkey_of(arg_matches, "pool").unwrap(); - let stake_authority = pubkey_of(arg_matches, "stake_authority").unwrap(); - let token_receiver: Option = pubkey_of(arg_matches, "token_receiver"); - let referrer: Option = pubkey_of(arg_matches, "referrer"); - let withdraw_authority = get_signer( - arg_matches, - "withdraw_authority", - &cli_config.keypair_path, - &mut wallet_manager, - SignerFromPathConfig { - allow_null_signer: false, - }, - ); - command_deposit_all_stake( - &config, - &stake_pool_address, - &stake_authority, - withdraw_authority, - &token_receiver, - &referrer, - ) - } - _ => unreachable!(), - } - .map_err(|err| { - eprintln!("{}", err); - exit(1); - }); -} diff --git a/stake-pool/cli/src/output.rs b/stake-pool/cli/src/output.rs deleted file mode 100644 index 7ca8feab3d2..00000000000 --- a/stake-pool/cli/src/output.rs +++ /dev/null @@ -1,496 +0,0 @@ -use { - serde::{Deserialize, Serialize}, - solana_cli_output::{QuietDisplay, VerboseDisplay}, - solana_sdk::native_token::Sol, - solana_sdk::{pubkey::Pubkey, stake::state::Lockup}, - spl_stake_pool::state::{Fee, StakePool, StakeStatus, ValidatorList, ValidatorStakeInfo}, - std::fmt::{Display, Formatter, Result, Write}, -}; - -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub(crate) struct CliStakePools { - pub pools: Vec, -} - -impl Display for CliStakePools { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - for pool in &self.pools { - writeln!( - f, - "Address: {}\tManager: {}\tLamports: {}\tPool tokens: {}\tValidators: {}", - pool.address, - pool.manager, - pool.total_lamports, - pool.pool_token_supply, - pool.validator_list.len() - )?; - } - writeln!(f, "Total number of pools: {}", &self.pools.len())?; - Ok(()) - } -} - -impl QuietDisplay for CliStakePools {} -impl VerboseDisplay for CliStakePools {} - -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub(crate) struct CliStakePool { - pub address: String, - pub pool_withdraw_authority: String, - pub manager: String, - pub staker: String, - pub stake_deposit_authority: String, - pub stake_withdraw_bump_seed: u8, - pub max_validators: u32, - pub validator_list: Vec, - pub validator_list_storage_account: String, - pub reserve_stake: String, - pub pool_mint: String, - pub manager_fee_account: String, - pub token_program_id: String, - pub total_lamports: u64, - pub pool_token_supply: u64, - pub last_update_epoch: u64, - pub lockup: CliStakePoolLockup, - pub epoch_fee: CliStakePoolFee, - pub next_epoch_fee: Option, - pub preferred_deposit_validator_vote_address: Option, - pub preferred_withdraw_validator_vote_address: Option, - pub stake_deposit_fee: CliStakePoolFee, - pub stake_withdrawal_fee: CliStakePoolFee, - pub next_stake_withdrawal_fee: Option, - pub stake_referral_fee: u8, - pub sol_deposit_authority: Option, - pub sol_deposit_fee: CliStakePoolFee, - pub sol_referral_fee: u8, - pub sol_withdraw_authority: Option, - pub sol_withdrawal_fee: CliStakePoolFee, - pub next_sol_withdrawal_fee: Option, - pub last_epoch_pool_token_supply: u64, - pub last_epoch_total_lamports: u64, - pub details: Option, -} - -impl QuietDisplay for CliStakePool {} -impl VerboseDisplay for CliStakePool { - fn write_str(&self, w: &mut dyn Write) -> Result { - writeln!(w, "Stake Pool Info")?; - writeln!(w, "===============")?; - writeln!(w, "Stake Pool: {}", &self.address)?; - writeln!( - w, - "Validator List: {}", - &self.validator_list_storage_account - )?; - writeln!(w, "Manager: {}", &self.manager)?; - writeln!(w, "Staker: {}", &self.staker)?; - writeln!(w, "Depositor: {}", &self.stake_deposit_authority)?; - writeln!( - w, - "SOL Deposit Authority: {}", - &self - .sol_deposit_authority - .as_ref() - .unwrap_or(&"None".to_string()) - )?; - writeln!( - w, - "SOL Withdraw Authority: {}", - &self - .sol_withdraw_authority - .as_ref() - .unwrap_or(&"None".to_string()) - )?; - writeln!(w, "Withdraw Authority: {}", &self.pool_withdraw_authority)?; - writeln!(w, "Pool Token Mint: {}", &self.pool_mint)?; - writeln!(w, "Fee Account: {}", &self.manager_fee_account)?; - match &self.preferred_deposit_validator_vote_address { - None => {} - Some(s) => { - writeln!(w, "Preferred Deposit Validator: {}", s)?; - } - } - match &self.preferred_withdraw_validator_vote_address { - None => {} - Some(s) => { - writeln!(w, "Preferred Withraw Validator: {}", s)?; - } - } - writeln!(w, "Epoch Fee: {} of epoch rewards", &self.epoch_fee)?; - if let Some(next_epoch_fee) = &self.next_epoch_fee { - writeln!(w, "Next Epoch Fee: {} of epoch rewards", next_epoch_fee)?; - } - writeln!( - w, - "Stake Withdrawal Fee: {} of withdrawal amount", - &self.stake_withdrawal_fee - )?; - if let Some(next_stake_withdrawal_fee) = &self.next_stake_withdrawal_fee { - writeln!( - w, - "Next Stake Withdrawal Fee: {} of withdrawal amount", - next_stake_withdrawal_fee - )?; - } - writeln!( - w, - "SOL Withdrawal Fee: {} of withdrawal amount", - &self.sol_withdrawal_fee - )?; - if let Some(next_sol_withdrawal_fee) = &self.next_sol_withdrawal_fee { - writeln!( - w, - "Next SOL Withdrawal Fee: {} of withdrawal amount", - next_sol_withdrawal_fee - )?; - } - writeln!( - w, - "Stake Deposit Fee: {} of deposit amount", - &self.stake_deposit_fee - )?; - writeln!( - w, - "SOL Deposit Fee: {} of deposit amount", - &self.sol_deposit_fee - )?; - writeln!( - w, - "Stake Deposit Referral Fee: {}% of Stake Deposit Fee", - &self.stake_referral_fee - )?; - writeln!( - w, - "SOL Deposit Referral Fee: {}% of SOL Deposit Fee", - &self.sol_referral_fee - )?; - writeln!(w)?; - - match &self.details { - None => {} - Some(details) => { - VerboseDisplay::write_str(details, w)?; - } - } - Ok(()) - } -} - -impl Display for CliStakePool { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - writeln!(f, "Stake Pool: {}", &self.address)?; - writeln!( - f, - "Validator List: {}", - &self.validator_list_storage_account - )?; - writeln!(f, "Pool Token Mint: {}", &self.pool_mint)?; - match &self.preferred_deposit_validator_vote_address { - None => {} - Some(s) => { - writeln!(f, "Preferred Deposit Validator: {}", s)?; - } - } - match &self.preferred_withdraw_validator_vote_address { - None => {} - Some(s) => { - writeln!(f, "Preferred Withraw Validator: {}", s)?; - } - } - writeln!(f, "Epoch Fee: {} of epoch rewards", &self.epoch_fee)?; - writeln!( - f, - "Stake Withdrawal Fee: {} of withdrawal amount", - &self.stake_withdrawal_fee - )?; - writeln!( - f, - "SOL Withdrawal Fee: {} of withdrawal amount", - &self.sol_withdrawal_fee - )?; - writeln!( - f, - "Stake Deposit Fee: {} of deposit amount", - &self.stake_deposit_fee - )?; - writeln!( - f, - "SOL Deposit Fee: {} of deposit amount", - &self.sol_deposit_fee - )?; - writeln!( - f, - "Stake Deposit Referral Fee: {}% of Stake Deposit Fee", - &self.stake_referral_fee - )?; - writeln!( - f, - "SOL Deposit Referral Fee: {}% of SOL Deposit Fee", - &self.sol_referral_fee - )?; - Ok(()) - } -} - -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub(crate) struct CliStakePoolDetails { - pub reserve_stake_account_address: String, - pub reserve_stake_lamports: u64, - pub minimum_reserve_stake_balance: u64, - pub stake_accounts: Vec, - pub total_lamports: u64, - pub total_pool_tokens: f64, - pub current_number_of_validators: u32, - pub max_number_of_validators: u32, - pub update_required: bool, -} - -impl Display for CliStakePoolDetails { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - writeln!( - f, - "Reserve Account: {}\tAvailable Balance: {}", - &self.reserve_stake_account_address, - Sol(self.reserve_stake_lamports - self.minimum_reserve_stake_balance), - )?; - for stake_account in &self.stake_accounts { - writeln!( - f, - "Vote Account: {}\tBalance: {}\tLast Update Epoch: {}", - stake_account.vote_account_address, - Sol(stake_account.validator_lamports), - stake_account.validator_last_update_epoch, - )?; - } - writeln!( - f, - "Total Pool Stake: {} {}", - Sol(self.total_lamports), - if self.update_required { - " [UPDATE REQUIRED]" - } else { - "" - }, - )?; - writeln!(f, "Total Pool Tokens: {}", &self.total_pool_tokens,)?; - writeln!( - f, - "Current Number of Validators: {}", - &self.current_number_of_validators, - )?; - writeln!( - f, - "Max Number of Validators: {}", - &self.max_number_of_validators, - )?; - Ok(()) - } -} - -impl QuietDisplay for CliStakePoolDetails {} -impl VerboseDisplay for CliStakePoolDetails { - fn write_str(&self, w: &mut dyn Write) -> Result { - writeln!(w, "Stake Accounts")?; - writeln!(w, "--------------")?; - writeln!( - w, - "Reserve Account: {}\tAvailable Balance: {}", - &self.reserve_stake_account_address, - Sol(self.reserve_stake_lamports - self.minimum_reserve_stake_balance), - )?; - for stake_account in &self.stake_accounts { - writeln!( - w, - "Vote Account: {}\tStake Account: {}\tActive Balance: {}\tTransient Stake Account: {}\tTransient Balance: {}\tLast Update Epoch: {}{}", - stake_account.vote_account_address, - stake_account.stake_account_address, - Sol(stake_account.validator_active_stake_lamports), - stake_account.validator_transient_stake_account_address, - Sol(stake_account.validator_transient_stake_lamports), - stake_account.validator_last_update_epoch, - if stake_account.update_required { - " [UPDATE REQUIRED]" - } else { - "" - }, - )?; - } - writeln!( - w, - "Total Pool Stake: {} {}", - Sol(self.total_lamports), - if self.update_required { - " [UPDATE REQUIRED]" - } else { - "" - }, - )?; - writeln!(w, "Total Pool Tokens: {}", &self.total_pool_tokens,)?; - writeln!( - w, - "Current Number of Validators: {}", - &self.current_number_of_validators, - )?; - writeln!( - w, - "Max Number of Validators: {}", - &self.max_number_of_validators, - )?; - Ok(()) - } -} - -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub(crate) struct CliStakePoolStakeAccountInfo { - pub vote_account_address: String, - pub stake_account_address: String, - pub validator_active_stake_lamports: u64, - pub validator_last_update_epoch: u64, - pub validator_lamports: u64, - pub validator_transient_stake_account_address: String, - pub validator_transient_stake_lamports: u64, - pub update_required: bool, -} - -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub(crate) struct CliStakePoolValidator { - pub active_stake_lamports: u64, - pub transient_stake_lamports: u64, - pub last_update_epoch: u64, - pub transient_seed_suffix_start: u64, - pub transient_seed_suffix_end: u64, - pub status: CliStakePoolValidatorStakeStatus, - pub vote_account_address: String, -} - -impl From for CliStakePoolValidator { - fn from(v: ValidatorStakeInfo) -> Self { - Self { - active_stake_lamports: v.active_stake_lamports, - transient_stake_lamports: v.transient_stake_lamports, - last_update_epoch: v.last_update_epoch, - transient_seed_suffix_start: v.transient_seed_suffix_start, - transient_seed_suffix_end: v.transient_seed_suffix_end, - status: CliStakePoolValidatorStakeStatus::from(v.status), - vote_account_address: v.vote_account_address.to_string(), - } - } -} - -impl From for CliStakePoolValidatorStakeStatus { - fn from(s: StakeStatus) -> CliStakePoolValidatorStakeStatus { - match s { - StakeStatus::Active => CliStakePoolValidatorStakeStatus::Active, - StakeStatus::DeactivatingTransient => { - CliStakePoolValidatorStakeStatus::DeactivatingTransient - } - StakeStatus::ReadyForRemoval => CliStakePoolValidatorStakeStatus::ReadyForRemoval, - } - } -} - -#[derive(Serialize, Deserialize)] -pub(crate) enum CliStakePoolValidatorStakeStatus { - Active, - DeactivatingTransient, - ReadyForRemoval, -} - -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CliStakePoolLockup { - pub unix_timestamp: i64, - pub epoch: u64, - pub custodian: String, -} - -impl From for CliStakePoolLockup { - fn from(l: Lockup) -> Self { - Self { - unix_timestamp: l.unix_timestamp, - epoch: l.epoch, - custodian: l.custodian.to_string(), - } - } -} - -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub(crate) struct CliStakePoolFee { - pub denominator: u64, - pub numerator: u64, -} - -impl Display for CliStakePoolFee { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - write!(f, "{}/{}", &self.numerator, &self.denominator) - } -} - -impl From for CliStakePoolFee { - fn from(f: Fee) -> Self { - Self { - denominator: f.denominator, - numerator: f.numerator, - } - } -} - -impl From<(Pubkey, StakePool, ValidatorList, Pubkey)> for CliStakePool { - fn from(s: (Pubkey, StakePool, ValidatorList, Pubkey)) -> Self { - let (address, stake_pool, validator_list, pool_withdraw_authority) = s; - Self { - address: address.to_string(), - pool_withdraw_authority: pool_withdraw_authority.to_string(), - manager: stake_pool.manager.to_string(), - staker: stake_pool.staker.to_string(), - stake_deposit_authority: stake_pool.stake_deposit_authority.to_string(), - stake_withdraw_bump_seed: stake_pool.stake_withdraw_bump_seed, - max_validators: validator_list.header.max_validators, - validator_list: validator_list - .validators - .into_iter() - .map(CliStakePoolValidator::from) - .collect(), - validator_list_storage_account: stake_pool.validator_list.to_string(), - reserve_stake: stake_pool.reserve_stake.to_string(), - pool_mint: stake_pool.pool_mint.to_string(), - manager_fee_account: stake_pool.manager_fee_account.to_string(), - token_program_id: stake_pool.token_program_id.to_string(), - total_lamports: stake_pool.total_lamports, - pool_token_supply: stake_pool.pool_token_supply, - last_update_epoch: stake_pool.last_update_epoch, - lockup: CliStakePoolLockup::from(stake_pool.lockup), - epoch_fee: CliStakePoolFee::from(stake_pool.epoch_fee), - next_epoch_fee: stake_pool.next_epoch_fee.map(CliStakePoolFee::from), - preferred_deposit_validator_vote_address: stake_pool - .preferred_deposit_validator_vote_address - .map(|x| x.to_string()), - preferred_withdraw_validator_vote_address: stake_pool - .preferred_withdraw_validator_vote_address - .map(|x| x.to_string()), - stake_deposit_fee: CliStakePoolFee::from(stake_pool.stake_deposit_fee), - stake_withdrawal_fee: CliStakePoolFee::from(stake_pool.stake_withdrawal_fee), - next_stake_withdrawal_fee: stake_pool - .next_stake_withdrawal_fee - .map(CliStakePoolFee::from), - stake_referral_fee: stake_pool.stake_referral_fee, - sol_deposit_authority: stake_pool.sol_deposit_authority.map(|x| x.to_string()), - sol_deposit_fee: CliStakePoolFee::from(stake_pool.sol_deposit_fee), - sol_referral_fee: stake_pool.sol_referral_fee, - sol_withdraw_authority: stake_pool.sol_withdraw_authority.map(|x| x.to_string()), - sol_withdrawal_fee: CliStakePoolFee::from(stake_pool.sol_withdrawal_fee), - next_sol_withdrawal_fee: stake_pool - .next_sol_withdrawal_fee - .map(CliStakePoolFee::from), - last_epoch_pool_token_supply: stake_pool.last_epoch_pool_token_supply, - last_epoch_total_lamports: stake_pool.last_epoch_total_lamports, - details: None, - } - } -} diff --git a/stake-pool/js/.eslintignore b/stake-pool/js/.eslintignore deleted file mode 100644 index 58542507948..00000000000 --- a/stake-pool/js/.eslintignore +++ /dev/null @@ -1,4 +0,0 @@ -dist -node_modules -.vscode -.idea diff --git a/stake-pool/js/.eslintrc.js b/stake-pool/js/.eslintrc.js deleted file mode 100644 index 63db7b8405f..00000000000 --- a/stake-pool/js/.eslintrc.js +++ /dev/null @@ -1,21 +0,0 @@ -module.exports = { - root: true, - env: { - es6: true, - node: true, - jest: true, - }, - extends: ['plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'], - plugins: ['@typescript-eslint/eslint-plugin'], - parser: '@typescript-eslint/parser', - parserOptions: { - sourceType: 'module', - }, - rules: { - '@typescript-eslint/interface-name-prefix': 'off', - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/explicit-module-boundary-types': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/ban-ts-comment': 'off', - }, -}; diff --git a/stake-pool/js/.gitignore b/stake-pool/js/.gitignore deleted file mode 100644 index 3764afb8006..00000000000 --- a/stake-pool/js/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# IDE & OS specific -.DS_Store -.idea -.vscode - -# Logs -logs -*.log - -# Dependencies -node_modules - -# Coverage -coverage -.nyc_output - -# Release -dist -dist.browser - -# TypeScript -declarations diff --git a/stake-pool/js/.prettierrc.js b/stake-pool/js/.prettierrc.js deleted file mode 100644 index 8446d684477..00000000000 --- a/stake-pool/js/.prettierrc.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - singleQuote: true, - trailingComma: 'all', - printWidth: 100, - endOfLine: 'lf', - semi: true, -}; diff --git a/stake-pool/js/README.md b/stake-pool/js/README.md deleted file mode 100644 index b4030d23cfd..00000000000 --- a/stake-pool/js/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# TypeScript bindings for stake-pool program - -For use with both node.js and in-browser. - -## Installation - -``` -npm install -``` - -## Build and run - -In the `js` folder: - -``` -npm run build -``` - -The build is available at `dist/index.js` (or `dist.browser/index.iife.js` in the browser). - -## Browser bundle -```html - - - - - -``` - -## Test - -``` -npm test -``` - -## Usage - -### JavaScript -```javascript -const solanaStakePool = require('@solana/spl-stake-pool'); -console.log(solanaStakePool); -``` - -### ES6 -```javascript -import * as solanaStakePool from '@solana/spl-stake-pool'; -console.log(solanaStakePool); -``` - -### Browser bundle -```javascript -// `solanaStakePool` is provided in the global namespace by the script bundle. -console.log(solanaStakePool); -``` \ No newline at end of file diff --git a/stake-pool/js/package-lock.json b/stake-pool/js/package-lock.json deleted file mode 100644 index 6550b98cb8e..00000000000 --- a/stake-pool/js/package-lock.json +++ /dev/null @@ -1,10949 +0,0 @@ -{ - "name": "@solana/spl-stake-pool", - "version": "0.6.4", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "@solana/spl-stake-pool", - "version": "0.6.4", - "license": "ISC", - "dependencies": { - "@project-serum/borsh": "^0.2.2", - "@solana/buffer-layout": "^4.0.0", - "@solana/spl-token": "^0.1.8", - "@solana/web3.js": "^1.30.2", - "bn.js": "^5.2.0", - "buffer": "^6.0.3" - }, - "devDependencies": { - "@rollup/plugin-alias": "^3.1.9", - "@rollup/plugin-commonjs": "^21.0.1", - "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-multi-entry": "^4.1.0", - "@rollup/plugin-node-resolve": "^13.1.3", - "@rollup/plugin-typescript": "^8.3.0", - "@types/bn.js": "^5.1.0", - "@types/jest": "^27.4.0", - "@typescript-eslint/eslint-plugin": "^5.11.0", - "@typescript-eslint/parser": "^5.11.0", - "cross-env": "^7.0.3", - "eslint": "^8.8.0", - "eslint-config-prettier": "^8.3.0", - "eslint-plugin-prettier": "^4.0.0", - "jest": "^27.5.1", - "prettier": "^2.5.1", - "rimraf": "^3.0.2", - "rollup": "^2.66.1", - "rollup-plugin-dts": "^4.1.0", - "rollup-plugin-node-polyfills": "^0.2.1", - "rollup-plugin-terser": "^7.0.2", - "ts-jest": "^27.1.3", - "typescript": "^4.5.4" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.0.tgz", - "integrity": "sha512-d5RysTlJ7hmw5Tw4UxgxcY3lkMe92n8sXCcuLPAyIAHK6j8DefDwtGnVVDgOnv+RnEosulDJ9NPKQL27bDId0g==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", - "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.2.tgz", - "integrity": "sha512-R3VH5G42VSDolRHyUO4V2cfag8WHcZyxdq5Z/m8Xyb92lW/Erm/6kM+XtRFGf3Mulre3mveni2NHfEUws8wSvw==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.0.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.0", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helpers": "^7.17.2", - "@babel/parser": "^7.17.0", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.0", - "@babel/types": "^7.17.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.0.tgz", - "integrity": "sha512-I3Omiv6FGOC29dtlZhkfXO6pgkmukJSlT26QjVvS1DGZe/NzSVCPG41X0tS21oZkJYlovfj9qDWgKP+Cn4bXxw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", - "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.16.4", - "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.17.5", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", - "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", - "dev": true, - "dependencies": { - "@babel/helper-get-function-arity": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", - "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", - "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", - "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", - "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", - "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", - "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", - "dev": true, - "dependencies": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.0", - "@babel/types": "^7.17.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.0.tgz", - "integrity": "sha512-VKXSCQx5D8S04ej+Dqsr1CzYvvWgf20jIw2D+YhQCrIlr2UZGaDds23Y0xg75/skOxpLCRpUZvk/1EAVkGoDOw==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", - "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", - "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==", - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.0.tgz", - "integrity": "sha512-fpFIXvqD6kC7c7PUNnZ0Z8cQXlarCLtCUpt2S1Dx7PjoRtCFffvOkHHSom+m5HIxMZn5bIBVb71lhabcmjEsqg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.0", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.0", - "@babel/types": "^7.17.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@eslint/eslintrc": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz", - "integrity": "sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.2.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/@ethersproject/bytes": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.5.0.tgz", - "integrity": "sha512-ABvc7BHWhZU9PNM/tANm/Qx4ostPGadAuQzWTr3doklZOhDlmcBqclrQe/ZXUIj3K8wC28oYeuRa+A37tX9kog==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/logger": "^5.5.0" - } - }, - "node_modules/@ethersproject/logger": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.5.0.tgz", - "integrity": "sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ] - }, - "node_modules/@ethersproject/sha2": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.5.0.tgz", - "integrity": "sha512-B5UBoglbCiHamRVPLA110J+2uqsifpZaTmid2/7W5rbtYVz6gus6/hSDieIU/6gaKIDcOj12WnOdiymEUHIAOA==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "hash.js": "1.1.7" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.3.tgz", - "integrity": "sha512-3xSMlXHh03hCcCmFc0rbKp3Ivt2PFEJnQUJDDMTJQ2wkECZWdq4GePs2ctc5H8zV+cHPaq8k2vU8mrQjA6iHdQ==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", - "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^27.5.1", - "jest-util": "^27.5.1", - "slash": "^3.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/core": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", - "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", - "dev": true, - "dependencies": { - "@jest/console": "^27.5.1", - "@jest/reporters": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^27.5.1", - "jest-config": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-resolve-dependencies": "^27.5.1", - "jest-runner": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "jest-watcher": "^27.5.1", - "micromatch": "^4.0.4", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/environment": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", - "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", - "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "@sinonjs/fake-timers": "^8.0.1", - "@types/node": "*", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", - "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", - "dev": true, - "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/types": "^27.5.1", - "expect": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", - "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-haste-map": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^8.1.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/source-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", - "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9", - "source-map": "^0.6.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", - "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", - "dev": true, - "dependencies": { - "@jest/console": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", - "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", - "dev": true, - "dependencies": { - "@jest/test-result": "^27.5.1", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-runtime": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", - "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.1.0", - "@jest/types": "^27.5.1", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-util": "^27.5.1", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.4.tgz", - "integrity": "sha512-cz8HFjOFfUBtvN+NXYSFMHYRdxZMaEl0XypVrhzxBgadKIXhIkRd8aMeHhmF56Sl7SuS8OnUpQ73/k9LE4VnLg==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.10", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.10.tgz", - "integrity": "sha512-Ht8wIW5v165atIX1p+JvKR5ONzUyF4Ac8DZIQ5kZs9zrb6M8SJNXpx1zn04rn65VjBMygRoMXcyYwNK0fT7bEg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", - "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@project-serum/borsh": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@project-serum/borsh/-/borsh-0.2.4.tgz", - "integrity": "sha512-tQPc1ktAp1Jtn9D72DmObAfhAic9ivfYBOS5b+T4H7MvkQ84uML88LY1LfvGep30mCy+ua5rf+X9ocPfg6u9MA==", - "dependencies": { - "bn.js": "^5.1.2", - "buffer-layout": "^1.2.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@solana/web3.js": "^1.2.0" - } - }, - "node_modules/@rollup/plugin-alias": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-3.1.9.tgz", - "integrity": "sha512-QI5fsEvm9bDzt32k39wpOwZhVzRcL5ydcffUHMyLVaVaLeC70I8TJZ17F1z1eMoLu4E/UOcH9BWVkKpIKdrfiw==", - "dev": true, - "dependencies": { - "slash": "^3.0.0" - }, - "engines": { - "node": ">=8.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@rollup/plugin-commonjs": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-21.0.1.tgz", - "integrity": "sha512-EA+g22lbNJ8p5kuZJUYyhhDK7WgJckW5g4pNN7n4mAFUM96VuwUnNT3xr2Db2iCZPI1pJPbGyfT5mS9T1dHfMg==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "commondir": "^1.0.1", - "estree-walker": "^2.0.1", - "glob": "^7.1.6", - "is-reference": "^1.2.1", - "magic-string": "^0.25.7", - "resolve": "^1.17.0" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^2.38.3" - } - }, - "node_modules/@rollup/plugin-json": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", - "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.0.8" - }, - "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" - } - }, - "node_modules/@rollup/plugin-multi-entry": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-multi-entry/-/plugin-multi-entry-4.1.0.tgz", - "integrity": "sha512-nellK5pr50W0JA2+bDJbG8F79GBP802J40YRoC0wyfpTAeAn5mJ4eaFiB/MN+YoX9hgb/6RJoZl9leDjZnUFKw==", - "dev": true, - "dependencies": { - "@rollup/plugin-virtual": "^2.0.3", - "matched": "^5.0.0" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" - } - }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.1.3.tgz", - "integrity": "sha512-BdxNk+LtmElRo5d06MGY4zoepyrXX1tkzX2hrnPEZ53k78GuOMWLqmJDGIIOPwVRIFZrLQOo+Yr6KtCuLIA0AQ==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "rollup": "^2.42.0" - } - }, - "node_modules/@rollup/plugin-typescript": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.3.0.tgz", - "integrity": "sha512-I5FpSvLbtAdwJ+naznv+B4sjXZUcIvLLceYpITAn7wAP8W0wqc5noLdGIp9HGVntNhRWXctwPYrSSFQxtl0FPA==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "resolve": "^1.17.0" - }, - "engines": { - "node": ">=8.0.0" - }, - "peerDependencies": { - "rollup": "^2.14.0", - "tslib": "*", - "typescript": ">=3.7.0" - } - }, - "node_modules/@rollup/plugin-virtual": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-2.0.3.tgz", - "integrity": "sha512-pw6ziJcyjZtntQ//bkad9qXaBx665SgEL8C8KI5wO8G5iU5MPxvdWrQyVaAvjojGm9tJoS8M9Z/EEepbqieYmw==", - "dev": true, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dev": true, - "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true - }, - "node_modules/@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "node_modules/@solana/buffer-layout": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.0.tgz", - "integrity": "sha512-lR0EMP2HC3+Mxwd4YcnZb0smnaDw7Bl2IQWZiTevRH5ZZBZn6VRWn3/92E3qdU4SSImJkA6IDHawOHAnx/qUvQ==", - "dependencies": { - "buffer": "~6.0.3" - }, - "engines": { - "node": ">=5.10" - } - }, - "node_modules/@solana/spl-token": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.1.8.tgz", - "integrity": "sha512-LZmYCKcPQDtJgecvWOgT/cnoIQPWjdH+QVyzPcFvyDUiT0DiRjZaam4aqNUyvchLFhzgunv3d9xOoyE34ofdoQ==", - "dependencies": { - "@babel/runtime": "^7.10.5", - "@solana/web3.js": "^1.21.0", - "bn.js": "^5.1.0", - "buffer": "6.0.3", - "buffer-layout": "^1.2.0", - "dotenv": "10.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@solana/web3.js": { - "version": "1.34.0", - "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.34.0.tgz", - "integrity": "sha512-6QvqN2DqEELvuV+5yUQM8P9fRiSG+6SzQ58HjumJqODu14r7eu5HXVWEymvKAvMLGME+0TmAdJHjw9xD5NgUWA==", - "dependencies": { - "@babel/runtime": "^7.12.5", - "@ethersproject/sha2": "^5.5.0", - "@solana/buffer-layout": "^3.0.0", - "bn.js": "^5.0.0", - "borsh": "^0.4.0", - "bs58": "^4.0.1", - "buffer": "6.0.1", - "cross-fetch": "^3.1.4", - "jayson": "^3.4.4", - "js-sha3": "^0.8.0", - "rpc-websockets": "^7.4.2", - "secp256k1": "^4.0.2", - "superstruct": "^0.14.2", - "tweetnacl": "^1.0.0" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/@solana/web3.js/node_modules/@solana/buffer-layout": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-3.0.0.tgz", - "integrity": "sha512-MVdgAKKL39tEs0l8je0hKaXLQFb7Rdfb0Xg2LjFZd8Lfdazkg6xiS98uAZrEKvaoF3i4M95ei9RydkGIDMeo3w==", - "dependencies": { - "buffer": "~6.0.3" - }, - "engines": { - "node": ">=5.10" - } - }, - "node_modules/@solana/web3.js/node_modules/@solana/buffer-layout/node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/@solana/web3.js/node_modules/buffer": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.1.tgz", - "integrity": "sha512-rVAXBwEcEoYtxnHSO5iWyhzV/O1WMtkUYWlfdLS7FjU4PnSJJHEfHXi/uHPI5EwltmOA794gN3bm3/pzuctWjQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@types/babel__core": { - "version": "7.1.18", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz", - "integrity": "sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", - "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.3.0" - } - }, - "node_modules/@types/bn.js": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.0.tgz", - "integrity": "sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.17.28", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", - "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.4.0.tgz", - "integrity": "sha512-gHl8XuC1RZ8H2j5sHv/JqsaxXkDDM9iDOgu0Wp8sjs4u/snb2PVehyWXJPr+ORA0RPpgw231mnutWI1+0hgjIQ==", - "dev": true, - "dependencies": { - "jest-diff": "^27.0.0", - "pretty-format": "^27.0.0" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", - "dev": true - }, - "node_modules/@types/lodash": { - "version": "4.14.178", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz", - "integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==" - }, - "node_modules/@types/node": { - "version": "17.0.17", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.17.tgz", - "integrity": "sha512-e8PUNQy1HgJGV3iU/Bp2+D/DXh3PYeyli8LgIwsQcs1Ar1LoaWHSIT6Rw+H2rNJmiq6SNWiDytfx8+gYj7wDHw==" - }, - "node_modules/@types/prettier": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.4.tgz", - "integrity": "sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA==", - "dev": true - }, - "node_modules/@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" - }, - "node_modules/@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" - }, - "node_modules/@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "node_modules/@types/ws": { - "version": "7.4.7", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", - "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "20.2.1", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", - "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.11.0.tgz", - "integrity": "sha512-HJh33bgzXe6jGRocOj4FmefD7hRY4itgjzOrSs3JPrTNXsX7j5+nQPciAUj/1nZtwo2kAc3C75jZO+T23gzSGw==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.11.0", - "@typescript-eslint/type-utils": "5.11.0", - "@typescript-eslint/utils": "5.11.0", - "debug": "^4.3.2", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.1.8", - "regexpp": "^3.2.0", - "semver": "^7.3.5", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.11.0.tgz", - "integrity": "sha512-x0DCjetHZYBRovJdr3U0zG9OOdNXUaFLJ82ehr1AlkArljJuwEsgnud+Q7umlGDFLFrs8tU8ybQDFocp/eX8mQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.11.0", - "@typescript-eslint/types": "5.11.0", - "@typescript-eslint/typescript-estree": "5.11.0", - "debug": "^4.3.2" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.11.0.tgz", - "integrity": "sha512-z+K4LlahDFVMww20t/0zcA7gq/NgOawaLuxgqGRVKS0PiZlCTIUtX0EJbC0BK1JtR4CelmkPK67zuCgpdlF4EA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.11.0", - "@typescript-eslint/visitor-keys": "5.11.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.11.0.tgz", - "integrity": "sha512-wDqdsYO6ofLaD4DsGZ0jGwxp4HrzD2YKulpEZXmgN3xo4BHJwf7kq49JTRpV0Gx6bxkSUmc9s0EIK1xPbFFpIA==", - "dev": true, - "dependencies": { - "@typescript-eslint/utils": "5.11.0", - "debug": "^4.3.2", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.11.0.tgz", - "integrity": "sha512-cxgBFGSRCoBEhvSVLkKw39+kMzUKHlJGVwwMbPcTZX3qEhuXhrjwaZXWMxVfxDgyMm+b5Q5b29Llo2yow8Y7xQ==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.11.0.tgz", - "integrity": "sha512-yVH9hKIv3ZN3lw8m/Jy5I4oXO4ZBMqijcXCdA4mY8ull6TPTAoQnKKrcZ0HDXg7Bsl0Unwwx7jcXMuNZc0m4lg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.11.0", - "@typescript-eslint/visitor-keys": "5.11.0", - "debug": "^4.3.2", - "globby": "^11.0.4", - "is-glob": "^4.0.3", - "semver": "^7.3.5", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.11.0.tgz", - "integrity": "sha512-g2I480tFE1iYRDyMhxPAtLQ9HAn0jjBtipgTCZmd9I9s11OV8CTsG+YfFciuNDcHqm4csbAgC2aVZCHzLxMSUw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.11.0", - "@typescript-eslint/types": "5.11.0", - "@typescript-eslint/typescript-estree": "5.11.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.11.0.tgz", - "integrity": "sha512-E8w/vJReMGuloGxJDkpPlGwhxocxOpSVgSvjiLO5IxZPmxZF30weOeJYyPSEACwM+X4NziYS9q+WkN/2DHYQwA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.11.0", - "eslint-visitor-keys": "^3.0.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } - }, - "node_modules/acorn-globals/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "node_modules/babel-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", - "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", - "dev": true, - "dependencies": { - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^27.5.1", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", - "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", - "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", - "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^27.5.1", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/base-x": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", - "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/bn.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", - "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" - }, - "node_modules/borsh": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.4.0.tgz", - "integrity": "sha512-aX6qtLya3K0AkT66CmYWCCDr77qsE9arV05OmdFpmat9qu8Pg9J5tBUPDztAW5fNh/d/MyVG/OYziP52Ndzx1g==", - "dependencies": { - "@types/bn.js": "^4.11.5", - "bn.js": "^5.0.0", - "bs58": "^4.0.0", - "text-encoding-utf-8": "^1.0.2" - } - }, - "node_modules/borsh/node_modules/@types/bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" - }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, - "node_modules/browserslist": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", - "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", - "dev": true, - "dependencies": { - "caniuse-lite": "^1.0.30001286", - "electron-to-chromium": "^1.4.17", - "escalade": "^3.1.1", - "node-releases": "^2.0.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bs58": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", - "dependencies": { - "base-x": "^3.0.2" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/buffer-layout": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz", - "integrity": "sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==", - "engines": { - "node": ">=4.5" - } - }, - "node_modules/bufferutil": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz", - "integrity": "sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==", - "hasInstallScript": true, - "optional": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } - }, - "node_modules/builtin-modules": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", - "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001311", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001311.tgz", - "integrity": "sha512-mleTFtFKfykEeW34EyfhGIFjGCqzhh38Y0LhdQ9aWF+HorZTtdgKV/1hEE0NlFkG2ubvisPV6l400tlbPys98A==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", - "dev": true - }, - "node_modules/circular-json": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.9.tgz", - "integrity": "sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ==", - "deprecated": "CircularJSON is in maintenance only, flatted is its successor." - }, - "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/convert-source-map/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/cross-env": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", - "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.1" - }, - "bin": { - "cross-env": "src/bin/cross-env.js", - "cross-env-shell": "src/bin/cross-env-shell.js" - }, - "engines": { - "node": ">=10.14", - "npm": ">=6", - "yarn": ">=1" - } - }, - "node_modules/cross-fetch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", - "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", - "dependencies": { - "node-fetch": "2.6.7" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "dependencies": { - "cssom": "~0.3.6" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "node_modules/data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dev": true, - "dependencies": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", - "dev": true - }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/delay": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", - "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/diff-sequences": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", - "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dev": true, - "dependencies": { - "webidl-conversions": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/domexception/node_modules/webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", - "engines": { - "node": ">=10" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.68", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.68.tgz", - "integrity": "sha512-cId+QwWrV8R1UawO6b9BR1hnkJ4EJPCPAr4h315vliHUtVUJDk39Sg1PMNnaWKfj5x+93ssjeJ9LKL6r8LaMiA==", - "dev": true - }, - "node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "node_modules/emittery": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", - "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" - }, - "node_modules/es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", - "dependencies": { - "es6-promise": "^4.0.3" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/escodegen/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/eslint": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.8.0.tgz", - "integrity": "sha512-H3KXAzQGBH1plhYS3okDix2ZthuYJlQQEGE5k0IKuEqUSiyu4AmxxlJ2MtTYeJ3xB4jDhcYCwGOg2TXYdnDXlQ==", - "dev": true, - "dependencies": { - "@eslint/eslintrc": "^1.0.5", - "@humanwhocodes/config-array": "^0.9.2", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.0", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.2.0", - "espree": "^9.3.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.6.0", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-prettier": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", - "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz", - "integrity": "sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==", - "dev": true, - "dependencies": { - "prettier-linter-helpers": "^1.0.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "peerDependencies": { - "eslint": ">=7.28.0", - "prettier": ">=2.0.0" - }, - "peerDependenciesMeta": { - "eslint-config-prettier": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz", - "integrity": "sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.0.tgz", - "integrity": "sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/espree": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.0.tgz", - "integrity": "sha512-d/5nCsb0JcqsSEeQzFZ8DH1RmxPcglRWh24EFTlUEmCKoehXGdpsx0RkHDubqUI8LSAIKMQp4r9SzQ3n+sm4HQ==", - "dev": true, - "dependencies": { - "acorn": "^8.7.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^3.1.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", - "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/eyes": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", - "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", - "engines": { - "node": "> 0.1.90" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", - "dev": true, - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", - "dev": true - }, - "node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dev": true, - "dependencies": { - "whatwg-encoding": "^1.0.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "node_modules/is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", - "dev": true - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "node_modules/is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "dev": true, - "dependencies": { - "@types/estree": "*" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/isomorphic-ws": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", - "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", - "peerDependencies": { - "ws": "*" - } - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", - "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jayson": { - "version": "3.6.6", - "resolved": "https://registry.npmjs.org/jayson/-/jayson-3.6.6.tgz", - "integrity": "sha512-f71uvrAWTtrwoww6MKcl9phQTC+56AopLyEenWvKVAIMz+q0oVGj6tenLZ7Z6UiPBkJtKLj4kt0tACllFQruGQ==", - "dependencies": { - "@types/connect": "^3.4.33", - "@types/express-serve-static-core": "^4.17.9", - "@types/lodash": "^4.14.159", - "@types/node": "^12.12.54", - "@types/ws": "^7.4.4", - "commander": "^2.20.3", - "delay": "^5.0.0", - "es6-promisify": "^5.0.0", - "eyes": "^0.1.8", - "isomorphic-ws": "^4.0.1", - "json-stringify-safe": "^5.0.1", - "JSONStream": "^1.3.5", - "lodash": "^4.17.20", - "uuid": "^8.3.2", - "ws": "^7.4.5" - }, - "bin": { - "jayson": "bin/jayson.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jayson/node_modules/@types/node": { - "version": "12.20.45", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.45.tgz", - "integrity": "sha512-1Jg2Qv5tuxBqgQV04+wO5u+wmSHbHgpORCJdeCLM+E+YdPElpdHhgywU+M1V1InL8rfOtpqtOjswk+uXTKwx7w==" - }, - "node_modules/jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", - "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", - "dev": true, - "dependencies": { - "@jest/core": "^27.5.1", - "import-local": "^3.0.2", - "jest-cli": "^27.5.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", - "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "execa": "^5.0.0", - "throat": "^6.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-circus": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", - "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", - "dev": true, - "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "expect": "^27.5.1", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3", - "throat": "^6.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-cli": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", - "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", - "dev": true, - "dependencies": { - "@jest/core": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "prompts": "^2.0.1", - "yargs": "^16.2.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-config": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", - "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.8.0", - "@jest/test-sequencer": "^27.5.1", - "@jest/types": "^27.5.1", - "babel-jest": "^27.5.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.9", - "jest-circus": "^27.5.1", - "jest-environment-jsdom": "^27.5.1", - "jest-environment-node": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-jasmine2": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-runner": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-diff": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", - "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-docblock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", - "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", - "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-each": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", - "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "jest-get-type": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-environment-jsdom": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", - "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", - "dev": true, - "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1", - "jsdom": "^16.6.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-environment-node": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", - "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", - "dev": true, - "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", - "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^27.5.1", - "jest-serializer": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "micromatch": "^4.0.4", - "walker": "^1.0.7" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-jasmine2": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", - "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", - "dev": true, - "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/source-map": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^27.5.1", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1", - "throat": "^6.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-leak-detector": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", - "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", - "dev": true, - "dependencies": { - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", - "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-mock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", - "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", - "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", - "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", - "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-snapshot": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-runner": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", - "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", - "dev": true, - "dependencies": { - "@jest/console": "^27.5.1", - "@jest/environment": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^27.5.1", - "jest-environment-jsdom": "^27.5.1", - "jest-environment-node": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-leak-detector": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "source-map-support": "^0.5.6", - "throat": "^6.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-runtime": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", - "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", - "dev": true, - "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/globals": "^27.5.1", - "@jest/source-map": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "execa": "^5.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-serializer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", - "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", - "dev": true, - "dependencies": { - "@types/node": "*", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", - "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.7.2", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.0.0", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^27.5.1", - "graceful-fs": "^4.2.9", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-util": "^27.5.1", - "natural-compare": "^1.4.0", - "pretty-format": "^27.5.1", - "semver": "^7.3.2" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-validate": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", - "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.5.1", - "leven": "^3.1.0", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watcher": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", - "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", - "dev": true, - "dependencies": { - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^27.5.1", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/js-sha3": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dev": true, - "dependencies": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "node_modules/json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", - "engines": [ - "node >= 0.2.0" - ] - }, - "node_modules/JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "dependencies": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - }, - "bin": { - "JSONStream": "bin.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", - "dev": true, - "dependencies": { - "sourcemap-codec": "^1.4.4" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/matched": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/matched/-/matched-5.0.1.tgz", - "integrity": "sha512-E1fhSTPRyhAlNaNvGXAgZQlq1hL0bgYMTk/6bktVlIhzUnX/SZs7296ACdVeNJE8xFNGSuvd9IpI7vSnmcqLvw==", - "dev": true, - "dependencies": { - "glob": "^7.1.6", - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", - "dev": true, - "dependencies": { - "mime-db": "1.51.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" - }, - "node_modules/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node_modules/node-addon-api": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", - "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==" - }, - "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-fetch/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" - }, - "node_modules/node-fetch/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" - }, - "node_modules/node-fetch/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/node-gyp-build": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", - "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", - "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", - "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rollup": { - "version": "2.67.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.67.2.tgz", - "integrity": "sha512-hoEiBWwZtf1QdK3jZIq59L0FJj4Fiv4RplCO4pvCRC86qsoFurWB4hKQIjoRf3WvJmk5UZ9b0y5ton+62fC7Tw==", - "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/rollup-plugin-dts": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-dts/-/rollup-plugin-dts-4.1.0.tgz", - "integrity": "sha512-rriXIm3jdUiYeiAAd1Fv+x2AxK6Kq6IybB2Z/IdoAW95fb4uRUurYsEYKa8L1seedezDeJhy8cfo8FEL9aZzqg==", - "dev": true, - "dependencies": { - "magic-string": "^0.25.7" - }, - "engines": { - "node": ">=v12.22.7" - }, - "funding": { - "url": "https://github.com/sponsors/Swatinem" - }, - "optionalDependencies": { - "@babel/code-frame": "^7.16.0" - }, - "peerDependencies": { - "rollup": "^2.55", - "typescript": "~4.1 || ~4.2 || ~4.3 || ~4.4 || ~4.5" - } - }, - "node_modules/rollup-plugin-inject": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz", - "integrity": "sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==", - "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject.", - "dev": true, - "dependencies": { - "estree-walker": "^0.6.1", - "magic-string": "^0.25.3", - "rollup-pluginutils": "^2.8.1" - } - }, - "node_modules/rollup-plugin-inject/node_modules/estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", - "dev": true - }, - "node_modules/rollup-plugin-node-polyfills": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz", - "integrity": "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==", - "dev": true, - "dependencies": { - "rollup-plugin-inject": "^3.0.0" - } - }, - "node_modules/rollup-plugin-terser": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", - "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "jest-worker": "^26.2.1", - "serialize-javascript": "^4.0.0", - "terser": "^5.0.0" - }, - "peerDependencies": { - "rollup": "^2.0.0" - } - }, - "node_modules/rollup-plugin-terser/node_modules/jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/rollup-pluginutils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", - "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", - "dev": true, - "dependencies": { - "estree-walker": "^0.6.1" - } - }, - "node_modules/rollup-pluginutils/node_modules/estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", - "dev": true - }, - "node_modules/rpc-websockets": { - "version": "7.4.17", - "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-7.4.17.tgz", - "integrity": "sha512-eolVi/qlXS13viIUH9aqrde902wzSLAai0IjmOZSRefp5I3CSG/vCnD0c0fDSYCWuEyUoRL1BHQA8K1baEUyow==", - "dependencies": { - "@babel/runtime": "^7.11.2", - "circular-json": "^0.5.9", - "eventemitter3": "^4.0.7", - "uuid": "^8.3.0", - "ws": "^7.4.5" - }, - "funding": { - "type": "paypal", - "url": "https://paypal.me/kozjak" - }, - "optionalDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dev": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/secp256k1": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", - "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", - "hasInstallScript": true, - "dependencies": { - "elliptic": "^6.5.4", - "node-addon-api": "^2.0.0", - "node-gyp-build": "^4.2.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/superstruct": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.14.2.tgz", - "integrity": "sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==" - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "node_modules/terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/terser": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", - "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", - "dev": true, - "dependencies": { - "commander": "^2.20.0", - "source-map": "~0.7.2", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "acorn": "^8.5.0" - }, - "peerDependenciesMeta": { - "acorn": { - "optional": true - } - } - }, - "node_modules/terser/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-encoding-utf-8": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", - "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==" - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "node_modules/throat": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", - "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", - "dev": true - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", - "dev": true, - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", - "dev": true, - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ts-jest": { - "version": "27.1.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.3.tgz", - "integrity": "sha512-6Nlura7s6uM9BVUAoqLH7JHyMXjz8gluryjpPXxr3IxZdAXnU6FhjvVLHFtfd1vsE1p8zD1OJfskkc0jhTSnkA==", - "dev": true, - "dependencies": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^27.0.0", - "json5": "2.x", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "7.x", - "yargs-parser": "20.x" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@types/jest": "^27.0.0", - "babel-jest": ">=27.0.0 <28", - "esbuild": "~0.14.0", - "jest": "^27.0.0", - "typescript": ">=3.8 <5.0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@types/jest": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - } - } - }, - "node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true, - "peer": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "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" - } - }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/typescript": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", - "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/utf-8-validate": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.8.tgz", - "integrity": "sha512-k4dW/Qja1BYDl2qD4tOMB9PFVha/UJtxTc1cXYOe3WwA/2m0Yn4qB7wLMpJyLJ/7DR0XnTut3HsCSzDT4ZvKgA==", - "hasInstallScript": true, - "optional": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "node_modules/v8-to-istanbul": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", - "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/v8-to-istanbul/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "dependencies": { - "browser-process-hrtime": "^1.0.0" - } - }, - "node_modules/w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dev": true, - "dependencies": { - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true, - "engines": { - "node": ">=10.4" - } - }, - "node_modules/whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "dependencies": { - "iconv-lite": "0.4.24" - } - }, - "node_modules/whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, - "node_modules/whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", - "dev": true, - "dependencies": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - } - }, - "dependencies": { - "@ampproject/remapping": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.0.tgz", - "integrity": "sha512-d5RysTlJ7hmw5Tw4UxgxcY3lkMe92n8sXCcuLPAyIAHK6j8DefDwtGnVVDgOnv+RnEosulDJ9NPKQL27bDId0g==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.0" - } - }, - "@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", - "dev": true, - "requires": { - "@babel/highlight": "^7.16.7" - } - }, - "@babel/compat-data": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", - "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", - "dev": true - }, - "@babel/core": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.2.tgz", - "integrity": "sha512-R3VH5G42VSDolRHyUO4V2cfag8WHcZyxdq5Z/m8Xyb92lW/Erm/6kM+XtRFGf3Mulre3mveni2NHfEUws8wSvw==", - "dev": true, - "requires": { - "@ampproject/remapping": "^2.0.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.0", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helpers": "^7.17.2", - "@babel/parser": "^7.17.0", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.0", - "@babel/types": "^7.17.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.0.tgz", - "integrity": "sha512-I3Omiv6FGOC29dtlZhkfXO6pgkmukJSlT26QjVvS1DGZe/NzSVCPG41X0tS21oZkJYlovfj9qDWgKP+Cn4bXxw==", - "dev": true, - "requires": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/helper-compilation-targets": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", - "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.16.4", - "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.17.5", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/helper-environment-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", - "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-module-imports": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", - "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-module-transforms": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", - "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", - "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", - "dev": true - }, - "@babel/helper-simple-access": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", - "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", - "dev": true - }, - "@babel/helper-validator-option": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", - "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", - "dev": true - }, - "@babel/helpers": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", - "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", - "dev": true, - "requires": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.0", - "@babel/types": "^7.17.0" - } - }, - "@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/parser": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.0.tgz", - "integrity": "sha512-VKXSCQx5D8S04ej+Dqsr1CzYvvWgf20jIw2D+YhQCrIlr2UZGaDds23Y0xg75/skOxpLCRpUZvk/1EAVkGoDOw==", - "dev": true - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-typescript": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", - "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/runtime": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", - "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/traverse": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.0.tgz", - "integrity": "sha512-fpFIXvqD6kC7c7PUNnZ0Z8cQXlarCLtCUpt2S1Dx7PjoRtCFffvOkHHSom+m5HIxMZn5bIBVb71lhabcmjEsqg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.0", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.0", - "@babel/types": "^7.17.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "dependencies": { - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.16.7", - "to-fast-properties": "^2.0.0" - } - }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "@eslint/eslintrc": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz", - "integrity": "sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.2.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - } - } - }, - "@ethersproject/bytes": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.5.0.tgz", - "integrity": "sha512-ABvc7BHWhZU9PNM/tANm/Qx4ostPGadAuQzWTr3doklZOhDlmcBqclrQe/ZXUIj3K8wC28oYeuRa+A37tX9kog==", - "requires": { - "@ethersproject/logger": "^5.5.0" - } - }, - "@ethersproject/logger": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.5.0.tgz", - "integrity": "sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg==" - }, - "@ethersproject/sha2": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.5.0.tgz", - "integrity": "sha512-B5UBoglbCiHamRVPLA110J+2uqsifpZaTmid2/7W5rbtYVz6gus6/hSDieIU/6gaKIDcOj12WnOdiymEUHIAOA==", - "requires": { - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "hash.js": "1.1.7" - } - }, - "@humanwhocodes/config-array": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.3.tgz", - "integrity": "sha512-3xSMlXHh03hCcCmFc0rbKp3Ivt2PFEJnQUJDDMTJQ2wkECZWdq4GePs2ctc5H8zV+cHPaq8k2vU8mrQjA6iHdQ==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - } - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "@jest/console": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", - "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^27.5.1", - "jest-util": "^27.5.1", - "slash": "^3.0.0" - } - }, - "@jest/core": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", - "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", - "dev": true, - "requires": { - "@jest/console": "^27.5.1", - "@jest/reporters": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^27.5.1", - "jest-config": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-resolve-dependencies": "^27.5.1", - "jest-runner": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "jest-watcher": "^27.5.1", - "micromatch": "^4.0.4", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "@jest/environment": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", - "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", - "dev": true, - "requires": { - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1" - } - }, - "@jest/fake-timers": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", - "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "@sinonjs/fake-timers": "^8.0.1", - "@types/node": "*", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" - } - }, - "@jest/globals": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", - "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", - "dev": true, - "requires": { - "@jest/environment": "^27.5.1", - "@jest/types": "^27.5.1", - "expect": "^27.5.1" - } - }, - "@jest/reporters": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", - "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", - "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-haste-map": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^8.1.0" - } - }, - "@jest/source-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", - "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", - "dev": true, - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9", - "source-map": "^0.6.0" - } - }, - "@jest/test-result": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", - "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", - "dev": true, - "requires": { - "@jest/console": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/test-sequencer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", - "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", - "dev": true, - "requires": { - "@jest/test-result": "^27.5.1", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-runtime": "^27.5.1" - } - }, - "@jest/transform": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", - "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^27.5.1", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-util": "^27.5.1", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" - } - }, - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.4.tgz", - "integrity": "sha512-cz8HFjOFfUBtvN+NXYSFMHYRdxZMaEl0XypVrhzxBgadKIXhIkRd8aMeHhmF56Sl7SuS8OnUpQ73/k9LE4VnLg==", - "dev": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.10", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.10.tgz", - "integrity": "sha512-Ht8wIW5v165atIX1p+JvKR5ONzUyF4Ac8DZIQ5kZs9zrb6M8SJNXpx1zn04rn65VjBMygRoMXcyYwNK0fT7bEg==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", - "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@project-serum/borsh": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@project-serum/borsh/-/borsh-0.2.4.tgz", - "integrity": "sha512-tQPc1ktAp1Jtn9D72DmObAfhAic9ivfYBOS5b+T4H7MvkQ84uML88LY1LfvGep30mCy+ua5rf+X9ocPfg6u9MA==", - "requires": { - "bn.js": "^5.1.2", - "buffer-layout": "^1.2.0" - } - }, - "@rollup/plugin-alias": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-3.1.9.tgz", - "integrity": "sha512-QI5fsEvm9bDzt32k39wpOwZhVzRcL5ydcffUHMyLVaVaLeC70I8TJZ17F1z1eMoLu4E/UOcH9BWVkKpIKdrfiw==", - "dev": true, - "requires": { - "slash": "^3.0.0" - } - }, - "@rollup/plugin-commonjs": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-21.0.1.tgz", - "integrity": "sha512-EA+g22lbNJ8p5kuZJUYyhhDK7WgJckW5g4pNN7n4mAFUM96VuwUnNT3xr2Db2iCZPI1pJPbGyfT5mS9T1dHfMg==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.1.0", - "commondir": "^1.0.1", - "estree-walker": "^2.0.1", - "glob": "^7.1.6", - "is-reference": "^1.2.1", - "magic-string": "^0.25.7", - "resolve": "^1.17.0" - } - }, - "@rollup/plugin-json": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", - "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.0.8" - } - }, - "@rollup/plugin-multi-entry": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-multi-entry/-/plugin-multi-entry-4.1.0.tgz", - "integrity": "sha512-nellK5pr50W0JA2+bDJbG8F79GBP802J40YRoC0wyfpTAeAn5mJ4eaFiB/MN+YoX9hgb/6RJoZl9leDjZnUFKw==", - "dev": true, - "requires": { - "@rollup/plugin-virtual": "^2.0.3", - "matched": "^5.0.0" - } - }, - "@rollup/plugin-node-resolve": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.1.3.tgz", - "integrity": "sha512-BdxNk+LtmElRo5d06MGY4zoepyrXX1tkzX2hrnPEZ53k78GuOMWLqmJDGIIOPwVRIFZrLQOo+Yr6KtCuLIA0AQ==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.19.0" - } - }, - "@rollup/plugin-typescript": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.3.0.tgz", - "integrity": "sha512-I5FpSvLbtAdwJ+naznv+B4sjXZUcIvLLceYpITAn7wAP8W0wqc5noLdGIp9HGVntNhRWXctwPYrSSFQxtl0FPA==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.1.0", - "resolve": "^1.17.0" - } - }, - "@rollup/plugin-virtual": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-2.0.3.tgz", - "integrity": "sha512-pw6ziJcyjZtntQ//bkad9qXaBx665SgEL8C8KI5wO8G5iU5MPxvdWrQyVaAvjojGm9tJoS8M9Z/EEepbqieYmw==", - "dev": true, - "requires": {} - }, - "@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dev": true, - "requires": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "dependencies": { - "estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true - } - } - }, - "@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, - "@solana/buffer-layout": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.0.tgz", - "integrity": "sha512-lR0EMP2HC3+Mxwd4YcnZb0smnaDw7Bl2IQWZiTevRH5ZZBZn6VRWn3/92E3qdU4SSImJkA6IDHawOHAnx/qUvQ==", - "requires": { - "buffer": "~6.0.3" - } - }, - "@solana/spl-token": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.1.8.tgz", - "integrity": "sha512-LZmYCKcPQDtJgecvWOgT/cnoIQPWjdH+QVyzPcFvyDUiT0DiRjZaam4aqNUyvchLFhzgunv3d9xOoyE34ofdoQ==", - "requires": { - "@babel/runtime": "^7.10.5", - "@solana/web3.js": "^1.21.0", - "bn.js": "^5.1.0", - "buffer": "6.0.3", - "buffer-layout": "^1.2.0", - "dotenv": "10.0.0" - } - }, - "@solana/web3.js": { - "version": "1.34.0", - "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.34.0.tgz", - "integrity": "sha512-6QvqN2DqEELvuV+5yUQM8P9fRiSG+6SzQ58HjumJqODu14r7eu5HXVWEymvKAvMLGME+0TmAdJHjw9xD5NgUWA==", - "requires": { - "@babel/runtime": "^7.12.5", - "@ethersproject/sha2": "^5.5.0", - "@solana/buffer-layout": "^3.0.0", - "bn.js": "^5.0.0", - "borsh": "^0.4.0", - "bs58": "^4.0.1", - "buffer": "6.0.1", - "cross-fetch": "^3.1.4", - "jayson": "^3.4.4", - "js-sha3": "^0.8.0", - "rpc-websockets": "^7.4.2", - "secp256k1": "^4.0.2", - "superstruct": "^0.14.2", - "tweetnacl": "^1.0.0" - }, - "dependencies": { - "@solana/buffer-layout": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-3.0.0.tgz", - "integrity": "sha512-MVdgAKKL39tEs0l8je0hKaXLQFb7Rdfb0Xg2LjFZd8Lfdazkg6xiS98uAZrEKvaoF3i4M95ei9RydkGIDMeo3w==", - "requires": { - "buffer": "~6.0.3" - }, - "dependencies": { - "buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - } - } - }, - "buffer": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.1.tgz", - "integrity": "sha512-rVAXBwEcEoYtxnHSO5iWyhzV/O1WMtkUYWlfdLS7FjU4PnSJJHEfHXi/uHPI5EwltmOA794gN3bm3/pzuctWjQ==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - } - } - }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true - }, - "@types/babel__core": { - "version": "7.1.18", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz", - "integrity": "sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", - "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/bn.js": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.0.tgz", - "integrity": "sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "requires": { - "@types/node": "*" - } - }, - "@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true - }, - "@types/express-serve-static-core": { - "version": "4.17.28", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", - "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/jest": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.4.0.tgz", - "integrity": "sha512-gHl8XuC1RZ8H2j5sHv/JqsaxXkDDM9iDOgu0Wp8sjs4u/snb2PVehyWXJPr+ORA0RPpgw231mnutWI1+0hgjIQ==", - "dev": true, - "requires": { - "jest-diff": "^27.0.0", - "pretty-format": "^27.0.0" - } - }, - "@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", - "dev": true - }, - "@types/lodash": { - "version": "4.14.178", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz", - "integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==" - }, - "@types/node": { - "version": "17.0.17", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.17.tgz", - "integrity": "sha512-e8PUNQy1HgJGV3iU/Bp2+D/DXh3PYeyli8LgIwsQcs1Ar1LoaWHSIT6Rw+H2rNJmiq6SNWiDytfx8+gYj7wDHw==" - }, - "@types/prettier": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.4.tgz", - "integrity": "sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA==", - "dev": true - }, - "@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" - }, - "@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" - }, - "@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "@types/ws": { - "version": "7.4.7", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", - "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", - "requires": { - "@types/node": "*" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "20.2.1", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", - "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", - "dev": true - }, - "@typescript-eslint/eslint-plugin": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.11.0.tgz", - "integrity": "sha512-HJh33bgzXe6jGRocOj4FmefD7hRY4itgjzOrSs3JPrTNXsX7j5+nQPciAUj/1nZtwo2kAc3C75jZO+T23gzSGw==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "5.11.0", - "@typescript-eslint/type-utils": "5.11.0", - "@typescript-eslint/utils": "5.11.0", - "debug": "^4.3.2", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.1.8", - "regexpp": "^3.2.0", - "semver": "^7.3.5", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/parser": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.11.0.tgz", - "integrity": "sha512-x0DCjetHZYBRovJdr3U0zG9OOdNXUaFLJ82ehr1AlkArljJuwEsgnud+Q7umlGDFLFrs8tU8ybQDFocp/eX8mQ==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "5.11.0", - "@typescript-eslint/types": "5.11.0", - "@typescript-eslint/typescript-estree": "5.11.0", - "debug": "^4.3.2" - } - }, - "@typescript-eslint/scope-manager": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.11.0.tgz", - "integrity": "sha512-z+K4LlahDFVMww20t/0zcA7gq/NgOawaLuxgqGRVKS0PiZlCTIUtX0EJbC0BK1JtR4CelmkPK67zuCgpdlF4EA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.11.0", - "@typescript-eslint/visitor-keys": "5.11.0" - } - }, - "@typescript-eslint/type-utils": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.11.0.tgz", - "integrity": "sha512-wDqdsYO6ofLaD4DsGZ0jGwxp4HrzD2YKulpEZXmgN3xo4BHJwf7kq49JTRpV0Gx6bxkSUmc9s0EIK1xPbFFpIA==", - "dev": true, - "requires": { - "@typescript-eslint/utils": "5.11.0", - "debug": "^4.3.2", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/types": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.11.0.tgz", - "integrity": "sha512-cxgBFGSRCoBEhvSVLkKw39+kMzUKHlJGVwwMbPcTZX3qEhuXhrjwaZXWMxVfxDgyMm+b5Q5b29Llo2yow8Y7xQ==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.11.0.tgz", - "integrity": "sha512-yVH9hKIv3ZN3lw8m/Jy5I4oXO4ZBMqijcXCdA4mY8ull6TPTAoQnKKrcZ0HDXg7Bsl0Unwwx7jcXMuNZc0m4lg==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.11.0", - "@typescript-eslint/visitor-keys": "5.11.0", - "debug": "^4.3.2", - "globby": "^11.0.4", - "is-glob": "^4.0.3", - "semver": "^7.3.5", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/utils": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.11.0.tgz", - "integrity": "sha512-g2I480tFE1iYRDyMhxPAtLQ9HAn0jjBtipgTCZmd9I9s11OV8CTsG+YfFciuNDcHqm4csbAgC2aVZCHzLxMSUw==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.11.0", - "@typescript-eslint/types": "5.11.0", - "@typescript-eslint/typescript-estree": "5.11.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - } - }, - "@typescript-eslint/visitor-keys": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.11.0.tgz", - "integrity": "sha512-E8w/vJReMGuloGxJDkpPlGwhxocxOpSVgSvjiLO5IxZPmxZF30weOeJYyPSEACwM+X4NziYS9q+WkN/2DHYQwA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.11.0", - "eslint-visitor-keys": "^3.0.0" - } - }, - "abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true - }, - "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "dev": true - }, - "acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "requires": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - }, - "dependencies": { - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - } - } - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - }, - "dependencies": { - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - } - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "babel-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", - "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", - "dev": true, - "requires": { - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^27.5.1", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - } - }, - "babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - } - }, - "babel-plugin-jest-hoist": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", - "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", - "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "requires": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - } - }, - "babel-preset-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", - "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^27.5.1", - "babel-preset-current-node-syntax": "^1.0.0" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "base-x": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", - "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "bn.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", - "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" - }, - "borsh": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.4.0.tgz", - "integrity": "sha512-aX6qtLya3K0AkT66CmYWCCDr77qsE9arV05OmdFpmat9qu8Pg9J5tBUPDztAW5fNh/d/MyVG/OYziP52Ndzx1g==", - "requires": { - "@types/bn.js": "^4.11.5", - "bn.js": "^5.0.0", - "bs58": "^4.0.0", - "text-encoding-utf-8": "^1.0.2" - }, - "dependencies": { - "@types/bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", - "requires": { - "@types/node": "*" - } - } - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" - }, - "browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, - "browserslist": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", - "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001286", - "electron-to-chromium": "^1.4.17", - "escalade": "^3.1.1", - "node-releases": "^2.0.1", - "picocolors": "^1.0.0" - } - }, - "bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "requires": { - "fast-json-stable-stringify": "2.x" - } - }, - "bs58": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", - "requires": { - "base-x": "^3.0.2" - } - }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "buffer-layout": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz", - "integrity": "sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==" - }, - "bufferutil": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz", - "integrity": "sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==", - "optional": true, - "requires": { - "node-gyp-build": "^4.3.0" - } - }, - "builtin-modules": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", - "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", - "dev": true - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001311", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001311.tgz", - "integrity": "sha512-mleTFtFKfykEeW34EyfhGIFjGCqzhh38Y0LhdQ9aWF+HorZTtdgKV/1hEE0NlFkG2ubvisPV6l400tlbPys98A==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true - }, - "ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", - "dev": true - }, - "circular-json": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.9.tgz", - "integrity": "sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ==" - }, - "cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } - } - }, - "cross-env": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", - "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.1" - } - }, - "cross-fetch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", - "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", - "requires": { - "node-fetch": "2.6.7" - } - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "requires": { - "cssom": "~0.3.6" - }, - "dependencies": { - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - } - } - }, - "data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dev": true, - "requires": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - } - }, - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", - "dev": true - }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true - }, - "delay": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", - "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==" - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true - }, - "diff-sequences": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", - "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dev": true, - "requires": { - "webidl-conversions": "^5.0.0" - }, - "dependencies": { - "webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true - } - } - }, - "dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" - }, - "electron-to-chromium": { - "version": "1.4.68", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.68.tgz", - "integrity": "sha512-cId+QwWrV8R1UawO6b9BR1hnkJ4EJPCPAr4h315vliHUtVUJDk39Sg1PMNnaWKfj5x+93ssjeJ9LKL6r8LaMiA==", - "dev": true - }, - "elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "requires": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } - } - }, - "emittery": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", - "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" - }, - "es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", - "requires": { - "es6-promise": "^4.0.3" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - } - } - }, - "eslint": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.8.0.tgz", - "integrity": "sha512-H3KXAzQGBH1plhYS3okDix2ZthuYJlQQEGE5k0IKuEqUSiyu4AmxxlJ2MtTYeJ3xB4jDhcYCwGOg2TXYdnDXlQ==", - "dev": true, - "requires": { - "@eslint/eslintrc": "^1.0.5", - "@humanwhocodes/config-array": "^0.9.2", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.0", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.2.0", - "espree": "^9.3.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.6.0", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "eslint-scope": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.0.tgz", - "integrity": "sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "eslint-config-prettier": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", - "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", - "dev": true, - "requires": {} - }, - "eslint-plugin-prettier": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz", - "integrity": "sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==", - "dev": true, - "requires": { - "prettier-linter-helpers": "^1.0.0" - } - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz", - "integrity": "sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ==", - "dev": true - }, - "espree": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.0.tgz", - "integrity": "sha512-d/5nCsb0JcqsSEeQzFZ8DH1RmxPcglRWh24EFTlUEmCKoehXGdpsx0RkHDubqUI8LSAIKMQp4r9SzQ3n+sm4HQ==", - "dev": true, - "requires": { - "acorn": "^8.7.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^3.1.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "expect": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", - "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1" - } - }, - "eyes": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", - "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, - "fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", - "dev": true, - "requires": { - "bser": "2.1.1" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", - "dev": true - }, - "form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dev": true, - "requires": { - "whatwg-encoding": "^1.0.5" - } - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "dev": true, - "requires": { - "@types/estree": "*" - } - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isomorphic-ws": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", - "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", - "requires": {} - }, - "istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - } - }, - "istanbul-reports": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", - "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "jayson": { - "version": "3.6.6", - "resolved": "https://registry.npmjs.org/jayson/-/jayson-3.6.6.tgz", - "integrity": "sha512-f71uvrAWTtrwoww6MKcl9phQTC+56AopLyEenWvKVAIMz+q0oVGj6tenLZ7Z6UiPBkJtKLj4kt0tACllFQruGQ==", - "requires": { - "@types/connect": "^3.4.33", - "@types/express-serve-static-core": "^4.17.9", - "@types/lodash": "^4.14.159", - "@types/node": "^12.12.54", - "@types/ws": "^7.4.4", - "commander": "^2.20.3", - "delay": "^5.0.0", - "es6-promisify": "^5.0.0", - "eyes": "^0.1.8", - "isomorphic-ws": "^4.0.1", - "json-stringify-safe": "^5.0.1", - "JSONStream": "^1.3.5", - "lodash": "^4.17.20", - "uuid": "^8.3.2", - "ws": "^7.4.5" - }, - "dependencies": { - "@types/node": { - "version": "12.20.45", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.45.tgz", - "integrity": "sha512-1Jg2Qv5tuxBqgQV04+wO5u+wmSHbHgpORCJdeCLM+E+YdPElpdHhgywU+M1V1InL8rfOtpqtOjswk+uXTKwx7w==" - } - } - }, - "jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", - "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", - "dev": true, - "requires": { - "@jest/core": "^27.5.1", - "import-local": "^3.0.2", - "jest-cli": "^27.5.1" - } - }, - "jest-changed-files": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", - "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "execa": "^5.0.0", - "throat": "^6.0.1" - } - }, - "jest-circus": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", - "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", - "dev": true, - "requires": { - "@jest/environment": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "expect": "^27.5.1", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3", - "throat": "^6.0.1" - } - }, - "jest-cli": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", - "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", - "dev": true, - "requires": { - "@jest/core": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "prompts": "^2.0.1", - "yargs": "^16.2.0" - } - }, - "jest-config": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", - "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", - "dev": true, - "requires": { - "@babel/core": "^7.8.0", - "@jest/test-sequencer": "^27.5.1", - "@jest/types": "^27.5.1", - "babel-jest": "^27.5.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.9", - "jest-circus": "^27.5.1", - "jest-environment-jsdom": "^27.5.1", - "jest-environment-node": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-jasmine2": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-runner": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - } - }, - "jest-diff": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", - "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - } - }, - "jest-docblock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", - "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", - "dev": true, - "requires": { - "detect-newline": "^3.0.0" - } - }, - "jest-each": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", - "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "jest-get-type": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1" - } - }, - "jest-environment-jsdom": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", - "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", - "dev": true, - "requires": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1", - "jsdom": "^16.6.0" - } - }, - "jest-environment-node": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", - "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", - "dev": true, - "requires": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" - } - }, - "jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", - "dev": true - }, - "jest-haste-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", - "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^27.5.1", - "jest-serializer": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "micromatch": "^4.0.4", - "walker": "^1.0.7" - } - }, - "jest-jasmine2": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", - "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", - "dev": true, - "requires": { - "@jest/environment": "^27.5.1", - "@jest/source-map": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^27.5.1", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1", - "throat": "^6.0.1" - } - }, - "jest-leak-detector": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", - "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", - "dev": true, - "requires": { - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - } - }, - "jest-matcher-utils": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", - "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - } - }, - "jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - } - }, - "jest-mock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", - "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "@types/node": "*" - } - }, - "jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "requires": {} - }, - "jest-regex-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", - "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", - "dev": true - }, - "jest-resolve": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", - "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - } - }, - "jest-resolve-dependencies": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", - "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-snapshot": "^27.5.1" - } - }, - "jest-runner": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", - "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", - "dev": true, - "requires": { - "@jest/console": "^27.5.1", - "@jest/environment": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^27.5.1", - "jest-environment-jsdom": "^27.5.1", - "jest-environment-node": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-leak-detector": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "source-map-support": "^0.5.6", - "throat": "^6.0.1" - } - }, - "jest-runtime": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", - "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", - "dev": true, - "requires": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/globals": "^27.5.1", - "@jest/source-map": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "execa": "^5.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - } - }, - "jest-serializer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", - "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", - "dev": true, - "requires": { - "@types/node": "*", - "graceful-fs": "^4.2.9" - } - }, - "jest-snapshot": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", - "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", - "dev": true, - "requires": { - "@babel/core": "^7.7.2", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.0.0", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^27.5.1", - "graceful-fs": "^4.2.9", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-util": "^27.5.1", - "natural-compare": "^1.4.0", - "pretty-format": "^27.5.1", - "semver": "^7.3.2" - } - }, - "jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - } - }, - "jest-validate": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", - "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.5.1", - "leven": "^3.1.0", - "pretty-format": "^27.5.1" - }, - "dependencies": { - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - } - } - }, - "jest-watcher": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", - "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", - "dev": true, - "requires": { - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^27.5.1", - "string-length": "^4.0.1" - } - }, - "jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "js-sha3": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dev": true, - "requires": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" - }, - "JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - } - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "dev": true - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", - "dev": true, - "requires": { - "sourcemap-codec": "^1.4.4" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "requires": { - "tmpl": "1.0.5" - } - }, - "matched": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/matched/-/matched-5.0.1.tgz", - "integrity": "sha512-E1fhSTPRyhAlNaNvGXAgZQlq1hL0bgYMTk/6bktVlIhzUnX/SZs7296ACdVeNJE8xFNGSuvd9IpI7vSnmcqLvw==", - "dev": true, - "requires": { - "glob": "^7.1.6", - "picomatch": "^2.2.1" - } - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", - "dev": true - }, - "mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", - "dev": true, - "requires": { - "mime-db": "1.51.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" - }, - "minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node-addon-api": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", - "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==" - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "requires": { - "whatwg-url": "^5.0.0" - }, - "dependencies": { - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - } - } - }, - "node-gyp-build": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", - "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==" - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true - }, - "node-releases": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", - "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "prettier": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", - "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", - "dev": true - }, - "prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "requires": { - "fast-diff": "^1.1.2" - } - }, - "pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - } - }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, - "requires": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "rollup": { - "version": "2.67.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.67.2.tgz", - "integrity": "sha512-hoEiBWwZtf1QdK3jZIq59L0FJj4Fiv4RplCO4pvCRC86qsoFurWB4hKQIjoRf3WvJmk5UZ9b0y5ton+62fC7Tw==", - "dev": true, - "requires": { - "fsevents": "~2.3.2" - } - }, - "rollup-plugin-dts": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-dts/-/rollup-plugin-dts-4.1.0.tgz", - "integrity": "sha512-rriXIm3jdUiYeiAAd1Fv+x2AxK6Kq6IybB2Z/IdoAW95fb4uRUurYsEYKa8L1seedezDeJhy8cfo8FEL9aZzqg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.16.0", - "magic-string": "^0.25.7" - } - }, - "rollup-plugin-inject": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz", - "integrity": "sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==", - "dev": true, - "requires": { - "estree-walker": "^0.6.1", - "magic-string": "^0.25.3", - "rollup-pluginutils": "^2.8.1" - }, - "dependencies": { - "estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", - "dev": true - } - } - }, - "rollup-plugin-node-polyfills": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz", - "integrity": "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==", - "dev": true, - "requires": { - "rollup-plugin-inject": "^3.0.0" - } - }, - "rollup-plugin-terser": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", - "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "jest-worker": "^26.2.1", - "serialize-javascript": "^4.0.0", - "terser": "^5.0.0" - }, - "dependencies": { - "jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - } - } - } - }, - "rollup-pluginutils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", - "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", - "dev": true, - "requires": { - "estree-walker": "^0.6.1" - }, - "dependencies": { - "estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", - "dev": true - } - } - }, - "rpc-websockets": { - "version": "7.4.17", - "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-7.4.17.tgz", - "integrity": "sha512-eolVi/qlXS13viIUH9aqrde902wzSLAai0IjmOZSRefp5I3CSG/vCnD0c0fDSYCWuEyUoRL1BHQA8K1baEUyow==", - "requires": { - "@babel/runtime": "^7.11.2", - "bufferutil": "^4.0.1", - "circular-json": "^0.5.9", - "eventemitter3": "^4.0.7", - "utf-8-validate": "^5.0.2", - "uuid": "^8.3.0", - "ws": "^7.4.5" - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dev": true, - "requires": { - "xmlchars": "^2.2.0" - } - }, - "secp256k1": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", - "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", - "requires": { - "elliptic": "^6.5.4", - "node-addon-api": "^2.0.0", - "node-gyp-build": "^4.2.0" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - } - } - }, - "string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "requires": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "superstruct": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.14.2.tgz", - "integrity": "sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", - "dev": true, - "requires": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - } - }, - "terser": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", - "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", - "dev": true, - "requires": { - "commander": "^2.20.0", - "source-map": "~0.7.2", - "source-map-support": "~0.5.20" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - } - } - }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "text-encoding-utf-8": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", - "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==" - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "throat": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", - "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", - "dev": true, - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" - } - }, - "tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", - "dev": true, - "requires": { - "punycode": "^2.1.1" - } - }, - "ts-jest": { - "version": "27.1.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.3.tgz", - "integrity": "sha512-6Nlura7s6uM9BVUAoqLH7JHyMXjz8gluryjpPXxr3IxZdAXnU6FhjvVLHFtfd1vsE1p8zD1OJfskkc0jhTSnkA==", - "dev": true, - "requires": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^27.0.0", - "json5": "2.x", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "7.x", - "yargs-parser": "20.x" - } - }, - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true, - "peer": true - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, - "tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "typescript": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", - "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", - "dev": true - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "utf-8-validate": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.8.tgz", - "integrity": "sha512-k4dW/Qja1BYDl2qD4tOMB9PFVha/UJtxTc1cXYOe3WwA/2m0Yn4qB7wLMpJyLJ/7DR0XnTut3HsCSzDT4ZvKgA==", - "optional": true, - "requires": { - "node-gyp-build": "^4.3.0" - } - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "v8-to-istanbul": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", - "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - } - } - }, - "w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "requires": { - "browser-process-hrtime": "^1.0.0" - } - }, - "w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dev": true, - "requires": { - "xml-name-validator": "^3.0.0" - } - }, - "walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "requires": { - "makeerror": "1.0.12" - } - }, - "webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true - }, - "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "requires": { - "iconv-lite": "0.4.24" - } - }, - "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, - "whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", - "dev": true, - "requires": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", - "requires": {} - }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true - } - } -} diff --git a/stake-pool/js/package.json b/stake-pool/js/package.json deleted file mode 100644 index e2bc8021045..00000000000 --- a/stake-pool/js/package.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "name": "@solana/spl-stake-pool", - "version": "0.6.4", - "description": "SPL Stake Pool Program JS API", - "scripts": { - "build": "npm run clean && tsc && cross-env NODE_ENV=production rollup -c", - "lint": "eslint --max-warnings 0 .", - "lint:fix": "eslint . --fix", - "test": "jest", - "test:watch": "jest --watch", - "test:cov": "jest --coverage", - "clean": "rimraf ./dist" - }, - "keywords": [], - "contributors": [ - "Solana Maintainers ", - "Lieu Zheng Hong", - "mFactory Team (https://mfactory.ch/)", - "SolBlaze (https://solblaze.org/)" - ], - "homepage": "https://solana.com", - "repository": { - "type": "git", - "url": "https://github.com/solana-labs/solana-program-library" - }, - "publishConfig": { - "access": "public" - }, - "browser": { - "./dist/index.cjs.js": "./dist/index.browser.esm.js", - "./dist/index.esm.js": "./dist/index.browser.esm.js" - }, - "main": "dist/index.cjs.js", - "module": "dist/index.esm.js", - "types": "dist/index.d.ts", - "browserslist": [ - "defaults", - "not IE 11", - "maintained node versions" - ], - "files": [ - "/dist", - "/src" - ], - "license": "ISC", - "dependencies": { - "@project-serum/borsh": "^0.2.2", - "@solana/buffer-layout": "^4.0.0", - "@solana/spl-token": "^0.1.8", - "@solana/web3.js": "^1.30.2", - "bn.js": "^5.2.0", - "buffer": "^6.0.3" - }, - "devDependencies": { - "@rollup/plugin-alias": "^3.1.9", - "@rollup/plugin-commonjs": "^21.0.1", - "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-multi-entry": "^4.1.0", - "@rollup/plugin-node-resolve": "^13.1.3", - "@rollup/plugin-typescript": "^8.3.0", - "@types/bn.js": "^5.1.0", - "@types/jest": "^27.4.0", - "@typescript-eslint/eslint-plugin": "^5.11.0", - "@typescript-eslint/parser": "^5.11.0", - "cross-env": "^7.0.3", - "eslint": "^8.8.0", - "eslint-config-prettier": "^8.3.0", - "eslint-plugin-prettier": "^4.0.0", - "jest": "^27.5.1", - "prettier": "^2.5.1", - "rimraf": "^3.0.2", - "rollup": "^2.66.1", - "rollup-plugin-dts": "^4.1.0", - "rollup-plugin-node-polyfills": "^0.2.1", - "rollup-plugin-terser": "^7.0.2", - "ts-jest": "^27.1.3", - "typescript": "^4.5.4" - }, - "jest": { - "moduleFileExtensions": [ - "js", - "json", - "ts" - ], - "rootDir": ".", - "transform": { - "^.+\\.(t|j)s$": "ts-jest" - }, - "testRegex": ".*\\.test\\.ts$", - "testEnvironment": "node" - } -} - diff --git a/stake-pool/js/rollup.config.js b/stake-pool/js/rollup.config.js deleted file mode 100644 index 03c9c19842a..00000000000 --- a/stake-pool/js/rollup.config.js +++ /dev/null @@ -1,125 +0,0 @@ -import typescript from '@rollup/plugin-typescript'; -import commonjs from '@rollup/plugin-commonjs'; -import json from '@rollup/plugin-json'; -import nodeResolve from '@rollup/plugin-node-resolve'; -import { terser } from 'rollup-plugin-terser'; - -const extensions = ['.js', '.ts']; - -function generateConfig(configType, format) { - const browser = configType === 'browser'; - - const config = { - input: 'src/index.ts', - plugins: [ - commonjs(), - nodeResolve({ - browser, - dedupe: ['bn.js', 'buffer'], - extensions, - preferBuiltins: !browser, - }), - typescript(), - ], - onwarn: function (warning, rollupWarn) { - if (warning.code !== 'CIRCULAR_DEPENDENCY') { - rollupWarn(warning); - } - }, - treeshake: { - moduleSideEffects: false, - }, - }; - - if (configType !== 'browser') { - // Prevent dependencies from being bundled - config.external = [ - '@project-serum/borsh', - '@solana/buffer-layout', - '@solana/spl-token', - '@solana/web3.js', - 'bn.js', - 'buffer', - ]; - } - - switch (configType) { - case 'browser': - switch (format) { - case 'esm': { - config.output = [ - { - file: 'dist/index.browser.esm.js', - format: 'es', - sourcemap: true, - }, - ]; - - // Prevent dependencies from being bundled - config.external = [ - '@project-serum/borsh', - '@solana/buffer-layout', - '@solana/spl-token', - '@solana/web3.js', - 'bn.js', - 'buffer', - ]; - - break; - } - case 'iife': { - config.external = ['http', 'https']; - - config.output = [ - { - file: 'dist/index.iife.js', - format: 'iife', - name: 'solanaStakePool', - sourcemap: true, - }, - { - file: 'dist/index.iife.min.js', - format: 'iife', - name: 'solanaStakePool', - sourcemap: true, - plugins: [terser({ mangle: false, compress: false })], - }, - ]; - - break; - } - default: - throw new Error(`Unknown format: ${format}`); - } - - // TODO: Find a workaround to avoid resolving the following JSON file: - // `node_modules/secp256k1/node_modules/elliptic/package.json` - config.plugins.push(json()); - - break; - case 'node': - config.output = [ - { - file: 'dist/index.cjs.js', - format: 'cjs', - sourcemap: true, - }, - { - file: 'dist/index.esm.js', - format: 'es', - sourcemap: true, - }, - ]; - break; - default: - throw new Error(`Unknown configType: ${configType}`); - } - - return config; -} - -export default [ - generateConfig('node'), - generateConfig('browser', 'esm'), - generateConfig('browser', 'iife'), -]; diff --git a/stake-pool/js/src/constants.ts b/stake-pool/js/src/constants.ts deleted file mode 100644 index 447835fac85..00000000000 --- a/stake-pool/js/src/constants.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Buffer } from 'buffer'; -import { LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js'; - -// Public key that identifies the SPL Stake Pool program. -export const STAKE_POOL_PROGRAM_ID = new PublicKey('SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy'); - -// Maximum number of validators to update during UpdateValidatorListBalance. -export const MAX_VALIDATORS_TO_UPDATE = 5; - -// Seed used to derive transient stake accounts. -export const TRANSIENT_STAKE_SEED_PREFIX = Buffer.from('transient'); - -// Minimum amount of staked SOL required in a validator stake account to allow -// for merges without a mismatch on credits observed -export const MINIMUM_ACTIVE_STAKE = LAMPORTS_PER_SOL; diff --git a/stake-pool/js/src/index.ts b/stake-pool/js/src/index.ts deleted file mode 100644 index 7eac0b4d7c0..00000000000 --- a/stake-pool/js/src/index.ts +++ /dev/null @@ -1,909 +0,0 @@ -import { - AccountInfo, - Connection, - Keypair, - PublicKey, - Signer, - StakeAuthorizationLayout, - StakeProgram, - SystemProgram, - TransactionInstruction, -} from '@solana/web3.js'; -import { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID, Token } from '@solana/spl-token'; -import { - ValidatorAccount, - addAssociatedTokenAccount, - arrayChunk, - calcLamportsWithdrawAmount, - findStakeProgramAddress, - findTransientStakeProgramAddress, - findWithdrawAuthorityProgramAddress, - getTokenAccount, - getValidatorListAccount, - newStakeAccount, - prepareWithdrawAccounts, - lamportsToSol, - solToLamports, -} from './utils'; -import { StakePoolInstruction } from './instructions'; -import { - StakePool, - StakePoolLayout, - ValidatorList, - ValidatorListLayout, - ValidatorStakeInfo, -} from './layouts'; -import { MAX_VALIDATORS_TO_UPDATE, MINIMUM_ACTIVE_STAKE, STAKE_POOL_PROGRAM_ID } from './constants'; - -export type { StakePool, AccountType, ValidatorList, ValidatorStakeInfo } from './layouts'; -export { STAKE_POOL_PROGRAM_ID } from './constants'; -export * from './instructions'; - -export interface ValidatorListAccount { - pubkey: PublicKey; - account: AccountInfo; -} - -export interface StakePoolAccount { - pubkey: PublicKey; - account: AccountInfo; -} - -export interface WithdrawAccount { - stakeAddress: PublicKey; - voteAddress?: PublicKey; - poolAmount: number; -} - -/** - * Wrapper class for a stake pool. - * Each stake pool has a stake pool account and a validator list account. - */ -export interface StakePoolAccounts { - stakePool: StakePoolAccount | undefined; - validatorList: ValidatorListAccount | undefined; -} - -/** - * Retrieves and deserializes a StakePool account using a web3js connection and the stake pool address. - * @param connection: An active web3js connection. - * @param stakePoolAddress: The public key (address) of the stake pool account. - */ -export async function getStakePoolAccount( - connection: Connection, - stakePoolAddress: PublicKey, -): Promise { - const account = await connection.getAccountInfo(stakePoolAddress); - - if (!account) { - throw new Error('Invalid stake pool account'); - } - - return { - pubkey: stakePoolAddress, - account: { - data: StakePoolLayout.decode(account.data), - executable: account.executable, - lamports: account.lamports, - owner: account.owner, - }, - }; -} - -/** - * Retrieves all StakePool and ValidatorList accounts that are running a particular StakePool program. - * @param connection: An active web3js connection. - * @param stakePoolProgramAddress: The public key (address) of the StakePool program. - */ -export async function getStakePoolAccounts( - connection: Connection, - stakePoolProgramAddress: PublicKey, -): Promise<(StakePoolAccount | ValidatorListAccount)[] | undefined> { - const response = await connection.getProgramAccounts(stakePoolProgramAddress); - - return response.map((a) => { - let decodedData; - - if (a.account.data.readUInt8() === 1) { - try { - decodedData = StakePoolLayout.decode(a.account.data); - } catch (error) { - console.log('Could not decode StakeAccount. Error:', error); - decodedData = undefined; - } - } else if (a.account.data.readUInt8() === 2) { - try { - decodedData = ValidatorListLayout.decode(a.account.data); - } catch (error) { - console.log('Could not decode ValidatorList. Error:', error); - decodedData = undefined; - } - } else { - console.error( - `Could not decode. StakePoolAccount Enum is ${a.account.data.readUInt8()}, expected 1 or 2!`, - ); - decodedData = undefined; - } - - return { - pubkey: a.pubkey, - account: { - data: decodedData, - executable: a.account.executable, - lamports: a.account.lamports, - owner: a.account.owner, - }, - }; - }); -} - -/** - * Creates instructions required to deposit stake to stake pool. - */ -export async function depositStake( - connection: Connection, - stakePoolAddress: PublicKey, - authorizedPubkey: PublicKey, - validatorVote: PublicKey, - depositStake: PublicKey, - poolTokenReceiverAccount?: PublicKey, -) { - const stakePool = await getStakePoolAccount(connection, stakePoolAddress); - - const withdrawAuthority = await findWithdrawAuthorityProgramAddress( - STAKE_POOL_PROGRAM_ID, - stakePoolAddress, - ); - - const validatorStake = await findStakeProgramAddress( - STAKE_POOL_PROGRAM_ID, - validatorVote, - stakePoolAddress, - ); - - const instructions: TransactionInstruction[] = []; - const signers: Signer[] = []; - - const poolMint = stakePool.account.data.poolMint; - - let rentFee = 0; - - // Create token account if not specified - if (!poolTokenReceiverAccount) { - const { associatedAddress, rentFee: fee } = await addAssociatedTokenAccount( - connection, - authorizedPubkey, - poolMint, - instructions, - ); - poolTokenReceiverAccount = associatedAddress; - rentFee += fee; - } - - instructions.push( - ...StakeProgram.authorize({ - stakePubkey: depositStake, - authorizedPubkey, - newAuthorizedPubkey: stakePool.account.data.stakeDepositAuthority, - stakeAuthorizationType: StakeAuthorizationLayout.Staker, - }).instructions, - ); - - instructions.push( - ...StakeProgram.authorize({ - stakePubkey: depositStake, - authorizedPubkey, - newAuthorizedPubkey: stakePool.account.data.stakeDepositAuthority, - stakeAuthorizationType: StakeAuthorizationLayout.Withdrawer, - }).instructions, - ); - - instructions.push( - StakePoolInstruction.depositStake({ - stakePool: stakePoolAddress, - validatorList: stakePool.account.data.validatorList, - depositAuthority: stakePool.account.data.stakeDepositAuthority, - reserveStake: stakePool.account.data.reserveStake, - managerFeeAccount: stakePool.account.data.managerFeeAccount, - referralPoolAccount: poolTokenReceiverAccount, - destinationPoolAccount: poolTokenReceiverAccount, - withdrawAuthority, - depositStake, - validatorStake, - poolMint, - }), - ); - - return { - instructions, - signers, - rentFee, - }; -} - -/** - * Creates instructions required to deposit sol to stake pool. - */ -export async function depositSol( - connection: Connection, - stakePoolAddress: PublicKey, - from: PublicKey, - lamports: number, - destinationTokenAccount?: PublicKey, - referrerTokenAccount?: PublicKey, - depositAuthority?: PublicKey, -) { - const fromBalance = await connection.getBalance(from, 'confirmed'); - if (fromBalance < lamports) { - throw new Error( - `Not enough SOL to deposit into pool. Maximum deposit amount is ${lamportsToSol( - fromBalance, - )} SOL.`, - ); - } - - const stakePoolAccount = await getStakePoolAccount(connection, stakePoolAddress); - const stakePool = stakePoolAccount.account.data; - - // Ephemeral SOL account just to do the transfer - const userSolTransfer = new Keypair(); - const signers: Signer[] = [userSolTransfer]; - const instructions: TransactionInstruction[] = []; - - let rentFee = 0; - - // Create the ephemeral SOL account - instructions.push( - SystemProgram.transfer({ - fromPubkey: from, - toPubkey: userSolTransfer.publicKey, - lamports, - }), - ); - - // Create token account if not specified - if (!destinationTokenAccount) { - const { associatedAddress, rentFee: fee } = await addAssociatedTokenAccount( - connection, - from, - stakePool.poolMint, - instructions, - ); - destinationTokenAccount = associatedAddress; - rentFee += fee; - } - - const withdrawAuthority = await findWithdrawAuthorityProgramAddress( - STAKE_POOL_PROGRAM_ID, - stakePoolAddress, - ); - - instructions.push( - StakePoolInstruction.depositSol({ - stakePool: stakePoolAddress, - reserveStake: stakePool.reserveStake, - fundingAccount: userSolTransfer.publicKey, - destinationPoolAccount: destinationTokenAccount, - managerFeeAccount: stakePool.managerFeeAccount, - referralPoolAccount: referrerTokenAccount ?? destinationTokenAccount, - poolMint: stakePool.poolMint, - lamports, - withdrawAuthority, - depositAuthority, - }), - ); - - return { - instructions, - signers, - rentFee, - }; -} - -/** - * Creates instructions required to withdraw stake from a stake pool. - */ -export async function withdrawStake( - connection: Connection, - stakePoolAddress: PublicKey, - tokenOwner: PublicKey, - amount: number, - useReserve = false, - voteAccountAddress?: PublicKey, - stakeReceiver?: PublicKey, - poolTokenAccount?: PublicKey, - validatorComparator?: (_a: ValidatorAccount, _b: ValidatorAccount) => number, -) { - const stakePool = await getStakePoolAccount(connection, stakePoolAddress); - const poolAmount = solToLamports(amount); - - if (!poolTokenAccount) { - poolTokenAccount = await Token.getAssociatedTokenAddress( - ASSOCIATED_TOKEN_PROGRAM_ID, - TOKEN_PROGRAM_ID, - stakePool.account.data.poolMint, - tokenOwner, - ); - } - - const tokenAccount = await getTokenAccount( - connection, - poolTokenAccount, - stakePool.account.data.poolMint, - ); - if (!tokenAccount) { - throw new Error('Invalid token account'); - } - - // Check withdrawFrom balance - if (tokenAccount.amount.toNumber() < poolAmount) { - throw new Error( - `Not enough token balance to withdraw ${lamportsToSol(poolAmount)} pool tokens. - Maximum withdraw amount is ${lamportsToSol(tokenAccount.amount.toNumber())} pool tokens.`, - ); - } - - const stakeAccountRentExemption = await connection.getMinimumBalanceForRentExemption( - StakeProgram.space, - ); - - const withdrawAuthority = await findWithdrawAuthorityProgramAddress( - STAKE_POOL_PROGRAM_ID, - stakePoolAddress, - ); - - const withdrawAccounts: WithdrawAccount[] = []; - - if (useReserve) { - withdrawAccounts.push({ - stakeAddress: stakePool.account.data.reserveStake, - voteAddress: undefined, - poolAmount, - }); - } else if (voteAccountAddress) { - const stakeAccountAddress = await findStakeProgramAddress( - STAKE_POOL_PROGRAM_ID, - voteAccountAddress, - stakePoolAddress, - ); - const stakeAccount = await connection.getAccountInfo(stakeAccountAddress); - if (!stakeAccount) { - throw new Error('Invalid Stake Account'); - } - - const availableForWithdrawal = calcLamportsWithdrawAmount( - stakePool.account.data, - stakeAccount.lamports - MINIMUM_ACTIVE_STAKE - stakeAccountRentExemption, - ); - - if (availableForWithdrawal < poolAmount) { - // noinspection ExceptionCaughtLocallyJS - throw new Error( - `Not enough lamports available for withdrawal from ${stakeAccountAddress}, - ${poolAmount} asked, ${availableForWithdrawal} available.`, - ); - } - withdrawAccounts.push({ - stakeAddress: stakeAccountAddress, - voteAddress: voteAccountAddress, - poolAmount, - }); - } else { - // Get the list of accounts to withdraw from - withdrawAccounts.push( - ...(await prepareWithdrawAccounts( - connection, - stakePool.account.data, - stakePoolAddress, - poolAmount, - validatorComparator, - poolTokenAccount.equals(stakePool.account.data.managerFeeAccount), - )), - ); - } - - // Construct transaction to withdraw from withdrawAccounts account list - const instructions: TransactionInstruction[] = []; - const userTransferAuthority = Keypair.generate(); - - const signers: Signer[] = [userTransferAuthority]; - - instructions.push( - Token.createApproveInstruction( - TOKEN_PROGRAM_ID, - poolTokenAccount, - userTransferAuthority.publicKey, - tokenOwner, - [], - poolAmount, - ), - ); - - let totalRentFreeBalances = 0; - - // Max 5 accounts to prevent an error: "Transaction too large" - const maxWithdrawAccounts = 5; - let i = 0; - - // Go through prepared accounts and withdraw/claim them - for (const withdrawAccount of withdrawAccounts) { - if (i > maxWithdrawAccounts) { - break; - } - // Convert pool tokens amount to lamports - const solWithdrawAmount = Math.ceil( - calcLamportsWithdrawAmount(stakePool.account.data, withdrawAccount.poolAmount), - ); - - let infoMsg = `Withdrawing ◎${solWithdrawAmount}, - from stake account ${withdrawAccount.stakeAddress?.toBase58()}`; - - if (withdrawAccount.voteAddress) { - infoMsg = `${infoMsg}, delegated to ${withdrawAccount.voteAddress?.toBase58()}`; - } - - console.info(infoMsg); - - let stakeToReceive; - - // Use separate mutable variable because withdraw might create a new account - if (!stakeReceiver) { - const stakeKeypair = newStakeAccount(tokenOwner, instructions, stakeAccountRentExemption); - signers.push(stakeKeypair); - totalRentFreeBalances += stakeAccountRentExemption; - stakeToReceive = stakeKeypair.publicKey; - } else { - stakeToReceive = stakeReceiver; - } - - instructions.push( - StakePoolInstruction.withdrawStake({ - stakePool: stakePoolAddress, - validatorList: stakePool.account.data.validatorList, - validatorStake: withdrawAccount.stakeAddress, - destinationStake: stakeToReceive, - destinationStakeAuthority: tokenOwner, - sourceTransferAuthority: userTransferAuthority.publicKey, - sourcePoolAccount: poolTokenAccount, - managerFeeAccount: stakePool.account.data.managerFeeAccount, - poolMint: stakePool.account.data.poolMint, - poolTokens: withdrawAccount.poolAmount, - withdrawAuthority, - }), - ); - i++; - } - - return { - instructions, - signers, - stakeReceiver, - totalRentFreeBalances, - }; -} - -/** - * Creates instructions required to withdraw SOL directly from a stake pool. - */ -export async function withdrawSol( - connection: Connection, - stakePoolAddress: PublicKey, - tokenOwner: PublicKey, - solReceiver: PublicKey, - amount: number, - solWithdrawAuthority?: PublicKey, -) { - const stakePool = await getStakePoolAccount(connection, stakePoolAddress); - const poolAmount = solToLamports(amount); - - const poolTokenAccount = await Token.getAssociatedTokenAddress( - ASSOCIATED_TOKEN_PROGRAM_ID, - TOKEN_PROGRAM_ID, - stakePool.account.data.poolMint, - tokenOwner, - ); - - const tokenAccount = await getTokenAccount( - connection, - poolTokenAccount, - stakePool.account.data.poolMint, - ); - if (!tokenAccount) { - throw new Error('Invalid token account'); - } - - // Check withdrawFrom balance - if (tokenAccount.amount.toNumber() < poolAmount) { - throw new Error( - `Not enough token balance to withdraw ${lamportsToSol(poolAmount)} pool tokens. - Maximum withdraw amount is ${lamportsToSol(tokenAccount.amount.toNumber())} pool tokens.`, - ); - } - - // Construct transaction to withdraw from withdrawAccounts account list - const instructions: TransactionInstruction[] = []; - const userTransferAuthority = Keypair.generate(); - const signers: Signer[] = [userTransferAuthority]; - - instructions.push( - Token.createApproveInstruction( - TOKEN_PROGRAM_ID, - poolTokenAccount, - userTransferAuthority.publicKey, - tokenOwner, - [], - poolAmount, - ), - ); - - const poolWithdrawAuthority = await findWithdrawAuthorityProgramAddress( - STAKE_POOL_PROGRAM_ID, - stakePoolAddress, - ); - - if (solWithdrawAuthority) { - const expectedSolWithdrawAuthority = stakePool.account.data.solWithdrawAuthority; - if (!expectedSolWithdrawAuthority) { - throw new Error('SOL withdraw authority specified in arguments but stake pool has none'); - } - if (solWithdrawAuthority.toBase58() != expectedSolWithdrawAuthority.toBase58()) { - throw new Error( - `Invalid deposit withdraw specified, expected ${expectedSolWithdrawAuthority.toBase58()}, received ${solWithdrawAuthority.toBase58()}`, - ); - } - } - - const withdrawTransaction = StakePoolInstruction.withdrawSol({ - stakePool: stakePoolAddress, - withdrawAuthority: poolWithdrawAuthority, - reserveStake: stakePool.account.data.reserveStake, - sourcePoolAccount: poolTokenAccount, - sourceTransferAuthority: userTransferAuthority.publicKey, - destinationSystemAccount: solReceiver, - managerFeeAccount: stakePool.account.data.managerFeeAccount, - poolMint: stakePool.account.data.poolMint, - poolTokens: poolAmount, - solWithdrawAuthority, - }); - - instructions.push(withdrawTransaction); - - return { - instructions, - signers, - }; -} - -/** - * Creates instructions required to increase validator stake. - */ -export async function increaseValidatorStake( - connection: Connection, - stakePoolAddress: PublicKey, - validatorVote: PublicKey, - lamports: number, -) { - const stakePool = await getStakePoolAccount(connection, stakePoolAddress); - - const validatorList = await getValidatorListAccount( - connection, - stakePool.account.data.validatorList, - ); - - const validatorInfo = validatorList.account.data.validators.find( - (v) => v.voteAccountAddress.toBase58() == validatorVote.toBase58(), - ); - - if (!validatorInfo) { - throw new Error('Vote account not found in validator list'); - } - - const withdrawAuthority = await findWithdrawAuthorityProgramAddress( - STAKE_POOL_PROGRAM_ID, - stakePoolAddress, - ); - - const transientStakeSeed = validatorInfo.transientSeedSuffixStart.addn(1); // bump up by one to avoid reuse - - const transientStake = await findTransientStakeProgramAddress( - STAKE_POOL_PROGRAM_ID, - validatorInfo.voteAccountAddress, - stakePoolAddress, - transientStakeSeed, - ); - - const validatorStake = await findStakeProgramAddress( - STAKE_POOL_PROGRAM_ID, - validatorInfo.voteAccountAddress, - stakePoolAddress, - ); - - const instructions: TransactionInstruction[] = []; - instructions.push( - StakePoolInstruction.increaseValidatorStake({ - stakePool: stakePoolAddress, - staker: stakePool.account.data.staker, - validatorList: stakePool.account.data.validatorList, - reserveStake: stakePool.account.data.reserveStake, - transientStakeSeed: transientStakeSeed.toNumber(), - withdrawAuthority, - transientStake, - validatorStake, - validatorVote, - lamports, - }), - ); - - return { - instructions, - }; -} - -/** - * Creates instructions required to decrease validator stake. - */ -export async function decreaseValidatorStake( - connection: Connection, - stakePoolAddress: PublicKey, - validatorVote: PublicKey, - lamports: number, -) { - const stakePool = await getStakePoolAccount(connection, stakePoolAddress); - const validatorList = await getValidatorListAccount( - connection, - stakePool.account.data.validatorList, - ); - - const validatorInfo = validatorList.account.data.validators.find( - (v) => v.voteAccountAddress.toBase58() == validatorVote.toBase58(), - ); - - if (!validatorInfo) { - throw new Error('Vote account not found in validator list'); - } - - const withdrawAuthority = await findWithdrawAuthorityProgramAddress( - STAKE_POOL_PROGRAM_ID, - stakePoolAddress, - ); - - const validatorStake = await findStakeProgramAddress( - STAKE_POOL_PROGRAM_ID, - validatorInfo.voteAccountAddress, - stakePoolAddress, - ); - - const transientStakeSeed = validatorInfo.transientSeedSuffixStart.addn(1); // bump up by one to avoid reuse - - const transientStake = await findTransientStakeProgramAddress( - STAKE_POOL_PROGRAM_ID, - validatorInfo.voteAccountAddress, - stakePoolAddress, - transientStakeSeed, - ); - - const instructions: TransactionInstruction[] = []; - instructions.push( - StakePoolInstruction.decreaseValidatorStake({ - stakePool: stakePoolAddress, - staker: stakePool.account.data.staker, - validatorList: stakePool.account.data.validatorList, - transientStakeSeed: transientStakeSeed.toNumber(), - withdrawAuthority, - validatorStake, - transientStake, - lamports, - }), - ); - - return { - instructions, - }; -} - -/** - * Creates instructions required to completely update a stake pool after epoch change. - */ -export async function updateStakePool( - connection: Connection, - stakePool: StakePoolAccount, - noMerge = false, -) { - const stakePoolAddress = stakePool.pubkey; - - const validatorList = await getValidatorListAccount( - connection, - stakePool.account.data.validatorList, - ); - - const withdrawAuthority = await findWithdrawAuthorityProgramAddress( - STAKE_POOL_PROGRAM_ID, - stakePoolAddress, - ); - - const updateListInstructions: TransactionInstruction[] = []; - const instructions: TransactionInstruction[] = []; - - let startIndex = 0; - const validatorChunks: Array = arrayChunk( - validatorList.account.data.validators, - MAX_VALIDATORS_TO_UPDATE, - ); - - for (const validatorChunk of validatorChunks) { - const validatorAndTransientStakePairs: PublicKey[] = []; - - for (const validator of validatorChunk) { - const validatorStake = await findStakeProgramAddress( - STAKE_POOL_PROGRAM_ID, - validator.voteAccountAddress, - stakePoolAddress, - ); - validatorAndTransientStakePairs.push(validatorStake); - - const transientStake = await findTransientStakeProgramAddress( - STAKE_POOL_PROGRAM_ID, - validator.voteAccountAddress, - stakePoolAddress, - validator.transientSeedSuffixStart, - ); - validatorAndTransientStakePairs.push(transientStake); - } - - updateListInstructions.push( - StakePoolInstruction.updateValidatorListBalance({ - stakePool: stakePoolAddress, - validatorList: stakePool.account.data.validatorList, - reserveStake: stakePool.account.data.reserveStake, - validatorAndTransientStakePairs, - withdrawAuthority, - startIndex, - noMerge, - }), - ); - startIndex += MAX_VALIDATORS_TO_UPDATE; - } - - instructions.push( - StakePoolInstruction.updateStakePoolBalance({ - stakePool: stakePoolAddress, - validatorList: stakePool.account.data.validatorList, - reserveStake: stakePool.account.data.reserveStake, - managerFeeAccount: stakePool.account.data.managerFeeAccount, - poolMint: stakePool.account.data.poolMint, - withdrawAuthority, - }), - ); - - instructions.push( - StakePoolInstruction.cleanupRemovedValidatorEntries({ - stakePool: stakePoolAddress, - validatorList: stakePool.account.data.validatorList, - }), - ); - - return { - updateListInstructions, - finalInstructions: instructions, - }; -} - -/** - * Retrieves detailed information about the StakePool. - */ -export async function stakePoolInfo(connection: Connection, stakePoolAddress: PublicKey) { - const stakePool = await getStakePoolAccount(connection, stakePoolAddress); - const reserveAccountStakeAddress = stakePool.account.data.reserveStake; - const totalLamports = stakePool.account.data.totalLamports; - const lastUpdateEpoch = stakePool.account.data.lastUpdateEpoch; - - const validatorList = await getValidatorListAccount( - connection, - stakePool.account.data.validatorList, - ); - - const maxNumberOfValidators = validatorList.account.data.maxValidators; - const currentNumberOfValidators = validatorList.account.data.validators.length; - - const epochInfo = await connection.getEpochInfo(); - const reserveStake = await connection.getAccountInfo(reserveAccountStakeAddress); - const withdrawAuthority = await findWithdrawAuthorityProgramAddress( - STAKE_POOL_PROGRAM_ID, - stakePoolAddress, - ); - - const minimumReserveStakeBalance = - (await connection.getMinimumBalanceForRentExemption(StakeProgram.space)) + 1; - - const stakeAccounts = await Promise.all( - validatorList.account.data.validators.map(async (validator) => { - const stakeAccountAddress = await findStakeProgramAddress( - STAKE_POOL_PROGRAM_ID, - validator.voteAccountAddress, - stakePoolAddress, - ); - const transientStakeAccountAddress = await findTransientStakeProgramAddress( - STAKE_POOL_PROGRAM_ID, - validator.voteAccountAddress, - stakePoolAddress, - validator.transientSeedSuffixStart, - ); - const updateRequired = !validator.lastUpdateEpoch.eqn(epochInfo.epoch); - return { - voteAccountAddress: validator.voteAccountAddress.toBase58(), - stakeAccountAddress: stakeAccountAddress.toBase58(), - validatorActiveStakeLamports: validator.activeStakeLamports.toString(), - validatorLastUpdateEpoch: validator.lastUpdateEpoch.toString(), - validatorLamports: validator.activeStakeLamports - .add(validator.transientStakeLamports) - .toString(), - validatorTransientStakeAccountAddress: transientStakeAccountAddress.toBase58(), - validatorTransientStakeLamports: validator.transientStakeLamports.toString(), - updateRequired, - }; - }), - ); - - const totalPoolTokens = lamportsToSol(stakePool.account.data.poolTokenSupply); - const updateRequired = !lastUpdateEpoch.eqn(epochInfo.epoch); - - return { - address: stakePoolAddress.toBase58(), - poolWithdrawAuthority: withdrawAuthority.toBase58(), - manager: stakePool.account.data.manager.toBase58(), - staker: stakePool.account.data.staker.toBase58(), - stakeDepositAuthority: stakePool.account.data.stakeDepositAuthority.toBase58(), - stakeWithdrawBumpSeed: stakePool.account.data.stakeWithdrawBumpSeed, - maxValidators: maxNumberOfValidators, - validatorList: validatorList.account.data.validators.map((validator) => { - return { - activeStakeLamports: validator.activeStakeLamports.toString(), - transientStakeLamports: validator.transientStakeLamports.toString(), - lastUpdateEpoch: validator.lastUpdateEpoch.toString(), - transientSeedSuffixStart: validator.transientSeedSuffixStart.toString(), - transientSeedSuffixEnd: validator.transientSeedSuffixEnd.toString(), - status: validator.status.toString(), - voteAccountAddress: validator.voteAccountAddress.toString(), - }; - }), // CliStakePoolValidator - validatorListStorageAccount: stakePool.account.data.validatorList.toBase58(), - reserveStake: stakePool.account.data.reserveStake.toBase58(), - poolMint: stakePool.account.data.poolMint.toBase58(), - managerFeeAccount: stakePool.account.data.managerFeeAccount.toBase58(), - tokenProgramId: stakePool.account.data.tokenProgramId.toBase58(), - totalLamports: stakePool.account.data.totalLamports.toString(), - poolTokenSupply: stakePool.account.data.poolTokenSupply.toString(), - lastUpdateEpoch: stakePool.account.data.lastUpdateEpoch.toString(), - lockup: stakePool.account.data.lockup, // pub lockup: CliStakePoolLockup - epochFee: stakePool.account.data.epochFee, - nextEpochFee: stakePool.account.data.nextEpochFee, - preferredDepositValidatorVoteAddress: - stakePool.account.data.preferredDepositValidatorVoteAddress, - preferredWithdrawValidatorVoteAddress: - stakePool.account.data.preferredWithdrawValidatorVoteAddress, - stakeDepositFee: stakePool.account.data.stakeDepositFee, - stakeWithdrawalFee: stakePool.account.data.stakeWithdrawalFee, - // CliStakePool the same - nextStakeWithdrawalFee: stakePool.account.data.nextStakeWithdrawalFee, - stakeReferralFee: stakePool.account.data.stakeReferralFee, - solDepositAuthority: stakePool.account.data.solDepositAuthority?.toBase58(), - solDepositFee: stakePool.account.data.solDepositFee, - solReferralFee: stakePool.account.data.solReferralFee, - solWithdrawAuthority: stakePool.account.data.solWithdrawAuthority?.toBase58(), - solWithdrawalFee: stakePool.account.data.solWithdrawalFee, - nextSolWithdrawalFee: stakePool.account.data.nextSolWithdrawalFee, - lastEpochPoolTokenSupply: stakePool.account.data.lastEpochPoolTokenSupply.toString(), - lastEpochTotalLamports: stakePool.account.data.lastEpochTotalLamports.toString(), - details: { - reserveStakeLamports: reserveStake?.lamports, - reserveAccountStakeAddress: reserveAccountStakeAddress.toBase58(), - minimumReserveStakeBalance, - stakeAccounts, - totalLamports, - totalPoolTokens, - currentNumberOfValidators, - maxNumberOfValidators, - updateRequired, - }, // CliStakePoolDetails - }; -} diff --git a/stake-pool/js/src/instructions.ts b/stake-pool/js/src/instructions.ts deleted file mode 100644 index 422bdc67d75..00000000000 --- a/stake-pool/js/src/instructions.ts +++ /dev/null @@ -1,672 +0,0 @@ -import { - PublicKey, - STAKE_CONFIG_ID, - SYSVAR_CLOCK_PUBKEY, - SYSVAR_RENT_PUBKEY, - SYSVAR_STAKE_HISTORY_PUBKEY, - StakeProgram, - SystemProgram, - TransactionInstruction, -} from '@solana/web3.js'; -import * as BufferLayout from '@solana/buffer-layout'; -import { TOKEN_PROGRAM_ID } from '@solana/spl-token'; -import { STAKE_POOL_PROGRAM_ID } from './constants'; -import { InstructionType, encodeData, decodeData } from './utils'; - -/** - * An enumeration of valid StakePoolInstructionType's - */ -export type StakePoolInstructionType = - | 'IncreaseValidatorStake' - | 'DecreaseValidatorStake' - | 'UpdateValidatorListBalance' - | 'UpdateStakePoolBalance' - | 'CleanupRemovedValidatorEntries' - | 'DepositStake' - | 'DepositSol' - | 'WithdrawStake' - | 'WithdrawSol'; - -const MOVE_STAKE_LAYOUT = BufferLayout.struct([ - BufferLayout.u8('instruction'), - BufferLayout.ns64('lamports'), - BufferLayout.ns64('transientStakeSeed'), -]); - -const UPDATE_VALIDATOR_LIST_BALANCE_LAYOUT = BufferLayout.struct([ - BufferLayout.u8('instruction'), - BufferLayout.u32('startIndex'), - BufferLayout.u8('noMerge'), -]); - -/** - * An enumeration of valid stake InstructionType's - * @internal - */ -export const STAKE_POOL_INSTRUCTION_LAYOUTS: { - [type in StakePoolInstructionType]: InstructionType; -} = Object.freeze({ - DecreaseValidatorStake: { - index: 3, - layout: MOVE_STAKE_LAYOUT, - }, - IncreaseValidatorStake: { - index: 4, - layout: MOVE_STAKE_LAYOUT, - }, - UpdateValidatorListBalance: { - index: 6, - layout: UPDATE_VALIDATOR_LIST_BALANCE_LAYOUT, - }, - UpdateStakePoolBalance: { - index: 7, - layout: BufferLayout.struct([BufferLayout.u8('instruction')]), - }, - CleanupRemovedValidatorEntries: { - index: 8, - layout: BufferLayout.struct([BufferLayout.u8('instruction')]), - }, - DepositStake: { - index: 9, - layout: BufferLayout.struct([BufferLayout.u8('instruction')]), - }, - /// Withdraw the token from the pool at the current ratio. - WithdrawStake: { - index: 10, - layout: BufferLayout.struct([ - BufferLayout.u8('instruction'), - BufferLayout.ns64('poolTokens'), - ]), - }, - /// Deposit SOL directly into the pool's reserve account. The output is a "pool" token - /// representing ownership into the pool. Inputs are converted to the current ratio. - DepositSol: { - index: 14, - layout: BufferLayout.struct([ - BufferLayout.u8('instruction'), - BufferLayout.ns64('lamports'), - ]), - }, - /// Withdraw SOL directly from the pool's reserve account. Fails if the - /// reserve does not have enough SOL. - WithdrawSol: { - index: 16, - layout: BufferLayout.struct([ - BufferLayout.u8('instruction'), - BufferLayout.ns64('poolTokens'), - ]), - }, -}); - -/** - * Cleans up validator stake account entries marked as `ReadyForRemoval` - */ -export type CleanupRemovedValidatorEntriesParams = { - stakePool: PublicKey; - validatorList: PublicKey; -}; - -/** - * Updates balances of validator and transient stake accounts in the pool. - */ -export type UpdateValidatorListBalanceParams = { - stakePool: PublicKey; - withdrawAuthority: PublicKey; - validatorList: PublicKey; - reserveStake: PublicKey; - validatorAndTransientStakePairs: PublicKey[]; - startIndex: number; - noMerge: boolean; -}; - -/** - * Updates total pool balance based on balances in the reserve and validator list. - */ -export type UpdateStakePoolBalanceParams = { - stakePool: PublicKey; - withdrawAuthority: PublicKey; - validatorList: PublicKey; - reserveStake: PublicKey; - managerFeeAccount: PublicKey; - poolMint: PublicKey; -}; - -/** - * (Staker only) Decrease active stake on a validator, eventually moving it to the reserve - */ -export type DecreaseValidatorStakeParams = { - stakePool: PublicKey; - staker: PublicKey; - withdrawAuthority: PublicKey; - validatorList: PublicKey; - validatorStake: PublicKey; - transientStake: PublicKey; - // Amount of lamports to split into the transient stake account. - lamports: number; - // Seed to used to create the transient stake account. - transientStakeSeed: number; -}; - -/** - * (Staker only) Increase stake on a validator from the reserve account. - */ -export type IncreaseValidatorStakeParams = { - stakePool: PublicKey; - staker: PublicKey; - withdrawAuthority: PublicKey; - validatorList: PublicKey; - reserveStake: PublicKey; - transientStake: PublicKey; - validatorStake: PublicKey; - validatorVote: PublicKey; - // Amount of lamports to split into the transient stake account. - lamports: number; - // Seed to used to create the transient stake account. - transientStakeSeed: number; -}; - -/** - * Deposits a stake account into the pool in exchange for pool tokens - */ -export type DepositStakeParams = { - stakePool: PublicKey; - validatorList: PublicKey; - depositAuthority: PublicKey; - withdrawAuthority: PublicKey; - depositStake: PublicKey; - validatorStake: PublicKey; - reserveStake: PublicKey; - destinationPoolAccount: PublicKey; - managerFeeAccount: PublicKey; - referralPoolAccount: PublicKey; - poolMint: PublicKey; -}; - -/** - * Withdraws a stake account from the pool in exchange for pool tokens - */ -export type WithdrawStakeParams = { - stakePool: PublicKey; - validatorList: PublicKey; - withdrawAuthority: PublicKey; - validatorStake: PublicKey; - destinationStake: PublicKey; - destinationStakeAuthority: PublicKey; - sourceTransferAuthority: PublicKey; - sourcePoolAccount: PublicKey; - managerFeeAccount: PublicKey; - poolMint: PublicKey; - poolTokens: number; -}; - -/** - * Withdraw sol instruction params - */ -export type WithdrawSolParams = { - stakePool: PublicKey; - sourcePoolAccount: PublicKey; - withdrawAuthority: PublicKey; - reserveStake: PublicKey; - destinationSystemAccount: PublicKey; - sourceTransferAuthority: PublicKey; - solWithdrawAuthority?: PublicKey | undefined; - managerFeeAccount: PublicKey; - poolMint: PublicKey; - poolTokens: number; -}; - -/** - * Deposit SOL directly into the pool's reserve account. The output is a "pool" token - * representing ownership into the pool. Inputs are converted to the current ratio. - */ -export type DepositSolParams = { - stakePool: PublicKey; - depositAuthority?: PublicKey | undefined; - withdrawAuthority: PublicKey; - reserveStake: PublicKey; - fundingAccount: PublicKey; - destinationPoolAccount: PublicKey; - managerFeeAccount: PublicKey; - referralPoolAccount: PublicKey; - poolMint: PublicKey; - lamports: number; -}; - -/** - * Stake Pool Instruction class - */ -export class StakePoolInstruction { - /** - * Creates instruction to update a set of validators in the stake pool. - */ - static updateValidatorListBalance( - params: UpdateValidatorListBalanceParams, - ): TransactionInstruction { - const { - stakePool, - withdrawAuthority, - validatorList, - reserveStake, - startIndex, - noMerge, - validatorAndTransientStakePairs, - } = params; - - const type = STAKE_POOL_INSTRUCTION_LAYOUTS.UpdateValidatorListBalance; - const data = encodeData(type, { startIndex, noMerge: noMerge ? 1 : 0 }); - - const keys = [ - { pubkey: stakePool, isSigner: false, isWritable: false }, - { pubkey: withdrawAuthority, isSigner: false, isWritable: false }, - { pubkey: validatorList, isSigner: false, isWritable: true }, - { pubkey: reserveStake, isSigner: false, isWritable: true }, - { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false }, - { pubkey: SYSVAR_STAKE_HISTORY_PUBKEY, isSigner: false, isWritable: false }, - { pubkey: StakeProgram.programId, isSigner: false, isWritable: false }, - ...validatorAndTransientStakePairs.map((pubkey) => ({ - pubkey, - isSigner: false, - isWritable: true, - })), - ]; - - return new TransactionInstruction({ - programId: STAKE_POOL_PROGRAM_ID, - keys, - data, - }); - } - - /** - * Creates instruction to update the overall stake pool balance. - */ - static updateStakePoolBalance(params: UpdateStakePoolBalanceParams): TransactionInstruction { - const { - stakePool, - withdrawAuthority, - validatorList, - reserveStake, - managerFeeAccount, - poolMint, - } = params; - - const type = STAKE_POOL_INSTRUCTION_LAYOUTS.UpdateStakePoolBalance; - const data = encodeData(type); - - const keys = [ - { pubkey: stakePool, isSigner: false, isWritable: true }, - { pubkey: withdrawAuthority, isSigner: false, isWritable: false }, - { pubkey: validatorList, isSigner: false, isWritable: true }, - { pubkey: reserveStake, isSigner: false, isWritable: false }, - { pubkey: managerFeeAccount, isSigner: false, isWritable: true }, - { pubkey: poolMint, isSigner: false, isWritable: true }, - { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, - ]; - - return new TransactionInstruction({ - programId: STAKE_POOL_PROGRAM_ID, - keys, - data, - }); - } - - /** - * Creates instruction to cleanup removed validator entries. - */ - static cleanupRemovedValidatorEntries( - params: CleanupRemovedValidatorEntriesParams, - ): TransactionInstruction { - const { stakePool, validatorList } = params; - - const type = STAKE_POOL_INSTRUCTION_LAYOUTS.CleanupRemovedValidatorEntries; - const data = encodeData(type); - - const keys = [ - { pubkey: stakePool, isSigner: false, isWritable: false }, - { pubkey: validatorList, isSigner: false, isWritable: true }, - ]; - - return new TransactionInstruction({ - programId: STAKE_POOL_PROGRAM_ID, - keys, - data, - }); - } - - /** - * Creates instruction to increase the stake on a validator. - */ - static increaseValidatorStake(params: IncreaseValidatorStakeParams): TransactionInstruction { - const { - stakePool, - staker, - withdrawAuthority, - validatorList, - reserveStake, - transientStake, - validatorStake, - validatorVote, - lamports, - transientStakeSeed, - } = params; - - const type = STAKE_POOL_INSTRUCTION_LAYOUTS.IncreaseValidatorStake; - const data = encodeData(type, { lamports, transientStakeSeed }); - - const keys = [ - { pubkey: stakePool, isSigner: false, isWritable: false }, - { pubkey: staker, isSigner: true, isWritable: false }, - { pubkey: withdrawAuthority, isSigner: false, isWritable: false }, - { pubkey: validatorList, isSigner: false, isWritable: true }, - { pubkey: reserveStake, isSigner: false, isWritable: true }, - { pubkey: transientStake, isSigner: false, isWritable: true }, - { pubkey: validatorStake, isSigner: false, isWritable: false }, - { pubkey: validatorVote, isSigner: false, isWritable: false }, - { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false }, - { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false }, - { pubkey: SYSVAR_STAKE_HISTORY_PUBKEY, isSigner: false, isWritable: false }, - { pubkey: STAKE_CONFIG_ID, isSigner: false, isWritable: false }, - { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }, - { pubkey: StakeProgram.programId, isSigner: false, isWritable: false }, - ]; - - return new TransactionInstruction({ - programId: STAKE_POOL_PROGRAM_ID, - keys, - data, - }); - } - - /** - * Creates instruction to decrease the stake on a validator. - */ - static decreaseValidatorStake(params: DecreaseValidatorStakeParams): TransactionInstruction { - const { - stakePool, - staker, - withdrawAuthority, - validatorList, - validatorStake, - transientStake, - lamports, - transientStakeSeed, - } = params; - - const type = STAKE_POOL_INSTRUCTION_LAYOUTS.DecreaseValidatorStake; - const data = encodeData(type, { lamports, transientStakeSeed }); - - const keys = [ - { pubkey: stakePool, isSigner: false, isWritable: false }, - { pubkey: staker, isSigner: true, isWritable: false }, - { pubkey: withdrawAuthority, isSigner: false, isWritable: false }, - { pubkey: validatorList, isSigner: false, isWritable: true }, - { pubkey: validatorStake, isSigner: false, isWritable: true }, - { pubkey: transientStake, isSigner: false, isWritable: true }, - { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false }, - { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false }, - { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }, - { pubkey: StakeProgram.programId, isSigner: false, isWritable: false }, - ]; - - return new TransactionInstruction({ - programId: STAKE_POOL_PROGRAM_ID, - keys, - data, - }); - } - - /** - * Creates a transaction instruction to deposit SOL into a stake pool. - */ - static depositStake(params: DepositStakeParams): TransactionInstruction { - const { - stakePool, - validatorList, - depositAuthority, - withdrawAuthority, - depositStake, - validatorStake, - reserveStake, - destinationPoolAccount, - managerFeeAccount, - referralPoolAccount, - poolMint, - } = params; - - const type = STAKE_POOL_INSTRUCTION_LAYOUTS.DepositStake; - const data = encodeData(type); - - const keys = [ - { pubkey: stakePool, isSigner: false, isWritable: true }, - { pubkey: validatorList, isSigner: false, isWritable: true }, - { pubkey: depositAuthority, isSigner: false, isWritable: false }, - { pubkey: withdrawAuthority, isSigner: false, isWritable: false }, - { pubkey: depositStake, isSigner: false, isWritable: true }, - { pubkey: validatorStake, isSigner: false, isWritable: true }, - { pubkey: reserveStake, isSigner: false, isWritable: true }, - { pubkey: destinationPoolAccount, isSigner: false, isWritable: true }, - { pubkey: managerFeeAccount, isSigner: false, isWritable: true }, - { pubkey: referralPoolAccount, isSigner: false, isWritable: true }, - { pubkey: poolMint, isSigner: false, isWritable: true }, - { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false }, - { pubkey: SYSVAR_STAKE_HISTORY_PUBKEY, isSigner: false, isWritable: false }, - { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, - { pubkey: StakeProgram.programId, isSigner: false, isWritable: false }, - ]; - - return new TransactionInstruction({ - programId: STAKE_POOL_PROGRAM_ID, - keys, - data, - }); - } - - /** - * Creates a transaction instruction to withdraw SOL from a stake pool. - */ - static depositSol(params: DepositSolParams): TransactionInstruction { - const { - stakePool, - withdrawAuthority, - depositAuthority, - reserveStake, - fundingAccount, - destinationPoolAccount, - managerFeeAccount, - referralPoolAccount, - poolMint, - lamports, - } = params; - - const type = STAKE_POOL_INSTRUCTION_LAYOUTS.DepositSol; - const data = encodeData(type, { lamports }); - - const keys = [ - { pubkey: stakePool, isSigner: false, isWritable: true }, - { pubkey: withdrawAuthority, isSigner: false, isWritable: false }, - { pubkey: reserveStake, isSigner: false, isWritable: true }, - { pubkey: fundingAccount, isSigner: true, isWritable: true }, - { pubkey: destinationPoolAccount, isSigner: false, isWritable: true }, - { pubkey: managerFeeAccount, isSigner: false, isWritable: true }, - { pubkey: referralPoolAccount, isSigner: false, isWritable: true }, - { pubkey: poolMint, isSigner: false, isWritable: true }, - { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }, - { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, - ]; - - if (depositAuthority) { - keys.push({ - pubkey: depositAuthority, - isSigner: true, - isWritable: false, - }); - } - - return new TransactionInstruction({ - programId: STAKE_POOL_PROGRAM_ID, - keys, - data, - }); - } - - /** - * Creates a transaction instruction to withdraw SOL from a stake pool. - */ - static withdrawStake(params: WithdrawStakeParams): TransactionInstruction { - const { - stakePool, - validatorList, - withdrawAuthority, - validatorStake, - destinationStake, - destinationStakeAuthority, - sourceTransferAuthority, - sourcePoolAccount, - managerFeeAccount, - poolMint, - poolTokens, - } = params; - - const type = STAKE_POOL_INSTRUCTION_LAYOUTS.WithdrawStake; - const data = encodeData(type, { poolTokens }); - - const keys = [ - { pubkey: stakePool, isSigner: false, isWritable: true }, - { pubkey: validatorList, isSigner: false, isWritable: true }, - { pubkey: withdrawAuthority, isSigner: false, isWritable: false }, - { pubkey: validatorStake, isSigner: false, isWritable: true }, - { pubkey: destinationStake, isSigner: false, isWritable: true }, - { pubkey: destinationStakeAuthority, isSigner: false, isWritable: false }, - { pubkey: sourceTransferAuthority, isSigner: true, isWritable: false }, - { pubkey: sourcePoolAccount, isSigner: false, isWritable: true }, - { pubkey: managerFeeAccount, isSigner: false, isWritable: true }, - { pubkey: poolMint, isSigner: false, isWritable: true }, - { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false }, - { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, - { pubkey: StakeProgram.programId, isSigner: false, isWritable: false }, - ]; - - return new TransactionInstruction({ - programId: STAKE_POOL_PROGRAM_ID, - keys, - data, - }); - } - - /** - * Creates a transaction instruction to withdraw SOL from a stake pool. - */ - static withdrawSol(params: WithdrawSolParams): TransactionInstruction { - const { - stakePool, - withdrawAuthority, - sourceTransferAuthority, - sourcePoolAccount, - reserveStake, - destinationSystemAccount, - managerFeeAccount, - solWithdrawAuthority, - poolMint, - poolTokens, - } = params; - - const type = STAKE_POOL_INSTRUCTION_LAYOUTS.WithdrawSol; - const data = encodeData(type, { poolTokens }); - - const keys = [ - { pubkey: stakePool, isSigner: false, isWritable: true }, - { pubkey: withdrawAuthority, isSigner: false, isWritable: false }, - { pubkey: sourceTransferAuthority, isSigner: true, isWritable: false }, - { pubkey: sourcePoolAccount, isSigner: false, isWritable: true }, - { pubkey: reserveStake, isSigner: false, isWritable: true }, - { pubkey: destinationSystemAccount, isSigner: false, isWritable: true }, - { pubkey: managerFeeAccount, isSigner: false, isWritable: true }, - { pubkey: poolMint, isSigner: false, isWritable: true }, - { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false }, - { pubkey: SYSVAR_STAKE_HISTORY_PUBKEY, isSigner: false, isWritable: false }, - { pubkey: StakeProgram.programId, isSigner: false, isWritable: false }, - { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, - ]; - - if (solWithdrawAuthority) { - keys.push({ - pubkey: solWithdrawAuthority, - isSigner: true, - isWritable: false, - }); - } - - return new TransactionInstruction({ - programId: STAKE_POOL_PROGRAM_ID, - keys, - data, - }); - } - - /** - * Decode a deposit stake pool instruction and retrieve the instruction params. - */ - static decodeDepositStake(instruction: TransactionInstruction): DepositStakeParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 11); - - decodeData(STAKE_POOL_INSTRUCTION_LAYOUTS.DepositStake, instruction.data); - - return { - stakePool: instruction.keys[0].pubkey, - validatorList: instruction.keys[1].pubkey, - depositAuthority: instruction.keys[2].pubkey, - withdrawAuthority: instruction.keys[3].pubkey, - depositStake: instruction.keys[4].pubkey, - validatorStake: instruction.keys[5].pubkey, - reserveStake: instruction.keys[6].pubkey, - destinationPoolAccount: instruction.keys[7].pubkey, - managerFeeAccount: instruction.keys[8].pubkey, - referralPoolAccount: instruction.keys[9].pubkey, - poolMint: instruction.keys[10].pubkey, - }; - } - - /** - * Decode a deposit sol instruction and retrieve the instruction params. - */ - static decodeDepositSol(instruction: TransactionInstruction): DepositSolParams { - this.checkProgramId(instruction.programId); - this.checkKeyLength(instruction.keys, 9); - - const { amount } = decodeData(STAKE_POOL_INSTRUCTION_LAYOUTS.DepositSol, instruction.data); - - return { - stakePool: instruction.keys[0].pubkey, - depositAuthority: instruction.keys[1].pubkey, - withdrawAuthority: instruction.keys[2].pubkey, - reserveStake: instruction.keys[3].pubkey, - fundingAccount: instruction.keys[4].pubkey, - destinationPoolAccount: instruction.keys[5].pubkey, - managerFeeAccount: instruction.keys[6].pubkey, - referralPoolAccount: instruction.keys[7].pubkey, - poolMint: instruction.keys[8].pubkey, - lamports: amount, - }; - } - - /** - * @internal - */ - private static checkProgramId(programId: PublicKey) { - if (!programId.equals(StakeProgram.programId)) { - throw new Error('Invalid instruction; programId is not StakeProgram'); - } - } - - /** - * @internal - */ - private static checkKeyLength(keys: Array, expectedLength: number) { - if (keys.length < expectedLength) { - throw new Error( - `Invalid instruction; found ${keys.length} keys, expected at least ${expectedLength}`, - ); - } - } -} diff --git a/stake-pool/js/src/layouts.ts b/stake-pool/js/src/layouts.ts deleted file mode 100644 index ba5d9489704..00000000000 --- a/stake-pool/js/src/layouts.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { publicKey, struct, u32, u64, u8, option, vec } from '@project-serum/borsh'; -import { Lockup, PublicKey } from '@solana/web3.js'; -import { AccountInfo } from '@solana/spl-token'; -import BN from 'bn.js'; - -export interface Fee { - denominator: BN; - numerator: BN; -} - -const feeFields = [u64('denominator'), u64('numerator')]; - -/** - * AccountLayout.encode from "@solana/spl-token" doesn't work - */ -export const AccountLayout = struct([ - publicKey('mint'), - publicKey('owner'), - u64('amount'), - u32('delegateOption'), - publicKey('delegate'), - u8('state'), - u32('isNativeOption'), - u64('isNative'), - u64('delegatedAmount'), - u32('closeAuthorityOption'), - publicKey('closeAuthority'), -]); - -export enum AccountType { - Uninitialized, - StakePool, - ValidatorList, -} - -export interface StakePool { - accountType: AccountType; - manager: PublicKey; - staker: PublicKey; - stakeDepositAuthority: PublicKey; - stakeWithdrawBumpSeed: number; - validatorList: PublicKey; - reserveStake: PublicKey; - poolMint: PublicKey; - managerFeeAccount: PublicKey; - tokenProgramId: PublicKey; - totalLamports: BN; - poolTokenSupply: BN; - lastUpdateEpoch: BN; - lockup: Lockup; - epochFee: Fee; - nextEpochFee?: Fee | undefined; - preferredDepositValidatorVoteAddress?: PublicKey | undefined; - preferredWithdrawValidatorVoteAddress?: PublicKey | undefined; - stakeDepositFee: Fee; - stakeWithdrawalFee: Fee; - nextStakeWithdrawalFee?: Fee | undefined; - stakeReferralFee: number; - solDepositAuthority?: PublicKey | undefined; - solDepositFee: Fee; - solReferralFee: number; - solWithdrawAuthority?: PublicKey | undefined; - solWithdrawalFee: Fee; - nextSolWithdrawalFee?: Fee | undefined; - lastEpochPoolTokenSupply: BN; - lastEpochTotalLamports: BN; -} - -export const StakePoolLayout = struct([ - u8('accountType'), - publicKey('manager'), - publicKey('staker'), - publicKey('stakeDepositAuthority'), - u8('stakeWithdrawBumpSeed'), - publicKey('validatorList'), - publicKey('reserveStake'), - publicKey('poolMint'), - publicKey('managerFeeAccount'), - publicKey('tokenProgramId'), - u64('totalLamports'), - u64('poolTokenSupply'), - u64('lastUpdateEpoch'), - struct([u64('unixTimestamp'), u64('epoch'), publicKey('custodian')], 'lockup'), - struct(feeFields, 'epochFee'), - option(struct(feeFields), 'nextEpochFee'), - option(publicKey(), 'preferredDepositValidatorVoteAddress'), - option(publicKey(), 'preferredWithdrawValidatorVoteAddress'), - struct(feeFields, 'stakeDepositFee'), - struct(feeFields, 'stakeWithdrawalFee'), - option(struct(feeFields), 'nextStakeWithdrawalFee'), - u8('stakeReferralFee'), - option(publicKey(), 'solDepositAuthority'), - struct(feeFields, 'solDepositFee'), - u8('solReferralFee'), - option(publicKey(), 'solWithdrawAuthority'), - struct(feeFields, 'solWithdrawalFee'), - option(struct(feeFields), 'nextSolWithdrawalFee'), - u64('lastEpochPoolTokenSupply'), - u64('lastEpochTotalLamports'), -]); - -export enum ValidatorStakeInfoStatus { - Active, - DeactivatingTransient, - ReadyForRemoval, -} - -export interface ValidatorStakeInfo { - status: ValidatorStakeInfoStatus; - voteAccountAddress: PublicKey; - activeStakeLamports: BN; - transientStakeLamports: BN; - transientSeedSuffixStart: BN; - transientSeedSuffixEnd: BN; - lastUpdateEpoch: BN; -} - -export const ValidatorStakeInfoLayout = struct([ - /// Amount of active stake delegated to this validator - /// Note that if `last_update_epoch` does not match the current epoch then - /// this field may not be accurate - u64('activeStakeLamports'), - /// Amount of transient stake delegated to this validator - /// Note that if `last_update_epoch` does not match the current epoch then - /// this field may not be accurate - u64('transientStakeLamports'), - /// Last epoch the active and transient stake lamports fields were updated - u64('lastUpdateEpoch'), - /// Start of the validator transient account seed suffixes - u64('transientSeedSuffixStart'), - /// End of the validator transient account seed suffixes - u64('transientSeedSuffixEnd'), - /// Status of the validator stake account - u8('status'), - /// Validator vote account address - publicKey('voteAccountAddress'), -]); - -export interface ValidatorList { - /// Account type, must be ValidatorList currently - accountType: number; - /// Maximum allowable number of validators - maxValidators: number; - /// List of stake info for each validator in the pool - validators: ValidatorStakeInfo[]; -} - -export const ValidatorListLayout = struct([ - u8('accountType'), - u32('maxValidators'), - vec(ValidatorStakeInfoLayout, 'validators'), -]); diff --git a/stake-pool/js/src/types/buffer-layout.d.ts b/stake-pool/js/src/types/buffer-layout.d.ts deleted file mode 100644 index 54773bbad86..00000000000 --- a/stake-pool/js/src/types/buffer-layout.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -declare module 'buffer-layout' { - export class Layout {} - export class UInt {} - /* eslint-disable @typescript-eslint/no-unused-vars */ - export function struct(fields: any, property?: string, decodePrefixes?: boolean): any; - export function s32(property?: string): UInt; - export function u32(property?: string): UInt; - export function s16(property?: string): UInt; - export function u16(property?: string): UInt; - export function s8(property?: string): UInt; - export function u8(property?: string): UInt; -} diff --git a/stake-pool/js/src/utils/index.ts b/stake-pool/js/src/utils/index.ts deleted file mode 100644 index 1091d0eccd2..00000000000 --- a/stake-pool/js/src/utils/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -export * from './math'; -export * from './program-address'; -export * from './stake'; -export * from './token'; -export * from './instruction'; - -export function arrayChunk(array: any[], size: number): any[] { - const result = []; - for (let i = 0; i < array.length; i += size) { - result.push(array.slice(i, i + size)); - } - return result; -} diff --git a/stake-pool/js/src/utils/instruction.ts b/stake-pool/js/src/utils/instruction.ts deleted file mode 100644 index 24ccad8ab00..00000000000 --- a/stake-pool/js/src/utils/instruction.ts +++ /dev/null @@ -1,46 +0,0 @@ -import * as BufferLayout from '@solana/buffer-layout'; -import { Buffer } from 'buffer'; - -/** - * @internal - */ -export type InstructionType = { - /** The Instruction index (from solana upstream program) */ - index: number; - /** The BufferLayout to use to build data */ - layout: BufferLayout.Layout; -}; - -/** - * Populate a buffer of instruction data using an InstructionType - * @internal - */ -export function encodeData(type: InstructionType, fields?: any): Buffer { - const allocLength = type.layout.span; - const data = Buffer.alloc(allocLength); - const layoutFields = Object.assign({ instruction: type.index }, fields); - type.layout.encode(layoutFields, data); - - return data; -} - -/** - * Decode instruction data buffer using an InstructionType - * @internal - */ -export function decodeData(type: InstructionType, buffer: Buffer): any { - let data; - try { - data = type.layout.decode(buffer); - } catch (err) { - throw new Error('invalid instruction; ' + err); - } - - if (data.instruction !== type.index) { - throw new Error( - `invalid instruction; instruction index mismatch ${data.instruction} != ${type.index}`, - ); - } - - return data; -} diff --git a/stake-pool/js/src/utils/math.ts b/stake-pool/js/src/utils/math.ts deleted file mode 100644 index ab64724e576..00000000000 --- a/stake-pool/js/src/utils/math.ts +++ /dev/null @@ -1,24 +0,0 @@ -import BN from 'bn.js'; -import { LAMPORTS_PER_SOL } from '@solana/web3.js'; - -export function solToLamports(amount: number): number { - if (isNaN(amount)) return Number(0); - return Number(amount * LAMPORTS_PER_SOL); -} - -export function lamportsToSol(lamports: number | BN): number { - if (typeof lamports === 'number') { - return Math.abs(lamports) / LAMPORTS_PER_SOL; - } - - let signMultiplier = 1; - if (lamports.isNeg()) { - signMultiplier = -1; - } - - const absLamports = lamports.abs(); - const lamportsString = absLamports.toString(10).padStart(10, '0'); - const splitIndex = lamportsString.length - 9; - const solString = lamportsString.slice(0, splitIndex) + '.' + lamportsString.slice(splitIndex); - return signMultiplier * parseFloat(solString); -} diff --git a/stake-pool/js/src/utils/program-address.ts b/stake-pool/js/src/utils/program-address.ts deleted file mode 100644 index 2eb364c1b9c..00000000000 --- a/stake-pool/js/src/utils/program-address.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { PublicKey } from '@solana/web3.js'; -import BN from 'bn.js'; -import { Buffer } from 'buffer'; -import { TRANSIENT_STAKE_SEED_PREFIX } from '../constants'; - -/** - * Generates the withdraw authority program address for the stake pool - */ -export async function findWithdrawAuthorityProgramAddress( - programId: PublicKey, - stakePoolAddress: PublicKey, -) { - const [publicKey] = await PublicKey.findProgramAddress( - [stakePoolAddress.toBuffer(), Buffer.from('withdraw')], - programId, - ); - return publicKey; -} - -/** - * Generates the stake program address for a validator's vote account - */ -export async function findStakeProgramAddress( - programId: PublicKey, - voteAccountAddress: PublicKey, - stakePoolAddress: PublicKey, -) { - const [publicKey] = await PublicKey.findProgramAddress( - [voteAccountAddress.toBuffer(), stakePoolAddress.toBuffer()], - programId, - ); - return publicKey; -} - -/** - * Generates the stake program address for a validator's vote account - */ -export async function findTransientStakeProgramAddress( - programId: PublicKey, - voteAccountAddress: PublicKey, - stakePoolAddress: PublicKey, - seed: BN, -) { - const [publicKey] = await PublicKey.findProgramAddress( - [ - TRANSIENT_STAKE_SEED_PREFIX, - voteAccountAddress.toBuffer(), - stakePoolAddress.toBuffer(), - new Uint8Array(seed.toArray('le', 8)), - ], - programId, - ); - return publicKey; -} diff --git a/stake-pool/js/src/utils/stake.ts b/stake-pool/js/src/utils/stake.ts deleted file mode 100644 index 9eef2c6c52e..00000000000 --- a/stake-pool/js/src/utils/stake.ts +++ /dev/null @@ -1,240 +0,0 @@ -import { - Connection, - Keypair, - PublicKey, - StakeProgram, - SystemProgram, - TransactionInstruction, -} from '@solana/web3.js'; -import { findStakeProgramAddress, findTransientStakeProgramAddress } from './program-address'; -import BN from 'bn.js'; - -import { lamportsToSol } from './math'; -import { WithdrawAccount } from '../index'; -import { - Fee, - StakePool, - ValidatorList, - ValidatorListLayout, - ValidatorStakeInfoStatus, -} from '../layouts'; -import { MINIMUM_ACTIVE_STAKE, STAKE_POOL_PROGRAM_ID } from '../constants'; - -export async function getValidatorListAccount(connection: Connection, pubkey: PublicKey) { - const account = await connection.getAccountInfo(pubkey); - if (!account) { - throw new Error('Invalid validator list account'); - } - return { - pubkey, - account: { - data: ValidatorListLayout.decode(account?.data) as ValidatorList, - executable: account.executable, - lamports: account.lamports, - owner: account.owner, - }, - }; -} - -export interface ValidatorAccount { - type: 'preferred' | 'active' | 'transient' | 'reserve'; - voteAddress?: PublicKey | undefined; - stakeAddress: PublicKey; - lamports: number; -} - -export async function prepareWithdrawAccounts( - connection: Connection, - stakePool: StakePool, - stakePoolAddress: PublicKey, - amount: number, - compareFn?: (a: ValidatorAccount, b: ValidatorAccount) => number, - skipFee?: boolean, -): Promise { - const validatorListAcc = await connection.getAccountInfo(stakePool.validatorList); - const validatorList = ValidatorListLayout.decode(validatorListAcc?.data) as ValidatorList; - - if (!validatorList?.validators || validatorList?.validators.length == 0) { - throw new Error('No accounts found'); - } - - const minBalanceForRentExemption = await connection.getMinimumBalanceForRentExemption( - StakeProgram.space, - ); - const minBalance = minBalanceForRentExemption + MINIMUM_ACTIVE_STAKE; - - let accounts = [] as Array<{ - type: 'preferred' | 'active' | 'transient' | 'reserve'; - voteAddress?: PublicKey | undefined; - stakeAddress: PublicKey; - lamports: number; - }>; - - // Prepare accounts - for (const validator of validatorList.validators) { - if (validator.status !== ValidatorStakeInfoStatus.Active) { - continue; - } - - const stakeAccountAddress = await findStakeProgramAddress( - STAKE_POOL_PROGRAM_ID, - validator.voteAccountAddress, - stakePoolAddress, - ); - - if (!validator.activeStakeLamports.isZero()) { - const isPreferred = stakePool?.preferredWithdrawValidatorVoteAddress?.equals( - validator.voteAccountAddress, - ); - accounts.push({ - type: isPreferred ? 'preferred' : 'active', - voteAddress: validator.voteAccountAddress, - stakeAddress: stakeAccountAddress, - lamports: validator.activeStakeLamports.toNumber(), - }); - } - - const transientStakeLamports = validator.transientStakeLamports.toNumber() - minBalance; - if (transientStakeLamports > 0) { - const transientStakeAccountAddress = await findTransientStakeProgramAddress( - STAKE_POOL_PROGRAM_ID, - validator.voteAccountAddress, - stakePoolAddress, - validator.transientSeedSuffixStart, - ); - accounts.push({ - type: 'transient', - voteAddress: validator.voteAccountAddress, - stakeAddress: transientStakeAccountAddress, - lamports: transientStakeLamports, - }); - } - } - - // Sort from highest to lowest balance - accounts = accounts.sort(compareFn ? compareFn : (a, b) => b.lamports - a.lamports); - - const reserveStake = await connection.getAccountInfo(stakePool.reserveStake); - const reserveStakeBalance = (reserveStake?.lamports ?? 0) - minBalanceForRentExemption - 1; - if (reserveStakeBalance > 0) { - accounts.push({ - type: 'reserve', - stakeAddress: stakePool.reserveStake, - lamports: reserveStakeBalance, - }); - } - - // Prepare the list of accounts to withdraw from - const withdrawFrom: WithdrawAccount[] = []; - let remainingAmount = amount; - - const fee = stakePool.stakeWithdrawalFee; - const inverseFee: Fee = { - numerator: fee.denominator.sub(fee.numerator), - denominator: fee.denominator, - }; - - for (const type of ['preferred', 'active', 'transient', 'reserve']) { - const filteredAccounts = accounts.filter((a) => a.type == type); - - for (const { stakeAddress, voteAddress, lamports } of filteredAccounts) { - if (lamports <= minBalance && type == 'transient') { - continue; - } - - let availableForWithdrawal = calcPoolTokensForDeposit(stakePool, lamports); - - if (!skipFee && !inverseFee.numerator.isZero()) { - availableForWithdrawal = divideBnToNumber( - new BN(availableForWithdrawal).mul(inverseFee.denominator), - inverseFee.numerator, - ); - } - - const poolAmount = Math.min(availableForWithdrawal, remainingAmount); - if (poolAmount <= 0) { - continue; - } - - // Those accounts will be withdrawn completely with `claim` instruction - withdrawFrom.push({ stakeAddress, voteAddress, poolAmount }); - remainingAmount -= poolAmount; - - if (remainingAmount == 0) { - break; - } - } - - if (remainingAmount == 0) { - break; - } - } - - // Not enough stake to withdraw the specified amount - if (remainingAmount > 0) { - throw new Error( - `No stake accounts found in this pool with enough balance to withdraw ${lamportsToSol( - amount, - )} pool tokens.`, - ); - } - - return withdrawFrom; -} - -/** - * Calculate the pool tokens that should be minted for a deposit of `stakeLamports` - */ -export function calcPoolTokensForDeposit(stakePool: StakePool, stakeLamports: number): number { - if (stakePool.poolTokenSupply.isZero() || stakePool.totalLamports.isZero()) { - return stakeLamports; - } - return Math.floor( - divideBnToNumber(new BN(stakeLamports).mul(stakePool.poolTokenSupply), stakePool.totalLamports), - ); -} - -/** - * Calculate lamports amount on withdrawal - */ -export function calcLamportsWithdrawAmount(stakePool: StakePool, poolTokens: number): number { - const numerator = new BN(poolTokens).mul(stakePool.totalLamports); - const denominator = stakePool.poolTokenSupply; - if (numerator.lt(denominator)) { - return 0; - } - return divideBnToNumber(numerator, denominator); -} - -export function divideBnToNumber(numerator: BN, denominator: BN): number { - if (denominator.isZero()) { - return 0; - } - const quotient = numerator.div(denominator).toNumber(); - const rem = numerator.umod(denominator); - const gcd = rem.gcd(denominator); - return quotient + rem.div(gcd).toNumber() / denominator.div(gcd).toNumber(); -} - -export function newStakeAccount( - feePayer: PublicKey, - instructions: TransactionInstruction[], - lamports: number, -): Keypair { - // Account for tokens not specified, creating one - const stakeReceiverKeypair = Keypair.generate(); - console.log(`Creating account to receive stake ${stakeReceiverKeypair.publicKey}`); - - instructions.push( - // Creating new account - SystemProgram.createAccount({ - fromPubkey: feePayer, - newAccountPubkey: stakeReceiverKeypair.publicKey, - lamports, - space: StakeProgram.space, - programId: StakeProgram.programId, - }), - ); - - return stakeReceiverKeypair; -} diff --git a/stake-pool/js/src/utils/token.ts b/stake-pool/js/src/utils/token.ts deleted file mode 100644 index ee20463f8c7..00000000000 --- a/stake-pool/js/src/utils/token.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { Connection, PublicKey, TransactionInstruction } from '@solana/web3.js'; -import { - AccountInfo, - ASSOCIATED_TOKEN_PROGRAM_ID, - MintInfo, - Token, - TOKEN_PROGRAM_ID, -} from '@solana/spl-token'; -import { AccountLayout } from '../layouts'; - -const FAILED_TO_FIND_ACCOUNT = 'Failed to find account'; -const INVALID_ACCOUNT_OWNER = 'Invalid account owner'; - -export async function getTokenMint( - connection: Connection, - tokenMintPubkey: PublicKey, -): Promise { - // @ts-ignore - const token = new Token(connection, tokenMintPubkey, TOKEN_PROGRAM_ID, null); - return token.getMintInfo(); -} - -/** - * Retrieve the associated account or create one if not found. - * This account may then be used as a `transfer()` or `approve()` destination - */ -export async function addAssociatedTokenAccount( - connection: Connection, - owner: PublicKey, - mint: PublicKey, - instructions: TransactionInstruction[], -) { - const associatedAddress = await Token.getAssociatedTokenAddress( - ASSOCIATED_TOKEN_PROGRAM_ID, - TOKEN_PROGRAM_ID, - mint, - owner, - ); - - let rentFee = 0; - - // This is the optimum logic, considering TX fee, client-side computation, - // RPC roundtrips and guaranteed idempotent. - // Sadly we can't do this atomically; - try { - const account = await connection.getAccountInfo(associatedAddress); - if (!account) { - // noinspection ExceptionCaughtLocallyJS - throw new Error(FAILED_TO_FIND_ACCOUNT); - } - } catch (err: any) { - // INVALID_ACCOUNT_OWNER can be possible if the associatedAddress has - // already been received some lamports (= became system accounts). - // Assuming program derived addressing is safe, this is the only case - // for the INVALID_ACCOUNT_OWNER in this code-path - if (err.message === FAILED_TO_FIND_ACCOUNT || err.message === INVALID_ACCOUNT_OWNER) { - instructions.push( - Token.createAssociatedTokenAccountInstruction( - ASSOCIATED_TOKEN_PROGRAM_ID, - TOKEN_PROGRAM_ID, - mint, - associatedAddress, - owner, - owner, - ), - ); - rentFee = await connection.getMinimumBalanceForRentExemption(AccountLayout.span); - } else { - throw err; - } - console.warn(err); - } - - return { - associatedAddress, - rentFee, - }; -} - -export async function getTokenAccount( - connection: Connection, - tokenAccountAddress: PublicKey, - expectedTokenMint: PublicKey, -): Promise { - try { - const account = await connection.getAccountInfo(tokenAccountAddress); - if (!account) { - // noinspection ExceptionCaughtLocallyJS - throw new Error(`Invalid account ${tokenAccountAddress.toBase58()}`); - } - const tokenAccount = AccountLayout.decode(account.data) as AccountInfo; - if (tokenAccount.mint?.toBase58() != expectedTokenMint.toBase58()) { - // noinspection ExceptionCaughtLocallyJS - throw new Error( - `Invalid token mint for ${tokenAccountAddress}, expected mint is ${expectedTokenMint}`, - ); - } - return tokenAccount; - } catch (error) { - console.log(error); - } -} diff --git a/stake-pool/js/test/equal.ts b/stake-pool/js/test/equal.ts deleted file mode 100644 index b86e417bc9b..00000000000 --- a/stake-pool/js/test/equal.ts +++ /dev/null @@ -1,37 +0,0 @@ -import BN from 'bn.js'; - -/** - * Helper function to do deep equality check because BNs are not equal. - * TODO: write this function recursively. For now, sufficient. - */ -export function deepStrictEqualBN(a: any, b: any) { - for (const key in a) { - if (b[key] instanceof BN) { - expect(b[key].toString()).toEqual(a[key].toString()); - } else { - if (a[key] instanceof Object) { - for (const subkey in a[key]) { - if (a[key][subkey] instanceof Object) { - if (a[key][subkey] instanceof BN) { - expect(b[key][subkey].toString()).toEqual(a[key][subkey].toString()); - } else { - for (const subsubkey in a[key][subkey]) { - if (a[key][subkey][subsubkey] instanceof BN) { - expect(b[key][subkey][subsubkey].toString()).toEqual( - a[key][subkey][subsubkey].toString(), - ); - } else { - expect(b[key][subkey][subsubkey]).toStrictEqual(a[key][subkey][subsubkey]); - } - } - } - } else { - expect(b[key][subkey]).toStrictEqual(a[key][subkey]); - } - } - } else { - expect(b[key]).toStrictEqual(a[key]); - } - } - } -} diff --git a/stake-pool/js/test/instructions.test.ts b/stake-pool/js/test/instructions.test.ts deleted file mode 100644 index 8a9681b13bd..00000000000 --- a/stake-pool/js/test/instructions.test.ts +++ /dev/null @@ -1,256 +0,0 @@ -import { - PublicKey, - Connection, - Keypair, - SystemProgram, - AccountInfo, - LAMPORTS_PER_SOL, -} from '@solana/web3.js'; -import { StakePoolLayout } from '../src/layouts'; -import { - STAKE_POOL_INSTRUCTION_LAYOUTS, - STAKE_POOL_PROGRAM_ID, - DepositSolParams, - StakePoolInstruction, - depositSol, - withdrawSol, - withdrawStake, -} from '../src'; - -import { decodeData } from '../src/utils'; - -import { mockTokenAccount, mockValidatorList, stakePoolMock } from './mocks'; - -describe('StakePoolProgram', () => { - const connection = new Connection('http://127.0.0.1:8899'); - - connection.getMinimumBalanceForRentExemption = jest.fn(async () => 10000); - - const stakePoolAddress = new PublicKey('SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy'); - - const data = Buffer.alloc(1024); - StakePoolLayout.encode(stakePoolMock, data); - - const stakePoolAccount = >{ - executable: true, - owner: stakePoolAddress, - lamports: 99999, - data, - }; - - it('StakePoolInstruction.depositSol', () => { - const payload: DepositSolParams = { - stakePool: stakePoolAddress, - withdrawAuthority: Keypair.generate().publicKey, - reserveStake: Keypair.generate().publicKey, - fundingAccount: Keypair.generate().publicKey, - destinationPoolAccount: Keypair.generate().publicKey, - managerFeeAccount: Keypair.generate().publicKey, - referralPoolAccount: Keypair.generate().publicKey, - poolMint: Keypair.generate().publicKey, - lamports: 99999, - }; - - const instruction = StakePoolInstruction.depositSol(payload); - - expect(instruction.keys).toHaveLength(10); - expect(instruction.keys[0].pubkey.toBase58()).toEqual(payload.stakePool.toBase58()); - expect(instruction.keys[1].pubkey.toBase58()).toEqual(payload.withdrawAuthority.toBase58()); - expect(instruction.keys[3].pubkey.toBase58()).toEqual(payload.fundingAccount.toBase58()); - expect(instruction.keys[4].pubkey.toBase58()).toEqual( - payload.destinationPoolAccount.toBase58(), - ); - expect(instruction.keys[5].pubkey.toBase58()).toEqual(payload.managerFeeAccount.toBase58()); - expect(instruction.keys[6].pubkey.toBase58()).toEqual(payload.referralPoolAccount.toBase58()); - expect(instruction.keys[8].pubkey.toBase58()).toEqual(SystemProgram.programId.toBase58()); - expect(instruction.keys[9].pubkey.toBase58()).toEqual(STAKE_POOL_PROGRAM_ID.toBase58()); - - const decodedData = decodeData(STAKE_POOL_INSTRUCTION_LAYOUTS.DepositSol, instruction.data); - - expect(decodedData.instruction).toEqual(STAKE_POOL_INSTRUCTION_LAYOUTS.DepositSol.index); - expect(decodedData.lamports).toEqual(payload.lamports); - - payload.depositAuthority = Keypair.generate().publicKey; - - const instruction2 = StakePoolInstruction.depositSol(payload); - - expect(instruction2.keys).toHaveLength(11); - expect(instruction2.keys[10].pubkey.toBase58()).toEqual(payload.depositAuthority.toBase58()); - }); - - describe('depositSol', () => { - const from = Keypair.generate().publicKey; - const balance = 10000; - - connection.getBalance = jest.fn(async () => balance); - - connection.getAccountInfo = jest.fn(async (pubKey) => { - if (pubKey == stakePoolAddress) { - return stakePoolAccount; - } - return >{ - executable: true, - owner: from, - lamports: balance, - data: null, - }; - }); - - it.only('should throw an error with invalid balance', async () => { - await expect(depositSol(connection, stakePoolAddress, from, balance + 1)).rejects.toThrow( - Error('Not enough SOL to deposit into pool. Maximum deposit amount is 0.00001 SOL.'), - ); - }); - - it.only('should throw an error with invalid account', async () => { - connection.getAccountInfo = jest.fn(async () => null); - await expect(depositSol(connection, stakePoolAddress, from, balance)).rejects.toThrow( - Error('Invalid stake pool account'), - ); - }); - - it.only('should call successfully', async () => { - connection.getAccountInfo = jest.fn(async (pubKey) => { - if (pubKey == stakePoolAddress) { - return stakePoolAccount; - } - return >{ - executable: true, - owner: from, - lamports: balance, - data: null, - }; - }); - - const res = await depositSol(connection, stakePoolAddress, from, balance); - - expect((connection.getAccountInfo as jest.Mock).mock.calls.length).toBe(2); - expect(res.instructions).toHaveLength(2); - expect(res.signers).toHaveLength(1); - }); - }); - - describe('withdrawSol', () => { - const tokenOwner = new PublicKey(0); - const solReceiver = new PublicKey(1); - - it.only('should throw an error with invalid stake pool account', async () => { - connection.getAccountInfo = jest.fn(async () => null); - await expect( - withdrawSol(connection, stakePoolAddress, tokenOwner, solReceiver, 1), - ).rejects.toThrowError('Invalid stake pool account'); - }); - - it.only('should throw an error with invalid token account', async () => { - connection.getAccountInfo = jest.fn(async (pubKey: PublicKey) => { - if (pubKey == stakePoolAddress) { - return stakePoolAccount; - } - if (pubKey.toBase58() == '9q2rZU5RujvyD9dmYKhzJAZfG4aGBbvQ8rWY52jCNBai') { - return null; - } - return null; - }); - - await expect( - withdrawSol(connection, stakePoolAddress, tokenOwner, solReceiver, 1), - ).rejects.toThrow(Error('Invalid token account')); - }); - - it.only('should throw an error with invalid token account balance', async () => { - connection.getAccountInfo = jest.fn(async (pubKey: PublicKey) => { - if (pubKey == stakePoolAddress) { - return stakePoolAccount; - } - if (pubKey.toBase58() == 'GQkqTamwqjaNDfsbNm7r3aXPJ4oTSqKC3d5t2PF9Smqd') { - return mockTokenAccount(0); - } - return null; - }); - - await expect( - withdrawSol(connection, stakePoolAddress, tokenOwner, solReceiver, 1), - ).rejects.toThrow( - Error( - 'Not enough token balance to withdraw 1 pool tokens.\n Maximum withdraw amount is 0 pool tokens.', - ), - ); - }); - - it.only('should call successfully', async () => { - connection.getAccountInfo = jest.fn(async (pubKey: PublicKey) => { - if (pubKey == stakePoolAddress) { - return stakePoolAccount; - } - if (pubKey.toBase58() == 'GQkqTamwqjaNDfsbNm7r3aXPJ4oTSqKC3d5t2PF9Smqd') { - return mockTokenAccount(LAMPORTS_PER_SOL); - } - return null; - }); - const res = await withdrawSol(connection, stakePoolAddress, tokenOwner, solReceiver, 1); - - expect((connection.getAccountInfo as jest.Mock).mock.calls.length).toBe(2); - expect(res.instructions).toHaveLength(2); - expect(res.signers).toHaveLength(1); - }); - }); - - describe('withdrawStake', () => { - const tokenOwner = new PublicKey(0); - - it.only('should throw an error with invalid token account', async () => { - connection.getAccountInfo = jest.fn(async (pubKey: PublicKey) => { - if (pubKey == stakePoolAddress) { - return stakePoolAccount; - } - return null; - }); - - await expect(withdrawStake(connection, stakePoolAddress, tokenOwner, 1)).rejects.toThrow( - Error('Invalid token account'), - ); - }); - - it.only('should throw an error with invalid token account balance', async () => { - connection.getAccountInfo = jest.fn(async (pubKey: PublicKey) => { - if (pubKey == stakePoolAddress) { - return stakePoolAccount; - } - if (pubKey.toBase58() == 'GQkqTamwqjaNDfsbNm7r3aXPJ4oTSqKC3d5t2PF9Smqd') { - return mockTokenAccount(0); - } - return null; - }); - - await expect(withdrawStake(connection, stakePoolAddress, tokenOwner, 1)).rejects.toThrow( - Error( - 'Not enough token balance to withdraw 1 pool tokens.\n' + - ' Maximum withdraw amount is 0 pool tokens.', - ), - ); - }); - - it.only('should call successfully', async () => { - connection.getAccountInfo = jest.fn(async (pubKey: PublicKey) => { - if (pubKey == stakePoolAddress) { - return stakePoolAccount; - } - if (pubKey.toBase58() == 'GQkqTamwqjaNDfsbNm7r3aXPJ4oTSqKC3d5t2PF9Smqd') { - return mockTokenAccount(LAMPORTS_PER_SOL * 2); - } - if (pubKey.toBase58() == stakePoolMock.validatorList.toBase58()) { - return mockValidatorList(); - } - return null; - }); - - const res = await withdrawStake(connection, stakePoolAddress, tokenOwner, 1); - - expect((connection.getAccountInfo as jest.Mock).mock.calls.length).toBe(4); - expect(res.instructions).toHaveLength(3); - expect(res.signers).toHaveLength(2); - expect(res.stakeReceiver).toEqual(undefined); - expect(res.totalRentFreeBalances).toEqual(10000); - }); - }); -}); diff --git a/stake-pool/js/test/layouts.test.ts b/stake-pool/js/test/layouts.test.ts deleted file mode 100644 index 053f43e1c7d..00000000000 --- a/stake-pool/js/test/layouts.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { StakePoolLayout, ValidatorListLayout, ValidatorList } from '../src/layouts'; -import { deepStrictEqualBN } from './equal'; -import { stakePoolMock, validatorListMock } from './mocks'; - -describe('layouts', () => { - describe('StakePoolAccount', () => { - it('should successfully decode StakePoolAccount data', () => { - const encodedData = Buffer.alloc(1024); - StakePoolLayout.encode(stakePoolMock, encodedData); - const decodedData = StakePoolLayout.decode(encodedData); - deepStrictEqualBN(decodedData, stakePoolMock); - }); - }); - - describe('ValidatorListAccount', () => { - it('should successfully decode ValidatorListAccount account data', () => { - const expectedData: ValidatorList = { - accountType: 0, - maxValidators: 10, - validators: [], - }; - const encodedData = Buffer.alloc(64); - ValidatorListLayout.encode(expectedData, encodedData); - const decodedData = ValidatorListLayout.decode(encodedData); - expect(decodedData).toEqual(expectedData); - }); - - it('should successfully decode ValidatorListAccount with nonempty ValidatorInfo', () => { - const encodedData = Buffer.alloc(1024); - ValidatorListLayout.encode(validatorListMock, encodedData); - const decodedData = ValidatorListLayout.decode(encodedData); - deepStrictEqualBN(decodedData, validatorListMock); - }); - }); -}); diff --git a/stake-pool/js/test/mocks.ts b/stake-pool/js/test/mocks.ts deleted file mode 100644 index df2c0c04cd4..00000000000 --- a/stake-pool/js/test/mocks.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { AccountInfo, LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js'; -import BN from 'bn.js'; -import { ValidatorStakeInfo } from '../src'; -import { ValidatorStakeInfoStatus, AccountLayout, ValidatorListLayout } from '../src/layouts'; - -export const stakePoolMock = { - accountType: 1, - manager: new PublicKey(11), - staker: new PublicKey(12), - stakeDepositAuthority: new PublicKey(13), - stakeWithdrawBumpSeed: 255, - validatorList: new PublicKey(14), - reserveStake: new PublicKey(15), - poolMint: new PublicKey(16), - managerFeeAccount: new PublicKey(17), - tokenProgramId: new PublicKey(18), - totalLamports: new BN(LAMPORTS_PER_SOL * 999), - poolTokenSupply: new BN(LAMPORTS_PER_SOL * 100), - lastUpdateEpoch: new BN('7c', 'hex'), - lockup: { - unixTimestamp: new BN(Date.now()), - epoch: new BN(1), - custodian: new PublicKey(0), - }, - epochFee: { - denominator: new BN(0), - numerator: new BN(0), - }, - nextEpochFee: { - denominator: new BN(0), - numerator: new BN(0), - }, - preferredDepositValidatorVoteAddress: new PublicKey(1), - preferredWithdrawValidatorVoteAddress: new PublicKey(2), - stakeDepositFee: { - denominator: new BN(0), - numerator: new BN(0), - }, - stakeWithdrawalFee: { - denominator: new BN(0), - numerator: new BN(0), - }, - nextStakeWithdrawalFee: { - denominator: new BN(0), - numerator: new BN(0), - }, - stakeReferralFee: 0, - solDepositAuthority: new PublicKey(0), - solDepositFee: { - denominator: new BN(0), - numerator: new BN(0), - }, - solReferralFee: 0, - solWithdrawAuthority: new PublicKey(0), - solWithdrawalFee: { - denominator: new BN(0), - numerator: new BN(0), - }, - nextSolWithdrawalFee: { - denominator: new BN(0), - numerator: new BN(0), - }, - lastEpochPoolTokenSupply: new BN(0), - lastEpochTotalLamports: new BN(0), -}; - -export const validatorListMock = { - accountType: 0, - maxValidators: 100, - validators: [ - { - status: ValidatorStakeInfoStatus.ReadyForRemoval, - voteAccountAddress: new PublicKey( - new BN('a9946a889af14fd3c9b33d5df309489d9699271a6b09ff3190fcb41cf21a2f8c', 'hex'), - ), - lastUpdateEpoch: new BN('c3', 'hex'), - activeStakeLamports: new BN(123), - transientStakeLamports: new BN(999), - transientSeedSuffixStart: new BN(999), - transientSeedSuffixEnd: new BN(999), - }, - { - status: ValidatorStakeInfoStatus.Active, - voteAccountAddress: new PublicKey( - new BN('3796d40645ee07e3c64117e3f73430471d4c40465f696ebc9b034c1fc06a9f7d', 'hex'), - ), - lastUpdateEpoch: new BN('c3', 'hex'), - activeStakeLamports: new BN(LAMPORTS_PER_SOL * 100), - transientStakeLamports: new BN(22), - transientSeedSuffixStart: new BN(0), - transientSeedSuffixEnd: new BN(0), - }, - { - status: ValidatorStakeInfoStatus.Active, - voteAccountAddress: new PublicKey( - new BN('e4e37d6f2e80c0bb0f3da8a06304e57be5cda6efa2825b86780aa320d9784cf8', 'hex'), - ), - lastUpdateEpoch: new BN('c3', 'hex'), - activeStakeLamports: new BN(0), - transientStakeLamports: new BN(0), - transientSeedSuffixStart: new BN('a', 'hex'), - transientSeedSuffixEnd: new BN('a', 'hex'), - }, - ], -}; - -export function mockTokenAccount(amount = 0) { - const data = Buffer.alloc(1024); - AccountLayout.encode( - { - state: 0, - mint: stakePoolMock.poolMint, - owner: new PublicKey(0), - amount: new BN(amount), - // address: new PublicKey(0), - // delegate: null, - // delegatedAmount: new BN(0), - // isInitialized: true, - // isFrozen: false, - // isNative: false, - // rentExemptReserve: null, - // closeAuthority: null, - }, - data, - ); - - return >{ - executable: true, - owner: new PublicKey(0), - lamports: amount, - data, - }; -} - -export function mockValidatorList() { - const data = Buffer.alloc(1024); - ValidatorListLayout.encode(validatorListMock, data); - return >{ - executable: true, - owner: new PublicKey(0), - lamports: 0, - data, - }; -} diff --git a/stake-pool/js/tsconfig.json b/stake-pool/js/tsconfig.json deleted file mode 100644 index d8b2a264814..00000000000 --- a/stake-pool/js/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "compilerOptions": { - "module": "esnext", - "target": "es2019", - "baseUrl": "./src", - "outDir": "dist", - "declaration": true, - "declarationDir": "dist", - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "noFallthroughCasesInSwitch": true, - "noImplicitReturns": true - }, - "include": [ - "src/**/*.ts" - ] -} diff --git a/stake-pool/program/Cargo.toml b/stake-pool/program/Cargo.toml deleted file mode 100644 index 77658747abc..00000000000 --- a/stake-pool/program/Cargo.toml +++ /dev/null @@ -1,36 +0,0 @@ -[package] -name = "spl-stake-pool" -version = "0.6.4" -description = "Solana Program Library Stake Pool" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana-program-library" -license = "Apache-2.0" -edition = "2018" - -[features] -no-entrypoint = [] -test-bpf = [] - -[dependencies] -arrayref = "0.3.6" -borsh = "0.9" -mpl-token-metadata = { version = "1.3.1", features = [ "no-entrypoint" ] } -num-derive = "0.3" -num-traits = "0.2" -num_enum = "0.5.4" -serde = "1.0.130" -serde_derive = "1.0.103" -solana-program = "1.10.33" -spl-math = { version = "0.1", path = "../../libraries/math", features = [ "no-entrypoint" ] } -spl-token = { version = "3.3", path = "../../token/program", features = [ "no-entrypoint" ] } -thiserror = "1.0" -bincode = "1.3.1" - -[dev-dependencies] -proptest = "1.0" -solana-program-test = "1.10.33" -solana-sdk = "1.10.33" -solana-vote-program = "1.10.33" - -[lib] -crate-type = ["cdylib", "lib"] diff --git a/stake-pool/program/program-id.md b/stake-pool/program/program-id.md deleted file mode 100644 index 7b5157e41d3..00000000000 --- a/stake-pool/program/program-id.md +++ /dev/null @@ -1 +0,0 @@ -SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy diff --git a/stake-pool/program/proptest-regressions/state.txt b/stake-pool/program/proptest-regressions/state.txt deleted file mode 100644 index 769e8a16890..00000000000 --- a/stake-pool/program/proptest-regressions/state.txt +++ /dev/null @@ -1 +0,0 @@ -cc 41ce1c46341336993e5e5d5aa94c30865e63f9e00d31d397aef88ec79fc312ca diff --git a/stake-pool/program/src/big_vec.rs b/stake-pool/program/src/big_vec.rs deleted file mode 100644 index b98a29ecb9f..00000000000 --- a/stake-pool/program/src/big_vec.rs +++ /dev/null @@ -1,378 +0,0 @@ -//! Big vector type, used with vectors that can't be serde'd - -use { - arrayref::array_ref, - borsh::{BorshDeserialize, BorshSerialize}, - solana_program::{ - program_error::ProgramError, program_memory::sol_memmove, program_pack::Pack, - }, - std::marker::PhantomData, -}; - -/// Contains easy to use utilities for a big vector of Borsh-compatible types, -/// to avoid managing the entire struct on-chain and blow through stack limits. -pub struct BigVec<'data> { - /// Underlying data buffer, pieces of which are serialized - pub data: &'data mut [u8], -} - -const VEC_SIZE_BYTES: usize = 4; - -impl<'data> BigVec<'data> { - /// Get the length of the vector - pub fn len(&self) -> u32 { - let vec_len = array_ref![self.data, 0, VEC_SIZE_BYTES]; - u32::from_le_bytes(*vec_len) - } - - /// Find out if the vector has no contents (as demanded by clippy) - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Retain all elements that match the provided function, discard all others - pub fn retain(&mut self, predicate: fn(&[u8]) -> bool) -> Result<(), ProgramError> { - let mut vec_len = self.len(); - let mut removals_found = 0; - let mut dst_start_index = 0; - - let data_start_index = VEC_SIZE_BYTES; - let data_end_index = - data_start_index.saturating_add((vec_len as usize).saturating_mul(T::LEN)); - for start_index in (data_start_index..data_end_index).step_by(T::LEN) { - let end_index = start_index + T::LEN; - let slice = &self.data[start_index..end_index]; - if !predicate(slice) { - let gap = removals_found * T::LEN; - if removals_found > 0 { - // In case the compute budget is ever bumped up, allowing us - // to use this safe code instead: - // self.data.copy_within(dst_start_index + gap..start_index, dst_start_index); - unsafe { - sol_memmove( - self.data[dst_start_index..start_index - gap].as_mut_ptr(), - self.data[dst_start_index + gap..start_index].as_mut_ptr(), - start_index - gap - dst_start_index, - ); - } - } - dst_start_index = start_index - gap; - removals_found += 1; - vec_len -= 1; - } - } - - // final memmove - if removals_found > 0 { - let gap = removals_found * T::LEN; - // In case the compute budget is ever bumped up, allowing us - // to use this safe code instead: - //self.data.copy_within(dst_start_index + gap..data_end_index, dst_start_index); - unsafe { - sol_memmove( - self.data[dst_start_index..data_end_index - gap].as_mut_ptr(), - self.data[dst_start_index + gap..data_end_index].as_mut_ptr(), - data_end_index - gap - dst_start_index, - ); - } - } - - let mut vec_len_ref = &mut self.data[0..VEC_SIZE_BYTES]; - vec_len.serialize(&mut vec_len_ref)?; - - Ok(()) - } - - /// Extracts a slice of the data types - pub fn deserialize_mut_slice( - &mut self, - skip: usize, - len: usize, - ) -> Result, ProgramError> { - let vec_len = self.len(); - let last_item_index = skip - .checked_add(len) - .ok_or(ProgramError::AccountDataTooSmall)?; - if last_item_index > vec_len as usize { - return Err(ProgramError::AccountDataTooSmall); - } - - let start_index = VEC_SIZE_BYTES.saturating_add(skip.saturating_mul(T::LEN)); - let end_index = start_index.saturating_add(len.saturating_mul(T::LEN)); - let mut deserialized = vec![]; - for slice in self.data[start_index..end_index].chunks_exact_mut(T::LEN) { - deserialized.push(unsafe { &mut *(slice.as_ptr() as *mut T) }); - } - Ok(deserialized) - } - - /// Add new element to the end - pub fn push(&mut self, element: T) -> Result<(), ProgramError> { - let mut vec_len_ref = &mut self.data[0..VEC_SIZE_BYTES]; - let mut vec_len = u32::try_from_slice(vec_len_ref)?; - - let start_index = VEC_SIZE_BYTES + vec_len as usize * T::LEN; - let end_index = start_index + T::LEN; - - vec_len += 1; - vec_len.serialize(&mut vec_len_ref)?; - - if self.data.len() < end_index { - return Err(ProgramError::AccountDataTooSmall); - } - let element_ref = &mut self.data[start_index..start_index + T::LEN]; - element.pack_into_slice(element_ref); - Ok(()) - } - - /// Get an iterator for the type provided - pub fn iter<'vec, T: Pack>(&'vec self) -> Iter<'data, 'vec, T> { - Iter { - len: self.len() as usize, - current: 0, - current_index: VEC_SIZE_BYTES, - inner: self, - phantom: PhantomData, - } - } - - /// Get a mutable iterator for the type provided - pub fn iter_mut<'vec, T: Pack>(&'vec mut self) -> IterMut<'data, 'vec, T> { - IterMut { - len: self.len() as usize, - current: 0, - current_index: VEC_SIZE_BYTES, - inner: self, - phantom: PhantomData, - } - } - - /// Find matching data in the array - pub fn find(&self, data: &[u8], predicate: fn(&[u8], &[u8]) -> bool) -> Option<&T> { - let len = self.len() as usize; - let mut current = 0; - let mut current_index = VEC_SIZE_BYTES; - while current != len { - let end_index = current_index + T::LEN; - let current_slice = &self.data[current_index..end_index]; - if predicate(current_slice, data) { - return Some(unsafe { &*(current_slice.as_ptr() as *const T) }); - } - current_index = end_index; - current += 1; - } - None - } - - /// Find matching data in the array - pub fn find_mut( - &mut self, - data: &[u8], - predicate: fn(&[u8], &[u8]) -> bool, - ) -> Option<&mut T> { - let len = self.len() as usize; - let mut current = 0; - let mut current_index = VEC_SIZE_BYTES; - while current != len { - let end_index = current_index + T::LEN; - let current_slice = &self.data[current_index..end_index]; - if predicate(current_slice, data) { - return Some(unsafe { &mut *(current_slice.as_ptr() as *mut T) }); - } - current_index = end_index; - current += 1; - } - None - } -} - -/// Iterator wrapper over a BigVec -pub struct Iter<'data, 'vec, T> { - len: usize, - current: usize, - current_index: usize, - inner: &'vec BigVec<'data>, - phantom: PhantomData, -} - -impl<'data, 'vec, T: Pack + 'data> Iterator for Iter<'data, 'vec, T> { - type Item = &'data T; - - fn next(&mut self) -> Option { - if self.current == self.len { - None - } else { - let end_index = self.current_index + T::LEN; - let value = Some(unsafe { - &*(self.inner.data[self.current_index..end_index].as_ptr() as *const T) - }); - self.current += 1; - self.current_index = end_index; - value - } - } -} - -/// Iterator wrapper over a BigVec -pub struct IterMut<'data, 'vec, T> { - len: usize, - current: usize, - current_index: usize, - inner: &'vec mut BigVec<'data>, - phantom: PhantomData, -} - -impl<'data, 'vec, T: Pack + 'data> Iterator for IterMut<'data, 'vec, T> { - type Item = &'data mut T; - - fn next(&mut self) -> Option { - if self.current == self.len { - None - } else { - let end_index = self.current_index + T::LEN; - let value = Some(unsafe { - &mut *(self.inner.data[self.current_index..end_index].as_ptr() as *mut T) - }); - self.current += 1; - self.current_index = end_index; - value - } - } -} - -#[cfg(test)] -mod tests { - use { - super::*, - solana_program::{program_memory::sol_memcmp, program_pack::Sealed}, - }; - - #[derive(Debug, PartialEq)] - struct TestStruct { - value: u64, - } - - impl Sealed for TestStruct {} - - impl Pack for TestStruct { - const LEN: usize = 8; - fn pack_into_slice(&self, data: &mut [u8]) { - let mut data = data; - self.value.serialize(&mut data).unwrap(); - } - fn unpack_from_slice(src: &[u8]) -> Result { - Ok(TestStruct { - value: u64::try_from_slice(src).unwrap(), - }) - } - } - - impl TestStruct { - fn new(value: u64) -> Self { - Self { value } - } - } - - fn from_slice<'data, 'other>(data: &'data mut [u8], vec: &'other [u64]) -> BigVec<'data> { - let mut big_vec = BigVec { data }; - for element in vec { - big_vec.push(TestStruct::new(*element)).unwrap(); - } - big_vec - } - - fn check_big_vec_eq(big_vec: &BigVec, slice: &[u64]) { - assert!(big_vec - .iter::() - .map(|x| &x.value) - .zip(slice.iter()) - .all(|(a, b)| a == b)); - } - - #[test] - fn push() { - let mut data = [0u8; 4 + 8 * 3]; - let mut v = BigVec { data: &mut data }; - v.push(TestStruct::new(1)).unwrap(); - check_big_vec_eq(&v, &[1]); - v.push(TestStruct::new(2)).unwrap(); - check_big_vec_eq(&v, &[1, 2]); - v.push(TestStruct::new(3)).unwrap(); - check_big_vec_eq(&v, &[1, 2, 3]); - assert_eq!( - v.push(TestStruct::new(4)).unwrap_err(), - ProgramError::AccountDataTooSmall - ); - } - - #[test] - fn retain() { - fn mod_2_predicate(data: &[u8]) -> bool { - u64::try_from_slice(data).unwrap() % 2 == 0 - } - - let mut data = [0u8; 4 + 8 * 4]; - let mut v = from_slice(&mut data, &[1, 2, 3, 4]); - v.retain::(mod_2_predicate).unwrap(); - check_big_vec_eq(&v, &[2, 4]); - } - - fn find_predicate(a: &[u8], b: &[u8]) -> bool { - if a.len() != b.len() { - false - } else { - sol_memcmp(a, b, a.len()) == 0 - } - } - - #[test] - fn find() { - let mut data = [0u8; 4 + 8 * 4]; - let v = from_slice(&mut data, &[1, 2, 3, 4]); - assert_eq!( - v.find::(&1u64.to_le_bytes(), find_predicate), - Some(&TestStruct::new(1)) - ); - assert_eq!( - v.find::(&4u64.to_le_bytes(), find_predicate), - Some(&TestStruct::new(4)) - ); - assert_eq!( - v.find::(&5u64.to_le_bytes(), find_predicate), - None - ); - } - - #[test] - fn find_mut() { - let mut data = [0u8; 4 + 8 * 4]; - let mut v = from_slice(&mut data, &[1, 2, 3, 4]); - let mut test_struct = v - .find_mut::(&1u64.to_le_bytes(), find_predicate) - .unwrap(); - test_struct.value = 0; - check_big_vec_eq(&v, &[0, 2, 3, 4]); - assert_eq!( - v.find_mut::(&5u64.to_le_bytes(), find_predicate), - None - ); - } - - #[test] - fn deserialize_mut_slice() { - let mut data = [0u8; 4 + 8 * 4]; - let mut v = from_slice(&mut data, &[1, 2, 3, 4]); - let mut slice = v.deserialize_mut_slice::(1, 2).unwrap(); - slice[0].value = 10; - slice[1].value = 11; - check_big_vec_eq(&v, &[1, 10, 11, 4]); - assert_eq!( - v.deserialize_mut_slice::(1, 4).unwrap_err(), - ProgramError::AccountDataTooSmall - ); - assert_eq!( - v.deserialize_mut_slice::(4, 1).unwrap_err(), - ProgramError::AccountDataTooSmall - ); - } -} diff --git a/stake-pool/program/src/entrypoint.rs b/stake-pool/program/src/entrypoint.rs deleted file mode 100644 index a809d7f226e..00000000000 --- a/stake-pool/program/src/entrypoint.rs +++ /dev/null @@ -1,26 +0,0 @@ -//! Program entrypoint - -#![cfg(all(target_os = "solana", not(feature = "no-entrypoint")))] - -use { - crate::{error::StakePoolError, processor::Processor}, - solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, - program_error::PrintProgramError, pubkey::Pubkey, - }, -}; - -entrypoint!(process_instruction); -fn process_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - instruction_data: &[u8], -) -> ProgramResult { - if let Err(error) = Processor::process(program_id, accounts, instruction_data) { - // catch the error so we can print it - error.print::(); - Err(error) - } else { - Ok(()) - } -} diff --git a/stake-pool/program/src/error.rs b/stake-pool/program/src/error.rs deleted file mode 100644 index 908b947d0a3..00000000000 --- a/stake-pool/program/src/error.rs +++ /dev/null @@ -1,148 +0,0 @@ -//! Error types - -use { - num_derive::FromPrimitive, - solana_program::{decode_error::DecodeError, program_error::ProgramError}, - thiserror::Error, -}; - -/// Errors that may be returned by the StakePool program. -#[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] -pub enum StakePoolError { - // 0. - /// The account cannot be initialized because it is already being used. - #[error("AlreadyInUse")] - AlreadyInUse, - /// The program address provided doesn't match the value generated by the program. - #[error("InvalidProgramAddress")] - InvalidProgramAddress, - /// The stake pool state is invalid. - #[error("InvalidState")] - InvalidState, - /// The calculation failed. - #[error("CalculationFailure")] - CalculationFailure, - /// Stake pool fee > 1. - #[error("FeeTooHigh")] - FeeTooHigh, - - // 5. - /// Token account is associated with the wrong mint. - #[error("WrongAccountMint")] - WrongAccountMint, - /// Wrong pool manager account. - #[error("WrongManager")] - WrongManager, - /// Required signature is missing. - #[error("SignatureMissing")] - SignatureMissing, - /// Invalid validator stake list account. - #[error("InvalidValidatorStakeList")] - InvalidValidatorStakeList, - /// Invalid manager fee account. - #[error("InvalidFeeAccount")] - InvalidFeeAccount, - - // 10. - /// Specified pool mint account is wrong. - #[error("WrongPoolMint")] - WrongPoolMint, - /// Stake account is not in the state expected by the program. - #[error("WrongStakeState")] - WrongStakeState, - /// User stake is not active - #[error("UserStakeNotActive")] - UserStakeNotActive, - /// Stake account voting for this validator already exists in the pool. - #[error("ValidatorAlreadyAdded")] - ValidatorAlreadyAdded, - /// Stake account for this validator not found in the pool. - #[error("ValidatorNotFound")] - ValidatorNotFound, - - // 15. - /// Stake account address not properly derived from the validator address. - #[error("InvalidStakeAccountAddress")] - InvalidStakeAccountAddress, - /// Identify validator stake accounts with old balances and update them. - #[error("StakeListOutOfDate")] - StakeListOutOfDate, - /// First update old validator stake account balances and then pool stake balance. - #[error("StakeListAndPoolOutOfDate")] - StakeListAndPoolOutOfDate, - /// Validator stake account is not found in the list storage. - #[error("UnknownValidatorStakeAccount")] - UnknownValidatorStakeAccount, - /// Wrong minting authority set for mint pool account - #[error("WrongMintingAuthority")] - WrongMintingAuthority, - - // 20. - /// The size of the given validator stake list does match the expected amount - #[error("UnexpectedValidatorListAccountSize")] - UnexpectedValidatorListAccountSize, - /// Wrong pool staker account. - #[error("WrongStaker")] - WrongStaker, - /// Pool token supply is not zero on initialization - #[error("NonZeroPoolTokenSupply")] - NonZeroPoolTokenSupply, - /// The lamports in the validator stake account is not equal to the minimum - #[error("StakeLamportsNotEqualToMinimum")] - StakeLamportsNotEqualToMinimum, - /// The provided deposit stake account is not delegated to the preferred deposit vote account - #[error("IncorrectDepositVoteAddress")] - IncorrectDepositVoteAddress, - - // 25. - /// The provided withdraw stake account is not the preferred deposit vote account - #[error("IncorrectWithdrawVoteAddress")] - IncorrectWithdrawVoteAddress, - /// The mint has an invalid freeze authority - #[error("InvalidMintFreezeAuthority")] - InvalidMintFreezeAuthority, - /// Proposed fee increase exceeds stipulated ratio - #[error("FeeIncreaseTooHigh")] - FeeIncreaseTooHigh, - /// Not enough pool tokens provided to withdraw stake with one lamport - #[error("WithdrawalTooSmall")] - WithdrawalTooSmall, - /// Not enough lamports provided for deposit to result in one pool token - #[error("DepositTooSmall")] - DepositTooSmall, - - // 30. - /// Provided stake deposit authority does not match the program's - #[error("InvalidStakeDepositAuthority")] - InvalidStakeDepositAuthority, - /// Provided sol deposit authority does not match the program's - #[error("InvalidSolDepositAuthority")] - InvalidSolDepositAuthority, - /// Provided preferred validator is invalid - #[error("InvalidPreferredValidator")] - InvalidPreferredValidator, - /// Provided validator stake account already has a transient stake account in use - #[error("TransientAccountInUse")] - TransientAccountInUse, - /// Provided sol withdraw authority does not match the program's - #[error("InvalidSolWithdrawAuthority")] - InvalidSolWithdrawAuthority, - - // 35. - /// Too much SOL withdrawn from the stake pool's reserve account - #[error("SolWithdrawalTooLarge")] - SolWithdrawalTooLarge, - /// Provided metadata account does not match metadata account derived for pool mint - #[error("InvalidMetadataAccount")] - InvalidMetadataAccount, -} -impl From for ProgramError { - fn from(e: StakePoolError) -> Self { - ProgramError::Custom(e as u32) - } -} -impl DecodeError for StakePoolError { - fn type_of() -> &'static str { - "Stake Pool Error" - } -} diff --git a/stake-pool/program/src/instruction.rs b/stake-pool/program/src/instruction.rs deleted file mode 100644 index 04353fbbff9..00000000000 --- a/stake-pool/program/src/instruction.rs +++ /dev/null @@ -1,1391 +0,0 @@ -//! Instruction types - -#![allow(clippy::too_many_arguments)] - -use { - crate::{ - find_deposit_authority_program_address, find_stake_program_address, - find_transient_stake_program_address, find_withdraw_authority_program_address, - state::{Fee, FeeType, StakePool, ValidatorList}, - MAX_VALIDATORS_TO_UPDATE, - }, - borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, - mpl_token_metadata::pda::find_metadata_account, - solana_program::{ - instruction::{AccountMeta, Instruction}, - pubkey::Pubkey, - stake, system_program, sysvar, - }, -}; - -/// Defines which validator vote account is set during the -/// `SetPreferredValidator` instruction -#[repr(C)] -#[derive(Clone, Debug, PartialEq, BorshSerialize, BorshDeserialize, BorshSchema)] -pub enum PreferredValidatorType { - /// Set preferred validator for deposits - Deposit, - /// Set preferred validator for withdraws - Withdraw, -} - -/// Defines which authority to update in the `SetFundingAuthority` -/// instruction -#[repr(C)] -#[derive(Clone, Debug, PartialEq, BorshSerialize, BorshDeserialize, BorshSchema)] -pub enum FundingType { - /// Sets the stake deposit authority - StakeDeposit, - /// Sets the SOL deposit authority - SolDeposit, - /// Sets the SOL withdraw authority - SolWithdraw, -} - -/// Instructions supported by the StakePool program. -#[repr(C)] -#[derive(Clone, Debug, PartialEq, BorshSerialize, BorshDeserialize, BorshSchema)] -pub enum StakePoolInstruction { - /// Initializes a new StakePool. - /// - /// 0. `[w]` New StakePool to create. - /// 1. `[s]` Manager - /// 2. `[]` Staker - /// 3. `[]` Stake pool withdraw authority - /// 4. `[w]` Uninitialized validator stake list storage account - /// 5. `[]` Reserve stake account must be initialized, have zero balance, - /// and staker / withdrawer authority set to pool withdraw authority. - /// 6. `[]` Pool token mint. Must have zero supply, owned by withdraw authority. - /// 7. `[]` Pool account to deposit the generated fee for manager. - /// 8. `[]` Token program id - /// 9. `[]` (Optional) Deposit authority that must sign all deposits. - /// Defaults to the program address generated using - /// `find_deposit_authority_program_address`, making deposits permissionless. - Initialize { - /// Fee assessed as percentage of perceived rewards - #[allow(dead_code)] // but it's not - fee: Fee, - /// Fee charged per withdrawal as percentage of withdrawal - #[allow(dead_code)] // but it's not - withdrawal_fee: Fee, - /// Fee charged per deposit as percentage of deposit - #[allow(dead_code)] // but it's not - deposit_fee: Fee, - /// Percentage [0-100] of deposit_fee that goes to referrer - #[allow(dead_code)] // but it's not - referral_fee: u8, - /// Maximum expected number of validators - #[allow(dead_code)] // but it's not - max_validators: u32, - }, - - /// (Staker only) Adds stake account delegated to validator to the pool's - /// list of managed validators. - /// - /// The stake account will have the rent-exempt amount plus - /// `crate::MINIMUM_ACTIVE_STAKE` (currently 0.001 SOL). - /// - /// 0. `[w]` Stake pool - /// 1. `[s]` Staker - /// 2. `[ws]` Funding account (must be a system account) - /// 3. `[]` Stake pool withdraw authority - /// 4. `[w]` Validator stake list storage account - /// 5. `[w]` Stake account to add to the pool - /// 6. `[]` Validator this stake account will be delegated to - /// 7. `[]` Rent sysvar - /// 8. `[]` Clock sysvar - /// 9. '[]' Stake history sysvar - /// 10. '[]' Stake config sysvar - /// 11. `[]` System program - /// 12. `[]` Stake program - AddValidatorToPool, - - /// (Staker only) Removes validator from the pool - /// - /// Only succeeds if the validator stake account has the minimum of - /// `crate::MINIMUM_ACTIVE_STAKE` (currently 0.001 SOL) plus the rent-exempt - /// amount. - /// - /// 0. `[w]` Stake pool - /// 1. `[s]` Staker - /// 2. `[]` Stake pool withdraw authority - /// 3. `[]` New withdraw/staker authority to set in the stake account - /// 4. `[w]` Validator stake list storage account - /// 5. `[w]` Stake account to remove from the pool - /// 6. `[]` Transient stake account, to check that that we're not trying to activate - /// 7. `[w]` Destination stake account, to receive the minimum SOL from the validator stake account - /// 8. `[]` Sysvar clock - /// 9. `[]` Stake program id, - RemoveValidatorFromPool, - - /// (Staker only) Decrease active stake on a validator, eventually moving it to the reserve - /// - /// Internally, this instruction splits a validator stake account into its - /// corresponding transient stake account and deactivates it. - /// - /// In order to rebalance the pool without taking custody, the staker needs - /// a way of reducing the stake on a stake account. This instruction splits - /// some amount of stake, up to the total activated stake, from the canonical - /// validator stake account, into its "transient" stake account. - /// - /// The instruction only succeeds if the transient stake account does not - /// exist. The amount of lamports to move must be at least rent-exemption - /// plus 1 lamport. - /// - /// 0. `[]` Stake pool - /// 1. `[s]` Stake pool staker - /// 2. `[]` Stake pool withdraw authority - /// 3. `[w]` Validator list - /// 4. `[w]` Canonical stake account to split from - /// 5. `[w]` Transient stake account to receive split - /// 6. `[]` Clock sysvar - /// 7. `[]` Rent sysvar - /// 8. `[]` System program - /// 9. `[]` Stake program - DecreaseValidatorStake { - /// amount of lamports to split into the transient stake account - #[allow(dead_code)] // but it's not - lamports: u64, - /// seed used to create transient stake account - #[allow(dead_code)] // but it's not - transient_stake_seed: u64, - }, - - /// (Staker only) Increase stake on a validator from the reserve account - /// - /// Internally, this instruction splits reserve stake into a transient stake - /// account and delegate to the appropriate validator. `UpdateValidatorListBalance` - /// will do the work of merging once it's ready. - /// - /// This instruction only succeeds if the transient stake account does not exist. - /// The minimum amount to move is rent-exemption plus `crate::MINIMUM_ACTIVE_STAKE` - /// (currently 0.001 SOL) in order to avoid issues on credits observed when - /// merging active stakes later. - /// - /// 0. `[]` Stake pool - /// 1. `[s]` Stake pool staker - /// 2. `[]` Stake pool withdraw authority - /// 3. `[w]` Validator list - /// 4. `[w]` Stake pool reserve stake - /// 5. `[w]` Transient stake account - /// 6. `[]` Validator stake account - /// 7. `[]` Validator vote account to delegate to - /// 8. '[]' Clock sysvar - /// 9. '[]' Rent sysvar - /// 10. `[]` Stake History sysvar - /// 11. `[]` Stake Config sysvar - /// 12. `[]` System program - /// 13. `[]` Stake program - /// userdata: amount of lamports to increase on the given validator. - /// The actual amount split into the transient stake account is: - /// `lamports + stake_rent_exemption` - /// The rent-exemption of the stake account is withdrawn back to the reserve - /// after it is merged. - IncreaseValidatorStake { - /// amount of lamports to increase on the given validator - #[allow(dead_code)] // but it's not - lamports: u64, - /// seed used to create transient stake account - #[allow(dead_code)] // but it's not - transient_stake_seed: u64, - }, - - /// (Staker only) Set the preferred deposit or withdraw stake account for the - /// stake pool - /// - /// In order to avoid users abusing the stake pool as a free conversion - /// between SOL staked on different validators, the staker can force all - /// deposits and/or withdraws to go to one chosen account, or unset that account. - /// - /// 0. `[w]` Stake pool - /// 1. `[s]` Stake pool staker - /// 2. `[]` Validator list - /// - /// Fails if the validator is not part of the stake pool. - SetPreferredValidator { - /// Affected operation (deposit or withdraw) - #[allow(dead_code)] // but it's not - validator_type: PreferredValidatorType, - /// Validator vote account that deposits or withdraws must go through, - /// unset with None - #[allow(dead_code)] // but it's not - validator_vote_address: Option, - }, - - /// Updates balances of validator and transient stake accounts in the pool - /// - /// While going through the pairs of validator and transient stake accounts, - /// if the transient stake is inactive, it is merged into the reserve stake - /// account. If the transient stake is active and has matching credits - /// observed, it is merged into the canonical validator stake account. In - /// all other states, nothing is done, and the balance is simply added to - /// the canonical stake account balance. - /// - /// 0. `[]` Stake pool - /// 1. `[]` Stake pool withdraw authority - /// 2. `[w]` Validator stake list storage account - /// 3. `[w]` Reserve stake account - /// 4. `[]` Sysvar clock - /// 5. `[]` Sysvar stake history - /// 6. `[]` Stake program - /// 7. ..7+N ` [] N pairs of validator and transient stake accounts - UpdateValidatorListBalance { - /// Index to start updating on the validator list - #[allow(dead_code)] // but it's not - start_index: u32, - /// If true, don't try merging transient stake accounts into the reserve or - /// validator stake account. Useful for testing or if a particular stake - /// account is in a bad state, but we still want to update - #[allow(dead_code)] // but it's not - no_merge: bool, - }, - - /// Updates total pool balance based on balances in the reserve and validator list - /// - /// 0. `[w]` Stake pool - /// 1. `[]` Stake pool withdraw authority - /// 2. `[w]` Validator stake list storage account - /// 3. `[]` Reserve stake account - /// 4. `[w]` Account to receive pool fee tokens - /// 5. `[w]` Pool mint account - /// 6. `[]` Pool token program - UpdateStakePoolBalance, - - /// Cleans up validator stake account entries marked as `ReadyForRemoval` - /// - /// 0. `[]` Stake pool - /// 1. `[w]` Validator stake list storage account - CleanupRemovedValidatorEntries, - - /// Deposit some stake into the pool. The output is a "pool" token representing ownership - /// into the pool. Inputs are converted to the current ratio. - /// - /// 0. `[w]` Stake pool - /// 1. `[w]` Validator stake list storage account - /// 2. `[s]/[]` Stake pool deposit authority - /// 3. `[]` Stake pool withdraw authority - /// 4. `[w]` Stake account to join the pool (withdraw authority for the stake account should be first set to the stake pool deposit authority) - /// 5. `[w]` Validator stake account for the stake account to be merged with - /// 6. `[w]` Reserve stake account, to withdraw rent exempt reserve - /// 7. `[w]` User account to receive pool tokens - /// 8. `[w]` Account to receive pool fee tokens - /// 9. `[w]` Account to receive a portion of pool fee tokens as referral fees - /// 10. `[w]` Pool token mint account - /// 11. '[]' Sysvar clock account - /// 12. '[]' Sysvar stake history account - /// 13. `[]` Pool token program id, - /// 14. `[]` Stake program id, - DepositStake, - - /// Withdraw the token from the pool at the current ratio. - /// - /// Succeeds if the stake account has enough SOL to cover the desired amount - /// of pool tokens, and if the withdrawal keeps the total staked amount - /// above the minimum of rent-exempt amount + 0.001 SOL. - /// - /// When allowing withdrawals, the order of priority goes: - /// - /// * preferred withdraw validator stake account (if set) - /// * validator stake accounts - /// * transient stake accounts - /// * reserve stake account - /// - /// A user can freely withdraw from a validator stake account, and if they - /// are all at the minimum, then they can withdraw from transient stake - /// accounts, and if they are all at minimum, then they can withdraw from - /// the reserve. - /// - /// 0. `[w]` Stake pool - /// 1. `[w]` Validator stake list storage account - /// 2. `[]` Stake pool withdraw authority - /// 3. `[w]` Validator or reserve stake account to split - /// 4. `[w]` Unitialized stake account to receive withdrawal - /// 5. `[]` User account to set as a new withdraw authority - /// 6. `[s]` User transfer authority, for pool token account - /// 7. `[w]` User account with pool tokens to burn from - /// 8. `[w]` Account to receive pool fee tokens - /// 9. `[w]` Pool token mint account - /// 10. `[]` Sysvar clock account (required) - /// 11. `[]` Pool token program id - /// 12. `[]` Stake program id, - /// userdata: amount of pool tokens to withdraw - WithdrawStake(u64), - - /// (Manager only) Update manager - /// - /// 0. `[w]` StakePool - /// 1. `[s]` Manager - /// 2. `[s]` New manager - /// 3. `[]` New manager fee account - SetManager, - - /// (Manager only) Update fee - /// - /// 0. `[w]` StakePool - /// 1. `[s]` Manager - SetFee { - /// Type of fee to update and value to update it to - #[allow(dead_code)] // but it's not - fee: FeeType, - }, - - /// (Manager or staker only) Update staker - /// - /// 0. `[w]` StakePool - /// 1. `[s]` Manager or current staker - /// 2. '[]` New staker pubkey - SetStaker, - - /// Deposit SOL directly into the pool's reserve account. The output is a "pool" token - /// representing ownership into the pool. Inputs are converted to the current ratio. - /// - /// 0. `[w]` Stake pool - /// 1. `[]` Stake pool withdraw authority - /// 2. `[w]` Reserve stake account, to deposit SOL - /// 3. `[s]` Account providing the lamports to be deposited into the pool - /// 4. `[w]` User account to receive pool tokens - /// 5. `[w]` Account to receive fee tokens - /// 6. `[w]` Account to receive a portion of fee as referral fees - /// 7. `[w]` Pool token mint account - /// 8. `[]` System program account - /// 9. `[]` Token program id - /// 10. `[s]` (Optional) Stake pool sol deposit authority. - DepositSol(u64), - - /// (Manager only) Update SOL deposit authority - /// - /// 0. `[w]` StakePool - /// 1. `[s]` Manager - /// 2. '[]` New authority pubkey or none - SetFundingAuthority(FundingType), - - /// Withdraw SOL directly from the pool's reserve account. Fails if the - /// reserve does not have enough SOL. - /// - /// 0. `[w]` Stake pool - /// 1. `[]` Stake pool withdraw authority - /// 2. `[s]` User transfer authority, for pool token account - /// 3. `[w]` User account to burn pool tokens - /// 4. `[w]` Reserve stake account, to withdraw SOL - /// 5. `[w]` Account receiving the lamports from the reserve, must be a system account - /// 6. `[w]` Account to receive pool fee tokens - /// 7. `[w]` Pool token mint account - /// 8. '[]' Clock sysvar - /// 9. '[]' Stake history sysvar - /// 10. `[]` Stake program account - /// 11. `[]` Token program id - /// 12. `[s]` (Optional) Stake pool sol withdraw authority - WithdrawSol(u64), - - /// Create token metadata for the stake-pool token in the - /// metaplex-token program - /// 0. `[]` Stake pool - /// 1. `[s]` Manager - /// 2. `[]` Stake pool withdraw authority - /// 3. `[]` Pool token mint account - /// 4. `[s, w]` Payer for creation of token metadata account - /// 5. `[w]` Token metadata account - /// 6. `[]` Metadata program id - /// 7. `[]` System program id - /// 8. `[]` Rent sysvar - CreateTokenMetadata { - #[allow(dead_code)] - /// Token name - name: String, - #[allow(dead_code)] - /// Token symbol e.g. stkSOL - symbol: String, - /// URI of the uploaded metadata of the spl-token - #[allow(dead_code)] - uri: String, - }, - /// Update token metadata for the stake-pool token in the - /// metaplex-token program - /// - /// 0. `[]` Stake pool - /// 1. `[s]` Manager - /// 2. `[]` Stake pool withdraw authority - /// 3. `[w]` Token metadata account - /// 4. `[]` Metadata program id - UpdateTokenMetadata { - #[allow(dead_code)] - /// Token name - name: String, - #[allow(dead_code)] - /// Token symbol e.g. stkSOL - symbol: String, - /// URI of the uploaded metadata of the spl-token - #[allow(dead_code)] - uri: String, - }, -} - -/// Creates an 'initialize' instruction. -pub fn initialize( - program_id: &Pubkey, - stake_pool: &Pubkey, - manager: &Pubkey, - staker: &Pubkey, - stake_pool_withdraw_authority: &Pubkey, - validator_list: &Pubkey, - reserve_stake: &Pubkey, - pool_mint: &Pubkey, - manager_pool_account: &Pubkey, - token_program_id: &Pubkey, - deposit_authority: Option, - fee: Fee, - withdrawal_fee: Fee, - deposit_fee: Fee, - referral_fee: u8, - max_validators: u32, -) -> Instruction { - let init_data = StakePoolInstruction::Initialize { - fee, - withdrawal_fee, - deposit_fee, - referral_fee, - max_validators, - }; - let data = init_data.try_to_vec().unwrap(); - let mut accounts = vec![ - AccountMeta::new(*stake_pool, false), - AccountMeta::new_readonly(*manager, true), - AccountMeta::new_readonly(*staker, false), - AccountMeta::new_readonly(*stake_pool_withdraw_authority, false), - AccountMeta::new(*validator_list, false), - AccountMeta::new_readonly(*reserve_stake, false), - AccountMeta::new(*pool_mint, false), - AccountMeta::new(*manager_pool_account, false), - AccountMeta::new_readonly(*token_program_id, false), - ]; - if let Some(deposit_authority) = deposit_authority { - accounts.push(AccountMeta::new_readonly(deposit_authority, true)); - } - Instruction { - program_id: *program_id, - accounts, - data, - } -} - -/// Creates `AddValidatorToPool` instruction (add new validator stake account to the pool) -pub fn add_validator_to_pool( - program_id: &Pubkey, - stake_pool: &Pubkey, - staker: &Pubkey, - funder: &Pubkey, - stake_pool_withdraw: &Pubkey, - validator_list: &Pubkey, - stake: &Pubkey, - validator: &Pubkey, -) -> Instruction { - let accounts = vec![ - AccountMeta::new(*stake_pool, false), - AccountMeta::new_readonly(*staker, true), - AccountMeta::new(*funder, true), - AccountMeta::new_readonly(*stake_pool_withdraw, false), - AccountMeta::new(*validator_list, false), - AccountMeta::new(*stake, false), - AccountMeta::new_readonly(*validator, false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - AccountMeta::new_readonly(sysvar::stake_history::id(), false), - AccountMeta::new_readonly(stake::config::id(), false), - AccountMeta::new_readonly(system_program::id(), false), - AccountMeta::new_readonly(stake::program::id(), false), - ]; - Instruction { - program_id: *program_id, - accounts, - data: StakePoolInstruction::AddValidatorToPool - .try_to_vec() - .unwrap(), - } -} - -/// Creates `RemoveValidatorFromPool` instruction (remove validator stake account from the pool) -pub fn remove_validator_from_pool( - program_id: &Pubkey, - stake_pool: &Pubkey, - staker: &Pubkey, - stake_pool_withdraw: &Pubkey, - new_stake_authority: &Pubkey, - validator_list: &Pubkey, - stake_account: &Pubkey, - transient_stake_account: &Pubkey, - destination_stake_account: &Pubkey, -) -> Instruction { - let accounts = vec![ - AccountMeta::new(*stake_pool, false), - AccountMeta::new_readonly(*staker, true), - AccountMeta::new_readonly(*stake_pool_withdraw, false), - AccountMeta::new_readonly(*new_stake_authority, false), - AccountMeta::new(*validator_list, false), - AccountMeta::new(*stake_account, false), - AccountMeta::new_readonly(*transient_stake_account, false), - AccountMeta::new(*destination_stake_account, false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - AccountMeta::new_readonly(stake::program::id(), false), - ]; - Instruction { - program_id: *program_id, - accounts, - data: StakePoolInstruction::RemoveValidatorFromPool - .try_to_vec() - .unwrap(), - } -} - -/// Creates `DecreaseValidatorStake` instruction (rebalance from validator account to -/// transient account) -pub fn decrease_validator_stake( - program_id: &Pubkey, - stake_pool: &Pubkey, - staker: &Pubkey, - stake_pool_withdraw_authority: &Pubkey, - validator_list: &Pubkey, - validator_stake: &Pubkey, - transient_stake: &Pubkey, - lamports: u64, - transient_stake_seed: u64, -) -> Instruction { - let accounts = vec![ - AccountMeta::new_readonly(*stake_pool, false), - AccountMeta::new_readonly(*staker, true), - AccountMeta::new_readonly(*stake_pool_withdraw_authority, false), - AccountMeta::new(*validator_list, false), - AccountMeta::new(*validator_stake, false), - AccountMeta::new(*transient_stake, false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - AccountMeta::new_readonly(system_program::id(), false), - AccountMeta::new_readonly(stake::program::id(), false), - ]; - Instruction { - program_id: *program_id, - accounts, - data: StakePoolInstruction::DecreaseValidatorStake { - lamports, - transient_stake_seed, - } - .try_to_vec() - .unwrap(), - } -} - -/// Creates `IncreaseValidatorStake` instruction (rebalance from reserve account to -/// transient account) -pub fn increase_validator_stake( - program_id: &Pubkey, - stake_pool: &Pubkey, - staker: &Pubkey, - stake_pool_withdraw_authority: &Pubkey, - validator_list: &Pubkey, - reserve_stake: &Pubkey, - transient_stake: &Pubkey, - validator_stake: &Pubkey, - validator: &Pubkey, - lamports: u64, - transient_stake_seed: u64, -) -> Instruction { - let accounts = vec![ - AccountMeta::new_readonly(*stake_pool, false), - AccountMeta::new_readonly(*staker, true), - AccountMeta::new_readonly(*stake_pool_withdraw_authority, false), - AccountMeta::new(*validator_list, false), - AccountMeta::new(*reserve_stake, false), - AccountMeta::new(*transient_stake, false), - AccountMeta::new_readonly(*validator_stake, false), - AccountMeta::new_readonly(*validator, false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - AccountMeta::new_readonly(sysvar::stake_history::id(), false), - AccountMeta::new_readonly(stake::config::id(), false), - AccountMeta::new_readonly(system_program::id(), false), - AccountMeta::new_readonly(stake::program::id(), false), - ]; - Instruction { - program_id: *program_id, - accounts, - data: StakePoolInstruction::IncreaseValidatorStake { - lamports, - transient_stake_seed, - } - .try_to_vec() - .unwrap(), - } -} - -/// Creates `SetPreferredDepositValidator` instruction -pub fn set_preferred_validator( - program_id: &Pubkey, - stake_pool_address: &Pubkey, - staker: &Pubkey, - validator_list_address: &Pubkey, - validator_type: PreferredValidatorType, - validator_vote_address: Option, -) -> Instruction { - Instruction { - program_id: *program_id, - accounts: vec![ - AccountMeta::new(*stake_pool_address, false), - AccountMeta::new_readonly(*staker, true), - AccountMeta::new_readonly(*validator_list_address, false), - ], - data: StakePoolInstruction::SetPreferredValidator { - validator_type, - validator_vote_address, - } - .try_to_vec() - .unwrap(), - } -} - -/// Create an `AddValidatorToPool` instruction given an existing stake pool and -/// vote account -pub fn add_validator_to_pool_with_vote( - program_id: &Pubkey, - stake_pool: &StakePool, - stake_pool_address: &Pubkey, - funder: &Pubkey, - vote_account_address: &Pubkey, -) -> Instruction { - let pool_withdraw_authority = - find_withdraw_authority_program_address(program_id, stake_pool_address).0; - let (stake_account_address, _) = - find_stake_program_address(program_id, vote_account_address, stake_pool_address); - add_validator_to_pool( - program_id, - stake_pool_address, - &stake_pool.staker, - funder, - &pool_withdraw_authority, - &stake_pool.validator_list, - &stake_account_address, - vote_account_address, - ) -} - -/// Create an `RemoveValidatorFromPool` instruction given an existing stake pool and -/// vote account -pub fn remove_validator_from_pool_with_vote( - program_id: &Pubkey, - stake_pool: &StakePool, - stake_pool_address: &Pubkey, - vote_account_address: &Pubkey, - new_stake_account_authority: &Pubkey, - transient_stake_seed: u64, - destination_stake_address: &Pubkey, -) -> Instruction { - let pool_withdraw_authority = - find_withdraw_authority_program_address(program_id, stake_pool_address).0; - let (stake_account_address, _) = - find_stake_program_address(program_id, vote_account_address, stake_pool_address); - let (transient_stake_account, _) = find_transient_stake_program_address( - program_id, - vote_account_address, - stake_pool_address, - transient_stake_seed, - ); - remove_validator_from_pool( - program_id, - stake_pool_address, - &stake_pool.staker, - &pool_withdraw_authority, - new_stake_account_authority, - &stake_pool.validator_list, - &stake_account_address, - &transient_stake_account, - destination_stake_address, - ) -} - -/// Create an `IncreaseValidatorStake` instruction given an existing stake pool and -/// vote account -pub fn increase_validator_stake_with_vote( - program_id: &Pubkey, - stake_pool: &StakePool, - stake_pool_address: &Pubkey, - vote_account_address: &Pubkey, - lamports: u64, - transient_stake_seed: u64, -) -> Instruction { - let pool_withdraw_authority = - find_withdraw_authority_program_address(program_id, stake_pool_address).0; - let (transient_stake_address, _) = find_transient_stake_program_address( - program_id, - vote_account_address, - stake_pool_address, - transient_stake_seed, - ); - let (validator_stake_address, _) = - find_stake_program_address(program_id, vote_account_address, stake_pool_address); - - increase_validator_stake( - program_id, - stake_pool_address, - &stake_pool.staker, - &pool_withdraw_authority, - &stake_pool.validator_list, - &stake_pool.reserve_stake, - &transient_stake_address, - &validator_stake_address, - vote_account_address, - lamports, - transient_stake_seed, - ) -} - -/// Create a `DecreaseValidatorStake` instruction given an existing stake pool and -/// vote account -pub fn decrease_validator_stake_with_vote( - program_id: &Pubkey, - stake_pool: &StakePool, - stake_pool_address: &Pubkey, - vote_account_address: &Pubkey, - lamports: u64, - transient_stake_seed: u64, -) -> Instruction { - let pool_withdraw_authority = - find_withdraw_authority_program_address(program_id, stake_pool_address).0; - let (validator_stake_address, _) = - find_stake_program_address(program_id, vote_account_address, stake_pool_address); - let (transient_stake_address, _) = find_transient_stake_program_address( - program_id, - vote_account_address, - stake_pool_address, - transient_stake_seed, - ); - decrease_validator_stake( - program_id, - stake_pool_address, - &stake_pool.staker, - &pool_withdraw_authority, - &stake_pool.validator_list, - &validator_stake_address, - &transient_stake_address, - lamports, - transient_stake_seed, - ) -} - -/// Creates `UpdateValidatorListBalance` instruction (update validator stake account balances) -pub fn update_validator_list_balance( - program_id: &Pubkey, - stake_pool: &Pubkey, - stake_pool_withdraw_authority: &Pubkey, - validator_list_address: &Pubkey, - reserve_stake: &Pubkey, - validator_list: &ValidatorList, - validator_vote_accounts: &[Pubkey], - start_index: u32, - no_merge: bool, -) -> Instruction { - let mut accounts = vec![ - AccountMeta::new_readonly(*stake_pool, false), - AccountMeta::new_readonly(*stake_pool_withdraw_authority, false), - AccountMeta::new(*validator_list_address, false), - AccountMeta::new(*reserve_stake, false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - AccountMeta::new_readonly(sysvar::stake_history::id(), false), - AccountMeta::new_readonly(stake::program::id(), false), - ]; - accounts.append( - &mut validator_vote_accounts - .iter() - .flat_map(|vote_account_address| { - let validator_stake_info = validator_list.find(vote_account_address); - if let Some(validator_stake_info) = validator_stake_info { - let (validator_stake_account, _) = - find_stake_program_address(program_id, vote_account_address, stake_pool); - let (transient_stake_account, _) = find_transient_stake_program_address( - program_id, - vote_account_address, - stake_pool, - validator_stake_info.transient_seed_suffix_start, - ); - vec![ - AccountMeta::new(validator_stake_account, false), - AccountMeta::new(transient_stake_account, false), - ] - } else { - vec![] - } - }) - .collect::>(), - ); - Instruction { - program_id: *program_id, - accounts, - data: StakePoolInstruction::UpdateValidatorListBalance { - start_index, - no_merge, - } - .try_to_vec() - .unwrap(), - } -} - -/// Creates `UpdateStakePoolBalance` instruction (pool balance from the stake account list balances) -pub fn update_stake_pool_balance( - program_id: &Pubkey, - stake_pool: &Pubkey, - withdraw_authority: &Pubkey, - validator_list_storage: &Pubkey, - reserve_stake: &Pubkey, - manager_fee_account: &Pubkey, - stake_pool_mint: &Pubkey, - token_program_id: &Pubkey, -) -> Instruction { - let accounts = vec![ - AccountMeta::new(*stake_pool, false), - AccountMeta::new_readonly(*withdraw_authority, false), - AccountMeta::new(*validator_list_storage, false), - AccountMeta::new_readonly(*reserve_stake, false), - AccountMeta::new(*manager_fee_account, false), - AccountMeta::new(*stake_pool_mint, false), - AccountMeta::new_readonly(*token_program_id, false), - ]; - Instruction { - program_id: *program_id, - accounts, - data: StakePoolInstruction::UpdateStakePoolBalance - .try_to_vec() - .unwrap(), - } -} - -/// Creates `CleanupRemovedValidatorEntries` instruction (removes entries from the validator list) -pub fn cleanup_removed_validator_entries( - program_id: &Pubkey, - stake_pool: &Pubkey, - validator_list_storage: &Pubkey, -) -> Instruction { - let accounts = vec![ - AccountMeta::new_readonly(*stake_pool, false), - AccountMeta::new(*validator_list_storage, false), - ]; - Instruction { - program_id: *program_id, - accounts, - data: StakePoolInstruction::CleanupRemovedValidatorEntries - .try_to_vec() - .unwrap(), - } -} - -/// Creates all `UpdateValidatorListBalance` and `UpdateStakePoolBalance` -/// instructions for fully updating a stake pool each epoch -pub fn update_stake_pool( - program_id: &Pubkey, - stake_pool: &StakePool, - validator_list: &ValidatorList, - stake_pool_address: &Pubkey, - no_merge: bool, -) -> (Vec, Vec) { - let vote_accounts: Vec = validator_list - .validators - .iter() - .map(|item| item.vote_account_address) - .collect(); - - let (withdraw_authority, _) = - find_withdraw_authority_program_address(program_id, stake_pool_address); - - let mut update_list_instructions: Vec = vec![]; - let mut start_index = 0; - for accounts_chunk in vote_accounts.chunks(MAX_VALIDATORS_TO_UPDATE) { - update_list_instructions.push(update_validator_list_balance( - program_id, - stake_pool_address, - &withdraw_authority, - &stake_pool.validator_list, - &stake_pool.reserve_stake, - validator_list, - accounts_chunk, - start_index, - no_merge, - )); - start_index += MAX_VALIDATORS_TO_UPDATE as u32; - } - - let final_instructions = vec![ - update_stake_pool_balance( - program_id, - stake_pool_address, - &withdraw_authority, - &stake_pool.validator_list, - &stake_pool.reserve_stake, - &stake_pool.manager_fee_account, - &stake_pool.pool_mint, - &stake_pool.token_program_id, - ), - cleanup_removed_validator_entries( - program_id, - stake_pool_address, - &stake_pool.validator_list, - ), - ]; - (update_list_instructions, final_instructions) -} - -/// Creates instructions required to deposit into a stake pool, given a stake -/// account owned by the user. -pub fn deposit_stake( - program_id: &Pubkey, - stake_pool: &Pubkey, - validator_list_storage: &Pubkey, - stake_pool_withdraw_authority: &Pubkey, - deposit_stake_address: &Pubkey, - deposit_stake_withdraw_authority: &Pubkey, - validator_stake_account: &Pubkey, - reserve_stake_account: &Pubkey, - pool_tokens_to: &Pubkey, - manager_fee_account: &Pubkey, - referrer_pool_tokens_account: &Pubkey, - pool_mint: &Pubkey, - token_program_id: &Pubkey, -) -> Vec { - let stake_pool_deposit_authority = - find_deposit_authority_program_address(program_id, stake_pool).0; - let accounts = vec![ - AccountMeta::new(*stake_pool, false), - AccountMeta::new(*validator_list_storage, false), - AccountMeta::new_readonly(stake_pool_deposit_authority, false), - AccountMeta::new_readonly(*stake_pool_withdraw_authority, false), - AccountMeta::new(*deposit_stake_address, false), - AccountMeta::new(*validator_stake_account, false), - AccountMeta::new(*reserve_stake_account, false), - AccountMeta::new(*pool_tokens_to, false), - AccountMeta::new(*manager_fee_account, false), - AccountMeta::new(*referrer_pool_tokens_account, false), - AccountMeta::new(*pool_mint, false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - AccountMeta::new_readonly(sysvar::stake_history::id(), false), - AccountMeta::new_readonly(*token_program_id, false), - AccountMeta::new_readonly(stake::program::id(), false), - ]; - vec![ - stake::instruction::authorize( - deposit_stake_address, - deposit_stake_withdraw_authority, - &stake_pool_deposit_authority, - stake::state::StakeAuthorize::Staker, - None, - ), - stake::instruction::authorize( - deposit_stake_address, - deposit_stake_withdraw_authority, - &stake_pool_deposit_authority, - stake::state::StakeAuthorize::Withdrawer, - None, - ), - Instruction { - program_id: *program_id, - accounts, - data: StakePoolInstruction::DepositStake.try_to_vec().unwrap(), - }, - ] -} - -/// Creates instructions required to deposit into a stake pool, given a stake -/// account owned by the user. The difference with `deposit()` is that a deposit -/// authority must sign this instruction, which is required for private pools. -pub fn deposit_stake_with_authority( - program_id: &Pubkey, - stake_pool: &Pubkey, - validator_list_storage: &Pubkey, - stake_pool_deposit_authority: &Pubkey, - stake_pool_withdraw_authority: &Pubkey, - deposit_stake_address: &Pubkey, - deposit_stake_withdraw_authority: &Pubkey, - validator_stake_account: &Pubkey, - reserve_stake_account: &Pubkey, - pool_tokens_to: &Pubkey, - manager_fee_account: &Pubkey, - referrer_pool_tokens_account: &Pubkey, - pool_mint: &Pubkey, - token_program_id: &Pubkey, -) -> Vec { - let accounts = vec![ - AccountMeta::new(*stake_pool, false), - AccountMeta::new(*validator_list_storage, false), - AccountMeta::new_readonly(*stake_pool_deposit_authority, true), - AccountMeta::new_readonly(*stake_pool_withdraw_authority, false), - AccountMeta::new(*deposit_stake_address, false), - AccountMeta::new(*validator_stake_account, false), - AccountMeta::new(*reserve_stake_account, false), - AccountMeta::new(*pool_tokens_to, false), - AccountMeta::new(*manager_fee_account, false), - AccountMeta::new(*referrer_pool_tokens_account, false), - AccountMeta::new(*pool_mint, false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - AccountMeta::new_readonly(sysvar::stake_history::id(), false), - AccountMeta::new_readonly(*token_program_id, false), - AccountMeta::new_readonly(stake::program::id(), false), - ]; - vec![ - stake::instruction::authorize( - deposit_stake_address, - deposit_stake_withdraw_authority, - stake_pool_deposit_authority, - stake::state::StakeAuthorize::Staker, - None, - ), - stake::instruction::authorize( - deposit_stake_address, - deposit_stake_withdraw_authority, - stake_pool_deposit_authority, - stake::state::StakeAuthorize::Withdrawer, - None, - ), - Instruction { - program_id: *program_id, - accounts, - data: StakePoolInstruction::DepositStake.try_to_vec().unwrap(), - }, - ] -} - -/// Creates instructions required to deposit SOL directly into a stake pool. -pub fn deposit_sol( - program_id: &Pubkey, - stake_pool: &Pubkey, - stake_pool_withdraw_authority: &Pubkey, - reserve_stake_account: &Pubkey, - lamports_from: &Pubkey, - pool_tokens_to: &Pubkey, - manager_fee_account: &Pubkey, - referrer_pool_tokens_account: &Pubkey, - pool_mint: &Pubkey, - token_program_id: &Pubkey, - amount: u64, -) -> Instruction { - let accounts = vec![ - AccountMeta::new(*stake_pool, false), - AccountMeta::new_readonly(*stake_pool_withdraw_authority, false), - AccountMeta::new(*reserve_stake_account, false), - AccountMeta::new(*lamports_from, true), - AccountMeta::new(*pool_tokens_to, false), - AccountMeta::new(*manager_fee_account, false), - AccountMeta::new(*referrer_pool_tokens_account, false), - AccountMeta::new(*pool_mint, false), - AccountMeta::new_readonly(system_program::id(), false), - AccountMeta::new_readonly(*token_program_id, false), - ]; - Instruction { - program_id: *program_id, - accounts, - data: StakePoolInstruction::DepositSol(amount) - .try_to_vec() - .unwrap(), - } -} - -/// Creates instruction required to deposit SOL directly into a stake pool. -/// The difference with `deposit_sol()` is that a deposit -/// authority must sign this instruction. -pub fn deposit_sol_with_authority( - program_id: &Pubkey, - stake_pool: &Pubkey, - sol_deposit_authority: &Pubkey, - stake_pool_withdraw_authority: &Pubkey, - reserve_stake_account: &Pubkey, - lamports_from: &Pubkey, - pool_tokens_to: &Pubkey, - manager_fee_account: &Pubkey, - referrer_pool_tokens_account: &Pubkey, - pool_mint: &Pubkey, - token_program_id: &Pubkey, - amount: u64, -) -> Instruction { - let accounts = vec![ - AccountMeta::new(*stake_pool, false), - AccountMeta::new_readonly(*stake_pool_withdraw_authority, false), - AccountMeta::new(*reserve_stake_account, false), - AccountMeta::new(*lamports_from, true), - AccountMeta::new(*pool_tokens_to, false), - AccountMeta::new(*manager_fee_account, false), - AccountMeta::new(*referrer_pool_tokens_account, false), - AccountMeta::new(*pool_mint, false), - AccountMeta::new_readonly(system_program::id(), false), - AccountMeta::new_readonly(*token_program_id, false), - AccountMeta::new_readonly(*sol_deposit_authority, true), - ]; - Instruction { - program_id: *program_id, - accounts, - data: StakePoolInstruction::DepositSol(amount) - .try_to_vec() - .unwrap(), - } -} - -/// Creates a 'WithdrawStake' instruction. -pub fn withdraw_stake( - program_id: &Pubkey, - stake_pool: &Pubkey, - validator_list_storage: &Pubkey, - stake_pool_withdraw: &Pubkey, - stake_to_split: &Pubkey, - stake_to_receive: &Pubkey, - user_stake_authority: &Pubkey, - user_transfer_authority: &Pubkey, - user_pool_token_account: &Pubkey, - manager_fee_account: &Pubkey, - pool_mint: &Pubkey, - token_program_id: &Pubkey, - amount: u64, -) -> Instruction { - let accounts = vec![ - AccountMeta::new(*stake_pool, false), - AccountMeta::new(*validator_list_storage, false), - AccountMeta::new_readonly(*stake_pool_withdraw, false), - AccountMeta::new(*stake_to_split, false), - AccountMeta::new(*stake_to_receive, false), - AccountMeta::new_readonly(*user_stake_authority, false), - AccountMeta::new_readonly(*user_transfer_authority, true), - AccountMeta::new(*user_pool_token_account, false), - AccountMeta::new(*manager_fee_account, false), - AccountMeta::new(*pool_mint, false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - AccountMeta::new_readonly(*token_program_id, false), - AccountMeta::new_readonly(stake::program::id(), false), - ]; - Instruction { - program_id: *program_id, - accounts, - data: StakePoolInstruction::WithdrawStake(amount) - .try_to_vec() - .unwrap(), - } -} - -/// Creates instruction required to withdraw SOL directly from a stake pool. -pub fn withdraw_sol( - program_id: &Pubkey, - stake_pool: &Pubkey, - stake_pool_withdraw_authority: &Pubkey, - user_transfer_authority: &Pubkey, - pool_tokens_from: &Pubkey, - reserve_stake_account: &Pubkey, - lamports_to: &Pubkey, - manager_fee_account: &Pubkey, - pool_mint: &Pubkey, - token_program_id: &Pubkey, - pool_tokens: u64, -) -> Instruction { - let accounts = vec![ - AccountMeta::new(*stake_pool, false), - AccountMeta::new_readonly(*stake_pool_withdraw_authority, false), - AccountMeta::new_readonly(*user_transfer_authority, true), - AccountMeta::new(*pool_tokens_from, false), - AccountMeta::new(*reserve_stake_account, false), - AccountMeta::new(*lamports_to, false), - AccountMeta::new(*manager_fee_account, false), - AccountMeta::new(*pool_mint, false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - AccountMeta::new_readonly(sysvar::stake_history::id(), false), - AccountMeta::new_readonly(stake::program::id(), false), - AccountMeta::new_readonly(*token_program_id, false), - ]; - Instruction { - program_id: *program_id, - accounts, - data: StakePoolInstruction::WithdrawSol(pool_tokens) - .try_to_vec() - .unwrap(), - } -} - -/// Creates instruction required to withdraw SOL directly from a stake pool. -/// The difference with `withdraw_sol()` is that the sol withdraw authority -/// must sign this instruction. -pub fn withdraw_sol_with_authority( - program_id: &Pubkey, - stake_pool: &Pubkey, - sol_withdraw_authority: &Pubkey, - stake_pool_withdraw_authority: &Pubkey, - user_transfer_authority: &Pubkey, - pool_tokens_from: &Pubkey, - reserve_stake_account: &Pubkey, - lamports_to: &Pubkey, - manager_fee_account: &Pubkey, - pool_mint: &Pubkey, - token_program_id: &Pubkey, - pool_tokens: u64, -) -> Instruction { - let accounts = vec![ - AccountMeta::new(*stake_pool, false), - AccountMeta::new_readonly(*stake_pool_withdraw_authority, false), - AccountMeta::new_readonly(*user_transfer_authority, true), - AccountMeta::new(*pool_tokens_from, false), - AccountMeta::new(*reserve_stake_account, false), - AccountMeta::new(*lamports_to, false), - AccountMeta::new(*manager_fee_account, false), - AccountMeta::new(*pool_mint, false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - AccountMeta::new_readonly(sysvar::stake_history::id(), false), - AccountMeta::new_readonly(stake::program::id(), false), - AccountMeta::new_readonly(*token_program_id, false), - AccountMeta::new_readonly(*sol_withdraw_authority, true), - ]; - Instruction { - program_id: *program_id, - accounts, - data: StakePoolInstruction::WithdrawSol(pool_tokens) - .try_to_vec() - .unwrap(), - } -} - -/// Creates a 'set manager' instruction. -pub fn set_manager( - program_id: &Pubkey, - stake_pool: &Pubkey, - manager: &Pubkey, - new_manager: &Pubkey, - new_fee_receiver: &Pubkey, -) -> Instruction { - let accounts = vec![ - AccountMeta::new(*stake_pool, false), - AccountMeta::new_readonly(*manager, true), - AccountMeta::new_readonly(*new_manager, true), - AccountMeta::new_readonly(*new_fee_receiver, false), - ]; - Instruction { - program_id: *program_id, - accounts, - data: StakePoolInstruction::SetManager.try_to_vec().unwrap(), - } -} - -/// Creates a 'set fee' instruction. -pub fn set_fee( - program_id: &Pubkey, - stake_pool: &Pubkey, - manager: &Pubkey, - fee: FeeType, -) -> Instruction { - let accounts = vec![ - AccountMeta::new(*stake_pool, false), - AccountMeta::new_readonly(*manager, true), - ]; - Instruction { - program_id: *program_id, - accounts, - data: StakePoolInstruction::SetFee { fee }.try_to_vec().unwrap(), - } -} - -/// Creates a 'set staker' instruction. -pub fn set_staker( - program_id: &Pubkey, - stake_pool: &Pubkey, - set_staker_authority: &Pubkey, - new_staker: &Pubkey, -) -> Instruction { - let accounts = vec![ - AccountMeta::new(*stake_pool, false), - AccountMeta::new_readonly(*set_staker_authority, true), - AccountMeta::new_readonly(*new_staker, false), - ]; - Instruction { - program_id: *program_id, - accounts, - data: StakePoolInstruction::SetStaker.try_to_vec().unwrap(), - } -} - -/// Creates a 'SetFundingAuthority' instruction. -pub fn set_funding_authority( - program_id: &Pubkey, - stake_pool: &Pubkey, - manager: &Pubkey, - new_sol_deposit_authority: Option<&Pubkey>, - funding_type: FundingType, -) -> Instruction { - let mut accounts = vec![ - AccountMeta::new(*stake_pool, false), - AccountMeta::new_readonly(*manager, true), - ]; - if let Some(auth) = new_sol_deposit_authority { - accounts.push(AccountMeta::new_readonly(*auth, false)) - } - Instruction { - program_id: *program_id, - accounts, - data: StakePoolInstruction::SetFundingAuthority(funding_type) - .try_to_vec() - .unwrap(), - } -} - -/// Creates an instruction to update metadata in the mpl token metadata program account for -/// the pool token -pub fn update_token_metadata( - program_id: &Pubkey, - stake_pool: &Pubkey, - manager: &Pubkey, - pool_mint: &Pubkey, - name: String, - symbol: String, - uri: String, -) -> Instruction { - let (stake_pool_withdraw_authority, _) = - find_withdraw_authority_program_address(program_id, stake_pool); - let (token_metadata, _) = find_metadata_account(pool_mint); - - let accounts = vec![ - AccountMeta::new_readonly(*stake_pool, false), - AccountMeta::new_readonly(*manager, true), - AccountMeta::new_readonly(stake_pool_withdraw_authority, false), - AccountMeta::new(token_metadata, false), - AccountMeta::new_readonly(mpl_token_metadata::id(), false), - ]; - - Instruction { - program_id: *program_id, - accounts, - data: StakePoolInstruction::UpdateTokenMetadata { name, symbol, uri } - .try_to_vec() - .unwrap(), - } -} - -/// Creates an instruction to create metadata using the mpl token metadata program for -/// the pool token -pub fn create_token_metadata( - program_id: &Pubkey, - stake_pool: &Pubkey, - manager: &Pubkey, - pool_mint: &Pubkey, - payer: &Pubkey, - name: String, - symbol: String, - uri: String, -) -> Instruction { - let (stake_pool_withdraw_authority, _) = - find_withdraw_authority_program_address(program_id, stake_pool); - let (token_metadata, _) = find_metadata_account(pool_mint); - - let accounts = vec![ - AccountMeta::new_readonly(*stake_pool, false), - AccountMeta::new_readonly(*manager, true), - AccountMeta::new_readonly(stake_pool_withdraw_authority, false), - AccountMeta::new_readonly(*pool_mint, false), - AccountMeta::new(*payer, true), - AccountMeta::new(token_metadata, false), - AccountMeta::new_readonly(mpl_token_metadata::id(), false), - AccountMeta::new_readonly(system_program::id(), false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - ]; - - Instruction { - program_id: *program_id, - accounts, - data: StakePoolInstruction::CreateTokenMetadata { name, symbol, uri } - .try_to_vec() - .unwrap(), - } -} diff --git a/stake-pool/program/src/lib.rs b/stake-pool/program/src/lib.rs deleted file mode 100644 index aa6931ddf2f..00000000000 --- a/stake-pool/program/src/lib.rs +++ /dev/null @@ -1,129 +0,0 @@ -#![deny(missing_docs)] - -//! A program for creating and managing pools of stake - -pub mod big_vec; -pub mod error; -pub mod instruction; -pub mod processor; -pub mod state; - -#[cfg(not(feature = "no-entrypoint"))] -pub mod entrypoint; - -// Export current sdk types for downstream users building with a different sdk version -pub use solana_program; -use { - crate::state::Fee, - solana_program::{native_token::LAMPORTS_PER_SOL, pubkey::Pubkey, stake::state::Meta}, -}; - -/// Seed for deposit authority seed -const AUTHORITY_DEPOSIT: &[u8] = b"deposit"; - -/// Seed for withdraw authority seed -const AUTHORITY_WITHDRAW: &[u8] = b"withdraw"; - -/// Seed for transient stake account -const TRANSIENT_STAKE_SEED_PREFIX: &[u8] = b"transient"; - -/// Minimum amount of staked SOL required in a validator stake account to allow -/// for merges without a mismatch on credits observed -pub const MINIMUM_ACTIVE_STAKE: u64 = LAMPORTS_PER_SOL; - -/// Minimum amount of SOL in the reserve -pub const MINIMUM_RESERVE_LAMPORTS: u64 = LAMPORTS_PER_SOL; - -/// Maximum amount of validator stake accounts to update per -/// `UpdateValidatorListBalance` instruction, based on compute limits -pub const MAX_VALIDATORS_TO_UPDATE: usize = 5; - -/// Maximum factor by which a withdrawal fee can be increased per epoch -/// protecting stakers from malicious users. -/// If current fee is 0, WITHDRAWAL_BASELINE_FEE is used as the baseline -pub const MAX_WITHDRAWAL_FEE_INCREASE: Fee = Fee { - numerator: 3, - denominator: 2, -}; -/// Drop-in baseline fee when evaluating withdrawal fee increases when fee is 0 -pub const WITHDRAWAL_BASELINE_FEE: Fee = Fee { - numerator: 1, - denominator: 1000, -}; - -/// The maximum number of transient stake accounts respecting -/// transaction account limits. -pub const MAX_TRANSIENT_STAKE_ACCOUNTS: usize = 10; - -/// Get the stake amount under consideration when calculating pool token -/// conversions -#[inline] -pub fn minimum_stake_lamports(meta: &Meta) -> u64 { - meta.rent_exempt_reserve - .saturating_add(MINIMUM_ACTIVE_STAKE) -} - -/// Get the stake amount under consideration when calculating pool token -/// conversions -#[inline] -pub fn minimum_reserve_lamports(meta: &Meta) -> u64 { - meta.rent_exempt_reserve - .saturating_add(MINIMUM_RESERVE_LAMPORTS) -} - -/// Generates the deposit authority program address for the stake pool -pub fn find_deposit_authority_program_address( - program_id: &Pubkey, - stake_pool_address: &Pubkey, -) -> (Pubkey, u8) { - Pubkey::find_program_address( - &[&stake_pool_address.to_bytes()[..32], AUTHORITY_DEPOSIT], - program_id, - ) -} - -/// Generates the withdraw authority program address for the stake pool -pub fn find_withdraw_authority_program_address( - program_id: &Pubkey, - stake_pool_address: &Pubkey, -) -> (Pubkey, u8) { - Pubkey::find_program_address( - &[&stake_pool_address.to_bytes(), AUTHORITY_WITHDRAW], - program_id, - ) -} - -/// Generates the stake program address for a validator's vote account -pub fn find_stake_program_address( - program_id: &Pubkey, - vote_account_address: &Pubkey, - stake_pool_address: &Pubkey, -) -> (Pubkey, u8) { - Pubkey::find_program_address( - &[ - &vote_account_address.to_bytes(), - &stake_pool_address.to_bytes(), - ], - program_id, - ) -} - -/// Generates the stake program address for a validator's vote account -pub fn find_transient_stake_program_address( - program_id: &Pubkey, - vote_account_address: &Pubkey, - stake_pool_address: &Pubkey, - seed: u64, -) -> (Pubkey, u8) { - Pubkey::find_program_address( - &[ - TRANSIENT_STAKE_SEED_PREFIX, - &vote_account_address.to_bytes(), - &stake_pool_address.to_bytes(), - &seed.to_le_bytes(), - ], - program_id, - ) -} - -solana_program::declare_id!("SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy"); diff --git a/stake-pool/program/src/processor.rs b/stake-pool/program/src/processor.rs deleted file mode 100644 index d26c4efbae5..00000000000 --- a/stake-pool/program/src/processor.rs +++ /dev/null @@ -1,3193 +0,0 @@ -//! Program state processor - -use { - crate::{ - error::StakePoolError, - find_deposit_authority_program_address, - instruction::{FundingType, PreferredValidatorType, StakePoolInstruction}, - minimum_reserve_lamports, minimum_stake_lamports, - state::{ - AccountType, Fee, FeeType, StakePool, StakeStatus, ValidatorList, ValidatorListHeader, - ValidatorStakeInfo, - }, - AUTHORITY_DEPOSIT, AUTHORITY_WITHDRAW, MINIMUM_ACTIVE_STAKE, TRANSIENT_STAKE_SEED_PREFIX, - }, - borsh::{BorshDeserialize, BorshSerialize}, - mpl_token_metadata::{ - instruction::{create_metadata_accounts_v3, update_metadata_accounts_v2}, - pda::find_metadata_account, - state::DataV2, - }, - num_traits::FromPrimitive, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - borsh::try_from_slice_unchecked, - clock::{Clock, Epoch}, - decode_error::DecodeError, - entrypoint::ProgramResult, - msg, - program::{invoke, invoke_signed}, - program_error::{PrintProgramError, ProgramError}, - program_pack::Pack, - pubkey::Pubkey, - rent::Rent, - stake, system_instruction, system_program, - sysvar::Sysvar, - }, - spl_token::state::Mint, -}; - -/// Deserialize the stake state from AccountInfo -fn get_stake_state( - stake_account_info: &AccountInfo, -) -> Result<(stake::state::Meta, stake::state::Stake), ProgramError> { - let stake_state = - try_from_slice_unchecked::(&stake_account_info.data.borrow())?; - match stake_state { - stake::state::StakeState::Stake(meta, stake) => Ok((meta, stake)), - _ => Err(StakePoolError::WrongStakeState.into()), - } -} - -/// Check validity of vote address for a particular stake account -fn check_validator_stake_address( - program_id: &Pubkey, - stake_pool_address: &Pubkey, - stake_account_address: &Pubkey, - vote_address: &Pubkey, -) -> Result<(), ProgramError> { - // Check stake account address validity - let (validator_stake_address, _) = - crate::find_stake_program_address(program_id, vote_address, stake_pool_address); - if validator_stake_address != *stake_account_address { - msg!( - "Incorrect stake account address for vote {}, expected {}, received {}", - vote_address, - validator_stake_address, - stake_account_address - ); - Err(StakePoolError::InvalidStakeAccountAddress.into()) - } else { - Ok(()) - } -} - -/// Check validity of vote address for a particular stake account -fn check_transient_stake_address( - program_id: &Pubkey, - stake_pool_address: &Pubkey, - stake_account_address: &Pubkey, - vote_address: &Pubkey, - seed: u64, -) -> Result { - // Check stake account address validity - let (transient_stake_address, bump_seed) = crate::find_transient_stake_program_address( - program_id, - vote_address, - stake_pool_address, - seed, - ); - if transient_stake_address != *stake_account_address { - Err(StakePoolError::InvalidStakeAccountAddress.into()) - } else { - Ok(bump_seed) - } -} - -/// Check mpl metadata account address for the pool mint -fn check_mpl_metadata_account_address( - metadata_address: &Pubkey, - pool_mint: &Pubkey, -) -> Result<(), ProgramError> { - let (metadata_account_pubkey, _) = find_metadata_account(pool_mint); - if metadata_account_pubkey != *metadata_address { - Err(StakePoolError::InvalidMetadataAccount.into()) - } else { - Ok(()) - } -} - -/// Check system program address -fn check_system_program(program_id: &Pubkey) -> Result<(), ProgramError> { - if *program_id != system_program::id() { - msg!( - "Expected system program {}, received {}", - system_program::id(), - program_id - ); - Err(ProgramError::IncorrectProgramId) - } else { - Ok(()) - } -} - -/// Check stake program address -fn check_stake_program(program_id: &Pubkey) -> Result<(), ProgramError> { - if *program_id != stake::program::id() { - msg!( - "Expected stake program {}, received {}", - stake::program::id(), - program_id - ); - Err(ProgramError::IncorrectProgramId) - } else { - Ok(()) - } -} - -/// Check mpl metadata program -fn check_mpl_metadata_program(program_id: &Pubkey) -> Result<(), ProgramError> { - if *program_id != mpl_token_metadata::id() { - msg!( - "Expected mpl metadata program {}, received {}", - mpl_token_metadata::id(), - program_id - ); - Err(ProgramError::IncorrectProgramId) - } else { - Ok(()) - } -} - -/// Check rent sysvar correctness -fn check_rent_sysvar(sysvar_key: &Pubkey) -> Result<(), ProgramError> { - if *sysvar_key != solana_program::sysvar::rent::id() { - msg!( - "Expected rent sysvar {}, received {}", - solana_program::sysvar::rent::id(), - sysvar_key - ); - Err(ProgramError::InvalidArgument) - } else { - Ok(()) - } -} - -/// Check account owner is the given program -fn check_account_owner( - account_info: &AccountInfo, - program_id: &Pubkey, -) -> Result<(), ProgramError> { - if *program_id != *account_info.owner { - msg!( - "Expected account to be owned by program {}, received {}", - program_id, - account_info.owner - ); - Err(ProgramError::IncorrectProgramId) - } else { - Ok(()) - } -} - -/// Checks if a stake acount can be managed by the pool -fn stake_is_usable_by_pool( - meta: &stake::state::Meta, - expected_authority: &Pubkey, - expected_lockup: &stake::state::Lockup, -) -> bool { - meta.authorized.staker == *expected_authority - && meta.authorized.withdrawer == *expected_authority - && meta.lockup == *expected_lockup -} - -/// Create a transient stake account without transferring lamports -fn create_transient_stake_account<'a>( - transient_stake_account_info: AccountInfo<'a>, - transient_stake_account_signer_seeds: &[&[u8]], - system_program_info: AccountInfo<'a>, -) -> Result<(), ProgramError> { - invoke_signed( - &system_instruction::allocate( - transient_stake_account_info.key, - std::mem::size_of::() as u64, - ), - &[ - transient_stake_account_info.clone(), - system_program_info.clone(), - ], - &[transient_stake_account_signer_seeds], - )?; - invoke_signed( - &system_instruction::assign(transient_stake_account_info.key, &stake::program::id()), - &[transient_stake_account_info, system_program_info], - &[transient_stake_account_signer_seeds], - ) -} - -/// Create an account on a program-derived address -fn create_pda_account<'a>( - payer: &AccountInfo<'a>, - required_lamports: u64, - space: usize, - owner: &Pubkey, - system_program: &AccountInfo<'a>, - new_pda_account: &AccountInfo<'a>, - new_pda_signer_seeds: &[&[u8]], -) -> ProgramResult { - if new_pda_account.lamports() > 0 { - let required_lamports = required_lamports.saturating_sub(new_pda_account.lamports()); - if required_lamports > 0 { - invoke( - &system_instruction::transfer(payer.key, new_pda_account.key, required_lamports), - &[ - payer.clone(), - new_pda_account.clone(), - system_program.clone(), - ], - )?; - } - - invoke_signed( - &system_instruction::allocate(new_pda_account.key, space as u64), - &[new_pda_account.clone(), system_program.clone()], - &[new_pda_signer_seeds], - )?; - - invoke_signed( - &system_instruction::assign(new_pda_account.key, owner), - &[new_pda_account.clone(), system_program.clone()], - &[new_pda_signer_seeds], - ) - } else { - invoke_signed( - &system_instruction::create_account( - payer.key, - new_pda_account.key, - required_lamports, - space as u64, - owner, - ), - &[ - payer.clone(), - new_pda_account.clone(), - system_program.clone(), - ], - &[new_pda_signer_seeds], - ) - } -} - -/// Program state handler. -pub struct Processor {} -impl Processor { - /// Issue a delegate_stake instruction. - #[allow(clippy::too_many_arguments)] - fn stake_delegate<'a>( - stake_info: AccountInfo<'a>, - vote_account_info: AccountInfo<'a>, - clock_info: AccountInfo<'a>, - stake_history_info: AccountInfo<'a>, - stake_config_info: AccountInfo<'a>, - authority_info: AccountInfo<'a>, - stake_pool: &Pubkey, - authority_type: &[u8], - bump_seed: u8, - ) -> Result<(), ProgramError> { - let authority_signature_seeds = - [&stake_pool.to_bytes()[..32], authority_type, &[bump_seed]]; - let signers = &[&authority_signature_seeds[..]]; - - let ix = stake::instruction::delegate_stake( - stake_info.key, - authority_info.key, - vote_account_info.key, - ); - - invoke_signed( - &ix, - &[ - stake_info, - vote_account_info, - clock_info, - stake_history_info, - stake_config_info, - authority_info, - ], - signers, - ) - } - - /// Issue a stake_deactivate instruction. - fn stake_deactivate<'a>( - stake_info: AccountInfo<'a>, - clock_info: AccountInfo<'a>, - authority_info: AccountInfo<'a>, - stake_pool: &Pubkey, - authority_type: &[u8], - bump_seed: u8, - ) -> Result<(), ProgramError> { - let authority_signature_seeds = - [&stake_pool.to_bytes()[..32], authority_type, &[bump_seed]]; - let signers = &[&authority_signature_seeds[..]]; - - let ix = stake::instruction::deactivate_stake(stake_info.key, authority_info.key); - - invoke_signed(&ix, &[stake_info, clock_info, authority_info], signers) - } - - /// Issue a stake_split instruction. - fn stake_split<'a>( - stake_pool: &Pubkey, - stake_account: AccountInfo<'a>, - authority: AccountInfo<'a>, - authority_type: &[u8], - bump_seed: u8, - amount: u64, - split_stake: AccountInfo<'a>, - ) -> Result<(), ProgramError> { - let me_bytes = stake_pool.to_bytes(); - let authority_signature_seeds = [&me_bytes[..32], authority_type, &[bump_seed]]; - let signers = &[&authority_signature_seeds[..]]; - - let split_instruction = - stake::instruction::split(stake_account.key, authority.key, amount, split_stake.key); - - invoke_signed( - split_instruction.last().unwrap(), - &[stake_account, split_stake, authority], - signers, - ) - } - - /// Issue a stake_merge instruction. - #[allow(clippy::too_many_arguments)] - fn stake_merge<'a>( - stake_pool: &Pubkey, - source_account: AccountInfo<'a>, - authority: AccountInfo<'a>, - authority_type: &[u8], - bump_seed: u8, - destination_account: AccountInfo<'a>, - clock: AccountInfo<'a>, - stake_history: AccountInfo<'a>, - stake_program_info: AccountInfo<'a>, - ) -> Result<(), ProgramError> { - let me_bytes = stake_pool.to_bytes(); - let authority_signature_seeds = [&me_bytes[..32], authority_type, &[bump_seed]]; - let signers = &[&authority_signature_seeds[..]]; - - let merge_instruction = - stake::instruction::merge(destination_account.key, source_account.key, authority.key); - - invoke_signed( - &merge_instruction[0], - &[ - destination_account, - source_account, - clock, - stake_history, - authority, - stake_program_info, - ], - signers, - ) - } - - /// Issue stake::instruction::authorize instructions to update both authorities - fn stake_authorize<'a>( - stake_account: AccountInfo<'a>, - stake_authority: AccountInfo<'a>, - new_stake_authority: &Pubkey, - clock: AccountInfo<'a>, - stake_program_info: AccountInfo<'a>, - ) -> Result<(), ProgramError> { - let authorize_instruction = stake::instruction::authorize( - stake_account.key, - stake_authority.key, - new_stake_authority, - stake::state::StakeAuthorize::Staker, - None, - ); - - invoke( - &authorize_instruction, - &[ - stake_account.clone(), - clock.clone(), - stake_authority.clone(), - stake_program_info.clone(), - ], - )?; - - let authorize_instruction = stake::instruction::authorize( - stake_account.key, - stake_authority.key, - new_stake_authority, - stake::state::StakeAuthorize::Withdrawer, - None, - ); - - invoke( - &authorize_instruction, - &[stake_account, clock, stake_authority, stake_program_info], - ) - } - - /// Issue stake::instruction::authorize instructions to update both authorities - #[allow(clippy::too_many_arguments)] - fn stake_authorize_signed<'a>( - stake_pool: &Pubkey, - stake_account: AccountInfo<'a>, - stake_authority: AccountInfo<'a>, - authority_type: &[u8], - bump_seed: u8, - new_stake_authority: &Pubkey, - clock: AccountInfo<'a>, - stake_program_info: AccountInfo<'a>, - ) -> Result<(), ProgramError> { - let me_bytes = stake_pool.to_bytes(); - let authority_signature_seeds = [&me_bytes[..32], authority_type, &[bump_seed]]; - let signers = &[&authority_signature_seeds[..]]; - - let authorize_instruction = stake::instruction::authorize( - stake_account.key, - stake_authority.key, - new_stake_authority, - stake::state::StakeAuthorize::Staker, - None, - ); - - invoke_signed( - &authorize_instruction, - &[ - stake_account.clone(), - clock.clone(), - stake_authority.clone(), - stake_program_info.clone(), - ], - signers, - )?; - - let authorize_instruction = stake::instruction::authorize( - stake_account.key, - stake_authority.key, - new_stake_authority, - stake::state::StakeAuthorize::Withdrawer, - None, - ); - invoke_signed( - &authorize_instruction, - &[stake_account, clock, stake_authority, stake_program_info], - signers, - ) - } - - /// Issue stake::instruction::withdraw instruction to move additional lamports - #[allow(clippy::too_many_arguments)] - fn stake_withdraw<'a>( - stake_pool: &Pubkey, - source_account: AccountInfo<'a>, - authority: AccountInfo<'a>, - authority_type: &[u8], - bump_seed: u8, - destination_account: AccountInfo<'a>, - clock: AccountInfo<'a>, - stake_history: AccountInfo<'a>, - stake_program_info: AccountInfo<'a>, - lamports: u64, - ) -> Result<(), ProgramError> { - let me_bytes = stake_pool.to_bytes(); - let authority_signature_seeds = [&me_bytes[..32], authority_type, &[bump_seed]]; - let signers = &[&authority_signature_seeds[..]]; - let custodian_pubkey = None; - - let withdraw_instruction = stake::instruction::withdraw( - source_account.key, - authority.key, - destination_account.key, - lamports, - custodian_pubkey, - ); - - invoke_signed( - &withdraw_instruction, - &[ - source_account, - destination_account, - clock, - stake_history, - authority, - stake_program_info, - ], - signers, - ) - } - - /// Issue a spl_token `Burn` instruction. - #[allow(clippy::too_many_arguments)] - fn token_burn<'a>( - token_program: AccountInfo<'a>, - burn_account: AccountInfo<'a>, - mint: AccountInfo<'a>, - authority: AccountInfo<'a>, - amount: u64, - ) -> Result<(), ProgramError> { - let ix = spl_token::instruction::burn( - token_program.key, - burn_account.key, - mint.key, - authority.key, - &[], - amount, - )?; - - invoke(&ix, &[burn_account, mint, authority, token_program]) - } - - /// Issue a spl_token `MintTo` instruction. - #[allow(clippy::too_many_arguments)] - fn token_mint_to<'a>( - stake_pool: &Pubkey, - token_program: AccountInfo<'a>, - mint: AccountInfo<'a>, - destination: AccountInfo<'a>, - authority: AccountInfo<'a>, - authority_type: &[u8], - bump_seed: u8, - amount: u64, - ) -> Result<(), ProgramError> { - let me_bytes = stake_pool.to_bytes(); - let authority_signature_seeds = [&me_bytes[..32], authority_type, &[bump_seed]]; - let signers = &[&authority_signature_seeds[..]]; - - let ix = spl_token::instruction::mint_to( - token_program.key, - mint.key, - destination.key, - authority.key, - &[], - amount, - )?; - - invoke_signed(&ix, &[mint, destination, authority, token_program], signers) - } - - /// Issue a spl_token `Transfer` instruction. - #[allow(clippy::too_many_arguments)] - fn token_transfer<'a>( - token_program: AccountInfo<'a>, - source: AccountInfo<'a>, - destination: AccountInfo<'a>, - authority: AccountInfo<'a>, - amount: u64, - ) -> Result<(), ProgramError> { - let ix = spl_token::instruction::transfer( - token_program.key, - source.key, - destination.key, - authority.key, - &[], - amount, - )?; - invoke(&ix, &[source, destination, authority, token_program]) - } - - fn sol_transfer<'a>( - source: AccountInfo<'a>, - destination: AccountInfo<'a>, - system_program: AccountInfo<'a>, - amount: u64, - ) -> Result<(), ProgramError> { - let ix = solana_program::system_instruction::transfer(source.key, destination.key, amount); - invoke(&ix, &[source, destination, system_program]) - } - - /// Processes `Initialize` instruction. - #[inline(never)] // needed due to stack size violation - fn process_initialize( - program_id: &Pubkey, - accounts: &[AccountInfo], - epoch_fee: Fee, - withdrawal_fee: Fee, - deposit_fee: Fee, - referral_fee: u8, - max_validators: u32, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let stake_pool_info = next_account_info(account_info_iter)?; - let manager_info = next_account_info(account_info_iter)?; - let staker_info = next_account_info(account_info_iter)?; - let withdraw_authority_info = next_account_info(account_info_iter)?; - let validator_list_info = next_account_info(account_info_iter)?; - let reserve_stake_info = next_account_info(account_info_iter)?; - let pool_mint_info = next_account_info(account_info_iter)?; - let manager_fee_info = next_account_info(account_info_iter)?; - let token_program_info = next_account_info(account_info_iter)?; - - let rent = Rent::get()?; - - if !manager_info.is_signer { - msg!("Manager did not sign initialization"); - return Err(StakePoolError::SignatureMissing.into()); - } - - if stake_pool_info.key == validator_list_info.key { - msg!("Cannot use same account for stake pool and validator list"); - return Err(StakePoolError::AlreadyInUse.into()); - } - - check_account_owner(stake_pool_info, program_id)?; - let mut stake_pool = try_from_slice_unchecked::(&stake_pool_info.data.borrow())?; - if !stake_pool.is_uninitialized() { - msg!("Provided stake pool already in use"); - return Err(StakePoolError::AlreadyInUse.into()); - } - - check_account_owner(validator_list_info, program_id)?; - let mut validator_list = - try_from_slice_unchecked::(&validator_list_info.data.borrow())?; - if !validator_list.header.is_uninitialized() { - msg!("Provided validator list already in use"); - return Err(StakePoolError::AlreadyInUse.into()); - } - - let data_length = validator_list_info.data_len(); - let expected_max_validators = ValidatorList::calculate_max_validators(data_length); - if expected_max_validators != max_validators as usize || max_validators == 0 { - msg!( - "Incorrect validator list size provided, expected {}, provided {}", - expected_max_validators, - max_validators - ); - return Err(StakePoolError::UnexpectedValidatorListAccountSize.into()); - } - validator_list.header.account_type = AccountType::ValidatorList; - validator_list.header.max_validators = max_validators; - validator_list.validators.clear(); - - if !rent.is_exempt(stake_pool_info.lamports(), stake_pool_info.data_len()) { - msg!("Stake pool not rent-exempt"); - return Err(ProgramError::AccountNotRentExempt); - } - - if !rent.is_exempt( - validator_list_info.lamports(), - validator_list_info.data_len(), - ) { - msg!("Validator stake list not rent-exempt"); - return Err(ProgramError::AccountNotRentExempt); - } - - // Numerator should be smaller than or equal to denominator (fee <= 1) - if epoch_fee.numerator > epoch_fee.denominator - || withdrawal_fee.numerator > withdrawal_fee.denominator - || deposit_fee.numerator > deposit_fee.denominator - || referral_fee > 100u8 - { - return Err(StakePoolError::FeeTooHigh.into()); - } - - if *token_program_info.key != spl_token::id() { - msg!( - "Only the SPL token program is currently supported, expected {}, received {}", - spl_token::id(), - *token_program_info.key - ); - return Err(ProgramError::IncorrectProgramId); - } - - if manager_fee_info.owner != token_program_info.key { - return Err(ProgramError::IncorrectProgramId); - } - - if pool_mint_info.owner != token_program_info.key { - return Err(ProgramError::IncorrectProgramId); - } - - if *pool_mint_info.key - != spl_token::state::Account::unpack_from_slice(&manager_fee_info.data.borrow())?.mint - { - return Err(StakePoolError::WrongAccountMint.into()); - } - - let (stake_deposit_authority, sol_deposit_authority) = - match next_account_info(account_info_iter) { - Ok(deposit_authority_info) => ( - *deposit_authority_info.key, - Some(*deposit_authority_info.key), - ), - Err(_) => ( - find_deposit_authority_program_address(program_id, stake_pool_info.key).0, - None, - ), - }; - let (withdraw_authority_key, stake_withdraw_bump_seed) = - crate::find_withdraw_authority_program_address(program_id, stake_pool_info.key); - if withdraw_authority_key != *withdraw_authority_info.key { - msg!( - "Incorrect withdraw authority provided, expected {}, received {}", - withdraw_authority_key, - withdraw_authority_info.key - ); - return Err(StakePoolError::InvalidProgramAddress.into()); - } - - let pool_mint = Mint::unpack_from_slice(&pool_mint_info.data.borrow())?; - - if pool_mint.supply != 0 { - return Err(StakePoolError::NonZeroPoolTokenSupply.into()); - } - - if !pool_mint.mint_authority.contains(&withdraw_authority_key) { - return Err(StakePoolError::WrongMintingAuthority.into()); - } - - if pool_mint.freeze_authority.is_some() { - return Err(StakePoolError::InvalidMintFreezeAuthority.into()); - } - - if *reserve_stake_info.owner != stake::program::id() { - msg!("Reserve stake account not owned by stake program"); - return Err(ProgramError::IncorrectProgramId); - } - let stake_state = try_from_slice_unchecked::( - &reserve_stake_info.data.borrow(), - )?; - let total_lamports = if let stake::state::StakeState::Initialized(meta) = stake_state { - if meta.lockup != stake::state::Lockup::default() { - msg!("Reserve stake account has some lockup"); - return Err(StakePoolError::WrongStakeState.into()); - } - - if meta.authorized.staker != withdraw_authority_key { - msg!( - "Reserve stake account has incorrect staker {}, should be {}", - meta.authorized.staker, - withdraw_authority_key - ); - return Err(StakePoolError::WrongStakeState.into()); - } - - if meta.authorized.withdrawer != withdraw_authority_key { - msg!( - "Reserve stake account has incorrect withdrawer {}, should be {}", - meta.authorized.staker, - withdraw_authority_key - ); - return Err(StakePoolError::WrongStakeState.into()); - } - reserve_stake_info - .lamports() - .checked_sub(minimum_reserve_lamports(&meta)) - .ok_or(StakePoolError::CalculationFailure)? - } else { - msg!("Reserve stake account not in intialized state"); - return Err(StakePoolError::WrongStakeState.into()); - }; - - if total_lamports > 0 { - Self::token_mint_to( - stake_pool_info.key, - token_program_info.clone(), - pool_mint_info.clone(), - manager_fee_info.clone(), - withdraw_authority_info.clone(), - AUTHORITY_WITHDRAW, - stake_withdraw_bump_seed, - total_lamports, - )?; - } - - validator_list.serialize(&mut *validator_list_info.data.borrow_mut())?; - - stake_pool.account_type = AccountType::StakePool; - stake_pool.manager = *manager_info.key; - stake_pool.staker = *staker_info.key; - stake_pool.stake_deposit_authority = stake_deposit_authority; - stake_pool.stake_withdraw_bump_seed = stake_withdraw_bump_seed; - stake_pool.validator_list = *validator_list_info.key; - stake_pool.reserve_stake = *reserve_stake_info.key; - stake_pool.pool_mint = *pool_mint_info.key; - stake_pool.manager_fee_account = *manager_fee_info.key; - stake_pool.token_program_id = *token_program_info.key; - stake_pool.total_lamports = total_lamports; - stake_pool.pool_token_supply = total_lamports; - stake_pool.last_update_epoch = Clock::get()?.epoch; - stake_pool.lockup = stake::state::Lockup::default(); - stake_pool.epoch_fee = epoch_fee; - stake_pool.next_epoch_fee = None; - stake_pool.preferred_deposit_validator_vote_address = None; - stake_pool.preferred_withdraw_validator_vote_address = None; - stake_pool.stake_deposit_fee = deposit_fee; - stake_pool.stake_withdrawal_fee = withdrawal_fee; - stake_pool.next_stake_withdrawal_fee = None; - stake_pool.stake_referral_fee = referral_fee; - stake_pool.sol_deposit_authority = sol_deposit_authority; - stake_pool.sol_deposit_fee = deposit_fee; - stake_pool.sol_referral_fee = referral_fee; - stake_pool.sol_withdraw_authority = None; - stake_pool.sol_withdrawal_fee = withdrawal_fee; - stake_pool.next_sol_withdrawal_fee = None; - stake_pool.last_epoch_pool_token_supply = 0; - stake_pool.last_epoch_total_lamports = 0; - - stake_pool - .serialize(&mut *stake_pool_info.data.borrow_mut()) - .map_err(|e| e.into()) - } - - /// Processes `AddValidatorToPool` instruction. - #[inline(never)] // needed due to stack size violation - fn process_add_validator_to_pool( - program_id: &Pubkey, - accounts: &[AccountInfo], - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let stake_pool_info = next_account_info(account_info_iter)?; - let staker_info = next_account_info(account_info_iter)?; - let funder_info = next_account_info(account_info_iter)?; - let withdraw_authority_info = next_account_info(account_info_iter)?; - let validator_list_info = next_account_info(account_info_iter)?; - let stake_info = next_account_info(account_info_iter)?; - let validator_vote_info = next_account_info(account_info_iter)?; - let rent_info = next_account_info(account_info_iter)?; - let rent = &Rent::from_account_info(rent_info)?; - let clock_info = next_account_info(account_info_iter)?; - let clock = &Clock::from_account_info(clock_info)?; - let stake_history_info = next_account_info(account_info_iter)?; - let stake_config_info = next_account_info(account_info_iter)?; - let system_program_info = next_account_info(account_info_iter)?; - let stake_program_info = next_account_info(account_info_iter)?; - - check_system_program(system_program_info.key)?; - check_stake_program(stake_program_info.key)?; - - check_account_owner(stake_pool_info, program_id)?; - let stake_pool = try_from_slice_unchecked::(&stake_pool_info.data.borrow())?; - if !stake_pool.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - - stake_pool.check_authority_withdraw( - withdraw_authority_info.key, - program_id, - stake_pool_info.key, - )?; - - stake_pool.check_staker(staker_info)?; - stake_pool.check_validator_list(validator_list_info)?; - - if stake_pool.last_update_epoch < clock.epoch { - return Err(StakePoolError::StakeListAndPoolOutOfDate.into()); - } - - check_account_owner(validator_list_info, program_id)?; - let mut validator_list_data = validator_list_info.data.borrow_mut(); - let (header, mut validator_list) = - ValidatorListHeader::deserialize_vec(&mut validator_list_data)?; - if !header.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - if header.max_validators == validator_list.len() { - return Err(ProgramError::AccountDataTooSmall); - } - let maybe_validator_stake_info = validator_list.find::( - validator_vote_info.key.as_ref(), - ValidatorStakeInfo::memcmp_pubkey, - ); - if maybe_validator_stake_info.is_some() { - return Err(StakePoolError::ValidatorAlreadyAdded.into()); - } - - let (stake_address, bump_seed) = crate::find_stake_program_address( - program_id, - validator_vote_info.key, - stake_pool_info.key, - ); - if stake_address != *stake_info.key { - return Err(StakePoolError::InvalidStakeAccountAddress.into()); - } - - let stake_account_signer_seeds: &[&[_]] = &[ - &validator_vote_info.key.to_bytes()[..32], - &stake_pool_info.key.to_bytes()[..32], - &[bump_seed], - ]; - - // Fund the stake account with the minimum + rent-exempt balance - let space = std::mem::size_of::(); - let required_lamports = MINIMUM_ACTIVE_STAKE + rent.minimum_balance(space); - - // Create new stake account - create_pda_account( - funder_info, - required_lamports, - space, - &stake::program::id(), - system_program_info, - stake_info, - stake_account_signer_seeds, - )?; - invoke( - &stake::instruction::initialize( - stake_info.key, - &stake::state::Authorized { - staker: *withdraw_authority_info.key, - withdrawer: *withdraw_authority_info.key, - }, - &stake::state::Lockup::default(), - ), - &[ - stake_info.clone(), - rent_info.clone(), - stake_program_info.clone(), - ], - )?; - - Self::stake_delegate( - stake_info.clone(), - validator_vote_info.clone(), - clock_info.clone(), - stake_history_info.clone(), - stake_config_info.clone(), - withdraw_authority_info.clone(), - stake_pool_info.key, - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - )?; - - validator_list.push(ValidatorStakeInfo { - status: StakeStatus::Active, - vote_account_address: *validator_vote_info.key, - active_stake_lamports: 0, - transient_stake_lamports: 0, - last_update_epoch: clock.epoch, - transient_seed_suffix_start: 0, - transient_seed_suffix_end: 0, - })?; - - Ok(()) - } - - /// Processes `RemoveValidatorFromPool` instruction. - #[inline(never)] // needed due to stack size violation - fn process_remove_validator_from_pool( - program_id: &Pubkey, - accounts: &[AccountInfo], - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let stake_pool_info = next_account_info(account_info_iter)?; - let staker_info = next_account_info(account_info_iter)?; - let withdraw_authority_info = next_account_info(account_info_iter)?; - let new_stake_authority_info = next_account_info(account_info_iter)?; - let validator_list_info = next_account_info(account_info_iter)?; - let stake_account_info = next_account_info(account_info_iter)?; - let transient_stake_account_info = next_account_info(account_info_iter)?; - let destination_stake_account_info = next_account_info(account_info_iter)?; - let clock_info = next_account_info(account_info_iter)?; - let clock = &Clock::from_account_info(clock_info)?; - let stake_program_info = next_account_info(account_info_iter)?; - - check_stake_program(stake_program_info.key)?; - check_account_owner(stake_pool_info, program_id)?; - - let mut stake_pool = try_from_slice_unchecked::(&stake_pool_info.data.borrow())?; - if !stake_pool.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - - stake_pool.check_authority_withdraw( - withdraw_authority_info.key, - program_id, - stake_pool_info.key, - )?; - stake_pool.check_staker(staker_info)?; - - if stake_pool.last_update_epoch < clock.epoch { - return Err(StakePoolError::StakeListAndPoolOutOfDate.into()); - } - - stake_pool.check_validator_list(validator_list_info)?; - - check_account_owner(validator_list_info, program_id)?; - let mut validator_list_data = validator_list_info.data.borrow_mut(); - let (header, mut validator_list) = - ValidatorListHeader::deserialize_vec(&mut validator_list_data)?; - if !header.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - - let (meta, stake) = get_stake_state(stake_account_info)?; - let vote_account_address = stake.delegation.voter_pubkey; - check_validator_stake_address( - program_id, - stake_pool_info.key, - stake_account_info.key, - &vote_account_address, - )?; - - let maybe_validator_stake_info = validator_list.find_mut::( - vote_account_address.as_ref(), - ValidatorStakeInfo::memcmp_pubkey, - ); - if maybe_validator_stake_info.is_none() { - msg!( - "Vote account {} not found in stake pool", - vote_account_address - ); - return Err(StakePoolError::ValidatorNotFound.into()); - } - let mut validator_stake_info = maybe_validator_stake_info.unwrap(); - - let stake_lamports = **stake_account_info.lamports.borrow(); - let required_lamports = minimum_stake_lamports(&meta); - if stake_lamports != required_lamports { - msg!( - "Attempting to remove validator account with {} lamports, must have {} lamports", - stake_lamports, - required_lamports - ); - return Err(StakePoolError::StakeLamportsNotEqualToMinimum.into()); - } - - if stake.delegation.stake != MINIMUM_ACTIVE_STAKE { - msg!( - "Error: attempting to remove stake with delegation of {} lamports, must have {} lamports", - stake.delegation.stake, - MINIMUM_ACTIVE_STAKE - ); - return Err(StakePoolError::StakeLamportsNotEqualToMinimum.into()); - } - - let new_status = if validator_stake_info.transient_stake_lamports > 0 { - check_transient_stake_address( - program_id, - stake_pool_info.key, - transient_stake_account_info.key, - &vote_account_address, - validator_stake_info.transient_seed_suffix_start, - )?; - - match get_stake_state(transient_stake_account_info) { - Ok((meta, stake)) - if meta.authorized.staker == *withdraw_authority_info.key - && meta.authorized.withdrawer == *withdraw_authority_info.key => - { - if stake.delegation.deactivation_epoch == Epoch::MAX { - msg!( - "Transient stake {} activating, can't remove stake {} on validator {}", - transient_stake_account_info.key, - stake_account_info.key, - vote_account_address - ); - return Err(StakePoolError::WrongStakeState.into()); - } else { - // stake is deactivating, mark the entry as such - StakeStatus::DeactivatingTransient - } - } - _ => StakeStatus::ReadyForRemoval, - } - } else { - StakeStatus::ReadyForRemoval - }; - - // split whole thing into destination stake account - Self::stake_split( - stake_pool_info.key, - stake_account_info.clone(), - withdraw_authority_info.clone(), - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - stake_account_info.lamports(), - destination_stake_account_info.clone(), - )?; - - Self::stake_authorize_signed( - stake_pool_info.key, - destination_stake_account_info.clone(), - withdraw_authority_info.clone(), - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - new_stake_authority_info.key, - clock_info.clone(), - stake_program_info.clone(), - )?; - - validator_stake_info.status = new_status; - - if stake_pool.preferred_deposit_validator_vote_address == Some(vote_account_address) { - stake_pool.preferred_deposit_validator_vote_address = None; - } - if stake_pool.preferred_withdraw_validator_vote_address == Some(vote_account_address) { - stake_pool.preferred_withdraw_validator_vote_address = None; - } - stake_pool.serialize(&mut *stake_pool_info.data.borrow_mut())?; - - Ok(()) - } - - /// Processes `DecreaseValidatorStake` instruction. - #[inline(never)] // needed due to stack size violation - fn process_decrease_validator_stake( - program_id: &Pubkey, - accounts: &[AccountInfo], - lamports: u64, - transient_stake_seed: u64, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let stake_pool_info = next_account_info(account_info_iter)?; - let staker_info = next_account_info(account_info_iter)?; - let withdraw_authority_info = next_account_info(account_info_iter)?; - let validator_list_info = next_account_info(account_info_iter)?; - let validator_stake_account_info = next_account_info(account_info_iter)?; - let transient_stake_account_info = next_account_info(account_info_iter)?; - let clock_info = next_account_info(account_info_iter)?; - let clock = &Clock::from_account_info(clock_info)?; - let rent_info = next_account_info(account_info_iter)?; - let rent = &Rent::from_account_info(rent_info)?; - let system_program_info = next_account_info(account_info_iter)?; - let stake_program_info = next_account_info(account_info_iter)?; - - check_system_program(system_program_info.key)?; - check_stake_program(stake_program_info.key)?; - check_account_owner(stake_pool_info, program_id)?; - - let stake_pool = try_from_slice_unchecked::(&stake_pool_info.data.borrow())?; - if !stake_pool.is_valid() { - msg!("Expected valid stake pool"); - return Err(StakePoolError::InvalidState.into()); - } - - stake_pool.check_authority_withdraw( - withdraw_authority_info.key, - program_id, - stake_pool_info.key, - )?; - stake_pool.check_staker(staker_info)?; - - if stake_pool.last_update_epoch < clock.epoch { - return Err(StakePoolError::StakeListAndPoolOutOfDate.into()); - } - - stake_pool.check_validator_list(validator_list_info)?; - check_account_owner(validator_list_info, program_id)?; - let validator_list_data = &mut *validator_list_info.data.borrow_mut(); - let (validator_list_header, mut validator_list) = - ValidatorListHeader::deserialize_vec(validator_list_data)?; - if !validator_list_header.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - - let (meta, stake) = get_stake_state(validator_stake_account_info)?; - let vote_account_address = stake.delegation.voter_pubkey; - check_validator_stake_address( - program_id, - stake_pool_info.key, - validator_stake_account_info.key, - &vote_account_address, - )?; - - let maybe_validator_stake_info = validator_list.find_mut::( - vote_account_address.as_ref(), - ValidatorStakeInfo::memcmp_pubkey, - ); - if maybe_validator_stake_info.is_none() { - msg!( - "Vote account {} not found in stake pool", - vote_account_address - ); - return Err(StakePoolError::ValidatorNotFound.into()); - } - let mut validator_stake_info = maybe_validator_stake_info.unwrap(); - if validator_stake_info.transient_stake_lamports > 0 { - return Err(StakePoolError::TransientAccountInUse.into()); - } - - let transient_stake_bump_seed = check_transient_stake_address( - program_id, - stake_pool_info.key, - transient_stake_account_info.key, - &vote_account_address, - transient_stake_seed, - )?; - let transient_stake_account_signer_seeds: &[&[_]] = &[ - TRANSIENT_STAKE_SEED_PREFIX, - &vote_account_address.to_bytes(), - &stake_pool_info.key.to_bytes(), - &transient_stake_seed.to_le_bytes(), - &[transient_stake_bump_seed], - ]; - - let stake_rent = rent.minimum_balance(std::mem::size_of::()); - if lamports <= stake_rent { - msg!( - "Need more than {} lamports for transient stake to be rent-exempt, {} provided", - stake_rent, - lamports - ); - return Err(ProgramError::AccountNotRentExempt); - } - - let remaining_lamports = validator_stake_account_info - .lamports() - .checked_sub(lamports) - .ok_or(ProgramError::InsufficientFunds)?; - let required_lamports = minimum_stake_lamports(&meta); - if remaining_lamports < required_lamports { - msg!("Need at least {} lamports in the stake account after decrease, {} requested, {} is the current possible maximum", - required_lamports, - lamports, - validator_stake_account_info.lamports().checked_sub(required_lamports).ok_or(StakePoolError::CalculationFailure)? - ); - return Err(ProgramError::InsufficientFunds); - } - - create_transient_stake_account( - transient_stake_account_info.clone(), - transient_stake_account_signer_seeds, - system_program_info.clone(), - )?; - - // split into transient stake account - Self::stake_split( - stake_pool_info.key, - validator_stake_account_info.clone(), - withdraw_authority_info.clone(), - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - lamports, - transient_stake_account_info.clone(), - )?; - - // deactivate transient stake - Self::stake_deactivate( - transient_stake_account_info.clone(), - clock_info.clone(), - withdraw_authority_info.clone(), - stake_pool_info.key, - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - )?; - - validator_stake_info.active_stake_lamports = validator_stake_info - .active_stake_lamports - .checked_sub(lamports) - .ok_or(StakePoolError::CalculationFailure)?; - validator_stake_info.transient_stake_lamports = lamports; - validator_stake_info.transient_seed_suffix_start = transient_stake_seed; - - Ok(()) - } - - /// Processes `IncreaseValidatorStake` instruction. - #[inline(never)] // needed due to stack size violation - fn process_increase_validator_stake( - program_id: &Pubkey, - accounts: &[AccountInfo], - lamports: u64, - transient_stake_seed: u64, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let stake_pool_info = next_account_info(account_info_iter)?; - let staker_info = next_account_info(account_info_iter)?; - let withdraw_authority_info = next_account_info(account_info_iter)?; - let validator_list_info = next_account_info(account_info_iter)?; - let reserve_stake_account_info = next_account_info(account_info_iter)?; - let transient_stake_account_info = next_account_info(account_info_iter)?; - let validator_stake_account_info = next_account_info(account_info_iter)?; - let validator_vote_account_info = next_account_info(account_info_iter)?; - let clock_info = next_account_info(account_info_iter)?; - let clock = &Clock::from_account_info(clock_info)?; - let rent_info = next_account_info(account_info_iter)?; - let rent = &Rent::from_account_info(rent_info)?; - let stake_history_info = next_account_info(account_info_iter)?; - let stake_config_info = next_account_info(account_info_iter)?; - let system_program_info = next_account_info(account_info_iter)?; - let stake_program_info = next_account_info(account_info_iter)?; - - check_system_program(system_program_info.key)?; - check_stake_program(stake_program_info.key)?; - check_account_owner(stake_pool_info, program_id)?; - - let stake_pool = try_from_slice_unchecked::(&stake_pool_info.data.borrow())?; - if !stake_pool.is_valid() { - msg!("Expected valid stake pool"); - return Err(StakePoolError::InvalidState.into()); - } - - stake_pool.check_authority_withdraw( - withdraw_authority_info.key, - program_id, - stake_pool_info.key, - )?; - stake_pool.check_staker(staker_info)?; - - if stake_pool.last_update_epoch < clock.epoch { - return Err(StakePoolError::StakeListAndPoolOutOfDate.into()); - } - - stake_pool.check_validator_list(validator_list_info)?; - stake_pool.check_reserve_stake(reserve_stake_account_info)?; - check_account_owner(validator_list_info, program_id)?; - - let mut validator_list_data = validator_list_info.data.borrow_mut(); - let (header, mut validator_list) = - ValidatorListHeader::deserialize_vec(&mut validator_list_data)?; - if !header.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - - let vote_account_address = validator_vote_account_info.key; - - let maybe_validator_stake_info = validator_list.find_mut::( - vote_account_address.as_ref(), - ValidatorStakeInfo::memcmp_pubkey, - ); - if maybe_validator_stake_info.is_none() { - msg!( - "Vote account {} not found in stake pool", - vote_account_address - ); - return Err(StakePoolError::ValidatorNotFound.into()); - } - let mut validator_stake_info = maybe_validator_stake_info.unwrap(); - if validator_stake_info.transient_stake_lamports > 0 { - return Err(StakePoolError::TransientAccountInUse.into()); - } - - // Check that the validator stake account is actually delegated to the right - // validator. This can happen if a validator was force destaked during a - // cluster restart. - { - check_account_owner(validator_stake_account_info, stake_program_info.key)?; - check_validator_stake_address( - program_id, - stake_pool_info.key, - validator_stake_account_info.key, - vote_account_address, - )?; - let (meta, stake) = get_stake_state(validator_stake_account_info)?; - if !stake_is_usable_by_pool(&meta, withdraw_authority_info.key, &stake_pool.lockup) { - msg!("Validator stake for {} not usable by pool, must be owned by withdraw authority", vote_account_address); - return Err(StakePoolError::WrongStakeState.into()); - } - if stake.delegation.voter_pubkey != *vote_account_address { - msg!( - "Validator stake {} not delegated to {}", - validator_stake_account_info.key, - vote_account_address - ); - return Err(StakePoolError::WrongStakeState.into()); - } - } - - let transient_stake_bump_seed = check_transient_stake_address( - program_id, - stake_pool_info.key, - transient_stake_account_info.key, - vote_account_address, - transient_stake_seed, - )?; - let transient_stake_account_signer_seeds: &[&[_]] = &[ - TRANSIENT_STAKE_SEED_PREFIX, - &vote_account_address.to_bytes(), - &stake_pool_info.key.to_bytes(), - &transient_stake_seed.to_le_bytes(), - &[transient_stake_bump_seed], - ]; - - if validator_stake_info.status != StakeStatus::Active { - msg!("Validator is marked for removal and no longer allows increases"); - return Err(StakePoolError::ValidatorNotFound.into()); - } - - let stake_rent = rent.minimum_balance(std::mem::size_of::()); - if lamports < MINIMUM_ACTIVE_STAKE { - msg!( - "Need more than {} lamports for transient stake to be rent-exempt and mergeable, {} provided", - MINIMUM_ACTIVE_STAKE, - lamports - ); - return Err(ProgramError::AccountNotRentExempt); - } - - // the stake account rent exemption is withdrawn after the merge, so - let total_lamports = lamports.saturating_add(stake_rent); - - if reserve_stake_account_info - .lamports() - .saturating_sub(total_lamports) - <= stake_rent - { - let max_split_amount = reserve_stake_account_info - .lamports() - .saturating_sub(2 * stake_rent); - msg!( - "Reserve stake does not have enough lamports for increase, must be less than {}, {} requested", - max_split_amount, - lamports - ); - return Err(ProgramError::InsufficientFunds); - } - - create_transient_stake_account( - transient_stake_account_info.clone(), - transient_stake_account_signer_seeds, - system_program_info.clone(), - )?; - - // split into transient stake account - Self::stake_split( - stake_pool_info.key, - reserve_stake_account_info.clone(), - withdraw_authority_info.clone(), - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - total_lamports, - transient_stake_account_info.clone(), - )?; - - // activate transient stake to validator - Self::stake_delegate( - transient_stake_account_info.clone(), - validator_vote_account_info.clone(), - clock_info.clone(), - stake_history_info.clone(), - stake_config_info.clone(), - withdraw_authority_info.clone(), - stake_pool_info.key, - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - )?; - - validator_stake_info.transient_stake_lamports = total_lamports; - validator_stake_info.transient_seed_suffix_start = transient_stake_seed; - - Ok(()) - } - - /// Process `SetPreferredValidator` instruction - #[inline(never)] // needed due to stack size violation - fn process_set_preferred_validator( - program_id: &Pubkey, - accounts: &[AccountInfo], - validator_type: PreferredValidatorType, - vote_account_address: Option, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let stake_pool_info = next_account_info(account_info_iter)?; - let staker_info = next_account_info(account_info_iter)?; - let validator_list_info = next_account_info(account_info_iter)?; - - check_account_owner(stake_pool_info, program_id)?; - check_account_owner(validator_list_info, program_id)?; - - let mut stake_pool = try_from_slice_unchecked::(&stake_pool_info.data.borrow())?; - if !stake_pool.is_valid() { - msg!("Expected valid stake pool"); - return Err(StakePoolError::InvalidState.into()); - } - - stake_pool.check_staker(staker_info)?; - stake_pool.check_validator_list(validator_list_info)?; - - let mut validator_list_data = validator_list_info.data.borrow_mut(); - let (header, validator_list) = - ValidatorListHeader::deserialize_vec(&mut validator_list_data)?; - if !header.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - - if let Some(vote_account_address) = vote_account_address { - let maybe_validator_stake_info = validator_list.find::( - vote_account_address.as_ref(), - ValidatorStakeInfo::memcmp_pubkey, - ); - match maybe_validator_stake_info { - Some(vsi) => { - if vsi.status != StakeStatus::Active { - msg!("Validator for {:?} about to be removed, cannot set as preferred deposit account", validator_type); - return Err(StakePoolError::InvalidPreferredValidator.into()); - } - } - None => { - msg!("Validator for {:?} not present in the stake pool, cannot set as preferred deposit account", validator_type); - return Err(StakePoolError::ValidatorNotFound.into()); - } - } - } - - match validator_type { - PreferredValidatorType::Deposit => { - stake_pool.preferred_deposit_validator_vote_address = vote_account_address - } - PreferredValidatorType::Withdraw => { - stake_pool.preferred_withdraw_validator_vote_address = vote_account_address - } - }; - stake_pool.serialize(&mut *stake_pool_info.data.borrow_mut())?; - Ok(()) - } - - /// Processes `UpdateValidatorListBalance` instruction. - #[inline(always)] // needed to maximize number of validators - fn process_update_validator_list_balance( - program_id: &Pubkey, - accounts: &[AccountInfo], - start_index: u32, - no_merge: bool, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let stake_pool_info = next_account_info(account_info_iter)?; - let withdraw_authority_info = next_account_info(account_info_iter)?; - let validator_list_info = next_account_info(account_info_iter)?; - let reserve_stake_info = next_account_info(account_info_iter)?; - let clock_info = next_account_info(account_info_iter)?; - let clock = &Clock::from_account_info(clock_info)?; - let stake_history_info = next_account_info(account_info_iter)?; - let stake_program_info = next_account_info(account_info_iter)?; - let validator_stake_accounts = account_info_iter.as_slice(); - - check_account_owner(stake_pool_info, program_id)?; - let stake_pool = try_from_slice_unchecked::(&stake_pool_info.data.borrow())?; - if !stake_pool.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - stake_pool.check_validator_list(validator_list_info)?; - stake_pool.check_authority_withdraw( - withdraw_authority_info.key, - program_id, - stake_pool_info.key, - )?; - stake_pool.check_reserve_stake(reserve_stake_info)?; - check_stake_program(stake_program_info.key)?; - - if validator_stake_accounts - .len() - .checked_rem(2) - .ok_or(StakePoolError::CalculationFailure)? - != 0 - { - msg!("Odd number of validator stake accounts passed in, should be pairs of validator stake and transient stake accounts"); - return Err(StakePoolError::UnexpectedValidatorListAccountSize.into()); - } - - check_account_owner(validator_list_info, program_id)?; - let mut validator_list_data = validator_list_info.data.borrow_mut(); - let (validator_list_header, mut validator_slice) = - ValidatorListHeader::deserialize_mut_slice( - &mut validator_list_data, - start_index as usize, - validator_stake_accounts.len() / 2, - )?; - - if !validator_list_header.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - - let validator_iter = &mut validator_slice - .iter_mut() - .zip(validator_stake_accounts.chunks_exact(2)); - for (validator_stake_record, validator_stakes) in validator_iter { - // chunks_exact means that we always get 2 elements, making this safe - let validator_stake_info = validator_stakes.first().unwrap(); - let transient_stake_info = validator_stakes.last().unwrap(); - if check_validator_stake_address( - program_id, - stake_pool_info.key, - validator_stake_info.key, - &validator_stake_record.vote_account_address, - ) - .is_err() - { - continue; - }; - if check_transient_stake_address( - program_id, - stake_pool_info.key, - transient_stake_info.key, - &validator_stake_record.vote_account_address, - validator_stake_record.transient_seed_suffix_start, - ) - .is_err() - { - continue; - }; - - let mut active_stake_lamports = 0; - let mut transient_stake_lamports = 0; - let validator_stake_state = try_from_slice_unchecked::( - &validator_stake_info.data.borrow(), - ) - .ok(); - let transient_stake_state = try_from_slice_unchecked::( - &transient_stake_info.data.borrow(), - ) - .ok(); - - // Possible merge situations for transient stake - // * active -> merge into validator stake - // * activating -> nothing, just account its lamports - // * deactivating -> nothing, just account its lamports - // * inactive -> merge into reserve stake - // * not a stake -> ignore - match transient_stake_state { - Some(stake::state::StakeState::Initialized(meta)) => { - if stake_is_usable_by_pool( - &meta, - withdraw_authority_info.key, - &stake_pool.lockup, - ) { - if no_merge { - transient_stake_lamports = transient_stake_info.lamports(); - } else { - // merge into reserve - Self::stake_merge( - stake_pool_info.key, - transient_stake_info.clone(), - withdraw_authority_info.clone(), - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - reserve_stake_info.clone(), - clock_info.clone(), - stake_history_info.clone(), - stake_program_info.clone(), - )?; - if validator_stake_record.status == StakeStatus::DeactivatingTransient { - // the validator stake was previously removed, and - // now this entry can be removed totally - validator_stake_record.status = StakeStatus::ReadyForRemoval; - } - } - } - } - Some(stake::state::StakeState::Stake(meta, stake)) => { - if stake_is_usable_by_pool( - &meta, - withdraw_authority_info.key, - &stake_pool.lockup, - ) { - let account_stake = meta - .rent_exempt_reserve - .saturating_add(stake.delegation.stake); - if no_merge { - transient_stake_lamports = account_stake; - } else if stake.delegation.deactivation_epoch < clock.epoch { - // deactivated, merge into reserve - Self::stake_merge( - stake_pool_info.key, - transient_stake_info.clone(), - withdraw_authority_info.clone(), - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - reserve_stake_info.clone(), - clock_info.clone(), - stake_history_info.clone(), - stake_program_info.clone(), - )?; - if validator_stake_record.status == StakeStatus::DeactivatingTransient { - // the validator stake was previously removed, and - // now this entry can be removed totally - validator_stake_record.status = StakeStatus::ReadyForRemoval; - } - } else if stake.delegation.activation_epoch < clock.epoch { - if let Some(stake::state::StakeState::Stake(_, validator_stake)) = - validator_stake_state - { - if validator_stake.delegation.activation_epoch < clock.epoch { - let additional_lamports = transient_stake_info - .lamports() - .saturating_sub(stake.delegation.stake); - Self::stake_merge( - stake_pool_info.key, - transient_stake_info.clone(), - withdraw_authority_info.clone(), - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - validator_stake_info.clone(), - clock_info.clone(), - stake_history_info.clone(), - stake_program_info.clone(), - )?; - - // post merge of two active stakes, withdraw - // the extra back to the reserve - if additional_lamports > 0 { - Self::stake_withdraw( - stake_pool_info.key, - validator_stake_info.clone(), - withdraw_authority_info.clone(), - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - reserve_stake_info.clone(), - clock_info.clone(), - stake_history_info.clone(), - stake_program_info.clone(), - additional_lamports, - )?; - } - } else { - msg!("Stake activating or just active, not ready to merge"); - transient_stake_lamports = account_stake; - } - } else { - msg!("Transient stake is activating or active, but validator stake is not, need to add the validator stake account on {} back into the stake pool", stake.delegation.voter_pubkey); - transient_stake_lamports = account_stake; - } - } else { - msg!("Transient stake not ready to be merged anywhere"); - transient_stake_lamports = account_stake; - } - } - } - None - | Some(stake::state::StakeState::Uninitialized) - | Some(stake::state::StakeState::RewardsPool) => {} // do nothing - } - - // Status for validator stake - // * active -> do everything - // * any other state / not a stake -> error state, but account for transient stake - let validator_stake_state = try_from_slice_unchecked::( - &validator_stake_info.data.borrow(), - ) - .ok(); - match validator_stake_state { - Some(stake::state::StakeState::Stake(_, stake)) => { - if validator_stake_record.status == StakeStatus::Active { - active_stake_lamports = stake - .delegation - .stake - .checked_sub(MINIMUM_ACTIVE_STAKE) - .ok_or(StakePoolError::CalculationFailure)?; - } else { - msg!("Validator stake account no longer part of the pool, ignoring"); - } - } - Some(stake::state::StakeState::Initialized(meta)) - if stake_is_usable_by_pool( - &meta, - withdraw_authority_info.key, - &stake_pool.lockup, - ) => - { - // If a validator stake is `Initialized`, the validator could - // have been destaked during a cluster restart. Either way, - // absorb those lamports into the reserve. The transient - // stake was likely absorbed into the reserve earlier. - Self::stake_merge( - stake_pool_info.key, - validator_stake_info.clone(), - withdraw_authority_info.clone(), - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - reserve_stake_info.clone(), - clock_info.clone(), - stake_history_info.clone(), - stake_program_info.clone(), - )?; - validator_stake_record.status = StakeStatus::ReadyForRemoval; - } - Some(stake::state::StakeState::Initialized(_)) - | Some(stake::state::StakeState::Uninitialized) - | Some(stake::state::StakeState::RewardsPool) - | None => { - msg!("Validator stake account no longer part of the pool, ignoring"); - } - } - - validator_stake_record.last_update_epoch = clock.epoch; - validator_stake_record.active_stake_lamports = active_stake_lamports; - validator_stake_record.transient_stake_lamports = transient_stake_lamports; - } - - Ok(()) - } - - /// Processes `UpdateStakePoolBalance` instruction. - #[inline(always)] // needed to optimize number of validators - fn process_update_stake_pool_balance( - program_id: &Pubkey, - accounts: &[AccountInfo], - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let stake_pool_info = next_account_info(account_info_iter)?; - let withdraw_info = next_account_info(account_info_iter)?; - let validator_list_info = next_account_info(account_info_iter)?; - let reserve_stake_info = next_account_info(account_info_iter)?; - let manager_fee_info = next_account_info(account_info_iter)?; - let pool_mint_info = next_account_info(account_info_iter)?; - let token_program_info = next_account_info(account_info_iter)?; - let clock = Clock::get()?; - - check_account_owner(stake_pool_info, program_id)?; - let mut stake_pool = try_from_slice_unchecked::(&stake_pool_info.data.borrow())?; - if !stake_pool.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - stake_pool.check_mint(pool_mint_info)?; - stake_pool.check_authority_withdraw(withdraw_info.key, program_id, stake_pool_info.key)?; - stake_pool.check_reserve_stake(reserve_stake_info)?; - if stake_pool.manager_fee_account != *manager_fee_info.key { - return Err(StakePoolError::InvalidFeeAccount.into()); - } - - if *validator_list_info.key != stake_pool.validator_list { - return Err(StakePoolError::InvalidValidatorStakeList.into()); - } - if stake_pool.token_program_id != *token_program_info.key { - return Err(ProgramError::IncorrectProgramId); - } - - check_account_owner(validator_list_info, program_id)?; - let mut validator_list_data = validator_list_info.data.borrow_mut(); - let (header, validator_list) = - ValidatorListHeader::deserialize_vec(&mut validator_list_data)?; - if !header.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - - let previous_lamports = stake_pool.total_lamports; - let previous_pool_token_supply = stake_pool.pool_token_supply; - let reserve_stake = try_from_slice_unchecked::( - &reserve_stake_info.data.borrow(), - )?; - let mut total_lamports = if let stake::state::StakeState::Initialized(meta) = reserve_stake - { - reserve_stake_info - .lamports() - .checked_sub(minimum_reserve_lamports(&meta)) - .ok_or(StakePoolError::CalculationFailure)? - } else { - msg!("Reserve stake account in unknown state, aborting"); - return Err(StakePoolError::WrongStakeState.into()); - }; - for validator_stake_record in validator_list.iter::() { - if validator_stake_record.last_update_epoch < clock.epoch { - return Err(StakePoolError::StakeListOutOfDate.into()); - } - total_lamports = total_lamports - .checked_add(validator_stake_record.stake_lamports()) - .ok_or(StakePoolError::CalculationFailure)?; - } - - let reward_lamports = total_lamports.saturating_sub(previous_lamports); - - // If the manager fee info is invalid, they don't deserve to receive the fee. - let fee = if stake_pool.check_manager_fee_info(manager_fee_info).is_ok() { - stake_pool - .calc_epoch_fee_amount(reward_lamports) - .ok_or(StakePoolError::CalculationFailure)? - } else { - 0 - }; - - if fee > 0 { - Self::token_mint_to( - stake_pool_info.key, - token_program_info.clone(), - pool_mint_info.clone(), - manager_fee_info.clone(), - withdraw_info.clone(), - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - fee, - )?; - } - - if stake_pool.last_update_epoch < clock.epoch { - if let Some(fee) = stake_pool.next_epoch_fee { - stake_pool.epoch_fee = fee; - stake_pool.next_epoch_fee = None; - } - if let Some(fee) = stake_pool.next_stake_withdrawal_fee { - stake_pool.stake_withdrawal_fee = fee; - stake_pool.next_stake_withdrawal_fee = None; - } - if let Some(fee) = stake_pool.next_sol_withdrawal_fee { - stake_pool.sol_withdrawal_fee = fee; - stake_pool.next_sol_withdrawal_fee = None; - } - stake_pool.last_update_epoch = clock.epoch; - stake_pool.last_epoch_total_lamports = previous_lamports; - stake_pool.last_epoch_pool_token_supply = previous_pool_token_supply; - } - stake_pool.total_lamports = total_lamports; - - let pool_mint = Mint::unpack_from_slice(&pool_mint_info.data.borrow())?; - stake_pool.pool_token_supply = pool_mint.supply; - - stake_pool.serialize(&mut *stake_pool_info.data.borrow_mut())?; - - Ok(()) - } - - /// Processes the `CleanupRemovedValidatorEntries` instruction - #[inline(never)] // needed to avoid stack size violation - fn process_cleanup_removed_validator_entries( - program_id: &Pubkey, - accounts: &[AccountInfo], - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let stake_pool_info = next_account_info(account_info_iter)?; - let validator_list_info = next_account_info(account_info_iter)?; - - check_account_owner(stake_pool_info, program_id)?; - let stake_pool = try_from_slice_unchecked::(&stake_pool_info.data.borrow())?; - if !stake_pool.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - stake_pool.check_validator_list(validator_list_info)?; - - check_account_owner(validator_list_info, program_id)?; - let mut validator_list_data = validator_list_info.data.borrow_mut(); - let (header, mut validator_list) = - ValidatorListHeader::deserialize_vec(&mut validator_list_data)?; - if !header.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - - validator_list.retain::(ValidatorStakeInfo::is_not_removed)?; - - Ok(()) - } - - /// Processes [DepositStake](enum.Instruction.html). - #[inline(never)] // needed to avoid stack size violation - fn process_deposit_stake(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let stake_pool_info = next_account_info(account_info_iter)?; - let validator_list_info = next_account_info(account_info_iter)?; - let stake_deposit_authority_info = next_account_info(account_info_iter)?; - let withdraw_authority_info = next_account_info(account_info_iter)?; - let stake_info = next_account_info(account_info_iter)?; - let validator_stake_account_info = next_account_info(account_info_iter)?; - let reserve_stake_account_info = next_account_info(account_info_iter)?; - let dest_user_pool_info = next_account_info(account_info_iter)?; - let manager_fee_info = next_account_info(account_info_iter)?; - let referrer_fee_info = next_account_info(account_info_iter)?; - let pool_mint_info = next_account_info(account_info_iter)?; - let clock_info = next_account_info(account_info_iter)?; - let clock = &Clock::from_account_info(clock_info)?; - let stake_history_info = next_account_info(account_info_iter)?; - let token_program_info = next_account_info(account_info_iter)?; - let stake_program_info = next_account_info(account_info_iter)?; - - check_stake_program(stake_program_info.key)?; - - check_account_owner(stake_pool_info, program_id)?; - let mut stake_pool = try_from_slice_unchecked::(&stake_pool_info.data.borrow())?; - if !stake_pool.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - - stake_pool.check_authority_withdraw( - withdraw_authority_info.key, - program_id, - stake_pool_info.key, - )?; - stake_pool.check_stake_deposit_authority(stake_deposit_authority_info.key)?; - stake_pool.check_mint(pool_mint_info)?; - stake_pool.check_validator_list(validator_list_info)?; - stake_pool.check_reserve_stake(reserve_stake_account_info)?; - - if stake_pool.token_program_id != *token_program_info.key { - return Err(ProgramError::IncorrectProgramId); - } - - if stake_pool.manager_fee_account != *manager_fee_info.key { - return Err(StakePoolError::InvalidFeeAccount.into()); - } - - if stake_pool.last_update_epoch < clock.epoch { - return Err(StakePoolError::StakeListAndPoolOutOfDate.into()); - } - - check_account_owner(validator_list_info, program_id)?; - let mut validator_list_data = validator_list_info.data.borrow_mut(); - let (header, mut validator_list) = - ValidatorListHeader::deserialize_vec(&mut validator_list_data)?; - if !header.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - - let (_, validator_stake) = get_stake_state(validator_stake_account_info)?; - let pre_all_validator_lamports = validator_stake_account_info.lamports(); - let vote_account_address = validator_stake.delegation.voter_pubkey; - check_validator_stake_address( - program_id, - stake_pool_info.key, - validator_stake_account_info.key, - &vote_account_address, - )?; - if let Some(preferred_deposit) = stake_pool.preferred_deposit_validator_vote_address { - if preferred_deposit != vote_account_address { - msg!( - "Incorrect deposit address, expected {}, received {}", - preferred_deposit, - vote_account_address - ); - return Err(StakePoolError::IncorrectDepositVoteAddress.into()); - } - } - - let mut validator_stake_info = validator_list - .find_mut::( - vote_account_address.as_ref(), - ValidatorStakeInfo::memcmp_pubkey, - ) - .ok_or(StakePoolError::ValidatorNotFound)?; - - if validator_stake_info.status != StakeStatus::Active { - msg!("Validator is marked for removal and no longer accepting deposits"); - return Err(StakePoolError::ValidatorNotFound.into()); - } - - msg!("Stake pre merge {}", validator_stake.delegation.stake); - - let (stake_deposit_authority_program_address, deposit_bump_seed) = - find_deposit_authority_program_address(program_id, stake_pool_info.key); - if *stake_deposit_authority_info.key == stake_deposit_authority_program_address { - Self::stake_authorize_signed( - stake_pool_info.key, - stake_info.clone(), - stake_deposit_authority_info.clone(), - AUTHORITY_DEPOSIT, - deposit_bump_seed, - withdraw_authority_info.key, - clock_info.clone(), - stake_program_info.clone(), - )?; - } else { - Self::stake_authorize( - stake_info.clone(), - stake_deposit_authority_info.clone(), - withdraw_authority_info.key, - clock_info.clone(), - stake_program_info.clone(), - )?; - } - - Self::stake_merge( - stake_pool_info.key, - stake_info.clone(), - withdraw_authority_info.clone(), - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - validator_stake_account_info.clone(), - clock_info.clone(), - stake_history_info.clone(), - stake_program_info.clone(), - )?; - - let (_, post_validator_stake) = get_stake_state(validator_stake_account_info)?; - let post_all_validator_lamports = validator_stake_account_info.lamports(); - msg!("Stake post merge {}", post_validator_stake.delegation.stake); - - let total_deposit_lamports = post_all_validator_lamports - .checked_sub(pre_all_validator_lamports) - .ok_or(StakePoolError::CalculationFailure)?; - let stake_deposit_lamports = post_validator_stake - .delegation - .stake - .checked_sub(validator_stake.delegation.stake) - .ok_or(StakePoolError::CalculationFailure)?; - let sol_deposit_lamports = total_deposit_lamports - .checked_sub(stake_deposit_lamports) - .ok_or(StakePoolError::CalculationFailure)?; - - let new_pool_tokens = stake_pool - .calc_pool_tokens_for_deposit(total_deposit_lamports) - .ok_or(StakePoolError::CalculationFailure)?; - let new_pool_tokens_from_stake = stake_pool - .calc_pool_tokens_for_deposit(stake_deposit_lamports) - .ok_or(StakePoolError::CalculationFailure)?; - let new_pool_tokens_from_sol = new_pool_tokens - .checked_sub(new_pool_tokens_from_stake) - .ok_or(StakePoolError::CalculationFailure)?; - - let stake_deposit_fee = stake_pool - .calc_pool_tokens_stake_deposit_fee(new_pool_tokens_from_stake) - .ok_or(StakePoolError::CalculationFailure)?; - let sol_deposit_fee = stake_pool - .calc_pool_tokens_sol_deposit_fee(new_pool_tokens_from_sol) - .ok_or(StakePoolError::CalculationFailure)?; - - let total_fee = stake_deposit_fee - .checked_add(sol_deposit_fee) - .ok_or(StakePoolError::CalculationFailure)?; - let pool_tokens_user = new_pool_tokens - .checked_sub(total_fee) - .ok_or(StakePoolError::CalculationFailure)?; - - let pool_tokens_referral_fee = stake_pool - .calc_pool_tokens_stake_referral_fee(total_fee) - .ok_or(StakePoolError::CalculationFailure)?; - - let pool_tokens_manager_deposit_fee = total_fee - .checked_sub(pool_tokens_referral_fee) - .ok_or(StakePoolError::CalculationFailure)?; - - if pool_tokens_user - .saturating_add(pool_tokens_manager_deposit_fee) - .saturating_add(pool_tokens_referral_fee) - != new_pool_tokens - { - return Err(StakePoolError::CalculationFailure.into()); - } - - if pool_tokens_user == 0 { - return Err(StakePoolError::DepositTooSmall.into()); - } - - Self::token_mint_to( - stake_pool_info.key, - token_program_info.clone(), - pool_mint_info.clone(), - dest_user_pool_info.clone(), - withdraw_authority_info.clone(), - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - pool_tokens_user, - )?; - if pool_tokens_manager_deposit_fee > 0 { - Self::token_mint_to( - stake_pool_info.key, - token_program_info.clone(), - pool_mint_info.clone(), - manager_fee_info.clone(), - withdraw_authority_info.clone(), - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - pool_tokens_manager_deposit_fee, - )?; - } - if pool_tokens_referral_fee > 0 { - Self::token_mint_to( - stake_pool_info.key, - token_program_info.clone(), - pool_mint_info.clone(), - referrer_fee_info.clone(), - withdraw_authority_info.clone(), - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - pool_tokens_referral_fee, - )?; - } - - // withdraw additional lamports to the reserve - if sol_deposit_lamports > 0 { - Self::stake_withdraw( - stake_pool_info.key, - validator_stake_account_info.clone(), - withdraw_authority_info.clone(), - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - reserve_stake_account_info.clone(), - clock_info.clone(), - stake_history_info.clone(), - stake_program_info.clone(), - sol_deposit_lamports, - )?; - } - - stake_pool.pool_token_supply = stake_pool - .pool_token_supply - .checked_add(new_pool_tokens) - .ok_or(StakePoolError::CalculationFailure)?; - // We treat the extra lamports as though they were - // transferred directly to the reserve stake account. - stake_pool.total_lamports = stake_pool - .total_lamports - .checked_add(total_deposit_lamports) - .ok_or(StakePoolError::CalculationFailure)?; - stake_pool.serialize(&mut *stake_pool_info.data.borrow_mut())?; - - validator_stake_info.active_stake_lamports = post_validator_stake - .delegation - .stake - .checked_sub(MINIMUM_ACTIVE_STAKE) - .ok_or(StakePoolError::CalculationFailure)?; - - Ok(()) - } - - /// Processes [DepositSol](enum.Instruction.html). - #[inline(never)] // needed to avoid stack size violation - fn process_deposit_sol( - program_id: &Pubkey, - accounts: &[AccountInfo], - deposit_lamports: u64, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let stake_pool_info = next_account_info(account_info_iter)?; - let withdraw_authority_info = next_account_info(account_info_iter)?; - let reserve_stake_account_info = next_account_info(account_info_iter)?; - let from_user_lamports_info = next_account_info(account_info_iter)?; - let dest_user_pool_info = next_account_info(account_info_iter)?; - let manager_fee_info = next_account_info(account_info_iter)?; - let referrer_fee_info = next_account_info(account_info_iter)?; - let pool_mint_info = next_account_info(account_info_iter)?; - let system_program_info = next_account_info(account_info_iter)?; - let token_program_info = next_account_info(account_info_iter)?; - let sol_deposit_authority_info = next_account_info(account_info_iter); - - let clock = Clock::get()?; - - check_account_owner(stake_pool_info, program_id)?; - let mut stake_pool = try_from_slice_unchecked::(&stake_pool_info.data.borrow())?; - if !stake_pool.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - - stake_pool.check_authority_withdraw( - withdraw_authority_info.key, - program_id, - stake_pool_info.key, - )?; - stake_pool.check_sol_deposit_authority(sol_deposit_authority_info)?; - stake_pool.check_mint(pool_mint_info)?; - stake_pool.check_reserve_stake(reserve_stake_account_info)?; - - if stake_pool.token_program_id != *token_program_info.key { - return Err(ProgramError::IncorrectProgramId); - } - check_system_program(system_program_info.key)?; - - if stake_pool.manager_fee_account != *manager_fee_info.key { - return Err(StakePoolError::InvalidFeeAccount.into()); - } - - // We want this to hold to ensure that deposit_sol mints pool tokens - // at the right price - if stake_pool.last_update_epoch < clock.epoch { - return Err(StakePoolError::StakeListAndPoolOutOfDate.into()); - } - - let new_pool_tokens = stake_pool - .calc_pool_tokens_for_deposit(deposit_lamports) - .ok_or(StakePoolError::CalculationFailure)?; - - let pool_tokens_sol_deposit_fee = stake_pool - .calc_pool_tokens_sol_deposit_fee(new_pool_tokens) - .ok_or(StakePoolError::CalculationFailure)?; - let pool_tokens_user = new_pool_tokens - .checked_sub(pool_tokens_sol_deposit_fee) - .ok_or(StakePoolError::CalculationFailure)?; - - let pool_tokens_referral_fee = stake_pool - .calc_pool_tokens_sol_referral_fee(pool_tokens_sol_deposit_fee) - .ok_or(StakePoolError::CalculationFailure)?; - let pool_tokens_manager_deposit_fee = pool_tokens_sol_deposit_fee - .checked_sub(pool_tokens_referral_fee) - .ok_or(StakePoolError::CalculationFailure)?; - - if pool_tokens_user - .saturating_add(pool_tokens_manager_deposit_fee) - .saturating_add(pool_tokens_referral_fee) - != new_pool_tokens - { - return Err(StakePoolError::CalculationFailure.into()); - } - - if pool_tokens_user == 0 { - return Err(StakePoolError::DepositTooSmall.into()); - } - - Self::sol_transfer( - from_user_lamports_info.clone(), - reserve_stake_account_info.clone(), - system_program_info.clone(), - deposit_lamports, - )?; - - Self::token_mint_to( - stake_pool_info.key, - token_program_info.clone(), - pool_mint_info.clone(), - dest_user_pool_info.clone(), - withdraw_authority_info.clone(), - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - pool_tokens_user, - )?; - - if pool_tokens_manager_deposit_fee > 0 { - Self::token_mint_to( - stake_pool_info.key, - token_program_info.clone(), - pool_mint_info.clone(), - manager_fee_info.clone(), - withdraw_authority_info.clone(), - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - pool_tokens_manager_deposit_fee, - )?; - } - - if pool_tokens_referral_fee > 0 { - Self::token_mint_to( - stake_pool_info.key, - token_program_info.clone(), - pool_mint_info.clone(), - referrer_fee_info.clone(), - withdraw_authority_info.clone(), - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - pool_tokens_referral_fee, - )?; - } - - stake_pool.pool_token_supply = stake_pool - .pool_token_supply - .checked_add(new_pool_tokens) - .ok_or(StakePoolError::CalculationFailure)?; - stake_pool.total_lamports = stake_pool - .total_lamports - .checked_add(deposit_lamports) - .ok_or(StakePoolError::CalculationFailure)?; - stake_pool.serialize(&mut *stake_pool_info.data.borrow_mut())?; - - Ok(()) - } - - /// Processes [WithdrawStake](enum.Instruction.html). - #[inline(never)] // needed to avoid stack size violation - fn process_withdraw_stake( - program_id: &Pubkey, - accounts: &[AccountInfo], - pool_tokens: u64, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let stake_pool_info = next_account_info(account_info_iter)?; - let validator_list_info = next_account_info(account_info_iter)?; - let withdraw_authority_info = next_account_info(account_info_iter)?; - let stake_split_from = next_account_info(account_info_iter)?; - let stake_split_to = next_account_info(account_info_iter)?; - let user_stake_authority_info = next_account_info(account_info_iter)?; - let user_transfer_authority_info = next_account_info(account_info_iter)?; - let burn_from_pool_info = next_account_info(account_info_iter)?; - let manager_fee_info = next_account_info(account_info_iter)?; - let pool_mint_info = next_account_info(account_info_iter)?; - let clock_info = next_account_info(account_info_iter)?; - let clock = &Clock::from_account_info(clock_info)?; - let token_program_info = next_account_info(account_info_iter)?; - let stake_program_info = next_account_info(account_info_iter)?; - - check_stake_program(stake_program_info.key)?; - check_account_owner(stake_pool_info, program_id)?; - let mut stake_pool = try_from_slice_unchecked::(&stake_pool_info.data.borrow())?; - if !stake_pool.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - - stake_pool.check_mint(pool_mint_info)?; - stake_pool.check_validator_list(validator_list_info)?; - stake_pool.check_authority_withdraw( - withdraw_authority_info.key, - program_id, - stake_pool_info.key, - )?; - - if stake_pool.manager_fee_account != *manager_fee_info.key { - return Err(StakePoolError::InvalidFeeAccount.into()); - } - if stake_pool.token_program_id != *token_program_info.key { - return Err(ProgramError::IncorrectProgramId); - } - - if stake_pool.last_update_epoch < clock.epoch { - return Err(StakePoolError::StakeListAndPoolOutOfDate.into()); - } - - check_account_owner(validator_list_info, program_id)?; - let mut validator_list_data = validator_list_info.data.borrow_mut(); - let (header, mut validator_list) = - ValidatorListHeader::deserialize_vec(&mut validator_list_data)?; - if !header.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - - // To prevent a faulty manager fee account from preventing withdrawals - // if the token program does not own the account, or if the account is not initialized - let pool_tokens_fee = if stake_pool.manager_fee_account == *burn_from_pool_info.key - || stake_pool.check_manager_fee_info(manager_fee_info).is_err() - { - 0 - } else { - stake_pool - .calc_pool_tokens_stake_withdrawal_fee(pool_tokens) - .ok_or(StakePoolError::CalculationFailure)? - }; - let pool_tokens_burnt = pool_tokens - .checked_sub(pool_tokens_fee) - .ok_or(StakePoolError::CalculationFailure)?; - - let withdraw_lamports = stake_pool - .calc_lamports_withdraw_amount(pool_tokens_burnt) - .ok_or(StakePoolError::CalculationFailure)?; - - if withdraw_lamports == 0 { - return Err(StakePoolError::WithdrawalTooSmall.into()); - } - - let has_active_stake = validator_list - .find::( - &0u64.to_le_bytes(), - ValidatorStakeInfo::active_lamports_not_equal, - ) - .is_some(); - - let validator_list_item_info = if *stake_split_from.key == stake_pool.reserve_stake { - // check that the validator stake accounts have no withdrawable stake - let has_transient_stake = validator_list - .find::( - &0u64.to_le_bytes(), - ValidatorStakeInfo::transient_lamports_not_equal, - ) - .is_some(); - if has_transient_stake || has_active_stake { - msg!("Error withdrawing from reserve: validator stake accounts have lamports available, please use those first."); - return Err(StakePoolError::StakeLamportsNotEqualToMinimum.into()); - } - - // check that reserve has enough (should never fail, but who knows?) - let stake_state = try_from_slice_unchecked::( - &stake_split_from.data.borrow(), - )?; - let meta = stake_state.meta().ok_or(StakePoolError::WrongStakeState)?; - stake_split_from - .lamports() - .checked_sub(minimum_reserve_lamports(&meta)) - .ok_or(StakePoolError::StakeLamportsNotEqualToMinimum)?; - None - } else { - let (_, stake) = get_stake_state(stake_split_from)?; - let vote_account_address = stake.delegation.voter_pubkey; - - if let Some(preferred_withdraw_validator) = - stake_pool.preferred_withdraw_validator_vote_address - { - let preferred_validator_info = validator_list - .find::( - preferred_withdraw_validator.as_ref(), - ValidatorStakeInfo::memcmp_pubkey, - ) - .ok_or(StakePoolError::ValidatorNotFound)?; - if preferred_withdraw_validator != vote_account_address - && preferred_validator_info.active_stake_lamports > 0 - { - msg!("Validator vote address {} is preferred for withdrawals, it currently has {} lamports available. Please withdraw those before using other validator stake accounts.", preferred_withdraw_validator, preferred_validator_info.active_stake_lamports); - return Err(StakePoolError::IncorrectWithdrawVoteAddress.into()); - } - } - - let validator_stake_info = validator_list - .find_mut::( - vote_account_address.as_ref(), - ValidatorStakeInfo::memcmp_pubkey, - ) - .ok_or(StakePoolError::ValidatorNotFound)?; - - // if there's any active stake, we must withdraw from an active - // stake account - let withdrawing_from_transient_stake = if has_active_stake { - check_validator_stake_address( - program_id, - stake_pool_info.key, - stake_split_from.key, - &vote_account_address, - )?; - false - } else { - check_transient_stake_address( - program_id, - stake_pool_info.key, - stake_split_from.key, - &vote_account_address, - validator_stake_info.transient_seed_suffix_start, - )?; - true - }; - - if validator_stake_info.status != StakeStatus::Active { - msg!("Validator is marked for removal and no longer allowing withdrawals"); - return Err(StakePoolError::ValidatorNotFound.into()); - } - - let remaining_lamports = stake.delegation.stake.saturating_sub(withdraw_lamports); - if remaining_lamports < MINIMUM_ACTIVE_STAKE { - msg!("Attempting to withdraw {} lamports from validator account with {} stake lamports, {} must remain", withdraw_lamports, stake.delegation.stake, MINIMUM_ACTIVE_STAKE); - return Err(StakePoolError::StakeLamportsNotEqualToMinimum.into()); - } - Some((validator_stake_info, withdrawing_from_transient_stake)) - }; - - Self::token_burn( - token_program_info.clone(), - burn_from_pool_info.clone(), - pool_mint_info.clone(), - user_transfer_authority_info.clone(), - pool_tokens_burnt, - )?; - - Self::stake_split( - stake_pool_info.key, - stake_split_from.clone(), - withdraw_authority_info.clone(), - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - withdraw_lamports, - stake_split_to.clone(), - )?; - - Self::stake_authorize_signed( - stake_pool_info.key, - stake_split_to.clone(), - withdraw_authority_info.clone(), - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - user_stake_authority_info.key, - clock_info.clone(), - stake_program_info.clone(), - )?; - - if pool_tokens_fee > 0 { - Self::token_transfer( - token_program_info.clone(), - burn_from_pool_info.clone(), - manager_fee_info.clone(), - user_transfer_authority_info.clone(), - pool_tokens_fee, - )?; - } - - stake_pool.pool_token_supply = stake_pool - .pool_token_supply - .checked_sub(pool_tokens_burnt) - .ok_or(StakePoolError::CalculationFailure)?; - stake_pool.total_lamports = stake_pool - .total_lamports - .checked_sub(withdraw_lamports) - .ok_or(StakePoolError::CalculationFailure)?; - stake_pool.serialize(&mut *stake_pool_info.data.borrow_mut())?; - - if let Some((validator_list_item, withdrawing_from_transient_stake_account)) = - validator_list_item_info - { - if withdrawing_from_transient_stake_account { - validator_list_item.transient_stake_lamports = validator_list_item - .transient_stake_lamports - .checked_sub(withdraw_lamports) - .ok_or(StakePoolError::CalculationFailure)?; - } else { - validator_list_item.active_stake_lamports = validator_list_item - .active_stake_lamports - .checked_sub(withdraw_lamports) - .ok_or(StakePoolError::CalculationFailure)?; - } - } - - Ok(()) - } - - /// Processes [WithdrawSol](enum.Instruction.html). - #[inline(never)] // needed to avoid stack size violation - fn process_withdraw_sol( - program_id: &Pubkey, - accounts: &[AccountInfo], - pool_tokens: u64, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let stake_pool_info = next_account_info(account_info_iter)?; - let withdraw_authority_info = next_account_info(account_info_iter)?; - let user_transfer_authority_info = next_account_info(account_info_iter)?; - let burn_from_pool_info = next_account_info(account_info_iter)?; - let reserve_stake_info = next_account_info(account_info_iter)?; - let destination_lamports_info = next_account_info(account_info_iter)?; - let manager_fee_info = next_account_info(account_info_iter)?; - let pool_mint_info = next_account_info(account_info_iter)?; - let clock_info = next_account_info(account_info_iter)?; - let stake_history_info = next_account_info(account_info_iter)?; - let stake_program_info = next_account_info(account_info_iter)?; - let token_program_info = next_account_info(account_info_iter)?; - let sol_withdraw_authority_info = next_account_info(account_info_iter); - - check_account_owner(stake_pool_info, program_id)?; - let mut stake_pool = try_from_slice_unchecked::(&stake_pool_info.data.borrow())?; - if !stake_pool.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - - stake_pool.check_authority_withdraw( - withdraw_authority_info.key, - program_id, - stake_pool_info.key, - )?; - stake_pool.check_sol_withdraw_authority(sol_withdraw_authority_info)?; - stake_pool.check_mint(pool_mint_info)?; - stake_pool.check_reserve_stake(reserve_stake_info)?; - - if stake_pool.token_program_id != *token_program_info.key { - return Err(ProgramError::IncorrectProgramId); - } - check_stake_program(stake_program_info.key)?; - - if stake_pool.manager_fee_account != *manager_fee_info.key { - return Err(StakePoolError::InvalidFeeAccount.into()); - } - - // We want this to hold to ensure that withdraw_sol burns pool tokens - // at the right price - if stake_pool.last_update_epoch < Clock::get()?.epoch { - return Err(StakePoolError::StakeListAndPoolOutOfDate.into()); - } - - // To prevent a faulty manager fee account from preventing withdrawals - // if the token program does not own the account, or if the account is not initialized - let pool_tokens_fee = if stake_pool.manager_fee_account == *burn_from_pool_info.key - || stake_pool.check_manager_fee_info(manager_fee_info).is_err() - { - 0 - } else { - stake_pool - .calc_pool_tokens_sol_withdrawal_fee(pool_tokens) - .ok_or(StakePoolError::CalculationFailure)? - }; - let pool_tokens_burnt = pool_tokens - .checked_sub(pool_tokens_fee) - .ok_or(StakePoolError::CalculationFailure)?; - - let withdraw_lamports = stake_pool - .calc_lamports_withdraw_amount(pool_tokens_burnt) - .ok_or(StakePoolError::CalculationFailure)?; - - if withdraw_lamports == 0 { - return Err(StakePoolError::WithdrawalTooSmall.into()); - } - - let new_reserve_lamports = reserve_stake_info - .lamports() - .saturating_sub(withdraw_lamports); - let stake_state = try_from_slice_unchecked::( - &reserve_stake_info.data.borrow(), - )?; - if let stake::state::StakeState::Initialized(meta) = stake_state { - let minimum_reserve_lamports = minimum_reserve_lamports(&meta); - if new_reserve_lamports < minimum_reserve_lamports { - msg!("Attempting to withdraw {} lamports, maximum possible SOL withdrawal is {} lamports", - withdraw_lamports, - reserve_stake_info.lamports().saturating_sub(minimum_reserve_lamports) - ); - return Err(StakePoolError::SolWithdrawalTooLarge.into()); - } - } else { - msg!("Reserve stake account not in intialized state"); - return Err(StakePoolError::WrongStakeState.into()); - }; - - Self::token_burn( - token_program_info.clone(), - burn_from_pool_info.clone(), - pool_mint_info.clone(), - user_transfer_authority_info.clone(), - pool_tokens_burnt, - )?; - - if pool_tokens_fee > 0 { - Self::token_transfer( - token_program_info.clone(), - burn_from_pool_info.clone(), - manager_fee_info.clone(), - user_transfer_authority_info.clone(), - pool_tokens_fee, - )?; - } - - Self::stake_withdraw( - stake_pool_info.key, - reserve_stake_info.clone(), - withdraw_authority_info.clone(), - AUTHORITY_WITHDRAW, - stake_pool.stake_withdraw_bump_seed, - destination_lamports_info.clone(), - clock_info.clone(), - stake_history_info.clone(), - stake_program_info.clone(), - withdraw_lamports, - )?; - - stake_pool.pool_token_supply = stake_pool - .pool_token_supply - .checked_sub(pool_tokens_burnt) - .ok_or(StakePoolError::CalculationFailure)?; - stake_pool.total_lamports = stake_pool - .total_lamports - .checked_sub(withdraw_lamports) - .ok_or(StakePoolError::CalculationFailure)?; - stake_pool.serialize(&mut *stake_pool_info.data.borrow_mut())?; - - Ok(()) - } - - #[inline(never)] - fn process_create_pool_token_metadata( - program_id: &Pubkey, - accounts: &[AccountInfo], - name: String, - symbol: String, - uri: String, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let stake_pool_info = next_account_info(account_info_iter)?; - let manager_info = next_account_info(account_info_iter)?; - let withdraw_authority_info = next_account_info(account_info_iter)?; - let pool_mint_info = next_account_info(account_info_iter)?; - let payer_info = next_account_info(account_info_iter)?; - let metadata_info = next_account_info(account_info_iter)?; - let mpl_token_metadata_program_info = next_account_info(account_info_iter)?; - let system_program_info = next_account_info(account_info_iter)?; - let rent_sysvar_info = next_account_info(account_info_iter)?; - - if !payer_info.is_signer { - msg!("Payer did not sign metadata creation"); - return Err(StakePoolError::SignatureMissing.into()); - } - - check_system_program(system_program_info.key)?; - check_rent_sysvar(rent_sysvar_info.key)?; - check_account_owner(payer_info, &system_program::id())?; - check_account_owner(stake_pool_info, program_id)?; - check_mpl_metadata_program(mpl_token_metadata_program_info.key)?; - - let stake_pool = try_from_slice_unchecked::(&stake_pool_info.data.borrow())?; - if !stake_pool.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - - stake_pool.check_manager(manager_info)?; - stake_pool.check_authority_withdraw( - withdraw_authority_info.key, - program_id, - stake_pool_info.key, - )?; - stake_pool.check_mint(pool_mint_info)?; - check_mpl_metadata_account_address(metadata_info.key, &stake_pool.pool_mint)?; - - // Token mint authority for stake-pool token is stake-pool withdraw authority - let token_mint_authority = withdraw_authority_info; - - let new_metadata_instruction = create_metadata_accounts_v3( - *mpl_token_metadata_program_info.key, - *metadata_info.key, - *pool_mint_info.key, - *token_mint_authority.key, - *payer_info.key, - *token_mint_authority.key, - name, - symbol, - uri, - None, - 0, - true, - true, - None, - None, - None, - ); - - let (_, stake_withdraw_bump_seed) = - crate::find_withdraw_authority_program_address(program_id, stake_pool_info.key); - - let token_mint_authority_signer_seeds: &[&[_]] = &[ - &stake_pool_info.key.to_bytes()[..32], - AUTHORITY_WITHDRAW, - &[stake_withdraw_bump_seed], - ]; - - invoke_signed( - &new_metadata_instruction, - &[ - metadata_info.clone(), - pool_mint_info.clone(), - withdraw_authority_info.clone(), - payer_info.clone(), - withdraw_authority_info.clone(), - system_program_info.clone(), - rent_sysvar_info.clone(), - mpl_token_metadata_program_info.clone(), - ], - &[token_mint_authority_signer_seeds], - )?; - - Ok(()) - } - - #[inline(never)] - fn process_update_pool_token_metadata( - program_id: &Pubkey, - accounts: &[AccountInfo], - name: String, - symbol: String, - uri: String, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - - let stake_pool_info = next_account_info(account_info_iter)?; - let manager_info = next_account_info(account_info_iter)?; - let withdraw_authority_info = next_account_info(account_info_iter)?; - let metadata_info = next_account_info(account_info_iter)?; - let mpl_token_metadata_program_info = next_account_info(account_info_iter)?; - - check_account_owner(stake_pool_info, program_id)?; - - check_mpl_metadata_program(mpl_token_metadata_program_info.key)?; - - let stake_pool = try_from_slice_unchecked::(&stake_pool_info.data.borrow())?; - if !stake_pool.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - - stake_pool.check_manager(manager_info)?; - stake_pool.check_authority_withdraw( - withdraw_authority_info.key, - program_id, - stake_pool_info.key, - )?; - check_mpl_metadata_account_address(metadata_info.key, &stake_pool.pool_mint)?; - - // Token mint authority for stake-pool token is withdraw authority only - let token_mint_authority = withdraw_authority_info; - - let update_metadata_accounts_instruction = update_metadata_accounts_v2( - *mpl_token_metadata_program_info.key, - *metadata_info.key, - *token_mint_authority.key, - None, - Some(DataV2 { - name, - symbol, - uri, - seller_fee_basis_points: 0, - creators: None, - collection: None, - uses: None, - }), - None, - Some(true), - ); - - let (_, stake_withdraw_bump_seed) = - crate::find_withdraw_authority_program_address(program_id, stake_pool_info.key); - - let token_mint_authority_signer_seeds: &[&[_]] = &[ - &stake_pool_info.key.to_bytes()[..32], - AUTHORITY_WITHDRAW, - &[stake_withdraw_bump_seed], - ]; - - invoke_signed( - &update_metadata_accounts_instruction, - &[ - metadata_info.clone(), - withdraw_authority_info.clone(), - mpl_token_metadata_program_info.clone(), - ], - &[token_mint_authority_signer_seeds], - )?; - - Ok(()) - } - - /// Processes [SetManager](enum.Instruction.html). - #[inline(never)] // needed to avoid stack size violation - fn process_set_manager(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let stake_pool_info = next_account_info(account_info_iter)?; - let manager_info = next_account_info(account_info_iter)?; - let new_manager_info = next_account_info(account_info_iter)?; - let new_manager_fee_info = next_account_info(account_info_iter)?; - - check_account_owner(stake_pool_info, program_id)?; - let mut stake_pool = try_from_slice_unchecked::(&stake_pool_info.data.borrow())?; - check_account_owner(new_manager_fee_info, &stake_pool.token_program_id)?; - if !stake_pool.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - - stake_pool.check_manager(manager_info)?; - if !new_manager_info.is_signer { - msg!("New manager signature missing"); - return Err(StakePoolError::SignatureMissing.into()); - } - - if stake_pool.pool_mint - != spl_token::state::Account::unpack_from_slice(&new_manager_fee_info.data.borrow())? - .mint - { - return Err(StakePoolError::WrongAccountMint.into()); - } - - stake_pool.manager = *new_manager_info.key; - stake_pool.manager_fee_account = *new_manager_fee_info.key; - stake_pool.serialize(&mut *stake_pool_info.data.borrow_mut())?; - Ok(()) - } - - /// Processes [SetFee](enum.Instruction.html). - #[inline(never)] // needed to avoid stack size violation - fn process_set_fee( - program_id: &Pubkey, - accounts: &[AccountInfo], - fee: FeeType, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let stake_pool_info = next_account_info(account_info_iter)?; - let manager_info = next_account_info(account_info_iter)?; - let clock = Clock::get()?; - - check_account_owner(stake_pool_info, program_id)?; - let mut stake_pool = try_from_slice_unchecked::(&stake_pool_info.data.borrow())?; - if !stake_pool.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - stake_pool.check_manager(manager_info)?; - - if fee.can_only_change_next_epoch() && stake_pool.last_update_epoch < clock.epoch { - return Err(StakePoolError::StakeListAndPoolOutOfDate.into()); - } - - fee.check_too_high()?; - stake_pool.update_fee(&fee)?; - stake_pool.serialize(&mut *stake_pool_info.data.borrow_mut())?; - Ok(()) - } - - /// Processes [SetStaker](enum.Instruction.html). - #[inline(never)] // needed to avoid stack size violation - fn process_set_staker(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let stake_pool_info = next_account_info(account_info_iter)?; - let set_staker_authority_info = next_account_info(account_info_iter)?; - let new_staker_info = next_account_info(account_info_iter)?; - - check_account_owner(stake_pool_info, program_id)?; - let mut stake_pool = try_from_slice_unchecked::(&stake_pool_info.data.borrow())?; - if !stake_pool.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - - let staker_signed = stake_pool.check_staker(set_staker_authority_info); - let manager_signed = stake_pool.check_manager(set_staker_authority_info); - if staker_signed.is_err() && manager_signed.is_err() { - return Err(StakePoolError::SignatureMissing.into()); - } - stake_pool.staker = *new_staker_info.key; - stake_pool.serialize(&mut *stake_pool_info.data.borrow_mut())?; - Ok(()) - } - - /// Processes [SetFundingAuthority](enum.Instruction.html). - #[inline(never)] // needed to avoid stack size violation - fn process_set_funding_authority( - program_id: &Pubkey, - accounts: &[AccountInfo], - funding_type: FundingType, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let stake_pool_info = next_account_info(account_info_iter)?; - let manager_info = next_account_info(account_info_iter)?; - - let new_authority = next_account_info(account_info_iter) - .ok() - .map(|new_authority_account_info| *new_authority_account_info.key); - - check_account_owner(stake_pool_info, program_id)?; - let mut stake_pool = try_from_slice_unchecked::(&stake_pool_info.data.borrow())?; - if !stake_pool.is_valid() { - return Err(StakePoolError::InvalidState.into()); - } - stake_pool.check_manager(manager_info)?; - match funding_type { - FundingType::StakeDeposit => { - stake_pool.stake_deposit_authority = new_authority.unwrap_or( - find_deposit_authority_program_address(program_id, stake_pool_info.key).0, - ); - } - FundingType::SolDeposit => stake_pool.sol_deposit_authority = new_authority, - FundingType::SolWithdraw => stake_pool.sol_withdraw_authority = new_authority, - } - stake_pool.serialize(&mut *stake_pool_info.data.borrow_mut())?; - Ok(()) - } - - /// Processes [Instruction](enum.Instruction.html). - pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult { - let instruction = StakePoolInstruction::try_from_slice(input)?; - match instruction { - StakePoolInstruction::Initialize { - fee, - withdrawal_fee, - deposit_fee, - referral_fee, - max_validators, - } => { - msg!("Instruction: Initialize stake pool"); - Self::process_initialize( - program_id, - accounts, - fee, - withdrawal_fee, - deposit_fee, - referral_fee, - max_validators, - ) - } - StakePoolInstruction::AddValidatorToPool => { - msg!("Instruction: AddValidatorToPool"); - Self::process_add_validator_to_pool(program_id, accounts) - } - StakePoolInstruction::RemoveValidatorFromPool => { - msg!("Instruction: RemoveValidatorFromPool"); - Self::process_remove_validator_from_pool(program_id, accounts) - } - StakePoolInstruction::DecreaseValidatorStake { - lamports, - transient_stake_seed, - } => { - msg!("Instruction: DecreaseValidatorStake"); - Self::process_decrease_validator_stake( - program_id, - accounts, - lamports, - transient_stake_seed, - ) - } - StakePoolInstruction::IncreaseValidatorStake { - lamports, - transient_stake_seed, - } => { - msg!("Instruction: IncreaseValidatorStake"); - Self::process_increase_validator_stake( - program_id, - accounts, - lamports, - transient_stake_seed, - ) - } - StakePoolInstruction::SetPreferredValidator { - validator_type, - validator_vote_address, - } => { - msg!("Instruction: SetPreferredValidator"); - Self::process_set_preferred_validator( - program_id, - accounts, - validator_type, - validator_vote_address, - ) - } - StakePoolInstruction::UpdateValidatorListBalance { - start_index, - no_merge, - } => { - msg!("Instruction: UpdateValidatorListBalance"); - Self::process_update_validator_list_balance( - program_id, - accounts, - start_index, - no_merge, - ) - } - StakePoolInstruction::UpdateStakePoolBalance => { - msg!("Instruction: UpdateStakePoolBalance"); - Self::process_update_stake_pool_balance(program_id, accounts) - } - StakePoolInstruction::CleanupRemovedValidatorEntries => { - msg!("Instruction: CleanupRemovedValidatorEntries"); - Self::process_cleanup_removed_validator_entries(program_id, accounts) - } - StakePoolInstruction::DepositStake => { - msg!("Instruction: DepositStake"); - Self::process_deposit_stake(program_id, accounts) - } - StakePoolInstruction::WithdrawStake(amount) => { - msg!("Instruction: WithdrawStake"); - Self::process_withdraw_stake(program_id, accounts, amount) - } - StakePoolInstruction::SetFee { fee } => { - msg!("Instruction: SetFee"); - Self::process_set_fee(program_id, accounts, fee) - } - StakePoolInstruction::SetManager => { - msg!("Instruction: SetManager"); - Self::process_set_manager(program_id, accounts) - } - StakePoolInstruction::SetStaker => { - msg!("Instruction: SetStaker"); - Self::process_set_staker(program_id, accounts) - } - StakePoolInstruction::SetFundingAuthority(funding_type) => { - msg!("Instruction: SetFundingAuthority"); - Self::process_set_funding_authority(program_id, accounts, funding_type) - } - StakePoolInstruction::DepositSol(lamports) => { - msg!("Instruction: DepositSol"); - Self::process_deposit_sol(program_id, accounts, lamports) - } - StakePoolInstruction::WithdrawSol(pool_tokens) => { - msg!("Instruction: WithdrawSol"); - Self::process_withdraw_sol(program_id, accounts, pool_tokens) - } - StakePoolInstruction::CreateTokenMetadata { name, symbol, uri } => { - msg!("Instruction: CreateTokenMetadata"); - Self::process_create_pool_token_metadata(program_id, accounts, name, symbol, uri) - } - StakePoolInstruction::UpdateTokenMetadata { name, symbol, uri } => { - msg!("Instruction: UpdateTokenMetadata"); - Self::process_update_pool_token_metadata(program_id, accounts, name, symbol, uri) - } - } - } -} - -impl PrintProgramError for StakePoolError { - fn print(&self) - where - E: 'static + std::error::Error + DecodeError + PrintProgramError + FromPrimitive, - { - match self { - StakePoolError::AlreadyInUse => msg!("Error: The account cannot be initialized because it is already being used"), - StakePoolError::InvalidProgramAddress => msg!("Error: The program address provided doesn't match the value generated by the program"), - StakePoolError::InvalidState => msg!("Error: The stake pool state is invalid"), - StakePoolError::CalculationFailure => msg!("Error: The calculation failed"), - StakePoolError::FeeTooHigh => msg!("Error: Stake pool fee > 1"), - StakePoolError::WrongAccountMint => msg!("Error: Token account is associated with the wrong mint"), - StakePoolError::WrongManager => msg!("Error: Wrong pool manager account"), - StakePoolError::SignatureMissing => msg!("Error: Required signature is missing"), - StakePoolError::InvalidValidatorStakeList => msg!("Error: Invalid validator stake list account"), - StakePoolError::InvalidFeeAccount => msg!("Error: Invalid manager fee account"), - StakePoolError::WrongPoolMint => msg!("Error: Specified pool mint account is wrong"), - StakePoolError::WrongStakeState => msg!("Error: Stake account is not in the state expected by the program"), - StakePoolError::UserStakeNotActive => msg!("Error: User stake is not active"), - StakePoolError::ValidatorAlreadyAdded => msg!("Error: Stake account voting for this validator already exists in the pool"), - StakePoolError::ValidatorNotFound => msg!("Error: Stake account for this validator not found in the pool"), - StakePoolError::InvalidStakeAccountAddress => msg!("Error: Stake account address not properly derived from the validator address"), - StakePoolError::StakeListOutOfDate => msg!("Error: Identify validator stake accounts with old balances and update them"), - StakePoolError::StakeListAndPoolOutOfDate => msg!("Error: First update old validator stake account balances and then pool stake balance"), - StakePoolError::UnknownValidatorStakeAccount => { - msg!("Error: Validator stake account is not found in the list storage") - } - StakePoolError::WrongMintingAuthority => msg!("Error: Wrong minting authority set for mint pool account"), - StakePoolError::UnexpectedValidatorListAccountSize=> msg!("Error: The size of the given validator stake list does match the expected amount"), - StakePoolError::WrongStaker=> msg!("Error: Wrong pool staker account"), - StakePoolError::NonZeroPoolTokenSupply => msg!("Error: Pool token supply is not zero on initialization"), - StakePoolError::StakeLamportsNotEqualToMinimum => msg!("Error: The lamports in the validator stake account is not equal to the minimum"), - StakePoolError::IncorrectDepositVoteAddress => msg!("Error: The provided deposit stake account is not delegated to the preferred deposit vote account"), - StakePoolError::IncorrectWithdrawVoteAddress => msg!("Error: The provided withdraw stake account is not the preferred deposit vote account"), - StakePoolError::InvalidMintFreezeAuthority => msg!("Error: The mint has an invalid freeze authority"), - StakePoolError::FeeIncreaseTooHigh => msg!("Error: The fee cannot increase by a factor exceeding the stipulated ratio"), - StakePoolError::WithdrawalTooSmall => msg!("Error: Not enough pool tokens provided to withdraw 1-lamport stake"), - StakePoolError::DepositTooSmall => msg!("Error: Not enough lamports provided for deposit to result in one pool token"), - StakePoolError::InvalidStakeDepositAuthority => msg!("Error: Provided stake deposit authority does not match the program's"), - StakePoolError::InvalidSolDepositAuthority => msg!("Error: Provided sol deposit authority does not match the program's"), - StakePoolError::InvalidPreferredValidator => msg!("Error: Provided preferred validator is invalid"), - StakePoolError::TransientAccountInUse => msg!("Error: Provided validator stake account already has a transient stake account in use"), - StakePoolError::InvalidSolWithdrawAuthority => msg!("Error: Provided sol withdraw authority does not match the program's"), - StakePoolError::SolWithdrawalTooLarge => msg!("Error: Too much SOL withdrawn from the stake pool's reserve account"), - StakePoolError::InvalidMetadataAccount => msg!("Error: Metadata account derived from pool mint account does not match the one passed to program") - } - } -} diff --git a/stake-pool/program/src/state.rs b/stake-pool/program/src/state.rs deleted file mode 100644 index 88901dc6a9c..00000000000 --- a/stake-pool/program/src/state.rs +++ /dev/null @@ -1,1153 +0,0 @@ -//! State transition types - -use { - crate::{ - big_vec::BigVec, error::StakePoolError, MAX_WITHDRAWAL_FEE_INCREASE, - WITHDRAWAL_BASELINE_FEE, - }, - borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, - num_derive::FromPrimitive, - num_traits::FromPrimitive, - solana_program::{ - account_info::AccountInfo, - borsh::get_instance_packed_len, - msg, - program_error::ProgramError, - program_memory::sol_memcmp, - program_pack::{Pack, Sealed}, - pubkey::{Pubkey, PUBKEY_BYTES}, - stake::state::Lockup, - }, - spl_math::checked_ceil_div::CheckedCeilDiv, - spl_token::state::{Account, AccountState}, - std::{convert::TryFrom, fmt, matches}, -}; - -/// Enum representing the account type managed by the program -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] -pub enum AccountType { - /// If the account has not been initialized, the enum will be 0 - Uninitialized, - /// Stake pool - StakePool, - /// Validator stake list - ValidatorList, -} - -impl Default for AccountType { - fn default() -> Self { - AccountType::Uninitialized - } -} - -/// Initialized program details. -#[repr(C)] -#[derive(Clone, Debug, Default, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] -pub struct StakePool { - /// Account type, must be StakePool currently - pub account_type: AccountType, - - /// Manager authority, allows for updating the staker, manager, and fee account - pub manager: Pubkey, - - /// Staker authority, allows for adding and removing validators, and managing stake - /// distribution - pub staker: Pubkey, - - /// Stake deposit authority - /// - /// If a depositor pubkey is specified on initialization, then deposits must be - /// signed by this authority. If no deposit authority is specified, - /// then the stake pool will default to the result of: - /// `Pubkey::find_program_address( - /// &[&stake_pool_address.to_bytes()[..32], b"deposit"], - /// program_id, - /// )` - pub stake_deposit_authority: Pubkey, - - /// Stake withdrawal authority bump seed - /// for `create_program_address(&[state::StakePool account, "withdrawal"])` - pub stake_withdraw_bump_seed: u8, - - /// Validator stake list storage account - pub validator_list: Pubkey, - - /// Reserve stake account, holds deactivated stake - pub reserve_stake: Pubkey, - - /// Pool Mint - pub pool_mint: Pubkey, - - /// Manager fee account - pub manager_fee_account: Pubkey, - - /// Pool token program id - pub token_program_id: Pubkey, - - /// Total stake under management. - /// Note that if `last_update_epoch` does not match the current epoch then - /// this field may not be accurate - pub total_lamports: u64, - - /// Total supply of pool tokens (should always match the supply in the Pool Mint) - pub pool_token_supply: u64, - - /// Last epoch the `total_lamports` field was updated - pub last_update_epoch: u64, - - /// Lockup that all stakes in the pool must have - pub lockup: Lockup, - - /// Fee taken as a proportion of rewards each epoch - pub epoch_fee: Fee, - - /// Fee for next epoch - pub next_epoch_fee: Option, - - /// Preferred deposit validator vote account pubkey - pub preferred_deposit_validator_vote_address: Option, - - /// Preferred withdraw validator vote account pubkey - pub preferred_withdraw_validator_vote_address: Option, - - /// Fee assessed on stake deposits - pub stake_deposit_fee: Fee, - - /// Fee assessed on withdrawals - pub stake_withdrawal_fee: Fee, - - /// Future stake withdrawal fee, to be set for the following epoch - pub next_stake_withdrawal_fee: Option, - - /// Fees paid out to referrers on referred stake deposits. - /// Expressed as a percentage (0 - 100) of deposit fees. - /// i.e. `stake_deposit_fee`% of stake deposited is collected as deposit fees for every deposit - /// and `stake_referral_fee`% of the collected stake deposit fees is paid out to the referrer - pub stake_referral_fee: u8, - - /// Toggles whether the `DepositSol` instruction requires a signature from - /// this `sol_deposit_authority` - pub sol_deposit_authority: Option, - - /// Fee assessed on SOL deposits - pub sol_deposit_fee: Fee, - - /// Fees paid out to referrers on referred SOL deposits. - /// Expressed as a percentage (0 - 100) of SOL deposit fees. - /// i.e. `sol_deposit_fee`% of SOL deposited is collected as deposit fees for every deposit - /// and `sol_referral_fee`% of the collected SOL deposit fees is paid out to the referrer - pub sol_referral_fee: u8, - - /// Toggles whether the `WithdrawSol` instruction requires a signature from - /// the `deposit_authority` - pub sol_withdraw_authority: Option, - - /// Fee assessed on SOL withdrawals - pub sol_withdrawal_fee: Fee, - - /// Future SOL withdrawal fee, to be set for the following epoch - pub next_sol_withdrawal_fee: Option, - - /// Last epoch's total pool tokens, used only for APR estimation - pub last_epoch_pool_token_supply: u64, - - /// Last epoch's total lamports, used only for APR estimation - pub last_epoch_total_lamports: u64, -} -impl StakePool { - /// calculate the pool tokens that should be minted for a deposit of `stake_lamports` - #[inline] - pub fn calc_pool_tokens_for_deposit(&self, stake_lamports: u64) -> Option { - if self.total_lamports == 0 || self.pool_token_supply == 0 { - return Some(stake_lamports); - } - u64::try_from( - (stake_lamports as u128) - .checked_mul(self.pool_token_supply as u128)? - .checked_div(self.total_lamports as u128)?, - ) - .ok() - } - - /// calculate lamports amount on withdrawal - #[inline] - pub fn calc_lamports_withdraw_amount(&self, pool_tokens: u64) -> Option { - // `checked_ceil_div` returns `None` for a 0 quotient result, but in this - // case, a return of 0 is valid for small amounts of pool tokens. So - // we check for that separately - let numerator = (pool_tokens as u128).checked_mul(self.total_lamports as u128)?; - let denominator = self.pool_token_supply as u128; - if numerator < denominator || denominator == 0 { - Some(0) - } else { - let (quotient, _) = numerator.checked_ceil_div(denominator)?; - u64::try_from(quotient).ok() - } - } - - /// calculate pool tokens to be deducted as withdrawal fees - #[inline] - pub fn calc_pool_tokens_stake_withdrawal_fee(&self, pool_tokens: u64) -> Option { - u64::try_from(self.stake_withdrawal_fee.apply(pool_tokens)?).ok() - } - - /// calculate pool tokens to be deducted as withdrawal fees - #[inline] - pub fn calc_pool_tokens_sol_withdrawal_fee(&self, pool_tokens: u64) -> Option { - u64::try_from(self.sol_withdrawal_fee.apply(pool_tokens)?).ok() - } - - /// calculate pool tokens to be deducted as stake deposit fees - #[inline] - pub fn calc_pool_tokens_stake_deposit_fee(&self, pool_tokens_minted: u64) -> Option { - u64::try_from(self.stake_deposit_fee.apply(pool_tokens_minted)?).ok() - } - - /// calculate pool tokens to be deducted from deposit fees as referral fees - #[inline] - pub fn calc_pool_tokens_stake_referral_fee(&self, stake_deposit_fee: u64) -> Option { - u64::try_from( - (stake_deposit_fee as u128) - .checked_mul(self.stake_referral_fee as u128)? - .checked_div(100u128)?, - ) - .ok() - } - - /// calculate pool tokens to be deducted as SOL deposit fees - #[inline] - pub fn calc_pool_tokens_sol_deposit_fee(&self, pool_tokens_minted: u64) -> Option { - u64::try_from(self.sol_deposit_fee.apply(pool_tokens_minted)?).ok() - } - - /// calculate pool tokens to be deducted from SOL deposit fees as referral fees - #[inline] - pub fn calc_pool_tokens_sol_referral_fee(&self, sol_deposit_fee: u64) -> Option { - u64::try_from( - (sol_deposit_fee as u128) - .checked_mul(self.sol_referral_fee as u128)? - .checked_div(100u128)?, - ) - .ok() - } - - /// Calculate the fee in pool tokens that goes to the manager - /// - /// This function assumes that `reward_lamports` has not already been added - /// to the stake pool's `total_lamports` - #[inline] - pub fn calc_epoch_fee_amount(&self, reward_lamports: u64) -> Option { - if reward_lamports == 0 { - return Some(0); - } - let total_lamports = (self.total_lamports as u128).checked_add(reward_lamports as u128)?; - let fee_lamports = self.epoch_fee.apply(reward_lamports)?; - if total_lamports == fee_lamports || self.pool_token_supply == 0 { - Some(reward_lamports) - } else { - u64::try_from( - (self.pool_token_supply as u128) - .checked_mul(fee_lamports)? - .checked_div(total_lamports.checked_sub(fee_lamports)?)?, - ) - .ok() - } - } - - /// Checks that the withdraw or deposit authority is valid - fn check_program_derived_authority( - authority_address: &Pubkey, - program_id: &Pubkey, - stake_pool_address: &Pubkey, - authority_seed: &[u8], - bump_seed: u8, - ) -> Result<(), ProgramError> { - let expected_address = Pubkey::create_program_address( - &[ - &stake_pool_address.to_bytes()[..32], - authority_seed, - &[bump_seed], - ], - program_id, - )?; - - if *authority_address == expected_address { - Ok(()) - } else { - msg!( - "Incorrect authority provided, expected {}, received {}", - expected_address, - authority_address - ); - Err(StakePoolError::InvalidProgramAddress.into()) - } - } - - /// Check if the manager fee info is a valid token program account - /// capable of receiving tokens from the mint. - pub(crate) fn check_manager_fee_info( - &self, - manager_fee_info: &AccountInfo, - ) -> Result<(), ProgramError> { - let token_account = Account::unpack(&manager_fee_info.data.borrow())?; - if manager_fee_info.owner != &self.token_program_id - || token_account.state != AccountState::Initialized - || token_account.mint != self.pool_mint - { - msg!("Manager fee account is not owned by token program, is not initialized, or does not match stake pool's mint"); - return Err(StakePoolError::InvalidFeeAccount.into()); - } - Ok(()) - } - - /// Checks that the withdraw authority is valid - #[inline] - pub(crate) fn check_authority_withdraw( - &self, - withdraw_authority: &Pubkey, - program_id: &Pubkey, - stake_pool_address: &Pubkey, - ) -> Result<(), ProgramError> { - Self::check_program_derived_authority( - withdraw_authority, - program_id, - stake_pool_address, - crate::AUTHORITY_WITHDRAW, - self.stake_withdraw_bump_seed, - ) - } - /// Checks that the deposit authority is valid - #[inline] - pub(crate) fn check_stake_deposit_authority( - &self, - stake_deposit_authority: &Pubkey, - ) -> Result<(), ProgramError> { - if self.stake_deposit_authority == *stake_deposit_authority { - Ok(()) - } else { - Err(StakePoolError::InvalidStakeDepositAuthority.into()) - } - } - - /// Checks that the deposit authority is valid - /// Does nothing if `sol_deposit_authority` is currently not set - #[inline] - pub(crate) fn check_sol_deposit_authority( - &self, - maybe_sol_deposit_authority: Result<&AccountInfo, ProgramError>, - ) -> Result<(), ProgramError> { - if let Some(auth) = self.sol_deposit_authority { - let sol_deposit_authority = maybe_sol_deposit_authority?; - if auth != *sol_deposit_authority.key { - msg!("Expected {}, received {}", auth, sol_deposit_authority.key); - return Err(StakePoolError::InvalidSolDepositAuthority.into()); - } - if !sol_deposit_authority.is_signer { - msg!("SOL Deposit authority signature missing"); - return Err(StakePoolError::SignatureMissing.into()); - } - } - Ok(()) - } - - /// Checks that the sol withdraw authority is valid - /// Does nothing if `sol_withdraw_authority` is currently not set - #[inline] - pub(crate) fn check_sol_withdraw_authority( - &self, - maybe_sol_withdraw_authority: Result<&AccountInfo, ProgramError>, - ) -> Result<(), ProgramError> { - if let Some(auth) = self.sol_withdraw_authority { - let sol_withdraw_authority = maybe_sol_withdraw_authority?; - if auth != *sol_withdraw_authority.key { - return Err(StakePoolError::InvalidSolWithdrawAuthority.into()); - } - if !sol_withdraw_authority.is_signer { - msg!("SOL withdraw authority signature missing"); - return Err(StakePoolError::SignatureMissing.into()); - } - } - Ok(()) - } - - /// Check mint is correct - #[inline] - pub(crate) fn check_mint(&self, mint_info: &AccountInfo) -> Result<(), ProgramError> { - if *mint_info.key != self.pool_mint { - Err(StakePoolError::WrongPoolMint.into()) - } else { - Ok(()) - } - } - - /// Check manager validity and signature - pub(crate) fn check_manager(&self, manager_info: &AccountInfo) -> Result<(), ProgramError> { - if *manager_info.key != self.manager { - msg!( - "Incorrect manager provided, expected {}, received {}", - self.manager, - manager_info.key - ); - return Err(StakePoolError::WrongManager.into()); - } - if !manager_info.is_signer { - msg!("Manager signature missing"); - return Err(StakePoolError::SignatureMissing.into()); - } - Ok(()) - } - - /// Check staker validity and signature - pub(crate) fn check_staker(&self, staker_info: &AccountInfo) -> Result<(), ProgramError> { - if *staker_info.key != self.staker { - msg!( - "Incorrect staker provided, expected {}, received {}", - self.staker, - staker_info.key - ); - return Err(StakePoolError::WrongStaker.into()); - } - if !staker_info.is_signer { - msg!("Staker signature missing"); - return Err(StakePoolError::SignatureMissing.into()); - } - Ok(()) - } - - /// Check the validator list is valid - pub fn check_validator_list( - &self, - validator_list_info: &AccountInfo, - ) -> Result<(), ProgramError> { - if *validator_list_info.key != self.validator_list { - msg!( - "Invalid validator list provided, expected {}, received {}", - self.validator_list, - validator_list_info.key - ); - Err(StakePoolError::InvalidValidatorStakeList.into()) - } else { - Ok(()) - } - } - - /// Check the reserve stake is valid - pub fn check_reserve_stake( - &self, - reserve_stake_info: &AccountInfo, - ) -> Result<(), ProgramError> { - if *reserve_stake_info.key != self.reserve_stake { - msg!( - "Invalid reserve stake provided, expected {}, received {}", - self.reserve_stake, - reserve_stake_info.key - ); - Err(StakePoolError::InvalidProgramAddress.into()) - } else { - Ok(()) - } - } - - /// Check if StakePool is actually initialized as a stake pool - pub fn is_valid(&self) -> bool { - self.account_type == AccountType::StakePool - } - - /// Check if StakePool is currently uninitialized - pub fn is_uninitialized(&self) -> bool { - self.account_type == AccountType::Uninitialized - } - - /// Updates one of the StakePool's fees. - pub fn update_fee(&mut self, fee: &FeeType) -> Result<(), StakePoolError> { - match fee { - FeeType::SolReferral(new_fee) => self.sol_referral_fee = *new_fee, - FeeType::StakeReferral(new_fee) => self.stake_referral_fee = *new_fee, - FeeType::Epoch(new_fee) => self.next_epoch_fee = Some(*new_fee), - FeeType::StakeWithdrawal(new_fee) => { - new_fee.check_withdrawal(&self.stake_withdrawal_fee)?; - self.next_stake_withdrawal_fee = Some(*new_fee) - } - FeeType::SolWithdrawal(new_fee) => { - new_fee.check_withdrawal(&self.sol_withdrawal_fee)?; - self.next_sol_withdrawal_fee = Some(*new_fee) - } - FeeType::SolDeposit(new_fee) => self.sol_deposit_fee = *new_fee, - FeeType::StakeDeposit(new_fee) => self.stake_deposit_fee = *new_fee, - }; - Ok(()) - } -} - -/// Storage list for all validator stake accounts in the pool. -#[repr(C)] -#[derive(Clone, Debug, Default, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] -pub struct ValidatorList { - /// Data outside of the validator list, separated out for cheaper deserializations - pub header: ValidatorListHeader, - - /// List of stake info for each validator in the pool - pub validators: Vec, -} - -/// Helper type to deserialize just the start of a ValidatorList -#[repr(C)] -#[derive(Clone, Debug, Default, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] -pub struct ValidatorListHeader { - /// Account type, must be ValidatorList currently - pub account_type: AccountType, - - /// Maximum allowable number of validators - pub max_validators: u32, -} - -/// Status of the stake account in the validator list, for accounting -#[derive( - FromPrimitive, Copy, Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema, -)] -pub enum StakeStatus { - /// Stake account is active, there may be a transient stake as well - Active, - /// Only transient stake account exists, when a transient stake is - /// deactivating during validator removal - DeactivatingTransient, - /// No more validator stake accounts exist, entry ready for removal during - /// `UpdateStakePoolBalance` - ReadyForRemoval, -} - -impl Default for StakeStatus { - fn default() -> Self { - Self::Active - } -} - -/// Information about a validator in the pool -/// -/// NOTE: ORDER IS VERY IMPORTANT HERE, PLEASE DO NOT RE-ORDER THE FIELDS UNLESS -/// THERE'S AN EXTREMELY GOOD REASON. -/// -/// To save on BPF instructions, the serialized bytes are reinterpreted with an -/// unsafe pointer cast, which means that this structure cannot have any -/// undeclared alignment-padding in its representation. -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] -pub struct ValidatorStakeInfo { - /// Amount of active stake delegated to this validator, minus the minimum - /// required stake amount of rent-exemption + `crate::MINIMUM_ACTIVE_STAKE` - /// (currently 1 SOL). - /// - /// Note that if `last_update_epoch` does not match the current epoch then - /// this field may not be accurate - pub active_stake_lamports: u64, - - /// Amount of transient stake delegated to this validator - /// - /// Note that if `last_update_epoch` does not match the current epoch then - /// this field may not be accurate - pub transient_stake_lamports: u64, - - /// Last epoch the active and transient stake lamports fields were updated - pub last_update_epoch: u64, - - /// Start of the validator transient account seed suffixess - pub transient_seed_suffix_start: u64, - - /// End of the validator transient account seed suffixes - pub transient_seed_suffix_end: u64, - - /// Status of the validator stake account - pub status: StakeStatus, - - /// Validator vote account address - pub vote_account_address: Pubkey, -} - -impl ValidatorStakeInfo { - /// Get the total lamports delegated to this validator (active and transient) - pub fn stake_lamports(&self) -> u64 { - self.active_stake_lamports - .checked_add(self.transient_stake_lamports) - .unwrap() - } - - /// Performs a very cheap comparison, for checking if this validator stake - /// info matches the vote account address - pub fn memcmp_pubkey(data: &[u8], vote_address_bytes: &[u8]) -> bool { - sol_memcmp( - &data[41..41 + PUBKEY_BYTES], - vote_address_bytes, - PUBKEY_BYTES, - ) == 0 - } - - /// Performs a very cheap comparison, for checking if this validator stake - /// info does not have active lamports equal to the given bytes - pub fn active_lamports_not_equal(data: &[u8], lamports_le_bytes: &[u8]) -> bool { - sol_memcmp(&data[0..8], lamports_le_bytes, 8) != 0 - } - - /// Performs a very cheap comparison, for checking if this validator stake - /// info does not have lamports equal to the given bytes - pub fn transient_lamports_not_equal(data: &[u8], lamports_le_bytes: &[u8]) -> bool { - sol_memcmp(&data[8..16], lamports_le_bytes, 8) != 0 - } - - /// Check that the validator stake info is valid - pub fn is_not_removed(data: &[u8]) -> bool { - FromPrimitive::from_u8(data[40]) != Some(StakeStatus::ReadyForRemoval) - } -} - -impl Sealed for ValidatorStakeInfo {} - -impl Pack for ValidatorStakeInfo { - const LEN: usize = 73; - fn pack_into_slice(&self, data: &mut [u8]) { - let mut data = data; - self.serialize(&mut data).unwrap(); - } - fn unpack_from_slice(src: &[u8]) -> Result { - let unpacked = Self::try_from_slice(src)?; - Ok(unpacked) - } -} - -impl ValidatorList { - /// Create an empty instance containing space for `max_validators` and preferred validator keys - pub fn new(max_validators: u32) -> Self { - Self { - header: ValidatorListHeader { - account_type: AccountType::ValidatorList, - max_validators, - }, - validators: vec![ValidatorStakeInfo::default(); max_validators as usize], - } - } - - /// Calculate the number of validator entries that fit in the provided length - pub fn calculate_max_validators(buffer_length: usize) -> usize { - let header_size = ValidatorListHeader::LEN + 4; - buffer_length.saturating_sub(header_size) / ValidatorStakeInfo::LEN - } - - /// Check if contains validator with particular pubkey - pub fn contains(&self, vote_account_address: &Pubkey) -> bool { - self.validators - .iter() - .any(|x| x.vote_account_address == *vote_account_address) - } - - /// Check if contains validator with particular pubkey - pub fn find_mut(&mut self, vote_account_address: &Pubkey) -> Option<&mut ValidatorStakeInfo> { - self.validators - .iter_mut() - .find(|x| x.vote_account_address == *vote_account_address) - } - /// Check if contains validator with particular pubkey - pub fn find(&self, vote_account_address: &Pubkey) -> Option<&ValidatorStakeInfo> { - self.validators - .iter() - .find(|x| x.vote_account_address == *vote_account_address) - } - - /// Check if the list has any active stake - pub fn has_active_stake(&self) -> bool { - self.validators.iter().any(|x| x.active_stake_lamports > 0) - } -} - -impl ValidatorListHeader { - const LEN: usize = 1 + 4; - - /// Check if validator stake list is actually initialized as a validator stake list - pub fn is_valid(&self) -> bool { - self.account_type == AccountType::ValidatorList - } - - /// Check if the validator stake list is uninitialized - pub fn is_uninitialized(&self) -> bool { - self.account_type == AccountType::Uninitialized - } - - /// Extracts a slice of ValidatorStakeInfo types from the vec part - /// of the ValidatorList - pub fn deserialize_mut_slice( - data: &mut [u8], - skip: usize, - len: usize, - ) -> Result<(Self, Vec<&mut ValidatorStakeInfo>), ProgramError> { - let (header, mut big_vec) = Self::deserialize_vec(data)?; - let validator_list = big_vec.deserialize_mut_slice::(skip, len)?; - Ok((header, validator_list)) - } - - /// Extracts the validator list into its header and internal BigVec - pub fn deserialize_vec(data: &mut [u8]) -> Result<(Self, BigVec), ProgramError> { - let mut data_mut = &data[..]; - let header = ValidatorListHeader::deserialize(&mut data_mut)?; - let length = get_instance_packed_len(&header)?; - - let big_vec = BigVec { - data: &mut data[length..], - }; - Ok((header, big_vec)) - } -} - -/// Fee rate as a ratio, minted on `UpdateStakePoolBalance` as a proportion of -/// the rewards -/// If either the numerator or the denominator is 0, the fee is considered to be 0 -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq, BorshSerialize, BorshDeserialize, BorshSchema)] -pub struct Fee { - /// denominator of the fee ratio - pub denominator: u64, - /// numerator of the fee ratio - pub numerator: u64, -} - -impl Fee { - /// Applies the Fee's rates to a given amount, `amt` - /// returning the amount to be subtracted from it as fees - /// (0 if denominator is 0 or amt is 0), - /// or None if overflow occurs - #[inline] - pub fn apply(&self, amt: u64) -> Option { - if self.denominator == 0 { - return Some(0); - } - (amt as u128) - .checked_mul(self.numerator as u128)? - .checked_div(self.denominator as u128) - } - - /// Withdrawal fees have some additional restrictions, - /// this fn checks if those are met, returning an error if not. - /// Does nothing and returns Ok if fee type is not withdrawal - pub fn check_withdrawal(&self, old_withdrawal_fee: &Fee) -> Result<(), StakePoolError> { - // If the previous withdrawal fee was 0, we allow the fee to be set to a - // maximum of (WITHDRAWAL_BASELINE_FEE * MAX_WITHDRAWAL_FEE_INCREASE) - let (old_num, old_denom) = - if old_withdrawal_fee.denominator == 0 || old_withdrawal_fee.numerator == 0 { - ( - WITHDRAWAL_BASELINE_FEE.numerator, - WITHDRAWAL_BASELINE_FEE.denominator, - ) - } else { - (old_withdrawal_fee.numerator, old_withdrawal_fee.denominator) - }; - - // Check that new_fee / old_fee <= MAX_WITHDRAWAL_FEE_INCREASE - // Program fails if provided numerator or denominator is too large, resulting in overflow - if (old_num as u128) - .checked_mul(self.denominator as u128) - .map(|x| x.checked_mul(MAX_WITHDRAWAL_FEE_INCREASE.numerator as u128)) - .ok_or(StakePoolError::CalculationFailure)? - < (self.numerator as u128) - .checked_mul(old_denom as u128) - .map(|x| x.checked_mul(MAX_WITHDRAWAL_FEE_INCREASE.denominator as u128)) - .ok_or(StakePoolError::CalculationFailure)? - { - msg!( - "Fee increase exceeds maximum allowed, proposed increase factor ({} / {})", - self.numerator * old_denom, - old_num * self.denominator, - ); - return Err(StakePoolError::FeeIncreaseTooHigh); - } - Ok(()) - } -} - -impl fmt::Display for Fee { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.numerator > 0 && self.denominator > 0 { - write!(f, "{}/{}", self.numerator, self.denominator) - } else { - write!(f, "none") - } - } -} - -/// The type of fees that can be set on the stake pool -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] -pub enum FeeType { - /// Referral fees for SOL deposits - SolReferral(u8), - /// Referral fees for stake deposits - StakeReferral(u8), - /// Management fee paid per epoch - Epoch(Fee), - /// Stake withdrawal fee - StakeWithdrawal(Fee), - /// Deposit fee for SOL deposits - SolDeposit(Fee), - /// Deposit fee for stake deposits - StakeDeposit(Fee), - /// SOL withdrawal fee - SolWithdrawal(Fee), -} - -impl FeeType { - /// Checks if the provided fee is too high, returning an error if so - pub fn check_too_high(&self) -> Result<(), StakePoolError> { - let too_high = match self { - Self::SolReferral(pct) => *pct > 100u8, - Self::StakeReferral(pct) => *pct > 100u8, - Self::Epoch(fee) => fee.numerator > fee.denominator, - Self::StakeWithdrawal(fee) => fee.numerator > fee.denominator, - Self::SolWithdrawal(fee) => fee.numerator > fee.denominator, - Self::SolDeposit(fee) => fee.numerator > fee.denominator, - Self::StakeDeposit(fee) => fee.numerator > fee.denominator, - }; - if too_high { - msg!("Fee greater than 100%: {:?}", self); - return Err(StakePoolError::FeeTooHigh); - } - Ok(()) - } - - /// Returns if the contained fee can only be updated earliest on the next epoch - #[inline] - pub fn can_only_change_next_epoch(&self) -> bool { - matches!( - self, - Self::StakeWithdrawal(_) | Self::SolWithdrawal(_) | Self::Epoch(_) - ) - } -} - -#[cfg(test)] -mod test { - use { - super::*, - proptest::prelude::*, - solana_program::{ - borsh::{get_instance_packed_len, get_packed_len, try_from_slice_unchecked}, - clock::{DEFAULT_SLOTS_PER_EPOCH, DEFAULT_S_PER_SLOT, SECONDS_PER_DAY}, - native_token::LAMPORTS_PER_SOL, - }, - }; - - fn uninitialized_validator_list() -> ValidatorList { - ValidatorList { - header: ValidatorListHeader { - account_type: AccountType::Uninitialized, - max_validators: 0, - }, - validators: vec![], - } - } - - fn test_validator_list(max_validators: u32) -> ValidatorList { - ValidatorList { - header: ValidatorListHeader { - account_type: AccountType::ValidatorList, - max_validators, - }, - validators: vec![ - ValidatorStakeInfo { - status: StakeStatus::Active, - vote_account_address: Pubkey::new_from_array([1; 32]), - active_stake_lamports: u64::from_le_bytes([255; 8]), - transient_stake_lamports: u64::from_le_bytes([128; 8]), - last_update_epoch: u64::from_le_bytes([64; 8]), - transient_seed_suffix_start: 0, - transient_seed_suffix_end: 0, - }, - ValidatorStakeInfo { - status: StakeStatus::DeactivatingTransient, - vote_account_address: Pubkey::new_from_array([2; 32]), - active_stake_lamports: 998877665544, - transient_stake_lamports: 222222222, - last_update_epoch: 11223445566, - transient_seed_suffix_start: 0, - transient_seed_suffix_end: 0, - }, - ValidatorStakeInfo { - status: StakeStatus::ReadyForRemoval, - vote_account_address: Pubkey::new_from_array([3; 32]), - active_stake_lamports: 0, - transient_stake_lamports: 0, - last_update_epoch: 999999999999999, - transient_seed_suffix_start: 0, - transient_seed_suffix_end: 0, - }, - ], - } - } - - #[test] - fn state_packing() { - let max_validators = 10_000; - let size = get_instance_packed_len(&ValidatorList::new(max_validators)).unwrap(); - let stake_list = uninitialized_validator_list(); - let mut byte_vec = vec![0u8; size]; - let mut bytes = byte_vec.as_mut_slice(); - stake_list.serialize(&mut bytes).unwrap(); - let stake_list_unpacked = try_from_slice_unchecked::(&byte_vec).unwrap(); - assert_eq!(stake_list_unpacked, stake_list); - - // Empty, one preferred key - let stake_list = ValidatorList { - header: ValidatorListHeader { - account_type: AccountType::ValidatorList, - max_validators: 0, - }, - validators: vec![], - }; - let mut byte_vec = vec![0u8; size]; - let mut bytes = byte_vec.as_mut_slice(); - stake_list.serialize(&mut bytes).unwrap(); - let stake_list_unpacked = try_from_slice_unchecked::(&byte_vec).unwrap(); - assert_eq!(stake_list_unpacked, stake_list); - - // With several accounts - let stake_list = test_validator_list(max_validators); - let mut byte_vec = vec![0u8; size]; - let mut bytes = byte_vec.as_mut_slice(); - stake_list.serialize(&mut bytes).unwrap(); - let stake_list_unpacked = try_from_slice_unchecked::(&byte_vec).unwrap(); - assert_eq!(stake_list_unpacked, stake_list); - } - - #[test] - fn validator_list_active_stake() { - let max_validators = 10_000; - let mut validator_list = test_validator_list(max_validators); - assert!(validator_list.has_active_stake()); - for validator in validator_list.validators.iter_mut() { - validator.active_stake_lamports = 0; - } - assert!(!validator_list.has_active_stake()); - } - - #[test] - fn validator_list_deserialize_mut_slice() { - let max_validators = 10; - let stake_list = test_validator_list(max_validators); - let mut serialized = stake_list.try_to_vec().unwrap(); - let (header, list) = ValidatorListHeader::deserialize_mut_slice( - &mut serialized, - 0, - stake_list.validators.len(), - ) - .unwrap(); - assert_eq!(header.account_type, AccountType::ValidatorList); - assert_eq!(header.max_validators, max_validators); - assert!(list - .iter() - .zip(stake_list.validators.iter()) - .all(|(a, b)| *a == b)); - - let (_, list) = ValidatorListHeader::deserialize_mut_slice(&mut serialized, 1, 2).unwrap(); - assert!(list - .iter() - .zip(stake_list.validators[1..].iter()) - .all(|(a, b)| *a == b)); - let (_, list) = ValidatorListHeader::deserialize_mut_slice(&mut serialized, 2, 1).unwrap(); - assert!(list - .iter() - .zip(stake_list.validators[2..].iter()) - .all(|(a, b)| *a == b)); - let (_, list) = ValidatorListHeader::deserialize_mut_slice(&mut serialized, 0, 2).unwrap(); - assert!(list - .iter() - .zip(stake_list.validators[..2].iter()) - .all(|(a, b)| *a == b)); - - assert_eq!( - ValidatorListHeader::deserialize_mut_slice(&mut serialized, 0, 4).unwrap_err(), - ProgramError::AccountDataTooSmall - ); - assert_eq!( - ValidatorListHeader::deserialize_mut_slice(&mut serialized, 1, 3).unwrap_err(), - ProgramError::AccountDataTooSmall - ); - } - - #[test] - fn validator_list_iter() { - let max_validators = 10; - let stake_list = test_validator_list(max_validators); - let mut serialized = stake_list.try_to_vec().unwrap(); - let (_, big_vec) = ValidatorListHeader::deserialize_vec(&mut serialized).unwrap(); - for (a, b) in big_vec - .iter::() - .zip(stake_list.validators.iter()) - { - assert_eq!(a, b); - } - } - - proptest! { - #[test] - fn stake_list_size_calculation(test_amount in 0..=100_000_u32) { - let validators = ValidatorList::new(test_amount); - let size = get_instance_packed_len(&validators).unwrap(); - assert_eq!(ValidatorList::calculate_max_validators(size), test_amount as usize); - assert_eq!(ValidatorList::calculate_max_validators(size.saturating_add(1)), test_amount as usize); - assert_eq!(ValidatorList::calculate_max_validators(size.saturating_add(get_packed_len::())), (test_amount + 1)as usize); - assert_eq!(ValidatorList::calculate_max_validators(size.saturating_sub(1)), (test_amount.saturating_sub(1)) as usize); - } - } - - prop_compose! { - fn fee()(denominator in 1..=u16::MAX)( - denominator in Just(denominator), - numerator in 0..=denominator, - ) -> (u64, u64) { - (numerator as u64, denominator as u64) - } - } - - prop_compose! { - fn total_stake_and_rewards()(total_lamports in 1..u64::MAX)( - total_lamports in Just(total_lamports), - rewards in 0..=total_lamports, - ) -> (u64, u64) { - (total_lamports - rewards, rewards) - } - } - - #[test] - fn specific_fee_calculation() { - // 10% of 10 SOL in rewards should be 1 SOL in fees - let epoch_fee = Fee { - numerator: 1, - denominator: 10, - }; - let mut stake_pool = StakePool { - total_lamports: 100 * LAMPORTS_PER_SOL, - pool_token_supply: 100 * LAMPORTS_PER_SOL, - epoch_fee, - ..StakePool::default() - }; - let reward_lamports = 10 * LAMPORTS_PER_SOL; - let pool_token_fee = stake_pool.calc_epoch_fee_amount(reward_lamports).unwrap(); - - stake_pool.total_lamports += reward_lamports; - stake_pool.pool_token_supply += pool_token_fee; - - let fee_lamports = stake_pool - .calc_lamports_withdraw_amount(pool_token_fee) - .unwrap(); - assert_eq!(fee_lamports, LAMPORTS_PER_SOL); - } - - #[test] - fn zero_withdraw_calculation() { - let epoch_fee = Fee { - numerator: 0, - denominator: 1, - }; - let stake_pool = StakePool { - epoch_fee, - ..StakePool::default() - }; - let fee_lamports = stake_pool.calc_lamports_withdraw_amount(0).unwrap(); - assert_eq!(fee_lamports, 0); - } - - #[test] - fn divide_by_zero_fee() { - let stake_pool = StakePool { - total_lamports: 0, - epoch_fee: Fee { - numerator: 1, - denominator: 10, - }, - ..StakePool::default() - }; - let rewards = 10; - let fee = stake_pool.calc_epoch_fee_amount(rewards).unwrap(); - assert_eq!(fee, rewards); - } - - #[test] - fn approximate_apr_calculation() { - // 8% / year means roughly .044% / epoch - let stake_pool = StakePool { - last_epoch_total_lamports: 100_000, - last_epoch_pool_token_supply: 100_000, - total_lamports: 100_044, - pool_token_supply: 100_000, - ..StakePool::default() - }; - let pool_token_value = - stake_pool.total_lamports as f64 / stake_pool.pool_token_supply as f64; - let last_epoch_pool_token_value = stake_pool.last_epoch_total_lamports as f64 - / stake_pool.last_epoch_pool_token_supply as f64; - let epoch_rate = pool_token_value / last_epoch_pool_token_value - 1.0; - const SECONDS_PER_EPOCH: f64 = DEFAULT_SLOTS_PER_EPOCH as f64 * DEFAULT_S_PER_SLOT; - const EPOCHS_PER_YEAR: f64 = SECONDS_PER_DAY as f64 * 365.25 / SECONDS_PER_EPOCH; - const EPSILON: f64 = 0.00001; - let yearly_rate = epoch_rate * EPOCHS_PER_YEAR; - assert!((yearly_rate - 0.080355).abs() < EPSILON); - } - - proptest! { - #[test] - fn fee_calculation( - (numerator, denominator) in fee(), - (total_lamports, reward_lamports) in total_stake_and_rewards(), - ) { - let epoch_fee = Fee { denominator, numerator }; - let mut stake_pool = StakePool { - total_lamports, - pool_token_supply: total_lamports, - epoch_fee, - ..StakePool::default() - }; - let pool_token_fee = stake_pool.calc_epoch_fee_amount(reward_lamports).unwrap(); - - stake_pool.total_lamports += reward_lamports; - stake_pool.pool_token_supply += pool_token_fee; - - let fee_lamports = stake_pool.calc_lamports_withdraw_amount(pool_token_fee).unwrap(); - let max_fee_lamports = u64::try_from((reward_lamports as u128) * (epoch_fee.numerator as u128) / (epoch_fee.denominator as u128)).unwrap(); - assert!(max_fee_lamports >= fee_lamports, - "Max possible fee must always be greater than or equal to what is actually withdrawn, max {} actual {}", - max_fee_lamports, - fee_lamports); - - // since we do two "flooring" conversions, the max epsilon should be - // correct up to 2 lamports (one for each floor division), plus a - // correction for huge discrepancies between rewards and total stake - let epsilon = 2 + reward_lamports / total_lamports; - assert!(max_fee_lamports - fee_lamports <= epsilon, - "Max expected fee in lamports {}, actually receive {}, epsilon {}", - max_fee_lamports, fee_lamports, epsilon); - } - } - - prop_compose! { - fn total_tokens_and_deposit()(total_lamports in 1..u64::MAX)( - total_lamports in Just(total_lamports), - pool_token_supply in 1..=total_lamports, - deposit_lamports in 1..total_lamports, - ) -> (u64, u64, u64) { - (total_lamports - deposit_lamports, pool_token_supply.saturating_sub(deposit_lamports).max(1), deposit_lamports) - } - } - - proptest! { - #[test] - fn deposit_and_withdraw( - (total_lamports, pool_token_supply, deposit_stake) in total_tokens_and_deposit() - ) { - let mut stake_pool = StakePool { - total_lamports, - pool_token_supply, - ..StakePool::default() - }; - let deposit_result = stake_pool.calc_pool_tokens_for_deposit(deposit_stake).unwrap(); - prop_assume!(deposit_result > 0); - stake_pool.total_lamports += deposit_stake; - stake_pool.pool_token_supply += deposit_result; - let withdraw_result = stake_pool.calc_lamports_withdraw_amount(deposit_result).unwrap(); - assert!(withdraw_result <= deposit_stake); - } - } -} diff --git a/stake-pool/program/tests/create_pool_token_metadata.rs b/stake-pool/program/tests/create_pool_token_metadata.rs deleted file mode 100644 index 3068df62524..00000000000 --- a/stake-pool/program/tests/create_pool_token_metadata.rs +++ /dev/null @@ -1,276 +0,0 @@ -#![cfg(feature = "test-bpf")] -mod helpers; - -use { - helpers::*, - mpl_token_metadata::{ - state::{MAX_NAME_LENGTH, MAX_SYMBOL_LENGTH, MAX_URI_LENGTH}, - utils::puffed_out_string, - }, - solana_program::{instruction::InstructionError, pubkey::Pubkey}, - solana_program_test::*, - solana_sdk::{ - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, - }, - spl_stake_pool::{ - error::StakePoolError::{AlreadyInUse, SignatureMissing, WrongManager}, - instruction, MINIMUM_RESERVE_LAMPORTS, - }, -}; - -async fn setup() -> (ProgramTestContext, StakePoolAccounts) { - let mut context = program_test_with_metadata_program() - .start_with_context() - .await; - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - (context, stake_pool_accounts) -} - -#[tokio::test] -async fn success_create_pool_token_metadata() { - let (mut context, stake_pool_accounts) = setup().await; - - let name = "test_name"; - let symbol = "SYM"; - let uri = "test_uri"; - - let puffed_name = puffed_out_string(&name, MAX_NAME_LENGTH); - let puffed_symbol = puffed_out_string(&symbol, MAX_SYMBOL_LENGTH); - let puffed_uri = puffed_out_string(&uri, MAX_URI_LENGTH); - - let ix = instruction::create_token_metadata( - &spl_stake_pool::id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &context.payer.pubkey(), - name.to_string(), - symbol.to_string(), - uri.to_string(), - ); - - let transaction = Transaction::new_signed_with_payer( - &[ix], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let metadata = get_metadata_account( - &mut context.banks_client, - &stake_pool_accounts.pool_mint.pubkey(), - ) - .await; - - assert_eq!(metadata.data.name.to_string(), puffed_name); - assert_eq!(metadata.data.symbol.to_string(), puffed_symbol); - assert_eq!(metadata.data.uri.to_string(), puffed_uri); -} - -#[tokio::test] -async fn fail_manager_did_not_sign() { - let (mut context, stake_pool_accounts) = setup().await; - - let name = "test_name"; - let symbol = "SYM"; - let uri = "test_uri"; - - let mut ix = instruction::create_token_metadata( - &spl_stake_pool::id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &context.payer.pubkey(), - name.to_string(), - symbol.to_string(), - uri.to_string(), - ); - ix.accounts[1].is_signer = false; - - let transaction = Transaction::new_signed_with_payer( - &[ix], - Some(&context.payer.pubkey()), - &[&context.payer], - context.last_blockhash, - ); - - let error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = SignatureMissing as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while manager signature missing"), - } -} - -#[tokio::test] -async fn fail_wrong_manager_signed() { - let (mut context, stake_pool_accounts) = setup().await; - - let name = "test_name"; - let symbol = "SYM"; - let uri = "test_uri"; - - let random_keypair = Keypair::new(); - let ix = instruction::create_token_metadata( - &spl_stake_pool::id(), - &stake_pool_accounts.stake_pool.pubkey(), - &random_keypair.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &context.payer.pubkey(), - name.to_string(), - symbol.to_string(), - uri.to_string(), - ); - - let transaction = Transaction::new_signed_with_payer( - &[ix], - Some(&context.payer.pubkey()), - &[&context.payer, &random_keypair], - context.last_blockhash, - ); - - let error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = WrongManager as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while signing with the wrong manager"), - } -} - -#[tokio::test] -async fn fail_wrong_mpl_metadata_program() { - let (mut context, stake_pool_accounts) = setup().await; - - let name = "test_name"; - let symbol = "SYM"; - let uri = "test_uri"; - - let random_keypair = Keypair::new(); - let mut ix = instruction::create_token_metadata( - &spl_stake_pool::id(), - &stake_pool_accounts.stake_pool.pubkey(), - &random_keypair.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &context.payer.pubkey(), - name.to_string(), - symbol.to_string(), - uri.to_string(), - ); - ix.accounts[7].pubkey = Pubkey::new_unique(); - - let transaction = Transaction::new_signed_with_payer( - &[ix], - Some(&context.payer.pubkey()), - &[&context.payer, &random_keypair], - context.last_blockhash, - ); - - let error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, error) => { - assert_eq!(error, InstructionError::IncorrectProgramId); - } - _ => panic!( - "Wrong error occurs while try to create metadata with wrong mpl token metadata program ID" - ), - } -} - -#[tokio::test] -async fn fail_create_metadata_twice() { - let (mut context, stake_pool_accounts) = setup().await; - - let name = "test_name"; - let symbol = "SYM"; - let uri = "test_uri"; - - let ix = instruction::create_token_metadata( - &spl_stake_pool::id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &context.payer.pubkey(), - name.to_string(), - symbol.to_string(), - uri.to_string(), - ); - - let transaction = Transaction::new_signed_with_payer( - &[ix.clone()], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - - let latest_blockhash = context.banks_client.get_latest_blockhash().await.unwrap(); - let transaction_2 = Transaction::new_signed_with_payer( - &[ix], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - latest_blockhash, - ); - - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let error = context - .banks_client - .process_transaction(transaction_2) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = AlreadyInUse as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while trying to create pool token metadata twice"), - } -} diff --git a/stake-pool/program/tests/decrease.rs b/stake-pool/program/tests/decrease.rs deleted file mode 100644 index 1089fba90dd..00000000000 --- a/stake-pool/program/tests/decrease.rs +++ /dev/null @@ -1,444 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod helpers; - -use { - bincode::deserialize, - helpers::*, - solana_program::{ - clock::Epoch, hash::Hash, instruction::InstructionError, pubkey::Pubkey, stake, - }, - solana_program_test::*, - solana_sdk::{ - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, - }, - spl_stake_pool::{ - error::StakePoolError, find_transient_stake_program_address, id, instruction, - MINIMUM_ACTIVE_STAKE, MINIMUM_RESERVE_LAMPORTS, - }, -}; - -async fn setup() -> ( - BanksClient, - Keypair, - Hash, - StakePoolAccounts, - ValidatorStakeAccount, - DepositStakeAccount, - u64, -) { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let rent = banks_client.get_rent().await.unwrap(); - let stake_rent = rent.minimum_balance(std::mem::size_of::()); - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let validator_stake_account = simple_add_validator_to_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - ) - .await; - - let deposit_info = simple_deposit_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - &validator_stake_account, - MINIMUM_ACTIVE_STAKE * 2 + stake_rent, - ) - .await - .unwrap(); - - let decrease_lamports = MINIMUM_ACTIVE_STAKE + stake_rent; - - ( - banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake_account, - deposit_info, - decrease_lamports, - ) -} - -#[tokio::test] -async fn success() { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake, - _deposit_info, - decrease_lamports, - ) = setup().await; - - // Save validator stake - let pre_validator_stake_account = - get_account(&mut banks_client, &validator_stake.stake_account).await; - - // Check no transient stake - let transient_account = banks_client - .get_account(validator_stake.transient_stake_account) - .await - .unwrap(); - assert!(transient_account.is_none()); - - let error = stake_pool_accounts - .decrease_validator_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - decrease_lamports, - validator_stake.transient_stake_seed, - ) - .await; - assert!(error.is_none()); - - // Check validator stake account balance - let validator_stake_account = - get_account(&mut banks_client, &validator_stake.stake_account).await; - let validator_stake_state = - deserialize::(&validator_stake_account.data).unwrap(); - assert_eq!( - pre_validator_stake_account.lamports - decrease_lamports, - validator_stake_account.lamports - ); - assert_eq!( - validator_stake_state - .delegation() - .unwrap() - .deactivation_epoch, - Epoch::MAX - ); - - // Check transient stake account state and balance - let transient_stake_account = - get_account(&mut banks_client, &validator_stake.transient_stake_account).await; - let transient_stake_state = - deserialize::(&transient_stake_account.data).unwrap(); - assert_eq!(transient_stake_account.lamports, decrease_lamports); - assert_ne!( - transient_stake_state - .delegation() - .unwrap() - .deactivation_epoch, - Epoch::MAX - ); -} - -#[tokio::test] -async fn fail_with_wrong_withdraw_authority() { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake, - _deposit_info, - decrease_lamports, - ) = setup().await; - - let wrong_authority = Pubkey::new_unique(); - - let transaction = Transaction::new_signed_with_payer( - &[instruction::decrease_validator_stake( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.staker.pubkey(), - &wrong_authority, - &stake_pool_accounts.validator_list.pubkey(), - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - decrease_lamports, - validator_stake.transient_stake_seed, - )], - Some(&payer.pubkey()), - &[&payer, &stake_pool_accounts.staker], - recent_blockhash, - ); - let error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = StakePoolError::InvalidProgramAddress as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while decreasing with wrong withdraw authority"), - } -} - -#[tokio::test] -async fn fail_with_wrong_validator_list() { - let ( - mut banks_client, - payer, - recent_blockhash, - mut stake_pool_accounts, - validator_stake, - _deposit_info, - decrease_lamports, - ) = setup().await; - - stake_pool_accounts.validator_list = Keypair::new(); - - let transaction = Transaction::new_signed_with_payer( - &[instruction::decrease_validator_stake( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.staker.pubkey(), - &stake_pool_accounts.withdraw_authority, - &stake_pool_accounts.validator_list.pubkey(), - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - decrease_lamports, - validator_stake.transient_stake_seed, - )], - Some(&payer.pubkey()), - &[&payer, &stake_pool_accounts.staker], - recent_blockhash, - ); - let error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = StakePoolError::InvalidValidatorStakeList as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while decreasing with wrong validator stake list account"), - } -} - -#[tokio::test] -async fn fail_with_unknown_validator() { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - _validator_stake, - _deposit_info, - decrease_lamports, - ) = setup().await; - - let unknown_stake = create_unknown_validator_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - - let transaction = Transaction::new_signed_with_payer( - &[instruction::decrease_validator_stake( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.staker.pubkey(), - &stake_pool_accounts.withdraw_authority, - &stake_pool_accounts.validator_list.pubkey(), - &unknown_stake.stake_account, - &unknown_stake.transient_stake_account, - decrease_lamports, - unknown_stake.transient_stake_seed, - )], - Some(&payer.pubkey()), - &[&payer, &stake_pool_accounts.staker], - recent_blockhash, - ); - let error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - assert_eq!( - error, - TransactionError::InstructionError( - 0, - InstructionError::Custom(StakePoolError::InvalidStakeAccountAddress as u32) - ) - ); -} - -#[tokio::test] -async fn fail_decrease_twice() { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake, - _deposit_info, - decrease_lamports, - ) = setup().await; - - let error = stake_pool_accounts - .decrease_validator_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - decrease_lamports, - validator_stake.transient_stake_seed, - ) - .await; - assert!(error.is_none()); - - let transient_stake_seed = validator_stake.transient_stake_seed * 100; - let transient_stake_address = find_transient_stake_program_address( - &id(), - &validator_stake.vote.pubkey(), - &stake_pool_accounts.stake_pool.pubkey(), - transient_stake_seed, - ) - .0; - let error = stake_pool_accounts - .decrease_validator_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &validator_stake.stake_account, - &transient_stake_address, - decrease_lamports, - transient_stake_seed, - ) - .await - .unwrap() - .unwrap(); - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = StakePoolError::TransientAccountInUse as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error"), - } -} - -#[tokio::test] -async fn fail_with_small_lamport_amount() { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake, - _deposit_info, - _decrease_lamports, - ) = setup().await; - - let rent = banks_client.get_rent().await.unwrap(); - let lamports = rent.minimum_balance(std::mem::size_of::()); - - let error = stake_pool_accounts - .decrease_validator_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - lamports, - validator_stake.transient_stake_seed, - ) - .await - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::AccountNotRentExempt) => {} - _ => panic!("Wrong error occurs while try to decrease small stake"), - } -} - -#[tokio::test] -async fn fail_big_overdraw() { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake, - deposit_info, - _decrease_lamports, - ) = setup().await; - - let error = stake_pool_accounts - .decrease_validator_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - deposit_info.stake_lamports * 1_000_000, - validator_stake.transient_stake_seed, - ) - .await - .unwrap() - .unwrap(); - - assert_eq!( - error, - TransactionError::InstructionError(0, InstructionError::InsufficientFunds) - ); -} - -#[tokio::test] -async fn fail_overdraw() { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake, - deposit_info, - _decrease_lamports, - ) = setup().await; - - let rent = banks_client.get_rent().await.unwrap(); - let stake_rent = rent.minimum_balance(std::mem::size_of::()); - - let error = stake_pool_accounts - .decrease_validator_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - deposit_info.stake_lamports + stake_rent + 1, - validator_stake.transient_stake_seed, - ) - .await - .unwrap() - .unwrap(); - - assert_eq!( - error, - TransactionError::InstructionError(0, InstructionError::InsufficientFunds) - ); -} diff --git a/stake-pool/program/tests/deposit.rs b/stake-pool/program/tests/deposit.rs deleted file mode 100644 index d38bb63a249..00000000000 --- a/stake-pool/program/tests/deposit.rs +++ /dev/null @@ -1,1019 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod helpers; - -use { - bincode::deserialize, - borsh::BorshSerialize, - helpers::*, - solana_program::{ - borsh::try_from_slice_unchecked, - instruction::{AccountMeta, Instruction, InstructionError}, - pubkey::Pubkey, - stake, sysvar, - }, - solana_program_test::*, - solana_sdk::{ - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, - transport::TransportError, - }, - spl_stake_pool::{ - error::StakePoolError, id, instruction, minimum_stake_lamports, state, - MINIMUM_RESERVE_LAMPORTS, - }, - spl_token::error as token_error, -}; - -async fn setup() -> ( - ProgramTestContext, - StakePoolAccounts, - ValidatorStakeAccount, - Keypair, - Pubkey, - Pubkey, - u64, -) { - let mut context = program_test().start_with_context().await; - - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let validator_stake_account = simple_add_validator_to_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_pool_accounts, - ) - .await; - - let first_normal_slot = context.genesis_config().epoch_schedule.first_normal_slot; - let slots_per_epoch = context.genesis_config().epoch_schedule.slots_per_epoch; - let mut slot = first_normal_slot; - context.warp_to_slot(slot).unwrap(); - - let user = Keypair::new(); - // make stake account - let deposit_stake = Keypair::new(); - let lockup = stake::state::Lockup::default(); - - let authorized = stake::state::Authorized { - staker: user.pubkey(), - withdrawer: user.pubkey(), - }; - - let stake_lamports = create_independent_stake_account( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &deposit_stake, - &authorized, - &lockup, - TEST_STAKE_AMOUNT, - ) - .await; - - delegate_stake_account( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &deposit_stake.pubkey(), - &user, - &validator_stake_account.vote.pubkey(), - ) - .await; - - slot += slots_per_epoch; - context.warp_to_slot(slot).unwrap(); - stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &[validator_stake_account.vote.pubkey()], - false, - ) - .await; - - // make pool token account - let pool_token_account = Keypair::new(); - create_token_account( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &pool_token_account, - &stake_pool_accounts.pool_mint.pubkey(), - &user.pubkey(), - ) - .await - .unwrap(); - - ( - context, - stake_pool_accounts, - validator_stake_account, - user, - deposit_stake.pubkey(), - pool_token_account.pubkey(), - stake_lamports, - ) -} - -#[tokio::test] -async fn success() { - let ( - mut context, - stake_pool_accounts, - validator_stake_account, - user, - deposit_stake, - pool_token_account, - stake_lamports, - ) = setup().await; - - let rent = context.banks_client.get_rent().await.unwrap(); - let stake_rent = rent.minimum_balance(std::mem::size_of::()); - - // Save stake pool state before depositing - let pre_stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let pre_stake_pool = - try_from_slice_unchecked::(pre_stake_pool.data.as_slice()).unwrap(); - - // Save validator stake account record before depositing - let validator_list = get_account( - &mut context.banks_client, - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let validator_list = - try_from_slice_unchecked::(validator_list.data.as_slice()).unwrap(); - let pre_validator_stake_item = validator_list - .find(&validator_stake_account.vote.pubkey()) - .unwrap(); - - // Save reserve state before depositing - let pre_reserve_lamports = get_account( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - ) - .await - .lamports; - - let error = stake_pool_accounts - .deposit_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &deposit_stake, - &pool_token_account, - &validator_stake_account.stake_account, - &user, - ) - .await; - assert!(error.is_none()); - - // Original stake account should be drained - assert!(context - .banks_client - .get_account(deposit_stake) - .await - .expect("get_account") - .is_none()); - - let tokens_issued = stake_lamports; // For now tokens are 1:1 to stake - - // Stake pool should add its balance to the pool balance - let post_stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let post_stake_pool = - try_from_slice_unchecked::(post_stake_pool.data.as_slice()).unwrap(); - assert_eq!( - post_stake_pool.total_lamports, - pre_stake_pool.total_lamports + stake_lamports - ); - assert_eq!( - post_stake_pool.pool_token_supply, - pre_stake_pool.pool_token_supply + tokens_issued - ); - - // Check minted tokens - let user_token_balance = - get_token_balance(&mut context.banks_client, &pool_token_account).await; - let tokens_issued_user = tokens_issued - - post_stake_pool - .calc_pool_tokens_sol_deposit_fee(stake_rent) - .unwrap() - - post_stake_pool - .calc_pool_tokens_stake_deposit_fee(stake_lamports - stake_rent) - .unwrap(); - assert_eq!(user_token_balance, tokens_issued_user); - - // Check balances in validator stake account list storage - let validator_list = get_account( - &mut context.banks_client, - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let validator_list = - try_from_slice_unchecked::(validator_list.data.as_slice()).unwrap(); - let post_validator_stake_item = validator_list - .find(&validator_stake_account.vote.pubkey()) - .unwrap(); - assert_eq!( - post_validator_stake_item.stake_lamports(), - pre_validator_stake_item.stake_lamports() + stake_lamports - stake_rent, - ); - - // Check validator stake account actual SOL balance - let validator_stake_account = get_account( - &mut context.banks_client, - &validator_stake_account.stake_account, - ) - .await; - let stake_state = - deserialize::(&validator_stake_account.data).unwrap(); - let meta = stake_state.meta().unwrap(); - assert_eq!( - validator_stake_account.lamports - minimum_stake_lamports(&meta), - post_validator_stake_item.stake_lamports() - ); - assert_eq!(post_validator_stake_item.transient_stake_lamports, 0); - - // Check reserve - let post_reserve_lamports = get_account( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - ) - .await - .lamports; - assert_eq!(post_reserve_lamports, pre_reserve_lamports + stake_rent); -} - -#[tokio::test] -async fn success_with_extra_stake_lamports() { - let ( - mut context, - stake_pool_accounts, - validator_stake_account, - user, - deposit_stake, - pool_token_account, - stake_lamports, - ) = setup().await; - - let extra_lamports = TEST_STAKE_AMOUNT * 3 + 1; - - transfer( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &deposit_stake, - extra_lamports, - ) - .await; - - let referrer = Keypair::new(); - let referrer_token_account = Keypair::new(); - create_token_account( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &referrer_token_account, - &stake_pool_accounts.pool_mint.pubkey(), - &referrer.pubkey(), - ) - .await - .unwrap(); - - let referrer_balance_pre = - get_token_balance(&mut context.banks_client, &referrer_token_account.pubkey()).await; - - let manager_pool_balance_pre = get_token_balance( - &mut context.banks_client, - &stake_pool_accounts.pool_fee_account.pubkey(), - ) - .await; - - let rent = context.banks_client.get_rent().await.unwrap(); - let stake_rent = rent.minimum_balance(std::mem::size_of::()); - - // Save stake pool state before depositing - let pre_stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let pre_stake_pool = - try_from_slice_unchecked::(pre_stake_pool.data.as_slice()).unwrap(); - - // Save validator stake account record before depositing - let validator_list = get_account( - &mut context.banks_client, - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let validator_list = - try_from_slice_unchecked::(validator_list.data.as_slice()).unwrap(); - let pre_validator_stake_item = validator_list - .find(&validator_stake_account.vote.pubkey()) - .unwrap(); - - // Save reserve state before depositing - let pre_reserve_lamports = get_account( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - ) - .await - .lamports; - - let error = stake_pool_accounts - .deposit_stake_with_referral( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &deposit_stake, - &pool_token_account, - &validator_stake_account.stake_account, - &user, - &referrer_token_account.pubkey(), - ) - .await; - assert!(error.is_none()); - - // Original stake account should be drained - assert!(context - .banks_client - .get_account(deposit_stake) - .await - .expect("get_account") - .is_none()); - - let tokens_issued = stake_lamports + extra_lamports; - // For now tokens are 1:1 to stake - - // Stake pool should add its balance to the pool balance - - // The extra lamports will not get recorded in total stake lamports unless - // update_stake_pool_balance is called - let post_stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - - let post_stake_pool = - try_from_slice_unchecked::(post_stake_pool.data.as_slice()).unwrap(); - assert_eq!( - post_stake_pool.total_lamports, - pre_stake_pool.total_lamports + extra_lamports + stake_lamports - ); - assert_eq!( - post_stake_pool.pool_token_supply, - pre_stake_pool.pool_token_supply + tokens_issued - ); - - // Check minted tokens - let user_token_balance = - get_token_balance(&mut context.banks_client, &pool_token_account).await; - - let fee_tokens = post_stake_pool - .calc_pool_tokens_sol_deposit_fee(extra_lamports + stake_rent) - .unwrap() - + post_stake_pool - .calc_pool_tokens_stake_deposit_fee(stake_lamports - stake_rent) - .unwrap(); - let tokens_issued_user = tokens_issued - fee_tokens; - assert_eq!(user_token_balance, tokens_issued_user); - - let referrer_balance_post = - get_token_balance(&mut context.banks_client, &referrer_token_account.pubkey()).await; - - let referral_fee = stake_pool_accounts.calculate_referral_fee(fee_tokens); - let manager_fee = fee_tokens - referral_fee; - - assert_eq!(referrer_balance_post - referrer_balance_pre, referral_fee); - - let manager_pool_balance_post = get_token_balance( - &mut context.banks_client, - &stake_pool_accounts.pool_fee_account.pubkey(), - ) - .await; - assert_eq!( - manager_pool_balance_post - manager_pool_balance_pre, - manager_fee - ); - - // Check balances in validator stake account list storage - let validator_list = get_account( - &mut context.banks_client, - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let validator_list = - try_from_slice_unchecked::(validator_list.data.as_slice()).unwrap(); - let post_validator_stake_item = validator_list - .find(&validator_stake_account.vote.pubkey()) - .unwrap(); - assert_eq!( - post_validator_stake_item.stake_lamports(), - pre_validator_stake_item.stake_lamports() + stake_lamports - stake_rent, - ); - - // Check validator stake account actual SOL balance - let validator_stake_account = get_account( - &mut context.banks_client, - &validator_stake_account.stake_account, - ) - .await; - let stake_state = - deserialize::(&validator_stake_account.data).unwrap(); - let meta = stake_state.meta().unwrap(); - assert_eq!( - validator_stake_account.lamports - minimum_stake_lamports(&meta), - post_validator_stake_item.stake_lamports() - ); - assert_eq!(post_validator_stake_item.transient_stake_lamports, 0); - - // Check reserve - let post_reserve_lamports = get_account( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - ) - .await - .lamports; - assert_eq!( - post_reserve_lamports, - pre_reserve_lamports + stake_rent + extra_lamports - ); -} - -#[tokio::test] -async fn fail_with_wrong_stake_program_id() { - let ( - mut context, - stake_pool_accounts, - validator_stake_account, - _user, - deposit_stake, - pool_token_account, - _stake_lamports, - ) = setup().await; - - let wrong_stake_program = Pubkey::new_unique(); - - let accounts = vec![ - AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false), - AccountMeta::new(stake_pool_accounts.validator_list.pubkey(), false), - AccountMeta::new_readonly(stake_pool_accounts.stake_deposit_authority, false), - AccountMeta::new_readonly(stake_pool_accounts.withdraw_authority, false), - AccountMeta::new(deposit_stake, false), - AccountMeta::new(validator_stake_account.stake_account, false), - AccountMeta::new(stake_pool_accounts.reserve_stake.pubkey(), false), - AccountMeta::new(pool_token_account, false), - AccountMeta::new(stake_pool_accounts.pool_fee_account.pubkey(), false), - AccountMeta::new(stake_pool_accounts.pool_fee_account.pubkey(), false), - AccountMeta::new(stake_pool_accounts.pool_mint.pubkey(), false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - AccountMeta::new_readonly(sysvar::stake_history::id(), false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new_readonly(wrong_stake_program, false), - ]; - let instruction = Instruction { - program_id: id(), - accounts, - data: instruction::StakePoolInstruction::DepositStake - .try_to_vec() - .unwrap(), - }; - - let mut transaction = - Transaction::new_with_payer(&[instruction], Some(&context.payer.pubkey())); - transaction.sign(&[&context.payer], context.last_blockhash); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError(_, error)) => { - assert_eq!(error, InstructionError::IncorrectProgramId); - } - _ => panic!("Wrong error occurs while try to make a deposit with wrong stake program ID"), - } -} - -#[tokio::test] -async fn fail_with_wrong_token_program_id() { - let ( - mut context, - stake_pool_accounts, - validator_stake_account, - user, - deposit_stake, - pool_token_account, - _stake_lamports, - ) = setup().await; - - let wrong_token_program = Keypair::new(); - - let mut transaction = Transaction::new_with_payer( - &instruction::deposit_stake( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - &stake_pool_accounts.withdraw_authority, - &deposit_stake, - &user.pubkey(), - &validator_stake_account.stake_account, - &stake_pool_accounts.reserve_stake.pubkey(), - &pool_token_account, - &stake_pool_accounts.pool_fee_account.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &wrong_token_program.pubkey(), - ), - Some(&context.payer.pubkey()), - ); - transaction.sign(&[&context.payer, &user], context.last_blockhash); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError(_, error)) => { - assert_eq!(error, InstructionError::IncorrectProgramId); - } - _ => panic!("Wrong error occurs while try to make a deposit with wrong token program ID"), - } -} - -#[tokio::test] -async fn fail_with_wrong_validator_list_account() { - let ( - mut context, - mut stake_pool_accounts, - validator_stake_account, - user, - deposit_stake, - pool_token_account, - _stake_lamports, - ) = setup().await; - - let wrong_validator_list = Keypair::new(); - stake_pool_accounts.validator_list = wrong_validator_list; - - let transaction_error = stake_pool_accounts - .deposit_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &deposit_stake, - &pool_token_account, - &validator_stake_account.stake_account, - &user, - ) - .await - .unwrap() - .unwrap(); - - match transaction_error { - TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - ) => { - let program_error = StakePoolError::InvalidValidatorStakeList as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while try to make a deposit with wrong validator stake list account"), - } -} - -#[tokio::test] -async fn fail_with_unknown_validator() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let unknown_stake = create_unknown_validator_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - - let user = Keypair::new(); - let user_pool_account = Keypair::new(); - create_token_account( - &mut banks_client, - &payer, - &recent_blockhash, - &user_pool_account, - &stake_pool_accounts.pool_mint.pubkey(), - &user.pubkey(), - ) - .await - .unwrap(); - - // make stake account - let user_stake = Keypair::new(); - let lockup = stake::state::Lockup::default(); - let authorized = stake::state::Authorized { - staker: user.pubkey(), - withdrawer: user.pubkey(), - }; - create_independent_stake_account( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake, - &authorized, - &lockup, - TEST_STAKE_AMOUNT, - ) - .await; - delegate_stake_account( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake.pubkey(), - &user, - &unknown_stake.vote.pubkey(), - ) - .await; - - let error = stake_pool_accounts - .deposit_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake.pubkey(), - &user_pool_account.pubkey(), - &unknown_stake.stake_account, - &user, - ) - .await - .unwrap() - .unwrap(); - - assert_eq!( - error, - TransactionError::InstructionError( - 2, - InstructionError::Custom(StakePoolError::InvalidStakeAccountAddress as u32) - ) - ); -} - -#[tokio::test] -async fn fail_with_wrong_withdraw_authority() { - let ( - mut context, - mut stake_pool_accounts, - validator_stake_account, - user, - deposit_stake, - pool_token_account, - _stake_lamports, - ) = setup().await; - - stake_pool_accounts.withdraw_authority = Pubkey::new_unique(); - - let transaction_error = stake_pool_accounts - .deposit_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &deposit_stake, - &pool_token_account, - &validator_stake_account.stake_account, - &user, - ) - .await - .unwrap() - .unwrap(); - - match transaction_error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = StakePoolError::InvalidProgramAddress as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while try to make a deposit with wrong withdraw authority"), - } -} - -#[tokio::test] -async fn fail_with_wrong_mint_for_receiver_acc() { - let ( - mut context, - stake_pool_accounts, - validator_stake_account, - user, - deposit_stake, - _pool_token_account, - _stake_lamports, - ) = setup().await; - - let outside_mint = Keypair::new(); - let outside_withdraw_auth = Keypair::new(); - let outside_manager = Keypair::new(); - let outside_pool_fee_acc = Keypair::new(); - - create_mint( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &outside_mint, - &outside_withdraw_auth.pubkey(), - ) - .await - .unwrap(); - - create_token_account( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &outside_pool_fee_acc, - &outside_mint.pubkey(), - &outside_manager.pubkey(), - ) - .await - .unwrap(); - - let transaction_error = stake_pool_accounts - .deposit_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &deposit_stake, - &outside_pool_fee_acc.pubkey(), - &validator_stake_account.stake_account, - &user, - ) - .await - .unwrap() - .unwrap(); - - match transaction_error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = token_error::TokenError::MintMismatch as u32; - assert_eq!(error_index, program_error); - } - _ => { - panic!("Wrong error occurs while try to deposit with wrong mint from receiver account") - } - } -} - -#[tokio::test] -async fn fail_with_uninitialized_validator_list() {} // TODO - -#[tokio::test] -async fn fail_with_out_of_dated_pool_balances() {} // TODO - -#[tokio::test] -async fn success_with_preferred_deposit() { - let ( - mut context, - stake_pool_accounts, - validator_stake, - user, - deposit_stake, - pool_token_account, - _stake_lamports, - ) = setup().await; - - stake_pool_accounts - .set_preferred_validator( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - instruction::PreferredValidatorType::Deposit, - Some(validator_stake.vote.pubkey()), - ) - .await; - - let error = stake_pool_accounts - .deposit_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &deposit_stake, - &pool_token_account, - &validator_stake.stake_account, - &user, - ) - .await; - assert!(error.is_none()); -} - -#[tokio::test] -async fn fail_with_wrong_preferred_deposit() { - let ( - mut context, - stake_pool_accounts, - validator_stake, - user, - deposit_stake, - pool_token_account, - _stake_lamports, - ) = setup().await; - - let preferred_validator = simple_add_validator_to_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_pool_accounts, - ) - .await; - - stake_pool_accounts - .set_preferred_validator( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - instruction::PreferredValidatorType::Deposit, - Some(preferred_validator.vote.pubkey()), - ) - .await; - - let error = stake_pool_accounts - .deposit_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &deposit_stake, - &pool_token_account, - &validator_stake.stake_account, - &user, - ) - .await - .unwrap() - .unwrap(); - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - assert_eq!( - error_index, - StakePoolError::IncorrectDepositVoteAddress as u32 - ); - } - _ => panic!("Wrong error occurs while try to make a deposit with wrong stake program ID"), - } -} - -#[tokio::test] -async fn success_with_referral_fee() { - let ( - mut context, - stake_pool_accounts, - validator_stake_account, - user, - deposit_stake, - pool_token_account, - stake_lamports, - ) = setup().await; - - let referrer = Keypair::new(); - let referrer_token_account = Keypair::new(); - create_token_account( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &referrer_token_account, - &stake_pool_accounts.pool_mint.pubkey(), - &referrer.pubkey(), - ) - .await - .unwrap(); - - let referrer_balance_pre = - get_token_balance(&mut context.banks_client, &referrer_token_account.pubkey()).await; - - let mut transaction = Transaction::new_with_payer( - &instruction::deposit_stake( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - &stake_pool_accounts.withdraw_authority, - &deposit_stake, - &user.pubkey(), - &validator_stake_account.stake_account, - &stake_pool_accounts.reserve_stake.pubkey(), - &pool_token_account, - &stake_pool_accounts.pool_fee_account.pubkey(), - &referrer_token_account.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &spl_token::id(), - ), - Some(&context.payer.pubkey()), - ); - transaction.sign(&[&context.payer, &user], context.last_blockhash); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let referrer_balance_post = - get_token_balance(&mut context.banks_client, &referrer_token_account.pubkey()).await; - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = - try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - let rent = context.banks_client.get_rent().await.unwrap(); - let stake_rent = rent.minimum_balance(std::mem::size_of::()); - let fee_tokens = stake_pool - .calc_pool_tokens_sol_deposit_fee(stake_rent) - .unwrap() - + stake_pool - .calc_pool_tokens_stake_deposit_fee(stake_lamports - stake_rent) - .unwrap(); - let referral_fee = stake_pool_accounts.calculate_referral_fee(fee_tokens); - assert!(referral_fee > 0); - assert_eq!(referrer_balance_pre + referral_fee, referrer_balance_post); -} - -#[tokio::test] -async fn fail_with_invalid_referrer() { - let ( - mut context, - stake_pool_accounts, - validator_stake_account, - user, - deposit_stake, - pool_token_account, - _stake_lamports, - ) = setup().await; - - let invalid_token_account = Keypair::new(); - - let mut transaction = Transaction::new_with_payer( - &instruction::deposit_stake( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - &stake_pool_accounts.withdraw_authority, - &deposit_stake, - &user.pubkey(), - &validator_stake_account.stake_account, - &stake_pool_accounts.reserve_stake.pubkey(), - &pool_token_account, - &stake_pool_accounts.pool_fee_account.pubkey(), - &invalid_token_account.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &spl_token::id(), - ), - Some(&context.payer.pubkey()), - ); - transaction.sign(&[&context.payer, &user], context.last_blockhash); - let transaction_error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match transaction_error { - TransactionError::InstructionError(_, InstructionError::InvalidAccountData) => (), - _ => panic!( - "Wrong error occurs while try to make a deposit with an invalid referrer account" - ), - } -} diff --git a/stake-pool/program/tests/deposit_authority.rs b/stake-pool/program/tests/deposit_authority.rs deleted file mode 100644 index afae4c086a1..00000000000 --- a/stake-pool/program/tests/deposit_authority.rs +++ /dev/null @@ -1,215 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod helpers; - -use { - helpers::*, - solana_program::{instruction::InstructionError, stake}, - solana_program_test::*, - solana_sdk::{ - borsh::try_from_slice_unchecked, - signature::{Keypair, Signer}, - transaction::TransactionError, - }, - spl_stake_pool::{error::StakePoolError, state::StakePool, MINIMUM_RESERVE_LAMPORTS}, -}; - -#[tokio::test] -async fn success_initialize() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let deposit_authority = Keypair::new(); - let stake_pool_accounts = StakePoolAccounts::new_with_deposit_authority(deposit_authority); - let deposit_authority = stake_pool_accounts.stake_deposit_authority; - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - // Stake pool now exists - let stake_pool_account = - get_account(&mut banks_client, &stake_pool_accounts.stake_pool.pubkey()).await; - let stake_pool = - try_from_slice_unchecked::(stake_pool_account.data.as_slice()).unwrap(); - assert_eq!(stake_pool.stake_deposit_authority, deposit_authority); - assert_eq!(stake_pool.sol_deposit_authority.unwrap(), deposit_authority); -} - -#[tokio::test] -async fn success_deposit() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_deposit_authority = Keypair::new(); - let stake_pool_accounts = - StakePoolAccounts::new_with_deposit_authority(stake_deposit_authority); - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let validator_stake_account = simple_add_validator_to_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - ) - .await; - - let user = Keypair::new(); - let user_stake = Keypair::new(); - let lockup = stake::state::Lockup::default(); - let authorized = stake::state::Authorized { - staker: user.pubkey(), - withdrawer: user.pubkey(), - }; - - let _stake_lamports = create_independent_stake_account( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake, - &authorized, - &lockup, - TEST_STAKE_AMOUNT, - ) - .await; - - delegate_stake_account( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake.pubkey(), - &user, - &validator_stake_account.vote.pubkey(), - ) - .await; - - // make pool token account - let user_pool_account = Keypair::new(); - create_token_account( - &mut banks_client, - &payer, - &recent_blockhash, - &user_pool_account, - &stake_pool_accounts.pool_mint.pubkey(), - &user.pubkey(), - ) - .await - .unwrap(); - - let error = stake_pool_accounts - .deposit_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake.pubkey(), - &user_pool_account.pubkey(), - &validator_stake_account.stake_account, - &user, - ) - .await; - assert!(error.is_none()); -} - -#[tokio::test] -async fn fail_deposit_without_authority_signature() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_deposit_authority = Keypair::new(); - let mut stake_pool_accounts = - StakePoolAccounts::new_with_deposit_authority(stake_deposit_authority); - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let validator_stake_account = simple_add_validator_to_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - ) - .await; - - let user = Keypair::new(); - let user_stake = Keypair::new(); - let lockup = stake::state::Lockup::default(); - let authorized = stake::state::Authorized { - staker: user.pubkey(), - withdrawer: user.pubkey(), - }; - - let _stake_lamports = create_independent_stake_account( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake, - &authorized, - &lockup, - TEST_STAKE_AMOUNT, - ) - .await; - - delegate_stake_account( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake.pubkey(), - &user, - &validator_stake_account.vote.pubkey(), - ) - .await; - - // make pool token account - let user_pool_account = Keypair::new(); - create_token_account( - &mut banks_client, - &payer, - &recent_blockhash, - &user_pool_account, - &stake_pool_accounts.pool_mint.pubkey(), - &user.pubkey(), - ) - .await - .unwrap(); - - let wrong_depositor = Keypair::new(); - stake_pool_accounts.stake_deposit_authority = wrong_depositor.pubkey(); - stake_pool_accounts.stake_deposit_authority_keypair = Some(wrong_depositor); - - let error = stake_pool_accounts - .deposit_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake.pubkey(), - &user_pool_account.pubkey(), - &validator_stake_account.stake_account, - &user, - ) - .await - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - assert_eq!( - error_index, - StakePoolError::InvalidStakeDepositAuthority as u32 - ); - } - _ => panic!("Wrong error occurs while try to make a deposit with wrong stake program ID"), - } -} diff --git a/stake-pool/program/tests/deposit_sol.rs b/stake-pool/program/tests/deposit_sol.rs deleted file mode 100644 index 72121a0e29f..00000000000 --- a/stake-pool/program/tests/deposit_sol.rs +++ /dev/null @@ -1,482 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod helpers; - -use { - helpers::*, - solana_program::{ - borsh::try_from_slice_unchecked, instruction::InstructionError, pubkey::Pubkey, - }, - solana_program_test::*, - solana_sdk::{ - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, - transport::TransportError, - }, - spl_stake_pool::{ - error, id, - instruction::{self, FundingType}, - state, MINIMUM_RESERVE_LAMPORTS, - }, - spl_token::error as token_error, -}; - -async fn setup() -> (ProgramTestContext, StakePoolAccounts, Keypair, Pubkey) { - let mut context = program_test().start_with_context().await; - - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let user = Keypair::new(); - - // make pool token account for user - let pool_token_account = Keypair::new(); - create_token_account( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &pool_token_account, - &stake_pool_accounts.pool_mint.pubkey(), - &user.pubkey(), - ) - .await - .unwrap(); - - ( - context, - stake_pool_accounts, - user, - pool_token_account.pubkey(), - ) -} - -#[tokio::test] -async fn success() { - let (mut context, stake_pool_accounts, _user, pool_token_account) = setup().await; - - // Save stake pool state before depositing - let pre_stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let pre_stake_pool = - try_from_slice_unchecked::(pre_stake_pool.data.as_slice()).unwrap(); - - // Save reserve state before depositing - let pre_reserve_lamports = get_account( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - ) - .await - .lamports; - - let error = stake_pool_accounts - .deposit_sol( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &pool_token_account, - TEST_STAKE_AMOUNT, - None, - ) - .await; - assert!(error.is_none()); - - let tokens_issued = TEST_STAKE_AMOUNT; // For now tokens are 1:1 to stake - - // Stake pool should add its balance to the pool balance - let post_stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let post_stake_pool = - try_from_slice_unchecked::(post_stake_pool.data.as_slice()).unwrap(); - assert_eq!( - post_stake_pool.total_lamports, - pre_stake_pool.total_lamports + TEST_STAKE_AMOUNT - ); - assert_eq!( - post_stake_pool.pool_token_supply, - pre_stake_pool.pool_token_supply + tokens_issued - ); - - // Check minted tokens - let user_token_balance = - get_token_balance(&mut context.banks_client, &pool_token_account).await; - let tokens_issued_user = - tokens_issued - stake_pool_accounts.calculate_sol_deposit_fee(tokens_issued); - assert_eq!(user_token_balance, tokens_issued_user); - - // Check reserve - let post_reserve_lamports = get_account( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - ) - .await - .lamports; - assert_eq!( - post_reserve_lamports, - pre_reserve_lamports + TEST_STAKE_AMOUNT - ); -} - -#[tokio::test] -async fn fail_with_wrong_token_program_id() { - let (mut context, stake_pool_accounts, _user, pool_token_account) = setup().await; - - let wrong_token_program = Keypair::new(); - - let mut transaction = Transaction::new_with_payer( - &[instruction::deposit_sol( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.withdraw_authority, - &stake_pool_accounts.reserve_stake.pubkey(), - &context.payer.pubkey(), - &pool_token_account, - &stake_pool_accounts.pool_fee_account.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &wrong_token_program.pubkey(), - TEST_STAKE_AMOUNT, - )], - Some(&context.payer.pubkey()), - ); - transaction.sign(&[&context.payer], context.last_blockhash); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError(_, error)) => { - assert_eq!(error, InstructionError::IncorrectProgramId); - } - _ => panic!("Wrong error occurs while try to make a deposit with wrong token program ID"), - } -} - -#[tokio::test] -async fn fail_with_wrong_withdraw_authority() { - let (mut context, mut stake_pool_accounts, _user, pool_token_account) = setup().await; - - stake_pool_accounts.withdraw_authority = Pubkey::new_unique(); - - let transaction_error = stake_pool_accounts - .deposit_sol( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &pool_token_account, - TEST_STAKE_AMOUNT, - None, - ) - .await - .unwrap() - .unwrap(); - - match transaction_error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = error::StakePoolError::InvalidProgramAddress as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while try to make a deposit with wrong withdraw authority"), - } -} - -#[tokio::test] -async fn fail_with_wrong_mint_for_receiver_acc() { - let (mut context, stake_pool_accounts, _user, _pool_token_account) = setup().await; - - let outside_mint = Keypair::new(); - let outside_withdraw_auth = Keypair::new(); - let outside_manager = Keypair::new(); - let outside_pool_fee_acc = Keypair::new(); - - create_mint( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &outside_mint, - &outside_withdraw_auth.pubkey(), - ) - .await - .unwrap(); - - create_token_account( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &outside_pool_fee_acc, - &outside_mint.pubkey(), - &outside_manager.pubkey(), - ) - .await - .unwrap(); - - let transaction_error = stake_pool_accounts - .deposit_sol( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &outside_pool_fee_acc.pubkey(), - TEST_STAKE_AMOUNT, - None, - ) - .await - .unwrap() - .unwrap(); - - match transaction_error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = token_error::TokenError::MintMismatch as u32; - assert_eq!(error_index, program_error); - } - _ => { - panic!("Wrong error occurs while try to deposit with wrong mint from receiver account") - } - } -} - -#[tokio::test] -async fn success_with_sol_deposit_authority() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let user = Keypair::new(); - - // make pool token account - let user_pool_account = Keypair::new(); - create_token_account( - &mut banks_client, - &payer, - &recent_blockhash, - &user_pool_account, - &stake_pool_accounts.pool_mint.pubkey(), - &user.pubkey(), - ) - .await - .unwrap(); - - let error = stake_pool_accounts - .deposit_sol( - &mut banks_client, - &payer, - &recent_blockhash, - &user_pool_account.pubkey(), - TEST_STAKE_AMOUNT, - None, - ) - .await; - assert!(error.is_none()); - - let sol_deposit_authority = Keypair::new(); - - let mut transaction = Transaction::new_with_payer( - &[instruction::set_funding_authority( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - Some(&sol_deposit_authority.pubkey()), - FundingType::SolDeposit, - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &stake_pool_accounts.manager], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - let error = stake_pool_accounts - .deposit_sol( - &mut banks_client, - &payer, - &recent_blockhash, - &user_pool_account.pubkey(), - TEST_STAKE_AMOUNT, - Some(&sol_deposit_authority), - ) - .await; - assert!(error.is_none()); -} - -#[tokio::test] -async fn fail_without_sol_deposit_authority_signature() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let sol_deposit_authority = Keypair::new(); - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let user = Keypair::new(); - - // make pool token account - let user_pool_account = Keypair::new(); - create_token_account( - &mut banks_client, - &payer, - &recent_blockhash, - &user_pool_account, - &stake_pool_accounts.pool_mint.pubkey(), - &user.pubkey(), - ) - .await - .unwrap(); - - let mut transaction = Transaction::new_with_payer( - &[instruction::set_funding_authority( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - Some(&sol_deposit_authority.pubkey()), - FundingType::SolDeposit, - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &stake_pool_accounts.manager], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - let wrong_depositor = Keypair::new(); - - let error = stake_pool_accounts - .deposit_sol( - &mut banks_client, - &payer, - &recent_blockhash, - &user_pool_account.pubkey(), - TEST_STAKE_AMOUNT, - Some(&wrong_depositor), - ) - .await - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - assert_eq!( - error_index, - error::StakePoolError::InvalidSolDepositAuthority as u32 - ); - } - _ => panic!("Wrong error occurs while trying to make a deposit without SOL deposit authority signature"), - } -} - -#[tokio::test] -async fn success_with_referral_fee() { - let (mut context, stake_pool_accounts, _user, pool_token_account) = setup().await; - - let referrer = Keypair::new(); - let referrer_token_account = Keypair::new(); - create_token_account( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &referrer_token_account, - &stake_pool_accounts.pool_mint.pubkey(), - &referrer.pubkey(), - ) - .await - .unwrap(); - - let referrer_balance_pre = - get_token_balance(&mut context.banks_client, &referrer_token_account.pubkey()).await; - - let mut transaction = Transaction::new_with_payer( - &[instruction::deposit_sol( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.withdraw_authority, - &stake_pool_accounts.reserve_stake.pubkey(), - &context.payer.pubkey(), - &pool_token_account, - &stake_pool_accounts.pool_fee_account.pubkey(), - &referrer_token_account.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &spl_token::id(), - TEST_STAKE_AMOUNT, - )], - Some(&context.payer.pubkey()), - ); - transaction.sign(&[&context.payer], context.last_blockhash); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let referrer_balance_post = - get_token_balance(&mut context.banks_client, &referrer_token_account.pubkey()).await; - let referral_fee = stake_pool_accounts.calculate_sol_referral_fee( - stake_pool_accounts.calculate_sol_deposit_fee(TEST_STAKE_AMOUNT), - ); - assert!(referral_fee > 0); - assert_eq!(referrer_balance_pre + referral_fee, referrer_balance_post); -} - -#[tokio::test] -async fn fail_with_invalid_referrer() { - let (mut context, stake_pool_accounts, _user, pool_token_account) = setup().await; - - let invalid_token_account = Keypair::new(); - - let mut transaction = Transaction::new_with_payer( - &[instruction::deposit_sol( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.withdraw_authority, - &stake_pool_accounts.reserve_stake.pubkey(), - &context.payer.pubkey(), - &pool_token_account, - &stake_pool_accounts.pool_fee_account.pubkey(), - &invalid_token_account.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &spl_token::id(), - TEST_STAKE_AMOUNT, - )], - Some(&context.payer.pubkey()), - ); - transaction.sign(&[&context.payer], context.last_blockhash); - let transaction_error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match transaction_error { - TransactionError::InstructionError(_, InstructionError::InvalidAccountData) => (), - _ => panic!( - "Wrong error occurs while try to make a deposit with an invalid referrer account" - ), - } -} diff --git a/stake-pool/program/tests/fixtures/mpl_token_metadata.so b/stake-pool/program/tests/fixtures/mpl_token_metadata.so deleted file mode 100755 index f7b3c9f1793..00000000000 Binary files a/stake-pool/program/tests/fixtures/mpl_token_metadata.so and /dev/null differ diff --git a/stake-pool/program/tests/force_destake.rs b/stake-pool/program/tests/force_destake.rs deleted file mode 100644 index afc33fb65f3..00000000000 --- a/stake-pool/program/tests/force_destake.rs +++ /dev/null @@ -1,193 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod helpers; - -use { - helpers::*, - solana_program::{instruction::InstructionError, pubkey::Pubkey, stake}, - solana_program_test::*, - solana_sdk::{ - account::{Account, WritableAccount}, - clock::Epoch, - signature::Signer, - transaction::TransactionError, - }, - spl_stake_pool::{ - error::StakePoolError, - find_stake_program_address, find_transient_stake_program_address, id, - state::{StakeStatus, ValidatorStakeInfo}, - MINIMUM_ACTIVE_STAKE, - }, -}; - -async fn setup() -> (ProgramTestContext, StakePoolAccounts, Pubkey) { - let mut program_test = program_test(); - let stake_pool_accounts = StakePoolAccounts::new(); - - let stake_pool_pubkey = stake_pool_accounts.stake_pool.pubkey(); - let (mut stake_pool, mut validator_list) = stake_pool_accounts.state(); - - let voter_pubkey = add_vote_account(&mut program_test); - let meta = stake::state::Meta { - rent_exempt_reserve: STAKE_ACCOUNT_RENT_EXEMPTION, - authorized: stake::state::Authorized { - staker: stake_pool_accounts.withdraw_authority, - withdrawer: stake_pool_accounts.withdraw_authority, - }, - lockup: stake_pool.lockup, - }; - - let stake_account = Account::create( - TEST_STAKE_AMOUNT + STAKE_ACCOUNT_RENT_EXEMPTION, - bincode::serialize::(&stake::state::StakeState::Initialized( - meta, - )) - .unwrap(), - stake::program::id(), - false, - Epoch::default(), - ); - - let (stake_address, _) = find_stake_program_address(&id(), &voter_pubkey, &stake_pool_pubkey); - program_test.add_account(stake_address, stake_account); - let active_stake_lamports = TEST_STAKE_AMOUNT - MINIMUM_ACTIVE_STAKE; - // add to validator list - validator_list.validators.push(ValidatorStakeInfo { - status: StakeStatus::Active, - vote_account_address: voter_pubkey, - active_stake_lamports, - transient_stake_lamports: 0, - last_update_epoch: 0, - transient_seed_suffix_start: 0, - transient_seed_suffix_end: 0, - }); - - stake_pool.total_lamports += active_stake_lamports; - stake_pool.pool_token_supply += active_stake_lamports; - - add_reserve_stake_account( - &mut program_test, - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.withdraw_authority, - TEST_STAKE_AMOUNT, - ); - add_stake_pool_account( - &mut program_test, - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool, - ); - add_validator_list_account( - &mut program_test, - &stake_pool_accounts.validator_list.pubkey(), - &validator_list, - stake_pool_accounts.max_validators, - ); - - add_mint_account( - &mut program_test, - &stake_pool_accounts.pool_mint.pubkey(), - &stake_pool_accounts.withdraw_authority, - stake_pool.pool_token_supply, - ); - add_token_account( - &mut program_test, - &stake_pool_accounts.pool_fee_account.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &stake_pool_accounts.manager.pubkey(), - ); - - let context = program_test.start_with_context().await; - (context, stake_pool_accounts, voter_pubkey) -} - -#[tokio::test] -async fn success_update() { - let (mut context, stake_pool_accounts, voter_pubkey) = setup().await; - let pre_reserve_lamports = context - .banks_client - .get_account(stake_pool_accounts.reserve_stake.pubkey()) - .await - .unwrap() - .unwrap() - .lamports; - let (stake_address, _) = find_stake_program_address( - &id(), - &voter_pubkey, - &stake_pool_accounts.stake_pool.pubkey(), - ); - let validator_stake_lamports = context - .banks_client - .get_account(stake_address) - .await - .unwrap() - .unwrap() - .lamports; - // update should merge the destaked validator stake account into the reserve - let error = stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &[voter_pubkey], - false, - ) - .await; - assert!(error.is_none()); - let post_reserve_lamports = context - .banks_client - .get_account(stake_pool_accounts.reserve_stake.pubkey()) - .await - .unwrap() - .unwrap() - .lamports; - assert_eq!( - post_reserve_lamports, - pre_reserve_lamports + validator_stake_lamports - ); - // test no more validator stake account - assert!(context - .banks_client - .get_account(stake_address) - .await - .unwrap() - .is_none()); -} - -#[tokio::test] -async fn fail_increase() { - let (mut context, stake_pool_accounts, voter_pubkey) = setup().await; - let (stake_address, _) = find_stake_program_address( - &id(), - &voter_pubkey, - &stake_pool_accounts.stake_pool.pubkey(), - ); - let transient_stake_seed = 0; - let transient_stake_address = find_transient_stake_program_address( - &id(), - &voter_pubkey, - &stake_pool_accounts.stake_pool.pubkey(), - transient_stake_seed, - ) - .0; - let error = stake_pool_accounts - .increase_validator_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &transient_stake_address, - &stake_address, - &voter_pubkey, - MINIMUM_ACTIVE_STAKE, - transient_stake_seed, - ) - .await - .unwrap() - .unwrap(); - assert_eq!( - error, - TransactionError::InstructionError( - 0, - InstructionError::Custom(StakePoolError::WrongStakeState as u32) - ) - ); -} diff --git a/stake-pool/program/tests/helpers/mod.rs b/stake-pool/program/tests/helpers/mod.rs deleted file mode 100644 index 346483130d0..00000000000 --- a/stake-pool/program/tests/helpers/mod.rs +++ /dev/null @@ -1,1849 +0,0 @@ -#![allow(dead_code)] - -use { - borsh::BorshSerialize, - mpl_token_metadata::{pda::find_metadata_account, state::Metadata}, - solana_program::{ - borsh::{get_instance_packed_len, get_packed_len, try_from_slice_unchecked}, - hash::Hash, - program_option::COption, - program_pack::Pack, - pubkey::Pubkey, - stake, system_instruction, system_program, - }, - solana_program_test::{processor, BanksClient, ProgramTest}, - solana_sdk::{ - account::{Account, WritableAccount}, - clock::{Clock, Epoch}, - signature::{Keypair, Signer}, - transaction::Transaction, - transport::TransportError, - }, - solana_vote_program::{ - self, vote_instruction, - vote_state::{VoteInit, VoteState, VoteStateVersions}, - }, - spl_stake_pool::{ - find_deposit_authority_program_address, find_stake_program_address, - find_transient_stake_program_address, find_withdraw_authority_program_address, id, - instruction, - processor::Processor, - state::{self, FeeType, ValidatorList}, - MINIMUM_ACTIVE_STAKE, MINIMUM_RESERVE_LAMPORTS, - }, -}; - -pub const TEST_STAKE_AMOUNT: u64 = 1_500_000_000; -pub const MAX_TEST_VALIDATORS: u32 = 10_000; -pub const DEFAULT_TRANSIENT_STAKE_SEED: u64 = 42; -pub const STAKE_ACCOUNT_RENT_EXEMPTION: u64 = 2_282_880; -const ACCOUNT_RENT_EXEMPTION: u64 = 1_000_000_000; // go with something big to be safe - -pub fn program_test() -> ProgramTest { - ProgramTest::new("spl_stake_pool", id(), processor!(Processor::process)) -} - -pub fn program_test_with_metadata_program() -> ProgramTest { - let mut program_test = ProgramTest::default(); - program_test.add_program("spl_stake_pool", id(), processor!(Processor::process)); - program_test.add_program("mpl_token_metadata", mpl_token_metadata::id(), None); - program_test -} - -pub async fn get_account(banks_client: &mut BanksClient, pubkey: &Pubkey) -> Account { - banks_client - .get_account(*pubkey) - .await - .expect("account not found") - .expect("account empty") -} - -pub async fn create_mint( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - pool_mint: &Keypair, - manager: &Pubkey, -) -> Result<(), TransportError> { - let rent = banks_client.get_rent().await.unwrap(); - let mint_rent = rent.minimum_balance(spl_token::state::Mint::LEN); - - let mut transaction = Transaction::new_with_payer( - &[ - system_instruction::create_account( - &payer.pubkey(), - &pool_mint.pubkey(), - mint_rent, - spl_token::state::Mint::LEN as u64, - &spl_token::id(), - ), - spl_token::instruction::initialize_mint( - &spl_token::id(), - &pool_mint.pubkey(), - manager, - None, - 0, - ) - .unwrap(), - ], - Some(&payer.pubkey()), - ); - transaction.sign(&[payer, pool_mint], *recent_blockhash); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - banks_client - .process_transaction(transaction) - .await - .map_err(|e| e.into()) -} - -pub async fn transfer( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - recipient: &Pubkey, - amount: u64, -) { - let transaction = Transaction::new_signed_with_payer( - &[system_instruction::transfer( - &payer.pubkey(), - recipient, - amount, - )], - Some(&payer.pubkey()), - &[payer], - *recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); -} - -pub async fn transfer_spl_tokens( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - source: &Pubkey, - destination: &Pubkey, - authority: &Keypair, - amount: u64, -) { - let transaction = Transaction::new_signed_with_payer( - &[spl_token::instruction::transfer( - &spl_token::id(), - source, - destination, - &authority.pubkey(), - &[], - amount, - ) - .unwrap()], - Some(&payer.pubkey()), - &[payer, authority], - *recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); -} - -pub async fn create_token_account( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - account: &Keypair, - pool_mint: &Pubkey, - manager: &Pubkey, -) -> Result<(), TransportError> { - let rent = banks_client.get_rent().await.unwrap(); - let account_rent = rent.minimum_balance(spl_token::state::Account::LEN); - - let mut transaction = Transaction::new_with_payer( - &[ - system_instruction::create_account( - &payer.pubkey(), - &account.pubkey(), - account_rent, - spl_token::state::Account::LEN as u64, - &spl_token::id(), - ), - spl_token::instruction::initialize_account( - &spl_token::id(), - &account.pubkey(), - pool_mint, - manager, - ) - .unwrap(), - ], - Some(&payer.pubkey()), - ); - transaction.sign(&[payer, account], *recent_blockhash); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - banks_client - .process_transaction(transaction) - .await - .map_err(|e| e.into()) -} - -pub async fn close_token_account( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - account: &Pubkey, - lamports_destination: &Pubkey, - manager: &Keypair, -) -> Result<(), TransportError> { - let mut transaction = Transaction::new_with_payer( - &[spl_token::instruction::close_account( - &spl_token::id(), - account, - lamports_destination, - &manager.pubkey(), - &[], - ) - .unwrap()], - Some(&payer.pubkey()), - ); - transaction.sign(&[payer, manager], *recent_blockhash); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - banks_client - .process_transaction(transaction) - .await - .map_err(|e| e.into()) -} - -pub async fn freeze_token_account( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - account: &Pubkey, - pool_mint: &Pubkey, - manager: &Keypair, -) -> Result<(), TransportError> { - let mut transaction = Transaction::new_with_payer( - &[spl_token::instruction::freeze_account( - &spl_token::id(), - account, - pool_mint, - &manager.pubkey(), - &[], - ) - .unwrap()], - Some(&payer.pubkey()), - ); - transaction.sign(&[payer, manager], *recent_blockhash); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - banks_client - .process_transaction(transaction) - .await - .map_err(|e| e.into()) -} - -pub async fn mint_tokens( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - mint: &Pubkey, - account: &Pubkey, - mint_authority: &Keypair, - amount: u64, -) -> Result<(), TransportError> { - let transaction = Transaction::new_signed_with_payer( - &[spl_token::instruction::mint_to( - &spl_token::id(), - mint, - account, - &mint_authority.pubkey(), - &[], - amount, - ) - .unwrap()], - Some(&payer.pubkey()), - &[payer, mint_authority], - *recent_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - banks_client - .process_transaction(transaction) - .await - .map_err(|e| e.into()) -} - -pub async fn burn_tokens( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - mint: &Pubkey, - account: &Pubkey, - authority: &Keypair, - amount: u64, -) -> Result<(), TransportError> { - let transaction = Transaction::new_signed_with_payer( - &[spl_token::instruction::burn( - &spl_token::id(), - account, - mint, - &authority.pubkey(), - &[], - amount, - ) - .unwrap()], - Some(&payer.pubkey()), - &[payer, authority], - *recent_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - banks_client - .process_transaction(transaction) - .await - .map_err(|e| e.into()) -} - -pub async fn get_token_balance(banks_client: &mut BanksClient, token: &Pubkey) -> u64 { - let token_account = banks_client.get_account(*token).await.unwrap().unwrap(); - let account_info: spl_token::state::Account = - spl_token::state::Account::unpack_from_slice(token_account.data.as_slice()).unwrap(); - account_info.amount -} - -pub async fn get_metadata_account(banks_client: &mut BanksClient, token_mint: &Pubkey) -> Metadata { - let (token_metadata, _) = find_metadata_account(token_mint); - let token_metadata_account = banks_client - .get_account(token_metadata) - .await - .unwrap() - .unwrap(); - try_from_slice_unchecked(token_metadata_account.data.as_slice()).unwrap() -} - -pub async fn get_token_supply(banks_client: &mut BanksClient, mint: &Pubkey) -> u64 { - let mint_account = banks_client.get_account(*mint).await.unwrap().unwrap(); - let account_info = - spl_token::state::Mint::unpack_from_slice(mint_account.data.as_slice()).unwrap(); - account_info.supply -} - -pub async fn delegate_tokens( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - account: &Pubkey, - manager: &Keypair, - delegate: &Pubkey, - amount: u64, -) { - let transaction = Transaction::new_signed_with_payer( - &[spl_token::instruction::approve( - &spl_token::id(), - account, - delegate, - &manager.pubkey(), - &[], - amount, - ) - .unwrap()], - Some(&payer.pubkey()), - &[payer, manager], - *recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); -} - -#[allow(clippy::too_many_arguments)] -pub async fn create_stake_pool( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - stake_pool: &Keypair, - validator_list: &Keypair, - reserve_stake: &Pubkey, - pool_mint: &Pubkey, - pool_token_account: &Pubkey, - manager: &Keypair, - staker: &Pubkey, - withdraw_authority: &Pubkey, - stake_deposit_authority: &Option, - epoch_fee: &state::Fee, - withdrawal_fee: &state::Fee, - deposit_fee: &state::Fee, - referral_fee: u8, - sol_deposit_fee: &state::Fee, - sol_referral_fee: u8, - max_validators: u32, -) -> Result<(), TransportError> { - let rent = banks_client.get_rent().await.unwrap(); - let rent_stake_pool = rent.minimum_balance(get_packed_len::()); - let validator_list_size = - get_instance_packed_len(&state::ValidatorList::new(max_validators)).unwrap(); - let rent_validator_list = rent.minimum_balance(validator_list_size); - - let mut transaction = Transaction::new_with_payer( - &[ - system_instruction::create_account( - &payer.pubkey(), - &stake_pool.pubkey(), - rent_stake_pool, - get_packed_len::() as u64, - &id(), - ), - system_instruction::create_account( - &payer.pubkey(), - &validator_list.pubkey(), - rent_validator_list, - validator_list_size as u64, - &id(), - ), - instruction::initialize( - &id(), - &stake_pool.pubkey(), - &manager.pubkey(), - staker, - withdraw_authority, - &validator_list.pubkey(), - reserve_stake, - pool_mint, - pool_token_account, - &spl_token::id(), - stake_deposit_authority.as_ref().map(|k| k.pubkey()), - *epoch_fee, - *withdrawal_fee, - *deposit_fee, - referral_fee, - max_validators, - ), - instruction::set_fee( - &id(), - &stake_pool.pubkey(), - &manager.pubkey(), - FeeType::SolDeposit(*sol_deposit_fee), - ), - instruction::set_fee( - &id(), - &stake_pool.pubkey(), - &manager.pubkey(), - FeeType::SolReferral(sol_referral_fee), - ), - ], - Some(&payer.pubkey()), - ); - let mut signers = vec![payer, stake_pool, validator_list, manager]; - if let Some(stake_deposit_authority) = stake_deposit_authority.as_ref() { - signers.push(stake_deposit_authority); - } - transaction.sign(&signers, *recent_blockhash); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - banks_client - .process_transaction(transaction) - .await - .map_err(|e| e.into()) -} - -pub async fn create_vote( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - validator: &Keypair, - vote: &Keypair, -) { - let rent = banks_client.get_rent().await.unwrap(); - let rent_voter = rent.minimum_balance(VoteState::size_of()); - - let mut instructions = vec![system_instruction::create_account( - &payer.pubkey(), - &validator.pubkey(), - rent.minimum_balance(0), - 0, - &system_program::id(), - )]; - instructions.append(&mut vote_instruction::create_account( - &payer.pubkey(), - &vote.pubkey(), - &VoteInit { - node_pubkey: validator.pubkey(), - authorized_voter: validator.pubkey(), - ..VoteInit::default() - }, - rent_voter, - )); - - let transaction = Transaction::new_signed_with_payer( - &instructions, - Some(&payer.pubkey()), - &[validator, vote, payer], - *recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); -} - -pub async fn create_independent_stake_account( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - stake: &Keypair, - authorized: &stake::state::Authorized, - lockup: &stake::state::Lockup, - stake_amount: u64, -) -> u64 { - let rent = banks_client.get_rent().await.unwrap(); - let lamports = - rent.minimum_balance(std::mem::size_of::()) + stake_amount; - - let transaction = Transaction::new_signed_with_payer( - &stake::instruction::create_account( - &payer.pubkey(), - &stake.pubkey(), - authorized, - lockup, - lamports, - ), - Some(&payer.pubkey()), - &[payer, stake], - *recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); - - lamports -} - -pub async fn create_blank_stake_account( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - stake: &Keypair, -) -> u64 { - let rent = banks_client.get_rent().await.unwrap(); - let lamports = rent.minimum_balance(std::mem::size_of::()) + 1; - - let transaction = Transaction::new_signed_with_payer( - &[system_instruction::create_account( - &payer.pubkey(), - &stake.pubkey(), - lamports, - std::mem::size_of::() as u64, - &stake::program::id(), - )], - Some(&payer.pubkey()), - &[payer, stake], - *recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); - - lamports -} - -pub async fn delegate_stake_account( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - stake: &Pubkey, - authorized: &Keypair, - vote: &Pubkey, -) { - let mut transaction = Transaction::new_with_payer( - &[stake::instruction::delegate_stake( - stake, - &authorized.pubkey(), - vote, - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[payer, authorized], *recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); -} - -pub async fn authorize_stake_account( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - stake: &Pubkey, - authorized: &Keypair, - new_authorized: &Pubkey, - stake_authorize: stake::state::StakeAuthorize, -) { - let mut transaction = Transaction::new_with_payer( - &[stake::instruction::authorize( - stake, - &authorized.pubkey(), - new_authorized, - stake_authorize, - None, - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[payer, authorized], *recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); -} - -pub async fn create_unknown_validator_stake( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - stake_pool: &Pubkey, -) -> ValidatorStakeAccount { - let mut unknown_stake = ValidatorStakeAccount::new(stake_pool, 222); - create_vote( - banks_client, - payer, - recent_blockhash, - &unknown_stake.validator, - &unknown_stake.vote, - ) - .await; - let user = Keypair::new(); - let fake_validator_stake = Keypair::new(); - create_independent_stake_account( - banks_client, - payer, - recent_blockhash, - &fake_validator_stake, - &stake::state::Authorized { - staker: user.pubkey(), - withdrawer: user.pubkey(), - }, - &stake::state::Lockup::default(), - MINIMUM_ACTIVE_STAKE, - ) - .await; - delegate_stake_account( - banks_client, - payer, - recent_blockhash, - &fake_validator_stake.pubkey(), - &user, - &unknown_stake.vote.pubkey(), - ) - .await; - unknown_stake.stake_account = fake_validator_stake.pubkey(); - unknown_stake -} - -pub struct ValidatorStakeAccount { - pub stake_account: Pubkey, - pub transient_stake_account: Pubkey, - pub transient_stake_seed: u64, - pub vote: Keypair, - pub validator: Keypair, - pub stake_pool: Pubkey, -} - -impl ValidatorStakeAccount { - pub fn new(stake_pool: &Pubkey, transient_stake_seed: u64) -> Self { - let validator = Keypair::new(); - let vote = Keypair::new(); - let (stake_account, _) = find_stake_program_address(&id(), &vote.pubkey(), stake_pool); - let (transient_stake_account, _) = find_transient_stake_program_address( - &id(), - &vote.pubkey(), - stake_pool, - transient_stake_seed, - ); - ValidatorStakeAccount { - stake_account, - transient_stake_account, - transient_stake_seed, - vote, - validator, - stake_pool: *stake_pool, - } - } -} - -pub struct StakePoolAccounts { - pub stake_pool: Keypair, - pub validator_list: Keypair, - pub reserve_stake: Keypair, - pub pool_mint: Keypair, - pub pool_fee_account: Keypair, - pub manager: Keypair, - pub staker: Keypair, - pub withdraw_authority: Pubkey, - pub stake_deposit_authority: Pubkey, - pub stake_deposit_authority_keypair: Option, - pub epoch_fee: state::Fee, - pub withdrawal_fee: state::Fee, - pub deposit_fee: state::Fee, - pub referral_fee: u8, - pub sol_deposit_fee: state::Fee, - pub sol_referral_fee: u8, - pub max_validators: u32, -} - -impl StakePoolAccounts { - pub fn new() -> Self { - let stake_pool = Keypair::new(); - let validator_list = Keypair::new(); - let stake_pool_address = &stake_pool.pubkey(); - let (stake_deposit_authority, _) = - find_deposit_authority_program_address(&id(), stake_pool_address); - let (withdraw_authority, _) = - find_withdraw_authority_program_address(&id(), stake_pool_address); - let reserve_stake = Keypair::new(); - let pool_mint = Keypair::new(); - let pool_fee_account = Keypair::new(); - let manager = Keypair::new(); - let staker = Keypair::new(); - - Self { - stake_pool, - validator_list, - reserve_stake, - pool_mint, - pool_fee_account, - manager, - staker, - withdraw_authority, - stake_deposit_authority, - stake_deposit_authority_keypair: None, - epoch_fee: state::Fee { - numerator: 1, - denominator: 100, - }, - withdrawal_fee: state::Fee { - numerator: 3, - denominator: 1000, - }, - deposit_fee: state::Fee { - numerator: 1, - denominator: 1000, - }, - referral_fee: 25, - sol_deposit_fee: state::Fee { - numerator: 3, - denominator: 100, - }, - sol_referral_fee: 50, - max_validators: MAX_TEST_VALIDATORS, - } - } - - pub fn new_with_deposit_authority(stake_deposit_authority: Keypair) -> Self { - let mut stake_pool_accounts = Self::new(); - stake_pool_accounts.stake_deposit_authority = stake_deposit_authority.pubkey(); - stake_pool_accounts.stake_deposit_authority_keypair = Some(stake_deposit_authority); - stake_pool_accounts - } - - pub fn calculate_fee(&self, amount: u64) -> u64 { - amount * self.epoch_fee.numerator / self.epoch_fee.denominator - } - - pub fn calculate_withdrawal_fee(&self, pool_tokens: u64) -> u64 { - pool_tokens * self.withdrawal_fee.numerator / self.withdrawal_fee.denominator - } - - pub fn calculate_referral_fee(&self, deposit_fee_collected: u64) -> u64 { - deposit_fee_collected * self.referral_fee as u64 / 100 - } - - pub fn calculate_sol_deposit_fee(&self, pool_tokens: u64) -> u64 { - pool_tokens * self.sol_deposit_fee.numerator / self.sol_deposit_fee.denominator - } - - pub fn calculate_sol_referral_fee(&self, deposit_fee_collected: u64) -> u64 { - deposit_fee_collected * self.sol_referral_fee as u64 / 100 - } - - pub async fn initialize_stake_pool( - &self, - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - reserve_lamports: u64, - ) -> Result<(), TransportError> { - create_mint( - banks_client, - payer, - recent_blockhash, - &self.pool_mint, - &self.withdraw_authority, - ) - .await?; - create_token_account( - banks_client, - payer, - recent_blockhash, - &self.pool_fee_account, - &self.pool_mint.pubkey(), - &self.manager.pubkey(), - ) - .await?; - create_independent_stake_account( - banks_client, - payer, - recent_blockhash, - &self.reserve_stake, - &stake::state::Authorized { - staker: self.withdraw_authority, - withdrawer: self.withdraw_authority, - }, - &stake::state::Lockup::default(), - reserve_lamports, - ) - .await; - create_stake_pool( - banks_client, - payer, - recent_blockhash, - &self.stake_pool, - &self.validator_list, - &self.reserve_stake.pubkey(), - &self.pool_mint.pubkey(), - &self.pool_fee_account.pubkey(), - &self.manager, - &self.staker.pubkey(), - &self.withdraw_authority, - &self.stake_deposit_authority_keypair, - &self.epoch_fee, - &self.withdrawal_fee, - &self.deposit_fee, - self.referral_fee, - &self.sol_deposit_fee, - self.sol_referral_fee, - self.max_validators, - ) - .await?; - - Ok(()) - } - - #[allow(clippy::too_many_arguments)] - pub async fn deposit_stake( - &self, - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - stake: &Pubkey, - pool_account: &Pubkey, - validator_stake_account: &Pubkey, - current_staker: &Keypair, - ) -> Option { - self.deposit_stake_with_referral( - banks_client, - payer, - recent_blockhash, - stake, - pool_account, - validator_stake_account, - current_staker, - &self.pool_fee_account.pubkey(), - ) - .await - } - - #[allow(clippy::too_many_arguments)] - pub async fn deposit_stake_with_referral( - &self, - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - stake: &Pubkey, - pool_account: &Pubkey, - validator_stake_account: &Pubkey, - current_staker: &Keypair, - referrer: &Pubkey, - ) -> Option { - let mut signers = vec![payer, current_staker]; - let instructions = - if let Some(stake_deposit_authority) = self.stake_deposit_authority_keypair.as_ref() { - signers.push(stake_deposit_authority); - instruction::deposit_stake_with_authority( - &id(), - &self.stake_pool.pubkey(), - &self.validator_list.pubkey(), - &self.stake_deposit_authority, - &self.withdraw_authority, - stake, - ¤t_staker.pubkey(), - validator_stake_account, - &self.reserve_stake.pubkey(), - pool_account, - &self.pool_fee_account.pubkey(), - referrer, - &self.pool_mint.pubkey(), - &spl_token::id(), - ) - } else { - instruction::deposit_stake( - &id(), - &self.stake_pool.pubkey(), - &self.validator_list.pubkey(), - &self.withdraw_authority, - stake, - ¤t_staker.pubkey(), - validator_stake_account, - &self.reserve_stake.pubkey(), - pool_account, - &self.pool_fee_account.pubkey(), - referrer, - &self.pool_mint.pubkey(), - &spl_token::id(), - ) - }; - let transaction = Transaction::new_signed_with_payer( - &instructions, - Some(&payer.pubkey()), - &signers, - *recent_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - banks_client - .process_transaction(transaction) - .await - .map_err(|e| e.into()) - .err() - } - - #[allow(clippy::too_many_arguments)] - pub async fn deposit_sol( - &self, - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - pool_account: &Pubkey, - amount: u64, - sol_deposit_authority: Option<&Keypair>, - ) -> Option { - let mut signers = vec![payer]; - let instruction = if let Some(sol_deposit_authority) = sol_deposit_authority { - signers.push(sol_deposit_authority); - instruction::deposit_sol_with_authority( - &id(), - &self.stake_pool.pubkey(), - &sol_deposit_authority.pubkey(), - &self.withdraw_authority, - &self.reserve_stake.pubkey(), - &payer.pubkey(), - pool_account, - &self.pool_fee_account.pubkey(), - &self.pool_fee_account.pubkey(), - &self.pool_mint.pubkey(), - &spl_token::id(), - amount, - ) - } else { - instruction::deposit_sol( - &id(), - &self.stake_pool.pubkey(), - &self.withdraw_authority, - &self.reserve_stake.pubkey(), - &payer.pubkey(), - pool_account, - &self.pool_fee_account.pubkey(), - &self.pool_fee_account.pubkey(), - &self.pool_mint.pubkey(), - &spl_token::id(), - amount, - ) - }; - let transaction = Transaction::new_signed_with_payer( - &[instruction], - Some(&payer.pubkey()), - &signers, - *recent_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - banks_client - .process_transaction(transaction) - .await - .map_err(|e| e.into()) - .err() - } - - #[allow(clippy::too_many_arguments)] - pub async fn withdraw_stake( - &self, - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - stake_recipient: &Pubkey, - user_transfer_authority: &Keypair, - pool_account: &Pubkey, - validator_stake_account: &Pubkey, - recipient_new_authority: &Pubkey, - amount: u64, - ) -> Option { - let transaction = Transaction::new_signed_with_payer( - &[instruction::withdraw_stake( - &id(), - &self.stake_pool.pubkey(), - &self.validator_list.pubkey(), - &self.withdraw_authority, - validator_stake_account, - stake_recipient, - recipient_new_authority, - &user_transfer_authority.pubkey(), - pool_account, - &self.pool_fee_account.pubkey(), - &self.pool_mint.pubkey(), - &spl_token::id(), - amount, - )], - Some(&payer.pubkey()), - &[payer, user_transfer_authority], - *recent_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - banks_client - .process_transaction(transaction) - .await - .map_err(|e| e.into()) - .err() - } - - #[allow(clippy::too_many_arguments)] - pub async fn withdraw_sol( - &self, - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - user: &Keypair, - pool_account: &Pubkey, - amount: u64, - sol_withdraw_authority: Option<&Keypair>, - ) -> Option { - let mut signers = vec![payer, user]; - let instruction = if let Some(sol_withdraw_authority) = sol_withdraw_authority { - signers.push(sol_withdraw_authority); - instruction::withdraw_sol_with_authority( - &id(), - &self.stake_pool.pubkey(), - &sol_withdraw_authority.pubkey(), - &self.withdraw_authority, - &user.pubkey(), - pool_account, - &self.reserve_stake.pubkey(), - &user.pubkey(), - &self.pool_fee_account.pubkey(), - &self.pool_mint.pubkey(), - &spl_token::id(), - amount, - ) - } else { - instruction::withdraw_sol( - &id(), - &self.stake_pool.pubkey(), - &self.withdraw_authority, - &user.pubkey(), - pool_account, - &self.reserve_stake.pubkey(), - &user.pubkey(), - &self.pool_fee_account.pubkey(), - &self.pool_mint.pubkey(), - &spl_token::id(), - amount, - ) - }; - let transaction = Transaction::new_signed_with_payer( - &[instruction], - Some(&payer.pubkey()), - &signers, - *recent_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - banks_client - .process_transaction(transaction) - .await - .map_err(|e| e.into()) - .err() - } - - pub async fn get_validator_list(&self, banks_client: &mut BanksClient) -> ValidatorList { - let validator_list_account = get_account(banks_client, &self.validator_list.pubkey()).await; - try_from_slice_unchecked::(validator_list_account.data.as_slice()).unwrap() - } - - pub async fn update_validator_list_balance( - &self, - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - validator_vote_accounts: &[Pubkey], - no_merge: bool, - ) -> Option { - let validator_list = self.get_validator_list(banks_client).await; - let transaction = Transaction::new_signed_with_payer( - &[instruction::update_validator_list_balance( - &id(), - &self.stake_pool.pubkey(), - &self.withdraw_authority, - &self.validator_list.pubkey(), - &self.reserve_stake.pubkey(), - &validator_list, - validator_vote_accounts, - 0, - no_merge, - )], - Some(&payer.pubkey()), - &[payer], - *recent_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - banks_client - .process_transaction(transaction) - .await - .map_err(|e| e.into()) - .err() - } - - pub async fn update_stake_pool_balance( - &self, - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - ) -> Option { - let transaction = Transaction::new_signed_with_payer( - &[instruction::update_stake_pool_balance( - &id(), - &self.stake_pool.pubkey(), - &self.withdraw_authority, - &self.validator_list.pubkey(), - &self.reserve_stake.pubkey(), - &self.pool_fee_account.pubkey(), - &self.pool_mint.pubkey(), - &spl_token::id(), - )], - Some(&payer.pubkey()), - &[payer], - *recent_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - banks_client - .process_transaction(transaction) - .await - .map_err(|e| e.into()) - .err() - } - - pub async fn cleanup_removed_validator_entries( - &self, - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - ) -> Option { - let transaction = Transaction::new_signed_with_payer( - &[instruction::cleanup_removed_validator_entries( - &id(), - &self.stake_pool.pubkey(), - &self.validator_list.pubkey(), - )], - Some(&payer.pubkey()), - &[payer], - *recent_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - banks_client - .process_transaction(transaction) - .await - .map_err(|e| e.into()) - .err() - } - - pub async fn update_all( - &self, - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - validator_vote_accounts: &[Pubkey], - no_merge: bool, - ) -> Option { - let validator_list = self.get_validator_list(banks_client).await; - let transaction = Transaction::new_signed_with_payer( - &[ - instruction::update_validator_list_balance( - &id(), - &self.stake_pool.pubkey(), - &self.withdraw_authority, - &self.validator_list.pubkey(), - &self.reserve_stake.pubkey(), - &validator_list, - validator_vote_accounts, - 0, - no_merge, - ), - instruction::update_stake_pool_balance( - &id(), - &self.stake_pool.pubkey(), - &self.withdraw_authority, - &self.validator_list.pubkey(), - &self.reserve_stake.pubkey(), - &self.pool_fee_account.pubkey(), - &self.pool_mint.pubkey(), - &spl_token::id(), - ), - instruction::cleanup_removed_validator_entries( - &id(), - &self.stake_pool.pubkey(), - &self.validator_list.pubkey(), - ), - ], - Some(&payer.pubkey()), - &[payer], - *recent_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - banks_client - .process_transaction(transaction) - .await - .map_err(|e| e.into()) - .err() - } - - pub async fn add_validator_to_pool( - &self, - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - stake: &Pubkey, - validator: &Pubkey, - ) -> Option { - let transaction = Transaction::new_signed_with_payer( - &[instruction::add_validator_to_pool( - &id(), - &self.stake_pool.pubkey(), - &self.staker.pubkey(), - &payer.pubkey(), - &self.withdraw_authority, - &self.validator_list.pubkey(), - stake, - validator, - )], - Some(&payer.pubkey()), - &[payer, &self.staker], - *recent_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - banks_client - .process_transaction(transaction) - .await - .map_err(|e| e.into()) - .err() - } - - #[allow(clippy::too_many_arguments)] - pub async fn remove_validator_from_pool( - &self, - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - new_authority: &Pubkey, - validator_stake: &Pubkey, - transient_stake: &Pubkey, - destination_stake: &Keypair, - ) -> Option { - let transaction = Transaction::new_signed_with_payer( - &[ - system_instruction::create_account( - &payer.pubkey(), - &destination_stake.pubkey(), - 0, - std::mem::size_of::() as u64, - &stake::program::id(), - ), - instruction::remove_validator_from_pool( - &id(), - &self.stake_pool.pubkey(), - &self.staker.pubkey(), - &self.withdraw_authority, - new_authority, - &self.validator_list.pubkey(), - validator_stake, - transient_stake, - &destination_stake.pubkey(), - ), - ], - Some(&payer.pubkey()), - &[payer, &self.staker, destination_stake], - *recent_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - banks_client - .process_transaction(transaction) - .await - .map_err(|e| e.into()) - .err() - } - - #[allow(clippy::too_many_arguments)] - pub async fn decrease_validator_stake( - &self, - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - validator_stake: &Pubkey, - transient_stake: &Pubkey, - lamports: u64, - transient_stake_seed: u64, - ) -> Option { - let transaction = Transaction::new_signed_with_payer( - &[instruction::decrease_validator_stake( - &id(), - &self.stake_pool.pubkey(), - &self.staker.pubkey(), - &self.withdraw_authority, - &self.validator_list.pubkey(), - validator_stake, - transient_stake, - lamports, - transient_stake_seed, - )], - Some(&payer.pubkey()), - &[payer, &self.staker], - *recent_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - banks_client - .process_transaction(transaction) - .await - .map_err(|e| e.into()) - .err() - } - - #[allow(clippy::too_many_arguments)] - pub async fn increase_validator_stake( - &self, - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - transient_stake: &Pubkey, - validator_stake: &Pubkey, - validator: &Pubkey, - lamports: u64, - transient_stake_seed: u64, - ) -> Option { - let transaction = Transaction::new_signed_with_payer( - &[instruction::increase_validator_stake( - &id(), - &self.stake_pool.pubkey(), - &self.staker.pubkey(), - &self.withdraw_authority, - &self.validator_list.pubkey(), - &self.reserve_stake.pubkey(), - transient_stake, - validator_stake, - validator, - lamports, - transient_stake_seed, - )], - Some(&payer.pubkey()), - &[payer, &self.staker], - *recent_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - banks_client - .process_transaction(transaction) - .await - .map_err(|e| e.into()) - .err() - } - - pub async fn set_preferred_validator( - &self, - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - validator_type: instruction::PreferredValidatorType, - validator: Option, - ) -> Option { - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_preferred_validator( - &id(), - &self.stake_pool.pubkey(), - &self.staker.pubkey(), - &self.validator_list.pubkey(), - validator_type, - validator, - )], - Some(&payer.pubkey()), - &[payer, &self.staker], - *recent_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - banks_client - .process_transaction(transaction) - .await - .map_err(|e| e.into()) - .err() - } - - pub fn state(&self) -> (state::StakePool, state::ValidatorList) { - let (_, stake_withdraw_bump_seed) = - find_withdraw_authority_program_address(&id(), &self.stake_pool.pubkey()); - let stake_pool = state::StakePool { - account_type: state::AccountType::StakePool, - manager: self.manager.pubkey(), - staker: self.staker.pubkey(), - stake_deposit_authority: self.stake_deposit_authority, - stake_withdraw_bump_seed, - validator_list: self.validator_list.pubkey(), - reserve_stake: self.reserve_stake.pubkey(), - pool_mint: self.pool_mint.pubkey(), - manager_fee_account: self.pool_fee_account.pubkey(), - token_program_id: spl_token::id(), - total_lamports: 0, - pool_token_supply: 0, - last_update_epoch: 0, - lockup: stake::state::Lockup::default(), - epoch_fee: self.epoch_fee, - next_epoch_fee: None, - preferred_deposit_validator_vote_address: None, - preferred_withdraw_validator_vote_address: None, - stake_deposit_fee: state::Fee::default(), - sol_deposit_fee: state::Fee::default(), - stake_withdrawal_fee: state::Fee::default(), - next_stake_withdrawal_fee: None, - stake_referral_fee: 0, - sol_referral_fee: 0, - sol_deposit_authority: None, - sol_withdraw_authority: None, - sol_withdrawal_fee: state::Fee::default(), - next_sol_withdrawal_fee: None, - last_epoch_pool_token_supply: 0, - last_epoch_total_lamports: 0, - }; - let mut validator_list = ValidatorList::new(self.max_validators); - validator_list.validators = vec![]; - (stake_pool, validator_list) - } -} - -pub async fn simple_add_validator_to_pool( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - stake_pool_accounts: &StakePoolAccounts, -) -> ValidatorStakeAccount { - let validator_stake = ValidatorStakeAccount::new( - &stake_pool_accounts.stake_pool.pubkey(), - DEFAULT_TRANSIENT_STAKE_SEED, - ); - - create_vote( - banks_client, - payer, - recent_blockhash, - &validator_stake.validator, - &validator_stake.vote, - ) - .await; - - let error = stake_pool_accounts - .add_validator_to_pool( - banks_client, - payer, - recent_blockhash, - &validator_stake.stake_account, - &validator_stake.vote.pubkey(), - ) - .await; - assert!(error.is_none()); - - validator_stake -} - -#[derive(Debug)] -pub struct DepositStakeAccount { - pub authority: Keypair, - pub stake: Keypair, - pub pool_account: Keypair, - pub stake_lamports: u64, - pub pool_tokens: u64, - pub vote_account: Pubkey, - pub validator_stake_account: Pubkey, -} - -impl DepositStakeAccount { - pub fn new_with_vote( - vote_account: Pubkey, - validator_stake_account: Pubkey, - stake_lamports: u64, - ) -> Self { - let authority = Keypair::new(); - let stake = Keypair::new(); - let pool_account = Keypair::new(); - Self { - authority, - stake, - pool_account, - vote_account, - validator_stake_account, - stake_lamports, - pool_tokens: 0, - } - } - - pub async fn create_and_delegate( - &self, - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - ) { - let lockup = stake::state::Lockup::default(); - let authorized = stake::state::Authorized { - staker: self.authority.pubkey(), - withdrawer: self.authority.pubkey(), - }; - create_independent_stake_account( - banks_client, - payer, - recent_blockhash, - &self.stake, - &authorized, - &lockup, - self.stake_lamports, - ) - .await; - delegate_stake_account( - banks_client, - payer, - recent_blockhash, - &self.stake.pubkey(), - &self.authority, - &self.vote_account, - ) - .await; - } - - pub async fn deposit_stake( - &mut self, - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - stake_pool_accounts: &StakePoolAccounts, - ) { - // make pool token account - create_token_account( - banks_client, - payer, - recent_blockhash, - &self.pool_account, - &stake_pool_accounts.pool_mint.pubkey(), - &self.authority.pubkey(), - ) - .await - .unwrap(); - - let error = stake_pool_accounts - .deposit_stake( - banks_client, - payer, - recent_blockhash, - &self.stake.pubkey(), - &self.pool_account.pubkey(), - &self.validator_stake_account, - &self.authority, - ) - .await; - self.pool_tokens = get_token_balance(banks_client, &self.pool_account.pubkey()).await; - assert!(error.is_none()); - } -} - -pub async fn simple_deposit_stake( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - stake_pool_accounts: &StakePoolAccounts, - validator_stake_account: &ValidatorStakeAccount, - stake_lamports: u64, -) -> Option { - let authority = Keypair::new(); - // make stake account - let stake = Keypair::new(); - let lockup = stake::state::Lockup::default(); - let authorized = stake::state::Authorized { - staker: authority.pubkey(), - withdrawer: authority.pubkey(), - }; - create_independent_stake_account( - banks_client, - payer, - recent_blockhash, - &stake, - &authorized, - &lockup, - stake_lamports, - ) - .await; - let vote_account = validator_stake_account.vote.pubkey(); - delegate_stake_account( - banks_client, - payer, - recent_blockhash, - &stake.pubkey(), - &authority, - &vote_account, - ) - .await; - // make pool token account - let pool_account = Keypair::new(); - create_token_account( - banks_client, - payer, - recent_blockhash, - &pool_account, - &stake_pool_accounts.pool_mint.pubkey(), - &authority.pubkey(), - ) - .await - .unwrap(); - - let validator_stake_account = validator_stake_account.stake_account; - let error = stake_pool_accounts - .deposit_stake( - banks_client, - payer, - recent_blockhash, - &stake.pubkey(), - &pool_account.pubkey(), - &validator_stake_account, - &authority, - ) - .await; - // backwards, but oh well! - if error.is_some() { - return None; - } - - let pool_tokens = get_token_balance(banks_client, &pool_account.pubkey()).await; - - Some(DepositStakeAccount { - authority, - stake, - pool_account, - stake_lamports, - pool_tokens, - vote_account, - validator_stake_account, - }) -} - -pub async fn get_validator_list_sum( - banks_client: &mut BanksClient, - reserve_stake: &Pubkey, - validator_list: &Pubkey, -) -> u64 { - let validator_list = banks_client - .get_account(*validator_list) - .await - .unwrap() - .unwrap(); - let validator_list = - try_from_slice_unchecked::(validator_list.data.as_slice()).unwrap(); - let reserve_stake = banks_client - .get_account(*reserve_stake) - .await - .unwrap() - .unwrap(); - - let validator_sum: u64 = validator_list - .validators - .iter() - .map(|info| info.stake_lamports()) - .sum(); - let rent = banks_client.get_rent().await.unwrap(); - let rent = rent.minimum_balance(std::mem::size_of::()); - validator_sum + reserve_stake.lamports - rent - MINIMUM_RESERVE_LAMPORTS -} - -pub fn add_vote_account(program_test: &mut ProgramTest) -> Pubkey { - let authorized_voter = Pubkey::new_unique(); - let authorized_withdrawer = Pubkey::new_unique(); - let commission = 1; - - // create vote account - let vote_pubkey = Pubkey::new_unique(); - let node_pubkey = Pubkey::new_unique(); - let vote_state = VoteStateVersions::new_current(VoteState::new( - &VoteInit { - node_pubkey, - authorized_voter, - authorized_withdrawer, - commission, - }, - &Clock::default(), - )); - let vote_account = Account::create( - ACCOUNT_RENT_EXEMPTION, - bincode::serialize::(&vote_state).unwrap(), - solana_vote_program::id(), - false, - Epoch::default(), - ); - program_test.add_account(vote_pubkey, vote_account); - vote_pubkey -} - -pub fn add_validator_stake_account( - program_test: &mut ProgramTest, - stake_pool: &mut state::StakePool, - validator_list: &mut state::ValidatorList, - stake_pool_pubkey: &Pubkey, - withdraw_authority: &Pubkey, - voter_pubkey: &Pubkey, - stake_amount: u64, -) { - let meta = stake::state::Meta { - rent_exempt_reserve: STAKE_ACCOUNT_RENT_EXEMPTION, - authorized: stake::state::Authorized { - staker: *withdraw_authority, - withdrawer: *withdraw_authority, - }, - lockup: stake_pool.lockup, - }; - - // create validator stake account - let stake = stake::state::Stake { - delegation: stake::state::Delegation { - voter_pubkey: *voter_pubkey, - stake: stake_amount, - activation_epoch: 0, - deactivation_epoch: u64::MAX, - warmup_cooldown_rate: 0.25, // default - }, - credits_observed: 0, - }; - - let stake_account = Account::create( - stake_amount + STAKE_ACCOUNT_RENT_EXEMPTION, - bincode::serialize::(&stake::state::StakeState::Stake( - meta, stake, - )) - .unwrap(), - stake::program::id(), - false, - Epoch::default(), - ); - - let (stake_address, _) = find_stake_program_address(&id(), voter_pubkey, stake_pool_pubkey); - program_test.add_account(stake_address, stake_account); - let active_stake_lamports = stake_amount - MINIMUM_ACTIVE_STAKE; - // add to validator list - validator_list.validators.push(state::ValidatorStakeInfo { - status: state::StakeStatus::Active, - vote_account_address: *voter_pubkey, - active_stake_lamports, - transient_stake_lamports: 0, - last_update_epoch: 0, - transient_seed_suffix_start: 0, - transient_seed_suffix_end: 0, - }); - - stake_pool.total_lamports += active_stake_lamports; - stake_pool.pool_token_supply += active_stake_lamports; -} - -pub fn add_reserve_stake_account( - program_test: &mut ProgramTest, - reserve_stake: &Pubkey, - withdraw_authority: &Pubkey, - stake_amount: u64, -) { - let meta = stake::state::Meta { - rent_exempt_reserve: STAKE_ACCOUNT_RENT_EXEMPTION, - authorized: stake::state::Authorized { - staker: *withdraw_authority, - withdrawer: *withdraw_authority, - }, - lockup: stake::state::Lockup::default(), - }; - let reserve_stake_account = Account::create( - stake_amount + STAKE_ACCOUNT_RENT_EXEMPTION, - bincode::serialize::(&stake::state::StakeState::Initialized( - meta, - )) - .unwrap(), - stake::program::id(), - false, - Epoch::default(), - ); - program_test.add_account(*reserve_stake, reserve_stake_account); -} - -pub fn add_stake_pool_account( - program_test: &mut ProgramTest, - stake_pool_pubkey: &Pubkey, - stake_pool: &state::StakePool, -) { - let mut stake_pool_bytes = stake_pool.try_to_vec().unwrap(); - // more room for optionals - stake_pool_bytes.extend_from_slice(&Pubkey::default().to_bytes()); - stake_pool_bytes.extend_from_slice(&Pubkey::default().to_bytes()); - let stake_pool_account = Account::create( - ACCOUNT_RENT_EXEMPTION, - stake_pool_bytes, - id(), - false, - Epoch::default(), - ); - program_test.add_account(*stake_pool_pubkey, stake_pool_account); -} - -pub fn add_validator_list_account( - program_test: &mut ProgramTest, - validator_list_pubkey: &Pubkey, - validator_list: &state::ValidatorList, - max_validators: u32, -) { - let mut validator_list_bytes = validator_list.try_to_vec().unwrap(); - // add extra room if needed - for _ in validator_list.validators.len()..max_validators as usize { - validator_list_bytes - .append(&mut state::ValidatorStakeInfo::default().try_to_vec().unwrap()); - } - let validator_list_account = Account::create( - ACCOUNT_RENT_EXEMPTION, - validator_list_bytes, - id(), - false, - Epoch::default(), - ); - program_test.add_account(*validator_list_pubkey, validator_list_account); -} - -pub fn add_mint_account( - program_test: &mut ProgramTest, - mint_key: &Pubkey, - mint_authority: &Pubkey, - supply: u64, -) { - let mut mint_vec = vec![0u8; spl_token::state::Mint::LEN]; - let mint = spl_token::state::Mint { - mint_authority: COption::Some(*mint_authority), - supply, - decimals: 9, - is_initialized: true, - freeze_authority: COption::None, - }; - Pack::pack(mint, &mut mint_vec).unwrap(); - let stake_pool_mint = Account::create( - ACCOUNT_RENT_EXEMPTION, - mint_vec, - spl_token::id(), - false, - Epoch::default(), - ); - program_test.add_account(*mint_key, stake_pool_mint); -} - -pub fn add_token_account( - program_test: &mut ProgramTest, - account_key: &Pubkey, - mint_key: &Pubkey, - owner: &Pubkey, -) { - let mut fee_account_vec = vec![0u8; spl_token::state::Account::LEN]; - let fee_account_data = spl_token::state::Account { - mint: *mint_key, - owner: *owner, - amount: 0, - delegate: COption::None, - state: spl_token::state::AccountState::Initialized, - is_native: COption::None, - delegated_amount: 0, - close_authority: COption::None, - }; - Pack::pack(fee_account_data, &mut fee_account_vec).unwrap(); - let fee_account = Account::create( - ACCOUNT_RENT_EXEMPTION, - fee_account_vec, - spl_token::id(), - false, - Epoch::default(), - ); - program_test.add_account(*account_key, fee_account); -} diff --git a/stake-pool/program/tests/huge_pool.rs b/stake-pool/program/tests/huge_pool.rs deleted file mode 100644 index d5d7a20d046..00000000000 --- a/stake-pool/program/tests/huge_pool.rs +++ /dev/null @@ -1,578 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod helpers; - -use { - helpers::*, - solana_program::{borsh::try_from_slice_unchecked, pubkey::Pubkey, stake}, - solana_program_test::*, - solana_sdk::{ - signature::{Keypair, Signer}, - transaction::Transaction, - }, - spl_stake_pool::{ - find_stake_program_address, find_transient_stake_program_address, id, - instruction::{self, PreferredValidatorType}, - state::{StakePool, StakeStatus, ValidatorList}, - MAX_VALIDATORS_TO_UPDATE, MINIMUM_ACTIVE_STAKE, - }, -}; - -const HUGE_POOL_SIZE: u32 = 2_950; -const STAKE_AMOUNT: u64 = 200_000_000_000; - -async fn setup( - max_validators: u32, - num_validators: u32, - stake_amount: u64, -) -> ( - ProgramTestContext, - StakePoolAccounts, - Vec, - Pubkey, - Keypair, - Pubkey, - Pubkey, -) { - let mut program_test = program_test(); - let mut vote_account_pubkeys = vec![]; - let mut stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts.max_validators = max_validators; - - let stake_pool_pubkey = stake_pool_accounts.stake_pool.pubkey(); - let (mut stake_pool, mut validator_list) = stake_pool_accounts.state(); - - for _ in 0..max_validators { - vote_account_pubkeys.push(add_vote_account(&mut program_test)); - } - - for vote_account_address in vote_account_pubkeys.iter().take(num_validators as usize) { - add_validator_stake_account( - &mut program_test, - &mut stake_pool, - &mut validator_list, - &stake_pool_pubkey, - &stake_pool_accounts.withdraw_authority, - vote_account_address, - stake_amount, - ); - } - - add_reserve_stake_account( - &mut program_test, - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.withdraw_authority, - stake_amount, - ); - add_stake_pool_account( - &mut program_test, - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool, - ); - add_validator_list_account( - &mut program_test, - &stake_pool_accounts.validator_list.pubkey(), - &validator_list, - max_validators, - ); - - add_mint_account( - &mut program_test, - &stake_pool_accounts.pool_mint.pubkey(), - &stake_pool_accounts.withdraw_authority, - stake_pool.pool_token_supply, - ); - add_token_account( - &mut program_test, - &stake_pool_accounts.pool_fee_account.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &stake_pool_accounts.manager.pubkey(), - ); - - let mut context = program_test.start_with_context().await; - - let vote_pubkey = vote_account_pubkeys[HUGE_POOL_SIZE as usize - 1]; - // make stake account - let user = Keypair::new(); - let deposit_stake = Keypair::new(); - let lockup = stake::state::Lockup::default(); - - let authorized = stake::state::Authorized { - staker: user.pubkey(), - withdrawer: user.pubkey(), - }; - - let _stake_lamports = create_independent_stake_account( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &deposit_stake, - &authorized, - &lockup, - stake_amount, - ) - .await; - - delegate_stake_account( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &deposit_stake.pubkey(), - &user, - &vote_pubkey, - ) - .await; - - // make pool token account - let pool_token_account = Keypair::new(); - create_token_account( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &pool_token_account, - &stake_pool_accounts.pool_mint.pubkey(), - &user.pubkey(), - ) - .await - .unwrap(); - - ( - context, - stake_pool_accounts, - vote_account_pubkeys, - vote_pubkey, - user, - deposit_stake.pubkey(), - pool_token_account.pubkey(), - ) -} - -#[tokio::test] -async fn update() { - let (mut context, stake_pool_accounts, vote_account_pubkeys, _, _, _, _) = - setup(HUGE_POOL_SIZE, HUGE_POOL_SIZE, STAKE_AMOUNT).await; - - let validator_list = stake_pool_accounts - .get_validator_list(&mut context.banks_client) - .await; - let transaction = Transaction::new_signed_with_payer( - &[instruction::update_validator_list_balance( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.withdraw_authority, - &stake_pool_accounts.validator_list.pubkey(), - &stake_pool_accounts.reserve_stake.pubkey(), - &validator_list, - &vote_account_pubkeys[0..MAX_VALIDATORS_TO_UPDATE], - 0, - /* no_merge = */ false, - )], - Some(&context.payer.pubkey()), - &[&context.payer], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err(); - assert!(error.is_none()); - - let transaction = Transaction::new_signed_with_payer( - &[instruction::update_stake_pool_balance( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.withdraw_authority, - &stake_pool_accounts.validator_list.pubkey(), - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &spl_token::id(), - )], - Some(&context.payer.pubkey()), - &[&context.payer], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err(); - assert!(error.is_none()); - - let transaction = Transaction::new_signed_with_payer( - &[instruction::cleanup_removed_validator_entries( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - )], - Some(&context.payer.pubkey()), - &[&context.payer], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err(); - assert!(error.is_none()); -} - -#[tokio::test] -async fn remove_validator_from_pool() { - let (mut context, stake_pool_accounts, vote_account_pubkeys, _, _, _, _) = - setup(HUGE_POOL_SIZE, HUGE_POOL_SIZE, MINIMUM_ACTIVE_STAKE).await; - - let first_vote = vote_account_pubkeys[0]; - let (stake_address, _) = - find_stake_program_address(&id(), &first_vote, &stake_pool_accounts.stake_pool.pubkey()); - let transient_stake_seed = u64::MAX; - let (transient_stake_address, _) = find_transient_stake_program_address( - &id(), - &first_vote, - &stake_pool_accounts.stake_pool.pubkey(), - transient_stake_seed, - ); - - let new_authority = Pubkey::new_unique(); - let destination_stake = Keypair::new(); - let error = stake_pool_accounts - .remove_validator_from_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &new_authority, - &stake_address, - &transient_stake_address, - &destination_stake, - ) - .await; - assert!(error.is_none()); - - let middle_index = HUGE_POOL_SIZE as usize / 2; - let middle_vote = vote_account_pubkeys[middle_index]; - let (stake_address, _) = find_stake_program_address( - &id(), - &middle_vote, - &stake_pool_accounts.stake_pool.pubkey(), - ); - let (transient_stake_address, _) = find_transient_stake_program_address( - &id(), - &middle_vote, - &stake_pool_accounts.stake_pool.pubkey(), - transient_stake_seed, - ); - - let new_authority = Pubkey::new_unique(); - let destination_stake = Keypair::new(); - let error = stake_pool_accounts - .remove_validator_from_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &new_authority, - &stake_address, - &transient_stake_address, - &destination_stake, - ) - .await; - assert!(error.is_none()); - - let last_index = HUGE_POOL_SIZE as usize - 1; - let last_vote = vote_account_pubkeys[last_index]; - let (stake_address, _) = - find_stake_program_address(&id(), &last_vote, &stake_pool_accounts.stake_pool.pubkey()); - let (transient_stake_address, _) = find_transient_stake_program_address( - &id(), - &last_vote, - &stake_pool_accounts.stake_pool.pubkey(), - transient_stake_seed, - ); - - let new_authority = Pubkey::new_unique(); - let destination_stake = Keypair::new(); - let error = stake_pool_accounts - .remove_validator_from_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &new_authority, - &stake_address, - &transient_stake_address, - &destination_stake, - ) - .await; - assert!(error.is_none()); - - let validator_list = get_account( - &mut context.banks_client, - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let validator_list = - try_from_slice_unchecked::(validator_list.data.as_slice()).unwrap(); - let first_element = &validator_list.validators[0]; - assert_eq!(first_element.status, StakeStatus::ReadyForRemoval); - assert_eq!(first_element.active_stake_lamports, 0); - assert_eq!(first_element.transient_stake_lamports, 0); - - let middle_element = &validator_list.validators[middle_index]; - assert_eq!(middle_element.status, StakeStatus::ReadyForRemoval); - assert_eq!(middle_element.active_stake_lamports, 0); - assert_eq!(middle_element.transient_stake_lamports, 0); - - let last_element = &validator_list.validators[last_index]; - assert_eq!(last_element.status, StakeStatus::ReadyForRemoval); - assert_eq!(last_element.active_stake_lamports, 0); - assert_eq!(last_element.transient_stake_lamports, 0); - - let transaction = Transaction::new_signed_with_payer( - &[instruction::cleanup_removed_validator_entries( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - )], - Some(&context.payer.pubkey()), - &[&context.payer], - context.last_blockhash, - ); - - let error = context - .banks_client - .process_transaction(transaction) - .await - .err(); - assert!(error.is_none()); - - let validator_list = get_account( - &mut context.banks_client, - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let validator_list = - try_from_slice_unchecked::(validator_list.data.as_slice()).unwrap(); - assert_eq!(validator_list.validators.len() as u32, HUGE_POOL_SIZE - 3); - // assert they're gone - assert!(!validator_list - .validators - .iter() - .any(|x| x.vote_account_address == first_vote)); - assert!(!validator_list - .validators - .iter() - .any(|x| x.vote_account_address == middle_vote)); - assert!(!validator_list - .validators - .iter() - .any(|x| x.vote_account_address == last_vote)); - - // but that we didn't remove too many - assert!(validator_list - .validators - .iter() - .any(|x| x.vote_account_address == vote_account_pubkeys[1])); - assert!(validator_list - .validators - .iter() - .any(|x| x.vote_account_address == vote_account_pubkeys[middle_index - 1])); - assert!(validator_list - .validators - .iter() - .any(|x| x.vote_account_address == vote_account_pubkeys[middle_index + 1])); - assert!(validator_list - .validators - .iter() - .any(|x| x.vote_account_address == vote_account_pubkeys[last_index - 1])); -} - -#[tokio::test] -async fn add_validator_to_pool() { - let (mut context, stake_pool_accounts, _, test_vote_address, _, _, _) = - setup(HUGE_POOL_SIZE, HUGE_POOL_SIZE - 1, STAKE_AMOUNT).await; - - let last_index = HUGE_POOL_SIZE as usize - 1; - let stake_pool_pubkey = stake_pool_accounts.stake_pool.pubkey(); - let (stake_address, _) = - find_stake_program_address(&id(), &test_vote_address, &stake_pool_pubkey); - - let error = stake_pool_accounts - .add_validator_to_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_address, - &test_vote_address, - ) - .await; - assert!(error.is_none()); - - let validator_list = get_account( - &mut context.banks_client, - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let validator_list = - try_from_slice_unchecked::(validator_list.data.as_slice()).unwrap(); - assert_eq!(validator_list.validators.len(), last_index + 1); - let last_element = validator_list.validators[last_index]; - assert_eq!(last_element.status, StakeStatus::Active); - assert_eq!(last_element.active_stake_lamports, 0); - assert_eq!(last_element.transient_stake_lamports, 0); - assert_eq!(last_element.vote_account_address, test_vote_address); - - let transient_stake_seed = u64::MAX; - let (transient_stake_address, _) = find_transient_stake_program_address( - &id(), - &test_vote_address, - &stake_pool_pubkey, - transient_stake_seed, - ); - let increase_amount = MINIMUM_ACTIVE_STAKE; - let error = stake_pool_accounts - .increase_validator_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &transient_stake_address, - &stake_address, - &test_vote_address, - increase_amount, - transient_stake_seed, - ) - .await; - assert!(error.is_none(), "{:?}", error); - - let validator_list = get_account( - &mut context.banks_client, - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let validator_list = - try_from_slice_unchecked::(validator_list.data.as_slice()).unwrap(); - let last_element = validator_list.validators[last_index]; - assert_eq!(last_element.status, StakeStatus::Active); - assert_eq!(last_element.active_stake_lamports, 0); - assert_eq!( - last_element.transient_stake_lamports, - increase_amount + STAKE_ACCOUNT_RENT_EXEMPTION - ); - assert_eq!(last_element.vote_account_address, test_vote_address); -} - -#[tokio::test] -async fn set_preferred() { - let (mut context, stake_pool_accounts, _, vote_account_address, _, _, _) = - setup(HUGE_POOL_SIZE, HUGE_POOL_SIZE, STAKE_AMOUNT).await; - - let error = stake_pool_accounts - .set_preferred_validator( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - PreferredValidatorType::Deposit, - Some(vote_account_address), - ) - .await; - assert!(error.is_none()); - let error = stake_pool_accounts - .set_preferred_validator( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - PreferredValidatorType::Withdraw, - Some(vote_account_address), - ) - .await; - assert!(error.is_none()); - - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - - assert_eq!( - stake_pool.preferred_deposit_validator_vote_address, - Some(vote_account_address) - ); - assert_eq!( - stake_pool.preferred_withdraw_validator_vote_address, - Some(vote_account_address) - ); -} - -#[tokio::test] -async fn deposit_stake() { - let (mut context, stake_pool_accounts, _, vote_pubkey, user, stake_pubkey, pool_account_pubkey) = - setup(HUGE_POOL_SIZE, HUGE_POOL_SIZE, STAKE_AMOUNT).await; - - let (stake_address, _) = find_stake_program_address( - &id(), - &vote_pubkey, - &stake_pool_accounts.stake_pool.pubkey(), - ); - - let error = stake_pool_accounts - .deposit_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_pubkey, - &pool_account_pubkey, - &stake_address, - &user, - ) - .await; - assert!(error.is_none()); -} - -#[tokio::test] -async fn withdraw() { - let (mut context, stake_pool_accounts, _, vote_pubkey, user, stake_pubkey, pool_account_pubkey) = - setup(HUGE_POOL_SIZE, HUGE_POOL_SIZE, STAKE_AMOUNT).await; - - let (stake_address, _) = find_stake_program_address( - &id(), - &vote_pubkey, - &stake_pool_accounts.stake_pool.pubkey(), - ); - - let error = stake_pool_accounts - .deposit_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_pubkey, - &pool_account_pubkey, - &stake_address, - &user, - ) - .await; - assert!(error.is_none()); - - // Create stake account to withdraw to - let user_stake_recipient = Keypair::new(); - create_blank_stake_account( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &user_stake_recipient, - ) - .await; - - let error = stake_pool_accounts - .withdraw_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &user_stake_recipient.pubkey(), - &user, - &pool_account_pubkey, - &stake_address, - &user.pubkey(), - STAKE_AMOUNT, - ) - .await; - assert!(error.is_none(), "{:?}", error); -} diff --git a/stake-pool/program/tests/increase.rs b/stake-pool/program/tests/increase.rs deleted file mode 100644 index 13f55564a4d..00000000000 --- a/stake-pool/program/tests/increase.rs +++ /dev/null @@ -1,411 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod helpers; - -use { - bincode::deserialize, - helpers::*, - solana_program::{ - clock::Epoch, hash::Hash, instruction::InstructionError, pubkey::Pubkey, stake, - }, - solana_program_test::*, - solana_sdk::{ - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, - }, - spl_stake_pool::{ - error::StakePoolError, find_transient_stake_program_address, id, instruction, - MINIMUM_ACTIVE_STAKE, MINIMUM_RESERVE_LAMPORTS, - }, -}; - -async fn setup() -> ( - BanksClient, - Keypair, - Hash, - StakePoolAccounts, - ValidatorStakeAccount, - u64, -) { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - let reserve_lamports = 100_000_000_000 + MINIMUM_RESERVE_LAMPORTS; - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - reserve_lamports, - ) - .await - .unwrap(); - - let validator_stake_account = simple_add_validator_to_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - ) - .await; - - let _deposit_info = simple_deposit_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - &validator_stake_account, - MINIMUM_ACTIVE_STAKE, - ) - .await - .unwrap(); - - ( - banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake_account, - reserve_lamports, - ) -} - -#[tokio::test] -async fn success() { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake, - reserve_lamports, - ) = setup().await; - - // Save reserve stake - let pre_reserve_stake_account = get_account( - &mut banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - ) - .await; - - // Check no transient stake - let transient_account = banks_client - .get_account(validator_stake.transient_stake_account) - .await - .unwrap(); - assert!(transient_account.is_none()); - - let rent = banks_client.get_rent().await.unwrap(); - let stake_rent = rent.minimum_balance(std::mem::size_of::()); - let increase_amount = reserve_lamports - stake_rent - MINIMUM_RESERVE_LAMPORTS; - let error = stake_pool_accounts - .increase_validator_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &validator_stake.transient_stake_account, - &validator_stake.stake_account, - &validator_stake.vote.pubkey(), - increase_amount, - validator_stake.transient_stake_seed, - ) - .await; - assert!(error.is_none()); - - // Check reserve stake account balance - let reserve_stake_account = get_account( - &mut banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - ) - .await; - let reserve_stake_state = - deserialize::(&reserve_stake_account.data).unwrap(); - assert_eq!( - pre_reserve_stake_account.lamports - increase_amount - stake_rent, - reserve_stake_account.lamports - ); - assert!(reserve_stake_state.delegation().is_none()); - - // Check transient stake account state and balance - let transient_stake_account = - get_account(&mut banks_client, &validator_stake.transient_stake_account).await; - let transient_stake_state = - deserialize::(&transient_stake_account.data).unwrap(); - assert_eq!( - transient_stake_account.lamports, - increase_amount + stake_rent - ); - assert_ne!( - transient_stake_state.delegation().unwrap().activation_epoch, - Epoch::MAX - ); -} - -#[tokio::test] -async fn fail_with_wrong_withdraw_authority() { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake, - reserve_lamports, - ) = setup().await; - - let wrong_authority = Pubkey::new_unique(); - - let transaction = Transaction::new_signed_with_payer( - &[instruction::increase_validator_stake( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.staker.pubkey(), - &wrong_authority, - &stake_pool_accounts.validator_list.pubkey(), - &stake_pool_accounts.reserve_stake.pubkey(), - &validator_stake.transient_stake_account, - &validator_stake.stake_account, - &validator_stake.vote.pubkey(), - reserve_lamports / 2, - validator_stake.transient_stake_seed, - )], - Some(&payer.pubkey()), - &[&payer, &stake_pool_accounts.staker], - recent_blockhash, - ); - let error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = StakePoolError::InvalidProgramAddress as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error"), - } -} - -#[tokio::test] -async fn fail_with_wrong_validator_list() { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake, - reserve_lamports, - ) = setup().await; - - let wrong_validator_list = Pubkey::new_unique(); - - let transaction = Transaction::new_signed_with_payer( - &[instruction::increase_validator_stake( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.staker.pubkey(), - &stake_pool_accounts.withdraw_authority, - &wrong_validator_list, - &stake_pool_accounts.reserve_stake.pubkey(), - &validator_stake.transient_stake_account, - &validator_stake.stake_account, - &validator_stake.vote.pubkey(), - reserve_lamports / 2, - validator_stake.transient_stake_seed, - )], - Some(&payer.pubkey()), - &[&payer, &stake_pool_accounts.staker], - recent_blockhash, - ); - let error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = StakePoolError::InvalidValidatorStakeList as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error"), - } -} - -#[tokio::test] -async fn fail_with_unknown_validator() { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - _validator_stake, - reserve_lamports, - ) = setup().await; - - let unknown_stake = create_unknown_validator_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - - let transaction = Transaction::new_signed_with_payer( - &[instruction::increase_validator_stake( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.staker.pubkey(), - &stake_pool_accounts.withdraw_authority, - &stake_pool_accounts.validator_list.pubkey(), - &stake_pool_accounts.reserve_stake.pubkey(), - &unknown_stake.transient_stake_account, - &unknown_stake.stake_account, - &unknown_stake.vote.pubkey(), - reserve_lamports / 2, - unknown_stake.transient_stake_seed, - )], - Some(&payer.pubkey()), - &[&payer, &stake_pool_accounts.staker], - recent_blockhash, - ); - let error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - assert_eq!( - error, - TransactionError::InstructionError( - 0, - InstructionError::Custom(StakePoolError::ValidatorNotFound as u32) - ) - ); -} - -#[tokio::test] -async fn fail_increase_twice() { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake, - reserve_lamports, - ) = setup().await; - - let error = stake_pool_accounts - .increase_validator_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &validator_stake.transient_stake_account, - &validator_stake.stake_account, - &validator_stake.vote.pubkey(), - reserve_lamports / 3, - validator_stake.transient_stake_seed, - ) - .await; - assert!(error.is_none()); - - let transient_stake_seed = validator_stake.transient_stake_seed * 100; - let transient_stake_address = find_transient_stake_program_address( - &id(), - &validator_stake.vote.pubkey(), - &stake_pool_accounts.stake_pool.pubkey(), - transient_stake_seed, - ) - .0; - let error = stake_pool_accounts - .increase_validator_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &transient_stake_address, - &validator_stake.stake_account, - &validator_stake.vote.pubkey(), - reserve_lamports / 4, - transient_stake_seed, - ) - .await - .unwrap() - .unwrap(); - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = StakePoolError::TransientAccountInUse as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error"), - } -} - -#[tokio::test] -async fn fail_with_small_lamport_amount() { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake, - _reserve_lamports, - ) = setup().await; - - let error = stake_pool_accounts - .increase_validator_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &validator_stake.transient_stake_account, - &validator_stake.stake_account, - &validator_stake.vote.pubkey(), - MINIMUM_ACTIVE_STAKE - 1, - validator_stake.transient_stake_seed, - ) - .await - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::AccountNotRentExempt) => {} - _ => panic!("Wrong error"), - } -} - -#[tokio::test] -async fn fail_overdraw_reserve() { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake, - reserve_lamports, - ) = setup().await; - - let error = stake_pool_accounts - .increase_validator_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &validator_stake.transient_stake_account, - &validator_stake.stake_account, - &validator_stake.vote.pubkey(), - reserve_lamports, - validator_stake.transient_stake_seed, - ) - .await - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::InsufficientFunds) => {} - _ => panic!("Wrong error occurs while overdrawing reserve stake"), - } -} - -#[tokio::test] -async fn fail_with_force_destaked_validator() {} diff --git a/stake-pool/program/tests/initialize.rs b/stake-pool/program/tests/initialize.rs deleted file mode 100644 index 220f621e9fa..00000000000 --- a/stake-pool/program/tests/initialize.rs +++ /dev/null @@ -1,1362 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod helpers; - -use { - borsh::BorshSerialize, - helpers::*, - solana_program::{ - borsh::{get_instance_packed_len, get_packed_len, try_from_slice_unchecked}, - hash::Hash, - instruction::{AccountMeta, Instruction}, - program_pack::Pack, - pubkey::Pubkey, - stake, system_instruction, sysvar, - }, - solana_program_test::*, - solana_sdk::{ - instruction::InstructionError, - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, - transport::TransportError, - }, - spl_stake_pool::{error, id, instruction, state, MINIMUM_RESERVE_LAMPORTS}, -}; - -async fn create_required_accounts( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: &Hash, - stake_pool_accounts: &StakePoolAccounts, -) { - create_mint( - banks_client, - payer, - recent_blockhash, - &stake_pool_accounts.pool_mint, - &stake_pool_accounts.withdraw_authority, - ) - .await - .unwrap(); - - create_token_account( - banks_client, - payer, - recent_blockhash, - &stake_pool_accounts.pool_fee_account, - &stake_pool_accounts.pool_mint.pubkey(), - &stake_pool_accounts.manager.pubkey(), - ) - .await - .unwrap(); - - create_independent_stake_account( - banks_client, - payer, - recent_blockhash, - &stake_pool_accounts.reserve_stake, - &stake::state::Authorized { - staker: stake_pool_accounts.withdraw_authority, - withdrawer: stake_pool_accounts.withdraw_authority, - }, - &stake::state::Lockup::default(), - MINIMUM_RESERVE_LAMPORTS, - ) - .await; -} - -#[tokio::test] -async fn success() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - // Stake pool now exists - let stake_pool = get_account(&mut banks_client, &stake_pool_accounts.stake_pool.pubkey()).await; - assert_eq!(stake_pool.data.len(), get_packed_len::()); - assert_eq!(stake_pool.owner, id()); - - // Validator stake list storage initialized - let validator_list = get_account( - &mut banks_client, - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let validator_list = - try_from_slice_unchecked::(validator_list.data.as_slice()).unwrap(); - assert!(validator_list.header.is_valid()); -} - -#[tokio::test] -async fn fail_double_initialize() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let latest_blockhash = banks_client.get_latest_blockhash().await.unwrap(); - - let mut second_stake_pool_accounts = StakePoolAccounts::new(); - second_stake_pool_accounts.stake_pool = stake_pool_accounts.stake_pool; - - let transaction_error = second_stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &latest_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .err() - .unwrap(); - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = error::StakePoolError::AlreadyInUse as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while try to initialize already initialized stake pool"), - } -} - -#[tokio::test] -async fn fail_with_already_initialized_validator_list() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let latest_blockhash = banks_client.get_latest_blockhash().await.unwrap(); - - let mut second_stake_pool_accounts = StakePoolAccounts::new(); - second_stake_pool_accounts.validator_list = stake_pool_accounts.validator_list; - - let transaction_error = second_stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &latest_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .err() - .unwrap(); - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = error::StakePoolError::AlreadyInUse as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while try to initialize stake pool with already initialized stake list storage"), - } -} - -#[tokio::test] -async fn fail_with_high_fee() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let mut stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts.epoch_fee = state::Fee { - numerator: 100001, - denominator: 100000, - }; - - let transaction_error = stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .err() - .unwrap(); - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = error::StakePoolError::FeeTooHigh as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while try to initialize stake pool with high fee"), - } -} - -#[tokio::test] -async fn fail_with_high_withdrawal_fee() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let mut stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts.withdrawal_fee = state::Fee { - numerator: 100_001, - denominator: 100_000, - }; - - let transaction_error = stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .err() - .unwrap(); - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = error::StakePoolError::FeeTooHigh as u32; - assert_eq!(error_index, program_error); - } - _ => { - panic!("Wrong error occurs while try to initialize stake pool with high withdrawal fee") - } - } -} - -#[tokio::test] -async fn fail_with_wrong_max_validators() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - - create_required_accounts( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - ) - .await; - - let rent = banks_client.get_rent().await.unwrap(); - let rent_stake_pool = rent.minimum_balance(get_packed_len::()); - let validator_list_size = get_instance_packed_len(&state::ValidatorList::new( - stake_pool_accounts.max_validators - 1, - )) - .unwrap(); - let rent_validator_list = rent.minimum_balance(validator_list_size); - - let mut transaction = Transaction::new_with_payer( - &[ - system_instruction::create_account( - &payer.pubkey(), - &stake_pool_accounts.stake_pool.pubkey(), - rent_stake_pool, - get_packed_len::() as u64, - &id(), - ), - system_instruction::create_account( - &payer.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - rent_validator_list, - validator_list_size as u64, - &id(), - ), - instruction::initialize( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - &stake_pool_accounts.staker.pubkey(), - &stake_pool_accounts.withdraw_authority, - &stake_pool_accounts.validator_list.pubkey(), - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - &spl_token::id(), - None, - stake_pool_accounts.epoch_fee, - stake_pool_accounts.withdrawal_fee, - stake_pool_accounts.deposit_fee, - stake_pool_accounts.referral_fee, - stake_pool_accounts.max_validators, - ), - ], - Some(&payer.pubkey()), - ); - transaction.sign( - &[ - &payer, - &stake_pool_accounts.stake_pool, - &stake_pool_accounts.validator_list, - &stake_pool_accounts.manager, - ], - recent_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = error::StakePoolError::UnexpectedValidatorListAccountSize as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while try to initialize stake pool with high fee"), - } -} - -#[tokio::test] -async fn fail_with_wrong_mint_authority() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - let wrong_mint = Keypair::new(); - - create_required_accounts( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - ) - .await; - - // create wrong mint - create_mint( - &mut banks_client, - &payer, - &recent_blockhash, - &wrong_mint, - &stake_pool_accounts.withdraw_authority, - ) - .await - .unwrap(); - - let transaction_error = create_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts.stake_pool, - &stake_pool_accounts.validator_list, - &stake_pool_accounts.reserve_stake.pubkey(), - &wrong_mint.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - &stake_pool_accounts.manager, - &stake_pool_accounts.staker.pubkey(), - &stake_pool_accounts.withdraw_authority, - &None, - &stake_pool_accounts.epoch_fee, - &stake_pool_accounts.withdrawal_fee, - &stake_pool_accounts.deposit_fee, - stake_pool_accounts.referral_fee, - &stake_pool_accounts.sol_deposit_fee, - stake_pool_accounts.sol_referral_fee, - stake_pool_accounts.max_validators, - ) - .await - .err() - .unwrap(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = error::StakePoolError::WrongAccountMint as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while try to initialize stake pool with wrong mint authority of pool fee account"), - } -} - -#[tokio::test] -async fn fail_with_freeze_authority() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - - create_required_accounts( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - ) - .await; - - // create mint with freeze authority - let wrong_mint = Keypair::new(); - let rent = banks_client.get_rent().await.unwrap(); - let mint_rent = rent.minimum_balance(spl_token::state::Mint::LEN); - - let transaction = Transaction::new_signed_with_payer( - &[ - system_instruction::create_account( - &payer.pubkey(), - &wrong_mint.pubkey(), - mint_rent, - spl_token::state::Mint::LEN as u64, - &spl_token::id(), - ), - spl_token::instruction::initialize_mint( - &spl_token::id(), - &wrong_mint.pubkey(), - &stake_pool_accounts.withdraw_authority, - Some(&stake_pool_accounts.withdraw_authority), - 0, - ) - .unwrap(), - ], - Some(&payer.pubkey()), - &[&payer, &wrong_mint], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); - - let pool_fee_account = Keypair::new(); - create_token_account( - &mut banks_client, - &payer, - &recent_blockhash, - &pool_fee_account, - &wrong_mint.pubkey(), - &stake_pool_accounts.manager.pubkey(), - ) - .await - .unwrap(); - - let error = create_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts.stake_pool, - &stake_pool_accounts.validator_list, - &stake_pool_accounts.reserve_stake.pubkey(), - &wrong_mint.pubkey(), - &pool_fee_account.pubkey(), - &stake_pool_accounts.manager, - &stake_pool_accounts.staker.pubkey(), - &stake_pool_accounts.withdraw_authority, - &None, - &stake_pool_accounts.epoch_fee, - &stake_pool_accounts.withdrawal_fee, - &stake_pool_accounts.deposit_fee, - stake_pool_accounts.referral_fee, - &stake_pool_accounts.sol_deposit_fee, - stake_pool_accounts.sol_referral_fee, - stake_pool_accounts.max_validators, - ) - .await - .err() - .unwrap() - .unwrap(); - - assert_eq!( - error, - TransactionError::InstructionError( - 2, - InstructionError::Custom(error::StakePoolError::InvalidMintFreezeAuthority as u32), - ) - ); -} - -#[tokio::test] -async fn fail_with_wrong_token_program_id() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - - let wrong_token_program = Keypair::new(); - - create_mint( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts.pool_mint, - &stake_pool_accounts.withdraw_authority, - ) - .await - .unwrap(); - - create_token_account( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts.pool_fee_account, - &stake_pool_accounts.pool_mint.pubkey(), - &stake_pool_accounts.manager.pubkey(), - ) - .await - .unwrap(); - - let rent = banks_client.get_rent().await.unwrap(); - let rent_stake_pool = rent.minimum_balance(get_packed_len::()); - let validator_list_size = get_instance_packed_len(&state::ValidatorList::new( - stake_pool_accounts.max_validators, - )) - .unwrap(); - let rent_validator_list = rent.minimum_balance(validator_list_size); - - let mut transaction = Transaction::new_with_payer( - &[ - system_instruction::create_account( - &payer.pubkey(), - &stake_pool_accounts.stake_pool.pubkey(), - rent_stake_pool, - get_packed_len::() as u64, - &id(), - ), - system_instruction::create_account( - &payer.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - rent_validator_list, - validator_list_size as u64, - &id(), - ), - instruction::initialize( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - &stake_pool_accounts.staker.pubkey(), - &stake_pool_accounts.withdraw_authority, - &stake_pool_accounts.validator_list.pubkey(), - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - &wrong_token_program.pubkey(), - None, - stake_pool_accounts.epoch_fee, - stake_pool_accounts.withdrawal_fee, - stake_pool_accounts.deposit_fee, - stake_pool_accounts.referral_fee, - stake_pool_accounts.max_validators, - ), - ], - Some(&payer.pubkey()), - ); - transaction.sign( - &[ - &payer, - &stake_pool_accounts.stake_pool, - &stake_pool_accounts.validator_list, - &stake_pool_accounts.manager, - ], - recent_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError(_, error)) => { - assert_eq!(error, InstructionError::IncorrectProgramId); - } - _ => panic!( - "Wrong error occurs while try to initialize stake pool with wrong token program ID" - ), - } -} - -#[tokio::test] -async fn fail_with_fee_owned_by_wrong_token_program_id() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - - let wrong_token_program = Keypair::new(); - - create_mint( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts.pool_mint, - &stake_pool_accounts.withdraw_authority, - ) - .await - .unwrap(); - - let rent = banks_client.get_rent().await.unwrap(); - - let account_rent = rent.minimum_balance(spl_token::state::Account::LEN); - let transaction = Transaction::new_signed_with_payer( - &[system_instruction::create_account( - &payer.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - account_rent, - spl_token::state::Account::LEN as u64, - &wrong_token_program.pubkey(), - )], - Some(&payer.pubkey()), - &[&payer, &stake_pool_accounts.pool_fee_account], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); - - let rent_stake_pool = rent.minimum_balance(get_packed_len::()); - let validator_list_size = get_instance_packed_len(&state::ValidatorList::new( - stake_pool_accounts.max_validators, - )) - .unwrap(); - let rent_validator_list = rent.minimum_balance(validator_list_size); - - let mut transaction = Transaction::new_with_payer( - &[ - system_instruction::create_account( - &payer.pubkey(), - &stake_pool_accounts.stake_pool.pubkey(), - rent_stake_pool, - get_packed_len::() as u64, - &id(), - ), - system_instruction::create_account( - &payer.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - rent_validator_list, - validator_list_size as u64, - &id(), - ), - instruction::initialize( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - &stake_pool_accounts.staker.pubkey(), - &stake_pool_accounts.withdraw_authority, - &stake_pool_accounts.validator_list.pubkey(), - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - &wrong_token_program.pubkey(), - None, - stake_pool_accounts.epoch_fee, - stake_pool_accounts.withdrawal_fee, - stake_pool_accounts.deposit_fee, - stake_pool_accounts.referral_fee, - stake_pool_accounts.max_validators, - ), - ], - Some(&payer.pubkey()), - ); - transaction.sign( - &[ - &payer, - &stake_pool_accounts.stake_pool, - &stake_pool_accounts.validator_list, - &stake_pool_accounts.manager, - ], - recent_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError(_, error)) => { - assert_eq!(error, InstructionError::IncorrectProgramId); - } - _ => panic!( - "Wrong error occurs while try to initialize stake pool with wrong token program ID" - ), - } -} - -#[tokio::test] -async fn fail_with_wrong_fee_account() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - - create_mint( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts.pool_mint, - &stake_pool_accounts.withdraw_authority, - ) - .await - .unwrap(); - let rent = banks_client.get_rent().await.unwrap(); - let account_rent = rent.minimum_balance(spl_token::state::Account::LEN); - - let mut transaction = Transaction::new_with_payer( - &[system_instruction::create_account( - &payer.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - account_rent, - spl_token::state::Account::LEN as u64, - &Keypair::new().pubkey(), - )], - Some(&payer.pubkey()), - ); - transaction.sign( - &[&payer, &stake_pool_accounts.pool_fee_account], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); - - let transaction_error = create_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts.stake_pool, - &stake_pool_accounts.validator_list, - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - &stake_pool_accounts.manager, - &stake_pool_accounts.staker.pubkey(), - &stake_pool_accounts.withdraw_authority, - &None, - &stake_pool_accounts.epoch_fee, - &stake_pool_accounts.withdrawal_fee, - &stake_pool_accounts.deposit_fee, - stake_pool_accounts.referral_fee, - &stake_pool_accounts.sol_deposit_fee, - stake_pool_accounts.sol_referral_fee, - stake_pool_accounts.max_validators, - ) - .await - .err() - .unwrap() - .unwrap(); - - assert_eq!( - transaction_error, - TransactionError::InstructionError(2, InstructionError::IncorrectProgramId) - ); -} - -#[tokio::test] -async fn fail_with_wrong_withdraw_authority() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let mut stake_pool_accounts = StakePoolAccounts::new(); - - stake_pool_accounts.withdraw_authority = Keypair::new().pubkey(); - - let transaction_error = stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .err() - .unwrap(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = error::StakePoolError::InvalidProgramAddress as u32; - assert_eq!(error_index, program_error); - } - _ => panic!( - "Wrong error occurs while try to initialize stake pool with wrong withdraw authority" - ), - } -} - -#[tokio::test] -async fn fail_with_not_rent_exempt_pool() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - - create_required_accounts( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - ) - .await; - - let rent = banks_client.get_rent().await.unwrap(); - let validator_list_size = get_instance_packed_len(&state::ValidatorList::new( - stake_pool_accounts.max_validators, - )) - .unwrap(); - let rent_validator_list = rent.minimum_balance(validator_list_size); - - let mut transaction = Transaction::new_with_payer( - &[ - system_instruction::create_account( - &payer.pubkey(), - &stake_pool_accounts.stake_pool.pubkey(), - 1, - get_packed_len::() as u64, - &id(), - ), - system_instruction::create_account( - &payer.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - rent_validator_list, - validator_list_size as u64, - &id(), - ), - instruction::initialize( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - &stake_pool_accounts.staker.pubkey(), - &stake_pool_accounts.withdraw_authority, - &stake_pool_accounts.validator_list.pubkey(), - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - &spl_token::id(), - None, - stake_pool_accounts.epoch_fee, - stake_pool_accounts.withdrawal_fee, - stake_pool_accounts.deposit_fee, - stake_pool_accounts.referral_fee, - stake_pool_accounts.max_validators, - ), - ], - Some(&payer.pubkey()), - ); - transaction.sign( - &[ - &payer, - &stake_pool_accounts.stake_pool, - &stake_pool_accounts.validator_list, - &stake_pool_accounts.manager, - ], - recent_blockhash, - ); - let result = banks_client - .process_transaction(transaction) - .await - .unwrap_err() - .unwrap(); - assert!( - result == TransactionError::InstructionError(2, InstructionError::InvalidError,) - || result - == TransactionError::InstructionError(2, InstructionError::AccountNotRentExempt,) - ); -} - -#[tokio::test] -async fn fail_with_not_rent_exempt_validator_list() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - - create_required_accounts( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - ) - .await; - - let rent = banks_client.get_rent().await.unwrap(); - let rent_stake_pool = rent.minimum_balance(get_packed_len::()); - let validator_list_size = get_instance_packed_len(&state::ValidatorList::new( - stake_pool_accounts.max_validators, - )) - .unwrap(); - - let mut transaction = Transaction::new_with_payer( - &[ - system_instruction::create_account( - &payer.pubkey(), - &stake_pool_accounts.stake_pool.pubkey(), - rent_stake_pool, - get_packed_len::() as u64, - &id(), - ), - system_instruction::create_account( - &payer.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - 1, - validator_list_size as u64, - &id(), - ), - instruction::initialize( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - &stake_pool_accounts.staker.pubkey(), - &stake_pool_accounts.withdraw_authority, - &stake_pool_accounts.validator_list.pubkey(), - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - &spl_token::id(), - None, - stake_pool_accounts.epoch_fee, - stake_pool_accounts.withdrawal_fee, - stake_pool_accounts.deposit_fee, - stake_pool_accounts.referral_fee, - stake_pool_accounts.max_validators, - ), - ], - Some(&payer.pubkey()), - ); - transaction.sign( - &[ - &payer, - &stake_pool_accounts.stake_pool, - &stake_pool_accounts.validator_list, - &stake_pool_accounts.manager, - ], - recent_blockhash, - ); - - let result = banks_client - .process_transaction(transaction) - .await - .unwrap_err() - .unwrap(); - - assert!( - result == TransactionError::InstructionError(2, InstructionError::InvalidError,) - || result - == TransactionError::InstructionError(2, InstructionError::AccountNotRentExempt,) - ); -} - -#[tokio::test] -async fn fail_without_manager_signature() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - - create_required_accounts( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - ) - .await; - - let rent = banks_client.get_rent().await.unwrap(); - let rent_stake_pool = rent.minimum_balance(get_packed_len::()); - let validator_list_size = get_instance_packed_len(&state::ValidatorList::new( - stake_pool_accounts.max_validators, - )) - .unwrap(); - let rent_validator_list = rent.minimum_balance(validator_list_size); - - let init_data = instruction::StakePoolInstruction::Initialize { - fee: stake_pool_accounts.epoch_fee, - withdrawal_fee: stake_pool_accounts.withdrawal_fee, - deposit_fee: stake_pool_accounts.deposit_fee, - referral_fee: stake_pool_accounts.referral_fee, - max_validators: stake_pool_accounts.max_validators, - }; - let data = init_data.try_to_vec().unwrap(); - let accounts = vec![ - AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), true), - AccountMeta::new_readonly(stake_pool_accounts.manager.pubkey(), false), - AccountMeta::new_readonly(stake_pool_accounts.staker.pubkey(), false), - AccountMeta::new(stake_pool_accounts.validator_list.pubkey(), false), - AccountMeta::new_readonly(stake_pool_accounts.reserve_stake.pubkey(), false), - AccountMeta::new_readonly(stake_pool_accounts.pool_mint.pubkey(), false), - AccountMeta::new_readonly(stake_pool_accounts.pool_fee_account.pubkey(), false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - AccountMeta::new_readonly(spl_token::id(), false), - ]; - let stake_pool_init_instruction = Instruction { - program_id: id(), - accounts, - data, - }; - - let mut transaction = Transaction::new_with_payer( - &[ - system_instruction::create_account( - &payer.pubkey(), - &stake_pool_accounts.stake_pool.pubkey(), - rent_stake_pool, - get_packed_len::() as u64, - &id(), - ), - system_instruction::create_account( - &payer.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - rent_validator_list, - validator_list_size as u64, - &id(), - ), - stake_pool_init_instruction, - ], - Some(&payer.pubkey()), - ); - transaction.sign( - &[ - &payer, - &stake_pool_accounts.stake_pool, - &stake_pool_accounts.validator_list, - ], - recent_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = error::StakePoolError::SignatureMissing as u32; - assert_eq!(error_index, program_error); - } - _ => panic!( - "Wrong error occurs while try to initialize stake pool without manager's signature" - ), - } -} - -#[tokio::test] -async fn fail_with_pre_minted_pool_tokens() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - let mint_authority = Keypair::new(); - - create_mint( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts.pool_mint, - &mint_authority.pubkey(), - ) - .await - .unwrap(); - - create_token_account( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts.pool_fee_account, - &stake_pool_accounts.pool_mint.pubkey(), - &stake_pool_accounts.manager.pubkey(), - ) - .await - .unwrap(); - - mint_tokens( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts.pool_mint.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - &mint_authority, - 1, - ) - .await - .unwrap(); - - let transaction_error = create_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts.stake_pool, - &stake_pool_accounts.validator_list, - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - &stake_pool_accounts.manager, - &stake_pool_accounts.staker.pubkey(), - &stake_pool_accounts.withdraw_authority, - &None, - &stake_pool_accounts.epoch_fee, - &stake_pool_accounts.withdrawal_fee, - &stake_pool_accounts.deposit_fee, - stake_pool_accounts.referral_fee, - &stake_pool_accounts.sol_deposit_fee, - stake_pool_accounts.sol_referral_fee, - stake_pool_accounts.max_validators, - ) - .await - .err() - .unwrap(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = error::StakePoolError::NonZeroPoolTokenSupply as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while try to initialize stake pool with wrong mint authority of pool fee account"), - } -} - -#[tokio::test] -async fn fail_with_bad_reserve() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - let wrong_authority = Pubkey::new_unique(); - - create_required_accounts( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - ) - .await; - - { - let bad_stake = Keypair::new(); - create_independent_stake_account( - &mut banks_client, - &payer, - &recent_blockhash, - &bad_stake, - &stake::state::Authorized { - staker: wrong_authority, - withdrawer: stake_pool_accounts.withdraw_authority, - }, - &stake::state::Lockup::default(), - MINIMUM_RESERVE_LAMPORTS, - ) - .await; - - let error = create_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts.stake_pool, - &stake_pool_accounts.validator_list, - &bad_stake.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - &stake_pool_accounts.manager, - &stake_pool_accounts.staker.pubkey(), - &stake_pool_accounts.withdraw_authority, - &None, - &stake_pool_accounts.epoch_fee, - &stake_pool_accounts.withdrawal_fee, - &stake_pool_accounts.deposit_fee, - stake_pool_accounts.referral_fee, - &stake_pool_accounts.sol_deposit_fee, - stake_pool_accounts.sol_referral_fee, - stake_pool_accounts.max_validators, - ) - .await - .err() - .unwrap() - .unwrap(); - - assert_eq!( - error, - TransactionError::InstructionError( - 2, - InstructionError::Custom(error::StakePoolError::WrongStakeState as u32), - ) - ); - } - - { - let bad_stake = Keypair::new(); - create_independent_stake_account( - &mut banks_client, - &payer, - &recent_blockhash, - &bad_stake, - &stake::state::Authorized { - staker: stake_pool_accounts.withdraw_authority, - withdrawer: wrong_authority, - }, - &stake::state::Lockup::default(), - MINIMUM_RESERVE_LAMPORTS, - ) - .await; - - let error = create_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts.stake_pool, - &stake_pool_accounts.validator_list, - &bad_stake.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - &stake_pool_accounts.manager, - &stake_pool_accounts.staker.pubkey(), - &stake_pool_accounts.withdraw_authority, - &None, - &stake_pool_accounts.epoch_fee, - &stake_pool_accounts.withdrawal_fee, - &stake_pool_accounts.deposit_fee, - stake_pool_accounts.referral_fee, - &stake_pool_accounts.sol_deposit_fee, - stake_pool_accounts.sol_referral_fee, - stake_pool_accounts.max_validators, - ) - .await - .err() - .unwrap() - .unwrap(); - - assert_eq!( - error, - TransactionError::InstructionError( - 2, - InstructionError::Custom(error::StakePoolError::WrongStakeState as u32), - ) - ); - } - - { - let bad_stake = Keypair::new(); - create_independent_stake_account( - &mut banks_client, - &payer, - &recent_blockhash, - &bad_stake, - &stake::state::Authorized { - staker: stake_pool_accounts.withdraw_authority, - withdrawer: stake_pool_accounts.withdraw_authority, - }, - &stake::state::Lockup { - custodian: wrong_authority, - ..stake::state::Lockup::default() - }, - MINIMUM_RESERVE_LAMPORTS, - ) - .await; - - let error = create_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts.stake_pool, - &stake_pool_accounts.validator_list, - &bad_stake.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - &stake_pool_accounts.manager, - &stake_pool_accounts.staker.pubkey(), - &stake_pool_accounts.withdraw_authority, - &None, - &stake_pool_accounts.epoch_fee, - &stake_pool_accounts.withdrawal_fee, - &stake_pool_accounts.deposit_fee, - stake_pool_accounts.referral_fee, - &stake_pool_accounts.sol_deposit_fee, - stake_pool_accounts.sol_referral_fee, - stake_pool_accounts.max_validators, - ) - .await - .err() - .unwrap() - .unwrap(); - - assert_eq!( - error, - TransactionError::InstructionError( - 2, - InstructionError::Custom(error::StakePoolError::WrongStakeState as u32), - ) - ); - } - - { - let bad_stake = Keypair::new(); - let rent = banks_client.get_rent().await.unwrap(); - let lamports = rent.minimum_balance(std::mem::size_of::()) - + MINIMUM_RESERVE_LAMPORTS; - - let transaction = Transaction::new_signed_with_payer( - &[system_instruction::create_account( - &payer.pubkey(), - &bad_stake.pubkey(), - lamports, - std::mem::size_of::() as u64, - &stake::program::id(), - )], - Some(&payer.pubkey()), - &[&payer, &bad_stake], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); - - let error = create_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts.stake_pool, - &stake_pool_accounts.validator_list, - &bad_stake.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - &stake_pool_accounts.manager, - &stake_pool_accounts.staker.pubkey(), - &stake_pool_accounts.withdraw_authority, - &None, - &stake_pool_accounts.epoch_fee, - &stake_pool_accounts.withdrawal_fee, - &stake_pool_accounts.deposit_fee, - stake_pool_accounts.referral_fee, - &stake_pool_accounts.sol_deposit_fee, - stake_pool_accounts.sol_referral_fee, - stake_pool_accounts.max_validators, - ) - .await - .err() - .unwrap() - .unwrap(); - - assert_eq!( - error, - TransactionError::InstructionError( - 2, - InstructionError::Custom(error::StakePoolError::WrongStakeState as u32), - ) - ); - } -} - -#[tokio::test] -async fn success_with_extra_reserve_lamports() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - let init_lamports = 1_000_000_000_000; - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS + init_lamports, - ) - .await - .unwrap(); - - let init_pool_tokens = get_token_balance( - &mut banks_client, - &stake_pool_accounts.pool_fee_account.pubkey(), - ) - .await; - assert_eq!(init_pool_tokens, init_lamports); -} diff --git a/stake-pool/program/tests/set_deposit_fee.rs b/stake-pool/program/tests/set_deposit_fee.rs deleted file mode 100644 index ba7ead8015c..00000000000 --- a/stake-pool/program/tests/set_deposit_fee.rs +++ /dev/null @@ -1,278 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod helpers; - -use { - helpers::*, - solana_program_test::*, - solana_sdk::{ - borsh::try_from_slice_unchecked, - instruction::InstructionError, - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, - }, - spl_stake_pool::{ - error, id, instruction, - state::{Fee, FeeType, StakePool}, - MINIMUM_RESERVE_LAMPORTS, - }, -}; - -async fn setup(fee: Option) -> (ProgramTestContext, StakePoolAccounts, Fee) { - let mut context = program_test().start_with_context().await; - let mut stake_pool_accounts = StakePoolAccounts::new(); - if let Some(fee) = fee { - stake_pool_accounts.deposit_fee = fee; - } - stake_pool_accounts - .initialize_stake_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - let new_deposit_fee = Fee { - numerator: 823, - denominator: 1000, - }; - - (context, stake_pool_accounts, new_deposit_fee) -} - -#[tokio::test] -async fn success_stake() { - let (mut context, stake_pool_accounts, new_deposit_fee) = setup(None).await; - - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::StakeDeposit(new_deposit_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - assert_eq!(stake_pool.stake_deposit_fee, new_deposit_fee); -} - -#[tokio::test] -async fn success_stake_increase_fee_from_0() { - let (mut context, stake_pool_accounts, _) = setup(Some(Fee { - numerator: 0, - denominator: 0, - })) - .await; - let new_deposit_fee = Fee { - numerator: 324, - denominator: 1234, - }; - - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::StakeDeposit(new_deposit_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - assert_eq!(stake_pool.stake_deposit_fee, new_deposit_fee); -} - -#[tokio::test] -async fn fail_stake_wrong_manager() { - let (mut context, stake_pool_accounts, new_deposit_fee) = setup(None).await; - - let wrong_manager = Keypair::new(); - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &wrong_manager.pubkey(), - FeeType::StakeDeposit(new_deposit_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &wrong_manager], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = error::StakePoolError::WrongManager as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while signing with the wrong manager"), - } -} - -#[tokio::test] -async fn fail_stake_high_deposit_fee() { - let (mut context, stake_pool_accounts, _new_deposit_fee) = setup(None).await; - - let new_deposit_fee = Fee { - numerator: 100001, - denominator: 100000, - }; - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::StakeDeposit(new_deposit_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = error::StakePoolError::FeeTooHigh as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs when setting fee too high"), - } -} - -#[tokio::test] -async fn success_sol() { - let (mut context, stake_pool_accounts, new_deposit_fee) = setup(None).await; - - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::SolDeposit(new_deposit_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - assert_eq!(stake_pool.sol_deposit_fee, new_deposit_fee); -} - -#[tokio::test] -async fn fail_sol_wrong_manager() { - let (mut context, stake_pool_accounts, new_deposit_fee) = setup(None).await; - - let wrong_manager = Keypair::new(); - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &wrong_manager.pubkey(), - FeeType::SolDeposit(new_deposit_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &wrong_manager], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = error::StakePoolError::WrongManager as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while signing with the wrong manager"), - } -} - -#[tokio::test] -async fn fail_sol_high_deposit_fee() { - let (mut context, stake_pool_accounts, _new_deposit_fee) = setup(None).await; - - let new_deposit_fee = Fee { - numerator: 100001, - denominator: 100000, - }; - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::SolDeposit(new_deposit_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = error::StakePoolError::FeeTooHigh as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs when setting fee too high"), - } -} diff --git a/stake-pool/program/tests/set_epoch_fee.rs b/stake-pool/program/tests/set_epoch_fee.rs deleted file mode 100644 index d63a23a6afa..00000000000 --- a/stake-pool/program/tests/set_epoch_fee.rs +++ /dev/null @@ -1,226 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod helpers; - -use { - helpers::*, - solana_program_test::*, - solana_sdk::{ - borsh::try_from_slice_unchecked, - instruction::InstructionError, - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, - }, - spl_stake_pool::{ - error, id, instruction, - state::{Fee, FeeType, StakePool}, - MINIMUM_RESERVE_LAMPORTS, - }, -}; - -async fn setup() -> (ProgramTestContext, StakePoolAccounts, Fee) { - let mut context = program_test().start_with_context().await; - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - let new_fee = Fee { - numerator: 10, - denominator: 10, - }; - - (context, stake_pool_accounts, new_fee) -} - -#[tokio::test] -async fn success() { - let (mut context, stake_pool_accounts, new_fee) = setup().await; - - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - let old_fee = stake_pool.epoch_fee; - - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::Epoch(new_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - - assert_eq!(stake_pool.epoch_fee, old_fee); - assert_eq!(stake_pool.next_epoch_fee, Some(new_fee)); - - let first_normal_slot = context.genesis_config().epoch_schedule.first_normal_slot; - let slots_per_epoch = context.genesis_config().epoch_schedule.slots_per_epoch; - - context - .warp_to_slot(first_normal_slot + slots_per_epoch) - .unwrap(); - stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &[], - false, - ) - .await; - - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - assert_eq!(stake_pool.epoch_fee, new_fee); - assert_eq!(stake_pool.next_epoch_fee, None); -} - -#[tokio::test] -async fn fail_wrong_manager() { - let (mut context, stake_pool_accounts, new_fee) = setup().await; - - let wrong_manager = Keypair::new(); - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &wrong_manager.pubkey(), - FeeType::Epoch(new_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &wrong_manager], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = error::StakePoolError::WrongManager as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while malicious try to set manager"), - } -} - -#[tokio::test] -async fn fail_high_fee() { - let (mut context, stake_pool_accounts, _new_fee) = setup().await; - - let new_fee = Fee { - numerator: 11, - denominator: 10, - }; - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::Epoch(new_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = error::StakePoolError::FeeTooHigh as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs when setting fee too high"), - } -} - -#[tokio::test] -async fn fail_not_updated() { - let mut context = program_test().start_with_context().await; - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - let new_fee = Fee { - numerator: 10, - denominator: 100, - }; - - // move forward so an update is required - let first_normal_slot = context.genesis_config().epoch_schedule.first_normal_slot; - let slots_per_epoch = context.genesis_config().epoch_schedule.slots_per_epoch; - context - .warp_to_slot(first_normal_slot + slots_per_epoch) - .unwrap(); - - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::Epoch(new_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = error::StakePoolError::StakeListAndPoolOutOfDate as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs when stake pool out of date"), - } -} diff --git a/stake-pool/program/tests/set_funding_authority.rs b/stake-pool/program/tests/set_funding_authority.rs deleted file mode 100644 index fb4607daa7e..00000000000 --- a/stake-pool/program/tests/set_funding_authority.rs +++ /dev/null @@ -1,267 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod helpers; - -use { - borsh::BorshSerialize, - helpers::*, - solana_program::{ - borsh::try_from_slice_unchecked, - hash::Hash, - instruction::{AccountMeta, Instruction}, - }, - solana_program_test::*, - solana_sdk::{ - instruction::InstructionError, - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, - transport::TransportError, - }, - spl_stake_pool::{ - error, find_deposit_authority_program_address, id, - instruction::{self, FundingType}, - state, MINIMUM_RESERVE_LAMPORTS, - }, -}; - -async fn setup() -> (BanksClient, Keypair, Hash, StakePoolAccounts, Keypair) { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let new_deposit_authority = Keypair::new(); - - ( - banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - new_deposit_authority, - ) -} - -#[tokio::test] -async fn success_set_stake_deposit_authority() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, new_authority) = - setup().await; - - let mut transaction = Transaction::new_with_payer( - &[instruction::set_funding_authority( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - Some(&new_authority.pubkey()), - FundingType::StakeDeposit, - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &stake_pool_accounts.manager], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - let stake_pool = get_account(&mut banks_client, &stake_pool_accounts.stake_pool.pubkey()).await; - let stake_pool = - try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - - assert_eq!(stake_pool.stake_deposit_authority, new_authority.pubkey()); - - let mut transaction = Transaction::new_with_payer( - &[instruction::set_funding_authority( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - None, - FundingType::StakeDeposit, - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &stake_pool_accounts.manager], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - let stake_pool = get_account(&mut banks_client, &stake_pool_accounts.stake_pool.pubkey()).await; - let stake_pool = - try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - - assert_eq!( - stake_pool.stake_deposit_authority, - find_deposit_authority_program_address(&id(), &stake_pool_accounts.stake_pool.pubkey()).0 - ); -} - -#[tokio::test] -async fn fail_wrong_manager() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, new_authority) = - setup().await; - - let mut transaction = Transaction::new_with_payer( - &[instruction::set_funding_authority( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &new_authority.pubkey(), - Some(&new_authority.pubkey()), - FundingType::StakeDeposit, - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &new_authority], recent_blockhash); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = error::StakePoolError::WrongManager as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while malicious try to set manager"), - } -} - -#[tokio::test] -async fn fail_without_signature() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, new_authority) = - setup().await; - - let data = instruction::StakePoolInstruction::SetFundingAuthority(FundingType::StakeDeposit) - .try_to_vec() - .unwrap(); - let accounts = vec![ - AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false), - AccountMeta::new_readonly(stake_pool_accounts.manager.pubkey(), false), - AccountMeta::new_readonly(new_authority.pubkey(), false), - ]; - let instruction = Instruction { - program_id: id(), - accounts, - data, - }; - - let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = error::StakePoolError::SignatureMissing as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while try to set new manager without signature"), - } -} - -#[tokio::test] -async fn success_set_sol_deposit_authority() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, new_sol_deposit_authority) = - setup().await; - - let mut transaction = Transaction::new_with_payer( - &[instruction::set_funding_authority( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - Some(&new_sol_deposit_authority.pubkey()), - FundingType::SolDeposit, - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &stake_pool_accounts.manager], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - let stake_pool = get_account(&mut banks_client, &stake_pool_accounts.stake_pool.pubkey()).await; - let stake_pool = - try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - - assert_eq!( - stake_pool.sol_deposit_authority, - Some(new_sol_deposit_authority.pubkey()) - ); - - let mut transaction = Transaction::new_with_payer( - &[instruction::set_funding_authority( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - None, - FundingType::SolDeposit, - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &stake_pool_accounts.manager], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - let stake_pool = get_account(&mut banks_client, &stake_pool_accounts.stake_pool.pubkey()).await; - let stake_pool = - try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - - assert_eq!(stake_pool.sol_deposit_authority, None); -} - -#[tokio::test] -async fn success_set_withdraw_authority() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, new_authority) = - setup().await; - - let mut transaction = Transaction::new_with_payer( - &[instruction::set_funding_authority( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - Some(&new_authority.pubkey()), - FundingType::SolWithdraw, - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &stake_pool_accounts.manager], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - let stake_pool = get_account(&mut banks_client, &stake_pool_accounts.stake_pool.pubkey()).await; - let stake_pool = - try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - - assert_eq!( - stake_pool.sol_withdraw_authority, - Some(new_authority.pubkey()) - ); - - let mut transaction = Transaction::new_with_payer( - &[instruction::set_funding_authority( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - None, - FundingType::SolWithdraw, - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &stake_pool_accounts.manager], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - let stake_pool = get_account(&mut banks_client, &stake_pool_accounts.stake_pool.pubkey()).await; - let stake_pool = - try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - - assert_eq!(stake_pool.sol_withdraw_authority, None); -} diff --git a/stake-pool/program/tests/set_manager.rs b/stake-pool/program/tests/set_manager.rs deleted file mode 100644 index 64fcdb064f8..00000000000 --- a/stake-pool/program/tests/set_manager.rs +++ /dev/null @@ -1,289 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod helpers; - -use { - borsh::BorshSerialize, - helpers::*, - solana_program::{ - borsh::try_from_slice_unchecked, - hash::Hash, - instruction::{AccountMeta, Instruction}, - }, - solana_program_test::*, - solana_sdk::{ - instruction::InstructionError, - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, - transport::TransportError, - }, - spl_stake_pool::{error, id, instruction, state, MINIMUM_RESERVE_LAMPORTS}, -}; - -async fn setup() -> ( - BanksClient, - Keypair, - Hash, - StakePoolAccounts, - Keypair, - Keypair, -) { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let new_pool_fee = Keypair::new(); - let new_manager = Keypair::new(); - create_token_account( - &mut banks_client, - &payer, - &recent_blockhash, - &new_pool_fee, - &stake_pool_accounts.pool_mint.pubkey(), - &new_manager.pubkey(), - ) - .await - .unwrap(); - - ( - banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - new_pool_fee, - new_manager, - ) -} - -#[tokio::test] -async fn test_set_manager() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, new_pool_fee, new_manager) = - setup().await; - - let mut transaction = Transaction::new_with_payer( - &[instruction::set_manager( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - &new_manager.pubkey(), - &new_pool_fee.pubkey(), - )], - Some(&payer.pubkey()), - ); - transaction.sign( - &[&payer, &stake_pool_accounts.manager, &new_manager], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); - - let stake_pool = get_account(&mut banks_client, &stake_pool_accounts.stake_pool.pubkey()).await; - let stake_pool = - try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - - assert_eq!(stake_pool.manager, new_manager.pubkey()); -} - -#[tokio::test] -async fn test_set_manager_by_malicious() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, new_pool_fee, new_manager) = - setup().await; - - let mut transaction = Transaction::new_with_payer( - &[instruction::set_manager( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &new_manager.pubkey(), - &new_manager.pubkey(), - &new_pool_fee.pubkey(), - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &new_manager], recent_blockhash); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = error::StakePoolError::WrongManager as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while malicious try to set manager"), - } -} - -#[tokio::test] -async fn test_set_manager_without_existing_signature() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, new_pool_fee, new_manager) = - setup().await; - - let data = instruction::StakePoolInstruction::SetManager - .try_to_vec() - .unwrap(); - let accounts = vec![ - AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false), - AccountMeta::new_readonly(stake_pool_accounts.manager.pubkey(), false), - AccountMeta::new_readonly(new_manager.pubkey(), true), - AccountMeta::new_readonly(new_pool_fee.pubkey(), false), - ]; - let instruction = Instruction { - program_id: id(), - accounts, - data, - }; - - let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey())); - transaction.sign(&[&payer, &new_manager], recent_blockhash); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = error::StakePoolError::SignatureMissing as u32; - assert_eq!(error_index, program_error); - } - _ => panic!( - "Wrong error occurs while try to set new manager without existing manager signature" - ), - } -} - -#[tokio::test] -async fn test_set_manager_without_new_signature() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, new_pool_fee, new_manager) = - setup().await; - - let data = instruction::StakePoolInstruction::SetManager - .try_to_vec() - .unwrap(); - let accounts = vec![ - AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false), - AccountMeta::new_readonly(stake_pool_accounts.manager.pubkey(), true), - AccountMeta::new_readonly(new_manager.pubkey(), false), - AccountMeta::new_readonly(new_pool_fee.pubkey(), false), - ]; - let instruction = Instruction { - program_id: id(), - accounts, - data, - }; - - let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey())); - transaction.sign(&[&payer, &stake_pool_accounts.manager], recent_blockhash); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = error::StakePoolError::SignatureMissing as u32; - assert_eq!(error_index, program_error); - } - _ => { - panic!("Wrong error occurs while try to set new manager without new manager signature") - } - } -} - -#[tokio::test] -async fn test_set_manager_with_wrong_mint_for_pool_fee_acc() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let new_mint = Keypair::new(); - let new_withdraw_auth = Keypair::new(); - let new_pool_fee = Keypair::new(); - let new_manager = Keypair::new(); - - create_mint( - &mut banks_client, - &payer, - &recent_blockhash, - &new_mint, - &new_withdraw_auth.pubkey(), - ) - .await - .unwrap(); - create_token_account( - &mut banks_client, - &payer, - &recent_blockhash, - &new_pool_fee, - &new_mint.pubkey(), - &new_manager.pubkey(), - ) - .await - .unwrap(); - - let mut transaction = Transaction::new_with_payer( - &[instruction::set_manager( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - &new_manager.pubkey(), - &new_pool_fee.pubkey(), - )], - Some(&payer.pubkey()), - ); - transaction.sign( - &[&payer, &stake_pool_accounts.manager, &new_manager], - recent_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = error::StakePoolError::WrongAccountMint as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while try to set new manager with wrong mint"), - } -} diff --git a/stake-pool/program/tests/set_preferred.rs b/stake-pool/program/tests/set_preferred.rs deleted file mode 100644 index 10b11a81c0f..00000000000 --- a/stake-pool/program/tests/set_preferred.rs +++ /dev/null @@ -1,265 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod helpers; - -use { - helpers::*, - solana_program::hash::Hash, - solana_program_test::*, - solana_sdk::{ - borsh::try_from_slice_unchecked, - instruction::InstructionError, - pubkey::Pubkey, - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, - }, - spl_stake_pool::{ - error, find_transient_stake_program_address, id, - instruction::{self, PreferredValidatorType}, - state::StakePool, - MINIMUM_RESERVE_LAMPORTS, - }, -}; - -async fn setup() -> ( - BanksClient, - Keypair, - Hash, - StakePoolAccounts, - ValidatorStakeAccount, -) { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let validator_stake_account = simple_add_validator_to_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - ) - .await; - - ( - banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake_account, - ) -} - -#[tokio::test] -async fn success_deposit() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, validator_stake_account) = - setup().await; - - let vote_account_address = validator_stake_account.vote.pubkey(); - let error = stake_pool_accounts - .set_preferred_validator( - &mut banks_client, - &payer, - &recent_blockhash, - PreferredValidatorType::Deposit, - Some(vote_account_address), - ) - .await; - assert!(error.is_none()); - - let stake_pool = get_account(&mut banks_client, &stake_pool_accounts.stake_pool.pubkey()).await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - - assert_eq!( - stake_pool.preferred_deposit_validator_vote_address, - Some(vote_account_address) - ); - assert_eq!(stake_pool.preferred_withdraw_validator_vote_address, None); -} - -#[tokio::test] -async fn success_withdraw() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, validator_stake_account) = - setup().await; - - let vote_account_address = validator_stake_account.vote.pubkey(); - - let error = stake_pool_accounts - .set_preferred_validator( - &mut banks_client, - &payer, - &recent_blockhash, - PreferredValidatorType::Withdraw, - Some(vote_account_address), - ) - .await; - assert!(error.is_none()); - - let stake_pool = get_account(&mut banks_client, &stake_pool_accounts.stake_pool.pubkey()).await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - - assert_eq!(stake_pool.preferred_deposit_validator_vote_address, None); - assert_eq!( - stake_pool.preferred_withdraw_validator_vote_address, - Some(vote_account_address) - ); -} - -#[tokio::test] -async fn success_unset() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, validator_stake_account) = - setup().await; - - let vote_account_address = validator_stake_account.vote.pubkey(); - let error = stake_pool_accounts - .set_preferred_validator( - &mut banks_client, - &payer, - &recent_blockhash, - PreferredValidatorType::Withdraw, - Some(vote_account_address), - ) - .await; - assert!(error.is_none()); - - let stake_pool = get_account(&mut banks_client, &stake_pool_accounts.stake_pool.pubkey()).await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - - assert_eq!( - stake_pool.preferred_withdraw_validator_vote_address, - Some(vote_account_address) - ); - - let error = stake_pool_accounts - .set_preferred_validator( - &mut banks_client, - &payer, - &recent_blockhash, - PreferredValidatorType::Withdraw, - None, - ) - .await; - assert!(error.is_none()); - - let stake_pool = get_account(&mut banks_client, &stake_pool_accounts.stake_pool.pubkey()).await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - - assert_eq!(stake_pool.preferred_withdraw_validator_vote_address, None); -} - -#[tokio::test] -async fn fail_wrong_staker() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, _) = setup().await; - - let wrong_staker = Keypair::new(); - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_preferred_validator( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &wrong_staker.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - PreferredValidatorType::Withdraw, - None, - )], - Some(&payer.pubkey()), - &[&payer, &wrong_staker], - recent_blockhash, - ); - let error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = error::StakePoolError::WrongStaker as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while malicious try to set manager"), - } -} - -#[tokio::test] -async fn fail_not_present_validator() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, _) = setup().await; - - let validator_vote_address = Pubkey::new_unique(); - let error = stake_pool_accounts - .set_preferred_validator( - &mut banks_client, - &payer, - &recent_blockhash, - PreferredValidatorType::Withdraw, - Some(validator_vote_address), - ) - .await - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = error::StakePoolError::ValidatorNotFound as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while malicious try to set manager"), - } -} - -#[tokio::test] -async fn fail_ready_for_removal() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, validator_stake_account) = - setup().await; - let validator_vote_address = validator_stake_account.vote.pubkey(); - - // Mark validator as ready for removal - let transient_stake_seed = 0; - let (transient_stake_address, _) = find_transient_stake_program_address( - &id(), - &validator_vote_address, - &stake_pool_accounts.stake_pool.pubkey(), - transient_stake_seed, - ); - let new_authority = Pubkey::new_unique(); - let destination_stake = Keypair::new(); - let remove_err = stake_pool_accounts - .remove_validator_from_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &new_authority, - &validator_stake_account.stake_account, - &transient_stake_address, - &destination_stake, - ) - .await; - assert!(remove_err.is_none()); - - let error = stake_pool_accounts - .set_preferred_validator( - &mut banks_client, - &payer, - &recent_blockhash, - PreferredValidatorType::Withdraw, - Some(validator_vote_address), - ) - .await - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = error::StakePoolError::InvalidPreferredValidator as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while trying to set ReadyForRemoval validator"), - } -} diff --git a/stake-pool/program/tests/set_referral_fee.rs b/stake-pool/program/tests/set_referral_fee.rs deleted file mode 100644 index cdc93fb9d60..00000000000 --- a/stake-pool/program/tests/set_referral_fee.rs +++ /dev/null @@ -1,262 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod helpers; - -use { - helpers::*, - solana_program_test::*, - solana_sdk::{ - borsh::try_from_slice_unchecked, - instruction::InstructionError, - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, - }, - spl_stake_pool::{ - error, id, instruction, - state::{FeeType, StakePool}, - MINIMUM_RESERVE_LAMPORTS, - }, -}; - -async fn setup(fee: Option) -> (ProgramTestContext, StakePoolAccounts, u8) { - let mut context = program_test().start_with_context().await; - let mut stake_pool_accounts = StakePoolAccounts::new(); - if let Some(fee) = fee { - stake_pool_accounts.referral_fee = fee; - } - stake_pool_accounts - .initialize_stake_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - let new_referral_fee = 15u8; - - (context, stake_pool_accounts, new_referral_fee) -} - -#[tokio::test] -async fn success_stake() { - let (mut context, stake_pool_accounts, new_referral_fee) = setup(None).await; - - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::StakeReferral(new_referral_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - assert_eq!(stake_pool.stake_referral_fee, new_referral_fee); -} - -#[tokio::test] -async fn success_stake_increase_fee_from_0() { - let (mut context, stake_pool_accounts, _) = setup(Some(0u8)).await; - let new_referral_fee = 30u8; - - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::StakeReferral(new_referral_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - assert_eq!(stake_pool.stake_referral_fee, new_referral_fee); -} - -#[tokio::test] -async fn fail_stake_wrong_manager() { - let (mut context, stake_pool_accounts, new_referral_fee) = setup(None).await; - - let wrong_manager = Keypair::new(); - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &wrong_manager.pubkey(), - FeeType::StakeReferral(new_referral_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &wrong_manager], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = error::StakePoolError::WrongManager as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while signing with the wrong manager"), - } -} - -#[tokio::test] -async fn fail_stake_high_referral_fee() { - let (mut context, stake_pool_accounts, _new_referral_fee) = setup(None).await; - - let new_referral_fee = 110u8; - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::StakeReferral(new_referral_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = error::StakePoolError::FeeTooHigh as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs when setting fee too high"), - } -} - -#[tokio::test] -async fn success_sol() { - let (mut context, stake_pool_accounts, new_referral_fee) = setup(None).await; - - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::SolReferral(new_referral_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - assert_eq!(stake_pool.sol_referral_fee, new_referral_fee); -} - -#[tokio::test] -async fn fail_sol_wrong_manager() { - let (mut context, stake_pool_accounts, new_referral_fee) = setup(None).await; - - let wrong_manager = Keypair::new(); - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &wrong_manager.pubkey(), - FeeType::SolReferral(new_referral_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &wrong_manager], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = error::StakePoolError::WrongManager as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while signing with the wrong manager"), - } -} - -#[tokio::test] -async fn fail_sol_high_referral_fee() { - let (mut context, stake_pool_accounts, _new_referral_fee) = setup(None).await; - - let new_referral_fee = 110u8; - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::SolReferral(new_referral_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = error::StakePoolError::FeeTooHigh as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs when setting fee too high"), - } -} diff --git a/stake-pool/program/tests/set_staker.rs b/stake-pool/program/tests/set_staker.rs deleted file mode 100644 index 49efad607cd..00000000000 --- a/stake-pool/program/tests/set_staker.rs +++ /dev/null @@ -1,187 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod helpers; - -use { - borsh::BorshSerialize, - helpers::*, - solana_program::{ - borsh::try_from_slice_unchecked, - hash::Hash, - instruction::{AccountMeta, Instruction}, - }, - solana_program_test::*, - solana_sdk::{ - instruction::InstructionError, - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, - transport::TransportError, - }, - spl_stake_pool::{error, id, instruction, state, MINIMUM_RESERVE_LAMPORTS}, -}; - -async fn setup() -> (BanksClient, Keypair, Hash, StakePoolAccounts, Keypair) { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let new_staker = Keypair::new(); - - ( - banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - new_staker, - ) -} - -#[tokio::test] -async fn success_set_staker_as_manager() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, new_staker) = - setup().await; - - let mut transaction = Transaction::new_with_payer( - &[instruction::set_staker( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - &new_staker.pubkey(), - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &stake_pool_accounts.manager], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - let stake_pool = get_account(&mut banks_client, &stake_pool_accounts.stake_pool.pubkey()).await; - let stake_pool = - try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - - assert_eq!(stake_pool.staker, new_staker.pubkey()); -} - -#[tokio::test] -async fn success_set_staker_as_staker() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, new_staker) = - setup().await; - - let mut transaction = Transaction::new_with_payer( - &[instruction::set_staker( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.staker.pubkey(), - &new_staker.pubkey(), - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &stake_pool_accounts.staker], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - let stake_pool = get_account(&mut banks_client, &stake_pool_accounts.stake_pool.pubkey()).await; - let stake_pool = - try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - - assert_eq!(stake_pool.staker, new_staker.pubkey()); - - let mut transaction = Transaction::new_with_payer( - &[instruction::set_staker( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &new_staker.pubkey(), - &stake_pool_accounts.staker.pubkey(), - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &new_staker], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - let stake_pool = get_account(&mut banks_client, &stake_pool_accounts.stake_pool.pubkey()).await; - let stake_pool = - try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - - assert_eq!(stake_pool.staker, stake_pool_accounts.staker.pubkey()); -} - -#[tokio::test] -async fn fail_wrong_manager() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, new_staker) = - setup().await; - - let mut transaction = Transaction::new_with_payer( - &[instruction::set_staker( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &new_staker.pubkey(), - &new_staker.pubkey(), - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &new_staker], recent_blockhash); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = error::StakePoolError::SignatureMissing as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while malicious try to set manager"), - } -} - -#[tokio::test] -async fn fail_set_staker_without_signature() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, new_staker) = - setup().await; - - let data = instruction::StakePoolInstruction::SetStaker - .try_to_vec() - .unwrap(); - let accounts = vec![ - AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false), - AccountMeta::new_readonly(stake_pool_accounts.manager.pubkey(), false), - AccountMeta::new_readonly(new_staker.pubkey(), false), - ]; - let instruction = Instruction { - program_id: id(), - accounts, - data, - }; - - let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = error::StakePoolError::SignatureMissing as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while try to set new manager without signature"), - } -} diff --git a/stake-pool/program/tests/set_withdrawal_fee.rs b/stake-pool/program/tests/set_withdrawal_fee.rs deleted file mode 100644 index 1b2d48ae9ec..00000000000 --- a/stake-pool/program/tests/set_withdrawal_fee.rs +++ /dev/null @@ -1,669 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod helpers; - -use { - helpers::*, - solana_program_test::*, - solana_sdk::{ - borsh::try_from_slice_unchecked, - instruction::InstructionError, - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, - }, - spl_stake_pool::{ - error, id, instruction, - state::{Fee, FeeType, StakePool}, - MINIMUM_RESERVE_LAMPORTS, - }, -}; - -async fn setup(fee: Option) -> (ProgramTestContext, StakePoolAccounts, Fee) { - let mut context = program_test().start_with_context().await; - let mut stake_pool_accounts = StakePoolAccounts::new(); - if let Some(fee) = fee { - stake_pool_accounts.withdrawal_fee = fee; - } - stake_pool_accounts - .initialize_stake_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - let new_withdrawal_fee = Fee { - numerator: 4, - denominator: 1000, - }; - - (context, stake_pool_accounts, new_withdrawal_fee) -} - -#[tokio::test] -async fn success() { - let (mut context, stake_pool_accounts, new_withdrawal_fee) = setup(None).await; - - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - let old_stake_withdrawal_fee = stake_pool.stake_withdrawal_fee; - let old_sol_withdrawal_fee = stake_pool.sol_withdrawal_fee; - - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::StakeWithdrawal(new_withdrawal_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::SolWithdrawal(new_withdrawal_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - - assert_eq!(stake_pool.stake_withdrawal_fee, old_stake_withdrawal_fee); - assert_eq!( - stake_pool.next_stake_withdrawal_fee, - Some(new_withdrawal_fee) - ); - assert_eq!(stake_pool.sol_withdrawal_fee, old_sol_withdrawal_fee); - assert_eq!(stake_pool.next_sol_withdrawal_fee, Some(new_withdrawal_fee)); - - let first_normal_slot = context.genesis_config().epoch_schedule.first_normal_slot; - let slots_per_epoch = context.genesis_config().epoch_schedule.slots_per_epoch; - - context - .warp_to_slot(first_normal_slot + slots_per_epoch) - .unwrap(); - stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &[], - false, - ) - .await; - - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - assert_eq!(stake_pool.stake_withdrawal_fee, new_withdrawal_fee); - assert_eq!(stake_pool.next_stake_withdrawal_fee, None); - assert_eq!(stake_pool.sol_withdrawal_fee, new_withdrawal_fee); - assert_eq!(stake_pool.next_sol_withdrawal_fee, None); -} - -#[tokio::test] -async fn success_fee_cannot_increase_more_than_once() { - let (mut context, stake_pool_accounts, new_withdrawal_fee) = setup(None).await; - - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - let old_stake_withdrawal_fee = stake_pool.stake_withdrawal_fee; - let old_sol_withdrawal_fee = stake_pool.sol_withdrawal_fee; - - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::StakeWithdrawal(new_withdrawal_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::SolWithdrawal(new_withdrawal_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - - assert_eq!(stake_pool.stake_withdrawal_fee, old_stake_withdrawal_fee); - assert_eq!( - stake_pool.next_stake_withdrawal_fee, - Some(new_withdrawal_fee) - ); - assert_eq!(stake_pool.sol_withdrawal_fee, old_sol_withdrawal_fee); - assert_eq!(stake_pool.next_sol_withdrawal_fee, Some(new_withdrawal_fee)); - - let first_normal_slot = context.genesis_config().epoch_schedule.first_normal_slot; - let slots_per_epoch = context.genesis_config().epoch_schedule.slots_per_epoch; - - context - .warp_to_slot(first_normal_slot + slots_per_epoch) - .unwrap(); - stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &[], - false, - ) - .await; - - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - assert_eq!(stake_pool.stake_withdrawal_fee, new_withdrawal_fee); - assert_eq!(stake_pool.next_stake_withdrawal_fee, None); - assert_eq!(stake_pool.sol_withdrawal_fee, new_withdrawal_fee); - assert_eq!(stake_pool.next_sol_withdrawal_fee, None); - - // try setting to the old fee in the same epoch - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::StakeWithdrawal(old_stake_withdrawal_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::SolWithdrawal(old_sol_withdrawal_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - assert_eq!(stake_pool.stake_withdrawal_fee, new_withdrawal_fee); - assert_eq!( - stake_pool.next_stake_withdrawal_fee, - Some(old_stake_withdrawal_fee) - ); - assert_eq!(stake_pool.sol_withdrawal_fee, new_withdrawal_fee); - assert_eq!( - stake_pool.next_sol_withdrawal_fee, - Some(old_sol_withdrawal_fee) - ); - - let error = stake_pool_accounts - .update_stake_pool_balance( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - ) - .await; - assert!(error.is_none()); - - // Check that nothing has changed after updating the stake pool - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - assert_eq!(stake_pool.stake_withdrawal_fee, new_withdrawal_fee); - assert_eq!( - stake_pool.next_stake_withdrawal_fee, - Some(old_stake_withdrawal_fee) - ); - assert_eq!(stake_pool.sol_withdrawal_fee, new_withdrawal_fee); - assert_eq!( - stake_pool.next_sol_withdrawal_fee, - Some(old_sol_withdrawal_fee) - ); -} - -#[tokio::test] -async fn success_increase_fee_from_0() { - let (mut context, stake_pool_accounts, _) = setup(Some(Fee { - numerator: 0, - denominator: 1, - })) - .await; - let new_withdrawal_fee = Fee { - numerator: 15, - denominator: 10000, - }; - - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - let old_stake_withdrawal_fee = stake_pool.stake_withdrawal_fee; - let old_sol_withdrawal_fee = stake_pool.sol_withdrawal_fee; - - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::StakeWithdrawal(new_withdrawal_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::SolWithdrawal(new_withdrawal_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - - assert_eq!(stake_pool.stake_withdrawal_fee, old_stake_withdrawal_fee); - assert_eq!( - stake_pool.next_stake_withdrawal_fee, - Some(new_withdrawal_fee) - ); - assert_eq!(stake_pool.sol_withdrawal_fee, old_sol_withdrawal_fee); - assert_eq!(stake_pool.next_sol_withdrawal_fee, Some(new_withdrawal_fee)); - - let first_normal_slot = context.genesis_config().epoch_schedule.first_normal_slot; - let slots_per_epoch = context.genesis_config().epoch_schedule.slots_per_epoch; - - context - .warp_to_slot(first_normal_slot + slots_per_epoch) - .unwrap(); - stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &[], - false, - ) - .await; - - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - assert_eq!(stake_pool.stake_withdrawal_fee, new_withdrawal_fee); - assert_eq!(stake_pool.next_stake_withdrawal_fee, None); - assert_eq!(stake_pool.sol_withdrawal_fee, new_withdrawal_fee); - assert_eq!(stake_pool.next_sol_withdrawal_fee, None); -} - -#[tokio::test] -async fn fail_wrong_manager() { - let (mut context, stake_pool_accounts, new_stake_withdrawal_fee) = setup(None).await; - - let wrong_manager = Keypair::new(); - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &wrong_manager.pubkey(), - FeeType::StakeWithdrawal(new_stake_withdrawal_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &wrong_manager], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = error::StakePoolError::WrongManager as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while signing with the wrong manager"), - } -} - -#[tokio::test] -async fn fail_high_withdrawal_fee() { - let (mut context, stake_pool_accounts, _new_stake_withdrawal_fee) = setup(None).await; - - let new_stake_withdrawal_fee = Fee { - numerator: 11, - denominator: 10, - }; - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::StakeWithdrawal(new_stake_withdrawal_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = error::StakePoolError::FeeTooHigh as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs when setting fee too high"), - } -} - -#[tokio::test] -async fn fail_high_stake_fee_increase() { - let (mut context, stake_pool_accounts, _new_stake_withdrawal_fee) = setup(None).await; - let new_withdrawal_fee = Fee { - numerator: 46, - denominator: 10_000, - }; - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::StakeWithdrawal(new_withdrawal_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = error::StakePoolError::FeeIncreaseTooHigh as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs when increasing fee by too large a factor"), - } -} - -#[tokio::test] -async fn fail_high_sol_fee_increase() { - let (mut context, stake_pool_accounts, _new_stake_withdrawal_fee) = setup(None).await; - let new_withdrawal_fee = Fee { - numerator: 46, - denominator: 10_000, - }; - - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::SolWithdrawal(new_withdrawal_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = error::StakePoolError::FeeIncreaseTooHigh as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs when increasing fee by too large a factor"), - } -} - -#[tokio::test] -async fn fail_high_stake_fee_increase_from_0() { - let (mut context, stake_pool_accounts, _new_stake_withdrawal_fee) = setup(Some(Fee { - numerator: 0, - denominator: 1, - })) - .await; - let new_withdrawal_fee = Fee { - numerator: 16, - denominator: 10_000, - }; - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::StakeWithdrawal(new_withdrawal_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = error::StakePoolError::FeeIncreaseTooHigh as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs when increasing fee by too large a factor"), - } -} - -#[tokio::test] -async fn fail_high_sol_fee_increase_from_0() { - let (mut context, stake_pool_accounts, _new_stake_withdrawal_fee) = setup(Some(Fee { - numerator: 0, - denominator: 1, - })) - .await; - let new_withdrawal_fee = Fee { - numerator: 16, - denominator: 10_000, - }; - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::SolWithdrawal(new_withdrawal_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = error::StakePoolError::FeeIncreaseTooHigh as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs when increasing fee by too large a factor"), - } -} - -#[tokio::test] -async fn fail_not_updated() { - let mut context = program_test().start_with_context().await; - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - let new_stake_withdrawal_fee = Fee { - numerator: 11, - denominator: 100, - }; - - // move forward so an update is required - let first_normal_slot = context.genesis_config().epoch_schedule.first_normal_slot; - let slots_per_epoch = context.genesis_config().epoch_schedule.slots_per_epoch; - context - .warp_to_slot(first_normal_slot + slots_per_epoch) - .unwrap(); - - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_fee( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - FeeType::StakeWithdrawal(new_stake_withdrawal_fee), - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = error::StakePoolError::StakeListAndPoolOutOfDate as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs when stake pool out of date"), - } -} diff --git a/stake-pool/program/tests/update_pool_token_metadata.rs b/stake-pool/program/tests/update_pool_token_metadata.rs deleted file mode 100644 index fd27f806296..00000000000 --- a/stake-pool/program/tests/update_pool_token_metadata.rs +++ /dev/null @@ -1,198 +0,0 @@ -#![cfg(feature = "test-bpf")] -mod helpers; - -use { - helpers::*, - mpl_token_metadata::{ - state::{MAX_NAME_LENGTH, MAX_SYMBOL_LENGTH, MAX_URI_LENGTH}, - utils::puffed_out_string, - }, - solana_program::instruction::InstructionError, - solana_program_test::*, - solana_sdk::{ - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, - }, - spl_stake_pool::{ - error::StakePoolError::{SignatureMissing, WrongManager}, - instruction, MINIMUM_RESERVE_LAMPORTS, - }, -}; - -async fn setup() -> (ProgramTestContext, StakePoolAccounts) { - let mut context = program_test_with_metadata_program() - .start_with_context() - .await; - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let name = "test_name"; - let symbol = "SYM"; - let uri = "test_uri"; - - let ix = instruction::create_token_metadata( - &spl_stake_pool::id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &context.payer.pubkey(), - name.to_string(), - symbol.to_string(), - uri.to_string(), - ); - - let transaction = Transaction::new_signed_with_payer( - &[ix], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - (context, stake_pool_accounts) -} - -#[tokio::test] -async fn success_update_pool_token_metadata() { - let (mut context, stake_pool_accounts) = setup().await; - - let updated_name = "updated_name"; - let updated_symbol = "USYM"; - let updated_uri = "updated_uri"; - - let puffed_name = puffed_out_string(&updated_name, MAX_NAME_LENGTH); - let puffed_symbol = puffed_out_string(&updated_symbol, MAX_SYMBOL_LENGTH); - let puffed_uri = puffed_out_string(&updated_uri, MAX_URI_LENGTH); - - let ix = instruction::update_token_metadata( - &spl_stake_pool::id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - updated_name.to_string(), - updated_symbol.to_string(), - updated_uri.to_string(), - ); - - let transaction = Transaction::new_signed_with_payer( - &[ix], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let metadata = get_metadata_account( - &mut context.banks_client, - &stake_pool_accounts.pool_mint.pubkey(), - ) - .await; - - assert_eq!(metadata.data.name.to_string(), puffed_name); - assert_eq!(metadata.data.symbol.to_string(), puffed_symbol); - assert_eq!(metadata.data.uri.to_string(), puffed_uri); -} - -#[tokio::test] -async fn fail_manager_did_not_sign() { - let (mut context, stake_pool_accounts) = setup().await; - - let updated_name = "updated_name"; - let updated_symbol = "USYM"; - let updated_uri = "updated_uri"; - - let mut ix = instruction::update_token_metadata( - &spl_stake_pool::id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - updated_name.to_string(), - updated_symbol.to_string(), - updated_uri.to_string(), - ); - ix.accounts[1].is_signer = false; - - let transaction = Transaction::new_signed_with_payer( - &[ix], - Some(&context.payer.pubkey()), - &[&context.payer], - context.last_blockhash, - ); - - let error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = SignatureMissing as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while manager signature missing"), - } -} - -#[tokio::test] -async fn fail_wrong_manager_signed() { - let (mut context, stake_pool_accounts) = setup().await; - - let updated_name = "updated_name"; - let updated_symbol = "USYM"; - let updated_uri = "updated_uri"; - - let random_keypair = Keypair::new(); - let ix = instruction::update_token_metadata( - &spl_stake_pool::id(), - &stake_pool_accounts.stake_pool.pubkey(), - &random_keypair.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - updated_name.to_string(), - updated_symbol.to_string(), - updated_uri.to_string(), - ); - - let transaction = Transaction::new_signed_with_payer( - &[ix], - Some(&context.payer.pubkey()), - &[&context.payer, &random_keypair], - context.last_blockhash, - ); - - let error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - let program_error = WrongManager as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while signing with the wrong manager"), - } -} diff --git a/stake-pool/program/tests/update_stake_pool_balance.rs b/stake-pool/program/tests/update_stake_pool_balance.rs deleted file mode 100644 index 3b415c0a300..00000000000 --- a/stake-pool/program/tests/update_stake_pool_balance.rs +++ /dev/null @@ -1,361 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod helpers; - -use { - helpers::*, - solana_program::{ - borsh::try_from_slice_unchecked, instruction::InstructionError, pubkey::Pubkey, - }, - solana_program_test::*, - solana_sdk::{ - signature::{Keypair, Signer}, - transaction::TransactionError, - }, - spl_stake_pool::{error::StakePoolError, state::StakePool, MINIMUM_RESERVE_LAMPORTS}, -}; - -async fn setup() -> ( - ProgramTestContext, - StakePoolAccounts, - Vec, -) { - let mut context = program_test().start_with_context().await; - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - // Add several accounts - let mut stake_accounts: Vec = vec![]; - const STAKE_ACCOUNTS: u64 = 3; - for _ in 0..STAKE_ACCOUNTS { - let validator_stake_account = simple_add_validator_to_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_pool_accounts, - ) - .await; - - let _deposit_info = simple_deposit_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_pool_accounts, - &validator_stake_account, - TEST_STAKE_AMOUNT, - ) - .await - .unwrap(); - - stake_accounts.push(validator_stake_account); - } - - (context, stake_pool_accounts, stake_accounts) -} - -#[tokio::test] -async fn success() { - let (mut context, stake_pool_accounts, stake_accounts) = setup().await; - - let pre_fee = get_token_balance( - &mut context.banks_client, - &stake_pool_accounts.pool_fee_account.pubkey(), - ) - .await; - - let pre_balance = get_validator_list_sum( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - assert_eq!(pre_balance, stake_pool.total_lamports); - - let pre_token_supply = get_token_supply( - &mut context.banks_client, - &stake_pool_accounts.pool_mint.pubkey(), - ) - .await; - - let error = stake_pool_accounts - .update_stake_pool_balance( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - ) - .await; - assert!(error.is_none()); - - // Increment vote credits to earn rewards - const VOTE_CREDITS: u64 = 1_000; - for stake_account in &stake_accounts { - context.increment_vote_account_credits(&stake_account.vote.pubkey(), VOTE_CREDITS); - } - - // Update epoch - let first_normal_slot = context.genesis_config().epoch_schedule.first_normal_slot; - let slots_per_epoch = context.genesis_config().epoch_schedule.slots_per_epoch; - context - .warp_to_slot(first_normal_slot + slots_per_epoch) - .unwrap(); - - // Update list and pool - let error = stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - stake_accounts - .iter() - .map(|v| v.vote.pubkey()) - .collect::>() - .as_slice(), - false, - ) - .await; - assert!(error.is_none()); - - // Check fee - let post_balance = get_validator_list_sum( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - assert_eq!(post_balance, stake_pool.total_lamports); - - let post_fee = get_token_balance( - &mut context.banks_client, - &stake_pool_accounts.pool_fee_account.pubkey(), - ) - .await; - let pool_token_supply = get_token_supply( - &mut context.banks_client, - &stake_pool_accounts.pool_mint.pubkey(), - ) - .await; - let actual_fee = post_fee - pre_fee; - assert_eq!(pool_token_supply - pre_token_supply, actual_fee); - - let expected_fee_lamports = (post_balance - pre_balance) * stake_pool.epoch_fee.numerator - / stake_pool.epoch_fee.denominator; - let actual_fee_lamports = stake_pool.calc_pool_tokens_for_deposit(actual_fee).unwrap(); - assert_eq!(actual_fee_lamports, expected_fee_lamports); - - let expected_fee = expected_fee_lamports * pool_token_supply / post_balance; - assert_eq!(expected_fee, actual_fee); - - assert_eq!(pool_token_supply, stake_pool.pool_token_supply); - assert_eq!(pre_token_supply, stake_pool.last_epoch_pool_token_supply); - assert_eq!(pre_balance, stake_pool.last_epoch_total_lamports); -} - -#[tokio::test] -async fn success_ignoring_extra_lamports() { - let (mut context, stake_pool_accounts, stake_accounts) = setup().await; - - let pre_balance = get_validator_list_sum( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - assert_eq!(pre_balance, stake_pool.total_lamports); - - let pre_token_supply = get_token_supply( - &mut context.banks_client, - &stake_pool_accounts.pool_mint.pubkey(), - ) - .await; - - let error = stake_pool_accounts - .update_stake_pool_balance( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - ) - .await; - assert!(error.is_none()); - - // Transfer extra funds, should not be taken into account - const EXTRA_STAKE_AMOUNT: u64 = 1_000_000; - for stake_account in &stake_accounts { - transfer( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_account.stake_account, - EXTRA_STAKE_AMOUNT, - ) - .await; - } - - // Update epoch - let first_normal_slot = context.genesis_config().epoch_schedule.first_normal_slot; - let slots_per_epoch = context.genesis_config().epoch_schedule.slots_per_epoch; - context - .warp_to_slot(first_normal_slot + slots_per_epoch) - .unwrap(); - - // Update list and pool - let error = stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - stake_accounts - .iter() - .map(|v| v.vote.pubkey()) - .collect::>() - .as_slice(), - false, - ) - .await; - assert!(error.is_none()); - - // Check fee - let post_balance = get_validator_list_sum( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - assert_eq!(post_balance, pre_balance); - let pool_token_supply = get_token_supply( - &mut context.banks_client, - &stake_pool_accounts.pool_mint.pubkey(), - ) - .await; - assert_eq!(pool_token_supply, pre_token_supply); -} - -#[tokio::test] -async fn fail_with_wrong_validator_list() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let mut stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let wrong_validator_list = Keypair::new(); - stake_pool_accounts.validator_list = wrong_validator_list; - let error = stake_pool_accounts - .update_stake_pool_balance(&mut banks_client, &payer, &recent_blockhash) - .await - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - ) => { - let program_error = StakePoolError::InvalidValidatorStakeList as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while try to update pool balance with wrong validator stake list account"), - } -} - -#[tokio::test] -async fn fail_with_wrong_pool_fee_account() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let mut stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let wrong_fee_account = Keypair::new(); - stake_pool_accounts.pool_fee_account = wrong_fee_account; - let error = stake_pool_accounts - .update_stake_pool_balance(&mut banks_client, &payer, &recent_blockhash) - .await - .unwrap() - .unwrap(); - - match error { - TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - ) => { - let program_error = StakePoolError::InvalidFeeAccount as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while try to update pool balance with wrong validator stake list account"), - } -} - -#[tokio::test] -async fn fail_with_wrong_reserve() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let mut stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let wrong_reserve_stake = Keypair::new(); - stake_pool_accounts.reserve_stake = wrong_reserve_stake; - let error = stake_pool_accounts - .update_stake_pool_balance(&mut banks_client, &payer, &recent_blockhash) - .await - .unwrap() - .unwrap(); - - assert_eq!( - error, - TransactionError::InstructionError( - 0, - InstructionError::Custom(StakePoolError::InvalidProgramAddress as u32), - ) - ); -} - -#[tokio::test] -async fn test_update_stake_pool_balance_with_uninitialized_validator_list() {} // TODO - -#[tokio::test] -async fn test_update_stake_pool_balance_with_out_of_dated_validators_balances() {} // TODO diff --git a/stake-pool/program/tests/update_validator_list_balance.rs b/stake-pool/program/tests/update_validator_list_balance.rs deleted file mode 100644 index 21ba0f3df92..00000000000 --- a/stake-pool/program/tests/update_validator_list_balance.rs +++ /dev/null @@ -1,838 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod helpers; - -use { - helpers::*, - solana_program::{borsh::try_from_slice_unchecked, program_pack::Pack, pubkey::Pubkey, stake}, - solana_program_test::*, - solana_sdk::{ - signature::{Keypair, Signer}, - stake::state::{Authorized, Lockup, StakeState}, - system_instruction, - transaction::Transaction, - }, - spl_stake_pool::{ - find_transient_stake_program_address, find_withdraw_authority_program_address, id, - instruction, - state::{StakePool, StakeStatus, ValidatorList}, - MAX_VALIDATORS_TO_UPDATE, MINIMUM_ACTIVE_STAKE, MINIMUM_RESERVE_LAMPORTS, - }, - spl_token::state::Mint, -}; - -async fn setup( - num_validators: usize, -) -> ( - ProgramTestContext, - StakePoolAccounts, - Vec, - Vec, - u64, - u64, - u64, -) { - let mut context = program_test().start_with_context().await; - let first_normal_slot = context.genesis_config().epoch_schedule.first_normal_slot; - let slots_per_epoch = context.genesis_config().epoch_schedule.slots_per_epoch; - let mut slot = first_normal_slot; - context.warp_to_slot(slot).unwrap(); - - let reserve_stake_amount = TEST_STAKE_AMOUNT * num_validators as u64; - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - reserve_stake_amount + MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - // Add several accounts with some stake - let mut stake_accounts: Vec = vec![]; - let mut deposit_accounts: Vec = vec![]; - for _ in 0..num_validators { - let stake_account = - ValidatorStakeAccount::new(&stake_pool_accounts.stake_pool.pubkey(), u64::MAX); - create_vote( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_account.validator, - &stake_account.vote, - ) - .await; - - let error = stake_pool_accounts - .add_validator_to_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_account.stake_account, - &stake_account.vote.pubkey(), - ) - .await; - assert!(error.is_none()); - - let deposit_account = DepositStakeAccount::new_with_vote( - stake_account.vote.pubkey(), - stake_account.stake_account, - TEST_STAKE_AMOUNT, - ); - deposit_account - .create_and_delegate( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - ) - .await; - - stake_accounts.push(stake_account); - deposit_accounts.push(deposit_account); - } - - // Warp forward so the stakes properly activate, and deposit - slot += slots_per_epoch; - context.warp_to_slot(slot).unwrap(); - - stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - stake_accounts - .iter() - .map(|v| v.vote.pubkey()) - .collect::>() - .as_slice(), - false, - ) - .await; - - for deposit_account in &mut deposit_accounts { - deposit_account - .deposit_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_pool_accounts, - ) - .await; - } - - slot += slots_per_epoch; - context.warp_to_slot(slot).unwrap(); - - stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - stake_accounts - .iter() - .map(|v| v.vote.pubkey()) - .collect::>() - .as_slice(), - false, - ) - .await; - - ( - context, - stake_pool_accounts, - stake_accounts, - deposit_accounts, - TEST_STAKE_AMOUNT, - reserve_stake_amount, - slot, - ) -} - -#[tokio::test] -async fn success() { - let num_validators = 5; - let ( - mut context, - stake_pool_accounts, - stake_accounts, - _, - validator_lamports, - reserve_lamports, - mut slot, - ) = setup(num_validators).await; - - // Check current balance in the list - let rent = context.banks_client.get_rent().await.unwrap(); - let stake_rent = rent.minimum_balance(std::mem::size_of::()); - // initially, have all of the deposits plus their rent, and the reserve stake - let initial_lamports = - (validator_lamports + stake_rent) * num_validators as u64 + reserve_lamports; - assert_eq!( - get_validator_list_sum( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.validator_list.pubkey() - ) - .await, - initial_lamports, - ); - - // Simulate rewards - for stake_account in &stake_accounts { - context.increment_vote_account_credits(&stake_account.vote.pubkey(), 100); - } - - // Warp one more epoch so the rewards are paid out - let slots_per_epoch = context.genesis_config().epoch_schedule.slots_per_epoch; - slot += slots_per_epoch; - context.warp_to_slot(slot).unwrap(); - - stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - stake_accounts - .iter() - .map(|v| v.vote.pubkey()) - .collect::>() - .as_slice(), - false, - ) - .await; - let new_lamports = get_validator_list_sum( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - assert!(new_lamports > initial_lamports); - - let stake_pool_info = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(&stake_pool_info.data).unwrap(); - assert_eq!(new_lamports, stake_pool.total_lamports); -} - -#[tokio::test] -async fn merge_into_reserve() { - let (mut context, stake_pool_accounts, stake_accounts, _, lamports, _, mut slot) = - setup(MAX_VALIDATORS_TO_UPDATE).await; - - let pre_lamports = get_validator_list_sum( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - - let reserve_stake = context - .banks_client - .get_account(stake_pool_accounts.reserve_stake.pubkey()) - .await - .unwrap() - .unwrap(); - let pre_reserve_lamports = reserve_stake.lamports; - - println!("Decrease from all validators"); - for stake_account in &stake_accounts { - let error = stake_pool_accounts - .decrease_validator_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_account.stake_account, - &stake_account.transient_stake_account, - lamports, - stake_account.transient_stake_seed, - ) - .await; - assert!(error.is_none()); - } - - println!("Update, should not change, no merges yet"); - stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - stake_accounts - .iter() - .map(|v| v.vote.pubkey()) - .collect::>() - .as_slice(), - false, - ) - .await; - - let expected_lamports = get_validator_list_sum( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - assert_eq!(pre_lamports, expected_lamports); - - let stake_pool_info = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(&stake_pool_info.data).unwrap(); - assert_eq!(expected_lamports, stake_pool.total_lamports); - - println!("Warp one more epoch so the stakes deactivate"); - let slots_per_epoch = context.genesis_config().epoch_schedule.slots_per_epoch; - slot += slots_per_epoch; - context.warp_to_slot(slot).unwrap(); - - stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - stake_accounts - .iter() - .map(|v| v.vote.pubkey()) - .collect::>() - .as_slice(), - false, - ) - .await; - let expected_lamports = get_validator_list_sum( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - assert_eq!(pre_lamports, expected_lamports); - - let reserve_stake = context - .banks_client - .get_account(stake_pool_accounts.reserve_stake.pubkey()) - .await - .unwrap() - .unwrap(); - let post_reserve_lamports = reserve_stake.lamports; - assert!(post_reserve_lamports > pre_reserve_lamports); - - let stake_pool_info = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(&stake_pool_info.data).unwrap(); - assert_eq!(expected_lamports, stake_pool.total_lamports); -} - -#[tokio::test] -async fn merge_into_validator_stake() { - let (mut context, stake_pool_accounts, stake_accounts, _, lamports, reserve_lamports, mut slot) = - setup(MAX_VALIDATORS_TO_UPDATE).await; - - let rent = context.banks_client.get_rent().await.unwrap(); - let pre_lamports = get_validator_list_sum( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - - // Increase stake to all validators - for stake_account in &stake_accounts { - let error = stake_pool_accounts - .increase_validator_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_account.transient_stake_account, - &stake_account.stake_account, - &stake_account.vote.pubkey(), - reserve_lamports / stake_accounts.len() as u64, - stake_account.transient_stake_seed, - ) - .await; - assert!(error.is_none()); - } - - // Warp just a little bit to get a new blockhash and update again - context.warp_to_slot(slot + 10).unwrap(); - - // Update, should not change, no merges yet - let error = stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - stake_accounts - .iter() - .map(|v| v.vote.pubkey()) - .collect::>() - .as_slice(), - false, - ) - .await; - assert!(error.is_none()); - - let expected_lamports = get_validator_list_sum( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - assert_eq!(pre_lamports, expected_lamports); - let stake_pool_info = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(&stake_pool_info.data).unwrap(); - assert_eq!(expected_lamports, stake_pool.total_lamports); - - // Warp one more epoch so the stakes activate, ready to merge - let slots_per_epoch = context.genesis_config().epoch_schedule.slots_per_epoch; - slot += slots_per_epoch; - context.warp_to_slot(slot).unwrap(); - - let error = stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - stake_accounts - .iter() - .map(|v| v.vote.pubkey()) - .collect::>() - .as_slice(), - false, - ) - .await; - assert!(error.is_none()); - let current_lamports = get_validator_list_sum( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let stake_pool_info = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(&stake_pool_info.data).unwrap(); - assert_eq!(current_lamports, stake_pool.total_lamports); - - // Check that transient accounts are gone - for stake_account in &stake_accounts { - assert!(context - .banks_client - .get_account(stake_account.transient_stake_account) - .await - .unwrap() - .is_none()); - } - - // Check validator stake accounts have the expected balance now: - // validator stake account minimum + deposited lamports + rents + increased lamports - let stake_rent = rent.minimum_balance(std::mem::size_of::()); - let expected_lamports = MINIMUM_ACTIVE_STAKE - + lamports - + reserve_lamports / stake_accounts.len() as u64 - + stake_rent; - for stake_account in &stake_accounts { - let validator_stake = - get_account(&mut context.banks_client, &stake_account.stake_account).await; - assert_eq!(validator_stake.lamports, expected_lamports); - } - - // Check reserve stake accounts for expected balance: - // own rent, other account rents, and 1 extra lamport - let reserve_stake = get_account( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - ) - .await; - assert_eq!( - reserve_stake.lamports, - MINIMUM_RESERVE_LAMPORTS + stake_rent * (1 + stake_accounts.len() as u64) - ); -} - -#[tokio::test] -async fn merge_transient_stake_after_remove() { - let (mut context, stake_pool_accounts, stake_accounts, _, lamports, reserve_lamports, mut slot) = - setup(1).await; - - let rent = context.banks_client.get_rent().await.unwrap(); - let stake_rent = rent.minimum_balance(std::mem::size_of::()); - let deactivated_lamports = lamports; - let new_authority = Pubkey::new_unique(); - let destination_stake = Keypair::new(); - // Decrease and remove all validators - for stake_account in &stake_accounts { - let error = stake_pool_accounts - .decrease_validator_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_account.stake_account, - &stake_account.transient_stake_account, - deactivated_lamports, - stake_account.transient_stake_seed, - ) - .await; - assert!(error.is_none()); - let error = stake_pool_accounts - .remove_validator_from_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &new_authority, - &stake_account.stake_account, - &stake_account.transient_stake_account, - &destination_stake, - ) - .await; - assert!(error.is_none()); - } - - // Warp forward to merge time - let slots_per_epoch = context.genesis_config().epoch_schedule.slots_per_epoch; - slot += slots_per_epoch; - context.warp_to_slot(slot).unwrap(); - - // Update without merge, status should be DeactivatingTransient - let error = stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - stake_accounts - .iter() - .map(|v| v.vote.pubkey()) - .collect::>() - .as_slice(), - true, - ) - .await; - assert!(error.is_none()); - - let validator_list = get_account( - &mut context.banks_client, - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let validator_list = - try_from_slice_unchecked::(validator_list.data.as_slice()).unwrap(); - assert_eq!(validator_list.validators.len(), 1); - assert_eq!( - validator_list.validators[0].status, - StakeStatus::DeactivatingTransient - ); - assert_eq!(validator_list.validators[0].active_stake_lamports, 0); - assert_eq!( - validator_list.validators[0].transient_stake_lamports, - deactivated_lamports - ); - - // Update with merge, status should be ReadyForRemoval and no lamports - let error = stake_pool_accounts - .update_validator_list_balance( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - stake_accounts - .iter() - .map(|v| v.vote.pubkey()) - .collect::>() - .as_slice(), - false, - ) - .await; - assert!(error.is_none()); - - let validator_list = get_account( - &mut context.banks_client, - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let validator_list = - try_from_slice_unchecked::(validator_list.data.as_slice()).unwrap(); - assert_eq!(validator_list.validators.len(), 1); - assert_eq!( - validator_list.validators[0].status, - StakeStatus::ReadyForRemoval - ); - assert_eq!(validator_list.validators[0].stake_lamports(), 0); - - let reserve_stake = context - .banks_client - .get_account(stake_pool_accounts.reserve_stake.pubkey()) - .await - .unwrap() - .unwrap(); - assert_eq!( - reserve_stake.lamports, - reserve_lamports + deactivated_lamports + 2 * stake_rent + MINIMUM_RESERVE_LAMPORTS - ); - - // Update stake pool balance and cleanup, should be gone - let error = stake_pool_accounts - .update_stake_pool_balance( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - ) - .await; - assert!(error.is_none()); - - let error = stake_pool_accounts - .cleanup_removed_validator_entries( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - ) - .await; - assert!(error.is_none()); - - let validator_list = get_account( - &mut context.banks_client, - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let validator_list = - try_from_slice_unchecked::(validator_list.data.as_slice()).unwrap(); - assert_eq!(validator_list.validators.len(), 0); -} - -#[tokio::test] -async fn success_with_burned_tokens() { - let num_validators = 5; - let (mut context, stake_pool_accounts, stake_accounts, deposit_accounts, _, _, mut slot) = - setup(num_validators).await; - - let mint_info = get_account( - &mut context.banks_client, - &stake_pool_accounts.pool_mint.pubkey(), - ) - .await; - let mint = Mint::unpack(&mint_info.data).unwrap(); - - let stake_pool_info = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(&stake_pool_info.data).unwrap(); - assert_eq!(mint.supply, stake_pool.pool_token_supply); - - burn_tokens( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_pool_accounts.pool_mint.pubkey(), - &deposit_accounts[0].pool_account.pubkey(), - &deposit_accounts[0].authority, - deposit_accounts[0].pool_tokens, - ) - .await - .unwrap(); - - let mint_info = get_account( - &mut context.banks_client, - &stake_pool_accounts.pool_mint.pubkey(), - ) - .await; - let mint = Mint::unpack(&mint_info.data).unwrap(); - assert_ne!(mint.supply, stake_pool.pool_token_supply); - - let slots_per_epoch = context.genesis_config().epoch_schedule.slots_per_epoch; - slot += slots_per_epoch; - context.warp_to_slot(slot).unwrap(); - - stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - stake_accounts - .iter() - .map(|v| v.vote.pubkey()) - .collect::>() - .as_slice(), - false, - ) - .await; - - let stake_pool_info = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(&stake_pool_info.data).unwrap(); - - assert_eq!(mint.supply, stake_pool.pool_token_supply); -} - -#[tokio::test] -async fn success_ignoring_hijacked_transient_stake_with_authorized() { - let hijacker = Pubkey::new_unique(); - check_ignored_hijacked_transient_stake(Some(&Authorized::auto(&hijacker)), None).await; -} - -#[tokio::test] -async fn success_ignoring_hijacked_transient_stake_with_lockup() { - let hijacker = Pubkey::new_unique(); - check_ignored_hijacked_transient_stake( - None, - Some(&Lockup { - custodian: hijacker, - ..Lockup::default() - }), - ) - .await; -} - -async fn check_ignored_hijacked_transient_stake( - hijack_authorized: Option<&Authorized>, - hijack_lockup: Option<&Lockup>, -) { - let num_validators = 1; - let (mut context, stake_pool_accounts, stake_accounts, _, lamports, _, mut slot) = - setup(num_validators).await; - - let rent = context.banks_client.get_rent().await.unwrap(); - let stake_rent = rent.minimum_balance(std::mem::size_of::()); - - let pre_lamports = get_validator_list_sum( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let (withdraw_authority, _) = - find_withdraw_authority_program_address(&id(), &stake_pool_accounts.stake_pool.pubkey()); - - println!("Decrease from all validators"); - let stake_account = &stake_accounts[0]; - let error = stake_pool_accounts - .decrease_validator_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_account.stake_account, - &stake_account.transient_stake_account, - lamports, - stake_account.transient_stake_seed, - ) - .await; - assert!(error.is_none()); - - println!("Warp one epoch so the stakes deactivate and merge"); - let slots_per_epoch = context.genesis_config().epoch_schedule.slots_per_epoch; - slot += slots_per_epoch; - context.warp_to_slot(slot).unwrap(); - - println!("During update, hijack the transient stake account"); - let validator_list = stake_pool_accounts - .get_validator_list(&mut context.banks_client) - .await; - let transient_stake_address = find_transient_stake_program_address( - &id(), - &stake_account.vote.pubkey(), - &stake_pool_accounts.stake_pool.pubkey(), - stake_account.transient_stake_seed, - ) - .0; - let transaction = Transaction::new_signed_with_payer( - &[ - instruction::update_validator_list_balance( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.withdraw_authority, - &stake_pool_accounts.validator_list.pubkey(), - &stake_pool_accounts.reserve_stake.pubkey(), - &validator_list, - &[stake_account.vote.pubkey()], - 0, - /* no_merge = */ false, - ), - system_instruction::transfer( - &context.payer.pubkey(), - &transient_stake_address, - stake_rent + MINIMUM_RESERVE_LAMPORTS, - ), - stake::instruction::initialize( - &transient_stake_address, - hijack_authorized.unwrap_or(&Authorized::auto(&withdraw_authority)), - hijack_lockup.unwrap_or(&Lockup::default()), - ), - instruction::update_stake_pool_balance( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.withdraw_authority, - &stake_pool_accounts.validator_list.pubkey(), - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &spl_token::id(), - ), - instruction::cleanup_removed_validator_entries( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - ), - ], - Some(&context.payer.pubkey()), - &[&context.payer], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err(); - assert!(error.is_none()); - - println!("Update again normally, should be no change in the lamports"); - stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - stake_accounts - .iter() - .map(|v| v.vote.pubkey()) - .collect::>() - .as_slice(), - false, - ) - .await; - - let expected_lamports = get_validator_list_sum( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - assert_eq!(pre_lamports, expected_lamports); - - let stake_pool_info = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(&stake_pool_info.data).unwrap(); - assert_eq!(pre_lamports, stake_pool.total_lamports); -} - -#[tokio::test] -async fn fail_with_uninitialized_validator_list() {} // TODO - -#[tokio::test] -async fn success_with_force_destaked_validator() {} diff --git a/stake-pool/program/tests/vsa_add.rs b/stake-pool/program/tests/vsa_add.rs deleted file mode 100644 index de0c6665ad4..00000000000 --- a/stake-pool/program/tests/vsa_add.rs +++ /dev/null @@ -1,558 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod helpers; - -use { - bincode::deserialize, - borsh::BorshSerialize, - helpers::*, - solana_program::{ - borsh::try_from_slice_unchecked, - hash::Hash, - instruction::{AccountMeta, Instruction, InstructionError}, - pubkey::Pubkey, - stake, system_program, sysvar, - }, - solana_program_test::*, - solana_sdk::{ - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, - transport::TransportError, - }, - spl_stake_pool::{ - error::StakePoolError, find_stake_program_address, id, instruction, state, - MINIMUM_RESERVE_LAMPORTS, - }, -}; - -async fn setup() -> ( - BanksClient, - Keypair, - Hash, - StakePoolAccounts, - ValidatorStakeAccount, -) { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let validator_stake = ValidatorStakeAccount::new(&stake_pool_accounts.stake_pool.pubkey(), 0); - create_vote( - &mut banks_client, - &payer, - &recent_blockhash, - &validator_stake.validator, - &validator_stake.vote, - ) - .await; - - ( - banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake, - ) -} - -#[tokio::test] -async fn success() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, validator_stake) = - setup().await; - - let error = stake_pool_accounts - .add_validator_to_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &validator_stake.stake_account, - &validator_stake.vote.pubkey(), - ) - .await; - assert!(error.is_none()); - - // Check if validator account was added to the list - let validator_list = get_account( - &mut banks_client, - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let validator_list = - try_from_slice_unchecked::(validator_list.data.as_slice()).unwrap(); - assert_eq!( - validator_list, - state::ValidatorList { - header: state::ValidatorListHeader { - account_type: state::AccountType::ValidatorList, - max_validators: stake_pool_accounts.max_validators, - }, - validators: vec![state::ValidatorStakeInfo { - status: state::StakeStatus::Active, - vote_account_address: validator_stake.vote.pubkey(), - last_update_epoch: 0, - active_stake_lamports: 0, - transient_stake_lamports: 0, - transient_seed_suffix_start: 0, - transient_seed_suffix_end: 0, - }] - } - ); - - // Check stake account existence and authority - let stake = get_account(&mut banks_client, &validator_stake.stake_account).await; - let stake_state = deserialize::(&stake.data).unwrap(); - match stake_state { - stake::state::StakeState::Stake(meta, _) => { - assert_eq!( - &meta.authorized.staker, - &stake_pool_accounts.withdraw_authority - ); - assert_eq!( - &meta.authorized.withdrawer, - &stake_pool_accounts.withdraw_authority - ); - } - _ => panic!(), - } -} - -#[tokio::test] -async fn fail_with_wrong_validator_list_account() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, validator_stake) = - setup().await; - - let wrong_validator_list = Keypair::new(); - - let mut transaction = Transaction::new_with_payer( - &[instruction::add_validator_to_pool( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.staker.pubkey(), - &payer.pubkey(), - &stake_pool_accounts.withdraw_authority, - &wrong_validator_list.pubkey(), - &validator_stake.stake_account, - &validator_stake.vote.pubkey(), - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &stake_pool_accounts.staker], recent_blockhash); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = StakePoolError::InvalidValidatorStakeList as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while try to add validator stake address with wrong validator stake list account"), - } -} - -#[tokio::test] -async fn fail_double_add() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, validator_stake) = - setup().await; - - stake_pool_accounts - .add_validator_to_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &validator_stake.stake_account, - &validator_stake.vote.pubkey(), - ) - .await; - - let latest_blockhash = banks_client.get_latest_blockhash().await.unwrap(); - - let transaction_error = stake_pool_accounts - .add_validator_to_pool( - &mut banks_client, - &payer, - &latest_blockhash, - &validator_stake.stake_account, - &validator_stake.vote.pubkey(), - ) - .await - .unwrap(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = StakePoolError::ValidatorAlreadyAdded as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while try to add already added validator stake account"), - } -} - -#[tokio::test] -async fn fail_wrong_staker() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, validator_stake) = - setup().await; - - let malicious = Keypair::new(); - - let mut transaction = Transaction::new_with_payer( - &[instruction::add_validator_to_pool( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &malicious.pubkey(), - &payer.pubkey(), - &stake_pool_accounts.withdraw_authority, - &stake_pool_accounts.validator_list.pubkey(), - &validator_stake.stake_account, - &validator_stake.vote.pubkey(), - )], - Some(&payer.pubkey()), - ); - transaction.sign(&[&payer, &malicious], recent_blockhash); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = StakePoolError::WrongStaker as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while malicious try to add validator stake account"), - } -} - -#[tokio::test] -async fn fail_without_signature() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, validator_stake) = - setup().await; - - let accounts = vec![ - AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false), - AccountMeta::new_readonly(stake_pool_accounts.staker.pubkey(), false), - AccountMeta::new(payer.pubkey(), false), - AccountMeta::new_readonly(stake_pool_accounts.withdraw_authority, false), - AccountMeta::new(stake_pool_accounts.validator_list.pubkey(), false), - AccountMeta::new(validator_stake.stake_account, false), - AccountMeta::new(validator_stake.vote.pubkey(), false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - AccountMeta::new_readonly(sysvar::stake_history::id(), false), - AccountMeta::new_readonly(stake::config::id(), false), - AccountMeta::new_readonly(system_program::id(), false), - AccountMeta::new_readonly(stake::program::id(), false), - ]; - let instruction = Instruction { - program_id: id(), - accounts, - data: instruction::StakePoolInstruction::AddValidatorToPool - .try_to_vec() - .unwrap(), - }; - - let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = StakePoolError::SignatureMissing as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while malicious try to add validator stake account without signing transaction"), - } -} - -#[tokio::test] -async fn fail_with_wrong_stake_program_id() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, validator_stake) = - setup().await; - - let wrong_stake_program = Pubkey::new_unique(); - let accounts = vec![ - AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false), - AccountMeta::new_readonly(stake_pool_accounts.staker.pubkey(), true), - AccountMeta::new(payer.pubkey(), true), - AccountMeta::new_readonly(stake_pool_accounts.withdraw_authority, false), - AccountMeta::new(stake_pool_accounts.validator_list.pubkey(), false), - AccountMeta::new(validator_stake.stake_account, false), - AccountMeta::new(validator_stake.vote.pubkey(), false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - AccountMeta::new_readonly(sysvar::stake_history::id(), false), - AccountMeta::new_readonly(stake::config::id(), false), - AccountMeta::new_readonly(system_program::id(), false), - AccountMeta::new_readonly(wrong_stake_program, false), - ]; - let instruction = Instruction { - program_id: id(), - accounts, - data: instruction::StakePoolInstruction::AddValidatorToPool - .try_to_vec() - .unwrap(), - }; - let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey())); - transaction.sign(&[&payer, &stake_pool_accounts.staker], recent_blockhash); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError(_, error)) => { - assert_eq!(error, InstructionError::IncorrectProgramId); - } - _ => panic!( - "Wrong error occurs while try to add validator stake account with wrong stake program ID" - ), - } -} - -#[tokio::test] -async fn fail_with_wrong_system_program_id() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, validator_stake) = - setup().await; - - let wrong_system_program = Pubkey::new_unique(); - - let accounts = vec![ - AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false), - AccountMeta::new_readonly(stake_pool_accounts.staker.pubkey(), true), - AccountMeta::new(payer.pubkey(), true), - AccountMeta::new_readonly(stake_pool_accounts.withdraw_authority, false), - AccountMeta::new(stake_pool_accounts.validator_list.pubkey(), false), - AccountMeta::new(validator_stake.stake_account, false), - AccountMeta::new(validator_stake.vote.pubkey(), false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - AccountMeta::new_readonly(sysvar::stake_history::id(), false), - AccountMeta::new_readonly(stake::config::id(), false), - AccountMeta::new_readonly(wrong_system_program, false), - AccountMeta::new_readonly(stake::program::id(), false), - ]; - let instruction = Instruction { - program_id: id(), - accounts, - data: instruction::StakePoolInstruction::AddValidatorToPool - .try_to_vec() - .unwrap(), - }; - let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey())); - transaction.sign(&[&payer, &stake_pool_accounts.staker], recent_blockhash); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError(_, error)) => { - assert_eq!(error, InstructionError::IncorrectProgramId); - } - _ => panic!( - "Wrong error occurs while try to add validator stake account with wrong stake program ID" - ), - } -} - -#[tokio::test] -async fn fail_add_too_many_validator_stake_accounts() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let mut stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts.max_validators = 1; - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let validator_stake = ValidatorStakeAccount::new(&stake_pool_accounts.stake_pool.pubkey(), 0); - create_vote( - &mut banks_client, - &payer, - &recent_blockhash, - &validator_stake.validator, - &validator_stake.vote, - ) - .await; - - let error = stake_pool_accounts - .add_validator_to_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &validator_stake.stake_account, - &validator_stake.vote.pubkey(), - ) - .await; - assert!(error.is_none()); - - let validator_stake = ValidatorStakeAccount::new(&stake_pool_accounts.stake_pool.pubkey(), 0); - create_vote( - &mut banks_client, - &payer, - &recent_blockhash, - &validator_stake.validator, - &validator_stake.vote, - ) - .await; - let error = stake_pool_accounts - .add_validator_to_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &validator_stake.stake_account, - &validator_stake.vote.pubkey(), - ) - .await - .unwrap() - .unwrap(); - assert_eq!( - error, - TransactionError::InstructionError(0, InstructionError::AccountDataTooSmall), - ); -} - -#[tokio::test] -async fn fail_with_unupdated_stake_pool() {} // TODO - -#[tokio::test] -async fn fail_with_uninitialized_validator_list_account() {} // TODO - -#[tokio::test] -async fn fail_on_non_vote_account() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, _) = setup().await; - - let validator = Pubkey::new_unique(); - let (stake_account, _) = - find_stake_program_address(&id(), &validator, &stake_pool_accounts.stake_pool.pubkey()); - - let error = stake_pool_accounts - .add_validator_to_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_account, - &validator, - ) - .await - .unwrap() - .unwrap(); - - assert_eq!( - error, - TransactionError::InstructionError(0, InstructionError::IncorrectProgramId,) - ); -} - -#[tokio::test] -async fn fail_on_incorrectly_derived_stake_account() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, validator_stake) = - setup().await; - - let bad_stake_account = Pubkey::new_unique(); - let error = stake_pool_accounts - .add_validator_to_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &bad_stake_account, - &validator_stake.vote.pubkey(), - ) - .await - .unwrap() - .unwrap(); - - assert_eq!( - error, - TransactionError::InstructionError( - 0, - InstructionError::Custom(StakePoolError::InvalidStakeAccountAddress as u32), - ) - ); -} - -#[tokio::test] -async fn success_with_lamports_in_account() { - let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, validator_stake) = - setup().await; - - transfer( - &mut banks_client, - &payer, - &recent_blockhash, - &validator_stake.stake_account, - 1_000_000, - ) - .await; - - let error = stake_pool_accounts - .add_validator_to_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &validator_stake.stake_account, - &validator_stake.vote.pubkey(), - ) - .await; - assert!(error.is_none()); - - // Check stake account existence and authority - let stake = get_account(&mut banks_client, &validator_stake.stake_account).await; - let stake_state = deserialize::(&stake.data).unwrap(); - match stake_state { - stake::state::StakeState::Stake(meta, _) => { - assert_eq!( - &meta.authorized.staker, - &stake_pool_accounts.withdraw_authority - ); - assert_eq!( - &meta.authorized.withdrawer, - &stake_pool_accounts.withdraw_authority - ); - } - _ => panic!(), - } -} diff --git a/stake-pool/program/tests/vsa_remove.rs b/stake-pool/program/tests/vsa_remove.rs deleted file mode 100644 index aec2b98323b..00000000000 --- a/stake-pool/program/tests/vsa_remove.rs +++ /dev/null @@ -1,868 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod helpers; - -use { - bincode::deserialize, - borsh::BorshSerialize, - helpers::*, - solana_program::{ - borsh::try_from_slice_unchecked, - instruction::{AccountMeta, Instruction, InstructionError}, - pubkey::Pubkey, - stake, system_instruction, sysvar, - }, - solana_program_test::*, - solana_sdk::{ - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, - transport::TransportError, - }, - spl_stake_pool::{ - error::StakePoolError, find_transient_stake_program_address, id, instruction, state, - MINIMUM_ACTIVE_STAKE, MINIMUM_RESERVE_LAMPORTS, - }, -}; - -async fn setup() -> ( - ProgramTestContext, - StakePoolAccounts, - ValidatorStakeAccount, - Pubkey, - Keypair, -) { - let mut context = program_test().start_with_context().await; - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - 10_000_000_000 + MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let validator_stake = - ValidatorStakeAccount::new(&stake_pool_accounts.stake_pool.pubkey(), u64::MAX); - create_vote( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &validator_stake.validator, - &validator_stake.vote, - ) - .await; - - let error = stake_pool_accounts - .add_validator_to_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &validator_stake.stake_account, - &validator_stake.vote.pubkey(), - ) - .await; - assert!(error.is_none()); - - let new_authority = Pubkey::new_unique(); - let destination_stake = Keypair::new(); - - ( - context, - stake_pool_accounts, - validator_stake, - new_authority, - destination_stake, - ) -} - -#[tokio::test] -async fn success() { - let (mut context, stake_pool_accounts, validator_stake, new_authority, destination_stake) = - setup().await; - - let error = stake_pool_accounts - .remove_validator_from_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &new_authority, - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - &destination_stake, - ) - .await; - assert!(error.is_none()); - - let error = stake_pool_accounts - .cleanup_removed_validator_entries( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - ) - .await; - assert!(error.is_none()); - - // Check if account was removed from the list of stake accounts - let validator_list = get_account( - &mut context.banks_client, - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let validator_list = - try_from_slice_unchecked::(validator_list.data.as_slice()).unwrap(); - assert_eq!( - validator_list, - state::ValidatorList { - header: state::ValidatorListHeader { - account_type: state::AccountType::ValidatorList, - max_validators: stake_pool_accounts.max_validators, - }, - validators: vec![] - } - ); - - // Check stake account no longer exists - let account = context - .banks_client - .get_account(validator_stake.stake_account) - .await - .unwrap(); - assert!(account.is_none()); - let stake = get_account(&mut context.banks_client, &destination_stake.pubkey()).await; - let stake_state = deserialize::(&stake.data).unwrap(); - match stake_state { - stake::state::StakeState::Stake(meta, _) => { - assert_eq!(&meta.authorized.staker, &new_authority); - assert_eq!(&meta.authorized.withdrawer, &new_authority); - } - _ => panic!(), - } -} - -#[tokio::test] -async fn fail_with_wrong_stake_program_id() { - let (mut context, stake_pool_accounts, validator_stake, new_authority, destination_stake) = - setup().await; - - let wrong_stake_program = Pubkey::new_unique(); - - let accounts = vec![ - AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false), - AccountMeta::new_readonly(stake_pool_accounts.staker.pubkey(), true), - AccountMeta::new_readonly(stake_pool_accounts.withdraw_authority, false), - AccountMeta::new_readonly(new_authority, false), - AccountMeta::new(stake_pool_accounts.validator_list.pubkey(), false), - AccountMeta::new(validator_stake.stake_account, false), - AccountMeta::new_readonly(validator_stake.transient_stake_account, false), - AccountMeta::new(destination_stake.pubkey(), false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - AccountMeta::new_readonly(wrong_stake_program, false), - ]; - let instruction = Instruction { - program_id: id(), - accounts, - data: instruction::StakePoolInstruction::RemoveValidatorFromPool - .try_to_vec() - .unwrap(), - }; - - let mut transaction = - Transaction::new_with_payer(&[instruction], Some(&context.payer.pubkey())); - transaction.sign( - &[&context.payer, &stake_pool_accounts.staker], - context.last_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - error, - )) => { - assert_eq!(error, InstructionError::IncorrectProgramId); - } - _ => panic!("Wrong error occurs while try to remove validator stake address with wrong stake program ID"), - } -} - -#[tokio::test] -async fn fail_with_wrong_validator_list_account() { - let (mut context, stake_pool_accounts, validator_stake, new_authority, destination_stake) = - setup().await; - - let wrong_validator_list = Keypair::new(); - - let mut transaction = Transaction::new_with_payer( - &[instruction::remove_validator_from_pool( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.staker.pubkey(), - &stake_pool_accounts.withdraw_authority, - &new_authority, - &wrong_validator_list.pubkey(), - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - &destination_stake.pubkey(), - )], - Some(&context.payer.pubkey()), - ); - transaction.sign( - &[&context.payer, &stake_pool_accounts.staker], - context.last_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = StakePoolError::InvalidValidatorStakeList as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while try to remove validator stake address with wrong validator stake list account"), - } -} - -#[tokio::test] -async fn fail_not_at_minimum() { - let (mut context, stake_pool_accounts, validator_stake, new_authority, destination_stake) = - setup().await; - - transfer( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &validator_stake.stake_account, - 1_000_001, - ) - .await; - - let error = stake_pool_accounts - .remove_validator_from_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &new_authority, - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - &destination_stake, - ) - .await - .unwrap() - .unwrap(); - assert_eq!( - error, - TransactionError::InstructionError( - 1, - InstructionError::Custom(StakePoolError::StakeLamportsNotEqualToMinimum as u32) - ), - ); -} - -#[tokio::test] -async fn fail_double_remove() { - let (mut context, stake_pool_accounts, validator_stake, new_authority, destination_stake) = - setup().await; - - let error = stake_pool_accounts - .remove_validator_from_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &new_authority, - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - &destination_stake, - ) - .await; - assert!(error.is_none()); - - let error = stake_pool_accounts - .cleanup_removed_validator_entries( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - ) - .await; - assert!(error.is_none()); - - let _latest_blockhash = context.banks_client.get_latest_blockhash().await.unwrap(); - - let destination_stake = Keypair::new(); - let error = stake_pool_accounts - .remove_validator_from_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &new_authority, - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - &destination_stake, - ) - .await - .unwrap() - .unwrap(); - - assert!(matches!( - error, - TransactionError::InstructionError(1, InstructionError::BorshIoError(_),) - )); -} - -#[tokio::test] -async fn fail_wrong_staker() { - let (mut context, stake_pool_accounts, validator_stake, new_authority, destination_stake) = - setup().await; - - let malicious = Keypair::new(); - - let mut transaction = Transaction::new_with_payer( - &[instruction::remove_validator_from_pool( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &malicious.pubkey(), - &stake_pool_accounts.withdraw_authority, - &new_authority, - &stake_pool_accounts.validator_list.pubkey(), - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - &destination_stake.pubkey(), - )], - Some(&context.payer.pubkey()), - ); - transaction.sign(&[&context.payer, &malicious], context.last_blockhash); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = StakePoolError::WrongStaker as u32; - assert_eq!(error_index, program_error); - } - _ => { - panic!("Wrong error occurs while not an staker try to remove validator stake address") - } - } -} - -#[tokio::test] -async fn fail_no_signature() { - let (mut context, stake_pool_accounts, validator_stake, new_authority, destination_stake) = - setup().await; - - let accounts = vec![ - AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false), - AccountMeta::new_readonly(stake_pool_accounts.staker.pubkey(), false), - AccountMeta::new_readonly(stake_pool_accounts.withdraw_authority, false), - AccountMeta::new_readonly(new_authority, false), - AccountMeta::new(stake_pool_accounts.validator_list.pubkey(), false), - AccountMeta::new(validator_stake.stake_account, false), - AccountMeta::new_readonly(validator_stake.transient_stake_account, false), - AccountMeta::new(destination_stake.pubkey(), false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - AccountMeta::new_readonly(stake::program::id(), false), - ]; - let instruction = Instruction { - program_id: id(), - accounts, - data: instruction::StakePoolInstruction::RemoveValidatorFromPool - .try_to_vec() - .unwrap(), - }; - - let transaction = Transaction::new_signed_with_payer( - &[instruction], - Some(&context.payer.pubkey()), - &[&context.payer], - context.last_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = context - .banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = StakePoolError::SignatureMissing as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while malicious try to remove validator stake account without signing transaction"), - } -} - -#[tokio::test] -async fn fail_with_activating_transient_stake() { - let (mut context, stake_pool_accounts, validator_stake, new_authority, destination_stake) = - setup().await; - - // increase the validator stake - let error = stake_pool_accounts - .increase_validator_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &validator_stake.transient_stake_account, - &validator_stake.stake_account, - &validator_stake.vote.pubkey(), - 2_000_000_000, - validator_stake.transient_stake_seed, - ) - .await; - assert!(error.is_none()); - - let error = stake_pool_accounts - .remove_validator_from_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &new_authority, - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - &destination_stake, - ) - .await - .unwrap() - .unwrap(); - match error { - TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - ) => { - let program_error = StakePoolError::WrongStakeState as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while removing validator stake account while transient stake is activating"), - } -} - -#[tokio::test] -async fn success_with_deactivating_transient_stake() { - let (mut context, stake_pool_accounts, validator_stake, new_authority, destination_stake) = - setup().await; - - let rent = context.banks_client.get_rent().await.unwrap(); - let stake_rent = rent.minimum_balance(std::mem::size_of::()); - let deposit_info = simple_deposit_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_pool_accounts, - &validator_stake, - TEST_STAKE_AMOUNT, - ) - .await - .unwrap(); - - // increase the validator stake - let error = stake_pool_accounts - .decrease_validator_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - TEST_STAKE_AMOUNT + stake_rent, - validator_stake.transient_stake_seed, - ) - .await; - assert!(error.is_none()); - - let error = stake_pool_accounts - .remove_validator_from_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &new_authority, - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - &destination_stake, - ) - .await; - assert!(error.is_none()); - - // fail deposit - let maybe_deposit = simple_deposit_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_pool_accounts, - &validator_stake, - TEST_STAKE_AMOUNT, - ) - .await; - assert!(maybe_deposit.is_none()); - - // fail withdraw - let user_stake_recipient = Keypair::new(); - create_blank_stake_account( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &user_stake_recipient, - ) - .await; - - let user_transfer_authority = Keypair::new(); - let new_authority = Pubkey::new_unique(); - delegate_tokens( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &deposit_info.pool_account.pubkey(), - &deposit_info.authority, - &user_transfer_authority.pubkey(), - 1, - ) - .await; - let error = stake_pool_accounts - .withdraw_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &user_stake_recipient.pubkey(), - &user_transfer_authority, - &deposit_info.pool_account.pubkey(), - &validator_stake.stake_account, - &new_authority, - 1, - ) - .await; - assert!(error.is_some()); - - // check validator has changed - let validator_list = get_account( - &mut context.banks_client, - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let validator_list = - try_from_slice_unchecked::(validator_list.data.as_slice()).unwrap(); - let expected_list = state::ValidatorList { - header: state::ValidatorListHeader { - account_type: state::AccountType::ValidatorList, - max_validators: stake_pool_accounts.max_validators, - }, - validators: vec![state::ValidatorStakeInfo { - status: state::StakeStatus::DeactivatingTransient, - vote_account_address: validator_stake.vote.pubkey(), - last_update_epoch: 0, - active_stake_lamports: 0, - transient_stake_lamports: TEST_STAKE_AMOUNT + stake_rent, - transient_seed_suffix_start: validator_stake.transient_stake_seed, - transient_seed_suffix_end: 0, - }], - }; - assert_eq!(validator_list, expected_list); - - // Update, should not change, no merges yet - let error = stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &[validator_stake.vote.pubkey()], - false, - ) - .await; - assert!(error.is_none()); - - let validator_list = get_account( - &mut context.banks_client, - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let validator_list = - try_from_slice_unchecked::(validator_list.data.as_slice()).unwrap(); - assert_eq!(validator_list, expected_list); -} - -#[tokio::test] -async fn success_resets_preferred_validator() { - let (mut context, stake_pool_accounts, validator_stake, new_authority, destination_stake) = - setup().await; - - stake_pool_accounts - .set_preferred_validator( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - instruction::PreferredValidatorType::Deposit, - Some(validator_stake.vote.pubkey()), - ) - .await; - stake_pool_accounts - .set_preferred_validator( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - instruction::PreferredValidatorType::Withdraw, - Some(validator_stake.vote.pubkey()), - ) - .await; - - let error = stake_pool_accounts - .remove_validator_from_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &new_authority, - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - &destination_stake, - ) - .await; - assert!(error.is_none()); - - let error = stake_pool_accounts - .cleanup_removed_validator_entries( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - ) - .await; - assert!(error.is_none()); - - // Check if account was removed from the list of stake accounts - let validator_list = get_account( - &mut context.banks_client, - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let validator_list = - try_from_slice_unchecked::(validator_list.data.as_slice()).unwrap(); - assert_eq!( - validator_list, - state::ValidatorList { - header: state::ValidatorListHeader { - account_type: state::AccountType::ValidatorList, - max_validators: stake_pool_accounts.max_validators, - }, - validators: vec![] - } - ); - - // Check of stake account authority has changed - let stake = get_account(&mut context.banks_client, &destination_stake.pubkey()).await; - let stake_state = deserialize::(&stake.data).unwrap(); - match stake_state { - stake::state::StakeState::Stake(meta, _) => { - assert_eq!(&meta.authorized.staker, &new_authority); - assert_eq!(&meta.authorized.withdrawer, &new_authority); - } - _ => panic!(), - } -} - -#[tokio::test] -async fn success_with_hijacked_transient_account() { - let (mut context, stake_pool_accounts, validator_stake, new_authority, destination_stake) = - setup().await; - let rent = context.banks_client.get_rent().await.unwrap(); - let stake_rent = rent.minimum_balance(std::mem::size_of::()); - let increase_amount = MINIMUM_ACTIVE_STAKE + stake_rent; - - // increase stake on validator - let error = stake_pool_accounts - .increase_validator_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &validator_stake.transient_stake_account, - &validator_stake.stake_account, - &validator_stake.vote.pubkey(), - increase_amount, - validator_stake.transient_stake_seed, - ) - .await; - assert!(error.is_none()); - - // warp forward to merge - let first_normal_slot = context.genesis_config().epoch_schedule.first_normal_slot; - let slots_per_epoch = context.genesis_config().epoch_schedule.slots_per_epoch; - let mut slot = first_normal_slot + slots_per_epoch; - context.warp_to_slot(slot).unwrap(); - stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &[validator_stake.vote.pubkey()], - false, - ) - .await; - - // decrease - let error = stake_pool_accounts - .decrease_validator_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - increase_amount, - validator_stake.transient_stake_seed, - ) - .await; - assert!(error.is_none()); - - // warp forward to merge - slot += slots_per_epoch; - context.warp_to_slot(slot).unwrap(); - - // hijack - let validator_list = stake_pool_accounts - .get_validator_list(&mut context.banks_client) - .await; - let hijacker = Keypair::new(); - let transient_stake_address = find_transient_stake_program_address( - &id(), - &validator_stake.vote.pubkey(), - &stake_pool_accounts.stake_pool.pubkey(), - validator_stake.transient_stake_seed, - ) - .0; - let transaction = Transaction::new_signed_with_payer( - &[ - instruction::update_validator_list_balance( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.withdraw_authority, - &stake_pool_accounts.validator_list.pubkey(), - &stake_pool_accounts.reserve_stake.pubkey(), - &validator_list, - &[validator_stake.vote.pubkey()], - 0, - /* no_merge = */ false, - ), - system_instruction::transfer( - &context.payer.pubkey(), - &transient_stake_address, - MINIMUM_RESERVE_LAMPORTS + stake_rent, - ), - stake::instruction::initialize( - &transient_stake_address, - &stake::state::Authorized { - staker: hijacker.pubkey(), - withdrawer: hijacker.pubkey(), - }, - &stake::state::Lockup::default(), - ), - instruction::update_stake_pool_balance( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.withdraw_authority, - &stake_pool_accounts.validator_list.pubkey(), - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &spl_token::id(), - ), - instruction::cleanup_removed_validator_entries( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - ), - ], - Some(&context.payer.pubkey()), - &[&context.payer], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err(); - assert!(error.is_none()); - - // activate transient stake account - delegate_stake_account( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &transient_stake_address, - &hijacker, - &validator_stake.vote.pubkey(), - ) - .await; - - // Remove works even though transient account is activating - let error = stake_pool_accounts - .remove_validator_from_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &new_authority, - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - &destination_stake, - ) - .await; - assert!(error.is_none()); - - let error = stake_pool_accounts - .cleanup_removed_validator_entries( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - ) - .await; - assert!(error.is_none()); - - // Check if account was removed from the list of stake accounts - let validator_list = get_account( - &mut context.banks_client, - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let validator_list = - try_from_slice_unchecked::(validator_list.data.as_slice()).unwrap(); - assert_eq!( - validator_list, - state::ValidatorList { - header: state::ValidatorListHeader { - account_type: state::AccountType::ValidatorList, - max_validators: stake_pool_accounts.max_validators, - }, - validators: vec![] - } - ); -} - -#[tokio::test] -async fn fail_not_updated_stake_pool() {} // TODO - -#[tokio::test] -async fn fail_with_uninitialized_validator_list_account() {} // TODO diff --git a/stake-pool/program/tests/withdraw.rs b/stake-pool/program/tests/withdraw.rs deleted file mode 100644 index e3fbc2baf8d..00000000000 --- a/stake-pool/program/tests/withdraw.rs +++ /dev/null @@ -1,1626 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod helpers; - -use { - bincode::deserialize, - borsh::BorshSerialize, - helpers::*, - solana_program::{ - borsh::try_from_slice_unchecked, - hash::Hash, - instruction::{AccountMeta, Instruction, InstructionError}, - pubkey::Pubkey, - stake, sysvar, - }, - solana_program_test::*, - solana_sdk::{ - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, - transport::TransportError, - }, - spl_stake_pool::{ - error::StakePoolError, id, instruction, minimum_stake_lamports, state, - MINIMUM_ACTIVE_STAKE, MINIMUM_RESERVE_LAMPORTS, - }, - spl_token::error::TokenError, -}; - -async fn setup() -> ( - BanksClient, - Keypair, - Hash, - StakePoolAccounts, - ValidatorStakeAccount, - DepositStakeAccount, - Keypair, - Keypair, - u64, -) { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let validator_stake_account = simple_add_validator_to_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - ) - .await; - - let deposit_info = simple_deposit_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - &validator_stake_account, - MINIMUM_ACTIVE_STAKE * 3, - ) - .await - .unwrap(); - - let tokens_to_withdraw = deposit_info.pool_tokens; - - // Delegate tokens for withdrawing - let user_transfer_authority = Keypair::new(); - delegate_tokens( - &mut banks_client, - &payer, - &recent_blockhash, - &deposit_info.pool_account.pubkey(), - &deposit_info.authority, - &user_transfer_authority.pubkey(), - tokens_to_withdraw, - ) - .await; - - // Create stake account to withdraw to - let user_stake_recipient = Keypair::new(); - create_blank_stake_account( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake_recipient, - ) - .await; - - ( - banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake_account, - deposit_info, - user_transfer_authority, - user_stake_recipient, - tokens_to_withdraw, - ) -} - -#[tokio::test] -async fn success() { - _success(SuccessTestType::Success).await; -} - -#[tokio::test] -async fn success_with_closed_manager_fee_account() { - _success(SuccessTestType::UninitializedManagerFee).await; -} - -enum SuccessTestType { - Success, - UninitializedManagerFee, -} - -async fn _success(test_type: SuccessTestType) { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake_account, - deposit_info, - user_transfer_authority, - user_stake_recipient, - tokens_to_withdraw, - ) = setup().await; - - // Save stake pool state before withdrawal - let stake_pool_before = - get_account(&mut banks_client, &stake_pool_accounts.stake_pool.pubkey()).await; - let stake_pool_before = - try_from_slice_unchecked::(stake_pool_before.data.as_slice()).unwrap(); - - // Check user recipient stake account balance - let initial_stake_lamports = get_account(&mut banks_client, &user_stake_recipient.pubkey()) - .await - .lamports; - - // Save validator stake account record before withdrawal - let validator_list = get_account( - &mut banks_client, - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let validator_list = - try_from_slice_unchecked::(validator_list.data.as_slice()).unwrap(); - let validator_stake_item_before = validator_list - .find(&validator_stake_account.vote.pubkey()) - .unwrap(); - - // Save user token balance - let user_token_balance_before = - get_token_balance(&mut banks_client, &deposit_info.pool_account.pubkey()).await; - - // Save pool fee token balance - let pool_fee_balance_before = get_token_balance( - &mut banks_client, - &stake_pool_accounts.pool_fee_account.pubkey(), - ) - .await; - - let destination_keypair = Keypair::new(); - create_token_account( - &mut banks_client, - &payer, - &recent_blockhash, - &destination_keypair, - &stake_pool_accounts.pool_mint.pubkey(), - &Keypair::new().pubkey(), - ) - .await - .unwrap(); - - if let SuccessTestType::UninitializedManagerFee = test_type { - transfer_spl_tokens( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts.pool_fee_account.pubkey(), - &destination_keypair.pubkey(), - &stake_pool_accounts.manager, - pool_fee_balance_before, - ) - .await; - // Check that the account cannot be frozen due to lack of - // freeze authority. - let transaction_error = freeze_token_account( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts.pool_fee_account.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &stake_pool_accounts.manager, - ) - .await - .unwrap_err(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError(_, error)) => { - assert_eq!(error, InstructionError::Custom(0x10)); - } - _ => panic!("Wrong error occurs while try to withdraw with wrong stake program ID"), - } - close_token_account( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts.pool_fee_account.pubkey(), - &destination_keypair.pubkey(), - &stake_pool_accounts.manager, - ) - .await - .unwrap(); - } - - let new_authority = Pubkey::new_unique(); - let error = stake_pool_accounts - .withdraw_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake_recipient.pubkey(), - &user_transfer_authority, - &deposit_info.pool_account.pubkey(), - &validator_stake_account.stake_account, - &new_authority, - tokens_to_withdraw, - ) - .await; - assert!(error.is_none()); - - // Check pool stats - let stake_pool = get_account(&mut banks_client, &stake_pool_accounts.stake_pool.pubkey()).await; - let stake_pool = - try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - // first and only deposit, lamports:pool 1:1 - let tokens_withdrawal_fee = match test_type { - SuccessTestType::Success => { - stake_pool_accounts.calculate_withdrawal_fee(tokens_to_withdraw) - } - _ => 0, - }; - let tokens_burnt = tokens_to_withdraw - tokens_withdrawal_fee; - assert_eq!( - stake_pool.total_lamports, - stake_pool_before.total_lamports - tokens_burnt - ); - assert_eq!( - stake_pool.pool_token_supply, - stake_pool_before.pool_token_supply - tokens_burnt - ); - - if let SuccessTestType::Success = test_type { - // Check manager received withdrawal fee - let pool_fee_balance = get_token_balance( - &mut banks_client, - &stake_pool_accounts.pool_fee_account.pubkey(), - ) - .await; - assert_eq!( - pool_fee_balance, - pool_fee_balance_before + tokens_withdrawal_fee, - ); - } - - // Check validator stake list storage - let validator_list = get_account( - &mut banks_client, - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let validator_list = - try_from_slice_unchecked::(validator_list.data.as_slice()).unwrap(); - let validator_stake_item = validator_list - .find(&validator_stake_account.vote.pubkey()) - .unwrap(); - assert_eq!( - validator_stake_item.stake_lamports(), - validator_stake_item_before.stake_lamports() - tokens_burnt - ); - assert_eq!( - validator_stake_item.active_stake_lamports, - validator_stake_item.stake_lamports(), - ); - - // Check tokens used - let user_token_balance = - get_token_balance(&mut banks_client, &deposit_info.pool_account.pubkey()).await; - assert_eq!( - user_token_balance, - user_token_balance_before - tokens_to_withdraw - ); - - // Check validator stake account balance - let validator_stake_account = - get_account(&mut banks_client, &validator_stake_account.stake_account).await; - let stake_state = - deserialize::(&validator_stake_account.data).unwrap(); - let meta = stake_state.meta().unwrap(); - assert_eq!( - validator_stake_account.lamports - minimum_stake_lamports(&meta), - validator_stake_item.active_stake_lamports - ); - - // Check user recipient stake account balance - let user_stake_recipient_account = - get_account(&mut banks_client, &user_stake_recipient.pubkey()).await; - assert_eq!( - user_stake_recipient_account.lamports, - initial_stake_lamports + tokens_burnt - ); -} - -#[tokio::test] -async fn fail_with_wrong_stake_program() { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake_account, - deposit_info, - user_transfer_authority, - user_stake_recipient, - tokens_to_burn, - ) = setup().await; - - let new_authority = Pubkey::new_unique(); - let wrong_stake_program = Pubkey::new_unique(); - - let accounts = vec![ - AccountMeta::new(stake_pool_accounts.stake_pool.pubkey(), false), - AccountMeta::new(stake_pool_accounts.validator_list.pubkey(), false), - AccountMeta::new_readonly(stake_pool_accounts.withdraw_authority, false), - AccountMeta::new(validator_stake_account.stake_account, false), - AccountMeta::new(user_stake_recipient.pubkey(), false), - AccountMeta::new_readonly(new_authority, false), - AccountMeta::new_readonly(user_transfer_authority.pubkey(), true), - AccountMeta::new(deposit_info.pool_account.pubkey(), false), - AccountMeta::new(stake_pool_accounts.pool_fee_account.pubkey(), false), - AccountMeta::new(stake_pool_accounts.pool_mint.pubkey(), false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new_readonly(wrong_stake_program, false), - ]; - let instruction = Instruction { - program_id: id(), - accounts, - data: instruction::StakePoolInstruction::WithdrawStake(tokens_to_burn) - .try_to_vec() - .unwrap(), - }; - - let transaction = Transaction::new_signed_with_payer( - &[instruction], - Some(&payer.pubkey()), - &[&payer, &user_transfer_authority], - recent_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError(_, error)) => { - assert_eq!(error, InstructionError::IncorrectProgramId); - } - _ => panic!("Wrong error occurs while try to withdraw with wrong stake program ID"), - } -} - -#[tokio::test] -async fn fail_with_wrong_withdraw_authority() { - let ( - mut banks_client, - payer, - recent_blockhash, - mut stake_pool_accounts, - validator_stake_account, - deposit_info, - user_transfer_authority, - user_stake_recipient, - tokens_to_burn, - ) = setup().await; - - let new_authority = Pubkey::new_unique(); - stake_pool_accounts.withdraw_authority = Keypair::new().pubkey(); - - let transaction_error = stake_pool_accounts - .withdraw_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake_recipient.pubkey(), - &user_transfer_authority, - &deposit_info.pool_account.pubkey(), - &validator_stake_account.stake_account, - &new_authority, - tokens_to_burn, - ) - .await - .unwrap(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = StakePoolError::InvalidProgramAddress as u32; - assert_eq!(error_index, program_error); - } - _ => panic!("Wrong error occurs while try to withdraw with wrong withdraw authority"), - } -} - -#[tokio::test] -async fn fail_with_wrong_token_program_id() { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake_account, - deposit_info, - user_transfer_authority, - user_stake_recipient, - tokens_to_burn, - ) = setup().await; - - let new_authority = Pubkey::new_unique(); - let wrong_token_program = Keypair::new(); - - let transaction = Transaction::new_signed_with_payer( - &[instruction::withdraw_stake( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - &stake_pool_accounts.withdraw_authority, - &validator_stake_account.stake_account, - &user_stake_recipient.pubkey(), - &new_authority, - &user_transfer_authority.pubkey(), - &deposit_info.pool_account.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &wrong_token_program.pubkey(), - tokens_to_burn, - )], - Some(&payer.pubkey()), - &[&payer, &user_transfer_authority], - recent_blockhash, - ); - #[allow(clippy::useless_conversion)] // Remove during upgrade to 1.10 - let transaction_error = banks_client - .process_transaction(transaction) - .await - .err() - .unwrap() - .into(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError(_, error)) => { - assert_eq!(error, InstructionError::IncorrectProgramId); - } - _ => panic!("Wrong error occurs while try to withdraw with wrong token program ID"), - } -} - -#[tokio::test] -async fn fail_with_wrong_validator_list() { - let ( - mut banks_client, - payer, - recent_blockhash, - mut stake_pool_accounts, - validator_stake, - deposit_info, - user_transfer_authority, - user_stake_recipient, - tokens_to_burn, - ) = setup().await; - - let new_authority = Pubkey::new_unique(); - stake_pool_accounts.validator_list = Keypair::new(); - - let transaction_error = stake_pool_accounts - .withdraw_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake_recipient.pubkey(), - &user_transfer_authority, - &deposit_info.pool_account.pubkey(), - &validator_stake.stake_account, - &new_authority, - tokens_to_burn, - ) - .await - .unwrap(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = StakePoolError::InvalidValidatorStakeList as u32; - assert_eq!(error_index, program_error); - } - _ => panic!( - "Wrong error occurs while try to withdraw with wrong validator stake list account" - ), - } -} - -#[tokio::test] -async fn fail_with_unknown_validator() { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - _, - deposit_info, - user_transfer_authority, - user_stake_recipient, - tokens_to_withdraw, - ) = setup().await; - - let unknown_stake = create_unknown_validator_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - - let new_authority = Pubkey::new_unique(); - let error = stake_pool_accounts - .withdraw_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake_recipient.pubkey(), - &user_transfer_authority, - &deposit_info.pool_account.pubkey(), - &unknown_stake.stake_account, - &new_authority, - tokens_to_withdraw, - ) - .await - .unwrap() - .unwrap(); - - assert_eq!( - error, - TransactionError::InstructionError( - 0, - InstructionError::Custom(StakePoolError::ValidatorNotFound as u32) - ) - ); -} - -#[tokio::test] -async fn fail_double_withdraw_to_the_same_account() { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake_account, - deposit_info, - user_transfer_authority, - user_stake_recipient, - tokens_to_burn, - ) = setup().await; - - let new_authority = Pubkey::new_unique(); - let error = stake_pool_accounts - .withdraw_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake_recipient.pubkey(), - &user_transfer_authority, - &deposit_info.pool_account.pubkey(), - &validator_stake_account.stake_account, - &new_authority, - tokens_to_burn / 2, - ) - .await; - assert!(error.is_none()); - - let latest_blockhash = banks_client.get_latest_blockhash().await.unwrap(); - - // Delegate tokens for burning - delegate_tokens( - &mut banks_client, - &payer, - &latest_blockhash, - &deposit_info.pool_account.pubkey(), - &deposit_info.authority, - &user_transfer_authority.pubkey(), - tokens_to_burn / 2, - ) - .await; - - let transaction_error = stake_pool_accounts - .withdraw_stake( - &mut banks_client, - &payer, - &latest_blockhash, - &user_stake_recipient.pubkey(), - &user_transfer_authority, - &deposit_info.pool_account.pubkey(), - &validator_stake_account.stake_account, - &new_authority, - tokens_to_burn / 2, - ) - .await - .unwrap(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError(_, error)) => { - assert_eq!(error, InstructionError::InvalidAccountData); - } - _ => panic!("Wrong error occurs while try to do double withdraw"), - } -} - -#[tokio::test] -async fn fail_without_token_approval() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let validator_stake_account = simple_add_validator_to_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - ) - .await; - - let deposit_info = simple_deposit_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - &validator_stake_account, - TEST_STAKE_AMOUNT, - ) - .await - .unwrap(); - - let tokens_to_burn = deposit_info.pool_tokens / 4; - - // Create stake account to withdraw to - let user_stake_recipient = Keypair::new(); - create_blank_stake_account( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake_recipient, - ) - .await; - - let new_authority = Pubkey::new_unique(); - let user_transfer_authority = Keypair::new(); - let transaction_error = stake_pool_accounts - .withdraw_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake_recipient.pubkey(), - &user_transfer_authority, - &deposit_info.pool_account.pubkey(), - &validator_stake_account.stake_account, - &new_authority, - tokens_to_burn, - ) - .await - .unwrap(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = TokenError::OwnerMismatch as u32; - assert_eq!(error_index, program_error); - } - _ => panic!( - "Wrong error occurs while try to do withdraw without token delegation for burn before" - ), - } -} - -#[tokio::test] -async fn fail_with_low_delegation() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut banks_client, - &payer, - &recent_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let validator_stake_account = simple_add_validator_to_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - ) - .await; - - let deposit_info = simple_deposit_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - &validator_stake_account, - TEST_STAKE_AMOUNT, - ) - .await - .unwrap(); - - let tokens_to_burn = deposit_info.pool_tokens / 4; - - let user_transfer_authority = Keypair::new(); - // Delegate tokens for burning - delegate_tokens( - &mut banks_client, - &payer, - &recent_blockhash, - &deposit_info.pool_account.pubkey(), - &deposit_info.authority, - &user_transfer_authority.pubkey(), - 1, - ) - .await; - - // Create stake account to withdraw to - let user_stake_recipient = Keypair::new(); - create_blank_stake_account( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake_recipient, - ) - .await; - - let new_authority = Pubkey::new_unique(); - let transaction_error = stake_pool_accounts - .withdraw_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake_recipient.pubkey(), - &user_transfer_authority, - &deposit_info.pool_account.pubkey(), - &validator_stake_account.stake_account, - &new_authority, - tokens_to_burn, - ) - .await - .unwrap(); - - match transaction_error { - TransportError::TransactionError(TransactionError::InstructionError( - _, - InstructionError::Custom(error_index), - )) => { - let program_error = TokenError::InsufficientFunds as u32; - assert_eq!(error_index, program_error); - } - _ => panic!( - "Wrong error occurs while try to do withdraw with not enough delegated tokens to burn" - ), - } -} - -#[tokio::test] -async fn fail_overdraw_validator() { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - _validator_stake_account, - deposit_info, - user_transfer_authority, - user_stake_recipient, - tokens_to_burn, - ) = setup().await; - - let validator_stake_account = simple_add_validator_to_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - ) - .await; - - let new_authority = Pubkey::new_unique(); - let error = stake_pool_accounts - .withdraw_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake_recipient.pubkey(), - &user_transfer_authority, - &deposit_info.pool_account.pubkey(), - &validator_stake_account.stake_account, - &new_authority, - tokens_to_burn, - ) - .await - .unwrap() - .unwrap(); - assert_eq!( - error, - TransactionError::InstructionError( - 0, - InstructionError::Custom(StakePoolError::StakeLamportsNotEqualToMinimum as u32) - ), - ); -} - -#[tokio::test] -async fn success_with_reserve() { - let mut context = program_test().start_with_context().await; - let stake_pool_accounts = StakePoolAccounts::new(); - let initial_reserve_lamports = MINIMUM_RESERVE_LAMPORTS; - stake_pool_accounts - .initialize_stake_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - initial_reserve_lamports, - ) - .await - .unwrap(); - - let validator_stake = simple_add_validator_to_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_pool_accounts, - ) - .await; - - let rent = context.banks_client.get_rent().await.unwrap(); - let stake_rent = rent.minimum_balance(std::mem::size_of::()); - let deposit_lamports = (MINIMUM_ACTIVE_STAKE + stake_rent) * 2; - - let deposit_info = simple_deposit_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_pool_accounts, - &validator_stake, - deposit_lamports, - ) - .await - .unwrap(); - - // decrease some stake - let error = stake_pool_accounts - .decrease_validator_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - deposit_lamports / 2, - validator_stake.transient_stake_seed, - ) - .await; - assert!(error.is_none()); - - // warp forward to deactivation - let first_normal_slot = context.genesis_config().epoch_schedule.first_normal_slot; - let slots_per_epoch = context.genesis_config().epoch_schedule.slots_per_epoch; - context - .warp_to_slot(first_normal_slot + slots_per_epoch) - .unwrap(); - - // update to merge deactivated stake into reserve - stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &[validator_stake.vote.pubkey()], - false, - ) - .await; - - // Delegate tokens for using for withdrawal - let user_transfer_authority = Keypair::new(); - delegate_tokens( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &deposit_info.pool_account.pubkey(), - &deposit_info.authority, - &user_transfer_authority.pubkey(), - deposit_info.pool_tokens, - ) - .await; - - // Withdraw directly from reserve, fail because some stake left - let withdraw_destination = Keypair::new(); - let withdraw_destination_authority = Pubkey::new_unique(); - let initial_stake_lamports = create_blank_stake_account( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &withdraw_destination, - ) - .await; - let error = stake_pool_accounts - .withdraw_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &withdraw_destination.pubkey(), - &user_transfer_authority, - &deposit_info.pool_account.pubkey(), - &stake_pool_accounts.reserve_stake.pubkey(), - &withdraw_destination_authority, - deposit_info.pool_tokens, - ) - .await - .unwrap() - .unwrap(); - assert_eq!( - error, - TransactionError::InstructionError( - 0, - InstructionError::Custom(StakePoolError::StakeLamportsNotEqualToMinimum as u32) - ) - ); - - // decrease rest of stake - let error = stake_pool_accounts - .decrease_validator_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - deposit_lamports / 2 + stake_rent, - validator_stake.transient_stake_seed, - ) - .await; - assert!(error.is_none()); - - // warp forward to deactivation - context - .warp_to_slot(first_normal_slot + 2 * slots_per_epoch) - .unwrap(); - - // update to merge deactivated stake into reserve - stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &[validator_stake.vote.pubkey()], - false, - ) - .await; - - // now it works - let error = stake_pool_accounts - .withdraw_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &withdraw_destination.pubkey(), - &user_transfer_authority, - &deposit_info.pool_account.pubkey(), - &stake_pool_accounts.reserve_stake.pubkey(), - &withdraw_destination_authority, - deposit_info.pool_tokens, - ) - .await; - assert!(error.is_none()); - - // first and only deposit, lamports:pool 1:1 - let stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = - try_from_slice_unchecked::(stake_pool.data.as_slice()).unwrap(); - // the entire deposit is actually stake since it isn't activated, so only - // the stake deposit fee is charged - let deposit_fee = stake_pool - .calc_pool_tokens_stake_deposit_fee(stake_rent + deposit_info.stake_lamports) - .unwrap(); - assert_eq!( - deposit_info.stake_lamports + stake_rent - deposit_fee, - deposit_info.pool_tokens, - "stake {} rent {} deposit fee {} pool tokens {}", - deposit_info.stake_lamports, - stake_rent, - deposit_fee, - deposit_info.pool_tokens - ); - - let withdrawal_fee = stake_pool_accounts.calculate_withdrawal_fee(deposit_info.pool_tokens); - - // Check tokens used - let user_token_balance = get_token_balance( - &mut context.banks_client, - &deposit_info.pool_account.pubkey(), - ) - .await; - assert_eq!(user_token_balance, 0); - - // Check reserve stake account balance - let reserve_stake_account = get_account( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - ) - .await; - let stake_state = deserialize::(&reserve_stake_account.data).unwrap(); - let meta = stake_state.meta().unwrap(); - assert_eq!( - initial_reserve_lamports + meta.rent_exempt_reserve + withdrawal_fee + deposit_fee, - reserve_stake_account.lamports - ); - - // Check user recipient stake account balance - let user_stake_recipient_account = - get_account(&mut context.banks_client, &withdraw_destination.pubkey()).await; - assert_eq!( - user_stake_recipient_account.lamports, - initial_stake_lamports + deposit_info.stake_lamports + stake_rent - - withdrawal_fee - - deposit_fee - ); -} - -#[tokio::test] -async fn success_with_preferred_validator() { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake, - deposit_info, - user_transfer_authority, - user_stake_recipient, - tokens_to_burn, - ) = setup().await; - - stake_pool_accounts - .set_preferred_validator( - &mut banks_client, - &payer, - &recent_blockhash, - instruction::PreferredValidatorType::Withdraw, - Some(validator_stake.vote.pubkey()), - ) - .await; - - let new_authority = Pubkey::new_unique(); - let error = stake_pool_accounts - .withdraw_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake_recipient.pubkey(), - &user_transfer_authority, - &deposit_info.pool_account.pubkey(), - &validator_stake.stake_account, - &new_authority, - tokens_to_burn, - ) - .await; - assert!(error.is_none()); -} - -#[tokio::test] -async fn fail_with_wrong_preferred_withdraw() { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake, - deposit_info, - user_transfer_authority, - user_stake_recipient, - tokens_to_burn, - ) = setup().await; - - let preferred_validator = simple_add_validator_to_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - ) - .await; - - stake_pool_accounts - .set_preferred_validator( - &mut banks_client, - &payer, - &recent_blockhash, - instruction::PreferredValidatorType::Withdraw, - Some(preferred_validator.vote.pubkey()), - ) - .await; - - // preferred is empty, this works - let new_authority = Pubkey::new_unique(); - let error = stake_pool_accounts - .withdraw_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake_recipient.pubkey(), - &user_transfer_authority, - &deposit_info.pool_account.pubkey(), - &validator_stake.stake_account, - &new_authority, - tokens_to_burn, - ) - .await; - assert!(error.is_none()); - - // deposit into preferred, then fail - let _preferred_deposit = simple_deposit_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - &preferred_validator, - TEST_STAKE_AMOUNT, - ) - .await - .unwrap(); - - // Create stake account to withdraw to - let user_stake_recipient = Keypair::new(); - create_blank_stake_account( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake_recipient, - ) - .await; - - let error = stake_pool_accounts - .withdraw_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake_recipient.pubkey(), - &user_transfer_authority, - &deposit_info.pool_account.pubkey(), - &validator_stake.stake_account, - &new_authority, - tokens_to_burn, - ) - .await - .unwrap() - .unwrap(); - match error { - TransactionError::InstructionError(_, InstructionError::Custom(error_index)) => { - assert_eq!( - error_index, - StakePoolError::IncorrectWithdrawVoteAddress as u32 - ); - } - _ => panic!("Wrong error occurs while try to make a deposit with wrong stake program ID"), - } -} - -#[tokio::test] -async fn fail_withdraw_from_transient() { - let mut context = program_test().start_with_context().await; - let stake_pool_accounts = StakePoolAccounts::new(); - let initial_reserve_lamports = MINIMUM_RESERVE_LAMPORTS; - stake_pool_accounts - .initialize_stake_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - initial_reserve_lamports, - ) - .await - .unwrap(); - - // add a preferred withdraw validator, keep it empty, to be sure that this works - let preferred_validator = simple_add_validator_to_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_pool_accounts, - ) - .await; - - stake_pool_accounts - .set_preferred_validator( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - instruction::PreferredValidatorType::Withdraw, - Some(preferred_validator.vote.pubkey()), - ) - .await; - - let validator_stake = simple_add_validator_to_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_pool_accounts, - ) - .await; - - let rent = context.banks_client.get_rent().await.unwrap(); - let stake_rent = rent.minimum_balance(std::mem::size_of::()); - let deposit_lamports = (MINIMUM_ACTIVE_STAKE + stake_rent) * 2; - - let deposit_info = simple_deposit_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_pool_accounts, - &validator_stake, - deposit_lamports, - ) - .await - .unwrap(); - - // Delegate tokens for burning during withdraw - let user_transfer_authority = Keypair::new(); - delegate_tokens( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &deposit_info.pool_account.pubkey(), - &deposit_info.authority, - &user_transfer_authority.pubkey(), - deposit_info.pool_tokens, - ) - .await; - - // decrease to minimum stake + 1 lamport - let error = stake_pool_accounts - .decrease_validator_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - deposit_lamports + stake_rent - 1, - validator_stake.transient_stake_seed, - ) - .await; - assert!(error.is_none()); - - let withdraw_destination = Keypair::new(); - let withdraw_destination_authority = Pubkey::new_unique(); - let _initial_stake_lamports = create_blank_stake_account( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &withdraw_destination, - ) - .await; - - // fail withdrawing from transient, still a lamport in the validator stake account - let error = stake_pool_accounts - .withdraw_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &withdraw_destination.pubkey(), - &user_transfer_authority, - &deposit_info.pool_account.pubkey(), - &validator_stake.transient_stake_account, - &withdraw_destination_authority, - deposit_info.pool_tokens / 2, - ) - .await - .unwrap() - .unwrap(); - assert_eq!( - error, - TransactionError::InstructionError( - 0, - InstructionError::Custom(StakePoolError::InvalidStakeAccountAddress as u32) - ) - ); -} - -#[tokio::test] -async fn success_withdraw_from_transient() { - let mut context = program_test().start_with_context().await; - let stake_pool_accounts = StakePoolAccounts::new(); - let initial_reserve_lamports = MINIMUM_RESERVE_LAMPORTS; - stake_pool_accounts - .initialize_stake_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - initial_reserve_lamports, - ) - .await - .unwrap(); - - // add a preferred withdraw validator, keep it empty, to be sure that this works - let preferred_validator = simple_add_validator_to_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_pool_accounts, - ) - .await; - - stake_pool_accounts - .set_preferred_validator( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - instruction::PreferredValidatorType::Withdraw, - Some(preferred_validator.vote.pubkey()), - ) - .await; - - let validator_stake = simple_add_validator_to_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_pool_accounts, - ) - .await; - - let rent = context.banks_client.get_rent().await.unwrap(); - let stake_rent = rent.minimum_balance(std::mem::size_of::()); - - // compensate for the fee and the minimum balance in the transient stake account - let deposit_lamports = (MINIMUM_ACTIVE_STAKE + stake_rent) * 3; - - let deposit_info = simple_deposit_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_pool_accounts, - &validator_stake, - deposit_lamports, - ) - .await - .unwrap(); - - // Delegate tokens for burning during withdraw - let user_transfer_authority = Keypair::new(); - delegate_tokens( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &deposit_info.pool_account.pubkey(), - &deposit_info.authority, - &user_transfer_authority.pubkey(), - deposit_info.pool_tokens, - ) - .await; - - let withdraw_destination = Keypair::new(); - let withdraw_destination_authority = Pubkey::new_unique(); - let _initial_stake_lamports = create_blank_stake_account( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &withdraw_destination, - ) - .await; - - // decrease all of stake - let error = stake_pool_accounts - .decrease_validator_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - deposit_lamports + stake_rent, - validator_stake.transient_stake_seed, - ) - .await; - assert!(error.is_none()); - - // nothing left in the validator stake account (or any others), so withdrawing - // from the transient account is ok! - let error = stake_pool_accounts - .withdraw_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &withdraw_destination.pubkey(), - &user_transfer_authority, - &deposit_info.pool_account.pubkey(), - &validator_stake.transient_stake_account, - &withdraw_destination_authority, - deposit_info.pool_tokens / 2, - ) - .await; - assert!(error.is_none()); -} - -#[tokio::test] -async fn success_withdraw_all_fee_tokens() { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - validator_stake_account, - deposit_info, - user_transfer_authority, - user_stake_recipient, - tokens_to_withdraw, - ) = setup().await; - - // move tokens to fee account - transfer_spl_tokens( - &mut banks_client, - &payer, - &recent_blockhash, - &deposit_info.pool_account.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - &user_transfer_authority, - tokens_to_withdraw, - ) - .await; - - let fee_tokens = get_token_balance( - &mut banks_client, - &stake_pool_accounts.pool_fee_account.pubkey(), - ) - .await; - - let user_transfer_authority = Keypair::new(); - delegate_tokens( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts.pool_fee_account.pubkey(), - &stake_pool_accounts.manager, - &user_transfer_authority.pubkey(), - fee_tokens, - ) - .await; - - let new_authority = Pubkey::new_unique(); - let error = stake_pool_accounts - .withdraw_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake_recipient.pubkey(), - &user_transfer_authority, - &stake_pool_accounts.pool_fee_account.pubkey(), - &validator_stake_account.stake_account, - &new_authority, - fee_tokens, - ) - .await; - assert!(error.is_none()); - - // Check balance is 0 - let fee_tokens = get_token_balance( - &mut banks_client, - &stake_pool_accounts.pool_fee_account.pubkey(), - ) - .await; - assert_eq!(fee_tokens, 0); -} - -#[tokio::test] -async fn success_empty_out_stake_with_fee() { - let ( - mut banks_client, - payer, - recent_blockhash, - stake_pool_accounts, - _, - deposit_info, - user_transfer_authority, - user_stake_recipient, - tokens_to_withdraw, - ) = setup().await; - - // add another validator and deposit into it - let other_validator_stake_account = simple_add_validator_to_pool( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - ) - .await; - - let other_deposit_info = simple_deposit_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &stake_pool_accounts, - &other_validator_stake_account, - TEST_STAKE_AMOUNT, - ) - .await - .unwrap(); - - // move tokens to new account - transfer_spl_tokens( - &mut banks_client, - &payer, - &recent_blockhash, - &deposit_info.pool_account.pubkey(), - &other_deposit_info.pool_account.pubkey(), - &user_transfer_authority, - tokens_to_withdraw, - ) - .await; - - let user_tokens = - get_token_balance(&mut banks_client, &other_deposit_info.pool_account.pubkey()).await; - - let user_transfer_authority = Keypair::new(); - delegate_tokens( - &mut banks_client, - &payer, - &recent_blockhash, - &other_deposit_info.pool_account.pubkey(), - &other_deposit_info.authority, - &user_transfer_authority.pubkey(), - user_tokens, - ) - .await; - - // calculate exactly how much to withdraw, given the fee, to get the account - // down to 0, using an inverse fee calculation - let validator_stake_account = get_account( - &mut banks_client, - &other_validator_stake_account.stake_account, - ) - .await; - let stake_state = - deserialize::(&validator_stake_account.data).unwrap(); - let meta = stake_state.meta().unwrap(); - let lamports_to_withdraw = validator_stake_account.lamports - minimum_stake_lamports(&meta); - let stake_pool_account = - get_account(&mut banks_client, &stake_pool_accounts.stake_pool.pubkey()).await; - let stake_pool = - try_from_slice_unchecked::(stake_pool_account.data.as_slice()).unwrap(); - let fee = stake_pool.stake_withdrawal_fee; - let inverse_fee = state::Fee { - numerator: fee.denominator - fee.numerator, - denominator: fee.denominator, - }; - let pool_tokens_to_withdraw = - lamports_to_withdraw * inverse_fee.denominator / inverse_fee.numerator; - - let new_authority = Pubkey::new_unique(); - let error = stake_pool_accounts - .withdraw_stake( - &mut banks_client, - &payer, - &recent_blockhash, - &user_stake_recipient.pubkey(), - &user_transfer_authority, - &other_deposit_info.pool_account.pubkey(), - &other_validator_stake_account.stake_account, - &new_authority, - pool_tokens_to_withdraw, - ) - .await; - assert!(error.is_none()); - - // Check balance of validator stake account is MINIMUM + rent-exemption - let validator_stake_account = get_account( - &mut banks_client, - &other_validator_stake_account.stake_account, - ) - .await; - let stake_state = - deserialize::(&validator_stake_account.data).unwrap(); - let meta = stake_state.meta().unwrap(); - assert_eq!( - validator_stake_account.lamports, - minimum_stake_lamports(&meta) - ); -} diff --git a/stake-pool/program/tests/withdraw_sol.rs b/stake-pool/program/tests/withdraw_sol.rs deleted file mode 100644 index 82686de96f1..00000000000 --- a/stake-pool/program/tests/withdraw_sol.rs +++ /dev/null @@ -1,312 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod helpers; - -use { - helpers::*, - solana_program::{ - borsh::try_from_slice_unchecked, instruction::InstructionError, pubkey::Pubkey, stake, - }, - solana_program_test::*, - solana_sdk::{ - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, - }, - spl_stake_pool::{ - error::StakePoolError, - id, - instruction::{self, FundingType}, - state, MINIMUM_RESERVE_LAMPORTS, - }, -}; - -async fn setup() -> (ProgramTestContext, StakePoolAccounts, Keypair, Pubkey, u64) { - let mut context = program_test().start_with_context().await; - - let stake_pool_accounts = StakePoolAccounts::new(); - stake_pool_accounts - .initialize_stake_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - let user = Keypair::new(); - - // make pool token account for user - let pool_token_account = Keypair::new(); - create_token_account( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &pool_token_account, - &stake_pool_accounts.pool_mint.pubkey(), - &user.pubkey(), - ) - .await - .unwrap(); - - let error = stake_pool_accounts - .deposit_sol( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &pool_token_account.pubkey(), - TEST_STAKE_AMOUNT, - None, - ) - .await; - assert!(error.is_none()); - - let tokens_issued = - get_token_balance(&mut context.banks_client, &pool_token_account.pubkey()).await; - - ( - context, - stake_pool_accounts, - user, - pool_token_account.pubkey(), - tokens_issued, - ) -} - -#[tokio::test] -async fn success() { - let (mut context, stake_pool_accounts, user, pool_token_account, pool_tokens) = setup().await; - - // Save stake pool state before withdrawing - let pre_stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let pre_stake_pool = - try_from_slice_unchecked::(pre_stake_pool.data.as_slice()).unwrap(); - - // Save reserve state before withdrawing - let pre_reserve_lamports = get_account( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - ) - .await - .lamports; - - let error = stake_pool_accounts - .withdraw_sol( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &user, - &pool_token_account, - pool_tokens, - None, - ) - .await; - assert!(error.is_none()); - - // Stake pool should add its balance to the pool balance - let post_stake_pool = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let post_stake_pool = - try_from_slice_unchecked::(post_stake_pool.data.as_slice()).unwrap(); - let amount_withdrawn_minus_fee = - pool_tokens - stake_pool_accounts.calculate_withdrawal_fee(pool_tokens); - assert_eq!( - post_stake_pool.total_lamports, - pre_stake_pool.total_lamports - amount_withdrawn_minus_fee - ); - assert_eq!( - post_stake_pool.pool_token_supply, - pre_stake_pool.pool_token_supply - amount_withdrawn_minus_fee - ); - - // Check minted tokens - let user_token_balance = - get_token_balance(&mut context.banks_client, &pool_token_account).await; - assert_eq!(user_token_balance, 0); - - // Check reserve - let post_reserve_lamports = get_account( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - ) - .await - .lamports; - assert_eq!( - post_reserve_lamports, - pre_reserve_lamports - amount_withdrawn_minus_fee - ); -} - -#[tokio::test] -async fn fail_with_wrong_withdraw_authority() { - let (mut context, mut stake_pool_accounts, user, pool_token_account, pool_tokens) = - setup().await; - - stake_pool_accounts.withdraw_authority = Pubkey::new_unique(); - - let error = stake_pool_accounts - .withdraw_sol( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &user, - &pool_token_account, - pool_tokens, - None, - ) - .await - .unwrap() - .unwrap(); - - assert_eq!( - error, - TransactionError::InstructionError( - 0, - InstructionError::Custom(StakePoolError::InvalidProgramAddress as u32) - ) - ); -} - -#[tokio::test] -async fn fail_overdraw_reserve() { - let (mut context, stake_pool_accounts, user, pool_token_account, _) = setup().await; - - // add a validator and increase stake to drain the reserve - let validator_stake = simple_add_validator_to_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_pool_accounts, - ) - .await; - - let rent = context.banks_client.get_rent().await.unwrap(); - let stake_rent = rent.minimum_balance(std::mem::size_of::()); - let error = stake_pool_accounts - .increase_validator_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &validator_stake.transient_stake_account, - &validator_stake.stake_account, - &validator_stake.vote.pubkey(), - TEST_STAKE_AMOUNT - stake_rent, - validator_stake.transient_stake_seed, - ) - .await; - assert!(error.is_none()); - - // try to withdraw one lamport, will overdraw - let error = stake_pool_accounts - .withdraw_sol( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &user, - &pool_token_account, - 1, - None, - ) - .await - .unwrap() - .unwrap(); - - assert_eq!( - error, - TransactionError::InstructionError( - 0, - InstructionError::Custom(StakePoolError::SolWithdrawalTooLarge as u32) - ) - ); -} - -#[tokio::test] -async fn success_with_sol_withdraw_authority() { - let (mut context, stake_pool_accounts, user, pool_token_account, pool_tokens) = setup().await; - let sol_withdraw_authority = Keypair::new(); - - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_funding_authority( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - Some(&sol_withdraw_authority.pubkey()), - FundingType::SolWithdraw, - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let error = stake_pool_accounts - .withdraw_sol( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &user, - &pool_token_account, - pool_tokens, - Some(&sol_withdraw_authority), - ) - .await; - assert!(error.is_none()); -} - -#[tokio::test] -async fn fail_without_sol_withdraw_authority_signature() { - let (mut context, stake_pool_accounts, user, pool_token_account, pool_tokens) = setup().await; - let sol_withdraw_authority = Keypair::new(); - - let transaction = Transaction::new_signed_with_payer( - &[instruction::set_funding_authority( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.manager.pubkey(), - Some(&sol_withdraw_authority.pubkey()), - FundingType::SolWithdraw, - )], - Some(&context.payer.pubkey()), - &[&context.payer, &stake_pool_accounts.manager], - context.last_blockhash, - ); - context - .banks_client - .process_transaction(transaction) - .await - .unwrap(); - - let wrong_withdrawer = Keypair::new(); - let error = stake_pool_accounts - .withdraw_sol( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &user, - &pool_token_account, - pool_tokens, - Some(&wrong_withdrawer), - ) - .await - .unwrap() - .unwrap(); - - assert_eq!( - error, - TransactionError::InstructionError( - 0, - InstructionError::Custom(StakePoolError::InvalidSolWithdrawAuthority as u32) - ) - ); -} diff --git a/stake-pool/py/.flake8 b/stake-pool/py/.flake8 deleted file mode 100644 index aa079ec57f8..00000000000 --- a/stake-pool/py/.flake8 +++ /dev/null @@ -1,2 +0,0 @@ -[flake8] -max-line-length=120 diff --git a/stake-pool/py/.gitignore b/stake-pool/py/.gitignore deleted file mode 100644 index ad0e7548ff2..00000000000 --- a/stake-pool/py/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# python cache files -*__pycache__* -.pytest_cache -.mypy_cache - -# venv -venv/ diff --git a/stake-pool/py/LICENSE b/stake-pool/py/LICENSE deleted file mode 100644 index 7e71f6e9a88..00000000000 --- a/stake-pool/py/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2022 Solana Foundation. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/stake-pool/py/README.md b/stake-pool/py/README.md deleted file mode 100644 index cda7beea17b..00000000000 --- a/stake-pool/py/README.md +++ /dev/null @@ -1,68 +0,0 @@ -# Stake-Pool Python Bindings - -Preliminary Python bindings to interact with the stake pool program, enabling -simple stake delegation bots. - -## To do - -* More reference bot implementations -* Add bindings for all stake pool instructions, see `TODO`s in `stake_pool/instructions.py` -* Finish bindings for vote and stake program -* Upstream vote and stake program bindings to https://github.com/michaelhly/solana-py - -## Development - -### Environment Setup - -1. Ensure that Python 3 is installed with `venv`: https://www.python.org/downloads/ -2. (Optional, but highly recommended) Setup and activate a virtual environment: - -``` -$ python3 -m venv venv -$ source venv/bin/activate -``` - -3. Install build and dev requirements - -``` -$ pip install -r requirements.txt -$ pip install -r optional-requirements.txt -``` - -4. Install the Solana tool suite: https://docs.solana.com/cli/install-solana-cli-tools - -### Test - -Testing through `pytest`: - -``` -$ python3 -m pytest -``` - -Note: the tests all run against a `solana-test-validator` with short epochs of 64 -slots (25.6 seconds exactly). Some tests wait for epoch changes, so they take -time, roughly 90 seconds total at the time of this writing. - -### Formatting - -``` -$ flake8 bot spl_token stake stake_pool system tests vote -``` - -### Type Checker - -``` -$ mypy bot stake stake_pool tests vote spl_token system -``` - -## Delegation Bots - -The `./bot` directory contains sample stake pool delegation bot implementations: - -* `rebalance`: simple bot to make the amount delegated to each validator -uniform, while also maintaining some SOL in the reserve if desired. Can be run -with the stake pool address, staker keypair, and SOL to leave in the reserve: - -``` -$ python3 bot/rebalance.py Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR staker.json 10.5 -``` diff --git a/stake-pool/py/bot/__init__.py b/stake-pool/py/bot/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/stake-pool/py/bot/rebalance.py b/stake-pool/py/bot/rebalance.py deleted file mode 100644 index bc656a87591..00000000000 --- a/stake-pool/py/bot/rebalance.py +++ /dev/null @@ -1,132 +0,0 @@ -import argparse -import asyncio -import json - -from solana.keypair import Keypair -from solana.publickey import PublicKey -from solana.rpc.async_api import AsyncClient -from solana.rpc.commitment import Confirmed - -from stake.constants import STAKE_LEN, LAMPORTS_PER_SOL -from stake_pool.actions import decrease_validator_stake, increase_validator_stake, update_stake_pool -from stake_pool.constants import MINIMUM_ACTIVE_STAKE -from stake_pool.state import StakePool, ValidatorList - - -async def get_client(endpoint: str) -> AsyncClient: - print(f'Connecting to network at {endpoint}') - async_client = AsyncClient(endpoint=endpoint, commitment=Confirmed) - total_attempts = 10 - current_attempt = 0 - while not await async_client.is_connected(): - if current_attempt == total_attempts: - raise Exception("Could not connect to test validator") - else: - current_attempt += 1 - await asyncio.sleep(1) - return async_client - - -async def rebalance(endpoint: str, stake_pool_address: PublicKey, staker: Keypair, retained_reserve_amount: float): - async_client = await get_client(endpoint) - - resp = await async_client.get_epoch_info(commitment=Confirmed) - epoch = resp['result']['epoch'] - resp = await async_client.get_account_info(stake_pool_address, commitment=Confirmed) - data = resp['result']['value']['data'] - stake_pool = StakePool.decode(data[0], data[1]) - - print(f'Stake pool last update epoch {stake_pool.last_update_epoch}, current epoch {epoch}') - if stake_pool.last_update_epoch != epoch: - print('Updating stake pool') - await update_stake_pool(async_client, staker, stake_pool_address) - resp = await async_client.get_account_info(stake_pool_address, commitment=Confirmed) - data = resp['result']['value']['data'] - stake_pool = StakePool.decode(data[0], data[1]) - - resp = await async_client.get_minimum_balance_for_rent_exemption(STAKE_LEN) - stake_rent_exemption = resp['result'] - retained_reserve_lamports = int(retained_reserve_amount * LAMPORTS_PER_SOL) - - resp = await async_client.get_account_info(stake_pool.validator_list, commitment=Confirmed) - data = resp['result']['value']['data'] - validator_list = ValidatorList.decode(data[0], data[1]) - - print('Stake pool stats:') - print(f'* {stake_pool.total_lamports} total lamports') - num_validators = len(validator_list.validators) - print(f'* {num_validators} validators') - print(f'* Retaining {retained_reserve_lamports} lamports in the reserve') - lamports_per_validator = (stake_pool.total_lamports - retained_reserve_lamports) // num_validators - num_increases = sum([ - 1 for validator in validator_list.validators - if validator.transient_stake_lamports == 0 and validator.active_stake_lamports < lamports_per_validator - ]) - total_usable_lamports = stake_pool.total_lamports - retained_reserve_lamports - num_increases * stake_rent_exemption - lamports_per_validator = total_usable_lamports // num_validators - print(f'* {lamports_per_validator} lamports desired per validator') - - futures = [] - for validator in validator_list.validators: - if validator.transient_stake_lamports != 0: - print(f'Skipping {validator.vote_account_address}: {validator.transient_stake_lamports} transient lamports') - else: - if validator.active_stake_lamports > lamports_per_validator: - lamports_to_decrease = validator.active_stake_lamports - lamports_per_validator - if lamports_to_decrease <= stake_rent_exemption: - print(f'Skipping decrease on {validator.vote_account_address}, \ -currently at {validator.active_stake_lamports} lamports, \ -decrease of {lamports_to_decrease} below the rent exmption') - else: - futures.append(decrease_validator_stake( - async_client, staker, staker, stake_pool_address, - validator.vote_account_address, lamports_to_decrease - )) - elif validator.active_stake_lamports < lamports_per_validator: - lamports_to_increase = lamports_per_validator - validator.active_stake_lamports - if lamports_to_increase < MINIMUM_ACTIVE_STAKE: - print(f'Skipping increase on {validator.vote_account_address}, \ -currently at {validator.active_stake_lamports} lamports, \ -increase of {lamports_to_increase} less than the minimum of {MINIMUM_ACTIVE_STAKE}') - else: - futures.append(increase_validator_stake( - async_client, staker, staker, stake_pool_address, - validator.vote_account_address, lamports_to_increase - )) - else: - print(f'{validator.vote_account_address}: already at {lamports_per_validator}') - - print('Executing strategy') - await asyncio.gather(*futures) - print('Done') - await async_client.close() - - -def keypair_from_file(keyfile_name: str) -> Keypair: - with open(keyfile_name, 'r') as keyfile: - data = keyfile.read() - int_list = json.loads(data) - bytes_list = [value.to_bytes(1, 'little') for value in int_list] - return Keypair.from_secret_key(b''.join(bytes_list)) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='Rebalance stake evenly between all the validators in a stake pool.') - parser.add_argument('stake_pool', metavar='STAKE_POOL_ADDRESS', type=str, - help='Stake pool to rebalance, given by a public key in base-58,\ - e.g. Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR') - parser.add_argument('staker', metavar='STAKER_KEYPAIR', type=str, - help='Staker for the stake pool, given by a keypair file, e.g. staker.json') - parser.add_argument('reserve_amount', metavar='RESERVE_AMOUNT', type=float, - help='Amount of SOL to keep in the reserve, e.g. 10.5') - parser.add_argument('--endpoint', metavar='ENDPOINT_URL', type=str, - default='https://api.mainnet-beta.solana.com', - help='RPC endpoint to use, e.g. https://api.mainnet-beta.solana.com') - - args = parser.parse_args() - stake_pool = PublicKey(args.stake_pool) - staker = keypair_from_file(args.staker) - print(f'Rebalancing stake pool {stake_pool}') - print(f'Staker public key: {staker.public_key}') - print(f'Amount to leave in the reserve: {args.reserve_amount} SOL') - asyncio.run(rebalance(args.endpoint, stake_pool, staker, args.reserve_amount)) diff --git a/stake-pool/py/optional-requirements.txt b/stake-pool/py/optional-requirements.txt deleted file mode 100644 index 5aa593192f4..00000000000 --- a/stake-pool/py/optional-requirements.txt +++ /dev/null @@ -1,15 +0,0 @@ -attrs==22.1.0 -flake8==5.0.3 -iniconfig==1.1.1 -mccabe==0.7.0 -mypy==0.971 -mypy-extensions==0.4.3 -packaging==21.3 -pluggy==1.0.0 -py==1.11.0 -pycodestyle==2.9.0 -pyflakes==2.5.0 -pyparsing==3.0.9 -pytest==7.1.2 -pytest-asyncio==0.19.0 -tomli==2.0.1 diff --git a/stake-pool/py/requirements.txt b/stake-pool/py/requirements.txt deleted file mode 100644 index 1b72ffc61ad..00000000000 --- a/stake-pool/py/requirements.txt +++ /dev/null @@ -1,19 +0,0 @@ -anyio==3.6.1 -base58==2.1.1 -cachetools==4.2.4 -certifi==2022.6.15 -cffi==1.15.1 -charset-normalizer==2.1.0 -construct==2.10.68 -h11==0.12.0 -httpcore==0.15.0 -httpx==0.23.0 -idna==3.3 -pycparser==2.21 -PyNaCl==1.5.0 -requests==2.28.1 -rfc3986==1.5.0 -sniffio==1.2.0 -solana==0.18.1 -typing_extensions==4.3.0 -urllib3==1.26.11 diff --git a/stake-pool/py/spl_token/__init__.py b/stake-pool/py/spl_token/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/stake-pool/py/spl_token/actions.py b/stake-pool/py/spl_token/actions.py deleted file mode 100644 index 6c00a9285cf..00000000000 --- a/stake-pool/py/spl_token/actions.py +++ /dev/null @@ -1,57 +0,0 @@ -from solana.publickey import PublicKey -from solana.keypair import Keypair -from solana.rpc.async_api import AsyncClient -from solana.rpc.commitment import Confirmed -from solana.rpc.types import TxOpts -from solana.transaction import Transaction -import solana.system_program as sys - -from spl.token.constants import TOKEN_PROGRAM_ID -from spl.token.async_client import AsyncToken -from spl.token._layouts import MINT_LAYOUT -import spl.token.instructions as spl_token - - -async def create_associated_token_account( - client: AsyncClient, - payer: Keypair, - owner: PublicKey, - mint: PublicKey -) -> PublicKey: - txn = Transaction() - create_txn = spl_token.create_associated_token_account( - payer=payer.public_key, owner=owner, mint=mint - ) - txn.add(create_txn) - await client.send_transaction(txn, payer, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed)) - return create_txn.keys[1].pubkey - - -async def create_mint(client: AsyncClient, payer: Keypair, mint: Keypair, mint_authority: PublicKey): - mint_balance = await AsyncToken.get_min_balance_rent_for_exempt_for_mint(client) - print(f"Creating pool token mint {mint.public_key}") - txn = Transaction() - txn.add( - sys.create_account( - sys.CreateAccountParams( - from_pubkey=payer.public_key, - new_account_pubkey=mint.public_key, - lamports=mint_balance, - space=MINT_LAYOUT.sizeof(), - program_id=TOKEN_PROGRAM_ID, - ) - ) - ) - txn.add( - spl_token.initialize_mint( - spl_token.InitializeMintParams( - program_id=TOKEN_PROGRAM_ID, - mint=mint.public_key, - decimals=9, - mint_authority=mint_authority, - freeze_authority=None, - ) - ) - ) - await client.send_transaction( - txn, payer, mint, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed)) diff --git a/stake-pool/py/stake/__init__.py b/stake-pool/py/stake/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/stake-pool/py/stake/actions.py b/stake-pool/py/stake/actions.py deleted file mode 100644 index 2963a43da62..00000000000 --- a/stake-pool/py/stake/actions.py +++ /dev/null @@ -1,87 +0,0 @@ -from solana.publickey import PublicKey -from solana.keypair import Keypair -from solana.rpc.async_api import AsyncClient -from solana.rpc.commitment import Confirmed -from solana.rpc.types import TxOpts -from solana.sysvar import SYSVAR_CLOCK_PUBKEY, SYSVAR_STAKE_HISTORY_PUBKEY -from solana.transaction import Transaction -import solana.system_program as sys - -from stake.constants import STAKE_LEN, STAKE_PROGRAM_ID, SYSVAR_STAKE_CONFIG_ID -from stake.state import Authorized, Lockup, StakeAuthorize -import stake.instructions as st - - -async def create_stake(client: AsyncClient, payer: Keypair, stake: Keypair, authority: PublicKey, lamports: int): - print(f"Creating stake {stake.public_key}") - resp = await client.get_minimum_balance_for_rent_exemption(STAKE_LEN) - txn = Transaction() - txn.add( - sys.create_account( - sys.CreateAccountParams( - from_pubkey=payer.public_key, - new_account_pubkey=stake.public_key, - lamports=resp['result'] + lamports, - space=STAKE_LEN, - program_id=STAKE_PROGRAM_ID, - ) - ) - ) - txn.add( - st.initialize( - st.InitializeParams( - stake=stake.public_key, - authorized=Authorized( - staker=authority, - withdrawer=authority, - ), - lockup=Lockup( - unix_timestamp=0, - epoch=0, - custodian=sys.SYS_PROGRAM_ID, - ) - ) - ) - ) - await client.send_transaction( - txn, payer, stake, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed)) - - -async def delegate_stake(client: AsyncClient, payer: Keypair, staker: Keypair, stake: PublicKey, vote: PublicKey): - txn = Transaction() - txn.add( - st.delegate_stake( - st.DelegateStakeParams( - stake=stake, - vote=vote, - clock_sysvar=SYSVAR_CLOCK_PUBKEY, - stake_history_sysvar=SYSVAR_STAKE_HISTORY_PUBKEY, - stake_config_id=SYSVAR_STAKE_CONFIG_ID, - staker=staker.public_key, - ) - ) - ) - signers = [payer, staker] if payer != staker else [payer] - await client.send_transaction( - txn, *signers, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed)) - - -async def authorize( - client: AsyncClient, payer: Keypair, authority: Keypair, stake: PublicKey, - new_authority: PublicKey, stake_authorize: StakeAuthorize -): - txn = Transaction() - txn.add( - st.authorize( - st.AuthorizeParams( - stake=stake, - clock_sysvar=SYSVAR_CLOCK_PUBKEY, - authority=authority.public_key, - new_authority=new_authority, - stake_authorize=stake_authorize, - ) - ) - ) - signers = [payer, authority] if payer != authority else [payer] - await client.send_transaction( - txn, *signers, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed)) diff --git a/stake-pool/py/stake/constants.py b/stake-pool/py/stake/constants.py deleted file mode 100644 index 344a8a5e768..00000000000 --- a/stake-pool/py/stake/constants.py +++ /dev/null @@ -1,18 +0,0 @@ -"""Stake Program Constants.""" - -from solana.publickey import PublicKey - -STAKE_PROGRAM_ID: PublicKey = PublicKey("Stake11111111111111111111111111111111111111") -"""Public key that identifies the Stake program.""" - -SYSVAR_STAKE_CONFIG_ID: PublicKey = PublicKey("StakeConfig11111111111111111111111111111111") -"""Public key that identifies the Stake config sysvar.""" - -STAKE_LEN: int = 200 -"""Size of stake account.""" - -LAMPORTS_PER_SOL: int = 1_000_000_000 -"""Number of lamports per SOL""" - -MINIMUM_DELEGATION: int = LAMPORTS_PER_SOL -"""Minimum delegation allowed by the stake program""" diff --git a/stake-pool/py/stake/instructions.py b/stake-pool/py/stake/instructions.py deleted file mode 100644 index f4b116bac5b..00000000000 --- a/stake-pool/py/stake/instructions.py +++ /dev/null @@ -1,178 +0,0 @@ -"""Stake Program Instructions.""" - -from enum import IntEnum -from typing import NamedTuple - -from construct import Switch # type: ignore -from construct import Int32ul, Pass # type: ignore -from construct import Bytes, Struct - -from solana.publickey import PublicKey -from solana.sysvar import SYSVAR_RENT_PUBKEY -from solana.transaction import AccountMeta, TransactionInstruction - -from stake.constants import STAKE_PROGRAM_ID -from stake.state import AUTHORIZED_LAYOUT, LOCKUP_LAYOUT, Authorized, Lockup, StakeAuthorize - -PUBLIC_KEY_LAYOUT = Bytes(32) - - -class InitializeParams(NamedTuple): - """Initialize stake transaction params.""" - - stake: PublicKey - """`[w]` Uninitialized stake account.""" - authorized: Authorized - """Information about the staker and withdrawer keys.""" - lockup: Lockup - """Stake lockup, if any.""" - - -class DelegateStakeParams(NamedTuple): - """Initialize stake transaction params.""" - - stake: PublicKey - """`[w]` Uninitialized stake account.""" - vote: PublicKey - """`[]` Vote account to which this stake will be delegated.""" - clock_sysvar: PublicKey - """`[]` Clock sysvar.""" - stake_history_sysvar: PublicKey - """`[]` Stake history sysvar that carries stake warmup/cooldown history.""" - stake_config_id: PublicKey - """`[]` Address of config account that carries stake config.""" - staker: PublicKey - """`[s]` Stake authority.""" - - -class AuthorizeParams(NamedTuple): - """Authorize stake transaction params.""" - - stake: PublicKey - """`[w]` Initialized stake account to modify.""" - clock_sysvar: PublicKey - """`[]` Clock sysvar.""" - authority: PublicKey - """`[s]` Current stake authority.""" - - # Params - new_authority: PublicKey - """New authority's public key.""" - stake_authorize: StakeAuthorize - """Type of authority to modify, staker or withdrawer.""" - - -class InstructionType(IntEnum): - """Stake Instruction Types.""" - - INITIALIZE = 0 - AUTHORIZE = 1 - DELEGATE_STAKE = 2 - SPLIT = 3 - WITHDRAW = 4 - DEACTIVATE = 5 - SET_LOCKUP = 6 - MERGE = 7 - AUTHORIZE_WITH_SEED = 8 - INITIALIZE_CHECKED = 9 - AUTHORIZED_CHECKED = 10 - AUTHORIZED_CHECKED_WITH_SEED = 11 - SET_LOCKUP_CHECKED = 12 - - -INITIALIZE_LAYOUT = Struct( - "authorized" / AUTHORIZED_LAYOUT, - "lockup" / LOCKUP_LAYOUT, -) - - -AUTHORIZE_LAYOUT = Struct( - "new_authority" / PUBLIC_KEY_LAYOUT, - "stake_authorize" / Int32ul, -) - - -INSTRUCTIONS_LAYOUT = Struct( - "instruction_type" / Int32ul, - "args" - / Switch( - lambda this: this.instruction_type, - { - InstructionType.INITIALIZE: INITIALIZE_LAYOUT, - InstructionType.AUTHORIZE: AUTHORIZE_LAYOUT, - InstructionType.DELEGATE_STAKE: Pass, - InstructionType.SPLIT: Pass, - InstructionType.WITHDRAW: Pass, - InstructionType.DEACTIVATE: Pass, - InstructionType.SET_LOCKUP: Pass, - InstructionType.MERGE: Pass, - InstructionType.AUTHORIZE_WITH_SEED: Pass, - InstructionType.INITIALIZE_CHECKED: Pass, - InstructionType.AUTHORIZED_CHECKED: Pass, - InstructionType.AUTHORIZED_CHECKED_WITH_SEED: Pass, - InstructionType.SET_LOCKUP_CHECKED: Pass, - }, - ), -) - - -def initialize(params: InitializeParams) -> TransactionInstruction: - """Creates a transaction instruction to initialize a new stake.""" - return TransactionInstruction( - keys=[ - AccountMeta(pubkey=params.stake, is_signer=False, is_writable=True), - AccountMeta(pubkey=SYSVAR_RENT_PUBKEY, is_signer=False, is_writable=False), - ], - program_id=STAKE_PROGRAM_ID, - data=INSTRUCTIONS_LAYOUT.build( - dict( - instruction_type=InstructionType.INITIALIZE, - args=dict( - authorized=params.authorized.as_bytes_dict(), - lockup=params.lockup.as_bytes_dict(), - ), - ) - ) - ) - - -def delegate_stake(params: DelegateStakeParams) -> TransactionInstruction: - """Creates an instruction to delegate a stake account.""" - return TransactionInstruction( - keys=[ - AccountMeta(pubkey=params.stake, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.vote, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.clock_sysvar, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.stake_history_sysvar, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.stake_config_id, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.staker, is_signer=True, is_writable=False), - ], - program_id=STAKE_PROGRAM_ID, - data=INSTRUCTIONS_LAYOUT.build( - dict( - instruction_type=InstructionType.DELEGATE_STAKE, - args=None, - ) - ) - ) - - -def authorize(params: AuthorizeParams) -> TransactionInstruction: - """Creates an instruction to change the authority on a stake account.""" - return TransactionInstruction( - keys=[ - AccountMeta(pubkey=params.stake, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.clock_sysvar, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.authority, is_signer=True, is_writable=False), - ], - program_id=STAKE_PROGRAM_ID, - data=INSTRUCTIONS_LAYOUT.build( - dict( - instruction_type=InstructionType.AUTHORIZE, - args={ - 'new_authority': bytes(params.new_authority), - 'stake_authorize': params.stake_authorize, - }, - ) - ) - ) diff --git a/stake-pool/py/stake/state.py b/stake-pool/py/stake/state.py deleted file mode 100644 index 9ff48d34aec..00000000000 --- a/stake-pool/py/stake/state.py +++ /dev/null @@ -1,132 +0,0 @@ -"""Stake State.""" - -from enum import IntEnum -from typing import NamedTuple, Dict -from construct import Bytes, Container, Struct, Float64l, Int32ul, Int64ul # type: ignore - -from solana.publickey import PublicKey -from solana.utils.helpers import decode_byte_string - -PUBLIC_KEY_LAYOUT = Bytes(32) - - -class Lockup(NamedTuple): - """Lockup for a stake account.""" - unix_timestamp: int - epoch: int - custodian: PublicKey - - @classmethod - def decode_container(cls, container: Container): - return Lockup( - unix_timestamp=container['unix_timestamp'], - epoch=container['epoch'], - custodian=PublicKey(container['custodian']), - ) - - def as_bytes_dict(self) -> Dict: - self_dict = self._asdict() - self_dict['custodian'] = bytes(self_dict['custodian']) - return self_dict - - -class Authorized(NamedTuple): - """Define who is authorized to change a stake.""" - staker: PublicKey - withdrawer: PublicKey - - def as_bytes_dict(self) -> Dict: - return { - 'staker': bytes(self.staker), - 'withdrawer': bytes(self.withdrawer), - } - - -class StakeAuthorize(IntEnum): - """Stake Authorization Types.""" - STAKER = 0 - WITHDRAWER = 1 - - -class StakeStateType(IntEnum): - """Stake State Types.""" - UNINITIALIZED = 0 - INITIALIZED = 1 - STAKE = 2 - REWARDS_POOL = 3 - - -class StakeState(NamedTuple): - state_type: StakeStateType - state: Container - - """Stake state.""" - @classmethod - def decode(cls, data: str, encoding: str): - data_bytes = decode_byte_string(data, encoding) - parsed = STAKE_STATE_LAYOUT.parse(data_bytes) - return StakeState( - state_type=parsed['state_type'], - state=parsed['state'], - ) - - -LOCKUP_LAYOUT = Struct( - "unix_timestamp" / Int64ul, - "epoch" / Int64ul, - "custodian" / PUBLIC_KEY_LAYOUT, -) - - -AUTHORIZED_LAYOUT = Struct( - "staker" / PUBLIC_KEY_LAYOUT, - "withdrawer" / PUBLIC_KEY_LAYOUT, -) - -META_LAYOUT = Struct( - "rent_exempt_reserve" / Int64ul, - "authorized" / AUTHORIZED_LAYOUT, - "lockup" / LOCKUP_LAYOUT, -) - -META_LAYOUT = Struct( - "rent_exempt_reserve" / Int64ul, - "authorized" / AUTHORIZED_LAYOUT, - "lockup" / LOCKUP_LAYOUT, -) - -DELEGATION_LAYOUT = Struct( - "voter_pubkey" / PUBLIC_KEY_LAYOUT, - "stake" / Int64ul, - "activation_epoch" / Int64ul, - "deactivation_epoch" / Int64ul, - "warmup_cooldown_rate" / Float64l, -) - -STAKE_LAYOUT = Struct( - "delegation" / DELEGATION_LAYOUT, - "credits_observed" / Int64ul, -) - -STAKE_AND_META_LAYOUT = Struct( - "meta" / META_LAYOUT, - "stake" / STAKE_LAYOUT, -) - -STAKE_STATE_LAYOUT = Struct( - "state_type" / Int32ul, - "state" / STAKE_AND_META_LAYOUT, - # NOTE: This can be done better, but was mainly needed for testing. Ideally, - # we would have something like: - # - # Switch( - # lambda this: this.state, - # { - # StakeStateType.UNINITIALIZED: Pass, - # StakeStateType.INITIALIZED: META_LAYOUT, - # StakeStateType.STAKE: STAKE_AND_META_LAYOUT, - # } - # ), - # - # Unfortunately, it didn't work. -) diff --git a/stake-pool/py/stake_pool/__init__.py b/stake-pool/py/stake_pool/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/stake-pool/py/stake_pool/actions.py b/stake-pool/py/stake_pool/actions.py deleted file mode 100644 index 970205a3039..00000000000 --- a/stake-pool/py/stake_pool/actions.py +++ /dev/null @@ -1,582 +0,0 @@ -from typing import Tuple - -from solana.keypair import Keypair -from solana.publickey import PublicKey -from solana.rpc.async_api import AsyncClient -from solana.rpc.commitment import Confirmed -from solana.rpc.types import TxOpts -from solana.sysvar import SYSVAR_CLOCK_PUBKEY, SYSVAR_RENT_PUBKEY, SYSVAR_STAKE_HISTORY_PUBKEY -from solana.transaction import Transaction -import solana.system_program as sys - -from spl.token.constants import TOKEN_PROGRAM_ID - -from stake.constants import STAKE_PROGRAM_ID, STAKE_LEN, SYSVAR_STAKE_CONFIG_ID -import stake.instructions as st -from stake.state import StakeAuthorize -from stake_pool.constants import \ - MAX_VALIDATORS_TO_UPDATE, \ - MINIMUM_RESERVE_LAMPORTS, \ - STAKE_POOL_PROGRAM_ID, \ - find_stake_program_address, \ - find_transient_stake_program_address, \ - find_withdraw_authority_program_address -from stake_pool.state import STAKE_POOL_LAYOUT, ValidatorList, Fee, StakePool -import stake_pool.instructions as sp - -from stake.actions import create_stake -from spl_token.actions import create_mint, create_associated_token_account - - -async def create(client: AsyncClient, manager: Keypair, - stake_pool: Keypair, validator_list: Keypair, - pool_mint: PublicKey, reserve_stake: PublicKey, - manager_fee_account: PublicKey, fee: Fee, referral_fee: int): - resp = await client.get_minimum_balance_for_rent_exemption(STAKE_POOL_LAYOUT.sizeof()) - pool_balance = resp['result'] - txn = Transaction() - txn.add( - sys.create_account( - sys.CreateAccountParams( - from_pubkey=manager.public_key, - new_account_pubkey=stake_pool.public_key, - lamports=pool_balance, - space=STAKE_POOL_LAYOUT.sizeof(), - program_id=STAKE_POOL_PROGRAM_ID, - ) - ) - ) - max_validators = 2950 # current supported max by the program, go big! - validator_list_size = ValidatorList.calculate_validator_list_size(max_validators) - resp = await client.get_minimum_balance_for_rent_exemption(validator_list_size) - validator_list_balance = resp['result'] - txn.add( - sys.create_account( - sys.CreateAccountParams( - from_pubkey=manager.public_key, - new_account_pubkey=validator_list.public_key, - lamports=validator_list_balance, - space=validator_list_size, - program_id=STAKE_POOL_PROGRAM_ID, - ) - ) - ) - await client.send_transaction( - txn, manager, stake_pool, validator_list, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed)) - - (withdraw_authority, seed) = find_withdraw_authority_program_address( - STAKE_POOL_PROGRAM_ID, stake_pool.public_key) - txn = Transaction() - txn.add( - sp.initialize( - sp.InitializeParams( - program_id=STAKE_POOL_PROGRAM_ID, - stake_pool=stake_pool.public_key, - manager=manager.public_key, - staker=manager.public_key, - withdraw_authority=withdraw_authority, - validator_list=validator_list.public_key, - reserve_stake=reserve_stake, - pool_mint=pool_mint, - manager_fee_account=manager_fee_account, - token_program_id=TOKEN_PROGRAM_ID, - epoch_fee=fee, - withdrawal_fee=fee, - deposit_fee=fee, - referral_fee=referral_fee, - max_validators=max_validators, - ) - ) - ) - await client.send_transaction( - txn, manager, validator_list, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed)) - - -async def create_all(client: AsyncClient, manager: Keypair, fee: Fee, referral_fee: int) -> Tuple[PublicKey, PublicKey]: - stake_pool = Keypair() - validator_list = Keypair() - (pool_withdraw_authority, seed) = find_withdraw_authority_program_address( - STAKE_POOL_PROGRAM_ID, stake_pool.public_key) - - reserve_stake = Keypair() - await create_stake(client, manager, reserve_stake, pool_withdraw_authority, MINIMUM_RESERVE_LAMPORTS) - - pool_mint = Keypair() - await create_mint(client, manager, pool_mint, pool_withdraw_authority) - - manager_fee_account = await create_associated_token_account( - client, - manager, - manager.public_key, - pool_mint.public_key, - ) - - fee = Fee(numerator=1, denominator=1000) - referral_fee = 20 - await create( - client, manager, stake_pool, validator_list, pool_mint.public_key, - reserve_stake.public_key, manager_fee_account, fee, referral_fee) - return (stake_pool.public_key, validator_list.public_key) - - -async def add_validator_to_pool( - client: AsyncClient, funder: Keypair, - stake_pool_address: PublicKey, validator: PublicKey -): - resp = await client.get_account_info(stake_pool_address, commitment=Confirmed) - data = resp['result']['value']['data'] - stake_pool = StakePool.decode(data[0], data[1]) - txn = Transaction() - txn.add( - sp.add_validator_to_pool_with_vote( - STAKE_POOL_PROGRAM_ID, - stake_pool_address, - stake_pool.staker, - stake_pool.validator_list, - funder.public_key, - validator, - ) - ) - await client.send_transaction( - txn, funder, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed)) - - -async def remove_validator_from_pool( - client: AsyncClient, staker: Keypair, - stake_pool_address: PublicKey, validator: PublicKey -): - resp = await client.get_account_info(stake_pool_address, commitment=Confirmed) - data = resp['result']['value']['data'] - stake_pool = StakePool.decode(data[0], data[1]) - resp = await client.get_account_info(stake_pool.validator_list, commitment=Confirmed) - data = resp['result']['value']['data'] - validator_list = ValidatorList.decode(data[0], data[1]) - validator_info = next(x for x in validator_list.validators if x.vote_account_address == validator) - destination_stake = Keypair() - txn = Transaction() - txn.add( - sys.create_account( - sys.CreateAccountParams( - from_pubkey=staker.public_key, - new_account_pubkey=destination_stake.public_key, - lamports=0, # will get filled by split - space=STAKE_LEN, - program_id=STAKE_PROGRAM_ID, - ) - ) - ) - txn.add( - sp.remove_validator_from_pool_with_vote( - STAKE_POOL_PROGRAM_ID, - stake_pool_address, - stake_pool.staker, - stake_pool.validator_list, - staker.public_key, - validator, - validator_info.transient_seed_suffix_start, - destination_stake.public_key - ) - ) - await client.send_transaction( - txn, staker, destination_stake, - opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed)) - - -async def deposit_sol( - client: AsyncClient, funder: Keypair, stake_pool_address: PublicKey, - destination_token_account: PublicKey, amount: int, -): - resp = await client.get_account_info(stake_pool_address, commitment=Confirmed) - data = resp['result']['value']['data'] - stake_pool = StakePool.decode(data[0], data[1]) - - (withdraw_authority, seed) = find_withdraw_authority_program_address(STAKE_POOL_PROGRAM_ID, stake_pool_address) - - txn = Transaction() - txn.add( - sp.deposit_sol( - sp.DepositSolParams( - program_id=STAKE_POOL_PROGRAM_ID, - stake_pool=stake_pool_address, - withdraw_authority=withdraw_authority, - reserve_stake=stake_pool.reserve_stake, - funding_account=funder.public_key, - destination_pool_account=destination_token_account, - manager_fee_account=stake_pool.manager_fee_account, - referral_pool_account=destination_token_account, - pool_mint=stake_pool.pool_mint, - system_program_id=sys.SYS_PROGRAM_ID, - token_program_id=stake_pool.token_program_id, - amount=amount, - deposit_authority=None, - ) - ) - ) - await client.send_transaction( - txn, funder, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed)) - - -async def withdraw_sol( - client: AsyncClient, owner: Keypair, source_token_account: PublicKey, - stake_pool_address: PublicKey, destination_system_account: PublicKey, amount: int, -): - resp = await client.get_account_info(stake_pool_address, commitment=Confirmed) - data = resp['result']['value']['data'] - stake_pool = StakePool.decode(data[0], data[1]) - - (withdraw_authority, seed) = find_withdraw_authority_program_address(STAKE_POOL_PROGRAM_ID, stake_pool_address) - - txn = Transaction() - txn.add( - sp.withdraw_sol( - sp.WithdrawSolParams( - program_id=STAKE_POOL_PROGRAM_ID, - stake_pool=stake_pool_address, - withdraw_authority=withdraw_authority, - source_transfer_authority=owner.public_key, - source_pool_account=source_token_account, - reserve_stake=stake_pool.reserve_stake, - destination_system_account=destination_system_account, - manager_fee_account=stake_pool.manager_fee_account, - pool_mint=stake_pool.pool_mint, - clock_sysvar=SYSVAR_CLOCK_PUBKEY, - stake_history_sysvar=SYSVAR_STAKE_HISTORY_PUBKEY, - stake_program_id=STAKE_PROGRAM_ID, - token_program_id=stake_pool.token_program_id, - amount=amount, - sol_withdraw_authority=None, - ) - ) - ) - await client.send_transaction( - txn, owner, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed)) - - -async def deposit_stake( - client: AsyncClient, - deposit_stake_authority: Keypair, - stake_pool_address: PublicKey, - validator_vote: PublicKey, - deposit_stake: PublicKey, - destination_pool_account: PublicKey, -): - resp = await client.get_account_info(stake_pool_address, commitment=Confirmed) - data = resp['result']['value']['data'] - stake_pool = StakePool.decode(data[0], data[1]) - - (withdraw_authority, _) = find_withdraw_authority_program_address(STAKE_POOL_PROGRAM_ID, stake_pool_address) - (validator_stake, _) = find_stake_program_address( - STAKE_POOL_PROGRAM_ID, - validator_vote, - stake_pool_address, - ) - - txn = Transaction() - txn.add( - st.authorize( - st.AuthorizeParams( - stake=deposit_stake, - clock_sysvar=SYSVAR_CLOCK_PUBKEY, - authority=deposit_stake_authority.public_key, - new_authority=stake_pool.stake_deposit_authority, - stake_authorize=StakeAuthorize.STAKER, - ) - ) - ) - txn.add( - st.authorize( - st.AuthorizeParams( - stake=deposit_stake, - clock_sysvar=SYSVAR_CLOCK_PUBKEY, - authority=deposit_stake_authority.public_key, - new_authority=stake_pool.stake_deposit_authority, - stake_authorize=StakeAuthorize.WITHDRAWER, - ) - ) - ) - txn.add( - sp.deposit_stake( - sp.DepositStakeParams( - program_id=STAKE_POOL_PROGRAM_ID, - stake_pool=stake_pool_address, - validator_list=stake_pool.validator_list, - deposit_authority=stake_pool.stake_deposit_authority, - withdraw_authority=withdraw_authority, - deposit_stake=deposit_stake, - validator_stake=validator_stake, - reserve_stake=stake_pool.reserve_stake, - destination_pool_account=destination_pool_account, - manager_fee_account=stake_pool.manager_fee_account, - referral_pool_account=destination_pool_account, - pool_mint=stake_pool.pool_mint, - clock_sysvar=SYSVAR_CLOCK_PUBKEY, - stake_history_sysvar=SYSVAR_STAKE_HISTORY_PUBKEY, - token_program_id=stake_pool.token_program_id, - stake_program_id=STAKE_PROGRAM_ID, - ) - ) - ) - await client.send_transaction( - txn, deposit_stake_authority, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed)) - - -async def withdraw_stake( - client: AsyncClient, - payer: Keypair, - source_transfer_authority: Keypair, - destination_stake: Keypair, - stake_pool_address: PublicKey, - validator_vote: PublicKey, - destination_stake_authority: PublicKey, - source_pool_account: PublicKey, - amount: int, -): - resp = await client.get_account_info(stake_pool_address, commitment=Confirmed) - data = resp['result']['value']['data'] - stake_pool = StakePool.decode(data[0], data[1]) - - (withdraw_authority, _) = find_withdraw_authority_program_address(STAKE_POOL_PROGRAM_ID, stake_pool_address) - (validator_stake, _) = find_stake_program_address( - STAKE_POOL_PROGRAM_ID, - validator_vote, - stake_pool_address, - ) - - resp = await client.get_minimum_balance_for_rent_exemption(STAKE_LEN) - stake_rent_exemption = resp['result'] - - txn = Transaction() - txn.add( - sys.create_account( - sys.CreateAccountParams( - from_pubkey=payer.public_key, - new_account_pubkey=destination_stake.public_key, - lamports=stake_rent_exemption, - space=STAKE_LEN, - program_id=STAKE_PROGRAM_ID, - ) - ) - ) - txn.add( - sp.withdraw_stake( - sp.WithdrawStakeParams( - program_id=STAKE_POOL_PROGRAM_ID, - stake_pool=stake_pool_address, - validator_list=stake_pool.validator_list, - withdraw_authority=withdraw_authority, - validator_stake=validator_stake, - destination_stake=destination_stake.public_key, - destination_stake_authority=destination_stake_authority, - source_transfer_authority=source_transfer_authority.public_key, - source_pool_account=source_pool_account, - manager_fee_account=stake_pool.manager_fee_account, - pool_mint=stake_pool.pool_mint, - clock_sysvar=SYSVAR_CLOCK_PUBKEY, - token_program_id=stake_pool.token_program_id, - stake_program_id=STAKE_PROGRAM_ID, - amount=amount, - ) - ) - ) - signers = [payer, source_transfer_authority, destination_stake] \ - if payer != source_transfer_authority else [payer, destination_stake] - await client.send_transaction( - txn, *signers, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed)) - - -async def update_stake_pool(client: AsyncClient, payer: Keypair, stake_pool_address: PublicKey): - """Create and send all instructions to completely update a stake pool after epoch change.""" - resp = await client.get_account_info(stake_pool_address, commitment=Confirmed) - data = resp['result']['value']['data'] - stake_pool = StakePool.decode(data[0], data[1]) - resp = await client.get_account_info(stake_pool.validator_list, commitment=Confirmed) - data = resp['result']['value']['data'] - validator_list = ValidatorList.decode(data[0], data[1]) - (withdraw_authority, seed) = find_withdraw_authority_program_address(STAKE_POOL_PROGRAM_ID, stake_pool_address) - update_list_instructions = [] - validator_chunks = [ - validator_list.validators[i:i+MAX_VALIDATORS_TO_UPDATE] - for i in range(0, len(validator_list.validators), MAX_VALIDATORS_TO_UPDATE) - ] - start_index = 0 - for validator_chunk in validator_chunks: - validator_and_transient_stake_pairs = [] - for validator in validator_chunk: - (validator_stake_address, _) = find_stake_program_address( - STAKE_POOL_PROGRAM_ID, - validator.vote_account_address, - stake_pool_address, - ) - validator_and_transient_stake_pairs.append(validator_stake_address) - (transient_stake_address, _) = find_transient_stake_program_address( - STAKE_POOL_PROGRAM_ID, - validator.vote_account_address, - stake_pool_address, - validator.transient_seed_suffix_start, - ) - validator_and_transient_stake_pairs.append(transient_stake_address) - update_list_instructions.append( - sp.update_validator_list_balance( - sp.UpdateValidatorListBalanceParams( - program_id=STAKE_POOL_PROGRAM_ID, - stake_pool=stake_pool_address, - withdraw_authority=withdraw_authority, - validator_list=stake_pool.validator_list, - reserve_stake=stake_pool.reserve_stake, - clock_sysvar=SYSVAR_CLOCK_PUBKEY, - stake_history_sysvar=SYSVAR_STAKE_HISTORY_PUBKEY, - stake_program_id=STAKE_PROGRAM_ID, - validator_and_transient_stake_pairs=validator_and_transient_stake_pairs, - start_index=start_index, - no_merge=False, - ) - ) - ) - start_index += MAX_VALIDATORS_TO_UPDATE - if update_list_instructions: - last_instruction = update_list_instructions.pop() - for update_list_instruction in update_list_instructions: - txn = Transaction() - txn.add(update_list_instruction) - await client.send_transaction( - txn, payer, opts=TxOpts(skip_confirmation=True, preflight_commitment=Confirmed)) - txn = Transaction() - txn.add(last_instruction) - await client.send_transaction( - txn, payer, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed)) - txn = Transaction() - txn.add( - sp.update_stake_pool_balance( - sp.UpdateStakePoolBalanceParams( - program_id=STAKE_POOL_PROGRAM_ID, - stake_pool=stake_pool_address, - withdraw_authority=withdraw_authority, - validator_list=stake_pool.validator_list, - reserve_stake=stake_pool.reserve_stake, - manager_fee_account=stake_pool.manager_fee_account, - pool_mint=stake_pool.pool_mint, - token_program_id=stake_pool.token_program_id, - ) - ) - ) - txn.add( - sp.cleanup_removed_validator_entries( - sp.CleanupRemovedValidatorEntriesParams( - program_id=STAKE_POOL_PROGRAM_ID, - stake_pool=stake_pool_address, - validator_list=stake_pool.validator_list, - ) - ) - ) - await client.send_transaction( - txn, payer, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed)) - - -async def increase_validator_stake( - client: AsyncClient, payer: Keypair, staker: Keypair, stake_pool_address: PublicKey, - validator_vote: PublicKey, lamports: int -): - resp = await client.get_account_info(stake_pool_address, commitment=Confirmed) - data = resp['result']['value']['data'] - stake_pool = StakePool.decode(data[0], data[1]) - - resp = await client.get_account_info(stake_pool.validator_list, commitment=Confirmed) - data = resp['result']['value']['data'] - validator_list = ValidatorList.decode(data[0], data[1]) - (withdraw_authority, seed) = find_withdraw_authority_program_address(STAKE_POOL_PROGRAM_ID, stake_pool_address) - - validator_info = next(x for x in validator_list.validators if x.vote_account_address == validator_vote) - transient_stake_seed = validator_info.transient_seed_suffix_start + 1 # bump up by one to avoid reuse - (transient_stake, _) = find_transient_stake_program_address( - STAKE_POOL_PROGRAM_ID, - validator_info.vote_account_address, - stake_pool_address, - transient_stake_seed, - ) - (validator_stake, _) = find_stake_program_address( - STAKE_POOL_PROGRAM_ID, - validator_info.vote_account_address, - stake_pool_address, - ) - - txn = Transaction() - txn.add( - sp.increase_validator_stake( - sp.IncreaseValidatorStakeParams( - program_id=STAKE_POOL_PROGRAM_ID, - stake_pool=stake_pool_address, - staker=staker.public_key, - withdraw_authority=withdraw_authority, - validator_list=stake_pool.validator_list, - reserve_stake=stake_pool.reserve_stake, - transient_stake=transient_stake, - validator_stake=validator_stake, - validator_vote=validator_vote, - clock_sysvar=SYSVAR_CLOCK_PUBKEY, - rent_sysvar=SYSVAR_RENT_PUBKEY, - stake_history_sysvar=SYSVAR_STAKE_HISTORY_PUBKEY, - stake_config_sysvar=SYSVAR_STAKE_CONFIG_ID, - system_program_id=sys.SYS_PROGRAM_ID, - stake_program_id=STAKE_PROGRAM_ID, - lamports=lamports, - transient_stake_seed=transient_stake_seed, - ) - ) - ) - - signers = [payer, staker] if payer != staker else [payer] - await client.send_transaction( - txn, *signers, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed)) - - -async def decrease_validator_stake( - client: AsyncClient, payer: Keypair, staker: Keypair, stake_pool_address: PublicKey, - validator_vote: PublicKey, lamports: int -): - resp = await client.get_account_info(stake_pool_address, commitment=Confirmed) - data = resp['result']['value']['data'] - stake_pool = StakePool.decode(data[0], data[1]) - - resp = await client.get_account_info(stake_pool.validator_list, commitment=Confirmed) - data = resp['result']['value']['data'] - validator_list = ValidatorList.decode(data[0], data[1]) - (withdraw_authority, seed) = find_withdraw_authority_program_address(STAKE_POOL_PROGRAM_ID, stake_pool_address) - - validator_info = next(x for x in validator_list.validators if x.vote_account_address == validator_vote) - (validator_stake, _) = find_stake_program_address( - STAKE_POOL_PROGRAM_ID, - validator_info.vote_account_address, - stake_pool_address, - ) - transient_stake_seed = validator_info.transient_seed_suffix_start + 1 # bump up by one to avoid reuse - (transient_stake, _) = find_transient_stake_program_address( - STAKE_POOL_PROGRAM_ID, - validator_info.vote_account_address, - stake_pool_address, - transient_stake_seed, - ) - - txn = Transaction() - txn.add( - sp.decrease_validator_stake( - sp.DecreaseValidatorStakeParams( - program_id=STAKE_POOL_PROGRAM_ID, - stake_pool=stake_pool_address, - staker=staker.public_key, - withdraw_authority=withdraw_authority, - validator_list=stake_pool.validator_list, - validator_stake=validator_stake, - transient_stake=transient_stake, - clock_sysvar=SYSVAR_CLOCK_PUBKEY, - rent_sysvar=SYSVAR_RENT_PUBKEY, - system_program_id=sys.SYS_PROGRAM_ID, - stake_program_id=STAKE_PROGRAM_ID, - lamports=lamports, - transient_stake_seed=transient_stake_seed, - ) - ) - ) - - signers = [payer, staker] if payer != staker else [payer] - await client.send_transaction( - txn, *signers, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed)) diff --git a/stake-pool/py/stake_pool/constants.py b/stake-pool/py/stake_pool/constants.py deleted file mode 100644 index 3af4dce4fda..00000000000 --- a/stake-pool/py/stake_pool/constants.py +++ /dev/null @@ -1,81 +0,0 @@ -"""SPL Stake Pool Constants.""" - -from typing import Tuple - -from solana.publickey import PublicKey -from stake.constants import MINIMUM_DELEGATION - -STAKE_POOL_PROGRAM_ID: PublicKey = PublicKey("SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy") -"""Public key that identifies the SPL Stake Pool program.""" - -MAX_VALIDATORS_TO_UPDATE: int = 5 -"""Maximum number of validators to update during UpdateValidatorListBalance.""" - -MINIMUM_RESERVE_LAMPORTS: int = MINIMUM_DELEGATION -"""Minimum balance required in the stake pool reserve""" - -MINIMUM_ACTIVE_STAKE: int = MINIMUM_DELEGATION -"""Minimum active delegated staked required in a stake account""" - - -def find_deposit_authority_program_address( - program_id: PublicKey, - stake_pool_address: PublicKey, -) -> Tuple[PublicKey, int]: - """Generates the deposit authority program address for the stake pool""" - return PublicKey.find_program_address( - [bytes(stake_pool_address), AUTHORITY_DEPOSIT], - program_id, - ) - - -def find_withdraw_authority_program_address( - program_id: PublicKey, - stake_pool_address: PublicKey, -) -> Tuple[PublicKey, int]: - """Generates the withdraw authority program address for the stake pool""" - return PublicKey.find_program_address( - [bytes(stake_pool_address), AUTHORITY_WITHDRAW], - program_id, - ) - - -def find_stake_program_address( - program_id: PublicKey, - vote_account_address: PublicKey, - stake_pool_address: PublicKey, -) -> Tuple[PublicKey, int]: - """Generates the stake program address for a validator's vote account""" - return PublicKey.find_program_address( - [ - bytes(vote_account_address), - bytes(stake_pool_address), - ], - program_id, - ) - - -def find_transient_stake_program_address( - program_id: PublicKey, - vote_account_address: PublicKey, - stake_pool_address: PublicKey, - seed: int, -) -> Tuple[PublicKey, int]: - """Generates the stake program address for a validator's vote account""" - return PublicKey.find_program_address( - [ - TRANSIENT_STAKE_SEED_PREFIX, - bytes(vote_account_address), - bytes(stake_pool_address), - seed.to_bytes(8, 'little'), - ], - program_id, - ) - - -AUTHORITY_DEPOSIT = b"deposit" -"""Seed used to derive the default stake pool deposit authority.""" -AUTHORITY_WITHDRAW = b"withdraw" -"""Seed used to derive the stake pool withdraw authority.""" -TRANSIENT_STAKE_SEED_PREFIX = b"transient" -"""Seed used to derive transient stake accounts.""" diff --git a/stake-pool/py/stake_pool/instructions.py b/stake-pool/py/stake_pool/instructions.py deleted file mode 100644 index dfc3c8a3034..00000000000 --- a/stake-pool/py/stake_pool/instructions.py +++ /dev/null @@ -1,918 +0,0 @@ -"""SPL Stake Pool Instructions.""" - -from enum import IntEnum -from typing import List, NamedTuple, Optional -from construct import Struct, Switch, Int8ul, Int32ul, Int64ul, Pass # type: ignore - -from solana.publickey import PublicKey -from solana.transaction import AccountMeta, TransactionInstruction -from solana.system_program import SYS_PROGRAM_ID -from solana.sysvar import SYSVAR_CLOCK_PUBKEY, SYSVAR_RENT_PUBKEY, SYSVAR_STAKE_HISTORY_PUBKEY -from spl.token.constants import TOKEN_PROGRAM_ID - -from stake.constants import STAKE_PROGRAM_ID, SYSVAR_STAKE_CONFIG_ID -from stake_pool.constants import find_stake_program_address, find_transient_stake_program_address -from stake_pool.constants import find_withdraw_authority_program_address -from stake_pool.constants import STAKE_POOL_PROGRAM_ID -from stake_pool.state import Fee, FEE_LAYOUT - - -class PreferredValidatorType(IntEnum): - """Specifies the validator type for SetPreferredValidator instruction.""" - - DEPOSIT = 0 - """Specifies the preferred deposit validator.""" - WITHDRAW = 1 - """Specifies the preferred withdraw validator.""" - - -class FundingType(IntEnum): - """Defines which authority to update in the `SetFundingAuthority` instruction.""" - - STAKE_DEPOSIT = 0 - """Sets the stake deposit authority.""" - SOL_DEPOSIT = 1 - """Sets the SOL deposit authority.""" - SOL_WITHDRAW = 2 - """Sets the SOL withdraw authority.""" - - -class InitializeParams(NamedTuple): - """Initialize token mint transaction params.""" - - # Accounts - program_id: PublicKey - """SPL Stake Pool program account.""" - stake_pool: PublicKey - """[w] Stake Pool account to initialize.""" - manager: PublicKey - """[s] Manager for new stake pool.""" - staker: PublicKey - """[] Staker for the new stake pool.""" - withdraw_authority: PublicKey - """[] Withdraw authority for the new stake pool.""" - validator_list: PublicKey - """[w] Uninitialized validator list account for the new stake pool.""" - reserve_stake: PublicKey - """[] Reserve stake account.""" - pool_mint: PublicKey - """[w] Pool token mint account.""" - manager_fee_account: PublicKey - """[w] Manager's fee account""" - token_program_id: PublicKey - """[] SPL Token program id.""" - - # Params - epoch_fee: Fee - """Fee assessed as percentage of rewards.""" - withdrawal_fee: Fee - """Fee charged per withdrawal.""" - deposit_fee: Fee - """Fee charged per deposit.""" - referral_fee: int - """Percentage [0-100] of deposit fee that goes to referrer.""" - max_validators: int - """Maximum number of possible validators in the pool.""" - - # Optional - deposit_authority: Optional[PublicKey] = None - """[] Optional deposit authority that must sign all deposits.""" - - -class AddValidatorToPoolParams(NamedTuple): - """(Staker only) Adds stake account delegated to validator to the pool's list of managed validators.""" - - program_id: PublicKey - """SPL Stake Pool program account.""" - stake_pool: PublicKey - """`[w]` Stake pool.""" - staker: PublicKey - """`[s]` Staker.""" - funding_account: PublicKey - """`[ws]` Funding account (must be a system account).""" - withdraw_authority: PublicKey - """`[]` Stake pool withdraw authority.""" - validator_list: PublicKey - """`[w]` Validator stake list storage account.""" - validator_stake: PublicKey - """`[w]` Stake account to add to the pool.""" - validator_vote: PublicKey - """`[]` Validator this stake account will be delegated to.""" - rent_sysvar: PublicKey - """`[]` Rent sysvar.""" - clock_sysvar: PublicKey - """`[]` Clock sysvar.""" - stake_history_sysvar: PublicKey - """'[]' Stake history sysvar.""" - stake_config_sysvar: PublicKey - """'[]' Stake config sysvar.""" - system_program_id: PublicKey - """`[]` System program.""" - stake_program_id: PublicKey - """`[]` Stake program.""" - - -class RemoveValidatorFromPoolParams(NamedTuple): - """(Staker only) Removes validator from the pool.""" - - program_id: PublicKey - """SPL Stake Pool program account.""" - stake_pool: PublicKey - """`[w]` Stake pool.""" - staker: PublicKey - """`[s]` Staker.""" - withdraw_authority: PublicKey - """`[]` Stake pool withdraw authority.""" - new_stake_authority: PublicKey - """`[]` New stake / withdraw authority on the split stake account.""" - validator_list: PublicKey - """`[w]` Validator stake list storage account.""" - validator_stake: PublicKey - """`[w]` Stake account to remove from the pool.""" - transient_stake: PublicKey - """`[]` Transient stake account, to check that there's no activation ongoing.""" - destination_stake: PublicKey - """`[w]` Destination stake account, to receive the minimum SOL from the validator stake account.""" - clock_sysvar: PublicKey - """'[]' Stake config sysvar.""" - stake_program_id: PublicKey - """`[]` Stake program.""" - - -class DecreaseValidatorStakeParams(NamedTuple): - """(Staker only) Decrease active stake on a validator, eventually moving it to the reserve""" - - # Accounts - program_id: PublicKey - """SPL Stake Pool program account.""" - stake_pool: PublicKey - """`[]` Stake pool.""" - staker: PublicKey - """`[s]` Staker.""" - withdraw_authority: PublicKey - """`[]` Stake pool withdraw authority.""" - validator_list: PublicKey - """`[w]` Validator stake list storage account.""" - validator_stake: PublicKey - """`[w]` Canonical stake to split from.""" - transient_stake: PublicKey - """`[w]` Transient stake account to receive split.""" - clock_sysvar: PublicKey - """`[]` Clock sysvar.""" - rent_sysvar: PublicKey - """`[]` Rent sysvar.""" - system_program_id: PublicKey - """`[]` System program.""" - stake_program_id: PublicKey - """`[]` Stake program.""" - - # Params - lamports: int - """Amount of lamports to split into the transient stake account.""" - transient_stake_seed: int - """Seed to used to create the transient stake account.""" - - -class IncreaseValidatorStakeParams(NamedTuple): - """(Staker only) Increase stake on a validator from the reserve account.""" - - # Accounts - program_id: PublicKey - """SPL Stake Pool program account.""" - stake_pool: PublicKey - """`[]` Stake pool.""" - staker: PublicKey - """`[s]` Staker.""" - withdraw_authority: PublicKey - """`[]` Stake pool withdraw authority.""" - validator_list: PublicKey - """`[w]` Validator stake list storage account.""" - reserve_stake: PublicKey - """`[w]` Stake pool's reserve.""" - transient_stake: PublicKey - """`[w]` Transient stake account to receive split.""" - validator_stake: PublicKey - """`[]` Canonical stake account to check.""" - validator_vote: PublicKey - """`[]` Validator vote account to delegate to.""" - clock_sysvar: PublicKey - """`[]` Clock sysvar.""" - rent_sysvar: PublicKey - """`[]` Rent sysvar.""" - stake_history_sysvar: PublicKey - """'[]' Stake history sysvar.""" - stake_config_sysvar: PublicKey - """'[]' Stake config sysvar.""" - system_program_id: PublicKey - """`[]` System program.""" - stake_program_id: PublicKey - """`[]` Stake program.""" - - # Params - lamports: int - """Amount of lamports to split into the transient stake account.""" - transient_stake_seed: int - """Seed to used to create the transient stake account.""" - - -class SetPreferredValidatorParams(NamedTuple): - pass - - -class UpdateValidatorListBalanceParams(NamedTuple): - """Updates balances of validator and transient stake accounts in the pool.""" - - # Accounts - program_id: PublicKey - """SPL Stake Pool program account.""" - stake_pool: PublicKey - """`[]` Stake pool.""" - withdraw_authority: PublicKey - """`[]` Stake pool withdraw authority.""" - validator_list: PublicKey - """`[w]` Validator stake list storage account.""" - reserve_stake: PublicKey - """`[w]` Stake pool's reserve.""" - clock_sysvar: PublicKey - """`[]` Clock sysvar.""" - stake_history_sysvar: PublicKey - """'[]' Stake history sysvar.""" - stake_program_id: PublicKey - """`[]` Stake program.""" - validator_and_transient_stake_pairs: List[PublicKey] - """[] N pairs of validator and transient stake accounts""" - - # Params - start_index: int - """Index to start updating on the validator list.""" - no_merge: bool - """If true, don't try merging transient stake accounts.""" - - -class UpdateStakePoolBalanceParams(NamedTuple): - """Updates total pool balance based on balances in the reserve and validator list.""" - - program_id: PublicKey - """SPL Stake Pool program account.""" - stake_pool: PublicKey - """`[w]` Stake pool.""" - withdraw_authority: PublicKey - """`[]` Stake pool withdraw authority.""" - validator_list: PublicKey - """`[w]` Validator stake list storage account.""" - reserve_stake: PublicKey - """`[w]` Stake pool's reserve.""" - manager_fee_account: PublicKey - """`[w]` Account to receive pool fee tokens.""" - pool_mint: PublicKey - """`[w]` Pool mint account.""" - token_program_id: PublicKey - """`[]` Pool token program.""" - - -class CleanupRemovedValidatorEntriesParams(NamedTuple): - """Cleans up validator stake account entries marked as `ReadyForRemoval`""" - - program_id: PublicKey - """SPL Stake Pool program account.""" - stake_pool: PublicKey - """`[w]` Stake pool.""" - validator_list: PublicKey - """`[w]` Validator stake list storage account.""" - - -class DepositStakeParams(NamedTuple): - """Deposits a stake account into the pool in exchange for pool tokens""" - - program_id: PublicKey - """SPL Stake Pool program account.""" - stake_pool: PublicKey - """`[w]` Stake pool""" - validator_list: PublicKey - """`[w]` Validator stake list storage account""" - deposit_authority: PublicKey - """`[s]/[]` Stake pool deposit authority""" - withdraw_authority: PublicKey - """`[]` Stake pool withdraw authority""" - deposit_stake: PublicKey - """`[w]` Stake account to join the pool (stake's withdraw authority set to the stake pool deposit authority)""" - validator_stake: PublicKey - """`[w]` Validator stake account for the stake account to be merged with""" - reserve_stake: PublicKey - """`[w]` Reserve stake account, to withdraw rent exempt reserve""" - destination_pool_account: PublicKey - """`[w]` User account to receive pool tokens""" - manager_fee_account: PublicKey - """`[w]` Account to receive pool fee tokens""" - referral_pool_account: PublicKey - """`[w]` Account to receive a portion of pool fee tokens as referral fees""" - pool_mint: PublicKey - """`[w]` Pool token mint account""" - clock_sysvar: PublicKey - """`[]` Sysvar clock account""" - stake_history_sysvar: PublicKey - """`[]` Sysvar stake history account""" - token_program_id: PublicKey - """`[]` Pool token program id""" - stake_program_id: PublicKey - """`[]` Stake program id""" - - -class WithdrawStakeParams(NamedTuple): - """Withdraws a stake account from the pool in exchange for pool tokens""" - - program_id: PublicKey - """SPL Stake Pool program account.""" - stake_pool: PublicKey - """`[w]` Stake pool""" - validator_list: PublicKey - """`[w]` Validator stake list storage account""" - withdraw_authority: PublicKey - """`[]` Stake pool withdraw authority""" - validator_stake: PublicKey - """`[w]` Validator or reserve stake account to split""" - destination_stake: PublicKey - """`[w]` Unitialized stake account to receive withdrawal""" - destination_stake_authority: PublicKey - """`[]` User account to set as a new withdraw authority""" - source_transfer_authority: PublicKey - """`[s]` User transfer authority, for pool token account""" - source_pool_account: PublicKey - """`[w]` User account with pool tokens to burn from""" - manager_fee_account: PublicKey - """`[w]` Account to receive pool fee tokens""" - pool_mint: PublicKey - """`[w]` Pool token mint account""" - clock_sysvar: PublicKey - """`[]` Sysvar clock account""" - token_program_id: PublicKey - """`[]` Pool token program id""" - stake_program_id: PublicKey - """`[]` Stake program id""" - - # Params - amount: int - """Amount of pool tokens to burn in exchange for stake""" - - -class SetManagerParams(NamedTuple): - pass - - -class SetFeeParams(NamedTuple): - pass - - -class SetStakerParams(NamedTuple): - pass - - -class DepositSolParams(NamedTuple): - """Deposit SOL directly into the pool's reserve account. The output is a "pool" token - representing ownership into the pool. Inputs are converted to the current ratio.""" - - # Accounts - program_id: PublicKey - """SPL Stake Pool program account.""" - stake_pool: PublicKey - """`[w]` Stake pool.""" - withdraw_authority: PublicKey - """`[]` Stake pool withdraw authority.""" - reserve_stake: PublicKey - """`[w]` Stake pool's reserve.""" - funding_account: PublicKey - """`[ws]` Funding account (must be a system account).""" - destination_pool_account: PublicKey - """`[w]` User account to receive pool tokens.""" - manager_fee_account: PublicKey - """`[w]` Manager's pool token account to receive deposit fee.""" - referral_pool_account: PublicKey - """`[w]` Referrer pool token account to receive referral fee.""" - pool_mint: PublicKey - """`[w]` Pool token mint.""" - system_program_id: PublicKey - """`[]` System program.""" - token_program_id: PublicKey - """`[]` Token program.""" - - # Params - amount: int - """Amount of SOL to deposit""" - - # Optional - deposit_authority: Optional[PublicKey] = None - """`[s]` (Optional) Stake pool sol deposit authority.""" - - -class SetFundingAuthorityParams(NamedTuple): - pass - - -class WithdrawSolParams(NamedTuple): - """Withdraw SOL directly from the pool's reserve account.""" - - # Accounts - program_id: PublicKey - """SPL Stake Pool program account.""" - stake_pool: PublicKey - """`[w]` Stake pool.""" - withdraw_authority: PublicKey - """`[]` Stake pool withdraw authority.""" - source_transfer_authority: PublicKey - """`[s]` Transfer authority for user pool token account.""" - source_pool_account: PublicKey - """`[w]` User's pool token account to burn pool tokens.""" - reserve_stake: PublicKey - """`[w]` Stake pool's reserve.""" - destination_system_account: PublicKey - """`[w]` Destination system account to receive lamports from the reserve.""" - manager_fee_account: PublicKey - """`[w]` Manager's pool token account to receive fee.""" - pool_mint: PublicKey - """`[w]` Pool token mint.""" - clock_sysvar: PublicKey - """`[]` Clock sysvar.""" - stake_history_sysvar: PublicKey - """'[]' Stake history sysvar.""" - stake_program_id: PublicKey - """`[]` Stake program.""" - token_program_id: PublicKey - """`[]` Token program.""" - - # Params - amount: int - """Amount of pool tokens to burn""" - - # Optional - sol_withdraw_authority: Optional[PublicKey] = None - """`[s]` (Optional) Stake pool sol withdraw authority.""" - - -class InstructionType(IntEnum): - """Stake Pool Instruction Types.""" - - INITIALIZE = 0 - ADD_VALIDATOR_TO_POOL = 1 - REMOVE_VALIDATOR_FROM_POOL = 2 - DECREASE_VALIDATOR_STAKE = 3 - INCREASE_VALIDATOR_STAKE = 4 - SET_PREFERRED_VALIDATOR = 5 - UPDATE_VALIDATOR_LIST_BALANCE = 6 - UPDATE_STAKE_POOL_BALANCE = 7 - CLEANUP_REMOVED_VALIDATOR_ENTRIES = 8 - DEPOSIT_STAKE = 9 - WITHDRAW_STAKE = 10 - SET_MANAGER = 11 - SET_FEE = 12 - SET_STAKER = 13 - DEPOSIT_SOL = 14 - SET_FUNDING_AUTHORITY = 15 - WITHDRAW_SOL = 16 - - -INITIALIZE_LAYOUT = Struct( - "epoch_fee" / FEE_LAYOUT, - "withdrawal_fee" / FEE_LAYOUT, - "deposit_fee" / FEE_LAYOUT, - "referral_fee" / Int8ul, - "max_validators" / Int32ul, -) - -MOVE_STAKE_LAYOUT = Struct( - "lamports" / Int64ul, - "transient_stake_seed" / Int64ul, -) - -UPDATE_VALIDATOR_LIST_BALANCE_LAYOUT = Struct( - "start_index" / Int32ul, - "no_merge" / Int8ul, -) - -AMOUNT_LAYOUT = Struct( - "amount" / Int64ul -) - -INSTRUCTIONS_LAYOUT = Struct( - "instruction_type" / Int8ul, - "args" - / Switch( - lambda this: this.instruction_type, - { - InstructionType.INITIALIZE: INITIALIZE_LAYOUT, - InstructionType.ADD_VALIDATOR_TO_POOL: Pass, - InstructionType.REMOVE_VALIDATOR_FROM_POOL: Pass, - InstructionType.DECREASE_VALIDATOR_STAKE: MOVE_STAKE_LAYOUT, - InstructionType.INCREASE_VALIDATOR_STAKE: MOVE_STAKE_LAYOUT, - InstructionType.SET_PREFERRED_VALIDATOR: Pass, # TODO - InstructionType.UPDATE_VALIDATOR_LIST_BALANCE: UPDATE_VALIDATOR_LIST_BALANCE_LAYOUT, - InstructionType.UPDATE_STAKE_POOL_BALANCE: Pass, - InstructionType.CLEANUP_REMOVED_VALIDATOR_ENTRIES: Pass, - InstructionType.DEPOSIT_STAKE: Pass, - InstructionType.WITHDRAW_STAKE: AMOUNT_LAYOUT, - InstructionType.SET_MANAGER: Pass, # TODO - InstructionType.SET_FEE: Pass, # TODO - InstructionType.SET_STAKER: Pass, # TODO - InstructionType.DEPOSIT_SOL: AMOUNT_LAYOUT, - InstructionType.SET_FUNDING_AUTHORITY: Pass, # TODO - InstructionType.WITHDRAW_SOL: AMOUNT_LAYOUT, - }, - ), -) - - -def initialize(params: InitializeParams) -> TransactionInstruction: - """Creates a transaction instruction to initialize a new stake pool.""" - - data = INSTRUCTIONS_LAYOUT.build( - dict( - instruction_type=InstructionType.INITIALIZE, - args=dict( - epoch_fee=params.epoch_fee._asdict(), - withdrawal_fee=params.withdrawal_fee._asdict(), - deposit_fee=params.deposit_fee._asdict(), - referral_fee=params.referral_fee, - max_validators=params.max_validators - ), - ) - ) - keys = [ - AccountMeta(pubkey=params.stake_pool, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.manager, is_signer=True, is_writable=False), - AccountMeta(pubkey=params.staker, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.withdraw_authority, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.validator_list, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.reserve_stake, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.pool_mint, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.manager_fee_account, is_signer=False, is_writable=True), - AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False), - ] - if params.deposit_authority: - keys.append( - AccountMeta(pubkey=params.deposit_authority, is_signer=True, is_writable=False), - ) - return TransactionInstruction( - keys=keys, - program_id=params.program_id, - data=data, - ) - - -def add_validator_to_pool(params: AddValidatorToPoolParams) -> TransactionInstruction: - """Creates instruction to add a validator to the pool.""" - return TransactionInstruction( - keys=[ - AccountMeta(pubkey=params.stake_pool, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.staker, is_signer=True, is_writable=False), - AccountMeta(pubkey=params.funding_account, is_signer=True, is_writable=True), - AccountMeta(pubkey=params.withdraw_authority, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.validator_list, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.validator_stake, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.validator_vote, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.rent_sysvar, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.clock_sysvar, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.stake_history_sysvar, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.stake_config_sysvar, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.system_program_id, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.stake_program_id, is_signer=False, is_writable=False), - ], - program_id=params.program_id, - data=INSTRUCTIONS_LAYOUT.build( - dict( - instruction_type=InstructionType.ADD_VALIDATOR_TO_POOL, - args=None - ) - ) - ) - - -def add_validator_to_pool_with_vote( - program_id: PublicKey, - stake_pool: PublicKey, - staker: PublicKey, - validator_list: PublicKey, - funder: PublicKey, - validator: PublicKey -) -> TransactionInstruction: - """Creates instruction to add a validator based on their vote account address.""" - (withdraw_authority, seed) = find_withdraw_authority_program_address(program_id, stake_pool) - (validator_stake, seed) = find_stake_program_address(program_id, validator, stake_pool) - return add_validator_to_pool( - AddValidatorToPoolParams( - program_id=STAKE_POOL_PROGRAM_ID, - stake_pool=stake_pool, - staker=staker, - funding_account=funder, - withdraw_authority=withdraw_authority, - validator_list=validator_list, - validator_stake=validator_stake, - validator_vote=validator, - rent_sysvar=SYSVAR_RENT_PUBKEY, - clock_sysvar=SYSVAR_CLOCK_PUBKEY, - stake_history_sysvar=SYSVAR_STAKE_HISTORY_PUBKEY, - stake_config_sysvar=SYSVAR_STAKE_CONFIG_ID, - system_program_id=SYS_PROGRAM_ID, - stake_program_id=STAKE_PROGRAM_ID, - ) - ) - - -def remove_validator_from_pool(params: RemoveValidatorFromPoolParams) -> TransactionInstruction: - """Creates instruction to remove a validator from the pool.""" - return TransactionInstruction( - keys=[ - AccountMeta(pubkey=params.stake_pool, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.staker, is_signer=True, is_writable=False), - AccountMeta(pubkey=params.withdraw_authority, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.new_stake_authority, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.validator_list, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.validator_stake, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.transient_stake, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.destination_stake, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.clock_sysvar, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.stake_program_id, is_signer=False, is_writable=False), - ], - program_id=params.program_id, - data=INSTRUCTIONS_LAYOUT.build( - dict( - instruction_type=InstructionType.REMOVE_VALIDATOR_FROM_POOL, - args=None - ) - ) - ) - - -def remove_validator_from_pool_with_vote( - program_id: PublicKey, - stake_pool: PublicKey, - staker: PublicKey, - validator_list: PublicKey, - new_stake_authority: PublicKey, - validator: PublicKey, - transient_stake_seed: int, - destination_stake: PublicKey, -) -> TransactionInstruction: - """Creates instruction to remove a validator based on their vote account address.""" - (withdraw_authority, seed) = find_withdraw_authority_program_address(program_id, stake_pool) - (validator_stake, seed) = find_stake_program_address(program_id, validator, stake_pool) - (transient_stake, seed) = find_transient_stake_program_address( - program_id, validator, stake_pool, transient_stake_seed) - return remove_validator_from_pool( - RemoveValidatorFromPoolParams( - program_id=STAKE_POOL_PROGRAM_ID, - stake_pool=stake_pool, - staker=staker, - withdraw_authority=withdraw_authority, - new_stake_authority=new_stake_authority, - validator_list=validator_list, - validator_stake=validator_stake, - transient_stake=transient_stake, - destination_stake=destination_stake, - clock_sysvar=SYSVAR_CLOCK_PUBKEY, - stake_program_id=STAKE_PROGRAM_ID, - ) - ) - - -def deposit_stake(params: DepositStakeParams) -> TransactionInstruction: - """Creates a transaction instruction to deposit SOL into a stake pool.""" - keys = [ - AccountMeta(pubkey=params.stake_pool, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.validator_list, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.deposit_authority, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.withdraw_authority, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.deposit_stake, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.validator_stake, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.reserve_stake, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.destination_pool_account, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.manager_fee_account, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.referral_pool_account, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.pool_mint, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.clock_sysvar, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.stake_history_sysvar, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.token_program_id, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.stake_program_id, is_signer=False, is_writable=False), - ] - return TransactionInstruction( - keys=keys, - program_id=params.program_id, - data=INSTRUCTIONS_LAYOUT.build( - dict( - instruction_type=InstructionType.DEPOSIT_STAKE, - args=None, - ) - ) - ) - - -def withdraw_stake(params: WithdrawStakeParams) -> TransactionInstruction: - """Creates a transaction instruction to withdraw SOL from a stake pool.""" - return TransactionInstruction( - keys=[ - AccountMeta(pubkey=params.stake_pool, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.validator_list, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.withdraw_authority, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.validator_stake, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.destination_stake, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.destination_stake_authority, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.source_transfer_authority, is_signer=True, is_writable=False), - AccountMeta(pubkey=params.source_pool_account, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.manager_fee_account, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.pool_mint, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.clock_sysvar, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.token_program_id, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.stake_program_id, is_signer=False, is_writable=False), - ], - program_id=params.program_id, - data=INSTRUCTIONS_LAYOUT.build( - dict( - instruction_type=InstructionType.WITHDRAW_STAKE, - args={'amount': params.amount} - ) - ) - ) - - -def deposit_sol(params: DepositSolParams) -> TransactionInstruction: - """Creates a transaction instruction to deposit SOL into a stake pool.""" - keys = [ - AccountMeta(pubkey=params.stake_pool, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.withdraw_authority, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.reserve_stake, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.funding_account, is_signer=True, is_writable=True), - AccountMeta(pubkey=params.destination_pool_account, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.manager_fee_account, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.referral_pool_account, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.pool_mint, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.system_program_id, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.token_program_id, is_signer=False, is_writable=False), - ] - if params.deposit_authority: - keys.append(AccountMeta(pubkey=params.deposit_authority, is_signer=True, is_writable=False)) - return TransactionInstruction( - keys=keys, - program_id=params.program_id, - data=INSTRUCTIONS_LAYOUT.build( - dict( - instruction_type=InstructionType.DEPOSIT_SOL, - args={'amount': params.amount} - ) - ) - ) - - -def withdraw_sol(params: WithdrawSolParams) -> TransactionInstruction: - """Creates a transaction instruction to withdraw SOL from a stake pool.""" - keys = [ - AccountMeta(pubkey=params.stake_pool, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.withdraw_authority, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.source_transfer_authority, is_signer=True, is_writable=False), - AccountMeta(pubkey=params.source_pool_account, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.reserve_stake, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.destination_system_account, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.manager_fee_account, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.pool_mint, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.clock_sysvar, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.stake_history_sysvar, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.stake_program_id, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.token_program_id, is_signer=False, is_writable=False), - ] - - if params.sol_withdraw_authority: - AccountMeta(pubkey=params.sol_withdraw_authority, is_signer=True, is_writable=False) - - return TransactionInstruction( - keys=keys, - program_id=params.program_id, - data=INSTRUCTIONS_LAYOUT.build( - dict( - instruction_type=InstructionType.WITHDRAW_SOL, - args={'amount': params.amount} - ) - ) - ) - - -def update_validator_list_balance(params: UpdateValidatorListBalanceParams) -> TransactionInstruction: - """Creates instruction to update a set of validators in the stake pool.""" - keys = [ - AccountMeta(pubkey=params.stake_pool, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.withdraw_authority, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.validator_list, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.reserve_stake, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.clock_sysvar, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.stake_history_sysvar, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.stake_program_id, is_signer=False, is_writable=False), - ] - keys.extend([ - AccountMeta(pubkey=pubkey, is_signer=False, is_writable=True) - for pubkey in params.validator_and_transient_stake_pairs - ]) - return TransactionInstruction( - keys=keys, - program_id=params.program_id, - data=INSTRUCTIONS_LAYOUT.build( - dict( - instruction_type=InstructionType.UPDATE_VALIDATOR_LIST_BALANCE, - args={'start_index': params.start_index, 'no_merge': params.no_merge} - ) - ) - ) - - -def update_stake_pool_balance(params: UpdateStakePoolBalanceParams) -> TransactionInstruction: - """Creates instruction to update the overall stake pool balance.""" - return TransactionInstruction( - keys=[ - AccountMeta(pubkey=params.stake_pool, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.withdraw_authority, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.validator_list, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.reserve_stake, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.manager_fee_account, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.pool_mint, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.token_program_id, is_signer=False, is_writable=False), - ], - program_id=params.program_id, - data=INSTRUCTIONS_LAYOUT.build( - dict( - instruction_type=InstructionType.UPDATE_STAKE_POOL_BALANCE, - args=None, - ) - ) - ) - - -def cleanup_removed_validator_entries(params: CleanupRemovedValidatorEntriesParams) -> TransactionInstruction: - """Creates instruction to cleanup removed validator entries.""" - return TransactionInstruction( - keys=[ - AccountMeta(pubkey=params.stake_pool, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.validator_list, is_signer=False, is_writable=True), - ], - program_id=params.program_id, - data=INSTRUCTIONS_LAYOUT.build( - dict( - instruction_type=InstructionType.CLEANUP_REMOVED_VALIDATOR_ENTRIES, - args=None, - ) - ) - ) - - -def increase_validator_stake(params: IncreaseValidatorStakeParams) -> TransactionInstruction: - """Creates instruction to increase the stake on a validator.""" - return TransactionInstruction( - keys=[ - AccountMeta(pubkey=params.stake_pool, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.staker, is_signer=True, is_writable=False), - AccountMeta(pubkey=params.withdraw_authority, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.validator_list, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.reserve_stake, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.transient_stake, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.validator_stake, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.validator_vote, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.clock_sysvar, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.rent_sysvar, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.stake_history_sysvar, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.stake_config_sysvar, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.system_program_id, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.stake_program_id, is_signer=False, is_writable=False), - ], - program_id=params.program_id, - data=INSTRUCTIONS_LAYOUT.build( - dict( - instruction_type=InstructionType.INCREASE_VALIDATOR_STAKE, - args={ - 'lamports': params.lamports, - 'transient_stake_seed': params.transient_stake_seed - } - ) - ) - ) - - -def decrease_validator_stake(params: DecreaseValidatorStakeParams) -> TransactionInstruction: - """Creates instruction to decrease the stake on a validator.""" - return TransactionInstruction( - keys=[ - AccountMeta(pubkey=params.stake_pool, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.staker, is_signer=True, is_writable=False), - AccountMeta(pubkey=params.withdraw_authority, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.validator_list, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.validator_stake, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.transient_stake, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.clock_sysvar, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.rent_sysvar, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.system_program_id, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.stake_program_id, is_signer=False, is_writable=False), - ], - program_id=params.program_id, - data=INSTRUCTIONS_LAYOUT.build( - dict( - instruction_type=InstructionType.DECREASE_VALIDATOR_STAKE, - args={ - 'lamports': params.lamports, - 'transient_stake_seed': params.transient_stake_seed - } - ) - ) - ) diff --git a/stake-pool/py/stake_pool/state.py b/stake-pool/py/stake_pool/state.py deleted file mode 100644 index 8791c3e25f0..00000000000 --- a/stake-pool/py/stake_pool/state.py +++ /dev/null @@ -1,322 +0,0 @@ -"""SPL Stake Pool State.""" - -from enum import IntEnum -from typing import List, NamedTuple, Optional -from construct import Bytes, Container, Struct, Switch, Int8ul, Int32ul, Int64ul, Pass # type: ignore - -from solana.publickey import PublicKey -from solana.utils.helpers import decode_byte_string -from stake.state import Lockup, LOCKUP_LAYOUT - -PUBLIC_KEY_LAYOUT = Bytes(32) - - -def decode_optional_publickey(container: Container) -> Optional[PublicKey]: - if container: - return PublicKey(container.popitem()[1]) - else: - return None - - -class Fee(NamedTuple): - """Fee assessed by the stake pool, expressed as numerator / denominator.""" - numerator: int - denominator: int - - @classmethod - def decode_container(cls, container: Container): - return Fee( - numerator=container['numerator'], - denominator=container['denominator'], - ) - - @classmethod - def decode_optional_container(cls, container: Container): - if container: - return cls.decode_container(container) - else: - return None - - -class StakePool(NamedTuple): - """Stake pool and all its data.""" - manager: PublicKey - staker: PublicKey - stake_deposit_authority: PublicKey - stake_withdraw_bump_seed: int - validator_list: PublicKey - reserve_stake: PublicKey - pool_mint: PublicKey - manager_fee_account: PublicKey - token_program_id: PublicKey - total_lamports: int - pool_token_supply: int - last_update_epoch: int - lockup: Lockup - epoch_fee: Fee - next_epoch_fee: Optional[Fee] - preferred_deposit_validator: Optional[PublicKey] - preferred_withdraw_validator: Optional[PublicKey] - stake_deposit_fee: Fee - stake_withdrawal_fee: Fee - next_stake_withdrawal_fee: Optional[Fee] - stake_referral_fee: int - sol_deposit_authority: Optional[PublicKey] - sol_deposit_fee: Fee - sol_referral_fee: int - sol_withdraw_authority: Optional[PublicKey] - sol_withdrawal_fee: Fee - next_sol_withdrawal_fee: Optional[Fee] - last_epoch_pool_token_supply: int - last_epoch_total_lamports: int - - @classmethod - def decode(cls, data: str, encoding: str): - data_bytes = decode_byte_string(data, encoding) - parsed = DECODE_STAKE_POOL_LAYOUT.parse(data_bytes) - return StakePool( - manager=PublicKey(parsed['manager']), - staker=PublicKey(parsed['staker']), - stake_deposit_authority=PublicKey(parsed['stake_deposit_authority']), - stake_withdraw_bump_seed=parsed['stake_withdraw_bump_seed'], - validator_list=PublicKey(parsed['validator_list']), - reserve_stake=PublicKey(parsed['reserve_stake']), - pool_mint=PublicKey(parsed['pool_mint']), - manager_fee_account=PublicKey(parsed['manager_fee_account']), - token_program_id=PublicKey(parsed['token_program_id']), - total_lamports=parsed['total_lamports'], - pool_token_supply=parsed['pool_token_supply'], - last_update_epoch=parsed['last_update_epoch'], - lockup=Lockup.decode_container(parsed['lockup']), - epoch_fee=Fee.decode_container(parsed['epoch_fee']), - next_epoch_fee=Fee.decode_optional_container(parsed['next_epoch_fee']), - preferred_deposit_validator=decode_optional_publickey(parsed['preferred_deposit_validator']), - preferred_withdraw_validator=decode_optional_publickey(parsed['preferred_withdraw_validator']), - stake_deposit_fee=Fee.decode_container(parsed['stake_deposit_fee']), - stake_withdrawal_fee=Fee.decode_container(parsed['stake_withdrawal_fee']), - next_stake_withdrawal_fee=Fee.decode_optional_container(parsed['next_stake_withdrawal_fee']), - stake_referral_fee=parsed['stake_referral_fee'], - sol_deposit_authority=decode_optional_publickey(parsed['sol_deposit_authority']), - sol_deposit_fee=Fee.decode_container(parsed['sol_deposit_fee']), - sol_referral_fee=parsed['sol_referral_fee'], - sol_withdraw_authority=decode_optional_publickey(parsed['sol_withdraw_authority']), - sol_withdrawal_fee=Fee.decode_container(parsed['sol_withdrawal_fee']), - next_sol_withdrawal_fee=Fee.decode_optional_container(parsed['next_sol_withdrawal_fee']), - last_epoch_pool_token_supply=parsed['last_epoch_pool_token_supply'], - last_epoch_total_lamports=parsed['last_epoch_total_lamports'], - ) - - -class StakeStatus(IntEnum): - """Specifies the status of a stake on a validator in a stake pool.""" - - ACTIVE = 0 - """Stake is active and normal.""" - DEACTIVATING_TRANSIENT = 1 - """Stake has been removed, but a deactivating transient stake still exists.""" - READY_FOR_REMOVAL = 2 - """No more validator stake accounts exist, entry ready for removal.""" - - -class ValidatorStakeInfo(NamedTuple): - active_stake_lamports: int - """Amount of active stake delegated to this validator.""" - - transient_stake_lamports: int - """Amount of transient stake delegated to this validator.""" - - last_update_epoch: int - """Last epoch the active and transient stake lamports fields were updated.""" - - transient_seed_suffix_start: int - """Start of the validator transient account seed suffixes.""" - - transient_seed_suffix_end: int - """End of the validator transient account seed suffixes.""" - - status: StakeStatus - """Status of the validator stake account.""" - - vote_account_address: PublicKey - """Validator vote account address.""" - - @classmethod - def decode_container(cls, container: Container): - return ValidatorStakeInfo( - active_stake_lamports=container['active_stake_lamports'], - transient_stake_lamports=container['transient_stake_lamports'], - last_update_epoch=container['last_update_epoch'], - transient_seed_suffix_start=container['transient_seed_suffix_start'], - transient_seed_suffix_end=container['transient_seed_suffix_end'], - status=container['status'], - vote_account_address=PublicKey(container['vote_account_address']), - ) - - -class ValidatorList(NamedTuple): - """List of validators and amount staked, associated to a stake pool.""" - - max_validators: int - """Maximum number of validators possible in the list.""" - - validators: List[ValidatorStakeInfo] - """Info for each validator in the stake pool.""" - - @staticmethod - def calculate_validator_list_size(max_validators: int) -> int: - layout = VALIDATOR_LIST_LAYOUT + VALIDATOR_INFO_LAYOUT[max_validators] - return layout.sizeof() - - @classmethod - def decode(cls, data: str, encoding: str): - data_bytes = decode_byte_string(data, encoding) - parsed = DECODE_VALIDATOR_LIST_LAYOUT.parse(data_bytes) - print(parsed) - return ValidatorList( - max_validators=parsed['max_validators'], - validators=[ValidatorStakeInfo.decode_container(container) for container in parsed['validators']], - ) - - -FEE_LAYOUT = Struct( - "denominator" / Int64ul, - "numerator" / Int64ul, -) - -STAKE_POOL_LAYOUT = Struct( - "account_type" / Int8ul, - "manager" / PUBLIC_KEY_LAYOUT, - "staker" / PUBLIC_KEY_LAYOUT, - "stake_deposit_authority" / PUBLIC_KEY_LAYOUT, - "stake_withdraw_bump_seed" / Int8ul, - "validator_list" / PUBLIC_KEY_LAYOUT, - "reserve_stake" / PUBLIC_KEY_LAYOUT, - "pool_mint" / PUBLIC_KEY_LAYOUT, - "manager_fee_account" / PUBLIC_KEY_LAYOUT, - "token_program_id" / PUBLIC_KEY_LAYOUT, - "total_lamports" / Int64ul, - "pool_token_supply" / Int64ul, - "last_update_epoch" / Int64ul, - "lockup" / LOCKUP_LAYOUT, - "epoch_fee" / FEE_LAYOUT, - "next_epoch_fee_option" / Int8ul, - "next_epoch_fee" / FEE_LAYOUT, - "preferred_deposit_validator_option" / Int8ul, - "preferred_deposit_validator" / PUBLIC_KEY_LAYOUT, - "preferred_withdraw_validator_option" / Int8ul, - "preferred_withdraw_validator" / PUBLIC_KEY_LAYOUT, - "stake_deposit_fee" / FEE_LAYOUT, - "stake_withdrawal_fee" / FEE_LAYOUT, - "next_stake_withdrawal_fee_option" / Int8ul, - "next_stake_withdrawal_fee" / FEE_LAYOUT, - "stake_referral_fee" / Int8ul, - "sol_deposit_authority_option" / Int8ul, - "sol_deposit_authority" / PUBLIC_KEY_LAYOUT, - "sol_deposit_fee" / FEE_LAYOUT, - "sol_referral_fee" / Int8ul, - "sol_withdraw_authority_option" / Int8ul, - "sol_withdraw_authority" / PUBLIC_KEY_LAYOUT, - "sol_withdrawal_fee" / FEE_LAYOUT, - "next_sol_withdrawal_fee_option" / Int8ul, - "next_sol_withdrawal_fee" / FEE_LAYOUT, - "last_epoch_pool_token_supply" / Int64ul, - "last_epoch_total_lamports" / Int64ul, -) - -DECODE_STAKE_POOL_LAYOUT = Struct( - "account_type" / Int8ul, - "manager" / PUBLIC_KEY_LAYOUT, - "staker" / PUBLIC_KEY_LAYOUT, - "stake_deposit_authority" / PUBLIC_KEY_LAYOUT, - "stake_withdraw_bump_seed" / Int8ul, - "validator_list" / PUBLIC_KEY_LAYOUT, - "reserve_stake" / PUBLIC_KEY_LAYOUT, - "pool_mint" / PUBLIC_KEY_LAYOUT, - "manager_fee_account" / PUBLIC_KEY_LAYOUT, - "token_program_id" / PUBLIC_KEY_LAYOUT, - "total_lamports" / Int64ul, - "pool_token_supply" / Int64ul, - "last_update_epoch" / Int64ul, - "lockup" / LOCKUP_LAYOUT, - "epoch_fee" / FEE_LAYOUT, - "next_epoch_fee_option" / Int8ul, - "next_epoch_fee" / Switch( - lambda this: this.next_epoch_fee_option, - { - 0: Pass, - 1: FEE_LAYOUT, - }), - "preferred_deposit_validator_option" / Int8ul, - "preferred_deposit_validator" / Switch( - lambda this: this.preferred_deposit_validator_option, - { - 0: Pass, - 1: PUBLIC_KEY_LAYOUT, - }), - "preferred_withdraw_validator_option" / Int8ul, - "preferred_withdraw_validator" / Switch( - lambda this: this.preferred_withdraw_validator_option, - { - 0: Pass, - 1: PUBLIC_KEY_LAYOUT, - }), - "stake_deposit_fee" / FEE_LAYOUT, - "stake_withdrawal_fee" / FEE_LAYOUT, - "next_stake_withdrawal_fee_option" / Int8ul, - "next_stake_withdrawal_fee" / Switch( - lambda this: this.next_stake_withdrawal_fee_option, - { - 0: Pass, - 1: FEE_LAYOUT, - }), - "stake_referral_fee" / Int8ul, - "sol_deposit_authority_option" / Int8ul, - "sol_deposit_authority" / Switch( - lambda this: this.sol_deposit_authority_option, - { - 0: Pass, - 1: PUBLIC_KEY_LAYOUT, - }), - "sol_deposit_fee" / FEE_LAYOUT, - "sol_referral_fee" / Int8ul, - "sol_withdraw_authority_option" / Int8ul, - "sol_withdraw_authority" / Switch( - lambda this: this.sol_withdraw_authority_option, - { - 0: Pass, - 1: PUBLIC_KEY_LAYOUT, - }), - "sol_withdrawal_fee" / FEE_LAYOUT, - "next_sol_withdrawal_fee_option" / Int8ul, - "next_sol_withdrawal_fee" / Switch( - lambda this: this.next_sol_withdrawal_fee_option, - { - 0: Pass, - 1: FEE_LAYOUT, - }), - "last_epoch_pool_token_supply" / Int64ul, - "last_epoch_total_lamports" / Int64ul, -) - -VALIDATOR_INFO_LAYOUT = Struct( - "active_stake_lamports" / Int64ul, - "transient_stake_lamports" / Int64ul, - "last_update_epoch" / Int64ul, - "transient_seed_suffix_start" / Int64ul, - "transient_seed_suffix_end" / Int64ul, - "status" / Int8ul, - "vote_account_address" / PUBLIC_KEY_LAYOUT, -) - -VALIDATOR_LIST_LAYOUT = Struct( - "account_type" / Int8ul, - "max_validators" / Int32ul, - "validators_len" / Int32ul, -) - -DECODE_VALIDATOR_LIST_LAYOUT = Struct( - "account_type" / Int8ul, - "max_validators" / Int32ul, - "validators_len" / Int32ul, - "validators" / VALIDATOR_INFO_LAYOUT[lambda this: this.validators_len], -) diff --git a/stake-pool/py/system/__init__.py b/stake-pool/py/system/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/stake-pool/py/system/actions.py b/stake-pool/py/system/actions.py deleted file mode 100644 index 0b16a04587f..00000000000 --- a/stake-pool/py/system/actions.py +++ /dev/null @@ -1,9 +0,0 @@ -from solana.publickey import PublicKey -from solana.rpc.async_api import AsyncClient -from solana.rpc.commitment import Confirmed - - -async def airdrop(client: AsyncClient, receiver: PublicKey, lamports: int): - print(f"Airdropping {lamports} lamports to {receiver}...") - resp = await client.request_airdrop(receiver, lamports, Confirmed) - await client.confirm_transaction(resp['result'], Confirmed) diff --git a/stake-pool/py/tests/conftest.py b/stake-pool/py/tests/conftest.py deleted file mode 100644 index 9e39dda84ae..00000000000 --- a/stake-pool/py/tests/conftest.py +++ /dev/null @@ -1,111 +0,0 @@ -import asyncio -import pytest -import pytest_asyncio -import os -import shutil -import tempfile -from typing import AsyncIterator, List, Tuple -from subprocess import Popen - -from solana.keypair import Keypair -from solana.publickey import PublicKey -from solana.rpc.async_api import AsyncClient -from solana.rpc.commitment import Confirmed - -from vote.actions import create_vote -from system.actions import airdrop -from stake_pool.actions import create_all, add_validator_to_pool -from stake_pool.state import Fee - -NUM_SLOTS_PER_EPOCH: int = 32 - - -@pytest.fixture(scope="session") -def solana_test_validator(): - old_cwd = os.getcwd() - newpath = tempfile.mkdtemp() - os.chdir(newpath) - validator = Popen([ - "solana-test-validator", - "--reset", "--quiet", - "--bpf-program", "SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy", - f"{old_cwd}/../../target/deploy/spl_stake_pool.so", - "--slots-per-epoch", str(NUM_SLOTS_PER_EPOCH), - ],) - yield - validator.kill() - os.chdir(old_cwd) - shutil.rmtree(newpath) - - -@pytest_asyncio.fixture -async def validators(async_client, payer) -> List[PublicKey]: - num_validators = 3 - validators = [] - for i in range(num_validators): - vote = Keypair() - node = Keypair() - await create_vote(async_client, payer, vote, node, payer.public_key, payer.public_key, 10) - validators.append(vote.public_key) - return validators - - -@pytest_asyncio.fixture -async def stake_pool_addresses(async_client, payer, validators, waiter) -> Tuple[PublicKey, PublicKey]: - fee = Fee(numerator=1, denominator=1000) - referral_fee = 20 - # Change back to `wait_for_next_epoch_if_soon` once https://github.com/solana-labs/solana/pull/26851 is available - await waiter.wait_for_next_epoch(async_client) - stake_pool_addresses = await create_all(async_client, payer, fee, referral_fee) - for validator in validators: - await add_validator_to_pool(async_client, payer, stake_pool_addresses[0], validator) - return stake_pool_addresses - - -@pytest_asyncio.fixture -async def async_client(solana_test_validator) -> AsyncIterator[AsyncClient]: - async_client = AsyncClient(commitment=Confirmed) - total_attempts = 20 - current_attempt = 0 - while not await async_client.is_connected(): - if current_attempt == total_attempts: - raise Exception("Could not connect to test validator") - else: - current_attempt += 1 - await asyncio.sleep(1.0) - yield async_client - await async_client.close() - - -@pytest_asyncio.fixture -async def payer(async_client) -> Keypair: - payer = Keypair() - airdrop_lamports = 20_000_000_000 - await airdrop(async_client, payer.public_key, airdrop_lamports) - return payer - - -class Waiter: - @staticmethod - async def wait_for_next_epoch(async_client: AsyncClient): - resp = await async_client.get_epoch_info(commitment=Confirmed) - current_epoch = resp['result']['epoch'] - next_epoch = current_epoch - while current_epoch == next_epoch: - await asyncio.sleep(1.0) - resp = await async_client.get_epoch_info(commitment=Confirmed) - next_epoch = resp['result']['epoch'] - - @staticmethod - async def wait_for_next_epoch_if_soon(async_client: AsyncClient): - resp = await async_client.get_epoch_info(commitment=Confirmed) - if resp['result']['slotsInEpoch'] - resp['result']['slotIndex'] < NUM_SLOTS_PER_EPOCH // 2: - await Waiter.wait_for_next_epoch(async_client) - return True - else: - return False - - -@pytest.fixture -def waiter() -> Waiter: - return Waiter() diff --git a/stake-pool/py/tests/test_a_time_sensitive.py b/stake-pool/py/tests/test_a_time_sensitive.py deleted file mode 100644 index abac2005318..00000000000 --- a/stake-pool/py/tests/test_a_time_sensitive.py +++ /dev/null @@ -1,78 +0,0 @@ -"""Time sensitive test, so run it first out of the bunch.""" -import asyncio -import pytest -from solana.rpc.commitment import Confirmed -from spl.token.instructions import get_associated_token_address - -from stake.constants import STAKE_LEN -from stake_pool.actions import deposit_sol, decrease_validator_stake, increase_validator_stake, update_stake_pool -from stake_pool.constants import MINIMUM_ACTIVE_STAKE -from stake_pool.state import StakePool, ValidatorList - - -@pytest.mark.asyncio -async def test_increase_decrease_this_is_very_slow(async_client, validators, payer, stake_pool_addresses, waiter): - (stake_pool_address, validator_list_address) = stake_pool_addresses - - resp = await async_client.get_minimum_balance_for_rent_exemption(STAKE_LEN) - stake_rent_exemption = resp['result'] - increase_amount = MINIMUM_ACTIVE_STAKE * 4 - decrease_amount = increase_amount // 2 - deposit_amount = (increase_amount + stake_rent_exemption) * len(validators) - - resp = await async_client.get_account_info(stake_pool_address, commitment=Confirmed) - data = resp['result']['value']['data'] - stake_pool = StakePool.decode(data[0], data[1]) - token_account = get_associated_token_address(payer.public_key, stake_pool.pool_mint) - await deposit_sol(async_client, payer, stake_pool_address, token_account, deposit_amount) - - # increase to all - futures = [ - increase_validator_stake(async_client, payer, payer, stake_pool_address, validator, increase_amount) - for validator in validators - ] - await asyncio.gather(*futures) - - resp = await async_client.get_account_info(validator_list_address, commitment=Confirmed) - data = resp['result']['value']['data'] - validator_list = ValidatorList.decode(data[0], data[1]) - for validator in validator_list.validators: - assert validator.transient_stake_lamports == increase_amount + stake_rent_exemption - assert validator.active_stake_lamports == 0 - - print("Waiting for epoch to roll over") - await waiter.wait_for_next_epoch(async_client) - await update_stake_pool(async_client, payer, stake_pool_address) - - resp = await async_client.get_account_info(validator_list_address, commitment=Confirmed) - data = resp['result']['value']['data'] - validator_list = ValidatorList.decode(data[0], data[1]) - for validator in validator_list.validators: - assert validator.last_update_epoch != 0 - assert validator.transient_stake_lamports == 0 - assert validator.active_stake_lamports == increase_amount # rent exemption brought back to reserve - - # decrease from all - futures = [ - decrease_validator_stake(async_client, payer, payer, stake_pool_address, validator, decrease_amount) - for validator in validators - ] - await asyncio.gather(*futures) - - resp = await async_client.get_account_info(validator_list_address, commitment=Confirmed) - data = resp['result']['value']['data'] - validator_list = ValidatorList.decode(data[0], data[1]) - for validator in validator_list.validators: - assert validator.transient_stake_lamports == decrease_amount - assert validator.active_stake_lamports == increase_amount - decrease_amount - - print("Waiting for epoch to roll over") - await waiter.wait_for_next_epoch(async_client) - await update_stake_pool(async_client, payer, stake_pool_address) - - resp = await async_client.get_account_info(validator_list_address, commitment=Confirmed) - data = resp['result']['value']['data'] - validator_list = ValidatorList.decode(data[0], data[1]) - for validator in validator_list.validators: - assert validator.transient_stake_lamports == 0 - assert validator.active_stake_lamports == increase_amount - decrease_amount diff --git a/stake-pool/py/tests/test_add_remove.py b/stake-pool/py/tests/test_add_remove.py deleted file mode 100644 index 5937a2299e7..00000000000 --- a/stake-pool/py/tests/test_add_remove.py +++ /dev/null @@ -1,31 +0,0 @@ -import asyncio -import pytest -from solana.rpc.commitment import Confirmed - -from stake_pool.state import ValidatorList, StakeStatus -from stake_pool.actions import remove_validator_from_pool - - -@pytest.mark.asyncio -async def test_add_remove_validators(async_client, validators, payer, stake_pool_addresses): - (stake_pool_address, validator_list_address) = stake_pool_addresses - resp = await async_client.get_account_info(validator_list_address, commitment=Confirmed) - data = resp['result']['value']['data'] - validator_list = ValidatorList.decode(data[0], data[1]) - assert len(validator_list.validators) == len(validators) - futures = [] - for validator_info in validator_list.validators: - assert validator_info.vote_account_address in validators - assert validator_info.active_stake_lamports == 0 - assert validator_info.transient_stake_lamports == 0 - assert validator_info.status == StakeStatus.ACTIVE - futures.append( - remove_validator_from_pool(async_client, payer, stake_pool_address, validator_info.vote_account_address) - ) - await asyncio.gather(*futures) - - resp = await async_client.get_account_info(validator_list_address, commitment=Confirmed) - data = resp['result']['value']['data'] - validator_list = ValidatorList.decode(data[0], data[1]) - for validator_info in validator_list.validators: - assert validator_info.status == StakeStatus.READY_FOR_REMOVAL diff --git a/stake-pool/py/tests/test_bot_rebalance.py b/stake-pool/py/tests/test_bot_rebalance.py deleted file mode 100644 index 69876e11b04..00000000000 --- a/stake-pool/py/tests/test_bot_rebalance.py +++ /dev/null @@ -1,80 +0,0 @@ -"""Time sensitive test, so run it first out of the bunch.""" -import pytest -from solana.rpc.commitment import Confirmed -from spl.token.instructions import get_associated_token_address - -from stake.constants import STAKE_LEN, LAMPORTS_PER_SOL -from stake_pool.actions import deposit_sol -from stake_pool.constants import MINIMUM_ACTIVE_STAKE, MINIMUM_RESERVE_LAMPORTS -from stake_pool.state import StakePool, ValidatorList - -from bot.rebalance import rebalance - - -ENDPOINT: str = "http://127.0.0.1:8899" - - -@pytest.mark.asyncio -async def test_rebalance_this_is_very_slow(async_client, validators, payer, stake_pool_addresses, waiter): - (stake_pool_address, validator_list_address) = stake_pool_addresses - resp = await async_client.get_minimum_balance_for_rent_exemption(STAKE_LEN) - stake_rent_exemption = resp['result'] - increase_amount = MINIMUM_ACTIVE_STAKE - deposit_amount = (increase_amount + stake_rent_exemption) * len(validators) - - resp = await async_client.get_account_info(stake_pool_address, commitment=Confirmed) - data = resp['result']['value']['data'] - stake_pool = StakePool.decode(data[0], data[1]) - token_account = get_associated_token_address(payer.public_key, stake_pool.pool_mint) - await deposit_sol(async_client, payer, stake_pool_address, token_account, deposit_amount) - - # Test case 1: Increase - await rebalance(ENDPOINT, stake_pool_address, payer, 0.0) - - # should only have minimum left - resp = await async_client.get_account_info(stake_pool.reserve_stake, commitment=Confirmed) - assert resp['result']['value']['lamports'] == stake_rent_exemption + MINIMUM_RESERVE_LAMPORTS - - # should all be the same - resp = await async_client.get_account_info(validator_list_address, commitment=Confirmed) - data = resp['result']['value']['data'] - validator_list = ValidatorList.decode(data[0], data[1]) - for validator in validator_list.validators: - assert validator.active_stake_lamports == 0 - assert validator.transient_stake_lamports == increase_amount + stake_rent_exemption - - # Test case 2: Decrease - print('Waiting for next epoch') - await waiter.wait_for_next_epoch(async_client) - await rebalance(ENDPOINT, stake_pool_address, payer, deposit_amount / LAMPORTS_PER_SOL) - - # should still only have minimum left + rent exemptions from increase - resp = await async_client.get_account_info(stake_pool.reserve_stake, commitment=Confirmed) - reserve_lamports = resp['result']['value']['lamports'] - assert reserve_lamports == stake_rent_exemption * (1 + len(validator_list.validators)) + MINIMUM_RESERVE_LAMPORTS - - # should all be decreasing now - resp = await async_client.get_account_info(validator_list_address, commitment=Confirmed) - data = resp['result']['value']['data'] - validator_list = ValidatorList.decode(data[0], data[1]) - for validator in validator_list.validators: - assert validator.active_stake_lamports == 0 - assert validator.transient_stake_lamports == increase_amount - - # Test case 3: Do nothing - print('Waiting for next epoch') - await waiter.wait_for_next_epoch(async_client) - await rebalance(ENDPOINT, stake_pool_address, payer, deposit_amount / LAMPORTS_PER_SOL) - - # should still only have minimum left + rent exemptions from increase - resp = await async_client.get_account_info(stake_pool.reserve_stake, commitment=Confirmed) - reserve_lamports = resp['result']['value']['lamports'] - assert reserve_lamports == stake_rent_exemption + deposit_amount + MINIMUM_RESERVE_LAMPORTS - - # should all be decreasing now - resp = await async_client.get_account_info(validator_list_address, commitment=Confirmed) - data = resp['result']['value']['data'] - validator_list = ValidatorList.decode(data[0], data[1]) - for validator in validator_list.validators: - assert validator.active_stake_lamports == 0 - assert validator.transient_stake_lamports == 0 diff --git a/stake-pool/py/tests/test_create.py b/stake-pool/py/tests/test_create.py deleted file mode 100644 index 97600ae3926..00000000000 --- a/stake-pool/py/tests/test_create.py +++ /dev/null @@ -1,71 +0,0 @@ -import pytest -from solana.keypair import Keypair -from solana.rpc.commitment import Confirmed -from spl.token.constants import TOKEN_PROGRAM_ID - -from stake_pool.constants import \ - find_withdraw_authority_program_address, \ - MINIMUM_RESERVE_LAMPORTS, \ - STAKE_POOL_PROGRAM_ID -from stake_pool.state import StakePool, Fee - -from stake.actions import create_stake -from stake_pool.actions import create -from spl_token.actions import create_mint, create_associated_token_account - - -@pytest.mark.asyncio -async def test_create_stake_pool(async_client, payer): - stake_pool = Keypair() - validator_list = Keypair() - (pool_withdraw_authority, seed) = find_withdraw_authority_program_address( - STAKE_POOL_PROGRAM_ID, stake_pool.public_key) - - reserve_stake = Keypair() - await create_stake(async_client, payer, reserve_stake, pool_withdraw_authority, MINIMUM_RESERVE_LAMPORTS) - - pool_mint = Keypair() - await create_mint(async_client, payer, pool_mint, pool_withdraw_authority) - - manager_fee_account = await create_associated_token_account( - async_client, - payer, - payer.public_key, - pool_mint.public_key, - ) - - fee = Fee(numerator=1, denominator=1000) - referral_fee = 20 - await create( - async_client, payer, stake_pool, validator_list, pool_mint.public_key, - reserve_stake.public_key, manager_fee_account, fee, referral_fee) - resp = await async_client.get_account_info(stake_pool.public_key, commitment=Confirmed) - assert resp['result']['value']['owner'] == str(STAKE_POOL_PROGRAM_ID) - data = resp['result']['value']['data'] - pool_data = StakePool.decode(data[0], data[1]) - assert pool_data.manager == payer.public_key - assert pool_data.staker == payer.public_key - assert pool_data.stake_withdraw_bump_seed == seed - assert pool_data.validator_list == validator_list.public_key - assert pool_data.reserve_stake == reserve_stake.public_key - assert pool_data.pool_mint == pool_mint.public_key - assert pool_data.manager_fee_account == manager_fee_account - assert pool_data.token_program_id == TOKEN_PROGRAM_ID - assert pool_data.total_lamports == 0 - assert pool_data.pool_token_supply == 0 - assert pool_data.epoch_fee == fee - assert pool_data.next_epoch_fee is None - assert pool_data.preferred_deposit_validator is None - assert pool_data.preferred_withdraw_validator is None - assert pool_data.stake_deposit_fee == fee - assert pool_data.stake_withdrawal_fee == fee - assert pool_data.next_stake_withdrawal_fee is None - assert pool_data.stake_referral_fee == referral_fee - assert pool_data.sol_deposit_authority is None - assert pool_data.sol_deposit_fee == fee - assert pool_data.sol_referral_fee == referral_fee - assert pool_data.sol_withdraw_authority is None - assert pool_data.sol_withdrawal_fee == fee - assert pool_data.next_sol_withdrawal_fee is None - assert pool_data.last_epoch_pool_token_supply == 0 - assert pool_data.last_epoch_total_lamports == 0 diff --git a/stake-pool/py/tests/test_deposit_withdraw_sol.py b/stake-pool/py/tests/test_deposit_withdraw_sol.py deleted file mode 100644 index c61a353f592..00000000000 --- a/stake-pool/py/tests/test_deposit_withdraw_sol.py +++ /dev/null @@ -1,26 +0,0 @@ -import pytest -from solana.rpc.commitment import Confirmed -from solana.keypair import Keypair -from spl.token.instructions import get_associated_token_address - -from stake_pool.state import Fee, StakePool -from stake_pool.actions import create_all, deposit_sol, withdraw_sol - - -@pytest.mark.asyncio -async def test_deposit_withdraw_sol(async_client, payer): - fee = Fee(numerator=1, denominator=1000) - referral_fee = 20 - (stake_pool_address, validator_list_address) = await create_all(async_client, payer, fee, referral_fee) - resp = await async_client.get_account_info(stake_pool_address, commitment=Confirmed) - data = resp['result']['value']['data'] - stake_pool = StakePool.decode(data[0], data[1]) - token_account = get_associated_token_address(payer.public_key, stake_pool.pool_mint) - deposit_amount = 100_000_000 - await deposit_sol(async_client, payer, stake_pool_address, token_account, deposit_amount) - pool_token_balance = await async_client.get_token_account_balance(token_account, Confirmed) - assert pool_token_balance['result']['value']['amount'] == str(deposit_amount) - recipient = Keypair() - await withdraw_sol(async_client, payer, token_account, stake_pool_address, recipient.public_key, deposit_amount) - pool_token_balance = await async_client.get_token_account_balance(token_account, Confirmed) - assert pool_token_balance['result']['value']['amount'] == str('0') diff --git a/stake-pool/py/tests/test_deposit_withdraw_stake.py b/stake-pool/py/tests/test_deposit_withdraw_stake.py deleted file mode 100644 index 896960dcb17..00000000000 --- a/stake-pool/py/tests/test_deposit_withdraw_stake.py +++ /dev/null @@ -1,50 +0,0 @@ -import pytest -from solana.rpc.commitment import Confirmed -from solana.keypair import Keypair -from spl.token.instructions import get_associated_token_address - -from stake.actions import create_stake, delegate_stake -from stake.constants import STAKE_LEN -from stake.state import StakeState -from stake_pool.actions import deposit_stake, withdraw_stake, update_stake_pool -from stake_pool.constants import MINIMUM_ACTIVE_STAKE -from stake_pool.state import StakePool - - -@pytest.mark.asyncio -async def test_deposit_withdraw_stake(async_client, validators, payer, stake_pool_addresses, waiter): - (stake_pool_address, validator_list_address) = stake_pool_addresses - resp = await async_client.get_account_info(stake_pool_address, commitment=Confirmed) - data = resp['result']['value']['data'] - stake_pool = StakePool.decode(data[0], data[1]) - validator = next(iter(validators)) - stake_amount = MINIMUM_ACTIVE_STAKE - stake = Keypair() - await create_stake(async_client, payer, stake, payer.public_key, stake_amount) - stake = stake.public_key - await delegate_stake(async_client, payer, payer, stake, validator) - resp = await async_client.get_account_info(stake, commitment=Confirmed) - data = resp['result']['value']['data'] - stake_state = StakeState.decode(data[0], data[1]) - print(stake_state) - - await waiter.wait_for_next_epoch(async_client) - - await update_stake_pool(async_client, payer, stake_pool_address) - token_account = get_associated_token_address(payer.public_key, stake_pool.pool_mint) - await deposit_stake(async_client, payer, stake_pool_address, validator, stake, token_account) - pool_token_balance = await async_client.get_token_account_balance(token_account, Confirmed) - pool_token_balance = pool_token_balance['result']['value']['amount'] - resp = await async_client.get_minimum_balance_for_rent_exemption(STAKE_LEN) - stake_rent_exemption = resp['result'] - assert pool_token_balance == str(stake_amount + stake_rent_exemption) - - destination_stake = Keypair() - await withdraw_stake( - async_client, payer, payer, destination_stake, stake_pool_address, validator, - payer.public_key, token_account, stake_amount - ) - - pool_token_balance = await async_client.get_token_account_balance(token_account, Confirmed) - pool_token_balance = pool_token_balance['result']['value']['amount'] - assert pool_token_balance == str(stake_rent_exemption) diff --git a/stake-pool/py/tests/test_stake.py b/stake-pool/py/tests/test_stake.py deleted file mode 100644 index fdf016bc297..00000000000 --- a/stake-pool/py/tests/test_stake.py +++ /dev/null @@ -1,33 +0,0 @@ -import asyncio -import pytest -from solana.keypair import Keypair - -from stake.actions import authorize, create_stake, delegate_stake -from stake.constants import MINIMUM_DELEGATION -from stake.state import StakeAuthorize - - -@pytest.mark.asyncio -async def test_create_stake(async_client, payer): - stake = Keypair() - await create_stake(async_client, payer, stake, payer.public_key, 1) - - -@pytest.mark.asyncio -async def test_delegate_stake(async_client, validators, payer): - validator = validators[0] - stake = Keypair() - await create_stake(async_client, payer, stake, payer.public_key, 1) - await delegate_stake(async_client, payer, payer, stake.public_key, validator) - - -@pytest.mark.asyncio -async def test_authorize_stake(async_client, payer): - stake = Keypair() - new_authority = Keypair() - await create_stake(async_client, payer, stake, payer.public_key, MINIMUM_DELEGATION) - await asyncio.gather( - authorize(async_client, payer, payer, stake.public_key, new_authority.public_key, StakeAuthorize.STAKER), - authorize(async_client, payer, payer, stake.public_key, new_authority.public_key, StakeAuthorize.WITHDRAWER) - ) - await authorize(async_client, payer, new_authority, stake.public_key, payer.public_key, StakeAuthorize.WITHDRAWER) diff --git a/stake-pool/py/tests/test_system.py b/stake-pool/py/tests/test_system.py deleted file mode 100644 index 31d2af3437a..00000000000 --- a/stake-pool/py/tests/test_system.py +++ /dev/null @@ -1,14 +0,0 @@ -import pytest -from solana.keypair import Keypair -from solana.rpc.commitment import Confirmed - -import system.actions - - -@pytest.mark.asyncio -async def test_airdrop(async_client): - manager = Keypair() - airdrop_lamports = 1_000_000 - await system.actions.airdrop(async_client, manager.public_key, airdrop_lamports) - resp = await async_client.get_balance(manager.public_key, commitment=Confirmed) - assert resp['result']['value'] == airdrop_lamports diff --git a/stake-pool/py/tests/test_token.py b/stake-pool/py/tests/test_token.py deleted file mode 100644 index 1d92c179db7..00000000000 --- a/stake-pool/py/tests/test_token.py +++ /dev/null @@ -1,16 +0,0 @@ -import pytest -from solana.keypair import Keypair - -from spl_token.actions import create_mint, create_associated_token_account - - -@pytest.mark.asyncio -async def test_create_mint(async_client, payer): - pool_mint = Keypair() - await create_mint(async_client, payer, pool_mint, payer.public_key) - await create_associated_token_account( - async_client, - payer, - payer.public_key, - pool_mint.public_key, - ) diff --git a/stake-pool/py/tests/test_vote.py b/stake-pool/py/tests/test_vote.py deleted file mode 100644 index b0861d465fd..00000000000 --- a/stake-pool/py/tests/test_vote.py +++ /dev/null @@ -1,16 +0,0 @@ -import pytest -from solana.keypair import Keypair -from solana.publickey import PublicKey -from solana.rpc.commitment import Confirmed - -from vote.actions import create_vote -from vote.constants import VOTE_PROGRAM_ID - - -@pytest.mark.asyncio -async def test_create_vote(async_client, payer): - vote = Keypair() - node = Keypair() - await create_vote(async_client, payer, vote, node, payer.public_key, payer.public_key, 10) - resp = await async_client.get_account_info(vote.public_key, commitment=Confirmed) - assert PublicKey(resp['result']['value']['owner']) == VOTE_PROGRAM_ID diff --git a/stake-pool/py/vote/__init__.py b/stake-pool/py/vote/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/stake-pool/py/vote/actions.py b/stake-pool/py/vote/actions.py deleted file mode 100644 index 9f3fc49f197..00000000000 --- a/stake-pool/py/vote/actions.py +++ /dev/null @@ -1,45 +0,0 @@ -from solana.publickey import PublicKey -from solana.keypair import Keypair -from solana.rpc.async_api import AsyncClient -from solana.rpc.commitment import Confirmed -from solana.rpc.types import TxOpts -from solana.sysvar import SYSVAR_CLOCK_PUBKEY, SYSVAR_RENT_PUBKEY -from solana.transaction import Transaction -import solana.system_program as sys - -from vote.constants import VOTE_PROGRAM_ID, VOTE_STATE_LEN -from vote.instructions import initialize, InitializeParams - - -async def create_vote( - client: AsyncClient, payer: Keypair, vote: Keypair, node: Keypair, - voter: PublicKey, withdrawer: PublicKey, commission: int): - print(f"Creating vote account {vote.public_key}") - resp = await client.get_minimum_balance_for_rent_exemption(VOTE_STATE_LEN) - txn = Transaction() - txn.add( - sys.create_account( - sys.CreateAccountParams( - from_pubkey=payer.public_key, - new_account_pubkey=vote.public_key, - lamports=resp['result'], - space=VOTE_STATE_LEN, - program_id=VOTE_PROGRAM_ID, - ) - ) - ) - txn.add( - initialize( - InitializeParams( - vote=vote.public_key, - rent_sysvar=SYSVAR_RENT_PUBKEY, - clock_sysvar=SYSVAR_CLOCK_PUBKEY, - node=node.public_key, - authorized_voter=voter, - authorized_withdrawer=withdrawer, - commission=commission, - ) - ) - ) - await client.send_transaction( - txn, payer, vote, node, opts=TxOpts(skip_confirmation=False, preflight_commitment=Confirmed)) diff --git a/stake-pool/py/vote/constants.py b/stake-pool/py/vote/constants.py deleted file mode 100644 index 21f006e4a52..00000000000 --- a/stake-pool/py/vote/constants.py +++ /dev/null @@ -1,8 +0,0 @@ -from solana.publickey import PublicKey - - -VOTE_PROGRAM_ID = PublicKey("Vote111111111111111111111111111111111111111") -"""Program id for the native vote program.""" - -VOTE_STATE_LEN: int = 3731 -"""Size of vote account.""" diff --git a/stake-pool/py/vote/instructions.py b/stake-pool/py/vote/instructions.py deleted file mode 100644 index 267aeb4aa46..00000000000 --- a/stake-pool/py/vote/instructions.py +++ /dev/null @@ -1,98 +0,0 @@ -"""Vote Program Instructions.""" - -from enum import IntEnum -from typing import NamedTuple - -from construct import Bytes, Struct, Switch, Int8ul, Int32ul, Pass # type: ignore - -from solana.publickey import PublicKey -from solana.sysvar import SYSVAR_CLOCK_PUBKEY, SYSVAR_RENT_PUBKEY -from solana.transaction import AccountMeta, TransactionInstruction - -from vote.constants import VOTE_PROGRAM_ID - -PUBLIC_KEY_LAYOUT = Bytes(32) - - -class InitializeParams(NamedTuple): - """Initialize vote account params.""" - - vote: PublicKey - """`[w]` Uninitialized vote account""" - rent_sysvar: PublicKey - """`[]` Rent sysvar.""" - clock_sysvar: PublicKey - """`[]` Clock sysvar.""" - node: PublicKey - """`[s]` New validator identity.""" - - authorized_voter: PublicKey - """The authorized voter for this vote account.""" - authorized_withdrawer: PublicKey - """The authorized withdrawer for this vote account.""" - commission: int - """Commission, represented as a percentage""" - - -class InstructionType(IntEnum): - """Vote Instruction Types.""" - - INITIALIZE = 0 - AUTHORIZE = 1 - VOTE = 2 - WITHDRAW = 3 - UPDATE_VALIDATOR_IDENTITY = 4 - UPDATE_COMMISSION = 5 - VOTE_SWITCH = 6 - AUTHORIZE_CHECKED = 7 - - -INITIALIZE_LAYOUT = Struct( - "node" / PUBLIC_KEY_LAYOUT, - "authorized_voter" / PUBLIC_KEY_LAYOUT, - "authorized_withdrawer" / PUBLIC_KEY_LAYOUT, - "commission" / Int8ul, -) - -INSTRUCTIONS_LAYOUT = Struct( - "instruction_type" / Int32ul, - "args" - / Switch( - lambda this: this.instruction_type, - { - InstructionType.INITIALIZE: INITIALIZE_LAYOUT, - InstructionType.AUTHORIZE: Pass, # TODO - InstructionType.VOTE: Pass, # TODO - InstructionType.WITHDRAW: Pass, # TODO - InstructionType.UPDATE_VALIDATOR_IDENTITY: Pass, # TODO - InstructionType.UPDATE_COMMISSION: Pass, # TODO - InstructionType.VOTE_SWITCH: Pass, # TODO - InstructionType.AUTHORIZE_CHECKED: Pass, # TODO - }, - ), -) - - -def initialize(params: InitializeParams) -> TransactionInstruction: - """Creates a transaction instruction to initialize a new stake.""" - data = INSTRUCTIONS_LAYOUT.build( - dict( - instruction_type=InstructionType.INITIALIZE, - args=dict( - node=bytes(params.node), - authorized_voter=bytes(params.authorized_voter), - authorized_withdrawer=bytes(params.authorized_withdrawer), - commission=params.commission, - ), - ) - ) - return TransactionInstruction( - keys=[ - AccountMeta(pubkey=params.vote, is_signer=False, is_writable=True), - AccountMeta(pubkey=params.rent_sysvar or SYSVAR_RENT_PUBKEY, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.clock_sysvar or SYSVAR_CLOCK_PUBKEY, is_signer=False, is_writable=False), - AccountMeta(pubkey=params.node, is_signer=True, is_writable=False), - ], - program_id=VOTE_PROGRAM_ID, - data=data, - ) diff --git a/stateless-asks/README.md b/stateless-asks/README.md index 1f49ea9d95c..15dd07bf3ec 100644 --- a/stateless-asks/README.md +++ b/stateless-asks/README.md @@ -1,22 +1,27 @@ # Stateless Offer - Simple program to make token offers to any bidder that can satisfy - the constraints. +Simple program to make token offers to any bidder that can satisfy +the constraints. - This program is stateless. It is up to the maker to advertise. It - uses the PDA as a one way hash of the offer that the maker wants - to create. The maker then only needs to approve their token to the - PDA address for the taker to receive the items. The maker doesn't - need to be online to complete the transaction, but needs to advertise - the offer off-chain. +This program is stateless. It is up to the maker to advertise. It +uses the PDA as a one way hash of the offer that the maker wants +to create. The maker then only needs to approve their token to the +PDA address for the taker to receive the items. The maker doesn't +need to be online to complete the transaction, but needs to advertise +the offer off-chain. - ## Maker - 1. compute the offer PDA - 2. approve the token delegation for the amount to the PDA - 3. publish the offer off-chain +## Maker +1. compute the offer PDA +2. approve the token delegation for the amount to the PDA +3. publish the offer off-chain - ## Taker - 1. Create the offer TX - 2. Submit the TX to the stateless-offer program +## Taker +1. Create the offer TX +2. Submit the TX to the stateless-offer program - To cancel, the maker simply needs to cancel the delegation. +To cancel, the maker simply needs to cancel the delegation. + +## Audit + +The repository [README](https://github.com/solana-labs/solana-program-library#audits) +contains information about program audits. diff --git a/stateless-asks/program/Cargo.toml b/stateless-asks/program/Cargo.toml index 0b605e64dca..2d4288f74c0 100644 --- a/stateless-asks/program/Cargo.toml +++ b/stateless-asks/program/Cargo.toml @@ -1,29 +1,33 @@ [package] name = "stateless-asks" version = "0.1.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] no-entrypoint = [] -test-bpf = [] +test-sbf = [] [dependencies] -borsh = "0.9.1" -solana-program = "1.10.33" -spl-token = { version = "3.3", path = "../../token/program", features = ["no-entrypoint"] } -spl-associated-token-account = {version = "1.0", path = "../../associated-token-account/program", features = ["no-entrypoint"]} -metaplex-token-metadata = { version = "0.0.1", features = ["no-entrypoint"] } -thiserror = "1.0" +borsh = "1.5.3" +solana-program = "2.1.0" +spl-token = { version = "7.0", features = [ + "no-entrypoint", +] } +spl-associated-token-account-client = { version = "2.0.0" } +thiserror = "2.0" [dev-dependencies] -solana-program-test = "1.10.33" -solana-sdk = "1.10.33" +solana-program-test = "2.1.0" +solana-sdk = "2.1.0" [lib] crate-type = ["cdylib", "lib"] [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] + +[lints] +workspace = true diff --git a/stateless-asks/program/src/entrypoint.rs b/stateless-asks/program/src/entrypoint.rs index 3baa990ba0d..cbf8ed562f9 100644 --- a/stateless-asks/program/src/entrypoint.rs +++ b/stateless-asks/program/src/entrypoint.rs @@ -1,12 +1,11 @@ #![cfg(all(target_os = "solana", not(feature = "no-entrypoint")))] -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, pubkey::Pubkey, +use { + crate::processor::Processor, + solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey}, }; -use crate::processor::Processor; - -entrypoint!(process_instruction); +solana_program::entrypoint!(process_instruction); fn process_instruction( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/stateless-asks/program/src/error.rs b/stateless-asks/program/src/error.rs index ef35e575c3c..cc97352949f 100644 --- a/stateless-asks/program/src/error.rs +++ b/stateless-asks/program/src/error.rs @@ -1,6 +1,4 @@ -use thiserror::Error; - -use solana_program::program_error::ProgramError; +use {solana_program::program_error::ProgramError, thiserror::Error}; #[derive(Error, Debug, Copy, Clone)] pub enum UtilError { diff --git a/stateless-asks/program/src/instruction.rs b/stateless-asks/program/src/instruction.rs index c46f215dba4..07e79af4536 100644 --- a/stateless-asks/program/src/instruction.rs +++ b/stateless-asks/program/src/instruction.rs @@ -16,15 +16,16 @@ pub enum StatelessOfferInstruction { /// Accept a StatelessOffer /// Let's walk through the actions of Alice (maker) and Bob (taker) /// - /// Alice has some amount Token A in mkr_src_account and she creates mkr_dst_account if it doesn't exist - /// Alice calls Approve on mkr_src_account for maker_size to some transfer_authority owned by the Stateless Ask program. - /// This transfer_authority's approval size/mint are expressed in the seeds of the PDA + /// Alice has some amount Token A in mkr_src_account and she creates + /// mkr_dst_account if it doesn't exist Alice calls Approve on + /// mkr_src_account for maker_size to some transfer_authority owned by the + /// Stateless Ask program. This transfer_authority's approval size/mint + /// are expressed in the seeds of the PDA /// /// Some time later: /// - /// Bob initializes tkr_src_account (Token B) and tkr_dst_account (Token A) if they don't exist - /// Bob (or anyone) executes AcceptOffer - /// + /// Bob initializes tkr_src_account (Token B) and tkr_dst_account (Token A) + /// if they don't exist Bob (or anyone) executes AcceptOffer AcceptOffer { #[allow(dead_code)] has_metadata: bool, @@ -62,7 +63,7 @@ pub fn accept_offer( taker_size, bump_seed, }; - let data = init_data.try_to_vec().unwrap(); + let data = borsh::to_vec(&init_data).unwrap(); let mut accounts = vec![ AccountMeta::new_readonly(*maker_wallet, false), AccountMeta::new_readonly(*taker_wallet, true), @@ -112,7 +113,7 @@ pub fn accept_offer_with_metadata( taker_size, bump_seed, }; - let data = init_data.try_to_vec().unwrap(); + let data = borsh::to_vec(&init_data).unwrap(); let mut accounts = vec![ AccountMeta::new_readonly(*maker_wallet, false), AccountMeta::new_readonly(*taker_wallet, true), diff --git a/stateless-asks/program/src/lib.rs b/stateless-asks/program/src/lib.rs index d7261f820f8..e1a49e842f2 100644 --- a/stateless-asks/program/src/lib.rs +++ b/stateless-asks/program/src/lib.rs @@ -6,5 +6,6 @@ pub mod validation_utils; #[cfg(not(feature = "no-entrypoint"))] mod entrypoint; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version pub use solana_program; diff --git a/stateless-asks/program/src/processor.rs b/stateless-asks/program/src/processor.rs index 20561146636..3b399c246d8 100644 --- a/stateless-asks/program/src/processor.rs +++ b/stateless-asks/program/src/processor.rs @@ -1,27 +1,66 @@ //! Program state processor -use metaplex_token_metadata::state::Metadata; -use solana_program::program_option::COption; -use std::slice::Iter; - -use crate::error::UtilError; -use crate::instruction::StatelessOfferInstruction; -use crate::validation_utils::{assert_is_ata, assert_keys_equal}; use { + crate::{ + error::UtilError, + instruction::StatelessOfferInstruction, + validation_utils::{assert_is_ata, assert_keys_equal}, + }, borsh::BorshDeserialize, solana_program::{ - account_info::next_account_info, - account_info::AccountInfo, + account_info::{next_account_info, AccountInfo}, + borsh1::try_from_slice_unchecked, entrypoint::ProgramResult, msg, program::{invoke, invoke_signed}, program_error::ProgramError, + program_option::COption, program_pack::Pack, pubkey::Pubkey, system_instruction, system_program, }, + std::slice::Iter, }; +pub(crate) mod inline_mpl_token_metadata { + use {borsh::BorshDeserialize, solana_program::pubkey::Pubkey}; + solana_program::declare_id!("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"); + + #[derive(Clone, BorshDeserialize, Debug, PartialEq, Eq)] + pub(crate) struct Metadata { + /// Account discriminator. + pub key: u8, + /// Address of the update authority. + pub update_authority: Pubkey, + /// Address of the mint. + pub mint: Pubkey, + /// Asset data. + pub data: Data, + } + + #[derive(BorshDeserialize, Default, PartialEq, Eq, Debug, Clone)] + pub(crate) struct Data { + /// The name of the asset + pub name: String, + /// The symbol for the asset + pub symbol: String, + /// URI pointing to JSON representing the asset + pub uri: String, + /// Royalty basis points that goes to creators in secondary sales + /// (0-10000) + pub seller_fee_basis_points: u16, + /// Array of creators, optional + pub creators: Option>, + } + + #[derive(BorshDeserialize, PartialEq, Debug, Clone, Eq, Hash)] + pub(crate) struct Creator { + pub address: Pubkey, + pub verified: bool, + pub share: u8, + } +} + /// Program state handler. pub struct Processor {} impl Processor { @@ -89,18 +128,18 @@ fn process_accept_offer( let (maker_metadata_key, _) = Pubkey::find_program_address( &[ b"metadata", - metaplex_token_metadata::id().as_ref(), + inline_mpl_token_metadata::id().as_ref(), maker_src_mint.key.as_ref(), ], - &metaplex_token_metadata::id(), + &inline_mpl_token_metadata::id(), ); let (taker_metadata_key, _) = Pubkey::find_program_address( &[ b"metadata", - metaplex_token_metadata::id().as_ref(), + inline_mpl_token_metadata::id().as_ref(), taker_src_mint.key.as_ref(), ], - &metaplex_token_metadata::id(), + &inline_mpl_token_metadata::id(), ); if *metadata_info.key == maker_metadata_key { msg!("Taker pays for fees"); @@ -165,10 +204,10 @@ fn process_accept_offer( } msg!("Delegate matches"); assert_keys_equal(spl_token::id(), *token_program_info.key)?; - // Both of these transfers will fail if the `transfer_authority` is the delegate of these ATA's - // One consideration is that the taker can get tricked in the case that the maker size is greater than - // the token amount in the maker's ATA, but these stateless offers should just be invalidated in - // the client. + // Both of these transfers will fail if the `transfer_authority` is the delegate + // of these ATA's One consideration is that the taker can get tricked in the + // case that the maker size is greater than the token amount in the maker's + // ATA, but these stateless offers should just be invalidated in the client. assert_is_ata(maker_src_account, maker_wallet.key, maker_src_mint.key)?; assert_is_ata(taker_dst_account, taker_wallet.key, maker_src_mint.key)?; invoke_signed( @@ -246,7 +285,12 @@ fn pay_creator_fees<'a>( is_native: bool, seeds: &[&[u8]], ) -> Result { - let metadata = Metadata::from_account_info(metadata_info)?; + if *metadata_info.owner != inline_mpl_token_metadata::id() { + return Err(ProgramError::InvalidAccountData); + } + let metadata = try_from_slice_unchecked::( + &metadata_info.try_borrow_data()?, + )?; let fees = metadata.data.seller_fee_basis_points; let total_fee = (fees as u64) .checked_mul(size) diff --git a/stateless-asks/program/src/validation_utils.rs b/stateless-asks/program/src/validation_utils.rs index 05112e480c0..6e61b0d43f2 100644 --- a/stateless-asks/program/src/validation_utils.rs +++ b/stateless-asks/program/src/validation_utils.rs @@ -1,14 +1,15 @@ -use super::error::UtilError; -use solana_program::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - program_error::ProgramError, - program_pack::{IsInitialized, Pack}, - pubkey::Pubkey, +use { + super::error::UtilError, + solana_program::{ + account_info::AccountInfo, + entrypoint::ProgramResult, + program_error::ProgramError, + program_pack::{IsInitialized, Pack}, + pubkey::Pubkey, + }, + spl_associated_token_account_client::address::get_associated_token_address, + spl_token::{self, state::Account}, }; -use spl_associated_token_account::get_associated_token_address; -use spl_token; -use spl_token::state::Account; pub fn assert_is_ata(ata: &AccountInfo, wallet: &Pubkey, mint: &Pubkey) -> ProgramResult { assert_owned_by(ata, &spl_token::id())?; diff --git a/token-collection/README.md b/token-collection/README.md new file mode 100644 index 00000000000..0b311156f35 --- /dev/null +++ b/token-collection/README.md @@ -0,0 +1,24 @@ +# SPL Token Collection + +This program serves as a reference implementation for using the SPL Token Group +interface to create an on-chain program for managing token collections - such +as NFT Collections. + +This program bears a lot of similarity to the example program found at +`token-group/example`, but with some additional implementations centered around +specifically token collections. + +## How Collections Work in this Program + +Strictly for demonstration purposes, this program is going to require the +following: + +- Group tokens must be NFTs (0 decimals, 1 supply) +- Group tokens must have metadata +- Member tokens can be any SPL token, but must have metadata +- Member tokens can be part of multiple collections + +## Demonstration + +For a particularly fleshed-out example of this program in action, check out the +`token-collections.rs` test under `tests`! \ No newline at end of file diff --git a/token-collection/program/Cargo.toml b/token-collection/program/Cargo.toml new file mode 100644 index 00000000000..535315a2ae3 --- /dev/null +++ b/token-collection/program/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "spl-token-collection" +version = "0.1.0" +description = "Solana Program Library Token Collection" +authors = ["Solana Labs Maintainers "] +repository = "https://github.com/solana-labs/solana-program-library" +license = "Apache-2.0" +edition = "2021" + +[features] +no-entrypoint = [] +test-sbf = [] + +[dependencies] +solana-program = "2.1.0" +spl-pod = { version = "0.5.0" } +spl-program-error = { version = "0.6.0" } +spl-token-2022 = { version = "6.0.0", features = ["no-entrypoint"] } +spl-token-group-example = { version = "0.2", features = ["no-entrypoint"] } +spl-token-group-interface = { version = "0.5.0" } +spl-token-metadata-interface = { version = "0.6.0" } +spl-type-length-value = { version = "0.7.0" } + +[dev-dependencies] +solana-program-test = "2.1.0" +solana-sdk = "2.1.0" +spl-discriminator = { version = "0.4.0" } +spl-token-client = { version = "0.13.0" } + +[lib] +crate-type = ["cdylib", "lib"] + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] diff --git a/token-collection/program/src/entrypoint.rs b/token-collection/program/src/entrypoint.rs new file mode 100644 index 00000000000..0336a5f1c99 --- /dev/null +++ b/token-collection/program/src/entrypoint.rs @@ -0,0 +1,23 @@ +//! Program entrypoint + +use { + crate::processor, + solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, program_error::PrintProgramError, + pubkey::Pubkey, + }, + spl_token_group_interface::error::TokenGroupError, +}; + +solana_program::entrypoint!(process_instruction); +fn process_instruction( + program_id: &Pubkey, + accounts: &[AccountInfo], + instruction_data: &[u8], +) -> ProgramResult { + if let Err(error) = processor::process(program_id, accounts, instruction_data) { + error.print::(); + return Err(error); + } + Ok(()) +} diff --git a/token-collection/program/src/lib.rs b/token-collection/program/src/lib.rs new file mode 100644 index 00000000000..6e539b2fd80 --- /dev/null +++ b/token-collection/program/src/lib.rs @@ -0,0 +1,10 @@ +//! Crate defining the Token Collection program implementing the +//! SPL Token Group interface. + +#![deny(missing_docs)] +#![forbid(unsafe_code)] + +pub mod processor; + +#[cfg(not(feature = "no-entrypoint"))] +mod entrypoint; diff --git a/token-collection/program/src/processor.rs b/token-collection/program/src/processor.rs new file mode 100644 index 00000000000..c5153a03771 --- /dev/null +++ b/token-collection/program/src/processor.rs @@ -0,0 +1,162 @@ +//! Program state processor + +use { + solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + msg, + program_error::ProgramError, + program_option::COption, + pubkey::Pubkey, + }, + spl_pod::optional_keys::OptionalNonZeroPubkey, + spl_token_2022::{ + extension::{ + metadata_pointer::MetadataPointer, BaseStateWithExtensions, StateWithExtensions, + }, + state::Mint, + }, + spl_token_group_interface::{ + error::TokenGroupError, + instruction::{InitializeGroup, TokenGroupInstruction}, + state::{TokenGroup, TokenGroupMember}, + }, + spl_token_metadata_interface::state::TokenMetadata, + spl_type_length_value::state::TlvStateMut, +}; + +fn check_update_authority( + update_authority_info: &AccountInfo, + expected_update_authority: &OptionalNonZeroPubkey, +) -> ProgramResult { + if !update_authority_info.is_signer { + return Err(ProgramError::MissingRequiredSignature); + } + let update_authority = Option::::from(*expected_update_authority) + .ok_or(TokenGroupError::ImmutableGroup)?; + if update_authority != *update_authority_info.key { + return Err(TokenGroupError::IncorrectUpdateAuthority.into()); + } + Ok(()) +} + +/// Checks that a mint is valid and contains metadata. +fn check_mint_and_metadata( + mint_info: &AccountInfo, + mint_authority_info: &AccountInfo, +) -> ProgramResult { + let mint_data = mint_info.try_borrow_data()?; + let mint = StateWithExtensions::::unpack(&mint_data)?; + + if !mint_authority_info.is_signer { + return Err(ProgramError::MissingRequiredSignature); + } + if mint.base.mint_authority.as_ref() != COption::Some(mint_authority_info.key) { + return Err(TokenGroupError::IncorrectMintAuthority.into()); + } + + let metadata_pointer = mint.get_extension::()?; + let metadata_pointer_address = Option::::from(metadata_pointer.metadata_address); + + // If the metadata is inside the mint (Token2022), make sure it contains + // valid TokenMetadata + if metadata_pointer_address == Some(*mint_info.key) { + mint.get_variable_len_extension::()?; + } + + Ok(()) +} + +/// Processes an [InitializeGroup](enum.GroupInterfaceInstruction.html) +/// instruction to initialize a collection. +pub fn process_initialize_collection( + _program_id: &Pubkey, + accounts: &[AccountInfo], + data: InitializeGroup, +) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + + let collection_info = next_account_info(account_info_iter)?; + let mint_info = next_account_info(account_info_iter)?; + let mint_authority_info = next_account_info(account_info_iter)?; + + check_mint_and_metadata(mint_info, mint_authority_info)?; + + // Initialize the collection + let mut buffer = collection_info.try_borrow_mut_data()?; + let mut state = TlvStateMut::unpack(&mut buffer)?; + let (collection, _) = state.init_value::(false)?; + *collection = TokenGroup::new(mint_info.key, data.update_authority, data.max_size.into()); + + Ok(()) +} + +/// Processes an [InitializeMember](enum.GroupInterfaceInstruction.html) +/// instruction +pub fn process_initialize_collection_member( + _program_id: &Pubkey, + accounts: &[AccountInfo], +) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + + let member_info = next_account_info(account_info_iter)?; + let mint_info = next_account_info(account_info_iter)?; + let mint_authority_info = next_account_info(account_info_iter)?; + let collection_info = next_account_info(account_info_iter)?; + let collection_update_authority_info = next_account_info(account_info_iter)?; + + check_mint_and_metadata(mint_info, mint_authority_info)?; + + if member_info.key == collection_info.key { + return Err(TokenGroupError::MemberAccountIsGroupAccount.into()); + } + + let mut buffer = collection_info.try_borrow_mut_data()?; + let mut state = TlvStateMut::unpack(&mut buffer)?; + let collection = state.get_first_value_mut::()?; + + check_update_authority( + collection_update_authority_info, + &collection.update_authority, + )?; + let member_number = collection.increment_size()?; + + let mut buffer = member_info.try_borrow_mut_data()?; + let mut state = TlvStateMut::unpack(&mut buffer)?; + + // This program uses `allow_repetition: true` because the same mint can be + // a member of multiple collections. + let (member, _) = state.init_value::(/* allow_repetition */ true)?; + *member = TokenGroupMember::new(mint_info.key, collection_info.key, member_number); + + Ok(()) +} + +/// Processes an `SplTokenGroupInstruction` +pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult { + let instruction = TokenGroupInstruction::unpack(input)?; + match instruction { + TokenGroupInstruction::InitializeGroup(data) => { + msg!("Instruction: InitializeCollection"); + process_initialize_collection(program_id, accounts, data) + } + TokenGroupInstruction::UpdateGroupMaxSize(data) => { + msg!("Instruction: UpdateCollectionMaxSize"); + // Same functionality as the example program + spl_token_group_example::processor::process_update_group_max_size( + program_id, accounts, data, + ) + } + TokenGroupInstruction::UpdateGroupAuthority(data) => { + msg!("Instruction: UpdateCollectionAuthority"); + // Same functionality as the example program + spl_token_group_example::processor::process_update_group_authority( + program_id, accounts, data, + ) + } + TokenGroupInstruction::InitializeMember(_) => { + msg!("Instruction: InitializeCollectionMember"); + process_initialize_collection_member(program_id, accounts) + } + } +} diff --git a/token-collection/program/tests/setup.rs b/token-collection/program/tests/setup.rs new file mode 100644 index 00000000000..363fc5c1b5a --- /dev/null +++ b/token-collection/program/tests/setup.rs @@ -0,0 +1,123 @@ +#![cfg(feature = "test-sbf")] + +use { + solana_program::system_instruction, + solana_program_test::{processor, tokio::sync::Mutex, ProgramTest, ProgramTestContext}, + solana_sdk::{pubkey::Pubkey, signature::Keypair, signer::Signer, transaction::Transaction}, + spl_token_client::{ + client::{ + ProgramBanksClient, ProgramBanksClientProcessTransaction, ProgramClient, + SendTransaction, SimulateTransaction, + }, + token::{ExtensionInitializationParams, Token}, + }, + spl_token_group_interface::instruction::initialize_group, + spl_token_metadata_interface::state::TokenMetadata, + std::sync::Arc, +}; + +/// Set up a program test +pub async fn setup_program_test( + program_id: &Pubkey, +) -> ( + Arc>, + Arc>, + Arc, +) { + let mut program_test = ProgramTest::new( + "spl_token_collection", + *program_id, + processor!(spl_token_collection::processor::process), + ); + program_test.prefer_bpf(false); + program_test.add_program( + "spl_token_2022", + spl_token_2022::id(), + processor!(spl_token_2022::processor::Processor::process), + ); + let context = program_test.start_with_context().await; + let payer = Arc::new(context.payer.insecure_clone()); + let context = Arc::new(Mutex::new(context)); + let client: Arc> = + Arc::new(ProgramBanksClient::new_from_context( + Arc::clone(&context), + ProgramBanksClientProcessTransaction, + )); + (context, client, payer) +} + +/// Set up a Token-2022 mint and metadata +pub async fn setup_mint_and_metadata( + token_client: &Token, + mint_keypair: &Keypair, + mint_authority_keypair: &Keypair, + token_metadata: &TokenMetadata, + payer: Arc, +) { + token_client + .create_mint( + &mint_authority_keypair.pubkey(), + None, + vec![ExtensionInitializationParams::MetadataPointer { + authority: Some(mint_authority_keypair.pubkey()), + metadata_address: Some(mint_keypair.pubkey()), + }], + &[mint_keypair], + ) + .await + .unwrap(); + token_client + .token_metadata_initialize_with_rent_transfer( + &payer.pubkey(), + &mint_authority_keypair.pubkey(), + &mint_authority_keypair.pubkey(), + token_metadata.name.clone(), + token_metadata.symbol.clone(), + token_metadata.uri.clone(), + &[&payer, mint_authority_keypair], + ) + .await + .unwrap(); +} + +/// Initialize a token group +#[allow(clippy::too_many_arguments)] +pub async fn setup_group( + context: &mut ProgramTestContext, + program_id: &Pubkey, + group: &Keypair, + mint: &Keypair, + mint_authority: &Keypair, + update_authority: Option, + max_size: u64, + rent_lamports: u64, + space: usize, +) { + let transaction = Transaction::new_signed_with_payer( + &[ + system_instruction::create_account( + &context.payer.pubkey(), + &group.pubkey(), + rent_lamports, + space.try_into().unwrap(), + program_id, + ), + initialize_group( + program_id, + &group.pubkey(), + &mint.pubkey(), + &mint_authority.pubkey(), + update_authority, + max_size, + ), + ], + Some(&context.payer.pubkey()), + &[&context.payer, mint_authority, group], + context.last_blockhash, + ); + context + .banks_client + .process_transaction(transaction) + .await + .unwrap(); +} diff --git a/token-collection/program/tests/token_collection.rs b/token-collection/program/tests/token_collection.rs new file mode 100644 index 00000000000..79505163a43 --- /dev/null +++ b/token-collection/program/tests/token_collection.rs @@ -0,0 +1,389 @@ +#![cfg(feature = "test-sbf")] + +mod setup; + +use { + setup::{setup_group, setup_mint_and_metadata, setup_program_test}, + solana_program::{pubkey::Pubkey, system_instruction}, + solana_program_test::tokio, + solana_sdk::{signature::Keypair, signer::Signer, transaction::Transaction}, + spl_token_client::token::Token, + spl_token_group_interface::{ + instruction::initialize_member, + state::{TokenGroup, TokenGroupMember}, + }, + spl_token_metadata_interface::state::TokenMetadata, + spl_type_length_value::state::{TlvState, TlvStateBorrowed}, +}; + +/// All snakes are reptiles, but not all reptiles are snakes. +#[tokio::test] +async fn test_token_collection() { + let program_id = Pubkey::new_unique(); + let (context, client, payer) = setup_program_test(&program_id).await; + + // Set up the "Reptiles" collection mint and metadata + let reptile = Keypair::new(); + let reptile_mint = Keypair::new(); + let reptile_mint_authority = Keypair::new(); + let reptile_update_authority = Keypair::new(); + let reptile_metadata_state = TokenMetadata { + name: "Reptiles".to_string(), + symbol: "RPTL".to_string(), + ..TokenMetadata::default() + }; + setup_mint_and_metadata( + &Token::new( + client.clone(), + &spl_token_2022::id(), + &reptile_mint.pubkey(), + Some(0), + payer.clone(), + ), + &reptile_mint, + &reptile_mint_authority, + &reptile_metadata_state, + payer.clone(), + ) + .await; + + // Set up the "Snakes" collection mint and metadata + let snake = Keypair::new(); + let snake_mint = Keypair::new(); + let snake_mint_authority = Keypair::new(); + let snake_update_authority = Keypair::new(); + let snake_metadata_state = TokenMetadata { + name: "Snakes".to_string(), + symbol: "SNKE".to_string(), + ..TokenMetadata::default() + }; + setup_mint_and_metadata( + &Token::new( + client.clone(), + &spl_token_2022::id(), + &snake_mint.pubkey(), + Some(0), + payer.clone(), + ), + &snake_mint, + &snake_mint_authority, + &snake_metadata_state, + payer.clone(), + ) + .await; + + // Set up the "Python" mint and metadata + let python = Keypair::new(); + let python_mint = Keypair::new(); + let python_mint_authority = Keypair::new(); + let python_metadata_state = TokenMetadata { + name: "Python".to_string(), + symbol: "PYTH".to_string(), + ..TokenMetadata::default() + }; + setup_mint_and_metadata( + &Token::new( + client.clone(), + &spl_token_2022::id(), + &python_mint.pubkey(), + Some(0), + payer.clone(), + ), + &python_mint, + &python_mint_authority, + &python_metadata_state, + payer.clone(), + ) + .await; + + // Set up the "Cobra" mint and metadata + let cobra = Keypair::new(); + let cobra_mint = Keypair::new(); + let cobra_mint_authority = Keypair::new(); + let cobra_metadata_state = TokenMetadata { + name: "Cobra".to_string(), + symbol: "CBRA".to_string(), + ..TokenMetadata::default() + }; + setup_mint_and_metadata( + &Token::new( + client.clone(), + &spl_token_2022::id(), + &cobra_mint.pubkey(), + Some(0), + payer.clone(), + ), + &cobra_mint, + &cobra_mint_authority, + &cobra_metadata_state, + payer.clone(), + ) + .await; + + // Set up the "Iguana" mint and metadata + let iguana = Keypair::new(); + let iguana_mint = Keypair::new(); + let iguana_mint_authority = Keypair::new(); + let iguana_metadata_state = TokenMetadata { + name: "Iguana".to_string(), + symbol: "IGUA".to_string(), + ..TokenMetadata::default() + }; + setup_mint_and_metadata( + &Token::new( + client.clone(), + &spl_token_2022::id(), + &iguana_mint.pubkey(), + Some(0), + payer.clone(), + ), + &iguana_mint, + &iguana_mint_authority, + &iguana_metadata_state, + payer.clone(), + ) + .await; + + let mut context = context.lock().await; + + let rent = context.banks_client.get_rent().await.unwrap(); + let collection_space = TlvStateBorrowed::get_base_len() + std::mem::size_of::(); + let collection_rent_lamports = rent.minimum_balance(collection_space); + let member_space = TlvStateBorrowed::get_base_len() + std::mem::size_of::(); + let member_rent_lamports = rent.minimum_balance(member_space); + + // Create the collections using the SPL Token Collection program + setup_group( + &mut context, + &program_id, + &reptile, + &reptile_mint, + &reptile_mint_authority, + Some(reptile_update_authority.pubkey()), + 3, + collection_rent_lamports, + collection_space, + ) + .await; + setup_group( + &mut context, + &program_id, + &snake, + &snake_mint, + &snake_mint_authority, + Some(snake_update_authority.pubkey()), + 2, + collection_rent_lamports, + collection_space, + ) + .await; + + // Create the member accounts ahead of time + let transaction = Transaction::new_signed_with_payer( + &[ + system_instruction::create_account( + &context.payer.pubkey(), + &python.pubkey(), + member_rent_lamports.checked_mul(2).unwrap(), // 2 collections + u64::try_from(member_space).unwrap().checked_mul(2).unwrap(), // 2 collections + &program_id, + ), + system_instruction::create_account( + &context.payer.pubkey(), + &cobra.pubkey(), + member_rent_lamports.checked_mul(2).unwrap(), // 2 collections + u64::try_from(member_space).unwrap().checked_mul(2).unwrap(), // 2 collections + &program_id, + ), + system_instruction::create_account( + &context.payer.pubkey(), + &iguana.pubkey(), + member_rent_lamports, + member_space.try_into().unwrap(), + &program_id, + ), + ], + Some(&context.payer.pubkey()), + &[&context.payer, &python, &cobra, &iguana], + context.last_blockhash, + ); + context + .banks_client + .process_transaction(transaction) + .await + .unwrap(); + + // A python is both a reptile and a snake! + let transaction = Transaction::new_signed_with_payer( + &[ + initialize_member( + &program_id, + &python.pubkey(), + &python_mint.pubkey(), + &python_mint_authority.pubkey(), + &reptile.pubkey(), + &reptile_update_authority.pubkey(), + ), + initialize_member( + &program_id, + &python.pubkey(), + &python_mint.pubkey(), + &python_mint_authority.pubkey(), + &snake.pubkey(), + &snake_update_authority.pubkey(), + ), + ], + Some(&context.payer.pubkey()), + &[ + &context.payer, + &python_mint_authority, + &reptile_update_authority, + &snake_update_authority, + ], + context.last_blockhash, + ); + context + .banks_client + .process_transaction(transaction) + .await + .unwrap(); + + // A cobra is both a reptile and a snake! + let transaction = Transaction::new_signed_with_payer( + &[ + initialize_member( + &program_id, + &cobra.pubkey(), + &cobra_mint.pubkey(), + &cobra_mint_authority.pubkey(), + &reptile.pubkey(), + &reptile_update_authority.pubkey(), + ), + initialize_member( + &program_id, + &cobra.pubkey(), + &cobra_mint.pubkey(), + &cobra_mint_authority.pubkey(), + &snake.pubkey(), + &snake_update_authority.pubkey(), + ), + ], + Some(&context.payer.pubkey()), + &[ + &context.payer, + &cobra_mint_authority, + &reptile_update_authority, + &snake_update_authority, + ], + context.last_blockhash, + ); + context + .banks_client + .process_transaction(transaction) + .await + .unwrap(); + + // An iguana is a reptile but not a snake! + let mut transaction = Transaction::new_signed_with_payer( + &[initialize_member( + &program_id, + &iguana.pubkey(), + &iguana_mint.pubkey(), + &iguana_mint_authority.pubkey(), + &reptile.pubkey(), + &reptile_update_authority.pubkey(), + )], + Some(&context.payer.pubkey()), + &[ + &context.payer, + &iguana_mint_authority, + &reptile_update_authority, + ], + context.last_blockhash, + ); + transaction.sign( + &[ + &context.payer, + &iguana_mint_authority, + &reptile_update_authority, + ], + context.last_blockhash, + ); + context + .banks_client + .process_transaction(transaction) + .await + .unwrap(); + + // The "Reptiles" collection should have 3 members + let buffer = context + .banks_client + .get_account(reptile.pubkey()) + .await + .unwrap() + .unwrap() + .data; + let state = TlvStateBorrowed::unpack(&buffer).unwrap(); + let collection = state.get_first_value::().unwrap(); + assert_eq!(u64::from(collection.size), 3); + + // The "Snakes" collection should have 2 members + let buffer = context + .banks_client + .get_account(snake.pubkey()) + .await + .unwrap() + .unwrap() + .data; + let state = TlvStateBorrowed::unpack(&buffer).unwrap(); + let collection = state.get_first_value::().unwrap(); + assert_eq!(u64::from(collection.size), 2); + + // The "Python" should be a member of 2 collections + let buffer = context + .banks_client + .get_account(python.pubkey()) + .await + .unwrap() + .unwrap() + .data; + let state = TlvStateBorrowed::unpack(&buffer).unwrap(); + let membership = state + .get_value_with_repetition::(0) + .unwrap(); + assert_eq!(membership.group, reptile.pubkey(),); + let membership = state + .get_value_with_repetition::(1) + .unwrap(); + assert_eq!(membership.group, snake.pubkey(),); + + // The "Cobra" should be a member of 2 collections + let buffer = context + .banks_client + .get_account(cobra.pubkey()) + .await + .unwrap() + .unwrap() + .data; + let state = TlvStateBorrowed::unpack(&buffer).unwrap(); + let membership = state + .get_value_with_repetition::(0) + .unwrap(); + assert_eq!(membership.group, reptile.pubkey(),); + let membership = state + .get_value_with_repetition::(1) + .unwrap(); + assert_eq!(membership.group, snake.pubkey(),); + + // The "Iguana" should be a member of 1 collection + let buffer = context + .banks_client + .get_account(iguana.pubkey()) + .await + .unwrap() + .unwrap() + .data; + let state = TlvStateBorrowed::unpack(&buffer).unwrap(); + let membership = state.get_first_value::().unwrap(); + assert_eq!(membership.group, reptile.pubkey(),); +} diff --git a/token-group/README.md b/token-group/README.md new file mode 100644 index 00000000000..cd23e7d1c8e --- /dev/null +++ b/token-group/README.md @@ -0,0 +1,2 @@ +NOTE: The token-group interface, program, and clients are now maintained at +[solana-program/token-group](https://github.com/solana-program/token-group). diff --git a/token-lending/Anchor.toml b/token-lending/Anchor.toml deleted file mode 100644 index 2394d60290f..00000000000 --- a/token-lending/Anchor.toml +++ /dev/null @@ -1,11 +0,0 @@ -anchor_version = "0.14.0" - -[workspace] -members = ["program"] - -[provider] -cluster = "devnet" -wallet = "~/.config/solana/id.json" - -[programs.devnet] -spl-token-lending = "LendZqTs7gn5CTSJU1jWKhKuVpjJGom45nnwPb2AMTi" \ No newline at end of file diff --git a/token-lending/README.md b/token-lending/README.md index 9b03d5cb512..96968ff2730 100644 --- a/token-lending/README.md +++ b/token-lending/README.md @@ -6,14 +6,15 @@ Full documentation is available at https://spl.solana.com/token-lending Web3 bindings are available in the `./js` directory. -### On-chain programs +## Audit + +The repository [README](https://github.com/solana-labs/solana-program-library#audits) +contains information about program audits. -Please note that only the lending program deployed to devnet is currently operational. +### On-chain programs | Cluster | Program Address | | --- | --- | -| Mainnet Beta | [`LendZqTs8gn5CTSJU1jWKhKuVpjJGom45nnwPb2AMTi`](https://explorer.solana.com/address/LendZqTs7gn5CTSJU1jWKhKuVpjJGom45nnwPb2AMTi) | -| Testnet | [`6TvznH3B2e3p2mbhufNBpgSrLx6UkgvxtVQvopEZ2kuH`](https://explorer.solana.com/address/6TvznH3B2e3p2mbhufNBpgSrLx6UkgvxtVQvopEZ2kuH?cluster=testnet) | | Devnet | [`6TvznH3B2e3p2mbhufNBpgSrLx6UkgvxtVQvopEZ2kuH`](https://explorer.solana.com/address/6TvznH3B2e3p2mbhufNBpgSrLx6UkgvxtVQvopEZ2kuH?cluster=devnet) | ### Documentation @@ -80,7 +81,7 @@ This is optional! You can skip these steps and use the [Token Lending CLI](./cli 1. Build the program binaries: ```shell cargo build - cargo build-bpf + cargo build-sbf ``` 1. Prepare to deploy to devnet: diff --git a/token-lending/cli/Cargo.toml b/token-lending/cli/Cargo.toml index 0981e5cc8b0..9181e0c0285 100644 --- a/token-lending/cli/Cargo.toml +++ b/token-lending/cli/Cargo.toml @@ -1,7 +1,7 @@ [package] -authors = ["Solana Maintainers "] +authors = ["Solana Labs Maintainers "] description = "SPL Token Lending CLI" -edition = "2018" +edition = "2021" homepage = "https://spl.solana.com/token-lending" license = "Apache-2.0" name = "spl-token-lending-cli" @@ -10,14 +10,14 @@ version = "0.2.0" [dependencies] clap = "2.33.3" -solana-clap-utils = "=1.10.33" -solana-cli-config = "=1.10.33" -solana-client = "=1.10.33" -solana-logger = "=1.10.33" -solana-sdk = "=1.10.33" -solana-program = "=1.10.33" +solana-clap-utils = "2.1.0" +solana-cli-config = "2.1.0" +solana-client = "2.1.0" +solana-logger = "2.1.0" +solana-sdk = "2.1.0" +solana-program = "2.1.0" spl-token-lending = { version = "0.2", path="../program", features = [ "no-entrypoint" ] } -spl-token = { version = "3.3", path="../../token/program", features = [ "no-entrypoint" ] } +spl-token = { version = "7.0", features = [ "no-entrypoint" ] } [[bin]] name = "spl-token-lending" diff --git a/token-lending/cli/src/main.rs b/token-lending/cli/src/main.rs index 3021a1dd565..3ba1eb293a6 100644 --- a/token-lending/cli/src/main.rs +++ b/token-lending/cli/src/main.rs @@ -1,3 +1,4 @@ +#![allow(clippy::arithmetic_side_effects)] use { clap::{ crate_description, crate_name, crate_version, value_t, App, AppSettings, Arg, ArgMatches, diff --git a/token-lending/flash_loan_receiver/Cargo.toml b/token-lending/flash_loan_receiver/Cargo.toml index 6eac13fd1ac..00ab194ba13 100644 --- a/token-lending/flash_loan_receiver/Cargo.toml +++ b/token-lending/flash_loan_receiver/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "flash_loan_receiver" version = "1.0.0" -edition = "2018" +edition = "2021" [dependencies] -arrayref = "0.3.6" -solana-program = "1.10.33" -spl-token = { version = "3.3", path = "../../token/program", features=["no-entrypoint"] } +arrayref = "0.3.9" +solana-program = "2.1.0" +spl-token = { version = "7.0", features=["no-entrypoint"] } [lib] crate-type = ["cdylib", "lib"] diff --git a/token-lending/flash_loan_receiver/src/entrypoint.rs b/token-lending/flash_loan_receiver/src/entrypoint.rs index 633133e1941..55b8b4c2eb7 100644 --- a/token-lending/flash_loan_receiver/src/entrypoint.rs +++ b/token-lending/flash_loan_receiver/src/entrypoint.rs @@ -1,8 +1,6 @@ -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, pubkey::Pubkey, -}; +use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey}; -entrypoint!(process_instruction); +solana_program::entrypoint!(process_instruction); fn process_instruction( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/token-lending/flash_loan_receiver/src/processor.rs b/token-lending/flash_loan_receiver/src/processor.rs index 5908632d897..f9f9c350fbd 100644 --- a/token-lending/flash_loan_receiver/src/processor.rs +++ b/token-lending/flash_loan_receiver/src/processor.rs @@ -1,12 +1,13 @@ -use std::convert::TryInto; - -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - program::invoke, - program_error::ProgramError, - pubkey::Pubkey, +use { + solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + msg, + program::invoke, + program_error::ProgramError, + pubkey::Pubkey, + }, + std::convert::TryInto, }; pub fn process_instruction( @@ -60,9 +61,8 @@ fn unpack_amount(input: &[u8]) -> Result { .and_then(|slice| slice.try_into().ok()) .map(u64::from_le_bytes) .ok_or(ProgramError::InvalidInstructionData) - .map_err(|e| { + .inspect_err(|_| { msg!("Failed to unpack amount."); - e })?; Ok(amount) } diff --git a/token-lending/js/.prettierignore b/token-lending/js/.prettierignore deleted file mode 100644 index 741a987a650..00000000000 --- a/token-lending/js/.prettierignore +++ /dev/null @@ -1,2 +0,0 @@ -docs -lib diff --git a/token-lending/js/.prettierrc b/token-lending/js/.prettierrc deleted file mode 100644 index f19e7945f9a..00000000000 --- a/token-lending/js/.prettierrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "printWidth": 120, - "trailingComma": "es5", - "tabWidth": 4, - "semi": true, - "singleQuote": true -} \ No newline at end of file diff --git a/token-lending/js/README.md b/token-lending/js/README.md index eb306b2888a..71c1ce31f9f 100644 --- a/token-lending/js/README.md +++ b/token-lending/js/README.md @@ -8,12 +8,12 @@ Install the library and its peer dependencies in your app: ### Yarn ```shell -yarn add @solana/spl-token-lending @solana/spl-token @solana/web3.js +yarn add @solana/spl-token-lending @solana/spl-token @solana/web3.js@1 ``` ### NPM ```shell -npm install @solana/spl-token-lending @solana/spl-token @solana/web3.js +npm install @solana/spl-token-lending @solana/spl-token @solana/web3.js@1 ``` ## Documentation diff --git a/token-lending/js/package.json b/token-lending/js/package.json index e1ec514396d..4da2598570c 100644 --- a/token-lending/js/package.json +++ b/token-lending/js/package.json @@ -1,9 +1,9 @@ { "name": "@solana/spl-token-lending", - "version": "0.3.4", + "version": "0.3.10", "description": "SPL Token Lending JavaScript API", "license": "MIT", - "author": "Solana Maintainers ", + "author": "Solana Labs Maintainers ", "repository": { "type": "git", "url": "https://github.com/solana-labs/solana-program-library" @@ -22,11 +22,13 @@ "lib" ], "scripts": { - "build": "rm -rf lib/* && tsc && rollup -c && rm lib/rollup.config.d.ts", - "deploy": "yarn docs && gh-pages -d docs -e token-lending", - "docs": "rm -rf docs/* && typedoc", - "lint": "eslint . --ext .ts --max-warnings 0 && prettier --check '**/*.{ts,js,json}'", - "lint:fix": "eslint . --ext .ts --fix && prettier --write '**/*.{ts,js,json}'" + "clean": "rm -rf lib/*", + "clean:docs": "rm -rf docs/*", + "build": "tsc && rollup --configPlugin @rollup/plugin-typescript -c && rm lib/rollup.config.d.ts", + "deploy": "npm docs && gh-pages -d docs -e token-lending", + "docs": "typedoc", + "lint": "eslint . --ext .ts --max-warnings 0", + "lint:fix": "eslint . --ext .ts --fix" }, "dependencies": { "@solana/buffer-layout": "^4.0.0", @@ -35,30 +37,25 @@ "bignumber.js": "^9.0.1" }, "peerDependencies": { - "@solana/spl-token": "^0.1.6", - "@solana/web3.js": "^1.20.0" + "@solana/spl-token": "0.4.9", + "@solana/web3.js": "^1.20.3" }, "devDependencies": { - "@rollup/plugin-commonjs": "^21.0.2", - "@rollup/plugin-node-resolve": "^13.1.3", - "@rollup/plugin-typescript": "^8.3.1", - "@solana/spl-token": "^0.2.0", - "@solana/web3.js": "^1.36.0", - "@types/eslint": "^8.4.1", - "@types/eslint-plugin-prettier": "^3.1.0", - "@types/node": "^16.0.0", - "@types/prettier": "^2.4.4", - "@typescript-eslint/eslint-plugin": "^5.16.0", - "@typescript-eslint/parser": "^5.16.0", - "eslint": "^8.12.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-prettier": "^4.0.0", - "gh-pages": "^3.2.3", - "prettier": "^2.6.1", - "rollup": "^2.70.1", - "ts-node": "^10.7.0", - "tslib": "^2.3.0", - "typedoc": "^0.22.13", - "typescript": "^4.6.3" + "@rollup/plugin-commonjs": "^28.0.2", + "@rollup/plugin-node-resolve": "^16.0.0", + "@rollup/plugin-typescript": "^12.1.2", + "@solana/spl-token": "0.4.9", + "@solana/web3.js": "^1.95.5", + "@types/eslint": "^8.56.7", + "@types/node": "^22.10.5", + "@typescript-eslint/eslint-plugin": "^8.4.0", + "@typescript-eslint/parser": "^8.4.0", + "eslint": "^8.57.0", + "gh-pages": "^6.3.0", + "rollup": "^4.30.1", + "ts-node": "^10.9.2", + "tslib": "^2.8.1", + "typedoc": "^0.27.6", + "typescript": "^5.7.2" } } diff --git a/token-lending/js/rollup.config.ts b/token-lending/js/rollup.config.ts index 7e688cf9b4e..fb152329dbc 100644 --- a/token-lending/js/rollup.config.ts +++ b/token-lending/js/rollup.config.ts @@ -1,9 +1,10 @@ import commonjs from '@rollup/plugin-commonjs'; import nodeResolve from '@rollup/plugin-node-resolve'; import typescript from '@rollup/plugin-typescript'; -import pkg from './package.json'; +import { RollupOptions } from 'rollup'; +import pkg from './package.json' assert { type: 'json' }; -export default { +const config: RollupOptions = { input: 'src/index.ts', output: [ { file: pkg.main, format: 'cjs', sourcemap: true }, @@ -15,3 +16,4 @@ export default { }, plugins: [typescript(), commonjs(), nodeResolve()], }; +export default config; diff --git a/token-lending/js/src/instructions/borrowObligationLiquidity.ts b/token-lending/js/src/instructions/borrowObligationLiquidity.ts index 0c7da66efd1..9b30eabc090 100644 --- a/token-lending/js/src/instructions/borrowObligationLiquidity.ts +++ b/token-lending/js/src/instructions/borrowObligationLiquidity.ts @@ -22,7 +22,7 @@ export const borrowObligationLiquidityInstruction = ( lendingMarket: PublicKey, lendingMarketAuthority: PublicKey, obligationOwner: PublicKey, - hostFeeReceiver?: PublicKey + hostFeeReceiver?: PublicKey, ): TransactionInstruction => { const data = Buffer.alloc(DataLayout.span); DataLayout.encode( @@ -30,7 +30,7 @@ export const borrowObligationLiquidityInstruction = ( instruction: LendingInstruction.BorrowObligationLiquidity, liquidityAmount: BigInt(liquidityAmount), }, - data + data, ); const keys = [ diff --git a/token-lending/js/src/instructions/depositObligationCollateral.ts b/token-lending/js/src/instructions/depositObligationCollateral.ts index 3dca3dc6cff..ab960c70058 100644 --- a/token-lending/js/src/instructions/depositObligationCollateral.ts +++ b/token-lending/js/src/instructions/depositObligationCollateral.ts @@ -20,7 +20,7 @@ export const depositObligationCollateralInstruction = ( obligation: PublicKey, lendingMarket: PublicKey, obligationOwner: PublicKey, - transferAuthority: PublicKey + transferAuthority: PublicKey, ): TransactionInstruction => { const data = Buffer.alloc(DataLayout.span); DataLayout.encode( @@ -28,7 +28,7 @@ export const depositObligationCollateralInstruction = ( instruction: LendingInstruction.DepositObligationCollateral, collateralAmount: BigInt(collateralAmount), }, - data + data, ); const keys = [ diff --git a/token-lending/js/src/instructions/depositReserveLiquidity.ts b/token-lending/js/src/instructions/depositReserveLiquidity.ts index 588e63eb3bb..e61561c4761 100644 --- a/token-lending/js/src/instructions/depositReserveLiquidity.ts +++ b/token-lending/js/src/instructions/depositReserveLiquidity.ts @@ -21,7 +21,7 @@ export const depositReserveLiquidityInstruction = ( reserveCollateralMint: PublicKey, lendingMarket: PublicKey, lendingMarketAuthority: PublicKey, - transferAuthority: PublicKey + transferAuthority: PublicKey, ): TransactionInstruction => { const data = Buffer.alloc(DataLayout.span); DataLayout.encode( @@ -29,7 +29,7 @@ export const depositReserveLiquidityInstruction = ( instruction: LendingInstruction.DepositReserveLiquidity, liquidityAmount: BigInt(liquidityAmount), }, - data + data, ); const keys = [ diff --git a/token-lending/js/src/instructions/flashLoan.ts b/token-lending/js/src/instructions/flashLoan.ts index 35d5bf01425..96d7cfc68d8 100644 --- a/token-lending/js/src/instructions/flashLoan.ts +++ b/token-lending/js/src/instructions/flashLoan.ts @@ -22,7 +22,7 @@ export const flashLoanInstruction = ( lendingMarket: PublicKey, lendingMarketAuthority: PublicKey, flashLoanProgram: PublicKey, - transferAuthority: PublicKey + transferAuthority: PublicKey, ): TransactionInstruction => { const data = Buffer.alloc(DataLayout.span); DataLayout.encode( @@ -30,7 +30,7 @@ export const flashLoanInstruction = ( instruction: LendingInstruction.FlashLoan, liquidityAmount: BigInt(liquidityAmount), }, - data + data, ); const keys = [ diff --git a/token-lending/js/src/instructions/initLendingMarket.ts b/token-lending/js/src/instructions/initLendingMarket.ts index 9c05c08bf47..f9f83f9f177 100644 --- a/token-lending/js/src/instructions/initLendingMarket.ts +++ b/token-lending/js/src/instructions/initLendingMarket.ts @@ -16,7 +16,7 @@ const DataLayout = struct([u8('instruction'), publicKey('owner'), blob(32, export const initLendingMarketInstruction = ( owner: PublicKey, quoteCurrency: Uint8Array, - lendingMarket: PublicKey + lendingMarket: PublicKey, ): TransactionInstruction => { const data = Buffer.alloc(DataLayout.span); DataLayout.encode( @@ -25,7 +25,7 @@ export const initLendingMarketInstruction = ( owner, quoteCurrency, }, - data + data, ); const keys = [ diff --git a/token-lending/js/src/instructions/initObligation.ts b/token-lending/js/src/instructions/initObligation.ts index 60911f43326..b59ef1d5357 100644 --- a/token-lending/js/src/instructions/initObligation.ts +++ b/token-lending/js/src/instructions/initObligation.ts @@ -13,7 +13,7 @@ const DataLayout = struct([u8('instruction')]); export const initObligationInstruction = ( obligation: PublicKey, lendingMarket: PublicKey, - obligationOwner: PublicKey + obligationOwner: PublicKey, ): TransactionInstruction => { const data = Buffer.alloc(DataLayout.span); DataLayout.encode({ instruction: LendingInstruction.InitObligation }, data); diff --git a/token-lending/js/src/instructions/initReserve.ts b/token-lending/js/src/instructions/initReserve.ts index 936459d619f..4d5c6ee567e 100644 --- a/token-lending/js/src/instructions/initReserve.ts +++ b/token-lending/js/src/instructions/initReserve.ts @@ -30,7 +30,7 @@ export const initReserveInstruction = ( lendingMarket: PublicKey, lendingMarketAuthority: PublicKey, lendingMarketOwner: PublicKey, - transferAuthority: PublicKey + transferAuthority: PublicKey, ): TransactionInstruction => { const data = Buffer.alloc(DataLayout.span); DataLayout.encode( @@ -39,7 +39,7 @@ export const initReserveInstruction = ( liquidityAmount: BigInt(liquidityAmount), config, }, - data + data, ); const keys = [ diff --git a/token-lending/js/src/instructions/liquidateObligation.ts b/token-lending/js/src/instructions/liquidateObligation.ts index df0f338a90e..77264289299 100644 --- a/token-lending/js/src/instructions/liquidateObligation.ts +++ b/token-lending/js/src/instructions/liquidateObligation.ts @@ -23,7 +23,7 @@ export const liquidateObligationInstruction = ( obligation: PublicKey, lendingMarket: PublicKey, lendingMarketAuthority: PublicKey, - transferAuthority: PublicKey + transferAuthority: PublicKey, ): TransactionInstruction => { const data = Buffer.alloc(DataLayout.span); DataLayout.encode( @@ -31,7 +31,7 @@ export const liquidateObligationInstruction = ( instruction: LendingInstruction.LiquidateObligation, liquidityAmount: BigInt(liquidityAmount), }, - data + data, ); const keys = [ diff --git a/token-lending/js/src/instructions/redeemReserveCollateral.ts b/token-lending/js/src/instructions/redeemReserveCollateral.ts index 40c66a1350c..c4bbf09566e 100644 --- a/token-lending/js/src/instructions/redeemReserveCollateral.ts +++ b/token-lending/js/src/instructions/redeemReserveCollateral.ts @@ -21,7 +21,7 @@ export const redeemReserveCollateralInstruction = ( reserveLiquiditySupply: PublicKey, lendingMarket: PublicKey, lendingMarketAuthority: PublicKey, - transferAuthority: PublicKey + transferAuthority: PublicKey, ): TransactionInstruction => { const data = Buffer.alloc(DataLayout.span); DataLayout.encode( @@ -29,7 +29,7 @@ export const redeemReserveCollateralInstruction = ( instruction: LendingInstruction.RedeemReserveCollateral, collateralAmount: BigInt(collateralAmount), }, - data + data, ); const keys = [ diff --git a/token-lending/js/src/instructions/refreshObligation.ts b/token-lending/js/src/instructions/refreshObligation.ts index e673dd5192b..f2eb43ee2e2 100644 --- a/token-lending/js/src/instructions/refreshObligation.ts +++ b/token-lending/js/src/instructions/refreshObligation.ts @@ -12,7 +12,7 @@ const DataLayout = struct([u8('instruction')]); export const refreshObligationInstruction = ( obligation: PublicKey, depositReserves: PublicKey[], - borrowReserves: PublicKey[] + borrowReserves: PublicKey[], ): TransactionInstruction => { const data = Buffer.alloc(DataLayout.span); DataLayout.encode({ instruction: LendingInstruction.RefreshObligation }, data); diff --git a/token-lending/js/src/instructions/repayObligationLiquidity.ts b/token-lending/js/src/instructions/repayObligationLiquidity.ts index 0a63173ff25..7af02463fb8 100644 --- a/token-lending/js/src/instructions/repayObligationLiquidity.ts +++ b/token-lending/js/src/instructions/repayObligationLiquidity.ts @@ -19,7 +19,7 @@ export const repayObligationLiquidityInstruction = ( repayReserve: PublicKey, obligation: PublicKey, lendingMarket: PublicKey, - transferAuthority: PublicKey + transferAuthority: PublicKey, ): TransactionInstruction => { const data = Buffer.alloc(DataLayout.span); DataLayout.encode( @@ -27,7 +27,7 @@ export const repayObligationLiquidityInstruction = ( instruction: LendingInstruction.RepayObligationLiquidity, liquidityAmount: BigInt(liquidityAmount), }, - data + data, ); const keys = [ diff --git a/token-lending/js/src/instructions/setLendingMarketOwner.ts b/token-lending/js/src/instructions/setLendingMarketOwner.ts index b1b98a95299..9007d72e5a1 100644 --- a/token-lending/js/src/instructions/setLendingMarketOwner.ts +++ b/token-lending/js/src/instructions/setLendingMarketOwner.ts @@ -14,7 +14,7 @@ const DataLayout = struct([u8('instruction'), publicKey('newOwner')]); export const setLendingMarketOwnerInstruction = ( newOwner: PublicKey, lendingMarket: PublicKey, - currentOwner: PublicKey + currentOwner: PublicKey, ): TransactionInstruction => { const data = Buffer.alloc(DataLayout.span); DataLayout.encode( @@ -22,7 +22,7 @@ export const setLendingMarketOwnerInstruction = ( instruction: LendingInstruction.SetLendingMarketOwner, newOwner, }, - data + data, ); const keys = [ diff --git a/token-lending/js/src/instructions/withdrawObligationCollateral.ts b/token-lending/js/src/instructions/withdrawObligationCollateral.ts index 1b8178c6cf5..9087fc316b3 100644 --- a/token-lending/js/src/instructions/withdrawObligationCollateral.ts +++ b/token-lending/js/src/instructions/withdrawObligationCollateral.ts @@ -20,7 +20,7 @@ export const withdrawObligationCollateralInstruction = ( obligation: PublicKey, lendingMarket: PublicKey, lendingMarketAuthority: PublicKey, - obligationOwner: PublicKey + obligationOwner: PublicKey, ): TransactionInstruction => { const data = Buffer.alloc(DataLayout.span); DataLayout.encode( @@ -28,7 +28,7 @@ export const withdrawObligationCollateralInstruction = ( instruction: LendingInstruction.WithdrawObligationCollateral, collateralAmount: BigInt(collateralAmount), }, - data + data, ); const keys = [ diff --git a/token-lending/js/src/state/lendingMarket.ts b/token-lending/js/src/state/lendingMarket.ts index 8768a3138f7..3a6530535b4 100644 --- a/token-lending/js/src/state/lendingMarket.ts +++ b/token-lending/js/src/state/lendingMarket.ts @@ -23,7 +23,7 @@ export const LendingMarketLayout = struct( publicKey('oracleProgramId'), blob(128, 'padding'), ], - 'lendingMarket' + 'lendingMarket', ); export const LENDING_MARKET_SIZE = LendingMarketLayout.span; diff --git a/token-lending/js/src/state/obligation.ts b/token-lending/js/src/state/obligation.ts index ba455df1ab0..61949959e4e 100644 --- a/token-lending/js/src/state/obligation.ts +++ b/token-lending/js/src/state/obligation.ts @@ -49,7 +49,7 @@ export interface ObligationDataFlat { /** @internal */ export const ObligationCollateralLayout = struct( [publicKey('depositReserve'), u64('depositedAmount'), decimal('marketValue')], - 'collateral' + 'collateral', ); /** @internal */ @@ -60,7 +60,7 @@ export const ObligationLiquidityLayout = struct( decimal('borrowedAmountWads'), decimal('marketValue'), ], - 'liquidity' + 'liquidity', ); /** @internal */ @@ -78,7 +78,7 @@ export const ObligationLayout = struct( u8('borrowsLen'), blob(ObligationCollateralLayout.span + 9 * ObligationLiquidityLayout.span, 'dataFlat'), ], - 'obligation' + 'obligation', ); export const OBLIGATION_SIZE = ObligationLayout.span; diff --git a/token-lending/js/src/state/reserve.ts b/token-lending/js/src/state/reserve.ts index 1c242a67006..0c9ac718adb 100644 --- a/token-lending/js/src/state/reserve.ts +++ b/token-lending/js/src/state/reserve.ts @@ -63,19 +63,19 @@ export const ReserveLiquidityLayout = struct( decimal('cumulativeBorrowRateWads'), decimal('marketPrice'), ], - 'liquidity' + 'liquidity', ); /** @internal */ export const ReserveCollateralLayout = struct( [publicKey('mintPubkey'), u64('mintTotalSupply'), publicKey('supplyPubkey')], - 'collateral' + 'collateral', ); /** @internal */ export const ReserveFeesLayout = struct( [u64('borrowFeeWad'), u64('flashLoanFeeWad'), u8('hostFeePercentage')], - 'fees' + 'fees', ); /** @internal */ @@ -90,7 +90,7 @@ export const ReserveConfigLayout = struct( u8('maxBorrowRate'), ReserveFeesLayout, ], - 'config' + 'config', ); /** @internal */ diff --git a/token-lending/js/src/util/layout.ts b/token-lending/js/src/util/layout.ts index dc55b09b82b..6d1a3cb8dec 100644 --- a/token-lending/js/src/util/layout.ts +++ b/token-lending/js/src/util/layout.ts @@ -2,7 +2,7 @@ import { AccountInfo, PublicKey } from '@solana/web3.js'; export type Parser = ( pubkey: PublicKey, - info: AccountInfo + info: AccountInfo, ) => | { pubkey: PublicKey; diff --git a/token-lending/js/tsconfig.json b/token-lending/js/tsconfig.json index eda3ea00e1d..9a8ce86d220 100644 --- a/token-lending/js/tsconfig.json +++ b/token-lending/js/tsconfig.json @@ -3,7 +3,6 @@ "target": "esnext", "emitDeclarationOnly": true, "outDir": "lib", - "typeRoots": ["node_modules/@types", "types"], "module": "esnext", "esModuleInterop": true, "resolveJsonModule": true, diff --git a/token-lending/js/yarn.lock b/token-lending/js/yarn.lock deleted file mode 100644 index a4b0a08306d..00000000000 --- a/token-lending/js/yarn.lock +++ /dev/null @@ -1,2111 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5": - version "7.16.5" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.5.tgz#7f3e34bf8bdbbadf03fbb7b1ea0d929569c9487a" - integrity sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA== - dependencies: - regenerator-runtime "^0.13.4" - -"@cspotcode/source-map-consumer@0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" - integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== - -"@cspotcode/source-map-support@0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5" - integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA== - dependencies: - "@cspotcode/source-map-consumer" "0.8.0" - -"@eslint/eslintrc@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.1.tgz#8b5e1c49f4077235516bc9ec7d41378c0f69b8c6" - integrity sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ== - dependencies: - ajv "^6.12.4" - debug "^4.3.2" - espree "^9.3.1" - globals "^13.9.0" - ignore "^5.2.0" - import-fresh "^3.2.1" - js-yaml "^4.1.0" - minimatch "^3.0.4" - strip-json-comments "^3.1.1" - -"@ethersproject/bytes@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.5.0.tgz#cb11c526de657e7b45d2e0f0246fb3b9d29a601c" - integrity sha512-ABvc7BHWhZU9PNM/tANm/Qx4ostPGadAuQzWTr3doklZOhDlmcBqclrQe/ZXUIj3K8wC28oYeuRa+A37tX9kog== - dependencies: - "@ethersproject/logger" "^5.5.0" - -"@ethersproject/logger@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.5.0.tgz#0c2caebeff98e10aefa5aef27d7441c7fd18cf5d" - integrity sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg== - -"@ethersproject/sha2@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.5.0.tgz#a40a054c61f98fd9eee99af2c3cc6ff57ec24db7" - integrity sha512-B5UBoglbCiHamRVPLA110J+2uqsifpZaTmid2/7W5rbtYVz6gus6/hSDieIU/6gaKIDcOj12WnOdiymEUHIAOA== - dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - hash.js "1.1.7" - -"@hapi/hoek@^9.0.0": - version "9.2.1" - resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.2.1.tgz#9551142a1980503752536b5050fd99f4a7f13b17" - integrity sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw== - -"@hapi/topo@^5.0.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012" - integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== - dependencies: - "@hapi/hoek" "^9.0.0" - -"@humanwhocodes/config-array@^0.9.2": - version "0.9.2" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.2.tgz#68be55c737023009dfc5fe245d51181bb6476914" - integrity sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA== - dependencies: - "@humanwhocodes/object-schema" "^1.2.1" - debug "^4.1.1" - minimatch "^3.0.4" - -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== - -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - -"@nodelib/fs.walk@^1.2.3": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - -"@rollup/plugin-commonjs@^21.0.2": - version "21.0.2" - resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-21.0.2.tgz#0b9c539aa1837c94abfaf87945838b0fc8564891" - integrity sha512-d/OmjaLVO4j/aQX69bwpWPpbvI3TJkQuxoAk7BH8ew1PyoMBLTOuvJTjzG8oEoW7drIIqB0KCJtfFLu/2GClWg== - dependencies: - "@rollup/pluginutils" "^3.1.0" - commondir "^1.0.1" - estree-walker "^2.0.1" - glob "^7.1.6" - is-reference "^1.2.1" - magic-string "^0.25.7" - resolve "^1.17.0" - -"@rollup/plugin-node-resolve@^13.1.3": - version "13.1.3" - resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.1.3.tgz#2ed277fb3ad98745424c1d2ba152484508a92d79" - integrity sha512-BdxNk+LtmElRo5d06MGY4zoepyrXX1tkzX2hrnPEZ53k78GuOMWLqmJDGIIOPwVRIFZrLQOo+Yr6KtCuLIA0AQ== - dependencies: - "@rollup/pluginutils" "^3.1.0" - "@types/resolve" "1.17.1" - builtin-modules "^3.1.0" - deepmerge "^4.2.2" - is-module "^1.0.0" - resolve "^1.19.0" - -"@rollup/plugin-typescript@^8.3.1": - version "8.3.1" - resolved "https://registry.yarnpkg.com/@rollup/plugin-typescript/-/plugin-typescript-8.3.1.tgz#b7dc75ed6b4876e260b9e80624fab23bc98e4ac1" - integrity sha512-84rExe3ICUBXzqNX48WZV2Jp3OddjTMX97O2Py6D1KJaGSwWp0mDHXj+bCGNJqWHIEKDIT2U0sDjhP4czKi6cA== - dependencies: - "@rollup/pluginutils" "^3.1.0" - resolve "^1.17.0" - -"@rollup/pluginutils@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b" - integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg== - dependencies: - "@types/estree" "0.0.39" - estree-walker "^1.0.1" - picomatch "^2.2.2" - -"@sideway/address@^4.1.3": - version "4.1.4" - resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0" - integrity sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw== - dependencies: - "@hapi/hoek" "^9.0.0" - -"@sideway/formula@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.0.tgz#fe158aee32e6bd5de85044be615bc08478a0a13c" - integrity sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg== - -"@sideway/pinpoint@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" - integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== - -"@solana/buffer-layout-utils@^0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz#b45a6cab3293a2eb7597cceb474f229889d875ca" - integrity sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g== - dependencies: - "@solana/buffer-layout" "^4.0.0" - "@solana/web3.js" "^1.32.0" - bigint-buffer "^1.1.5" - bignumber.js "^9.0.1" - -"@solana/buffer-layout@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-3.0.0.tgz#b9353caeb9a1589cb77a1b145bcb1a9a93114326" - integrity sha512-MVdgAKKL39tEs0l8je0hKaXLQFb7Rdfb0Xg2LjFZd8Lfdazkg6xiS98uAZrEKvaoF3i4M95ei9RydkGIDMeo3w== - dependencies: - buffer "~6.0.3" - -"@solana/buffer-layout@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-4.0.0.tgz#75b1b11adc487234821c81dfae3119b73a5fd734" - integrity sha512-lR0EMP2HC3+Mxwd4YcnZb0smnaDw7Bl2IQWZiTevRH5ZZBZn6VRWn3/92E3qdU4SSImJkA6IDHawOHAnx/qUvQ== - dependencies: - buffer "~6.0.3" - -"@solana/spl-token@^0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@solana/spl-token/-/spl-token-0.2.0.tgz#329bb6babb5de0f9c40035ddb1657f01a8347acd" - integrity sha512-RWcn31OXtdqIxmkzQfB2R+WpsJOVS6rKuvpxJFjvik2LyODd+WN58ZP3Rpjpro03fscGAkzlFuP3r42doRJgyQ== - dependencies: - "@solana/buffer-layout" "^4.0.0" - "@solana/buffer-layout-utils" "^0.2.0" - "@solana/web3.js" "^1.32.0" - start-server-and-test "^1.14.0" - -"@solana/web3.js@^1.32.0": - version "1.32.0" - resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.32.0.tgz#b9821de52d0e773c363516c3dcef9be701295d82" - integrity sha512-jquZ/VBvM3zXAaTJvdWd9mlP0WiZaZqjji0vw5UAsb5IKIossrLhHtyUqMfo41Qkdwu1aVwf7YWG748i4XIJnw== - dependencies: - "@babel/runtime" "^7.12.5" - "@ethersproject/sha2" "^5.5.0" - "@solana/buffer-layout" "^3.0.0" - bn.js "^5.0.0" - borsh "^0.4.0" - bs58 "^4.0.1" - buffer "6.0.1" - cross-fetch "^3.1.4" - jayson "^3.4.4" - js-sha3 "^0.8.0" - rpc-websockets "^7.4.2" - secp256k1 "^4.0.2" - superstruct "^0.14.2" - tweetnacl "^1.0.0" - -"@solana/web3.js@^1.36.0": - version "1.36.0" - resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.36.0.tgz#79d7d5217b49b80139f4de68953adc5b9a9a264f" - integrity sha512-RNT1451iRR7TyW7EJKMCrH/0OXawIe4zVm0DWQASwXlR/u1jmW6FrmH0lujIh7cGTlfOVbH+2ZU9AVUPLBFzwA== - dependencies: - "@babel/runtime" "^7.12.5" - "@ethersproject/sha2" "^5.5.0" - "@solana/buffer-layout" "^3.0.0" - bn.js "^5.0.0" - borsh "^0.4.0" - bs58 "^4.0.1" - buffer "6.0.1" - cross-fetch "^3.1.4" - jayson "^3.4.4" - js-sha3 "^0.8.0" - rpc-websockets "^7.4.2" - secp256k1 "^4.0.2" - superstruct "^0.14.2" - tweetnacl "^1.0.0" - -"@tsconfig/node10@^1.0.7": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" - integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg== - -"@tsconfig/node12@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" - integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw== - -"@tsconfig/node14@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" - integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== - -"@tsconfig/node16@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" - integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== - -"@types/bn.js@^4.11.5": - version "4.11.6" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" - integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== - dependencies: - "@types/node" "*" - -"@types/connect@^3.4.33": - version "3.4.35" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" - integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== - dependencies: - "@types/node" "*" - -"@types/eslint-plugin-prettier@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@types/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.0.tgz#451b5e1e5f148a38dc41e9c5b61d45cd2e97af2c" - integrity sha512-6/UIuz99F0IvtDez4U3bRwAmN4VKnuw10Ibblf0iZhtNbmbonMSLqs/qqsXrGIAWvjy+vXqYwOljgtLhrETSMg== - dependencies: - "@types/eslint" "*" - -"@types/eslint@*": - version "8.2.1" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.2.1.tgz#13f3d69bac93c2ae008019c28783868d0a1d6605" - integrity sha512-UP9rzNn/XyGwb5RQ2fok+DzcIRIYwc16qTXse5+Smsy8MOIccCChT15KAwnsgQx4PzJkaMq4myFyZ4CL5TjhIQ== - dependencies: - "@types/estree" "*" - "@types/json-schema" "*" - -"@types/eslint@^8.4.1": - version "8.4.1" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.1.tgz#c48251553e8759db9e656de3efc846954ac32304" - integrity sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA== - dependencies: - "@types/estree" "*" - "@types/json-schema" "*" - -"@types/estree@*": - version "0.0.50" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" - integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== - -"@types/estree@0.0.39": - version "0.0.39" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" - integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== - -"@types/express-serve-static-core@^4.17.9": - version "4.17.26" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.26.tgz#5d9a8eeecb9d5f9d7fc1d85f541512a84638ae88" - integrity sha512-zeu3tpouA043RHxW0gzRxwCHchMgftE8GArRsvYT0ByDMbn19olQHx5jLue0LxWY6iYtXb7rXmuVtSkhy9YZvQ== - dependencies: - "@types/node" "*" - "@types/qs" "*" - "@types/range-parser" "*" - -"@types/json-schema@*": - version "7.0.9" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" - integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== - -"@types/json-schema@^7.0.9": - version "7.0.11" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" - integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== - -"@types/lodash@^4.14.159": - version "4.14.178" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.178.tgz#341f6d2247db528d4a13ddbb374bcdc80406f4f8" - integrity sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw== - -"@types/node@*": - version "17.0.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.0.tgz#62797cee3b8b497f6547503b2312254d4fe3c2bb" - integrity sha512-eMhwJXc931Ihh4tkU+Y7GiLzT/y/DBNpNtr4yU9O2w3SYBsr9NaOPhQlLKRmoWtI54uNwuo0IOUFQjVOTZYRvw== - -"@types/node@^12.12.54": - version "12.20.37" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.37.tgz#abb38afa9d6e8a2f627a8cb52290b3c80fbe61ed" - integrity sha512-i1KGxqcvJaLQali+WuypQnXwcplhtNtjs66eNsZpp2P2FL/trJJxx/VWsM0YCL2iMoIJrbXje48lvIQAQ4p2ZA== - -"@types/node@^16.0.0": - version "16.11.14" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.14.tgz#4939fb42e5b0ffb3ea7e193c28244fe7414977a6" - integrity sha512-mK6BKLpL0bG6v2CxHbm0ed6RcZrAtTHBTd/ZpnlVPVa3HkumsqLE4BC4u6TQ8D7pnrRbOU0am6epuALs+Ncnzw== - -"@types/prettier@^2.4.4": - version "2.4.4" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.4.4.tgz#5d9b63132df54d8909fce1c3f8ca260fdd693e17" - integrity sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA== - -"@types/qs@*": - version "6.9.7" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" - integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== - -"@types/range-parser@*": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" - integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== - -"@types/resolve@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6" - integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw== - dependencies: - "@types/node" "*" - -"@types/ws@^7.4.4": - version "7.4.7" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" - integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== - dependencies: - "@types/node" "*" - -"@typescript-eslint/eslint-plugin@^5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.16.0.tgz#78f246dd8d1b528fc5bfca99a8a64d4023a3d86d" - integrity sha512-SJoba1edXvQRMmNI505Uo4XmGbxCK9ARQpkvOd00anxzri9RNQk0DDCxD+LIl+jYhkzOJiOMMKYEHnHEODjdCw== - dependencies: - "@typescript-eslint/scope-manager" "5.16.0" - "@typescript-eslint/type-utils" "5.16.0" - "@typescript-eslint/utils" "5.16.0" - debug "^4.3.2" - functional-red-black-tree "^1.0.1" - ignore "^5.1.8" - regexpp "^3.2.0" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/parser@^5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.16.0.tgz#e4de1bde4b4dad5b6124d3da227347616ed55508" - integrity sha512-fkDq86F0zl8FicnJtdXakFs4lnuebH6ZADDw6CYQv0UZeIjHvmEw87m9/29nk2Dv5Lmdp0zQ3zDQhiMWQf/GbA== - dependencies: - "@typescript-eslint/scope-manager" "5.16.0" - "@typescript-eslint/types" "5.16.0" - "@typescript-eslint/typescript-estree" "5.16.0" - debug "^4.3.2" - -"@typescript-eslint/scope-manager@5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.16.0.tgz#7e7909d64bd0c4d8aef629cdc764b9d3e1d3a69a" - integrity sha512-P+Yab2Hovg8NekLIR/mOElCDPyGgFZKhGoZA901Yax6WR6HVeGLbsqJkZ+Cvk5nts/dAlFKm8PfL43UZnWdpIQ== - dependencies: - "@typescript-eslint/types" "5.16.0" - "@typescript-eslint/visitor-keys" "5.16.0" - -"@typescript-eslint/type-utils@5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.16.0.tgz#b482bdde1d7d7c0c7080f7f2f67ea9580b9e0692" - integrity sha512-SKygICv54CCRl1Vq5ewwQUJV/8padIWvPgCxlWPGO/OgQLCijY9G7lDu6H+mqfQtbzDNlVjzVWQmeqbLMBLEwQ== - dependencies: - "@typescript-eslint/utils" "5.16.0" - debug "^4.3.2" - tsutils "^3.21.0" - -"@typescript-eslint/types@5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.16.0.tgz#5827b011982950ed350f075eaecb7f47d3c643ee" - integrity sha512-oUorOwLj/3/3p/HFwrp6m/J2VfbLC8gjW5X3awpQJ/bSG+YRGFS4dpsvtQ8T2VNveV+LflQHjlLvB6v0R87z4g== - -"@typescript-eslint/typescript-estree@5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.16.0.tgz#32259459ec62f5feddca66adc695342f30101f61" - integrity sha512-SE4VfbLWUZl9MR+ngLSARptUv2E8brY0luCdgmUevU6arZRY/KxYoLI/3V/yxaURR8tLRN7bmZtJdgmzLHI6pQ== - dependencies: - "@typescript-eslint/types" "5.16.0" - "@typescript-eslint/visitor-keys" "5.16.0" - debug "^4.3.2" - globby "^11.0.4" - is-glob "^4.0.3" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/utils@5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.16.0.tgz#42218b459d6d66418a4eb199a382bdc261650679" - integrity sha512-iYej2ER6AwmejLWMWzJIHy3nPJeGDuCqf8Jnb+jAQVoPpmWzwQOfa9hWVB8GIQE5gsCv/rfN4T+AYb/V06WseQ== - dependencies: - "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.16.0" - "@typescript-eslint/types" "5.16.0" - "@typescript-eslint/typescript-estree" "5.16.0" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - -"@typescript-eslint/visitor-keys@5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.16.0.tgz#f27dc3b943e6317264c7492e390c6844cd4efbbb" - integrity sha512-jqxO8msp5vZDhikTwq9ubyMHqZ67UIvawohr4qF3KhlpL7gzSjOd+8471H3nh5LyABkaI85laEKKU8SnGUK5/g== - dependencies: - "@typescript-eslint/types" "5.16.0" - eslint-visitor-keys "^3.0.0" - -JSONStream@^1.3.5: - version "1.3.5" - resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" - integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== - dependencies: - jsonparse "^1.2.0" - through ">=2.2.7 <3" - -acorn-jsx@^5.3.1: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -acorn-walk@^8.1.1: - version "8.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" - integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== - -acorn@^8.4.1: - version "8.6.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.6.0.tgz#e3692ba0eb1a0c83eaa4f37f5fa7368dd7142895" - integrity sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw== - -acorn@^8.7.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" - integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== - -ajv@^6.10.0, ajv@^6.12.4: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - -array-union@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= - dependencies: - array-uniq "^1.0.1" - -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -array-uniq@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= - -async@^2.6.1: - version "2.6.3" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" - integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== - dependencies: - lodash "^4.17.14" - -axios@^0.21.1: - version "0.21.4" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" - integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== - dependencies: - follow-redirects "^1.14.0" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -base-x@^3.0.2: - version "3.0.9" - resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" - integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== - dependencies: - safe-buffer "^5.0.1" - -base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -bigint-buffer@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/bigint-buffer/-/bigint-buffer-1.1.5.tgz#d038f31c8e4534c1f8d0015209bf34b4fa6dd442" - integrity sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA== - dependencies: - bindings "^1.3.0" - -bignumber.js@^9.0.1: - version "9.0.2" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.2.tgz#71c6c6bed38de64e24a65ebe16cfcf23ae693673" - integrity sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw== - -bindings@^1.3.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - -bluebird@3.7.2: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - -bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - -bn.js@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" - integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== - -borsh@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.4.0.tgz#9dd6defe741627f1315eac2a73df61421f6ddb9f" - integrity sha512-aX6qtLya3K0AkT66CmYWCCDr77qsE9arV05OmdFpmat9qu8Pg9J5tBUPDztAW5fNh/d/MyVG/OYziP52Ndzx1g== - dependencies: - "@types/bn.js" "^4.11.5" - bn.js "^5.0.0" - bs58 "^4.0.0" - text-encoding-utf-8 "^1.0.2" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== - dependencies: - balanced-match "^1.0.0" - -braces@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -brorand@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= - -bs58@^4.0.0, bs58@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" - integrity sha1-vhYedsNU9veIrkBx9j806MTwpCo= - dependencies: - base-x "^3.0.2" - -buffer@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.1.tgz#3cbea8c1463e5a0779e30b66d4c88c6ffa182ac2" - integrity sha512-rVAXBwEcEoYtxnHSO5iWyhzV/O1WMtkUYWlfdLS7FjU4PnSJJHEfHXi/uHPI5EwltmOA794gN3bm3/pzuctWjQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - -buffer@~6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - -bufferutil@^4.0.1: - version "4.0.5" - resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.5.tgz#da9ea8166911cc276bf677b8aed2d02d31f59028" - integrity sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A== - dependencies: - node-gyp-build "^4.3.0" - -builtin-modules@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.2.0.tgz#45d5db99e7ee5e6bc4f362e008bf917ab5049887" - integrity sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA== - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -chalk@^4.0.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -check-more-types@2.24.0: - version "2.24.0" - resolved "https://registry.yarnpkg.com/check-more-types/-/check-more-types-2.24.0.tgz#1420ffb10fd444dcfc79b43891bbfffd32a84600" - integrity sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA= - -circular-json@^0.5.9: - version "0.5.9" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.9.tgz#932763ae88f4f7dead7a0d09c8a51a4743a53b1d" - integrity sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ== - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -commander@^2.18.0, commander@^2.20.3: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -create-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== - -cross-fetch@^3.1.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39" - integrity sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ== - dependencies: - node-fetch "2.6.1" - -cross-spawn@^7.0.2, cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -debug@4.3.2: - version "4.3.2" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" - integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== - dependencies: - ms "2.1.2" - -debug@^4.1.1, debug@^4.3.2: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== - dependencies: - ms "2.1.2" - -deep-is@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== - -deepmerge@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" - integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== - -delay@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" - integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== - -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -duplexer@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" - integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== - -elliptic@^6.5.2: - version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - -email-addresses@^3.0.1: - version "3.1.0" - resolved "https://registry.yarnpkg.com/email-addresses/-/email-addresses-3.1.0.tgz#cabf7e085cbdb63008a70319a74e6136188812fb" - integrity sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg== - -es6-promise@^4.0.3: - version "4.2.8" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" - integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== - -es6-promisify@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" - integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= - dependencies: - es6-promise "^4.0.3" - -escape-string-regexp@^1.0.2: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -eslint-config-prettier@^8.5.0: - version "8.5.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz#5a81680ec934beca02c7b1a61cf8ca34b66feab1" - integrity sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q== - -eslint-plugin-prettier@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz#8b99d1e4b8b24a762472b4567992023619cb98e0" - integrity sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ== - dependencies: - prettier-linter-helpers "^1.0.0" - -eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-scope@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" - integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== - dependencies: - esrecurse "^4.3.0" - estraverse "^5.2.0" - -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - -eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" - integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== - -eslint@^8.12.0: - version "8.12.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.12.0.tgz#c7a5bd1cfa09079aae64c9076c07eada66a46e8e" - integrity sha512-it1oBL9alZg1S8UycLm5YDMAkIhtH6FtAzuZs6YvoGVldWjbS08BkAdb/ymP9LlAyq8koANu32U7Ib/w+UNh8Q== - dependencies: - "@eslint/eslintrc" "^1.2.1" - "@humanwhocodes/config-array" "^0.9.2" - ajv "^6.10.0" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.3.2" - doctrine "^3.0.0" - escape-string-regexp "^4.0.0" - eslint-scope "^7.1.1" - eslint-utils "^3.0.0" - eslint-visitor-keys "^3.3.0" - espree "^9.3.1" - esquery "^1.4.0" - esutils "^2.0.2" - fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^6.0.1" - globals "^13.6.0" - ignore "^5.2.0" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - js-yaml "^4.1.0" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash.merge "^4.6.2" - minimatch "^3.0.4" - natural-compare "^1.4.0" - optionator "^0.9.1" - regexpp "^3.2.0" - strip-ansi "^6.0.1" - strip-json-comments "^3.1.0" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -espree@^9.3.1: - version "9.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.1.tgz#8793b4bc27ea4c778c19908e0719e7b8f4115bcd" - integrity sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ== - dependencies: - acorn "^8.7.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^3.3.0" - -esquery@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -estree-walker@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" - integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== - -estree-walker@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" - integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -event-stream@=3.3.4: - version "3.3.4" - resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" - integrity sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE= - dependencies: - duplexer "~0.1.1" - from "~0" - map-stream "~0.1.0" - pause-stream "0.0.11" - split "0.3" - stream-combiner "~0.0.4" - through "~2.3.1" - -eventemitter3@^4.0.7: - version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" - integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== - -execa@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - -eyes@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" - integrity sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A= - -fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-diff@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" - integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== - -fast-glob@^3.2.9: - version "3.2.11" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" - integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -fastq@^1.6.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" - integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== - dependencies: - reusify "^1.0.4" - -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== - dependencies: - flat-cache "^3.0.4" - -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - -filename-reserved-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229" - integrity sha1-q/c9+rc10EVECr/qLZHzieu/oik= - -filenamify@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/filenamify/-/filenamify-4.3.0.tgz#62391cb58f02b09971c9d4f9d63b3cf9aba03106" - integrity sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg== - dependencies: - filename-reserved-regex "^2.0.0" - strip-outer "^1.0.1" - trim-repeated "^1.0.0" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -find-cache-dir@^3.3.1: - version "3.3.2" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" - integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== - dependencies: - commondir "^1.0.1" - make-dir "^3.0.2" - pkg-dir "^4.1.0" - -find-up@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== - dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" - -flatted@^3.1.0: - version "3.2.4" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.4.tgz#28d9969ea90661b5134259f312ab6aa7929ac5e2" - integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw== - -follow-redirects@^1.14.0: - version "1.14.9" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7" - integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w== - -from@~0: - version "0.1.7" - resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" - integrity sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4= - -fs-extra@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - -gh-pages@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/gh-pages/-/gh-pages-3.2.3.tgz#897e5f15e111f42af57d21d430b83e5cdf29472c" - integrity sha512-jA1PbapQ1jqzacECfjUaO9gV8uBgU6XNMV0oXLtfCX3haGLe5Atq8BxlrADhbD6/UdG9j6tZLWAkAybndOXTJg== - dependencies: - async "^2.6.1" - commander "^2.18.0" - email-addresses "^3.0.1" - filenamify "^4.3.0" - find-cache-dir "^3.3.1" - fs-extra "^8.1.0" - globby "^6.1.0" - -glob-parent@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob-parent@^6.0.1: - version "6.0.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" - integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== - dependencies: - is-glob "^4.0.3" - -glob@^7.0.3, glob@^7.1.3, glob@^7.1.6, glob@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^13.6.0, globals@^13.9.0: - version "13.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.12.0.tgz#4d733760304230a0082ed96e21e5c565f898089e" - integrity sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg== - dependencies: - type-fest "^0.20.2" - -globby@^11.0.4: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" - -globby@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" - integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= - dependencies: - array-union "^1.0.1" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -graceful-fs@^4.1.6, graceful-fs@^4.2.0: - version "4.2.8" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" - integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - -ieee754@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -ignore@^5.1.8: - version "5.1.9" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.9.tgz#9ec1a5cbe8e1446ec60d4420060d43aa6e7382fb" - integrity sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ== - -ignore@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" - integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== - -import-fresh@^3.0.0, import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@^2.0.3, inherits@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -is-core-module@^2.2.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.0.tgz#0321336c3d0925e497fd97f5d95cb114a5ccd548" - integrity sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw== - dependencies: - has "^1.0.3" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" - integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE= - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-reference@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7" - integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ== - dependencies: - "@types/estree" "*" - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -isomorphic-ws@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" - integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== - -jayson@^3.4.4: - version "3.6.6" - resolved "https://registry.yarnpkg.com/jayson/-/jayson-3.6.6.tgz#189984f624e398f831bd2be8e8c80eb3abf764a1" - integrity sha512-f71uvrAWTtrwoww6MKcl9phQTC+56AopLyEenWvKVAIMz+q0oVGj6tenLZ7Z6UiPBkJtKLj4kt0tACllFQruGQ== - dependencies: - "@types/connect" "^3.4.33" - "@types/express-serve-static-core" "^4.17.9" - "@types/lodash" "^4.14.159" - "@types/node" "^12.12.54" - "@types/ws" "^7.4.4" - JSONStream "^1.3.5" - commander "^2.20.3" - delay "^5.0.0" - es6-promisify "^5.0.0" - eyes "^0.1.8" - isomorphic-ws "^4.0.1" - json-stringify-safe "^5.0.1" - lodash "^4.17.20" - uuid "^8.3.2" - ws "^7.4.5" - -joi@^17.4.0: - version "17.6.0" - resolved "https://registry.yarnpkg.com/joi/-/joi-17.6.0.tgz#0bb54f2f006c09a96e75ce687957bd04290054b2" - integrity sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw== - dependencies: - "@hapi/hoek" "^9.0.0" - "@hapi/topo" "^5.0.0" - "@sideway/address" "^4.1.3" - "@sideway/formula" "^3.0.0" - "@sideway/pinpoint" "^2.0.0" - -js-sha3@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" - integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== - -js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - -json-stringify-safe@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - -jsonc-parser@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.0.0.tgz#abdd785701c7e7eaca8a9ec8cf070ca51a745a22" - integrity sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA== - -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - -jsonparse@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" - integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= - -lazy-ass@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/lazy-ass/-/lazy-ass-1.6.0.tgz#7999655e8646c17f089fdd187d150d3324d54513" - integrity sha1-eZllXoZGwX8In90YfRUNMyTVRRM= - -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" - -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - -lodash@^4.17.14, lodash@^4.17.20, lodash@^4.17.21: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -lunr@^2.3.9: - version "2.3.9" - resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1" - integrity sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow== - -magic-string@^0.25.7: - version "0.25.7" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" - integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA== - dependencies: - sourcemap-codec "^1.4.4" - -make-dir@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - -make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -map-stream@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" - integrity sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ= - -marked@^4.0.12: - version "4.0.12" - resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.12.tgz#2262a4e6fd1afd2f13557726238b69a48b982f7d" - integrity sha512-hgibXWrEDNBWgGiK18j/4lkS6ihTe9sxtV4Q1OQppb/0zzyPSzoFANBa5MfsG/zgsWklmNnhm0XACZOH/0HBiQ== - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - -merge2@^1.3.0, merge2@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -micromatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== - dependencies: - braces "^3.0.1" - picomatch "^2.2.3" - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= - -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" - integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== - dependencies: - brace-expansion "^2.0.1" - -minimist@^1.2.5: - version "1.2.6" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" - integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -node-addon-api@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" - integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== - -node-fetch@2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" - integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== - -node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3" - integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q== - -npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - -object-assign@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== - dependencies: - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - word-wrap "^1.2.3" - -p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-key@^3.0.0, path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -pause-stream@0.0.11: - version "0.0.11" - resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" - integrity sha1-/lo0sMvOErWqaitAPuLnO2AvFEU= - dependencies: - through "~2.3" - -picomatch@^2.2.2, picomatch@^2.2.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" - integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== - -pify@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= - -pkg-dir@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== - dependencies: - find-up "^4.0.0" - -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== - dependencies: - fast-diff "^1.1.2" - -prettier@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.1.tgz#d472797e0d7461605c1609808e27b80c0f9cfe17" - integrity sha512-8UVbTBYGwN37Bs9LERmxCPjdvPxlEowx2urIL6urHzdb3SDq4B/Z6xLFCblrSnE4iKWcS6ziJ3aOYrc1kz/E2A== - -ps-tree@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.2.0.tgz#5e7425b89508736cdd4f2224d028f7bb3f722ebd" - integrity sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA== - dependencies: - event-stream "=3.3.4" - -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - -regenerator-runtime@^0.13.4: - version "0.13.9" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" - integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== - -regexpp@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve@^1.17.0, resolve@^1.19.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" - integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== - dependencies: - is-core-module "^2.2.0" - path-parse "^1.0.6" - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -rollup@^2.70.1: - version "2.70.1" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.70.1.tgz#824b1f1f879ea396db30b0fc3ae8d2fead93523e" - integrity sha512-CRYsI5EuzLbXdxC6RnYhOuRdtz4bhejPMSWjsFLfVM/7w/85n2szZv6yExqUXsBdz5KT8eoubeyDUDjhLHEslA== - optionalDependencies: - fsevents "~2.3.2" - -rpc-websockets@^7.4.2: - version "7.4.16" - resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.4.16.tgz#eb701cdef577d4357ba5f526d50e25f370396fac" - integrity sha512-0b7OVhutzwRIaYAtJo5tqtaQTWKfwAsKnaThOSOy+VkhVdleNUgb8eZnWSdWITRZZEigV5uPEIDr5KZe4DBrdQ== - dependencies: - "@babel/runtime" "^7.11.2" - circular-json "^0.5.9" - eventemitter3 "^4.0.7" - uuid "^8.3.0" - ws "^7.4.5" - optionalDependencies: - bufferutil "^4.0.1" - utf-8-validate "^5.0.2" - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -rxjs@^7.1.0: - version "7.5.5" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.5.tgz#2ebad89af0f560f460ad5cc4213219e1f7dd4e9f" - integrity sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw== - dependencies: - tslib "^2.1.0" - -safe-buffer@^5.0.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -secp256k1@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.2.tgz#15dd57d0f0b9fdb54ac1fa1694f40e5e9a54f4a1" - integrity sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg== - dependencies: - elliptic "^6.5.2" - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" - -semver@^6.0.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@^7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -shiki@^0.10.1: - version "0.10.1" - resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.10.1.tgz#6f9a16205a823b56c072d0f1a0bcd0f2646bef14" - integrity sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng== - dependencies: - jsonc-parser "^3.0.0" - vscode-oniguruma "^1.6.1" - vscode-textmate "5.2.0" - -signal-exit@^3.0.3: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -sourcemap-codec@^1.4.4: - version "1.4.8" - resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" - integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== - -split@0.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" - integrity sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8= - dependencies: - through "2" - -start-server-and-test@^1.14.0: - version "1.14.0" - resolved "https://registry.yarnpkg.com/start-server-and-test/-/start-server-and-test-1.14.0.tgz#c57f04f73eac15dd51733b551d775b40837fdde3" - integrity sha512-on5ELuxO2K0t8EmNj9MtVlFqwBMxfWOhu4U7uZD1xccVpFlOQKR93CSe0u98iQzfNxRyaNTb/CdadbNllplTsw== - dependencies: - bluebird "3.7.2" - check-more-types "2.24.0" - debug "4.3.2" - execa "5.1.1" - lazy-ass "1.6.0" - ps-tree "1.2.0" - wait-on "6.0.0" - -stream-combiner@~0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" - integrity sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ= - dependencies: - duplexer "~0.1.1" - -strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -strip-outer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631" - integrity sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg== - dependencies: - escape-string-regexp "^1.0.2" - -superstruct@^0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.14.2.tgz#0dbcdf3d83676588828f1cf5ed35cda02f59025b" - integrity sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ== - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -text-encoding-utf-8@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz#585b62197b0ae437e3c7b5d0af27ac1021e10d13" - integrity sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg== - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -through@2, "through@>=2.2.7 <3", through@~2.3, through@~2.3.1: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -trim-repeated@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21" - integrity sha1-42RqLqTokTEr9+rObPsFOAvAHCE= - dependencies: - escape-string-regexp "^1.0.2" - -ts-node@^10.7.0: - version "10.7.0" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.7.0.tgz#35d503d0fab3e2baa672a0e94f4b40653c2463f5" - integrity sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A== - dependencies: - "@cspotcode/source-map-support" "0.7.0" - "@tsconfig/node10" "^1.0.7" - "@tsconfig/node12" "^1.0.7" - "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.2" - acorn "^8.4.1" - acorn-walk "^8.1.1" - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - v8-compile-cache-lib "^3.0.0" - yn "3.1.1" - -tslib@^1.8.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tslib@^2.1.0, tslib@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" - integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== - -tsutils@^3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - -tweetnacl@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" - integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== - -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - -typedoc@^0.22.13: - version "0.22.13" - resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.22.13.tgz#d061f8f0fb7c9d686e48814f245bddeea4564e66" - integrity sha512-NHNI7Dr6JHa/I3+c62gdRNXBIyX7P33O9TafGLd07ur3MqzcKgwTvpg18EtvCLHJyfeSthAtCLpM7WkStUmDuQ== - dependencies: - glob "^7.2.0" - lunr "^2.3.9" - marked "^4.0.12" - minimatch "^5.0.1" - shiki "^0.10.1" - -typescript@^4.6.3: - version "4.6.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.3.tgz#eefeafa6afdd31d725584c67a0eaba80f6fc6c6c" - integrity sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw== - -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -utf-8-validate@^5.0.2: - version "5.0.7" - resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.7.tgz#c15a19a6af1f7ad9ec7ddc425747ca28c3644922" - integrity sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q== - dependencies: - node-gyp-build "^4.3.0" - -uuid@^8.3.0, uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - -v8-compile-cache-lib@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz#0582bcb1c74f3a2ee46487ceecf372e46bce53e8" - integrity sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA== - -v8-compile-cache@^2.0.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== - -vscode-oniguruma@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.6.1.tgz#2bf4dfcfe3dd2e56eb549a3068c8ee39e6c30ce5" - integrity sha512-vc4WhSIaVpgJ0jJIejjYxPvURJavX6QG41vu0mGhqywMkQqulezEqEQ3cO3gc8GvcOpX6ycmKGqRoROEMBNXTQ== - -vscode-textmate@5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.2.0.tgz#01f01760a391e8222fe4f33fbccbd1ad71aed74e" - integrity sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ== - -wait-on@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-6.0.0.tgz#7e9bf8e3d7fe2daecbb7a570ac8ca41e9311c7e7" - integrity sha512-tnUJr9p5r+bEYXPUdRseolmz5XqJTTj98JgOsfBn7Oz2dxfE2g3zw1jE+Mo8lopM3j3et/Mq1yW7kKX6qw7RVw== - dependencies: - axios "^0.21.1" - joi "^17.4.0" - lodash "^4.17.21" - minimist "^1.2.5" - rxjs "^7.1.0" - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -word-wrap@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -ws@^7.4.5: - version "7.5.6" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.6.tgz#e59fc509fb15ddfb65487ee9765c5a51dec5fe7b" - integrity sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yn@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== diff --git a/token-lending/program/Cargo.toml b/token-lending/program/Cargo.toml index a70fdc82234..07007776104 100644 --- a/token-lending/program/Cargo.toml +++ b/token-lending/program/Cargo.toml @@ -2,34 +2,33 @@ name = "spl-token-lending" version = "0.2.0" description = "Solana Program Library Token Lending" -authors = ["Solana Maintainers "] +authors = ["Solana Labs Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" license = "Apache-2.0" -edition = "2018" +edition = "2021" [features] no-entrypoint = [] -test-bpf = [] +test-sbf = [] [dependencies] -arrayref = "0.3.6" -bytemuck = "1.7.2" -num-derive = "0.3" +arrayref = "0.3.9" +bytemuck = "1.21.0" +num-derive = "0.4" num-traits = "0.2" -solana-program = "1.10.33" -spl-token = { version = "3.3", path = "../../token/program", features = [ "no-entrypoint" ] } -thiserror = "1.0" -uint = "0.9" +solana-program = "2.1.0" +spl-token = { version = "7.0", features = [ "no-entrypoint" ] } +thiserror = "2.0" +uint = "0.10" [dev-dependencies] assert_matches = "1.5.0" -base64 = "0.13" -log = "0.4.14" -proptest = "1.0" -solana-program-test = "1.10.33" -solana-sdk = "1.10.33" -serde = "1.0" -serde_yaml = "0.8" +proptest = "1.6" +solana-program-test = "2.1.0" +solana-sdk = "2.1.0" [lib] crate-type = ["cdylib", "lib"] + +[lints] +workspace = true diff --git a/token-lending/program/src/entrypoint.rs b/token-lending/program/src/entrypoint.rs index a1d68d8fa12..a0a78a9d4a0 100644 --- a/token-lending/program/src/entrypoint.rs +++ b/token-lending/program/src/entrypoint.rs @@ -2,13 +2,15 @@ #![cfg(all(target_os = "solana", not(feature = "no-entrypoint")))] -use crate::{error::LendingError, processor}; -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, - program_error::PrintProgramError, pubkey::Pubkey, +use { + crate::{error::LendingError, processor}, + solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, program_error::PrintProgramError, + pubkey::Pubkey, + }, }; -entrypoint!(process_instruction); +solana_program::entrypoint!(process_instruction); fn process_instruction( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/token-lending/program/src/error.rs b/token-lending/program/src/error.rs index 05aca35da32..21dc0acf34c 100644 --- a/token-lending/program/src/error.rs +++ b/token-lending/program/src/error.rs @@ -1,8 +1,10 @@ //! Error types -use num_derive::FromPrimitive; -use solana_program::{decode_error::DecodeError, program_error::ProgramError}; -use thiserror::Error; +use { + num_derive::FromPrimitive, + solana_program::{decode_error::DecodeError, program_error::ProgramError}, + thiserror::Error, +}; /// Errors that may be returned by the TokenLending program. #[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] @@ -17,7 +19,8 @@ pub enum LendingError { /// Lamport balance below rent-exempt threshold. #[error("Lamport balance below rent-exempt threshold")] NotRentExempt, - /// The program address provided doesn't match the value generated by the program. + /// The program address provided doesn't match the value generated by the + /// program. #[error("Market authority is invalid")] InvalidMarketAuthority, /// Expected a different market owner @@ -25,10 +28,12 @@ pub enum LendingError { InvalidMarketOwner, // 5 - /// The owner of the input isn't set to the program address generated by the program. + /// The owner of the input isn't set to the program address generated by the + /// program. #[error("Input account owner is not the program address")] InvalidAccountOwner, - /// The owner of the account input isn't set to the correct token program id. + /// The owner of the account input isn't set to the correct token program + /// id. #[error("Input token account is not owned by the correct token program id")] InvalidTokenOwner, /// Expected an SPL Token account @@ -160,6 +165,9 @@ pub enum LendingError { #[error("Not enough liquidity after flash loan")] NotEnoughLiquidityAfterFlashLoan, // 45 + /// Lending instruction exceeds desired slippage limit + #[error("Amount smaller than desired slippage limit")] + ExceededSlippage, } impl From for ProgramError { diff --git a/token-lending/program/src/instruction.rs b/token-lending/program/src/instruction.rs index 5ff50cf5c24..3ef6841230b 100644 --- a/token-lending/program/src/instruction.rs +++ b/token-lending/program/src/instruction.rs @@ -1,17 +1,19 @@ //! Instruction types -use crate::{ - error::LendingError, - state::{ReserveConfig, ReserveFees}, -}; -use solana_program::{ - instruction::{AccountMeta, Instruction}, - msg, - program_error::ProgramError, - pubkey::{Pubkey, PUBKEY_BYTES}, - sysvar, +use { + crate::{ + error::LendingError, + state::{ReserveConfig, ReserveFees}, + }, + solana_program::{ + instruction::{AccountMeta, Instruction}, + msg, + program_error::ProgramError, + pubkey::{Pubkey, PUBKEY_BYTES}, + sysvar, + }, + std::{convert::TryInto, mem::size_of}, }; -use std::{convert::TryInto, mem::size_of}; /// Instructions supported by the lending program. #[derive(Clone, Debug, PartialEq)] @@ -29,7 +31,9 @@ pub enum LendingInstruction { /// Owner authority which can add new reserves owner: Pubkey, /// Currency market prices are quoted in - /// e.g. "USD" null padded (`*b"USD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"`) or SPL token mint pubkey + /// e.g. "USD" null padded + /// (`*b"USD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + /// `) or SPL token mint pubkey quote_currency: [u8; 32], }, @@ -50,25 +54,26 @@ pub enum LendingInstruction { /// /// Accounts expected by this instruction: /// - /// 0. `[writable]` Source liquidity token account. - /// $authority can transfer $liquidity_amount. + /// 0. `[writable]` Source liquidity token account. $authority can + /// transfer $liquidity_amount. /// 1. `[writable]` Destination collateral token account - uninitialized. /// 2. `[writable]` Reserve account - uninitialized. /// 3. `[]` Reserve liquidity SPL Token mint. - /// 4. `[writable]` Reserve liquidity supply SPL Token account - uninitialized. + /// 4. `[writable]` Reserve liquidity supply SPL Token account - + /// uninitialized. /// 5. `[writable]` Reserve liquidity fee receiver - uninitialized. /// 6. `[writable]` Reserve collateral SPL Token mint - uninitialized. /// 7. `[writable]` Reserve collateral token supply - uninitialized. /// 8. `[]` Pyth product account. - /// 9. `[]` Pyth price account. - /// This will be used as the reserve liquidity oracle account. - /// 10 `[]` Lending market account. - /// 11 `[]` Derived lending market authority. - /// 12 `[signer]` Lending market owner. - /// 13 `[signer]` User transfer authority ($authority). - /// 14 `[]` Clock sysvar. - /// 15 `[]` Rent sysvar. - /// 16 `[]` Token program id. + /// 9. `[]` Pyth price account. This will be used as the reserve liquidity + /// oracle account. + /// 10. `[]` Lending market account. + /// 11. `[]` Derived lending market authority. + /// 12. `[signer]` Lending market owner. + /// 13. `[signer]` User transfer authority ($authority). + /// 14. `[]` Clock sysvar. + /// 15. `[]` Rent sysvar. + /// 16. `[]` Token program id. InitReserve { /// Initial amount of liquidity to deposit into the new reserve liquidity_amount: u64, @@ -82,19 +87,19 @@ pub enum LendingInstruction { /// Accounts expected by this instruction: /// /// 0. `[writable]` Reserve account. - /// 1. `[]` Reserve liquidity oracle account. - /// Must be the Pyth price account specified at InitReserve. + /// 1. `[]` Reserve liquidity oracle account. Must be the Pyth price + /// account specified at InitReserve. /// 2. `[]` Clock sysvar. RefreshReserve, // 4 - /// Deposit liquidity into a reserve in exchange for collateral. Collateral represents a share - /// of the reserve liquidity pool. + /// Deposit liquidity into a reserve in exchange for collateral. Collateral + /// represents a share of the reserve liquidity pool. /// /// Accounts expected by this instruction: /// - /// 0. `[writable]` Source liquidity token account. - /// $authority can transfer $liquidity_amount. + /// 0. `[writable]` Source liquidity token account. $authority can + /// transfer $liquidity_amount. /// 1. `[writable]` Destination collateral token account. /// 2. `[writable]` Reserve account. /// 3. `[writable]` Reserve liquidity supply SPL Token account. @@ -114,8 +119,8 @@ pub enum LendingInstruction { /// /// Accounts expected by this instruction: /// - /// 0. `[writable]` Source collateral token account. - /// $authority can transfer $collateral_amount. + /// 0. `[writable]` Source collateral token account. $authority can + /// transfer $collateral_amount. /// 1. `[writable]` Destination liquidity token account. /// 2. `[writable]` Reserve account. /// 3. `[writable]` Reserve collateral SPL Token mint. @@ -144,16 +149,19 @@ pub enum LendingInstruction { InitObligation, // 7 - /// Refresh an obligation's accrued interest and collateral and liquidity prices. Requires - /// refreshed reserves, as all obligation collateral deposit reserves in order, followed by all - /// liquidity borrow reserves in order. + /// Refresh an obligation's accrued interest and collateral and liquidity + /// prices. Requires refreshed reserves, as all obligation collateral + /// deposit reserves in order, followed by all liquidity borrow reserves + /// in order. /// /// Accounts expected by this instruction: /// /// 0. `[writable]` Obligation account. /// 1. `[]` Clock sysvar. - /// .. `[]` Collateral deposit reserve accounts - refreshed, all, in order. - /// .. `[]` Liquidity borrow reserve accounts - refreshed, all, in order. + /// 2. .. `[]` Collateral deposit reserve accounts - refreshed, all, in + /// order. + /// 3. .. `[]` Liquidity borrow reserve accounts - refreshed, all, in + /// order. RefreshObligation, // 8 @@ -161,10 +169,11 @@ pub enum LendingInstruction { /// /// Accounts expected by this instruction: /// - /// 0. `[writable]` Source collateral token account. - /// Minted by deposit reserve collateral mint. - /// $authority can transfer $collateral_amount. - /// 1. `[writable]` Destination deposit reserve collateral supply SPL Token account. + /// 0. `[writable]` Source collateral token account. Minted by deposit + /// reserve collateral mint. $authority can transfer + /// $collateral_amount. + /// 1. `[writable]` Destination deposit reserve collateral supply SPL + /// Token account. /// 2. `[]` Deposit reserve account - refreshed. /// 3. `[writable]` Obligation account. /// 4. `[]` Lending market account. @@ -178,13 +187,15 @@ pub enum LendingInstruction { }, // 9 - /// Withdraw collateral from an obligation. Requires a refreshed obligation and reserve. + /// Withdraw collateral from an obligation. Requires a refreshed obligation + /// and reserve. /// /// Accounts expected by this instruction: /// - /// 0. `[writable]` Source withdraw reserve collateral supply SPL Token account. - /// 1. `[writable]` Destination collateral token account. - /// Minted by withdraw reserve collateral mint. + /// 0. `[writable]` Source withdraw reserve collateral supply SPL Token + /// account. + /// 1. `[writable]` Destination collateral token account. Minted by + /// withdraw reserve collateral mint. /// 2. `[]` Withdraw reserve account - refreshed. /// 3. `[writable]` Obligation account - refreshed. /// 4. `[]` Lending market account. @@ -193,44 +204,49 @@ pub enum LendingInstruction { /// 7. `[]` Clock sysvar. /// 8. `[]` Token program id. WithdrawObligationCollateral { - /// Amount of collateral tokens to withdraw - u64::MAX for up to 100% of deposited amount + /// Amount of collateral tokens to withdraw - u64::MAX for up to 100% of + /// deposited amount collateral_amount: u64, }, // 10 - /// Borrow liquidity from a reserve by depositing collateral tokens. Requires a refreshed - /// obligation and reserve. + /// Borrow liquidity from a reserve by depositing collateral tokens. + /// Requires a refreshed obligation and reserve. /// /// Accounts expected by this instruction: /// - /// 0. `[writable]` Source borrow reserve liquidity supply SPL Token account. - /// 1. `[writable]` Destination liquidity token account. - /// Minted by borrow reserve liquidity mint. + /// 0. `[writable]` Source borrow reserve liquidity supply SPL Token + /// account. + /// 1. `[writable]` Destination liquidity token account. Minted by borrow + /// reserve liquidity mint. /// 2. `[writable]` Borrow reserve account - refreshed. - /// 3. `[writable]` Borrow reserve liquidity fee receiver account. - /// Must be the fee account specified at InitReserve. + /// 3. `[writable]` Borrow reserve liquidity fee receiver account. Must be + /// the fee account specified at InitReserve. /// 4. `[writable]` Obligation account - refreshed. /// 5. `[]` Lending market account. /// 6. `[]` Derived lending market authority. /// 7. `[signer]` Obligation owner. /// 8. `[]` Clock sysvar. /// 9. `[]` Token program id. - /// 10 `[optional, writable]` Host fee receiver account. + /// 10. `[optional, writable]` Host fee receiver account. BorrowObligationLiquidity { /// Amount of liquidity to borrow - u64::MAX for 100% of borrowing power liquidity_amount: u64, - // @TODO: slippage constraint - https://git.io/JmV67 + /// Minimum amount of liquidity to receive, if borrowing 100% of + /// borrowing power + slippage_limit: u64, }, // 11 - /// Repay borrowed liquidity to a reserve. Requires a refreshed obligation and reserve. + /// Repay borrowed liquidity to a reserve. Requires a refreshed obligation + /// and reserve. /// /// Accounts expected by this instruction: /// - /// 0. `[writable]` Source liquidity token account. - /// Minted by repay reserve liquidity mint. - /// $authority can transfer $liquidity_amount. - /// 1. `[writable]` Destination repay reserve liquidity supply SPL Token account. + /// 0. `[writable]` Source liquidity token account. Minted by repay + /// reserve liquidity mint. $authority can transfer $liquidity_amount. + /// 1. `[writable]` Destination repay reserve liquidity supply SPL Token + /// account. /// 2. `[writable]` Repay reserve account - refreshed. /// 3. `[writable]` Obligation account - refreshed. /// 4. `[]` Lending market account. @@ -243,16 +259,16 @@ pub enum LendingInstruction { }, // 12 - /// Repay borrowed liquidity to a reserve to receive collateral at a discount from an unhealthy - /// obligation. Requires a refreshed obligation and reserves. + /// Repay borrowed liquidity to a reserve to receive collateral at a + /// discount from an unhealthy obligation. Requires a refreshed + /// obligation and reserves. /// /// Accounts expected by this instruction: /// - /// 0. `[writable]` Source liquidity token account. - /// Minted by repay reserve liquidity mint. - /// $authority can transfer $liquidity_amount. - /// 1. `[writable]` Destination collateral token account. - /// Minted by withdraw reserve collateral mint. + /// 0. `[writable]` Source liquidity token account. Minted by repay + /// reserve liquidity mint. $authority can transfer $liquidity_amount. + /// 1. `[writable]` Destination collateral token account. Minted by + /// withdraw reserve collateral mint. /// 2. `[writable]` Repay reserve account - refreshed. /// 3. `[writable]` Repay reserve liquidity supply SPL Token account. /// 4. `[]` Withdraw reserve account - refreshed. @@ -261,10 +277,11 @@ pub enum LendingInstruction { /// 7. `[]` Lending market account. /// 8. `[]` Derived lending market authority. /// 9. `[signer]` User transfer authority ($authority). - /// 10 `[]` Clock sysvar. - /// 11 `[]` Token program id. + /// 10. `[]` Clock sysvar. + /// 11. `[]` Token program id. LiquidateObligation { - /// Amount of liquidity to repay - u64::MAX for up to 100% of borrowed amount + /// Amount of liquidity to repay - u64::MAX for up to 100% of borrowed + /// amount liquidity_amount: u64, }, @@ -273,44 +290,48 @@ pub enum LendingInstruction { /// /// Accounts expected by this instruction: /// - /// 0. `[writable]` Source liquidity token account. - /// Minted by reserve liquidity mint. - /// Must match the reserve liquidity supply. - /// 1. `[writable]` Destination liquidity token account. - /// Minted by reserve liquidity mint. + /// 0. `[writable]` Source liquidity token account. Minted by reserve + /// liquidity mint. Must match the reserve liquidity supply. + /// 1. `[writable]` Destination liquidity token account. Minted by reserve + /// liquidity mint. /// 2. `[writable]` Reserve account. - /// 3. `[writable]` Flash loan fee receiver account. - /// Must match the reserve liquidity fee receiver. + /// 3. `[writable]` Flash loan fee receiver account. Must match the + /// reserve liquidity fee receiver. /// 4. `[writable]` Host fee receiver. /// 5. `[]` Lending market account. /// 6. `[]` Derived lending market authority. /// 7. `[]` Token program id. - /// 8. `[]` Flash loan receiver program id. - /// Must implement an instruction that has tag of 0 and a signature of `(amount: u64)` - /// This instruction must return the amount to the source liquidity account. - /// .. `[any]` Additional accounts expected by the receiving program's `ReceiveFlashLoan` instruction. + /// 8. `[]` Flash loan receiver program id. Must implement an instruction + /// that has tag of 0 and a signature of `(amount: u64)` This + /// instruction must return the amount to the source liquidity account. + /// 9. .. `[any]` Additional accounts expected by the receiving program's + /// `ReceiveFlashLoan` instruction. /// - /// The flash loan receiver program that is to be invoked should contain an instruction with - /// tag `0` and accept the total amount (including fee) that needs to be returned back after - /// its execution has completed. + /// The flash loan receiver program that is to be invoked should contain + /// an instruction with tag `0` and accept the total amount (including + /// fee) that needs to be returned back after its execution has + /// completed. /// - /// Flash loan receiver should have an instruction with the following signature: + /// Flash loan receiver should have an instruction with the following + /// signature: /// - /// 0. `[writable]` Source liquidity (matching the destination from above). - /// 1. `[writable]` Destination liquidity (matching the source from above). + /// 0. `[writable]` Source liquidity (matching the destination from + /// above). + /// 1. `[writable]` Destination liquidity (matching the source from + /// above). /// 2. `[]` Token program id - /// .. `[any]` Additional accounts provided to the lending program's `FlashLoan` instruction above. - /// ReceiveFlashLoan { - /// // Amount that must be repaid by the receiver program - /// amount: u64 - /// } + /// 3. .. `[any]` Additional accounts provided to the lending program's + /// `FlashLoan` instruction above. ReceiveFlashLoan { // Amount that + /// must be repaid by the receiver program amount: u64 } FlashLoan { - /// The amount that is to be borrowed - u64::MAX for up to 100% of available liquidity + /// The amount that is to be borrowed - u64::MAX for up to 100% of + /// available liquidity amount: u64, }, // 14 - /// Modify the ReserveConfig parameters of an already initialized Reserve account + /// Modify the ReserveConfig parameters of an already initialized Reserve + /// account /// /// Accounts expected by this instruction: /// @@ -324,7 +345,8 @@ pub enum LendingInstruction { } impl LendingInstruction { - /// Unpacks a byte buffer into a [LendingInstruction](enum.LendingInstruction.html). + /// Unpacks a byte buffer into a + /// [LendingInstruction](enum.LendingInstruction.html). pub fn unpack(input: &[u8]) -> Result { let (&tag, rest) = input .split_first() @@ -370,8 +392,12 @@ impl LendingInstruction { Self::WithdrawObligationCollateral { collateral_amount } } 10 => { - let (liquidity_amount, _rest) = Self::unpack_u64(rest)?; - Self::BorrowObligationLiquidity { liquidity_amount } + let (liquidity_amount, rest) = Self::unpack_u64(rest)?; + let (slippage_limit, _rest) = Self::unpack_u64(rest).unwrap_or((0, &[])); + Self::BorrowObligationLiquidity { + liquidity_amount, + slippage_limit, + } } 11 => { let (liquidity_amount, _rest) = Self::unpack_u64(rest)?; @@ -444,7 +470,7 @@ impl LendingInstruction { return Err(LendingError::InstructionUnpackError.into()); } let (key, rest) = input.split_at(PUBKEY_BYTES); - let pk = Pubkey::new(key); + let pk = Pubkey::try_from(key).map_err(|_| LendingError::InstructionUnpackError)?; Ok((pk, rest)) } @@ -476,7 +502,8 @@ impl LendingInstruction { }) } - /// Packs a [LendingInstruction](enum.LendingInstruction.html) into a byte buffer. + /// Packs a [LendingInstruction](enum.LendingInstruction.html) into a byte + /// buffer. pub fn pack(&self) -> Vec { let mut buf = Vec::with_capacity(size_of::()); match *self { @@ -525,9 +552,13 @@ impl LendingInstruction { buf.push(9); buf.extend_from_slice(&collateral_amount.to_le_bytes()); } - Self::BorrowObligationLiquidity { liquidity_amount } => { + Self::BorrowObligationLiquidity { + liquidity_amount, + slippage_limit, + } => { buf.push(10); buf.extend_from_slice(&liquidity_amount.to_le_bytes()); + buf.extend_from_slice(&slippage_limit.to_le_bytes()); } Self::RepayObligationLiquidity { liquidity_amount } => { buf.push(11); @@ -860,6 +891,7 @@ pub fn withdraw_obligation_collateral( pub fn borrow_obligation_liquidity( program_id: Pubkey, liquidity_amount: u64, + slippage_limit: Option, source_liquidity_pubkey: Pubkey, destination_liquidity_pubkey: Pubkey, borrow_reserve_pubkey: Pubkey, @@ -888,10 +920,15 @@ pub fn borrow_obligation_liquidity( if let Some(host_fee_receiver_pubkey) = host_fee_receiver_pubkey { accounts.push(AccountMeta::new(host_fee_receiver_pubkey, false)); } + let slippage_limit = slippage_limit.unwrap_or(0); Instruction { program_id, accounts, - data: LendingInstruction::BorrowObligationLiquidity { liquidity_amount }.pack(), + data: LendingInstruction::BorrowObligationLiquidity { + liquidity_amount, + slippage_limit, + } + .pack(), } } @@ -1309,6 +1346,7 @@ mod tests { let instruction = borrow_obligation_liquidity( program_id, liquidity_amount, + None, source_liquidity_pubkey, destination_liquidity_pubkey, borrow_reserve_pubkey, @@ -1322,7 +1360,11 @@ mod tests { assert_eq!(instruction.accounts.len(), 11); assert_eq!( instruction.data, - LendingInstruction::BorrowObligationLiquidity { liquidity_amount }.pack() + LendingInstruction::BorrowObligationLiquidity { + liquidity_amount, + slippage_limit: 0 + } + .pack() ); } diff --git a/token-lending/program/src/lib.rs b/token-lending/program/src/lib.rs index 0800719c2e5..49cb6c6635b 100644 --- a/token-lending/program/src/lib.rs +++ b/token-lending/program/src/lib.rs @@ -1,3 +1,4 @@ +#![allow(clippy::arithmetic_side_effects)] #![deny(missing_docs)] //! A lending program for the Solana blockchain. @@ -10,7 +11,8 @@ pub mod processor; pub mod pyth; pub mod state; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version pub use solana_program; solana_program::declare_id!("6TvznH3B2e3p2mbhufNBpgSrLx6UkgvxtVQvopEZ2kuH"); diff --git a/token-lending/program/src/math/decimal.rs b/token-lending/program/src/math/decimal.rs index 8cc3fc8baa9..957778ab163 100644 --- a/token-lending/program/src/math/decimal.rs +++ b/token-lending/program/src/math/decimal.rs @@ -11,14 +11,17 @@ #![allow(clippy::assign_op_pattern)] #![allow(clippy::ptr_offset_with_cast)] #![allow(clippy::manual_range_contains)] - -use crate::{ - error::LendingError, - math::{common::*, Rate}, +#![allow(missing_docs)] + +use { + crate::{ + error::LendingError, + math::{common::*, Rate}, + }, + solana_program::program_error::ProgramError, + std::{convert::TryFrom, fmt}, + uint::construct_uint, }; -use solana_program::program_error::ProgramError; -use std::{convert::TryFrom, fmt}; -use uint::construct_uint; // U192 with 192 bits consisting of 3 x 64-bit words construct_uint! { diff --git a/token-lending/program/src/math/mod.rs b/token-lending/program/src/math/mod.rs index 42744272f03..836a2f39c1a 100644 --- a/token-lending/program/src/math/mod.rs +++ b/token-lending/program/src/math/mod.rs @@ -4,6 +4,4 @@ mod common; mod decimal; mod rate; -pub use common::*; -pub use decimal::*; -pub use rate::*; +pub use {common::*, decimal::*, rate::*}; diff --git a/token-lending/program/src/math/rate.rs b/token-lending/program/src/math/rate.rs index c404c8ff2b8..12d3090486f 100644 --- a/token-lending/program/src/math/rate.rs +++ b/token-lending/program/src/math/rate.rs @@ -17,14 +17,17 @@ #![allow(clippy::ptr_offset_with_cast)] #![allow(clippy::reversed_empty_ranges)] #![allow(clippy::manual_range_contains)] - -use crate::{ - error::LendingError, - math::{common::*, decimal::Decimal}, +#![allow(missing_docs)] + +use { + crate::{ + error::LendingError, + math::{common::*, decimal::Decimal}, + }, + solana_program::program_error::ProgramError, + std::{convert::TryFrom, fmt}, + uint::construct_uint, }; -use solana_program::program_error::ProgramError; -use std::{convert::TryFrom, fmt}; -use uint::construct_uint; // U128 with 128 bits consisting of 2 x 64-bit words construct_uint! { diff --git a/token-lending/program/src/processor.rs b/token-lending/program/src/processor.rs index d42585697f0..acae01c8375 100644 --- a/token-lending/program/src/processor.rs +++ b/token-lending/program/src/processor.rs @@ -1,33 +1,37 @@ //! Program state processor -use crate::{ - error::LendingError, - instruction::LendingInstruction, - math::{Decimal, Rate, TryAdd, TryDiv, TryMul}, - pyth, - state::{ - CalculateBorrowResult, CalculateLiquidationResult, CalculateRepayResult, - InitLendingMarketParams, InitObligationParams, InitReserveParams, LendingMarket, - NewReserveCollateralParams, NewReserveLiquidityParams, Obligation, Reserve, - ReserveCollateral, ReserveConfig, ReserveLiquidity, +use { + crate::{ + error::LendingError, + instruction::LendingInstruction, + math::{Decimal, Rate, TryAdd, TryDiv, TryMul}, + pyth, + state::{ + CalculateBorrowResult, CalculateLiquidationResult, CalculateRepayResult, + InitLendingMarketParams, InitObligationParams, InitReserveParams, LendingMarket, + NewReserveCollateralParams, NewReserveLiquidityParams, Obligation, Reserve, + ReserveCollateral, ReserveConfig, ReserveLiquidity, + }, }, + num_traits::FromPrimitive, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + decode_error::DecodeError, + entrypoint::ProgramResult, + instruction::Instruction, + msg, + program::{invoke, invoke_signed}, + program_error::{PrintProgramError, ProgramError}, + program_pack::{IsInitialized, Pack}, + pubkey::Pubkey, + sysvar::{clock::Clock, rent::Rent, Sysvar}, + }, + spl_token::{ + solana_program::instruction::AccountMeta, + state::{Account, Mint}, + }, + std::convert::TryInto, }; -use num_traits::FromPrimitive; -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - decode_error::DecodeError, - entrypoint::ProgramResult, - instruction::Instruction, - msg, - program::{invoke, invoke_signed}, - program_error::{PrintProgramError, ProgramError}, - program_pack::{IsInitialized, Pack}, - pubkey::Pubkey, - sysvar::{clock::Clock, rent::Rent, Sysvar}, -}; -use spl_token::solana_program::instruction::AccountMeta; -use spl_token::state::{Account, Mint}; -use std::convert::TryInto; /// Processes an instruction pub fn process_instruction( @@ -83,9 +87,17 @@ pub fn process_instruction( msg!("Instruction: Withdraw Obligation Collateral"); process_withdraw_obligation_collateral(program_id, collateral_amount, accounts) } - LendingInstruction::BorrowObligationLiquidity { liquidity_amount } => { + LendingInstruction::BorrowObligationLiquidity { + liquidity_amount, + slippage_limit, + } => { msg!("Instruction: Borrow Obligation Liquidity"); - process_borrow_obligation_liquidity(program_id, liquidity_amount, accounts) + process_borrow_obligation_liquidity( + program_id, + liquidity_amount, + slippage_limit, + accounts, + ) } LendingInstruction::RepayObligationLiquidity { liquidity_amount } => { msg!("Instruction: Repay Obligation Liquidity"); @@ -1023,6 +1035,7 @@ fn process_withdraw_obligation_collateral( fn process_borrow_obligation_liquidity( program_id: &Pubkey, liquidity_amount: u64, + slippage_limit: u64, accounts: &[AccountInfo], ) -> ProgramResult { if liquidity_amount == 0 { @@ -1141,6 +1154,11 @@ fn process_borrow_obligation_liquidity( return Err(LendingError::BorrowTooSmall.into()); } + if liquidity_amount == u64::MAX && receive_amount < slippage_limit { + msg!("Received liquidity would be smaller than the desired slippage limit"); + return Err(LendingError::ExceededSlippage.into()); + } + borrow_reserve.liquidity.borrow(borrow_amount)?; borrow_reserve.last_update.mark_stale(); Reserve::pack(borrow_reserve, &mut borrow_reserve_info.data.borrow_mut())?; @@ -1554,7 +1572,8 @@ fn process_flash_loan( return Err(LendingError::InvalidAccountInput.into()); } - // @FIXME: if u64::MAX is flash loaned, fees should be inclusive as with ordinary borrows + // @FIXME: if u64::MAX is flash loaned, fees should be inclusive as with + // ordinary borrows let flash_loan_amount = if liquidity_amount == u64::MAX { reserve.liquidity.available_amount } else { @@ -1699,8 +1718,9 @@ fn process_modify_reserve_config( let mut reserve = Reserve::unpack(&reserve_info.data.borrow_mut())?; // Validate that the reserve account corresponds to the correct lending market, - // after validating above that the lending market and lending market owner correspond, - // to prevent one compromised lending market owner from changing configs on other lending markets + // after validating above that the lending market and lending market owner + // correspond, to prevent one compromised lending market owner from changing + // configs on other lending markets if reserve.lending_market != *lending_market_info.key { msg!("Reserve account does not match the lending market"); return Err(LendingError::InvalidAccountInput.into()); diff --git a/token-lending/program/src/pyth.rs b/token-lending/program/src/pyth.rs index 10ec0408a62..67e88188cb9 100644 --- a/token-lending/program/src/pyth.rs +++ b/token-lending/program/src/pyth.rs @@ -1,5 +1,5 @@ #![allow(missing_docs)] -/// Derived from https://github.com/project-serum/anchor/blob/9224e0fa99093943a6190e396bccbc3387e5b230/examples/pyth/programs/pyth/src/pc.rs +/// Derived from https://github.com/coral-xyz/anchor/blob/9224e0fa99093943a6190e396bccbc3387e5b230/examples/pyth/programs/pyth/src/pc.rs use bytemuck::{ cast_slice, cast_slice_mut, from_bytes, from_bytes_mut, try_cast_slice, try_cast_slice_mut, Pod, PodCastError, Zeroable, @@ -21,7 +21,7 @@ pub struct AccKey { } #[derive(PartialEq, Copy, Clone)] -#[repr(C)] +#[repr(u32)] pub enum AccountType { Unknown, Mapping, @@ -30,7 +30,7 @@ pub enum AccountType { } #[derive(PartialEq, Copy, Clone)] -#[repr(C)] +#[repr(u32)] pub enum PriceStatus { Unknown, Trading, @@ -39,7 +39,7 @@ pub enum PriceStatus { } #[derive(PartialEq, Copy, Clone)] -#[repr(C)] +#[repr(u32)] pub enum CorpAction { NoCorpAct, } @@ -63,7 +63,7 @@ pub struct PriceComp { } #[derive(PartialEq, Copy, Clone)] -#[repr(C)] +#[repr(u32)] pub enum PriceType { Unknown, Price, diff --git a/token-lending/program/src/state/last_update.rs b/token-lending/program/src/state/last_update.rs index 68f95de7799..11fd10c0ae0 100644 --- a/token-lending/program/src/state/last_update.rs +++ b/token-lending/program/src/state/last_update.rs @@ -1,6 +1,8 @@ -use crate::error::LendingError; -use solana_program::{clock::Slot, program_error::ProgramError}; -use std::cmp::Ordering; +use { + crate::error::LendingError, + solana_program::{clock::Slot, program_error::ProgramError}, + std::cmp::Ordering, +}; /// Number of slots to consider stale after pub const STALE_AFTER_SLOTS_ELAPSED: u64 = 1; diff --git a/token-lending/program/src/state/lending_market.rs b/token-lending/program/src/state/lending_market.rs index 82b47e1d22d..326f5297296 100644 --- a/token-lending/program/src/state/lending_market.rs +++ b/token-lending/program/src/state/lending_market.rs @@ -1,10 +1,12 @@ -use super::*; -use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}; -use solana_program::{ - msg, - program_error::ProgramError, - program_pack::{IsInitialized, Pack, Sealed}, - pubkey::{Pubkey, PUBKEY_BYTES}, +use { + super::*, + arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}, + solana_program::{ + msg, + program_error::ProgramError, + program_pack::{IsInitialized, Pack, Sealed}, + pubkey::{Pubkey, PUBKEY_BYTES}, + }, }; /// Lending market state @@ -17,7 +19,9 @@ pub struct LendingMarket { /// Owner authority which can add new reserves pub owner: Pubkey, /// Currency market prices are quoted in - /// e.g. "USD" null padded (`*b"USD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"`) or a SPL token mint pubkey + /// e.g. "USD" null padded + /// (`*b"USD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"`) or + /// a SPL token mint pubkey pub quote_currency: [u8; 32], /// Token program id pub token_program_id: Pubkey, @@ -51,7 +55,9 @@ pub struct InitLendingMarketParams { /// Owner authority which can add new reserves pub owner: Pubkey, /// Currency market prices are quoted in - /// e.g. "USD" null padded (`*b"USD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"`) or a SPL token mint pubkey + /// e.g. "USD" null padded + /// (`*b"USD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"`) or + /// a SPL token mint pubkey pub quote_currency: [u8; 32], /// Token program id pub token_program_id: Pubkey, @@ -100,7 +106,8 @@ impl Pack for LendingMarket { oracle_program_id.copy_from_slice(self.oracle_program_id.as_ref()); } - /// Unpacks a byte buffer into a [LendingMarketInfo](struct.LendingMarketInfo.html) + /// Unpacks a byte buffer into a + /// [LendingMarketInfo](struct.LendingMarketInfo.html) fn unpack_from_slice(input: &[u8]) -> Result { let input = array_ref![input, 0, LENDING_MARKET_LEN]; #[allow(clippy::ptr_offset_with_cast)] diff --git a/token-lending/program/src/state/mod.rs b/token-lending/program/src/state/mod.rs index 55496a253e7..cd62910a17a 100644 --- a/token-lending/program/src/state/mod.rs +++ b/token-lending/program/src/state/mod.rs @@ -5,19 +5,18 @@ mod lending_market; mod obligation; mod reserve; -pub use last_update::*; -pub use lending_market::*; -pub use obligation::*; -pub use reserve::*; - -use crate::math::{Decimal, WAD}; -use solana_program::{ - clock::{DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT, SECONDS_PER_DAY}, - msg, - program_error::ProgramError, +use { + crate::math::{Decimal, WAD}, + solana_program::{ + clock::{DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT, SECONDS_PER_DAY}, + msg, + program_error::ProgramError, + }, }; +pub use {last_update::*, lending_market::*, obligation::*, reserve::*}; -/// Collateral tokens are initially valued at a ratio of 5:1 (collateral:liquidity) +/// Collateral tokens are initially valued at a ratio of 5:1 +/// (collateral:liquidity) // @FIXME: restore to 5 pub const INITIAL_COLLATERAL_RATIO: u64 = 1; const INITIAL_COLLATERAL_RATE: u64 = INITIAL_COLLATERAL_RATIO * WAD; diff --git a/token-lending/program/src/state/obligation.rs b/token-lending/program/src/state/obligation.rs index 817551881f6..a22a1ddd17d 100644 --- a/token-lending/program/src/state/obligation.rs +++ b/token-lending/program/src/state/obligation.rs @@ -1,23 +1,26 @@ -use super::*; -use crate::{ - error::LendingError, - math::{Decimal, Rate, TryAdd, TryDiv, TryMul, TrySub}, -}; -use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}; -use solana_program::{ - clock::Slot, - entrypoint::ProgramResult, - msg, - program_error::ProgramError, - program_pack::{IsInitialized, Pack, Sealed}, - pubkey::{Pubkey, PUBKEY_BYTES}, -}; -use std::{ - cmp::Ordering, - convert::{TryFrom, TryInto}, +use { + super::*, + crate::{ + error::LendingError, + math::{Decimal, Rate, TryAdd, TryDiv, TryMul, TrySub}, + }, + arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}, + solana_program::{ + clock::Slot, + entrypoint::ProgramResult, + msg, + program_error::ProgramError, + program_pack::{IsInitialized, Pack, Sealed}, + pubkey::{Pubkey, PUBKEY_BYTES}, + }, + std::{ + cmp::Ordering, + convert::{TryFrom, TryInto}, + }, }; -/// Max number of collateral and liquidity reserve accounts combined for an obligation +/// Max number of collateral and liquidity reserve accounts combined for an +/// obligation pub const MAX_OBLIGATION_RESERVES: usize = 10; /// Lending market obligation state @@ -31,7 +34,8 @@ pub struct Obligation { pub lending_market: Pubkey, /// Owner authority which can borrow liquidity pub owner: Pubkey, - /// Deposited collateral for the obligation, unique by deposit reserve address + /// Deposited collateral for the obligation, unique by deposit reserve + /// address pub deposits: Vec, /// Borrowed liquidity for the obligation, unique by borrow reserve address pub borrows: Vec, @@ -215,7 +219,8 @@ pub struct InitObligationParams { pub lending_market: Pubkey, /// Owner authority which can borrow liquidity pub owner: Pubkey, - /// Deposited collateral for the obligation, unique by deposit reserve address + /// Deposited collateral for the obligation, unique by deposit reserve + /// address pub deposits: Vec, /// Borrowed liquidity for the obligation, unique by borrow reserve address pub borrows: Vec, @@ -411,7 +416,8 @@ impl Pack for Obligation { } } - /// Unpacks a byte buffer into an [ObligationInfo](struct.ObligationInfo.html). + /// Unpacks a byte buffer into an + /// [ObligationInfo](struct.ObligationInfo.html). fn unpack_from_slice(src: &[u8]) -> Result { let input = array_ref![src, 0, OBLIGATION_LEN]; #[allow(clippy::ptr_offset_with_cast)] @@ -462,7 +468,7 @@ impl Pack for Obligation { let (deposit_reserve, deposited_amount, market_value) = array_refs![deposits_flat, PUBKEY_BYTES, 8, 16]; deposits.push(ObligationCollateral { - deposit_reserve: Pubkey::new(deposit_reserve), + deposit_reserve: Pubkey::new_from_array(*deposit_reserve), deposited_amount: u64::from_le_bytes(*deposited_amount), market_value: unpack_decimal(market_value), }); @@ -474,7 +480,7 @@ impl Pack for Obligation { let (borrow_reserve, cumulative_borrow_rate_wads, borrowed_amount_wads, market_value) = array_refs![borrows_flat, PUBKEY_BYTES, 16, 16, 16]; borrows.push(ObligationLiquidity { - borrow_reserve: Pubkey::new(borrow_reserve), + borrow_reserve: Pubkey::new_from_array(*borrow_reserve), cumulative_borrow_rate_wads: unpack_decimal(cumulative_borrow_rate_wads), borrowed_amount_wads: unpack_decimal(borrowed_amount_wads), market_value: unpack_decimal(market_value), @@ -502,9 +508,7 @@ impl Pack for Obligation { #[cfg(test)] mod test { - use super::*; - use crate::math::TryAdd; - use proptest::prelude::*; + use {super::*, crate::math::TryAdd, proptest::prelude::*}; const MAX_COMPOUNDED_INTEREST: u64 = 100; // 10,000% diff --git a/token-lending/program/src/state/reserve.rs b/token-lending/program/src/state/reserve.rs index 332d5a92121..26b14b8f91c 100644 --- a/token-lending/program/src/state/reserve.rs +++ b/token-lending/program/src/state/reserve.rs @@ -1,20 +1,22 @@ -use super::*; -use crate::{ - error::LendingError, - math::{Decimal, Rate, TryAdd, TryDiv, TryMul, TrySub}, -}; -use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}; -use solana_program::{ - clock::Slot, - entrypoint::ProgramResult, - msg, - program_error::ProgramError, - program_pack::{IsInitialized, Pack, Sealed}, - pubkey::{Pubkey, PUBKEY_BYTES}, -}; -use std::{ - cmp::Ordering, - convert::{TryFrom, TryInto}, +use { + super::*, + crate::{ + error::LendingError, + math::{Decimal, Rate, TryAdd, TryDiv, TryMul, TrySub}, + }, + arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}, + solana_program::{ + clock::Slot, + entrypoint::ProgramResult, + msg, + program_error::ProgramError, + program_pack::{IsInitialized, Pack, Sealed}, + pubkey::{Pubkey, PUBKEY_BYTES}, + }, + std::{ + cmp::Ordering, + convert::{TryFrom, TryInto}, + }, }; /// Percentage of an obligation that can be repaid during each liquidation call @@ -58,7 +60,8 @@ impl Reserve { self.config = params.config; } - /// Record deposited liquidity and return amount of collateral tokens to mint + /// Record deposited liquidity and return amount of collateral tokens to + /// mint pub fn deposit_liquidity(&mut self, liquidity_amount: u64) -> Result { let collateral_amount = self .collateral_exchange_rate()? @@ -255,7 +258,8 @@ impl Reserve { } } } else { - // calculate settle_amount and withdraw_amount, repay_amount is settle_amount rounded + // calculate settle_amount and withdraw_amount, repay_amount is settle_amount + // rounded let liquidation_amount = obligation .max_liquidation_amount(liquidity)? .min(max_amount); @@ -427,7 +431,8 @@ impl ReserveLiquidity { Ok(()) } - /// Add repay amount to available liquidity and subtract settle amount from total borrows + /// Add repay amount to available liquidity and subtract settle amount from + /// total borrows pub fn repay(&mut self, repay_amount: u64, settle_amount: Decimal) -> ProgramResult { self.available_amount = self .available_amount @@ -594,9 +599,11 @@ pub struct ReserveConfig { /// Target ratio of the value of borrows to deposits, as a percentage /// 0 if use as collateral is disabled pub loan_to_value_ratio: u8, - /// Bonus a liquidator gets when repaying part of an unhealthy obligation, as a percentage + /// Bonus a liquidator gets when repaying part of an unhealthy obligation, + /// as a percentage pub liquidation_bonus: u8, - /// Loan to value ratio at which an obligation can be liquidated, as a percentage + /// Loan to value ratio at which an obligation can be liquidated, as a + /// percentage pub liquidation_threshold: u8, /// Min borrow APY pub min_borrow_rate: u8, @@ -609,7 +616,8 @@ pub struct ReserveConfig { } impl ReserveConfig { - /// Validate the reserve configs, when initializing or modifying the reserve configs + /// Validate the reserve configs, when initializing or modifying the reserve + /// configs pub fn validate(&self) -> ProgramResult { if self.optimal_utilization_rate > 100 { msg!("Optimal utilization rate must be in range [0, 100]"); @@ -656,9 +664,9 @@ impl ReserveConfig { /// Additional fee information on a reserve /// -/// These exist separately from interest accrual fees, and are specifically for the program owner -/// and frontend host. The fees are paid out as a percentage of liquidity token amounts during -/// repayments and liquidations. +/// These exist separately from interest accrual fees, and are specifically for +/// the program owner and frontend host. The fees are paid out as a percentage +/// of liquidity token amounts during repayments and liquidations. #[derive(Clone, Copy, Debug, Default, PartialEq)] pub struct ReserveFees { /// Fee assessed on `BorrowObligationLiquidity`, expressed as a Wad. @@ -747,7 +755,7 @@ impl ReserveFees { } } -/// Calculate fees exlusive or inclusive of an amount +/// Calculate fees exclusive or inclusive of an amount pub enum FeeCalculation { /// Fee added to amount: fee = rate * amount Exclusive, @@ -762,7 +770,8 @@ impl IsInitialized for Reserve { } } -const RESERVE_LEN: usize = 571; // 1 + 8 + 1 + 32 + 32 + 1 + 32 + 32 + 32 + 8 + 16 + 16 + 16 + 32 + 8 + 32 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 8 + 8 + 1 + 248 +const RESERVE_LEN: usize = 571; // 1 + 8 + 1 + 32 + 32 + 1 + 32 + 32 + 32 + 8 + 16 + 16 + 16 + 32 + 8 + 32 + 1 + + // 1 + 1 + 1 + 1 + 1 + 1 + 8 + 8 + 1 + 248 impl Pack for Reserve { const LEN: usize = RESERVE_LEN; @@ -982,10 +991,12 @@ impl Pack for Reserve { #[cfg(test)] mod test { - use super::*; - use crate::math::{PERCENT_SCALER, WAD}; - use proptest::prelude::*; - use std::cmp::Ordering; + use { + super::*, + crate::math::{PERCENT_SCALER, WAD}, + proptest::prelude::*, + std::cmp::Ordering, + }; const MAX_LIQUIDITY: u64 = u64::MAX / 5; @@ -1000,7 +1011,8 @@ mod test { } } - // Creates rates (threshold, ltv) where 2 <= threshold <= 100 and threshold <= ltv <= 1,000% + // Creates rates (threshold, ltv) where 2 <= threshold <= 100 and threshold <= + // ltv <= 1,000% prop_compose! { fn unhealthy_rates()(threshold in 2..=100u8)( ltv_rate in threshold as u64..=1000u64, diff --git a/token-lending/program/tests/borrow_obligation_liquidity.rs b/token-lending/program/tests/borrow_obligation_liquidity.rs index 1ae0de23fd6..8152350749e 100644 --- a/token-lending/program/tests/borrow_obligation_liquidity.rs +++ b/token-lending/program/tests/borrow_obligation_liquidity.rs @@ -1,22 +1,24 @@ -#![cfg(feature = "test-bpf")] +#![allow(clippy::arithmetic_side_effects)] +#![cfg(feature = "test-sbf")] mod helpers; -use helpers::*; -use solana_program_test::*; -use solana_sdk::{ - instruction::InstructionError, - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, +use { + helpers::*, + solana_program_test::*, + solana_sdk::{ + instruction::InstructionError, + signature::{Keypair, Signer}, + transaction::{Transaction, TransactionError}, + }, + spl_token_lending::{ + error::LendingError, + instruction::{borrow_obligation_liquidity, refresh_obligation}, + math::Decimal, + processor::process_instruction, + state::{FeeCalculation, INITIAL_COLLATERAL_RATIO}, + }, }; -use spl_token_lending::{ - error::LendingError, - instruction::{borrow_obligation_liquidity, refresh_obligation}, - math::Decimal, - processor::process_instruction, - state::{FeeCalculation, INITIAL_COLLATERAL_RATIO}, -}; -use std::u64; #[tokio::test] async fn test_borrow_usdc_fixed_amount() { @@ -102,6 +104,7 @@ async fn test_borrow_usdc_fixed_amount() { borrow_obligation_liquidity( spl_token_lending::id(), USDC_BORROW_AMOUNT_FRACTIONAL, + None, usdc_test_reserve.liquidity_supply_pubkey, usdc_test_reserve.user_liquidity_pubkey, usdc_test_reserve.pubkey, @@ -249,6 +252,7 @@ async fn test_borrow_sol_max_amount() { borrow_obligation_liquidity( spl_token_lending::id(), u64::MAX, + None, sol_test_reserve.liquidity_supply_pubkey, sol_test_reserve.user_liquidity_pubkey, sol_test_reserve.pubkey, @@ -368,7 +372,7 @@ async fn test_borrow_too_large() { }, ); - let (mut banks_client, payer, recent_blockhash) = test.start().await; + let (banks_client, payer, recent_blockhash) = test.start().await; let mut transaction = Transaction::new_with_payer( &[ @@ -380,6 +384,7 @@ async fn test_borrow_too_large() { borrow_obligation_liquidity( spl_token_lending::id(), USDC_BORROW_AMOUNT_FRACTIONAL, + None, usdc_test_reserve.liquidity_supply_pubkey, usdc_test_reserve.user_liquidity_pubkey, usdc_test_reserve.pubkey, @@ -408,3 +413,353 @@ async fn test_borrow_too_large() { ) ); } + +#[tokio::test] +async fn test_borrow_max_receive_minimum() { + let mut test = ProgramTest::new( + "spl_token_lending", + spl_token_lending::id(), + processor!(process_instruction), + ); + + // limit to track compute unit increase + test.set_compute_max_units(60_000); + + const FEE_AMOUNT: u64 = 5000; + const HOST_FEE_AMOUNT: u64 = 1000; + + const USDC_DEPOSIT_AMOUNT_FRACTIONAL: u64 = + 2_000 * FRACTIONAL_TO_USDC * INITIAL_COLLATERAL_RATIO; + const SOL_BORROW_AMOUNT_LAMPORTS: u64 = 50 * LAMPORTS_TO_SOL; + const USDC_RESERVE_COLLATERAL_FRACTIONAL: u64 = 2 * USDC_DEPOSIT_AMOUNT_FRACTIONAL; + const SOL_RESERVE_LIQUIDITY_LAMPORTS: u64 = 2 * SOL_BORROW_AMOUNT_LAMPORTS; + const SLIPPAGE_LIMIT: u64 = SOL_BORROW_AMOUNT_LAMPORTS - FEE_AMOUNT; + + let user_accounts_owner = Keypair::new(); + let lending_market = add_lending_market(&mut test); + + let mut reserve_config = TEST_RESERVE_CONFIG; + reserve_config.loan_to_value_ratio = 50; + + let usdc_mint = add_usdc_mint(&mut test); + let usdc_oracle = add_usdc_oracle(&mut test); + let usdc_test_reserve = add_reserve( + &mut test, + &lending_market, + &usdc_oracle, + &user_accounts_owner, + AddReserveArgs { + liquidity_amount: USDC_RESERVE_COLLATERAL_FRACTIONAL, + liquidity_mint_pubkey: usdc_mint.pubkey, + liquidity_mint_decimals: usdc_mint.decimals, + config: reserve_config, + mark_fresh: true, + ..AddReserveArgs::default() + }, + ); + + let sol_oracle = add_sol_oracle(&mut test); + let sol_test_reserve = add_reserve( + &mut test, + &lending_market, + &sol_oracle, + &user_accounts_owner, + AddReserveArgs { + liquidity_amount: SOL_RESERVE_LIQUIDITY_LAMPORTS, + liquidity_mint_pubkey: spl_token::native_mint::id(), + liquidity_mint_decimals: 9, + config: reserve_config, + mark_fresh: true, + ..AddReserveArgs::default() + }, + ); + + let test_obligation = add_obligation( + &mut test, + &lending_market, + &user_accounts_owner, + AddObligationArgs { + deposits: &[(&usdc_test_reserve, USDC_DEPOSIT_AMOUNT_FRACTIONAL)], + ..AddObligationArgs::default() + }, + ); + + let (mut banks_client, payer, recent_blockhash) = test.start().await; + + let initial_liquidity_supply = + get_token_balance(&mut banks_client, sol_test_reserve.liquidity_supply_pubkey).await; + + let mut transaction = Transaction::new_with_payer( + &[ + refresh_obligation( + spl_token_lending::id(), + test_obligation.pubkey, + vec![usdc_test_reserve.pubkey], + ), + borrow_obligation_liquidity( + spl_token_lending::id(), + u64::MAX, + Some(SLIPPAGE_LIMIT), + sol_test_reserve.liquidity_supply_pubkey, + sol_test_reserve.user_liquidity_pubkey, + sol_test_reserve.pubkey, + sol_test_reserve.liquidity_fee_receiver_pubkey, + test_obligation.pubkey, + lending_market.pubkey, + test_obligation.owner, + Some(sol_test_reserve.liquidity_host_pubkey), + ), + ], + Some(&payer.pubkey()), + ); + + transaction.sign(&[&payer, &user_accounts_owner], recent_blockhash); + assert!(banks_client.process_transaction(transaction).await.is_ok()); + + let sol_reserve = sol_test_reserve.get_state(&mut banks_client).await; + let obligation = test_obligation.get_state(&mut banks_client).await; + + let (total_fee, host_fee) = sol_reserve + .config + .fees + .calculate_borrow_fees(SOL_BORROW_AMOUNT_LAMPORTS.into(), FeeCalculation::Inclusive) + .unwrap(); + + assert_eq!(total_fee, FEE_AMOUNT); + assert_eq!(host_fee, HOST_FEE_AMOUNT); + + let borrow_amount = + get_token_balance(&mut banks_client, sol_test_reserve.user_liquidity_pubkey).await; + assert_eq!(borrow_amount, SOL_BORROW_AMOUNT_LAMPORTS - FEE_AMOUNT); + + let liquidity = &obligation.borrows[0]; + assert_eq!( + liquidity.borrowed_amount_wads, + Decimal::from(SOL_BORROW_AMOUNT_LAMPORTS) + ); + + let liquidity_supply = + get_token_balance(&mut banks_client, sol_test_reserve.liquidity_supply_pubkey).await; + assert_eq!( + liquidity_supply, + initial_liquidity_supply - SOL_BORROW_AMOUNT_LAMPORTS + ); + + let fee_balance = get_token_balance( + &mut banks_client, + sol_test_reserve.liquidity_fee_receiver_pubkey, + ) + .await; + assert_eq!(fee_balance, FEE_AMOUNT - HOST_FEE_AMOUNT); + + let host_fee_balance = + get_token_balance(&mut banks_client, sol_test_reserve.liquidity_host_pubkey).await; + assert_eq!(host_fee_balance, HOST_FEE_AMOUNT); +} + +#[tokio::test] +async fn test_borrow_max_receive_less_than_slippage() { + let mut test = ProgramTest::new( + "spl_token_lending", + spl_token_lending::id(), + processor!(process_instruction), + ); + + // limit to track compute unit increase + test.set_compute_max_units(60_000); + + const FEE_AMOUNT: u64 = 5000; + + const USDC_DEPOSIT_AMOUNT_FRACTIONAL: u64 = + 2_000 * FRACTIONAL_TO_USDC * INITIAL_COLLATERAL_RATIO; + const SOL_BORROW_AMOUNT_LAMPORTS: u64 = 50 * LAMPORTS_TO_SOL; + const USDC_RESERVE_COLLATERAL_FRACTIONAL: u64 = 2 * USDC_DEPOSIT_AMOUNT_FRACTIONAL; + const SOL_RESERVE_LIQUIDITY_LAMPORTS: u64 = 2 * SOL_BORROW_AMOUNT_LAMPORTS; + const SLIPPAGE_LIMIT: u64 = SOL_BORROW_AMOUNT_LAMPORTS - FEE_AMOUNT + 1; + + let user_accounts_owner = Keypair::new(); + let lending_market = add_lending_market(&mut test); + + let mut reserve_config = TEST_RESERVE_CONFIG; + reserve_config.loan_to_value_ratio = 50; + + let usdc_mint = add_usdc_mint(&mut test); + let usdc_oracle = add_usdc_oracle(&mut test); + let usdc_test_reserve = add_reserve( + &mut test, + &lending_market, + &usdc_oracle, + &user_accounts_owner, + AddReserveArgs { + liquidity_amount: USDC_RESERVE_COLLATERAL_FRACTIONAL, + liquidity_mint_pubkey: usdc_mint.pubkey, + liquidity_mint_decimals: usdc_mint.decimals, + config: reserve_config, + mark_fresh: true, + ..AddReserveArgs::default() + }, + ); + + let sol_oracle = add_sol_oracle(&mut test); + let sol_test_reserve = add_reserve( + &mut test, + &lending_market, + &sol_oracle, + &user_accounts_owner, + AddReserveArgs { + liquidity_amount: SOL_RESERVE_LIQUIDITY_LAMPORTS, + liquidity_mint_pubkey: spl_token::native_mint::id(), + liquidity_mint_decimals: 9, + config: reserve_config, + mark_fresh: true, + ..AddReserveArgs::default() + }, + ); + + let test_obligation = add_obligation( + &mut test, + &lending_market, + &user_accounts_owner, + AddObligationArgs { + deposits: &[(&usdc_test_reserve, USDC_DEPOSIT_AMOUNT_FRACTIONAL)], + ..AddObligationArgs::default() + }, + ); + + let (banks_client, payer, recent_blockhash) = test.start().await; + + let mut transaction = Transaction::new_with_payer( + &[ + refresh_obligation( + spl_token_lending::id(), + test_obligation.pubkey, + vec![usdc_test_reserve.pubkey], + ), + borrow_obligation_liquidity( + spl_token_lending::id(), + u64::MAX, + Some(SLIPPAGE_LIMIT), + sol_test_reserve.liquidity_supply_pubkey, + sol_test_reserve.user_liquidity_pubkey, + sol_test_reserve.pubkey, + sol_test_reserve.liquidity_fee_receiver_pubkey, + test_obligation.pubkey, + lending_market.pubkey, + test_obligation.owner, + Some(sol_test_reserve.liquidity_host_pubkey), + ), + ], + Some(&payer.pubkey()), + ); + + transaction.sign(&[&payer, &user_accounts_owner], recent_blockhash); + assert_eq!( + banks_client + .process_transaction(transaction) + .await + .unwrap_err() + .unwrap(), + TransactionError::InstructionError( + 1, + InstructionError::Custom(LendingError::ExceededSlippage as u32) + ) + ); +} + +#[tokio::test] +async fn test_borrow_less_than_max_with_slippage() { + let mut test = ProgramTest::new( + "spl_token_lending", + spl_token_lending::id(), + processor!(process_instruction), + ); + + const USDC_TOTAL_BORROW_FRACTIONAL: u64 = 1_000 * FRACTIONAL_TO_USDC; + const FEE_AMOUNT: u64 = 100; + + const SOL_DEPOSIT_AMOUNT_LAMPORTS: u64 = 100 * LAMPORTS_TO_SOL * INITIAL_COLLATERAL_RATIO; + const USDC_BORROW_AMOUNT_FRACTIONAL: u64 = USDC_TOTAL_BORROW_FRACTIONAL - FEE_AMOUNT; + const SOL_RESERVE_COLLATERAL_LAMPORTS: u64 = 2 * SOL_DEPOSIT_AMOUNT_LAMPORTS; + const USDC_RESERVE_LIQUIDITY_FRACTIONAL: u64 = 2 * USDC_TOTAL_BORROW_FRACTIONAL; + const SLIPPAGE_LIMIT: u64 = u64::MAX; + + let user_accounts_owner = Keypair::new(); + let lending_market = add_lending_market(&mut test); + + let mut reserve_config = TEST_RESERVE_CONFIG; + reserve_config.loan_to_value_ratio = 50; + + let sol_oracle = add_sol_oracle(&mut test); + let sol_test_reserve = add_reserve( + &mut test, + &lending_market, + &sol_oracle, + &user_accounts_owner, + AddReserveArgs { + collateral_amount: SOL_RESERVE_COLLATERAL_LAMPORTS, + liquidity_mint_pubkey: spl_token::native_mint::id(), + liquidity_mint_decimals: 9, + config: reserve_config, + mark_fresh: true, + ..AddReserveArgs::default() + }, + ); + + let usdc_mint = add_usdc_mint(&mut test); + let usdc_oracle = add_usdc_oracle(&mut test); + let usdc_test_reserve = add_reserve( + &mut test, + &lending_market, + &usdc_oracle, + &user_accounts_owner, + AddReserveArgs { + liquidity_amount: USDC_RESERVE_LIQUIDITY_FRACTIONAL, + liquidity_mint_pubkey: usdc_mint.pubkey, + liquidity_mint_decimals: usdc_mint.decimals, + config: reserve_config, + mark_fresh: true, + ..AddReserveArgs::default() + }, + ); + + let test_obligation = add_obligation( + &mut test, + &lending_market, + &user_accounts_owner, + AddObligationArgs { + deposits: &[(&sol_test_reserve, SOL_DEPOSIT_AMOUNT_LAMPORTS)], + ..AddObligationArgs::default() + }, + ); + + let (banks_client, payer, recent_blockhash) = test.start().await; + + let mut transaction = Transaction::new_with_payer( + &[ + refresh_obligation( + spl_token_lending::id(), + test_obligation.pubkey, + vec![sol_test_reserve.pubkey], + ), + borrow_obligation_liquidity( + spl_token_lending::id(), + USDC_BORROW_AMOUNT_FRACTIONAL, + Some(SLIPPAGE_LIMIT), + usdc_test_reserve.liquidity_supply_pubkey, + usdc_test_reserve.user_liquidity_pubkey, + usdc_test_reserve.pubkey, + usdc_test_reserve.liquidity_fee_receiver_pubkey, + test_obligation.pubkey, + lending_market.pubkey, + test_obligation.owner, + Some(usdc_test_reserve.liquidity_host_pubkey), + ), + ], + Some(&payer.pubkey()), + ); + + transaction.sign(&[&payer, &user_accounts_owner], recent_blockhash); + + // check that transaction succeeds + banks_client.process_transaction(transaction).await.unwrap(); +} diff --git a/token-lending/program/tests/deposit_obligation_collateral.rs b/token-lending/program/tests/deposit_obligation_collateral.rs index 73e30dc08b0..cf2e3bcc828 100644 --- a/token-lending/program/tests/deposit_obligation_collateral.rs +++ b/token-lending/program/tests/deposit_obligation_collateral.rs @@ -1,17 +1,20 @@ -#![cfg(feature = "test-bpf")] +#![allow(clippy::arithmetic_side_effects)] +#![cfg(feature = "test-sbf")] mod helpers; -use helpers::*; -use solana_program_test::*; -use solana_sdk::{ - signature::{Keypair, Signer}, - transaction::Transaction, -}; -use spl_token::instruction::approve; -use spl_token_lending::{ - instruction::deposit_obligation_collateral, processor::process_instruction, - state::INITIAL_COLLATERAL_RATIO, +use { + helpers::*, + solana_program_test::*, + solana_sdk::{ + signature::{Keypair, Signer}, + transaction::Transaction, + }, + spl_token::instruction::approve, + spl_token_lending::{ + instruction::deposit_obligation_collateral, processor::process_instruction, + state::INITIAL_COLLATERAL_RATIO, + }, }; #[tokio::test] diff --git a/token-lending/program/tests/deposit_reserve_liquidity.rs b/token-lending/program/tests/deposit_reserve_liquidity.rs index ced4ea614ba..9e880687ad6 100644 --- a/token-lending/program/tests/deposit_reserve_liquidity.rs +++ b/token-lending/program/tests/deposit_reserve_liquidity.rs @@ -1,11 +1,12 @@ -#![cfg(feature = "test-bpf")] +#![allow(clippy::arithmetic_side_effects)] +#![cfg(feature = "test-sbf")] mod helpers; -use helpers::*; -use solana_program_test::*; -use solana_sdk::signature::Keypair; -use spl_token_lending::processor::process_instruction; +use { + helpers::*, solana_program_test::*, solana_sdk::signature::Keypair, + spl_token_lending::processor::process_instruction, +}; #[tokio::test] async fn test_success() { diff --git a/token-lending/program/tests/flash_loan.rs b/token-lending/program/tests/flash_loan.rs index ff00626e0b2..061c73a1bd5 100644 --- a/token-lending/program/tests/flash_loan.rs +++ b/token-lending/program/tests/flash_loan.rs @@ -1,18 +1,21 @@ -#![cfg(feature = "test-bpf")] +#![allow(clippy::arithmetic_side_effects)] +#![cfg(feature = "test-sbf")] mod helpers; -use helpers::*; -use solana_program::instruction::AccountMeta; -use solana_program_test::*; -use solana_sdk::{ - pubkey::Pubkey, - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, -}; -use spl_token::solana_program::instruction::InstructionError; -use spl_token_lending::{ - error::LendingError, instruction::flash_loan, processor::process_instruction, +use { + helpers::*, + solana_program::instruction::AccountMeta, + solana_program_test::*, + solana_sdk::{ + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::{Transaction, TransactionError}, + }, + spl_token::solana_program::instruction::InstructionError, + spl_token_lending::{ + error::LendingError, instruction::flash_loan, processor::process_instruction, + }, }; #[tokio::test] @@ -35,7 +38,7 @@ async fn test_success() { test.prefer_bpf(false); test.add_program( "flash_loan_receiver", - receiver_program_id.clone(), + receiver_program_id, processor!(helpers::flash_loan_receiver::process_instruction), ); @@ -94,11 +97,8 @@ async fn test_success() { usdc_test_reserve.liquidity_fee_receiver_pubkey, usdc_test_reserve.liquidity_host_pubkey, lending_market.pubkey, - receiver_program_id.clone(), - vec![AccountMeta::new_readonly( - receiver_authority_pubkey.clone(), - false, - )], + receiver_program_id, + vec![AccountMeta::new_readonly(receiver_authority_pubkey, false)], )], Some(&payer.pubkey()), ); @@ -155,7 +155,7 @@ async fn test_failure() { test.prefer_bpf(false); test.add_program( "flash_loan_receiver", - flash_loan_receiver_program_id.clone(), + flash_loan_receiver_program_id, processor!(helpers::flash_loan_receiver::process_instruction), ); @@ -206,11 +206,8 @@ async fn test_failure() { usdc_test_reserve.liquidity_fee_receiver_pubkey, usdc_test_reserve.liquidity_host_pubkey, lending_market.pubkey, - flash_loan_receiver_program_id.clone(), - vec![AccountMeta::new_readonly( - receiver_authority_pubkey.clone(), - false, - )], + flash_loan_receiver_program_id, + vec![AccountMeta::new_readonly(receiver_authority_pubkey, false)], )], Some(&payer.pubkey()), ); diff --git a/token-lending/program/tests/helpers/flash_loan_receiver.rs b/token-lending/program/tests/helpers/flash_loan_receiver.rs index 21d8c615ab9..6d258d8213e 100644 --- a/token-lending/program/tests/helpers/flash_loan_receiver.rs +++ b/token-lending/program/tests/helpers/flash_loan_receiver.rs @@ -1,35 +1,37 @@ -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, msg, pubkey::Pubkey, -}; - -use crate::helpers::flash_loan_receiver::FlashLoanReceiverError::InvalidInstruction; -use spl_token::{ - solana_program::{ - account_info::next_account_info, program::invoke_signed, program_error::ProgramError, - program_pack::Pack, +use { + crate::helpers::flash_loan_receiver::FlashLoanReceiverError::InvalidInstruction, + solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, msg, pubkey::Pubkey}, + spl_token::{ + solana_program::{ + account_info::next_account_info, program::invoke_signed, program_error::ProgramError, + program_pack::Pack, + }, + state::Account, }, - state::Account, + std::{cmp::min, convert::TryInto}, + thiserror::Error, }; -use std::cmp::min; -use std::convert::TryInto; -use thiserror::Error; pub enum FlashLoanReceiverInstruction { - /// Receive a flash loan and perform user-defined operation and finally return the fund back. + /// Receive a flash loan and perform user-defined operation and finally + /// return the fund back. /// /// Accounts expected: /// - /// 0. `[writable]` Source liquidity (matching the destination from above). - /// 1. `[writable]` Destination liquidity (matching the source from above). + /// 0. `[writable]` Source liquidity (matching the destination from + /// above). + /// 1. `[writable]` Destination liquidity (matching the source from + /// above). /// 2. `[]` Token program id - /// .. `[any]` Additional accounts provided to the lending program's `FlashLoan` instruction above. + /// 3. ..`[any]` Additional accounts provided to the lending program's + /// `FlashLoan` instruction above. ReceiveFlashLoan { /// The amount that is loaned amount: u64, }, } -entrypoint!(process_instruction); +solana_program::entrypoint!(process_instruction); pub fn process_instruction( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/token-lending/program/tests/helpers/genesis.rs b/token-lending/program/tests/helpers/genesis.rs deleted file mode 100644 index 6eba2f0e8d8..00000000000 --- a/token-lending/program/tests/helpers/genesis.rs +++ /dev/null @@ -1,91 +0,0 @@ -use serde::{Deserialize, Serialize}; -use solana_program::bpf_loader_upgradeable; -use solana_program_test::*; -use solana_sdk::{ - account::Account, - bpf_loader_upgradeable::UpgradeableLoaderState, - pubkey::Pubkey, - signature::{read_keypair_file, Signer}, -}; -use std::{collections::HashMap, fs::File, io::Write, path::Path}; - -/// An account where the data is encoded as a Base64 string. -#[derive(Serialize, Deserialize, Debug)] -pub struct Base64Account { - pub balance: u64, - pub owner: String, - pub data: String, - pub executable: bool, -} - -impl From for Base64Account { - fn from(account: Account) -> Self { - Self { - owner: account.owner.to_string(), - balance: account.lamports, - executable: account.executable, - data: base64::encode(&account.data), - } - } -} - -#[derive(Default)] -pub struct GenesisAccounts(HashMap); - -impl GenesisAccounts { - pub fn insert_upgradeable_program(&mut self, program_id: Pubkey, filename: &str) { - let program_file = - find_file(filename).unwrap_or_else(|| panic!("couldn't find {}", filename)); - let program_data = read_file(program_file); - let upgrade_authority_keypair = - read_keypair_file("tests/fixtures/lending_market_owner.json").unwrap(); - - let programdata_address = - Pubkey::find_program_address(&[program_id.as_ref()], &bpf_loader_upgradeable::id()).0; - let programdata_data_offset = UpgradeableLoaderState::programdata_data_offset().unwrap(); - let programdata_space = 2 * program_data.len() + programdata_data_offset; - let mut programdata_account = Account::new_data_with_space( - u32::MAX as u64, - &UpgradeableLoaderState::ProgramData { - slot: 0, - upgrade_authority_address: Some(upgrade_authority_keypair.pubkey()), - }, - programdata_space, - &bpf_loader_upgradeable::id(), - ) - .unwrap(); - - programdata_account.data - [programdata_data_offset..programdata_data_offset + program_data.len()] - .copy_from_slice(&program_data[..]); - - self.0 - .insert(programdata_address.to_string(), programdata_account.into()); - - let mut program_account = Account::new_data( - u32::MAX as u64, - &UpgradeableLoaderState::Program { - programdata_address, - }, - &bpf_loader_upgradeable::id(), - ) - .unwrap(); - program_account.executable = true; - - self.0 - .insert(program_id.to_string(), program_account.into()); - } - - pub async fn fetch_and_insert(&mut self, banks_client: &mut BanksClient, pubkey: Pubkey) { - let mut account: Account = banks_client.get_account(pubkey).await.unwrap().unwrap(); - account.lamports = u32::MAX as u64; - self.0.insert(pubkey.to_string(), account.into()); - } - - pub fn write_yaml(&self) { - let serialized = serde_yaml::to_string(&self.0).unwrap(); - let path = Path::new("../../target/deploy/lending_accounts.yml"); - let mut file = File::create(path).unwrap(); - file.write_all(&serialized.into_bytes()).unwrap(); - } -} diff --git a/token-lending/program/tests/helpers/mod.rs b/token-lending/program/tests/helpers/mod.rs index 1b0ad8916e1..9c6c873e2ea 100644 --- a/token-lending/program/tests/helpers/mod.rs +++ b/token-lending/program/tests/helpers/mod.rs @@ -1,36 +1,37 @@ #![allow(dead_code)] pub mod flash_loan_receiver; -pub mod genesis; - -use assert_matches::*; -use solana_program::{program_option::COption, program_pack::Pack, pubkey::Pubkey}; -use solana_program_test::*; -use solana_sdk::{ - account::Account, - signature::{read_keypair_file, Keypair, Signer}, - system_instruction::create_account, - transaction::{Transaction, TransactionError}, -}; -use spl_token::{ - instruction::approve, - state::{Account as Token, AccountState, Mint}, -}; -use spl_token_lending::{ - instruction::{ - borrow_obligation_liquidity, deposit_reserve_liquidity, init_lending_market, - init_obligation, init_reserve, liquidate_obligation, refresh_reserve, + +use { + assert_matches::*, + solana_program::{program_option::COption, program_pack::Pack, pubkey::Pubkey}, + solana_program_test::*, + solana_sdk::{ + account::Account, + signature::{read_keypair_file, Keypair, Signer}, + system_instruction::create_account, + transaction::{Transaction, TransactionError}, }, - math::{Decimal, Rate, TryAdd, TryMul}, - pyth, - state::{ - InitLendingMarketParams, InitObligationParams, InitReserveParams, LendingMarket, - NewReserveCollateralParams, NewReserveLiquidityParams, Obligation, ObligationCollateral, - ObligationLiquidity, Reserve, ReserveCollateral, ReserveConfig, ReserveFees, - ReserveLiquidity, INITIAL_COLLATERAL_RATIO, PROGRAM_VERSION, + spl_token::{ + instruction::approve, + state::{Account as Token, AccountState, Mint}, }, + spl_token_lending::{ + instruction::{ + borrow_obligation_liquidity, deposit_reserve_liquidity, init_lending_market, + init_obligation, init_reserve, liquidate_obligation, refresh_reserve, + }, + math::{Decimal, Rate, TryAdd, TryMul}, + pyth, + state::{ + InitLendingMarketParams, InitObligationParams, InitReserveParams, LendingMarket, + NewReserveCollateralParams, NewReserveLiquidityParams, Obligation, + ObligationCollateral, ObligationLiquidity, Reserve, ReserveCollateral, ReserveConfig, + ReserveFees, ReserveLiquidity, INITIAL_COLLATERAL_RATIO, PROGRAM_VERSION, + }, + }, + std::{convert::TryInto, str::FromStr}, }; -use std::{convert::TryInto, str::FromStr}; pub const QUOTE_CURRENCY: [u8; 32] = *b"USD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; @@ -47,9 +48,9 @@ pub const TEST_RESERVE_CONFIG: ReserveConfig = ReserveConfig { optimal_borrow_rate: 4, max_borrow_rate: 30, fees: ReserveFees { - /// 0.00001% (Aave borrow fee) + // 0.00001% (Aave borrow fee) borrow_fee_wad: 100_000_000_000, - /// 0.3% (Aave flash loan fee) + // 0.3% (Aave flash loan fee) flash_loan_fee_wad: 3_000_000_000_000_000, host_fee_percentage: 20, }, @@ -506,7 +507,7 @@ impl TestLendingMarket { ); let recent_blockhash = banks_client.get_latest_blockhash().await.unwrap(); - transaction.sign(&[&payer, &lending_market_keypair], recent_blockhash); + transaction.sign(&[payer, &lending_market_keypair], recent_blockhash); assert_matches!(banks_client.process_transaction(transaction).await, Ok(())); TestLendingMarket { @@ -628,7 +629,7 @@ impl TestLendingMarket { let recent_blockhash = banks_client.get_latest_blockhash().await.unwrap(); transaction.sign( - &[&payer, &user_accounts_owner, &user_transfer_authority], + &[payer, user_accounts_owner, &user_transfer_authority], recent_blockhash, ); assert!(banks_client.process_transaction(transaction).await.is_ok()); @@ -651,6 +652,7 @@ impl TestLendingMarket { &[borrow_obligation_liquidity( spl_token_lending::id(), liquidity_amount, + None, borrow_reserve.liquidity_supply_pubkey, borrow_reserve.user_liquidity_pubkey, borrow_reserve.pubkey, @@ -1101,16 +1103,16 @@ pub fn add_oracle( product_pubkey, u32::MAX as u64, oracle_program_id.pubkey(), - &format!("{}.bin", product_pubkey.to_string()), + &format!("{}.bin", product_pubkey), ); // Add Pyth price account after setting the price - let filename = &format!("{}.bin", price_pubkey.to_string()); + let filename = &format!("{}.bin", price_pubkey); let mut pyth_price_data = read_file(find_file(filename).unwrap_or_else(|| { panic!("Unable to locate {}", filename); })); - let mut pyth_price = pyth::load_mut::(pyth_price_data.as_mut_slice()).unwrap(); + let pyth_price = pyth::load_mut::(pyth_price_data.as_mut_slice()).unwrap(); let decimals = 10u64 .checked_pow(pyth_price.expo.checked_abs().unwrap().try_into().unwrap()) @@ -1153,12 +1155,12 @@ pub async fn create_and_mint_to_token_account( ) -> Pubkey { if let Some(mint_authority) = mint_authority { let account_pubkey = - create_token_account(banks_client, mint_pubkey, &payer, Some(authority), None).await; + create_token_account(banks_client, mint_pubkey, payer, Some(authority), None).await; mint_to( banks_client, mint_pubkey, - &payer, + payer, account_pubkey, mint_authority, amount, @@ -1170,7 +1172,7 @@ pub async fn create_and_mint_to_token_account( create_token_account( banks_client, mint_pubkey, - &payer, + payer, Some(authority), Some(amount), ) @@ -1212,7 +1214,7 @@ pub async fn create_token_account( ); let recent_blockhash = banks_client.get_latest_blockhash().await.unwrap(); - transaction.sign(&[&payer, &token_keypair], recent_blockhash); + transaction.sign(&[payer, &token_keypair], recent_blockhash); assert_matches!(banks_client.process_transaction(transaction).await, Ok(())); diff --git a/token-lending/program/tests/init_lending_market.rs b/token-lending/program/tests/init_lending_market.rs index ee9e602333c..a4b8d48a429 100644 --- a/token-lending/program/tests/init_lending_market.rs +++ b/token-lending/program/tests/init_lending_market.rs @@ -1,16 +1,19 @@ -#![cfg(feature = "test-bpf")] +#![allow(clippy::arithmetic_side_effects)] +#![cfg(feature = "test-sbf")] mod helpers; -use helpers::*; -use solana_program_test::*; -use solana_sdk::{ - instruction::InstructionError, - signature::Signer, - transaction::{Transaction, TransactionError}, -}; -use spl_token_lending::{ - error::LendingError, instruction::init_lending_market, processor::process_instruction, +use { + helpers::*, + solana_program_test::*, + solana_sdk::{ + instruction::InstructionError, + signature::Signer, + transaction::{Transaction, TransactionError}, + }, + spl_token_lending::{ + error::LendingError, instruction::init_lending_market, processor::process_instruction, + }, }; #[tokio::test] @@ -40,7 +43,7 @@ async fn test_already_initialized() { ); let existing_market = add_lending_market(&mut test); - let (mut banks_client, payer, recent_blockhash) = test.start().await; + let (banks_client, payer, recent_blockhash) = test.start().await; let mut transaction = Transaction::new_with_payer( &[init_lending_market( diff --git a/token-lending/program/tests/init_obligation.rs b/token-lending/program/tests/init_obligation.rs index 05f4c50d401..9ba184168a4 100644 --- a/token-lending/program/tests/init_obligation.rs +++ b/token-lending/program/tests/init_obligation.rs @@ -1,16 +1,19 @@ -#![cfg(feature = "test-bpf")] +#![allow(clippy::arithmetic_side_effects)] +#![cfg(feature = "test-sbf")] mod helpers; -use helpers::*; -use solana_program_test::*; -use solana_sdk::{ - instruction::InstructionError, - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, -}; -use spl_token_lending::{ - error::LendingError, instruction::init_obligation, processor::process_instruction, +use { + helpers::*, + solana_program_test::*, + solana_sdk::{ + instruction::InstructionError, + signature::{Keypair, Signer}, + transaction::{Transaction, TransactionError}, + }, + spl_token_lending::{ + error::LendingError, instruction::init_obligation, processor::process_instruction, + }, }; #[tokio::test] @@ -61,7 +64,7 @@ async fn test_already_initialized() { AddObligationArgs::default(), ); - let (mut banks_client, payer, recent_blockhash) = test.start().await; + let (banks_client, payer, recent_blockhash) = test.start().await; let mut transaction = Transaction::new_with_payer( &[init_obligation( spl_token_lending::id(), diff --git a/token-lending/program/tests/init_reserve.rs b/token-lending/program/tests/init_reserve.rs index c2407bec63e..134a7e5277c 100644 --- a/token-lending/program/tests/init_reserve.rs +++ b/token-lending/program/tests/init_reserve.rs @@ -1,19 +1,22 @@ -#![cfg(feature = "test-bpf")] +#![allow(clippy::arithmetic_side_effects)] +#![cfg(feature = "test-sbf")] mod helpers; -use helpers::*; -use solana_program_test::*; -use solana_sdk::{ - instruction::InstructionError, - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, -}; -use spl_token_lending::{ - error::LendingError, - instruction::init_reserve, - processor::process_instruction, - state::{ReserveFees, INITIAL_COLLATERAL_RATIO}, +use { + helpers::*, + solana_program_test::*, + solana_sdk::{ + instruction::InstructionError, + signature::{Keypair, Signer}, + transaction::{Transaction, TransactionError}, + }, + spl_token_lending::{ + error::LendingError, + instruction::init_reserve, + processor::process_instruction, + state::{ReserveFees, INITIAL_COLLATERAL_RATIO}, + }, }; #[tokio::test] @@ -104,7 +107,7 @@ async fn test_already_initialized() { }, ); - let (mut banks_client, payer, recent_blockhash) = test.start().await; + let (banks_client, payer, recent_blockhash) = test.start().await; let mut transaction = Transaction::new_with_payer( &[init_reserve( diff --git a/token-lending/program/tests/liquidate_obligation.rs b/token-lending/program/tests/liquidate_obligation.rs index d052fae6e43..df7687fb772 100644 --- a/token-lending/program/tests/liquidate_obligation.rs +++ b/token-lending/program/tests/liquidate_obligation.rs @@ -1,18 +1,21 @@ -#![cfg(feature = "test-bpf")] +#![allow(clippy::arithmetic_side_effects)] +#![cfg(feature = "test-sbf")] mod helpers; -use helpers::*; -use solana_program_test::*; -use solana_sdk::{ - signature::{Keypair, Signer}, - transaction::Transaction, -}; -use spl_token::instruction::approve; -use spl_token_lending::{ - instruction::{liquidate_obligation, refresh_obligation}, - processor::process_instruction, - state::INITIAL_COLLATERAL_RATIO, +use { + helpers::*, + solana_program_test::*, + solana_sdk::{ + signature::{Keypair, Signer}, + transaction::Transaction, + }, + spl_token::instruction::approve, + spl_token_lending::{ + instruction::{liquidate_obligation, refresh_obligation}, + processor::process_instruction, + state::INITIAL_COLLATERAL_RATIO, + }, }; #[tokio::test] diff --git a/token-lending/program/tests/modify_reserve_config.rs b/token-lending/program/tests/modify_reserve_config.rs index 8986db71313..2fe71ce5038 100644 --- a/token-lending/program/tests/modify_reserve_config.rs +++ b/token-lending/program/tests/modify_reserve_config.rs @@ -1,22 +1,25 @@ -#![cfg(feature = "test-bpf")] +#![allow(clippy::arithmetic_side_effects)] +#![cfg(feature = "test-sbf")] mod helpers; -use helpers::*; -use solana_program::pubkey::Pubkey; -use solana_program_test::*; -use solana_sdk::{ - instruction::InstructionError, - signature::{read_keypair_file, Keypair, Signer}, - transaction::{Transaction, TransactionError}, -}; -use spl_token_lending::{ - error::LendingError, - instruction::modify_reserve_config, - processor::process_instruction, - state::{ - InitLendingMarketParams, LendingMarket, ReserveConfig, ReserveFees, - INITIAL_COLLATERAL_RATIO, +use { + helpers::*, + solana_program::pubkey::Pubkey, + solana_program_test::*, + solana_sdk::{ + instruction::InstructionError, + signature::{read_keypair_file, Keypair, Signer}, + transaction::{Transaction, TransactionError}, + }, + spl_token_lending::{ + error::LendingError, + instruction::modify_reserve_config, + processor::process_instruction, + state::{ + InitLendingMarketParams, LendingMarket, ReserveConfig, ReserveFees, + INITIAL_COLLATERAL_RATIO, + }, }, }; @@ -134,7 +137,7 @@ async fn wrong_signer_of_lending_market_cannot_change_reserve_config() { let other_lending_market_owner = Keypair::new(); other_lending_market.owner = other_lending_market_owner; - let (mut banks_client, payer, recent_blockhash) = test.start().await; + let (banks_client, payer, recent_blockhash) = test.start().await; const OPTIMAL_UTILIZATION_RATE_CHANGE: u8 = 10; @@ -301,9 +304,10 @@ async fn owner_of_different_lending_market_cannot_change_reserve_config() { #[tokio::test] // Right owner, wrong lending market async fn correct_owner_providing_wrong_lending_market_fails() { - // When the correct owner of the lending market and reserve provides, perhaps inadvertently, - // a lending market that is different from the given reserve's corresponding lending market, - // then the transaction to modify the current reserve config should fail. + // When the correct owner of the lending market and reserve provides, perhaps + // inadvertently, a lending market that is different from the given + // reserve's corresponding lending market, then the transaction to modify + // the current reserve config should fail. let mut test = ProgramTest::new( "spl_token_lending", spl_token_lending::id(), @@ -363,7 +367,9 @@ async fn correct_owner_providing_wrong_lending_market_fails() { new_config, sol_test_reserve.pubkey, other_lending_market.pubkey, - lending_market.owner.pubkey(), //lending_market.owner == other_lending_market.owner, defined by `add_lending_market` + // lending_market.owner == other_lending_market.owner, defined by + // `add_lending_market` + lending_market.owner.pubkey(), )], Some(&payer.pubkey()), ); diff --git a/token-lending/program/tests/obligation_end_to_end.rs b/token-lending/program/tests/obligation_end_to_end.rs index 1f306c63b18..57b66d125f3 100644 --- a/token-lending/program/tests/obligation_end_to_end.rs +++ b/token-lending/program/tests/obligation_end_to_end.rs @@ -1,25 +1,28 @@ -#![cfg(feature = "test-bpf")] +#![allow(clippy::arithmetic_side_effects)] +#![cfg(feature = "test-sbf")] mod helpers; -use helpers::*; -use solana_program_test::*; -use solana_sdk::{ - account::Account, - signature::{Keypair, Signer}, - system_instruction::create_account, - transaction::Transaction, -}; -use spl_token::{instruction::approve, solana_program::program_pack::Pack}; -use spl_token_lending::{ - instruction::{ - borrow_obligation_liquidity, deposit_obligation_collateral, init_obligation, - refresh_obligation, refresh_reserve, repay_obligation_liquidity, - withdraw_obligation_collateral, +use { + helpers::*, + solana_program_test::*, + solana_sdk::{ + account::Account, + signature::{Keypair, Signer}, + system_instruction::create_account, + transaction::Transaction, + }, + spl_token::{instruction::approve, solana_program::program_pack::Pack}, + spl_token_lending::{ + instruction::{ + borrow_obligation_liquidity, deposit_obligation_collateral, init_obligation, + refresh_obligation, refresh_reserve, repay_obligation_liquidity, + withdraw_obligation_collateral, + }, + math::Decimal, + processor::process_instruction, + state::{Obligation, INITIAL_COLLATERAL_RATIO}, }, - math::Decimal, - processor::process_instruction, - state::{Obligation, INITIAL_COLLATERAL_RATIO}, }; #[tokio::test] @@ -165,6 +168,7 @@ async fn test_success() { borrow_obligation_liquidity( spl_token_lending::id(), USDC_BORROW_AMOUNT_FRACTIONAL, + None, usdc_test_reserve.liquidity_supply_pubkey, usdc_test_reserve.user_liquidity_pubkey, usdc_test_reserve.pubkey, diff --git a/token-lending/program/tests/redeem_reserve_collateral.rs b/token-lending/program/tests/redeem_reserve_collateral.rs index b8b9c342db0..61df380303c 100644 --- a/token-lending/program/tests/redeem_reserve_collateral.rs +++ b/token-lending/program/tests/redeem_reserve_collateral.rs @@ -1,17 +1,20 @@ -#![cfg(feature = "test-bpf")] +#![allow(clippy::arithmetic_side_effects)] +#![cfg(feature = "test-sbf")] mod helpers; -use helpers::*; -use solana_program_test::*; -use solana_sdk::{ - signature::{Keypair, Signer}, - transaction::Transaction, -}; -use spl_token::instruction::approve; -use spl_token_lending::{ - instruction::redeem_reserve_collateral, processor::process_instruction, - state::INITIAL_COLLATERAL_RATIO, +use { + helpers::*, + solana_program_test::*, + solana_sdk::{ + signature::{Keypair, Signer}, + transaction::Transaction, + }, + spl_token::instruction::approve, + spl_token_lending::{ + instruction::redeem_reserve_collateral, processor::process_instruction, + state::INITIAL_COLLATERAL_RATIO, + }, }; #[tokio::test] @@ -49,7 +52,7 @@ async fn test_success() { }, ); - let (mut banks_client, payer, recent_blockhash) = test.start().await; + let (banks_client, payer, recent_blockhash) = test.start().await; let user_transfer_authority = Keypair::new(); let mut transaction = Transaction::new_with_payer( diff --git a/token-lending/program/tests/refresh_obligation.rs b/token-lending/program/tests/refresh_obligation.rs index 07485f4a0ca..e07e948ec75 100644 --- a/token-lending/program/tests/refresh_obligation.rs +++ b/token-lending/program/tests/refresh_obligation.rs @@ -1,20 +1,21 @@ -#![cfg(feature = "test-bpf")] +#![allow(clippy::arithmetic_side_effects)] +#![cfg(feature = "test-sbf")] mod helpers; -use helpers::*; -use solana_program_test::*; -use solana_sdk::{ - signature::{Keypair, Signer}, - transaction::Transaction, -}; -use spl_token_lending::math::{Rate, TryAdd, TryMul}; -use spl_token_lending::state::SLOTS_PER_YEAR; -use spl_token_lending::{ - instruction::{refresh_obligation, refresh_reserve}, - math::{Decimal, TryDiv}, - processor::process_instruction, - state::INITIAL_COLLATERAL_RATIO, +use { + helpers::*, + solana_program_test::*, + solana_sdk::{ + signature::{Keypair, Signer}, + transaction::Transaction, + }, + spl_token_lending::{ + instruction::{refresh_obligation, refresh_reserve}, + math::{Decimal, Rate, TryAdd, TryDiv, TryMul}, + processor::process_instruction, + state::{INITIAL_COLLATERAL_RATIO, SLOTS_PER_YEAR}, + }, }; #[tokio::test] diff --git a/token-lending/program/tests/refresh_reserve.rs b/token-lending/program/tests/refresh_reserve.rs index 131989526e1..66ace0fef70 100644 --- a/token-lending/program/tests/refresh_reserve.rs +++ b/token-lending/program/tests/refresh_reserve.rs @@ -1,18 +1,21 @@ -#![cfg(feature = "test-bpf")] +#![allow(clippy::arithmetic_side_effects)] +#![cfg(feature = "test-sbf")] mod helpers; -use helpers::*; -use solana_program_test::*; -use solana_sdk::{ - signature::{Keypair, Signer}, - transaction::Transaction, -}; -use spl_token_lending::{ - instruction::refresh_reserve, - math::{Decimal, Rate, TryAdd, TryDiv, TryMul}, - processor::process_instruction, - state::SLOTS_PER_YEAR, +use { + helpers::*, + solana_program_test::*, + solana_sdk::{ + signature::{Keypair, Signer}, + transaction::Transaction, + }, + spl_token_lending::{ + instruction::refresh_reserve, + math::{Decimal, Rate, TryAdd, TryDiv, TryMul}, + processor::process_instruction, + state::SLOTS_PER_YEAR, + }, }; #[tokio::test] diff --git a/token-lending/program/tests/repay_obligation_liquidity.rs b/token-lending/program/tests/repay_obligation_liquidity.rs index a280e615b7f..0b1dc5eeb39 100644 --- a/token-lending/program/tests/repay_obligation_liquidity.rs +++ b/token-lending/program/tests/repay_obligation_liquidity.rs @@ -1,18 +1,21 @@ -#![cfg(feature = "test-bpf")] +#![allow(clippy::arithmetic_side_effects)] +#![cfg(feature = "test-sbf")] mod helpers; -use helpers::*; -use solana_program_test::*; -use solana_sdk::{ - signature::{Keypair, Signer}, - transaction::Transaction, -}; -use spl_token::instruction::approve; -use spl_token_lending::instruction::refresh_obligation; -use spl_token_lending::{ - instruction::repay_obligation_liquidity, processor::process_instruction, - state::INITIAL_COLLATERAL_RATIO, +use { + helpers::*, + solana_program_test::*, + solana_sdk::{ + signature::{Keypair, Signer}, + transaction::Transaction, + }, + spl_token::instruction::approve, + spl_token_lending::{ + instruction::{refresh_obligation, repay_obligation_liquidity}, + processor::process_instruction, + state::INITIAL_COLLATERAL_RATIO, + }, }; #[tokio::test] diff --git a/token-lending/program/tests/set_lending_market_owner.rs b/token-lending/program/tests/set_lending_market_owner.rs index 8fdf9134e30..1a6302c091b 100644 --- a/token-lending/program/tests/set_lending_market_owner.rs +++ b/token-lending/program/tests/set_lending_market_owner.rs @@ -1,20 +1,23 @@ -#![cfg(feature = "test-bpf")] +#![allow(clippy::arithmetic_side_effects)] +#![cfg(feature = "test-sbf")] mod helpers; -use helpers::*; -use solana_program::instruction::{AccountMeta, Instruction}; -use solana_program_test::*; -use solana_sdk::{ - instruction::InstructionError, - pubkey::Pubkey, - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, -}; -use spl_token_lending::{ - error::LendingError, - instruction::{set_lending_market_owner, LendingInstruction}, - processor::process_instruction, +use { + helpers::*, + solana_program::instruction::{AccountMeta, Instruction}, + solana_program_test::*, + solana_sdk::{ + instruction::InstructionError, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::{Transaction, TransactionError}, + }, + spl_token_lending::{ + error::LendingError, + instruction::{set_lending_market_owner, LendingInstruction}, + processor::process_instruction, + }, }; #[tokio::test] @@ -63,7 +66,7 @@ async fn test_invalid_owner() { ); let lending_market = add_lending_market(&mut test); - let (mut banks_client, payer, recent_blockhash) = test.start().await; + let (banks_client, payer, recent_blockhash) = test.start().await; let invalid_owner = Keypair::new(); let new_owner = Pubkey::new_unique(); @@ -101,7 +104,7 @@ async fn test_owner_not_signer() { ); let lending_market = add_lending_market(&mut test); - let (mut banks_client, payer, recent_blockhash) = test.start().await; + let (banks_client, payer, recent_blockhash) = test.start().await; let new_owner = Pubkey::new_unique(); let mut transaction = Transaction::new_with_payer( diff --git a/token-lending/program/tests/withdraw_obligation_collateral.rs b/token-lending/program/tests/withdraw_obligation_collateral.rs index dd8fb191333..bad6bb81130 100644 --- a/token-lending/program/tests/withdraw_obligation_collateral.rs +++ b/token-lending/program/tests/withdraw_obligation_collateral.rs @@ -1,21 +1,23 @@ -#![cfg(feature = "test-bpf")] +#![allow(clippy::arithmetic_side_effects)] +#![cfg(feature = "test-sbf")] mod helpers; -use helpers::*; -use solana_program_test::*; -use solana_sdk::{ - instruction::InstructionError, - signature::{Keypair, Signer}, - transaction::{Transaction, TransactionError}, +use { + helpers::*, + solana_program_test::*, + solana_sdk::{ + instruction::InstructionError, + signature::{Keypair, Signer}, + transaction::{Transaction, TransactionError}, + }, + spl_token_lending::{ + error::LendingError, + instruction::{refresh_obligation, withdraw_obligation_collateral}, + processor::process_instruction, + state::INITIAL_COLLATERAL_RATIO, + }, }; -use spl_token_lending::{ - error::LendingError, - instruction::{refresh_obligation, withdraw_obligation_collateral}, - processor::process_instruction, - state::INITIAL_COLLATERAL_RATIO, -}; -use std::u64; #[tokio::test] async fn test_withdraw_fixed_amount() { @@ -317,7 +319,7 @@ async fn test_withdraw_too_large() { }, ); - let (mut banks_client, payer, recent_blockhash) = test.start().await; + let (banks_client, payer, recent_blockhash) = test.start().await; let mut transaction = Transaction::new_with_payer( &[ diff --git a/token-metadata/README.md b/token-metadata/README.md new file mode 100644 index 00000000000..dc5a2bf8f62 --- /dev/null +++ b/token-metadata/README.md @@ -0,0 +1,2 @@ +NOTE: The token-metadat interface, program, and clients are now maintained at +[solana-program/token-metadata](https://github.com/solana-program/token-metadata). diff --git a/token-swap/README.md b/token-swap/README.md index bf1b9c5661d..c78affb358f 100644 --- a/token-swap/README.md +++ b/token-swap/README.md @@ -6,33 +6,18 @@ Full documentation is available at https://spl.solana.com/token-swap JavaScript bindings are available in the `./js` directory. +## Audit + +The repository [README](https://github.com/solana-labs/solana-program-library#audits) +contains information about program audits. + ## Building master To build a development version of the Token Swap program, you can use the normal build command for Solana programs: ```sh -cargo build-bpf -``` - -## Building mainnet v2.0.0 - -For the version deployed to `SwaPpA9LAaLfeLi3a68M4DjnLqgtticKg6CnyNwgAC8`, -the Token Swap Program contains a `production` feature to fix constraints on fees -and fee account owner. A developer can deploy the program, allow others to create -pools, and earn a "protocol fee" on all activity. - -Since Solana programs cannot contain any modifiable state, we must hard-code -all constraints into the program. `SwapConstraints` in `program/src/constraints.rs` -contains all hard-coded fields for fees. Additionally the -`SWAP_PROGRAM_OWNER_FEE_ADDRESS` environment variable specifies the public key -that must own all fee accounts. - -You can build the production version of Token Swap running on devnet, testnet, and -mainnet-beta using the following command: - -```sh -SWAP_PROGRAM_OWNER_FEE_ADDRESS=HfoTxFR1Tm6kGmWgYWD6J7YHVy1UwqSULUGVLXkJqaKN cargo build-bpf --features=production +cargo build-sbf ``` ## Testing @@ -87,9 +72,3 @@ Then run all tests: ```sh npm run start-with-test-validator ``` - -If you are testing a production build, use: - -```sh -SWAP_PROGRAM_OWNER_FEE_ADDRESS="HfoTxFR1Tm6kGmWgYWD6J7YHVy1UwqSULUGVLXkJqaKN" npm run start-with-test-validator -``` diff --git a/token-swap/js/.eslintignore b/token-swap/js/.eslintignore index 9b1c8b133c9..502167fa0b8 100644 --- a/token-swap/js/.eslintignore +++ b/token-swap/js/.eslintignore @@ -1 +1 @@ -/dist +/lib diff --git a/token-swap/js/.eslintrc b/token-swap/js/.eslintrc new file mode 100644 index 00000000000..5aef10a4729 --- /dev/null +++ b/token-swap/js/.eslintrc @@ -0,0 +1,34 @@ +{ + "root": true, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended", + "plugin:require-extensions/recommended" + ], + "parser": "@typescript-eslint/parser", + "plugins": [ + "@typescript-eslint", + "prettier", + "require-extensions" + ], + "rules": { + "@typescript-eslint/ban-ts-comment": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-empty-interface": "off", + "@typescript-eslint/consistent-type-imports": "error" + }, + "overrides": [ + { + "files": [ + "examples/**/*", + "test/**/*" + ], + "rules": { + "require-extensions/require-extensions": "off", + "require-extensions/require-index": "off" + } + } + ] +} diff --git a/token-swap/js/.eslintrc.js b/token-swap/js/.eslintrc.js deleted file mode 100644 index 4009315178c..00000000000 --- a/token-swap/js/.eslintrc.js +++ /dev/null @@ -1,55 +0,0 @@ -// eslint-disable-next-line -module.exports = { - // eslint-disable-line import/no-commonjs - env: { - browser: true, - es6: true, - node: true, - }, - extends: [ - 'eslint:recommended', - 'plugin:import/errors', - 'plugin:import/warnings', - ], - parserOptions: { - sourceType: 'module', - ecmaVersion: 8, - }, - rules: { - 'no-trailing-spaces': ['error'], - 'import/first': ['error'], - 'import/no-commonjs': ['error'], - 'import/order': [ - 'error', - { - groups: [ - ['internal', 'external', 'builtin'], - ['index', 'sibling', 'parent'], - ], - 'newlines-between': 'always', - }, - ], - indent: [ - 'error', - 2, - { - MemberExpression: 1, - SwitchCase: 1, - }, - ], - 'linebreak-style': ['error', 'unix'], - 'no-console': [0], - quotes: [ - 'error', - 'single', - {avoidEscape: true, allowTemplateLiterals: true}, - ], - 'require-await': ['error'], - semi: ['error', 'always'], - }, - settings: { - react: { - version: 'detect', - }, - }, -}; diff --git a/token-swap/js/.gitignore b/token-swap/js/.gitignore index 4ec71138b5b..89820915e6e 100644 --- a/token-swap/js/.gitignore +++ b/token-swap/js/.gitignore @@ -1,2 +1,2 @@ test-ledger/ -dist/ +lib/ diff --git a/token-swap/js/.mocharc.json b/token-swap/js/.mocharc.json new file mode 100644 index 00000000000..9a5bb4c43b3 --- /dev/null +++ b/token-swap/js/.mocharc.json @@ -0,0 +1,8 @@ +{ + "extension": ["ts"], + "node-option": [ + "experimental-specifier-resolution=node", + "loader=ts-node/esm" + ], + "timeout": 100000 +} diff --git a/token-swap/js/.prettierrc.yaml b/token-swap/js/.prettierrc.yaml index 8deef5dd96a..59f717fb8ca 100644 --- a/token-swap/js/.prettierrc.yaml +++ b/token-swap/js/.prettierrc.yaml @@ -1,6 +1,5 @@ arrowParens: "avoid" bracketSpacing: false -jsxBracketSameLine: false semi: true singleQuote: true tabWidth: 2 diff --git a/token-swap/js/package-lock.json b/token-swap/js/package-lock.json deleted file mode 100644 index a7693573293..00000000000 --- a/token-swap/js/package-lock.json +++ /dev/null @@ -1,6347 +0,0 @@ -{ - "name": "@solana/spl-token-swap", - "version": "0.2.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "@solana/spl-token-swap", - "version": "0.2.0", - "license": "MIT", - "dependencies": { - "@solana/buffer-layout": "^4.0.0", - "@solana/web3.js": "^1.42.0", - "bn.js": "^5.1.3" - }, - "devDependencies": { - "@solana/spl-token": "0.1.8", - "@types/bn.js": "^5.1.0", - "eslint": "^7.9.0", - "eslint-plugin-import": "^2.22.0", - "prettier": "^2.1.2", - "start-server-and-test": "^1.11.6", - "ts-node": "^10.0.0", - "typescript": "^4.2.4", - "typescript-esm": "^2.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/runtime": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", - "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==", - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@cspotcode/source-map-consumer": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", - "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", - "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-consumer": "0.8.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/@ethersproject/bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.6.0.tgz", - "integrity": "sha512-3hJPlYemb9V4VLfJF5BfN0+55vltPZSHU3QKUyP9M3Y2TcajbiRrz65UG+xVHOzBereB1b9mn7r12o177xgN7w==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/logger": "^5.6.0" - } - }, - "node_modules/@ethersproject/logger": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.6.0.tgz", - "integrity": "sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ] - }, - "node_modules/@ethersproject/sha2": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.6.0.tgz", - "integrity": "sha512-1tNWCPFLu1n3JM9t4/kytz35DkuF9MxqkGGEHNauEbaARdm2fafnOyw1s0tIQDPKF/7bkP1u3dbrmjpn5CelyA==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "hash.js": "1.1.7" - } - }, - "node_modules/@hapi/hoek": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz", - "integrity": "sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw==", - "dev": true - }, - "node_modules/@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", - "dev": true, - "dependencies": { - "@hapi/hoek": "^9.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@kristoferbaxter/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@kristoferbaxter/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-aPFon+UXJ0758piFg/sp0tKr67675UWR9ssa39gN0ynJAY5wDQ8u57H0Z0uaeu0z1gEvLnLF8T1/rLrCZ4gFIg==", - "dev": true - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@sideway/address": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.3.tgz", - "integrity": "sha512-8ncEUtmnTsMmL7z1YPB47kPUq7LpKWJNFPsRzHiIajGC5uXlWGn+AmkYPcHNl8S4tcEGx+cnORnNYaw2wvL+LQ==", - "dev": true, - "dependencies": { - "@hapi/hoek": "^9.0.0" - } - }, - "node_modules/@sideway/formula": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", - "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==", - "dev": true - }, - "node_modules/@sideway/pinpoint": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", - "dev": true - }, - "node_modules/@solana/buffer-layout": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.0.tgz", - "integrity": "sha512-lR0EMP2HC3+Mxwd4YcnZb0smnaDw7Bl2IQWZiTevRH5ZZBZn6VRWn3/92E3qdU4SSImJkA6IDHawOHAnx/qUvQ==", - "dependencies": { - "buffer": "~6.0.3" - }, - "engines": { - "node": ">=5.10" - } - }, - "node_modules/@solana/buffer-layout-utils": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz", - "integrity": "sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g==", - "dependencies": { - "@solana/buffer-layout": "^4.0.0", - "@solana/web3.js": "^1.32.0", - "bigint-buffer": "^1.1.5", - "bignumber.js": "^9.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@solana/spl-token": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.1.8.tgz", - "integrity": "sha512-LZmYCKcPQDtJgecvWOgT/cnoIQPWjdH+QVyzPcFvyDUiT0DiRjZaam4aqNUyvchLFhzgunv3d9xOoyE34ofdoQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.10.5", - "@solana/web3.js": "^1.21.0", - "bn.js": "^5.1.0", - "buffer": "6.0.3", - "buffer-layout": "^1.2.0", - "dotenv": "10.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@solana/web3.js": { - "version": "1.42.0", - "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.42.0.tgz", - "integrity": "sha512-QqGh5DWzrgsWRx4sCPDQIm3390b7buPR16tZI61slQaQwJ2ymrSXPQCe4PPTJEIlzGjCV3dkn2vpT2R32BfK2Q==", - "dependencies": { - "@babel/runtime": "^7.12.5", - "@ethersproject/sha2": "^5.5.0", - "@solana/buffer-layout": "^4.0.0", - "@solana/buffer-layout-utils": "^0.2.0", - "bn.js": "^5.0.0", - "borsh": "^0.7.0", - "bs58": "^4.0.1", - "buffer": "6.0.1", - "cross-fetch": "^3.1.4", - "fast-stable-stringify": "^1.0.0", - "jayson": "^3.4.4", - "js-sha3": "^0.8.0", - "rpc-websockets": "^7.4.2", - "secp256k1": "^4.0.2", - "superstruct": "^0.14.2", - "tweetnacl": "^1.0.0" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/@solana/web3.js/node_modules/buffer": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.1.tgz", - "integrity": "sha512-rVAXBwEcEoYtxnHSO5iWyhzV/O1WMtkUYWlfdLS7FjU4PnSJJHEfHXi/uHPI5EwltmOA794gN3bm3/pzuctWjQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", - "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", - "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", - "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", - "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", - "dev": true - }, - "node_modules/@types/bn.js": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.0.tgz", - "integrity": "sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.17.28", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", - "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", - "dev": true - }, - "node_modules/@types/lodash": { - "version": "4.14.179", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.179.tgz", - "integrity": "sha512-uwc1x90yCKqGcIOAT6DwOSuxnrAbpkdPsUOZtwrXb4D/6wZs+6qG7QnIawDuZWg0sWpxl+ltIKCaLoMlna678w==" - }, - "node_modules/@types/node": { - "version": "17.0.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", - "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==" - }, - "node_modules/@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" - }, - "node_modules/@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" - }, - "node_modules/@types/ws": { - "version": "7.4.7", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", - "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/array-includes": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.map": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.4.tgz", - "integrity": "sha512-Qds9QnX7A0qISY7JT5WuJO0NJPE9CMlC6JzHQfhpqAAQQzufVRoeH7EzUY5GcPTx72voG8LV/5eo+b8Qi8hmhA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "es-array-method-boxes-properly": "^1.0.0", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "dev": true, - "dependencies": { - "follow-redirects": "^1.14.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/base-x": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", - "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/bigint-buffer": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/bigint-buffer/-/bigint-buffer-1.1.5.tgz", - "integrity": "sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==", - "hasInstallScript": true, - "dependencies": { - "bindings": "^1.3.0" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/bignumber.js": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", - "integrity": "sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==", - "engines": { - "node": "*" - } - }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "node_modules/bn.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", - "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" - }, - "node_modules/borsh": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz", - "integrity": "sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==", - "dependencies": { - "bn.js": "^5.2.0", - "bs58": "^4.0.0", - "text-encoding-utf-8": "^1.0.2" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" - }, - "node_modules/bs58": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", - "dependencies": { - "base-x": "^3.0.2" - } - }, - "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/buffer-layout": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz", - "integrity": "sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==", - "dev": true, - "engines": { - "node": ">=4.5" - } - }, - "node_modules/bufferutil": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz", - "integrity": "sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==", - "hasInstallScript": true, - "optional": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/check-more-types": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", - "integrity": "sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA=", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/circular-json": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.9.tgz", - "integrity": "sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ==", - "deprecated": "CircularJSON is in maintenance only, flatted is its successor." - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/cross-fetch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", - "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", - "dependencies": { - "node-fetch": "2.6.7" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "dependencies": { - "object-keys": "^1.0.12" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/delay": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", - "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true - }, - "node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", - "dev": true - }, - "node_modules/es-get-iterator": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", - "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.0", - "has-symbols": "^1.0.1", - "is-arguments": "^1.1.0", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.5", - "isarray": "^2.0.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" - }, - "node_modules/es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", - "dependencies": { - "es6-promise": "^4.0.3" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "resolve": "^1.20.0" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", - "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "find-up": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.25.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", - "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.2", - "has": "^1.0.3", - "is-core-module": "^2.8.0", - "is-glob": "^4.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.5", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.12.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, - "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/event-stream": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", - "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", - "dev": true, - "dependencies": { - "duplexer": "~0.1.1", - "from": "~0", - "map-stream": "~0.1.0", - "pause-stream": "0.0.11", - "split": "0.3", - "stream-combiner": "~0.0.4", - "through": "~2.3.1" - } - }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/eyes": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", - "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", - "engines": { - "node": "> 0.1.90" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", - "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", - "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "node_modules/fast-stable-stringify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz", - "integrity": "sha1-XFVDRisiru79NtBbNOUceMuG0xM=" - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", - "dev": true - }, - "node_modules/follow-redirects": { - "version": "1.14.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", - "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", - "dev": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/isomorphic-ws": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", - "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", - "peerDependencies": { - "ws": "*" - } - }, - "node_modules/iterate-iterator": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.2.tgz", - "integrity": "sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/iterate-value": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", - "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", - "dev": true, - "dependencies": { - "es-get-iterator": "^1.0.2", - "iterate-iterator": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/jayson": { - "version": "3.6.6", - "resolved": "https://registry.npmjs.org/jayson/-/jayson-3.6.6.tgz", - "integrity": "sha512-f71uvrAWTtrwoww6MKcl9phQTC+56AopLyEenWvKVAIMz+q0oVGj6tenLZ7Z6UiPBkJtKLj4kt0tACllFQruGQ==", - "dependencies": { - "@types/connect": "^3.4.33", - "@types/express-serve-static-core": "^4.17.9", - "@types/lodash": "^4.14.159", - "@types/node": "^12.12.54", - "@types/ws": "^7.4.4", - "commander": "^2.20.3", - "delay": "^5.0.0", - "es6-promisify": "^5.0.0", - "eyes": "^0.1.8", - "isomorphic-ws": "^4.0.1", - "json-stringify-safe": "^5.0.1", - "JSONStream": "^1.3.5", - "lodash": "^4.17.20", - "uuid": "^8.3.2", - "ws": "^7.4.5" - }, - "bin": { - "jayson": "bin/jayson.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jayson/node_modules/@types/node": { - "version": "12.20.47", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.47.tgz", - "integrity": "sha512-BzcaRsnFuznzOItW1WpQrDHM7plAa7GIDMZ6b5pnMbkqEtM/6WCOhvZar39oeMQP79gwvFUWjjptE7/KGcNqFg==" - }, - "node_modules/joi": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.0.tgz", - "integrity": "sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw==", - "dev": true, - "dependencies": { - "@hapi/hoek": "^9.0.0", - "@hapi/topo": "^5.0.0", - "@sideway/address": "^4.1.3", - "@sideway/formula": "^3.0.0", - "@sideway/pinpoint": "^2.0.0" - } - }, - "node_modules/js-sha3": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", - "engines": [ - "node >= 0.2.0" - ] - }, - "node_modules/JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "dependencies": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - }, - "bin": { - "JSONStream": "bin.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/lazy-ass": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", - "integrity": "sha1-eZllXoZGwX8In90YfRUNMyTVRRM=", - "dev": true, - "engines": { - "node": "> 0.8" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", - "dev": true, - "dependencies": { - "sourcemap-codec": "^1.4.4" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/map-stream": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", - "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", - "dev": true - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "node_modules/mri": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.6.tgz", - "integrity": "sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node_modules/node-addon-api": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", - "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==" - }, - "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-gyp-build": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", - "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", - "dev": true, - "dependencies": { - "through": "~2.3" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", - "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/promise.allsettled": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.4.tgz", - "integrity": "sha512-o73CbvQh/OnPFShxHcHxk0baXR2a1m4ozb85ha0H14VEoi/EJJLa9mnPfEWJx9RjA9MLfhdjZ8I6HhWtBa64Ag==", - "dev": true, - "dependencies": { - "array.prototype.map": "^1.0.3", - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "get-intrinsic": "^1.0.2", - "iterate-value": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/ps-tree": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.2.0.tgz", - "integrity": "sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==", - "dev": true, - "dependencies": { - "event-stream": "=3.3.4" - }, - "bin": { - "ps-tree": "bin/ps-tree.js" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rpc-websockets": { - "version": "7.4.17", - "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-7.4.17.tgz", - "integrity": "sha512-eolVi/qlXS13viIUH9aqrde902wzSLAai0IjmOZSRefp5I3CSG/vCnD0c0fDSYCWuEyUoRL1BHQA8K1baEUyow==", - "dependencies": { - "@babel/runtime": "^7.11.2", - "circular-json": "^0.5.9", - "eventemitter3": "^4.0.7", - "uuid": "^8.3.0", - "ws": "^7.4.5" - }, - "funding": { - "type": "paypal", - "url": "https://paypal.me/kozjak" - }, - "optionalDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rxjs": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", - "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/secp256k1": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", - "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", - "hasInstallScript": true, - "dependencies": { - "elliptic": "^6.5.4", - "node-addon-api": "^2.0.0", - "node-gyp-build": "^4.2.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - }, - "node_modules/split": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", - "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", - "dev": true, - "dependencies": { - "through": "2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/start-server-and-test": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-1.14.0.tgz", - "integrity": "sha512-on5ELuxO2K0t8EmNj9MtVlFqwBMxfWOhu4U7uZD1xccVpFlOQKR93CSe0u98iQzfNxRyaNTb/CdadbNllplTsw==", - "dev": true, - "dependencies": { - "bluebird": "3.7.2", - "check-more-types": "2.24.0", - "debug": "4.3.2", - "execa": "5.1.1", - "lazy-ass": "1.6.0", - "ps-tree": "1.2.0", - "wait-on": "6.0.0" - }, - "bin": { - "server-test": "src/bin/start.js", - "start-server-and-test": "src/bin/start.js", - "start-test": "src/bin/start.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/start-server-and-test/node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/stream-combiner": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", - "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", - "dev": true, - "dependencies": { - "duplexer": "~0.1.1" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/superstruct": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.14.2.tgz", - "integrity": "sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==" - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/table": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", - "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", - "dev": true, - "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/text-encoding-utf-8": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", - "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==" - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" - }, - "node_modules/ts-node": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz", - "integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "0.7.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.0", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/ts-node/node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/tsconfig-paths": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.13.0.tgz", - "integrity": "sha512-nWuffZppoaYK0vQ1SQmkSsQzJoHA4s6uzdb2waRpD806x9yfq153AdVsWz4je2qZcW+pENrMQXbGQ3sMCkXuhw==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.0", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "node_modules/tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz", - "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/typescript-esm": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/typescript-esm/-/typescript-esm-2.0.0.tgz", - "integrity": "sha512-/dERe64gRgZ3pSzP6Lc2DNiCdVPz1+mVlbkV9cl9eDunAqfelZHRA8MRTqEJLK6u6Adc6Z8Yy1lQY4nWUIh/5A==", - "dev": true, - "dependencies": { - "@kristoferbaxter/estree-walker": "2.0.2", - "acorn": "8.1.0", - "fast-glob": "3.2.5", - "magic-string": "0.25.7", - "mri": "1.1.6", - "promise.allsettled": "1.0.4", - "typescript": "4.2.3" - }, - "bin": { - "tsc-esm": "dist/tsc-esm" - } - }, - "node_modules/typescript-esm/node_modules/acorn": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz", - "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/typescript-esm/node_modules/typescript": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", - "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/utf-8-validate": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.9.tgz", - "integrity": "sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q==", - "hasInstallScript": true, - "optional": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz", - "integrity": "sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA==", - "dev": true - }, - "node_modules/wait-on": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.0.tgz", - "integrity": "sha512-tnUJr9p5r+bEYXPUdRseolmz5XqJTTj98JgOsfBn7Oz2dxfE2g3zw1jE+Mo8lopM3j3et/Mq1yW7kKX6qw7RVw==", - "dev": true, - "dependencies": { - "axios": "^0.21.1", - "joi": "^17.4.0", - "lodash": "^4.17.21", - "minimist": "^1.2.5", - "rxjs": "^7.1.0" - }, - "bin": { - "wait-on": "bin/wait-on" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - } - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/runtime": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", - "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "@cspotcode/source-map-consumer": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", - "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", - "dev": true - }, - "@cspotcode/source-map-support": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", - "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", - "dev": true, - "requires": { - "@cspotcode/source-map-consumer": "0.8.0" - } - }, - "@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - } - }, - "@ethersproject/bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.6.0.tgz", - "integrity": "sha512-3hJPlYemb9V4VLfJF5BfN0+55vltPZSHU3QKUyP9M3Y2TcajbiRrz65UG+xVHOzBereB1b9mn7r12o177xgN7w==", - "requires": { - "@ethersproject/logger": "^5.6.0" - } - }, - "@ethersproject/logger": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.6.0.tgz", - "integrity": "sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg==" - }, - "@ethersproject/sha2": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.6.0.tgz", - "integrity": "sha512-1tNWCPFLu1n3JM9t4/kytz35DkuF9MxqkGGEHNauEbaARdm2fafnOyw1s0tIQDPKF/7bkP1u3dbrmjpn5CelyA==", - "requires": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "hash.js": "1.1.7" - } - }, - "@hapi/hoek": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz", - "integrity": "sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw==", - "dev": true - }, - "@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", - "dev": true, - "requires": { - "@hapi/hoek": "^9.0.0" - } - }, - "@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - } - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "@kristoferbaxter/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@kristoferbaxter/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-aPFon+UXJ0758piFg/sp0tKr67675UWR9ssa39gN0ynJAY5wDQ8u57H0Z0uaeu0z1gEvLnLF8T1/rLrCZ4gFIg==", - "dev": true - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@sideway/address": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.3.tgz", - "integrity": "sha512-8ncEUtmnTsMmL7z1YPB47kPUq7LpKWJNFPsRzHiIajGC5uXlWGn+AmkYPcHNl8S4tcEGx+cnORnNYaw2wvL+LQ==", - "dev": true, - "requires": { - "@hapi/hoek": "^9.0.0" - } - }, - "@sideway/formula": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", - "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==", - "dev": true - }, - "@sideway/pinpoint": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", - "dev": true - }, - "@solana/buffer-layout": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.0.tgz", - "integrity": "sha512-lR0EMP2HC3+Mxwd4YcnZb0smnaDw7Bl2IQWZiTevRH5ZZBZn6VRWn3/92E3qdU4SSImJkA6IDHawOHAnx/qUvQ==", - "requires": { - "buffer": "~6.0.3" - } - }, - "@solana/buffer-layout-utils": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz", - "integrity": "sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g==", - "requires": { - "@solana/buffer-layout": "^4.0.0", - "@solana/web3.js": "^1.32.0", - "bigint-buffer": "^1.1.5", - "bignumber.js": "^9.0.1" - } - }, - "@solana/spl-token": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.1.8.tgz", - "integrity": "sha512-LZmYCKcPQDtJgecvWOgT/cnoIQPWjdH+QVyzPcFvyDUiT0DiRjZaam4aqNUyvchLFhzgunv3d9xOoyE34ofdoQ==", - "dev": true, - "requires": { - "@babel/runtime": "^7.10.5", - "@solana/web3.js": "^1.21.0", - "bn.js": "^5.1.0", - "buffer": "6.0.3", - "buffer-layout": "^1.2.0", - "dotenv": "10.0.0" - } - }, - "@solana/web3.js": { - "version": "1.42.0", - "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.42.0.tgz", - "integrity": "sha512-QqGh5DWzrgsWRx4sCPDQIm3390b7buPR16tZI61slQaQwJ2ymrSXPQCe4PPTJEIlzGjCV3dkn2vpT2R32BfK2Q==", - "requires": { - "@babel/runtime": "^7.12.5", - "@ethersproject/sha2": "^5.5.0", - "@solana/buffer-layout": "^4.0.0", - "@solana/buffer-layout-utils": "^0.2.0", - "bn.js": "^5.0.0", - "borsh": "^0.7.0", - "bs58": "^4.0.1", - "buffer": "6.0.1", - "cross-fetch": "^3.1.4", - "fast-stable-stringify": "^1.0.0", - "jayson": "^3.4.4", - "js-sha3": "^0.8.0", - "rpc-websockets": "^7.4.2", - "secp256k1": "^4.0.2", - "superstruct": "^0.14.2", - "tweetnacl": "^1.0.0" - }, - "dependencies": { - "buffer": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.1.tgz", - "integrity": "sha512-rVAXBwEcEoYtxnHSO5iWyhzV/O1WMtkUYWlfdLS7FjU4PnSJJHEfHXi/uHPI5EwltmOA794gN3bm3/pzuctWjQ==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - } - } - }, - "@tsconfig/node10": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", - "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", - "dev": true - }, - "@tsconfig/node12": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", - "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", - "dev": true - }, - "@tsconfig/node14": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", - "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", - "dev": true - }, - "@tsconfig/node16": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", - "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", - "dev": true - }, - "@types/bn.js": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.0.tgz", - "integrity": "sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "requires": { - "@types/node": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.17.28", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", - "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", - "dev": true - }, - "@types/lodash": { - "version": "4.14.179", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.179.tgz", - "integrity": "sha512-uwc1x90yCKqGcIOAT6DwOSuxnrAbpkdPsUOZtwrXb4D/6wZs+6qG7QnIawDuZWg0sWpxl+ltIKCaLoMlna678w==" - }, - "@types/node": { - "version": "17.0.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", - "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==" - }, - "@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" - }, - "@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" - }, - "@types/ws": { - "version": "7.4.7", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", - "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", - "requires": { - "@types/node": "*" - } - }, - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "array-includes": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.7" - } - }, - "array.prototype.flat": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" - } - }, - "array.prototype.map": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.4.tgz", - "integrity": "sha512-Qds9QnX7A0qISY7JT5WuJO0NJPE9CMlC6JzHQfhpqAAQQzufVRoeH7EzUY5GcPTx72voG8LV/5eo+b8Qi8hmhA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "es-array-method-boxes-properly": "^1.0.0", - "is-string": "^1.0.7" - } - }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true - }, - "axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "dev": true, - "requires": { - "follow-redirects": "^1.14.0" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "base-x": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", - "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "bigint-buffer": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/bigint-buffer/-/bigint-buffer-1.1.5.tgz", - "integrity": "sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==", - "requires": { - "bindings": "^1.3.0" - } - }, - "bignumber.js": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", - "integrity": "sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==" - }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "requires": { - "file-uri-to-path": "1.0.0" - } - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "bn.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", - "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" - }, - "borsh": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz", - "integrity": "sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==", - "requires": { - "bn.js": "^5.2.0", - "bs58": "^4.0.0", - "text-encoding-utf-8": "^1.0.2" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" - }, - "bs58": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", - "requires": { - "base-x": "^3.0.2" - } - }, - "buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "buffer-layout": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz", - "integrity": "sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==", - "dev": true - }, - "bufferutil": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz", - "integrity": "sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==", - "optional": true, - "requires": { - "node-gyp-build": "^4.3.0" - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "check-more-types": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", - "integrity": "sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA=", - "dev": true - }, - "circular-json": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.9.tgz", - "integrity": "sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ==" - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "cross-fetch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", - "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", - "requires": { - "node-fetch": "2.6.7" - } - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "delay": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", - "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==" - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", - "dev": true - }, - "duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true - }, - "elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "requires": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } - }, - "es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } - }, - "es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", - "dev": true - }, - "es-get-iterator": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", - "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.0", - "has-symbols": "^1.0.1", - "is-arguments": "^1.1.0", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.5", - "isarray": "^2.0.5" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" - }, - "es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", - "requires": { - "es6-promise": "^4.0.3" - } - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", - "dev": true, - "requires": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - } - }, - "eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", - "dev": true, - "requires": { - "debug": "^3.2.7", - "resolve": "^1.20.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "eslint-module-utils": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", - "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", - "dev": true, - "requires": { - "debug": "^3.2.7", - "find-up": "^2.1.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "eslint-plugin-import": { - "version": "2.25.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", - "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", - "dev": true, - "requires": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.2", - "has": "^1.0.3", - "is-core-module": "^2.8.0", - "is-glob": "^4.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.5", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.12.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - }, - "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, - "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "event-stream": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", - "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", - "dev": true, - "requires": { - "duplexer": "~0.1.1", - "from": "~0", - "map-stream": "~0.1.0", - "pause-stream": "0.0.11", - "split": "0.3", - "stream-combiner": "~0.0.4", - "through": "~2.3.1" - } - }, - "eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "eyes": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", - "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-glob": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", - "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", - "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fast-stable-stringify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz", - "integrity": "sha1-XFVDRisiru79NtBbNOUceMuG0xM=" - }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", - "dev": true - }, - "follow-redirects": { - "version": "1.14.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", - "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==", - "dev": true - }, - "from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true - }, - "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "dev": true - }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "dev": true - }, - "is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "dev": true - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isomorphic-ws": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", - "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", - "requires": {} - }, - "iterate-iterator": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.2.tgz", - "integrity": "sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw==", - "dev": true - }, - "iterate-value": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", - "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", - "dev": true, - "requires": { - "es-get-iterator": "^1.0.2", - "iterate-iterator": "^1.0.1" - } - }, - "jayson": { - "version": "3.6.6", - "resolved": "https://registry.npmjs.org/jayson/-/jayson-3.6.6.tgz", - "integrity": "sha512-f71uvrAWTtrwoww6MKcl9phQTC+56AopLyEenWvKVAIMz+q0oVGj6tenLZ7Z6UiPBkJtKLj4kt0tACllFQruGQ==", - "requires": { - "@types/connect": "^3.4.33", - "@types/express-serve-static-core": "^4.17.9", - "@types/lodash": "^4.14.159", - "@types/node": "^12.12.54", - "@types/ws": "^7.4.4", - "commander": "^2.20.3", - "delay": "^5.0.0", - "es6-promisify": "^5.0.0", - "eyes": "^0.1.8", - "isomorphic-ws": "^4.0.1", - "json-stringify-safe": "^5.0.1", - "JSONStream": "^1.3.5", - "lodash": "^4.17.20", - "uuid": "^8.3.2", - "ws": "^7.4.5" - }, - "dependencies": { - "@types/node": { - "version": "12.20.47", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.47.tgz", - "integrity": "sha512-BzcaRsnFuznzOItW1WpQrDHM7plAa7GIDMZ6b5pnMbkqEtM/6WCOhvZar39oeMQP79gwvFUWjjptE7/KGcNqFg==" - } - } - }, - "joi": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.0.tgz", - "integrity": "sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw==", - "dev": true, - "requires": { - "@hapi/hoek": "^9.0.0", - "@hapi/topo": "^5.0.0", - "@sideway/address": "^4.1.3", - "@sideway/formula": "^3.0.0", - "@sideway/pinpoint": "^2.0.0" - } - }, - "js-sha3": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" - }, - "JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - } - }, - "lazy-ass": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", - "integrity": "sha1-eZllXoZGwX8In90YfRUNMyTVRRM=", - "dev": true - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", - "dev": true, - "requires": { - "sourcemap-codec": "^1.4.4" - } - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "map-stream": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", - "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", - "dev": true - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "mri": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.6.tgz", - "integrity": "sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node-addon-api": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", - "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==" - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "node-gyp-build": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", - "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==" - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } - }, - "object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", - "dev": true, - "requires": { - "through": "~2.3" - } - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "prettier": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", - "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", - "dev": true - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "promise.allsettled": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.4.tgz", - "integrity": "sha512-o73CbvQh/OnPFShxHcHxk0baXR2a1m4ozb85ha0H14VEoi/EJJLa9mnPfEWJx9RjA9MLfhdjZ8I6HhWtBa64Ag==", - "dev": true, - "requires": { - "array.prototype.map": "^1.0.3", - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "get-intrinsic": "^1.0.2", - "iterate-value": "^1.0.2" - } - }, - "ps-tree": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.2.0.tgz", - "integrity": "sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==", - "dev": true, - "requires": { - "event-stream": "=3.3.4" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true - }, - "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, - "requires": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "rpc-websockets": { - "version": "7.4.17", - "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-7.4.17.tgz", - "integrity": "sha512-eolVi/qlXS13viIUH9aqrde902wzSLAai0IjmOZSRefp5I3CSG/vCnD0c0fDSYCWuEyUoRL1BHQA8K1baEUyow==", - "requires": { - "@babel/runtime": "^7.11.2", - "bufferutil": "^4.0.1", - "circular-json": "^0.5.9", - "eventemitter3": "^4.0.7", - "utf-8-validate": "^5.0.2", - "uuid": "^8.3.0", - "ws": "^7.4.5" - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "rxjs": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", - "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", - "dev": true, - "requires": { - "tslib": "^2.1.0" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "secp256k1": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", - "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", - "requires": { - "elliptic": "^6.5.4", - "node-addon-api": "^2.0.0", - "node-gyp-build": "^4.2.0" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - } - }, - "sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - }, - "split": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", - "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", - "dev": true, - "requires": { - "through": "2" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "start-server-and-test": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-1.14.0.tgz", - "integrity": "sha512-on5ELuxO2K0t8EmNj9MtVlFqwBMxfWOhu4U7uZD1xccVpFlOQKR93CSe0u98iQzfNxRyaNTb/CdadbNllplTsw==", - "dev": true, - "requires": { - "bluebird": "3.7.2", - "check-more-types": "2.24.0", - "debug": "4.3.2", - "execa": "5.1.1", - "lazy-ass": "1.6.0", - "ps-tree": "1.2.0", - "wait-on": "6.0.0" - }, - "dependencies": { - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - } - } - }, - "stream-combiner": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", - "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", - "dev": true, - "requires": { - "duplexer": "~0.1.1" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "superstruct": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.14.2.tgz", - "integrity": "sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "table": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", - "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", - "dev": true, - "requires": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } - } - }, - "text-encoding-utf-8": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", - "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==" - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" - }, - "ts-node": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz", - "integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==", - "dev": true, - "requires": { - "@cspotcode/source-map-support": "0.7.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.0", - "yn": "3.1.1" - }, - "dependencies": { - "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "dev": true - } - } - }, - "tsconfig-paths": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.13.0.tgz", - "integrity": "sha512-nWuffZppoaYK0vQ1SQmkSsQzJoHA4s6uzdb2waRpD806x9yfq153AdVsWz4je2qZcW+pENrMQXbGQ3sMCkXuhw==", - "dev": true, - "requires": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.0", - "strip-bom": "^3.0.0" - } - }, - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "typescript": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz", - "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==", - "dev": true - }, - "typescript-esm": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/typescript-esm/-/typescript-esm-2.0.0.tgz", - "integrity": "sha512-/dERe64gRgZ3pSzP6Lc2DNiCdVPz1+mVlbkV9cl9eDunAqfelZHRA8MRTqEJLK6u6Adc6Z8Yy1lQY4nWUIh/5A==", - "dev": true, - "requires": { - "@kristoferbaxter/estree-walker": "2.0.2", - "acorn": "8.1.0", - "fast-glob": "3.2.5", - "magic-string": "0.25.7", - "mri": "1.1.6", - "promise.allsettled": "1.0.4", - "typescript": "4.2.3" - }, - "dependencies": { - "acorn": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz", - "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==", - "dev": true - }, - "typescript": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", - "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", - "dev": true - } - } - }, - "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "utf-8-validate": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.9.tgz", - "integrity": "sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q==", - "optional": true, - "requires": { - "node-gyp-build": "^4.3.0" - } - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "v8-compile-cache-lib": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz", - "integrity": "sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA==", - "dev": true - }, - "wait-on": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.0.tgz", - "integrity": "sha512-tnUJr9p5r+bEYXPUdRseolmz5XqJTTj98JgOsfBn7Oz2dxfE2g3zw1jE+Mo8lopM3j3et/Mq1yW7kKX6qw7RVw==", - "dev": true, - "requires": { - "axios": "^0.21.1", - "joi": "^17.4.0", - "lodash": "^4.17.21", - "minimist": "^1.2.5", - "rxjs": "^7.1.0" - } - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", - "requires": {} - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true - } - } -} diff --git a/token-swap/js/package.json b/token-swap/js/package.json index 2d1e7d8337a..9c80d5dfc68 100644 --- a/token-swap/js/package.json +++ b/token-swap/js/package.json @@ -1,9 +1,10 @@ { "name": "@solana/spl-token-swap", - "version": "0.2.0", + "version": "0.4.4", "description": "SPL Token Swap JavaScript API", "license": "MIT", - "author": "Solana Maintainers ", + "type": "module", + "author": "Solana Labs Maintainers ", "homepage": "https://solana.com/", "repository": { "type": "git", @@ -15,45 +16,53 @@ "publishConfig": { "access": "public" }, - "main": "dist/cjs/index.js", - "types": "dist/types/index.d.ts", - "module": "dist/esm/index.js", + "main": "lib/cjs/index.js", + "types": "lib/types/index.d.ts", + "module": "lib/esm/index.js", "sideEffects": false, "exports": { - "import": "./dist/esm/index.js", - "require": "./dist/cjs/index.js" + "types": "./lib/types/index.d.ts", + "import": "./lib/esm/index.js", + "require": "./lib/cjs/index.js" }, "files": [ - "dist", + "lib", "src", "README.md" ], "scripts": { - "build": "tsc -p tsconfig.json && tsc-esm -p tsconfig.json && tsc -p tsconfig.cjs.json", - "postbuild": "echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json && echo '{\"type\":\"module\"}' > dist/esm/package.json", - "test": "ts-node test/main.ts", - "start-with-test-validator": "start-server-and-test 'solana-test-validator --bpf-program SwapsVeCiPHMUAtzQWZw7RjsKjgCjhwU55QGu4U1Szw ../../target/deploy/spl_token_swap.so --reset --quiet' http://localhost:8899/health test", - "lint": "npm run pretty && eslint --max-warnings 0 .", - "lint:fix": "npm run pretty:fix && eslint . --fix", - "build:program": "cargo build-bpf --manifest-path ../program/Cargo.toml", - "pretty": "prettier --check '{,???/**/}*.ts'", - "pretty:fix": "prettier --write '{,???/**/}*.ts'" + "clean": "rm -rf lib/*", + "build": "tsc --build --verbose tsconfig.all.json", + "postbuild": "echo '{\"type\":\"commonjs\"}' > lib/cjs/package.json && echo '{\"type\":\"module\"}' > lib/esm/package.json", + "build:program": "cargo build-sbf --manifest-path=../program/Cargo.toml", + "test:js": "mocha test", + "test": "start-server-and-test 'solana-test-validator --bpf-program SwapsVeCiPHMUAtzQWZw7RjsKjgCjhwU55QGu4U1Szw ../../target/deploy/spl_token_swap.so --reset --quiet' http://127.0.0.1:8899/health test:js", + "lint": "eslint --max-warnings 0 .", + "lint:fix": "eslint . --fix" }, "keywords": [], "dependencies": { - "bn.js": "^5.1.3", - "@solana/web3.js": "^1.42.0", - "@solana/buffer-layout": "^4.0.0" + "@solana/buffer-layout": "^4.0.0", + "@solana/buffer-layout-utils": "^0.2.0" + }, + "peerDependencies": { + "@solana/web3.js": "^1.95.5" }, "devDependencies": { - "@solana/spl-token": "0.1.8", - "@types/bn.js": "^5.1.0", - "eslint": "^7.9.0", - "eslint-plugin-import": "^2.22.0", - "prettier": "^2.1.2", - "start-server-and-test": "^1.11.6", - "ts-node": "^10.0.0", - "typescript": "^4.2.4", - "typescript-esm": "^2.0.0" + "@solana/spl-token": "0.4.9", + "@solana/web3.js": "^1.95.5", + "@types/bn.js": "^5.1.6", + "@types/chai-as-promised": "^8.0.1", + "@types/chai": "^5.0.1", + "@types/mocha": "^10.0.10", + "@typescript-eslint/eslint-plugin": "^8.4.0", + "@typescript-eslint/parser": "^8.4.0", + "eslint": "^8.57.0", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-require-extensions": "^0.1.1", + "mocha": "^11.0.1", + "start-server-and-test": "^2.0.9", + "ts-node": "^10.9.2", + "typescript": "^5.7.2" } } diff --git a/token-swap/js/src/buffer-layout.d.ts b/token-swap/js/src/buffer-layout.d.ts deleted file mode 100644 index 7bdc850c7fe..00000000000 --- a/token-swap/js/src/buffer-layout.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module '@solana/buffer-layout'; diff --git a/token-swap/js/src/index.ts b/token-swap/js/src/index.ts index 8a8a1bac70d..7d286af1ebd 100644 --- a/token-swap/js/src/index.ts +++ b/token-swap/js/src/index.ts @@ -1,23 +1,20 @@ -import assert from 'assert'; -import BN from 'bn.js'; import {Buffer} from 'buffer'; -import * as BufferLayout from '@solana/buffer-layout'; +import {struct, u8, blob} from '@solana/buffer-layout'; import type { ConfirmOptions, Connection, + Keypair, TransactionSignature, } from '@solana/web3.js'; import { - Account, PublicKey, SystemProgram, Transaction, TransactionInstruction, sendAndConfirmTransaction, } from '@solana/web3.js'; - -import * as Layout from './layout'; -import {loadAccount} from './util/account'; +import {u64, publicKey} from '@solana/buffer-layout-utils'; +import {loadAccount} from './util/account.js'; export const TOKEN_SWAP_PROGRAM_ID: PublicKey = new PublicKey( 'SwapsVeCiPHMUAtzQWZw7RjsKjgCjhwU55QGu4U1Szw', @@ -27,68 +24,102 @@ export const OLD_TOKEN_SWAP_PROGRAM_ID: PublicKey = new PublicKey( 'SwaPpA9LAaLfeLi3a68M4DjnLqgtticKg6CnyNwgAC8', ); -/** - * Some amount of tokens - */ -export class Numberu64 extends BN { - /** - * Convert to Buffer representation - */ - toBuffer(): Buffer { - const a = super.toArray().reverse(); - const b = Buffer.from(a); - if (b.length === 8) { - return b; - } - assert(b.length < 8, 'Numberu64 too large'); +export interface RawTokenSwap { + version: number; + isInitialized: boolean; + bumpSeed: number; + poolTokenProgramId: PublicKey; + tokenAccountA: PublicKey; + tokenAccountB: PublicKey; + tokenPool: PublicKey; + mintA: PublicKey; + mintB: PublicKey; + feeAccount: PublicKey; + tradeFeeNumerator: bigint; + tradeFeeDenominator: bigint; + ownerTradeFeeNumerator: bigint; + ownerTradeFeeDenominator: bigint; + ownerWithdrawFeeNumerator: bigint; + ownerWithdrawFeeDenominator: bigint; + hostFeeNumerator: bigint; + hostFeeDenominator: bigint; + curveType: number; + curveParameters: Uint8Array; +} - const zeroPad = Buffer.alloc(8); - b.copy(zeroPad); - return zeroPad; - } +export const TokenSwapLayout = struct([ + u8('version'), + u8('isInitialized'), + u8('bumpSeed'), + publicKey('poolTokenProgramId'), + publicKey('tokenAccountA'), + publicKey('tokenAccountB'), + publicKey('tokenPool'), + publicKey('mintA'), + publicKey('mintB'), + publicKey('feeAccount'), + u64('tradeFeeNumerator'), + u64('tradeFeeDenominator'), + u64('ownerTradeFeeNumerator'), + u64('ownerTradeFeeDenominator'), + u64('ownerWithdrawFeeNumerator'), + u64('ownerWithdrawFeeDenominator'), + u64('hostFeeNumerator'), + u64('hostFeeDenominator'), + u8('curveType'), + blob(32, 'curveParameters'), +]); - /** - * Construct a Numberu64 from Buffer representation - */ - static fromBuffer(buffer: Buffer): Numberu64 { - assert(buffer.length === 8, `Invalid buffer length: ${buffer.length}`); - return new Numberu64( - [...buffer] - .reverse() - .map(i => `00${i.toString(16)}`.slice(-2)) - .join(''), - 16, - ); - } +export interface CreateInstruction { + instruction: number; + tradeFeeNumerator: bigint; + tradeFeeDenominator: bigint; + ownerTradeFeeNumerator: bigint; + ownerTradeFeeDenominator: bigint; + ownerWithdrawFeeNumerator: bigint; + ownerWithdrawFeeDenominator: bigint; + hostFeeNumerator: bigint; + hostFeeDenominator: bigint; + curveType: number; + curveParameters: Uint8Array; } -export const TokenSwapLayout = BufferLayout.struct([ - BufferLayout.u8('version'), - BufferLayout.u8('isInitialized'), - BufferLayout.u8('bumpSeed'), - Layout.publicKey('tokenProgramId'), - Layout.publicKey('tokenAccountA'), - Layout.publicKey('tokenAccountB'), - Layout.publicKey('tokenPool'), - Layout.publicKey('mintA'), - Layout.publicKey('mintB'), - Layout.publicKey('feeAccount'), - Layout.uint64('tradeFeeNumerator'), - Layout.uint64('tradeFeeDenominator'), - Layout.uint64('ownerTradeFeeNumerator'), - Layout.uint64('ownerTradeFeeDenominator'), - Layout.uint64('ownerWithdrawFeeNumerator'), - Layout.uint64('ownerWithdrawFeeDenominator'), - Layout.uint64('hostFeeNumerator'), - Layout.uint64('hostFeeDenominator'), - BufferLayout.u8('curveType'), - BufferLayout.blob(32, 'curveParameters'), -]); +export interface SwapInstruction { + instruction: number; + amountIn: bigint; + minimumAmountOut: bigint; +} + +export interface DepositAllInstruction { + instruction: number; + poolTokenAmount: bigint; + maximumTokenA: bigint; + maximumTokenB: bigint; +} + +export interface WithdrawAllInstruction { + instruction: number; + poolTokenAmount: bigint; + minimumTokenA: bigint; + minimumTokenB: bigint; +} + +export interface DepositSingleTokenTypeInstruction { + instruction: number; + sourceTokenAmount: bigint; + minimumPoolTokenAmount: bigint; +} + +export interface WithdrawSingleTokenTypeInstruction { + instruction: number; + destinationTokenAmount: bigint; + maximumPoolTokenAmount: bigint; +} export const CurveType = Object.freeze({ ConstantProduct: 0, // Constant product curve, Uniswap-style ConstantPrice: 1, // Constant price curve, always X amount of A token for 1 B token, where X is defined at init - Offset: 3, // Offset curve, like Uniswap, but with an additional offset on the token B side + Offset: 2, // Offset curve, like Uniswap, but with an additional offset on the token B side }); /** @@ -101,7 +132,7 @@ export class TokenSwap { * @param connection The connection to use * @param tokenSwap The token swap account * @param swapProgramId The program ID of the token-swap program - * @param tokenProgramId The program ID of the token program + * @param poolTokenProgramId The program ID of the token program for the pool tokens * @param poolToken The pool token * @param authority The authority over the swap and accounts * @param tokenAccountA The token swap's Token A account @@ -123,7 +154,7 @@ export class TokenSwap { private connection: Connection, public tokenSwap: PublicKey, public swapProgramId: PublicKey, - public tokenProgramId: PublicKey, + public poolTokenProgramId: PublicKey, public poolToken: PublicKey, public feeAccount: PublicKey, public authority: PublicKey, @@ -131,21 +162,21 @@ export class TokenSwap { public tokenAccountB: PublicKey, public mintA: PublicKey, public mintB: PublicKey, - public tradeFeeNumerator: Numberu64, - public tradeFeeDenominator: Numberu64, - public ownerTradeFeeNumerator: Numberu64, - public ownerTradeFeeDenominator: Numberu64, - public ownerWithdrawFeeNumerator: Numberu64, - public ownerWithdrawFeeDenominator: Numberu64, - public hostFeeNumerator: Numberu64, - public hostFeeDenominator: Numberu64, + public tradeFeeNumerator: bigint, + public tradeFeeDenominator: bigint, + public ownerTradeFeeNumerator: bigint, + public ownerTradeFeeDenominator: bigint, + public ownerWithdrawFeeNumerator: bigint, + public ownerWithdrawFeeDenominator: bigint, + public hostFeeNumerator: bigint, + public hostFeeDenominator: bigint, public curveType: number, - public payer: Account, + public payer: Keypair, ) { this.connection = connection; this.tokenSwap = tokenSwap; this.swapProgramId = swapProgramId; - this.tokenProgramId = tokenProgramId; + this.poolTokenProgramId = poolTokenProgramId; this.poolToken = poolToken; this.feeAccount = feeAccount; this.authority = authority; @@ -179,25 +210,25 @@ export class TokenSwap { } static createInitSwapInstruction( - tokenSwapAccount: Account, + tokenSwapAccount: Keypair, authority: PublicKey, tokenAccountA: PublicKey, tokenAccountB: PublicKey, tokenPool: PublicKey, feeAccount: PublicKey, tokenAccountPool: PublicKey, - tokenProgramId: PublicKey, + poolTokenProgramId: PublicKey, swapProgramId: PublicKey, - tradeFeeNumerator: number, - tradeFeeDenominator: number, - ownerTradeFeeNumerator: number, - ownerTradeFeeDenominator: number, - ownerWithdrawFeeNumerator: number, - ownerWithdrawFeeDenominator: number, - hostFeeNumerator: number, - hostFeeDenominator: number, + tradeFeeNumerator: bigint, + tradeFeeDenominator: bigint, + ownerTradeFeeNumerator: bigint, + ownerTradeFeeDenominator: bigint, + ownerWithdrawFeeNumerator: bigint, + ownerWithdrawFeeDenominator: bigint, + hostFeeNumerator: bigint, + hostFeeDenominator: bigint, curveType: number, - curveParameters: Numberu64 = new Numberu64(0), + curveParameters: Uint8Array = new Uint8Array(), ): TransactionInstruction { const keys = [ {pubkey: tokenSwapAccount.publicKey, isSigner: false, isWritable: true}, @@ -207,28 +238,28 @@ export class TokenSwap { {pubkey: tokenPool, isSigner: false, isWritable: true}, {pubkey: feeAccount, isSigner: false, isWritable: false}, {pubkey: tokenAccountPool, isSigner: false, isWritable: true}, - {pubkey: tokenProgramId, isSigner: false, isWritable: false}, + {pubkey: poolTokenProgramId, isSigner: false, isWritable: false}, ]; - const commandDataLayout = BufferLayout.struct([ - BufferLayout.u8('instruction'), - BufferLayout.nu64('tradeFeeNumerator'), - BufferLayout.nu64('tradeFeeDenominator'), - BufferLayout.nu64('ownerTradeFeeNumerator'), - BufferLayout.nu64('ownerTradeFeeDenominator'), - BufferLayout.nu64('ownerWithdrawFeeNumerator'), - BufferLayout.nu64('ownerWithdrawFeeDenominator'), - BufferLayout.nu64('hostFeeNumerator'), - BufferLayout.nu64('hostFeeDenominator'), - BufferLayout.u8('curveType'), - BufferLayout.blob(32, 'curveParameters'), + const commandDataLayout = struct([ + u8('instruction'), + u64('tradeFeeNumerator'), + u64('tradeFeeDenominator'), + u64('ownerTradeFeeNumerator'), + u64('ownerTradeFeeDenominator'), + u64('ownerWithdrawFeeNumerator'), + u64('ownerWithdrawFeeDenominator'), + u64('hostFeeNumerator'), + u64('hostFeeDenominator'), + u8('curveType'), + blob(32, 'curveParameters'), ]); let data = Buffer.alloc(1024); // package curve parameters // NOTE: currently assume all curves take a single parameter, u64 int // the remaining 24 of the 32 bytes available are filled with 0s - let curveParamsBuffer = Buffer.alloc(32); - curveParameters.toBuffer().copy(curveParamsBuffer); + const curveParamsBuffer = Buffer.alloc(32); + Buffer.from(curveParameters).copy(curveParamsBuffer); { const encodeLength = commandDataLayout.encode( @@ -260,7 +291,7 @@ export class TokenSwap { connection: Connection, address: PublicKey, programId: PublicKey, - payer: Account, + payer: Keypair, ): Promise { const data = await loadAccount(connection, address, programId); const tokenSwapData = TokenSwapLayout.decode(data); @@ -279,39 +310,14 @@ export class TokenSwap { const tokenAccountB = new PublicKey(tokenSwapData.tokenAccountB); const mintA = new PublicKey(tokenSwapData.mintA); const mintB = new PublicKey(tokenSwapData.mintB); - const tokenProgramId = new PublicKey(tokenSwapData.tokenProgramId); - - const tradeFeeNumerator = Numberu64.fromBuffer( - tokenSwapData.tradeFeeNumerator, - ); - const tradeFeeDenominator = Numberu64.fromBuffer( - tokenSwapData.tradeFeeDenominator, - ); - const ownerTradeFeeNumerator = Numberu64.fromBuffer( - tokenSwapData.ownerTradeFeeNumerator, - ); - const ownerTradeFeeDenominator = Numberu64.fromBuffer( - tokenSwapData.ownerTradeFeeDenominator, - ); - const ownerWithdrawFeeNumerator = Numberu64.fromBuffer( - tokenSwapData.ownerWithdrawFeeNumerator, - ); - const ownerWithdrawFeeDenominator = Numberu64.fromBuffer( - tokenSwapData.ownerWithdrawFeeDenominator, - ); - const hostFeeNumerator = Numberu64.fromBuffer( - tokenSwapData.hostFeeNumerator, - ); - const hostFeeDenominator = Numberu64.fromBuffer( - tokenSwapData.hostFeeDenominator, - ); + const poolTokenProgramId = new PublicKey(tokenSwapData.poolTokenProgramId); const curveType = tokenSwapData.curveType; return new TokenSwap( connection, address, programId, - tokenProgramId, + poolTokenProgramId, poolToken, feeAccount, authority, @@ -319,14 +325,14 @@ export class TokenSwap { tokenAccountB, mintA, mintB, - tradeFeeNumerator, - tradeFeeDenominator, - ownerTradeFeeNumerator, - ownerTradeFeeDenominator, - ownerWithdrawFeeNumerator, - ownerWithdrawFeeDenominator, - hostFeeNumerator, - hostFeeDenominator, + tokenSwapData.tradeFeeNumerator, + tokenSwapData.tradeFeeDenominator, + tokenSwapData.ownerTradeFeeNumerator, + tokenSwapData.ownerTradeFeeDenominator, + tokenSwapData.ownerWithdrawFeeNumerator, + tokenSwapData.ownerWithdrawFeeDenominator, + tokenSwapData.hostFeeNumerator, + tokenSwapData.hostFeeDenominator, curveType, payer, ); @@ -343,7 +349,7 @@ export class TokenSwap { * @param tokenAccountB: The token swap's Token B account * @param poolToken The pool token * @param tokenAccountPool The token swap's pool token account - * @param tokenProgramId The program ID of the token program + * @param poolTokenProgramId The program ID of the token program for pool tokens * @param swapProgramId The program ID of the token-swap program * @param feeNumerator Numerator of the fee ratio * @param feeDenominator Denominator of the fee ratio @@ -351,8 +357,8 @@ export class TokenSwap { */ static async createTokenSwap( connection: Connection, - payer: Account, - tokenSwapAccount: Account, + payer: Keypair, + tokenSwapAccount: Keypair, authority: PublicKey, tokenAccountA: PublicKey, tokenAccountB: PublicKey, @@ -362,25 +368,24 @@ export class TokenSwap { feeAccount: PublicKey, tokenAccountPool: PublicKey, swapProgramId: PublicKey, - tokenProgramId: PublicKey, - tradeFeeNumerator: number, - tradeFeeDenominator: number, - ownerTradeFeeNumerator: number, - ownerTradeFeeDenominator: number, - ownerWithdrawFeeNumerator: number, - ownerWithdrawFeeDenominator: number, - hostFeeNumerator: number, - hostFeeDenominator: number, + poolTokenProgramId: PublicKey, + tradeFeeNumerator: bigint, + tradeFeeDenominator: bigint, + ownerTradeFeeNumerator: bigint, + ownerTradeFeeDenominator: bigint, + ownerWithdrawFeeNumerator: bigint, + ownerWithdrawFeeDenominator: bigint, + hostFeeNumerator: bigint, + hostFeeDenominator: bigint, curveType: number, - curveParameters?: Numberu64, + curveParameters?: Uint8Array, confirmOptions?: ConfirmOptions, ): Promise { - let transaction; const tokenSwap = new TokenSwap( connection, tokenSwapAccount.publicKey, swapProgramId, - tokenProgramId, + poolTokenProgramId, poolToken, feeAccount, authority, @@ -388,23 +393,22 @@ export class TokenSwap { tokenAccountB, mintA, mintB, - new Numberu64(tradeFeeNumerator), - new Numberu64(tradeFeeDenominator), - new Numberu64(ownerTradeFeeNumerator), - new Numberu64(ownerTradeFeeDenominator), - new Numberu64(ownerWithdrawFeeNumerator), - new Numberu64(ownerWithdrawFeeDenominator), - new Numberu64(hostFeeNumerator), - new Numberu64(hostFeeDenominator), + tradeFeeNumerator, + tradeFeeDenominator, + ownerTradeFeeNumerator, + ownerTradeFeeDenominator, + ownerWithdrawFeeNumerator, + ownerWithdrawFeeDenominator, + hostFeeNumerator, + hostFeeDenominator, curveType, payer, ); // Allocate memory for the account - const balanceNeeded = await TokenSwap.getMinBalanceRentForExemptTokenSwap( - connection, - ); - transaction = new Transaction(); + const balanceNeeded = + await TokenSwap.getMinBalanceRentForExemptTokenSwap(connection); + const transaction = new Transaction(); transaction.add( SystemProgram.createAccount({ fromPubkey: payer.publicKey, @@ -423,7 +427,7 @@ export class TokenSwap { poolToken, feeAccount, tokenAccountPool, - tokenProgramId, + poolTokenProgramId, swapProgramId, tradeFeeNumerator, tradeFeeDenominator, @@ -455,6 +459,10 @@ export class TokenSwap { * @param poolSource Pool's source token account * @param poolDestination Pool's destination token account * @param userDestination User's destination token account + * @param sourceMint Mint for the source token + * @param destinationMint Mint for the destination token + * @param sourceTokenProgramId Program id for the source token + * @param destinationTokenProgramId Program id for the destination token * @param hostFeeAccount Host account to gather fees * @param userTransferAuthority Account delegated to transfer user's tokens * @param amountIn Amount to transfer from source account @@ -465,10 +473,14 @@ export class TokenSwap { poolSource: PublicKey, poolDestination: PublicKey, userDestination: PublicKey, + sourceMint: PublicKey, + destinationMint: PublicKey, + sourceTokenProgramId: PublicKey, + destinationTokenProgramId: PublicKey, hostFeeAccount: PublicKey | null, - userTransferAuthority: Account, - amountIn: number | Numberu64, - minimumAmountOut: number | Numberu64, + userTransferAuthority: Keypair, + amountIn: bigint, + minimumAmountOut: bigint, confirmOptions?: ConfirmOptions, ): Promise { return await sendAndConfirmTransaction( @@ -485,8 +497,12 @@ export class TokenSwap { this.poolToken, this.feeAccount, hostFeeAccount, + sourceMint, + destinationMint, this.swapProgramId, - this.tokenProgramId, + sourceTokenProgramId, + destinationTokenProgramId, + this.poolTokenProgramId, amountIn, minimumAmountOut, ), @@ -507,23 +523,27 @@ export class TokenSwap { poolMint: PublicKey, feeAccount: PublicKey, hostFeeAccount: PublicKey | null, + sourceMint: PublicKey, + destinationMint: PublicKey, swapProgramId: PublicKey, - tokenProgramId: PublicKey, - amountIn: number | Numberu64, - minimumAmountOut: number | Numberu64, + sourceTokenProgramId: PublicKey, + destinationTokenProgramId: PublicKey, + poolTokenProgramId: PublicKey, + amountIn: bigint, + minimumAmountOut: bigint, ): TransactionInstruction { - const dataLayout = BufferLayout.struct([ - BufferLayout.u8('instruction'), - Layout.uint64('amountIn'), - Layout.uint64('minimumAmountOut'), + const dataLayout = struct([ + u8('instruction'), + u64('amountIn'), + u64('minimumAmountOut'), ]); const data = Buffer.alloc(dataLayout.span); dataLayout.encode( { instruction: 1, // Swap instruction - amountIn: new Numberu64(amountIn).toBuffer(), - minimumAmountOut: new Numberu64(minimumAmountOut).toBuffer(), + amountIn, + minimumAmountOut, }, data, ); @@ -538,7 +558,11 @@ export class TokenSwap { {pubkey: userDestination, isSigner: false, isWritable: true}, {pubkey: poolMint, isSigner: false, isWritable: true}, {pubkey: feeAccount, isSigner: false, isWritable: true}, - {pubkey: tokenProgramId, isSigner: false, isWritable: false}, + {pubkey: sourceMint, isSigner: false, isWritable: false}, + {pubkey: destinationMint, isSigner: false, isWritable: false}, + {pubkey: sourceTokenProgramId, isSigner: false, isWritable: false}, + {pubkey: destinationTokenProgramId, isSigner: false, isWritable: false}, + {pubkey: poolTokenProgramId, isSigner: false, isWritable: false}, ]; if (hostFeeAccount !== null) { keys.push({pubkey: hostFeeAccount, isSigner: false, isWritable: true}); @@ -555,6 +579,8 @@ export class TokenSwap { * @param userAccountA User account for token A * @param userAccountB User account for token B * @param poolAccount User account for pool token + * @param tokenProgramIdA Program id for token A + * @param tokenProgramIdB Program id for token B * @param userTransferAuthority Account delegated to transfer user's tokens * @param poolTokenAmount Amount of pool tokens to mint * @param maximumTokenA The maximum amount of token A to deposit @@ -564,10 +590,12 @@ export class TokenSwap { userAccountA: PublicKey, userAccountB: PublicKey, poolAccount: PublicKey, - userTransferAuthority: Account, - poolTokenAmount: number | Numberu64, - maximumTokenA: number | Numberu64, - maximumTokenB: number | Numberu64, + tokenProgramIdA: PublicKey, + tokenProgramIdB: PublicKey, + userTransferAuthority: Keypair, + poolTokenAmount: bigint, + maximumTokenA: bigint, + maximumTokenB: bigint, confirmOptions?: ConfirmOptions, ): Promise { return await sendAndConfirmTransaction( @@ -583,8 +611,12 @@ export class TokenSwap { this.tokenAccountB, this.poolToken, poolAccount, + this.mintA, + this.mintB, this.swapProgramId, - this.tokenProgramId, + tokenProgramIdA, + tokenProgramIdB, + this.poolTokenProgramId, poolTokenAmount, maximumTokenA, maximumTokenB, @@ -605,26 +637,30 @@ export class TokenSwap { intoB: PublicKey, poolToken: PublicKey, poolAccount: PublicKey, + mintA: PublicKey, + mintB: PublicKey, swapProgramId: PublicKey, - tokenProgramId: PublicKey, - poolTokenAmount: number | Numberu64, - maximumTokenA: number | Numberu64, - maximumTokenB: number | Numberu64, + tokenProgramIdA: PublicKey, + tokenProgramIdB: PublicKey, + poolTokenProgramId: PublicKey, + poolTokenAmount: bigint, + maximumTokenA: bigint, + maximumTokenB: bigint, ): TransactionInstruction { - const dataLayout = BufferLayout.struct([ - BufferLayout.u8('instruction'), - Layout.uint64('poolTokenAmount'), - Layout.uint64('maximumTokenA'), - Layout.uint64('maximumTokenB'), + const dataLayout = struct([ + u8('instruction'), + u64('poolTokenAmount'), + u64('maximumTokenA'), + u64('maximumTokenB'), ]); const data = Buffer.alloc(dataLayout.span); dataLayout.encode( { instruction: 2, // Deposit instruction - poolTokenAmount: new Numberu64(poolTokenAmount).toBuffer(), - maximumTokenA: new Numberu64(maximumTokenA).toBuffer(), - maximumTokenB: new Numberu64(maximumTokenB).toBuffer(), + poolTokenAmount, + maximumTokenA, + maximumTokenB, }, data, ); @@ -639,7 +675,11 @@ export class TokenSwap { {pubkey: intoB, isSigner: false, isWritable: true}, {pubkey: poolToken, isSigner: false, isWritable: true}, {pubkey: poolAccount, isSigner: false, isWritable: true}, - {pubkey: tokenProgramId, isSigner: false, isWritable: false}, + {pubkey: mintA, isSigner: false, isWritable: false}, + {pubkey: mintB, isSigner: false, isWritable: false}, + {pubkey: tokenProgramIdA, isSigner: false, isWritable: false}, + {pubkey: tokenProgramIdB, isSigner: false, isWritable: false}, + {pubkey: poolTokenProgramId, isSigner: false, isWritable: false}, ]; return new TransactionInstruction({ keys, @@ -654,6 +694,8 @@ export class TokenSwap { * @param userAccountA User account for token A * @param userAccountB User account for token B * @param poolAccount User account for pool token + * @param tokenProgramIdA Program id for token A + * @param tokenProgramIdB Program id for token B * @param userTransferAuthority Account delegated to transfer user's tokens * @param poolTokenAmount Amount of pool tokens to burn * @param minimumTokenA The minimum amount of token A to withdraw @@ -663,10 +705,12 @@ export class TokenSwap { userAccountA: PublicKey, userAccountB: PublicKey, poolAccount: PublicKey, - userTransferAuthority: Account, - poolTokenAmount: number | Numberu64, - minimumTokenA: number | Numberu64, - minimumTokenB: number | Numberu64, + tokenProgramIdA: PublicKey, + tokenProgramIdB: PublicKey, + userTransferAuthority: Keypair, + poolTokenAmount: bigint, + minimumTokenA: bigint, + minimumTokenB: bigint, confirmOptions?: ConfirmOptions, ): Promise { return await sendAndConfirmTransaction( @@ -683,8 +727,12 @@ export class TokenSwap { this.tokenAccountB, userAccountA, userAccountB, + this.mintA, + this.mintB, this.swapProgramId, - this.tokenProgramId, + this.poolTokenProgramId, + tokenProgramIdA, + tokenProgramIdB, poolTokenAmount, minimumTokenA, minimumTokenB, @@ -706,26 +754,30 @@ export class TokenSwap { fromB: PublicKey, userAccountA: PublicKey, userAccountB: PublicKey, + mintA: PublicKey, + mintB: PublicKey, swapProgramId: PublicKey, - tokenProgramId: PublicKey, - poolTokenAmount: number | Numberu64, - minimumTokenA: number | Numberu64, - minimumTokenB: number | Numberu64, + poolTokenProgramId: PublicKey, + tokenProgramIdA: PublicKey, + tokenProgramIdB: PublicKey, + poolTokenAmount: bigint, + minimumTokenA: bigint, + minimumTokenB: bigint, ): TransactionInstruction { - const dataLayout = BufferLayout.struct([ - BufferLayout.u8('instruction'), - Layout.uint64('poolTokenAmount'), - Layout.uint64('minimumTokenA'), - Layout.uint64('minimumTokenB'), + const dataLayout = struct([ + u8('instruction'), + u64('poolTokenAmount'), + u64('minimumTokenA'), + u64('minimumTokenB'), ]); const data = Buffer.alloc(dataLayout.span); dataLayout.encode( { instruction: 3, // Withdraw instruction - poolTokenAmount: new Numberu64(poolTokenAmount).toBuffer(), - minimumTokenA: new Numberu64(minimumTokenA).toBuffer(), - minimumTokenB: new Numberu64(minimumTokenB).toBuffer(), + poolTokenAmount, + minimumTokenA, + minimumTokenB, }, data, ); @@ -741,7 +793,11 @@ export class TokenSwap { {pubkey: userAccountA, isSigner: false, isWritable: true}, {pubkey: userAccountB, isSigner: false, isWritable: true}, {pubkey: feeAccount, isSigner: false, isWritable: true}, - {pubkey: tokenProgramId, isSigner: false, isWritable: false}, + {pubkey: mintA, isSigner: false, isWritable: false}, + {pubkey: mintB, isSigner: false, isWritable: false}, + {pubkey: poolTokenProgramId, isSigner: false, isWritable: false}, + {pubkey: tokenProgramIdA, isSigner: false, isWritable: false}, + {pubkey: tokenProgramIdB, isSigner: false, isWritable: false}, ]; return new TransactionInstruction({ keys, @@ -754,6 +810,8 @@ export class TokenSwap { * Deposit one side of tokens into the pool * @param userAccount User account to deposit token A or B * @param poolAccount User account to receive pool tokens + * @param sourceMint Mint for the source token + * @param sourceTokenProgramId Program id for the source token * @param userTransferAuthority Account delegated to transfer user's tokens * @param sourceTokenAmount The amount of token A or B to deposit * @param minimumPoolTokenAmount Minimum amount of pool tokens to mint @@ -761,9 +819,11 @@ export class TokenSwap { async depositSingleTokenTypeExactAmountIn( userAccount: PublicKey, poolAccount: PublicKey, - userTransferAuthority: Account, - sourceTokenAmount: number | Numberu64, - minimumPoolTokenAmount: number | Numberu64, + sourceMint: PublicKey, + sourceTokenProgramId: PublicKey, + userTransferAuthority: Keypair, + sourceTokenAmount: bigint, + minimumPoolTokenAmount: bigint, confirmOptions?: ConfirmOptions, ): Promise { return await sendAndConfirmTransaction( @@ -778,8 +838,10 @@ export class TokenSwap { this.tokenAccountB, this.poolToken, poolAccount, + sourceMint, this.swapProgramId, - this.tokenProgramId, + sourceTokenProgramId, + this.poolTokenProgramId, sourceTokenAmount, minimumPoolTokenAmount, ), @@ -798,25 +860,25 @@ export class TokenSwap { intoB: PublicKey, poolToken: PublicKey, poolAccount: PublicKey, + sourceMint: PublicKey, swapProgramId: PublicKey, - tokenProgramId: PublicKey, - sourceTokenAmount: number | Numberu64, - minimumPoolTokenAmount: number | Numberu64, + sourceTokenProgramId: PublicKey, + poolTokenProgramId: PublicKey, + sourceTokenAmount: bigint, + minimumPoolTokenAmount: bigint, ): TransactionInstruction { - const dataLayout = BufferLayout.struct([ - BufferLayout.u8('instruction'), - Layout.uint64('sourceTokenAmount'), - Layout.uint64('minimumPoolTokenAmount'), + const dataLayout = struct([ + u8('instruction'), + u64('sourceTokenAmount'), + u64('minimumPoolTokenAmount'), ]); const data = Buffer.alloc(dataLayout.span); dataLayout.encode( { instruction: 4, // depositSingleTokenTypeExactAmountIn instruction - sourceTokenAmount: new Numberu64(sourceTokenAmount).toBuffer(), - minimumPoolTokenAmount: new Numberu64( - minimumPoolTokenAmount, - ).toBuffer(), + sourceTokenAmount, + minimumPoolTokenAmount, }, data, ); @@ -830,7 +892,9 @@ export class TokenSwap { {pubkey: intoB, isSigner: false, isWritable: true}, {pubkey: poolToken, isSigner: false, isWritable: true}, {pubkey: poolAccount, isSigner: false, isWritable: true}, - {pubkey: tokenProgramId, isSigner: false, isWritable: false}, + {pubkey: sourceMint, isSigner: false, isWritable: false}, + {pubkey: sourceTokenProgramId, isSigner: false, isWritable: false}, + {pubkey: poolTokenProgramId, isSigner: false, isWritable: false}, ]; return new TransactionInstruction({ keys, @@ -844,6 +908,8 @@ export class TokenSwap { * * @param userAccount User account to receive token A or B * @param poolAccount User account to burn pool token + * @param destinationMint Mint for the destination token + * @param destinationTokenProgramId Program id for the destination token * @param userTransferAuthority Account delegated to transfer user's tokens * @param destinationTokenAmount The amount of token A or B to withdraw * @param maximumPoolTokenAmount Maximum amount of pool tokens to burn @@ -851,9 +917,11 @@ export class TokenSwap { async withdrawSingleTokenTypeExactAmountOut( userAccount: PublicKey, poolAccount: PublicKey, - userTransferAuthority: Account, - destinationTokenAmount: number | Numberu64, - maximumPoolTokenAmount: number | Numberu64, + destinationMint: PublicKey, + destinationTokenProgramId: PublicKey, + userTransferAuthority: Keypair, + destinationTokenAmount: bigint, + maximumPoolTokenAmount: bigint, confirmOptions?: ConfirmOptions, ): Promise { return await sendAndConfirmTransaction( @@ -869,8 +937,10 @@ export class TokenSwap { this.tokenAccountA, this.tokenAccountB, userAccount, + destinationMint, this.swapProgramId, - this.tokenProgramId, + this.poolTokenProgramId, + destinationTokenProgramId, destinationTokenAmount, maximumPoolTokenAmount, ), @@ -890,27 +960,25 @@ export class TokenSwap { fromA: PublicKey, fromB: PublicKey, userAccount: PublicKey, + destinationMint: PublicKey, swapProgramId: PublicKey, - tokenProgramId: PublicKey, - destinationTokenAmount: number | Numberu64, - maximumPoolTokenAmount: number | Numberu64, + poolTokenProgramId: PublicKey, + destinationTokenProgramId: PublicKey, + destinationTokenAmount: bigint, + maximumPoolTokenAmount: bigint, ): TransactionInstruction { - const dataLayout = BufferLayout.struct([ - BufferLayout.u8('instruction'), - Layout.uint64('destinationTokenAmount'), - Layout.uint64('maximumPoolTokenAmount'), + const dataLayout = struct([ + u8('instruction'), + u64('destinationTokenAmount'), + u64('maximumPoolTokenAmount'), ]); const data = Buffer.alloc(dataLayout.span); dataLayout.encode( { instruction: 5, // withdrawSingleTokenTypeExactAmountOut instruction - destinationTokenAmount: new Numberu64( - destinationTokenAmount, - ).toBuffer(), - maximumPoolTokenAmount: new Numberu64( - maximumPoolTokenAmount, - ).toBuffer(), + destinationTokenAmount, + maximumPoolTokenAmount, }, data, ); @@ -925,7 +993,9 @@ export class TokenSwap { {pubkey: fromB, isSigner: false, isWritable: true}, {pubkey: userAccount, isSigner: false, isWritable: true}, {pubkey: feeAccount, isSigner: false, isWritable: true}, - {pubkey: tokenProgramId, isSigner: false, isWritable: false}, + {pubkey: destinationMint, isSigner: false, isWritable: false}, + {pubkey: poolTokenProgramId, isSigner: false, isWritable: false}, + {pubkey: destinationTokenProgramId, isSigner: false, isWritable: false}, ]; return new TransactionInstruction({ keys, diff --git a/token-swap/js/src/layout.ts b/token-swap/js/src/layout.ts deleted file mode 100644 index d753f783016..00000000000 --- a/token-swap/js/src/layout.ts +++ /dev/null @@ -1,45 +0,0 @@ -import * as BufferLayout from '@solana/buffer-layout'; - -/** - * Layout for a public key - */ -export const publicKey = (property: string = 'publicKey'): Object => { - return BufferLayout.blob(32, property); -}; - -/** - * Layout for a 64bit unsigned value - */ -export const uint64 = (property: string = 'uint64'): Object => { - return BufferLayout.blob(8, property); -}; - -/** - * Layout for a Rust String type - */ -export const rustString = (property: string = 'string'): Object => { - const rsl = BufferLayout.struct( - [ - BufferLayout.u32('length'), - BufferLayout.u32('lengthPadding'), - BufferLayout.blob(BufferLayout.offset(BufferLayout.u32(), -8), 'chars'), - ], - property, - ); - const _decode = rsl.decode.bind(rsl); - const _encode = rsl.encode.bind(rsl); - - rsl.decode = (buffer: Buffer, offset: number) => { - const data = _decode(buffer, offset); - return data.chars.toString('utf8'); - }; - - rsl.encode = (str: string, buffer: Buffer, offset: number) => { - const data = { - chars: Buffer.from(str, 'utf8'), - }; - return _encode(data, buffer, offset); - }; - - return rsl; -}; diff --git a/token-swap/js/src/util/account.ts b/token-swap/js/src/util/account.ts index 85741cd9293..2355c4f1367 100644 --- a/token-swap/js/src/util/account.ts +++ b/token-swap/js/src/util/account.ts @@ -1,5 +1,4 @@ -import type {Connection} from '@solana/web3.js'; -import {PublicKey} from '@solana/web3.js'; +import type {Connection, PublicKey} from '@solana/web3.js'; export async function loadAccount( connection: Connection, diff --git a/token-swap/js/src/util/new-account-with-lamports.ts b/token-swap/js/src/util/new-account-with-lamports.ts index cf7dcfd4a8b..caf5de7e677 100644 --- a/token-swap/js/src/util/new-account-with-lamports.ts +++ b/token-swap/js/src/util/new-account-with-lamports.ts @@ -1,12 +1,13 @@ -import {Account, Connection} from '@solana/web3.js'; +import type {Connection} from '@solana/web3.js'; +import {Keypair} from '@solana/web3.js'; -import {sleep} from './sleep'; +import {sleep} from './sleep.js'; export async function newAccountWithLamports( connection: Connection, lamports: number = 1000000, -): Promise { - const account = new Account(); +): Promise { + const account = Keypair.generate(); let retries = 30; await connection.requestAirdrop(account.publicKey, lamports); diff --git a/token-swap/js/src/util/new-system-account-with-airdrop.ts b/token-swap/js/src/util/new-system-account-with-airdrop.ts index f3587744904..9b41e7da247 100644 --- a/token-swap/js/src/util/new-system-account-with-airdrop.ts +++ b/token-swap/js/src/util/new-system-account-with-airdrop.ts @@ -1,4 +1,5 @@ -import {Account, Connection} from '@solana/web3.js'; +import type {Connection} from '@solana/web3.js'; +import {Account} from '@solana/web3.js'; /** * Create a new system account and airdrop it some lamports diff --git a/token-swap/js/test/main.test.ts b/token-swap/js/test/main.test.ts new file mode 100644 index 00000000000..e0967a1bb40 --- /dev/null +++ b/token-swap/js/test/main.test.ts @@ -0,0 +1,872 @@ +import { + Keypair, + Connection, + PublicKey, + SystemProgram, + Transaction, + sendAndConfirmTransaction, +} from '@solana/web3.js'; +import { + approve, + createMint, + createAccount, + createApproveInstruction, + createInitializeAccountInstruction, + getAccount, + getMint, + getMinimumBalanceForRentExemptAccount, + mintTo, + AccountLayout, + TOKEN_PROGRAM_ID, +} from '@solana/spl-token'; + +import {TokenSwap, CurveType, TOKEN_SWAP_PROGRAM_ID} from '../src'; +import {newAccountWithLamports} from '../src/util/new-account-with-lamports'; +import {sleep} from '../src/util/sleep'; + +describe('spl-token-swap instructions', () => { + it('executes properly', async () => { + // These test cases are designed to run sequentially and in the following order + console.log('Run test: createTokenSwap (constant price)'); + const constantPrice = new Uint8Array(8); + constantPrice[0] = 1; + await createTokenSwap(CurveType.ConstantPrice, constantPrice); + console.log( + 'Run test: createTokenSwap (constant product, used further in tests)', + ); + await createTokenSwap(CurveType.ConstantProduct); + console.log('Run test: deposit all token types'); + await depositAllTokenTypes(); + console.log('Run test: withdraw all token types'); + await withdrawAllTokenTypes(); + console.log('Run test: swap'); + await swap(); + console.log('Run test: create account, approve, swap all at once'); + await createAccountAndSwapAtomic(); + console.log('Run test: deposit one exact amount in'); + await depositSingleTokenTypeExactAmountIn(); + console.log('Run test: withdraw one exact amount out'); + await withdrawSingleTokenTypeExactAmountOut(); + console.log('Success\n'); + }); +}); + +// The following globals are created by `createTokenSwap` and used by subsequent tests +// Token swap +let tokenSwap: TokenSwap; +// authority of the token and accounts +let authority: PublicKey; +// bump seed used to generate the authority public key +let bumpSeed: number; +// owner of the user accounts +let owner: Keypair; +// payer for transactions +let payer: Keypair; +// Token pool +let tokenPool: PublicKey; +let tokenAccountPool: PublicKey; +let feeAccount: PublicKey; +// Tokens swapped +let mintA: PublicKey; +const mintAProgramId: PublicKey = TOKEN_PROGRAM_ID; +let mintB: PublicKey; +const mintBProgramId: PublicKey = TOKEN_PROGRAM_ID; +let tokenAccountA: PublicKey; +let tokenAccountB: PublicKey; + +// Hard-coded fee address, for testing production mode +const SWAP_PROGRAM_OWNER_FEE_ADDRESS = + process.env.SWAP_PROGRAM_OWNER_FEE_ADDRESS; + +// Pool fees +const TRADING_FEE_NUMERATOR = 25n; +const TRADING_FEE_DENOMINATOR = 10000n; +const OWNER_TRADING_FEE_NUMERATOR = 5n; +const OWNER_TRADING_FEE_DENOMINATOR = 10000n; +const OWNER_WITHDRAW_FEE_NUMERATOR = SWAP_PROGRAM_OWNER_FEE_ADDRESS ? 0n : 1n; +const OWNER_WITHDRAW_FEE_DENOMINATOR = SWAP_PROGRAM_OWNER_FEE_ADDRESS ? 0n : 6n; +const HOST_FEE_NUMERATOR = 20n; +const HOST_FEE_DENOMINATOR = 100n; + +// Initial amount in each swap token +let currentSwapTokenA = 1000000n; +let currentSwapTokenB = 1000000n; +let currentFeeAmount = 0n; + +// Swap instruction constants +// Because there is no withdraw fee in the production version, these numbers +// need to get slightly tweaked in the two cases. +const SWAP_AMOUNT_IN = 100000n; +const SWAP_AMOUNT_OUT = SWAP_PROGRAM_OWNER_FEE_ADDRESS ? 90661n : 90674n; +const SWAP_FEE = SWAP_PROGRAM_OWNER_FEE_ADDRESS ? 22727n : 22730n; +const HOST_SWAP_FEE = SWAP_PROGRAM_OWNER_FEE_ADDRESS + ? (SWAP_FEE * HOST_FEE_NUMERATOR) / HOST_FEE_DENOMINATOR + : 0n; +const OWNER_SWAP_FEE = SWAP_FEE - HOST_SWAP_FEE; + +// Pool token amount minted on init +const DEFAULT_POOL_TOKEN_AMOUNT = 1000000000n; +// Pool token amount to withdraw / deposit +const POOL_TOKEN_AMOUNT = 10000000n; + +function assert(condition: boolean, message?: string) { + if (!condition) { + console.log(Error().stack + ':token-test.js'); + throw message || 'Assertion failed'; + } +} + +let connection: Connection; +async function getConnection(): Promise { + if (connection) return connection; + + const url = 'http://127.0.0.1:8899'; + connection = new Connection(url, 'processed'); + const version = await connection.getVersion(); + + console.log('Connection to cluster established:', url, version); + return connection; +} + +export async function createTokenSwap( + curveType: number, + curveParameters?: Uint8Array, +): Promise { + const connection = await getConnection(); + payer = await newAccountWithLamports(connection, 1000000000); + owner = await newAccountWithLamports(connection, 1000000000); + const tokenSwapAccount = Keypair.generate(); + + [authority, bumpSeed] = await PublicKey.findProgramAddress( + [tokenSwapAccount.publicKey.toBuffer()], + TOKEN_SWAP_PROGRAM_ID, + ); + + console.log('creating pool mint'); + tokenPool = await createMint( + connection, + payer, + authority, + null, + 2, + Keypair.generate(), + undefined, + TOKEN_PROGRAM_ID, + ); + + console.log('creating pool account'); + tokenAccountPool = await createAccount( + connection, + payer, + tokenPool, + owner.publicKey, + Keypair.generate(), + ); + const ownerKey = SWAP_PROGRAM_OWNER_FEE_ADDRESS || owner.publicKey.toString(); + feeAccount = await createAccount( + connection, + payer, + tokenPool, + new PublicKey(ownerKey), + Keypair.generate(), + ); + + console.log('creating token A'); + mintA = await createMint( + connection, + payer, + owner.publicKey, + null, + 2, + Keypair.generate(), + undefined, + mintAProgramId, + ); + + console.log('creating token A account'); + tokenAccountA = await createAccount( + connection, + payer, + mintA, + authority, + Keypair.generate(), + ); + console.log('minting token A to swap'); + await mintTo( + connection, + payer, + mintA, + tokenAccountA, + owner, + currentSwapTokenA, + ); + + console.log('creating token B'); + mintB = await createMint( + connection, + payer, + owner.publicKey, + null, + 2, + Keypair.generate(), + undefined, + mintBProgramId, + ); + + console.log('creating token B account'); + tokenAccountB = await createAccount( + connection, + payer, + mintB, + authority, + Keypair.generate(), + ); + console.log('minting token B to swap'); + await mintTo( + connection, + payer, + mintB, + tokenAccountB, + owner, + currentSwapTokenB, + ); + + console.log('creating token swap'); + const swapPayer = await newAccountWithLamports(connection, 10000000000); + tokenSwap = await TokenSwap.createTokenSwap( + connection, + swapPayer, + tokenSwapAccount, + authority, + tokenAccountA, + tokenAccountB, + tokenPool, + mintA, + mintB, + feeAccount, + tokenAccountPool, + TOKEN_SWAP_PROGRAM_ID, + TOKEN_PROGRAM_ID, + TRADING_FEE_NUMERATOR, + TRADING_FEE_DENOMINATOR, + OWNER_TRADING_FEE_NUMERATOR, + OWNER_TRADING_FEE_DENOMINATOR, + OWNER_WITHDRAW_FEE_NUMERATOR, + OWNER_WITHDRAW_FEE_DENOMINATOR, + HOST_FEE_NUMERATOR, + HOST_FEE_DENOMINATOR, + curveType, + curveParameters, + ); + + console.log('loading token swap'); + const fetchedTokenSwap = await TokenSwap.loadTokenSwap( + connection, + tokenSwapAccount.publicKey, + TOKEN_SWAP_PROGRAM_ID, + swapPayer, + ); + + assert(fetchedTokenSwap.poolTokenProgramId.equals(TOKEN_PROGRAM_ID)); + assert(fetchedTokenSwap.tokenAccountA.equals(tokenAccountA)); + assert(fetchedTokenSwap.tokenAccountB.equals(tokenAccountB)); + assert(fetchedTokenSwap.mintA.equals(mintA)); + assert(fetchedTokenSwap.mintB.equals(mintB)); + assert(fetchedTokenSwap.poolToken.equals(tokenPool)); + assert(fetchedTokenSwap.feeAccount.equals(feeAccount)); + assert(TRADING_FEE_NUMERATOR == fetchedTokenSwap.tradeFeeNumerator); + assert(TRADING_FEE_DENOMINATOR == fetchedTokenSwap.tradeFeeDenominator); + assert( + OWNER_TRADING_FEE_NUMERATOR == fetchedTokenSwap.ownerTradeFeeNumerator, + ); + assert( + OWNER_TRADING_FEE_DENOMINATOR == fetchedTokenSwap.ownerTradeFeeDenominator, + ); + assert( + OWNER_WITHDRAW_FEE_NUMERATOR == fetchedTokenSwap.ownerWithdrawFeeNumerator, + ); + assert( + OWNER_WITHDRAW_FEE_DENOMINATOR == + fetchedTokenSwap.ownerWithdrawFeeDenominator, + ); + assert(HOST_FEE_NUMERATOR == fetchedTokenSwap.hostFeeNumerator); + assert(HOST_FEE_DENOMINATOR == fetchedTokenSwap.hostFeeDenominator); + assert(curveType == fetchedTokenSwap.curveType); +} + +export async function depositAllTokenTypes(): Promise { + const poolMintInfo = await getMint(connection, tokenPool); + const supply = poolMintInfo.supply; + const swapTokenA = await getAccount(connection, tokenAccountA); + const tokenA = (swapTokenA.amount * BigInt(POOL_TOKEN_AMOUNT)) / supply; + const swapTokenB = await getAccount(connection, tokenAccountB); + const tokenB = (swapTokenB.amount * BigInt(POOL_TOKEN_AMOUNT)) / supply; + + const userTransferAuthority = Keypair.generate(); + console.log('Creating depositor token a account'); + const userAccountA = await createAccount( + connection, + payer, + mintA, + owner.publicKey, + Keypair.generate(), + ); + await mintTo(connection, payer, mintA, userAccountA, owner, tokenA); + await approve( + connection, + payer, + userAccountA, + userTransferAuthority.publicKey, + owner, + tokenA, + ); + console.log('Creating depositor token b account'); + const userAccountB = await createAccount( + connection, + payer, + mintB, + owner.publicKey, + Keypair.generate(), + ); + await mintTo(connection, payer, mintB, userAccountB, owner, tokenB); + await approve( + connection, + payer, + userAccountB, + userTransferAuthority.publicKey, + owner, + tokenB, + ); + console.log('Creating depositor pool token account'); + const newAccountPool = await createAccount( + connection, + payer, + tokenPool, + owner.publicKey, + Keypair.generate(), + ); + + const confirmOptions = { + skipPreflight: true, + }; + + console.log('Depositing into swap'); + await tokenSwap.depositAllTokenTypes( + userAccountA, + userAccountB, + newAccountPool, + TOKEN_PROGRAM_ID, + TOKEN_PROGRAM_ID, + userTransferAuthority, + POOL_TOKEN_AMOUNT, + tokenA, + tokenB, + confirmOptions, + ); + + let info; + info = await getAccount(connection, userAccountA); + assert(info.amount == 0n); + info = await getAccount(connection, userAccountB); + assert(info.amount == 0n); + info = await getAccount(connection, tokenAccountA); + assert(info.amount == currentSwapTokenA + tokenA); + currentSwapTokenA += tokenA; + info = await getAccount(connection, tokenAccountB); + assert(info.amount == currentSwapTokenB + tokenB); + currentSwapTokenB += tokenB; + info = await getAccount(connection, newAccountPool); + assert(info.amount == POOL_TOKEN_AMOUNT); +} + +export async function withdrawAllTokenTypes(): Promise { + const poolMintInfo = await getMint(connection, tokenPool); + const supply = poolMintInfo.supply; + let swapTokenA = await getAccount(connection, tokenAccountA); + let swapTokenB = await getAccount(connection, tokenAccountB); + let feeAmount = 0n; + if (OWNER_WITHDRAW_FEE_NUMERATOR !== 0n) { + feeAmount = + (POOL_TOKEN_AMOUNT * OWNER_WITHDRAW_FEE_NUMERATOR) / + OWNER_WITHDRAW_FEE_DENOMINATOR; + } + const poolTokenAmount = POOL_TOKEN_AMOUNT - feeAmount; + const tokenA = (swapTokenA.amount * BigInt(poolTokenAmount)) / supply; + const tokenB = (swapTokenB.amount * BigInt(poolTokenAmount)) / supply; + + console.log('Creating withdraw token A account'); + const userAccountA = await createAccount( + connection, + payer, + mintA, + owner.publicKey, + Keypair.generate(), + ); + console.log('Creating withdraw token B account'); + const userAccountB = await createAccount( + connection, + payer, + mintB, + owner.publicKey, + Keypair.generate(), + ); + + const userTransferAuthority = Keypair.generate(); + console.log('Approving withdrawal from pool account'); + await approve( + connection, + payer, + tokenAccountPool, + userTransferAuthority.publicKey, + owner, + POOL_TOKEN_AMOUNT, + ); + + const confirmOptions = { + skipPreflight: true, + }; + + console.log('Withdrawing pool tokens for A and B tokens'); + await tokenSwap.withdrawAllTokenTypes( + userAccountA, + userAccountB, + tokenAccountPool, + TOKEN_PROGRAM_ID, + TOKEN_PROGRAM_ID, + userTransferAuthority, + POOL_TOKEN_AMOUNT, + tokenA, + tokenB, + confirmOptions, + ); + + //const poolMintInfo = await tokenPool.getMintInfo(); + swapTokenA = await getAccount(connection, tokenAccountA); + swapTokenB = await getAccount(connection, tokenAccountB); + + let info = await getAccount(connection, tokenAccountPool); + assert(info.amount == DEFAULT_POOL_TOKEN_AMOUNT - POOL_TOKEN_AMOUNT); + assert(swapTokenA.amount == currentSwapTokenA - tokenA); + currentSwapTokenA -= tokenA; + assert(swapTokenB.amount == currentSwapTokenB - tokenB); + currentSwapTokenB -= tokenB; + info = await getAccount(connection, userAccountA); + assert(info.amount == tokenA); + info = await getAccount(connection, userAccountB); + assert(info.amount == tokenB); + info = await getAccount(connection, feeAccount); + assert(info.amount == feeAmount); + currentFeeAmount = feeAmount; +} + +export async function createAccountAndSwapAtomic(): Promise { + console.log('Creating swap token a account'); + const userAccountA = await createAccount( + connection, + payer, + mintA, + owner.publicKey, + Keypair.generate(), + ); + await mintTo(connection, payer, mintA, userAccountA, owner, SWAP_AMOUNT_IN); + + // @ts-ignore + const balanceNeeded = await getMinimumBalanceForRentExemptAccount(connection); + const newAccount = Keypair.generate(); + const transaction = new Transaction(); + transaction.add( + SystemProgram.createAccount({ + fromPubkey: owner.publicKey, + newAccountPubkey: newAccount.publicKey, + lamports: balanceNeeded, + space: AccountLayout.span, + programId: mintBProgramId, + }), + ); + + transaction.add( + createInitializeAccountInstruction( + newAccount.publicKey, + mintB, + owner.publicKey, + mintBProgramId, + ), + ); + + const userTransferAuthority = Keypair.generate(); + transaction.add( + createApproveInstruction( + userAccountA, + userTransferAuthority.publicKey, + owner.publicKey, + SWAP_AMOUNT_IN, + [], + mintAProgramId, + ), + ); + + transaction.add( + TokenSwap.swapInstruction( + tokenSwap.tokenSwap, + tokenSwap.authority, + userTransferAuthority.publicKey, + userAccountA, + tokenSwap.tokenAccountA, + tokenSwap.tokenAccountB, + newAccount.publicKey, + tokenSwap.poolToken, + tokenSwap.feeAccount, + null, + tokenSwap.mintA, + tokenSwap.mintB, + tokenSwap.swapProgramId, + TOKEN_PROGRAM_ID, + TOKEN_PROGRAM_ID, + tokenSwap.poolTokenProgramId, + SWAP_AMOUNT_IN, + 0n, + ), + ); + + const confirmOptions = { + skipPreflight: true, + }; + + // Send the instructions + console.log('sending big instruction'); + await sendAndConfirmTransaction( + connection, + transaction, + [payer, owner, newAccount, userTransferAuthority], + confirmOptions, + ); + + let info; + info = await getAccount(connection, tokenAccountA); + currentSwapTokenA = info.amount; + info = await getAccount(connection, tokenAccountB); + currentSwapTokenB = info.amount; +} + +export async function swap(): Promise { + console.log('Creating swap token a account'); + const userAccountA = await createAccount( + connection, + payer, + mintA, + owner.publicKey, + Keypair.generate(), + ); + await mintTo(connection, payer, mintA, userAccountA, owner, SWAP_AMOUNT_IN); + const userTransferAuthority = Keypair.generate(); + await approve( + connection, + payer, + userAccountA, + userTransferAuthority.publicKey, + owner, + SWAP_AMOUNT_IN, + ); + console.log('Creating swap token b account'); + const userAccountB = await createAccount( + connection, + payer, + mintB, + owner.publicKey, + Keypair.generate(), + ); + const poolAccount = SWAP_PROGRAM_OWNER_FEE_ADDRESS + ? await createAccount( + connection, + payer, + tokenPool, + owner.publicKey, + Keypair.generate(), + ) + : null; + + const confirmOptions = { + skipPreflight: true, + }; + + console.log('Swapping'); + await tokenSwap.swap( + userAccountA, + tokenAccountA, + tokenAccountB, + userAccountB, + tokenSwap.mintA, + tokenSwap.mintB, + TOKEN_PROGRAM_ID, + TOKEN_PROGRAM_ID, + poolAccount, + userTransferAuthority, + SWAP_AMOUNT_IN, + SWAP_AMOUNT_OUT, + confirmOptions, + ); + + await sleep(500); + + let info; + info = await getAccount(connection, userAccountA); + assert(info.amount == 0n); + + info = await getAccount(connection, userAccountB); + assert(info.amount == SWAP_AMOUNT_OUT); + + info = await getAccount(connection, tokenAccountA); + assert(info.amount == currentSwapTokenA + SWAP_AMOUNT_IN); + currentSwapTokenA += SWAP_AMOUNT_IN; + + info = await getAccount(connection, tokenAccountB); + assert(info.amount == currentSwapTokenB - SWAP_AMOUNT_OUT); + currentSwapTokenB -= SWAP_AMOUNT_OUT; + + info = await getAccount(connection, tokenAccountPool); + assert(info.amount == DEFAULT_POOL_TOKEN_AMOUNT - POOL_TOKEN_AMOUNT); + + info = await getAccount(connection, feeAccount); + assert(info.amount == currentFeeAmount + OWNER_SWAP_FEE); + + if (poolAccount != null) { + info = await getAccount(connection, poolAccount); + assert(info.amount == HOST_SWAP_FEE); + } +} + +function tradingTokensToPoolTokens( + sourceAmount: bigint, + swapSourceAmount: bigint, + poolAmount: bigint, +): bigint { + const tradingFee = + (sourceAmount / 2n) * (TRADING_FEE_NUMERATOR / TRADING_FEE_DENOMINATOR); + const ownerTradingFee = + (sourceAmount / 2n) * + (OWNER_TRADING_FEE_NUMERATOR / OWNER_TRADING_FEE_DENOMINATOR); + const sourceAmountPostFee = sourceAmount - tradingFee - ownerTradingFee; + const root = Math.sqrt( + Number(sourceAmountPostFee) / Number(swapSourceAmount) + 1, + ); + return BigInt(Math.floor(Number(poolAmount) * (root - 1))); +} + +export async function depositSingleTokenTypeExactAmountIn(): Promise { + // Pool token amount to deposit on one side + const depositAmount = 10000n; + + const poolMintInfo = await getMint(connection, tokenPool); + const supply = poolMintInfo.supply; + const swapTokenA = await getAccount(connection, tokenAccountA); + //const poolTokenA = tradingTokensToPoolTokens( + // depositAmount, + // swapTokenA.amount, + // supply, + //); + const poolTokenA = 0n; // maybe do this better eventually + const swapTokenB = await getAccount(connection, tokenAccountB); + //const poolTokenB = tradingTokensToPoolTokens( + // depositAmount, + // swapTokenB.amount, + // supply, + //; + const poolTokenB = 0n; // maybe do this better eventually + + const userTransferAuthority = Keypair.generate(); + console.log('Creating depositor token a account'); + const userAccountA = await createAccount( + connection, + payer, + mintA, + owner.publicKey, + Keypair.generate(), + ); + await mintTo(connection, payer, mintA, userAccountA, owner, depositAmount); + await approve( + connection, + payer, + userAccountA, + userTransferAuthority.publicKey, + owner, + depositAmount, + ); + console.log('Creating depositor token b account'); + const userAccountB = await createAccount( + connection, + payer, + mintB, + owner.publicKey, + Keypair.generate(), + ); + await mintTo(connection, payer, mintB, userAccountB, owner, depositAmount); + await approve( + connection, + payer, + userAccountB, + userTransferAuthority.publicKey, + owner, + depositAmount, + ); + console.log('Creating depositor pool token account'); + const newAccountPool = await createAccount( + connection, + payer, + tokenPool, + owner.publicKey, + Keypair.generate(), + ); + + const confirmOptions = { + skipPreflight: true, + }; + + console.log('Depositing token A into swap'); + await tokenSwap.depositSingleTokenTypeExactAmountIn( + userAccountA, + newAccountPool, + tokenSwap.mintA, + TOKEN_PROGRAM_ID, + userTransferAuthority, + depositAmount, + poolTokenA, + confirmOptions, + ); + + let info; + info = await getAccount(connection, userAccountA); + assert(info.amount == 0n); + info = await getAccount(connection, tokenAccountA); + assert(info.amount == currentSwapTokenA + depositAmount); + currentSwapTokenA += depositAmount; + + console.log('Depositing token B into swap'); + await tokenSwap.depositSingleTokenTypeExactAmountIn( + userAccountB, + newAccountPool, + tokenSwap.mintB, + TOKEN_PROGRAM_ID, + userTransferAuthority, + depositAmount, + poolTokenB, + confirmOptions, + ); + + info = await getAccount(connection, userAccountB); + assert(info.amount == 0n); + info = await getAccount(connection, tokenAccountB); + assert(info.amount == currentSwapTokenB + depositAmount); + currentSwapTokenB += depositAmount; + info = await getAccount(connection, newAccountPool); + assert(info.amount >= poolTokenA + poolTokenB); +} + +export async function withdrawSingleTokenTypeExactAmountOut(): Promise { + // Pool token amount to withdraw on one side + const withdrawAmount = 50000n; + + const poolMintInfo = await getMint(connection, tokenPool); + const supply = poolMintInfo.supply; + + const swapTokenA = await getAccount(connection, tokenAccountA); + const swapTokenAPost = swapTokenA.amount - withdrawAmount; + //const poolTokenA = tradingTokensToPoolTokens( + // withdrawAmount, + // swapTokenAPost, + // supply, + //); + //if (OWNER_WITHDRAW_FEE_NUMERATOR !== 0n) { + // adjustedPoolTokenA *= + // 1n + OWNER_WITHDRAW_FEE_NUMERATOR / OWNER_WITHDRAW_FEE_DENOMINATOR; + //} + const adjustedPoolTokenA = 1_000_000_000_000n; // maybe do this better + + const swapTokenB = await getAccount(connection, tokenAccountB); + const swapTokenBPost = swapTokenB.amount - withdrawAmount; + //const poolTokenB = tradingTokensToPoolTokens( + // withdrawAmount, + // swapTokenBPost, + // supply, + //); + //if (OWNER_WITHDRAW_FEE_NUMERATOR !== 0n) { + // adjustedPoolTokenB *= + // 1n + OWNER_WITHDRAW_FEE_NUMERATOR / OWNER_WITHDRAW_FEE_DENOMINATOR; + //} + const adjustedPoolTokenB = 1_000_000_000_000n; // maybe do this better + + const userTransferAuthority = Keypair.generate(); + console.log('Creating withdraw token a account'); + const userAccountA = await createAccount( + connection, + payer, + mintA, + owner.publicKey, + Keypair.generate(), + ); + console.log('Creating withdraw token b account'); + const userAccountB = await createAccount( + connection, + payer, + mintB, + owner.publicKey, + Keypair.generate(), + ); + console.log('Creating withdraw pool token account'); + const poolAccount = await getAccount(connection, tokenAccountPool); + const poolTokenAmount = poolAccount.amount; + await approve( + connection, + payer, + tokenAccountPool, + userTransferAuthority.publicKey, + owner, + adjustedPoolTokenA + adjustedPoolTokenB, + ); + + const confirmOptions = { + skipPreflight: true, + }; + + console.log('Withdrawing token A only'); + await tokenSwap.withdrawSingleTokenTypeExactAmountOut( + userAccountA, + tokenAccountPool, + tokenSwap.mintA, + TOKEN_PROGRAM_ID, + userTransferAuthority, + withdrawAmount, + adjustedPoolTokenA, + confirmOptions, + ); + + let info; + info = await getAccount(connection, userAccountA); + assert(info.amount == withdrawAmount); + info = await getAccount(connection, tokenAccountA); + assert(info.amount == currentSwapTokenA - withdrawAmount); + currentSwapTokenA += withdrawAmount; + info = await getAccount(connection, tokenAccountPool); + assert(info.amount >= poolTokenAmount - adjustedPoolTokenA); + + console.log('Withdrawing token B only'); + await tokenSwap.withdrawSingleTokenTypeExactAmountOut( + userAccountB, + tokenAccountPool, + tokenSwap.mintB, + TOKEN_PROGRAM_ID, + userTransferAuthority, + withdrawAmount, + adjustedPoolTokenB, + confirmOptions, + ); + + info = await getAccount(connection, userAccountB); + assert(info.amount == withdrawAmount); + info = await getAccount(connection, tokenAccountB); + assert(info.amount == currentSwapTokenB - withdrawAmount); + currentSwapTokenB += withdrawAmount; + info = await getAccount(connection, tokenAccountPool); + assert( + info.amount >= poolTokenAmount - adjustedPoolTokenA - adjustedPoolTokenB, + ); +} diff --git a/token-swap/js/test/main.ts b/token-swap/js/test/main.ts deleted file mode 100644 index ea48f0f9cae..00000000000 --- a/token-swap/js/test/main.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { - createAccountAndSwapAtomic, - createTokenSwap, - swap, - depositAllTokenTypes, - withdrawAllTokenTypes, - depositSingleTokenTypeExactAmountIn, - withdrawSingleTokenTypeExactAmountOut, -} from './token-swap-test'; -import {CurveType, Numberu64} from '../src'; - -async function main() { - // These test cases are designed to run sequentially and in the following order - console.log('Run test: createTokenSwap (constant price)'); - await createTokenSwap(CurveType.ConstantPrice, new Numberu64(1)); - console.log( - 'Run test: createTokenSwap (constant product, used further in tests)', - ); - await createTokenSwap(CurveType.ConstantProduct); - console.log('Run test: deposit all token types'); - await depositAllTokenTypes(); - console.log('Run test: withdraw all token types'); - await withdrawAllTokenTypes(); - console.log('Run test: swap'); - await swap(); - console.log('Run test: create account, approve, swap all at once'); - await createAccountAndSwapAtomic(); - console.log('Run test: deposit one exact amount in'); - await depositSingleTokenTypeExactAmountIn(); - console.log('Run test: withrdaw one exact amount out'); - await withdrawSingleTokenTypeExactAmountOut(); - console.log('Success\n'); -} - -main() - .catch(err => { - console.error(err); - process.exit(-1); - }) - .then(() => process.exit()); diff --git a/token-swap/js/test/token-swap-test.ts b/token-swap/js/test/token-swap-test.ts deleted file mode 100644 index a422bffdc47..00000000000 --- a/token-swap/js/test/token-swap-test.ts +++ /dev/null @@ -1,694 +0,0 @@ -import { - Account, - Connection, - PublicKey, - SystemProgram, - Transaction, - sendAndConfirmTransaction -} from '@solana/web3.js'; -import {AccountLayout, Token, TOKEN_PROGRAM_ID} from '@solana/spl-token'; - -import {TokenSwap, CurveType, TOKEN_SWAP_PROGRAM_ID} from '../src'; -import {newAccountWithLamports} from '../src/util/new-account-with-lamports'; -import {sleep} from '../src/util/sleep'; -import {Numberu64} from '../src'; - -// The following globals are created by `createTokenSwap` and used by subsequent tests -// Token swap -let tokenSwap: TokenSwap; -// authority of the token and accounts -let authority: PublicKey; -// bump seed used to generate the authority public key -let bumpSeed: number; -// owner of the user accounts -let owner: Account; -// Token pool -let tokenPool: Token; -let tokenAccountPool: PublicKey; -let feeAccount: PublicKey; -// Tokens swapped -let mintA: Token; -let mintB: Token; -let tokenAccountA: PublicKey; -let tokenAccountB: PublicKey; - -// Hard-coded fee address, for testing production mode -const SWAP_PROGRAM_OWNER_FEE_ADDRESS = - process.env.SWAP_PROGRAM_OWNER_FEE_ADDRESS; - -// Pool fees -const TRADING_FEE_NUMERATOR = 25; -const TRADING_FEE_DENOMINATOR = 10000; -const OWNER_TRADING_FEE_NUMERATOR = 5; -const OWNER_TRADING_FEE_DENOMINATOR = 10000; -const OWNER_WITHDRAW_FEE_NUMERATOR = SWAP_PROGRAM_OWNER_FEE_ADDRESS ? 0 : 1; -const OWNER_WITHDRAW_FEE_DENOMINATOR = SWAP_PROGRAM_OWNER_FEE_ADDRESS ? 0 : 6; -const HOST_FEE_NUMERATOR = 20; -const HOST_FEE_DENOMINATOR = 100; - -// Initial amount in each swap token -let currentSwapTokenA = 1000000; -let currentSwapTokenB = 1000000; -let currentFeeAmount = 0; - -// Swap instruction constants -// Because there is no withdraw fee in the production version, these numbers -// need to get slightly tweaked in the two cases. -const SWAP_AMOUNT_IN = 100000; -const SWAP_AMOUNT_OUT = SWAP_PROGRAM_OWNER_FEE_ADDRESS ? 90661 : 90674; -const SWAP_FEE = SWAP_PROGRAM_OWNER_FEE_ADDRESS ? 22273 : 22277; -const HOST_SWAP_FEE = SWAP_PROGRAM_OWNER_FEE_ADDRESS - ? Math.floor((SWAP_FEE * HOST_FEE_NUMERATOR) / HOST_FEE_DENOMINATOR) - : 0; -const OWNER_SWAP_FEE = SWAP_FEE - HOST_SWAP_FEE; - -// Pool token amount minted on init -const DEFAULT_POOL_TOKEN_AMOUNT = 1000000000; -// Pool token amount to withdraw / deposit -const POOL_TOKEN_AMOUNT = 10000000; - -function assert(condition: boolean, message?: string) { - if (!condition) { - console.log(Error().stack + ':token-test.js'); - throw message || 'Assertion failed'; - } -} - -let connection: Connection; -async function getConnection(): Promise { - if (connection) return connection; - - const url = 'http://localhost:8899'; - connection = new Connection(url, 'recent'); - const version = await connection.getVersion(); - - console.log('Connection to cluster established:', url, version); - return connection; -} - -export async function createTokenSwap( - curveType: number, - curveParameters?: Numberu64, -): Promise { - const connection = await getConnection(); - const payer = await newAccountWithLamports(connection, 1000000000); - owner = await newAccountWithLamports(connection, 1000000000); - const tokenSwapAccount = new Account(); - - [authority, bumpSeed] = await PublicKey.findProgramAddress( - [tokenSwapAccount.publicKey.toBuffer()], - TOKEN_SWAP_PROGRAM_ID, - ); - - console.log('creating pool mint'); - tokenPool = await Token.createMint( - connection, - payer, - authority, - null, - 2, - TOKEN_PROGRAM_ID, - ); - - console.log('creating pool account'); - tokenAccountPool = await tokenPool.createAccount(owner.publicKey); - const ownerKey = SWAP_PROGRAM_OWNER_FEE_ADDRESS || owner.publicKey.toString(); - feeAccount = await tokenPool.createAccount(new PublicKey(ownerKey)); - - console.log('creating token A'); - mintA = await Token.createMint( - connection, - payer, - owner.publicKey, - null, - 2, - TOKEN_PROGRAM_ID, - ); - - console.log('creating token A account'); - tokenAccountA = await mintA.createAccount(authority); - console.log('minting token A to swap'); - await mintA.mintTo(tokenAccountA, owner, [], currentSwapTokenA); - - console.log('creating token B'); - mintB = await Token.createMint( - connection, - payer, - owner.publicKey, - null, - 2, - TOKEN_PROGRAM_ID, - ); - - console.log('creating token B account'); - tokenAccountB = await mintB.createAccount(authority); - console.log('minting token B to swap'); - await mintB.mintTo(tokenAccountB, owner, [], currentSwapTokenB); - - console.log('creating token swap'); - const swapPayer = await newAccountWithLamports(connection, 10000000000); - tokenSwap = await TokenSwap.createTokenSwap( - connection, - swapPayer, - tokenSwapAccount, - authority, - tokenAccountA, - tokenAccountB, - tokenPool.publicKey, - mintA.publicKey, - mintB.publicKey, - feeAccount, - tokenAccountPool, - TOKEN_SWAP_PROGRAM_ID, - TOKEN_PROGRAM_ID, - TRADING_FEE_NUMERATOR, - TRADING_FEE_DENOMINATOR, - OWNER_TRADING_FEE_NUMERATOR, - OWNER_TRADING_FEE_DENOMINATOR, - OWNER_WITHDRAW_FEE_NUMERATOR, - OWNER_WITHDRAW_FEE_DENOMINATOR, - HOST_FEE_NUMERATOR, - HOST_FEE_DENOMINATOR, - curveType, - curveParameters, - ); - - console.log('loading token swap'); - const fetchedTokenSwap = await TokenSwap.loadTokenSwap( - connection, - tokenSwapAccount.publicKey, - TOKEN_SWAP_PROGRAM_ID, - swapPayer, - ); - - assert(fetchedTokenSwap.tokenProgramId.equals(TOKEN_PROGRAM_ID)); - assert(fetchedTokenSwap.tokenAccountA.equals(tokenAccountA)); - assert(fetchedTokenSwap.tokenAccountB.equals(tokenAccountB)); - assert(fetchedTokenSwap.mintA.equals(mintA.publicKey)); - assert(fetchedTokenSwap.mintB.equals(mintB.publicKey)); - assert(fetchedTokenSwap.poolToken.equals(tokenPool.publicKey)); - assert(fetchedTokenSwap.feeAccount.equals(feeAccount)); - assert( - TRADING_FEE_NUMERATOR == fetchedTokenSwap.tradeFeeNumerator.toNumber(), - ); - assert( - TRADING_FEE_DENOMINATOR == fetchedTokenSwap.tradeFeeDenominator.toNumber(), - ); - assert( - OWNER_TRADING_FEE_NUMERATOR == - fetchedTokenSwap.ownerTradeFeeNumerator.toNumber(), - ); - assert( - OWNER_TRADING_FEE_DENOMINATOR == - fetchedTokenSwap.ownerTradeFeeDenominator.toNumber(), - ); - assert( - OWNER_WITHDRAW_FEE_NUMERATOR == - fetchedTokenSwap.ownerWithdrawFeeNumerator.toNumber(), - ); - assert( - OWNER_WITHDRAW_FEE_DENOMINATOR == - fetchedTokenSwap.ownerWithdrawFeeDenominator.toNumber(), - ); - assert(HOST_FEE_NUMERATOR == fetchedTokenSwap.hostFeeNumerator.toNumber()); - assert( - HOST_FEE_DENOMINATOR == fetchedTokenSwap.hostFeeDenominator.toNumber(), - ); - assert(curveType == fetchedTokenSwap.curveType); -} - -export async function depositAllTokenTypes(): Promise { - const poolMintInfo = await tokenPool.getMintInfo(); - const supply = poolMintInfo.supply.toNumber(); - const swapTokenA = await mintA.getAccountInfo(tokenAccountA); - const tokenA = Math.floor( - (swapTokenA.amount.toNumber() * POOL_TOKEN_AMOUNT) / supply, - ); - const swapTokenB = await mintB.getAccountInfo(tokenAccountB); - const tokenB = Math.floor( - (swapTokenB.amount.toNumber() * POOL_TOKEN_AMOUNT) / supply, - ); - - const userTransferAuthority = new Account(); - console.log('Creating depositor token a account'); - const userAccountA = await mintA.createAccount(owner.publicKey); - await mintA.mintTo(userAccountA, owner, [], tokenA); - await mintA.approve( - userAccountA, - userTransferAuthority.publicKey, - owner, - [], - tokenA, - ); - console.log('Creating depositor token b account'); - const userAccountB = await mintB.createAccount(owner.publicKey); - await mintB.mintTo(userAccountB, owner, [], tokenB); - await mintB.approve( - userAccountB, - userTransferAuthority.publicKey, - owner, - [], - tokenB, - ); - console.log('Creating depositor pool token account'); - const newAccountPool = await tokenPool.createAccount(owner.publicKey); - - const confirmOptions = { - skipPreflight: true - } - - console.log('Depositing into swap'); - await tokenSwap.depositAllTokenTypes( - userAccountA, - userAccountB, - newAccountPool, - userTransferAuthority, - POOL_TOKEN_AMOUNT, - tokenA, - tokenB, - confirmOptions - ); - - let info; - info = await mintA.getAccountInfo(userAccountA); - assert(info.amount.toNumber() == 0); - info = await mintB.getAccountInfo(userAccountB); - assert(info.amount.toNumber() == 0); - info = await mintA.getAccountInfo(tokenAccountA); - assert(info.amount.toNumber() == currentSwapTokenA + tokenA); - currentSwapTokenA += tokenA; - info = await mintB.getAccountInfo(tokenAccountB); - assert(info.amount.toNumber() == currentSwapTokenB + tokenB); - currentSwapTokenB += tokenB; - info = await tokenPool.getAccountInfo(newAccountPool); - assert(info.amount.toNumber() == POOL_TOKEN_AMOUNT); -} - -export async function withdrawAllTokenTypes(): Promise { - const poolMintInfo = await tokenPool.getMintInfo(); - const supply = poolMintInfo.supply.toNumber(); - let swapTokenA = await mintA.getAccountInfo(tokenAccountA); - let swapTokenB = await mintB.getAccountInfo(tokenAccountB); - let feeAmount = 0; - if (OWNER_WITHDRAW_FEE_NUMERATOR !== 0) { - feeAmount = Math.floor( - (POOL_TOKEN_AMOUNT * OWNER_WITHDRAW_FEE_NUMERATOR) / - OWNER_WITHDRAW_FEE_DENOMINATOR, - ); - } - const poolTokenAmount = POOL_TOKEN_AMOUNT - feeAmount; - const tokenA = Math.floor( - (swapTokenA.amount.toNumber() * poolTokenAmount) / supply, - ); - const tokenB = Math.floor( - (swapTokenB.amount.toNumber() * poolTokenAmount) / supply, - ); - - console.log('Creating withdraw token A account'); - let userAccountA = await mintA.createAccount(owner.publicKey); - console.log('Creating withdraw token B account'); - let userAccountB = await mintB.createAccount(owner.publicKey); - - const userTransferAuthority = new Account(); - console.log('Approving withdrawal from pool account'); - await tokenPool.approve( - tokenAccountPool, - userTransferAuthority.publicKey, - owner, - [], - POOL_TOKEN_AMOUNT, - ); - - const confirmOptions = { - skipPreflight: true - } - - console.log('Withdrawing pool tokens for A and B tokens'); - await tokenSwap.withdrawAllTokenTypes( - userAccountA, - userAccountB, - tokenAccountPool, - userTransferAuthority, - POOL_TOKEN_AMOUNT, - tokenA, - tokenB, - confirmOptions - ); - - //const poolMintInfo = await tokenPool.getMintInfo(); - swapTokenA = await mintA.getAccountInfo(tokenAccountA); - swapTokenB = await mintB.getAccountInfo(tokenAccountB); - - let info = await tokenPool.getAccountInfo(tokenAccountPool); - assert( - info.amount.toNumber() == DEFAULT_POOL_TOKEN_AMOUNT - POOL_TOKEN_AMOUNT, - ); - assert(swapTokenA.amount.toNumber() == currentSwapTokenA - tokenA); - currentSwapTokenA -= tokenA; - assert(swapTokenB.amount.toNumber() == currentSwapTokenB - tokenB); - currentSwapTokenB -= tokenB; - info = await mintA.getAccountInfo(userAccountA); - assert(info.amount.toNumber() == tokenA); - info = await mintB.getAccountInfo(userAccountB); - assert(info.amount.toNumber() == tokenB); - info = await tokenPool.getAccountInfo(feeAccount); - assert(info.amount.toNumber() == feeAmount); - currentFeeAmount = feeAmount; -} - -export async function createAccountAndSwapAtomic(): Promise { - console.log('Creating swap token a account'); - let userAccountA = await mintA.createAccount(owner.publicKey); - await mintA.mintTo(userAccountA, owner, [], SWAP_AMOUNT_IN); - - // @ts-ignore - const balanceNeeded = await Token.getMinBalanceRentForExemptAccount( - connection, - ); - const newAccount = new Account(); - const transaction = new Transaction(); - transaction.add( - SystemProgram.createAccount({ - fromPubkey: owner.publicKey, - newAccountPubkey: newAccount.publicKey, - lamports: balanceNeeded, - space: AccountLayout.span, - programId: mintB.programId, - }), - ); - - transaction.add( - Token.createInitAccountInstruction( - mintB.programId, - mintB.publicKey, - newAccount.publicKey, - owner.publicKey, - ), - ); - - const userTransferAuthority = new Account(); - transaction.add( - Token.createApproveInstruction( - mintA.programId, - userAccountA, - userTransferAuthority.publicKey, - owner.publicKey, - [owner], - SWAP_AMOUNT_IN, - ), - ); - - transaction.add( - TokenSwap.swapInstruction( - tokenSwap.tokenSwap, - tokenSwap.authority, - userTransferAuthority.publicKey, - userAccountA, - tokenSwap.tokenAccountA, - tokenSwap.tokenAccountB, - newAccount.publicKey, - tokenSwap.poolToken, - tokenSwap.feeAccount, - null, - tokenSwap.swapProgramId, - tokenSwap.tokenProgramId, - SWAP_AMOUNT_IN, - 0, - ), - ); - - const confirmOptions = { - skipPreflight: true - } - - // Send the instructions - console.log('sending big instruction'); - await sendAndConfirmTransaction( - connection, - transaction, - [owner, newAccount, userTransferAuthority], - confirmOptions - ); - - let info; - info = await mintA.getAccountInfo(tokenAccountA); - currentSwapTokenA = info.amount.toNumber(); - info = await mintB.getAccountInfo(tokenAccountB); - currentSwapTokenB = info.amount.toNumber(); -} - -export async function swap(): Promise { - console.log('Creating swap token a account'); - let userAccountA = await mintA.createAccount(owner.publicKey); - await mintA.mintTo(userAccountA, owner, [], SWAP_AMOUNT_IN); - const userTransferAuthority = new Account(); - await mintA.approve( - userAccountA, - userTransferAuthority.publicKey, - owner, - [], - SWAP_AMOUNT_IN, - ); - console.log('Creating swap token b account'); - let userAccountB = await mintB.createAccount(owner.publicKey); - let poolAccount = SWAP_PROGRAM_OWNER_FEE_ADDRESS - ? await tokenPool.createAccount(owner.publicKey) - : null; - - const confirmOptions = { - skipPreflight: true - } - - console.log('Swapping'); - await tokenSwap.swap( - userAccountA, - tokenAccountA, - tokenAccountB, - userAccountB, - poolAccount, - userTransferAuthority, - SWAP_AMOUNT_IN, - SWAP_AMOUNT_OUT, - confirmOptions - ); - - await sleep(500); - - let info; - info = await mintA.getAccountInfo(userAccountA); - assert(info.amount.toNumber() == 0); - - info = await mintB.getAccountInfo(userAccountB); - assert(info.amount.toNumber() == SWAP_AMOUNT_OUT); - - info = await mintA.getAccountInfo(tokenAccountA); - assert(info.amount.toNumber() == currentSwapTokenA + SWAP_AMOUNT_IN); - currentSwapTokenA += SWAP_AMOUNT_IN; - - info = await mintB.getAccountInfo(tokenAccountB); - assert(info.amount.toNumber() == currentSwapTokenB - SWAP_AMOUNT_OUT); - currentSwapTokenB -= SWAP_AMOUNT_OUT; - - info = await tokenPool.getAccountInfo(tokenAccountPool); - assert( - info.amount.toNumber() == DEFAULT_POOL_TOKEN_AMOUNT - POOL_TOKEN_AMOUNT, - ); - - info = await tokenPool.getAccountInfo(feeAccount); - assert(info.amount.toNumber() == currentFeeAmount + OWNER_SWAP_FEE); - - if (poolAccount != null) { - info = await tokenPool.getAccountInfo(poolAccount); - assert(info.amount.toNumber() == HOST_SWAP_FEE); - } -} - -function tradingTokensToPoolTokens( - sourceAmount: number, - swapSourceAmount: number, - poolAmount: number, -): number { - const tradingFee = - (sourceAmount / 2) * (TRADING_FEE_NUMERATOR / TRADING_FEE_DENOMINATOR); - const sourceAmountPostFee = sourceAmount - tradingFee; - const root = Math.sqrt(sourceAmountPostFee / swapSourceAmount + 1); - return Math.floor(poolAmount * (root - 1)); -} - -export async function depositSingleTokenTypeExactAmountIn(): Promise { - // Pool token amount to deposit on one side - const depositAmount = 10000; - - const poolMintInfo = await tokenPool.getMintInfo(); - const supply = poolMintInfo.supply.toNumber(); - const swapTokenA = await mintA.getAccountInfo(tokenAccountA); - const poolTokenA = tradingTokensToPoolTokens( - depositAmount, - swapTokenA.amount.toNumber(), - supply, - ); - const swapTokenB = await mintB.getAccountInfo(tokenAccountB); - const poolTokenB = tradingTokensToPoolTokens( - depositAmount, - swapTokenB.amount.toNumber(), - supply, - ); - - const userTransferAuthority = new Account(); - console.log('Creating depositor token a account'); - const userAccountA = await mintA.createAccount(owner.publicKey); - await mintA.mintTo(userAccountA, owner, [], depositAmount); - await mintA.approve( - userAccountA, - userTransferAuthority.publicKey, - owner, - [], - depositAmount, - ); - console.log('Creating depositor token b account'); - const userAccountB = await mintB.createAccount(owner.publicKey); - await mintB.mintTo(userAccountB, owner, [], depositAmount); - await mintB.approve( - userAccountB, - userTransferAuthority.publicKey, - owner, - [], - depositAmount, - ); - console.log('Creating depositor pool token account'); - const newAccountPool = await tokenPool.createAccount(owner.publicKey); - - const confirmOptions = { - skipPreflight: true - } - - console.log('Depositing token A into swap'); - await tokenSwap.depositSingleTokenTypeExactAmountIn( - userAccountA, - newAccountPool, - userTransferAuthority, - depositAmount, - poolTokenA, - confirmOptions - ); - - let info; - info = await mintA.getAccountInfo(userAccountA); - assert(info.amount.toNumber() == 0); - info = await mintA.getAccountInfo(tokenAccountA); - assert(info.amount.toNumber() == currentSwapTokenA + depositAmount); - currentSwapTokenA += depositAmount; - - console.log('Depositing token B into swap'); - await tokenSwap.depositSingleTokenTypeExactAmountIn( - userAccountB, - newAccountPool, - userTransferAuthority, - depositAmount, - poolTokenB, - confirmOptions - ); - - info = await mintB.getAccountInfo(userAccountB); - assert(info.amount.toNumber() == 0); - info = await mintB.getAccountInfo(tokenAccountB); - assert(info.amount.toNumber() == currentSwapTokenB + depositAmount); - currentSwapTokenB += depositAmount; - info = await tokenPool.getAccountInfo(newAccountPool); - assert(info.amount.toNumber() >= poolTokenA + poolTokenB); -} - -export async function withdrawSingleTokenTypeExactAmountOut(): Promise { - // Pool token amount to withdraw on one side - const withdrawAmount = 50000; - const roundingAmount = 1.0001; // make math a little easier - - const poolMintInfo = await tokenPool.getMintInfo(); - const supply = poolMintInfo.supply.toNumber(); - - const swapTokenA = await mintA.getAccountInfo(tokenAccountA); - const swapTokenAPost = swapTokenA.amount.toNumber() - withdrawAmount; - const poolTokenA = tradingTokensToPoolTokens( - withdrawAmount, - swapTokenAPost, - supply, - ); - let adjustedPoolTokenA = poolTokenA * roundingAmount; - if (OWNER_WITHDRAW_FEE_NUMERATOR !== 0) { - adjustedPoolTokenA *= - 1 + OWNER_WITHDRAW_FEE_NUMERATOR / OWNER_WITHDRAW_FEE_DENOMINATOR; - } - - const swapTokenB = await mintB.getAccountInfo(tokenAccountB); - const swapTokenBPost = swapTokenB.amount.toNumber() - withdrawAmount; - const poolTokenB = tradingTokensToPoolTokens( - withdrawAmount, - swapTokenBPost, - supply, - ); - let adjustedPoolTokenB = poolTokenB * roundingAmount; - if (OWNER_WITHDRAW_FEE_NUMERATOR !== 0) { - adjustedPoolTokenB *= - 1 + OWNER_WITHDRAW_FEE_NUMERATOR / OWNER_WITHDRAW_FEE_DENOMINATOR; - } - - const userTransferAuthority = new Account(); - console.log('Creating withdraw token a account'); - const userAccountA = await mintA.createAccount(owner.publicKey); - console.log('Creating withdraw token b account'); - const userAccountB = await mintB.createAccount(owner.publicKey); - console.log('Creating withdraw pool token account'); - const poolAccount = await tokenPool.getAccountInfo(tokenAccountPool); - const poolTokenAmount = poolAccount.amount.toNumber(); - await tokenPool.approve( - tokenAccountPool, - userTransferAuthority.publicKey, - owner, - [], - adjustedPoolTokenA + adjustedPoolTokenB, - ); - - const confirmOptions = { - skipPreflight: true - } - - console.log('Withdrawing token A only'); - await tokenSwap.withdrawSingleTokenTypeExactAmountOut( - userAccountA, - tokenAccountPool, - userTransferAuthority, - withdrawAmount, - adjustedPoolTokenA, - confirmOptions - ); - - let info; - info = await mintA.getAccountInfo(userAccountA); - assert(info.amount.toNumber() == withdrawAmount); - info = await mintA.getAccountInfo(tokenAccountA); - assert(info.amount.toNumber() == currentSwapTokenA - withdrawAmount); - currentSwapTokenA += withdrawAmount; - info = await tokenPool.getAccountInfo(tokenAccountPool); - assert(info.amount.toNumber() >= poolTokenAmount - adjustedPoolTokenA); - - console.log('Withdrawing token B only'); - await tokenSwap.withdrawSingleTokenTypeExactAmountOut( - userAccountB, - tokenAccountPool, - userTransferAuthority, - withdrawAmount, - adjustedPoolTokenB, - confirmOptions - ); - - info = await mintB.getAccountInfo(userAccountB); - assert(info.amount.toNumber() == withdrawAmount); - info = await mintB.getAccountInfo(tokenAccountB); - assert(info.amount.toNumber() == currentSwapTokenB - withdrawAmount); - currentSwapTokenB += withdrawAmount; - info = await tokenPool.getAccountInfo(tokenAccountPool); - assert( - info.amount.toNumber() >= - poolTokenAmount - adjustedPoolTokenA - adjustedPoolTokenB, - ); -} diff --git a/token-swap/js/tsconfig.all.json b/token-swap/js/tsconfig.all.json new file mode 100644 index 00000000000..917ce153962 --- /dev/null +++ b/token-swap/js/tsconfig.all.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.root.json", + "references": [ + { + "path": "./tsconfig.cjs.json" + }, + { + "path": "./tsconfig.esm.json" + } + ] +} diff --git a/token-swap/js/tsconfig.base.json b/token-swap/js/tsconfig.base.json new file mode 100644 index 00000000000..baeb8a34d98 --- /dev/null +++ b/token-swap/js/tsconfig.base.json @@ -0,0 +1,14 @@ +{ + "include": [], + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "Node", + "esModuleInterop": true, + "isolatedModules": true, + "noEmitOnError": true, + "resolveJsonModule": true, + "strict": true, + "stripInternal": true + } +} diff --git a/token-swap/js/tsconfig.cjs.json b/token-swap/js/tsconfig.cjs.json index 7ecb4e6f1e5..7e4292fb5e6 100644 --- a/token-swap/js/tsconfig.cjs.json +++ b/token-swap/js/tsconfig.cjs.json @@ -1,10 +1,10 @@ { - "extends": "./tsconfig.json", - "compilerOptions": { - "target": "es6", - "module": "commonjs", - "outDir": "dist/cjs", - "declarationDir": null, - "declaration": false - } + "extends": "./tsconfig.base.json", + "include": ["src"], + "compilerOptions": { + "outDir": "lib/cjs", + "target": "ES2016", + "module": "CommonJS", + "sourceMap": true + } } diff --git a/token-swap/js/tsconfig.esm.json b/token-swap/js/tsconfig.esm.json new file mode 100644 index 00000000000..a74c93600c5 --- /dev/null +++ b/token-swap/js/tsconfig.esm.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.base.json", + "include": ["src"], + "compilerOptions": { + "outDir": "lib/esm", + "declarationDir": "lib/types", + "target": "ES2020", + "module": "ES2020", + "sourceMap": true, + "declaration": true, + "declarationMap": true + } +} diff --git a/token-swap/js/tsconfig.json b/token-swap/js/tsconfig.json index c0f2f6fe699..ab064c43dc9 100644 --- a/token-swap/js/tsconfig.json +++ b/token-swap/js/tsconfig.json @@ -1,21 +1,8 @@ { + "extends": "./tsconfig.all.json", + "include": ["src", "test"], "compilerOptions": { - "target": "esnext", - "skipLibCheck": true, - "declaration": true, - "declarationDir": "./dist/types", - "outDir": "./dist/esm", - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "module": "commonjs", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "baseUrl": "./src", - "noFallthroughCasesInSwitch": true, - "noImplicitReturns": true - }, - "include": ["./src/**/*"] + "noEmit": true, + "skipLibCheck": true + } } diff --git a/token-swap/js/tsconfig.root.json b/token-swap/js/tsconfig.root.json new file mode 100644 index 00000000000..fdffcb60b1e --- /dev/null +++ b/token-swap/js/tsconfig.root.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.base.json", + "compilerOptions": { + "composite": true + } +} diff --git a/token-swap/program/Cargo.toml b/token-swap/program/Cargo.toml index 8995df1242c..022e9390403 100644 --- a/token-swap/program/Cargo.toml +++ b/token-swap/program/Cargo.toml @@ -2,10 +2,10 @@ name = "spl-token-swap" version = "3.0.0" description = "Solana Program Library Token Swap" -authors = ["Solana Maintainers "] +authors = ["Solana Labs Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" license = "Apache-2.0" -edition = "2018" +edition = "2021" [features] no-entrypoint = [] @@ -13,22 +13,23 @@ production = [] fuzz = ["arbitrary", "roots"] [dependencies] -arrayref = "0.3.6" -enum_dispatch = "0.3.7" -num-derive = "0.3" +arrayref = "0.3.9" +enum_dispatch = "0.3.13" +num-derive = "0.4" num-traits = "0.2" -solana-program = "1.10.33" -spl-math = { version = "0.1", path = "../../libraries/math", features = [ "no-entrypoint" ] } -spl-token = { version = "3.3", path = "../../token/program", features = [ "no-entrypoint" ] } -thiserror = "1.0" -arbitrary = { version = "1.0", features = ["derive"], optional = true } -roots = { version = "0.0.7", optional = true } +solana-program = "2.1.0" +spl-math = { version = "0.3", path = "../../libraries/math" } +spl-token = { version = "7.0", features = [ "no-entrypoint" ] } +spl-token-2022 = { version = "6.0.0", features = [ "no-entrypoint" ] } +thiserror = "2.0" +arbitrary = { version = "1.4", features = ["derive"], optional = true } +roots = { version = "0.0.8", optional = true } [dev-dependencies] -solana-sdk = "1.10.33" -proptest = "1.0" -sim = { path = "./sim" } -roots = "0.0.7" +proptest = "1.6" +roots = "0.0.8" +solana-sdk = "2.1.0" +test-case = "3.3" [lib] crate-type = ["cdylib", "lib"] diff --git a/token-swap/program/fuzz/Cargo.toml b/token-swap/program/fuzz/Cargo.toml index b6957f0f137..77d85c045b5 100644 --- a/token-swap/program/fuzz/Cargo.toml +++ b/token-swap/program/fuzz/Cargo.toml @@ -2,18 +2,18 @@ name = "spl-token-swap-fuzz" version = "0.0.1" description = "Solana Program Library Token Swap Fuzzer" -authors = ["Solana Maintainers "] +authors = ["Solana Labs Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" license = "Apache-2.0" -edition = "2018" +edition = "2021" publish = false [dependencies] -honggfuzz = { version = "0.5.54" } -arbitrary = { version = "1.0", features = ["derive"] } -solana-program = "1.10.33" -spl-math = { version = "0.1", path = "../../../libraries/math", features = [ "no-entrypoint" ] } -spl-token = { version = "3.3", path = "../../../token/program", features = [ "no-entrypoint" ] } +honggfuzz = { version = "0.5.56" } +arbitrary = { version = "1.4", features = ["derive"] } +solana-program = "2.1.0" +spl-math = { version = "0.3", path = "../../../libraries/math" } +spl-token = { version = "7.0", features = [ "no-entrypoint" ] } spl-token-swap = { path = "..", features = ["fuzz", "no-entrypoint"] } [[bin]] diff --git a/token-swap/program/fuzz/src/instructions.rs b/token-swap/program/fuzz/src/instructions.rs index e06bf42919a..62f765fde46 100644 --- a/token-swap/program/fuzz/src/instructions.rs +++ b/token-swap/program/fuzz/src/instructions.rs @@ -1,5 +1,4 @@ -use std::sync::Arc; - +#![allow(clippy::arithmetic_side_effects)] use { arbitrary::Arbitrary, honggfuzz::fuzz, @@ -13,7 +12,6 @@ use { constant_product::ConstantProductCurve, fees::Fees, offset::OffsetCurve, - stable::StableCurve, }, error::SwapError, instruction::{ @@ -26,7 +24,10 @@ use { native_token::{get_token_balance, transfer}, native_token_swap::NativeTokenSwap, }, - std::collections::{HashMap, HashSet}, + std::{ + collections::{HashMap, HashSet}, + sync::Arc, + }, }; #[derive(Debug, Arbitrary, Clone)] @@ -354,6 +355,7 @@ fn run_fuzz_instruction( let pool_account = pool_accounts.get_mut(&pool_token_id).unwrap(); token_swap.deposit_single_token_type_exact_amount_in( source_token_account, + trade_direction, pool_account, instruction, ) @@ -371,6 +373,7 @@ fn run_fuzz_instruction( let pool_account = pool_accounts.get_mut(&pool_token_id).unwrap(); token_swap.withdraw_single_token_type_exact_amount_out( pool_account, + trade_direction, destination_token_account, instruction, ) @@ -387,7 +390,7 @@ fn run_fuzz_instruction( || e == TokenError::InsufficientFunds.into()) { println!("{:?}", e); - Err(e).unwrap() + panic!("{:?}", e) } }) .ok(); @@ -465,7 +468,6 @@ fn get_swap_curve(curve_type: CurveType) -> SwapCurve { CurveType::ConstantPrice => Arc::new(ConstantPriceCurve { token_b_price: 10_000_000, }), - CurveType::Stable => Arc::new(StableCurve { amp: 100 }), CurveType::Offset => Arc::new(OffsetCurve { token_b_offset: 100_000_000_000, }), diff --git a/token-swap/program/fuzz/src/lib.rs b/token-swap/program/fuzz/src/lib.rs index c6d42fd254f..ac2eb1bc88d 100644 --- a/token-swap/program/fuzz/src/lib.rs +++ b/token-swap/program/fuzz/src/lib.rs @@ -1,3 +1,4 @@ +#![allow(clippy::arithmetic_side_effects)] pub mod native_account_data; pub mod native_processor; pub mod native_token; diff --git a/token-swap/program/fuzz/src/native_processor.rs b/token-swap/program/fuzz/src/native_processor.rs index 6115197c4bd..3e451d65e68 100644 --- a/token-swap/program/fuzz/src/native_processor.rs +++ b/token-swap/program/fuzz/src/native_processor.rs @@ -1,8 +1,9 @@ -use crate::native_account_data::NativeAccountData; - -use solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, instruction::Instruction, - program_error::ProgramError, program_stubs, pubkey::Pubkey, +use { + crate::native_account_data::NativeAccountData, + solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, instruction::Instruction, + program_error::ProgramError, program_stubs, pubkey::Pubkey, + }, }; struct TestSyscallStubs {} diff --git a/token-swap/program/fuzz/src/native_token.rs b/token-swap/program/fuzz/src/native_token.rs index b1235c2f1e4..9b7981c43ab 100644 --- a/token-swap/program/fuzz/src/native_token.rs +++ b/token-swap/program/fuzz/src/native_token.rs @@ -1,8 +1,8 @@ -use crate::native_account_data::NativeAccountData; - -use spl_token::state::{Account as TokenAccount, AccountState as TokenAccountState, Mint}; - -use solana_program::{program_option::COption, program_pack::Pack, pubkey::Pubkey}; +use { + crate::native_account_data::NativeAccountData, + solana_program::{program_option::COption, program_pack::Pack, pubkey::Pubkey}, + spl_token::state::{Account as TokenAccount, AccountState as TokenAccountState, Mint}, +}; pub fn create_mint(owner: &Pubkey) -> NativeAccountData { let mut account_data = NativeAccountData::new(Mint::LEN, spl_token::id()); diff --git a/token-swap/program/fuzz/src/native_token_swap.rs b/token-swap/program/fuzz/src/native_token_swap.rs index 802c0cd03b2..0ca6731edbc 100644 --- a/token-swap/program/fuzz/src/native_token_swap.rs +++ b/token-swap/program/fuzz/src/native_token_swap.rs @@ -1,22 +1,22 @@ //! Helpers for working with swaps in a fuzzing environment -use crate::native_account_data::NativeAccountData; -use crate::native_processor::do_process_instruction; -use crate::native_token; - -use spl_token_swap::{ - curve::{base::SwapCurve, fees::Fees}, - instruction::{ - self, DepositAllTokenTypes, DepositSingleTokenTypeExactAmountIn, Swap, - WithdrawAllTokenTypes, WithdrawSingleTokenTypeExactAmountOut, +use { + crate::{ + native_account_data::NativeAccountData, native_processor::do_process_instruction, + native_token, + }, + solana_program::{bpf_loader, entrypoint::ProgramResult, pubkey::Pubkey, system_program}, + spl_token::instruction::approve, + spl_token_swap::{ + curve::{base::SwapCurve, calculator::TradeDirection, fees::Fees}, + instruction::{ + self, DepositAllTokenTypes, DepositSingleTokenTypeExactAmountIn, Swap, + WithdrawAllTokenTypes, WithdrawSingleTokenTypeExactAmountOut, + }, + state::SwapVersion, }, - state::SwapVersion, }; -use spl_token::instruction::approve; - -use solana_program::{bpf_loader, entrypoint::ProgramResult, pubkey::Pubkey, system_program}; - pub struct NativeTokenSwap { pub user_account: NativeAccountData, pub bump_seed: u8, @@ -31,7 +31,9 @@ pub struct NativeTokenSwap { pub token_a_mint_account: NativeAccountData, pub token_b_account: NativeAccountData, pub token_b_mint_account: NativeAccountData, - pub token_program_account: NativeAccountData, + pub pool_token_program_account: NativeAccountData, + pub token_a_program_account: NativeAccountData, + pub token_b_program_account: NativeAccountData, } pub fn create_program_account(program_id: Pubkey) -> NativeAccountData { @@ -56,7 +58,9 @@ impl NativeTokenSwap { &spl_token_swap::id(), ); let mut authority_account = create_program_account(authority_key); - let mut token_program_account = create_program_account(spl_token::id()); + let mut pool_token_program_account = create_program_account(spl_token::id()); + let token_a_program_account = create_program_account(spl_token::id()); + let token_b_program_account = create_program_account(spl_token::id()); let mut pool_mint_account = native_token::create_mint(&authority_account.key); let mut pool_token_account = @@ -101,7 +105,7 @@ impl NativeTokenSwap { pool_mint_account.as_account_info(), pool_fee_account.as_account_info(), pool_token_account.as_account_info(), - token_program_account.as_account_info(), + pool_token_program_account.as_account_info(), ], ) .unwrap(); @@ -120,7 +124,9 @@ impl NativeTokenSwap { token_a_mint_account, token_b_account, token_b_mint_account, - token_program_account, + pool_token_program_account, + token_a_program_account, + token_b_program_account, } } @@ -154,7 +160,7 @@ impl NativeTokenSwap { user_transfer_account.is_signer = true; do_process_instruction( approve( - &self.token_program_account.key, + &self.token_a_program_account.key, &token_a_account.key, &user_transfer_account.key, &self.user_account.key, @@ -172,6 +178,8 @@ impl NativeTokenSwap { let swap_instruction = instruction::swap( &spl_token_swap::id(), &spl_token::id(), + &spl_token::id(), + &spl_token::id(), &self.swap_account.key, &self.authority_account.key, &user_transfer_account.key, @@ -181,6 +189,8 @@ impl NativeTokenSwap { &token_b_account.key, &self.pool_mint_account.key, &self.pool_fee_account.key, + &self.token_a_mint_account.key, + &self.token_b_mint_account.key, Some(&self.pool_token_account.key), instruction, ) @@ -198,7 +208,11 @@ impl NativeTokenSwap { token_b_account.as_account_info(), self.pool_mint_account.as_account_info(), self.pool_fee_account.as_account_info(), - self.token_program_account.as_account_info(), + self.token_a_mint_account.as_account_info(), + self.token_b_mint_account.as_account_info(), + self.token_a_program_account.as_account_info(), + self.token_b_program_account.as_account_info(), + self.pool_token_program_account.as_account_info(), self.pool_token_account.as_account_info(), ], ) @@ -214,7 +228,7 @@ impl NativeTokenSwap { user_transfer_account.is_signer = true; do_process_instruction( approve( - &self.token_program_account.key, + &self.token_b_program_account.key, &token_b_account.key, &user_transfer_account.key, &self.user_account.key, @@ -233,6 +247,8 @@ impl NativeTokenSwap { let swap_instruction = instruction::swap( &spl_token_swap::id(), &spl_token::id(), + &spl_token::id(), + &spl_token::id(), &self.swap_account.key, &self.authority_account.key, &user_transfer_account.key, @@ -242,6 +258,8 @@ impl NativeTokenSwap { &token_a_account.key, &self.pool_mint_account.key, &self.pool_fee_account.key, + &self.token_b_mint_account.key, + &self.token_a_mint_account.key, Some(&self.pool_token_account.key), instruction, ) @@ -259,7 +277,11 @@ impl NativeTokenSwap { token_a_account.as_account_info(), self.pool_mint_account.as_account_info(), self.pool_fee_account.as_account_info(), - self.token_program_account.as_account_info(), + self.token_b_mint_account.as_account_info(), + self.token_a_mint_account.as_account_info(), + self.token_b_program_account.as_account_info(), + self.token_a_program_account.as_account_info(), + self.pool_token_program_account.as_account_info(), self.pool_token_account.as_account_info(), ], ) @@ -276,7 +298,7 @@ impl NativeTokenSwap { user_transfer_account.is_signer = true; do_process_instruction( approve( - &self.token_program_account.key, + &self.token_a_program_account.key, &token_a_account.key, &user_transfer_account.key, &self.user_account.key, @@ -294,7 +316,7 @@ impl NativeTokenSwap { do_process_instruction( approve( - &self.token_program_account.key, + &self.token_b_program_account.key, &token_b_account.key, &user_transfer_account.key, &self.user_account.key, @@ -319,6 +341,8 @@ impl NativeTokenSwap { let deposit_instruction = instruction::deposit_all_token_types( &spl_token_swap::id(), &spl_token::id(), + &spl_token::id(), + &spl_token::id(), &self.swap_account.key, &self.authority_account.key, &user_transfer_account.key, @@ -328,6 +352,8 @@ impl NativeTokenSwap { &self.token_b_account.key, &self.pool_mint_account.key, &pool_account.key, + &self.token_a_mint_account.key, + &self.token_b_mint_account.key, instruction, ) .unwrap(); @@ -344,7 +370,11 @@ impl NativeTokenSwap { self.token_b_account.as_account_info(), self.pool_mint_account.as_account_info(), pool_account.as_account_info(), - self.token_program_account.as_account_info(), + self.token_a_mint_account.as_account_info(), + self.token_b_mint_account.as_account_info(), + self.token_a_program_account.as_account_info(), + self.token_b_program_account.as_account_info(), + self.pool_token_program_account.as_account_info(), ], ) } @@ -366,7 +396,7 @@ impl NativeTokenSwap { } do_process_instruction( approve( - &self.token_program_account.key, + &self.pool_token_program_account.key, &pool_account.key, &user_transfer_account.key, &self.user_account.key, @@ -385,6 +415,8 @@ impl NativeTokenSwap { let withdraw_instruction = instruction::withdraw_all_token_types( &spl_token_swap::id(), &spl_token::id(), + &spl_token::id(), + &spl_token::id(), &self.swap_account.key, &self.authority_account.key, &user_transfer_account.key, @@ -395,6 +427,8 @@ impl NativeTokenSwap { &self.token_b_account.key, &token_a_account.key, &token_b_account.key, + &self.token_a_mint_account.key, + &self.token_b_mint_account.key, instruction, ) .unwrap(); @@ -412,7 +446,11 @@ impl NativeTokenSwap { token_a_account.as_account_info(), token_b_account.as_account_info(), self.pool_fee_account.as_account_info(), - self.token_program_account.as_account_info(), + self.token_a_mint_account.as_account_info(), + self.token_b_mint_account.as_account_info(), + self.pool_token_program_account.as_account_info(), + self.token_a_program_account.as_account_info(), + self.token_b_program_account.as_account_info(), ], ) } @@ -420,14 +458,19 @@ impl NativeTokenSwap { pub fn deposit_single_token_type_exact_amount_in( &mut self, source_token_account: &mut NativeAccountData, + trade_direction: TradeDirection, pool_account: &mut NativeAccountData, mut instruction: DepositSingleTokenTypeExactAmountIn, ) -> ProgramResult { let mut user_transfer_account = NativeAccountData::new(0, system_program::id()); user_transfer_account.is_signer = true; + let source_token_program = match trade_direction { + TradeDirection::AtoB => &mut self.token_a_program_account, + TradeDirection::BtoA => &mut self.token_b_program_account, + }; do_process_instruction( approve( - &self.token_program_account.key, + &source_token_program.key, &source_token_account.key, &user_transfer_account.key, &self.user_account.key, @@ -449,9 +492,15 @@ impl NativeTokenSwap { instruction.minimum_pool_token_amount = 2; } + let source_token_mint_account = match trade_direction { + TradeDirection::AtoB => &mut self.token_a_mint_account, + TradeDirection::BtoA => &mut self.token_b_mint_account, + }; + let deposit_instruction = instruction::deposit_single_token_type_exact_amount_in( &spl_token_swap::id(), &spl_token::id(), + &spl_token::id(), &self.swap_account.key, &self.authority_account.key, &user_transfer_account.key, @@ -460,6 +509,7 @@ impl NativeTokenSwap { &self.token_b_account.key, &self.pool_mint_account.key, &pool_account.key, + &source_token_mint_account.key, instruction, ) .unwrap(); @@ -475,7 +525,9 @@ impl NativeTokenSwap { self.token_b_account.as_account_info(), self.pool_mint_account.as_account_info(), pool_account.as_account_info(), - self.token_program_account.as_account_info(), + source_token_mint_account.as_account_info(), + self.token_a_program_account.as_account_info(), + self.pool_token_program_account.as_account_info(), ], ) } @@ -483,6 +535,7 @@ impl NativeTokenSwap { pub fn withdraw_single_token_type_exact_amount_out( &mut self, pool_account: &mut NativeAccountData, + trade_direction: TradeDirection, destination_token_account: &mut NativeAccountData, mut instruction: WithdrawSingleTokenTypeExactAmountOut, ) -> ProgramResult { @@ -496,7 +549,7 @@ impl NativeTokenSwap { } do_process_instruction( approve( - &self.token_program_account.key, + &self.pool_token_program_account.key, &pool_account.key, &user_transfer_account.key, &self.user_account.key, @@ -512,9 +565,18 @@ impl NativeTokenSwap { ) .unwrap(); + let destination_token_program = match trade_direction { + TradeDirection::AtoB => &mut self.token_a_program_account, + TradeDirection::BtoA => &mut self.token_b_program_account, + }; + let destination_token_mint_account = match trade_direction { + TradeDirection::AtoB => &mut self.token_a_mint_account, + TradeDirection::BtoA => &mut self.token_b_mint_account, + }; let withdraw_instruction = instruction::withdraw_single_token_type_exact_amount_out( &spl_token_swap::id(), &spl_token::id(), + &spl_token::id(), &self.swap_account.key, &self.authority_account.key, &user_transfer_account.key, @@ -524,6 +586,7 @@ impl NativeTokenSwap { &self.token_a_account.key, &self.token_b_account.key, &destination_token_account.key, + &destination_token_mint_account.key, instruction, ) .unwrap(); @@ -540,7 +603,9 @@ impl NativeTokenSwap { self.token_b_account.as_account_info(), destination_token_account.as_account_info(), self.pool_fee_account.as_account_info(), - self.token_program_account.as_account_info(), + destination_token_mint_account.as_account_info(), + self.pool_token_program_account.as_account_info(), + destination_token_program.as_account_info(), ], ) } diff --git a/token-swap/program/proptest-regressions/curve/constant_price.txt b/token-swap/program/proptest-regressions/curve/constant_price.txt new file mode 100644 index 00000000000..a146ac8a4e5 --- /dev/null +++ b/token-swap/program/proptest-regressions/curve/constant_price.txt @@ -0,0 +1 @@ +cc 2594e0e0a7f4471f4929439462cb19c5b187294cc0ede01a155051179eb99bdd diff --git a/token-swap/program/proptest-regressions/curve/stable.txt b/token-swap/program/proptest-regressions/curve/stable.txt deleted file mode 100644 index 044aa25e477..00000000000 --- a/token-swap/program/proptest-regressions/curve/stable.txt +++ /dev/null @@ -1 +0,0 @@ -cc ccac4396e983bbc29b354a5b048bf9da13013fed999bd331049d2fd1f674dc55 diff --git a/token-swap/program/sim/Cargo.toml b/token-swap/program/sim/Cargo.toml deleted file mode 100644 index 0c12e61a95e..00000000000 --- a/token-swap/program/sim/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "sim" -version = "0.1.0" -authors = ["michaelhly "] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -pyo3 = { version = "0.15.1", features = ["auto-initialize"] } diff --git a/token-swap/program/sim/simulation.py b/token-swap/program/sim/simulation.py deleted file mode 100644 index e1b6baa3189..00000000000 --- a/token-swap/program/sim/simulation.py +++ /dev/null @@ -1,188 +0,0 @@ -# Source from: https://github.com/curvefi/curve-contract/blob/master/tests/simulation.py - -class Curve: - - """ - Python model of Curve pool math. - """ - - def __init__(self, A, D, n, fee = 10 ** 7, p=None, tokens=None): - """ - A: Amplification coefficient - D: Total deposit size - n: number of currencies - p: target prices - """ - self.A = A # actually A * n ** (n - 1) because it's an invariant - self.n = n - self.fee = fee - if p: - self.p = p - else: - self.p = [10 ** 18] * n - if isinstance(D, list): - self.x = D - else: - self.x = [D // n * 10 ** 18 // _p for _p in self.p] - self.tokens = tokens - - def xp(self): - return [x * p // 10 ** 18 for x, p in zip(self.x, self.p)] - - def D(self): - """ - D invariant calculation in non-overflowing integer operations - iteratively - - A * sum(x_i) * n**n + D = A * D * n**n + D**(n+1) / (n**n * prod(x_i)) - - Converging solution: - D[j+1] = (A * n**n * sum(x_i) - D[j]**(n+1) / (n**n prod(x_i))) / (A * n**n - 1) - """ - Dprev = 0 - xp = self.xp() - S = sum(xp) - D = S - Ann = self.A * self.n - - counter = 0 - - while abs(D - Dprev) > 1: - D_P = D - for x in xp: - D_P = D_P * D // (self.n * x + 1) - Dprev = D - D = (Ann * S + D_P * self.n) * D // ((Ann - 1) * D + (self.n + 1) * D_P) - - counter += 1 - if counter > 1000: - break - - return D - - def y(self, i, j, x): - """ - Calculate x[j] if one makes x[i] = x - - Done by solving quadratic equation iteratively. - x_1**2 + x1 * (sum' - (A*n**n - 1) * D / (A * n**n)) = D ** (n + 1) / (n ** (2 * n) * prod' * A) - x_1**2 + b*x_1 = c - - x_1 = (x_1**2 + c) / (2*x_1 + b) - """ - D = self.D() - xx = self.xp() - xx[i] = x # x is quantity of underlying asset brought to 1e18 precision - xx = [xx[k] for k in range(self.n) if k != j] - Ann = self.A * self.n - c = D - for y in xx: - c = c * D // (y * self.n) - c = c * D // (self.n * Ann) - b = sum(xx) + D // Ann - D - y_prev = 0 - y = D - - counter = 0 - - while abs(y - y_prev) > 1: - y_prev = y - y = (y ** 2 + c) // (2 * y + b) - - counter += 1 - if counter > 1000: - break - - return y # the result is in underlying units too - - def y_D(self, i, _D): - """ - Calculate x[j] if one makes x[i] = x - - Done by solving quadratic equation iteratively. - x_1**2 + x1 * (sum' - (A*n**n - 1) * D / (A * n**n)) = D ** (n + 1) / (n ** (2 * n) * prod' * A) - x_1**2 + b*x_1 = c - - x_1 = (x_1**2 + c) / (2*x_1 + b) - """ - xx = self.xp() - xx = [xx[k] for k in range(self.n) if k != i] - S = sum(xx) - Ann = self.A * self.n - c = _D - for y in xx: - c = c * _D // (y * self.n) - c = c * _D // (self.n * Ann) - b = S + _D // Ann - y_prev = 0 - y = _D - - counter = 0 - - while abs(y - y_prev) > 1: - y_prev = y - y = (y ** 2 + c) // (2 * y + b - _D) - - counter += 1 - if counter > 1000: - break - - return y # the result is in underlying units too - - def dy(self, i, j, dx): - # dx and dy are in underlying units - xp = self.xp() - return xp[j] - self.y(i, j, xp[i] + dx) - - def exchange(self, i, j, dx): - xp = self.xp() - x = xp[i] + dx - y = self.y(i, j, x) - dy = xp[j] - y - fee = dy * self.fee // 10 ** 10 - - #assert dy > 0 - if dy == 0: - return 0 - - self.x[i] = x * 10 ** 18 // self.p[i] - self.x[j] = (y + fee) * 10 ** 18 // self.p[j] - return dy - fee - - def remove_liquidity_imbalance(self, amounts): - _fee = self.fee * self.n // (4 * (self.n - 1)) - - old_balances = self.x - new_balances = self.x[:] - D0 = self.D() - for i in range(self.n): - new_balances[i] -= amounts[i] - self.x = new_balances - D1 = self.D() - self.x = old_balances - fees = [0] * self.n - for i in range(self.n): - ideal_balance = D1 * old_balances[i] // D0 - difference = abs(ideal_balance - new_balances[i]) - fees[i] = _fee * difference // 10 ** 10 - new_balances[i] -= fees[i] - self.x = new_balances - D2 = self.D() - self.x = old_balances - - token_amount = (D0 - D2) * self.tokens // D0 - - return token_amount - - def calc_withdraw_one_coin(self, token_amount, i): - xp = self.xp() - if self.fee: - fee = self.fee - self.fee * xp[i] // sum(xp) + 5 * 10 ** 5 - else: - fee = 0 - - D0 = self.D() - D1 = D0 - token_amount * D0 // self.tokens - dy = xp[i] - self.y_D(i, D1) - - return dy - dy * fee // 10 ** 10 diff --git a/token-swap/program/sim/src/lib.rs b/token-swap/program/sim/src/lib.rs deleted file mode 100644 index 7181c0f5b1d..00000000000 --- a/token-swap/program/sim/src/lib.rs +++ /dev/null @@ -1,193 +0,0 @@ -use pyo3::prelude::*; -use pyo3::types::PyTuple; -use std::fs::File; -use std::io::prelude::*; - -const FILE_NAME: &str = "simulation.py"; -const FILE_PATH: &str = "sim/simulation.py"; -const MODULE_NAME: &str = "simulation"; - -const DEFAULT_POOL_TOKENS: u128 = 0; -const DEFAULT_TARGET_PRICE: u128 = 1000000000000000000; -pub const MODEL_FEE_NUMERATOR: u128 = 1; -pub const MODEL_FEE_DENOMINATOR: u128 = 1000; - -pub struct StableSwapModel { - py_src: String, - pub amp_factor: u128, - pub balances: Vec, - pub n_coins: u8, - pub fee: u128, - pub target_prices: Vec, - pub pool_tokens: u128, -} - -impl StableSwapModel { - pub fn new(amp_factor: u128, balances: Vec, n_coins: u8) -> StableSwapModel { - let mut src_file = File::open(FILE_PATH).unwrap(); - let mut src_content = String::new(); - let _ = src_file.read_to_string(&mut src_content); - - Self { - py_src: src_content, - amp_factor, - balances, - n_coins, - fee: 0, - target_prices: vec![DEFAULT_TARGET_PRICE, DEFAULT_TARGET_PRICE], - pool_tokens: DEFAULT_POOL_TOKENS, - } - } - - pub fn new_with_pool_tokens( - amp_factor: u128, - balances: Vec, - n_coins: u8, - pool_token_amount: u128, - ) -> StableSwapModel { - let mut src_file = File::open(FILE_PATH).unwrap(); - let mut src_content = String::new(); - let _ = src_file.read_to_string(&mut src_content); - - Self { - py_src: src_content, - amp_factor, - balances, - n_coins, - fee: 0, - target_prices: vec![DEFAULT_TARGET_PRICE, DEFAULT_TARGET_PRICE], - pool_tokens: pool_token_amount, - } - } - - pub fn sim_d(&self) -> u128 { - let gil = Python::acquire_gil(); - return self - .call0(gil.python(), "D") - .unwrap() - .extract(gil.python()) - .unwrap(); - } - - pub fn sim_dy(&self, i: u128, j: u128, dx: u128) -> u128 { - let gil = Python::acquire_gil(); - return self - .call1(gil.python(), "dy", (i, j, dx)) - .unwrap() - .extract(gil.python()) - .unwrap(); - } - - pub fn sim_exchange(&self, i: u128, j: u128, dx: u128) -> u128 { - let gil = Python::acquire_gil(); - return self - .call1(gil.python(), "exchange", (i, j, dx)) - .unwrap() - .extract(gil.python()) - .unwrap(); - } - - pub fn sim_xp(&self) -> Vec { - let gil = Python::acquire_gil(); - return self - .call0(gil.python(), "xp") - .unwrap() - .extract(gil.python()) - .unwrap(); - } - - pub fn sim_y(&self, i: u128, j: u128, x: u128) -> u128 { - let gil = Python::acquire_gil(); - return self - .call1(gil.python(), "y", (i, j, x)) - .unwrap() - .extract(gil.python()) - .unwrap(); - } - - pub fn sim_y_d(&self, i: u128, d: u128) -> u128 { - let gil = Python::acquire_gil(); - return self - .call1(gil.python(), "y_D", (i, d)) - .unwrap() - .extract(gil.python()) - .unwrap(); - } - - pub fn sim_remove_liquidity_imbalance(&self, amounts: Vec) -> u128 { - let gil = Python::acquire_gil(); - return self - .call1( - gil.python(), - "remove_liquidity_imbalance", - PyTuple::new(gil.python(), amounts.to_vec()), - ) - .unwrap() - .extract(gil.python()) - .unwrap(); - } - - pub fn sim_calc_withdraw_one_coin(&self, token_amount: u128, i: u128) -> u128 { - let gil = Python::acquire_gil(); - return self - .call1(gil.python(), "calc_withdraw_one_coin", (token_amount, i)) - .unwrap() - .extract(gil.python()) - .unwrap(); - } - - fn call0(&self, py: Python, method_name: &str) -> Result { - let sim = PyModule::from_code(py, &self.py_src, FILE_NAME, MODULE_NAME).unwrap(); - let model = sim - .getattr("Curve")? - .call1(( - self.amp_factor, - self.balances.to_vec(), - self.n_coins, - self.fee, - self.target_prices.to_vec(), - self.pool_tokens, - )) - .unwrap() - .to_object(py); - let py_ret = model.as_ref(py).call_method0(method_name); - self.extract_py_ret(py, py_ret) - } - - fn call1( - &self, - py: Python, - method_name: &str, - args: impl IntoPy>, - ) -> Result { - let sim = PyModule::from_code(py, &self.py_src, FILE_NAME, MODULE_NAME).unwrap(); - let model = sim - .getattr("Curve")? - .call1(( - self.amp_factor, - self.balances.to_vec(), - self.n_coins, - self.fee, - self.target_prices.to_vec(), - self.pool_tokens, - )) - .unwrap() - .to_object(py); - let py_ret = model.as_ref(py).call_method1(method_name, args); - self.extract_py_ret(py, py_ret) - } - - fn extract_py_ret(&self, py: Python, ret: PyResult<&PyAny>) -> Result { - match ret { - Ok(v) => v.extract(), - Err(e) => { - e.print_and_set_sys_last_vars(py); - panic!("Python execution failed.") - } - } - } - - pub fn print_src(&self) { - println!("{}", self.py_src); - } -} diff --git a/token-swap/program/src/constraints.rs b/token-swap/program/src/constraints.rs index 4498af07304..66e9c3ec9b1 100644 --- a/token-swap/program/src/constraints.rs +++ b/token-swap/program/src/constraints.rs @@ -1,16 +1,17 @@ //! Various constraints as required for production environments -use crate::{ - curve::{ - base::{CurveType, SwapCurve}, - fees::Fees, +#[cfg(feature = "production")] +use std::option_env; +use { + crate::{ + curve::{ + base::{CurveType, SwapCurve}, + fees::Fees, + }, + error::SwapError, }, - error::SwapError, + solana_program::program_error::ProgramError, }; -use solana_program::program_error::ProgramError; - -#[cfg(feature = "production")] -use std::env; /// Encodes fee constraints, used in multihost environments where the program /// may be used by multiple frontends, to ensure that proper fees are being @@ -20,7 +21,7 @@ use std::env; /// cannot be used, so we have to split the curves based on their types. pub struct SwapConstraints<'a> { /// Owner of the program - pub owner_key: &'a str, + pub owner_key: Option<&'a str>, /// Valid curve types pub valid_curve_types: &'a [CurveType], /// Valid fees @@ -60,7 +61,7 @@ impl<'a> SwapConstraints<'a> { } #[cfg(feature = "production")] -const OWNER_KEY: &str = env!("SWAP_PROGRAM_OWNER_FEE_ADDRESS"); +const OWNER_KEY: Option<&str> = option_env!("SWAP_PROGRAM_OWNER_FEE_ADDRESS"); #[cfg(feature = "production")] const FEES: &Fees = &Fees { trade_fee_numerator: 0, @@ -98,9 +99,11 @@ pub const SWAP_CONSTRAINTS: Option = { #[cfg(test)] mod tests { - use super::*; - use crate::curve::{base::CurveType, constant_product::ConstantProductCurve}; - use std::sync::Arc; + use { + super::*, + crate::curve::{base::CurveType, constant_product::ConstantProductCurve}, + std::sync::Arc, + }; #[test] fn validate_fees() { @@ -112,7 +115,7 @@ mod tests { let owner_withdraw_fee_denominator = 10; let host_fee_numerator = 10; let host_fee_denominator = 100; - let owner_key = ""; + let owner_key = Some(""); let curve_type = CurveType::ConstantProduct; let valid_fees = Fees { trade_fee_numerator, diff --git a/token-swap/program/src/curve/base.rs b/token-swap/program/src/curve/base.rs index 85ad6ac661a..2014437bae7 100644 --- a/token-swap/program/src/curve/base.rs +++ b/token-swap/program/src/curve/base.rs @@ -1,37 +1,37 @@ //! Base curve implementation -use solana_program::{ - program_error::ProgramError, - program_pack::{Pack, Sealed}, -}; - -use crate::curve::{ - calculator::{CurveCalculator, SwapWithoutFeesResult, TradeDirection}, - constant_price::ConstantPriceCurve, - constant_product::ConstantProductCurve, - fees::Fees, - offset::OffsetCurve, - stable::StableCurve, -}; -use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}; -use std::convert::{TryFrom, TryInto}; -use std::fmt::Debug; -use std::sync::Arc; - #[cfg(feature = "fuzz")] use arbitrary::Arbitrary; +use { + crate::curve::{ + calculator::{CurveCalculator, RoundDirection, SwapWithoutFeesResult, TradeDirection}, + constant_price::ConstantPriceCurve, + constant_product::ConstantProductCurve, + fees::Fees, + offset::OffsetCurve, + }, + arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}, + solana_program::{ + program_error::ProgramError, + program_pack::{Pack, Sealed}, + }, + std::{ + convert::{TryFrom, TryInto}, + fmt::Debug, + sync::Arc, + }, +}; /// Curve types supported by the token-swap program. #[cfg_attr(feature = "fuzz", derive(Arbitrary))] #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq)] pub enum CurveType { - /// Uniswap-style constant product curve, invariant = token_a_amount * token_b_amount + /// Uniswap-style constant product curve, invariant = token_a_amount * + /// token_b_amount ConstantProduct, /// Flat line, always providing 1:1 from one token to another ConstantPrice, - /// Stable, like uniswap, but with wide zone of 1:1 instead of one point - Stable, /// Offset curve, like Uniswap, but the token B side has a faked offset Offset, } @@ -123,7 +123,9 @@ impl SwapCurve { // https://github.com/balancer-labs/balancer-core/blob/f4ed5d65362a8d6cec21662fb6eae233b0babc1f/contracts/BMath.sol#L117 let half_source_amount = std::cmp::max(1, source_amount.checked_div(2)?); let trade_fee = fees.trading_fee(half_source_amount)?; - let source_amount = source_amount.checked_sub(trade_fee)?; + let owner_fee = fees.owner_trading_fee(half_source_amount)?; + let total_fees = trade_fee.checked_add(owner_fee)?; + let source_amount = source_amount.checked_sub(total_fees)?; self.calculator.deposit_single_token_type( source_amount, swap_token_a_amount, @@ -146,18 +148,22 @@ impl SwapCurve { if source_amount == 0 { return Some(0); } - // Get the trading fee incurred if *half* the source amount is swapped - // for the other side. Reference at: + // Since we want to get the amount required to get the exact amount out, + // we need the inverse trading fee incurred if *half* the source amount + // is swapped for the other side. Reference at: // https://github.com/balancer-labs/balancer-core/blob/f4ed5d65362a8d6cec21662fb6eae233b0babc1f/contracts/BMath.sol#L117 - let half_source_amount = std::cmp::max(1, source_amount.checked_div(2)?); - let trade_fee = fees.trading_fee(half_source_amount)?; - let source_amount = source_amount.checked_sub(trade_fee)?; + let half_source_amount = source_amount.checked_add(1)?.checked_div(2)?; // round up + let pre_fee_source_amount = fees.pre_trading_fee_amount(half_source_amount)?; + let source_amount = source_amount + .checked_sub(half_source_amount)? + .checked_add(pre_fee_source_amount)?; self.calculator.withdraw_single_token_type_exact_out( source_amount, swap_token_a_amount, swap_token_b_amount, pool_supply, trade_direction, + RoundDirection::Ceiling, ) } } @@ -201,8 +207,8 @@ impl PartialEq for SwapCurve { impl Sealed for SwapCurve {} impl Pack for SwapCurve { - /// Size of encoding of all curve parameters, which include fees and any other - /// constants used to calculate swaps, deposits, and withdrawals. + /// Size of encoding of all curve parameters, which include fees and any + /// other constants used to calculate swaps, deposits, and withdrawals. /// This includes 1 byte for the type, and 72 for the calculator to use as /// it needs. Some calculators may be smaller than 72 bytes. const LEN: usize = 33; @@ -222,7 +228,6 @@ impl Pack for SwapCurve { CurveType::ConstantPrice => { Arc::new(ConstantPriceCurve::unpack_from_slice(calculator)?) } - CurveType::Stable => Arc::new(StableCurve::unpack_from_slice(calculator)?), CurveType::Offset => Arc::new(OffsetCurve::unpack_from_slice(calculator)?), }, }) @@ -252,16 +257,15 @@ impl TryFrom for CurveType { match curve_type { 0 => Ok(CurveType::ConstantProduct), 1 => Ok(CurveType::ConstantPrice), - 2 => Ok(CurveType::Stable), - 3 => Ok(CurveType::Offset), + 2 => Ok(CurveType::Offset), _ => Err(ProgramError::InvalidAccountData), } } } #[cfg(test)] -mod tests { - use super::*; +mod test { + use {super::*, crate::curve::calculator::test::total_and_intermediate, proptest::prelude::*}; #[test] fn pack_swap_curve() { @@ -379,7 +383,7 @@ mod tests { let swap_source_amount: u128 = 1_000; let swap_destination_amount: u128 = 50_000; let source_amount: u128 = 100; - let curve = ConstantProductCurve::default(); + let curve = ConstantProductCurve; let fees = Fees::default(); let swap_curve = SwapCurve { curve_type: CurveType::ConstantProduct, @@ -398,4 +402,170 @@ mod tests { assert_eq!(result.destination_amount_swapped, 4545); assert_eq!(result.new_swap_destination_amount, 45455); } + + fn one_sided_deposit_vs_swap( + source_amount: u128, + swap_source_amount: u128, + swap_destination_amount: u128, + pool_supply: u128, + fees: Fees, + ) -> (u128, u128) { + let curve = ConstantProductCurve; + let swap_curve = SwapCurve { + curve_type: CurveType::ConstantProduct, + calculator: Arc::new(curve), + }; + // do the A to B swap + let results = swap_curve + .swap( + source_amount, + swap_source_amount, + swap_destination_amount, + TradeDirection::AtoB, + &fees, + ) + .unwrap(); + + // deposit just A, get pool tokens + let deposit_pool_tokens = swap_curve + .deposit_single_token_type( + results.source_amount_swapped, + swap_source_amount, + swap_destination_amount, + pool_supply, + TradeDirection::AtoB, + &fees, + ) + .unwrap(); + let withdraw_pool_tokens = swap_curve + .withdraw_single_token_type_exact_out( + results.destination_amount_swapped, + swap_source_amount + results.source_amount_swapped, + swap_destination_amount, + pool_supply + deposit_pool_tokens, + TradeDirection::BtoA, + &fees, + ) + .unwrap(); + (withdraw_pool_tokens, deposit_pool_tokens) + } + + #[test] + fn one_sided_equals_swap_with_fee_specific() { + let pool_supply: u128 = 1_000_000; + let swap_source_amount: u128 = 1_000_000; + let swap_destination_amount: u128 = 50_000_000; + let source_amount: u128 = 10_000; + let fees = Fees { + trade_fee_numerator: 25, + trade_fee_denominator: 1_000, + owner_trade_fee_numerator: 5, + owner_trade_fee_denominator: 1_000, + ..Fees::default() + }; + let (withdraw_pool_tokens, deposit_pool_tokens) = one_sided_deposit_vs_swap( + source_amount, + swap_source_amount, + swap_destination_amount, + pool_supply, + fees, + ); + // these checks *must* always hold + assert!(withdraw_pool_tokens >= deposit_pool_tokens); + let epsilon = 2; + assert!(withdraw_pool_tokens - deposit_pool_tokens <= epsilon); + + // these checks may change if the calc is updated + assert_eq!(withdraw_pool_tokens, 4914); + assert_eq!(deposit_pool_tokens, 4912); + } + + proptest! { + #[test] + fn one_sided_equals_swap_with_fee( + (swap_source_amount, source_amount) in total_and_intermediate(u64::MAX), + swap_destination_amount in 1..u64::MAX, + pool_supply in 1..u64::MAX, + ) { + let fees = Fees { + trade_fee_numerator: 25, + trade_fee_denominator: 1_000, + owner_trade_fee_numerator: 5, + owner_trade_fee_denominator: 1_000, + ..Fees::default() + }; + let (withdraw_pool_tokens, deposit_pool_tokens) = one_sided_deposit_vs_swap( + pool_supply.into(), + swap_source_amount.into(), + swap_destination_amount.into(), + source_amount.into(), + fees + ); + // the cost to withdraw B must always be higher than the amount gained through deposit + assert!(withdraw_pool_tokens >= deposit_pool_tokens); + } + + #[test] + fn one_sided_equals_swap_with_withdrawal_fee( + (swap_source_amount, source_amount) in total_and_intermediate(u64::MAX), + swap_destination_amount in 1..u64::MAX, + pool_supply in 1..u64::MAX, + ) { + let fees = Fees { + trade_fee_numerator: 25, + trade_fee_denominator: 1_000, + owner_trade_fee_numerator: 5, + owner_trade_fee_denominator: 1_000, + owner_withdraw_fee_numerator: 1, + owner_withdraw_fee_denominator: 1_000, + ..Fees::default() + }; + let (withdraw_pool_tokens, deposit_pool_tokens) = one_sided_deposit_vs_swap( + pool_supply.into(), + swap_source_amount.into(), + swap_destination_amount.into(), + source_amount.into(), + fees + ); + // the cost to withdraw B must always be higher than the amount gained through deposit + assert!(withdraw_pool_tokens >= deposit_pool_tokens); + } + + #[test] + fn one_sided_equals_swap_without_fee( + (swap_source_amount, source_amount) in total_and_intermediate(u64::MAX), + swap_destination_amount in 1..u64::MAX, + pool_supply in 1..u64::MAX, + ) { + let fees = Fees::default(); + let (withdraw_pool_tokens, deposit_pool_tokens) = one_sided_deposit_vs_swap( + pool_supply.into(), + swap_source_amount.into(), + swap_destination_amount.into(), + source_amount.into(), + fees + ); + let difference = if withdraw_pool_tokens >= deposit_pool_tokens { + withdraw_pool_tokens - deposit_pool_tokens + } else { + deposit_pool_tokens - withdraw_pool_tokens + }; + // Accurate to one part in 1,000,000 -- without fees, it can go either + // way due to vast differences in the pool token and trading token + // amounts. + // For example, if there's only 1 pool token and 1 destination token, + // but a source amount of 1,000,000,000, we can lose up to 1,000,000,000 + // in precision during an operation. + // See the proptests in calculator.rs for more specific versions. + let epsilon = std::cmp::max(1, withdraw_pool_tokens / 1_000_000); + assert!( + difference <= epsilon, + "difference between {} and {} expected to be less than {}, actually {}", + withdraw_pool_tokens, + deposit_pool_tokens, + epsilon, + difference + ); + } + } } diff --git a/token-swap/program/src/curve/calculator.rs b/token-swap/program/src/curve/calculator.rs index 90af0a5f6fd..36d9de468ea 100644 --- a/token-swap/program/src/curve/calculator.rs +++ b/token-swap/program/src/curve/calculator.rs @@ -1,9 +1,8 @@ //! Swap calculations -use {crate::error::SwapError, spl_math::precise_number::PreciseNumber, std::fmt::Debug}; - #[cfg(feature = "fuzz")] use arbitrary::Arbitrary; +use {crate::error::SwapError, spl_math::precise_number::PreciseNumber, std::fmt::Debug}; /// Initial amount of pool tokens for swap contract, hard-coded to something /// "sensible" given a maximum of u128. @@ -115,8 +114,8 @@ pub trait CurveCalculator: Debug + DynPack { /// Get the amount of pool tokens for the deposited amount of token A or B. /// /// This is used for single-sided deposits. It essentially performs a swap - /// followed by a deposit. Because a swap is implicitly performed, this will - /// change the spot price of the pool. + /// followed by a deposit. Because a swap is implicitly performed, this + /// will change the spot price of the pool. /// /// See more background for the calculation at: /// @@ -147,6 +146,7 @@ pub trait CurveCalculator: Debug + DynPack { swap_token_b_amount: u128, pool_supply: u128, trade_direction: TradeDirection, + round_direction: RoundDirection, ) -> Option; /// Validate that the given curve has no invalid parameters @@ -194,9 +194,7 @@ pub trait CurveCalculator: Debug + DynPack { /// Test helpers for curves #[cfg(test)] pub mod test { - use super::*; - use proptest::prelude::*; - use spl_math::uint::U256; + use {super::*, proptest::prelude::*, spl_math::uint::U256}; /// The epsilon for most curves when performing the conversion test, /// comparing a one-sided deposit to a swap + deposit. @@ -294,13 +292,13 @@ pub mod test { ); } - /// Test function to check that withdrawing token A is the same as withdrawing - /// both and swapping one side. + /// Test function to check that withdrawing token A is the same as + /// withdrawing both and swapping one side. /// Since calculations use unsigned integers, there will be truncation at /// some point, meaning we can't have perfect equality. /// We guarantee that the relative error between withdrawing one side and - /// performing a withdraw plus a swap will be at most some epsilon provided by - /// the curve. Most curves guarantee accuracy within 0.5%. + /// performing a withdraw plus a swap will be at most some epsilon provided + /// by the curve. Most curves guarantee accuracy within 0.5%. pub fn check_withdraw_token_conversion( curve: &dyn CurveCalculator, pool_token_amount: u128, @@ -360,6 +358,7 @@ pub mod test { swap_token_b_amount, pool_token_supply, opposite_direction, + RoundDirection::Ceiling, ) .unwrap(); @@ -516,9 +515,9 @@ pub mod test { let value = curve .normalized_value(swap_token_a_amount, swap_token_b_amount) .unwrap(); - // since we can get rounding issues on the pool value which make it seem that the - // value per token has gone down, we bump it up by an epsilon of 1 to - // cover all cases + // since we can get rounding issues on the pool value which make it seem that + // the value per token has gone down, we bump it up by an epsilon of 1 + // to cover all cases let new_value = curve .normalized_value(new_swap_token_a_amount, new_swap_token_b_amount) .unwrap(); @@ -537,7 +536,7 @@ pub mod test { } prop_compose! { - pub fn total_and_intermediate()(total in 1..u64::MAX) + pub fn total_and_intermediate(max_value: u64)(total in 1..max_value) (intermediate in 1..total, total in Just(total)) -> (u64, u64) { (total, intermediate) diff --git a/token-swap/program/src/curve/constant_price.rs b/token-swap/program/src/curve/constant_price.rs index 61b9f16a304..b9e5272b50a 100644 --- a/token-swap/program/src/curve/constant_price.rs +++ b/token-swap/program/src/curve/constant_price.rs @@ -173,6 +173,7 @@ impl CurveCalculator for ConstantPriceCurve { swap_token_b_amount: u128, pool_supply: u128, trade_direction: TradeDirection, + round_direction: RoundDirection, ) -> Option { trading_tokens_to_pool_tokens( self.token_b_price, @@ -181,7 +182,7 @@ impl CurveCalculator for ConstantPriceCurve { swap_token_b_amount, pool_supply, trade_direction, - RoundDirection::Ceiling, + round_direction, ) } @@ -216,8 +217,8 @@ impl CurveCalculator for ConstantPriceCurve { ) -> Option { let swap_token_b_value = swap_token_b_amount.checked_mul(self.token_b_price as u128)?; // special logic in case we're close to the limits, avoid overflowing u128 - let value = if swap_token_b_value.saturating_sub(std::u64::MAX.into()) - > (std::u128::MAX.saturating_sub(std::u64::MAX.into())) + let value = if swap_token_b_value.saturating_sub(u64::MAX.into()) + > (u128::MAX.saturating_sub(u64::MAX.into())) { swap_token_b_value .checked_div(2)? @@ -261,16 +262,18 @@ impl DynPack for ConstantPriceCurve { #[cfg(test)] mod tests { - use super::*; - use crate::curve::calculator::{ - test::{ - check_curve_value_from_swap, check_deposit_token_conversion, - check_withdraw_token_conversion, total_and_intermediate, - CONVERSION_BASIS_POINTS_GUARANTEE, + use { + super::*, + crate::curve::calculator::{ + test::{ + check_curve_value_from_swap, check_deposit_token_conversion, + check_withdraw_token_conversion, total_and_intermediate, + CONVERSION_BASIS_POINTS_GUARANTEE, + }, + INITIAL_SWAP_POOL_AMOUNT, }, - INITIAL_SWAP_POOL_AMOUNT, + proptest::prelude::*, }; - use proptest::prelude::*; #[test] fn swap_calculation_no_price() { @@ -454,7 +457,7 @@ mod tests { proptest! { #[test] fn withdraw_token_conversion( - (pool_token_supply, pool_token_amount) in total_and_intermediate(), + (pool_token_supply, pool_token_amount) in total_and_intermediate(u64::MAX), swap_token_a_amount in 1..u64::MAX, swap_token_b_amount in 1..u32::MAX, // kept small to avoid proptest rejections token_b_price in 1..u32::MAX, // kept small to avoid proptest rejections @@ -492,7 +495,8 @@ mod tests { swap_token_a_amount, swap_token_b_amount, TradeDirection::AtoB, - CONVERSION_BASIS_POINTS_GUARANTEE + // TODO see why this needs to be so high + CONVERSION_BASIS_POINTS_GUARANTEE * 20 ); check_withdraw_token_conversion( &curve, @@ -501,7 +505,8 @@ mod tests { swap_token_a_amount, swap_token_b_amount, TradeDirection::BtoA, - CONVERSION_BASIS_POINTS_GUARANTEE + // TODO see why this needs to be so high + CONVERSION_BASIS_POINTS_GUARANTEE * 20 ); } } @@ -568,7 +573,6 @@ mod tests { ) { let curve = ConstantPriceCurve { token_b_price: token_b_price as u64 }; let pool_token_amount = pool_token_amount as u128; - let pool_token_supply = pool_token_supply as u128; let swap_token_a_amount = swap_token_a_amount as u128; let swap_token_b_amount = swap_token_b_amount as u128; let token_b_price = token_b_price as u128; @@ -609,7 +613,7 @@ mod tests { proptest! { #[test] fn curve_value_does_not_decrease_from_withdraw( - (pool_token_supply, pool_token_amount) in total_and_intermediate(), + (pool_token_supply, pool_token_amount) in total_and_intermediate(u64::MAX), swap_token_a_amount in 1..u64::MAX, swap_token_b_amount in 1..u32::MAX, // kept small to avoid proptest rejections token_b_price in 1..u32::MAX, // kept small to avoid proptest rejections diff --git a/token-swap/program/src/curve/constant_product.rs b/token-swap/program/src/curve/constant_product.rs index 9b3363f4b57..c13a66b564d 100644 --- a/token-swap/program/src/curve/constant_product.rs +++ b/token-swap/program/src/curve/constant_product.rs @@ -48,8 +48,8 @@ pub fn swap( /// Get the amount of trading tokens for the given amount of pool tokens, /// provided the total trading tokens and supply of pool tokens. /// -/// The constant product implementation is a simple ratio calculation for how many -/// trading tokens correspond to a certain number of pool tokens +/// The constant product implementation is a simple ratio calculation for how +/// many trading tokens correspond to a certain number of pool tokens pub fn pool_tokens_to_trading_tokens( pool_tokens: u128, pool_token_supply: u128, @@ -144,7 +144,9 @@ pub fn withdraw_single_token_type_exact_out( let source_amount = PreciseNumber::new(source_amount)?; let ratio = source_amount.checked_div(&swap_source_amount)?; let one = PreciseNumber::new(1)?; - let base = one.checked_sub(&ratio)?; + let base = one + .checked_sub(&ratio) + .unwrap_or_else(|| PreciseNumber::new(0).unwrap()); let root = one.checked_sub(&base.sqrt()?)?; let pool_supply = PreciseNumber::new(pool_supply)?; let pool_tokens = pool_supply.checked_mul(&root)?; @@ -157,8 +159,8 @@ pub fn withdraw_single_token_type_exact_out( /// Calculates the total normalized value of the curve given the liquidity /// parameters. /// -/// The constant product implementation for this function gives the square root of -/// the Uniswap invariant. +/// The constant product implementation for this function gives the square root +/// of the Uniswap invariant. pub fn normalized_value( swap_token_a_amount: u128, swap_token_b_amount: u128, @@ -182,8 +184,9 @@ impl CurveCalculator for ConstantProductCurve { swap(source_amount, swap_source_amount, swap_destination_amount) } - /// The constant product implementation is a simple ratio calculation for how many - /// trading tokens correspond to a certain number of pool tokens + /// The constant product implementation is a simple ratio calculation for + /// how many trading tokens correspond to a certain number of pool + /// tokens fn pool_tokens_to_trading_tokens( &self, pool_tokens: u128, @@ -227,6 +230,7 @@ impl CurveCalculator for ConstantProductCurve { swap_token_b_amount: u128, pool_supply: u128, trade_direction: TradeDirection, + round_direction: RoundDirection, ) -> Option { withdraw_single_token_type_exact_out( source_amount, @@ -234,7 +238,7 @@ impl CurveCalculator for ConstantProductCurve { swap_token_b_amount, pool_supply, trade_direction, - RoundDirection::Ceiling, + round_direction, ) } @@ -275,17 +279,19 @@ impl DynPack for ConstantProductCurve { #[cfg(test)] mod tests { - use super::*; - use crate::curve::calculator::{ - test::{ - check_curve_value_from_swap, check_deposit_token_conversion, - check_pool_value_from_deposit, check_pool_value_from_withdraw, - check_withdraw_token_conversion, total_and_intermediate, - CONVERSION_BASIS_POINTS_GUARANTEE, + use { + super::*, + crate::curve::calculator::{ + test::{ + check_curve_value_from_swap, check_deposit_token_conversion, + check_pool_value_from_deposit, check_pool_value_from_withdraw, + check_withdraw_token_conversion, total_and_intermediate, + CONVERSION_BASIS_POINTS_GUARANTEE, + }, + RoundDirection, INITIAL_SWAP_POOL_AMOUNT, }, - RoundDirection, INITIAL_SWAP_POOL_AMOUNT, + proptest::prelude::*, }; - use proptest::prelude::*; #[test] fn initial_pool_amount() { @@ -376,7 +382,7 @@ mod tests { #[test] fn constant_product_swap_rounding() { - let curve = ConstantProductCurve::default(); + let curve = ConstantProductCurve; // much too small assert!(curve @@ -384,16 +390,26 @@ mod tests { .is_none()); // spot: 10 * 4m / 70b = 0 let tests: &[(u128, u128, u128, u128, u128)] = &[ - (10, 4_000_000, 70_000_000_000, 10, 174_999), // spot: 10 * 70b / ~4m = 174,999.99 - (20, 30_000 - 20, 10_000, 18, 6), // spot: 20 * 1 / 3.000 = 6.6667 (source can be 18 to get 6 dest.) - (19, 30_000 - 20, 10_000, 18, 6), // spot: 19 * 1 / 2.999 = 6.3334 (source can be 18 to get 6 dest.) - (18, 30_000 - 20, 10_000, 18, 6), // spot: 18 * 1 / 2.999 = 6.0001 - (10, 20_000, 30_000, 10, 14), // spot: 10 * 3 / 2.0010 = 14.99 - (10, 20_000 - 9, 30_000, 10, 14), // spot: 10 * 3 / 2.0001 = 14.999 - (10, 20_000 - 10, 30_000, 10, 15), // spot: 10 * 3 / 2.0000 = 15 - (100, 60_000, 30_000, 99, 49), // spot: 100 * 3 / 6.001 = 49.99 (source can be 99 to get 49 dest.) - (99, 60_000, 30_000, 99, 49), // spot: 99 * 3 / 6.001 = 49.49 - (98, 60_000, 30_000, 97, 48), // spot: 98 * 3 / 6.001 = 48.99 (source can be 97 to get 48 dest.) + // spot: 10 * 70b / ~4m = 174,999.99 + (10, 4_000_000, 70_000_000_000, 10, 174_999), + // spot: 20 * 1 / 3.000 = 6.6667 (source can be 18 to get 6 dest.) + (20, 30_000 - 20, 10_000, 18, 6), + // spot: 19 * 1 / 2.999 = 6.3334 (source can be 18 to get 6 dest.) + (19, 30_000 - 20, 10_000, 18, 6), + // spot: 18 * 1 / 2.999 = 6.0001 + (18, 30_000 - 20, 10_000, 18, 6), + // spot: 10 * 3 / 2.0010 = 14.99 + (10, 20_000, 30_000, 10, 14), + // spot: 10 * 3 / 2.0001 = 14.999 + (10, 20_000 - 9, 30_000, 10, 14), + // spot: 10 * 3 / 2.0000 = 15 + (10, 20_000 - 10, 30_000, 10, 15), + // spot: 100 * 3 / 6.001 = 49.99 (source can be 99 to get 49 dest.) + (100, 60_000, 30_000, 99, 49), + // spot: 99 * 3 / 6.001 = 49.49 + (99, 60_000, 30_000, 99, 49), + // spot: 98 * 3 / 6.001 = 48.99 (source can be 97 to get 48 dest.) + (98, 60_000, 30_000, 97, 48), ]; for ( source_amount, @@ -450,7 +466,7 @@ mod tests { proptest! { #[test] fn withdraw_token_conversion( - (pool_token_supply, pool_token_amount) in total_and_intermediate(), + (pool_token_supply, pool_token_amount) in total_and_intermediate(u64::MAX), swap_token_a_amount in 1..u64::MAX, swap_token_b_amount in 1..u64::MAX, ) { @@ -524,7 +540,7 @@ mod tests { proptest! { #[test] fn curve_value_does_not_decrease_from_withdraw( - (pool_token_supply, pool_token_amount) in total_and_intermediate(), + (pool_token_supply, pool_token_amount) in total_and_intermediate(u64::MAX), swap_token_a_amount in 1..u64::MAX, swap_token_b_amount in 1..u64::MAX, ) { diff --git a/token-swap/program/src/curve/fees.rs b/token-swap/program/src/curve/fees.rs index 53fcad2eed4..844a6342315 100644 --- a/token-swap/program/src/curve/fees.rs +++ b/token-swap/program/src/curve/fees.rs @@ -1,12 +1,13 @@ //! All fee information, to be used for validation currently -use crate::error::SwapError; -use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}; -use solana_program::{ - program_error::ProgramError, - program_pack::{IsInitialized, Pack, Sealed}, +use { + crate::error::SwapError, + arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}, + solana_program::{ + program_error::ProgramError, + program_pack::{IsInitialized, Pack, Sealed}, + }, }; -use std::convert::TryFrom; /// Encapsulates all fee information and calculations for swap operations #[derive(Clone, Debug, Default, PartialEq)] @@ -18,9 +19,9 @@ pub struct Fees { /// Trade fee denominator pub trade_fee_denominator: u64, - /// Owner trading fees are extra token amounts that are held inside the token - /// accounts during a trade, with the equivalent in pool tokens minted to - /// the owner of the program. + /// Owner trading fees are extra token amounts that are held inside the + /// token accounts during a trade, with the equivalent in pool tokens + /// minted to the owner of the program. /// Owner trade fee numerator pub owner_trade_fee_numerator: u64, /// Owner trade fee denominator @@ -61,6 +62,29 @@ pub fn calculate_fee( } } +fn ceil_div(dividend: u128, divisor: u128) -> Option { + dividend + .checked_add(divisor)? + .checked_sub(1)? + .checked_div(divisor) +} + +fn pre_fee_amount( + post_fee_amount: u128, + fee_numerator: u128, + fee_denominator: u128, +) -> Option { + if fee_numerator == 0 || fee_denominator == 0 { + Some(post_fee_amount) + } else if fee_numerator == fee_denominator || post_fee_amount == 0 { + Some(0) + } else { + let numerator = post_fee_amount.checked_mul(fee_denominator)?; + let denominator = fee_denominator.checked_sub(fee_numerator)?; + ceil_div(numerator, denominator) + } +} + fn validate_fraction(numerator: u64, denominator: u64) -> Result<(), SwapError> { if denominator == 0 && numerator == 0 { Ok(()) @@ -76,8 +100,8 @@ impl Fees { pub fn owner_withdraw_fee(&self, pool_tokens: u128) -> Option { calculate_fee( pool_tokens, - u128::try_from(self.owner_withdraw_fee_numerator).ok()?, - u128::try_from(self.owner_withdraw_fee_denominator).ok()?, + u128::from(self.owner_withdraw_fee_numerator), + u128::from(self.owner_withdraw_fee_denominator), ) } @@ -85,8 +109,8 @@ impl Fees { pub fn trading_fee(&self, trading_tokens: u128) -> Option { calculate_fee( trading_tokens, - u128::try_from(self.trade_fee_numerator).ok()?, - u128::try_from(self.trade_fee_denominator).ok()?, + u128::from(self.trade_fee_numerator), + u128::from(self.trade_fee_denominator), ) } @@ -94,18 +118,48 @@ impl Fees { pub fn owner_trading_fee(&self, trading_tokens: u128) -> Option { calculate_fee( trading_tokens, - u128::try_from(self.owner_trade_fee_numerator).ok()?, - u128::try_from(self.owner_trade_fee_denominator).ok()?, + u128::from(self.owner_trade_fee_numerator), + u128::from(self.owner_trade_fee_denominator), ) } + /// Calculate the inverse trading amount, how much input is needed to give + /// the provided output + pub fn pre_trading_fee_amount(&self, post_fee_amount: u128) -> Option { + if self.trade_fee_numerator == 0 || self.trade_fee_denominator == 0 { + pre_fee_amount( + post_fee_amount, + self.owner_trade_fee_numerator as u128, + self.owner_trade_fee_denominator as u128, + ) + } else if self.owner_trade_fee_numerator == 0 || self.owner_trade_fee_denominator == 0 { + pre_fee_amount( + post_fee_amount, + self.trade_fee_numerator as u128, + self.trade_fee_denominator as u128, + ) + } else { + pre_fee_amount( + post_fee_amount, + (self.trade_fee_numerator as u128) + .checked_mul(self.owner_trade_fee_denominator as u128)? + .checked_add( + (self.owner_trade_fee_numerator as u128) + .checked_mul(self.trade_fee_denominator as u128)?, + )?, + (self.trade_fee_denominator as u128) + .checked_mul(self.owner_trade_fee_denominator as u128)?, + ) + } + } + /// Calculate the host fee based on the owner fee, only used in production /// situations where a program is hosted by multiple frontends pub fn host_fee(&self, owner_fee: u128) -> Option { calculate_fee( owner_fee, - u128::try_from(self.host_fee_numerator).ok()?, - u128::try_from(self.host_fee_denominator).ok()?, + u128::from(self.host_fee_numerator), + u128::from(self.host_fee_denominator), ) } diff --git a/token-swap/program/src/curve/mod.rs b/token-swap/program/src/curve/mod.rs index d7acbcf0eef..9d1fe8946c7 100644 --- a/token-swap/program/src/curve/mod.rs +++ b/token-swap/program/src/curve/mod.rs @@ -6,4 +6,3 @@ pub mod constant_price; pub mod constant_product; pub mod fees; pub mod offset; -pub mod stable; diff --git a/token-swap/program/src/curve/offset.rs b/token-swap/program/src/curve/offset.rs index 1498a271ce7..8d5937536d0 100644 --- a/token-swap/program/src/curve/offset.rs +++ b/token-swap/program/src/curve/offset.rs @@ -33,8 +33,11 @@ pub struct OffsetCurve { impl CurveCalculator for OffsetCurve { /// Constant product swap ensures token a * (token b + offset) = constant /// This is guaranteed to work for all values such that: + /// /// - 1 <= source_amount <= u64::MAX - /// - 1 <= (swap_source_amount * (swap_destination_amount + token_b_offset)) <= u128::MAX + /// - 1 <= (swap_source_amount * (swap_destination_amount + + /// token_b_offset)) <= u128::MAX + /// /// If the offset and token B are both close to u64::MAX, there can be /// overflow errors with the invariant. fn swap_without_fees( @@ -104,6 +107,7 @@ impl CurveCalculator for OffsetCurve { swap_token_b_amount: u128, pool_supply: u128, trade_direction: TradeDirection, + round_direction: RoundDirection, ) -> Option { let token_b_offset = self.token_b_offset as u128; withdraw_single_token_type_exact_out( @@ -112,7 +116,7 @@ impl CurveCalculator for OffsetCurve { swap_token_b_amount.checked_add(token_b_offset)?, pool_supply, trade_direction, - RoundDirection::Ceiling, + round_direction, ) } @@ -140,8 +144,8 @@ impl CurveCalculator for OffsetCurve { false } - /// The normalized value of the offset curve simply needs to add the offset to - /// the token B side before calculating + /// The normalized value of the offset curve simply needs to add the offset + /// to the token B side before calculating fn normalized_value( &self, swap_token_a_amount: u128, @@ -185,17 +189,19 @@ impl DynPack for OffsetCurve { #[cfg(test)] mod tests { - use super::*; - use crate::curve::calculator::{ - test::{ - check_curve_value_from_swap, check_deposit_token_conversion, - check_pool_value_from_deposit, check_pool_value_from_withdraw, - check_withdraw_token_conversion, total_and_intermediate, - CONVERSION_BASIS_POINTS_GUARANTEE, + use { + super::*, + crate::curve::calculator::{ + test::{ + check_curve_value_from_swap, check_deposit_token_conversion, + check_pool_value_from_deposit, check_pool_value_from_withdraw, + check_withdraw_token_conversion, total_and_intermediate, + CONVERSION_BASIS_POINTS_GUARANTEE, + }, + INITIAL_SWAP_POOL_AMOUNT, }, - INITIAL_SWAP_POOL_AMOUNT, + proptest::prelude::*, }; - use proptest::prelude::*; #[test] fn pack_curve() { @@ -394,7 +400,7 @@ mod tests { proptest! { #[test] fn withdraw_token_conversion( - (pool_token_supply, pool_token_amount) in total_and_intermediate(), + (pool_token_supply, pool_token_amount) in total_and_intermediate(u64::MAX), swap_token_a_amount in 1..u64::MAX, (swap_token_b_amount, token_b_offset) in values_sum_within_u64(), ) { @@ -473,9 +479,9 @@ mod tests { (swap_source_amount * swap_destination_amount)); check_curve_value_from_swap( &curve, - source_token_amount as u128, - swap_source_amount as u128, - swap_destination_amount as u128, + source_token_amount, + swap_source_amount, + swap_destination_amount, TradeDirection::AtoB ); } @@ -501,9 +507,9 @@ mod tests { prop_assume!(!(swap_source_amount + token_b_offset).overflowing_mul(swap_destination_amount).1); check_curve_value_from_swap( &curve, - source_token_amount as u128, - swap_source_amount as u128, - swap_destination_amount as u128, + source_token_amount, + swap_source_amount, + swap_destination_amount, TradeDirection::BtoA ); } @@ -541,7 +547,7 @@ mod tests { proptest! { #[test] fn curve_value_does_not_decrease_from_withdraw( - (pool_token_supply, pool_token_amount) in total_and_intermediate(), + (pool_token_supply, pool_token_amount) in total_and_intermediate(u64::MAX), swap_token_a_amount in 1..u64::MAX, (swap_token_b_amount, token_b_offset) in values_sum_within_u64(), ) { diff --git a/token-swap/program/src/curve/stable.rs b/token-swap/program/src/curve/stable.rs deleted file mode 100644 index 9ec7b2fd4a1..00000000000 --- a/token-swap/program/src/curve/stable.rs +++ /dev/null @@ -1,665 +0,0 @@ -//! The curve.fi invariant calculator. -use { - crate::{ - curve::calculator::{ - CurveCalculator, DynPack, RoundDirection, SwapWithoutFeesResult, TradeDirection, - TradingTokenResult, - }, - error::SwapError, - }, - arrayref::{array_mut_ref, array_ref}, - solana_program::{ - program_error::ProgramError, - program_pack::{IsInitialized, Pack, Sealed}, - }, - spl_math::{checked_ceil_div::CheckedCeilDiv, precise_number::PreciseNumber, uint::U256}, - std::convert::TryFrom, -}; - -const N_COINS: u8 = 2; -const N_COINS_SQUARED: u8 = 4; -const ITERATIONS: u8 = 32; - -/// Calculates A for deriving D -/// -/// Per discussion with the designer and writer of stable curves, this A is not -/// the same as the A from the whitepaper, it's actually `A * n**(n-1)`, so when -/// you set A, you actually set `A * n**(n-1)`. This is because `D**n / prod(x)` -/// loses precision with a huge A value. -/// -/// There is little information to document this choice, but the original contracts -/// use this same convention, see a comment in the code at: -/// https://github.com/curvefi/curve-contract/blob/b0bbf77f8f93c9c5f4e415bce9cd71f0cdee960e/contracts/pool-templates/base/SwapTemplateBase.vy#L136 -fn compute_a(amp: u64) -> Option { - amp.checked_mul(N_COINS as u64) -} - -/// Returns self to the power of b -fn checked_u8_power(a: &U256, b: u8) -> Option { - let mut result = *a; - for _ in 1..b { - result = result.checked_mul(*a)?; - } - Some(result) -} - -/// Returns self multiplied by b -fn checked_u8_mul(a: &U256, b: u8) -> Option { - let mut result = *a; - for _ in 1..b { - result = result.checked_add(*a)?; - } - Some(result) -} - -/// StableCurve struct implementing CurveCalculator -#[derive(Clone, Debug, Default, PartialEq)] -pub struct StableCurve { - /// Amplifier constant - pub amp: u64, -} - -/// d = (leverage * sum_x + d_product * n_coins) * initial_d / ((leverage - 1) * initial_d + (n_coins + 1) * d_product) -fn calculate_step(initial_d: &U256, leverage: u64, sum_x: u128, d_product: &U256) -> Option { - let leverage_mul = U256::from(leverage).checked_mul(sum_x.into())?; - let d_p_mul = checked_u8_mul(d_product, N_COINS)?; - - let l_val = leverage_mul.checked_add(d_p_mul)?.checked_mul(*initial_d)?; - - let leverage_sub = initial_d.checked_mul((leverage.checked_sub(1)?).into())?; - let n_coins_sum = checked_u8_mul(d_product, N_COINS.checked_add(1)?)?; - - let r_val = leverage_sub.checked_add(n_coins_sum)?; - - l_val.checked_div(r_val) -} - -/// Compute stable swap invariant (D) -/// Equation: -/// A * sum(x_i) * n**n + D = A * D * n**n + D**(n+1) / (n**n * prod(x_i)) -fn compute_d(leverage: u64, amount_a: u128, amount_b: u128) -> Option { - let amount_a_times_coins = - checked_u8_mul(&U256::from(amount_a), N_COINS)?.checked_add(U256::one())?; - let amount_b_times_coins = - checked_u8_mul(&U256::from(amount_b), N_COINS)?.checked_add(U256::one())?; - let sum_x = amount_a.checked_add(amount_b)?; // sum(x_i), a.k.a S - if sum_x == 0 { - Some(0) - } else { - let mut d_previous: U256; - let mut d: U256 = sum_x.into(); - - // Newton's method to approximate D - for _ in 0..ITERATIONS { - let mut d_product = d; - d_product = d_product - .checked_mul(d)? - .checked_div(amount_a_times_coins)?; - d_product = d_product - .checked_mul(d)? - .checked_div(amount_b_times_coins)?; - d_previous = d; - //d = (leverage * sum_x + d_p * n_coins) * d / ((leverage - 1) * d + (n_coins + 1) * d_p); - d = calculate_step(&d, leverage, sum_x, &d_product)?; - // Equality with the precision of 1 - if d == d_previous { - break; - } - } - u128::try_from(d).ok() - } -} - -/// Compute swap amount `y` in proportion to `x` -/// Solve for y: -/// y**2 + y * (sum' - (A*n**n - 1) * D / (A * n**n)) = D ** (n + 1) / (n ** (2 * n) * prod' * A) -/// y**2 + b*y = c -fn compute_new_destination_amount( - leverage: u64, - new_source_amount: u128, - d_val: u128, -) -> Option { - // Upscale to U256 - let leverage: U256 = leverage.into(); - let new_source_amount: U256 = new_source_amount.into(); - let d_val: U256 = d_val.into(); - let zero = U256::from(0u128); - let one = U256::from(1u128); - - // sum' = prod' = x - // c = D ** (n + 1) / (n ** (2 * n) * prod' * A) - let c = checked_u8_power(&d_val, N_COINS.checked_add(1)?)? - .checked_div(checked_u8_mul(&new_source_amount, N_COINS_SQUARED)?.checked_mul(leverage)?)?; - - // b = sum' - (A*n**n - 1) * D / (A * n**n) - let b = new_source_amount.checked_add(d_val.checked_div(leverage)?)?; - - // Solve for y by approximating: y**2 + b*y = c - let mut y = d_val; - for _ in 0..ITERATIONS { - let numerator = checked_u8_power(&y, 2)?.checked_add(c)?; - let denominator = checked_u8_mul(&y, 2)?.checked_add(b)?.checked_sub(d_val)?; - // checked_ceil_div is conservative, not allowing for a 0 return, but we can - // ceiling to 1 token in this case since we're solving through approximation, - // and not doing a constant product calculation - let (y_new, _) = numerator.checked_ceil_div(denominator).unwrap_or_else(|| { - if numerator == U256::from(0u128) { - (zero, zero) - } else { - (one, zero) - } - }); - if y_new == y { - break; - } else { - y = y_new; - } - } - u128::try_from(y).ok() -} - -impl CurveCalculator for StableCurve { - /// Stable curve - fn swap_without_fees( - &self, - source_amount: u128, - swap_source_amount: u128, - swap_destination_amount: u128, - _trade_direction: TradeDirection, - ) -> Option { - if source_amount == 0 { - return Some(SwapWithoutFeesResult { - source_amount_swapped: 0, - destination_amount_swapped: 0, - }); - } - let leverage = compute_a(self.amp)?; - - let new_source_amount = swap_source_amount.checked_add(source_amount)?; - let new_destination_amount = compute_new_destination_amount( - leverage, - new_source_amount, - compute_d(leverage, swap_source_amount, swap_destination_amount)?, - )?; - - let amount_swapped = swap_destination_amount.checked_sub(new_destination_amount)?; - - Some(SwapWithoutFeesResult { - source_amount_swapped: source_amount, - destination_amount_swapped: amount_swapped, - }) - } - - /// Re-implementation of `remove_liquidity`: - /// - /// - fn pool_tokens_to_trading_tokens( - &self, - pool_tokens: u128, - pool_token_supply: u128, - swap_token_a_amount: u128, - swap_token_b_amount: u128, - round_direction: RoundDirection, - ) -> Option { - let mut token_a_amount = pool_tokens - .checked_mul(swap_token_a_amount)? - .checked_div(pool_token_supply)?; - let mut token_b_amount = pool_tokens - .checked_mul(swap_token_b_amount)? - .checked_div(pool_token_supply)?; - let (token_a_amount, token_b_amount) = match round_direction { - RoundDirection::Floor => (token_a_amount, token_b_amount), - RoundDirection::Ceiling => { - let token_a_remainder = pool_tokens - .checked_mul(swap_token_a_amount)? - .checked_rem(pool_token_supply)?; - - if token_a_remainder > 0 && token_a_amount > 0 { - token_a_amount += 1; - } - let token_b_remainder = pool_tokens - .checked_mul(swap_token_b_amount)? - .checked_rem(pool_token_supply)?; - if token_b_remainder > 0 && token_b_amount > 0 { - token_b_amount += 1; - } - (token_a_amount, token_b_amount) - } - }; - Some(TradingTokenResult { - token_a_amount, - token_b_amount, - }) - } - - /// Get the amount of pool tokens for the given amount of token A or B. - /// Re-implementation of `calc_token_amount`: - /// - /// - fn deposit_single_token_type( - &self, - source_amount: u128, - swap_token_a_amount: u128, - swap_token_b_amount: u128, - pool_supply: u128, - trade_direction: TradeDirection, - ) -> Option { - if source_amount == 0 { - return Some(0); - } - let leverage = compute_a(self.amp)?; - let d0 = PreciseNumber::new(compute_d( - leverage, - swap_token_a_amount, - swap_token_b_amount, - )?)?; - let (deposit_token_amount, other_token_amount) = match trade_direction { - TradeDirection::AtoB => (swap_token_a_amount, swap_token_b_amount), - TradeDirection::BtoA => (swap_token_b_amount, swap_token_a_amount), - }; - let updated_deposit_token_amount = deposit_token_amount.checked_add(source_amount)?; - let d1 = PreciseNumber::new(compute_d( - leverage, - updated_deposit_token_amount, - other_token_amount, - )?)?; - let diff = d1.checked_sub(&d0)?; - let final_amount = - (diff.checked_mul(&PreciseNumber::new(pool_supply)?))?.checked_div(&d0)?; - final_amount.floor()?.to_imprecise() - } - - fn withdraw_single_token_type_exact_out( - &self, - source_amount: u128, - swap_token_a_amount: u128, - swap_token_b_amount: u128, - pool_supply: u128, - trade_direction: TradeDirection, - ) -> Option { - if source_amount == 0 { - return Some(0); - } - let leverage = compute_a(self.amp)?; - let d0 = PreciseNumber::new(compute_d( - leverage, - swap_token_a_amount, - swap_token_b_amount, - )?)?; - let (withdraw_token_amount, other_token_amount) = match trade_direction { - TradeDirection::AtoB => (swap_token_a_amount, swap_token_b_amount), - TradeDirection::BtoA => (swap_token_b_amount, swap_token_a_amount), - }; - let updated_deposit_token_amount = withdraw_token_amount.checked_sub(source_amount)?; - let d1 = PreciseNumber::new(compute_d( - leverage, - updated_deposit_token_amount, - other_token_amount, - )?)?; - let diff = d0.checked_sub(&d1)?; - let final_amount = - (diff.checked_mul(&PreciseNumber::new(pool_supply)?))?.checked_div(&d0)?; - final_amount.ceiling()?.to_imprecise() - } - - fn normalized_value( - &self, - swap_token_a_amount: u128, - swap_token_b_amount: u128, - ) -> Option { - #[cfg(not(any(test, feature = "fuzz")))] - { - let leverage = compute_a(self.amp)?; - PreciseNumber::new(compute_d( - leverage, - swap_token_a_amount, - swap_token_b_amount, - )?) - } - #[cfg(any(test, feature = "fuzz"))] - { - use roots::{find_roots_cubic_normalized, Roots}; - let x = swap_token_a_amount as f64; - let y = swap_token_b_amount as f64; - let c = (4.0 * (self.amp as f64)) - 1.0; - let d = 16.0 * (self.amp as f64) * x * y * (x + y); - let roots = find_roots_cubic_normalized(0.0, c, d); - let x0 = match roots { - Roots::No(_) => panic!("No roots found for cubic equations"), - Roots::One(x) => x[0], - Roots::Two(_) => panic!("Two roots found for cubic, mathematically impossible"), - Roots::Three(x) => x[1], - Roots::Four(_) => panic!("Four roots found for cubic, mathematically impossible"), - }; - - let root_uint = (x0 * ((10f64).powf(11.0))).round() as u128; - let precision = PreciseNumber::new(10)?.checked_pow(11)?; - let two = PreciseNumber::new(2)?; - PreciseNumber::new(root_uint)? - .checked_div(&precision)? - .checked_div(&two) - } - } - - fn validate(&self) -> Result<(), SwapError> { - // TODO are all amps valid? - Ok(()) - } -} - -/// IsInitialized is required to use `Pack::pack` and `Pack::unpack` -impl IsInitialized for StableCurve { - fn is_initialized(&self) -> bool { - true - } -} -impl Sealed for StableCurve {} -impl Pack for StableCurve { - const LEN: usize = 8; - fn pack_into_slice(&self, output: &mut [u8]) { - (self as &dyn DynPack).pack_into_slice(output); - } - - fn unpack_from_slice(input: &[u8]) -> Result { - let amp = array_ref![input, 0, 8]; - Ok(Self { - amp: u64::from_le_bytes(*amp), - }) - } -} - -impl DynPack for StableCurve { - fn pack_into_slice(&self, output: &mut [u8]) { - let amp = array_mut_ref![output, 0, 8]; - *amp = self.amp.to_le_bytes(); - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::curve::calculator::{ - test::{ - check_curve_value_from_swap, check_deposit_token_conversion, - check_pool_value_from_deposit, check_pool_value_from_withdraw, - check_withdraw_token_conversion, total_and_intermediate, - CONVERSION_BASIS_POINTS_GUARANTEE, - }, - RoundDirection, INITIAL_SWAP_POOL_AMOUNT, - }; - use proptest::prelude::*; - use sim::StableSwapModel; - - #[test] - fn initial_pool_amount() { - let amp = 1; - let calculator = StableCurve { amp }; - assert_eq!(calculator.new_pool_supply(), INITIAL_SWAP_POOL_AMOUNT); - } - - fn check_pool_token_rate( - token_a: u128, - token_b: u128, - deposit: u128, - supply: u128, - expected_a: u128, - expected_b: u128, - ) { - let amp = 1; - let calculator = StableCurve { amp }; - let results = calculator - .pool_tokens_to_trading_tokens( - deposit, - supply, - token_a, - token_b, - RoundDirection::Ceiling, - ) - .unwrap(); - assert_eq!(results.token_a_amount, expected_a); - assert_eq!(results.token_b_amount, expected_b); - } - - #[test] - fn trading_token_conversion() { - check_pool_token_rate(2, 49, 5, 10, 1, 25); - check_pool_token_rate(100, 202, 5, 101, 5, 10); - check_pool_token_rate(5, 501, 2, 10, 1, 101); - } - - #[test] - fn swap_zero() { - let curve = StableCurve { amp: 100 }; - let result = curve.swap_without_fees(0, 100, 1_000_000_000_000_000, TradeDirection::AtoB); - - let result = result.unwrap(); - assert_eq!(result.source_amount_swapped, 0); - assert_eq!(result.destination_amount_swapped, 0); - } - - proptest! { - #[test] - fn swap_no_fee( - swap_source_amount in 100..1_000_000_000_000_000_000u128, - swap_destination_amount in 100..1_000_000_000_000_000_000u128, - source_amount in 100..100_000_000_000u128, - amp in 1..150u64 - ) { - prop_assume!(source_amount < swap_source_amount); - - let curve = StableCurve { amp }; - - let model: StableSwapModel = StableSwapModel::new( - curve.amp.into(), - vec![swap_source_amount, swap_destination_amount], - N_COINS, - ); - - let result = curve.swap_without_fees( - source_amount, - swap_source_amount, - swap_destination_amount, - TradeDirection::AtoB, - ); - - let result = result.unwrap(); - let sim_result = model.sim_exchange(0, 1, source_amount); - - let diff = - (sim_result as i128 - result.destination_amount_swapped as i128).abs(); - - // tolerate a difference of 2 because of the ceiling during calculation - let tolerance = std::cmp::max(2, sim_result as i128 / 1_000_000_000); - - assert!( - diff <= tolerance, - "result={}, sim_result={}, amp={}, source_amount={}, swap_source_amount={}, swap_destination_amount={}, diff={}", - result.destination_amount_swapped, - sim_result, - amp, - source_amount, - swap_source_amount, - swap_destination_amount, - diff - ); - } - } - - #[test] - fn pack_curve() { - let amp = 1; - let curve = StableCurve { amp }; - - let mut packed = [0u8; StableCurve::LEN]; - Pack::pack_into_slice(&curve, &mut packed[..]); - let unpacked = StableCurve::unpack(&packed).unwrap(); - assert_eq!(curve, unpacked); - - let mut packed = vec![]; - packed.extend_from_slice(&.to_le_bytes()); - let unpacked = StableCurve::unpack(&packed).unwrap(); - assert_eq!(curve, unpacked); - } - - proptest! { - #[test] - fn curve_value_does_not_decrease_from_deposit( - pool_token_amount in 1..u64::MAX, - pool_token_supply in 1..u64::MAX, - swap_token_a_amount in 1..u64::MAX, - swap_token_b_amount in 1..u64::MAX, - amp in 1..100, - ) { - let pool_token_amount = pool_token_amount as u128; - let pool_token_supply = pool_token_supply as u128; - let swap_token_a_amount = swap_token_a_amount as u128; - let swap_token_b_amount = swap_token_b_amount as u128; - // Make sure we will get at least one trading token out for each - // side, otherwise the calculation fails - prop_assume!(pool_token_amount * swap_token_a_amount / pool_token_supply >= 1); - prop_assume!(pool_token_amount * swap_token_b_amount / pool_token_supply >= 1); - let curve = StableCurve { - amp: amp as u64 - }; - check_pool_value_from_deposit( - &curve, - pool_token_amount, - pool_token_supply, - swap_token_a_amount, - swap_token_b_amount, - ); - } - } - - proptest! { - #[test] - fn curve_value_does_not_decrease_from_withdraw( - (pool_token_supply, pool_token_amount) in total_and_intermediate(), - swap_token_a_amount in 1..u64::MAX, - swap_token_b_amount in 1..u64::MAX, - amp in 1..100, - ) { - let pool_token_amount = pool_token_amount as u128; - let pool_token_supply = pool_token_supply as u128; - let swap_token_a_amount = swap_token_a_amount as u128; - let swap_token_b_amount = swap_token_b_amount as u128; - // Make sure we will get at least one trading token out for each - // side, otherwise the calculation fails - prop_assume!(pool_token_amount * swap_token_a_amount / pool_token_supply >= 1); - prop_assume!(pool_token_amount * swap_token_b_amount / pool_token_supply >= 1); - let curve = StableCurve { - amp: amp as u64 - }; - check_pool_value_from_withdraw( - &curve, - pool_token_amount, - pool_token_supply, - swap_token_a_amount, - swap_token_b_amount, - ); - } - } - - proptest! { - #[test] - fn curve_value_does_not_decrease_from_swap( - source_token_amount in 1..u64::MAX, - swap_source_amount in 1..u64::MAX, - swap_destination_amount in 1..u64::MAX, - amp in 1..100, - ) { - let curve = StableCurve { amp: amp as u64 }; - check_curve_value_from_swap( - &curve, - source_token_amount as u128, - swap_source_amount as u128, - swap_destination_amount as u128, - TradeDirection::AtoB - ); - } - } - - proptest! { - #[test] - fn deposit_token_conversion( - // in the pool token conversion calcs, we simulate trading half of - // source_token_amount, so this needs to be at least 2 - source_token_amount in 2..u64::MAX, - swap_source_amount in 1..u64::MAX, - swap_destination_amount in 2..u64::MAX, - pool_supply in INITIAL_SWAP_POOL_AMOUNT..u64::MAX as u128, - amp in 1..100u64, - ) { - let curve = StableCurve { amp }; - check_deposit_token_conversion( - &curve, - source_token_amount as u128, - swap_source_amount as u128, - swap_destination_amount as u128, - TradeDirection::AtoB, - pool_supply, - CONVERSION_BASIS_POINTS_GUARANTEE * 100, - ); - - check_deposit_token_conversion( - &curve, - source_token_amount as u128, - swap_source_amount as u128, - swap_destination_amount as u128, - TradeDirection::BtoA, - pool_supply, - CONVERSION_BASIS_POINTS_GUARANTEE * 100, - ); - } - } - - proptest! { - #[test] - fn withdraw_token_conversion( - (pool_token_supply, pool_token_amount) in total_and_intermediate(), - swap_token_a_amount in 1..u64::MAX, - swap_token_b_amount in 1..u64::MAX, - amp in 1..100u64, - ) { - let curve = StableCurve { amp }; - check_withdraw_token_conversion( - &curve, - pool_token_amount as u128, - pool_token_supply as u128, - swap_token_a_amount as u128, - swap_token_b_amount as u128, - TradeDirection::AtoB, - CONVERSION_BASIS_POINTS_GUARANTEE - ); - check_withdraw_token_conversion( - &curve, - pool_token_amount as u128, - pool_token_supply as u128, - swap_token_a_amount as u128, - swap_token_b_amount as u128, - TradeDirection::BtoA, - CONVERSION_BASIS_POINTS_GUARANTEE - ); - } - } - - // this test comes from a failed proptest - #[test] - fn withdraw_token_conversion_huge_withdrawal() { - let pool_token_supply: u64 = 12798273514859089136; - let pool_token_amount: u64 = 12798243809352362806; - let swap_token_a_amount: u64 = 10000000000000000000; - let swap_token_b_amount: u64 = 6000000000000000000; - let amp = 72; - let curve = StableCurve { amp }; - check_withdraw_token_conversion( - &curve, - pool_token_amount as u128, - pool_token_supply as u128, - swap_token_a_amount as u128, - swap_token_b_amount as u128, - TradeDirection::AtoB, - CONVERSION_BASIS_POINTS_GUARANTEE, - ); - } -} diff --git a/token-swap/program/src/entrypoint.rs b/token-swap/program/src/entrypoint.rs index b41aa6fc3f1..a8ae2f338cf 100644 --- a/token-swap/program/src/entrypoint.rs +++ b/token-swap/program/src/entrypoint.rs @@ -1,12 +1,14 @@ //! Program entrypoint definitions -use crate::{error::SwapError, processor::Processor}; -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, - program_error::PrintProgramError, pubkey::Pubkey, +use { + crate::{error::SwapError, processor::Processor}, + solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, program_error::PrintProgramError, + pubkey::Pubkey, + }, }; -entrypoint!(process_instruction); +solana_program::entrypoint!(process_instruction); fn process_instruction( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/token-swap/program/src/error.rs b/token-swap/program/src/error.rs index e4e7bbb3fae..1f1ce81ddcd 100644 --- a/token-swap/program/src/error.rs +++ b/token-swap/program/src/error.rs @@ -1,12 +1,14 @@ //! Error types -use num_derive::FromPrimitive; -use solana_program::{ - decode_error::DecodeError, - msg, - program_error::{PrintProgramError, ProgramError}, +use { + num_derive::FromPrimitive, + solana_program::{ + decode_error::DecodeError, + msg, + program_error::{PrintProgramError, ProgramError}, + }, + thiserror::Error, }; -use thiserror::Error; /// Errors that may be returned by the TokenSwap program. #[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] @@ -15,21 +17,26 @@ pub enum SwapError { /// The account cannot be initialized because it is already being used. #[error("Swap account already in use")] AlreadyInUse, - /// The program address provided doesn't match the value generated by the program. + /// The program address provided doesn't match the value generated by the + /// program. #[error("Invalid program address generated from bump seed and key")] InvalidProgramAddress, - /// The owner of the input isn't set to the program address generated by the program. + /// The owner of the input isn't set to the program address generated by the + /// program. #[error("Input account owner is not the program address")] InvalidOwner, - /// The owner of the pool token output is set to the program address generated by the program. + /// The owner of the pool token output is set to the program address + /// generated by the program. #[error("Output pool account owner cannot be the program address")] InvalidOutputOwner, - /// The deserialization of the account returned something besides State::Mint. + /// The deserialization of the account returned something besides + /// State::Mint. #[error("Deserialized account is not an SPL Token mint")] ExpectedMint, // 5. - /// The deserialization of the account returned something besides State::Account. + /// The deserialization of the account returned something besides + /// State::Account. #[error("Deserialized account is not an SPL Token account")] ExpectedAccount, /// The input token account is empty. @@ -92,7 +99,8 @@ pub enum SwapError { /// The provided fee does not match the program owner's constraints #[error("The provided fee does not match the program owner's constraints")] InvalidFee, - /// The provided token program does not match the token program expected by the swap + /// The provided token program does not match the token program expected by + /// the swap #[error("The provided token program does not match the token program expected by the swap")] IncorrectTokenProgramId, @@ -106,6 +114,9 @@ pub enum SwapError { /// The operation cannot be performed on the given curve #[error("The operation cannot be performed on the given curve")] UnsupportedCurveOperation, + /// The pool fee account is invalid. + #[error("The pool fee account is invalid")] + InvalidFeeAccount, } impl From for ProgramError { fn from(e: SwapError) -> Self { @@ -186,6 +197,9 @@ impl PrintProgramError for SwapError { SwapError::UnsupportedCurveOperation => { msg!("Error: The operation cannot be performed on the given curve") } + SwapError::InvalidFeeAccount => { + msg!("Error: The pool fee account is invalid") + } } } } diff --git a/token-swap/program/src/instruction.rs b/token-swap/program/src/instruction.rs index c8803df1223..874727d3d35 100644 --- a/token-swap/program/src/instruction.rs +++ b/token-swap/program/src/instruction.rs @@ -2,19 +2,21 @@ #![allow(clippy::too_many_arguments)] -use crate::curve::{base::SwapCurve, fees::Fees}; -use crate::error::SwapError; -use solana_program::{ - instruction::{AccountMeta, Instruction}, - program_error::ProgramError, - program_pack::Pack, - pubkey::Pubkey, -}; -use std::convert::TryInto; -use std::mem::size_of; - #[cfg(feature = "fuzz")] use arbitrary::Arbitrary; +use { + crate::{ + curve::{base::SwapCurve, fees::Fees}, + error::SwapError, + }, + solana_program::{ + instruction::{AccountMeta, Instruction}, + program_error::ProgramError, + program_pack::Pack, + pubkey::Pubkey, + }, + std::{convert::TryInto, mem::size_of}, +}; /// Initialize instruction data #[repr(C)] @@ -32,9 +34,11 @@ pub struct Initialize { #[repr(C)] #[derive(Clone, Debug, PartialEq)] pub struct Swap { - /// SOURCE amount to transfer, output to DESTINATION is based on the exchange rate + /// SOURCE amount to transfer, output to DESTINATION is based on the + /// exchange rate pub amount_in: u64, - /// Minimum amount of DESTINATION token to output, prevents excessive slippage + /// Minimum amount of DESTINATION token to output, prevents excessive + /// slippage pub minimum_amount_out: u64, } @@ -85,8 +89,8 @@ pub struct DepositSingleTokenTypeExactAmountIn { pub struct WithdrawSingleTokenTypeExactAmountOut { /// Amount of token A or B to receive pub destination_token_amount: u64, - /// Maximum amount of pool tokens to burn. User receives an output of token A - /// or B based on the percentage of the pool tokens that are returned. + /// Maximum amount of pool tokens to burn. User receives an output of token + /// A or B based on the percentage of the pool tokens that are returned. pub maximum_pool_token_amount: u64, } @@ -97,15 +101,17 @@ pub enum SwapInstruction { /// Initializes a new swap /// /// 0. `[writable, signer]` New Token-swap to create. - /// 1. `[]` swap authority derived from `create_program_address(&[Token-swap account])` + /// 1. `[]` swap authority derived from + /// `create_program_address(&[Token-swap account])` /// 2. `[]` token_a Account. Must be non zero, owned by swap authority. /// 3. `[]` token_b Account. Must be non zero, owned by swap authority. - /// 4. `[writable]` Pool Token Mint. Must be empty, owned by swap authority. - /// 5. `[]` Pool Token Account to deposit trading and withdraw fees. - /// Must be empty, not owned by swap authority + /// 4. `[writable]` Pool Token Mint. Must be empty, owned by swap + /// authority. + /// 5. `[]` Pool Token Account to deposit trading and withdraw fees. Must + /// be empty, not owned by swap authority /// 6. `[writable]` Pool Token Account to deposit the initial pool token - /// supply. Must be empty, not owned by swap authority. - /// 7. `[]` Token program id + /// supply. Must be empty, not owned by swap authority. + /// 7. `[]` Pool Token program id Initialize(Initialize), /// Swap the tokens in the pool. @@ -113,14 +119,23 @@ pub enum SwapInstruction { /// 0. `[]` Token-swap /// 1. `[]` swap authority /// 2. `[]` user transfer authority - /// 3. `[writable]` token_(A|B) SOURCE Account, amount is transferable by user transfer authority, - /// 4. `[writable]` token_(A|B) Base Account to swap INTO. Must be the SOURCE token. - /// 5. `[writable]` token_(A|B) Base Account to swap FROM. Must be the DESTINATION token. - /// 6. `[writable]` token_(A|B) DESTINATION Account assigned to USER as the owner. + /// 3. `[writable]` token_(A|B) SOURCE Account, amount is transferable by + /// user transfer authority, + /// 4. `[writable]` token_(A|B) Base Account to swap INTO. Must be the + /// SOURCE token. + /// 5. `[writable]` token_(A|B) Base Account to swap FROM. Must be the + /// DESTINATION token. + /// 6. `[writable]` token_(A|B) DESTINATION Account assigned to USER as + /// the owner. /// 7. `[writable]` Pool token mint, to generate trading fees /// 8. `[writable]` Fee account, to receive trading fees - /// 9. `[]` Token program id - /// 10. `[optional, writable]` Host fee account to receive additional trading fees + /// 9. `[]` Token (A|B) SOURCE mint + /// 10. `[]` Token (A|B) DESTINATION mint + /// 11. `[]` Token (A|B) SOURCE program id + /// 12. `[]` Token (A|B) DESTINATION program id + /// 13. `[]` Pool Token program id + /// 14. `[optional, writable]` Host fee account to receive additional + /// trading fees Swap(Swap), /// Deposit both types of tokens into the pool. The output is a "pool" @@ -135,40 +150,54 @@ pub enum SwapInstruction { /// 5. `[writable]` token_a Base Account to deposit into. /// 6. `[writable]` token_b Base Account to deposit into. /// 7. `[writable]` Pool MINT account, swap authority is the owner. - /// 8. `[writable]` Pool Account to deposit the generated tokens, user is the owner. - /// 9. `[]` Token program id + /// 8. `[writable]` Pool Account to deposit the generated tokens, user is + /// the owner. + /// 9. `[]` Token A mint + /// 10. `[]` Token B mint + /// 11. `[]` Token A program id + /// 12. `[]` Token B program id + /// 13. `[]` Pool Token program id DepositAllTokenTypes(DepositAllTokenTypes), - /// Withdraw both types of tokens from the pool at the current ratio, given - /// pool tokens. The pool tokens are burned in exchange for an equivalent - /// amount of token A and B. + /// Withdraw both types of tokens from the pool at the current ratio, + /// given pool tokens. The pool tokens are burned in exchange for an + /// equivalent amount of token A and B. /// /// 0. `[]` Token-swap /// 1. `[]` swap authority /// 2. `[]` user transfer authority /// 3. `[writable]` Pool mint account, swap authority is the owner - /// 4. `[writable]` SOURCE Pool account, amount is transferable by user transfer authority. + /// 4. `[writable]` SOURCE Pool account, amount is transferable by user + /// transfer authority. /// 5. `[writable]` token_a Swap Account to withdraw FROM. /// 6. `[writable]` token_b Swap Account to withdraw FROM. /// 7. `[writable]` token_a user Account to credit. /// 8. `[writable]` token_b user Account to credit. /// 9. `[writable]` Fee account, to receive withdrawal fees - /// 10. `[]` Token program id + /// 10. `[]` Token A mint + /// 11. `[]` Token B mint + /// 12. `[]` Pool Token program id + /// 13. `[]` Token A program id + /// 14. `[]` Token B program id WithdrawAllTokenTypes(WithdrawAllTokenTypes), - /// Deposit one type of tokens into the pool. The output is a "pool" token - /// representing ownership into the pool. Input token is converted as if - /// a swap and deposit all token types were performed. + /// Deposit one type of tokens into the pool. The output is a "pool" + /// token representing ownership into the pool. Input token is + /// converted as if a swap and deposit all token types were performed. /// /// 0. `[]` Token-swap /// 1. `[]` swap authority /// 2. `[]` user transfer authority - /// 3. `[writable]` token_(A|B) SOURCE Account, amount is transferable by user transfer authority, + /// 3. `[writable]` token_(A|B) SOURCE Account, amount is transferable by + /// user transfer authority, /// 4. `[writable]` token_a Swap Account, may deposit INTO. /// 5. `[writable]` token_b Swap Account, may deposit INTO. /// 6. `[writable]` Pool MINT account, swap authority is the owner. - /// 7. `[writable]` Pool Account to deposit the generated tokens, user is the owner. - /// 8. `[]` Token program id + /// 7. `[writable]` Pool Account to deposit the generated tokens, user is + /// the owner. + /// 8. `[]` Token (A|B) SOURCE mint + /// 9. `[]` Token (A|B) SOURCE program id + /// 10. `[]` Pool Token program id DepositSingleTokenTypeExactAmountIn(DepositSingleTokenTypeExactAmountIn), /// Withdraw one token type from the pool at the current ratio given the @@ -178,17 +207,21 @@ pub enum SwapInstruction { /// 1. `[]` swap authority /// 2. `[]` user transfer authority /// 3. `[writable]` Pool mint account, swap authority is the owner - /// 4. `[writable]` SOURCE Pool account, amount is transferable by user transfer authority. + /// 4. `[writable]` SOURCE Pool account, amount is transferable by user + /// transfer authority. /// 5. `[writable]` token_a Swap Account to potentially withdraw from. /// 6. `[writable]` token_b Swap Account to potentially withdraw from. /// 7. `[writable]` token_(A|B) User Account to credit /// 8. `[writable]` Fee account, to receive withdrawal fees - /// 9. `[]` Token program id + /// 9. `[]` Token (A|B) DESTINATION mint + /// 10. `[]` Pool Token program id + /// 11. `[]` Token (A|B) DESTINATION program id WithdrawSingleTokenTypeExactAmountOut(WithdrawSingleTokenTypeExactAmountOut), } impl SwapInstruction { - /// Unpacks a byte buffer into a [SwapInstruction](enum.SwapInstruction.html). + /// Unpacks a byte buffer into a + /// [SwapInstruction](enum.SwapInstruction.html). pub fn unpack(input: &[u8]) -> Result { let (&tag, rest) = input.split_first().ok_or(SwapError::InvalidInstruction)?; Ok(match tag { @@ -267,7 +300,7 @@ impl SwapInstruction { /// Packs a [SwapInstruction](enum.SwapInstruction.html) into a byte buffer. pub fn pack(&self) -> Vec { let mut buf = Vec::with_capacity(size_of::()); - match &*self { + match self { Self::Initialize(Initialize { fees, swap_curve }) => { buf.push(0); let mut fees_slice = [0u8; Fees::LEN]; @@ -366,7 +399,9 @@ pub fn initialize( /// Creates a 'deposit_all_token_types' instruction. pub fn deposit_all_token_types( program_id: &Pubkey, - token_program_id: &Pubkey, + token_a_program_id: &Pubkey, + token_b_program_id: &Pubkey, + pool_token_program_id: &Pubkey, swap_pubkey: &Pubkey, authority_pubkey: &Pubkey, user_transfer_authority_pubkey: &Pubkey, @@ -376,6 +411,8 @@ pub fn deposit_all_token_types( swap_token_b_pubkey: &Pubkey, pool_mint_pubkey: &Pubkey, destination_pubkey: &Pubkey, + token_a_mint_pubkey: &Pubkey, + token_b_mint_pubkey: &Pubkey, instruction: DepositAllTokenTypes, ) -> Result { let data = SwapInstruction::DepositAllTokenTypes(instruction).pack(); @@ -390,7 +427,11 @@ pub fn deposit_all_token_types( AccountMeta::new(*swap_token_b_pubkey, false), AccountMeta::new(*pool_mint_pubkey, false), AccountMeta::new(*destination_pubkey, false), - AccountMeta::new_readonly(*token_program_id, false), + AccountMeta::new_readonly(*token_a_mint_pubkey, false), + AccountMeta::new_readonly(*token_b_mint_pubkey, false), + AccountMeta::new_readonly(*token_a_program_id, false), + AccountMeta::new_readonly(*token_b_program_id, false), + AccountMeta::new_readonly(*pool_token_program_id, false), ]; Ok(Instruction { @@ -403,7 +444,9 @@ pub fn deposit_all_token_types( /// Creates a 'withdraw_all_token_types' instruction. pub fn withdraw_all_token_types( program_id: &Pubkey, - token_program_id: &Pubkey, + pool_token_program_id: &Pubkey, + token_a_program_id: &Pubkey, + token_b_program_id: &Pubkey, swap_pubkey: &Pubkey, authority_pubkey: &Pubkey, user_transfer_authority_pubkey: &Pubkey, @@ -414,6 +457,8 @@ pub fn withdraw_all_token_types( swap_token_b_pubkey: &Pubkey, destination_token_a_pubkey: &Pubkey, destination_token_b_pubkey: &Pubkey, + token_a_mint_pubkey: &Pubkey, + token_b_mint_pubkey: &Pubkey, instruction: WithdrawAllTokenTypes, ) -> Result { let data = SwapInstruction::WithdrawAllTokenTypes(instruction).pack(); @@ -429,7 +474,11 @@ pub fn withdraw_all_token_types( AccountMeta::new(*destination_token_a_pubkey, false), AccountMeta::new(*destination_token_b_pubkey, false), AccountMeta::new(*fee_account_pubkey, false), - AccountMeta::new_readonly(*token_program_id, false), + AccountMeta::new_readonly(*token_a_mint_pubkey, false), + AccountMeta::new_readonly(*token_b_mint_pubkey, false), + AccountMeta::new_readonly(*pool_token_program_id, false), + AccountMeta::new_readonly(*token_a_program_id, false), + AccountMeta::new_readonly(*token_b_program_id, false), ]; Ok(Instruction { @@ -442,7 +491,8 @@ pub fn withdraw_all_token_types( /// Creates a 'deposit_single_token_type_exact_amount_in' instruction. pub fn deposit_single_token_type_exact_amount_in( program_id: &Pubkey, - token_program_id: &Pubkey, + source_token_program_id: &Pubkey, + pool_token_program_id: &Pubkey, swap_pubkey: &Pubkey, authority_pubkey: &Pubkey, user_transfer_authority_pubkey: &Pubkey, @@ -451,6 +501,7 @@ pub fn deposit_single_token_type_exact_amount_in( swap_token_b_pubkey: &Pubkey, pool_mint_pubkey: &Pubkey, destination_pubkey: &Pubkey, + source_mint_pubkey: &Pubkey, instruction: DepositSingleTokenTypeExactAmountIn, ) -> Result { let data = SwapInstruction::DepositSingleTokenTypeExactAmountIn(instruction).pack(); @@ -464,7 +515,9 @@ pub fn deposit_single_token_type_exact_amount_in( AccountMeta::new(*swap_token_b_pubkey, false), AccountMeta::new(*pool_mint_pubkey, false), AccountMeta::new(*destination_pubkey, false), - AccountMeta::new_readonly(*token_program_id, false), + AccountMeta::new_readonly(*source_mint_pubkey, false), + AccountMeta::new_readonly(*source_token_program_id, false), + AccountMeta::new_readonly(*pool_token_program_id, false), ]; Ok(Instruction { @@ -477,7 +530,8 @@ pub fn deposit_single_token_type_exact_amount_in( /// Creates a 'withdraw_single_token_type_exact_amount_out' instruction. pub fn withdraw_single_token_type_exact_amount_out( program_id: &Pubkey, - token_program_id: &Pubkey, + pool_token_program_id: &Pubkey, + destination_token_program_id: &Pubkey, swap_pubkey: &Pubkey, authority_pubkey: &Pubkey, user_transfer_authority_pubkey: &Pubkey, @@ -487,6 +541,7 @@ pub fn withdraw_single_token_type_exact_amount_out( swap_token_a_pubkey: &Pubkey, swap_token_b_pubkey: &Pubkey, destination_pubkey: &Pubkey, + destination_mint_pubkey: &Pubkey, instruction: WithdrawSingleTokenTypeExactAmountOut, ) -> Result { let data = SwapInstruction::WithdrawSingleTokenTypeExactAmountOut(instruction).pack(); @@ -501,7 +556,9 @@ pub fn withdraw_single_token_type_exact_amount_out( AccountMeta::new(*swap_token_b_pubkey, false), AccountMeta::new(*destination_pubkey, false), AccountMeta::new(*fee_account_pubkey, false), - AccountMeta::new_readonly(*token_program_id, false), + AccountMeta::new_readonly(*destination_mint_pubkey, false), + AccountMeta::new_readonly(*pool_token_program_id, false), + AccountMeta::new_readonly(*destination_token_program_id, false), ]; Ok(Instruction { @@ -514,7 +571,9 @@ pub fn withdraw_single_token_type_exact_amount_out( /// Creates a 'swap' instruction. pub fn swap( program_id: &Pubkey, - token_program_id: &Pubkey, + source_token_program_id: &Pubkey, + destination_token_program_id: &Pubkey, + pool_token_program_id: &Pubkey, swap_pubkey: &Pubkey, authority_pubkey: &Pubkey, user_transfer_authority_pubkey: &Pubkey, @@ -524,6 +583,8 @@ pub fn swap( destination_pubkey: &Pubkey, pool_mint_pubkey: &Pubkey, pool_fee_pubkey: &Pubkey, + source_mint_pubkey: &Pubkey, + destination_mint_pubkey: &Pubkey, host_fee_pubkey: Option<&Pubkey>, instruction: Swap, ) -> Result { @@ -539,7 +600,11 @@ pub fn swap( AccountMeta::new(*destination_pubkey, false), AccountMeta::new(*pool_mint_pubkey, false), AccountMeta::new(*pool_fee_pubkey, false), - AccountMeta::new_readonly(*token_program_id, false), + AccountMeta::new_readonly(*source_mint_pubkey, false), + AccountMeta::new_readonly(*destination_mint_pubkey, false), + AccountMeta::new_readonly(*source_token_program_id, false), + AccountMeta::new_readonly(*destination_token_program_id, false), + AccountMeta::new_readonly(*pool_token_program_id, false), ]; if let Some(host_fee_pubkey) = host_fee_pubkey { accounts.push(AccountMeta::new(*host_fee_pubkey, false)); @@ -565,9 +630,11 @@ pub fn unpack(input: &[u8]) -> Result<&T, ProgramError> { #[cfg(test)] mod tests { - use super::*; - use crate::curve::{base::CurveType, stable::StableCurve}; - use std::sync::Arc; + use { + super::*, + crate::curve::{base::CurveType, offset::OffsetCurve}, + std::sync::Arc, + }; #[test] fn pack_intialize() { @@ -589,9 +656,9 @@ mod tests { host_fee_numerator, host_fee_denominator, }; - let amp: u64 = 1; - let curve_type = CurveType::Stable; - let calculator = Arc::new(StableCurve { amp }); + let token_b_offset: u64 = 1_000_000_000; + let curve_type = CurveType::Offset; + let calculator = Arc::new(OffsetCurve { token_b_offset }); let swap_curve = SwapCurve { curve_type, calculator, @@ -608,7 +675,7 @@ mod tests { expect.extend_from_slice(&host_fee_numerator.to_le_bytes()); expect.extend_from_slice(&host_fee_denominator.to_le_bytes()); expect.push(curve_type as u8); - expect.extend_from_slice(&.to_le_bytes()); + expect.extend_from_slice(&token_b_offset.to_le_bytes()); expect.extend_from_slice(&[0u8; 24]); assert_eq!(packed, expect); let unpacked = SwapInstruction::unpack(&expect).unwrap(); diff --git a/token-swap/program/src/lib.rs b/token-swap/program/src/lib.rs index 96e3c3580ae..34fa02092dd 100644 --- a/token-swap/program/src/lib.rs +++ b/token-swap/program/src/lib.rs @@ -1,3 +1,4 @@ +#![allow(clippy::arithmetic_side_effects)] #![deny(missing_docs)] //! An Uniswap-like program for the Solana blockchain. @@ -12,7 +13,8 @@ pub mod state; #[cfg(not(feature = "no-entrypoint"))] mod entrypoint; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version pub use solana_program; solana_program::declare_id!("SwapsVeCiPHMUAtzQWZw7RjsKjgCjhwU55QGu4U1Szw"); diff --git a/token-swap/program/src/processor.rs b/token-swap/program/src/processor.rs index 5cec140a3ca..09b22b25964 100644 --- a/token-swap/program/src/processor.rs +++ b/token-swap/program/src/processor.rs @@ -1,34 +1,45 @@ //! Program state processor -use crate::constraints::{SwapConstraints, SWAP_CONSTRAINTS}; -use crate::{ - curve::{ - base::SwapCurve, - calculator::{RoundDirection, TradeDirection}, - fees::Fees, +use { + crate::{ + constraints::{SwapConstraints, SWAP_CONSTRAINTS}, + curve::{ + base::SwapCurve, + calculator::{RoundDirection, TradeDirection}, + fees::Fees, + }, + error::SwapError, + instruction::{ + DepositAllTokenTypes, DepositSingleTokenTypeExactAmountIn, Initialize, Swap, + SwapInstruction, WithdrawAllTokenTypes, WithdrawSingleTokenTypeExactAmountOut, + }, + state::{SwapState, SwapV1, SwapVersion}, }, - error::SwapError, - instruction::{ - DepositAllTokenTypes, DepositSingleTokenTypeExactAmountIn, Initialize, Swap, - SwapInstruction, WithdrawAllTokenTypes, WithdrawSingleTokenTypeExactAmountOut, + num_traits::FromPrimitive, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + clock::Clock, + decode_error::DecodeError, + entrypoint::ProgramResult, + instruction::Instruction, + msg, + program::invoke_signed, + program_error::{PrintProgramError, ProgramError}, + program_option::COption, + pubkey::Pubkey, + sysvar::Sysvar, }, - state::{SwapState, SwapV1, SwapVersion}, -}; -use num_traits::FromPrimitive; -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - decode_error::DecodeError, - entrypoint::ProgramResult, - instruction::Instruction, - msg, - program::invoke_signed, - program_error::{PrintProgramError, ProgramError}, - program_option::COption, - program_pack::Pack, - pubkey::Pubkey, + spl_token_2022::{ + check_spl_token_program_account, + error::TokenError, + extension::{ + mint_close_authority::MintCloseAuthority, transfer_fee::TransferFeeConfig, + BaseStateWithExtensions, StateWithExtensions, + }, + state::{Account, Mint}, + }, + std::{convert::TryInto, error::Error}, }; -use spl_token::error::TokenError; -use std::{convert::TryInto, error::Error}; /// Program state handler. pub struct Processor {} @@ -37,11 +48,14 @@ impl Processor { pub fn unpack_token_account( account_info: &AccountInfo, token_program_id: &Pubkey, - ) -> Result { - if account_info.owner != token_program_id { + ) -> Result { + if account_info.owner != token_program_id + && check_spl_token_program_account(account_info.owner).is_err() + { Err(SwapError::IncorrectTokenProgramId) } else { - spl_token::state::Account::unpack(&account_info.data.borrow()) + StateWithExtensions::::unpack(&account_info.data.borrow()) + .map(|a| a.base) .map_err(|_| SwapError::ExpectedAccount) } } @@ -50,15 +64,31 @@ impl Processor { pub fn unpack_mint( account_info: &AccountInfo, token_program_id: &Pubkey, - ) -> Result { - if account_info.owner != token_program_id { + ) -> Result { + if account_info.owner != token_program_id + && check_spl_token_program_account(account_info.owner).is_err() + { Err(SwapError::IncorrectTokenProgramId) } else { - spl_token::state::Mint::unpack(&account_info.data.borrow()) + StateWithExtensions::::unpack(&account_info.data.borrow()) + .map(|m| m.base) .map_err(|_| SwapError::ExpectedMint) } } + /// Unpacks a spl_token `Mint` with extension data + pub fn unpack_mint_with_extensions<'a>( + account_data: &'a [u8], + owner: &Pubkey, + token_program_id: &Pubkey, + ) -> Result, SwapError> { + if owner != token_program_id && check_spl_token_program_account(owner).is_err() { + Err(SwapError::IncorrectTokenProgramId) + } else { + StateWithExtensions::::unpack(account_data).map_err(|_| SwapError::ExpectedMint) + } + } + /// Calculates the authority id by generating a program address. pub fn authority_id( program_id: &Pubkey, @@ -83,7 +113,7 @@ impl Processor { let authority_signature_seeds = [&swap_bytes[..32], &[bump_seed]]; let signers = &[&authority_signature_seeds[..]]; - let ix = spl_token::instruction::burn( + let ix = spl_token_2022::instruction::burn( token_program.key, burn_account.key, mint.key, @@ -112,7 +142,7 @@ impl Processor { let swap_bytes = swap.to_bytes(); let authority_signature_seeds = [&swap_bytes[..32], &[bump_seed]]; let signers = &[&authority_signature_seeds[..]]; - let ix = spl_token::instruction::mint_to( + let ix = spl_token_2022::instruction::mint_to( token_program.key, mint.key, destination.key, @@ -129,29 +159,34 @@ impl Processor { } /// Issue a spl_token `Transfer` instruction. + #[allow(clippy::too_many_arguments)] pub fn token_transfer<'a>( swap: &Pubkey, token_program: AccountInfo<'a>, source: AccountInfo<'a>, + mint: AccountInfo<'a>, destination: AccountInfo<'a>, authority: AccountInfo<'a>, bump_seed: u8, amount: u64, + decimals: u8, ) -> Result<(), ProgramError> { let swap_bytes = swap.to_bytes(); let authority_signature_seeds = [&swap_bytes[..32], &[bump_seed]]; let signers = &[&authority_signature_seeds[..]]; - let ix = spl_token::instruction::transfer( + let ix = spl_token_2022::instruction::transfer_checked( token_program.key, source.key, + mint.key, destination.key, authority.key, &[], amount, + decimals, )?; invoke_signed_wrapper::( &ix, - &[source, destination, authority, token_program], + &[source, mint, destination, authority, token_program], signers, ) } @@ -165,7 +200,7 @@ impl Processor { token_a_info: &AccountInfo, token_b_info: &AccountInfo, pool_mint_info: &AccountInfo, - token_program_info: &AccountInfo, + pool_token_program_info: &AccountInfo, user_token_a_info: Option<&AccountInfo>, user_token_b_info: Option<&AccountInfo>, pool_fee_account_info: Option<&AccountInfo>, @@ -187,7 +222,7 @@ impl Processor { if *pool_mint_info.key != *token_swap.pool_mint() { return Err(SwapError::IncorrectPoolMint.into()); } - if *token_program_info.key != *token_swap.token_program_id() { + if *pool_token_program_info.key != *token_swap.token_program_id() { return Err(SwapError::IncorrectTokenProgramId.into()); } if let Some(user_token_a_info) = user_token_a_info { @@ -224,9 +259,9 @@ impl Processor { let pool_mint_info = next_account_info(account_info_iter)?; let fee_account_info = next_account_info(account_info_iter)?; let destination_info = next_account_info(account_info_iter)?; - let token_program_info = next_account_info(account_info_iter)?; + let pool_token_program_info = next_account_info(account_info_iter)?; - let token_program_id = *token_program_info.key; + let token_program_id = *pool_token_program_info.key; if SwapVersion::is_initialized(&swap_info.data.borrow()) { return Err(SwapError::AlreadyInUse.into()); } @@ -240,7 +275,21 @@ impl Processor { let token_b = Self::unpack_token_account(token_b_info, &token_program_id)?; let fee_account = Self::unpack_token_account(fee_account_info, &token_program_id)?; let destination = Self::unpack_token_account(destination_info, &token_program_id)?; - let pool_mint = Self::unpack_mint(pool_mint_info, &token_program_id)?; + let pool_mint = { + let pool_mint_data = pool_mint_info.data.borrow(); + let pool_mint = Self::unpack_mint_with_extensions( + &pool_mint_data, + pool_mint_info.owner, + &token_program_id, + )?; + if let Ok(extension) = pool_mint.get_extension::() { + let close_authority: Option = extension.close_authority.into(); + if close_authority.is_some() { + return Err(SwapError::InvalidCloseAuthority.into()); + } + } + pool_mint.base + }; if *authority_info.key != token_a.owner { return Err(SwapError::InvalidOwner.into()); } @@ -289,6 +338,7 @@ impl Processor { if let Some(swap_constraints) = swap_constraints { let owner_key = swap_constraints .owner_key + .unwrap() .parse::() .map_err(|_| SwapError::InvalidOwner)?; if fee_account.owner != owner_key { @@ -304,7 +354,7 @@ impl Processor { Self::token_mint_to( swap_info.key, - token_program_info.clone(), + pool_token_program_info.clone(), pool_mint_info.clone(), destination_info.clone(), authority_info.clone(), @@ -346,7 +396,11 @@ impl Processor { let destination_info = next_account_info(account_info_iter)?; let pool_mint_info = next_account_info(account_info_iter)?; let pool_fee_account_info = next_account_info(account_info_iter)?; - let token_program_info = next_account_info(account_info_iter)?; + let source_token_mint_info = next_account_info(account_info_iter)?; + let destination_token_mint_info = next_account_info(account_info_iter)?; + let source_token_program_info = next_account_info(account_info_iter)?; + let destination_token_program_info = next_account_info(account_info_iter)?; + let pool_token_program_info = next_account_info(account_info_iter)?; if swap_info.owner != program_id { return Err(ProgramError::IncorrectProgramId); @@ -383,7 +437,7 @@ impl Processor { if *pool_fee_account_info.key != *token_swap.pool_fee_account() { return Err(SwapError::IncorrectFeeAccount.into()); } - if *token_program_info.key != *token_swap.token_program_id() { + if *pool_token_program_info.key != *token_swap.token_program_id() { return Err(SwapError::IncorrectTokenProgramId.into()); } @@ -393,6 +447,27 @@ impl Processor { Self::unpack_token_account(swap_destination_info, token_swap.token_program_id())?; let pool_mint = Self::unpack_mint(pool_mint_info, token_swap.token_program_id())?; + // Take transfer fees into account for actual amount transferred in + let actual_amount_in = { + let source_mint_data = source_token_mint_info.data.borrow(); + let source_mint = Self::unpack_mint_with_extensions( + &source_mint_data, + source_token_mint_info.owner, + token_swap.token_program_id(), + )?; + + if let Ok(transfer_fee_config) = source_mint.get_extension::() { + amount_in.saturating_sub( + transfer_fee_config + .calculate_epoch_fee(Clock::get()?.epoch, amount_in) + .ok_or(SwapError::FeeCalculationFailure)?, + ) + } else { + amount_in + } + }; + + // Calculate the trade amounts let trade_direction = if *swap_source_info.key == *token_swap.token_a_account() { TradeDirection::AtoB } else { @@ -401,16 +476,61 @@ impl Processor { let result = token_swap .swap_curve() .swap( - to_u128(amount_in)?, - to_u128(source_account.amount)?, - to_u128(dest_account.amount)?, + u128::from(actual_amount_in), + u128::from(source_account.amount), + u128::from(dest_account.amount), trade_direction, token_swap.fees(), ) .ok_or(SwapError::ZeroTradingTokens)?; - if result.destination_amount_swapped < to_u128(minimum_amount_out)? { - return Err(SwapError::ExceededSlippage.into()); - } + + // Re-calculate the source amount swapped based on what the curve says + let (source_transfer_amount, source_mint_decimals) = { + let source_amount_swapped = to_u64(result.source_amount_swapped)?; + + let source_mint_data = source_token_mint_info.data.borrow(); + let source_mint = Self::unpack_mint_with_extensions( + &source_mint_data, + source_token_mint_info.owner, + token_swap.token_program_id(), + )?; + let amount = + if let Ok(transfer_fee_config) = source_mint.get_extension::() { + source_amount_swapped.saturating_add( + transfer_fee_config + .calculate_inverse_epoch_fee(Clock::get()?.epoch, source_amount_swapped) + .ok_or(SwapError::FeeCalculationFailure)?, + ) + } else { + source_amount_swapped + }; + (amount, source_mint.base.decimals) + }; + + let (destination_transfer_amount, destination_mint_decimals) = { + let destination_mint_data = destination_token_mint_info.data.borrow(); + let destination_mint = Self::unpack_mint_with_extensions( + &destination_mint_data, + source_token_mint_info.owner, + token_swap.token_program_id(), + )?; + let amount_out = to_u64(result.destination_amount_swapped)?; + let amount_received = if let Ok(transfer_fee_config) = + destination_mint.get_extension::() + { + amount_out.saturating_sub( + transfer_fee_config + .calculate_epoch_fee(Clock::get()?.epoch, amount_out) + .ok_or(SwapError::FeeCalculationFailure)?, + ) + } else { + amount_out + }; + if amount_received < minimum_amount_out { + return Err(SwapError::ExceededSlippage.into()); + } + (amount_out, destination_mint.base.decimals) + }; let (swap_token_a_amount, swap_token_b_amount) = match trade_direction { TradeDirection::AtoB => ( @@ -425,27 +545,29 @@ impl Processor { Self::token_transfer( swap_info.key, - token_program_info.clone(), + source_token_program_info.clone(), source_info.clone(), + source_token_mint_info.clone(), swap_source_info.clone(), user_transfer_authority_info.clone(), token_swap.bump_seed(), - to_u64(result.source_amount_swapped)?, + source_transfer_amount, + source_mint_decimals, )?; - let mut pool_token_amount = token_swap - .swap_curve() - .withdraw_single_token_type_exact_out( - result.owner_fee, - swap_token_a_amount, - swap_token_b_amount, - to_u128(pool_mint.supply)?, - trade_direction, - token_swap.fees(), - ) - .ok_or(SwapError::FeeCalculationFailure)?; - - if pool_token_amount > 0 { + if result.owner_fee > 0 { + let mut pool_token_amount = token_swap + .swap_curve() + .calculator + .withdraw_single_token_type_exact_out( + result.owner_fee, + swap_token_a_amount, + swap_token_b_amount, + u128::from(pool_mint.supply), + trade_direction, + RoundDirection::Floor, + ) + .ok_or(SwapError::FeeCalculationFailure)?; // Allow error to fall through if let Ok(host_fee_account_info) = next_account_info(account_info_iter) { let host_fee_account = Self::unpack_token_account( @@ -465,7 +587,7 @@ impl Processor { .ok_or(SwapError::FeeCalculationFailure)?; Self::token_mint_to( swap_info.key, - token_program_info.clone(), + pool_token_program_info.clone(), pool_mint_info.clone(), host_fee_account_info.clone(), authority_info.clone(), @@ -474,25 +596,32 @@ impl Processor { )?; } } - Self::token_mint_to( - swap_info.key, - token_program_info.clone(), - pool_mint_info.clone(), - pool_fee_account_info.clone(), - authority_info.clone(), - token_swap.bump_seed(), - to_u64(pool_token_amount)?, - )?; + if token_swap + .check_pool_fee_info(pool_fee_account_info) + .is_ok() + { + Self::token_mint_to( + swap_info.key, + pool_token_program_info.clone(), + pool_mint_info.clone(), + pool_fee_account_info.clone(), + authority_info.clone(), + token_swap.bump_seed(), + to_u64(pool_token_amount)?, + )?; + }; } Self::token_transfer( swap_info.key, - token_program_info.clone(), + destination_token_program_info.clone(), swap_destination_info.clone(), + destination_token_mint_info.clone(), destination_info.clone(), authority_info.clone(), token_swap.bump_seed(), - to_u64(result.destination_amount_swapped)?, + destination_transfer_amount, + destination_mint_decimals, )?; Ok(()) @@ -516,7 +645,11 @@ impl Processor { let token_b_info = next_account_info(account_info_iter)?; let pool_mint_info = next_account_info(account_info_iter)?; let dest_info = next_account_info(account_info_iter)?; - let token_program_info = next_account_info(account_info_iter)?; + let token_a_mint_info = next_account_info(account_info_iter)?; + let token_b_mint_info = next_account_info(account_info_iter)?; + let token_a_program_info = next_account_info(account_info_iter)?; + let token_b_program_info = next_account_info(account_info_iter)?; + let pool_token_program_info = next_account_info(account_info_iter)?; let token_swap = SwapVersion::unpack(&swap_info.data.borrow())?; let calculator = &token_swap.swap_curve().calculator; @@ -531,7 +664,7 @@ impl Processor { token_a_info, token_b_info, pool_mint_info, - token_program_info, + pool_token_program_info, Some(source_a_info), Some(source_b_info), None, @@ -540,9 +673,9 @@ impl Processor { let token_a = Self::unpack_token_account(token_a_info, token_swap.token_program_id())?; let token_b = Self::unpack_token_account(token_b_info, token_swap.token_program_id())?; let pool_mint = Self::unpack_mint(pool_mint_info, token_swap.token_program_id())?; - let current_pool_mint_supply = to_u128(pool_mint.supply)?; + let current_pool_mint_supply = u128::from(pool_mint.supply); let (pool_token_amount, pool_mint_supply) = if current_pool_mint_supply > 0 { - (to_u128(pool_token_amount)?, current_pool_mint_supply) + (u128::from(pool_token_amount), current_pool_mint_supply) } else { (calculator.new_pool_supply(), calculator.new_pool_supply()) }; @@ -551,8 +684,8 @@ impl Processor { .pool_tokens_to_trading_tokens( pool_token_amount, pool_mint_supply, - to_u128(token_a.amount)?, - to_u128(token_b.amount)?, + u128::from(token_a.amount), + u128::from(token_b.amount), RoundDirection::Ceiling, ) .ok_or(SwapError::ZeroTradingTokens)?; @@ -575,25 +708,29 @@ impl Processor { Self::token_transfer( swap_info.key, - token_program_info.clone(), + token_a_program_info.clone(), source_a_info.clone(), + token_a_mint_info.clone(), token_a_info.clone(), user_transfer_authority_info.clone(), token_swap.bump_seed(), token_a_amount, + Self::unpack_mint(token_a_mint_info, token_swap.token_program_id())?.decimals, )?; Self::token_transfer( swap_info.key, - token_program_info.clone(), + token_b_program_info.clone(), source_b_info.clone(), + token_b_mint_info.clone(), token_b_info.clone(), user_transfer_authority_info.clone(), token_swap.bump_seed(), token_b_amount, + Self::unpack_mint(token_b_mint_info, token_swap.token_program_id())?.decimals, )?; Self::token_mint_to( swap_info.key, - token_program_info.clone(), + pool_token_program_info.clone(), pool_mint_info.clone(), dest_info.clone(), authority_info.clone(), @@ -623,7 +760,11 @@ impl Processor { let dest_token_a_info = next_account_info(account_info_iter)?; let dest_token_b_info = next_account_info(account_info_iter)?; let pool_fee_account_info = next_account_info(account_info_iter)?; - let token_program_info = next_account_info(account_info_iter)?; + let token_a_mint_info = next_account_info(account_info_iter)?; + let token_b_mint_info = next_account_info(account_info_iter)?; + let pool_token_program_info = next_account_info(account_info_iter)?; + let token_a_program_info = next_account_info(account_info_iter)?; + let token_b_program_info = next_account_info(account_info_iter)?; let token_swap = SwapVersion::unpack(&swap_info.data.borrow())?; Self::check_accounts( @@ -634,7 +775,7 @@ impl Processor { token_a_info, token_b_info, pool_mint_info, - token_program_info, + pool_token_program_info, Some(dest_token_a_info), Some(dest_token_b_info), Some(pool_fee_account_info), @@ -646,25 +787,30 @@ impl Processor { let calculator = &token_swap.swap_curve().calculator; - let withdraw_fee: u128 = if *pool_fee_account_info.key == *source_info.key { - // withdrawing from the fee account, don't assess withdraw fee - 0 - } else { - token_swap - .fees() - .owner_withdraw_fee(to_u128(pool_token_amount)?) - .ok_or(SwapError::FeeCalculationFailure)? + let withdraw_fee = match token_swap.check_pool_fee_info(pool_fee_account_info) { + Ok(_) => { + if *pool_fee_account_info.key == *source_info.key { + // withdrawing from the fee account, don't assess withdraw fee + 0 + } else { + token_swap + .fees() + .owner_withdraw_fee(u128::from(pool_token_amount)) + .ok_or(SwapError::FeeCalculationFailure)? + } + } + Err(_) => 0, }; - let pool_token_amount = to_u128(pool_token_amount)? + let pool_token_amount = u128::from(pool_token_amount) .checked_sub(withdraw_fee) .ok_or(SwapError::CalculationFailure)?; let results = calculator .pool_tokens_to_trading_tokens( pool_token_amount, - to_u128(pool_mint.supply)?, - to_u128(token_a.amount)?, - to_u128(token_b.amount)?, + u128::from(pool_mint.supply), + u128::from(token_a.amount), + u128::from(token_b.amount), RoundDirection::Floor, ) .ok_or(SwapError::ZeroTradingTokens)?; @@ -688,17 +834,19 @@ impl Processor { if withdraw_fee > 0 { Self::token_transfer( swap_info.key, - token_program_info.clone(), + pool_token_program_info.clone(), source_info.clone(), + pool_mint_info.clone(), pool_fee_account_info.clone(), user_transfer_authority_info.clone(), token_swap.bump_seed(), to_u64(withdraw_fee)?, + pool_mint.decimals, )?; } Self::token_burn( swap_info.key, - token_program_info.clone(), + pool_token_program_info.clone(), source_info.clone(), pool_mint_info.clone(), user_transfer_authority_info.clone(), @@ -709,23 +857,27 @@ impl Processor { if token_a_amount > 0 { Self::token_transfer( swap_info.key, - token_program_info.clone(), + token_a_program_info.clone(), token_a_info.clone(), + token_a_mint_info.clone(), dest_token_a_info.clone(), authority_info.clone(), token_swap.bump_seed(), token_a_amount, + Self::unpack_mint(token_a_mint_info, token_swap.token_program_id())?.decimals, )?; } if token_b_amount > 0 { Self::token_transfer( swap_info.key, - token_program_info.clone(), + token_b_program_info.clone(), token_b_info.clone(), + token_b_mint_info.clone(), dest_token_b_info.clone(), authority_info.clone(), token_swap.bump_seed(), token_b_amount, + Self::unpack_mint(token_b_mint_info, token_swap.token_program_id())?.decimals, )?; } Ok(()) @@ -747,7 +899,9 @@ impl Processor { let swap_token_b_info = next_account_info(account_info_iter)?; let pool_mint_info = next_account_info(account_info_iter)?; let destination_info = next_account_info(account_info_iter)?; - let token_program_info = next_account_info(account_info_iter)?; + let source_token_mint_info = next_account_info(account_info_iter)?; + let source_token_program_info = next_account_info(account_info_iter)?; + let pool_token_program_info = next_account_info(account_info_iter)?; let token_swap = SwapVersion::unpack(&swap_info.data.borrow())?; let calculator = &token_swap.swap_curve().calculator; @@ -782,21 +936,21 @@ impl Processor { swap_token_a_info, swap_token_b_info, pool_mint_info, - token_program_info, + pool_token_program_info, source_a_info, source_b_info, None, )?; let pool_mint = Self::unpack_mint(pool_mint_info, token_swap.token_program_id())?; - let pool_mint_supply = to_u128(pool_mint.supply)?; + let pool_mint_supply = u128::from(pool_mint.supply); let pool_token_amount = if pool_mint_supply > 0 { token_swap .swap_curve() .deposit_single_token_type( - to_u128(source_token_amount)?, - to_u128(swap_token_a.amount)?, - to_u128(swap_token_b.amount)?, + u128::from(source_token_amount), + u128::from(swap_token_a.amount), + u128::from(swap_token_b.amount), pool_mint_supply, trade_direction, token_swap.fees(), @@ -818,29 +972,35 @@ impl Processor { TradeDirection::AtoB => { Self::token_transfer( swap_info.key, - token_program_info.clone(), + source_token_program_info.clone(), source_info.clone(), + source_token_mint_info.clone(), swap_token_a_info.clone(), user_transfer_authority_info.clone(), token_swap.bump_seed(), source_token_amount, + Self::unpack_mint(source_token_mint_info, token_swap.token_program_id())? + .decimals, )?; } TradeDirection::BtoA => { Self::token_transfer( swap_info.key, - token_program_info.clone(), + source_token_program_info.clone(), source_info.clone(), + source_token_mint_info.clone(), swap_token_b_info.clone(), user_transfer_authority_info.clone(), token_swap.bump_seed(), source_token_amount, + Self::unpack_mint(source_token_mint_info, token_swap.token_program_id())? + .decimals, )?; } } Self::token_mint_to( swap_info.key, - token_program_info.clone(), + pool_token_program_info.clone(), pool_mint_info.clone(), destination_info.clone(), authority_info.clone(), @@ -851,7 +1011,8 @@ impl Processor { Ok(()) } - /// Processes a [WithdrawSingleTokenTypeExactAmountOut](enum.Instruction.html). + /// Processes a + /// [WithdrawSingleTokenTypeExactAmountOut](enum.Instruction.html). pub fn process_withdraw_single_token_type_exact_amount_out( program_id: &Pubkey, destination_token_amount: u64, @@ -868,7 +1029,9 @@ impl Processor { let swap_token_b_info = next_account_info(account_info_iter)?; let destination_info = next_account_info(account_info_iter)?; let pool_fee_account_info = next_account_info(account_info_iter)?; - let token_program_info = next_account_info(account_info_iter)?; + let destination_token_mint_info = next_account_info(account_info_iter)?; + let pool_token_program_info = next_account_info(account_info_iter)?; + let destination_token_program_info = next_account_info(account_info_iter)?; let token_swap = SwapVersion::unpack(&swap_info.data.borrow())?; let destination_account = @@ -898,21 +1061,21 @@ impl Processor { swap_token_a_info, swap_token_b_info, pool_mint_info, - token_program_info, + pool_token_program_info, destination_a_info, destination_b_info, Some(pool_fee_account_info), )?; let pool_mint = Self::unpack_mint(pool_mint_info, token_swap.token_program_id())?; - let pool_mint_supply = to_u128(pool_mint.supply)?; - let swap_token_a_amount = to_u128(swap_token_a.amount)?; - let swap_token_b_amount = to_u128(swap_token_b.amount)?; + let pool_mint_supply = u128::from(pool_mint.supply); + let swap_token_a_amount = u128::from(swap_token_a.amount); + let swap_token_b_amount = u128::from(swap_token_b.amount); let burn_pool_token_amount = token_swap .swap_curve() .withdraw_single_token_type_exact_out( - to_u128(destination_token_amount)?, + u128::from(destination_token_amount), swap_token_a_amount, swap_token_b_amount, pool_mint_supply, @@ -921,14 +1084,19 @@ impl Processor { ) .ok_or(SwapError::ZeroTradingTokens)?; - let withdraw_fee: u128 = if *pool_fee_account_info.key == *source_info.key { - // withdrawing from the fee account, don't assess withdraw fee - 0 - } else { - token_swap - .fees() - .owner_withdraw_fee(burn_pool_token_amount) - .ok_or(SwapError::FeeCalculationFailure)? + let withdraw_fee = match token_swap.check_pool_fee_info(pool_fee_account_info) { + Ok(_) => { + if *pool_fee_account_info.key == *source_info.key { + // withdrawing from the fee account, don't assess withdraw fee + 0 + } else { + token_swap + .fees() + .owner_withdraw_fee(burn_pool_token_amount) + .ok_or(SwapError::FeeCalculationFailure)? + } + } + Err(_) => 0, }; let pool_token_amount = burn_pool_token_amount .checked_add(withdraw_fee) @@ -944,17 +1112,19 @@ impl Processor { if withdraw_fee > 0 { Self::token_transfer( swap_info.key, - token_program_info.clone(), + pool_token_program_info.clone(), source_info.clone(), + pool_mint_info.clone(), pool_fee_account_info.clone(), user_transfer_authority_info.clone(), token_swap.bump_seed(), to_u64(withdraw_fee)?, + pool_mint.decimals, )?; } Self::token_burn( swap_info.key, - token_program_info.clone(), + pool_token_program_info.clone(), source_info.clone(), pool_mint_info.clone(), user_transfer_authority_info.clone(), @@ -966,23 +1136,29 @@ impl Processor { TradeDirection::AtoB => { Self::token_transfer( swap_info.key, - token_program_info.clone(), + destination_token_program_info.clone(), swap_token_a_info.clone(), + destination_token_mint_info.clone(), destination_info.clone(), authority_info.clone(), token_swap.bump_seed(), destination_token_amount, + Self::unpack_mint(destination_token_mint_info, token_swap.token_program_id())? + .decimals, )?; } TradeDirection::BtoA => { Self::token_transfer( swap_info.key, - token_program_info.clone(), + destination_token_program_info.clone(), swap_token_b_info.clone(), + destination_token_mint_info.clone(), destination_info.clone(), authority_info.clone(), token_swap.bump_seed(), destination_token_amount, + Self::unpack_mint(destination_token_mint_info, token_swap.token_program_id())? + .decimals, )?; } } @@ -1075,10 +1251,6 @@ impl Processor { } } -fn to_u128(val: u64) -> Result { - val.try_into().map_err(|_| SwapError::ConversionFailure) -} - fn to_u64(val: u128) -> Result { val.try_into().map_err(|_| SwapError::ConversionFailure) } @@ -1091,36 +1263,50 @@ fn invoke_signed_wrapper( where T: 'static + PrintProgramError + DecodeError + FromPrimitive + Error, { - invoke_signed(instruction, account_infos, signers_seeds).map_err(|err| { + invoke_signed(instruction, account_infos, signers_seeds).inspect_err(|err| { err.print::(); - err }) } #[cfg(test)] mod tests { - use super::*; - use crate::{ - curve::calculator::{CurveCalculator, INITIAL_SWAP_POOL_AMOUNT}, - curve::{ - base::CurveType, constant_price::ConstantPriceCurve, - constant_product::ConstantProductCurve, offset::OffsetCurve, + use { + super::*, + crate::{ + curve::{ + base::CurveType, + calculator::{CurveCalculator, INITIAL_SWAP_POOL_AMOUNT}, + constant_price::ConstantPriceCurve, + constant_product::ConstantProductCurve, + offset::OffsetCurve, + }, + instruction::{ + deposit_all_token_types, deposit_single_token_type_exact_amount_in, initialize, + swap, withdraw_all_token_types, withdraw_single_token_type_exact_amount_out, + }, }, - instruction::{ - deposit_all_token_types, deposit_single_token_type_exact_amount_in, initialize, swap, - withdraw_all_token_types, withdraw_single_token_type_exact_amount_out, + solana_program::{ + clock::Clock, entrypoint::SUCCESS, instruction::Instruction, program_pack::Pack, + program_stubs, rent::Rent, }, - }; - use solana_program::{instruction::Instruction, program_stubs, rent::Rent}; - use solana_sdk::account::{create_account_for_test, create_is_signer_account_infos, Account}; - use spl_token::{ - error::TokenError, - instruction::{ - approve, freeze_account, initialize_account, initialize_mint, mint_to, revoke, - set_authority, AuthorityType, + solana_sdk::account::{ + create_account_for_test, create_is_signer_account_infos, Account as SolanaAccount, + }, + spl_token_2022::{ + error::TokenError, + extension::{ + transfer_fee::{instruction::initialize_transfer_fee_config, TransferFee}, + ExtensionType, + }, + instruction::{ + approve, close_account, freeze_account, initialize_account, + initialize_immutable_owner, initialize_mint, initialize_mint_close_authority, + mint_to, revoke, set_authority, AuthorityType, + }, }, + std::sync::Arc, + test_case::test_case, }; - use std::sync::Arc; // Test program id for the swap program. const SWAP_PROGRAM_ID: Pubkey = Pubkey::new_from_array([2u8; 32]); @@ -1138,7 +1324,10 @@ mod tests { let mut new_account_infos = vec![]; // mimic check for token program in accounts - if !account_infos.iter().any(|x| *x.key == spl_token::id()) { + if !account_infos + .iter() + .any(|x| *x.key == spl_token::id() || *x.key == spl_token_2022::id()) + { return Err(ProgramError::InvalidAccountData); } @@ -1158,11 +1347,28 @@ mod tests { } } - spl_token::processor::Processor::process( - &instruction.program_id, - &new_account_infos, - &instruction.data, - ) + if instruction.program_id == spl_token::id() { + spl_token::processor::Processor::process( + &instruction.program_id, + &new_account_infos, + &instruction.data, + ) + } else if instruction.program_id == spl_token_2022::id() { + spl_token_2022::processor::Processor::process( + &instruction.program_id, + &new_account_infos, + &instruction.data, + ) + } else { + Err(ProgramError::IncorrectProgramId) + } + } + + fn sol_get_clock_sysvar(&self, var_addr: *mut u8) -> u64 { + unsafe { + *(var_addr as *mut _ as *mut Clock) = Clock::default(); + } + SUCCESS } } @@ -1175,46 +1381,67 @@ mod tests { }); } + #[derive(Default)] + struct SwapTransferFees { + pool_token: TransferFee, + token_a: TransferFee, + token_b: TransferFee, + } + struct SwapAccountInfo { bump_seed: u8, authority_key: Pubkey, fees: Fees, + transfer_fees: SwapTransferFees, swap_curve: SwapCurve, swap_key: Pubkey, - swap_account: Account, + swap_account: SolanaAccount, pool_mint_key: Pubkey, - pool_mint_account: Account, + pool_mint_account: SolanaAccount, pool_fee_key: Pubkey, - pool_fee_account: Account, + pool_fee_account: SolanaAccount, pool_token_key: Pubkey, - pool_token_account: Account, + pool_token_account: SolanaAccount, token_a_key: Pubkey, - token_a_account: Account, + token_a_account: SolanaAccount, token_a_mint_key: Pubkey, - token_a_mint_account: Account, + token_a_mint_account: SolanaAccount, token_b_key: Pubkey, - token_b_account: Account, + token_b_account: SolanaAccount, token_b_mint_key: Pubkey, - token_b_mint_account: Account, + token_b_mint_account: SolanaAccount, + pool_token_program_id: Pubkey, + token_a_program_id: Pubkey, + token_b_program_id: Pubkey, } impl SwapAccountInfo { + #[allow(clippy::too_many_arguments)] pub fn new( user_key: &Pubkey, fees: Fees, + transfer_fees: SwapTransferFees, swap_curve: SwapCurve, token_a_amount: u64, token_b_amount: u64, + pool_token_program_id: &Pubkey, + token_a_program_id: &Pubkey, + token_b_program_id: &Pubkey, ) -> Self { let swap_key = Pubkey::new_unique(); - let swap_account = Account::new(0, SwapVersion::LATEST_LEN, &SWAP_PROGRAM_ID); + let swap_account = SolanaAccount::new(0, SwapVersion::LATEST_LEN, &SWAP_PROGRAM_ID); let (authority_key, bump_seed) = Pubkey::find_program_address(&[&swap_key.to_bytes()[..]], &SWAP_PROGRAM_ID); - let (pool_mint_key, mut pool_mint_account) = - create_mint(&spl_token::id(), &authority_key, None); + let (pool_mint_key, mut pool_mint_account) = create_mint( + pool_token_program_id, + &authority_key, + None, + None, + &transfer_fees.pool_token, + ); let (pool_token_key, pool_token_account) = mint_token( - &spl_token::id(), + pool_token_program_id, &pool_mint_key, &mut pool_mint_account, &authority_key, @@ -1222,27 +1449,37 @@ mod tests { 0, ); let (pool_fee_key, pool_fee_account) = mint_token( - &spl_token::id(), + pool_token_program_id, &pool_mint_key, &mut pool_mint_account, &authority_key, user_key, 0, ); - let (token_a_mint_key, mut token_a_mint_account) = - create_mint(&spl_token::id(), user_key, None); + let (token_a_mint_key, mut token_a_mint_account) = create_mint( + token_a_program_id, + user_key, + None, + None, + &transfer_fees.token_a, + ); let (token_a_key, token_a_account) = mint_token( - &spl_token::id(), + token_a_program_id, &token_a_mint_key, &mut token_a_mint_account, user_key, &authority_key, token_a_amount, ); - let (token_b_mint_key, mut token_b_mint_account) = - create_mint(&spl_token::id(), user_key, None); + let (token_b_mint_key, mut token_b_mint_account) = create_mint( + token_b_program_id, + user_key, + None, + None, + &transfer_fees.token_b, + ); let (token_b_key, token_b_account) = mint_token( - &spl_token::id(), + token_b_program_id, &token_b_mint_key, &mut token_b_mint_account, user_key, @@ -1254,6 +1491,7 @@ mod tests { bump_seed, authority_key, fees, + transfer_fees, swap_curve, swap_key, swap_account, @@ -1271,6 +1509,9 @@ mod tests { token_b_account, token_b_mint_key, token_b_mint_account, + pool_token_program_id: *pool_token_program_id, + token_a_program_id: *token_a_program_id, + token_b_program_id: *token_b_program_id, } } @@ -1278,7 +1519,7 @@ mod tests { do_process_instruction( initialize( &SWAP_PROGRAM_ID, - &spl_token::id(), + &self.pool_token_program_id, &self.swap_key, &self.authority_key, &self.token_a_key, @@ -1292,13 +1533,13 @@ mod tests { .unwrap(), vec![ &mut self.swap_account, - &mut Account::default(), + &mut SolanaAccount::default(), &mut self.token_a_account, &mut self.token_b_account, &mut self.pool_mint_account, &mut self.pool_fee_account, &mut self.pool_token_account, - &mut Account::default(), + &mut SolanaAccount::default(), ], ) } @@ -1310,9 +1551,16 @@ mod tests { a_amount: u64, b_amount: u64, pool_amount: u64, - ) -> (Pubkey, Account, Pubkey, Account, Pubkey, Account) { + ) -> ( + Pubkey, + SolanaAccount, + Pubkey, + SolanaAccount, + Pubkey, + SolanaAccount, + ) { let (token_a_key, token_a_account) = mint_token( - &spl_token::id(), + &self.token_a_program_id, &self.token_a_mint_key, &mut self.token_a_mint_account, mint_owner, @@ -1320,7 +1568,7 @@ mod tests { a_amount, ); let (token_b_key, token_b_account) = mint_token( - &spl_token::id(), + &self.token_b_program_id, &self.token_b_mint_key, &mut self.token_b_mint_account, mint_owner, @@ -1328,7 +1576,7 @@ mod tests { b_amount, ); let (pool_key, pool_account) = mint_token( - &spl_token::id(), + &self.pool_token_program_id, &self.pool_mint_key, &mut self.pool_mint_account, &self.authority_key, @@ -1345,16 +1593,47 @@ mod tests { ) } - fn get_token_account(&self, account_key: &Pubkey) -> &Account { + fn get_swap_key(&self, mint_key: &Pubkey) -> &Pubkey { + if *mint_key == self.token_a_mint_key { + &self.token_a_key + } else if *mint_key == self.token_b_mint_key { + &self.token_b_key + } else { + panic!("Could not find matching swap token account"); + } + } + + fn get_token_program_id(&self, account_key: &Pubkey) -> &Pubkey { if *account_key == self.token_a_key { - return &self.token_a_account; + &self.token_a_program_id } else if *account_key == self.token_b_key { - return &self.token_b_account; + &self.token_b_program_id + } else { + panic!("Could not find matching swap token account"); } - panic!("Could not find matching swap token account"); } - fn set_token_account(&mut self, account_key: &Pubkey, account: Account) { + fn get_token_mint(&self, account_key: &Pubkey) -> (Pubkey, SolanaAccount) { + if *account_key == self.token_a_key { + (self.token_a_mint_key, self.token_a_mint_account.clone()) + } else if *account_key == self.token_b_key { + (self.token_b_mint_key, self.token_b_mint_account.clone()) + } else { + panic!("Could not find matching swap token account"); + } + } + + fn get_token_account(&self, account_key: &Pubkey) -> &SolanaAccount { + if *account_key == self.token_a_key { + &self.token_a_account + } else if *account_key == self.token_b_key { + &self.token_b_account + } else { + panic!("Could not find matching swap token account"); + } + } + + fn set_token_account(&mut self, account_key: &Pubkey, account: SolanaAccount) { if *account_key == self.token_a_key { self.token_a_account = account; return; @@ -1370,19 +1649,21 @@ mod tests { &mut self, user_key: &Pubkey, user_source_key: &Pubkey, - user_source_account: &mut Account, + user_source_account: &mut SolanaAccount, swap_source_key: &Pubkey, swap_destination_key: &Pubkey, user_destination_key: &Pubkey, - user_destination_account: &mut Account, + user_destination_account: &mut SolanaAccount, amount_in: u64, minimum_amount_out: u64, ) -> ProgramResult { let user_transfer_key = Pubkey::new_unique(); + let source_token_program_id = self.get_token_program_id(swap_source_key); + let destination_token_program_id = self.get_token_program_id(swap_destination_key); // approve moving from user source account do_process_instruction( approve( - &spl_token::id(), + source_token_program_id, user_source_key, &user_transfer_key, user_key, @@ -1392,12 +1673,15 @@ mod tests { .unwrap(), vec![ user_source_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], ) .unwrap(); + let (source_mint_key, mut source_mint_account) = self.get_token_mint(swap_source_key); + let (destination_mint_key, mut destination_mint_account) = + self.get_token_mint(swap_destination_key); let mut swap_source_account = self.get_token_account(swap_source_key).clone(); let mut swap_destination_account = self.get_token_account(swap_destination_key).clone(); @@ -1405,7 +1689,9 @@ mod tests { do_process_instruction( swap( &SWAP_PROGRAM_ID, - &spl_token::id(), + source_token_program_id, + destination_token_program_id, + &self.pool_token_program_id, &self.swap_key, &self.authority_key, &user_transfer_key, @@ -1415,6 +1701,8 @@ mod tests { user_destination_key, &self.pool_mint_key, &self.pool_fee_key, + &source_mint_key, + &destination_mint_key, None, Swap { amount_in, @@ -1424,15 +1712,19 @@ mod tests { .unwrap(), vec![ &mut self.swap_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), user_source_account, &mut swap_source_account, &mut swap_destination_account, user_destination_account, &mut self.pool_mint_account, &mut self.pool_fee_account, - &mut Account::default(), + &mut source_mint_account, + &mut destination_mint_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], )?; @@ -1447,19 +1739,20 @@ mod tests { &mut self, depositor_key: &Pubkey, depositor_token_a_key: &Pubkey, - depositor_token_a_account: &mut Account, + depositor_token_a_account: &mut SolanaAccount, depositor_token_b_key: &Pubkey, - depositor_token_b_account: &mut Account, + depositor_token_b_account: &mut SolanaAccount, depositor_pool_key: &Pubkey, - depositor_pool_account: &mut Account, + depositor_pool_account: &mut SolanaAccount, pool_token_amount: u64, maximum_token_a_amount: u64, maximum_token_b_amount: u64, ) -> ProgramResult { let user_transfer_authority = Pubkey::new_unique(); + let token_a_program_id = depositor_token_a_account.owner; do_process_instruction( approve( - &spl_token::id(), + &token_a_program_id, depositor_token_a_key, &user_transfer_authority, depositor_key, @@ -1469,15 +1762,16 @@ mod tests { .unwrap(), vec![ depositor_token_a_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], ) .unwrap(); + let token_b_program_id = depositor_token_b_account.owner; do_process_instruction( approve( - &spl_token::id(), + &token_b_program_id, depositor_token_b_key, &user_transfer_authority, depositor_key, @@ -1487,16 +1781,19 @@ mod tests { .unwrap(), vec![ depositor_token_b_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], ) .unwrap(); + let pool_token_program_id = depositor_pool_account.owner; do_process_instruction( deposit_all_token_types( &SWAP_PROGRAM_ID, - &spl_token::id(), + &token_a_program_id, + &token_b_program_id, + &pool_token_program_id, &self.swap_key, &self.authority_key, &user_transfer_authority, @@ -1506,6 +1803,8 @@ mod tests { &self.token_b_key, &self.pool_mint_key, depositor_pool_key, + &self.token_a_mint_key, + &self.token_b_mint_key, DepositAllTokenTypes { pool_token_amount, maximum_token_a_amount, @@ -1515,15 +1814,19 @@ mod tests { .unwrap(), vec![ &mut self.swap_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), depositor_token_a_account, depositor_token_b_account, &mut self.token_a_account, &mut self.token_b_account, &mut self.pool_mint_account, depositor_pool_account, - &mut Account::default(), + &mut self.token_a_mint_account, + &mut self.token_b_mint_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], ) } @@ -1533,20 +1836,21 @@ mod tests { &mut self, user_key: &Pubkey, pool_key: &Pubkey, - pool_account: &mut Account, + pool_account: &mut SolanaAccount, token_a_key: &Pubkey, - token_a_account: &mut Account, + token_a_account: &mut SolanaAccount, token_b_key: &Pubkey, - token_b_account: &mut Account, + token_b_account: &mut SolanaAccount, pool_token_amount: u64, minimum_token_a_amount: u64, minimum_token_b_amount: u64, ) -> ProgramResult { let user_transfer_authority_key = Pubkey::new_unique(); + let pool_token_program_id = pool_account.owner; // approve user transfer authority to take out pool tokens do_process_instruction( approve( - &spl_token::id(), + &pool_token_program_id, pool_key, &user_transfer_authority_key, user_key, @@ -1556,17 +1860,21 @@ mod tests { .unwrap(), vec![ pool_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], ) .unwrap(); // withdraw token a and b correctly + let token_a_program_id = token_a_account.owner; + let token_b_program_id = token_b_account.owner; do_process_instruction( withdraw_all_token_types( &SWAP_PROGRAM_ID, - &spl_token::id(), + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, &self.swap_key, &self.authority_key, &user_transfer_authority_key, @@ -1577,6 +1885,8 @@ mod tests { &self.token_b_key, token_a_key, token_b_key, + &self.token_a_mint_key, + &self.token_b_mint_key, WithdrawAllTokenTypes { pool_token_amount, minimum_token_a_amount, @@ -1586,8 +1896,8 @@ mod tests { .unwrap(), vec![ &mut self.swap_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), &mut self.pool_mint_account, pool_account, &mut self.token_a_account, @@ -1595,7 +1905,11 @@ mod tests { token_a_account, token_b_account, &mut self.pool_fee_account, - &mut Account::default(), + &mut self.token_a_mint_account, + &mut self.token_b_mint_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], ) } @@ -1605,16 +1919,17 @@ mod tests { &mut self, depositor_key: &Pubkey, deposit_account_key: &Pubkey, - deposit_token_account: &mut Account, + deposit_token_account: &mut SolanaAccount, deposit_pool_key: &Pubkey, - deposit_pool_account: &mut Account, + deposit_pool_account: &mut SolanaAccount, source_token_amount: u64, minimum_pool_token_amount: u64, ) -> ProgramResult { let user_transfer_authority_key = Pubkey::new_unique(); + let source_token_program_id = deposit_token_account.owner; do_process_instruction( approve( - &spl_token::id(), + &source_token_program_id, deposit_account_key, &user_transfer_authority_key, depositor_key, @@ -1624,16 +1939,26 @@ mod tests { .unwrap(), vec![ deposit_token_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], ) .unwrap(); + let source_mint_key = + StateWithExtensions::::unpack(&deposit_token_account.data) + .unwrap() + .base + .mint; + let swap_source_key = self.get_swap_key(&source_mint_key); + let (source_mint_key, mut source_mint_account) = self.get_token_mint(swap_source_key); + + let pool_token_program_id = deposit_pool_account.owner; do_process_instruction( deposit_single_token_type_exact_amount_in( &SWAP_PROGRAM_ID, - &spl_token::id(), + &source_token_program_id, + &pool_token_program_id, &self.swap_key, &self.authority_key, &user_transfer_authority_key, @@ -1642,6 +1967,7 @@ mod tests { &self.token_b_key, &self.pool_mint_key, deposit_pool_key, + &source_mint_key, DepositSingleTokenTypeExactAmountIn { source_token_amount, minimum_pool_token_amount, @@ -1650,14 +1976,16 @@ mod tests { .unwrap(), vec![ &mut self.swap_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), deposit_token_account, &mut self.token_a_account, &mut self.token_b_account, &mut self.pool_mint_account, deposit_pool_account, - &mut Account::default(), + &mut source_mint_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], ) } @@ -1667,17 +1995,18 @@ mod tests { &mut self, user_key: &Pubkey, pool_key: &Pubkey, - pool_account: &mut Account, + pool_account: &mut SolanaAccount, destination_key: &Pubkey, - destination_account: &mut Account, + destination_account: &mut SolanaAccount, destination_token_amount: u64, maximum_pool_token_amount: u64, ) -> ProgramResult { let user_transfer_authority_key = Pubkey::new_unique(); + let pool_token_program_id = pool_account.owner; // approve user transfer authority to take out pool tokens do_process_instruction( approve( - &spl_token::id(), + &pool_token_program_id, pool_key, &user_transfer_authority_key, user_key, @@ -1687,16 +2016,27 @@ mod tests { .unwrap(), vec![ pool_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], ) .unwrap(); + let destination_mint_key = + StateWithExtensions::::unpack(&destination_account.data) + .unwrap() + .base + .mint; + let swap_destination_key = self.get_swap_key(&destination_mint_key); + let (destination_mint_key, mut destination_mint_account) = + self.get_token_mint(swap_destination_key); + + let destination_token_program_id = destination_account.owner; do_process_instruction( withdraw_single_token_type_exact_amount_out( &SWAP_PROGRAM_ID, - &spl_token::id(), + &pool_token_program_id, + &destination_token_program_id, &self.swap_key, &self.authority_key, &user_transfer_authority_key, @@ -1706,6 +2046,7 @@ mod tests { &self.token_a_key, &self.token_b_key, destination_key, + &destination_mint_key, WithdrawSingleTokenTypeExactAmountOut { destination_token_amount, maximum_pool_token_amount, @@ -1714,15 +2055,17 @@ mod tests { .unwrap(), vec![ &mut self.swap_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), &mut self.pool_mint_account, pool_account, &mut self.token_a_account, &mut self.token_b_account, destination_account, &mut self.pool_fee_account, - &mut Account::default(), + &mut destination_mint_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], ) } @@ -1738,7 +2081,7 @@ mod tests { fn do_process_instruction_with_fee_constraints( instruction: Instruction, - accounts: Vec<&mut Account>, + accounts: Vec<&mut SolanaAccount>, swap_constraints: &Option, ) -> ProgramResult { test_syscall_stubs(); @@ -1760,12 +2103,20 @@ mod tests { &instruction.data, swap_constraints, ) - } else { + } else if instruction.program_id == spl_token::id() { spl_token::processor::Processor::process( &instruction.program_id, &account_infos, &instruction.data, ) + } else if instruction.program_id == spl_token_2022::id() { + spl_token_2022::processor::Processor::process( + &instruction.program_id, + &account_infos, + &instruction.data, + ) + } else { + Err(ProgramError::IncorrectProgramId) }; if res.is_ok() { @@ -1791,7 +2142,7 @@ mod tests { fn do_process_instruction( instruction: Instruction, - accounts: Vec<&mut Account>, + accounts: Vec<&mut SolanaAccount>, ) -> ProgramResult { do_process_instruction_with_fee_constraints(instruction, accounts, &SWAP_CONSTRAINTS) } @@ -1799,20 +2150,33 @@ mod tests { fn mint_token( program_id: &Pubkey, mint_key: &Pubkey, - mint_account: &mut Account, + mint_account: &mut SolanaAccount, mint_authority_key: &Pubkey, account_owner_key: &Pubkey, amount: u64, - ) -> (Pubkey, Account) { + ) -> (Pubkey, SolanaAccount) { let account_key = Pubkey::new_unique(); - let mut account_account = Account::new( - account_minimum_balance(), - spl_token::state::Account::get_packed_len(), - program_id, - ); - let mut mint_authority_account = Account::default(); + let space = if *program_id == spl_token_2022::id() { + ExtensionType::try_calculate_account_len::(&[ + ExtensionType::ImmutableOwner, + ExtensionType::TransferFeeAmount, + ]) + .unwrap() + } else { + Account::get_packed_len() + }; + let minimum_balance = Rent::default().minimum_balance(space); + let mut account_account = SolanaAccount::new(minimum_balance, space, program_id); + let mut mint_authority_account = SolanaAccount::default(); let mut rent_sysvar_account = create_account_for_test(&Rent::free()); + // no-ops in normal token, so we're good to run it either way + do_process_instruction( + initialize_immutable_owner(program_id, &account_key).unwrap(), + vec![&mut account_account], + ) + .unwrap(); + do_process_instruction( initialize_account(program_id, &account_key, mint_key, account_owner_key).unwrap(), vec![ @@ -1851,15 +2215,53 @@ mod tests { program_id: &Pubkey, authority_key: &Pubkey, freeze_authority: Option<&Pubkey>, - ) -> (Pubkey, Account) { + close_authority: Option<&Pubkey>, + fees: &TransferFee, + ) -> (Pubkey, SolanaAccount) { let mint_key = Pubkey::new_unique(); - let mut mint_account = Account::new( - mint_minimum_balance(), - spl_token::state::Mint::get_packed_len(), - program_id, - ); + let space = if *program_id == spl_token_2022::id() { + if close_authority.is_some() { + ExtensionType::try_calculate_account_len::(&[ + ExtensionType::MintCloseAuthority, + ExtensionType::TransferFeeConfig, + ]) + .unwrap() + } else { + ExtensionType::try_calculate_account_len::(&[ + ExtensionType::TransferFeeConfig, + ]) + .unwrap() + } + } else { + Mint::get_packed_len() + }; + let minimum_balance = Rent::default().minimum_balance(space); + let mut mint_account = SolanaAccount::new(minimum_balance, space, program_id); let mut rent_sysvar_account = create_account_for_test(&Rent::free()); + if *program_id == spl_token_2022::id() { + if close_authority.is_some() { + do_process_instruction( + initialize_mint_close_authority(program_id, &mint_key, close_authority) + .unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + } + do_process_instruction( + initialize_transfer_fee_config( + program_id, + &mint_key, + freeze_authority, + freeze_authority, + fees.transfer_fee_basis_points.into(), + fees.maximum_fee.into(), + ) + .unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + } do_process_instruction( initialize_mint(program_id, &mint_key, authority_key, freeze_authority, 2).unwrap(), vec![&mut mint_account, &mut rent_sysvar_account], @@ -1869,16 +2271,17 @@ mod tests { (mint_key, mint_account) } - #[test] - fn test_token_program_id_error() { + #[test_case(spl_token::id(); "token")] + #[test_case(spl_token_2022::id(); "token-2022")] + fn test_token_program_id_error(token_program_id: Pubkey) { test_syscall_stubs(); let swap_key = Pubkey::new_unique(); - let mut mint = (Pubkey::new_unique(), Account::default()); - let mut destination = (Pubkey::new_unique(), Account::default()); - let token_program = (spl_token::id(), Account::default()); + let mut mint = (Pubkey::new_unique(), SolanaAccount::default()); + let mut destination = (Pubkey::new_unique(), SolanaAccount::default()); + let token_program = (token_program_id, SolanaAccount::default()); let (authority_key, bump_seed) = Pubkey::find_program_address(&[&swap_key.to_bytes()[..]], &SWAP_PROGRAM_ID); - let mut authority = (authority_key, Account::default()); + let mut authority = (authority_key, SolanaAccount::default()); let swap_bytes = swap_key.to_bytes(); let authority_signature_seeds = [&swap_bytes[..32], &[bump_seed]]; let signers = &[&authority_signature_seeds[..]]; @@ -1899,31 +2302,31 @@ mod tests { assert_eq!(err, ProgramError::InvalidAccountData); } - #[test] - fn test_token_error() { + #[test_case(spl_token::id(); "token")] + #[test_case(spl_token_2022::id(); "token-2022")] + fn test_token_error(token_program_id: Pubkey) { test_syscall_stubs(); - let token_id = spl_token::id(); let swap_key = Pubkey::new_unique(); let mut mint = ( Pubkey::new_unique(), - Account::new( + SolanaAccount::new( mint_minimum_balance(), spl_token::state::Mint::get_packed_len(), - &token_id, + &token_program_id, ), ); let mut destination = ( Pubkey::new_unique(), - Account::new( + SolanaAccount::new( account_minimum_balance(), spl_token::state::Account::get_packed_len(), - &token_id, + &token_program_id, ), ); - let mut token_program = (token_id, Account::default()); + let mut token_program = (token_program_id, SolanaAccount::default()); let (authority_key, bump_seed) = Pubkey::find_program_address(&[&swap_key.to_bytes()[..]], &SWAP_PROGRAM_ID); - let mut authority = (authority_key, Account::default()); + let mut authority = (authority_key, SolanaAccount::default()); let swap_bytes = swap_key.to_bytes(); let authority_signature_seeds = [&swap_bytes[..32], &[bump_seed]]; let signers = &[&authority_signature_seeds[..]]; @@ -1992,8 +2395,15 @@ mod tests { assert_eq!(err, ProgramError::Custom(TokenError::AccountFrozen as u32)); } - #[test] - fn test_initialize() { + #[test_case(spl_token::id(), spl_token::id(), spl_token::id(); "all-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token_2022::id(); "all-token-2022")] + #[test_case(spl_token::id(), spl_token_2022::id(), spl_token_2022::id(); "mixed-pool-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token::id(); "mixed-pool-token-2022")] + fn test_initialize( + pool_token_program_id: Pubkey, + token_a_program_id: Pubkey, + token_b_program_id: Pubkey, + ) { let user_key = Pubkey::new_unique(); let trade_fee_numerator = 1; let trade_fee_denominator = 2; @@ -2023,13 +2433,22 @@ mod tests { calculator: Arc::new(ConstantProductCurve {}), }; - let mut accounts = - SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount); + let mut accounts = SwapAccountInfo::new( + &user_key, + fees, + SwapTransferFees::default(), + swap_curve, + token_a_amount, + token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, + ); // uninitialized token a account { let old_account = accounts.token_a_account; - accounts.token_a_account = Account::new(0, 0, &spl_token::id()); + accounts.token_a_account = SolanaAccount::new(0, 0, &token_a_program_id); assert_eq!( Err(SwapError::ExpectedAccount.into()), accounts.initialize_swap() @@ -2040,7 +2459,7 @@ mod tests { // uninitialized token b account { let old_account = accounts.token_b_account; - accounts.token_b_account = Account::new(0, 0, &spl_token::id()); + accounts.token_b_account = SolanaAccount::new(0, 0, &token_b_program_id); assert_eq!( Err(SwapError::ExpectedAccount.into()), accounts.initialize_swap() @@ -2051,7 +2470,7 @@ mod tests { // uninitialized pool mint { let old_account = accounts.pool_mint_account; - accounts.pool_mint_account = Account::new(0, 0, &spl_token::id()); + accounts.pool_mint_account = SolanaAccount::new(0, 0, &pool_token_program_id); assert_eq!( Err(SwapError::ExpectedMint.into()), accounts.initialize_swap() @@ -2062,7 +2481,7 @@ mod tests { // token A account owner is not swap authority { let (_token_a_key, token_a_account) = mint_token( - &spl_token::id(), + &token_a_program_id, &accounts.token_a_mint_key, &mut accounts.token_a_mint_account, &user_key, @@ -2081,7 +2500,7 @@ mod tests { // token B account owner is not swap authority { let (_token_b_key, token_b_account) = mint_token( - &spl_token::id(), + &token_b_program_id, &accounts.token_b_mint_key, &mut accounts.token_b_mint_account, &user_key, @@ -2100,7 +2519,7 @@ mod tests { // pool token account owner is swap authority { let (_pool_token_key, pool_token_account) = mint_token( - &spl_token::id(), + &pool_token_program_id, &accounts.pool_mint_key, &mut accounts.pool_mint_account, &accounts.authority_key, @@ -2119,7 +2538,7 @@ mod tests { // pool fee account owner is swap authority { let (_pool_fee_key, pool_fee_account) = mint_token( - &spl_token::id(), + &pool_token_program_id, &accounts.pool_mint_key, &mut accounts.pool_mint_account, &accounts.authority_key, @@ -2137,8 +2556,13 @@ mod tests { // pool mint authority is not swap authority { - let (_pool_mint_key, pool_mint_account) = - create_mint(&spl_token::id(), &user_key, None); + let (_pool_mint_key, pool_mint_account) = create_mint( + &pool_token_program_id, + &user_key, + None, + None, + &TransferFee::default(), + ); let old_mint = accounts.pool_mint_account; accounts.pool_mint_account = pool_mint_account; assert_eq!( @@ -2150,8 +2574,13 @@ mod tests { // pool mint token has freeze authority { - let (_pool_mint_key, pool_mint_account) = - create_mint(&spl_token::id(), &accounts.authority_key, Some(&user_key)); + let (_pool_mint_key, pool_mint_account) = create_mint( + &pool_token_program_id, + &accounts.authority_key, + Some(&user_key), + None, + &TransferFee::default(), + ); let old_mint = accounts.pool_mint_account; accounts.pool_mint_account = pool_mint_account; assert_eq!( @@ -2161,10 +2590,28 @@ mod tests { accounts.pool_mint_account = old_mint; } + // pool mint token has close authority, only available in token-2022 + if pool_token_program_id == spl_token_2022::id() { + let (_pool_mint_key, pool_mint_account) = create_mint( + &pool_token_program_id, + &accounts.authority_key, + None, + Some(&user_key), + &TransferFee::default(), + ); + let old_mint = accounts.pool_mint_account; + accounts.pool_mint_account = pool_mint_account; + assert_eq!( + Err(SwapError::InvalidCloseAuthority.into()), + accounts.initialize_swap() + ); + accounts.pool_mint_account = old_mint; + } + // token A account owned by wrong program { let (_token_a_key, mut token_a_account) = mint_token( - &spl_token::id(), + &token_a_program_id, &accounts.token_a_mint_key, &mut accounts.token_a_mint_account, &user_key, @@ -2184,7 +2631,7 @@ mod tests { // token B account owned by wrong program { let (_token_b_key, mut token_b_account) = mint_token( - &spl_token::id(), + &token_b_program_id, &accounts.token_b_mint_key, &mut accounts.token_b_mint_account, &user_key, @@ -2204,7 +2651,7 @@ mod tests { // empty token A account { let (_token_a_key, token_a_account) = mint_token( - &spl_token::id(), + &token_a_program_id, &accounts.token_a_mint_key, &mut accounts.token_a_mint_account, &user_key, @@ -2223,7 +2670,7 @@ mod tests { // empty token B account { let (_token_b_key, token_b_account) = mint_token( - &spl_token::id(), + &token_b_program_id, &accounts.token_b_mint_key, &mut accounts.token_b_mint_account, &user_key, @@ -2244,12 +2691,17 @@ mod tests { let old_mint = accounts.pool_mint_account; let old_pool_account = accounts.pool_token_account; - let (_pool_mint_key, pool_mint_account) = - create_mint(&spl_token::id(), &accounts.authority_key, None); + let (_pool_mint_key, pool_mint_account) = create_mint( + &pool_token_program_id, + &accounts.authority_key, + None, + None, + &TransferFee::default(), + ); accounts.pool_mint_account = pool_mint_account; let (_empty_pool_token_key, empty_pool_token_account) = mint_token( - &spl_token::id(), + &pool_token_program_id, &accounts.pool_mint_key, &mut accounts.pool_mint_account, &accounts.authority_key, @@ -2258,7 +2710,7 @@ mod tests { ); let (_pool_token_key, pool_token_account) = mint_token( - &spl_token::id(), + &pool_token_program_id, &accounts.pool_mint_key, &mut accounts.pool_mint_account, &accounts.authority_key, @@ -2287,7 +2739,7 @@ mod tests { // pool fee account has wrong mint { let (_pool_fee_key, pool_fee_account) = mint_token( - &spl_token::id(), + &token_a_program_id, &accounts.token_a_mint_key, &mut accounts.token_a_mint_account, &user_key, @@ -2307,7 +2759,7 @@ mod tests { { do_process_instruction( approve( - &spl_token::id(), + &token_a_program_id, &accounts.token_a_key, &user_key, &accounts.authority_key, @@ -2317,8 +2769,8 @@ mod tests { .unwrap(), vec![ &mut accounts.token_a_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], ) .unwrap(); @@ -2329,13 +2781,13 @@ mod tests { do_process_instruction( revoke( - &spl_token::id(), + &token_a_program_id, &accounts.token_a_key, &accounts.authority_key, &[], ) .unwrap(), - vec![&mut accounts.token_a_account, &mut Account::default()], + vec![&mut accounts.token_a_account, &mut SolanaAccount::default()], ) .unwrap(); } @@ -2344,7 +2796,7 @@ mod tests { { do_process_instruction( approve( - &spl_token::id(), + &token_b_program_id, &accounts.token_b_key, &user_key, &accounts.authority_key, @@ -2354,8 +2806,8 @@ mod tests { .unwrap(), vec![ &mut accounts.token_b_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], ) .unwrap(); @@ -2366,13 +2818,13 @@ mod tests { do_process_instruction( revoke( - &spl_token::id(), + &token_b_program_id, &accounts.token_b_key, &accounts.authority_key, &[], ) .unwrap(), - vec![&mut accounts.token_b_account, &mut Account::default()], + vec![&mut accounts.token_b_account, &mut SolanaAccount::default()], ) .unwrap(); } @@ -2381,7 +2833,7 @@ mod tests { { do_process_instruction( set_authority( - &spl_token::id(), + &token_a_program_id, &accounts.token_a_key, Some(&user_key), AuthorityType::CloseAccount, @@ -2389,7 +2841,7 @@ mod tests { &[], ) .unwrap(), - vec![&mut accounts.token_a_account, &mut Account::default()], + vec![&mut accounts.token_a_account, &mut SolanaAccount::default()], ) .unwrap(); assert_eq!( @@ -2399,7 +2851,7 @@ mod tests { do_process_instruction( set_authority( - &spl_token::id(), + &token_a_program_id, &accounts.token_a_key, None, AuthorityType::CloseAccount, @@ -2407,7 +2859,7 @@ mod tests { &[], ) .unwrap(), - vec![&mut accounts.token_a_account, &mut Account::default()], + vec![&mut accounts.token_a_account, &mut SolanaAccount::default()], ) .unwrap(); } @@ -2416,7 +2868,7 @@ mod tests { { do_process_instruction( set_authority( - &spl_token::id(), + &token_b_program_id, &accounts.token_b_key, Some(&user_key), AuthorityType::CloseAccount, @@ -2424,7 +2876,7 @@ mod tests { &[], ) .unwrap(), - vec![&mut accounts.token_b_account, &mut Account::default()], + vec![&mut accounts.token_b_account, &mut SolanaAccount::default()], ) .unwrap(); assert_eq!( @@ -2434,7 +2886,7 @@ mod tests { do_process_instruction( set_authority( - &spl_token::id(), + &token_b_program_id, &accounts.token_b_key, None, AuthorityType::CloseAccount, @@ -2442,7 +2894,7 @@ mod tests { &[], ) .unwrap(), - vec![&mut accounts.token_b_account, &mut Account::default()], + vec![&mut accounts.token_b_account, &mut SolanaAccount::default()], ) .unwrap(); } @@ -2451,7 +2903,7 @@ mod tests { { let wrong_program_id = Pubkey::new_unique(); assert_eq!( - Err(SwapError::IncorrectTokenProgramId.into()), + Err(ProgramError::IncorrectProgramId), do_process_instruction( initialize( &SWAP_PROGRAM_ID, @@ -2469,13 +2921,13 @@ mod tests { .unwrap(), vec![ &mut accounts.swap_account, - &mut Account::default(), + &mut SolanaAccount::default(), &mut accounts.token_a_account, &mut accounts.token_b_account, &mut accounts.pool_mint_account, &mut accounts.pool_fee_account, &mut accounts.pool_token_account, - &mut Account::default(), + &mut SolanaAccount::default(), ], ) ); @@ -2484,7 +2936,7 @@ mod tests { // create swap with same token A and B { let (_token_a_repeat_key, token_a_repeat_account) = mint_token( - &spl_token::id(), + &token_a_program_id, &accounts.token_a_mint_key, &mut accounts.token_a_mint_account, &user_key, @@ -2520,8 +2972,17 @@ mod tests { curve_type: CurveType::ConstantPrice, calculator: Arc::new(ConstantPriceCurve { token_b_price }), }; - let mut accounts = - SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount); + let mut accounts = SwapAccountInfo::new( + &user_key, + fees, + SwapTransferFees::default(), + swap_curve, + token_a_amount, + token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, + ); assert_eq!( Err(SwapError::InvalidCurve.into()), accounts.initialize_swap() @@ -2545,8 +3006,17 @@ mod tests { curve_type: CurveType::ConstantPrice, calculator: Arc::new(ConstantPriceCurve { token_b_price }), }; - let mut accounts = - SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount); + let mut accounts = SwapAccountInfo::new( + &user_key, + fees, + SwapTransferFees::default(), + swap_curve, + token_a_amount, + token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, + ); accounts.initialize_swap().unwrap(); } @@ -2567,8 +3037,17 @@ mod tests { curve_type: CurveType::Offset, calculator: Arc::new(OffsetCurve { token_b_offset }), }; - let mut accounts = - SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount); + let mut accounts = SwapAccountInfo::new( + &user_key, + fees, + SwapTransferFees::default(), + swap_curve, + token_a_amount, + token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, + ); assert_eq!( Err(SwapError::InvalidCurve.into()), accounts.initialize_swap() @@ -2592,8 +3071,17 @@ mod tests { curve_type: CurveType::Offset, calculator: Arc::new(OffsetCurve { token_b_offset }), }; - let mut accounts = - SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount); + let mut accounts = SwapAccountInfo::new( + &user_key, + fees, + SwapTransferFees::default(), + swap_curve, + token_a_amount, + token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, + ); accounts.initialize_swap().unwrap(); } @@ -2621,26 +3109,30 @@ mod tests { curve_type: CurveType::ConstantProduct, calculator: Arc::new(curve), }; - let owner_key = &new_key.to_string(); + let owner_key = new_key.to_string(); let valid_curve_types = &[CurveType::ConstantProduct]; let constraints = Some(SwapConstraints { - owner_key, + owner_key: Some(owner_key.as_ref()), valid_curve_types, fees: &fees, }); let mut accounts = SwapAccountInfo::new( &user_key, fees.clone(), + SwapTransferFees::default(), swap_curve, token_a_amount, token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, ); assert_eq!( Err(SwapError::InvalidOwner.into()), do_process_instruction_with_fee_constraints( initialize( &SWAP_PROGRAM_ID, - &spl_token::id(), + &pool_token_program_id, &accounts.swap_key, &accounts.authority_key, &accounts.token_a_key, @@ -2654,13 +3146,13 @@ mod tests { .unwrap(), vec![ &mut accounts.swap_account, - &mut Account::default(), + &mut SolanaAccount::default(), &mut accounts.token_a_account, &mut accounts.token_b_account, &mut accounts.pool_mint_account, &mut accounts.pool_fee_account, &mut accounts.pool_token_account, - &mut Account::default(), + &mut SolanaAccount::default(), ], &constraints, ) @@ -2690,10 +3182,10 @@ mod tests { curve_type: CurveType::ConstantProduct, calculator: Arc::new(curve), }; - let owner_key = &user_key.to_string(); + let owner_key = user_key.to_string(); let valid_curve_types = &[CurveType::ConstantProduct]; let constraints = Some(SwapConstraints { - owner_key, + owner_key: Some(owner_key.as_ref()), valid_curve_types, fees: &fees, }); @@ -2702,16 +3194,20 @@ mod tests { let mut accounts = SwapAccountInfo::new( &user_key, bad_fees, + SwapTransferFees::default(), swap_curve, token_a_amount, token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, ); assert_eq!( Err(SwapError::InvalidFee.into()), do_process_instruction_with_fee_constraints( initialize( &SWAP_PROGRAM_ID, - &spl_token::id(), + &pool_token_program_id, &accounts.swap_key, &accounts.authority_key, &accounts.token_a_key, @@ -2725,13 +3221,13 @@ mod tests { .unwrap(), vec![ &mut accounts.swap_account, - &mut Account::default(), + &mut SolanaAccount::default(), &mut accounts.token_a_account, &mut accounts.token_b_account, &mut accounts.pool_mint_account, &mut accounts.pool_fee_account, &mut accounts.pool_token_account, - &mut Account::default(), + &mut SolanaAccount::default(), ], &constraints, ) @@ -2761,24 +3257,28 @@ mod tests { curve_type: CurveType::ConstantProduct, calculator: Arc::new(curve), }; - let owner_key = &user_key.to_string(); + let owner_key = user_key.to_string(); let valid_curve_types = &[CurveType::ConstantProduct]; let constraints = Some(SwapConstraints { - owner_key, + owner_key: Some(owner_key.as_ref()), valid_curve_types, fees: &fees, }); let mut accounts = SwapAccountInfo::new( &user_key, fees.clone(), + SwapTransferFees::default(), swap_curve, token_a_amount, token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, ); do_process_instruction_with_fee_constraints( initialize( &SWAP_PROGRAM_ID, - &spl_token::id(), + &pool_token_program_id, &accounts.swap_key, &accounts.authority_key, &accounts.token_a_key, @@ -2792,13 +3292,13 @@ mod tests { .unwrap(), vec![ &mut accounts.swap_account, - &mut Account::default(), + &mut SolanaAccount::default(), &mut accounts.token_a_account, &mut accounts.token_b_account, &mut accounts.pool_mint_account, &mut accounts.pool_fee_account, &mut accounts.pool_token_account, - &mut Account::default(), + &mut SolanaAccount::default(), ], &constraints, ) @@ -2825,18 +3325,28 @@ mod tests { assert_eq!(*swap_state.token_a_mint(), accounts.token_a_mint_key); assert_eq!(*swap_state.token_b_mint(), accounts.token_b_mint_key); assert_eq!(*swap_state.pool_fee_account(), accounts.pool_fee_key); - let token_a = spl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap(); - assert_eq!(token_a.amount, token_a_amount); - let token_b = spl_token::state::Account::unpack(&accounts.token_b_account.data).unwrap(); - assert_eq!(token_b.amount, token_b_amount); + let token_a = + StateWithExtensions::::unpack(&accounts.token_a_account.data).unwrap(); + assert_eq!(token_a.base.amount, token_a_amount); + let token_b = + StateWithExtensions::::unpack(&accounts.token_b_account.data).unwrap(); + assert_eq!(token_b.base.amount, token_b_amount); let pool_account = - spl_token::state::Account::unpack(&accounts.pool_token_account.data).unwrap(); - let pool_mint = spl_token::state::Mint::unpack(&accounts.pool_mint_account.data).unwrap(); - assert_eq!(pool_mint.supply, pool_account.amount); + StateWithExtensions::::unpack(&accounts.pool_token_account.data).unwrap(); + let pool_mint = + StateWithExtensions::::unpack(&accounts.pool_mint_account.data).unwrap(); + assert_eq!(pool_mint.base.supply, pool_account.base.amount); } - #[test] - fn test_deposit() { + #[test_case(spl_token::id(), spl_token::id(), spl_token::id(); "all-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token_2022::id(); "all-token-2022")] + #[test_case(spl_token::id(), spl_token_2022::id(), spl_token_2022::id(); "mixed-pool-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token::id(); "mixed-pool-token-2022")] + fn test_deposit( + pool_token_program_id: Pubkey, + token_a_program_id: Pubkey, + token_b_program_id: Pubkey, + ) { let user_key = Pubkey::new_unique(); let depositor_key = Pubkey::new_unique(); let trade_fee_numerator = 1; @@ -2867,8 +3377,17 @@ mod tests { calculator: Arc::new(ConstantProductCurve {}), }; - let mut accounts = - SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount); + let mut accounts = SwapAccountInfo::new( + &user_key, + fees, + SwapTransferFees::default(), + swap_curve, + token_a_amount, + token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, + ); // depositing 10% of the current pool amount in token A and B means // that our pool tokens will be worth 1 / 10 of the current pool amount @@ -2917,7 +3436,7 @@ mod tests { ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0); let old_swap_account = accounts.swap_account; let mut wrong_swap_account = old_swap_account.clone(); - wrong_swap_account.owner = spl_token::id(); + wrong_swap_account.owner = pool_token_program_id; accounts.swap_account = wrong_swap_account; assert_eq!( Err(ProgramError::IncorrectProgramId), @@ -2950,7 +3469,7 @@ mod tests { let old_authority = accounts.authority_key; let (bad_authority_key, _bump_seed) = Pubkey::find_program_address( &[&accounts.swap_key.to_bytes()[..]], - &spl_token::id(), + &pool_token_program_id, ); accounts.authority_key = bad_authority_key; assert_eq!( @@ -3047,8 +3566,13 @@ mod tests { pool_key, mut pool_account, ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0); + let expected_error: ProgramError = if token_a_account.owner == token_b_account.owner { + TokenError::MintMismatch.into() + } else { + ProgramError::InvalidAccountData + }; assert_eq!( - Err(TokenError::MintMismatch.into()), + Err(expected_error), accounts.deposit_all_token_types( &depositor_key, &token_b_key, @@ -3080,10 +3604,15 @@ mod tests { _token_b_key, mut _token_b_account, _pool_key, - mut _pool_account, + pool_account, ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0); + let expected_error: ProgramError = if token_a_account.owner == pool_account.owner { + TokenError::MintMismatch.into() + } else { + SwapError::IncorrectTokenProgramId.into() + }; assert_eq!( - Err(TokenError::MintMismatch.into()), + Err(expected_error), accounts.deposit_all_token_types( &depositor_key, &token_a_key, @@ -3115,7 +3644,9 @@ mod tests { do_process_instruction( deposit_all_token_types( &SWAP_PROGRAM_ID, - &spl_token::id(), + &token_a_program_id, + &token_b_program_id, + &pool_token_program_id, &accounts.swap_key, &accounts.authority_key, &user_transfer_authority_key, @@ -3125,6 +3656,8 @@ mod tests { &accounts.token_b_key, &accounts.pool_mint_key, &pool_key, + &accounts.token_a_mint_key, + &accounts.token_b_mint_key, DepositAllTokenTypes { pool_token_amount: pool_amount.try_into().unwrap(), maximum_token_a_amount: deposit_a, @@ -3134,15 +3667,19 @@ mod tests { .unwrap(), vec![ &mut accounts.swap_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), &mut token_a_account, &mut token_b_account, &mut accounts.token_a_account, &mut accounts.token_b_account, &mut accounts.pool_mint_account, &mut pool_account, - &mut Account::default(), + &mut accounts.token_a_mint_account, + &mut accounts.token_b_mint_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], ) ); @@ -3165,6 +3702,8 @@ mod tests { deposit_all_token_types( &SWAP_PROGRAM_ID, &wrong_key, + &wrong_key, + &wrong_key, &accounts.swap_key, &accounts.authority_key, &accounts.authority_key, @@ -3174,6 +3713,8 @@ mod tests { &accounts.token_b_key, &accounts.pool_mint_key, &pool_key, + &accounts.token_a_mint_key, + &accounts.token_b_mint_key, DepositAllTokenTypes { pool_token_amount: pool_amount.try_into().unwrap(), maximum_token_a_amount: deposit_a, @@ -3183,15 +3724,19 @@ mod tests { .unwrap(), vec![ &mut accounts.swap_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), &mut token_a_account, &mut token_b_account, &mut accounts.token_a_account, &mut accounts.token_b_account, &mut accounts.pool_mint_account, &mut pool_account, - &mut Account::default(), + &mut accounts.token_a_mint_account, + &mut accounts.token_b_mint_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], ) ); @@ -3271,8 +3816,13 @@ mod tests { pool_key, mut pool_account, ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0); - let (pool_mint_key, pool_mint_account) = - create_mint(&spl_token::id(), &accounts.authority_key, None); + let (pool_mint_key, pool_mint_account) = create_mint( + &pool_token_program_id, + &accounts.authority_key, + None, + None, + &TransferFee::default(), + ); let old_pool_key = accounts.pool_mint_key; let old_pool_account = accounts.pool_mint_account; accounts.pool_mint_key = pool_mint_key; @@ -3298,7 +3848,7 @@ mod tests { accounts.pool_mint_account = old_pool_account; } - // deposit 1 pool token fails beacuse it equates to 0 swap tokens + // deposit 1 pool token fails because it equates to 0 swap tokens { let ( token_a_key, @@ -3427,29 +3977,36 @@ mod tests { .unwrap(); let swap_token_a = - spl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap(); - assert_eq!(swap_token_a.amount, deposit_a + token_a_amount); + StateWithExtensions::::unpack(&accounts.token_a_account.data).unwrap(); + assert_eq!(swap_token_a.base.amount, deposit_a + token_a_amount); let swap_token_b = - spl_token::state::Account::unpack(&accounts.token_b_account.data).unwrap(); - assert_eq!(swap_token_b.amount, deposit_b + token_b_amount); - let token_a = spl_token::state::Account::unpack(&token_a_account.data).unwrap(); - assert_eq!(token_a.amount, 0); - let token_b = spl_token::state::Account::unpack(&token_b_account.data).unwrap(); - assert_eq!(token_b.amount, 0); - let pool_account = spl_token::state::Account::unpack(&pool_account.data).unwrap(); + StateWithExtensions::::unpack(&accounts.token_b_account.data).unwrap(); + assert_eq!(swap_token_b.base.amount, deposit_b + token_b_amount); + let token_a = StateWithExtensions::::unpack(&token_a_account.data).unwrap(); + assert_eq!(token_a.base.amount, 0); + let token_b = StateWithExtensions::::unpack(&token_b_account.data).unwrap(); + assert_eq!(token_b.base.amount, 0); + let pool_account = StateWithExtensions::::unpack(&pool_account.data).unwrap(); let swap_pool_account = - spl_token::state::Account::unpack(&accounts.pool_token_account.data).unwrap(); + StateWithExtensions::::unpack(&accounts.pool_token_account.data).unwrap(); let pool_mint = - spl_token::state::Mint::unpack(&accounts.pool_mint_account.data).unwrap(); + StateWithExtensions::::unpack(&accounts.pool_mint_account.data).unwrap(); assert_eq!( - pool_mint.supply, - pool_account.amount + swap_pool_account.amount + pool_mint.base.supply, + pool_account.base.amount + swap_pool_account.base.amount ); } } - #[test] - fn test_withdraw() { + #[test_case(spl_token::id(), spl_token::id(), spl_token::id(); "all-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token_2022::id(); "all-token-2022")] + #[test_case(spl_token::id(), spl_token_2022::id(), spl_token_2022::id(); "mixed-pool-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token::id(); "mixed-pool-token-2022")] + fn test_withdraw( + pool_token_program_id: Pubkey, + token_a_program_id: Pubkey, + token_b_program_id: Pubkey, + ) { let user_key = Pubkey::new_unique(); let trade_fee_numerator = 1; let trade_fee_denominator = 2; @@ -3487,8 +4044,17 @@ mod tests { let minimum_token_a_amount = initial_a / 40; let minimum_token_b_amount = initial_b / 40; - let mut accounts = - SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount); + let mut accounts = SwapAccountInfo::new( + &user_key, + fees, + SwapTransferFees::default(), + swap_curve, + token_a_amount, + token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, + ); // swap not initialized { @@ -3531,7 +4097,7 @@ mod tests { ) = accounts.setup_token_accounts(&user_key, &withdrawer_key, initial_a, initial_b, 0); let old_swap_account = accounts.swap_account; let mut wrong_swap_account = old_swap_account.clone(); - wrong_swap_account.owner = spl_token::id(); + wrong_swap_account.owner = pool_token_program_id; accounts.swap_account = wrong_swap_account; assert_eq!( Err(ProgramError::IncorrectProgramId), @@ -3564,7 +4130,7 @@ mod tests { let old_authority = accounts.authority_key; let (bad_authority_key, _bump_seed) = Pubkey::find_program_address( &[&accounts.swap_key.to_bytes()[..]], - &spl_token::id(), + &pool_token_program_id, ); accounts.authority_key = bad_authority_key; assert_eq!( @@ -3634,8 +4200,13 @@ mod tests { initial_b, withdraw_amount.try_into().unwrap(), ); + let expected_error: ProgramError = if token_a_account.owner == token_b_account.owner { + TokenError::MintMismatch.into() + } else { + ProgramError::InvalidAccountData + }; assert_eq!( - Err(TokenError::MintMismatch.into()), + Err(expected_error), accounts.withdraw_all_token_types( &withdrawer_key, &pool_key, @@ -3673,7 +4244,7 @@ mod tests { _token_b_key, _token_b_account, _pool_key, - _pool_account, + pool_account, ) = accounts.setup_token_accounts( &user_key, &withdrawer_key, @@ -3681,8 +4252,13 @@ mod tests { initial_b, withdraw_amount.try_into().unwrap(), ); + let expected_error: ProgramError = if token_a_account.owner == pool_account.owner { + TokenError::MintMismatch.into() + } else { + SwapError::IncorrectTokenProgramId.into() + }; assert_eq!( - Err(TokenError::MintMismatch.into()), + Err(expected_error), accounts.withdraw_all_token_types( &withdrawer_key, &wrong_token_a_key, @@ -3773,7 +4349,9 @@ mod tests { do_process_instruction( withdraw_all_token_types( &SWAP_PROGRAM_ID, - &spl_token::id(), + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, &accounts.swap_key, &accounts.authority_key, &user_transfer_authority_key, @@ -3784,6 +4362,8 @@ mod tests { &accounts.token_b_key, &token_a_key, &token_b_key, + &accounts.token_a_mint_key, + &accounts.token_b_mint_key, WithdrawAllTokenTypes { pool_token_amount: withdraw_amount.try_into().unwrap(), minimum_token_a_amount, @@ -3793,8 +4373,8 @@ mod tests { .unwrap(), vec![ &mut accounts.swap_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), &mut accounts.pool_mint_account, &mut pool_account, &mut accounts.token_a_account, @@ -3802,7 +4382,11 @@ mod tests { &mut token_a_account, &mut token_b_account, &mut accounts.pool_fee_account, - &mut Account::default(), + &mut accounts.token_a_mint_account, + &mut accounts.token_b_mint_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], ) ); @@ -3831,6 +4415,8 @@ mod tests { withdraw_all_token_types( &SWAP_PROGRAM_ID, &wrong_key, + &wrong_key, + &wrong_key, &accounts.swap_key, &accounts.authority_key, &accounts.authority_key, @@ -3841,6 +4427,8 @@ mod tests { &accounts.token_b_key, &token_a_key, &token_b_key, + &accounts.token_a_mint_key, + &accounts.token_b_mint_key, WithdrawAllTokenTypes { pool_token_amount: withdraw_amount.try_into().unwrap(), minimum_token_a_amount, @@ -3850,8 +4438,8 @@ mod tests { .unwrap(), vec![ &mut accounts.swap_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), &mut accounts.pool_mint_account, &mut pool_account, &mut accounts.token_a_account, @@ -3859,7 +4447,11 @@ mod tests { &mut token_a_account, &mut token_b_account, &mut accounts.pool_fee_account, - &mut Account::default(), + &mut accounts.token_a_mint_account, + &mut accounts.token_b_mint_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], ) ); @@ -3951,8 +4543,13 @@ mod tests { initial_b, initial_pool.try_into().unwrap(), ); - let (pool_mint_key, pool_mint_account) = - create_mint(&spl_token::id(), &accounts.authority_key, None); + let (pool_mint_key, pool_mint_account) = create_mint( + &pool_token_program_id, + &accounts.authority_key, + None, + None, + &TransferFee::default(), + ); let old_pool_key = accounts.pool_mint_key; let old_pool_account = accounts.pool_mint_account; accounts.pool_mint_key = pool_mint_key; @@ -4146,50 +4743,50 @@ mod tests { .unwrap(); let swap_token_a = - spl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap(); + StateWithExtensions::::unpack(&accounts.token_a_account.data).unwrap(); let swap_token_b = - spl_token::state::Account::unpack(&accounts.token_b_account.data).unwrap(); + StateWithExtensions::::unpack(&accounts.token_b_account.data).unwrap(); let pool_mint = - spl_token::state::Mint::unpack(&accounts.pool_mint_account.data).unwrap(); + StateWithExtensions::::unpack(&accounts.pool_mint_account.data).unwrap(); let withdraw_fee = accounts.fees.owner_withdraw_fee(withdraw_amount).unwrap(); let results = accounts .swap_curve .calculator .pool_tokens_to_trading_tokens( withdraw_amount - withdraw_fee, - pool_mint.supply.try_into().unwrap(), - swap_token_a.amount.try_into().unwrap(), - swap_token_b.amount.try_into().unwrap(), + pool_mint.base.supply.into(), + swap_token_a.base.amount.into(), + swap_token_b.base.amount.into(), RoundDirection::Floor, ) .unwrap(); assert_eq!( - swap_token_a.amount, + swap_token_a.base.amount, token_a_amount - to_u64(results.token_a_amount).unwrap() ); assert_eq!( - swap_token_b.amount, + swap_token_b.base.amount, token_b_amount - to_u64(results.token_b_amount).unwrap() ); - let token_a = spl_token::state::Account::unpack(&token_a_account.data).unwrap(); + let token_a = StateWithExtensions::::unpack(&token_a_account.data).unwrap(); assert_eq!( - token_a.amount, + token_a.base.amount, initial_a + to_u64(results.token_a_amount).unwrap() ); - let token_b = spl_token::state::Account::unpack(&token_b_account.data).unwrap(); + let token_b = StateWithExtensions::::unpack(&token_b_account.data).unwrap(); assert_eq!( - token_b.amount, + token_b.base.amount, initial_b + to_u64(results.token_b_amount).unwrap() ); - let pool_account = spl_token::state::Account::unpack(&pool_account.data).unwrap(); + let pool_account = StateWithExtensions::::unpack(&pool_account.data).unwrap(); assert_eq!( - pool_account.amount, + pool_account.base.amount, to_u64(initial_pool - withdraw_amount).unwrap() ); let fee_account = - spl_token::state::Account::unpack(&accounts.pool_fee_account.data).unwrap(); + StateWithExtensions::::unpack(&accounts.pool_fee_account.data).unwrap(); assert_eq!( - fee_account.amount, + fee_account.base.amount, TryInto::::try_into(withdraw_fee).unwrap() ); } @@ -4207,8 +4804,9 @@ mod tests { let pool_fee_key = accounts.pool_fee_key; let mut pool_fee_account = accounts.pool_fee_account.clone(); - let fee_account = spl_token::state::Account::unpack(&pool_fee_account.data).unwrap(); - let pool_fee_amount = fee_account.amount; + let fee_account = + StateWithExtensions::::unpack(&pool_fee_account.data).unwrap(); + let pool_fee_amount = fee_account.base.amount; accounts .withdraw_all_token_types( @@ -4226,37 +4824,44 @@ mod tests { .unwrap(); let swap_token_a = - spl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap(); + StateWithExtensions::::unpack(&accounts.token_a_account.data).unwrap(); let swap_token_b = - spl_token::state::Account::unpack(&accounts.token_b_account.data).unwrap(); + StateWithExtensions::::unpack(&accounts.token_b_account.data).unwrap(); let pool_mint = - spl_token::state::Mint::unpack(&accounts.pool_mint_account.data).unwrap(); + StateWithExtensions::::unpack(&accounts.pool_mint_account.data).unwrap(); let results = accounts .swap_curve .calculator .pool_tokens_to_trading_tokens( - pool_fee_amount.try_into().unwrap(), - pool_mint.supply.try_into().unwrap(), - swap_token_a.amount.try_into().unwrap(), - swap_token_b.amount.try_into().unwrap(), + pool_fee_amount.into(), + pool_mint.base.supply.into(), + swap_token_a.base.amount.into(), + swap_token_b.base.amount.into(), RoundDirection::Floor, ) .unwrap(); - let token_a = spl_token::state::Account::unpack(&token_a_account.data).unwrap(); + let token_a = StateWithExtensions::::unpack(&token_a_account.data).unwrap(); assert_eq!( - token_a.amount, + token_a.base.amount, TryInto::::try_into(results.token_a_amount).unwrap() ); - let token_b = spl_token::state::Account::unpack(&token_b_account.data).unwrap(); + let token_b = StateWithExtensions::::unpack(&token_b_account.data).unwrap(); assert_eq!( - token_b.amount, + token_b.base.amount, TryInto::::try_into(results.token_b_amount).unwrap() ); } } - #[test] - fn test_deposit_one_exact_in() { + #[test_case(spl_token::id(), spl_token::id(), spl_token::id(); "all-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token_2022::id(); "all-token-2022")] + #[test_case(spl_token::id(), spl_token_2022::id(), spl_token_2022::id(); "mixed-pool-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token::id(); "mixed-pool-token-2022")] + fn test_deposit_one_exact_in( + pool_token_program_id: Pubkey, + token_a_program_id: Pubkey, + token_b_program_id: Pubkey, + ) { let user_key = Pubkey::new_unique(); let depositor_key = Pubkey::new_unique(); let trade_fee_numerator = 1; @@ -4287,13 +4892,22 @@ mod tests { calculator: Arc::new(ConstantProductCurve {}), }; - let mut accounts = - SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount); - - let deposit_a = token_a_amount / 10; - let deposit_b = token_b_amount / 10; - let pool_amount = to_u64(INITIAL_SWAP_POOL_AMOUNT / 100).unwrap(); - + let mut accounts = SwapAccountInfo::new( + &user_key, + fees, + SwapTransferFees::default(), + swap_curve, + token_a_amount, + token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, + ); + + let deposit_a = token_a_amount / 10; + let deposit_b = token_b_amount / 10; + let pool_amount = to_u64(INITIAL_SWAP_POOL_AMOUNT / 100).unwrap(); + // swap not initialized { let ( @@ -4332,7 +4946,7 @@ mod tests { ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0); let old_swap_account = accounts.swap_account; let mut wrong_swap_account = old_swap_account.clone(); - wrong_swap_account.owner = spl_token::id(); + wrong_swap_account.owner = pool_token_program_id; accounts.swap_account = wrong_swap_account; assert_eq!( Err(ProgramError::IncorrectProgramId), @@ -4362,7 +4976,7 @@ mod tests { let old_authority = accounts.authority_key; let (bad_authority_key, _bump_seed) = Pubkey::find_program_address( &[&accounts.swap_key.to_bytes()[..]], - &spl_token::id(), + &pool_token_program_id, ); accounts.authority_key = bad_authority_key; assert_eq!( @@ -4430,10 +5044,15 @@ mod tests { token_b_key, mut token_b_account, _pool_key, - mut _pool_account, + pool_account, ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0); + let expected_error: ProgramError = if token_b_account.owner == pool_account.owner { + TokenError::MintMismatch.into() + } else { + SwapError::IncorrectTokenProgramId.into() + }; assert_eq!( - Err(TokenError::MintMismatch.into()), + Err(expected_error), accounts.deposit_single_token_type_exact_amount_in( &depositor_key, &token_a_key, @@ -4462,7 +5081,8 @@ mod tests { do_process_instruction( deposit_single_token_type_exact_amount_in( &SWAP_PROGRAM_ID, - &spl_token::id(), + &token_a_program_id, + &pool_token_program_id, &accounts.swap_key, &accounts.authority_key, &user_transfer_authority_key, @@ -4471,6 +5091,7 @@ mod tests { &accounts.token_b_key, &accounts.pool_mint_key, &pool_key, + &accounts.token_a_mint_key, DepositSingleTokenTypeExactAmountIn { source_token_amount: deposit_a, minimum_pool_token_amount: pool_amount, @@ -4479,14 +5100,16 @@ mod tests { .unwrap(), vec![ &mut accounts.swap_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), &mut token_a_account, &mut accounts.token_a_account, &mut accounts.token_b_account, &mut accounts.pool_mint_account, &mut pool_account, - &mut Account::default(), + &mut accounts.token_a_mint_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], ) ); @@ -4509,6 +5132,7 @@ mod tests { deposit_single_token_type_exact_amount_in( &SWAP_PROGRAM_ID, &wrong_key, + &wrong_key, &accounts.swap_key, &accounts.authority_key, &accounts.authority_key, @@ -4517,6 +5141,7 @@ mod tests { &accounts.token_b_key, &accounts.pool_mint_key, &pool_key, + &accounts.token_a_mint_key, DepositSingleTokenTypeExactAmountIn { source_token_amount: deposit_a, minimum_pool_token_amount: pool_amount, @@ -4525,14 +5150,16 @@ mod tests { .unwrap(), vec![ &mut accounts.swap_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), &mut token_a_account, &mut accounts.token_a_account, &mut accounts.token_b_account, &mut accounts.pool_mint_account, &mut pool_account, - &mut Account::default(), + &mut accounts.token_a_mint_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], ) ); @@ -4606,8 +5233,13 @@ mod tests { pool_key, mut pool_account, ) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0); - let (pool_mint_key, pool_mint_account) = - create_mint(&spl_token::id(), &accounts.authority_key, None); + let (pool_mint_key, pool_mint_account) = create_mint( + &pool_token_program_id, + &accounts.authority_key, + None, + None, + &TransferFee::default(), + ); let old_pool_key = accounts.pool_mint_key; let old_pool_account = accounts.pool_mint_account; accounts.pool_mint_key = pool_mint_key; @@ -4732,11 +5364,11 @@ mod tests { .unwrap(); let swap_token_a = - spl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap(); - assert_eq!(swap_token_a.amount, deposit_a + token_a_amount); + StateWithExtensions::::unpack(&accounts.token_a_account.data).unwrap(); + assert_eq!(swap_token_a.base.amount, deposit_a + token_a_amount); - let token_a = spl_token::state::Account::unpack(&token_a_account.data).unwrap(); - assert_eq!(token_a.amount, 0); + let token_a = StateWithExtensions::::unpack(&token_a_account.data).unwrap(); + assert_eq!(token_a.base.amount, 0); accounts .deposit_single_token_type_exact_amount_in( @@ -4750,26 +5382,33 @@ mod tests { ) .unwrap(); let swap_token_b = - spl_token::state::Account::unpack(&accounts.token_b_account.data).unwrap(); - assert_eq!(swap_token_b.amount, deposit_b + token_b_amount); + StateWithExtensions::::unpack(&accounts.token_b_account.data).unwrap(); + assert_eq!(swap_token_b.base.amount, deposit_b + token_b_amount); - let token_b = spl_token::state::Account::unpack(&token_b_account.data).unwrap(); - assert_eq!(token_b.amount, 0); + let token_b = StateWithExtensions::::unpack(&token_b_account.data).unwrap(); + assert_eq!(token_b.base.amount, 0); - let pool_account = spl_token::state::Account::unpack(&pool_account.data).unwrap(); + let pool_account = StateWithExtensions::::unpack(&pool_account.data).unwrap(); let swap_pool_account = - spl_token::state::Account::unpack(&accounts.pool_token_account.data).unwrap(); + StateWithExtensions::::unpack(&accounts.pool_token_account.data).unwrap(); let pool_mint = - spl_token::state::Mint::unpack(&accounts.pool_mint_account.data).unwrap(); + StateWithExtensions::::unpack(&accounts.pool_mint_account.data).unwrap(); assert_eq!( - pool_mint.supply, - pool_account.amount + swap_pool_account.amount + pool_mint.base.supply, + pool_account.base.amount + swap_pool_account.base.amount ); } } - #[test] - fn test_withdraw_one_exact_out() { + #[test_case(spl_token::id(), spl_token::id(), spl_token::id(); "all-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token_2022::id(); "all-token-2022")] + #[test_case(spl_token::id(), spl_token_2022::id(), spl_token_2022::id(); "mixed-pool-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token::id(); "mixed-pool-token-2022")] + fn test_withdraw_one_exact_out( + pool_token_program_id: Pubkey, + token_a_program_id: Pubkey, + token_b_program_id: Pubkey, + ) { let user_key = Pubkey::new_unique(); let trade_fee_numerator = 1; let trade_fee_denominator = 2; @@ -4807,8 +5446,17 @@ mod tests { let destination_a_amount = initial_a / 40; let destination_b_amount = initial_b / 40; - let mut accounts = - SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount); + let mut accounts = SwapAccountInfo::new( + &user_key, + fees, + SwapTransferFees::default(), + swap_curve, + token_a_amount, + token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, + ); // swap not initialized { @@ -4848,7 +5496,7 @@ mod tests { ) = accounts.setup_token_accounts(&user_key, &withdrawer_key, initial_a, initial_b, 0); let old_swap_account = accounts.swap_account; let mut wrong_swap_account = old_swap_account.clone(); - wrong_swap_account.owner = spl_token::id(); + wrong_swap_account.owner = pool_token_program_id; accounts.swap_account = wrong_swap_account; assert_eq!( Err(ProgramError::IncorrectProgramId), @@ -4878,7 +5526,7 @@ mod tests { let old_authority = accounts.authority_key; let (bad_authority_key, _bump_seed) = Pubkey::find_program_address( &[&accounts.swap_key.to_bytes()[..]], - &spl_token::id(), + &pool_token_program_id, ); accounts.authority_key = bad_authority_key; assert_eq!( @@ -4934,7 +5582,7 @@ mod tests { token_b_key, mut token_b_account, _pool_key, - _pool_account, + pool_account, ) = accounts.setup_token_accounts( &user_key, &withdrawer_key, @@ -4942,8 +5590,13 @@ mod tests { initial_b, maximum_pool_token_amount, ); + let expected_error: ProgramError = if token_a_account.owner == pool_account.owner { + TokenError::MintMismatch.into() + } else { + SwapError::IncorrectTokenProgramId.into() + }; assert_eq!( - Err(TokenError::MintMismatch.into()), + Err(expected_error), accounts.withdraw_single_token_type_exact_amount_out( &withdrawer_key, &token_a_key, @@ -5028,7 +5681,8 @@ mod tests { do_process_instruction( withdraw_single_token_type_exact_amount_out( &SWAP_PROGRAM_ID, - &spl_token::id(), + &pool_token_program_id, + &token_a_program_id, &accounts.swap_key, &accounts.authority_key, &user_transfer_authority_key, @@ -5038,6 +5692,7 @@ mod tests { &accounts.token_a_key, &accounts.token_b_key, &token_a_key, + &accounts.token_a_mint_key, WithdrawSingleTokenTypeExactAmountOut { destination_token_amount: destination_a_amount, maximum_pool_token_amount, @@ -5046,15 +5701,17 @@ mod tests { .unwrap(), vec![ &mut accounts.swap_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), &mut accounts.pool_mint_account, &mut pool_account, &mut accounts.token_a_account, &mut accounts.token_b_account, &mut token_a_account, &mut accounts.pool_fee_account, - &mut Account::default(), + &mut accounts.token_a_mint_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], ) ); @@ -5083,6 +5740,7 @@ mod tests { withdraw_single_token_type_exact_amount_out( &SWAP_PROGRAM_ID, &wrong_key, + &wrong_key, &accounts.swap_key, &accounts.authority_key, &accounts.authority_key, @@ -5092,6 +5750,7 @@ mod tests { &accounts.token_a_key, &accounts.token_b_key, &token_a_key, + &accounts.token_a_mint_key, WithdrawSingleTokenTypeExactAmountOut { destination_token_amount: destination_a_amount, maximum_pool_token_amount, @@ -5100,15 +5759,17 @@ mod tests { .unwrap(), vec![ &mut accounts.swap_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), &mut accounts.pool_mint_account, &mut pool_account, &mut accounts.token_a_account, &mut accounts.token_b_account, &mut token_a_account, &mut accounts.pool_fee_account, - &mut Account::default(), + &mut accounts.token_a_mint_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], ) ); @@ -5194,8 +5855,13 @@ mod tests { initial_b, initial_pool.try_into().unwrap(), ); - let (pool_mint_key, pool_mint_account) = - create_mint(&spl_token::id(), &accounts.authority_key, None); + let (pool_mint_key, pool_mint_account) = create_mint( + &pool_token_program_id, + &accounts.authority_key, + None, + None, + &TransferFee::default(), + ); let old_pool_key = accounts.pool_mint_key; let old_pool_account = accounts.pool_mint_account; accounts.pool_mint_key = pool_mint_key; @@ -5326,19 +5992,19 @@ mod tests { ); let swap_token_a = - spl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap(); + StateWithExtensions::::unpack(&accounts.token_a_account.data).unwrap(); let swap_token_b = - spl_token::state::Account::unpack(&accounts.token_b_account.data).unwrap(); + StateWithExtensions::::unpack(&accounts.token_b_account.data).unwrap(); let pool_mint = - spl_token::state::Mint::unpack(&accounts.pool_mint_account.data).unwrap(); + StateWithExtensions::::unpack(&accounts.pool_mint_account.data).unwrap(); let pool_token_amount = accounts .swap_curve .withdraw_single_token_type_exact_out( - destination_a_amount.try_into().unwrap(), - swap_token_a.amount.try_into().unwrap(), - swap_token_b.amount.try_into().unwrap(), - pool_mint.supply.try_into().unwrap(), + destination_a_amount.into(), + swap_token_a.base.amount.into(), + swap_token_b.base.amount.into(), + pool_mint.base.supply.into(), TradeDirection::AtoB, &accounts.fees, ) @@ -5358,20 +6024,23 @@ mod tests { .unwrap(); let swap_token_a = - spl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap(); + StateWithExtensions::::unpack(&accounts.token_a_account.data).unwrap(); - assert_eq!(swap_token_a.amount, token_a_amount - destination_a_amount); - let token_a = spl_token::state::Account::unpack(&token_a_account.data).unwrap(); - assert_eq!(token_a.amount, initial_a + destination_a_amount); + assert_eq!( + swap_token_a.base.amount, + token_a_amount - destination_a_amount + ); + let token_a = StateWithExtensions::::unpack(&token_a_account.data).unwrap(); + assert_eq!(token_a.base.amount, initial_a + destination_a_amount); - let pool_account = spl_token::state::Account::unpack(&pool_account.data).unwrap(); + let pool_account = StateWithExtensions::::unpack(&pool_account.data).unwrap(); assert_eq!( - pool_account.amount, + pool_account.base.amount, to_u64(initial_pool - pool_token_amount - withdraw_fee).unwrap() ); let fee_account = - spl_token::state::Account::unpack(&accounts.pool_fee_account.data).unwrap(); - assert_eq!(fee_account.amount, to_u64(withdraw_fee).unwrap()); + StateWithExtensions::::unpack(&accounts.pool_fee_account.data).unwrap(); + assert_eq!(fee_account.base.amount, to_u64(withdraw_fee).unwrap()); } // correct withdrawal from fee account @@ -5388,13 +6057,14 @@ mod tests { let fee_a_amount = 2; let pool_fee_key = accounts.pool_fee_key; let mut pool_fee_account = accounts.pool_fee_account.clone(); - let fee_account = spl_token::state::Account::unpack(&pool_fee_account.data).unwrap(); - let pool_fee_amount = fee_account.amount; + let fee_account = + StateWithExtensions::::unpack(&pool_fee_account.data).unwrap(); + let pool_fee_amount = fee_account.base.amount; let swap_token_a = - spl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap(); + StateWithExtensions::::unpack(&accounts.token_a_account.data).unwrap(); - let token_a_amount = swap_token_a.amount; + let token_a_amount = swap_token_a.base.amount; accounts .withdraw_single_token_type_exact_amount_out( &user_key, @@ -5408,20 +6078,25 @@ mod tests { .unwrap(); let swap_token_a = - spl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap(); + StateWithExtensions::::unpack(&accounts.token_a_account.data).unwrap(); - assert_eq!(swap_token_a.amount, token_a_amount - fee_a_amount); - let token_a = spl_token::state::Account::unpack(&token_a_account.data).unwrap(); - assert_eq!(token_a.amount, initial_a + fee_a_amount); + assert_eq!(swap_token_a.base.amount, token_a_amount - fee_a_amount); + let token_a = StateWithExtensions::::unpack(&token_a_account.data).unwrap(); + assert_eq!(token_a.base.amount, initial_a + fee_a_amount); } } + #[allow(clippy::too_many_arguments)] fn check_valid_swap_curve( fees: Fees, + transfer_fees: SwapTransferFees, curve_type: CurveType, calculator: Arc, token_a_amount: u64, token_b_amount: u64, + pool_token_program_id: &Pubkey, + token_a_program_id: &Pubkey, + token_b_program_id: &Pubkey, ) { let user_key = Pubkey::new_unique(); let swapper_key = Pubkey::new_unique(); @@ -5434,9 +6109,13 @@ mod tests { let mut accounts = SwapAccountInfo::new( &user_key, fees.clone(), + transfer_fees, swap_curve.clone(), token_a_amount, token_b_amount, + pool_token_program_id, + token_a_program_id, + token_b_program_id, ); let initial_a = token_a_amount / 5; let initial_b = token_b_amount / 5; @@ -5456,8 +6135,9 @@ mod tests { // swap one way let a_to_b_amount = initial_a / 10; let minimum_token_b_amount = 0; - let pool_mint = spl_token::state::Mint::unpack(&accounts.pool_mint_account.data).unwrap(); - let initial_supply = pool_mint.supply; + let pool_mint = + StateWithExtensions::::unpack(&accounts.pool_mint_account.data).unwrap(); + let initial_supply = pool_mint.base.supply; accounts .swap( &swapper_key, @@ -5472,61 +6152,74 @@ mod tests { ) .unwrap(); + // tweak values based on transfer fees assessed + let token_a_fee = accounts + .transfer_fees + .token_a + .calculate_fee(a_to_b_amount) + .unwrap(); + let actual_a_to_b_amount = a_to_b_amount - token_a_fee; let results = swap_curve .swap( - a_to_b_amount.try_into().unwrap(), - token_a_amount.try_into().unwrap(), - token_b_amount.try_into().unwrap(), + actual_a_to_b_amount.into(), + token_a_amount.into(), + token_b_amount.into(), TradeDirection::AtoB, &fees, ) .unwrap(); let swap_token_a = - spl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap(); - let token_a_amount = swap_token_a.amount; + StateWithExtensions::::unpack(&accounts.token_a_account.data).unwrap(); + let token_a_amount = swap_token_a.base.amount; assert_eq!( token_a_amount, TryInto::::try_into(results.new_swap_source_amount).unwrap() ); - let token_a = spl_token::state::Account::unpack(&token_a_account.data).unwrap(); - assert_eq!(token_a.amount, initial_a - a_to_b_amount); + let token_a = StateWithExtensions::::unpack(&token_a_account.data).unwrap(); + assert_eq!(token_a.base.amount, initial_a - a_to_b_amount); let swap_token_b = - spl_token::state::Account::unpack(&accounts.token_b_account.data).unwrap(); - let token_b_amount = swap_token_b.amount; + StateWithExtensions::::unpack(&accounts.token_b_account.data).unwrap(); + let token_b_amount = swap_token_b.base.amount; assert_eq!( token_b_amount, TryInto::::try_into(results.new_swap_destination_amount).unwrap() ); - let token_b = spl_token::state::Account::unpack(&token_b_account.data).unwrap(); + let token_b = StateWithExtensions::::unpack(&token_b_account.data).unwrap(); assert_eq!( - token_b.amount, + token_b.base.amount, initial_b + to_u64(results.destination_amount_swapped).unwrap() ); - let first_fee = swap_curve - .withdraw_single_token_type_exact_out( - results.owner_fee, - token_a_amount.try_into().unwrap(), - token_b_amount.try_into().unwrap(), - initial_supply.try_into().unwrap(), - TradeDirection::AtoB, - &fees, - ) - .unwrap(); + let first_fee = if results.owner_fee > 0 { + swap_curve + .calculator + .withdraw_single_token_type_exact_out( + results.owner_fee, + token_a_amount.into(), + token_b_amount.into(), + initial_supply.into(), + TradeDirection::AtoB, + RoundDirection::Floor, + ) + .unwrap() + } else { + 0 + }; let fee_account = - spl_token::state::Account::unpack(&accounts.pool_fee_account.data).unwrap(); + StateWithExtensions::::unpack(&accounts.pool_fee_account.data).unwrap(); assert_eq!( - fee_account.amount, + fee_account.base.amount, TryInto::::try_into(first_fee).unwrap() ); let first_swap_amount = results.destination_amount_swapped; // swap the other way - let pool_mint = spl_token::state::Mint::unpack(&accounts.pool_mint_account.data).unwrap(); - let initial_supply = pool_mint.supply; + let pool_mint = + StateWithExtensions::::unpack(&accounts.pool_mint_account.data).unwrap(); + let initial_supply = pool_mint.base.supply; let b_to_a_amount = initial_b / 10; let minimum_a_amount = 0; @@ -5544,60 +6237,82 @@ mod tests { ) .unwrap(); - let results = swap_curve + let mut results = swap_curve .swap( - b_to_a_amount.try_into().unwrap(), - token_b_amount.try_into().unwrap(), - token_a_amount.try_into().unwrap(), + b_to_a_amount.into(), + token_b_amount.into(), + token_a_amount.into(), TradeDirection::BtoA, &fees, ) .unwrap(); + // tweak values based on transfer fees assessed + let token_a_fee = accounts + .transfer_fees + .token_a + .calculate_fee(results.destination_amount_swapped.try_into().unwrap()) + .unwrap(); + results.destination_amount_swapped -= token_a_fee as u128; let swap_token_a = - spl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap(); - let token_a_amount = swap_token_a.amount; + StateWithExtensions::::unpack(&accounts.token_a_account.data).unwrap(); + let token_a_amount = swap_token_a.base.amount; assert_eq!( token_a_amount, TryInto::::try_into(results.new_swap_destination_amount).unwrap() ); - let token_a = spl_token::state::Account::unpack(&token_a_account.data).unwrap(); + let token_a = StateWithExtensions::::unpack(&token_a_account.data).unwrap(); assert_eq!( - token_a.amount, + token_a.base.amount, initial_a - a_to_b_amount + to_u64(results.destination_amount_swapped).unwrap() ); let swap_token_b = - spl_token::state::Account::unpack(&accounts.token_b_account.data).unwrap(); - let token_b_amount = swap_token_b.amount; + StateWithExtensions::::unpack(&accounts.token_b_account.data).unwrap(); + let token_b_amount = swap_token_b.base.amount; assert_eq!( token_b_amount, TryInto::::try_into(results.new_swap_source_amount).unwrap() ); - let token_b = spl_token::state::Account::unpack(&token_b_account.data).unwrap(); + let token_b = StateWithExtensions::::unpack(&token_b_account.data).unwrap(); assert_eq!( - token_b.amount, + token_b.base.amount, initial_b + to_u64(first_swap_amount).unwrap() - to_u64(results.source_amount_swapped).unwrap() ); - let second_fee = swap_curve - .withdraw_single_token_type_exact_out( - results.owner_fee, - token_a_amount.try_into().unwrap(), - token_b_amount.try_into().unwrap(), - initial_supply.try_into().unwrap(), - TradeDirection::BtoA, - &fees, - ) - .unwrap(); + let second_fee = if results.owner_fee > 0 { + swap_curve + .calculator + .withdraw_single_token_type_exact_out( + results.owner_fee, + token_a_amount.into(), + token_b_amount.into(), + initial_supply.into(), + TradeDirection::BtoA, + RoundDirection::Floor, + ) + .unwrap() + } else { + 0 + }; let fee_account = - spl_token::state::Account::unpack(&accounts.pool_fee_account.data).unwrap(); - assert_eq!(fee_account.amount, to_u64(first_fee + second_fee).unwrap()); + StateWithExtensions::::unpack(&accounts.pool_fee_account.data).unwrap(); + assert_eq!( + fee_account.base.amount, + to_u64(first_fee + second_fee).unwrap() + ); } - #[test] - fn test_valid_swap_curves_all_fees() { + #[test_case(spl_token::id(), spl_token::id(), spl_token::id(); "all-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token_2022::id(); "all-token-2022")] + #[test_case(spl_token::id(), spl_token_2022::id(), spl_token_2022::id(); "mixed-pool-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token::id(); "mixed-pool-token-2022")] + fn test_valid_swap_curve_all_fees( + pool_token_program_id: Pubkey, + token_a_program_id: Pubkey, + token_b_program_id: Pubkey, + ) { // All fees let trade_fee_numerator = 1; let trade_fee_denominator = 10; @@ -5623,31 +6338,50 @@ mod tests { check_valid_swap_curve( fees.clone(), + SwapTransferFees::default(), CurveType::ConstantProduct, Arc::new(ConstantProductCurve {}), token_a_amount, token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, ); let token_b_price = 1; check_valid_swap_curve( fees.clone(), + SwapTransferFees::default(), CurveType::ConstantPrice, Arc::new(ConstantPriceCurve { token_b_price }), token_a_amount, token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, ); let token_b_offset = 10_000_000_000; check_valid_swap_curve( fees, + SwapTransferFees::default(), CurveType::Offset, Arc::new(OffsetCurve { token_b_offset }), token_a_amount, token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, ); } - #[test] - fn test_valid_swap_curves_trade_fee_only() { + #[test_case(spl_token::id(), spl_token::id(), spl_token::id(); "all-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token_2022::id(); "all-token-2022")] + #[test_case(spl_token::id(), spl_token_2022::id(), spl_token_2022::id(); "mixed-pool-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token::id(); "mixed-pool-token-2022")] + fn test_valid_swap_curve_trade_fee_only( + pool_token_program_id: Pubkey, + token_a_program_id: Pubkey, + token_b_program_id: Pubkey, + ) { let trade_fee_numerator = 1; let trade_fee_denominator = 10; let owner_trade_fee_numerator = 0; @@ -5672,31 +6406,50 @@ mod tests { check_valid_swap_curve( fees.clone(), + SwapTransferFees::default(), CurveType::ConstantProduct, Arc::new(ConstantProductCurve {}), token_a_amount, token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, ); let token_b_price = 10_000; check_valid_swap_curve( fees.clone(), + SwapTransferFees::default(), CurveType::ConstantPrice, Arc::new(ConstantPriceCurve { token_b_price }), token_a_amount, token_b_amount / token_b_price, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, ); let token_b_offset = 1; check_valid_swap_curve( fees, + SwapTransferFees::default(), CurveType::Offset, Arc::new(OffsetCurve { token_b_offset }), token_a_amount, token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, ); } - #[test] - fn test_valid_swap_with_fee_constraints() { + #[test_case(spl_token::id(), spl_token::id(), spl_token::id(); "all-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token_2022::id(); "all-token-2022")] + #[test_case(spl_token::id(), spl_token_2022::id(), spl_token_2022::id(); "mixed-pool-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token::id(); "mixed-pool-token-2022")] + fn test_valid_swap_with_fee_constraints( + pool_token_program_id: Pubkey, + token_a_program_id: Pubkey, + token_b_program_id: Pubkey, + ) { let owner_key = Pubkey::new_unique(); let trade_fee_numerator = 1; @@ -5728,26 +6481,30 @@ mod tests { calculator: Arc::new(curve), }; - let owner_key_str = &owner_key.to_string(); + let owner_key_str = owner_key.to_string(); let valid_curve_types = &[CurveType::ConstantProduct]; let constraints = Some(SwapConstraints { - owner_key: owner_key_str, + owner_key: Some(owner_key_str.as_ref()), valid_curve_types, fees: &fees, }); let mut accounts = SwapAccountInfo::new( &owner_key, fees.clone(), + SwapTransferFees::default(), swap_curve, token_a_amount, token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, ); // initialize swap do_process_instruction_with_fee_constraints( initialize( &SWAP_PROGRAM_ID, - &spl_token::id(), + &pool_token_program_id, &accounts.swap_key, &accounts.authority_key, &accounts.token_a_key, @@ -5761,13 +6518,13 @@ mod tests { .unwrap(), vec![ &mut accounts.swap_account, - &mut Account::default(), + &mut SolanaAccount::default(), &mut accounts.token_a_account, &mut accounts.token_b_account, &mut accounts.pool_mint_account, &mut accounts.pool_fee_account, &mut accounts.pool_token_account, - &mut Account::default(), + &mut SolanaAccount::default(), ], &constraints, ) @@ -5797,7 +6554,9 @@ mod tests { do_process_instruction_with_fee_constraints( swap( &SWAP_PROGRAM_ID, - &spl_token::id(), + &token_a_program_id, + &token_b_program_id, + &pool_token_program_id, &accounts.swap_key, &accounts.authority_key, &accounts.authority_key, @@ -5807,6 +6566,8 @@ mod tests { &token_b_key, &accounts.pool_mint_key, &accounts.pool_fee_key, + &accounts.token_a_mint_key, + &accounts.token_b_mint_key, Some(&pool_key), Swap { amount_in, @@ -5816,15 +6577,19 @@ mod tests { .unwrap(), vec![ &mut accounts.swap_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), &mut token_a_account, &mut accounts.token_a_account, &mut accounts.token_b_account, &mut token_b_account, &mut accounts.pool_mint_account, &mut accounts.pool_fee_account, - &mut Account::default(), + &mut accounts.token_a_mint_account, + &mut accounts.token_b_mint_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), &mut pool_account, ], &constraints, @@ -5832,19 +6597,26 @@ mod tests { .unwrap(); // check that fees were taken in the host fee account - let host_fee_account = spl_token::state::Account::unpack(&pool_account.data).unwrap(); + let host_fee_account = StateWithExtensions::::unpack(&pool_account.data).unwrap(); let owner_fee_account = - spl_token::state::Account::unpack(&accounts.pool_fee_account.data).unwrap(); - let total_fee = owner_fee_account.amount * host_fee_denominator + StateWithExtensions::::unpack(&accounts.pool_fee_account.data).unwrap(); + let total_fee = owner_fee_account.base.amount * host_fee_denominator / (host_fee_denominator - host_fee_numerator); assert_eq!( total_fee, - host_fee_account.amount + owner_fee_account.amount + host_fee_account.base.amount + owner_fee_account.base.amount ); } - #[test] - fn test_invalid_swap() { + #[test_case(spl_token::id(), spl_token::id(), spl_token::id(); "all-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token_2022::id(); "all-token-2022")] + #[test_case(spl_token::id(), spl_token_2022::id(), spl_token_2022::id(); "mixed-pool-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token::id(); "mixed-pool-token-2022")] + fn test_invalid_swap( + pool_token_program_id: Pubkey, + token_a_program_id: Pubkey, + token_b_program_id: Pubkey, + ) { let user_key = Pubkey::new_unique(); let swapper_key = Pubkey::new_unique(); let trade_fee_numerator = 1; @@ -5873,8 +6645,17 @@ mod tests { curve_type, calculator: Arc::new(ConstantProductCurve {}), }; - let mut accounts = - SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount); + let mut accounts = SwapAccountInfo::new( + &user_key, + fees, + SwapTransferFees::default(), + swap_curve, + token_a_amount, + token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, + ); let initial_a = token_a_amount / 5; let initial_b = token_b_amount / 5; @@ -5923,7 +6704,7 @@ mod tests { ) = accounts.setup_token_accounts(&user_key, &swapper_key, initial_a, initial_b, 0); let old_swap_account = accounts.swap_account; let mut wrong_swap_account = old_swap_account.clone(); - wrong_swap_account.owner = spl_token::id(); + wrong_swap_account.owner = pool_token_program_id; accounts.swap_account = wrong_swap_account; assert_eq!( Err(ProgramError::IncorrectProgramId), @@ -5955,7 +6736,7 @@ mod tests { let old_authority = accounts.authority_key; let (bad_authority_key, _bump_seed) = Pubkey::find_program_address( &[&accounts.swap_key.to_bytes()[..]], - &spl_token::id(), + &pool_token_program_id, ); accounts.authority_key = bad_authority_key; assert_eq!( @@ -5992,6 +6773,8 @@ mod tests { swap( &SWAP_PROGRAM_ID, &wrong_program_id, + &wrong_program_id, + &wrong_program_id, &accounts.swap_key, &accounts.authority_key, &accounts.authority_key, @@ -6001,6 +6784,8 @@ mod tests { &token_b_key, &accounts.pool_mint_key, &accounts.pool_fee_key, + &accounts.token_a_mint_key, + &accounts.token_b_mint_key, None, Swap { amount_in: initial_a, @@ -6010,15 +6795,19 @@ mod tests { .unwrap(), vec![ &mut accounts.swap_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), &mut token_a_account, &mut accounts.token_a_account, &mut accounts.token_b_account, &mut token_b_account, &mut accounts.pool_mint_account, &mut accounts.pool_fee_account, - &mut Account::default(), + &mut accounts.token_a_mint_account, + &mut accounts.token_b_mint_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], ), ); @@ -6066,7 +6855,9 @@ mod tests { do_process_instruction( swap( &SWAP_PROGRAM_ID, - &spl_token::id(), + &token_a_program_id, + &token_b_program_id, + &pool_token_program_id, &accounts.swap_key, &accounts.authority_key, &user_transfer_key, @@ -6076,6 +6867,8 @@ mod tests { &token_b_key, &accounts.pool_mint_key, &accounts.pool_fee_key, + &accounts.token_a_mint_key, + &accounts.token_b_mint_key, None, Swap { amount_in: initial_a, @@ -6085,15 +6878,19 @@ mod tests { .unwrap(), vec![ &mut accounts.swap_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), &mut token_a_account.clone(), &mut token_a_account, &mut token_b_account.clone(), &mut token_b_account, &mut accounts.pool_mint_account, &mut accounts.pool_fee_account, - &mut Account::default(), + &mut accounts.token_a_mint_account, + &mut accounts.token_b_mint_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], ), ); @@ -6161,8 +6958,13 @@ mod tests { _pool_key, _pool_account, ) = accounts.setup_token_accounts(&user_key, &swapper_key, initial_a, initial_b, 0); - let (pool_mint_key, pool_mint_account) = - create_mint(&spl_token::id(), &accounts.authority_key, None); + let (pool_mint_key, pool_mint_account) = create_mint( + &pool_token_program_id, + &accounts.authority_key, + None, + None, + &TransferFee::default(), + ); let old_pool_key = accounts.pool_mint_key; let old_pool_account = accounts.pool_mint_account; accounts.pool_mint_key = pool_mint_key; @@ -6235,7 +7037,9 @@ mod tests { do_process_instruction( swap( &SWAP_PROGRAM_ID, - &spl_token::id(), + &token_a_program_id, + &token_b_program_id, + &pool_token_program_id, &accounts.swap_key, &accounts.authority_key, &user_transfer_key, @@ -6245,6 +7049,8 @@ mod tests { &token_b_key, &accounts.pool_mint_key, &accounts.pool_fee_key, + &accounts.token_a_mint_key, + &accounts.token_b_mint_key, None, Swap { amount_in: initial_a, @@ -6254,15 +7060,19 @@ mod tests { .unwrap(), vec![ &mut accounts.swap_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), &mut token_a_account, &mut accounts.token_a_account, &mut accounts.token_b_account, &mut token_b_account, &mut accounts.pool_mint_account, &mut accounts.pool_fee_account, - &mut Account::default(), + &mut accounts.token_a_mint_account, + &mut accounts.token_b_mint_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], ), ); @@ -6374,7 +7184,7 @@ mod tests { _pool_key, _pool_account, ) = accounts.setup_token_accounts(&user_key, &authority_key, initial_a, initial_b, 0); - let owner_key = &swapper_key.to_string(); + let owner_key = swapper_key.to_string(); let fees = Fees { trade_fee_numerator, trade_fee_denominator, @@ -6386,14 +7196,16 @@ mod tests { host_fee_denominator, }; let constraints = Some(SwapConstraints { - owner_key, + owner_key: Some(owner_key.as_ref()), valid_curve_types: &[], fees: &fees, }); do_process_instruction_with_fee_constraints( swap( &SWAP_PROGRAM_ID, - &spl_token::id(), + &token_a_program_id, + &token_b_program_id, + &pool_token_program_id, &accounts.swap_key, &accounts.authority_key, &accounts.authority_key, @@ -6403,6 +7215,8 @@ mod tests { &token_b_key, &accounts.pool_mint_key, &accounts.pool_fee_key, + &accounts.token_a_mint_key, + &accounts.token_b_mint_key, None, Swap { amount_in: initial_a, @@ -6412,15 +7226,19 @@ mod tests { .unwrap(), vec![ &mut accounts.swap_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), &mut token_a_account, &mut accounts.token_a_account, &mut accounts.token_b_account, &mut token_b_account, &mut accounts.pool_mint_account, &mut accounts.pool_fee_account, - &mut Account::default(), + &mut accounts.token_a_mint_account, + &mut accounts.token_b_mint_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), ], &constraints, ) @@ -6446,7 +7264,7 @@ mod tests { _pool_key, _pool_account, ) = accounts.setup_token_accounts(&user_key, &authority_key, initial_a, initial_b, 0); - let owner_key = &swapper_key.to_string(); + let owner_key = swapper_key.to_string(); let fees = Fees { trade_fee_numerator, trade_fee_denominator, @@ -6458,7 +7276,7 @@ mod tests { host_fee_denominator, }; let constraints = Some(SwapConstraints { - owner_key, + owner_key: Some(owner_key.as_ref()), valid_curve_types: &[], fees: &fees, }); @@ -6467,7 +7285,9 @@ mod tests { do_process_instruction_with_fee_constraints( swap( &SWAP_PROGRAM_ID, - &spl_token::id(), + &token_a_program_id, + &token_b_program_id, + &pool_token_program_id, &accounts.swap_key, &accounts.authority_key, &accounts.authority_key, @@ -6477,6 +7297,8 @@ mod tests { &token_b_key, &accounts.pool_mint_key, &accounts.pool_fee_key, + &accounts.token_a_mint_key, + &accounts.token_b_mint_key, Some(&bad_token_a_key), Swap { amount_in: initial_a, @@ -6486,15 +7308,19 @@ mod tests { .unwrap(), vec![ &mut accounts.swap_account, - &mut Account::default(), - &mut Account::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), &mut token_a_account, &mut accounts.token_a_account, &mut accounts.token_b_account, &mut token_b_account, &mut accounts.pool_mint_account, &mut accounts.pool_fee_account, - &mut Account::default(), + &mut accounts.token_a_mint_account, + &mut accounts.token_b_mint_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), &mut bad_token_a_account, ], &constraints, @@ -6503,8 +7329,15 @@ mod tests { } } - #[test] - fn test_overdraw_offset_curve() { + #[test_case(spl_token::id(), spl_token::id(), spl_token::id(); "all-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token_2022::id(); "all-token-2022")] + #[test_case(spl_token::id(), spl_token_2022::id(), spl_token_2022::id(); "mixed-pool-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token::id(); "mixed-pool-token-2022")] + fn test_overdraw_offset_curve( + pool_token_program_id: Pubkey, + token_a_program_id: Pubkey, + token_b_program_id: Pubkey, + ) { let trade_fee_numerator = 1; let trade_fee_denominator = 10; let owner_trade_fee_numerator = 1; @@ -6535,8 +7368,17 @@ mod tests { let user_key = Pubkey::new_unique(); let swapper_key = Pubkey::new_unique(); - let mut accounts = - SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount); + let mut accounts = SwapAccountInfo::new( + &user_key, + fees, + SwapTransferFees::default(), + swap_curve, + token_a_amount, + token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, + ); accounts.initialize_swap().unwrap(); @@ -6653,8 +7495,15 @@ mod tests { } } - #[test] - fn test_withdraw_all_offset_curve() { + #[test_case(spl_token::id(), spl_token::id(), spl_token::id(); "all-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token_2022::id(); "all-token-2022")] + #[test_case(spl_token::id(), spl_token_2022::id(), spl_token_2022::id(); "mixed-pool-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token::id(); "mixed-pool-token-2022")] + fn test_withdraw_all_offset_curve( + pool_token_program_id: Pubkey, + token_a_program_id: Pubkey, + token_b_program_id: Pubkey, + ) { let trade_fee_numerator = 1; let trade_fee_denominator = 10; let owner_trade_fee_numerator = 1; @@ -6686,8 +7535,17 @@ mod tests { let user_key = Pubkey::new_unique(); let withdrawer_key = Pubkey::new_unique(); - let mut accounts = - SwapAccountInfo::new(&user_key, fees, swap_curve, token_a_amount, token_b_amount); + let mut accounts = SwapAccountInfo::new( + &user_key, + fees, + SwapTransferFees::default(), + swap_curve, + token_a_amount, + token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, + ); accounts.initialize_swap().unwrap(); @@ -6722,20 +7580,27 @@ mod tests { ) .unwrap(); - let token_a = spl_token::state::Account::unpack(&token_a_account.data).unwrap(); - assert_eq!(token_a.amount, token_a_amount); - let token_b = spl_token::state::Account::unpack(&token_b_account.data).unwrap(); - assert_eq!(token_b.amount, token_b_amount); + let token_a = StateWithExtensions::::unpack(&token_a_account.data).unwrap(); + assert_eq!(token_a.base.amount, token_a_amount); + let token_b = StateWithExtensions::::unpack(&token_b_account.data).unwrap(); + assert_eq!(token_b.base.amount, token_b_amount); let swap_token_a = - spl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap(); - assert_eq!(swap_token_a.amount, 0); + StateWithExtensions::::unpack(&accounts.token_a_account.data).unwrap(); + assert_eq!(swap_token_a.base.amount, 0); let swap_token_b = - spl_token::state::Account::unpack(&accounts.token_b_account.data).unwrap(); - assert_eq!(swap_token_b.amount, 0); + StateWithExtensions::::unpack(&accounts.token_b_account.data).unwrap(); + assert_eq!(swap_token_b.base.amount, 0); } - #[test] - fn test_withdraw_all_constant_price_curve() { + #[test_case(spl_token::id(), spl_token::id(), spl_token::id(); "all-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token_2022::id(); "all-token-2022")] + #[test_case(spl_token::id(), spl_token_2022::id(), spl_token_2022::id(); "mixed-pool-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token::id(); "mixed-pool-token-2022")] + fn test_withdraw_all_constant_price_curve( + pool_token_program_id: Pubkey, + token_a_program_id: Pubkey, + token_b_program_id: Pubkey, + ) { let trade_fee_numerator = 1; let trade_fee_denominator = 10; let owner_trade_fee_numerator = 1; @@ -6773,9 +7638,13 @@ mod tests { let mut accounts = SwapAccountInfo::new( &user_key, fees, + SwapTransferFees::default(), swap_curve, swap_token_a_amount, swap_token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, ); accounts.initialize_swap().unwrap(); @@ -6827,16 +7696,16 @@ mod tests { ) .unwrap(); - let token_a = spl_token::state::Account::unpack(&token_a_account.data).unwrap(); - assert_eq!(token_a.amount, swap_token_a_amount); - let token_b = spl_token::state::Account::unpack(&token_b_account.data).unwrap(); - assert_eq!(token_b.amount, 750); + let token_a = StateWithExtensions::::unpack(&token_a_account.data).unwrap(); + assert_eq!(token_a.base.amount, swap_token_a_amount); + let token_b = StateWithExtensions::::unpack(&token_b_account.data).unwrap(); + assert_eq!(token_b.base.amount, 750); let swap_token_a = - spl_token::state::Account::unpack(&accounts.token_a_account.data).unwrap(); - assert_eq!(swap_token_a.amount, 0); + StateWithExtensions::::unpack(&accounts.token_a_account.data).unwrap(); + assert_eq!(swap_token_a.base.amount, 0); let swap_token_b = - spl_token::state::Account::unpack(&accounts.token_b_account.data).unwrap(); - assert_eq!(swap_token_b.amount, 250); + StateWithExtensions::::unpack(&accounts.token_b_account.data).unwrap(); + assert_eq!(swap_token_b.base.amount, 250); // deposit now, not enough to cover the tokens already in there let token_b_amount = 10; @@ -6906,8 +7775,15 @@ mod tests { .unwrap(); } - #[test] - fn test_deposits_allowed_single_token() { + #[test_case(spl_token::id(), spl_token::id(), spl_token::id(); "all-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token_2022::id(); "all-token-2022")] + #[test_case(spl_token::id(), spl_token_2022::id(), spl_token_2022::id(); "mixed-pool-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token::id(); "mixed-pool-token-2022")] + fn test_deposits_allowed_single_token( + pool_token_program_id: Pubkey, + token_a_program_id: Pubkey, + token_b_program_id: Pubkey, + ) { let trade_fee_numerator = 1; let trade_fee_denominator = 10; let owner_trade_fee_numerator = 1; @@ -6941,9 +7817,13 @@ mod tests { let mut accounts = SwapAccountInfo::new( &creator_key, fees, + SwapTransferFees::default(), swap_curve, token_a_amount, token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, ); accounts.initialize_swap().unwrap(); @@ -6972,4 +7852,525 @@ mod tests { ) ); } + + #[test_case(spl_token::id(), spl_token::id(), spl_token::id(); "all-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token_2022::id(); "all-token-2022")] + #[test_case(spl_token::id(), spl_token_2022::id(), spl_token_2022::id(); "mixed-pool-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token::id(); "mixed-pool-token-2022")] + fn test_withdraw_with_invalid_fee_account( + pool_token_program_id: Pubkey, + token_a_program_id: Pubkey, + token_b_program_id: Pubkey, + ) { + let user_key = Pubkey::new_unique(); + + let fees = Fees { + trade_fee_numerator: 1, + trade_fee_denominator: 2, + owner_trade_fee_numerator: 1, + owner_trade_fee_denominator: 10, + owner_withdraw_fee_numerator: 1, + owner_withdraw_fee_denominator: 5, + host_fee_numerator: 7, + host_fee_denominator: 100, + }; + + let token_a_amount = 1000; + let token_b_amount = 2000; + let swap_curve = SwapCurve { + curve_type: CurveType::ConstantProduct, + calculator: Arc::new(ConstantProductCurve {}), + }; + + let withdrawer_key = Pubkey::new_unique(); + let initial_a = token_a_amount / 10; + let initial_b = token_b_amount / 10; + let initial_pool = swap_curve.calculator.new_pool_supply() / 10; + let withdraw_amount = initial_pool / 4; + let minimum_token_a_amount = initial_a / 40; + let minimum_token_b_amount = initial_b / 40; + + let mut accounts = SwapAccountInfo::new( + &user_key, + fees, + SwapTransferFees::default(), + swap_curve, + token_a_amount, + token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, + ); + + accounts.initialize_swap().unwrap(); + + let ( + token_a_key, + mut token_a_account, + token_b_key, + mut token_b_account, + pool_key, + mut pool_account, + ) = accounts.setup_token_accounts( + &user_key, + &withdrawer_key, + initial_a, + initial_b, + initial_pool.try_into().unwrap(), + ); + + let destination_key = Pubkey::new_unique(); + let mut destination = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &withdrawer_key, + ); + + do_process_instruction( + close_account( + &pool_token_program_id, + &accounts.pool_fee_key, + &destination_key, + &user_key, + &[], + ) + .unwrap(), + vec![ + &mut accounts.pool_fee_account, + &mut destination, + &mut SolanaAccount::default(), + ], + ) + .unwrap(); + + let user_transfer_authority_key = Pubkey::new_unique(); + let pool_token_amount = withdraw_amount.try_into().unwrap(); + + do_process_instruction( + approve( + &pool_token_program_id, + &pool_key, + &user_transfer_authority_key, + &withdrawer_key, + &[], + pool_token_amount, + ) + .unwrap(), + vec![ + &mut pool_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), + ], + ) + .unwrap(); + + do_process_instruction( + withdraw_all_token_types( + &SWAP_PROGRAM_ID, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, + &accounts.swap_key, + &accounts.authority_key, + &user_transfer_authority_key, + &accounts.pool_mint_key, + &accounts.pool_fee_key, + &pool_key, + &accounts.token_a_key, + &accounts.token_b_key, + &token_a_key, + &token_b_key, + &accounts.token_a_mint_key, + &accounts.token_b_mint_key, + WithdrawAllTokenTypes { + pool_token_amount, + minimum_token_a_amount, + minimum_token_b_amount, + }, + ) + .unwrap(), + vec![ + &mut accounts.swap_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), + &mut accounts.pool_mint_account, + &mut pool_account, + &mut accounts.token_a_account, + &mut accounts.token_b_account, + &mut token_a_account, + &mut token_b_account, + &mut accounts.pool_fee_account, + &mut accounts.token_a_mint_account, + &mut accounts.token_b_mint_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), + ], + ) + .unwrap(); + } + + #[test_case(spl_token::id(), spl_token::id(), spl_token::id(); "all-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token_2022::id(); "all-token-2022")] + #[test_case(spl_token::id(), spl_token_2022::id(), spl_token_2022::id(); "mixed-pool-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token::id(); "mixed-pool-token-2022")] + fn test_withdraw_one_exact_out_with_invalid_fee_account( + pool_token_program_id: Pubkey, + token_a_program_id: Pubkey, + token_b_program_id: Pubkey, + ) { + let user_key = Pubkey::new_unique(); + + let fees = Fees { + trade_fee_numerator: 1, + trade_fee_denominator: 2, + owner_trade_fee_numerator: 1, + owner_trade_fee_denominator: 10, + owner_withdraw_fee_numerator: 1, + owner_withdraw_fee_denominator: 5, + host_fee_numerator: 7, + host_fee_denominator: 100, + }; + + let token_a_amount = 1000; + let token_b_amount = 2000; + let swap_curve = SwapCurve { + curve_type: CurveType::ConstantProduct, + calculator: Arc::new(ConstantProductCurve {}), + }; + + let withdrawer_key = Pubkey::new_unique(); + let initial_a = token_a_amount / 10; + let initial_b = token_b_amount / 10; + let initial_pool = swap_curve.calculator.new_pool_supply() / 10; + let maximum_pool_token_amount = to_u64(initial_pool / 4).unwrap(); + let destination_a_amount = initial_a / 40; + + let mut accounts = SwapAccountInfo::new( + &user_key, + fees, + SwapTransferFees::default(), + swap_curve, + token_a_amount, + token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, + ); + + accounts.initialize_swap().unwrap(); + + let ( + token_a_key, + mut token_a_account, + _token_b_key, + _token_b_account, + pool_key, + mut pool_account, + ) = accounts.setup_token_accounts( + &user_key, + &withdrawer_key, + initial_a, + initial_b, + initial_pool.try_into().unwrap(), + ); + + let destination_key = Pubkey::new_unique(); + let mut destination = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &withdrawer_key, + ); + + do_process_instruction( + close_account( + &pool_token_program_id, + &accounts.pool_fee_key, + &destination_key, + &user_key, + &[], + ) + .unwrap(), + vec![ + &mut accounts.pool_fee_account, + &mut destination, + &mut SolanaAccount::default(), + ], + ) + .unwrap(); + + let user_transfer_authority_key = Pubkey::new_unique(); + + do_process_instruction( + approve( + &pool_token_program_id, + &pool_key, + &user_transfer_authority_key, + &withdrawer_key, + &[], + maximum_pool_token_amount, + ) + .unwrap(), + vec![ + &mut pool_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), + ], + ) + .unwrap(); + + do_process_instruction( + withdraw_single_token_type_exact_amount_out( + &SWAP_PROGRAM_ID, + &pool_token_program_id, + &token_a_program_id, + &accounts.swap_key, + &accounts.authority_key, + &user_transfer_authority_key, + &accounts.pool_mint_key, + &accounts.pool_fee_key, + &pool_key, + &accounts.token_a_key, + &accounts.token_b_key, + &token_a_key, + &accounts.token_a_mint_key, + WithdrawSingleTokenTypeExactAmountOut { + destination_token_amount: destination_a_amount, + maximum_pool_token_amount, + }, + ) + .unwrap(), + vec![ + &mut accounts.swap_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), + &mut accounts.pool_mint_account, + &mut pool_account, + &mut accounts.token_a_account, + &mut accounts.token_b_account, + &mut token_a_account, + &mut accounts.pool_fee_account, + &mut accounts.token_a_mint_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), + ], + ) + .unwrap(); + } + + #[test_case(spl_token::id(), spl_token::id(), spl_token::id(); "all-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token_2022::id(); "all-token-2022")] + #[test_case(spl_token::id(), spl_token_2022::id(), spl_token_2022::id(); "mixed-pool-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token::id(); "mixed-pool-token-2022")] + fn test_valid_swap_with_invalid_fee_account( + pool_token_program_id: Pubkey, + token_a_program_id: Pubkey, + token_b_program_id: Pubkey, + ) { + let owner_key = &Pubkey::new_unique(); + + let token_a_amount = 1_000_000; + let token_b_amount = 5_000_000; + + let fees = Fees { + trade_fee_numerator: 1, + trade_fee_denominator: 10, + owner_trade_fee_numerator: 1, + owner_trade_fee_denominator: 30, + owner_withdraw_fee_numerator: 1, + owner_withdraw_fee_denominator: 30, + host_fee_numerator: 10, + host_fee_denominator: 100, + }; + + let swap_curve = SwapCurve { + curve_type: CurveType::ConstantProduct, + calculator: Arc::new(ConstantProductCurve {}), + }; + + let owner_key_str = owner_key.to_string(); + let constraints = Some(SwapConstraints { + owner_key: Some(owner_key_str.as_ref()), + valid_curve_types: &[CurveType::ConstantProduct], + fees: &fees, + }); + let mut accounts = SwapAccountInfo::new( + owner_key, + fees.clone(), + SwapTransferFees::default(), + swap_curve, + token_a_amount, + token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, + ); + + do_process_instruction_with_fee_constraints( + initialize( + &SWAP_PROGRAM_ID, + &pool_token_program_id, + &accounts.swap_key, + &accounts.authority_key, + &accounts.token_a_key, + &accounts.token_b_key, + &accounts.pool_mint_key, + &accounts.pool_fee_key, + &accounts.pool_token_key, + accounts.fees.clone(), + accounts.swap_curve.clone(), + ) + .unwrap(), + vec![ + &mut accounts.swap_account, + &mut SolanaAccount::default(), + &mut accounts.token_a_account, + &mut accounts.token_b_account, + &mut accounts.pool_mint_account, + &mut accounts.pool_fee_account, + &mut accounts.pool_token_account, + &mut SolanaAccount::default(), + ], + &constraints, + ) + .unwrap(); + + let authority_key = accounts.authority_key; + + let ( + token_a_key, + mut token_a_account, + token_b_key, + mut token_b_account, + pool_key, + mut pool_account, + ) = accounts.setup_token_accounts( + owner_key, + &authority_key, + token_a_amount, + token_b_amount, + 0, + ); + + let destination_key = Pubkey::new_unique(); + let mut destination = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + owner_key, + ); + + do_process_instruction( + close_account( + &pool_token_program_id, + &accounts.pool_fee_key, + &destination_key, + owner_key, + &[], + ) + .unwrap(), + vec![ + &mut accounts.pool_fee_account, + &mut destination, + &mut SolanaAccount::default(), + ], + ) + .unwrap(); + + do_process_instruction_with_fee_constraints( + swap( + &SWAP_PROGRAM_ID, + &token_a_program_id, + &token_b_program_id, + &pool_token_program_id, + &accounts.swap_key, + &accounts.authority_key, + &accounts.authority_key, + &token_a_key, + &accounts.token_a_key, + &accounts.token_b_key, + &token_b_key, + &accounts.pool_mint_key, + &accounts.pool_fee_key, + &accounts.token_a_mint_key, + &accounts.token_b_mint_key, + Some(&pool_key), + Swap { + amount_in: token_a_amount / 2, + minimum_amount_out: 0, + }, + ) + .unwrap(), + vec![ + &mut accounts.swap_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), + &mut token_a_account, + &mut accounts.token_a_account, + &mut accounts.token_b_account, + &mut token_b_account, + &mut accounts.pool_mint_account, + &mut accounts.pool_fee_account, + &mut accounts.token_a_mint_account, + &mut accounts.token_b_mint_account, + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), + &mut SolanaAccount::default(), + &mut pool_account, + ], + &constraints, + ) + .unwrap(); + } + + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token_2022::id(); "all-token-2022")] + #[test_case(spl_token::id(), spl_token_2022::id(), spl_token_2022::id(); "mixed-pool-token")] + #[test_case(spl_token_2022::id(), spl_token_2022::id(), spl_token::id(); "mixed-pool-token-2022")] + fn test_swap_curve_with_transfer_fees( + pool_token_program_id: Pubkey, + token_a_program_id: Pubkey, + token_b_program_id: Pubkey, + ) { + // All fees + let trade_fee_numerator = 1; + let trade_fee_denominator = 10; + let owner_trade_fee_numerator = 1; + let owner_trade_fee_denominator = 30; + let owner_withdraw_fee_numerator = 1; + let owner_withdraw_fee_denominator = 30; + let host_fee_numerator = 20; + let host_fee_denominator = 100; + let fees = Fees { + trade_fee_numerator, + trade_fee_denominator, + owner_trade_fee_numerator, + owner_trade_fee_denominator, + owner_withdraw_fee_numerator, + owner_withdraw_fee_denominator, + host_fee_numerator, + host_fee_denominator, + }; + + let token_a_amount = 10_000_000_000; + let token_b_amount = 50_000_000_000; + + check_valid_swap_curve( + fees, + SwapTransferFees { + pool_token: TransferFee::default(), + token_a: TransferFee { + epoch: 0.into(), + transfer_fee_basis_points: 100.into(), + maximum_fee: 1_000_000_000.into(), + }, + token_b: TransferFee::default(), + }, + CurveType::ConstantProduct, + Arc::new(ConstantProductCurve {}), + token_a_amount, + token_b_amount, + &pool_token_program_id, + &token_a_program_id, + &token_b_program_id, + ); + } } diff --git a/token-swap/program/src/state.rs b/token-swap/program/src/state.rs index 144add6b6ea..d0205d8efdc 100644 --- a/token-swap/program/src/state.rs +++ b/token-swap/program/src/state.rs @@ -1,14 +1,25 @@ //! State transition types -use crate::curve::{base::SwapCurve, fees::Fees}; -use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}; -use enum_dispatch::enum_dispatch; -use solana_program::{ - program_error::ProgramError, - program_pack::{IsInitialized, Pack, Sealed}, - pubkey::Pubkey, +use { + crate::{ + curve::{base::SwapCurve, fees::Fees}, + error::SwapError, + }, + arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}, + enum_dispatch::enum_dispatch, + solana_program::{ + account_info::AccountInfo, + msg, + program_error::ProgramError, + program_pack::{IsInitialized, Pack, Sealed}, + pubkey::Pubkey, + }, + spl_token_2022::{ + extension::StateWithExtensions, + state::{Account, AccountState}, + }, + std::sync::Arc, }; -use std::sync::Arc; /// Trait representing access to program state across all versions #[enum_dispatch] @@ -33,6 +44,9 @@ pub trait SwapState { /// Address of pool fee account fn pool_fee_account(&self) -> &Pubkey; + /// Check if the pool fee info is a valid token program account + /// capable of receiving tokens from the mint. + fn check_pool_fee_info(&self, pool_fee_info: &AccountInfo) -> Result<(), ProgramError>; /// Fees associated with swap fn fees(&self) -> &Fees; @@ -164,6 +178,25 @@ impl SwapState for SwapV1 { &self.pool_fee_account } + fn check_pool_fee_info(&self, pool_fee_info: &AccountInfo) -> Result<(), ProgramError> { + let data = &pool_fee_info.data.borrow(); + let token_account = + StateWithExtensions::::unpack(data).map_err(|err| match err { + ProgramError::InvalidAccountData | ProgramError::UninitializedAccount => { + SwapError::InvalidFeeAccount.into() + } + _ => err, + })?; + if pool_fee_info.owner != &self.token_program_id + || token_account.base.state != AccountState::Initialized + || token_account.base.mint != self.pool_mint + { + msg!("Pool fee account is not owned by token program, is not initialized, or does not match stake pool's mint"); + return Err(SwapError::InvalidFeeAccount.into()); + } + Ok(()) + } + fn fees(&self) -> &Fees { &self.fees } @@ -250,10 +283,7 @@ impl Pack for SwapV1 { #[cfg(test)] mod tests { - use super::*; - use crate::curve::stable::StableCurve; - - use std::convert::TryInto; + use {super::*, crate::curve::offset::OffsetCurve, std::convert::TryInto}; const TEST_FEES: Fees = Fees { trade_fee_numerator: 1, @@ -276,8 +306,10 @@ mod tests { const TEST_POOL_FEE_ACCOUNT: Pubkey = Pubkey::new_from_array([7u8; 32]); const TEST_CURVE_TYPE: u8 = 2; - const TEST_AMP: u64 = 1; - const TEST_CURVE: StableCurve = StableCurve { amp: TEST_AMP }; + const TEST_TOKEN_B_OFFSET: u64 = 1_000_000_000; + const TEST_CURVE: OffsetCurve = OffsetCurve { + token_b_offset: TEST_TOKEN_B_OFFSET, + }; #[test] fn swap_version_pack() { @@ -362,7 +394,7 @@ mod tests { packed.extend_from_slice(&TEST_FEES.host_fee_numerator.to_le_bytes()); packed.extend_from_slice(&TEST_FEES.host_fee_denominator.to_le_bytes()); packed.push(TEST_CURVE_TYPE); - packed.extend_from_slice(&TEST_AMP.to_le_bytes()); + packed.extend_from_slice(&TEST_TOKEN_B_OFFSET.to_le_bytes()); packed.extend_from_slice(&[0u8; 24]); let unpacked = SwapV1::unpack(&packed).unwrap(); assert_eq!(swap_info, unpacked); diff --git a/token-swap/proposals/DynamicMarketMaking.md b/token-swap/proposals/DynamicMarketMaking.md index 20901def2d7..49d64c779c4 100644 --- a/token-swap/proposals/DynamicMarketMaking.md +++ b/token-swap/proposals/DynamicMarketMaking.md @@ -1,6 +1,10 @@ -# Serum DEX Dynamic market making curve for token-swap +# Openbook DEX Dynamic market making curve for token-swap -Implement a curve for token-swap that accepts serum CLOB dex for the same pair. Implementation should 'split'/'route' portion of order using predefined curve for the pool and the rest to the dex as IOC order. Dynamic curve should find ideal size of the order based on the curve parameters and market depth for a given DEX. +Implement a curve for token-swap that accepts CLOB dex for the same pair. +Implementation should 'split'/'route' portion of order using predefined curve +for the pool and the rest to the dex as IOC order. Dynamic curve should find +ideal size of the order based on the curve parameters and market depth for a +given DEX. Ideas: * CLOB fee discounts @@ -10,4 +14,4 @@ Ideas: - AMM should charge same fee structure with 30bps difference from fees in CLOB ## Links -1. CLOB implementation: https://github.com/project-serum/serum-dex/tree/master/dex \ No newline at end of file +1. CLOB implementation: https://github.com/openbook-dex/program/tree/master/dex diff --git a/token-upgrade/README.md b/token-upgrade/README.md new file mode 100644 index 00000000000..b1925e6bbb1 --- /dev/null +++ b/token-upgrade/README.md @@ -0,0 +1,9 @@ +# Token Upgrade + +The Token Upgrade Program provides a stateless protocol for permanently converting +tokens from one mint to another. + +## Audit + +The repository [README](https://github.com/solana-labs/solana-program-library#audits) +contains information about program audits. diff --git a/token-upgrade/cli/Cargo.toml b/token-upgrade/cli/Cargo.toml new file mode 100644 index 00000000000..f542f67007b --- /dev/null +++ b/token-upgrade/cli/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "spl-token-upgrade-cli" +version = "0.1.1" +description = "SPL Token Upgrade Command-line Utility" +authors = ["Solana Labs Maintainers "] +repository = "https://github.com/solana-labs/solana-program-library" +license = "Apache-2.0" +edition = "2021" + +[build-dependencies] +walkdir = "2" + +[dependencies] +clap = { version = "3", features = ["cargo"] } +futures-util = "0.3.31" +solana-clap-v3-utils = "2.1.0" +solana-cli-config = "2.1.0" +solana-client = "2.1.0" +solana-logger = "2.1.0" +solana-remote-wallet = "2.1.0" +solana-sdk = "2.1.0" +spl-associated-token-account-client = { version = "2.0.0" } +spl-token = { version = "7.0", features = ["no-entrypoint"] } +spl-token-2022 = { version = "6.0.0", features = ["no-entrypoint"] } +spl-token-client = { version = "0.13.0" } +spl-token-upgrade = { version = "0.1", path = "../program", features = ["no-entrypoint"] } +tokio = { version = "1", features = ["full"] } + +[dev-dependencies] +solana-test-validator = "2.1.0" + +[[bin]] +name = "spl-token-upgrade" +path = "src/main.rs" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] diff --git a/token-upgrade/cli/src/main.rs b/token-upgrade/cli/src/main.rs new file mode 100644 index 00000000000..852418d7d4c --- /dev/null +++ b/token-upgrade/cli/src/main.rs @@ -0,0 +1,821 @@ +use { + clap::{crate_description, crate_name, crate_version, Arg, ArgAction, Command}, + solana_clap_v3_utils::{ + input_parsers::{ + parse_url_or_moniker, + signer::{SignerSource, SignerSourceParserBuilder}, + }, + input_validators::normalize_to_url_if_moniker, + keypair::{signer_from_path, signer_from_source, SignerFromPathConfig}, + }, + solana_client::nonblocking::rpc_client::RpcClient, + solana_remote_wallet::remote_wallet::RemoteWalletManager, + solana_sdk::{ + commitment_config::CommitmentConfig, + message::Message, + program_option::COption, + pubkey::Pubkey, + signature::{Signature, Signer}, + transaction::Transaction, + }, + spl_associated_token_account_client::address::get_associated_token_address_with_program_id, + spl_token_2022::{ + extension::StateWithExtensions, + state::{Account, Mint}, + }, + spl_token_client::{ + client::{ProgramRpcClient, ProgramRpcClientSendTransaction, RpcClientResponse}, + token::Token, + }, + spl_token_upgrade::{get_token_upgrade_authority_address, instruction::exchange}, + std::{error::Error, process::exit, rc::Rc, sync::Arc}, +}; + +struct Config { + commitment_config: CommitmentConfig, + payer: Arc, + json_rpc_url: String, + verbose: bool, +} + +async fn get_mint_owner_checked( + rpc_client: &RpcClient, + mint: &Pubkey, +) -> Result> { + let mint_account = rpc_client.get_account(mint).await?; + let _ = StateWithExtensions::::unpack(&mint_account.data) + .map_err(|_| format!("Account {} is not a valid mint", mint))?; + Ok(mint_account.owner) +} + +async fn escrow_exists_checked( + rpc_client: &RpcClient, + escrow: &Pubkey, + escrow_authority: &Pubkey, + mint: &Pubkey, +) -> Result> { + if let Ok(escrow_account) = rpc_client.get_account(escrow).await { + let account_state = StateWithExtensions::::unpack(&escrow_account.data) + .map_err(|_| format!("Account {} is not a valid account", escrow))?; + if account_state.base.mint != *mint { + Err(format!( + "Escrow account is for mint {}, need an account for mint {}", + account_state.base.mint, mint + ) + .into()) + } else if account_state.base.owner != *escrow_authority + && account_state.base.delegate != COption::Some(*escrow_authority) + { + Err(format!("Escrow account {} is neither owned by nor delegated to escrow authority {}, please provide another account", escrow, escrow_authority).into()) + } else { + Ok(true) + } + } else { + Ok(false) + } +} + +async fn process_create_escrow_account( + rpc_client: &Arc, + payer: &Arc, + original_mint: &Pubkey, + new_mint: &Pubkey, + account_keypair: Option<&dyn Signer>, +) -> Result> { + let _ = get_mint_owner_checked(rpc_client, original_mint).await?; + let new_program_id = get_mint_owner_checked(rpc_client, new_mint).await?; + let escrow_authority = + get_token_upgrade_authority_address(original_mint, new_mint, &spl_token_upgrade::id()); + + let program_client = Arc::new(ProgramRpcClient::new( + rpc_client.clone(), + ProgramRpcClientSendTransaction, + )); + let token = Token::new( + program_client.clone(), + &new_program_id, + new_mint, + None, + payer.clone(), + ); + + let escrow = account_keypair + .map(|k| k.pubkey()) + .unwrap_or_else(|| token.get_associated_token_address(&escrow_authority)); + + if escrow_exists_checked(rpc_client, &escrow, &escrow_authority, new_mint).await? { + return Err(format!( + "Escrow account {} already exists, not doing anything", + escrow + ) + .into()); + } + + println!( + "Creating escrow account {} owned by escrow authority {}", + escrow, escrow_authority + ); + if let Some(keypair) = account_keypair { + token + .create_auxiliary_token_account(keypair, &escrow_authority) + .await + .map_err(|e| e.into()) + } else { + token + .create_associated_token_account(&escrow_authority) + .await + .map_err(|e| e.into()) + } +} + +#[allow(clippy::too_many_arguments)] +async fn process_exchange( + rpc_client: &Arc, + payer: &Arc, + original_mint: &Pubkey, + new_mint: &Pubkey, + owner: &Arc, + burn_from: Option, + escrow: Option, + destination: Option, + multisig_pubkeys: &[Pubkey], + bulk_signers: Vec>, +) -> Result> { + let original_program_id = get_mint_owner_checked(rpc_client, original_mint).await?; + let new_program_id = get_mint_owner_checked(rpc_client, new_mint).await?; + let escrow_authority = + get_token_upgrade_authority_address(original_mint, new_mint, &spl_token_upgrade::id()); + + let burn_from = burn_from.unwrap_or_else(|| { + get_associated_token_address_with_program_id( + &owner.pubkey(), + original_mint, + &original_program_id, + ) + }); + + let escrow = escrow.unwrap_or_else(|| { + get_associated_token_address_with_program_id(&escrow_authority, new_mint, &new_program_id) + }); + + let destination = destination.unwrap_or_else(|| { + get_associated_token_address_with_program_id(&owner.pubkey(), new_mint, &new_program_id) + }); + + println!( + "Burning tokens from account {}, receiving tokens into account {}", + burn_from, destination + ); + let mut transaction = Transaction::new_unsigned(Message::new( + &[exchange( + &spl_token_upgrade::id(), + &burn_from, + original_mint, + &escrow, + &destination, + new_mint, + &original_program_id, + &new_program_id, + &owner.pubkey(), + &multisig_pubkeys.iter().collect::>(), + )], + Some(&payer.pubkey()), + )); + + let blockhash = rpc_client + .get_latest_blockhash() + .await + .map_err(|err| format!("error: unable to get latest blockhash: {}", err))?; + + transaction + .try_sign(&bulk_signers, blockhash) + .map_err(|err| format!("error: failed to sign transaction: {}", err))?; + + let signature = rpc_client + .send_and_confirm_transaction_with_spinner(&transaction) + .await + .map_err(|err| format!("error: send transaction: {}", err))?; + + Ok(signature) +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + let app_matches = Command::new(crate_name!()) + .about(crate_description!()) + .version(crate_version!()) + .subcommand_required(true) + .arg_required_else_help(true) + .arg({ + let arg = Arg::new("config_file") + .short('C') + .long("config") + .value_name("PATH") + .takes_value(true) + .global(true) + .help("Configuration file to use"); + if let Some(ref config_file) = *solana_cli_config::CONFIG_FILE { + arg.default_value(config_file) + } else { + arg + } + }) + .arg( + Arg::new("payer") + .long("payer") + .value_name("KEYPAIR") + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) + .takes_value(true) + .global(true) + .help("Filepath or URL to a keypair [default: client keypair]"), + ) + .arg( + Arg::new("verbose") + .long("verbose") + .short('v') + .takes_value(false) + .global(true) + .help("Show additional information"), + ) + .arg( + Arg::new("json_rpc_url") + .short('u') + .long("url") + .value_name("URL") + .takes_value(true) + .global(true) + .value_parser(parse_url_or_moniker) + .help("JSON RPC URL for the cluster [default: value from configuration file]"), + ) + .subcommand( + Command::new("create-escrow").about("Create token account for the program escrow") + .arg( + Arg::new("original_mint") + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) + .value_name("ADDRESS") + .required(true) + .takes_value(true) + .index(1) + .help("Original mint address, whose tokens will be burned") + ) + .arg( + Arg::new("new_mint") + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) + .value_name("ADDRESS") + .required(true) + .takes_value(true) + .index(2) + .help("New mint address, whose tokens will be transferred to users") + ) + .arg( + Arg::new("account_keypair") + .value_name("ACCOUNT_KEYPAIR") + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) + .takes_value(true) + .index(3) + .help("Specify the account keypair. This may be a keypair file or the ASK keyword. [default: associated token account for escrow authority]"), + ) + ) + .subcommand( + Command::new("exchange").about("Exchange original tokens for new tokens") + .arg( + Arg::new("original_mint") + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) + .value_name("ADDRESS") + .required(true) + .takes_value(true) + .index(1) + .help("Original mint address, whose tokens will be burned") + ) + .arg( + Arg::new("new_mint") + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) + .value_name("ADDRESS") + .required(true) + .takes_value(true) + .index(2) + .help("New mint address, whose tokens will be transferred to users") + ) + .arg( + Arg::new("owner") + .long("owner") + .value_name("OWNER_KEYPAIR") + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) + .takes_value(true) + .help("Specify the owner or delegate for the burnt account. This may be a keypair file or the ASK keyword. [default: fee payer]"), + ) + .arg( + Arg::new("burn_from") + .long("burn-from") + .value_name("BURN_TOKEN_ACCOUNT_ADDRESS") + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) + .takes_value(true) + .help("Specify the burnt account address. [default: associated token account for owner on original mint]"), + ) + .arg( + Arg::new("escrow") + .long("escrow") + .value_name("ESCROW_TOKEN_ACCOUNT_ADDRESS") + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) + .takes_value(true) + .help("Specify the escrow account address to transfer from. [default: associated token account for the escrow authority on new mint]"), + ) + .arg( + Arg::new("destination") + .long("destination") + .value_name("DESTINATION_ACCOUNT_ADDRESS") + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) + .takes_value(true) + .help("Specify the destination account to receive new tokens. [default: associated token account for owner on new mint]"), + ) + .arg( + Arg::new("multisig_signer") + .long("multisig-signer") + .value_parser(SignerSourceParserBuilder::default().allow_all().build()) + .value_name("MULTISIG_SIGNER") + .takes_value(true) + .action(ArgAction::Append) + .min_values(0) + .max_values(spl_token_2022::instruction::MAX_SIGNERS) + .help("Member signer of a multisig account") + ) + ) + .get_matches(); + + let (command, matches) = app_matches.subcommand().unwrap(); + let mut wallet_manager: Option> = None; + + let config = { + let cli_config = if let Some(config_file) = matches.try_get_one::("config_file")? { + solana_cli_config::Config::load(config_file).unwrap_or_default() + } else { + solana_cli_config::Config::default() + }; + + let payer = if let Ok(Some((signer, _))) = + SignerSource::try_get_signer(matches, "payer", &mut wallet_manager) + { + Box::new(signer) + } else { + signer_from_path( + matches, + &cli_config.keypair_path, + "payer", + &mut wallet_manager, + )? + }; + + let json_rpc_url = normalize_to_url_if_moniker( + matches + .get_one::("json_rpc_url") + .unwrap_or(&cli_config.json_rpc_url), + ); + + Config { + commitment_config: CommitmentConfig::confirmed(), + payer: Arc::from(payer), + json_rpc_url, + verbose: matches.try_contains_id("verbose")?, + } + }; + solana_logger::setup_with_default("solana=info"); + + if config.verbose { + println!("JSON RPC URL: {}", config.json_rpc_url); + } + let rpc_client = Arc::new(RpcClient::new_with_commitment( + config.json_rpc_url.clone(), + config.commitment_config, + )); + + match (command, matches) { + ("create-escrow", arg_matches) => { + let original_mint = + SignerSource::try_get_pubkey(arg_matches, "original_mint", &mut wallet_manager) + .unwrap() + .unwrap(); + let new_mint = + SignerSource::try_get_pubkey(arg_matches, "new_mint", &mut wallet_manager) + .unwrap() + .unwrap(); + let account_keypair = + SignerSource::try_get_signer(matches, "account_keypair", &mut wallet_manager)? + .map(|(signer, _)| signer); + let response = process_create_escrow_account( + &rpc_client, + &config.payer, + &original_mint, + &new_mint, + account_keypair.as_ref().map(|k| k.as_ref()), + ) + .await + .unwrap_or_else(|err| { + eprintln!("error: create escrow: {}", err); + exit(1); + }); + println!("{}", response); + } + ("exchange", arg_matches) => { + let mut bulk_signers = vec![config.payer.clone()]; + let mut multisig_pubkeys = vec![]; + + if let Some(sources) = arg_matches.try_get_many::("multisig_signer")? { + for (i, source) in sources.enumerate() { + let name = format!("{}-{}", "multisig_signer", i.saturating_add(1)); + let signer = + signer_from_source(arg_matches, source, &name, &mut wallet_manager) + .unwrap_or_else(|e| { + eprint!("error parsing multisig signer: {}", e); + exit(1); + }); + let signer_pubkey = signer.pubkey(); + let signer = Arc::from(signer); + if !bulk_signers.contains(&signer) { + bulk_signers.push(signer); + } + if !multisig_pubkeys.contains(&signer_pubkey) { + multisig_pubkeys.push(signer_pubkey); + } + } + } + + let original_mint = + SignerSource::try_get_pubkey(arg_matches, "original_mint", &mut wallet_manager) + .unwrap() + .unwrap(); + let new_mint = + SignerSource::try_get_pubkey(arg_matches, "new_mint", &mut wallet_manager) + .unwrap() + .unwrap(); + let signer_config = SignerFromPathConfig { + allow_null_signer: !multisig_pubkeys.is_empty(), + }; + let owner = if let Ok(Some((signer, _))) = + SignerSource::try_get_signer(matches, "owner", &mut wallet_manager) + { + Arc::from(signer) + } else { + config.payer.clone() + }; + if !signer_config.allow_null_signer && !bulk_signers.contains(&owner) { + bulk_signers.push(owner.clone()); + } + let burn_from = + SignerSource::try_get_pubkey(arg_matches, "burn_from", &mut wallet_manager) + .unwrap(); + let escrow = + SignerSource::try_get_pubkey(arg_matches, "escrow", &mut wallet_manager).unwrap(); + let destination = + SignerSource::try_get_pubkey(arg_matches, "destination", &mut wallet_manager) + .unwrap(); + + let signature = process_exchange( + &rpc_client, + &config.payer, + &original_mint, + &new_mint, + &owner, + burn_from, + escrow, + destination, + &multisig_pubkeys, + bulk_signers, + ) + .await + .unwrap_or_else(|err| { + eprintln!("error: send transaction: {}", err); + exit(1); + }); + println!("Signature: {}", signature); + } + _ => unreachable!(), + }; + + Ok(()) +} + +#[cfg(test)] +mod test { + use { + super::*, + solana_sdk::{bpf_loader_upgradeable, signer::keypair::Keypair}, + solana_test_validator::{TestValidator, TestValidatorGenesis, UpgradeableProgramInfo}, + spl_token_client::client::{ProgramClient, SendTransaction, SimulateTransaction}, + std::path::PathBuf, + }; + + async fn new_validator_for_test() -> (TestValidator, Keypair) { + solana_logger::setup(); + let mut test_validator_genesis = TestValidatorGenesis::default(); + test_validator_genesis.add_upgradeable_programs_with_path(&[UpgradeableProgramInfo { + program_id: spl_token_upgrade::id(), + loader: bpf_loader_upgradeable::id(), + program_path: PathBuf::from("../../target/deploy/spl_token_upgrade.so"), + upgrade_authority: Pubkey::new_unique(), + }]); + test_validator_genesis.start_async().await + } + + async fn setup_mint( + program_id: &Pubkey, + mint_authority: &Pubkey, + decimals: u8, + payer: Arc, + client: Arc>, + ) -> Token { + let mint_account = Keypair::new(); + let token = Token::new( + client, + program_id, + &mint_account.pubkey(), + Some(decimals), + payer, + ); + token + .create_mint(mint_authority, None, vec![], &[&mint_account]) + .await + .unwrap(); + token + } + + #[tokio::test] + async fn success_create_escrow() { + let (test_validator, payer) = new_validator_for_test().await; + let payer: Arc = Arc::new(payer); + let rpc_client = Arc::new(test_validator.get_async_rpc_client()); + let client = Arc::new(ProgramRpcClient::new( + rpc_client.clone(), + ProgramRpcClientSendTransaction, + )); + + let mint_authority = Keypair::new(); + let decimals = 2; + + let original_token = setup_mint( + &spl_token::id(), + &mint_authority.pubkey(), + decimals, + payer.clone(), + client.clone(), + ) + .await; + let new_token = setup_mint( + &spl_token_2022::id(), + &mint_authority.pubkey(), + decimals, + payer.clone(), + client.clone(), + ) + .await; + + let account_keypair = Keypair::new(); + assert!(process_create_escrow_account( + &rpc_client, + &payer, + original_token.get_address(), + new_token.get_address(), + Some(&account_keypair) + ) + .await + .is_ok()); + let escrow_authority = get_token_upgrade_authority_address( + original_token.get_address(), + new_token.get_address(), + &spl_token_upgrade::id(), + ); + let escrow = new_token + .get_account_info(&account_keypair.pubkey()) + .await + .unwrap(); + assert_eq!(escrow.base.owner, escrow_authority); + assert_eq!(&escrow.base.mint, new_token.get_address()); + + assert!(process_create_escrow_account( + &rpc_client, + &payer, + original_token.get_address(), + new_token.get_address(), + None + ) + .await + .is_ok()); + let escrow = new_token + .get_account_info(&new_token.get_associated_token_address(&escrow_authority)) + .await + .unwrap(); + assert_eq!(escrow.base.owner, escrow_authority); + assert_eq!(&escrow.base.mint, new_token.get_address()); + } + + #[tokio::test] + async fn success_exchange_associated_accounts() { + let (test_validator, payer) = new_validator_for_test().await; + let payer: Arc = Arc::new(payer); + let rpc_client = Arc::new(test_validator.get_async_rpc_client()); + let client = Arc::new(ProgramRpcClient::new( + rpc_client.clone(), + ProgramRpcClientSendTransaction, + )); + + let mint_authority = Keypair::new(); + let decimals = 2; + + let original_token = setup_mint( + &spl_token::id(), + &mint_authority.pubkey(), + decimals, + payer.clone(), + client.clone(), + ) + .await; + let new_token = setup_mint( + &spl_token_2022::id(), + &mint_authority.pubkey(), + decimals, + payer.clone(), + client.clone(), + ) + .await; + + process_create_escrow_account( + &rpc_client, + &payer, + original_token.get_address(), + new_token.get_address(), + None, + ) + .await + .unwrap(); + + let user = Keypair::new(); + let amount = 1_000_000_000_000; + original_token + .create_associated_token_account(&user.pubkey()) + .await + .unwrap(); + let burn_from = original_token.get_associated_token_address(&user.pubkey()); + + original_token + .mint_to( + &burn_from, + &mint_authority.pubkey(), + amount, + &[&mint_authority], + ) + .await + .unwrap(); + + // mint tokens to the escrow + let escrow_authority = get_token_upgrade_authority_address( + original_token.get_address(), + new_token.get_address(), + &spl_token_upgrade::id(), + ); + let escrow = new_token.get_associated_token_address(&escrow_authority); + new_token + .mint_to( + &escrow, + &mint_authority.pubkey(), + amount, + &[&mint_authority], + ) + .await + .unwrap(); + + new_token + .create_associated_token_account(&user.pubkey()) + .await + .unwrap(); + let destination = new_token.get_associated_token_address(&user.pubkey()); + + let user: Arc = Arc::new(user); + process_exchange( + &rpc_client, + &payer, + original_token.get_address(), + new_token.get_address(), + &user, + None, + None, + None, + &[], + vec![payer.clone(), user.clone()], + ) + .await + .unwrap(); + + let burn_account = original_token.get_account_info(&burn_from).await.unwrap(); + assert_eq!(burn_account.base.amount, 0); + + let escrow_account = new_token.get_account_info(&escrow).await.unwrap(); + assert_eq!(escrow_account.base.amount, 0); + + let destination_account = new_token.get_account_info(&destination).await.unwrap(); + assert_eq!(destination_account.base.amount, amount); + } + + #[tokio::test] + async fn success_exchange_auxiliary_accounts() { + let (test_validator, payer) = new_validator_for_test().await; + let payer: Arc = Arc::new(payer); + let rpc_client = Arc::new(test_validator.get_async_rpc_client()); + let client = Arc::new(ProgramRpcClient::new( + rpc_client.clone(), + ProgramRpcClientSendTransaction, + )); + + let mint_authority = Keypair::new(); + let decimals = 2; + + let original_token = setup_mint( + &spl_token::id(), + &mint_authority.pubkey(), + decimals, + payer.clone(), + client.clone(), + ) + .await; + let new_token = setup_mint( + &spl_token_2022::id(), + &mint_authority.pubkey(), + decimals, + payer.clone(), + client.clone(), + ) + .await; + + let escrow = Keypair::new(); + process_create_escrow_account( + &rpc_client, + &payer, + original_token.get_address(), + new_token.get_address(), + Some(&escrow), + ) + .await + .unwrap(); + let escrow = escrow.pubkey(); + + let user = Keypair::new(); + let amount = 1_000_000_000_000; + let burn_from = Keypair::new(); + original_token + .create_auxiliary_token_account(&burn_from, &user.pubkey()) + .await + .unwrap(); + let burn_from = burn_from.pubkey(); + + original_token + .mint_to( + &burn_from, + &mint_authority.pubkey(), + amount, + &[&mint_authority], + ) + .await + .unwrap(); + + // mint tokens to the escrow + new_token + .mint_to( + &escrow, + &mint_authority.pubkey(), + amount, + &[&mint_authority], + ) + .await + .unwrap(); + + let destination = Keypair::new(); + new_token + .create_auxiliary_token_account(&destination, &user.pubkey()) + .await + .unwrap(); + let destination = destination.pubkey(); + + let user: Arc = Arc::new(user); + process_exchange( + &rpc_client, + &payer, + original_token.get_address(), + new_token.get_address(), + &user, + Some(burn_from), + Some(escrow), + Some(destination), + &[], + vec![payer.clone(), user.clone()], + ) + .await + .unwrap(); + + let burn_account = original_token.get_account_info(&burn_from).await.unwrap(); + assert_eq!(burn_account.base.amount, 0); + + let escrow_account = new_token.get_account_info(&escrow).await.unwrap(); + assert_eq!(escrow_account.base.amount, 0); + + let destination_account = new_token.get_account_info(&destination).await.unwrap(); + assert_eq!(destination_account.base.amount, amount); + } +} diff --git a/token-upgrade/program/Cargo.toml b/token-upgrade/program/Cargo.toml new file mode 100644 index 00000000000..296cdb2bd18 --- /dev/null +++ b/token-upgrade/program/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "spl-token-upgrade" +version = "0.1.1" +description = "Solana Program Library Token Upgrade" +authors = ["Solana Labs Maintainers "] +repository = "https://github.com/solana-labs/solana-program-library" +license = "Apache-2.0" +edition = "2021" + +[features] +no-entrypoint = [] +test-sbf = [] + +[dependencies] +num-derive = "0.4" +num-traits = "0.2" +num_enum = "0.7.3" +solana-program = "2.1.0" +spl-token-2022 = { version = "6.0.0", features = ["no-entrypoint"] } +thiserror = "2.0" + +[dev-dependencies] +solana-program-test = "2.1.0" +solana-sdk = "2.1.0" +spl-token = { version = "7.0", features = ["no-entrypoint"] } +spl-token-client = { version = "0.13.0" } +test-case = "3.3" + +[lib] +crate-type = ["cdylib", "lib"] + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] diff --git a/token-upgrade/program/program-id.md b/token-upgrade/program/program-id.md new file mode 100644 index 00000000000..f5d24b3c13c --- /dev/null +++ b/token-upgrade/program/program-id.md @@ -0,0 +1 @@ +TkupDoNseygccBCjSsrSpMccjwHfTYwcrjpnDSrFDhC diff --git a/token-upgrade/program/src/entrypoint.rs b/token-upgrade/program/src/entrypoint.rs new file mode 100644 index 00000000000..bb9a931af22 --- /dev/null +++ b/token-upgrade/program/src/entrypoint.rs @@ -0,0 +1,14 @@ +//! Program entrypoint + +#![cfg(not(feature = "no-entrypoint"))] + +use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey}; + +solana_program::entrypoint!(process_instruction); +fn process_instruction( + program_id: &Pubkey, + accounts: &[AccountInfo], + instruction_data: &[u8], +) -> ProgramResult { + crate::processor::process(program_id, accounts, instruction_data) +} diff --git a/token-upgrade/program/src/error.rs b/token-upgrade/program/src/error.rs new file mode 100644 index 00000000000..aec48cc879d --- /dev/null +++ b/token-upgrade/program/src/error.rs @@ -0,0 +1,29 @@ +//! Error types + +use { + num_derive::FromPrimitive, + solana_program::{decode_error::DecodeError, program_error::ProgramError}, + thiserror::Error, +}; + +/// Errors that may be returned by the program. +#[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] +pub enum TokenUpgradeError { + // 0 + /// Account does not match address derivation + #[error("Account does not match address derivation")] + InvalidOwner, + /// Decimals of original and new token mint do not match + #[error("Decimals of original and new token mint do not match")] + DecimalsMismatch, +} +impl From for ProgramError { + fn from(e: TokenUpgradeError) -> Self { + ProgramError::Custom(e as u32) + } +} +impl DecodeError for TokenUpgradeError { + fn type_of() -> &'static str { + "TokenUpgradeError" + } +} diff --git a/token-upgrade/program/src/instruction.rs b/token-upgrade/program/src/instruction.rs new file mode 100644 index 00000000000..527a263702c --- /dev/null +++ b/token-upgrade/program/src/instruction.rs @@ -0,0 +1,80 @@ +//! Program instructions + +use { + crate::get_token_upgrade_authority_address, + num_enum::{IntoPrimitive, TryFromPrimitive}, + solana_program::{ + instruction::{AccountMeta, Instruction}, + pubkey::Pubkey, + }, +}; + +/// Instructions supported by the TokenUpgrade program +#[derive(Clone, Copy, Debug, TryFromPrimitive, IntoPrimitive)] +#[repr(u8)] +pub enum TokenUpgradeInstruction { + /// Burns all of the original tokens in the user's account, and transfers + /// the same amount of tokens from an account owned by a PDA into + /// another account. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writeable]` Original token account to burn from + /// 1. `[writeable]` Original token mint + /// 2. `[writeable]` Escrow of new tokens held by or delegated to PDA at + /// address: `get_token_upgrade_authority_address(original_mint, + /// new_mint, program_id)` + /// 3. `[writeable]` New token account to transfer into + /// 4. `[]` New token mint + /// 5. `[]` Transfer authority (owner or delegate) of new token escrow + /// held by PDA, must be: + /// `get_token_upgrade_authority_address(original_mint, new_mint, + /// program_id)` + /// 6. `[]` SPL Token program for original mint + /// 7. `[]` SPL Token program for new mint + /// 8. `[]` Original token account transfer authority (owner or delegate) + /// 9. ..9+M `[signer]` M multisig signer accounts + /// + /// Data expected by this instruction: + /// None + Exchange, +} + +/// Create an `Exchange` instruction +#[allow(clippy::too_many_arguments)] +pub fn exchange( + program_id: &Pubkey, + original_account: &Pubkey, + original_mint: &Pubkey, + new_escrow: &Pubkey, + new_account: &Pubkey, + new_mint: &Pubkey, + original_token_program_id: &Pubkey, + new_token_program_id: &Pubkey, + original_transfer_authority: &Pubkey, + original_multisig_signers: &[&Pubkey], +) -> Instruction { + let escrow_authority = get_token_upgrade_authority_address(original_mint, new_mint, program_id); + let mut accounts = Vec::with_capacity(9usize.saturating_add(original_multisig_signers.len())); + accounts.push(AccountMeta::new(*original_account, false)); + accounts.push(AccountMeta::new(*original_mint, false)); + accounts.push(AccountMeta::new(*new_escrow, false)); + accounts.push(AccountMeta::new(*new_account, false)); + accounts.push(AccountMeta::new(*new_mint, false)); + accounts.push(AccountMeta::new_readonly(escrow_authority, false)); + accounts.push(AccountMeta::new_readonly(*original_token_program_id, false)); + accounts.push(AccountMeta::new_readonly(*new_token_program_id, false)); + accounts.push(AccountMeta::new_readonly( + *original_transfer_authority, + original_multisig_signers.is_empty(), + )); + for signer_pubkey in original_multisig_signers.iter() { + accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); + } + + Instruction { + program_id: *program_id, + accounts, + data: vec![TokenUpgradeInstruction::Exchange.into()], + } +} diff --git a/token-upgrade/program/src/lib.rs b/token-upgrade/program/src/lib.rs new file mode 100644 index 00000000000..7944b70b618 --- /dev/null +++ b/token-upgrade/program/src/lib.rs @@ -0,0 +1,61 @@ +//! Convention for upgrading tokens from one program to another +#![deny(missing_docs)] +#![forbid(unsafe_code)] + +mod entrypoint; +pub mod error; +pub mod instruction; +pub mod processor; + +// Export current SDK types for downstream users building with a different SDK +// version +pub use solana_program; +use solana_program::pubkey::Pubkey; + +solana_program::declare_id!("TkupDoNseygccBCjSsrSpMccjwHfTYwcrjpnDSrFDhC"); + +const TOKEN_ESCROW_AUTHORITY_SEED: &[u8] = b"token-escrow-authority"; + +/// Get the upgrade token account authority +pub fn get_token_upgrade_authority_address( + original_mint: &Pubkey, + new_mint: &Pubkey, + program_id: &Pubkey, +) -> Pubkey { + get_token_upgrade_authority_address_and_bump_seed(original_mint, new_mint, program_id).0 +} + +pub(crate) fn get_token_upgrade_authority_address_and_bump_seed( + original_mint: &Pubkey, + new_mint: &Pubkey, + program_id: &Pubkey, +) -> (Pubkey, u8) { + Pubkey::find_program_address( + &collect_token_upgrade_authority_seeds(original_mint, new_mint), + program_id, + ) +} + +pub(crate) fn collect_token_upgrade_authority_seeds<'a>( + original_mint: &'a Pubkey, + new_mint: &'a Pubkey, +) -> [&'a [u8]; 3] { + [ + TOKEN_ESCROW_AUTHORITY_SEED, + original_mint.as_ref(), + new_mint.as_ref(), + ] +} + +pub(crate) fn collect_token_upgrade_authority_signer_seeds<'a>( + original_mint: &'a Pubkey, + new_mint: &'a Pubkey, + bump_seed: &'a [u8], +) -> [&'a [u8]; 4] { + [ + TOKEN_ESCROW_AUTHORITY_SEED, + original_mint.as_ref(), + new_mint.as_ref(), + bump_seed, + ] +} diff --git a/token-upgrade/program/src/processor.rs b/token-upgrade/program/src/processor.rs new file mode 100644 index 00000000000..661f1473b3b --- /dev/null +++ b/token-upgrade/program/src/processor.rs @@ -0,0 +1,190 @@ +//! Program state processor + +use { + crate::{ + collect_token_upgrade_authority_signer_seeds, error::TokenUpgradeError, + get_token_upgrade_authority_address_and_bump_seed, instruction::TokenUpgradeInstruction, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + msg, + program::{invoke, invoke_signed}, + program_error::ProgramError, + pubkey::Pubkey, + }, + spl_token_2022::{ + extension::StateWithExtensions, + instruction::decode_instruction_type, + state::{Account, Mint}, + }, +}; + +fn check_owner(account_info: &AccountInfo, expected_owner: &Pubkey) -> ProgramResult { + if account_info.owner != expected_owner { + Err(ProgramError::IllegalOwner) + } else { + Ok(()) + } +} + +fn burn_original_tokens<'a>( + original_token_program: AccountInfo<'a>, + source: AccountInfo<'a>, + mint: AccountInfo<'a>, + authority: AccountInfo<'a>, + multisig_signers: &[AccountInfo<'a>], + amount: u64, + decimals: u8, +) -> ProgramResult { + let multisig_pubkeys = multisig_signers.iter().map(|s| s.key).collect::>(); + let ix = spl_token_2022::instruction::burn_checked( + original_token_program.key, + source.key, + mint.key, + authority.key, + &multisig_pubkeys, + amount, + decimals, + )?; + let mut account_infos = vec![source, mint, authority]; + account_infos.extend_from_slice(multisig_signers); + invoke(&ix, &account_infos) +} + +#[allow(clippy::too_many_arguments)] +fn transfer_new_tokens<'a>( + new_token_program: AccountInfo<'a>, + source: AccountInfo<'a>, + mint: AccountInfo<'a>, + destination: AccountInfo<'a>, + authority: AccountInfo<'a>, + authority_seeds: &[&[u8]], + amount: u64, + decimals: u8, +) -> Result<(), ProgramError> { + let ix = spl_token_2022::instruction::transfer_checked( + new_token_program.key, + source.key, + mint.key, + destination.key, + authority.key, + &[], + amount, + decimals, + )?; + invoke_signed( + &ix, + &[source, mint, destination, authority], + &[authority_seeds], + ) +} + +fn process_exchange(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + + let original_account_info = next_account_info(account_info_iter)?; + let original_mint_info = next_account_info(account_info_iter)?; + let new_escrow_info = next_account_info(account_info_iter)?; + let new_account_info = next_account_info(account_info_iter)?; + let new_mint_info = next_account_info(account_info_iter)?; + let new_transfer_authority_info = next_account_info(account_info_iter)?; + let original_token_program = next_account_info(account_info_iter)?; + let new_token_program = next_account_info(account_info_iter)?; + let original_transfer_authority_info = next_account_info(account_info_iter)?; + + // owner checks + check_owner(original_account_info, original_token_program.key)?; + check_owner(original_mint_info, original_token_program.key)?; + check_owner(new_escrow_info, new_token_program.key)?; + check_owner(new_account_info, new_token_program.key)?; + check_owner(new_mint_info, new_token_program.key)?; + + // PDA derivation check + let (expected_escrow_authority, bump_seed) = get_token_upgrade_authority_address_and_bump_seed( + original_mint_info.key, + new_mint_info.key, + program_id, + ); + let bump_seed = [bump_seed]; + let authority_seeds = collect_token_upgrade_authority_signer_seeds( + original_mint_info.key, + new_mint_info.key, + &bump_seed, + ); + if expected_escrow_authority != *new_transfer_authority_info.key { + msg!( + "Expected escrow authority {}, received {}", + &expected_escrow_authority, + new_transfer_authority_info.key + ); + return Err(TokenUpgradeError::InvalidOwner.into()); + } + + // pull out these values in a block to drop all data before performing CPIs + let (token_amount, decimals) = { + // check mints are actually mints + let original_mint_data = original_mint_info.try_borrow_data()?; + let original_mint = StateWithExtensions::::unpack(&original_mint_data)?; + let new_mint_data = new_mint_info.try_borrow_data()?; + let new_mint = StateWithExtensions::::unpack(&new_mint_data)?; + + // check accounts are actually accounts + let original_account_data = original_account_info.try_borrow_data()?; + let original_account = StateWithExtensions::::unpack(&original_account_data)?; + let new_escrow_data = new_escrow_info.try_borrow_data()?; + let new_escrow = StateWithExtensions::::unpack(&new_escrow_data)?; + let new_account_data = new_account_info.try_borrow_data()?; + let _ = StateWithExtensions::::unpack(&new_account_data)?; + + let token_amount = original_account.base.amount; + if new_escrow.base.amount < token_amount { + msg!( + "Escrow only has {} tokens, needs at least {}", + new_escrow.base.amount, + token_amount + ); + return Err(ProgramError::InsufficientFunds); + } + if original_mint.base.decimals != new_mint.base.decimals { + msg!( + "Original and new token mint decimals mismatch: original has {} decimals, and new has {}", + original_mint.base.decimals, + new_mint.base.decimals, + ); + return Err(TokenUpgradeError::DecimalsMismatch.into()); + } + + (original_account.base.amount, original_mint.base.decimals) + }; + + burn_original_tokens( + original_token_program.clone(), + original_account_info.clone(), + original_mint_info.clone(), + original_transfer_authority_info.clone(), + account_info_iter.as_slice(), + token_amount, + decimals, + )?; + + transfer_new_tokens( + new_token_program.clone(), + new_escrow_info.clone(), + new_mint_info.clone(), + new_account_info.clone(), + new_transfer_authority_info.clone(), + &authority_seeds, + token_amount, + decimals, + )?; + + Ok(()) +} + +/// Instruction processor +pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult { + match decode_instruction_type(input)? { + TokenUpgradeInstruction::Exchange => process_exchange(program_id, accounts), + } +} diff --git a/token-upgrade/program/tests/functional.rs b/token-upgrade/program/tests/functional.rs new file mode 100644 index 00000000000..3938f9f65ec --- /dev/null +++ b/token-upgrade/program/tests/functional.rs @@ -0,0 +1,413 @@ +// Mark this test as SBF-only due to current `ProgramTest` limitations when +// CPIing into the system program +#![cfg(feature = "test-sbf")] + +use { + solana_program_test::{ + processor, + tokio::{self, sync::Mutex}, + ProgramTest, ProgramTestContext, + }, + solana_sdk::{ + instruction::{AccountMeta, InstructionError}, + pubkey::Pubkey, + signature::Signer, + signer::keypair::Keypair, + transaction::{Transaction, TransactionError}, + }, + spl_token_client::{ + client::{ + ProgramBanksClient, ProgramBanksClientProcessTransaction, ProgramClient, + SendTransaction, SimulateTransaction, + }, + token::Token, + }, + spl_token_upgrade::{ + error::TokenUpgradeError, get_token_upgrade_authority_address, instruction::exchange, + }, + std::sync::Arc, + test_case::test_case, +}; + +fn keypair_clone(kp: &Keypair) -> Keypair { + Keypair::from_bytes(&kp.to_bytes()).expect("failed to copy keypair") +} + +async fn setup() -> ( + Arc>, + Arc>, + Arc, +) { + let mut program_test = ProgramTest::new( + "spl_token_upgrade", + spl_token_upgrade::id(), + processor!(spl_token_upgrade::processor::process), + ); + + program_test.prefer_bpf(false); // simplicity in the build + + program_test.add_program( + "spl_token_2022", + spl_token_2022::id(), + processor!(spl_token_2022::processor::Processor::process), + ); + program_test.add_program( + "spl_token", + spl_token::id(), + processor!(spl_token::processor::Processor::process), + ); + + let context = program_test.start_with_context().await; + let payer = Arc::new(keypair_clone(&context.payer)); + let context = Arc::new(Mutex::new(context)); + + let client: Arc> = + Arc::new(ProgramBanksClient::new_from_context( + Arc::clone(&context), + ProgramBanksClientProcessTransaction, + )); + (context, client, payer) +} + +async fn setup_mint( + program_id: &Pubkey, + mint_authority: &Pubkey, + decimals: u8, + payer: Arc, + client: Arc>, +) -> Token { + let mint_account = Keypair::new(); + let token = Token::new( + client, + program_id, + &mint_account.pubkey(), + Some(decimals), + payer, + ); + token + .create_mint(mint_authority, None, vec![], &[&mint_account]) + .await + .unwrap(); + token +} + +#[test_case(spl_token::id(), spl_token_2022::id() ; "upgrade to token-2022")] +#[test_case(spl_token_2022::id(), spl_token::id() ; "downgrade to token")] +#[test_case(spl_token::id(), spl_token::id() ; "token to token")] +#[test_case(spl_token_2022::id(), spl_token_2022::id() ; "token-2022 to token-2022")] +#[tokio::test] +async fn success(original_program_id: Pubkey, new_program_id: Pubkey) { + let (context, client, payer) = setup().await; + + let wallet = Keypair::new(); + let mint_authority = Keypair::new(); + let mint_authority_pubkey = mint_authority.pubkey(); + + let decimals = 2; + let original_token = setup_mint( + &original_program_id, + &mint_authority_pubkey, + decimals, + payer.clone(), + client.clone(), + ) + .await; + let new_token = setup_mint( + &new_program_id, + &mint_authority_pubkey, + decimals, + payer.clone(), + client.clone(), + ) + .await; + + let program_escrow = get_token_upgrade_authority_address( + original_token.get_address(), + new_token.get_address(), + &spl_token_upgrade::id(), + ); + + original_token + .create_associated_token_account(&wallet.pubkey()) + .await + .unwrap(); + let original_account = original_token.get_associated_token_address(&wallet.pubkey()); + let token_amount = 1_000_000_000_000; + original_token + .mint_to( + &original_account, + &mint_authority_pubkey, + token_amount, + &[&mint_authority], + ) + .await + .unwrap(); + + new_token + .create_associated_token_account(&wallet.pubkey()) + .await + .unwrap(); + let new_account = new_token.get_associated_token_address(&wallet.pubkey()); + new_token + .create_associated_token_account(&program_escrow) + .await + .unwrap(); + let escrow_account = new_token.get_associated_token_address(&program_escrow); + new_token + .mint_to( + &escrow_account, + &mint_authority_pubkey, + token_amount, + &[&mint_authority], + ) + .await + .unwrap(); + + { + let context = context.lock().await; + let transaction = Transaction::new_signed_with_payer( + &[exchange( + &spl_token_upgrade::id(), + &original_account, + original_token.get_address(), + &escrow_account, + &new_account, + new_token.get_address(), + &original_program_id, + &new_program_id, + &wallet.pubkey(), + &[], + )], + Some(&context.payer.pubkey()), + &[&context.payer, &wallet], + context.last_blockhash, + ); + context + .banks_client + .process_transaction(transaction) + .await + .unwrap(); + } + + let original_mint = original_token.get_mint_info().await.unwrap(); + assert_eq!(original_mint.base.supply, 0); + let original_account_info = original_token + .get_account_info(&original_account) + .await + .unwrap(); + assert_eq!(original_account_info.base.amount, 0); + let new_account_info = new_token.get_account_info(&new_account).await.unwrap(); + assert_eq!(new_account_info.base.amount, token_amount); + let escrow_info = new_token.get_account_info(&escrow_account).await.unwrap(); + assert_eq!(escrow_info.base.amount, 0); +} + +#[test_case(spl_token::id(), spl_token_2022::id() ; "fail upgrade to token-2022")] +#[tokio::test] +async fn fail_incorrect_escrow_derivation(original_program_id: Pubkey, new_program_id: Pubkey) { + let (context, client, payer) = setup().await; + + let wallet = Keypair::new(); + let mint_authority = Keypair::new(); + let mint_authority_pubkey = mint_authority.pubkey(); + + let decimals = 2; + let original_token = setup_mint( + &original_program_id, + &mint_authority_pubkey, + decimals, + payer.clone(), + client.clone(), + ) + .await; + let new_token = setup_mint( + &new_program_id, + &mint_authority_pubkey, + decimals, + payer.clone(), + client.clone(), + ) + .await; + + // backwards derivation + let program_escrow = get_token_upgrade_authority_address( + new_token.get_address(), + original_token.get_address(), + &spl_token_upgrade::id(), + ); + + original_token + .create_associated_token_account(&wallet.pubkey()) + .await + .unwrap(); + let original_account = original_token.get_associated_token_address(&wallet.pubkey()); + let token_amount = 1_000_000_000_000; + original_token + .mint_to( + &original_account, + &mint_authority_pubkey, + token_amount, + &[&mint_authority], + ) + .await + .unwrap(); + + new_token + .create_associated_token_account(&wallet.pubkey()) + .await + .unwrap(); + let new_account = new_token.get_associated_token_address(&wallet.pubkey()); + new_token + .create_associated_token_account(&program_escrow) + .await + .unwrap(); + let escrow_account = new_token.get_associated_token_address(&program_escrow); + new_token + .mint_to( + &escrow_account, + &mint_authority_pubkey, + token_amount, + &[&mint_authority], + ) + .await + .unwrap(); + + let mut instruction = exchange( + &spl_token_upgrade::id(), + &original_account, + original_token.get_address(), + &escrow_account, + &new_account, + new_token.get_address(), + &original_program_id, + &new_program_id, + &wallet.pubkey(), + &[], + ); + instruction.accounts[5] = AccountMeta::new_readonly(program_escrow, false); + let context = context.lock().await; + let transaction = Transaction::new_signed_with_payer( + &[instruction], + Some(&context.payer.pubkey()), + &[&context.payer, &wallet], + context.last_blockhash, + ); + let error = context + .banks_client + .process_transaction(transaction) + .await + .unwrap_err() + .unwrap(); + assert_eq!( + error, + TransactionError::InstructionError( + 0, + InstructionError::Custom(TokenUpgradeError::InvalidOwner as u32) + ) + ); +} + +#[test_case(spl_token::id(), spl_token_2022::id() ; "fail upgrade to token-2022")] +#[tokio::test] +async fn fail_decimals_mismatch(original_program_id: Pubkey, new_program_id: Pubkey) { + let (context, client, payer) = setup().await; + + let wallet = Keypair::new(); + let mint_authority = Keypair::new(); + let mint_authority_pubkey = mint_authority.pubkey(); + + // different decimals + let original_decimals = 2; + let new_decimals = 3; + + let original_token = setup_mint( + &original_program_id, + &mint_authority_pubkey, + original_decimals, + payer.clone(), + client.clone(), + ) + .await; + let new_token = setup_mint( + &new_program_id, + &mint_authority_pubkey, + new_decimals, + payer.clone(), + client.clone(), + ) + .await; + + let program_escrow = get_token_upgrade_authority_address( + original_token.get_address(), + new_token.get_address(), + &spl_token_upgrade::id(), + ); + + original_token + .create_associated_token_account(&wallet.pubkey()) + .await + .unwrap(); + let original_account = original_token.get_associated_token_address(&wallet.pubkey()); + let token_amount = 1_000_000_000_000; + original_token + .mint_to( + &original_account, + &mint_authority_pubkey, + token_amount, + &[&mint_authority], + ) + .await + .unwrap(); + + new_token + .create_associated_token_account(&wallet.pubkey()) + .await + .unwrap(); + let new_account = new_token.get_associated_token_address(&wallet.pubkey()); + new_token + .create_associated_token_account(&program_escrow) + .await + .unwrap(); + let escrow_account = new_token.get_associated_token_address(&program_escrow); + new_token + .mint_to( + &escrow_account, + &mint_authority_pubkey, + token_amount, + &[&mint_authority], + ) + .await + .unwrap(); + + let context = context.lock().await; + let transaction = Transaction::new_signed_with_payer( + &[exchange( + &spl_token_upgrade::id(), + &original_account, + original_token.get_address(), + &escrow_account, + &new_account, + new_token.get_address(), + &original_program_id, + &new_program_id, + &wallet.pubkey(), + &[], + )], + Some(&context.payer.pubkey()), + &[&context.payer, &wallet], + context.last_blockhash, + ); + let error = context + .banks_client + .process_transaction(transaction) + .await + .unwrap_err() + .unwrap(); + assert_eq!( + error, + TransactionError::InstructionError( + 0, + InstructionError::Custom(TokenUpgradeError::DecimalsMismatch as u32) + ) + ); +} diff --git a/token-wrap/program/Cargo.toml b/token-wrap/program/Cargo.toml new file mode 100644 index 00000000000..9fd8596ca3f --- /dev/null +++ b/token-wrap/program/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "spl-token-wrap" +version = "0.1.0" +description = "Solana Program Library Token Wrap" +authors = ["Solana Maintainers "] +repository = "https://github.com/solana-labs/solana-program-library" +license = "Apache-2.0" +edition = "2018" + +[features] +no-entrypoint = [] +test-sbf = [] + +[dependencies] +bytemuck = { version = "1.21.0", features = ["derive"] } +num_enum = "0.7" +solana-program = "2.1.0" +spl-associated-token-account = { version = "6.0.0", features = ["no-entrypoint"] } +spl-token = { version = "7.0", features = ["no-entrypoint"] } +spl-token-2022 = { version = "6.0.0", features = ["no-entrypoint"] } +thiserror = "2.0" + +[lib] +crate-type = ["cdylib", "lib"] + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[lints] +workspace = true diff --git a/token-wrap/program/src/entrypoint.rs b/token-wrap/program/src/entrypoint.rs new file mode 100644 index 00000000000..62a02f2a465 --- /dev/null +++ b/token-wrap/program/src/entrypoint.rs @@ -0,0 +1,14 @@ +//! Program entrypoint + +#![cfg(all(target_os = "solana", not(feature = "no-entrypoint")))] + +use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey}; + +solana_program::entrypoint!(process_instruction); +fn process_instruction( + program_id: &Pubkey, + accounts: &[AccountInfo], + instruction_data: &[u8], +) -> ProgramResult { + crate::processor::process_instruction(program_id, accounts, instruction_data) +} diff --git a/token-wrap/program/src/instruction.rs b/token-wrap/program/src/instruction.rs new file mode 100644 index 00000000000..bca604a95e6 --- /dev/null +++ b/token-wrap/program/src/instruction.rs @@ -0,0 +1,81 @@ +//! Program instructions + +use num_enum::{IntoPrimitive, TryFromPrimitive}; + +/// Instructions supported by the Token Wrap program +#[derive(Clone, Debug, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(u8)] +pub enum TokenWrapInstruction { + /// Create a wrapped token mint + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writeable,signer]` Funding account for mint and backpointer (must + /// be a system account) + /// 1. `[writeable]` Unallocated wrapped mint account to create, address + /// must be: `get_wrapped_mint_address(unwrapped_mint_address, + /// wrapped_token_program_id)` + /// 2. `[writeable]` Unallocated wrapped backpointer account to create + /// `get_wrapped_mint_backpointer_address(wrapped_mint_address)` + /// 3. `[]` Existing unwrapped mint + /// 4. `[]` System program + /// 5. `[]` SPL Token program for wrapped mint + /// + /// Data expected by this instruction: + /// * bool: true = idempotent creation, false = non-idempotent creation + CreateMint, + + /// Wrap tokens + /// + /// Move a user's unwrapped tokens into an escrow account and mint the same + /// number of wrapped tokens into the provided account. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writeable]` Unwrapped token account to wrap + /// 1. `[writeable]` Escrow of unwrapped tokens, must be owned by: + /// `get_wrapped_mint_authority(wrapped_mint_address)` + /// 2. `[]` Unwrapped token mint + /// 3. `[writeable]` Wrapped mint, must be initialized, address must be: + /// `get_wrapped_mint_address(unwrapped_mint_address, + /// wrapped_token_program_id)` + /// 4. `[writeable]` Recipient wrapped token account + /// 5. `[]` Escrow mint authority, address must be: + /// `get_wrapped_mint_authority(wrapped_mint)` + /// 6. `[]` SPL Token program for unwrapped mint + /// 7. `[]` SPL Token program for wrapped mint + /// 8. `[signer]` Transfer authority on unwrapped token account + /// 9. ..8+M. `[signer]` (Optional) M multisig signers on unwrapped token + /// account + /// + /// Data expected by this instruction: + /// * little-endian u64 representing the amount to wrap + Wrap, + + /// Unwrap tokens + /// + /// Burn user wrapped tokens and transfer the same amount of unwrapped + /// tokens from the escrow account to the provided account. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writeable]` Wrapped token account to unwrap + /// 1. `[writeable]` Wrapped mint, address must be: + /// `get_wrapped_mint_address(unwrapped_mint_address, + /// wrapped_token_program_id)` + /// 2. `[writeable]` Escrow of unwrapped tokens, must be owned by: + /// `get_wrapped_mint_authority(wrapped_mint_address)` + /// 3. `[writeable]` Recipient unwrapped tokens + /// 4. `[]` Unwrapped token mint + /// 5. `[]` Escrow unwrapped token authority + /// `get_wrapped_mint_authority(wrapped_mint)` + /// 6. `[]` SPL Token program for wrapped mint + /// 7. `[]` SPL Token program for unwrapped mint + /// 8. `[signer]` Transfer authority on wrapped token account + /// 9. ..8+M. `[signer]` (Optional) M multisig signers on wrapped token + /// account + /// + /// Data expected by this instruction: + /// * little-endian u64 representing the amount to unwrap + Unwrap, +} diff --git a/token-wrap/program/src/lib.rs b/token-wrap/program/src/lib.rs new file mode 100644 index 00000000000..79fda0836c2 --- /dev/null +++ b/token-wrap/program/src/lib.rs @@ -0,0 +1,116 @@ +//! Token Wrap program +#![deny(missing_docs)] +#![forbid(unsafe_code)] + +mod entrypoint; +pub mod instruction; +pub mod processor; +pub mod state; + +// Export current SDK types for downstream users building with a different SDK +// version +pub use solana_program; +use solana_program::pubkey::Pubkey; + +solana_program::declare_id!("TwRapQCDhWkZRrDaHfZGuHxkZ91gHDRkyuzNqeU5MgR"); + +const WRAPPED_MINT_SEED: &[u8] = br"mint"; + +pub(crate) fn get_wrapped_mint_address_with_seed( + unwrapped_mint: &Pubkey, + wrapped_token_program_id: &Pubkey, +) -> (Pubkey, u8) { + Pubkey::find_program_address( + &get_wrapped_mint_seeds(unwrapped_mint, wrapped_token_program_id), + &id(), + ) +} + +pub(crate) fn get_wrapped_mint_seeds<'a>( + unwrapped_mint: &'a Pubkey, + wrapped_token_program_id: &'a Pubkey, +) -> [&'a [u8]; 3] { + [ + WRAPPED_MINT_SEED, + unwrapped_mint.as_ref(), + wrapped_token_program_id.as_ref(), + ] +} + +pub(crate) fn _get_wrapped_mint_signer_seeds<'a>( + unwrapped_mint: &'a Pubkey, + wrapped_token_program_id: &'a Pubkey, + bump_seed: &'a [u8], +) -> [&'a [u8]; 4] { + [ + WRAPPED_MINT_SEED, + unwrapped_mint.as_ref(), + wrapped_token_program_id.as_ref(), + bump_seed, + ] +} + +/// Derive the SPL Token wrapped mint address associated with an unwrapped mint +pub fn get_wrapped_mint_address( + unwrapped_mint: &Pubkey, + wrapped_token_program_id: &Pubkey, +) -> Pubkey { + get_wrapped_mint_address_with_seed(unwrapped_mint, wrapped_token_program_id).0 +} + +const WRAPPED_MINT_AUTHORITY_SEED: &[u8] = br"authority"; + +pub(crate) fn get_wrapped_mint_authority_seeds(wrapped_mint: &Pubkey) -> [&[u8]; 2] { + [WRAPPED_MINT_AUTHORITY_SEED, wrapped_mint.as_ref()] +} + +pub(crate) fn _get_wrapped_mint_authority_signer_seeds<'a>( + wrapped_mint: &'a Pubkey, + bump_seed: &'a [u8], +) -> [&'a [u8]; 3] { + [ + WRAPPED_MINT_AUTHORITY_SEED, + wrapped_mint.as_ref(), + bump_seed, + ] +} + +pub(crate) fn get_wrapped_mint_authority_with_seed(wrapped_mint: &Pubkey) -> (Pubkey, u8) { + Pubkey::find_program_address(&get_wrapped_mint_authority_seeds(wrapped_mint), &id()) +} + +/// Derive the SPL Token wrapped mint authority address +pub fn get_wrapped_mint_authority(wrapped_mint: &Pubkey) -> Pubkey { + get_wrapped_mint_authority_with_seed(wrapped_mint).0 +} + +const WRAPPED_MINT_BACKPOINTER_SEED: &[u8] = br"backpointer"; + +pub(crate) fn get_wrapped_mint_backpointer_address_seeds(wrapped_mint: &Pubkey) -> [&[u8]; 2] { + [WRAPPED_MINT_BACKPOINTER_SEED, wrapped_mint.as_ref()] +} + +pub(crate) fn _get_wrapped_mint_backpointer_address_signer_seeds<'a>( + wrapped_mint: &'a Pubkey, + bump_seed: &'a [u8], +) -> [&'a [u8]; 3] { + [ + WRAPPED_MINT_BACKPOINTER_SEED, + wrapped_mint.as_ref(), + bump_seed, + ] +} + +pub(crate) fn get_wrapped_mint_backpointer_address_with_seed( + wrapped_mint: &Pubkey, +) -> (Pubkey, u8) { + Pubkey::find_program_address( + &get_wrapped_mint_backpointer_address_seeds(wrapped_mint), + &id(), + ) +} + +/// Derive the SPL Token wrapped mint backpointer address +pub fn get_wrapped_mint_backpointer_address(wrapped_mint: &Pubkey) -> Pubkey { + get_wrapped_mint_backpointer_address_with_seed(wrapped_mint).0 +} diff --git a/token-wrap/program/src/processor.rs b/token-wrap/program/src/processor.rs new file mode 100644 index 00000000000..bb0cf1a7eea --- /dev/null +++ b/token-wrap/program/src/processor.rs @@ -0,0 +1,26 @@ +//! Program state processor + +use { + crate::instruction::TokenWrapInstruction, + solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey}, + spl_token_2022::instruction::decode_instruction_type, +}; + +/// Instruction processor +pub fn process_instruction( + _program_id: &Pubkey, + _accounts: &[AccountInfo], + input: &[u8], +) -> ProgramResult { + match decode_instruction_type(input)? { + TokenWrapInstruction::CreateMint => { + unimplemented!(); + } + TokenWrapInstruction::Wrap => { + unimplemented!(); + } + TokenWrapInstruction::Unwrap => { + unimplemented!(); + } + } +} diff --git a/token-wrap/program/src/state.rs b/token-wrap/program/src/state.rs new file mode 100644 index 00000000000..977c34d6e07 --- /dev/null +++ b/token-wrap/program/src/state.rs @@ -0,0 +1,24 @@ +//! Program state + +use { + bytemuck::{Pod, Zeroable}, + solana_program::pubkey::Pubkey, +}; + +/// Backpointer +/// +/// Since the backpointer account address is derived from the wrapped mint, it +/// allows clients to easily work with wrapped tokens. +/// +/// Try to fetch the account at `get_wrapped_mint_backpointer_address`. +/// * if it doesn't exist, then the token is not wrapped +/// * if it exists, read the data in the account as the unwrapped mint address +/// +/// With this info, clients can easily unwrap tokens, even if they don't know +/// the origin. +#[derive(Copy, Clone, Debug, PartialEq, Pod, Zeroable)] +#[repr(transparent)] +pub struct Backpointer { + /// Address that the wrapped mint is wrapping + pub unwrapped_mint: Pubkey, +} diff --git a/token/.gitignore b/token/.gitignore deleted file mode 100644 index 2a77c909079..00000000000 --- a/token/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/twoxtx-solana/ diff --git a/token/README.md b/token/README.md index c7fcfa98d54..e2e43253970 100644 --- a/token/README.md +++ b/token/README.md @@ -1,10 +1,9 @@ -# Token program +NOTE: The token program is now maintained at +[solana-program/token](https://github.com/solana-program/token). -A token program on the Solana blockchain, usable for fungible and non-fungible tokens. +The token-2022 program, confidential-transfers, clients, CLI, and JS library are +maintained at +[solana-program/token-2022](https://github.com/solana-program/token-2022). -This program provides an interface and implementation that third parties can -utilize to create and use their tokens. - -Full documentation is available at https://spl.solana.com/token - -JavaScript bindings are available in the `./js` directory. +The transfer-hook interface, example program, and clients are maintained at +[solana-program/transfer-hook](https://github.com/solana-program/transfer-hook). diff --git a/token/cli/Cargo.toml b/token/cli/Cargo.toml deleted file mode 100644 index f5d35d16a24..00000000000 --- a/token/cli/Cargo.toml +++ /dev/null @@ -1,47 +0,0 @@ -[package] -authors = ["Solana Maintainers "] -description = "SPL-Token Command-line Utility" -edition = "2018" -homepage = "https://spl.solana.com/token" -license = "Apache-2.0" -name = "spl-token-cli" -repository = "https://github.com/solana-labs/solana-program-library" -version = "2.0.16" - -[build-dependencies] -walkdir = "2" - -[dependencies] -clap = "2.33.3" -console = "0.14.0" -indicatif = "0.16.2" -serde = "1.0.130" -serde_derive = "1.0.103" -serde_json = "1.0.68" -solana-account-decoder = "=1.10.33" -solana-clap-utils = "=1.10.33" -solana-cli-config = "=1.10.33" -solana-cli-output = "=1.10.33" -solana-client = "=1.10.33" -solana-logger = "=1.10.33" -solana-remote-wallet = "=1.10.33" -solana-sdk = "=1.10.33" -solana-transaction-status = "=1.10.33" -spl-token = { version = "3.3", path="../program", features = [ "no-entrypoint" ] } -spl-token-2022 = { version = "0.4", path="../program-2022", features = [ "no-entrypoint" ] } -spl-token-client = { version = "0.1", path="../client" } -spl-associated-token-account = { version = "1.0.5", path="../../associated-token-account/program", features = [ "no-entrypoint" ] } -spl-memo = { version = "3.0.1", path="../../memo/program", features = ["no-entrypoint"] } -strum = "0.24" -strum_macros = "0.24" -tokio = "1.14" - -[dev-dependencies] -solana-test-validator = "=1.10.33" -assert_cmd = "2.0.4" -serial_test = "0.8.0" -tempfile = "3.3.0" - -[[bin]] -name = "spl-token" -path = "src/main.rs" diff --git a/token/cli/README.md b/token/cli/README.md deleted file mode 100644 index b3e02be8ee0..00000000000 --- a/token/cli/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# SPL Token program command-line utility - -A basic command-line for creating and using SPL Tokens. See https://spl.solana.com/token for more details diff --git a/token/cli/build.rs b/token/cli/build.rs deleted file mode 100644 index 387204a1b33..00000000000 --- a/token/cli/build.rs +++ /dev/null @@ -1,79 +0,0 @@ -extern crate walkdir; - -use { - std::{env, path::Path, process::Command}, - walkdir::WalkDir, -}; - -fn rerun_if_changed(directory: &Path) { - let src = directory.join("src"); - let files_in_src: Vec<_> = WalkDir::new(src) - .into_iter() - .map(|entry| entry.unwrap()) - .filter(|entry| { - if !entry.file_type().is_file() { - return false; - } - true - }) - .map(|f| f.path().to_str().unwrap().to_owned()) - .collect(); - - for file in files_in_src { - if !Path::new(&file).is_file() { - panic!("{} is not a file", file); - } - println!("cargo:rerun-if-changed={}", file); - } - let toml = directory.join("Cargo.toml").to_str().unwrap().to_owned(); - println!("cargo:rerun-if-changed={}", toml); -} - -fn build_bpf(program_directory: &Path) { - let toml_file = program_directory.join("Cargo.toml"); - let toml_file = format!("{}", toml_file.display()); - let args = vec!["build-bpf", "--manifest-path", &toml_file]; - let output = Command::new("cargo") - .args(&args) - .output() - .expect("Error running cargo build-bpf"); - if let Ok(output_str) = std::str::from_utf8(&output.stdout) { - let subs = output_str.split('\n'); - for sub in subs { - println!("cargo:warning=(not a warning) {}", sub); - } - } -} - -fn main() { - let is_debug = env::var("DEBUG").map(|v| v == "true").unwrap_or(false); - let build_dependent_programs = env::var("BUILD_DEPENDENT_PROGRAMS") - .map(|v| v != "false" && v != "0") - .unwrap_or(false); - if is_debug && build_dependent_programs { - let cwd = env::current_dir().expect("Unable to get current working directory"); - let spl_token_2022_dir = cwd - .parent() - .expect("Unable to get parent directory of current working dir") - .join("program-2022"); - rerun_if_changed(&spl_token_2022_dir); - let spl_token_dir = cwd - .parent() - .expect("Unable to get parent directory of current working dir") - .join("program"); - rerun_if_changed(&spl_token_dir); - let spl_associated_token_account_dir = cwd - .parent() - .expect("Unable to get parent directory of current working dir") - .parent() - .expect("Unable to get parent directory of current working dir") - .join("associated-token-account") - .join("program"); - rerun_if_changed(&spl_associated_token_account_dir); - - build_bpf(&spl_token_dir); - build_bpf(&spl_token_2022_dir); - build_bpf(&spl_associated_token_account_dir); - } - println!("cargo:rerun-if-changed=build.rs"); -} diff --git a/token/cli/src/bench.rs b/token/cli/src/bench.rs deleted file mode 100644 index c724191ffb8..00000000000 --- a/token/cli/src/bench.rs +++ /dev/null @@ -1,496 +0,0 @@ -/// The `bench` subcommand -use { - crate::{config::Config, owner_address_arg, CommandResult, Error}, - clap::{value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand}, - solana_clap_utils::{ - input_parsers::pubkey_of_signer, - input_validators::{is_amount, is_parsable, is_valid_pubkey}, - }, - solana_client::{ - nonblocking::rpc_client::RpcClient, rpc_client::RpcClient as BlockingRpcClient, - tpu_client::TpuClient, tpu_client::TpuClientConfig, - }, - solana_remote_wallet::remote_wallet::RemoteWalletManager, - solana_sdk::{ - message::Message, native_token::Sol, program_pack::Pack, pubkey::Pubkey, signature::Signer, - system_instruction, - }, - spl_associated_token_account::*, - spl_token_2022::{ - extension::StateWithExtensions, - instruction, - state::{Account, Mint}, - }, - std::{sync::Arc, time::Instant}, -}; - -pub(crate) trait BenchSubCommand { - fn bench_subcommand(self) -> Self; -} - -impl BenchSubCommand for App<'_, '_> { - fn bench_subcommand(self) -> Self { - self.subcommand( - SubCommand::with_name("bench") - .about("Token benchmarking facilities") - .setting(AppSettings::InferSubcommands) - .setting(AppSettings::SubcommandRequiredElseHelp) - .subcommand( - SubCommand::with_name("create-accounts") - .about("Create multiple token accounts for benchmarking") - .arg( - Arg::with_name("token") - .validator(is_valid_pubkey) - .value_name("TOKEN_ADDRESS") - .takes_value(true) - .index(1) - .required(true) - .help("The token that the accounts will hold"), - ) - .arg( - Arg::with_name("n") - .validator(is_parsable::) - .value_name("N") - .takes_value(true) - .index(2) - .required(true) - .help("The number of accounts to create"), - ) - .arg(owner_address_arg()), - ) - .subcommand( - SubCommand::with_name("close-accounts") - .about("Close multiple token accounts used for benchmarking") - .arg( - Arg::with_name("token") - .validator(is_valid_pubkey) - .value_name("TOKEN_ADDRESS") - .takes_value(true) - .index(1) - .required(true) - .help("The token that the accounts held"), - ) - .arg( - Arg::with_name("n") - .validator(is_parsable::) - .value_name("N") - .takes_value(true) - .index(2) - .required(true) - .help("The number of accounts to close"), - ) - .arg(owner_address_arg()), - ) - .subcommand( - SubCommand::with_name("deposit-into") - .about("Deposit tokens into multiple accounts") - .arg( - Arg::with_name("token") - .validator(is_valid_pubkey) - .value_name("TOKEN_ADDRESS") - .takes_value(true) - .index(1) - .required(true) - .help("The token that the accounts will hold"), - ) - .arg( - Arg::with_name("n") - .validator(is_parsable::) - .value_name("N") - .takes_value(true) - .index(2) - .required(true) - .help("The number of accounts to deposit into"), - ) - .arg( - Arg::with_name("amount") - .validator(is_amount) - .value_name("TOKEN_AMOUNT") - .takes_value(true) - .index(3) - .required(true) - .help("Amount to deposit into each account, in tokens"), - ) - .arg( - Arg::with_name("from") - .long("from") - .validator(is_valid_pubkey) - .value_name("SOURCE_TOKEN_ACCOUNT_ADDRESS") - .takes_value(true) - .help("The source token account address [default: associated token account for --owner]") - ) - .arg(owner_address_arg()), - ) - .subcommand( - SubCommand::with_name("withdraw-from") - .about("Withdraw tokens from multiple accounts") - .arg( - Arg::with_name("token") - .validator(is_valid_pubkey) - .value_name("TOKEN_ADDRESS") - .takes_value(true) - .index(1) - .required(true) - .help("The token that the accounts hold"), - ) - .arg( - Arg::with_name("n") - .validator(is_parsable::) - .value_name("N") - .takes_value(true) - .index(2) - .required(true) - .help("The number of accounts to withdraw from"), - ) - .arg( - Arg::with_name("amount") - .validator(is_amount) - .value_name("TOKEN_AMOUNT") - .takes_value(true) - .index(3) - .required(true) - .help("Amount to withdraw from each account, in tokens"), - ) - .arg( - Arg::with_name("to") - .long("to") - .validator(is_valid_pubkey) - .value_name("RECIPIENT_TOKEN_ACCOUNT_ADDRESS") - .takes_value(true) - .help("The recipient token account address [default: associated token account for --owner]") - ) - .arg(owner_address_arg()), - ), - ) - } -} - -pub(crate) async fn bench_process_command( - matches: &ArgMatches<'_>, - config: &Config<'_>, - mut signers: Vec>, - wallet_manager: &mut Option>, -) -> CommandResult { - assert!(!config.sign_only); - - match matches.subcommand() { - ("create-accounts", Some(arg_matches)) => { - let token = pubkey_of_signer(arg_matches, "token", wallet_manager) - .unwrap() - .unwrap(); - let n = value_t_or_exit!(arg_matches, "n", usize); - - let (owner_signer, owner) = - config.signer_or_default(arg_matches, "owner", wallet_manager); - signers.push(owner_signer); - - command_create_accounts(config, signers, &token, n, &owner).await?; - } - ("close-accounts", Some(arg_matches)) => { - let token = pubkey_of_signer(arg_matches, "token", wallet_manager) - .unwrap() - .unwrap(); - let n = value_t_or_exit!(arg_matches, "n", usize); - let (owner_signer, owner) = - config.signer_or_default(arg_matches, "owner", wallet_manager); - signers.push(owner_signer); - - command_close_accounts(config, signers, &token, n, &owner).await?; - } - ("deposit-into", Some(arg_matches)) => { - let token = pubkey_of_signer(arg_matches, "token", wallet_manager) - .unwrap() - .unwrap(); - let n = value_t_or_exit!(arg_matches, "n", usize); - let ui_amount = value_t_or_exit!(arg_matches, "amount", f64); - let (owner_signer, owner) = - config.signer_or_default(arg_matches, "owner", wallet_manager); - signers.push(owner_signer); - let from = pubkey_of_signer(arg_matches, "from", wallet_manager).unwrap(); - command_deposit_into_or_withdraw_from( - config, signers, &token, n, &owner, ui_amount, from, true, - ) - .await?; - } - ("withdraw-from", Some(arg_matches)) => { - let token = pubkey_of_signer(arg_matches, "token", wallet_manager) - .unwrap() - .unwrap(); - let n = value_t_or_exit!(arg_matches, "n", usize); - let ui_amount = value_t_or_exit!(arg_matches, "amount", f64); - let (owner_signer, owner) = - config.signer_or_default(arg_matches, "owner", wallet_manager); - signers.push(owner_signer); - let to = pubkey_of_signer(arg_matches, "to", wallet_manager).unwrap(); - command_deposit_into_or_withdraw_from( - config, signers, &token, n, &owner, ui_amount, to, false, - ) - .await?; - } - _ => unreachable!(), - } - - Ok("".to_string()) -} - -fn get_token_address_with_seed( - program_id: &Pubkey, - token: &Pubkey, - owner: &Pubkey, - i: usize, -) -> (Pubkey, String) { - let seed = format!("{}{}", i, token)[..31].to_string(); - ( - Pubkey::create_with_seed(owner, &seed, program_id).unwrap(), - seed, - ) -} - -fn get_token_addresses_with_seed( - program_id: &Pubkey, - token: &Pubkey, - owner: &Pubkey, - n: usize, -) -> Vec<(Pubkey, String)> { - (0..n) - .map(|i| get_token_address_with_seed(program_id, token, owner, i)) - .collect() -} - -async fn get_valid_mint_program_id( - rpc_client: &RpcClient, - token: &Pubkey, -) -> Result { - let mint_account = rpc_client - .get_account(token) - .await - .map_err(|err| format!("Token mint {} does not exist: {}", token, err))?; - - StateWithExtensions::::unpack(&mint_account.data) - .map_err(|err| format!("Invalid token mint {}: {}", token, err))?; - Ok(mint_account.owner) -} - -async fn command_create_accounts( - config: &Config<'_>, - signers: Vec>, - token: &Pubkey, - n: usize, - owner: &Pubkey, -) -> Result<(), Error> { - let rpc_client = &config.rpc_client; - - println!("Scanning accounts..."); - let program_id = get_valid_mint_program_id(rpc_client, token).await?; - - let minimum_balance_for_rent_exemption = rpc_client - .get_minimum_balance_for_rent_exemption(Account::get_packed_len()) - .await?; - - let mut lamports_required = 0; - - let token_addresses_with_seed = get_token_addresses_with_seed(&program_id, token, owner, n); - let mut messages = vec![]; - for address_chunk in token_addresses_with_seed.chunks(100) { - let accounts_chunk = rpc_client - .get_multiple_accounts(&address_chunk.iter().map(|x| x.0).collect::>()) - .await?; - - for (account, (address, seed)) in accounts_chunk.iter().zip(address_chunk) { - if account.is_none() { - lamports_required += minimum_balance_for_rent_exemption; - messages.push(Message::new( - &[ - system_instruction::create_account_with_seed( - &config.fee_payer, - address, - owner, - seed, - minimum_balance_for_rent_exemption, - Account::get_packed_len() as u64, - &program_id, - ), - instruction::initialize_account(&program_id, address, token, owner)?, - ], - Some(&config.fee_payer), - )); - } - } - } - - send_messages(config, &messages, lamports_required, signers).await -} - -async fn command_close_accounts( - config: &Config<'_>, - signers: Vec>, - token: &Pubkey, - n: usize, - owner: &Pubkey, -) -> Result<(), Error> { - let rpc_client = &config.rpc_client; - - println!("Scanning accounts..."); - let program_id = get_valid_mint_program_id(rpc_client, token).await?; - - let token_addresses_with_seed = get_token_addresses_with_seed(&program_id, token, owner, n); - let mut messages = vec![]; - for address_chunk in token_addresses_with_seed.chunks(100) { - let accounts_chunk = rpc_client - .get_multiple_accounts(&address_chunk.iter().map(|x| x.0).collect::>()) - .await?; - - for (account, (address, _seed)) in accounts_chunk.iter().zip(address_chunk) { - if let Some(account) = account { - match StateWithExtensions::::unpack(&account.data) { - Ok(token_account) => { - if token_account.base.amount != 0 { - eprintln!( - "Token account {} holds a balance; unable to close it", - address, - ); - } else { - messages.push(Message::new( - &[instruction::close_account( - &program_id, - address, - owner, - owner, - &[], - )?], - Some(&config.fee_payer), - )); - } - } - Err(err) => { - eprintln!("Invalid token account {}: {}", address, err) - } - } - } - } - } - - send_messages(config, &messages, 0, signers).await -} - -#[allow(clippy::too_many_arguments)] -async fn command_deposit_into_or_withdraw_from( - config: &Config<'_>, - signers: Vec>, - token: &Pubkey, - n: usize, - owner: &Pubkey, - ui_amount: f64, - from_or_to: Option, - deposit_into: bool, -) -> Result<(), Error> { - let rpc_client = &config.rpc_client; - - println!("Scanning accounts..."); - let program_id = get_valid_mint_program_id(rpc_client, token).await?; - - let mint_info = config.get_mint_info(token, None).await?; - let from_or_to = from_or_to - .unwrap_or_else(|| get_associated_token_address_with_program_id(owner, token, &program_id)); - config.check_account(&from_or_to, Some(*token)).await?; - let amount = spl_token::ui_amount_to_amount(ui_amount, mint_info.decimals); - - let token_addresses_with_seed = get_token_addresses_with_seed(&program_id, token, owner, n); - let mut messages = vec![]; - for address_chunk in token_addresses_with_seed.chunks(100) { - let accounts_chunk = rpc_client - .get_multiple_accounts(&address_chunk.iter().map(|x| x.0).collect::>()) - .await?; - - for (account, (address, _seed)) in accounts_chunk.iter().zip(address_chunk) { - if account.is_some() { - messages.push(Message::new( - &[instruction::transfer_checked( - &program_id, - if deposit_into { &from_or_to } else { address }, - token, - if deposit_into { address } else { &from_or_to }, - owner, - &[], - amount, - mint_info.decimals, - )?], - Some(&config.fee_payer), - )); - } else { - eprintln!("Token account does not exist: {}", address) - } - } - } - - send_messages(config, &messages, 0, signers).await -} - -async fn send_messages( - config: &Config<'_>, - messages: &[Message], - mut lamports_required: u64, - signers: Vec>, -) -> Result<(), Error> { - if messages.is_empty() { - println!("Nothing to do"); - return Ok(()); - } - - let (_blockhash, fee_calculator, _last_valid_block_height) = config - .rpc_client - .get_recent_blockhash_with_commitment(config.rpc_client.commitment()) - .await? - .value; - - lamports_required += messages - .iter() - .map(|message| fee_calculator.calculate_fee(message)) - .sum::(); - - println!( - "Sending {:?} messages for ~{}", - messages.len(), - Sol(lamports_required) - ); - - crate::check_fee_payer_balance(config, lamports_required).await?; - - // TODO use async tpu client once it's available in 1.11 - let start = Instant::now(); - let rpc_client = BlockingRpcClient::new(config.rpc_client.url()); - let tpu_client = TpuClient::new( - Arc::new(rpc_client), - &config.websocket_url, - TpuClientConfig::default(), - )?; - let transaction_errors = - tpu_client.send_and_confirm_messages_with_spinner(messages, &signers)?; - for (i, transaction_error) in transaction_errors.into_iter().enumerate() { - if let Some(transaction_error) = transaction_error { - println!("Message {} failed with {:?}", i, transaction_error); - } - } - let elapsed = Instant::now().duration_since(start); - let tps = messages.len() as f64 / elapsed.as_secs_f64(); - println!( - "Average TPS: {:.2}\nElapsed time: {} seconds", - tps, - elapsed.as_secs_f64(), - ); - - let stats = config.rpc_client.get_transport_stats(); - println!("Total RPC requests: {}", stats.request_count); - println!( - "Total RPC time: {:.2} seconds", - stats.elapsed_time.as_secs_f64() - ); - if stats.rate_limited_time != std::time::Duration::default() { - println!( - "Total idle time due to RPC rate limiting: {:.2} seconds", - stats.rate_limited_time.as_secs_f64() - ); - } - - Ok(()) -} diff --git a/token/cli/src/config.rs b/token/cli/src/config.rs deleted file mode 100644 index a5a5b03049e..00000000000 --- a/token/cli/src/config.rs +++ /dev/null @@ -1,287 +0,0 @@ -use crate::Error; -use clap::ArgMatches; -use solana_clap_utils::{ - input_parsers::pubkey_of_signer, - keypair::{pubkey_from_path, signer_from_path_with_config, SignerFromPathConfig}, -}; -use solana_cli_output::OutputFormat; -use solana_client::nonblocking::rpc_client::RpcClient; -use solana_remote_wallet::remote_wallet::RemoteWalletManager; -use solana_sdk::{pubkey::Pubkey, signature::Signer}; -use spl_associated_token_account::*; -use spl_token_2022::{ - extension::StateWithExtensionsOwned, - state::{Account, Mint}, -}; -use spl_token_client::client::{ProgramClient, ProgramRpcClientSendTransaction}; -use std::{process::exit, sync::Arc}; - -#[cfg(test)] -use solana_sdk::signer::keypair::Keypair; - -pub(crate) enum KeypairOrPath { - /// Used for testing environments to avoid touching the filesystem - #[cfg(test)] - Keypair(Keypair), - /// Used for real CLI usage - Path(String), -} - -pub(crate) struct MintInfo { - pub program_id: Pubkey, - pub address: Pubkey, - pub decimals: u8, -} - -pub(crate) struct Config<'a> { - pub(crate) rpc_client: Arc, - pub(crate) program_client: Arc>, - pub(crate) websocket_url: String, - pub(crate) output_format: OutputFormat, - pub(crate) fee_payer: Pubkey, - pub(crate) default_keypair: KeypairOrPath, - pub(crate) nonce_account: Option, - pub(crate) nonce_authority: Option, - pub(crate) sign_only: bool, - pub(crate) dump_transaction_message: bool, - pub(crate) multisigner_pubkeys: Vec<&'a Pubkey>, - pub(crate) program_id: Pubkey, -} - -impl<'a> Config<'a> { - // Check if an explicit token account address was provided, otherwise - // return the associated token address for the default address. - pub(crate) async fn associated_token_address_or_override( - &self, - arg_matches: &ArgMatches<'_>, - override_name: &str, - wallet_manager: &mut Option>, - ) -> Pubkey { - let token = pubkey_of_signer(arg_matches, "token", wallet_manager).unwrap(); - self.associated_token_address_for_token_or_override( - arg_matches, - override_name, - wallet_manager, - token, - ) - .await - } - - // Check if an explicit token account address was provided, otherwise - // return the associated token address for the default address. - pub(crate) async fn associated_token_address_for_token_or_override( - &self, - arg_matches: &ArgMatches<'_>, - override_name: &str, - wallet_manager: &mut Option>, - token: Option, - ) -> Pubkey { - if let Some(address) = pubkey_of_signer(arg_matches, override_name, wallet_manager).unwrap() - { - return address; - } - - let token = token.unwrap(); - let program_id = self.get_mint_info(&token, None).await.unwrap().program_id; - self.associated_token_address_for_token_and_program( - arg_matches, - wallet_manager, - &token, - &program_id, - ) - } - - pub(crate) fn associated_token_address_for_token_and_program( - &self, - arg_matches: &ArgMatches<'_>, - wallet_manager: &mut Option>, - token: &Pubkey, - program_id: &Pubkey, - ) -> Pubkey { - let owner = self - .default_address(arg_matches, wallet_manager) - .unwrap_or_else(|e| { - eprintln!("error: {}", e); - exit(1); - }); - get_associated_token_address_with_program_id(&owner, token, program_id) - } - - // Checks if an explicit address was provided, otherwise return the default address. - pub(crate) fn pubkey_or_default( - &self, - arg_matches: &ArgMatches, - address_name: &str, - wallet_manager: &mut Option>, - ) -> Pubkey { - if address_name != "owner" { - if let Some(address) = - pubkey_of_signer(arg_matches, address_name, wallet_manager).unwrap() - { - return address; - } - } - - return self - .default_address(arg_matches, wallet_manager) - .unwrap_or_else(|e| { - eprintln!("error: {}", e); - exit(1); - }); - } - - // Checks if an explicit signer was provided, otherwise return the default signer. - pub(crate) fn signer_or_default( - &self, - arg_matches: &ArgMatches, - authority_name: &str, - wallet_manager: &mut Option>, - ) -> (Box, Pubkey) { - // If there are `--multisig-signers` on the command line, allow `NullSigner`s to - // be returned for multisig account addresses - let config = SignerFromPathConfig { - allow_null_signer: !self.multisigner_pubkeys.is_empty(), - }; - let mut load_authority = move || { - // fallback handled in default_signer() for backward compatibility - if authority_name != "owner" { - if let Some(keypair_path) = arg_matches.value_of(authority_name) { - return signer_from_path_with_config( - arg_matches, - keypair_path, - authority_name, - wallet_manager, - &config, - ); - } - } - - self.default_signer(arg_matches, wallet_manager, &config) - }; - - let authority = load_authority().unwrap_or_else(|e| { - eprintln!("error: {}", e); - exit(1); - }); - - let authority_address = authority.pubkey(); - (authority, authority_address) - } - - fn default_address( - &self, - matches: &ArgMatches, - wallet_manager: &mut Option>, - ) -> Result> { - // for backwards compatibility, check owner before cli config default - if let Some(address) = pubkey_of_signer(matches, "owner", wallet_manager).unwrap() { - return Ok(address); - } - - match &self.default_keypair { - #[cfg(test)] - KeypairOrPath::Keypair(keypair) => Ok(keypair.pubkey()), - KeypairOrPath::Path(path) => pubkey_from_path(matches, path, "default", wallet_manager), - } - } - - fn default_signer( - &self, - matches: &ArgMatches, - wallet_manager: &mut Option>, - config: &SignerFromPathConfig, - ) -> Result, Box> { - // for backwards compatibility, check owner before cli config default - if let Some(owner_path) = matches.value_of("owner") { - return signer_from_path_with_config( - matches, - owner_path, - "owner", - wallet_manager, - config, - ); - } - - match &self.default_keypair { - #[cfg(test)] - KeypairOrPath::Keypair(keypair) => { - let cloned = Keypair::from_bytes(&keypair.to_bytes()).unwrap(); - Ok(Box::new(cloned)) - } - KeypairOrPath::Path(path) => { - signer_from_path_with_config(matches, path, "default", wallet_manager, config) - } - } - } - - pub(crate) async fn get_mint_info( - &self, - mint: &Pubkey, - mint_decimals: Option, - ) -> Result { - if self.sign_only { - Ok(MintInfo { - program_id: self.program_id, - address: *mint, - decimals: mint_decimals.unwrap_or_default(), - }) - } else { - let account = self.rpc_client.get_account(mint).await?; - self.check_owner(mint, &account.owner)?; - let mint_account = StateWithExtensionsOwned::::unpack(account.data) - .map_err(|_| format!("Could not find mint account {}", mint))?; - if let Some(decimals) = mint_decimals { - if decimals != mint_account.base.decimals { - return Err(format!( - "Mint {:?} has decimals {}, not configured decimals {}", - mint, mint_account.base.decimals, decimals - ) - .into()); - } - } - Ok(MintInfo { - program_id: account.owner, - address: *mint, - decimals: mint_account.base.decimals, - }) - } - } - - pub(crate) fn check_owner(&self, account: &Pubkey, owner: &Pubkey) -> Result<(), Error> { - if self.program_id != *owner { - Err(format!( - "Account {:?} is owned by {}, not configured program id {}", - account, owner, self.program_id - ) - .into()) - } else { - Ok(()) - } - } - - pub(crate) async fn check_account( - &self, - token_account: &Pubkey, - mint_address: Option, - ) -> Result { - if !self.sign_only { - let account = self.rpc_client.get_account(token_account).await?; - let source_account = StateWithExtensionsOwned::::unpack(account.data) - .map_err(|_| format!("Could not find token account {}", token_account))?; - let source_mint = source_account.base.mint; - if let Some(mint) = mint_address { - if source_mint != mint { - return Err(format!( - "Source {:?} does not contain {:?} tokens", - token_account, mint - ) - .into()); - } - } - self.check_owner(token_account, &account.owner)?; - Ok(source_mint) - } else { - Ok(mint_address.unwrap_or_default()) - } - } -} diff --git a/token/cli/src/main.rs b/token/cli/src/main.rs deleted file mode 100644 index 40b9a4bff5c..00000000000 --- a/token/cli/src/main.rs +++ /dev/null @@ -1,4167 +0,0 @@ -#![allow(deprecated)] // TODO: Remove when SPL upgrades to Solana 1.8 -use clap::{ - crate_description, crate_name, crate_version, value_t, value_t_or_exit, App, AppSettings, Arg, - ArgMatches, SubCommand, -}; -use serde::Serialize; -use solana_account_decoder::{ - parse_token::{TokenAccountType, UiAccountState}, - UiAccountData, -}; -use solana_clap_utils::{ - fee_payer::fee_payer_arg, - input_parsers::{pubkey_of, pubkey_of_signer, pubkeys_of_multiple_signers, value_of}, - input_validators::{ - is_amount, is_amount_or_all, is_parsable, is_url_or_moniker, is_valid_pubkey, - is_valid_signer, normalize_to_url_if_moniker, - }, - keypair::{signer_from_path, CliSignerInfo}, - memo::memo_arg, - nonce::*, - offline::{self, *}, - ArgConstant, -}; -use solana_cli_output::{ - return_signers_data, CliSignOnlyData, CliSignature, OutputFormat, QuietDisplay, - ReturnSignersConfig, VerboseDisplay, -}; -use solana_client::{nonblocking::rpc_client::RpcClient, rpc_request::TokenAccountsFilter}; -use solana_remote_wallet::remote_wallet::RemoteWalletManager; -use solana_sdk::{ - commitment_config::CommitmentConfig, - instruction::Instruction, - message::Message, - native_token::*, - program_option::COption, - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - system_instruction, system_program, - transaction::Transaction, -}; -use spl_associated_token_account::{ - get_associated_token_address_with_program_id, instruction::create_associated_token_account, -}; -use spl_token_2022::{ - extension::StateWithExtensionsOwned, - instruction::*, - state::{Account, Mint, Multisig}, -}; -use spl_token_client::client::{ProgramClient, ProgramRpcClient, ProgramRpcClientSendTransaction}; -use std::{ - collections::HashMap, fmt::Display, process::exit, str::FromStr, string::ToString, sync::Arc, -}; -use strum_macros::{EnumString, IntoStaticStr, ToString}; - -mod config; -use config::{Config, KeypairOrPath, MintInfo}; - -mod output; -use output::*; - -mod sort; -use sort::{is_supported_program, sort_and_parse_token_accounts}; - -mod bench; -use bench::*; - -pub const OWNER_ADDRESS_ARG: ArgConstant<'static> = ArgConstant { - name: "owner", - long: "owner", - help: "Address of the token's owner. Defaults to the client keypair address.", -}; - -pub const OWNER_KEYPAIR_ARG: ArgConstant<'static> = ArgConstant { - name: "owner", - long: "owner", - help: "Keypair of the token's owner. Defaults to the client keypair.", -}; - -pub const MINT_ADDRESS_ARG: ArgConstant<'static> = ArgConstant { - name: "mint_address", - long: "mint-address", - help: "Address of mint that token account is associated with. Required by --sign-only", -}; - -pub const MINT_DECIMALS_ARG: ArgConstant<'static> = ArgConstant { - name: "mint_decimals", - long: "mint-decimals", - help: "Decimals of mint that token account is associated with. Required by --sign-only", -}; - -pub const DELEGATE_ADDRESS_ARG: ArgConstant<'static> = ArgConstant { - name: "delegate_address", - long: "delegate-address", - help: "Address of delegate currently assigned to token account. Required by --sign-only", -}; - -pub const MULTISIG_SIGNER_ARG: ArgConstant<'static> = ArgConstant { - name: "multisig_signer", - long: "multisig-signer", - help: "Member signer of a multisig account", -}; - -#[derive(Debug, Clone, Copy, PartialEq, EnumString, IntoStaticStr, ToString)] -#[strum(serialize_all = "kebab-case")] -pub enum CommandName { - CreateToken, - Close, - Bench, - CreateAccount, - CreateMultisig, - Authorize, - Transfer, - Burn, - Mint, - Freeze, - Thaw, - Wrap, - Unwrap, - Approve, - Revoke, - Balance, - Supply, - Accounts, - Address, - AccountInfo, - MultisigInfo, - Gc, - SyncNative, -} - -pub fn owner_address_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name(OWNER_ADDRESS_ARG.name) - .long(OWNER_ADDRESS_ARG.long) - .takes_value(true) - .value_name("OWNER_ADDRESS") - .validator(is_valid_pubkey) - .help(OWNER_ADDRESS_ARG.help) -} - -pub fn owner_keypair_arg_with_value_name<'a, 'b>(value_name: &'static str) -> Arg<'a, 'b> { - Arg::with_name(OWNER_KEYPAIR_ARG.name) - .long(OWNER_KEYPAIR_ARG.long) - .takes_value(true) - .value_name(value_name) - .validator(is_valid_signer) - .help(OWNER_KEYPAIR_ARG.help) -} - -pub fn owner_keypair_arg<'a, 'b>() -> Arg<'a, 'b> { - owner_keypair_arg_with_value_name("OWNER_KEYPAIR") -} - -pub fn mint_address_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name(MINT_ADDRESS_ARG.name) - .long(MINT_ADDRESS_ARG.long) - .takes_value(true) - .value_name("MINT_ADDRESS") - .validator(is_valid_pubkey) - .requires(SIGN_ONLY_ARG.name) - .requires(BLOCKHASH_ARG.name) - .help(MINT_ADDRESS_ARG.help) -} - -fn is_mint_decimals(string: String) -> Result<(), String> { - is_parsable::(string) -} - -pub fn mint_decimals_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name(MINT_DECIMALS_ARG.name) - .long(MINT_DECIMALS_ARG.long) - .takes_value(true) - .value_name("MINT_DECIMALS") - .validator(is_mint_decimals) - .requires(SIGN_ONLY_ARG.name) - .requires(BLOCKHASH_ARG.name) - .help(MINT_DECIMALS_ARG.help) -} - -pub trait MintArgs { - fn mint_args(self) -> Self; -} - -impl MintArgs for App<'_, '_> { - fn mint_args(self) -> Self { - self.arg(mint_address_arg().requires(MINT_DECIMALS_ARG.name)) - .arg(mint_decimals_arg().requires(MINT_ADDRESS_ARG.name)) - } -} - -pub fn delegate_address_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name(DELEGATE_ADDRESS_ARG.name) - .long(DELEGATE_ADDRESS_ARG.long) - .takes_value(true) - .value_name("DELEGATE_ADDRESS") - .validator(is_valid_pubkey) - .requires(SIGN_ONLY_ARG.name) - .requires(BLOCKHASH_ARG.name) - .help(DELEGATE_ADDRESS_ARG.help) -} - -pub fn multisig_signer_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name(MULTISIG_SIGNER_ARG.name) - .long(MULTISIG_SIGNER_ARG.long) - .validator(is_valid_signer) - .value_name("MULTISIG_SIGNER") - .takes_value(true) - .multiple(true) - .min_values(0u64) - .max_values(MAX_SIGNERS as u64) - .help(MULTISIG_SIGNER_ARG.help) -} - -fn is_multisig_minimum_signers(string: String) -> Result<(), String> { - let v = u8::from_str(&string).map_err(|e| e.to_string())? as usize; - if v < MIN_SIGNERS { - Err(format!("must be at least {}", MIN_SIGNERS)) - } else if v > MAX_SIGNERS { - Err(format!("must be at most {}", MAX_SIGNERS)) - } else { - Ok(()) - } -} - -pub(crate) type Error = Box; - -type BulkSigners = Vec>; -pub(crate) type CommandResult = Result; - -fn new_throwaway_signer() -> (Box, Pubkey) { - let keypair = Keypair::new(); - let pubkey = keypair.pubkey(); - (Box::new(keypair) as Box, pubkey) -} - -fn get_signer( - matches: &ArgMatches<'_>, - keypair_name: &str, - wallet_manager: &mut Option>, -) -> Option<(Box, Pubkey)> { - matches.value_of(keypair_name).map(|path| { - let signer = - signer_from_path(matches, path, keypair_name, wallet_manager).unwrap_or_else(|e| { - eprintln!("error: {}", e); - exit(1); - }); - let signer_pubkey = signer.pubkey(); - (signer, signer_pubkey) - }) -} - -pub(crate) async fn check_fee_payer_balance( - config: &Config<'_>, - required_balance: u64, -) -> Result<(), Error> { - let balance = config.rpc_client.get_balance(&config.fee_payer).await?; - if balance < required_balance { - Err(format!( - "Fee payer, {}, has insufficient balance: {} required, {} available", - config.fee_payer, - lamports_to_sol(required_balance), - lamports_to_sol(balance) - ) - .into()) - } else { - Ok(()) - } -} - -async fn check_wallet_balance( - config: &Config<'_>, - wallet: &Pubkey, - required_balance: u64, -) -> Result<(), Error> { - let balance = config.rpc_client.get_balance(wallet).await?; - if balance < required_balance { - Err(format!( - "Wallet {}, has insufficient balance: {} required, {} available", - wallet, - lamports_to_sol(required_balance), - lamports_to_sol(balance) - ) - .into()) - } else { - Ok(()) - } -} - -type SignersOf = Vec<(Box, Pubkey)>; -pub fn signers_of( - matches: &ArgMatches<'_>, - name: &str, - wallet_manager: &mut Option>, -) -> Result, Box> { - if let Some(values) = matches.values_of(name) { - let mut results = Vec::new(); - for (i, value) in values.enumerate() { - let name = format!("{}-{}", name, i + 1); - let signer = signer_from_path(matches, value, &name, wallet_manager)?; - let signer_pubkey = signer.pubkey(); - results.push((signer, signer_pubkey)); - } - Ok(Some(results)) - } else { - Ok(None) - } -} - -#[allow(clippy::too_many_arguments)] -async fn command_create_token( - config: &Config<'_>, - decimals: u8, - token: Pubkey, - authority: Pubkey, - enable_freeze: bool, - memo: Option, - bulk_signers: Vec>, -) -> CommandResult { - println_display(config, format!("Creating token {}", token)); - - let minimum_balance_for_rent_exemption = if !config.sign_only { - config - .program_client - .get_minimum_balance_for_rent_exemption(Mint::LEN) - .await? - } else { - 0 - }; - let freeze_authority_pubkey = if enable_freeze { Some(authority) } else { None }; - - let mut instructions = vec![ - system_instruction::create_account( - &config.fee_payer, - &token, - minimum_balance_for_rent_exemption, - Mint::LEN as u64, - &config.program_id, - ), - initialize_mint( - &config.program_id, - &token, - &authority, - freeze_authority_pubkey.as_ref(), - decimals, - )?, - ]; - if let Some(text) = memo { - instructions.push(spl_memo::build_memo(text.as_bytes(), &[&config.fee_payer])); - } - - let tx_return = handle_tx( - &CliSignerInfo { - signers: bulk_signers, - }, - config, - false, - minimum_balance_for_rent_exemption, - instructions, - ) - .await?; - - Ok(match tx_return { - TransactionReturnData::CliSignature(cli_signature) => format_output( - CliMint { - address: token.to_string(), - decimals, - transaction_data: cli_signature, - }, - &CommandName::CreateToken, - config, - ), - TransactionReturnData::CliSignOnlyData(cli_sign_only_data) => { - format_output(cli_sign_only_data, &CommandName::CreateToken, config) - } - }) -} - -async fn command_create_account( - config: &Config<'_>, - token: Pubkey, - owner: Pubkey, - maybe_account: Option, - bulk_signers: Vec>, -) -> CommandResult { - let minimum_balance_for_rent_exemption = if !config.sign_only { - config - .program_client - .get_minimum_balance_for_rent_exemption(Account::LEN) - .await? - } else { - 0 - }; - - let mint_info = config.get_mint_info(&token, None).await?; - let (account, system_account_ok, instructions) = if let Some(account) = maybe_account { - println_display(config, format!("Creating account {}", account)); - ( - account, - false, - vec![ - system_instruction::create_account( - &config.fee_payer, - &account, - minimum_balance_for_rent_exemption, - Account::LEN as u64, - &mint_info.program_id, - ), - initialize_account(&mint_info.program_id, &account, &token, &owner)?, - ], - ) - } else { - let account = - get_associated_token_address_with_program_id(&owner, &token, &mint_info.program_id); - println_display(config, format!("Creating account {}", account)); - ( - account, - true, - vec![create_associated_token_account( - &config.fee_payer, - &owner, - &token, - &mint_info.program_id, - )], - ) - }; - - if !config.sign_only { - if let Some(account_data) = config - .rpc_client - .get_account_with_commitment(&account, config.rpc_client.commitment()) - .await? - .value - { - if !(account_data.owner == system_program::id() && system_account_ok) { - return Err(format!("Error: Account already exists: {}", account).into()); - } - } - } - - let tx_return = handle_tx( - &CliSignerInfo { - signers: bulk_signers, - }, - config, - false, - minimum_balance_for_rent_exemption, - instructions, - ) - .await?; - - Ok(match tx_return { - TransactionReturnData::CliSignature(signature) => { - config.output_format.formatted_string(&signature) - } - TransactionReturnData::CliSignOnlyData(sign_only_data) => { - config.output_format.formatted_string(&sign_only_data) - } - }) -} - -async fn command_create_multisig( - config: &Config<'_>, - multisig: Pubkey, - minimum_signers: u8, - multisig_members: Vec, - bulk_signers: BulkSigners, -) -> CommandResult { - println_display( - config, - format!( - "Creating {}/{} multisig {}", - minimum_signers, - multisig_members.len(), - multisig - ), - ); - - let minimum_balance_for_rent_exemption = if !config.sign_only { - config - .program_client - .get_minimum_balance_for_rent_exemption(Multisig::LEN) - .await? - } else { - 0 - }; - - let instructions = vec![ - system_instruction::create_account( - &config.fee_payer, - &multisig, - minimum_balance_for_rent_exemption, - Multisig::LEN as u64, - &config.program_id, - ), - initialize_multisig( - &config.program_id, - &multisig, - multisig_members.iter().collect::>().as_slice(), - minimum_signers, - )?, - ]; - - let tx_return = handle_tx( - &CliSignerInfo { - signers: bulk_signers, - }, - config, - false, - minimum_balance_for_rent_exemption, - instructions, - ) - .await?; - Ok(match tx_return { - TransactionReturnData::CliSignature(signature) => { - config.output_format.formatted_string(&signature) - } - TransactionReturnData::CliSignOnlyData(sign_only_data) => { - config.output_format.formatted_string(&sign_only_data) - } - }) -} - -#[allow(clippy::too_many_arguments)] -async fn command_authorize( - config: &Config<'_>, - account: Pubkey, - authority_type: AuthorityType, - authority: Pubkey, - new_authority: Option, - force_authorize: bool, - bulk_signers: BulkSigners, -) -> CommandResult { - let auth_str = match authority_type { - AuthorityType::MintTokens => "mint authority", - AuthorityType::FreezeAccount => "freeze authority", - AuthorityType::AccountOwner => "owner", - AuthorityType::CloseAccount => "close account authority", - AuthorityType::CloseMint => "close mint authority", - AuthorityType::TransferFeeConfig => "transfer fee authority", - AuthorityType::WithheldWithdraw => "withdraw withheld authority", - AuthorityType::InterestRate => "interest rate authority", - }; - let (previous_authority, program_id) = if !config.sign_only { - let target_account = config.rpc_client.get_account(&account).await?; - config.check_owner(&account, &target_account.owner)?; - let program_id = target_account.owner; - let previous_authority = if let Ok(mint) = - StateWithExtensionsOwned::::unpack(target_account.data.clone()) - { - match authority_type { - AuthorityType::AccountOwner | AuthorityType::CloseAccount => Err(format!( - "Authority type `{}` not supported for SPL Token mints", - auth_str - )), - AuthorityType::MintTokens => Ok(mint.base.mint_authority), - AuthorityType::FreezeAccount => Ok(mint.base.freeze_authority), - AuthorityType::CloseMint => unimplemented!(), - AuthorityType::TransferFeeConfig => unimplemented!(), - AuthorityType::WithheldWithdraw => unimplemented!(), - AuthorityType::InterestRate => unimplemented!(), - } - } else if let Ok(token_account) = - StateWithExtensionsOwned::::unpack(target_account.data) - { - let check_associated_token_account = || -> Result<(), Error> { - let maybe_associated_token_account = get_associated_token_address_with_program_id( - &token_account.base.owner, - &token_account.base.mint, - &program_id, - ); - if account == maybe_associated_token_account - && !force_authorize - && Some(authority) != new_authority - { - Err(format!( - "Error: attempting to change the `{}` of an associated token account", - auth_str - ) - .into()) - } else { - Ok(()) - } - }; - - match authority_type { - AuthorityType::MintTokens - | AuthorityType::FreezeAccount - | AuthorityType::CloseMint - | AuthorityType::TransferFeeConfig - | AuthorityType::WithheldWithdraw - | AuthorityType::InterestRate => Err(format!( - "Authority type `{}` not supported for SPL Token accounts", - auth_str - )), - AuthorityType::AccountOwner => { - check_associated_token_account()?; - Ok(COption::Some(token_account.base.owner)) - } - AuthorityType::CloseAccount => { - check_associated_token_account()?; - Ok(COption::Some( - token_account - .base - .close_authority - .unwrap_or(token_account.base.owner), - )) - } - } - } else { - Err("Unsupported account data format".to_string()) - }?; - (previous_authority, program_id) - } else { - (COption::None, config.program_id) - }; - println_display( - config, - format!( - "Updating {}\n Current {}: {}\n New {}: {}", - account, - auth_str, - previous_authority - .map(|pubkey| pubkey.to_string()) - .unwrap_or_else(|| "disabled".to_string()), - auth_str, - new_authority - .map(|pubkey| pubkey.to_string()) - .unwrap_or_else(|| "disabled".to_string()) - ), - ); - - let instructions = vec![set_authority( - &program_id, - &account, - new_authority.as_ref(), - authority_type, - &authority, - &config.multisigner_pubkeys, - )?]; - let tx_return = handle_tx( - &CliSignerInfo { - signers: bulk_signers, - }, - config, - false, - 0, - instructions, - ) - .await?; - Ok(match tx_return { - TransactionReturnData::CliSignature(signature) => { - config.output_format.formatted_string(&signature) - } - TransactionReturnData::CliSignOnlyData(sign_only_data) => { - config.output_format.formatted_string(&sign_only_data) - } - }) -} - -async fn validate_mint(config: &Config<'_>, token: Pubkey) -> Result { - let mint = config - .rpc_client - .get_account(&token) - .await - .map_err(|_| format!("Mint account not found {:?}", token))?; - config.check_owner(&token, &mint.owner)?; - if StateWithExtensionsOwned::::unpack(mint.data).is_err() { - return Err(format!("Invalid mint account {:?}", token).into()); - } - Ok(mint.owner) -} - -#[allow(clippy::too_many_arguments)] -async fn command_transfer( - config: &Config<'_>, - token: Pubkey, - ui_amount: Option, - recipient: Pubkey, - sender: Option, - sender_owner: Pubkey, - allow_unfunded_recipient: bool, - fund_recipient: bool, - mint_decimals: Option, - recipient_is_ata_owner: bool, - use_unchecked_instruction: bool, - memo: Option, - bulk_signers: BulkSigners, - no_wait: bool, - allow_non_system_account_recipient: bool, -) -> CommandResult { - let mint_info = config.get_mint_info(&token, mint_decimals).await?; - let sender = if let Some(sender) = sender { - sender - } else { - get_associated_token_address_with_program_id(&sender_owner, &token, &mint_info.program_id) - }; - config.check_account(&sender, Some(token)).await?; - let maybe_transfer_balance = - ui_amount.map(|ui_amount| spl_token::ui_amount_to_amount(ui_amount, mint_info.decimals)); - let transfer_balance = if !config.sign_only { - let sender_token_amount = config - .rpc_client - .get_token_account_balance(&sender) - .await - .map_err(|err| { - format!( - "Error: Failed to get token balance of sender address {}: {}", - sender, err - ) - })?; - let sender_balance = sender_token_amount.amount.parse::().map_err(|err| { - format!( - "Token account {} balance could not be parsed: {}", - sender, err - ) - })?; - let transfer_balance = maybe_transfer_balance.unwrap_or(sender_balance); - println_display( - config, - format!( - "Transfer {} tokens\n Sender: {}\n Recipient: {}", - spl_token::amount_to_ui_amount(transfer_balance, mint_info.decimals), - sender, - recipient - ), - ); - - if transfer_balance > sender_balance { - return Err(format!( - "Error: Sender has insufficient funds, current balance is {}", - spl_token_2022::amount_to_ui_amount_string_trimmed( - sender_balance, - mint_info.decimals - ) - ) - .into()); - } - transfer_balance - } else { - maybe_transfer_balance.unwrap() - }; - - let mut instructions = vec![]; - - let mut recipient_token_account = recipient; - let mut minimum_balance_for_rent_exemption = 0; - - let recipient_is_token_account = if !config.sign_only { - let recipient_account_info = config - .rpc_client - .get_account_with_commitment(&recipient, config.rpc_client.commitment()) - .await? - .value - .map(|account| { - ( - account.owner == mint_info.program_id && account.data.len() == Account::LEN, - account.owner == system_program::id(), - ) - }); - if let Some((recipient_is_token_account, recipient_is_system_account)) = - recipient_account_info - { - if !recipient_is_token_account - && !recipient_is_system_account - && !allow_non_system_account_recipient - { - return Err("Error: The recipient address is not owned by the System Program. \ - Add `--allow-non-system-account-recipient` to complete the transfer. \ - ".into()); - } - } else if recipient_account_info.is_none() && !allow_unfunded_recipient { - return Err("Error: The recipient address is not funded. \ - Add `--allow-unfunded-recipient` to complete the transfer. \ - " - .into()); - } - recipient_account_info - .map(|(recipient_is_token_account, _)| recipient_is_token_account) - .unwrap_or(false) - } else { - !recipient_is_ata_owner - }; - - if !recipient_is_token_account { - recipient_token_account = get_associated_token_address_with_program_id( - &recipient, - &mint_info.address, - &mint_info.program_id, - ); - println_display( - config, - format!( - " Recipient associated token account: {}", - recipient_token_account - ), - ); - - let needs_funding = if !config.sign_only { - if let Some(recipient_token_account_data) = config - .rpc_client - .get_account_with_commitment( - &recipient_token_account, - config.rpc_client.commitment(), - ) - .await? - .value - { - if recipient_token_account_data.owner == system_program::id() { - true - } else if recipient_token_account_data.owner == mint_info.program_id { - false - } else { - return Err( - format!("Error: Unsupported recipient address: {}", recipient).into(), - ); - } - } else { - true - } - } else { - fund_recipient - }; - - if needs_funding { - if fund_recipient { - if !config.sign_only { - minimum_balance_for_rent_exemption += config - .program_client - .get_minimum_balance_for_rent_exemption(Account::LEN) - .await?; - println_display( - config, - format!( - " Funding recipient: {} ({} SOL)", - recipient_token_account, - lamports_to_sol(minimum_balance_for_rent_exemption) - ), - ); - } - instructions.push(create_associated_token_account( - &config.fee_payer, - &recipient, - &mint_info.address, - &mint_info.program_id, - )); - } else { - return Err( - "Error: Recipient's associated token account does not exist. \ - Add `--fund-recipient` to fund their account" - .into(), - ); - } - } - } - - if use_unchecked_instruction { - instructions.push(transfer( - &mint_info.program_id, - &sender, - &recipient_token_account, - &sender_owner, - &config.multisigner_pubkeys, - transfer_balance, - )?); - } else { - instructions.push(transfer_checked( - &mint_info.program_id, - &sender, - &mint_info.address, - &recipient_token_account, - &sender_owner, - &config.multisigner_pubkeys, - transfer_balance, - mint_info.decimals, - )?); - } - if let Some(text) = memo { - instructions.push(spl_memo::build_memo(text.as_bytes(), &[&config.fee_payer])); - } - let tx_return = handle_tx( - &CliSignerInfo { - signers: bulk_signers, - }, - config, - no_wait, - minimum_balance_for_rent_exemption, - instructions, - ) - .await?; - Ok(match tx_return { - TransactionReturnData::CliSignature(signature) => { - config.output_format.formatted_string(&signature) - } - TransactionReturnData::CliSignOnlyData(sign_only_data) => { - config.output_format.formatted_string(&sign_only_data) - } - }) -} - -#[allow(clippy::too_many_arguments)] -async fn command_burn( - config: &Config<'_>, - source: Pubkey, - source_owner: Pubkey, - ui_amount: f64, - mint_address: Option, - mint_decimals: Option, - use_unchecked_instruction: bool, - memo: Option, - bulk_signers: BulkSigners, -) -> CommandResult { - println_display( - config, - format!("Burn {} tokens\n Source: {}", ui_amount, source), - ); - - let mint_address = config.check_account(&source, mint_address).await?; - let mint_info = config.get_mint_info(&mint_address, mint_decimals).await?; - let amount = spl_token::ui_amount_to_amount(ui_amount, mint_info.decimals); - - let mut instructions = if use_unchecked_instruction { - vec![burn( - &mint_info.program_id, - &source, - &mint_info.address, - &source_owner, - &config.multisigner_pubkeys, - amount, - )?] - } else { - vec![burn_checked( - &mint_info.program_id, - &source, - &mint_info.address, - &source_owner, - &config.multisigner_pubkeys, - amount, - mint_info.decimals, - )?] - }; - if let Some(text) = memo { - instructions.push(spl_memo::build_memo(text.as_bytes(), &[&config.fee_payer])); - } - let tx_return = handle_tx( - &CliSignerInfo { - signers: bulk_signers, - }, - config, - false, - 0, - instructions, - ) - .await?; - Ok(match tx_return { - TransactionReturnData::CliSignature(signature) => { - config.output_format.formatted_string(&signature) - } - TransactionReturnData::CliSignOnlyData(sign_only_data) => { - config.output_format.formatted_string(&sign_only_data) - } - }) -} - -#[allow(clippy::too_many_arguments)] -async fn command_mint( - config: &Config<'_>, - token: Pubkey, - ui_amount: f64, - recipient: Pubkey, - mint_info: MintInfo, - mint_authority: Pubkey, - use_unchecked_instruction: bool, - bulk_signers: BulkSigners, -) -> CommandResult { - println_display( - config, - format!( - "Minting {} tokens\n Token: {}\n Recipient: {}", - ui_amount, token, recipient - ), - ); - - let amount = spl_token::ui_amount_to_amount(ui_amount, mint_info.decimals); - let instructions = if use_unchecked_instruction { - vec![mint_to( - &mint_info.program_id, - &token, - &recipient, - &mint_authority, - &config.multisigner_pubkeys, - amount, - )?] - } else { - vec![mint_to_checked( - &mint_info.program_id, - &token, - &recipient, - &mint_authority, - &config.multisigner_pubkeys, - amount, - mint_info.decimals, - )?] - }; - let tx_return = handle_tx( - &CliSignerInfo { - signers: bulk_signers, - }, - config, - false, - 0, - instructions, - ) - .await?; - Ok(match tx_return { - TransactionReturnData::CliSignature(signature) => { - config.output_format.formatted_string(&signature) - } - TransactionReturnData::CliSignOnlyData(sign_only_data) => { - config.output_format.formatted_string(&sign_only_data) - } - }) -} - -async fn command_freeze( - config: &Config<'_>, - account: Pubkey, - mint_address: Option, - freeze_authority: Pubkey, - bulk_signers: BulkSigners, -) -> CommandResult { - let mint_address = config.check_account(&account, mint_address).await?; - let mint_info = config.get_mint_info(&mint_address, None).await?; - - println_display( - config, - format!( - "Freezing account: {}\n Token: {}", - account, mint_info.address - ), - ); - - let instructions = vec![freeze_account( - &mint_info.program_id, - &account, - &mint_info.address, - &freeze_authority, - &config.multisigner_pubkeys, - )?]; - let tx_return = handle_tx( - &CliSignerInfo { - signers: bulk_signers, - }, - config, - false, - 0, - instructions, - ) - .await?; - Ok(match tx_return { - TransactionReturnData::CliSignature(signature) => { - config.output_format.formatted_string(&signature) - } - TransactionReturnData::CliSignOnlyData(sign_only_data) => { - config.output_format.formatted_string(&sign_only_data) - } - }) -} - -async fn command_thaw( - config: &Config<'_>, - account: Pubkey, - mint_address: Option, - freeze_authority: Pubkey, - bulk_signers: BulkSigners, -) -> CommandResult { - let mint_address = config.check_account(&account, mint_address).await?; - let mint_info = config.get_mint_info(&mint_address, None).await?; - - println_display( - config, - format!( - "Thawing account: {}\n Token: {}", - account, mint_info.address - ), - ); - - let instructions = vec![thaw_account( - &mint_info.program_id, - &account, - &mint_info.address, - &freeze_authority, - &config.multisigner_pubkeys, - )?]; - let tx_return = handle_tx( - &CliSignerInfo { - signers: bulk_signers, - }, - config, - false, - 0, - instructions, - ) - .await?; - Ok(match tx_return { - TransactionReturnData::CliSignature(signature) => { - config.output_format.formatted_string(&signature) - } - TransactionReturnData::CliSignOnlyData(sign_only_data) => { - config.output_format.formatted_string(&sign_only_data) - } - }) -} - -fn native_mint(program_id: &Pubkey) -> Result { - if program_id == &spl_token_2022::id() { - Ok(spl_token_2022::native_mint::id()) - } else if program_id == &spl_token::id() { - Ok(spl_token::native_mint::id()) - } else { - Err(format!("Error: unknown token program id {}", program_id).into()) - } -} - -async fn command_wrap( - config: &Config<'_>, - sol: f64, - wallet_address: Pubkey, - wrapped_sol_account: Option, - bulk_signers: BulkSigners, -) -> CommandResult { - let lamports = sol_to_lamports(sol); - - let native_mint = native_mint(&config.program_id)?; - let instructions = if let Some(wrapped_sol_account) = wrapped_sol_account { - println_display( - config, - format!("Wrapping {} SOL into {}", sol, wrapped_sol_account), - ); - vec![ - system_instruction::create_account( - &wallet_address, - &wrapped_sol_account, - lamports, - Account::LEN as u64, - &config.program_id, - ), - initialize_account( - &config.program_id, - &wrapped_sol_account, - &native_mint, - &wallet_address, - )?, - ] - } else { - let account = get_associated_token_address_with_program_id( - &wallet_address, - &native_mint, - &config.program_id, - ); - - if !config.sign_only { - if let Some(account_data) = config - .rpc_client - .get_account_with_commitment(&account, config.rpc_client.commitment()) - .await? - .value - { - if account_data.owner != system_program::id() { - return Err(format!("Error: Account already exists: {}", account).into()); - } - } - } - - println_display(config, format!("Wrapping {} SOL into {}", sol, account)); - vec![ - system_instruction::transfer(&wallet_address, &account, lamports), - create_associated_token_account( - &config.fee_payer, - &wallet_address, - &native_mint, - &config.program_id, - ), - ] - }; - if !config.sign_only { - check_wallet_balance(config, &wallet_address, lamports).await?; - } - let tx_return = handle_tx( - &CliSignerInfo { - signers: bulk_signers, - }, - config, - false, - 0, - instructions, - ) - .await?; - Ok(match tx_return { - TransactionReturnData::CliSignature(signature) => { - config.output_format.formatted_string(&signature) - } - TransactionReturnData::CliSignOnlyData(sign_only_data) => { - config.output_format.formatted_string(&sign_only_data) - } - }) -} - -async fn command_unwrap( - config: &Config<'_>, - wallet_address: Pubkey, - address: Option, - bulk_signers: BulkSigners, -) -> CommandResult { - let use_associated_account = address.is_none(); - let native_mint = native_mint(&config.program_id)?; - let address = address.unwrap_or_else(|| { - get_associated_token_address_with_program_id( - &wallet_address, - &native_mint, - &config.program_id, - ) - }); - println_display(config, format!("Unwrapping {}", address)); - if !config.sign_only { - let lamports = config.rpc_client.get_balance(&address).await?; - if lamports == 0 { - if use_associated_account { - return Err("No wrapped SOL in associated account; did you mean to specify an auxiliary address?".to_string().into()); - } else { - return Err(format!("No wrapped SOL in {}", address).into()); - } - } - println_display( - config, - format!(" Amount: {} SOL", lamports_to_sol(lamports)), - ); - } - println_display(config, format!(" Recipient: {}", &wallet_address)); - - let instructions = vec![close_account( - &config.program_id, - &address, - &wallet_address, - &wallet_address, - &config.multisigner_pubkeys, - )?]; - let tx_return = handle_tx( - &CliSignerInfo { - signers: bulk_signers, - }, - config, - false, - 0, - instructions, - ) - .await?; - Ok(match tx_return { - TransactionReturnData::CliSignature(signature) => { - config.output_format.formatted_string(&signature) - } - TransactionReturnData::CliSignOnlyData(sign_only_data) => { - config.output_format.formatted_string(&sign_only_data) - } - }) -} - -#[allow(clippy::too_many_arguments)] -async fn command_approve( - config: &Config<'_>, - account: Pubkey, - owner: Pubkey, - ui_amount: f64, - delegate: Pubkey, - mint_address: Option, - mint_decimals: Option, - use_unchecked_instruction: bool, - bulk_signers: BulkSigners, -) -> CommandResult { - println_display( - config, - format!( - "Approve {} tokens\n Account: {}\n Delegate: {}", - ui_amount, account, delegate - ), - ); - - let mint_address = config.check_account(&account, mint_address).await?; - let mint_info = config.get_mint_info(&mint_address, mint_decimals).await?; - let amount = spl_token::ui_amount_to_amount(ui_amount, mint_info.decimals); - - let instructions = if use_unchecked_instruction { - vec![approve( - &mint_info.program_id, - &account, - &delegate, - &owner, - &config.multisigner_pubkeys, - amount, - )?] - } else { - vec![approve_checked( - &mint_info.program_id, - &account, - &mint_info.address, - &delegate, - &owner, - &config.multisigner_pubkeys, - amount, - mint_info.decimals, - )?] - }; - let tx_return = handle_tx( - &CliSignerInfo { - signers: bulk_signers, - }, - config, - false, - 0, - instructions, - ) - .await?; - Ok(match tx_return { - TransactionReturnData::CliSignature(signature) => { - config.output_format.formatted_string(&signature) - } - TransactionReturnData::CliSignOnlyData(sign_only_data) => { - config.output_format.formatted_string(&sign_only_data) - } - }) -} - -async fn command_revoke( - config: &Config<'_>, - account: Pubkey, - owner: Pubkey, - delegate: Option, - bulk_signers: BulkSigners, -) -> CommandResult { - let (delegate, program_id) = if !config.sign_only { - let source_account = config.rpc_client.get_account(&account).await?; - let source_state = StateWithExtensionsOwned::::unpack(source_account.data) - .map_err(|_| format!("Could not deserialize token account {}", account))?; - - let delegate = if let COption::Some(delegate) = source_state.base.delegate { - Some(delegate) - } else { - None - }; - - config.check_owner(&account, &source_account.owner)?; - (delegate, source_account.owner) - } else { - (delegate, config.program_id) - }; - - if let Some(delegate) = delegate { - println_display( - config, - format!( - "Revoking approval\n Account: {}\n Delegate: {}", - account, delegate - ), - ); - } else { - return Err(format!("No delegate on account {}", account).into()); - } - - let instructions = vec![revoke( - &program_id, - &account, - &owner, - &config.multisigner_pubkeys, - )?]; - let tx_return = handle_tx( - &CliSignerInfo { - signers: bulk_signers, - }, - config, - false, - 0, - instructions, - ) - .await?; - Ok(match tx_return { - TransactionReturnData::CliSignature(signature) => { - config.output_format.formatted_string(&signature) - } - TransactionReturnData::CliSignOnlyData(sign_only_data) => { - config.output_format.formatted_string(&sign_only_data) - } - }) -} - -async fn command_close( - config: &Config<'_>, - account: Pubkey, - close_authority: Pubkey, - recipient: Pubkey, - bulk_signers: BulkSigners, -) -> CommandResult { - let (is_recipient_wrapped, program_id) = if config.sign_only { - (false, config.program_id) - } else { - let source_account = config.rpc_client.get_account(&account).await?; - let source_state = StateWithExtensionsOwned::::unpack(source_account.data) - .map_err(|_| format!("Could not deserialize token account {}", account))?; - let source_amount = source_state.base.amount; - - if !source_state.base.is_native() && source_amount > 0 { - return Err(format!( - "Account {} still has {} tokens; empty the account in order to close it.", - account, source_amount, - ) - .into()); - } - config.check_owner(&account, &source_account.owner)?; - - let recipient_account = config.rpc_client.get_token_account(&recipient).await?; - let is_recipient_wrapped = recipient_account.map(|x| x.is_native).unwrap_or(false); - (is_recipient_wrapped, source_account.owner) - }; - - let mut instructions = vec![close_account( - &program_id, - &account, - &recipient, - &close_authority, - &config.multisigner_pubkeys, - )?]; - - if is_recipient_wrapped { - instructions.push(sync_native(&program_id, &recipient)?); - } - - let tx_return = handle_tx( - &CliSignerInfo { - signers: bulk_signers, - }, - config, - false, - 0, - instructions, - ) - .await?; - Ok(match tx_return { - TransactionReturnData::CliSignature(signature) => { - config.output_format.formatted_string(&signature) - } - TransactionReturnData::CliSignOnlyData(sign_only_data) => { - config.output_format.formatted_string(&sign_only_data) - } - }) -} - -async fn command_balance(config: &Config<'_>, address: Pubkey) -> CommandResult { - let balance = config - .rpc_client - .get_token_account_balance(&address) - .await - .map_err(|_| format!("Could not find token account {}", address))?; - let cli_token_amount = CliTokenAmount { amount: balance }; - Ok(config.output_format.formatted_string(&cli_token_amount)) -} - -async fn command_supply(config: &Config<'_>, address: Pubkey) -> CommandResult { - let supply = config.rpc_client.get_token_supply(&address).await?; - let cli_token_amount = CliTokenAmount { amount: supply }; - Ok(config.output_format.formatted_string(&cli_token_amount)) -} - -async fn command_accounts( - config: &Config<'_>, - token: Option, - owner: Pubkey, -) -> CommandResult { - let program_id = if let Some(token) = token { - validate_mint(config, token).await? - } else { - config.program_id - }; - let accounts = config - .rpc_client - .get_token_accounts_by_owner( - &owner, - match token { - Some(token) => TokenAccountsFilter::Mint(token), - None => TokenAccountsFilter::ProgramId(program_id), - }, - ) - .await?; - if accounts.is_empty() { - println!("None"); - return Ok("".to_string()); - } - - let (mint_accounts, unsupported_accounts, max_len_balance, includes_aux) = - sort_and_parse_token_accounts(&owner, accounts, &program_id); - let aux_len = if includes_aux { 10 } else { 0 }; - - let cli_token_accounts = CliTokenAccounts { - accounts: mint_accounts - .into_iter() - .map(|(_mint, accounts_list)| accounts_list) - .collect(), - unsupported_accounts, - max_len_balance, - aux_len, - token_is_some: token.is_some(), - }; - Ok(config.output_format.formatted_string(&cli_token_accounts)) -} - -async fn command_address( - config: &Config<'_>, - token: Option, - owner: Pubkey, -) -> CommandResult { - let mut cli_address = CliWalletAddress { - wallet_address: owner.to_string(), - ..CliWalletAddress::default() - }; - if let Some(token) = token { - let program_id = validate_mint(config, token).await?; - let associated_token_address = - get_associated_token_address_with_program_id(&owner, &token, &program_id); - cli_address.associated_token_address = Some(associated_token_address.to_string()); - } - Ok(config.output_format.formatted_string(&cli_address)) -} - -async fn command_account_info(config: &Config<'_>, address: Pubkey) -> CommandResult { - let account = config - .rpc_client - .get_token_account(&address) - .await - .map_err(|_| format!("Could not find token account {}", address))? - .unwrap(); - let mint = Pubkey::from_str(&account.mint).unwrap(); - let owner = Pubkey::from_str(&account.owner).unwrap(); - let program_id = config.rpc_client.get_account(&address).await?.owner; - let is_associated = - get_associated_token_address_with_program_id(&owner, &mint, &program_id) == address; - let cli_token_account = CliTokenAccount { - address: address.to_string(), - is_associated, - account, - }; - Ok(config.output_format.formatted_string(&cli_token_account)) -} - -async fn get_multisig(config: &Config<'_>, address: &Pubkey) -> Result { - let account = config.rpc_client.get_account(address).await?; - Multisig::unpack(&account.data).map_err(|e| e.into()) -} - -async fn command_multisig(config: &Config<'_>, address: Pubkey) -> CommandResult { - let multisig = get_multisig(config, &address).await?; - let n = multisig.n as usize; - assert!(n <= multisig.signers.len()); - let cli_multisig = CliMultisig { - address: address.to_string(), - m: multisig.m, - n: multisig.n, - signers: multisig - .signers - .iter() - .enumerate() - .filter_map(|(i, signer)| { - if i < n { - Some(signer.to_string()) - } else { - None - } - }) - .collect(), - }; - Ok(config.output_format.formatted_string(&cli_multisig)) -} - -async fn command_gc( - config: &Config<'_>, - owner: Pubkey, - close_empty_associated_accounts: bool, - bulk_signers: BulkSigners, -) -> CommandResult { - println_display( - config, - format!( - "Fetching token accounts associated with program {}", - config.program_id - ), - ); - let accounts = config - .rpc_client - .get_token_accounts_by_owner(&owner, TokenAccountsFilter::ProgramId(config.program_id)) - .await?; - if accounts.is_empty() { - println_display(config, "Nothing to do".to_string()); - return Ok("".to_string()); - } - - let minimum_balance_for_rent_exemption = if !config.sign_only { - config - .program_client - .get_minimum_balance_for_rent_exemption(Account::LEN) - .await? - } else { - 0 - }; - - let mut accounts_by_token = HashMap::new(); - - for keyed_account in accounts { - if let UiAccountData::Json(parsed_account) = keyed_account.account.data { - if is_supported_program(&parsed_account.program) { - if let Ok(TokenAccountType::Account(ui_token_account)) = - serde_json::from_value(parsed_account.parsed) - { - let frozen = ui_token_account.state == UiAccountState::Frozen; - - let token = ui_token_account - .mint - .parse::() - .unwrap_or_else(|err| panic!("Invalid mint: {}", err)); - let token_account = keyed_account - .pubkey - .parse::() - .unwrap_or_else(|err| panic!("Invalid token account: {}", err)); - let token_amount = ui_token_account - .token_amount - .amount - .parse::() - .unwrap_or_else(|err| panic!("Invalid token amount: {}", err)); - - let close_authority = ui_token_account.close_authority.map_or(owner, |s| { - s.parse::() - .unwrap_or_else(|err| panic!("Invalid close authority: {}", err)) - }); - - let entry = accounts_by_token.entry(token).or_insert_with(HashMap::new); - entry.insert( - token_account, - ( - token_amount, - ui_token_account.token_amount.decimals, - frozen, - close_authority, - ), - ); - } - } - } - } - - let mut instructions = vec![]; - let mut lamports_needed = 0; - - for (token, accounts) in accounts_by_token.into_iter() { - println_display(config, format!("Processing token: {}", token)); - let associated_token_account = - get_associated_token_address_with_program_id(&owner, &token, &config.program_id); - let total_balance: u64 = accounts.values().map(|account| account.0).sum(); - - if total_balance > 0 && !accounts.contains_key(&associated_token_account) { - // Create the associated token account - instructions.push(vec![create_associated_token_account( - &config.fee_payer, - &owner, - &token, - &config.program_id, - )]); - lamports_needed += minimum_balance_for_rent_exemption; - } - - for (address, (amount, decimals, frozen, close_authority)) in accounts { - match ( - address == associated_token_account, - close_empty_associated_accounts, - total_balance > 0, - ) { - (true, _, true) => continue, // don't ever close associated token account with amount - (true, false, _) => continue, // don't close associated token account if close_empty_associated_accounts isn't set - (true, true, false) => println_display( - config, - format!("Closing Account {}", associated_token_account), - ), - _ => {} - } - - if frozen { - // leave frozen accounts alone - continue; - } - - let mut account_instructions = vec![]; - - // Sanity check! - // we shouldn't ever be here, but if we are here, abort! - assert!(amount == 0 || address != associated_token_account); - - if amount > 0 { - // Transfer the account balance into the associated token account - account_instructions.push(transfer_checked( - &config.program_id, - &address, - &token, - &associated_token_account, - &owner, - &config.multisigner_pubkeys, - amount, - decimals, - )?); - } - // Close the account if config.owner is able to - if close_authority == owner { - account_instructions.push(close_account( - &config.program_id, - &address, - &owner, - &owner, - &config.multisigner_pubkeys, - )?); - } - - if !account_instructions.is_empty() { - instructions.push(account_instructions); - } - } - } - - let cli_signer_info = CliSignerInfo { - signers: bulk_signers, - }; - - let mut result = String::from(""); - for tx_instructions in instructions { - let tx_return = handle_tx( - &cli_signer_info, - config, - false, - lamports_needed, - tx_instructions, - ) - .await?; - result += &match tx_return { - TransactionReturnData::CliSignature(signature) => { - config.output_format.formatted_string(&signature) - } - TransactionReturnData::CliSignOnlyData(sign_only_data) => { - config.output_format.formatted_string(&sign_only_data) - } - }; - result += "\n"; - } - Ok(result) -} - -async fn command_sync_native( - native_account_address: Pubkey, - bulk_signers: Vec>, - config: &Config<'_>, -) -> CommandResult { - let program_id = if config.sign_only { - config.program_id - } else { - config - .rpc_client - .get_account(&native_account_address) - .await - .map_err(|err| { - format!( - "Token account {} does not exist: {}", - native_account_address, err - ) - })? - .owner - }; - - let tx_return = handle_tx( - &CliSignerInfo { - signers: bulk_signers, - }, - config, - false, - 0, - vec![sync_native(&program_id, &native_account_address)?], - ) - .await?; - Ok(match tx_return { - TransactionReturnData::CliSignature(signature) => { - config.output_format.formatted_string(&signature) - } - TransactionReturnData::CliSignOnlyData(sign_only_data) => { - config.output_format.formatted_string(&sign_only_data) - } - }) -} - -struct SignOnlyNeedsFullMintSpec {} -impl offline::ArgsConfig for SignOnlyNeedsFullMintSpec { - fn sign_only_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> { - arg.requires_all(&[MINT_ADDRESS_ARG.name, MINT_DECIMALS_ARG.name]) - } -} - -struct SignOnlyNeedsMintDecimals {} -impl offline::ArgsConfig for SignOnlyNeedsMintDecimals { - fn sign_only_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> { - arg.requires_all(&[MINT_DECIMALS_ARG.name]) - } -} - -struct SignOnlyNeedsMintAddress {} -impl offline::ArgsConfig for SignOnlyNeedsMintAddress { - fn sign_only_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> { - arg.requires_all(&[MINT_ADDRESS_ARG.name]) - } -} - -struct SignOnlyNeedsDelegateAddress {} -impl offline::ArgsConfig for SignOnlyNeedsDelegateAddress { - fn sign_only_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> { - arg.requires_all(&[DELEGATE_ADDRESS_ARG.name]) - } -} - -fn minimum_signers_help_string() -> String { - format!( - "The minimum number of signers required to allow the operation. [{} <= M <= N]", - MIN_SIGNERS - ) -} - -fn multisig_member_help_string() -> String { - format!( - "The public keys for each of the N signing members of this account. [{} <= N <= {}]", - MIN_SIGNERS, MAX_SIGNERS - ) -} - -fn app<'a, 'b>( - default_decimals: &'a str, - default_program_id: &'a str, - minimum_signers_help: &'b str, - multisig_member_help: &'b str, -) -> App<'a, 'b> { - App::new(crate_name!()) - .about(crate_description!()) - .version(crate_version!()) - .setting(AppSettings::SubcommandRequiredElseHelp) - .arg({ - let arg = Arg::with_name("config_file") - .short("C") - .long("config") - .value_name("PATH") - .takes_value(true) - .global(true) - .help("Configuration file to use"); - if let Some(ref config_file) = *solana_cli_config::CONFIG_FILE { - arg.default_value(config_file) - } else { - arg - } - }) - .arg( - Arg::with_name("verbose") - .short("v") - .long("verbose") - .takes_value(false) - .global(true) - .help("Show additional information"), - ) - .arg( - Arg::with_name("output_format") - .long("output") - .value_name("FORMAT") - .global(true) - .takes_value(true) - .possible_values(&["json", "json-compact"]) - .help("Return information in specified output format"), - ) - .arg( - Arg::with_name("program_id") - .short("p") - .long("program-id") - .value_name("ADDRESS") - .takes_value(true) - .global(true) - .default_value(default_program_id) - .validator(is_valid_pubkey) - .help("SPL Token program id"), - ) - .arg( - Arg::with_name("json_rpc_url") - .short("u") - .long("url") - .value_name("URL_OR_MONIKER") - .takes_value(true) - .global(true) - .validator(is_url_or_moniker) - .help( - "URL for Solana's JSON RPC or moniker (or their first letter): \ - [mainnet-beta, testnet, devnet, localhost] \ - Default from the configuration file." - ), - ) - .arg(fee_payer_arg().global(true)) - .arg( - Arg::with_name("use_unchecked_instruction") - .long("use-unchecked-instruction") - .takes_value(false) - .global(true) - .hidden(true) - .help("Use unchecked instruction if appropriate. Supports transfer, burn, mint, and approve."), - ) - .bench_subcommand() - .subcommand(SubCommand::with_name(CommandName::CreateToken.into()).about("Create a new token") - .arg( - Arg::with_name("token_keypair") - .value_name("TOKEN_KEYPAIR") - .validator(is_valid_signer) - .takes_value(true) - .index(1) - .help( - "Specify the token keypair. \ - This may be a keypair file or the ASK keyword. \ - [default: randomly generated keypair]" - ), - ) - .arg( - Arg::with_name("mint_authority") - .long("mint-authority") - .alias("owner") - .value_name("ADDRESS") - .validator(is_valid_pubkey) - .takes_value(true) - .help( - "Specify the mint authority address. \ - Defaults to the client keypair address." - ), - ) - .arg( - Arg::with_name("decimals") - .long("decimals") - .validator(is_mint_decimals) - .value_name("DECIMALS") - .takes_value(true) - .default_value(default_decimals) - .help("Number of base 10 digits to the right of the decimal place"), - ) - .arg( - Arg::with_name("enable_freeze") - .long("enable-freeze") - .takes_value(false) - .help( - "Enable the mint authority to freeze associated token accounts." - ), - ) - .nonce_args(true) - .arg(memo_arg()) - .offline_args(), - ) - .subcommand( - SubCommand::with_name(CommandName::CreateAccount.into()) - .about("Create a new token account") - .arg( - Arg::with_name("token") - .validator(is_valid_pubkey) - .value_name("TOKEN_ADDRESS") - .takes_value(true) - .index(1) - .required(true) - .help("The token that the account will hold"), - ) - .arg( - Arg::with_name("account_keypair") - .value_name("ACCOUNT_KEYPAIR") - .validator(is_valid_signer) - .takes_value(true) - .index(2) - .help( - "Specify the account keypair. \ - This may be a keypair file or the ASK keyword. \ - [default: associated token account for --owner]" - ), - ) - .arg(owner_address_arg()) - .nonce_args(true) - .offline_args(), - ) - .subcommand( - SubCommand::with_name(CommandName::CreateMultisig.into()) - .about("Create a new account describing an M:N multisignature") - .arg( - Arg::with_name("minimum_signers") - .value_name("MINIMUM_SIGNERS") - .validator(is_multisig_minimum_signers) - .takes_value(true) - .index(1) - .required(true) - .help(minimum_signers_help), - ) - .arg( - Arg::with_name("multisig_member") - .value_name("MULTISIG_MEMBER_PUBKEY") - .validator(is_valid_pubkey) - .takes_value(true) - .index(2) - .required(true) - .min_values(MIN_SIGNERS as u64) - .max_values(MAX_SIGNERS as u64) - .help(multisig_member_help), - ) - .arg( - Arg::with_name("address_keypair") - .long("address-keypair") - .value_name("ADDRESS_KEYPAIR") - .validator(is_valid_signer) - .takes_value(true) - .help( - "Specify the address keypair. \ - This may be a keypair file or the ASK keyword. \ - [default: randomly generated keypair]" - ), - ) - .nonce_args(true) - .offline_args(), - ) - .subcommand( - SubCommand::with_name(CommandName::Authorize.into()) - .about("Authorize a new signing keypair to a token or token account") - .arg( - Arg::with_name("address") - .validator(is_valid_pubkey) - .value_name("TOKEN_ADDRESS") - .takes_value(true) - .index(1) - .required(true) - .help("The address of the token account"), - ) - .arg( - Arg::with_name("authority_type") - .value_name("AUTHORITY_TYPE") - .takes_value(true) - .possible_values(&[ - "mint", "freeze", "owner", "close", - "close-mint", "transfer-fee-config", "withheld-withdraw", - "interest-rate", - ]) - .index(2) - .required(true) - .help("The new authority type. \ - Token mints support `mint` and `freeze` authorities;\ - Token accounts support `owner` and `close` authorities."), - ) - .arg( - Arg::with_name("new_authority") - .validator(is_valid_pubkey) - .value_name("AUTHORITY_ADDRESS") - .takes_value(true) - .index(3) - .required_unless("disable") - .help("The address of the new authority"), - ) - .arg( - Arg::with_name("authority") - .long("authority") - .alias("owner") - .value_name("KEYPAIR") - .validator(is_valid_signer) - .takes_value(true) - .help( - "Specify the current authority keypair. \ - Defaults to the client keypair." - ), - ) - .arg( - Arg::with_name("disable") - .long("disable") - .takes_value(false) - .conflicts_with("new_authority") - .help("Disable mint, freeze, or close functionality by setting authority to None.") - ) - .arg( - Arg::with_name("force") - .long("force") - .hidden(true) - .help("Force re-authorize the wallet's associate token account. Don't use this flag"), - ) - .arg(multisig_signer_arg()) - .nonce_args(true) - .offline_args(), - ) - .subcommand( - SubCommand::with_name(CommandName::Transfer.into()) - .about("Transfer tokens between accounts") - .arg( - Arg::with_name("token") - .validator(is_valid_pubkey) - .value_name("TOKEN_ADDRESS") - .takes_value(true) - .index(1) - .required(true) - .help("Token to transfer"), - ) - .arg( - Arg::with_name("amount") - .validator(is_amount_or_all) - .value_name("TOKEN_AMOUNT") - .takes_value(true) - .index(2) - .required(true) - .help("Amount to send, in tokens; accepts keyword ALL"), - ) - .arg( - Arg::with_name("recipient") - .validator(is_valid_pubkey) - .value_name("RECIPIENT_ADDRESS or RECIPIENT_TOKEN_ACCOUNT_ADDRESS") - .takes_value(true) - .index(3) - .required(true) - .help("If a token account address is provided, use it as the recipient. \ - Otherwise assume the recipient address is a user wallet and transfer to \ - the associated token account") - ) - .arg( - Arg::with_name("from") - .validator(is_valid_pubkey) - .value_name("SENDER_TOKEN_ACCOUNT_ADDRESS") - .takes_value(true) - .long("from") - .help("Specify the sending token account \ - [default: owner's associated token account]") - ) - .arg(owner_keypair_arg_with_value_name("SENDER_TOKEN_OWNER_KEYPAIR") - .help( - "Specify the owner of the sending token account. \ - This may be a keypair file, the ASK keyword. \ - Defaults to the client keypair.", - ), - ) - .arg( - Arg::with_name("allow_unfunded_recipient") - .long("allow-unfunded-recipient") - .takes_value(false) - .help("Complete the transfer even if the recipient address is not funded") - ) - .arg( - Arg::with_name("allow_empty_recipient") - .long("allow-empty-recipient") - .takes_value(false) - .hidden(true) // Deprecated, use --allow-unfunded-recipient instead - ) - .arg( - Arg::with_name("fund_recipient") - .long("fund-recipient") - .takes_value(false) - .help("Create the associated token account for the recipient if doesn't already exist") - ) - .arg( - Arg::with_name("no_wait") - .long("no-wait") - .takes_value(false) - .help("Return signature immediately after submitting the transaction, instead of waiting for confirmations"), - ) - .arg( - Arg::with_name("allow_non_system_account_recipient") - .long("allow-non-system-account-recipient") - .takes_value(false) - .help("Send tokens to the recipient even if the recipient is not a wallet owned by System Program."), - ) - .arg( - Arg::with_name("recipient_is_ata_owner") - .long("recipient-is-ata-owner") - .takes_value(false) - .requires("sign_only") - .help("In sign-only mode, specifies that the recipient is the owner of the associated token account rather than an actual token account"), - ) - .arg(multisig_signer_arg()) - .arg(mint_decimals_arg()) - .nonce_args(true) - .arg(memo_arg()) - .offline_args_config(&SignOnlyNeedsMintDecimals{}), - ) - .subcommand( - SubCommand::with_name(CommandName::Burn.into()) - .about("Burn tokens from an account") - .arg( - Arg::with_name("source") - .validator(is_valid_pubkey) - .value_name("SOURCE_TOKEN_ACCOUNT_ADDRESS") - .takes_value(true) - .index(1) - .required(true) - .help("The token account address to burn from"), - ) - .arg( - Arg::with_name("amount") - .validator(is_amount) - .value_name("TOKEN_AMOUNT") - .takes_value(true) - .index(2) - .required(true) - .help("Amount to burn, in tokens"), - ) - .arg(owner_keypair_arg_with_value_name("SOURCE_TOKEN_OWNER_KEYPAIR") - .help( - "Specify the source token owner account. \ - This may be a keypair file, the ASK keyword. \ - Defaults to the client keypair.", - ), - ) - .arg(multisig_signer_arg()) - .mint_args() - .nonce_args(true) - .arg(memo_arg()) - .offline_args_config(&SignOnlyNeedsFullMintSpec{}), - ) - .subcommand( - SubCommand::with_name(CommandName::Mint.into()) - .about("Mint new tokens") - .arg( - Arg::with_name("token") - .validator(is_valid_pubkey) - .value_name("TOKEN_ADDRESS") - .takes_value(true) - .index(1) - .required(true) - .help("The token to mint"), - ) - .arg( - Arg::with_name("amount") - .validator(is_amount) - .value_name("TOKEN_AMOUNT") - .takes_value(true) - .index(2) - .required(true) - .help("Amount to mint, in tokens"), - ) - .arg( - Arg::with_name("recipient") - .validator(is_valid_pubkey) - .value_name("RECIPIENT_TOKEN_ACCOUNT_ADDRESS") - .takes_value(true) - .index(3) - .help("The token account address of recipient [default: associated token account for --owner]"), - ) - .arg( - Arg::with_name("mint_authority") - .long("mint-authority") - .alias("owner") - .value_name("KEYPAIR") - .validator(is_valid_signer) - .takes_value(true) - .help( - "Specify the mint authority keypair. \ - This may be a keypair file or the ASK keyword. \ - Defaults to the client keypair." - ), - ) - .arg(mint_decimals_arg()) - .arg(multisig_signer_arg()) - .nonce_args(true) - .offline_args_config(&SignOnlyNeedsMintDecimals{}), - ) - .subcommand( - SubCommand::with_name(CommandName::Freeze.into()) - .about("Freeze a token account") - .arg( - Arg::with_name("account") - .validator(is_valid_pubkey) - .value_name("TOKEN_ACCOUNT_ADDRESS") - .takes_value(true) - .index(1) - .required(true) - .help("The address of the token account to freeze"), - ) - .arg( - Arg::with_name("freeze_authority") - .long("freeze-authority") - .alias("owner") - .value_name("KEYPAIR") - .validator(is_valid_signer) - .takes_value(true) - .help( - "Specify the freeze authority keypair. \ - This may be a keypair file or the ASK keyword. \ - Defaults to the client keypair." - ), - ) - .arg(mint_address_arg()) - .arg(multisig_signer_arg()) - .nonce_args(true) - .offline_args_config(&SignOnlyNeedsMintAddress{}), - ) - .subcommand( - SubCommand::with_name(CommandName::Thaw.into()) - .about("Thaw a token account") - .arg( - Arg::with_name("account") - .validator(is_valid_pubkey) - .value_name("TOKEN_ACCOUNT_ADDRESS") - .takes_value(true) - .index(1) - .required(true) - .help("The address of the token account to thaw"), - ) - .arg( - Arg::with_name("freeze_authority") - .long("freeze-authority") - .alias("owner") - .value_name("KEYPAIR") - .validator(is_valid_signer) - .takes_value(true) - .help( - "Specify the freeze authority keypair. \ - This may be a keypair file or the ASK keyword. \ - Defaults to the client keypair." - ), - ) - .arg(mint_address_arg()) - .arg(multisig_signer_arg()) - .nonce_args(true) - .offline_args_config(&SignOnlyNeedsMintAddress{}), - ) - .subcommand( - SubCommand::with_name(CommandName::Wrap.into()) - .about("Wrap native SOL in a SOL token account") - .arg( - Arg::with_name("amount") - .validator(is_amount) - .value_name("AMOUNT") - .takes_value(true) - .index(1) - .required(true) - .help("Amount of SOL to wrap"), - ) - .arg( - Arg::with_name("wallet_keypair") - .alias("owner") - .value_name("KEYPAIR") - .validator(is_valid_signer) - .takes_value(true) - .help( - "Specify the keypair for the wallet which will have its native SOL wrapped. \ - This wallet will be assigned as the owner of the wrapped SOL token account. \ - This may be a keypair file or the ASK keyword. \ - Defaults to the client keypair." - ), - ) - .arg( - Arg::with_name("create_aux_account") - .takes_value(false) - .long("create-aux-account") - .help("Wrap SOL in an auxiliary account instead of associated token account"), - ) - .nonce_args(true) - .offline_args(), - ) - .subcommand( - SubCommand::with_name(CommandName::Unwrap.into()) - .about("Unwrap a SOL token account") - .arg( - Arg::with_name("address") - .validator(is_valid_pubkey) - .value_name("TOKEN_ACCOUNT_ADDRESS") - .takes_value(true) - .index(1) - .help("The address of the auxiliary token account to unwrap \ - [default: associated token account for --owner]"), - ) - .arg( - Arg::with_name("wallet_keypair") - .alias("owner") - .value_name("KEYPAIR") - .validator(is_valid_signer) - .takes_value(true) - .help( - "Specify the keypair for the wallet which owns the wrapped SOL. \ - This wallet will receive the unwrapped SOL. \ - This may be a keypair file or the ASK keyword. \ - Defaults to the client keypair." - ), - ) - .arg(multisig_signer_arg()) - .nonce_args(true) - .offline_args(), - ) - .subcommand( - SubCommand::with_name(CommandName::Approve.into()) - .about("Approve a delegate for a token account") - .arg( - Arg::with_name("account") - .validator(is_valid_pubkey) - .value_name("TOKEN_ACCOUNT_ADDRESS") - .takes_value(true) - .index(1) - .required(true) - .help("The address of the token account to delegate"), - ) - .arg( - Arg::with_name("amount") - .validator(is_amount) - .value_name("TOKEN_AMOUNT") - .takes_value(true) - .index(2) - .required(true) - .help("Amount to approve, in tokens"), - ) - .arg( - Arg::with_name("delegate") - .validator(is_valid_pubkey) - .value_name("DELEGATE_TOKEN_ACCOUNT_ADDRESS") - .takes_value(true) - .index(3) - .required(true) - .help("The token account address of delegate"), - ) - .arg( - owner_keypair_arg() - ) - .arg(multisig_signer_arg()) - .mint_args() - .nonce_args(true) - .offline_args_config(&SignOnlyNeedsFullMintSpec{}), - ) - .subcommand( - SubCommand::with_name(CommandName::Revoke.into()) - .about("Revoke a delegate's authority") - .arg( - Arg::with_name("account") - .validator(is_valid_pubkey) - .value_name("TOKEN_ACCOUNT_ADDRESS") - .takes_value(true) - .index(1) - .required(true) - .help("The address of the token account"), - ) - .arg(owner_keypair_arg() - ) - .arg(delegate_address_arg()) - .arg(multisig_signer_arg()) - .nonce_args(true) - .offline_args_config(&SignOnlyNeedsDelegateAddress{}), - ) - .subcommand( - SubCommand::with_name(CommandName::Close.into()) - .about("Close a token account") - .arg( - Arg::with_name("token") - .validator(is_valid_pubkey) - .value_name("TOKEN_ADDRESS") - .takes_value(true) - .index(1) - .required_unless("address") - .help("Token to close. To close a specific account, use the `--address` parameter instead"), - ) - .arg(owner_address_arg()) - .arg( - Arg::with_name("recipient") - .long("recipient") - .validator(is_valid_pubkey) - .value_name("REFUND_ACCOUNT_ADDRESS") - .takes_value(true) - .help("The address of the account to receive remaining SOL [default: --owner]"), - ) - .arg( - Arg::with_name("close_authority") - .long("close-authority") - .alias("owner") - .value_name("KEYPAIR") - .validator(is_valid_signer) - .takes_value(true) - .help( - "Specify the token's close authority if it has one, \ - otherwise specify the token's owner keypair. \ - This may be a keypair file, the ASK keyword. \ - Defaults to the client keypair.", - ), - ) - .arg( - Arg::with_name("address") - .long("address") - .validator(is_valid_pubkey) - .value_name("TOKEN_ACCOUNT_ADDRESS") - .takes_value(true) - .conflicts_with("token") - .help("Specify the token account to close \ - [default: owner's associated token account]"), - ) - .arg(multisig_signer_arg()) - .nonce_args(true) - .offline_args(), - ) - .subcommand( - SubCommand::with_name(CommandName::Balance.into()) - .about("Get token account balance") - .arg( - Arg::with_name("token") - .validator(is_valid_pubkey) - .value_name("TOKEN_ADDRESS") - .takes_value(true) - .index(1) - .required_unless("address") - .help("Token of associated account. To query a specific account, use the `--address` parameter instead"), - ) - .arg(owner_address_arg().conflicts_with("address")) - .arg( - Arg::with_name("address") - .validator(is_valid_pubkey) - .value_name("TOKEN_ACCOUNT_ADDRESS") - .takes_value(true) - .long("address") - .conflicts_with("token") - .help("Specify the token account to query \ - [default: owner's associated token account]"), - ), - ) - .subcommand( - SubCommand::with_name(CommandName::Supply.into()) - .about("Get token supply") - .arg( - Arg::with_name("address") - .validator(is_valid_pubkey) - .value_name("TOKEN_ADDRESS") - .takes_value(true) - .index(1) - .required(true) - .help("The token address"), - ), - ) - .subcommand( - SubCommand::with_name(CommandName::Accounts.into()) - .about("List all token accounts by owner") - .arg( - Arg::with_name("token") - .validator(is_valid_pubkey) - .value_name("TOKEN_ADDRESS") - .takes_value(true) - .index(1) - .help("Limit results to the given token. [Default: list accounts for all tokens]"), - ) - .arg(owner_address_arg()) - ) - .subcommand( - SubCommand::with_name(CommandName::Address.into()) - .about("Get wallet address") - .arg( - Arg::with_name("token") - .validator(is_valid_pubkey) - .value_name("TOKEN_ADDRESS") - .takes_value(true) - .long("token") - .requires("verbose") - .help("Return the associated token address for the given token. \ - [Default: return the client keypair address]") - ) - .arg( - owner_address_arg() - .requires("token") - .help("Return the associated token address for the given owner. \ - [Default: return the associated token address for the client keypair]"), - ), - ) - .subcommand( - SubCommand::with_name(CommandName::AccountInfo.into()) - .about("Query details of an SPL Token account by address") - .arg( - Arg::with_name("token") - .validator(is_valid_pubkey) - .value_name("TOKEN_ADDRESS") - .takes_value(true) - .index(1) - .conflicts_with("address") - .required_unless("address") - .help("Token of associated account. \ - To query a specific account, use the `--address` parameter instead"), - ) - .arg( - owner_address_arg() - .index(2) - .conflicts_with("address") - .help("Owner of the associated account for the specified token. \ - To query a specific account, use the `--address` parameter instead. \ - Defaults to the client keypair."), - ) - .arg( - Arg::with_name("address") - .validator(is_valid_pubkey) - .value_name("TOKEN_ACCOUNT_ADDRESS") - .takes_value(true) - .long("address") - .conflicts_with("token") - .help("Specify the token account to query"), - ), - ) - .subcommand( - SubCommand::with_name(CommandName::MultisigInfo.into()) - .about("Query details about and SPL Token multisig account by address") - .arg( - Arg::with_name("address") - .validator(is_valid_pubkey) - .value_name("MULTISIG_ACCOUNT_ADDRESS") - .takes_value(true) - .index(1) - .required(true) - .help("The address of the SPL Token multisig account to query"), - ), - ) - .subcommand( - SubCommand::with_name(CommandName::Gc.into()) - .about("Cleanup unnecessary token accounts") - .arg(owner_keypair_arg()) - .arg( - Arg::with_name("close_empty_associated_accounts") - .long("close-empty-associated-accounts") - .takes_value(false) - .help("close all empty associated token accounts (to get SOL back)") - ) - ) - .subcommand( - SubCommand::with_name(CommandName::SyncNative.into()) - .about("Sync a native SOL token account to its underlying lamports") - .arg( - owner_address_arg() - .index(1) - .conflicts_with("address") - .help("Owner of the associated account for the native token. \ - To query a specific account, use the `--address` parameter instead. \ - Defaults to the client keypair."), - ) - .arg( - Arg::with_name("address") - .validator(is_valid_pubkey) - .value_name("TOKEN_ACCOUNT_ADDRESS") - .takes_value(true) - .long("address") - .conflicts_with("owner") - .help("Specify the specific token account address to sync"), - ), - ) -} - -#[tokio::main] -async fn main() -> Result<(), Error> { - let default_decimals = format!("{}", spl_token_2022::native_mint::DECIMALS); - let default_program_id = spl_token::id().to_string(); - let minimum_signers_help = minimum_signers_help_string(); - let multisig_member_help = multisig_member_help_string(); - let app_matches = app( - &default_decimals, - &default_program_id, - &minimum_signers_help, - &multisig_member_help, - ) - .get_matches(); - - let mut wallet_manager = None; - let mut bulk_signers: Vec> = Vec::new(); - let mut multisigner_ids = Vec::new(); - - let (sub_command, sub_matches) = app_matches.subcommand(); - let sub_command = CommandName::from_str(sub_command).unwrap(); - let matches = sub_matches.unwrap(); - - let config = { - let cli_config = if let Some(config_file) = matches.value_of("config_file") { - solana_cli_config::Config::load(config_file).unwrap_or_else(|_| { - eprintln!("error: Could not find config file `{}`", config_file); - exit(1); - }) - } else { - solana_cli_config::Config::default() - }; - let json_rpc_url = normalize_to_url_if_moniker( - matches - .value_of("json_rpc_url") - .unwrap_or(&cli_config.json_rpc_url), - ); - let websocket_url = solana_cli_config::Config::compute_websocket_url(&json_rpc_url); - - let (signer, fee_payer) = signer_from_path( - matches, - matches - .value_of("fee_payer") - .unwrap_or(&cli_config.keypair_path), - "fee_payer", - &mut wallet_manager, - ) - .map(|s| { - let p = s.pubkey(); - (s, p) - }) - .unwrap_or_else(|e| { - eprintln!("error: {}", e); - exit(1); - }); - bulk_signers.push(signer); - - let verbose = matches.is_present("verbose"); - let output_format = matches - .value_of("output_format") - .map(|value| match value { - "json" => OutputFormat::Json, - "json-compact" => OutputFormat::JsonCompact, - _ => unreachable!(), - }) - .unwrap_or(if verbose { - OutputFormat::DisplayVerbose - } else { - OutputFormat::Display - }); - - let nonce_account = pubkey_of_signer(matches, NONCE_ARG.name, &mut wallet_manager) - .unwrap_or_else(|e| { - eprintln!("error: {}", e); - exit(1); - }); - let nonce_authority = if nonce_account.is_some() { - let (signer, nonce_authority) = signer_from_path( - matches, - matches - .value_of(NONCE_AUTHORITY_ARG.name) - .unwrap_or(&cli_config.keypair_path), - NONCE_AUTHORITY_ARG.name, - &mut wallet_manager, - ) - .map(|s| { - let p = s.pubkey(); - (s, p) - }) - .unwrap_or_else(|e| { - eprintln!("error: {}", e); - exit(1); - }); - bulk_signers.push(signer); - - Some(nonce_authority) - } else { - None - }; - - let sign_only = matches.is_present(SIGN_ONLY_ARG.name); - let dump_transaction_message = matches.is_present(DUMP_TRANSACTION_MESSAGE.name); - let program_id = pubkey_of(matches, "program_id").unwrap(); - - let multisig_signers = signers_of(matches, MULTISIG_SIGNER_ARG.name, &mut wallet_manager) - .unwrap_or_else(|e| { - eprintln!("error: {}", e); - exit(1); - }); - if let Some(mut multisig_signers) = multisig_signers { - multisig_signers.sort_by(|(_, lp), (_, rp)| lp.cmp(rp)); - let (signers, pubkeys): (Vec<_>, Vec<_>) = multisig_signers.into_iter().unzip(); - bulk_signers.extend(signers); - multisigner_ids = pubkeys; - } - let multisigner_pubkeys = multisigner_ids.iter().collect::>(); - - let rpc_client = Arc::new(RpcClient::new_with_commitment( - json_rpc_url, - CommitmentConfig::confirmed(), - )); - let program_client: Arc> = Arc::new( - ProgramRpcClient::new(rpc_client.clone(), ProgramRpcClientSendTransaction), - ); - Config { - rpc_client, - program_client, - websocket_url, - output_format, - fee_payer, - default_keypair: KeypairOrPath::Path(cli_config.keypair_path), - nonce_account, - nonce_authority, - sign_only, - dump_transaction_message, - multisigner_pubkeys, - program_id, - } - }; - - solana_logger::setup_with_default("solana=info"); - let result = - process_command(&sub_command, matches, &config, wallet_manager, bulk_signers).await?; - println!("{}", result); - Ok(()) -} - -async fn process_command<'a>( - sub_command: &CommandName, - sub_matches: &ArgMatches<'_>, - config: &Config<'a>, - mut wallet_manager: Option>, - mut bulk_signers: Vec>, -) -> CommandResult { - match (sub_command, sub_matches) { - (CommandName::Bench, arg_matches) => { - bench_process_command( - arg_matches, - config, - std::mem::take(&mut bulk_signers), - &mut wallet_manager, - ) - .await - } - (CommandName::CreateToken, arg_matches) => { - let decimals = value_t_or_exit!(arg_matches, "decimals", u8); - let mint_authority = - config.pubkey_or_default(arg_matches, "mint_authority", &mut wallet_manager); - let memo = value_t!(arg_matches, "memo", String).ok(); - - let (token_signer, token) = - get_signer(arg_matches, "token_keypair", &mut wallet_manager) - .unwrap_or_else(new_throwaway_signer); - bulk_signers.push(token_signer); - - command_create_token( - config, - decimals, - token, - mint_authority, - arg_matches.is_present("enable_freeze"), - memo, - bulk_signers, - ) - .await - } - (CommandName::CreateAccount, arg_matches) => { - let token = pubkey_of_signer(arg_matches, "token", &mut wallet_manager) - .unwrap() - .unwrap(); - - // No need to add a signer when creating an associated token account - let account = get_signer(arg_matches, "account_keypair", &mut wallet_manager).map( - |(signer, account)| { - bulk_signers.push(signer); - account - }, - ); - - let owner = config.pubkey_or_default(arg_matches, "owner", &mut wallet_manager); - command_create_account(config, token, owner, account, bulk_signers).await - } - (CommandName::CreateMultisig, arg_matches) => { - let minimum_signers = value_of::(arg_matches, "minimum_signers").unwrap(); - let multisig_members = - pubkeys_of_multiple_signers(arg_matches, "multisig_member", &mut wallet_manager) - .unwrap_or_else(|e| { - eprintln!("error: {}", e); - exit(1); - }) - .unwrap(); - if minimum_signers as usize > multisig_members.len() { - eprintln!( - "error: MINIMUM_SIGNERS cannot be greater than the number \ - of MULTISIG_MEMBERs passed" - ); - exit(1); - } - - let (signer, account) = get_signer(arg_matches, "address_keypair", &mut wallet_manager) - .unwrap_or_else(new_throwaway_signer); - bulk_signers.push(signer); - - command_create_multisig( - config, - account, - minimum_signers, - multisig_members, - bulk_signers, - ) - .await - } - (CommandName::Authorize, arg_matches) => { - let address = pubkey_of_signer(arg_matches, "address", &mut wallet_manager) - .unwrap() - .unwrap(); - let authority_type = arg_matches.value_of("authority_type").unwrap(); - let authority_type = match authority_type { - "mint" => AuthorityType::MintTokens, - "freeze" => AuthorityType::FreezeAccount, - "owner" => AuthorityType::AccountOwner, - "close" => AuthorityType::CloseAccount, - "close-mint" => AuthorityType::CloseMint, - "transfer-fee-config" => AuthorityType::TransferFeeConfig, - "withheld-withdraw" => AuthorityType::WithheldWithdraw, - "interest-rate" => AuthorityType::InterestRate, - _ => unreachable!(), - }; - - let (authority_signer, authority) = - config.signer_or_default(arg_matches, "authority", &mut wallet_manager); - bulk_signers.push(authority_signer); - - let new_authority = - pubkey_of_signer(arg_matches, "new_authority", &mut wallet_manager).unwrap(); - let force_authorize = arg_matches.is_present("force"); - command_authorize( - config, - address, - authority_type, - authority, - new_authority, - force_authorize, - bulk_signers, - ) - .await - } - (CommandName::Transfer, arg_matches) => { - let token = pubkey_of_signer(arg_matches, "token", &mut wallet_manager) - .unwrap() - .unwrap(); - let amount = match arg_matches.value_of("amount").unwrap() { - "ALL" => None, - amount => Some(amount.parse::().unwrap()), - }; - let recipient = pubkey_of_signer(arg_matches, "recipient", &mut wallet_manager) - .unwrap() - .unwrap(); - let sender = pubkey_of_signer(arg_matches, "from", &mut wallet_manager).unwrap(); - - let (owner_signer, owner) = - config.signer_or_default(arg_matches, "owner", &mut wallet_manager); - bulk_signers.push(owner_signer); - - let mint_decimals = value_of::(arg_matches, MINT_DECIMALS_ARG.name); - let fund_recipient = arg_matches.is_present("fund_recipient"); - let allow_unfunded_recipient = arg_matches.is_present("allow_empty_recipient") - || arg_matches.is_present("allow_unfunded_recipient"); - - let recipient_is_ata_owner = arg_matches.is_present("recipient_is_ata_owner"); - let use_unchecked_instruction = arg_matches.is_present("use_unchecked_instruction"); - let memo = value_t!(arg_matches, "memo", String).ok(); - - command_transfer( - config, - token, - amount, - recipient, - sender, - owner, - allow_unfunded_recipient, - fund_recipient, - mint_decimals, - recipient_is_ata_owner, - use_unchecked_instruction, - memo, - bulk_signers, - arg_matches.is_present("no_wait"), - arg_matches.is_present("allow_non_system_account_recipient"), - ) - .await - } - (CommandName::Burn, arg_matches) => { - let source = pubkey_of_signer(arg_matches, "source", &mut wallet_manager) - .unwrap() - .unwrap(); - - let (owner_signer, owner) = - config.signer_or_default(arg_matches, "owner", &mut wallet_manager); - bulk_signers.push(owner_signer); - - let amount = value_t_or_exit!(arg_matches, "amount", f64); - let mint_address = - pubkey_of_signer(arg_matches, MINT_ADDRESS_ARG.name, &mut wallet_manager).unwrap(); - let mint_decimals = value_of::(arg_matches, MINT_DECIMALS_ARG.name); - let use_unchecked_instruction = arg_matches.is_present("use_unchecked_instruction"); - let memo = value_t!(arg_matches, "memo", String).ok(); - command_burn( - config, - source, - owner, - amount, - mint_address, - mint_decimals, - use_unchecked_instruction, - memo, - bulk_signers, - ) - .await - } - (CommandName::Mint, arg_matches) => { - let (mint_authority_signer, mint_authority) = - config.signer_or_default(arg_matches, "mint_authority", &mut wallet_manager); - bulk_signers.push(mint_authority_signer); - - let token = pubkey_of_signer(arg_matches, "token", &mut wallet_manager) - .unwrap() - .unwrap(); - let amount = value_t_or_exit!(arg_matches, "amount", f64); - let mint_decimals = value_of::(arg_matches, MINT_DECIMALS_ARG.name); - let mint_info = config.get_mint_info(&token, mint_decimals).await?; - let recipient = if let Some(address) = - pubkey_of_signer(arg_matches, "recipient", &mut wallet_manager).unwrap() - { - address - } else { - config.associated_token_address_for_token_and_program( - arg_matches, - &mut wallet_manager, - &mint_info.address, - &mint_info.program_id, - ) - }; - config.check_account(&recipient, Some(token)).await?; - let use_unchecked_instruction = arg_matches.is_present("use_unchecked_instruction"); - command_mint( - config, - token, - amount, - recipient, - mint_info, - mint_authority, - use_unchecked_instruction, - bulk_signers, - ) - .await - } - (CommandName::Freeze, arg_matches) => { - let (freeze_authority_signer, freeze_authority) = - config.signer_or_default(arg_matches, "freeze_authority", &mut wallet_manager); - bulk_signers.push(freeze_authority_signer); - - let account = pubkey_of_signer(arg_matches, "account", &mut wallet_manager) - .unwrap() - .unwrap(); - let mint_address = - pubkey_of_signer(arg_matches, MINT_ADDRESS_ARG.name, &mut wallet_manager).unwrap(); - command_freeze( - config, - account, - mint_address, - freeze_authority, - bulk_signers, - ) - .await - } - (CommandName::Thaw, arg_matches) => { - let (freeze_authority_signer, freeze_authority) = - config.signer_or_default(arg_matches, "freeze_authority", &mut wallet_manager); - bulk_signers.push(freeze_authority_signer); - - let account = pubkey_of_signer(arg_matches, "account", &mut wallet_manager) - .unwrap() - .unwrap(); - let mint_address = - pubkey_of_signer(arg_matches, MINT_ADDRESS_ARG.name, &mut wallet_manager).unwrap(); - command_thaw( - config, - account, - mint_address, - freeze_authority, - bulk_signers, - ) - .await - } - (CommandName::Wrap, arg_matches) => { - let amount = value_t_or_exit!(arg_matches, "amount", f64); - let account = if arg_matches.is_present("create_aux_account") { - let (signer, account) = new_throwaway_signer(); - bulk_signers.push(signer); - Some(account) - } else { - // No need to add a signer when creating an associated token account - None - }; - - let (wallet_signer, wallet_address) = - config.signer_or_default(arg_matches, "wallet_keypair", &mut wallet_manager); - bulk_signers.push(wallet_signer); - - command_wrap(config, amount, wallet_address, account, bulk_signers).await - } - (CommandName::Unwrap, arg_matches) => { - let (wallet_signer, wallet_address) = - config.signer_or_default(arg_matches, "wallet_keypair", &mut wallet_manager); - bulk_signers.push(wallet_signer); - - let address = pubkey_of_signer(arg_matches, "address", &mut wallet_manager).unwrap(); - command_unwrap(config, wallet_address, address, bulk_signers).await - } - (CommandName::Approve, arg_matches) => { - let (owner_signer, owner_address) = - config.signer_or_default(arg_matches, "owner", &mut wallet_manager); - bulk_signers.push(owner_signer); - - let account = pubkey_of_signer(arg_matches, "account", &mut wallet_manager) - .unwrap() - .unwrap(); - let amount = value_t_or_exit!(arg_matches, "amount", f64); - let delegate = pubkey_of_signer(arg_matches, "delegate", &mut wallet_manager) - .unwrap() - .unwrap(); - let mint_address = - pubkey_of_signer(arg_matches, MINT_ADDRESS_ARG.name, &mut wallet_manager).unwrap(); - let mint_decimals = value_of::(arg_matches, MINT_DECIMALS_ARG.name); - let use_unchecked_instruction = arg_matches.is_present("use_unchecked_instruction"); - command_approve( - config, - account, - owner_address, - amount, - delegate, - mint_address, - mint_decimals, - use_unchecked_instruction, - bulk_signers, - ) - .await - } - (CommandName::Revoke, arg_matches) => { - let (owner_signer, owner_address) = - config.signer_or_default(arg_matches, "owner", &mut wallet_manager); - bulk_signers.push(owner_signer); - - let account = pubkey_of_signer(arg_matches, "account", &mut wallet_manager) - .unwrap() - .unwrap(); - let delegate_address = - pubkey_of_signer(arg_matches, DELEGATE_ADDRESS_ARG.name, &mut wallet_manager) - .unwrap(); - command_revoke( - config, - account, - owner_address, - delegate_address, - bulk_signers, - ) - .await - } - (CommandName::Close, arg_matches) => { - let (close_authority_signer, close_authority) = - config.signer_or_default(arg_matches, "close_authority", &mut wallet_manager); - bulk_signers.push(close_authority_signer); - - let address = config - .associated_token_address_or_override(arg_matches, "address", &mut wallet_manager) - .await; - let recipient = config.pubkey_or_default(arg_matches, "recipient", &mut wallet_manager); - command_close(config, address, close_authority, recipient, bulk_signers).await - } - (CommandName::Balance, arg_matches) => { - let address = config - .associated_token_address_or_override(arg_matches, "address", &mut wallet_manager) - .await; - command_balance(config, address).await - } - (CommandName::Supply, arg_matches) => { - let address = pubkey_of_signer(arg_matches, "address", &mut wallet_manager) - .unwrap() - .unwrap(); - command_supply(config, address).await - } - (CommandName::Accounts, arg_matches) => { - let token = pubkey_of_signer(arg_matches, "token", &mut wallet_manager).unwrap(); - let owner = config.pubkey_or_default(arg_matches, "owner", &mut wallet_manager); - command_accounts(config, token, owner).await - } - (CommandName::Address, arg_matches) => { - let token = pubkey_of_signer(arg_matches, "token", &mut wallet_manager).unwrap(); - let owner = config.pubkey_or_default(arg_matches, "owner", &mut wallet_manager); - command_address(config, token, owner).await - } - (CommandName::AccountInfo, arg_matches) => { - let address = config - .associated_token_address_or_override(arg_matches, "address", &mut wallet_manager) - .await; - command_account_info(config, address).await - } - (CommandName::MultisigInfo, arg_matches) => { - let address = pubkey_of_signer(arg_matches, "address", &mut wallet_manager) - .unwrap() - .unwrap(); - command_multisig(config, address).await - } - (CommandName::Gc, arg_matches) => { - match config.output_format { - OutputFormat::Json | OutputFormat::JsonCompact => { - eprintln!( - "`spl-token gc` does not support the `--ouput` parameter at this time" - ); - exit(1); - } - _ => {} - } - - let close_empty_associated_accounts = - arg_matches.is_present("close_empty_associated_accounts"); - - let (owner_signer, owner_address) = - config.signer_or_default(arg_matches, "owner", &mut wallet_manager); - bulk_signers.push(owner_signer); - - command_gc( - config, - owner_address, - close_empty_associated_accounts, - bulk_signers, - ) - .await - } - (CommandName::SyncNative, arg_matches) => { - let program_id = config.program_id; - let native_mint = native_mint(&program_id)?; - let address = config - .associated_token_address_for_token_or_override( - arg_matches, - "address", - &mut wallet_manager, - Some(native_mint), - ) - .await; - command_sync_native(address, bulk_signers, config).await - } - } -} - -fn format_output(command_output: T, command_name: &CommandName, config: &Config) -> String -where - T: Serialize + Display + QuietDisplay + VerboseDisplay, -{ - config.output_format.formatted_string(&CommandOutput { - command_name: command_name.to_string(), - command_output, - }) -} -enum TransactionReturnData { - CliSignature(CliSignature), - CliSignOnlyData(CliSignOnlyData), -} -async fn handle_tx<'a>( - signer_info: &CliSignerInfo, - config: &Config<'a>, - no_wait: bool, - minimum_balance_for_rent_exemption: u64, - instructions: Vec, -) -> Result { - let fee_payer = Some(&config.fee_payer); - - let recent_blockhash = config.rpc_client.get_latest_blockhash().await?; - let message = if let Some(nonce_account) = config.nonce_account.as_ref() { - let mut message = Message::new_with_nonce( - instructions, - fee_payer, - nonce_account, - config.nonce_authority.as_ref().unwrap(), - ); - message.recent_blockhash = recent_blockhash; - message - } else { - Message::new_with_blockhash(&instructions, fee_payer, &recent_blockhash) - }; - let fee = config.rpc_client.get_fee_for_message(&message).await?; - - if !config.sign_only { - check_fee_payer_balance(config, minimum_balance_for_rent_exemption + fee).await?; - } - - let signers = signer_info.signers_for_message(&message); - let mut transaction = Transaction::new_unsigned(message); - - if config.sign_only { - transaction.try_partial_sign(&signers, recent_blockhash)?; - Ok(TransactionReturnData::CliSignOnlyData(return_signers_data( - &transaction, - &ReturnSignersConfig { - dump_transaction_message: config.dump_transaction_message, - }, - ))) - } else { - transaction.try_sign(&signers, recent_blockhash)?; - let signature = if no_wait { - config.rpc_client.send_transaction(&transaction).await? - } else { - config - .rpc_client - .send_and_confirm_transaction_with_spinner(&transaction) - .await? - }; - Ok(TransactionReturnData::CliSignature(CliSignature { - signature: signature.to_string(), - })) - } -} - -#[cfg(test)] -mod tests { - use { - super::*, - serial_test::serial, - solana_sdk::{ - bpf_loader, - signature::{write_keypair_file, Keypair, Signer}, - }, - solana_test_validator::{ProgramInfo, TestValidator, TestValidatorGenesis}, - std::path::PathBuf, - tempfile::NamedTempFile, - }; - - fn clone_keypair(keypair: &Keypair) -> Keypair { - Keypair::from_bytes(&keypair.to_bytes()).unwrap() - } - - const TEST_DECIMALS: u8 = 0; - - async fn new_validator_for_test() -> (TestValidator, Keypair) { - solana_logger::setup(); - let mut test_validator_genesis = TestValidatorGenesis::default(); - test_validator_genesis.add_programs_with_path(&[ - ProgramInfo { - program_id: spl_token::id(), - loader: bpf_loader::id(), - program_path: PathBuf::from("../../target/deploy/spl_token.so"), - }, - ProgramInfo { - program_id: spl_associated_token_account::id(), - loader: bpf_loader::id(), - program_path: PathBuf::from("../../target/deploy/spl_associated_token_account.so"), - }, - ProgramInfo { - program_id: spl_token_2022::id(), - loader: bpf_loader::id(), - program_path: PathBuf::from("../../target/deploy/spl_token_2022.so"), - }, - ]); - test_validator_genesis.start_async().await - } - - fn test_config<'a>( - test_validator: &TestValidator, - payer: &Keypair, - program_id: &Pubkey, - ) -> Config<'a> { - let websocket_url = test_validator.rpc_pubsub_url(); - let rpc_client = Arc::new(test_validator.get_async_rpc_client()); - let program_client: Arc> = Arc::new( - ProgramRpcClient::new(rpc_client.clone(), ProgramRpcClientSendTransaction), - ); - Config { - rpc_client, - program_client, - websocket_url, - output_format: OutputFormat::JsonCompact, - fee_payer: payer.pubkey(), - default_keypair: KeypairOrPath::Keypair(clone_keypair(payer)), - nonce_account: None, - nonce_authority: None, - sign_only: false, - dump_transaction_message: false, - multisigner_pubkeys: vec![], - program_id: *program_id, - } - } - - async fn do_create_native_mint(config: &Config<'_>, program_id: &Pubkey, payer: &Keypair) { - if program_id == &spl_token_2022::id() { - let native_mint = spl_token_2022::native_mint::id(); - if config.rpc_client.get_account(&native_mint).await.is_err() { - let transaction = Transaction::new_signed_with_payer( - &[create_native_mint(program_id, &payer.pubkey()).unwrap()], - Some(&payer.pubkey()), - &[payer], - config.rpc_client.get_latest_blockhash().await.unwrap(), - ); - config - .rpc_client - .send_and_confirm_transaction(&transaction) - .await - .unwrap(); - } - } - } - - async fn create_token(config: &Config<'_>, payer: &Keypair) -> Pubkey { - let token = Keypair::new(); - let token_pubkey = token.pubkey(); - let bulk_signers: Vec> = - vec![Box::new(clone_keypair(payer)), Box::new(token)]; - - command_create_token( - config, - TEST_DECIMALS, - token_pubkey, - payer.pubkey(), - false, - None, - bulk_signers, - ) - .await - .unwrap(); - token_pubkey - } - - async fn create_auxiliary_account( - config: &Config<'_>, - payer: &Keypair, - mint: Pubkey, - ) -> Pubkey { - let auxiliary = Keypair::new(); - let address = auxiliary.pubkey(); - let bulk_signers: Vec> = - vec![Box::new(clone_keypair(payer)), Box::new(auxiliary)]; - command_create_account(config, mint, payer.pubkey(), Some(address), bulk_signers) - .await - .unwrap(); - address - } - - async fn create_associated_account( - config: &Config<'_>, - payer: &Keypair, - mint: Pubkey, - ) -> Pubkey { - let bulk_signers: Vec> = vec![Box::new(clone_keypair(payer))]; - command_create_account(config, mint, payer.pubkey(), None, bulk_signers) - .await - .unwrap(); - get_associated_token_address_with_program_id(&payer.pubkey(), &mint, &config.program_id) - } - - async fn mint_tokens( - config: &Config<'_>, - payer: &Keypair, - mint: Pubkey, - ui_amount: f64, - recipient: Pubkey, - ) { - let bulk_signers: Vec> = vec![Box::new(clone_keypair(payer))]; - command_mint( - config, - mint, - ui_amount, - recipient, - MintInfo { - program_id: config.program_id, - address: mint, - decimals: TEST_DECIMALS, - }, - payer.pubkey(), - false, - bulk_signers, - ) - .await - .unwrap(); - } - - async fn process_test_command( - config: &Config<'_>, - payer: &Keypair, - args: &[&str], - ) -> CommandResult { - let default_decimals = format!("{}", spl_token_2022::native_mint::DECIMALS); - let default_program_id = spl_token::id().to_string(); - let minimum_signers_help = minimum_signers_help_string(); - let multisig_member_help = multisig_member_help_string(); - - let app_matches = app( - &default_decimals, - &default_program_id, - &minimum_signers_help, - &multisig_member_help, - ) - .get_matches_from(args); - let (sub_command, sub_matches) = app_matches.subcommand(); - let sub_command = CommandName::from_str(sub_command).unwrap(); - let matches = sub_matches.unwrap(); - - let wallet_manager = None; - let bulk_signers: Vec> = vec![Box::new(clone_keypair(payer))]; - process_command(&sub_command, matches, config, wallet_manager, bulk_signers).await - } - - #[tokio::test] - #[serial] - async fn create_token_default() { - let (test_validator, payer) = new_validator_for_test().await; - for program_id in [spl_token::id(), spl_token_2022::id()] { - let config = test_config(&test_validator, &payer, &program_id); - let result = process_test_command( - &config, - &payer, - &["spl-token", CommandName::CreateToken.into()], - ) - .await; - let value: serde_json::Value = serde_json::from_str(&result.unwrap()).unwrap(); - let mint = - Pubkey::from_str(value["commandOutput"]["address"].as_str().unwrap()).unwrap(); - let account = config.rpc_client.get_account(&mint).await.unwrap(); - assert_eq!(account.owner, program_id); - } - } - - #[tokio::test] - #[serial] - async fn supply() { - let (test_validator, payer) = new_validator_for_test().await; - for program_id in [spl_token::id(), spl_token_2022::id()] { - let config = test_config(&test_validator, &payer, &program_id); - let token = create_token(&config, &payer).await; - let result = process_test_command( - &config, - &payer, - &["spl-token", CommandName::Supply.into(), &token.to_string()], - ) - .await; - let value: serde_json::Value = serde_json::from_str(&result.unwrap()).unwrap(); - assert_eq!(value["amount"], "0"); - assert_eq!(value["uiAmountString"], "0"); - } - } - - #[tokio::test] - #[serial] - async fn create_account_default() { - let (test_validator, payer) = new_validator_for_test().await; - for program_id in [spl_token::id(), spl_token_2022::id()] { - let config = test_config(&test_validator, &payer, &program_id); - let token = create_token(&config, &payer).await; - let result = process_test_command( - &config, - &payer, - &[ - "spl-token", - CommandName::CreateAccount.into(), - &token.to_string(), - ], - ) - .await; - result.unwrap(); - } - } - - #[tokio::test] - #[serial] - async fn account_info() { - let (test_validator, payer) = new_validator_for_test().await; - for program_id in [spl_token::id(), spl_token_2022::id()] { - let config = test_config(&test_validator, &payer, &program_id); - let token = create_token(&config, &payer).await; - let _account = create_associated_account(&config, &payer, token).await; - let result = process_test_command( - &config, - &payer, - &[ - "spl-token", - CommandName::AccountInfo.into(), - &token.to_string(), - ], - ) - .await; - let value: serde_json::Value = serde_json::from_str(&result.unwrap()).unwrap(); - let account = get_associated_token_address_with_program_id( - &payer.pubkey(), - &token, - &config.program_id, - ); - assert_eq!(value["address"], account.to_string()); - assert_eq!(value["mint"], token.to_string()); - assert_eq!(value["isAssociated"], true); - assert_eq!(value["isNative"], false); - assert_eq!(value["owner"], payer.pubkey().to_string()); - assert_eq!(value["state"], "initialized"); - } - } - - #[tokio::test] - #[serial] - async fn balance() { - let (test_validator, payer) = new_validator_for_test().await; - for program_id in [spl_token::id(), spl_token_2022::id()] { - let config = test_config(&test_validator, &payer, &program_id); - let token = create_token(&config, &payer).await; - let _account = create_associated_account(&config, &payer, token).await; - let result = process_test_command( - &config, - &payer, - &["spl-token", CommandName::Balance.into(), &token.to_string()], - ) - .await; - let value: serde_json::Value = serde_json::from_str(&result.unwrap()).unwrap(); - assert_eq!(value["amount"], "0"); - assert_eq!(value["uiAmountString"], "0"); - } - } - - #[tokio::test] - #[serial] - async fn mint() { - let (test_validator, payer) = new_validator_for_test().await; - for program_id in [spl_token::id(), spl_token_2022::id()] { - let config = test_config(&test_validator, &payer, &program_id); - let token = create_token(&config, &payer).await; - let account = create_associated_account(&config, &payer, token).await; - let result = process_test_command( - &config, - &payer, - &[ - "spl-token", - CommandName::Mint.into(), - &token.to_string(), - "100", - ], - ) - .await; - result.unwrap(); - let account = config.rpc_client.get_account(&account).await.unwrap(); - let token_account = StateWithExtensionsOwned::::unpack(account.data).unwrap(); - assert_eq!(token_account.base.amount, 100); - assert_eq!(token_account.base.mint, token); - assert_eq!(token_account.base.owner, payer.pubkey()); - } - } - - #[tokio::test] - #[serial] - async fn balance_after_mint() { - let (test_validator, payer) = new_validator_for_test().await; - for program_id in [spl_token::id(), spl_token_2022::id()] { - let config = test_config(&test_validator, &payer, &program_id); - let token = create_token(&config, &payer).await; - let account = create_associated_account(&config, &payer, token).await; - let ui_amount = 100.0; - mint_tokens(&config, &payer, token, ui_amount, account).await; - let result = process_test_command( - &config, - &payer, - &["spl-token", CommandName::Balance.into(), &token.to_string()], - ) - .await; - let value: serde_json::Value = serde_json::from_str(&result.unwrap()).unwrap(); - assert_eq!(value["amount"], format!("{}", ui_amount)); - assert_eq!(value["uiAmountString"], format!("{}", ui_amount)); - } - } - - #[tokio::test] - #[serial] - async fn accounts() { - let (test_validator, payer) = new_validator_for_test().await; - for program_id in [spl_token::id(), spl_token_2022::id()] { - let config = test_config(&test_validator, &payer, &program_id); - let token1 = create_token(&config, &payer).await; - let _account1 = create_associated_account(&config, &payer, token1).await; - let token2 = create_token(&config, &payer).await; - let _account2 = create_associated_account(&config, &payer, token2).await; - let token3 = create_token(&config, &payer).await; - let result = process_test_command( - &config, - &payer, - &["spl-token", CommandName::Accounts.into()], - ) - .await - .unwrap(); - assert!(result.contains(&token1.to_string())); - assert!(result.contains(&token2.to_string())); - assert!(!result.contains(&token3.to_string())); - } - } - - #[tokio::test] - #[serial] - async fn wrap() { - let (test_validator, payer) = new_validator_for_test().await; - for program_id in [spl_token::id(), spl_token_2022::id()] { - let native_mint = native_mint(&program_id).unwrap(); - let config = test_config(&test_validator, &payer, &program_id); - do_create_native_mint(&config, &program_id, &payer).await; - let _result = process_test_command( - &config, - &payer, - &["spl-token", CommandName::Wrap.into(), "0.5"], - ) - .await - .unwrap(); - let account = get_associated_token_address_with_program_id( - &payer.pubkey(), - &native_mint, - &config.program_id, - ); - let account = config.rpc_client.get_account(&account).await.unwrap(); - let token_account = StateWithExtensionsOwned::::unpack(account.data).unwrap(); - assert_eq!(token_account.base.mint, native_mint); - assert_eq!(token_account.base.owner, payer.pubkey()); - assert!(token_account.base.is_native()); - } - } - - #[tokio::test] - #[serial] - async fn unwrap() { - let (test_validator, payer) = new_validator_for_test().await; - for program_id in [spl_token::id(), spl_token_2022::id()] { - let config = test_config(&test_validator, &payer, &program_id); - do_create_native_mint(&config, &program_id, &payer).await; - let (signer, account) = new_throwaway_signer(); - let bulk_signers: Vec> = vec![Box::new(clone_keypair(&payer)), signer]; - command_wrap(&config, 0.5, payer.pubkey(), Some(account), bulk_signers) - .await - .unwrap(); - let result = process_test_command( - &config, - &payer, - &[ - "spl-token", - CommandName::Unwrap.into(), - &account.to_string(), - ], - ) - .await; - result.unwrap(); - config.rpc_client.get_account(&account).await.unwrap_err(); - } - } - - #[tokio::test] - #[serial] - async fn transfer() { - let (test_validator, payer) = new_validator_for_test().await; - for program_id in [spl_token::id(), spl_token_2022::id()] { - let config = test_config(&test_validator, &payer, &program_id); - let token = create_token(&config, &payer).await; - let source = create_associated_account(&config, &payer, token).await; - let destination = create_auxiliary_account(&config, &payer, token).await; - let ui_amount = 100.0; - mint_tokens(&config, &payer, token, ui_amount, source).await; - let result = process_test_command( - &config, - &payer, - &[ - "spl-token", - CommandName::Transfer.into(), - &token.to_string(), - "10", - &destination.to_string(), - ], - ) - .await; - result.unwrap(); - - let account = config.rpc_client.get_account(&source).await.unwrap(); - let token_account = StateWithExtensionsOwned::::unpack(account.data).unwrap(); - assert_eq!(token_account.base.amount, 90); - let account = config.rpc_client.get_account(&destination).await.unwrap(); - let token_account = StateWithExtensionsOwned::::unpack(account.data).unwrap(); - assert_eq!(token_account.base.amount, 10); - } - } - - #[tokio::test] - #[serial] - async fn transfer_fund_recipient() { - let (test_validator, payer) = new_validator_for_test().await; - for program_id in [spl_token::id(), spl_token_2022::id()] { - let config = test_config(&test_validator, &payer, &program_id); - let token = create_token(&config, &payer).await; - let source = create_associated_account(&config, &payer, token).await; - let recipient = Keypair::new().pubkey().to_string(); - let ui_amount = 100.0; - mint_tokens(&config, &payer, token, ui_amount, source).await; - let result = process_test_command( - &config, - &payer, - &[ - "spl-token", - CommandName::Transfer.into(), - "--fund-recipient", - "--allow-unfunded-recipient", - &token.to_string(), - "10", - &recipient, - ], - ) - .await; - result.unwrap(); - - let account = config.rpc_client.get_account(&source).await.unwrap(); - let token_account = StateWithExtensionsOwned::::unpack(account.data).unwrap(); - assert_eq!(token_account.base.amount, 90); - } - } - - #[tokio::test] - #[serial] - async fn failing_to_allow_non_system_account_recipient() { - let (test_validator, payer) = new_validator_for_test().await; - let config = test_config(&test_validator, &payer, &spl_token::id()); - - let token = create_token(&config, &payer).await; - let source = create_associated_account(&config, &payer, token).await; - let recipient = token.to_string(); - let ui_amount = 100.0; - mint_tokens(&config, &payer, token, ui_amount, source).await; - let result = process_test_command( - &config, - &payer, - &[ - "spl-token", - CommandName::Transfer.into(), - "--fund-recipient", - &token.to_string(), - "10", - &recipient, - ], - ) - .await; - assert!(result.is_err()); - } - - #[tokio::test] - #[serial] - async fn allow_non_system_account_recipient() { - let (test_validator, payer) = new_validator_for_test().await; - let config = test_config(&test_validator, &payer, &spl_token::id()); - - let token = create_token(&config, &payer).await; - let source = create_associated_account(&config, &payer, token).await; - let recipient = token.to_string(); - let ui_amount = 100.0; - mint_tokens(&config, &payer, token, ui_amount, source).await; - let result = process_test_command( - &config, - &payer, - &[ - "spl-token", - CommandName::Transfer.into(), - "--fund-recipient", - "--allow-non-system-account-recipient", - "--allow-unfunded-recipient", - &token.to_string(), - "10", - &recipient, - ], - ) - .await; - result.unwrap(); - - let ui_account = config - .rpc_client - .get_token_account(&source) - .await - .unwrap() - .unwrap(); - assert_eq!(ui_account.token_amount.amount, "90"); - } - - #[tokio::test] - #[serial] - async fn close_wrapped_sol_account() { - let (test_validator, payer) = new_validator_for_test().await; - for program_id in [spl_token::id(), spl_token_2022::id()] { - let config = test_config(&test_validator, &payer, &program_id); - let bulk_signers: Vec> = vec![Box::new(clone_keypair(&payer))]; - - let native_mint = native_mint(&program_id).unwrap(); - let token = create_token(&config, &payer).await; - let source = create_associated_account(&config, &payer, token).await; - do_create_native_mint(&config, &program_id, &payer).await; - let ui_amount = 10.0; - command_wrap(&config, ui_amount, payer.pubkey(), None, bulk_signers) - .await - .unwrap(); - - let recipient = get_associated_token_address_with_program_id( - &payer.pubkey(), - &native_mint, - &program_id, - ); - let result = process_test_command( - &config, - &payer, - &[ - "spl-token", - CommandName::Close.into(), - "--address", - &source.to_string(), - "--recipient", - &recipient.to_string(), - ], - ) - .await; - result.unwrap(); - - let ui_account = config - .rpc_client - .get_token_account(&recipient) - .await - .unwrap() - .unwrap(); - assert_eq!(ui_account.token_amount.amount, "10000000000"); - } - } - - #[tokio::test] - #[serial] - async fn disable_mint_authority() { - let (test_validator, payer) = new_validator_for_test().await; - for program_id in [spl_token::id(), spl_token_2022::id()] { - let config = test_config(&test_validator, &payer, &program_id); - let token = create_token(&config, &payer).await; - let result = process_test_command( - &config, - &payer, - &[ - "spl-token", - CommandName::Authorize.into(), - &token.to_string(), - "mint", - "--disable", - ], - ) - .await; - result.unwrap(); - - let account = config.rpc_client.get_account(&token).await.unwrap(); - let mint = Mint::unpack(&account.data).unwrap(); - assert_eq!(mint.mint_authority, COption::None); - } - } - - #[tokio::test] - #[serial] - async fn gc() { - let (test_validator, payer) = new_validator_for_test().await; - for program_id in [spl_token::id(), spl_token_2022::id()] { - let mut config = test_config(&test_validator, &payer, &program_id); - let token = create_token(&config, &payer).await; - let _account = create_associated_account(&config, &payer, token).await; - let _aux1 = create_auxiliary_account(&config, &payer, token).await; - let _aux2 = create_auxiliary_account(&config, &payer, token).await; - let _aux3 = create_auxiliary_account(&config, &payer, token).await; - let result = process_test_command( - &config, - &payer, - &[ - "spl-token", - CommandName::Accounts.into(), - &token.to_string(), - ], - ) - .await - .unwrap(); - let value: serde_json::Value = serde_json::from_str(&result).unwrap(); - assert_eq!(value["accounts"].as_array().unwrap().len(), 4); - config.output_format = OutputFormat::Display; // fixup eventually? - let _result = - process_test_command(&config, &payer, &["spl-token", CommandName::Gc.into()]) - .await - .unwrap(); - config.output_format = OutputFormat::JsonCompact; - let result = process_test_command( - &config, - &payer, - &[ - "spl-token", - CommandName::Accounts.into(), - &token.to_string(), - ], - ) - .await - .unwrap(); - let value: serde_json::Value = serde_json::from_str(&result).unwrap(); - assert_eq!(value["accounts"].as_array().unwrap().len(), 1); - } - } - - #[tokio::test] - #[serial] - async fn set_owner() { - let (test_validator, payer) = new_validator_for_test().await; - for program_id in [spl_token::id(), spl_token_2022::id()] { - let config = test_config(&test_validator, &payer, &program_id); - let token = create_token(&config, &payer).await; - let aux = create_auxiliary_account(&config, &payer, token).await; - let aux_string = aux.to_string(); - let _result = process_test_command( - &config, - &payer, - &[ - "spl-token", - CommandName::Authorize.into(), - &aux_string, - "owner", - &aux_string, - ], - ) - .await - .unwrap(); - let account = config.rpc_client.get_account(&aux).await.unwrap(); - let token_account = StateWithExtensionsOwned::::unpack(account.data).unwrap(); - assert_eq!(token_account.base.mint, token); - assert_eq!(token_account.base.owner, aux); - } - } - - #[tokio::test] - #[serial] - async fn transfer_with_account_delegate() { - let (test_validator, payer) = new_validator_for_test().await; - for program_id in [spl_token::id(), spl_token_2022::id()] { - let config = test_config(&test_validator, &payer, &program_id); - - let token = create_token(&config, &payer).await; - let source = create_associated_account(&config, &payer, token).await; - let destination = create_auxiliary_account(&config, &payer, token).await; - let delegate = Keypair::new(); - - let file = NamedTempFile::new().unwrap(); - write_keypair_file(&delegate, &file).unwrap(); - - let ui_amount = 100.0; - mint_tokens(&config, &payer, token, ui_amount, source).await; - - let ui_account = config - .rpc_client - .get_token_account(&source) - .await - .unwrap() - .unwrap(); - assert_eq!(ui_account.token_amount.amount, "100"); - assert_eq!(ui_account.delegate, None); - assert_eq!(ui_account.delegated_amount, None); - let ui_account = config - .rpc_client - .get_token_account(&destination) - .await - .unwrap() - .unwrap(); - assert_eq!(ui_account.token_amount.amount, "0"); - - process_test_command( - &config, - &payer, - &[ - "spl-token", - CommandName::Approve.into(), - &source.to_string(), - "10", - &delegate.pubkey().to_string(), - ], - ) - .await - .unwrap(); - - let ui_account = config - .rpc_client - .get_token_account(&source) - .await - .unwrap() - .unwrap(); - assert_eq!(ui_account.delegate.unwrap(), delegate.pubkey().to_string()); - assert_eq!(ui_account.delegated_amount.unwrap().amount, "10"); - - let result = process_test_command( - &config, - &payer, - &[ - "spl-token", - CommandName::Transfer.into(), - &token.to_string(), - "10", - &destination.to_string(), - "--from", - &source.to_string(), - "--owner", - file.path().to_str().unwrap(), - ], - ) - .await; - result.unwrap(); - - let ui_account = config - .rpc_client - .get_token_account(&source) - .await - .unwrap() - .unwrap(); - assert_eq!(ui_account.token_amount.amount, "90"); - assert_eq!(ui_account.delegate, None); - assert_eq!(ui_account.delegated_amount, None); - let ui_account = config - .rpc_client - .get_token_account(&destination) - .await - .unwrap() - .unwrap(); - assert_eq!(ui_account.token_amount.amount, "10"); - } - } - - #[tokio::test] - #[serial] - async fn burn_with_account_delegate() { - let (test_validator, payer) = new_validator_for_test().await; - for program_id in [spl_token::id(), spl_token_2022::id()] { - let config = test_config(&test_validator, &payer, &program_id); - - let token = create_token(&config, &payer).await; - let source = create_associated_account(&config, &payer, token).await; - let delegate = Keypair::new(); - - let file = NamedTempFile::new().unwrap(); - write_keypair_file(&delegate, &file).unwrap(); - - let ui_amount = 100.0; - mint_tokens(&config, &payer, token, ui_amount, source).await; - - let ui_account = config - .rpc_client - .get_token_account(&source) - .await - .unwrap() - .unwrap(); - assert_eq!(ui_account.token_amount.amount, "100"); - assert_eq!(ui_account.delegate, None); - assert_eq!(ui_account.delegated_amount, None); - - process_test_command( - &config, - &payer, - &[ - "spl-token", - CommandName::Approve.into(), - &source.to_string(), - "10", - &delegate.pubkey().to_string(), - ], - ) - .await - .unwrap(); - - let ui_account = config - .rpc_client - .get_token_account(&source) - .await - .unwrap() - .unwrap(); - assert_eq!(ui_account.delegate.unwrap(), delegate.pubkey().to_string()); - assert_eq!(ui_account.delegated_amount.unwrap().amount, "10"); - - let result = process_test_command( - &config, - &payer, - &[ - "spl-token", - CommandName::Burn.into(), - &source.to_string(), - "10", - "--owner", - file.path().to_str().unwrap(), - ], - ) - .await; - result.unwrap(); - - let ui_account = config - .rpc_client - .get_token_account(&source) - .await - .unwrap() - .unwrap(); - assert_eq!(ui_account.token_amount.amount, "90"); - assert_eq!(ui_account.delegate, None); - assert_eq!(ui_account.delegated_amount, None); - } - } -} diff --git a/token/cli/src/output.rs b/token/cli/src/output.rs deleted file mode 100644 index e4de48433e3..00000000000 --- a/token/cli/src/output.rs +++ /dev/null @@ -1,408 +0,0 @@ -use crate::{config::Config, sort::UnsupportedAccount}; -use console::Emoji; -use serde::{Deserialize, Serialize, Serializer}; -use solana_account_decoder::parse_token::{UiAccountState, UiTokenAccount, UiTokenAmount}; -use solana_cli_output::{display::writeln_name_value, OutputFormat, QuietDisplay, VerboseDisplay}; -use std::fmt::{self, Display}; - -pub(crate) trait Output: Serialize + fmt::Display + QuietDisplay + VerboseDisplay {} - -static WARNING: Emoji = Emoji("⚠️", "!"); - -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub(crate) struct CommandOutput -where - T: Serialize + Display + QuietDisplay + VerboseDisplay, -{ - pub(crate) command_name: String, - pub(crate) command_output: T, -} - -impl Display for CommandOutput -where - T: Serialize + Display + QuietDisplay + VerboseDisplay, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - Display::fmt(&self.command_output, f) - } -} - -impl QuietDisplay for CommandOutput -where - T: Serialize + Display + QuietDisplay + VerboseDisplay, -{ - fn write_str(&self, w: &mut dyn std::fmt::Write) -> std::fmt::Result { - QuietDisplay::write_str(&self.command_output, w) - } -} - -impl VerboseDisplay for CommandOutput -where - T: Serialize + Display + QuietDisplay + VerboseDisplay, -{ - fn write_str(&self, w: &mut dyn std::fmt::Write) -> std::fmt::Result { - writeln_name_value(w, "Command: ", &self.command_name)?; - VerboseDisplay::write_str(&self.command_output, w) - } -} - -pub(crate) fn println_display(config: &Config, message: String) { - match config.output_format { - OutputFormat::Display | OutputFormat::DisplayVerbose => { - println!("{}", message); - } - _ => {} - } -} - -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub(crate) struct CliMint -where - T: Serialize + Display + QuietDisplay + VerboseDisplay, -{ - pub(crate) address: String, - pub(crate) decimals: u8, - pub(crate) transaction_data: T, -} - -impl Display for CliMint -where - T: Serialize + Display + QuietDisplay + VerboseDisplay, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!(f)?; - writeln_name_value(f, "Address: ", &self.address)?; - writeln_name_value(f, "Decimals: ", &format!("{}", self.decimals))?; - Display::fmt(&self.transaction_data, f) - } -} -impl QuietDisplay for CliMint -where - T: Serialize + Display + QuietDisplay + VerboseDisplay, -{ - fn write_str(&self, w: &mut dyn std::fmt::Write) -> std::fmt::Result { - writeln!(w)?; - writeln_name_value(w, "Address: ", &self.address)?; - writeln_name_value(w, "Decimals: ", &format!("{}", self.decimals))?; - QuietDisplay::write_str(&self.transaction_data, w) - } -} -impl VerboseDisplay for CliMint -where - T: Serialize + Display + QuietDisplay + VerboseDisplay, -{ - fn write_str(&self, w: &mut dyn std::fmt::Write) -> std::fmt::Result { - writeln!(w)?; - writeln_name_value(w, "Address: ", &self.address)?; - writeln_name_value(w, "Decimals: ", &format!("{}", self.decimals))?; - VerboseDisplay::write_str(&self.transaction_data, w) - } -} - -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub(crate) struct CliTokenAmount { - #[serde(flatten)] - pub(crate) amount: UiTokenAmount, -} - -impl QuietDisplay for CliTokenAmount {} -impl VerboseDisplay for CliTokenAmount { - fn write_str(&self, w: &mut dyn fmt::Write) -> fmt::Result { - writeln!(w, "ui amount: {}", self.amount.real_number_string_trimmed())?; - writeln!(w, "decimals: {}", self.amount.decimals)?; - writeln!(w, "amount: {}", self.amount.amount) - } -} - -impl fmt::Display for CliTokenAmount { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - writeln!(f, "{}", self.amount.real_number_string_trimmed()) - } -} - -#[derive(Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub(crate) struct CliWalletAddress { - pub(crate) wallet_address: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) associated_token_address: Option, -} - -impl QuietDisplay for CliWalletAddress {} -impl VerboseDisplay for CliWalletAddress {} - -impl fmt::Display for CliWalletAddress { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - writeln!(f, "Wallet address: {}", self.wallet_address)?; - if let Some(associated_token_address) = &self.associated_token_address { - writeln!(f, "Associated token address: {}", associated_token_address)?; - } - Ok(()) - } -} - -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub(crate) struct CliMultisig { - pub(crate) address: String, - pub(crate) m: u8, - pub(crate) n: u8, - pub(crate) signers: Vec, -} - -impl QuietDisplay for CliMultisig {} -impl VerboseDisplay for CliMultisig {} - -impl fmt::Display for CliMultisig { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - writeln!(f)?; - writeln_name_value(f, "Address:", &self.address)?; - writeln_name_value(f, "M/N:", &format!("{}/{}", self.m, self.n))?; - writeln_name_value(f, "Signers:", " ")?; - let width = if self.n >= 9 { 4 } else { 3 }; - for i in 0..self.n as usize { - let title = format!("{1:>0$}:", width, i + 1); - let pubkey = &self.signers[i]; - writeln_name_value(f, &title, pubkey)?; - } - Ok(()) - } -} - -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub(crate) struct CliTokenAccount { - pub(crate) address: String, - pub(crate) is_associated: bool, - #[serde(flatten)] - pub(crate) account: UiTokenAccount, -} - -impl QuietDisplay for CliTokenAccount {} -impl VerboseDisplay for CliTokenAccount {} - -impl fmt::Display for CliTokenAccount { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - writeln!(f)?; - if self.is_associated { - writeln_name_value(f, "Address:", &self.address)?; - } else { - writeln_name_value(f, "Address:", &format!("{} (Aux*)", self.address))?; - } - writeln_name_value( - f, - "Balance:", - &self.account.token_amount.real_number_string_trimmed(), - )?; - let mint = format!( - "{}{}", - self.account.mint, - if self.account.is_native { - " (native)" - } else { - "" - } - ); - writeln_name_value(f, "Mint:", &mint)?; - writeln_name_value(f, "Owner:", &self.account.owner)?; - writeln_name_value(f, "State:", &format!("{:?}", self.account.state))?; - if let Some(delegate) = &self.account.delegate { - writeln!(f, "Delegation:")?; - writeln_name_value(f, " Delegate:", delegate)?; - let allowance = self.account.delegated_amount.as_ref().unwrap(); - writeln_name_value(f, " Allowance:", &allowance.real_number_string_trimmed())?; - } else { - writeln_name_value(f, "Delegation:", "")?; - } - writeln_name_value( - f, - "Close authority:", - self.account - .close_authority - .as_ref() - .unwrap_or(&String::new()), - )?; - if !self.is_associated { - writeln!(f)?; - writeln!(f, "* Please run `spl-token gc` to clean up Aux accounts")?; - } - Ok(()) - } -} - -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub(crate) struct CliTokenAccounts { - #[serde(serialize_with = "flattened")] - pub(crate) accounts: Vec>, - #[serde(skip_serializing_if = "Vec::is_empty")] - pub(crate) unsupported_accounts: Vec, - #[serde(skip_serializing)] - pub(crate) max_len_balance: usize, - #[serde(skip_serializing)] - pub(crate) aux_len: usize, - #[serde(skip_serializing)] - pub(crate) token_is_some: bool, -} - -impl QuietDisplay for CliTokenAccounts {} -impl VerboseDisplay for CliTokenAccounts { - fn write_str(&self, w: &mut dyn fmt::Write) -> fmt::Result { - let mut gc_alert = false; - if self.token_is_some { - writeln!( - w, - "{:<44} {:<2$}", - "Account", "Balance", self.max_len_balance - )?; - writeln!( - w, - "-------------------------------------------------------------" - )?; - } else { - writeln!( - w, - "{:<44} {:<44} {:<3$}", - "Token", "Account", "Balance", self.max_len_balance - )?; - writeln!(w, "----------------------------------------------------------------------------------------------------------")?; - } - for accounts_list in self.accounts.iter() { - let mut aux_counter = 1; - for account in accounts_list { - let maybe_aux = if !account.is_associated { - gc_alert = true; - let message = format!(" (Aux-{}*)", aux_counter); - aux_counter += 1; - message - } else { - "".to_string() - }; - let maybe_frozen = if let UiAccountState::Frozen = account.account.state { - format!(" {} Frozen", WARNING) - } else { - "".to_string() - }; - if self.token_is_some { - writeln!( - w, - "{:<44} {:<4$}{:<5$}{}", - account.address, - account.account.token_amount.real_number_string_trimmed(), - maybe_aux, - maybe_frozen, - self.max_len_balance, - self.aux_len, - )?; - } else { - writeln!( - w, - "{:<44} {:<44} {:<5$}{:<6$}{}", - account.account.mint, - account.address, - account.account.token_amount.real_number_string_trimmed(), - maybe_aux, - maybe_frozen, - self.max_len_balance, - self.aux_len, - )?; - } - } - } - for unsupported_account in &self.unsupported_accounts { - writeln!( - w, - "{:<44} {}", - unsupported_account.address, unsupported_account.err - )?; - } - if gc_alert { - writeln!(w)?; - writeln!(w, "* Please run `spl-token gc` to clean up Aux accounts")?; - } - Ok(()) - } -} - -impl fmt::Display for CliTokenAccounts { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut gc_alert = false; - if self.token_is_some { - writeln!(f, "{:<1$}", "Balance", self.max_len_balance)?; - writeln!(f, "-------------")?; - } else { - writeln!( - f, - "{:<44} {:<2$}", - "Token", "Balance", self.max_len_balance - )?; - writeln!( - f, - "---------------------------------------------------------------" - )?; - } - for accounts_list in self.accounts.iter() { - let mut aux_counter = 1; - for account in accounts_list { - let maybe_aux = if !account.is_associated { - gc_alert = true; - let message = format!(" (Aux-{}*)", aux_counter); - aux_counter += 1; - message - } else { - "".to_string() - }; - let maybe_frozen = if let UiAccountState::Frozen = account.account.state { - format!(" {} Frozen", WARNING) - } else { - "".to_string() - }; - if self.token_is_some { - writeln!( - f, - "{:<3$}{:<4$}{}", - account.account.token_amount.real_number_string_trimmed(), - maybe_aux, - maybe_frozen, - self.max_len_balance, - self.aux_len, - )?; - } else { - writeln!( - f, - "{:<44} {:<4$}{:<5$}{}", - account.account.mint, - account.account.token_amount.real_number_string_trimmed(), - maybe_aux, - maybe_frozen, - self.max_len_balance, - self.aux_len, - )?; - } - } - } - for unsupported_account in &self.unsupported_accounts { - writeln!( - f, - "{:<44} {}", - unsupported_account.address, unsupported_account.err - )?; - } - if gc_alert { - writeln!(f)?; - writeln!(f, "* Please run `spl-token gc` to clean up Aux accounts")?; - } - Ok(()) - } -} - -fn flattened( - vec: &[Vec], - serializer: S, -) -> Result { - let flattened: Vec<_> = vec.iter().flatten().collect(); - flattened.serialize(serializer) -} diff --git a/token/cli/src/sort.rs b/token/cli/src/sort.rs deleted file mode 100644 index 725a7ba71ea..00000000000 --- a/token/cli/src/sort.rs +++ /dev/null @@ -1,97 +0,0 @@ -use crate::output::CliTokenAccount; -use serde::{Deserialize, Serialize}; -use solana_account_decoder::{parse_token::TokenAccountType, UiAccountData}; -use solana_client::rpc_response::RpcKeyedAccount; -use solana_sdk::pubkey::Pubkey; -use std::{ - collections::{btree_map::Entry, BTreeMap}, - str::FromStr, -}; - -pub(crate) type MintAccounts = BTreeMap>; - -#[derive(Serialize, Deserialize)] -pub(crate) struct UnsupportedAccount { - pub address: String, - pub err: String, -} - -pub(crate) fn is_supported_program(program_name: &str) -> bool { - program_name == "spl-token" || program_name == "spl-token-2022" -} - -pub(crate) fn sort_and_parse_token_accounts( - owner: &Pubkey, - accounts: Vec, - program_id: &Pubkey, -) -> (MintAccounts, Vec, usize, bool) { - let mut mint_accounts: MintAccounts = BTreeMap::new(); - let mut unsupported_accounts = vec![]; - let mut max_len_balance = 0; - let mut includes_aux = false; - for keyed_account in accounts { - let address = keyed_account.pubkey; - - if let UiAccountData::Json(parsed_account) = keyed_account.account.data { - if !is_supported_program(&parsed_account.program) { - unsupported_accounts.push(UnsupportedAccount { - address, - err: format!("Unsupported account program: {}", parsed_account.program), - }); - } else { - match serde_json::from_value(parsed_account.parsed) { - Ok(TokenAccountType::Account(ui_token_account)) => { - let mint = ui_token_account.mint.clone(); - let is_associated = if let Ok(mint) = Pubkey::from_str(&mint) { - spl_associated_token_account::get_associated_token_address_with_program_id(owner, &mint, program_id).to_string() == address - } else { - includes_aux = true; - false - }; - let len_balance = ui_token_account - .token_amount - .real_number_string_trimmed() - .len(); - max_len_balance = max_len_balance.max(len_balance); - let parsed_account = CliTokenAccount { - address, - account: ui_token_account, - is_associated, - }; - let entry = mint_accounts.entry(mint); - match entry { - Entry::Occupied(_) => { - entry.and_modify(|e| e.push(parsed_account)); - } - Entry::Vacant(_) => { - entry.or_insert_with(|| vec![parsed_account]); - } - } - } - Ok(_) => unsupported_accounts.push(UnsupportedAccount { - address, - err: "Not a token account".to_string(), - }), - Err(err) => unsupported_accounts.push(UnsupportedAccount { - address, - err: format!("Account parse failure: {}", err), - }), - } - } - } else { - unsupported_accounts.push(UnsupportedAccount { - address, - err: "Unsupported account data format".to_string(), - }); - } - } - for (_, array) in mint_accounts.iter_mut() { - array.sort_by(|a, b| b.is_associated.cmp(&a.is_associated)); - } - ( - mint_accounts, - unsupported_accounts, - max_len_balance, - includes_aux, - ) -} diff --git a/token/cli/tests/config.rs b/token/cli/tests/config.rs deleted file mode 100644 index ff0bfad9dfb..00000000000 --- a/token/cli/tests/config.rs +++ /dev/null @@ -1,11 +0,0 @@ -use assert_cmd::cmd::Command; - -#[test] -fn invalid_config_will_cause_commands_to_fail() { - let mut cmd = Command::cargo_bin("spl-token").unwrap(); - let args = &["address", "--config", "~/nonexistent/config.yml"]; - cmd.args(args) - .assert() - .stderr("error: Could not find config file `~/nonexistent/config.yml`\n"); - cmd.args(args).assert().code(1).failure(); -} diff --git a/token/client/Cargo.toml b/token/client/Cargo.toml deleted file mode 100644 index 52084f18a37..00000000000 --- a/token/client/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -authors = ["Solana Maintainers "] -description = "SPL-Token Rust Client" -edition = "2018" -license = "Apache-2.0" -name = "spl-token-client" -repository = "https://github.com/solana-labs/solana-program-library" -version = "0.1.0" - -[dependencies] -async-trait = "0.1" -solana-client = "=1.10.33" -solana-program-test = "=1.10.33" -solana-sdk = "=1.10.33" -# We never want the entrypoint for ATA, but we want the entrypoint for token when -# testing token -spl-associated-token-account = { version = "1.0.5", path = "../../associated-token-account/program", features = ["no-entrypoint"] } -spl-memo = { version = "3.0.1", path = "../../memo/program", features = ["no-entrypoint"] } -spl-token-2022 = { version = "0.4", path="../program-2022" } -thiserror = "1.0" diff --git a/token/client/src/client.rs b/token/client/src/client.rs deleted file mode 100644 index 24cef85edac..00000000000 --- a/token/client/src/client.rs +++ /dev/null @@ -1,242 +0,0 @@ -use { - async_trait::async_trait, - solana_client::nonblocking::rpc_client::RpcClient, - solana_program_test::{tokio::sync::Mutex, BanksClient, ProgramTestContext}, - solana_sdk::{ - account::Account, hash::Hash, pubkey::Pubkey, signature::Signature, - transaction::Transaction, - }, - std::{fmt, future::Future, pin::Pin, sync::Arc}, -}; - -type BoxFuture<'a, T> = Pin + Send + 'a>>; - -/// Basic trait for sending transactions to validator. -pub trait SendTransaction { - type Output; -} - -/// Extends basic `SendTransaction` trait with function `send` where client is `&mut BanksClient`. -/// Required for `ProgramBanksClient`. -pub trait SendTransactionBanksClient: SendTransaction { - fn send<'a>( - &self, - client: &'a mut BanksClient, - transaction: Transaction, - ) -> BoxFuture<'a, ProgramClientResult>; -} - -/// Send transaction to validator using `BanksClient::process_transaction`. -#[derive(Debug, Clone, Copy, Default)] -pub struct ProgramBanksClientProcessTransaction; - -impl SendTransaction for ProgramBanksClientProcessTransaction { - type Output = (); -} - -impl SendTransactionBanksClient for ProgramBanksClientProcessTransaction { - fn send<'a>( - &self, - client: &'a mut BanksClient, - transaction: Transaction, - ) -> BoxFuture<'a, ProgramClientResult> { - Box::pin(async move { - client - .process_transaction(transaction) - .await - .map_err(Into::into) - }) - } -} - -/// Extends basic `SendTransaction` trait with function `send` where client is `&RpcClient`. -/// Required for `ProgramRpcClient`. -pub trait SendTransactionRpc: SendTransaction { - fn send<'a>( - &self, - client: &'a RpcClient, - transaction: &'a Transaction, - ) -> BoxFuture<'a, ProgramClientResult>; -} - -#[derive(Debug, Clone, Copy, Default)] -pub struct ProgramRpcClientSendTransaction; - -impl SendTransaction for ProgramRpcClientSendTransaction { - type Output = Signature; -} - -impl SendTransactionRpc for ProgramRpcClientSendTransaction { - fn send<'a>( - &self, - client: &'a RpcClient, - transaction: &'a Transaction, - ) -> BoxFuture<'a, ProgramClientResult> { - Box::pin(async move { - client - .send_and_confirm_transaction(transaction) - .await - .map_err(Into::into) - }) - } -} - -// -pub type ProgramClientError = Box; -pub type ProgramClientResult = Result; - -/// Generic client interface for programs. -#[async_trait] -pub trait ProgramClient -where - ST: SendTransaction, -{ - async fn get_minimum_balance_for_rent_exemption( - &self, - data_len: usize, - ) -> ProgramClientResult; - - async fn get_latest_blockhash(&self) -> ProgramClientResult; - - async fn send_transaction(&self, transaction: &Transaction) -> ProgramClientResult; - - async fn get_account(&self, address: Pubkey) -> ProgramClientResult>; -} - -enum ProgramBanksClientContext { - Client(Arc>), - Context(Arc>), -} - -/// Program client for `BanksClient` from crate `solana-program-test`. -pub struct ProgramBanksClient { - context: ProgramBanksClientContext, - send: ST, -} - -impl fmt::Debug for ProgramBanksClient { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ProgramBanksClient").finish() - } -} - -impl ProgramBanksClient { - fn new(context: ProgramBanksClientContext, send: ST) -> Self { - Self { context, send } - } - - pub fn new_from_client(client: Arc>, send: ST) -> Self { - Self::new(ProgramBanksClientContext::Client(client), send) - } - - pub fn new_from_context(context: Arc>, send: ST) -> Self { - Self::new(ProgramBanksClientContext::Context(context), send) - } - - async fn run_in_lock(&self, f: F) -> O - where - for<'a> F: Fn(&'a mut BanksClient) -> BoxFuture<'a, O>, - { - match &self.context { - ProgramBanksClientContext::Client(client) => { - let mut lock = client.lock().await; - f(&mut lock).await - } - ProgramBanksClientContext::Context(context) => { - let mut lock = context.lock().await; - f(&mut lock.banks_client).await - } - } - } -} - -#[async_trait] -impl ProgramClient for ProgramBanksClient -where - ST: SendTransactionBanksClient + Send + Sync, -{ - async fn get_minimum_balance_for_rent_exemption( - &self, - data_len: usize, - ) -> ProgramClientResult { - self.run_in_lock(|client| { - Box::pin(async move { - let rent = client.get_rent().await?; - Ok(rent.minimum_balance(data_len)) - }) - }) - .await - } - - async fn get_latest_blockhash(&self) -> ProgramClientResult { - self.run_in_lock(|client| { - Box::pin(async move { client.get_latest_blockhash().await.map_err(Into::into) }) - }) - .await - } - - async fn send_transaction(&self, transaction: &Transaction) -> ProgramClientResult { - self.run_in_lock(|client| { - let transaction = transaction.clone(); - self.send.send(client, transaction) - }) - .await - } - - async fn get_account(&self, address: Pubkey) -> ProgramClientResult> { - self.run_in_lock(|client| { - Box::pin(async move { client.get_account(address).await.map_err(Into::into) }) - }) - .await - } -} - -/// Program client for `RpcClient` from crate `solana-client`. -pub struct ProgramRpcClient { - client: Arc, - send: ST, -} - -impl fmt::Debug for ProgramRpcClient { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ProgramRpcClient").finish() - } -} - -impl ProgramRpcClient { - pub fn new(client: Arc, send: ST) -> Self { - Self { client, send } - } -} - -#[async_trait] -impl ProgramClient for ProgramRpcClient -where - ST: SendTransactionRpc + Send + Sync, -{ - async fn get_minimum_balance_for_rent_exemption( - &self, - data_len: usize, - ) -> ProgramClientResult { - self.client - .get_minimum_balance_for_rent_exemption(data_len) - .await - .map_err(Into::into) - } - - async fn get_latest_blockhash(&self) -> ProgramClientResult { - self.client.get_latest_blockhash().await.map_err(Into::into) - } - - async fn send_transaction(&self, transaction: &Transaction) -> ProgramClientResult { - self.send.send(&self.client, transaction).await - } - - async fn get_account(&self, address: Pubkey) -> ProgramClientResult> { - Ok(self - .client - .get_account_with_commitment(&address, self.client.commitment()) - .await? - .value) - } -} diff --git a/token/client/src/lib.rs b/token/client/src/lib.rs deleted file mode 100644 index e512e638357..00000000000 --- a/token/client/src/lib.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod client; -pub mod token; - -pub use spl_token_2022; diff --git a/token/client/src/token.rs b/token/client/src/token.rs deleted file mode 100644 index 85fd58d19ea..00000000000 --- a/token/client/src/token.rs +++ /dev/null @@ -1,1807 +0,0 @@ -use { - crate::client::{ProgramClient, ProgramClientError, SendTransaction}, - solana_program_test::tokio::time, - solana_sdk::{ - account::Account as BaseAccount, - epoch_info::EpochInfo, - hash::Hash, - instruction::Instruction, - program_error::ProgramError, - pubkey::Pubkey, - signer::{signers::Signers, Signer, SignerError}, - system_instruction, - transaction::Transaction, - }, - spl_associated_token_account::{ - get_associated_token_address_with_program_id, instruction::create_associated_token_account, - }, - spl_token_2022::{ - extension::{ - confidential_transfer, default_account_state, interest_bearing_mint, memo_transfer, - transfer_fee, ExtensionType, StateWithExtensionsOwned, - }, - instruction, native_mint, - solana_zk_token_sdk::{ - encryption::{auth_encryption::*, elgamal::*}, - errors::ProofError, - instruction::transfer_with_fee::FeeParameters, - }, - state::{Account, AccountState, Mint}, - }, - std::{ - convert::TryInto, - fmt, io, - sync::{Arc, RwLock}, - time::{Duration, Instant}, - }, - thiserror::Error, -}; - -#[derive(Error, Debug)] -pub enum TokenError { - #[error("client error: {0}")] - Client(ProgramClientError), - #[error("program error: {0}")] - Program(#[from] ProgramError), - #[error("account not found")] - AccountNotFound, - #[error("invalid account owner")] - AccountInvalidOwner, - #[error("invalid account mint")] - AccountInvalidMint, - #[error("proof error: {0}")] - Proof(ProofError), - #[error("maximum deposit transfer amount exceeded")] - MaximumDepositTransferAmountExceeded, - #[error("encryption key error")] - Key(SignerError), - #[error("account decryption failed")] - AccountDecryption, - #[error("not enough funds in account")] - NotEnoughFunds, -} -impl PartialEq for TokenError { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - // TODO not great, but workable for tests - (Self::Client(ref a), Self::Client(ref b)) => a.to_string() == b.to_string(), - (Self::Program(ref a), Self::Program(ref b)) => a == b, - (Self::AccountNotFound, Self::AccountNotFound) => true, - (Self::AccountInvalidOwner, Self::AccountInvalidOwner) => true, - (Self::AccountInvalidMint, Self::AccountInvalidMint) => true, - _ => false, - } - } -} - -/// Encapsulates initializing an extension -#[derive(Clone, Debug, PartialEq)] -pub enum ExtensionInitializationParams { - ConfidentialTransferMint { - ct_mint: confidential_transfer::ConfidentialTransferMint, - }, - DefaultAccountState { - state: AccountState, - }, - MintCloseAuthority { - close_authority: Option, - }, - TransferFeeConfig { - transfer_fee_config_authority: Option, - withdraw_withheld_authority: Option, - transfer_fee_basis_points: u16, - maximum_fee: u64, - }, - InterestBearingConfig { - rate_authority: Option, - rate: i16, - }, -} -impl ExtensionInitializationParams { - /// Get the extension type associated with the init params - pub fn extension(&self) -> ExtensionType { - match self { - Self::ConfidentialTransferMint { .. } => ExtensionType::ConfidentialTransferMint, - Self::DefaultAccountState { .. } => ExtensionType::DefaultAccountState, - Self::MintCloseAuthority { .. } => ExtensionType::MintCloseAuthority, - Self::TransferFeeConfig { .. } => ExtensionType::TransferFeeConfig, - Self::InterestBearingConfig { .. } => ExtensionType::InterestBearingConfig, - } - } - /// Generate an appropriate initialization instruction for the given mint - pub fn instruction( - self, - token_program_id: &Pubkey, - mint: &Pubkey, - ) -> Result { - match self { - Self::ConfidentialTransferMint { ct_mint } => { - confidential_transfer::instruction::initialize_mint( - token_program_id, - mint, - &ct_mint, - ) - } - Self::DefaultAccountState { state } => { - default_account_state::instruction::initialize_default_account_state( - token_program_id, - mint, - &state, - ) - } - Self::MintCloseAuthority { close_authority } => { - instruction::initialize_mint_close_authority( - token_program_id, - mint, - close_authority.as_ref(), - ) - } - Self::TransferFeeConfig { - transfer_fee_config_authority, - withdraw_withheld_authority, - transfer_fee_basis_points, - maximum_fee, - } => transfer_fee::instruction::initialize_transfer_fee_config( - token_program_id, - mint, - transfer_fee_config_authority.as_ref(), - withdraw_withheld_authority.as_ref(), - transfer_fee_basis_points, - maximum_fee, - ), - Self::InterestBearingConfig { - rate_authority, - rate, - } => interest_bearing_mint::instruction::initialize( - token_program_id, - mint, - rate_authority, - rate, - ), - } - } -} - -pub type TokenResult = Result; - -pub struct Token { - client: Arc>, - pubkey: Pubkey, /*token mint*/ - payer: S, - program_id: Pubkey, - memo: Arc>>, -} - -impl fmt::Debug for Token -where - S: Signer, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Token") - .field("pubkey", &self.pubkey) - .field("payer", &self.payer.pubkey()) - .field("memo", &self.memo.read().unwrap()) - .finish() - } -} - -impl Token -where - T: SendTransaction, - S: Signer, -{ - pub fn new( - client: Arc>, - program_id: &Pubkey, - address: &Pubkey, - payer: S, - ) -> Self { - Token { - client, - pubkey: *address, - payer, - program_id: *program_id, - memo: Arc::new(RwLock::new(None)), - } - } - - /// Get token address. - pub fn get_address(&self) -> &Pubkey { - &self.pubkey - } - - pub fn with_payer(&self, payer: S2) -> Token { - Token { - client: Arc::clone(&self.client), - pubkey: self.pubkey, - payer, - program_id: self.program_id, - memo: Arc::new(RwLock::new(None)), - } - } - - pub fn with_memo>(&self, memo: M) -> &Self { - let mut w_memo = self.memo.write().unwrap(); - *w_memo = Some(memo.as_ref().to_string()); - self - } - - pub async fn get_new_latest_blockhash(&self) -> TokenResult { - let blockhash = self - .client - .get_latest_blockhash() - .await - .map_err(TokenError::Client)?; - let start = Instant::now(); - let mut num_retries = 0; - while start.elapsed().as_secs() < 5 { - let new_blockhash = self - .client - .get_latest_blockhash() - .await - .map_err(TokenError::Client)?; - if new_blockhash != blockhash { - return Ok(new_blockhash); - } - - time::sleep(Duration::from_millis(200)).await; - num_retries += 1; - } - - Err(TokenError::Client(Box::new(io::Error::new( - io::ErrorKind::Other, - format!( - "Unable to get new blockhash after {}ms (retried {} times), stuck at {}", - start.elapsed().as_millis(), - num_retries, - blockhash - ), - )))) - } - - pub async fn process_ixs( - &self, - token_instructions: &[Instruction], - signing_keypairs: &S2, - ) -> TokenResult { - let mut instructions = vec![]; - let mut w_memo = self.memo.write().unwrap(); - if let Some(memo) = w_memo.take() { - instructions.push(spl_memo::build_memo(memo.as_bytes(), &[])); - } - instructions.extend_from_slice(token_instructions); - let latest_blockhash = self - .client - .get_latest_blockhash() - .await - .map_err(TokenError::Client)?; - - let mut tx = Transaction::new_with_payer(&instructions, Some(&self.payer.pubkey())); - tx.try_partial_sign(&[&self.payer], latest_blockhash) - .map_err(|error| TokenError::Client(error.into()))?; - tx.try_sign(signing_keypairs, latest_blockhash) - .map_err(|error| TokenError::Client(error.into()))?; - - self.client - .send_transaction(&tx) - .await - .map_err(TokenError::Client) - } - - /// Create and initialize a token. - #[allow(clippy::too_many_arguments)] - pub async fn create_mint<'a, S2: Signer>( - client: Arc>, - program_id: &'a Pubkey, - payer: S, - mint_account: &'a S2, - mint_authority: &'a Pubkey, - freeze_authority: Option<&'a Pubkey>, - decimals: u8, - extension_initialization_params: Vec, - ) -> TokenResult { - let mint_pubkey = mint_account.pubkey(); - let extension_types = extension_initialization_params - .iter() - .map(|e| e.extension()) - .collect::>(); - let space = ExtensionType::get_account_len::(&extension_types); - let token = Self::new(client, program_id, &mint_account.pubkey(), payer); - let mut instructions = vec![system_instruction::create_account( - &token.payer.pubkey(), - &mint_pubkey, - token - .client - .get_minimum_balance_for_rent_exemption(space) - .await - .map_err(TokenError::Client)?, - space as u64, - program_id, - )]; - for params in extension_initialization_params { - instructions.push(params.instruction(program_id, &mint_pubkey)?); - } - instructions.push(instruction::initialize_mint( - program_id, - &mint_pubkey, - mint_authority, - freeze_authority, - decimals, - )?); - token.process_ixs(&instructions, &[mint_account]).await?; - - Ok(token) - } - - /// Create native mint - pub async fn create_native_mint( - client: Arc>, - program_id: &Pubkey, - payer: S, - ) -> TokenResult { - let token = Self::new(client, program_id, &native_mint::id(), payer); - token - .process_ixs::<[&dyn Signer; 0]>( - &[instruction::create_native_mint( - program_id, - &token.payer.pubkey(), - )?], - &[], - ) - .await?; - - Ok(token) - } - - /// Get the address for the associated token account. - pub fn get_associated_token_address(&self, owner: &Pubkey) -> Pubkey { - get_associated_token_address_with_program_id(owner, &self.pubkey, &self.program_id) - } - - /// Create and initialize the associated account. - pub async fn create_associated_token_account(&self, owner: &Pubkey) -> TokenResult { - self.process_ixs::<[&dyn Signer; 0]>( - &[create_associated_token_account( - &self.payer.pubkey(), - owner, - &self.pubkey, - &self.program_id, - )], - &[], - ) - .await - .map(|_| self.get_associated_token_address(owner)) - .map_err(Into::into) - } - - /// Create and initialize a new token account. - pub async fn create_auxiliary_token_account( - &self, - account: &S, - owner: &Pubkey, - ) -> TokenResult { - self.create_auxiliary_token_account_with_extension_space(account, owner, vec![]) - .await - } - - /// Create and initialize a new token account. - pub async fn create_auxiliary_token_account_with_extension_space( - &self, - account: &S, - owner: &Pubkey, - extensions: Vec, - ) -> TokenResult { - let state = self.get_mint_info().await?; - let mint_extensions: Vec = state.get_extension_types()?; - let mut required_extensions = - ExtensionType::get_required_init_account_extensions(&mint_extensions); - for extension_type in extensions.into_iter() { - if !required_extensions.contains(&extension_type) { - required_extensions.push(extension_type); - } - } - let space = ExtensionType::get_account_len::(&required_extensions); - self.process_ixs( - &[ - system_instruction::create_account( - &self.payer.pubkey(), - &account.pubkey(), - self.client - .get_minimum_balance_for_rent_exemption(space) - .await - .map_err(TokenError::Client)?, - space as u64, - &self.program_id, - ), - instruction::initialize_account( - &self.program_id, - &account.pubkey(), - &self.pubkey, - owner, - )?, - ], - &[account], - ) - .await - .map(|_| account.pubkey()) - .map_err(Into::into) - } - - /// Retrieve a raw account - pub async fn get_account(&self, account: &Pubkey) -> TokenResult { - self.client - .get_account(*account) - .await - .map_err(TokenError::Client)? - .ok_or(TokenError::AccountNotFound) - } - - /// Retrive mint information. - pub async fn get_mint_info(&self) -> TokenResult> { - let account = self.get_account(&self.pubkey).await?; - if account.owner != self.program_id { - return Err(TokenError::AccountInvalidOwner); - } - - StateWithExtensionsOwned::::unpack(account.data).map_err(Into::into) - } - - /// Retrieve account information. - pub async fn get_account_info( - &self, - account: &Pubkey, - ) -> TokenResult> { - let account = self.get_account(account).await?; - if account.owner != self.program_id { - return Err(TokenError::AccountInvalidOwner); - } - let account = StateWithExtensionsOwned::::unpack(account.data)?; - if account.base.mint != *self.get_address() { - return Err(TokenError::AccountInvalidMint); - } - - Ok(account) - } - - /// Retrieve the associated account or create one if not found. - pub async fn get_or_create_associated_account_info( - &self, - owner: &Pubkey, - ) -> TokenResult> { - let account = self.get_associated_token_address(owner); - match self.get_account_info(&account).await { - Ok(account) => Ok(account), - // AccountInvalidOwner is possible if account already received some lamports. - Err(TokenError::AccountNotFound) | Err(TokenError::AccountInvalidOwner) => { - self.create_associated_token_account(owner).await?; - self.get_account_info(&account).await - } - Err(error) => Err(error), - } - } - - /// Assign a new authority to the account. - pub async fn set_authority( - &self, - account: &Pubkey, - new_authority: Option<&Pubkey>, - authority_type: instruction::AuthorityType, - owner: &S2, - ) -> TokenResult<()> { - self.process_ixs( - &[instruction::set_authority( - &self.program_id, - account, - new_authority, - authority_type, - &owner.pubkey(), - &[], - )?], - &[owner], - ) - .await - .map(|_| ()) - } - - /// Mint new tokens - pub async fn mint_to( - &self, - destination: &Pubkey, - authority: &S2, - amount: u64, - ) -> TokenResult<()> { - self.process_ixs( - &[instruction::mint_to( - &self.program_id, - &self.pubkey, - destination, - &authority.pubkey(), - &[], - amount, - )?], - &[authority], - ) - .await - .map(|_| ()) - } - - /// Transfer tokens to another account - pub async fn transfer_unchecked( - &self, - source: &Pubkey, - destination: &Pubkey, - authority: &S2, - amount: u64, - ) -> TokenResult { - self.process_ixs( - #[allow(deprecated)] - &[instruction::transfer( - &self.program_id, - source, - destination, - &authority.pubkey(), - &[], - amount, - )?], - &[authority], - ) - .await - } - - /// Transfer tokens to another account - pub async fn transfer_checked( - &self, - source: &Pubkey, - destination: &Pubkey, - authority: &S2, - amount: u64, - decimals: u8, - ) -> TokenResult { - self.process_ixs( - &[instruction::transfer_checked( - &self.program_id, - source, - &self.pubkey, - destination, - &authority.pubkey(), - &[], - amount, - decimals, - )?], - &[authority], - ) - .await - } - - /// Transfer tokens to another account, given an expected fee - pub async fn transfer_checked_with_fee( - &self, - source: &Pubkey, - destination: &Pubkey, - authority: &S2, - amount: u64, - decimals: u8, - fee: u64, - ) -> TokenResult { - self.process_ixs( - &[transfer_fee::instruction::transfer_checked_with_fee( - &self.program_id, - source, - &self.pubkey, - destination, - &authority.pubkey(), - &[], - amount, - decimals, - fee, - )?], - &[authority], - ) - .await - } - - /// Burn tokens from account - pub async fn burn( - &self, - source: &Pubkey, - authority: &S2, - amount: u64, - ) -> TokenResult { - self.process_ixs( - &[instruction::burn( - &self.program_id, - source, - &self.pubkey, - &authority.pubkey(), - &[], - amount, - )?], - &[authority], - ) - .await - } - - /// Burn tokens from account - pub async fn burn_checked( - &self, - source: &Pubkey, - authority: &S2, - amount: u64, - decimals: u8, - ) -> TokenResult { - self.process_ixs( - &[instruction::burn_checked( - &self.program_id, - source, - &self.pubkey, - &authority.pubkey(), - &[], - amount, - decimals, - )?], - &[authority], - ) - .await - } - - /// Approve a delegate to spend tokens - pub async fn approve( - &self, - source: &Pubkey, - delegate: &Pubkey, - authority: &S2, - amount: u64, - ) -> TokenResult { - self.process_ixs( - &[instruction::approve( - &self.program_id, - source, - delegate, - &authority.pubkey(), - &[], - amount, - )?], - &[authority], - ) - .await - } - - /// Approve a delegate to spend tokens, with decimal check - pub async fn approve_checked( - &self, - source: &Pubkey, - delegate: &Pubkey, - authority: &S2, - amount: u64, - decimals: u8, - ) -> TokenResult { - self.process_ixs( - &[instruction::approve_checked( - &self.program_id, - source, - &self.pubkey, - delegate, - &authority.pubkey(), - &[], - amount, - decimals, - )?], - &[authority], - ) - .await - } - - /// Revoke a delegate - pub async fn revoke( - &self, - source: &Pubkey, - authority: &S2, - ) -> TokenResult { - self.process_ixs( - &[instruction::revoke( - &self.program_id, - source, - &authority.pubkey(), - &[], - )?], - &[authority], - ) - .await - } - - /// Close account into another - pub async fn close_account( - &self, - account: &Pubkey, - destination: &Pubkey, - authority: &S2, - ) -> TokenResult { - self.process_ixs( - &[instruction::close_account( - &self.program_id, - account, - destination, - &authority.pubkey(), - &[], - )?], - &[authority], - ) - .await - } - - /// Freeze a token account - pub async fn freeze_account( - &self, - account: &Pubkey, - authority: &S2, - ) -> TokenResult { - self.process_ixs( - &[instruction::freeze_account( - &self.program_id, - account, - &self.pubkey, - &authority.pubkey(), - &[], - )?], - &[authority], - ) - .await - } - - /// Thaw / unfreeze a token account - pub async fn thaw_account( - &self, - account: &Pubkey, - authority: &S2, - ) -> TokenResult { - self.process_ixs( - &[instruction::thaw_account( - &self.program_id, - account, - &self.pubkey, - &authority.pubkey(), - &[], - )?], - &[authority], - ) - .await - } - - /// Sync native account lamports - pub async fn sync_native(&self, account: &Pubkey) -> TokenResult { - self.process_ixs::<[&dyn Signer; 0]>( - &[instruction::sync_native(&self.program_id, account)?], - &[], - ) - .await - } - - /// Set transfer fee - pub async fn set_transfer_fee( - &self, - authority: &S2, - transfer_fee_basis_points: u16, - maximum_fee: u64, - ) -> TokenResult { - self.process_ixs( - &[transfer_fee::instruction::set_transfer_fee( - &self.program_id, - &self.pubkey, - &authority.pubkey(), - &[], - transfer_fee_basis_points, - maximum_fee, - )?], - &[authority], - ) - .await - } - - /// Set default account state on mint - pub async fn set_default_account_state( - &self, - authority: &S2, - state: &AccountState, - ) -> TokenResult { - self.process_ixs( - &[ - default_account_state::instruction::update_default_account_state( - &self.program_id, - &self.pubkey, - &authority.pubkey(), - &[], - state, - )?, - ], - &[authority], - ) - .await - } - - /// Harvest withheld tokens to mint - pub async fn harvest_withheld_tokens_to_mint( - &self, - sources: &[&Pubkey], - ) -> TokenResult { - self.process_ixs::<[&dyn Signer; 0]>( - &[transfer_fee::instruction::harvest_withheld_tokens_to_mint( - &self.program_id, - &self.pubkey, - sources, - )?], - &[], - ) - .await - } - - /// Withdraw withheld tokens from mint - pub async fn withdraw_withheld_tokens_from_mint( - &self, - destination: &Pubkey, - authority: &S2, - ) -> TokenResult { - self.process_ixs( - &[ - transfer_fee::instruction::withdraw_withheld_tokens_from_mint( - &self.program_id, - &self.pubkey, - destination, - &authority.pubkey(), - &[], - )?, - ], - &[authority], - ) - .await - } - - /// Withdraw withheld tokens from accounts - pub async fn withdraw_withheld_tokens_from_accounts( - &self, - destination: &Pubkey, - authority: &S2, - sources: &[&Pubkey], - ) -> TokenResult { - self.process_ixs( - &[ - transfer_fee::instruction::withdraw_withheld_tokens_from_accounts( - &self.program_id, - &self.pubkey, - destination, - &authority.pubkey(), - &[], - sources, - )?, - ], - &[authority], - ) - .await - } - - /// Reallocate a token account to be large enough for a set of ExtensionTypes - pub async fn reallocate( - &self, - account: &Pubkey, - authority: &S2, - extension_types: &[ExtensionType], - ) -> TokenResult { - self.process_ixs( - &[instruction::reallocate( - &self.program_id, - account, - &self.payer.pubkey(), - &authority.pubkey(), - &[], - extension_types, - )?], - &[authority], - ) - .await - } - - /// Require memos on transfers into this account - pub async fn enable_required_transfer_memos( - &self, - account: &Pubkey, - authority: &S2, - ) -> TokenResult { - self.process_ixs( - &[memo_transfer::instruction::enable_required_transfer_memos( - &self.program_id, - account, - &authority.pubkey(), - &[], - )?], - &[authority], - ) - .await - } - - /// Stop requiring memos on transfers into this account - pub async fn disable_required_transfer_memos( - &self, - account: &Pubkey, - authority: &S2, - ) -> TokenResult { - self.process_ixs( - &[memo_transfer::instruction::disable_required_transfer_memos( - &self.program_id, - account, - &authority.pubkey(), - &[], - )?], - &[authority], - ) - .await - } - - /// Update interest rate - pub async fn update_interest_rate( - &self, - authority: &S2, - new_rate: i16, - ) -> TokenResult { - self.process_ixs( - &[interest_bearing_mint::instruction::update_rate( - &self.program_id, - self.get_address(), - &authority.pubkey(), - &[], - new_rate, - )?], - &[authority], - ) - .await - } - - /// Update confidential transfer mint - pub async fn confidential_transfer_update_mint( - &self, - authority: &S2, - new_ct_mint: confidential_transfer::ConfidentialTransferMint, - new_authority: Option<&S2>, - ) -> TokenResult { - let mut signers = vec![authority]; - if let Some(new_authority) = new_authority { - signers.push(new_authority); - } - self.process_ixs( - &[confidential_transfer::instruction::update_mint( - &self.program_id, - &self.pubkey, - &new_ct_mint, - &authority.pubkey(), - )?], - &signers, - ) - .await - } - - /// Configures confidential transfers for a token account - pub async fn confidential_transfer_configure_token_account( - &self, - token_account: &Pubkey, - authority: &S2, - ) -> TokenResult { - let maximum_pending_balance_credit_counter = - 2 << confidential_transfer::MAXIMUM_DEPOSIT_TRANSFER_AMOUNT_BIT_LENGTH; - - self.confidential_transfer_configure_token_account_with_pending_counter( - token_account, - authority, - maximum_pending_balance_credit_counter, - ) - .await - } - - pub async fn confidential_transfer_configure_token_account_with_pending_counter( - &self, - token_account: &Pubkey, - authority: &S2, - maximum_pending_balance_credit_counter: u64, - ) -> TokenResult { - let elgamal_pubkey = ElGamalKeypair::new(authority, token_account) - .map_err(TokenError::Key)? - .public; - let decryptable_zero_balance = AeKey::new(authority, token_account) - .map_err(TokenError::Key)? - .encrypt(0); - - self.confidential_transfer_configure_token_account_with_pending_counter_and_keypair( - token_account, - authority, - maximum_pending_balance_credit_counter, - elgamal_pubkey, - decryptable_zero_balance, - ) - .await - } - - pub async fn confidential_transfer_configure_token_account_with_pending_counter_and_keypair< - S2: Signer, - >( - &self, - token_account: &Pubkey, - authority: &S2, - maximum_pending_balance_credit_counter: u64, - elgamal_pubkey: ElGamalPubkey, - decryptable_zero_balance: AeCiphertext, - ) -> TokenResult { - self.process_ixs( - &[confidential_transfer::instruction::configure_account( - &self.program_id, - token_account, - &self.pubkey, - elgamal_pubkey.into(), - decryptable_zero_balance, - maximum_pending_balance_credit_counter, - &authority.pubkey(), - &[], - )?], - &[authority], - ) - .await - } - - /// Approves a token account for confidential transfers - pub async fn confidential_transfer_approve_account( - &self, - token_account: &Pubkey, - authority: &S2, - ) -> TokenResult { - self.process_ixs( - &[confidential_transfer::instruction::approve_account( - &self.program_id, - token_account, - &self.pubkey, - &authority.pubkey(), - )?], - &[authority], - ) - .await - } - - /// Prepare a token account with the confidential transfer extension for closing - pub async fn confidential_transfer_empty_account( - &self, - token_account: &Pubkey, - authority: &S2, - ) -> TokenResult { - let elgamal_keypair = - ElGamalKeypair::new(authority, token_account).map_err(TokenError::Key)?; - self.confidential_transfer_empty_account_with_keypair( - token_account, - authority, - &elgamal_keypair, - ) - .await - } - - pub async fn confidential_transfer_empty_account_with_keypair( - &self, - token_account: &Pubkey, - authority: &S2, - elgamal_keypair: &ElGamalKeypair, - ) -> TokenResult { - let state = self.get_account_info(token_account).await.unwrap(); - let extension = - state.get_extension::()?; - - let proof_data = confidential_transfer::instruction::CloseAccountData::new( - elgamal_keypair, - &extension.available_balance.try_into().unwrap(), - ) - .map_err(TokenError::Proof)?; - - self.process_ixs( - &confidential_transfer::instruction::empty_account( - &self.program_id, - token_account, - &authority.pubkey(), - &[], - &proof_data, - )?, - &[authority], - ) - .await - } - - /// Fetch and decrypt the available balance of a confidential token account using the uniquely - /// derived decryption key from a signer - pub async fn confidential_transfer_get_available_balance( - &self, - token_account: &Pubkey, - authority: &S2, - ) -> TokenResult { - let authenticated_encryption_key = - AeKey::new(authority, token_account).map_err(TokenError::Key)?; - - self.confidential_transfer_get_available_balance_with_key( - token_account, - &authenticated_encryption_key, - ) - .await - } - - /// Fetch and decrypt the available balance of a confidential token account using a custom - /// decryption key - pub async fn confidential_transfer_get_available_balance_with_key( - &self, - token_account: &Pubkey, - authenticated_encryption_key: &AeKey, - ) -> TokenResult { - let state = self.get_account_info(token_account).await.unwrap(); - let extension = - state.get_extension::()?; - - let decryptable_balance_ciphertext: AeCiphertext = extension - .decryptable_available_balance - .try_into() - .map_err(TokenError::Proof)?; - let decryptable_balance = decryptable_balance_ciphertext - .decrypt(authenticated_encryption_key) - .ok_or(TokenError::AccountDecryption)?; - - Ok(decryptable_balance) - } - - /// Fetch and decrypt the pending balance of a confidential token account using the uniquely - /// derived decryption key from a signer - pub async fn confidential_transfer_get_pending_balance( - &self, - token_account: &Pubkey, - authority: &S2, - ) -> TokenResult { - let elgamal_keypair = - ElGamalKeypair::new(authority, token_account).map_err(TokenError::Key)?; - - self.confidential_transfer_get_pending_balance_with_key(token_account, &elgamal_keypair) - .await - } - - /// Fetch and decrypt the pending balance of a confidential token account using a custom - /// decryption key - pub async fn confidential_transfer_get_pending_balance_with_key( - &self, - token_account: &Pubkey, - elgamal_keypair: &ElGamalKeypair, - ) -> TokenResult { - let state = self.get_account_info(token_account).await.unwrap(); - let extension = - state.get_extension::()?; - - // decrypt pending balance - let pending_balance_lo = extension - .pending_balance_lo - .decrypt(&elgamal_keypair.secret) - .ok_or(TokenError::AccountDecryption)?; - let pending_balance_hi = extension - .pending_balance_hi - .decrypt(&elgamal_keypair.secret) - .ok_or(TokenError::AccountDecryption)?; - - let pending_balance = pending_balance_lo - .checked_add(pending_balance_hi << confidential_transfer::PENDING_BALANCE_HI_BIT_LENGTH) - .ok_or(TokenError::AccountDecryption)?; - - Ok(pending_balance) - } - - pub async fn confidential_transfer_get_withheld_amount( - &self, - withdraw_withheld_authority: &S2, - sources: &[&Pubkey], - ) -> TokenResult { - let withdraw_withheld_authority_elgamal_keypair = - ElGamalKeypair::new(withdraw_withheld_authority, &self.pubkey) - .map_err(TokenError::Key)?; - - self.confidential_transfer_get_withheld_amount_with_key( - &withdraw_withheld_authority_elgamal_keypair, - sources, - ) - .await - } - - pub async fn confidential_transfer_get_withheld_amount_with_key( - &self, - withdraw_withheld_authority_elgamal_keypair: &ElGamalKeypair, - sources: &[&Pubkey], - ) -> TokenResult { - let mut aggregate_withheld_amount_ciphertext = ElGamalCiphertext::default(); - for &source in sources { - let state = self.get_account_info(source).await.unwrap(); - let extension = - state.get_extension::()?; - - let withheld_amount_ciphertext: ElGamalCiphertext = - extension.withheld_amount.try_into().unwrap(); - - aggregate_withheld_amount_ciphertext = - aggregate_withheld_amount_ciphertext + withheld_amount_ciphertext; - } - - let aggregate_withheld_amount = aggregate_withheld_amount_ciphertext - .decrypt_u32(&withdraw_withheld_authority_elgamal_keypair.secret) - .ok_or(TokenError::AccountDecryption)?; - - Ok(aggregate_withheld_amount) - } - - /// Fetch the ElGamal public key associated with a confidential token account - pub async fn confidential_transfer_get_encryption_pubkey( - &self, - token_account: &Pubkey, - ) -> TokenResult { - let state = self.get_account_info(token_account).await.unwrap(); - let extension = - state.get_extension::()?; - let encryption_pubkey = extension - .encryption_pubkey - .try_into() - .map_err(TokenError::Proof)?; - - Ok(encryption_pubkey) - } - - /// Fetch the ElGamal pubkey key of the auditor associated with a confidential token mint - pub async fn confidential_transfer_get_auditor_encryption_pubkey( - &self, - ) -> TokenResult { - let mint_state = self.get_mint_info().await.unwrap(); - let ct_mint = - mint_state.get_extension::()?; - let auditor_pubkey = ct_mint - .auditor_encryption_pubkey - .try_into() - .map_err(TokenError::Proof)?; - - Ok(auditor_pubkey) - } - - /// Fetch the ElGamal pubkey key of the withdraw withheld authority associated with a - /// confidential token mint - pub async fn confidential_transfer_get_withdraw_withheld_authority_encryption_pubkey< - S2: Signer, - >( - &self, - ) -> TokenResult { - let mint_state = self.get_mint_info().await.unwrap(); - let ct_mint = - mint_state.get_extension::()?; - let auditor_pubkey = ct_mint - .withdraw_withheld_authority_encryption_pubkey - .try_into() - .map_err(TokenError::Proof)?; - - Ok(auditor_pubkey) - } - - /// Deposit SPL Tokens into the pending balance of a confidential token account - pub async fn confidential_transfer_deposit( - &self, - source_token_account: &Pubkey, - destination_token_account: &Pubkey, - source_token_authority: &S2, - amount: u64, - decimals: u8, - ) -> TokenResult { - if amount >> confidential_transfer::MAXIMUM_DEPOSIT_TRANSFER_AMOUNT_BIT_LENGTH != 0 { - return Err(TokenError::MaximumDepositTransferAmountExceeded); - } - - self.process_ixs( - &[confidential_transfer::instruction::deposit( - &self.program_id, - source_token_account, - &self.pubkey, - destination_token_account, - amount, - decimals, - &source_token_authority.pubkey(), - &[], - )?], - &[source_token_authority], - ) - .await - } - - /// Withdraw SPL Tokens from the available balance of a confidential token account using the - /// uniquely derived decryption key from a signer - #[allow(clippy::too_many_arguments)] - pub async fn confidential_transfer_withdraw( - &self, - source_token_account: &Pubkey, - destination_token_account: &Pubkey, - source_token_authority: &S2, - amount: u64, - source_available_balance: u64, - source_available_balance_ciphertext: &ElGamalCiphertext, - decimals: u8, - ) -> TokenResult { - let source_elgamal_keypair = - ElGamalKeypair::new(source_token_authority, source_token_account) - .map_err(TokenError::Key)?; - let source_authenticated_encryption_key = - AeKey::new(source_token_authority, source_token_account).map_err(TokenError::Key)?; - - self.confidential_transfer_withdraw_with_key( - source_token_account, - destination_token_account, - source_token_authority, - amount, - decimals, - source_available_balance, - source_available_balance_ciphertext, - &source_elgamal_keypair, - &source_authenticated_encryption_key, - ) - .await - } - - /// Withdraw SPL Tokens from the available balance of a confidential token account using custom - /// keys - #[allow(clippy::too_many_arguments)] - pub async fn confidential_transfer_withdraw_with_key( - &self, - source_token_account: &Pubkey, - destination_token_account: &Pubkey, - source_token_authority: &S2, - amount: u64, - decimals: u8, - source_available_balance: u64, - source_available_balance_ciphertext: &ElGamalCiphertext, - source_elgamal_keypair: &ElGamalKeypair, - source_authenticated_encryption_key: &AeKey, - ) -> TokenResult { - let proof_data = confidential_transfer::instruction::WithdrawData::new( - amount, - source_elgamal_keypair, - source_available_balance, - source_available_balance_ciphertext, - ) - .map_err(TokenError::Proof)?; - - let source_remaining_balance = source_available_balance - .checked_sub(amount) - .ok_or(TokenError::NotEnoughFunds)?; - let new_source_decryptable_available_balance = - source_authenticated_encryption_key.encrypt(source_remaining_balance); - - self.process_ixs( - &confidential_transfer::instruction::withdraw( - &self.program_id, - source_token_account, - destination_token_account, - &self.pubkey, - amount, - decimals, - new_source_decryptable_available_balance, - &source_token_authority.pubkey(), - &[], - &proof_data, - )?, - &[source_token_authority], - ) - .await - } - - /// Transfer tokens confidentially using the uniquely derived decryption keys from a signer - #[allow(clippy::too_many_arguments)] - pub async fn confidential_transfer_transfer( - &self, - source_token_account: &Pubkey, - destination_token_account: &Pubkey, - source_token_authority: &S2, - amount: u64, - source_available_balance: u64, - source_available_balance_ciphertext: &ElGamalCiphertext, - destination_elgamal_pubkey: &ElGamalPubkey, - auditor_elgamal_pubkey: &ElGamalPubkey, - ) -> TokenResult { - let source_elgamal_keypair = - ElGamalKeypair::new(source_token_authority, source_token_account) - .map_err(TokenError::Key)?; - let source_authenticated_encryption_key = - AeKey::new(source_token_authority, source_token_account).map_err(TokenError::Key)?; - - self.confidential_transfer_transfer_with_key( - source_token_account, - destination_token_account, - source_token_authority, - amount, - source_available_balance, - source_available_balance_ciphertext, - destination_elgamal_pubkey, - auditor_elgamal_pubkey, - &source_elgamal_keypair, - &source_authenticated_encryption_key, - ) - .await - } - - /// Transfer tokens confidentially using custom decryption keys - #[allow(clippy::too_many_arguments)] - pub async fn confidential_transfer_transfer_with_key( - &self, - source_token_account: &Pubkey, - destination_token_account: &Pubkey, - source_token_authority: &S2, - amount: u64, - source_available_balance: u64, - source_available_balance_ciphertext: &ElGamalCiphertext, - destination_elgamal_pubkey: &ElGamalPubkey, - auditor_elgamal_pubkey: &ElGamalPubkey, - source_elgamal_keypair: &ElGamalKeypair, - source_authenticated_encryption_key: &AeKey, - ) -> TokenResult { - if amount >> confidential_transfer::MAXIMUM_DEPOSIT_TRANSFER_AMOUNT_BIT_LENGTH != 0 { - return Err(TokenError::MaximumDepositTransferAmountExceeded); - } - - let proof_data = confidential_transfer::instruction::TransferData::new( - amount, - ( - source_available_balance, - source_available_balance_ciphertext, - ), - source_elgamal_keypair, - (destination_elgamal_pubkey, auditor_elgamal_pubkey), - ) - .map_err(TokenError::Proof)?; - - let source_remaining_balance = source_available_balance - .checked_sub(amount) - .ok_or(TokenError::NotEnoughFunds)?; - let new_source_available_balance = - source_authenticated_encryption_key.encrypt(source_remaining_balance); - - self.process_ixs( - &confidential_transfer::instruction::transfer( - &self.program_id, - source_token_account, - destination_token_account, - &self.pubkey, - new_source_available_balance, - &source_token_authority.pubkey(), - &[], - &proof_data, - )?, - &[source_token_authority], - ) - .await - } - - /// Transfer tokens confidentially with fee using the uniquely derived decryption keys from a - /// signer - #[allow(clippy::too_many_arguments)] - pub async fn confidential_transfer_transfer_with_fee( - &self, - source_token_account: &Pubkey, - destination_token_account: &Pubkey, - source_token_authority: &S2, - amount: u64, - source_available_balance: u64, - source_available_balance_ciphertext: &ElGamalCiphertext, - destination_elgamal_pubkey: &ElGamalPubkey, - auditor_elgamal_pubkey: &ElGamalPubkey, - withdraw_withheld_authority_elgamal_pubkey: &ElGamalPubkey, - epoch_info: &EpochInfo, - ) -> TokenResult { - let source_elgamal_keypair = - ElGamalKeypair::new(source_token_authority, source_token_account) - .map_err(TokenError::Key)?; - let source_authenticated_encryption_key = - AeKey::new(source_token_authority, source_token_account).map_err(TokenError::Key)?; - - self.confidential_transfer_transfer_with_fee_with_key( - source_token_account, - destination_token_account, - source_token_authority, - amount, - source_available_balance, - source_available_balance_ciphertext, - destination_elgamal_pubkey, - auditor_elgamal_pubkey, - withdraw_withheld_authority_elgamal_pubkey, - &source_elgamal_keypair, - &source_authenticated_encryption_key, - epoch_info, - ) - .await - } - - /// Transfer tokens confidential with fee using custom decryption keys - #[allow(clippy::too_many_arguments)] - pub async fn confidential_transfer_transfer_with_fee_with_key( - &self, - source_token_account: &Pubkey, - destination_token_account: &Pubkey, - source_token_authority: &S2, - amount: u64, - source_available_balance: u64, - source_available_balance_ciphertext: &ElGamalCiphertext, - destination_elgamal_pubkey: &ElGamalPubkey, - auditor_elgamal_pubkey: &ElGamalPubkey, - withdraw_withheld_authority_elgamal_pubkey: &ElGamalPubkey, - source_elgamal_keypair: &ElGamalKeypair, - source_authenticated_encryption_key: &AeKey, - epoch_info: &EpochInfo, - ) -> TokenResult { - if amount >> confidential_transfer::MAXIMUM_DEPOSIT_TRANSFER_AMOUNT_BIT_LENGTH != 0 { - return Err(TokenError::MaximumDepositTransferAmountExceeded); - } - - // TODO: take transfer fee params as input - let mint_state = self.get_mint_info().await.unwrap(); - let transfer_fee_config = mint_state - .get_extension::() - .unwrap(); - let fee_parameters = transfer_fee_config.get_epoch_fee(epoch_info.epoch); - - let proof_data = confidential_transfer::instruction::TransferWithFeeData::new( - amount, - ( - source_available_balance, - source_available_balance_ciphertext, - ), - source_elgamal_keypair, - (destination_elgamal_pubkey, auditor_elgamal_pubkey), - FeeParameters { - fee_rate_basis_points: u16::from(fee_parameters.transfer_fee_basis_points), - maximum_fee: u64::from(fee_parameters.maximum_fee), - }, - withdraw_withheld_authority_elgamal_pubkey, - ) - .map_err(TokenError::Proof)?; - - let source_remaining_balance = source_available_balance - .checked_sub(amount) - .ok_or(TokenError::NotEnoughFunds)?; - let new_source_decryptable_balance = - source_authenticated_encryption_key.encrypt(source_remaining_balance); - - self.process_ixs( - &confidential_transfer::instruction::transfer_with_fee( - &self.program_id, - source_token_account, - destination_token_account, - &self.pubkey, - new_source_decryptable_balance, - &source_token_authority.pubkey(), - &[], - &proof_data, - )?, - &[source_token_authority], - ) - .await - } - - /// Applies the confidential transfer pending balance to the available balance using the - /// uniquely derived decryption key - pub async fn confidential_transfer_apply_pending_balance( - &self, - token_account: &Pubkey, - authority: &S2, - available_balance: u64, - pending_balance: u64, - expected_pending_balance_credit_counter: u64, - ) -> TokenResult { - let authenticated_encryption_key = - AeKey::new(authority, token_account).map_err(TokenError::Key)?; - - self.confidential_transfer_apply_pending_balance_with_key( - token_account, - authority, - available_balance, - pending_balance, - expected_pending_balance_credit_counter, - &authenticated_encryption_key, - ) - .await - } - - /// Applies the confidential transfer pending balance to the available balance using a custom - /// decryption key - pub async fn confidential_transfer_apply_pending_balance_with_key( - &self, - token_account: &Pubkey, - authority: &S2, - available_balance: u64, - pending_balance: u64, - expected_pending_balance_credit_counter: u64, - authenticated_encryption_key: &AeKey, - ) -> TokenResult { - let new_decryptable_balance = available_balance.checked_add(pending_balance).unwrap(); - let new_decryptable_balance_ciphertext = - authenticated_encryption_key.encrypt(new_decryptable_balance); - - self.process_ixs( - &[confidential_transfer::instruction::apply_pending_balance( - &self.program_id, - token_account, - expected_pending_balance_credit_counter, - new_decryptable_balance_ciphertext, - &authority.pubkey(), - &[], - )?], - &[authority], - ) - .await - } - - /// Enable confidential transfer `Deposit` and `Transfer` instructions for a token account - pub async fn confidential_transfer_enable_balance_credits( - &self, - token_account: &Pubkey, - authority: &S2, - ) -> TokenResult { - self.process_ixs( - &[confidential_transfer::instruction::enable_balance_credits( - &self.program_id, - token_account, - &authority.pubkey(), - &[], - )?], - &[authority], - ) - .await - } - - /// Disable confidential transfer `Deposit` and `Transfer` instructions for a token account - pub async fn confidential_transfer_disable_balance_credits( - &self, - token_account: &Pubkey, - authority: &S2, - ) -> TokenResult { - self.process_ixs( - &[confidential_transfer::instruction::disable_balance_credits( - &self.program_id, - token_account, - &authority.pubkey(), - &[], - )?], - &[authority], - ) - .await - } - - /// Withdraw withheld confidential tokens from mint using the uniquely derived decryption key - pub async fn confidential_transfer_withdraw_withheld_tokens_from_mint( - &self, - withdraw_withheld_authority: &S2, - destination_token_account: &Pubkey, - destination_elgamal_pubkey: &ElGamalPubkey, - withheld_amount: u64, - withheld_amount_ciphertext: &ElGamalCiphertext, - ) -> TokenResult { - // derive withheld authority elgamal key - let withdraw_withheld_authority_elgamal_keypair = - ElGamalKeypair::new(withdraw_withheld_authority, &self.pubkey) - .map_err(TokenError::Key)?; - - self.confidential_transfer_withdraw_withheld_tokens_from_mint_with_key( - withdraw_withheld_authority, - destination_token_account, - destination_elgamal_pubkey, - withheld_amount, - withheld_amount_ciphertext, - &withdraw_withheld_authority_elgamal_keypair, - ) - .await - } - - /// Withdraw withheld confidential tokens from mint using a custom decryption key - pub async fn confidential_transfer_withdraw_withheld_tokens_from_mint_with_key( - &self, - withdraw_withheld_authority: &S2, - destination_token_account: &Pubkey, - destination_elgamal_pubkey: &ElGamalPubkey, - withheld_amount: u64, - withheld_amount_ciphertext: &ElGamalCiphertext, - withdraw_withheld_authority_elgamal_keypair: &ElGamalKeypair, - ) -> TokenResult { - let proof_data = confidential_transfer::instruction::WithdrawWithheldTokensData::new( - withdraw_withheld_authority_elgamal_keypair, - destination_elgamal_pubkey, - withheld_amount_ciphertext, - withheld_amount, - ) - .map_err(TokenError::Proof)?; - - self.process_ixs( - &confidential_transfer::instruction::withdraw_withheld_tokens_from_mint( - &self.program_id, - &self.pubkey, - destination_token_account, - &withdraw_withheld_authority.pubkey(), - &[], - &proof_data, - )?, - &[withdraw_withheld_authority], - ) - .await - } - - /// Withdraw withheld confidential tokens from accounts using the uniquely derived decryption - /// key - pub async fn confidential_transfer_withdraw_withheld_tokens_from_accounts( - &self, - withdraw_withheld_authority: &S2, - destination_token_account: &Pubkey, - destination_elgamal_pubkey: &ElGamalPubkey, - aggregate_withheld_amount: u64, - aggregate_withheld_amount_ciphertext: &ElGamalCiphertext, - sources: &[&Pubkey], - ) -> TokenResult { - let withdraw_withheld_authority_elgamal_keypair = - ElGamalKeypair::new(withdraw_withheld_authority, &self.pubkey) - .map_err(TokenError::Key)?; - - self.confidential_transfer_withdraw_withheld_tokens_from_accounts_with_key( - withdraw_withheld_authority, - destination_token_account, - destination_elgamal_pubkey, - aggregate_withheld_amount, - aggregate_withheld_amount_ciphertext, - &withdraw_withheld_authority_elgamal_keypair, - sources, - ) - .await - } - - /// Withdraw withheld confidential tokens from accounts using a custom decryption key - #[allow(clippy::too_many_arguments)] - pub async fn confidential_transfer_withdraw_withheld_tokens_from_accounts_with_key< - S2: Signer, - >( - &self, - withdraw_withheld_authority: &S2, - destination_token_account: &Pubkey, - destination_elgamal_pubkey: &ElGamalPubkey, - aggregate_withheld_amount: u64, - aggregate_withheld_amount_ciphertext: &ElGamalCiphertext, - withdraw_withheld_authority_elgamal_keypair: &ElGamalKeypair, - sources: &[&Pubkey], - ) -> TokenResult { - let proof_data = confidential_transfer::instruction::WithdrawWithheldTokensData::new( - withdraw_withheld_authority_elgamal_keypair, - destination_elgamal_pubkey, - aggregate_withheld_amount_ciphertext, - aggregate_withheld_amount, - ) - .map_err(TokenError::Proof)?; - - self.process_ixs( - &confidential_transfer::instruction::withdraw_withheld_tokens_from_accounts( - &self.program_id, - &self.pubkey, - destination_token_account, - &withdraw_withheld_authority.pubkey(), - &[], - sources, - &proof_data, - )?, - &[withdraw_withheld_authority], - ) - .await - } - - /// Harvest withheld confidential tokens to mint - pub async fn confidential_transfer_harvest_withheld_tokens_to_mint( - &self, - sources: &[&Pubkey], - ) -> TokenResult { - self.process_ixs::<[&dyn Signer; 0]>( - &[ - confidential_transfer::instruction::harvest_withheld_tokens_to_mint( - &self.program_id, - &self.pubkey, - sources, - )?, - ], - &[], - ) - .await - } -} diff --git a/token/client/tests/program-test.rs b/token/client/tests/program-test.rs deleted file mode 100644 index fa9fe199ca1..00000000000 --- a/token/client/tests/program-test.rs +++ /dev/null @@ -1,292 +0,0 @@ -use { - solana_program_test::{ - tokio::{self, sync::Mutex}, - ProgramTest, - }, - solana_sdk::{ - program_option::COption, - signer::{keypair::Keypair, Signer}, - }, - spl_token_2022::{instruction, state}, - spl_token_client::{ - client::{ProgramBanksClient, ProgramBanksClientProcessTransaction, ProgramClient}, - token::Token, - }, - std::sync::Arc, -}; - -struct TestContext { - pub decimals: u8, - pub mint_authority: Keypair, - pub token: Token, - - pub alice: Keypair, - pub bob: Keypair, -} - -impl TestContext { - async fn new() -> Self { - let program_test = ProgramTest::default(); - let ctx = program_test.start_with_context().await; - let ctx = Arc::new(Mutex::new(ctx)); - - let payer = keypair_clone(&ctx.lock().await.payer); - - let client: Arc> = - Arc::new(ProgramBanksClient::new_from_context( - Arc::clone(&ctx), - ProgramBanksClientProcessTransaction, - )); - - let decimals: u8 = 6; - - let mint_account = Keypair::new(); - let mint_authority = Keypair::new(); - let mint_authority_pubkey = mint_authority.pubkey(); - - let token = Token::create_mint( - Arc::clone(&client), - &spl_token_2022::id(), - keypair_clone(&payer), - &mint_account, - &mint_authority_pubkey, - None, - decimals, - vec![], - ) - .await - .expect("failed to create mint"); - - Self { - decimals, - mint_authority, - token, - - alice: Keypair::new(), - bob: Keypair::new(), - } - } -} - -fn keypair_clone(kp: &Keypair) -> Keypair { - Keypair::from_bytes(&kp.to_bytes()).expect("failed to copy keypair") -} - -// TODO unignore once spl-token-2022 becomes spl-token, and is included in -// ProgramTest by default -#[ignore] -#[tokio::test] -async fn associated_token_account() { - let TestContext { token, alice, .. } = TestContext::new().await; - - let alice_vault = token - .create_associated_token_account(&alice.pubkey()) - .await - .expect("failed to create associated token account"); - - assert_eq!( - token.get_associated_token_address(&alice.pubkey()), - alice_vault - ); - - assert_eq!( - token - .get_account_info(&alice_vault) - .await - .expect("failed to get account info") - .base, - state::Account { - mint: *token.get_address(), - owner: alice.pubkey(), - amount: 0, - delegate: COption::None, - state: state::AccountState::Initialized, - is_native: COption::None, - delegated_amount: 0, - close_authority: COption::None, - } - ); -} - -// TODO unignore once spl-token-2022 becomes spl-token, and is included in -// ProgramTest by default -#[ignore] -#[tokio::test] -async fn get_or_create_associated_token_account() { - let TestContext { token, alice, .. } = TestContext::new().await; - - assert_eq!( - token - .get_or_create_associated_account_info(&alice.pubkey()) - .await - .expect("failed to get account info") - .base, - state::Account { - mint: *token.get_address(), - owner: alice.pubkey(), - amount: 0, - delegate: COption::None, - state: state::AccountState::Initialized, - is_native: COption::None, - delegated_amount: 0, - close_authority: COption::None, - } - ); -} - -// TODO unignore once spl-token-2022 becomes spl-token, and is included in -// ProgramTest by default -#[ignore] -#[tokio::test] -async fn set_authority() { - let TestContext { - mint_authority, - token, - alice, - bob, - .. - } = TestContext::new().await; - - let alice_vault = token - .create_associated_token_account(&alice.pubkey()) - .await - .expect("failed to create associated token account"); - - token - .mint_to(&alice_vault, &mint_authority, 1) - .await - .expect("failed to mint token"); - - token - .set_authority( - token.get_address(), - None, - instruction::AuthorityType::MintTokens, - &mint_authority, - ) - .await - .expect("failed to set authority"); - - let mint = token - .get_mint_info() - .await - .expect("failed to get mint info"); - assert!(mint.base.mint_authority.is_none()); - - // TODO: compare - // Err(Client(TransactionError(InstructionError(0, Custom(5))))) - assert!(token - .mint_to(&alice_vault, &mint_authority, 2) - .await - .is_err()); - - token - .set_authority( - &alice_vault, - Some(&bob.pubkey()), - instruction::AuthorityType::AccountOwner, - &alice, - ) - .await - .expect("failed to set_authority"); - - assert_eq!( - token - .get_account_info(&alice_vault) - .await - .expect("failed to get account info") - .base - .owner, - bob.pubkey(), - ); -} - -// TODO unignore once spl-token-2022 becomes spl-token, and is included in -// ProgramTest by default -#[ignore] -#[tokio::test] -async fn mint_to() { - let TestContext { - decimals, - mint_authority, - token, - alice, - .. - } = TestContext::new().await; - - let alice_vault = token - .create_associated_token_account(&alice.pubkey()) - .await - .expect("failed to create associated token account"); - - let mint_amount = 10 * u64::pow(10, decimals as u32); - token - .mint_to(&alice_vault, &mint_authority, mint_amount) - .await - .expect("failed to mint token"); - - assert_eq!( - token - .get_account_info(&alice_vault) - .await - .expect("failed to get account") - .base - .amount, - mint_amount - ); -} - -// TODO unignore once spl-token-2022 becomes spl-token, and is included in -// ProgramTest by default -#[ignore] -#[tokio::test] -async fn transfer() { - let TestContext { - decimals, - mint_authority, - token, - alice, - bob, - .. - } = TestContext::new().await; - - let alice_vault = token - .create_associated_token_account(&alice.pubkey()) - .await - .expect("failed to create associated token account"); - let bob_vault = token - .create_associated_token_account(&bob.pubkey()) - .await - .expect("failed to create associated token account"); - - let mint_amount = 10 * u64::pow(10, decimals as u32); - token - .mint_to(&alice_vault, &mint_authority, mint_amount) - .await - .expect("failed to mint token"); - - let transfer_amount = mint_amount.overflowing_div(3).0; - token - .transfer_checked(&alice_vault, &bob_vault, &alice, transfer_amount, decimals) - .await - .expect("failed to transfer"); - - assert_eq!( - token - .get_account_info(&alice_vault) - .await - .expect("failed to get account") - .base - .amount, - mint_amount - transfer_amount - ); - assert_eq!( - token - .get_account_info(&bob_vault) - .await - .expect("failed to get account") - .base - .amount, - transfer_amount - ); -} diff --git a/token/js/.editorconfig b/token/js/.editorconfig deleted file mode 100644 index 3e10c03d05b..00000000000 --- a/token/js/.editorconfig +++ /dev/null @@ -1,9 +0,0 @@ -root = true - -[*] -charset = utf-8 -indent_style = space -indent_size = 4 -end_of_line = lf -insert_final_newline = true -trim_trailing_whitespace = true \ No newline at end of file diff --git a/token/js/.eslintignore b/token/js/.eslintignore deleted file mode 100644 index b3c7b6f5789..00000000000 --- a/token/js/.eslintignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules - -docs -lib diff --git a/token/js/.eslintrc.json b/token/js/.eslintrc.json deleted file mode 100644 index 38eb3be922b..00000000000 --- a/token/js/.eslintrc.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "root": true, - "env": { - "browser": true, - "node": true, - "es6": true - }, - "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], - "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint", "prettier"], - "rules": { - "@typescript-eslint/ban-ts-comment": "off" - } -} diff --git a/token/js/.gitignore b/token/js/.gitignore deleted file mode 100644 index 7bc72baf8e6..00000000000 --- a/token/js/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -lib -docs diff --git a/token/js/.mocharc.json b/token/js/.mocharc.json deleted file mode 100644 index 451c14c3016..00000000000 --- a/token/js/.mocharc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extension": ["ts"], - "node-option": ["experimental-specifier-resolution=node", "loader=ts-node/esm"], - "timeout": 5000 -} diff --git a/token/js/.nojekyll b/token/js/.nojekyll deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/token/js/.prettierignore b/token/js/.prettierignore deleted file mode 100644 index a81d45c2402..00000000000 --- a/token/js/.prettierignore +++ /dev/null @@ -1,3 +0,0 @@ -docs -lib -test-ledger diff --git a/token/js/.prettierrc b/token/js/.prettierrc deleted file mode 100644 index b9ce4c1923a..00000000000 --- a/token/js/.prettierrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "printWidth": 120, - "trailingComma": "es5", - "tabWidth": 4, - "semi": true, - "singleQuote": true -} \ No newline at end of file diff --git a/token/js/FAQ.md b/token/js/FAQ.md deleted file mode 100644 index d253231f318..00000000000 --- a/token/js/FAQ.md +++ /dev/null @@ -1,9 +0,0 @@ -# FAQ (Frequently Asked Questions) - -- [How can I get support?](#how-can-i-get-support) - -## How can I get support? - -Please ask questions in the #developer-support channel on the Solana Discord: https://discord.com/invite/solana - -After reading this FAQ, if you've found a bug or you'd like to request a feature, please [open an issue](https://github.com/solana-labs/solana-program-library/issues/new). diff --git a/token/js/LICENSE b/token/js/LICENSE deleted file mode 100644 index d6456956733..00000000000 --- a/token/js/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/token/js/README.md b/token/js/README.md deleted file mode 100644 index 3a292b58248..00000000000 --- a/token/js/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# `@solana/spl-token` - -A TypeScript library for interacting with the SPL Token program. - -## Links - -- [TypeScript Docs](https://solana-labs.github.io/solana-program-library/token/js/) -- [FAQ (Frequently Asked Questions)](./FAQ.md) -- [Install](#install) -- [Build from Source](#build-from-source) - -## Install - -```shell -yarn add @solana/spl-token -``` - -## Build from Source - -1. Clone the project: -```shell -git clone https://github.com/solana-labs/solana-program-library.git -``` - -2. Navigate to the library: -```shell -cd solana-program-library/token/js -``` - -3. Install the dependencies: -```shell -yarn install -``` - -4. Build the library: -```shell -yarn build -``` - -5. Build the on-chain programs: -```shell -yarn test:build-programs -``` - -6. Run the tests: -```shell -yarn test -``` - -7. Run the example: -```shell -yarn example -``` diff --git a/token/js/examples/create_mint_and_transfer_tokens.ts b/token/js/examples/create_mint_and_transfer_tokens.ts deleted file mode 100644 index 183cbb09961..00000000000 --- a/token/js/examples/create_mint_and_transfer_tokens.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { clusterApiUrl, Connection, Keypair, LAMPORTS_PER_SOL } from '@solana/web3.js'; -import { createMint, getOrCreateAssociatedTokenAccount, mintTo, transfer } from '../src'; // @FIXME: replace with @solana/spl-token - -(async () => { - // Connect to cluster - const connection = new Connection(clusterApiUrl('devnet'), 'confirmed'); - - // Generate a new wallet keypair and airdrop SOL - const fromWallet = Keypair.generate(); - const fromAirdropSignature = await connection.requestAirdrop(fromWallet.publicKey, LAMPORTS_PER_SOL); - - // Wait for airdrop confirmation - await connection.confirmTransaction(fromAirdropSignature); - - // Generate a new wallet to receive newly minted token - const toWallet = Keypair.generate(); - - // Create new token mint - const mint = await createMint(connection, fromWallet, fromWallet.publicKey, null, 9); - - // Get the token account of the fromWallet address, and if it does not exist, create it - const fromTokenAccount = await getOrCreateAssociatedTokenAccount( - connection, - fromWallet, - mint, - fromWallet.publicKey - ); - - // Get the token account of the toWallet address, and if it does not exist, create it - const toTokenAccount = await getOrCreateAssociatedTokenAccount(connection, fromWallet, mint, toWallet.publicKey); - - // Mint 1 new token to the "fromTokenAccount" account we just created - let signature = await mintTo( - connection, - fromWallet, - mint, - fromTokenAccount.address, - fromWallet.publicKey, - 1000000000, - [] - ); - console.log('mint tx:', signature); - - // Transfer the new token to the "toTokenAccount" we just created - signature = await transfer( - connection, - fromWallet, - fromTokenAccount.address, - toTokenAccount.address, - fromWallet.publicKey, - 1000000000, - [] - ); - console.log('transfer tx:', signature); -})(); diff --git a/token/js/package.json b/token/js/package.json deleted file mode 100644 index 7694fe0615e..00000000000 --- a/token/js/package.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "name": "@solana/spl-token", - "version": "0.2.0", - "author": "Solana Maintainers ", - "repository": "https://github.com/solana-labs/solana-program-library", - "license": "Apache-2.0", - "publishConfig": { - "access": "public" - }, - "files": [ - "lib", - "src", - "LICENSE", - "README.md" - ], - "type": "module", - "sideEffects": false, - "main": "lib/cjs/index.js", - "module": "lib/esm/index.mjs", - "types": "lib/types/index.d.ts", - "exports": { - "import": "./lib/esm/index.mjs", - "require": "./lib/cjs/index.js" - }, - "scripts": { - "clean": "shx rm -rf lib", - "build": "yarn clean && tsc -p tsconfig.json; tsc-esm -p tsconfig.json && tsc -p tsconfig.cjs.json", - "postbuild": "echo '{\"type\":\"commonjs\"}' > lib/cjs/package.json && echo '{\"type\":\"module\"}' > lib/esm/package.json", - "deploy": "yarn docs && gh-pages --dist docs --dest token/js --dotfiles", - "example": "node --experimental-specifier-resolution=node --loader ts-node/esm examples/create_mint_and_transfer_tokens.ts", - "test": "yarn test:unit && yarn test:e2e-built && yarn test:e2e-native && yarn test:e2e-2022", - "test:unit": "mocha test/unit", - "test:e2e-built": "start-server-and-test 'solana-test-validator --bpf-program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA ../../target/deploy/spl_token.so --reset --quiet' http://localhost:8899/health 'mocha test/e2e'", - "test:e2e-2022": "TEST_PROGRAM_ID=TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb start-server-and-test 'solana-test-validator --bpf-program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL ../../target/deploy/spl_associated_token_account.so --bpf-program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb ../../target/deploy/spl_token_2022.so --reset --quiet' http://localhost:8899/health 'mocha test/e2e*'", - "test:e2e-native": "start-server-and-test 'solana-test-validator --reset --quiet' http://localhost:8899/health 'mocha test/e2e'", - "test:build-programs": "cargo build-bpf --manifest-path ../program/Cargo.toml && cargo build-bpf --manifest-path ../program-2022/Cargo.toml && cargo build-bpf --manifest-path ../../associated-token-account/program/Cargo.toml", - "docs": "shx rm -rf docs && NODE_OPTIONS=--max_old_space_size=4096 typedoc && shx cp .nojekyll docs/", - "fmt": "prettier --write '{*,**/*}.{js,ts,jsx,tsx,json}'", - "lint": "eslint --max-warnings 0 --ext .ts . && prettier --check '{*,**/*}.{js,ts,jsx,tsx,json}'", - "lint:fix": "eslint --fix --ext .ts . && yarn fmt", - "nuke": "shx rm -rf node_modules yarn.lock" - }, - "dependencies": { - "@solana/buffer-layout": "^4.0.0", - "@solana/buffer-layout-utils": "^0.2.0", - "@solana/web3.js": "^1.41.0" - }, - "devDependencies": { - "@solana/spl-memo": "^0.1.0", - "@types/chai-as-promised": "^7.1.4", - "@types/eslint": "^8.4.0", - "@types/eslint-plugin-prettier": "^3.1.0", - "@types/mocha": "^9.1.0", - "@types/node": "^16.11.21", - "@types/prettier": "^2.4.3", - "@typescript-eslint/eslint-plugin": "^5.10.0", - "@typescript-eslint/parser": "^5.10.0", - "chai": "^4.3.4", - "chai-as-promised": "^7.1.1", - "eslint": "^8.7.0", - "eslint-config-prettier": "^8.3.0", - "eslint-plugin-prettier": "^4.0.0", - "gh-pages": "^3.2.3", - "mocha": "^9.1.4", - "prettier": "^2.5.1", - "shx": "^0.3.4", - "start-server-and-test": "^1.14.0", - "ts-node": "^10.4.0", - "tslib": "^2.3.1", - "typedoc": "^0.22.11", - "typescript": "^4.5.5", - "typescript-esm": "^2.0.0" - } -} diff --git a/token/js/src/actions/approve.ts b/token/js/src/actions/approve.ts deleted file mode 100644 index cb4bfb13b67..00000000000 --- a/token/js/src/actions/approve.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { - ConfirmOptions, - Connection, - PublicKey, - sendAndConfirmTransaction, - Signer, - Transaction, - TransactionSignature, -} from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { createApproveInstruction } from '../instructions/index'; -import { getSigners } from './internal'; - -/** - * Approve a delegate to transfer up to a maximum number of tokens from an account - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param account Address of the token account - * @param delegate Account authorized to transfer tokens from the account - * @param owner Owner of the account - * @param amount Maximum number of tokens the delegate may transfer - * @param multiSigners Signing accounts if `owner` is a multisig - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Signature of the confirmed transaction - */ -export async function approve( - connection: Connection, - payer: Signer, - account: PublicKey, - delegate: PublicKey, - owner: Signer | PublicKey, - amount: number | bigint, - multiSigners: Signer[] = [], - confirmOptions?: ConfirmOptions, - programId = TOKEN_PROGRAM_ID -): Promise { - const [ownerPublicKey, signers] = getSigners(owner, multiSigners); - - const transaction = new Transaction().add( - createApproveInstruction(account, delegate, ownerPublicKey, amount, multiSigners, programId) - ); - - return await sendAndConfirmTransaction(connection, transaction, [payer, ...signers], confirmOptions); -} diff --git a/token/js/src/actions/approveChecked.ts b/token/js/src/actions/approveChecked.ts deleted file mode 100644 index 402d4fbfd24..00000000000 --- a/token/js/src/actions/approveChecked.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { - ConfirmOptions, - Connection, - PublicKey, - sendAndConfirmTransaction, - Signer, - Transaction, - TransactionSignature, -} from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { createApproveCheckedInstruction } from '../instructions/index'; -import { getSigners } from './internal'; - -/** - * Approve a delegate to transfer up to a maximum number of tokens from an account, asserting the token mint and - * decimals - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param account Address of the account - * @param delegate Account authorized to perform a transfer tokens from the source account - * @param owner Owner of the source account - * @param amount Maximum number of tokens the delegate may transfer - * @param decimals Number of decimals in approve amount - * @param multiSigners Signing accounts if `owner` is a multisig - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Signature of the confirmed transaction - */ -export async function approveChecked( - connection: Connection, - payer: Signer, - mint: PublicKey, - account: PublicKey, - delegate: PublicKey, - owner: Signer | PublicKey, - amount: number | bigint, - decimals: number, - multiSigners: Signer[] = [], - confirmOptions?: ConfirmOptions, - programId = TOKEN_PROGRAM_ID -): Promise { - const [ownerPublicKey, signers] = getSigners(owner, multiSigners); - - const transaction = new Transaction().add( - createApproveCheckedInstruction( - account, - mint, - delegate, - ownerPublicKey, - amount, - decimals, - multiSigners, - programId - ) - ); - - return await sendAndConfirmTransaction(connection, transaction, [payer, ...signers], confirmOptions); -} diff --git a/token/js/src/actions/burn.ts b/token/js/src/actions/burn.ts deleted file mode 100644 index 3cc5cd82e26..00000000000 --- a/token/js/src/actions/burn.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { - ConfirmOptions, - Connection, - PublicKey, - sendAndConfirmTransaction, - Signer, - Transaction, - TransactionSignature, -} from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { createBurnInstruction } from '../instructions/index'; -import { getSigners } from './internal'; - -/** - * Burn tokens from an account - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param account Account to burn tokens from - * @param mint Mint for the account - * @param owner Account owner - * @param amount Amount to burn - * @param multiSigners Signing accounts if `owner` is a multisig - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Signature of the confirmed transaction - */ -export async function burn( - connection: Connection, - payer: Signer, - account: PublicKey, - mint: PublicKey, - owner: Signer | PublicKey, - amount: number | bigint, - multiSigners: Signer[] = [], - confirmOptions?: ConfirmOptions, - programId = TOKEN_PROGRAM_ID -): Promise { - const [ownerPublicKey, signers] = getSigners(owner, multiSigners); - - const transaction = new Transaction().add( - createBurnInstruction(account, mint, ownerPublicKey, amount, multiSigners, programId) - ); - - return await sendAndConfirmTransaction(connection, transaction, [payer, ...signers], confirmOptions); -} diff --git a/token/js/src/actions/burnChecked.ts b/token/js/src/actions/burnChecked.ts deleted file mode 100644 index 44d7d0e6ee6..00000000000 --- a/token/js/src/actions/burnChecked.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { - ConfirmOptions, - Connection, - PublicKey, - sendAndConfirmTransaction, - Signer, - Transaction, - TransactionSignature, -} from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { createBurnCheckedInstruction } from '../instructions/index'; -import { getSigners } from './internal'; - -/** - * Burn tokens from an account, asserting the token mint and decimals - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param account Account to burn tokens from - * @param mint Mint for the account - * @param owner Account owner - * @param amount Amount to burn - * @param decimals Number of decimals in amount to burn - * @param multiSigners Signing accounts if `owner` is a multisig - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Signature of the confirmed transaction - */ -export async function burnChecked( - connection: Connection, - payer: Signer, - account: PublicKey, - mint: PublicKey, - owner: Signer | PublicKey, - amount: number | bigint, - decimals: number, - multiSigners: Signer[] = [], - confirmOptions?: ConfirmOptions, - programId = TOKEN_PROGRAM_ID -): Promise { - const [ownerPublicKey, signers] = getSigners(owner, multiSigners); - - const transaction = new Transaction().add( - createBurnCheckedInstruction(account, mint, ownerPublicKey, amount, decimals, multiSigners, programId) - ); - - return await sendAndConfirmTransaction(connection, transaction, [payer, ...signers], confirmOptions); -} diff --git a/token/js/src/actions/closeAccount.ts b/token/js/src/actions/closeAccount.ts deleted file mode 100644 index 2781aa2f593..00000000000 --- a/token/js/src/actions/closeAccount.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { - ConfirmOptions, - Connection, - PublicKey, - sendAndConfirmTransaction, - Signer, - Transaction, - TransactionSignature, -} from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { createCloseAccountInstruction } from '../instructions/index'; -import { getSigners } from './internal'; - -/** - * Close a token account - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param account Account to close - * @param destination Account to receive the remaining balance of the closed account - * @param authority Authority which is allowed to close the account - * @param multiSigners Signing accounts if `authority` is a multisig - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Signature of the confirmed transaction - */ -export async function closeAccount( - connection: Connection, - payer: Signer, - account: PublicKey, - destination: PublicKey, - authority: Signer | PublicKey, - multiSigners: Signer[] = [], - confirmOptions?: ConfirmOptions, - programId = TOKEN_PROGRAM_ID -): Promise { - const [authorityPublicKey, signers] = getSigners(authority, multiSigners); - - const transaction = new Transaction().add( - createCloseAccountInstruction(account, destination, authorityPublicKey, multiSigners, programId) - ); - - return await sendAndConfirmTransaction(connection, transaction, [payer, ...signers], confirmOptions); -} diff --git a/token/js/src/actions/createAccount.ts b/token/js/src/actions/createAccount.ts deleted file mode 100644 index 8709ce886fa..00000000000 --- a/token/js/src/actions/createAccount.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { - ConfirmOptions, - Connection, - Keypair, - PublicKey, - sendAndConfirmTransaction, - Signer, - SystemProgram, - Transaction, -} from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { createInitializeAccountInstruction } from '../instructions/index'; -import { getMint } from '../state/index'; -import { createAssociatedTokenAccount } from './createAssociatedTokenAccount'; -import { getAccountLenForMint } from '../extensions/extensionType'; - -/** - * Create and initialize a new token account - * - * @param connection Connection to use - * @param payer Payer of the transaction and initialization fees - * @param mint Mint for the account - * @param owner Owner of the new account - * @param keypair Optional keypair, defaulting to the associated token account for the `mint` and `owner` - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Address of the new token account - */ -export async function createAccount( - connection: Connection, - payer: Signer, - mint: PublicKey, - owner: PublicKey, - keypair?: Keypair, - confirmOptions?: ConfirmOptions, - programId = TOKEN_PROGRAM_ID -): Promise { - // If a keypair isn't provided, create the associated token account and return its address - if (!keypair) return await createAssociatedTokenAccount(connection, payer, mint, owner, confirmOptions, programId); - - // Otherwise, create the account with the provided keypair and return its public key - const mintState = await getMint(connection, mint, confirmOptions?.commitment, programId); - const space = getAccountLenForMint(mintState); - const lamports = await connection.getMinimumBalanceForRentExemption(space); - - const transaction = new Transaction().add( - SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - newAccountPubkey: keypair.publicKey, - space, - lamports, - programId, - }), - createInitializeAccountInstruction(keypair.publicKey, mint, owner, programId) - ); - - await sendAndConfirmTransaction(connection, transaction, [payer, keypair], confirmOptions); - - return keypair.publicKey; -} diff --git a/token/js/src/actions/createAssociatedTokenAccount.ts b/token/js/src/actions/createAssociatedTokenAccount.ts deleted file mode 100644 index a74502d5e28..00000000000 --- a/token/js/src/actions/createAssociatedTokenAccount.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { ConfirmOptions, Connection, PublicKey, sendAndConfirmTransaction, Signer, Transaction } from '@solana/web3.js'; -import { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID } from '../constants'; -import { createAssociatedTokenAccountInstruction } from '../instructions/index'; -import { getAssociatedTokenAddress } from '../state/index'; - -/** - * Create and initialize a new associated token account - * - * @param connection Connection to use - * @param payer Payer of the transaction and initialization fees - * @param mint Mint for the account - * @param owner Owner of the new account - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * @param associatedTokenProgramId SPL Associated Token program account - * - * @return Address of the new associated token account - */ -export async function createAssociatedTokenAccount( - connection: Connection, - payer: Signer, - mint: PublicKey, - owner: PublicKey, - confirmOptions?: ConfirmOptions, - programId = TOKEN_PROGRAM_ID, - associatedTokenProgramId = ASSOCIATED_TOKEN_PROGRAM_ID -): Promise { - const associatedToken = await getAssociatedTokenAddress(mint, owner, false, programId, associatedTokenProgramId); - - const transaction = new Transaction().add( - createAssociatedTokenAccountInstruction( - payer.publicKey, - associatedToken, - owner, - mint, - programId, - associatedTokenProgramId - ) - ); - - await sendAndConfirmTransaction(connection, transaction, [payer], confirmOptions); - - return associatedToken; -} diff --git a/token/js/src/actions/createMint.ts b/token/js/src/actions/createMint.ts deleted file mode 100644 index 134cb816830..00000000000 --- a/token/js/src/actions/createMint.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { - ConfirmOptions, - Connection, - Keypair, - PublicKey, - sendAndConfirmTransaction, - Signer, - SystemProgram, - Transaction, -} from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { createInitializeMintInstruction } from '../instructions/index'; -import { getMinimumBalanceForRentExemptMint, MINT_SIZE } from '../state/index'; - -/** - * Create and initialize a new mint - * - * @param connection Connection to use - * @param payer Payer of the transaction and initialization fees - * @param mintAuthority Account or multisig that will control minting - * @param freezeAuthority Optional account or multisig that can freeze token accounts - * @param decimals Location of the decimal place - * @param keypair Optional keypair, defaulting to a new random one - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Address of the new mint - */ -export async function createMint( - connection: Connection, - payer: Signer, - mintAuthority: PublicKey, - freezeAuthority: PublicKey | null, - decimals: number, - keypair = Keypair.generate(), - confirmOptions?: ConfirmOptions, - programId = TOKEN_PROGRAM_ID -): Promise { - const lamports = await getMinimumBalanceForRentExemptMint(connection); - - const transaction = new Transaction().add( - SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - newAccountPubkey: keypair.publicKey, - space: MINT_SIZE, - lamports, - programId, - }), - createInitializeMintInstruction(keypair.publicKey, decimals, mintAuthority, freezeAuthority, programId) - ); - - await sendAndConfirmTransaction(connection, transaction, [payer, keypair], confirmOptions); - - return keypair.publicKey; -} diff --git a/token/js/src/actions/createMultisig.ts b/token/js/src/actions/createMultisig.ts deleted file mode 100644 index 920fb0c8e1b..00000000000 --- a/token/js/src/actions/createMultisig.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { - ConfirmOptions, - Connection, - Keypair, - PublicKey, - sendAndConfirmTransaction, - Signer, - SystemProgram, - Transaction, -} from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { createInitializeMultisigInstruction } from '../instructions/index'; -import { getMinimumBalanceForRentExemptMultisig, MULTISIG_SIZE } from '../state/index'; - -/** - * Create and initialize a new multisig - * - * @param connection Connection to use - * @param payer Payer of the transaction and initialization fees - * @param signers Full set of signers - * @param m Number of required signatures - * @param keypair Optional keypair, defaulting to a new random one - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Address of the new multisig - */ -export async function createMultisig( - connection: Connection, - payer: Signer, - signers: PublicKey[], - m: number, - keypair = Keypair.generate(), - confirmOptions?: ConfirmOptions, - programId = TOKEN_PROGRAM_ID -): Promise { - const lamports = await getMinimumBalanceForRentExemptMultisig(connection); - - const transaction = new Transaction().add( - SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - newAccountPubkey: keypair.publicKey, - space: MULTISIG_SIZE, - lamports, - programId, - }), - createInitializeMultisigInstruction(keypair.publicKey, signers, m, programId) - ); - - await sendAndConfirmTransaction(connection, transaction, [payer, keypair], confirmOptions); - - return keypair.publicKey; -} diff --git a/token/js/src/actions/createNativeMint.ts b/token/js/src/actions/createNativeMint.ts deleted file mode 100644 index 79d26d8d550..00000000000 --- a/token/js/src/actions/createNativeMint.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ConfirmOptions, Connection, sendAndConfirmTransaction, Signer, Transaction } from '@solana/web3.js'; -import { TOKEN_2022_PROGRAM_ID, NATIVE_MINT_2022 } from '../constants'; -import { createCreateNativeMintInstruction } from '../instructions/index'; - -/** - * Create native mint - * - * @param connection Connection to use - * @param payer Payer of the transaction and initialization fees - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * @param nativeMint Native mint id associated with program - */ -export async function createNativeMint( - connection: Connection, - payer: Signer, - confirmOptions?: ConfirmOptions, - nativeMint = NATIVE_MINT_2022, - programId = TOKEN_2022_PROGRAM_ID -): Promise { - const transaction = new Transaction().add( - createCreateNativeMintInstruction(payer.publicKey, nativeMint, programId) - ); - await sendAndConfirmTransaction(connection, transaction, [payer], confirmOptions); -} diff --git a/token/js/src/actions/createWrappedNativeAccount.ts b/token/js/src/actions/createWrappedNativeAccount.ts deleted file mode 100644 index d91b743af3a..00000000000 --- a/token/js/src/actions/createWrappedNativeAccount.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { - ConfirmOptions, - Connection, - Keypair, - PublicKey, - sendAndConfirmTransaction, - Signer, - SystemProgram, - Transaction, -} from '@solana/web3.js'; -import { ASSOCIATED_TOKEN_PROGRAM_ID, NATIVE_MINT, TOKEN_PROGRAM_ID } from '../constants'; -import { - createAssociatedTokenAccountInstruction, - createInitializeAccountInstruction, - createSyncNativeInstruction, -} from '../instructions/index'; -import { ACCOUNT_SIZE, getAssociatedTokenAddress, getMinimumBalanceForRentExemptAccount } from '../state/index'; -import { createAccount } from './createAccount'; - -/** - * Create, initialize, and fund a new wrapped native SOL account - * - * @param connection Connection to use - * @param payer Payer of the transaction and initialization fees - * @param owner Owner of the new token account - * @param amount Number of lamports to wrap - * @param keypair Optional keypair, defaulting to the associated token account for the native mint and `owner` - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Address of the new wrapped native SOL account - */ -export async function createWrappedNativeAccount( - connection: Connection, - payer: Signer, - owner: PublicKey, - amount: number, - keypair?: Keypair, - confirmOptions?: ConfirmOptions, - programId = TOKEN_PROGRAM_ID, - nativeMint = NATIVE_MINT -): Promise { - // If the amount provided is explicitly 0 or NaN, just create the account without funding it - if (!amount) return await createAccount(connection, payer, nativeMint, owner, keypair, confirmOptions, programId); - - // If a keypair isn't provided, create the account at the owner's ATA for the native mint and return its address - if (!keypair) { - const associatedToken = await getAssociatedTokenAddress( - nativeMint, - owner, - false, - programId, - ASSOCIATED_TOKEN_PROGRAM_ID - ); - - const transaction = new Transaction().add( - createAssociatedTokenAccountInstruction( - payer.publicKey, - associatedToken, - owner, - nativeMint, - programId, - ASSOCIATED_TOKEN_PROGRAM_ID - ), - SystemProgram.transfer({ - fromPubkey: payer.publicKey, - toPubkey: associatedToken, - lamports: amount, - }), - createSyncNativeInstruction(associatedToken, programId) - ); - - await sendAndConfirmTransaction(connection, transaction, [payer], confirmOptions); - - return associatedToken; - } - - // Otherwise, create the account with the provided keypair and return its public key - const lamports = await getMinimumBalanceForRentExemptAccount(connection); - - const transaction = new Transaction().add( - SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - newAccountPubkey: keypair.publicKey, - space: ACCOUNT_SIZE, - lamports, - programId, - }), - SystemProgram.transfer({ - fromPubkey: payer.publicKey, - toPubkey: keypair.publicKey, - lamports: amount, - }), - createInitializeAccountInstruction(keypair.publicKey, nativeMint, owner, programId) - ); - - await sendAndConfirmTransaction(connection, transaction, [payer, keypair], confirmOptions); - - return keypair.publicKey; -} diff --git a/token/js/src/actions/freezeAccount.ts b/token/js/src/actions/freezeAccount.ts deleted file mode 100644 index d3b56f352f6..00000000000 --- a/token/js/src/actions/freezeAccount.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { - ConfirmOptions, - Connection, - PublicKey, - sendAndConfirmTransaction, - Signer, - Transaction, - TransactionSignature, -} from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { createFreezeAccountInstruction } from '../instructions/index'; -import { getSigners } from './internal'; - -/** - * Freeze a token account - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param account Account to freeze - * @param mint Mint for the account - * @param authority Mint freeze authority - * @param multiSigners Signing accounts if `authority` is a multisig - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Signature of the confirmed transaction - */ -export async function freezeAccount( - connection: Connection, - payer: Signer, - account: PublicKey, - mint: PublicKey, - authority: Signer | PublicKey, - multiSigners: Signer[] = [], - confirmOptions?: ConfirmOptions, - programId = TOKEN_PROGRAM_ID -): Promise { - const [authorityPublicKey, signers] = getSigners(authority, multiSigners); - - const transaction = new Transaction().add( - createFreezeAccountInstruction(account, mint, authorityPublicKey, multiSigners, programId) - ); - - return await sendAndConfirmTransaction(connection, transaction, [payer, ...signers], confirmOptions); -} diff --git a/token/js/src/actions/getOrCreateAssociatedTokenAccount.ts b/token/js/src/actions/getOrCreateAssociatedTokenAccount.ts deleted file mode 100644 index 2b0e774a3d1..00000000000 --- a/token/js/src/actions/getOrCreateAssociatedTokenAccount.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { - Commitment, - ConfirmOptions, - Connection, - PublicKey, - sendAndConfirmTransaction, - Signer, - Transaction, -} from '@solana/web3.js'; -import { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID } from '../constants'; -import { - TokenAccountNotFoundError, - TokenInvalidAccountOwnerError, - TokenInvalidMintError, - TokenInvalidOwnerError, -} from '../errors'; -import { createAssociatedTokenAccountInstruction } from '../instructions/index'; -import { Account, getAccount, getAssociatedTokenAddress } from '../state/index'; - -/** - * Retrieve the associated token account, or create it if it doesn't exist - * - * @param connection Connection to use - * @param payer Payer of the transaction and initialization fees - * @param mint Mint associated with the account to set or verify - * @param owner Owner of the account to set or verify - * @param allowOwnerOffCurve Allow the owner account to be a PDA (Program Derived Address) - * @param commitment Desired level of commitment for querying the state - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * @param associatedTokenProgramId SPL Associated Token program account - * - * @return Address of the new associated token account - */ -export async function getOrCreateAssociatedTokenAccount( - connection: Connection, - payer: Signer, - mint: PublicKey, - owner: PublicKey, - allowOwnerOffCurve = false, - commitment?: Commitment, - confirmOptions?: ConfirmOptions, - programId = TOKEN_PROGRAM_ID, - associatedTokenProgramId = ASSOCIATED_TOKEN_PROGRAM_ID -): Promise { - const associatedToken = await getAssociatedTokenAddress( - mint, - owner, - allowOwnerOffCurve, - programId, - associatedTokenProgramId - ); - - // This is the optimal logic, considering TX fee, client-side computation, RPC roundtrips and guaranteed idempotent. - // Sadly we can't do this atomically. - let account: Account; - try { - account = await getAccount(connection, associatedToken, commitment, programId); - } catch (error: unknown) { - // TokenAccountNotFoundError can be possible if the associated address has already received some lamports, - // becoming a system account. Assuming program derived addressing is safe, this is the only case for the - // TokenInvalidAccountOwnerError in this code path. - if (error instanceof TokenAccountNotFoundError || error instanceof TokenInvalidAccountOwnerError) { - // As this isn't atomic, it's possible others can create associated accounts meanwhile. - try { - const transaction = new Transaction().add( - createAssociatedTokenAccountInstruction( - payer.publicKey, - associatedToken, - owner, - mint, - programId, - associatedTokenProgramId - ) - ); - - await sendAndConfirmTransaction(connection, transaction, [payer], confirmOptions); - } catch (error: unknown) { - // Ignore all errors; for now there is no API-compatible way to selectively ignore the expected - // instruction error if the associated account exists already. - } - - // Now this should always succeed - account = await getAccount(connection, associatedToken, commitment, programId); - } else { - throw error; - } - } - - if (!account.mint.equals(mint)) throw new TokenInvalidMintError(); - if (!account.owner.equals(owner)) throw new TokenInvalidOwnerError(); - - return account; -} diff --git a/token/js/src/actions/index.ts b/token/js/src/actions/index.ts deleted file mode 100644 index ddf0af38103..00000000000 --- a/token/js/src/actions/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -export * from './createMint'; -export * from './createNativeMint'; -export * from './createAccount'; -export * from './createWrappedNativeAccount'; -export * from './createMultisig'; -export * from './transfer'; -export * from './approve'; -export * from './revoke'; -export * from './setAuthority'; -export * from './mintTo'; -export * from './burn'; -export * from './closeAccount'; -export * from './freezeAccount'; -export * from './thawAccount'; -export * from './transferChecked'; -export * from './approveChecked'; -export * from './mintToChecked'; -export * from './burnChecked'; -export * from './syncNative'; - -export * from './createAssociatedTokenAccount'; -export * from './getOrCreateAssociatedTokenAccount'; diff --git a/token/js/src/actions/internal.ts b/token/js/src/actions/internal.ts deleted file mode 100644 index f080fb20db6..00000000000 --- a/token/js/src/actions/internal.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { PublicKey, Signer } from '@solana/web3.js'; - -/** @internal */ -export function getSigners(signerOrMultisig: Signer | PublicKey, multiSigners: Signer[]): [PublicKey, Signer[]] { - return signerOrMultisig instanceof PublicKey - ? [signerOrMultisig, multiSigners] - : [signerOrMultisig.publicKey, [signerOrMultisig]]; -} diff --git a/token/js/src/actions/mintTo.ts b/token/js/src/actions/mintTo.ts deleted file mode 100644 index 2c376171373..00000000000 --- a/token/js/src/actions/mintTo.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { - ConfirmOptions, - Connection, - PublicKey, - sendAndConfirmTransaction, - Signer, - Transaction, - TransactionSignature, -} from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { createMintToInstruction } from '../instructions/index'; -import { getSigners } from './internal'; - -/** - * Mint tokens to an account - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param mint Mint for the account - * @param destination Address of the account to mint to - * @param authority Minting authority - * @param amount Amount to mint - * @param multiSigners Signing accounts if `authority` is a multisig - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Signature of the confirmed transaction - */ -export async function mintTo( - connection: Connection, - payer: Signer, - mint: PublicKey, - destination: PublicKey, - authority: Signer | PublicKey, - amount: number | bigint, - multiSigners: Signer[] = [], - confirmOptions?: ConfirmOptions, - programId = TOKEN_PROGRAM_ID -): Promise { - const [authorityPublicKey, signers] = getSigners(authority, multiSigners); - - const transaction = new Transaction().add( - createMintToInstruction(mint, destination, authorityPublicKey, amount, multiSigners, programId) - ); - - return await sendAndConfirmTransaction(connection, transaction, [payer, ...signers], confirmOptions); -} diff --git a/token/js/src/actions/mintToChecked.ts b/token/js/src/actions/mintToChecked.ts deleted file mode 100644 index 8cea0a95b3a..00000000000 --- a/token/js/src/actions/mintToChecked.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { - ConfirmOptions, - Connection, - PublicKey, - sendAndConfirmTransaction, - Signer, - Transaction, - TransactionSignature, -} from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { createMintToCheckedInstruction } from '../instructions/index'; -import { getSigners } from './internal'; - -/** - * Mint tokens to an account, asserting the token mint and decimals - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param mint Mint for the account - * @param destination Address of the account to mint to - * @param authority Minting authority - * @param amount Amount to mint - * @param decimals Number of decimals in amount to mint - * @param multiSigners Signing accounts if `authority` is a multisig - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Signature of the confirmed transaction - */ -export async function mintToChecked( - connection: Connection, - payer: Signer, - mint: PublicKey, - destination: PublicKey, - authority: Signer | PublicKey, - amount: number | bigint, - decimals: number, - multiSigners: Signer[] = [], - confirmOptions?: ConfirmOptions, - programId = TOKEN_PROGRAM_ID -): Promise { - const [authorityPublicKey, signers] = getSigners(authority, multiSigners); - - const transaction = new Transaction().add( - createMintToCheckedInstruction(mint, destination, authorityPublicKey, amount, decimals, multiSigners, programId) - ); - - return await sendAndConfirmTransaction(connection, transaction, [payer, ...signers], confirmOptions); -} diff --git a/token/js/src/actions/revoke.ts b/token/js/src/actions/revoke.ts deleted file mode 100644 index 23eeea3809e..00000000000 --- a/token/js/src/actions/revoke.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { - ConfirmOptions, - Connection, - PublicKey, - sendAndConfirmTransaction, - Signer, - Transaction, - TransactionSignature, -} from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { createRevokeInstruction } from '../instructions/index'; -import { getSigners } from './internal'; - -/** - * Revoke approval for the transfer of tokens from an account - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param account Address of the token account - * @param owner Owner of the account - * @param multiSigners Signing accounts if `owner` is a multisig - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Signature of the confirmed transaction - */ -export async function revoke( - connection: Connection, - payer: Signer, - account: PublicKey, - owner: Signer | PublicKey, - multiSigners: Signer[] = [], - confirmOptions?: ConfirmOptions, - programId = TOKEN_PROGRAM_ID -): Promise { - const [ownerPublicKey, signers] = getSigners(owner, multiSigners); - - const transaction = new Transaction().add( - createRevokeInstruction(account, ownerPublicKey, multiSigners, programId) - ); - - return await sendAndConfirmTransaction(connection, transaction, [payer, ...signers], confirmOptions); -} diff --git a/token/js/src/actions/setAuthority.ts b/token/js/src/actions/setAuthority.ts deleted file mode 100644 index 95f3a48cd01..00000000000 --- a/token/js/src/actions/setAuthority.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { - ConfirmOptions, - Connection, - PublicKey, - sendAndConfirmTransaction, - Signer, - Transaction, - TransactionSignature, -} from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { AuthorityType, createSetAuthorityInstruction } from '../instructions/index'; -import { getSigners } from './internal'; - -/** - * Assign a new authority to the account - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param account Address of the account - * @param currentAuthority Current authority of the specified type - * @param authorityType Type of authority to set - * @param newAuthority New authority of the account - * @param multiSigners Signing accounts if `currentAuthority` is a multisig - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Signature of the confirmed transaction - */ -export async function setAuthority( - connection: Connection, - payer: Signer, - account: PublicKey, - currentAuthority: Signer | PublicKey, - authorityType: AuthorityType, - newAuthority: PublicKey | null, - multiSigners: Signer[] = [], - confirmOptions?: ConfirmOptions, - programId = TOKEN_PROGRAM_ID -): Promise { - const [currentAuthorityPublicKey, signers] = getSigners(currentAuthority, multiSigners); - - const transaction = new Transaction().add( - createSetAuthorityInstruction( - account, - currentAuthorityPublicKey, - authorityType, - newAuthority, - multiSigners, - programId - ) - ); - - return await sendAndConfirmTransaction(connection, transaction, [payer, ...signers], confirmOptions); -} diff --git a/token/js/src/actions/syncNative.ts b/token/js/src/actions/syncNative.ts deleted file mode 100644 index f97cf9f960e..00000000000 --- a/token/js/src/actions/syncNative.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { - ConfirmOptions, - Connection, - PublicKey, - sendAndConfirmTransaction, - Signer, - Transaction, - TransactionSignature, -} from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { createSyncNativeInstruction } from '../instructions/index'; - -/** - * Sync the balance of a native SPL token account to the underlying system account's lamports - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param account Native account to sync - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Signature of the confirmed transaction - */ -export async function syncNative( - connection: Connection, - payer: Signer, - account: PublicKey, - confirmOptions?: ConfirmOptions, - programId = TOKEN_PROGRAM_ID -): Promise { - const transaction = new Transaction().add(createSyncNativeInstruction(account, programId)); - - return await sendAndConfirmTransaction(connection, transaction, [payer], confirmOptions); -} diff --git a/token/js/src/actions/thawAccount.ts b/token/js/src/actions/thawAccount.ts deleted file mode 100644 index 89be4f61ca0..00000000000 --- a/token/js/src/actions/thawAccount.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { - ConfirmOptions, - Connection, - PublicKey, - sendAndConfirmTransaction, - Signer, - Transaction, - TransactionSignature, -} from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { createThawAccountInstruction } from '../instructions/index'; -import { getSigners } from './internal'; - -/** - * Thaw (unfreeze) a token account - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param account Account to thaw - * @param mint Mint for the account - * @param authority Mint freeze authority - * @param multiSigners Signing accounts if `authority` is a multisig - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Signature of the confirmed transaction - */ -export async function thawAccount( - connection: Connection, - payer: Signer, - account: PublicKey, - mint: PublicKey, - authority: Signer | PublicKey, - multiSigners: Signer[] = [], - confirmOptions?: ConfirmOptions, - programId = TOKEN_PROGRAM_ID -): Promise { - const [authorityPublicKey, signers] = getSigners(authority, multiSigners); - - const transaction = new Transaction().add( - createThawAccountInstruction(account, mint, authorityPublicKey, multiSigners, programId) - ); - - return await sendAndConfirmTransaction(connection, transaction, [payer, ...signers], confirmOptions); -} diff --git a/token/js/src/actions/transfer.ts b/token/js/src/actions/transfer.ts deleted file mode 100644 index f51f5b59a5e..00000000000 --- a/token/js/src/actions/transfer.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { - ConfirmOptions, - Connection, - PublicKey, - sendAndConfirmTransaction, - Signer, - Transaction, - TransactionSignature, -} from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { createTransferInstruction } from '../instructions/index'; -import { getSigners } from './internal'; - -/** - * Transfer tokens from one account to another - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param source Source account - * @param destination Destination account - * @param owner Owner of the source account - * @param amount Number of tokens to transfer - * @param multiSigners Signing accounts if `owner` is a multisig - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Signature of the confirmed transaction - */ -export async function transfer( - connection: Connection, - payer: Signer, - source: PublicKey, - destination: PublicKey, - owner: Signer | PublicKey, - amount: number | bigint, - multiSigners: Signer[] = [], - confirmOptions?: ConfirmOptions, - programId = TOKEN_PROGRAM_ID -): Promise { - const [ownerPublicKey, signers] = getSigners(owner, multiSigners); - - const transaction = new Transaction().add( - createTransferInstruction(source, destination, ownerPublicKey, amount, multiSigners, programId) - ); - - return await sendAndConfirmTransaction(connection, transaction, [payer, ...signers], confirmOptions); -} diff --git a/token/js/src/actions/transferChecked.ts b/token/js/src/actions/transferChecked.ts deleted file mode 100644 index 3104e14497a..00000000000 --- a/token/js/src/actions/transferChecked.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { - ConfirmOptions, - Connection, - PublicKey, - sendAndConfirmTransaction, - Signer, - Transaction, - TransactionSignature, -} from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { createTransferCheckedInstruction } from '../instructions/index'; -import { getSigners } from './internal'; - -/** - * Transfer tokens from one account to another, asserting the token mint and decimals - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param source Source account - * @param mint Mint for the account - * @param destination Destination account - * @param owner Owner of the source account - * @param amount Number of tokens to transfer - * @param decimals Number of decimals in transfer amount - * @param multiSigners Signing accounts if `owner` is a multisig - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Signature of the confirmed transaction - */ -export async function transferChecked( - connection: Connection, - payer: Signer, - source: PublicKey, - mint: PublicKey, - destination: PublicKey, - owner: Signer | PublicKey, - amount: number | bigint, - decimals: number, - multiSigners: Signer[] = [], - confirmOptions?: ConfirmOptions, - programId = TOKEN_PROGRAM_ID -): Promise { - const [ownerPublicKey, signers] = getSigners(owner, multiSigners); - - const transaction = new Transaction().add( - createTransferCheckedInstruction( - source, - mint, - destination, - ownerPublicKey, - amount, - decimals, - multiSigners, - programId - ) - ); - - return await sendAndConfirmTransaction(connection, transaction, [payer, ...signers], confirmOptions); -} diff --git a/token/js/src/constants.ts b/token/js/src/constants.ts deleted file mode 100644 index 55524086f9d..00000000000 --- a/token/js/src/constants.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { PublicKey } from '@solana/web3.js'; - -/** Address of the SPL Token program */ -export const TOKEN_PROGRAM_ID = new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'); - -/** Address of the SPL Token 2022 program */ -export const TOKEN_2022_PROGRAM_ID = new PublicKey('TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb'); - -/** Address of the SPL Associated Token Account program */ -export const ASSOCIATED_TOKEN_PROGRAM_ID = new PublicKey('ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'); - -/** Address of the special mint for wrapped native SOL in spl-token */ -export const NATIVE_MINT = new PublicKey('So11111111111111111111111111111111111111112'); - -/** Address of the special mint for wrapped native SOL in spl-token-2022 */ -export const NATIVE_MINT_2022 = new PublicKey('9pan9bMn5HatX4EJdBwg9VgCa7Uz5HL8N1m5D3NdXejP'); - -/** Check that the token program provided is not `Tokenkeg...`, useful when using extensions */ -export function programSupportsExtensions(programId: PublicKey): boolean { - if (programId === TOKEN_PROGRAM_ID) { - return false; - } else { - return true; - } -} diff --git a/token/js/src/errors.ts b/token/js/src/errors.ts deleted file mode 100644 index 5e633d35202..00000000000 --- a/token/js/src/errors.ts +++ /dev/null @@ -1,66 +0,0 @@ -/** Base class for errors */ -export abstract class TokenError extends Error { - constructor(message?: string) { - super(message); - } -} - -/** Thrown if an account is not found at the expected address */ -export class TokenAccountNotFoundError extends TokenError { - name = 'TokenAccountNotFoundError'; -} - -/** Thrown if a program state account is not a valid Account */ -export class TokenInvalidAccountError extends TokenError { - name = 'TokenInvalidAccountError'; -} - -/** Thrown if a program state account is not owned by the expected token program */ -export class TokenInvalidAccountOwnerError extends TokenError { - name = 'TokenInvalidAccountOwnerError'; -} - -/** Thrown if the byte length of an program state account doesn't match the expected size */ -export class TokenInvalidAccountSizeError extends TokenError { - name = 'TokenInvalidAccountSizeError'; -} - -/** Thrown if the mint of a token account doesn't match the expected mint */ -export class TokenInvalidMintError extends TokenError { - name = 'TokenInvalidMintError'; -} - -/** Thrown if the owner of a token account doesn't match the expected owner */ -export class TokenInvalidOwnerError extends TokenError { - name = 'TokenInvalidOwnerError'; -} - -/** Thrown if the owner of a token account is a PDA (Program Derived Address) */ -export class TokenOwnerOffCurveError extends TokenError { - name = 'TokenOwnerOffCurveError'; -} - -/** Thrown if an instruction's program is invalid */ -export class TokenInvalidInstructionProgramError extends TokenError { - name = 'TokenInvalidInstructionProgramError'; -} - -/** Thrown if an instruction's keys are invalid */ -export class TokenInvalidInstructionKeysError extends TokenError { - name = 'TokenInvalidInstructionKeysError'; -} - -/** Thrown if an instruction's data is invalid */ -export class TokenInvalidInstructionDataError extends TokenError { - name = 'TokenInvalidInstructionDataError'; -} - -/** Thrown if an instruction's type is invalid */ -export class TokenInvalidInstructionTypeError extends TokenError { - name = 'TokenInvalidInstructionTypeError'; -} - -/** Thrown if the program does not support the desired instruction */ -export class TokenUnsupportedInstructionError extends TokenError { - name = 'TokenUnsupportedInstructionError'; -} diff --git a/token/js/src/extensions/accountType.ts b/token/js/src/extensions/accountType.ts deleted file mode 100644 index 6389c930f68..00000000000 --- a/token/js/src/extensions/accountType.ts +++ /dev/null @@ -1,6 +0,0 @@ -export enum AccountType { - Uninitialized, - Mint, - Account, -} -export const ACCOUNT_TYPE_SIZE = 1; diff --git a/token/js/src/extensions/defaultAccountState/actions.ts b/token/js/src/extensions/defaultAccountState/actions.ts deleted file mode 100644 index 27957312b88..00000000000 --- a/token/js/src/extensions/defaultAccountState/actions.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { - ConfirmOptions, - Connection, - PublicKey, - sendAndConfirmTransaction, - Signer, - Transaction, - TransactionSignature, -} from '@solana/web3.js'; -import { TOKEN_2022_PROGRAM_ID } from '../../constants'; -import { AccountState } from '../../state'; -import { - createInitializeDefaultAccountStateInstruction, - createUpdateDefaultAccountStateInstruction, -} from './instructions'; -import { getSigners } from '../../actions/internal'; - -/** - * Initialize a default account state on a mint - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param mint Mint to initialize with extension - * @param state Account state with which to initialize new accounts - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Signature of the confirmed transaction - */ -export async function initializeDefaultAccountState( - connection: Connection, - payer: Signer, - mint: PublicKey, - state: AccountState, - confirmOptions?: ConfirmOptions, - programId = TOKEN_2022_PROGRAM_ID -): Promise { - const transaction = new Transaction().add(createInitializeDefaultAccountStateInstruction(mint, state, programId)); - - return await sendAndConfirmTransaction(connection, transaction, [payer], confirmOptions); -} - -/** - * Update the default account state on a mint - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param mint Mint to modify - * @param state New account state to set on created accounts - * @param freezeAuthority Freeze authority of the mint - * @param multiSigners Signing accounts if `freezeAuthority` is a multisig - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Signature of the confirmed transaction - */ -export async function updateDefaultAccountState( - connection: Connection, - payer: Signer, - mint: PublicKey, - state: AccountState, - freezeAuthority: Signer | PublicKey, - multiSigners: Signer[] = [], - confirmOptions?: ConfirmOptions, - programId = TOKEN_2022_PROGRAM_ID -): Promise { - const [freezeAuthorityPublicKey, signers] = getSigners(freezeAuthority, multiSigners); - - const transaction = new Transaction().add( - createUpdateDefaultAccountStateInstruction(mint, state, freezeAuthorityPublicKey, signers, programId) - ); - - return await sendAndConfirmTransaction(connection, transaction, [payer, ...signers], confirmOptions); -} diff --git a/token/js/src/extensions/defaultAccountState/index.ts b/token/js/src/extensions/defaultAccountState/index.ts deleted file mode 100644 index b38df5f4622..00000000000 --- a/token/js/src/extensions/defaultAccountState/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './actions'; -export * from './instructions'; -export * from './state'; diff --git a/token/js/src/extensions/defaultAccountState/instructions.ts b/token/js/src/extensions/defaultAccountState/instructions.ts deleted file mode 100644 index 18a41e1ae60..00000000000 --- a/token/js/src/extensions/defaultAccountState/instructions.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { PublicKey, Signer, TransactionInstruction } from '@solana/web3.js'; -import { AccountState } from '../../state/account'; -import { TokenInstruction } from '../../instructions/types'; -import { programSupportsExtensions, TOKEN_2022_PROGRAM_ID } from '../../constants'; -import { TokenUnsupportedInstructionError } from '../../errors'; - -export enum DefaultAccountStateInstruction { - Initialize = 0, - Update = 1, -} - -/** TODO: docs */ -export interface DefaultAccountStateInstructionData { - instruction: TokenInstruction.DefaultAccountStateExtension; - defaultAccountStateInstruction: DefaultAccountStateInstruction; - accountState: AccountState; -} - -/** TODO: docs */ -export const defaultAccountStateInstructionData = struct([ - u8('instruction'), - u8('defaultAccountStateInstruction'), - u8('accountState'), -]); - -/** - * Construct an InitializeDefaultAccountState instruction - * - * @param mint Mint to initialize - * @param accountState Default account state to set on all new accounts - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createInitializeDefaultAccountStateInstruction( - mint: PublicKey, - accountState: AccountState, - programId = TOKEN_2022_PROGRAM_ID -): TransactionInstruction { - if (!programSupportsExtensions(programId)) { - throw new TokenUnsupportedInstructionError(); - } - const keys = [{ pubkey: mint, isSigner: false, isWritable: true }]; - const data = Buffer.alloc(defaultAccountStateInstructionData.span); - defaultAccountStateInstructionData.encode( - { - instruction: TokenInstruction.DefaultAccountStateExtension, - defaultAccountStateInstruction: DefaultAccountStateInstruction.Initialize, - accountState, - }, - data - ); - - return new TransactionInstruction({ keys, programId, data }); -} - -/** - * Construct an UpdateDefaultAccountState instruction - * - * @param mint Mint to update - * @param accountState Default account state to set on all accounts - * @param freezeAuthority The mint's freeze authority - * @param signers The signer account(s) for a multisig - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createUpdateDefaultAccountStateInstruction( - mint: PublicKey, - accountState: AccountState, - freezeAuthority: PublicKey, - multiSigners: Signer[] = [], - programId = TOKEN_2022_PROGRAM_ID -): TransactionInstruction { - if (!programSupportsExtensions(programId)) { - throw new TokenUnsupportedInstructionError(); - } - const keys = [{ pubkey: mint, isSigner: false, isWritable: true }]; - keys.push({ pubkey: freezeAuthority, isSigner: !multiSigners.length, isWritable: false }); - for (const signer of multiSigners) { - keys.push({ pubkey: signer.publicKey, isSigner: true, isWritable: false }); - } - - const data = Buffer.alloc(defaultAccountStateInstructionData.span); - defaultAccountStateInstructionData.encode( - { - instruction: TokenInstruction.DefaultAccountStateExtension, - defaultAccountStateInstruction: DefaultAccountStateInstruction.Update, - accountState, - }, - data - ); - - return new TransactionInstruction({ keys, programId, data }); -} diff --git a/token/js/src/extensions/defaultAccountState/state.ts b/token/js/src/extensions/defaultAccountState/state.ts deleted file mode 100644 index 0b316bca0c4..00000000000 --- a/token/js/src/extensions/defaultAccountState/state.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { AccountState } from '../../state'; -import { Mint } from '../../state'; -import { ExtensionType, getExtensionData } from '../extensionType'; - -/** DefaultAccountState as stored by the program */ -export interface DefaultAccountState { - /** Default AccountState in which new accounts are initialized */ - state: AccountState; -} - -/** Buffer layout for de/serializing a transfer fee config extension */ -export const DefaultAccountStateLayout = struct([u8('state')]); - -export const DEFAULT_ACCOUNT_STATE_SIZE = DefaultAccountStateLayout.span; - -export function getDefaultAccountState(mint: Mint): DefaultAccountState | null { - const extensionData = getExtensionData(ExtensionType.DefaultAccountState, mint.tlvData); - if (extensionData !== null) { - return DefaultAccountStateLayout.decode(extensionData); - } else { - return null; - } -} diff --git a/token/js/src/extensions/extensionType.ts b/token/js/src/extensions/extensionType.ts deleted file mode 100644 index cbc0f4760f6..00000000000 --- a/token/js/src/extensions/extensionType.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { ACCOUNT_SIZE } from '../state/account'; -import { Mint, MINT_SIZE } from '../state/mint'; -import { MULTISIG_SIZE } from '../state/multisig'; -import { ACCOUNT_TYPE_SIZE } from './accountType'; -import { MEMO_TRANSFER_SIZE } from './memoTransfer'; -import { DEFAULT_ACCOUNT_STATE_SIZE } from './defaultAccountState'; -import { MINT_CLOSE_AUTHORITY_SIZE } from './mintCloseAuthority'; -import { IMMUTABLE_OWNER_SIZE } from './immutableOwner'; -import { TRANSFER_FEE_CONFIG_SIZE, TRANSFER_FEE_AMOUNT_SIZE } from './transferFee'; -import { NON_TRANSFERABLE_SIZE } from './nonTransferable'; -import { INTEREST_BEARING_MINT_CONFIG_STATE_SIZE } from './interestBearingMint/state'; - -export enum ExtensionType { - Uninitialized, - TransferFeeConfig, - TransferFeeAmount, - MintCloseAuthority, - ConfidentialTransferMint, - ConfidentialTransferAccount, - DefaultAccountState, - ImmutableOwner, - MemoTransfer, - NonTransferable, - InterestBearingMint, -} - -export const TYPE_SIZE = 2; -export const LENGTH_SIZE = 2; - -// NOTE: All of these should eventually use their type's Span instead of these -// constants. This is provided for at least creation to work. -export function getTypeLen(e: ExtensionType): number { - switch (e) { - case ExtensionType.Uninitialized: - return 0; - case ExtensionType.TransferFeeConfig: - return TRANSFER_FEE_CONFIG_SIZE; - case ExtensionType.TransferFeeAmount: - return TRANSFER_FEE_AMOUNT_SIZE; - case ExtensionType.MintCloseAuthority: - return MINT_CLOSE_AUTHORITY_SIZE; - case ExtensionType.ConfidentialTransferMint: - return 97; - case ExtensionType.ConfidentialTransferAccount: - return 286; - case ExtensionType.DefaultAccountState: - return DEFAULT_ACCOUNT_STATE_SIZE; - case ExtensionType.ImmutableOwner: - return IMMUTABLE_OWNER_SIZE; - case ExtensionType.MemoTransfer: - return MEMO_TRANSFER_SIZE; - case ExtensionType.NonTransferable: - return NON_TRANSFERABLE_SIZE; - case ExtensionType.InterestBearingMint: - return INTEREST_BEARING_MINT_CONFIG_STATE_SIZE; - default: - throw Error(`Unknown extension type: ${e}`); - } -} - -export function getAccountTypeOfMintType(e: ExtensionType): ExtensionType { - switch (e) { - case ExtensionType.TransferFeeConfig: - return ExtensionType.TransferFeeAmount; - case ExtensionType.ConfidentialTransferMint: - return ExtensionType.ConfidentialTransferAccount; - case ExtensionType.TransferFeeAmount: - case ExtensionType.ConfidentialTransferAccount: - case ExtensionType.DefaultAccountState: - case ExtensionType.ImmutableOwner: - case ExtensionType.MemoTransfer: - case ExtensionType.MintCloseAuthority: - case ExtensionType.NonTransferable: - case ExtensionType.Uninitialized: - case ExtensionType.InterestBearingMint: - return ExtensionType.Uninitialized; - } -} - -function getLen(extensionTypes: ExtensionType[], baseSize: number): number { - if (extensionTypes.length === 0) { - return baseSize; - } else { - const accountLength = - ACCOUNT_SIZE + - ACCOUNT_TYPE_SIZE + - extensionTypes - .filter((element, i) => i === extensionTypes.indexOf(element)) - .map((element) => getTypeLen(element) + TYPE_SIZE + LENGTH_SIZE) - .reduce((a, b) => a + b); - if (accountLength === MULTISIG_SIZE) { - return accountLength + TYPE_SIZE; - } else { - return accountLength; - } - } -} - -export function getMintLen(extensionTypes: ExtensionType[]): number { - return getLen(extensionTypes, MINT_SIZE); -} - -export function getAccountLen(extensionTypes: ExtensionType[]): number { - return getLen(extensionTypes, ACCOUNT_SIZE); -} - -export function getExtensionData(extension: ExtensionType, tlvData: Buffer): Buffer | null { - let extensionTypeIndex = 0; - while (extensionTypeIndex < tlvData.length) { - const entryType = tlvData.readUInt16LE(extensionTypeIndex); - const entryLength = tlvData.readUInt16LE(extensionTypeIndex + TYPE_SIZE); - const typeIndex = extensionTypeIndex + TYPE_SIZE + LENGTH_SIZE; - if (entryType == extension) { - return tlvData.slice(typeIndex, typeIndex + entryLength); - } - extensionTypeIndex = typeIndex + entryLength; - } - return null; -} - -export function getExtensionTypes(tlvData: Buffer): ExtensionType[] { - const extensionTypes = []; - let extensionTypeIndex = 0; - while (extensionTypeIndex < tlvData.length) { - const entryType = tlvData.readUInt16LE(extensionTypeIndex); - extensionTypes.push(entryType); - const entryLength = tlvData.readUInt16LE(extensionTypeIndex + TYPE_SIZE); - extensionTypeIndex += TYPE_SIZE + LENGTH_SIZE + entryLength; - } - return extensionTypes; -} - -export function getAccountLenForMint(mint: Mint): number { - const extensionTypes = getExtensionTypes(mint.tlvData); - const accountExtensions = extensionTypes.map(getAccountTypeOfMintType); - return getAccountLen(accountExtensions); -} diff --git a/token/js/src/extensions/immutableOwner.ts b/token/js/src/extensions/immutableOwner.ts deleted file mode 100644 index 5e88aa0aa27..00000000000 --- a/token/js/src/extensions/immutableOwner.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { struct } from '@solana/buffer-layout'; -import { Account } from '../state/account'; -import { ExtensionType, getExtensionData } from './extensionType'; - -/** ImmutableOwner as stored by the program */ -export interface ImmutableOwner {} // eslint-disable-line - -/** Buffer layout for de/serializing an account */ -export const ImmutableOwnerLayout = struct([]); - -export const IMMUTABLE_OWNER_SIZE = ImmutableOwnerLayout.span; - -export function getImmutableOwner(account: Account): ImmutableOwner | null { - const extensionData = getExtensionData(ExtensionType.ImmutableOwner, account.tlvData); - if (extensionData !== null) { - return ImmutableOwnerLayout.decode(extensionData); - } else { - return null; - } -} diff --git a/token/js/src/extensions/index.ts b/token/js/src/extensions/index.ts deleted file mode 100644 index 3803bb7d9e2..00000000000 --- a/token/js/src/extensions/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -export * from './accountType'; -export * from './defaultAccountState/index'; -export * from './extensionType'; -export * from './memoTransfer/index'; -export * from './mintCloseAuthority'; -export * from './immutableOwner'; -export * from './interestBearingMint'; -export * from './nonTransferable'; -export * from './transferFee/index'; diff --git a/token/js/src/extensions/interestBearingMint/actions.ts b/token/js/src/extensions/interestBearingMint/actions.ts deleted file mode 100644 index 552aadfafa0..00000000000 --- a/token/js/src/extensions/interestBearingMint/actions.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { - ConfirmOptions, - Connection, - Keypair, - PublicKey, - sendAndConfirmTransaction, - Signer, - SystemProgram, - Transaction, -} from '@solana/web3.js'; -import { getSigners } from '../../actions/internal'; -import { TOKEN_2022_PROGRAM_ID } from '../../constants'; -import { createInitializeMintInstruction } from '../../instructions'; -import { ExtensionType, getMintLen } from '../extensionType'; -import { - createInitializeInterestBearingMintInstruction, - createUpdateRateInterestBearingMintInstruction, -} from './instructions'; - -/** - * Initialize an interest bearing account on a mint - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param mintAuthority Account or multisig that will control minting - * @param freezeAuthority Optional account or multisig that can freeze token accounts - * @param rateAuthority The public key for the account that can update the rate - * @param rate The initial interest rate - * @param decimals Location of the decimal place - * @param keypair Optional keypair, defaulting to a new random one - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Public key of the mint - */ -export async function createInterestBearingMint( - connection: Connection, - payer: Signer, - mintAuthority: PublicKey, - freezeAuthority: PublicKey, - rateAuthority: PublicKey, - rate: number, - decimals: number, - keypair = Keypair.generate(), - confirmOptions?: ConfirmOptions, - programId = TOKEN_2022_PROGRAM_ID -): Promise { - const mintLen = getMintLen([ExtensionType.InterestBearingMint]); - const lamports = await connection.getMinimumBalanceForRentExemption(mintLen); - const transaction = new Transaction().add( - SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - newAccountPubkey: keypair.publicKey, - space: mintLen, - lamports, - programId, - }), - createInitializeInterestBearingMintInstruction(keypair.publicKey, rateAuthority, rate, programId), - createInitializeMintInstruction(keypair.publicKey, decimals, mintAuthority, freezeAuthority, programId) - ); - await sendAndConfirmTransaction(connection, transaction, [payer, keypair], confirmOptions); - return keypair.publicKey; -} - -/** - * Update the interest rate of an interest bearing account - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param mint Public key of the mint - * @param rateAuthority The public key for the account that can update the rate - * @param rate The initial interest rate - * @param multiSigners Signing accounts if `owner` is a multisig - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Signature of the confirmed transaction - */ -export async function updateRateInterestBearingMint( - connection: Connection, - payer: Signer, - mint: PublicKey, - rateAuthority: Signer, - rate: number, - multiSigners: Signer[] = [], - confirmOptions?: ConfirmOptions, - programId = TOKEN_2022_PROGRAM_ID -): Promise { - const [rateAuthorityPublicKey, signers] = getSigners(rateAuthority, multiSigners); - const transaction = new Transaction().add( - createUpdateRateInterestBearingMintInstruction(mint, rateAuthorityPublicKey, rate, signers, programId) - ); - - return await sendAndConfirmTransaction(connection, transaction, [payer, rateAuthority, ...signers], confirmOptions); -} diff --git a/token/js/src/extensions/interestBearingMint/index.ts b/token/js/src/extensions/interestBearingMint/index.ts deleted file mode 100644 index b38df5f4622..00000000000 --- a/token/js/src/extensions/interestBearingMint/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './actions'; -export * from './instructions'; -export * from './state'; diff --git a/token/js/src/extensions/interestBearingMint/instructions.ts b/token/js/src/extensions/interestBearingMint/instructions.ts deleted file mode 100644 index ca330ce5f74..00000000000 --- a/token/js/src/extensions/interestBearingMint/instructions.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { struct, s16, u8 } from '@solana/buffer-layout'; -import { publicKey } from '@solana/buffer-layout-utils'; -import { PublicKey, Signer, TransactionInstruction } from '@solana/web3.js'; -import { TOKEN_2022_PROGRAM_ID } from '../../constants'; -import { TokenInstruction } from '../../instructions'; -import { addSigners } from '../../instructions/internal'; - -export enum InterestBearingMintInstruction { - Initialize = 0, - UpdateRate = 1, -} - -export interface InterestBearingMintInitializeInstructionData { - instruction: TokenInstruction.InterestBearingMintExtension; - interestBearingMintInstruction: InterestBearingMintInstruction.Initialize; - rateAuthority: PublicKey; - rate: number; -} - -export interface InterestBearingMintUpdateRateInstructionData { - instruction: TokenInstruction.InterestBearingMintExtension; - interestBearingMintInstruction: InterestBearingMintInstruction.UpdateRate; - rate: number; -} - -export const interestBearingMintInitializeInstructionData = struct([ - u8('instruction'), - u8('interestBearingMintInstruction'), - // TODO: Make this an optional public key - publicKey('rateAuthority'), - s16('rate'), -]); - -export const interestBearingMintUpdateRateInstructionData = struct([ - u8('instruction'), - u8('interestBearingMintInstruction'), - s16('rate'), -]); - -/** - * Construct an InitializeInterestBearingMint instruction - * - * @param mint Mint to initialize - * @param rateAuthority The public key for the account that can update the rate - * @param rate The initial interest rate - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createInitializeInterestBearingMintInstruction( - mint: PublicKey, - rateAuthority: PublicKey, - rate: number, - programId = TOKEN_2022_PROGRAM_ID -) { - const keys = [{ pubkey: mint, isSigner: false, isWritable: true }]; - const data = Buffer.alloc(interestBearingMintInitializeInstructionData.span); - interestBearingMintInitializeInstructionData.encode( - { - instruction: TokenInstruction.InterestBearingMintExtension, - interestBearingMintInstruction: InterestBearingMintInstruction.Initialize, - rateAuthority, - rate, - }, - data - ); - return new TransactionInstruction({ keys, programId, data }); -} - -/** - * Construct an UpdateRateInterestBearingMint instruction - * - * @param mint Mint to initialize - * @param rateAuthority The public key for the account that can update the rate - * @param rate The updated interest rate - * @param multiSigners Signing accounts if `rateAuthority` is a multisig - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createUpdateRateInterestBearingMintInstruction( - mint: PublicKey, - rateAuthority: PublicKey, - rate: number, - multiSigners: Signer[] = [], - programId = TOKEN_2022_PROGRAM_ID -) { - const keys = addSigners( - [ - { pubkey: mint, isSigner: false, isWritable: true }, - { pubkey: rateAuthority, isSigner: !multiSigners.length, isWritable: false }, - ], - rateAuthority, - multiSigners - ); - const data = Buffer.alloc(interestBearingMintUpdateRateInstructionData.span); - interestBearingMintUpdateRateInstructionData.encode( - { - instruction: TokenInstruction.InterestBearingMintExtension, - interestBearingMintInstruction: InterestBearingMintInstruction.UpdateRate, - rate, - }, - data - ); - return new TransactionInstruction({ keys, programId, data }); -} diff --git a/token/js/src/extensions/interestBearingMint/state.ts b/token/js/src/extensions/interestBearingMint/state.ts deleted file mode 100644 index e901a385937..00000000000 --- a/token/js/src/extensions/interestBearingMint/state.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { s16, ns64, struct } from '@solana/buffer-layout'; -import { publicKey } from '@solana/buffer-layout-utils'; -import { PublicKey } from '@solana/web3.js'; -import { Mint } from '../../state'; -import { ExtensionType, getExtensionData } from '../extensionType'; - -export interface InterestBearingMintConfigState { - rateAuthority: PublicKey; - initializationTimestamp: BigInt; - preUpdateAverageRate: number; - lastUpdateTimestamp: BigInt; - currentRate: number; -} - -export const InterestBearingMintConfigStateLayout = struct([ - publicKey('rateAuthority'), - ns64('initializationTimestamp'), - s16('preUpdateAverageRate'), - ns64('lastUpdateTimestamp'), - s16('currentRate'), -]); - -export const INTEREST_BEARING_MINT_CONFIG_STATE_SIZE = InterestBearingMintConfigStateLayout.span; - -export function getInterestBearingMintConfigState(mint: Mint): InterestBearingMintConfigState | null { - const extensionData = getExtensionData(ExtensionType.InterestBearingMint, mint.tlvData); - if (extensionData !== null) { - return InterestBearingMintConfigStateLayout.decode(extensionData); - } - return null; -} diff --git a/token/js/src/extensions/memoTransfer/actions.ts b/token/js/src/extensions/memoTransfer/actions.ts deleted file mode 100644 index 883af8609bb..00000000000 --- a/token/js/src/extensions/memoTransfer/actions.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { - ConfirmOptions, - Connection, - PublicKey, - sendAndConfirmTransaction, - Signer, - Transaction, - TransactionSignature, -} from '@solana/web3.js'; -import { TOKEN_2022_PROGRAM_ID } from '../../constants'; -import { - createEnableRequiredMemoTransfersInstruction, - createDisableRequiredMemoTransfersInstruction, -} from './instructions'; -import { getSigners } from '../../actions/internal'; - -/** - * Enable memo transfers on the given account - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param account Account to modify - * @param owner Owner of the account - * @param multiSigners Signing accounts if `owner` is a multisig - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Signature of the confirmed transaction - */ -export async function enableRequiredMemoTransfers( - connection: Connection, - payer: Signer, - account: PublicKey, - owner: Signer | PublicKey, - multiSigners: Signer[] = [], - confirmOptions?: ConfirmOptions, - programId = TOKEN_2022_PROGRAM_ID -): Promise { - const [ownerPublicKey, signers] = getSigners(owner, multiSigners); - - const transaction = new Transaction().add( - createEnableRequiredMemoTransfersInstruction(account, ownerPublicKey, signers, programId) - ); - - return await sendAndConfirmTransaction(connection, transaction, [payer, ...signers], confirmOptions); -} - -/** - * Disable memo transfers on the given account - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param account Account to modify - * @param owner Owner of the account - * @param multiSigners Signing accounts if `owner` is a multisig - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Signature of the confirmed transaction - */ -export async function disableRequiredMemoTransfers( - connection: Connection, - payer: Signer, - account: PublicKey, - owner: Signer | PublicKey, - multiSigners: Signer[] = [], - confirmOptions?: ConfirmOptions, - programId = TOKEN_2022_PROGRAM_ID -): Promise { - const [ownerPublicKey, signers] = getSigners(owner, multiSigners); - - const transaction = new Transaction().add( - createDisableRequiredMemoTransfersInstruction(account, ownerPublicKey, signers, programId) - ); - - return await sendAndConfirmTransaction(connection, transaction, [payer, ...signers], confirmOptions); -} diff --git a/token/js/src/extensions/memoTransfer/index.ts b/token/js/src/extensions/memoTransfer/index.ts deleted file mode 100644 index b38df5f4622..00000000000 --- a/token/js/src/extensions/memoTransfer/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './actions'; -export * from './instructions'; -export * from './state'; diff --git a/token/js/src/extensions/memoTransfer/instructions.ts b/token/js/src/extensions/memoTransfer/instructions.ts deleted file mode 100644 index b58d8d83fff..00000000000 --- a/token/js/src/extensions/memoTransfer/instructions.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { PublicKey, Signer, TransactionInstruction } from '@solana/web3.js'; -import { TokenInstruction } from '../../instructions/types'; -import { programSupportsExtensions, TOKEN_2022_PROGRAM_ID } from '../../constants'; -import { TokenUnsupportedInstructionError } from '../../errors'; - -export enum MemoTransferInstruction { - Enable = 0, - Disable = 1, -} - -/** TODO: docs */ -export interface MemoTransferInstructionData { - instruction: TokenInstruction.MemoTransferExtension; - memoTransferInstruction: MemoTransferInstruction; -} - -/** TODO: docs */ -export const memoTransferInstructionData = struct([ - u8('instruction'), - u8('memoTransferInstruction'), -]); - -/** - * Construct an EnableRequiredMemoTransfers instruction - * - * @param account Token account to update - * @param authority The account's owner/delegate - * @param signers The signer account(s) - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createEnableRequiredMemoTransfersInstruction( - account: PublicKey, - authority: PublicKey, - multiSigners: Signer[] = [], - programId = TOKEN_2022_PROGRAM_ID -): TransactionInstruction { - return createMemoTransferInstruction(/* enable */ true, account, authority, multiSigners, programId); -} - -/** - * Construct a DisableMemoTransfer instruction - * - * @param account Token account to update - * @param authority The account's owner/delegate - * @param signers The signer account(s) - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createDisableRequiredMemoTransfersInstruction( - account: PublicKey, - authority: PublicKey, - multiSigners: Signer[] = [], - programId = TOKEN_2022_PROGRAM_ID -): TransactionInstruction { - return createMemoTransferInstruction(/* enable */ false, account, authority, multiSigners, programId); -} - -function createMemoTransferInstruction( - enable: boolean, - account: PublicKey, - authority: PublicKey, - multiSigners: Signer[], - programId: PublicKey -): TransactionInstruction { - if (!programSupportsExtensions(programId)) { - throw new TokenUnsupportedInstructionError(); - } - const keys = [{ pubkey: account, isSigner: false, isWritable: true }]; - keys.push({ pubkey: authority, isSigner: !multiSigners.length, isWritable: false }); - for (const signer of multiSigners) { - keys.push({ pubkey: signer.publicKey, isSigner: true, isWritable: false }); - } - - const data = Buffer.alloc(memoTransferInstructionData.span); - memoTransferInstructionData.encode( - { - instruction: TokenInstruction.MemoTransferExtension, - memoTransferInstruction: enable ? MemoTransferInstruction.Enable : MemoTransferInstruction.Disable, - }, - data - ); - - return new TransactionInstruction({ keys, programId, data }); -} diff --git a/token/js/src/extensions/memoTransfer/state.ts b/token/js/src/extensions/memoTransfer/state.ts deleted file mode 100644 index e8a8649f806..00000000000 --- a/token/js/src/extensions/memoTransfer/state.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { struct } from '@solana/buffer-layout'; -import { bool } from '@solana/buffer-layout-utils'; -import { Account } from '../../state'; -import { ExtensionType, getExtensionData } from '../extensionType'; - -/** MemoTransfer as stored by the program */ -export interface MemoTransfer { - /** Require transfers into this account to be accompanied by a memo */ - requireIncomingTransferMemos: boolean; -} - -/** Buffer layout for de/serializing a transfer fee config extension */ -export const MemoTransferLayout = struct([bool('requireIncomingTransferMemos')]); - -export const MEMO_TRANSFER_SIZE = MemoTransferLayout.span; - -export function getMemoTransfer(account: Account): MemoTransfer | null { - const extensionData = getExtensionData(ExtensionType.MemoTransfer, account.tlvData); - if (extensionData !== null) { - return MemoTransferLayout.decode(extensionData); - } else { - return null; - } -} diff --git a/token/js/src/extensions/mintCloseAuthority.ts b/token/js/src/extensions/mintCloseAuthority.ts deleted file mode 100644 index 956979d0a67..00000000000 --- a/token/js/src/extensions/mintCloseAuthority.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { struct } from '@solana/buffer-layout'; -import { publicKey } from '@solana/buffer-layout-utils'; -import { PublicKey } from '@solana/web3.js'; -import { Mint } from '../state/mint'; -import { ExtensionType, getExtensionData } from './extensionType'; - -/** MintCloseAuthority as stored by the program */ -export interface MintCloseAuthority { - closeAuthority: PublicKey; -} - -/** Buffer layout for de/serializing a mint */ -export const MintCloseAuthorityLayout = struct([publicKey('closeAuthority')]); - -export const MINT_CLOSE_AUTHORITY_SIZE = MintCloseAuthorityLayout.span; - -export function getMintCloseAuthority(mint: Mint): MintCloseAuthority | null { - const extensionData = getExtensionData(ExtensionType.MintCloseAuthority, mint.tlvData); - if (extensionData !== null) { - return MintCloseAuthorityLayout.decode(extensionData); - } else { - return null; - } -} diff --git a/token/js/src/extensions/nonTransferable.ts b/token/js/src/extensions/nonTransferable.ts deleted file mode 100644 index f025abd6c90..00000000000 --- a/token/js/src/extensions/nonTransferable.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { struct } from '@solana/buffer-layout'; -import { Mint } from '../state/mint'; -import { ExtensionType, getExtensionData } from './extensionType'; - -/** Non-transferable state as stored by the program */ -export interface NonTransferable {} // eslint-disable-line - -/** Buffer layout for de/serializing an account */ -export const NonTransferableLayout = struct([]); - -export const NON_TRANSFERABLE_SIZE = NonTransferableLayout.span; - -export function getNonTransferable(mint: Mint): NonTransferable | null { - const extensionData = getExtensionData(ExtensionType.NonTransferable, mint.tlvData); - if (extensionData !== null) { - return NonTransferableLayout.decode(extensionData); - } else { - return null; - } -} diff --git a/token/js/src/extensions/transferFee/actions.ts b/token/js/src/extensions/transferFee/actions.ts deleted file mode 100644 index 4f541bff75a..00000000000 --- a/token/js/src/extensions/transferFee/actions.ts +++ /dev/null @@ -1,167 +0,0 @@ -import { - ConfirmOptions, - Connection, - PublicKey, - sendAndConfirmTransaction, - Signer, - Transaction, - TransactionSignature, -} from '@solana/web3.js'; -import { TOKEN_2022_PROGRAM_ID } from '../../constants'; -import { - createTransferCheckedWithFeeInstruction, - createHarvestWithheldTokensToMintInstruction, - createWithdrawWithheldTokensFromAccountsInstruction, - createWithdrawWithheldTokensFromMintInstruction, -} from './instructions'; -import { getSigners } from '../../actions/internal'; - -/** - * Transfer tokens from one account to another, asserting the transfer fee, token mint, and decimals - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param source Source account - * @param mint Mint for the account - * @param destination Destination account - * @param owner Owner of the source account - * @param amount Number of tokens to transfer - * @param decimals Number of decimals in transfer amount - * @param multiSigners Signing accounts if `owner` is a multisig - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Signature of the confirmed transaction - */ -export async function transferCheckedWithFee( - connection: Connection, - payer: Signer, - source: PublicKey, - mint: PublicKey, - destination: PublicKey, - owner: Signer | PublicKey, - amount: bigint, - decimals: number, - fee: bigint, - multiSigners: Signer[] = [], - confirmOptions?: ConfirmOptions, - programId = TOKEN_2022_PROGRAM_ID -): Promise { - const [ownerPublicKey, signers] = getSigners(owner, multiSigners); - - const transaction = new Transaction().add( - createTransferCheckedWithFeeInstruction( - source, - mint, - destination, - ownerPublicKey, - amount, - decimals, - fee, - multiSigners, - programId - ) - ); - - return await sendAndConfirmTransaction(connection, transaction, [payer, ...signers], confirmOptions); -} - -/** - * Withdraw withheld tokens from mint - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param mint The token mint - * @param destination The destination account - * @param authority The mint's withdraw withheld tokens authority - * @param multiSigners Signing accounts if `owner` is a multisig - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Signature of the confirmed transaction - */ -export async function withdrawWithheldTokensFromMint( - connection: Connection, - payer: Signer, - mint: PublicKey, - destination: PublicKey, - authority: Signer | PublicKey, - multiSigners: Signer[] = [], - confirmOptions?: ConfirmOptions, - programId = TOKEN_2022_PROGRAM_ID -): Promise { - const [authorityPublicKey, signers] = getSigners(authority, multiSigners); - - const transaction = new Transaction().add( - createWithdrawWithheldTokensFromMintInstruction(mint, destination, authorityPublicKey, signers, programId) - ); - - return await sendAndConfirmTransaction(connection, transaction, [payer, ...signers], confirmOptions); -} - -/** - * Withdraw withheld tokens from accounts - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param mint The token mint - * @param destination The destination account - * @param authority The mint's withdraw withheld tokens authority - * @param multiSigners Signing accounts if `owner` is a multisig - * @param sources Source accounts from which to withdraw withheld fees - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Signature of the confirmed transaction - */ -export async function withdrawWithheldTokensFromAccounts( - connection: Connection, - payer: Signer, - mint: PublicKey, - destination: PublicKey, - authority: Signer | PublicKey, - multiSigners: Signer[], - sources: PublicKey[], - confirmOptions?: ConfirmOptions, - programId = TOKEN_2022_PROGRAM_ID -): Promise { - const [authorityPublicKey, signers] = getSigners(authority, multiSigners); - - const transaction = new Transaction().add( - createWithdrawWithheldTokensFromAccountsInstruction( - mint, - destination, - authorityPublicKey, - signers, - sources, - programId - ) - ); - - return await sendAndConfirmTransaction(connection, transaction, [payer, ...signers], confirmOptions); -} - -/** - * Harvest withheld tokens from accounts to the mint - * - * @param connection Connection to use - * @param payer Payer of the transaction fees - * @param mint The token mint - * @param sources Source accounts from which to withdraw withheld fees - * @param confirmOptions Options for confirming the transaction - * @param programId SPL Token program account - * - * @return Signature of the confirmed transaction - */ -export async function harvestWithheldTokensToMint( - connection: Connection, - payer: Signer, - mint: PublicKey, - sources: PublicKey[], - confirmOptions?: ConfirmOptions, - programId = TOKEN_2022_PROGRAM_ID -): Promise { - const transaction = new Transaction().add(createHarvestWithheldTokensToMintInstruction(mint, sources, programId)); - - return await sendAndConfirmTransaction(connection, transaction, [payer], confirmOptions); -} diff --git a/token/js/src/extensions/transferFee/index.ts b/token/js/src/extensions/transferFee/index.ts deleted file mode 100644 index b38df5f4622..00000000000 --- a/token/js/src/extensions/transferFee/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './actions'; -export * from './instructions'; -export * from './state'; diff --git a/token/js/src/extensions/transferFee/instructions.ts b/token/js/src/extensions/transferFee/instructions.ts deleted file mode 100644 index f045a20099f..00000000000 --- a/token/js/src/extensions/transferFee/instructions.ts +++ /dev/null @@ -1,834 +0,0 @@ -import { struct, u8, u16 } from '@solana/buffer-layout'; -import { publicKey, u64 } from '@solana/buffer-layout-utils'; -import { AccountMeta, PublicKey, Signer, TransactionInstruction } from '@solana/web3.js'; -import { - TokenUnsupportedInstructionError, - TokenInvalidInstructionDataError, - TokenInvalidInstructionKeysError, - TokenInvalidInstructionProgramError, - TokenInvalidInstructionTypeError, -} from '../../errors'; -import { TokenInstruction } from '../../instructions/types'; -import { programSupportsExtensions, TOKEN_2022_PROGRAM_ID } from '../../constants'; - -export enum TransferFeeInstruction { - InitializeTransferFeeConfig = 0, - TransferCheckedWithFee = 1, - WithdrawWithheldTokensFromMint = 2, - WithdrawWithheldTokensFromAccounts = 3, - HarvestWithheldTokensToMint = 4, - SetTransferFee = 5, -} - -// InitializeTransferFeeConfig - -/** TODO: docs */ -export interface InitializeTransferFeeConfigInstructionData { - instruction: TokenInstruction.TransferFeeExtension; - transferFeeInstruction: TransferFeeInstruction.InitializeTransferFeeConfig; - transferFeeConfigAuthorityOption: 1 | 0; - transferFeeConfigAuthority: PublicKey; - withdrawWithheldAuthorityOption: 1 | 0; - withdrawWithheldAuthority: PublicKey; - transferFeeBasisPoints: number; - maximumFee: BigInt; -} - -/** TODO: docs */ -export const initializeTransferFeeConfigInstructionData = struct([ - u8('instruction'), - u8('transferFeeInstruction'), - u8('transferFeeConfigAuthorityOption'), - publicKey('transferFeeConfigAuthority'), - u8('withdrawWithheldAuthorityOption'), - publicKey('withdrawWithheldAuthority'), - u16('transferFeeBasisPoints'), - u64('maximumFee'), -]); - -/** - * Construct an InitializeTransferFeeConfig instruction - * - * @param mint Token mint account - * @param transferFeeConfigAuthority Optional authority that can update the fees - * @param withdrawWithheldAuthority Optional authority that can withdraw fees - * @param transferFeeBasisPoints Amount of transfer collected as fees, expressed as basis points of the transfer amount - * @param maximumFee Maximum fee assessed on transfers - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createInitializeTransferFeeConfigInstruction( - mint: PublicKey, - transferFeeConfigAuthority: PublicKey | null, - withdrawWithheldAuthority: PublicKey | null, - transferFeeBasisPoints: number, - maximumFee: BigInt, - programId = TOKEN_2022_PROGRAM_ID -): TransactionInstruction { - if (!programSupportsExtensions(programId)) { - throw new TokenUnsupportedInstructionError(); - } - const keys = [{ pubkey: mint, isSigner: false, isWritable: true }]; - - const data = Buffer.alloc(initializeTransferFeeConfigInstructionData.span); - initializeTransferFeeConfigInstructionData.encode( - { - instruction: TokenInstruction.TransferFeeExtension, - transferFeeInstruction: TransferFeeInstruction.InitializeTransferFeeConfig, - transferFeeConfigAuthorityOption: transferFeeConfigAuthority ? 1 : 0, - transferFeeConfigAuthority: transferFeeConfigAuthority || new PublicKey(0), - withdrawWithheldAuthorityOption: withdrawWithheldAuthority ? 1 : 0, - withdrawWithheldAuthority: withdrawWithheldAuthority || new PublicKey(0), - transferFeeBasisPoints: transferFeeBasisPoints, - maximumFee: maximumFee, - }, - data - ); - - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid InitializeTransferFeeConfig instruction */ -export interface DecodedInitializeTransferFeeConfigInstruction { - programId: PublicKey; - keys: { - mint: AccountMeta; - }; - data: { - instruction: TokenInstruction.TransferFeeExtension; - transferFeeInstruction: TransferFeeInstruction.InitializeTransferFeeConfig; - transferFeeConfigAuthority: PublicKey | null; - withdrawWithheldAuthority: PublicKey | null; - transferFeeBasisPoints: number; - maximumFee: BigInt; - }; -} - -/** - * Decode an InitializeTransferFeeConfig instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeInitializeTransferFeeConfigInstruction( - instruction: TransactionInstruction, - programId: PublicKey -): DecodedInitializeTransferFeeConfigInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== initializeTransferFeeConfigInstructionData.span) - throw new TokenInvalidInstructionDataError(); - - const { - keys: { mint }, - data, - } = decodeInitializeTransferFeeConfigInstructionUnchecked(instruction); - if ( - data.instruction !== TokenInstruction.TransferFeeExtension || - data.transferFeeInstruction !== TransferFeeInstruction.InitializeTransferFeeConfig - ) - throw new TokenInvalidInstructionTypeError(); - if (!mint) throw new TokenInvalidInstructionKeysError(); - - return { - programId, - keys: { - mint, - }, - data, - }; -} - -/** A decoded, non-validated InitializeTransferFeeConfig instruction */ -export interface DecodedInitializeTransferFeeConfigInstructionUnchecked { - programId: PublicKey; - keys: { - mint: AccountMeta | undefined; - }; - data: { - instruction: TokenInstruction.TransferFeeExtension; - transferFeeInstruction: TransferFeeInstruction.InitializeTransferFeeConfig; - transferFeeConfigAuthority: PublicKey | null; - withdrawWithheldAuthority: PublicKey | null; - transferFeeBasisPoints: number; - maximumFee: BigInt; - }; -} - -/** - * Decode an InitializeTransferFeeConfig instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeInitializeTransferFeeConfigInstructionUnchecked({ - programId, - keys: [mint], - data, -}: TransactionInstruction): DecodedInitializeTransferFeeConfigInstructionUnchecked { - const { - instruction, - transferFeeInstruction, - transferFeeConfigAuthorityOption, - transferFeeConfigAuthority, - withdrawWithheldAuthorityOption, - withdrawWithheldAuthority, - transferFeeBasisPoints, - maximumFee, - } = initializeTransferFeeConfigInstructionData.decode(data); - - return { - programId, - keys: { - mint, - }, - data: { - instruction, - transferFeeInstruction, - transferFeeConfigAuthority: transferFeeConfigAuthorityOption ? transferFeeConfigAuthority : null, - withdrawWithheldAuthority: withdrawWithheldAuthorityOption ? withdrawWithheldAuthority : null, - transferFeeBasisPoints, - maximumFee, - }, - }; -} - -// TransferCheckedWithFee -export interface TransferCheckedWithFeeInstructionData { - instruction: TokenInstruction.TransferFeeExtension; - transferFeeInstruction: TransferFeeInstruction.TransferCheckedWithFee; - amount: BigInt; - decimals: number; - fee: BigInt; -} - -export const transferCheckedWithFeeInstructionData = struct([ - u8('instruction'), - u8('transferFeeInstruction'), - u64('amount'), - u8('decimals'), - u64('fee'), -]); - -/** - * Construct an TransferCheckedWithFee instruction - * - * @param source The source account - * @param mint The token mint - * @param destination The destination account - * @param authority The source account's owner/delegate - * @param signers The signer account(s) - * @param amount The amount of tokens to transfer - * @param decimals The expected number of base 10 digits to the right of the decimal place - * @param fee The expected fee assesed on this transfer, calculated off-chain based on the transferFeeBasisPoints and maximumFee of the mint. - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createTransferCheckedWithFeeInstruction( - source: PublicKey, - mint: PublicKey, - destination: PublicKey, - authority: PublicKey, - amount: BigInt, - decimals: number, - fee: BigInt, - multiSigners: Signer[] = [], - programId = TOKEN_2022_PROGRAM_ID -): TransactionInstruction { - if (!programSupportsExtensions(programId)) { - throw new TokenUnsupportedInstructionError(); - } - const data = Buffer.alloc(transferCheckedWithFeeInstructionData.span); - transferCheckedWithFeeInstructionData.encode( - { - instruction: TokenInstruction.TransferFeeExtension, - transferFeeInstruction: TransferFeeInstruction.TransferCheckedWithFee, - amount, - decimals, - fee, - }, - data - ); - const keys: AccountMeta[] = []; - keys.push({ pubkey: source, isSigner: false, isWritable: true }); - keys.push({ pubkey: mint, isSigner: false, isWritable: false }); - keys.push({ pubkey: destination, isSigner: false, isWritable: true }); - keys.push({ pubkey: authority, isSigner: !multiSigners.length, isWritable: false }); - for (const signer of multiSigners) { - keys.push({ pubkey: signer.publicKey, isSigner: true, isWritable: false }); - } - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid TransferCheckedWithFee instruction */ -export interface DecodedTransferCheckedWithFeeInstruction { - programId: PublicKey; - keys: { - source: AccountMeta; - mint: AccountMeta; - destination: AccountMeta; - authority: AccountMeta; - signers: AccountMeta[] | null; - }; - data: { - instruction: TokenInstruction.TransferFeeExtension; - transferFeeInstruction: TransferFeeInstruction.TransferCheckedWithFee; - amount: BigInt; - decimals: number; - fee: BigInt; - }; -} - -/** - * Decode a TransferCheckedWithFee instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeTransferCheckedWithFeeInstruction( - instruction: TransactionInstruction, - programId: PublicKey -): DecodedTransferCheckedWithFeeInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== transferCheckedWithFeeInstructionData.span) - throw new TokenInvalidInstructionDataError(); - - const { - keys: { source, mint, destination, authority, signers }, - data, - } = decodeTransferCheckedWithFeeInstructionUnchecked(instruction); - if ( - data.instruction !== TokenInstruction.TransferFeeExtension || - data.transferFeeInstruction !== TransferFeeInstruction.TransferCheckedWithFee - ) - throw new TokenInvalidInstructionTypeError(); - if (!mint) throw new TokenInvalidInstructionKeysError(); - - return { - programId, - keys: { - source, - mint, - destination, - authority, - signers: signers ? signers : null, - }, - data, - }; -} - -/** A decoded, non-validated TransferCheckedWithFees instruction */ -export interface DecodedTransferCheckedWithFeeInstructionUnchecked { - programId: PublicKey; - keys: { - source: AccountMeta; - mint: AccountMeta; - destination: AccountMeta; - authority: AccountMeta; - signers: AccountMeta[] | undefined; - }; - data: { - instruction: TokenInstruction.TransferFeeExtension; - transferFeeInstruction: TransferFeeInstruction.TransferCheckedWithFee; - amount: BigInt; - decimals: number; - fee: BigInt; - }; -} - -/** - * Decode a TransferCheckedWithFees instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeTransferCheckedWithFeeInstructionUnchecked({ - programId, - keys: [source, mint, destination, authority, ...signers], - data, -}: TransactionInstruction): DecodedTransferCheckedWithFeeInstructionUnchecked { - const { instruction, transferFeeInstruction, amount, decimals, fee } = - transferCheckedWithFeeInstructionData.decode(data); - - return { - programId, - keys: { - source, - mint, - destination, - authority, - signers, - }, - data: { - instruction, - transferFeeInstruction, - amount, - decimals, - fee, - }, - }; -} - -// WithdrawWithheldTokensFromMint -export interface WithdrawWithheldTokensFromMintInstructionData { - instruction: TokenInstruction.TransferFeeExtension; - transferFeeInstruction: TransferFeeInstruction.WithdrawWithheldTokensFromMint; -} - -export const withdrawWithheldTokensFromMintInstructionData = struct([ - u8('instruction'), - u8('transferFeeInstruction'), -]); - -/** - * Construct a WithdrawWithheldTokensFromMint instruction - * - * @param mint The token mint - * @param destination The destination account - * @param authority The source account's owner/delegate - * @param signers The signer account(s) - * @param programID SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createWithdrawWithheldTokensFromMintInstruction( - mint: PublicKey, - destination: PublicKey, - authority: PublicKey, - signers: Signer[] = [], - programId = TOKEN_2022_PROGRAM_ID -): TransactionInstruction { - if (!programSupportsExtensions(programId)) { - throw new TokenUnsupportedInstructionError(); - } - const data = Buffer.alloc(withdrawWithheldTokensFromMintInstructionData.span); - withdrawWithheldTokensFromMintInstructionData.encode( - { - instruction: TokenInstruction.TransferFeeExtension, - transferFeeInstruction: TransferFeeInstruction.WithdrawWithheldTokensFromMint, - }, - data - ); - const keys: AccountMeta[] = []; - keys.push( - { pubkey: mint, isSigner: false, isWritable: true }, - { pubkey: destination, isSigner: false, isWritable: true }, - { pubkey: authority, isSigner: !signers.length, isWritable: false } - ); - for (const signer of signers) { - keys.push({ pubkey: signer.publicKey, isSigner: true, isWritable: false }); - } - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid WithdrawWithheldTokensFromMint instruction */ -export interface DecodedWithdrawWithheldTokensFromMintInstruction { - programId: PublicKey; - keys: { - mint: AccountMeta; - destination: AccountMeta; - authority: AccountMeta; - signers: AccountMeta[] | null; - }; - data: { - instruction: TokenInstruction.TransferFeeExtension; - transferFeeInstruction: TransferFeeInstruction.WithdrawWithheldTokensFromMint; - }; -} - -/** - * Decode a WithdrawWithheldTokensFromMint instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeWithdrawWithheldTokensFromMintInstruction( - instruction: TransactionInstruction, - programId: PublicKey -): DecodedWithdrawWithheldTokensFromMintInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== withdrawWithheldTokensFromMintInstructionData.span) - throw new TokenInvalidInstructionDataError(); - - const { - keys: { mint, destination, authority, signers }, - data, - } = decodeWithdrawWithheldTokensFromMintInstructionUnchecked(instruction); - if ( - data.instruction !== TokenInstruction.TransferFeeExtension || - data.transferFeeInstruction !== TransferFeeInstruction.WithdrawWithheldTokensFromMint - ) - throw new TokenInvalidInstructionTypeError(); - if (!mint) throw new TokenInvalidInstructionKeysError(); - - return { - programId, - keys: { - mint, - destination, - authority, - signers: signers ? signers : null, - }, - data, - }; -} - -/** A decoded, valid WithdrawWithheldTokensFromMint instruction */ -export interface DecodedWithdrawWithheldTokensFromMintInstructionUnchecked { - programId: PublicKey; - keys: { - mint: AccountMeta; - destination: AccountMeta; - authority: AccountMeta; - signers: AccountMeta[] | null; - }; - data: { - instruction: TokenInstruction.TransferFeeExtension; - transferFeeInstruction: TransferFeeInstruction.WithdrawWithheldTokensFromMint; - }; -} - -/** - * Decode a WithdrawWithheldTokensFromMint instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeWithdrawWithheldTokensFromMintInstructionUnchecked({ - programId, - keys: [mint, destination, authority, ...signers], - data, -}: TransactionInstruction): DecodedWithdrawWithheldTokensFromMintInstructionUnchecked { - const { instruction, transferFeeInstruction } = withdrawWithheldTokensFromMintInstructionData.decode(data); - - return { - programId, - keys: { - mint, - destination, - authority, - signers, - }, - data: { - instruction, - transferFeeInstruction, - }, - }; -} - -// WithdrawWithheldTokensFromAccounts -export interface WithdrawWithheldTokensFromAccountsInstructionData { - instruction: TokenInstruction.TransferFeeExtension; - transferFeeInstruction: TransferFeeInstruction.WithdrawWithheldTokensFromAccounts; - numTokenAccounts: number; -} - -export const withdrawWithheldTokensFromAccountsInstructionData = - struct([ - u8('instruction'), - u8('transferFeeInstruction'), - u8('numTokenAccounts'), - ]); - -/** - * Construct a WithdrawWithheldTokensFromAccounts instruction - * - * @param mint The token mint - * @param destination The destination account - * @param authority The source account's owner/delegate - * @param signers The signer account(s) - * @param sources The source accounts to withdraw from - * @param programID SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createWithdrawWithheldTokensFromAccountsInstruction( - mint: PublicKey, - destination: PublicKey, - authority: PublicKey, - signers: Signer[], - sources: PublicKey[], - programId = TOKEN_2022_PROGRAM_ID -): TransactionInstruction { - if (!programSupportsExtensions(programId)) { - throw new TokenUnsupportedInstructionError(); - } - const data = Buffer.alloc(withdrawWithheldTokensFromAccountsInstructionData.span); - withdrawWithheldTokensFromAccountsInstructionData.encode( - { - instruction: TokenInstruction.TransferFeeExtension, - transferFeeInstruction: TransferFeeInstruction.WithdrawWithheldTokensFromAccounts, - numTokenAccounts: sources.length, - }, - data - ); - const keys: AccountMeta[] = []; - keys.push( - { pubkey: mint, isSigner: false, isWritable: true }, - { pubkey: destination, isSigner: false, isWritable: true }, - { pubkey: authority, isSigner: !signers.length, isWritable: false } - ); - for (const signer of signers) { - keys.push({ pubkey: signer.publicKey, isSigner: true, isWritable: false }); - } - for (const source of sources) { - keys.push({ pubkey: source, isSigner: false, isWritable: true }); - } - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid WithdrawWithheldTokensFromAccounts instruction */ -export interface DecodedWithdrawWithheldTokensFromAccountsInstruction { - programId: PublicKey; - keys: { - mint: AccountMeta; - destination: AccountMeta; - authority: AccountMeta; - signers: AccountMeta[] | null; - sources: AccountMeta[] | null; - }; - data: { - instruction: TokenInstruction.TransferFeeExtension; - transferFeeInstruction: TransferFeeInstruction.WithdrawWithheldTokensFromAccounts; - numTokenAccounts: number; - }; -} - -/** - * Decode a WithdrawWithheldTokensFromAccounts instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeWithdrawWithheldTokensFromAccountsInstruction( - instruction: TransactionInstruction, - programId: PublicKey -): DecodedWithdrawWithheldTokensFromAccountsInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== withdrawWithheldTokensFromAccountsInstructionData.span) - throw new TokenInvalidInstructionDataError(); - - const { - keys: { mint, destination, authority, signers, sources }, - data, - } = decodeWithdrawWithheldTokensFromAccountsInstructionUnchecked(instruction); - if ( - data.instruction !== TokenInstruction.TransferFeeExtension || - data.transferFeeInstruction !== TransferFeeInstruction.WithdrawWithheldTokensFromAccounts - ) - throw new TokenInvalidInstructionTypeError(); - if (!mint) throw new TokenInvalidInstructionKeysError(); - - return { - programId, - keys: { - mint, - destination, - authority, - signers: signers ? signers : null, - sources: sources ? sources : null, - }, - data, - }; -} - -/** A decoded, valid WithdrawWithheldTokensFromAccounts instruction */ -export interface DecodedWithdrawWithheldTokensFromAccountsInstructionUnchecked { - programId: PublicKey; - keys: { - mint: AccountMeta; - destination: AccountMeta; - authority: AccountMeta; - signers: AccountMeta[] | null; - sources: AccountMeta[] | null; - }; - data: { - instruction: TokenInstruction.TransferFeeExtension; - transferFeeInstruction: TransferFeeInstruction.WithdrawWithheldTokensFromAccounts; - numTokenAccounts: number; - }; -} - -/** - * Decode a WithdrawWithheldTokensFromAccount instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeWithdrawWithheldTokensFromAccountsInstructionUnchecked({ - programId, - keys, - data, -}: TransactionInstruction): DecodedWithdrawWithheldTokensFromAccountsInstructionUnchecked { - const { instruction, transferFeeInstruction, numTokenAccounts } = - withdrawWithheldTokensFromAccountsInstructionData.decode(data); - const [mint, destination, authority, signers, sources] = [ - keys[0], - keys[1], - keys[2], - keys.slice(3, 3 + numTokenAccounts), - keys.slice(-1 * numTokenAccounts), - ]; - return { - programId, - keys: { - mint, - destination, - authority, - signers, - sources, - }, - data: { - instruction, - transferFeeInstruction, - numTokenAccounts, - }, - }; -} - -// HarvestWithheldTokensToMint - -export interface HarvestWithheldTokensToMintInstructionData { - instruction: TokenInstruction.TransferFeeExtension; - transferFeeInstruction: TransferFeeInstruction.HarvestWithheldTokensToMint; -} - -export const harvestWithheldTokensToMintInstructionData = struct([ - u8('instruction'), - u8('transferFeeInstruction'), -]); - -/** - * Construct a HarvestWithheldTokensToMint instruction - * - * @param mint The token mint - * @param sources The source accounts to withdraw from - * @param programID SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createHarvestWithheldTokensToMintInstruction( - mint: PublicKey, - sources: PublicKey[], - programId = TOKEN_2022_PROGRAM_ID -): TransactionInstruction { - if (!programSupportsExtensions(programId)) { - throw new TokenUnsupportedInstructionError(); - } - const data = Buffer.alloc(harvestWithheldTokensToMintInstructionData.span); - harvestWithheldTokensToMintInstructionData.encode( - { - instruction: TokenInstruction.TransferFeeExtension, - transferFeeInstruction: TransferFeeInstruction.HarvestWithheldTokensToMint, - }, - data - ); - const keys: AccountMeta[] = []; - keys.push({ pubkey: mint, isSigner: false, isWritable: true }); - for (const source of sources) { - keys.push({ pubkey: source, isSigner: false, isWritable: true }); - } - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid HarvestWithheldTokensToMint instruction */ -export interface DecodedHarvestWithheldTokensToMintInstruction { - programId: PublicKey; - keys: { - mint: AccountMeta; - sources: AccountMeta[] | null; - }; - data: { - instruction: TokenInstruction.TransferFeeExtension; - transferFeeInstruction: TransferFeeInstruction.HarvestWithheldTokensToMint; - }; -} - -/** - * Decode a HarvestWithheldTokensToMint instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeHarvestWithheldTokensToMintInstruction( - instruction: TransactionInstruction, - programId: PublicKey -): DecodedHarvestWithheldTokensToMintInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== harvestWithheldTokensToMintInstructionData.span) - throw new TokenInvalidInstructionDataError(); - - const { - keys: { mint, sources }, - data, - } = decodeHarvestWithheldTokensToMintInstructionUnchecked(instruction); - if ( - data.instruction !== TokenInstruction.TransferFeeExtension || - data.transferFeeInstruction !== TransferFeeInstruction.HarvestWithheldTokensToMint - ) - throw new TokenInvalidInstructionTypeError(); - if (!mint) throw new TokenInvalidInstructionKeysError(); - - return { - programId, - keys: { - mint, - sources, - }, - data, - }; -} - -/** A decoded, valid HarvestWithheldTokensToMint instruction */ -export interface DecodedHarvestWithheldTokensToMintInstructionUnchecked { - programId: PublicKey; - keys: { - mint: AccountMeta; - sources: AccountMeta[] | null; - }; - data: { - instruction: TokenInstruction.TransferFeeExtension; - transferFeeInstruction: TransferFeeInstruction.HarvestWithheldTokensToMint; - }; -} - -/** - * Decode a HarvestWithheldTokensToMint instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeHarvestWithheldTokensToMintInstructionUnchecked({ - programId, - keys: [mint, ...sources], - data, -}: TransactionInstruction): DecodedHarvestWithheldTokensToMintInstructionUnchecked { - const { instruction, transferFeeInstruction } = harvestWithheldTokensToMintInstructionData.decode(data); - return { - programId, - keys: { - mint, - sources, - }, - data: { - instruction, - transferFeeInstruction, - }, - }; -} diff --git a/token/js/src/extensions/transferFee/state.ts b/token/js/src/extensions/transferFee/state.ts deleted file mode 100644 index 0481f31efcf..00000000000 --- a/token/js/src/extensions/transferFee/state.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { struct, u16, Layout } from '@solana/buffer-layout'; -import { publicKey, u64 } from '@solana/buffer-layout-utils'; -import { PublicKey } from '@solana/web3.js'; -import { Account } from '../../state'; -import { Mint } from '../../state/mint'; -import { ExtensionType, getExtensionData } from '../extensionType'; - -export const MAX_FEE_BASIS_POINTS = 10_000; -export const ONE_IN_BASIS_POINTS: BigInt = MAX_FEE_BASIS_POINTS as unknown as BigInt; - -/** TransferFeeConfig as stored by the program */ -export interface TransferFee { - /** First epoch where the transfer fee takes effect */ - epoch: BigInt; - /** Maximum fee assessed on transfers, expressed as an amount of tokens */ - maximumFee: BigInt; - /** - * Amount of transfer collected as fees, expressed as basis points of the - * transfer amount, ie. increments of 0.01% - */ - transferFeeBasisPoints: number; -} - -/** Transfer fee extension data for mints. */ -export interface TransferFeeConfig { - /** Optional authority to set the fee */ - transferFeeConfigAuthority: PublicKey; - /** Withdraw from mint instructions must be signed by this key */ - withdrawWithheldAuthority: PublicKey; - /** Withheld transfer fee tokens that have been moved to the mint for withdrawal */ - withheldAmount: BigInt; - /** Older transfer fee, used if the current epoch < newerTransferFee.epoch */ - olderTransferFee: TransferFee; - /** Newer transfer fee, used if the current epoch >= newerTransferFee.epoch */ - newerTransferFee: TransferFee; -} - -/** Buffer layout for de/serializing a transfer fee */ -export function transferFeeLayout(property?: string): Layout { - return struct([u64('epoch'), u64('maximumFee'), u16('transferFeeBasisPoints')], property); -} - -/** Buffer layout for de/serializing a transfer fee config extension */ -export const TransferFeeConfigLayout = struct([ - publicKey('transferFeeConfigAuthority'), - publicKey('withdrawWithheldAuthority'), - u64('withheldAmount'), - transferFeeLayout('olderTransferFee'), - transferFeeLayout('newerTransferFee'), -]); - -export const TRANSFER_FEE_CONFIG_SIZE = TransferFeeConfigLayout.span; - -/** Transfer fee amount data for accounts. */ -export interface TransferFeeAmount { - /** Withheld transfer fee tokens that can be claimed by the fee authority */ - withheldAmount: BigInt; -} -/** Buffer layout for de/serializing */ -export const TransferFeeAmountLayout = struct([u64('withheldAmount')]); -export const TRANSFER_FEE_AMOUNT_SIZE = TransferFeeAmountLayout.span; - -export function getTransferFeeConfig(mint: Mint): TransferFeeConfig | null { - const extensionData = getExtensionData(ExtensionType.TransferFeeConfig, mint.tlvData); - if (extensionData !== null) { - return TransferFeeConfigLayout.decode(extensionData); - } else { - return null; - } -} - -export function getTransferFeeAmount(account: Account): TransferFeeAmount | null { - const extensionData = getExtensionData(ExtensionType.TransferFeeAmount, account.tlvData); - if (extensionData !== null) { - return TransferFeeAmountLayout.decode(extensionData); - } else { - return null; - } -} diff --git a/token/js/src/index.ts b/token/js/src/index.ts deleted file mode 100644 index d9afdc91d0d..00000000000 --- a/token/js/src/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from './extensions/index'; -export * from './instructions/index'; -export * from './state/index'; -export * from './actions/index'; -export * from './constants'; -export * from './errors'; diff --git a/token/js/src/instructions/approve.ts b/token/js/src/instructions/approve.ts deleted file mode 100644 index 8b3ea0f9e46..00000000000 --- a/token/js/src/instructions/approve.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { u64 } from '@solana/buffer-layout-utils'; -import { AccountMeta, PublicKey, Signer, TransactionInstruction } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { - TokenInvalidInstructionDataError, - TokenInvalidInstructionKeysError, - TokenInvalidInstructionProgramError, - TokenInvalidInstructionTypeError, -} from '../errors'; -import { addSigners } from './internal'; -import { TokenInstruction } from './types'; - -/** TODO: docs */ -export interface ApproveInstructionData { - instruction: TokenInstruction.Approve; - amount: bigint; -} - -/** TODO: docs */ -export const approveInstructionData = struct([u8('instruction'), u64('amount')]); - -/** - * Construct an Approve instruction - * - * @param account Account to set the delegate for - * @param delegate Account authorized to transfer tokens from the account - * @param owner Owner of the account - * @param amount Maximum number of tokens the delegate may transfer - * @param multiSigners Signing accounts if `owner` is a multisig - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createApproveInstruction( - account: PublicKey, - delegate: PublicKey, - owner: PublicKey, - amount: number | bigint, - multiSigners: Signer[] = [], - programId = TOKEN_PROGRAM_ID -): TransactionInstruction { - const keys = addSigners( - [ - { pubkey: account, isSigner: false, isWritable: true }, - { pubkey: delegate, isSigner: false, isWritable: false }, - ], - owner, - multiSigners - ); - - const data = Buffer.alloc(approveInstructionData.span); - approveInstructionData.encode( - { - instruction: TokenInstruction.Approve, - amount: BigInt(amount), - }, - data - ); - - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid Approve instruction */ -export interface DecodedApproveInstruction { - programId: PublicKey; - keys: { - account: AccountMeta; - delegate: AccountMeta; - owner: AccountMeta; - multiSigners: AccountMeta[]; - }; - data: { - instruction: TokenInstruction.Approve; - amount: bigint; - }; -} - -/** - * Decode an Approve instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeApproveInstruction( - instruction: TransactionInstruction, - programId = TOKEN_PROGRAM_ID -): DecodedApproveInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== approveInstructionData.span) throw new TokenInvalidInstructionDataError(); - - const { - keys: { account, delegate, owner, multiSigners }, - data, - } = decodeApproveInstructionUnchecked(instruction); - if (data.instruction !== TokenInstruction.Approve) throw new TokenInvalidInstructionTypeError(); - if (!account || !delegate || !owner) throw new TokenInvalidInstructionKeysError(); - - // TODO: key checks? - - return { - programId, - keys: { - account, - delegate, - owner, - multiSigners, - }, - data, - }; -} - -/** A decoded, non-validated Approve instruction */ -export interface DecodedApproveInstructionUnchecked { - programId: PublicKey; - keys: { - account: AccountMeta | undefined; - delegate: AccountMeta | undefined; - owner: AccountMeta | undefined; - multiSigners: AccountMeta[]; - }; - data: { - instruction: number; - amount: bigint; - }; -} - -/** - * Decode an Approve instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeApproveInstructionUnchecked({ - programId, - keys: [account, delegate, owner, ...multiSigners], - data, -}: TransactionInstruction): DecodedApproveInstructionUnchecked { - return { - programId, - keys: { - account, - delegate, - owner, - multiSigners, - }, - data: approveInstructionData.decode(data), - }; -} diff --git a/token/js/src/instructions/approveChecked.ts b/token/js/src/instructions/approveChecked.ts deleted file mode 100644 index 37c4281fb5f..00000000000 --- a/token/js/src/instructions/approveChecked.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { u64 } from '@solana/buffer-layout-utils'; -import { AccountMeta, PublicKey, Signer, TransactionInstruction } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { - TokenInvalidInstructionDataError, - TokenInvalidInstructionKeysError, - TokenInvalidInstructionProgramError, - TokenInvalidInstructionTypeError, -} from '../errors'; -import { addSigners } from './internal'; -import { TokenInstruction } from './types'; - -/** TODO: docs */ -export interface ApproveCheckedInstructionData { - instruction: TokenInstruction.ApproveChecked; - amount: bigint; - decimals: number; -} - -/** TODO: docs */ -export const approveCheckedInstructionData = struct([ - u8('instruction'), - u64('amount'), - u8('decimals'), -]); - -/** - * Construct an ApproveChecked instruction - * - * @param account Account to set the delegate for - * @param mint Mint account - * @param delegate Account authorized to transfer of tokens from the account - * @param owner Owner of the account - * @param amount Maximum number of tokens the delegate may transfer - * @param decimals Number of decimals in approve amount - * @param multiSigners Signing accounts if `owner` is a multisig - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createApproveCheckedInstruction( - account: PublicKey, - mint: PublicKey, - delegate: PublicKey, - owner: PublicKey, - amount: number | bigint, - decimals: number, - multiSigners: Signer[] = [], - programId = TOKEN_PROGRAM_ID -): TransactionInstruction { - const keys = addSigners( - [ - { pubkey: account, isSigner: false, isWritable: true }, - { pubkey: mint, isSigner: false, isWritable: false }, - { pubkey: delegate, isSigner: false, isWritable: false }, - ], - owner, - multiSigners - ); - - const data = Buffer.alloc(approveCheckedInstructionData.span); - approveCheckedInstructionData.encode( - { - instruction: TokenInstruction.ApproveChecked, - amount: BigInt(amount), - decimals, - }, - data - ); - - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid ApproveChecked instruction */ -export interface DecodedApproveCheckedInstruction { - programId: PublicKey; - keys: { - account: AccountMeta; - mint: AccountMeta; - delegate: AccountMeta; - owner: AccountMeta; - multiSigners: AccountMeta[]; - }; - data: { - instruction: TokenInstruction.ApproveChecked; - amount: bigint; - decimals: number; - }; -} - -/** - * Decode an ApproveChecked instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeApproveCheckedInstruction( - instruction: TransactionInstruction, - programId = TOKEN_PROGRAM_ID -): DecodedApproveCheckedInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== approveCheckedInstructionData.span) throw new TokenInvalidInstructionDataError(); - - const { - keys: { account, mint, delegate, owner, multiSigners }, - data, - } = decodeApproveCheckedInstructionUnchecked(instruction); - if (data.instruction !== TokenInstruction.ApproveChecked) throw new TokenInvalidInstructionTypeError(); - if (!account || !mint || !delegate || !owner) throw new TokenInvalidInstructionKeysError(); - - // TODO: key checks? - - return { - programId, - keys: { - account, - mint, - delegate, - owner, - multiSigners, - }, - data, - }; -} - -/** A decoded, non-validated ApproveChecked instruction */ -export interface DecodedApproveCheckedInstructionUnchecked { - programId: PublicKey; - keys: { - account: AccountMeta | undefined; - mint: AccountMeta | undefined; - delegate: AccountMeta | undefined; - owner: AccountMeta | undefined; - multiSigners: AccountMeta[]; - }; - data: { - instruction: number; - amount: bigint; - decimals: number; - }; -} - -/** - * Decode an ApproveChecked instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeApproveCheckedInstructionUnchecked({ - programId, - keys: [account, mint, delegate, owner, ...multiSigners], - data, -}: TransactionInstruction): DecodedApproveCheckedInstructionUnchecked { - return { - programId, - keys: { - account, - mint, - delegate, - owner, - multiSigners, - }, - data: approveCheckedInstructionData.decode(data), - }; -} diff --git a/token/js/src/instructions/associatedTokenAccount.ts b/token/js/src/instructions/associatedTokenAccount.ts deleted file mode 100644 index e45f0d56891..00000000000 --- a/token/js/src/instructions/associatedTokenAccount.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { PublicKey, SystemProgram, SYSVAR_RENT_PUBKEY, TransactionInstruction } from '@solana/web3.js'; -import { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID } from '../constants'; - -/** - * Construct an AssociatedTokenAccount instruction - * - * @param payer Payer of the initialization fees - * @param associatedToken New associated token account - * @param owner Owner of the new account - * @param mint Token mint account - * @param programId SPL Token program account - * @param associatedTokenProgramId SPL Associated Token program account - * - * @return Instruction to add to a transaction - */ -export function createAssociatedTokenAccountInstruction( - payer: PublicKey, - associatedToken: PublicKey, - owner: PublicKey, - mint: PublicKey, - programId = TOKEN_PROGRAM_ID, - associatedTokenProgramId = ASSOCIATED_TOKEN_PROGRAM_ID -): TransactionInstruction { - const keys = [ - { pubkey: payer, isSigner: true, isWritable: true }, - { pubkey: associatedToken, isSigner: false, isWritable: true }, - { pubkey: owner, isSigner: false, isWritable: false }, - { pubkey: mint, isSigner: false, isWritable: false }, - { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }, - { pubkey: programId, isSigner: false, isWritable: false }, - { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false }, - ]; - - return new TransactionInstruction({ - keys, - programId: associatedTokenProgramId, - data: Buffer.alloc(0), - }); -} diff --git a/token/js/src/instructions/burn.ts b/token/js/src/instructions/burn.ts deleted file mode 100644 index 4d310292d89..00000000000 --- a/token/js/src/instructions/burn.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { u64 } from '@solana/buffer-layout-utils'; -import { AccountMeta, PublicKey, Signer, TransactionInstruction } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { - TokenInvalidInstructionDataError, - TokenInvalidInstructionKeysError, - TokenInvalidInstructionProgramError, - TokenInvalidInstructionTypeError, -} from '../errors'; -import { addSigners } from './internal'; -import { TokenInstruction } from './types'; - -/** TODO: docs */ -export interface BurnInstructionData { - instruction: TokenInstruction.Burn; - amount: bigint; -} - -/** TODO: docs */ -export const burnInstructionData = struct([u8('instruction'), u64('amount')]); - -/** - * Construct a Burn instruction - * - * @param account Account to burn tokens from - * @param mint Mint for the account - * @param owner Owner of the account - * @param amount Number of tokens to burn - * @param multiSigners Signing accounts if `owner` is a multisig - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createBurnInstruction( - account: PublicKey, - mint: PublicKey, - owner: PublicKey, - amount: number | bigint, - multiSigners: Signer[] = [], - programId = TOKEN_PROGRAM_ID -): TransactionInstruction { - const keys = addSigners( - [ - { pubkey: account, isSigner: false, isWritable: true }, - { pubkey: mint, isSigner: false, isWritable: true }, - ], - owner, - multiSigners - ); - - const data = Buffer.alloc(burnInstructionData.span); - burnInstructionData.encode( - { - instruction: TokenInstruction.Burn, - amount: BigInt(amount), - }, - data - ); - - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid Burn instruction */ -export interface DecodedBurnInstruction { - programId: PublicKey; - keys: { - account: AccountMeta; - mint: AccountMeta; - owner: AccountMeta; - multiSigners: AccountMeta[]; - }; - data: { - instruction: TokenInstruction.Burn; - amount: bigint; - }; -} - -/** - * Decode a Burn instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeBurnInstruction( - instruction: TransactionInstruction, - programId = TOKEN_PROGRAM_ID -): DecodedBurnInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== burnInstructionData.span) throw new TokenInvalidInstructionDataError(); - - const { - keys: { account, mint, owner, multiSigners }, - data, - } = decodeBurnInstructionUnchecked(instruction); - if (data.instruction !== TokenInstruction.Burn) throw new TokenInvalidInstructionTypeError(); - if (!account || !mint || !owner) throw new TokenInvalidInstructionKeysError(); - - // TODO: key checks? - - return { - programId, - keys: { - account, - mint, - owner, - multiSigners, - }, - data, - }; -} - -/** A decoded, non-validated Burn instruction */ -export interface DecodedBurnInstructionUnchecked { - programId: PublicKey; - keys: { - account: AccountMeta | undefined; - mint: AccountMeta | undefined; - owner: AccountMeta | undefined; - multiSigners: AccountMeta[]; - }; - data: { - instruction: number; - amount: bigint; - }; -} - -/** - * Decode a Burn instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeBurnInstructionUnchecked({ - programId, - keys: [account, mint, owner, ...multiSigners], - data, -}: TransactionInstruction): DecodedBurnInstructionUnchecked { - return { - programId, - keys: { - account, - mint, - owner, - multiSigners, - }, - data: burnInstructionData.decode(data), - }; -} diff --git a/token/js/src/instructions/burnChecked.ts b/token/js/src/instructions/burnChecked.ts deleted file mode 100644 index ae290182ec4..00000000000 --- a/token/js/src/instructions/burnChecked.ts +++ /dev/null @@ -1,162 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { u64 } from '@solana/buffer-layout-utils'; -import { AccountMeta, PublicKey, Signer, TransactionInstruction } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { - TokenInvalidInstructionDataError, - TokenInvalidInstructionKeysError, - TokenInvalidInstructionProgramError, - TokenInvalidInstructionTypeError, -} from '../errors'; -import { addSigners } from './internal'; -import { TokenInstruction } from './types'; - -/** TODO: docs */ -export interface BurnCheckedInstructionData { - instruction: TokenInstruction.BurnChecked; - amount: bigint; - decimals: number; -} - -/** TODO: docs */ -export const burnCheckedInstructionData = struct([ - u8('instruction'), - u64('amount'), - u8('decimals'), -]); - -/** - * Construct a BurnChecked instruction - * - * @param mint Mint for the account - * @param account Account to burn tokens from - * @param owner Owner of the account - * @param amount Number of tokens to burn - * @param decimals Number of decimals in burn amount - * @param multiSigners Signing accounts if `owner` is a multisig - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createBurnCheckedInstruction( - account: PublicKey, - mint: PublicKey, - owner: PublicKey, - amount: number | bigint, - decimals: number, - multiSigners: Signer[] = [], - programId = TOKEN_PROGRAM_ID -): TransactionInstruction { - const keys = addSigners( - [ - { pubkey: account, isSigner: false, isWritable: true }, - { pubkey: mint, isSigner: false, isWritable: true }, - ], - owner, - multiSigners - ); - - const data = Buffer.alloc(burnCheckedInstructionData.span); - burnCheckedInstructionData.encode( - { - instruction: TokenInstruction.BurnChecked, - amount: BigInt(amount), - decimals, - }, - data - ); - - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid BurnChecked instruction */ -export interface DecodedBurnCheckedInstruction { - programId: PublicKey; - keys: { - account: AccountMeta; - mint: AccountMeta; - owner: AccountMeta; - multiSigners: AccountMeta[]; - }; - data: { - instruction: TokenInstruction.BurnChecked; - amount: bigint; - decimals: number; - }; -} - -/** - * Decode a BurnChecked instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeBurnCheckedInstruction( - instruction: TransactionInstruction, - programId = TOKEN_PROGRAM_ID -): DecodedBurnCheckedInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== burnCheckedInstructionData.span) throw new TokenInvalidInstructionDataError(); - - const { - keys: { account, mint, owner, multiSigners }, - data, - } = decodeBurnCheckedInstructionUnchecked(instruction); - if (data.instruction !== TokenInstruction.BurnChecked) throw new TokenInvalidInstructionTypeError(); - if (!account || !mint || !owner) throw new TokenInvalidInstructionKeysError(); - - // TODO: key checks? - - return { - programId, - keys: { - account, - mint, - owner, - multiSigners, - }, - data, - }; -} - -/** A decoded, non-validated BurnChecked instruction */ -export interface DecodedBurnCheckedInstructionUnchecked { - programId: PublicKey; - keys: { - account: AccountMeta | undefined; - mint: AccountMeta | undefined; - owner: AccountMeta | undefined; - multiSigners: AccountMeta[]; - }; - data: { - instruction: number; - amount: bigint; - decimals: number; - }; -} - -/** - * Decode a BurnChecked instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeBurnCheckedInstructionUnchecked({ - programId, - keys: [account, mint, owner, ...multiSigners], - data, -}: TransactionInstruction): DecodedBurnCheckedInstructionUnchecked { - return { - programId, - keys: { - account, - mint, - owner, - multiSigners, - }, - data: burnCheckedInstructionData.decode(data), - }; -} diff --git a/token/js/src/instructions/closeAccount.ts b/token/js/src/instructions/closeAccount.ts deleted file mode 100644 index 71a7ddba1a5..00000000000 --- a/token/js/src/instructions/closeAccount.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { AccountMeta, PublicKey, Signer, TransactionInstruction } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { - TokenInvalidInstructionDataError, - TokenInvalidInstructionKeysError, - TokenInvalidInstructionProgramError, - TokenInvalidInstructionTypeError, -} from '../errors'; -import { addSigners } from './internal'; -import { TokenInstruction } from './types'; - -/** TODO: docs */ -export interface CloseAccountInstructionData { - instruction: TokenInstruction.CloseAccount; -} - -/** TODO: docs */ -export const closeAccountInstructionData = struct([u8('instruction')]); - -/** - * Construct a CloseAccount instruction - * - * @param account Account to close - * @param destination Account to receive the remaining balance of the closed account - * @param authority Account close authority - * @param multiSigners Signing accounts if `authority` is a multisig - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createCloseAccountInstruction( - account: PublicKey, - destination: PublicKey, - authority: PublicKey, - multiSigners: Signer[] = [], - programId = TOKEN_PROGRAM_ID -): TransactionInstruction { - const keys = addSigners( - [ - { pubkey: account, isSigner: false, isWritable: true }, - { pubkey: destination, isSigner: false, isWritable: true }, - ], - authority, - multiSigners - ); - - const data = Buffer.alloc(closeAccountInstructionData.span); - closeAccountInstructionData.encode({ instruction: TokenInstruction.CloseAccount }, data); - - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid CloseAccount instruction */ -export interface DecodedCloseAccountInstruction { - programId: PublicKey; - keys: { - account: AccountMeta; - destination: AccountMeta; - authority: AccountMeta; - multiSigners: AccountMeta[]; - }; - data: { - instruction: TokenInstruction.CloseAccount; - }; -} - -/** - * Decode a CloseAccount instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeCloseAccountInstruction( - instruction: TransactionInstruction, - programId = TOKEN_PROGRAM_ID -): DecodedCloseAccountInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== closeAccountInstructionData.span) throw new TokenInvalidInstructionDataError(); - - const { - keys: { account, destination, authority, multiSigners }, - data, - } = decodeCloseAccountInstructionUnchecked(instruction); - if (data.instruction !== TokenInstruction.CloseAccount) throw new TokenInvalidInstructionTypeError(); - if (!account || !destination || !authority) throw new TokenInvalidInstructionKeysError(); - - // TODO: key checks? - - return { - programId, - keys: { - account, - destination, - authority, - multiSigners, - }, - data, - }; -} - -/** A decoded, non-validated CloseAccount instruction */ -export interface DecodedCloseAccountInstructionUnchecked { - programId: PublicKey; - keys: { - account: AccountMeta | undefined; - destination: AccountMeta | undefined; - authority: AccountMeta | undefined; - multiSigners: AccountMeta[]; - }; - data: { - instruction: number; - }; -} - -/** - * Decode a CloseAccount instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeCloseAccountInstructionUnchecked({ - programId, - keys: [account, destination, authority, ...multiSigners], - data, -}: TransactionInstruction): DecodedCloseAccountInstructionUnchecked { - return { - programId, - keys: { - account, - destination, - authority, - multiSigners, - }, - data: closeAccountInstructionData.decode(data), - }; -} diff --git a/token/js/src/instructions/createNativeMint.ts b/token/js/src/instructions/createNativeMint.ts deleted file mode 100644 index 52ce6d1237d..00000000000 --- a/token/js/src/instructions/createNativeMint.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { PublicKey, TransactionInstruction, SystemProgram } from '@solana/web3.js'; -import { TOKEN_2022_PROGRAM_ID, NATIVE_MINT_2022 } from '../constants'; -import { TokenInstruction } from './types'; -import { TokenUnsupportedInstructionError } from '../errors'; -import { programSupportsExtensions } from '../constants'; - -/** TODO: docs */ -export interface CreateNativeMintInstructionData { - instruction: TokenInstruction.CreateNativeMint; -} - -/** TODO: docs */ -export const createNativeMintInstructionData = struct([u8('instruction')]); - -/** - * Construct a CreateNativeMint instruction - * - * @param account New token account - * @param mint Mint account - * @param owner Owner of the new account - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createCreateNativeMintInstruction( - payer: PublicKey, - nativeMintId = NATIVE_MINT_2022, - programId = TOKEN_2022_PROGRAM_ID -): TransactionInstruction { - if (!programSupportsExtensions(programId)) { - throw new TokenUnsupportedInstructionError(); - } - const keys = [ - { pubkey: payer, isSigner: true, isWritable: true }, - { pubkey: nativeMintId, isSigner: false, isWritable: true }, - { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }, - ]; - - const data = Buffer.alloc(createNativeMintInstructionData.span); - createNativeMintInstructionData.encode({ instruction: TokenInstruction.CreateNativeMint }, data); - - return new TransactionInstruction({ keys, programId, data }); -} diff --git a/token/js/src/instructions/decode.ts b/token/js/src/instructions/decode.ts deleted file mode 100644 index 4c235024906..00000000000 --- a/token/js/src/instructions/decode.ts +++ /dev/null @@ -1,208 +0,0 @@ -import { u8 } from '@solana/buffer-layout'; -import { TransactionInstruction } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { TokenInvalidInstructionDataError, TokenInvalidInstructionTypeError } from '../errors'; -import { decodeApproveInstruction, DecodedApproveInstruction } from './approve'; -import { decodeApproveCheckedInstruction, DecodedApproveCheckedInstruction } from './approveChecked'; -import { decodeBurnInstruction, DecodedBurnInstruction } from './burn'; -import { decodeBurnCheckedInstruction, DecodedBurnCheckedInstruction } from './burnChecked'; -import { decodeCloseAccountInstruction, DecodedCloseAccountInstruction } from './closeAccount'; -import { DecodedFreezeAccountInstruction, decodeFreezeAccountInstruction } from './freezeAccount'; -import { DecodedInitializeAccountInstruction, decodeInitializeAccountInstruction } from './initializeAccount'; -import { DecodedInitializeAccount2Instruction, decodeInitializeAccount2Instruction } from './initializeAccount2'; -import { DecodedInitializeAccount3Instruction, decodeInitializeAccount3Instruction } from './initializeAccount3'; -import { DecodedInitializeMintInstruction, decodeInitializeMintInstruction } from './initializeMint'; -import { DecodedInitializeMultisigInstruction, decodeInitializeMultisigInstruction } from './initializeMultisig'; -import { DecodedMintToInstruction, decodeMintToInstruction } from './mintTo'; -import { DecodedMintToCheckedInstruction, decodeMintToCheckedInstruction } from './mintToChecked'; -import { DecodedRevokeInstruction, decodeRevokeInstruction } from './revoke'; -import { DecodedSetAuthorityInstruction, decodeSetAuthorityInstruction } from './setAuthority'; -import { DecodedSyncNativeInstruction, decodeSyncNativeInstruction } from './syncNative'; -import { DecodedThawAccountInstruction, decodeThawAccountInstruction } from './thawAccount'; -import { DecodedTransferInstruction, decodeTransferInstruction } from './transfer'; -import { DecodedTransferCheckedInstruction, decodeTransferCheckedInstruction } from './transferChecked'; -import { TokenInstruction } from './types'; - -/** TODO: docs */ -export type DecodedInstruction = - | DecodedInitializeMintInstruction - | DecodedInitializeAccountInstruction - | DecodedInitializeMultisigInstruction - | DecodedTransferInstruction - | DecodedApproveInstruction - | DecodedRevokeInstruction - | DecodedSetAuthorityInstruction - | DecodedMintToInstruction - | DecodedBurnInstruction - | DecodedCloseAccountInstruction - | DecodedFreezeAccountInstruction - | DecodedThawAccountInstruction - | DecodedTransferCheckedInstruction - | DecodedApproveCheckedInstruction - | DecodedMintToCheckedInstruction - | DecodedBurnCheckedInstruction - | DecodedInitializeAccount2Instruction - | DecodedSyncNativeInstruction - | DecodedInitializeAccount3Instruction - // | DecodedInitializeMultisig2Instruction - // | DecodedInitializeMint2Instruction - // TODO: implement ^ and remove `never` - | never; - -/** TODO: docs */ -export function decodeInstruction( - instruction: TransactionInstruction, - programId = TOKEN_PROGRAM_ID -): DecodedInstruction { - if (!instruction.data.length) throw new TokenInvalidInstructionDataError(); - - const type = u8().decode(instruction.data); - if (type === TokenInstruction.InitializeMint) return decodeInitializeMintInstruction(instruction, programId); - if (type === TokenInstruction.InitializeAccount) return decodeInitializeAccountInstruction(instruction, programId); - if (type === TokenInstruction.InitializeMultisig) - return decodeInitializeMultisigInstruction(instruction, programId); - if (type === TokenInstruction.Transfer) return decodeTransferInstruction(instruction, programId); - if (type === TokenInstruction.Approve) return decodeApproveInstruction(instruction, programId); - if (type === TokenInstruction.Revoke) return decodeRevokeInstruction(instruction, programId); - if (type === TokenInstruction.SetAuthority) return decodeSetAuthorityInstruction(instruction, programId); - if (type === TokenInstruction.MintTo) return decodeMintToInstruction(instruction, programId); - if (type === TokenInstruction.Burn) return decodeBurnInstruction(instruction, programId); - if (type === TokenInstruction.CloseAccount) return decodeCloseAccountInstruction(instruction, programId); - if (type === TokenInstruction.FreezeAccount) return decodeFreezeAccountInstruction(instruction, programId); - if (type === TokenInstruction.ThawAccount) return decodeThawAccountInstruction(instruction, programId); - if (type === TokenInstruction.TransferChecked) return decodeTransferCheckedInstruction(instruction, programId); - if (type === TokenInstruction.ApproveChecked) return decodeApproveCheckedInstruction(instruction, programId); - if (type === TokenInstruction.MintToChecked) return decodeMintToCheckedInstruction(instruction, programId); - if (type === TokenInstruction.BurnChecked) return decodeBurnCheckedInstruction(instruction, programId); - if (type === TokenInstruction.InitializeAccount2) - return decodeInitializeAccount2Instruction(instruction, programId); - if (type === TokenInstruction.SyncNative) return decodeSyncNativeInstruction(instruction, programId); - // TODO: implement - if (type === TokenInstruction.InitializeAccount3) - return decodeInitializeAccount3Instruction(instruction, programId); - // TODO: implement - if (type === TokenInstruction.InitializeMultisig2) throw new TokenInvalidInstructionTypeError(); - // TODO: implement - if (type === TokenInstruction.InitializeMint2) throw new TokenInvalidInstructionTypeError(); - - throw new TokenInvalidInstructionTypeError(); -} - -/** TODO: docs */ -export function isInitializeMintInstruction(decoded: DecodedInstruction): decoded is DecodedInitializeMintInstruction { - return decoded.data.instruction === TokenInstruction.InitializeMint; -} - -/** TODO: docs */ -export function isInitializeAccountInstruction( - decoded: DecodedInstruction -): decoded is DecodedInitializeAccountInstruction { - return decoded.data.instruction === TokenInstruction.InitializeAccount; -} - -/** TODO: docs */ -export function isInitializeMultisigInstruction( - decoded: DecodedInstruction -): decoded is DecodedInitializeMultisigInstruction { - return decoded.data.instruction === TokenInstruction.InitializeMultisig; -} - -/** TODO: docs */ -export function isTransferInstruction(decoded: DecodedInstruction): decoded is DecodedTransferInstruction { - return decoded.data.instruction === TokenInstruction.Transfer; -} - -/** TODO: docs */ -export function isApproveInstruction(decoded: DecodedInstruction): decoded is DecodedApproveInstruction { - return decoded.data.instruction === TokenInstruction.Approve; -} - -/** TODO: docs */ -export function isRevokeInstruction(decoded: DecodedInstruction): decoded is DecodedRevokeInstruction { - return decoded.data.instruction === TokenInstruction.Revoke; -} - -/** TODO: docs */ -export function isSetAuthorityInstruction(decoded: DecodedInstruction): decoded is DecodedSetAuthorityInstruction { - return decoded.data.instruction === TokenInstruction.SetAuthority; -} - -/** TODO: docs */ -export function isMintToInstruction(decoded: DecodedInstruction): decoded is DecodedMintToInstruction { - return decoded.data.instruction === TokenInstruction.MintTo; -} - -/** TODO: docs */ -export function isBurnInstruction(decoded: DecodedInstruction): decoded is DecodedBurnInstruction { - return decoded.data.instruction === TokenInstruction.Burn; -} - -/** TODO: docs */ -export function isCloseAccountInstruction(decoded: DecodedInstruction): decoded is DecodedCloseAccountInstruction { - return decoded.data.instruction === TokenInstruction.CloseAccount; -} - -/** TODO: docs */ -export function isFreezeAccountInstruction(decoded: DecodedInstruction): decoded is DecodedFreezeAccountInstruction { - return decoded.data.instruction === TokenInstruction.FreezeAccount; -} - -/** TODO: docs */ -export function isThawAccountInstruction(decoded: DecodedInstruction): decoded is DecodedThawAccountInstruction { - return decoded.data.instruction === TokenInstruction.ThawAccount; -} - -/** TODO: docs */ -export function isTransferCheckedInstruction( - decoded: DecodedInstruction -): decoded is DecodedTransferCheckedInstruction { - return decoded.data.instruction === TokenInstruction.TransferChecked; -} - -/** TODO: docs */ -export function isApproveCheckedInstruction(decoded: DecodedInstruction): decoded is DecodedApproveCheckedInstruction { - return decoded.data.instruction === TokenInstruction.ApproveChecked; -} - -/** TODO: docs */ -export function isMintToCheckedInstruction(decoded: DecodedInstruction): decoded is DecodedMintToCheckedInstruction { - return decoded.data.instruction === TokenInstruction.MintToChecked; -} - -/** TODO: docs */ -export function isBurnCheckedInstruction(decoded: DecodedInstruction): decoded is DecodedBurnCheckedInstruction { - return decoded.data.instruction === TokenInstruction.BurnChecked; -} - -/** TODO: docs */ -export function isInitializeAccount2Instruction( - decoded: DecodedInstruction -): decoded is DecodedInitializeAccount2Instruction { - return decoded.data.instruction === TokenInstruction.InitializeAccount2; -} - -/** TODO: docs */ -export function isSyncNativeInstruction(decoded: DecodedInstruction): decoded is DecodedSyncNativeInstruction { - return decoded.data.instruction === TokenInstruction.SyncNative; -} - -/** TODO: docs */ -export function isInitializeAccount3Instruction( - decoded: DecodedInstruction -): decoded is DecodedInitializeAccount3Instruction { - return decoded.data.instruction === TokenInstruction.InitializeAccount3; -} - -/** TODO: docs, implement */ -// export function isInitializeMultisig2Instruction( -// decoded: DecodedInstruction -// ): decoded is DecodedInitializeMultisig2Instruction { -// return decoded.data.instruction === TokenInstruction.InitializeMultisig2; -// } - -/** TODO: docs, implement */ -// export function isInitializeMint2Instruction( -// decoded: DecodedInstruction -// ): decoded is DecodedInitializeMint2Instruction { -// return decoded.data.instruction === TokenInstruction.InitializeMint2; -// } diff --git a/token/js/src/instructions/freezeAccount.ts b/token/js/src/instructions/freezeAccount.ts deleted file mode 100644 index 670b7be662e..00000000000 --- a/token/js/src/instructions/freezeAccount.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { AccountMeta, PublicKey, Signer, TransactionInstruction } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { - TokenInvalidInstructionDataError, - TokenInvalidInstructionKeysError, - TokenInvalidInstructionProgramError, - TokenInvalidInstructionTypeError, -} from '../errors'; -import { addSigners } from './internal'; -import { TokenInstruction } from './types'; - -/** TODO: docs */ -export interface FreezeAccountInstructionData { - instruction: TokenInstruction.FreezeAccount; -} - -/** TODO: docs */ -export const freezeAccountInstructionData = struct([u8('instruction')]); - -/** - * Construct a FreezeAccount instruction - * - * @param account Account to freeze - * @param mint Mint account - * @param authority Mint freeze authority - * @param multiSigners Signing accounts if `authority` is a multisig - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createFreezeAccountInstruction( - account: PublicKey, - mint: PublicKey, - authority: PublicKey, - multiSigners: Signer[] = [], - programId = TOKEN_PROGRAM_ID -): TransactionInstruction { - const keys = addSigners( - [ - { pubkey: account, isSigner: false, isWritable: true }, - { pubkey: mint, isSigner: false, isWritable: false }, - ], - authority, - multiSigners - ); - - const data = Buffer.alloc(freezeAccountInstructionData.span); - freezeAccountInstructionData.encode({ instruction: TokenInstruction.FreezeAccount }, data); - - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid FreezeAccount instruction */ -export interface DecodedFreezeAccountInstruction { - programId: PublicKey; - keys: { - account: AccountMeta; - mint: AccountMeta; - authority: AccountMeta; - multiSigners: AccountMeta[]; - }; - data: { - instruction: TokenInstruction.FreezeAccount; - }; -} - -/** - * Decode a FreezeAccount instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeFreezeAccountInstruction( - instruction: TransactionInstruction, - programId = TOKEN_PROGRAM_ID -): DecodedFreezeAccountInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== freezeAccountInstructionData.span) throw new TokenInvalidInstructionDataError(); - - const { - keys: { account, mint, authority, multiSigners }, - data, - } = decodeFreezeAccountInstructionUnchecked(instruction); - if (data.instruction !== TokenInstruction.FreezeAccount) throw new TokenInvalidInstructionTypeError(); - if (!account || !mint || !authority) throw new TokenInvalidInstructionKeysError(); - - // TODO: key checks? - - return { - programId, - keys: { - account, - mint, - authority, - multiSigners, - }, - data, - }; -} - -/** A decoded, non-validated FreezeAccount instruction */ -export interface DecodedFreezeAccountInstructionUnchecked { - programId: PublicKey; - keys: { - account: AccountMeta | undefined; - mint: AccountMeta | undefined; - authority: AccountMeta | undefined; - multiSigners: AccountMeta[]; - }; - data: { - instruction: number; - }; -} - -/** - * Decode a FreezeAccount instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeFreezeAccountInstructionUnchecked({ - programId, - keys: [account, mint, authority, ...multiSigners], - data, -}: TransactionInstruction): DecodedFreezeAccountInstructionUnchecked { - return { - programId, - keys: { - account, - mint, - authority, - multiSigners, - }, - data: freezeAccountInstructionData.decode(data), - }; -} diff --git a/token/js/src/instructions/index.ts b/token/js/src/instructions/index.ts deleted file mode 100644 index 4b34a247dc0..00000000000 --- a/token/js/src/instructions/index.ts +++ /dev/null @@ -1,31 +0,0 @@ -export * from './types'; - -export * from './initializeMint'; // 0 -export * from './initializeAccount'; // 1 -export * from './initializeMultisig'; // 2 -export * from './transfer'; // 3 -export * from './approve'; // 4 -export * from './revoke'; // 5 -export * from './setAuthority'; // 6 -export * from './mintTo'; // 7 -export * from './burn'; // 8 -export * from './closeAccount'; // 9 -export * from './freezeAccount'; // 10 -export * from './thawAccount'; // 11 -export * from './transferChecked'; // 12 -export * from './approveChecked'; // 13 -export * from './mintToChecked'; // 14 -export * from './burnChecked'; // 15 -export * from './initializeAccount2'; // 16 -export * from './syncNative'; // 17 -export * from './initializeAccount3'; // 18 -export * from './initializeMultisig2'; // 19 -export * from './initializeMint2'; // 20 -export * from './initializeImmutableOwner'; // 22 -export * from './initializeMintCloseAuthority'; // 23 -export * from './createNativeMint'; // 29 -export * from './initializeNonTransferableMint'; // 32 - -export * from './decode'; - -export * from './associatedTokenAccount'; diff --git a/token/js/src/instructions/initializeAccount.ts b/token/js/src/instructions/initializeAccount.ts deleted file mode 100644 index 1aa2c88ba05..00000000000 --- a/token/js/src/instructions/initializeAccount.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { AccountMeta, PublicKey, SYSVAR_RENT_PUBKEY, TransactionInstruction } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { - TokenInvalidInstructionDataError, - TokenInvalidInstructionKeysError, - TokenInvalidInstructionProgramError, - TokenInvalidInstructionTypeError, -} from '../errors'; -import { TokenInstruction } from './types'; - -/** TODO: docs */ -export interface InitializeAccountInstructionData { - instruction: TokenInstruction.InitializeAccount; -} - -/** TODO: docs */ -export const initializeAccountInstructionData = struct([u8('instruction')]); - -/** - * Construct an InitializeAccount instruction - * - * @param account New token account - * @param mint Mint account - * @param owner Owner of the new account - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createInitializeAccountInstruction( - account: PublicKey, - mint: PublicKey, - owner: PublicKey, - programId = TOKEN_PROGRAM_ID -): TransactionInstruction { - const keys = [ - { pubkey: account, isSigner: false, isWritable: true }, - { pubkey: mint, isSigner: false, isWritable: false }, - { pubkey: owner, isSigner: false, isWritable: false }, - { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false }, - ]; - - const data = Buffer.alloc(initializeAccountInstructionData.span); - initializeAccountInstructionData.encode({ instruction: TokenInstruction.InitializeAccount }, data); - - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid InitializeAccount instruction */ -export interface DecodedInitializeAccountInstruction { - programId: PublicKey; - keys: { - account: AccountMeta; - mint: AccountMeta; - owner: AccountMeta; - rent: AccountMeta; - }; - data: { - instruction: TokenInstruction.InitializeAccount; - }; -} - -/** - * Decode an InitializeAccount instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeInitializeAccountInstruction( - instruction: TransactionInstruction, - programId = TOKEN_PROGRAM_ID -): DecodedInitializeAccountInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== initializeAccountInstructionData.span) throw new TokenInvalidInstructionDataError(); - - const { - keys: { account, mint, owner, rent }, - data, - } = decodeInitializeAccountInstructionUnchecked(instruction); - if (data.instruction !== TokenInstruction.InitializeAccount) throw new TokenInvalidInstructionTypeError(); - if (!account || !mint || !owner || !rent) throw new TokenInvalidInstructionKeysError(); - - // TODO: key checks? - - return { - programId, - keys: { - account, - mint, - owner, - rent, - }, - data, - }; -} - -/** A decoded, non-validated InitializeAccount instruction */ -export interface DecodedInitializeAccountInstructionUnchecked { - programId: PublicKey; - keys: { - account: AccountMeta | undefined; - mint: AccountMeta | undefined; - owner: AccountMeta | undefined; - rent: AccountMeta | undefined; - }; - data: { - instruction: number; - }; -} - -/** - * Decode an InitializeAccount instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeInitializeAccountInstructionUnchecked({ - programId, - keys: [account, mint, owner, rent], - data, -}: TransactionInstruction): DecodedInitializeAccountInstructionUnchecked { - return { - programId, - keys: { - account, - mint, - owner, - rent, - }, - data: initializeAccountInstructionData.decode(data), - }; -} diff --git a/token/js/src/instructions/initializeAccount2.ts b/token/js/src/instructions/initializeAccount2.ts deleted file mode 100644 index a988a49cedb..00000000000 --- a/token/js/src/instructions/initializeAccount2.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { TokenInstruction } from './types'; -import { struct, u8 } from '@solana/buffer-layout'; -import { publicKey } from '@solana/buffer-layout-utils'; -import { AccountMeta, PublicKey, SYSVAR_RENT_PUBKEY, TransactionInstruction } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { - TokenInvalidInstructionDataError, - TokenInvalidInstructionKeysError, - TokenInvalidInstructionProgramError, - TokenInvalidInstructionTypeError, -} from '../errors'; - -export interface InitializeAccount2InstructionData { - instruction: TokenInstruction.InitializeAccount2; - owner: PublicKey; -} - -export const initializeAccount2InstructionData = struct([ - u8('instruction'), - publicKey('owner'), -]); - -/** - * Construct an InitializeAccount2 instruction - * - * @param account New token account - * @param mint Mint account - * @param owner New account's owner/multisignature - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createInitializeAccount2Instruction( - account: PublicKey, - mint: PublicKey, - owner: PublicKey, - programId = TOKEN_PROGRAM_ID -): TransactionInstruction { - const keys = [ - { pubkey: account, isSigner: false, isWritable: true }, - { pubkey: mint, isSigner: false, isWritable: false }, - { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false }, - ]; - const data = Buffer.alloc(initializeAccount2InstructionData.span); - initializeAccount2InstructionData.encode({ instruction: TokenInstruction.InitializeAccount2, owner }, data); - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid InitializeAccount2 instruction */ -export interface DecodedInitializeAccount2Instruction { - programId: PublicKey; - keys: { - account: AccountMeta; - mint: AccountMeta; - rent: AccountMeta; - }; - data: { - instruction: TokenInstruction.InitializeAccount2; - owner: PublicKey; - }; -} - -/** - * Decode an InitializeAccount2 instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeInitializeAccount2Instruction( - instruction: TransactionInstruction, - programId = TOKEN_PROGRAM_ID -): DecodedInitializeAccount2Instruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== initializeAccount2InstructionData.span) - throw new TokenInvalidInstructionDataError(); - - const { - keys: { account, mint, rent }, - data, - } = decodeInitializeAccount2InstructionUnchecked(instruction); - if (data.instruction !== TokenInstruction.InitializeAccount2) throw new TokenInvalidInstructionTypeError(); - if (!account || !mint || !rent) throw new TokenInvalidInstructionKeysError(); - - // TODO: key checks? - - return { - programId, - keys: { - account, - mint, - rent, - }, - data, - }; -} - -/** A decoded, non-validated InitializeAccount2 instruction */ -export interface DecodedInitializeAccount2InstructionUnchecked { - programId: PublicKey; - keys: { - account: AccountMeta | undefined; - mint: AccountMeta | undefined; - rent: AccountMeta | undefined; - }; - data: { - instruction: number; - owner: PublicKey; - }; -} - -/** - * Decode an InitializeAccount2 instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeInitializeAccount2InstructionUnchecked({ - programId, - keys: [account, mint, rent], - data, -}: TransactionInstruction): DecodedInitializeAccount2InstructionUnchecked { - return { - programId, - keys: { - account, - mint, - rent, - }, - data: initializeAccount2InstructionData.decode(data), - }; -} diff --git a/token/js/src/instructions/initializeAccount3.ts b/token/js/src/instructions/initializeAccount3.ts deleted file mode 100644 index 569fed5a82c..00000000000 --- a/token/js/src/instructions/initializeAccount3.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { TokenInstruction } from './types'; -import { struct, u8 } from '@solana/buffer-layout'; -import { publicKey } from '@solana/buffer-layout-utils'; -import { AccountMeta, PublicKey, TransactionInstruction } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { - TokenInvalidInstructionDataError, - TokenInvalidInstructionKeysError, - TokenInvalidInstructionProgramError, - TokenInvalidInstructionTypeError, -} from '../errors'; - -export interface InitializeAccount3InstructionData { - instruction: TokenInstruction.InitializeAccount3; - owner: PublicKey; -} - -export const initializeAccount3InstructionData = struct([ - u8('instruction'), - publicKey('owner'), -]); - -/** - * Construct an InitializeAccount3 instruction - * - * @param account New token account - * @param mint Mint account - * @param owner New account's owner/multisignature - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createInitializeAccount3Instruction( - account: PublicKey, - mint: PublicKey, - owner: PublicKey, - programId = TOKEN_PROGRAM_ID -): TransactionInstruction { - const keys = [ - { pubkey: account, isSigner: false, isWritable: true }, - { pubkey: mint, isSigner: false, isWritable: false }, - ]; - const data = Buffer.alloc(initializeAccount3InstructionData.span); - initializeAccount3InstructionData.encode({ instruction: TokenInstruction.InitializeAccount3, owner }, data); - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid InitializeAccount3 instruction */ -export interface DecodedInitializeAccount3Instruction { - programId: PublicKey; - keys: { - account: AccountMeta; - mint: AccountMeta; - }; - data: { - instruction: TokenInstruction.InitializeAccount3; - owner: PublicKey; - }; -} - -/** - * Decode an InitializeAccount3 instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeInitializeAccount3Instruction( - instruction: TransactionInstruction, - programId = TOKEN_PROGRAM_ID -): DecodedInitializeAccount3Instruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== initializeAccount3InstructionData.span) - throw new TokenInvalidInstructionDataError(); - - const { - keys: { account, mint }, - data, - } = decodeInitializeAccount3InstructionUnchecked(instruction); - if (data.instruction !== TokenInstruction.InitializeAccount3) throw new TokenInvalidInstructionTypeError(); - if (!account || !mint) throw new TokenInvalidInstructionKeysError(); - - // TODO: key checks? - - return { - programId, - keys: { - account, - mint, - }, - data, - }; -} - -/** A decoded, non-validated InitializeAccount3 instruction */ -export interface DecodedInitializeAccount3InstructionUnchecked { - programId: PublicKey; - keys: { - account: AccountMeta | undefined; - mint: AccountMeta | undefined; - }; - data: { - instruction: number; - owner: PublicKey; - }; -} - -/** - * Decode an InitializeAccount3 instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeInitializeAccount3InstructionUnchecked({ - programId, - keys: [account, mint], - data, -}: TransactionInstruction): DecodedInitializeAccount3InstructionUnchecked { - return { - programId, - keys: { - account, - mint, - }, - data: initializeAccount3InstructionData.decode(data), - }; -} diff --git a/token/js/src/instructions/initializeImmutableOwner.ts b/token/js/src/instructions/initializeImmutableOwner.ts deleted file mode 100644 index 72ad8c19ead..00000000000 --- a/token/js/src/instructions/initializeImmutableOwner.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { AccountMeta, PublicKey, TransactionInstruction } from '@solana/web3.js'; -import { - TokenInvalidInstructionDataError, - TokenInvalidInstructionKeysError, - TokenInvalidInstructionProgramError, - TokenInvalidInstructionTypeError, -} from '../errors'; -import { TokenInstruction } from './types'; - -/** Deserialized instruction for the initiation of an immutable owner account */ -export interface InitializeImmutableOwnerInstructionData { - instruction: TokenInstruction.InitializeImmutableOwner; -} - -/** The struct that represents the instruction data as it is read by the program */ -export const initializeImmutableOwnerInstructionData = struct([ - u8('instruction'), -]); - -/** - * Construct an InitializeImmutableOwner instruction - * - * @param account Immutable Owner Account - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createInitializeImmutableOwnerInstruction( - account: PublicKey, - programId: PublicKey -): TransactionInstruction { - const keys = [{ pubkey: account, isSigner: false, isWritable: true }]; - - const data = Buffer.alloc(initializeImmutableOwnerInstructionData.span); - initializeImmutableOwnerInstructionData.encode( - { - instruction: TokenInstruction.InitializeImmutableOwner, - }, - data - ); - - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid InitializeImmutableOwner instruction */ -export interface DecodedInitializeImmutableOwnerInstruction { - programId: PublicKey; - keys: { - account: AccountMeta; - }; - data: { - instruction: TokenInstruction.InitializeImmutableOwner; - }; -} - -/** - * Decode an InitializeImmutableOwner instruction and validate it - * - * @param instruction InitializeImmutableOwner instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeInitializeImmutableOwnerInstruction( - instruction: TransactionInstruction, - programId: PublicKey -): DecodedInitializeImmutableOwnerInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== initializeImmutableOwnerInstructionData.span) - throw new TokenInvalidInstructionDataError(); - - const { - keys: { account }, - data, - } = decodeInitializeImmutableOwnerInstructionUnchecked(instruction); - if (data.instruction !== TokenInstruction.InitializeImmutableOwner) throw new TokenInvalidInstructionTypeError(); - if (!account) throw new TokenInvalidInstructionKeysError(); - - return { - programId, - keys: { - account, - }, - data, - }; -} - -/** A decoded, non-validated InitializeImmutableOwner instruction */ -export interface DecodedInitializeImmutableOwnerInstructionUnchecked { - programId: PublicKey; - keys: { - account: AccountMeta | undefined; - }; - data: { - instruction: number; - }; -} - -/** - * Decode an InitializeImmutableOwner instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeInitializeImmutableOwnerInstructionUnchecked({ - programId, - keys: [account], - data, -}: TransactionInstruction): DecodedInitializeImmutableOwnerInstructionUnchecked { - const { instruction } = initializeImmutableOwnerInstructionData.decode(data); - - return { - programId, - keys: { - account: account, - }, - data: { - instruction, - }, - }; -} diff --git a/token/js/src/instructions/initializeMint.ts b/token/js/src/instructions/initializeMint.ts deleted file mode 100644 index 3feaf951e74..00000000000 --- a/token/js/src/instructions/initializeMint.ts +++ /dev/null @@ -1,161 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { publicKey } from '@solana/buffer-layout-utils'; -import { AccountMeta, PublicKey, SYSVAR_RENT_PUBKEY, TransactionInstruction } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { - TokenInvalidInstructionDataError, - TokenInvalidInstructionKeysError, - TokenInvalidInstructionProgramError, - TokenInvalidInstructionTypeError, -} from '../errors'; -import { TokenInstruction } from './types'; - -/** TODO: docs */ -export interface InitializeMintInstructionData { - instruction: TokenInstruction.InitializeMint; - decimals: number; - mintAuthority: PublicKey; - freezeAuthorityOption: 1 | 0; - freezeAuthority: PublicKey; -} - -/** TODO: docs */ -export const initializeMintInstructionData = struct([ - u8('instruction'), - u8('decimals'), - publicKey('mintAuthority'), - u8('freezeAuthorityOption'), - publicKey('freezeAuthority'), -]); - -/** - * Construct an InitializeMint instruction - * - * @param mint Token mint account - * @param decimals Number of decimals in token account amounts - * @param mintAuthority Minting authority - * @param freezeAuthority Optional authority that can freeze token accounts - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createInitializeMintInstruction( - mint: PublicKey, - decimals: number, - mintAuthority: PublicKey, - freezeAuthority: PublicKey | null, - programId = TOKEN_PROGRAM_ID -): TransactionInstruction { - const keys = [ - { pubkey: mint, isSigner: false, isWritable: true }, - { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false }, - ]; - - const data = Buffer.alloc(initializeMintInstructionData.span); - initializeMintInstructionData.encode( - { - instruction: TokenInstruction.InitializeMint, - decimals, - mintAuthority, - freezeAuthorityOption: freezeAuthority ? 1 : 0, - freezeAuthority: freezeAuthority || new PublicKey(0), - }, - data - ); - - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid InitializeMint instruction */ -export interface DecodedInitializeMintInstruction { - programId: PublicKey; - keys: { - mint: AccountMeta; - rent: AccountMeta; - }; - data: { - instruction: TokenInstruction.InitializeMint; - decimals: number; - mintAuthority: PublicKey; - freezeAuthority: PublicKey | null; - }; -} - -/** - * Decode an InitializeMint instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeInitializeMintInstruction( - instruction: TransactionInstruction, - programId = TOKEN_PROGRAM_ID -): DecodedInitializeMintInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== initializeMintInstructionData.span) throw new TokenInvalidInstructionDataError(); - - const { - keys: { mint, rent }, - data, - } = decodeInitializeMintInstructionUnchecked(instruction); - if (data.instruction !== TokenInstruction.InitializeMint) throw new TokenInvalidInstructionTypeError(); - if (!mint || !rent) throw new TokenInvalidInstructionKeysError(); - - // TODO: key checks? - - return { - programId, - keys: { - mint, - rent, - }, - data, - }; -} - -/** A decoded, non-validated InitializeMint instruction */ -export interface DecodedInitializeMintInstructionUnchecked { - programId: PublicKey; - keys: { - mint: AccountMeta | undefined; - rent: AccountMeta | undefined; - }; - data: { - instruction: number; - decimals: number; - mintAuthority: PublicKey; - freezeAuthority: PublicKey | null; - }; -} - -/** - * Decode an InitializeMint instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeInitializeMintInstructionUnchecked({ - programId, - keys: [mint, rent], - data, -}: TransactionInstruction): DecodedInitializeMintInstructionUnchecked { - const { instruction, decimals, mintAuthority, freezeAuthorityOption, freezeAuthority } = - initializeMintInstructionData.decode(data); - - return { - programId, - keys: { - mint, - rent, - }, - data: { - instruction, - decimals, - mintAuthority, - freezeAuthority: freezeAuthorityOption ? freezeAuthority : null, - }, - }; -} diff --git a/token/js/src/instructions/initializeMint2.ts b/token/js/src/instructions/initializeMint2.ts deleted file mode 100644 index 434426c176f..00000000000 --- a/token/js/src/instructions/initializeMint2.ts +++ /dev/null @@ -1 +0,0 @@ -export {}; // TODO: implement diff --git a/token/js/src/instructions/initializeMintCloseAuthority.ts b/token/js/src/instructions/initializeMintCloseAuthority.ts deleted file mode 100644 index 0dfe758a7fe..00000000000 --- a/token/js/src/instructions/initializeMintCloseAuthority.ts +++ /dev/null @@ -1,142 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { publicKey } from '@solana/buffer-layout-utils'; -import { AccountMeta, PublicKey, TransactionInstruction } from '@solana/web3.js'; -import { - TokenUnsupportedInstructionError, - TokenInvalidInstructionDataError, - TokenInvalidInstructionKeysError, - TokenInvalidInstructionProgramError, - TokenInvalidInstructionTypeError, -} from '../errors'; -import { TokenInstruction } from './types'; -import { programSupportsExtensions } from '../constants'; - -/** TODO: docs */ -export interface InitializeMintCloseAuthorityInstructionData { - instruction: TokenInstruction.InitializeMintCloseAuthority; - closeAuthorityOption: 1 | 0; - closeAuthority: PublicKey; -} - -/** TODO: docs */ -export const initializeMintCloseAuthorityInstructionData = struct([ - u8('instruction'), - u8('closeAuthorityOption'), - publicKey('closeAuthority'), -]); - -/** - * Construct an InitializeMintCloseAuthority instruction - * - * @param mint Token mint account - * @param closeAuthority Optional authority that can close the mint - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createInitializeMintCloseAuthorityInstruction( - mint: PublicKey, - closeAuthority: PublicKey | null, - programId: PublicKey -): TransactionInstruction { - if (!programSupportsExtensions(programId)) { - throw new TokenUnsupportedInstructionError(); - } - const keys = [{ pubkey: mint, isSigner: false, isWritable: true }]; - - const data = Buffer.alloc(initializeMintCloseAuthorityInstructionData.span); - initializeMintCloseAuthorityInstructionData.encode( - { - instruction: TokenInstruction.InitializeMintCloseAuthority, - closeAuthorityOption: closeAuthority ? 1 : 0, - closeAuthority: closeAuthority || new PublicKey(0), - }, - data - ); - - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid InitializeMintCloseAuthority instruction */ -export interface DecodedInitializeMintCloseAuthorityInstruction { - programId: PublicKey; - keys: { - mint: AccountMeta; - }; - data: { - instruction: TokenInstruction.InitializeMintCloseAuthority; - closeAuthority: PublicKey | null; - }; -} - -/** - * Decode an InitializeMintCloseAuthority instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeInitializeMintCloseAuthorityInstruction( - instruction: TransactionInstruction, - programId: PublicKey -): DecodedInitializeMintCloseAuthorityInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== initializeMintCloseAuthorityInstructionData.span) - throw new TokenInvalidInstructionDataError(); - - const { - keys: { mint }, - data, - } = decodeInitializeMintCloseAuthorityInstructionUnchecked(instruction); - if (data.instruction !== TokenInstruction.InitializeMintCloseAuthority) - throw new TokenInvalidInstructionTypeError(); - if (!mint) throw new TokenInvalidInstructionKeysError(); - - return { - programId, - keys: { - mint, - }, - data, - }; -} - -/** A decoded, non-validated InitializeMintCloseAuthority instruction */ -export interface DecodedInitializeMintCloseAuthorityInstructionUnchecked { - programId: PublicKey; - keys: { - mint: AccountMeta | undefined; - }; - data: { - instruction: number; - closeAuthority: PublicKey | null; - }; -} - -/** - * Decode an InitializeMintCloseAuthority instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeInitializeMintCloseAuthorityInstructionUnchecked({ - programId, - keys: [mint], - data, -}: TransactionInstruction): DecodedInitializeMintCloseAuthorityInstructionUnchecked { - const { instruction, closeAuthorityOption, closeAuthority } = - initializeMintCloseAuthorityInstructionData.decode(data); - - return { - programId, - keys: { - mint, - }, - data: { - instruction, - closeAuthority: closeAuthorityOption ? closeAuthority : null, - }, - }; -} diff --git a/token/js/src/instructions/initializeMultisig.ts b/token/js/src/instructions/initializeMultisig.ts deleted file mode 100644 index 53c561a4b3a..00000000000 --- a/token/js/src/instructions/initializeMultisig.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { AccountMeta, PublicKey, SYSVAR_RENT_PUBKEY, TransactionInstruction } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { - TokenInvalidInstructionDataError, - TokenInvalidInstructionKeysError, - TokenInvalidInstructionProgramError, - TokenInvalidInstructionTypeError, -} from '../errors'; -import { TokenInstruction } from './types'; - -/** TODO: docs */ -export interface InitializeMultisigInstructionData { - instruction: TokenInstruction.InitializeMultisig; - m: number; -} - -/** TODO: docs */ -export const initializeMultisigInstructionData = struct([ - u8('instruction'), - u8('m'), -]); - -/** - * Construct an InitializeMultisig instruction - * - * @param account Multisig account - * @param signers Full set of signers - * @param m Number of required signatures - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createInitializeMultisigInstruction( - account: PublicKey, - signers: PublicKey[], - m: number, - programId = TOKEN_PROGRAM_ID -): TransactionInstruction { - const keys = [ - { pubkey: account, isSigner: false, isWritable: true }, - { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false }, - ]; - for (const signer of signers) { - keys.push({ pubkey: signer, isSigner: false, isWritable: false }); - } - - const data = Buffer.alloc(initializeMultisigInstructionData.span); - initializeMultisigInstructionData.encode( - { - instruction: TokenInstruction.InitializeMultisig, - m, - }, - data - ); - - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid InitializeMultisig instruction */ -export interface DecodedInitializeMultisigInstruction { - programId: PublicKey; - keys: { - account: AccountMeta; - rent: AccountMeta; - signers: AccountMeta[]; - }; - data: { - instruction: TokenInstruction.InitializeMultisig; - m: number; - }; -} - -/** - * Decode an InitializeMultisig instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeInitializeMultisigInstruction( - instruction: TransactionInstruction, - programId = TOKEN_PROGRAM_ID -): DecodedInitializeMultisigInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== initializeMultisigInstructionData.span) - throw new TokenInvalidInstructionDataError(); - - const { - keys: { account, rent, signers }, - data, - } = decodeInitializeMultisigInstructionUnchecked(instruction); - if (data.instruction !== TokenInstruction.InitializeMultisig) throw new TokenInvalidInstructionTypeError(); - if (!account || !rent || !signers.length) throw new TokenInvalidInstructionKeysError(); - - // TODO: key checks? - - return { - programId, - keys: { - account, - rent, - signers, - }, - data, - }; -} - -/** A decoded, non-validated InitializeMultisig instruction */ -export interface DecodedInitializeMultisigInstructionUnchecked { - programId: PublicKey; - keys: { - account: AccountMeta | undefined; - rent: AccountMeta | undefined; - signers: AccountMeta[]; - }; - data: { - instruction: number; - m: number; - }; -} - -/** - * Decode an InitializeMultisig instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeInitializeMultisigInstructionUnchecked({ - programId, - keys: [account, rent, ...signers], - data, -}: TransactionInstruction): DecodedInitializeMultisigInstructionUnchecked { - return { - programId, - keys: { - account, - rent, - signers, - }, - data: initializeMultisigInstructionData.decode(data), - }; -} diff --git a/token/js/src/instructions/initializeMultisig2.ts b/token/js/src/instructions/initializeMultisig2.ts deleted file mode 100644 index 434426c176f..00000000000 --- a/token/js/src/instructions/initializeMultisig2.ts +++ /dev/null @@ -1 +0,0 @@ -export {}; // TODO: implement diff --git a/token/js/src/instructions/initializeNonTransferableMint.ts b/token/js/src/instructions/initializeNonTransferableMint.ts deleted file mode 100644 index faf513c9dc5..00000000000 --- a/token/js/src/instructions/initializeNonTransferableMint.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { PublicKey, TransactionInstruction } from '@solana/web3.js'; -import { TokenInstruction } from './types'; -import { TokenUnsupportedInstructionError } from '../errors'; -import { programSupportsExtensions } from '../constants'; - -/** Deserialized instruction for the initiation of an immutable owner account */ -export interface InitializeNonTransferableMintInstructionData { - instruction: TokenInstruction.InitializeNonTransferableMint; -} - -/** The struct that represents the instruction data as it is read by the program */ -export const initializeNonTransferableMintInstructionData = struct([ - u8('instruction'), -]); - -/** - * Construct an InitializeNonTransferableMint instruction - * - * @param mint Mint Account to make non-transferable - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createInitializeNonTransferableMintInstruction( - mint: PublicKey, - programId: PublicKey -): TransactionInstruction { - if (!programSupportsExtensions(programId)) { - throw new TokenUnsupportedInstructionError(); - } - const keys = [{ pubkey: mint, isSigner: false, isWritable: true }]; - - const data = Buffer.alloc(initializeNonTransferableMintInstructionData.span); - initializeNonTransferableMintInstructionData.encode( - { - instruction: TokenInstruction.InitializeNonTransferableMint, - }, - data - ); - - return new TransactionInstruction({ keys, programId, data }); -} diff --git a/token/js/src/instructions/internal.ts b/token/js/src/instructions/internal.ts deleted file mode 100644 index 5aedcdb0ee4..00000000000 --- a/token/js/src/instructions/internal.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { AccountMeta, PublicKey, Signer } from '@solana/web3.js'; - -/** @internal */ -export function addSigners(keys: AccountMeta[], ownerOrAuthority: PublicKey, multiSigners: Signer[]): AccountMeta[] { - if (multiSigners.length) { - keys.push({ pubkey: ownerOrAuthority, isSigner: false, isWritable: false }); - for (const signer of multiSigners) { - keys.push({ pubkey: signer.publicKey, isSigner: true, isWritable: false }); - } - } else { - keys.push({ pubkey: ownerOrAuthority, isSigner: true, isWritable: false }); - } - return keys; -} diff --git a/token/js/src/instructions/mintTo.ts b/token/js/src/instructions/mintTo.ts deleted file mode 100644 index 3a60f96c388..00000000000 --- a/token/js/src/instructions/mintTo.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { u64 } from '@solana/buffer-layout-utils'; -import { AccountMeta, PublicKey, Signer, TransactionInstruction } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { - TokenInvalidInstructionDataError, - TokenInvalidInstructionKeysError, - TokenInvalidInstructionProgramError, - TokenInvalidInstructionTypeError, -} from '../errors'; -import { addSigners } from './internal'; -import { TokenInstruction } from './types'; - -/** TODO: docs */ -export interface MintToInstructionData { - instruction: TokenInstruction.MintTo; - amount: bigint; -} - -/** TODO: docs */ -export const mintToInstructionData = struct([u8('instruction'), u64('amount')]); - -/** - * Construct a MintTo instruction - * - * @param mint Public key of the mint - * @param destination Address of the token account to mint to - * @param authority The mint authority - * @param amount Amount to mint - * @param multiSigners Signing accounts if `authority` is a multisig - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createMintToInstruction( - mint: PublicKey, - destination: PublicKey, - authority: PublicKey, - amount: number | bigint, - multiSigners: Signer[] = [], - programId = TOKEN_PROGRAM_ID -): TransactionInstruction { - const keys = addSigners( - [ - { pubkey: mint, isSigner: false, isWritable: true }, - { pubkey: destination, isSigner: false, isWritable: true }, - ], - authority, - multiSigners - ); - - const data = Buffer.alloc(mintToInstructionData.span); - mintToInstructionData.encode( - { - instruction: TokenInstruction.MintTo, - amount: BigInt(amount), - }, - data - ); - - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid MintTo instruction */ -export interface DecodedMintToInstruction { - programId: PublicKey; - keys: { - mint: AccountMeta; - destination: AccountMeta; - authority: AccountMeta; - multiSigners: AccountMeta[]; - }; - data: { - instruction: TokenInstruction.MintTo; - amount: bigint; - }; -} - -/** - * Decode a MintTo instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeMintToInstruction( - instruction: TransactionInstruction, - programId = TOKEN_PROGRAM_ID -): DecodedMintToInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== mintToInstructionData.span) throw new TokenInvalidInstructionDataError(); - - const { - keys: { mint, destination, authority, multiSigners }, - data, - } = decodeMintToInstructionUnchecked(instruction); - if (data.instruction !== TokenInstruction.MintTo) throw new TokenInvalidInstructionTypeError(); - if (!mint || !destination || !authority) throw new TokenInvalidInstructionKeysError(); - - // TODO: key checks? - - return { - programId, - keys: { - mint, - destination, - authority, - multiSigners, - }, - data, - }; -} - -/** A decoded, non-validated MintTo instruction */ -export interface DecodedMintToInstructionUnchecked { - programId: PublicKey; - keys: { - mint: AccountMeta | undefined; - destination: AccountMeta | undefined; - authority: AccountMeta | undefined; - multiSigners: AccountMeta[]; - }; - data: { - instruction: number; - amount: bigint; - }; -} - -/** - * Decode a MintTo instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeMintToInstructionUnchecked({ - programId, - keys: [mint, destination, authority, ...multiSigners], - data, -}: TransactionInstruction): DecodedMintToInstructionUnchecked { - return { - programId, - keys: { - mint, - destination, - authority, - multiSigners, - }, - data: mintToInstructionData.decode(data), - }; -} diff --git a/token/js/src/instructions/mintToChecked.ts b/token/js/src/instructions/mintToChecked.ts deleted file mode 100644 index 91445d06700..00000000000 --- a/token/js/src/instructions/mintToChecked.ts +++ /dev/null @@ -1,162 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { u64 } from '@solana/buffer-layout-utils'; -import { AccountMeta, PublicKey, Signer, TransactionInstruction } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { - TokenInvalidInstructionDataError, - TokenInvalidInstructionKeysError, - TokenInvalidInstructionProgramError, - TokenInvalidInstructionTypeError, -} from '../errors'; -import { addSigners } from './internal'; -import { TokenInstruction } from './types'; - -/** TODO: docs */ -export interface MintToCheckedInstructionData { - instruction: TokenInstruction.MintToChecked; - amount: bigint; - decimals: number; -} - -/** TODO: docs */ -export const mintToCheckedInstructionData = struct([ - u8('instruction'), - u64('amount'), - u8('decimals'), -]); - -/** - * Construct a MintToChecked instruction - * - * @param mint Public key of the mint - * @param destination Address of the token account to mint to - * @param authority The mint authority - * @param amount Amount to mint - * @param decimals Number of decimals in amount to mint - * @param multiSigners Signing accounts if `authority` is a multisig - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createMintToCheckedInstruction( - mint: PublicKey, - destination: PublicKey, - authority: PublicKey, - amount: number | bigint, - decimals: number, - multiSigners: Signer[] = [], - programId = TOKEN_PROGRAM_ID -): TransactionInstruction { - const keys = addSigners( - [ - { pubkey: mint, isSigner: false, isWritable: true }, - { pubkey: destination, isSigner: false, isWritable: true }, - ], - authority, - multiSigners - ); - - const data = Buffer.alloc(mintToCheckedInstructionData.span); - mintToCheckedInstructionData.encode( - { - instruction: TokenInstruction.MintToChecked, - amount: BigInt(amount), - decimals, - }, - data - ); - - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid MintToChecked instruction */ -export interface DecodedMintToCheckedInstruction { - programId: PublicKey; - keys: { - mint: AccountMeta; - destination: AccountMeta; - authority: AccountMeta; - multiSigners: AccountMeta[]; - }; - data: { - instruction: TokenInstruction.MintToChecked; - amount: bigint; - decimals: number; - }; -} - -/** - * Decode a MintToChecked instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeMintToCheckedInstruction( - instruction: TransactionInstruction, - programId = TOKEN_PROGRAM_ID -): DecodedMintToCheckedInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== mintToCheckedInstructionData.span) throw new TokenInvalidInstructionDataError(); - - const { - keys: { mint, destination, authority, multiSigners }, - data, - } = decodeMintToCheckedInstructionUnchecked(instruction); - if (data.instruction !== TokenInstruction.MintToChecked) throw new TokenInvalidInstructionTypeError(); - if (!mint || !destination || !authority) throw new TokenInvalidInstructionKeysError(); - - // TODO: key checks? - - return { - programId, - keys: { - mint, - destination, - authority, - multiSigners, - }, - data, - }; -} - -/** A decoded, non-validated MintToChecked instruction */ -export interface DecodedMintToCheckedInstructionUnchecked { - programId: PublicKey; - keys: { - mint: AccountMeta | undefined; - destination: AccountMeta | undefined; - authority: AccountMeta | undefined; - multiSigners: AccountMeta[]; - }; - data: { - instruction: number; - amount: bigint; - decimals: number; - }; -} - -/** - * Decode a MintToChecked instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeMintToCheckedInstructionUnchecked({ - programId, - keys: [mint, destination, authority, ...multiSigners], - data, -}: TransactionInstruction): DecodedMintToCheckedInstructionUnchecked { - return { - programId, - keys: { - mint, - destination, - authority, - multiSigners, - }, - data: mintToCheckedInstructionData.decode(data), - }; -} diff --git a/token/js/src/instructions/revoke.ts b/token/js/src/instructions/revoke.ts deleted file mode 100644 index 6a3808801de..00000000000 --- a/token/js/src/instructions/revoke.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { AccountMeta, PublicKey, Signer, TransactionInstruction } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { - TokenInvalidInstructionDataError, - TokenInvalidInstructionKeysError, - TokenInvalidInstructionProgramError, - TokenInvalidInstructionTypeError, -} from '../errors'; -import { addSigners } from './internal'; -import { TokenInstruction } from './types'; - -/** TODO: docs */ -export interface RevokeInstructionData { - instruction: TokenInstruction.Revoke; -} - -/** TODO: docs */ -export const revokeInstructionData = struct([u8('instruction')]); - -/** - * Construct a Revoke instruction - * - * @param account Address of the token account - * @param owner Owner of the account - * @param multiSigners Signing accounts if `owner` is a multisig - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createRevokeInstruction( - account: PublicKey, - owner: PublicKey, - multiSigners: Signer[] = [], - programId = TOKEN_PROGRAM_ID -): TransactionInstruction { - const keys = addSigners([{ pubkey: account, isSigner: false, isWritable: true }], owner, multiSigners); - - const data = Buffer.alloc(revokeInstructionData.span); - revokeInstructionData.encode({ instruction: TokenInstruction.Revoke }, data); - - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid Revoke instruction */ -export interface DecodedRevokeInstruction { - programId: PublicKey; - keys: { - account: AccountMeta; - owner: AccountMeta; - multiSigners: AccountMeta[]; - }; - data: { - instruction: TokenInstruction.Revoke; - }; -} - -/** - * Decode a Revoke instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeRevokeInstruction( - instruction: TransactionInstruction, - programId = TOKEN_PROGRAM_ID -): DecodedRevokeInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== revokeInstructionData.span) throw new TokenInvalidInstructionDataError(); - - const { - keys: { account, owner, multiSigners }, - data, - } = decodeRevokeInstructionUnchecked(instruction); - if (data.instruction !== TokenInstruction.Revoke) throw new TokenInvalidInstructionTypeError(); - if (!account || !owner) throw new TokenInvalidInstructionKeysError(); - - // TODO: key checks? - - return { - programId, - keys: { - account, - owner, - multiSigners, - }, - data, - }; -} - -/** A decoded, non-validated Revoke instruction */ -export interface DecodedRevokeInstructionUnchecked { - programId: PublicKey; - keys: { - account: AccountMeta | undefined; - owner: AccountMeta | undefined; - multiSigners: AccountMeta[]; - }; - data: { - instruction: number; - }; -} - -/** - * Decode a Revoke instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeRevokeInstructionUnchecked({ - programId, - keys: [account, owner, ...multiSigners], - data, -}: TransactionInstruction): DecodedRevokeInstructionUnchecked { - return { - programId, - keys: { - account, - owner, - multiSigners, - }, - data: revokeInstructionData.decode(data), - }; -} diff --git a/token/js/src/instructions/setAuthority.ts b/token/js/src/instructions/setAuthority.ts deleted file mode 100644 index 5f83fdb9c32..00000000000 --- a/token/js/src/instructions/setAuthority.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { publicKey } from '@solana/buffer-layout-utils'; -import { AccountMeta, PublicKey, Signer, TransactionInstruction } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { - TokenInvalidInstructionDataError, - TokenInvalidInstructionKeysError, - TokenInvalidInstructionProgramError, - TokenInvalidInstructionTypeError, -} from '../errors'; -import { addSigners } from './internal'; -import { TokenInstruction } from './types'; - -/** Authority types defined by the program */ -export enum AuthorityType { - MintTokens = 0, - FreezeAccount = 1, - AccountOwner = 2, - CloseAccount = 3, -} - -/** TODO: docs */ -export interface SetAuthorityInstructionData { - instruction: TokenInstruction.SetAuthority; - authorityType: AuthorityType; - newAuthorityOption: 1 | 0; - newAuthority: PublicKey; -} - -/** TODO: docs */ -export const setAuthorityInstructionData = struct([ - u8('instruction'), - u8('authorityType'), - u8('newAuthorityOption'), - publicKey('newAuthority'), -]); - -/** - * Construct a SetAuthority instruction - * - * @param account Address of the token account - * @param currentAuthority Current authority of the specified type - * @param authorityType Type of authority to set - * @param newAuthority New authority of the account - * @param multiSigners Signing accounts if `currentAuthority` is a multisig - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createSetAuthorityInstruction( - account: PublicKey, - currentAuthority: PublicKey, - authorityType: AuthorityType, - newAuthority: PublicKey | null, - multiSigners: Signer[] = [], - programId = TOKEN_PROGRAM_ID -): TransactionInstruction { - const keys = addSigners([{ pubkey: account, isSigner: false, isWritable: true }], currentAuthority, multiSigners); - - const data = Buffer.alloc(setAuthorityInstructionData.span); - setAuthorityInstructionData.encode( - { - instruction: TokenInstruction.SetAuthority, - authorityType, - newAuthorityOption: newAuthority ? 1 : 0, - newAuthority: newAuthority || new PublicKey(0), - }, - data - ); - - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid SetAuthority instruction */ -export interface DecodedSetAuthorityInstruction { - programId: PublicKey; - keys: { - account: AccountMeta; - currentAuthority: AccountMeta; - multiSigners: AccountMeta[]; - }; - data: { - instruction: TokenInstruction.SetAuthority; - authorityType: AuthorityType; - newAuthority: PublicKey | null; - }; -} - -/** - * Decode a SetAuthority instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeSetAuthorityInstruction( - instruction: TransactionInstruction, - programId = TOKEN_PROGRAM_ID -): DecodedSetAuthorityInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== setAuthorityInstructionData.span) throw new TokenInvalidInstructionDataError(); - - const { - keys: { account, currentAuthority, multiSigners }, - data, - } = decodeSetAuthorityInstructionUnchecked(instruction); - if (data.instruction !== TokenInstruction.SetAuthority) throw new TokenInvalidInstructionTypeError(); - if (!account || !currentAuthority) throw new TokenInvalidInstructionKeysError(); - - // TODO: key checks? - - return { - programId, - keys: { - account, - currentAuthority, - multiSigners, - }, - data, - }; -} - -/** A decoded, non-validated SetAuthority instruction */ -export interface DecodedSetAuthorityInstructionUnchecked { - programId: PublicKey; - keys: { - account: AccountMeta | undefined; - currentAuthority: AccountMeta | undefined; - multiSigners: AccountMeta[]; - }; - data: { - instruction: number; - authorityType: AuthorityType; - newAuthority: PublicKey | null; - }; -} - -/** - * Decode a SetAuthority instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeSetAuthorityInstructionUnchecked({ - programId, - keys: [account, currentAuthority, ...multiSigners], - data, -}: TransactionInstruction): DecodedSetAuthorityInstructionUnchecked { - const { instruction, authorityType, newAuthorityOption, newAuthority } = setAuthorityInstructionData.decode(data); - - return { - programId, - keys: { - account, - currentAuthority, - multiSigners, - }, - data: { - instruction, - authorityType, - newAuthority: newAuthorityOption ? newAuthority : null, - }, - }; -} diff --git a/token/js/src/instructions/syncNative.ts b/token/js/src/instructions/syncNative.ts deleted file mode 100644 index 085a83bae50..00000000000 --- a/token/js/src/instructions/syncNative.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { AccountMeta, PublicKey, TransactionInstruction } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { - TokenInvalidInstructionDataError, - TokenInvalidInstructionKeysError, - TokenInvalidInstructionProgramError, - TokenInvalidInstructionTypeError, -} from '../errors'; -import { TokenInstruction } from './types'; - -/** TODO: docs */ -export interface SyncNativeInstructionData { - instruction: TokenInstruction.SyncNative; -} - -/** TODO: docs */ -export const syncNativeInstructionData = struct([u8('instruction')]); - -/** - * Construct a SyncNative instruction - * - * @param account Native account to sync lamports from - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createSyncNativeInstruction(account: PublicKey, programId = TOKEN_PROGRAM_ID): TransactionInstruction { - const keys = [{ pubkey: account, isSigner: false, isWritable: true }]; - - const data = Buffer.alloc(syncNativeInstructionData.span); - syncNativeInstructionData.encode({ instruction: TokenInstruction.SyncNative }, data); - - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid SyncNative instruction */ -export interface DecodedSyncNativeInstruction { - programId: PublicKey; - keys: { - account: AccountMeta; - }; - data: { - instruction: TokenInstruction.SyncNative; - }; -} - -/** - * Decode a SyncNative instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeSyncNativeInstruction( - instruction: TransactionInstruction, - programId = TOKEN_PROGRAM_ID -): DecodedSyncNativeInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== syncNativeInstructionData.span) throw new TokenInvalidInstructionDataError(); - - const { - keys: { account }, - data, - } = decodeSyncNativeInstructionUnchecked(instruction); - if (data.instruction !== TokenInstruction.SyncNative) throw new TokenInvalidInstructionTypeError(); - if (!account) throw new TokenInvalidInstructionKeysError(); - - // TODO: key checks? - - return { - programId, - keys: { - account, - }, - data, - }; -} - -/** A decoded, non-validated SyncNative instruction */ -export interface DecodedSyncNativeInstructionUnchecked { - programId: PublicKey; - keys: { - account: AccountMeta | undefined; - }; - data: { - instruction: number; - }; -} - -/** - * Decode a SyncNative instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeSyncNativeInstructionUnchecked({ - programId, - keys: [account], - data, -}: TransactionInstruction): DecodedSyncNativeInstructionUnchecked { - return { - programId, - keys: { - account, - }, - data: syncNativeInstructionData.decode(data), - }; -} diff --git a/token/js/src/instructions/thawAccount.ts b/token/js/src/instructions/thawAccount.ts deleted file mode 100644 index 81428052d3b..00000000000 --- a/token/js/src/instructions/thawAccount.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { AccountMeta, PublicKey, Signer, TransactionInstruction } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { - TokenInvalidInstructionDataError, - TokenInvalidInstructionKeysError, - TokenInvalidInstructionProgramError, - TokenInvalidInstructionTypeError, -} from '../errors'; -import { addSigners } from './internal'; -import { TokenInstruction } from './types'; - -/** TODO: docs */ -export interface ThawAccountInstructionData { - instruction: TokenInstruction.ThawAccount; -} - -/** TODO: docs */ -export const thawAccountInstructionData = struct([u8('instruction')]); - -/** - * Construct a ThawAccount instruction - * - * @param account Account to thaw - * @param mint Mint account - * @param authority Mint freeze authority - * @param multiSigners Signing accounts if `authority` is a multisig - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createThawAccountInstruction( - account: PublicKey, - mint: PublicKey, - authority: PublicKey, - multiSigners: Signer[] = [], - programId = TOKEN_PROGRAM_ID -): TransactionInstruction { - const keys = addSigners( - [ - { pubkey: account, isSigner: false, isWritable: true }, - { pubkey: mint, isSigner: false, isWritable: false }, - ], - authority, - multiSigners - ); - - const data = Buffer.alloc(thawAccountInstructionData.span); - thawAccountInstructionData.encode({ instruction: TokenInstruction.ThawAccount }, data); - - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid ThawAccount instruction */ -export interface DecodedThawAccountInstruction { - programId: PublicKey; - keys: { - account: AccountMeta; - mint: AccountMeta; - authority: AccountMeta; - multiSigners: AccountMeta[]; - }; - data: { - instruction: TokenInstruction.ThawAccount; - }; -} - -/** - * Decode a ThawAccount instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeThawAccountInstruction( - instruction: TransactionInstruction, - programId = TOKEN_PROGRAM_ID -): DecodedThawAccountInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== thawAccountInstructionData.span) throw new TokenInvalidInstructionDataError(); - - const { - keys: { account, mint, authority, multiSigners }, - data, - } = decodeThawAccountInstructionUnchecked(instruction); - if (data.instruction !== TokenInstruction.ThawAccount) throw new TokenInvalidInstructionTypeError(); - if (!account || !mint || !authority) throw new TokenInvalidInstructionKeysError(); - - // TODO: key checks? - - return { - programId, - keys: { - account, - mint, - authority, - multiSigners, - }, - data, - }; -} - -/** A decoded, non-validated ThawAccount instruction */ -export interface DecodedThawAccountInstructionUnchecked { - programId: PublicKey; - keys: { - account: AccountMeta | undefined; - mint: AccountMeta | undefined; - authority: AccountMeta | undefined; - multiSigners: AccountMeta[]; - }; - data: { - instruction: number; - }; -} - -/** - * Decode a ThawAccount instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeThawAccountInstructionUnchecked({ - programId, - keys: [account, mint, authority, ...multiSigners], - data, -}: TransactionInstruction): DecodedThawAccountInstructionUnchecked { - return { - programId, - keys: { - account, - mint, - authority, - multiSigners, - }, - data: thawAccountInstructionData.decode(data), - }; -} diff --git a/token/js/src/instructions/transfer.ts b/token/js/src/instructions/transfer.ts deleted file mode 100644 index 3208ec0c91b..00000000000 --- a/token/js/src/instructions/transfer.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { u64 } from '@solana/buffer-layout-utils'; -import { AccountMeta, PublicKey, Signer, TransactionInstruction } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { - TokenInvalidInstructionDataError, - TokenInvalidInstructionKeysError, - TokenInvalidInstructionProgramError, - TokenInvalidInstructionTypeError, -} from '../errors'; -import { addSigners } from './internal'; -import { TokenInstruction } from './types'; - -/** TODO: docs */ -export interface TransferInstructionData { - instruction: TokenInstruction.Transfer; - amount: bigint; -} - -/** TODO: docs */ -export const transferInstructionData = struct([u8('instruction'), u64('amount')]); - -/** - * Construct a Transfer instruction - * - * @param source Source account - * @param destination Destination account - * @param owner Owner of the source account - * @param amount Number of tokens to transfer - * @param multiSigners Signing accounts if `owner` is a multisig - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createTransferInstruction( - source: PublicKey, - destination: PublicKey, - owner: PublicKey, - amount: number | bigint, - multiSigners: Signer[] = [], - programId = TOKEN_PROGRAM_ID -): TransactionInstruction { - const keys = addSigners( - [ - { pubkey: source, isSigner: false, isWritable: true }, - { pubkey: destination, isSigner: false, isWritable: true }, - ], - owner, - multiSigners - ); - - const data = Buffer.alloc(transferInstructionData.span); - transferInstructionData.encode( - { - instruction: TokenInstruction.Transfer, - amount: BigInt(amount), - }, - data - ); - - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid Transfer instruction */ -export interface DecodedTransferInstruction { - programId: PublicKey; - keys: { - source: AccountMeta; - destination: AccountMeta; - owner: AccountMeta; - multiSigners: AccountMeta[]; - }; - data: { - instruction: TokenInstruction.Transfer; - amount: bigint; - }; -} - -/** - * Decode a Transfer instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeTransferInstruction( - instruction: TransactionInstruction, - programId = TOKEN_PROGRAM_ID -): DecodedTransferInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== transferInstructionData.span) throw new TokenInvalidInstructionDataError(); - - const { - keys: { source, destination, owner, multiSigners }, - data, - } = decodeTransferInstructionUnchecked(instruction); - if (data.instruction !== TokenInstruction.Transfer) throw new TokenInvalidInstructionTypeError(); - if (!source || !destination || !owner) throw new TokenInvalidInstructionKeysError(); - - // TODO: key checks? - - return { - programId, - keys: { - source, - destination, - owner, - multiSigners, - }, - data, - }; -} - -/** A decoded, non-validated Transfer instruction */ -export interface DecodedTransferInstructionUnchecked { - programId: PublicKey; - keys: { - source: AccountMeta | undefined; - destination: AccountMeta | undefined; - owner: AccountMeta | undefined; - multiSigners: AccountMeta[]; - }; - data: { - instruction: number; - amount: bigint; - }; -} - -/** - * Decode a Transfer instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeTransferInstructionUnchecked({ - programId, - keys: [source, destination, owner, ...multiSigners], - data, -}: TransactionInstruction): DecodedTransferInstructionUnchecked { - return { - programId, - keys: { - source, - destination, - owner, - multiSigners, - }, - data: transferInstructionData.decode(data), - }; -} diff --git a/token/js/src/instructions/transferChecked.ts b/token/js/src/instructions/transferChecked.ts deleted file mode 100644 index 33c04aa232e..00000000000 --- a/token/js/src/instructions/transferChecked.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { u64 } from '@solana/buffer-layout-utils'; -import { AccountMeta, PublicKey, Signer, TransactionInstruction } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { - TokenInvalidInstructionDataError, - TokenInvalidInstructionKeysError, - TokenInvalidInstructionProgramError, - TokenInvalidInstructionTypeError, -} from '../errors'; -import { addSigners } from './internal'; -import { TokenInstruction } from './types'; - -/** TODO: docs */ -export interface TransferCheckedInstructionData { - instruction: TokenInstruction.TransferChecked; - amount: bigint; - decimals: number; -} - -/** TODO: docs */ -export const transferCheckedInstructionData = struct([ - u8('instruction'), - u64('amount'), - u8('decimals'), -]); - -/** - * Construct a TransferChecked instruction - * - * @param source Source account - * @param mint Mint account - * @param destination Destination account - * @param owner Owner of the source account - * @param amount Number of tokens to transfer - * @param decimals Number of decimals in transfer amount - * @param multiSigners Signing accounts if `owner` is a multisig - * @param programId SPL Token program account - * - * @return Instruction to add to a transaction - */ -export function createTransferCheckedInstruction( - source: PublicKey, - mint: PublicKey, - destination: PublicKey, - owner: PublicKey, - amount: number | bigint, - decimals: number, - multiSigners: Signer[] = [], - programId = TOKEN_PROGRAM_ID -): TransactionInstruction { - const keys = addSigners( - [ - { pubkey: source, isSigner: false, isWritable: true }, - { pubkey: mint, isSigner: false, isWritable: false }, - { pubkey: destination, isSigner: false, isWritable: true }, - ], - owner, - multiSigners - ); - - const data = Buffer.alloc(transferCheckedInstructionData.span); - transferCheckedInstructionData.encode( - { - instruction: TokenInstruction.TransferChecked, - amount: BigInt(amount), - decimals, - }, - data - ); - - return new TransactionInstruction({ keys, programId, data }); -} - -/** A decoded, valid TransferChecked instruction */ -export interface DecodedTransferCheckedInstruction { - programId: PublicKey; - keys: { - source: AccountMeta; - mint: AccountMeta; - destination: AccountMeta; - owner: AccountMeta; - multiSigners: AccountMeta[]; - }; - data: { - instruction: TokenInstruction.TransferChecked; - amount: bigint; - decimals: number; - }; -} - -/** - * Decode a TransferChecked instruction and validate it - * - * @param instruction Transaction instruction to decode - * @param programId SPL Token program account - * - * @return Decoded, valid instruction - */ -export function decodeTransferCheckedInstruction( - instruction: TransactionInstruction, - programId = TOKEN_PROGRAM_ID -): DecodedTransferCheckedInstruction { - if (!instruction.programId.equals(programId)) throw new TokenInvalidInstructionProgramError(); - if (instruction.data.length !== transferCheckedInstructionData.span) throw new TokenInvalidInstructionDataError(); - - const { - keys: { source, mint, destination, owner, multiSigners }, - data, - } = decodeTransferCheckedInstructionUnchecked(instruction); - if (data.instruction !== TokenInstruction.TransferChecked) throw new TokenInvalidInstructionTypeError(); - if (!source || !mint || !destination || !owner) throw new TokenInvalidInstructionKeysError(); - - // TODO: key checks? - - return { - programId, - keys: { - source, - mint, - destination, - owner, - multiSigners, - }, - data, - }; -} - -/** A decoded, non-validated TransferChecked instruction */ -export interface DecodedTransferCheckedInstructionUnchecked { - programId: PublicKey; - keys: { - source: AccountMeta | undefined; - mint: AccountMeta | undefined; - destination: AccountMeta | undefined; - owner: AccountMeta | undefined; - multiSigners: AccountMeta[]; - }; - data: { - instruction: number; - amount: bigint; - decimals: number; - }; -} - -/** - * Decode a TransferChecked instruction without validating it - * - * @param instruction Transaction instruction to decode - * - * @return Decoded, non-validated instruction - */ -export function decodeTransferCheckedInstructionUnchecked({ - programId, - keys: [source, mint, destination, owner, ...multiSigners], - data, -}: TransactionInstruction): DecodedTransferCheckedInstructionUnchecked { - return { - programId, - keys: { - source, - mint, - destination, - owner, - multiSigners, - }, - data: transferCheckedInstructionData.decode(data), - }; -} diff --git a/token/js/src/instructions/types.ts b/token/js/src/instructions/types.ts deleted file mode 100644 index cba1a6db323..00000000000 --- a/token/js/src/instructions/types.ts +++ /dev/null @@ -1,37 +0,0 @@ -/** Instructions defined by the program */ -export enum TokenInstruction { - InitializeMint = 0, - InitializeAccount = 1, - InitializeMultisig = 2, - Transfer = 3, - Approve = 4, - Revoke = 5, - SetAuthority = 6, - MintTo = 7, - Burn = 8, - CloseAccount = 9, - FreezeAccount = 10, - ThawAccount = 11, - TransferChecked = 12, - ApproveChecked = 13, - MintToChecked = 14, - BurnChecked = 15, - InitializeAccount2 = 16, - SyncNative = 17, - InitializeAccount3 = 18, - InitializeMultisig2 = 19, - InitializeMint2 = 20, - GetAccountDataSize = 21, - InitializeImmutableOwner = 22, - AmountToUiAmount = 23, - UiAmountToAmount = 24, - InitializeMintCloseAuthority = 25, - TransferFeeExtension = 26, - ConfidentialTransferExtension = 27, - DefaultAccountStateExtension = 28, - Reallocate = 29, - MemoTransferExtension = 30, - CreateNativeMint = 31, - InitializeNonTransferableMint = 32, - InterestBearingMintExtension = 33, -} diff --git a/token/js/src/state/account.ts b/token/js/src/state/account.ts deleted file mode 100644 index 17e6aaeedec..00000000000 --- a/token/js/src/state/account.ts +++ /dev/null @@ -1,187 +0,0 @@ -import { struct, u32, u8 } from '@solana/buffer-layout'; -import { publicKey, u64 } from '@solana/buffer-layout-utils'; -import { Commitment, Connection, PublicKey, AccountInfo } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { - TokenAccountNotFoundError, - TokenInvalidAccountError, - TokenInvalidAccountOwnerError, - TokenInvalidAccountSizeError, -} from '../errors'; -import { MULTISIG_SIZE } from './multisig'; -import { AccountType, ACCOUNT_TYPE_SIZE } from '../extensions/accountType'; -import { ExtensionType, getAccountLen } from '../extensions/extensionType'; - -/** Information about a token account */ -export interface Account { - /** Address of the account */ - address: PublicKey; - /** Mint associated with the account */ - mint: PublicKey; - /** Owner of the account */ - owner: PublicKey; - /** Number of tokens the account holds */ - amount: bigint; - /** Authority that can transfer tokens from the account */ - delegate: PublicKey | null; - /** Number of tokens the delegate is authorized to transfer */ - delegatedAmount: bigint; - /** True if the account is initialized */ - isInitialized: boolean; - /** True if the account is frozen */ - isFrozen: boolean; - /** True if the account is a native token account */ - isNative: boolean; - /** - * If the account is a native token account, it must be rent-exempt. The rent-exempt reserve is the amount that must - * remain in the balance until the account is closed. - */ - rentExemptReserve: bigint | null; - /** Optional authority to close the account */ - closeAuthority: PublicKey | null; - tlvData: Buffer; -} - -/** Token account state as stored by the program */ -export enum AccountState { - Uninitialized = 0, - Initialized = 1, - Frozen = 2, -} - -/** Token account as stored by the program */ -export interface RawAccount { - mint: PublicKey; - owner: PublicKey; - amount: bigint; - delegateOption: 1 | 0; - delegate: PublicKey; - state: AccountState; - isNativeOption: 1 | 0; - isNative: bigint; - delegatedAmount: bigint; - closeAuthorityOption: 1 | 0; - closeAuthority: PublicKey; -} - -/** Buffer layout for de/serializing a token account */ -export const AccountLayout = struct([ - publicKey('mint'), - publicKey('owner'), - u64('amount'), - u32('delegateOption'), - publicKey('delegate'), - u8('state'), - u32('isNativeOption'), - u64('isNative'), - u64('delegatedAmount'), - u32('closeAuthorityOption'), - publicKey('closeAuthority'), -]); - -/** Byte length of a token account */ -export const ACCOUNT_SIZE = AccountLayout.span; - -/** - * Retrieve information about a token account - * - * @param connection Connection to use - * @param address Token account - * @param commitment Desired level of commitment for querying the state - * @param programId SPL Token program account - * - * @return Token account information - */ -export async function getAccount( - connection: Connection, - address: PublicKey, - commitment?: Commitment, - programId = TOKEN_PROGRAM_ID -): Promise { - const info = await connection.getAccountInfo(address, commitment); - return unpackAccount(info, address, programId); -} - -/** - * Retrieve information about multiple token accounts in a single RPC call - * - * @param connection Connection to use - * @param addresses Token accounts - * @param commitment Desired level of commitment for querying the state - * @param programId SPL Token program account - * - * @return Token account information - */ -export async function getMultipleAccounts( - connection: Connection, - addresses: PublicKey[], - commitment?: Commitment, - programId = TOKEN_PROGRAM_ID -): Promise { - const infos = await connection.getMultipleAccountsInfo(addresses, commitment); - const accounts = []; - for (let i = 0; i < infos.length; i++) { - const account = unpackAccount(infos[i], addresses[i], programId); - accounts.push(account); - } - return accounts; -} - -/** Get the minimum lamport balance for a base token account to be rent exempt - * - * @param connection Connection to use - * @param commitment Desired level of commitment for querying the state - * - * @return Amount of lamports required - */ -export async function getMinimumBalanceForRentExemptAccount( - connection: Connection, - commitment?: Commitment -): Promise { - return await getMinimumBalanceForRentExemptAccountWithExtensions(connection, [], commitment); -} - -/** Get the minimum lamport balance for a rent-exempt token account with extensions - * - * @param connection Connection to use - * @param commitment Desired level of commitment for querying the state - * - * @return Amount of lamports required - */ -export async function getMinimumBalanceForRentExemptAccountWithExtensions( - connection: Connection, - extensions: ExtensionType[], - commitment?: Commitment -): Promise { - const accountLen = getAccountLen(extensions); - return await connection.getMinimumBalanceForRentExemption(accountLen, commitment); -} - -function unpackAccount(info: AccountInfo | null, address: PublicKey, programId: PublicKey) { - if (!info) throw new TokenAccountNotFoundError(); - if (!info.owner.equals(programId)) throw new TokenInvalidAccountOwnerError(); - if (info.data.length < ACCOUNT_SIZE) throw new TokenInvalidAccountSizeError(); - - const rawAccount = AccountLayout.decode(info.data.slice(0, ACCOUNT_SIZE)); - let tlvData = Buffer.alloc(0); - if (info.data.length > ACCOUNT_SIZE) { - if (info.data.length === MULTISIG_SIZE) throw new TokenInvalidAccountSizeError(); - if (info.data[ACCOUNT_SIZE] != AccountType.Account) throw new TokenInvalidAccountError(); - tlvData = info.data.slice(ACCOUNT_SIZE + ACCOUNT_TYPE_SIZE); - } - - return { - address, - mint: rawAccount.mint, - owner: rawAccount.owner, - amount: rawAccount.amount, - delegate: rawAccount.delegateOption ? rawAccount.delegate : null, - delegatedAmount: rawAccount.delegatedAmount, - isInitialized: rawAccount.state !== AccountState.Uninitialized, - isFrozen: rawAccount.state === AccountState.Frozen, - isNative: !!rawAccount.isNativeOption, - rentExemptReserve: rawAccount.isNativeOption ? rawAccount.isNative : null, - closeAuthority: rawAccount.closeAuthorityOption ? rawAccount.closeAuthority : null, - tlvData, - }; -} diff --git a/token/js/src/state/index.ts b/token/js/src/state/index.ts deleted file mode 100644 index 2c623b6fa64..00000000000 --- a/token/js/src/state/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './account'; -export * from './mint'; -export * from './multisig'; diff --git a/token/js/src/state/mint.ts b/token/js/src/state/mint.ts deleted file mode 100644 index f489294c000..00000000000 --- a/token/js/src/state/mint.ts +++ /dev/null @@ -1,190 +0,0 @@ -import { struct, u32, u8 } from '@solana/buffer-layout'; -import { bool, publicKey, u64 } from '@solana/buffer-layout-utils'; -import { Commitment, Connection, PublicKey } from '@solana/web3.js'; -import { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID } from '../constants'; -import { - TokenAccountNotFoundError, - TokenInvalidAccountOwnerError, - TokenInvalidAccountSizeError, - TokenInvalidMintError, - TokenOwnerOffCurveError, -} from '../errors'; -import { ACCOUNT_SIZE } from './account'; -import { MULTISIG_SIZE } from './multisig'; -import { AccountType, ACCOUNT_TYPE_SIZE } from '../extensions/accountType'; -import { ExtensionType, getMintLen } from '../extensions/extensionType'; - -/** Information about a mint */ -export interface Mint { - /** Address of the mint */ - address: PublicKey; - /** - * Optional authority used to mint new tokens. The mint authority may only be provided during mint creation. - * If no mint authority is present then the mint has a fixed supply and no further tokens may be minted. - */ - mintAuthority: PublicKey | null; - /** Total supply of tokens */ - supply: bigint; - /** Number of base 10 digits to the right of the decimal place */ - decimals: number; - /** Is this mint initialized */ - isInitialized: boolean; - /** Optional authority to freeze token accounts */ - freezeAuthority: PublicKey | null; - /** Additional data for extension */ - tlvData: Buffer; -} - -/** Mint as stored by the program */ -export interface RawMint { - mintAuthorityOption: 1 | 0; - mintAuthority: PublicKey; - supply: bigint; - decimals: number; - isInitialized: boolean; - freezeAuthorityOption: 1 | 0; - freezeAuthority: PublicKey; -} - -/** Buffer layout for de/serializing a mint */ -export const MintLayout = struct([ - u32('mintAuthorityOption'), - publicKey('mintAuthority'), - u64('supply'), - u8('decimals'), - bool('isInitialized'), - u32('freezeAuthorityOption'), - publicKey('freezeAuthority'), -]); - -/** Byte length of a mint */ -export const MINT_SIZE = MintLayout.span; - -/** - * Retrieve information about a mint - * - * @param connection Connection to use - * @param address Mint account - * @param commitment Desired level of commitment for querying the state - * @param programId SPL Token program account - * - * @return Mint information - */ -export async function getMint( - connection: Connection, - address: PublicKey, - commitment?: Commitment, - programId = TOKEN_PROGRAM_ID -): Promise { - const info = await connection.getAccountInfo(address, commitment); - if (!info) throw new TokenAccountNotFoundError(); - if (!info.owner.equals(programId)) throw new TokenInvalidAccountOwnerError(); - if (info.data.length < MINT_SIZE) throw new TokenInvalidAccountSizeError(); - - const rawMint = MintLayout.decode(info.data.slice(0, MINT_SIZE)); - let tlvData = Buffer.alloc(0); - if (info.data.length > MINT_SIZE) { - if (info.data.length <= ACCOUNT_SIZE) throw new TokenInvalidAccountSizeError(); - if (info.data.length === MULTISIG_SIZE) throw new TokenInvalidAccountSizeError(); - if (info.data[ACCOUNT_SIZE] != AccountType.Mint) throw new TokenInvalidMintError(); - tlvData = info.data.slice(ACCOUNT_SIZE + ACCOUNT_TYPE_SIZE); - } - - return { - address, - mintAuthority: rawMint.mintAuthorityOption ? rawMint.mintAuthority : null, - supply: rawMint.supply, - decimals: rawMint.decimals, - isInitialized: rawMint.isInitialized, - freezeAuthority: rawMint.freezeAuthorityOption ? rawMint.freezeAuthority : null, - tlvData, - }; -} - -/** Get the minimum lamport balance for a mint to be rent exempt - * - * @param connection Connection to use - * @param commitment Desired level of commitment for querying the state - * - * @return Amount of lamports required - */ -export async function getMinimumBalanceForRentExemptMint( - connection: Connection, - commitment?: Commitment -): Promise { - return await getMinimumBalanceForRentExemptMintWithExtensions(connection, [], commitment); -} - -/** Get the minimum lamport balance for a rent-exempt mint with extensions - * - * @param connection Connection to use - * @param extensions Extension types included in the mint - * @param commitment Desired level of commitment for querying the state - * - * @return Amount of lamports required - */ -export async function getMinimumBalanceForRentExemptMintWithExtensions( - connection: Connection, - extensions: ExtensionType[], - commitment?: Commitment -): Promise { - const mintLen = getMintLen(extensions); - return await connection.getMinimumBalanceForRentExemption(mintLen, commitment); -} - -/** - * Async version of getAssociatedTokenAddressSync - * For backwards compatibility - * - * @param mint Token mint account - * @param owner Owner of the new account - * @param allowOwnerOffCurve Allow the owner account to be a PDA (Program Derived Address) - * @param programId SPL Token program account - * @param associatedTokenProgramId SPL Associated Token program account - * - * @return Promise containing the address of the associated token account - */ -export async function getAssociatedTokenAddress( - mint: PublicKey, - owner: PublicKey, - allowOwnerOffCurve = false, - programId = TOKEN_PROGRAM_ID, - associatedTokenProgramId = ASSOCIATED_TOKEN_PROGRAM_ID -): Promise { - if (!allowOwnerOffCurve && !PublicKey.isOnCurve(owner.toBuffer())) throw new TokenOwnerOffCurveError(); - - const [address] = await PublicKey.findProgramAddress( - [owner.toBuffer(), programId.toBuffer(), mint.toBuffer()], - associatedTokenProgramId - ); - - return address; -} - -/** - * Get the address of the associated token account for a given mint and owner - * - * @param mint Token mint account - * @param owner Owner of the new account - * @param allowOwnerOffCurve Allow the owner account to be a PDA (Program Derived Address) - * @param programId SPL Token program account - * @param associatedTokenProgramId SPL Associated Token program account - * - * @return Address of the associated token account - */ -export function getAssociatedTokenAddressSync( - mint: PublicKey, - owner: PublicKey, - allowOwnerOffCurve = false, - programId = TOKEN_PROGRAM_ID, - associatedTokenProgramId = ASSOCIATED_TOKEN_PROGRAM_ID -): PublicKey { - if (!allowOwnerOffCurve && !PublicKey.isOnCurve(owner.toBuffer())) throw new TokenOwnerOffCurveError(); - - const [address] = PublicKey.findProgramAddressSync( - [owner.toBuffer(), programId.toBuffer(), mint.toBuffer()], - associatedTokenProgramId - ); - - return address; -} diff --git a/token/js/src/state/multisig.ts b/token/js/src/state/multisig.ts deleted file mode 100644 index 7f0f3daad6d..00000000000 --- a/token/js/src/state/multisig.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { struct, u8 } from '@solana/buffer-layout'; -import { bool, publicKey } from '@solana/buffer-layout-utils'; -import { Commitment, Connection, PublicKey } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../constants'; -import { TokenAccountNotFoundError, TokenInvalidAccountOwnerError, TokenInvalidAccountSizeError } from '../errors'; - -/** Information about a multisig */ -export interface Multisig { - /** Address of the multisig */ - address: PublicKey; - /** Number of signers required */ - m: number; - /** Number of possible signers, corresponds to the number of `signers` that are valid */ - n: number; - /** Is this mint initialized */ - isInitialized: boolean; - /** Full set of signers, of which `n` are valid */ - signer1: PublicKey; - signer2: PublicKey; - signer3: PublicKey; - signer4: PublicKey; - signer5: PublicKey; - signer6: PublicKey; - signer7: PublicKey; - signer8: PublicKey; - signer9: PublicKey; - signer10: PublicKey; - signer11: PublicKey; -} - -/** Multisig as stored by the program */ -export type RawMultisig = Omit; - -/** Buffer layout for de/serializing a multisig */ -export const MultisigLayout = struct([ - u8('m'), - u8('n'), - bool('isInitialized'), - publicKey('signer1'), - publicKey('signer2'), - publicKey('signer3'), - publicKey('signer4'), - publicKey('signer5'), - publicKey('signer6'), - publicKey('signer7'), - publicKey('signer8'), - publicKey('signer9'), - publicKey('signer10'), - publicKey('signer11'), -]); - -/** Byte length of a multisig */ -export const MULTISIG_SIZE = MultisigLayout.span; - -/** - * Retrieve information about a multisig - * - * @param connection Connection to use - * @param address Multisig account - * @param commitment Desired level of commitment for querying the state - * @param programId SPL Token program account - * - * @return Multisig information - */ -export async function getMultisig( - connection: Connection, - address: PublicKey, - commitment?: Commitment, - programId = TOKEN_PROGRAM_ID -): Promise { - const info = await connection.getAccountInfo(address, commitment); - if (!info) throw new TokenAccountNotFoundError(); - if (!info.owner.equals(programId)) throw new TokenInvalidAccountOwnerError(); - if (info.data.length != MULTISIG_SIZE) throw new TokenInvalidAccountSizeError(); - - return { address, ...MultisigLayout.decode(info.data) }; -} - -/** Get the minimum lamport balance for a multisig to be rent exempt - * - * @param connection Connection to use - * @param commitment Desired level of commitment for querying the state - * - * @return Amount of lamports required - */ -export async function getMinimumBalanceForRentExemptMultisig( - connection: Connection, - commitment?: Commitment -): Promise { - return await connection.getMinimumBalanceForRentExemption(MULTISIG_SIZE, commitment); -} diff --git a/token/js/test/common.ts b/token/js/test/common.ts deleted file mode 100644 index b9f8ca03325..00000000000 --- a/token/js/test/common.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { PublicKey, Keypair, Connection, Signer } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID } from '../src'; - -export async function newAccountWithLamports(connection: Connection, lamports = 1000000): Promise { - const account = Keypair.generate(); - const signature = await connection.requestAirdrop(account.publicKey, lamports); - await connection.confirmTransaction(signature); - return account; -} - -export async function getConnection(): Promise { - const url = 'http://localhost:8899'; - const connection = new Connection(url, 'confirmed'); - await connection.getVersion(); - return connection; -} - -export const TEST_PROGRAM_ID = process.env.TEST_PROGRAM_ID - ? new PublicKey(process.env.TEST_PROGRAM_ID) - : TOKEN_PROGRAM_ID; diff --git a/token/js/test/e2e-2022/closeMint.test.ts b/token/js/test/e2e-2022/closeMint.test.ts deleted file mode 100644 index e5cb9a277d9..00000000000 --- a/token/js/test/e2e-2022/closeMint.test.ts +++ /dev/null @@ -1,90 +0,0 @@ -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -chai.use(chaiAsPromised); - -import { - sendAndConfirmTransaction, - Connection, - Keypair, - PublicKey, - Signer, - SystemProgram, - Transaction, -} from '@solana/web3.js'; -import { - createAccount, - createInitializeMintInstruction, - createInitializeMintCloseAuthorityInstruction, - closeAccount, - mintTo, - getMintLen, - ExtensionType, -} from '../../src'; -import { TEST_PROGRAM_ID, newAccountWithLamports, getConnection } from '../common'; - -const TEST_TOKEN_DECIMALS = 2; -const EXTENSIONS = [ExtensionType.MintCloseAuthority]; -describe('closeMint', () => { - let connection: Connection; - let payer: Signer; - let mint: PublicKey; - let mintAuthority: Keypair; - let closeAuthority: Keypair; - let account: PublicKey; - let destination: PublicKey; - before(async () => { - connection = await getConnection(); - payer = await newAccountWithLamports(connection, 1000000000); - mintAuthority = Keypair.generate(); - closeAuthority = Keypair.generate(); - }); - beforeEach(async () => { - const mintKeypair = Keypair.generate(); - mint = mintKeypair.publicKey; - const mintLen = getMintLen(EXTENSIONS); - const lamports = await connection.getMinimumBalanceForRentExemption(mintLen); - - const transaction = new Transaction().add( - SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - newAccountPubkey: mint, - space: mintLen, - lamports, - programId: TEST_PROGRAM_ID, - }), - createInitializeMintCloseAuthorityInstruction(mint, closeAuthority.publicKey, TEST_PROGRAM_ID), - createInitializeMintInstruction(mint, TEST_TOKEN_DECIMALS, mintAuthority.publicKey, null, TEST_PROGRAM_ID) - ); - - await sendAndConfirmTransaction(connection, transaction, [payer, mintKeypair], undefined); - }); - it('failsWithNonZeroAmount', async () => { - const owner = Keypair.generate(); - destination = Keypair.generate().publicKey; - account = await createAccount(connection, payer, mint, owner.publicKey, undefined, undefined, TEST_PROGRAM_ID); - const amount = BigInt(1000); - await mintTo(connection, payer, mint, account, mintAuthority, amount, [], undefined, TEST_PROGRAM_ID); - expect(closeAccount(connection, payer, mint, destination, closeAuthority, [], undefined, TEST_PROGRAM_ID)).to.be - .rejected; - }); - it('works', async () => { - destination = Keypair.generate().publicKey; - const accountInfo = await connection.getAccountInfo(mint); - let rentExemptAmount; - expect(accountInfo).to.not.be.null; - if (accountInfo !== null) { - rentExemptAmount = accountInfo.lamports; - } - - await closeAccount(connection, payer, mint, destination, closeAuthority, [], undefined, TEST_PROGRAM_ID); - - const closedInfo = await connection.getAccountInfo(mint); - expect(closedInfo).to.be.null; - - const destinationInfo = await connection.getAccountInfo(destination); - expect(destinationInfo).to.not.be.null; - if (destinationInfo !== null) { - expect(destinationInfo.lamports).to.eql(rentExemptAmount); - } - }); -}); diff --git a/token/js/test/e2e-2022/defaultAccountState.test.ts b/token/js/test/e2e-2022/defaultAccountState.test.ts deleted file mode 100644 index 33e2ee66853..00000000000 --- a/token/js/test/e2e-2022/defaultAccountState.test.ts +++ /dev/null @@ -1,115 +0,0 @@ -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -chai.use(chaiAsPromised); - -import { - sendAndConfirmTransaction, - Connection, - Keypair, - PublicKey, - Signer, - SystemProgram, - Transaction, -} from '@solana/web3.js'; -import { - AccountState, - createAccount, - createInitializeMintInstruction, - createInitializeDefaultAccountStateInstruction, - getAccount, - getDefaultAccountState, - getMint, - getMintLen, - updateDefaultAccountState, - ExtensionType, -} from '../../src'; -import { TEST_PROGRAM_ID, newAccountWithLamports, getConnection } from '../common'; - -const TEST_STATE = AccountState.Frozen; -const TEST_TOKEN_DECIMALS = 2; -const EXTENSIONS = [ExtensionType.DefaultAccountState]; -describe('defaultAccountState', () => { - let connection: Connection; - let payer: Signer; - let mint: PublicKey; - let mintAuthority: Keypair; - let freezeAuthority: Keypair; - before(async () => { - connection = await getConnection(); - payer = await newAccountWithLamports(connection, 1000000000); - mintAuthority = Keypair.generate(); - freezeAuthority = Keypair.generate(); - }); - beforeEach(async () => { - const mintKeypair = Keypair.generate(); - mint = mintKeypair.publicKey; - const mintLen = getMintLen(EXTENSIONS); - const lamports = await connection.getMinimumBalanceForRentExemption(mintLen); - - const transaction = new Transaction().add( - SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - newAccountPubkey: mint, - space: mintLen, - lamports, - programId: TEST_PROGRAM_ID, - }), - createInitializeDefaultAccountStateInstruction(mint, TEST_STATE, TEST_PROGRAM_ID), - createInitializeMintInstruction( - mint, - TEST_TOKEN_DECIMALS, - mintAuthority.publicKey, - freezeAuthority.publicKey, - TEST_PROGRAM_ID - ) - ); - - await sendAndConfirmTransaction(connection, transaction, [payer, mintKeypair], undefined); - }); - it('defaults to frozen', async () => { - const mintInfo = await getMint(connection, mint, undefined, TEST_PROGRAM_ID); - const defaultAccountState = getDefaultAccountState(mintInfo); - expect(defaultAccountState).to.not.be.null; - if (defaultAccountState !== null) { - expect(defaultAccountState.state).to.eql(TEST_STATE); - } - const owner = Keypair.generate(); - const account = await createAccount( - connection, - payer, - mint, - owner.publicKey, - undefined, - undefined, - TEST_PROGRAM_ID - ); - const accountInfo = await getAccount(connection, account, undefined, TEST_PROGRAM_ID); - expect(accountInfo.isFrozen).to.be.true; - expect(accountInfo.isInitialized).to.be.true; - }); - it('defaults to initialized after update', async () => { - await updateDefaultAccountState( - connection, - payer, - mint, - AccountState.Initialized, - freezeAuthority, - [], - undefined, - TEST_PROGRAM_ID - ); - const owner = Keypair.generate(); - const account = await createAccount( - connection, - payer, - mint, - owner.publicKey, - undefined, - undefined, - TEST_PROGRAM_ID - ); - const accountInfo = await getAccount(connection, account, undefined, TEST_PROGRAM_ID); - expect(accountInfo.isFrozen).to.be.false; - expect(accountInfo.isInitialized).to.be.true; - }); -}); diff --git a/token/js/test/e2e-2022/immutableOwner.test.ts b/token/js/test/e2e-2022/immutableOwner.test.ts deleted file mode 100644 index febdda828a8..00000000000 --- a/token/js/test/e2e-2022/immutableOwner.test.ts +++ /dev/null @@ -1,85 +0,0 @@ -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -chai.use(chaiAsPromised); - -import { - Connection, - Keypair, - PublicKey, - Signer, - SystemProgram, - Transaction, - sendAndConfirmTransaction, -} from '@solana/web3.js'; - -import { - AuthorityType, - setAuthority, - ExtensionType, - createInitializeImmutableOwnerInstruction, - createInitializeAccountInstruction, - createMint, - getAccountLen, -} from '../../src'; - -import { TEST_PROGRAM_ID, newAccountWithLamports, getConnection } from '../common'; -const TEST_TOKEN_DECIMALS = 2; -const EXTENSIONS = [ExtensionType.ImmutableOwner]; -describe('immutableOwner', () => { - let connection: Connection; - let payer: Signer; - let owner: Keypair; - let account: PublicKey; - let mint: PublicKey; - before(async () => { - connection = await getConnection(); - payer = await newAccountWithLamports(connection, 1000000000); - }); - beforeEach(async () => { - const mintAuthority = Keypair.generate(); - const mintKeypair = Keypair.generate(); - mint = await createMint( - connection, - payer, - mintAuthority.publicKey, - mintAuthority.publicKey, - TEST_TOKEN_DECIMALS, - mintKeypair, - undefined, - TEST_PROGRAM_ID - ); - owner = Keypair.generate(); - const accountLen = getAccountLen(EXTENSIONS); - const lamports = await connection.getMinimumBalanceForRentExemption(accountLen); - const accountKeypair = Keypair.generate(); - account = accountKeypair.publicKey; - const transaction = new Transaction().add( - SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - newAccountPubkey: account, - space: accountLen, - lamports, - programId: TEST_PROGRAM_ID, - }), - createInitializeImmutableOwnerInstruction(account, TEST_PROGRAM_ID), - createInitializeAccountInstruction(account, mint, owner.publicKey, TEST_PROGRAM_ID) - ); - await sendAndConfirmTransaction(connection, transaction, [payer, accountKeypair], undefined); - }); - it('AccountOwner', async () => { - const newOwner = Keypair.generate(); - expect( - setAuthority( - connection, - payer, - account, - newOwner, - AuthorityType.AccountOwner, - owner.publicKey, - [], - undefined, - TEST_PROGRAM_ID - ) - ).to.be.rejected; - }); -}); diff --git a/token/js/test/e2e-2022/interestBearingMint.test.ts b/token/js/test/e2e-2022/interestBearingMint.test.ts deleted file mode 100644 index f44b48060a4..00000000000 --- a/token/js/test/e2e-2022/interestBearingMint.test.ts +++ /dev/null @@ -1,83 +0,0 @@ -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -chai.use(chaiAsPromised); - -import { Connection, Keypair, PublicKey, Signer } from '@solana/web3.js'; -import { - createInterestBearingMint, - getInterestBearingMintConfigState, - getMint, - updateRateInterestBearingMint, -} from '../../src'; -import { getConnection, newAccountWithLamports, TEST_PROGRAM_ID } from '../common'; - -const TEST_TOKEN_DECIMALS = 2; -const TEST_RATE = 10; -const TEST_UPDATE_RATE = 50; - -describe('interestBearingMint', () => { - let connection: Connection; - let payer: Signer; - let mint: PublicKey; - let rateAuthority: Keypair; - let mintAuthority: Keypair; - let freezeAuthority: Keypair; - let mintKeypair: Keypair; - - before(async () => { - connection = await getConnection(); - payer = await newAccountWithLamports(connection, 1000000000); - rateAuthority = Keypair.generate(); - mintAuthority = Keypair.generate(); - freezeAuthority = Keypair.generate(); - }); - - it('initialize and update rate', async () => { - mintKeypair = Keypair.generate(); - mint = mintKeypair.publicKey; - await createInterestBearingMint( - connection, - payer, - mintAuthority.publicKey, - freezeAuthority.publicKey, - rateAuthority.publicKey, - TEST_RATE, - TEST_TOKEN_DECIMALS, - mintKeypair, - undefined, - TEST_PROGRAM_ID - ); - const mintInfo = await getMint(connection, mint, undefined, TEST_PROGRAM_ID); - const interestBearingMintConfigState = getInterestBearingMintConfigState(mintInfo); - expect(interestBearingMintConfigState).to.not.be.null; - if (interestBearingMintConfigState !== null) { - expect(interestBearingMintConfigState.rateAuthority).to.eql(rateAuthority.publicKey); - expect(interestBearingMintConfigState.preUpdateAverageRate).to.eql(TEST_RATE); - expect(interestBearingMintConfigState.currentRate).to.eql(TEST_RATE); - expect(interestBearingMintConfigState.lastUpdateTimestamp).to.be.greaterThan(0); - expect(interestBearingMintConfigState.initializationTimestamp).to.be.greaterThan(0); - } - - await updateRateInterestBearingMint( - connection, - payer, - mint, - rateAuthority, - TEST_UPDATE_RATE, - [], - undefined, - TEST_PROGRAM_ID - ); - const mintInfoUpdatedRate = await getMint(connection, mint, undefined, TEST_PROGRAM_ID); - const updatedRateConfigState = getInterestBearingMintConfigState(mintInfoUpdatedRate); - - expect(updatedRateConfigState).to.not.be.null; - if (updatedRateConfigState !== null) { - expect(updatedRateConfigState.rateAuthority).to.eql(rateAuthority.publicKey); - expect(updatedRateConfigState.currentRate).to.eql(TEST_UPDATE_RATE); - expect(updatedRateConfigState.preUpdateAverageRate).to.eql(TEST_RATE); - expect(updatedRateConfigState.lastUpdateTimestamp).to.be.greaterThan(0); - expect(updatedRateConfigState.initializationTimestamp).to.be.greaterThan(0); - } - }); -}); diff --git a/token/js/test/e2e-2022/memoTransfer.test.ts b/token/js/test/e2e-2022/memoTransfer.test.ts deleted file mode 100644 index d9f8d4f11bc..00000000000 --- a/token/js/test/e2e-2022/memoTransfer.test.ts +++ /dev/null @@ -1,128 +0,0 @@ -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -chai.use(chaiAsPromised); - -import { - sendAndConfirmTransaction, - Connection, - Keypair, - PublicKey, - Signer, - SystemProgram, - Transaction, -} from '@solana/web3.js'; -import { createMemoInstruction } from '@solana/spl-memo'; -import { - createAccount, - createMint, - createEnableRequiredMemoTransfersInstruction, - createInitializeAccountInstruction, - createTransferInstruction, - getAccount, - getMemoTransfer, - disableRequiredMemoTransfers, - enableRequiredMemoTransfers, - mintTo, - transfer, - getAccountLen, - ExtensionType, -} from '../../src'; -import { TEST_PROGRAM_ID, newAccountWithLamports, getConnection } from '../common'; - -const TEST_TOKEN_DECIMALS = 2; -const TRANSFER_AMOUNT = 1_000; -const EXTENSIONS = [ExtensionType.MemoTransfer]; -describe('memoTransfer', () => { - let connection: Connection; - let payer: Signer; - let owner: Keypair; - let mint: PublicKey; - let mintAuthority: Keypair; - let source: PublicKey; - let destination: PublicKey; - before(async () => { - connection = await getConnection(); - payer = await newAccountWithLamports(connection, 1000000000); - mintAuthority = Keypair.generate(); - owner = Keypair.generate(); - }); - beforeEach(async () => { - const mintKeypair = Keypair.generate(); - mint = await createMint( - connection, - payer, - mintAuthority.publicKey, - mintAuthority.publicKey, - TEST_TOKEN_DECIMALS, - mintKeypair, - undefined, - TEST_PROGRAM_ID - ); - - source = await createAccount( - connection, - payer, - mint, - owner.publicKey, - undefined, // uses ATA by default - undefined, - TEST_PROGRAM_ID - ); - - const destinationKeypair = Keypair.generate(); - destination = destinationKeypair.publicKey; - const accountLen = getAccountLen(EXTENSIONS); - const lamports = await connection.getMinimumBalanceForRentExemption(accountLen); - - const transaction = new Transaction().add( - SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - newAccountPubkey: destination, - space: accountLen, - lamports, - programId: TEST_PROGRAM_ID, - }), - createInitializeAccountInstruction(destination, mint, owner.publicKey, TEST_PROGRAM_ID), - createEnableRequiredMemoTransfersInstruction(destination, owner.publicKey, [], TEST_PROGRAM_ID) - ); - - await sendAndConfirmTransaction(connection, transaction, [payer, owner, destinationKeypair], undefined); - await mintTo( - connection, - payer, - mint, - source, - mintAuthority, - TRANSFER_AMOUNT * 10, - [], - undefined, - TEST_PROGRAM_ID - ); - }); - it('fails without memo when enabled', async () => { - const accountInfo = await getAccount(connection, destination, undefined, TEST_PROGRAM_ID); - const memoTransfer = getMemoTransfer(accountInfo); - expect(memoTransfer).to.not.be.null; - if (memoTransfer !== null) { - expect(memoTransfer.requireIncomingTransferMemos).to.be.true; - } - expect(transfer(connection, payer, source, destination, owner, TRANSFER_AMOUNT, [], undefined, TEST_PROGRAM_ID)) - .to.be.rejected; - }); - it('works without memo when disabled', async () => { - await disableRequiredMemoTransfers(connection, payer, destination, owner, [], undefined, TEST_PROGRAM_ID); - await transfer(connection, payer, source, destination, owner, TRANSFER_AMOUNT, [], undefined, TEST_PROGRAM_ID); - await enableRequiredMemoTransfers(connection, payer, destination, owner, [], undefined, TEST_PROGRAM_ID); - expect(transfer(connection, payer, source, destination, owner, TRANSFER_AMOUNT, [], undefined, TEST_PROGRAM_ID)) - .to.be.rejected; - }); - it('works with memo when enabled', async () => { - const transaction = new Transaction().add( - createMemoInstruction('transfer with a memo', [payer.publicKey, owner.publicKey]), - createTransferInstruction(source, destination, owner.publicKey, TRANSFER_AMOUNT, [], TEST_PROGRAM_ID) - ); - await sendAndConfirmTransaction(connection, transaction, [payer, owner], { - preflightCommitment: 'confirmed', - }); - }); -}); diff --git a/token/js/test/e2e-2022/nonTransferableMint.test.ts b/token/js/test/e2e-2022/nonTransferableMint.test.ts deleted file mode 100644 index 69367e6a13e..00000000000 --- a/token/js/test/e2e-2022/nonTransferableMint.test.ts +++ /dev/null @@ -1,106 +0,0 @@ -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -chai.use(chaiAsPromised); - -import { - sendAndConfirmTransaction, - Connection, - Keypair, - PublicKey, - Signer, - SystemProgram, - Transaction, -} from '@solana/web3.js'; -import { - createInitializeMintInstruction, - createInitializeNonTransferableMintInstruction, - createInitializeImmutableOwnerInstruction, - createInitializeAccountInstruction, - mintTo, - getAccountLen, - getMint, - getMintLen, - getNonTransferable, - transfer, - ExtensionType, -} from '../../src'; -import { TEST_PROGRAM_ID, newAccountWithLamports, getConnection } from '../common'; - -const TEST_TOKEN_DECIMALS = 2; -const EXTENSIONS = [ExtensionType.NonTransferable]; -describe('nonTransferable', () => { - let connection: Connection; - let payer: Signer; - let mint: PublicKey; - let mintAuthority: Keypair; - before(async () => { - connection = await getConnection(); - payer = await newAccountWithLamports(connection, 1000000000); - mintAuthority = Keypair.generate(); - }); - beforeEach(async () => { - const mintKeypair = Keypair.generate(); - mint = mintKeypair.publicKey; - const mintLen = getMintLen(EXTENSIONS); - const lamports = await connection.getMinimumBalanceForRentExemption(mintLen); - - const transaction = new Transaction().add( - SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - newAccountPubkey: mint, - space: mintLen, - lamports, - programId: TEST_PROGRAM_ID, - }), - createInitializeNonTransferableMintInstruction(mint, TEST_PROGRAM_ID), - createInitializeMintInstruction(mint, TEST_TOKEN_DECIMALS, mintAuthority.publicKey, null, TEST_PROGRAM_ID) - ); - - await sendAndConfirmTransaction(connection, transaction, [payer, mintKeypair], undefined); - }); - it('fails transfer', async () => { - const mintInfo = await getMint(connection, mint, undefined, TEST_PROGRAM_ID); - const nonTransferable = getNonTransferable(mintInfo); - expect(nonTransferable).to.not.be.null; - - const owner = Keypair.generate(); - const accountLen = getAccountLen([ExtensionType.ImmutableOwner]); - const lamports = await connection.getMinimumBalanceForRentExemption(accountLen); - - const sourceKeypair = Keypair.generate(); - const source = sourceKeypair.publicKey; - let transaction = new Transaction().add( - SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - newAccountPubkey: source, - space: accountLen, - lamports, - programId: TEST_PROGRAM_ID, - }), - createInitializeImmutableOwnerInstruction(source, TEST_PROGRAM_ID), - createInitializeAccountInstruction(source, mint, owner.publicKey, TEST_PROGRAM_ID) - ); - await sendAndConfirmTransaction(connection, transaction, [payer, sourceKeypair], undefined); - - const destinationKeypair = Keypair.generate(); - const destination = destinationKeypair.publicKey; - transaction = new Transaction().add( - SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - newAccountPubkey: destination, - space: accountLen, - lamports, - programId: TEST_PROGRAM_ID, - }), - createInitializeImmutableOwnerInstruction(destination, TEST_PROGRAM_ID), - createInitializeAccountInstruction(destination, mint, owner.publicKey, TEST_PROGRAM_ID) - ); - await sendAndConfirmTransaction(connection, transaction, [payer, destinationKeypair], undefined); - - const amount = BigInt(1000); - await mintTo(connection, payer, mint, source, mintAuthority, amount, [], undefined, TEST_PROGRAM_ID); - - expect(transfer(connection, payer, source, destination, owner, amount, [], undefined, TEST_PROGRAM_ID)).to.be - .rejected; - }); -}); diff --git a/token/js/test/e2e-2022/transferFee.test.ts b/token/js/test/e2e-2022/transferFee.test.ts deleted file mode 100644 index ca5b4112eb0..00000000000 --- a/token/js/test/e2e-2022/transferFee.test.ts +++ /dev/null @@ -1,236 +0,0 @@ -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -chai.use(chaiAsPromised); - -import { - Connection, - Keypair, - PublicKey, - Signer, - SystemProgram, - Transaction, - sendAndConfirmTransaction, -} from '@solana/web3.js'; - -import { - ExtensionType, - createInitializeMintInstruction, - getTransferFeeAmount, - getTransferFeeConfig, - mintTo, - transferChecked, - createAccount, - getAccount, - getMint, - getMintLen, -} from '../../src'; - -import { - createInitializeTransferFeeConfigInstruction, - harvestWithheldTokensToMint, - transferCheckedWithFee, - withdrawWithheldTokensFromAccounts, - withdrawWithheldTokensFromMint, -} from '../../src/extensions/transferFee/index'; - -import { TEST_PROGRAM_ID, newAccountWithLamports, getConnection } from '../common'; -const TEST_TOKEN_DECIMALS = 2; -const MINT_EXTENSIONS = [ExtensionType.TransferFeeConfig]; -const MINT_AMOUNT = BigInt(1_000_000_000); -const TRANSFER_AMOUNT = BigInt(1_000_000); -const FEE_BASIS_POINTS = 100; -const MAX_FEE = BigInt(100_000); -const FEE = (TRANSFER_AMOUNT * BigInt(FEE_BASIS_POINTS)) / BigInt(10_000); -describe('transferFee', () => { - let connection: Connection; - let payer: Signer; - let owner: Keypair; - let sourceAccount: PublicKey; - let destinationAccount: PublicKey; - let mint: PublicKey; - let transferFeeConfigAuthority: Keypair; - let withdrawWithheldAuthority: Keypair; - before(async () => { - connection = await getConnection(); - payer = await newAccountWithLamports(connection, 1000000000); - transferFeeConfigAuthority = Keypair.generate(); - withdrawWithheldAuthority = Keypair.generate(); - }); - beforeEach(async () => { - const mintAuthority = Keypair.generate(); - const mintKeypair = Keypair.generate(); - mint = mintKeypair.publicKey; - const mintLen = getMintLen(MINT_EXTENSIONS); - const mintLamports = await connection.getMinimumBalanceForRentExemption(mintLen); - const mintTransaction = new Transaction().add( - SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - newAccountPubkey: mint, - space: mintLen, - lamports: mintLamports, - programId: TEST_PROGRAM_ID, - }), - createInitializeTransferFeeConfigInstruction( - mint, - transferFeeConfigAuthority.publicKey, - withdrawWithheldAuthority.publicKey, - FEE_BASIS_POINTS, - MAX_FEE, - TEST_PROGRAM_ID - ), - createInitializeMintInstruction(mint, TEST_TOKEN_DECIMALS, mintAuthority.publicKey, null, TEST_PROGRAM_ID) - ); - await sendAndConfirmTransaction(connection, mintTransaction, [payer, mintKeypair], undefined); - - owner = Keypair.generate(); - sourceAccount = await createAccount( - connection, - payer, - mint, - owner.publicKey, - undefined, - undefined, - TEST_PROGRAM_ID - ); - await mintTo( - connection, - payer, - mint, - sourceAccount, - mintAuthority, - MINT_AMOUNT, - [], - undefined, - TEST_PROGRAM_ID - ); - - const accountKeypair = Keypair.generate(); - destinationAccount = await createAccount( - connection, - payer, - mint, - owner.publicKey, - accountKeypair, - undefined, - TEST_PROGRAM_ID - ); - - await transferChecked( - connection, - payer, - sourceAccount, - mint, - destinationAccount, - owner, - TRANSFER_AMOUNT, - TEST_TOKEN_DECIMALS, - [], - undefined, - TEST_PROGRAM_ID - ); - }); - it('initializes', async () => { - const mintInfo = await getMint(connection, mint, undefined, TEST_PROGRAM_ID); - const transferFeeConfig = getTransferFeeConfig(mintInfo); - expect(transferFeeConfig).to.not.be.null; - if (transferFeeConfig !== null) { - expect(transferFeeConfig.transferFeeConfigAuthority).to.eql(transferFeeConfigAuthority.publicKey); - expect(transferFeeConfig.withdrawWithheldAuthority).to.eql(withdrawWithheldAuthority.publicKey); - expect(transferFeeConfig.olderTransferFee.transferFeeBasisPoints).to.eql(FEE_BASIS_POINTS); - expect(transferFeeConfig.olderTransferFee.maximumFee).to.eql(MAX_FEE); - expect(transferFeeConfig.newerTransferFee.transferFeeBasisPoints).to.eql(FEE_BASIS_POINTS); - expect(transferFeeConfig.newerTransferFee.maximumFee).to.eql(MAX_FEE); - expect(transferFeeConfig.withheldAmount).to.eql(BigInt(0)); - } - - const accountInfo = await getAccount(connection, destinationAccount, undefined, TEST_PROGRAM_ID); - const transferFeeAmount = getTransferFeeAmount(accountInfo); - expect(transferFeeAmount).to.not.be.null; - if (transferFeeAmount !== null) { - expect(transferFeeAmount.withheldAmount).to.eql(FEE); - } - }); - it('transferCheckedWithFee', async () => { - await transferCheckedWithFee( - connection, - payer, - sourceAccount, - mint, - destinationAccount, - owner, - TRANSFER_AMOUNT, - TEST_TOKEN_DECIMALS, - FEE, - [], - undefined, - TEST_PROGRAM_ID - ); - const accountInfo = await getAccount(connection, destinationAccount, undefined, TEST_PROGRAM_ID); - const transferFeeAmount = getTransferFeeAmount(accountInfo); - expect(transferFeeAmount).to.not.be.null; - if (transferFeeAmount !== null) { - expect(transferFeeAmount.withheldAmount).to.eql(FEE * BigInt(2)); - } - }); - it('withdrawWithheldTokensFromAccounts', async () => { - await withdrawWithheldTokensFromAccounts( - connection, - payer, - mint, - destinationAccount, - withdrawWithheldAuthority, - [], - [destinationAccount], - undefined, - TEST_PROGRAM_ID - ); - const accountInfo = await getAccount(connection, destinationAccount, undefined, TEST_PROGRAM_ID); - expect(accountInfo.amount).to.eql(TRANSFER_AMOUNT); - const transferFeeAmount = getTransferFeeAmount(accountInfo); - expect(transferFeeAmount).to.not.be.null; - if (transferFeeAmount !== null) { - expect(transferFeeAmount.withheldAmount).to.eql(BigInt(0)); - } - }); - it('harvestWithheldTokensToMint', async () => { - await harvestWithheldTokensToMint(connection, payer, mint, [destinationAccount], undefined, TEST_PROGRAM_ID); - const accountInfo = await getAccount(connection, destinationAccount, undefined, TEST_PROGRAM_ID); - const transferFeeAmount = getTransferFeeAmount(accountInfo); - expect(transferFeeAmount).to.not.be.null; - if (transferFeeAmount !== null) { - expect(transferFeeAmount.withheldAmount).to.eql(BigInt(0)); - } - const mintInfo = await getMint(connection, mint, undefined, TEST_PROGRAM_ID); - const transferFeeConfig = getTransferFeeConfig(mintInfo); - expect(transferFeeConfig).to.not.be.null; - if (transferFeeConfig !== null) { - expect(transferFeeConfig.withheldAmount).to.eql(FEE); - } - }); - it('withdrawWithheldTokensFromMint', async () => { - await harvestWithheldTokensToMint(connection, payer, mint, [destinationAccount], undefined, TEST_PROGRAM_ID); - await withdrawWithheldTokensFromMint( - connection, - payer, - mint, - destinationAccount, - withdrawWithheldAuthority, - [], - undefined, - TEST_PROGRAM_ID - ); - const accountInfo = await getAccount(connection, destinationAccount, undefined, TEST_PROGRAM_ID); - expect(accountInfo.amount).to.eql(TRANSFER_AMOUNT); - const transferFeeAmount = getTransferFeeAmount(accountInfo); - expect(transferFeeAmount).to.not.be.null; - if (transferFeeAmount !== null) { - expect(transferFeeAmount.withheldAmount).to.eql(BigInt(0)); - } - const mintInfo = await getMint(connection, mint, undefined, TEST_PROGRAM_ID); - const transferFeeConfig = getTransferFeeConfig(mintInfo); - expect(transferFeeConfig).to.not.be.null; - if (transferFeeConfig !== null) { - expect(transferFeeConfig.withheldAmount).to.eql(BigInt(0)); - } - }); -}); diff --git a/token/js/test/e2e/burn.test.ts b/token/js/test/e2e/burn.test.ts deleted file mode 100644 index 4786fb8d07f..00000000000 --- a/token/js/test/e2e/burn.test.ts +++ /dev/null @@ -1,63 +0,0 @@ -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -chai.use(chaiAsPromised); - -import { Connection, Keypair, PublicKey, Signer } from '@solana/web3.js'; -import { createMint, createAccount, getAccount, mintTo, burn, burnChecked } from '../../src'; -import { TEST_PROGRAM_ID, newAccountWithLamports, getConnection } from '../common'; - -const TEST_TOKEN_DECIMALS = 2; -describe('burn', () => { - let connection: Connection; - let payer: Signer; - let mint: PublicKey; - let mintAuthority: Keypair; - let owner: Keypair; - let account: PublicKey; - let amount: bigint; - before(async () => { - connection = await getConnection(); - payer = await newAccountWithLamports(connection, 1000000000); - mintAuthority = Keypair.generate(); - const mintKeypair = Keypair.generate(); - mint = await createMint( - connection, - payer, - mintAuthority.publicKey, - mintAuthority.publicKey, - TEST_TOKEN_DECIMALS, - mintKeypair, - undefined, - TEST_PROGRAM_ID - ); - }); - beforeEach(async () => { - owner = Keypair.generate(); - account = await createAccount(connection, payer, mint, owner.publicKey, undefined, undefined, TEST_PROGRAM_ID); - amount = BigInt(1000); - await mintTo(connection, payer, mint, account, mintAuthority, amount, [], undefined, TEST_PROGRAM_ID); - }); - it('burn', async () => { - const burnAmount = BigInt(1); - await burn(connection, payer, account, mint, owner, burnAmount, [], undefined, TEST_PROGRAM_ID); - const accountInfo = await getAccount(connection, account, undefined, TEST_PROGRAM_ID); - expect(accountInfo.amount).to.eql(amount - burnAmount); - }); - it('burnChecked', async () => { - const burnAmount = BigInt(1); - await burnChecked( - connection, - payer, - account, - mint, - owner, - burnAmount, - TEST_TOKEN_DECIMALS, - [], - undefined, - TEST_PROGRAM_ID - ); - const accountInfo = await getAccount(connection, account, undefined, TEST_PROGRAM_ID); - expect(accountInfo.amount).to.eql(amount - burnAmount); - }); -}); diff --git a/token/js/test/e2e/close.test.ts b/token/js/test/e2e/close.test.ts deleted file mode 100644 index 2cb1db74227..00000000000 --- a/token/js/test/e2e/close.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -chai.use(chaiAsPromised); - -import { Connection, Keypair, PublicKey, Signer } from '@solana/web3.js'; -import { createMint, createAccount, closeAccount, mintTo } from '../../src'; -import { TEST_PROGRAM_ID, newAccountWithLamports, getConnection } from '../common'; - -const TEST_TOKEN_DECIMALS = 2; -describe('close', () => { - let connection: Connection; - let payer: Signer; - let mint: PublicKey; - let mintAuthority: Keypair; - let freezeAuthority: Keypair; - let owner: Keypair; - let account: PublicKey; - let destination: PublicKey; - before(async () => { - connection = await getConnection(); - payer = await newAccountWithLamports(connection, 1000000000); - mintAuthority = Keypair.generate(); - freezeAuthority = Keypair.generate(); - const mintKeypair = Keypair.generate(); - mint = await createMint( - connection, - payer, - mintAuthority.publicKey, - freezeAuthority.publicKey, - TEST_TOKEN_DECIMALS, - mintKeypair, - undefined, - TEST_PROGRAM_ID - ); - }); - beforeEach(async () => { - owner = Keypair.generate(); - destination = Keypair.generate().publicKey; - account = await createAccount(connection, payer, mint, owner.publicKey, undefined, undefined, TEST_PROGRAM_ID); - }); - it('failsWithNonZeroAmount', async () => { - const amount = BigInt(1000); - await mintTo(connection, payer, mint, account, mintAuthority, amount, [], undefined, TEST_PROGRAM_ID); - expect(closeAccount(connection, payer, account, destination, owner, [], undefined, TEST_PROGRAM_ID)).to.be - .rejected; - }); - it('works', async () => { - const accountInfo = await connection.getAccountInfo(account); - let tokenRentExemptAmount; - expect(accountInfo).to.not.be.null; - if (accountInfo !== null) { - tokenRentExemptAmount = accountInfo.lamports; - } - - await closeAccount(connection, payer, account, destination, owner, [], undefined, TEST_PROGRAM_ID); - - const closedInfo = await connection.getAccountInfo(account); - expect(closedInfo).to.be.null; - - const destinationInfo = await connection.getAccountInfo(destination); - expect(destinationInfo).to.not.be.null; - if (destinationInfo !== null) { - expect(destinationInfo.lamports).to.eql(tokenRentExemptAmount); - } - }); -}); diff --git a/token/js/test/e2e/create.test.ts b/token/js/test/e2e/create.test.ts deleted file mode 100644 index f0622240ea4..00000000000 --- a/token/js/test/e2e/create.test.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { Connection, Keypair, PublicKey, Signer } from '@solana/web3.js'; - -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -chai.use(chaiAsPromised); - -import { - ASSOCIATED_TOKEN_PROGRAM_ID, - createMint, - getMint, - createAccount, - getAccount, - getAssociatedTokenAddress, -} from '../../src'; - -import { TEST_PROGRAM_ID, newAccountWithLamports, getConnection } from '../common'; - -const TEST_TOKEN_DECIMALS = 2; -describe('createMint', () => { - it('works', async () => { - const connection = await getConnection(); - const payer = await newAccountWithLamports(connection, 1000000000); - const testMintAuthority = Keypair.generate(); - const mintKeypair = Keypair.generate(); - const mint = await createMint( - connection, - payer, - testMintAuthority.publicKey, - testMintAuthority.publicKey, - TEST_TOKEN_DECIMALS, - mintKeypair, - undefined, - TEST_PROGRAM_ID - ); - - const mintInfo = await getMint(connection, mint, undefined, TEST_PROGRAM_ID); - - expect(mintInfo.mintAuthority).to.eql(testMintAuthority.publicKey); - expect(mintInfo.supply).to.eql(BigInt(0)); - expect(mintInfo.decimals).to.eql(TEST_TOKEN_DECIMALS); - expect(mintInfo.isInitialized).to.be.true; - expect(mintInfo.freezeAuthority).to.eql(testMintAuthority.publicKey); - }); -}); - -describe('createAccount', () => { - let connection: Connection; - let payer: Signer; - let mint: PublicKey; - before(async () => { - connection = await getConnection(); - payer = await newAccountWithLamports(connection, 1000000000); - const mintAuthority = Keypair.generate(); - const mintKeypair = Keypair.generate(); - mint = await createMint( - connection, - payer, - mintAuthority.publicKey, - mintAuthority.publicKey, - TEST_TOKEN_DECIMALS, - mintKeypair, - undefined, - TEST_PROGRAM_ID - ); - }), - it('auxiliary token account', async () => { - const owner = Keypair.generate(); - const account = await createAccount( - connection, - payer, - mint, - owner.publicKey, - Keypair.generate(), - undefined, - TEST_PROGRAM_ID - ); - const accountInfo = await getAccount(connection, account, undefined, TEST_PROGRAM_ID); - expect(accountInfo.mint).to.eql(mint); - expect(accountInfo.owner).to.eql(owner.publicKey); - expect(accountInfo.amount).to.eql(BigInt(0)); - expect(accountInfo.delegate).to.be.null; - expect(accountInfo.delegatedAmount).to.eql(BigInt(0)); - expect(accountInfo.isInitialized).to.be.true; - expect(accountInfo.isFrozen).to.be.false; - expect(accountInfo.isNative).to.be.false; - expect(accountInfo.rentExemptReserve).to.be.null; - expect(accountInfo.closeAuthority).to.be.null; - - // you can create as many accounts as with same owner - const account2 = await createAccount( - connection, - payer, - mint, - owner.publicKey, - Keypair.generate(), - undefined, - TEST_PROGRAM_ID - ); - expect(account2).to.not.eql(account); - }), - it('associated token account', async () => { - const owner = Keypair.generate(); - const associatedAddress = await getAssociatedTokenAddress( - mint, - owner.publicKey, - false, - TEST_PROGRAM_ID, - ASSOCIATED_TOKEN_PROGRAM_ID - ); - - // associated account shouldn't exist - const info = await connection.getAccountInfo(associatedAddress); - expect(info).to.be.null; - - const createdAddress = await createAccount( - connection, - payer, - mint, - owner.publicKey, - undefined, // uses ATA by default - undefined, - TEST_PROGRAM_ID - ); - expect(createdAddress).to.eql(associatedAddress); - - const accountInfo = await getAccount(connection, associatedAddress, undefined, TEST_PROGRAM_ID); - expect(accountInfo).to.not.be.null; - expect(accountInfo.mint).to.eql(mint); - expect(accountInfo.owner).to.eql(owner.publicKey); - expect(accountInfo.amount).to.eql(BigInt(0)); - - // creating again should cause TX error for the associated token account - expect( - createAccount( - connection, - payer, - mint, - owner.publicKey, - undefined, // uses ATA by default - undefined, - TEST_PROGRAM_ID - ) - ).to.be.rejected; - }); -}); diff --git a/token/js/test/e2e/freeze.test.ts b/token/js/test/e2e/freeze.test.ts deleted file mode 100644 index 67a14d4148e..00000000000 --- a/token/js/test/e2e/freeze.test.ts +++ /dev/null @@ -1,60 +0,0 @@ -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -chai.use(chaiAsPromised); - -import { Connection, Keypair, PublicKey, Signer } from '@solana/web3.js'; - -import { burn, createMint, createAccount, getAccount, freezeAccount, thawAccount, mintTo } from '../../src'; -import { TEST_PROGRAM_ID, newAccountWithLamports, getConnection } from '../common'; - -const TEST_TOKEN_DECIMALS = 2; -describe('freezeThaw', () => { - let connection: Connection; - let payer: Signer; - let mint: PublicKey; - let mintAuthority: Keypair; - let freezeAuthority: Keypair; - let owner: Keypair; - let account: PublicKey; - let amount: bigint; - const burnAmount = BigInt(1); - before(async () => { - connection = await getConnection(); - payer = await newAccountWithLamports(connection, 1000000000); - mintAuthority = Keypair.generate(); - freezeAuthority = Keypair.generate(); - const mintKeypair = Keypair.generate(); - mint = await createMint( - connection, - payer, - mintAuthority.publicKey, - freezeAuthority.publicKey, - TEST_TOKEN_DECIMALS, - mintKeypair, - undefined, - TEST_PROGRAM_ID - ); - }); - beforeEach(async () => { - owner = Keypair.generate(); - account = await createAccount(connection, payer, mint, owner.publicKey, undefined, undefined, TEST_PROGRAM_ID); - amount = BigInt(1000); - await mintTo(connection, payer, mint, account, mintAuthority, amount, [], undefined, TEST_PROGRAM_ID); - }); - it('freezes', async () => { - await freezeAccount(connection, payer, account, mint, freezeAuthority, [], undefined, TEST_PROGRAM_ID); - - expect(burn(connection, payer, account, mint, owner, burnAmount, [], undefined, TEST_PROGRAM_ID)).to.be - .rejected; - }); - it('thaws', async () => { - await freezeAccount(connection, payer, account, mint, freezeAuthority, [], undefined, TEST_PROGRAM_ID); - - await thawAccount(connection, payer, account, mint, freezeAuthority, [], undefined, TEST_PROGRAM_ID); - - await burn(connection, payer, account, mint, owner, burnAmount, [], undefined, TEST_PROGRAM_ID); - const accountInfo = await getAccount(connection, account, undefined, TEST_PROGRAM_ID); - - expect(accountInfo.amount).to.eql(amount - burnAmount); - }); -}); diff --git a/token/js/test/e2e/mint.test.ts b/token/js/test/e2e/mint.test.ts deleted file mode 100644 index 9d1999af120..00000000000 --- a/token/js/test/e2e/mint.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -chai.use(chaiAsPromised); - -import { Connection, Keypair, PublicKey, Signer } from '@solana/web3.js'; - -import { createMint, getMint, createAccount, getAccount, mintTo, mintToChecked } from '../../src'; - -import { TEST_PROGRAM_ID, newAccountWithLamports, getConnection } from '../common'; - -const TEST_TOKEN_DECIMALS = 2; -describe('mint', () => { - let connection: Connection; - let payer: Signer; - let mint: PublicKey; - let mintAuthority: Keypair; - let owner: Keypair; - let account: PublicKey; - before(async () => { - connection = await getConnection(); - payer = await newAccountWithLamports(connection, 1000000000); - mintAuthority = Keypair.generate(); - const mintKeypair = Keypair.generate(); - mint = await createMint( - connection, - payer, - mintAuthority.publicKey, - mintAuthority.publicKey, - TEST_TOKEN_DECIMALS, - mintKeypair, - undefined, - TEST_PROGRAM_ID - ); - owner = Keypair.generate(); - account = await createAccount(connection, payer, mint, owner.publicKey, undefined, undefined, TEST_PROGRAM_ID); - }); - it('mintTo', async () => { - const amount = BigInt(1000); - await mintTo(connection, payer, mint, account, mintAuthority, amount, [], undefined, TEST_PROGRAM_ID); - - const mintInfo = await getMint(connection, mint, undefined, TEST_PROGRAM_ID); - expect(mintInfo.supply).to.eql(amount); - - const accountInfo = await getAccount(connection, account, undefined, TEST_PROGRAM_ID); - expect(accountInfo.amount).to.eql(amount); - }); - it('mintToChecked', async () => { - const amount = BigInt(1000); - await mintToChecked( - connection, - payer, - mint, - account, - mintAuthority, - amount, - TEST_TOKEN_DECIMALS, - [], - undefined, - TEST_PROGRAM_ID - ); - - expect( - mintToChecked(connection, payer, mint, account, mintAuthority, amount, 1, [], undefined, TEST_PROGRAM_ID) - ).to.be.rejected; - }); -}); diff --git a/token/js/test/e2e/multisig.test.ts b/token/js/test/e2e/multisig.test.ts deleted file mode 100644 index 239700dfaf5..00000000000 --- a/token/js/test/e2e/multisig.test.ts +++ /dev/null @@ -1,120 +0,0 @@ -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -chai.use(chaiAsPromised); - -import { Connection, Keypair, PublicKey, Signer } from '@solana/web3.js'; - -import { - AuthorityType, - createMint, - createAccount, - getAccount, - mintTo, - transfer, - approve, - getMultisig, - createMultisig, - setAuthority, -} from '../../src'; - -import { TEST_PROGRAM_ID, newAccountWithLamports, getConnection } from '../common'; - -const TEST_TOKEN_DECIMALS = 2; -const M = 2; -const N = 5; -describe('multisig', () => { - let connection: Connection; - let payer: Signer; - let mint: PublicKey; - let mintAuthority: Keypair; - let account1: PublicKey; - let account2: PublicKey; - let amount: bigint; - let multisig: PublicKey; - let signers: Keypair[]; - let signerPublicKeys: PublicKey[]; - before(async () => { - connection = await getConnection(); - payer = await newAccountWithLamports(connection, 1000000000); - mintAuthority = Keypair.generate(); - const mintKeypair = Keypair.generate(); - signers = []; - signerPublicKeys = []; - for (let i = 0; i < N; ++i) { - const signer = Keypair.generate(); - signers.push(signer); - signerPublicKeys.push(signer.publicKey); - } - mint = await createMint( - connection, - payer, - mintAuthority.publicKey, - mintAuthority.publicKey, - TEST_TOKEN_DECIMALS, - mintKeypair, - undefined, - TEST_PROGRAM_ID - ); - }); - beforeEach(async () => { - multisig = await createMultisig(connection, payer, signerPublicKeys, M, undefined, undefined, TEST_PROGRAM_ID); - account1 = await createAccount( - connection, - payer, - mint, - multisig, - Keypair.generate(), - undefined, - TEST_PROGRAM_ID - ); - account2 = await createAccount( - connection, - payer, - mint, - multisig, - Keypair.generate(), - undefined, - TEST_PROGRAM_ID - ); - amount = BigInt(1000); - await mintTo(connection, payer, mint, account1, mintAuthority, amount, [], undefined, TEST_PROGRAM_ID); - }); - it('create', async () => { - const multisigInfo = await getMultisig(connection, multisig, undefined, TEST_PROGRAM_ID); - expect(multisigInfo.m).to.eql(M); - expect(multisigInfo.n).to.eql(N); - expect(multisigInfo.signer1).to.eql(signerPublicKeys[0]); - expect(multisigInfo.signer2).to.eql(signerPublicKeys[1]); - expect(multisigInfo.signer3).to.eql(signerPublicKeys[2]); - expect(multisigInfo.signer4).to.eql(signerPublicKeys[3]); - expect(multisigInfo.signer5).to.eql(signerPublicKeys[4]); - }); - it('transfer', async () => { - await transfer(connection, payer, account1, account2, multisig, amount, signers, undefined, TEST_PROGRAM_ID); - const accountInfo = await getAccount(connection, account2, undefined, TEST_PROGRAM_ID); - expect(accountInfo.amount).to.eql(amount); - }); - it('approve', async () => { - const delegate = Keypair.generate().publicKey; - await approve(connection, payer, account1, delegate, multisig, amount, signers, undefined, TEST_PROGRAM_ID); - const approvedAccountInfo = await getAccount(connection, account1, undefined, TEST_PROGRAM_ID); - expect(approvedAccountInfo.delegatedAmount).to.eql(amount); - expect(approvedAccountInfo.delegate).to.eql(delegate); - }); - it('setAuthority', async () => { - const newOwner = Keypair.generate().publicKey; - await setAuthority( - connection, - payer, - account1, - multisig, - AuthorityType.AccountOwner, - newOwner, - signers, - undefined, - TEST_PROGRAM_ID - ); - const accountInfo = await getAccount(connection, account1, undefined, TEST_PROGRAM_ID); - expect(accountInfo.owner).to.eql(newOwner); - }); -}); diff --git a/token/js/test/e2e/native.test.ts b/token/js/test/e2e/native.test.ts deleted file mode 100644 index 5661bf3e23c..00000000000 --- a/token/js/test/e2e/native.test.ts +++ /dev/null @@ -1,119 +0,0 @@ -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -chai.use(chaiAsPromised); - -import { - Connection, - Keypair, - PublicKey, - Signer, - Transaction, - SystemProgram, - sendAndConfirmTransaction, -} from '@solana/web3.js'; -import { - NATIVE_MINT, - NATIVE_MINT_2022, - TOKEN_PROGRAM_ID, - closeAccount, - getAccount, - createNativeMint, - createWrappedNativeAccount, - syncNative, -} from '../../src'; -import { TEST_PROGRAM_ID, newAccountWithLamports, getConnection } from '../common'; - -describe('native', () => { - let connection: Connection; - let payer: Signer; - let owner: Keypair; - let account: PublicKey; - let amount: number; - let nativeMint: PublicKey; - before(async () => { - amount = 1_000_000_000; - connection = await getConnection(); - payer = await newAccountWithLamports(connection, 100_000_000_000); - if (TEST_PROGRAM_ID == TOKEN_PROGRAM_ID) { - nativeMint = NATIVE_MINT; - } else { - nativeMint = NATIVE_MINT_2022; - await createNativeMint(connection, payer, undefined, nativeMint, TEST_PROGRAM_ID); - } - }); - beforeEach(async () => { - owner = Keypair.generate(); - account = await createWrappedNativeAccount( - connection, - payer, - owner.publicKey, - amount, - undefined, - undefined, - TEST_PROGRAM_ID, - nativeMint - ); - }); - it('works', async () => { - const accountInfo = await getAccount(connection, account, undefined, TEST_PROGRAM_ID); - expect(accountInfo.isNative).to.be.true; - expect(accountInfo.amount).to.eql(BigInt(amount)); - }); - it('syncNative', async () => { - let balance = 0; - const preInfo = await connection.getAccountInfo(account); - expect(preInfo).to.not.be.null; - if (preInfo != null) { - balance = preInfo.lamports; - } - - // transfer lamports into the native account - const additionalLamports = 100; - await sendAndConfirmTransaction( - connection, - new Transaction().add( - SystemProgram.transfer({ - fromPubkey: payer.publicKey, - toPubkey: account, - lamports: additionalLamports, - }) - ), - [payer] - ); - - // no change in the amount - const preAccountInfo = await getAccount(connection, account, undefined, TEST_PROGRAM_ID); - expect(preAccountInfo.isNative).to.be.true; - expect(preAccountInfo.amount).to.eql(BigInt(amount)); - - // but change in lamports - const postInfo = await connection.getAccountInfo(account); - expect(postInfo).to.not.be.null; - if (postInfo !== null) { - expect(postInfo.lamports).to.eql(balance + additionalLamports); - } - - // sync, amount changes - await syncNative(connection, payer, account, undefined, TEST_PROGRAM_ID); - const postAccountInfo = await getAccount(connection, account, undefined, TEST_PROGRAM_ID); - expect(postAccountInfo.isNative).to.be.true; - expect(postAccountInfo.amount).to.eql(BigInt(amount + additionalLamports)); - }); - it('closeAccount', async () => { - let balance = 0; - const preInfo = await connection.getAccountInfo(account); - expect(preInfo).to.not.be.null; - if (preInfo != null) { - balance = preInfo.lamports; - } - const destination = Keypair.generate().publicKey; - await closeAccount(connection, payer, account, destination, owner, [], undefined, TEST_PROGRAM_ID); - const nullInfo = await connection.getAccountInfo(account); - expect(nullInfo).to.be.null; - const destinationInfo = await connection.getAccountInfo(destination); - expect(destinationInfo).to.not.be.null; - if (destinationInfo != null) { - expect(destinationInfo.lamports).to.eql(balance); - } - }); -}); diff --git a/token/js/test/e2e/setAuthority.test.ts b/token/js/test/e2e/setAuthority.test.ts deleted file mode 100644 index 50f7745f6fa..00000000000 --- a/token/js/test/e2e/setAuthority.test.ts +++ /dev/null @@ -1,118 +0,0 @@ -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -chai.use(chaiAsPromised); - -import { Connection, Keypair, PublicKey, Signer } from '@solana/web3.js'; - -import { AuthorityType, createMint, createAccount, getAccount, getMint, setAuthority } from '../../src'; - -import { TEST_PROGRAM_ID, newAccountWithLamports, getConnection } from '../common'; - -const TEST_TOKEN_DECIMALS = 2; -describe('setAuthority', () => { - let connection: Connection; - let payer: Signer; - let mint: PublicKey; - let mintAuthority: Keypair; - let owner: Keypair; - let account: PublicKey; - before(async () => { - connection = await getConnection(); - payer = await newAccountWithLamports(connection, 1000000000); - mintAuthority = Keypair.generate(); - const mintKeypair = Keypair.generate(); - mint = await createMint( - connection, - payer, - mintAuthority.publicKey, - mintAuthority.publicKey, - TEST_TOKEN_DECIMALS, - mintKeypair, - undefined, - TEST_PROGRAM_ID - ); - }); - beforeEach(async () => { - owner = Keypair.generate(); - account = await createAccount( - connection, - payer, - mint, - owner.publicKey, - Keypair.generate(), - undefined, - TEST_PROGRAM_ID - ); - }); - it('AccountOwner', async () => { - const newOwner = Keypair.generate(); - await setAuthority( - connection, - payer, - account, - owner, - AuthorityType.AccountOwner, - newOwner.publicKey, - [], - undefined, - TEST_PROGRAM_ID - ); - const accountInfo = await getAccount(connection, account, undefined, TEST_PROGRAM_ID); - expect(accountInfo.owner).to.eql(newOwner.publicKey); - await setAuthority( - connection, - payer, - account, - newOwner, - AuthorityType.AccountOwner, - owner.publicKey, - [], - undefined, - TEST_PROGRAM_ID - ); - expect( - setAuthority( - connection, - payer, - account, - newOwner, - AuthorityType.AccountOwner, - owner.publicKey, - [], - undefined, - TEST_PROGRAM_ID - ) - ).to.be.rejected; - }); - it('MintAuthority', async () => { - await setAuthority( - connection, - payer, - mint, - mintAuthority, - AuthorityType.MintTokens, - null, - [], - undefined, - TEST_PROGRAM_ID - ); - const mintInfo = await getMint(connection, mint, undefined, TEST_PROGRAM_ID); - expect(mintInfo.mintAuthority).to.be.null; - }); - it('CloseAuthority', async () => { - const closeAuthority = Keypair.generate(); - await setAuthority( - connection, - payer, - account, - owner, - AuthorityType.CloseAccount, - closeAuthority.publicKey, - [], - undefined, - TEST_PROGRAM_ID - ); - const accountInfo = await getAccount(connection, account, undefined, TEST_PROGRAM_ID); - expect(accountInfo.closeAuthority).to.eql(closeAuthority.publicKey); - }); -}); diff --git a/token/js/test/e2e/transfer.test.ts b/token/js/test/e2e/transfer.test.ts deleted file mode 100644 index 03c93d04f97..00000000000 --- a/token/js/test/e2e/transfer.test.ts +++ /dev/null @@ -1,164 +0,0 @@ -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -chai.use(chaiAsPromised); - -import { Connection, Keypair, PublicKey, Signer } from '@solana/web3.js'; - -import { - createMint, - createAccount, - getAccount, - mintTo, - transfer, - transferChecked, - approve, - approveChecked, - revoke, -} from '../../src'; - -import { TEST_PROGRAM_ID, newAccountWithLamports, getConnection } from '../common'; - -const TEST_TOKEN_DECIMALS = 2; -describe('transfer', () => { - let connection: Connection; - let payer: Signer; - let mint: PublicKey; - let mintAuthority: Keypair; - let owner1: Keypair; - let account1: PublicKey; - let owner2: Keypair; - let account2: PublicKey; - let amount: bigint; - before(async () => { - connection = await getConnection(); - payer = await newAccountWithLamports(connection, 1000000000); - mintAuthority = Keypair.generate(); - const mintKeypair = Keypair.generate(); - mint = await createMint( - connection, - payer, - mintAuthority.publicKey, - mintAuthority.publicKey, - TEST_TOKEN_DECIMALS, - mintKeypair, - undefined, - TEST_PROGRAM_ID - ); - }); - beforeEach(async () => { - owner1 = Keypair.generate(); - account1 = await createAccount( - connection, - payer, - mint, - owner1.publicKey, - undefined, - undefined, - TEST_PROGRAM_ID - ); - owner2 = Keypair.generate(); - account2 = await createAccount( - connection, - payer, - mint, - owner2.publicKey, - undefined, - undefined, - TEST_PROGRAM_ID - ); - amount = BigInt(1000); - await mintTo(connection, payer, mint, account1, mintAuthority, amount, [], undefined, TEST_PROGRAM_ID); - }); - it('transfer', async () => { - await transfer(connection, payer, account1, account2, owner1, amount, [], undefined, TEST_PROGRAM_ID); - - const destAccountInfo = await getAccount(connection, account2, undefined, TEST_PROGRAM_ID); - expect(destAccountInfo.amount).to.eql(amount); - - const sourceAccountInfo = await getAccount(connection, account1, undefined, TEST_PROGRAM_ID); - expect(sourceAccountInfo.amount).to.eql(BigInt(0)); - }); - it('transferChecked', async () => { - const transferAmount = amount / BigInt(2); - await transferChecked( - connection, - payer, - account1, - mint, - account2, - owner1, - transferAmount, - TEST_TOKEN_DECIMALS, - [], - undefined, - TEST_PROGRAM_ID - ); - - const destAccountInfo = await getAccount(connection, account2, undefined, TEST_PROGRAM_ID); - expect(destAccountInfo.amount).to.eql(transferAmount); - - const sourceAccountInfo = await getAccount(connection, account1, undefined, TEST_PROGRAM_ID); - expect(sourceAccountInfo.amount).to.eql(transferAmount); - expect( - transferChecked( - connection, - payer, - account1, - mint, - account2, - owner1, - transferAmount, - TEST_TOKEN_DECIMALS - 1, - [], - undefined, - TEST_PROGRAM_ID - ) - ).to.be.rejected; - }); - it('approveRevoke', async () => { - const delegate = Keypair.generate(); - const delegatedAmount = amount / BigInt(2); - await approve( - connection, - payer, - account1, - delegate.publicKey, - owner1, - delegatedAmount, - [], - undefined, - TEST_PROGRAM_ID - ); - const approvedAccountInfo = await getAccount(connection, account1, undefined, TEST_PROGRAM_ID); - expect(approvedAccountInfo.delegatedAmount).to.eql(delegatedAmount); - expect(approvedAccountInfo.delegate).to.eql(delegate.publicKey); - await revoke(connection, payer, account1, owner1, [], undefined, TEST_PROGRAM_ID); - const revokedAccountInfo = await getAccount(connection, account1, undefined, TEST_PROGRAM_ID); - expect(revokedAccountInfo.delegatedAmount).to.eql(BigInt(0)); - expect(revokedAccountInfo.delegate).to.be.null; - }); - it('delegateTransfer', async () => { - const delegate = Keypair.generate(); - const delegatedAmount = amount / BigInt(2); - await approveChecked( - connection, - payer, - mint, - account1, - delegate.publicKey, - owner1, - delegatedAmount, - TEST_TOKEN_DECIMALS, - [], - undefined, - TEST_PROGRAM_ID - ); - const transferAmount = delegatedAmount - BigInt(1); - await transfer(connection, payer, account1, account2, delegate, transferAmount, [], undefined, TEST_PROGRAM_ID); - const accountInfo = await getAccount(connection, account1, undefined, TEST_PROGRAM_ID); - expect(accountInfo.delegatedAmount).to.eql(delegatedAmount - transferAmount); - expect(accountInfo.delegate).to.eql(delegate.publicKey); - expect(transfer(connection, payer, account1, account2, delegate, BigInt(2), [], undefined, TEST_PROGRAM_ID)).to - .be.rejected; - }); -}); diff --git a/token/js/test/unit/decode.test.ts b/token/js/test/unit/decode.test.ts deleted file mode 100644 index baef5e66c5d..00000000000 --- a/token/js/test/unit/decode.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Keypair } from '@solana/web3.js'; -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import { createInitializeMintCloseAuthorityInstruction, TOKEN_2022_PROGRAM_ID } from '../../src'; - -chai.use(chaiAsPromised); - -describe('spl-token-2022 instructions', () => { - it('InitializeMintCloseAuthority', () => { - const ix = createInitializeMintCloseAuthorityInstruction( - Keypair.generate().publicKey, - Keypair.generate().publicKey, - TOKEN_2022_PROGRAM_ID - ); - expect(ix.programId).to.eql(TOKEN_2022_PROGRAM_ID); - expect(ix.keys).to.have.length(1); - }); -}); diff --git a/token/js/test/unit/index.test.ts b/token/js/test/unit/index.test.ts deleted file mode 100644 index f49b96a75ba..00000000000 --- a/token/js/test/unit/index.test.ts +++ /dev/null @@ -1,188 +0,0 @@ -import { Keypair, PublicKey } from '@solana/web3.js'; -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import { - ASSOCIATED_TOKEN_PROGRAM_ID, - createAssociatedTokenAccountInstruction, - createInitializeMintInstruction, - createSyncNativeInstruction, - createTransferCheckedInstruction, - getAssociatedTokenAddress, - TOKEN_PROGRAM_ID, - TOKEN_2022_PROGRAM_ID, - TokenOwnerOffCurveError, - getAccountLen, - ExtensionType, - getAssociatedTokenAddressSync, - createInitializeAccount2Instruction, - createInitializeAccount3Instruction, -} from '../../src'; - -chai.use(chaiAsPromised); - -describe('spl-token instructions', () => { - it('TransferChecked', () => { - const ix = createTransferCheckedInstruction( - Keypair.generate().publicKey, - Keypair.generate().publicKey, - Keypair.generate().publicKey, - Keypair.generate().publicKey, - 1, - 9 - ); - expect(ix.programId).to.eql(TOKEN_PROGRAM_ID); - expect(ix.keys).to.have.length(4); - }); - - it('InitializeMint', () => { - const ix = createInitializeMintInstruction(Keypair.generate().publicKey, 9, Keypair.generate().publicKey, null); - expect(ix.programId).to.eql(TOKEN_PROGRAM_ID); - expect(ix.keys).to.have.length(2); - }); - - it('SyncNative', () => { - const ix = createSyncNativeInstruction(Keypair.generate().publicKey); - expect(ix.programId).to.eql(TOKEN_PROGRAM_ID); - expect(ix.keys).to.have.length(1); - }); - - it('InitializeAccount2', () => { - const ix = createInitializeAccount2Instruction( - Keypair.generate().publicKey, - Keypair.generate().publicKey, - Keypair.generate().publicKey - ); - expect(ix.programId).to.eql(TOKEN_PROGRAM_ID); - expect(ix.keys).to.have.length(3); - }); - - it('InitializeAccount3', () => { - const ix = createInitializeAccount3Instruction( - Keypair.generate().publicKey, - Keypair.generate().publicKey, - Keypair.generate().publicKey - ); - expect(ix.programId).to.eql(TOKEN_PROGRAM_ID); - expect(ix.keys).to.have.length(2); - }); -}); - -describe('spl-token-2022 instructions', () => { - it('TransferChecked', () => { - const ix = createTransferCheckedInstruction( - Keypair.generate().publicKey, - Keypair.generate().publicKey, - Keypair.generate().publicKey, - Keypair.generate().publicKey, - 1, - 9, - [], - TOKEN_2022_PROGRAM_ID - ); - expect(ix.programId).to.eql(TOKEN_2022_PROGRAM_ID); - expect(ix.keys).to.have.length(4); - }); - - it('InitializeMint', () => { - const ix = createInitializeMintInstruction( - Keypair.generate().publicKey, - 9, - Keypair.generate().publicKey, - null, - TOKEN_2022_PROGRAM_ID - ); - expect(ix.programId).to.eql(TOKEN_2022_PROGRAM_ID); - expect(ix.keys).to.have.length(2); - }); - - it('SyncNative', () => { - const ix = createSyncNativeInstruction(Keypair.generate().publicKey, TOKEN_2022_PROGRAM_ID); - expect(ix.programId).to.eql(TOKEN_2022_PROGRAM_ID); - expect(ix.keys).to.have.length(1); - }); -}); - -describe('spl-associated-token-account instructions', () => { - it('create', () => { - const ix = createAssociatedTokenAccountInstruction( - Keypair.generate().publicKey, - Keypair.generate().publicKey, - Keypair.generate().publicKey, - Keypair.generate().publicKey - ); - expect(ix.programId).to.eql(ASSOCIATED_TOKEN_PROGRAM_ID); - expect(ix.keys).to.have.length(7); - }); -}); - -describe('state', () => { - it('getAssociatedTokenAddress', async () => { - const associatedPublicKey = await getAssociatedTokenAddress( - new PublicKey('7o36UsWR1JQLpZ9PE2gn9L4SQ69CNNiWAXd4Jt7rqz9Z'), - new PublicKey('B8UwBUUnKwCyKuGMbFKWaG7exYdDk2ozZrPg72NyVbfj') - ); - expect(associatedPublicKey.toString()).to.eql( - new PublicKey('DShWnroshVbeUp28oopA3Pu7oFPDBtC1DBmPECXXAQ9n').toString() - ); - await expect( - getAssociatedTokenAddress( - new PublicKey('7o36UsWR1JQLpZ9PE2gn9L4SQ69CNNiWAXd4Jt7rqz9Z'), - associatedPublicKey - ) - ).to.be.rejectedWith(TokenOwnerOffCurveError); - - const associatedPublicKey2 = await getAssociatedTokenAddress( - new PublicKey('7o36UsWR1JQLpZ9PE2gn9L4SQ69CNNiWAXd4Jt7rqz9Z'), - associatedPublicKey, - true - ); - expect(associatedPublicKey2.toString()).to.eql( - new PublicKey('F3DmXZFqkfEWFA7MN2vDPs813GeEWPaT6nLk4PSGuWJd').toString() - ); - }); - - it('getAssociatedTokenAddressSync matches getAssociatedTokenAddress', async () => { - const asyncAssociatedPublicKey = await getAssociatedTokenAddress( - new PublicKey('7o36UsWR1JQLpZ9PE2gn9L4SQ69CNNiWAXd4Jt7rqz9Z'), - new PublicKey('B8UwBUUnKwCyKuGMbFKWaG7exYdDk2ozZrPg72NyVbfj') - ); - const associatedPublicKey = getAssociatedTokenAddressSync( - new PublicKey('7o36UsWR1JQLpZ9PE2gn9L4SQ69CNNiWAXd4Jt7rqz9Z'), - new PublicKey('B8UwBUUnKwCyKuGMbFKWaG7exYdDk2ozZrPg72NyVbfj') - ); - expect(associatedPublicKey.toString()).to.eql( - new PublicKey('DShWnroshVbeUp28oopA3Pu7oFPDBtC1DBmPECXXAQ9n').toString() - ); - expect(asyncAssociatedPublicKey.toString()).to.eql(associatedPublicKey.toString()); - - expect(function () { - getAssociatedTokenAddressSync( - new PublicKey('7o36UsWR1JQLpZ9PE2gn9L4SQ69CNNiWAXd4Jt7rqz9Z'), - associatedPublicKey - ); - }).to.throw(TokenOwnerOffCurveError); - - const asyncAssociatedPublicKey2 = await getAssociatedTokenAddress( - new PublicKey('7o36UsWR1JQLpZ9PE2gn9L4SQ69CNNiWAXd4Jt7rqz9Z'), - asyncAssociatedPublicKey, - true - ); - const associatedPublicKey2 = getAssociatedTokenAddressSync( - new PublicKey('7o36UsWR1JQLpZ9PE2gn9L4SQ69CNNiWAXd4Jt7rqz9Z'), - associatedPublicKey, - true - ); - expect(associatedPublicKey2.toString()).to.eql( - new PublicKey('F3DmXZFqkfEWFA7MN2vDPs813GeEWPaT6nLk4PSGuWJd').toString() - ); - expect(asyncAssociatedPublicKey2.toString()).to.eql(associatedPublicKey2.toString()); - }); -}); - -describe('extensionType', () => { - it('calculates size', () => { - expect(getAccountLen([ExtensionType.MintCloseAuthority, ExtensionType.TransferFeeConfig])).to.eql(314); - expect(getAccountLen([])).to.eql(165); - expect(getAccountLen([ExtensionType.ImmutableOwner])).to.eql(170); - }); -}); diff --git a/token/js/test/unit/programId.test.ts b/token/js/test/unit/programId.test.ts deleted file mode 100644 index 34ac9dbfca1..00000000000 --- a/token/js/test/unit/programId.test.ts +++ /dev/null @@ -1,73 +0,0 @@ -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import { PublicKey } from '@solana/web3.js'; -import { - AccountState, - createCreateNativeMintInstruction, - createEnableRequiredMemoTransfersInstruction, - createInitializeNonTransferableMintInstruction, - createInitializeTransferFeeConfigInstruction, - createInitializeMintCloseAuthorityInstruction, - createInitializeDefaultAccountStateInstruction, - NATIVE_MINT, - NATIVE_MINT_2022, - TOKEN_PROGRAM_ID, - TOKEN_2022_PROGRAM_ID, - TokenUnsupportedInstructionError, -} from '../../src'; -chai.use(chaiAsPromised); - -describe('unsupported extensions in spl-token', () => { - const mint = new PublicKey('7o36UsWR1JQLpZ9PE2gn9L4SQ69CNNiWAXd4Jt7rqz9Z'); - const account = new PublicKey('7o36UsWR1JQLpZ9PE2gn9L4SQ69CNNiWAXd4Jt7rqz9Z'); - const authority = new PublicKey('7o36UsWR1JQLpZ9PE2gn9L4SQ69CNNiWAXd4Jt7rqz9Z'); - const payer = new PublicKey('7o36UsWR1JQLpZ9PE2gn9L4SQ69CNNiWAXd4Jt7rqz9Z'); - it('initializeMintCloseAuthority', () => { - expect(function () { - createInitializeMintCloseAuthorityInstruction(mint, null, TOKEN_PROGRAM_ID); - }).to.throw(TokenUnsupportedInstructionError); - expect(function () { - createInitializeMintCloseAuthorityInstruction(mint, null, TOKEN_2022_PROGRAM_ID); - }).to.not.throw(TokenUnsupportedInstructionError); - }); - it('defaultAccountState', () => { - expect(function () { - createInitializeDefaultAccountStateInstruction(mint, AccountState.Frozen, TOKEN_PROGRAM_ID); - }).to.throw(TokenUnsupportedInstructionError); - expect(function () { - createInitializeDefaultAccountStateInstruction(mint, AccountState.Frozen, TOKEN_2022_PROGRAM_ID); - }).to.not.throw(TokenUnsupportedInstructionError); - }); - it('memoTransfer', () => { - expect(function () { - createEnableRequiredMemoTransfersInstruction(account, authority, [], TOKEN_PROGRAM_ID); - }).to.throw(TokenUnsupportedInstructionError); - expect(function () { - createEnableRequiredMemoTransfersInstruction(account, authority, [], TOKEN_2022_PROGRAM_ID); - }).to.not.throw(TokenUnsupportedInstructionError); - }); - it('transferFee', () => { - expect(function () { - createInitializeTransferFeeConfigInstruction(mint, null, null, 0, BigInt(0), TOKEN_PROGRAM_ID); - }).to.throw(TokenUnsupportedInstructionError); - expect(function () { - createInitializeTransferFeeConfigInstruction(mint, null, null, 0, BigInt(0), TOKEN_2022_PROGRAM_ID); - }).to.not.throw(TokenUnsupportedInstructionError); - }); - it('nativeMint', () => { - expect(function () { - createCreateNativeMintInstruction(payer, NATIVE_MINT, TOKEN_PROGRAM_ID); - }).to.throw(TokenUnsupportedInstructionError); - expect(function () { - createCreateNativeMintInstruction(payer, NATIVE_MINT_2022, TOKEN_2022_PROGRAM_ID); - }).to.not.throw(TokenUnsupportedInstructionError); - }); - it('nonTransferableMint', () => { - expect(function () { - createInitializeNonTransferableMintInstruction(mint, TOKEN_PROGRAM_ID); - }).to.throw(TokenUnsupportedInstructionError); - expect(function () { - createInitializeNonTransferableMintInstruction(mint, TOKEN_2022_PROGRAM_ID); - }).to.not.throw(TokenUnsupportedInstructionError); - }); -}); diff --git a/token/js/tsconfig.cjs.json b/token/js/tsconfig.cjs.json deleted file mode 100644 index 443b583a03d..00000000000 --- a/token/js/tsconfig.cjs.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "target": "es6", - "module": "commonjs", - "outDir": "lib/cjs", - "declarationDir": null, - "declaration": false - } -} diff --git a/token/js/tsconfig.json b/token/js/tsconfig.json deleted file mode 100644 index f06fe4da26b..00000000000 --- a/token/js/tsconfig.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "include": ["src", "types"], - "exclude": ["node_modules"], - "compilerOptions": { - "target": "es2019", - "module": "esnext", - "outDir": "lib/esm", - "declarationDir": "lib/types", - "noEmit": false, - "declaration": true, - "sourceMap": true, - "noEmitOnError": true, - "stripInternal": true, - "moduleResolution": "node", - "jsx": "react", - "strict": true, - "esModuleInterop": true, - "resolveJsonModule": true, - "isolatedModules": true, - "typeRoots": ["node_modules/@types"] - }, - "typedocOptions": { - "entryPoints": "src/index.ts", - "out": "docs", - "readme": "README.md" - } -} diff --git a/token/js/yarn.lock b/token/js/yarn.lock deleted file mode 100644 index d2844d9a9c2..00000000000 --- a/token/js/yarn.lock +++ /dev/null @@ -1,2740 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.7.tgz#03ff99f64106588c9c403c6ecb8c3bafbbdff1fa" - integrity sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ== - dependencies: - regenerator-runtime "^0.13.4" - -"@cspotcode/source-map-consumer@0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" - integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== - -"@cspotcode/source-map-support@0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5" - integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA== - dependencies: - "@cspotcode/source-map-consumer" "0.8.0" - -"@eslint/eslintrc@^1.0.5": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.0.5.tgz#33f1b838dbf1f923bfa517e008362b78ddbbf318" - integrity sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ== - dependencies: - ajv "^6.12.4" - debug "^4.3.2" - espree "^9.2.0" - globals "^13.9.0" - ignore "^4.0.6" - import-fresh "^3.2.1" - js-yaml "^4.1.0" - minimatch "^3.0.4" - strip-json-comments "^3.1.1" - -"@ethersproject/bytes@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.5.0.tgz#cb11c526de657e7b45d2e0f0246fb3b9d29a601c" - integrity sha512-ABvc7BHWhZU9PNM/tANm/Qx4ostPGadAuQzWTr3doklZOhDlmcBqclrQe/ZXUIj3K8wC28oYeuRa+A37tX9kog== - dependencies: - "@ethersproject/logger" "^5.5.0" - -"@ethersproject/logger@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.5.0.tgz#0c2caebeff98e10aefa5aef27d7441c7fd18cf5d" - integrity sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg== - -"@ethersproject/sha2@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.5.0.tgz#a40a054c61f98fd9eee99af2c3cc6ff57ec24db7" - integrity sha512-B5UBoglbCiHamRVPLA110J+2uqsifpZaTmid2/7W5rbtYVz6gus6/hSDieIU/6gaKIDcOj12WnOdiymEUHIAOA== - dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - hash.js "1.1.7" - -"@hapi/hoek@^9.0.0": - version "9.2.1" - resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.2.1.tgz#9551142a1980503752536b5050fd99f4a7f13b17" - integrity sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw== - -"@hapi/topo@^5.0.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012" - integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== - dependencies: - "@hapi/hoek" "^9.0.0" - -"@humanwhocodes/config-array@^0.9.2": - version "0.9.2" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.2.tgz#68be55c737023009dfc5fe245d51181bb6476914" - integrity sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA== - dependencies: - "@humanwhocodes/object-schema" "^1.2.1" - debug "^4.1.1" - minimatch "^3.0.4" - -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== - -"@kristoferbaxter/estree-walker@2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@kristoferbaxter/estree-walker/-/estree-walker-2.0.2.tgz#a448a7b298a42c87502c8ab53038d7c0ad2a73a2" - integrity sha512-aPFon+UXJ0758piFg/sp0tKr67675UWR9ssa39gN0ynJAY5wDQ8u57H0Z0uaeu0z1gEvLnLF8T1/rLrCZ4gFIg== - -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - -"@nodelib/fs.walk@^1.2.3": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - -"@sideway/address@^4.1.3": - version "4.1.3" - resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.3.tgz#d93cce5d45c5daec92ad76db492cc2ee3c64ab27" - integrity sha512-8ncEUtmnTsMmL7z1YPB47kPUq7LpKWJNFPsRzHiIajGC5uXlWGn+AmkYPcHNl8S4tcEGx+cnORnNYaw2wvL+LQ== - dependencies: - "@hapi/hoek" "^9.0.0" - -"@sideway/formula@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.0.tgz#fe158aee32e6bd5de85044be615bc08478a0a13c" - integrity sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg== - -"@sideway/pinpoint@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" - integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== - -"@solana/buffer-layout-utils@^0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz#b45a6cab3293a2eb7597cceb474f229889d875ca" - integrity sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g== - dependencies: - "@solana/buffer-layout" "^4.0.0" - "@solana/web3.js" "^1.32.0" - bigint-buffer "^1.1.5" - bignumber.js "^9.0.1" - -"@solana/buffer-layout@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-4.0.0.tgz#75b1b11adc487234821c81dfae3119b73a5fd734" - integrity sha512-lR0EMP2HC3+Mxwd4YcnZb0smnaDw7Bl2IQWZiTevRH5ZZBZn6VRWn3/92E3qdU4SSImJkA6IDHawOHAnx/qUvQ== - dependencies: - buffer "~6.0.3" - -"@solana/spl-memo@^0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@solana/spl-memo/-/spl-memo-0.1.0.tgz#2578a48da5184b306195bef0d658dec532b46c74" - integrity sha512-2Ob89TYXVkLXsdRIsVh9H/9rJrVXpOTapn/f/32n5/B8JRaSRBcVBLIAgAwSjMH1oJdBlmBO0lt8+cbWBrRLuA== - dependencies: - "@solana/web3.js" "^1.41.0" - buffer "^6.0.3" - -"@solana/web3.js@^1.32.0", "@solana/web3.js@^1.41.0": - version "1.41.10" - resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.41.10.tgz#fb1bf7d8ca25f126a2166fed1733fe357298a076" - integrity sha512-2mPNoxGDt5jZ4MYA+aK7qKzvdXdN0niy7suYfkbrcgAWahJ/WSfPD2W0IvySDdLLfCQojSs7sdHIW+xsKV9dyQ== - dependencies: - "@babel/runtime" "^7.12.5" - "@ethersproject/sha2" "^5.5.0" - "@solana/buffer-layout" "^4.0.0" - "@solana/buffer-layout-utils" "^0.2.0" - bn.js "^5.0.0" - borsh "^0.7.0" - bs58 "^4.0.1" - buffer "6.0.1" - cross-fetch "^3.1.4" - fast-stable-stringify "^1.0.0" - jayson "^3.4.4" - js-sha3 "^0.8.0" - rpc-websockets "^7.4.2" - secp256k1 "^4.0.2" - superstruct "^0.14.2" - tweetnacl "^1.0.0" - -"@tsconfig/node10@^1.0.7": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" - integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg== - -"@tsconfig/node12@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" - integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw== - -"@tsconfig/node14@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" - integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== - -"@tsconfig/node16@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" - integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== - -"@types/chai-as-promised@^7.1.4": - version "7.1.4" - resolved "https://registry.yarnpkg.com/@types/chai-as-promised/-/chai-as-promised-7.1.4.tgz#caf64e76fb056b8c8ced4b761ed499272b737601" - integrity sha512-1y3L1cHePcIm5vXkh1DSGf/zQq5n5xDKG1fpCvf18+uOkpce0Z1ozNFPkyWsVswK7ntN1sZBw3oU6gmN+pDUcA== - dependencies: - "@types/chai" "*" - -"@types/chai@*": - version "4.3.0" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.0.tgz#23509ebc1fa32f1b4d50d6a66c4032d5b8eaabdc" - integrity sha512-/ceqdqeRraGolFTcfoXNiqjyQhZzbINDngeoAq9GoHa8PPK1yNzTaxWjA6BFWp5Ua9JpXEMSS4s5i9tS0hOJtw== - -"@types/connect@^3.4.33": - version "3.4.35" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" - integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== - dependencies: - "@types/node" "*" - -"@types/eslint-plugin-prettier@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@types/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.0.tgz#451b5e1e5f148a38dc41e9c5b61d45cd2e97af2c" - integrity sha512-6/UIuz99F0IvtDez4U3bRwAmN4VKnuw10Ibblf0iZhtNbmbonMSLqs/qqsXrGIAWvjy+vXqYwOljgtLhrETSMg== - dependencies: - "@types/eslint" "*" - -"@types/eslint@*", "@types/eslint@^8.4.0": - version "8.4.0" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.0.tgz#95712d5b32fd99a0d9493c31c6197ea7471c3ba6" - integrity sha512-JUYa/5JwoqikCy7O7jKtuNe9Z4ZZt615G+1EKfaDGSNEpzaA2OwbV/G1v08Oa7fd1XzlFoSCvt9ePl9/6FyAug== - dependencies: - "@types/estree" "*" - "@types/json-schema" "*" - -"@types/estree@*": - version "0.0.50" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" - integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== - -"@types/express-serve-static-core@^4.17.9": - version "4.17.28" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz#c47def9f34ec81dc6328d0b1b5303d1ec98d86b8" - integrity sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig== - dependencies: - "@types/node" "*" - "@types/qs" "*" - "@types/range-parser" "*" - -"@types/json-schema@*", "@types/json-schema@^7.0.9": - version "7.0.9" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" - integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== - -"@types/lodash@^4.14.159": - version "4.14.178" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.178.tgz#341f6d2247db528d4a13ddbb374bcdc80406f4f8" - integrity sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw== - -"@types/mocha@^9.1.0": - version "9.1.0" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.0.tgz#baf17ab2cca3fcce2d322ebc30454bff487efad5" - integrity sha512-QCWHkbMv4Y5U9oW10Uxbr45qMMSzl4OzijsozynUAgx3kEHUdXB00udx2dWDQ7f2TU2a2uuiFaRZjCe3unPpeg== - -"@types/node@*": - version "17.0.10" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.10.tgz#616f16e9d3a2a3d618136b1be244315d95bd7cab" - integrity sha512-S/3xB4KzyFxYGCppyDt68yzBU9ysL88lSdIah4D6cptdcltc4NCPCAMc0+PCpg/lLIyC7IPvj2Z52OJWeIUkog== - -"@types/node@^12.12.54": - version "12.20.42" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.42.tgz#2f021733232c2130c26f9eabbdd3bfd881774733" - integrity sha512-aI3/oo5DzyiI5R/xAhxxRzfZlWlsbbqdgxfTPkqu/Zt+23GXiJvMCyPJT4+xKSXOnLqoL8jJYMLTwvK2M3a5hw== - -"@types/node@^16.11.21": - version "16.11.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.21.tgz#474d7589a30afcf5291f59bd49cca9ad171ffde4" - integrity sha512-Pf8M1XD9i1ksZEcCP8vuSNwooJ/bZapNmIzpmsMaL+jMI+8mEYU3PKvs+xDNuQcJWF/x24WzY4qxLtB0zNow9A== - -"@types/prettier@^2.4.3": - version "2.4.3" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.4.3.tgz#a3c65525b91fca7da00ab1a3ac2b5a2a4afbffbf" - integrity sha512-QzSuZMBuG5u8HqYz01qtMdg/Jfctlnvj1z/lYnIDXs/golxw0fxtRAHd9KrzjR7Yxz1qVeI00o0kiO3PmVdJ9w== - -"@types/qs@*": - version "6.9.7" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" - integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== - -"@types/range-parser@*": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" - integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== - -"@types/ws@^7.4.4": - version "7.4.7" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" - integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== - dependencies: - "@types/node" "*" - -"@typescript-eslint/eslint-plugin@^5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.10.0.tgz#e90afea96dff8620892ad216b0e4ccdf8ee32d3a" - integrity sha512-XXVKnMsq2fuu9K2KsIxPUGqb6xAImz8MEChClbXmE3VbveFtBUU5bzM6IPVWqzyADIgdkS2Ws/6Xo7W2TeZWjQ== - dependencies: - "@typescript-eslint/scope-manager" "5.10.0" - "@typescript-eslint/type-utils" "5.10.0" - "@typescript-eslint/utils" "5.10.0" - debug "^4.3.2" - functional-red-black-tree "^1.0.1" - ignore "^5.1.8" - regexpp "^3.2.0" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/parser@^5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.10.0.tgz#8f59e036f5f1cffc178cacbd5ccdd02aeb96c91c" - integrity sha512-pJB2CCeHWtwOAeIxv8CHVGJhI5FNyJAIpx5Pt72YkK3QfEzt6qAlXZuyaBmyfOdM62qU0rbxJzNToPTVeJGrQw== - dependencies: - "@typescript-eslint/scope-manager" "5.10.0" - "@typescript-eslint/types" "5.10.0" - "@typescript-eslint/typescript-estree" "5.10.0" - debug "^4.3.2" - -"@typescript-eslint/scope-manager@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.10.0.tgz#bb5d872e8b9e36203908595507fbc4d3105329cb" - integrity sha512-tgNgUgb4MhqK6DoKn3RBhyZ9aJga7EQrw+2/OiDk5hKf3pTVZWyqBi7ukP+Z0iEEDMF5FDa64LqODzlfE4O/Dg== - dependencies: - "@typescript-eslint/types" "5.10.0" - "@typescript-eslint/visitor-keys" "5.10.0" - -"@typescript-eslint/type-utils@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.10.0.tgz#8524b9479c19c478347a7df216827e749e4a51e5" - integrity sha512-TzlyTmufJO5V886N+hTJBGIfnjQDQ32rJYxPaeiyWKdjsv2Ld5l8cbS7pxim4DeNs62fKzRSt8Q14Evs4JnZyQ== - dependencies: - "@typescript-eslint/utils" "5.10.0" - debug "^4.3.2" - tsutils "^3.21.0" - -"@typescript-eslint/types@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.10.0.tgz#beb3cb345076f5b088afe996d57bcd1dfddaa75c" - integrity sha512-wUljCgkqHsMZbw60IbOqT/puLfyqqD5PquGiBo1u1IS3PLxdi3RDGlyf032IJyh+eQoGhz9kzhtZa+VC4eWTlQ== - -"@typescript-eslint/typescript-estree@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.10.0.tgz#4be24a3dea0f930bb1397c46187d0efdd955a224" - integrity sha512-x+7e5IqfwLwsxTdliHRtlIYkgdtYXzE0CkFeV6ytAqq431ZyxCFzNMNR5sr3WOlIG/ihVZr9K/y71VHTF/DUQA== - dependencies: - "@typescript-eslint/types" "5.10.0" - "@typescript-eslint/visitor-keys" "5.10.0" - debug "^4.3.2" - globby "^11.0.4" - is-glob "^4.0.3" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/utils@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.10.0.tgz#c3d152a85da77c400e37281355561c72fb1b5a65" - integrity sha512-IGYwlt1CVcFoE2ueW4/ioEwybR60RAdGeiJX/iDAw0t5w0wK3S7QncDwpmsM70nKgGTuVchEWB8lwZwHqPAWRg== - dependencies: - "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.10.0" - "@typescript-eslint/types" "5.10.0" - "@typescript-eslint/typescript-estree" "5.10.0" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - -"@typescript-eslint/visitor-keys@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.10.0.tgz#770215497ad67cd15a572b52089991d5dfe06281" - integrity sha512-GMxj0K1uyrFLPKASLmZzCuSddmjZVbVj3Ouy5QVuIGKZopxvOr24JsS7gruz6C3GExE01mublZ3mIBOaon9zuQ== - dependencies: - "@typescript-eslint/types" "5.10.0" - eslint-visitor-keys "^3.0.0" - -"@ungap/promise-all-settled@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" - integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== - -JSONStream@^1.3.5: - version "1.3.5" - resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" - integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== - dependencies: - jsonparse "^1.2.0" - through ">=2.2.7 <3" - -acorn-jsx@^5.3.1: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -acorn-walk@^8.1.1: - version "8.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" - integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== - -acorn@8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.1.0.tgz#52311fd7037ae119cbb134309e901aa46295b3fe" - integrity sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA== - -acorn@^8.4.1, acorn@^8.7.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" - integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== - -ajv@^6.10.0, ajv@^6.12.4: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ansi-colors@4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -anymatch@~3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - -array-union@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= - dependencies: - array-uniq "^1.0.1" - -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -array-uniq@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= - -array.prototype.map@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/array.prototype.map/-/array.prototype.map-1.0.4.tgz#0d97b640cfdd036c1b41cfe706a5e699aa0711f2" - integrity sha512-Qds9QnX7A0qISY7JT5WuJO0NJPE9CMlC6JzHQfhpqAAQQzufVRoeH7EzUY5GcPTx72voG8LV/5eo+b8Qi8hmhA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - es-array-method-boxes-properly "^1.0.0" - is-string "^1.0.7" - -assertion-error@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" - integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== - -async@^2.6.1: - version "2.6.3" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" - integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== - dependencies: - lodash "^4.17.14" - -axios@^0.21.1: - version "0.21.4" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" - integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== - dependencies: - follow-redirects "^1.14.0" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -base-x@^3.0.2: - version "3.0.9" - resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" - integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== - dependencies: - safe-buffer "^5.0.1" - -base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -bigint-buffer@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/bigint-buffer/-/bigint-buffer-1.1.5.tgz#d038f31c8e4534c1f8d0015209bf34b4fa6dd442" - integrity sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA== - dependencies: - bindings "^1.3.0" - -bignumber.js@^9.0.1: - version "9.0.2" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.2.tgz#71c6c6bed38de64e24a65ebe16cfcf23ae693673" - integrity sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw== - -binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== - -bindings@^1.3.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - -bluebird@3.7.2: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - -bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - -bn.js@^5.0.0, bn.js@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" - integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== - -borsh@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.7.0.tgz#6e9560d719d86d90dc589bca60ffc8a6c51fec2a" - integrity sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA== - dependencies: - bn.js "^5.2.0" - bs58 "^4.0.0" - text-encoding-utf-8 "^1.0.2" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^3.0.1, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -brorand@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= - -browser-stdout@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" - integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== - -bs58@^4.0.0, bs58@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" - integrity sha1-vhYedsNU9veIrkBx9j806MTwpCo= - dependencies: - base-x "^3.0.2" - -buffer@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.1.tgz#3cbea8c1463e5a0779e30b66d4c88c6ffa182ac2" - integrity sha512-rVAXBwEcEoYtxnHSO5iWyhzV/O1WMtkUYWlfdLS7FjU4PnSJJHEfHXi/uHPI5EwltmOA794gN3bm3/pzuctWjQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - -buffer@^6.0.3, buffer@~6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - -bufferutil@^4.0.1: - version "4.0.6" - resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.6.tgz#ebd6c67c7922a0e902f053e5d8be5ec850e48433" - integrity sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw== - dependencies: - node-gyp-build "^4.3.0" - -call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -camelcase@^6.0.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" - integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== - -chai-as-promised@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-7.1.1.tgz#08645d825deb8696ee61725dbf590c012eb00ca0" - integrity sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA== - dependencies: - check-error "^1.0.2" - -chai@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.4.tgz#b55e655b31e1eac7099be4c08c21964fce2e6c49" - integrity sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA== - dependencies: - assertion-error "^1.1.0" - check-error "^1.0.2" - deep-eql "^3.0.1" - get-func-name "^2.0.0" - pathval "^1.1.1" - type-detect "^4.0.5" - -chalk@^4.0.0, chalk@^4.1.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -check-error@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" - integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= - -check-more-types@2.24.0: - version "2.24.0" - resolved "https://registry.yarnpkg.com/check-more-types/-/check-more-types-2.24.0.tgz#1420ffb10fd444dcfc79b43891bbfffd32a84600" - integrity sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA= - -chokidar@3.5.2: - version "3.5.2" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" - integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - -circular-json@^0.5.9: - version "0.5.9" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.9.tgz#932763ae88f4f7dead7a0d09c8a51a4743a53b1d" - integrity sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ== - -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -commander@^2.18.0, commander@^2.20.3: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -create-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== - -cross-fetch@^3.1.4: - version "3.1.5" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" - integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== - dependencies: - node-fetch "2.6.7" - -cross-spawn@^7.0.2, cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -debug@4.3.2: - version "4.3.2" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" - integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== - dependencies: - ms "2.1.2" - -debug@^4.1.1, debug@^4.3.2: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== - dependencies: - ms "2.1.2" - -decamelize@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" - integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== - -deep-eql@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" - integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== - dependencies: - type-detect "^4.0.0" - -deep-is@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== - -define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - -delay@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" - integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== - -diff@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" - integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== - -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -duplexer@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" - integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== - -elliptic@^6.5.4: - version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - -email-addresses@^3.0.1: - version "3.1.0" - resolved "https://registry.yarnpkg.com/email-addresses/-/email-addresses-3.1.0.tgz#cabf7e085cbdb63008a70319a74e6136188812fb" - integrity sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -es-abstract@^1.18.0-next.2, es-abstract@^1.19.0: - version "1.19.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" - integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== - dependencies: - call-bind "^1.0.2" - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - get-intrinsic "^1.1.1" - get-symbol-description "^1.0.0" - has "^1.0.3" - has-symbols "^1.0.2" - internal-slot "^1.0.3" - is-callable "^1.2.4" - is-negative-zero "^2.0.1" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.1" - is-string "^1.0.7" - is-weakref "^1.0.1" - object-inspect "^1.11.0" - object-keys "^1.1.1" - object.assign "^4.1.2" - string.prototype.trimend "^1.0.4" - string.prototype.trimstart "^1.0.4" - unbox-primitive "^1.0.1" - -es-array-method-boxes-properly@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" - integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== - -es-get-iterator@^1.0.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.2.tgz#9234c54aba713486d7ebde0220864af5e2b283f7" - integrity sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.0" - has-symbols "^1.0.1" - is-arguments "^1.1.0" - is-map "^2.0.2" - is-set "^2.0.2" - is-string "^1.0.5" - isarray "^2.0.5" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -es6-promise@^4.0.3: - version "4.2.8" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" - integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== - -es6-promisify@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" - integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= - dependencies: - es6-promise "^4.0.3" - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -escape-string-regexp@^1.0.2: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -eslint-config-prettier@^8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz#f7471b20b6fe8a9a9254cc684454202886a2dd7a" - integrity sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew== - -eslint-plugin-prettier@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz#8b99d1e4b8b24a762472b4567992023619cb98e0" - integrity sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ== - dependencies: - prettier-linter-helpers "^1.0.0" - -eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-scope@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.0.tgz#c1f6ea30ac583031f203d65c73e723b01298f153" - integrity sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg== - dependencies: - esrecurse "^4.3.0" - estraverse "^5.2.0" - -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - -eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.1.0, eslint-visitor-keys@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz#6fbb166a6798ee5991358bc2daa1ba76cc1254a1" - integrity sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ== - -eslint@^8.7.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.7.0.tgz#22e036842ee5b7cf87b03fe237731675b4d3633c" - integrity sha512-ifHYzkBGrzS2iDU7KjhCAVMGCvF6M3Xfs8X8b37cgrUlDt6bWRTpRh6T/gtSXv1HJ/BUGgmjvNvOEGu85Iif7w== - dependencies: - "@eslint/eslintrc" "^1.0.5" - "@humanwhocodes/config-array" "^0.9.2" - ajv "^6.10.0" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.3.2" - doctrine "^3.0.0" - escape-string-regexp "^4.0.0" - eslint-scope "^7.1.0" - eslint-utils "^3.0.0" - eslint-visitor-keys "^3.2.0" - espree "^9.3.0" - esquery "^1.4.0" - esutils "^2.0.2" - fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^6.0.1" - globals "^13.6.0" - ignore "^5.2.0" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - js-yaml "^4.1.0" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash.merge "^4.6.2" - minimatch "^3.0.4" - natural-compare "^1.4.0" - optionator "^0.9.1" - regexpp "^3.2.0" - strip-ansi "^6.0.1" - strip-json-comments "^3.1.0" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -espree@^9.2.0, espree@^9.3.0: - version "9.3.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.0.tgz#c1240d79183b72aaee6ccfa5a90bc9111df085a8" - integrity sha512-d/5nCsb0JcqsSEeQzFZ8DH1RmxPcglRWh24EFTlUEmCKoehXGdpsx0RkHDubqUI8LSAIKMQp4r9SzQ3n+sm4HQ== - dependencies: - acorn "^8.7.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^3.1.0" - -esquery@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -event-stream@=3.3.4: - version "3.3.4" - resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" - integrity sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE= - dependencies: - duplexer "~0.1.1" - from "~0" - map-stream "~0.1.0" - pause-stream "0.0.11" - split "0.3" - stream-combiner "~0.0.4" - through "~2.3.1" - -eventemitter3@^4.0.7: - version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" - integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== - -execa@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - -eyes@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" - integrity sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A= - -fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-diff@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" - integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== - -fast-glob@3.2.5: - version "3.2.5" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.5.tgz#7939af2a656de79a4f1901903ee8adcaa7cb9661" - integrity sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.0" - merge2 "^1.3.0" - micromatch "^4.0.2" - picomatch "^2.2.1" - -fast-glob@^3.2.9: - version "3.2.11" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" - integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -fast-stable-stringify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz#5c5543462b22aeeefd36d05b34e51c78cb86d313" - integrity sha1-XFVDRisiru79NtBbNOUceMuG0xM= - -fastq@^1.6.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" - integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== - dependencies: - reusify "^1.0.4" - -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== - dependencies: - flat-cache "^3.0.4" - -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - -filename-reserved-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229" - integrity sha1-q/c9+rc10EVECr/qLZHzieu/oik= - -filenamify@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/filenamify/-/filenamify-4.3.0.tgz#62391cb58f02b09971c9d4f9d63b3cf9aba03106" - integrity sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg== - dependencies: - filename-reserved-regex "^2.0.0" - strip-outer "^1.0.1" - trim-repeated "^1.0.0" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -find-cache-dir@^3.3.1: - version "3.3.2" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" - integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== - dependencies: - commondir "^1.0.1" - make-dir "^3.0.2" - pkg-dir "^4.1.0" - -find-up@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - -find-up@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== - dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" - -flat@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" - integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== - -flatted@^3.1.0: - version "3.2.4" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.4.tgz#28d9969ea90661b5134259f312ab6aa7929ac5e2" - integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw== - -follow-redirects@^1.14.0: - version "1.14.8" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc" - integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA== - -from@~0: - version "0.1.7" - resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" - integrity sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4= - -fs-extra@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -get-func-name@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" - integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= - -get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" - integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - -get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - -get-symbol-description@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" - integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" - -gh-pages@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/gh-pages/-/gh-pages-3.2.3.tgz#897e5f15e111f42af57d21d430b83e5cdf29472c" - integrity sha512-jA1PbapQ1jqzacECfjUaO9gV8uBgU6XNMV0oXLtfCX3haGLe5Atq8BxlrADhbD6/UdG9j6tZLWAkAybndOXTJg== - dependencies: - async "^2.6.1" - commander "^2.18.0" - email-addresses "^3.0.1" - filenamify "^4.3.0" - find-cache-dir "^3.3.1" - fs-extra "^8.1.0" - globby "^6.1.0" - -glob-parent@^5.1.0, glob-parent@^5.1.2, glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob-parent@^6.0.1: - version "6.0.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" - integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== - dependencies: - is-glob "^4.0.3" - -glob@7.1.7: - version "7.1.7" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" - integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^7.0.0, glob@^7.0.3, glob@^7.1.3, glob@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^13.6.0, globals@^13.9.0: - version "13.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.12.0.tgz#4d733760304230a0082ed96e21e5c565f898089e" - integrity sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg== - dependencies: - type-fest "^0.20.2" - -globby@^11.0.4: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" - -globby@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" - integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= - dependencies: - array-union "^1.0.1" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -graceful-fs@^4.1.6, graceful-fs@^4.2.0: - version "4.2.9" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" - integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== - -growl@1.10.5: - version "1.10.5" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" - integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== - -has-bigints@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" - integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-symbols@^1.0.1, has-symbols@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" - integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== - -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== - dependencies: - has-symbols "^1.0.2" - -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -he@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - -hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - -ieee754@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -ignore@^5.1.8, ignore@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" - integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== - -import-fresh@^3.0.0, import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@^2.0.3, inherits@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -internal-slot@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" - integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== - dependencies: - get-intrinsic "^1.1.0" - has "^1.0.3" - side-channel "^1.0.4" - -interpret@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" - integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== - -is-arguments@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" - integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== - dependencies: - has-bigints "^1.0.1" - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-callable@^1.1.4, is-callable@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" - integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== - -is-core-module@^2.8.0: - version "2.8.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" - integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== - dependencies: - has "^1.0.3" - -is-date-object@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== - dependencies: - has-tostringtag "^1.0.0" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-map@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" - integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== - -is-negative-zero@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== - -is-number-object@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" - integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== - dependencies: - has-tostringtag "^1.0.0" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-plain-obj@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" - integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== - -is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-set@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" - integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== - -is-shared-array-buffer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" - integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - -is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== - dependencies: - has-tostringtag "^1.0.0" - -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== - dependencies: - has-symbols "^1.0.2" - -is-unicode-supported@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" - integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== - -is-weakref@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" - integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== - dependencies: - call-bind "^1.0.2" - -isarray@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -isomorphic-ws@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" - integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== - -iterate-iterator@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/iterate-iterator/-/iterate-iterator-1.0.2.tgz#551b804c9eaa15b847ea6a7cdc2f5bf1ec150f91" - integrity sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw== - -iterate-value@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/iterate-value/-/iterate-value-1.0.2.tgz#935115bd37d006a52046535ebc8d07e9c9337f57" - integrity sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ== - dependencies: - es-get-iterator "^1.0.2" - iterate-iterator "^1.0.1" - -jayson@^3.4.4: - version "3.6.6" - resolved "https://registry.yarnpkg.com/jayson/-/jayson-3.6.6.tgz#189984f624e398f831bd2be8e8c80eb3abf764a1" - integrity sha512-f71uvrAWTtrwoww6MKcl9phQTC+56AopLyEenWvKVAIMz+q0oVGj6tenLZ7Z6UiPBkJtKLj4kt0tACllFQruGQ== - dependencies: - "@types/connect" "^3.4.33" - "@types/express-serve-static-core" "^4.17.9" - "@types/lodash" "^4.14.159" - "@types/node" "^12.12.54" - "@types/ws" "^7.4.4" - JSONStream "^1.3.5" - commander "^2.20.3" - delay "^5.0.0" - es6-promisify "^5.0.0" - eyes "^0.1.8" - isomorphic-ws "^4.0.1" - json-stringify-safe "^5.0.1" - lodash "^4.17.20" - uuid "^8.3.2" - ws "^7.4.5" - -joi@^17.4.0: - version "17.6.0" - resolved "https://registry.yarnpkg.com/joi/-/joi-17.6.0.tgz#0bb54f2f006c09a96e75ce687957bd04290054b2" - integrity sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw== - dependencies: - "@hapi/hoek" "^9.0.0" - "@hapi/topo" "^5.0.0" - "@sideway/address" "^4.1.3" - "@sideway/formula" "^3.0.0" - "@sideway/pinpoint" "^2.0.0" - -js-sha3@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" - integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== - -js-yaml@4.1.0, js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - -json-stringify-safe@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - -jsonc-parser@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.0.0.tgz#abdd785701c7e7eaca8a9ec8cf070ca51a745a22" - integrity sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA== - -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - -jsonparse@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" - integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= - -lazy-ass@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/lazy-ass/-/lazy-ass-1.6.0.tgz#7999655e8646c17f089fdd187d150d3324d54513" - integrity sha1-eZllXoZGwX8In90YfRUNMyTVRRM= - -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" - -locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - -lodash@^4.17.14, lodash@^4.17.20, lodash@^4.17.21: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -log-symbols@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" - integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== - dependencies: - chalk "^4.1.0" - is-unicode-supported "^0.1.0" - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -lunr@^2.3.9: - version "2.3.9" - resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1" - integrity sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow== - -magic-string@0.25.7: - version "0.25.7" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" - integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA== - dependencies: - sourcemap-codec "^1.4.4" - -make-dir@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - -make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -map-stream@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" - integrity sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ= - -marked@^4.0.10: - version "4.0.10" - resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.10.tgz#423e295385cc0c3a70fa495e0df68b007b879423" - integrity sha512-+QvuFj0nGgO970fySghXGmuw+Fd0gD2x3+MqCWLIPf5oxdv1Ka6b2q+z9RP01P/IaKPMEramy+7cNy/Lw8c3hw== - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - -merge2@^1.3.0, merge2@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -micromatch@^4.0.2, micromatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== - dependencies: - braces "^3.0.1" - picomatch "^2.2.3" - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= - -minimatch@3.0.4, minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.2.3, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -mocha@^9.1.4: - version "9.1.4" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.1.4.tgz#5a332d6ade6345b975fd97b5b39139854c8e1b32" - integrity sha512-+q2aV5VlJZuLgCWoBvGI5zEwPF9eEI0kr/sAA9Jm4xMND7RfIEyF8JE7C0JIg8WXRG+P1sdIAb5ccoHPlXLzcw== - dependencies: - "@ungap/promise-all-settled" "1.1.2" - ansi-colors "4.1.1" - browser-stdout "1.3.1" - chokidar "3.5.2" - debug "4.3.2" - diff "5.0.0" - escape-string-regexp "4.0.0" - find-up "5.0.0" - glob "7.1.7" - growl "1.10.5" - he "1.2.0" - js-yaml "4.1.0" - log-symbols "4.1.0" - minimatch "3.0.4" - ms "2.1.3" - nanoid "3.1.25" - serialize-javascript "6.0.0" - strip-json-comments "3.1.1" - supports-color "8.1.1" - which "2.0.2" - workerpool "6.1.5" - yargs "16.2.0" - yargs-parser "20.2.4" - yargs-unparser "2.0.0" - -mri@1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.6.tgz#49952e1044db21dbf90f6cd92bc9c9a777d415a6" - integrity sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ== - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -nanoid@3.1.25: - version "3.1.25" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152" - integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -node-addon-api@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" - integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== - -node-fetch@2.6.7: - version "2.6.7" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" - integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== - dependencies: - whatwg-url "^5.0.0" - -node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3" - integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q== - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - -object-assign@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -object-inspect@^1.11.0, object-inspect@^1.9.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" - integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== - -object-keys@^1.0.12, object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object.assign@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" - integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - has-symbols "^1.0.1" - object-keys "^1.1.1" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== - dependencies: - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - word-wrap "^1.2.3" - -p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-limit@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - -p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-key@^3.0.0, path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -pathval@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" - integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== - -pause-stream@0.0.11: - version "0.0.11" - resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" - integrity sha1-/lo0sMvOErWqaitAPuLnO2AvFEU= - dependencies: - through "~2.3" - -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -pify@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= - -pkg-dir@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== - dependencies: - find-up "^4.0.0" - -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== - dependencies: - fast-diff "^1.1.2" - -prettier@^2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" - integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== - -promise.allsettled@1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/promise.allsettled/-/promise.allsettled-1.0.4.tgz#65e71f2a604082ed69c548b68603294090ee6803" - integrity sha512-o73CbvQh/OnPFShxHcHxk0baXR2a1m4ozb85ha0H14VEoi/EJJLa9mnPfEWJx9RjA9MLfhdjZ8I6HhWtBa64Ag== - dependencies: - array.prototype.map "^1.0.3" - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" - get-intrinsic "^1.0.2" - iterate-value "^1.0.2" - -ps-tree@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.2.0.tgz#5e7425b89508736cdd4f2224d028f7bb3f722ebd" - integrity sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA== - dependencies: - event-stream "=3.3.4" - -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - -randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - -rechoir@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" - integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= - dependencies: - resolve "^1.1.6" - -regenerator-runtime@^0.13.4: - version "0.13.9" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" - integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== - -regexpp@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve@^1.1.6: - version "1.21.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.21.1.tgz#1a88c73f5ca8ab0aabc8b888c4170de26c92c4cc" - integrity sha512-lfEImVbnolPuaSZuLQ52cAxPBHeI77sPwCOWRdy12UG/CNa8an7oBHH1R+Fp1/mUqSJi4c8TIP6FOIPSZAUrEQ== - dependencies: - is-core-module "^2.8.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -rpc-websockets@^7.4.2: - version "7.4.16" - resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.4.16.tgz#eb701cdef577d4357ba5f526d50e25f370396fac" - integrity sha512-0b7OVhutzwRIaYAtJo5tqtaQTWKfwAsKnaThOSOy+VkhVdleNUgb8eZnWSdWITRZZEigV5uPEIDr5KZe4DBrdQ== - dependencies: - "@babel/runtime" "^7.11.2" - circular-json "^0.5.9" - eventemitter3 "^4.0.7" - uuid "^8.3.0" - ws "^7.4.5" - optionalDependencies: - bufferutil "^4.0.1" - utf-8-validate "^5.0.2" - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -rxjs@^7.1.0: - version "7.5.4" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.4.tgz#3d6bd407e6b7ce9a123e76b1e770dc5761aa368d" - integrity sha512-h5M3Hk78r6wAheJF0a5YahB1yRQKCsZ4MsGdZ5O9ETbVtjPcScGfrMmoOq7EBsCRzd4BDkvDJ7ogP8Sz5tTFiQ== - dependencies: - tslib "^2.1.0" - -safe-buffer@^5.0.1, safe-buffer@^5.1.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -secp256k1@^4.0.2: - version "4.0.3" - resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.3.tgz#c4559ecd1b8d3c1827ed2d1b94190d69ce267303" - integrity sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA== - dependencies: - elliptic "^6.5.4" - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" - -semver@^6.0.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@^7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - -serialize-javascript@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" - integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== - dependencies: - randombytes "^2.1.0" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -shelljs@^0.8.5: - version "0.8.5" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c" - integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow== - dependencies: - glob "^7.0.0" - interpret "^1.0.0" - rechoir "^0.6.2" - -shiki@^0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.10.0.tgz#85f21ecfa95b377ff64db6c71442c22c220e9540" - integrity sha512-iczxaIYeBFHTFrQPb9DVy2SKgYxC4Wo7Iucm7C17cCh2Ge/refnvHscUOxM85u57MfLoNOtjoEFUWt9gBexblA== - dependencies: - jsonc-parser "^3.0.0" - vscode-oniguruma "^1.6.1" - vscode-textmate "5.2.0" - -shx@^0.3.4: - version "0.3.4" - resolved "https://registry.yarnpkg.com/shx/-/shx-0.3.4.tgz#74289230b4b663979167f94e1935901406e40f02" - integrity sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g== - dependencies: - minimist "^1.2.3" - shelljs "^0.8.5" - -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== - dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" - -signal-exit@^3.0.3: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -sourcemap-codec@^1.4.4: - version "1.4.8" - resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" - integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== - -split@0.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" - integrity sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8= - dependencies: - through "2" - -start-server-and-test@^1.14.0: - version "1.14.0" - resolved "https://registry.yarnpkg.com/start-server-and-test/-/start-server-and-test-1.14.0.tgz#c57f04f73eac15dd51733b551d775b40837fdde3" - integrity sha512-on5ELuxO2K0t8EmNj9MtVlFqwBMxfWOhu4U7uZD1xccVpFlOQKR93CSe0u98iQzfNxRyaNTb/CdadbNllplTsw== - dependencies: - bluebird "3.7.2" - check-more-types "2.24.0" - debug "4.3.2" - execa "5.1.1" - lazy-ass "1.6.0" - ps-tree "1.2.0" - wait-on "6.0.0" - -stream-combiner@~0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" - integrity sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ= - dependencies: - duplexer "~0.1.1" - -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string.prototype.trimend@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" - integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -string.prototype.trimstart@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" - integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - -strip-json-comments@3.1.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -strip-outer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631" - integrity sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg== - dependencies: - escape-string-regexp "^1.0.2" - -superstruct@^0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.14.2.tgz#0dbcdf3d83676588828f1cf5ed35cda02f59025b" - integrity sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ== - -supports-color@8.1.1: - version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - -text-encoding-utf-8@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz#585b62197b0ae437e3c7b5d0af27ac1021e10d13" - integrity sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg== - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -through@2, "through@>=2.2.7 <3", through@~2.3, through@~2.3.1: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= - -trim-repeated@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21" - integrity sha1-42RqLqTokTEr9+rObPsFOAvAHCE= - dependencies: - escape-string-regexp "^1.0.2" - -ts-node@^10.4.0: - version "10.4.0" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.4.0.tgz#680f88945885f4e6cf450e7f0d6223dd404895f7" - integrity sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A== - dependencies: - "@cspotcode/source-map-support" "0.7.0" - "@tsconfig/node10" "^1.0.7" - "@tsconfig/node12" "^1.0.7" - "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.2" - acorn "^8.4.1" - acorn-walk "^8.1.1" - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - yn "3.1.1" - -tslib@^1.8.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tslib@^2.1.0, tslib@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" - integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== - -tsutils@^3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - -tweetnacl@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" - integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== - -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - -type-detect@^4.0.0, type-detect@^4.0.5: - version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== - -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - -typedoc@^0.22.11: - version "0.22.11" - resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.22.11.tgz#a3d7f4577eef9fc82dd2e8f4e2915e69f884c250" - integrity sha512-pVr3hh6dkS3lPPaZz1fNpvcrqLdtEvXmXayN55czlamSgvEjh+57GUqfhAI1Xsuu/hNHUT1KNSx8LH2wBP/7SA== - dependencies: - glob "^7.2.0" - lunr "^2.3.9" - marked "^4.0.10" - minimatch "^3.0.4" - shiki "^0.10.0" - -typescript-esm@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/typescript-esm/-/typescript-esm-2.0.0.tgz#07857699d339e28f2fc88e1fafd6a855170e39f6" - integrity sha512-/dERe64gRgZ3pSzP6Lc2DNiCdVPz1+mVlbkV9cl9eDunAqfelZHRA8MRTqEJLK6u6Adc6Z8Yy1lQY4nWUIh/5A== - dependencies: - "@kristoferbaxter/estree-walker" "2.0.2" - acorn "8.1.0" - fast-glob "3.2.5" - magic-string "0.25.7" - mri "1.1.6" - promise.allsettled "1.0.4" - typescript "4.2.3" - -typescript@4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.3.tgz#39062d8019912d43726298f09493d598048c1ce3" - integrity sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw== - -typescript@^4.5.5: - version "4.5.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3" - integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA== - -unbox-primitive@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" - integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== - dependencies: - function-bind "^1.1.1" - has-bigints "^1.0.1" - has-symbols "^1.0.2" - which-boxed-primitive "^1.0.2" - -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -utf-8-validate@^5.0.2: - version "5.0.8" - resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.8.tgz#4a735a61661dbb1c59a0868c397d2fe263f14e58" - integrity sha512-k4dW/Qja1BYDl2qD4tOMB9PFVha/UJtxTc1cXYOe3WwA/2m0Yn4qB7wLMpJyLJ/7DR0XnTut3HsCSzDT4ZvKgA== - dependencies: - node-gyp-build "^4.3.0" - -uuid@^8.3.0, uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - -v8-compile-cache@^2.0.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== - -vscode-oniguruma@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.6.1.tgz#2bf4dfcfe3dd2e56eb549a3068c8ee39e6c30ce5" - integrity sha512-vc4WhSIaVpgJ0jJIejjYxPvURJavX6QG41vu0mGhqywMkQqulezEqEQ3cO3gc8GvcOpX6ycmKGqRoROEMBNXTQ== - -vscode-textmate@5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.2.0.tgz#01f01760a391e8222fe4f33fbccbd1ad71aed74e" - integrity sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ== - -wait-on@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-6.0.0.tgz#7e9bf8e3d7fe2daecbb7a570ac8ca41e9311c7e7" - integrity sha512-tnUJr9p5r+bEYXPUdRseolmz5XqJTTj98JgOsfBn7Oz2dxfE2g3zw1jE+Mo8lopM3j3et/Mq1yW7kKX6qw7RVw== - dependencies: - axios "^0.21.1" - joi "^17.4.0" - lodash "^4.17.21" - minimist "^1.2.5" - rxjs "^7.1.0" - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - -which@2.0.2, which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -word-wrap@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - -workerpool@6.1.5: - version "6.1.5" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.1.5.tgz#0f7cf076b6215fd7e1da903ff6f22ddd1886b581" - integrity sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw== - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -ws@^7.4.5: - version "7.5.6" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.6.tgz#e59fc509fb15ddfb65487ee9765c5a51dec5fe7b" - integrity sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA== - -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yargs-parser@20.2.4: - version "20.2.4" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" - integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== - -yargs-parser@^20.2.2: - version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - -yargs-unparser@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" - integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== - dependencies: - camelcase "^6.0.0" - decamelize "^4.0.0" - flat "^5.0.2" - is-plain-obj "^2.1.0" - -yargs@16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - -yn@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== - -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/token/program-2022-test/Cargo.toml b/token/program-2022-test/Cargo.toml deleted file mode 100644 index 809fa6517b6..00000000000 --- a/token/program-2022-test/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -authors = ["Solana Maintainers "] -description = "SPL-Token 2022 Integration Tests" -edition = "2018" -license = "Apache-2.0" -name = "spl-token-2022-test" -repository = "https://github.com/solana-labs/solana-program-library" -version = "0.0.1" - -[features] -test-bpf = [] - -[build-dependencies] -walkdir = "2" - -[dev-dependencies] -async-trait = "0.1" -solana-program = "=1.10.33" -solana-program-test = "=1.10.33" -solana-sdk = "=1.10.33" -spl-associated-token-account = { version = "1.0.5", path = "../../associated-token-account/program" } -spl-memo = { version = "3.0.1", path = "../../memo/program", features = ["no-entrypoint"] } -spl-token-2022 = { version = "0.4", path="../program-2022", features = ["no-entrypoint"] } -spl-token-client = { version = "0.1.0", path = "../client" } diff --git a/token/program-2022-test/build.rs b/token/program-2022-test/build.rs deleted file mode 100644 index 1668421895d..00000000000 --- a/token/program-2022-test/build.rs +++ /dev/null @@ -1,63 +0,0 @@ -extern crate walkdir; - -use { - std::{env, path::Path, process::Command}, - walkdir::WalkDir, -}; - -fn rerun_if_changed(directory: &Path) { - let src = directory.join("src"); - let files_in_src: Vec<_> = WalkDir::new(src) - .into_iter() - .map(|entry| entry.unwrap()) - .filter(|entry| { - if !entry.file_type().is_file() { - return false; - } - true - }) - .map(|f| f.path().to_str().unwrap().to_owned()) - .collect(); - - for file in files_in_src { - if !Path::new(&file).is_file() { - panic!("{} is not a file", file); - } - println!("cargo:rerun-if-changed={}", file); - } - let toml = directory.join("Cargo.toml").to_str().unwrap().to_owned(); - println!("cargo:rerun-if-changed={}", toml); -} - -fn main() { - let cwd = env::current_dir().expect("Unable to get current working directory"); - let spl_token_2022_dir = cwd - .parent() - .expect("Unable to get parent directory of current working dir") - .join("program-2022"); - rerun_if_changed(&spl_token_2022_dir); - println!("cargo:rerun-if-changed=build.rs"); - - let spl_token_2022_toml = spl_token_2022_dir.join("Cargo.toml"); - let spl_token_2022_toml = format!("{}", spl_token_2022_toml.display()); - let args = vec!["build-bpf", "--manifest-path", &spl_token_2022_toml]; - let output = Command::new("cargo") - .args(&args) - .output() - .expect("Error running cargo build-bpf"); - if let Ok(output_str) = std::str::from_utf8(&output.stdout) { - let subs = output_str.split('\n'); - for sub in subs { - println!("cargo:warning=(not a warning) {}", sub); - } - } - - // Set the temporary `twoxtx` cfg if `../twoxtx-setup.sh` was run - let twoxtx_solana_dir = cwd - .parent() - .expect("Unable to get parent directory of current working dir") - .join("twoxtx-solana"); - if twoxtx_solana_dir.exists() { - println!("cargo:rustc-cfg=twoxtx"); - } -} diff --git a/token/program-2022-test/tests/burn.rs b/token/program-2022-test/tests/burn.rs deleted file mode 100644 index 1b7102dfd09..00000000000 --- a/token/program-2022-test/tests/burn.rs +++ /dev/null @@ -1,262 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod program_test; -use { - program_test::{TestContext, TokenContext}, - solana_program_test::tokio, - solana_sdk::{ - instruction::InstructionError, pubkey::Pubkey, signature::Signer, signer::keypair::Keypair, - transaction::TransactionError, transport::TransportError, - }, - spl_token_2022::error::TokenError, - spl_token_client::token::{ExtensionInitializationParams, TokenError as TokenClientError}, -}; - -async fn run_basic(context: TestContext) { - let TokenContext { - decimals, - mint_authority, - token, - alice, - bob, - .. - } = context.token_context.unwrap(); - - let alice_account = Keypair::new(); - let alice_account = token - .create_auxiliary_token_account(&alice_account, &alice.pubkey()) - .await - .unwrap(); - - // mint a token - let amount = 10; - token - .mint_to(&alice_account, &mint_authority, amount) - .await - .unwrap(); - - // unchecked is ok - token.burn(&alice_account, &alice, 1).await.unwrap(); - - // checked is ok - token - .burn_checked(&alice_account, &alice, 1, decimals) - .await - .unwrap(); - - // burn too much is not ok - let error = token - .burn_checked(&alice_account, &alice, amount, decimals) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::InsufficientFunds as u32) - ) - ))) - ); - - // wrong signer - let error = token - .burn_checked(&alice_account, &bob, 1, decimals) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::OwnerMismatch as u32) - ) - ))) - ); -} - -#[tokio::test] -async fn basic() { - let mut context = TestContext::new().await; - context.init_token_with_mint(vec![]).await.unwrap(); - run_basic(context).await; -} - -#[tokio::test] -async fn basic_with_extension() { - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::TransferFeeConfig { - transfer_fee_config_authority: Some(Pubkey::new_unique()), - withdraw_withheld_authority: Some(Pubkey::new_unique()), - transfer_fee_basis_points: 100u16, - maximum_fee: 1_000u64, - }]) - .await - .unwrap(); - run_basic(context).await; -} - -async fn run_self_owned(context: TestContext) { - let TokenContext { - decimals, - mint_authority, - token, - alice, - .. - } = context.token_context.unwrap(); - - let alice_account = token - .create_auxiliary_token_account(&alice, &alice.pubkey()) - .await - .unwrap(); - - // mint a token - let amount = 10; - token - .mint_to(&alice_account, &mint_authority, amount) - .await - .unwrap(); - - // unchecked is ok - token.burn(&alice_account, &alice, 1).await.unwrap(); - - // checked is ok - token - .burn_checked(&alice_account, &alice, 1, decimals) - .await - .unwrap(); -} - -#[tokio::test] -async fn self_owned() { - let mut context = TestContext::new().await; - context.init_token_with_mint(vec![]).await.unwrap(); - run_self_owned(context).await; -} - -#[tokio::test] -async fn self_owned_with_extension() { - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::TransferFeeConfig { - transfer_fee_config_authority: Some(Pubkey::new_unique()), - withdraw_withheld_authority: Some(Pubkey::new_unique()), - transfer_fee_basis_points: 100u16, - maximum_fee: 1_000u64, - }]) - .await - .unwrap(); - run_self_owned(context).await; -} - -async fn run_burn_and_close_system_or_incinerator(context: TestContext, non_owner: &Pubkey) { - let TokenContext { - decimals, - mint_authority, - token, - alice, - .. - } = context.token_context.unwrap(); - - let alice_account = Keypair::new(); - let alice_account = token - .create_auxiliary_token_account(&alice_account, &alice.pubkey()) - .await - .unwrap(); - - // mint a token - token - .mint_to(&alice_account, &mint_authority, 1) - .await - .unwrap(); - - // transfer token to incinerator/system - let non_owner_account = Keypair::new(); - let non_owner_account = token - .create_auxiliary_token_account(&non_owner_account, non_owner) - .await - .unwrap(); - token - .transfer_checked(&alice_account, &non_owner_account, &alice, 1, decimals) - .await - .unwrap(); - - // can't close when holding tokens - let carlos = Keypair::new(); - let error = token - .close_account( - &non_owner_account, - &solana_program::incinerator::id(), - &carlos, - ) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::NonNativeHasBalance as u32) - ) - ))) - ); - - // but anyone can burn it - token - .burn_checked(&non_owner_account, &carlos, 1, decimals) - .await - .unwrap(); - - // closing fails if destination is not the incinerator - let error = token - .close_account(&non_owner_account, &carlos.pubkey(), &carlos) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError(0, InstructionError::InvalidAccountData) - ))) - ); - - let error = token - .close_account( - &non_owner_account, - &solana_program::system_program::id(), - &carlos, - ) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError(0, InstructionError::InvalidAccountData) - ))) - ); - - // ... and then close it - token.get_new_latest_blockhash().await.unwrap(); - token - .close_account( - &non_owner_account, - &solana_program::incinerator::id(), - &carlos, - ) - .await - .unwrap(); -} - -#[tokio::test] -async fn burn_and_close_incinerator_tokens() { - let mut context = TestContext::new().await; - context.init_token_with_mint(vec![]).await.unwrap(); - run_burn_and_close_system_or_incinerator(context, &solana_program::incinerator::id()).await; -} - -#[tokio::test] -async fn burn_and_close_system_tokens() { - let mut context = TestContext::new().await; - context.init_token_with_mint(vec![]).await.unwrap(); - run_burn_and_close_system_or_incinerator(context, &solana_program::system_program::id()).await; -} diff --git a/token/program-2022-test/tests/close_account.rs b/token/program-2022-test/tests/close_account.rs deleted file mode 100644 index 1e19d50ee92..00000000000 --- a/token/program-2022-test/tests/close_account.rs +++ /dev/null @@ -1,167 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod program_test; -use { - program_test::TestContext, - solana_program_test::tokio, - solana_sdk::{ - instruction::InstructionError, program_pack::Pack, pubkey::Pubkey, signature::Signer, - signer::keypair::Keypair, system_instruction, transaction::TransactionError, - transport::TransportError, - }, - spl_token_2022::{instruction, state::Account}, - spl_token_client::token::{ExtensionInitializationParams, TokenError as TokenClientError}, -}; - -#[tokio::test] -async fn success_init_after_close_account() { - let mut context = TestContext::new().await; - let payer = Keypair::from_bytes(&context.context.lock().await.payer.to_bytes()).unwrap(); - context.init_token_with_mint(vec![]).await.unwrap(); - let token = context.token_context.take().unwrap().token; - let token_program_id = spl_token_2022::id(); - let owner = Keypair::new(); - let token_account_keypair = Keypair::new(); - let token_account = token - .create_auxiliary_token_account(&token_account_keypair, &owner.pubkey()) - .await - .unwrap(); - - let destination = Pubkey::new_unique(); - token - .process_ixs( - &[ - instruction::close_account( - &token_program_id, - &token_account, - &destination, - &owner.pubkey(), - &[], - ) - .unwrap(), - system_instruction::create_account( - &payer.pubkey(), - &token_account, - 1_000_000_000, - Account::LEN as u64, - &token_program_id, - ), - instruction::initialize_account( - &token_program_id, - &token_account, - token.get_address(), - &owner.pubkey(), - ) - .unwrap(), - ], - &[&owner, &payer, &token_account_keypair], - ) - .await - .unwrap(); - let destination = token.get_account(&destination).await.unwrap(); - assert!(destination.lamports > 0); -} - -#[tokio::test] -async fn fail_init_after_close_account() { - let mut context = TestContext::new().await; - let payer = Keypair::from_bytes(&context.context.lock().await.payer.to_bytes()).unwrap(); - context.init_token_with_mint(vec![]).await.unwrap(); - let token = context.token_context.take().unwrap().token; - let token_program_id = spl_token_2022::id(); - let owner = Keypair::new(); - let token_account = token - .create_auxiliary_token_account(&Keypair::new(), &owner.pubkey()) - .await - .unwrap(); - - let destination = Pubkey::new_unique(); - let error = token - .process_ixs( - &[ - instruction::close_account( - &token_program_id, - &token_account, - &destination, - &owner.pubkey(), - &[], - ) - .unwrap(), - system_instruction::transfer(&payer.pubkey(), &token_account, 1_000_000_000), - instruction::initialize_account( - &token_program_id, - &token_account, - token.get_address(), - &owner.pubkey(), - ) - .unwrap(), - ], - &[&owner, &payer], - ) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError(2, InstructionError::InvalidAccountData,) - ))) - ); - let error = token.get_account(&destination).await.unwrap_err(); - assert_eq!(error, TokenClientError::AccountNotFound); -} - -#[tokio::test] -async fn fail_init_after_close_mint() { - let close_authority = Keypair::new(); - let mut context = TestContext::new().await; - let payer = Keypair::from_bytes(&context.context.lock().await.payer.to_bytes()).unwrap(); - context - .init_token_with_mint(vec![ExtensionInitializationParams::MintCloseAuthority { - close_authority: Some(close_authority.pubkey()), - }]) - .await - .unwrap(); - let token = context.token_context.take().unwrap().token; - let token_program_id = spl_token_2022::id(); - - let destination = Pubkey::new_unique(); - let error = token - .process_ixs( - &[ - instruction::close_account( - &token_program_id, - token.get_address(), - &destination, - &close_authority.pubkey(), - &[], - ) - .unwrap(), - system_instruction::transfer(&payer.pubkey(), token.get_address(), 1_000_000_000), - instruction::initialize_mint_close_authority( - &token_program_id, - token.get_address(), - None, - ) - .unwrap(), - instruction::initialize_mint( - &token_program_id, - token.get_address(), - &close_authority.pubkey(), - None, - 0, - ) - .unwrap(), - ], - &[&close_authority, &payer], - ) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError(2, InstructionError::InvalidAccountData,) - ))) - ); - let error = token.get_account(&destination).await.unwrap_err(); - assert_eq!(error, TokenClientError::AccountNotFound); -} diff --git a/token/program-2022-test/tests/confidential_transfer.rs b/token/program-2022-test/tests/confidential_transfer.rs deleted file mode 100644 index 47222c271e8..00000000000 --- a/token/program-2022-test/tests/confidential_transfer.rs +++ /dev/null @@ -1,1372 +0,0 @@ -#![cfg(feature = "test-bpf")] -#![cfg(twoxtx)] - -mod program_test; -use { - program_test::{TestContext, TokenContext}, - solana_program_test::tokio, - solana_sdk::{ - epoch_info::EpochInfo, instruction::InstructionError, pubkey::Pubkey, signature::Signer, - signer::keypair::Keypair, transaction::TransactionError, transport::TransportError, - }, - spl_token_2022::{ - error::TokenError, - extension::{ - confidential_transfer::{ - ConfidentialTransferAccount, ConfidentialTransferMint, EncryptedWithheldAmount, - }, - ExtensionType, - }, - solana_zk_token_sdk::{ - encryption::{auth_encryption::*, elgamal::*}, - zk_token_elgamal::{self, pod::Zeroable}, - }, - }, - spl_token_client::{ - client::SendTransaction, - token::{ExtensionInitializationParams, Token, TokenError as TokenClientError}, - }, - std::convert::TryInto, -}; - -const TEST_MAXIMUM_FEE: u64 = 100; -const TEST_FEE_BASIS_POINTS: u16 = 250; -const TEST_MAXIMUM_PENDING_BALANCE_CREDIT_COUNTER: u64 = 2; - -fn test_epoch_info() -> EpochInfo { - EpochInfo { - epoch: 0, - slot_index: 0, - slots_in_epoch: 0, - absolute_slot: 0, - block_height: 0, - transaction_count: None, - } -} - -struct ConfidentialTransferMintWithKeypairs { - ct_mint: ConfidentialTransferMint, - ct_mint_authority: Keypair, - #[allow(dead_code)] - ct_mint_transfer_auditor_encryption_keypair: ElGamalKeypair, - ct_mint_withdraw_withheld_authority_encryption_keypair: ElGamalKeypair, -} - -impl ConfidentialTransferMintWithKeypairs { - fn new() -> Self { - let ct_mint_authority = Keypair::new(); - let ct_mint_transfer_auditor_encryption_keypair = ElGamalKeypair::new_rand(); - let ct_mint_withdraw_withheld_authority_encryption_keypair = ElGamalKeypair::new_rand(); - let ct_mint = ConfidentialTransferMint { - authority: ct_mint_authority.pubkey().into(), - auto_approve_new_accounts: true.into(), - auditor_encryption_pubkey: ct_mint_transfer_auditor_encryption_keypair.public.into(), - withdraw_withheld_authority_encryption_pubkey: - ct_mint_withdraw_withheld_authority_encryption_keypair - .public - .into(), - withheld_amount: EncryptedWithheldAmount::zeroed(), - }; - Self { - ct_mint, - ct_mint_authority, - ct_mint_transfer_auditor_encryption_keypair, - ct_mint_withdraw_withheld_authority_encryption_keypair, - } - } - - fn without_auto_approve() -> Self { - let mut x = Self::new(); - x.ct_mint.auto_approve_new_accounts = false.into(); - x - } -} - -struct ConfidentialTokenAccountMeta { - token_account: Pubkey, - elgamal_keypair: ElGamalKeypair, - ae_key: AeKey, -} - -impl ConfidentialTokenAccountMeta { - async fn new(token: &Token, owner: &Keypair) -> Self - where - T: SendTransaction, - { - let token_account = token - .create_auxiliary_token_account_with_extension_space( - &Keypair::new(), - &owner.pubkey(), - vec![ExtensionType::ConfidentialTransferAccount], - ) - .await - .unwrap(); - - let elgamal_keypair = ElGamalKeypair::new(owner, &token_account).unwrap(); - let ae_key = AeKey::new(owner, &token_account).unwrap(); - - token - .confidential_transfer_configure_token_account_with_pending_counter( - &token_account, - owner, - TEST_MAXIMUM_PENDING_BALANCE_CREDIT_COUNTER, - ) - .await - .unwrap(); - - Self { - token_account, - elgamal_keypair, - ae_key, - } - } - - async fn with_tokens( - token: &Token, - owner: &Keypair, - mint_authority: &Keypair, - amount: u64, - decimals: u8, - ) -> Self - where - T: SendTransaction, - { - let meta = Self::new(token, owner).await; - - token - .mint_to(&meta.token_account, mint_authority, amount) - .await - .unwrap(); - - token - .confidential_transfer_deposit( - &meta.token_account, - &meta.token_account, - owner, - amount, - decimals, - ) - .await - .unwrap(); - - token - .confidential_transfer_apply_pending_balance(&meta.token_account, owner, 0, amount, 1) - .await - .unwrap(); - meta - } - - async fn check_balances( - &self, - token: &Token, - expected: ConfidentialTokenAccountBalances, - ) where - T: SendTransaction, - { - let state = token.get_account_info(&self.token_account).await.unwrap(); - let extension = state - .get_extension::() - .unwrap(); - - assert_eq!( - extension - .pending_balance_lo - .decrypt(&self.elgamal_keypair.secret) - .unwrap(), - expected.pending_balance_lo, - ); - assert_eq!( - extension - .pending_balance_hi - .decrypt(&self.elgamal_keypair.secret) - .unwrap(), - expected.pending_balance_hi, - ); - assert_eq!( - extension - .available_balance - .decrypt(&self.elgamal_keypair.secret) - .unwrap(), - expected.available_balance, - ); - assert_eq!( - self.ae_key - .decrypt(&extension.decryptable_available_balance.try_into().unwrap()) - .unwrap(), - expected.decryptable_available_balance, - ); - } -} - -struct ConfidentialTokenAccountBalances { - pending_balance_lo: u64, - pending_balance_hi: u64, - available_balance: u64, - decryptable_available_balance: u64, -} - -async fn check_withheld_amount_in_mint( - token: &Token, - withdraw_withheld_authority_encryption_keypair: &ElGamalKeypair, - expected: u64, -) where - T: SendTransaction, -{ - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - let decrypted_amount = extension - .withheld_amount - .decrypt(&withdraw_withheld_authority_encryption_keypair.secret) - .unwrap(); - assert_eq!(decrypted_amount, expected); -} - -#[tokio::test] -async fn ct_initialize_and_update_mint() { - let wrong_keypair = Keypair::new(); - - let ConfidentialTransferMintWithKeypairs { - ct_mint, - ct_mint_authority, - .. - } = ConfidentialTransferMintWithKeypairs::new(); - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ - ExtensionInitializationParams::ConfidentialTransferMint { ct_mint }, - ]) - .await - .unwrap(); - - let TokenContext { token, .. } = context.token_context.unwrap(); - - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!(*extension, ct_mint); - - // Change the authority - let new_ct_mint_authority = Keypair::new(); - let new_ct_mint = ConfidentialTransferMint { - authority: new_ct_mint_authority.pubkey(), - ..ConfidentialTransferMint::default() - }; - - let err = token - .confidential_transfer_update_mint( - &wrong_keypair, - new_ct_mint, - Some(&new_ct_mint_authority), - ) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError(0, InstructionError::MissingRequiredSignature) - ))) - ); - token - .confidential_transfer_update_mint( - &ct_mint_authority, - new_ct_mint, - Some(&new_ct_mint_authority), - ) - .await - .unwrap(); - - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!(*extension, new_ct_mint); - - // Clear the authority - let new_ct_mint = ConfidentialTransferMint::default(); - token - .confidential_transfer_update_mint(&new_ct_mint_authority, new_ct_mint, None) - .await - .unwrap(); - - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!(*extension, new_ct_mint); -} - -#[tokio::test] -async fn ct_configure_token_account() { - let ConfidentialTransferMintWithKeypairs { - ct_mint, - ct_mint_authority, - .. - } = ConfidentialTransferMintWithKeypairs::without_auto_approve(); - - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ - ExtensionInitializationParams::ConfidentialTransferMint { ct_mint }, - ]) - .await - .unwrap(); - - let TokenContext { token, alice, .. } = context.token_context.unwrap(); - let alice_meta = ConfidentialTokenAccountMeta::new(&token, &alice).await; - - let state = token - .get_account_info(&alice_meta.token_account) - .await - .unwrap(); - let extension = state - .get_extension::() - .unwrap(); - assert!(!bool::from(&extension.approved)); - assert!(bool::from(&extension.allow_balance_credits)); - assert_eq!( - extension.encryption_pubkey, - alice_meta.elgamal_keypair.public.into() - ); - assert_eq!( - alice_meta - .ae_key - .decrypt(&(extension.decryptable_available_balance.try_into().unwrap())) - .unwrap(), - 0 - ); - - token - .confidential_transfer_approve_account(&alice_meta.token_account, &ct_mint_authority) - .await - .unwrap(); - - let state = token - .get_account_info(&alice_meta.token_account) - .await - .unwrap(); - let extension = state - .get_extension::() - .unwrap(); - assert!(bool::from(&extension.approved)); - - // Configuring an already initialized account should produce an error - let err = token - .confidential_transfer_configure_token_account_with_pending_counter( - &alice_meta.token_account, - &alice, - TEST_MAXIMUM_PENDING_BALANCE_CREDIT_COUNTER, - ) - .await - .unwrap_err(); - - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::ExtensionAlreadyInitialized as u32), - ) - ))) - ); -} - -#[tokio::test] -async fn ct_enable_disable_balance_credits() { - let ConfidentialTransferMintWithKeypairs { ct_mint, .. } = - ConfidentialTransferMintWithKeypairs::new(); - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ - ExtensionInitializationParams::ConfidentialTransferMint { ct_mint }, - ]) - .await - .unwrap(); - - let TokenContext { token, alice, .. } = context.token_context.unwrap(); - let alice_meta = ConfidentialTokenAccountMeta::new(&token, &alice).await; - - token - .confidential_transfer_disable_balance_credits(&alice_meta.token_account, &alice) - .await - .unwrap(); - let state = token - .get_account_info(&alice_meta.token_account) - .await - .unwrap(); - let extension = state - .get_extension::() - .unwrap(); - assert!(!bool::from(&extension.allow_balance_credits)); - - token - .confidential_transfer_enable_balance_credits(&alice_meta.token_account, &alice) - .await - .unwrap(); - let state = token - .get_account_info(&alice_meta.token_account) - .await - .unwrap(); - let extension = state - .get_extension::() - .unwrap(); - assert!(bool::from(&extension.allow_balance_credits)); -} - -#[tokio::test] -async fn ct_new_account_is_empty() { - let ConfidentialTransferMintWithKeypairs { ct_mint, .. } = - ConfidentialTransferMintWithKeypairs::new(); - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ - ExtensionInitializationParams::ConfidentialTransferMint { ct_mint }, - ]) - .await - .unwrap(); - - let TokenContext { token, alice, .. } = context.token_context.unwrap(); - - let alice_meta = ConfidentialTokenAccountMeta::new(&token, &alice).await; - token - .confidential_transfer_empty_account(&alice_meta.token_account, &alice) - .await - .unwrap(); -} - -#[tokio::test] -async fn ct_deposit() { - let ConfidentialTransferMintWithKeypairs { ct_mint, .. } = - ConfidentialTransferMintWithKeypairs::new(); - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ - ExtensionInitializationParams::ConfidentialTransferMint { ct_mint }, - ]) - .await - .unwrap(); - - let TokenContext { - token, - alice, - mint_authority, - decimals, - .. - } = context.token_context.unwrap(); - let alice_meta = ConfidentialTokenAccountMeta::new(&token, &alice).await; - - token - .mint_to(&alice_meta.token_account, &mint_authority, 65537) - .await - .unwrap(); - - let state = token - .get_account_info(&alice_meta.token_account) - .await - .unwrap(); - assert_eq!(state.base.amount, 65537); - let extension = state - .get_extension::() - .unwrap(); - assert_eq!(extension.pending_balance_credit_counter, 0.into()); - assert_eq!(extension.expected_pending_balance_credit_counter, 0.into()); - assert_eq!(extension.actual_pending_balance_credit_counter, 0.into()); - assert_eq!( - extension.pending_balance_lo, - zk_token_elgamal::pod::ElGamalCiphertext::zeroed() - ); - assert_eq!( - extension.pending_balance_hi, - zk_token_elgamal::pod::ElGamalCiphertext::zeroed() - ); - assert_eq!( - extension.available_balance, - zk_token_elgamal::pod::ElGamalCiphertext::zeroed() - ); - - token - .confidential_transfer_deposit( - &alice_meta.token_account, - &alice_meta.token_account, - &alice, - 65537, - decimals, - ) - .await - .unwrap(); - - let state = token - .get_account_info(&alice_meta.token_account) - .await - .unwrap(); - assert_eq!(state.base.amount, 0); - let extension = state - .get_extension::() - .unwrap(); - assert_eq!(extension.pending_balance_credit_counter, 1.into()); - assert_eq!(extension.expected_pending_balance_credit_counter, 0.into()); - assert_eq!(extension.actual_pending_balance_credit_counter, 0.into()); - - alice_meta - .check_balances( - &token, - ConfidentialTokenAccountBalances { - pending_balance_lo: 1, - pending_balance_hi: 1, - available_balance: 0, - decryptable_available_balance: 0, - }, - ) - .await; - - token - .confidential_transfer_deposit( - &alice_meta.token_account, - &alice_meta.token_account, - &alice, - 0, - decimals, - ) - .await - .unwrap(); - - let err = token - .confidential_transfer_deposit( - &alice_meta.token_account, - &alice_meta.token_account, - &alice, - 0, - decimals, - ) - .await - .unwrap_err(); - - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom( - TokenError::MaximumPendingBalanceCreditCounterExceeded as u32 - ), - ) - ))) - ); - - token - .confidential_transfer_apply_pending_balance(&alice_meta.token_account, &alice, 0, 65537, 2) - .await - .unwrap(); - - let state = token - .get_account_info(&alice_meta.token_account) - .await - .unwrap(); - let extension = state - .get_extension::() - .unwrap(); - assert_eq!(extension.pending_balance_credit_counter, 0.into()); - assert_eq!(extension.expected_pending_balance_credit_counter, 2.into()); - assert_eq!(extension.actual_pending_balance_credit_counter, 2.into()); -} - -#[tokio::test] -async fn ct_withdraw() { - let ConfidentialTransferMintWithKeypairs { ct_mint, .. } = - ConfidentialTransferMintWithKeypairs::new(); - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ - ExtensionInitializationParams::ConfidentialTransferMint { ct_mint }, - ]) - .await - .unwrap(); - - let TokenContext { - token, - alice, - mint_authority, - decimals, - .. - } = context.token_context.unwrap(); - - let alice_meta = - ConfidentialTokenAccountMeta::with_tokens(&token, &alice, &mint_authority, 42, decimals) - .await; - - let state = token - .get_account_info(&alice_meta.token_account) - .await - .unwrap(); - let extension = state - .get_extension::() - .unwrap(); - assert_eq!(state.base.amount, 0); - - token - .confidential_transfer_withdraw( - &alice_meta.token_account, - &alice_meta.token_account, - &alice, - 21, - 42, - &extension.available_balance.try_into().unwrap(), - decimals, - ) - .await - .unwrap(); - - let state = token - .get_account_info(&alice_meta.token_account) - .await - .unwrap(); - let extension = state - .get_extension::() - .unwrap(); - assert_eq!(state.base.amount, 21); - - alice_meta - .check_balances( - &token, - ConfidentialTokenAccountBalances { - pending_balance_lo: 0, - pending_balance_hi: 0, - available_balance: 21, - decryptable_available_balance: 21, - }, - ) - .await; - - token - .confidential_transfer_withdraw( - &alice_meta.token_account, - &alice_meta.token_account, - &alice, - 21, - 21, - &extension.available_balance.try_into().unwrap(), - decimals, - ) - .await - .unwrap(); - - let state = token - .get_account_info(&alice_meta.token_account) - .await - .unwrap(); - assert_eq!(state.base.amount, 42); - - alice_meta - .check_balances( - &token, - ConfidentialTokenAccountBalances { - pending_balance_lo: 0, - pending_balance_hi: 0, - available_balance: 0, - decryptable_available_balance: 0, - }, - ) - .await; - - token - .confidential_transfer_empty_account(&alice_meta.token_account, &alice) - .await - .unwrap(); -} - -#[tokio::test] -async fn ct_transfer() { - let ConfidentialTransferMintWithKeypairs { ct_mint, .. } = - ConfidentialTransferMintWithKeypairs::new(); - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ - ExtensionInitializationParams::ConfidentialTransferMint { ct_mint }, - ]) - .await - .unwrap(); - - let TokenContext { - token, - alice, - bob, - mint_authority, - decimals, - .. - } = context.token_context.unwrap(); - let alice_meta = - ConfidentialTokenAccountMeta::with_tokens(&token, &alice, &mint_authority, 42, decimals) - .await; - let bob_meta = ConfidentialTokenAccountMeta::new(&token, &bob).await; - - let state = token - .get_account_info(&alice_meta.token_account) - .await - .unwrap(); - let extension = state - .get_extension::() - .unwrap(); - - // Self-transfer of 0 tokens - token - .confidential_transfer_transfer( - &alice_meta.token_account, - &alice_meta.token_account, - &alice, - 0, // amount - 42, - &extension.available_balance.try_into().unwrap(), - &alice_meta.elgamal_keypair.public, - &ct_mint.auditor_encryption_pubkey.try_into().unwrap(), - ) - .await - .unwrap(); - - alice_meta - .check_balances( - &token, - ConfidentialTokenAccountBalances { - pending_balance_lo: 0, - pending_balance_hi: 0, - available_balance: 42, - decryptable_available_balance: 42, - }, - ) - .await; - - let state = token - .get_account_info(&alice_meta.token_account) - .await - .unwrap(); - let extension = state - .get_extension::() - .unwrap(); - - // Self-transfer of N tokens - token - .confidential_transfer_transfer( - &alice_meta.token_account, - &alice_meta.token_account, - &alice, - 42, // amount - 42, - &extension.available_balance.try_into().unwrap(), - &alice_meta.elgamal_keypair.public, - &ct_mint.auditor_encryption_pubkey.try_into().unwrap(), - ) - .await - .unwrap(); - - alice_meta - .check_balances( - &token, - ConfidentialTokenAccountBalances { - pending_balance_lo: 42, - pending_balance_hi: 0, - available_balance: 0, - decryptable_available_balance: 0, - }, - ) - .await; - - let state = token - .get_account_info(&alice_meta.token_account) - .await - .unwrap(); - let extension = state - .get_extension::() - .unwrap(); - - let err = token - .confidential_transfer_transfer( - &alice_meta.token_account, - &alice_meta.token_account, - &alice, - 0, // amount - 0, - &extension.available_balance.try_into().unwrap(), - &alice_meta.elgamal_keypair.public, - &ct_mint.auditor_encryption_pubkey.try_into().unwrap(), - ) - .await - .unwrap_err(); - - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 1, - InstructionError::Custom( - TokenError::MaximumPendingBalanceCreditCounterExceeded as u32 - ), - ) - ))) - ); - - token - .confidential_transfer_apply_pending_balance(&alice_meta.token_account, &alice, 0, 42, 2) - .await - .unwrap(); - - alice_meta - .check_balances( - &token, - ConfidentialTokenAccountBalances { - pending_balance_lo: 0, - pending_balance_hi: 0, - available_balance: 42, - decryptable_available_balance: 42, - }, - ) - .await; - - let state = token - .get_account_info(&alice_meta.token_account) - .await - .unwrap(); - let extension = state - .get_extension::() - .unwrap(); - - token - .confidential_transfer_transfer( - &alice_meta.token_account, - &bob_meta.token_account, - &alice, - 42, // amount - 42, - &extension.available_balance.try_into().unwrap(), - &bob_meta.elgamal_keypair.public, - &ct_mint.auditor_encryption_pubkey.try_into().unwrap(), - ) - .await - .unwrap(); - - alice_meta - .check_balances( - &token, - ConfidentialTokenAccountBalances { - pending_balance_lo: 0, - pending_balance_hi: 0, - available_balance: 0, - decryptable_available_balance: 0, - }, - ) - .await; - - token - .confidential_transfer_empty_account(&alice_meta.token_account, &alice) - .await - .unwrap(); - - let err = token - .confidential_transfer_empty_account(&bob_meta.token_account, &bob) - .await - .unwrap_err(); - - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError(1, InstructionError::InvalidAccountData) - ))) - ); - - bob_meta - .check_balances( - &token, - ConfidentialTokenAccountBalances { - pending_balance_lo: 42, - pending_balance_hi: 0, - available_balance: 0, - decryptable_available_balance: 0, - }, - ) - .await; - - token - .confidential_transfer_apply_pending_balance(&bob_meta.token_account, &bob, 0, 42, 1) - .await - .unwrap(); - - bob_meta - .check_balances( - &token, - ConfidentialTokenAccountBalances { - pending_balance_lo: 0, - pending_balance_hi: 0, - available_balance: 42, - decryptable_available_balance: 42, - }, - ) - .await; -} - -#[tokio::test] -async fn ct_transfer_with_fee() { - let ConfidentialTransferMintWithKeypairs { ct_mint, .. } = - ConfidentialTransferMintWithKeypairs::new(); - - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ - ExtensionInitializationParams::TransferFeeConfig { - transfer_fee_config_authority: Some(Pubkey::new_unique()), - withdraw_withheld_authority: Some(Pubkey::new_unique()), - transfer_fee_basis_points: TEST_FEE_BASIS_POINTS, - maximum_fee: TEST_MAXIMUM_FEE, - }, - ExtensionInitializationParams::ConfidentialTransferMint { ct_mint }, - ]) - .await - .unwrap(); - - let TokenContext { - token, - alice, - bob, - mint_authority, - decimals, - .. - } = context.token_context.unwrap(); - - let epoch_info = test_epoch_info(); - - let alice_meta = - ConfidentialTokenAccountMeta::with_tokens(&token, &alice, &mint_authority, 100, decimals) - .await; - let bob_meta = ConfidentialTokenAccountMeta::new(&token, &bob).await; - - let state = token - .get_account_info(&alice_meta.token_account) - .await - .unwrap(); - let extension = state - .get_extension::() - .unwrap(); - - // Self-transfer of 0 tokens - token - .confidential_transfer_transfer_with_fee( - &alice_meta.token_account, - &alice_meta.token_account, - &alice, - 0, - 100, - &extension.available_balance.try_into().unwrap(), - &alice_meta.elgamal_keypair.public, - &ct_mint.auditor_encryption_pubkey.try_into().unwrap(), - &ct_mint - .withdraw_withheld_authority_encryption_pubkey - .try_into() - .unwrap(), - &epoch_info, - ) - .await - .unwrap(); - - alice_meta - .check_balances( - &token, - ConfidentialTokenAccountBalances { - pending_balance_lo: 0, - pending_balance_hi: 0, - available_balance: 100, - decryptable_available_balance: 100, - }, - ) - .await; - - // Self-transfers does not incur a fee - token - .confidential_transfer_transfer_with_fee( - &alice_meta.token_account, - &alice_meta.token_account, - &alice, - 100, - 100, - &extension.available_balance.try_into().unwrap(), - &alice_meta.elgamal_keypair.public, - &ct_mint.auditor_encryption_pubkey.try_into().unwrap(), - &ct_mint - .withdraw_withheld_authority_encryption_pubkey - .try_into() - .unwrap(), - &epoch_info, - ) - .await - .unwrap(); - - alice_meta - .check_balances( - &token, - ConfidentialTokenAccountBalances { - pending_balance_lo: 100, - pending_balance_hi: 0, - available_balance: 0, - decryptable_available_balance: 0, - }, - ) - .await; - - token - .confidential_transfer_apply_pending_balance(&alice_meta.token_account, &alice, 0, 100, 2) - .await - .unwrap(); - - alice_meta - .check_balances( - &token, - ConfidentialTokenAccountBalances { - pending_balance_lo: 0, - pending_balance_hi: 0, - available_balance: 100, - decryptable_available_balance: 100, - }, - ) - .await; - - token - .confidential_transfer_transfer_with_fee( - &alice_meta.token_account, - &bob_meta.token_account, - &alice, - 100, - 100, - &extension.available_balance.try_into().unwrap(), - &bob_meta.elgamal_keypair.public, - &ct_mint.auditor_encryption_pubkey.try_into().unwrap(), - &ct_mint - .withdraw_withheld_authority_encryption_pubkey - .try_into() - .unwrap(), - &epoch_info, - ) - .await - .unwrap(); - - alice_meta - .check_balances( - &token, - ConfidentialTokenAccountBalances { - pending_balance_lo: 0, - pending_balance_hi: 0, - available_balance: 0, - decryptable_available_balance: 0, - }, - ) - .await; - - // Alice account cannot be closed since there are withheld fees from self-transfer - token - .confidential_transfer_empty_account(&alice_meta.token_account, &alice) - .await - .unwrap(); - - let err = token - .confidential_transfer_empty_account(&bob_meta.token_account, &bob) - .await - .unwrap_err(); - - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError(1, InstructionError::InvalidAccountData) - ))) - ); - - bob_meta - .check_balances( - &token, - ConfidentialTokenAccountBalances { - pending_balance_lo: 97, - pending_balance_hi: 0, - available_balance: 0, - decryptable_available_balance: 0, - }, - ) - .await; - - token - .confidential_transfer_apply_pending_balance(&bob_meta.token_account, &bob, 0, 97, 1) - .await - .unwrap(); - - bob_meta - .check_balances( - &token, - ConfidentialTokenAccountBalances { - pending_balance_lo: 0, - pending_balance_hi: 0, - available_balance: 97, - decryptable_available_balance: 97, - }, - ) - .await; -} - -#[tokio::test] -async fn ct_withdraw_withheld_tokens_from_mint() { - let ConfidentialTransferMintWithKeypairs { - ct_mint, - ct_mint_withdraw_withheld_authority_encryption_keypair, - .. - } = ConfidentialTransferMintWithKeypairs::new(); - - let ct_mint_withdraw_withheld_authority = Keypair::new(); - - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ - ExtensionInitializationParams::TransferFeeConfig { - transfer_fee_config_authority: Some(Pubkey::new_unique()), - withdraw_withheld_authority: Some(ct_mint_withdraw_withheld_authority.pubkey()), - transfer_fee_basis_points: TEST_FEE_BASIS_POINTS, - maximum_fee: TEST_MAXIMUM_FEE, - }, - ExtensionInitializationParams::ConfidentialTransferMint { ct_mint }, - ]) - .await - .unwrap(); - - let TokenContext { - token, - alice, - bob, - mint_authority, - decimals, - .. - } = context.token_context.unwrap(); - - let epoch_info = test_epoch_info(); - - let alice_meta = - ConfidentialTokenAccountMeta::with_tokens(&token, &alice, &mint_authority, 100, decimals) - .await; - let bob_meta = ConfidentialTokenAccountMeta::new(&token, &bob).await; - - token - .confidential_transfer_withdraw_withheld_tokens_from_mint_with_key( - &ct_mint_withdraw_withheld_authority, - &alice_meta.token_account, - &alice_meta.elgamal_keypair.public, - 0_u64, - &ct_mint.withheld_amount.try_into().unwrap(), - &ct_mint_withdraw_withheld_authority_encryption_keypair, - ) - .await - .unwrap(); - - alice_meta - .check_balances( - &token, - ConfidentialTokenAccountBalances { - pending_balance_lo: 0, - pending_balance_hi: 0, - available_balance: 100, - decryptable_available_balance: 100, - }, - ) - .await; - - check_withheld_amount_in_mint( - &token, - &ct_mint_withdraw_withheld_authority_encryption_keypair, - 0, - ) - .await; - - let state = token - .get_account_info(&alice_meta.token_account) - .await - .unwrap(); - let extension = state - .get_extension::() - .unwrap(); - - // Test fee is 2.5% so the withheld fees should be 3 - token - .confidential_transfer_transfer_with_fee( - &alice_meta.token_account, - &bob_meta.token_account, - &alice, - 100, - 100, - &extension.available_balance.try_into().unwrap(), - &bob_meta.elgamal_keypair.public, - &ct_mint.auditor_encryption_pubkey.try_into().unwrap(), - &ct_mint - .withdraw_withheld_authority_encryption_pubkey - .try_into() - .unwrap(), - &epoch_info, - ) - .await - .unwrap(); - - let state = token - .get_account_info(&bob_meta.token_account) - .await - .unwrap(); - let extension = state - .get_extension::() - .unwrap(); - - assert_eq!( - extension - .withheld_amount - .decrypt(&ct_mint_withdraw_withheld_authority_encryption_keypair.secret), - Some(3), - ); - - token - .confidential_transfer_harvest_withheld_tokens_to_mint(&[&bob_meta.token_account]) - .await - .unwrap(); - - check_withheld_amount_in_mint( - &token, - &ct_mint_withdraw_withheld_authority_encryption_keypair, - 3, - ) - .await; - - let state = token.get_mint_info().await.unwrap(); - let ct_mint = state.get_extension::().unwrap(); - - token - .confidential_transfer_withdraw_withheld_tokens_from_mint_with_key( - &ct_mint_withdraw_withheld_authority, - &alice_meta.token_account, - &alice_meta.elgamal_keypair.public, - 3_u64, - &ct_mint.withheld_amount.try_into().unwrap(), - &ct_mint_withdraw_withheld_authority_encryption_keypair, - ) - .await - .unwrap(); - - alice_meta - .check_balances( - &token, - ConfidentialTokenAccountBalances { - pending_balance_lo: 3, - pending_balance_hi: 0, - available_balance: 0, - decryptable_available_balance: 0, - }, - ) - .await; -} - -#[tokio::test] -async fn ct_withdraw_withheld_tokens_from_accounts() { - let ConfidentialTransferMintWithKeypairs { - ct_mint, - ct_mint_transfer_auditor_encryption_keypair, - ct_mint_withdraw_withheld_authority_encryption_keypair, - .. - } = ConfidentialTransferMintWithKeypairs::new(); - - let ct_mint_withdraw_withheld_authority = Keypair::new(); - - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ - ExtensionInitializationParams::TransferFeeConfig { - transfer_fee_config_authority: Some(Pubkey::new_unique()), - withdraw_withheld_authority: Some(ct_mint_withdraw_withheld_authority.pubkey()), - transfer_fee_basis_points: TEST_FEE_BASIS_POINTS, - maximum_fee: TEST_MAXIMUM_FEE, - }, - ExtensionInitializationParams::ConfidentialTransferMint { ct_mint }, - ]) - .await - .unwrap(); - - let TokenContext { - token, - alice, - bob, - mint_authority, - decimals, - .. - } = context.token_context.unwrap(); - - let epoch_info = test_epoch_info(); - - let alice_meta = - ConfidentialTokenAccountMeta::with_tokens(&token, &alice, &mint_authority, 100, decimals) - .await; - let bob_meta = ConfidentialTokenAccountMeta::new(&token, &bob).await; - - let state = token - .get_account_info(&alice_meta.token_account) - .await - .unwrap(); - let extension = state - .get_extension::() - .unwrap(); - - // Test fee is 2.5% so the withheld fees should be 3 - token - .confidential_transfer_transfer_with_fee( - &alice_meta.token_account, - &bob_meta.token_account, - &alice, - 100, - 100, - &extension.available_balance.try_into().unwrap(), - &bob_meta.elgamal_keypair.public, - &ct_mint_transfer_auditor_encryption_keypair.public, - &ct_mint_withdraw_withheld_authority_encryption_keypair.public, - &epoch_info, - ) - .await - .unwrap(); - - let state = token - .get_account_info(&bob_meta.token_account) - .await - .unwrap(); - let extension = state - .get_extension::() - .unwrap(); - - assert_eq!( - extension - .withheld_amount - .decrypt(&ct_mint_withdraw_withheld_authority_encryption_keypair.secret), - Some(3), - ); - - token - .confidential_transfer_withdraw_withheld_tokens_from_accounts_with_key( - &ct_mint_withdraw_withheld_authority, - &alice_meta.token_account, - &alice_meta.elgamal_keypair.public, - 3_u64, - &extension.withheld_amount.try_into().unwrap(), - &ct_mint_withdraw_withheld_authority_encryption_keypair, - &[&bob_meta.token_account], - ) - .await - .unwrap(); - - bob_meta - .check_balances( - &token, - ConfidentialTokenAccountBalances { - pending_balance_lo: 97, - pending_balance_hi: 0, - available_balance: 0, - decryptable_available_balance: 0, - }, - ) - .await; - - alice_meta - .check_balances( - &token, - ConfidentialTokenAccountBalances { - pending_balance_lo: 3, - pending_balance_hi: 0, - available_balance: 0, - decryptable_available_balance: 0, - }, - ) - .await; -} diff --git a/token/program-2022-test/tests/default_account_state.rs b/token/program-2022-test/tests/default_account_state.rs deleted file mode 100644 index d7b90048c3f..00000000000 --- a/token/program-2022-test/tests/default_account_state.rs +++ /dev/null @@ -1,298 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod program_test; -use { - program_test::{TestContext, TokenContext}, - solana_program_test::tokio, - solana_sdk::{ - instruction::InstructionError, program_option::COption, pubkey::Pubkey, signature::Signer, - signer::keypair::Keypair, transaction::TransactionError, transport::TransportError, - }, - spl_token_2022::{ - error::TokenError, extension::default_account_state::DefaultAccountState, - instruction::AuthorityType, state::AccountState, - }, - spl_token_client::token::{ExtensionInitializationParams, TokenError as TokenClientError}, - std::convert::TryFrom, -}; - -#[tokio::test] -async fn success_init_default_acct_state_frozen() { - let default_account_state = AccountState::Frozen; - let mut context = TestContext::new().await; - context - .init_token_with_freezing_mint(vec![ExtensionInitializationParams::DefaultAccountState { - state: default_account_state, - }]) - .await - .unwrap(); - let TokenContext { - decimals, - mint_authority, - freeze_authority, - token, - .. - } = context.token_context.unwrap(); - - let state = token.get_mint_info().await.unwrap(); - assert_eq!(state.base.decimals, decimals); - assert_eq!( - state.base.mint_authority, - COption::Some(mint_authority.pubkey()) - ); - assert_eq!(state.base.supply, 0); - assert!(state.base.is_initialized); - assert_eq!( - state.base.freeze_authority, - COption::Some(freeze_authority.unwrap().pubkey()) - ); - let extension = state.get_extension::().unwrap(); - assert_eq!( - AccountState::try_from(extension.state).unwrap(), - default_account_state, - ); -} - -#[tokio::test] -async fn fail_init_no_authority_default_acct_state_frozen() { - let default_account_state = AccountState::Frozen; - let mut context = TestContext::new().await; - let err = context - .init_token_with_mint(vec![ExtensionInitializationParams::DefaultAccountState { - state: default_account_state, - }]) - .await - .unwrap_err(); - - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 2, - InstructionError::Custom(TokenError::MintCannotFreeze as u32) - ) - ))) - ); -} - -#[tokio::test] -async fn success_init_default_acct_state_initialized() { - let default_account_state = AccountState::Initialized; - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::DefaultAccountState { - state: default_account_state, - }]) - .await - .unwrap(); - let TokenContext { - decimals, - mint_authority, - token, - .. - } = context.token_context.unwrap(); - - let state = token.get_mint_info().await.unwrap(); - assert_eq!(state.base.decimals, decimals); - assert_eq!( - state.base.mint_authority, - COption::Some(mint_authority.pubkey()) - ); - assert_eq!(state.base.supply, 0); - assert!(state.base.is_initialized); - assert_eq!(state.base.freeze_authority, COption::None); - let extension = state.get_extension::().unwrap(); - assert_eq!( - AccountState::try_from(extension.state).unwrap(), - default_account_state, - ); -} - -#[tokio::test] -async fn success_no_authority_init_default_acct_state_initialized() { - let default_account_state = AccountState::Initialized; - let mut context = TestContext::new().await; - context - .init_token_with_freezing_mint(vec![ExtensionInitializationParams::DefaultAccountState { - state: default_account_state, - }]) - .await - .unwrap(); - let TokenContext { - decimals, - mint_authority, - freeze_authority, - token, - .. - } = context.token_context.unwrap(); - - let state = token.get_mint_info().await.unwrap(); - assert_eq!(state.base.decimals, decimals); - assert_eq!( - state.base.mint_authority, - COption::Some(mint_authority.pubkey()) - ); - assert_eq!(state.base.supply, 0); - assert!(state.base.is_initialized); - assert_eq!( - state.base.freeze_authority, - COption::Some(freeze_authority.unwrap().pubkey()) - ); - let extension = state.get_extension::().unwrap(); - assert_eq!( - AccountState::try_from(extension.state).unwrap(), - default_account_state, - ); -} - -#[tokio::test] -async fn fail_invalid_default_acct_state() { - let default_account_state = AccountState::Uninitialized; - let mut context = TestContext::new().await; - let err = context - .init_token_with_freezing_mint(vec![ExtensionInitializationParams::DefaultAccountState { - state: default_account_state, - }]) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 1, - InstructionError::Custom(TokenError::InvalidState as u32) - ) - ))) - ); -} - -#[tokio::test] -async fn end_to_end_default_account_state() { - let default_account_state = AccountState::Frozen; - let mut context = TestContext::new().await; - context - .init_token_with_freezing_mint(vec![ExtensionInitializationParams::DefaultAccountState { - state: default_account_state, - }]) - .await - .unwrap(); - let TokenContext { - mint_authority, - freeze_authority, - token, - .. - } = context.token_context.unwrap(); - - let freeze_authority = freeze_authority.unwrap(); - - let owner = Pubkey::new_unique(); - let account = Keypair::new(); - let account = token - .create_auxiliary_token_account(&account, &owner) - .await - .unwrap(); - let account_state = token.get_account_info(&account).await.unwrap(); - assert_eq!(account_state.base.state, default_account_state); - - // Invalid default state - let err = token - .set_default_account_state(&mint_authority, &AccountState::Uninitialized) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::InvalidState as u32) - ) - ))) - ); - - token - .set_default_account_state(&freeze_authority, &AccountState::Initialized) - .await - .unwrap(); - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!( - AccountState::try_from(extension.state).unwrap(), - AccountState::Initialized, - ); - - let owner = Pubkey::new_unique(); - let account = Keypair::new(); - let account = token - .create_auxiliary_token_account(&account, &owner) - .await - .unwrap(); - let account_state = token.get_account_info(&account).await.unwrap(); - assert_eq!(account_state.base.state, AccountState::Initialized); - - // adjusting freeze authority adjusts default state authority - let new_authority = Keypair::new(); - token - .set_authority( - token.get_address(), - Some(&new_authority.pubkey()), - AuthorityType::FreezeAccount, - &freeze_authority, - ) - .await - .unwrap(); - - let err = token - .set_default_account_state(&mint_authority, &AccountState::Frozen) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::OwnerMismatch as u32) - ) - ))) - ); - - token - .set_default_account_state(&new_authority, &AccountState::Frozen) - .await - .unwrap(); - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!( - AccountState::try_from(extension.state).unwrap(), - AccountState::Frozen, - ); - - token - .set_authority( - token.get_address(), - None, - AuthorityType::FreezeAccount, - &new_authority, - ) - .await - .unwrap(); - - let err = token - .set_default_account_state(&new_authority, &AccountState::Initialized) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::NoAuthorityExists as u32) - ) - ))) - ); - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!( - AccountState::try_from(extension.state).unwrap(), - AccountState::Frozen, - ); -} diff --git a/token/program-2022-test/tests/delegate.rs b/token/program-2022-test/tests/delegate.rs deleted file mode 100644 index 1dc4f08d927..00000000000 --- a/token/program-2022-test/tests/delegate.rs +++ /dev/null @@ -1,268 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod program_test; -use { - program_test::{TestContext, TokenContext}, - solana_program_test::tokio, - solana_sdk::{ - instruction::InstructionError, pubkey::Pubkey, signature::Signer, signer::keypair::Keypair, - transaction::TransactionError, transport::TransportError, - }, - spl_token_2022::error::TokenError, - spl_token_client::token::{ExtensionInitializationParams, TokenError as TokenClientError}, -}; - -#[derive(PartialEq)] -enum TransferMode { - All, - CheckedOnly, -} - -#[derive(PartialEq)] -enum ApproveMode { - Unchecked, - Checked, -} - -#[derive(PartialEq)] -enum OwnerMode { - SelfOwned, - External, -} - -async fn run_basic( - context: TestContext, - owner_mode: OwnerMode, - transfer_mode: TransferMode, - approve_mode: ApproveMode, -) { - let TokenContext { - decimals, - mint_authority, - token, - alice, - bob, - .. - } = context.token_context.unwrap(); - - let alice_account = match owner_mode { - OwnerMode::SelfOwned => token - .create_auxiliary_token_account(&alice, &alice.pubkey()) - .await - .unwrap(), - OwnerMode::External => { - let alice_account = Keypair::new(); - token - .create_auxiliary_token_account(&alice_account, &alice.pubkey()) - .await - .unwrap() - } - }; - let bob_account = Keypair::new(); - let bob_account = token - .create_auxiliary_token_account(&bob_account, &bob.pubkey()) - .await - .unwrap(); - - // mint tokens - let amount = 100; - token - .mint_to(&alice_account, &mint_authority, amount) - .await - .unwrap(); - - // delegate to bob - let delegated_amount = 10; - match approve_mode { - ApproveMode::Unchecked => token - .approve(&alice_account, &bob.pubkey(), &alice, delegated_amount) - .await - .unwrap(), - ApproveMode::Checked => token - .approve_checked( - &alice_account, - &bob.pubkey(), - &alice, - delegated_amount, - decimals, - ) - .await - .unwrap(), - } - - // transfer too much is not ok - let error = token - .transfer_checked( - &alice_account, - &bob_account, - &bob, - delegated_amount + 1, - decimals, - ) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::InsufficientFunds as u32) - ) - ))) - ); - - // transfer is ok - if transfer_mode == TransferMode::All { - token - .transfer_unchecked(&alice_account, &bob_account, &bob, 1) - .await - .unwrap(); - } - - token - .transfer_checked(&alice_account, &bob_account, &bob, 1, decimals) - .await - .unwrap(); - - // burn is ok - token.burn(&alice_account, &bob, 1).await.unwrap(); - token - .burn_checked(&alice_account, &bob, 1, decimals) - .await - .unwrap(); - - // wrong signer - let error = token - .transfer_checked(&alice_account, &bob_account, &Keypair::new(), 1, decimals) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::OwnerMismatch as u32) - ) - ))) - ); - - // revoke - token.revoke(&alice_account, &alice).await.unwrap(); - - // now fails - let error = token - .transfer_checked(&alice_account, &bob_account, &bob, 2, decimals) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::OwnerMismatch as u32) - ) - ))) - ); -} - -#[tokio::test] -async fn basic() { - let mut context = TestContext::new().await; - context.init_token_with_mint(vec![]).await.unwrap(); - run_basic( - context, - OwnerMode::External, - TransferMode::All, - ApproveMode::Unchecked, - ) - .await; -} - -#[tokio::test] -async fn basic_checked() { - let mut context = TestContext::new().await; - context.init_token_with_mint(vec![]).await.unwrap(); - run_basic( - context, - OwnerMode::External, - TransferMode::All, - ApproveMode::Checked, - ) - .await; -} - -#[tokio::test] -async fn basic_self_owned() { - let mut context = TestContext::new().await; - context.init_token_with_mint(vec![]).await.unwrap(); - run_basic( - context, - OwnerMode::SelfOwned, - TransferMode::All, - ApproveMode::Checked, - ) - .await; -} - -#[tokio::test] -async fn basic_with_extension() { - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::TransferFeeConfig { - transfer_fee_config_authority: Some(Pubkey::new_unique()), - withdraw_withheld_authority: Some(Pubkey::new_unique()), - transfer_fee_basis_points: 100u16, - maximum_fee: 1_000u64, - }]) - .await - .unwrap(); - run_basic( - context, - OwnerMode::External, - TransferMode::CheckedOnly, - ApproveMode::Unchecked, - ) - .await; -} - -#[tokio::test] -async fn basic_with_extension_checked() { - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::TransferFeeConfig { - transfer_fee_config_authority: Some(Pubkey::new_unique()), - withdraw_withheld_authority: Some(Pubkey::new_unique()), - transfer_fee_basis_points: 100u16, - maximum_fee: 1_000u64, - }]) - .await - .unwrap(); - run_basic( - context, - OwnerMode::External, - TransferMode::CheckedOnly, - ApproveMode::Checked, - ) - .await; -} - -#[tokio::test] -async fn basic_self_owned_with_extension() { - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::TransferFeeConfig { - transfer_fee_config_authority: Some(Pubkey::new_unique()), - withdraw_withheld_authority: Some(Pubkey::new_unique()), - transfer_fee_basis_points: 100u16, - maximum_fee: 1_000u64, - }]) - .await - .unwrap(); - run_basic( - context, - OwnerMode::SelfOwned, - TransferMode::CheckedOnly, - ApproveMode::Checked, - ) - .await; -} diff --git a/token/program-2022-test/tests/freeze.rs b/token/program-2022-test/tests/freeze.rs deleted file mode 100644 index d6c3855ee90..00000000000 --- a/token/program-2022-test/tests/freeze.rs +++ /dev/null @@ -1,44 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod program_test; -use { - program_test::{TestContext, TokenContext}, - solana_program_test::tokio, - solana_sdk::{signature::Signer, signer::keypair::Keypair}, - spl_token_2022::state::AccountState, -}; - -#[tokio::test] -async fn basic() { - let mut context = TestContext::new().await; - context.init_token_with_freezing_mint(vec![]).await.unwrap(); - let TokenContext { - freeze_authority, - token, - alice, - .. - } = context.token_context.unwrap(); - let freeze_authority = freeze_authority.unwrap(); - - let account = Keypair::new(); - let account = token - .create_auxiliary_token_account(&account, &alice.pubkey()) - .await - .unwrap(); - let state = token.get_account_info(&account).await.unwrap(); - assert_eq!(state.base.state, AccountState::Initialized); - - token - .freeze_account(&account, &freeze_authority) - .await - .unwrap(); - let state = token.get_account_info(&account).await.unwrap(); - assert_eq!(state.base.state, AccountState::Frozen); - - token - .thaw_account(&account, &freeze_authority) - .await - .unwrap(); - let state = token.get_account_info(&account).await.unwrap(); - assert_eq!(state.base.state, AccountState::Initialized); -} diff --git a/token/program-2022-test/tests/initialize_account.rs b/token/program-2022-test/tests/initialize_account.rs deleted file mode 100644 index 1e96a62f7fa..00000000000 --- a/token/program-2022-test/tests/initialize_account.rs +++ /dev/null @@ -1,259 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod program_test; -use { - program_test::TestContext, - solana_program_test::tokio, - solana_sdk::{ - instruction::InstructionError, - program_pack::Pack, - pubkey::Pubkey, - signature::Signer, - signer::keypair::Keypair, - system_instruction, - transaction::{Transaction, TransactionError}, - }, - spl_token_2022::{ - error::TokenError, - extension::{ - transfer_fee::{self, TransferFeeAmount}, - ExtensionType, StateWithExtensions, - }, - instruction, - state::{Account, Mint}, - }, -}; - -#[tokio::test] -async fn no_extensions() { - let context = TestContext::new().await; - let mut ctx = context.context.lock().await; - let rent = ctx.banks_client.get_rent().await.unwrap(); - let mint_account = Keypair::new(); - let mint_authority_pubkey = Pubkey::new_unique(); - - let space = ExtensionType::get_account_len::(&[]); - let instructions = vec![ - system_instruction::create_account( - &ctx.payer.pubkey(), - &mint_account.pubkey(), - rent.minimum_balance(space), - space as u64, - &spl_token_2022::id(), - ), - instruction::initialize_mint( - &spl_token_2022::id(), - &mint_account.pubkey(), - &mint_authority_pubkey, - None, - 9, - ) - .unwrap(), - ]; - let tx = Transaction::new_signed_with_payer( - &instructions, - Some(&ctx.payer.pubkey()), - &[&ctx.payer, &mint_account], - ctx.last_blockhash, - ); - ctx.banks_client.process_transaction(tx).await.unwrap(); - - let account = Keypair::new(); - let account_owner_pubkey = Pubkey::new_unique(); - let space = ExtensionType::get_account_len::(&[]); - let instructions = vec![ - system_instruction::create_account( - &ctx.payer.pubkey(), - &account.pubkey(), - rent.minimum_balance(space), - space as u64, - &spl_token_2022::id(), - ), - instruction::initialize_account3( - &spl_token_2022::id(), - &account.pubkey(), - &mint_account.pubkey(), - &account_owner_pubkey, - ) - .unwrap(), - ]; - let tx = Transaction::new_signed_with_payer( - &instructions, - Some(&ctx.payer.pubkey()), - &[&ctx.payer, &account], - ctx.last_blockhash, - ); - ctx.banks_client.process_transaction(tx).await.unwrap(); - let account_info = ctx - .banks_client - .get_account(account.pubkey()) - .await - .expect("get_account") - .expect("account not none"); - assert_eq!(account_info.data.len(), spl_token_2022::state::Account::LEN); - assert_eq!(account_info.owner, spl_token_2022::id()); - assert_eq!(account_info.lamports, rent.minimum_balance(space)); -} - -#[tokio::test] -async fn fail_on_invalid_mint() { - let context = TestContext::new().await; - let mut ctx = context.context.lock().await; - let rent = ctx.banks_client.get_rent().await.unwrap(); - let mint_account = Keypair::new(); - - let space = ExtensionType::get_account_len::(&[]); - let instructions = vec![system_instruction::create_account( - &ctx.payer.pubkey(), - &mint_account.pubkey(), - rent.minimum_balance(space), - space as u64, - &spl_token_2022::id(), - )]; - let tx = Transaction::new_signed_with_payer( - &instructions, - Some(&ctx.payer.pubkey()), - &[&ctx.payer, &mint_account], - ctx.last_blockhash, - ); - ctx.banks_client.process_transaction(tx).await.unwrap(); - - let account = Keypair::new(); - let account_owner_pubkey = Pubkey::new_unique(); - let space = ExtensionType::get_account_len::(&[]); - let instructions = vec![ - system_instruction::create_account( - &ctx.payer.pubkey(), - &account.pubkey(), - rent.minimum_balance(space), - space as u64, - &spl_token_2022::id(), - ), - instruction::initialize_account3( - &spl_token_2022::id(), - &account.pubkey(), - &mint_account.pubkey(), - &account_owner_pubkey, - ) - .unwrap(), - ]; - let tx = Transaction::new_signed_with_payer( - &instructions, - Some(&ctx.payer.pubkey()), - &[&ctx.payer, &account], - ctx.last_blockhash, - ); - #[allow(clippy::useless_conversion)] - let err: TransactionError = ctx - .banks_client - .process_transaction(tx) - .await - .unwrap_err() - .unwrap() - .into(); - assert_eq!( - err, - TransactionError::InstructionError( - 1, - InstructionError::Custom(TokenError::InvalidMint as u32) - ) - ); -} - -#[tokio::test] -async fn single_extension() { - let context = TestContext::new().await; - let mut ctx = context.context.lock().await; - let rent = ctx.banks_client.get_rent().await.unwrap(); - let mint_account = Keypair::new(); - let mint_authority_pubkey = Pubkey::new_unique(); - - let space = ExtensionType::get_account_len::(&[ExtensionType::TransferFeeConfig]); - let instructions = vec![ - system_instruction::create_account( - &ctx.payer.pubkey(), - &mint_account.pubkey(), - rent.minimum_balance(space), - space as u64, - &spl_token_2022::id(), - ), - transfer_fee::instruction::initialize_transfer_fee_config( - &spl_token_2022::id(), - &mint_account.pubkey(), - None, - None, - 10, - 4242, - ) - .unwrap(), - instruction::initialize_mint( - &spl_token_2022::id(), - &mint_account.pubkey(), - &mint_authority_pubkey, - None, - 9, - ) - .unwrap(), - ]; - let tx = Transaction::new_signed_with_payer( - &instructions, - Some(&ctx.payer.pubkey()), - &[&ctx.payer, &mint_account], - ctx.last_blockhash, - ); - ctx.banks_client.process_transaction(tx).await.unwrap(); - - let account = Keypair::new(); - let account_owner_pubkey = Pubkey::new_unique(); - let space = ExtensionType::get_account_len::(&[ExtensionType::TransferFeeAmount]); - let instructions = vec![ - system_instruction::create_account( - &ctx.payer.pubkey(), - &account.pubkey(), - rent.minimum_balance(space), - space as u64, - &spl_token_2022::id(), - ), - instruction::initialize_account3( - &spl_token_2022::id(), - &account.pubkey(), - &mint_account.pubkey(), - &account_owner_pubkey, - ) - .unwrap(), - ]; - let tx = Transaction::new_signed_with_payer( - &instructions, - Some(&ctx.payer.pubkey()), - &[&ctx.payer, &account], - ctx.last_blockhash, - ); - ctx.banks_client.process_transaction(tx).await.unwrap(); - let account_info = ctx - .banks_client - .get_account(account.pubkey()) - .await - .expect("get_account") - .expect("account not none"); - assert_eq!( - account_info.data.len(), - ExtensionType::get_account_len::(&[ExtensionType::TransferFeeAmount]), - ); - assert_eq!(account_info.owner, spl_token_2022::id()); - assert_eq!(account_info.lamports, rent.minimum_balance(space)); - let state = StateWithExtensions::::unpack(&account_info.data).unwrap(); - assert_eq!(state.base.mint, mint_account.pubkey()); - assert_eq!( - &state.get_extension_types().unwrap(), - &[ExtensionType::TransferFeeAmount] - ); - let unpacked_extension = state.get_extension::().unwrap(); - assert_eq!( - *unpacked_extension, - TransferFeeAmount { - withheld_amount: 0.into() - } - ); -} - -// TODO: add test for multiple Account extensions when memo extension is present diff --git a/token/program-2022-test/tests/initialize_mint.rs b/token/program-2022-test/tests/initialize_mint.rs deleted file mode 100644 index d5082d96938..00000000000 --- a/token/program-2022-test/tests/initialize_mint.rs +++ /dev/null @@ -1,490 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod program_test; -use { - program_test::{TestContext, TokenContext}, - solana_program_test::tokio, - solana_sdk::{ - instruction::InstructionError, - program_option::COption, - program_pack::Pack, - pubkey::Pubkey, - signature::Signer, - signer::keypair::Keypair, - system_instruction, - transaction::{Transaction, TransactionError}, - }, - spl_token_2022::{ - error::TokenError, - extension::{mint_close_authority::MintCloseAuthority, transfer_fee, ExtensionType}, - instruction, native_mint, - state::Mint, - }, - spl_token_client::token::ExtensionInitializationParams, - std::convert::TryInto, -}; - -#[tokio::test] -async fn success_base() { - let mut context = TestContext::new().await; - context.init_token_with_mint(vec![]).await.unwrap(); - let TokenContext { - decimals, - mint_authority, - token, - .. - } = context.token_context.unwrap(); - - let mint = token.get_mint_info().await.unwrap(); - assert_eq!(mint.base.decimals, decimals); - assert_eq!( - mint.base.mint_authority, - COption::Some(mint_authority.pubkey()) - ); - assert_eq!(mint.base.supply, 0); - assert!(mint.base.is_initialized); - assert_eq!(mint.base.freeze_authority, COption::None); -} - -#[tokio::test] -async fn fail_extension_no_space() { - let context = TestContext::new().await; - let mut ctx = context.context.lock().await; - let rent = ctx.banks_client.get_rent().await.unwrap(); - let mint_account = Keypair::new(); - let mint_authority_pubkey = Pubkey::new_unique(); - - let space = Mint::LEN; - let instructions = vec![ - system_instruction::create_account( - &ctx.payer.pubkey(), - &mint_account.pubkey(), - rent.minimum_balance(space), - space as u64, - &spl_token_2022::id(), - ), - instruction::initialize_mint_close_authority( - &spl_token_2022::id(), - &mint_account.pubkey(), - Some(&mint_authority_pubkey), - ) - .unwrap(), - instruction::initialize_mint( - &spl_token_2022::id(), - &mint_account.pubkey(), - &mint_authority_pubkey, - None, - 9, - ) - .unwrap(), - ]; - - let tx = Transaction::new_signed_with_payer( - &instructions, - Some(&ctx.payer.pubkey()), - &[&ctx.payer, &mint_account], - ctx.last_blockhash, - ); - #[allow(clippy::useless_conversion)] - let err: TransactionError = ctx - .banks_client - .process_transaction(tx) - .await - .unwrap_err() - .unwrap() - .into(); - assert_eq!( - err, - TransactionError::InstructionError(1, InstructionError::InvalidAccountData) - ); -} - -#[tokio::test] -async fn fail_extension_after_mint_init() { - let context = TestContext::new().await; - let mut ctx = context.context.lock().await; - let rent = ctx.banks_client.get_rent().await.unwrap(); - let mint_account = Keypair::new(); - let mint_authority_pubkey = Pubkey::new_unique(); - - let space = ExtensionType::get_account_len::(&[ExtensionType::MintCloseAuthority]); - let instructions = vec![ - system_instruction::create_account( - &ctx.payer.pubkey(), - &mint_account.pubkey(), - rent.minimum_balance(space), - space as u64, - &spl_token_2022::id(), - ), - instruction::initialize_mint( - &spl_token_2022::id(), - &mint_account.pubkey(), - &mint_authority_pubkey, - None, - 9, - ) - .unwrap(), - instruction::initialize_mint_close_authority( - &spl_token_2022::id(), - &mint_account.pubkey(), - Some(&mint_authority_pubkey), - ) - .unwrap(), - ]; - - let tx = Transaction::new_signed_with_payer( - &instructions, - Some(&ctx.payer.pubkey()), - &[&ctx.payer, &mint_account], - ctx.last_blockhash, - ); - #[allow(clippy::useless_conversion)] - let err: TransactionError = ctx - .banks_client - .process_transaction(tx) - .await - .unwrap_err() - .unwrap() - .into(); - assert_eq!( - err, - TransactionError::InstructionError(1, InstructionError::InvalidAccountData) - ); -} - -#[tokio::test] -async fn success_extension_and_base() { - let close_authority = Some(Pubkey::new_unique()); - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::MintCloseAuthority { - close_authority, - }]) - .await - .unwrap(); - let TokenContext { - decimals, - mint_authority, - token, - .. - } = context.token_context.unwrap(); - - let state = token.get_mint_info().await.unwrap(); - assert_eq!(state.base.decimals, decimals); - assert_eq!( - state.base.mint_authority, - COption::Some(mint_authority.pubkey()) - ); - assert_eq!(state.base.supply, 0); - assert!(state.base.is_initialized); - assert_eq!(state.base.freeze_authority, COption::None); - let extension = state.get_extension::().unwrap(); - assert_eq!( - extension.close_authority, - close_authority.try_into().unwrap(), - ); -} - -#[tokio::test] -async fn fail_init_overallocated_mint() { - let context = TestContext::new().await; - let mut ctx = context.context.lock().await; - let rent = ctx.banks_client.get_rent().await.unwrap(); - let mint_account = Keypair::new(); - let mint_authority_pubkey = Pubkey::new_unique(); - - let space = ExtensionType::get_account_len::(&[ExtensionType::MintCloseAuthority]); - let instructions = vec![ - system_instruction::create_account( - &ctx.payer.pubkey(), - &mint_account.pubkey(), - rent.minimum_balance(space), - space as u64, - &spl_token_2022::id(), - ), - instruction::initialize_mint( - &spl_token_2022::id(), - &mint_account.pubkey(), - &mint_authority_pubkey, - None, - 9, - ) - .unwrap(), - ]; - - let tx = Transaction::new_signed_with_payer( - &instructions, - Some(&ctx.payer.pubkey()), - &[&ctx.payer, &mint_account], - ctx.last_blockhash, - ); - #[allow(clippy::useless_conversion)] - let err: TransactionError = ctx - .banks_client - .process_transaction(tx) - .await - .unwrap_err() - .unwrap() - .into(); - assert_eq!( - err, - TransactionError::InstructionError(1, InstructionError::InvalidAccountData) - ); -} - -#[tokio::test] -async fn fail_account_init_after_mint_extension() { - let context = TestContext::new().await; - let mut ctx = context.context.lock().await; - let rent = ctx.banks_client.get_rent().await.unwrap(); - let mint_account = Keypair::new(); - let mint_authority_pubkey = Pubkey::new_unique(); - let token_account = Keypair::new(); - - let mint_space = ExtensionType::get_account_len::(&[]); - let account_space = - ExtensionType::get_account_len::(&[ExtensionType::MintCloseAuthority]); - let instructions = vec![ - system_instruction::create_account( - &ctx.payer.pubkey(), - &mint_account.pubkey(), - rent.minimum_balance(mint_space), - mint_space as u64, - &spl_token_2022::id(), - ), - instruction::initialize_mint( - &spl_token_2022::id(), - &mint_account.pubkey(), - &mint_authority_pubkey, - None, - 9, - ) - .unwrap(), - system_instruction::create_account( - &ctx.payer.pubkey(), - &token_account.pubkey(), - rent.minimum_balance(account_space), - account_space as u64, - &spl_token_2022::id(), - ), - instruction::initialize_mint_close_authority( - &spl_token_2022::id(), - &token_account.pubkey(), - Some(&mint_authority_pubkey), - ) - .unwrap(), - instruction::initialize_account( - &spl_token_2022::id(), - &token_account.pubkey(), - &mint_account.pubkey(), - &mint_authority_pubkey, - ) - .unwrap(), - ]; - - let tx = Transaction::new_signed_with_payer( - &instructions, - Some(&ctx.payer.pubkey()), - &[&ctx.payer, &mint_account, &token_account], - ctx.last_blockhash, - ); - #[allow(clippy::useless_conversion)] - let err: TransactionError = ctx - .banks_client - .process_transaction(tx) - .await - .unwrap_err() - .unwrap() - .into(); - assert_eq!( - err, - TransactionError::InstructionError( - 4, - InstructionError::Custom(TokenError::ExtensionBaseMismatch as u32) - ) - ); -} - -#[tokio::test] -async fn fail_account_init_after_mint_init() { - let context = TestContext::new().await; - let mut ctx = context.context.lock().await; - let rent = ctx.banks_client.get_rent().await.unwrap(); - let mint_account = Keypair::new(); - let mint_authority_pubkey = Pubkey::new_unique(); - - let mint_space = ExtensionType::get_account_len::(&[]); - let instructions = vec![ - system_instruction::create_account( - &ctx.payer.pubkey(), - &mint_account.pubkey(), - rent.minimum_balance(mint_space), - mint_space as u64, - &spl_token_2022::id(), - ), - instruction::initialize_mint( - &spl_token_2022::id(), - &mint_account.pubkey(), - &mint_authority_pubkey, - None, - 9, - ) - .unwrap(), - instruction::initialize_account( - &spl_token_2022::id(), - &mint_account.pubkey(), - &mint_account.pubkey(), - &mint_authority_pubkey, - ) - .unwrap(), - ]; - - let tx = Transaction::new_signed_with_payer( - &instructions, - Some(&ctx.payer.pubkey()), - &[&ctx.payer, &mint_account], - ctx.last_blockhash, - ); - #[allow(clippy::useless_conversion)] - let err: TransactionError = ctx - .banks_client - .process_transaction(tx) - .await - .unwrap_err() - .unwrap() - .into(); - assert_eq!( - err, - TransactionError::InstructionError(2, InstructionError::InvalidAccountData) - ); -} - -#[tokio::test] -async fn fail_account_init_after_mint_init_with_extension() { - let context = TestContext::new().await; - let mut ctx = context.context.lock().await; - let rent = ctx.banks_client.get_rent().await.unwrap(); - let mint_account = Keypair::new(); - let mint_authority_pubkey = Pubkey::new_unique(); - - let mint_space = ExtensionType::get_account_len::(&[ExtensionType::MintCloseAuthority]); - let instructions = vec![ - system_instruction::create_account( - &ctx.payer.pubkey(), - &mint_account.pubkey(), - rent.minimum_balance(mint_space), - mint_space as u64, - &spl_token_2022::id(), - ), - instruction::initialize_mint_close_authority( - &spl_token_2022::id(), - &mint_account.pubkey(), - Some(&mint_authority_pubkey), - ) - .unwrap(), - instruction::initialize_mint( - &spl_token_2022::id(), - &mint_account.pubkey(), - &mint_authority_pubkey, - None, - 9, - ) - .unwrap(), - instruction::initialize_account( - &spl_token_2022::id(), - &mint_account.pubkey(), - &mint_account.pubkey(), - &mint_authority_pubkey, - ) - .unwrap(), - ]; - - let tx = Transaction::new_signed_with_payer( - &instructions, - Some(&ctx.payer.pubkey()), - &[&ctx.payer, &mint_account], - ctx.last_blockhash, - ); - #[allow(clippy::useless_conversion)] - let err: TransactionError = ctx - .banks_client - .process_transaction(tx) - .await - .unwrap_err() - .unwrap() - .into(); - assert_eq!( - err, - TransactionError::InstructionError(3, InstructionError::InvalidAccountData) - ); -} - -#[tokio::test] -async fn fail_fee_init_after_mint_init() { - let context = TestContext::new().await; - let mut ctx = context.context.lock().await; - let rent = ctx.banks_client.get_rent().await.unwrap(); - let mint_account = Keypair::new(); - let mint_authority_pubkey = Pubkey::new_unique(); - - let space = ExtensionType::get_account_len::(&[ExtensionType::TransferFeeConfig]); - let instructions = vec![ - system_instruction::create_account( - &ctx.payer.pubkey(), - &mint_account.pubkey(), - rent.minimum_balance(space), - space as u64, - &spl_token_2022::id(), - ), - instruction::initialize_mint( - &spl_token_2022::id(), - &mint_account.pubkey(), - &mint_authority_pubkey, - None, - 9, - ) - .unwrap(), - transfer_fee::instruction::initialize_transfer_fee_config( - &spl_token_2022::id(), - &mint_account.pubkey(), - Some(&Pubkey::new_unique()), - Some(&Pubkey::new_unique()), - 10, - 100, - ) - .unwrap(), - ]; - - let tx = Transaction::new_signed_with_payer( - &instructions, - Some(&ctx.payer.pubkey()), - &[&ctx.payer, &mint_account], - ctx.last_blockhash, - ); - #[allow(clippy::useless_conversion)] - let err: TransactionError = ctx - .banks_client - .process_transaction(tx) - .await - .unwrap_err() - .unwrap() - .into(); - assert_eq!( - err, - TransactionError::InstructionError(1, InstructionError::InvalidAccountData) - ); -} - -#[tokio::test] -async fn create_native_mint() { - let mut context = TestContext::new().await; - context.init_token_with_native_mint().await.unwrap(); - let TokenContext { token, .. } = context.token_context.unwrap(); - - let mint = token.get_mint_info().await.unwrap(); - assert_eq!(mint.base.decimals, native_mint::DECIMALS); - assert_eq!(mint.base.mint_authority, COption::None,); - assert_eq!(mint.base.supply, 0); - assert!(mint.base.is_initialized); - assert_eq!(mint.base.freeze_authority, COption::None); -} diff --git a/token/program-2022-test/tests/interest_bearing_mint.rs b/token/program-2022-test/tests/interest_bearing_mint.rs deleted file mode 100644 index 8fc2d116af9..00000000000 --- a/token/program-2022-test/tests/interest_bearing_mint.rs +++ /dev/null @@ -1,347 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod program_test; -use { - program_test::{keypair_clone, TestContext, TokenContext}, - solana_program_test::{ - processor, - tokio::{self, sync::Mutex}, - ProgramTest, - }, - solana_sdk::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - instruction::{AccountMeta, Instruction, InstructionError}, - msg, - program::{get_return_data, invoke}, - program_error::ProgramError, - pubkey::Pubkey, - signature::Signer, - signer::keypair::Keypair, - transaction::{Transaction, TransactionError}, - transport::TransportError, - }, - spl_token_2022::{ - error::TokenError, - extension::interest_bearing_mint::InterestBearingConfig, - instruction::{amount_to_ui_amount, ui_amount_to_amount, AuthorityType}, - processor::Processor, - }, - spl_token_client::token::{ExtensionInitializationParams, TokenError as TokenClientError}, - std::{convert::TryInto, sync::Arc}, -}; - -#[tokio::test] -async fn success_initialize() { - for (rate, rate_authority) in [(i16::MIN, None), (i16::MAX, Some(Pubkey::new_unique()))] { - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::InterestBearingConfig { - rate_authority, - rate, - }]) - .await - .unwrap(); - let TokenContext { token, .. } = context.token_context.unwrap(); - - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!( - Option::::from(extension.rate_authority), - rate_authority, - ); - assert_eq!(i16::from(extension.current_rate), rate,); - assert_eq!(i16::from(extension.pre_update_average_rate), rate,); - } -} - -#[tokio::test] -async fn update_rate() { - let rate_authority = Keypair::new(); - let initial_rate = 500; - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::InterestBearingConfig { - rate_authority: Some(rate_authority.pubkey()), - rate: initial_rate, - }]) - .await - .unwrap(); - let TokenContext { token, .. } = context.token_context.take().unwrap(); - - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!(i16::from(extension.current_rate), initial_rate); - assert_eq!(i16::from(extension.pre_update_average_rate), initial_rate); - let initialization_timestamp = i64::from(extension.initialization_timestamp); - assert_eq!( - extension.initialization_timestamp, - extension.last_update_timestamp - ); - - // warp forward, so last update timestamp is advanced during update - let warp_slot = 1_000; - let initial_num_warps = 10; - for i in 1..initial_num_warps { - context - .context - .lock() - .await - .warp_to_slot(i * warp_slot) - .unwrap(); - } - - // correct - let middle_rate = 1_000; - token - .update_interest_rate(&rate_authority, middle_rate) - .await - .unwrap(); - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!(i16::from(extension.current_rate), middle_rate); - assert_eq!(i16::from(extension.pre_update_average_rate), initial_rate); - let last_update_timestamp = i64::from(extension.last_update_timestamp); - assert!(last_update_timestamp > initialization_timestamp); - - // warp forward - let final_num_warps = 20; - for i in initial_num_warps..final_num_warps { - context - .context - .lock() - .await - .warp_to_slot(i * warp_slot) - .unwrap(); - } - - // update again, pre_update_average_rate is between the two previous - let new_rate = 2_000; - token - .update_interest_rate(&rate_authority, new_rate) - .await - .unwrap(); - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!(i16::from(extension.current_rate), new_rate); - let pre_update_average_rate = i16::from(extension.pre_update_average_rate); - assert!(pre_update_average_rate > initial_rate); - assert!(middle_rate > pre_update_average_rate); - let final_update_timestamp = i64::from(extension.last_update_timestamp); - assert!(final_update_timestamp > last_update_timestamp); - - // wrong signer - let err = token - .update_interest_rate(&Keypair::new(), 0) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::OwnerMismatch as u32) - ) - ))) - ); -} - -#[tokio::test] -async fn set_authority() { - let rate_authority = Keypair::new(); - let initial_rate = 500; - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::InterestBearingConfig { - rate_authority: Some(rate_authority.pubkey()), - rate: initial_rate, - }]) - .await - .unwrap(); - let TokenContext { token, .. } = context.token_context.take().unwrap(); - - // success - let new_rate_authority = Keypair::new(); - token - .set_authority( - token.get_address(), - Some(&new_rate_authority.pubkey()), - AuthorityType::InterestRate, - &rate_authority, - ) - .await - .unwrap(); - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!( - extension.rate_authority, - Some(new_rate_authority.pubkey()).try_into().unwrap(), - ); - token - .update_interest_rate(&new_rate_authority, 10) - .await - .unwrap(); - let err = token - .update_interest_rate(&rate_authority, 100) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::OwnerMismatch as u32) - ) - ))) - ); - - // set to none - token - .set_authority( - token.get_address(), - None, - AuthorityType::InterestRate, - &new_rate_authority, - ) - .await - .unwrap(); - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!(extension.rate_authority, None.try_into().unwrap(),); - - // now all fail - let err = token - .update_interest_rate(&new_rate_authority, 50) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::NoAuthorityExists as u32) - ) - ))) - ); - let err = token - .update_interest_rate(&rate_authority, 5) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::NoAuthorityExists as u32) - ) - ))) - ); -} - -// test program to CPI into token to get ui amounts -fn process_instruction( - _program_id: &Pubkey, - accounts: &[AccountInfo], - _input: &[u8], -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_info = next_account_info(account_info_iter)?; - let token_program = next_account_info(account_info_iter)?; - // 10 tokens, with 9 decimal places - let test_amount = 10_000_000_000; - // "10" as an amount should be smaller than test_amount due to interest - invoke( - &ui_amount_to_amount(token_program.key, mint_info.key, "10")?, - &[mint_info.clone(), token_program.clone()], - )?; - let (_, return_data) = get_return_data().unwrap(); - let amount = u64::from_le_bytes(return_data[0..8].try_into().unwrap()); - msg!("amount: {}", amount); - if amount >= test_amount { - return Err(ProgramError::InvalidInstructionData); - } - - // test_amount as a UI amount should be larger due to interest - invoke( - &amount_to_ui_amount(token_program.key, mint_info.key, test_amount)?, - &[mint_info.clone(), token_program.clone()], - )?; - let (_, return_data) = get_return_data().unwrap(); - let ui_amount = String::from_utf8(return_data).unwrap(); - msg!("ui amount: {}", ui_amount); - let float_ui_amount = ui_amount.parse::().unwrap(); - if float_ui_amount <= 10.0 { - return Err(ProgramError::InvalidInstructionData); - } - Ok(()) -} - -#[tokio::test] -async fn amount_conversions() { - let rate_authority = Keypair::new(); - let mut program_test = ProgramTest::default(); - program_test.prefer_bpf(false); - program_test.add_program( - "spl_token_2022", - spl_token_2022::id(), - processor!(Processor::process), - ); - let program_id = Pubkey::new_unique(); - program_test.add_program( - "ui_amount_to_amount", - program_id, - processor!(process_instruction), - ); - - let context = program_test.start_with_context().await; - let payer = keypair_clone(&context.payer); - let last_blockhash = context.last_blockhash; - let context = Arc::new(Mutex::new(context)); - let mut context = TestContext { - context, - token_context: None, - }; - let initial_rate = i16::MAX; - context - .init_token_with_mint(vec![ExtensionInitializationParams::InterestBearingConfig { - rate_authority: Some(rate_authority.pubkey()), - rate: initial_rate, - }]) - .await - .unwrap(); - let TokenContext { token, .. } = context.token_context.take().unwrap(); - - // warp forward, so interest is accrued - let warp_slot = 1_000; - let initial_num_warps = 10; - for i in 1..initial_num_warps { - context - .context - .lock() - .await - .warp_to_slot(i * warp_slot) - .unwrap(); - } - - let transaction = Transaction::new_signed_with_payer( - &[Instruction { - program_id, - accounts: vec![ - AccountMeta::new_readonly(*token.get_address(), false), - AccountMeta::new_readonly(spl_token_2022::id(), false), - ], - data: vec![], - }], - Some(&payer.pubkey()), - &[&payer], - last_blockhash, - ); - context - .context - .lock() - .await - .banks_client - .process_transaction(transaction) - .await - .unwrap(); -} diff --git a/token/program-2022-test/tests/memo_transfer.rs b/token/program-2022-test/tests/memo_transfer.rs deleted file mode 100644 index dce23f8bb45..00000000000 --- a/token/program-2022-test/tests/memo_transfer.rs +++ /dev/null @@ -1,222 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod program_test; -use { - program_test::{TestContext, TokenContext}, - solana_program_test::{ - tokio::{self, sync::Mutex}, - ProgramTestContext, - }, - solana_sdk::{ - instruction::InstructionError, - pubkey::Pubkey, - signature::Signer, - system_instruction, - transaction::{Transaction, TransactionError}, - transport::TransportError, - }, - spl_token_2022::{ - error::TokenError, - extension::{memo_transfer::MemoTransfer, ExtensionType}, - }, - spl_token_client::token::TokenError as TokenClientError, - std::sync::Arc, -}; - -async fn test_memo_transfers( - context: Arc>, - token_context: TokenContext, - alice_account: Pubkey, - bob_account: Pubkey, -) { - let TokenContext { - mint_authority, - token, - alice, - bob, - .. - } = token_context; - - // mint tokens - token - .mint_to(&alice_account, &mint_authority, 4242) - .await - .unwrap(); - - // require memo transfers into bob_account - token - .enable_required_transfer_memos(&bob_account, &bob) - .await - .unwrap(); - - let bob_state = token.get_account_info(&bob_account).await.unwrap(); - let extension = bob_state.get_extension::().unwrap(); - assert!(bool::from(extension.require_incoming_transfer_memos)); - - // attempt to transfer from alice to bob without memo - let err = token - .transfer_unchecked(&alice_account, &bob_account, &alice, 10) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::NoMemo as u32) - ) - ))) - ); - let bob_state = token.get_account_info(&bob_account).await.unwrap(); - assert_eq!(bob_state.base.amount, 0); - - // attempt to transfer from alice to bob with misplaced memo, v1 and current - let mut memo_ix = spl_memo::build_memo(&[240, 159, 166, 150], &[]); - for program_id in [spl_memo::id(), spl_memo::v1::id()] { - let mut ctx = context.lock().await; - memo_ix.program_id = program_id; - #[allow(deprecated)] - let instructions = vec![ - memo_ix.clone(), - system_instruction::transfer(&ctx.payer.pubkey(), &alice.pubkey(), 42), - spl_token_2022::instruction::transfer( - &spl_token_2022::id(), - &alice_account, - &bob_account, - &alice.pubkey(), - &[], - 10, - ) - .unwrap(), - ]; - let tx = Transaction::new_signed_with_payer( - &instructions, - Some(&ctx.payer.pubkey()), - &[&ctx.payer, &alice], - ctx.last_blockhash, - ); - #[allow(clippy::useless_conversion)] - let err: TransactionError = ctx - .banks_client - .process_transaction(tx) - .await - .unwrap_err() - .unwrap() - .into(); - drop(ctx); - assert_eq!( - err, - TransactionError::InstructionError( - 2, - InstructionError::Custom(TokenError::NoMemo as u32) - ) - ); - let bob_state = token.get_account_info(&bob_account).await.unwrap(); - assert_eq!(bob_state.base.amount, 0); - } - - // transfer with memo - token - .with_memo("🦖") - .transfer_unchecked(&alice_account, &bob_account, &alice, 10) - .await - .unwrap(); - let bob_state = token.get_account_info(&bob_account).await.unwrap(); - assert_eq!(bob_state.base.amount, 10); - - // transfer with memo v1 - let mut ctx = context.lock().await; - memo_ix.program_id = spl_memo::v1::id(); - #[allow(deprecated)] - let instructions = vec![ - memo_ix, - spl_token_2022::instruction::transfer( - &spl_token_2022::id(), - &alice_account, - &bob_account, - &alice.pubkey(), - &[], - 11, - ) - .unwrap(), - ]; - let tx = Transaction::new_signed_with_payer( - &instructions, - Some(&ctx.payer.pubkey()), - &[&ctx.payer, &alice], - ctx.last_blockhash, - ); - ctx.banks_client.process_transaction(tx).await.unwrap(); - drop(ctx); - let bob_state = token.get_account_info(&bob_account).await.unwrap(); - assert_eq!(bob_state.base.amount, 21); - - // stop requiring memo transfers into bob_account - token - .disable_required_transfer_memos(&bob_account, &bob) - .await - .unwrap(); - - // transfer from alice to bob without memo - token - .transfer_unchecked(&alice_account, &bob_account, &alice, 12) - .await - .unwrap(); - let bob_state = token.get_account_info(&bob_account).await.unwrap(); - assert_eq!(bob_state.base.amount, 33); -} - -#[tokio::test] -async fn require_memo_transfers_without_realloc() { - let mut context = TestContext::new().await; - context.init_token_with_mint(vec![]).await.unwrap(); - let token_context = context.token_context.unwrap(); - - // create token accounts - let alice_account = token_context - .token - .create_auxiliary_token_account(&token_context.alice, &token_context.alice.pubkey()) - .await - .unwrap(); - let bob_account = token_context - .token - .create_auxiliary_token_account_with_extension_space( - &token_context.bob, - &token_context.bob.pubkey(), - vec![ExtensionType::MemoTransfer], - ) - .await - .unwrap(); - - test_memo_transfers(context.context, token_context, alice_account, bob_account).await; -} - -#[tokio::test] -async fn require_memo_transfers_with_realloc() { - let mut context = TestContext::new().await; - context.init_token_with_mint(vec![]).await.unwrap(); - let token_context = context.token_context.unwrap(); - - // create token accounts - let alice_account = token_context - .token - .create_auxiliary_token_account(&token_context.alice, &token_context.alice.pubkey()) - .await - .unwrap(); - let bob_account = token_context - .token - .create_auxiliary_token_account(&token_context.bob, &token_context.bob.pubkey()) - .await - .unwrap(); - token_context - .token - .reallocate( - &token_context.bob.pubkey(), - &token_context.bob, - &[ExtensionType::MemoTransfer], - ) - .await - .unwrap(); - - test_memo_transfers(context.context, token_context, alice_account, bob_account).await; -} diff --git a/token/program-2022-test/tests/mint_close_authority.rs b/token/program-2022-test/tests/mint_close_authority.rs deleted file mode 100644 index e9b02b7957f..00000000000 --- a/token/program-2022-test/tests/mint_close_authority.rs +++ /dev/null @@ -1,256 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod program_test; -use { - program_test::{TestContext, TokenContext}, - solana_program_test::tokio, - solana_sdk::{ - instruction::InstructionError, program_option::COption, pubkey::Pubkey, signature::Signer, - signer::keypair::Keypair, transaction::TransactionError, transport::TransportError, - }, - spl_token_2022::{ - error::TokenError, extension::mint_close_authority::MintCloseAuthority, instruction, - }, - spl_token_client::token::{ExtensionInitializationParams, TokenError as TokenClientError}, - std::convert::TryInto, -}; - -#[tokio::test] -async fn success_init() { - let close_authority = Some(Pubkey::new_unique()); - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::MintCloseAuthority { - close_authority, - }]) - .await - .unwrap(); - let TokenContext { - decimals, - mint_authority, - token, - .. - } = context.token_context.unwrap(); - - let state = token.get_mint_info().await.unwrap(); - assert_eq!(state.base.decimals, decimals); - assert_eq!( - state.base.mint_authority, - COption::Some(mint_authority.pubkey()) - ); - assert_eq!(state.base.supply, 0); - assert!(state.base.is_initialized); - assert_eq!(state.base.freeze_authority, COption::None); - let extension = state.get_extension::().unwrap(); - assert_eq!( - extension.close_authority, - close_authority.try_into().unwrap(), - ); -} - -#[tokio::test] -async fn set_authority() { - let close_authority = Keypair::new(); - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::MintCloseAuthority { - close_authority: Some(close_authority.pubkey()), - }]) - .await - .unwrap(); - let token = context.token_context.unwrap().token; - let new_authority = Keypair::new(); - - // fail, wrong signature - let wrong = Keypair::new(); - let err = token - .set_authority( - token.get_address(), - Some(&new_authority.pubkey()), - instruction::AuthorityType::CloseMint, - &wrong, - ) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::OwnerMismatch as u32) - ) - ))) - ); - - // success - token - .set_authority( - token.get_address(), - Some(&new_authority.pubkey()), - instruction::AuthorityType::CloseMint, - &close_authority, - ) - .await - .unwrap(); - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!( - extension.close_authority, - Some(new_authority.pubkey()).try_into().unwrap(), - ); - - // set to none - token - .set_authority( - token.get_address(), - None, - instruction::AuthorityType::CloseMint, - &new_authority, - ) - .await - .unwrap(); - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!(extension.close_authority, None.try_into().unwrap(),); - - // fail set again - let err = token - .set_authority( - token.get_address(), - Some(&close_authority.pubkey()), - instruction::AuthorityType::CloseMint, - &new_authority, - ) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::AuthorityTypeNotSupported as u32) - ) - ))) - ); - - // fail close - let destination = Pubkey::new_unique(); - let err = token - .close_account(token.get_address(), &destination, &new_authority) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::AuthorityTypeNotSupported as u32) - ) - ))) - ); -} - -#[tokio::test] -async fn success_close() { - let close_authority = Keypair::new(); - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::MintCloseAuthority { - close_authority: Some(close_authority.pubkey()), - }]) - .await - .unwrap(); - let token = context.token_context.unwrap().token; - - let destination = Pubkey::new_unique(); - token - .close_account(token.get_address(), &destination, &close_authority) - .await - .unwrap(); - let destination = token.get_account(&destination).await.unwrap(); - assert!(destination.lamports > 0); -} - -#[tokio::test] -async fn fail_without_extension() { - let close_authority = Pubkey::new_unique(); - let mut context = TestContext::new().await; - context.init_token_with_mint(vec![]).await.unwrap(); - let TokenContext { - mint_authority, - token, - .. - } = context.token_context.unwrap(); - - // fail set - let err = token - .set_authority( - token.get_address(), - Some(&close_authority), - instruction::AuthorityType::CloseMint, - &mint_authority, - ) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError(0, InstructionError::InvalidAccountData) - ))) - ); - - // fail close - let destination = Pubkey::new_unique(); - let err = token - .close_account(token.get_address(), &destination, &mint_authority) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError(0, InstructionError::InvalidAccountData) - ))) - ); -} - -#[tokio::test] -async fn fail_close_with_supply() { - let close_authority = Keypair::new(); - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::MintCloseAuthority { - close_authority: Some(close_authority.pubkey()), - }]) - .await - .unwrap(); - let TokenContext { - mint_authority, - token, - .. - } = context.token_context.unwrap(); - - // mint a token - let owner = Pubkey::new_unique(); - let account = Keypair::new(); - let account = token - .create_auxiliary_token_account(&account, &owner) - .await - .unwrap(); - token.mint_to(&account, &mint_authority, 1).await.unwrap(); - - // fail close - let destination = Pubkey::new_unique(); - let err = token - .close_account(token.get_address(), &destination, &close_authority) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::MintHasSupply as u32) - ) - ))) - ); -} diff --git a/token/program-2022-test/tests/program_test.rs b/token/program-2022-test/tests/program_test.rs deleted file mode 100644 index 80e979e6787..00000000000 --- a/token/program-2022-test/tests/program_test.rs +++ /dev/null @@ -1,124 +0,0 @@ -#![allow(dead_code)] - -use { - solana_program_test::{processor, tokio::sync::Mutex, ProgramTest, ProgramTestContext}, - solana_sdk::signer::{keypair::Keypair, Signer}, - spl_token_2022::{id, native_mint, processor::Processor}, - spl_token_client::{ - client::{ProgramBanksClient, ProgramBanksClientProcessTransaction, ProgramClient}, - token::{ExtensionInitializationParams, Token, TokenResult}, - }, - std::sync::Arc, -}; - -pub struct TokenContext { - pub decimals: u8, - pub mint_authority: Keypair, - pub token: Token, - pub alice: Keypair, - pub bob: Keypair, - pub freeze_authority: Option, -} - -pub struct TestContext { - pub context: Arc>, - pub token_context: Option, -} - -impl TestContext { - pub async fn new() -> Self { - let program_test = ProgramTest::new("spl_token_2022", id(), processor!(Processor::process)); - let context = program_test.start_with_context().await; - let context = Arc::new(Mutex::new(context)); - - Self { - context, - token_context: None, - } - } - - pub async fn init_token_with_mint( - &mut self, - extension_init_params: Vec, - ) -> TokenResult<()> { - self._init_token_with_mint(extension_init_params, None) - .await - } - - pub async fn init_token_with_freezing_mint( - &mut self, - extension_init_params: Vec, - ) -> TokenResult<()> { - let freeze_authority = Keypair::new(); - self._init_token_with_mint(extension_init_params, Some(freeze_authority)) - .await - } - - pub async fn _init_token_with_mint( - &mut self, - extension_init_params: Vec, - freeze_authority: Option, - ) -> TokenResult<()> { - let payer = keypair_clone(&self.context.lock().await.payer); - let client: Arc> = - Arc::new(ProgramBanksClient::new_from_context( - Arc::clone(&self.context), - ProgramBanksClientProcessTransaction, - )); - - let decimals: u8 = 9; - - let mint_account = Keypair::new(); - let mint_authority = Keypair::new(); - let mint_authority_pubkey = mint_authority.pubkey(); - let freeze_authority_pubkey = freeze_authority - .as_ref() - .map(|authority| authority.pubkey()); - - let token = Token::create_mint( - Arc::clone(&client), - &id(), - payer, - &mint_account, - &mint_authority_pubkey, - freeze_authority_pubkey.as_ref(), - decimals, - extension_init_params, - ) - .await?; - self.token_context = Some(TokenContext { - decimals, - mint_authority, - token, - alice: Keypair::new(), - bob: Keypair::new(), - freeze_authority, - }); - - Ok(()) - } - - pub async fn init_token_with_native_mint(&mut self) -> TokenResult<()> { - let payer = keypair_clone(&self.context.lock().await.payer); - let client: Arc> = - Arc::new(ProgramBanksClient::new_from_context( - Arc::clone(&self.context), - ProgramBanksClientProcessTransaction, - )); - - let token = Token::create_native_mint(Arc::clone(&client), &id(), payer).await?; - self.token_context = Some(TokenContext { - decimals: native_mint::DECIMALS, - mint_authority: Keypair::new(), /*bogus*/ - token, - alice: Keypair::new(), - bob: Keypair::new(), - freeze_authority: None, - }); - Ok(()) - } -} - -pub(crate) fn keypair_clone(kp: &Keypair) -> Keypair { - Keypair::from_bytes(&kp.to_bytes()).expect("failed to copy keypair") -} diff --git a/token/program-2022-test/tests/reallocate.rs b/token/program-2022-test/tests/reallocate.rs deleted file mode 100644 index e1783e94391..00000000000 --- a/token/program-2022-test/tests/reallocate.rs +++ /dev/null @@ -1,165 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod program_test; -use { - program_test::{TestContext, TokenContext}, - solana_program_test::tokio, - solana_sdk::{ - instruction::InstructionError, program_option::COption, pubkey::Pubkey, signature::Signer, - signer::keypair::Keypair, transaction::TransactionError, transport::TransportError, - }, - spl_token_2022::{error::TokenError, extension::ExtensionType, state::Account}, - spl_token_client::token::{ExtensionInitializationParams, TokenError as TokenClientError}, - std::convert::TryInto, -}; - -#[tokio::test] -async fn reallocate() { - let mut context = TestContext::new().await; - context.init_token_with_mint(vec![]).await.unwrap(); - let TokenContext { - token, - alice, - mint_authority, - .. - } = context.token_context.unwrap(); - - // reallocate fails on wrong account type - let error = token - .reallocate( - token.get_address(), - &mint_authority, - &[ExtensionType::ImmutableOwner], - ) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError(0, InstructionError::InvalidAccountData) - ))) - ); - - // create account just large enough for base - let alice_account = Keypair::new(); - let alice_account = token - .create_auxiliary_token_account(&alice_account, &alice.pubkey()) - .await - .unwrap(); - - // reallocate fails on invalid extension type - let error = token - .reallocate(&alice_account, &alice, &[ExtensionType::MintCloseAuthority]) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::InvalidState as u32) - ) - ))) - ); - - // reallocate fails on invalid authority - let error = token - .reallocate( - &alice_account, - &mint_authority, - &[ExtensionType::ImmutableOwner], - ) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::OwnerMismatch as u32) - ) - ))) - ); - - // reallocate succeeds - token - .reallocate(&alice_account, &alice, &[ExtensionType::ImmutableOwner]) - .await - .unwrap(); - let account = token.get_account(&alice_account).await.unwrap(); - assert_eq!( - account.data.len(), - ExtensionType::get_account_len::(&[ExtensionType::ImmutableOwner]) - ); - - // reallocate succeeds with noop if account is already large enough - token.get_new_latest_blockhash().await.unwrap(); - token - .reallocate(&alice_account, &alice, &[ExtensionType::ImmutableOwner]) - .await - .unwrap(); - let account = token.get_account(&alice_account).await.unwrap(); - assert_eq!( - account.data.len(), - ExtensionType::get_account_len::(&[ExtensionType::ImmutableOwner]) - ); - - // reallocate only reallocates enough for new extension, and dedupes extensions - token - .reallocate( - &alice_account, - &alice, - &[ - ExtensionType::ImmutableOwner, - ExtensionType::ImmutableOwner, - ExtensionType::TransferFeeAmount, - ExtensionType::TransferFeeAmount, - ], - ) - .await - .unwrap(); - let account = token.get_account(&alice_account).await.unwrap(); - assert_eq!( - account.data.len(), - ExtensionType::get_account_len::(&[ - ExtensionType::ImmutableOwner, - ExtensionType::TransferFeeAmount - ]) - ); -} - -#[tokio::test] -async fn reallocate_without_current_extension_knowledge() { - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::TransferFeeConfig { - transfer_fee_config_authority: COption::Some(Pubkey::new_unique()).try_into().unwrap(), - withdraw_withheld_authority: COption::Some(Pubkey::new_unique()).try_into().unwrap(), - transfer_fee_basis_points: 250, - maximum_fee: 10_000_000, - }]) - .await - .unwrap(); - let TokenContext { token, alice, .. } = context.token_context.unwrap(); - - // create account just large enough for TransferFeeAmount extension - let alice_account = Keypair::new(); - let alice_account = token - .create_auxiliary_token_account(&alice_account, &alice.pubkey()) - .await - .unwrap(); - - // reallocate resizes account to accommodate new and existing extensions - token - .reallocate(&alice_account, &alice, &[ExtensionType::ImmutableOwner]) - .await - .unwrap(); - let account = token.get_account(&alice_account).await.unwrap(); - assert_eq!( - account.data.len(), - ExtensionType::get_account_len::(&[ - ExtensionType::TransferFeeAmount, - ExtensionType::ImmutableOwner - ]) - ); -} diff --git a/token/program-2022-test/tests/sync_native.rs b/token/program-2022-test/tests/sync_native.rs deleted file mode 100644 index 0b99149c900..00000000000 --- a/token/program-2022-test/tests/sync_native.rs +++ /dev/null @@ -1,82 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod program_test; -use { - program_test::{TestContext, TokenContext}, - solana_program_test::{ - tokio::{self, sync::Mutex}, - ProgramTestContext, - }, - solana_sdk::{ - pubkey::Pubkey, signature::Signer, signer::keypair::Keypair, system_instruction, - transaction::Transaction, - }, - spl_token_2022::extension::ExtensionType, - spl_token_client::{client::ProgramBanksClientProcessTransaction, token::Token}, - std::sync::Arc, -}; - -async fn run_basic( - token: Token, - context: Arc>, - account: Pubkey, -) { - let account_info = token.get_account_info(&account).await.unwrap(); - assert_eq!(account_info.base.amount, 0); - - // system transfer to account - let amount = 1_000; - { - let mut context = context.lock().await; - let instructions = vec![system_instruction::transfer( - &context.payer.pubkey(), - &account, - amount, - )]; - let tx = Transaction::new_signed_with_payer( - &instructions, - Some(&context.payer.pubkey()), - &[&context.payer], - context.last_blockhash, - ); - context.banks_client.process_transaction(tx).await.unwrap(); - } - let account_info = token.get_account_info(&account).await.unwrap(); - assert_eq!(account_info.base.amount, 0); - - token.sync_native(&account).await.unwrap(); - let account_info = token.get_account_info(&account).await.unwrap(); - assert_eq!(account_info.base.amount, amount); -} - -#[tokio::test] -async fn basic() { - let mut context = TestContext::new().await; - context.init_token_with_native_mint().await.unwrap(); - let TokenContext { token, alice, .. } = context.token_context.unwrap(); - let context = context.context.clone(); - - let account = token - .create_auxiliary_token_account(&Keypair::new(), &alice.pubkey()) - .await - .unwrap(); - run_basic(token, context, account).await; -} - -#[tokio::test] -async fn basic_with_extension() { - let mut context = TestContext::new().await; - context.init_token_with_native_mint().await.unwrap(); - let TokenContext { token, alice, .. } = context.token_context.unwrap(); - let context = context.context.clone(); - - let account = token - .create_auxiliary_token_account_with_extension_space( - &Keypair::new(), - &alice.pubkey(), - vec![ExtensionType::ImmutableOwner], - ) - .await - .unwrap(); - run_basic(token, context, account).await; -} diff --git a/token/program-2022-test/tests/transfer.rs b/token/program-2022-test/tests/transfer.rs deleted file mode 100644 index 5e52fa01d66..00000000000 --- a/token/program-2022-test/tests/transfer.rs +++ /dev/null @@ -1,309 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod program_test; -use { - program_test::{TestContext, TokenContext}, - solana_program_test::tokio, - solana_sdk::{ - instruction::InstructionError, pubkey::Pubkey, signature::Signer, signer::keypair::Keypair, - transaction::TransactionError, transport::TransportError, - }, - spl_token_2022::error::TokenError, - spl_token_client::token::{ExtensionInitializationParams, TokenError as TokenClientError}, -}; - -#[derive(PartialEq)] -enum TestMode { - All, - CheckedOnly, -} - -async fn run_basic_transfers(context: TestContext, test_mode: TestMode) { - let TokenContext { - decimals, - mint_authority, - token, - alice, - bob, - .. - } = context.token_context.unwrap(); - - let alice_account = Keypair::new(); - let alice_account = token - .create_auxiliary_token_account(&alice_account, &alice.pubkey()) - .await - .unwrap(); - let bob_account = Keypair::new(); - let bob_account = token - .create_auxiliary_token_account(&bob_account, &bob.pubkey()) - .await - .unwrap(); - - // mint a token - let amount = 10; - token - .mint_to(&alice_account, &mint_authority, amount) - .await - .unwrap(); - - if test_mode == TestMode::All { - // unchecked is ok - token - .transfer_unchecked(&alice_account, &bob_account, &alice, 1) - .await - .unwrap(); - } - - // checked is ok - token - .transfer_checked(&alice_account, &bob_account, &alice, 1, decimals) - .await - .unwrap(); - - // transfer too much is not ok - let error = token - .transfer_checked(&alice_account, &bob_account, &alice, amount, decimals) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::InsufficientFunds as u32) - ) - ))) - ); - - // wrong signer - let error = token - .transfer_checked(&alice_account, &bob_account, &bob, 1, decimals) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::OwnerMismatch as u32) - ) - ))) - ); -} - -#[tokio::test] -async fn basic() { - let mut context = TestContext::new().await; - context.init_token_with_mint(vec![]).await.unwrap(); - run_basic_transfers(context, TestMode::All).await; -} - -#[tokio::test] -async fn basic_with_extension() { - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::TransferFeeConfig { - transfer_fee_config_authority: Some(Pubkey::new_unique()), - withdraw_withheld_authority: Some(Pubkey::new_unique()), - transfer_fee_basis_points: 100u16, - maximum_fee: 1_000_000u64, - }]) - .await - .unwrap(); - run_basic_transfers(context, TestMode::CheckedOnly).await; -} - -async fn run_self_transfers(context: TestContext, test_mode: TestMode) { - let TokenContext { - decimals, - mint_authority, - token, - alice, - .. - } = context.token_context.unwrap(); - - let alice_account = Keypair::new(); - let alice_account = token - .create_auxiliary_token_account(&alice_account, &alice.pubkey()) - .await - .unwrap(); - - // mint a token - let amount = 10; - token - .mint_to(&alice_account, &mint_authority, amount) - .await - .unwrap(); - - // self transfer is ok - token - .transfer_checked(&alice_account, &alice_account, &alice, 1, decimals) - .await - .unwrap(); - if test_mode == TestMode::All { - token - .transfer_unchecked(&alice_account, &alice_account, &alice, 1) - .await - .unwrap(); - } - - // too much self transfer is not ok - let error = token - .transfer_checked(&alice_account, &alice_account, &alice, amount + 1, decimals) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::InsufficientFunds as u32) - ) - ))) - ); -} - -#[tokio::test] -async fn self_transfer() { - let mut context = TestContext::new().await; - context.init_token_with_mint(vec![]).await.unwrap(); - run_self_transfers(context, TestMode::All).await; -} - -#[tokio::test] -async fn self_transfer_with_extension() { - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::TransferFeeConfig { - transfer_fee_config_authority: Some(Pubkey::new_unique()), - withdraw_withheld_authority: Some(Pubkey::new_unique()), - transfer_fee_basis_points: 100u16, - maximum_fee: 1_000_000u64, - }]) - .await - .unwrap(); - run_self_transfers(context, TestMode::CheckedOnly).await; -} - -async fn run_self_owned(context: TestContext, test_mode: TestMode) { - let TokenContext { - decimals, - mint_authority, - token, - alice, - bob, - .. - } = context.token_context.unwrap(); - - let alice_account = token - .create_auxiliary_token_account(&alice, &alice.pubkey()) - .await - .unwrap(); - let bob_account = Keypair::new(); - let bob_account = token - .create_auxiliary_token_account(&bob_account, &bob.pubkey()) - .await - .unwrap(); - - // mint a token - let amount = 10; - token - .mint_to(&alice_account, &mint_authority, amount) - .await - .unwrap(); - - if test_mode == TestMode::All { - // unchecked is ok - token - .transfer_unchecked(&alice_account, &bob_account, &alice, 1) - .await - .unwrap(); - } - - // checked is ok - token - .transfer_checked(&alice_account, &bob_account, &alice, 1, decimals) - .await - .unwrap(); - - // self transfer is ok - token - .transfer_checked(&alice_account, &alice_account, &alice, 1, decimals) - .await - .unwrap(); -} - -#[tokio::test] -async fn self_owned() { - let mut context = TestContext::new().await; - context.init_token_with_mint(vec![]).await.unwrap(); - run_self_owned(context, TestMode::All).await; -} - -#[tokio::test] -async fn self_owned_with_extension() { - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::TransferFeeConfig { - transfer_fee_config_authority: Some(Pubkey::new_unique()), - withdraw_withheld_authority: Some(Pubkey::new_unique()), - transfer_fee_basis_points: 100u16, - maximum_fee: 1_000_000u64, - }]) - .await - .unwrap(); - run_self_owned(context, TestMode::CheckedOnly).await; -} - -#[tokio::test] -async fn transfer_with_fee_on_mint_without_fee_configured() { - let mut context = TestContext::new().await; - context.init_token_with_mint(vec![]).await.unwrap(); - let TokenContext { - decimals, - mint_authority, - token, - alice, - bob, - .. - } = context.token_context.unwrap(); - - let alice_account = Keypair::new(); - let alice_account = token - .create_auxiliary_token_account(&alice_account, &alice.pubkey()) - .await - .unwrap(); - let bob_account = Keypair::new(); - let bob_account = token - .create_auxiliary_token_account(&bob_account, &bob.pubkey()) - .await - .unwrap(); - - // mint some tokens - let amount = 10; - token - .mint_to(&alice_account, &mint_authority, amount) - .await - .unwrap(); - - // success if expected fee is 0 - token - .transfer_checked_with_fee(&alice_account, &bob_account, &alice, 1, decimals, 0) - .await - .unwrap(); - - // fail for anything else - let error = token - .transfer_checked_with_fee(&alice_account, &bob_account, &alice, 2, decimals, 1) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::FeeMismatch as u32) - ) - ))) - ); -} diff --git a/token/program-2022-test/tests/transfer_fee.rs b/token/program-2022-test/tests/transfer_fee.rs deleted file mode 100644 index 4ee4a7a87ba..00000000000 --- a/token/program-2022-test/tests/transfer_fee.rs +++ /dev/null @@ -1,1646 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod program_test; -use { - program_test::{TestContext, TokenContext}, - solana_program_test::tokio, - solana_sdk::{ - instruction::InstructionError, program_option::COption, pubkey::Pubkey, signature::Signer, - signer::keypair::Keypair, transaction::TransactionError, transport::TransportError, - }, - spl_token_2022::{ - error::TokenError, - extension::transfer_fee::{ - TransferFee, TransferFeeAmount, TransferFeeConfig, MAX_FEE_BASIS_POINTS, - }, - instruction, - }, - spl_token_client::{ - client::ProgramBanksClientProcessTransaction, - token::{ExtensionInitializationParams, Token, TokenError as TokenClientError}, - }, - std::convert::TryInto, -}; - -const TEST_MAXIMUM_FEE: u64 = 10_000_000; -const TEST_FEE_BASIS_POINTS: u16 = 250; - -fn test_transfer_fee() -> TransferFee { - TransferFee { - epoch: 0.into(), - transfer_fee_basis_points: TEST_FEE_BASIS_POINTS.into(), - maximum_fee: TEST_MAXIMUM_FEE.into(), - } -} - -fn test_transfer_fee_config() -> TransferFeeConfig { - let transfer_fee = test_transfer_fee(); - TransferFeeConfig { - transfer_fee_config_authority: COption::Some(Pubkey::new_unique()).try_into().unwrap(), - withdraw_withheld_authority: COption::Some(Pubkey::new_unique()).try_into().unwrap(), - withheld_amount: 0.into(), - older_transfer_fee: transfer_fee, - newer_transfer_fee: transfer_fee, - } -} - -struct TransferFeeConfigWithKeypairs { - transfer_fee_config: TransferFeeConfig, - transfer_fee_config_authority: Keypair, - withdraw_withheld_authority: Keypair, -} - -fn test_transfer_fee_config_with_keypairs() -> TransferFeeConfigWithKeypairs { - let transfer_fee = test_transfer_fee(); - let transfer_fee_config_authority = Keypair::new(); - let withdraw_withheld_authority = Keypair::new(); - let transfer_fee_config = TransferFeeConfig { - transfer_fee_config_authority: COption::Some(transfer_fee_config_authority.pubkey()) - .try_into() - .unwrap(), - withdraw_withheld_authority: COption::Some(withdraw_withheld_authority.pubkey()) - .try_into() - .unwrap(), - withheld_amount: 0.into(), - older_transfer_fee: transfer_fee, - newer_transfer_fee: transfer_fee, - }; - TransferFeeConfigWithKeypairs { - transfer_fee_config, - transfer_fee_config_authority, - withdraw_withheld_authority, - } -} - -struct TokenWithAccounts { - context: TestContext, - token: Token, - transfer_fee_config: TransferFeeConfig, - withdraw_withheld_authority: Keypair, - freeze_authority: Keypair, - alice: Keypair, - alice_account: Pubkey, - bob_account: Pubkey, - decimals: u8, -} - -async fn create_mint_with_accounts(alice_amount: u64) -> TokenWithAccounts { - let TransferFeeConfigWithKeypairs { - transfer_fee_config_authority, - withdraw_withheld_authority, - transfer_fee_config, - .. - } = test_transfer_fee_config_with_keypairs(); - let mut context = TestContext::new().await; - let transfer_fee_basis_points = u16::from( - transfer_fee_config - .newer_transfer_fee - .transfer_fee_basis_points, - ); - let maximum_fee = u64::from(transfer_fee_config.newer_transfer_fee.maximum_fee); - context - .init_token_with_freezing_mint(vec![ExtensionInitializationParams::TransferFeeConfig { - transfer_fee_config_authority: transfer_fee_config_authority.pubkey().into(), - withdraw_withheld_authority: withdraw_withheld_authority.pubkey().into(), - transfer_fee_basis_points, - maximum_fee, - }]) - .await - .unwrap(); - let TokenContext { - decimals, - mint_authority, - freeze_authority, - token, - alice, - bob, - .. - } = context.token_context.take().unwrap(); - - // token account is self-owned just to test another case - let alice_account = token - .create_auxiliary_token_account(&alice, &alice.pubkey()) - .await - .unwrap(); - let bob_account = Keypair::new(); - let bob_account = token - .create_auxiliary_token_account(&bob_account, &bob.pubkey()) - .await - .unwrap(); - - // mint tokens - token - .mint_to(&alice_account, &mint_authority, alice_amount) - .await - .unwrap(); - TokenWithAccounts { - context, - token, - transfer_fee_config, - withdraw_withheld_authority, - freeze_authority: freeze_authority.unwrap(), - alice, - alice_account, - bob_account, - decimals, - } -} - -#[tokio::test] -async fn success_init() { - let TransferFeeConfig { - transfer_fee_config_authority, - withdraw_withheld_authority, - newer_transfer_fee, - .. - } = test_transfer_fee_config(); - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::TransferFeeConfig { - transfer_fee_config_authority: transfer_fee_config_authority.into(), - withdraw_withheld_authority: withdraw_withheld_authority.into(), - transfer_fee_basis_points: newer_transfer_fee.transfer_fee_basis_points.into(), - maximum_fee: newer_transfer_fee.maximum_fee.into(), - }]) - .await - .unwrap(); - let TokenContext { - decimals, - mint_authority, - token, - .. - } = context.token_context.unwrap(); - - let state = token.get_mint_info().await.unwrap(); - assert_eq!(state.base.decimals, decimals); - assert_eq!( - state.base.mint_authority, - COption::Some(mint_authority.pubkey()) - ); - assert_eq!(state.base.supply, 0); - assert!(state.base.is_initialized); - assert_eq!(state.base.freeze_authority, COption::None); - let extension = state.get_extension::().unwrap(); - assert_eq!( - extension.transfer_fee_config_authority, - transfer_fee_config_authority, - ); - assert_eq!( - extension.withdraw_withheld_authority, - withdraw_withheld_authority, - ); - assert_eq!(extension.newer_transfer_fee, newer_transfer_fee); - assert_eq!(extension.older_transfer_fee, newer_transfer_fee); -} - -#[tokio::test] -async fn fail_init_default_pubkey_as_authority() { - let TransferFeeConfig { - transfer_fee_config_authority, - newer_transfer_fee, - .. - } = test_transfer_fee_config(); - let mut context = TestContext::new().await; - let err = context - .init_token_with_mint(vec![ExtensionInitializationParams::TransferFeeConfig { - transfer_fee_config_authority: transfer_fee_config_authority.into(), - withdraw_withheld_authority: Some(Pubkey::default()), - transfer_fee_basis_points: newer_transfer_fee.transfer_fee_basis_points.into(), - maximum_fee: newer_transfer_fee.maximum_fee.into(), - }]) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError(1, InstructionError::InvalidArgument) - ))) - ); -} - -#[tokio::test] -async fn fail_init_fee_too_high() { - let TransferFeeConfig { - transfer_fee_config_authority, - withdraw_withheld_authority, - newer_transfer_fee, - .. - } = test_transfer_fee_config(); - let mut context = TestContext::new().await; - let err = context - .init_token_with_mint(vec![ExtensionInitializationParams::TransferFeeConfig { - transfer_fee_config_authority: transfer_fee_config_authority.into(), - withdraw_withheld_authority: withdraw_withheld_authority.into(), - transfer_fee_basis_points: MAX_FEE_BASIS_POINTS + 1, - maximum_fee: newer_transfer_fee.maximum_fee.into(), - }]) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 1, - InstructionError::Custom(TokenError::TransferFeeExceedsMaximum as u32) - ) - ))) - ); -} - -#[tokio::test] -async fn set_fee() { - let TransferFeeConfigWithKeypairs { - transfer_fee_config_authority, - withdraw_withheld_authority, - transfer_fee_config: TransferFeeConfig { - newer_transfer_fee, .. - }, - .. - } = test_transfer_fee_config_with_keypairs(); - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::TransferFeeConfig { - transfer_fee_config_authority: transfer_fee_config_authority.pubkey().into(), - withdraw_withheld_authority: withdraw_withheld_authority.pubkey().into(), - transfer_fee_basis_points: newer_transfer_fee.transfer_fee_basis_points.into(), - maximum_fee: newer_transfer_fee.maximum_fee.into(), - }]) - .await - .unwrap(); - - // warp to first normal slot to easily calculate epochs - let epoch_schedule = context.context.lock().await.genesis_config().epoch_schedule; - let first_normal_slot = epoch_schedule.first_normal_slot; - let slots_per_epoch = epoch_schedule.slots_per_epoch; - context - .context - .lock() - .await - .warp_to_slot(first_normal_slot) - .unwrap(); - - let token = context.token_context.unwrap().token; - - // set to something new, old fee not touched - let new_transfer_fee_basis_points = MAX_FEE_BASIS_POINTS; - let new_maximum_fee = u64::MAX; - token - .set_transfer_fee( - &transfer_fee_config_authority, - new_transfer_fee_basis_points, - new_maximum_fee, - ) - .await - .unwrap(); - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!( - extension.newer_transfer_fee.transfer_fee_basis_points, - new_transfer_fee_basis_points.into() - ); - assert_eq!( - extension.newer_transfer_fee.maximum_fee, - new_maximum_fee.into() - ); - assert_eq!(extension.older_transfer_fee, newer_transfer_fee); - - // set again, old fee still not touched - let new_transfer_fee_basis_points = 0; - let new_maximum_fee = 0; - token - .set_transfer_fee( - &transfer_fee_config_authority, - new_transfer_fee_basis_points, - new_maximum_fee, - ) - .await - .unwrap(); - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!( - extension.newer_transfer_fee.transfer_fee_basis_points, - new_transfer_fee_basis_points.into() - ); - assert_eq!( - extension.newer_transfer_fee.maximum_fee, - new_maximum_fee.into() - ); - assert_eq!(extension.older_transfer_fee, newer_transfer_fee); - - // warp forward one epoch, old fee still not touched when set - let new_transfer_fee_basis_points = 10; - let new_maximum_fee = 10; - context - .context - .lock() - .await - .warp_to_slot(first_normal_slot + slots_per_epoch) - .unwrap(); - token - .set_transfer_fee( - &transfer_fee_config_authority, - new_transfer_fee_basis_points, - new_maximum_fee, - ) - .await - .unwrap(); - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!( - extension.newer_transfer_fee.transfer_fee_basis_points, - new_transfer_fee_basis_points.into() - ); - assert_eq!( - extension.newer_transfer_fee.maximum_fee, - new_maximum_fee.into() - ); - assert_eq!(extension.older_transfer_fee, newer_transfer_fee); - - // warp forward two epochs, old fee is replaced on set - let newer_transfer_fee = extension.newer_transfer_fee; - context - .context - .lock() - .await - .warp_to_slot(first_normal_slot + 3 * slots_per_epoch) - .unwrap(); - let new_transfer_fee_basis_points = MAX_FEE_BASIS_POINTS; - let new_maximum_fee = u64::MAX; - token - .set_transfer_fee( - &transfer_fee_config_authority, - new_transfer_fee_basis_points, - new_maximum_fee, - ) - .await - .unwrap(); - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!( - extension.newer_transfer_fee.transfer_fee_basis_points, - new_transfer_fee_basis_points.into() - ); - assert_eq!( - extension.newer_transfer_fee.maximum_fee, - new_maximum_fee.into() - ); - assert_eq!(extension.older_transfer_fee, newer_transfer_fee); - - // fail, wrong signer - let error = token - .set_transfer_fee( - &withdraw_withheld_authority, - new_transfer_fee_basis_points, - new_maximum_fee, - ) - .await - .err() - .unwrap(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::OwnerMismatch as u32) - ) - ))) - ); - - // fail, set too high - let error = token - .set_transfer_fee( - &transfer_fee_config_authority, - MAX_FEE_BASIS_POINTS + 1, - new_maximum_fee, - ) - .await - .err() - .unwrap(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::TransferFeeExceedsMaximum as u32) - ) - ))) - ); -} - -#[tokio::test] -async fn fail_unsupported_mint() { - let mut context = TestContext::new().await; - context.init_token_with_mint(vec![]).await.unwrap(); - let TokenContext { - mint_authority, - token, - .. - } = context.token_context.unwrap(); - let transfer_fee_basis_points = u16::MAX; - let maximum_fee = u64::MAX; - let error = token - .set_transfer_fee(&mint_authority, transfer_fee_basis_points, maximum_fee) - .await - .err() - .unwrap(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError(0, InstructionError::InvalidAccountData) - ))) - ); - let error = token - .harvest_withheld_tokens_to_mint(&[]) - .await - .err() - .unwrap(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError(0, InstructionError::InvalidAccountData) - ))) - ); - let error = token - .withdraw_withheld_tokens_from_mint(&Pubkey::new_unique(), &mint_authority) - .await - .err() - .unwrap(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError(0, InstructionError::InvalidAccountData) - ))) - ); -} - -#[tokio::test] -async fn set_transfer_fee_config_authority() { - let TransferFeeConfigWithKeypairs { - transfer_fee_config_authority, - withdraw_withheld_authority, - transfer_fee_config: TransferFeeConfig { - newer_transfer_fee, .. - }, - .. - } = test_transfer_fee_config_with_keypairs(); - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::TransferFeeConfig { - transfer_fee_config_authority: transfer_fee_config_authority.pubkey().into(), - withdraw_withheld_authority: withdraw_withheld_authority.pubkey().into(), - transfer_fee_basis_points: newer_transfer_fee.transfer_fee_basis_points.into(), - maximum_fee: newer_transfer_fee.maximum_fee.into(), - }]) - .await - .unwrap(); - let token = context.token_context.unwrap().token; - - let new_authority = Keypair::new(); - let wrong = Keypair::new(); - - // fail, wrong signer - let err = token - .set_authority( - token.get_address(), - Some(&new_authority.pubkey()), - instruction::AuthorityType::TransferFeeConfig, - &wrong, - ) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::OwnerMismatch as u32) - ) - ))) - ); - - // success - token - .set_authority( - token.get_address(), - Some(&new_authority.pubkey()), - instruction::AuthorityType::TransferFeeConfig, - &transfer_fee_config_authority, - ) - .await - .unwrap(); - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!( - extension.transfer_fee_config_authority, - Some(new_authority.pubkey()).try_into().unwrap(), - ); - - // assert new_authority can update transfer fee config, and old cannot - let transfer_fee_basis_points = MAX_FEE_BASIS_POINTS; - let maximum_fee = u64::MAX; - let err = token - .set_transfer_fee( - &transfer_fee_config_authority, - transfer_fee_basis_points, - maximum_fee, - ) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::OwnerMismatch as u32) - ) - ))) - ); - token - .set_transfer_fee(&new_authority, transfer_fee_basis_points, maximum_fee) - .await - .unwrap(); - - // set to none - token - .set_authority( - token.get_address(), - None, - instruction::AuthorityType::TransferFeeConfig, - &new_authority, - ) - .await - .unwrap(); - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!( - extension.transfer_fee_config_authority, - None.try_into().unwrap(), - ); - - // fail set again - let err = token - .set_authority( - token.get_address(), - Some(&transfer_fee_config_authority.pubkey()), - instruction::AuthorityType::TransferFeeConfig, - &new_authority, - ) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::AuthorityTypeNotSupported as u32) - ) - ))) - ); - - // fail update transfer fee config - let err = token - .set_transfer_fee(&transfer_fee_config_authority, 0, 0) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::NoAuthorityExists as u32) - ) - ))) - ); -} - -#[tokio::test] -async fn set_withdraw_withheld_authority() { - let TransferFeeConfigWithKeypairs { - transfer_fee_config_authority, - withdraw_withheld_authority, - transfer_fee_config: TransferFeeConfig { - newer_transfer_fee, .. - }, - .. - } = test_transfer_fee_config_with_keypairs(); - let mut context = TestContext::new().await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::TransferFeeConfig { - transfer_fee_config_authority: transfer_fee_config_authority.pubkey().into(), - withdraw_withheld_authority: withdraw_withheld_authority.pubkey().into(), - transfer_fee_basis_points: newer_transfer_fee.transfer_fee_basis_points.into(), - maximum_fee: newer_transfer_fee.maximum_fee.into(), - }]) - .await - .unwrap(); - let token = context.token_context.unwrap().token; - - let new_authority = Keypair::new(); - let wrong = Keypair::new(); - - // fail, wrong signer - let err = token - .set_authority( - token.get_address(), - Some(&new_authority.pubkey()), - instruction::AuthorityType::WithheldWithdraw, - &wrong, - ) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::OwnerMismatch as u32) - ) - ))) - ); - - // success - token - .set_authority( - token.get_address(), - Some(&new_authority.pubkey()), - instruction::AuthorityType::WithheldWithdraw, - &withdraw_withheld_authority, - ) - .await - .unwrap(); - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!( - extension.withdraw_withheld_authority, - Some(new_authority.pubkey()).try_into().unwrap(), - ); - - // new authority can withdraw tokens - let account = token - .create_auxiliary_token_account(&Keypair::new(), &new_authority.pubkey()) - .await - .unwrap(); - token - .withdraw_withheld_tokens_from_accounts(&account, &new_authority, &[&account]) - .await - .unwrap(); - // old one cannot - let error = token - .withdraw_withheld_tokens_from_accounts(&account, &withdraw_withheld_authority, &[&account]) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::OwnerMismatch as u32) - ) - ))) - ); - - // set to none - token - .set_authority( - token.get_address(), - None, - instruction::AuthorityType::WithheldWithdraw, - &new_authority, - ) - .await - .unwrap(); - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!( - extension.withdraw_withheld_authority, - None.try_into().unwrap(), - ); - - // fail set again - let err = token - .set_authority( - token.get_address(), - Some(&withdraw_withheld_authority.pubkey()), - instruction::AuthorityType::WithheldWithdraw, - &new_authority, - ) - .await - .unwrap_err(); - assert_eq!( - err, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::AuthorityTypeNotSupported as u32) - ) - ))) - ); - - // assert no authority can withdraw withheld fees - let account = token - .create_auxiliary_token_account(&Keypair::new(), &new_authority.pubkey()) - .await - .unwrap(); - let error = token - .withdraw_withheld_tokens_from_accounts(&account, &withdraw_withheld_authority, &[&account]) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::NoAuthorityExists as u32) - ) - ))) - ); - let error = token - .withdraw_withheld_tokens_from_accounts(&account, &new_authority, &[&account]) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::NoAuthorityExists as u32) - ) - ))) - ); -} - -#[tokio::test] -async fn transfer_checked() { - let maximum_fee = TEST_MAXIMUM_FEE; - let mut alice_amount = maximum_fee * 100; - let TokenWithAccounts { - token, - transfer_fee_config, - alice, - alice_account, - bob_account, - decimals, - .. - } = create_mint_with_accounts(alice_amount).await; - - // fail unchecked always - let error = token - .transfer_unchecked(&alice_account, &bob_account, &alice, maximum_fee) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::MintRequiredForTransfer as u32) - ) - ))) - ); - - // fail because amount too high - let error = token - .transfer_checked( - &alice_account, - &bob_account, - &alice, - alice_amount + 1, - decimals, - ) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::InsufficientFunds as u32) - ) - ))) - ); - - let mut withheld_amount = 0; - let mut transferred_amount = 0; - - // success, clean calculation for transfer fee - let fee = transfer_fee_config - .calculate_epoch_fee(0, maximum_fee) - .unwrap(); - token - .transfer_checked(&alice_account, &bob_account, &alice, maximum_fee, decimals) - .await - .unwrap(); - alice_amount -= maximum_fee; - withheld_amount += fee; - transferred_amount += maximum_fee - fee; - - let alice_state = token.get_account_info(&alice_account).await.unwrap(); - assert_eq!(alice_state.base.amount, alice_amount); - let extension = alice_state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, 0.into()); - let bob_state = token.get_account_info(&bob_account).await.unwrap(); - assert_eq!(bob_state.base.amount, transferred_amount); - let extension = bob_state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, withheld_amount.into()); - - // success, rounded up transfer fee - let transfer_amount = maximum_fee - 1; - let fee = transfer_fee_config - .calculate_epoch_fee(0, transfer_amount) - .unwrap(); - token - .transfer_checked( - &alice_account, - &bob_account, - &alice, - transfer_amount, - decimals, - ) - .await - .unwrap(); - alice_amount -= transfer_amount; - withheld_amount += fee; - transferred_amount += transfer_amount - fee; - let alice_state = token.get_account_info(&alice_account).await.unwrap(); - assert_eq!(alice_state.base.amount, alice_amount); - let extension = alice_state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, 0.into()); - let bob_state = token.get_account_info(&bob_account).await.unwrap(); - assert_eq!(bob_state.base.amount, transferred_amount); - let extension = bob_state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, withheld_amount.into()); - - // success, maximum fee kicks in - let transfer_amount = 1 + maximum_fee * (MAX_FEE_BASIS_POINTS as u64) - / (u16::from( - transfer_fee_config - .newer_transfer_fee - .transfer_fee_basis_points, - ) as u64); - let fee = transfer_fee_config - .calculate_epoch_fee(0, transfer_amount) - .unwrap(); - assert_eq!(fee, maximum_fee); // sanity - token - .transfer_checked( - &alice_account, - &bob_account, - &alice, - transfer_amount, - decimals, - ) - .await - .unwrap(); - alice_amount -= transfer_amount; - withheld_amount += fee; - transferred_amount += transfer_amount - fee; - let alice_state = token.get_account_info(&alice_account).await.unwrap(); - assert_eq!(alice_state.base.amount, alice_amount); - let extension = alice_state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, 0.into()); - let bob_state = token.get_account_info(&bob_account).await.unwrap(); - assert_eq!(bob_state.base.amount, transferred_amount); - let extension = bob_state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, withheld_amount.into()); - - // transfer down to 1 token - token - .transfer_checked( - &alice_account, - &bob_account, - &alice, - alice_amount - 1, - decimals, - ) - .await - .unwrap(); - transferred_amount += alice_amount - 1 - maximum_fee; - alice_amount = 1; - withheld_amount += maximum_fee; - let alice_state = token.get_account_info(&alice_account).await.unwrap(); - assert_eq!(alice_state.base.amount, alice_amount); - let extension = alice_state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, 0.into()); - let bob_state = token.get_account_info(&bob_account).await.unwrap(); - assert_eq!(bob_state.base.amount, transferred_amount); - let extension = bob_state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, withheld_amount.into()); - - // final transfer, only move tokens to withheld amount, nothing received - token - .transfer_checked(&alice_account, &bob_account, &alice, 1, decimals) - .await - .unwrap(); - withheld_amount += 1; - let alice_state = token.get_account_info(&alice_account).await.unwrap(); - assert_eq!(alice_state.base.amount, 0); - let extension = alice_state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, 0.into()); - let bob_state = token.get_account_info(&bob_account).await.unwrap(); - assert_eq!(bob_state.base.amount, transferred_amount); - let extension = bob_state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, withheld_amount.into()); -} - -#[tokio::test] -async fn transfer_checked_with_fee() { - let maximum_fee = TEST_MAXIMUM_FEE; - let alice_amount = maximum_fee * 100; - let TokenWithAccounts { - token, - transfer_fee_config, - alice, - alice_account, - bob_account, - decimals, - .. - } = create_mint_with_accounts(alice_amount).await; - - // incorrect fee, too high - let transfer_amount = maximum_fee; - let fee = transfer_fee_config - .calculate_epoch_fee(0, transfer_amount) - .unwrap() - + 1; - let error = token - .transfer_checked_with_fee( - &alice_account, - &bob_account, - &alice, - transfer_amount, - decimals, - fee, - ) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::FeeMismatch as u32) - ) - ))) - ); - - // incorrect fee, too low - let fee = transfer_fee_config - .calculate_epoch_fee(0, transfer_amount) - .unwrap() - - 1; - let error = token - .transfer_checked_with_fee( - &alice_account, - &bob_account, - &alice, - transfer_amount, - decimals, - fee, - ) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::FeeMismatch as u32) - ) - ))) - ); - - // correct fee, not enough tokens - let fee = transfer_fee_config - .calculate_epoch_fee(0, alice_amount + 1) - .unwrap() - - 1; - let error = token - .transfer_checked_with_fee( - &alice_account, - &bob_account, - &alice, - alice_amount + 1, - decimals, - fee, - ) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::InsufficientFunds as u32) - ) - ))) - ); - - // correct fee - let fee = transfer_fee_config - .calculate_epoch_fee(0, transfer_amount) - .unwrap(); - token - .transfer_checked_with_fee( - &alice_account, - &bob_account, - &alice, - transfer_amount, - decimals, - fee, - ) - .await - .unwrap(); - let alice_state = token.get_account_info(&alice_account).await.unwrap(); - assert_eq!(alice_state.base.amount, alice_amount - transfer_amount); - let extension = alice_state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, 0.into()); - let bob_state = token.get_account_info(&bob_account).await.unwrap(); - assert_eq!(bob_state.base.amount, transfer_amount - fee); - let extension = bob_state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, fee.into()); -} - -#[tokio::test] -async fn no_fees_from_self_transfer() { - let amount = TEST_MAXIMUM_FEE; - let alice_amount = amount * 100; - let TokenWithAccounts { - token, - transfer_fee_config, - alice, - alice_account, - decimals, - .. - } = create_mint_with_accounts(alice_amount).await; - - // self transfer, no fee assessed - let fee = transfer_fee_config.calculate_epoch_fee(0, amount).unwrap(); - token - .transfer_checked_with_fee( - &alice_account, - &alice_account, - &alice, - amount, - decimals, - fee, - ) - .await - .unwrap(); - let alice_state = token.get_account_info(&alice_account).await.unwrap(); - assert_eq!(alice_state.base.amount, alice_amount); - let extension = alice_state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, 0.into()); -} - -async fn create_and_transfer_to_account( - token: &Token, - source: &Pubkey, - authority: &Keypair, - owner: &Pubkey, - amount: u64, - decimals: u8, -) -> Pubkey { - let account = token - .create_auxiliary_token_account(&Keypair::new(), owner) - .await - .unwrap(); - token - .transfer_checked(source, &account, authority, amount, decimals) - .await - .unwrap(); - account -} - -#[tokio::test] -async fn harvest_withheld_tokens_to_mint() { - let amount = TEST_MAXIMUM_FEE; - let alice_amount = amount * 100; - let TokenWithAccounts { - mut context, - token, - transfer_fee_config, - alice, - alice_account, - decimals, - .. - } = create_mint_with_accounts(alice_amount).await; - - // harvest from zero accounts - token.harvest_withheld_tokens_to_mint(&[]).await.unwrap(); - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, 0.into()); - - // harvest from one account - let accumulated_fees = transfer_fee_config.calculate_epoch_fee(0, amount).unwrap(); - let account = create_and_transfer_to_account( - &token, - &alice_account, - &alice, - &alice.pubkey(), - amount, - decimals, - ) - .await; - token - .harvest_withheld_tokens_to_mint(&[&account]) - .await - .unwrap(); - let state = token.get_account_info(&account).await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, 0.into()); - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, accumulated_fees.into()); - - // no fail harvesting from account belonging to different mint, but nothing - // happens - let account = create_and_transfer_to_account( - &token, - &alice_account, - &alice, - &alice.pubkey(), - amount, - decimals, - ) - .await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::TransferFeeConfig { - transfer_fee_config_authority: Some(Pubkey::new_unique()), - withdraw_withheld_authority: Some(Pubkey::new_unique()), - transfer_fee_basis_points: TEST_FEE_BASIS_POINTS, - maximum_fee: TEST_MAXIMUM_FEE, - }]) - .await - .unwrap(); - let TokenContext { token, .. } = context.token_context.take().unwrap(); - token - .harvest_withheld_tokens_to_mint(&[&account]) - .await - .unwrap(); - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, 0.into()); -} - -#[tokio::test] -async fn max_harvest_withheld_tokens_to_mint() { - let amount = TEST_MAXIMUM_FEE; - let alice_amount = amount * 100; - let TokenWithAccounts { - token, - transfer_fee_config, - alice, - alice_account, - decimals, - .. - } = create_mint_with_accounts(alice_amount).await; - - // harvest from max accounts, which is around 35, AKA 34 accounts + 1 mint - // see https://docs.solana.com/proposals/transactions-v2#problem - let mut accounts = vec![]; - let max_accounts = 34; - for _ in 0..max_accounts { - let account = create_and_transfer_to_account( - &token, - &alice_account, - &alice, - &alice.pubkey(), - amount, - decimals, - ) - .await; - accounts.push(account); - } - let accounts: Vec<_> = accounts.iter().collect(); - let accumulated_fees = - max_accounts * transfer_fee_config.calculate_epoch_fee(0, amount).unwrap(); - token - .harvest_withheld_tokens_to_mint(&accounts) - .await - .unwrap(); - for account in accounts { - let state = token.get_account_info(account).await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, 0.into()); - } - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, accumulated_fees.into()); -} - -#[tokio::test] -async fn max_withdraw_withheld_tokens_from_accounts() { - let amount = TEST_MAXIMUM_FEE; - let alice_amount = amount * 100; - let TokenWithAccounts { - token, - withdraw_withheld_authority, - transfer_fee_config, - alice, - alice_account, - decimals, - .. - } = create_mint_with_accounts(alice_amount).await; - - // withdraw from max accounts, which is around 35: 1 mint, 1 destination, 1 authority, - // 32 accounts - // see https://docs.solana.com/proposals/transactions-v2#problem - let destination = token - .create_auxiliary_token_account(&Keypair::new(), &alice.pubkey()) - .await - .unwrap(); - let mut accounts = vec![]; - let max_accounts = 32; - for _ in 0..max_accounts { - let account = create_and_transfer_to_account( - &token, - &alice_account, - &alice, - &alice.pubkey(), - amount, - decimals, - ) - .await; - accounts.push(account); - } - let accounts: Vec<_> = accounts.iter().collect(); - let accumulated_fees = - max_accounts * transfer_fee_config.calculate_epoch_fee(0, amount).unwrap(); - token - .withdraw_withheld_tokens_from_accounts( - &destination, - &withdraw_withheld_authority, - &accounts, - ) - .await - .unwrap(); - for account in accounts { - let state = token.get_account_info(account).await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, 0.into()); - } - let state = token.get_account_info(&destination).await.unwrap(); - assert_eq!(state.base.amount, accumulated_fees); -} - -#[tokio::test] -async fn withdraw_withheld_tokens_from_mint() { - let amount = TEST_MAXIMUM_FEE; - let alice_amount = amount * 100; - let TokenWithAccounts { - mut context, - token, - transfer_fee_config, - withdraw_withheld_authority, - freeze_authority, - alice, - alice_account, - decimals, - bob_account, - .. - } = create_mint_with_accounts(alice_amount).await; - - // no tokens withheld on mint - token - .withdraw_withheld_tokens_from_mint(&alice_account, &withdraw_withheld_authority) - .await - .unwrap(); - let state = token.get_account_info(&alice_account).await.unwrap(); - assert_eq!(state.base.amount, alice_amount); - let extension = state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, 0.into()); - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, 0.into()); - - // transfer + harvest to mint - let fee = transfer_fee_config.calculate_epoch_fee(0, amount).unwrap(); - let account = create_and_transfer_to_account( - &token, - &alice_account, - &alice, - &alice.pubkey(), - amount, - decimals, - ) - .await; - - let state = token.get_account_info(&account).await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, fee.into()); - - token - .harvest_withheld_tokens_to_mint(&[&account]) - .await - .unwrap(); - - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, fee.into()); - - // success - token - .withdraw_withheld_tokens_from_mint(&bob_account, &withdraw_withheld_authority) - .await - .unwrap(); - let state = token.get_account_info(&bob_account).await.unwrap(); - assert_eq!(state.base.amount, fee); - let state = token.get_account_info(&account).await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, 0.into()); - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, 0.into()); - - // fail wrong signer - let error = token - .withdraw_withheld_tokens_from_mint(&alice_account, &alice) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::OwnerMismatch as u32) - ) - ))) - ); - - // fail frozen account - let account = create_and_transfer_to_account( - &token, - &alice_account, - &alice, - &alice.pubkey(), - amount, - decimals, - ) - .await; - token - .freeze_account(&account, &freeze_authority) - .await - .unwrap(); - let error = token - .withdraw_withheld_tokens_from_mint(&account, &withdraw_withheld_authority) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::AccountFrozen as u32) - ) - ))) - ); - - // set to none, fail - let account = create_and_transfer_to_account( - &token, - &alice_account, - &alice, - &alice.pubkey(), - amount, - decimals, - ) - .await; - token - .set_authority( - token.get_address(), - None, - instruction::AuthorityType::WithheldWithdraw, - &withdraw_withheld_authority, - ) - .await - .unwrap(); - let error = token - .withdraw_withheld_tokens_from_mint(&account, &withdraw_withheld_authority) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::NoAuthorityExists as u32) - ) - ))) - ); - - // fail on new mint with mint mismatch - context - .init_token_with_mint(vec![ExtensionInitializationParams::TransferFeeConfig { - transfer_fee_config_authority: Some(Pubkey::new_unique()), - withdraw_withheld_authority: Some(withdraw_withheld_authority.pubkey()), - transfer_fee_basis_points: TEST_FEE_BASIS_POINTS, - maximum_fee: TEST_MAXIMUM_FEE, - }]) - .await - .unwrap(); - let TokenContext { token, .. } = context.token_context.take().unwrap(); - let error = token - .withdraw_withheld_tokens_from_mint(&account, &withdraw_withheld_authority) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::MintMismatch as u32) - ) - ))) - ); -} - -#[tokio::test] -async fn withdraw_withheld_tokens_from_accounts() { - let amount = TEST_MAXIMUM_FEE; - let alice_amount = amount * 100; - let TokenWithAccounts { - mut context, - token, - withdraw_withheld_authority, - alice, - alice_account, - decimals, - .. - } = create_mint_with_accounts(alice_amount).await; - - // wrong signer - let error = token - .withdraw_withheld_tokens_from_accounts(&alice_account, &Keypair::new(), &[]) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::OwnerMismatch as u32) - ) - ))) - ); - - // withdraw from zero accounts - token - .withdraw_withheld_tokens_from_accounts(&alice_account, &withdraw_withheld_authority, &[]) - .await - .unwrap(); - let state = token.get_account_info(&alice_account).await.unwrap(); - assert_eq!(state.base.amount, alice_amount); - - // self-harvest from one account - let account = create_and_transfer_to_account( - &token, - &alice_account, - &alice, - &alice.pubkey(), - amount, - decimals, - ) - .await; - token - .withdraw_withheld_tokens_from_accounts(&account, &withdraw_withheld_authority, &[&account]) - .await - .unwrap(); - let state = token.get_account_info(&account).await.unwrap(); - let extension = state.get_extension::().unwrap(); - // we transferred to this account, and then withdrew the fee to it, so it's - // like doing a fee-less transfer! - assert_eq!(extension.withheld_amount, 0.into()); - assert_eq!(state.base.amount, amount); - - // harvest again from the same account - token - .withdraw_withheld_tokens_from_accounts( - &alice_account, - &withdraw_withheld_authority, - &[&account], - ) - .await - .unwrap(); - let state = token.get_account_info(&account).await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, 0.into()); - assert_eq!(state.base.amount, amount); - let state = token.get_account_info(&alice_account).await.unwrap(); - assert_eq!(state.base.amount, alice_amount - amount); - - // no fail harvesting from account belonging to different mint, but nothing - // happens - let account = create_and_transfer_to_account( - &token, - &alice_account, - &alice, - &alice.pubkey(), - amount, - decimals, - ) - .await; - context - .init_token_with_mint(vec![ExtensionInitializationParams::TransferFeeConfig { - transfer_fee_config_authority: Some(Pubkey::new_unique()), - withdraw_withheld_authority: Some(withdraw_withheld_authority.pubkey()), - transfer_fee_basis_points: TEST_FEE_BASIS_POINTS, - maximum_fee: TEST_MAXIMUM_FEE, - }]) - .await - .unwrap(); - let TokenContext { token, .. } = context.token_context.take().unwrap(); - let withdraw_account = token - .create_auxiliary_token_account(&Keypair::new(), &alice.pubkey()) - .await - .unwrap(); - token - .withdraw_withheld_tokens_from_accounts( - &withdraw_account, - &withdraw_withheld_authority, - &[&account], - ) - .await - .unwrap(); - let state = token.get_mint_info().await.unwrap(); - let extension = state.get_extension::().unwrap(); - assert_eq!(extension.withheld_amount, 0.into()); - - // fail withdrawing into account on different mint - let error = token - .withdraw_withheld_tokens_from_accounts( - &account, - &withdraw_withheld_authority, - &[&withdraw_account], - ) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::MintMismatch as u32) - ) - ))) - ); -} - -#[tokio::test] -async fn fail_close_with_withheld() { - let amount = TEST_MAXIMUM_FEE; - let alice_amount = amount * 100; - let TokenWithAccounts { - token, - transfer_fee_config, - alice, - alice_account, - decimals, - .. - } = create_mint_with_accounts(alice_amount).await; - - // accrue withheld fees on new account - let account = create_and_transfer_to_account( - &token, - &alice_account, - &alice, - &alice.pubkey(), - amount, - decimals, - ) - .await; - - // empty the account - let fee = transfer_fee_config.calculate_epoch_fee(0, amount).unwrap(); - token - .transfer_checked(&account, &alice_account, &alice, amount - fee, decimals) - .await - .unwrap(); - - // fail to close - let error = token - .close_account(&account, &Pubkey::new_unique(), &alice) - .await - .unwrap_err(); - assert_eq!( - error, - TokenClientError::Client(Box::new(TransportError::TransactionError( - TransactionError::InstructionError( - 0, - InstructionError::Custom(TokenError::AccountHasWithheldTransferFees as u32) - ) - ))) - ); - - // harvest the fees to the mint - token - .harvest_withheld_tokens_to_mint(&[&account]) - .await - .unwrap(); - - // successfully close - token - .close_account(&account, &Pubkey::new_unique(), &alice) - .await - .unwrap(); -} diff --git a/token/program-2022/Cargo.toml b/token/program-2022/Cargo.toml deleted file mode 100644 index 95231bd2615..00000000000 --- a/token/program-2022/Cargo.toml +++ /dev/null @@ -1,45 +0,0 @@ -[package] -name = "spl-token-2022" -version = "0.4.2" -description = "Solana Program Library Token 2022" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana-program-library" -license = "Apache-2.0" -edition = "2018" -exclude = ["js/**"] - -[features] -no-entrypoint = [] -test-bpf = [] -serde-traits = ["serde", "serde_with"] -# Remove these features once the underlying syscalls are released on all networks -default = ["zk-ops"] -zk-ops = [] - -[dependencies] -arrayref = "0.3.6" -bytemuck = { version = "1.7.2", features = ["derive"] } -num-derive = "0.3" -num-traits = "0.2" -num_enum = "0.5.4" -solana-program = "1.10.33" -solana-zk-token-sdk = "1.10.33" -spl-memo = { version = "3.0.1", path = "../../memo/program", features = [ "no-entrypoint" ] } -spl-token = { version = "3.3", path = "../program", features = ["no-entrypoint"] } -thiserror = "1.0" -serde = { version = "1.0.136", optional = true } -serde_with = { version = "1.14.0", optional = true } - -[dev-dependencies] -lazy_static = "1.4.0" -proptest = "1.0" -serial_test = "0.5.1" -solana-program-test = "1.10.33" -solana-sdk = "1.10.33" -serde_json = "1.0.81" - -[lib] -crate-type = ["cdylib", "lib"] - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] diff --git a/token/program-2022/Xargo.toml b/token/program-2022/Xargo.toml deleted file mode 100644 index 1744f098ae1..00000000000 --- a/token/program-2022/Xargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.bpfel-unknown-unknown.dependencies.std] -features = [] \ No newline at end of file diff --git a/token/program-2022/inc/token.h b/token/program-2022/inc/token.h deleted file mode 100644 index 145c0c5e07b..00000000000 --- a/token/program-2022/inc/token.h +++ /dev/null @@ -1,687 +0,0 @@ -/* Autogenerated SPL Token program C Bindings */ - -#pragma once - -#include -#include -#include -#include - -/** - * Minimum number of multisignature signers (min N) - */ -#define Token_MIN_SIGNERS 1 - -/** - * Maximum number of multisignature signers (max N) - */ -#define Token_MAX_SIGNERS 11 - -/** - * Account state. - */ -enum Token_AccountState -#ifdef __cplusplus - : uint8_t -#endif // __cplusplus - { - /** - * Account is not yet initialized - */ - Token_AccountState_Uninitialized, - /** - * Account is initialized; the account owner and/or delegate may perform permitted operations - * on this account - */ - Token_AccountState_Initialized, - /** - * Account has been frozen by the mint freeze authority. Neither the account owner nor - * the delegate are able to perform operations on this account. - */ - Token_AccountState_Frozen, -}; -#ifndef __cplusplus -typedef uint8_t Token_AccountState; -#endif // __cplusplus - -/** - * Specifies the authority type for SetAuthority instructions - */ -enum Token_AuthorityType -#ifdef __cplusplus - : uint8_t -#endif // __cplusplus - { - /** - * Authority to mint new tokens - */ - Token_AuthorityType_MintTokens, - /** - * Authority to freeze any account associated with the Mint - */ - Token_AuthorityType_FreezeAccount, - /** - * Owner of a given token account - */ - Token_AuthorityType_AccountOwner, - /** - * Authority to close a token account - */ - Token_AuthorityType_CloseAccount, -}; -#ifndef __cplusplus -typedef uint8_t Token_AuthorityType; -#endif // __cplusplus - -typedef uint8_t Token_Pubkey[32]; - -/** - * A C representation of Rust's `std::option::Option` - */ -typedef enum Token_COption_Pubkey_Tag { - /** - * No value - */ - Token_COption_Pubkey_None_Pubkey, - /** - * Some value `T` - */ - Token_COption_Pubkey_Some_Pubkey, -} Token_COption_Pubkey_Tag; - -typedef struct Token_COption_Pubkey { - Token_COption_Pubkey_Tag tag; - union { - struct { - Token_Pubkey some; - }; - }; -} Token_COption_Pubkey; - -/** - * Instructions supported by the token program. - */ -typedef enum Token_TokenInstruction_Tag { - /** - * Initializes a new mint and optionally deposits all the newly minted - * tokens in an account. - * - * The `InitializeMint` instruction requires no signers and MUST be - * included within the same Transaction as the system program's - * `CreateAccount` instruction that creates the account being initialized. - * Otherwise another party can acquire ownership of the uninitialized - * account. - * - * Accounts expected by this instruction: - * - * 0. `[writable]` The mint to initialize. - * 1. `[]` Rent sysvar - * - */ - Token_TokenInstruction_InitializeMint, - /** - * Initializes a new account to hold tokens. If this account is associated - * with the native mint then the token balance of the initialized account - * will be equal to the amount of SOL in the account. If this account is - * associated with another mint, that mint must be initialized before this - * command can succeed. - * - * The `InitializeAccount` instruction requires no signers and MUST be - * included within the same Transaction as the system program's - * `CreateAccount` instruction that creates the account being initialized. - * Otherwise another party can acquire ownership of the uninitialized - * account. - * - * Accounts expected by this instruction: - * - * 0. `[writable]` The account to initialize. - * 1. `[]` The mint this account will be associated with. - * 2. `[]` The new account's owner/multisignature. - * 3. `[]` Rent sysvar - */ - Token_TokenInstruction_InitializeAccount, - /** - * Initializes a multisignature account with N provided signers. - * - * Multisignature accounts can used in place of any single owner/delegate - * accounts in any token instruction that require an owner/delegate to be - * present. The variant field represents the number of signers (M) - * required to validate this multisignature account. - * - * The `InitializeMultisig` instruction requires no signers and MUST be - * included within the same Transaction as the system program's - * `CreateAccount` instruction that creates the account being initialized. - * Otherwise another party can acquire ownership of the uninitialized - * account. - * - * Accounts expected by this instruction: - * - * 0. `[writable]` The multisignature account to initialize. - * 1. `[]` Rent sysvar - * 2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <= - * 11. - */ - Token_TokenInstruction_InitializeMultisig, - /** - * Transfers tokens from one account to another either directly or via a - * delegate. If this account is associated with the native mint then equal - * amounts of SOL and Tokens will be transferred to the destination - * account. - * - * Accounts expected by this instruction: - * - * * Single owner/delegate - * 0. `[writable]` The source account. - * 1. `[writable]` The destination account. - * 2. `[signer]` The source account's owner/delegate. - * - * * Multisignature owner/delegate - * 0. `[writable]` The source account. - * 1. `[writable]` The destination account. - * 2. `[]` The source account's multisignature owner/delegate. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_Transfer, - /** - * Approves a delegate. A delegate is given the authority over tokens on - * behalf of the source account's owner. - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The source account. - * 1. `[]` The delegate. - * 2. `[signer]` The source account owner. - * - * * Multisignature owner - * 0. `[writable]` The source account. - * 1. `[]` The delegate. - * 2. `[]` The source account's multisignature owner. - * 3. ..3+M `[signer]` M signer accounts - */ - Token_TokenInstruction_Approve, - /** - * Revokes the delegate's authority. - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The source account. - * 1. `[signer]` The source account owner. - * - * * Multisignature owner - * 0. `[writable]` The source account. - * 1. `[]` The source account's multisignature owner. - * 2. ..2+M `[signer]` M signer accounts - */ - Token_TokenInstruction_Revoke, - /** - * Sets a new authority of a mint or account. - * - * Accounts expected by this instruction: - * - * * Single authority - * 0. `[writable]` The mint or account to change the authority of. - * 1. `[signer]` The current authority of the mint or account. - * - * * Multisignature authority - * 0. `[writable]` The mint or account to change the authority of. - * 1. `[]` The mint's or account's current multisignature authority. - * 2. ..2+M `[signer]` M signer accounts - */ - Token_TokenInstruction_SetAuthority, - /** - * Mints new tokens to an account. The native mint does not support - * minting. - * - * Accounts expected by this instruction: - * - * * Single authority - * 0. `[writable]` The mint. - * 1. `[writable]` The account to mint tokens to. - * 2. `[signer]` The mint's minting authority. - * - * * Multisignature authority - * 0. `[writable]` The mint. - * 1. `[writable]` The account to mint tokens to. - * 2. `[]` The mint's multisignature mint-tokens authority. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_MintTo, - /** - * Burns tokens by removing them from an account. `Burn` does not support - * accounts associated with the native mint, use `CloseAccount` instead. - * - * Accounts expected by this instruction: - * - * * Single owner/delegate - * 0. `[writable]` The account to burn from. - * 1. `[writable]` The token mint. - * 2. `[signer]` The account's owner/delegate. - * - * * Multisignature owner/delegate - * 0. `[writable]` The account to burn from. - * 1. `[writable]` The token mint. - * 2. `[]` The account's multisignature owner/delegate. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_Burn, - /** - * Close an account by transferring all its SOL to the destination account. - * Non-native accounts may only be closed if its token amount is zero. - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The account to close. - * 1. `[writable]` The destination account. - * 2. `[signer]` The account's owner. - * - * * Multisignature owner - * 0. `[writable]` The account to close. - * 1. `[writable]` The destination account. - * 2. `[]` The account's multisignature owner. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_CloseAccount, - /** - * Freeze an Initialized account using the Mint's freeze_authority (if - * set). - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The account to freeze. - * 1. `[]` The token mint. - * 2. `[signer]` The mint freeze authority. - * - * * Multisignature owner - * 0. `[writable]` The account to freeze. - * 1. `[]` The token mint. - * 2. `[]` The mint's multisignature freeze authority. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_FreezeAccount, - /** - * Thaw a Frozen account using the Mint's freeze_authority (if set). - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The account to freeze. - * 1. `[]` The token mint. - * 2. `[signer]` The mint freeze authority. - * - * * Multisignature owner - * 0. `[writable]` The account to freeze. - * 1. `[]` The token mint. - * 2. `[]` The mint's multisignature freeze authority. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_ThawAccount, - /** - * Transfers tokens from one account to another either directly or via a - * delegate. If this account is associated with the native mint then equal - * amounts of SOL and Tokens will be transferred to the destination - * account. - * - * This instruction differs from Transfer in that the token mint and - * decimals value is checked by the caller. This may be useful when - * creating transactions offline or within a hardware wallet. - * - * Accounts expected by this instruction: - * - * * Single owner/delegate - * 0. `[writable]` The source account. - * 1. `[]` The token mint. - * 2. `[writable]` The destination account. - * 3. `[signer]` The source account's owner/delegate. - * - * * Multisignature owner/delegate - * 0. `[writable]` The source account. - * 1. `[]` The token mint. - * 2. `[writable]` The destination account. - * 3. `[]` The source account's multisignature owner/delegate. - * 4. ..4+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_TransferChecked, - /** - * Approves a delegate. A delegate is given the authority over tokens on - * behalf of the source account's owner. - * - * This instruction differs from Approve in that the token mint and - * decimals value is checked by the caller. This may be useful when - * creating transactions offline or within a hardware wallet. - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The source account. - * 1. `[]` The token mint. - * 2. `[]` The delegate. - * 3. `[signer]` The source account owner. - * - * * Multisignature owner - * 0. `[writable]` The source account. - * 1. `[]` The token mint. - * 2. `[]` The delegate. - * 3. `[]` The source account's multisignature owner. - * 4. ..4+M `[signer]` M signer accounts - */ - Token_TokenInstruction_ApproveChecked, - /** - * Mints new tokens to an account. The native mint does not support - * minting. - * - * This instruction differs from MintTo in that the decimals value is - * checked by the caller. This may be useful when creating transactions - * offline or within a hardware wallet. - * - * Accounts expected by this instruction: - * - * * Single authority - * 0. `[writable]` The mint. - * 1. `[writable]` The account to mint tokens to. - * 2. `[signer]` The mint's minting authority. - * - * * Multisignature authority - * 0. `[writable]` The mint. - * 1. `[writable]` The account to mint tokens to. - * 2. `[]` The mint's multisignature mint-tokens authority. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_MintToChecked, - /** - * Burns tokens by removing them from an account. `BurnChecked` does not - * support accounts associated with the native mint, use `CloseAccount` - * instead. - * - * This instruction differs from Burn in that the decimals value is checked - * by the caller. This may be useful when creating transactions offline or - * within a hardware wallet. - * - * Accounts expected by this instruction: - * - * * Single owner/delegate - * 0. `[writable]` The account to burn from. - * 1. `[writable]` The token mint. - * 2. `[signer]` The account's owner/delegate. - * - * * Multisignature owner/delegate - * 0. `[writable]` The account to burn from. - * 1. `[writable]` The token mint. - * 2. `[]` The account's multisignature owner/delegate. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_BurnChecked, - /** - * Like InitializeAccount, but the owner pubkey is passed via instruction data - * rather than the accounts list. This variant may be preferable when using - * Cross Program Invocation from an instruction that does not need the owner's - * `AccountInfo` otherwise. - * - * Accounts expected by this instruction: - * - * 0. `[writable]` The account to initialize. - * 1. `[]` The mint this account will be associated with. - * 3. `[]` Rent sysvar - */ - Token_TokenInstruction_InitializeAccount2, - /** - * Given a wrapped / native token account (a token account containing SOL) - * updates its amount field based on the account's underlying `lamports`. - * This is useful if a non-wrapped SOL account uses `system_instruction::transfer` - * to move lamports to a wrapped token account, and needs to have its token - * `amount` field updated. - * - * Accounts expected by this instruction: - * - * 0. `[writable]` The native token account to sync with its underlying lamports. - */ - Token_TokenInstruction_SyncNative, -} Token_TokenInstruction_Tag; - -typedef struct Token_TokenInstruction_Token_InitializeMint_Body { - /** - * Number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; - /** - * The authority/multisignature to mint tokens. - */ - Token_Pubkey mint_authority; - /** - * The freeze authority/multisignature of the mint. - */ - struct Token_COption_Pubkey freeze_authority; -} Token_TokenInstruction_Token_InitializeMint_Body; - -typedef struct Token_TokenInstruction_Token_InitializeMultisig_Body { - /** - * The number of signers (M) required to validate this multisignature - * account. - */ - uint8_t m; -} Token_TokenInstruction_Token_InitializeMultisig_Body; - -typedef struct Token_TokenInstruction_Token_Transfer_Body { - /** - * The amount of tokens to transfer. - */ - uint64_t amount; -} Token_TokenInstruction_Token_Transfer_Body; - -typedef struct Token_TokenInstruction_Token_Approve_Body { - /** - * The amount of tokens the delegate is approved for. - */ - uint64_t amount; -} Token_TokenInstruction_Token_Approve_Body; - -typedef struct Token_TokenInstruction_Token_SetAuthority_Body { - /** - * The type of authority to update. - */ - Token_AuthorityType authority_type; - /** - * The new authority - */ - struct Token_COption_Pubkey new_authority; -} Token_TokenInstruction_Token_SetAuthority_Body; - -typedef struct Token_TokenInstruction_Token_MintTo_Body { - /** - * The amount of new tokens to mint. - */ - uint64_t amount; -} Token_TokenInstruction_Token_MintTo_Body; - -typedef struct Token_TokenInstruction_Token_Burn_Body { - /** - * The amount of tokens to burn. - */ - uint64_t amount; -} Token_TokenInstruction_Token_Burn_Body; - -typedef struct Token_TokenInstruction_Token_TransferChecked_Body { - /** - * The amount of tokens to transfer. - */ - uint64_t amount; - /** - * Expected number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; -} Token_TokenInstruction_Token_TransferChecked_Body; - -typedef struct Token_TokenInstruction_Token_ApproveChecked_Body { - /** - * The amount of tokens the delegate is approved for. - */ - uint64_t amount; - /** - * Expected number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; -} Token_TokenInstruction_Token_ApproveChecked_Body; - -typedef struct Token_TokenInstruction_Token_MintToChecked_Body { - /** - * The amount of new tokens to mint. - */ - uint64_t amount; - /** - * Expected number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; -} Token_TokenInstruction_Token_MintToChecked_Body; - -typedef struct Token_TokenInstruction_Token_BurnChecked_Body { - /** - * The amount of tokens to burn. - */ - uint64_t amount; - /** - * Expected number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; -} Token_TokenInstruction_Token_BurnChecked_Body; - -typedef struct Token_TokenInstruction_Token_InitializeAccount2_Body { - /** - * The new account's owner/multisignature. - */ - Token_Pubkey owner; -} Token_TokenInstruction_Token_InitializeAccount2_Body; - -typedef struct Token_TokenInstruction { - Token_TokenInstruction_Tag tag; - union { - Token_TokenInstruction_Token_InitializeMint_Body initialize_mint; - Token_TokenInstruction_Token_InitializeMultisig_Body initialize_multisig; - Token_TokenInstruction_Token_Transfer_Body transfer; - Token_TokenInstruction_Token_Approve_Body approve; - Token_TokenInstruction_Token_SetAuthority_Body set_authority; - Token_TokenInstruction_Token_MintTo_Body mint_to; - Token_TokenInstruction_Token_Burn_Body burn; - Token_TokenInstruction_Token_TransferChecked_Body transfer_checked; - Token_TokenInstruction_Token_ApproveChecked_Body approve_checked; - Token_TokenInstruction_Token_MintToChecked_Body mint_to_checked; - Token_TokenInstruction_Token_BurnChecked_Body burn_checked; - Token_TokenInstruction_Token_InitializeAccount2_Body initialize_account2; - }; -} Token_TokenInstruction; - -/** - * Mint data. - */ -typedef struct Token_Mint { - /** - * Optional authority used to mint new tokens. The mint authority may only be provided during - * mint creation. If no mint authority is present then the mint has a fixed supply and no - * further tokens may be minted. - */ - struct Token_COption_Pubkey mint_authority; - /** - * Total supply of tokens. - */ - uint64_t supply; - /** - * Number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; - /** - * Is `true` if this structure has been initialized - */ - bool is_initialized; - /** - * Optional authority to freeze token accounts. - */ - struct Token_COption_Pubkey freeze_authority; -} Token_Mint; - -/** - * A C representation of Rust's `std::option::Option` - */ -typedef enum Token_COption_u64_Tag { - /** - * No value - */ - Token_COption_u64_None_u64, - /** - * Some value `T` - */ - Token_COption_u64_Some_u64, -} Token_COption_u64_Tag; - -typedef struct Token_COption_u64 { - Token_COption_u64_Tag tag; - union { - struct { - uint64_t some; - }; - }; -} Token_COption_u64; - -/** - * Account data. - */ -typedef struct Token_Account { - /** - * The mint associated with this account - */ - Token_Pubkey mint; - /** - * The owner of this account. - */ - Token_Pubkey owner; - /** - * The amount of tokens this account holds. - */ - uint64_t amount; - /** - * If `delegate` is `Some` then `delegated_amount` represents - * the amount authorized by the delegate - */ - struct Token_COption_Pubkey delegate; - /** - * The account's state - */ - Token_AccountState state; - /** - * If is_some, this is a native token, and the value logs the rent-exempt reserve. An Account - * is required to be rent-exempt, so the value is used by the Processor to ensure that wrapped - * SOL accounts do not drop below this threshold. - */ - struct Token_COption_u64 is_native; - /** - * The amount delegated - */ - uint64_t delegated_amount; - /** - * Optional authority to close the account. - */ - struct Token_COption_Pubkey close_authority; -} Token_Account; - -/** - * Multisignature data. - */ -typedef struct Token_Multisig { - /** - * Number of signers required - */ - uint8_t m; - /** - * Number of valid signers - */ - uint8_t n; - /** - * Is `true` if this structure has been initialized - */ - bool is_initialized; - /** - * Signer public keys - */ - Token_Pubkey signers[Token_MAX_SIGNERS]; -} Token_Multisig; diff --git a/token/program-2022/program-id.md b/token/program-2022/program-id.md deleted file mode 100644 index 7d999512781..00000000000 --- a/token/program-2022/program-id.md +++ /dev/null @@ -1 +0,0 @@ -TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb diff --git a/token/program-2022/src/entrypoint.rs b/token/program-2022/src/entrypoint.rs deleted file mode 100644 index 1e534c5eda9..00000000000 --- a/token/program-2022/src/entrypoint.rs +++ /dev/null @@ -1,23 +0,0 @@ -//! Program entrypoint - -use { - crate::{error::TokenError, processor::Processor}, - solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, - program_error::PrintProgramError, pubkey::Pubkey, - }, -}; - -entrypoint!(process_instruction); -fn process_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - instruction_data: &[u8], -) -> ProgramResult { - if let Err(error) = Processor::process(program_id, accounts, instruction_data) { - // catch the error so we can print it - error.print::(); - return Err(error); - } - Ok(()) -} diff --git a/token/program-2022/src/error.rs b/token/program-2022/src/error.rs deleted file mode 100644 index 1a8d9603ade..00000000000 --- a/token/program-2022/src/error.rs +++ /dev/null @@ -1,273 +0,0 @@ -//! Error types - -use { - num_derive::FromPrimitive, - solana_program::{ - decode_error::DecodeError, - msg, - program_error::{PrintProgramError, ProgramError}, - }, - thiserror::Error, -}; - -/// Errors that may be returned by the Token program. -#[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] -pub enum TokenError { - // 0 - /// Lamport balance below rent-exempt threshold. - #[error("Lamport balance below rent-exempt threshold")] - NotRentExempt, - /// Insufficient funds for the operation requested. - #[error("Insufficient funds")] - InsufficientFunds, - /// Invalid Mint. - #[error("Invalid Mint")] - InvalidMint, - /// Account not associated with this Mint. - #[error("Account not associated with this Mint")] - MintMismatch, - /// Owner does not match. - #[error("Owner does not match")] - OwnerMismatch, - - // 5 - /// This token's supply is fixed and new tokens cannot be minted. - #[error("Fixed supply")] - FixedSupply, - /// The account cannot be initialized because it is already being used. - #[error("Already in use")] - AlreadyInUse, - /// Invalid number of provided signers. - #[error("Invalid number of provided signers")] - InvalidNumberOfProvidedSigners, - /// Invalid number of required signers. - #[error("Invalid number of required signers")] - InvalidNumberOfRequiredSigners, - /// State is uninitialized. - #[error("State is unititialized")] - UninitializedState, - - // 10 - /// Instruction does not support native tokens - #[error("Instruction does not support native tokens")] - NativeNotSupported, - /// Non-native account can only be closed if its balance is zero - #[error("Non-native account can only be closed if its balance is zero")] - NonNativeHasBalance, - /// Invalid instruction - #[error("Invalid instruction")] - InvalidInstruction, - /// State is invalid for requested operation. - #[error("State is invalid for requested operation")] - InvalidState, - /// Operation overflowed - #[error("Operation overflowed")] - Overflow, - - // 15 - /// Account does not support specified authority type. - #[error("Account does not support specified authority type")] - AuthorityTypeNotSupported, - /// This token mint cannot freeze accounts. - #[error("This token mint cannot freeze accounts")] - MintCannotFreeze, - /// Account is frozen; all account operations will fail - #[error("Account is frozen")] - AccountFrozen, - /// Mint decimals mismatch between the client and mint - #[error("The provided decimals value different from the Mint decimals")] - MintDecimalsMismatch, - /// Instruction does not support non-native tokens - #[error("Instruction does not support non-native tokens")] - NonNativeNotSupported, - - // 20 - /// Extension type does not match already existing extensions - #[error("Extension type does not match already existing extensions")] - ExtensionTypeMismatch, - /// Extension does not match the base type provided - #[error("Extension does not match the base type provided")] - ExtensionBaseMismatch, - /// Extension already initialized on this account - #[error("Extension already initialized on this account")] - ExtensionAlreadyInitialized, - /// An account can only be closed if its confidential balance is zero - #[error("An account can only be closed if its confidential balance is zero")] - ConfidentialTransferAccountHasBalance, - /// Account not approved for confidential transfers - #[error("Account not approved for confidential transfers")] - ConfidentialTransferAccountNotApproved, - - // 25 - /// Account not accepting deposits or transfers - #[error("Account not accepting deposits or transfers")] - ConfidentialTransferDepositsAndTransfersDisabled, - /// ElGamal public key mismatch - #[error("ElGamal public key mismatch")] - ConfidentialTransferElGamalPubkeyMismatch, - /// Balance mismatch - #[error("Balance mismatch")] - ConfidentialTransferBalanceMismatch, - /// Mint has non-zero supply. Burn all tokens before closing the mint. - #[error("Mint has non-zero supply. Burn all tokens before closing the mint")] - MintHasSupply, - /// No authority exists to perform the desired operation - #[error("No authority exists to perform the desired operation")] - NoAuthorityExists, - - // 30 - /// Transfer fee exceeds maximum of 10,000 basis points - #[error("Transfer fee exceeds maximum of 10,000 basis points")] - TransferFeeExceedsMaximum, - /// Mint required for this account to transfer tokens, use `transfer_checked` or `transfer_checked_with_fee` - #[error("Mint required for this account to transfer tokens, use `transfer_checked` or `transfer_checked_with_fee`")] - MintRequiredForTransfer, - /// Calculated fee does not match expected fee - #[error("Calculated fee does not match expected fee")] - FeeMismatch, - /// Fee parameters associated with confidential transfer zero-knowledge proofs do not match fee parameters in mint - #[error( - "Fee parameters associated with zero-knowledge proofs do not match fee parameters in mint" - )] - FeeParametersMismatch, - /// The owner authority cannot be changed - #[error("The owner authority cannot be changed")] - ImmutableOwner, - - // 35 - /// An account can only be closed if its withheld fee balance is zero, harvest fees to the - /// mint and try again - #[error("An account can only be closed if its withheld fee balance is zero, harvest fees to the mint and try again")] - AccountHasWithheldTransferFees, - - /// No memo in previous instruction; required for recipient to receive a transfer - #[error("No memo in previous instruction; required for recipient to receive a transfer")] - NoMemo, - /// Transfer is disabled for this mint - #[error("Transfer is disabled for this mint")] - NonTransferable, - /// Non-transferable tokens can't be minted to an account without immutable ownership - #[error("Non-transferable tokens can't be minted to an account without immutable ownership")] - NonTransferableNeedsImmutableOwnership, - /// The total number of `Deposit` and `Transfer` instructions to an account cannot exceed the - /// associated `maximum_pending_balance_credit_counter` - #[error( - "The total number of `Deposit` and `Transfer` instructions to an account cannot exceed - the associated `maximum_pending_balance_credit_counter`" - )] - MaximumPendingBalanceCreditCounterExceeded, -} -impl From for ProgramError { - fn from(e: TokenError) -> Self { - ProgramError::Custom(e as u32) - } -} -impl DecodeError for TokenError { - fn type_of() -> &'static str { - "TokenError" - } -} - -impl PrintProgramError for TokenError { - fn print(&self) - where - E: 'static + std::error::Error + DecodeError + num_traits::FromPrimitive, - { - match self { - TokenError::NotRentExempt => msg!("Error: Lamport balance below rent-exempt threshold"), - TokenError::InsufficientFunds => msg!("Error: insufficient funds"), - TokenError::InvalidMint => msg!("Error: Invalid Mint"), - TokenError::MintMismatch => msg!("Error: Account not associated with this Mint"), - TokenError::OwnerMismatch => msg!("Error: owner does not match"), - TokenError::FixedSupply => msg!("Error: the total supply of this token is fixed"), - TokenError::AlreadyInUse => msg!("Error: account or token already in use"), - TokenError::InvalidNumberOfProvidedSigners => { - msg!("Error: Invalid number of provided signers") - } - TokenError::InvalidNumberOfRequiredSigners => { - msg!("Error: Invalid number of required signers") - } - TokenError::UninitializedState => msg!("Error: State is uninitialized"), - TokenError::NativeNotSupported => { - msg!("Error: Instruction does not support native tokens") - } - TokenError::NonNativeHasBalance => { - msg!("Error: Non-native account can only be closed if its balance is zero") - } - TokenError::InvalidInstruction => msg!("Error: Invalid instruction"), - TokenError::InvalidState => msg!("Error: Invalid account state for operation"), - TokenError::Overflow => msg!("Error: Operation overflowed"), - TokenError::AuthorityTypeNotSupported => { - msg!("Error: Account does not support specified authority type") - } - TokenError::MintCannotFreeze => msg!("Error: This token mint cannot freeze accounts"), - TokenError::AccountFrozen => msg!("Error: Account is frozen"), - TokenError::MintDecimalsMismatch => { - msg!("Error: decimals different from the Mint decimals") - } - TokenError::NonNativeNotSupported => { - msg!("Error: Instruction does not support non-native tokens") - } - TokenError::ExtensionTypeMismatch => { - msg!("Error: New extension type does not match already existing extensions") - } - TokenError::ExtensionBaseMismatch => { - msg!("Error: Extension does not match the base type provided") - } - TokenError::ExtensionAlreadyInitialized => { - msg!("Error: Extension already initialized on this account") - } - TokenError::ConfidentialTransferAccountHasBalance => { - msg!("Error: An account can only be closed if its confidential balance is zero") - } - TokenError::ConfidentialTransferAccountNotApproved => { - msg!("Error: Account not approved for confidential transfers") - } - TokenError::ConfidentialTransferDepositsAndTransfersDisabled => { - msg!("Error: Account not accepting deposits or transfers") - } - TokenError::ConfidentialTransferElGamalPubkeyMismatch => { - msg!("Error: ElGamal public key mismatch") - } - TokenError::ConfidentialTransferBalanceMismatch => { - msg!("Error: Balance mismatch") - } - TokenError::MintHasSupply => { - msg!("Error: Mint has non-zero supply. Burn all tokens before closing the mint") - } - TokenError::NoAuthorityExists => { - msg!("Error: No authority exists to perform the desired operation"); - } - TokenError::TransferFeeExceedsMaximum => { - msg!("Error: Transfer fee exceeds maximum of 10,000 basis points"); - } - TokenError::MintRequiredForTransfer => { - msg!("Mint required for this account to transfer tokens, use `transfer_checked` or `transfer_checked_with_fee`"); - } - TokenError::FeeMismatch => { - msg!("Calculated fee does not match expected fee"); - } - TokenError::FeeParametersMismatch => { - msg!("Fee parameters associated with zero-knowledge proofs do not match fee parameters in mint") - } - TokenError::ImmutableOwner => { - msg!("The owner authority cannot be changed"); - } - TokenError::AccountHasWithheldTransferFees => { - msg!("Error: An account can only be closed if its withheld fee balance is zero, harvest fees to the mint and try again"); - } - TokenError::NoMemo => { - msg!("Error: No memo in previous instruction; required for recipient to receive a transfer"); - } - TokenError::NonTransferable => { - msg!("Transfer is disabled for this mint"); - } - TokenError::NonTransferableNeedsImmutableOwnership => { - msg!("Non-transferable tokens can't be minted to an account without immutable ownership"); - } - TokenError::MaximumPendingBalanceCreditCounterExceeded => { - msg!("The total number of `Deposit` and `Transfer` instructions to an account cannot exceed the associated `maximum_pending_balance_credit_counter`"); - } - } - } -} diff --git a/token/program-2022/src/extension/confidential_transfer/instruction.rs b/token/program-2022/src/extension/confidential_transfer/instruction.rs deleted file mode 100644 index 20917f17c7a..00000000000 --- a/token/program-2022/src/extension/confidential_transfer/instruction.rs +++ /dev/null @@ -1,1115 +0,0 @@ -#[cfg(not(target_os = "solana"))] -use solana_zk_token_sdk::encryption::auth_encryption::AeCiphertext; -pub use solana_zk_token_sdk::zk_token_proof_instruction::*; -use { - crate::{ - check_program_account, - extension::confidential_transfer::*, - instruction::{encode_instruction, TokenInstruction}, - }, - bytemuck::{Pod, Zeroable}, - num_enum::{IntoPrimitive, TryFromPrimitive}, - solana_program::{ - instruction::{AccountMeta, Instruction}, - program_error::ProgramError, - pubkey::Pubkey, - sysvar, - }, - solana_zk_token_sdk::zk_token_elgamal::pod, - std::convert::TryFrom, -}; - -/// Confidential Transfer extension instructions -#[derive(Clone, Copy, Debug, TryFromPrimitive, IntoPrimitive)] -#[repr(u8)] -pub enum ConfidentialTransferInstruction { - /// Initializes confidential transfers for a mint. - /// - /// The `ConfidentialTransferInstruction::InitializeMint` instruction requires no signers - /// and MUST be included within the same Transaction as `TokenInstruction::InitializeMint`. - /// Otherwise another party can initialize the configuration. - /// - /// The instruction fails if the `TokenInstruction::InitializeMint` instruction has already - /// executed for the mint. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The SPL Token mint. - /// - /// Data expected by this instruction: - /// `ConfidentialTransferMint` - /// - InitializeMint, - - /// Updates the confidential transfer mint configuration for a mint. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The SPL Token mint. - /// 1. `[signer]` Confidential transfer mint authority. - /// 2. `[signer]` New confidential transfer mint authority. - /// - /// Data expected by this instruction: - /// `ConfidentialTransferMint` - /// - UpdateMint, - - /// Configures confidential transfers for a token account. - /// - /// The instruction fails if the confidential transfers are already configured, or if the mint - /// was not initialized with confidential transfer support. - /// - /// The instruction fails if the `TokenInstruction::InitializeAccount` instruction has not yet - /// successfully executed for the token account. - /// - /// Upon success confidential deposits and transfers are enabled, use the - /// `DisableBalanceCredits` instruction to disable. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner/delegate - /// 0. `[writeable]` The SPL Token account. - /// 1. `[]` The corresponding SPL Token mint. - /// 2. `[signer]` The single source account owner. - /// - /// * Multisignature owner/delegate - /// 0. `[writeable]` The SPL Token account. - /// 1. `[]` The corresponding SPL Token mint. - /// 2. `[]` The multisig source account owner. - /// 3.. `[signer]` Required M signer accounts for the SPL Token Multisig account. - /// - /// Data expected by this instruction: - /// `ConfigureAccountInstructionData` - /// - ConfigureAccount, - - /// Approves a token account for confidential transfers. - /// - /// Approval is only required when the `ConfidentialTransferMint::approve_new_accounts` - /// field is set in the SPL Token mint. This instruction must be executed after the account - /// owner configures their account for confidential transfers with - /// `ConfidentialTransferInstruction::ConfigureAccount`. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The SPL Token account to approve. - /// 1. `[]` The SPL Token mint. - /// 2. `[signer]` Confidential transfer auditor authority. - /// - /// Data expected by this instruction: - /// None - /// - ApproveAccount, - - /// Prepare a token account for closing. The account must not hold any confidential tokens in - /// its pending or available balances. Use - /// `ConfidentialTransferInstruction::DisableBalanceCredits` to block balance credit changes - /// first if necessary. - /// - /// Note that a newly configured account is always empty, so this instruction is not required - /// prior to account closing if no instructions beyond - /// `ConfidentialTransferInstruction::ConfigureAccount` have affected the token account. - /// - /// * Single owner/delegate - /// 0. `[writable]` The SPL Token account. - /// 1. `[]` Instructions sysvar. - /// 2. `[signer]` The single account owner. - /// - /// * Multisignature owner/delegate - /// 0. `[writable]` The SPL Token account. - /// 1. `[]` Instructions sysvar. - /// 2. `[]` The multisig account owner. - /// 3.. `[signer]` Required M signer accounts for the SPL Token Multisig account. - /// - /// Data expected by this instruction: - /// `EmptyAccountInstructionData` - /// - EmptyAccount, - - /// Deposit SPL Tokens into the pending balance of a confidential token account. - /// - /// The account owner can then invoke the `ApplyPendingBalance` instruction to roll the deposit - /// into their available balance at a time of their choosing. - /// - /// Fails if the source or destination accounts are frozen. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner/delegate - /// 0. `[writable]` The source SPL Token account. - /// 1. `[writable]` The destination SPL Token account with confidential transfers configured. - /// 2. `[]` The token mint. - /// 3. `[signer]` The single source account owner or delegate. - /// - /// * Multisignature owner/delegate - /// 0. `[writable]` The source SPL Token account. - /// 1. `[writable]` The destination SPL Token account with confidential transfers configured. - /// 2. `[]` The token mint. - /// 3. `[]` The multisig source account owner or delegate. - /// 4.. `[signer]` Required M signer accounts for the SPL Token Multisig account. - /// - /// Data expected by this instruction: - /// `DepositInstructionData` - /// - Deposit, - - /// Withdraw SPL Tokens from the available balance of a confidential token account. - /// - /// Fails if the source or destination accounts are frozen. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner/delegate - /// 0. `[writable]` The source SPL Token account with confidential transfers configured. - /// 1. `[writable]` The destination SPL Token account. - /// 2. `[]` The token mint. - /// 3. `[]` Instructions sysvar. - /// 4. `[signer]` The single source account owner. - /// - /// * Multisignature owner/delegate - /// 0. `[writable]` The source SPL Token account with confidential transfers configured. - /// 1. `[writable]` The destination SPL Token account. - /// 2. `[]` The token mint. - /// 3. `[]` Instructions sysvar. - /// 4. `[]` The multisig source account owner. - /// 5.. `[signer]` Required M signer accounts for the SPL Token Multisig account. - /// - /// Data expected by this instruction: - /// `WithdrawInstructionData` - /// - Withdraw, - - /// Transfer tokens confidentially. - /// - /// * Single owner/delegate - /// 1. `[writable]` The source SPL Token account. - /// 2. `[writable]` The destination SPL Token account. - /// 3. `[]` The token mint. - /// 4. `[]` Instructions sysvar. - /// 5. `[signer]` The single source account owner. - /// - /// * Multisignature owner/delegate - /// 1. `[writable]` The source SPL Token account. - /// 2. `[writable]` The destination SPL Token account. - /// 3. `[]` The token mint. - /// 4. `[]` Instructions sysvar. - /// 5. `[]` The multisig source account owner. - /// 6.. `[signer]` Required M signer accounts for the SPL Token Multisig account. - /// - /// Data expected by this instruction: - /// `TransferInstructionData` - /// - Transfer, - - /// Transfer tokens confidentially with fee. - /// - /// * Single owner/delegate - /// 1. `[writable]` The source SPL Token account. - /// 2. `[writable]` The destination SPL Token account. - /// 3. `[]` The token mint. - /// 4. `[]` Instructions sysvar. - /// 5. `[signer]` The single source account owner. - /// - /// * Multisignature owner/delegate - /// 1. `[writable]` The source SPL Token account. - /// 2. `[writable]` The destination SPL Token account. - /// 3. `[]` The token mint. - /// 4. `[]` Instructions sysvar. - /// 5. `[]` The multisig source account owner. - /// 6.. `[signer]` Required M signer accounts for the SPL Token Multisig account. - /// - /// Data expected by this instruction: - /// `TransferInstructionData` - /// - TransferWithFee, - - /// Applies the pending balance to the available balance, based on the history of `Deposit` - /// and/or `Transfer` instructions. - /// - /// After submitting `ApplyPendingBalance`, the client should compare - /// `ConfidentialTransferAccount::expected_pending_balance_credit_counter` with - /// `ConfidentialTransferAccount::actual_applied_pending_balance_instructions`. If they are - /// equal then the `ConfidentialTransferAccount::decryptable_available_balance` is consistent - /// with `ConfidentialTransferAccount::available_balance`. If they differ then there is more - /// pending balance to be applied. - /// - /// Account expected by this instruction: - /// - /// * Single owner/delegate - /// 0. `[writable]` The SPL Token account. - /// 1. `[signer]` The single account owner. - /// - /// * Multisignature owner/delegate - /// 0. `[writable]` The SPL Token account. - /// 1. `[]` The multisig account owner. - /// 2.. `[signer]` Required M signer accounts for the SPL Token Multisig account. - /// - /// Data expected by this instruction: - /// `ApplyPendingBalanceData` - /// - ApplyPendingBalance, - - /// Enable confidential transfer `Deposit` and `Transfer` instructions for a token account. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner/delegate - /// 0. `[writable]` The SPL Token account. - /// 1. `[signer]` Single authority. - /// - /// * Multisignature owner/delegate - /// 0. `[writable]` The SPL Token account. - /// 1. `[]` Multisig authority. - /// 2.. `[signer]` Required M signer accounts for the SPL Token Multisig account. - /// - /// Data expected by this instruction: - /// None - /// - EnableBalanceCredits, - - /// Disable confidential transfer `Deposit` and `Transfer` instructions for a token account. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner/delegate - /// 0. `[writable]` The SPL Token account. - /// 1. `[signer]` The single account owner. - /// - /// * Multisignature owner/delegate - /// 0. `[writable]` The SPL Token account. - /// 1. `[]` The multisig account owner. - /// 2.. `[signer]` Required M signer accounts for the SPL Token Multisig account. - /// - /// Data expected by this instruction: - /// None - /// - DisableBalanceCredits, - - /// Transfer all withheld confidential tokens in the mint to an account. Signed by the mint's - /// withdraw withheld tokens authority. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner/delegate - /// 0. `[writable]` The token mint. Must include the `TransferFeeConfig` extension. - /// 1. `[writable]` The fee receiver account. Must include the `TransferFeeAmount` and - /// `ConfidentialTransferAccount` extensions. - /// 2. `[]` Instructions sysvar. - /// 3. `[signer]` The mint's `withdraw_withheld_authority`. - /// - /// * Multisignature owner/delegate - /// 0. `[writable]` The token mint. Must include the `TransferFeeConfig` extension. - /// 1. `[writable]` The fee receiver account. Must include the `TransferFeeAmount` and - /// `ConfidentialTransferAccount` extensions. - /// 2. `[]` Instructions sysvar. - /// 3. `[]` The mint's multisig `withdraw_withheld_authority`. - /// 4. ..3+M `[signer]` M signer accounts. - /// - /// Data expected by this instruction: - /// WithdrawWithheldTokensFromMintData - /// - WithdrawWithheldTokensFromMint, - - /// Transfer all withheld tokens to an account. Signed by the mint's withdraw withheld tokens - /// authority. This instruction is susceptible to front-running. Use - /// `HarvestWithheldTokensToMint` and `WithdrawWithheldTokensFromMint` as an alternative. - /// - /// Note on front-running: This instruction requires a zero-knowledge proof verification - /// instruction that is checked with respect to the account state (the currently withheld - /// fees). Suppose that a withdraw withheld authority generates the - /// `WithdrawWithheldTokensFromAccounts` instruction along with a corresponding zero-knowledge - /// proof for a specified set of accounts, and submits it on chain. If the withheld fees at any - /// of the specified accounts change before the `WithdrawWithheldTokensFromAccounts` is - /// executed on chain, the zero-knowledge proof will not verify with respect to the new state, - /// forcing the transaction to fail. - /// - /// If front-running occurs, then users can look up the updated states of the accounts, - /// generate a new zero-knowledge proof and try again. Alternatively, withdraw withheld - /// authority can first move the withheld amount to the mint using - /// `HarvestWithheldTokensToMint` and then move the withheld fees from mint to a specified - /// destination account using `WithdrawWithheldTokensFromMint`. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner/delegate - /// 0. `[]` The token mint. Must include the `TransferFeeConfig` extension. - /// 1. `[writable]` The fee receiver account. Must include the `TransferFeeAmount` and - /// `ConfidentialTransferAccount` extensions. - /// 2. `[]` Instructions sysvar. - /// 3. `[signer]` The mint's `withdraw_withheld_authority`. - /// 4. ..3+N `[writable]` The source accounts to withdraw from. - /// - /// * Multisignature owner/delegate - /// 0. `[]` The token mint. Must include the `TransferFeeConfig` extension. - /// 1. `[writable]` The fee receiver account. Must include the `TransferFeeAmount` and - /// `ConfidentialTransferAccount` extensions. - /// 2. `[]` Instructions sysvar. - /// 3. `[]` The mint's multisig `withdraw_withheld_authority`. - /// 4. ..4+M `[signer]` M signer accounts. - /// 4+M+1. ..3+M+N `[writable]` The source accounts to withdraw from. - /// - /// Data expected by this instruction: - /// WithdrawWithheldTokensFromAccountsData - /// - WithdrawWithheldTokensFromAccounts, - - /// Permissionless instruction to transfer all withheld confidential tokens to the mint. - /// - /// Succeeds for frozen accounts. - /// - /// Accounts provided should include both the `TransferFeeAmount` and - /// `ConfidentialTransferAccount` extension. If not, the account is skipped. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The mint. - /// 1. ..1+N `[writable]` The source accounts to harvest from. - /// - /// Data expected by this instruction: - /// None - /// - HarvestWithheldTokensToMint, -} - -/// Data expected by `ConfidentialTransferInstruction::ConfigureAccount` -#[derive(Clone, Copy, Pod, Zeroable)] -#[repr(C)] -pub struct ConfigureAccountInstructionData { - /// The public key associated with the account - pub encryption_pubkey: EncryptionPubkey, - /// The decryptable balance (always 0) once the configure account succeeds - pub decryptable_zero_balance: DecryptableBalance, - /// The maximum number of despots and transfers that an account can receiver before the - /// `ApplyPendingBalance` is executed - pub maximum_pending_balance_credit_counter: PodU64, -} - -/// Data expected by `ConfidentialTransferInstruction::EmptyAccount` -#[derive(Clone, Copy, Pod, Zeroable)] -#[repr(C)] -pub struct EmptyAccountInstructionData { - /// Relative location of the `ProofInstruction::VerifyCloseAccount` instruction to the - /// `EmptyAccount` instruction in the transaction - pub proof_instruction_offset: i8, -} - -/// Data expected by `ConfidentialTransferInstruction::Deposit` -#[derive(Clone, Copy, Pod, Zeroable)] -#[repr(C)] -pub struct DepositInstructionData { - /// The amount of tokens to deposit - pub amount: PodU64, - /// Expected number of base 10 digits to the right of the decimal place - pub decimals: u8, -} - -/// Data expected by `ConfidentialTransferInstruction::Withdraw` -#[derive(Clone, Copy, Pod, Zeroable)] -#[repr(C)] -pub struct WithdrawInstructionData { - /// The amount of tokens to withdraw - pub amount: PodU64, - /// Expected number of base 10 digits to the right of the decimal place - pub decimals: u8, - /// The new decryptable balance if the withrawal succeeds - pub new_decryptable_available_balance: DecryptableBalance, - /// Relative location of the `ProofInstruction::VerifyWithdraw` instruction to the `Withdraw` - /// instruction in the transaction - pub proof_instruction_offset: i8, -} - -/// Data expected by `ConfidentialTransferInstruction::Transfer` and -/// `ConfidentialTransferInstruction::TransferWithFee` -#[derive(Clone, Copy, Pod, Zeroable)] -#[repr(C)] -pub struct TransferInstructionData { - /// The new source decryptable balance if the transfer succeeds - pub new_source_decryptable_available_balance: DecryptableBalance, - /// Relative location of the `ProofInstruction::VerifyTransfer` instruction to the - /// `Transfer` instruction in the transaction - pub proof_instruction_offset: i8, -} - -/// Data expected by `ConfidentialTransferInstruction::ApplyPendingBalance` -#[derive(Clone, Copy, Pod, Zeroable)] -#[repr(C)] -pub struct ApplyPendingBalanceData { - /// The expected number of pending balance credits since the last successful - /// `ApplyPendingBalance` instruction - pub expected_pending_balance_credit_counter: PodU64, - /// The new decryptable balance if the pending balance is applied successfully - pub new_decryptable_available_balance: pod::AeCiphertext, -} - -/// Data expected by `ConfidentialTransferInstruction::WithdrawWithheldTokensFromMint` -#[derive(Clone, Copy, Pod, Zeroable)] -#[repr(C)] -pub struct WithdrawWithheldTokensFromMintData { - /// Relative location of the `ProofInstruction::VerifyWithdrawWithheld` instruction to the - /// `WithdrawWithheldTokensFromMint` instruction in the transaction - pub proof_instruction_offset: i8, -} - -/// Data expected by `ConfidentialTransferInstruction::WithdrawWithheldTokensFromAccounts` -#[derive(Clone, Copy, Pod, Zeroable)] -#[repr(C)] -pub struct WithdrawWithheldTokensFromAccountsData { - /// Number of token accounts harvested - pub num_token_accounts: u8, - /// Relative location of the `ProofInstruction::VerifyWithdrawWithheld` instruction to the - /// `VerifyWithdrawWithheldTokensFromAccounts` instruction in the transaction - pub proof_instruction_offset: i8, -} - -/// Create a `InitializeMint` instruction -pub fn initialize_mint( - token_program_id: &Pubkey, - mint: &Pubkey, - ct_mint: &ConfidentialTransferMint, -) -> Result { - check_program_account(token_program_id)?; - let accounts = vec![AccountMeta::new(*mint, false)]; - Ok(encode_instruction( - token_program_id, - accounts, - TokenInstruction::ConfidentialTransferExtension, - ConfidentialTransferInstruction::InitializeMint, - ct_mint, - )) -} - -/// Create a `UpdateMint` instruction -pub fn update_mint( - token_program_id: &Pubkey, - mint: &Pubkey, - new_ct_mint: &ConfidentialTransferMint, - authority: &Pubkey, -) -> Result { - check_program_account(token_program_id)?; - let accounts = vec![ - AccountMeta::new(*mint, false), - AccountMeta::new_readonly(*authority, true), - AccountMeta::new_readonly( - new_ct_mint.authority, - new_ct_mint.authority != Pubkey::default(), - ), - ]; - Ok(encode_instruction( - token_program_id, - accounts, - TokenInstruction::ConfidentialTransferExtension, - ConfidentialTransferInstruction::UpdateMint, - new_ct_mint, - )) -} - -/// Create a `ConfigureAccount` instruction -#[allow(clippy::too_many_arguments)] -#[cfg(not(target_os = "solana"))] -pub fn configure_account( - token_program_id: &Pubkey, - token_account: &Pubkey, - mint: &Pubkey, - encryption_pubkey: EncryptionPubkey, - decryptable_zero_balance: AeCiphertext, - maximum_pending_balance_credit_counter: u64, - authority: &Pubkey, - multisig_signers: &[&Pubkey], -) -> Result { - check_program_account(token_program_id)?; - let mut accounts = vec![ - AccountMeta::new(*token_account, false), - AccountMeta::new_readonly(*mint, false), - AccountMeta::new_readonly(*authority, multisig_signers.is_empty()), - ]; - - for multisig_signer in multisig_signers.iter() { - accounts.push(AccountMeta::new_readonly(**multisig_signer, true)); - } - - Ok(encode_instruction( - token_program_id, - accounts, - TokenInstruction::ConfidentialTransferExtension, - ConfidentialTransferInstruction::ConfigureAccount, - &ConfigureAccountInstructionData { - encryption_pubkey, - decryptable_zero_balance: decryptable_zero_balance.into(), - maximum_pending_balance_credit_counter: maximum_pending_balance_credit_counter.into(), - }, - )) -} - -/// Create an `ApproveAccount` instruction -pub fn approve_account( - token_program_id: &Pubkey, - account_to_approve: &Pubkey, - mint: &Pubkey, - authority: &Pubkey, -) -> Result { - check_program_account(token_program_id)?; - let accounts = vec![ - AccountMeta::new(*account_to_approve, false), - AccountMeta::new_readonly(*mint, false), - AccountMeta::new_readonly(*authority, true), - ]; - Ok(encode_instruction( - token_program_id, - accounts, - TokenInstruction::ConfidentialTransferExtension, - ConfidentialTransferInstruction::ApproveAccount, - &(), - )) -} - -/// Create an inner `EmptyAccount` instruction -/// -/// This instruction is suitable for use with a cross-program `invoke` -pub fn inner_empty_account( - token_program_id: &Pubkey, - token_account: &Pubkey, - authority: &Pubkey, - multisig_signers: &[&Pubkey], - proof_instruction_offset: i8, -) -> Result { - check_program_account(token_program_id)?; - let mut accounts = vec![ - AccountMeta::new(*token_account, false), - AccountMeta::new_readonly(sysvar::instructions::id(), false), - AccountMeta::new_readonly(*authority, multisig_signers.is_empty()), - ]; - - for multisig_signer in multisig_signers.iter() { - accounts.push(AccountMeta::new_readonly(**multisig_signer, true)); - } - - Ok(encode_instruction( - token_program_id, - accounts, - TokenInstruction::ConfidentialTransferExtension, - ConfidentialTransferInstruction::EmptyAccount, - &EmptyAccountInstructionData { - proof_instruction_offset, - }, - )) -} - -/// Create a `EmptyAccount` instruction -pub fn empty_account( - token_program_id: &Pubkey, - token_account: &Pubkey, - authority: &Pubkey, - multisig_signers: &[&Pubkey], - proof_data: &CloseAccountData, -) -> Result, ProgramError> { - Ok(vec![ - verify_close_account(proof_data), - inner_empty_account( - token_program_id, - token_account, - authority, - multisig_signers, - -1, - )?, // calls check_program_account - ]) -} - -/// Create a `Deposit` instruction -#[allow(clippy::too_many_arguments)] -pub fn deposit( - token_program_id: &Pubkey, - source_token_account: &Pubkey, - mint: &Pubkey, - destination_token_account: &Pubkey, - amount: u64, - decimals: u8, - authority: &Pubkey, - multisig_signers: &[&Pubkey], -) -> Result { - check_program_account(token_program_id)?; - let mut accounts = vec![ - AccountMeta::new(*source_token_account, false), - AccountMeta::new(*destination_token_account, false), - AccountMeta::new_readonly(*mint, false), - AccountMeta::new_readonly(*authority, multisig_signers.is_empty()), - ]; - - for multisig_signer in multisig_signers.iter() { - accounts.push(AccountMeta::new_readonly(**multisig_signer, true)); - } - - Ok(encode_instruction( - token_program_id, - accounts, - TokenInstruction::ConfidentialTransferExtension, - ConfidentialTransferInstruction::Deposit, - &DepositInstructionData { - amount: amount.into(), - decimals, - }, - )) -} - -/// Create a inner `Withdraw` instruction -/// -/// This instruction is suitable for use with a cross-program `invoke` -#[allow(clippy::too_many_arguments)] -pub fn inner_withdraw( - token_program_id: &Pubkey, - source_token_account: &Pubkey, - destination_token_account: &Pubkey, - mint: &Pubkey, - amount: u64, - decimals: u8, - new_decryptable_available_balance: DecryptableBalance, - authority: &Pubkey, - multisig_signers: &[&Pubkey], - proof_instruction_offset: i8, -) -> Result { - check_program_account(token_program_id)?; - let mut accounts = vec![ - AccountMeta::new(*source_token_account, false), - AccountMeta::new(*destination_token_account, false), - AccountMeta::new_readonly(*mint, false), - AccountMeta::new_readonly(sysvar::instructions::id(), false), - AccountMeta::new_readonly(*authority, multisig_signers.is_empty()), - ]; - - for multisig_signer in multisig_signers.iter() { - accounts.push(AccountMeta::new_readonly(**multisig_signer, true)); - } - - Ok(encode_instruction( - token_program_id, - accounts, - TokenInstruction::ConfidentialTransferExtension, - ConfidentialTransferInstruction::Withdraw, - &WithdrawInstructionData { - amount: amount.into(), - decimals, - new_decryptable_available_balance, - proof_instruction_offset, - }, - )) -} - -/// Create a `Withdraw` instruction -#[allow(clippy::too_many_arguments)] -#[cfg(not(target_os = "solana"))] -pub fn withdraw( - token_program_id: &Pubkey, - source_token_account: &Pubkey, - destination_token_account: &Pubkey, - mint: &Pubkey, - amount: u64, - decimals: u8, - new_decryptable_available_balance: AeCiphertext, - authority: &Pubkey, - multisig_signers: &[&Pubkey], - proof_data: &WithdrawData, -) -> Result, ProgramError> { - Ok(vec![ - verify_withdraw(proof_data), - inner_withdraw( - token_program_id, - source_token_account, - destination_token_account, - mint, - amount, - decimals, - new_decryptable_available_balance.into(), - authority, - multisig_signers, - -1, - )?, // calls check_program_account - ]) -} - -/// Create a inner `Transfer` instruction -/// -/// This instruction is suitable for use with a cross-program `invoke` -#[allow(clippy::too_many_arguments)] -pub fn inner_transfer( - token_program_id: &Pubkey, - source_token_account: &Pubkey, - destination_token_account: &Pubkey, - mint: &Pubkey, - new_source_decryptable_available_balance: DecryptableBalance, - authority: &Pubkey, - multisig_signers: &[&Pubkey], - proof_instruction_offset: i8, -) -> Result { - check_program_account(token_program_id)?; - let mut accounts = vec![ - AccountMeta::new(*source_token_account, false), - AccountMeta::new(*destination_token_account, false), - AccountMeta::new_readonly(*mint, false), - AccountMeta::new_readonly(sysvar::instructions::id(), false), - AccountMeta::new_readonly(*authority, multisig_signers.is_empty()), - ]; - - for multisig_signer in multisig_signers.iter() { - accounts.push(AccountMeta::new_readonly(**multisig_signer, true)); - } - - Ok(encode_instruction( - token_program_id, - accounts, - TokenInstruction::ConfidentialTransferExtension, - ConfidentialTransferInstruction::Transfer, - &TransferInstructionData { - new_source_decryptable_available_balance, - proof_instruction_offset, - }, - )) -} - -/// Create a `Transfer` instruction -#[allow(clippy::too_many_arguments)] -#[cfg(not(target_os = "solana"))] -pub fn transfer( - token_program_id: &Pubkey, - source_token_account: &Pubkey, - destination_token_account: &Pubkey, - mint: &Pubkey, - new_source_decryptable_available_balance: AeCiphertext, - authority: &Pubkey, - multisig_signers: &[&Pubkey], - proof_data: &TransferData, -) -> Result, ProgramError> { - Ok(vec![ - verify_transfer(proof_data), - inner_transfer( - token_program_id, - source_token_account, - destination_token_account, - mint, - new_source_decryptable_available_balance.into(), - authority, - multisig_signers, - -1, - )?, // calls check_program_account - ]) -} - -/// Create a inner `TransferWithFee` instruction -/// -/// This instruction is suitable for use with a cross-program `invoke` -#[allow(clippy::too_many_arguments)] -pub fn inner_transfer_with_fee( - token_program_id: &Pubkey, - source_token_account: &Pubkey, - destination_token_account: &Pubkey, - mint: &Pubkey, - new_source_decryptable_available_balance: DecryptableBalance, - authority: &Pubkey, - multisig_signers: &[&Pubkey], - proof_instruction_offset: i8, -) -> Result { - check_program_account(token_program_id)?; - let mut accounts = vec![ - AccountMeta::new(*source_token_account, false), - AccountMeta::new(*destination_token_account, false), - AccountMeta::new_readonly(*mint, false), - AccountMeta::new_readonly(sysvar::instructions::id(), false), - AccountMeta::new_readonly(*authority, multisig_signers.is_empty()), - ]; - - for multisig_signer in multisig_signers.iter() { - accounts.push(AccountMeta::new_readonly(**multisig_signer, true)); - } - - Ok(encode_instruction( - token_program_id, - accounts, - TokenInstruction::ConfidentialTransferExtension, - ConfidentialTransferInstruction::TransferWithFee, - &TransferInstructionData { - new_source_decryptable_available_balance, - proof_instruction_offset, - }, - )) -} - -/// Create a `Transfer` instruction -#[allow(clippy::too_many_arguments)] -#[cfg(not(target_os = "solana"))] -pub fn transfer_with_fee( - token_program_id: &Pubkey, - source_token_account: &Pubkey, - destination_token_account: &Pubkey, - mint: &Pubkey, - new_source_decryptable_available_balance: AeCiphertext, - authority: &Pubkey, - multisig_signers: &[&Pubkey], - proof_data: &TransferWithFeeData, -) -> Result, ProgramError> { - Ok(vec![ - verify_transfer_with_fee(proof_data), - inner_transfer_with_fee( - token_program_id, - source_token_account, - destination_token_account, - mint, - new_source_decryptable_available_balance.into(), - authority, - multisig_signers, - -1, - )?, // calls check_program_account - ]) -} - -/// Create a inner `ApplyPendingBalance` instruction -/// -/// This instruction is suitable for use with a cross-program `invoke` -pub fn inner_apply_pending_balance( - token_program_id: &Pubkey, - token_account: &Pubkey, - expected_pending_balance_credit_counter: u64, - new_decryptable_available_balance: DecryptableBalance, - authority: &Pubkey, - multisig_signers: &[&Pubkey], -) -> Result { - check_program_account(token_program_id)?; - let mut accounts = vec![ - AccountMeta::new(*token_account, false), - AccountMeta::new_readonly(*authority, multisig_signers.is_empty()), - ]; - - for multisig_signer in multisig_signers.iter() { - accounts.push(AccountMeta::new_readonly(**multisig_signer, true)); - } - - Ok(encode_instruction( - token_program_id, - accounts, - TokenInstruction::ConfidentialTransferExtension, - ConfidentialTransferInstruction::ApplyPendingBalance, - &ApplyPendingBalanceData { - expected_pending_balance_credit_counter: expected_pending_balance_credit_counter.into(), - new_decryptable_available_balance, - }, - )) -} - -/// Create a `ApplyPendingBalance` instruction -#[cfg(not(target_os = "solana"))] -pub fn apply_pending_balance( - token_program_id: &Pubkey, - token_account: &Pubkey, - pending_balance_instructions: u64, - new_decryptable_available_balance: AeCiphertext, - authority: &Pubkey, - multisig_signers: &[&Pubkey], -) -> Result { - inner_apply_pending_balance( - token_program_id, - token_account, - pending_balance_instructions, - new_decryptable_available_balance.into(), - authority, - multisig_signers, - ) // calls check_program_account -} - -fn enable_or_disable_balance_credits( - instruction: ConfidentialTransferInstruction, - token_program_id: &Pubkey, - token_account: &Pubkey, - authority: &Pubkey, - multisig_signers: &[&Pubkey], -) -> Result { - check_program_account(token_program_id)?; - let mut accounts = vec![ - AccountMeta::new(*token_account, false), - AccountMeta::new_readonly(*authority, multisig_signers.is_empty()), - ]; - - for multisig_signer in multisig_signers.iter() { - accounts.push(AccountMeta::new_readonly(**multisig_signer, true)); - } - - Ok(encode_instruction( - token_program_id, - accounts, - TokenInstruction::ConfidentialTransferExtension, - instruction, - &(), - )) -} - -/// Create a `EnableBalanceCredits` instruction -pub fn enable_balance_credits( - token_program_id: &Pubkey, - token_account: &Pubkey, - authority: &Pubkey, - multisig_signers: &[&Pubkey], -) -> Result { - enable_or_disable_balance_credits( - ConfidentialTransferInstruction::EnableBalanceCredits, - token_program_id, - token_account, - authority, - multisig_signers, - ) -} - -/// Create a `DisableBalanceCredits` instruction -pub fn disable_balance_credits( - token_program_id: &Pubkey, - token_account: &Pubkey, - authority: &Pubkey, - multisig_signers: &[&Pubkey], -) -> Result { - enable_or_disable_balance_credits( - ConfidentialTransferInstruction::DisableBalanceCredits, - token_program_id, - token_account, - authority, - multisig_signers, - ) -} - -/// Create a inner `WithdrawWithheldTokensFromMint` instruction -/// -/// This instruction is suitable for use with a cross-program `invoke` -pub fn inner_withdraw_withheld_tokens_from_mint( - token_program_id: &Pubkey, - mint: &Pubkey, - destination: &Pubkey, - authority: &Pubkey, - multisig_signers: &[&Pubkey], - proof_instruction_offset: i8, -) -> Result { - check_program_account(token_program_id)?; - let mut accounts = vec![ - AccountMeta::new(*mint, false), - AccountMeta::new(*destination, false), - AccountMeta::new_readonly(sysvar::instructions::id(), false), - AccountMeta::new_readonly(*authority, multisig_signers.is_empty()), - ]; - - for multisig_signer in multisig_signers.iter() { - accounts.push(AccountMeta::new(**multisig_signer, false)); - } - - Ok(encode_instruction( - token_program_id, - accounts, - TokenInstruction::ConfidentialTransferExtension, - ConfidentialTransferInstruction::WithdrawWithheldTokensFromMint, - &WithdrawWithheldTokensFromMintData { - proof_instruction_offset, - }, - )) -} - -/// Create a `WithdrawWithheldTokensFromMint` instruction -pub fn withdraw_withheld_tokens_from_mint( - token_program_id: &Pubkey, - mint: &Pubkey, - destination: &Pubkey, - authority: &Pubkey, - multisig_signers: &[&Pubkey], - proof_data: &WithdrawWithheldTokensData, -) -> Result, ProgramError> { - Ok(vec![ - verify_withdraw_withheld_tokens(proof_data), - inner_withdraw_withheld_tokens_from_mint( - token_program_id, - mint, - destination, - authority, - multisig_signers, - -1, - )?, - ]) -} - -/// Create a inner `WithdrawWithheldTokensFromMint` instruction -/// -/// This instruction is suitable for use with a cross-program `invoke` -pub fn inner_withdraw_withheld_tokens_from_accounts( - token_program_id: &Pubkey, - mint: &Pubkey, - destination: &Pubkey, - authority: &Pubkey, - multisig_signers: &[&Pubkey], - sources: &[&Pubkey], - proof_instruction_offset: i8, -) -> Result { - check_program_account(token_program_id)?; - let num_token_accounts = - u8::try_from(sources.len()).map_err(|_| ProgramError::InvalidInstructionData)?; - let mut accounts = vec![ - AccountMeta::new(*mint, false), - AccountMeta::new(*destination, false), - AccountMeta::new_readonly(sysvar::instructions::id(), false), - AccountMeta::new_readonly(*authority, multisig_signers.is_empty()), - ]; - - for multisig_signer in multisig_signers.iter() { - accounts.push(AccountMeta::new(**multisig_signer, false)); - } - - for source in sources.iter() { - accounts.push(AccountMeta::new(**source, false)); - } - - Ok(encode_instruction( - token_program_id, - accounts, - TokenInstruction::ConfidentialTransferExtension, - ConfidentialTransferInstruction::WithdrawWithheldTokensFromAccounts, - &WithdrawWithheldTokensFromAccountsData { - proof_instruction_offset, - num_token_accounts, - }, - )) -} - -/// Create a `WithdrawWithheldTokensFromAccounts` instruction -pub fn withdraw_withheld_tokens_from_accounts( - token_program_id: &Pubkey, - mint: &Pubkey, - destination: &Pubkey, - authority: &Pubkey, - multisig_signers: &[&Pubkey], - sources: &[&Pubkey], - proof_data: &WithdrawWithheldTokensData, -) -> Result, ProgramError> { - Ok(vec![ - verify_withdraw_withheld_tokens(proof_data), - inner_withdraw_withheld_tokens_from_accounts( - token_program_id, - mint, - destination, - authority, - multisig_signers, - sources, - -1, - )?, - ]) -} - -/// Creates a `HarvestWithheldTokensToMint` instruction -pub fn harvest_withheld_tokens_to_mint( - token_program_id: &Pubkey, - mint: &Pubkey, - sources: &[&Pubkey], -) -> Result { - check_program_account(token_program_id)?; - let mut accounts = vec![AccountMeta::new(*mint, false)]; - - for source in sources.iter() { - accounts.push(AccountMeta::new(**source, false)); - } - - Ok(encode_instruction( - token_program_id, - accounts, - TokenInstruction::ConfidentialTransferExtension, - ConfidentialTransferInstruction::HarvestWithheldTokensToMint, - &(), - )) -} diff --git a/token/program-2022/src/extension/confidential_transfer/mod.rs b/token/program-2022/src/extension/confidential_transfer/mod.rs deleted file mode 100644 index 72a199815ff..00000000000 --- a/token/program-2022/src/extension/confidential_transfer/mod.rs +++ /dev/null @@ -1,153 +0,0 @@ -use { - crate::{ - error::TokenError, - extension::{Extension, ExtensionType}, - pod::*, - }, - bytemuck::{Pod, Zeroable}, - solana_program::{entrypoint::ProgramResult, pubkey::Pubkey}, - solana_zk_token_sdk::zk_token_elgamal::pod, -}; - -/// Maximum bit length of any deposit or transfer amount -/// -/// Any deposit or transfer amount must be less than 2^48 -pub const MAXIMUM_DEPOSIT_TRANSFER_AMOUNT_BIT_LENGTH: usize = 48; - -/// Bit length of the low bits of pending balance plaintext -pub const PENDING_BALANCE_LO_BIT_LENGTH: usize = 16; -/// Bit length of the high bits of pending balance plaintext -pub const PENDING_BALANCE_HI_BIT_LENGTH: usize = 48; - -/// Confidential Transfer Extension instructions -pub mod instruction; - -/// Confidential Transfer Extension processor -pub mod processor; - -/// ElGamal public key used for encryption -pub type EncryptionPubkey = pod::ElGamalPubkey; -/// ElGamal ciphertext containing an account balance -pub type EncryptedBalance = pod::ElGamalCiphertext; -/// Authenticated encryption containing an account balance -pub type DecryptableBalance = pod::AeCiphertext; -/// (aggregated) ElGamal ciphertext containing a transfer fee -pub type EncryptedFee = pod::FeeEncryption; -/// ElGamal ciphertext containing a withheld amount -pub type EncryptedWithheldAmount = pod::ElGamalCiphertext; - -/// Confidential transfer mint configuration -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] -pub struct ConfidentialTransferMint { - /// Authority to modify the `ConfidentialTransferMint` configuration and to approve new - /// accounts (if `auto_approve_new_accounts` is true) - /// - /// Note that setting an authority of `Pubkey::default()` is the idiomatic way to disable - /// future changes to the configuration. - /// - /// The legacy Token Multisig account is not supported as the authority - pub authority: Pubkey, - - /// Indicate if newly configured accounts must be approved by the `authority` before they may be - /// used by the user. - /// - /// * If `true`, no approval is required and new accounts may be used immediately - /// * If `false`, the authority must approve newly configured accounts (see - /// `ConfidentialTransferInstruction::ConfigureAccount`) - pub auto_approve_new_accounts: PodBool, - - /// * If non-zero, transfers must include ElGamal cypertext with this public key permitting the - /// auditor to decode the transfer amount. - /// * If all zero, auditing is currently disabled. - pub auditor_encryption_pubkey: EncryptionPubkey, - - /// * If non-zero, transfers must include ElGamal cypertext of the transfer fee with this - /// public key. If this is the case, but the base mint is not extended for fees, then any - /// transfer will fail. - /// * If all zero, transfer fee is disabled. If this is the case, but the base mint is extended - /// for fees, then any transfer will fail. - pub withdraw_withheld_authority_encryption_pubkey: EncryptionPubkey, - - /// Withheld transfer fee confidential tokens that have been moved to the mint for withdrawal. - /// This will always be zero if fees are never enabled. - pub withheld_amount: EncryptedWithheldAmount, -} - -impl Extension for ConfidentialTransferMint { - const TYPE: ExtensionType = ExtensionType::ConfidentialTransferMint; -} - -/// Confidential account state -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] -pub struct ConfidentialTransferAccount { - /// `true` if this account has been approved for use. All confidential transfer operations for - /// the account will fail until approval is granted. - pub approved: PodBool, - - /// The public key associated with ElGamal encryption - pub encryption_pubkey: EncryptionPubkey, - - /// The low 16 bits of the pending balance (encrypted by `encryption_pubkey`) - pub pending_balance_lo: EncryptedBalance, - - /// The high 48 bits of the pending balance (encrypted by `encryption_pubkey`) - pub pending_balance_hi: EncryptedBalance, - - /// The available balance (encrypted by `encrypiton_pubkey`) - pub available_balance: EncryptedBalance, - - /// The decryptable available balance - pub decryptable_available_balance: DecryptableBalance, - - /// `pending_balance` may only be credited by `Deposit` or `Transfer` instructions if `true` - pub allow_balance_credits: PodBool, - - /// The total number of `Deposit` and `Transfer` instructions that have credited - /// `pending_balance` - pub pending_balance_credit_counter: PodU64, - - /// The maximum number of `Deposit` and `Transfer` instructions that can credit - /// `pending_balance` before the `ApplyPendingBalance` instruction is executed - pub maximum_pending_balance_credit_counter: PodU64, - - /// The `expected_pending_balance_credit_counter` value that was included in the last - /// `ApplyPendingBalance` instruction - pub expected_pending_balance_credit_counter: PodU64, - - /// The actual `pending_balance_credit_counter` when the last `ApplyPendingBalance` instruction - /// was executed - pub actual_pending_balance_credit_counter: PodU64, - - /// The withheld amount of fees. This will always be zero if fees are never enabled. - pub withheld_amount: EncryptedWithheldAmount, -} - -impl Extension for ConfidentialTransferAccount { - const TYPE: ExtensionType = ExtensionType::ConfidentialTransferAccount; -} - -impl ConfidentialTransferAccount { - /// Check if a `ConfidentialTransferAccount` has been approved for use - pub fn approved(&self) -> ProgramResult { - if bool::from(&self.approved) { - Ok(()) - } else { - Err(TokenError::ConfidentialTransferAccountNotApproved.into()) - } - } - - /// Check if a `ConfidentialTransferAccount` is in a closable state - pub fn closable(&self) -> ProgramResult { - if self.pending_balance_lo == EncryptedBalance::zeroed() - && self.pending_balance_hi == EncryptedBalance::zeroed() - && self.available_balance == EncryptedBalance::zeroed() - && self.withheld_amount == EncryptedWithheldAmount::zeroed() - { - Ok(()) - } else { - Err(TokenError::ConfidentialTransferAccountHasBalance.into()) - } - } -} diff --git a/token/program-2022/src/extension/confidential_transfer/processor.rs b/token/program-2022/src/extension/confidential_transfer/processor.rs deleted file mode 100644 index fcafb805b86..00000000000 --- a/token/program-2022/src/extension/confidential_transfer/processor.rs +++ /dev/null @@ -1,1317 +0,0 @@ -use { - crate::{ - check_program_account, - error::TokenError, - extension::{ - confidential_transfer::{instruction::*, *}, - StateWithExtensions, StateWithExtensionsMut, - }, - instruction::{decode_instruction_data, decode_instruction_type}, - processor::Processor, - state::{Account, Mint}, - }, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - instruction::Instruction, - msg, - program_error::ProgramError, - pubkey::Pubkey, - sysvar::instructions::get_instruction_relative, - }, - solana_zk_token_sdk::zk_token_proof_program, -}; -// Remove feature once zk ops syscalls are enabled on all networks -#[cfg(feature = "zk-ops")] -use { - crate::extension::transfer_fee::TransferFeeConfig, - solana_program::{clock::Clock, sysvar::Sysvar}, - solana_zk_token_sdk::zk_token_elgamal::ops, -}; - -fn decode_proof_instruction( - expected: ProofInstruction, - instruction: &Instruction, -) -> Result<&T, ProgramError> { - if instruction.program_id != zk_token_proof_program::id() - || ProofInstruction::decode_type(&instruction.data) != Some(expected) - { - msg!("Unexpected proof instruction"); - return Err(ProgramError::InvalidInstructionData); - } - - ProofInstruction::decode_data(&instruction.data).ok_or(ProgramError::InvalidInstructionData) -} - -/// Processes an [InitializeMint] instruction. -fn process_initialize_mint( - accounts: &[AccountInfo], - confidential_transfer_mint: &ConfidentialTransferMint, -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_info = next_account_info(account_info_iter)?; - - check_program_account(mint_info.owner)?; - let mint_data = &mut mint_info.data.borrow_mut(); - let mut mint = StateWithExtensionsMut::::unpack_uninitialized(mint_data)?; - *mint.init_extension::(true)? = *confidential_transfer_mint; - - Ok(()) -} - -/// Processes an [UpdateMint] instruction. -fn process_update_mint( - accounts: &[AccountInfo], - new_confidential_transfer_mint: &ConfidentialTransferMint, -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - let new_authority_info = next_account_info(account_info_iter)?; - - check_program_account(mint_info.owner)?; - let mint_data = &mut mint_info.data.borrow_mut(); - let mut mint = StateWithExtensionsMut::::unpack(mint_data)?; - let confidential_transfer_mint = mint.get_extension_mut::()?; - - if authority_info.is_signer - && confidential_transfer_mint.authority == *authority_info.key - && (new_authority_info.is_signer || *new_authority_info.key == Pubkey::default()) - && new_confidential_transfer_mint.authority == *new_authority_info.key - { - *confidential_transfer_mint = *new_confidential_transfer_mint; - Ok(()) - } else { - Err(ProgramError::MissingRequiredSignature) - } -} - -/// Processes a [ConfigureAccount] instruction. -fn process_configure_account( - program_id: &Pubkey, - accounts: &[AccountInfo], - ConfigureAccountInstructionData { - encryption_pubkey, - decryptable_zero_balance, - maximum_pending_balance_credit_counter, - }: &ConfigureAccountInstructionData, -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let token_account_info = next_account_info(account_info_iter)?; - let mint_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - let authority_info_data_len = authority_info.data_len(); - - check_program_account(token_account_info.owner)?; - let token_account_data = &mut token_account_info.data.borrow_mut(); - let mut token_account = StateWithExtensionsMut::::unpack(token_account_data)?; - - if token_account.base.mint != *mint_info.key { - return Err(TokenError::MintMismatch.into()); - } - - Processor::validate_owner( - program_id, - &token_account.base.owner, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?; - - check_program_account(mint_info.owner)?; - let mint_data = &mut mint_info.data.borrow(); - let mint = StateWithExtensions::::unpack(mint_data)?; - let confidential_transfer_mint = mint.get_extension::()?; - - // Note: The caller is expected to use the `Reallocate` instruction to ensure there is - // sufficient room in their token account for the new `ConfidentialTransferAccount` extension - let mut confidential_transfer_account = - token_account.init_extension::(false)?; - confidential_transfer_account.approved = confidential_transfer_mint.auto_approve_new_accounts; - confidential_transfer_account.encryption_pubkey = *encryption_pubkey; - confidential_transfer_account.maximum_pending_balance_credit_counter = - *maximum_pending_balance_credit_counter; - - /* - An ElGamal ciphertext is of the form - ElGamalCiphertext { - msg_comm: r * H + x * G - decrypt_handle: r * P - } - - where - - G, H: constants for the system (RistrettoPoint) - - P: ElGamal public key component (RistrettoPoint) - - r: encryption randomness (Scalar) - - x: message (Scalar) - - Upon receiving a `ConfigureAccount` instruction, the ZK Token program should encrypt x=0 - (i.e. Scalar::zero()) and store it as `pending_balance_lo`, `pending_balance_hi`, and - `available_balance`. - - For regular encryption, it is important that r is generated from a proper randomness source. But - for the `ConfigureAccount` instruction, it is already known that x is always 0. So r can just be - set Scalar::zero(). - - This means that the ElGamalCiphertext should simply be - ElGamalCiphertext { - msg_comm: 0 * H + 0 * G = 0 - decrypt_handle: 0 * P = 0 - } - - This should just be encoded as [0; 64] - */ - confidential_transfer_account.pending_balance_lo = EncryptedBalance::zeroed(); - confidential_transfer_account.pending_balance_hi = EncryptedBalance::zeroed(); - confidential_transfer_account.available_balance = EncryptedBalance::zeroed(); - - confidential_transfer_account.decryptable_available_balance = *decryptable_zero_balance; - confidential_transfer_account.allow_balance_credits = true.into(); - confidential_transfer_account.pending_balance_credit_counter = 0.into(); - confidential_transfer_account.expected_pending_balance_credit_counter = 0.into(); - confidential_transfer_account.actual_pending_balance_credit_counter = 0.into(); - confidential_transfer_account.withheld_amount = EncryptedWithheldAmount::zeroed(); - - Ok(()) -} - -/// Processes an [ApproveAccount] instruction. -fn process_approve_account(accounts: &[AccountInfo]) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let token_account_info = next_account_info(account_info_iter)?; - let mint_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - - check_program_account(token_account_info.owner)?; - let token_account_data = &mut token_account_info.data.borrow_mut(); - let mut token_account = StateWithExtensionsMut::::unpack(token_account_data)?; - - check_program_account(mint_info.owner)?; - let mint_data = &mint_info.data.borrow_mut(); - let mint = StateWithExtensions::::unpack(mint_data)?; - let confidential_transfer_mint = mint.get_extension::()?; - - if authority_info.is_signer && *authority_info.key == confidential_transfer_mint.authority { - let mut confidential_transfer_state = - token_account.get_extension_mut::()?; - confidential_transfer_state.approved = true.into(); - Ok(()) - } else { - Err(ProgramError::MissingRequiredSignature) - } -} - -/// Processes an [EmptyAccount] instruction. -fn process_empty_account( - program_id: &Pubkey, - accounts: &[AccountInfo], - proof_instruction_offset: i64, -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let token_account_info = next_account_info(account_info_iter)?; - let instructions_sysvar_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - let authority_info_data_len = authority_info.data_len(); - - check_program_account(token_account_info.owner)?; - let token_account_data = &mut token_account_info.data.borrow_mut(); - let mut token_account = StateWithExtensionsMut::::unpack(token_account_data)?; - - Processor::validate_owner( - program_id, - &token_account.base.owner, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?; - - let mut confidential_transfer_account = - token_account.get_extension_mut::()?; - - let previous_instruction = - get_instruction_relative(proof_instruction_offset, instructions_sysvar_info)?; - let proof_data = decode_proof_instruction::( - ProofInstruction::VerifyCloseAccount, - &previous_instruction, - )?; - - if confidential_transfer_account.pending_balance_lo != EncryptedBalance::zeroed() { - msg!("Pending balance is not zero"); - return Err(ProgramError::InvalidAccountData); - } - - if confidential_transfer_account.pending_balance_hi != EncryptedBalance::zeroed() { - msg!("Pending balance is not zero"); - return Err(ProgramError::InvalidAccountData); - } - - if confidential_transfer_account.available_balance != proof_data.ciphertext { - msg!("Available balance mismatch"); - return Err(ProgramError::InvalidInstructionData); - } - - confidential_transfer_account.available_balance = EncryptedBalance::zeroed(); - confidential_transfer_account.closable()?; - - Ok(()) -} - -/// Processes a [Deposit] instruction. -#[cfg(feature = "zk-ops")] -fn process_deposit( - program_id: &Pubkey, - accounts: &[AccountInfo], - amount: u64, - expected_decimals: u8, -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let token_account_info = next_account_info(account_info_iter)?; - let destination_token_account_info = next_account_info(account_info_iter)?; - let mint_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - let authority_info_data_len = authority_info.data_len(); - - check_program_account(mint_info.owner)?; - let mint_data = &mint_info.data.borrow_mut(); - let mint = StateWithExtensions::::unpack(mint_data)?; - - if expected_decimals != mint.base.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); - } - - // Process source account - { - check_program_account(token_account_info.owner)?; - let token_account_data = &mut token_account_info.data.borrow_mut(); - let mut token_account = StateWithExtensionsMut::::unpack(token_account_data)?; - - Processor::validate_owner( - program_id, - &token_account.base.owner, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?; - - if token_account.base.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - - if token_account.base.mint != *mint_info.key { - return Err(TokenError::MintMismatch.into()); - } - - // Wrapped SOL deposits are not supported because lamports cannot be vanished. - assert!(!token_account.base.is_native()); - token_account.base.amount = token_account - .base - .amount - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - - token_account.pack_base(); - } - - // - // Finished with the source token account at this point. Drop all references to it to avoid a - // double borrow if the source and destination accounts are the same - // - - // Process destination account - { - check_program_account(destination_token_account_info.owner)?; - let destination_token_account_data = &mut destination_token_account_info.data.borrow_mut(); - let mut destination_token_account = - StateWithExtensionsMut::::unpack(destination_token_account_data)?; - - if destination_token_account.base.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - - if destination_token_account.base.mint != *mint_info.key { - return Err(TokenError::MintMismatch.into()); - } - - let mut destination_confidential_transfer_account = - destination_token_account.get_extension_mut::()?; - destination_confidential_transfer_account.approved()?; - - if !bool::from(&destination_confidential_transfer_account.allow_balance_credits) { - return Err(TokenError::ConfidentialTransferDepositsAndTransfersDisabled.into()); - } - - // Divide deposit into the low 16 and high 48 bits and then add to the appropriate pending - // ciphertexts - destination_confidential_transfer_account.pending_balance_lo = ops::add_to( - &destination_confidential_transfer_account.pending_balance_lo, - amount << PENDING_BALANCE_HI_BIT_LENGTH >> PENDING_BALANCE_HI_BIT_LENGTH, - ) - .ok_or(ProgramError::InvalidInstructionData)?; - - destination_confidential_transfer_account.pending_balance_hi = ops::add_to( - &destination_confidential_transfer_account.pending_balance_hi, - amount >> PENDING_BALANCE_LO_BIT_LENGTH, - ) - .ok_or(ProgramError::InvalidInstructionData)?; - - destination_confidential_transfer_account.pending_balance_credit_counter = - (u64::from(destination_confidential_transfer_account.pending_balance_credit_counter) - .checked_add(1) - .ok_or(ProgramError::InvalidInstructionData)?) - .into(); - - if u64::from(destination_confidential_transfer_account.pending_balance_credit_counter) - > u64::from( - destination_confidential_transfer_account.maximum_pending_balance_credit_counter, - ) - { - return Err(TokenError::MaximumPendingBalanceCreditCounterExceeded.into()); - } - } - - Ok(()) -} - -/// Processes a [Withdraw] instruction. -#[cfg(feature = "zk-ops")] -fn process_withdraw( - program_id: &Pubkey, - accounts: &[AccountInfo], - amount: u64, - expected_decimals: u8, - new_decryptable_available_balance: DecryptableBalance, - proof_instruction_offset: i64, -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let token_account_info = next_account_info(account_info_iter)?; - let destination_token_account_info = next_account_info(account_info_iter)?; - let mint_info = next_account_info(account_info_iter)?; - let instructions_sysvar_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - let authority_info_data_len = authority_info.data_len(); - - check_program_account(mint_info.owner)?; - let mint_data = &mint_info.data.borrow_mut(); - let mint = StateWithExtensions::::unpack(mint_data)?; - - if expected_decimals != mint.base.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); - } - - let previous_instruction = - get_instruction_relative(proof_instruction_offset, instructions_sysvar_info)?; - - let proof_data = decode_proof_instruction::( - ProofInstruction::VerifyWithdraw, - &previous_instruction, - )?; - - // Process source account - { - check_program_account(token_account_info.owner)?; - let token_account_data = &mut token_account_info.data.borrow_mut(); - let mut token_account = StateWithExtensionsMut::::unpack(token_account_data)?; - - Processor::validate_owner( - program_id, - &token_account.base.owner, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?; - - if token_account.base.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - - if token_account.base.mint != *mint_info.key { - return Err(TokenError::MintMismatch.into()); - } - - let mut confidential_transfer_account = - token_account.get_extension_mut::()?; - - confidential_transfer_account.available_balance = - ops::subtract_from(&confidential_transfer_account.available_balance, amount) - .ok_or(ProgramError::InvalidInstructionData)?; - - if confidential_transfer_account.available_balance != proof_data.final_ciphertext { - return Err(TokenError::ConfidentialTransferBalanceMismatch.into()); - } - - confidential_transfer_account.decryptable_available_balance = - new_decryptable_available_balance; - } - - // - // Finished with the source token account at this point. Drop all references to it to avoid a - // double borrow if the source and destination accounts are the same - // - - // Process destination account - { - check_program_account(destination_token_account_info.owner)?; - let destination_token_account_data = &mut destination_token_account_info.data.borrow_mut(); - let mut destination_token_account = - StateWithExtensionsMut::::unpack(destination_token_account_data)?; - - if destination_token_account.base.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - - if destination_token_account.base.mint != *mint_info.key { - return Err(TokenError::MintMismatch.into()); - } - - // Wrapped SOL withdrawals are not supported because lamports cannot be apparated. - assert!(!destination_token_account.base.is_native()); - destination_token_account.base.amount = destination_token_account - .base - .amount - .checked_add(amount) - .ok_or(TokenError::Overflow)?; - - destination_token_account.pack_base(); - } - - Ok(()) -} - -/// Processes an [Transfer] instruction. -#[cfg(feature = "zk-ops")] -fn process_transfer( - program_id: &Pubkey, - accounts: &[AccountInfo], - new_source_decryptable_available_balance: DecryptableBalance, - proof_instruction_offset: i64, -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let token_account_info = next_account_info(account_info_iter)?; - let destination_token_account_info = next_account_info(account_info_iter)?; - let mint_info = next_account_info(account_info_iter)?; - let instructions_sysvar_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - - check_program_account(mint_info.owner)?; - let mint_data = &mint_info.data.borrow_mut(); - let mint = StateWithExtensions::::unpack(mint_data)?; - let confidential_transfer_mint = mint.get_extension::()?; - - let previous_instruction = - get_instruction_relative(proof_instruction_offset, instructions_sysvar_info)?; - - if let Ok(transfer_fee_config) = mint.get_extension::() { - // mint is extended for fees - let proof_data = decode_proof_instruction::( - ProofInstruction::VerifyTransferWithFee, - &previous_instruction, - )?; - - if proof_data.transfer_with_fee_pubkeys.auditor_pubkey - != confidential_transfer_mint.auditor_encryption_pubkey - { - return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); - } - - // `withdraw_withheld_authority` ElGamal pubkey in proof data and mint must match - if proof_data - .transfer_with_fee_pubkeys - .withdraw_withheld_authority_pubkey - != confidential_transfer_mint.withdraw_withheld_authority_encryption_pubkey - { - return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); - } - - // fee parameters in proof data and mint must match - let epoch = Clock::get()?.epoch; - let (maximum_fee, transfer_fee_basis_points) = - if u64::from(transfer_fee_config.newer_transfer_fee.epoch) < epoch { - ( - u64::from(transfer_fee_config.older_transfer_fee.maximum_fee), - u16::from( - transfer_fee_config - .older_transfer_fee - .transfer_fee_basis_points, - ), - ) - } else { - ( - u64::from(transfer_fee_config.newer_transfer_fee.maximum_fee), - u16::from( - transfer_fee_config - .newer_transfer_fee - .transfer_fee_basis_points, - ), - ) - }; - - if u64::from(proof_data.fee_parameters.maximum_fee) != maximum_fee - || u16::from(proof_data.fee_parameters.fee_rate_basis_points) - != transfer_fee_basis_points - { - return Err(TokenError::FeeParametersMismatch.into()); - } - - let source_ciphertext_lo = EncryptedBalance::from(( - proof_data.ciphertext_lo.commitment, - proof_data.ciphertext_lo.source_handle, - )); - let source_ciphertext_hi = EncryptedBalance::from(( - proof_data.ciphertext_hi.commitment, - proof_data.ciphertext_hi.source_handle, - )); - - process_source_for_transfer( - program_id, - token_account_info, - mint_info, - authority_info, - account_info_iter.as_slice(), - &proof_data.transfer_with_fee_pubkeys.source_pubkey, - &source_ciphertext_lo, - &source_ciphertext_hi, - new_source_decryptable_available_balance, - )?; - - let destination_ciphertext_lo = EncryptedBalance::from(( - proof_data.ciphertext_lo.commitment, - proof_data.ciphertext_lo.destination_handle, - )); - let destination_ciphertext_hi = EncryptedBalance::from(( - proof_data.ciphertext_hi.commitment, - proof_data.ciphertext_hi.destination_handle, - )); - - let fee_ciphertext = if token_account_info.key == destination_token_account_info.key { - None - } else { - Some(proof_data.fee_ciphertext) - }; - - process_destination_for_transfer( - destination_token_account_info, - mint_info, - &proof_data.transfer_with_fee_pubkeys.destination_pubkey, - &destination_ciphertext_lo, - &destination_ciphertext_hi, - fee_ciphertext, - )?; - } else { - // mint is not extended for fees - let proof_data = decode_proof_instruction::( - ProofInstruction::VerifyTransfer, - &previous_instruction, - )?; - - if proof_data.transfer_pubkeys.auditor_pubkey - != confidential_transfer_mint.auditor_encryption_pubkey - { - return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); - } - - let source_ciphertext_lo = EncryptedBalance::from(( - proof_data.ciphertext_lo.commitment, - proof_data.ciphertext_lo.source_handle, - )); - let source_ciphertext_hi = EncryptedBalance::from(( - proof_data.ciphertext_hi.commitment, - proof_data.ciphertext_hi.source_handle, - )); - - process_source_for_transfer( - program_id, - token_account_info, - mint_info, - authority_info, - account_info_iter.as_slice(), - &proof_data.transfer_pubkeys.source_pubkey, - &source_ciphertext_lo, - &source_ciphertext_hi, - new_source_decryptable_available_balance, - )?; - - let destination_ciphertext_lo = EncryptedBalance::from(( - proof_data.ciphertext_lo.commitment, - proof_data.ciphertext_lo.destination_handle, - )); - let destination_ciphertext_hi = EncryptedBalance::from(( - proof_data.ciphertext_hi.commitment, - proof_data.ciphertext_hi.destination_handle, - )); - - process_destination_for_transfer( - destination_token_account_info, - mint_info, - &proof_data.transfer_pubkeys.destination_pubkey, - &destination_ciphertext_lo, - &destination_ciphertext_hi, - None, - )?; - } - - Ok(()) -} - -#[allow(clippy::too_many_arguments)] -#[cfg(feature = "zk-ops")] -fn process_source_for_transfer( - program_id: &Pubkey, - token_account_info: &AccountInfo, - mint_info: &AccountInfo, - authority_info: &AccountInfo, - signers: &[AccountInfo], - source_encryption_pubkey: &EncryptionPubkey, - source_ciphertext_lo: &EncryptedBalance, - source_ciphertext_hi: &EncryptedBalance, - new_source_decryptable_available_balance: DecryptableBalance, -) -> ProgramResult { - check_program_account(token_account_info.owner)?; - let authority_info_data_len = authority_info.data_len(); - let token_account_data = &mut token_account_info.data.borrow_mut(); - let mut token_account = StateWithExtensionsMut::::unpack(token_account_data)?; - - Processor::validate_owner( - program_id, - &token_account.base.owner, - authority_info, - authority_info_data_len, - signers, - )?; - - if token_account.base.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - - if token_account.base.mint != *mint_info.key { - return Err(TokenError::MintMismatch.into()); - } - - let mut confidential_transfer_account = - token_account.get_extension_mut::()?; - confidential_transfer_account.approved()?; - if *source_encryption_pubkey != confidential_transfer_account.encryption_pubkey { - return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); - } - - let new_source_available_balance = { - ops::subtract_with_lo_hi( - &confidential_transfer_account.available_balance, - source_ciphertext_lo, - source_ciphertext_hi, - ) - .ok_or(ProgramError::InvalidInstructionData)? - }; - - confidential_transfer_account.available_balance = new_source_available_balance; - confidential_transfer_account.decryptable_available_balance = - new_source_decryptable_available_balance; - - Ok(()) -} - -#[cfg(feature = "zk-ops")] -fn process_destination_for_transfer( - destination_token_account_info: &AccountInfo, - mint_info: &AccountInfo, - destination_encryption_pubkey: &EncryptionPubkey, - destination_ciphertext_lo: &EncryptedBalance, - destination_ciphertext_hi: &EncryptedBalance, - encrypted_fee: Option, -) -> ProgramResult { - check_program_account(destination_token_account_info.owner)?; - let destination_token_account_data = &mut destination_token_account_info.data.borrow_mut(); - let mut destination_token_account = - StateWithExtensionsMut::::unpack(destination_token_account_data)?; - - if destination_token_account.base.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - - if destination_token_account.base.mint != *mint_info.key { - return Err(TokenError::MintMismatch.into()); - } - - let mut destination_confidential_transfer_account = - destination_token_account.get_extension_mut::()?; - destination_confidential_transfer_account.approved()?; - - if !bool::from(&destination_confidential_transfer_account.allow_balance_credits) { - return Err(TokenError::ConfidentialTransferDepositsAndTransfersDisabled.into()); - } - - if *destination_encryption_pubkey != destination_confidential_transfer_account.encryption_pubkey - { - return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); - } - - let new_destination_pending_balance_lo = ops::add( - &destination_confidential_transfer_account.pending_balance_lo, - destination_ciphertext_lo, - ) - .ok_or(ProgramError::InvalidInstructionData)?; - - let new_destination_pending_balance_hi = ops::add( - &destination_confidential_transfer_account.pending_balance_hi, - destination_ciphertext_hi, - ) - .ok_or(ProgramError::InvalidInstructionData)?; - - let new_destination_pending_balance_credit_counter = - u64::from(destination_confidential_transfer_account.pending_balance_credit_counter) - .checked_add(1) - .ok_or(ProgramError::InvalidInstructionData)?; - - if new_destination_pending_balance_credit_counter - > u64::from( - destination_confidential_transfer_account.maximum_pending_balance_credit_counter, - ) - { - return Err(TokenError::MaximumPendingBalanceCreditCounterExceeded.into()); - } - - destination_confidential_transfer_account.pending_balance_lo = - new_destination_pending_balance_lo; - destination_confidential_transfer_account.pending_balance_hi = - new_destination_pending_balance_hi; - destination_confidential_transfer_account.pending_balance_credit_counter = - new_destination_pending_balance_credit_counter.into(); - - // update destination account withheld fees - if let Some(ciphertext_fee) = encrypted_fee { - let ciphertext_fee_destination: EncryptedWithheldAmount = - (ciphertext_fee.commitment, ciphertext_fee.destination_handle).into(); - let ciphertext_fee_withheld_authority: EncryptedWithheldAmount = ( - ciphertext_fee.commitment, - ciphertext_fee.withdraw_withheld_authority_handle, - ) - .into(); - - // subtract fee from destination pending balance - let new_destination_pending_balance = ops::subtract( - &destination_confidential_transfer_account.pending_balance_lo, - &ciphertext_fee_destination, - ) - .ok_or(ProgramError::InvalidInstructionData)?; - - // add encrypted fee to current withheld fee - let new_withheld_amount = ops::add( - &destination_confidential_transfer_account.withheld_amount, - &ciphertext_fee_withheld_authority, - ) - .ok_or(ProgramError::InvalidInstructionData)?; - - destination_confidential_transfer_account.pending_balance_lo = - new_destination_pending_balance; - destination_confidential_transfer_account.withheld_amount = new_withheld_amount; - } - - Ok(()) -} - -/// Processes an [ApplyPendingBalance] instruction. -#[cfg(feature = "zk-ops")] -fn process_apply_pending_balance( - program_id: &Pubkey, - accounts: &[AccountInfo], - ApplyPendingBalanceData { - expected_pending_balance_credit_counter, - new_decryptable_available_balance, - }: &ApplyPendingBalanceData, -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let token_account_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - let authority_info_data_len = authority_info.data_len(); - - check_program_account(token_account_info.owner)?; - let token_account_data = &mut token_account_info.data.borrow_mut(); - let mut token_account = StateWithExtensionsMut::::unpack(token_account_data)?; - - Processor::validate_owner( - program_id, - &token_account.base.owner, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?; - - let mut confidential_transfer_account = - token_account.get_extension_mut::()?; - - confidential_transfer_account.available_balance = ops::add_with_lo_hi( - &confidential_transfer_account.available_balance, - &confidential_transfer_account.pending_balance_lo, - &confidential_transfer_account.pending_balance_hi, - ) - .ok_or(ProgramError::InvalidInstructionData)?; - - confidential_transfer_account.actual_pending_balance_credit_counter = - confidential_transfer_account.pending_balance_credit_counter; - confidential_transfer_account.expected_pending_balance_credit_counter = - *expected_pending_balance_credit_counter; - confidential_transfer_account.decryptable_available_balance = - *new_decryptable_available_balance; - confidential_transfer_account.pending_balance_credit_counter = 0.into(); - confidential_transfer_account.pending_balance_lo = EncryptedBalance::zeroed(); - confidential_transfer_account.pending_balance_hi = EncryptedBalance::zeroed(); - - Ok(()) -} - -/// Processes an [DisableBalanceCredits] or [EnableBalanceCredits] instruction. -fn process_allow_balance_credits( - program_id: &Pubkey, - accounts: &[AccountInfo], - allow_balance_credits: bool, -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let token_account_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - let authority_info_data_len = authority_info.data_len(); - - check_program_account(token_account_info.owner)?; - let token_account_data = &mut token_account_info.data.borrow_mut(); - let mut token_account = StateWithExtensionsMut::::unpack(token_account_data)?; - - Processor::validate_owner( - program_id, - &token_account.base.owner, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?; - - let mut confidential_transfer_account = - token_account.get_extension_mut::()?; - confidential_transfer_account.allow_balance_credits = allow_balance_credits.into(); - - Ok(()) -} - -/// Processes an [WithdrawWithheldTokensFromMint] instruction. -#[cfg(feature = "zk-ops")] -fn process_withdraw_withheld_tokens_from_mint( - program_id: &Pubkey, - accounts: &[AccountInfo], - proof_instruction_offset: i64, -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_account_info = next_account_info(account_info_iter)?; - let destination_account_info = next_account_info(account_info_iter)?; - let instructions_sysvar_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - let authority_info_data_len = authority_info.data_len(); - - let mut mint_data = mint_account_info.data.borrow_mut(); - let mut mint = StateWithExtensionsMut::::unpack(&mut mint_data)?; - - // mint must be extended for fees - { - let transfer_fee_config = mint.get_extension::()?; - let withdraw_withheld_authority = - Option::::from(transfer_fee_config.withdraw_withheld_authority) - .ok_or(TokenError::NoAuthorityExists)?; - Processor::validate_owner( - program_id, - &withdraw_withheld_authority, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?; - } // free `transfer_fee_config` to borrow `confidential_transfer_mint` as mutable - - let confidential_transfer_mint = mint.get_extension_mut::()?; - - // basic checks for the destination account - must be extended for confidential transfers - let mut destination_account_data = destination_account_info.data.borrow_mut(); - let mut destination_account = - StateWithExtensionsMut::::unpack(&mut destination_account_data)?; - if destination_account.base.mint != *mint_account_info.key { - return Err(TokenError::MintMismatch.into()); - } - if destination_account.base.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - let mut destination_confidential_transfer_account = - destination_account.get_extension_mut::()?; - destination_confidential_transfer_account.approved()?; - // verify consistency of proof data - let previous_instruction = - get_instruction_relative(proof_instruction_offset, instructions_sysvar_info)?; - let proof_data = decode_proof_instruction::( - ProofInstruction::VerifyWithdrawWithheldTokens, - &previous_instruction, - )?; - - // withdraw withheld authority ElGamal pubkey should match in the proof data and mint - if proof_data.withdraw_withheld_authority_pubkey - != confidential_transfer_mint.withdraw_withheld_authority_encryption_pubkey - { - return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); - } - - // destination ElGamal pubkey should match in the proof data and destination account - if proof_data.destination_pubkey != destination_confidential_transfer_account.encryption_pubkey - { - return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); - } - - // withheld amount ciphertext must match in the proof data and mint - if proof_data.withdraw_withheld_authority_ciphertext - != confidential_transfer_mint.withheld_amount - { - return Err(TokenError::ConfidentialTransferBalanceMismatch.into()); - } - - // The proof data contains the mint withheld amount encrypted under the destination ElGamal pubkey. - // This amount should be added to the destination pending balance. - let new_destination_pending_balance = ops::add( - &destination_confidential_transfer_account.pending_balance_lo, - &proof_data.destination_ciphertext, - ) - .ok_or(ProgramError::InvalidInstructionData)?; - - destination_confidential_transfer_account.pending_balance_lo = new_destination_pending_balance; - - // fee is now withdrawn, so zero out mint withheld amount - confidential_transfer_mint.withheld_amount = EncryptedWithheldAmount::zeroed(); - - Ok(()) -} - -#[cfg(feature = "zk-ops")] -fn process_withdraw_withheld_tokens_from_accounts( - program_id: &Pubkey, - accounts: &[AccountInfo], - num_token_accounts: u8, - proof_instruction_offset: i64, -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_account_info = next_account_info(account_info_iter)?; - let destination_account_info = next_account_info(account_info_iter)?; - let instructions_sysvar_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - let authority_info_data_len = authority_info.data_len(); - let account_infos = account_info_iter.as_slice(); - let num_signers = account_infos - .len() - .saturating_sub(num_token_accounts as usize); - - let mut mint_data = mint_account_info.data.borrow_mut(); - let mut mint = StateWithExtensionsMut::::unpack(&mut mint_data)?; - - // mint must be extended for fees - let transfer_fee_config = mint.get_extension::()?; - let withdraw_withheld_authority = - Option::::from(transfer_fee_config.withdraw_withheld_authority) - .ok_or(TokenError::NoAuthorityExists)?; - Processor::validate_owner( - program_id, - &withdraw_withheld_authority, - authority_info, - authority_info_data_len, - &account_infos[..num_signers], - )?; - - let mut destination_account_data = destination_account_info.data.borrow_mut(); - let mut destination_account = - StateWithExtensionsMut::::unpack(&mut destination_account_data)?; - if destination_account.base.mint != *mint_account_info.key { - return Err(TokenError::MintMismatch.into()); - } - if destination_account.base.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - - // sum up the withheld amounts in all the accounts - let mut aggregate_withheld_amount = EncryptedWithheldAmount::zeroed(); - for account_info in &account_infos[num_signers..] { - // self-harvest, can't double-borrow the underlying data - if account_info.key == destination_account_info.key { - let confidential_transfer_destination_account = destination_account - .get_extension_mut::() - .map_err(|_| TokenError::InvalidState)?; - - aggregate_withheld_amount = ops::add( - &aggregate_withheld_amount, - &confidential_transfer_destination_account.withheld_amount, - ) - .ok_or(ProgramError::InvalidInstructionData)?; - - confidential_transfer_destination_account.withheld_amount = - EncryptedWithheldAmount::zeroed(); - } else { - match harvest_from_account(mint_account_info.key, account_info) { - Ok(encrypted_withheld_amount) => { - aggregate_withheld_amount = - ops::add(&aggregate_withheld_amount, &encrypted_withheld_amount) - .ok_or(ProgramError::InvalidInstructionData)?; - } - Err(e) => { - msg!("Error harvesting from {}: {}", account_info.key, e); - } - } - } - } - - let mut destination_confidential_transfer_account = - destination_account.get_extension_mut::()?; - destination_confidential_transfer_account.approved()?; - // verify consistency of proof data - let previous_instruction = - get_instruction_relative(proof_instruction_offset, instructions_sysvar_info)?; - let proof_data = decode_proof_instruction::( - ProofInstruction::VerifyWithdrawWithheldTokens, - &previous_instruction, - )?; - - // withdraw withheld authority ElGamal pubkey should match in the proof data and mint - let confidential_transfer_mint = mint.get_extension_mut::()?; - if proof_data.withdraw_withheld_authority_pubkey - != confidential_transfer_mint.withdraw_withheld_authority_encryption_pubkey - { - return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); - } - - // destination ElGamal pubkey should match in the proof data and destination account - if proof_data.destination_pubkey != destination_confidential_transfer_account.encryption_pubkey - { - return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); - } - - // withheld amount ciphertext must match in the proof data and mint - if proof_data.withdraw_withheld_authority_ciphertext != aggregate_withheld_amount { - return Err(TokenError::ConfidentialTransferBalanceMismatch.into()); - } - - // add the sum of the withheld fees to destination pending balance - let new_destination_pending_balance = ops::add( - &destination_confidential_transfer_account.pending_balance_lo, - &proof_data.destination_ciphertext, - ) - .ok_or(ProgramError::InvalidInstructionData)?; - - destination_confidential_transfer_account.pending_balance_lo = new_destination_pending_balance; - - Ok(()) -} - -#[cfg(feature = "zk-ops")] -fn harvest_from_account<'a, 'b>( - mint_key: &'b Pubkey, - token_account_info: &'b AccountInfo<'a>, -) -> Result { - let mut token_account_data = token_account_info.data.borrow_mut(); - let mut token_account = StateWithExtensionsMut::::unpack(&mut token_account_data) - .map_err(|_| TokenError::InvalidState)?; - if token_account.base.mint != *mint_key { - return Err(TokenError::MintMismatch); - } - check_program_account(token_account_info.owner).map_err(|_| TokenError::InvalidState)?; - - let confidential_transfer_token_account = token_account - .get_extension_mut::() - .map_err(|_| TokenError::InvalidState)?; - - let withheld_amount = confidential_transfer_token_account.withheld_amount; - confidential_transfer_token_account.withheld_amount = EncryptedWithheldAmount::zeroed(); - - Ok(withheld_amount) -} - -/// Processes an [HarvestWithheldTokensToMint] instruction. -#[cfg(feature = "zk-ops")] -fn process_harvest_withheld_tokens_to_mint(accounts: &[AccountInfo]) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_account_info = next_account_info(account_info_iter)?; - let token_account_infos = account_info_iter.as_slice(); - - let mut mint_data = mint_account_info.data.borrow_mut(); - let mut mint = StateWithExtensionsMut::::unpack(&mut mint_data)?; - mint.get_extension::()?; - let confidential_transfer_mint = mint.get_extension_mut::()?; - - for token_account_info in token_account_infos { - match harvest_from_account(mint_account_info.key, token_account_info) { - Ok(withheld_amount) => { - let new_mint_withheld_amount = ops::add( - &confidential_transfer_mint.withheld_amount, - &withheld_amount, - ) - .ok_or(ProgramError::InvalidInstructionData)?; - - confidential_transfer_mint.withheld_amount = new_mint_withheld_amount; - } - Err(e) => { - msg!("Error harvesting from {}: {}", token_account_info.key, e); - } - } - } - Ok(()) -} - -#[allow(dead_code)] -pub(crate) fn process_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - input: &[u8], -) -> ProgramResult { - check_program_account(program_id)?; - - match decode_instruction_type(input)? { - ConfidentialTransferInstruction::InitializeMint => { - msg!("ConfidentialTransferInstruction::InitializeMint"); - process_initialize_mint( - accounts, - decode_instruction_data::(input)?, - ) - } - ConfidentialTransferInstruction::UpdateMint => { - msg!("ConfidentialTransferInstruction::UpdateMint"); - process_update_mint( - accounts, - decode_instruction_data::(input)?, - ) - } - ConfidentialTransferInstruction::ConfigureAccount => { - msg!("ConfidentialTransferInstruction::ConfigureAccount"); - process_configure_account( - program_id, - accounts, - decode_instruction_data::(input)?, - ) - } - ConfidentialTransferInstruction::ApproveAccount => { - msg!("ConfidentialTransferInstruction::ApproveAccount"); - process_approve_account(accounts) - } - ConfidentialTransferInstruction::EmptyAccount => { - msg!("ConfidentialTransferInstruction::EmptyAccount"); - let data = decode_instruction_data::(input)?; - process_empty_account(program_id, accounts, data.proof_instruction_offset as i64) - } - ConfidentialTransferInstruction::Deposit => { - msg!("ConfidentialTransferInstruction::Deposit"); - #[cfg(feature = "zk-ops")] - { - let data = decode_instruction_data::(input)?; - process_deposit(program_id, accounts, data.amount.into(), data.decimals) - } - #[cfg(not(feature = "zk-ops"))] - Err(ProgramError::InvalidInstructionData) - } - ConfidentialTransferInstruction::Withdraw => { - msg!("ConfidentialTransferInstruction::Withdraw"); - #[cfg(feature = "zk-ops")] - { - let data = decode_instruction_data::(input)?; - process_withdraw( - program_id, - accounts, - data.amount.into(), - data.decimals, - data.new_decryptable_available_balance, - data.proof_instruction_offset as i64, - ) - } - #[cfg(not(feature = "zk-ops"))] - Err(ProgramError::InvalidInstructionData) - } - ConfidentialTransferInstruction::Transfer => { - msg!("ConfidentialTransferInstruction::Transfer"); - #[cfg(feature = "zk-ops")] - { - let data = decode_instruction_data::(input)?; - process_transfer( - program_id, - accounts, - data.new_source_decryptable_available_balance, - data.proof_instruction_offset as i64, - ) - } - #[cfg(not(feature = "zk-ops"))] - Err(ProgramError::InvalidInstructionData) - } - ConfidentialTransferInstruction::TransferWithFee => { - msg!("ConfidentialTransferInstruction::TransferWithFee"); - #[cfg(feature = "zk-ops")] - { - let data = decode_instruction_data::(input)?; - process_transfer( - program_id, - accounts, - data.new_source_decryptable_available_balance, - data.proof_instruction_offset as i64, - ) - } - #[cfg(not(feature = "zk-ops"))] - { - Err(ProgramError::InvalidInstructionData) - } - } - ConfidentialTransferInstruction::ApplyPendingBalance => { - msg!("ConfidentialTransferInstruction::ApplyPendingBalance"); - #[cfg(feature = "zk-ops")] - { - process_apply_pending_balance( - program_id, - accounts, - decode_instruction_data::(input)?, - ) - } - #[cfg(not(feature = "zk-ops"))] - { - Err(ProgramError::InvalidInstructionData) - } - } - ConfidentialTransferInstruction::DisableBalanceCredits => { - msg!("ConfidentialTransferInstruction::DisableBalanceCredits"); - process_allow_balance_credits(program_id, accounts, false) - } - ConfidentialTransferInstruction::EnableBalanceCredits => { - msg!("ConfidentialTransferInstruction::EnableBalanceCredits"); - process_allow_balance_credits(program_id, accounts, true) - } - ConfidentialTransferInstruction::WithdrawWithheldTokensFromMint => { - msg!("ConfidentialTransferInstruction::WithdrawWithheldTokensFromMint"); - #[cfg(feature = "zk-ops")] - { - let data = decode_instruction_data::(input)?; - process_withdraw_withheld_tokens_from_mint( - program_id, - accounts, - data.proof_instruction_offset as i64, - ) - } - #[cfg(not(feature = "zk-ops"))] - Err(ProgramError::InvalidInstructionData) - } - ConfidentialTransferInstruction::WithdrawWithheldTokensFromAccounts => { - msg!("ConfidentialTransferInstruction::WithdrawWithheldTokensFromAccounts"); - #[cfg(feature = "zk-ops")] - { - let data = - decode_instruction_data::(input)?; - process_withdraw_withheld_tokens_from_accounts( - program_id, - accounts, - data.num_token_accounts, - data.proof_instruction_offset as i64, - ) - } - #[cfg(not(feature = "zk-ops"))] - Err(ProgramError::InvalidInstructionData) - } - ConfidentialTransferInstruction::HarvestWithheldTokensToMint => { - msg!("ConfidentialTransferInstruction::HarvestWithheldTokensToMint"); - #[cfg(feature = "zk-ops")] - { - process_harvest_withheld_tokens_to_mint(accounts) - } - #[cfg(not(feature = "zk-ops"))] - { - Err(ProgramError::InvalidInstructionData) - } - } - } -} diff --git a/token/program-2022/src/extension/default_account_state/instruction.rs b/token/program-2022/src/extension/default_account_state/instruction.rs deleted file mode 100644 index c872f41e89e..00000000000 --- a/token/program-2022/src/extension/default_account_state/instruction.rs +++ /dev/null @@ -1,124 +0,0 @@ -use { - crate::{ - check_program_account, error::TokenError, instruction::TokenInstruction, - state::AccountState, - }, - num_enum::{IntoPrimitive, TryFromPrimitive}, - solana_program::{ - instruction::{AccountMeta, Instruction}, - program_error::ProgramError, - pubkey::Pubkey, - }, - std::convert::TryFrom, -}; - -/// Default Account State extension instructions -#[derive(Clone, Copy, Debug, PartialEq, IntoPrimitive, TryFromPrimitive)] -#[repr(u8)] -pub enum DefaultAccountStateInstruction { - /// Initialize a new mint with the default state for new Accounts. - /// - /// Fails if the mint has already been initialized, so must be called before - /// `InitializeMint`. - /// - /// The mint must have exactly enough space allocated for the base mint (82 - /// bytes), plus 83 bytes of padding, 1 byte reserved for the account type, - /// then space required for this extension, plus any others. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The mint to initialize. - /// - /// Data expected by this instruction: - /// `crate::state::AccountState` - /// - Initialize, - /// Update the default state for new Accounts. Only supported for mints that include the - /// `DefaultAccountState` extension. - /// - /// Accounts expected by this instruction: - /// - /// * Single authority - /// 0. `[writable]` The mint. - /// 1. `[signer]` The mint freeze authority. - /// - /// * Multisignature authority - /// 0. `[writable]` The mint. - /// 1. `[]` The mint's multisignature freeze authority. - /// 2. ..2+M `[signer]` M signer accounts. - /// - /// Data expected by this instruction: - /// `crate::state::AccountState` - /// - Update, -} - -/// Utility function for decoding a DefaultAccountState instruction and its data -pub fn decode_instruction( - input: &[u8], -) -> Result<(DefaultAccountStateInstruction, AccountState), ProgramError> { - if input.len() != 2 { - return Err(TokenError::InvalidInstruction.into()); - } - Ok(( - DefaultAccountStateInstruction::try_from(input[0]) - .or(Err(TokenError::InvalidInstruction))?, - AccountState::try_from(input[1]).or(Err(TokenError::InvalidInstruction))?, - )) -} - -fn encode_instruction( - token_program_id: &Pubkey, - accounts: Vec, - instruction_type: DefaultAccountStateInstruction, - state: &AccountState, -) -> Instruction { - let mut data = TokenInstruction::DefaultAccountStateExtension.pack(); - data.push(instruction_type.into()); - data.push((*state).into()); - Instruction { - program_id: *token_program_id, - accounts, - data, - } -} - -/// Create an `Initialize` instruction -pub fn initialize_default_account_state( - token_program_id: &Pubkey, - mint: &Pubkey, - state: &AccountState, -) -> Result { - check_program_account(token_program_id)?; - let accounts = vec![AccountMeta::new(*mint, false)]; - Ok(encode_instruction( - token_program_id, - accounts, - DefaultAccountStateInstruction::Initialize, - state, - )) -} - -/// Create an `Initialize` instruction -pub fn update_default_account_state( - token_program_id: &Pubkey, - mint: &Pubkey, - freeze_authority: &Pubkey, - signers: &[&Pubkey], - state: &AccountState, -) -> Result { - check_program_account(token_program_id)?; - let mut accounts = vec![ - AccountMeta::new(*mint, false), - AccountMeta::new_readonly(*freeze_authority, signers.is_empty()), - ]; - for signer_pubkey in signers.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - Ok(encode_instruction( - token_program_id, - accounts, - DefaultAccountStateInstruction::Update, - state, - )) -} diff --git a/token/program-2022/src/extension/default_account_state/mod.rs b/token/program-2022/src/extension/default_account_state/mod.rs deleted file mode 100644 index 848ea4627d1..00000000000 --- a/token/program-2022/src/extension/default_account_state/mod.rs +++ /dev/null @@ -1,23 +0,0 @@ -use { - crate::extension::{Extension, ExtensionType}, - bytemuck::{Pod, Zeroable}, -}; - -/// Default Account state extension instructions -pub mod instruction; - -/// Default Account state extension processor -pub mod processor; - -/// Default Account::state extension data for mints. -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] -pub struct DefaultAccountState { - /// Default Account::state in which new Accounts should be initialized - pub state: PodAccountState, -} -impl Extension for DefaultAccountState { - const TYPE: ExtensionType = ExtensionType::DefaultAccountState; -} - -type PodAccountState = u8; diff --git a/token/program-2022/src/extension/default_account_state/processor.rs b/token/program-2022/src/extension/default_account_state/processor.rs deleted file mode 100644 index becc9fa8ee3..00000000000 --- a/token/program-2022/src/extension/default_account_state/processor.rs +++ /dev/null @@ -1,91 +0,0 @@ -use { - crate::{ - check_program_account, - error::TokenError, - extension::{ - default_account_state::{ - instruction::{decode_instruction, DefaultAccountStateInstruction}, - DefaultAccountState, - }, - StateWithExtensionsMut, - }, - processor::Processor, - state::{AccountState, Mint}, - }, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - pubkey::Pubkey, - }, -}; - -fn check_valid_default_state(state: AccountState) -> ProgramResult { - match state { - AccountState::Uninitialized => Err(TokenError::InvalidState.into()), - _ => Ok(()), - } -} - -fn process_initialize_default_account_state( - accounts: &[AccountInfo], - state: AccountState, -) -> ProgramResult { - check_valid_default_state(state)?; - let account_info_iter = &mut accounts.iter(); - let mint_account_info = next_account_info(account_info_iter)?; - let mut mint_data = mint_account_info.data.borrow_mut(); - let mut mint = StateWithExtensionsMut::::unpack_uninitialized(&mut mint_data)?; - let extension = mint.init_extension::(true)?; - extension.state = state.into(); - Ok(()) -} - -fn process_update_default_account_state( - program_id: &Pubkey, - accounts: &[AccountInfo], - state: AccountState, -) -> ProgramResult { - check_valid_default_state(state)?; - let account_info_iter = &mut accounts.iter(); - let mint_account_info = next_account_info(account_info_iter)?; - let freeze_authority_info = next_account_info(account_info_iter)?; - let freeze_authority_info_data_len = freeze_authority_info.data_len(); - - let mut mint_data = mint_account_info.data.borrow_mut(); - let mut mint = StateWithExtensionsMut::::unpack(&mut mint_data)?; - - let freeze_authority = - Option::::from(mint.base.freeze_authority).ok_or(TokenError::NoAuthorityExists)?; - Processor::validate_owner( - program_id, - &freeze_authority, - freeze_authority_info, - freeze_authority_info_data_len, - account_info_iter.as_slice(), - )?; - - let extension = mint.get_extension_mut::()?; - extension.state = state.into(); - Ok(()) -} - -pub(crate) fn process_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - input: &[u8], -) -> ProgramResult { - check_program_account(program_id)?; - - let (instruction, state) = decode_instruction(input)?; - match instruction { - DefaultAccountStateInstruction::Initialize => { - msg!("DefaultAccountStateInstruction::Initialize"); - process_initialize_default_account_state(accounts, state) - } - DefaultAccountStateInstruction::Update => { - msg!("DefaultAccountStateInstruction::Update"); - process_update_default_account_state(program_id, accounts, state) - } - } -} diff --git a/token/program-2022/src/extension/immutable_owner.rs b/token/program-2022/src/extension/immutable_owner.rs deleted file mode 100644 index 32d03210b60..00000000000 --- a/token/program-2022/src/extension/immutable_owner.rs +++ /dev/null @@ -1,13 +0,0 @@ -use { - crate::extension::{Extension, ExtensionType}, - bytemuck::{Pod, Zeroable}, -}; - -/// Indicates that the Account owner authority cannot be changed -#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] -#[repr(transparent)] -pub struct ImmutableOwner; - -impl Extension for ImmutableOwner { - const TYPE: ExtensionType = ExtensionType::ImmutableOwner; -} diff --git a/token/program-2022/src/extension/interest_bearing_mint/instruction.rs b/token/program-2022/src/extension/interest_bearing_mint/instruction.rs deleted file mode 100644 index 5231bb959e0..00000000000 --- a/token/program-2022/src/extension/interest_bearing_mint/instruction.rs +++ /dev/null @@ -1,113 +0,0 @@ -use { - crate::{ - check_program_account, - extension::interest_bearing_mint::BasisPoints, - instruction::{encode_instruction, TokenInstruction}, - pod::OptionalNonZeroPubkey, - }, - bytemuck::{Pod, Zeroable}, - num_enum::{IntoPrimitive, TryFromPrimitive}, - solana_program::{ - instruction::{AccountMeta, Instruction}, - program_error::ProgramError, - pubkey::Pubkey, - }, - std::convert::TryInto, -}; - -/// Interesting-bearing mint extension instructions -#[derive(Clone, Copy, Debug, PartialEq, IntoPrimitive, TryFromPrimitive)] -#[repr(u8)] -pub enum InterestBearingMintInstruction { - /// Initialize a new mint with interest accrual. - /// - /// Fails if the mint has already been initialized, so must be called before - /// `InitializeMint`. - /// - /// The mint must have exactly enough space allocated for the base mint (82 - /// bytes), plus 83 bytes of padding, 1 byte reserved for the account type, - /// then space required for this extension, plus any others. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The mint to initialize. - /// - /// Data expected by this instruction: - /// `crate::extension::interest_bearing::instruction::InitializeInstructionData` - /// - Initialize, - /// Update the interest rate. Only supported for mints that include the - /// `InterestBearingConfig` extension. - /// - /// Accounts expected by this instruction: - /// - /// * Single authority - /// 0. `[writable]` The mint. - /// 1. `[signer]` The mint rate authority. - /// - /// * Multisignature authority - /// 0. `[writable]` The mint. - /// 1. `[]` The mint's multisignature rate authority. - /// 2. ..2+M `[signer]` M signer accounts. - /// - /// Data expected by this instruction: - /// `crate::extension::interest_bearing::BasisPoints` - /// - UpdateRate, -} - -/// Data expected by `InterestBearing::Initialize` -#[derive(Clone, Copy, Pod, Zeroable)] -#[repr(C)] -pub struct InitializeInstructionData { - /// The public key for the account that can update the rate - pub rate_authority: OptionalNonZeroPubkey, - /// The initial interest rate - pub rate: BasisPoints, -} - -/// Create an `Initialize` instruction -pub fn initialize( - token_program_id: &Pubkey, - mint: &Pubkey, - rate_authority: Option, - rate: i16, -) -> Result { - check_program_account(token_program_id)?; - let accounts = vec![AccountMeta::new(*mint, false)]; - Ok(encode_instruction( - token_program_id, - accounts, - TokenInstruction::InterestBearingMintExtension, - InterestBearingMintInstruction::Initialize, - &InitializeInstructionData { - rate_authority: rate_authority.try_into()?, - rate: rate.into(), - }, - )) -} - -/// Create an `UpdateRate` instruction -pub fn update_rate( - token_program_id: &Pubkey, - mint: &Pubkey, - rate_authority: &Pubkey, - signers: &[&Pubkey], - rate: i16, -) -> Result { - check_program_account(token_program_id)?; - let mut accounts = vec![ - AccountMeta::new(*mint, false), - AccountMeta::new_readonly(*rate_authority, signers.is_empty()), - ]; - for signer_pubkey in signers.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - Ok(encode_instruction( - token_program_id, - accounts, - TokenInstruction::InterestBearingMintExtension, - InterestBearingMintInstruction::UpdateRate, - &BasisPoints::from(rate), - )) -} diff --git a/token/program-2022/src/extension/interest_bearing_mint/mod.rs b/token/program-2022/src/extension/interest_bearing_mint/mod.rs deleted file mode 100644 index 2be210c317d..00000000000 --- a/token/program-2022/src/extension/interest_bearing_mint/mod.rs +++ /dev/null @@ -1,450 +0,0 @@ -use { - crate::{ - extension::{Extension, ExtensionType}, - pod::{OptionalNonZeroPubkey, PodI16, PodI64}, - }, - bytemuck::{Pod, Zeroable}, - solana_program::program_error::ProgramError, - std::convert::TryInto, -}; - -/// Interest-bearing mint extension instructions -pub mod instruction; - -/// Interest-bearing mint extension processor -pub mod processor; - -/// Annual interest rate, expressed as basis points -pub type BasisPoints = PodI16; -const ONE_IN_BASIS_POINTS: f64 = 10_000.; -const SECONDS_PER_YEAR: f64 = 60. * 60. * 24. * 365.24; - -/// UnixTimestamp expressed with an alignment-independent type -pub type UnixTimestamp = PodI64; - -/// Interest-bearing extension data for mints -/// -/// Tokens accrue interest at an annual rate expressed by `current_rate`, -/// compounded continuously, so APY will be higher than the published interest -/// rate. -/// -/// To support changing the rate, the config also maintains state for the previous -/// rate. -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] -pub struct InterestBearingConfig { - /// Authority that can set the interest rate and authority - pub rate_authority: OptionalNonZeroPubkey, - /// Timestamp of initialization, from which to base interest calculations - pub initialization_timestamp: UnixTimestamp, - /// Average rate from initialization until the last time it was updated - pub pre_update_average_rate: BasisPoints, - /// Timestamp of the last update, used to calculate the total amount accrued - pub last_update_timestamp: UnixTimestamp, - /// Current rate, since the last update - pub current_rate: BasisPoints, -} -impl InterestBearingConfig { - fn pre_update_timespan(&self) -> Option { - i64::from(self.last_update_timestamp).checked_sub(self.initialization_timestamp.into()) - } - - fn pre_update_exp(&self) -> Option { - let numerator = (i16::from(self.pre_update_average_rate) as i128) - .checked_mul(self.pre_update_timespan()? as i128)? as f64; - let exponent = numerator / SECONDS_PER_YEAR / ONE_IN_BASIS_POINTS; - Some(exponent.exp()) - } - - fn post_update_timespan(&self, unix_timestamp: i64) -> Option { - unix_timestamp.checked_sub(self.last_update_timestamp.into()) - } - - fn post_update_exp(&self, unix_timestamp: i64) -> Option { - let numerator = (i16::from(self.current_rate) as i128) - .checked_mul(self.post_update_timespan(unix_timestamp)? as i128)? - as f64; - let exponent = numerator / SECONDS_PER_YEAR / ONE_IN_BASIS_POINTS; - Some(exponent.exp()) - } - - fn total_scale(&self, decimals: u8, unix_timestamp: i64) -> Option { - Some( - self.pre_update_exp()? * self.post_update_exp(unix_timestamp)? - / 10_f64.powi(decimals as i32), - ) - } - - /// Convert a raw amount to its UI representation using the given decimals field - /// Excess zeroes or unneeded decimal point are trimmed. - pub fn amount_to_ui_amount( - &self, - amount: u64, - decimals: u8, - unix_timestamp: i64, - ) -> Option { - let scaled_amount_with_interest = - (amount as f64) * self.total_scale(decimals, unix_timestamp)?; - Some(scaled_amount_with_interest.to_string()) - } - - /// Try to convert a UI represenation of a token amount to its raw amount using the given decimals - /// field - pub fn try_ui_amount_into_amount( - &self, - ui_amount: &str, - decimals: u8, - unix_timestamp: i64, - ) -> Result { - let scaled_amount = ui_amount - .parse::() - .map_err(|_| ProgramError::InvalidArgument)?; - let amount = scaled_amount - / self - .total_scale(decimals, unix_timestamp) - .ok_or(ProgramError::InvalidArgument)?; - if amount > (u64::MAX as f64) || amount < (u64::MIN as f64) || amount.is_nan() { - Err(ProgramError::InvalidArgument) - } else { - Ok(amount.round() as u64) // this is important, if you round earlier, you'll get wrong "inf" answers - } - } - - /// The new average rate is the time-weighted average of the current rate and average rate, - /// solving for r such that: - /// - /// exp(r_1 * t_1) * exp(r_2 * t_2) = exp(r * (t_1 + t_2)) - /// - /// r_1 * t_1 + r_2 * t_2 = r * (t_1 + t_2) - /// - /// r = (r_1 * t_1 + r_2 * t_2) / (t_1 + t_2) - pub fn time_weighted_average_rate(&self, current_timestamp: i64) -> Option { - let initialization_timestamp = i64::from(self.initialization_timestamp) as i128; - let last_update_timestamp = i64::from(self.last_update_timestamp) as i128; - - let r_1 = i16::from(self.pre_update_average_rate) as i128; - let t_1 = last_update_timestamp.checked_sub(initialization_timestamp)?; - let r_2 = i16::from(self.current_rate) as i128; - let t_2 = (current_timestamp as i128).checked_sub(last_update_timestamp)?; - let total_timespan = t_1.checked_add(t_2)?; - let average_rate = if total_timespan == 0 { - // happens in testing situations, just use the new rate since the earlier - // one was never practically used - r_2 - } else { - r_1.checked_mul(t_1)? - .checked_add(r_2.checked_mul(t_2)?)? - .checked_div(total_timespan)? - }; - average_rate.try_into().ok() - } -} -impl Extension for InterestBearingConfig { - const TYPE: ExtensionType = ExtensionType::InterestBearingConfig; -} - -#[cfg(test)] -mod tests { - use {super::*, proptest::prelude::*}; - - const INT_SECONDS_PER_YEAR: i64 = 6 * 6 * 24 * 36524; - const TEST_DECIMALS: u8 = 2; - - #[test] - fn seconds_per_year() { - assert_eq!(SECONDS_PER_YEAR, 31_556_736.); - assert_eq!(INT_SECONDS_PER_YEAR, 31_556_736); - } - - #[test] - fn specific_amount_to_ui_amount() { - // constant 5% - let config = InterestBearingConfig { - rate_authority: OptionalNonZeroPubkey::default(), - initialization_timestamp: 0.into(), - pre_update_average_rate: 500.into(), - last_update_timestamp: INT_SECONDS_PER_YEAR.into(), - current_rate: 500.into(), - }; - // 1 year at 5% gives a total of exp(0.05) = 1.0512710963760241 - let ui_amount = config - .amount_to_ui_amount(1, 0, INT_SECONDS_PER_YEAR) - .unwrap(); - assert_eq!(ui_amount, "1.0512710963760241"); - // with 1 decimal place - let ui_amount = config - .amount_to_ui_amount(1, 1, INT_SECONDS_PER_YEAR) - .unwrap(); - assert_eq!(ui_amount, "0.10512710963760241"); - // with 10 decimal places - let ui_amount = config - .amount_to_ui_amount(1, 10, INT_SECONDS_PER_YEAR) - .unwrap(); - assert_eq!(ui_amount, "0.00000000010512710963760242"); // different digit at the end! - - // huge amount with 10 decimal places - let ui_amount = config - .amount_to_ui_amount(10_000_000_000, 10, INT_SECONDS_PER_YEAR) - .unwrap(); - assert_eq!(ui_amount, "1.0512710963760241"); - - // negative - let config = InterestBearingConfig { - rate_authority: OptionalNonZeroPubkey::default(), - initialization_timestamp: 0.into(), - pre_update_average_rate: PodI16::from(-500), - last_update_timestamp: INT_SECONDS_PER_YEAR.into(), - current_rate: PodI16::from(-500), - }; - // 1 year at -5% gives a total of exp(-0.05) = 0.951229424500714 - let ui_amount = config - .amount_to_ui_amount(1, 0, INT_SECONDS_PER_YEAR) - .unwrap(); - assert_eq!(ui_amount, "0.951229424500714"); - - // net out - let config = InterestBearingConfig { - rate_authority: OptionalNonZeroPubkey::default(), - initialization_timestamp: 0.into(), - pre_update_average_rate: PodI16::from(-500), - last_update_timestamp: INT_SECONDS_PER_YEAR.into(), - current_rate: PodI16::from(500), - }; - // 1 year at -5% and 1 year at 5% gives a total of 1 - let ui_amount = config - .amount_to_ui_amount(1, 0, INT_SECONDS_PER_YEAR * 2) - .unwrap(); - assert_eq!(ui_amount, "1"); - - // huge values - let config = InterestBearingConfig { - rate_authority: OptionalNonZeroPubkey::default(), - initialization_timestamp: 0.into(), - pre_update_average_rate: PodI16::from(500), - last_update_timestamp: INT_SECONDS_PER_YEAR.into(), - current_rate: PodI16::from(500), - }; - let ui_amount = config - .amount_to_ui_amount(u64::MAX, 0, INT_SECONDS_PER_YEAR * 2) - .unwrap(); - assert_eq!(ui_amount, "20386805083448100000"); - let ui_amount = config - .amount_to_ui_amount(u64::MAX, 0, INT_SECONDS_PER_YEAR * 10_000) - .unwrap(); - // there's an underflow risk, but it works! - assert_eq!(ui_amount, "258917064265813830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - } - - #[test] - fn specific_ui_amount_to_amount() { - // constant 5% - let config = InterestBearingConfig { - rate_authority: OptionalNonZeroPubkey::default(), - initialization_timestamp: 0.into(), - pre_update_average_rate: 500.into(), - last_update_timestamp: INT_SECONDS_PER_YEAR.into(), - current_rate: 500.into(), - }; - // 1 year at 5% gives a total of exp(0.05) = 1.0512710963760241 - let amount = config - .try_ui_amount_into_amount("1.0512710963760241", 0, INT_SECONDS_PER_YEAR) - .unwrap(); - assert_eq!(1, amount); - // with 1 decimal place - let amount = config - .try_ui_amount_into_amount("0.10512710963760241", 1, INT_SECONDS_PER_YEAR) - .unwrap(); - assert_eq!(amount, 1); - // with 10 decimal places - let amount = config - .try_ui_amount_into_amount("0.00000000010512710963760242", 10, INT_SECONDS_PER_YEAR) - .unwrap(); - assert_eq!(amount, 1); - - // huge amount with 10 decimal places - let amount = config - .try_ui_amount_into_amount("1.0512710963760241", 10, INT_SECONDS_PER_YEAR) - .unwrap(); - assert_eq!(amount, 10_000_000_000); - - // negative - let config = InterestBearingConfig { - rate_authority: OptionalNonZeroPubkey::default(), - initialization_timestamp: 0.into(), - pre_update_average_rate: PodI16::from(-500), - last_update_timestamp: INT_SECONDS_PER_YEAR.into(), - current_rate: PodI16::from(-500), - }; - // 1 year at -5% gives a total of exp(-0.05) = 0.951229424500714 - let amount = config - .try_ui_amount_into_amount("0.951229424500714", 0, INT_SECONDS_PER_YEAR) - .unwrap(); - assert_eq!(amount, 1); - - // net out - let config = InterestBearingConfig { - rate_authority: OptionalNonZeroPubkey::default(), - initialization_timestamp: 0.into(), - pre_update_average_rate: PodI16::from(-500), - last_update_timestamp: INT_SECONDS_PER_YEAR.into(), - current_rate: PodI16::from(500), - }; - // 1 year at -5% and 1 year at 5% gives a total of 1 - let amount = config - .try_ui_amount_into_amount("1", 0, INT_SECONDS_PER_YEAR * 2) - .unwrap(); - assert_eq!(amount, 1); - - // huge values - let config = InterestBearingConfig { - rate_authority: OptionalNonZeroPubkey::default(), - initialization_timestamp: 0.into(), - pre_update_average_rate: PodI16::from(500), - last_update_timestamp: INT_SECONDS_PER_YEAR.into(), - current_rate: PodI16::from(500), - }; - let amount = config - .try_ui_amount_into_amount("20386805083448100000", 0, INT_SECONDS_PER_YEAR * 2) - .unwrap(); - assert_eq!(amount, u64::MAX); - let amount = config - .try_ui_amount_into_amount("258917064265813830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 0, INT_SECONDS_PER_YEAR * 10_000) - .unwrap(); - assert_eq!(amount, u64::MAX); - // scientific notation "e" - let amount = config - .try_ui_amount_into_amount("2.5891706426581383e236", 0, INT_SECONDS_PER_YEAR * 10_000) - .unwrap(); - assert_eq!(amount, u64::MAX); - // scientific notation "E" - let amount = config - .try_ui_amount_into_amount("2.5891706426581383E236", 0, INT_SECONDS_PER_YEAR * 10_000) - .unwrap(); - assert_eq!(amount, u64::MAX); - - // overflow u64 fail - assert_eq!( - Err(ProgramError::InvalidArgument), - config.try_ui_amount_into_amount("20386805083448200001", 0, INT_SECONDS_PER_YEAR) - ); - - for fail_ui_amount in ["-0.0000000000000000000001", "inf", "-inf", "NaN"] { - assert_eq!( - Err(ProgramError::InvalidArgument), - config.try_ui_amount_into_amount(fail_ui_amount, 0, INT_SECONDS_PER_YEAR) - ); - } - } - - #[test] - fn specific_amount_to_ui_amount_no_interest() { - let config = InterestBearingConfig { - rate_authority: OptionalNonZeroPubkey::default(), - initialization_timestamp: 0.into(), - pre_update_average_rate: 0.into(), - last_update_timestamp: INT_SECONDS_PER_YEAR.into(), - current_rate: 0.into(), - }; - for (amount, expected) in [(23, "0.23"), (110, "1.1"), (4200, "42"), (0, "0")] { - let ui_amount = config - .amount_to_ui_amount(amount, TEST_DECIMALS, INT_SECONDS_PER_YEAR) - .unwrap(); - assert_eq!(ui_amount, expected); - } - } - - #[test] - fn specific_ui_amount_to_amount_no_interest() { - let config = InterestBearingConfig { - rate_authority: OptionalNonZeroPubkey::default(), - initialization_timestamp: 0.into(), - pre_update_average_rate: 0.into(), - last_update_timestamp: INT_SECONDS_PER_YEAR.into(), - current_rate: 0.into(), - }; - for (ui_amount, expected) in [ - ("0.23", 23), - ("0.20", 20), - ("0.2000", 20), - (".2", 20), - ("1.1", 110), - ("1.10", 110), - ("42", 4200), - ("42.", 4200), - ("0", 0), - ] { - let amount = config - .try_ui_amount_into_amount(ui_amount, TEST_DECIMALS, INT_SECONDS_PER_YEAR) - .unwrap(); - assert_eq!(expected, amount); - } - - // this is invalid with normal mints, but rounding for this mint makes it ok - let amount = config - .try_ui_amount_into_amount("0.111", TEST_DECIMALS, INT_SECONDS_PER_YEAR) - .unwrap(); - assert_eq!(11, amount); - - // fail if invalid ui_amount passed in - for ui_amount in ["", ".", "0.t"] { - assert_eq!( - Err(ProgramError::InvalidArgument), - config.try_ui_amount_into_amount(ui_amount, TEST_DECIMALS, INT_SECONDS_PER_YEAR), - ); - } - } - - prop_compose! { - /// Three values in ascending order - fn low_middle_high() - (middle in 1..i64::MAX - 1) - (low in 0..=middle, middle in Just(middle), high in middle..=i64::MAX) - -> (i64, i64, i64) { - (low, middle, high) - } - } - - proptest! { - #[test] - fn time_weighted_average_calc( - current_rate in i16::MIN..i16::MAX, - pre_update_average_rate in i16::MIN..i16::MAX, - (initialization_timestamp, last_update_timestamp, current_timestamp) in low_middle_high(), - ) { - let config = InterestBearingConfig { - rate_authority: OptionalNonZeroPubkey::default(), - initialization_timestamp: initialization_timestamp.into(), - pre_update_average_rate: pre_update_average_rate.into(), - last_update_timestamp: last_update_timestamp.into(), - current_rate: current_rate.into(), - }; - let new_rate = config.time_weighted_average_rate(current_timestamp).unwrap(); - if pre_update_average_rate <= current_rate { - assert!(pre_update_average_rate <= new_rate); - assert!(new_rate <= current_rate); - } else { - assert!(current_rate <= new_rate); - assert!(new_rate <= pre_update_average_rate); - } - } - - #[test] - fn amount_to_ui_amount( - current_rate in i16::MIN..i16::MAX, - pre_update_average_rate in i16::MIN..i16::MAX, - (initialization_timestamp, last_update_timestamp, current_timestamp) in low_middle_high(), - amount in 0..=u64::MAX, - decimals in 0u8..20u8, - ) { - let config = InterestBearingConfig { - rate_authority: OptionalNonZeroPubkey::default(), - initialization_timestamp: initialization_timestamp.into(), - pre_update_average_rate: pre_update_average_rate.into(), - last_update_timestamp: last_update_timestamp.into(), - current_rate: current_rate.into(), - }; - let ui_amount = config.amount_to_ui_amount(amount, decimals, current_timestamp); - assert!(ui_amount.is_some()); - } - } -} diff --git a/token/program-2022/src/extension/interest_bearing_mint/processor.rs b/token/program-2022/src/extension/interest_bearing_mint/processor.rs deleted file mode 100644 index 3c05084ad84..00000000000 --- a/token/program-2022/src/extension/interest_bearing_mint/processor.rs +++ /dev/null @@ -1,107 +0,0 @@ -use { - crate::{ - check_program_account, - error::TokenError, - extension::{ - interest_bearing_mint::{ - instruction::{InitializeInstructionData, InterestBearingMintInstruction}, - BasisPoints, InterestBearingConfig, - }, - StateWithExtensionsMut, - }, - instruction::{decode_instruction_data, decode_instruction_type}, - pod::OptionalNonZeroPubkey, - processor::Processor, - state::Mint, - }, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - clock::Clock, - entrypoint::ProgramResult, - msg, - pubkey::Pubkey, - sysvar::Sysvar, - }, -}; - -fn process_initialize( - _program_id: &Pubkey, - accounts: &[AccountInfo], - rate_authority: &OptionalNonZeroPubkey, - rate: &BasisPoints, -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_account_info = next_account_info(account_info_iter)?; - let mut mint_data = mint_account_info.data.borrow_mut(); - let mut mint = StateWithExtensionsMut::::unpack_uninitialized(&mut mint_data)?; - - let clock = Clock::get()?; - let extension = mint.init_extension::(true)?; - extension.rate_authority = *rate_authority; - extension.initialization_timestamp = clock.unix_timestamp.into(); - extension.last_update_timestamp = clock.unix_timestamp.into(); - // There is no validation on the rate, since ridiculous values are *technically* - // possible! - extension.pre_update_average_rate = *rate; - extension.current_rate = *rate; - Ok(()) -} - -fn process_update_rate( - program_id: &Pubkey, - accounts: &[AccountInfo], - new_rate: &BasisPoints, -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_account_info = next_account_info(account_info_iter)?; - let owner_info = next_account_info(account_info_iter)?; - let owner_info_data_len = owner_info.data_len(); - - let mut mint_data = mint_account_info.data.borrow_mut(); - let mut mint = StateWithExtensionsMut::::unpack(&mut mint_data)?; - let extension = mint.get_extension_mut::()?; - let rate_authority = - Option::::from(extension.rate_authority).ok_or(TokenError::NoAuthorityExists)?; - - Processor::validate_owner( - program_id, - &rate_authority, - owner_info, - owner_info_data_len, - account_info_iter.as_slice(), - )?; - - let clock = Clock::get()?; - let new_average_rate = extension - .time_weighted_average_rate(clock.unix_timestamp) - .ok_or(TokenError::Overflow)?; - extension.pre_update_average_rate = new_average_rate.into(); - extension.last_update_timestamp = clock.unix_timestamp.into(); - // There is no validation on the rate, since ridiculous values are *technically* - // possible! - extension.current_rate = *new_rate; - Ok(()) -} - -pub(crate) fn process_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - input: &[u8], -) -> ProgramResult { - check_program_account(program_id)?; - match decode_instruction_type(input)? { - InterestBearingMintInstruction::Initialize => { - msg!("InterestBearingMintInstruction::Initialize"); - let InitializeInstructionData { - rate_authority, - rate, - } = decode_instruction_data(input)?; - process_initialize(program_id, accounts, rate_authority, rate) - } - InterestBearingMintInstruction::UpdateRate => { - msg!("InterestBearingMintInstruction::UpdateRate"); - let new_rate = decode_instruction_data(input)?; - process_update_rate(program_id, accounts, new_rate) - } - } -} diff --git a/token/program-2022/src/extension/memo_transfer/instruction.rs b/token/program-2022/src/extension/memo_transfer/instruction.rs deleted file mode 100644 index 1f87c9e3aa6..00000000000 --- a/token/program-2022/src/extension/memo_transfer/instruction.rs +++ /dev/null @@ -1,95 +0,0 @@ -use { - crate::{ - check_program_account, - instruction::{encode_instruction, TokenInstruction}, - }, - num_enum::{IntoPrimitive, TryFromPrimitive}, - solana_program::{ - instruction::{AccountMeta, Instruction}, - program_error::ProgramError, - pubkey::Pubkey, - }, -}; - -/// Default Account State extension instructions -#[derive(Clone, Copy, Debug, PartialEq, IntoPrimitive, TryFromPrimitive)] -#[repr(u8)] -pub enum RequiredMemoTransfersInstruction { - /// Require memos for transfers into this Account. Adds the MemoTransfer extension to the - /// Account, if it doesn't already exist. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The account to update. - /// 1. `[signer]` The account's owner. - /// - /// * Multisignature authority - /// 0. `[writable]` The account to update. - /// 1. `[]` The account's multisignature owner. - /// 2. ..2+M `[signer]` M signer accounts. - /// - Enable, - /// Stop requiring memos for transfers into this Account. - /// - /// Fails if the account does not have the extension present. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The account to update. - /// 1. `[signer]` The account's owner. - /// - /// * Multisignature authority - /// 0. `[writable]` The account to update. - /// 1. `[]` The account's multisignature owner. - /// 2. ..2+M `[signer]` M signer accounts. - /// - Disable, -} - -/// Create an `Enable` instruction -pub fn enable_required_transfer_memos( - token_program_id: &Pubkey, - account: &Pubkey, - owner: &Pubkey, - signers: &[&Pubkey], -) -> Result { - check_program_account(token_program_id)?; - let mut accounts = vec![ - AccountMeta::new(*account, false), - AccountMeta::new_readonly(*owner, signers.is_empty()), - ]; - for signer_pubkey in signers.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - Ok(encode_instruction( - token_program_id, - accounts, - TokenInstruction::MemoTransferExtension, - RequiredMemoTransfersInstruction::Enable, - &(), - )) -} - -/// Create a `Disable` instruction -pub fn disable_required_transfer_memos( - token_program_id: &Pubkey, - account: &Pubkey, - owner: &Pubkey, - signers: &[&Pubkey], -) -> Result { - check_program_account(token_program_id)?; - let mut accounts = vec![ - AccountMeta::new(*account, false), - AccountMeta::new_readonly(*owner, signers.is_empty()), - ]; - for signer_pubkey in signers.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - Ok(encode_instruction( - token_program_id, - accounts, - TokenInstruction::MemoTransferExtension, - RequiredMemoTransfersInstruction::Disable, - &(), - )) -} diff --git a/token/program-2022/src/extension/memo_transfer/mod.rs b/token/program-2022/src/extension/memo_transfer/mod.rs deleted file mode 100644 index 4f586132b9e..00000000000 --- a/token/program-2022/src/extension/memo_transfer/mod.rs +++ /dev/null @@ -1,52 +0,0 @@ -use { - crate::{ - error::TokenError, - extension::{Extension, ExtensionType, StateWithExtensionsMut}, - pod::PodBool, - state::Account, - }, - bytemuck::{Pod, Zeroable}, - solana_program::{ - instruction::get_processed_sibling_instruction, program_error::ProgramError, pubkey::Pubkey, - }, -}; - -/// Memo Transfer extension instructions -pub mod instruction; - -/// Memo Transfer extension processor -pub mod processor; - -/// Memo Transfer extension for Accounts -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] -pub struct MemoTransfer { - /// Require transfers into this account to be accompanied by a memo - pub require_incoming_transfer_memos: PodBool, -} -impl Extension for MemoTransfer { - const TYPE: ExtensionType = ExtensionType::MemoTransfer; -} - -/// Determine if a memo is required for transfers into this account -pub fn memo_required(account_state: &StateWithExtensionsMut) -> bool { - if let Ok(extension) = account_state.get_extension::() { - return extension.require_incoming_transfer_memos.into(); - } - false -} - -/// Check if the previous sibling instruction is a memo -pub fn check_previous_sibling_instruction_is_memo() -> Result<(), ProgramError> { - let is_memo_program = |program_id: &Pubkey| -> bool { - program_id == &spl_memo::id() || program_id == &spl_memo::v1::id() - }; - let previous_instruction = get_processed_sibling_instruction(0); - match previous_instruction { - Some(instruction) if is_memo_program(&instruction.program_id) => {} - _ => { - return Err(TokenError::NoMemo.into()); - } - } - Ok(()) -} diff --git a/token/program-2022/src/extension/memo_transfer/processor.rs b/token/program-2022/src/extension/memo_transfer/processor.rs deleted file mode 100644 index 38c987cabe5..00000000000 --- a/token/program-2022/src/extension/memo_transfer/processor.rs +++ /dev/null @@ -1,96 +0,0 @@ -use { - crate::{ - check_program_account, - extension::{ - memo_transfer::{instruction::RequiredMemoTransfersInstruction, MemoTransfer}, - StateWithExtensionsMut, - }, - instruction::decode_instruction_type, - processor::Processor, - state::Account, - }, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - pubkey::Pubkey, - }, -}; - -fn process_enable_required_memo_transfers( - program_id: &Pubkey, - accounts: &[AccountInfo], -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let token_account_info = next_account_info(account_info_iter)?; - let owner_info = next_account_info(account_info_iter)?; - let owner_info_data_len = owner_info.data_len(); - - let mut account_data = token_account_info.data.borrow_mut(); - let mut account = StateWithExtensionsMut::::unpack(&mut account_data)?; - - Processor::validate_owner( - program_id, - &account.base.owner, - owner_info, - owner_info_data_len, - account_info_iter.as_slice(), - )?; - - let extension = if let Ok(extension) = account.get_extension_mut::() { - extension - } else { - account.init_extension::(true)? - }; - extension.require_incoming_transfer_memos = true.into(); - Ok(()) -} - -fn process_diasble_required_memo_transfers( - program_id: &Pubkey, - accounts: &[AccountInfo], -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let token_account_info = next_account_info(account_info_iter)?; - let owner_info = next_account_info(account_info_iter)?; - let owner_info_data_len = owner_info.data_len(); - - let mut account_data = token_account_info.data.borrow_mut(); - let mut account = StateWithExtensionsMut::::unpack(&mut account_data)?; - - Processor::validate_owner( - program_id, - &account.base.owner, - owner_info, - owner_info_data_len, - account_info_iter.as_slice(), - )?; - - let extension = if let Ok(extension) = account.get_extension_mut::() { - extension - } else { - account.init_extension::(true)? - }; - extension.require_incoming_transfer_memos = false.into(); - Ok(()) -} - -#[allow(dead_code)] -pub(crate) fn process_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - input: &[u8], -) -> ProgramResult { - check_program_account(program_id)?; - - match decode_instruction_type(input)? { - RequiredMemoTransfersInstruction::Enable => { - msg!("RequiredMemoTransfersInstruction::Enable"); - process_enable_required_memo_transfers(program_id, accounts) - } - RequiredMemoTransfersInstruction::Disable => { - msg!("RequiredMemoTransfersInstruction::Disable"); - process_diasble_required_memo_transfers(program_id, accounts) - } - } -} diff --git a/token/program-2022/src/extension/mint_close_authority.rs b/token/program-2022/src/extension/mint_close_authority.rs deleted file mode 100644 index beb76a96d7e..00000000000 --- a/token/program-2022/src/extension/mint_close_authority.rs +++ /dev/null @@ -1,18 +0,0 @@ -use { - crate::{ - extension::{Extension, ExtensionType}, - pod::*, - }, - bytemuck::{Pod, Zeroable}, -}; - -/// Close authority extension data for mints. -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] -pub struct MintCloseAuthority { - /// Optional authority to close the mint - pub close_authority: OptionalNonZeroPubkey, -} -impl Extension for MintCloseAuthority { - const TYPE: ExtensionType = ExtensionType::MintCloseAuthority; -} diff --git a/token/program-2022/src/extension/mod.rs b/token/program-2022/src/extension/mod.rs deleted file mode 100644 index 7c895fa7f66..00000000000 --- a/token/program-2022/src/extension/mod.rs +++ /dev/null @@ -1,1600 +0,0 @@ -//! Extensions available to token mints and accounts - -use { - crate::{ - error::TokenError, - extension::{ - confidential_transfer::{ConfidentialTransferAccount, ConfidentialTransferMint}, - default_account_state::DefaultAccountState, - immutable_owner::ImmutableOwner, - interest_bearing_mint::InterestBearingConfig, - memo_transfer::MemoTransfer, - mint_close_authority::MintCloseAuthority, - non_transferable::NonTransferable, - transfer_fee::{TransferFeeAmount, TransferFeeConfig}, - }, - pod::*, - state::{Account, Mint, Multisig}, - }, - bytemuck::{Pod, Zeroable}, - num_enum::{IntoPrimitive, TryFromPrimitive}, - solana_program::{ - program_error::ProgramError, - program_pack::{IsInitialized, Pack}, - }, - std::{ - convert::{TryFrom, TryInto}, - mem::size_of, - }, -}; - -#[cfg(feature = "serde-traits")] -use serde::{Deserialize, Serialize}; - -/// Confidential Transfer extension -pub mod confidential_transfer; -/// Default Account State extension -pub mod default_account_state; -/// Immutable Owner extension -pub mod immutable_owner; -/// Interest-Bearing Mint extension -pub mod interest_bearing_mint; -/// Memo Transfer extension -pub mod memo_transfer; -/// Mint Close Authority extension -pub mod mint_close_authority; -/// Non Transferable extension -pub mod non_transferable; -/// Utility to reallocate token accounts -pub mod reallocate; -/// Transfer Fee extension -pub mod transfer_fee; - -/// Length in TLV structure -#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] -#[repr(transparent)] -pub struct Length(PodU16); -impl From for usize { - fn from(n: Length) -> Self { - Self::from(u16::from(n.0)) - } -} -impl TryFrom for Length { - type Error = ProgramError; - fn try_from(n: usize) -> Result { - u16::try_from(n) - .map(|v| Self(PodU16::from(v))) - .map_err(|_| ProgramError::AccountDataTooSmall) - } -} - -/// Helper function to get the current TlvIndices from the current spot -fn get_tlv_indices(type_start: usize) -> TlvIndices { - let length_start = type_start.saturating_add(size_of::()); - let value_start = length_start.saturating_add(pod_get_packed_len::()); - TlvIndices { - type_start, - length_start, - value_start, - } -} - -/// Helper struct for returning the indices of the type, length, and value in -/// a TLV entry -#[derive(Debug)] -struct TlvIndices { - pub type_start: usize, - pub length_start: usize, - pub value_start: usize, -} -fn get_extension_indices( - tlv_data: &[u8], - init: bool, -) -> Result { - let mut start_index = 0; - let v_account_type = V::TYPE.get_account_type(); - while start_index < tlv_data.len() { - let tlv_indices = get_tlv_indices(start_index); - if tlv_data.len() < tlv_indices.value_start { - return Err(ProgramError::InvalidAccountData); - } - let extension_type = - ExtensionType::try_from(&tlv_data[tlv_indices.type_start..tlv_indices.length_start])?; - let account_type = extension_type.get_account_type(); - // got to an empty spot, can init here, or move forward if not initing - if extension_type == ExtensionType::Uninitialized { - if init { - return Ok(tlv_indices); - } else { - start_index = tlv_indices.length_start; - } - } else if extension_type == V::TYPE { - // found an instance of the extension that we're initializing, return! - return Ok(tlv_indices); - } else if v_account_type != account_type { - return Err(TokenError::ExtensionTypeMismatch.into()); - } else { - let length = pod_from_bytes::( - &tlv_data[tlv_indices.length_start..tlv_indices.value_start], - )?; - let value_end_index = tlv_indices.value_start.saturating_add(usize::from(*length)); - start_index = value_end_index; - } - } - Err(ProgramError::InvalidAccountData) -} - -fn get_extension_types(tlv_data: &[u8]) -> Result, ProgramError> { - let mut extension_types = vec![]; - let mut start_index = 0; - while start_index < tlv_data.len() { - let tlv_indices = get_tlv_indices(start_index); - if tlv_data.len() < tlv_indices.value_start { - return Ok(extension_types); - } - let extension_type = - ExtensionType::try_from(&tlv_data[tlv_indices.type_start..tlv_indices.length_start])?; - if extension_type == ExtensionType::Uninitialized { - return Ok(extension_types); - } else { - extension_types.push(extension_type); - let length = pod_from_bytes::( - &tlv_data[tlv_indices.length_start..tlv_indices.value_start], - )?; - - let value_end_index = tlv_indices.value_start.saturating_add(usize::from(*length)); - start_index = value_end_index; - } - } - Ok(extension_types) -} - -fn get_first_extension_type(tlv_data: &[u8]) -> Result, ProgramError> { - if tlv_data.is_empty() { - Ok(None) - } else { - let tlv_indices = get_tlv_indices(0); - if tlv_data.len() <= tlv_indices.length_start { - return Ok(None); - } - let extension_type = - ExtensionType::try_from(&tlv_data[tlv_indices.type_start..tlv_indices.length_start])?; - if extension_type == ExtensionType::Uninitialized { - Ok(None) - } else { - Ok(Some(extension_type)) - } - } -} - -fn check_min_len_and_not_multisig(input: &[u8], minimum_len: usize) -> Result<(), ProgramError> { - if input.len() == Multisig::LEN || input.len() < minimum_len { - Err(ProgramError::InvalidAccountData) - } else { - Ok(()) - } -} - -fn check_account_type(account_type: AccountType) -> Result<(), ProgramError> { - if account_type != S::ACCOUNT_TYPE { - Err(ProgramError::InvalidAccountData) - } else { - Ok(()) - } -} - -/// Any account with extensions must be at least `Account::LEN`. Both mints and -/// accounts can have extensions -/// A mint with extensions that takes it past 165 could be indiscernible from an -/// Account with an extension, even if we add the account type. For example, -/// let's say we have: -/// -/// Account: 165 bytes... + [2, 0, 3, 0, 100, ....] -/// ^ ^ ^ ^ -/// acct type extension length data... -/// -/// Mint: 82 bytes... + 83 bytes of other extension data + [2, 0, 3, 0, 100, ....] -/// ^ data in extension just happens to look like this -/// -/// With this approach, we only start writing the TLV data after Account::LEN, -/// which means we always know that the account type is going to be right after -/// that. We do a special case checking for a Multisig length, because those -/// aren't extensible under any circumstances. -const BASE_ACCOUNT_LENGTH: usize = Account::LEN; - -fn type_and_tlv_indices( - rest_input: &[u8], -) -> Result, ProgramError> { - if rest_input.is_empty() { - Ok(None) - } else { - let account_type_index = BASE_ACCOUNT_LENGTH.saturating_sub(S::LEN); - // check padding is all zeroes - let tlv_start_index = account_type_index.saturating_add(size_of::()); - if rest_input.len() <= tlv_start_index { - return Err(ProgramError::InvalidAccountData); - } - if rest_input[..account_type_index] != vec![0; account_type_index] { - Err(ProgramError::InvalidAccountData) - } else { - Ok(Some((account_type_index, tlv_start_index))) - } - } -} - -/// Checks a base buffer to verify if it is an Account without having to completely deserialize it -fn is_initialized_account(input: &[u8]) -> Result { - const ACCOUNT_INITIALIZED_INDEX: usize = 108; // See state.rs#L99 - - if input.len() != BASE_ACCOUNT_LENGTH { - return Err(ProgramError::InvalidAccountData); - } - Ok(input[ACCOUNT_INITIALIZED_INDEX] != 0) -} - -fn get_extension(tlv_data: &[u8]) -> Result<&V, ProgramError> { - if V::TYPE.get_account_type() != S::ACCOUNT_TYPE { - return Err(ProgramError::InvalidAccountData); - } - let TlvIndices { - type_start: _, - length_start, - value_start, - } = get_extension_indices::(tlv_data, false)?; - // get_extension_indices has checked that tlv_data is long enough to include these indices - let length = pod_from_bytes::(&tlv_data[length_start..value_start])?; - let value_end = value_start.saturating_add(usize::from(*length)); - pod_from_bytes::(&tlv_data[value_start..value_end]) -} - -/// Encapsulates owned immutable base state data (mint or account) with possible extensions -#[derive(Debug, PartialEq)] -pub struct StateWithExtensionsOwned { - /// Unpacked base data - pub base: S, - /// Raw TLV data, deserialized on demand - tlv_data: Vec, -} -impl StateWithExtensionsOwned { - /// Unpack base state, leaving the extension data as a slice - /// - /// Fails if the base state is not initialized. - pub fn unpack(mut input: Vec) -> Result { - check_min_len_and_not_multisig(&input, S::LEN)?; - let mut rest = input.split_off(S::LEN); - let base = S::unpack(&input)?; - if let Some((account_type_index, tlv_start_index)) = type_and_tlv_indices::(&rest)? { - // type_and_tlv_indices() checks that returned indexes are within range - let account_type = AccountType::try_from(rest[account_type_index]) - .map_err(|_| ProgramError::InvalidAccountData)?; - check_account_type::(account_type)?; - let tlv_data = rest.split_off(tlv_start_index); - Ok(Self { base, tlv_data }) - } else { - Ok(Self { - base, - tlv_data: vec![], - }) - } - } - - /// Unpack a portion of the TLV data as the desired type - pub fn get_extension(&self) -> Result<&V, ProgramError> { - get_extension::(&self.tlv_data) - } - - /// Iterates through the TLV entries, returning only the types - pub fn get_extension_types(&self) -> Result, ProgramError> { - get_extension_types(&self.tlv_data) - } -} - -/// Encapsulates immutable base state data (mint or account) with possible extensions -#[derive(Debug, PartialEq)] -pub struct StateWithExtensions<'data, S: BaseState> { - /// Unpacked base data - pub base: S, - /// Slice of data containing all TLV data, deserialized on demand - tlv_data: &'data [u8], -} -impl<'data, S: BaseState> StateWithExtensions<'data, S> { - /// Unpack base state, leaving the extension data as a slice - /// - /// Fails if the base state is not initialized. - pub fn unpack(input: &'data [u8]) -> Result { - check_min_len_and_not_multisig(input, S::LEN)?; - let (base_data, rest) = input.split_at(S::LEN); - let base = S::unpack(base_data)?; - if let Some((account_type_index, tlv_start_index)) = type_and_tlv_indices::(rest)? { - // type_and_tlv_indices() checks that returned indexes are within range - let account_type = AccountType::try_from(rest[account_type_index]) - .map_err(|_| ProgramError::InvalidAccountData)?; - check_account_type::(account_type)?; - Ok(Self { - base, - tlv_data: &rest[tlv_start_index..], - }) - } else { - Ok(Self { - base, - tlv_data: &[], - }) - } - } - - /// Unpack a portion of the TLV data as the desired type - pub fn get_extension(&self) -> Result<&V, ProgramError> { - get_extension::(self.tlv_data) - } - - /// Iterates through the TLV entries, returning only the types - pub fn get_extension_types(&self) -> Result, ProgramError> { - get_extension_types(self.tlv_data) - } -} - -/// Encapsulates mutable base state data (mint or account) with possible extensions -#[derive(Debug, PartialEq)] -pub struct StateWithExtensionsMut<'data, S: BaseState> { - /// Unpacked base data - pub base: S, - /// Raw base data - base_data: &'data mut [u8], - /// Writable account type - account_type: &'data mut [u8], - /// Slice of data containing all TLV data, deserialized on demand - tlv_data: &'data mut [u8], -} -impl<'data, S: BaseState> StateWithExtensionsMut<'data, S> { - /// Unpack base state, leaving the extension data as a mutable slice - /// - /// Fails if the base state is not initialized. - pub fn unpack(input: &'data mut [u8]) -> Result { - check_min_len_and_not_multisig(input, S::LEN)?; - let (base_data, rest) = input.split_at_mut(S::LEN); - let base = S::unpack(base_data)?; - if let Some((account_type_index, tlv_start_index)) = type_and_tlv_indices::(rest)? { - // type_and_tlv_indices() checks that returned indexes are within range - let account_type = AccountType::try_from(rest[account_type_index]) - .map_err(|_| ProgramError::InvalidAccountData)?; - check_account_type::(account_type)?; - let (account_type, tlv_data) = rest.split_at_mut(tlv_start_index); - Ok(Self { - base, - base_data, - account_type: &mut account_type[account_type_index..tlv_start_index], - tlv_data, - }) - } else { - Ok(Self { - base, - base_data, - account_type: &mut [], - tlv_data: &mut [], - }) - } - } - - /// Unpack an uninitialized base state, leaving the extension data as a mutable slice - /// - /// Fails if the base state has already been initialized. - pub fn unpack_uninitialized(input: &'data mut [u8]) -> Result { - check_min_len_and_not_multisig(input, S::LEN)?; - let (base_data, rest) = input.split_at_mut(S::LEN); - let base = S::unpack_unchecked(base_data)?; - if base.is_initialized() { - return Err(TokenError::AlreadyInUse.into()); - } - if let Some((account_type_index, tlv_start_index)) = type_and_tlv_indices::(rest)? { - // type_and_tlv_indices() checks that returned indexes are within range - let account_type = AccountType::try_from(rest[account_type_index]) - .map_err(|_| ProgramError::InvalidAccountData)?; - if account_type != AccountType::Uninitialized { - return Err(ProgramError::InvalidAccountData); - } - let (account_type, tlv_data) = rest.split_at_mut(tlv_start_index); - let state = Self { - base, - base_data, - account_type: &mut account_type[account_type_index..tlv_start_index], - tlv_data, - }; - if let Some(extension_type) = state.get_first_extension_type()? { - let account_type = extension_type.get_account_type(); - if account_type != S::ACCOUNT_TYPE { - return Err(TokenError::ExtensionBaseMismatch.into()); - } - } - Ok(state) - } else { - Ok(Self { - base, - base_data, - account_type: &mut [], - tlv_data: &mut [], - }) - } - } - - /// Unpack a portion of the TLV data as the desired type that allows modifying the type - pub fn get_extension_mut(&mut self) -> Result<&mut V, ProgramError> { - if V::TYPE.get_account_type() != S::ACCOUNT_TYPE { - return Err(ProgramError::InvalidAccountData); - } - let TlvIndices { - type_start, - length_start, - value_start, - } = get_extension_indices::(self.tlv_data, false)?; - - if self.tlv_data[type_start..].len() < V::TYPE.get_tlv_len() { - return Err(ProgramError::InvalidAccountData); - } - let length = pod_from_bytes::(&self.tlv_data[length_start..value_start])?; - let value_end = value_start.saturating_add(usize::from(*length)); - pod_from_bytes_mut::(&mut self.tlv_data[value_start..value_end]) - } - - /// Unpack a portion of the TLV data as the desired type - pub fn get_extension(&self) -> Result<&V, ProgramError> { - if V::TYPE.get_account_type() != S::ACCOUNT_TYPE { - return Err(ProgramError::InvalidAccountData); - } - let TlvIndices { - type_start, - length_start, - value_start, - } = get_extension_indices::(self.tlv_data, false)?; - - if self.tlv_data[type_start..].len() < V::TYPE.get_tlv_len() { - return Err(ProgramError::InvalidAccountData); - } - let length = pod_from_bytes::(&self.tlv_data[length_start..value_start])?; - let value_end = value_start.saturating_add(usize::from(*length)); - pod_from_bytes::(&self.tlv_data[value_start..value_end]) - } - - /// Packs base state data into the base data portion - pub fn pack_base(&mut self) { - S::pack_into_slice(&self.base, self.base_data); - } - - /// Packs the default extension data into an open slot if not already found in the - /// data buffer. If extension is already found in the buffer, it overwrites the existing - /// extension with the default state if `overwrite` is set. If extension found, but - /// `overwrite` is not set, it returns error. - pub fn init_extension( - &mut self, - overwrite: bool, - ) -> Result<&mut V, ProgramError> { - if V::TYPE.get_account_type() != S::ACCOUNT_TYPE { - return Err(ProgramError::InvalidAccountData); - } - let TlvIndices { - type_start, - length_start, - value_start, - } = get_extension_indices::(self.tlv_data, true)?; - - if self.tlv_data[type_start..].len() < V::TYPE.get_tlv_len() { - return Err(ProgramError::InvalidAccountData); - } - let extension_type = ExtensionType::try_from(&self.tlv_data[type_start..length_start])?; - - if extension_type == ExtensionType::Uninitialized || overwrite { - // write extension type - let extension_type_array: [u8; 2] = V::TYPE.into(); - let extension_type_ref = &mut self.tlv_data[type_start..length_start]; - extension_type_ref.copy_from_slice(&extension_type_array); - // write length - let length_ref = - pod_from_bytes_mut::(&mut self.tlv_data[length_start..value_start])?; - // maybe this becomes smarter later for dynamically sized extensions - let length = pod_get_packed_len::(); - *length_ref = Length::try_from(length).unwrap(); - - let value_end = value_start.saturating_add(length); - let extension_ref = - pod_from_bytes_mut::(&mut self.tlv_data[value_start..value_end])?; - *extension_ref = V::default(); - Ok(extension_ref) - } else { - // extension is already initialized, but no overwrite permission - Err(TokenError::ExtensionAlreadyInitialized.into()) - } - } - - /// If `extension_type` is an Account-associated ExtensionType that requires initialization on - /// InitializeAccount, this method packs the default relevant Extension of an ExtensionType - /// into an open slot if not already found in the data buffer, otherwise overwrites the - /// existing extension with the default state. For all other ExtensionTypes, this is a no-op. - pub fn init_account_extension_from_type( - &mut self, - extension_type: ExtensionType, - ) -> Result<(), ProgramError> { - if extension_type.get_account_type() != AccountType::Account { - return Ok(()); - } - match extension_type { - ExtensionType::TransferFeeAmount => { - self.init_extension::(true).map(|_| ()) - } - // ConfidentialTransfers are currently opt-in only, so this is a no-op for extra safety - // on InitializeAccount - ExtensionType::ConfidentialTransferAccount => Ok(()), - #[cfg(test)] - ExtensionType::AccountPaddingTest => { - self.init_extension::(true).map(|_| ()) - } - _ => unreachable!(), - } - } - - /// Write the account type into the buffer, done during the base - /// state initialization - /// Noops if there is no room for an extension in the account, needed for - /// pure base mints / accounts. - pub fn init_account_type(&mut self) -> Result<(), ProgramError> { - if !self.account_type.is_empty() { - if let Some(extension_type) = self.get_first_extension_type()? { - let account_type = extension_type.get_account_type(); - if account_type != S::ACCOUNT_TYPE { - return Err(TokenError::ExtensionBaseMismatch.into()); - } - } - self.account_type[0] = S::ACCOUNT_TYPE.into(); - } - Ok(()) - } - - /// Iterates through the TLV entries, returning only the types - pub fn get_extension_types(&self) -> Result, ProgramError> { - get_extension_types(self.tlv_data) - } - - fn get_first_extension_type(&self) -> Result, ProgramError> { - get_first_extension_type(self.tlv_data) - } -} - -/// If AccountType is uninitialized, set it to the BaseState's ACCOUNT_TYPE; -/// if AccountType is already set, check is set correctly for BaseState -/// This method assumes that the `base_data` has already been packed with data of the desired type. -pub fn set_account_type(input: &mut [u8]) -> Result<(), ProgramError> { - check_min_len_and_not_multisig(input, S::LEN)?; - let (base_data, rest) = input.split_at_mut(S::LEN); - if S::ACCOUNT_TYPE == AccountType::Account && !is_initialized_account(base_data)? { - return Err(ProgramError::InvalidAccountData); - } - if let Some((account_type_index, _tlv_start_index)) = type_and_tlv_indices::(rest)? { - let mut account_type = AccountType::try_from(rest[account_type_index]) - .map_err(|_| ProgramError::InvalidAccountData)?; - if account_type == AccountType::Uninitialized { - rest[account_type_index] = S::ACCOUNT_TYPE.into(); - account_type = S::ACCOUNT_TYPE; - } - check_account_type::(account_type)?; - Ok(()) - } else { - Err(ProgramError::InvalidAccountData) - } -} - -/// Different kinds of accounts. Note that `Mint`, `Account`, and `Multisig` types -/// are determined exclusively by the size of the account, and are not included in -/// the account data. `AccountType` is only included if extensions have been -/// initialized. -#[repr(u8)] -#[derive(Clone, Copy, Debug, PartialEq, TryFromPrimitive, IntoPrimitive)] -pub enum AccountType { - /// Marker for 0 data - Uninitialized, - /// Mint account with additional extensions - Mint, - /// Token holding account with additional extensions - Account, -} -impl Default for AccountType { - fn default() -> Self { - Self::Uninitialized - } -} - -/// Extensions that can be applied to mints or accounts. Mint extensions must only be -/// applied to mint accounts, and account extensions must only be applied to token holding -/// accounts. -#[repr(u16)] -#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))] -#[derive(Clone, Copy, Debug, PartialEq, TryFromPrimitive, IntoPrimitive)] -pub enum ExtensionType { - /// Used as padding if the account size would otherwise be 355, same as a multisig - Uninitialized, - /// Includes transfer fee rate info and accompanying authorities to withdraw and set the fee - TransferFeeConfig, - /// Includes withheld transfer fees - TransferFeeAmount, - /// Includes an optional mint close authority - MintCloseAuthority, - /// Auditor configuration for confidential transfers - ConfidentialTransferMint, - /// State for confidential transfers - ConfidentialTransferAccount, - /// Specifies the default Account::state for new Accounts - DefaultAccountState, - /// Indicates that the Account owner authority cannot be changed - ImmutableOwner, - /// Require inbound transfers to have memo - MemoTransfer, - /// Indicates that the tokens from this mint can't be transfered - NonTransferable, - /// Tokens accrue interest over time, - InterestBearingConfig, - /// Padding extension used to make an account exactly Multisig::LEN, used for testing - #[cfg(test)] - AccountPaddingTest = u16::MAX - 1, - /// Padding extension used to make a mint exactly Multisig::LEN, used for testing - #[cfg(test)] - MintPaddingTest = u16::MAX, -} -impl TryFrom<&[u8]> for ExtensionType { - type Error = ProgramError; - fn try_from(a: &[u8]) -> Result { - Self::try_from(u16::from_le_bytes( - a.try_into().map_err(|_| ProgramError::InvalidAccountData)?, - )) - .map_err(|_| ProgramError::InvalidAccountData) - } -} -impl From for [u8; 2] { - fn from(a: ExtensionType) -> Self { - u16::from(a).to_le_bytes() - } -} -impl ExtensionType { - /// Get the data length of the type associated with the enum - pub fn get_type_len(&self) -> usize { - match self { - ExtensionType::Uninitialized => 0, - ExtensionType::TransferFeeConfig => pod_get_packed_len::(), - ExtensionType::TransferFeeAmount => pod_get_packed_len::(), - ExtensionType::MintCloseAuthority => pod_get_packed_len::(), - ExtensionType::ImmutableOwner => pod_get_packed_len::(), - ExtensionType::ConfidentialTransferMint => { - pod_get_packed_len::() - } - ExtensionType::ConfidentialTransferAccount => { - pod_get_packed_len::() - } - ExtensionType::DefaultAccountState => pod_get_packed_len::(), - ExtensionType::MemoTransfer => pod_get_packed_len::(), - ExtensionType::NonTransferable => pod_get_packed_len::(), - ExtensionType::InterestBearingConfig => pod_get_packed_len::(), - #[cfg(test)] - ExtensionType::AccountPaddingTest => pod_get_packed_len::(), - #[cfg(test)] - ExtensionType::MintPaddingTest => pod_get_packed_len::(), - } - } - - /// Get the TLV length for an ExtensionType - fn get_tlv_len(&self) -> usize { - self.get_type_len() - .saturating_add(size_of::()) - .saturating_add(pod_get_packed_len::()) - } - - /// Get the TLV length for a set of ExtensionTypes - fn get_total_tlv_len(extension_types: &[Self]) -> usize { - // dedupe extensions - let mut extensions = vec![]; - for extension_type in extension_types { - if !extensions.contains(&extension_type) { - extensions.push(extension_type); - } - } - let tlv_len: usize = extensions.iter().map(|e| e.get_tlv_len()).sum(); - if tlv_len - == Multisig::LEN - .saturating_sub(BASE_ACCOUNT_LENGTH) - .saturating_sub(size_of::()) - { - tlv_len.saturating_add(size_of::()) - } else { - tlv_len - } - } - - /// Get the required account data length for the given ExtensionTypes - pub fn get_account_len(extension_types: &[Self]) -> usize { - if extension_types.is_empty() { - S::LEN - } else { - let extension_size = Self::get_total_tlv_len(extension_types); - extension_size - .saturating_add(BASE_ACCOUNT_LENGTH) - .saturating_add(size_of::()) - } - } - - /// Get the associated account type - pub fn get_account_type(&self) -> AccountType { - match self { - ExtensionType::Uninitialized => AccountType::Uninitialized, - ExtensionType::TransferFeeConfig - | ExtensionType::MintCloseAuthority - | ExtensionType::ConfidentialTransferMint - | ExtensionType::DefaultAccountState - | ExtensionType::NonTransferable - | ExtensionType::InterestBearingConfig => AccountType::Mint, - ExtensionType::ImmutableOwner - | ExtensionType::TransferFeeAmount - | ExtensionType::ConfidentialTransferAccount - | ExtensionType::MemoTransfer => AccountType::Account, - #[cfg(test)] - ExtensionType::AccountPaddingTest => AccountType::Account, - #[cfg(test)] - ExtensionType::MintPaddingTest => AccountType::Mint, - } - } - - /// Based on a set of AccountType::Mint ExtensionTypes, get the list of AccountType::Account - /// ExtensionTypes required on InitializeAccount - pub fn get_required_init_account_extensions(mint_extension_types: &[Self]) -> Vec { - let mut account_extension_types = vec![]; - for extension_type in mint_extension_types { - #[allow(clippy::single_match)] - match extension_type { - ExtensionType::TransferFeeConfig => { - account_extension_types.push(ExtensionType::TransferFeeAmount); - } - #[cfg(test)] - ExtensionType::MintPaddingTest => { - account_extension_types.push(ExtensionType::AccountPaddingTest); - } - _ => {} - } - } - account_extension_types - } -} - -/// Trait for base states, specifying the associated enum -pub trait BaseState: Pack + IsInitialized { - /// Associated extension type enum, checked at the start of TLV entries - const ACCOUNT_TYPE: AccountType; -} -impl BaseState for Account { - const ACCOUNT_TYPE: AccountType = AccountType::Account; -} -impl BaseState for Mint { - const ACCOUNT_TYPE: AccountType = AccountType::Mint; -} - -/// Trait to be implemented by all extension states, specifying which extension -/// and account type they are associated with -pub trait Extension: Pod + Default { - /// Associated extension type enum, checked at the start of TLV entries - const TYPE: ExtensionType; -} - -/// Padding a mint account to be exactly Multisig::LEN. -/// We need to pad 185 bytes, since Multisig::LEN = 355, Account::LEN = 165, -/// size_of AccountType = 1, size_of ExtensionType = 2, size_of Length = 2. -/// 355 - 165 - 1 - 2 - 2 = 185 -#[cfg(test)] -#[repr(C)] -#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)] -pub struct MintPaddingTest { - /// Largest value under 185 that implements Pod - pub padding1: [u8; 128], - /// Largest value under 57 that implements Pod - pub padding2: [u8; 48], - /// Exact value needed to finish the padding - pub padding3: [u8; 9], -} -#[cfg(test)] -impl Extension for MintPaddingTest { - const TYPE: ExtensionType = ExtensionType::MintPaddingTest; -} -#[cfg(test)] -impl Default for MintPaddingTest { - fn default() -> Self { - Self { - padding1: [1; 128], - padding2: [2; 48], - padding3: [3; 9], - } - } -} -/// Account version of the MintPadding -#[cfg(test)] -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] -pub struct AccountPaddingTest(MintPaddingTest); -#[cfg(test)] -impl Extension for AccountPaddingTest { - const TYPE: ExtensionType = ExtensionType::AccountPaddingTest; -} - -#[cfg(test)] -mod test { - use { - super::*, - crate::state::test::{TEST_ACCOUNT, TEST_ACCOUNT_SLICE, TEST_MINT, TEST_MINT_SLICE}, - solana_program::pubkey::Pubkey, - transfer_fee::test::test_transfer_fee_config, - }; - - const MINT_WITH_EXTENSION: &[u8] = &[ - // base mint - 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 42, 0, 0, 0, 0, 0, 0, 0, 7, 1, 1, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // padding - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // account type - 1, // extension type - 3, 0, // length - 32, 0, // data - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, - ]; - - #[test] - fn unpack_opaque_buffer() { - let state = StateWithExtensions::::unpack(MINT_WITH_EXTENSION).unwrap(); - assert_eq!(state.base, TEST_MINT); - let extension = state.get_extension::().unwrap(); - let close_authority = OptionalNonZeroPubkey::try_from(Some(Pubkey::new(&[1; 32]))).unwrap(); - assert_eq!(extension.close_authority, close_authority); - assert_eq!( - state.get_extension::(), - Err(ProgramError::InvalidAccountData) - ); - assert_eq!( - StateWithExtensions::::unpack(MINT_WITH_EXTENSION), - Err(ProgramError::InvalidAccountData) - ); - - let state = StateWithExtensions::::unpack(TEST_MINT_SLICE).unwrap(); - assert_eq!(state.base, TEST_MINT); - - let mut test_mint = TEST_MINT_SLICE.to_vec(); - let state = StateWithExtensionsMut::::unpack(&mut test_mint).unwrap(); - assert_eq!(state.base, TEST_MINT); - } - - #[test] - fn fail_unpack_opaque_buffer() { - // input buffer too small - let mut buffer = vec![0, 3]; - assert_eq!( - StateWithExtensions::::unpack(&buffer), - Err(ProgramError::InvalidAccountData) - ); - assert_eq!( - StateWithExtensionsMut::::unpack(&mut buffer), - Err(ProgramError::InvalidAccountData) - ); - assert_eq!( - StateWithExtensionsMut::::unpack_uninitialized(&mut buffer), - Err(ProgramError::InvalidAccountData) - ); - - // tweak the account type - let mut buffer = MINT_WITH_EXTENSION.to_vec(); - buffer[BASE_ACCOUNT_LENGTH] = 3; - assert_eq!( - StateWithExtensions::::unpack(&buffer), - Err(ProgramError::InvalidAccountData) - ); - - // clear the mint initialized byte - let mut buffer = MINT_WITH_EXTENSION.to_vec(); - buffer[45] = 0; - assert_eq!( - StateWithExtensions::::unpack(&buffer), - Err(ProgramError::UninitializedAccount) - ); - - // tweak the padding - let mut buffer = MINT_WITH_EXTENSION.to_vec(); - buffer[Mint::LEN] = 100; - assert_eq!( - StateWithExtensions::::unpack(&buffer), - Err(ProgramError::InvalidAccountData) - ); - - // tweak the extension type - let mut buffer = MINT_WITH_EXTENSION.to_vec(); - buffer[BASE_ACCOUNT_LENGTH + 1] = 2; - let state = StateWithExtensions::::unpack(&buffer).unwrap(); - assert_eq!( - state.get_extension::(), - Err(ProgramError::Custom( - TokenError::ExtensionTypeMismatch as u32 - )) - ); - - // tweak the length, too big - let mut buffer = MINT_WITH_EXTENSION.to_vec(); - buffer[BASE_ACCOUNT_LENGTH + 3] = 100; - let state = StateWithExtensions::::unpack(&buffer).unwrap(); - assert_eq!( - state.get_extension::(), - Err(ProgramError::InvalidAccountData) - ); - - // tweak the length, too small - let mut buffer = MINT_WITH_EXTENSION.to_vec(); - buffer[BASE_ACCOUNT_LENGTH + 3] = 10; - let state = StateWithExtensions::::unpack(&buffer).unwrap(); - assert_eq!( - state.get_extension::(), - Err(ProgramError::InvalidAccountData) - ); - } - - #[test] - fn mint_with_extension_pack_unpack() { - let mint_size = ExtensionType::get_account_len::(&[ - ExtensionType::MintCloseAuthority, - ExtensionType::TransferFeeConfig, - ]); - let mut buffer = vec![0; mint_size]; - - // fail unpack - assert_eq!( - StateWithExtensionsMut::::unpack(&mut buffer), - Err(ProgramError::UninitializedAccount), - ); - - let mut state = StateWithExtensionsMut::::unpack_uninitialized(&mut buffer).unwrap(); - // fail init account extension - assert_eq!( - state.init_extension::(true), - Err(ProgramError::InvalidAccountData), - ); - - // success write extension - let close_authority = OptionalNonZeroPubkey::try_from(Some(Pubkey::new(&[1; 32]))).unwrap(); - let extension = state.init_extension::(true).unwrap(); - extension.close_authority = close_authority; - assert_eq!( - &state.get_extension_types().unwrap(), - &[ExtensionType::MintCloseAuthority] - ); - - // fail init extension when already initialized - assert_eq!( - state.init_extension::(false), - Err(ProgramError::Custom( - TokenError::ExtensionAlreadyInitialized as u32 - )) - ); - - // fail unpack as account, a mint extension was written - assert_eq!( - StateWithExtensionsMut::::unpack_uninitialized(&mut buffer), - Err(ProgramError::Custom( - TokenError::ExtensionBaseMismatch as u32 - )) - ); - - // fail unpack again, still no base data - assert_eq!( - StateWithExtensionsMut::::unpack(&mut buffer.clone()), - Err(ProgramError::UninitializedAccount), - ); - - // write base mint - let mut state = StateWithExtensionsMut::::unpack_uninitialized(&mut buffer).unwrap(); - state.base = TEST_MINT; - state.pack_base(); - state.init_account_type().unwrap(); - - // check raw buffer - let mut expect = TEST_MINT_SLICE.to_vec(); - expect.extend_from_slice(&[0; BASE_ACCOUNT_LENGTH - Mint::LEN]); // padding - expect.push(AccountType::Mint.into()); - expect.extend_from_slice(&(ExtensionType::MintCloseAuthority as u16).to_le_bytes()); - expect - .extend_from_slice(&(pod_get_packed_len::() as u16).to_le_bytes()); - expect.extend_from_slice(&[1; 32]); // data - expect.extend_from_slice(&[0; size_of::()]); - expect.extend_from_slice(&[0; size_of::()]); - expect.extend_from_slice(&[0; size_of::()]); - assert_eq!(expect, buffer); - - // unpack uninitialized will now fail because the Mint is now initialized - assert_eq!( - StateWithExtensionsMut::::unpack_uninitialized(&mut buffer.clone()), - Err(TokenError::AlreadyInUse.into()), - ); - - // check unpacking - let mut state = StateWithExtensionsMut::::unpack(&mut buffer).unwrap(); - - // update base - state.base = TEST_MINT; - state.base.supply += 100; - state.pack_base(); - - // check unpacking - let mut unpacked_extension = state.get_extension_mut::().unwrap(); - assert_eq!(*unpacked_extension, MintCloseAuthority { close_authority }); - - // update extension - let close_authority = OptionalNonZeroPubkey::try_from(None).unwrap(); - unpacked_extension.close_authority = close_authority; - - // check updates are propagated - let base = state.base; - let state = StateWithExtensions::::unpack(&buffer).unwrap(); - assert_eq!(state.base, base); - let unpacked_extension = state.get_extension::().unwrap(); - assert_eq!(*unpacked_extension, MintCloseAuthority { close_authority }); - - // check raw buffer - let mut expect = vec![0; Mint::LEN]; - Mint::pack_into_slice(&base, &mut expect); - expect.extend_from_slice(&[0; BASE_ACCOUNT_LENGTH - Mint::LEN]); // padding - expect.push(AccountType::Mint.into()); - expect.extend_from_slice(&(ExtensionType::MintCloseAuthority as u16).to_le_bytes()); - expect - .extend_from_slice(&(pod_get_packed_len::() as u16).to_le_bytes()); - expect.extend_from_slice(&[0; 32]); - expect.extend_from_slice(&[0; size_of::()]); - expect.extend_from_slice(&[0; size_of::()]); - expect.extend_from_slice(&[0; size_of::()]); - assert_eq!(expect, buffer); - - // fail unpack as an account - assert_eq!( - StateWithExtensions::::unpack(&buffer), - Err(ProgramError::InvalidAccountData), - ); - - let mut state = StateWithExtensionsMut::::unpack(&mut buffer).unwrap(); - // init one more extension - let mint_transfer_fee = test_transfer_fee_config(); - let new_extension = state.init_extension::(true).unwrap(); - new_extension.transfer_fee_config_authority = - mint_transfer_fee.transfer_fee_config_authority; - new_extension.withdraw_withheld_authority = mint_transfer_fee.withdraw_withheld_authority; - new_extension.withheld_amount = mint_transfer_fee.withheld_amount; - new_extension.older_transfer_fee = mint_transfer_fee.older_transfer_fee; - new_extension.newer_transfer_fee = mint_transfer_fee.newer_transfer_fee; - - assert_eq!( - &state.get_extension_types().unwrap(), - &[ - ExtensionType::MintCloseAuthority, - ExtensionType::TransferFeeConfig - ] - ); - - // check raw buffer - let mut expect = vec![0; Mint::LEN]; - Mint::pack_into_slice(&base, &mut expect); - expect.extend_from_slice(&[0; BASE_ACCOUNT_LENGTH - Mint::LEN]); // padding - expect.push(AccountType::Mint.into()); - expect.extend_from_slice(&(ExtensionType::MintCloseAuthority as u16).to_le_bytes()); - expect - .extend_from_slice(&(pod_get_packed_len::() as u16).to_le_bytes()); - expect.extend_from_slice(&[0; 32]); // data - expect.extend_from_slice(&(ExtensionType::TransferFeeConfig as u16).to_le_bytes()); - expect.extend_from_slice(&(pod_get_packed_len::() as u16).to_le_bytes()); - expect.extend_from_slice(pod_bytes_of(&mint_transfer_fee)); - assert_eq!(expect, buffer); - - // fail to init one more extension that does not fit - let mut state = StateWithExtensionsMut::::unpack(&mut buffer).unwrap(); - assert_eq!( - state.init_extension::(true), - Err(ProgramError::InvalidAccountData), - ); - } - - #[test] - fn mint_extension_any_order() { - let mint_size = ExtensionType::get_account_len::(&[ - ExtensionType::MintCloseAuthority, - ExtensionType::TransferFeeConfig, - ]); - let mut buffer = vec![0; mint_size]; - - let mut state = StateWithExtensionsMut::::unpack_uninitialized(&mut buffer).unwrap(); - // write extensions - let close_authority = OptionalNonZeroPubkey::try_from(Some(Pubkey::new(&[1; 32]))).unwrap(); - let extension = state.init_extension::(true).unwrap(); - extension.close_authority = close_authority; - - let mint_transfer_fee = test_transfer_fee_config(); - let extension = state.init_extension::(true).unwrap(); - extension.transfer_fee_config_authority = mint_transfer_fee.transfer_fee_config_authority; - extension.withdraw_withheld_authority = mint_transfer_fee.withdraw_withheld_authority; - extension.withheld_amount = mint_transfer_fee.withheld_amount; - extension.older_transfer_fee = mint_transfer_fee.older_transfer_fee; - extension.newer_transfer_fee = mint_transfer_fee.newer_transfer_fee; - - assert_eq!( - &state.get_extension_types().unwrap(), - &[ - ExtensionType::MintCloseAuthority, - ExtensionType::TransferFeeConfig - ] - ); - - // write base mint - let mut state = StateWithExtensionsMut::::unpack_uninitialized(&mut buffer).unwrap(); - state.base = TEST_MINT; - state.pack_base(); - state.init_account_type().unwrap(); - - let mut other_buffer = vec![0; mint_size]; - let mut state = - StateWithExtensionsMut::::unpack_uninitialized(&mut other_buffer).unwrap(); - - // write base mint - state.base = TEST_MINT; - state.pack_base(); - state.init_account_type().unwrap(); - - // write extensions in a different order - let mint_transfer_fee = test_transfer_fee_config(); - let extension = state.init_extension::(true).unwrap(); - extension.transfer_fee_config_authority = mint_transfer_fee.transfer_fee_config_authority; - extension.withdraw_withheld_authority = mint_transfer_fee.withdraw_withheld_authority; - extension.withheld_amount = mint_transfer_fee.withheld_amount; - extension.older_transfer_fee = mint_transfer_fee.older_transfer_fee; - extension.newer_transfer_fee = mint_transfer_fee.newer_transfer_fee; - - let close_authority = OptionalNonZeroPubkey::try_from(Some(Pubkey::new(&[1; 32]))).unwrap(); - let extension = state.init_extension::(true).unwrap(); - extension.close_authority = close_authority; - - assert_eq!( - &state.get_extension_types().unwrap(), - &[ - ExtensionType::TransferFeeConfig, - ExtensionType::MintCloseAuthority - ] - ); - - // buffers are NOT the same because written in a different order - assert_ne!(buffer, other_buffer); - let state = StateWithExtensions::::unpack(&buffer).unwrap(); - let other_state = StateWithExtensions::::unpack(&other_buffer).unwrap(); - - // BUT mint and extensions are the same - assert_eq!( - state.get_extension::().unwrap(), - other_state.get_extension::().unwrap() - ); - assert_eq!( - state.get_extension::().unwrap(), - other_state.get_extension::().unwrap() - ); - assert_eq!(state.base, other_state.base); - } - - #[test] - fn mint_with_multisig_len() { - let mut buffer = vec![0; Multisig::LEN]; - assert_eq!( - StateWithExtensionsMut::::unpack_uninitialized(&mut buffer), - Err(ProgramError::InvalidAccountData), - ); - let mint_size = ExtensionType::get_account_len::(&[ExtensionType::MintPaddingTest]); - assert_eq!(mint_size, Multisig::LEN + size_of::()); - let mut buffer = vec![0; mint_size]; - - // write base mint - let mut state = StateWithExtensionsMut::::unpack_uninitialized(&mut buffer).unwrap(); - state.base = TEST_MINT; - state.pack_base(); - state.init_account_type().unwrap(); - - // write padding - let extension = state.init_extension::(true).unwrap(); - extension.padding1 = [1; 128]; - extension.padding2 = [1; 48]; - extension.padding3 = [1; 9]; - - assert_eq!( - &state.get_extension_types().unwrap(), - &[ExtensionType::MintPaddingTest] - ); - - // check raw buffer - let mut expect = TEST_MINT_SLICE.to_vec(); - expect.extend_from_slice(&[0; BASE_ACCOUNT_LENGTH - Mint::LEN]); // padding - expect.push(AccountType::Mint.into()); - expect.extend_from_slice(&(ExtensionType::MintPaddingTest as u16).to_le_bytes()); - expect.extend_from_slice(&(pod_get_packed_len::() as u16).to_le_bytes()); - expect.extend_from_slice(&vec![1; pod_get_packed_len::()]); - expect.extend_from_slice(&(ExtensionType::Uninitialized as u16).to_le_bytes()); - assert_eq!(expect, buffer); - } - - #[test] - fn account_with_extension_pack_unpack() { - let account_size = - ExtensionType::get_account_len::(&[ExtensionType::TransferFeeAmount]); - let mut buffer = vec![0; account_size]; - - // fail unpack - assert_eq!( - StateWithExtensionsMut::::unpack(&mut buffer), - Err(ProgramError::UninitializedAccount), - ); - - let mut state = - StateWithExtensionsMut::::unpack_uninitialized(&mut buffer).unwrap(); - // fail init mint extension - assert_eq!( - state.init_extension::(true), - Err(ProgramError::InvalidAccountData), - ); - // success write extension - let withheld_amount = PodU64::from(u64::MAX); - let extension = state.init_extension::(true).unwrap(); - extension.withheld_amount = withheld_amount; - - assert_eq!( - &state.get_extension_types().unwrap(), - &[ExtensionType::TransferFeeAmount] - ); - - // fail unpack again, still no base data - assert_eq!( - StateWithExtensionsMut::::unpack(&mut buffer.clone()), - Err(ProgramError::UninitializedAccount), - ); - - // write base account - let mut state = - StateWithExtensionsMut::::unpack_uninitialized(&mut buffer).unwrap(); - state.base = TEST_ACCOUNT; - state.pack_base(); - state.init_account_type().unwrap(); - let base = state.base; - - // check raw buffer - let mut expect = TEST_ACCOUNT_SLICE.to_vec(); - expect.push(AccountType::Account.into()); - expect.extend_from_slice(&(ExtensionType::TransferFeeAmount as u16).to_le_bytes()); - expect.extend_from_slice(&(pod_get_packed_len::() as u16).to_le_bytes()); - expect.extend_from_slice(&u64::from(withheld_amount).to_le_bytes()); - assert_eq!(expect, buffer); - - // check unpacking - let mut state = StateWithExtensionsMut::::unpack(&mut buffer).unwrap(); - assert_eq!(state.base, base); - assert_eq!( - &state.get_extension_types().unwrap(), - &[ExtensionType::TransferFeeAmount] - ); - - // update base - state.base = TEST_ACCOUNT; - state.base.amount += 100; - state.pack_base(); - - // check unpacking - let mut unpacked_extension = state.get_extension_mut::().unwrap(); - assert_eq!(*unpacked_extension, TransferFeeAmount { withheld_amount }); - - // update extension - let withheld_amount = PodU64::from(u32::MAX as u64); - unpacked_extension.withheld_amount = withheld_amount; - - // check updates are propagated - let base = state.base; - let state = StateWithExtensions::::unpack(&buffer).unwrap(); - assert_eq!(state.base, base); - let unpacked_extension = state.get_extension::().unwrap(); - assert_eq!(*unpacked_extension, TransferFeeAmount { withheld_amount }); - - // check raw buffer - let mut expect = vec![0; Account::LEN]; - Account::pack_into_slice(&base, &mut expect); - expect.push(AccountType::Account.into()); - expect.extend_from_slice(&(ExtensionType::TransferFeeAmount as u16).to_le_bytes()); - expect.extend_from_slice(&(pod_get_packed_len::() as u16).to_le_bytes()); - expect.extend_from_slice(&u64::from(withheld_amount).to_le_bytes()); - assert_eq!(expect, buffer); - - // fail unpack as a mint - assert_eq!( - StateWithExtensions::::unpack(&buffer), - Err(ProgramError::InvalidAccountData), - ); - } - - #[test] - fn account_with_multisig_len() { - let mut buffer = vec![0; Multisig::LEN]; - assert_eq!( - StateWithExtensionsMut::::unpack_uninitialized(&mut buffer), - Err(ProgramError::InvalidAccountData), - ); - let account_size = - ExtensionType::get_account_len::(&[ExtensionType::AccountPaddingTest]); - assert_eq!(account_size, Multisig::LEN + size_of::()); - let mut buffer = vec![0; account_size]; - - // write base account - let mut state = - StateWithExtensionsMut::::unpack_uninitialized(&mut buffer).unwrap(); - state.base = TEST_ACCOUNT; - state.pack_base(); - state.init_account_type().unwrap(); - - // write padding - let extension = state.init_extension::(true).unwrap(); - extension.0.padding1 = [2; 128]; - extension.0.padding2 = [2; 48]; - extension.0.padding3 = [2; 9]; - - assert_eq!( - &state.get_extension_types().unwrap(), - &[ExtensionType::AccountPaddingTest] - ); - - // check raw buffer - let mut expect = TEST_ACCOUNT_SLICE.to_vec(); - expect.push(AccountType::Account.into()); - expect.extend_from_slice(&(ExtensionType::AccountPaddingTest as u16).to_le_bytes()); - expect - .extend_from_slice(&(pod_get_packed_len::() as u16).to_le_bytes()); - expect.extend_from_slice(&vec![2; pod_get_packed_len::()]); - expect.extend_from_slice(&(ExtensionType::Uninitialized as u16).to_le_bytes()); - assert_eq!(expect, buffer); - } - - #[test] - fn test_set_account_type() { - // account with buffer big enough for AccountType and Extension - let mut buffer = TEST_ACCOUNT_SLICE.to_vec(); - let needed_len = - ExtensionType::get_account_len::(&[ExtensionType::ImmutableOwner]) - - buffer.len(); - buffer.append(&mut vec![0; needed_len]); - let err = StateWithExtensionsMut::::unpack(&mut buffer).unwrap_err(); - assert_eq!(err, ProgramError::InvalidAccountData); - set_account_type::(&mut buffer).unwrap(); - // unpack is viable after manual set_account_type - let mut state = StateWithExtensionsMut::::unpack(&mut buffer).unwrap(); - assert_eq!(state.base, TEST_ACCOUNT); - assert_eq!(state.account_type[0], AccountType::Account as u8); - state.init_extension::(true).unwrap(); // just confirming initialization works - - // account with buffer big enough for AccountType only - let mut buffer = TEST_ACCOUNT_SLICE.to_vec(); - buffer.append(&mut vec![0; 2]); - let err = StateWithExtensionsMut::::unpack(&mut buffer).unwrap_err(); - assert_eq!(err, ProgramError::InvalidAccountData); - set_account_type::(&mut buffer).unwrap(); - // unpack is viable after manual set_account_type - let state = StateWithExtensionsMut::::unpack(&mut buffer).unwrap(); - assert_eq!(state.base, TEST_ACCOUNT); - assert_eq!(state.account_type[0], AccountType::Account as u8); - - // account with AccountType already set => noop - let mut buffer = TEST_ACCOUNT_SLICE.to_vec(); - buffer.append(&mut vec![2, 0]); - let _ = StateWithExtensionsMut::::unpack(&mut buffer).unwrap(); - set_account_type::(&mut buffer).unwrap(); - let state = StateWithExtensionsMut::::unpack(&mut buffer).unwrap(); - assert_eq!(state.base, TEST_ACCOUNT); - assert_eq!(state.account_type[0], AccountType::Account as u8); - - // account with wrong AccountType fails - let mut buffer = TEST_ACCOUNT_SLICE.to_vec(); - buffer.append(&mut vec![1, 0]); - let err = StateWithExtensionsMut::::unpack(&mut buffer).unwrap_err(); - assert_eq!(err, ProgramError::InvalidAccountData); - let err = set_account_type::(&mut buffer).unwrap_err(); - assert_eq!(err, ProgramError::InvalidAccountData); - - // mint with buffer big enough for AccountType and Extension - let mut buffer = TEST_MINT_SLICE.to_vec(); - let needed_len = - ExtensionType::get_account_len::(&[ExtensionType::MintCloseAuthority]) - - buffer.len(); - buffer.append(&mut vec![0; needed_len]); - let err = StateWithExtensionsMut::::unpack(&mut buffer).unwrap_err(); - assert_eq!(err, ProgramError::InvalidAccountData); - set_account_type::(&mut buffer).unwrap(); - // unpack is viable after manual set_account_type - let mut state = StateWithExtensionsMut::::unpack(&mut buffer).unwrap(); - assert_eq!(state.base, TEST_MINT); - assert_eq!(state.account_type[0], AccountType::Mint as u8); - state.init_extension::(true).unwrap(); - - // mint with buffer big enough for AccountType only - let mut buffer = TEST_MINT_SLICE.to_vec(); - buffer.append(&mut vec![0; Account::LEN - Mint::LEN]); - buffer.append(&mut vec![0; 2]); - let err = StateWithExtensionsMut::::unpack(&mut buffer).unwrap_err(); - assert_eq!(err, ProgramError::InvalidAccountData); - set_account_type::(&mut buffer).unwrap(); - // unpack is viable after manual set_account_type - let state = StateWithExtensionsMut::::unpack(&mut buffer).unwrap(); - assert_eq!(state.base, TEST_MINT); - assert_eq!(state.account_type[0], AccountType::Mint as u8); - - // mint with AccountType already set => noop - let mut buffer = TEST_MINT_SLICE.to_vec(); - buffer.append(&mut vec![0; Account::LEN - Mint::LEN]); - buffer.append(&mut vec![1, 0]); - set_account_type::(&mut buffer).unwrap(); - let state = StateWithExtensionsMut::::unpack(&mut buffer).unwrap(); - assert_eq!(state.base, TEST_MINT); - assert_eq!(state.account_type[0], AccountType::Mint as u8); - - // mint with wrong AccountType fails - let mut buffer = TEST_MINT_SLICE.to_vec(); - buffer.append(&mut vec![0; Account::LEN - Mint::LEN]); - buffer.append(&mut vec![2, 0]); - let err = StateWithExtensionsMut::::unpack(&mut buffer).unwrap_err(); - assert_eq!(err, ProgramError::InvalidAccountData); - let err = set_account_type::(&mut buffer).unwrap_err(); - assert_eq!(err, ProgramError::InvalidAccountData); - } - - #[test] - fn test_set_account_type_wrongly() { - // try to set Account account_type to Mint - let mut buffer = TEST_ACCOUNT_SLICE.to_vec(); - buffer.append(&mut vec![0; 2]); - let err = set_account_type::(&mut buffer).unwrap_err(); - assert_eq!(err, ProgramError::InvalidAccountData); - - // try to set Mint account_type to Account - let mut buffer = TEST_MINT_SLICE.to_vec(); - buffer.append(&mut vec![0; Account::LEN - Mint::LEN]); - buffer.append(&mut vec![0; 2]); - let err = set_account_type::(&mut buffer).unwrap_err(); - assert_eq!(err, ProgramError::InvalidAccountData); - } - - #[test] - fn test_get_required_init_account_extensions() { - // Some mint extensions with no required account extensions - let mint_extensions = vec![ - ExtensionType::MintCloseAuthority, - ExtensionType::Uninitialized, - ]; - assert_eq!( - ExtensionType::get_required_init_account_extensions(&mint_extensions), - vec![] - ); - - // One mint extension with required account extension, one without - let mint_extensions = vec![ - ExtensionType::TransferFeeConfig, - ExtensionType::MintCloseAuthority, - ]; - assert_eq!( - ExtensionType::get_required_init_account_extensions(&mint_extensions), - vec![ExtensionType::TransferFeeAmount] - ); - - // Some mint extensions both with required account extensions - let mint_extensions = vec![ - ExtensionType::TransferFeeConfig, - ExtensionType::MintPaddingTest, - ]; - assert_eq!( - ExtensionType::get_required_init_account_extensions(&mint_extensions), - vec![ - ExtensionType::TransferFeeAmount, - ExtensionType::AccountPaddingTest - ] - ); - - // Demonstrate that method does not dedupe inputs or outputs - let mint_extensions = vec![ - ExtensionType::TransferFeeConfig, - ExtensionType::TransferFeeConfig, - ]; - assert_eq!( - ExtensionType::get_required_init_account_extensions(&mint_extensions), - vec![ - ExtensionType::TransferFeeAmount, - ExtensionType::TransferFeeAmount - ] - ); - } - - #[test] - fn mint_without_extensions() { - let space = ExtensionType::get_account_len::(&[]); - let mut buffer = vec![0; space]; - assert_eq!( - StateWithExtensionsMut::::unpack_uninitialized(&mut buffer), - Err(ProgramError::InvalidAccountData), - ); - - // write base account - let mut state = StateWithExtensionsMut::::unpack_uninitialized(&mut buffer).unwrap(); - state.base = TEST_MINT; - state.pack_base(); - state.init_account_type().unwrap(); - - // fail init extension - assert_eq!( - state.init_extension::(true), - Err(ProgramError::InvalidAccountData), - ); - - assert_eq!(TEST_MINT_SLICE, buffer); - } - - #[test] - fn test_init_nonzero_default() { - let mint_size = ExtensionType::get_account_len::(&[ExtensionType::MintPaddingTest]); - let mut buffer = vec![0; mint_size]; - let mut state = StateWithExtensionsMut::::unpack_uninitialized(&mut buffer).unwrap(); - state.base = TEST_MINT; - state.pack_base(); - state.init_account_type().unwrap(); - let extension = state.init_extension::(true).unwrap(); - assert_eq!(extension.padding1, [1; 128]); - assert_eq!(extension.padding2, [2; 48]); - assert_eq!(extension.padding3, [3; 9]); - } - - #[test] - fn test_init_buffer_too_small() { - let mint_size = - ExtensionType::get_account_len::(&[ExtensionType::MintCloseAuthority]); - let mut buffer = vec![0; mint_size - 1]; - let mut state = StateWithExtensionsMut::::unpack_uninitialized(&mut buffer).unwrap(); - let err = state - .init_extension::(true) - .unwrap_err(); - assert_eq!(err, ProgramError::InvalidAccountData); - - state.tlv_data[0] = 3; - state.tlv_data[2] = 32; - let err = state.get_extension_mut::().unwrap_err(); - assert_eq!(err, ProgramError::InvalidAccountData); - - let mut buffer = vec![0; Mint::LEN + 2]; - let err = StateWithExtensionsMut::::unpack_uninitialized(&mut buffer).unwrap_err(); - assert_eq!(err, ProgramError::InvalidAccountData); - - let mut buffer = vec![0; BASE_ACCOUNT_LENGTH + 2]; - let mut state = StateWithExtensionsMut::::unpack_uninitialized(&mut buffer).unwrap(); - let err = state.get_extension_mut::().unwrap_err(); - assert_eq!(err, ProgramError::InvalidAccountData); - - assert_eq!(state.get_extension_types().unwrap(), vec![]); - } - - #[test] - fn test_extension_with_no_data() { - let account_size = - ExtensionType::get_account_len::(&[ExtensionType::ImmutableOwner]); - let mut buffer = vec![0; account_size]; - let mut state = - StateWithExtensionsMut::::unpack_uninitialized(&mut buffer).unwrap(); - state.base = TEST_ACCOUNT; - state.pack_base(); - state.init_account_type().unwrap(); - state.init_extension::(true).unwrap(); - - assert_eq!( - get_first_extension_type(state.tlv_data).unwrap(), - Some(ExtensionType::ImmutableOwner) - ); - assert_eq!( - get_extension_types(state.tlv_data).unwrap(), - vec![ExtensionType::ImmutableOwner] - ); - } -} diff --git a/token/program-2022/src/extension/non_transferable.rs b/token/program-2022/src/extension/non_transferable.rs deleted file mode 100644 index 5e454a88f00..00000000000 --- a/token/program-2022/src/extension/non_transferable.rs +++ /dev/null @@ -1,13 +0,0 @@ -use { - crate::extension::{Extension, ExtensionType}, - bytemuck::{Pod, Zeroable}, -}; - -/// Indicates that the tokens from this mint can't be transfered -#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] -#[repr(transparent)] -pub struct NonTransferable; - -impl Extension for NonTransferable { - const TYPE: ExtensionType = ExtensionType::NonTransferable; -} diff --git a/token/program-2022/src/extension/reallocate.rs b/token/program-2022/src/extension/reallocate.rs deleted file mode 100644 index 7c2bf555ad0..00000000000 --- a/token/program-2022/src/extension/reallocate.rs +++ /dev/null @@ -1,87 +0,0 @@ -use { - crate::{ - error::TokenError, - extension::{set_account_type, AccountType, ExtensionType, StateWithExtensions}, - processor::Processor, - state::Account, - }, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - program::invoke, - pubkey::Pubkey, - system_instruction, - sysvar::{rent::Rent, Sysvar}, - }, -}; - -/// Processes a [Reallocate](enum.TokenInstruction.html) instruction -pub fn process_reallocate( - program_id: &Pubkey, - accounts: &[AccountInfo], - new_extension_types: Vec, -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let token_account_info = next_account_info(account_info_iter)?; - let payer_info = next_account_info(account_info_iter)?; - let system_program_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - let authority_info_data_len = authority_info.data_len(); - - // check that account is the right type and validate owner - let mut current_extension_types = { - let token_account = token_account_info.data.borrow(); - let account = StateWithExtensions::::unpack(&token_account)?; - Processor::validate_owner( - program_id, - &account.base.owner, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?; - account.get_extension_types()? - }; - - // check that all desired extensions are for the right account type - if new_extension_types - .iter() - .any(|extension_type| extension_type.get_account_type() != AccountType::Account) - { - return Err(TokenError::InvalidState.into()); - } - // ExtensionType::get_account_len() dedupes types, so just a dumb concatenation is fine here - current_extension_types.extend_from_slice(&new_extension_types); - let needed_account_len = ExtensionType::get_account_len::(¤t_extension_types); - - // if account is already large enough, return early - if token_account_info.data_len() >= needed_account_len { - return Ok(()); - } - - // reallocate - msg!( - "account needs realloc, +{:?} bytes", - needed_account_len - token_account_info.data_len() - ); - token_account_info.realloc(needed_account_len, false)?; - - // if additional lamports needed to remain rent-exempt, transfer them - let rent = Rent::get()?; - let new_minimum_balance = rent.minimum_balance(needed_account_len); - let lamports_diff = new_minimum_balance.saturating_sub(token_account_info.lamports()); - invoke( - &system_instruction::transfer(payer_info.key, token_account_info.key, lamports_diff), - &[ - payer_info.clone(), - token_account_info.clone(), - system_program_info.clone(), - ], - )?; - - // unpack to set account_type, if needed - let mut token_account = token_account_info.data.borrow_mut(); - set_account_type::(&mut token_account)?; - - Ok(()) -} diff --git a/token/program-2022/src/extension/transfer_fee/instruction.rs b/token/program-2022/src/extension/transfer_fee/instruction.rs deleted file mode 100644 index 5cf442db7c6..00000000000 --- a/token/program-2022/src/extension/transfer_fee/instruction.rs +++ /dev/null @@ -1,503 +0,0 @@ -use { - crate::{check_program_account, error::TokenError, instruction::TokenInstruction}, - solana_program::{ - instruction::{AccountMeta, Instruction}, - program_error::ProgramError, - program_option::COption, - pubkey::Pubkey, - }, - std::convert::TryFrom, -}; - -#[cfg(feature = "serde-traits")] -use { - crate::serialization::coption_fromstr, - serde::{Deserialize, Serialize}, -}; - -/// Transfer Fee extension instructions -#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))] -#[derive(Clone, Copy, Debug, PartialEq)] -#[repr(u8)] -pub enum TransferFeeInstruction { - /// Initialize the transfer fee on a new mint. - /// - /// Fails if the mint has already been initialized, so must be called before - /// `InitializeMint`. - /// - /// The mint must have exactly enough space allocated for the base mint (82 - /// bytes), plus 83 bytes of padding, 1 byte reserved for the account type, - /// then space required for this extension, plus any others. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The mint to initialize. - InitializeTransferFeeConfig { - /// Pubkey that may update the fees - #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))] - transfer_fee_config_authority: COption, - /// Withdraw instructions must be signed by this key - #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))] - withdraw_withheld_authority: COption, - /// Amount of transfer collected as fees, expressed as basis points of the - /// transfer amount - transfer_fee_basis_points: u16, - /// Maximum fee assessed on transfers - maximum_fee: u64, - }, - /// Transfer, providing expected mint information and fees - /// - /// Accounts expected by this instruction: - /// - /// * Single owner/delegate - /// 0. `[writable]` The source account. Must include the `TransferFeeAmount` extension. - /// 1. `[]` The token mint. Must include the `TransferFeeConfig` extension. - /// 2. `[writable]` The destination account. Must include the `TransferFeeAmount` extension. - /// 3. `[signer]` The source account's owner/delegate. - /// - /// * Multisignature owner/delegate - /// 0. `[writable]` The source account. - /// 1. `[]` The token mint. - /// 2. `[writable]` The destination account. - /// 3. `[]` The source account's multisignature owner/delegate. - /// 4. ..4+M `[signer]` M signer accounts. - TransferCheckedWithFee { - /// The amount of tokens to transfer. - amount: u64, - /// Expected number of base 10 digits to the right of the decimal place. - decimals: u8, - /// Expected fee assessed on this transfer, calculated off-chain based on - /// the transfer_fee_basis_points and maximum_fee of the mint. - fee: u64, - }, - /// Transfer all withheld tokens in the mint to an account. Signed by the mint's - /// withdraw withheld tokens authority. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner/delegate - /// 0. `[writable]` The token mint. Must include the `TransferFeeConfig` extension. - /// 1. `[writable]` The fee receiver account. Must include the `TransferFeeAmount` extension - /// associated with the provided mint. - /// 2. `[signer]` The mint's `withdraw_withheld_authority`. - /// - /// * Multisignature owner/delegate - /// 0. `[writable]` The token mint. - /// 1. `[writable]` The destination account. - /// 2. `[]` The mint's multisig `withdraw_withheld_authority`. - /// 3. ..3+M `[signer]` M signer accounts. - WithdrawWithheldTokensFromMint, - /// Transfer all withheld tokens to an account. Signed by the mint's - /// withdraw withheld tokens authority. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner/delegate - /// 0. `[]` The token mint. Must include the `TransferFeeConfig` extension. - /// 1. `[writable]` The fee receiver account. Must include the `TransferFeeAmount` - /// extension and be associated with the provided mint. - /// 2. `[signer]` The mint's `withdraw_withheld_authority`. - /// 3. ..3+N `[writable]` The source accounts to withdraw from. - /// - /// * Multisignature owner/delegate - /// 0. `[]` The token mint. - /// 1. `[writable]` The destination account. - /// 2. `[]` The mint's multisig `withdraw_withheld_authority`. - /// 3. ..3+M `[signer]` M signer accounts. - /// 3+M+1. ..3+M+N `[writable]` The source accounts to withdraw from. - WithdrawWithheldTokensFromAccounts { - /// Number of token accounts harvested - num_token_accounts: u8, - }, - /// Permissionless instruction to transfer all withheld tokens to the mint. - /// - /// Succeeds for frozen accounts. - /// - /// Accounts provided should include the `TransferFeeAmount` extension. If not, - /// the account is skipped. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The mint. - /// 1. ..1+N `[writable]` The source accounts to harvest from. - HarvestWithheldTokensToMint, - /// Set transfer fee. Only supported for mints that include the `TransferFeeConfig` extension. - /// - /// Accounts expected by this instruction: - /// - /// * Single authority - /// 0. `[writable]` The mint. - /// 1. `[signer]` The mint's fee account owner. - /// - /// * Multisignature authority - /// 0. `[writable]` The mint. - /// 1. `[]` The mint's multisignature fee account owner. - /// 2. ..2+M `[signer]` M signer accounts. - SetTransferFee { - /// Amount of transfer collected as fees, expressed as basis points of the - /// transfer amount - transfer_fee_basis_points: u16, - /// Maximum fee assessed on transfers - maximum_fee: u64, - }, -} -impl TransferFeeInstruction { - /// Unpacks a byte buffer into a TransferFeeInstruction - pub fn unpack(input: &[u8]) -> Result<(Self, &[u8]), ProgramError> { - use TokenError::InvalidInstruction; - - let (&tag, rest) = input.split_first().ok_or(InvalidInstruction)?; - Ok(match tag { - 0 => { - let (transfer_fee_config_authority, rest) = - TokenInstruction::unpack_pubkey_option(rest)?; - let (withdraw_withheld_authority, rest) = - TokenInstruction::unpack_pubkey_option(rest)?; - let (transfer_fee_basis_points, rest) = TokenInstruction::unpack_u16(rest)?; - let (maximum_fee, rest) = TokenInstruction::unpack_u64(rest)?; - let instruction = Self::InitializeTransferFeeConfig { - transfer_fee_config_authority, - withdraw_withheld_authority, - transfer_fee_basis_points, - maximum_fee, - }; - (instruction, rest) - } - 1 => { - let (amount, decimals, rest) = TokenInstruction::unpack_amount_decimals(rest)?; - let (fee, rest) = TokenInstruction::unpack_u64(rest)?; - let instruction = Self::TransferCheckedWithFee { - amount, - decimals, - fee, - }; - (instruction, rest) - } - 2 => (Self::WithdrawWithheldTokensFromMint, rest), - 3 => { - let (&num_token_accounts, rest) = rest.split_first().ok_or(InvalidInstruction)?; - let instruction = Self::WithdrawWithheldTokensFromAccounts { num_token_accounts }; - (instruction, rest) - } - 4 => (Self::HarvestWithheldTokensToMint, rest), - 5 => { - let (transfer_fee_basis_points, rest) = TokenInstruction::unpack_u16(rest)?; - let (maximum_fee, rest) = TokenInstruction::unpack_u64(rest)?; - let instruction = Self::SetTransferFee { - transfer_fee_basis_points, - maximum_fee, - }; - (instruction, rest) - } - _ => return Err(TokenError::InvalidInstruction.into()), - }) - } - - /// Packs a TransferFeeInstruction into a byte buffer. - pub fn pack(&self, buffer: &mut Vec) { - match *self { - Self::InitializeTransferFeeConfig { - ref transfer_fee_config_authority, - ref withdraw_withheld_authority, - transfer_fee_basis_points, - maximum_fee, - } => { - buffer.push(0); - TokenInstruction::pack_pubkey_option(transfer_fee_config_authority, buffer); - TokenInstruction::pack_pubkey_option(withdraw_withheld_authority, buffer); - buffer.extend_from_slice(&transfer_fee_basis_points.to_le_bytes()); - buffer.extend_from_slice(&maximum_fee.to_le_bytes()); - } - Self::TransferCheckedWithFee { - amount, - decimals, - fee, - } => { - buffer.push(1); - buffer.extend_from_slice(&amount.to_le_bytes()); - buffer.extend_from_slice(&decimals.to_le_bytes()); - buffer.extend_from_slice(&fee.to_le_bytes()); - } - Self::WithdrawWithheldTokensFromMint => { - buffer.push(2); - } - Self::WithdrawWithheldTokensFromAccounts { num_token_accounts } => { - buffer.push(3); - buffer.push(num_token_accounts); - } - Self::HarvestWithheldTokensToMint => { - buffer.push(4); - } - Self::SetTransferFee { - transfer_fee_basis_points, - maximum_fee, - } => { - buffer.push(5); - buffer.extend_from_slice(&transfer_fee_basis_points.to_le_bytes()); - buffer.extend_from_slice(&maximum_fee.to_le_bytes()); - } - } - } -} - -/// Create a `InitializeTransferFeeConfig` instruction -pub fn initialize_transfer_fee_config( - token_program_id: &Pubkey, - mint: &Pubkey, - transfer_fee_config_authority: Option<&Pubkey>, - withdraw_withheld_authority: Option<&Pubkey>, - transfer_fee_basis_points: u16, - maximum_fee: u64, -) -> Result { - check_program_account(token_program_id)?; - let transfer_fee_config_authority = transfer_fee_config_authority.cloned().into(); - let withdraw_withheld_authority = withdraw_withheld_authority.cloned().into(); - let data = TokenInstruction::TransferFeeExtension( - TransferFeeInstruction::InitializeTransferFeeConfig { - transfer_fee_config_authority, - withdraw_withheld_authority, - transfer_fee_basis_points, - maximum_fee, - }, - ) - .pack(); - - Ok(Instruction { - program_id: *token_program_id, - accounts: vec![AccountMeta::new(*mint, false)], - data, - }) -} - -/// Create a `TransferCheckedWithFee` instruction -#[allow(clippy::too_many_arguments)] -pub fn transfer_checked_with_fee( - token_program_id: &Pubkey, - source: &Pubkey, - mint: &Pubkey, - destination: &Pubkey, - authority: &Pubkey, - signers: &[&Pubkey], - amount: u64, - decimals: u8, - fee: u64, -) -> Result { - check_program_account(token_program_id)?; - let data = - TokenInstruction::TransferFeeExtension(TransferFeeInstruction::TransferCheckedWithFee { - amount, - decimals, - fee, - }) - .pack(); - - let mut accounts = Vec::with_capacity(4 + signers.len()); - accounts.push(AccountMeta::new(*source, false)); - accounts.push(AccountMeta::new_readonly(*mint, false)); - accounts.push(AccountMeta::new(*destination, false)); - accounts.push(AccountMeta::new_readonly(*authority, signers.is_empty())); - for signer in signers.iter() { - accounts.push(AccountMeta::new_readonly(**signer, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `WithdrawWithheldTokensFromMint` instruction -pub fn withdraw_withheld_tokens_from_mint( - token_program_id: &Pubkey, - mint: &Pubkey, - destination: &Pubkey, - authority: &Pubkey, - signers: &[&Pubkey], -) -> Result { - check_program_account(token_program_id)?; - let mut accounts = Vec::with_capacity(3 + signers.len()); - accounts.push(AccountMeta::new(*mint, false)); - accounts.push(AccountMeta::new(*destination, false)); - accounts.push(AccountMeta::new_readonly(*authority, signers.is_empty())); - for signer in signers.iter() { - accounts.push(AccountMeta::new_readonly(**signer, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data: TokenInstruction::TransferFeeExtension( - TransferFeeInstruction::WithdrawWithheldTokensFromMint, - ) - .pack(), - }) -} - -/// Creates a `WithdrawWithheldTokensFromAccounts` instruction -pub fn withdraw_withheld_tokens_from_accounts( - token_program_id: &Pubkey, - mint: &Pubkey, - destination: &Pubkey, - authority: &Pubkey, - signers: &[&Pubkey], - sources: &[&Pubkey], -) -> Result { - check_program_account(token_program_id)?; - let num_token_accounts = - u8::try_from(sources.len()).map_err(|_| ProgramError::InvalidInstructionData)?; - let mut accounts = Vec::with_capacity(3 + signers.len() + sources.len()); - accounts.push(AccountMeta::new_readonly(*mint, false)); - accounts.push(AccountMeta::new(*destination, false)); - accounts.push(AccountMeta::new_readonly(*authority, signers.is_empty())); - for signer in signers.iter() { - accounts.push(AccountMeta::new_readonly(**signer, true)); - } - for source in sources.iter() { - accounts.push(AccountMeta::new(**source, false)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data: TokenInstruction::TransferFeeExtension( - TransferFeeInstruction::WithdrawWithheldTokensFromAccounts { num_token_accounts }, - ) - .pack(), - }) -} - -/// Creates a `HarvestWithheldTokensToMint` instruction -pub fn harvest_withheld_tokens_to_mint( - token_program_id: &Pubkey, - mint: &Pubkey, - sources: &[&Pubkey], -) -> Result { - check_program_account(token_program_id)?; - let mut accounts = Vec::with_capacity(1 + sources.len()); - accounts.push(AccountMeta::new(*mint, false)); - for source in sources.iter() { - accounts.push(AccountMeta::new(**source, false)); - } - Ok(Instruction { - program_id: *token_program_id, - accounts, - data: TokenInstruction::TransferFeeExtension( - TransferFeeInstruction::HarvestWithheldTokensToMint, - ) - .pack(), - }) -} - -/// Creates a `SetTransferFee` instruction -pub fn set_transfer_fee( - token_program_id: &Pubkey, - mint: &Pubkey, - authority: &Pubkey, - signers: &[&Pubkey], - transfer_fee_basis_points: u16, - maximum_fee: u64, -) -> Result { - check_program_account(token_program_id)?; - let mut accounts = Vec::with_capacity(2 + signers.len()); - accounts.push(AccountMeta::new(*mint, false)); - accounts.push(AccountMeta::new_readonly(*authority, signers.is_empty())); - for signer in signers.iter() { - accounts.push(AccountMeta::new_readonly(**signer, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data: TokenInstruction::TransferFeeExtension(TransferFeeInstruction::SetTransferFee { - transfer_fee_basis_points, - maximum_fee, - }) - .pack(), - }) -} - -#[cfg(test)] -mod test { - use super::*; - - const TRANSFER_FEE_PREFIX: u8 = 26; - - #[test] - fn test_instruction_packing() { - let check = TokenInstruction::TransferFeeExtension( - TransferFeeInstruction::InitializeTransferFeeConfig { - transfer_fee_config_authority: COption::Some(Pubkey::new(&[11u8; 32])), - withdraw_withheld_authority: COption::None, - transfer_fee_basis_points: 111, - maximum_fee: u64::MAX, - }, - ); - let packed = check.pack(); - let mut expect = vec![TRANSFER_FEE_PREFIX, 0, 1]; - expect.extend_from_slice(&[11u8; 32]); - expect.extend_from_slice(&[0]); - expect.extend_from_slice(&111u16.to_le_bytes()); - expect.extend_from_slice(&u64::MAX.to_le_bytes()); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::TransferFeeExtension( - TransferFeeInstruction::TransferCheckedWithFee { - amount: 24, - decimals: 24, - fee: 23, - }, - ); - let packed = check.pack(); - let mut expect = vec![TRANSFER_FEE_PREFIX, 1]; - expect.extend_from_slice(&24u64.to_le_bytes()); - expect.extend_from_slice(&[24u8]); - expect.extend_from_slice(&23u64.to_le_bytes()); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::TransferFeeExtension( - TransferFeeInstruction::WithdrawWithheldTokensFromMint, - ); - let packed = check.pack(); - let expect = [TRANSFER_FEE_PREFIX, 2]; - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let num_token_accounts = 255; - let check = TokenInstruction::TransferFeeExtension( - TransferFeeInstruction::WithdrawWithheldTokensFromAccounts { num_token_accounts }, - ); - let packed = check.pack(); - let expect = [TRANSFER_FEE_PREFIX, 3, num_token_accounts]; - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::TransferFeeExtension( - TransferFeeInstruction::HarvestWithheldTokensToMint, - ); - let packed = check.pack(); - let expect = [TRANSFER_FEE_PREFIX, 4]; - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = - TokenInstruction::TransferFeeExtension(TransferFeeInstruction::SetTransferFee { - transfer_fee_basis_points: u16::MAX, - maximum_fee: u64::MAX, - }); - let packed = check.pack(); - let mut expect = vec![TRANSFER_FEE_PREFIX, 5]; - expect.extend_from_slice(&u16::MAX.to_le_bytes()); - expect.extend_from_slice(&u64::MAX.to_le_bytes()); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - } -} diff --git a/token/program-2022/src/extension/transfer_fee/mod.rs b/token/program-2022/src/extension/transfer_fee/mod.rs deleted file mode 100644 index e32e58a49fa..00000000000 --- a/token/program-2022/src/extension/transfer_fee/mod.rs +++ /dev/null @@ -1,244 +0,0 @@ -use { - crate::{ - error::TokenError, - extension::{Extension, ExtensionType}, - pod::*, - }, - bytemuck::{Pod, Zeroable}, - solana_program::{clock::Epoch, entrypoint::ProgramResult}, - std::{cmp, convert::TryFrom}, -}; - -/// Transfer fee extension instructions -pub mod instruction; - -/// Transfer fee extension processor -pub mod processor; - -/// Maximum possible fee in basis points is 100%, aka 10_000 basis points -pub const MAX_FEE_BASIS_POINTS: u16 = 10_000; -const ONE_IN_BASIS_POINTS: u128 = MAX_FEE_BASIS_POINTS as u128; - -/// Transfer fee information -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] -pub struct TransferFee { - /// First epoch where the transfer fee takes effect - pub epoch: PodU64, // Epoch, - /// Maximum fee assessed on transfers, expressed as an amount of tokens - pub maximum_fee: PodU64, - /// Amount of transfer collected as fees, expressed as basis points of the - /// transfer amount, ie. increments of 0.01% - pub transfer_fee_basis_points: PodU16, -} -impl TransferFee { - /// Calculate the transfer fee - pub fn calculate(&self, amount: u64) -> Option { - let transfer_fee_basis_points = u16::from(self.transfer_fee_basis_points) as u128; - if transfer_fee_basis_points == 0 || amount == 0 { - Some(0) - } else { - let numerator = (amount as u128).checked_mul(transfer_fee_basis_points)?; - let mut raw_fee = numerator.checked_div(ONE_IN_BASIS_POINTS)?; - let remainder = numerator.checked_rem(ONE_IN_BASIS_POINTS)?; - if remainder > 0 { - raw_fee = raw_fee.checked_add(1)?; - } - // guaranteed to be ok - let raw_fee = u64::try_from(raw_fee).ok()?; - Some(cmp::min(raw_fee, u64::from(self.maximum_fee))) - } - } -} - -/// Transfer fee extension data for mints. -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] -pub struct TransferFeeConfig { - /// Optional authority to set the fee - pub transfer_fee_config_authority: OptionalNonZeroPubkey, - /// Withdraw from mint instructions must be signed by this key - pub withdraw_withheld_authority: OptionalNonZeroPubkey, - /// Withheld transfer fee tokens that have been moved to the mint for withdrawal - pub withheld_amount: PodU64, - /// Older transfer fee, used if the current epoch < new_transfer_fee.epoch - pub older_transfer_fee: TransferFee, - /// Newer transfer fee, used if the current epoch >= new_transfer_fee.epoch - pub newer_transfer_fee: TransferFee, -} -impl TransferFeeConfig { - /// Get the fee for the given epoch - pub fn get_epoch_fee(&self, epoch: Epoch) -> &TransferFee { - if epoch >= self.newer_transfer_fee.epoch.into() { - &self.newer_transfer_fee - } else { - &self.older_transfer_fee - } - } - /// Calculate the fee for the given epoch - pub fn calculate_epoch_fee(&self, epoch: Epoch, amount: u64) -> Option { - self.get_epoch_fee(epoch).calculate(amount) - } -} -impl Extension for TransferFeeConfig { - const TYPE: ExtensionType = ExtensionType::TransferFeeConfig; -} - -/// Transfer fee extension data for accounts. -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] -pub struct TransferFeeAmount { - /// Amount withheld during transfers, to be harvested to the mint - pub withheld_amount: PodU64, -} -impl TransferFeeAmount { - /// Check if the extension is in a closable state - pub fn closable(&self) -> ProgramResult { - if self.withheld_amount == 0.into() { - Ok(()) - } else { - Err(TokenError::AccountHasWithheldTransferFees.into()) - } - } -} -impl Extension for TransferFeeAmount { - const TYPE: ExtensionType = ExtensionType::TransferFeeAmount; -} - -#[cfg(test)] -pub(crate) mod test { - use {super::*, solana_program::pubkey::Pubkey, std::convert::TryFrom}; - - const NEWER_EPOCH: u64 = 100; - const OLDER_EPOCH: u64 = 1; - - pub(crate) fn test_transfer_fee_config() -> TransferFeeConfig { - TransferFeeConfig { - transfer_fee_config_authority: OptionalNonZeroPubkey::try_from(Some(Pubkey::new( - &[10; 32], - ))) - .unwrap(), - withdraw_withheld_authority: OptionalNonZeroPubkey::try_from(Some(Pubkey::new( - &[11; 32], - ))) - .unwrap(), - withheld_amount: PodU64::from(u64::MAX), - older_transfer_fee: TransferFee { - epoch: PodU64::from(OLDER_EPOCH), - maximum_fee: PodU64::from(10), - transfer_fee_basis_points: PodU16::from(100), - }, - newer_transfer_fee: TransferFee { - epoch: PodU64::from(NEWER_EPOCH), - maximum_fee: PodU64::from(5_000), - transfer_fee_basis_points: PodU16::from(1), - }, - } - } - - #[test] - fn epoch_fee() { - let transfer_fee_config = test_transfer_fee_config(); - // during epoch 100 and after, use newer transfer fee - assert_eq!( - transfer_fee_config.get_epoch_fee(NEWER_EPOCH).epoch, - NEWER_EPOCH.into() - ); - assert_eq!( - transfer_fee_config.get_epoch_fee(NEWER_EPOCH + 1).epoch, - NEWER_EPOCH.into() - ); - assert_eq!( - transfer_fee_config.get_epoch_fee(u64::MAX).epoch, - NEWER_EPOCH.into() - ); - // before that, use older transfer fee - assert_eq!( - transfer_fee_config.get_epoch_fee(NEWER_EPOCH - 1).epoch, - OLDER_EPOCH.into() - ); - assert_eq!( - transfer_fee_config.get_epoch_fee(OLDER_EPOCH).epoch, - OLDER_EPOCH.into() - ); - assert_eq!( - transfer_fee_config.get_epoch_fee(OLDER_EPOCH + 1).epoch, - OLDER_EPOCH.into() - ); - } - - #[test] - fn calculate_fee_max() { - let one = u64::try_from(ONE_IN_BASIS_POINTS).unwrap(); - let transfer_fee = TransferFee { - epoch: PodU64::from(0), - maximum_fee: PodU64::from(5_000), - transfer_fee_basis_points: PodU16::from(1), - }; - let maximum_fee = u64::from(transfer_fee.maximum_fee); - // hit maximum fee - assert_eq!(maximum_fee, transfer_fee.calculate(u64::MAX).unwrap()); - // at exactly the max - assert_eq!( - maximum_fee, - transfer_fee.calculate(maximum_fee * one).unwrap() - ); - // one token above, normally rounds up, but we're at the max - assert_eq!( - maximum_fee, - transfer_fee.calculate(maximum_fee * one + 1).unwrap() - ); - // one token below, rounds up to the max - assert_eq!( - maximum_fee, - transfer_fee.calculate(maximum_fee * one - 1).unwrap() - ); - } - - #[test] - fn calculate_fee_min() { - let one = u64::try_from(ONE_IN_BASIS_POINTS).unwrap(); - let transfer_fee = TransferFee { - epoch: PodU64::from(0), - maximum_fee: PodU64::from(5_000), - transfer_fee_basis_points: PodU16::from(1), - }; - let minimum_fee = 1; - // hit minimum fee even with 1 token - assert_eq!(minimum_fee, transfer_fee.calculate(1).unwrap()); - // still minimum at 2 tokens - assert_eq!(minimum_fee, transfer_fee.calculate(2).unwrap()); - // still minimum at 10_000 tokens - assert_eq!(minimum_fee, transfer_fee.calculate(one).unwrap()); - // 2 token fee at 10_001 - assert_eq!(minimum_fee + 1, transfer_fee.calculate(one + 1).unwrap()); - // zero is always zero - assert_eq!(0, transfer_fee.calculate(0).unwrap()); - } - - #[test] - fn calculate_fee_zero() { - let one = u64::try_from(ONE_IN_BASIS_POINTS).unwrap(); - let transfer_fee = TransferFee { - epoch: PodU64::from(0), - maximum_fee: PodU64::from(u64::MAX), - transfer_fee_basis_points: PodU16::from(0), - }; - // always zero fee - assert_eq!(0, transfer_fee.calculate(0).unwrap()); - assert_eq!(0, transfer_fee.calculate(u64::MAX).unwrap()); - assert_eq!(0, transfer_fee.calculate(1).unwrap()); - assert_eq!(0, transfer_fee.calculate(one).unwrap()); - - let transfer_fee = TransferFee { - epoch: PodU64::from(0), - maximum_fee: PodU64::from(0), - transfer_fee_basis_points: PodU16::from(MAX_FEE_BASIS_POINTS), - }; - // always zero fee - assert_eq!(0, transfer_fee.calculate(0).unwrap()); - assert_eq!(0, transfer_fee.calculate(u64::MAX).unwrap()); - assert_eq!(0, transfer_fee.calculate(1).unwrap()); - assert_eq!(0, transfer_fee.calculate(one).unwrap()); - } -} diff --git a/token/program-2022/src/extension/transfer_fee/processor.rs b/token/program-2022/src/extension/transfer_fee/processor.rs deleted file mode 100644 index 5d18b22fccf..00000000000 --- a/token/program-2022/src/extension/transfer_fee/processor.rs +++ /dev/null @@ -1,321 +0,0 @@ -use { - crate::{ - check_program_account, - error::TokenError, - extension::{ - transfer_fee::{ - instruction::TransferFeeInstruction, TransferFee, TransferFeeAmount, - TransferFeeConfig, MAX_FEE_BASIS_POINTS, - }, - StateWithExtensions, StateWithExtensionsMut, - }, - processor::Processor, - state::{Account, Mint}, - }, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - clock::Clock, - entrypoint::ProgramResult, - msg, - program_option::COption, - pubkey::Pubkey, - sysvar::Sysvar, - }, - std::convert::TryInto, -}; - -fn process_initialize_transfer_fee_config( - accounts: &[AccountInfo], - transfer_fee_config_authority: COption, - withdraw_withheld_authority: COption, - transfer_fee_basis_points: u16, - maximum_fee: u64, -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_account_info = next_account_info(account_info_iter)?; - - let mut mint_data = mint_account_info.data.borrow_mut(); - let mut mint = StateWithExtensionsMut::::unpack_uninitialized(&mut mint_data)?; - let extension = mint.init_extension::(true)?; - extension.transfer_fee_config_authority = transfer_fee_config_authority.try_into()?; - extension.withdraw_withheld_authority = withdraw_withheld_authority.try_into()?; - extension.withheld_amount = 0u64.into(); - - if transfer_fee_basis_points > MAX_FEE_BASIS_POINTS { - return Err(TokenError::TransferFeeExceedsMaximum.into()); - } - // To be safe, set newer and older transfer fees to the same thing on init, - // but only newer will actually be used - let epoch = Clock::get()?.epoch; - let transfer_fee = TransferFee { - epoch: epoch.into(), - transfer_fee_basis_points: transfer_fee_basis_points.into(), - maximum_fee: maximum_fee.into(), - }; - extension.older_transfer_fee = transfer_fee; - extension.newer_transfer_fee = transfer_fee; - - Ok(()) -} - -fn process_set_transfer_fee( - program_id: &Pubkey, - accounts: &[AccountInfo], - transfer_fee_basis_points: u16, - maximum_fee: u64, -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_account_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - let authority_info_data_len = authority_info.data_len(); - - let mut mint_data = mint_account_info.data.borrow_mut(); - let mut mint = StateWithExtensionsMut::::unpack(&mut mint_data)?; - let extension = mint.get_extension_mut::()?; - - let transfer_fee_config_authority = - Option::::from(extension.transfer_fee_config_authority) - .ok_or(TokenError::NoAuthorityExists)?; - Processor::validate_owner( - program_id, - &transfer_fee_config_authority, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?; - - if transfer_fee_basis_points > MAX_FEE_BASIS_POINTS { - return Err(TokenError::TransferFeeExceedsMaximum.into()); - } - - // When setting the transfer fee, we have two situations: - // * newer transfer fee epoch <= current epoch: - // newer transfer fee is the active one, so overwrite older transfer fee with newer, then overwrite newer transfer fee - // * newer transfer fee epoch >= next epoch: - // it was never used, so just overwrite next transfer fee - let epoch = Clock::get()?.epoch; - if u64::from(extension.newer_transfer_fee.epoch) <= epoch { - extension.older_transfer_fee = extension.newer_transfer_fee; - } - // set two epochs ahead to avoid rug pulls at the end of an epoch - let newer_fee_start_epoch = epoch.saturating_add(2); - let transfer_fee = TransferFee { - epoch: newer_fee_start_epoch.into(), - transfer_fee_basis_points: transfer_fee_basis_points.into(), - maximum_fee: maximum_fee.into(), - }; - extension.newer_transfer_fee = transfer_fee; - - Ok(()) -} - -fn process_withdraw_withheld_tokens_from_mint( - program_id: &Pubkey, - accounts: &[AccountInfo], -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_account_info = next_account_info(account_info_iter)?; - let destination_account_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - let authority_info_data_len = authority_info.data_len(); - - let mut mint_data = mint_account_info.data.borrow_mut(); - let mut mint = StateWithExtensionsMut::::unpack(&mut mint_data)?; - let extension = mint.get_extension_mut::()?; - - let withdraw_withheld_authority = Option::::from(extension.withdraw_withheld_authority) - .ok_or(TokenError::NoAuthorityExists)?; - Processor::validate_owner( - program_id, - &withdraw_withheld_authority, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?; - - let mut destination_account_data = destination_account_info.data.borrow_mut(); - let mut destination_account = - StateWithExtensionsMut::::unpack(&mut destination_account_data)?; - if destination_account.base.mint != *mint_account_info.key { - return Err(TokenError::MintMismatch.into()); - } - if destination_account.base.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - let withheld_amount = u64::from(extension.withheld_amount); - extension.withheld_amount = 0.into(); - destination_account.base.amount = destination_account - .base - .amount - .checked_add(withheld_amount) - .ok_or(TokenError::Overflow)?; - destination_account.pack_base(); - - Ok(()) -} - -fn harvest_from_account<'a, 'b>( - mint_key: &'b Pubkey, - token_account_info: &'b AccountInfo<'a>, -) -> Result { - let mut token_account_data = token_account_info.data.borrow_mut(); - let mut token_account = StateWithExtensionsMut::::unpack(&mut token_account_data) - .map_err(|_| TokenError::InvalidState)?; - if token_account.base.mint != *mint_key { - return Err(TokenError::MintMismatch); - } - check_program_account(token_account_info.owner).map_err(|_| TokenError::InvalidState)?; - let token_account_extension = token_account - .get_extension_mut::() - .map_err(|_| TokenError::InvalidState)?; - let account_withheld_amount = u64::from(token_account_extension.withheld_amount); - token_account_extension.withheld_amount = 0.into(); - Ok(account_withheld_amount) -} - -fn process_harvest_withheld_tokens_to_mint(accounts: &[AccountInfo]) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_account_info = next_account_info(account_info_iter)?; - let token_account_infos = account_info_iter.as_slice(); - - let mut mint_data = mint_account_info.data.borrow_mut(); - let mut mint = StateWithExtensionsMut::::unpack(&mut mint_data)?; - let mint_extension = mint.get_extension_mut::()?; - - for token_account_info in token_account_infos { - match harvest_from_account(mint_account_info.key, token_account_info) { - Ok(amount) => { - let mint_withheld_amount = u64::from(mint_extension.withheld_amount); - mint_extension.withheld_amount = mint_withheld_amount - .checked_add(amount) - .ok_or(TokenError::Overflow)? - .into(); - } - Err(e) => { - msg!("Error harvesting from {}: {}", token_account_info.key, e); - } - } - } - Ok(()) -} - -fn process_withdraw_withheld_tokens_from_accounts( - program_id: &Pubkey, - accounts: &[AccountInfo], - num_token_accounts: u8, -) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_account_info = next_account_info(account_info_iter)?; - let destination_account_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - let authority_info_data_len = authority_info.data_len(); - let account_infos = account_info_iter.as_slice(); - let num_signers = account_infos - .len() - .saturating_sub(num_token_accounts as usize); - - let mint_data = mint_account_info.data.borrow(); - let mint = StateWithExtensions::::unpack(&mint_data)?; - let extension = mint.get_extension::()?; - - let withdraw_withheld_authority = Option::::from(extension.withdraw_withheld_authority) - .ok_or(TokenError::NoAuthorityExists)?; - Processor::validate_owner( - program_id, - &withdraw_withheld_authority, - authority_info, - authority_info_data_len, - &account_infos[..num_signers], - )?; - - let mut destination_account_data = destination_account_info.data.borrow_mut(); - let mut destination_account = - StateWithExtensionsMut::::unpack(&mut destination_account_data)?; - if destination_account.base.mint != *mint_account_info.key { - return Err(TokenError::MintMismatch.into()); - } - if destination_account.base.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - for account_info in &account_infos[num_signers..] { - // self-harvest, can't double-borrow the underlying data - if account_info.key == destination_account_info.key { - let token_account_extension = destination_account - .get_extension_mut::() - .map_err(|_| TokenError::InvalidState)?; - let account_withheld_amount = u64::from(token_account_extension.withheld_amount); - token_account_extension.withheld_amount = 0.into(); - destination_account.base.amount = destination_account - .base - .amount - .checked_add(account_withheld_amount) - .ok_or(TokenError::Overflow)?; - } else { - match harvest_from_account(mint_account_info.key, account_info) { - Ok(amount) => { - destination_account.base.amount = destination_account - .base - .amount - .checked_add(amount) - .ok_or(TokenError::Overflow)?; - } - Err(e) => { - msg!("Error harvesting from {}: {}", account_info.key, e); - } - } - } - } - destination_account.pack_base(); - - Ok(()) -} - -pub(crate) fn process_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - instruction: TransferFeeInstruction, -) -> ProgramResult { - check_program_account(program_id)?; - - match instruction { - TransferFeeInstruction::InitializeTransferFeeConfig { - transfer_fee_config_authority, - withdraw_withheld_authority, - transfer_fee_basis_points, - maximum_fee, - } => process_initialize_transfer_fee_config( - accounts, - transfer_fee_config_authority, - withdraw_withheld_authority, - transfer_fee_basis_points, - maximum_fee, - ), - TransferFeeInstruction::TransferCheckedWithFee { - amount, - decimals, - fee, - } => { - msg!("TransferFeeInstruction: TransferCheckedWithFee"); - Processor::process_transfer(program_id, accounts, amount, Some(decimals), Some(fee)) - } - TransferFeeInstruction::WithdrawWithheldTokensFromMint => { - msg!("TransferFeeInstruction: WithdrawWithheldTokensFromMint"); - process_withdraw_withheld_tokens_from_mint(program_id, accounts) - } - TransferFeeInstruction::WithdrawWithheldTokensFromAccounts { num_token_accounts } => { - msg!("TransferFeeInstruction: WithdrawWithheldTokensFromAccounts"); - process_withdraw_withheld_tokens_from_accounts(program_id, accounts, num_token_accounts) - } - TransferFeeInstruction::HarvestWithheldTokensToMint => { - msg!("TransferFeeInstruction: HarvestWithheldTokensToMint"); - process_harvest_withheld_tokens_to_mint(accounts) - } - TransferFeeInstruction::SetTransferFee { - transfer_fee_basis_points, - maximum_fee, - } => { - msg!("TransferFeeInstruction: SetTransferFee"); - process_set_transfer_fee(program_id, accounts, transfer_fee_basis_points, maximum_fee) - } - } -} diff --git a/token/program-2022/src/generic_token_account.rs b/token/program-2022/src/generic_token_account.rs deleted file mode 100644 index 1123ba6fe8e..00000000000 --- a/token/program-2022/src/generic_token_account.rs +++ /dev/null @@ -1,62 +0,0 @@ -//! Generic Token Account, copied from spl_token::state -// Remove all of this and use spl-token's version once token 3.4.0 is released -use { - crate::state::AccountState, - solana_program::pubkey::{Pubkey, PUBKEY_BYTES}, -}; - -const SPL_TOKEN_ACCOUNT_MINT_OFFSET: usize = 0; -const SPL_TOKEN_ACCOUNT_OWNER_OFFSET: usize = 32; - -/// A trait for token Account structs to enable efficiently unpacking various fields -/// without unpacking the complete state. -pub trait GenericTokenAccount { - /// Check if the account data is a valid token account - fn valid_account_data(account_data: &[u8]) -> bool; - - /// Call after account length has already been verified to unpack the account owner - fn unpack_account_owner_unchecked(account_data: &[u8]) -> &Pubkey { - Self::unpack_pubkey_unchecked(account_data, SPL_TOKEN_ACCOUNT_OWNER_OFFSET) - } - - /// Call after account length has already been verified to unpack the account mint - fn unpack_account_mint_unchecked(account_data: &[u8]) -> &Pubkey { - Self::unpack_pubkey_unchecked(account_data, SPL_TOKEN_ACCOUNT_MINT_OFFSET) - } - - /// Call after account length has already been verified to unpack a Pubkey at - /// the specified offset. Panics if `account_data.len()` is less than `PUBKEY_BYTES` - fn unpack_pubkey_unchecked(account_data: &[u8], offset: usize) -> &Pubkey { - bytemuck::from_bytes(&account_data[offset..offset + PUBKEY_BYTES]) - } - - /// Unpacks an account's owner from opaque account data. - fn unpack_account_owner(account_data: &[u8]) -> Option<&Pubkey> { - if Self::valid_account_data(account_data) { - Some(Self::unpack_account_owner_unchecked(account_data)) - } else { - None - } - } - - /// Unpacks an account's mint from opaque account data. - fn unpack_account_mint(account_data: &[u8]) -> Option<&Pubkey> { - if Self::valid_account_data(account_data) { - Some(Self::unpack_account_mint_unchecked(account_data)) - } else { - None - } - } -} - -/// The offset of state field in Account's C representation -pub const ACCOUNT_INITIALIZED_INDEX: usize = 108; - -/// Check if the account data buffer represents an initialized account. -/// This is checking the `state` (AccountState) field of an Account object. -pub fn is_initialized_account(account_data: &[u8]) -> bool { - *account_data - .get(ACCOUNT_INITIALIZED_INDEX) - .unwrap_or(&(AccountState::Uninitialized as u8)) - != AccountState::Uninitialized as u8 -} diff --git a/token/program-2022/src/instruction.rs b/token/program-2022/src/instruction.rs deleted file mode 100644 index e948a9991f3..00000000000 --- a/token/program-2022/src/instruction.rs +++ /dev/null @@ -1,2287 +0,0 @@ -//! Instruction types - -#![allow(deprecated)] // needed to avoid deprecation warning when generating serde implementation for TokenInstruction - -use { - crate::{ - check_program_account, check_spl_token_program_account, - error::TokenError, - extension::{transfer_fee::instruction::TransferFeeInstruction, ExtensionType}, - pod::{pod_from_bytes, pod_get_packed_len}, - }, - bytemuck::Pod, - solana_program::{ - instruction::{AccountMeta, Instruction}, - program_error::ProgramError, - program_option::COption, - pubkey::{Pubkey, PUBKEY_BYTES}, - system_program, sysvar, - }, - std::{ - convert::{TryFrom, TryInto}, - mem::size_of, - }, -}; - -#[cfg(feature = "serde-traits")] -use { - crate::serialization::coption_fromstr, - serde::{Deserialize, Serialize}, - serde_with::{As, DisplayFromStr}, -}; - -/// Minimum number of multisignature signers (min N) -pub const MIN_SIGNERS: usize = 1; -/// Maximum number of multisignature signers (max N) -pub const MAX_SIGNERS: usize = 11; -/// Serialized length of a u16, for unpacking -const U16_BYTES: usize = 2; -/// Serialized length of a u64, for unpacking -const U64_BYTES: usize = 8; - -/// Instructions supported by the token program. -#[repr(C)] -#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))] -#[derive(Clone, Debug, PartialEq)] -pub enum TokenInstruction<'a> { - /// Initializes a new mint and optionally deposits all the newly minted - /// tokens in an account. - /// - /// The `InitializeMint` instruction requires no signers and MUST be - /// included within the same Transaction as the system program's - /// `CreateAccount` instruction that creates the account being initialized. - /// Otherwise another party can acquire ownership of the uninitialized - /// account. - /// - /// All extensions must be initialized before calling this instruction. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The mint to initialize. - /// 1. `[]` Rent sysvar - /// - InitializeMint { - /// Number of base 10 digits to the right of the decimal place. - decimals: u8, - /// The authority/multisignature to mint tokens. - #[cfg_attr(feature = "serde-traits", serde(with = "As::"))] - mint_authority: Pubkey, - /// The freeze authority/multisignature of the mint. - #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))] - freeze_authority: COption, - }, - /// Initializes a new account to hold tokens. If this account is associated - /// with the native mint then the token balance of the initialized account - /// will be equal to the amount of SOL in the account. If this account is - /// associated with another mint, that mint must be initialized before this - /// command can succeed. - /// - /// The `InitializeAccount` instruction requires no signers and MUST be - /// included within the same Transaction as the system program's - /// `CreateAccount` instruction that creates the account being initialized. - /// Otherwise another party can acquire ownership of the uninitialized - /// account. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The account to initialize. - /// 1. `[]` The mint this account will be associated with. - /// 2. `[]` The new account's owner/multisignature. - /// 3. `[]` Rent sysvar - InitializeAccount, - /// Initializes a multisignature account with N provided signers. - /// - /// Multisignature accounts can used in place of any single owner/delegate - /// accounts in any token instruction that require an owner/delegate to be - /// present. The variant field represents the number of signers (M) - /// required to validate this multisignature account. - /// - /// The `InitializeMultisig` instruction requires no signers and MUST be - /// included within the same Transaction as the system program's - /// `CreateAccount` instruction that creates the account being initialized. - /// Otherwise another party can acquire ownership of the uninitialized - /// account. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The multisignature account to initialize. - /// 1. `[]` Rent sysvar - /// 2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <= - /// 11. - InitializeMultisig { - /// The number of signers (M) required to validate this multisignature - /// account. - m: u8, - }, - /// NOTE This instruction is deprecated in favor of `TransferChecked` or - /// `TransferCheckedWithFee` - /// - /// Transfers tokens from one account to another either directly or via a - /// delegate. If this account is associated with the native mint then equal - /// amounts of SOL and Tokens will be transferred to the destination - /// account. - /// - /// If either account contains an `TransferFeeAmount` extension, this will fail. - /// Mints with the `TransferFeeConfig` extension are required in order to assess the fee. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner/delegate - /// 0. `[writable]` The source account. - /// 1. `[writable]` The destination account. - /// 2. `[signer]` The source account's owner/delegate. - /// - /// * Multisignature owner/delegate - /// 0. `[writable]` The source account. - /// 1. `[writable]` The destination account. - /// 2. `[]` The source account's multisignature owner/delegate. - /// 3. ..3+M `[signer]` M signer accounts. - #[deprecated( - since = "4.0.0", - note = "please use `TransferChecked` or `TransferCheckedWithFee` instead" - )] - Transfer { - /// The amount of tokens to transfer. - amount: u64, - }, - /// Approves a delegate. A delegate is given the authority over tokens on - /// behalf of the source account's owner. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner - /// 0. `[writable]` The source account. - /// 1. `[]` The delegate. - /// 2. `[signer]` The source account owner. - /// - /// * Multisignature owner - /// 0. `[writable]` The source account. - /// 1. `[]` The delegate. - /// 2. `[]` The source account's multisignature owner. - /// 3. ..3+M `[signer]` M signer accounts - Approve { - /// The amount of tokens the delegate is approved for. - amount: u64, - }, - /// Revokes the delegate's authority. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner - /// 0. `[writable]` The source account. - /// 1. `[signer]` The source account owner or current delegate. - /// - /// * Multisignature owner - /// 0. `[writable]` The source account. - /// 1. `[]` The source account's multisignature owner or current delegate. - /// 2. ..2+M `[signer]` M signer accounts - Revoke, - /// Sets a new authority of a mint or account. - /// - /// Accounts expected by this instruction: - /// - /// * Single authority - /// 0. `[writable]` The mint or account to change the authority of. - /// 1. `[signer]` The current authority of the mint or account. - /// - /// * Multisignature authority - /// 0. `[writable]` The mint or account to change the authority of. - /// 1. `[]` The mint's or account's current multisignature authority. - /// 2. ..2+M `[signer]` M signer accounts - SetAuthority { - /// The type of authority to update. - authority_type: AuthorityType, - /// The new authority - #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))] - new_authority: COption, - }, - /// Mints new tokens to an account. The native mint does not support - /// minting. - /// - /// Accounts expected by this instruction: - /// - /// * Single authority - /// 0. `[writable]` The mint. - /// 1. `[writable]` The account to mint tokens to. - /// 2. `[signer]` The mint's minting authority. - /// - /// * Multisignature authority - /// 0. `[writable]` The mint. - /// 1. `[writable]` The account to mint tokens to. - /// 2. `[]` The mint's multisignature mint-tokens authority. - /// 3. ..3+M `[signer]` M signer accounts. - MintTo { - /// The amount of new tokens to mint. - amount: u64, - }, - /// Burns tokens by removing them from an account. `Burn` does not support - /// accounts associated with the native mint, use `CloseAccount` instead. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner/delegate - /// 0. `[writable]` The account to burn from. - /// 1. `[writable]` The token mint. - /// 2. `[signer]` The account's owner/delegate. - /// - /// * Multisignature owner/delegate - /// 0. `[writable]` The account to burn from. - /// 1. `[writable]` The token mint. - /// 2. `[]` The account's multisignature owner/delegate. - /// 3. ..3+M `[signer]` M signer accounts. - Burn { - /// The amount of tokens to burn. - amount: u64, - }, - /// Close an account by transferring all its SOL to the destination account. - /// Non-native accounts may only be closed if its token amount is zero. - /// - /// Accounts with the `TransferFeeAmount` extension may only be closed if the withheld - /// amount is zero. - /// - /// Mints may be closed if they have the `MintCloseAuthority` extension and their token - /// supply is zero - /// - /// Note that if the account to close has a `ConfidentialTransferExtension`, the - /// `ConfidentialTransferInstruction::EmptyAccount` instruction must precede this - /// instruction. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner - /// 0. `[writable]` The account to close. - /// 1. `[writable]` The destination account. - /// 2. `[signer]` The account's owner. - /// - /// * Multisignature owner - /// 0. `[writable]` The account to close. - /// 1. `[writable]` The destination account. - /// 2. `[]` The account's multisignature owner. - /// 3. ..3+M `[signer]` M signer accounts. - CloseAccount, - /// Freeze an Initialized account using the Mint's freeze_authority (if - /// set). - /// - /// Accounts expected by this instruction: - /// - /// * Single owner - /// 0. `[writable]` The account to freeze. - /// 1. `[]` The token mint. - /// 2. `[signer]` The mint freeze authority. - /// - /// * Multisignature owner - /// 0. `[writable]` The account to freeze. - /// 1. `[]` The token mint. - /// 2. `[]` The mint's multisignature freeze authority. - /// 3. ..3+M `[signer]` M signer accounts. - FreezeAccount, - /// Thaw a Frozen account using the Mint's freeze_authority (if set). - /// - /// Accounts expected by this instruction: - /// - /// * Single owner - /// 0. `[writable]` The account to freeze. - /// 1. `[]` The token mint. - /// 2. `[signer]` The mint freeze authority. - /// - /// * Multisignature owner - /// 0. `[writable]` The account to freeze. - /// 1. `[]` The token mint. - /// 2. `[]` The mint's multisignature freeze authority. - /// 3. ..3+M `[signer]` M signer accounts. - ThawAccount, - - /// Transfers tokens from one account to another either directly or via a - /// delegate. If this account is associated with the native mint then equal - /// amounts of SOL and Tokens will be transferred to the destination - /// account. - /// - /// This instruction differs from Transfer in that the token mint and - /// decimals value is checked by the caller. This may be useful when - /// creating transactions offline or within a hardware wallet. - /// - /// If either account contains an `TransferFeeAmount` extension, the fee is - /// withheld in the destination account. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner/delegate - /// 0. `[writable]` The source account. - /// 1. `[]` The token mint. - /// 2. `[writable]` The destination account. - /// 3. `[signer]` The source account's owner/delegate. - /// - /// * Multisignature owner/delegate - /// 0. `[writable]` The source account. - /// 1. `[]` The token mint. - /// 2. `[writable]` The destination account. - /// 3. `[]` The source account's multisignature owner/delegate. - /// 4. ..4+M `[signer]` M signer accounts. - TransferChecked { - /// The amount of tokens to transfer. - amount: u64, - /// Expected number of base 10 digits to the right of the decimal place. - decimals: u8, - }, - /// Approves a delegate. A delegate is given the authority over tokens on - /// behalf of the source account's owner. - /// - /// This instruction differs from Approve in that the token mint and - /// decimals value is checked by the caller. This may be useful when - /// creating transactions offline or within a hardware wallet. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner - /// 0. `[writable]` The source account. - /// 1. `[]` The token mint. - /// 2. `[]` The delegate. - /// 3. `[signer]` The source account owner. - /// - /// * Multisignature owner - /// 0. `[writable]` The source account. - /// 1. `[]` The token mint. - /// 2. `[]` The delegate. - /// 3. `[]` The source account's multisignature owner. - /// 4. ..4+M `[signer]` M signer accounts - ApproveChecked { - /// The amount of tokens the delegate is approved for. - amount: u64, - /// Expected number of base 10 digits to the right of the decimal place. - decimals: u8, - }, - /// Mints new tokens to an account. The native mint does not support - /// minting. - /// - /// This instruction differs from MintTo in that the decimals value is - /// checked by the caller. This may be useful when creating transactions - /// offline or within a hardware wallet. - /// - /// Accounts expected by this instruction: - /// - /// * Single authority - /// 0. `[writable]` The mint. - /// 1. `[writable]` The account to mint tokens to. - /// 2. `[signer]` The mint's minting authority. - /// - /// * Multisignature authority - /// 0. `[writable]` The mint. - /// 1. `[writable]` The account to mint tokens to. - /// 2. `[]` The mint's multisignature mint-tokens authority. - /// 3. ..3+M `[signer]` M signer accounts. - MintToChecked { - /// The amount of new tokens to mint. - amount: u64, - /// Expected number of base 10 digits to the right of the decimal place. - decimals: u8, - }, - /// Burns tokens by removing them from an account. `BurnChecked` does not - /// support accounts associated with the native mint, use `CloseAccount` - /// instead. - /// - /// This instruction differs from Burn in that the decimals value is checked - /// by the caller. This may be useful when creating transactions offline or - /// within a hardware wallet. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner/delegate - /// 0. `[writable]` The account to burn from. - /// 1. `[writable]` The token mint. - /// 2. `[signer]` The account's owner/delegate. - /// - /// * Multisignature owner/delegate - /// 0. `[writable]` The account to burn from. - /// 1. `[writable]` The token mint. - /// 2. `[]` The account's multisignature owner/delegate. - /// 3. ..3+M `[signer]` M signer accounts. - BurnChecked { - /// The amount of tokens to burn. - amount: u64, - /// Expected number of base 10 digits to the right of the decimal place. - decimals: u8, - }, - /// Like InitializeAccount, but the owner pubkey is passed via instruction data - /// rather than the accounts list. This variant may be preferable when using - /// Cross Program Invocation from an instruction that does not need the owner's - /// `AccountInfo` otherwise. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The account to initialize. - /// 1. `[]` The mint this account will be associated with. - /// 2. `[]` Rent sysvar - InitializeAccount2 { - /// The new account's owner/multisignature. - owner: Pubkey, - }, - /// Given a wrapped / native token account (a token account containing SOL) - /// updates its amount field based on the account's underlying `lamports`. - /// This is useful if a non-wrapped SOL account uses `system_instruction::transfer` - /// to move lamports to a wrapped token account, and needs to have its token - /// `amount` field updated. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The native token account to sync with its underlying lamports. - SyncNative, - /// Like InitializeAccount2, but does not require the Rent sysvar to be provided - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The account to initialize. - /// 1. `[]` The mint this account will be associated with. - InitializeAccount3 { - /// The new account's owner/multisignature. - owner: Pubkey, - }, - /// Like InitializeMultisig, but does not require the Rent sysvar to be provided - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The multisignature account to initialize. - /// 1. ..1+N. `[]` The signer accounts, must equal to N where 1 <= N <= - /// 11. - InitializeMultisig2 { - /// The number of signers (M) required to validate this multisignature - /// account. - m: u8, - }, - /// Like InitializeMint, but does not require the Rent sysvar to be provided - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The mint to initialize. - /// - InitializeMint2 { - /// Number of base 10 digits to the right of the decimal place. - decimals: u8, - /// The authority/multisignature to mint tokens. - #[cfg_attr(feature = "serde-traits", serde(with = "As::"))] - mint_authority: Pubkey, - /// The freeze authority/multisignature of the mint. - #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))] - freeze_authority: COption, - }, - /// Gets the required size of an account for the given mint as a little-endian - /// `u64`. - /// - /// Return data can be fetched using `sol_get_return_data` and deserializing - /// the return data as a little-endian `u64`. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[]` The mint to calculate for - GetAccountDataSize { - /// Additional extension types to include in the returned account size - extension_types: Vec, - }, - /// Initialize the Immutable Owner extension for the given token account - /// - /// Fails if the account has already been initialized, so must be called before - /// `InitializeAccount`. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The account to initialize. - /// - /// Data expected by this instruction: - /// None - /// - InitializeImmutableOwner, - /// Convert an Amount of tokens to a UiAmount `string`, using the given mint. - /// - /// Fails on an invalid mint. - /// - /// Return data can be fetched using `sol_get_return_data` and deserialized with - /// `String::from_utf8`. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[]` The mint to calculate for - AmountToUiAmount { - /// The amount of tokens to convert. - amount: u64, - }, - /// Convert a UiAmount of tokens to a little-endian `u64` raw Amount, using the given mint. - /// - /// Return data can be fetched using `sol_get_return_data` and deserializing - /// the return data as a little-endian `u64`. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[]` The mint to calculate for - UiAmountToAmount { - /// The ui_amount of tokens to convert. - ui_amount: &'a str, - }, - /// Initialize the close account authority on a new mint. - /// - /// Fails if the mint has already been initialized, so must be called before - /// `InitializeMint`. - /// - /// The mint must have exactly enough space allocated for the base mint (82 - /// bytes), plus 83 bytes of padding, 1 byte reserved for the account type, - /// then space required for this extension, plus any others. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The mint to initialize. - InitializeMintCloseAuthority { - /// Authority that must sign the `CloseAccount` instruction on a mint - #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))] - close_authority: COption, - }, - /// The common instruction prefix for Transfer Fee extension instructions. - /// - /// See `extension::transfer_fee::instruction::TransferFeeInstruction` for - /// further details about the extended instructions that share this instruction prefix - TransferFeeExtension(TransferFeeInstruction), - /// The common instruction prefix for Confidential Transfer extension instructions. - /// - /// See `extension::confidential_transfer::instruction::ConfidentialTransferInstruction` for - /// further details about the extended instructions that share this instruction prefix - ConfidentialTransferExtension, - /// The common instruction prefix for Default Account State extension instructions. - /// - /// See `extension::default_account_state::instruction::DefaultAccountStateInstruction` for - /// further details about the extended instructions that share this instruction prefix - DefaultAccountStateExtension, - /// Check to see if a token account is large enough for a list of ExtensionTypes, and if not, - /// use reallocation to increase the data size. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner - /// 0. `[writable]` The account to reallocate. - /// 1. `[signer, writable]` The payer account to fund reallocation - /// 2. `[]` System program for reallocation funding - /// 3. `[signer]` The account's owner. - /// - /// * Multisignature owner - /// 0. `[writable]` The account to reallocate. - /// 1. `[signer, writable]` The payer account to fund reallocation - /// 2. `[]` System program for reallocation funding - /// 3. `[]` The account's multisignature owner/delegate. - /// 4. ..4+M `[signer]` M signer accounts. - /// - Reallocate { - /// New extension types to include in the reallocated account - extension_types: Vec, - }, - /// The common instruction prefix for Memo Transfer account extension instructions. - /// - /// See `extension::memo_transfer::instruction::RequiredMemoTransfersInstruction` for - /// further details about the extended instructions that share this instruction prefix - MemoTransferExtension, - /// Creates the native mint. - /// - /// This instruction only needs to be invoked once after deployment and is permissionless, - /// Wrapped SOL (`native_mint::id()`) will not be available until this instruction is - /// successfully executed. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writeable,signer]` Funding account (must be a system account) - /// 1. `[writable]` The native mint address - /// 2. `[]` System program for mint account funding - /// - CreateNativeMint, - /// Initialize the non transferable extension for the given mint account - /// - /// Fails if the account has already been initialized, so must be called before - /// `InitializeMint`. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The mint account to initialize. - /// - /// Data expected by this instruction: - /// None - /// - InitializeNonTransferableMint, - /// The common instruction prefix for Interest Bearing extension instructions. - /// - /// See `extension::interest_bearing_mint::instruction::InterestBearingMintInstruction` for - /// further details about the extended instructions that share this instruction prefix - InterestBearingMintExtension, -} -impl<'a> TokenInstruction<'a> { - /// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html). - pub fn unpack(input: &'a [u8]) -> Result { - use TokenError::InvalidInstruction; - - let (&tag, rest) = input.split_first().ok_or(InvalidInstruction)?; - Ok(match tag { - 0 => { - let (&decimals, rest) = rest.split_first().ok_or(InvalidInstruction)?; - let (mint_authority, rest) = Self::unpack_pubkey(rest)?; - let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?; - Self::InitializeMint { - mint_authority, - freeze_authority, - decimals, - } - } - 1 => Self::InitializeAccount, - 2 => { - let &m = rest.get(0).ok_or(InvalidInstruction)?; - Self::InitializeMultisig { m } - } - 3 | 4 | 7 | 8 => { - let amount = rest - .get(..U64_BYTES) - .and_then(|slice| slice.try_into().ok()) - .map(u64::from_le_bytes) - .ok_or(InvalidInstruction)?; - match tag { - #[allow(deprecated)] - 3 => Self::Transfer { amount }, - 4 => Self::Approve { amount }, - 7 => Self::MintTo { amount }, - 8 => Self::Burn { amount }, - _ => unreachable!(), - } - } - 5 => Self::Revoke, - 6 => { - let (authority_type, rest) = rest - .split_first() - .ok_or_else(|| ProgramError::from(InvalidInstruction)) - .and_then(|(&t, rest)| Ok((AuthorityType::from(t)?, rest)))?; - let (new_authority, _rest) = Self::unpack_pubkey_option(rest)?; - - Self::SetAuthority { - authority_type, - new_authority, - } - } - 9 => Self::CloseAccount, - 10 => Self::FreezeAccount, - 11 => Self::ThawAccount, - 12 => { - let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?; - Self::TransferChecked { amount, decimals } - } - 13 => { - let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?; - Self::ApproveChecked { amount, decimals } - } - 14 => { - let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?; - Self::MintToChecked { amount, decimals } - } - 15 => { - let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?; - Self::BurnChecked { amount, decimals } - } - 16 => { - let (owner, _rest) = Self::unpack_pubkey(rest)?; - Self::InitializeAccount2 { owner } - } - 17 => Self::SyncNative, - 18 => { - let (owner, _rest) = Self::unpack_pubkey(rest)?; - Self::InitializeAccount3 { owner } - } - 19 => { - let &m = rest.get(0).ok_or(InvalidInstruction)?; - Self::InitializeMultisig2 { m } - } - 20 => { - let (&decimals, rest) = rest.split_first().ok_or(InvalidInstruction)?; - let (mint_authority, rest) = Self::unpack_pubkey(rest)?; - let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?; - Self::InitializeMint2 { - mint_authority, - freeze_authority, - decimals, - } - } - 21 => { - let mut extension_types = vec![]; - for chunk in rest.chunks(size_of::()) { - extension_types.push(chunk.try_into()?); - } - Self::GetAccountDataSize { extension_types } - } - 22 => Self::InitializeImmutableOwner, - 23 => { - let (amount, _rest) = Self::unpack_u64(rest)?; - Self::AmountToUiAmount { amount } - } - 24 => { - let ui_amount = std::str::from_utf8(rest).map_err(|_| InvalidInstruction)?; - Self::UiAmountToAmount { ui_amount } - } - 25 => { - let (close_authority, _rest) = Self::unpack_pubkey_option(rest)?; - Self::InitializeMintCloseAuthority { close_authority } - } - 26 => { - let (instruction, _rest) = TransferFeeInstruction::unpack(rest)?; - Self::TransferFeeExtension(instruction) - } - 27 => Self::ConfidentialTransferExtension, - 28 => Self::DefaultAccountStateExtension, - 29 => { - let mut extension_types = vec![]; - for chunk in rest.chunks(size_of::()) { - extension_types.push(chunk.try_into()?); - } - Self::Reallocate { extension_types } - } - 30 => Self::MemoTransferExtension, - 31 => Self::CreateNativeMint, - 32 => Self::InitializeNonTransferableMint, - 33 => Self::InterestBearingMintExtension, - _ => return Err(TokenError::InvalidInstruction.into()), - }) - } - - /// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte buffer. - pub fn pack(&self) -> Vec { - let mut buf = Vec::with_capacity(size_of::()); - match self { - &Self::InitializeMint { - ref mint_authority, - ref freeze_authority, - decimals, - } => { - buf.push(0); - buf.push(decimals); - buf.extend_from_slice(mint_authority.as_ref()); - Self::pack_pubkey_option(freeze_authority, &mut buf); - } - Self::InitializeAccount => buf.push(1), - &Self::InitializeMultisig { m } => { - buf.push(2); - buf.push(m); - } - #[allow(deprecated)] - &Self::Transfer { amount } => { - buf.push(3); - buf.extend_from_slice(&amount.to_le_bytes()); - } - &Self::Approve { amount } => { - buf.push(4); - buf.extend_from_slice(&amount.to_le_bytes()); - } - &Self::MintTo { amount } => { - buf.push(7); - buf.extend_from_slice(&amount.to_le_bytes()); - } - &Self::Burn { amount } => { - buf.push(8); - buf.extend_from_slice(&amount.to_le_bytes()); - } - Self::Revoke => buf.push(5), - Self::SetAuthority { - authority_type, - ref new_authority, - } => { - buf.push(6); - buf.push(authority_type.into()); - Self::pack_pubkey_option(new_authority, &mut buf); - } - Self::CloseAccount => buf.push(9), - Self::FreezeAccount => buf.push(10), - Self::ThawAccount => buf.push(11), - &Self::TransferChecked { amount, decimals } => { - buf.push(12); - buf.extend_from_slice(&amount.to_le_bytes()); - buf.push(decimals); - } - &Self::ApproveChecked { amount, decimals } => { - buf.push(13); - buf.extend_from_slice(&amount.to_le_bytes()); - buf.push(decimals); - } - &Self::MintToChecked { amount, decimals } => { - buf.push(14); - buf.extend_from_slice(&amount.to_le_bytes()); - buf.push(decimals); - } - &Self::BurnChecked { amount, decimals } => { - buf.push(15); - buf.extend_from_slice(&amount.to_le_bytes()); - buf.push(decimals); - } - &Self::InitializeAccount2 { owner } => { - buf.push(16); - buf.extend_from_slice(owner.as_ref()); - } - &Self::SyncNative => { - buf.push(17); - } - &Self::InitializeAccount3 { owner } => { - buf.push(18); - buf.extend_from_slice(owner.as_ref()); - } - &Self::InitializeMultisig2 { m } => { - buf.push(19); - buf.push(m); - } - &Self::InitializeMint2 { - ref mint_authority, - ref freeze_authority, - decimals, - } => { - buf.push(20); - buf.push(decimals); - buf.extend_from_slice(mint_authority.as_ref()); - Self::pack_pubkey_option(freeze_authority, &mut buf); - } - &Self::GetAccountDataSize { - ref extension_types, - } => { - buf.push(21); - for extension_type in extension_types { - buf.extend_from_slice(&<[u8; 2]>::from(*extension_type)); - } - } - &Self::InitializeImmutableOwner => { - buf.push(22); - } - &Self::AmountToUiAmount { amount } => { - buf.push(23); - buf.extend_from_slice(&amount.to_le_bytes()); - } - Self::UiAmountToAmount { ui_amount } => { - buf.push(24); - buf.extend_from_slice(ui_amount.as_bytes()); - } - &Self::InitializeMintCloseAuthority { - ref close_authority, - } => { - buf.push(25); - Self::pack_pubkey_option(close_authority, &mut buf); - } - &Self::TransferFeeExtension(ref instruction) => { - buf.push(26); - TransferFeeInstruction::pack(instruction, &mut buf); - } - &Self::ConfidentialTransferExtension => { - buf.push(27); - } - &Self::DefaultAccountStateExtension => { - buf.push(28); - } - &Self::Reallocate { - ref extension_types, - } => { - buf.push(29); - for extension_type in extension_types { - buf.extend_from_slice(&<[u8; 2]>::from(*extension_type)); - } - } - &Self::MemoTransferExtension => { - buf.push(30); - } - &Self::CreateNativeMint => { - buf.push(31); - } - &Self::InitializeNonTransferableMint => { - buf.push(32); - } - &Self::InterestBearingMintExtension => { - buf.push(33); - } - }; - buf - } - - pub(crate) fn unpack_pubkey(input: &[u8]) -> Result<(Pubkey, &[u8]), ProgramError> { - let pk = input - .get(..PUBKEY_BYTES) - .map(Pubkey::new) - .ok_or(TokenError::InvalidInstruction)?; - Ok((pk, &input[PUBKEY_BYTES..])) - } - - pub(crate) fn unpack_pubkey_option( - input: &[u8], - ) -> Result<(COption, &[u8]), ProgramError> { - match input.split_first() { - Option::Some((&0, rest)) => Ok((COption::None, rest)), - Option::Some((&1, rest)) => { - let (pk, rest) = Self::unpack_pubkey(rest)?; - Ok((COption::Some(pk), rest)) - } - _ => Err(TokenError::InvalidInstruction.into()), - } - } - - pub(crate) fn pack_pubkey_option(value: &COption, buf: &mut Vec) { - match *value { - COption::Some(ref key) => { - buf.push(1); - buf.extend_from_slice(&key.to_bytes()); - } - COption::None => buf.push(0), - } - } - - pub(crate) fn unpack_u16(input: &[u8]) -> Result<(u16, &[u8]), ProgramError> { - let value = input - .get(..U16_BYTES) - .and_then(|slice| slice.try_into().ok()) - .map(u16::from_le_bytes) - .ok_or(TokenError::InvalidInstruction)?; - Ok((value, &input[U16_BYTES..])) - } - - pub(crate) fn unpack_u64(input: &[u8]) -> Result<(u64, &[u8]), ProgramError> { - let value = input - .get(..U64_BYTES) - .and_then(|slice| slice.try_into().ok()) - .map(u64::from_le_bytes) - .ok_or(TokenError::InvalidInstruction)?; - Ok((value, &input[U64_BYTES..])) - } - - pub(crate) fn unpack_amount_decimals(input: &[u8]) -> Result<(u64, u8, &[u8]), ProgramError> { - let (amount, rest) = Self::unpack_u64(input)?; - let (&decimals, rest) = rest.split_first().ok_or(TokenError::InvalidInstruction)?; - Ok((amount, decimals, rest)) - } -} - -/// Specifies the authority type for SetAuthority instructions -#[repr(u8)] -#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))] -#[derive(Clone, Debug, PartialEq)] -pub enum AuthorityType { - /// Authority to mint new tokens - MintTokens, - /// Authority to freeze any account associated with the Mint - FreezeAccount, - /// Owner of a given token account - AccountOwner, - /// Authority to close a token account - CloseAccount, - /// Authority to set the transfer fee - TransferFeeConfig, - /// Authority to withdraw withheld tokens from a mint - WithheldWithdraw, - /// Authority to close a mint account - CloseMint, - /// Authority to set the interest rate - InterestRate, -} - -impl AuthorityType { - fn into(&self) -> u8 { - match self { - AuthorityType::MintTokens => 0, - AuthorityType::FreezeAccount => 1, - AuthorityType::AccountOwner => 2, - AuthorityType::CloseAccount => 3, - AuthorityType::TransferFeeConfig => 4, - AuthorityType::WithheldWithdraw => 5, - AuthorityType::CloseMint => 6, - AuthorityType::InterestRate => 7, - } - } - - fn from(index: u8) -> Result { - match index { - 0 => Ok(AuthorityType::MintTokens), - 1 => Ok(AuthorityType::FreezeAccount), - 2 => Ok(AuthorityType::AccountOwner), - 3 => Ok(AuthorityType::CloseAccount), - 4 => Ok(AuthorityType::TransferFeeConfig), - 5 => Ok(AuthorityType::WithheldWithdraw), - 6 => Ok(AuthorityType::CloseMint), - 7 => Ok(AuthorityType::InterestRate), - _ => Err(TokenError::InvalidInstruction.into()), - } - } -} - -/// Creates a `InitializeMint` instruction. -pub fn initialize_mint( - token_program_id: &Pubkey, - mint_pubkey: &Pubkey, - mint_authority_pubkey: &Pubkey, - freeze_authority_pubkey: Option<&Pubkey>, - decimals: u8, -) -> Result { - check_spl_token_program_account(token_program_id)?; - let freeze_authority = freeze_authority_pubkey.cloned().into(); - let data = TokenInstruction::InitializeMint { - mint_authority: *mint_authority_pubkey, - freeze_authority, - decimals, - } - .pack(); - - let accounts = vec![ - AccountMeta::new(*mint_pubkey, false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - ]; - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `InitializeMint2` instruction. -pub fn initialize_mint2( - token_program_id: &Pubkey, - mint_pubkey: &Pubkey, - mint_authority_pubkey: &Pubkey, - freeze_authority_pubkey: Option<&Pubkey>, - decimals: u8, -) -> Result { - check_spl_token_program_account(token_program_id)?; - let freeze_authority = freeze_authority_pubkey.cloned().into(); - let data = TokenInstruction::InitializeMint2 { - mint_authority: *mint_authority_pubkey, - freeze_authority, - decimals, - } - .pack(); - - let accounts = vec![AccountMeta::new(*mint_pubkey, false)]; - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `InitializeAccount` instruction. -pub fn initialize_account( - token_program_id: &Pubkey, - account_pubkey: &Pubkey, - mint_pubkey: &Pubkey, - owner_pubkey: &Pubkey, -) -> Result { - check_spl_token_program_account(token_program_id)?; - let data = TokenInstruction::InitializeAccount.pack(); - - let accounts = vec![ - AccountMeta::new(*account_pubkey, false), - AccountMeta::new_readonly(*mint_pubkey, false), - AccountMeta::new_readonly(*owner_pubkey, false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - ]; - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `InitializeAccount2` instruction. -pub fn initialize_account2( - token_program_id: &Pubkey, - account_pubkey: &Pubkey, - mint_pubkey: &Pubkey, - owner_pubkey: &Pubkey, -) -> Result { - check_spl_token_program_account(token_program_id)?; - let data = TokenInstruction::InitializeAccount2 { - owner: *owner_pubkey, - } - .pack(); - - let accounts = vec![ - AccountMeta::new(*account_pubkey, false), - AccountMeta::new_readonly(*mint_pubkey, false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - ]; - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `InitializeAccount3` instruction. -pub fn initialize_account3( - token_program_id: &Pubkey, - account_pubkey: &Pubkey, - mint_pubkey: &Pubkey, - owner_pubkey: &Pubkey, -) -> Result { - check_spl_token_program_account(token_program_id)?; - let data = TokenInstruction::InitializeAccount3 { - owner: *owner_pubkey, - } - .pack(); - - let accounts = vec![ - AccountMeta::new(*account_pubkey, false), - AccountMeta::new_readonly(*mint_pubkey, false), - ]; - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `InitializeMultisig` instruction. -pub fn initialize_multisig( - token_program_id: &Pubkey, - multisig_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - m: u8, -) -> Result { - check_spl_token_program_account(token_program_id)?; - if !is_valid_signer_index(m as usize) - || !is_valid_signer_index(signer_pubkeys.len()) - || m as usize > signer_pubkeys.len() - { - return Err(ProgramError::MissingRequiredSignature); - } - let data = TokenInstruction::InitializeMultisig { m }.pack(); - - let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*multisig_pubkey, false)); - accounts.push(AccountMeta::new_readonly(sysvar::rent::id(), false)); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, false)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `InitializeMultisig2` instruction. -pub fn initialize_multisig2( - token_program_id: &Pubkey, - multisig_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - m: u8, -) -> Result { - check_spl_token_program_account(token_program_id)?; - if !is_valid_signer_index(m as usize) - || !is_valid_signer_index(signer_pubkeys.len()) - || m as usize > signer_pubkeys.len() - { - return Err(ProgramError::MissingRequiredSignature); - } - let data = TokenInstruction::InitializeMultisig2 { m }.pack(); - - let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*multisig_pubkey, false)); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, false)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `Transfer` instruction. -#[deprecated( - since = "4.0.0", - note = "please use `transfer_checked` or `transfer_checked_with_fee` instead" -)] -pub fn transfer( - token_program_id: &Pubkey, - source_pubkey: &Pubkey, - destination_pubkey: &Pubkey, - authority_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - amount: u64, -) -> Result { - check_spl_token_program_account(token_program_id)?; - #[allow(deprecated)] - let data = TokenInstruction::Transfer { amount }.pack(); - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*source_pubkey, false)); - accounts.push(AccountMeta::new(*destination_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *authority_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates an `Approve` instruction. -pub fn approve( - token_program_id: &Pubkey, - source_pubkey: &Pubkey, - delegate_pubkey: &Pubkey, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - amount: u64, -) -> Result { - check_spl_token_program_account(token_program_id)?; - let data = TokenInstruction::Approve { amount }.pack(); - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*source_pubkey, false)); - accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `Revoke` instruction. -pub fn revoke( - token_program_id: &Pubkey, - source_pubkey: &Pubkey, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], -) -> Result { - check_spl_token_program_account(token_program_id)?; - let data = TokenInstruction::Revoke.pack(); - - let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*source_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `SetAuthority` instruction. -pub fn set_authority( - token_program_id: &Pubkey, - owned_pubkey: &Pubkey, - new_authority_pubkey: Option<&Pubkey>, - authority_type: AuthorityType, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], -) -> Result { - check_spl_token_program_account(token_program_id)?; - let new_authority = new_authority_pubkey.cloned().into(); - let data = TokenInstruction::SetAuthority { - authority_type, - new_authority, - } - .pack(); - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*owned_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `MintTo` instruction. -pub fn mint_to( - token_program_id: &Pubkey, - mint_pubkey: &Pubkey, - account_pubkey: &Pubkey, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - amount: u64, -) -> Result { - check_spl_token_program_account(token_program_id)?; - let data = TokenInstruction::MintTo { amount }.pack(); - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*mint_pubkey, false)); - accounts.push(AccountMeta::new(*account_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `Burn` instruction. -pub fn burn( - token_program_id: &Pubkey, - account_pubkey: &Pubkey, - mint_pubkey: &Pubkey, - authority_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - amount: u64, -) -> Result { - check_spl_token_program_account(token_program_id)?; - let data = TokenInstruction::Burn { amount }.pack(); - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*account_pubkey, false)); - accounts.push(AccountMeta::new(*mint_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *authority_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `CloseAccount` instruction. -pub fn close_account( - token_program_id: &Pubkey, - account_pubkey: &Pubkey, - destination_pubkey: &Pubkey, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], -) -> Result { - check_spl_token_program_account(token_program_id)?; - let data = TokenInstruction::CloseAccount.pack(); - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*account_pubkey, false)); - accounts.push(AccountMeta::new(*destination_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `FreezeAccount` instruction. -pub fn freeze_account( - token_program_id: &Pubkey, - account_pubkey: &Pubkey, - mint_pubkey: &Pubkey, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], -) -> Result { - check_spl_token_program_account(token_program_id)?; - let data = TokenInstruction::FreezeAccount.pack(); - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*account_pubkey, false)); - accounts.push(AccountMeta::new_readonly(*mint_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `ThawAccount` instruction. -pub fn thaw_account( - token_program_id: &Pubkey, - account_pubkey: &Pubkey, - mint_pubkey: &Pubkey, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], -) -> Result { - check_spl_token_program_account(token_program_id)?; - let data = TokenInstruction::ThawAccount.pack(); - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*account_pubkey, false)); - accounts.push(AccountMeta::new_readonly(*mint_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `TransferChecked` instruction. -#[allow(clippy::too_many_arguments)] -pub fn transfer_checked( - token_program_id: &Pubkey, - source_pubkey: &Pubkey, - mint_pubkey: &Pubkey, - destination_pubkey: &Pubkey, - authority_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - amount: u64, - decimals: u8, -) -> Result { - check_spl_token_program_account(token_program_id)?; - let data = TokenInstruction::TransferChecked { amount, decimals }.pack(); - - let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*source_pubkey, false)); - accounts.push(AccountMeta::new_readonly(*mint_pubkey, false)); - accounts.push(AccountMeta::new(*destination_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *authority_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates an `ApproveChecked` instruction. -#[allow(clippy::too_many_arguments)] -pub fn approve_checked( - token_program_id: &Pubkey, - source_pubkey: &Pubkey, - mint_pubkey: &Pubkey, - delegate_pubkey: &Pubkey, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - amount: u64, - decimals: u8, -) -> Result { - check_spl_token_program_account(token_program_id)?; - let data = TokenInstruction::ApproveChecked { amount, decimals }.pack(); - - let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*source_pubkey, false)); - accounts.push(AccountMeta::new_readonly(*mint_pubkey, false)); - accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `MintToChecked` instruction. -pub fn mint_to_checked( - token_program_id: &Pubkey, - mint_pubkey: &Pubkey, - account_pubkey: &Pubkey, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - amount: u64, - decimals: u8, -) -> Result { - check_spl_token_program_account(token_program_id)?; - let data = TokenInstruction::MintToChecked { amount, decimals }.pack(); - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*mint_pubkey, false)); - accounts.push(AccountMeta::new(*account_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `BurnChecked` instruction. -pub fn burn_checked( - token_program_id: &Pubkey, - account_pubkey: &Pubkey, - mint_pubkey: &Pubkey, - authority_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - amount: u64, - decimals: u8, -) -> Result { - check_spl_token_program_account(token_program_id)?; - let data = TokenInstruction::BurnChecked { amount, decimals }.pack(); - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*account_pubkey, false)); - accounts.push(AccountMeta::new(*mint_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *authority_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `SyncNative` instruction -pub fn sync_native( - token_program_id: &Pubkey, - account_pubkey: &Pubkey, -) -> Result { - check_spl_token_program_account(token_program_id)?; - - Ok(Instruction { - program_id: *token_program_id, - accounts: vec![AccountMeta::new(*account_pubkey, false)], - data: TokenInstruction::SyncNative.pack(), - }) -} - -/// Creates a `GetAccountDataSize` instruction -pub fn get_account_data_size( - token_program_id: &Pubkey, - mint_pubkey: &Pubkey, - extension_types: &[ExtensionType], -) -> Result { - check_spl_token_program_account(token_program_id)?; - Ok(Instruction { - program_id: *token_program_id, - accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)], - data: TokenInstruction::GetAccountDataSize { - extension_types: extension_types.to_vec(), - } - .pack(), - }) -} - -/// Creates an `InitializeMintCloseAuthority` instruction -pub fn initialize_mint_close_authority( - token_program_id: &Pubkey, - mint_pubkey: &Pubkey, - close_authority: Option<&Pubkey>, -) -> Result { - check_program_account(token_program_id)?; - let close_authority = close_authority.cloned().into(); - Ok(Instruction { - program_id: *token_program_id, - accounts: vec![AccountMeta::new(*mint_pubkey, false)], - data: TokenInstruction::InitializeMintCloseAuthority { close_authority }.pack(), - }) -} - -/// Create an `InitializeImmutableOwner` instruction -pub fn initialize_immutable_owner( - token_program_id: &Pubkey, - token_account: &Pubkey, -) -> Result { - check_spl_token_program_account(token_program_id)?; - Ok(Instruction { - program_id: *token_program_id, - accounts: vec![AccountMeta::new(*token_account, false)], - data: TokenInstruction::InitializeImmutableOwner.pack(), - }) -} - -/// Creates an `AmountToUiAmount` instruction -pub fn amount_to_ui_amount( - token_program_id: &Pubkey, - mint_pubkey: &Pubkey, - amount: u64, -) -> Result { - check_spl_token_program_account(token_program_id)?; - - Ok(Instruction { - program_id: *token_program_id, - accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)], - data: TokenInstruction::AmountToUiAmount { amount }.pack(), - }) -} - -/// Creates a `UiAmountToAmount` instruction -pub fn ui_amount_to_amount( - token_program_id: &Pubkey, - mint_pubkey: &Pubkey, - ui_amount: &str, -) -> Result { - check_spl_token_program_account(token_program_id)?; - - Ok(Instruction { - program_id: *token_program_id, - accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)], - data: TokenInstruction::UiAmountToAmount { ui_amount }.pack(), - }) -} - -/// Creates a `Reallocate` instruction -pub fn reallocate( - token_program_id: &Pubkey, - account_pubkey: &Pubkey, - payer: &Pubkey, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - extension_types: &[ExtensionType], -) -> Result { - check_program_account(token_program_id)?; - - let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*account_pubkey, false)); - accounts.push(AccountMeta::new(*payer, true)); - accounts.push(AccountMeta::new_readonly(system_program::id(), false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data: TokenInstruction::Reallocate { - extension_types: extension_types.to_vec(), - } - .pack(), - }) -} - -/// Creates a `CreateNativeMint` instruction -pub fn create_native_mint( - token_program_id: &Pubkey, - payer: &Pubkey, -) -> Result { - check_program_account(token_program_id)?; - - Ok(Instruction { - program_id: *token_program_id, - accounts: vec![ - AccountMeta::new(*payer, true), - AccountMeta::new(crate::native_mint::id(), false), - AccountMeta::new_readonly(system_program::id(), false), - ], - data: TokenInstruction::CreateNativeMint.pack(), - }) -} - -/// Creates an `InitializeNonTransferableMint` instruction -pub fn initialize_non_transferable_mint( - token_program_id: &Pubkey, - mint_pubkey: &Pubkey, -) -> Result { - check_program_account(token_program_id)?; - Ok(Instruction { - program_id: *token_program_id, - accounts: vec![AccountMeta::new(*mint_pubkey, false)], - data: TokenInstruction::InitializeNonTransferableMint.pack(), - }) -} - -/// Utility function that checks index is between MIN_SIGNERS and MAX_SIGNERS -pub fn is_valid_signer_index(index: usize) -> bool { - (MIN_SIGNERS..=MAX_SIGNERS).contains(&index) -} - -/// Utility function for decoding just the instruction type -pub fn decode_instruction_type>(input: &[u8]) -> Result { - if input.is_empty() { - Err(ProgramError::InvalidInstructionData) - } else { - T::try_from(input[0]).map_err(|_| TokenError::InvalidInstruction.into()) - } -} - -/// Utility function for decoding instruction data -pub fn decode_instruction_data(input: &[u8]) -> Result<&T, ProgramError> { - if input.len() != pod_get_packed_len::().saturating_add(1) { - Err(ProgramError::InvalidInstructionData) - } else { - pod_from_bytes(&input[1..]) - } -} - -/// Utility function for encoding instruction data -pub(crate) fn encode_instruction, D: Pod>( - token_program_id: &Pubkey, - accounts: Vec, - token_instruction_type: TokenInstruction, - instruction_type: T, - instruction_data: &D, -) -> Instruction { - let mut data = token_instruction_type.pack(); - data.push(T::into(instruction_type)); - data.extend_from_slice(bytemuck::bytes_of(instruction_data)); - Instruction { - program_id: *token_program_id, - accounts, - data, - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_instruction_packing() { - let check = TokenInstruction::InitializeMint { - decimals: 2, - mint_authority: Pubkey::new(&[1u8; 32]), - freeze_authority: COption::None, - }; - let packed = check.pack(); - let mut expect = Vec::from([0u8, 2]); - expect.extend_from_slice(&[1u8; 32]); - expect.extend_from_slice(&[0]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::InitializeMint { - decimals: 2, - mint_authority: Pubkey::new(&[2u8; 32]), - freeze_authority: COption::Some(Pubkey::new(&[3u8; 32])), - }; - let packed = check.pack(); - let mut expect = vec![0u8, 2]; - expect.extend_from_slice(&[2u8; 32]); - expect.extend_from_slice(&[1]); - expect.extend_from_slice(&[3u8; 32]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::InitializeAccount; - let packed = check.pack(); - let expect = Vec::from([1u8]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::InitializeMultisig { m: 1 }; - let packed = check.pack(); - let expect = Vec::from([2u8, 1]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - #[allow(deprecated)] - let check = TokenInstruction::Transfer { amount: 1 }; - let packed = check.pack(); - let expect = Vec::from([3u8, 1, 0, 0, 0, 0, 0, 0, 0]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::Approve { amount: 1 }; - let packed = check.pack(); - let expect = Vec::from([4u8, 1, 0, 0, 0, 0, 0, 0, 0]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::Revoke; - let packed = check.pack(); - let expect = Vec::from([5u8]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::SetAuthority { - authority_type: AuthorityType::FreezeAccount, - new_authority: COption::Some(Pubkey::new(&[4u8; 32])), - }; - let packed = check.pack(); - let mut expect = Vec::from([6u8, 1]); - expect.extend_from_slice(&[1]); - expect.extend_from_slice(&[4u8; 32]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::MintTo { amount: 1 }; - let packed = check.pack(); - let expect = Vec::from([7u8, 1, 0, 0, 0, 0, 0, 0, 0]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::Burn { amount: 1 }; - let packed = check.pack(); - let expect = Vec::from([8u8, 1, 0, 0, 0, 0, 0, 0, 0]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::CloseAccount; - let packed = check.pack(); - let expect = Vec::from([9u8]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::FreezeAccount; - let packed = check.pack(); - let expect = Vec::from([10u8]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::ThawAccount; - let packed = check.pack(); - let expect = Vec::from([11u8]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::TransferChecked { - amount: 1, - decimals: 2, - }; - let packed = check.pack(); - let expect = Vec::from([12u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::ApproveChecked { - amount: 1, - decimals: 2, - }; - let packed = check.pack(); - let expect = Vec::from([13u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::MintToChecked { - amount: 1, - decimals: 2, - }; - let packed = check.pack(); - let expect = Vec::from([14u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::BurnChecked { - amount: 1, - decimals: 2, - }; - let packed = check.pack(); - let expect = Vec::from([15u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::InitializeAccount2 { - owner: Pubkey::new(&[2u8; 32]), - }; - let packed = check.pack(); - let mut expect = vec![16u8]; - expect.extend_from_slice(&[2u8; 32]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::SyncNative; - let packed = check.pack(); - let expect = vec![17u8]; - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::InitializeAccount3 { - owner: Pubkey::new(&[2u8; 32]), - }; - let packed = check.pack(); - let mut expect = vec![18u8]; - expect.extend_from_slice(&[2u8; 32]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::InitializeMultisig2 { m: 1 }; - let packed = check.pack(); - let expect = Vec::from([19u8, 1]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::InitializeMint2 { - decimals: 2, - mint_authority: Pubkey::new(&[1u8; 32]), - freeze_authority: COption::None, - }; - let packed = check.pack(); - let mut expect = Vec::from([20u8, 2]); - expect.extend_from_slice(&[1u8; 32]); - expect.extend_from_slice(&[0]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::InitializeMint2 { - decimals: 2, - mint_authority: Pubkey::new(&[2u8; 32]), - freeze_authority: COption::Some(Pubkey::new(&[3u8; 32])), - }; - let packed = check.pack(); - let mut expect = vec![20u8, 2]; - expect.extend_from_slice(&[2u8; 32]); - expect.extend_from_slice(&[1]); - expect.extend_from_slice(&[3u8; 32]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::GetAccountDataSize { - extension_types: vec![], - }; - let packed = check.pack(); - let expect = [21u8]; - assert_eq!(packed, &[21u8]); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::GetAccountDataSize { - extension_types: vec![ - ExtensionType::TransferFeeConfig, - ExtensionType::TransferFeeAmount, - ], - }; - let packed = check.pack(); - let expect = [21u8, 1, 0, 2, 0]; - assert_eq!(packed, &[21u8, 1, 0, 2, 0]); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::AmountToUiAmount { amount: 42 }; - let packed = check.pack(); - let expect = vec![23u8, 42, 0, 0, 0, 0, 0, 0, 0]; - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::UiAmountToAmount { ui_amount: "0.42" }; - let packed = check.pack(); - let expect = vec![24u8, 48, 46, 52, 50]; - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::InitializeMintCloseAuthority { - close_authority: COption::Some(Pubkey::new(&[10u8; 32])), - }; - let packed = check.pack(); - let mut expect = vec![25u8, 1]; - expect.extend_from_slice(&[10u8; 32]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::CreateNativeMint; - let packed = check.pack(); - let expect = vec![31u8]; - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - } - - macro_rules! test_instruction { - ($a:ident($($b:tt)*)) => { - let instruction_v3 = spl_token::instruction::$a($($b)*).unwrap(); - let instruction_2022 = $a($($b)*).unwrap(); - assert_eq!(instruction_v3, instruction_2022); - } - } - - #[test] - fn test_v3_compatibility() { - let token_program_id = spl_token::id(); - let mint_pubkey = Pubkey::new_unique(); - let mint_authority_pubkey = Pubkey::new_unique(); - let freeze_authority_pubkey = Pubkey::new_unique(); - let decimals = 9u8; - - let account_pubkey = Pubkey::new_unique(); - let owner_pubkey = Pubkey::new_unique(); - - let multisig_pubkey = Pubkey::new_unique(); - let signer_pubkeys_vec = vec![Pubkey::new_unique(); MAX_SIGNERS]; - let signer_pubkeys = signer_pubkeys_vec.iter().collect::>(); - let m = 10u8; - - let source_pubkey = Pubkey::new_unique(); - let destination_pubkey = Pubkey::new_unique(); - let authority_pubkey = Pubkey::new_unique(); - let amount = 1_000_000_000_000; - - let delegate_pubkey = Pubkey::new_unique(); - let owned_pubkey = Pubkey::new_unique(); - let new_authority_pubkey = Pubkey::new_unique(); - - let ui_amount = "100000.00"; - - test_instruction!(initialize_mint( - &token_program_id, - &mint_pubkey, - &mint_authority_pubkey, - None, - decimals, - )); - test_instruction!(initialize_mint2( - &token_program_id, - &mint_pubkey, - &mint_authority_pubkey, - Some(&freeze_authority_pubkey), - decimals, - )); - - test_instruction!(initialize_account( - &token_program_id, - &account_pubkey, - &mint_pubkey, - &owner_pubkey, - )); - test_instruction!(initialize_account2( - &token_program_id, - &account_pubkey, - &mint_pubkey, - &owner_pubkey, - )); - test_instruction!(initialize_account3( - &token_program_id, - &account_pubkey, - &mint_pubkey, - &owner_pubkey, - )); - test_instruction!(initialize_multisig( - &token_program_id, - &multisig_pubkey, - &signer_pubkeys, - m, - )); - test_instruction!(initialize_multisig2( - &token_program_id, - &multisig_pubkey, - &signer_pubkeys, - m, - )); - #[allow(deprecated)] - { - test_instruction!(transfer( - &token_program_id, - &source_pubkey, - &destination_pubkey, - &authority_pubkey, - &signer_pubkeys, - amount - )); - } - test_instruction!(transfer_checked( - &token_program_id, - &source_pubkey, - &mint_pubkey, - &destination_pubkey, - &authority_pubkey, - &signer_pubkeys, - amount, - decimals, - )); - test_instruction!(approve( - &token_program_id, - &source_pubkey, - &delegate_pubkey, - &owner_pubkey, - &signer_pubkeys, - amount - )); - test_instruction!(approve_checked( - &token_program_id, - &source_pubkey, - &mint_pubkey, - &delegate_pubkey, - &owner_pubkey, - &signer_pubkeys, - amount, - decimals - )); - test_instruction!(revoke( - &token_program_id, - &source_pubkey, - &owner_pubkey, - &signer_pubkeys, - )); - - // set_authority - { - let instruction_v3 = spl_token::instruction::set_authority( - &token_program_id, - &owned_pubkey, - Some(&new_authority_pubkey), - spl_token::instruction::AuthorityType::AccountOwner, - &owner_pubkey, - &signer_pubkeys, - ) - .unwrap(); - let instruction_2022 = set_authority( - &token_program_id, - &owned_pubkey, - Some(&new_authority_pubkey), - AuthorityType::AccountOwner, - &owner_pubkey, - &signer_pubkeys, - ) - .unwrap(); - assert_eq!(instruction_v3, instruction_2022); - } - - test_instruction!(mint_to( - &token_program_id, - &mint_pubkey, - &account_pubkey, - &owner_pubkey, - &signer_pubkeys, - amount, - )); - test_instruction!(mint_to_checked( - &token_program_id, - &mint_pubkey, - &account_pubkey, - &owner_pubkey, - &signer_pubkeys, - amount, - decimals, - )); - test_instruction!(burn( - &token_program_id, - &account_pubkey, - &mint_pubkey, - &authority_pubkey, - &signer_pubkeys, - amount, - )); - test_instruction!(burn_checked( - &token_program_id, - &account_pubkey, - &mint_pubkey, - &authority_pubkey, - &signer_pubkeys, - amount, - decimals, - )); - test_instruction!(close_account( - &token_program_id, - &account_pubkey, - &destination_pubkey, - &owner_pubkey, - &signer_pubkeys, - )); - test_instruction!(freeze_account( - &token_program_id, - &account_pubkey, - &mint_pubkey, - &owner_pubkey, - &signer_pubkeys, - )); - test_instruction!(thaw_account( - &token_program_id, - &account_pubkey, - &mint_pubkey, - &owner_pubkey, - &signer_pubkeys, - )); - test_instruction!(sync_native(&token_program_id, &account_pubkey,)); - - // get_account_data_size - { - let instruction_v3 = - spl_token::instruction::get_account_data_size(&token_program_id, &mint_pubkey) - .unwrap(); - let instruction_2022 = - get_account_data_size(&token_program_id, &mint_pubkey, &[]).unwrap(); - assert_eq!(instruction_v3, instruction_2022); - } - - test_instruction!(initialize_immutable_owner( - &token_program_id, - &account_pubkey, - )); - - test_instruction!(amount_to_ui_amount(&token_program_id, &mint_pubkey, amount,)); - - test_instruction!(ui_amount_to_amount( - &token_program_id, - &mint_pubkey, - ui_amount, - )); - } -} diff --git a/token/program-2022/src/lib.rs b/token/program-2022/src/lib.rs deleted file mode 100644 index 48fe4a559a7..00000000000 --- a/token/program-2022/src/lib.rs +++ /dev/null @@ -1,112 +0,0 @@ -#![deny(missing_docs)] -#![cfg_attr(not(test), forbid(unsafe_code))] - -//! An ERC20-like Token program for the Solana blockchain - -pub mod error; -pub mod extension; -pub mod generic_token_account; -pub mod instruction; -pub mod native_mint; -pub mod pod; -pub mod processor; -#[cfg(feature = "serde-traits")] -pub mod serialization; -pub mod state; - -#[cfg(not(feature = "no-entrypoint"))] -mod entrypoint; - -// Export current sdk types for downstream users building with a different sdk version -pub use solana_program; -use solana_program::{ - entrypoint::ProgramResult, - program_error::ProgramError, - program_memory::sol_memcmp, - pubkey::{Pubkey, PUBKEY_BYTES}, -}; -pub use solana_zk_token_sdk; - -/// Convert the UI representation of a token amount (using the decimals field defined in its mint) -/// to the raw amount -pub fn ui_amount_to_amount(ui_amount: f64, decimals: u8) -> u64 { - (ui_amount * 10_usize.pow(decimals as u32) as f64) as u64 -} - -/// Convert a raw amount to its UI representation (using the decimals field defined in its mint) -pub fn amount_to_ui_amount(amount: u64, decimals: u8) -> f64 { - amount as f64 / 10_usize.pow(decimals as u32) as f64 -} - -/// Convert a raw amount to its UI representation (using the decimals field defined in its mint) -pub fn amount_to_ui_amount_string(amount: u64, decimals: u8) -> String { - let decimals = decimals as usize; - if decimals > 0 { - // Left-pad zeros to decimals + 1, so we at least have an integer zero - let mut s = format!("{:01$}", amount, decimals + 1); - // Add the decimal point (Sorry, "," locales!) - s.insert(s.len() - decimals, '.'); - s - } else { - amount.to_string() - } -} - -/// Convert a raw amount to its UI representation using the given decimals field -/// Excess zeroes or unneeded decimal point are trimmed. -pub fn amount_to_ui_amount_string_trimmed(amount: u64, decimals: u8) -> String { - let mut s = amount_to_ui_amount_string(amount, decimals); - if decimals > 0 { - let zeros_trimmed = s.trim_end_matches('0'); - s = zeros_trimmed.trim_end_matches('.').to_string(); - } - s -} - -/// Try to convert a UI represenation of a token amount to its raw amount using the given decimals -/// field -pub fn try_ui_amount_into_amount(ui_amount: String, decimals: u8) -> Result { - let decimals = decimals as usize; - let mut parts = ui_amount.split('.'); - let mut amount_str = parts.next().unwrap().to_string(); // splitting a string, even an empty one, will always yield an iterator of at least len == 1 - let after_decimal = parts.next().unwrap_or(""); - let after_decimal = after_decimal.trim_end_matches('0'); - if (amount_str.is_empty() && after_decimal.is_empty()) - || parts.next().is_some() - || after_decimal.len() > decimals - { - return Err(ProgramError::InvalidArgument); - } - - amount_str.push_str(after_decimal); - for _ in 0..decimals.saturating_sub(after_decimal.len()) { - amount_str.push('0'); - } - amount_str - .parse::() - .map_err(|_| ProgramError::InvalidArgument) -} - -solana_program::declare_id!("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"); - -/// Checks that the supplied program ID is correct for spl-token-2022 -pub fn check_program_account(spl_token_program_id: &Pubkey) -> ProgramResult { - if spl_token_program_id != &id() { - return Err(ProgramError::IncorrectProgramId); - } - Ok(()) -} - -/// Checks that the supplied program ID is corect for spl-token or spl-token-2022 -pub fn check_spl_token_program_account(spl_token_program_id: &Pubkey) -> ProgramResult { - if spl_token_program_id != &id() && spl_token_program_id != &spl_token::id() { - return Err(ProgramError::IncorrectProgramId); - } - Ok(()) -} - -/// Checks two pubkeys for equality in a computationally cheap way using -/// `sol_memcmp` -pub fn cmp_pubkeys(a: &Pubkey, b: &Pubkey) -> bool { - sol_memcmp(a.as_ref(), b.as_ref(), PUBKEY_BYTES) == 0 -} diff --git a/token/program-2022/src/native_mint.rs b/token/program-2022/src/native_mint.rs deleted file mode 100644 index 48c993b0786..00000000000 --- a/token/program-2022/src/native_mint.rs +++ /dev/null @@ -1,36 +0,0 @@ -//! The Mint that represents the native token - -/// There are 10^9 lamports in one SOL -pub const DECIMALS: u8 = 9; - -// The Mint for native SOL Token accounts -solana_program::declare_id!("9pan9bMn5HatX4EJdBwg9VgCa7Uz5HL8N1m5D3NdXejP"); - -/// Seed for the native_mint's program-derived address -pub const PROGRAM_ADDRESS_SEEDS: &[&[u8]] = &["native-mint".as_bytes(), &[255]]; - -#[cfg(test)] -mod tests { - use { - super::*, - solana_program::{native_token::*, pubkey::Pubkey}, - }; - - #[test] - fn test_decimals() { - assert!( - (lamports_to_sol(42) - crate::amount_to_ui_amount(42, DECIMALS)).abs() < f64::EPSILON - ); - assert_eq!( - sol_to_lamports(42.), - crate::ui_amount_to_amount(42., DECIMALS) - ); - } - - #[test] - fn expected_native_mint_id() { - let native_mint_id = - Pubkey::create_program_address(PROGRAM_ADDRESS_SEEDS, &crate::id()).unwrap(); - assert_eq!(id(), native_mint_id); - } -} diff --git a/token/program-2022/src/pod.rs b/token/program-2022/src/pod.rs deleted file mode 100644 index d04a77c92f8..00000000000 --- a/token/program-2022/src/pod.rs +++ /dev/null @@ -1,197 +0,0 @@ -//! Solana program utilities for Plain Old Data types -use { - bytemuck::{Pod, Zeroable}, - solana_program::{program_error::ProgramError, program_option::COption, pubkey::Pubkey}, - std::convert::TryFrom, -}; - -/// A Pubkey that encodes `None` as all `0`, meant to be usable as a Pod type, -/// similar to all NonZero* number types from the bytemuck library. -#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] -#[repr(transparent)] -pub struct OptionalNonZeroPubkey(Pubkey); -impl TryFrom> for OptionalNonZeroPubkey { - type Error = ProgramError; - fn try_from(p: Option) -> Result { - match p { - None => Ok(Self(Pubkey::default())), - Some(pubkey) => { - if pubkey == Pubkey::default() { - Err(ProgramError::InvalidArgument) - } else { - Ok(Self(pubkey)) - } - } - } - } -} -impl TryFrom> for OptionalNonZeroPubkey { - type Error = ProgramError; - fn try_from(p: COption) -> Result { - match p { - COption::None => Ok(Self(Pubkey::default())), - COption::Some(pubkey) => { - if pubkey == Pubkey::default() { - Err(ProgramError::InvalidArgument) - } else { - Ok(Self(pubkey)) - } - } - } - } -} -impl From for Option { - fn from(p: OptionalNonZeroPubkey) -> Self { - if p.0 == Pubkey::default() { - None - } else { - Some(p.0) - } - } -} -impl From for COption { - fn from(p: OptionalNonZeroPubkey) -> Self { - if p.0 == Pubkey::default() { - COption::None - } else { - COption::Some(p.0) - } - } -} - -/// The standard `bool` is not a `Pod`, define a replacement that is -#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] -#[repr(transparent)] -pub struct PodBool(u8); -impl From for PodBool { - fn from(b: bool) -> Self { - Self(if b { 1 } else { 0 }) - } -} -impl From<&PodBool> for bool { - fn from(b: &PodBool) -> Self { - b.0 != 0 - } -} - -impl From for bool { - fn from(b: PodBool) -> Self { - b.0 != 0 - } -} - -/// Simple macro for implementing conversion functions between Pod* ints and standard ints. -/// -/// The standard int types can cause alignment issues when placed in a `Pod`, -/// so these replacements are usable in all `Pod`s. -macro_rules! impl_int_conversion { - ($P:ty, $I:ty) => { - impl From<$I> for $P { - fn from(n: $I) -> Self { - Self(n.to_le_bytes()) - } - } - impl From<$P> for $I { - fn from(pod: $P) -> Self { - Self::from_le_bytes(pod.0) - } - } - }; -} - -/// `u16` type that can be used in `Pod`s -#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] -#[repr(transparent)] -pub struct PodU16([u8; 2]); -impl_int_conversion!(PodU16, u16); - -/// `i16` type that can be used in `Pod`s -#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] -#[repr(transparent)] -pub struct PodI16([u8; 2]); -impl_int_conversion!(PodI16, i16); - -/// `u64` type that can be used in `Pod`s -#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] -#[repr(transparent)] -pub struct PodU64([u8; 8]); -impl_int_conversion!(PodU64, u64); - -/// `i64` type that can be used in `Pod`s -#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] -#[repr(transparent)] -pub struct PodI64([u8; 8]); -impl_int_conversion!(PodI64, i64); - -/// On-chain size of a `Pod` type -pub fn pod_get_packed_len() -> usize { - std::mem::size_of::() -} - -/// Convert a `Pod` into a slice (zero copy) -pub fn pod_bytes_of(t: &T) -> &[u8] { - bytemuck::bytes_of(t) -} - -/// Convert a slice into a `Pod` (zero copy) -pub fn pod_from_bytes(bytes: &[u8]) -> Result<&T, ProgramError> { - bytemuck::try_from_bytes(bytes).map_err(|_| ProgramError::InvalidArgument) -} - -/// Maybe convert a slice into a `Pod` (zero copy) -/// -/// Returns `None` if the slice is empty, but `Err` if all other lengths but `get_packed_len()` -/// This function exists primarily because `Option` is not a `Pod`. -pub fn pod_maybe_from_bytes(bytes: &[u8]) -> Result, ProgramError> { - if bytes.is_empty() { - Ok(None) - } else { - bytemuck::try_from_bytes(bytes) - .map(Some) - .map_err(|_| ProgramError::InvalidArgument) - } -} - -/// Convert a slice into a mutable `Pod` (zero copy) -pub fn pod_from_bytes_mut(bytes: &mut [u8]) -> Result<&mut T, ProgramError> { - bytemuck::try_from_bytes_mut(bytes).map_err(|_| ProgramError::InvalidArgument) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_pod_bool() { - assert!(pod_from_bytes::(&[]).is_err()); - assert!(pod_from_bytes::(&[0, 0]).is_err()); - - for i in 0..=u8::MAX { - assert_eq!(i != 0, bool::from(pod_from_bytes::(&[i]).unwrap())); - } - } - - #[test] - fn test_pod_u64() { - assert!(pod_from_bytes::(&[]).is_err()); - assert_eq!( - 1u64, - u64::from(*pod_from_bytes::(&[1, 0, 0, 0, 0, 0, 0, 0]).unwrap()) - ); - } - - #[test] - fn test_pod_option() { - assert_eq!( - Some(Pubkey::new_from_array([1; 32])), - Option::::from(*pod_from_bytes::(&[1; 32]).unwrap()) - ); - assert_eq!( - None, - Option::::from(*pod_from_bytes::(&[0; 32]).unwrap()) - ); - assert!(pod_from_bytes::(&[]).is_err()); - assert!(pod_from_bytes::(&[0; 1]).is_err()); - assert!(pod_from_bytes::(&[1; 1]).is_err()); - } -} diff --git a/token/program-2022/src/processor.rs b/token/program-2022/src/processor.rs deleted file mode 100644 index 6e3907dcc73..00000000000 --- a/token/program-2022/src/processor.rs +++ /dev/null @@ -1,7332 +0,0 @@ -//! Program state processor - -use { - crate::{ - check_program_account, cmp_pubkeys, - error::TokenError, - extension::{ - confidential_transfer::{self, ConfidentialTransferAccount}, - default_account_state::{self, DefaultAccountState}, - immutable_owner::ImmutableOwner, - interest_bearing_mint::{self, InterestBearingConfig}, - memo_transfer::{self, check_previous_sibling_instruction_is_memo, memo_required}, - mint_close_authority::MintCloseAuthority, - non_transferable::NonTransferable, - reallocate, - transfer_fee::{self, TransferFeeAmount, TransferFeeConfig}, - ExtensionType, StateWithExtensions, StateWithExtensionsMut, - }, - instruction::{is_valid_signer_index, AuthorityType, TokenInstruction, MAX_SIGNERS}, - native_mint, - state::{Account, AccountState, Mint, Multisig}, - }, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - clock::Clock, - entrypoint::ProgramResult, - msg, - program::{invoke, invoke_signed, set_return_data}, - program_error::ProgramError, - program_option::COption, - program_pack::Pack, - pubkey::Pubkey, - system_instruction, system_program, - sysvar::{rent::Rent, Sysvar}, - }, - std::convert::{TryFrom, TryInto}, -}; - -/// Program state handler. -pub struct Processor {} -impl Processor { - fn _process_initialize_mint( - accounts: &[AccountInfo], - decimals: u8, - mint_authority: Pubkey, - freeze_authority: COption, - rent_sysvar_account: bool, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_info = next_account_info(account_info_iter)?; - let mint_data_len = mint_info.data_len(); - let mut mint_data = mint_info.data.borrow_mut(); - let rent = if rent_sysvar_account { - Rent::from_account_info(next_account_info(account_info_iter)?)? - } else { - Rent::get()? - }; - - if !rent.is_exempt(mint_info.lamports(), mint_data_len) { - return Err(TokenError::NotRentExempt.into()); - } - - let mut mint = StateWithExtensionsMut::::unpack_uninitialized(&mut mint_data)?; - if mint.base.is_initialized { - return Err(TokenError::AlreadyInUse.into()); - } - - let extension_types = mint.get_extension_types()?; - if ExtensionType::get_account_len::(&extension_types) != mint_data_len { - return Err(ProgramError::InvalidAccountData); - } - - if let Ok(default_account_state) = mint.get_extension_mut::() { - let default_account_state = AccountState::try_from(default_account_state.state) - .or(Err(ProgramError::InvalidAccountData))?; - if default_account_state == AccountState::Frozen && freeze_authority.is_none() { - return Err(TokenError::MintCannotFreeze.into()); - } - } - - mint.base.mint_authority = COption::Some(mint_authority); - mint.base.decimals = decimals; - mint.base.is_initialized = true; - mint.base.freeze_authority = freeze_authority; - mint.pack_base(); - mint.init_account_type()?; - - Ok(()) - } - - /// Processes an [InitializeMint](enum.TokenInstruction.html) instruction. - pub fn process_initialize_mint( - accounts: &[AccountInfo], - decimals: u8, - mint_authority: Pubkey, - freeze_authority: COption, - ) -> ProgramResult { - Self::_process_initialize_mint(accounts, decimals, mint_authority, freeze_authority, true) - } - - /// Processes an [InitializeMint2](enum.TokenInstruction.html) instruction. - pub fn process_initialize_mint2( - accounts: &[AccountInfo], - decimals: u8, - mint_authority: Pubkey, - freeze_authority: COption, - ) -> ProgramResult { - Self::_process_initialize_mint(accounts, decimals, mint_authority, freeze_authority, false) - } - - fn _process_initialize_account( - accounts: &[AccountInfo], - owner: Option<&Pubkey>, - rent_sysvar_account: bool, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let new_account_info = next_account_info(account_info_iter)?; - let mint_info = next_account_info(account_info_iter)?; - let owner = if let Some(owner) = owner { - owner - } else { - next_account_info(account_info_iter)?.key - }; - let new_account_info_data_len = new_account_info.data_len(); - let rent = if rent_sysvar_account { - Rent::from_account_info(next_account_info(account_info_iter)?)? - } else { - Rent::get()? - }; - - let mut account_data = new_account_info.data.borrow_mut(); - // unpack_uninitialized checks account.base.is_initialized() under the hood - let mut account = - StateWithExtensionsMut::::unpack_uninitialized(&mut account_data)?; - - if !rent.is_exempt(new_account_info.lamports(), new_account_info_data_len) { - return Err(TokenError::NotRentExempt.into()); - } - - // get_required_account_extensions checks mint validity - let mint_data = mint_info.data.borrow(); - let mint = StateWithExtensions::::unpack(&mint_data) - .map_err(|_| Into::::into(TokenError::InvalidMint))?; - let required_extensions = - Self::get_required_account_extensions_from_unpacked_mint(mint_info.owner, &mint)?; - if ExtensionType::get_account_len::(&required_extensions) - > new_account_info_data_len - { - return Err(ProgramError::InvalidAccountData); - } - for extension in required_extensions { - account.init_account_extension_from_type(extension)?; - } - - let starting_state = - if let Ok(default_account_state) = mint.get_extension::() { - AccountState::try_from(default_account_state.state) - .or(Err(ProgramError::InvalidAccountData))? - } else { - AccountState::Initialized - }; - - account.base.mint = *mint_info.key; - account.base.owner = *owner; - account.base.close_authority = COption::None; - account.base.delegate = COption::None; - account.base.delegated_amount = 0; - account.base.state = starting_state; - if cmp_pubkeys(mint_info.key, &native_mint::id()) { - let rent_exempt_reserve = rent.minimum_balance(new_account_info_data_len); - account.base.is_native = COption::Some(rent_exempt_reserve); - account.base.amount = new_account_info - .lamports() - .checked_sub(rent_exempt_reserve) - .ok_or(TokenError::Overflow)?; - } else { - account.base.is_native = COption::None; - account.base.amount = 0; - }; - - account.pack_base(); - account.init_account_type()?; - - Ok(()) - } - - /// Processes an [InitializeAccount](enum.TokenInstruction.html) instruction. - pub fn process_initialize_account(accounts: &[AccountInfo]) -> ProgramResult { - Self::_process_initialize_account(accounts, None, true) - } - - /// Processes an [InitializeAccount2](enum.TokenInstruction.html) instruction. - pub fn process_initialize_account2(accounts: &[AccountInfo], owner: Pubkey) -> ProgramResult { - Self::_process_initialize_account(accounts, Some(&owner), true) - } - - /// Processes an [InitializeAccount3](enum.TokenInstruction.html) instruction. - pub fn process_initialize_account3(accounts: &[AccountInfo], owner: Pubkey) -> ProgramResult { - Self::_process_initialize_account(accounts, Some(&owner), false) - } - - fn _process_initialize_multisig( - accounts: &[AccountInfo], - m: u8, - rent_sysvar_account: bool, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let multisig_info = next_account_info(account_info_iter)?; - let multisig_info_data_len = multisig_info.data_len(); - let rent = if rent_sysvar_account { - Rent::from_account_info(next_account_info(account_info_iter)?)? - } else { - Rent::get()? - }; - - let mut multisig = Multisig::unpack_unchecked(&multisig_info.data.borrow())?; - if multisig.is_initialized { - return Err(TokenError::AlreadyInUse.into()); - } - - if !rent.is_exempt(multisig_info.lamports(), multisig_info_data_len) { - return Err(TokenError::NotRentExempt.into()); - } - - let signer_infos = account_info_iter.as_slice(); - multisig.m = m; - multisig.n = signer_infos.len() as u8; - if !is_valid_signer_index(multisig.n as usize) { - return Err(TokenError::InvalidNumberOfProvidedSigners.into()); - } - if !is_valid_signer_index(multisig.m as usize) { - return Err(TokenError::InvalidNumberOfRequiredSigners.into()); - } - for (i, signer_info) in signer_infos.iter().enumerate() { - multisig.signers[i] = *signer_info.key; - } - multisig.is_initialized = true; - - Multisig::pack(multisig, &mut multisig_info.data.borrow_mut())?; - - Ok(()) - } - - /// Processes a [InitializeMultisig](enum.TokenInstruction.html) instruction. - pub fn process_initialize_multisig(accounts: &[AccountInfo], m: u8) -> ProgramResult { - Self::_process_initialize_multisig(accounts, m, true) - } - - /// Processes a [InitializeMultisig2](enum.TokenInstruction.html) instruction. - pub fn process_initialize_multisig2(accounts: &[AccountInfo], m: u8) -> ProgramResult { - Self::_process_initialize_multisig(accounts, m, false) - } - - /// Processes a [Transfer](enum.TokenInstruction.html) instruction. - pub fn process_transfer( - program_id: &Pubkey, - accounts: &[AccountInfo], - amount: u64, - expected_decimals: Option, - expected_fee: Option, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - - let source_account_info = next_account_info(account_info_iter)?; - - let expected_mint_info = if let Some(expected_decimals) = expected_decimals { - Some((next_account_info(account_info_iter)?, expected_decimals)) - } else { - None - }; - - let destination_account_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - let authority_info_data_len = authority_info.data_len(); - - let mut source_account_data = source_account_info.data.borrow_mut(); - let mut source_account = - StateWithExtensionsMut::::unpack(&mut source_account_data)?; - if source_account.base.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - if source_account.base.amount < amount { - return Err(TokenError::InsufficientFunds.into()); - } - let fee = if let Some((mint_info, expected_decimals)) = expected_mint_info { - if !cmp_pubkeys(&source_account.base.mint, mint_info.key) { - return Err(TokenError::MintMismatch.into()); - } - - let mint_data = mint_info.try_borrow_data()?; - let mint = StateWithExtensions::::unpack(&mint_data)?; - - if mint.get_extension::().is_ok() { - return Err(TokenError::NonTransferable.into()); - } - - if expected_decimals != mint.base.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); - } - - if let Ok(transfer_fee_config) = mint.get_extension::() { - transfer_fee_config - .calculate_epoch_fee(Clock::get()?.epoch, amount) - .ok_or(TokenError::Overflow)? - } else { - 0 - } - } else { - // Transfer fee amount extension exists on the account, but no mint - // was provided to calculate the fee, abort - if source_account - .get_extension_mut::() - .is_ok() - { - return Err(TokenError::MintRequiredForTransfer.into()); - } else { - 0 - } - }; - if let Some(expected_fee) = expected_fee { - if expected_fee != fee { - msg!("Calculated fee {}, received {}", fee, expected_fee); - return Err(TokenError::FeeMismatch.into()); - } - } - - let self_transfer = cmp_pubkeys(source_account_info.key, destination_account_info.key); - match source_account.base.delegate { - COption::Some(ref delegate) if cmp_pubkeys(authority_info.key, delegate) => { - Self::validate_owner( - program_id, - delegate, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?; - if source_account.base.delegated_amount < amount { - return Err(TokenError::InsufficientFunds.into()); - } - if !self_transfer { - source_account.base.delegated_amount = source_account - .base - .delegated_amount - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - if source_account.base.delegated_amount == 0 { - source_account.base.delegate = COption::None; - } - } - } - _ => Self::validate_owner( - program_id, - &source_account.base.owner, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?, - }; - - // Revisit this later to see if it's worth adding a check to reduce - // compute costs, ie: - // if self_transfer || amount == 0 - check_program_account(source_account_info.owner)?; - check_program_account(destination_account_info.owner)?; - - // This check MUST occur just before the amounts are manipulated - // to ensure self-transfers are fully validated - if self_transfer { - return Ok(()); - } - - // self-transfer was dealt with earlier, so this *should* be safe - let mut destination_account_data = destination_account_info.data.borrow_mut(); - let mut destination_account = - StateWithExtensionsMut::::unpack(&mut destination_account_data)?; - - if destination_account.base.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - if !cmp_pubkeys(&source_account.base.mint, &destination_account.base.mint) { - return Err(TokenError::MintMismatch.into()); - } - - if memo_required(&destination_account) { - check_previous_sibling_instruction_is_memo()?; - } - - source_account.base.amount = source_account - .base - .amount - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - let credited_amount = amount.checked_sub(fee).ok_or(TokenError::Overflow)?; - destination_account.base.amount = destination_account - .base - .amount - .checked_add(credited_amount) - .ok_or(TokenError::Overflow)?; - if fee > 0 { - if let Ok(extension) = destination_account.get_extension_mut::() { - let new_withheld_amount = u64::from(extension.withheld_amount) - .checked_add(fee) - .ok_or(TokenError::Overflow)?; - extension.withheld_amount = new_withheld_amount.into(); - } else { - // Use the generic error since this should never happen. If there's - // a fee, then the mint has a fee configured, which means all accounts - // must have the withholding. - return Err(TokenError::InvalidState.into()); - } - } - - if source_account.base.is_native() { - let source_starting_lamports = source_account_info.lamports(); - **source_account_info.lamports.borrow_mut() = source_starting_lamports - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - - let destination_starting_lamports = destination_account_info.lamports(); - **destination_account_info.lamports.borrow_mut() = destination_starting_lamports - .checked_add(amount) - .ok_or(TokenError::Overflow)?; - } - - source_account.pack_base(); - destination_account.pack_base(); - - Ok(()) - } - - /// Processes an [Approve](enum.TokenInstruction.html) instruction. - pub fn process_approve( - program_id: &Pubkey, - accounts: &[AccountInfo], - amount: u64, - expected_decimals: Option, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - - let source_account_info = next_account_info(account_info_iter)?; - - let expected_mint_info = if let Some(expected_decimals) = expected_decimals { - Some((next_account_info(account_info_iter)?, expected_decimals)) - } else { - None - }; - let delegate_info = next_account_info(account_info_iter)?; - let owner_info = next_account_info(account_info_iter)?; - let owner_info_data_len = owner_info.data_len(); - - let mut source_account_data = source_account_info.data.borrow_mut(); - let mut source_account = - StateWithExtensionsMut::::unpack(&mut source_account_data)?; - - if source_account.base.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - - if let Some((mint_info, expected_decimals)) = expected_mint_info { - if !cmp_pubkeys(&source_account.base.mint, mint_info.key) { - return Err(TokenError::MintMismatch.into()); - } - - let mint_data = mint_info.data.borrow(); - let mint = StateWithExtensions::::unpack(&mint_data)?; - if expected_decimals != mint.base.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); - } - } - - Self::validate_owner( - program_id, - &source_account.base.owner, - owner_info, - owner_info_data_len, - account_info_iter.as_slice(), - )?; - - source_account.base.delegate = COption::Some(*delegate_info.key); - source_account.base.delegated_amount = amount; - source_account.pack_base(); - - Ok(()) - } - - /// Processes an [Revoke](enum.TokenInstruction.html) instruction. - pub fn process_revoke(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let source_account_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - let authority_info_data_len = authority_info.data_len(); - - let mut source_account_data = source_account_info.data.borrow_mut(); - let mut source_account = - StateWithExtensionsMut::::unpack(&mut source_account_data)?; - if source_account.base.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - - Self::validate_owner( - program_id, - match source_account.base.delegate { - COption::Some(ref delegate) if cmp_pubkeys(authority_info.key, delegate) => { - delegate - } - _ => &source_account.base.owner, - }, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?; - - source_account.base.delegate = COption::None; - source_account.base.delegated_amount = 0; - source_account.pack_base(); - - Ok(()) - } - - /// Processes a [SetAuthority](enum.TokenInstruction.html) instruction. - pub fn process_set_authority( - program_id: &Pubkey, - accounts: &[AccountInfo], - authority_type: AuthorityType, - new_authority: COption, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let account_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - let authority_info_data_len = authority_info.data_len(); - - let mut account_data = account_info.data.borrow_mut(); - if let Ok(mut account) = StateWithExtensionsMut::::unpack(&mut account_data) { - if account.base.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - - match authority_type { - AuthorityType::AccountOwner => { - Self::validate_owner( - program_id, - &account.base.owner, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?; - - if account.get_extension_mut::().is_ok() { - return Err(TokenError::ImmutableOwner.into()); - } - - if let COption::Some(authority) = new_authority { - account.base.owner = authority; - } else { - return Err(TokenError::InvalidInstruction.into()); - } - - account.base.delegate = COption::None; - account.base.delegated_amount = 0; - - if account.base.is_native() { - account.base.close_authority = COption::None; - } - } - AuthorityType::CloseAccount => { - let authority = account.base.close_authority.unwrap_or(account.base.owner); - Self::validate_owner( - program_id, - &authority, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?; - account.base.close_authority = new_authority; - } - _ => { - return Err(TokenError::AuthorityTypeNotSupported.into()); - } - } - account.pack_base(); - } else if let Ok(mut mint) = StateWithExtensionsMut::::unpack(&mut account_data) { - match authority_type { - AuthorityType::MintTokens => { - // Once a mint's supply is fixed, it cannot be undone by setting a new - // mint_authority - let mint_authority = mint - .base - .mint_authority - .ok_or(Into::::into(TokenError::FixedSupply))?; - Self::validate_owner( - program_id, - &mint_authority, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?; - mint.base.mint_authority = new_authority; - mint.pack_base(); - } - AuthorityType::FreezeAccount => { - // Once a mint's freeze authority is disabled, it cannot be re-enabled by - // setting a new freeze_authority - let freeze_authority = mint - .base - .freeze_authority - .ok_or(Into::::into(TokenError::MintCannotFreeze))?; - Self::validate_owner( - program_id, - &freeze_authority, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?; - mint.base.freeze_authority = new_authority; - mint.pack_base(); - } - AuthorityType::CloseMint => { - let extension = mint.get_extension_mut::()?; - let maybe_close_authority: Option = extension.close_authority.into(); - let close_authority = - maybe_close_authority.ok_or(TokenError::AuthorityTypeNotSupported)?; - Self::validate_owner( - program_id, - &close_authority, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?; - extension.close_authority = new_authority.try_into()?; - } - AuthorityType::TransferFeeConfig => { - let extension = mint.get_extension_mut::()?; - let maybe_transfer_fee_config_authority: Option = - extension.transfer_fee_config_authority.into(); - let transfer_fee_config_authority = maybe_transfer_fee_config_authority - .ok_or(TokenError::AuthorityTypeNotSupported)?; - Self::validate_owner( - program_id, - &transfer_fee_config_authority, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?; - extension.transfer_fee_config_authority = new_authority.try_into()?; - } - AuthorityType::WithheldWithdraw => { - let extension = mint.get_extension_mut::()?; - let maybe_withdraw_withheld_authority: Option = - extension.withdraw_withheld_authority.into(); - let withdraw_withheld_authority = maybe_withdraw_withheld_authority - .ok_or(TokenError::AuthorityTypeNotSupported)?; - Self::validate_owner( - program_id, - &withdraw_withheld_authority, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?; - extension.withdraw_withheld_authority = new_authority.try_into()?; - } - AuthorityType::InterestRate => { - let extension = mint.get_extension_mut::()?; - let maybe_rate_authority: Option = extension.rate_authority.into(); - let rate_authority = - maybe_rate_authority.ok_or(TokenError::AuthorityTypeNotSupported)?; - Self::validate_owner( - program_id, - &rate_authority, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?; - extension.rate_authority = new_authority.try_into()?; - } - _ => { - return Err(TokenError::AuthorityTypeNotSupported.into()); - } - } - } else { - return Err(ProgramError::InvalidAccountData); - } - - Ok(()) - } - - /// Processes a [MintTo](enum.TokenInstruction.html) instruction. - pub fn process_mint_to( - program_id: &Pubkey, - accounts: &[AccountInfo], - amount: u64, - expected_decimals: Option, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_info = next_account_info(account_info_iter)?; - let destination_account_info = next_account_info(account_info_iter)?; - let owner_info = next_account_info(account_info_iter)?; - let owner_info_data_len = owner_info.data_len(); - - let mut destination_account_data = destination_account_info.data.borrow_mut(); - let mut destination_account = - StateWithExtensionsMut::::unpack(&mut destination_account_data)?; - if destination_account.base.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - - if destination_account.base.is_native() { - return Err(TokenError::NativeNotSupported.into()); - } - if !cmp_pubkeys(mint_info.key, &destination_account.base.mint) { - return Err(TokenError::MintMismatch.into()); - } - - let mut mint_data = mint_info.data.borrow_mut(); - let mut mint = StateWithExtensionsMut::::unpack(&mut mint_data)?; - - // If the mint if non-transferable, only allow minting to accounts - // with immutable ownership. - if mint.get_extension::().is_ok() - && destination_account - .get_extension::() - .is_err() - { - return Err(TokenError::NonTransferableNeedsImmutableOwnership.into()); - } - - if let Some(expected_decimals) = expected_decimals { - if expected_decimals != mint.base.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); - } - } - - match mint.base.mint_authority { - COption::Some(mint_authority) => Self::validate_owner( - program_id, - &mint_authority, - owner_info, - owner_info_data_len, - account_info_iter.as_slice(), - )?, - COption::None => return Err(TokenError::FixedSupply.into()), - } - - // Revisit this later to see if it's worth adding a check to reduce - // compute costs, ie: - // if amount == 0 - check_program_account(mint_info.owner)?; - check_program_account(destination_account_info.owner)?; - - destination_account.base.amount = destination_account - .base - .amount - .checked_add(amount) - .ok_or(TokenError::Overflow)?; - - mint.base.supply = mint - .base - .supply - .checked_add(amount) - .ok_or(TokenError::Overflow)?; - - mint.pack_base(); - destination_account.pack_base(); - - Ok(()) - } - - /// Processes a [Burn](enum.TokenInstruction.html) instruction. - pub fn process_burn( - program_id: &Pubkey, - accounts: &[AccountInfo], - amount: u64, - expected_decimals: Option, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - - let source_account_info = next_account_info(account_info_iter)?; - let mint_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - let authority_info_data_len = authority_info.data_len(); - - let mut source_account_data = source_account_info.data.borrow_mut(); - let mut source_account = - StateWithExtensionsMut::::unpack(&mut source_account_data)?; - let mut mint_data = mint_info.data.borrow_mut(); - let mut mint = StateWithExtensionsMut::::unpack(&mut mint_data)?; - - if source_account.base.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - if source_account.base.is_native() { - return Err(TokenError::NativeNotSupported.into()); - } - if source_account.base.amount < amount { - return Err(TokenError::InsufficientFunds.into()); - } - if mint_info.key != &source_account.base.mint { - return Err(TokenError::MintMismatch.into()); - } - - if let Some(expected_decimals) = expected_decimals { - if expected_decimals != mint.base.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); - } - } - - if !source_account - .base - .is_owned_by_system_program_or_incinerator() - { - match source_account.base.delegate { - COption::Some(ref delegate) if cmp_pubkeys(authority_info.key, delegate) => { - Self::validate_owner( - program_id, - delegate, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?; - - if source_account.base.delegated_amount < amount { - return Err(TokenError::InsufficientFunds.into()); - } - source_account.base.delegated_amount = source_account - .base - .delegated_amount - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - if source_account.base.delegated_amount == 0 { - source_account.base.delegate = COption::None; - } - } - _ => Self::validate_owner( - program_id, - &source_account.base.owner, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?, - } - } - - // Revisit this later to see if it's worth adding a check to reduce - // compute costs, ie: - // if amount == 0 - check_program_account(source_account_info.owner)?; - check_program_account(mint_info.owner)?; - - source_account.base.amount = source_account - .base - .amount - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - mint.base.supply = mint - .base - .supply - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - - source_account.pack_base(); - mint.pack_base(); - - Ok(()) - } - - /// Processes a [CloseAccount](enum.TokenInstruction.html) instruction. - pub fn process_close_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let source_account_info = next_account_info(account_info_iter)?; - let destination_account_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - let authority_info_data_len = authority_info.data_len(); - - if cmp_pubkeys(source_account_info.key, destination_account_info.key) { - return Err(ProgramError::InvalidAccountData); - } - - let source_account_data = source_account_info.data.borrow(); - if let Ok(source_account) = StateWithExtensions::::unpack(&source_account_data) { - if !source_account.base.is_native() && source_account.base.amount != 0 { - return Err(TokenError::NonNativeHasBalance.into()); - } - - let authority = source_account - .base - .close_authority - .unwrap_or(source_account.base.owner); - - if !source_account - .base - .is_owned_by_system_program_or_incinerator() - { - Self::validate_owner( - program_id, - &authority, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?; - } else if !solana_program::incinerator::check_id(destination_account_info.key) { - return Err(ProgramError::InvalidAccountData); - } - - if let Ok(confidential_transfer_state) = - source_account.get_extension::() - { - confidential_transfer_state.closable()? - } - - if let Ok(transfer_fee_state) = source_account.get_extension::() { - transfer_fee_state.closable()? - } - } else if let Ok(mint) = StateWithExtensions::::unpack(&source_account_data) { - let extension = mint.get_extension::()?; - let maybe_authority: Option = extension.close_authority.into(); - let authority = maybe_authority.ok_or(TokenError::AuthorityTypeNotSupported)?; - Self::validate_owner( - program_id, - &authority, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - )?; - - if mint.base.supply != 0 { - return Err(TokenError::MintHasSupply.into()); - } - } else { - return Err(ProgramError::UninitializedAccount); - } - - let destination_starting_lamports = destination_account_info.lamports(); - **destination_account_info.lamports.borrow_mut() = destination_starting_lamports - .checked_add(source_account_info.lamports()) - .ok_or(TokenError::Overflow)?; - - **source_account_info.lamports.borrow_mut() = 0; - drop(source_account_data); - delete_account(source_account_info)?; - - Ok(()) - } - - /// Processes a [FreezeAccount](enum.TokenInstruction.html) or a - /// [ThawAccount](enum.TokenInstruction.html) instruction. - pub fn process_toggle_freeze_account( - program_id: &Pubkey, - accounts: &[AccountInfo], - freeze: bool, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let source_account_info = next_account_info(account_info_iter)?; - let mint_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - let authority_info_data_len = authority_info.data_len(); - - let mut source_account_data = source_account_info.data.borrow_mut(); - let mut source_account = - StateWithExtensionsMut::::unpack(&mut source_account_data)?; - if freeze && source_account.base.is_frozen() || !freeze && !source_account.base.is_frozen() - { - return Err(TokenError::InvalidState.into()); - } - if source_account.base.is_native() { - return Err(TokenError::NativeNotSupported.into()); - } - if !cmp_pubkeys(mint_info.key, &source_account.base.mint) { - return Err(TokenError::MintMismatch.into()); - } - - let mint_data = mint_info.data.borrow(); - let mint = StateWithExtensions::::unpack(&mint_data)?; - match mint.base.freeze_authority { - COption::Some(authority) => Self::validate_owner( - program_id, - &authority, - authority_info, - authority_info_data_len, - account_info_iter.as_slice(), - ), - COption::None => Err(TokenError::MintCannotFreeze.into()), - }?; - - source_account.base.state = if freeze { - AccountState::Frozen - } else { - AccountState::Initialized - }; - - source_account.pack_base(); - - Ok(()) - } - - /// Processes a [SyncNative](enum.TokenInstruction.html) instruction - pub fn process_sync_native(accounts: &[AccountInfo]) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let native_account_info = next_account_info(account_info_iter)?; - - check_program_account(native_account_info.owner)?; - let mut native_account_data = native_account_info.data.borrow_mut(); - let mut native_account = - StateWithExtensionsMut::::unpack(&mut native_account_data)?; - - if let COption::Some(rent_exempt_reserve) = native_account.base.is_native { - let new_amount = native_account_info - .lamports() - .checked_sub(rent_exempt_reserve) - .ok_or(TokenError::Overflow)?; - if new_amount < native_account.base.amount { - return Err(TokenError::InvalidState.into()); - } - native_account.base.amount = new_amount; - } else { - return Err(TokenError::NonNativeNotSupported.into()); - } - - native_account.pack_base(); - Ok(()) - } - - /// Processes an [InitializeMintCloseAuthority](enum.TokenInstruction.html) instruction - pub fn process_initialize_mint_close_authority( - accounts: &[AccountInfo], - close_authority: COption, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_account_info = next_account_info(account_info_iter)?; - - let mut mint_data = mint_account_info.data.borrow_mut(); - let mut mint = StateWithExtensionsMut::::unpack_uninitialized(&mut mint_data)?; - let extension = mint.init_extension::(true)?; - extension.close_authority = close_authority.try_into()?; - - Ok(()) - } - - /// Processes a [GetAccountDataSize](enum.TokenInstruction.html) instruction - pub fn process_get_account_data_size( - accounts: &[AccountInfo], - new_extension_types: Vec, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_account_info = next_account_info(account_info_iter)?; - - let mut account_extensions = Self::get_required_account_extensions(mint_account_info)?; - // ExtensionType::get_account_len() dedupes types, so just a dumb concatenation is fine - // here - account_extensions.extend_from_slice(&new_extension_types); - - let account_len = ExtensionType::get_account_len::(&account_extensions); - set_return_data(&account_len.to_le_bytes()); - - Ok(()) - } - - /// Processes an [InitializeImmutableOwner](enum.TokenInstruction.html) instruction - pub fn process_initialize_immutable_owner(accounts: &[AccountInfo]) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let token_account_info = next_account_info(account_info_iter)?; - let token_account_data = &mut token_account_info.data.borrow_mut(); - let mut token_account = - StateWithExtensionsMut::::unpack_uninitialized(token_account_data)?; - token_account - .init_extension::(true) - .map(|_| ()) - } - - /// Processes an [AmountToUiAmount](enum.TokenInstruction.html) instruction - pub fn process_amount_to_ui_amount(accounts: &[AccountInfo], amount: u64) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_info = next_account_info(account_info_iter)?; - check_program_account(mint_info.owner)?; - - let mint_data = mint_info.data.borrow(); - let mint = StateWithExtensions::::unpack(&mint_data) - .map_err(|_| Into::::into(TokenError::InvalidMint))?; - let ui_amount = if let Ok(extension) = mint.get_extension::() { - let unix_timestamp = Clock::get()?.unix_timestamp; - extension - .amount_to_ui_amount(amount, mint.base.decimals, unix_timestamp) - .ok_or(ProgramError::InvalidArgument)? - } else { - crate::amount_to_ui_amount_string_trimmed(amount, mint.base.decimals) - }; - - set_return_data(&ui_amount.into_bytes()); - Ok(()) - } - - /// Processes an [AmountToUiAmount](enum.TokenInstruction.html) instruction - pub fn process_ui_amount_to_amount(accounts: &[AccountInfo], ui_amount: &str) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_info = next_account_info(account_info_iter)?; - check_program_account(mint_info.owner)?; - - let mint_data = mint_info.data.borrow(); - let mint = StateWithExtensions::::unpack(&mint_data) - .map_err(|_| Into::::into(TokenError::InvalidMint))?; - let amount = if let Ok(extension) = mint.get_extension::() { - let unix_timestamp = Clock::get()?.unix_timestamp; - extension.try_ui_amount_into_amount(ui_amount, mint.base.decimals, unix_timestamp)? - } else { - crate::try_ui_amount_into_amount(ui_amount.to_string(), mint.base.decimals)? - }; - - set_return_data(&amount.to_le_bytes()); - Ok(()) - } - - /// Processes a [CreateNativeMint](enum.TokenInstruction.html) instruction - pub fn process_create_native_mint(accounts: &[AccountInfo]) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let payer_info = next_account_info(account_info_iter)?; - let native_mint_info = next_account_info(account_info_iter)?; - let system_program_info = next_account_info(account_info_iter)?; - - if *native_mint_info.key != native_mint::id() { - return Err(TokenError::InvalidMint.into()); - } - - let rent = Rent::get()?; - let new_minimum_balance = rent.minimum_balance(Mint::get_packed_len()); - let lamports_diff = new_minimum_balance.saturating_sub(native_mint_info.lamports()); - invoke( - &system_instruction::transfer(payer_info.key, native_mint_info.key, lamports_diff), - &[ - payer_info.clone(), - native_mint_info.clone(), - system_program_info.clone(), - ], - )?; - - invoke_signed( - &system_instruction::allocate(native_mint_info.key, Mint::get_packed_len() as u64), - &[native_mint_info.clone(), system_program_info.clone()], - &[native_mint::PROGRAM_ADDRESS_SEEDS], - )?; - - invoke_signed( - &system_instruction::assign(native_mint_info.key, &crate::id()), - &[native_mint_info.clone(), system_program_info.clone()], - &[native_mint::PROGRAM_ADDRESS_SEEDS], - )?; - - Mint::pack( - Mint { - decimals: native_mint::DECIMALS, - is_initialized: true, - ..Mint::default() - }, - &mut native_mint_info.data.borrow_mut(), - ) - } - - /// Processes an [InitializeNonTransferableMint](enum.TokenInstruction.html) instruction - pub fn process_initialize_non_transferable_mint(accounts: &[AccountInfo]) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_account_info = next_account_info(account_info_iter)?; - - let mut mint_data = mint_account_info.data.borrow_mut(); - let mut mint = StateWithExtensionsMut::::unpack_uninitialized(&mut mint_data)?; - mint.init_extension::(true)?; - - Ok(()) - } - - /// Processes an [Instruction](enum.Instruction.html). - pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult { - let instruction = TokenInstruction::unpack(input)?; - - match instruction { - TokenInstruction::InitializeMint { - decimals, - mint_authority, - freeze_authority, - } => { - msg!("Instruction: InitializeMint"); - Self::process_initialize_mint(accounts, decimals, mint_authority, freeze_authority) - } - TokenInstruction::InitializeMint2 { - decimals, - mint_authority, - freeze_authority, - } => { - msg!("Instruction: InitializeMint2"); - Self::process_initialize_mint2(accounts, decimals, mint_authority, freeze_authority) - } - TokenInstruction::InitializeAccount => { - msg!("Instruction: InitializeAccount"); - Self::process_initialize_account(accounts) - } - TokenInstruction::InitializeAccount2 { owner } => { - msg!("Instruction: InitializeAccount2"); - Self::process_initialize_account2(accounts, owner) - } - TokenInstruction::InitializeAccount3 { owner } => { - msg!("Instruction: InitializeAccount3"); - Self::process_initialize_account3(accounts, owner) - } - TokenInstruction::InitializeMultisig { m } => { - msg!("Instruction: InitializeMultisig"); - Self::process_initialize_multisig(accounts, m) - } - TokenInstruction::InitializeMultisig2 { m } => { - msg!("Instruction: InitializeMultisig2"); - Self::process_initialize_multisig2(accounts, m) - } - #[allow(deprecated)] - TokenInstruction::Transfer { amount } => { - msg!("Instruction: Transfer"); - Self::process_transfer(program_id, accounts, amount, None, None) - } - TokenInstruction::Approve { amount } => { - msg!("Instruction: Approve"); - Self::process_approve(program_id, accounts, amount, None) - } - TokenInstruction::Revoke => { - msg!("Instruction: Revoke"); - Self::process_revoke(program_id, accounts) - } - TokenInstruction::SetAuthority { - authority_type, - new_authority, - } => { - msg!("Instruction: SetAuthority"); - Self::process_set_authority(program_id, accounts, authority_type, new_authority) - } - TokenInstruction::MintTo { amount } => { - msg!("Instruction: MintTo"); - Self::process_mint_to(program_id, accounts, amount, None) - } - TokenInstruction::Burn { amount } => { - msg!("Instruction: Burn"); - Self::process_burn(program_id, accounts, amount, None) - } - TokenInstruction::CloseAccount => { - msg!("Instruction: CloseAccount"); - Self::process_close_account(program_id, accounts) - } - TokenInstruction::FreezeAccount => { - msg!("Instruction: FreezeAccount"); - Self::process_toggle_freeze_account(program_id, accounts, true) - } - TokenInstruction::ThawAccount => { - msg!("Instruction: ThawAccount"); - Self::process_toggle_freeze_account(program_id, accounts, false) - } - TokenInstruction::TransferChecked { amount, decimals } => { - msg!("Instruction: TransferChecked"); - Self::process_transfer(program_id, accounts, amount, Some(decimals), None) - } - TokenInstruction::ApproveChecked { amount, decimals } => { - msg!("Instruction: ApproveChecked"); - Self::process_approve(program_id, accounts, amount, Some(decimals)) - } - TokenInstruction::MintToChecked { amount, decimals } => { - msg!("Instruction: MintToChecked"); - Self::process_mint_to(program_id, accounts, amount, Some(decimals)) - } - TokenInstruction::BurnChecked { amount, decimals } => { - msg!("Instruction: BurnChecked"); - Self::process_burn(program_id, accounts, amount, Some(decimals)) - } - TokenInstruction::SyncNative => { - msg!("Instruction: SyncNative"); - Self::process_sync_native(accounts) - } - TokenInstruction::GetAccountDataSize { extension_types } => { - msg!("Instruction: GetAccountDataSize"); - Self::process_get_account_data_size(accounts, extension_types) - } - TokenInstruction::InitializeMintCloseAuthority { close_authority } => { - msg!("Instruction: InitializeMintCloseAuthority"); - Self::process_initialize_mint_close_authority(accounts, close_authority) - } - TokenInstruction::TransferFeeExtension(instruction) => { - transfer_fee::processor::process_instruction(program_id, accounts, instruction) - } - TokenInstruction::ConfidentialTransferExtension => { - confidential_transfer::processor::process_instruction( - program_id, - accounts, - &input[1..], - ) - } - TokenInstruction::DefaultAccountStateExtension => { - default_account_state::processor::process_instruction( - program_id, - accounts, - &input[1..], - ) - } - TokenInstruction::InitializeImmutableOwner => { - msg!("Instruction: InitializeImmutableOwner"); - Self::process_initialize_immutable_owner(accounts) - } - TokenInstruction::AmountToUiAmount { amount } => { - msg!("Instruction: AmountToUiAmount"); - Self::process_amount_to_ui_amount(accounts, amount) - } - TokenInstruction::UiAmountToAmount { ui_amount } => { - msg!("Instruction: UiAmountToAmount"); - Self::process_ui_amount_to_amount(accounts, ui_amount) - } - TokenInstruction::Reallocate { extension_types } => { - msg!("Instruction: Reallocate"); - reallocate::process_reallocate(program_id, accounts, extension_types) - } - TokenInstruction::MemoTransferExtension => { - memo_transfer::processor::process_instruction(program_id, accounts, &input[1..]) - } - TokenInstruction::CreateNativeMint => { - msg!("Instruction: CreateNativeMint"); - Self::process_create_native_mint(accounts) - } - TokenInstruction::InitializeNonTransferableMint => { - msg!("Instruction: InitializeNonTransferableMint"); - Self::process_initialize_non_transferable_mint(accounts) - } - TokenInstruction::InterestBearingMintExtension => { - interest_bearing_mint::processor::process_instruction( - program_id, - accounts, - &input[1..], - ) - } - } - } - - /// Validates owner(s) are present. Used for Mints and Accounts only. - pub fn validate_owner( - program_id: &Pubkey, - expected_owner: &Pubkey, - owner_account_info: &AccountInfo, - owner_account_data_len: usize, - signers: &[AccountInfo], - ) -> ProgramResult { - if !cmp_pubkeys(expected_owner, owner_account_info.key) { - return Err(TokenError::OwnerMismatch.into()); - } - - if cmp_pubkeys(program_id, owner_account_info.owner) - && owner_account_data_len == Multisig::get_packed_len() - { - let multisig = Multisig::unpack(&owner_account_info.data.borrow())?; - let mut num_signers = 0; - let mut matched = [false; MAX_SIGNERS]; - for signer in signers.iter() { - for (position, key) in multisig.signers[0..multisig.n as usize].iter().enumerate() { - if cmp_pubkeys(key, signer.key) && !matched[position] { - if !signer.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - matched[position] = true; - num_signers += 1; - } - } - } - if num_signers < multisig.m { - return Err(ProgramError::MissingRequiredSignature); - } - return Ok(()); - } else if !owner_account_info.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - Ok(()) - } - - fn get_required_account_extensions( - mint_account_info: &AccountInfo, - ) -> Result, ProgramError> { - let mint_data = mint_account_info.data.borrow(); - let state = StateWithExtensions::::unpack(&mint_data) - .map_err(|_| Into::::into(TokenError::InvalidMint))?; - Self::get_required_account_extensions_from_unpacked_mint(mint_account_info.owner, &state) - } - - fn get_required_account_extensions_from_unpacked_mint( - token_program_id: &Pubkey, - state: &StateWithExtensions, - ) -> Result, ProgramError> { - check_program_account(token_program_id)?; - let mint_extensions: Vec = state.get_extension_types()?; - Ok(ExtensionType::get_required_init_account_extensions( - &mint_extensions, - )) - } -} - -/// Helper function to mostly delete an account in a test environment. We could -/// potentially muck around the bytes assuming that a vec is passed in, but that -/// would be more trouble than it's worth. -#[cfg(not(target_arch = "bpf"))] -fn delete_account(account_info: &AccountInfo) -> Result<(), ProgramError> { - account_info.assign(&system_program::id()); - let mut account_data = account_info.data.borrow_mut(); - let data_len = account_data.len(); - solana_program::program_memory::sol_memset(*account_data, 0, data_len); - Ok(()) -} - -/// Helper function to totally delete an account on-chain -#[cfg(target_arch = "bpf")] -fn delete_account(account_info: &AccountInfo) -> Result<(), ProgramError> { - account_info.assign(&system_program::id()); - account_info.realloc(0, false) -} - -#[cfg(test)] -mod tests { - use { - super::*, - crate::{ - extension::transfer_fee::instruction::initialize_transfer_fee_config, instruction::*, - }, - serial_test::serial, - solana_program::{ - account_info::IntoAccountInfo, - clock::Epoch, - instruction::Instruction, - program_error::{self, PrintProgramError}, - sysvar::{clock::Clock, rent}, - }, - solana_sdk::account::{ - create_account_for_test, create_is_signer_account_infos, Account as SolanaAccount, - }, - std::sync::{Arc, RwLock}, - }; - - lazy_static::lazy_static! { - static ref EXPECTED_DATA: Arc>> = Arc::new(RwLock::new(Vec::new())); - } - - fn set_expected_data(expected_data: Vec) { - *EXPECTED_DATA.write().unwrap() = expected_data; - } - - struct SyscallStubs {} - impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs { - fn sol_log(&self, _message: &str) {} - - fn sol_invoke_signed( - &self, - _instruction: &Instruction, - _account_infos: &[AccountInfo], - _signers_seeds: &[&[&[u8]]], - ) -> ProgramResult { - Err(ProgramError::Custom(42)) // Not supported - } - - fn sol_get_clock_sysvar(&self, var_addr: *mut u8) -> u64 { - unsafe { - *(var_addr as *mut _ as *mut Clock) = Clock::default(); - } - solana_program::entrypoint::SUCCESS - } - - fn sol_get_epoch_schedule_sysvar(&self, _var_addr: *mut u8) -> u64 { - program_error::UNSUPPORTED_SYSVAR - } - - #[allow(deprecated)] - fn sol_get_fees_sysvar(&self, _var_addr: *mut u8) -> u64 { - program_error::UNSUPPORTED_SYSVAR - } - - fn sol_get_rent_sysvar(&self, var_addr: *mut u8) -> u64 { - unsafe { - *(var_addr as *mut _ as *mut Rent) = Rent::default(); - } - solana_program::entrypoint::SUCCESS - } - - fn sol_set_return_data(&self, data: &[u8]) { - assert_eq!(&*EXPECTED_DATA.read().unwrap(), data) - } - } - - fn do_process_instruction( - instruction: Instruction, - accounts: Vec<&mut SolanaAccount>, - ) -> ProgramResult { - { - use std::sync::Once; - static ONCE: Once = Once::new(); - - ONCE.call_once(|| { - solana_sdk::program_stubs::set_syscall_stubs(Box::new(SyscallStubs {})); - }); - } - - let mut meta = instruction - .accounts - .iter() - .zip(accounts) - .map(|(account_meta, account)| (&account_meta.pubkey, account_meta.is_signer, account)) - .collect::>(); - - let account_infos = create_is_signer_account_infos(&mut meta); - Processor::process(&instruction.program_id, &account_infos, &instruction.data) - } - - fn do_process_instruction_dups( - instruction: Instruction, - account_infos: Vec, - ) -> ProgramResult { - Processor::process(&instruction.program_id, &account_infos, &instruction.data) - } - - fn return_token_error_as_program_error() -> ProgramError { - TokenError::MintMismatch.into() - } - - fn rent_sysvar() -> SolanaAccount { - create_account_for_test(&Rent::default()) - } - - fn mint_minimum_balance() -> u64 { - Rent::default().minimum_balance(Mint::get_packed_len()) - } - - fn account_minimum_balance() -> u64 { - Rent::default().minimum_balance(Account::get_packed_len()) - } - - fn multisig_minimum_balance() -> u64 { - Rent::default().minimum_balance(Multisig::get_packed_len()) - } - - fn native_mint() -> SolanaAccount { - let mut rent_sysvar = rent_sysvar(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &crate::id()); - do_process_instruction( - initialize_mint( - &crate::id(), - &crate::native_mint::id(), - &Pubkey::default(), - None, - crate::native_mint::DECIMALS, - ) - .unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - mint_account - } - - #[test] - fn test_print_error() { - let error = return_token_error_as_program_error(); - error.print::(); - } - - #[test] - #[should_panic(expected = "Custom(3)")] - fn test_error_unwrap() { - Err::<(), ProgramError>(return_token_error_as_program_error()).unwrap(); - } - - #[test] - fn test_unique_account_sizes() { - assert_ne!(Mint::get_packed_len(), 0); - assert_ne!(Mint::get_packed_len(), Account::get_packed_len()); - assert_ne!(Mint::get_packed_len(), Multisig::get_packed_len()); - assert_ne!(Account::get_packed_len(), 0); - assert_ne!(Account::get_packed_len(), Multisig::get_packed_len()); - assert_ne!(Multisig::get_packed_len(), 0); - } - - #[test] - fn test_initialize_mint() { - let program_id = crate::id(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = SolanaAccount::new(42, Mint::get_packed_len(), &program_id); - let mint2_key = Pubkey::new_unique(); - let mut mint2_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // mint is not rent exempt - assert_eq!( - Err(TokenError::NotRentExempt.into()), - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar] - ) - ); - - mint_account.lamports = mint_minimum_balance(); - - // create new mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create twice - assert_eq!( - Err(TokenError::AlreadyInUse.into()), - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2,).unwrap(), - vec![&mut mint_account, &mut rent_sysvar] - ) - ); - - // create another mint that can freeze - do_process_instruction( - initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), - vec![&mut mint2_account, &mut rent_sysvar], - ) - .unwrap(); - let mint = Mint::unpack_unchecked(&mint2_account.data).unwrap(); - assert_eq!(mint.freeze_authority, COption::Some(owner_key)); - } - - #[test] - fn test_initialize_mint2() { - let program_id = crate::id(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = SolanaAccount::new(42, Mint::get_packed_len(), &program_id); - let mint2_key = Pubkey::new_unique(); - let mut mint2_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - - // mint is not rent exempt - assert_eq!( - Err(TokenError::NotRentExempt.into()), - do_process_instruction( - initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account] - ) - ); - - mint_account.lamports = mint_minimum_balance(); - - // create new mint - do_process_instruction( - initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - // create twice - assert_eq!( - Err(TokenError::AlreadyInUse.into()), - do_process_instruction( - initialize_mint2(&program_id, &mint_key, &owner_key, None, 2,).unwrap(), - vec![&mut mint_account] - ) - ); - - // create another mint that can freeze - do_process_instruction( - initialize_mint2(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), - vec![&mut mint2_account], - ) - .unwrap(); - let mint = Mint::unpack_unchecked(&mint2_account.data).unwrap(); - assert_eq!(mint.freeze_authority, COption::Some(owner_key)); - } - - #[test] - fn test_initialize_mint_account() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new(42, Account::get_packed_len(), &program_id); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // account is not rent exempt - assert_eq!( - Err(TokenError::NotRentExempt.into()), - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar - ], - ) - ); - - account_account.lamports = account_minimum_balance(); - - // mint is not valid (not initialized) - assert_eq!( - Err(TokenError::InvalidMint.into()), - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar - ], - ) - ); - - // create mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // mint not owned by program - let not_program_id = Pubkey::new_unique(); - mint_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar - ], - ) - ); - mint_account.owner = program_id; - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create twice - assert_eq!( - Err(TokenError::AlreadyInUse.into()), - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar - ], - ) - ); - } - - #[test] - fn test_transfer_dups() { - let program_id = crate::id(); - let account1_key = Pubkey::new_unique(); - let mut account1_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let mut account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let mut account2_info: AccountInfo = (&account2_key, false, &mut account2_account).into(); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account3_info: AccountInfo = (&account3_key, false, &mut account3_account).into(); - let account4_key = Pubkey::new_unique(); - let mut account4_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account4_info: AccountInfo = (&account4_key, true, &mut account4_account).into(); - let multisig_key = Pubkey::new_unique(); - let mut multisig_account = SolanaAccount::new( - multisig_minimum_balance(), - Multisig::get_packed_len(), - &program_id, - ); - let multisig_info: AccountInfo = (&multisig_key, true, &mut multisig_account).into(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - // create account - do_process_instruction_dups( - initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // create another account - do_process_instruction_dups( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - account2_info.clone(), - mint_info.clone(), - owner_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // mint to account - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], - ) - .unwrap(); - - // source-owner transfer - do_process_instruction_dups( - #[allow(deprecated)] - transfer( - &program_id, - &account1_key, - &account2_key, - &account1_key, - &[], - 500, - ) - .unwrap(), - vec![ - account1_info.clone(), - account2_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // source-owner TransferChecked - do_process_instruction_dups( - transfer_checked( - &program_id, - &account1_key, - &mint_key, - &account2_key, - &account1_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account2_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // source-delegate transfer - let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.amount = 1000; - account.delegated_amount = 1000; - account.delegate = COption::Some(account1_key); - account.owner = owner_key; - Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); - - do_process_instruction_dups( - #[allow(deprecated)] - transfer( - &program_id, - &account1_key, - &account2_key, - &account1_key, - &[], - 500, - ) - .unwrap(), - vec![ - account1_info.clone(), - account2_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // source-delegate TransferChecked - do_process_instruction_dups( - transfer_checked( - &program_id, - &account1_key, - &mint_key, - &account2_key, - &account1_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account2_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // test destination-owner transfer - do_process_instruction_dups( - initialize_account(&program_id, &account3_key, &mint_key, &account2_key).unwrap(), - vec![ - account3_info.clone(), - mint_info.clone(), - account2_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account3_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account3_info.clone(), owner_info.clone()], - ) - .unwrap(); - - account1_info.is_signer = false; - account2_info.is_signer = true; - do_process_instruction_dups( - #[allow(deprecated)] - transfer( - &program_id, - &account3_key, - &account2_key, - &account2_key, - &[], - 500, - ) - .unwrap(), - vec![ - account3_info.clone(), - account2_info.clone(), - account2_info.clone(), - ], - ) - .unwrap(); - - // destination-owner TransferChecked - do_process_instruction_dups( - transfer_checked( - &program_id, - &account3_key, - &mint_key, - &account2_key, - &account2_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![ - account3_info.clone(), - mint_info.clone(), - account2_info.clone(), - account2_info.clone(), - ], - ) - .unwrap(); - - // test source-multisig signer - do_process_instruction_dups( - initialize_multisig(&program_id, &multisig_key, &[&account4_key], 1).unwrap(), - vec![ - multisig_info.clone(), - rent_info.clone(), - account4_info.clone(), - ], - ) - .unwrap(); - - do_process_instruction_dups( - initialize_account(&program_id, &account4_key, &mint_key, &multisig_key).unwrap(), - vec![ - account4_info.clone(), - mint_info.clone(), - multisig_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account4_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account4_info.clone(), owner_info.clone()], - ) - .unwrap(); - - // source-multisig-signer transfer - do_process_instruction_dups( - #[allow(deprecated)] - transfer( - &program_id, - &account4_key, - &account2_key, - &multisig_key, - &[&account4_key], - 500, - ) - .unwrap(), - vec![ - account4_info.clone(), - account2_info.clone(), - multisig_info.clone(), - account4_info.clone(), - ], - ) - .unwrap(); - - // source-multisig-signer TransferChecked - do_process_instruction_dups( - transfer_checked( - &program_id, - &account4_key, - &mint_key, - &account2_key, - &multisig_key, - &[&account4_key], - 500, - 2, - ) - .unwrap(), - vec![ - account4_info.clone(), - mint_info.clone(), - account2_info.clone(), - multisig_info.clone(), - account4_info.clone(), - ], - ) - .unwrap(); - } - - #[test] - fn test_transfer() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let delegate_key = Pubkey::new_unique(); - let mut delegate_account = SolanaAccount::default(); - let mismatch_key = Pubkey::new_unique(); - let mut mismatch_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint2_key = Pubkey::new_unique(); - let mut rent_sysvar = rent_sysvar(); - - // create mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account3_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create mismatch account - do_process_instruction( - initialize_account(&program_id, &mismatch_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut mismatch_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); - account.mint = mint2_key; - Account::pack(account, &mut mismatch_account.data).unwrap(); - - // mint to account - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - // missing signer - #[allow(deprecated)] - let mut instruction = transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 1000, - ) - .unwrap(); - instruction.accounts[2].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - do_process_instruction( - instruction, - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - ); - - // mismatch mint - assert_eq!( - Err(TokenError::MintMismatch.into()), - do_process_instruction( - #[allow(deprecated)] - transfer( - &program_id, - &account_key, - &mismatch_key, - &owner_key, - &[], - 1000 - ) - .unwrap(), - vec![ - &mut account_account, - &mut mismatch_account, - &mut owner_account, - ], - ) - ); - - // missing owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - #[allow(deprecated)] - transfer( - &program_id, - &account_key, - &account2_key, - &owner2_key, - &[], - 1000 - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner2_account, - ], - ) - ); - - // account not owned by program - let not_program_id = Pubkey::new_unique(); - account_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - #[allow(deprecated)] - transfer(&program_id, &account_key, &account2_key, &owner_key, &[], 0,).unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner2_account, - ], - ) - ); - account_account.owner = program_id; - - // account 2 not owned by program - let not_program_id = Pubkey::new_unique(); - account2_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - #[allow(deprecated)] - transfer(&program_id, &account_key, &account2_key, &owner_key, &[], 0,).unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner2_account, - ], - ) - ); - account2_account.owner = program_id; - - // transfer - do_process_instruction( - #[allow(deprecated)] - transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 1000, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - .unwrap(); - - // insufficient funds - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - #[allow(deprecated)] - transfer(&program_id, &account_key, &account2_key, &owner_key, &[], 1).unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - ); - - // transfer half back - do_process_instruction( - #[allow(deprecated)] - transfer( - &program_id, - &account2_key, - &account_key, - &owner_key, - &[], - 500, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut account_account, - &mut owner_account, - ], - ) - .unwrap(); - - // incorrect decimals - assert_eq!( - Err(TokenError::MintDecimalsMismatch.into()), - do_process_instruction( - transfer_checked( - &program_id, - &account2_key, - &mint_key, - &account_key, - &owner_key, - &[], - 1, - 10 // <-- incorrect decimals - ) - .unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut account_account, - &mut owner_account, - ], - ) - ); - - // incorrect mint - assert_eq!( - Err(TokenError::MintMismatch.into()), - do_process_instruction( - transfer_checked( - &program_id, - &account2_key, - &account3_key, // <-- incorrect mint - &account_key, - &owner_key, - &[], - 1, - 2 - ) - .unwrap(), - vec![ - &mut account2_account, - &mut account3_account, // <-- incorrect mint - &mut account_account, - &mut owner_account, - ], - ) - ); - // transfer rest with explicit decimals - do_process_instruction( - transfer_checked( - &program_id, - &account2_key, - &mint_key, - &account_key, - &owner_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut account_account, - &mut owner_account, - ], - ) - .unwrap(); - - // insufficient funds - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - #[allow(deprecated)] - transfer(&program_id, &account2_key, &account_key, &owner_key, &[], 1).unwrap(), - vec![ - &mut account2_account, - &mut account_account, - &mut owner_account, - ], - ) - ); - - // approve delegate - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 100, - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - .unwrap(); - - // transfer via delegate - do_process_instruction( - #[allow(deprecated)] - transfer( - &program_id, - &account_key, - &account2_key, - &delegate_key, - &[], - 100, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut delegate_account, - ], - ) - .unwrap(); - - // insufficient funds approved via delegate - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - #[allow(deprecated)] - transfer( - &program_id, - &account_key, - &account2_key, - &delegate_key, - &[], - 100 - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut delegate_account, - ], - ) - ); - - // transfer rest - do_process_instruction( - #[allow(deprecated)] - transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 900, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - .unwrap(); - - // approve delegate - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 100, - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - .unwrap(); - - // insufficient funds in source account via delegate - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - #[allow(deprecated)] - transfer( - &program_id, - &account_key, - &account2_key, - &delegate_key, - &[], - 100 - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut delegate_account, - ], - ) - ); - } - - #[test] - fn test_self_transfer() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let delegate_key = Pubkey::new_unique(); - let mut delegate_account = SolanaAccount::default(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account3_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // mint to account - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - let account_info = (&account_key, false, &mut account_account).into_account_info(); - let account3_info = (&account3_key, false, &mut account3_account).into_account_info(); - let delegate_info = (&delegate_key, true, &mut delegate_account).into_account_info(); - let owner_info = (&owner_key, true, &mut owner_account).into_account_info(); - let owner2_info = (&owner2_key, true, &mut owner2_account).into_account_info(); - let mint_info = (&mint_key, false, &mut mint_account).into_account_info(); - - // transfer - #[allow(deprecated)] - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - owner_info.key, - &[], - 1000, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); - - // transfer checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner_info.key, - &[], - 1000, - 2, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); - - // missing signer - let mut owner_no_sign_info = owner_info.clone(); - #[allow(deprecated)] - let mut instruction = transfer( - &program_id, - account_info.key, - account_info.key, - owner_no_sign_info.key, - &[], - 1000, - ) - .unwrap(); - instruction.accounts[2].is_signer = false; - owner_no_sign_info.is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - owner_no_sign_info.clone(), - ], - &instruction.data, - ) - ); - - // missing signer checked - let mut instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner_no_sign_info.key, - &[], - 1000, - 2, - ) - .unwrap(); - instruction.accounts[3].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner_no_sign_info, - ], - &instruction.data, - ) - ); - - // missing owner - #[allow(deprecated)] - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - owner2_info.key, - &[], - 1000, - ) - .unwrap(); - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - owner2_info.clone(), - ], - &instruction.data, - ) - ); - - // missing owner checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner2_info.key, - &[], - 1000, - 2, - ) - .unwrap(); - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner2_info.clone(), - ], - &instruction.data, - ) - ); - - // insufficient funds - #[allow(deprecated)] - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - owner_info.key, - &[], - 1001, - ) - .unwrap(); - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - - // insufficient funds checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner_info.key, - &[], - 1001, - 2, - ) - .unwrap(); - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - - // incorrect decimals - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner_info.key, - &[], - 1, - 10, // <-- incorrect decimals - ) - .unwrap(); - assert_eq!( - Err(TokenError::MintDecimalsMismatch.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - - // incorrect mint - let instruction = transfer_checked( - &program_id, - account_info.key, - account3_info.key, // <-- incorrect mint - account_info.key, - owner_info.key, - &[], - 1, - 2, - ) - .unwrap(); - assert_eq!( - Err(TokenError::MintMismatch.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account3_info.clone(), // <-- incorrect mint - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - - // approve delegate - let instruction = approve( - &program_id, - account_info.key, - delegate_info.key, - owner_info.key, - &[], - 100, - ) - .unwrap(); - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - delegate_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - .unwrap(); - - // delegate transfer - #[allow(deprecated)] - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - delegate_info.key, - &[], - 100, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - delegate_info.clone(), - ], - &instruction.data, - ) - ); - // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); - assert_eq!(account.delegated_amount, 100); - - // delegate transfer checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - delegate_info.key, - &[], - 100, - 2, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - delegate_info.clone(), - ], - &instruction.data, - ) - ); - // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); - assert_eq!(account.delegated_amount, 100); - - // delegate insufficient funds - #[allow(deprecated)] - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - delegate_info.key, - &[], - 101, - ) - .unwrap(); - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - delegate_info.clone(), - ], - &instruction.data, - ) - ); - - // delegate insufficient funds checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - delegate_info.key, - &[], - 101, - 2, - ) - .unwrap(); - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - delegate_info.clone(), - ], - &instruction.data, - ) - ); - - // owner transfer with delegate assigned - #[allow(deprecated)] - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - owner_info.key, - &[], - 1000, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); - - // owner transfer with delegate assigned checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner_info.key, - &[], - 1000, - 2, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); - } - - #[test] - fn test_mintable_token_with_zero_supply() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create mint-able token with zero supply - let decimals = 2; - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, decimals).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!( - mint, - Mint { - mint_authority: COption::Some(owner_key), - supply: 0, - decimals, - is_initialized: true, - freeze_authority: COption::None, - } - ); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // mint to - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - let _ = Mint::unpack(&mint_account.data).unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 42); - - // mint to 2, with incorrect decimals - assert_eq!( - Err(TokenError::MintDecimalsMismatch.into()), - do_process_instruction( - mint_to_checked( - &program_id, - &mint_key, - &account_key, - &owner_key, - &[], - 42, - decimals + 1 - ) - .unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - ); - - let _ = Mint::unpack(&mint_account.data).unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 42); - - // mint to 2 - do_process_instruction( - mint_to_checked( - &program_id, - &mint_key, - &account_key, - &owner_key, - &[], - 42, - decimals, - ) - .unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - let _ = Mint::unpack(&mint_account.data).unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 84); - } - - #[test] - fn test_approve_dups() { - let program_id = crate::id(); - let account1_key = Pubkey::new_unique(); - let mut account1_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_info: AccountInfo = (&account2_key, false, &mut account2_account).into(); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account3_info: AccountInfo = (&account3_key, true, &mut account3_account).into(); - let multisig_key = Pubkey::new_unique(); - let mut multisig_account = SolanaAccount::new( - multisig_minimum_balance(), - Multisig::get_packed_len(), - &program_id, - ); - let multisig_info: AccountInfo = (&multisig_key, true, &mut multisig_account).into(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - // create account - do_process_instruction_dups( - initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // create another account - do_process_instruction_dups( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - account2_info.clone(), - mint_info.clone(), - owner_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // mint to account - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], - ) - .unwrap(); - - // source-owner approve - do_process_instruction_dups( - approve( - &program_id, - &account1_key, - &account2_key, - &account1_key, - &[], - 500, - ) - .unwrap(), - vec![ - account1_info.clone(), - account2_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // source-owner approve_checked - do_process_instruction_dups( - approve_checked( - &program_id, - &account1_key, - &mint_key, - &account2_key, - &account1_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account2_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // source-owner revoke - do_process_instruction_dups( - revoke(&program_id, &account1_key, &account1_key, &[]).unwrap(), - vec![account1_info.clone(), account1_info.clone()], - ) - .unwrap(); - - // test source-multisig signer - do_process_instruction_dups( - initialize_multisig(&program_id, &multisig_key, &[&account3_key], 1).unwrap(), - vec![ - multisig_info.clone(), - rent_info.clone(), - account3_info.clone(), - ], - ) - .unwrap(); - - do_process_instruction_dups( - initialize_account(&program_id, &account3_key, &mint_key, &multisig_key).unwrap(), - vec![ - account3_info.clone(), - mint_info.clone(), - multisig_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account3_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account3_info.clone(), owner_info.clone()], - ) - .unwrap(); - - // source-multisig-signer approve - do_process_instruction_dups( - approve( - &program_id, - &account3_key, - &account2_key, - &multisig_key, - &[&account3_key], - 500, - ) - .unwrap(), - vec![ - account3_info.clone(), - account2_info.clone(), - multisig_info.clone(), - account3_info.clone(), - ], - ) - .unwrap(); - - // source-multisig-signer approve_checked - do_process_instruction_dups( - approve_checked( - &program_id, - &account3_key, - &mint_key, - &account2_key, - &multisig_key, - &[&account3_key], - 500, - 2, - ) - .unwrap(), - vec![ - account3_info.clone(), - mint_info.clone(), - account2_info.clone(), - multisig_info.clone(), - account3_info.clone(), - ], - ) - .unwrap(); - - // source-owner multisig-signer - do_process_instruction_dups( - revoke(&program_id, &account3_key, &multisig_key, &[&account3_key]).unwrap(), - vec![ - account3_info.clone(), - multisig_info.clone(), - account3_info.clone(), - ], - ) - .unwrap(); - - // approve to source - do_process_instruction_dups( - approve_checked( - &program_id, - &account2_key, - &mint_key, - &account2_key, - &owner_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![ - account2_info.clone(), - mint_info.clone(), - account2_info.clone(), - owner_info.clone(), - ], - ) - .unwrap(); - - // source-delegate revoke, force account2 to be a signer - let account2_info: AccountInfo = (&account2_key, true, &mut account2_account).into(); - do_process_instruction_dups( - revoke(&program_id, &account2_key, &account2_key, &[]).unwrap(), - vec![account2_info.clone(), account2_info.clone()], - ) - .unwrap(); - } - - #[test] - fn test_approve() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let delegate_key = Pubkey::new_unique(); - let mut delegate_account = SolanaAccount::default(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // mint to account - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - // missing signer - let mut instruction = approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 100, - ) - .unwrap(); - instruction.accounts[2].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - do_process_instruction( - instruction, - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - ); - - // no owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner2_key, - &[], - 100 - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner2_account, - ], - ) - ); - - // approve delegate - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 100, - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - .unwrap(); - - // approve delegate 2, with incorrect decimals - assert_eq!( - Err(TokenError::MintDecimalsMismatch.into()), - do_process_instruction( - approve_checked( - &program_id, - &account_key, - &mint_key, - &delegate_key, - &owner_key, - &[], - 100, - 0 // <-- incorrect decimals - ) - .unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut delegate_account, - &mut owner_account, - ], - ) - ); - - // approve delegate 2, with incorrect mint - assert_eq!( - Err(TokenError::MintMismatch.into()), - do_process_instruction( - approve_checked( - &program_id, - &account_key, - &account2_key, // <-- bad mint - &delegate_key, - &owner_key, - &[], - 100, - 0 - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, // <-- bad mint - &mut delegate_account, - &mut owner_account, - ], - ) - ); - - // approve delegate 2 - do_process_instruction( - approve_checked( - &program_id, - &account_key, - &mint_key, - &delegate_key, - &owner_key, - &[], - 100, - 2, - ) - .unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut delegate_account, - &mut owner_account, - ], - ) - .unwrap(); - - // revoke delegate - do_process_instruction( - revoke(&program_id, &account_key, &owner_key, &[]).unwrap(), - vec![&mut account_account, &mut owner_account], - ) - .unwrap(); - - // approve delegate 3 - do_process_instruction( - approve_checked( - &program_id, - &account_key, - &mint_key, - &delegate_key, - &owner_key, - &[], - 100, - 2, - ) - .unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut delegate_account, - &mut owner_account, - ], - ) - .unwrap(); - - // revoke by delegate - do_process_instruction( - revoke(&program_id, &account_key, &delegate_key, &[]).unwrap(), - vec![&mut account_account, &mut delegate_account], - ) - .unwrap(); - - // fails the second time - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - revoke(&program_id, &account_key, &delegate_key, &[]).unwrap(), - vec![&mut account_account, &mut delegate_account], - ) - ); - } - - #[test] - fn test_set_authority_dups() { - let program_id = crate::id(); - let account1_key = Pubkey::new_unique(); - let mut account1_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &mint_key, Some(&mint_key), 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - // create account - do_process_instruction_dups( - initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // set mint_authority when currently self - do_process_instruction_dups( - set_authority( - &program_id, - &mint_key, - Some(&owner_key), - AuthorityType::MintTokens, - &mint_key, - &[], - ) - .unwrap(), - vec![mint_info.clone(), mint_info.clone()], - ) - .unwrap(); - - // set freeze_authority when currently self - do_process_instruction_dups( - set_authority( - &program_id, - &mint_key, - Some(&owner_key), - AuthorityType::FreezeAccount, - &mint_key, - &[], - ) - .unwrap(), - vec![mint_info.clone(), mint_info.clone()], - ) - .unwrap(); - - // set account owner when currently self - do_process_instruction_dups( - set_authority( - &program_id, - &account1_key, - Some(&owner_key), - AuthorityType::AccountOwner, - &account1_key, - &[], - ) - .unwrap(), - vec![account1_info.clone(), account1_info.clone()], - ) - .unwrap(); - - // set close_authority when currently self - let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.close_authority = COption::Some(account1_key); - Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); - - do_process_instruction_dups( - set_authority( - &program_id, - &account1_key, - Some(&owner_key), - AuthorityType::CloseAccount, - &account1_key, - &[], - ) - .unwrap(), - vec![account1_info.clone(), account1_info.clone()], - ) - .unwrap(); - } - - #[test] - fn test_set_authority() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let owner3_key = Pubkey::new_unique(); - let mut owner3_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint2_key = Pubkey::new_unique(); - let mut mint2_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create new mint with owner - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create mint with owner and freeze_authority - do_process_instruction( - initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), - vec![&mut mint2_account, &mut rent_sysvar], - ) - .unwrap(); - - // invalid account - assert_eq!( - Err(ProgramError::InvalidAccountData), - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner2_key), - AuthorityType::AccountOwner, - &owner_key, - &[] - ) - .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - ); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint2_key, &owner_key).unwrap(), - vec![ - &mut account2_account, - &mut mint2_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // missing owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner_key), - AuthorityType::AccountOwner, - &owner2_key, - &[] - ) - .unwrap(), - vec![&mut account_account, &mut owner2_account], - ) - ); - - // owner did not sign - let mut instruction = set_authority( - &program_id, - &account_key, - Some(&owner2_key), - AuthorityType::AccountOwner, - &owner_key, - &[], - ) - .unwrap(); - instruction.accounts[1].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - do_process_instruction(instruction, vec![&mut account_account, &mut owner_account,],) - ); - - // wrong authority type - assert_eq!( - Err(TokenError::AuthorityTypeNotSupported.into()), - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner2_key), - AuthorityType::FreezeAccount, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - ); - - // account owner may not be set to None - assert_eq!( - Err(TokenError::InvalidInstruction.into()), - do_process_instruction( - set_authority( - &program_id, - &account_key, - None, - AuthorityType::AccountOwner, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - ); - - // set delegate - do_process_instruction( - approve( - &program_id, - &account_key, - &owner2_key, - &owner_key, - &[], - u64::MAX, - ) - .unwrap(), - vec![ - &mut account_account, - &mut owner2_account, - &mut owner_account, - ], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.delegate, COption::Some(owner2_key)); - assert_eq!(account.delegated_amount, u64::MAX); - - // set owner - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner3_key), - AuthorityType::AccountOwner, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - .unwrap(); - - // check delegate cleared - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.delegate, COption::None); - assert_eq!(account.delegated_amount, 0); - - // set owner without existing delegate - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner2_key), - AuthorityType::AccountOwner, - &owner3_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner3_account], - ) - .unwrap(); - - // set close_authority - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner2_key), - AuthorityType::CloseAccount, - &owner2_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner2_account], - ) - .unwrap(); - - // close_authority may be set to None - do_process_instruction( - set_authority( - &program_id, - &account_key, - None, - AuthorityType::CloseAccount, - &owner2_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner2_account], - ) - .unwrap(); - - // wrong owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - set_authority( - &program_id, - &mint_key, - Some(&owner3_key), - AuthorityType::MintTokens, - &owner2_key, - &[] - ) - .unwrap(), - vec![&mut mint_account, &mut owner2_account], - ) - ); - - // owner did not sign - let mut instruction = set_authority( - &program_id, - &mint_key, - Some(&owner2_key), - AuthorityType::MintTokens, - &owner_key, - &[], - ) - .unwrap(); - instruction.accounts[1].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - do_process_instruction(instruction, vec![&mut mint_account, &mut owner_account],) - ); - - // cannot freeze - assert_eq!( - Err(TokenError::MintCannotFreeze.into()), - do_process_instruction( - set_authority( - &program_id, - &mint_key, - Some(&owner2_key), - AuthorityType::FreezeAccount, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut mint_account, &mut owner_account], - ) - ); - - // set owner - do_process_instruction( - set_authority( - &program_id, - &mint_key, - Some(&owner2_key), - AuthorityType::MintTokens, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut mint_account, &mut owner_account], - ) - .unwrap(); - - // set owner to None - do_process_instruction( - set_authority( - &program_id, - &mint_key, - None, - AuthorityType::MintTokens, - &owner2_key, - &[], - ) - .unwrap(), - vec![&mut mint_account, &mut owner2_account], - ) - .unwrap(); - - // test unsetting mint_authority is one-way operation - assert_eq!( - Err(TokenError::FixedSupply.into()), - do_process_instruction( - set_authority( - &program_id, - &mint2_key, - Some(&owner2_key), - AuthorityType::MintTokens, - &owner_key, - &[] - ) - .unwrap(), - vec![&mut mint_account, &mut owner_account], - ) - ); - - // set freeze_authority - do_process_instruction( - set_authority( - &program_id, - &mint2_key, - Some(&owner2_key), - AuthorityType::FreezeAccount, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut mint2_account, &mut owner_account], - ) - .unwrap(); - - // test unsetting freeze_authority is one-way operation - do_process_instruction( - set_authority( - &program_id, - &mint2_key, - None, - AuthorityType::FreezeAccount, - &owner2_key, - &[], - ) - .unwrap(), - vec![&mut mint2_account, &mut owner2_account], - ) - .unwrap(); - - assert_eq!( - Err(TokenError::MintCannotFreeze.into()), - do_process_instruction( - set_authority( - &program_id, - &mint2_key, - Some(&owner2_key), - AuthorityType::FreezeAccount, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut mint2_account, &mut owner2_account], - ) - ); - } - - #[test] - fn test_set_authority_with_immutable_owner_extension() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - - let account_len = - ExtensionType::get_account_len::(&[ExtensionType::ImmutableOwner]); - let mut account_account = SolanaAccount::new( - Rent::default().minimum_balance(account_len), - account_len, - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create mint - assert_eq!( - Ok(()), - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - ); - - // create account - assert_eq!( - Ok(()), - do_process_instruction( - initialize_immutable_owner(&program_id, &account_key).unwrap(), - vec![&mut account_account], - ) - ); - assert_eq!( - Ok(()), - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - ); - - // Immutable Owner extension blocks account owner authority changes - assert_eq!( - Err(TokenError::ImmutableOwner.into()), - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner2_key), - AuthorityType::AccountOwner, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - ); - } - - #[test] - fn test_mint_to_dups() { - let program_id = crate::id(); - let account1_key = Pubkey::new_unique(); - let mut account1_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &mint_key, None, 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - // create account - do_process_instruction_dups( - initialize_account(&program_id, &account1_key, &mint_key, &owner_key).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - owner_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // mint_to when mint_authority is self - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account1_key, &mint_key, &[], 42).unwrap(), - vec![mint_info.clone(), account1_info.clone(), mint_info.clone()], - ) - .unwrap(); - - // mint_to_checked when mint_authority is self - do_process_instruction_dups( - mint_to_checked(&program_id, &mint_key, &account1_key, &mint_key, &[], 42, 2).unwrap(), - vec![mint_info.clone(), account1_info.clone(), mint_info.clone()], - ) - .unwrap(); - - // mint_to when mint_authority is account owner - let mut mint = Mint::unpack_unchecked(&mint_info.data.borrow()).unwrap(); - mint.mint_authority = COption::Some(account1_key); - Mint::pack(mint, &mut mint_info.data.borrow_mut()).unwrap(); - do_process_instruction_dups( - mint_to( - &program_id, - &mint_key, - &account1_key, - &account1_key, - &[], - 42, - ) - .unwrap(), - vec![ - mint_info.clone(), - account1_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // mint_to_checked when mint_authority is account owner - do_process_instruction_dups( - mint_to( - &program_id, - &mint_key, - &account1_key, - &account1_key, - &[], - 42, - ) - .unwrap(), - vec![ - mint_info.clone(), - account1_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - } - - #[test] - fn test_mint_to() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let mismatch_key = Pubkey::new_unique(); - let mut mismatch_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint2_key = Pubkey::new_unique(); - let uninitialized_key = Pubkey::new_unique(); - let mut uninitialized_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let mut rent_sysvar = rent_sysvar(); - - // create new mint with owner - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account3_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create mismatch account - do_process_instruction( - initialize_account(&program_id, &mismatch_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut mismatch_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); - account.mint = mint2_key; - Account::pack(account, &mut mismatch_account.data).unwrap(); - - // mint to - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!(mint.supply, 42); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 42); - - // mint to another account to test supply accumulation - do_process_instruction( - mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(), - vec![&mut mint_account, &mut account2_account, &mut owner_account], - ) - .unwrap(); - - let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!(mint.supply, 84); - let account = Account::unpack_unchecked(&account2_account.data).unwrap(); - assert_eq!(account.amount, 42); - - // missing signer - let mut instruction = - mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(); - instruction.accounts[2].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - do_process_instruction( - instruction, - vec![&mut mint_account, &mut account2_account, &mut owner_account], - ) - ); - - // mismatch account - assert_eq!( - Err(TokenError::MintMismatch.into()), - do_process_instruction( - mint_to(&program_id, &mint_key, &mismatch_key, &owner_key, &[], 42).unwrap(), - vec![&mut mint_account, &mut mismatch_account, &mut owner_account], - ) - ); - - // missing owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - mint_to(&program_id, &mint_key, &account2_key, &owner2_key, &[], 42).unwrap(), - vec![ - &mut mint_account, - &mut account2_account, - &mut owner2_account, - ], - ) - ); - - // mint not owned by program - let not_program_id = Pubkey::new_unique(); - mint_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 0).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - ); - mint_account.owner = program_id; - - // account not owned by program - let not_program_id = Pubkey::new_unique(); - account_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 0).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - ); - account_account.owner = program_id; - - // uninitialized destination account - assert_eq!( - Err(ProgramError::UninitializedAccount), - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &uninitialized_key, - &owner_key, - &[], - 42 - ) - .unwrap(), - vec![ - &mut mint_account, - &mut uninitialized_account, - &mut owner_account, - ], - ) - ); - - // unset mint_authority and test minting fails - do_process_instruction( - set_authority( - &program_id, - &mint_key, - None, - AuthorityType::MintTokens, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut mint_account, &mut owner_account], - ) - .unwrap(); - assert_eq!( - Err(TokenError::FixedSupply.into()), - do_process_instruction( - mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(), - vec![&mut mint_account, &mut account2_account, &mut owner_account], - ) - ); - } - - #[test] - fn test_burn_dups() { - let program_id = crate::id(); - let account1_key = Pubkey::new_unique(); - let mut account1_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - // create account - do_process_instruction_dups( - initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // mint to account - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], - ) - .unwrap(); - - // source-owner burn - do_process_instruction_dups( - burn( - &program_id, - &mint_key, - &account1_key, - &account1_key, - &[], - 500, - ) - .unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // source-owner burn_checked - do_process_instruction_dups( - burn_checked( - &program_id, - &account1_key, - &mint_key, - &account1_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // mint-owner burn - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], - ) - .unwrap(); - let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.owner = mint_key; - Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); - do_process_instruction_dups( - burn(&program_id, &account1_key, &mint_key, &mint_key, &[], 500).unwrap(), - vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], - ) - .unwrap(); - - // mint-owner burn_checked - do_process_instruction_dups( - burn_checked( - &program_id, - &account1_key, - &mint_key, - &mint_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], - ) - .unwrap(); - - // source-delegate burn - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], - ) - .unwrap(); - let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.delegated_amount = 1000; - account.delegate = COption::Some(account1_key); - account.owner = owner_key; - Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); - do_process_instruction_dups( - burn( - &program_id, - &account1_key, - &mint_key, - &account1_key, - &[], - 500, - ) - .unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // source-delegate burn_checked - do_process_instruction_dups( - burn_checked( - &program_id, - &account1_key, - &mint_key, - &account1_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // mint-delegate burn - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], - ) - .unwrap(); - let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.delegated_amount = 1000; - account.delegate = COption::Some(mint_key); - account.owner = owner_key; - Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); - do_process_instruction_dups( - burn(&program_id, &account1_key, &mint_key, &mint_key, &[], 500).unwrap(), - vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], - ) - .unwrap(); - - // mint-delegate burn_checked - do_process_instruction_dups( - burn_checked( - &program_id, - &account1_key, - &mint_key, - &mint_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], - ) - .unwrap(); - } - - #[test] - fn test_burn() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let delegate_key = Pubkey::new_unique(); - let mut delegate_account = SolanaAccount::default(); - let mismatch_key = Pubkey::new_unique(); - let mut mismatch_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint2_key = Pubkey::new_unique(); - let mut rent_sysvar = rent_sysvar(); - - // create new mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account3_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create mismatch account - do_process_instruction( - initialize_account(&program_id, &mismatch_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut mismatch_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // mint to account - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - // mint to mismatch account and change mint key - do_process_instruction( - mint_to(&program_id, &mint_key, &mismatch_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut mismatch_account, &mut owner_account], - ) - .unwrap(); - let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); - account.mint = mint2_key; - Account::pack(account, &mut mismatch_account.data).unwrap(); - - // missing signer - let mut instruction = - burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 42).unwrap(); - instruction.accounts[1].is_signer = false; - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - instruction, - vec![ - &mut account_account, - &mut mint_account, - &mut delegate_account - ], - ) - ); - - // missing owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &owner2_key, &[], 42).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner2_account], - ) - ); - - // account not owned by program - let not_program_id = Pubkey::new_unique(); - account_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &owner_key, &[], 0).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - account_account.owner = program_id; - - // mint not owned by program - let not_program_id = Pubkey::new_unique(); - mint_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &owner_key, &[], 0).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - mint_account.owner = program_id; - - // mint mismatch - assert_eq!( - Err(TokenError::MintMismatch.into()), - do_process_instruction( - burn(&program_id, &mismatch_key, &mint_key, &owner_key, &[], 42).unwrap(), - vec![&mut mismatch_account, &mut mint_account, &mut owner_account], - ) - ); - - // burn - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &owner_key, &[], 21).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - - // burn_checked, with incorrect decimals - assert_eq!( - Err(TokenError::MintDecimalsMismatch.into()), - do_process_instruction( - burn_checked(&program_id, &account_key, &mint_key, &owner_key, &[], 21, 3).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - - // burn_checked - do_process_instruction( - burn_checked(&program_id, &account_key, &mint_key, &owner_key, &[], 21, 2).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - - let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!(mint.supply, 2000 - 42); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 1000 - 42); - - // insufficient funds - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - burn( - &program_id, - &account_key, - &mint_key, - &owner_key, - &[], - 100_000_000 - ) - .unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - - // approve delegate - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 84, - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - .unwrap(); - - // not a delegate of source account - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - burn( - &program_id, - &account_key, - &mint_key, - &owner_key, - &[], - 100_000_000 - ) - .unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - - // burn via delegate - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 84).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut delegate_account, - ], - ) - .unwrap(); - - // match - let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!(mint.supply, 2000 - 42 - 84); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 1000 - 42 - 84); - - // insufficient funds approved via delegate - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - burn( - &program_id, - &account_key, - &mint_key, - &delegate_key, - &[], - 100 - ) - .unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut delegate_account - ], - ) - ); - } - - #[test] - fn test_multisig() { - let program_id = crate::id(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let account_key = Pubkey::new_unique(); - let mut account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let multisig_key = Pubkey::new_unique(); - let mut multisig_account = SolanaAccount::new(42, Multisig::get_packed_len(), &program_id); - let multisig_delegate_key = Pubkey::new_unique(); - let mut multisig_delegate_account = SolanaAccount::new( - multisig_minimum_balance(), - Multisig::get_packed_len(), - &program_id, - ); - let signer_keys = vec![Pubkey::new_unique(); MAX_SIGNERS]; - let signer_key_refs: Vec<&Pubkey> = signer_keys.iter().collect(); - let mut signer_accounts = vec![SolanaAccount::new(0, 0, &program_id); MAX_SIGNERS]; - let mut rent_sysvar = rent_sysvar(); - - // multisig is not rent exempt - let account_info_iter = &mut signer_accounts.iter_mut(); - assert_eq!( - Err(TokenError::NotRentExempt.into()), - do_process_instruction( - initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), - vec![ - &mut multisig_account, - &mut rent_sysvar, - account_info_iter.next().unwrap(), - ], - ) - ); - - multisig_account.lamports = multisig_minimum_balance(); - let mut multisig_account2 = multisig_account.clone(); - - // single signer - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), - vec![ - &mut multisig_account, - &mut rent_sysvar, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // single signer using `initialize_multisig2` - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - initialize_multisig2(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), - vec![&mut multisig_account2, account_info_iter.next().unwrap()], - ) - .unwrap(); - - // multiple signer - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - initialize_multisig( - &program_id, - &multisig_delegate_key, - &signer_key_refs, - MAX_SIGNERS as u8, - ) - .unwrap(), - vec![ - &mut multisig_delegate_account, - &mut rent_sysvar, - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // create new mint with multisig owner - do_process_instruction( - initialize_mint(&program_id, &mint_key, &multisig_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account with multisig owner - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &multisig_key).unwrap(), - vec![ - &mut account, - &mut mint_account, - &mut multisig_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account with multisig owner - do_process_instruction( - initialize_account( - &program_id, - &account2_key, - &mint_key, - &multisig_delegate_key, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut multisig_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // mint to account - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account_key, - &multisig_key, - &[&signer_keys[0]], - 1000, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // approve - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - approve( - &program_id, - &account_key, - &multisig_delegate_key, - &multisig_key, - &[&signer_keys[0]], - 100, - ) - .unwrap(), - vec![ - &mut account, - &mut multisig_delegate_account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // transfer - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - #[allow(deprecated)] - transfer( - &program_id, - &account_key, - &account2_key, - &multisig_key, - &[&signer_keys[0]], - 42, - ) - .unwrap(), - vec![ - &mut account, - &mut account2_account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // transfer via delegate - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - #[allow(deprecated)] - transfer( - &program_id, - &account_key, - &account2_key, - &multisig_delegate_key, - &signer_key_refs, - 42, - ) - .unwrap(), - vec![ - &mut account, - &mut account2_account, - &mut multisig_delegate_account, - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // mint to - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account2_key, - &multisig_key, - &[&signer_keys[0]], - 42, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account2_account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // burn - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - burn( - &program_id, - &account_key, - &mint_key, - &multisig_key, - &[&signer_keys[0]], - 42, - ) - .unwrap(), - vec![ - &mut account, - &mut mint_account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // burn via delegate - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - burn( - &program_id, - &account_key, - &mint_key, - &multisig_delegate_key, - &signer_key_refs, - 42, - ) - .unwrap(), - vec![ - &mut account, - &mut mint_account, - &mut multisig_delegate_account, - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // freeze account - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let mint2_key = Pubkey::new_unique(); - let mut mint2_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - do_process_instruction( - initialize_mint( - &program_id, - &mint2_key, - &multisig_key, - Some(&multisig_key), - 2, - ) - .unwrap(), - vec![&mut mint2_account, &mut rent_sysvar], - ) - .unwrap(); - do_process_instruction( - initialize_account(&program_id, &account3_key, &mint2_key, &owner_key).unwrap(), - vec![ - &mut account3_account, - &mut mint2_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - mint_to( - &program_id, - &mint2_key, - &account3_key, - &multisig_key, - &[&signer_keys[0]], - 1000, - ) - .unwrap(), - vec![ - &mut mint2_account, - &mut account3_account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - freeze_account( - &program_id, - &account3_key, - &mint2_key, - &multisig_key, - &[&signer_keys[0]], - ) - .unwrap(), - vec![ - &mut account3_account, - &mut mint2_account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // do SetAuthority on mint - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - set_authority( - &program_id, - &mint_key, - Some(&owner_key), - AuthorityType::MintTokens, - &multisig_key, - &[&signer_keys[0]], - ) - .unwrap(), - vec![ - &mut mint_account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // do SetAuthority on account - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner_key), - AuthorityType::AccountOwner, - &multisig_key, - &[&signer_keys[0]], - ) - .unwrap(), - vec![ - &mut account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - } - - #[test] - fn test_validate_owner() { - let program_id = crate::id(); - let owner_key = Pubkey::new_unique(); - let account_to_validate = Pubkey::new_unique(); - let mut signer_keys = [Pubkey::default(); MAX_SIGNERS]; - for signer_key in signer_keys.iter_mut().take(MAX_SIGNERS) { - *signer_key = Pubkey::new_unique(); - } - let mut signer_lamports = 0; - let mut signer_data = vec![]; - let mut signers = vec![ - AccountInfo::new( - &owner_key, - true, - false, - &mut signer_lamports, - &mut signer_data, - &program_id, - false, - Epoch::default(), - ); - MAX_SIGNERS + 1 - ]; - for (signer, key) in signers.iter_mut().zip(&signer_keys) { - signer.key = key; - } - let mut lamports = 0; - let mut data = vec![0; Multisig::get_packed_len()]; - let mut multisig = Multisig::unpack_unchecked(&data).unwrap(); - multisig.m = MAX_SIGNERS as u8; - multisig.n = MAX_SIGNERS as u8; - multisig.signers = signer_keys; - multisig.is_initialized = true; - Multisig::pack(multisig, &mut data).unwrap(); - let owner_account_info = AccountInfo::new( - &owner_key, - false, - false, - &mut lamports, - &mut data, - &program_id, - false, - Epoch::default(), - ); - - // no multisig, but the account is its own authority, and data is mutably borrowed - { - let mut lamports = 0; - let mut data = vec![0; Account::get_packed_len()]; - let mut account = Account::unpack_unchecked(&data).unwrap(); - account.owner = account_to_validate; - Account::pack(account, &mut data).unwrap(); - let account_info = AccountInfo::new( - &account_to_validate, - true, - false, - &mut lamports, - &mut data, - &program_id, - false, - Epoch::default(), - ); - let account_info_data_len = account_info.data_len(); - let mut borrowed_data = account_info.try_borrow_mut_data().unwrap(); - Processor::validate_owner( - &program_id, - &account_to_validate, - &account_info, - account_info_data_len, - &[], - ) - .unwrap(); - // modify the data to be sure that it wasn't silently dropped by the compiler - borrowed_data[0] = 1; - } - - // full 11 of 11 - Processor::validate_owner( - &program_id, - &owner_key, - &owner_account_info, - owner_account_info.data_len(), - &signers, - ) - .unwrap(); - - // 1 of 11 - { - let mut multisig = - Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); - multisig.m = 1; - Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); - } - Processor::validate_owner( - &program_id, - &owner_key, - &owner_account_info, - owner_account_info.data_len(), - &signers, - ) - .unwrap(); - - // 2:1 - { - let mut multisig = - Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); - multisig.m = 2; - multisig.n = 1; - Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); - } - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - Processor::validate_owner( - &program_id, - &owner_key, - &owner_account_info, - owner_account_info.data_len(), - &signers - ) - ); - - // 0:11 - { - let mut multisig = - Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); - multisig.m = 0; - multisig.n = 11; - Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); - } - Processor::validate_owner( - &program_id, - &owner_key, - &owner_account_info, - owner_account_info.data_len(), - &signers, - ) - .unwrap(); - - // 2:11 but 0 provided - { - let mut multisig = - Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); - multisig.m = 2; - multisig.n = 11; - Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); - } - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - Processor::validate_owner( - &program_id, - &owner_key, - &owner_account_info, - owner_account_info.data_len(), - &[] - ) - ); - // 2:11 but 1 provided - { - let mut multisig = - Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); - multisig.m = 2; - multisig.n = 11; - Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); - } - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - Processor::validate_owner( - &program_id, - &owner_key, - &owner_account_info, - owner_account_info.data_len(), - &signers[0..1] - ) - ); - - // 2:11, 2 from middle provided - { - let mut multisig = - Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); - multisig.m = 2; - multisig.n = 11; - Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); - } - Processor::validate_owner( - &program_id, - &owner_key, - &owner_account_info, - owner_account_info.data_len(), - &signers[5..7], - ) - .unwrap(); - - // 11:11, one is not a signer - { - let mut multisig = - Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); - multisig.m = 11; - multisig.n = 11; - Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); - } - signers[5].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - Processor::validate_owner( - &program_id, - &owner_key, - &owner_account_info, - owner_account_info.data_len(), - &signers - ) - ); - signers[5].is_signer = true; - - // 11:11, single signer signs multiple times - { - let mut signer_lamports = 0; - let mut signer_data = vec![]; - let signers = vec![ - AccountInfo::new( - &signer_keys[5], - true, - false, - &mut signer_lamports, - &mut signer_data, - &program_id, - false, - Epoch::default(), - ); - MAX_SIGNERS + 1 - ]; - let mut multisig = - Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); - multisig.m = 11; - multisig.n = 11; - Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - Processor::validate_owner( - &program_id, - &owner_key, - &owner_account_info, - owner_account_info.data_len(), - &signers - ) - ); - } - } - - #[test] - fn test_owner_close_account_dups() { - let program_id = crate::id(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - let to_close_key = Pubkey::new_unique(); - let mut to_close_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let to_close_account_info: AccountInfo = - (&to_close_key, true, &mut to_close_account).into(); - let destination_account_key = Pubkey::new_unique(); - let mut destination_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let destination_account_info: AccountInfo = - (&destination_account_key, true, &mut destination_account).into(); - // create account - do_process_instruction_dups( - initialize_account(&program_id, &to_close_key, &mint_key, &to_close_key).unwrap(), - vec![ - to_close_account_info.clone(), - mint_info.clone(), - to_close_account_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // source-owner close - do_process_instruction_dups( - close_account( - &program_id, - &to_close_key, - &destination_account_key, - &to_close_key, - &[], - ) - .unwrap(), - vec![ - to_close_account_info.clone(), - destination_account_info.clone(), - to_close_account_info.clone(), - ], - ) - .unwrap(); - assert_eq!(*to_close_account_info.data.borrow(), &[0u8; Account::LEN]); - } - - #[test] - fn test_close_authority_close_account_dups() { - let program_id = crate::id(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - let to_close_key = Pubkey::new_unique(); - let mut to_close_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let to_close_account_info: AccountInfo = - (&to_close_key, true, &mut to_close_account).into(); - let destination_account_key = Pubkey::new_unique(); - let mut destination_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let destination_account_info: AccountInfo = - (&destination_account_key, true, &mut destination_account).into(); - // create account - do_process_instruction_dups( - initialize_account(&program_id, &to_close_key, &mint_key, &to_close_key).unwrap(), - vec![ - to_close_account_info.clone(), - mint_info.clone(), - to_close_account_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - let mut account = Account::unpack_unchecked(&to_close_account_info.data.borrow()).unwrap(); - account.close_authority = COption::Some(to_close_key); - account.owner = owner_key; - Account::pack(account, &mut to_close_account_info.data.borrow_mut()).unwrap(); - do_process_instruction_dups( - close_account( - &program_id, - &to_close_key, - &destination_account_key, - &to_close_key, - &[], - ) - .unwrap(), - vec![ - to_close_account_info.clone(), - destination_account_info.clone(), - to_close_account_info.clone(), - ], - ) - .unwrap(); - assert_eq!(*to_close_account_info.data.borrow(), &[0u8; Account::LEN]); - } - - #[test] - fn test_close_account() { - let program_id = crate::id(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance() + 42, - Account::get_packed_len(), - &program_id, - ); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mut rent_sysvar = rent_sysvar(); - - // uninitialized - assert_eq!( - Err(ProgramError::UninitializedAccount), - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner2_account, - ], - ) - ); - - // initialize and mint to non-native account - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), - vec![ - &mut mint_account, - &mut account_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 42); - - // initialize native account - do_process_instruction( - initialize_account( - &program_id, - &account2_key, - &crate::native_mint::id(), - &owner_key, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account2_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 42); - - // close non-native account with balance - assert_eq!( - Err(TokenError::NonNativeHasBalance.into()), - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner_account, - ], - ) - ); - assert_eq!(account_account.lamports, account_minimum_balance()); - - // empty account - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &owner_key, &[], 42).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - - // wrong owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner2_account, - ], - ) - ); - - // close account - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner_account, - ], - ) - .unwrap(); - assert_eq!(account_account.lamports, 0); - assert_eq!(account3_account.lamports, 2 * account_minimum_balance()); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 0); - - // fund and initialize new non-native account to test close authority - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - account_account.lamports = 2; - - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner2_key), - AuthorityType::CloseAccount, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - .unwrap(); - - // account owner cannot authorize close if close_authority is set - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner_account, - ], - ) - ); - - // close non-native account with close_authority - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner2_account, - ], - ) - .unwrap(); - assert_eq!(account_account.lamports, 0); - assert_eq!(account3_account.lamports, 2 * account_minimum_balance() + 2); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 0); - - // close native account - do_process_instruction( - close_account(&program_id, &account2_key, &account3_key, &owner_key, &[]).unwrap(), - vec![ - &mut account2_account, - &mut account3_account, - &mut owner_account, - ], - ) - .unwrap(); - assert_eq!(account2_account.data, [0u8; Account::LEN]); - assert_eq!( - account3_account.lamports, - 3 * account_minimum_balance() + 2 + 42 - ); - } - - #[test] - fn test_native_token() { - let program_id = crate::id(); - let mut mint_account = native_mint(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance() + 40, - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new(account_minimum_balance(), 0, &program_id); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let owner3_key = Pubkey::new_unique(); - let mut rent_sysvar = rent_sysvar(); - - // initialize native account - do_process_instruction( - initialize_account( - &program_id, - &account_key, - &crate::native_mint::id(), - &owner_key, - ) - .unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 40); - - // initialize native account - do_process_instruction( - initialize_account( - &program_id, - &account2_key, - &crate::native_mint::id(), - &owner_key, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account2_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 0); - - // mint_to unsupported - assert_eq!( - Err(TokenError::NativeNotSupported.into()), - do_process_instruction( - mint_to( - &program_id, - &crate::native_mint::id(), - &account_key, - &owner_key, - &[], - 42 - ) - .unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - ); - - // burn unsupported - let bogus_mint_key = Pubkey::new_unique(); - let mut bogus_mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - do_process_instruction( - initialize_mint(&program_id, &bogus_mint_key, &owner_key, None, 2).unwrap(), - vec![&mut bogus_mint_account, &mut rent_sysvar], - ) - .unwrap(); - - assert_eq!( - Err(TokenError::NativeNotSupported.into()), - do_process_instruction( - burn( - &program_id, - &account_key, - &bogus_mint_key, - &owner_key, - &[], - 42 - ) - .unwrap(), - vec![ - &mut account_account, - &mut bogus_mint_account, - &mut owner_account - ], - ) - ); - - // ensure can't transfer below rent-exempt reserve - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - #[allow(deprecated)] - transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 50, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - ); - - // transfer between native accounts - do_process_instruction( - #[allow(deprecated)] - transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 40, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - .unwrap(); - assert_eq!(account_account.lamports, account_minimum_balance()); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 0); - assert_eq!(account2_account.lamports, account_minimum_balance() + 40); - let account = Account::unpack_unchecked(&account2_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 40); - - // set close authority - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner3_key), - AuthorityType::CloseAccount, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.close_authority, COption::Some(owner3_key)); - - // set new account owner - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner2_key), - AuthorityType::AccountOwner, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - .unwrap(); - - // close authority cleared - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.close_authority, COption::None); - - // close native account - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner2_account, - ], - ) - .unwrap(); - assert_eq!(account_account.lamports, 0); - assert_eq!(account3_account.lamports, 2 * account_minimum_balance()); - assert_eq!(account_account.data, [0u8; Account::LEN]); - } - - #[test] - fn test_overflow() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mint_owner_key = Pubkey::new_unique(); - let mut mint_owner_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create new mint with owner - do_process_instruction( - initialize_mint(&program_id, &mint_key, &mint_owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create an account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner2_key).unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner2_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // mint the max to an account - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account_key, - &mint_owner_key, - &[], - u64::MAX, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account_account, - &mut mint_owner_account, - ], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, u64::MAX); - - // attempt to mint one more to account - assert_eq!( - Err(TokenError::Overflow.into()), - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account_key, - &mint_owner_key, - &[], - 1, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account_account, - &mut mint_owner_account, - ], - ) - ); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, u64::MAX); - - // atttempt to mint one more to the other account - assert_eq!( - Err(TokenError::Overflow.into()), - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account2_key, - &mint_owner_key, - &[], - 1, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account2_account, - &mut mint_owner_account, - ], - ) - ); - - // burn some of the supply - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &owner_key, &[], 100).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, u64::MAX - 100); - - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account_key, - &mint_owner_key, - &[], - 100, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account_account, - &mut mint_owner_account, - ], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, u64::MAX); - - // manipulate account balance to attempt overflow transfer - let mut account = Account::unpack_unchecked(&account2_account.data).unwrap(); - account.amount = 1; - Account::pack(account, &mut account2_account.data).unwrap(); - - assert_eq!( - Err(TokenError::Overflow.into()), - do_process_instruction( - #[allow(deprecated)] - transfer( - &program_id, - &account2_key, - &account_key, - &owner2_key, - &[], - 1, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut account_account, - &mut owner2_account, - ], - ) - ); - } - - #[test] - fn test_frozen() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create new mint and fund first account - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // fund first account - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - // no transfer if either account is frozen - let mut account = Account::unpack_unchecked(&account2_account.data).unwrap(); - account.state = AccountState::Frozen; - Account::pack(account, &mut account2_account.data).unwrap(); - assert_eq!( - Err(TokenError::AccountFrozen.into()), - do_process_instruction( - #[allow(deprecated)] - transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 500, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - ); - - let mut account = Account::unpack_unchecked(&account_account.data).unwrap(); - account.state = AccountState::Initialized; - Account::pack(account, &mut account_account.data).unwrap(); - let mut account = Account::unpack_unchecked(&account2_account.data).unwrap(); - account.state = AccountState::Frozen; - Account::pack(account, &mut account2_account.data).unwrap(); - assert_eq!( - Err(TokenError::AccountFrozen.into()), - do_process_instruction( - #[allow(deprecated)] - transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 500, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - ); - - // no approve if account is frozen - let mut account = Account::unpack_unchecked(&account_account.data).unwrap(); - account.state = AccountState::Frozen; - Account::pack(account, &mut account_account.data).unwrap(); - let delegate_key = Pubkey::new_unique(); - let mut delegate_account = SolanaAccount::default(); - assert_eq!( - Err(TokenError::AccountFrozen.into()), - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 100 - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - ); - - // no revoke if account is frozen - let mut account = Account::unpack_unchecked(&account_account.data).unwrap(); - account.delegate = COption::Some(delegate_key); - account.delegated_amount = 100; - Account::pack(account, &mut account_account.data).unwrap(); - assert_eq!( - Err(TokenError::AccountFrozen.into()), - do_process_instruction( - revoke(&program_id, &account_key, &owner_key, &[]).unwrap(), - vec![&mut account_account, &mut owner_account], - ) - ); - - // no set authority if account is frozen - let new_owner_key = Pubkey::new_unique(); - assert_eq!( - Err(TokenError::AccountFrozen.into()), - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&new_owner_key), - AuthorityType::AccountOwner, - &owner_key, - &[] - ) - .unwrap(), - vec![&mut account_account, &mut owner_account,], - ) - ); - - // no mint_to if destination account is frozen - assert_eq!( - Err(TokenError::AccountFrozen.into()), - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 100).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account,], - ) - ); - - // no burn if account is frozen - assert_eq!( - Err(TokenError::AccountFrozen.into()), - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &owner_key, &[], 100).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - } - - #[test] - fn test_freeze_thaw_dups() { - let program_id = crate::id(); - let account1_key = Pubkey::new_unique(); - let mut account1_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &owner_key, Some(&account1_key), 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - // create account - do_process_instruction_dups( - initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // freeze where mint freeze_authority is account - do_process_instruction_dups( - freeze_account(&program_id, &account1_key, &mint_key, &account1_key, &[]).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // thaw where mint freeze_authority is account - let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.state = AccountState::Frozen; - Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); - do_process_instruction_dups( - thaw_account(&program_id, &account1_key, &mint_key, &account1_key, &[]).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - } - - #[test] - fn test_freeze_account() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account_owner_key = Pubkey::new_unique(); - let mut account_owner_account = SolanaAccount::default(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create new mint with owner different from account owner - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &account_owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut account_owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // mint to account - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - // mint cannot freeze - assert_eq!( - Err(TokenError::MintCannotFreeze.into()), - do_process_instruction( - freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - - // missing freeze_authority - let mut mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - mint.freeze_authority = COption::Some(owner_key); - Mint::pack(mint, &mut mint_account.data).unwrap(); - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - freeze_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner2_account], - ) - ); - - // check explicit thaw - assert_eq!( - Err(TokenError::InvalidState.into()), - do_process_instruction( - thaw_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner2_account], - ) - ); - - // freeze - do_process_instruction( - freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.state, AccountState::Frozen); - - // check explicit freeze - assert_eq!( - Err(TokenError::InvalidState.into()), - do_process_instruction( - freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - - // check thaw authority - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - thaw_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner2_account], - ) - ); - - // thaw - do_process_instruction( - thaw_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.state, AccountState::Initialized); - } - - #[test] - fn test_initialize_account2_and_3() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - do_process_instruction( - initialize_account2(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account2_account, &mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - assert_eq!(account_account, account2_account); - - do_process_instruction( - initialize_account3(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account3_account, &mut mint_account], - ) - .unwrap(); - - assert_eq!(account_account, account3_account); - } - - #[test] - fn test_sync_native() { - let program_id = crate::id(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let native_account_key = Pubkey::new_unique(); - let lamports = 40; - let mut native_account = SolanaAccount::new( - account_minimum_balance() + lamports, - Account::get_packed_len(), - &program_id, - ); - let non_native_account_key = Pubkey::new_unique(); - let mut non_native_account = SolanaAccount::new( - account_minimum_balance() + 50, - Account::get_packed_len(), - &program_id, - ); - - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let mut rent_sysvar = rent_sysvar(); - - // initialize non-native mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // initialize non-native account - do_process_instruction( - initialize_account(&program_id, &non_native_account_key, &mint_key, &owner_key) - .unwrap(), - vec![ - &mut non_native_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - let account = Account::unpack_unchecked(&non_native_account.data).unwrap(); - assert!(!account.is_native()); - assert_eq!(account.amount, 0); - - // fail sync non-native - assert_eq!( - Err(TokenError::NonNativeNotSupported.into()), - do_process_instruction( - sync_native(&program_id, &non_native_account_key,).unwrap(), - vec![&mut non_native_account], - ) - ); - - // fail sync uninitialized - assert_eq!( - Err(ProgramError::UninitializedAccount), - do_process_instruction( - sync_native(&program_id, &native_account_key,).unwrap(), - vec![&mut native_account], - ) - ); - - // wrap native account - do_process_instruction( - initialize_account( - &program_id, - &native_account_key, - &crate::native_mint::id(), - &owner_key, - ) - .unwrap(), - vec![ - &mut native_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // fail sync, not owned by program - let not_program_id = Pubkey::new_unique(); - native_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - sync_native(&program_id, &native_account_key,).unwrap(), - vec![&mut native_account], - ) - ); - native_account.owner = program_id; - - let account = Account::unpack_unchecked(&native_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, lamports); - - // sync, no change - do_process_instruction( - sync_native(&program_id, &native_account_key).unwrap(), - vec![&mut native_account], - ) - .unwrap(); - let account = Account::unpack_unchecked(&native_account.data).unwrap(); - assert_eq!(account.amount, lamports); - - // transfer sol - let new_lamports = lamports + 50; - native_account.lamports = account_minimum_balance() + new_lamports; - - // success sync - do_process_instruction( - sync_native(&program_id, &native_account_key).unwrap(), - vec![&mut native_account], - ) - .unwrap(); - let account = Account::unpack_unchecked(&native_account.data).unwrap(); - assert_eq!(account.amount, new_lamports); - - // reduce sol - native_account.lamports -= 1; - - // fail sync - assert_eq!( - Err(TokenError::InvalidState.into()), - do_process_instruction( - sync_native(&program_id, &native_account_key,).unwrap(), - vec![&mut native_account], - ) - ); - } - - #[test] - #[serial] - fn test_get_account_data_size() { - // see integration tests for return-data validity - let program_id = crate::id(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let mut rent_sysvar = rent_sysvar(); - - // Base mint - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_key = Pubkey::new_unique(); - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - set_expected_data( - ExtensionType::get_account_len::(&[]) - .to_le_bytes() - .to_vec(), - ); - do_process_instruction( - get_account_data_size(&program_id, &mint_key, &[]).unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data( - ExtensionType::get_account_len::(&[ExtensionType::TransferFeeAmount]) - .to_le_bytes() - .to_vec(), - ); - do_process_instruction( - get_account_data_size( - &program_id, - &mint_key, - &[ - ExtensionType::TransferFeeAmount, - ExtensionType::TransferFeeAmount, // Duplicate user input ignored... - ], - ) - .unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - // Native mint - let mut mint_account = native_mint(); - set_expected_data( - ExtensionType::get_account_len::(&[]) - .to_le_bytes() - .to_vec(), - ); - do_process_instruction( - get_account_data_size(&program_id, &mint_key, &[]).unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - // Extended mint - let mint_len = ExtensionType::get_account_len::(&[ExtensionType::TransferFeeConfig]); - let mut extended_mint_account = SolanaAccount::new( - Rent::default().minimum_balance(mint_len), - mint_len, - &program_id, - ); - let extended_mint_key = Pubkey::new_unique(); - do_process_instruction( - initialize_transfer_fee_config(&program_id, &extended_mint_key, None, None, 10, 4242) - .unwrap(), - vec![&mut extended_mint_account], - ) - .unwrap(); - do_process_instruction( - initialize_mint(&program_id, &extended_mint_key, &owner_key, None, 2).unwrap(), - vec![&mut extended_mint_account, &mut rent_sysvar], - ) - .unwrap(); - - set_expected_data( - ExtensionType::get_account_len::(&[ExtensionType::TransferFeeAmount]) - .to_le_bytes() - .to_vec(), - ); - do_process_instruction( - get_account_data_size(&program_id, &mint_key, &[]).unwrap(), - vec![&mut extended_mint_account], - ) - .unwrap(); - - do_process_instruction( - get_account_data_size( - &program_id, - &mint_key, - &[ExtensionType::TransferFeeAmount], // User extension that's also added by the mint ignored... - ) - .unwrap(), - vec![&mut extended_mint_account], - ) - .unwrap(); - - // Invalid mint - let mut invalid_mint_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let invalid_mint_key = Pubkey::new_unique(); - do_process_instruction( - initialize_account(&program_id, &invalid_mint_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut invalid_mint_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - assert_eq!( - do_process_instruction( - get_account_data_size(&program_id, &invalid_mint_key, &[]).unwrap(), - vec![&mut invalid_mint_account], - ), - Err(TokenError::InvalidMint.into()) - ); - - // Invalid mint owner - let invalid_program_id = Pubkey::new_unique(); - let mut invalid_mint_account = SolanaAccount::new( - mint_minimum_balance(), - Mint::get_packed_len(), - &invalid_program_id, - ); - let invalid_mint_key = Pubkey::new_unique(); - let mut instruction = - initialize_mint(&program_id, &invalid_mint_key, &owner_key, None, 2).unwrap(); - instruction.program_id = invalid_program_id; - do_process_instruction( - instruction, - vec![&mut invalid_mint_account, &mut rent_sysvar], - ) - .unwrap(); - - assert_eq!( - do_process_instruction( - get_account_data_size(&program_id, &invalid_mint_key, &[]).unwrap(), - vec![&mut invalid_mint_account], - ), - Err(ProgramError::IncorrectProgramId) - ); - } - - #[test] - #[serial] - fn test_amount_to_ui_amount() { - let program_id = crate::id(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // fail if an invalid mint is passed in - assert_eq!( - Err(TokenError::InvalidMint.into()), - do_process_instruction( - amount_to_ui_amount(&program_id, &mint_key, 110).unwrap(), - vec![&mut mint_account], - ) - ); - - // create mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - set_expected_data("0.23".as_bytes().to_vec()); - do_process_instruction( - amount_to_ui_amount(&program_id, &mint_key, 23).unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data("1.1".as_bytes().to_vec()); - do_process_instruction( - amount_to_ui_amount(&program_id, &mint_key, 110).unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data("42".as_bytes().to_vec()); - do_process_instruction( - amount_to_ui_amount(&program_id, &mint_key, 4200).unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data("0".as_bytes().to_vec()); - do_process_instruction( - amount_to_ui_amount(&program_id, &mint_key, 0).unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - } - - #[test] - #[serial] - fn test_ui_amount_to_amount() { - let program_id = crate::id(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // fail if an invalid mint is passed in - assert_eq!( - Err(TokenError::InvalidMint.into()), - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "1.1").unwrap(), - vec![&mut mint_account], - ) - ); - - // create mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - set_expected_data(23u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "0.23").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(20u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "0.20").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(20u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "0.2000").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(20u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, ".20").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(110u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "1.1").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(110u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "1.10").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(4200u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "42").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(4200u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "42.").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(0u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "0").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - // fail if invalid ui_amount passed in - assert_eq!( - Err(ProgramError::InvalidArgument), - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "").unwrap(), - vec![&mut mint_account], - ) - ); - assert_eq!( - Err(ProgramError::InvalidArgument), - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, ".").unwrap(), - vec![&mut mint_account], - ) - ); - assert_eq!( - Err(ProgramError::InvalidArgument), - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "0.111").unwrap(), - vec![&mut mint_account], - ) - ); - assert_eq!( - Err(ProgramError::InvalidArgument), - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "0.t").unwrap(), - vec![&mut mint_account], - ) - ); - } -} diff --git a/token/program-2022/src/serialization.rs b/token/program-2022/src/serialization.rs deleted file mode 100644 index 9b2d269748c..00000000000 --- a/token/program-2022/src/serialization.rs +++ /dev/null @@ -1,78 +0,0 @@ -//! serialization module - -/// helper function to ser/deser COption wrapped values -pub mod coption_fromstr { - use { - serde::{ - de::{Error, Unexpected, Visitor}, - Deserializer, Serializer, - }, - solana_program::program_option::COption, - std::{ - fmt::{self, Display}, - marker::PhantomData, - str::FromStr, - }, - }; - - /// serialize values supporting Display trait wrapped in COption - pub fn serialize(x: &COption, s: S) -> Result - where - S: Serializer, - T: Display, - { - match *x { - COption::Some(ref value) => s.serialize_some(&value.to_string()), - COption::None => s.serialize_none(), - } - } - - struct COptionVisitor { - s: PhantomData, - } - - impl<'de, T> Visitor<'de> for COptionVisitor - where - T: FromStr, - { - type Value = COption; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a FromStr type") - } - - fn visit_some(self, d: D) -> Result - where - D: Deserializer<'de>, - { - d.deserialize_str(self) - } - - fn visit_str(self, v: &str) -> Result - where - E: Error, - { - T::from_str(v) - .map(|r| COption::Some(r)) - .map_err(|_| E::invalid_value(Unexpected::Str(v), &"value string")) - } - - fn visit_none(self) -> Result - where - E: Error, - { - Ok(COption::None) - } - } - - /// deserialize values supporting Display trait wrapped in COption - pub fn deserialize<'de, D, T>(d: D) -> Result, D::Error> - where - D: Deserializer<'de>, - T: FromStr, - { - d.deserialize_option(COptionVisitor { - s: PhantomData::default(), - }) - } -} diff --git a/token/program-2022/src/state.rs b/token/program-2022/src/state.rs deleted file mode 100644 index 8be9acf9065..00000000000 --- a/token/program-2022/src/state.rs +++ /dev/null @@ -1,527 +0,0 @@ -//! State transition types - -use { - crate::{ - extension::AccountType, - generic_token_account::{is_initialized_account, GenericTokenAccount}, - instruction::MAX_SIGNERS, - }, - arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}, - num_enum::{IntoPrimitive, TryFromPrimitive}, - solana_program::{ - program_error::ProgramError, - program_option::COption, - program_pack::{IsInitialized, Pack, Sealed}, - pubkey::Pubkey, - }, -}; - -/// Mint data. -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq)] -pub struct Mint { - /// Optional authority used to mint new tokens. The mint authority may only be provided during - /// mint creation. If no mint authority is present then the mint has a fixed supply and no - /// further tokens may be minted. - pub mint_authority: COption, - /// Total supply of tokens. - pub supply: u64, - /// Number of base 10 digits to the right of the decimal place. - pub decimals: u8, - /// Is `true` if this structure has been initialized - pub is_initialized: bool, - /// Optional authority to freeze token accounts. - pub freeze_authority: COption, -} -impl Sealed for Mint {} -impl IsInitialized for Mint { - fn is_initialized(&self) -> bool { - self.is_initialized - } -} -impl Pack for Mint { - const LEN: usize = 82; - fn unpack_from_slice(src: &[u8]) -> Result { - let src = array_ref![src, 0, 82]; - let (mint_authority, supply, decimals, is_initialized, freeze_authority) = - array_refs![src, 36, 8, 1, 1, 36]; - let mint_authority = unpack_coption_key(mint_authority)?; - let supply = u64::from_le_bytes(*supply); - let decimals = decimals[0]; - let is_initialized = match is_initialized { - [0] => false, - [1] => true, - _ => return Err(ProgramError::InvalidAccountData), - }; - let freeze_authority = unpack_coption_key(freeze_authority)?; - Ok(Mint { - mint_authority, - supply, - decimals, - is_initialized, - freeze_authority, - }) - } - fn pack_into_slice(&self, dst: &mut [u8]) { - let dst = array_mut_ref![dst, 0, 82]; - let ( - mint_authority_dst, - supply_dst, - decimals_dst, - is_initialized_dst, - freeze_authority_dst, - ) = mut_array_refs![dst, 36, 8, 1, 1, 36]; - let &Mint { - ref mint_authority, - supply, - decimals, - is_initialized, - ref freeze_authority, - } = self; - pack_coption_key(mint_authority, mint_authority_dst); - *supply_dst = supply.to_le_bytes(); - decimals_dst[0] = decimals; - is_initialized_dst[0] = is_initialized as u8; - pack_coption_key(freeze_authority, freeze_authority_dst); - } -} - -/// Account data. -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq)] -pub struct Account { - /// The mint associated with this account - pub mint: Pubkey, - /// The owner of this account. - pub owner: Pubkey, - /// The amount of tokens this account holds. - pub amount: u64, - /// If `delegate` is `Some` then `delegated_amount` represents - /// the amount authorized by the delegate - pub delegate: COption, - /// The account's state - pub state: AccountState, - /// If is_some, this is a native token, and the value logs the rent-exempt reserve. An Account - /// is required to be rent-exempt, so the value is used by the Processor to ensure that wrapped - /// SOL accounts do not drop below this threshold. - pub is_native: COption, - /// The amount delegated - pub delegated_amount: u64, - /// Optional authority to close the account. - pub close_authority: COption, -} -impl Account { - /// Checks if account is frozen - pub fn is_frozen(&self) -> bool { - self.state == AccountState::Frozen - } - /// Checks if account is native - pub fn is_native(&self) -> bool { - self.is_native.is_some() - } - /// Checks if a token Account's owner is the system_program or the incinerator - pub fn is_owned_by_system_program_or_incinerator(&self) -> bool { - solana_program::system_program::check_id(&self.owner) - || solana_program::incinerator::check_id(&self.owner) - } -} -impl Sealed for Account {} -impl IsInitialized for Account { - fn is_initialized(&self) -> bool { - self.state != AccountState::Uninitialized - } -} -impl Pack for Account { - const LEN: usize = 165; - fn unpack_from_slice(src: &[u8]) -> Result { - let src = array_ref![src, 0, 165]; - let (mint, owner, amount, delegate, state, is_native, delegated_amount, close_authority) = - array_refs![src, 32, 32, 8, 36, 1, 12, 8, 36]; - Ok(Account { - mint: Pubkey::new_from_array(*mint), - owner: Pubkey::new_from_array(*owner), - amount: u64::from_le_bytes(*amount), - delegate: unpack_coption_key(delegate)?, - state: AccountState::try_from_primitive(state[0]) - .or(Err(ProgramError::InvalidAccountData))?, - is_native: unpack_coption_u64(is_native)?, - delegated_amount: u64::from_le_bytes(*delegated_amount), - close_authority: unpack_coption_key(close_authority)?, - }) - } - fn pack_into_slice(&self, dst: &mut [u8]) { - let dst = array_mut_ref![dst, 0, 165]; - let ( - mint_dst, - owner_dst, - amount_dst, - delegate_dst, - state_dst, - is_native_dst, - delegated_amount_dst, - close_authority_dst, - ) = mut_array_refs![dst, 32, 32, 8, 36, 1, 12, 8, 36]; - let &Account { - ref mint, - ref owner, - amount, - ref delegate, - state, - ref is_native, - delegated_amount, - ref close_authority, - } = self; - mint_dst.copy_from_slice(mint.as_ref()); - owner_dst.copy_from_slice(owner.as_ref()); - *amount_dst = amount.to_le_bytes(); - pack_coption_key(delegate, delegate_dst); - state_dst[0] = state as u8; - pack_coption_u64(is_native, is_native_dst); - *delegated_amount_dst = delegated_amount.to_le_bytes(); - pack_coption_key(close_authority, close_authority_dst); - } -} - -/// Account state. -#[repr(u8)] -#[derive(Clone, Copy, Debug, PartialEq, IntoPrimitive, TryFromPrimitive)] -pub enum AccountState { - /// Account is not yet initialized - Uninitialized, - /// Account is initialized; the account owner and/or delegate may perform permitted operations - /// on this account - Initialized, - /// Account has been frozen by the mint freeze authority. Neither the account owner nor - /// the delegate are able to perform operations on this account. - Frozen, -} - -impl Default for AccountState { - fn default() -> Self { - AccountState::Uninitialized - } -} - -/// Multisignature data. -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq)] -pub struct Multisig { - /// Number of signers required - pub m: u8, - /// Number of valid signers - pub n: u8, - /// Is `true` if this structure has been initialized - pub is_initialized: bool, - /// Signer public keys - pub signers: [Pubkey; MAX_SIGNERS], -} -impl Sealed for Multisig {} -impl IsInitialized for Multisig { - fn is_initialized(&self) -> bool { - self.is_initialized - } -} -impl Pack for Multisig { - const LEN: usize = 355; - fn unpack_from_slice(src: &[u8]) -> Result { - let src = array_ref![src, 0, 355]; - #[allow(clippy::ptr_offset_with_cast)] - let (m, n, is_initialized, signers_flat) = array_refs![src, 1, 1, 1, 32 * MAX_SIGNERS]; - let mut result = Multisig { - m: m[0], - n: n[0], - is_initialized: match is_initialized { - [0] => false, - [1] => true, - _ => return Err(ProgramError::InvalidAccountData), - }, - signers: [Pubkey::new_from_array([0u8; 32]); MAX_SIGNERS], - }; - for (src, dst) in signers_flat.chunks(32).zip(result.signers.iter_mut()) { - *dst = Pubkey::new(src); - } - Ok(result) - } - fn pack_into_slice(&self, dst: &mut [u8]) { - let dst = array_mut_ref![dst, 0, 355]; - #[allow(clippy::ptr_offset_with_cast)] - let (m, n, is_initialized, signers_flat) = mut_array_refs![dst, 1, 1, 1, 32 * MAX_SIGNERS]; - *m = [self.m]; - *n = [self.n]; - *is_initialized = [self.is_initialized as u8]; - for (i, src) in self.signers.iter().enumerate() { - let dst_array = array_mut_ref![signers_flat, 32 * i, 32]; - dst_array.copy_from_slice(src.as_ref()); - } - } -} - -// Helpers -pub(crate) fn pack_coption_key(src: &COption, dst: &mut [u8; 36]) { - let (tag, body) = mut_array_refs![dst, 4, 32]; - match src { - COption::Some(key) => { - *tag = [1, 0, 0, 0]; - body.copy_from_slice(key.as_ref()); - } - COption::None => { - *tag = [0; 4]; - } - } -} -pub(crate) fn unpack_coption_key(src: &[u8; 36]) -> Result, ProgramError> { - let (tag, body) = array_refs![src, 4, 32]; - match *tag { - [0, 0, 0, 0] => Ok(COption::None), - [1, 0, 0, 0] => Ok(COption::Some(Pubkey::new_from_array(*body))), - _ => Err(ProgramError::InvalidAccountData), - } -} -fn pack_coption_u64(src: &COption, dst: &mut [u8; 12]) { - let (tag, body) = mut_array_refs![dst, 4, 8]; - match src { - COption::Some(amount) => { - *tag = [1, 0, 0, 0]; - *body = amount.to_le_bytes(); - } - COption::None => { - *tag = [0; 4]; - } - } -} -fn unpack_coption_u64(src: &[u8; 12]) -> Result, ProgramError> { - let (tag, body) = array_refs![src, 4, 8]; - match *tag { - [0, 0, 0, 0] => Ok(COption::None), - [1, 0, 0, 0] => Ok(COption::Some(u64::from_le_bytes(*body))), - _ => Err(ProgramError::InvalidAccountData), - } -} - -// `spl_token_program_2022::extension::AccountType::Account` ordinal value -const ACCOUNTTYPE_ACCOUNT: u8 = AccountType::Account as u8; -impl GenericTokenAccount for Account { - fn valid_account_data(account_data: &[u8]) -> bool { - // Use spl_token::state::Account::valid_account_data once possible - account_data.len() == Account::LEN && is_initialized_account(account_data) - || (account_data.len() >= Account::LEN - && account_data.len() != Multisig::LEN - && ACCOUNTTYPE_ACCOUNT - == *account_data - .get(spl_token::state::Account::get_packed_len()) - .unwrap_or(&(AccountType::Uninitialized as u8)) - && is_initialized_account(account_data)) - } -} - -#[cfg(test)] -pub(crate) mod test { - use super::*; - use crate::generic_token_account::ACCOUNT_INITIALIZED_INDEX; - - pub const TEST_MINT: Mint = Mint { - mint_authority: COption::Some(Pubkey::new_from_array([1; 32])), - supply: 42, - decimals: 7, - is_initialized: true, - freeze_authority: COption::Some(Pubkey::new_from_array([2; 32])), - }; - pub const TEST_MINT_SLICE: &[u8] = &[ - 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 42, 0, 0, 0, 0, 0, 0, 0, 7, 1, 1, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - ]; - - pub const TEST_ACCOUNT: Account = Account { - mint: Pubkey::new_from_array([1; 32]), - owner: Pubkey::new_from_array([2; 32]), - amount: 3, - delegate: COption::Some(Pubkey::new_from_array([4; 32])), - state: AccountState::Frozen, - is_native: COption::Some(5), - delegated_amount: 6, - close_authority: COption::Some(Pubkey::new_from_array([7; 32])), - }; - pub const TEST_ACCOUNT_SLICE: &[u8] = &[ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 1, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, - 0, 6, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - ]; - - #[test] - fn test_pack_unpack() { - // Mint - let check = TEST_MINT; - let mut packed = vec![0; Mint::get_packed_len() + 1]; - assert_eq!( - Err(ProgramError::InvalidAccountData), - Mint::pack(check, &mut packed) - ); - let mut packed = vec![0; Mint::get_packed_len() - 1]; - assert_eq!( - Err(ProgramError::InvalidAccountData), - Mint::pack(check, &mut packed) - ); - let mut packed = vec![0; Mint::get_packed_len()]; - Mint::pack(check, &mut packed).unwrap(); - assert_eq!(packed, TEST_MINT_SLICE); - let unpacked = Mint::unpack(&packed).unwrap(); - assert_eq!(unpacked, check); - - // Account - let check = TEST_ACCOUNT; - let mut packed = vec![0; Account::get_packed_len() + 1]; - assert_eq!( - Err(ProgramError::InvalidAccountData), - Account::pack(check, &mut packed) - ); - let mut packed = vec![0; Account::get_packed_len() - 1]; - assert_eq!( - Err(ProgramError::InvalidAccountData), - Account::pack(check, &mut packed) - ); - let mut packed = vec![0; Account::get_packed_len()]; - Account::pack(check, &mut packed).unwrap(); - let expect = TEST_ACCOUNT_SLICE; - assert_eq!(packed, expect); - let unpacked = Account::unpack(&packed).unwrap(); - assert_eq!(unpacked, check); - - // Multisig - let check = Multisig { - m: 1, - n: 2, - is_initialized: true, - signers: [Pubkey::new(&[3; 32]); MAX_SIGNERS], - }; - let mut packed = vec![0; Multisig::get_packed_len() + 1]; - assert_eq!( - Err(ProgramError::InvalidAccountData), - Multisig::pack(check, &mut packed) - ); - let mut packed = vec![0; Multisig::get_packed_len() - 1]; - assert_eq!( - Err(ProgramError::InvalidAccountData), - Multisig::pack(check, &mut packed) - ); - let mut packed = vec![0; Multisig::get_packed_len()]; - Multisig::pack(check, &mut packed).unwrap(); - let expect = vec![ - 1, 2, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, - ]; - assert_eq!(packed, expect); - let unpacked = Multisig::unpack(&packed).unwrap(); - assert_eq!(unpacked, check); - } - - #[test] - fn test_unpack_token_owner() { - // Account data length < Account::LEN, unpack will not return a key - let src: [u8; 12] = [0; 12]; - let result = Account::unpack_account_owner(&src); - assert_eq!(result, Option::None); - - // The right account data size and initialized, unpack will return some key - let mut src: [u8; Account::LEN] = [0; Account::LEN]; - src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Initialized as u8; - let result = Account::unpack_account_owner(&src); - assert!(result.is_some()); - - // The right account data size and frozen, unpack will return some key - src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Frozen as u8; - let result = Account::unpack_account_owner(&src); - assert!(result.is_some()); - - // Account data length > account data size, but not a valid extension, - // unpack will not return a key - let mut src: [u8; Account::LEN + 5] = [0; Account::LEN + 5]; - src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Initialized as u8; - let result = Account::unpack_account_owner(&src); - assert_eq!(result, Option::None); - - // Account data length > account data size with a valid extension and initialized, - // expect some key returned - let mut src: [u8; Account::LEN + 5] = [0; Account::LEN + 5]; - src[Account::LEN] = AccountType::Account as u8; - src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Initialized as u8; - let result = Account::unpack_account_owner(&src); - assert!(result.is_some()); - - // Account data length > account data size with a valid extension but uninitialized, - // expect None - src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Uninitialized as u8; - let result = Account::unpack_account_owner(&src); - assert!(result.is_none()); - - // Account data length is multi-sig data size with a valid extension and initalized, - // expect none - let mut src: [u8; Multisig::LEN] = [0; Multisig::LEN]; - src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Initialized as u8; - src[Account::LEN] = AccountType::Account as u8; - let result = Account::unpack_account_owner(&src); - assert!(result.is_none()); - } - - #[test] - fn test_unpack_token_mint() { - // Account data length < Account::LEN, unpack will not return a key - let src: [u8; 12] = [0; 12]; - let result = Account::unpack_account_mint(&src); - assert_eq!(result, Option::None); - - // The right account data size and initialized, unpack will return some key - let mut src: [u8; Account::LEN] = [0; Account::LEN]; - src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Initialized as u8; - let result = Account::unpack_account_mint(&src); - assert!(result.is_some()); - - // The right account data size and frozen, unpack will return some key - src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Frozen as u8; - let result = Account::unpack_account_mint(&src); - assert!(result.is_some()); - - // Account data length > account data size, but not a valid extension, - // unpack will not return a key - let mut src: [u8; Account::LEN + 5] = [0; Account::LEN + 5]; - src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Initialized as u8; - let result = Account::unpack_account_mint(&src); - assert_eq!(result, Option::None); - - // Account data length > account data size with a valid extension and initalized, - // expect some key returned - let mut src: [u8; Account::LEN + 5] = [0; Account::LEN + 5]; - src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Initialized as u8; - src[Account::LEN] = AccountType::Account as u8; - let result = Account::unpack_account_mint(&src); - assert!(result.is_some()); - - // Account data length > account data size with a valid extension but uninitalized, - // expect none - src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Uninitialized as u8; - let result = Account::unpack_account_mint(&src); - assert!(result.is_none()); - - // Account data length is multi-sig data size with a valid extension and initalized, - // expect none - let mut src: [u8; Multisig::LEN] = [0; Multisig::LEN]; - src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Initialized as u8; - src[Account::LEN] = AccountType::Account as u8; - let result = Account::unpack_account_mint(&src); - assert!(result.is_none()); - } -} diff --git a/token/program-2022/tests/action.rs b/token/program-2022/tests/action.rs deleted file mode 100644 index 009713c24fe..00000000000 --- a/token/program-2022/tests/action.rs +++ /dev/null @@ -1,141 +0,0 @@ -use { - solana_program_test::BanksClient, - solana_sdk::{ - hash::Hash, - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - system_instruction, - transaction::Transaction, - transport::TransportError, - }, - spl_token_2022::{ - id, instruction, - state::{Account, Mint}, - }, -}; - -pub async fn create_mint( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: Hash, - pool_mint: &Keypair, - manager: &Pubkey, - decimals: u8, -) -> Result<(), TransportError> { - let rent = banks_client.get_rent().await.unwrap(); - let mint_rent = rent.minimum_balance(Mint::LEN); - - let transaction = Transaction::new_signed_with_payer( - &[ - system_instruction::create_account( - &payer.pubkey(), - &pool_mint.pubkey(), - mint_rent, - Mint::LEN as u64, - &id(), - ), - instruction::initialize_mint(&id(), &pool_mint.pubkey(), manager, None, decimals) - .unwrap(), - ], - Some(&payer.pubkey()), - &[payer, pool_mint], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await?; - Ok(()) -} - -pub async fn create_account( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: Hash, - account: &Keypair, - pool_mint: &Pubkey, - owner: &Pubkey, -) -> Result<(), TransportError> { - let rent = banks_client.get_rent().await.unwrap(); - let account_rent = rent.minimum_balance(Account::LEN); - - let transaction = Transaction::new_signed_with_payer( - &[ - system_instruction::create_account( - &payer.pubkey(), - &account.pubkey(), - account_rent, - Account::LEN as u64, - &id(), - ), - instruction::initialize_account(&id(), &account.pubkey(), pool_mint, owner).unwrap(), - ], - Some(&payer.pubkey()), - &[payer, account], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await?; - Ok(()) -} - -pub async fn mint_to( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: Hash, - mint: &Pubkey, - account: &Pubkey, - mint_authority: &Keypair, - amount: u64, -) -> Result<(), TransportError> { - let transaction = Transaction::new_signed_with_payer( - &[ - instruction::mint_to(&id(), mint, account, &mint_authority.pubkey(), &[], amount) - .unwrap(), - ], - Some(&payer.pubkey()), - &[payer, mint_authority], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await?; - Ok(()) -} - -#[allow(deprecated)] -pub async fn transfer( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: Hash, - source: &Pubkey, - destination: &Pubkey, - authority: &Keypair, - amount: u64, -) -> Result<(), TransportError> { - let transaction = Transaction::new_signed_with_payer( - &[ - instruction::transfer(&id(), source, destination, &authority.pubkey(), &[], amount) - .unwrap(), - ], - Some(&payer.pubkey()), - &[payer, authority], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await?; - Ok(()) -} - -pub async fn burn( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: Hash, - mint: &Pubkey, - account: &Pubkey, - authority: &Keypair, - amount: u64, -) -> Result<(), TransportError> { - let transaction = Transaction::new_signed_with_payer( - &[instruction::burn(&id(), account, mint, &authority.pubkey(), &[], amount).unwrap()], - Some(&payer.pubkey()), - &[payer, authority], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await?; - Ok(()) -} diff --git a/token/program-2022/tests/assert_instruction_count.rs b/token/program-2022/tests/assert_instruction_count.rs deleted file mode 100644 index edfdfa7813e..00000000000 --- a/token/program-2022/tests/assert_instruction_count.rs +++ /dev/null @@ -1,332 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod action; -use { - solana_program_test::{processor, tokio, ProgramTest}, - solana_sdk::{ - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - system_instruction, - transaction::Transaction, - }, - spl_token_2022::{ - id, instruction, - processor::Processor, - state::{Account, Mint}, - }, -}; - -const TRANSFER_AMOUNT: u64 = 1_000_000_000_000_000; - -#[tokio::test] -async fn initialize_mint() { - let mut pt = ProgramTest::new("spl_token_2022", id(), processor!(Processor::process)); - pt.set_compute_max_units(5_000); // last known 2252 - let (mut banks_client, payer, recent_blockhash) = pt.start().await; - - let owner_key = Pubkey::new_unique(); - let mint = Keypair::new(); - let decimals = 9; - - let rent = banks_client.get_rent().await.unwrap(); - let mint_rent = rent.minimum_balance(Mint::LEN); - let transaction = Transaction::new_signed_with_payer( - &[system_instruction::create_account( - &payer.pubkey(), - &mint.pubkey(), - mint_rent, - Mint::LEN as u64, - &id(), - )], - Some(&payer.pubkey()), - &[&payer, &mint], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); - - let transaction = Transaction::new_signed_with_payer( - &[ - instruction::initialize_mint(&id(), &mint.pubkey(), &owner_key, None, decimals) - .unwrap(), - ], - Some(&payer.pubkey()), - &[&payer], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); -} - -#[tokio::test] -async fn initialize_account() { - let mut pt = ProgramTest::new("spl_token_2022", id(), processor!(Processor::process)); - pt.set_compute_max_units(8_000); // last known 7064 - let (mut banks_client, payer, recent_blockhash) = pt.start().await; - - let owner = Keypair::new(); - let mint = Keypair::new(); - let account = Keypair::new(); - let decimals = 9; - - action::create_mint( - &mut banks_client, - &payer, - recent_blockhash, - &mint, - &owner.pubkey(), - decimals, - ) - .await - .unwrap(); - let rent = banks_client.get_rent().await.unwrap(); - let account_rent = rent.minimum_balance(Account::LEN); - let transaction = Transaction::new_signed_with_payer( - &[system_instruction::create_account( - &payer.pubkey(), - &account.pubkey(), - account_rent, - Account::LEN as u64, - &id(), - )], - Some(&payer.pubkey()), - &[&payer, &account], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); - - let transaction = Transaction::new_signed_with_payer( - &[instruction::initialize_account( - &id(), - &account.pubkey(), - &mint.pubkey(), - &owner.pubkey(), - ) - .unwrap()], - Some(&payer.pubkey()), - &[&payer], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); -} - -#[tokio::test] -async fn mint_to() { - let mut pt = ProgramTest::new("spl_token_2022", id(), processor!(Processor::process)); - pt.set_compute_max_units(8_000); // last known 7033 - let (mut banks_client, payer, recent_blockhash) = pt.start().await; - - let owner = Keypair::new(); - let mint = Keypair::new(); - let account = Keypair::new(); - let decimals = 9; - - action::create_mint( - &mut banks_client, - &payer, - recent_blockhash, - &mint, - &owner.pubkey(), - decimals, - ) - .await - .unwrap(); - action::create_account( - &mut banks_client, - &payer, - recent_blockhash, - &account, - &mint.pubkey(), - &owner.pubkey(), - ) - .await - .unwrap(); - - let transaction = Transaction::new_signed_with_payer( - &[instruction::mint_to( - &id(), - &mint.pubkey(), - &account.pubkey(), - &owner.pubkey(), - &[], - TRANSFER_AMOUNT, - ) - .unwrap()], - Some(&payer.pubkey()), - &[&payer, &owner], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); -} - -#[tokio::test] -async fn transfer() { - let mut pt = ProgramTest::new("spl_token_2022", id(), processor!(Processor::process)); - pt.set_compute_max_units(8_000); // last known 7033 - let (mut banks_client, payer, recent_blockhash) = pt.start().await; - - let owner = Keypair::new(); - let mint = Keypair::new(); - let source = Keypair::new(); - let destination = Keypair::new(); - let decimals = 9; - - action::create_mint( - &mut banks_client, - &payer, - recent_blockhash, - &mint, - &owner.pubkey(), - decimals, - ) - .await - .unwrap(); - action::create_account( - &mut banks_client, - &payer, - recent_blockhash, - &source, - &mint.pubkey(), - &owner.pubkey(), - ) - .await - .unwrap(); - action::create_account( - &mut banks_client, - &payer, - recent_blockhash, - &destination, - &mint.pubkey(), - &owner.pubkey(), - ) - .await - .unwrap(); - - action::mint_to( - &mut banks_client, - &payer, - recent_blockhash, - &mint.pubkey(), - &source.pubkey(), - &owner, - TRANSFER_AMOUNT, - ) - .await - .unwrap(); - - action::transfer( - &mut banks_client, - &payer, - recent_blockhash, - &source.pubkey(), - &destination.pubkey(), - &owner, - TRANSFER_AMOUNT, - ) - .await - .unwrap(); -} - -#[tokio::test] -async fn burn() { - let mut pt = ProgramTest::new("spl_token_2022", id(), processor!(Processor::process)); - pt.set_compute_max_units(8_000); // last known 7042 - let (mut banks_client, payer, recent_blockhash) = pt.start().await; - - let owner = Keypair::new(); - let mint = Keypair::new(); - let account = Keypair::new(); - let decimals = 9; - - action::create_mint( - &mut banks_client, - &payer, - recent_blockhash, - &mint, - &owner.pubkey(), - decimals, - ) - .await - .unwrap(); - action::create_account( - &mut banks_client, - &payer, - recent_blockhash, - &account, - &mint.pubkey(), - &owner.pubkey(), - ) - .await - .unwrap(); - - action::mint_to( - &mut banks_client, - &payer, - recent_blockhash, - &mint.pubkey(), - &account.pubkey(), - &owner, - TRANSFER_AMOUNT, - ) - .await - .unwrap(); - - action::burn( - &mut banks_client, - &payer, - recent_blockhash, - &mint.pubkey(), - &account.pubkey(), - &owner, - TRANSFER_AMOUNT, - ) - .await - .unwrap(); -} - -#[tokio::test] -async fn close_account() { - let mut pt = ProgramTest::new("spl_token_2022", id(), processor!(Processor::process)); - pt.set_compute_max_units(8_000); // last known 1783 - let (mut banks_client, payer, recent_blockhash) = pt.start().await; - - let owner = Keypair::new(); - let mint = Keypair::new(); - let account = Keypair::new(); - let decimals = 9; - - action::create_mint( - &mut banks_client, - &payer, - recent_blockhash, - &mint, - &owner.pubkey(), - decimals, - ) - .await - .unwrap(); - action::create_account( - &mut banks_client, - &payer, - recent_blockhash, - &account, - &mint.pubkey(), - &owner.pubkey(), - ) - .await - .unwrap(); - - let transaction = Transaction::new_signed_with_payer( - &[instruction::close_account( - &id(), - &account.pubkey(), - &owner.pubkey(), - &owner.pubkey(), - &[], - ) - .unwrap()], - Some(&payer.pubkey()), - &[&payer, &owner], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); -} diff --git a/token/program-2022/tests/serialization.rs b/token/program-2022/tests/serialization.rs deleted file mode 100644 index 46051e9ac5c..00000000000 --- a/token/program-2022/tests/serialization.rs +++ /dev/null @@ -1,37 +0,0 @@ -#![cfg(feature = "serde-traits")] - -use { - solana_program::program_option::COption, solana_sdk::pubkey::Pubkey, - spl_token_2022::instruction, std::str::FromStr, -}; - -#[test] -fn token_program_serde() { - let inst = instruction::TokenInstruction::InitializeMint2 { - decimals: 0, - mint_authority: Pubkey::from_str("4uQeVj5tqViQh7yWWGStvkEG1Zmhx6uasJtWCJziofM").unwrap(), - freeze_authority: COption::Some( - Pubkey::from_str("8opHzTAnfzRpPEx21XtnrVTX28YQuCpAjcn1PczScKh").unwrap(), - ), - }; - - let serialized = serde_json::to_string(&inst).unwrap(); - assert_eq!(&serialized, "{\"InitializeMint2\":{\"decimals\":0,\"mint_authority\":\"4uQeVj5tqViQh7yWWGStvkEG1Zmhx6uasJtWCJziofM\",\"freeze_authority\":\"8opHzTAnfzRpPEx21XtnrVTX28YQuCpAjcn1PczScKh\"}}"); - - serde_json::from_str::(&serialized).unwrap(); -} - -#[test] -fn token_program_serde_with_none() { - let inst = instruction::TokenInstruction::InitializeMintCloseAuthority { - close_authority: COption::None, - }; - - let serialized = serde_json::to_string(&inst).unwrap(); - assert_eq!( - &serialized, - "{\"InitializeMintCloseAuthority\":{\"close_authority\":null}}" - ); - - serde_json::from_str::(&serialized).unwrap(); -} diff --git a/token/program/Cargo.toml b/token/program/Cargo.toml deleted file mode 100644 index 481319e4bb6..00000000000 --- a/token/program/Cargo.toml +++ /dev/null @@ -1,35 +0,0 @@ -[package] -name = "spl-token" -version = "3.3.1" -description = "Solana Program Library Token" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana-program-library" -license = "Apache-2.0" -edition = "2018" -exclude = ["js/**"] - -[features] -no-entrypoint = [] -test-bpf = [] - -[dependencies] -arrayref = "0.3.6" -bytemuck = "1.7.2" -num-derive = "0.3" -num-traits = "0.2" -num_enum = "0.5.4" -solana-program = "1.10.33" -thiserror = "1.0" - -[dev-dependencies] -lazy_static = "1.4.0" -proptest = "1.0" -serial_test = "0.5.1" -solana-program-test = "1.10.33" -solana-sdk = "1.10.33" - -[lib] -crate-type = ["cdylib", "lib"] - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] diff --git a/token/program/Xargo.toml b/token/program/Xargo.toml deleted file mode 100644 index 1744f098ae1..00000000000 --- a/token/program/Xargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.bpfel-unknown-unknown.dependencies.std] -features = [] \ No newline at end of file diff --git a/token/program/inc/token.h b/token/program/inc/token.h deleted file mode 100644 index 145c0c5e07b..00000000000 --- a/token/program/inc/token.h +++ /dev/null @@ -1,687 +0,0 @@ -/* Autogenerated SPL Token program C Bindings */ - -#pragma once - -#include -#include -#include -#include - -/** - * Minimum number of multisignature signers (min N) - */ -#define Token_MIN_SIGNERS 1 - -/** - * Maximum number of multisignature signers (max N) - */ -#define Token_MAX_SIGNERS 11 - -/** - * Account state. - */ -enum Token_AccountState -#ifdef __cplusplus - : uint8_t -#endif // __cplusplus - { - /** - * Account is not yet initialized - */ - Token_AccountState_Uninitialized, - /** - * Account is initialized; the account owner and/or delegate may perform permitted operations - * on this account - */ - Token_AccountState_Initialized, - /** - * Account has been frozen by the mint freeze authority. Neither the account owner nor - * the delegate are able to perform operations on this account. - */ - Token_AccountState_Frozen, -}; -#ifndef __cplusplus -typedef uint8_t Token_AccountState; -#endif // __cplusplus - -/** - * Specifies the authority type for SetAuthority instructions - */ -enum Token_AuthorityType -#ifdef __cplusplus - : uint8_t -#endif // __cplusplus - { - /** - * Authority to mint new tokens - */ - Token_AuthorityType_MintTokens, - /** - * Authority to freeze any account associated with the Mint - */ - Token_AuthorityType_FreezeAccount, - /** - * Owner of a given token account - */ - Token_AuthorityType_AccountOwner, - /** - * Authority to close a token account - */ - Token_AuthorityType_CloseAccount, -}; -#ifndef __cplusplus -typedef uint8_t Token_AuthorityType; -#endif // __cplusplus - -typedef uint8_t Token_Pubkey[32]; - -/** - * A C representation of Rust's `std::option::Option` - */ -typedef enum Token_COption_Pubkey_Tag { - /** - * No value - */ - Token_COption_Pubkey_None_Pubkey, - /** - * Some value `T` - */ - Token_COption_Pubkey_Some_Pubkey, -} Token_COption_Pubkey_Tag; - -typedef struct Token_COption_Pubkey { - Token_COption_Pubkey_Tag tag; - union { - struct { - Token_Pubkey some; - }; - }; -} Token_COption_Pubkey; - -/** - * Instructions supported by the token program. - */ -typedef enum Token_TokenInstruction_Tag { - /** - * Initializes a new mint and optionally deposits all the newly minted - * tokens in an account. - * - * The `InitializeMint` instruction requires no signers and MUST be - * included within the same Transaction as the system program's - * `CreateAccount` instruction that creates the account being initialized. - * Otherwise another party can acquire ownership of the uninitialized - * account. - * - * Accounts expected by this instruction: - * - * 0. `[writable]` The mint to initialize. - * 1. `[]` Rent sysvar - * - */ - Token_TokenInstruction_InitializeMint, - /** - * Initializes a new account to hold tokens. If this account is associated - * with the native mint then the token balance of the initialized account - * will be equal to the amount of SOL in the account. If this account is - * associated with another mint, that mint must be initialized before this - * command can succeed. - * - * The `InitializeAccount` instruction requires no signers and MUST be - * included within the same Transaction as the system program's - * `CreateAccount` instruction that creates the account being initialized. - * Otherwise another party can acquire ownership of the uninitialized - * account. - * - * Accounts expected by this instruction: - * - * 0. `[writable]` The account to initialize. - * 1. `[]` The mint this account will be associated with. - * 2. `[]` The new account's owner/multisignature. - * 3. `[]` Rent sysvar - */ - Token_TokenInstruction_InitializeAccount, - /** - * Initializes a multisignature account with N provided signers. - * - * Multisignature accounts can used in place of any single owner/delegate - * accounts in any token instruction that require an owner/delegate to be - * present. The variant field represents the number of signers (M) - * required to validate this multisignature account. - * - * The `InitializeMultisig` instruction requires no signers and MUST be - * included within the same Transaction as the system program's - * `CreateAccount` instruction that creates the account being initialized. - * Otherwise another party can acquire ownership of the uninitialized - * account. - * - * Accounts expected by this instruction: - * - * 0. `[writable]` The multisignature account to initialize. - * 1. `[]` Rent sysvar - * 2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <= - * 11. - */ - Token_TokenInstruction_InitializeMultisig, - /** - * Transfers tokens from one account to another either directly or via a - * delegate. If this account is associated with the native mint then equal - * amounts of SOL and Tokens will be transferred to the destination - * account. - * - * Accounts expected by this instruction: - * - * * Single owner/delegate - * 0. `[writable]` The source account. - * 1. `[writable]` The destination account. - * 2. `[signer]` The source account's owner/delegate. - * - * * Multisignature owner/delegate - * 0. `[writable]` The source account. - * 1. `[writable]` The destination account. - * 2. `[]` The source account's multisignature owner/delegate. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_Transfer, - /** - * Approves a delegate. A delegate is given the authority over tokens on - * behalf of the source account's owner. - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The source account. - * 1. `[]` The delegate. - * 2. `[signer]` The source account owner. - * - * * Multisignature owner - * 0. `[writable]` The source account. - * 1. `[]` The delegate. - * 2. `[]` The source account's multisignature owner. - * 3. ..3+M `[signer]` M signer accounts - */ - Token_TokenInstruction_Approve, - /** - * Revokes the delegate's authority. - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The source account. - * 1. `[signer]` The source account owner. - * - * * Multisignature owner - * 0. `[writable]` The source account. - * 1. `[]` The source account's multisignature owner. - * 2. ..2+M `[signer]` M signer accounts - */ - Token_TokenInstruction_Revoke, - /** - * Sets a new authority of a mint or account. - * - * Accounts expected by this instruction: - * - * * Single authority - * 0. `[writable]` The mint or account to change the authority of. - * 1. `[signer]` The current authority of the mint or account. - * - * * Multisignature authority - * 0. `[writable]` The mint or account to change the authority of. - * 1. `[]` The mint's or account's current multisignature authority. - * 2. ..2+M `[signer]` M signer accounts - */ - Token_TokenInstruction_SetAuthority, - /** - * Mints new tokens to an account. The native mint does not support - * minting. - * - * Accounts expected by this instruction: - * - * * Single authority - * 0. `[writable]` The mint. - * 1. `[writable]` The account to mint tokens to. - * 2. `[signer]` The mint's minting authority. - * - * * Multisignature authority - * 0. `[writable]` The mint. - * 1. `[writable]` The account to mint tokens to. - * 2. `[]` The mint's multisignature mint-tokens authority. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_MintTo, - /** - * Burns tokens by removing them from an account. `Burn` does not support - * accounts associated with the native mint, use `CloseAccount` instead. - * - * Accounts expected by this instruction: - * - * * Single owner/delegate - * 0. `[writable]` The account to burn from. - * 1. `[writable]` The token mint. - * 2. `[signer]` The account's owner/delegate. - * - * * Multisignature owner/delegate - * 0. `[writable]` The account to burn from. - * 1. `[writable]` The token mint. - * 2. `[]` The account's multisignature owner/delegate. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_Burn, - /** - * Close an account by transferring all its SOL to the destination account. - * Non-native accounts may only be closed if its token amount is zero. - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The account to close. - * 1. `[writable]` The destination account. - * 2. `[signer]` The account's owner. - * - * * Multisignature owner - * 0. `[writable]` The account to close. - * 1. `[writable]` The destination account. - * 2. `[]` The account's multisignature owner. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_CloseAccount, - /** - * Freeze an Initialized account using the Mint's freeze_authority (if - * set). - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The account to freeze. - * 1. `[]` The token mint. - * 2. `[signer]` The mint freeze authority. - * - * * Multisignature owner - * 0. `[writable]` The account to freeze. - * 1. `[]` The token mint. - * 2. `[]` The mint's multisignature freeze authority. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_FreezeAccount, - /** - * Thaw a Frozen account using the Mint's freeze_authority (if set). - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The account to freeze. - * 1. `[]` The token mint. - * 2. `[signer]` The mint freeze authority. - * - * * Multisignature owner - * 0. `[writable]` The account to freeze. - * 1. `[]` The token mint. - * 2. `[]` The mint's multisignature freeze authority. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_ThawAccount, - /** - * Transfers tokens from one account to another either directly or via a - * delegate. If this account is associated with the native mint then equal - * amounts of SOL and Tokens will be transferred to the destination - * account. - * - * This instruction differs from Transfer in that the token mint and - * decimals value is checked by the caller. This may be useful when - * creating transactions offline or within a hardware wallet. - * - * Accounts expected by this instruction: - * - * * Single owner/delegate - * 0. `[writable]` The source account. - * 1. `[]` The token mint. - * 2. `[writable]` The destination account. - * 3. `[signer]` The source account's owner/delegate. - * - * * Multisignature owner/delegate - * 0. `[writable]` The source account. - * 1. `[]` The token mint. - * 2. `[writable]` The destination account. - * 3. `[]` The source account's multisignature owner/delegate. - * 4. ..4+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_TransferChecked, - /** - * Approves a delegate. A delegate is given the authority over tokens on - * behalf of the source account's owner. - * - * This instruction differs from Approve in that the token mint and - * decimals value is checked by the caller. This may be useful when - * creating transactions offline or within a hardware wallet. - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The source account. - * 1. `[]` The token mint. - * 2. `[]` The delegate. - * 3. `[signer]` The source account owner. - * - * * Multisignature owner - * 0. `[writable]` The source account. - * 1. `[]` The token mint. - * 2. `[]` The delegate. - * 3. `[]` The source account's multisignature owner. - * 4. ..4+M `[signer]` M signer accounts - */ - Token_TokenInstruction_ApproveChecked, - /** - * Mints new tokens to an account. The native mint does not support - * minting. - * - * This instruction differs from MintTo in that the decimals value is - * checked by the caller. This may be useful when creating transactions - * offline or within a hardware wallet. - * - * Accounts expected by this instruction: - * - * * Single authority - * 0. `[writable]` The mint. - * 1. `[writable]` The account to mint tokens to. - * 2. `[signer]` The mint's minting authority. - * - * * Multisignature authority - * 0. `[writable]` The mint. - * 1. `[writable]` The account to mint tokens to. - * 2. `[]` The mint's multisignature mint-tokens authority. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_MintToChecked, - /** - * Burns tokens by removing them from an account. `BurnChecked` does not - * support accounts associated with the native mint, use `CloseAccount` - * instead. - * - * This instruction differs from Burn in that the decimals value is checked - * by the caller. This may be useful when creating transactions offline or - * within a hardware wallet. - * - * Accounts expected by this instruction: - * - * * Single owner/delegate - * 0. `[writable]` The account to burn from. - * 1. `[writable]` The token mint. - * 2. `[signer]` The account's owner/delegate. - * - * * Multisignature owner/delegate - * 0. `[writable]` The account to burn from. - * 1. `[writable]` The token mint. - * 2. `[]` The account's multisignature owner/delegate. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_BurnChecked, - /** - * Like InitializeAccount, but the owner pubkey is passed via instruction data - * rather than the accounts list. This variant may be preferable when using - * Cross Program Invocation from an instruction that does not need the owner's - * `AccountInfo` otherwise. - * - * Accounts expected by this instruction: - * - * 0. `[writable]` The account to initialize. - * 1. `[]` The mint this account will be associated with. - * 3. `[]` Rent sysvar - */ - Token_TokenInstruction_InitializeAccount2, - /** - * Given a wrapped / native token account (a token account containing SOL) - * updates its amount field based on the account's underlying `lamports`. - * This is useful if a non-wrapped SOL account uses `system_instruction::transfer` - * to move lamports to a wrapped token account, and needs to have its token - * `amount` field updated. - * - * Accounts expected by this instruction: - * - * 0. `[writable]` The native token account to sync with its underlying lamports. - */ - Token_TokenInstruction_SyncNative, -} Token_TokenInstruction_Tag; - -typedef struct Token_TokenInstruction_Token_InitializeMint_Body { - /** - * Number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; - /** - * The authority/multisignature to mint tokens. - */ - Token_Pubkey mint_authority; - /** - * The freeze authority/multisignature of the mint. - */ - struct Token_COption_Pubkey freeze_authority; -} Token_TokenInstruction_Token_InitializeMint_Body; - -typedef struct Token_TokenInstruction_Token_InitializeMultisig_Body { - /** - * The number of signers (M) required to validate this multisignature - * account. - */ - uint8_t m; -} Token_TokenInstruction_Token_InitializeMultisig_Body; - -typedef struct Token_TokenInstruction_Token_Transfer_Body { - /** - * The amount of tokens to transfer. - */ - uint64_t amount; -} Token_TokenInstruction_Token_Transfer_Body; - -typedef struct Token_TokenInstruction_Token_Approve_Body { - /** - * The amount of tokens the delegate is approved for. - */ - uint64_t amount; -} Token_TokenInstruction_Token_Approve_Body; - -typedef struct Token_TokenInstruction_Token_SetAuthority_Body { - /** - * The type of authority to update. - */ - Token_AuthorityType authority_type; - /** - * The new authority - */ - struct Token_COption_Pubkey new_authority; -} Token_TokenInstruction_Token_SetAuthority_Body; - -typedef struct Token_TokenInstruction_Token_MintTo_Body { - /** - * The amount of new tokens to mint. - */ - uint64_t amount; -} Token_TokenInstruction_Token_MintTo_Body; - -typedef struct Token_TokenInstruction_Token_Burn_Body { - /** - * The amount of tokens to burn. - */ - uint64_t amount; -} Token_TokenInstruction_Token_Burn_Body; - -typedef struct Token_TokenInstruction_Token_TransferChecked_Body { - /** - * The amount of tokens to transfer. - */ - uint64_t amount; - /** - * Expected number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; -} Token_TokenInstruction_Token_TransferChecked_Body; - -typedef struct Token_TokenInstruction_Token_ApproveChecked_Body { - /** - * The amount of tokens the delegate is approved for. - */ - uint64_t amount; - /** - * Expected number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; -} Token_TokenInstruction_Token_ApproveChecked_Body; - -typedef struct Token_TokenInstruction_Token_MintToChecked_Body { - /** - * The amount of new tokens to mint. - */ - uint64_t amount; - /** - * Expected number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; -} Token_TokenInstruction_Token_MintToChecked_Body; - -typedef struct Token_TokenInstruction_Token_BurnChecked_Body { - /** - * The amount of tokens to burn. - */ - uint64_t amount; - /** - * Expected number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; -} Token_TokenInstruction_Token_BurnChecked_Body; - -typedef struct Token_TokenInstruction_Token_InitializeAccount2_Body { - /** - * The new account's owner/multisignature. - */ - Token_Pubkey owner; -} Token_TokenInstruction_Token_InitializeAccount2_Body; - -typedef struct Token_TokenInstruction { - Token_TokenInstruction_Tag tag; - union { - Token_TokenInstruction_Token_InitializeMint_Body initialize_mint; - Token_TokenInstruction_Token_InitializeMultisig_Body initialize_multisig; - Token_TokenInstruction_Token_Transfer_Body transfer; - Token_TokenInstruction_Token_Approve_Body approve; - Token_TokenInstruction_Token_SetAuthority_Body set_authority; - Token_TokenInstruction_Token_MintTo_Body mint_to; - Token_TokenInstruction_Token_Burn_Body burn; - Token_TokenInstruction_Token_TransferChecked_Body transfer_checked; - Token_TokenInstruction_Token_ApproveChecked_Body approve_checked; - Token_TokenInstruction_Token_MintToChecked_Body mint_to_checked; - Token_TokenInstruction_Token_BurnChecked_Body burn_checked; - Token_TokenInstruction_Token_InitializeAccount2_Body initialize_account2; - }; -} Token_TokenInstruction; - -/** - * Mint data. - */ -typedef struct Token_Mint { - /** - * Optional authority used to mint new tokens. The mint authority may only be provided during - * mint creation. If no mint authority is present then the mint has a fixed supply and no - * further tokens may be minted. - */ - struct Token_COption_Pubkey mint_authority; - /** - * Total supply of tokens. - */ - uint64_t supply; - /** - * Number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; - /** - * Is `true` if this structure has been initialized - */ - bool is_initialized; - /** - * Optional authority to freeze token accounts. - */ - struct Token_COption_Pubkey freeze_authority; -} Token_Mint; - -/** - * A C representation of Rust's `std::option::Option` - */ -typedef enum Token_COption_u64_Tag { - /** - * No value - */ - Token_COption_u64_None_u64, - /** - * Some value `T` - */ - Token_COption_u64_Some_u64, -} Token_COption_u64_Tag; - -typedef struct Token_COption_u64 { - Token_COption_u64_Tag tag; - union { - struct { - uint64_t some; - }; - }; -} Token_COption_u64; - -/** - * Account data. - */ -typedef struct Token_Account { - /** - * The mint associated with this account - */ - Token_Pubkey mint; - /** - * The owner of this account. - */ - Token_Pubkey owner; - /** - * The amount of tokens this account holds. - */ - uint64_t amount; - /** - * If `delegate` is `Some` then `delegated_amount` represents - * the amount authorized by the delegate - */ - struct Token_COption_Pubkey delegate; - /** - * The account's state - */ - Token_AccountState state; - /** - * If is_some, this is a native token, and the value logs the rent-exempt reserve. An Account - * is required to be rent-exempt, so the value is used by the Processor to ensure that wrapped - * SOL accounts do not drop below this threshold. - */ - struct Token_COption_u64 is_native; - /** - * The amount delegated - */ - uint64_t delegated_amount; - /** - * Optional authority to close the account. - */ - struct Token_COption_Pubkey close_authority; -} Token_Account; - -/** - * Multisignature data. - */ -typedef struct Token_Multisig { - /** - * Number of signers required - */ - uint8_t m; - /** - * Number of valid signers - */ - uint8_t n; - /** - * Is `true` if this structure has been initialized - */ - bool is_initialized; - /** - * Signer public keys - */ - Token_Pubkey signers[Token_MAX_SIGNERS]; -} Token_Multisig; diff --git a/token/program/program-id.md b/token/program/program-id.md deleted file mode 100644 index f397edf07a1..00000000000 --- a/token/program/program-id.md +++ /dev/null @@ -1 +0,0 @@ -TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA diff --git a/token/program/src/entrypoint.rs b/token/program/src/entrypoint.rs deleted file mode 100644 index 53315751b9a..00000000000 --- a/token/program/src/entrypoint.rs +++ /dev/null @@ -1,21 +0,0 @@ -//! Program entrypoint - -use crate::{error::TokenError, processor::Processor}; -use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, - program_error::PrintProgramError, pubkey::Pubkey, -}; - -entrypoint!(process_instruction); -fn process_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - instruction_data: &[u8], -) -> ProgramResult { - if let Err(error) = Processor::process(program_id, accounts, instruction_data) { - // catch the error so we can print it - error.print::(); - return Err(error); - } - Ok(()) -} diff --git a/token/program/src/error.rs b/token/program/src/error.rs deleted file mode 100644 index 454aa9e042d..00000000000 --- a/token/program/src/error.rs +++ /dev/null @@ -1,139 +0,0 @@ -//! Error types - -use num_derive::FromPrimitive; -use solana_program::{ - decode_error::DecodeError, - msg, - program_error::{PrintProgramError, ProgramError}, -}; -use thiserror::Error; - -/// Errors that may be returned by the Token program. -#[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] -pub enum TokenError { - // 0 - /// Lamport balance below rent-exempt threshold. - #[error("Lamport balance below rent-exempt threshold")] - NotRentExempt, - /// Insufficient funds for the operation requested. - #[error("Insufficient funds")] - InsufficientFunds, - /// Invalid Mint. - #[error("Invalid Mint")] - InvalidMint, - /// Account not associated with this Mint. - #[error("Account not associated with this Mint")] - MintMismatch, - /// Owner does not match. - #[error("Owner does not match")] - OwnerMismatch, - - // 5 - /// This token's supply is fixed and new tokens cannot be minted. - #[error("Fixed supply")] - FixedSupply, - /// The account cannot be initialized because it is already being used. - #[error("Already in use")] - AlreadyInUse, - /// Invalid number of provided signers. - #[error("Invalid number of provided signers")] - InvalidNumberOfProvidedSigners, - /// Invalid number of required signers. - #[error("Invalid number of required signers")] - InvalidNumberOfRequiredSigners, - /// State is uninitialized. - #[error("State is unititialized")] - UninitializedState, - - // 10 - /// Instruction does not support native tokens - #[error("Instruction does not support native tokens")] - NativeNotSupported, - /// Non-native account can only be closed if its balance is zero - #[error("Non-native account can only be closed if its balance is zero")] - NonNativeHasBalance, - /// Invalid instruction - #[error("Invalid instruction")] - InvalidInstruction, - /// State is invalid for requested operation. - #[error("State is invalid for requested operation")] - InvalidState, - /// Operation overflowed - #[error("Operation overflowed")] - Overflow, - - // 15 - /// Account does not support specified authority type. - #[error("Account does not support specified authority type")] - AuthorityTypeNotSupported, - /// This token mint cannot freeze accounts. - #[error("This token mint cannot freeze accounts")] - MintCannotFreeze, - /// Account is frozen; all account operations will fail - #[error("Account is frozen")] - AccountFrozen, - /// Mint decimals mismatch between the client and mint - #[error("The provided decimals value different from the Mint decimals")] - MintDecimalsMismatch, - /// Instruction does not support non-native tokens - #[error("Instruction does not support non-native tokens")] - NonNativeNotSupported, -} -impl From for ProgramError { - fn from(e: TokenError) -> Self { - ProgramError::Custom(e as u32) - } -} -impl DecodeError for TokenError { - fn type_of() -> &'static str { - "TokenError" - } -} - -impl PrintProgramError for TokenError { - fn print(&self) - where - E: 'static - + std::error::Error - + DecodeError - + PrintProgramError - + num_traits::FromPrimitive, - { - match self { - TokenError::NotRentExempt => msg!("Error: Lamport balance below rent-exempt threshold"), - TokenError::InsufficientFunds => msg!("Error: insufficient funds"), - TokenError::InvalidMint => msg!("Error: Invalid Mint"), - TokenError::MintMismatch => msg!("Error: Account not associated with this Mint"), - TokenError::OwnerMismatch => msg!("Error: owner does not match"), - TokenError::FixedSupply => msg!("Error: the total supply of this token is fixed"), - TokenError::AlreadyInUse => msg!("Error: account or token already in use"), - TokenError::InvalidNumberOfProvidedSigners => { - msg!("Error: Invalid number of provided signers") - } - TokenError::InvalidNumberOfRequiredSigners => { - msg!("Error: Invalid number of required signers") - } - TokenError::UninitializedState => msg!("Error: State is uninitialized"), - TokenError::NativeNotSupported => { - msg!("Error: Instruction does not support native tokens") - } - TokenError::NonNativeHasBalance => { - msg!("Error: Non-native account can only be closed if its balance is zero") - } - TokenError::InvalidInstruction => msg!("Error: Invalid instruction"), - TokenError::InvalidState => msg!("Error: Invalid account state for operation"), - TokenError::Overflow => msg!("Error: Operation overflowed"), - TokenError::AuthorityTypeNotSupported => { - msg!("Error: Account does not support specified authority type") - } - TokenError::MintCannotFreeze => msg!("Error: This token mint cannot freeze accounts"), - TokenError::AccountFrozen => msg!("Error: Account is frozen"), - TokenError::MintDecimalsMismatch => { - msg!("Error: decimals different from the Mint decimals") - } - TokenError::NonNativeNotSupported => { - msg!("Error: Instruction does not support non-native tokens") - } - } - } -} diff --git a/token/program/src/instruction.rs b/token/program/src/instruction.rs deleted file mode 100644 index c69c7bbe2eb..00000000000 --- a/token/program/src/instruction.rs +++ /dev/null @@ -1,1692 +0,0 @@ -//! Instruction types - -use crate::{check_program_account, error::TokenError}; -use solana_program::{ - instruction::{AccountMeta, Instruction}, - program_error::ProgramError, - program_option::COption, - pubkey::Pubkey, - sysvar, -}; -use std::convert::TryInto; -use std::mem::size_of; - -/// Minimum number of multisignature signers (min N) -pub const MIN_SIGNERS: usize = 1; -/// Maximum number of multisignature signers (max N) -pub const MAX_SIGNERS: usize = 11; - -/// Instructions supported by the token program. -#[repr(C)] -#[derive(Clone, Debug, PartialEq)] -pub enum TokenInstruction<'a> { - /// Initializes a new mint and optionally deposits all the newly minted - /// tokens in an account. - /// - /// The `InitializeMint` instruction requires no signers and MUST be - /// included within the same Transaction as the system program's - /// `CreateAccount` instruction that creates the account being initialized. - /// Otherwise another party can acquire ownership of the uninitialized - /// account. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The mint to initialize. - /// 1. `[]` Rent sysvar - /// - InitializeMint { - /// Number of base 10 digits to the right of the decimal place. - decimals: u8, - /// The authority/multisignature to mint tokens. - mint_authority: Pubkey, - /// The freeze authority/multisignature of the mint. - freeze_authority: COption, - }, - /// Initializes a new account to hold tokens. If this account is associated - /// with the native mint then the token balance of the initialized account - /// will be equal to the amount of SOL in the account. If this account is - /// associated with another mint, that mint must be initialized before this - /// command can succeed. - /// - /// The `InitializeAccount` instruction requires no signers and MUST be - /// included within the same Transaction as the system program's - /// `CreateAccount` instruction that creates the account being initialized. - /// Otherwise another party can acquire ownership of the uninitialized - /// account. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The account to initialize. - /// 1. `[]` The mint this account will be associated with. - /// 2. `[]` The new account's owner/multisignature. - /// 3. `[]` Rent sysvar - InitializeAccount, - /// Initializes a multisignature account with N provided signers. - /// - /// Multisignature accounts can used in place of any single owner/delegate - /// accounts in any token instruction that require an owner/delegate to be - /// present. The variant field represents the number of signers (M) - /// required to validate this multisignature account. - /// - /// The `InitializeMultisig` instruction requires no signers and MUST be - /// included within the same Transaction as the system program's - /// `CreateAccount` instruction that creates the account being initialized. - /// Otherwise another party can acquire ownership of the uninitialized - /// account. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The multisignature account to initialize. - /// 1. `[]` Rent sysvar - /// 2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <= - /// 11. - InitializeMultisig { - /// The number of signers (M) required to validate this multisignature - /// account. - m: u8, - }, - /// Transfers tokens from one account to another either directly or via a - /// delegate. If this account is associated with the native mint then equal - /// amounts of SOL and Tokens will be transferred to the destination - /// account. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner/delegate - /// 0. `[writable]` The source account. - /// 1. `[writable]` The destination account. - /// 2. `[signer]` The source account's owner/delegate. - /// - /// * Multisignature owner/delegate - /// 0. `[writable]` The source account. - /// 1. `[writable]` The destination account. - /// 2. `[]` The source account's multisignature owner/delegate. - /// 3. ..3+M `[signer]` M signer accounts. - Transfer { - /// The amount of tokens to transfer. - amount: u64, - }, - /// Approves a delegate. A delegate is given the authority over tokens on - /// behalf of the source account's owner. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner - /// 0. `[writable]` The source account. - /// 1. `[]` The delegate. - /// 2. `[signer]` The source account owner. - /// - /// * Multisignature owner - /// 0. `[writable]` The source account. - /// 1. `[]` The delegate. - /// 2. `[]` The source account's multisignature owner. - /// 3. ..3+M `[signer]` M signer accounts - Approve { - /// The amount of tokens the delegate is approved for. - amount: u64, - }, - /// Revokes the delegate's authority. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner - /// 0. `[writable]` The source account. - /// 1. `[signer]` The source account owner. - /// - /// * Multisignature owner - /// 0. `[writable]` The source account. - /// 1. `[]` The source account's multisignature owner. - /// 2. ..2+M `[signer]` M signer accounts - Revoke, - /// Sets a new authority of a mint or account. - /// - /// Accounts expected by this instruction: - /// - /// * Single authority - /// 0. `[writable]` The mint or account to change the authority of. - /// 1. `[signer]` The current authority of the mint or account. - /// - /// * Multisignature authority - /// 0. `[writable]` The mint or account to change the authority of. - /// 1. `[]` The mint's or account's current multisignature authority. - /// 2. ..2+M `[signer]` M signer accounts - SetAuthority { - /// The type of authority to update. - authority_type: AuthorityType, - /// The new authority - new_authority: COption, - }, - /// Mints new tokens to an account. The native mint does not support - /// minting. - /// - /// Accounts expected by this instruction: - /// - /// * Single authority - /// 0. `[writable]` The mint. - /// 1. `[writable]` The account to mint tokens to. - /// 2. `[signer]` The mint's minting authority. - /// - /// * Multisignature authority - /// 0. `[writable]` The mint. - /// 1. `[writable]` The account to mint tokens to. - /// 2. `[]` The mint's multisignature mint-tokens authority. - /// 3. ..3+M `[signer]` M signer accounts. - MintTo { - /// The amount of new tokens to mint. - amount: u64, - }, - /// Burns tokens by removing them from an account. `Burn` does not support - /// accounts associated with the native mint, use `CloseAccount` instead. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner/delegate - /// 0. `[writable]` The account to burn from. - /// 1. `[writable]` The token mint. - /// 2. `[signer]` The account's owner/delegate. - /// - /// * Multisignature owner/delegate - /// 0. `[writable]` The account to burn from. - /// 1. `[writable]` The token mint. - /// 2. `[]` The account's multisignature owner/delegate. - /// 3. ..3+M `[signer]` M signer accounts. - Burn { - /// The amount of tokens to burn. - amount: u64, - }, - /// Close an account by transferring all its SOL to the destination account. - /// Non-native accounts may only be closed if its token amount is zero. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner - /// 0. `[writable]` The account to close. - /// 1. `[writable]` The destination account. - /// 2. `[signer]` The account's owner. - /// - /// * Multisignature owner - /// 0. `[writable]` The account to close. - /// 1. `[writable]` The destination account. - /// 2. `[]` The account's multisignature owner. - /// 3. ..3+M `[signer]` M signer accounts. - CloseAccount, - /// Freeze an Initialized account using the Mint's freeze_authority (if - /// set). - /// - /// Accounts expected by this instruction: - /// - /// * Single owner - /// 0. `[writable]` The account to freeze. - /// 1. `[]` The token mint. - /// 2. `[signer]` The mint freeze authority. - /// - /// * Multisignature owner - /// 0. `[writable]` The account to freeze. - /// 1. `[]` The token mint. - /// 2. `[]` The mint's multisignature freeze authority. - /// 3. ..3+M `[signer]` M signer accounts. - FreezeAccount, - /// Thaw a Frozen account using the Mint's freeze_authority (if set). - /// - /// Accounts expected by this instruction: - /// - /// * Single owner - /// 0. `[writable]` The account to freeze. - /// 1. `[]` The token mint. - /// 2. `[signer]` The mint freeze authority. - /// - /// * Multisignature owner - /// 0. `[writable]` The account to freeze. - /// 1. `[]` The token mint. - /// 2. `[]` The mint's multisignature freeze authority. - /// 3. ..3+M `[signer]` M signer accounts. - ThawAccount, - - /// Transfers tokens from one account to another either directly or via a - /// delegate. If this account is associated with the native mint then equal - /// amounts of SOL and Tokens will be transferred to the destination - /// account. - /// - /// This instruction differs from Transfer in that the token mint and - /// decimals value is checked by the caller. This may be useful when - /// creating transactions offline or within a hardware wallet. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner/delegate - /// 0. `[writable]` The source account. - /// 1. `[]` The token mint. - /// 2. `[writable]` The destination account. - /// 3. `[signer]` The source account's owner/delegate. - /// - /// * Multisignature owner/delegate - /// 0. `[writable]` The source account. - /// 1. `[]` The token mint. - /// 2. `[writable]` The destination account. - /// 3. `[]` The source account's multisignature owner/delegate. - /// 4. ..4+M `[signer]` M signer accounts. - TransferChecked { - /// The amount of tokens to transfer. - amount: u64, - /// Expected number of base 10 digits to the right of the decimal place. - decimals: u8, - }, - /// Approves a delegate. A delegate is given the authority over tokens on - /// behalf of the source account's owner. - /// - /// This instruction differs from Approve in that the token mint and - /// decimals value is checked by the caller. This may be useful when - /// creating transactions offline or within a hardware wallet. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner - /// 0. `[writable]` The source account. - /// 1. `[]` The token mint. - /// 2. `[]` The delegate. - /// 3. `[signer]` The source account owner. - /// - /// * Multisignature owner - /// 0. `[writable]` The source account. - /// 1. `[]` The token mint. - /// 2. `[]` The delegate. - /// 3. `[]` The source account's multisignature owner. - /// 4. ..4+M `[signer]` M signer accounts - ApproveChecked { - /// The amount of tokens the delegate is approved for. - amount: u64, - /// Expected number of base 10 digits to the right of the decimal place. - decimals: u8, - }, - /// Mints new tokens to an account. The native mint does not support - /// minting. - /// - /// This instruction differs from MintTo in that the decimals value is - /// checked by the caller. This may be useful when creating transactions - /// offline or within a hardware wallet. - /// - /// Accounts expected by this instruction: - /// - /// * Single authority - /// 0. `[writable]` The mint. - /// 1. `[writable]` The account to mint tokens to. - /// 2. `[signer]` The mint's minting authority. - /// - /// * Multisignature authority - /// 0. `[writable]` The mint. - /// 1. `[writable]` The account to mint tokens to. - /// 2. `[]` The mint's multisignature mint-tokens authority. - /// 3. ..3+M `[signer]` M signer accounts. - MintToChecked { - /// The amount of new tokens to mint. - amount: u64, - /// Expected number of base 10 digits to the right of the decimal place. - decimals: u8, - }, - /// Burns tokens by removing them from an account. `BurnChecked` does not - /// support accounts associated with the native mint, use `CloseAccount` - /// instead. - /// - /// This instruction differs from Burn in that the decimals value is checked - /// by the caller. This may be useful when creating transactions offline or - /// within a hardware wallet. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner/delegate - /// 0. `[writable]` The account to burn from. - /// 1. `[writable]` The token mint. - /// 2. `[signer]` The account's owner/delegate. - /// - /// * Multisignature owner/delegate - /// 0. `[writable]` The account to burn from. - /// 1. `[writable]` The token mint. - /// 2. `[]` The account's multisignature owner/delegate. - /// 3. ..3+M `[signer]` M signer accounts. - BurnChecked { - /// The amount of tokens to burn. - amount: u64, - /// Expected number of base 10 digits to the right of the decimal place. - decimals: u8, - }, - /// Like InitializeAccount, but the owner pubkey is passed via instruction data - /// rather than the accounts list. This variant may be preferable when using - /// Cross Program Invocation from an instruction that does not need the owner's - /// `AccountInfo` otherwise. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The account to initialize. - /// 1. `[]` The mint this account will be associated with. - /// 3. `[]` Rent sysvar - InitializeAccount2 { - /// The new account's owner/multisignature. - owner: Pubkey, - }, - /// Given a wrapped / native token account (a token account containing SOL) - /// updates its amount field based on the account's underlying `lamports`. - /// This is useful if a non-wrapped SOL account uses `system_instruction::transfer` - /// to move lamports to a wrapped token account, and needs to have its token - /// `amount` field updated. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The native token account to sync with its underlying lamports. - SyncNative, - /// Like InitializeAccount2, but does not require the Rent sysvar to be provided - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The account to initialize. - /// 1. `[]` The mint this account will be associated with. - InitializeAccount3 { - /// The new account's owner/multisignature. - owner: Pubkey, - }, - /// Like InitializeMultisig, but does not require the Rent sysvar to be provided - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The multisignature account to initialize. - /// 1. ..1+N. `[]` The signer accounts, must equal to N where 1 <= N <= - /// 11. - InitializeMultisig2 { - /// The number of signers (M) required to validate this multisignature - /// account. - m: u8, - }, - /// Like InitializeMint, but does not require the Rent sysvar to be provided - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The mint to initialize. - /// - InitializeMint2 { - /// Number of base 10 digits to the right of the decimal place. - decimals: u8, - /// The authority/multisignature to mint tokens. - mint_authority: Pubkey, - /// The freeze authority/multisignature of the mint. - freeze_authority: COption, - }, - /// Gets the required size of an account for the given mint as a little-endian - /// `u64`. - /// - /// Return data can be fetched using `sol_get_return_data` and deserializing - /// the return data as a little-endian `u64`. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[]` The mint to calculate for - GetAccountDataSize, // typically, there's also data, but this program ignores it - /// Initialize the Immutable Owner extension for the given token account - /// - /// Fails if the account has already been initialized, so must be called before - /// `InitializeAccount`. - /// - /// No-ops in this version of the program, but is included for compatibility - /// with the Associated Token Account program. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The account to initialize. - /// - /// Data expected by this instruction: - /// None - InitializeImmutableOwner, - /// Convert an Amount of tokens to a UiAmount `string`, using the given mint. - /// In this version of the program, the mint can only specify the number of decimals. - /// - /// Fails on an invalid mint. - /// - /// Return data can be fetched using `sol_get_return_data` and deserialized with - /// `String::from_utf8`. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[]` The mint to calculate for - AmountToUiAmount { - /// The amount of tokens to reformat. - amount: u64, - }, - /// Convert a UiAmount of tokens to a little-endian `u64` raw Amount, using the given mint. - /// In this version of the program, the mint can only specify the number of decimals. - /// - /// Return data can be fetched using `sol_get_return_data` and deserializing - /// the return data as a little-endian `u64`. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[]` The mint to calculate for - UiAmountToAmount { - /// The ui_amount of tokens to reformat. - ui_amount: &'a str, - }, - // Any new variants also need to be added to program-2022 `TokenInstruction`, so that the - // latter remains a superset of this instruction set. New variants also need to be added to - // token/js/src/instructions/types.ts to maintain @solana/spl-token compatability -} -impl<'a> TokenInstruction<'a> { - /// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html). - pub fn unpack(input: &'a [u8]) -> Result { - use TokenError::InvalidInstruction; - - let (&tag, rest) = input.split_first().ok_or(InvalidInstruction)?; - Ok(match tag { - 0 => { - let (&decimals, rest) = rest.split_first().ok_or(InvalidInstruction)?; - let (mint_authority, rest) = Self::unpack_pubkey(rest)?; - let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?; - Self::InitializeMint { - mint_authority, - freeze_authority, - decimals, - } - } - 1 => Self::InitializeAccount, - 2 => { - let &m = rest.get(0).ok_or(InvalidInstruction)?; - Self::InitializeMultisig { m } - } - 3 | 4 | 7 | 8 => { - let amount = rest - .get(..8) - .and_then(|slice| slice.try_into().ok()) - .map(u64::from_le_bytes) - .ok_or(InvalidInstruction)?; - match tag { - 3 => Self::Transfer { amount }, - 4 => Self::Approve { amount }, - 7 => Self::MintTo { amount }, - 8 => Self::Burn { amount }, - _ => unreachable!(), - } - } - 5 => Self::Revoke, - 6 => { - let (authority_type, rest) = rest - .split_first() - .ok_or_else(|| ProgramError::from(InvalidInstruction)) - .and_then(|(&t, rest)| Ok((AuthorityType::from(t)?, rest)))?; - let (new_authority, _rest) = Self::unpack_pubkey_option(rest)?; - - Self::SetAuthority { - authority_type, - new_authority, - } - } - 9 => Self::CloseAccount, - 10 => Self::FreezeAccount, - 11 => Self::ThawAccount, - 12 => { - let (amount, rest) = rest.split_at(8); - let amount = amount - .try_into() - .ok() - .map(u64::from_le_bytes) - .ok_or(InvalidInstruction)?; - let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; - - Self::TransferChecked { amount, decimals } - } - 13 => { - let (amount, rest) = rest.split_at(8); - let amount = amount - .try_into() - .ok() - .map(u64::from_le_bytes) - .ok_or(InvalidInstruction)?; - let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; - - Self::ApproveChecked { amount, decimals } - } - 14 => { - let (amount, rest) = rest.split_at(8); - let amount = amount - .try_into() - .ok() - .map(u64::from_le_bytes) - .ok_or(InvalidInstruction)?; - let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; - - Self::MintToChecked { amount, decimals } - } - 15 => { - let (amount, rest) = rest.split_at(8); - let amount = amount - .try_into() - .ok() - .map(u64::from_le_bytes) - .ok_or(InvalidInstruction)?; - let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; - - Self::BurnChecked { amount, decimals } - } - 16 => { - let (owner, _rest) = Self::unpack_pubkey(rest)?; - Self::InitializeAccount2 { owner } - } - 17 => Self::SyncNative, - 18 => { - let (owner, _rest) = Self::unpack_pubkey(rest)?; - Self::InitializeAccount3 { owner } - } - 19 => { - let &m = rest.get(0).ok_or(InvalidInstruction)?; - Self::InitializeMultisig2 { m } - } - 20 => { - let (&decimals, rest) = rest.split_first().ok_or(InvalidInstruction)?; - let (mint_authority, rest) = Self::unpack_pubkey(rest)?; - let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?; - Self::InitializeMint2 { - mint_authority, - freeze_authority, - decimals, - } - } - 21 => Self::GetAccountDataSize, - 22 => Self::InitializeImmutableOwner, - 23 => { - let (amount, _rest) = rest.split_at(8); - let amount = amount - .try_into() - .ok() - .map(u64::from_le_bytes) - .ok_or(InvalidInstruction)?; - Self::AmountToUiAmount { amount } - } - 24 => { - let ui_amount = std::str::from_utf8(rest).map_err(|_| InvalidInstruction)?; - Self::UiAmountToAmount { ui_amount } - } - _ => return Err(TokenError::InvalidInstruction.into()), - }) - } - - /// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte buffer. - pub fn pack(&self) -> Vec { - let mut buf = Vec::with_capacity(size_of::()); - match self { - &Self::InitializeMint { - ref mint_authority, - ref freeze_authority, - decimals, - } => { - buf.push(0); - buf.push(decimals); - buf.extend_from_slice(mint_authority.as_ref()); - Self::pack_pubkey_option(freeze_authority, &mut buf); - } - Self::InitializeAccount => buf.push(1), - &Self::InitializeMultisig { m } => { - buf.push(2); - buf.push(m); - } - &Self::Transfer { amount } => { - buf.push(3); - buf.extend_from_slice(&amount.to_le_bytes()); - } - &Self::Approve { amount } => { - buf.push(4); - buf.extend_from_slice(&amount.to_le_bytes()); - } - &Self::MintTo { amount } => { - buf.push(7); - buf.extend_from_slice(&amount.to_le_bytes()); - } - &Self::Burn { amount } => { - buf.push(8); - buf.extend_from_slice(&amount.to_le_bytes()); - } - Self::Revoke => buf.push(5), - Self::SetAuthority { - authority_type, - ref new_authority, - } => { - buf.push(6); - buf.push(authority_type.into()); - Self::pack_pubkey_option(new_authority, &mut buf); - } - Self::CloseAccount => buf.push(9), - Self::FreezeAccount => buf.push(10), - Self::ThawAccount => buf.push(11), - &Self::TransferChecked { amount, decimals } => { - buf.push(12); - buf.extend_from_slice(&amount.to_le_bytes()); - buf.push(decimals); - } - &Self::ApproveChecked { amount, decimals } => { - buf.push(13); - buf.extend_from_slice(&amount.to_le_bytes()); - buf.push(decimals); - } - &Self::MintToChecked { amount, decimals } => { - buf.push(14); - buf.extend_from_slice(&amount.to_le_bytes()); - buf.push(decimals); - } - &Self::BurnChecked { amount, decimals } => { - buf.push(15); - buf.extend_from_slice(&amount.to_le_bytes()); - buf.push(decimals); - } - &Self::InitializeAccount2 { owner } => { - buf.push(16); - buf.extend_from_slice(owner.as_ref()); - } - &Self::SyncNative => { - buf.push(17); - } - &Self::InitializeAccount3 { owner } => { - buf.push(18); - buf.extend_from_slice(owner.as_ref()); - } - &Self::InitializeMultisig2 { m } => { - buf.push(19); - buf.push(m); - } - &Self::InitializeMint2 { - ref mint_authority, - ref freeze_authority, - decimals, - } => { - buf.push(20); - buf.push(decimals); - buf.extend_from_slice(mint_authority.as_ref()); - Self::pack_pubkey_option(freeze_authority, &mut buf); - } - &Self::GetAccountDataSize => { - buf.push(21); - } - &Self::InitializeImmutableOwner => { - buf.push(22); - } - &Self::AmountToUiAmount { amount } => { - buf.push(23); - buf.extend_from_slice(&amount.to_le_bytes()); - } - Self::UiAmountToAmount { ui_amount } => { - buf.push(24); - buf.extend_from_slice(ui_amount.as_bytes()); - } - }; - buf - } - - fn unpack_pubkey(input: &[u8]) -> Result<(Pubkey, &[u8]), ProgramError> { - if input.len() >= 32 { - let (key, rest) = input.split_at(32); - let pk = Pubkey::new(key); - Ok((pk, rest)) - } else { - Err(TokenError::InvalidInstruction.into()) - } - } - - fn unpack_pubkey_option(input: &[u8]) -> Result<(COption, &[u8]), ProgramError> { - match input.split_first() { - Option::Some((&0, rest)) => Ok((COption::None, rest)), - Option::Some((&1, rest)) if rest.len() >= 32 => { - let (key, rest) = rest.split_at(32); - let pk = Pubkey::new(key); - Ok((COption::Some(pk), rest)) - } - _ => Err(TokenError::InvalidInstruction.into()), - } - } - - fn pack_pubkey_option(value: &COption, buf: &mut Vec) { - match *value { - COption::Some(ref key) => { - buf.push(1); - buf.extend_from_slice(&key.to_bytes()); - } - COption::None => buf.push(0), - } - } -} - -/// Specifies the authority type for SetAuthority instructions -#[repr(u8)] -#[derive(Clone, Debug, PartialEq)] -pub enum AuthorityType { - /// Authority to mint new tokens - MintTokens, - /// Authority to freeze any account associated with the Mint - FreezeAccount, - /// Owner of a given token account - AccountOwner, - /// Authority to close a token account - CloseAccount, -} - -impl AuthorityType { - fn into(&self) -> u8 { - match self { - AuthorityType::MintTokens => 0, - AuthorityType::FreezeAccount => 1, - AuthorityType::AccountOwner => 2, - AuthorityType::CloseAccount => 3, - } - } - - fn from(index: u8) -> Result { - match index { - 0 => Ok(AuthorityType::MintTokens), - 1 => Ok(AuthorityType::FreezeAccount), - 2 => Ok(AuthorityType::AccountOwner), - 3 => Ok(AuthorityType::CloseAccount), - _ => Err(TokenError::InvalidInstruction.into()), - } - } -} - -/// Creates a `InitializeMint` instruction. -pub fn initialize_mint( - token_program_id: &Pubkey, - mint_pubkey: &Pubkey, - mint_authority_pubkey: &Pubkey, - freeze_authority_pubkey: Option<&Pubkey>, - decimals: u8, -) -> Result { - check_program_account(token_program_id)?; - let freeze_authority = freeze_authority_pubkey.cloned().into(); - let data = TokenInstruction::InitializeMint { - mint_authority: *mint_authority_pubkey, - freeze_authority, - decimals, - } - .pack(); - - let accounts = vec![ - AccountMeta::new(*mint_pubkey, false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - ]; - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `InitializeMint2` instruction. -pub fn initialize_mint2( - token_program_id: &Pubkey, - mint_pubkey: &Pubkey, - mint_authority_pubkey: &Pubkey, - freeze_authority_pubkey: Option<&Pubkey>, - decimals: u8, -) -> Result { - check_program_account(token_program_id)?; - let freeze_authority = freeze_authority_pubkey.cloned().into(); - let data = TokenInstruction::InitializeMint2 { - mint_authority: *mint_authority_pubkey, - freeze_authority, - decimals, - } - .pack(); - - let accounts = vec![AccountMeta::new(*mint_pubkey, false)]; - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `InitializeAccount` instruction. -pub fn initialize_account( - token_program_id: &Pubkey, - account_pubkey: &Pubkey, - mint_pubkey: &Pubkey, - owner_pubkey: &Pubkey, -) -> Result { - check_program_account(token_program_id)?; - let data = TokenInstruction::InitializeAccount.pack(); - - let accounts = vec![ - AccountMeta::new(*account_pubkey, false), - AccountMeta::new_readonly(*mint_pubkey, false), - AccountMeta::new_readonly(*owner_pubkey, false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - ]; - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `InitializeAccount2` instruction. -pub fn initialize_account2( - token_program_id: &Pubkey, - account_pubkey: &Pubkey, - mint_pubkey: &Pubkey, - owner_pubkey: &Pubkey, -) -> Result { - check_program_account(token_program_id)?; - let data = TokenInstruction::InitializeAccount2 { - owner: *owner_pubkey, - } - .pack(); - - let accounts = vec![ - AccountMeta::new(*account_pubkey, false), - AccountMeta::new_readonly(*mint_pubkey, false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - ]; - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `InitializeAccount3` instruction. -pub fn initialize_account3( - token_program_id: &Pubkey, - account_pubkey: &Pubkey, - mint_pubkey: &Pubkey, - owner_pubkey: &Pubkey, -) -> Result { - check_program_account(token_program_id)?; - let data = TokenInstruction::InitializeAccount3 { - owner: *owner_pubkey, - } - .pack(); - - let accounts = vec![ - AccountMeta::new(*account_pubkey, false), - AccountMeta::new_readonly(*mint_pubkey, false), - ]; - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `InitializeMultisig` instruction. -pub fn initialize_multisig( - token_program_id: &Pubkey, - multisig_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - m: u8, -) -> Result { - check_program_account(token_program_id)?; - if !is_valid_signer_index(m as usize) - || !is_valid_signer_index(signer_pubkeys.len()) - || m as usize > signer_pubkeys.len() - { - return Err(ProgramError::MissingRequiredSignature); - } - let data = TokenInstruction::InitializeMultisig { m }.pack(); - - let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*multisig_pubkey, false)); - accounts.push(AccountMeta::new_readonly(sysvar::rent::id(), false)); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, false)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `InitializeMultisig2` instruction. -pub fn initialize_multisig2( - token_program_id: &Pubkey, - multisig_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - m: u8, -) -> Result { - check_program_account(token_program_id)?; - if !is_valid_signer_index(m as usize) - || !is_valid_signer_index(signer_pubkeys.len()) - || m as usize > signer_pubkeys.len() - { - return Err(ProgramError::MissingRequiredSignature); - } - let data = TokenInstruction::InitializeMultisig2 { m }.pack(); - - let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*multisig_pubkey, false)); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, false)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `Transfer` instruction. -pub fn transfer( - token_program_id: &Pubkey, - source_pubkey: &Pubkey, - destination_pubkey: &Pubkey, - authority_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - amount: u64, -) -> Result { - check_program_account(token_program_id)?; - let data = TokenInstruction::Transfer { amount }.pack(); - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*source_pubkey, false)); - accounts.push(AccountMeta::new(*destination_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *authority_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates an `Approve` instruction. -pub fn approve( - token_program_id: &Pubkey, - source_pubkey: &Pubkey, - delegate_pubkey: &Pubkey, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - amount: u64, -) -> Result { - check_program_account(token_program_id)?; - let data = TokenInstruction::Approve { amount }.pack(); - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*source_pubkey, false)); - accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `Revoke` instruction. -pub fn revoke( - token_program_id: &Pubkey, - source_pubkey: &Pubkey, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], -) -> Result { - check_program_account(token_program_id)?; - let data = TokenInstruction::Revoke.pack(); - - let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*source_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `SetAuthority` instruction. -pub fn set_authority( - token_program_id: &Pubkey, - owned_pubkey: &Pubkey, - new_authority_pubkey: Option<&Pubkey>, - authority_type: AuthorityType, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], -) -> Result { - check_program_account(token_program_id)?; - let new_authority = new_authority_pubkey.cloned().into(); - let data = TokenInstruction::SetAuthority { - authority_type, - new_authority, - } - .pack(); - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*owned_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `MintTo` instruction. -pub fn mint_to( - token_program_id: &Pubkey, - mint_pubkey: &Pubkey, - account_pubkey: &Pubkey, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - amount: u64, -) -> Result { - check_program_account(token_program_id)?; - let data = TokenInstruction::MintTo { amount }.pack(); - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*mint_pubkey, false)); - accounts.push(AccountMeta::new(*account_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `Burn` instruction. -pub fn burn( - token_program_id: &Pubkey, - account_pubkey: &Pubkey, - mint_pubkey: &Pubkey, - authority_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - amount: u64, -) -> Result { - check_program_account(token_program_id)?; - let data = TokenInstruction::Burn { amount }.pack(); - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*account_pubkey, false)); - accounts.push(AccountMeta::new(*mint_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *authority_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `CloseAccount` instruction. -pub fn close_account( - token_program_id: &Pubkey, - account_pubkey: &Pubkey, - destination_pubkey: &Pubkey, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], -) -> Result { - check_program_account(token_program_id)?; - let data = TokenInstruction::CloseAccount.pack(); - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*account_pubkey, false)); - accounts.push(AccountMeta::new(*destination_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `FreezeAccount` instruction. -pub fn freeze_account( - token_program_id: &Pubkey, - account_pubkey: &Pubkey, - mint_pubkey: &Pubkey, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], -) -> Result { - check_program_account(token_program_id)?; - let data = TokenInstruction::FreezeAccount.pack(); - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*account_pubkey, false)); - accounts.push(AccountMeta::new_readonly(*mint_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `ThawAccount` instruction. -pub fn thaw_account( - token_program_id: &Pubkey, - account_pubkey: &Pubkey, - mint_pubkey: &Pubkey, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], -) -> Result { - check_program_account(token_program_id)?; - let data = TokenInstruction::ThawAccount.pack(); - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*account_pubkey, false)); - accounts.push(AccountMeta::new_readonly(*mint_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `TransferChecked` instruction. -#[allow(clippy::too_many_arguments)] -pub fn transfer_checked( - token_program_id: &Pubkey, - source_pubkey: &Pubkey, - mint_pubkey: &Pubkey, - destination_pubkey: &Pubkey, - authority_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - amount: u64, - decimals: u8, -) -> Result { - check_program_account(token_program_id)?; - let data = TokenInstruction::TransferChecked { amount, decimals }.pack(); - - let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*source_pubkey, false)); - accounts.push(AccountMeta::new_readonly(*mint_pubkey, false)); - accounts.push(AccountMeta::new(*destination_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *authority_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates an `ApproveChecked` instruction. -#[allow(clippy::too_many_arguments)] -pub fn approve_checked( - token_program_id: &Pubkey, - source_pubkey: &Pubkey, - mint_pubkey: &Pubkey, - delegate_pubkey: &Pubkey, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - amount: u64, - decimals: u8, -) -> Result { - check_program_account(token_program_id)?; - let data = TokenInstruction::ApproveChecked { amount, decimals }.pack(); - - let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*source_pubkey, false)); - accounts.push(AccountMeta::new_readonly(*mint_pubkey, false)); - accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `MintToChecked` instruction. -pub fn mint_to_checked( - token_program_id: &Pubkey, - mint_pubkey: &Pubkey, - account_pubkey: &Pubkey, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - amount: u64, - decimals: u8, -) -> Result { - check_program_account(token_program_id)?; - let data = TokenInstruction::MintToChecked { amount, decimals }.pack(); - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*mint_pubkey, false)); - accounts.push(AccountMeta::new(*account_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `BurnChecked` instruction. -pub fn burn_checked( - token_program_id: &Pubkey, - account_pubkey: &Pubkey, - mint_pubkey: &Pubkey, - authority_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - amount: u64, - decimals: u8, -) -> Result { - check_program_account(token_program_id)?; - let data = TokenInstruction::BurnChecked { amount, decimals }.pack(); - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*account_pubkey, false)); - accounts.push(AccountMeta::new(*mint_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *authority_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `SyncNative` instruction -pub fn sync_native( - token_program_id: &Pubkey, - account_pubkey: &Pubkey, -) -> Result { - check_program_account(token_program_id)?; - - Ok(Instruction { - program_id: *token_program_id, - accounts: vec![AccountMeta::new(*account_pubkey, false)], - data: TokenInstruction::SyncNative.pack(), - }) -} - -/// Creates a `GetAccountDataSize` instruction -pub fn get_account_data_size( - token_program_id: &Pubkey, - mint_pubkey: &Pubkey, -) -> Result { - check_program_account(token_program_id)?; - - Ok(Instruction { - program_id: *token_program_id, - accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)], - data: TokenInstruction::GetAccountDataSize.pack(), - }) -} - -/// Creates a `InitializeImmutableOwner` instruction -pub fn initialize_immutable_owner( - token_program_id: &Pubkey, - account_pubkey: &Pubkey, -) -> Result { - check_program_account(token_program_id)?; - Ok(Instruction { - program_id: *token_program_id, - accounts: vec![AccountMeta::new(*account_pubkey, false)], - data: TokenInstruction::InitializeImmutableOwner.pack(), - }) -} - -/// Creates an `AmountToUiAmount` instruction -pub fn amount_to_ui_amount( - token_program_id: &Pubkey, - mint_pubkey: &Pubkey, - amount: u64, -) -> Result { - check_program_account(token_program_id)?; - - Ok(Instruction { - program_id: *token_program_id, - accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)], - data: TokenInstruction::AmountToUiAmount { amount }.pack(), - }) -} - -/// Creates a `UiAmountToAmount` instruction -pub fn ui_amount_to_amount( - token_program_id: &Pubkey, - mint_pubkey: &Pubkey, - ui_amount: &str, -) -> Result { - check_program_account(token_program_id)?; - - Ok(Instruction { - program_id: *token_program_id, - accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)], - data: TokenInstruction::UiAmountToAmount { ui_amount }.pack(), - }) -} - -/// Utility function that checks index is between MIN_SIGNERS and MAX_SIGNERS -pub fn is_valid_signer_index(index: usize) -> bool { - (MIN_SIGNERS..=MAX_SIGNERS).contains(&index) -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_instruction_packing() { - let check = TokenInstruction::InitializeMint { - decimals: 2, - mint_authority: Pubkey::new(&[1u8; 32]), - freeze_authority: COption::None, - }; - let packed = check.pack(); - let mut expect = Vec::from([0u8, 2]); - expect.extend_from_slice(&[1u8; 32]); - expect.extend_from_slice(&[0]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::InitializeMint { - decimals: 2, - mint_authority: Pubkey::new(&[2u8; 32]), - freeze_authority: COption::Some(Pubkey::new(&[3u8; 32])), - }; - let packed = check.pack(); - let mut expect = vec![0u8, 2]; - expect.extend_from_slice(&[2u8; 32]); - expect.extend_from_slice(&[1]); - expect.extend_from_slice(&[3u8; 32]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::InitializeAccount; - let packed = check.pack(); - let expect = Vec::from([1u8]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::InitializeMultisig { m: 1 }; - let packed = check.pack(); - let expect = Vec::from([2u8, 1]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::Transfer { amount: 1 }; - let packed = check.pack(); - let expect = Vec::from([3u8, 1, 0, 0, 0, 0, 0, 0, 0]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::Approve { amount: 1 }; - let packed = check.pack(); - let expect = Vec::from([4u8, 1, 0, 0, 0, 0, 0, 0, 0]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::Revoke; - let packed = check.pack(); - let expect = Vec::from([5u8]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::SetAuthority { - authority_type: AuthorityType::FreezeAccount, - new_authority: COption::Some(Pubkey::new(&[4u8; 32])), - }; - let packed = check.pack(); - let mut expect = Vec::from([6u8, 1]); - expect.extend_from_slice(&[1]); - expect.extend_from_slice(&[4u8; 32]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::MintTo { amount: 1 }; - let packed = check.pack(); - let expect = Vec::from([7u8, 1, 0, 0, 0, 0, 0, 0, 0]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::Burn { amount: 1 }; - let packed = check.pack(); - let expect = Vec::from([8u8, 1, 0, 0, 0, 0, 0, 0, 0]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::CloseAccount; - let packed = check.pack(); - let expect = Vec::from([9u8]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::FreezeAccount; - let packed = check.pack(); - let expect = Vec::from([10u8]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::ThawAccount; - let packed = check.pack(); - let expect = Vec::from([11u8]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::TransferChecked { - amount: 1, - decimals: 2, - }; - let packed = check.pack(); - let expect = Vec::from([12u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::ApproveChecked { - amount: 1, - decimals: 2, - }; - let packed = check.pack(); - let expect = Vec::from([13u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::MintToChecked { - amount: 1, - decimals: 2, - }; - let packed = check.pack(); - let expect = Vec::from([14u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::BurnChecked { - amount: 1, - decimals: 2, - }; - let packed = check.pack(); - let expect = Vec::from([15u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::InitializeAccount2 { - owner: Pubkey::new(&[2u8; 32]), - }; - let packed = check.pack(); - let mut expect = vec![16u8]; - expect.extend_from_slice(&[2u8; 32]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::SyncNative; - let packed = check.pack(); - let expect = vec![17u8]; - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::InitializeAccount3 { - owner: Pubkey::new(&[2u8; 32]), - }; - let packed = check.pack(); - let mut expect = vec![18u8]; - expect.extend_from_slice(&[2u8; 32]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::InitializeMultisig2 { m: 1 }; - let packed = check.pack(); - let expect = Vec::from([19u8, 1]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::InitializeMint2 { - decimals: 2, - mint_authority: Pubkey::new(&[1u8; 32]), - freeze_authority: COption::None, - }; - let packed = check.pack(); - let mut expect = Vec::from([20u8, 2]); - expect.extend_from_slice(&[1u8; 32]); - expect.extend_from_slice(&[0]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::InitializeMint2 { - decimals: 2, - mint_authority: Pubkey::new(&[2u8; 32]), - freeze_authority: COption::Some(Pubkey::new(&[3u8; 32])), - }; - let packed = check.pack(); - let mut expect = vec![20u8, 2]; - expect.extend_from_slice(&[2u8; 32]); - expect.extend_from_slice(&[1]); - expect.extend_from_slice(&[3u8; 32]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::GetAccountDataSize; - let packed = check.pack(); - let expect = vec![21u8]; - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::InitializeImmutableOwner; - let packed = check.pack(); - let expect = vec![22u8]; - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::AmountToUiAmount { amount: 42 }; - let packed = check.pack(); - let expect = vec![23u8, 42, 0, 0, 0, 0, 0, 0, 0]; - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::UiAmountToAmount { ui_amount: "0.42" }; - let packed = check.pack(); - let expect = vec![24u8, 48, 46, 52, 50]; - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - } -} diff --git a/token/program/src/lib.rs b/token/program/src/lib.rs deleted file mode 100644 index 2252ac168de..00000000000 --- a/token/program/src/lib.rs +++ /dev/null @@ -1,87 +0,0 @@ -#![deny(missing_docs)] -#![cfg_attr(not(test), forbid(unsafe_code))] - -//! An ERC20-like Token program for the Solana blockchain - -pub mod error; -pub mod instruction; -pub mod native_mint; -pub mod processor; -pub mod state; - -#[cfg(not(feature = "no-entrypoint"))] -mod entrypoint; - -// Export current sdk types for downstream users building with a different sdk version -pub use solana_program; -use solana_program::{entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey}; - -/// Convert the UI representation of a token amount (using the decimals field defined in its mint) -/// to the raw amount -pub fn ui_amount_to_amount(ui_amount: f64, decimals: u8) -> u64 { - (ui_amount * 10_usize.pow(decimals as u32) as f64) as u64 -} - -/// Convert a raw amount to its UI representation (using the decimals field defined in its mint) -pub fn amount_to_ui_amount(amount: u64, decimals: u8) -> f64 { - amount as f64 / 10_usize.pow(decimals as u32) as f64 -} - -/// Convert a raw amount to its UI representation (using the decimals field defined in its mint) -pub fn amount_to_ui_amount_string(amount: u64, decimals: u8) -> String { - let decimals = decimals as usize; - if decimals > 0 { - // Left-pad zeros to decimals + 1, so we at least have an integer zero - let mut s = format!("{:01$}", amount, decimals + 1); - // Add the decimal point (Sorry, "," locales!) - s.insert(s.len() - decimals, '.'); - s - } else { - amount.to_string() - } -} - -/// Convert a raw amount to its UI representation using the given decimals field -/// Excess zeroes or unneeded decimal point are trimmed. -pub fn amount_to_ui_amount_string_trimmed(amount: u64, decimals: u8) -> String { - let mut s = amount_to_ui_amount_string(amount, decimals); - if decimals > 0 { - let zeros_trimmed = s.trim_end_matches('0'); - s = zeros_trimmed.trim_end_matches('.').to_string(); - } - s -} - -/// Try to convert a UI represenation of a token amount to its raw amount using the given decimals -/// field -pub fn try_ui_amount_into_amount(ui_amount: String, decimals: u8) -> Result { - let decimals = decimals as usize; - let mut parts = ui_amount.split('.'); - let mut amount_str = parts.next().unwrap().to_string(); // splitting a string, even an empty one, will always yield an iterator of at least len == 1 - let after_decimal = parts.next().unwrap_or(""); - let after_decimal = after_decimal.trim_end_matches('0'); - if (amount_str.is_empty() && after_decimal.is_empty()) - || parts.next().is_some() - || after_decimal.len() > decimals - { - return Err(ProgramError::InvalidArgument); - } - - amount_str.push_str(after_decimal); - for _ in 0..decimals.saturating_sub(after_decimal.len()) { - amount_str.push('0'); - } - amount_str - .parse::() - .map_err(|_| ProgramError::InvalidArgument) -} - -solana_program::declare_id!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); - -/// Checks that the supplied program ID is the correct one for SPL-token -pub fn check_program_account(spl_token_program_id: &Pubkey) -> ProgramResult { - if spl_token_program_id != &id() { - return Err(ProgramError::IncorrectProgramId); - } - Ok(()) -} diff --git a/token/program/src/native_mint.rs b/token/program/src/native_mint.rs deleted file mode 100644 index 0502f9f71e8..00000000000 --- a/token/program/src/native_mint.rs +++ /dev/null @@ -1,24 +0,0 @@ -//! The Mint that represents the native token - -/// There are 10^9 lamports in one SOL -pub const DECIMALS: u8 = 9; - -// The Mint for native SOL Token accounts -solana_program::declare_id!("So11111111111111111111111111111111111111112"); - -#[cfg(test)] -mod tests { - use super::*; - use solana_program::native_token::*; - - #[test] - fn test_decimals() { - assert!( - (lamports_to_sol(42) - crate::amount_to_ui_amount(42, DECIMALS)).abs() < f64::EPSILON - ); - assert_eq!( - sol_to_lamports(42.), - crate::ui_amount_to_amount(42., DECIMALS) - ); - } -} diff --git a/token/program/src/processor.rs b/token/program/src/processor.rs deleted file mode 100644 index de7152ad865..00000000000 --- a/token/program/src/processor.rs +++ /dev/null @@ -1,6963 +0,0 @@ -//! Program state processor - -use crate::{ - amount_to_ui_amount_string_trimmed, - error::TokenError, - instruction::{is_valid_signer_index, AuthorityType, TokenInstruction, MAX_SIGNERS}, - state::{Account, AccountState, Mint, Multisig}, - try_ui_amount_into_amount, -}; -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - program::set_return_data, - program_error::ProgramError, - program_memory::sol_memcmp, - program_option::COption, - program_pack::{IsInitialized, Pack}, - pubkey::{Pubkey, PUBKEY_BYTES}, - system_program, - sysvar::{rent::Rent, Sysvar}, -}; - -/// Program state handler. -pub struct Processor {} -impl Processor { - fn _process_initialize_mint( - accounts: &[AccountInfo], - decimals: u8, - mint_authority: Pubkey, - freeze_authority: COption, - rent_sysvar_account: bool, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_info = next_account_info(account_info_iter)?; - let mint_data_len = mint_info.data_len(); - let rent = if rent_sysvar_account { - Rent::from_account_info(next_account_info(account_info_iter)?)? - } else { - Rent::get()? - }; - - let mut mint = Mint::unpack_unchecked(&mint_info.data.borrow())?; - if mint.is_initialized { - return Err(TokenError::AlreadyInUse.into()); - } - - if !rent.is_exempt(mint_info.lamports(), mint_data_len) { - return Err(TokenError::NotRentExempt.into()); - } - - mint.mint_authority = COption::Some(mint_authority); - mint.decimals = decimals; - mint.is_initialized = true; - mint.freeze_authority = freeze_authority; - - Mint::pack(mint, &mut mint_info.data.borrow_mut())?; - - Ok(()) - } - - /// Processes an [InitializeMint](enum.TokenInstruction.html) instruction. - pub fn process_initialize_mint( - accounts: &[AccountInfo], - decimals: u8, - mint_authority: Pubkey, - freeze_authority: COption, - ) -> ProgramResult { - Self::_process_initialize_mint(accounts, decimals, mint_authority, freeze_authority, true) - } - - /// Processes an [InitializeMint2](enum.TokenInstruction.html) instruction. - pub fn process_initialize_mint2( - accounts: &[AccountInfo], - decimals: u8, - mint_authority: Pubkey, - freeze_authority: COption, - ) -> ProgramResult { - Self::_process_initialize_mint(accounts, decimals, mint_authority, freeze_authority, false) - } - - fn _process_initialize_account( - program_id: &Pubkey, - accounts: &[AccountInfo], - owner: Option<&Pubkey>, - rent_sysvar_account: bool, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let new_account_info = next_account_info(account_info_iter)?; - let mint_info = next_account_info(account_info_iter)?; - let owner = if let Some(owner) = owner { - owner - } else { - next_account_info(account_info_iter)?.key - }; - let new_account_info_data_len = new_account_info.data_len(); - let rent = if rent_sysvar_account { - Rent::from_account_info(next_account_info(account_info_iter)?)? - } else { - Rent::get()? - }; - - let mut account = Account::unpack_unchecked(&new_account_info.data.borrow())?; - if account.is_initialized() { - return Err(TokenError::AlreadyInUse.into()); - } - - if !rent.is_exempt(new_account_info.lamports(), new_account_info_data_len) { - return Err(TokenError::NotRentExempt.into()); - } - - let is_native_mint = Self::cmp_pubkeys(mint_info.key, &crate::native_mint::id()); - if !is_native_mint { - Self::check_account_owner(program_id, mint_info)?; - let _ = Mint::unpack(&mint_info.data.borrow_mut()) - .map_err(|_| Into::::into(TokenError::InvalidMint))?; - } - - account.mint = *mint_info.key; - account.owner = *owner; - account.close_authority = COption::None; - account.delegate = COption::None; - account.delegated_amount = 0; - account.state = AccountState::Initialized; - if is_native_mint { - let rent_exempt_reserve = rent.minimum_balance(new_account_info_data_len); - account.is_native = COption::Some(rent_exempt_reserve); - account.amount = new_account_info - .lamports() - .checked_sub(rent_exempt_reserve) - .ok_or(TokenError::Overflow)?; - } else { - account.is_native = COption::None; - account.amount = 0; - }; - - Account::pack(account, &mut new_account_info.data.borrow_mut())?; - - Ok(()) - } - - /// Processes an [InitializeAccount](enum.TokenInstruction.html) instruction. - pub fn process_initialize_account( - program_id: &Pubkey, - accounts: &[AccountInfo], - ) -> ProgramResult { - Self::_process_initialize_account(program_id, accounts, None, true) - } - - /// Processes an [InitializeAccount2](enum.TokenInstruction.html) instruction. - pub fn process_initialize_account2( - program_id: &Pubkey, - accounts: &[AccountInfo], - owner: Pubkey, - ) -> ProgramResult { - Self::_process_initialize_account(program_id, accounts, Some(&owner), true) - } - - /// Processes an [InitializeAccount3](enum.TokenInstruction.html) instruction. - pub fn process_initialize_account3( - program_id: &Pubkey, - accounts: &[AccountInfo], - owner: Pubkey, - ) -> ProgramResult { - Self::_process_initialize_account(program_id, accounts, Some(&owner), false) - } - - fn _process_initialize_multisig( - accounts: &[AccountInfo], - m: u8, - rent_sysvar_account: bool, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let multisig_info = next_account_info(account_info_iter)?; - let multisig_info_data_len = multisig_info.data_len(); - let rent = if rent_sysvar_account { - Rent::from_account_info(next_account_info(account_info_iter)?)? - } else { - Rent::get()? - }; - - let mut multisig = Multisig::unpack_unchecked(&multisig_info.data.borrow())?; - if multisig.is_initialized { - return Err(TokenError::AlreadyInUse.into()); - } - - if !rent.is_exempt(multisig_info.lamports(), multisig_info_data_len) { - return Err(TokenError::NotRentExempt.into()); - } - - let signer_infos = account_info_iter.as_slice(); - multisig.m = m; - multisig.n = signer_infos.len() as u8; - if !is_valid_signer_index(multisig.n as usize) { - return Err(TokenError::InvalidNumberOfProvidedSigners.into()); - } - if !is_valid_signer_index(multisig.m as usize) { - return Err(TokenError::InvalidNumberOfRequiredSigners.into()); - } - for (i, signer_info) in signer_infos.iter().enumerate() { - multisig.signers[i] = *signer_info.key; - } - multisig.is_initialized = true; - - Multisig::pack(multisig, &mut multisig_info.data.borrow_mut())?; - - Ok(()) - } - - /// Processes a [InitializeMultisig](enum.TokenInstruction.html) instruction. - pub fn process_initialize_multisig(accounts: &[AccountInfo], m: u8) -> ProgramResult { - Self::_process_initialize_multisig(accounts, m, true) - } - - /// Processes a [InitializeMultisig2](enum.TokenInstruction.html) instruction. - pub fn process_initialize_multisig2(accounts: &[AccountInfo], m: u8) -> ProgramResult { - Self::_process_initialize_multisig(accounts, m, false) - } - - /// Processes a [Transfer](enum.TokenInstruction.html) instruction. - pub fn process_transfer( - program_id: &Pubkey, - accounts: &[AccountInfo], - amount: u64, - expected_decimals: Option, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - - let source_account_info = next_account_info(account_info_iter)?; - - let expected_mint_info = if let Some(expected_decimals) = expected_decimals { - Some((next_account_info(account_info_iter)?, expected_decimals)) - } else { - None - }; - - let destination_account_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - - let mut source_account = Account::unpack(&source_account_info.data.borrow())?; - let mut destination_account = Account::unpack(&destination_account_info.data.borrow())?; - - if source_account.is_frozen() || destination_account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - if source_account.amount < amount { - return Err(TokenError::InsufficientFunds.into()); - } - if !Self::cmp_pubkeys(&source_account.mint, &destination_account.mint) { - return Err(TokenError::MintMismatch.into()); - } - - if let Some((mint_info, expected_decimals)) = expected_mint_info { - if !Self::cmp_pubkeys(mint_info.key, &source_account.mint) { - return Err(TokenError::MintMismatch.into()); - } - - let mint = Mint::unpack(&mint_info.data.borrow_mut())?; - if expected_decimals != mint.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); - } - } - - let self_transfer = - Self::cmp_pubkeys(source_account_info.key, destination_account_info.key); - - match source_account.delegate { - COption::Some(ref delegate) if Self::cmp_pubkeys(authority_info.key, delegate) => { - Self::validate_owner( - program_id, - delegate, - authority_info, - account_info_iter.as_slice(), - )?; - if source_account.delegated_amount < amount { - return Err(TokenError::InsufficientFunds.into()); - } - if !self_transfer { - source_account.delegated_amount = source_account - .delegated_amount - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - if source_account.delegated_amount == 0 { - source_account.delegate = COption::None; - } - } - } - _ => Self::validate_owner( - program_id, - &source_account.owner, - authority_info, - account_info_iter.as_slice(), - )?, - }; - - if self_transfer || amount == 0 { - Self::check_account_owner(program_id, source_account_info)?; - Self::check_account_owner(program_id, destination_account_info)?; - } - - // This check MUST occur just before the amounts are manipulated - // to ensure self-transfers are fully validated - if self_transfer { - return Ok(()); - } - - source_account.amount = source_account - .amount - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - destination_account.amount = destination_account - .amount - .checked_add(amount) - .ok_or(TokenError::Overflow)?; - - if source_account.is_native() { - let source_starting_lamports = source_account_info.lamports(); - **source_account_info.lamports.borrow_mut() = source_starting_lamports - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - - let destination_starting_lamports = destination_account_info.lamports(); - **destination_account_info.lamports.borrow_mut() = destination_starting_lamports - .checked_add(amount) - .ok_or(TokenError::Overflow)?; - } - - Account::pack(source_account, &mut source_account_info.data.borrow_mut())?; - Account::pack( - destination_account, - &mut destination_account_info.data.borrow_mut(), - )?; - - Ok(()) - } - - /// Processes an [Approve](enum.TokenInstruction.html) instruction. - pub fn process_approve( - program_id: &Pubkey, - accounts: &[AccountInfo], - amount: u64, - expected_decimals: Option, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - - let source_account_info = next_account_info(account_info_iter)?; - - let expected_mint_info = if let Some(expected_decimals) = expected_decimals { - Some((next_account_info(account_info_iter)?, expected_decimals)) - } else { - None - }; - let delegate_info = next_account_info(account_info_iter)?; - let owner_info = next_account_info(account_info_iter)?; - - let mut source_account = Account::unpack(&source_account_info.data.borrow())?; - - if source_account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - - if let Some((mint_info, expected_decimals)) = expected_mint_info { - if !Self::cmp_pubkeys(mint_info.key, &source_account.mint) { - return Err(TokenError::MintMismatch.into()); - } - - let mint = Mint::unpack(&mint_info.data.borrow_mut())?; - if expected_decimals != mint.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); - } - } - - Self::validate_owner( - program_id, - &source_account.owner, - owner_info, - account_info_iter.as_slice(), - )?; - - source_account.delegate = COption::Some(*delegate_info.key); - source_account.delegated_amount = amount; - - Account::pack(source_account, &mut source_account_info.data.borrow_mut())?; - - Ok(()) - } - - /// Processes an [Revoke](enum.TokenInstruction.html) instruction. - pub fn process_revoke(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let source_account_info = next_account_info(account_info_iter)?; - - let mut source_account = Account::unpack(&source_account_info.data.borrow())?; - - let owner_info = next_account_info(account_info_iter)?; - - if source_account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - - Self::validate_owner( - program_id, - &source_account.owner, - owner_info, - account_info_iter.as_slice(), - )?; - - source_account.delegate = COption::None; - source_account.delegated_amount = 0; - - Account::pack(source_account, &mut source_account_info.data.borrow_mut())?; - - Ok(()) - } - - /// Processes a [SetAuthority](enum.TokenInstruction.html) instruction. - pub fn process_set_authority( - program_id: &Pubkey, - accounts: &[AccountInfo], - authority_type: AuthorityType, - new_authority: COption, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let account_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - - if account_info.data_len() == Account::get_packed_len() { - let mut account = Account::unpack(&account_info.data.borrow())?; - - if account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - - match authority_type { - AuthorityType::AccountOwner => { - Self::validate_owner( - program_id, - &account.owner, - authority_info, - account_info_iter.as_slice(), - )?; - - if let COption::Some(authority) = new_authority { - account.owner = authority; - } else { - return Err(TokenError::InvalidInstruction.into()); - } - - account.delegate = COption::None; - account.delegated_amount = 0; - - if account.is_native() { - account.close_authority = COption::None; - } - } - AuthorityType::CloseAccount => { - let authority = account.close_authority.unwrap_or(account.owner); - Self::validate_owner( - program_id, - &authority, - authority_info, - account_info_iter.as_slice(), - )?; - account.close_authority = new_authority; - } - _ => { - return Err(TokenError::AuthorityTypeNotSupported.into()); - } - } - Account::pack(account, &mut account_info.data.borrow_mut())?; - } else if account_info.data_len() == Mint::get_packed_len() { - let mut mint = Mint::unpack(&account_info.data.borrow())?; - match authority_type { - AuthorityType::MintTokens => { - // Once a mint's supply is fixed, it cannot be undone by setting a new - // mint_authority - let mint_authority = mint - .mint_authority - .ok_or(Into::::into(TokenError::FixedSupply))?; - Self::validate_owner( - program_id, - &mint_authority, - authority_info, - account_info_iter.as_slice(), - )?; - mint.mint_authority = new_authority; - } - AuthorityType::FreezeAccount => { - // Once a mint's freeze authority is disabled, it cannot be re-enabled by - // setting a new freeze_authority - let freeze_authority = mint - .freeze_authority - .ok_or(Into::::into(TokenError::MintCannotFreeze))?; - Self::validate_owner( - program_id, - &freeze_authority, - authority_info, - account_info_iter.as_slice(), - )?; - mint.freeze_authority = new_authority; - } - _ => { - return Err(TokenError::AuthorityTypeNotSupported.into()); - } - } - Mint::pack(mint, &mut account_info.data.borrow_mut())?; - } else { - return Err(ProgramError::InvalidArgument); - } - - Ok(()) - } - - /// Processes a [MintTo](enum.TokenInstruction.html) instruction. - pub fn process_mint_to( - program_id: &Pubkey, - accounts: &[AccountInfo], - amount: u64, - expected_decimals: Option, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_info = next_account_info(account_info_iter)?; - let destination_account_info = next_account_info(account_info_iter)?; - let owner_info = next_account_info(account_info_iter)?; - - let mut destination_account = Account::unpack(&destination_account_info.data.borrow())?; - if destination_account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - - if destination_account.is_native() { - return Err(TokenError::NativeNotSupported.into()); - } - if !Self::cmp_pubkeys(mint_info.key, &destination_account.mint) { - return Err(TokenError::MintMismatch.into()); - } - - let mut mint = Mint::unpack(&mint_info.data.borrow())?; - if let Some(expected_decimals) = expected_decimals { - if expected_decimals != mint.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); - } - } - - match mint.mint_authority { - COption::Some(mint_authority) => Self::validate_owner( - program_id, - &mint_authority, - owner_info, - account_info_iter.as_slice(), - )?, - COption::None => return Err(TokenError::FixedSupply.into()), - } - - if amount == 0 { - Self::check_account_owner(program_id, mint_info)?; - Self::check_account_owner(program_id, destination_account_info)?; - } - - destination_account.amount = destination_account - .amount - .checked_add(amount) - .ok_or(TokenError::Overflow)?; - - mint.supply = mint - .supply - .checked_add(amount) - .ok_or(TokenError::Overflow)?; - - Account::pack( - destination_account, - &mut destination_account_info.data.borrow_mut(), - )?; - Mint::pack(mint, &mut mint_info.data.borrow_mut())?; - - Ok(()) - } - - /// Processes a [Burn](enum.TokenInstruction.html) instruction. - pub fn process_burn( - program_id: &Pubkey, - accounts: &[AccountInfo], - amount: u64, - expected_decimals: Option, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - - let source_account_info = next_account_info(account_info_iter)?; - let mint_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - - let mut source_account = Account::unpack(&source_account_info.data.borrow())?; - let mut mint = Mint::unpack(&mint_info.data.borrow())?; - - if source_account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - if source_account.is_native() { - return Err(TokenError::NativeNotSupported.into()); - } - if source_account.amount < amount { - return Err(TokenError::InsufficientFunds.into()); - } - if !Self::cmp_pubkeys(mint_info.key, &source_account.mint) { - return Err(TokenError::MintMismatch.into()); - } - - if let Some(expected_decimals) = expected_decimals { - if expected_decimals != mint.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); - } - } - - if !source_account.is_owned_by_system_program_or_incinerator() { - match source_account.delegate { - COption::Some(ref delegate) if Self::cmp_pubkeys(authority_info.key, delegate) => { - Self::validate_owner( - program_id, - delegate, - authority_info, - account_info_iter.as_slice(), - )?; - - if source_account.delegated_amount < amount { - return Err(TokenError::InsufficientFunds.into()); - } - source_account.delegated_amount = source_account - .delegated_amount - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - if source_account.delegated_amount == 0 { - source_account.delegate = COption::None; - } - } - _ => Self::validate_owner( - program_id, - &source_account.owner, - authority_info, - account_info_iter.as_slice(), - )?, - } - } - - if amount == 0 { - Self::check_account_owner(program_id, source_account_info)?; - Self::check_account_owner(program_id, mint_info)?; - } - - source_account.amount = source_account - .amount - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - mint.supply = mint - .supply - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - - Account::pack(source_account, &mut source_account_info.data.borrow_mut())?; - Mint::pack(mint, &mut mint_info.data.borrow_mut())?; - - Ok(()) - } - - /// Processes a [CloseAccount](enum.TokenInstruction.html) instruction. - pub fn process_close_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let source_account_info = next_account_info(account_info_iter)?; - let destination_account_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - - if Self::cmp_pubkeys(source_account_info.key, destination_account_info.key) { - return Err(ProgramError::InvalidAccountData); - } - - let source_account = Account::unpack(&source_account_info.data.borrow())?; - if !source_account.is_native() && source_account.amount != 0 { - return Err(TokenError::NonNativeHasBalance.into()); - } - - let authority = source_account - .close_authority - .unwrap_or(source_account.owner); - if !source_account.is_owned_by_system_program_or_incinerator() { - Self::validate_owner( - program_id, - &authority, - authority_info, - account_info_iter.as_slice(), - )?; - } else if !solana_program::incinerator::check_id(destination_account_info.key) { - return Err(ProgramError::InvalidAccountData); - } - - let destination_starting_lamports = destination_account_info.lamports(); - **destination_account_info.lamports.borrow_mut() = destination_starting_lamports - .checked_add(source_account_info.lamports()) - .ok_or(TokenError::Overflow)?; - - **source_account_info.lamports.borrow_mut() = 0; - delete_account(source_account_info)?; - - Ok(()) - } - - /// Processes a [FreezeAccount](enum.TokenInstruction.html) or a - /// [ThawAccount](enum.TokenInstruction.html) instruction. - pub fn process_toggle_freeze_account( - program_id: &Pubkey, - accounts: &[AccountInfo], - freeze: bool, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let source_account_info = next_account_info(account_info_iter)?; - let mint_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - - let mut source_account = Account::unpack(&source_account_info.data.borrow())?; - if freeze && source_account.is_frozen() || !freeze && !source_account.is_frozen() { - return Err(TokenError::InvalidState.into()); - } - if source_account.is_native() { - return Err(TokenError::NativeNotSupported.into()); - } - if !Self::cmp_pubkeys(mint_info.key, &source_account.mint) { - return Err(TokenError::MintMismatch.into()); - } - - let mint = Mint::unpack(&mint_info.data.borrow_mut())?; - match mint.freeze_authority { - COption::Some(authority) => Self::validate_owner( - program_id, - &authority, - authority_info, - account_info_iter.as_slice(), - ), - COption::None => Err(TokenError::MintCannotFreeze.into()), - }?; - - source_account.state = if freeze { - AccountState::Frozen - } else { - AccountState::Initialized - }; - - Account::pack(source_account, &mut source_account_info.data.borrow_mut())?; - - Ok(()) - } - - /// Processes a [SyncNative](enum.TokenInstruction.html) instruction - pub fn process_sync_native(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let native_account_info = next_account_info(account_info_iter)?; - Self::check_account_owner(program_id, native_account_info)?; - - let mut native_account = Account::unpack(&native_account_info.data.borrow())?; - - if let COption::Some(rent_exempt_reserve) = native_account.is_native { - let new_amount = native_account_info - .lamports() - .checked_sub(rent_exempt_reserve) - .ok_or(TokenError::Overflow)?; - if new_amount < native_account.amount { - return Err(TokenError::InvalidState.into()); - } - native_account.amount = new_amount; - } else { - return Err(TokenError::NonNativeNotSupported.into()); - } - - Account::pack(native_account, &mut native_account_info.data.borrow_mut())?; - Ok(()) - } - - /// Processes a [GetAccountDataSize](enum.TokenInstruction.html) instruction - pub fn process_get_account_data_size( - program_id: &Pubkey, - accounts: &[AccountInfo], - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - // make sure the mint is valid - let mint_info = next_account_info(account_info_iter)?; - Self::check_account_owner(program_id, mint_info)?; - let _ = Mint::unpack(&mint_info.data.borrow()) - .map_err(|_| Into::::into(TokenError::InvalidMint))?; - set_return_data(&Account::LEN.to_le_bytes()); - Ok(()) - } - - /// Processes an [InitializeImmutableOwner](enum.TokenInstruction.html) instruction - pub fn process_initialize_immutable_owner(accounts: &[AccountInfo]) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let token_account_info = next_account_info(account_info_iter)?; - let account = Account::unpack_unchecked(&token_account_info.data.borrow())?; - if account.is_initialized() { - return Err(TokenError::AlreadyInUse.into()); - } - msg!("Please upgrade to SPL Token 2022 for immutable owner support"); - Ok(()) - } - - /// Processes an [AmountToUiAmount](enum.TokenInstruction.html) instruction - pub fn process_amount_to_ui_amount( - program_id: &Pubkey, - accounts: &[AccountInfo], - amount: u64, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_info = next_account_info(account_info_iter)?; - Self::check_account_owner(program_id, mint_info)?; - - let mint = Mint::unpack(&mint_info.data.borrow_mut()) - .map_err(|_| Into::::into(TokenError::InvalidMint))?; - let ui_amount = amount_to_ui_amount_string_trimmed(amount, mint.decimals); - - set_return_data(&ui_amount.into_bytes()); - Ok(()) - } - - /// Processes an [AmountToUiAmount](enum.TokenInstruction.html) instruction - pub fn process_ui_amount_to_amount( - program_id: &Pubkey, - accounts: &[AccountInfo], - ui_amount: &str, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_info = next_account_info(account_info_iter)?; - Self::check_account_owner(program_id, mint_info)?; - - let mint = Mint::unpack(&mint_info.data.borrow_mut()) - .map_err(|_| Into::::into(TokenError::InvalidMint))?; - let amount = try_ui_amount_into_amount(ui_amount.to_string(), mint.decimals)?; - - set_return_data(&amount.to_le_bytes()); - Ok(()) - } - - /// Processes an [Instruction](enum.Instruction.html). - pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult { - let instruction = TokenInstruction::unpack(input)?; - - match instruction { - TokenInstruction::InitializeMint { - decimals, - mint_authority, - freeze_authority, - } => { - msg!("Instruction: InitializeMint"); - Self::process_initialize_mint(accounts, decimals, mint_authority, freeze_authority) - } - TokenInstruction::InitializeMint2 { - decimals, - mint_authority, - freeze_authority, - } => { - msg!("Instruction: InitializeMint2"); - Self::process_initialize_mint2(accounts, decimals, mint_authority, freeze_authority) - } - TokenInstruction::InitializeAccount => { - msg!("Instruction: InitializeAccount"); - Self::process_initialize_account(program_id, accounts) - } - TokenInstruction::InitializeAccount2 { owner } => { - msg!("Instruction: InitializeAccount2"); - Self::process_initialize_account2(program_id, accounts, owner) - } - TokenInstruction::InitializeAccount3 { owner } => { - msg!("Instruction: InitializeAccount3"); - Self::process_initialize_account3(program_id, accounts, owner) - } - TokenInstruction::InitializeMultisig { m } => { - msg!("Instruction: InitializeMultisig"); - Self::process_initialize_multisig(accounts, m) - } - TokenInstruction::InitializeMultisig2 { m } => { - msg!("Instruction: InitializeMultisig2"); - Self::process_initialize_multisig2(accounts, m) - } - TokenInstruction::Transfer { amount } => { - msg!("Instruction: Transfer"); - Self::process_transfer(program_id, accounts, amount, None) - } - TokenInstruction::Approve { amount } => { - msg!("Instruction: Approve"); - Self::process_approve(program_id, accounts, amount, None) - } - TokenInstruction::Revoke => { - msg!("Instruction: Revoke"); - Self::process_revoke(program_id, accounts) - } - TokenInstruction::SetAuthority { - authority_type, - new_authority, - } => { - msg!("Instruction: SetAuthority"); - Self::process_set_authority(program_id, accounts, authority_type, new_authority) - } - TokenInstruction::MintTo { amount } => { - msg!("Instruction: MintTo"); - Self::process_mint_to(program_id, accounts, amount, None) - } - TokenInstruction::Burn { amount } => { - msg!("Instruction: Burn"); - Self::process_burn(program_id, accounts, amount, None) - } - TokenInstruction::CloseAccount => { - msg!("Instruction: CloseAccount"); - Self::process_close_account(program_id, accounts) - } - TokenInstruction::FreezeAccount => { - msg!("Instruction: FreezeAccount"); - Self::process_toggle_freeze_account(program_id, accounts, true) - } - TokenInstruction::ThawAccount => { - msg!("Instruction: ThawAccount"); - Self::process_toggle_freeze_account(program_id, accounts, false) - } - TokenInstruction::TransferChecked { amount, decimals } => { - msg!("Instruction: TransferChecked"); - Self::process_transfer(program_id, accounts, amount, Some(decimals)) - } - TokenInstruction::ApproveChecked { amount, decimals } => { - msg!("Instruction: ApproveChecked"); - Self::process_approve(program_id, accounts, amount, Some(decimals)) - } - TokenInstruction::MintToChecked { amount, decimals } => { - msg!("Instruction: MintToChecked"); - Self::process_mint_to(program_id, accounts, amount, Some(decimals)) - } - TokenInstruction::BurnChecked { amount, decimals } => { - msg!("Instruction: BurnChecked"); - Self::process_burn(program_id, accounts, amount, Some(decimals)) - } - TokenInstruction::SyncNative => { - msg!("Instruction: SyncNative"); - Self::process_sync_native(program_id, accounts) - } - TokenInstruction::GetAccountDataSize => { - msg!("Instruction: GetAccountDataSize"); - Self::process_get_account_data_size(program_id, accounts) - } - TokenInstruction::InitializeImmutableOwner => { - msg!("Instruction: InitializeImmutableOwner"); - Self::process_initialize_immutable_owner(accounts) - } - TokenInstruction::AmountToUiAmount { amount } => { - msg!("Instruction: AmountToUiAmount"); - Self::process_amount_to_ui_amount(program_id, accounts, amount) - } - TokenInstruction::UiAmountToAmount { ui_amount } => { - msg!("Instruction: UiAmountToAmount"); - Self::process_ui_amount_to_amount(program_id, accounts, ui_amount) - } - } - } - - /// Checks that the account is owned by the expected program - pub fn check_account_owner(program_id: &Pubkey, account_info: &AccountInfo) -> ProgramResult { - if !Self::cmp_pubkeys(program_id, account_info.owner) { - Err(ProgramError::IncorrectProgramId) - } else { - Ok(()) - } - } - - /// Checks two pubkeys for equality in a computationally cheap way using - /// `sol_memcmp` - pub fn cmp_pubkeys(a: &Pubkey, b: &Pubkey) -> bool { - sol_memcmp(a.as_ref(), b.as_ref(), PUBKEY_BYTES) == 0 - } - - /// Validates owner(s) are present - pub fn validate_owner( - program_id: &Pubkey, - expected_owner: &Pubkey, - owner_account_info: &AccountInfo, - signers: &[AccountInfo], - ) -> ProgramResult { - if !Self::cmp_pubkeys(expected_owner, owner_account_info.key) { - return Err(TokenError::OwnerMismatch.into()); - } - if Self::cmp_pubkeys(program_id, owner_account_info.owner) - && owner_account_info.data_len() == Multisig::get_packed_len() - { - let multisig = Multisig::unpack(&owner_account_info.data.borrow())?; - let mut num_signers = 0; - let mut matched = [false; MAX_SIGNERS]; - for signer in signers.iter() { - for (position, key) in multisig.signers[0..multisig.n as usize].iter().enumerate() { - if Self::cmp_pubkeys(key, signer.key) && !matched[position] { - if !signer.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - matched[position] = true; - num_signers += 1; - } - } - } - if num_signers < multisig.m { - return Err(ProgramError::MissingRequiredSignature); - } - return Ok(()); - } else if !owner_account_info.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - Ok(()) - } -} - -/// Helper function to mostly delete an account in a test environment. We could -/// potentially muck around the bytes assuming that a vec is passed in, but that -/// would be more trouble than it's worth. -#[cfg(not(target_arch = "bpf"))] -fn delete_account(account_info: &AccountInfo) -> Result<(), ProgramError> { - account_info.assign(&system_program::id()); - let mut account_data = account_info.data.borrow_mut(); - let data_len = account_data.len(); - solana_program::program_memory::sol_memset(*account_data, 0, data_len); - Ok(()) -} - -/// Helper function to totally delete an account on-chain -#[cfg(target_arch = "bpf")] -fn delete_account(account_info: &AccountInfo) -> Result<(), ProgramError> { - account_info.assign(&system_program::id()); - account_info.realloc(0, false) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::instruction::*; - use serial_test::serial; - use solana_program::{ - account_info::IntoAccountInfo, - clock::Epoch, - instruction::Instruction, - program_error::{self, PrintProgramError}, - sysvar::rent, - }; - use solana_sdk::account::{ - create_account_for_test, create_is_signer_account_infos, Account as SolanaAccount, - }; - use std::sync::{Arc, RwLock}; - - lazy_static::lazy_static! { - static ref EXPECTED_DATA: Arc>> = Arc::new(RwLock::new(Vec::new())); - } - - fn set_expected_data(expected_data: Vec) { - *EXPECTED_DATA.write().unwrap() = expected_data; - } - - struct SyscallStubs {} - impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs { - fn sol_log(&self, _message: &str) {} - - fn sol_invoke_signed( - &self, - _instruction: &Instruction, - _account_infos: &[AccountInfo], - _signers_seeds: &[&[&[u8]]], - ) -> ProgramResult { - Err(ProgramError::Custom(42)) // Not supported - } - - fn sol_get_clock_sysvar(&self, _var_addr: *mut u8) -> u64 { - program_error::UNSUPPORTED_SYSVAR - } - - fn sol_get_epoch_schedule_sysvar(&self, _var_addr: *mut u8) -> u64 { - program_error::UNSUPPORTED_SYSVAR - } - - #[allow(deprecated)] - fn sol_get_fees_sysvar(&self, _var_addr: *mut u8) -> u64 { - program_error::UNSUPPORTED_SYSVAR - } - - fn sol_get_rent_sysvar(&self, var_addr: *mut u8) -> u64 { - unsafe { - *(var_addr as *mut _ as *mut Rent) = Rent::default(); - } - solana_program::entrypoint::SUCCESS - } - - fn sol_set_return_data(&self, data: &[u8]) { - assert_eq!(&*EXPECTED_DATA.write().unwrap(), data) - } - } - - fn do_process_instruction( - instruction: Instruction, - accounts: Vec<&mut SolanaAccount>, - ) -> ProgramResult { - { - use std::sync::Once; - static ONCE: Once = Once::new(); - - ONCE.call_once(|| { - solana_sdk::program_stubs::set_syscall_stubs(Box::new(SyscallStubs {})); - }); - } - - let mut meta = instruction - .accounts - .iter() - .zip(accounts) - .map(|(account_meta, account)| (&account_meta.pubkey, account_meta.is_signer, account)) - .collect::>(); - - let account_infos = create_is_signer_account_infos(&mut meta); - Processor::process(&instruction.program_id, &account_infos, &instruction.data) - } - - fn do_process_instruction_dups( - instruction: Instruction, - account_infos: Vec, - ) -> ProgramResult { - Processor::process(&instruction.program_id, &account_infos, &instruction.data) - } - - fn return_token_error_as_program_error() -> ProgramError { - TokenError::MintMismatch.into() - } - - fn rent_sysvar() -> SolanaAccount { - create_account_for_test(&Rent::default()) - } - - fn mint_minimum_balance() -> u64 { - Rent::default().minimum_balance(Mint::get_packed_len()) - } - - fn account_minimum_balance() -> u64 { - Rent::default().minimum_balance(Account::get_packed_len()) - } - - fn multisig_minimum_balance() -> u64 { - Rent::default().minimum_balance(Multisig::get_packed_len()) - } - - #[test] - fn test_print_error() { - let error = return_token_error_as_program_error(); - error.print::(); - } - - #[test] - #[should_panic(expected = "Custom(3)")] - fn test_error_unwrap() { - Err::<(), ProgramError>(return_token_error_as_program_error()).unwrap(); - } - - #[test] - fn test_unique_account_sizes() { - assert_ne!(Mint::get_packed_len(), 0); - assert_ne!(Mint::get_packed_len(), Account::get_packed_len()); - assert_ne!(Mint::get_packed_len(), Multisig::get_packed_len()); - assert_ne!(Account::get_packed_len(), 0); - assert_ne!(Account::get_packed_len(), Multisig::get_packed_len()); - assert_ne!(Multisig::get_packed_len(), 0); - } - - #[test] - fn test_pack_unpack() { - // Mint - let check = Mint { - mint_authority: COption::Some(Pubkey::new(&[1; 32])), - supply: 42, - decimals: 7, - is_initialized: true, - freeze_authority: COption::Some(Pubkey::new(&[2; 32])), - }; - let mut packed = vec![0; Mint::get_packed_len() + 1]; - assert_eq!( - Err(ProgramError::InvalidAccountData), - Mint::pack(check, &mut packed) - ); - let mut packed = vec![0; Mint::get_packed_len() - 1]; - assert_eq!( - Err(ProgramError::InvalidAccountData), - Mint::pack(check, &mut packed) - ); - let mut packed = vec![0; Mint::get_packed_len()]; - Mint::pack(check, &mut packed).unwrap(); - let expect = vec![ - 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 42, 0, 0, 0, 0, 0, 0, 0, 7, 1, 1, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - ]; - assert_eq!(packed, expect); - let unpacked = Mint::unpack(&packed).unwrap(); - assert_eq!(unpacked, check); - - // Account - let check = Account { - mint: Pubkey::new(&[1; 32]), - owner: Pubkey::new(&[2; 32]), - amount: 3, - delegate: COption::Some(Pubkey::new(&[4; 32])), - state: AccountState::Frozen, - is_native: COption::Some(5), - delegated_amount: 6, - close_authority: COption::Some(Pubkey::new(&[7; 32])), - }; - let mut packed = vec![0; Account::get_packed_len() + 1]; - assert_eq!( - Err(ProgramError::InvalidAccountData), - Account::pack(check, &mut packed) - ); - let mut packed = vec![0; Account::get_packed_len() - 1]; - assert_eq!( - Err(ProgramError::InvalidAccountData), - Account::pack(check, &mut packed) - ); - let mut packed = vec![0; Account::get_packed_len()]; - Account::pack(check, &mut packed).unwrap(); - let expect = vec![ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 1, 0, 0, 0, 5, 0, 0, - 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - ]; - assert_eq!(packed, expect); - let unpacked = Account::unpack(&packed).unwrap(); - assert_eq!(unpacked, check); - - // Multisig - let check = Multisig { - m: 1, - n: 2, - is_initialized: true, - signers: [Pubkey::new(&[3; 32]); MAX_SIGNERS], - }; - let mut packed = vec![0; Multisig::get_packed_len() + 1]; - assert_eq!( - Err(ProgramError::InvalidAccountData), - Multisig::pack(check, &mut packed) - ); - let mut packed = vec![0; Multisig::get_packed_len() - 1]; - assert_eq!( - Err(ProgramError::InvalidAccountData), - Multisig::pack(check, &mut packed) - ); - let mut packed = vec![0; Multisig::get_packed_len()]; - Multisig::pack(check, &mut packed).unwrap(); - let expect = vec![ - 1, 2, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, - ]; - assert_eq!(packed, expect); - let unpacked = Multisig::unpack(&packed).unwrap(); - assert_eq!(unpacked, check); - } - - #[test] - fn test_initialize_mint() { - let program_id = crate::id(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = SolanaAccount::new(42, Mint::get_packed_len(), &program_id); - let mint2_key = Pubkey::new_unique(); - let mut mint2_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // mint is not rent exempt - assert_eq!( - Err(TokenError::NotRentExempt.into()), - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar] - ) - ); - - mint_account.lamports = mint_minimum_balance(); - - // create new mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create twice - assert_eq!( - Err(TokenError::AlreadyInUse.into()), - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2,).unwrap(), - vec![&mut mint_account, &mut rent_sysvar] - ) - ); - - // create another mint that can freeze - do_process_instruction( - initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), - vec![&mut mint2_account, &mut rent_sysvar], - ) - .unwrap(); - let mint = Mint::unpack_unchecked(&mint2_account.data).unwrap(); - assert_eq!(mint.freeze_authority, COption::Some(owner_key)); - } - - #[test] - fn test_initialize_mint2() { - let program_id = crate::id(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = SolanaAccount::new(42, Mint::get_packed_len(), &program_id); - let mint2_key = Pubkey::new_unique(); - let mut mint2_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - - // mint is not rent exempt - assert_eq!( - Err(TokenError::NotRentExempt.into()), - do_process_instruction( - initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account] - ) - ); - - mint_account.lamports = mint_minimum_balance(); - - // create new mint - do_process_instruction( - initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - // create twice - assert_eq!( - Err(TokenError::AlreadyInUse.into()), - do_process_instruction( - initialize_mint2(&program_id, &mint_key, &owner_key, None, 2,).unwrap(), - vec![&mut mint_account] - ) - ); - - // create another mint that can freeze - do_process_instruction( - initialize_mint2(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), - vec![&mut mint2_account], - ) - .unwrap(); - let mint = Mint::unpack_unchecked(&mint2_account.data).unwrap(); - assert_eq!(mint.freeze_authority, COption::Some(owner_key)); - } - - #[test] - fn test_initialize_mint_account() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new(42, Account::get_packed_len(), &program_id); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // account is not rent exempt - assert_eq!( - Err(TokenError::NotRentExempt.into()), - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar - ], - ) - ); - - account_account.lamports = account_minimum_balance(); - - // mint is not valid (not initialized) - assert_eq!( - Err(TokenError::InvalidMint.into()), - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar - ], - ) - ); - - // create mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // mint not owned by program - let not_program_id = Pubkey::new_unique(); - mint_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar - ], - ) - ); - mint_account.owner = program_id; - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create twice - assert_eq!( - Err(TokenError::AlreadyInUse.into()), - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar - ], - ) - ); - } - - #[test] - fn test_transfer_dups() { - let program_id = crate::id(); - let account1_key = Pubkey::new_unique(); - let mut account1_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let mut account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let mut account2_info: AccountInfo = (&account2_key, false, &mut account2_account).into(); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account3_info: AccountInfo = (&account3_key, false, &mut account3_account).into(); - let account4_key = Pubkey::new_unique(); - let mut account4_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account4_info: AccountInfo = (&account4_key, true, &mut account4_account).into(); - let multisig_key = Pubkey::new_unique(); - let mut multisig_account = SolanaAccount::new( - multisig_minimum_balance(), - Multisig::get_packed_len(), - &program_id, - ); - let multisig_info: AccountInfo = (&multisig_key, true, &mut multisig_account).into(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - // create account - do_process_instruction_dups( - initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // create another account - do_process_instruction_dups( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - account2_info.clone(), - mint_info.clone(), - owner_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // mint to account - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], - ) - .unwrap(); - - // source-owner transfer - do_process_instruction_dups( - transfer( - &program_id, - &account1_key, - &account2_key, - &account1_key, - &[], - 500, - ) - .unwrap(), - vec![ - account1_info.clone(), - account2_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // source-owner TransferChecked - do_process_instruction_dups( - transfer_checked( - &program_id, - &account1_key, - &mint_key, - &account2_key, - &account1_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account2_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // source-delegate transfer - let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.amount = 1000; - account.delegated_amount = 1000; - account.delegate = COption::Some(account1_key); - account.owner = owner_key; - Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); - - do_process_instruction_dups( - transfer( - &program_id, - &account1_key, - &account2_key, - &account1_key, - &[], - 500, - ) - .unwrap(), - vec![ - account1_info.clone(), - account2_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // source-delegate TransferChecked - do_process_instruction_dups( - transfer_checked( - &program_id, - &account1_key, - &mint_key, - &account2_key, - &account1_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account2_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // test destination-owner transfer - do_process_instruction_dups( - initialize_account(&program_id, &account3_key, &mint_key, &account2_key).unwrap(), - vec![ - account3_info.clone(), - mint_info.clone(), - account2_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account3_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account3_info.clone(), owner_info.clone()], - ) - .unwrap(); - - account1_info.is_signer = false; - account2_info.is_signer = true; - do_process_instruction_dups( - transfer( - &program_id, - &account3_key, - &account2_key, - &account2_key, - &[], - 500, - ) - .unwrap(), - vec![ - account3_info.clone(), - account2_info.clone(), - account2_info.clone(), - ], - ) - .unwrap(); - - // destination-owner TransferChecked - do_process_instruction_dups( - transfer_checked( - &program_id, - &account3_key, - &mint_key, - &account2_key, - &account2_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![ - account3_info.clone(), - mint_info.clone(), - account2_info.clone(), - account2_info.clone(), - ], - ) - .unwrap(); - - // test source-multisig signer - do_process_instruction_dups( - initialize_multisig(&program_id, &multisig_key, &[&account4_key], 1).unwrap(), - vec![ - multisig_info.clone(), - rent_info.clone(), - account4_info.clone(), - ], - ) - .unwrap(); - - do_process_instruction_dups( - initialize_account(&program_id, &account4_key, &mint_key, &multisig_key).unwrap(), - vec![ - account4_info.clone(), - mint_info.clone(), - multisig_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account4_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account4_info.clone(), owner_info.clone()], - ) - .unwrap(); - - // source-multisig-signer transfer - do_process_instruction_dups( - transfer( - &program_id, - &account4_key, - &account2_key, - &multisig_key, - &[&account4_key], - 500, - ) - .unwrap(), - vec![ - account4_info.clone(), - account2_info.clone(), - multisig_info.clone(), - account4_info.clone(), - ], - ) - .unwrap(); - - // source-multisig-signer TransferChecked - do_process_instruction_dups( - transfer_checked( - &program_id, - &account4_key, - &mint_key, - &account2_key, - &multisig_key, - &[&account4_key], - 500, - 2, - ) - .unwrap(), - vec![ - account4_info.clone(), - mint_info.clone(), - account2_info.clone(), - multisig_info.clone(), - account4_info.clone(), - ], - ) - .unwrap(); - } - - #[test] - fn test_transfer() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let delegate_key = Pubkey::new_unique(); - let mut delegate_account = SolanaAccount::default(); - let mismatch_key = Pubkey::new_unique(); - let mut mismatch_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint2_key = Pubkey::new_unique(); - let mut rent_sysvar = rent_sysvar(); - - // create mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account3_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create mismatch account - do_process_instruction( - initialize_account(&program_id, &mismatch_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut mismatch_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); - account.mint = mint2_key; - Account::pack(account, &mut mismatch_account.data).unwrap(); - - // mint to account - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - // missing signer - let mut instruction = transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 1000, - ) - .unwrap(); - instruction.accounts[2].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - do_process_instruction( - instruction, - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - ); - - // mismatch mint - assert_eq!( - Err(TokenError::MintMismatch.into()), - do_process_instruction( - transfer( - &program_id, - &account_key, - &mismatch_key, - &owner_key, - &[], - 1000 - ) - .unwrap(), - vec![ - &mut account_account, - &mut mismatch_account, - &mut owner_account, - ], - ) - ); - - // missing owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &owner2_key, - &[], - 1000 - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner2_account, - ], - ) - ); - - // account not owned by program - let not_program_id = Pubkey::new_unique(); - account_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - transfer(&program_id, &account_key, &account2_key, &owner_key, &[], 0,).unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner2_account, - ], - ) - ); - account_account.owner = program_id; - - // account 2 not owned by program - let not_program_id = Pubkey::new_unique(); - account2_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - transfer(&program_id, &account_key, &account2_key, &owner_key, &[], 0,).unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner2_account, - ], - ) - ); - account2_account.owner = program_id; - - // transfer - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 1000, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - .unwrap(); - - // insufficient funds - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - transfer(&program_id, &account_key, &account2_key, &owner_key, &[], 1).unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - ); - - // transfer half back - do_process_instruction( - transfer( - &program_id, - &account2_key, - &account_key, - &owner_key, - &[], - 500, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut account_account, - &mut owner_account, - ], - ) - .unwrap(); - - // incorrect decimals - assert_eq!( - Err(TokenError::MintDecimalsMismatch.into()), - do_process_instruction( - transfer_checked( - &program_id, - &account2_key, - &mint_key, - &account_key, - &owner_key, - &[], - 1, - 10 // <-- incorrect decimals - ) - .unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut account_account, - &mut owner_account, - ], - ) - ); - - // incorrect mint - assert_eq!( - Err(TokenError::MintMismatch.into()), - do_process_instruction( - transfer_checked( - &program_id, - &account2_key, - &account3_key, // <-- incorrect mint - &account_key, - &owner_key, - &[], - 1, - 2 - ) - .unwrap(), - vec![ - &mut account2_account, - &mut account3_account, // <-- incorrect mint - &mut account_account, - &mut owner_account, - ], - ) - ); - // transfer rest with explicit decimals - do_process_instruction( - transfer_checked( - &program_id, - &account2_key, - &mint_key, - &account_key, - &owner_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut account_account, - &mut owner_account, - ], - ) - .unwrap(); - - // insufficient funds - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - transfer(&program_id, &account2_key, &account_key, &owner_key, &[], 1).unwrap(), - vec![ - &mut account2_account, - &mut account_account, - &mut owner_account, - ], - ) - ); - - // approve delegate - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 100, - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - .unwrap(); - - // transfer via delegate - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &delegate_key, - &[], - 100, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut delegate_account, - ], - ) - .unwrap(); - - // insufficient funds approved via delegate - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &delegate_key, - &[], - 100 - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut delegate_account, - ], - ) - ); - - // transfer rest - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 900, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - .unwrap(); - - // approve delegate - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 100, - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - .unwrap(); - - // insufficient funds in source account via delegate - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &delegate_key, - &[], - 100 - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut delegate_account, - ], - ) - ); - } - - #[test] - fn test_self_transfer() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let delegate_key = Pubkey::new_unique(); - let mut delegate_account = SolanaAccount::default(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account3_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // mint to account - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - let account_info = (&account_key, false, &mut account_account).into_account_info(); - let account3_info = (&account3_key, false, &mut account3_account).into_account_info(); - let delegate_info = (&delegate_key, true, &mut delegate_account).into_account_info(); - let owner_info = (&owner_key, true, &mut owner_account).into_account_info(); - let owner2_info = (&owner2_key, true, &mut owner2_account).into_account_info(); - let mint_info = (&mint_key, false, &mut mint_account).into_account_info(); - - // transfer - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - owner_info.key, - &[], - 1000, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); - - // transfer checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner_info.key, - &[], - 1000, - 2, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); - - // missing signer - let mut owner_no_sign_info = owner_info.clone(); - let mut instruction = transfer( - &program_id, - account_info.key, - account_info.key, - owner_no_sign_info.key, - &[], - 1000, - ) - .unwrap(); - instruction.accounts[2].is_signer = false; - owner_no_sign_info.is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - owner_no_sign_info.clone(), - ], - &instruction.data, - ) - ); - - // missing signer checked - let mut instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner_no_sign_info.key, - &[], - 1000, - 2, - ) - .unwrap(); - instruction.accounts[3].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner_no_sign_info, - ], - &instruction.data, - ) - ); - - // missing owner - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - owner2_info.key, - &[], - 1000, - ) - .unwrap(); - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - owner2_info.clone(), - ], - &instruction.data, - ) - ); - - // missing owner checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner2_info.key, - &[], - 1000, - 2, - ) - .unwrap(); - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner2_info.clone(), - ], - &instruction.data, - ) - ); - - // insufficient funds - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - owner_info.key, - &[], - 1001, - ) - .unwrap(); - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - - // insufficient funds checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner_info.key, - &[], - 1001, - 2, - ) - .unwrap(); - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - - // incorrect decimals - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner_info.key, - &[], - 1, - 10, // <-- incorrect decimals - ) - .unwrap(); - assert_eq!( - Err(TokenError::MintDecimalsMismatch.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - - // incorrect mint - let instruction = transfer_checked( - &program_id, - account_info.key, - account3_info.key, // <-- incorrect mint - account_info.key, - owner_info.key, - &[], - 1, - 2, - ) - .unwrap(); - assert_eq!( - Err(TokenError::MintMismatch.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account3_info.clone(), // <-- incorrect mint - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - - // approve delegate - let instruction = approve( - &program_id, - account_info.key, - delegate_info.key, - owner_info.key, - &[], - 100, - ) - .unwrap(); - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - delegate_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - .unwrap(); - - // delegate transfer - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - delegate_info.key, - &[], - 100, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - delegate_info.clone(), - ], - &instruction.data, - ) - ); - // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); - assert_eq!(account.delegated_amount, 100); - - // delegate transfer checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - delegate_info.key, - &[], - 100, - 2, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - delegate_info.clone(), - ], - &instruction.data, - ) - ); - // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); - assert_eq!(account.delegated_amount, 100); - - // delegate insufficient funds - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - delegate_info.key, - &[], - 101, - ) - .unwrap(); - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - delegate_info.clone(), - ], - &instruction.data, - ) - ); - - // delegate insufficient funds checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - delegate_info.key, - &[], - 101, - 2, - ) - .unwrap(); - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - delegate_info.clone(), - ], - &instruction.data, - ) - ); - - // owner transfer with delegate assigned - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - owner_info.key, - &[], - 1000, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); - - // owner transfer with delegate assigned checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner_info.key, - &[], - 1000, - 2, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); - } - - #[test] - fn test_mintable_token_with_zero_supply() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create mint-able token with zero supply - let decimals = 2; - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, decimals).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!( - mint, - Mint { - mint_authority: COption::Some(owner_key), - supply: 0, - decimals, - is_initialized: true, - freeze_authority: COption::None, - } - ); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // mint to - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - let _ = Mint::unpack(&mint_account.data).unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 42); - - // mint to 2, with incorrect decimals - assert_eq!( - Err(TokenError::MintDecimalsMismatch.into()), - do_process_instruction( - mint_to_checked( - &program_id, - &mint_key, - &account_key, - &owner_key, - &[], - 42, - decimals + 1 - ) - .unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - ); - - let _ = Mint::unpack(&mint_account.data).unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 42); - - // mint to 2 - do_process_instruction( - mint_to_checked( - &program_id, - &mint_key, - &account_key, - &owner_key, - &[], - 42, - decimals, - ) - .unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - let _ = Mint::unpack(&mint_account.data).unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 84); - } - - #[test] - fn test_approve_dups() { - let program_id = crate::id(); - let account1_key = Pubkey::new_unique(); - let mut account1_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_info: AccountInfo = (&account2_key, false, &mut account2_account).into(); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account3_info: AccountInfo = (&account3_key, true, &mut account3_account).into(); - let multisig_key = Pubkey::new_unique(); - let mut multisig_account = SolanaAccount::new( - multisig_minimum_balance(), - Multisig::get_packed_len(), - &program_id, - ); - let multisig_info: AccountInfo = (&multisig_key, true, &mut multisig_account).into(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - // create account - do_process_instruction_dups( - initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // create another account - do_process_instruction_dups( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - account2_info.clone(), - mint_info.clone(), - owner_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // mint to account - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], - ) - .unwrap(); - - // source-owner approve - do_process_instruction_dups( - approve( - &program_id, - &account1_key, - &account2_key, - &account1_key, - &[], - 500, - ) - .unwrap(), - vec![ - account1_info.clone(), - account2_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // source-owner approve_checked - do_process_instruction_dups( - approve_checked( - &program_id, - &account1_key, - &mint_key, - &account2_key, - &account1_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account2_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // source-owner revoke - do_process_instruction_dups( - revoke(&program_id, &account1_key, &account1_key, &[]).unwrap(), - vec![account1_info.clone(), account1_info.clone()], - ) - .unwrap(); - - // test source-multisig signer - do_process_instruction_dups( - initialize_multisig(&program_id, &multisig_key, &[&account3_key], 1).unwrap(), - vec![ - multisig_info.clone(), - rent_info.clone(), - account3_info.clone(), - ], - ) - .unwrap(); - - do_process_instruction_dups( - initialize_account(&program_id, &account3_key, &mint_key, &multisig_key).unwrap(), - vec![ - account3_info.clone(), - mint_info.clone(), - multisig_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account3_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account3_info.clone(), owner_info.clone()], - ) - .unwrap(); - - // source-multisig-signer approve - do_process_instruction_dups( - approve( - &program_id, - &account3_key, - &account2_key, - &multisig_key, - &[&account3_key], - 500, - ) - .unwrap(), - vec![ - account3_info.clone(), - account2_info.clone(), - multisig_info.clone(), - account3_info.clone(), - ], - ) - .unwrap(); - - // source-multisig-signer approve_checked - do_process_instruction_dups( - approve_checked( - &program_id, - &account3_key, - &mint_key, - &account2_key, - &multisig_key, - &[&account3_key], - 500, - 2, - ) - .unwrap(), - vec![ - account3_info.clone(), - mint_info.clone(), - account2_info.clone(), - multisig_info.clone(), - account3_info.clone(), - ], - ) - .unwrap(); - - // source-owner multisig-signer - do_process_instruction_dups( - revoke(&program_id, &account3_key, &multisig_key, &[&account3_key]).unwrap(), - vec![ - account3_info.clone(), - multisig_info.clone(), - account3_info.clone(), - ], - ) - .unwrap(); - } - - #[test] - fn test_approve() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let delegate_key = Pubkey::new_unique(); - let mut delegate_account = SolanaAccount::default(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // mint to account - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - // missing signer - let mut instruction = approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 100, - ) - .unwrap(); - instruction.accounts[2].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - do_process_instruction( - instruction, - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - ); - - // no owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner2_key, - &[], - 100 - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner2_account, - ], - ) - ); - - // approve delegate - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 100, - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - .unwrap(); - - // approve delegate 2, with incorrect decimals - assert_eq!( - Err(TokenError::MintDecimalsMismatch.into()), - do_process_instruction( - approve_checked( - &program_id, - &account_key, - &mint_key, - &delegate_key, - &owner_key, - &[], - 100, - 0 // <-- incorrect decimals - ) - .unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut delegate_account, - &mut owner_account, - ], - ) - ); - - // approve delegate 2, with incorrect mint - assert_eq!( - Err(TokenError::MintMismatch.into()), - do_process_instruction( - approve_checked( - &program_id, - &account_key, - &account2_key, // <-- bad mint - &delegate_key, - &owner_key, - &[], - 100, - 0 - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, // <-- bad mint - &mut delegate_account, - &mut owner_account, - ], - ) - ); - - // approve delegate 2 - do_process_instruction( - approve_checked( - &program_id, - &account_key, - &mint_key, - &delegate_key, - &owner_key, - &[], - 100, - 2, - ) - .unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut delegate_account, - &mut owner_account, - ], - ) - .unwrap(); - - // revoke delegate - do_process_instruction( - revoke(&program_id, &account_key, &owner_key, &[]).unwrap(), - vec![&mut account_account, &mut owner_account], - ) - .unwrap(); - } - - #[test] - fn test_set_authority_dups() { - let program_id = crate::id(); - let account1_key = Pubkey::new_unique(); - let mut account1_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &mint_key, Some(&mint_key), 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - // create account - do_process_instruction_dups( - initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // set mint_authority when currently self - do_process_instruction_dups( - set_authority( - &program_id, - &mint_key, - Some(&owner_key), - AuthorityType::MintTokens, - &mint_key, - &[], - ) - .unwrap(), - vec![mint_info.clone(), mint_info.clone()], - ) - .unwrap(); - - // set freeze_authority when currently self - do_process_instruction_dups( - set_authority( - &program_id, - &mint_key, - Some(&owner_key), - AuthorityType::FreezeAccount, - &mint_key, - &[], - ) - .unwrap(), - vec![mint_info.clone(), mint_info.clone()], - ) - .unwrap(); - - // set account owner when currently self - do_process_instruction_dups( - set_authority( - &program_id, - &account1_key, - Some(&owner_key), - AuthorityType::AccountOwner, - &account1_key, - &[], - ) - .unwrap(), - vec![account1_info.clone(), account1_info.clone()], - ) - .unwrap(); - - // set close_authority when currently self - let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.close_authority = COption::Some(account1_key); - Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); - - do_process_instruction_dups( - set_authority( - &program_id, - &account1_key, - Some(&owner_key), - AuthorityType::CloseAccount, - &account1_key, - &[], - ) - .unwrap(), - vec![account1_info.clone(), account1_info.clone()], - ) - .unwrap(); - } - - #[test] - fn test_set_authority() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let owner3_key = Pubkey::new_unique(); - let mut owner3_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint2_key = Pubkey::new_unique(); - let mut mint2_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create new mint with owner - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create mint with owner and freeze_authority - do_process_instruction( - initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), - vec![&mut mint2_account, &mut rent_sysvar], - ) - .unwrap(); - - // invalid account - assert_eq!( - Err(ProgramError::UninitializedAccount), - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner2_key), - AuthorityType::AccountOwner, - &owner_key, - &[] - ) - .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - ); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint2_key, &owner_key).unwrap(), - vec![ - &mut account2_account, - &mut mint2_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // missing owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner_key), - AuthorityType::AccountOwner, - &owner2_key, - &[] - ) - .unwrap(), - vec![&mut account_account, &mut owner2_account], - ) - ); - - // owner did not sign - let mut instruction = set_authority( - &program_id, - &account_key, - Some(&owner2_key), - AuthorityType::AccountOwner, - &owner_key, - &[], - ) - .unwrap(); - instruction.accounts[1].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - do_process_instruction(instruction, vec![&mut account_account, &mut owner_account,],) - ); - - // wrong authority type - assert_eq!( - Err(TokenError::AuthorityTypeNotSupported.into()), - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner2_key), - AuthorityType::FreezeAccount, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - ); - - // account owner may not be set to None - assert_eq!( - Err(TokenError::InvalidInstruction.into()), - do_process_instruction( - set_authority( - &program_id, - &account_key, - None, - AuthorityType::AccountOwner, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - ); - - // set delegate - do_process_instruction( - approve( - &program_id, - &account_key, - &owner2_key, - &owner_key, - &[], - u64::MAX, - ) - .unwrap(), - vec![ - &mut account_account, - &mut owner2_account, - &mut owner_account, - ], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.delegate, COption::Some(owner2_key)); - assert_eq!(account.delegated_amount, u64::MAX); - - // set owner - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner3_key), - AuthorityType::AccountOwner, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - .unwrap(); - - // check delegate cleared - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.delegate, COption::None); - assert_eq!(account.delegated_amount, 0); - - // set owner without existing delegate - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner2_key), - AuthorityType::AccountOwner, - &owner3_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner3_account], - ) - .unwrap(); - - // set close_authority - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner2_key), - AuthorityType::CloseAccount, - &owner2_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner2_account], - ) - .unwrap(); - - // close_authority may be set to None - do_process_instruction( - set_authority( - &program_id, - &account_key, - None, - AuthorityType::CloseAccount, - &owner2_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner2_account], - ) - .unwrap(); - - // wrong owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - set_authority( - &program_id, - &mint_key, - Some(&owner3_key), - AuthorityType::MintTokens, - &owner2_key, - &[] - ) - .unwrap(), - vec![&mut mint_account, &mut owner2_account], - ) - ); - - // owner did not sign - let mut instruction = set_authority( - &program_id, - &mint_key, - Some(&owner2_key), - AuthorityType::MintTokens, - &owner_key, - &[], - ) - .unwrap(); - instruction.accounts[1].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - do_process_instruction(instruction, vec![&mut mint_account, &mut owner_account],) - ); - - // cannot freeze - assert_eq!( - Err(TokenError::MintCannotFreeze.into()), - do_process_instruction( - set_authority( - &program_id, - &mint_key, - Some(&owner2_key), - AuthorityType::FreezeAccount, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut mint_account, &mut owner_account], - ) - ); - - // set owner - do_process_instruction( - set_authority( - &program_id, - &mint_key, - Some(&owner2_key), - AuthorityType::MintTokens, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut mint_account, &mut owner_account], - ) - .unwrap(); - - // set owner to None - do_process_instruction( - set_authority( - &program_id, - &mint_key, - None, - AuthorityType::MintTokens, - &owner2_key, - &[], - ) - .unwrap(), - vec![&mut mint_account, &mut owner2_account], - ) - .unwrap(); - - // test unsetting mint_authority is one-way operation - assert_eq!( - Err(TokenError::FixedSupply.into()), - do_process_instruction( - set_authority( - &program_id, - &mint2_key, - Some(&owner2_key), - AuthorityType::MintTokens, - &owner_key, - &[] - ) - .unwrap(), - vec![&mut mint_account, &mut owner_account], - ) - ); - - // set freeze_authority - do_process_instruction( - set_authority( - &program_id, - &mint2_key, - Some(&owner2_key), - AuthorityType::FreezeAccount, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut mint2_account, &mut owner_account], - ) - .unwrap(); - - // test unsetting freeze_authority is one-way operation - do_process_instruction( - set_authority( - &program_id, - &mint2_key, - None, - AuthorityType::FreezeAccount, - &owner2_key, - &[], - ) - .unwrap(), - vec![&mut mint2_account, &mut owner2_account], - ) - .unwrap(); - - assert_eq!( - Err(TokenError::MintCannotFreeze.into()), - do_process_instruction( - set_authority( - &program_id, - &mint2_key, - Some(&owner2_key), - AuthorityType::FreezeAccount, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut mint2_account, &mut owner2_account], - ) - ); - } - - #[test] - fn test_mint_to_dups() { - let program_id = crate::id(); - let account1_key = Pubkey::new_unique(); - let mut account1_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &mint_key, None, 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - // create account - do_process_instruction_dups( - initialize_account(&program_id, &account1_key, &mint_key, &owner_key).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - owner_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // mint_to when mint_authority is self - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account1_key, &mint_key, &[], 42).unwrap(), - vec![mint_info.clone(), account1_info.clone(), mint_info.clone()], - ) - .unwrap(); - - // mint_to_checked when mint_authority is self - do_process_instruction_dups( - mint_to_checked(&program_id, &mint_key, &account1_key, &mint_key, &[], 42, 2).unwrap(), - vec![mint_info.clone(), account1_info.clone(), mint_info.clone()], - ) - .unwrap(); - - // mint_to when mint_authority is account owner - let mut mint = Mint::unpack_unchecked(&mint_info.data.borrow()).unwrap(); - mint.mint_authority = COption::Some(account1_key); - Mint::pack(mint, &mut mint_info.data.borrow_mut()).unwrap(); - do_process_instruction_dups( - mint_to( - &program_id, - &mint_key, - &account1_key, - &account1_key, - &[], - 42, - ) - .unwrap(), - vec![ - mint_info.clone(), - account1_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // mint_to_checked when mint_authority is account owner - do_process_instruction_dups( - mint_to( - &program_id, - &mint_key, - &account1_key, - &account1_key, - &[], - 42, - ) - .unwrap(), - vec![ - mint_info.clone(), - account1_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - } - - #[test] - fn test_mint_to() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let mismatch_key = Pubkey::new_unique(); - let mut mismatch_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint2_key = Pubkey::new_unique(); - let uninitialized_key = Pubkey::new_unique(); - let mut uninitialized_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let mut rent_sysvar = rent_sysvar(); - - // create new mint with owner - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account3_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create mismatch account - do_process_instruction( - initialize_account(&program_id, &mismatch_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut mismatch_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); - account.mint = mint2_key; - Account::pack(account, &mut mismatch_account.data).unwrap(); - - // mint to - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!(mint.supply, 42); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 42); - - // mint to another account to test supply accumulation - do_process_instruction( - mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(), - vec![&mut mint_account, &mut account2_account, &mut owner_account], - ) - .unwrap(); - - let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!(mint.supply, 84); - let account = Account::unpack_unchecked(&account2_account.data).unwrap(); - assert_eq!(account.amount, 42); - - // missing signer - let mut instruction = - mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(); - instruction.accounts[2].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - do_process_instruction( - instruction, - vec![&mut mint_account, &mut account2_account, &mut owner_account], - ) - ); - - // mismatch account - assert_eq!( - Err(TokenError::MintMismatch.into()), - do_process_instruction( - mint_to(&program_id, &mint_key, &mismatch_key, &owner_key, &[], 42).unwrap(), - vec![&mut mint_account, &mut mismatch_account, &mut owner_account], - ) - ); - - // missing owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - mint_to(&program_id, &mint_key, &account2_key, &owner2_key, &[], 42).unwrap(), - vec![ - &mut mint_account, - &mut account2_account, - &mut owner2_account, - ], - ) - ); - - // mint not owned by program - let not_program_id = Pubkey::new_unique(); - mint_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 0).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - ); - mint_account.owner = program_id; - - // account not owned by program - let not_program_id = Pubkey::new_unique(); - account_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 0).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - ); - account_account.owner = program_id; - - // uninitialized destination account - assert_eq!( - Err(ProgramError::UninitializedAccount), - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &uninitialized_key, - &owner_key, - &[], - 42 - ) - .unwrap(), - vec![ - &mut mint_account, - &mut uninitialized_account, - &mut owner_account, - ], - ) - ); - - // unset mint_authority and test minting fails - do_process_instruction( - set_authority( - &program_id, - &mint_key, - None, - AuthorityType::MintTokens, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut mint_account, &mut owner_account], - ) - .unwrap(); - assert_eq!( - Err(TokenError::FixedSupply.into()), - do_process_instruction( - mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(), - vec![&mut mint_account, &mut account2_account, &mut owner_account], - ) - ); - } - - #[test] - fn test_burn_dups() { - let program_id = crate::id(); - let account1_key = Pubkey::new_unique(); - let mut account1_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - // create account - do_process_instruction_dups( - initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // mint to account - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], - ) - .unwrap(); - - // source-owner burn - do_process_instruction_dups( - burn( - &program_id, - &mint_key, - &account1_key, - &account1_key, - &[], - 500, - ) - .unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // source-owner burn_checked - do_process_instruction_dups( - burn_checked( - &program_id, - &account1_key, - &mint_key, - &account1_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // mint-owner burn - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], - ) - .unwrap(); - let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.owner = mint_key; - Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); - do_process_instruction_dups( - burn(&program_id, &account1_key, &mint_key, &mint_key, &[], 500).unwrap(), - vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], - ) - .unwrap(); - - // mint-owner burn_checked - do_process_instruction_dups( - burn_checked( - &program_id, - &account1_key, - &mint_key, - &mint_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], - ) - .unwrap(); - - // source-delegate burn - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], - ) - .unwrap(); - let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.delegated_amount = 1000; - account.delegate = COption::Some(account1_key); - account.owner = owner_key; - Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); - do_process_instruction_dups( - burn( - &program_id, - &account1_key, - &mint_key, - &account1_key, - &[], - 500, - ) - .unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // source-delegate burn_checked - do_process_instruction_dups( - burn_checked( - &program_id, - &account1_key, - &mint_key, - &account1_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // mint-delegate burn - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], - ) - .unwrap(); - let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.delegated_amount = 1000; - account.delegate = COption::Some(mint_key); - account.owner = owner_key; - Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); - do_process_instruction_dups( - burn(&program_id, &account1_key, &mint_key, &mint_key, &[], 500).unwrap(), - vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], - ) - .unwrap(); - - // mint-delegate burn_checked - do_process_instruction_dups( - burn_checked( - &program_id, - &account1_key, - &mint_key, - &mint_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], - ) - .unwrap(); - } - - #[test] - fn test_burn() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let delegate_key = Pubkey::new_unique(); - let mut delegate_account = SolanaAccount::default(); - let mismatch_key = Pubkey::new_unique(); - let mut mismatch_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint2_key = Pubkey::new_unique(); - let mut rent_sysvar = rent_sysvar(); - - // create new mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account3_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create mismatch account - do_process_instruction( - initialize_account(&program_id, &mismatch_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut mismatch_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // mint to account - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - // mint to mismatch account and change mint key - do_process_instruction( - mint_to(&program_id, &mint_key, &mismatch_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut mismatch_account, &mut owner_account], - ) - .unwrap(); - let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); - account.mint = mint2_key; - Account::pack(account, &mut mismatch_account.data).unwrap(); - - // missing signer - let mut instruction = - burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 42).unwrap(); - instruction.accounts[1].is_signer = false; - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - instruction, - vec![ - &mut account_account, - &mut mint_account, - &mut delegate_account - ], - ) - ); - - // missing owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &owner2_key, &[], 42).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner2_account], - ) - ); - - // account not owned by program - let not_program_id = Pubkey::new_unique(); - account_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &owner_key, &[], 0).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - account_account.owner = program_id; - - // mint not owned by program - let not_program_id = Pubkey::new_unique(); - mint_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &owner_key, &[], 0).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - mint_account.owner = program_id; - - // mint mismatch - assert_eq!( - Err(TokenError::MintMismatch.into()), - do_process_instruction( - burn(&program_id, &mismatch_key, &mint_key, &owner_key, &[], 42).unwrap(), - vec![&mut mismatch_account, &mut mint_account, &mut owner_account], - ) - ); - - // burn - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &owner_key, &[], 21).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - - // burn_checked, with incorrect decimals - assert_eq!( - Err(TokenError::MintDecimalsMismatch.into()), - do_process_instruction( - burn_checked(&program_id, &account_key, &mint_key, &owner_key, &[], 21, 3).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - - // burn_checked - do_process_instruction( - burn_checked(&program_id, &account_key, &mint_key, &owner_key, &[], 21, 2).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - - let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!(mint.supply, 2000 - 42); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 1000 - 42); - - // insufficient funds - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - burn( - &program_id, - &account_key, - &mint_key, - &owner_key, - &[], - 100_000_000 - ) - .unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - - // approve delegate - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 84, - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - .unwrap(); - - // not a delegate of source account - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - burn( - &program_id, - &account_key, - &mint_key, - &owner_key, - &[], - 100_000_000 - ) - .unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - - // burn via delegate - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 84).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut delegate_account, - ], - ) - .unwrap(); - - // match - let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!(mint.supply, 2000 - 42 - 84); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 1000 - 42 - 84); - - // insufficient funds approved via delegate - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - burn( - &program_id, - &account_key, - &mint_key, - &delegate_key, - &[], - 100 - ) - .unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut delegate_account - ], - ) - ); - } - - #[test] - fn test_burn_and_close_system_and_incinerator_tokens() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let incinerator_account_key = Pubkey::new_unique(); - let mut incinerator_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let system_account_key = Pubkey::new_unique(); - let mut system_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let recipient_key = Pubkey::new_unique(); - let mut recipient_account = SolanaAccount::default(); - let mut mock_incinerator_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - - // create new mint - do_process_instruction( - initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account3(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut mint_account], - ) - .unwrap(); - - // create incinerator- and system-owned accounts - do_process_instruction( - initialize_account3( - &program_id, - &incinerator_account_key, - &mint_key, - &solana_program::incinerator::id(), - ) - .unwrap(), - vec![&mut incinerator_account, &mut mint_account], - ) - .unwrap(); - do_process_instruction( - initialize_account3( - &program_id, - &system_account_key, - &mint_key, - &solana_program::system_program::id(), - ) - .unwrap(), - vec![&mut system_account, &mut mint_account], - ) - .unwrap(); - - // mint to account - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - // transfer half to incinerator, half to system program - do_process_instruction( - transfer( - &program_id, - &account_key, - &incinerator_account_key, - &owner_key, - &[], - 500, - ) - .unwrap(), - vec![ - &mut account_account, - &mut incinerator_account, - &mut owner_account, - ], - ) - .unwrap(); - do_process_instruction( - transfer( - &program_id, - &account_key, - &system_account_key, - &owner_key, - &[], - 500, - ) - .unwrap(), - vec![ - &mut account_account, - &mut system_account, - &mut owner_account, - ], - ) - .unwrap(); - - // close with balance fails - assert_eq!( - Err(TokenError::NonNativeHasBalance.into()), - do_process_instruction( - close_account( - &program_id, - &incinerator_account_key, - &solana_program::incinerator::id(), - &owner_key, - &[] - ) - .unwrap(), - vec![ - &mut incinerator_account, - &mut mock_incinerator_account, - &mut owner_account, - ], - ) - ); - assert_eq!( - Err(TokenError::NonNativeHasBalance.into()), - do_process_instruction( - close_account( - &program_id, - &system_account_key, - &solana_program::incinerator::id(), - &owner_key, - &[] - ) - .unwrap(), - vec![ - &mut system_account, - &mut mock_incinerator_account, - &mut owner_account, - ], - ) - ); - - // anyone can burn - do_process_instruction( - burn( - &program_id, - &incinerator_account_key, - &mint_key, - &recipient_key, - &[], - 500, - ) - .unwrap(), - vec![ - &mut incinerator_account, - &mut mint_account, - &mut recipient_account, - ], - ) - .unwrap(); - do_process_instruction( - burn( - &program_id, - &system_account_key, - &mint_key, - &recipient_key, - &[], - 500, - ) - .unwrap(), - vec![ - &mut system_account, - &mut mint_account, - &mut recipient_account, - ], - ) - .unwrap(); - - // closing fails if destination is not the incinerator - assert_eq!( - Err(ProgramError::InvalidAccountData), - do_process_instruction( - close_account( - &program_id, - &incinerator_account_key, - &recipient_key, - &owner_key, - &[] - ) - .unwrap(), - vec![ - &mut incinerator_account, - &mut recipient_account, - &mut owner_account, - ], - ) - ); - assert_eq!( - Err(ProgramError::InvalidAccountData), - do_process_instruction( - close_account( - &program_id, - &system_account_key, - &recipient_key, - &owner_key, - &[] - ) - .unwrap(), - vec![ - &mut system_account, - &mut recipient_account, - &mut owner_account, - ], - ) - ); - - // closing succeeds with incinerator recipient - do_process_instruction( - close_account( - &program_id, - &incinerator_account_key, - &solana_program::incinerator::id(), - &owner_key, - &[], - ) - .unwrap(), - vec![ - &mut incinerator_account, - &mut mock_incinerator_account, - &mut owner_account, - ], - ) - .unwrap(); - - do_process_instruction( - close_account( - &program_id, - &system_account_key, - &solana_program::incinerator::id(), - &owner_key, - &[], - ) - .unwrap(), - vec![ - &mut system_account, - &mut mock_incinerator_account, - &mut owner_account, - ], - ) - .unwrap(); - } - - #[test] - fn test_multisig() { - let program_id = crate::id(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let account_key = Pubkey::new_unique(); - let mut account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let multisig_key = Pubkey::new_unique(); - let mut multisig_account = SolanaAccount::new(42, Multisig::get_packed_len(), &program_id); - let multisig_delegate_key = Pubkey::new_unique(); - let mut multisig_delegate_account = SolanaAccount::new( - multisig_minimum_balance(), - Multisig::get_packed_len(), - &program_id, - ); - let signer_keys = vec![Pubkey::new_unique(); MAX_SIGNERS]; - let signer_key_refs: Vec<&Pubkey> = signer_keys.iter().collect(); - let mut signer_accounts = vec![SolanaAccount::new(0, 0, &program_id); MAX_SIGNERS]; - let mut rent_sysvar = rent_sysvar(); - - // multisig is not rent exempt - let account_info_iter = &mut signer_accounts.iter_mut(); - assert_eq!( - Err(TokenError::NotRentExempt.into()), - do_process_instruction( - initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), - vec![ - &mut multisig_account, - &mut rent_sysvar, - account_info_iter.next().unwrap(), - ], - ) - ); - - multisig_account.lamports = multisig_minimum_balance(); - let mut multisig_account2 = multisig_account.clone(); - - // single signer - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), - vec![ - &mut multisig_account, - &mut rent_sysvar, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // single signer using `initialize_multisig2` - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - initialize_multisig2(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), - vec![&mut multisig_account2, account_info_iter.next().unwrap()], - ) - .unwrap(); - - // multiple signer - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - initialize_multisig( - &program_id, - &multisig_delegate_key, - &signer_key_refs, - MAX_SIGNERS as u8, - ) - .unwrap(), - vec![ - &mut multisig_delegate_account, - &mut rent_sysvar, - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // create new mint with multisig owner - do_process_instruction( - initialize_mint(&program_id, &mint_key, &multisig_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account with multisig owner - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &multisig_key).unwrap(), - vec![ - &mut account, - &mut mint_account, - &mut multisig_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account with multisig owner - do_process_instruction( - initialize_account( - &program_id, - &account2_key, - &mint_key, - &multisig_delegate_key, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut multisig_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // mint to account - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account_key, - &multisig_key, - &[&signer_keys[0]], - 1000, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // approve - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - approve( - &program_id, - &account_key, - &multisig_delegate_key, - &multisig_key, - &[&signer_keys[0]], - 100, - ) - .unwrap(), - vec![ - &mut account, - &mut multisig_delegate_account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // transfer - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &multisig_key, - &[&signer_keys[0]], - 42, - ) - .unwrap(), - vec![ - &mut account, - &mut account2_account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // transfer via delegate - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &multisig_delegate_key, - &signer_key_refs, - 42, - ) - .unwrap(), - vec![ - &mut account, - &mut account2_account, - &mut multisig_delegate_account, - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // mint to - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account2_key, - &multisig_key, - &[&signer_keys[0]], - 42, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account2_account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // burn - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - burn( - &program_id, - &account_key, - &mint_key, - &multisig_key, - &[&signer_keys[0]], - 42, - ) - .unwrap(), - vec![ - &mut account, - &mut mint_account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // burn via delegate - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - burn( - &program_id, - &account_key, - &mint_key, - &multisig_delegate_key, - &signer_key_refs, - 42, - ) - .unwrap(), - vec![ - &mut account, - &mut mint_account, - &mut multisig_delegate_account, - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // freeze account - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let mint2_key = Pubkey::new_unique(); - let mut mint2_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - do_process_instruction( - initialize_mint( - &program_id, - &mint2_key, - &multisig_key, - Some(&multisig_key), - 2, - ) - .unwrap(), - vec![&mut mint2_account, &mut rent_sysvar], - ) - .unwrap(); - do_process_instruction( - initialize_account(&program_id, &account3_key, &mint2_key, &owner_key).unwrap(), - vec![ - &mut account3_account, - &mut mint2_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - mint_to( - &program_id, - &mint2_key, - &account3_key, - &multisig_key, - &[&signer_keys[0]], - 1000, - ) - .unwrap(), - vec![ - &mut mint2_account, - &mut account3_account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - freeze_account( - &program_id, - &account3_key, - &mint2_key, - &multisig_key, - &[&signer_keys[0]], - ) - .unwrap(), - vec![ - &mut account3_account, - &mut mint2_account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // do SetAuthority on mint - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - set_authority( - &program_id, - &mint_key, - Some(&owner_key), - AuthorityType::MintTokens, - &multisig_key, - &[&signer_keys[0]], - ) - .unwrap(), - vec![ - &mut mint_account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // do SetAuthority on account - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner_key), - AuthorityType::AccountOwner, - &multisig_key, - &[&signer_keys[0]], - ) - .unwrap(), - vec![ - &mut account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - } - - #[test] - fn test_validate_owner() { - let program_id = crate::id(); - let owner_key = Pubkey::new_unique(); - let mut signer_keys = [Pubkey::default(); MAX_SIGNERS]; - for signer_key in signer_keys.iter_mut().take(MAX_SIGNERS) { - *signer_key = Pubkey::new_unique(); - } - let mut signer_lamports = 0; - let mut signer_data = vec![]; - let mut signers = vec![ - AccountInfo::new( - &owner_key, - true, - false, - &mut signer_lamports, - &mut signer_data, - &program_id, - false, - Epoch::default(), - ); - MAX_SIGNERS + 1 - ]; - for (signer, key) in signers.iter_mut().zip(&signer_keys) { - signer.key = key; - } - let mut lamports = 0; - let mut data = vec![0; Multisig::get_packed_len()]; - let mut multisig = Multisig::unpack_unchecked(&data).unwrap(); - multisig.m = MAX_SIGNERS as u8; - multisig.n = MAX_SIGNERS as u8; - multisig.signers = signer_keys; - multisig.is_initialized = true; - Multisig::pack(multisig, &mut data).unwrap(); - let owner_account_info = AccountInfo::new( - &owner_key, - false, - false, - &mut lamports, - &mut data, - &program_id, - false, - Epoch::default(), - ); - - // full 11 of 11 - Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers).unwrap(); - - // 1 of 11 - { - let mut multisig = - Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); - multisig.m = 1; - Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); - } - Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers).unwrap(); - - // 2:1 - { - let mut multisig = - Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); - multisig.m = 2; - multisig.n = 1; - Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); - } - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers) - ); - - // 0:11 - { - let mut multisig = - Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); - multisig.m = 0; - multisig.n = 11; - Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); - } - Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers).unwrap(); - - // 2:11 but 0 provided - { - let mut multisig = - Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); - multisig.m = 2; - multisig.n = 11; - Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); - } - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &[]) - ); - // 2:11 but 1 provided - { - let mut multisig = - Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); - multisig.m = 2; - multisig.n = 11; - Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); - } - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers[0..1]) - ); - - // 2:11, 2 from middle provided - { - let mut multisig = - Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); - multisig.m = 2; - multisig.n = 11; - Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); - } - Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers[5..7]) - .unwrap(); - - // 11:11, one is not a signer - { - let mut multisig = - Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); - multisig.m = 11; - multisig.n = 11; - Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); - } - signers[5].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers) - ); - signers[5].is_signer = true; - - // 11:11, single signer signs multiple times - { - let mut signer_lamports = 0; - let mut signer_data = vec![]; - let signers = vec![ - AccountInfo::new( - &signer_keys[5], - true, - false, - &mut signer_lamports, - &mut signer_data, - &program_id, - false, - Epoch::default(), - ); - MAX_SIGNERS + 1 - ]; - let mut multisig = - Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); - multisig.m = 11; - multisig.n = 11; - Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers) - ); - } - } - - #[test] - fn test_owner_close_account_dups() { - let program_id = crate::id(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - let to_close_key = Pubkey::new_unique(); - let mut to_close_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let to_close_account_info: AccountInfo = - (&to_close_key, true, &mut to_close_account).into(); - let destination_account_key = Pubkey::new_unique(); - let mut destination_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let destination_account_info: AccountInfo = - (&destination_account_key, true, &mut destination_account).into(); - // create account - do_process_instruction_dups( - initialize_account(&program_id, &to_close_key, &mint_key, &to_close_key).unwrap(), - vec![ - to_close_account_info.clone(), - mint_info.clone(), - to_close_account_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // source-owner close - do_process_instruction_dups( - close_account( - &program_id, - &to_close_key, - &destination_account_key, - &to_close_key, - &[], - ) - .unwrap(), - vec![ - to_close_account_info.clone(), - destination_account_info.clone(), - to_close_account_info.clone(), - ], - ) - .unwrap(); - assert_eq!(*to_close_account_info.data.borrow(), &[0u8; Account::LEN]); - } - - #[test] - fn test_close_authority_close_account_dups() { - let program_id = crate::id(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - let to_close_key = Pubkey::new_unique(); - let mut to_close_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let to_close_account_info: AccountInfo = - (&to_close_key, true, &mut to_close_account).into(); - let destination_account_key = Pubkey::new_unique(); - let mut destination_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let destination_account_info: AccountInfo = - (&destination_account_key, true, &mut destination_account).into(); - // create account - do_process_instruction_dups( - initialize_account(&program_id, &to_close_key, &mint_key, &to_close_key).unwrap(), - vec![ - to_close_account_info.clone(), - mint_info.clone(), - to_close_account_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - let mut account = Account::unpack_unchecked(&to_close_account_info.data.borrow()).unwrap(); - account.close_authority = COption::Some(to_close_key); - account.owner = owner_key; - Account::pack(account, &mut to_close_account_info.data.borrow_mut()).unwrap(); - do_process_instruction_dups( - close_account( - &program_id, - &to_close_key, - &destination_account_key, - &to_close_key, - &[], - ) - .unwrap(), - vec![ - to_close_account_info.clone(), - destination_account_info.clone(), - to_close_account_info.clone(), - ], - ) - .unwrap(); - assert_eq!(*to_close_account_info.data.borrow(), &[0u8; Account::LEN]); - } - - #[test] - fn test_close_account() { - let program_id = crate::id(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance() + 42, - Account::get_packed_len(), - &program_id, - ); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mut rent_sysvar = rent_sysvar(); - - // uninitialized - assert_eq!( - Err(ProgramError::UninitializedAccount), - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner2_account, - ], - ) - ); - - // initialize and mint to non-native account - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), - vec![ - &mut mint_account, - &mut account_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 42); - - // initialize native account - do_process_instruction( - initialize_account( - &program_id, - &account2_key, - &crate::native_mint::id(), - &owner_key, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account2_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 42); - - // close non-native account with balance - assert_eq!( - Err(TokenError::NonNativeHasBalance.into()), - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner_account, - ], - ) - ); - assert_eq!(account_account.lamports, account_minimum_balance()); - - // empty account - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &owner_key, &[], 42).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - - // wrong owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner2_account, - ], - ) - ); - - // close account - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner_account, - ], - ) - .unwrap(); - assert_eq!(account_account.lamports, 0); - assert_eq!(account3_account.lamports, 2 * account_minimum_balance()); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 0); - - // fund and initialize new non-native account to test close authority - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - account_account.lamports = 2; - - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner2_key), - AuthorityType::CloseAccount, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - .unwrap(); - - // account owner cannot authorize close if close_authority is set - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner_account, - ], - ) - ); - - // close non-native account with close_authority - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner2_account, - ], - ) - .unwrap(); - assert_eq!(account_account.lamports, 0); - assert_eq!(account3_account.lamports, 2 * account_minimum_balance() + 2); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 0); - - // close native account - do_process_instruction( - close_account(&program_id, &account2_key, &account3_key, &owner_key, &[]).unwrap(), - vec![ - &mut account2_account, - &mut account3_account, - &mut owner_account, - ], - ) - .unwrap(); - assert_eq!(account2_account.data, [0u8; Account::LEN]); - assert_eq!( - account3_account.lamports, - 3 * account_minimum_balance() + 2 + 42 - ); - } - - #[test] - fn test_native_token() { - let program_id = crate::id(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance() + 40, - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new(account_minimum_balance(), 0, &program_id); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let owner3_key = Pubkey::new_unique(); - let mut rent_sysvar = rent_sysvar(); - - // initialize native account - do_process_instruction( - initialize_account( - &program_id, - &account_key, - &crate::native_mint::id(), - &owner_key, - ) - .unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 40); - - // initialize native account - do_process_instruction( - initialize_account( - &program_id, - &account2_key, - &crate::native_mint::id(), - &owner_key, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account2_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 0); - - // mint_to unsupported - assert_eq!( - Err(TokenError::NativeNotSupported.into()), - do_process_instruction( - mint_to( - &program_id, - &crate::native_mint::id(), - &account_key, - &owner_key, - &[], - 42 - ) - .unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - ); - - // burn unsupported - let bogus_mint_key = Pubkey::new_unique(); - let mut bogus_mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - do_process_instruction( - initialize_mint(&program_id, &bogus_mint_key, &owner_key, None, 2).unwrap(), - vec![&mut bogus_mint_account, &mut rent_sysvar], - ) - .unwrap(); - - assert_eq!( - Err(TokenError::NativeNotSupported.into()), - do_process_instruction( - burn( - &program_id, - &account_key, - &bogus_mint_key, - &owner_key, - &[], - 42 - ) - .unwrap(), - vec![ - &mut account_account, - &mut bogus_mint_account, - &mut owner_account - ], - ) - ); - - // ensure can't transfer below rent-exempt reserve - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 50, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - ); - - // transfer between native accounts - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 40, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - .unwrap(); - assert_eq!(account_account.lamports, account_minimum_balance()); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 0); - assert_eq!(account2_account.lamports, account_minimum_balance() + 40); - let account = Account::unpack_unchecked(&account2_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 40); - - // set close authority - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner3_key), - AuthorityType::CloseAccount, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.close_authority, COption::Some(owner3_key)); - - // set new account owner - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner2_key), - AuthorityType::AccountOwner, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - .unwrap(); - - // close authority cleared - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.close_authority, COption::None); - - // close native account - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner2_account, - ], - ) - .unwrap(); - assert_eq!(account_account.lamports, 0); - assert_eq!(account3_account.lamports, 2 * account_minimum_balance()); - assert_eq!(account_account.data, [0u8; Account::LEN]); - } - - #[test] - fn test_overflow() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mint_owner_key = Pubkey::new_unique(); - let mut mint_owner_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create new mint with owner - do_process_instruction( - initialize_mint(&program_id, &mint_key, &mint_owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create an account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner2_key).unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner2_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // mint the max to an account - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account_key, - &mint_owner_key, - &[], - u64::MAX, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account_account, - &mut mint_owner_account, - ], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, u64::MAX); - - // attempt to mint one more to account - assert_eq!( - Err(TokenError::Overflow.into()), - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account_key, - &mint_owner_key, - &[], - 1, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account_account, - &mut mint_owner_account, - ], - ) - ); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, u64::MAX); - - // atttempt to mint one more to the other account - assert_eq!( - Err(TokenError::Overflow.into()), - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account2_key, - &mint_owner_key, - &[], - 1, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account2_account, - &mut mint_owner_account, - ], - ) - ); - - // burn some of the supply - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &owner_key, &[], 100).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, u64::MAX - 100); - - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account_key, - &mint_owner_key, - &[], - 100, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account_account, - &mut mint_owner_account, - ], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, u64::MAX); - - // manipulate account balance to attempt overflow transfer - let mut account = Account::unpack_unchecked(&account2_account.data).unwrap(); - account.amount = 1; - Account::pack(account, &mut account2_account.data).unwrap(); - - assert_eq!( - Err(TokenError::Overflow.into()), - do_process_instruction( - transfer( - &program_id, - &account2_key, - &account_key, - &owner2_key, - &[], - 1, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut account_account, - &mut owner2_account, - ], - ) - ); - } - - #[test] - fn test_frozen() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create new mint and fund first account - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // fund first account - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - // no transfer if either account is frozen - let mut account = Account::unpack_unchecked(&account2_account.data).unwrap(); - account.state = AccountState::Frozen; - Account::pack(account, &mut account2_account.data).unwrap(); - assert_eq!( - Err(TokenError::AccountFrozen.into()), - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 500, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - ); - - let mut account = Account::unpack_unchecked(&account_account.data).unwrap(); - account.state = AccountState::Initialized; - Account::pack(account, &mut account_account.data).unwrap(); - let mut account = Account::unpack_unchecked(&account2_account.data).unwrap(); - account.state = AccountState::Frozen; - Account::pack(account, &mut account2_account.data).unwrap(); - assert_eq!( - Err(TokenError::AccountFrozen.into()), - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 500, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - ); - - // no approve if account is frozen - let mut account = Account::unpack_unchecked(&account_account.data).unwrap(); - account.state = AccountState::Frozen; - Account::pack(account, &mut account_account.data).unwrap(); - let delegate_key = Pubkey::new_unique(); - let mut delegate_account = SolanaAccount::default(); - assert_eq!( - Err(TokenError::AccountFrozen.into()), - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 100 - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - ); - - // no revoke if account is frozen - let mut account = Account::unpack_unchecked(&account_account.data).unwrap(); - account.delegate = COption::Some(delegate_key); - account.delegated_amount = 100; - Account::pack(account, &mut account_account.data).unwrap(); - assert_eq!( - Err(TokenError::AccountFrozen.into()), - do_process_instruction( - revoke(&program_id, &account_key, &owner_key, &[]).unwrap(), - vec![&mut account_account, &mut owner_account], - ) - ); - - // no set authority if account is frozen - let new_owner_key = Pubkey::new_unique(); - assert_eq!( - Err(TokenError::AccountFrozen.into()), - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&new_owner_key), - AuthorityType::AccountOwner, - &owner_key, - &[] - ) - .unwrap(), - vec![&mut account_account, &mut owner_account,], - ) - ); - - // no mint_to if destination account is frozen - assert_eq!( - Err(TokenError::AccountFrozen.into()), - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 100).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account,], - ) - ); - - // no burn if account is frozen - assert_eq!( - Err(TokenError::AccountFrozen.into()), - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &owner_key, &[], 100).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - } - - #[test] - fn test_freeze_thaw_dups() { - let program_id = crate::id(); - let account1_key = Pubkey::new_unique(); - let mut account1_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &owner_key, Some(&account1_key), 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - // create account - do_process_instruction_dups( - initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // freeze where mint freeze_authority is account - do_process_instruction_dups( - freeze_account(&program_id, &account1_key, &mint_key, &account1_key, &[]).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // thaw where mint freeze_authority is account - let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.state = AccountState::Frozen; - Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); - do_process_instruction_dups( - thaw_account(&program_id, &account1_key, &mint_key, &account1_key, &[]).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - } - - #[test] - fn test_freeze_account() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account_owner_key = Pubkey::new_unique(); - let mut account_owner_account = SolanaAccount::default(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create new mint with owner different from account owner - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &account_owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut account_owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // mint to account - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - // mint cannot freeze - assert_eq!( - Err(TokenError::MintCannotFreeze.into()), - do_process_instruction( - freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - - // missing freeze_authority - let mut mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - mint.freeze_authority = COption::Some(owner_key); - Mint::pack(mint, &mut mint_account.data).unwrap(); - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - freeze_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner2_account], - ) - ); - - // check explicit thaw - assert_eq!( - Err(TokenError::InvalidState.into()), - do_process_instruction( - thaw_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner2_account], - ) - ); - - // freeze - do_process_instruction( - freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.state, AccountState::Frozen); - - // check explicit freeze - assert_eq!( - Err(TokenError::InvalidState.into()), - do_process_instruction( - freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - - // check thaw authority - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - thaw_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner2_account], - ) - ); - - // thaw - do_process_instruction( - thaw_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.state, AccountState::Initialized); - } - - #[test] - fn test_initialize_account2_and_3() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - do_process_instruction( - initialize_account2(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account2_account, &mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - assert_eq!(account_account, account2_account); - - do_process_instruction( - initialize_account3(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account3_account, &mut mint_account], - ) - .unwrap(); - - assert_eq!(account_account, account3_account); - } - - #[test] - fn test_sync_native() { - let program_id = crate::id(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let native_account_key = Pubkey::new_unique(); - let lamports = 40; - let mut native_account = SolanaAccount::new( - account_minimum_balance() + lamports, - Account::get_packed_len(), - &program_id, - ); - let non_native_account_key = Pubkey::new_unique(); - let mut non_native_account = SolanaAccount::new( - account_minimum_balance() + 50, - Account::get_packed_len(), - &program_id, - ); - - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let mut rent_sysvar = rent_sysvar(); - - // initialize non-native mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // initialize non-native account - do_process_instruction( - initialize_account(&program_id, &non_native_account_key, &mint_key, &owner_key) - .unwrap(), - vec![ - &mut non_native_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - let account = Account::unpack_unchecked(&non_native_account.data).unwrap(); - assert!(!account.is_native()); - assert_eq!(account.amount, 0); - - // fail sync non-native - assert_eq!( - Err(TokenError::NonNativeNotSupported.into()), - do_process_instruction( - sync_native(&program_id, &non_native_account_key,).unwrap(), - vec![&mut non_native_account], - ) - ); - - // fail sync uninitialized - assert_eq!( - Err(ProgramError::UninitializedAccount), - do_process_instruction( - sync_native(&program_id, &native_account_key,).unwrap(), - vec![&mut native_account], - ) - ); - - // wrap native account - do_process_instruction( - initialize_account( - &program_id, - &native_account_key, - &crate::native_mint::id(), - &owner_key, - ) - .unwrap(), - vec![ - &mut native_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // fail sync, not owned by program - let not_program_id = Pubkey::new_unique(); - native_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - sync_native(&program_id, &native_account_key,).unwrap(), - vec![&mut native_account], - ) - ); - native_account.owner = program_id; - - let account = Account::unpack_unchecked(&native_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, lamports); - - // sync, no change - do_process_instruction( - sync_native(&program_id, &native_account_key).unwrap(), - vec![&mut native_account], - ) - .unwrap(); - let account = Account::unpack_unchecked(&native_account.data).unwrap(); - assert_eq!(account.amount, lamports); - - // transfer sol - let new_lamports = lamports + 50; - native_account.lamports = account_minimum_balance() + new_lamports; - - // success sync - do_process_instruction( - sync_native(&program_id, &native_account_key).unwrap(), - vec![&mut native_account], - ) - .unwrap(); - let account = Account::unpack_unchecked(&native_account.data).unwrap(); - assert_eq!(account.amount, new_lamports); - - // reduce sol - native_account.lamports -= 1; - - // fail sync - assert_eq!( - Err(TokenError::InvalidState.into()), - do_process_instruction( - sync_native(&program_id, &native_account_key,).unwrap(), - vec![&mut native_account], - ) - ); - } - - #[test] - #[serial] - fn test_get_account_data_size() { - // see integration tests for return-data validity - let program_id = crate::id(); - let owner_key = Pubkey::new_unique(); - let mut rent_sysvar = rent_sysvar(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_key = Pubkey::new_unique(); - // fail if an invalid mint is passed in - assert_eq!( - Err(TokenError::InvalidMint.into()), - do_process_instruction( - get_account_data_size(&program_id, &mint_key).unwrap(), - vec![&mut mint_account], - ) - ); - - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - set_expected_data(Account::LEN.to_le_bytes().to_vec()); - do_process_instruction( - get_account_data_size(&program_id, &mint_key).unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - } - - #[test] - fn test_initialize_immutable_owner() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // success initialize immutable - do_process_instruction( - initialize_immutable_owner(&program_id, &account_key).unwrap(), - vec![&mut account_account], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // fail post-init - assert_eq!( - Err(TokenError::AlreadyInUse.into()), - do_process_instruction( - initialize_immutable_owner(&program_id, &account_key).unwrap(), - vec![&mut account_account], - ) - ); - } - - #[test] - #[serial] - fn test_amount_to_ui_amount() { - let program_id = crate::id(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // fail if an invalid mint is passed in - assert_eq!( - Err(TokenError::InvalidMint.into()), - do_process_instruction( - amount_to_ui_amount(&program_id, &mint_key, 110).unwrap(), - vec![&mut mint_account], - ) - ); - - // create mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - set_expected_data("0.23".as_bytes().to_vec()); - do_process_instruction( - amount_to_ui_amount(&program_id, &mint_key, 23).unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data("1.1".as_bytes().to_vec()); - do_process_instruction( - amount_to_ui_amount(&program_id, &mint_key, 110).unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data("42".as_bytes().to_vec()); - do_process_instruction( - amount_to_ui_amount(&program_id, &mint_key, 4200).unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data("0".as_bytes().to_vec()); - do_process_instruction( - amount_to_ui_amount(&program_id, &mint_key, 0).unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - } - - #[test] - #[serial] - fn test_ui_amount_to_amount() { - let program_id = crate::id(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // fail if an invalid mint is passed in - assert_eq!( - Err(TokenError::InvalidMint.into()), - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "1.1").unwrap(), - vec![&mut mint_account], - ) - ); - - // create mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - set_expected_data(23u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "0.23").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(20u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "0.20").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(20u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "0.2000").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(20u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, ".20").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(110u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "1.1").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(110u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "1.10").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(4200u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "42").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(4200u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "42.").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(0u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "0").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - // fail if invalid ui_amount passed in - assert_eq!( - Err(ProgramError::InvalidArgument), - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "").unwrap(), - vec![&mut mint_account], - ) - ); - assert_eq!( - Err(ProgramError::InvalidArgument), - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, ".").unwrap(), - vec![&mut mint_account], - ) - ); - assert_eq!( - Err(ProgramError::InvalidArgument), - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "0.111").unwrap(), - vec![&mut mint_account], - ) - ); - assert_eq!( - Err(ProgramError::InvalidArgument), - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "0.t").unwrap(), - vec![&mut mint_account], - ) - ); - } -} diff --git a/token/program/src/state.rs b/token/program/src/state.rs deleted file mode 100644 index 60701418047..00000000000 --- a/token/program/src/state.rs +++ /dev/null @@ -1,488 +0,0 @@ -//! State transition types - -use crate::instruction::MAX_SIGNERS; -use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}; -use num_enum::TryFromPrimitive; -use solana_program::{ - program_error::ProgramError, - program_option::COption, - program_pack::{IsInitialized, Pack, Sealed}, - pubkey::{Pubkey, PUBKEY_BYTES}, -}; - -/// Mint data. -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq)] -pub struct Mint { - /// Optional authority used to mint new tokens. The mint authority may only be provided during - /// mint creation. If no mint authority is present then the mint has a fixed supply and no - /// further tokens may be minted. - pub mint_authority: COption, - /// Total supply of tokens. - pub supply: u64, - /// Number of base 10 digits to the right of the decimal place. - pub decimals: u8, - /// Is `true` if this structure has been initialized - pub is_initialized: bool, - /// Optional authority to freeze token accounts. - pub freeze_authority: COption, -} -impl Sealed for Mint {} -impl IsInitialized for Mint { - fn is_initialized(&self) -> bool { - self.is_initialized - } -} -impl Pack for Mint { - const LEN: usize = 82; - fn unpack_from_slice(src: &[u8]) -> Result { - let src = array_ref![src, 0, 82]; - let (mint_authority, supply, decimals, is_initialized, freeze_authority) = - array_refs![src, 36, 8, 1, 1, 36]; - let mint_authority = unpack_coption_key(mint_authority)?; - let supply = u64::from_le_bytes(*supply); - let decimals = decimals[0]; - let is_initialized = match is_initialized { - [0] => false, - [1] => true, - _ => return Err(ProgramError::InvalidAccountData), - }; - let freeze_authority = unpack_coption_key(freeze_authority)?; - Ok(Mint { - mint_authority, - supply, - decimals, - is_initialized, - freeze_authority, - }) - } - fn pack_into_slice(&self, dst: &mut [u8]) { - let dst = array_mut_ref![dst, 0, 82]; - let ( - mint_authority_dst, - supply_dst, - decimals_dst, - is_initialized_dst, - freeze_authority_dst, - ) = mut_array_refs![dst, 36, 8, 1, 1, 36]; - let &Mint { - ref mint_authority, - supply, - decimals, - is_initialized, - ref freeze_authority, - } = self; - pack_coption_key(mint_authority, mint_authority_dst); - *supply_dst = supply.to_le_bytes(); - decimals_dst[0] = decimals; - is_initialized_dst[0] = is_initialized as u8; - pack_coption_key(freeze_authority, freeze_authority_dst); - } -} - -/// Account data. -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq)] -pub struct Account { - /// The mint associated with this account - pub mint: Pubkey, - /// The owner of this account. - pub owner: Pubkey, - /// The amount of tokens this account holds. - pub amount: u64, - /// If `delegate` is `Some` then `delegated_amount` represents - /// the amount authorized by the delegate - pub delegate: COption, - /// The account's state - pub state: AccountState, - /// If is_native.is_some, this is a native token, and the value logs the rent-exempt reserve. An - /// Account is required to be rent-exempt, so the value is used by the Processor to ensure that - /// wrapped SOL accounts do not drop below this threshold. - pub is_native: COption, - /// The amount delegated - pub delegated_amount: u64, - /// Optional authority to close the account. - pub close_authority: COption, -} -impl Account { - /// Checks if account is frozen - pub fn is_frozen(&self) -> bool { - self.state == AccountState::Frozen - } - /// Checks if account is native - pub fn is_native(&self) -> bool { - self.is_native.is_some() - } - /// Checks if a token Account's owner is the system_program or the incinerator - pub fn is_owned_by_system_program_or_incinerator(&self) -> bool { - solana_program::system_program::check_id(&self.owner) - || solana_program::incinerator::check_id(&self.owner) - } -} -impl Sealed for Account {} -impl IsInitialized for Account { - fn is_initialized(&self) -> bool { - self.state != AccountState::Uninitialized - } -} -impl Pack for Account { - const LEN: usize = 165; - fn unpack_from_slice(src: &[u8]) -> Result { - let src = array_ref![src, 0, 165]; - let (mint, owner, amount, delegate, state, is_native, delegated_amount, close_authority) = - array_refs![src, 32, 32, 8, 36, 1, 12, 8, 36]; - Ok(Account { - mint: Pubkey::new_from_array(*mint), - owner: Pubkey::new_from_array(*owner), - amount: u64::from_le_bytes(*amount), - delegate: unpack_coption_key(delegate)?, - state: AccountState::try_from_primitive(state[0]) - .or(Err(ProgramError::InvalidAccountData))?, - is_native: unpack_coption_u64(is_native)?, - delegated_amount: u64::from_le_bytes(*delegated_amount), - close_authority: unpack_coption_key(close_authority)?, - }) - } - fn pack_into_slice(&self, dst: &mut [u8]) { - let dst = array_mut_ref![dst, 0, 165]; - let ( - mint_dst, - owner_dst, - amount_dst, - delegate_dst, - state_dst, - is_native_dst, - delegated_amount_dst, - close_authority_dst, - ) = mut_array_refs![dst, 32, 32, 8, 36, 1, 12, 8, 36]; - let &Account { - ref mint, - ref owner, - amount, - ref delegate, - state, - ref is_native, - delegated_amount, - ref close_authority, - } = self; - mint_dst.copy_from_slice(mint.as_ref()); - owner_dst.copy_from_slice(owner.as_ref()); - *amount_dst = amount.to_le_bytes(); - pack_coption_key(delegate, delegate_dst); - state_dst[0] = state as u8; - pack_coption_u64(is_native, is_native_dst); - *delegated_amount_dst = delegated_amount.to_le_bytes(); - pack_coption_key(close_authority, close_authority_dst); - } -} - -/// Account state. -#[repr(u8)] -#[derive(Clone, Copy, Debug, PartialEq, TryFromPrimitive)] -pub enum AccountState { - /// Account is not yet initialized - Uninitialized, - /// Account is initialized; the account owner and/or delegate may perform permitted operations - /// on this account - Initialized, - /// Account has been frozen by the mint freeze authority. Neither the account owner nor - /// the delegate are able to perform operations on this account. - Frozen, -} - -impl Default for AccountState { - fn default() -> Self { - AccountState::Uninitialized - } -} - -/// Multisignature data. -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq)] -pub struct Multisig { - /// Number of signers required - pub m: u8, - /// Number of valid signers - pub n: u8, - /// Is `true` if this structure has been initialized - pub is_initialized: bool, - /// Signer public keys - pub signers: [Pubkey; MAX_SIGNERS], -} -impl Sealed for Multisig {} -impl IsInitialized for Multisig { - fn is_initialized(&self) -> bool { - self.is_initialized - } -} -impl Pack for Multisig { - const LEN: usize = 355; - fn unpack_from_slice(src: &[u8]) -> Result { - let src = array_ref![src, 0, 355]; - #[allow(clippy::ptr_offset_with_cast)] - let (m, n, is_initialized, signers_flat) = array_refs![src, 1, 1, 1, 32 * MAX_SIGNERS]; - let mut result = Multisig { - m: m[0], - n: n[0], - is_initialized: match is_initialized { - [0] => false, - [1] => true, - _ => return Err(ProgramError::InvalidAccountData), - }, - signers: [Pubkey::new_from_array([0u8; 32]); MAX_SIGNERS], - }; - for (src, dst) in signers_flat.chunks(32).zip(result.signers.iter_mut()) { - *dst = Pubkey::new(src); - } - Ok(result) - } - fn pack_into_slice(&self, dst: &mut [u8]) { - let dst = array_mut_ref![dst, 0, 355]; - #[allow(clippy::ptr_offset_with_cast)] - let (m, n, is_initialized, signers_flat) = mut_array_refs![dst, 1, 1, 1, 32 * MAX_SIGNERS]; - *m = [self.m]; - *n = [self.n]; - *is_initialized = [self.is_initialized as u8]; - for (i, src) in self.signers.iter().enumerate() { - let dst_array = array_mut_ref![signers_flat, 32 * i, 32]; - dst_array.copy_from_slice(src.as_ref()); - } - } -} - -// Helpers -fn pack_coption_key(src: &COption, dst: &mut [u8; 36]) { - let (tag, body) = mut_array_refs![dst, 4, 32]; - match src { - COption::Some(key) => { - *tag = [1, 0, 0, 0]; - body.copy_from_slice(key.as_ref()); - } - COption::None => { - *tag = [0; 4]; - } - } -} -fn unpack_coption_key(src: &[u8; 36]) -> Result, ProgramError> { - let (tag, body) = array_refs![src, 4, 32]; - match *tag { - [0, 0, 0, 0] => Ok(COption::None), - [1, 0, 0, 0] => Ok(COption::Some(Pubkey::new_from_array(*body))), - _ => Err(ProgramError::InvalidAccountData), - } -} -fn pack_coption_u64(src: &COption, dst: &mut [u8; 12]) { - let (tag, body) = mut_array_refs![dst, 4, 8]; - match src { - COption::Some(amount) => { - *tag = [1, 0, 0, 0]; - *body = amount.to_le_bytes(); - } - COption::None => { - *tag = [0; 4]; - } - } -} -fn unpack_coption_u64(src: &[u8; 12]) -> Result, ProgramError> { - let (tag, body) = array_refs![src, 4, 8]; - match *tag { - [0, 0, 0, 0] => Ok(COption::None), - [1, 0, 0, 0] => Ok(COption::Some(u64::from_le_bytes(*body))), - _ => Err(ProgramError::InvalidAccountData), - } -} - -const SPL_TOKEN_ACCOUNT_MINT_OFFSET: usize = 0; -const SPL_TOKEN_ACCOUNT_OWNER_OFFSET: usize = 32; - -/// A trait for token Account structs to enable efficiently unpacking various fields -/// without unpacking the complete state. -pub trait GenericTokenAccount { - /// Check if the account data is a valid token account - fn valid_account_data(account_data: &[u8]) -> bool; - - /// Call after account length has already been verified to unpack the account owner - fn unpack_account_owner_unchecked(account_data: &[u8]) -> &Pubkey { - Self::unpack_pubkey_unchecked(account_data, SPL_TOKEN_ACCOUNT_OWNER_OFFSET) - } - - /// Call after account length has already been verified to unpack the account mint - fn unpack_account_mint_unchecked(account_data: &[u8]) -> &Pubkey { - Self::unpack_pubkey_unchecked(account_data, SPL_TOKEN_ACCOUNT_MINT_OFFSET) - } - - /// Call after account length has already been verified to unpack a Pubkey at - /// the specified offset. Panics if `account_data.len()` is less than `PUBKEY_BYTES` - fn unpack_pubkey_unchecked(account_data: &[u8], offset: usize) -> &Pubkey { - bytemuck::from_bytes(&account_data[offset..offset + PUBKEY_BYTES]) - } - - /// Unpacks an account's owner from opaque account data. - fn unpack_account_owner(account_data: &[u8]) -> Option<&Pubkey> { - if Self::valid_account_data(account_data) { - Some(Self::unpack_account_owner_unchecked(account_data)) - } else { - None - } - } - - /// Unpacks an account's mint from opaque account data. - fn unpack_account_mint(account_data: &[u8]) -> Option<&Pubkey> { - if Self::valid_account_data(account_data) { - Some(Self::unpack_account_mint_unchecked(account_data)) - } else { - None - } - } -} - -/// The offset of state field in Account's C representation -pub const ACCOUNT_INITIALIZED_INDEX: usize = 108; - -/// Check if the account data buffer represents an initialized account. -/// This is checking the `state` (AccountState) field of an Account object. -pub fn is_initialized_account(account_data: &[u8]) -> bool { - *account_data - .get(ACCOUNT_INITIALIZED_INDEX) - .unwrap_or(&(AccountState::Uninitialized as u8)) - != AccountState::Uninitialized as u8 -} - -impl GenericTokenAccount for Account { - fn valid_account_data(account_data: &[u8]) -> bool { - account_data.len() == Account::LEN && is_initialized_account(account_data) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_mint_unpack_from_slice() { - let src: [u8; 82] = [0; 82]; - let mint = Mint::unpack_from_slice(&src).unwrap(); - assert!(!mint.is_initialized); - - let mut src: [u8; 82] = [0; 82]; - src[45] = 2; - let mint = Mint::unpack_from_slice(&src).unwrap_err(); - assert_eq!(mint, ProgramError::InvalidAccountData); - } - - #[test] - fn test_account_state() { - let account_state = AccountState::default(); - assert_eq!(account_state, AccountState::Uninitialized); - } - - #[test] - fn test_multisig_unpack_from_slice() { - let src: [u8; 355] = [0; 355]; - let multisig = Multisig::unpack_from_slice(&src).unwrap(); - assert_eq!(multisig.m, 0); - assert_eq!(multisig.n, 0); - assert!(!multisig.is_initialized); - - let mut src: [u8; 355] = [0; 355]; - src[0] = 1; - src[1] = 1; - src[2] = 1; - let multisig = Multisig::unpack_from_slice(&src).unwrap(); - assert_eq!(multisig.m, 1); - assert_eq!(multisig.n, 1); - assert!(multisig.is_initialized); - - let mut src: [u8; 355] = [0; 355]; - src[2] = 2; - let multisig = Multisig::unpack_from_slice(&src).unwrap_err(); - assert_eq!(multisig, ProgramError::InvalidAccountData); - } - - #[test] - fn test_unpack_coption_key() { - let src: [u8; 36] = [0; 36]; - let result = unpack_coption_key(&src).unwrap(); - assert_eq!(result, COption::None); - - let mut src: [u8; 36] = [0; 36]; - src[1] = 1; - let result = unpack_coption_key(&src).unwrap_err(); - assert_eq!(result, ProgramError::InvalidAccountData); - } - - #[test] - fn test_unpack_coption_u64() { - let src: [u8; 12] = [0; 12]; - let result = unpack_coption_u64(&src).unwrap(); - assert_eq!(result, COption::None); - - let mut src: [u8; 12] = [0; 12]; - src[0] = 1; - let result = unpack_coption_u64(&src).unwrap(); - assert_eq!(result, COption::Some(0)); - - let mut src: [u8; 12] = [0; 12]; - src[1] = 1; - let result = unpack_coption_u64(&src).unwrap_err(); - assert_eq!(result, ProgramError::InvalidAccountData); - } - - #[test] - fn test_unpack_token_owner() { - // Account data length < Account::LEN, unpack will not return a key - let src: [u8; 12] = [0; 12]; - let result = Account::unpack_account_owner(&src); - assert_eq!(result, Option::None); - - // The right account data size and intialized, unpack will return some key - let mut src: [u8; Account::LEN] = [0; Account::LEN]; - src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Initialized as u8; - let result = Account::unpack_account_owner(&src); - assert!(result.is_some()); - - // The right account data size and frozen, unpack will return some key - src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Frozen as u8; - let result = Account::unpack_account_owner(&src); - assert!(result.is_some()); - - // The right account data size and uninitialized, unpack will return None - src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Uninitialized as u8; - let result = Account::unpack_account_mint(&src); - assert_eq!(result, Option::None); - - // Account data length > account data size, unpack will not return a key - let src: [u8; Account::LEN + 5] = [0; Account::LEN + 5]; - let result = Account::unpack_account_owner(&src); - assert_eq!(result, Option::None); - } - - #[test] - fn test_unpack_token_mint() { - // Account data length < Account::LEN, unpack will not return a key - let src: [u8; 12] = [0; 12]; - let result = Account::unpack_account_mint(&src); - assert_eq!(result, Option::None); - - // The right account data size and initialized, unpack will return some key - let mut src: [u8; Account::LEN] = [0; Account::LEN]; - src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Initialized as u8; - let result = Account::unpack_account_mint(&src); - assert!(result.is_some()); - - // The right account data size and frozen, unpack will return some key - src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Frozen as u8; - let result = Account::unpack_account_mint(&src); - assert!(result.is_some()); - - // The right account data size and uninitialized, unpack will return None - src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Uninitialized as u8; - let result = Account::unpack_account_mint(&src); - assert_eq!(result, Option::None); - - // Account data length > account data size, unpack will not return a key - let src: [u8; Account::LEN + 5] = [0; Account::LEN + 5]; - let result = Account::unpack_account_mint(&src); - assert_eq!(result, Option::None); - } -} diff --git a/token/program/tests/action.rs b/token/program/tests/action.rs deleted file mode 100644 index 0a67538b0ff..00000000000 --- a/token/program/tests/action.rs +++ /dev/null @@ -1,140 +0,0 @@ -use { - solana_program_test::BanksClient, - solana_sdk::{ - hash::Hash, - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - system_instruction, - transaction::Transaction, - transport::TransportError, - }, - spl_token::{ - id, instruction, - state::{Account, Mint}, - }, -}; - -pub async fn create_mint( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: Hash, - pool_mint: &Keypair, - manager: &Pubkey, - decimals: u8, -) -> Result<(), TransportError> { - let rent = banks_client.get_rent().await.unwrap(); - let mint_rent = rent.minimum_balance(Mint::LEN); - - let transaction = Transaction::new_signed_with_payer( - &[ - system_instruction::create_account( - &payer.pubkey(), - &pool_mint.pubkey(), - mint_rent, - Mint::LEN as u64, - &id(), - ), - instruction::initialize_mint(&id(), &pool_mint.pubkey(), manager, None, decimals) - .unwrap(), - ], - Some(&payer.pubkey()), - &[payer, pool_mint], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await?; - Ok(()) -} - -pub async fn create_account( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: Hash, - account: &Keypair, - pool_mint: &Pubkey, - owner: &Pubkey, -) -> Result<(), TransportError> { - let rent = banks_client.get_rent().await.unwrap(); - let account_rent = rent.minimum_balance(Account::LEN); - - let transaction = Transaction::new_signed_with_payer( - &[ - system_instruction::create_account( - &payer.pubkey(), - &account.pubkey(), - account_rent, - Account::LEN as u64, - &id(), - ), - instruction::initialize_account(&id(), &account.pubkey(), pool_mint, owner).unwrap(), - ], - Some(&payer.pubkey()), - &[payer, account], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await?; - Ok(()) -} - -pub async fn mint_to( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: Hash, - mint: &Pubkey, - account: &Pubkey, - mint_authority: &Keypair, - amount: u64, -) -> Result<(), TransportError> { - let transaction = Transaction::new_signed_with_payer( - &[ - instruction::mint_to(&id(), mint, account, &mint_authority.pubkey(), &[], amount) - .unwrap(), - ], - Some(&payer.pubkey()), - &[payer, mint_authority], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await?; - Ok(()) -} - -pub async fn transfer( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: Hash, - source: &Pubkey, - destination: &Pubkey, - authority: &Keypair, - amount: u64, -) -> Result<(), TransportError> { - let transaction = Transaction::new_signed_with_payer( - &[ - instruction::transfer(&id(), source, destination, &authority.pubkey(), &[], amount) - .unwrap(), - ], - Some(&payer.pubkey()), - &[payer, authority], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await?; - Ok(()) -} - -pub async fn burn( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: Hash, - mint: &Pubkey, - account: &Pubkey, - authority: &Keypair, - amount: u64, -) -> Result<(), TransportError> { - let transaction = Transaction::new_signed_with_payer( - &[instruction::burn(&id(), account, mint, &authority.pubkey(), &[], amount).unwrap()], - Some(&payer.pubkey()), - &[payer, authority], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await?; - Ok(()) -} diff --git a/token/program/tests/assert_instruction_count.rs b/token/program/tests/assert_instruction_count.rs deleted file mode 100644 index d663c549fc8..00000000000 --- a/token/program/tests/assert_instruction_count.rs +++ /dev/null @@ -1,332 +0,0 @@ -#![cfg(feature = "test-bpf")] - -mod action; -use { - solana_program_test::{processor, tokio, ProgramTest}, - solana_sdk::{ - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - system_instruction, - transaction::Transaction, - }, - spl_token::{ - id, instruction, - processor::Processor, - state::{Account, Mint}, - }, -}; - -const TRANSFER_AMOUNT: u64 = 1_000_000_000_000_000; - -#[tokio::test] -async fn initialize_mint() { - let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_compute_max_units(5_000); // last known 2252 - let (mut banks_client, payer, recent_blockhash) = pt.start().await; - - let owner_key = Pubkey::new_unique(); - let mint = Keypair::new(); - let decimals = 9; - - let rent = banks_client.get_rent().await.unwrap(); - let mint_rent = rent.minimum_balance(Mint::LEN); - let transaction = Transaction::new_signed_with_payer( - &[system_instruction::create_account( - &payer.pubkey(), - &mint.pubkey(), - mint_rent, - Mint::LEN as u64, - &id(), - )], - Some(&payer.pubkey()), - &[&payer, &mint], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); - - let transaction = Transaction::new_signed_with_payer( - &[ - instruction::initialize_mint(&id(), &mint.pubkey(), &owner_key, None, decimals) - .unwrap(), - ], - Some(&payer.pubkey()), - &[&payer], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); -} - -#[tokio::test] -async fn initialize_account() { - let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_compute_max_units(6_000); // last known 3284 - let (mut banks_client, payer, recent_blockhash) = pt.start().await; - - let owner = Keypair::new(); - let mint = Keypair::new(); - let account = Keypair::new(); - let decimals = 9; - - action::create_mint( - &mut banks_client, - &payer, - recent_blockhash, - &mint, - &owner.pubkey(), - decimals, - ) - .await - .unwrap(); - let rent = banks_client.get_rent().await.unwrap(); - let account_rent = rent.minimum_balance(Account::LEN); - let transaction = Transaction::new_signed_with_payer( - &[system_instruction::create_account( - &payer.pubkey(), - &account.pubkey(), - account_rent, - Account::LEN as u64, - &id(), - )], - Some(&payer.pubkey()), - &[&payer, &account], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); - - let transaction = Transaction::new_signed_with_payer( - &[instruction::initialize_account( - &id(), - &account.pubkey(), - &mint.pubkey(), - &owner.pubkey(), - ) - .unwrap()], - Some(&payer.pubkey()), - &[&payer], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); -} - -#[tokio::test] -async fn mint_to() { - let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_compute_max_units(6_000); // last known 2668 - let (mut banks_client, payer, recent_blockhash) = pt.start().await; - - let owner = Keypair::new(); - let mint = Keypair::new(); - let account = Keypair::new(); - let decimals = 9; - - action::create_mint( - &mut banks_client, - &payer, - recent_blockhash, - &mint, - &owner.pubkey(), - decimals, - ) - .await - .unwrap(); - action::create_account( - &mut banks_client, - &payer, - recent_blockhash, - &account, - &mint.pubkey(), - &owner.pubkey(), - ) - .await - .unwrap(); - - let transaction = Transaction::new_signed_with_payer( - &[instruction::mint_to( - &id(), - &mint.pubkey(), - &account.pubkey(), - &owner.pubkey(), - &[], - TRANSFER_AMOUNT, - ) - .unwrap()], - Some(&payer.pubkey()), - &[&payer, &owner], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); -} - -#[tokio::test] -async fn transfer() { - let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_compute_max_units(7_000); // last known 2972 - let (mut banks_client, payer, recent_blockhash) = pt.start().await; - - let owner = Keypair::new(); - let mint = Keypair::new(); - let source = Keypair::new(); - let destination = Keypair::new(); - let decimals = 9; - - action::create_mint( - &mut banks_client, - &payer, - recent_blockhash, - &mint, - &owner.pubkey(), - decimals, - ) - .await - .unwrap(); - action::create_account( - &mut banks_client, - &payer, - recent_blockhash, - &source, - &mint.pubkey(), - &owner.pubkey(), - ) - .await - .unwrap(); - action::create_account( - &mut banks_client, - &payer, - recent_blockhash, - &destination, - &mint.pubkey(), - &owner.pubkey(), - ) - .await - .unwrap(); - - action::mint_to( - &mut banks_client, - &payer, - recent_blockhash, - &mint.pubkey(), - &source.pubkey(), - &owner, - TRANSFER_AMOUNT, - ) - .await - .unwrap(); - - action::transfer( - &mut banks_client, - &payer, - recent_blockhash, - &source.pubkey(), - &destination.pubkey(), - &owner, - TRANSFER_AMOUNT, - ) - .await - .unwrap(); -} - -#[tokio::test] -async fn burn() { - let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_compute_max_units(6_000); // last known 2655 - let (mut banks_client, payer, recent_blockhash) = pt.start().await; - - let owner = Keypair::new(); - let mint = Keypair::new(); - let account = Keypair::new(); - let decimals = 9; - - action::create_mint( - &mut banks_client, - &payer, - recent_blockhash, - &mint, - &owner.pubkey(), - decimals, - ) - .await - .unwrap(); - action::create_account( - &mut banks_client, - &payer, - recent_blockhash, - &account, - &mint.pubkey(), - &owner.pubkey(), - ) - .await - .unwrap(); - - action::mint_to( - &mut banks_client, - &payer, - recent_blockhash, - &mint.pubkey(), - &account.pubkey(), - &owner, - TRANSFER_AMOUNT, - ) - .await - .unwrap(); - - action::burn( - &mut banks_client, - &payer, - recent_blockhash, - &mint.pubkey(), - &account.pubkey(), - &owner, - TRANSFER_AMOUNT, - ) - .await - .unwrap(); -} - -#[tokio::test] -async fn close_account() { - let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_compute_max_units(6_000); // last known 1783 - let (mut banks_client, payer, recent_blockhash) = pt.start().await; - - let owner = Keypair::new(); - let mint = Keypair::new(); - let account = Keypair::new(); - let decimals = 9; - - action::create_mint( - &mut banks_client, - &payer, - recent_blockhash, - &mint, - &owner.pubkey(), - decimals, - ) - .await - .unwrap(); - action::create_account( - &mut banks_client, - &payer, - recent_blockhash, - &account, - &mint.pubkey(), - &owner.pubkey(), - ) - .await - .unwrap(); - - let transaction = Transaction::new_signed_with_payer( - &[instruction::close_account( - &id(), - &account.pubkey(), - &owner.pubkey(), - &owner.pubkey(), - &[], - ) - .unwrap()], - Some(&payer.pubkey()), - &[&payer, &owner], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); -} diff --git a/token/program/tests/close_account.rs b/token/program/tests/close_account.rs deleted file mode 100644 index 195a7aa9d0f..00000000000 --- a/token/program/tests/close_account.rs +++ /dev/null @@ -1,202 +0,0 @@ -#![cfg(feature = "test-bpf")] - -use { - solana_program_test::{processor, tokio, ProgramTest, ProgramTestContext}, - solana_sdk::{ - instruction::InstructionError, - program_pack::Pack, - pubkey::Pubkey, - signature::Signer, - signer::keypair::Keypair, - system_instruction, - transaction::{Transaction, TransactionError}, - }, - spl_token::{ - instruction, - processor::Processor, - state::{Account, Mint}, - }, -}; - -async fn setup_mint_and_account( - context: &mut ProgramTestContext, - mint: &Keypair, - token_account: &Keypair, - owner: &Pubkey, - token_program_id: &Pubkey, -) { - let rent = context.banks_client.get_rent().await.unwrap(); - let mint_authority_pubkey = Pubkey::new_unique(); - - let space = Mint::LEN; - let tx = Transaction::new_signed_with_payer( - &[ - system_instruction::create_account( - &context.payer.pubkey(), - &mint.pubkey(), - rent.minimum_balance(space), - space as u64, - &token_program_id, - ), - instruction::initialize_mint( - &token_program_id, - &mint.pubkey(), - &mint_authority_pubkey, - None, - 9, - ) - .unwrap(), - ], - Some(&context.payer.pubkey()), - &[&context.payer, mint], - context.last_blockhash, - ); - context.banks_client.process_transaction(tx).await.unwrap(); - let space = Account::LEN; - let tx = Transaction::new_signed_with_payer( - &[ - system_instruction::create_account( - &context.payer.pubkey(), - &token_account.pubkey(), - rent.minimum_balance(space), - space as u64, - &token_program_id, - ), - instruction::initialize_account( - &token_program_id, - &token_account.pubkey(), - &mint.pubkey(), - &owner, - ) - .unwrap(), - ], - Some(&context.payer.pubkey()), - &[&context.payer, &token_account], - context.last_blockhash, - ); - context.banks_client.process_transaction(tx).await.unwrap(); -} - -#[tokio::test] -async fn success_init_after_close_account() { - let program_test = - ProgramTest::new("spl_token", spl_token::id(), processor!(Processor::process)); - let mut context = program_test.start_with_context().await; - let mint = Keypair::new(); - let token_account = Keypair::new(); - let owner = Keypair::new(); - let token_program_id = spl_token::id(); - setup_mint_and_account( - &mut context, - &mint, - &token_account, - &owner.pubkey(), - &token_program_id, - ) - .await; - - let destination = Pubkey::new_unique(); - let tx = Transaction::new_signed_with_payer( - &[ - instruction::close_account( - &token_program_id, - &token_account.pubkey(), - &destination, - &owner.pubkey(), - &[], - ) - .unwrap(), - system_instruction::create_account( - &context.payer.pubkey(), - &token_account.pubkey(), - 1_000_000_000, - Account::LEN as u64, - &token_program_id, - ), - instruction::initialize_account( - &token_program_id, - &token_account.pubkey(), - &mint.pubkey(), - &owner.pubkey(), - ) - .unwrap(), - ], - Some(&context.payer.pubkey()), - &[&context.payer, &owner, &token_account], - context.last_blockhash, - ); - context.banks_client.process_transaction(tx).await.unwrap(); - let destination = context - .banks_client - .get_account(destination) - .await - .unwrap() - .unwrap(); - assert!(destination.lamports > 0); -} - -#[tokio::test] -async fn fail_init_after_close_account() { - let program_test = - ProgramTest::new("spl_token", spl_token::id(), processor!(Processor::process)); - let mut context = program_test.start_with_context().await; - let mint = Keypair::new(); - let token_account = Keypair::new(); - let owner = Keypair::new(); - let token_program_id = spl_token::id(); - setup_mint_and_account( - &mut context, - &mint, - &token_account, - &owner.pubkey(), - &token_program_id, - ) - .await; - - let destination = Pubkey::new_unique(); - let tx = Transaction::new_signed_with_payer( - &[ - instruction::close_account( - &token_program_id, - &token_account.pubkey(), - &destination, - &owner.pubkey(), - &[], - ) - .unwrap(), - system_instruction::transfer( - &context.payer.pubkey(), - &token_account.pubkey(), - 1_000_000_000, - ), - instruction::initialize_account( - &token_program_id, - &token_account.pubkey(), - &mint.pubkey(), - &owner.pubkey(), - ) - .unwrap(), - ], - Some(&context.payer.pubkey()), - &[&context.payer, &owner], - context.last_blockhash, - ); - #[allow(clippy::useless_conversion)] - let error: TransactionError = context - .banks_client - .process_transaction(tx) - .await - .unwrap_err() - .unwrap() - .into(); - assert_eq!( - error, - TransactionError::InstructionError(2, InstructionError::InvalidAccountData) - ); - assert!(context - .banks_client - .get_account(destination) - .await - .unwrap() - .is_none()); -} diff --git a/token/twoxtx-setup.sh b/token/twoxtx-setup.sh deleted file mode 100755 index 1856d58f6e7..00000000000 --- a/token/twoxtx-setup.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash -# -# Patch in a Solana v1.11 monorepo that supports 2x transactions for testing the -# SPL Token 2022 Confidential Transfer extension -# - -set -e - -here="$(dirname "$0")" -cd "$here" - -if [[ ! -d twoxtx-solana ]]; then - if [[ -n $CI ]]; then - git config --global user.email "you@example.com" - git config --global user.name "Your Name" - git clone https://github.com/solana-labs/solana.git twoxtx-solana - else - git clone git@github.com:solana-labs/solana.git twoxtx-solana - fi -fi - -if [[ ! -f twoxtx-solana/.twoxtx-patched ]]; then - git -C twoxtx-solana am "$PWD"/twoxtx.patch - touch twoxtx-solana/.twoxtx-patched -fi - -../patch.crates-io.sh twoxtx-solana -exit 0 diff --git a/token/twoxtx.patch b/token/twoxtx.patch deleted file mode 100644 index 477585c5d08..00000000000 --- a/token/twoxtx.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 935ad2c371da8405bb85922b9941d35b3dc68ceb Mon Sep 17 00:00:00 2001 -From: Steven Czabaniuk -Date: Wed, 29 Sep 2021 15:43:36 -0500 -Subject: [PATCH] feat: double PACKET_DATA_SIZE - -Try blind double of PACKET_DATA_SIZE; this double things across the -board and is not a permanent solution. ---- - rpc/src/rpc.rs | 16 +++++++++++----- - sdk/src/packet.rs | 3 ++- - web3.js/src/transaction.ts | 4 +++- - 3 files changed, 16 insertions(+), 7 deletions(-) - -diff --git a/rpc/src/rpc.rs b/rpc/src/rpc.rs -index 1a0dcdeb6c..e33492fa84 100644 ---- a/rpc/src/rpc.rs -+++ b/rpc/src/rpc.rs -@@ -4214,8 +4214,11 @@ pub mod rpc_obsolete_v1_7 { - } - } - --const MAX_BASE58_SIZE: usize = 1683; // Golden, bump if PACKET_DATA_SIZE changes --const MAX_BASE64_SIZE: usize = 1644; // Golden, bump if PACKET_DATA_SIZE changes -+// These values need to be updated if PACKET_DATA_SIZE changes. The correct values can -+// be found by hand or by simply encoding `PACKET_DATA_SIZE` bytes and checking length. -+// `test_max_encoded_tx_goldens` ensures these values are correct. -+const MAX_BASE58_SIZE: usize = 3365; -+const MAX_BASE64_SIZE: usize = 3288; - fn decode_and_deserialize( - encoded: String, - encoding: TransactionBinaryEncoding, -@@ -7749,7 +7752,7 @@ pub mod tests { - } - - #[test] -- fn test_worst_case_encoded_tx_goldens() { -+ fn test_max_encoded_tx_goldens() { - let ff_tx = vec![0xffu8; PACKET_DATA_SIZE]; - let tx58 = bs58::encode(&ff_tx).into_string(); - assert_eq!(tx58.len(), MAX_BASE58_SIZE); -@@ -7759,8 +7762,11 @@ pub mod tests { - - #[test] - fn test_decode_and_deserialize_too_large_payloads_fail() { -- // +2 because +1 still fits in base64 encoded worst-case -- let too_big = PACKET_DATA_SIZE + 2; -+ // 4 base64 digits are generated from groups of 3 bytes; however, those 4 digits -+ // are generated even if the group only has 1 or 2 bytes. -+ // So, we need 4 - (PACKET_DATA_SIZE % 3) extra bytes to ensure we'll spill over -+ let extra_bytes = 4 - (PACKET_DATA_SIZE % 3); -+ let too_big = PACKET_DATA_SIZE + extra_bytes; - let tx_ser = vec![0xffu8; too_big]; - let tx58 = bs58::encode(&tx_ser).into_string(); - let tx58_len = tx58.len(); -diff --git a/sdk/src/packet.rs b/sdk/src/packet.rs -index efea219043..473a92ecfe 100644 ---- a/sdk/src/packet.rs -+++ b/sdk/src/packet.rs -@@ -12,7 +12,8 @@ use { - /// 1280 is IPv6 minimum MTU - /// 40 bytes is the size of the IPv6 header - /// 8 bytes is the size of the fragment header --pub const PACKET_DATA_SIZE: usize = 1280 - 40 - 8; -+/// Double the minimum to support larger than MTU transactions -+pub const PACKET_DATA_SIZE: usize = 2 * (1280 - 40 - 8); - - bitflags! { - #[repr(C)] -diff --git a/web3.js/src/transaction-constants.ts b/web3.js/src/transaction-constants.ts -index 591873f8b6..f94d5778ba 100644 ---- a/web3.js/src/transaction-constants.ts -+++ b/web3.js/src/transaction-constants.ts -@@ -5,6 +5,6 @@ - * 40 bytes is the size of the IPv6 header - * 8 bytes is the size of the fragment header - */ --export const PACKET_DATA_SIZE = 1280 - 40 - 8; -+export const PACKET_DATA_SIZE = 2464; - - export const SIGNATURE_LENGTH_IN_BYTES = 64; - --- -2.32.0 (Apple Git-132) diff --git a/token/zk-token-protocol-paper/part1.pdf b/token/zk-token-protocol-paper/part1.pdf deleted file mode 100644 index 41384d32d03..00000000000 Binary files a/token/zk-token-protocol-paper/part1.pdf and /dev/null differ diff --git a/token/zk-token-protocol-paper/part2.pdf b/token/zk-token-protocol-paper/part2.pdf deleted file mode 100644 index 09ed0e81232..00000000000 Binary files a/token/zk-token-protocol-paper/part2.pdf and /dev/null differ diff --git a/turbo.json b/turbo.json new file mode 100644 index 00000000000..3e2f34d3455 --- /dev/null +++ b/turbo.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://turbo.build/schema.json", + "remoteCache": { + "signature": true + }, + "tasks": { + "build": { + "dependsOn": ["^build"], + "outputs": ["dist/**", "lib/**"] + }, + "build:program": { + "dependsOn": ["^build:program"] + }, + "clean": {}, + "lint:fix": { + "inputs": ["tsconfig*.json", "src/**", "test/**"], + "outputs": [] + }, + "lint": { + "inputs": ["tsconfig*.json", "src/**", "test/**"], + "outputs": [] + }, + "test": { + "inputs": ["src/**", "test/**"], + "outputs": [] + } + } +} diff --git a/update-solana-dependencies.sh b/update-solana-dependencies.sh index 4c4b96cd283..04d5b3afc65 100755 --- a/update-solana-dependencies.sh +++ b/update-solana-dependencies.sh @@ -21,30 +21,123 @@ while IFS='' read -r line; do tomls+=("$line"); done < <(find . -name Cargo.toml crates=( solana-account-decoder + solana-account-decoder-client-types solana-banks-client + solana-banks-interface solana-banks-server - solana-bpf-loader-program + solana-bloom + solana-bucket-map + solana-builtins-default-costs solana-clap-utils + solana-clap-v3-utils solana-cli-config solana-cli-output solana-client + solana-compute-budget + solana-connection-cache solana-core + solana-entry + solana-faucet + solana-fee + solana-frozen-abi + solana-frozen-abi-macro + agave-geyser-plugin-interface + solana-geyser-plugin-manager + solana-gossip + solana-lattice-hash + solana-ledger + solana-log-collector solana-logger - solana-notifier - solana-program + solana-measure + solana-merkle-tree + solana-metrics + solana-net-utils + solana-perf + solana-poh + solana-program-runtime solana-program-test + solana-address-lookup-table-program + solana-bpf-loader-program + solana-compute-budget-program + solana-config-program + solana-stake-program + solana-system-program + solana-vote-program + solana-zk-elgamal-proof-program + solana-zk-token-proof-program + solana-pubsub-client + solana-quic-client + solana-rayon-threadlimit solana-remote-wallet + solana-rpc + solana-rpc-client + solana-rpc-client-api + solana-rpc-client-nonce-utils solana-runtime + solana-runtime-transaction solana-sdk - solana-stake-program + solana-sdk-macro + solana-program + solana-send-transaction-service + solana-storage-bigtable + solana-storage-proto + solana-streamer + solana-svm-rent-collector + solana-svm-transaction solana-test-validator + solana-thin-client + solana-tpu-client solana-transaction-status - solana-vote-program + solana-transaction-status-client-types + solana-udp-client solana-version solana-zk-token-sdk + solana-zk-sdk + solana-bn254 + solana-curve25519 + solana-secp256k1-recover + solana-account + solana-account-info + solana-atomic-u64 + solana-bincode + solana-borsh + solana-clock + solana-cpi + solana-decode-error + solana-define-syscall + solana-derivation-path + solana-epoch-schedule + solana-feature-set + solana-fee-calculator + solana-hash + solana-inflation + solana-instruction + solana-last-restart-slot + solana-msg + solana-native-token + solana-packet + solana-precompile-error + solana-program-entrypoint + solana-program-error + solana-program-memory + solana-program-option + solana-program-pack + solana-pubkey + solana-rent + solana-sanitize + solana-serde-varint + solana-serialize-utils + solana-sha256-hasher + solana-short-vec + solana-signature + solana-slot-hashes + solana-stable-layout + solana-timings + solana-transaction-error ) set -x for crate in "${crates[@]}"; do - sed -E -i'' -e "s:(${crate} = \")(=?)${old_solana_ver}\".*:\1\2${solana_ver}\":" "${tomls[@]}" + sed -E -i'' -e "s:(${crate} = \")([=<>]*)${old_solana_ver}([^\"]*)\".*:\1\2${solana_ver}\3\":" "${tomls[@]}" + sed -E -i'' -e "s:(${crate} = \{ version = \")([=<>]*)${old_solana_ver}([^\"]*)(\".*):\1\2${solana_ver}\3\4:" "${tomls[@]}" done diff --git a/utils/cgen/Cargo.toml b/utils/cgen/Cargo.toml index 76fe792181a..440a327583b 100644 --- a/utils/cgen/Cargo.toml +++ b/utils/cgen/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "cgen" version = "0.1.0" -authors = ["Solana Maintainers "] +authors = ["Solana Labs Maintainers "] publish = false -edition = "2018" +edition = "2021" [dependencies] cbindgen = "=0.16.0" diff --git a/utils/cgen/src/main.rs b/utils/cgen/src/main.rs index cbb1bf16d46..d774d562f9e 100644 --- a/utils/cgen/src/main.rs +++ b/utils/cgen/src/main.rs @@ -1,7 +1,6 @@ extern crate cbindgen; -use std::env; -use std::path::Path; +use std::{env, path::Path}; fn token>(crate_dir: P) { let output_file = crate_dir.as_ref().join("inc/token.h"); @@ -62,6 +61,6 @@ fn main() { .parent() .unwrap(); - token(&workspace_root.join("token/program")); - token_swap(&workspace_root.join("token-swap/program")); + token(workspace_root.join("token/program")); + token_swap(workspace_root.join("token-swap/program")); } diff --git a/utils/test-client/Cargo.toml b/utils/test-client/Cargo.toml index becd4257fcb..12f53134e6b 100644 --- a/utils/test-client/Cargo.toml +++ b/utils/test-client/Cargo.toml @@ -1,14 +1,14 @@ [package] name = "test-client" version = "0.1.0" -authors = ["Solana Maintainers "] +authors = ["Solana Labs Maintainers "] publish = false -edition = "2018" +edition = "2021" # Used to ensure that SPL programs are buildable by external clients [dependencies] -solana-sdk = "1.10.33" -spl-memo = { path = "../../memo/program", features = [ "no-entrypoint" ] } -spl-token = { path = "../../token/program", features = [ "no-entrypoint" ] } +solana-sdk = "2.1.0" +spl-memo = { version = "6.0.0", features = [ "no-entrypoint" ] } +spl-token = { version = "7.0.0", features = [ "no-entrypoint" ] } spl-token-swap = { path = "../../token-swap/program", features = [ "no-entrypoint" ] }